aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig6
-rw-r--r--drivers/Makefile6
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c49
-rw-r--r--drivers/acpi/acpi_ipmi.c525
-rw-r--r--drivers/acpi/acpica/Makefile2
-rw-r--r--drivers/acpi/acpica/acevents.h21
-rw-r--r--drivers/acpi/acpica/acglobal.h9
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/aclocal.h13
-rw-r--r--drivers/acpi/acpica/acobject.h2
-rw-r--r--drivers/acpi/acpica/evevent.c12
-rw-r--r--drivers/acpi/acpica/evgpe.c265
-rw-r--r--drivers/acpi/acpica/evgpeblk.c33
-rw-r--r--drivers/acpi/acpica/evgpeinit.c28
-rw-r--r--drivers/acpi/acpica/evgpeutil.c39
-rw-r--r--drivers/acpi/acpica/evmisc.c92
-rw-r--r--drivers/acpi/acpica/evxface.c77
-rw-r--r--drivers/acpi/acpica/evxfevnt.c600
-rw-r--r--drivers/acpi/acpica/evxfgpe.c669
-rw-r--r--drivers/acpi/acpica/hwgpe.c32
-rw-r--r--drivers/acpi/acpica/nsinit.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c3
-rw-r--r--drivers/acpi/acpica/utmutex.c1
-rw-r--r--drivers/acpi/apei/apei-internal.h2
-rw-r--r--drivers/acpi/apei/cper.c311
-rw-r--r--drivers/acpi/apei/einj.c2
-rw-r--r--drivers/acpi/apei/erst.c36
-rw-r--r--drivers/acpi/apei/ghes.c431
-rw-r--r--drivers/acpi/apei/hest.c36
-rw-r--r--drivers/acpi/battery.c16
-rw-r--r--drivers/acpi/bus.c153
-rw-r--r--drivers/acpi/button.c9
-rw-r--r--drivers/acpi/debugfs.c2
-rw-r--r--drivers/acpi/dock.c2
-rw-r--r--drivers/acpi/ec.c8
-rw-r--r--drivers/acpi/fan.c27
-rw-r--r--drivers/acpi/glue.c5
-rw-r--r--drivers/acpi/internal.h13
-rw-r--r--drivers/acpi/numa.c10
-rw-r--r--drivers/acpi/nvs.c144
-rw-r--r--drivers/acpi/osl.c130
-rw-r--r--drivers/acpi/pci_root.c35
-rw-r--r--drivers/acpi/power.c140
-rw-r--r--drivers/acpi/proc.c41
-rw-r--r--drivers/acpi/processor_core.c4
-rw-r--r--drivers/acpi/processor_driver.c80
-rw-r--r--drivers/acpi/processor_idle.c34
-rw-r--r--drivers/acpi/processor_thermal.c9
-rw-r--r--drivers/acpi/processor_throttling.c190
-rw-r--r--drivers/acpi/sbs.c2
-rw-r--r--drivers/acpi/scan.c159
-rw-r--r--drivers/acpi/sleep.c33
-rw-r--r--drivers/acpi/sysfs.c19
-rw-r--r--drivers/acpi/thermal.c5
-rw-r--r--drivers/acpi/video.c106
-rw-r--r--drivers/acpi/video_detect.c57
-rw-r--r--drivers/acpi/wakeup.c22
-rw-r--r--drivers/amba/bus.c39
-rw-r--r--drivers/ata/Kconfig50
-rw-r--r--drivers/ata/Makefile3
-rw-r--r--drivers/ata/acard-ahci.c528
-rw-r--r--drivers/ata/ahci.h3
-rw-r--r--drivers/ata/libahci.c11
-rw-r--r--drivers/ata/libata-core.c30
-rw-r--r--drivers/ata/libata-eh.c17
-rw-r--r--drivers/ata/libata-scsi.c82
-rw-r--r--drivers/ata/libata-sff.c9
-rw-r--r--drivers/ata/pata_cs5536.c20
-rw-r--r--drivers/ata/pata_hpt366.c51
-rw-r--r--drivers/ata/pata_hpt37x.c236
-rw-r--r--drivers/ata/pata_hpt3x2n.c150
-rw-r--r--drivers/ata/pata_legacy.c2
-rw-r--r--drivers/ata/pata_octeon_cf.c2
-rw-r--r--drivers/ata/sata_via.c9
-rw-r--r--drivers/ata/sata_vsc.c2
-rw-r--r--drivers/atm/adummy.c2
-rw-r--r--drivers/atm/ambassador.c22
-rw-r--r--drivers/atm/atmtcp.c7
-rw-r--r--drivers/atm/eni.c2
-rw-r--r--drivers/atm/firestream.c2
-rw-r--r--drivers/atm/fore200e.c16
-rw-r--r--drivers/atm/he.c2
-rw-r--r--drivers/atm/horizon.c3
-rw-r--r--drivers/atm/idt77252.c3
-rw-r--r--drivers/atm/idt77252.h2
-rw-r--r--drivers/atm/iphase.c6
-rw-r--r--drivers/atm/lanai.c9
-rw-r--r--drivers/atm/nicstar.c3
-rw-r--r--drivers/atm/solos-attrlist.c1
-rw-r--r--drivers/atm/solos-pci.c16
-rw-r--r--drivers/atm/zatm.c2
-rw-r--r--drivers/base/base.h62
-rw-r--r--drivers/base/bus.c15
-rw-r--r--drivers/base/class.c42
-rw-r--r--drivers/base/core.c65
-rw-r--r--drivers/base/node.c21
-rw-r--r--drivers/base/power/generic_ops.c6
-rw-r--r--drivers/base/power/main.c178
-rw-r--r--drivers/base/power/runtime.c47
-rw-r--r--drivers/base/power/wakeup.c20
-rw-r--r--drivers/block/Kconfig1
-rw-r--r--drivers/block/amiflop.c2
-rw-r--r--drivers/block/aoe/aoeblk.c3
-rw-r--r--drivers/block/aoe/aoecmd.c6
-rw-r--r--drivers/block/ataflop.c2
-rw-r--r--drivers/block/cciss.c159
-rw-r--r--drivers/block/cciss.h8
-rw-r--r--drivers/block/cciss_cmd.h2
-rw-r--r--drivers/block/cciss_scsi.c8
-rw-r--r--drivers/block/drbd/drbd_actlog.c42
-rw-r--r--drivers/block/drbd/drbd_int.h54
-rw-r--r--drivers/block/drbd/drbd_main.c155
-rw-r--r--drivers/block/drbd/drbd_nl.c128
-rw-r--r--drivers/block/drbd/drbd_proc.c1
-rw-r--r--drivers/block/drbd/drbd_receiver.c232
-rw-r--r--drivers/block/drbd/drbd_req.c38
-rw-r--r--drivers/block/drbd/drbd_req.h3
-rw-r--r--drivers/block/drbd/drbd_worker.c34
-rw-r--r--drivers/block/floppy.c23
-rw-r--r--drivers/block/loop.c12
-rw-r--r--drivers/block/pktcdvd.c22
-rw-r--r--drivers/block/rbd.c761
-rw-r--r--drivers/block/xen-blkfront.c61
-rw-r--r--drivers/bluetooth/ath3k.c4
-rw-r--r--drivers/bluetooth/btusb.c17
-rw-r--r--drivers/bluetooth/hci_ldisc.c6
-rw-r--r--drivers/cdrom/cdrom.c56
-rw-r--r--drivers/cdrom/gdrom.c2
-rw-r--r--drivers/char/Kconfig18
-rw-r--r--drivers/char/Makefile46
-rw-r--r--drivers/char/agp/agp.h1
-rw-r--r--drivers/char/agp/amd64-agp.c33
-rw-r--r--drivers/char/agp/compat_ioctl.c1
-rw-r--r--drivers/char/agp/compat_ioctl.h1
-rw-r--r--drivers/char/agp/frontend.c9
-rw-r--r--drivers/char/agp/generic.c27
-rw-r--r--drivers/char/agp/intel-agp.c9
-rw-r--r--drivers/char/agp/intel-agp.h16
-rw-r--r--drivers/char/agp/intel-gtt.c812
-rw-r--r--drivers/char/amiserial.c2
-rw-r--r--drivers/char/briq_panel.c1
-rw-r--r--drivers/char/hpet.c1
-rw-r--r--drivers/char/hvc_dcc.c133
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hvsi.c4
-rw-r--r--drivers/char/hw_random/core.c1
-rw-r--r--drivers/char/hw_random/via-rng.c10
-rw-r--r--drivers/char/i8k.c7
-rw-r--r--drivers/char/ip2/ip2main.c2
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c27
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c33
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c2
-rw-r--r--drivers/char/istallion.c1
-rw-r--r--drivers/char/nozomi.c1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c3
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c2
-rw-r--r--drivers/char/pcmcia/ipwireless/network.c3
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c1
-rw-r--r--drivers/char/ramoops.c21
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/raw.c14
-rw-r--r--drivers/char/rocket.c2
-rw-r--r--drivers/char/serial167.c1
-rw-r--r--drivers/char/snsc.h1
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/specialix.c3
-rw-r--r--drivers/char/stallion.c1
-rw-r--r--drivers/char/sx.c1
-rw-r--r--drivers/char/tpm/tpm.c24
-rw-r--r--drivers/char/tpm/tpm.h5
-rw-r--r--drivers/char/tpm/tpm_tis.c24
-rw-r--r--drivers/char/uv_mmtimer.c1
-rw-r--r--drivers/char/virtio_console.c37
-rw-r--r--drivers/clk/Kconfig4
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/clkdev.c176
-rw-r--r--drivers/clocksource/sh_cmt.c27
-rw-r--r--drivers/clocksource/sh_mtu2.c10
-rw-r--r--drivers/clocksource/sh_tmu.c10
-rw-r--r--drivers/connector/cn_proc.c5
-rw-r--r--drivers/connector/connector.c1
-rw-r--r--drivers/cpufreq/cpufreq.c1
-rw-r--r--drivers/cpuidle/cpuidle.c93
-rw-r--r--drivers/crypto/mv_cesa.c2
-rw-r--r--drivers/crypto/n2_core.c4
-rw-r--r--drivers/crypto/omap-aes.c260
-rw-r--r--drivers/crypto/omap-sham.c374
-rw-r--r--drivers/crypto/padlock-aes.c4
-rw-r--r--drivers/crypto/padlock-sha.c8
-rw-r--r--drivers/crypto/padlock.h23
-rw-r--r--drivers/dca/dca-core.c2
-rw-r--r--drivers/dma/Kconfig11
-rw-r--r--drivers/dma/Makefile4
-rw-r--r--drivers/dma/amba-pl08x.c1168
-rw-r--r--drivers/dma/at_hdmac.c21
-rw-r--r--drivers/dma/fsldma.c10
-rw-r--r--drivers/dma/fsldma.h9
-rw-r--r--drivers/dma/imx-dma.c2
-rw-r--r--drivers/dma/imx-sdma.c178
-rw-r--r--drivers/dma/intel_mid_dma.c47
-rw-r--r--drivers/dma/ioat/Makefile2
-rw-r--r--drivers/dma/iop-adma.c4
-rw-r--r--drivers/dma/mpc512x_dma.c187
-rw-r--r--drivers/dma/mv_xor.c2
-rw-r--r--drivers/dma/pch_dma.c34
-rw-r--r--drivers/dma/ppc4xx/adma.c5
-rw-r--r--drivers/dma/shdma.c131
-rw-r--r--drivers/dma/shdma.h1
-rw-r--r--drivers/dma/ste_dma40.c191
-rw-r--r--drivers/dma/ste_dma40_ll.c246
-rw-r--r--drivers/dma/ste_dma40_ll.h36
-rw-r--r--drivers/edac/Kconfig8
-rw-r--r--drivers/edac/Makefile8
-rw-r--r--drivers/edac/amd64_edac.c831
-rw-r--r--drivers/edac/amd64_edac.h86
-rw-r--r--drivers/edac/amd64_edac_inj.c25
-rw-r--r--drivers/edac/amd8131_edac.h2
-rw-r--r--drivers/edac/cell_edac.c4
-rw-r--r--drivers/edac/cpc925_edac.c9
-rw-r--r--drivers/edac/e752x_edac.c8
-rw-r--r--drivers/edac/edac_core.h13
-rw-r--r--drivers/edac/edac_mc.c14
-rw-r--r--drivers/edac/edac_mc_sysfs.c57
-rw-r--r--drivers/edac/i5100_edac.c9
-rw-r--r--drivers/edac/i7core_edac.c6
-rw-r--r--drivers/edac/mce_amd.c450
-rw-r--r--drivers/edac/mce_amd.h14
-rw-r--r--drivers/edac/mce_amd_inj.c11
-rw-r--r--drivers/edac/ppc4xx_edac.c6
-rw-r--r--drivers/firewire/Kconfig2
-rw-r--r--drivers/firewire/core-cdev.c7
-rw-r--r--drivers/firewire/core-transaction.c58
-rw-r--r--drivers/firewire/core.h4
-rw-r--r--drivers/firewire/net.c207
-rw-r--r--drivers/firewire/nosy.c3
-rw-r--r--drivers/firewire/ohci.c689
-rw-r--r--drivers/firewire/sbp2.c4
-rw-r--r--drivers/gpio/Kconfig22
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/adp5588-gpio.c39
-rw-r--r--drivers/gpio/cs5535-gpio.c172
-rw-r--r--drivers/gpio/gpiolib.c3
-rw-r--r--drivers/gpio/langwell_gpio.c16
-rw-r--r--drivers/gpio/max732x.c38
-rw-r--r--drivers/gpio/ml_ioh_gpio.c352
-rw-r--r--drivers/gpio/pca953x.c38
-rw-r--r--drivers/gpio/pl061.c28
-rw-r--r--drivers/gpio/rdc321x-gpio.c2
-rw-r--r--drivers/gpio/stmpe-gpio.c36
-rw-r--r--drivers/gpio/sx150x.c46
-rw-r--r--drivers/gpio/tc35892-gpio.c389
-rw-r--r--drivers/gpio/tc3589x-gpio.c389
-rw-r--r--drivers/gpio/timbgpio.c26
-rw-r--r--drivers/gpio/vr41xx_giu.c48
-rw-r--r--drivers/gpio/wm8994-gpio.c24
-rw-r--r--drivers/gpu/drm/Kconfig1
-rw-r--r--drivers/gpu/drm/drm_agpsupport.c6
-rw-r--r--drivers/gpu/drm/drm_crtc.c10
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c37
-rw-r--r--drivers/gpu/drm/drm_edid.c26
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c24
-rw-r--r--drivers/gpu/drm/drm_fops.c3
-rw-r--r--drivers/gpu/drm/drm_irq.c587
-rw-r--r--drivers/gpu/drm/drm_mm.c40
-rw-r--r--drivers/gpu/drm/drm_stub.c10
-rw-r--r--drivers/gpu/drm/i915/Makefile2
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7017.c2
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c548
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c826
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c95
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h619
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c3788
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c23
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c138
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c1377
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c95
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c139
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c859
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h299
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c146
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h91
-rw-r--r--drivers/gpu/drm/i915/intel_acpi.c34
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c17
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c183
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1406
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c251
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h28
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c51
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c32
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c192
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c10
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c120
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c83
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c1198
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h158
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c130
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c14
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/Makefile17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c13
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c108
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c354
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c383
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c129
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c207
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c58
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h483
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c188
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c124
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c165
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.h19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c1206
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c457
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mm.c171
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mm.h65
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_notifier.c44
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c754
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c40
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.c80
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h75
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c218
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c317
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_util.c69
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_util.h45
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.c439
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.h113
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c12
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c13
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c102
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c240
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c645
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c50
-rw-r--r--drivers/gpu/drm/nouveau/nv04_pm.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fb.c124
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c19
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c203
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c244
-rw-r--r--drivers/gpu/drm/nouveau/nv30_fb.c23
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fb.c22
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c204
-rw-r--r--drivers/gpu/drm/nouveau/nv40_grctx.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mc.c14
-rw-r--r--drivers/gpu/drm/nouveau/nv50_calc.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c31
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c405
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.c345
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.h10
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fb.c71
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c114
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c45
-rw-r--r--drivers/gpu/drm/nouveau/nv50_gpio.c198
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c717
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c379
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vm.c180
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vram.c190
-rw-r--r--drivers/gpu/drm/nouveau/nv84_crypt.c140
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fbcon.c269
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c365
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c706
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.h64
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_grctx.c2874
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_instmem.c317
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_vm.c123
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_vram.c99
-rw-r--r--drivers/gpu/drm/nouveau/nvreg.h3
-rw-r--r--drivers/gpu/drm/radeon/Makefile5
-rw-r--r--drivers/gpu/drm/radeon/ObjectID.h48
-rw-r--r--drivers/gpu/drm/radeon/atom.c15
-rw-r--r--drivers/gpu/drm/radeon/atombios.h999
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c64
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c870
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_kms.c94
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h6
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h54
-rw-r--r--drivers/gpu/drm/radeon/ni.c316
-rw-r--r--drivers/gpu/drm/radeon/ni_reg.h86
-rw-r--r--drivers/gpu/drm/radeon/nid.h41
-rw-r--r--drivers/gpu/drm/radeon/r100.c93
-rw-r--r--drivers/gpu/drm/radeon/r100d.h2
-rw-r--r--drivers/gpu/drm/radeon/r300.c34
-rw-r--r--drivers/gpu/drm/radeon/r300d.h1
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h4
-rw-r--r--drivers/gpu/drm/radeon/r600.c421
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c318
-rw-r--r--drivers/gpu/drm/radeon/r600_reg.h1
-rw-r--r--drivers/gpu/drm/radeon/r600d.h54
-rw-r--r--drivers/gpu/drm/radeon/radeon.h156
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c153
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h65
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c1289
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c54
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c77
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c17
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c409
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c34
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c579
-rw-r--r--drivers/gpu/drm/radeon/radeon_family.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c49
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c46
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c64
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h38
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c79
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h14
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c94
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h13
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_trace.h82
-rw-r--r--drivers/gpu/drm/radeon/radeon_trace_points.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c5
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen2
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rv51516
-rw-r--r--drivers/gpu/drm/radeon/rs400.c2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c138
-rw-r--r--drivers/gpu/drm/radeon/rv770.c205
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h47
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c256
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_manager.c81
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c138
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c29
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c169
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c4
-rw-r--r--drivers/gpu/drm/via/via_dmablit.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c14
-rw-r--r--drivers/gpu/stub/Kconfig2
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c78
-rw-r--r--drivers/hid/Kconfig37
-rw-r--r--drivers/hid/Makefile15
-rw-r--r--drivers/hid/hid-3m-pct.c38
-rw-r--r--drivers/hid/hid-a4tech.c6
-rw-r--r--drivers/hid/hid-apple.c63
-rw-r--r--drivers/hid/hid-axff.c14
-rw-r--r--drivers/hid/hid-belkin.c4
-rw-r--r--drivers/hid/hid-cando.c4
-rw-r--r--drivers/hid/hid-cherry.c3
-rw-r--r--drivers/hid/hid-core.c131
-rw-r--r--drivers/hid/hid-cypress.c4
-rw-r--r--drivers/hid/hid-debug.c4
-rw-r--r--drivers/hid/hid-drff.c14
-rw-r--r--drivers/hid/hid-egalax.c135
-rw-r--r--drivers/hid/hid-elecom.c3
-rw-r--r--drivers/hid/hid-emsff.c161
-rw-r--r--drivers/hid/hid-gaff.c13
-rw-r--r--drivers/hid/hid-ids.h23
-rw-r--r--drivers/hid/hid-input.c56
-rw-r--r--drivers/hid/hid-kye.c4
-rw-r--r--drivers/hid/hid-lg.c15
-rw-r--r--drivers/hid/hid-lg2ff.c9
-rw-r--r--drivers/hid/hid-lg3ff.c9
-rw-r--r--drivers/hid/hid-lg4ff.c9
-rw-r--r--drivers/hid/hid-lgff.c8
-rw-r--r--drivers/hid/hid-magicmouse.c20
-rw-r--r--drivers/hid/hid-microsoft.c7
-rw-r--r--drivers/hid/hid-monterey.c3
-rw-r--r--drivers/hid/hid-mosart.c23
-rw-r--r--drivers/hid/hid-multitouch.c516
-rw-r--r--drivers/hid/hid-ntrig.c9
-rw-r--r--drivers/hid/hid-ortek.c3
-rw-r--r--drivers/hid/hid-petalynx.c7
-rw-r--r--drivers/hid/hid-picolcd.c58
-rw-r--r--drivers/hid/hid-pl.c16
-rw-r--r--drivers/hid/hid-prodikeys.c27
-rw-r--r--drivers/hid/hid-quanta.c2
-rw-r--r--drivers/hid/hid-roccat-kone.c404
-rw-r--r--drivers/hid/hid-roccat-kone.h19
-rw-r--r--drivers/hid/hid-roccat-koneplus.c837
-rw-r--r--drivers/hid/hid-roccat-koneplus.h224
-rw-r--r--drivers/hid/hid-roccat-pyra.c411
-rw-r--r--drivers/hid/hid-roccat-pyra.h23
-rw-r--r--drivers/hid/hid-roccat.c53
-rw-r--r--drivers/hid/hid-roccat.h5
-rw-r--r--drivers/hid/hid-samsung.c8
-rw-r--r--drivers/hid/hid-sjoy.c16
-rw-r--r--drivers/hid/hid-sony.c11
-rw-r--r--drivers/hid/hid-stantum.c2
-rw-r--r--drivers/hid/hid-sunplus.c3
-rw-r--r--drivers/hid/hid-tmff.c29
-rw-r--r--drivers/hid/hid-topseed.c1
-rw-r--r--drivers/hid/hid-wacom.c28
-rw-r--r--drivers/hid/hid-zpff.c11
-rw-r--r--drivers/hid/hid-zydacron.c11
-rw-r--r--drivers/hid/hidraw.c37
-rw-r--r--drivers/hid/usbhid/Makefile6
-rw-r--r--drivers/hid/usbhid/hid-core.c105
-rw-r--r--drivers/hid/usbhid/hid-pidff.c164
-rw-r--r--drivers/hid/usbhid/hid-quirks.c3
-rw-r--r--drivers/hid/usbhid/hiddev.c242
-rw-r--r--drivers/hid/usbhid/usbhid.h1
-rw-r--r--drivers/hid/usbhid/usbkbd.c24
-rw-r--r--drivers/hwmon/Kconfig24
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru.c36
-rw-r--r--drivers/hwmon/abituguru3.c45
-rw-r--r--drivers/hwmon/ad7414.c6
-rw-r--r--drivers/hwmon/adm1026.c20
-rw-r--r--drivers/hwmon/adm9240.c32
-rw-r--r--drivers/hwmon/ads7828.c4
-rw-r--r--drivers/hwmon/adt7470.c8
-rw-r--r--drivers/hwmon/amc6821.c2
-rw-r--r--drivers/hwmon/applesmc.c1632
-rw-r--r--drivers/hwmon/asb100.c9
-rw-r--r--drivers/hwmon/asus_atk0110.c7
-rw-r--r--drivers/hwmon/coretemp.c11
-rw-r--r--drivers/hwmon/dme1737.c201
-rw-r--r--drivers/hwmon/ds620.c337
-rw-r--r--drivers/hwmon/emc1403.c16
-rw-r--r--drivers/hwmon/f71805f.c29
-rw-r--r--drivers/hwmon/f71882fg.c23
-rw-r--r--drivers/hwmon/fschmd.c5
-rw-r--r--drivers/hwmon/gpio-fan.c8
-rw-r--r--drivers/hwmon/hp_accel.c13
-rw-r--r--drivers/hwmon/hwmon-vid.c11
-rw-r--r--drivers/hwmon/hwmon.c4
-rw-r--r--drivers/hwmon/i5k_amb.c2
-rw-r--r--drivers/hwmon/ibmaem.c4
-rw-r--r--drivers/hwmon/it87.c91
-rw-r--r--drivers/hwmon/lis3lv02d.c23
-rw-r--r--drivers/hwmon/lis3lv02d_i2c.c10
-rw-r--r--drivers/hwmon/lm70.c5
-rw-r--r--drivers/hwmon/lm78.c14
-rw-r--r--drivers/hwmon/lm93.c4
-rw-r--r--drivers/hwmon/lm95241.c494
-rw-r--r--drivers/hwmon/ltc4215.c4
-rw-r--r--drivers/hwmon/ltc4261.c5
-rw-r--r--drivers/hwmon/max6650.c2
-rw-r--r--drivers/hwmon/pc87360.c53
-rw-r--r--drivers/hwmon/pc87427.c26
-rw-r--r--drivers/hwmon/pcf8591.c5
-rw-r--r--drivers/hwmon/pkgtemp.c7
-rw-r--r--drivers/hwmon/s3c-hwmon.c2
-rw-r--r--drivers/hwmon/sht21.c307
-rw-r--r--drivers/hwmon/sis5595.c10
-rw-r--r--drivers/hwmon/smsc47b397.c13
-rw-r--r--drivers/hwmon/smsc47m1.c31
-rw-r--r--drivers/hwmon/via-cputemp.c35
-rw-r--r--drivers/hwmon/via686a.c24
-rw-r--r--drivers/hwmon/vt1211.c30
-rw-r--r--drivers/hwmon/vt8231.c10
-rw-r--r--drivers/hwmon/w83627ehf.c23
-rw-r--r--drivers/hwmon/w83627hf.c17
-rw-r--r--drivers/hwmon/w83781d.c29
-rw-r--r--drivers/hwmon/w83792d.c44
-rw-r--r--drivers/hwmon/w83793.c38
-rw-r--r--drivers/hwmon/w83795.c211
-rw-r--r--drivers/i2c/Kconfig3
-rw-r--r--drivers/i2c/algos/Kconfig14
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c31
-rw-r--r--drivers/i2c/busses/Kconfig9
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c24
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c900
-rw-r--r--drivers/i2c/busses/i2c-i801.c334
-rw-r--r--drivers/i2c/busses/i2c-intel-mid.c2
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c6
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h2
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c45
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c10
-rw-r--r--drivers/i2c/busses/i2c-ocores.c145
-rw-r--r--drivers/i2c/busses/i2c-omap.c83
-rw-r--r--drivers/i2c/busses/scx200_acb.c200
-rw-r--r--drivers/i2c/i2c-core.c131
-rw-r--r--drivers/i2c/i2c-mux.c1
-rw-r--r--drivers/i2c/muxes/Kconfig12
-rw-r--r--drivers/i2c/muxes/Makefile1
-rw-r--r--drivers/i2c/muxes/gpio-i2cmux.c184
-rw-r--r--drivers/idle/intel_idle.c80
-rw-r--r--drivers/infiniband/core/addr.c14
-rw-r--r--drivers/infiniband/core/ud_header.c30
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c99
-rw-r--r--drivers/infiniband/core/uverbs_marshall.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c56
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c32
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c8
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c9
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c2
-rw-r--r--drivers/infiniband/hw/mlx4/main.c10
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c4
-rw-r--r--drivers/infiniband/hw/qib/qib.h2
-rw-r--r--drivers/infiniband/hw/qib/qib_cq.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_driver.c155
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c10
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c375
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c6
-rw-r--r--drivers/infiniband/hw/qib/qib_intr.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_keys.c80
-rw-r--r--drivers/infiniband/hw/qib/qib_mad.c45
-rw-r--r--drivers/infiniband/hw/qib/qib_mr.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c32
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c24
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c57
-rw-r--r--drivers/infiniband/hw/qib/qib_user_sdma.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h11
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c51
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c62
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c390
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h46
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/apm-power.c14
-rw-r--r--drivers/input/evbug.c18
-rw-r--r--drivers/input/evdev.c132
-rw-r--r--drivers/input/ff-core.c11
-rw-r--r--drivers/input/ff-memless.c31
-rw-r--r--drivers/input/gameport/gameport.c154
-rw-r--r--drivers/input/input-mt.c170
-rw-r--r--drivers/input/input-polldev.c5
-rw-r--r--drivers/input/input.c181
-rw-r--r--drivers/input/joydev.c4
-rw-r--r--drivers/input/joystick/Kconfig10
-rw-r--r--drivers/input/joystick/Makefile1
-rw-r--r--drivers/input/joystick/as5011.c367
-rw-r--r--drivers/input/joystick/iforce/Makefile15
-rw-r--r--drivers/input/joystick/turbografx.c1
-rw-r--r--drivers/input/joystick/xpad.c123
-rw-r--r--drivers/input/keyboard/Kconfig57
-rw-r--r--drivers/input/keyboard/Makefile4
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c186
-rw-r--r--drivers/input/keyboard/adp5588-keys.c74
-rw-r--r--drivers/input/keyboard/atkbd.c12
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c261
-rw-r--r--drivers/input/keyboard/omap-keypad.c41
-rw-r--r--drivers/input/keyboard/spear-keyboard.c344
-rw-r--r--drivers/input/keyboard/tc3589x-keypad.c472
-rw-r--r--drivers/input/keyboard/tca6416-keypad.c13
-rw-r--r--drivers/input/misc/Kconfig42
-rw-r--r--drivers/input/misc/Makefile3
-rw-r--r--drivers/input/misc/cma3000_d0x.c398
-rw-r--r--drivers/input/misc/cma3000_d0x.h42
-rw-r--r--drivers/input/misc/cma3000_d0x_i2c.c143
-rw-r--r--drivers/input/misc/pcf8574_keypad.c42
-rw-r--r--drivers/input/misc/uinput.c8
-rw-r--r--drivers/input/mouse/appletouch.c2
-rw-r--r--drivers/input/mouse/bcm5974.c40
-rw-r--r--drivers/input/mouse/hgpk.c695
-rw-r--r--drivers/input/mouse/hgpk.h31
-rw-r--r--drivers/input/mouse/psmouse-base.c1
-rw-r--r--drivers/input/mouse/synaptics.c129
-rw-r--r--drivers/input/mouse/synaptics.h6
-rw-r--r--drivers/input/mousedev.c10
-rw-r--r--drivers/input/serio/Kconfig3
-rw-r--r--drivers/input/serio/ams_delta_serio.c1
-rw-r--r--drivers/input/serio/ct82c710.c8
-rw-r--r--drivers/input/serio/gscps2.c2
-rw-r--r--drivers/input/serio/hil_mlc.c5
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c18
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h69
-rw-r--r--drivers/input/serio/i8042.c98
-rw-r--r--drivers/input/serio/i8042.h14
-rw-r--r--drivers/input/serio/ps2mult.c2
-rw-r--r--drivers/input/serio/serio.c155
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/tablet/acecad.c3
-rw-r--r--drivers/input/tablet/aiptek.c28
-rw-r--r--drivers/input/tablet/wacom.h1
-rw-r--r--drivers/input/tablet/wacom_wac.c45
-rw-r--r--drivers/input/tablet/wacom_wac.h4
-rw-r--r--drivers/input/touchscreen/Kconfig24
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c17
-rw-r--r--drivers/input/touchscreen/ad7879.c32
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c4
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c15
-rw-r--r--drivers/input/touchscreen/eeti_ts.c16
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c17
-rw-r--r--drivers/input/touchscreen/migor_ts.c12
-rw-r--r--drivers/input/touchscreen/qt602240_ts.c21
-rw-r--r--drivers/input/touchscreen/st1232.c274
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c1
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c247
-rw-r--r--drivers/input/xen-kbdfront.c10
-rw-r--r--drivers/isdn/capi/capidrv.c1
-rw-r--r--drivers/isdn/capi/kcapi.c26
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c4
-rw-r--r--drivers/isdn/gigaset/capi.c1
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c4
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c4
-rw-r--r--drivers/isdn/hardware/mISDN/ipac.h4
-rw-r--r--drivers/isdn/hardware/mISDN/isar.h2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c4
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c2
-rw-r--r--drivers/isdn/hisax/callc.c4
-rw-r--r--drivers/isdn/hisax/config.c2
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c4
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c2
-rw-r--r--drivers/isdn/hisax/hfc_pci.c4
-rw-r--r--drivers/isdn/hisax/hfc_sx.c6
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/hisax/ipacx.c2
-rw-r--r--drivers/isdn/hisax/isar.c19
-rw-r--r--drivers/isdn/hisax/isdnl1.h1
-rw-r--r--drivers/isdn/hisax/isdnl3.c2
-rw-r--r--drivers/isdn/hisax/netjet.c10
-rw-r--r--drivers/isdn/hisax/st5481_d.c6
-rw-r--r--drivers/isdn/i4l/isdn_concap.c2
-rw-r--r--drivers/isdn/i4l/isdn_net.c20
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c26
-rw-r--r--drivers/isdn/icn/icn.c7
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c2
-rw-r--r--drivers/isdn/mISDN/hwchannel.c4
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/isdn/mISDN/layer1.c10
-rw-r--r--drivers/isdn/mISDN/layer2.c12
-rw-r--r--drivers/isdn/mISDN/socket.c2
-rw-r--r--drivers/isdn/mISDN/tei.c23
-rw-r--r--drivers/leds/Kconfig70
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-class.c105
-rw-r--r--drivers/leds/led-triggers.c2
-rw-r--r--drivers/leds/leds-gpio.c2
-rw-r--r--drivers/leds/leds-lp5521.c804
-rw-r--r--drivers/leds/leds-lp5523.c1046
-rw-r--r--drivers/leds/leds-net5501.c2
-rw-r--r--drivers/leds/leds-pca9532.c66
-rw-r--r--drivers/leds/leds-ss4200.c1
-rw-r--r--drivers/leds/leds-wm8350.c2
-rw-r--r--drivers/leds/ledtrig-backlight.c61
-rw-r--r--drivers/leds/ledtrig-timer.c124
-rw-r--r--drivers/macintosh/Kconfig1
-rw-r--r--drivers/macintosh/adb-iop.c4
-rw-r--r--drivers/macintosh/ams/ams-core.c2
-rw-r--r--drivers/macintosh/mac_hid.c8
-rw-r--r--drivers/macintosh/macio_asic.c7
-rw-r--r--drivers/macintosh/rack-meter.c4
-rw-r--r--drivers/macintosh/therm_pm72.c30
-rw-r--r--drivers/macintosh/via-pmu-backlight.c4
-rw-r--r--drivers/macintosh/via-pmu.c2
-rw-r--r--drivers/md/Kconfig24
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/bitmap.c12
-rw-r--r--drivers/md/dm-crypt.c618
-rw-r--r--drivers/md/dm-delay.c2
-rw-r--r--drivers/md/dm-ioctl.c111
-rw-r--r--drivers/md/dm-kcopyd.c57
-rw-r--r--drivers/md/dm-log-userspace-base.c139
-rw-r--r--drivers/md/dm-log-userspace-transfer.c1
-rw-r--r--drivers/md/dm-log.c2
-rw-r--r--drivers/md/dm-mpath.c67
-rw-r--r--drivers/md/dm-raid.c697
-rw-r--r--drivers/md/dm-raid1.c19
-rw-r--r--drivers/md/dm-snap-persistent.c4
-rw-r--r--drivers/md/dm-snap.c62
-rw-r--r--drivers/md/dm-stripe.c27
-rw-r--r--drivers/md/dm-table.c50
-rw-r--r--drivers/md/dm.c29
-rw-r--r--drivers/md/md.c276
-rw-r--r--drivers/md/md.h13
-rw-r--r--drivers/md/raid1.c34
-rw-r--r--drivers/md/raid10.c19
-rw-r--r--drivers/md/raid5.c16
-rw-r--r--drivers/media/IR/ir-functions.c356
-rw-r--r--drivers/media/IR/ir-keytable.c708
-rw-r--r--drivers/media/IR/ir-sysfs.c362
-rw-r--r--drivers/media/IR/keymaps/rc-tbs-nec.c73
-rw-r--r--drivers/media/IR/keymaps/rc-tt-1500.c82
-rw-r--r--drivers/media/IR/rc-map.c107
-rw-r--r--drivers/media/Kconfig54
-rw-r--r--drivers/media/Makefile2
-rw-r--r--drivers/media/common/saa7146_hlp.c8
-rw-r--r--drivers/media/common/saa7146_i2c.c1
-rw-r--r--drivers/media/common/saa7146_video.c48
-rw-r--r--drivers/media/common/tuners/Kconfig8
-rw-r--r--drivers/media/common/tuners/max2165.c10
-rw-r--r--drivers/media/common/tuners/tda18218.c2
-rw-r--r--drivers/media/dvb/dm1105/Kconfig3
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c44
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c3
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c6
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c16
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c16
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h4
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c22
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c4
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.c13
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-core.c6
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c62
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c18
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c146
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c16
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h2
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c14
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c18
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c106
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h28
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c54
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c28
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h8
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c329
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c24
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c18
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c16
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c35
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c12
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c12
-rw-r--r--drivers/media/dvb/frontends/Kconfig15
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/af9013.c2
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c8
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c51
-rw-r--r--drivers/media/dvb/frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c10
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c10
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c1
-rw-r--r--drivers/media/dvb/frontends/ix2505v.c2
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c11
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.c615
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.h52
-rw-r--r--drivers/media/dvb/frontends/s921.c548
-rw-r--r--drivers/media/dvb/frontends/s921.h47
-rw-r--r--drivers/media/dvb/frontends/s921_core.c216
-rw-r--r--drivers/media/dvb/frontends/s921_core.h114
-rw-r--r--drivers/media/dvb/frontends/s921_module.c192
-rw-r--r--drivers/media/dvb/frontends/s921_module.h49
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c2
-rw-r--r--drivers/media/dvb/frontends/stb6100.c198
-rw-r--r--drivers/media/dvb/frontends/stv090x.c6
-rw-r--r--drivers/media/dvb/mantis/Kconfig2
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c2
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.c6
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_common.h4
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c17
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c76
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.h2
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.c1
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.c10
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.c6
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.c8
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c9
-rw-r--r--drivers/media/dvb/ngene/ngene-dvb.c1
-rw-r--r--drivers/media/dvb/ngene/ngene-i2c.c1
-rw-r--r--drivers/media/dvb/siano/Kconfig2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c2
-rw-r--r--drivers/media/dvb/siano/smsir.c52
-rw-r--r--drivers/media/dvb/siano/smsir.h5
-rw-r--r--drivers/media/dvb/siano/smsusb.c9
-rw-r--r--drivers/media/dvb/ttpci/Kconfig3
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c54
-rw-r--r--drivers/media/radio/Kconfig16
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-aimslab.c39
-rw-r--r--drivers/media/radio/radio-aztech.c6
-rw-r--r--drivers/media/radio/radio-cadet.c12
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c6
-rw-r--r--drivers/media/radio/radio-gemtek.c14
-rw-r--r--drivers/media/radio/radio-maestro.c14
-rw-r--r--drivers/media/radio/radio-maxiradio.c2
-rw-r--r--drivers/media/radio/radio-miropcm20.c6
-rw-r--r--drivers/media/radio/radio-mr800.c1
-rw-r--r--drivers/media/radio/radio-rtrack2.c10
-rw-r--r--drivers/media/radio/radio-sf16fmi.c7
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c11
-rw-r--r--drivers/media/radio/radio-si4713.c5
-rw-r--r--drivers/media/radio/radio-tea5764.c49
-rw-r--r--drivers/media/radio/radio-terratec.c8
-rw-r--r--drivers/media/radio/radio-timb.c5
-rw-r--r--drivers/media/radio/radio-trust.c18
-rw-r--r--drivers/media/radio/radio-typhoon.c16
-rw-r--r--drivers/media/radio/radio-wl1273.c2330
-rw-r--r--drivers/media/radio/radio-zoltrix.c30
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h2
-rw-r--r--drivers/media/radio/si4713-i2c.c74
-rw-r--r--drivers/media/radio/si4713-i2c.h5
-rw-r--r--drivers/media/rc/Kconfig (renamed from drivers/media/IR/Kconfig)70
-rw-r--r--drivers/media/rc/Makefile (renamed from drivers/media/IR/Makefile)8
-rw-r--r--drivers/media/rc/ene_ir.c (renamed from drivers/media/IR/ene_ir.c)131
-rw-r--r--drivers/media/rc/ene_ir.h (renamed from drivers/media/IR/ene_ir.h)3
-rw-r--r--drivers/media/rc/imon.c (renamed from drivers/media/IR/imon.c)107
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c (renamed from drivers/media/IR/ir-jvc-decoder.c)17
-rw-r--r--drivers/media/rc/ir-lirc-codec.c (renamed from drivers/media/IR/ir-lirc-codec.c)132
-rw-r--r--drivers/media/rc/ir-nec-decoder.c (renamed from drivers/media/IR/ir-nec-decoder.c)27
-rw-r--r--drivers/media/rc/ir-raw.c (renamed from drivers/media/IR/ir-raw-event.c)197
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c (renamed from drivers/media/IR/ir-rc5-decoder.c)17
-rw-r--r--drivers/media/rc/ir-rc5-sz-decoder.c (renamed from drivers/media/IR/ir-rc5-sz-decoder.c)17
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c (renamed from drivers/media/IR/ir-rc6-decoder.c)21
-rw-r--r--drivers/media/rc/ir-sony-decoder.c (renamed from drivers/media/IR/ir-sony-decoder.c)15
-rw-r--r--drivers/media/rc/keymaps/Kconfig (renamed from drivers/media/IR/keymaps/Kconfig)2
-rw-r--r--drivers/media/rc/keymaps/Makefile (renamed from drivers/media/IR/keymaps/Makefile)2
-rw-r--r--drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c (renamed from drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-alink-dtu-m.c (renamed from drivers/media/IR/keymaps/rc-alink-dtu-m.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-anysee.c (renamed from drivers/media/IR/keymaps/rc-anysee.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-apac-viewcomp.c (renamed from drivers/media/IR/keymaps/rc-apac-viewcomp.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-asus-pc39.c (renamed from drivers/media/IR/keymaps/rc-asus-pc39.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c (renamed from drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-a16d.c (renamed from drivers/media/IR/keymaps/rc-avermedia-a16d.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c (renamed from drivers/media/IR/keymaps/rc-avermedia-cardbus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-dvbt.c (renamed from drivers/media/IR/keymaps/rc-avermedia-dvbt.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m135a.c (renamed from drivers/media/IR/keymaps/rc-avermedia-m135a.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c (renamed from drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-rm-ks.c (renamed from drivers/media/IR/keymaps/rc-avermedia-rm-ks.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia.c (renamed from drivers/media/IR/keymaps/rc-avermedia.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avertv-303.c (renamed from drivers/media/IR/keymaps/rc-avertv-303.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c (renamed from drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-behold-columbus.c (renamed from drivers/media/IR/keymaps/rc-behold-columbus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c (renamed from drivers/media/IR/keymaps/rc-behold.c)78
-rw-r--r--drivers/media/rc/keymaps/rc-budget-ci-old.c (renamed from drivers/media/IR/keymaps/rc-budget-ci-old.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy-1400.c (renamed from drivers/media/IR/keymaps/rc-cinergy-1400.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy.c (renamed from drivers/media/IR/keymaps/rc-cinergy.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c (renamed from drivers/media/IR/keymaps/rc-dib0700-nec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-rc5.c (renamed from drivers/media/IR/keymaps/rc-dib0700-rc5.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c (renamed from drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-digittrade.c (renamed from drivers/media/IR/keymaps/rc-digittrade.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dm1105-nec.c (renamed from drivers/media/IR/keymaps/rc-dm1105-nec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c (renamed from drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c (renamed from drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-em-terratec.c (renamed from drivers/media/IR/keymaps/rc-em-terratec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv-fm53.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv-fm53.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv2.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv2.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-evga-indtube.c (renamed from drivers/media/IR/keymaps/rc-evga-indtube.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-eztv.c (renamed from drivers/media/IR/keymaps/rc-eztv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-flydvb.c (renamed from drivers/media/IR/keymaps/rc-flydvb.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-flyvideo.c (renamed from drivers/media/IR/keymaps/rc-flyvideo.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-fusionhdtv-mce.c (renamed from drivers/media/IR/keymaps/rc-fusionhdtv-mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-gadmei-rm008z.c (renamed from drivers/media/IR/keymaps/rc-gadmei-rm008z.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c (renamed from drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-gotview7135.c (renamed from drivers/media/IR/keymaps/rc-gotview7135.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge-new.c (renamed from drivers/media/IR/keymaps/rc-hauppauge-new.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-imon-mce.c (renamed from drivers/media/IR/keymaps/rc-imon-mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c (renamed from drivers/media/IR/keymaps/rc-imon-pad.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-iodata-bctv7e.c (renamed from drivers/media/IR/keymaps/rc-iodata-bctv7e.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kaiomy.c (renamed from drivers/media/IR/keymaps/rc-kaiomy.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-315u.c (renamed from drivers/media/IR/keymaps/rc-kworld-315u.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c (renamed from drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-leadtek-y04g0051.c (renamed from drivers/media/IR/keymaps/rc-leadtek-y04g0051.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-lirc.c (renamed from drivers/media/IR/keymaps/rc-lirc.c)12
-rw-r--r--drivers/media/rc/keymaps/rc-lme2510.c (renamed from drivers/media/IR/keymaps/rc-lme2510.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-manli.c (renamed from drivers/media/IR/keymaps/rc-manli.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-ii.c (renamed from drivers/media/IR/keymaps/rc-msi-digivox-ii.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-iii.c (renamed from drivers/media/IR/keymaps/rc-msi-digivox-iii.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c (renamed from drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere.c (renamed from drivers/media/IR/keymaps/rc-msi-tvanywhere.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-nebula.c (renamed from drivers/media/IR/keymaps/rc-nebula.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c (renamed from drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-norwood.c (renamed from drivers/media/IR/keymaps/rc-norwood.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-npgtech.c (renamed from drivers/media/IR/keymaps/rc-npgtech.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pctv-sedna.c (renamed from drivers/media/IR/keymaps/rc-pctv-sedna.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-color.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-color.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-grey.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-grey.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c77
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c (renamed from drivers/media/IR/keymaps/rc-pixelview-mk12.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-new.c (renamed from drivers/media/IR/keymaps/rc-pixelview-new.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview.c (renamed from drivers/media/IR/keymaps/rc-pixelview.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-powercolor-real-angel.c (renamed from drivers/media/IR/keymaps/rc-powercolor-real-angel.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-proteus-2309.c (renamed from drivers/media/IR/keymaps/rc-proteus-2309.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-purpletv.c (renamed from drivers/media/IR/keymaps/rc-purpletv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pv951.c (renamed from drivers/media/IR/keymaps/rc-pv951.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c (renamed from drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c)48
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-tv.c (renamed from drivers/media/IR/keymaps/rc-rc5-tv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-rc6-mce.c (renamed from drivers/media/IR/keymaps/rc-rc6-mce.c)31
-rw-r--r--drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c (renamed from drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-streamzap.c (renamed from drivers/media/IR/keymaps/rc-streamzap.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-tbs-nec.c75
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c (renamed from drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim.c (renamed from drivers/media/IR/keymaps/rc-terratec-slim.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-tevii-nec.c (renamed from drivers/media/IR/keymaps/rc-tevii-nec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand.c (renamed from drivers/media/IR/keymaps/rc-total-media-in-hand.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-trekstor.c (renamed from drivers/media/IR/keymaps/rc-trekstor.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c82
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan1027.c (renamed from drivers/media/IR/keymaps/rc-twinhan1027.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-m1f.c92
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-s350.c (renamed from drivers/media/IR/keymaps/rc-videomate-s350.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-tv-pvr.c (renamed from drivers/media/IR/keymaps/rc-videomate-tv-pvr.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c (renamed from drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c (renamed from drivers/media/IR/keymaps/rc-winfast.c)10
-rw-r--r--drivers/media/rc/lirc_dev.c (renamed from drivers/media/IR/lirc_dev.c)37
-rw-r--r--drivers/media/rc/mceusb.c (renamed from drivers/media/IR/mceusb.c)266
-rw-r--r--drivers/media/rc/nuvoton-cir.c (renamed from drivers/media/IR/nuvoton-cir.c)104
-rw-r--r--drivers/media/rc/nuvoton-cir.h (renamed from drivers/media/IR/nuvoton-cir.h)3
-rw-r--r--drivers/media/rc/rc-core-priv.h (renamed from drivers/media/IR/ir-core-priv.h)34
-rw-r--r--drivers/media/rc/rc-loopback.c260
-rw-r--r--drivers/media/rc/rc-main.c1135
-rw-r--r--drivers/media/rc/streamzap.c (renamed from drivers/media/IR/streamzap.c)88
-rw-r--r--drivers/media/rc/winbond-cir.c (renamed from drivers/input/misc/winbond-cir.c)886
-rw-r--r--drivers/media/video/Kconfig38
-rw-r--r--drivers/media/video/Makefile12
-rw-r--r--drivers/media/video/arv.c2
-rw-r--r--drivers/media/video/au0828/au0828-cards.c4
-rw-r--r--drivers/media/video/au0828/au0828-video.c118
-rw-r--r--drivers/media/video/au0828/au0828.h6
-rw-r--r--drivers/media/video/bt8xx/Kconfig4
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c22
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c175
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c243
-rw-r--r--drivers/media/video/bt8xx/bttv.h1
-rw-r--r--drivers/media/video/bt8xx/bttvp.h34
-rw-r--r--drivers/media/video/bw-qcam.c2
-rw-r--r--drivers/media/video/c-qcam.c2
-rw-r--r--drivers/media/video/cafe_ccic.c15
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c38
-rw-r--r--drivers/media/video/cx18/Kconfig3
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.c8
-rw-r--r--drivers/media/video/cx18/cx18-cards.c64
-rw-r--r--drivers/media/video/cx18/cx18-controls.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c19
-rw-r--r--drivers/media/video/cx18/cx18-driver.h13
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c64
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c10
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c6
-rw-r--r--drivers/media/video/cx18/cx18-streams.c47
-rw-r--r--drivers/media/video/cx18/cx18-streams.h3
-rw-r--r--drivers/media/video/cx18/cx23418.h2
-rw-r--r--drivers/media/video/cx231xx/Kconfig19
-rw-r--r--drivers/media/video/cx231xx/Makefile5
-rw-r--r--drivers/media/video/cx231xx/cx231xx-417.c10
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c7
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c77
-rw-r--r--drivers/media/video/cx231xx/cx231xx-core.c12
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c40
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c112
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c12
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h26
-rw-r--r--drivers/media/video/cx2341x.c8
-rw-r--r--drivers/media/video/cx23885/Kconfig2
-rw-r--r--drivers/media/video/cx23885/cimax2.c24
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c9
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c35
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c72
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c42
-rw-r--r--drivers/media/video/cx23885/cx23885.h6
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c19
-rw-r--r--drivers/media/video/cx25840/cx25840-ir.c4
-rw-r--r--drivers/media/video/cx88/Kconfig3
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c99
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c3
-rw-r--r--drivers/media/video/cx88/cx88-cards.c18
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c8
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c1
-rw-r--r--drivers/media/video/cx88/cx88-input.c282
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c8
-rw-r--r--drivers/media/video/cx88/cx88-video.c47
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c1
-rw-r--r--drivers/media/video/cx88/cx88.h6
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c3
-rw-r--r--drivers/media/video/davinci/vpif.h2
-rw-r--r--drivers/media/video/davinci/vpif_capture.c1
-rw-r--r--drivers/media/video/davinci/vpif_display.c2
-rw-r--r--drivers/media/video/davinci/vpss.c2
-rw-r--r--drivers/media/video/em28xx/Kconfig5
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c102
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c16
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c80
-rw-r--r--drivers/media/video/em28xx/em28xx-vbi.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c32
-rw-r--r--drivers/media/video/em28xx/em28xx.h4
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c3
-rw-r--r--drivers/media/video/fsl-viu.c28
-rw-r--r--drivers/media/video/gspca/cpia1.c12
-rw-r--r--drivers/media/video/gspca/gspca.c64
-rw-r--r--drivers/media/video/gspca/gspca.h4
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c2
-rw-r--r--drivers/media/video/gspca/ov519.c1683
-rw-r--r--drivers/media/video/gspca/ov534.c14
-rw-r--r--drivers/media/video/gspca/ov534_9.c1
-rw-r--r--drivers/media/video/gspca/pac207.c4
-rw-r--r--drivers/media/video/gspca/pac7302.c2
-rw-r--r--drivers/media/video/gspca/pac7311.c2
-rw-r--r--drivers/media/video/gspca/sn9c20x.c141
-rw-r--r--drivers/media/video/gspca/sonixb.c236
-rw-r--r--drivers/media/video/gspca/sonixj.c434
-rw-r--r--drivers/media/video/gspca/spca561.c2
-rw-r--r--drivers/media/video/gspca/sq905c.c1
-rw-r--r--drivers/media/video/gspca/sq930x.c28
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c57
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h11
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c18
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_sensor.h4
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.c291
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.h13
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h9
-rw-r--r--drivers/media/video/gspca/t613.c2
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c74
-rw-r--r--drivers/media/video/gspca/w996Xcf.c325
-rw-r--r--drivers/media/video/gspca/xirlink_cit.c194
-rw-r--r--drivers/media/video/gspca/zc3xx.c292
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c53
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h6
-rw-r--r--drivers/media/video/hexium_gemini.c18
-rw-r--r--drivers/media/video/hexium_orion.c18
-rw-r--r--drivers/media/video/imx074.c3
-rw-r--r--drivers/media/video/ir-kbd-i2c.c77
-rw-r--r--drivers/media/video/ivtv/Kconfig3
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c5
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h4
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c28
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c65
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c115
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.h5
-rw-r--r--drivers/media/video/mem2mem_testdev.c21
-rw-r--r--drivers/media/video/meye.c14
-rw-r--r--drivers/media/video/mt9m001.c1
-rw-r--r--drivers/media/video/mt9m111.c1
-rw-r--r--drivers/media/video/mt9t031.c1
-rw-r--r--drivers/media/video/mt9v022.c1
-rw-r--r--drivers/media/video/mx1_camera.c7
-rw-r--r--drivers/media/video/mx2_camera.c18
-rw-r--r--drivers/media/video/mx3_camera.c9
-rw-r--r--drivers/media/video/mxb.c20
-rw-r--r--drivers/media/video/omap/omap_vout.c3
-rw-r--r--drivers/media/video/omap1_camera.c16
-rw-r--r--drivers/media/video/omap24xxcam.c6
-rw-r--r--drivers/media/video/ov2640.c1205
-rw-r--r--drivers/media/video/ov6650.c6
-rw-r--r--drivers/media/video/ov772x.c17
-rw-r--r--drivers/media/video/ov9640.c19
-rw-r--r--drivers/media/video/pms.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c4
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c7
-rw-r--r--drivers/media/video/pwc/pwc-if.c69
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c30
-rw-r--r--drivers/media/video/pwc/pwc.h1
-rw-r--r--drivers/media/video/pxa_camera.c2
-rw-r--r--drivers/media/video/rj54n1cb0c.c1
-rw-r--r--drivers/media/video/s2255drv.c44
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c53
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c56
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h24
-rw-r--r--drivers/media/video/s5p-fimc/regs-fimc.h3
-rw-r--r--drivers/media/video/saa6588.c14
-rw-r--r--drivers/media/video/saa7115.c11
-rw-r--r--drivers/media/video/saa7134/Kconfig2
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c180
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c15
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c69
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c3
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c435
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c26
-rw-r--r--drivers/media/video/saa7134/saa7134.h26
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c123
-rw-r--r--drivers/media/video/saa7164/saa7164-buffer.c92
-rw-r--r--drivers/media/video/saa7164/saa7164-bus.c16
-rw-r--r--drivers/media/video/saa7164/saa7164-cards.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-cmd.c10
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c44
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c33
-rw-r--r--drivers/media/video/saa7164/saa7164-fw.c12
-rw-r--r--drivers/media/video/saa7164/saa7164-i2c.c4
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c37
-rw-r--r--drivers/media/video/saa7164/saa7164.h18
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c4
-rw-r--r--drivers/media/video/sh_vou.c15
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c3
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h4
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h2
-rw-r--r--drivers/media/video/soc_camera.c139
-rw-r--r--drivers/media/video/sr030pc30.c2
-rw-r--r--drivers/media/video/stk-webcam.c152
-rw-r--r--drivers/media/video/tea6415c.c2
-rw-r--r--drivers/media/video/timblogiw.c893
-rw-r--r--drivers/media/video/tlg2300/Kconfig4
-rw-r--r--drivers/media/video/tlg2300/pd-main.c16
-rw-r--r--drivers/media/video/tvp7002.c2
-rw-r--r--drivers/media/video/usbvideo/Kconfig45
-rw-r--r--drivers/media/video/usbvideo/Makefile4
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c3977
-rw-r--r--drivers/media/video/usbvideo/konicawc.c992
-rw-r--r--drivers/media/video/usbvideo/ultracam.c685
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c1860
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c1635
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c61
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c626
-rw-r--r--drivers/media/video/usbvision/usbvision.h267
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c48
-rw-r--r--drivers/media/video/uvc/uvc_queue.c133
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c192
-rw-r--r--drivers/media/video/uvc/uvc_video.c3
-rw-r--r--drivers/media/video/uvc/uvcvideo.h10
-rw-r--r--drivers/media/video/v4l1-compat.c1277
-rw-r--r--drivers/media/video/v4l2-common.c21
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c331
-rw-r--r--drivers/media/video/v4l2-ctrls.c55
-rw-r--r--drivers/media/video/v4l2-dev.c72
-rw-r--r--drivers/media/video/v4l2-device.c1
-rw-r--r--drivers/media/video/v4l2-ioctl.c86
-rw-r--r--drivers/media/video/via-camera.c17
-rw-r--r--drivers/media/video/videobuf-core.c30
-rw-r--r--drivers/media/video/videobuf-dma-sg.c34
-rw-r--r--drivers/media/video/vino.c7
-rw-r--r--drivers/media/video/vivi.c12
-rw-r--r--drivers/media/video/w9966.c2
-rw-r--r--drivers/media/video/wm8775.c104
-rw-r--r--drivers/media/video/zoran/zoran.h108
-rw-r--r--drivers/media/video/zoran/zoran_card.c8
-rw-r--r--drivers/media/video/zoran/zoran_device.c2
-rw-r--r--drivers/media/video/zoran/zoran_driver.c355
-rw-r--r--drivers/memstick/core/memstick.c19
-rw-r--r--drivers/memstick/core/mspro_block.c151
-rw-r--r--drivers/memstick/host/jmb38x_ms.c120
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h2
-rw-r--r--drivers/message/fusion/mptbase.c2
-rw-r--r--drivers/message/fusion/mptfc.c7
-rw-r--r--drivers/message/fusion/mptsas.c6
-rw-r--r--drivers/message/fusion/mptspi.c4
-rw-r--r--drivers/message/i2o/i2o_block.c2
-rw-r--r--drivers/message/i2o/i2o_scsi.c6
-rw-r--r--drivers/mfd/88pm860x-core.c36
-rw-r--r--drivers/mfd/Kconfig32
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/ab3550-core.c28
-rw-r--r--drivers/mfd/ab8500-core.c308
-rw-r--r--drivers/mfd/ab8500-debugfs.c1016
-rw-r--r--drivers/mfd/ab8500-spi.c143
-rw-r--r--drivers/mfd/asic3.c62
-rw-r--r--drivers/mfd/cs5535-mfd.c151
-rw-r--r--drivers/mfd/ezx-pcap.c25
-rw-r--r--drivers/mfd/htc-egpio.c27
-rw-r--r--drivers/mfd/htc-i2cpld.c40
-rw-r--r--drivers/mfd/jz4740-adc.c25
-rw-r--r--drivers/mfd/max8925-core.c30
-rw-r--r--drivers/mfd/max8998-irq.c37
-rw-r--r--drivers/mfd/max8998.c134
-rw-r--r--drivers/mfd/mc13xxx-core.c2
-rw-r--r--drivers/mfd/menelaus.c3
-rw-r--r--drivers/mfd/mfd-core.c4
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c6
-rw-r--r--drivers/mfd/sm501.c9
-rw-r--r--drivers/mfd/stmpe.c28
-rw-r--r--drivers/mfd/t7l66xb.c20
-rw-r--r--drivers/mfd/tc35892.c345
-rw-r--r--drivers/mfd/tc3589x.c422
-rw-r--r--drivers/mfd/tc6393xb.c22
-rw-r--r--drivers/mfd/timberdale.c61
-rw-r--r--drivers/mfd/timberdale.h2
-rw-r--r--drivers/mfd/tps65010.c15
-rw-r--r--drivers/mfd/tps6586x.c36
-rw-r--r--drivers/mfd/twl-core.c46
-rw-r--r--drivers/mfd/twl4030-irq.c28
-rw-r--r--drivers/mfd/twl6030-irq.c11
-rw-r--r--drivers/mfd/vx855.c2
-rw-r--r--drivers/mfd/wl1273-core.c148
-rw-r--r--drivers/mfd/wm831x-core.c25
-rw-r--r--drivers/mfd/wm831x-i2c.c14
-rw-r--r--drivers/mfd/wm831x-irq.c53
-rw-r--r--drivers/mfd/wm831x-spi.c18
-rw-r--r--drivers/mfd/wm8350-irq.c32
-rw-r--r--drivers/mfd/wm8994-core.c139
-rw-r--r--drivers/mfd/wm8994-irq.c32
-rw-r--r--drivers/misc/Kconfig4
-rw-r--r--drivers/misc/apds9802als.c3
-rw-r--r--drivers/misc/arm-charlcd.c2
-rw-r--r--drivers/misc/bh1770glc.c8
-rw-r--r--drivers/misc/cs5535-mfgpt.c73
-rw-r--r--drivers/misc/eeprom/at24.c43
-rw-r--r--drivers/misc/ioc4.c29
-rw-r--r--drivers/misc/isl29020.c8
-rw-r--r--drivers/misc/sgi-xp/xpc_partition.c25
-rw-r--r--drivers/misc/vmw_balloon.c13
-rw-r--r--drivers/mmc/card/Kconfig1
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/Kconfig11
-rw-r--r--drivers/mmc/core/bus.c8
-rw-r--r--drivers/mmc/core/core.c211
-rw-r--r--drivers/mmc/core/core.h9
-rw-r--r--drivers/mmc/core/debugfs.c5
-rw-r--r--drivers/mmc/core/host.c206
-rw-r--r--drivers/mmc/core/host.h21
-rw-r--r--drivers/mmc/core/mmc.c87
-rw-r--r--drivers/mmc/core/mmc_ops.c101
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c16
-rw-r--r--drivers/mmc/core/sdio.c87
-rw-r--r--drivers/mmc/core/sdio_bus.c57
-rw-r--r--drivers/mmc/host/Kconfig43
-rw-r--r--drivers/mmc/host/Makefile3
-rw-r--r--drivers/mmc/host/at91_mci.c13
-rw-r--r--drivers/mmc/host/atmel-mci.c18
-rw-r--r--drivers/mmc/host/au1xmmc.c2
-rw-r--r--drivers/mmc/host/davinci_mmc.c80
-rw-r--r--drivers/mmc/host/dw_mmc.c1796
-rw-r--r--drivers/mmc/host/dw_mmc.h168
-rw-r--r--drivers/mmc/host/mmci.c207
-rw-r--r--drivers/mmc/host/mmci.h9
-rw-r--r--drivers/mmc/host/msm_sdcc.c139
-rw-r--r--drivers/mmc/host/msm_sdcc.h8
-rw-r--r--drivers/mmc/host/mxcmmc.c53
-rw-r--r--drivers/mmc/host/omap.c24
-rw-r--r--drivers/mmc/host/omap_hsmmc.c4
-rw-r--r--drivers/mmc/host/sdhci-dove.c70
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c12
-rw-r--r--drivers/mmc/host/sdhci-of-core.c13
-rw-r--r--drivers/mmc/host/sdhci-pci.c192
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c6
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h2
-rw-r--r--drivers/mmc/host/sdhci-pxa.c4
-rw-r--r--drivers/mmc/host/sdhci-s3c.c66
-rw-r--r--drivers/mmc/host/sdhci-tegra.c257
-rw-r--r--drivers/mmc/host/sdhci.c99
-rw-r--r--drivers/mmc/host/sdhci.h12
-rw-r--r--drivers/mmc/host/sdricoh_cs.c4
-rw-r--r--drivers/mmc/host/sh_mmcif.c429
-rw-r--r--drivers/mmc/host/tmio_mmc.c561
-rw-r--r--drivers/mmc/host/tmio_mmc.h228
-rw-r--r--drivers/mmc/host/ushc.c30
-rw-r--r--drivers/mtd/devices/block2mtd.c10
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c2
-rw-r--r--drivers/mtd/mtdchar.c2
-rw-r--r--drivers/mtd/mtdoops.c5
-rw-r--r--drivers/mtd/nand/nand_base.c2
-rw-r--r--drivers/mtd/nand/omap2.c1
-rw-r--r--drivers/mtd/onenand/omap2.c3
-rw-r--r--drivers/mtd/ubi/io.c37
-rw-r--r--drivers/mtd/ubi/scan.c20
-rw-r--r--drivers/net/3c501.c4
-rw-r--r--drivers/net/3c503.c4
-rw-r--r--drivers/net/3c507.c6
-rw-r--r--drivers/net/3c515.c2
-rw-r--r--drivers/net/3c527.c6
-rw-r--r--drivers/net/3c59x.c6
-rw-r--r--drivers/net/8139cp.c10
-rw-r--r--drivers/net/8139too.c3
-rw-r--r--drivers/net/82596.c2
-rw-r--r--drivers/net/Kconfig287
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/Space.c5
-rw-r--r--drivers/net/arm/am79c961a.c9
-rw-r--r--drivers/net/arm/ixp4xx_eth.c4
-rw-r--r--drivers/net/arm/ks8695net.c288
-rw-r--r--drivers/net/arm/w90p910_ether.c2
-rw-r--r--drivers/net/at1700.c8
-rw-r--r--drivers/net/atarilance.c2
-rw-r--r--drivers/net/atl1c/atl1c_hw.c2
-rw-r--r--drivers/net/atl1c/atl1c_main.c41
-rw-r--r--drivers/net/atl1e/atl1e_main.c2
-rw-r--r--drivers/net/atlx/atl1.c13
-rw-r--r--drivers/net/atlx/atl2.c4
-rw-r--r--drivers/net/au1000_eth.c12
-rw-r--r--drivers/net/ax88796.c8
-rw-r--r--drivers/net/b44.c11
-rw-r--r--drivers/net/bcm63xx_enet.c2
-rw-r--r--drivers/net/benet/be.h41
-rw-r--r--drivers/net/benet/be_cmds.c146
-rw-r--r--drivers/net/benet/be_cmds.h42
-rw-r--r--drivers/net/benet/be_ethtool.c4
-rw-r--r--drivers/net/benet/be_hw.h39
-rw-r--r--drivers/net/benet/be_main.c260
-rw-r--r--drivers/net/bfin_mac.c83
-rw-r--r--drivers/net/bfin_mac.h11
-rw-r--r--drivers/net/bna/bfa_defs.h22
-rw-r--r--drivers/net/bna/bfa_defs_mfg_comm.h22
-rw-r--r--drivers/net/bna/bfa_ioc.c1219
-rw-r--r--drivers/net/bna/bfa_ioc.h49
-rw-r--r--drivers/net/bna/bfa_ioc_ct.c102
-rw-r--r--drivers/net/bna/bfi_ctreg.h41
-rw-r--r--drivers/net/bna/bna.h6
-rw-r--r--drivers/net/bna/bna_ctrl.c377
-rw-r--r--drivers/net/bna/bna_txrx.c44
-rw-r--r--drivers/net/bna/bna_types.h11
-rw-r--r--drivers/net/bna/bnad.c427
-rw-r--r--drivers/net/bna/bnad.h31
-rw-r--r--drivers/net/bna/bnad_ethtool.c9
-rw-r--r--drivers/net/bnx2.c121
-rw-r--r--drivers/net/bnx2.h2
-rw-r--r--drivers/net/bnx2x/Makefile2
-rw-r--r--drivers/net/bnx2x/bnx2x.h166
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c199
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.h73
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.c2118
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.h196
-rw-r--r--drivers/net/bnx2x/bnx2x_dump.h988
-rw-r--r--drivers/net/bnx2x/bnx2x_ethtool.c379
-rw-r--r--drivers/net/bnx2x/bnx2x_hsi.h336
-rw-r--r--drivers/net/bnx2x/bnx2x_init.h220
-rw-r--r--drivers/net/bnx2x/bnx2x_init_ops.h4
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c723
-rw-r--r--drivers/net/bnx2x/bnx2x_link.h56
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c774
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h128
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.c18
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.h2
-rw-r--r--drivers/net/bonding/Makefile2
-rw-r--r--drivers/net/bonding/bond_3ad.c9
-rw-r--r--drivers/net/bonding/bond_alb.c36
-rw-r--r--drivers/net/bonding/bond_alb.h38
-rw-r--r--drivers/net/bonding/bond_debugfs.c146
-rw-r--r--drivers/net/bonding/bond_ipv6.c7
-rw-r--r--drivers/net/bonding/bond_main.c87
-rw-r--r--drivers/net/bonding/bonding.h28
-rw-r--r--drivers/net/caif/caif_shm_u5500.c4
-rw-r--r--drivers/net/caif/caif_shmcore.c2
-rw-r--r--drivers/net/caif/caif_spi.c61
-rw-r--r--drivers/net/caif/caif_spi_slave.c13
-rw-r--r--drivers/net/can/Kconfig21
-rw-r--r--drivers/net/can/Makefile1
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/janz-ican3.c9
-rw-r--r--drivers/net/can/mscan/mscan.c2
-rw-r--r--drivers/net/can/pch_can.c1360
-rw-r--r--drivers/net/can/sja1000/plx_pci.c2
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c8
-rw-r--r--drivers/net/can/slcan.c756
-rw-r--r--drivers/net/cassini.c22
-rw-r--r--drivers/net/cassini.h3
-rw-r--r--drivers/net/chelsio/my3126.c2
-rw-r--r--drivers/net/chelsio/sge.c10
-rw-r--r--drivers/net/chelsio/subr.c2
-rw-r--r--drivers/net/cnic.c782
-rw-r--r--drivers/net/cnic.h27
-rw-r--r--drivers/net/cnic_defs.h2095
-rw-r--r--drivers/net/cnic_if.h26
-rw-r--r--drivers/net/cris/eth_v10.c34
-rw-r--r--drivers/net/cxgb3/ael1002.c24
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c7
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c6
-rw-r--r--drivers/net/cxgb3/mc5.c2
-rw-r--r--drivers/net/cxgb3/t3_hw.c4
-rw-r--r--drivers/net/cxgb4/cxgb4.h4
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c141
-rw-r--r--drivers/net/cxgb4/sge.c22
-rw-r--r--drivers/net/cxgb4/t4_hw.c95
-rw-r--r--drivers/net/cxgb4/t4fw_api.h1
-rw-r--r--drivers/net/cxgb4vf/adapter.h2
-rw-r--r--drivers/net/cxgb4vf/cxgb4vf_main.c176
-rw-r--r--drivers/net/cxgb4vf/sge.c131
-rw-r--r--drivers/net/cxgb4vf/t4vf_common.h1
-rw-r--r--drivers/net/cxgb4vf/t4vf_hw.c131
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dm9000.c2
-rw-r--r--drivers/net/e1000/e1000_hw.c348
-rw-r--r--drivers/net/e1000/e1000_hw.h61
-rw-r--r--drivers/net/e1000/e1000_main.c77
-rw-r--r--drivers/net/e1000/e1000_osdep.h19
-rw-r--r--drivers/net/e1000/e1000_param.c13
-rw-r--r--drivers/net/e1000e/82571.c270
-rw-r--r--drivers/net/e1000e/Makefile2
-rw-r--r--drivers/net/e1000e/defines.h11
-rw-r--r--drivers/net/e1000e/e1000.h9
-rw-r--r--drivers/net/e1000e/es2lan.c14
-rw-r--r--drivers/net/e1000e/ethtool.c203
-rw-r--r--drivers/net/e1000e/hw.h5
-rw-r--r--drivers/net/e1000e/ich8lan.c104
-rw-r--r--drivers/net/e1000e/lib.c164
-rw-r--r--drivers/net/e1000e/netdev.c381
-rw-r--r--drivers/net/e1000e/param.c8
-rw-r--r--drivers/net/e1000e/phy.c96
-rw-r--r--drivers/net/e2100.c2
-rw-r--r--drivers/net/eepro.c13
-rw-r--r--drivers/net/eexpress.c2
-rw-r--r--drivers/net/ehea/ehea.h17
-rw-r--r--drivers/net/ehea/ehea_ethtool.c34
-rw-r--r--drivers/net/ehea/ehea_main.c454
-rw-r--r--drivers/net/ehea/ehea_phyp.c40
-rw-r--r--drivers/net/ehea/ehea_qmr.c89
-rw-r--r--drivers/net/enic/enic.h6
-rw-r--r--drivers/net/enic/enic_main.c250
-rw-r--r--drivers/net/enic/enic_res.h1
-rw-r--r--drivers/net/enic/vnic_vic.h31
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/ethoc.c160
-rw-r--r--drivers/net/fec.c248
-rw-r--r--drivers/net/fec.h5
-rw-r--r--drivers/net/fec_mpc52xx.c19
-rw-r--r--drivers/net/forcedeth.c1168
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/gianfar.c28
-rw-r--r--drivers/net/gianfar.h10
-rw-r--r--drivers/net/gianfar_ethtool.c5
-rw-r--r--drivers/net/greth.c221
-rw-r--r--drivers/net/greth.h2
-rw-r--r--drivers/net/hamachi.c4
-rw-r--r--drivers/net/hamradio/yam.c4
-rw-r--r--drivers/net/hp.c6
-rw-r--r--drivers/net/ibm_newemac/core.c7
-rw-r--r--drivers/net/ibmveth.c7
-rw-r--r--drivers/net/ifb.c48
-rw-r--r--drivers/net/igb/e1000_82575.c37
-rw-r--r--drivers/net/igb/e1000_82575.h5
-rw-r--r--drivers/net/igb/e1000_defines.h7
-rw-r--r--drivers/net/igb/e1000_hw.h6
-rw-r--r--drivers/net/igb/e1000_nvm.c93
-rw-r--r--drivers/net/igb/e1000_nvm.h2
-rw-r--r--drivers/net/igb/e1000_phy.c11
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb.h1
-rw-r--r--drivers/net/igb/igb_main.c100
-rw-r--r--drivers/net/igbvf/Makefile2
-rw-r--r--drivers/net/igbvf/defines.h2
-rw-r--r--drivers/net/igbvf/ethtool.c9
-rw-r--r--drivers/net/igbvf/igbvf.h4
-rw-r--r--drivers/net/igbvf/mbx.c2
-rw-r--r--drivers/net/igbvf/mbx.h2
-rw-r--r--drivers/net/igbvf/netdev.c33
-rw-r--r--drivers/net/igbvf/regs.h2
-rw-r--r--drivers/net/igbvf/vf.c6
-rw-r--r--drivers/net/igbvf/vf.h4
-rw-r--r--drivers/net/ipg.c6
-rw-r--r--drivers/net/irda/act200l-sir.c2
-rw-r--r--drivers/net/irda/bfin_sir.h2
-rw-r--r--drivers/net/irda/donauboe.c4
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/irda/mcs7780.c2
-rw-r--r--drivers/net/irda/sh_sir.c2
-rw-r--r--drivers/net/irda/smsc-ircc2.c2
-rw-r--r--drivers/net/iseries_veth.c27
-rw-r--r--drivers/net/ixgb/ixgb_main.c61
-rw-r--r--drivers/net/ixgb/ixgb_param.c21
-rw-r--r--drivers/net/ixgbe/Makefile2
-rw-r--r--drivers/net/ixgbe/ixgbe.h143
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c58
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c891
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c256
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h10
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb.c17
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb.h3
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82598.c12
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.c12
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c55
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c439
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c15
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c2296
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.c42
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.h2
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.c52
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.h5
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c57
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h136
-rw-r--r--drivers/net/ixgbe/ixgbe_x540.c724
-rw-r--r--drivers/net/ixgbevf/Makefile2
-rw-r--r--drivers/net/ixgbevf/defines.h3
-rw-r--r--drivers/net/ixgbevf/ethtool.c18
-rw-r--r--drivers/net/ixgbevf/ixgbevf.h6
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c27
-rw-r--r--drivers/net/ixgbevf/mbx.c2
-rw-r--r--drivers/net/ixgbevf/mbx.h2
-rw-r--r--drivers/net/ixgbevf/regs.h2
-rw-r--r--drivers/net/ixgbevf/vf.c8
-rw-r--r--drivers/net/ixgbevf/vf.h3
-rw-r--r--drivers/net/jme.c24
-rw-r--r--drivers/net/ks8851.c33
-rw-r--r--drivers/net/ksz884x.c22
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lib82596.c2
-rw-r--r--drivers/net/lib8390.c24
-rw-r--r--drivers/net/ll_temac_main.c6
-rw-r--r--drivers/net/macvlan.c113
-rw-r--r--drivers/net/macvtap.c5
-rw-r--r--drivers/net/mlx4/alloc.c3
-rw-r--r--drivers/net/mlx4/en_netdev.c3
-rw-r--r--drivers/net/mlx4/fw.c2
-rw-r--r--drivers/net/mv643xx_eth.c9
-rw-r--r--drivers/net/myri10ge/myri10ge.c8
-rw-r--r--drivers/net/ne-h8300.c12
-rw-r--r--drivers/net/netconsole.c8
-rw-r--r--drivers/net/netxen/netxen_nic.h5
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c26
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c21
-rw-r--r--drivers/net/netxen/netxen_nic_init.c7
-rw-r--r--drivers/net/netxen/netxen_nic_main.c16
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c4
-rw-r--r--drivers/net/niu.c4
-rw-r--r--drivers/net/pch_gbe/pch_gbe_ethtool.c19
-rw-r--r--drivers/net/pch_gbe/pch_gbe_main.c18
-rw-r--r--drivers/net/pch_gbe/pch_gbe_param.c8
-rw-r--r--drivers/net/pcmcia/axnet_cs.c49
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c3
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/icplus.c59
-rw-r--r--drivers/net/phy/marvell.c182
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/ppp_async.c10
-rw-r--r--drivers/net/ppp_deflate.c9
-rw-r--r--drivers/net/ppp_generic.c73
-rw-r--r--drivers/net/ppp_mppe.c7
-rw-r--r--drivers/net/ppp_synctty.c3
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--drivers/net/pptp.c5
-rw-r--r--drivers/net/pxa168_eth.c9
-rw-r--r--drivers/net/qla3xxx.c8
-rw-r--r--drivers/net/qlcnic/qlcnic.h63
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c28
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c159
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h27
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c91
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c186
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c100
-rw-r--r--drivers/net/qlge/qlge.h5
-rw-r--r--drivers/net/qlge/qlge_dbg.c21
-rw-r--r--drivers/net/qlge/qlge_ethtool.c19
-rw-r--r--drivers/net/qlge/qlge_main.c28
-rw-r--r--drivers/net/qlge/qlge_mpi.c14
-rw-r--r--drivers/net/r6040.c2
-rw-r--r--drivers/net/r8169.c1806
-rw-r--r--drivers/net/s2io.c79
-rw-r--r--drivers/net/s2io.h9
-rw-r--r--drivers/net/sc92031.c3
-rw-r--r--drivers/net/sfc/efx.c99
-rw-r--r--drivers/net/sfc/efx.h7
-rw-r--r--drivers/net/sfc/ethtool.c168
-rw-r--r--drivers/net/sfc/falcon.c208
-rw-r--r--drivers/net/sfc/falcon_boards.c120
-rw-r--r--drivers/net/sfc/falcon_xmac.c14
-rw-r--r--drivers/net/sfc/filter.c255
-rw-r--r--drivers/net/sfc/filter.h149
-rw-r--r--drivers/net/sfc/io.h153
-rw-r--r--drivers/net/sfc/mcdi.c3
-rw-r--r--drivers/net/sfc/mcdi_phy.c1
-rw-r--r--drivers/net/sfc/mdio_10g.c1
-rw-r--r--drivers/net/sfc/mtd.c98
-rw-r--r--drivers/net/sfc/net_driver.h99
-rw-r--r--drivers/net/sfc/nic.c96
-rw-r--r--drivers/net/sfc/nic.h12
-rw-r--r--drivers/net/sfc/qt202x_phy.c6
-rw-r--r--drivers/net/sfc/rx.c30
-rw-r--r--drivers/net/sfc/siena.c10
-rw-r--r--drivers/net/sfc/spi.h5
-rw-r--r--drivers/net/sfc/tenxpress.c2
-rw-r--r--drivers/net/sfc/tx.c122
-rw-r--r--drivers/net/sh_eth.c245
-rw-r--r--drivers/net/sh_eth.h1
-rw-r--r--drivers/net/sis190.c3
-rw-r--r--drivers/net/sis900.c2
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/skfp/smt.c4
-rw-r--r--drivers/net/skge.c55
-rw-r--r--drivers/net/sky2.c300
-rw-r--r--drivers/net/sky2.h48
-rw-r--r--drivers/net/smc-ultra.c8
-rw-r--r--drivers/net/smsc911x.h2
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/stmmac/stmmac.h40
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c16
-rw-r--r--drivers/net/stmmac/stmmac_main.c271
-rw-r--r--drivers/net/stmmac/stmmac_mdio.c8
-rw-r--r--drivers/net/sundance.c27
-rw-r--r--drivers/net/sungem.c14
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/sunlance.c10
-rw-r--r--drivers/net/tehuti.c10
-rw-r--r--drivers/net/tg3.c424
-rw-r--r--drivers/net/tg3.h42
-rw-r--r--drivers/net/tile/Makefile10
-rw-r--r--drivers/net/tile/tilepro.c2398
-rw-r--r--drivers/net/tokenring/ibmtr.c5
-rw-r--r--drivers/net/tulip/de2104x.c19
-rw-r--r--drivers/net/tulip/dmfe.c6
-rw-r--r--drivers/net/tulip/tulip_core.c15
-rw-r--r--drivers/net/tun.c4
-rw-r--r--drivers/net/typhoon.c1
-rw-r--r--drivers/net/ucc_geth.c28
-rw-r--r--drivers/net/ucc_geth.h3
-rw-r--r--drivers/net/usb/Kconfig19
-rw-r--r--drivers/net/usb/Makefile1
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/usb/cdc_ether.c4
-rw-r--r--drivers/net/usb/cdc_ncm.c1215
-rw-r--r--drivers/net/usb/hso.c54
-rw-r--r--drivers/net/usb/ipheth.c2
-rw-r--r--drivers/net/usb/mcs7830.c14
-rw-r--r--drivers/net/usb/pegasus.c4
-rw-r--r--drivers/net/usb/sierra_net.c5
-rw-r--r--drivers/net/usb/smsc95xx.c7
-rw-r--r--drivers/net/usb/usbnet.c59
-rw-r--r--drivers/net/veth.c4
-rw-r--r--drivers/net/via-rhine.c326
-rw-r--r--drivers/net/via-velocity.c2
-rw-r--r--drivers/net/virtio_net.c14
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c967
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c174
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h81
-rw-r--r--drivers/net/vxge/vxge-config.c3604
-rw-r--r--drivers/net/vxge/vxge-config.h169
-rw-r--r--drivers/net/vxge/vxge-ethtool.c112
-rw-r--r--drivers/net/vxge/vxge-main.c1107
-rw-r--r--drivers/net/vxge/vxge-main.h86
-rw-r--r--drivers/net/vxge/vxge-reg.h33
-rw-r--r--drivers/net/vxge/vxge-traffic.c775
-rw-r--r--drivers/net/vxge/vxge-traffic.h51
-rw-r--r--drivers/net/vxge/vxge-version.h33
-rw-r--r--drivers/net/wan/dscc4.c8
-rw-r--r--drivers/net/wan/hd64572.c5
-rw-r--r--drivers/net/wan/x25_asy.c13
-rw-r--r--drivers/net/wd.c2
-rw-r--r--drivers/net/wimax/i2400m/driver.c98
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h23
-rw-r--r--drivers/net/wimax/i2400m/sdio.c1
-rw-r--r--drivers/net/wimax/i2400m/usb.c3
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/airo.c20
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c2
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c6
-rw-r--r--drivers/net/wireless/ath/ath.h111
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig18
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c219
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c40
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h292
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c28
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c1576
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h7
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c6
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c34
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c24
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.h18
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c180
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c139
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c409
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c11
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c774
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c327
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c571
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c754
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c696
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h37
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c1221
-rw-r--r--drivers/net/wireless/ath/ath5k/rfbuffer.h1169
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c107
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c305
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c223
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c144
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h104
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c605
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c3201
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.h82
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c289
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c123
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c166
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c344
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h78
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9485_initvals.h943
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h73
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c132
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c59
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h15
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c83
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h21
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c225
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h90
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c302
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c295
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c374
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c266
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h39
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c342
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c118
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c683
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c46
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c305
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h82
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c175
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c211
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h14
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c620
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c110
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c96
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c126
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h31
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c32
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c856
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h5
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c3
-rw-r--r--drivers/net/wireless/ath/carl9170/fwcmd.h13
-rw-r--r--drivers/net/wireless/ath/carl9170/hw.h7
-rw-r--r--drivers/net/wireless/ath/carl9170/mac.c56
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c24
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.c27
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.h24
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c82
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c66
-rw-r--r--drivers/net/wireless/ath/carl9170/version.h6
-rw-r--r--drivers/net/wireless/ath/debug.c15
-rw-r--r--drivers/net/wireless/ath/debug.h90
-rw-r--r--drivers/net/wireless/ath/key.c39
-rw-r--r--drivers/net/wireless/ath/main.c20
-rw-r--r--drivers/net/wireless/ath/regd.c8
-rw-r--r--drivers/net/wireless/atmel.c6
-rw-r--r--drivers/net/wireless/b43/Kconfig13
-rw-r--r--drivers/net/wireless/b43/Makefile8
-rw-r--r--drivers/net/wireless/b43/b43.h21
-rw-r--r--drivers/net/wireless/b43/dma.c5
-rw-r--r--drivers/net/wireless/b43/main.c68
-rw-r--r--drivers/net/wireless/b43/phy_common.c22
-rw-r--r--drivers/net/wireless/b43/phy_common.h8
-rw-r--r--drivers/net/wireless/b43/phy_g.c2
-rw-r--r--drivers/net/wireless/b43/phy_n.c594
-rw-r--r--drivers/net/wireless/b43/phy_n.h2
-rw-r--r--drivers/net/wireless/b43/radio_2055.c502
-rw-r--r--drivers/net/wireless/b43/radio_2056.c9062
-rw-r--r--drivers/net/wireless/b43/radio_2056.h1084
-rw-r--r--drivers/net/wireless/b43/rfkill.c19
-rw-r--r--drivers/net/wireless/b43/sdio.c1
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c228
-rw-r--r--drivers/net/wireless/b43legacy/main.c47
-rw-r--r--drivers/net/wireless/b43legacy/phy.c2
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c3
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c15
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c8
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c1
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c7
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c9
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig3
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c97
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c369
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c140
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c465
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c230
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c373
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ict.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c136
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c642
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c160
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c618
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h61
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c971
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h96
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h91
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h51
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-legacy.c662
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-legacy.h79
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c190
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c66
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c91
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c2
-rw-r--r--drivers/net/wireless/libertas/cfg.c14
-rw-r--r--drivers/net/wireless/libertas/cmd.c8
-rw-r--r--drivers/net/wireless/libertas/dev.h2
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c1
-rw-r--r--drivers/net/wireless/libertas/if_spi.c3
-rw-r--r--drivers/net/wireless/libertas/if_usb.c13
-rw-r--r--drivers/net/wireless/libertas/main.c12
-rw-r--r--drivers/net/wireless/libertas/rx.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c5
-rw-r--r--drivers/net/wireless/mwl8k.c670
-rw-r--r--drivers/net/wireless/orinoco/main.c18
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c14
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c1
-rw-r--r--drivers/net/wireless/orinoco/scan.c8
-rw-r--r--drivers/net/wireless/orinoco/scan.h1
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c14
-rw-r--r--drivers/net/wireless/orinoco/wext.c12
-rw-r--r--drivers/net/wireless/p54/p54usb.c8
-rw-r--r--drivers/net/wireless/p54/txrx.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c6
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/ray_cs.c18
-rw-r--r--drivers/net/wireless/rndis_wlan.c402
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig75
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c144
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c150
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c98
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h218
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c223
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c215
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c363
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h114
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c104
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c63
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c270
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h74
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c305
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c185
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h64
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c107
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h38
-rw-r--r--drivers/net/wireless/rtl818x/Makefile9
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/Makefile5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c (renamed from drivers/net/wireless/rtl818x/rtl8180_dev.c)8
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/grf5101.c (renamed from drivers/net/wireless/rtl818x/rtl8180_grf5101.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/grf5101.h (renamed from drivers/net/wireless/rtl818x/rtl8180_grf5101.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/max2820.c (renamed from drivers/net/wireless/rtl818x/rtl8180_max2820.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/max2820.h (renamed from drivers/net/wireless/rtl818x/rtl8180_max2820.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8180.h (renamed from drivers/net/wireless/rtl818x/rtl8180.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225.c (renamed from drivers/net/wireless/rtl818x/rtl8180_rtl8225.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225.h (renamed from drivers/net/wireless/rtl818x/rtl8180_rtl8225.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/sa2400.c (renamed from drivers/net/wireless/rtl818x/rtl8180_sa2400.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/sa2400.h (renamed from drivers/net/wireless/rtl818x/rtl8180_sa2400.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/Makefile5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c (renamed from drivers/net/wireless/rtl818x/rtl8187_dev.c)146
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/leds.c (renamed from drivers/net/wireless/rtl818x/rtl8187_leds.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/leds.h (renamed from drivers/net/wireless/rtl818x/rtl8187_leds.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rfkill.c (renamed from drivers/net/wireless/rtl818x/rtl8187_rfkill.c)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rfkill.h (renamed from drivers/net/wireless/rtl818x/rtl8187_rfkill.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8187.h (renamed from drivers/net/wireless/rtl818x/rtl8187.h)2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8225.c (renamed from drivers/net/wireless/rtl818x/rtl8187_rtl8225.c)24
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8225.h (renamed from drivers/net/wireless/rtl818x/rtl8187_rtl8225.h)0
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig15
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile13
-rw-r--r--drivers/net/wireless/rtlwifi/base.c956
-rw-r--r--drivers/net/wireless/rtlwifi/base.h120
-rw-r--r--drivers/net/wireless/rtlwifi/cam.c291
-rw-r--r--drivers/net/wireless/rtlwifi/cam.h53
-rw-r--r--drivers/net/wireless/rtlwifi/core.c1029
-rw-r--r--drivers/net/wireless/rtlwifi/core.h42
-rw-r--r--drivers/net/wireless/rtlwifi/debug.c50
-rw-r--r--drivers/net/wireless/rtlwifi/debug.h212
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.c1189
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.h124
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c1945
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h302
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c493
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h43
-rw-r--r--drivers/net/wireless/rtlwifi/rc.c329
-rw-r--r--drivers/net/wireless/rtlwifi/rc.h40
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c400
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h61
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/Makefile12
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/def.h257
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.c1473
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.h196
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/fw.c804
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/fw.h98
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c2162
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.h57
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/led.c144
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/led.h41
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.c2676
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.h237
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/reg.h2065
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/rf.c523
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/rf.h44
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c282
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.h37
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/table.c1224
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/table.h58
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c1031
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.h714
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1532
-rw-r--r--drivers/net/wireless/wl1251/acx.h4
-rw-r--r--drivers/net/wireless/wl1251/boot.c1
-rw-r--r--drivers/net/wireless/wl1251/main.c15
-rw-r--r--drivers/net/wireless/wl1251/sdio.c103
-rw-r--r--drivers/net/wireless/wl1251/spi.c9
-rw-r--r--drivers/net/wireless/wl1251/wl1251.h3
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig64
-rw-r--r--drivers/net/wireless/wl12xx/Makefile22
-rw-r--r--drivers/net/wireless/wl12xx/acx.c (renamed from drivers/net/wireless/wl12xx/wl1271_acx.c)99
-rw-r--r--drivers/net/wireless/wl12xx/acx.h (renamed from drivers/net/wireless/wl12xx/wl1271_acx.h)112
-rw-r--r--drivers/net/wireless/wl12xx/boot.c (renamed from drivers/net/wireless/wl12xx/wl1271_boot.c)38
-rw-r--r--drivers/net/wireless/wl12xx/boot.h (renamed from drivers/net/wireless/wl12xx/wl1271_boot.h)3
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c (renamed from drivers/net/wireless/wl12xx/wl1271_cmd.c)81
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h (renamed from drivers/net/wireless/wl12xx/wl1271_cmd.h)58
-rw-r--r--drivers/net/wireless/wl12xx/conf.h (renamed from drivers/net/wireless/wl12xx/wl1271_conf.h)4
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c480
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.h (renamed from drivers/net/wireless/wl12xx/wl1271_debugfs.h)6
-rw-r--r--drivers/net/wireless/wl12xx/event.c (renamed from drivers/net/wireless/wl12xx/wl1271_event.c)14
-rw-r--r--drivers/net/wireless/wl12xx/event.h (renamed from drivers/net/wireless/wl12xx/wl1271_event.h)4
-rw-r--r--drivers/net/wireless/wl12xx/ini.h (renamed from drivers/net/wireless/wl12xx/wl1271_ini.h)4
-rw-r--r--drivers/net/wireless/wl12xx/init.c (renamed from drivers/net/wireless/wl12xx/wl1271_init.c)23
-rw-r--r--drivers/net/wireless/wl12xx/init.h (renamed from drivers/net/wireless/wl12xx/wl1271_init.h)6
-rw-r--r--drivers/net/wireless/wl12xx/io.c (renamed from drivers/net/wireless/wl12xx/wl1271_io.c)5
-rw-r--r--drivers/net/wireless/wl12xx/io.h (renamed from drivers/net/wireless/wl12xx/wl1271_io.h)6
-rw-r--r--drivers/net/wireless/wl12xx/main.c (renamed from drivers/net/wireless/wl12xx/wl1271_main.c)494
-rw-r--r--drivers/net/wireless/wl12xx/ps.c (renamed from drivers/net/wireless/wl12xx/wl1271_ps.c)6
-rw-r--r--drivers/net/wireless/wl12xx/ps.h (renamed from drivers/net/wireless/wl12xx/wl1271_ps.h)8
-rw-r--r--drivers/net/wireless/wl12xx/reg.h (renamed from drivers/net/wireless/wl12xx/wl1271_reg.h)0
-rw-r--r--drivers/net/wireless/wl12xx/rx.c (renamed from drivers/net/wireless/wl12xx/wl1271_rx.c)38
-rw-r--r--drivers/net/wireless/wl12xx/rx.h (renamed from drivers/net/wireless/wl12xx/wl1271_rx.h)6
-rw-r--r--drivers/net/wireless/wl12xx/scan.c (renamed from drivers/net/wireless/wl12xx/wl1271_scan.c)17
-rw-r--r--drivers/net/wireless/wl12xx/scan.h (renamed from drivers/net/wireless/wl12xx/wl1271_scan.h)6
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c (renamed from drivers/net/wireless/wl12xx/wl1271_sdio.c)4
-rw-r--r--drivers/net/wireless/wl12xx/sdio_test.c520
-rw-r--r--drivers/net/wireless/wl12xx/spi.c (renamed from drivers/net/wireless/wl12xx/wl1271_spi.c)6
-rw-r--r--drivers/net/wireless/wl12xx/testmode.c (renamed from drivers/net/wireless/wl12xx/wl1271_testmode.c)18
-rw-r--r--drivers/net/wireless/wl12xx/testmode.h (renamed from drivers/net/wireless/wl12xx/wl1271_testmode.h)4
-rw-r--r--drivers/net/wireless/wl12xx/tx.c (renamed from drivers/net/wireless/wl12xx/wl1271_tx.c)196
-rw-r--r--drivers/net/wireless/wl12xx/tx.h (renamed from drivers/net/wireless/wl12xx/wl1271_tx.h)7
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.c583
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h (renamed from drivers/net/wireless/wl12xx/wl1271.h)154
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h17
-rw-r--r--drivers/net/wireless/wl3501_cs.c2
-rw-r--r--drivers/net/wireless/zd1201.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c2
-rw-r--r--drivers/net/xen-netfront.c6
-rw-r--r--drivers/net/xilinx_emaclite.c37
-rw-r--r--drivers/net/yellowfin.c4
-rw-r--r--drivers/net/znet.c2
-rw-r--r--drivers/nfc/Kconfig30
-rw-r--r--drivers/nfc/Makefile5
-rw-r--r--drivers/nfc/pn544.c891
-rw-r--r--drivers/of/Kconfig8
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/address.c54
-rw-r--r--drivers/of/fdt.c430
-rw-r--r--drivers/of/of_i2c.c2
-rw-r--r--drivers/of/of_mdio.c26
-rw-r--r--drivers/of/of_net.c48
-rw-r--r--drivers/of/platform.c22
-rw-r--r--drivers/oprofile/buffer_sync.c2
-rw-r--r--drivers/oprofile/cpu_buffer.c10
-rw-r--r--drivers/oprofile/cpu_buffer.h1
-rw-r--r--drivers/oprofile/timer_int.c13
-rw-r--r--drivers/parisc/dino.c1
-rw-r--r--drivers/parisc/eisa.c3
-rw-r--r--drivers/parisc/eisa_eeprom.c1
-rw-r--r--drivers/parisc/gsc.c3
-rw-r--r--drivers/parisc/iosapic.c8
-rw-r--r--drivers/parisc/led.c17
-rw-r--r--drivers/parisc/superio.c3
-rw-r--r--drivers/pci/Kconfig1
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/bus.c53
-rw-r--r--drivers/pci/dmar.c5
-rw-r--r--drivers/pci/hotplug/acpiphp.h1
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c6
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c3
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c1
-rw-r--r--drivers/pci/msi.c5
-rw-r--r--drivers/pci/msi.h6
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pci/pci-driver.c5
-rw-r--r--drivers/pci/pci-stub.c7
-rw-r--r--drivers/pci/pci-sysfs.c25
-rw-r--r--drivers/pci/pci.c37
-rw-r--r--drivers/pci/pci.h21
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c1
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h3
-rw-r--r--drivers/pci/pcie/aspm.c21
-rw-r--r--drivers/pci/pcie/pme.c31
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c23
-rw-r--r--drivers/pci/pcie/portdrv_core.c25
-rw-r--r--drivers/pci/pcie/portdrv_pci.c37
-rw-r--r--drivers/pci/proc.c3
-rw-r--r--drivers/pci/quirks.c44
-rw-r--r--drivers/pci/xen-pcifront.c6
-rw-r--r--drivers/pcmcia/Kconfig3
-rw-r--r--drivers/pcmcia/Makefile5
-rw-r--r--drivers/pcmcia/m32r_cfc.h2
-rw-r--r--drivers/pcmcia/m32r_pcc.h2
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/pd6729.c8
-rw-r--r--drivers/pcmcia/pd6729.h2
-rw-r--r--drivers/pcmcia/pxa2xx_balloon3.c11
-rw-r--r--drivers/pcmcia/pxa2xx_base.c64
-rw-r--r--drivers/pcmcia/pxa2xx_colibri.c229
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c2
-rw-r--r--drivers/pcmcia/sa1100_assabet.c2
-rw-r--r--drivers/pcmcia/sa1100_cerf.c2
-rw-r--r--drivers/pcmcia/sa1100_generic.c5
-rw-r--r--drivers/pcmcia/sa1100_generic.h1
-rw-r--r--drivers/pcmcia/sa1100_h3600.c2
-rw-r--r--drivers/pcmcia/sa1100_nanoengine.c219
-rw-r--r--drivers/pcmcia/sa1100_shannon.c2
-rw-r--r--drivers/pcmcia/sa1100_simpad.c2
-rw-r--r--drivers/pcmcia/soc_common.c138
-rw-r--r--drivers/pcmcia/soc_common.h3
-rw-r--r--drivers/platform/x86/Kconfig27
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c431
-rw-r--r--drivers/platform/x86/asus-laptop.c99
-rw-r--r--drivers/platform/x86/asus_acpi.c2
-rw-r--r--drivers/platform/x86/classmate-laptop.c19
-rw-r--r--drivers/platform/x86/compal-laptop.c8
-rw-r--r--drivers/platform/x86/dell-laptop.c2
-rw-r--r--drivers/platform/x86/eeepc-laptop.c13
-rw-r--r--drivers/platform/x86/eeepc-wmi.c613
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c8
-rw-r--r--drivers/platform/x86/hp-wmi.c2
-rw-r--r--drivers/platform/x86/ibm_rtl.c34
-rw-r--r--drivers/platform/x86/ideapad-laptop.c259
-rw-r--r--drivers/platform/x86/intel_ips.c36
-rw-r--r--drivers/platform/x86/intel_ips.h21
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c6
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c9
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c133
-rw-r--r--drivers/platform/x86/msi-wmi.c16
-rw-r--r--drivers/platform/x86/sony-laptop.c14
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c8
-rw-r--r--drivers/platform/x86/toshiba_acpi.c3
-rw-r--r--drivers/platform/x86/wmi.c135
-rw-r--r--drivers/pnp/Makefile6
-rw-r--r--drivers/pnp/core.c7
-rw-r--r--drivers/pnp/driver.c7
-rw-r--r--drivers/pnp/isapnp/Makefile6
-rw-r--r--drivers/pnp/isapnp/proc.c1
-rw-r--r--drivers/pnp/pnpacpi/Makefile3
-rw-r--r--drivers/pnp/pnpacpi/core.c95
-rw-r--r--drivers/pnp/pnpbios/Makefile5
-rw-r--r--drivers/power/Kconfig20
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/collie_battery.c13
-rw-r--r--drivers/power/ds2760_battery.c8
-rw-r--r--drivers/power/gpio-charger.c188
-rw-r--r--drivers/power/intel_mid_battery.c8
-rw-r--r--drivers/power/isp1704_charger.c201
-rw-r--r--drivers/power/jz4740-battery.c13
-rw-r--r--drivers/power/max17042_battery.c239
-rw-r--r--drivers/power/olpc_battery.c114
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/s3c_adc_battery.c16
-rw-r--r--drivers/power/tosa_battery.c13
-rw-r--r--drivers/power/wm97xx_battery.c4
-rw-r--r--drivers/power/z2_battery.c6
-rw-r--r--drivers/pps/Kconfig11
-rw-r--r--drivers/pps/Makefile3
-rw-r--r--drivers/pps/clients/Kconfig7
-rw-r--r--drivers/pps/clients/Makefile1
-rw-r--r--drivers/pps/clients/pps-ktimer.c44
-rw-r--r--drivers/pps/clients/pps-ldisc.c59
-rw-r--r--drivers/pps/clients/pps_parport.c258
-rw-r--r--drivers/pps/generators/Kconfig13
-rw-r--r--drivers/pps/generators/Makefile9
-rw-r--r--drivers/pps/generators/pps_gen_parport.c282
-rw-r--r--drivers/pps/kapi.c210
-rw-r--r--drivers/pps/kc.c122
-rw-r--r--drivers/pps/kc.h46
-rw-r--r--drivers/pps/pps.c156
-rw-r--r--drivers/ps3/Makefile2
-rw-r--r--drivers/rapidio/rio-scan.c160
-rw-r--r--drivers/rapidio/rio-sysfs.c4
-rw-r--r--drivers/rapidio/rio.c80
-rw-r--r--drivers/rapidio/switches/idt_gen2.c95
-rw-r--r--drivers/rapidio/switches/idtcps.c6
-rw-r--r--drivers/rapidio/switches/tsi568.c13
-rw-r--r--drivers/rapidio/switches/tsi57x.c56
-rw-r--r--drivers/regulator/88pm8607.c3
-rw-r--r--drivers/regulator/Kconfig22
-rw-r--r--drivers/regulator/Makefile3
-rw-r--r--drivers/regulator/ab3100.c5
-rw-r--r--drivers/regulator/ab8500.c453
-rw-r--r--drivers/regulator/core.c488
-rw-r--r--drivers/regulator/da903x.c17
-rw-r--r--drivers/regulator/isl6271a-regulator.c8
-rw-r--r--drivers/regulator/lp3971.c10
-rw-r--r--drivers/regulator/lp3972.c10
-rw-r--r--drivers/regulator/max1586.c30
-rw-r--r--drivers/regulator/max8649.c3
-rw-r--r--drivers/regulator/max8660.c14
-rw-r--r--drivers/regulator/max8925-regulator.c3
-rw-r--r--drivers/regulator/max8952.c3
-rw-r--r--drivers/regulator/max8998.c102
-rw-r--r--drivers/regulator/mc13783-regulator.c385
-rw-r--r--drivers/regulator/mc13892-regulator.c635
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c241
-rw-r--r--drivers/regulator/mc13xxx.h101
-rw-r--r--drivers/regulator/pcap-regulator.c7
-rw-r--r--drivers/regulator/pcf50633-regulator.c5
-rw-r--r--drivers/regulator/tps65023-regulator.c9
-rw-r--r--drivers/regulator/tps6507x-regulator.c10
-rw-r--r--drivers/regulator/tps6524x-regulator.c693
-rw-r--r--drivers/regulator/tps6586x-regulator.c48
-rw-r--r--drivers/regulator/twl-regulator.c17
-rw-r--r--drivers/regulator/wm831x-dcdc.c31
-rw-r--r--drivers/regulator/wm831x-ldo.c59
-rw-r--r--drivers/regulator/wm8350-regulator.c24
-rw-r--r--drivers/regulator/wm8400-regulator.c8
-rw-r--r--drivers/regulator/wm8994-regulator.c45
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c13
-rw-r--r--drivers/rtc/interface.c574
-rw-r--r--drivers/rtc/rtc-cmos.c19
-rw-r--r--drivers/rtc/rtc-dev.c104
-rw-r--r--drivers/rtc/rtc-ds1302.c2
-rw-r--r--drivers/rtc/rtc-ds1305.c2
-rw-r--r--drivers/rtc/rtc-ds1307.c12
-rw-r--r--drivers/rtc/rtc-ds1374.c2
-rw-r--r--drivers/rtc/rtc-ds3232.c2
-rw-r--r--drivers/rtc/rtc-lib.c28
-rw-r--r--drivers/rtc/rtc-max6902.c3
-rw-r--r--drivers/rtc/rtc-max8998.c54
-rw-r--r--drivers/rtc/rtc-mrst.c582
-rw-r--r--drivers/rtc/rtc-omap.c6
-rw-r--r--drivers/rtc/rtc-rs5c372.c2
-rw-r--r--drivers/rtc/rtc-rx8025.c2
-rw-r--r--drivers/rtc/rtc-sa1100.c161
-rw-r--r--drivers/rtc/rtc-sh.c4
-rw-r--r--drivers/s390/block/Kconfig24
-rw-r--r--drivers/s390/block/dasd.c314
-rw-r--r--drivers/s390/block/dasd_3990_erp.c16
-rw-r--r--drivers/s390/block/dasd_devmap.c155
-rw-r--r--drivers/s390/block/dasd_diag.c3
-rw-r--r--drivers/s390/block/dasd_eckd.c664
-rw-r--r--drivers/s390/block/dasd_eckd.h17
-rw-r--r--drivers/s390/block/dasd_eer.c2
-rw-r--r--drivers/s390/block/dasd_erp.c3
-rw-r--r--drivers/s390/block/dasd_fba.c21
-rw-r--r--drivers/s390/block/dasd_genhd.c2
-rw-r--r--drivers/s390/block/dasd_int.h35
-rw-r--r--drivers/s390/char/Kconfig69
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/fs3270.c1
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp.c18
-rw-r--r--drivers/s390/char/sclp_config.c1
-rw-r--r--drivers/s390/char/tape_3590.c18
-rw-r--r--drivers/s390/char/tape_block.c2
-rw-r--r--drivers/s390/char/tape_char.c1
-rw-r--r--drivers/s390/char/tape_class.h1
-rw-r--r--drivers/s390/char/tape_core.c70
-rw-r--r--drivers/s390/char/vmlogrdr.c37
-rw-r--r--drivers/s390/char/vmur.c3
-rw-r--r--drivers/s390/cio/ccwgroup.c78
-rw-r--r--drivers/s390/cio/chsc.c19
-rw-r--r--drivers/s390/cio/chsc.h18
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/css.c10
-rw-r--r--drivers/s390/cio/device.c12
-rw-r--r--drivers/s390/cio/device_ops.c40
-rw-r--r--drivers/s390/cio/itcw.c62
-rw-r--r--drivers/s390/cio/qdio.h31
-rw-r--r--drivers/s390/cio/qdio_debug.c1
-rw-r--r--drivers/s390/cio/qdio_main.c177
-rw-r--r--drivers/s390/cio/qdio_setup.c20
-rw-r--r--drivers/s390/cio/qdio_thinint.c58
-rw-r--r--drivers/s390/crypto/ap_bus.c67
-rw-r--r--drivers/s390/crypto/ap_bus.h2
-rw-r--r--drivers/s390/crypto/zcrypt_api.c13
-rw-r--r--drivers/s390/crypto/zcrypt_api.h1
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c82
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.h25
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c1
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c1
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c17
-rw-r--r--drivers/s390/kvm/kvm_virtio.c3
-rw-r--r--drivers/s390/net/Kconfig51
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_main.c2
-rw-r--r--drivers/s390/net/lcs.c14
-rw-r--r--drivers/s390/net/qeth_core.h9
-rw-r--r--drivers/s390/net/qeth_core_main.c59
-rw-r--r--drivers/s390/net/qeth_core_mpc.h2
-rw-r--r--drivers/s390/net/qeth_core_sys.c2
-rw-r--r--drivers/s390/net/qeth_l2_main.c11
-rw-r--r--drivers/s390/net/qeth_l3_main.c245
-rw-r--r--drivers/s390/scsi/zfcp_aux.c9
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c14
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c10
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c1177
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h497
-rw-r--r--drivers/s390/scsi/zfcp_erp.c152
-rw-r--r--drivers/s390/scsi/zfcp_ext.h52
-rw-r--r--drivers/s390/scsi/zfcp_fc.c20
-rw-r--r--drivers/s390/scsi/zfcp_fc.h2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c127
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c12
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c48
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c9
-rw-r--r--drivers/s390/scsi/zfcp_unit.c4
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/scsi/3w-9xxx.c4
-rw-r--r--drivers/scsi/3w-sas.c4
-rw-r--r--drivers/scsi/3w-xxxx.c4
-rw-r--r--drivers/scsi/53c700.c8
-rw-r--r--drivers/scsi/BusLogic.c3
-rw-r--r--drivers/scsi/BusLogic.h2
-rw-r--r--drivers/scsi/NCR5380.c3
-rw-r--r--drivers/scsi/NCR5380.h2
-rw-r--r--drivers/scsi/NCR53c406a.c4
-rw-r--r--drivers/scsi/a100u2w.c6
-rw-r--r--drivers/scsi/aacraid/commsup.c2
-rw-r--r--drivers/scsi/aacraid/linit.c4
-rw-r--r--drivers/scsi/advansys.c4
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/aha1542.c4
-rw-r--r--drivers/scsi/aha1542.h2
-rw-r--r--drivers/scsi/aha1740.c4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c4
-rw-r--r--drivers/scsi/aic7xxx_old.c4
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx.seq2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c6
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c10
-rw-r--r--drivers/scsi/arm/acornscsi.c4
-rw-r--r--drivers/scsi/arm/fas216.c10
-rw-r--r--drivers/scsi/arm/fas216.h18
-rw-r--r--drivers/scsi/atari_NCR5380.c4
-rw-r--r--drivers/scsi/atari_scsi.c17
-rw-r--r--drivers/scsi/atp870u.c4
-rw-r--r--drivers/scsi/be2iscsi/be_main.c5
-rw-r--r--drivers/scsi/bfa/Makefile4
-rw-r--r--drivers/scsi/bfa/bfa.h84
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim.h169
-rw-r--r--drivers/scsi/bfa/bfa_core.c519
-rw-r--r--drivers/scsi/bfa/bfa_cs.h118
-rw-r--r--drivers/scsi/bfa/bfa_defs.h60
-rw-r--r--drivers/scsi/bfa/bfa_defs_fcs.h48
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h90
-rw-r--r--drivers/scsi/bfa/bfa_drv.c107
-rw-r--r--drivers/scsi/bfa/bfa_fc.h661
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c305
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h30
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c1007
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.h206
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c527
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h167
-rw-r--r--drivers/scsi/bfa/bfa_fcs_fcpim.c70
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c802
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c406
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c19
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c27
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c1110
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h146
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c187
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c287
-rw-r--r--drivers/scsi/bfa/bfa_modules.h9
-rw-r--r--drivers/scsi/bfa/bfa_os_inc.h207
-rw-r--r--drivers/scsi/bfa/bfa_plog.h4
-rw-r--r--drivers/scsi/bfa/bfa_port.c75
-rw-r--r--drivers/scsi/bfa/bfa_port.h1
-rw-r--r--drivers/scsi/bfa/bfa_svc.c1212
-rw-r--r--drivers/scsi/bfa/bfa_svc.h104
-rw-r--r--drivers/scsi/bfa/bfad.c119
-rw-r--r--drivers/scsi/bfa/bfad_attr.c56
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c50
-rw-r--r--drivers/scsi/bfa/bfad_drv.h52
-rw-r--r--drivers/scsi/bfa/bfad_im.c156
-rw-r--r--drivers/scsi/bfa/bfad_im.h16
-rw-r--r--drivers/scsi/bfa/bfi.h66
-rw-r--r--drivers/scsi/bfa/bfi_cbreg.h1
-rw-r--r--drivers/scsi/bfa/bfi_ctreg.h41
-rw-r--r--drivers/scsi/bfa/bfi_ms.h116
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h3
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_hsi.h3
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h15
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c110
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c108
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c148
-rw-r--r--drivers/scsi/bnx2i/bnx2i_sysfs.c3
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c3
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c2
-rw-r--r--drivers/scsi/dc395x.c11
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c11
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c2
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/dpti.h2
-rw-r--r--drivers/scsi/dtc.h2
-rw-r--r--drivers/scsi/eata.c7
-rw-r--r--drivers/scsi/eata_pio.c4
-rw-r--r--drivers/scsi/esp_scsi.c4
-rw-r--r--drivers/scsi/fcoe/fcoe.c22
-rw-r--r--drivers/scsi/fcoe/libfcoe.c302
-rw-r--r--drivers/scsi/fd_mcs.c4
-rw-r--r--drivers/scsi/fdomain.c4
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c4
-rw-r--r--drivers/scsi/g_NCR5380.h2
-rw-r--r--drivers/scsi/gdth.c18
-rw-r--r--drivers/scsi/gdth_proc.c16
-rw-r--r--drivers/scsi/hpsa.c27
-rw-r--r--drivers/scsi/hpsa.h1
-rw-r--r--drivers/scsi/hptiop.c4
-rw-r--r--drivers/scsi/ibmmca.c6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c32
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c4
-rw-r--r--drivers/scsi/imm.c4
-rw-r--r--drivers/scsi/in2000.c4
-rw-r--r--drivers/scsi/in2000.h2
-rw-r--r--drivers/scsi/initio.c4
-rw-r--r--drivers/scsi/ipr.c70
-rw-r--r--drivers/scsi/ipr.h3
-rw-r--r--drivers/scsi/ips.c6
-rw-r--r--drivers/scsi/libfc/fc_disc.c5
-rw-r--r--drivers/scsi/libfc/fc_exch.c48
-rw-r--r--drivers/scsi/libfc/fc_fcp.c177
-rw-r--r--drivers/scsi/libfc/fc_libfc.h16
-rw-r--r--drivers/scsi/libfc/fc_lport.c28
-rw-r--r--drivers/scsi/libfc/fc_rport.c7
-rw-r--r--drivers/scsi/libiscsi.c62
-rw-r--r--drivers/scsi/libsas/sas_port.c18
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c7
-rw-r--r--drivers/scsi/lpfc/lpfc.h38
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c113
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c69
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h23
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h19
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c766
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c672
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h263
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h457
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c1162
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c104
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c16
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c95
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c1117
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h67
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c10
-rw-r--r--drivers/scsi/mac53c94.c4
-rw-r--r--drivers/scsi/megaraid.c6
-rw-r--r--drivers/scsi/megaraid.h4
-rw-r--r--drivers/scsi/megaraid/Makefile2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c7
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h79
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c (renamed from drivers/scsi/megaraid/megaraid_sas.c)899
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c516
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c2248
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h695
-rw-r--r--drivers/scsi/mesh.c4
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h9
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h20
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt3
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h9
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h8
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h6
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h9
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h49
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c199
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h27
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c347
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c185
-rw-r--r--drivers/scsi/ncr53c8xx.c4
-rw-r--r--drivers/scsi/nsp32.c7
-rw-r--r--drivers/scsi/osd/osd_initiator.c244
-rw-r--r--drivers/scsi/pas16.h2
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c4
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h3
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h1
-rw-r--r--drivers/scsi/pmcraid.c144
-rw-r--r--drivers/scsi/pmcraid.h27
-rw-r--r--drivers/scsi/ppa.c4
-rw-r--r--drivers/scsi/ps3rom.c4
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c31
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c131
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c117
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c28
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c67
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c218
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c274
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c103
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h25
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h5
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h3
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c12
-rw-r--r--drivers/scsi/qla4xxx/ql4_inline.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c12
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c25
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c33
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c151
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.h11
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c146
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h4
-rw-r--r--drivers/scsi/qlogicfas408.c4
-rw-r--r--drivers/scsi/qlogicfas408.h3
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/scsi.c18
-rw-r--r--drivers/scsi/scsi_debug.c5
-rw-r--r--drivers/scsi/scsi_error.c111
-rw-r--r--drivers/scsi/scsi_lib.c29
-rw-r--r--drivers/scsi/scsi_netlink.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c15
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c1
-rw-r--r--drivers/scsi/sd.c202
-rw-r--r--drivers/scsi/sd.h1
-rw-r--r--drivers/scsi/sr.c174
-rw-r--r--drivers/scsi/sr.h3
-rw-r--r--drivers/scsi/sr_ioctl.c11
-rw-r--r--drivers/scsi/st.c7
-rw-r--r--drivers/scsi/stex.c4
-rw-r--r--drivers/scsi/sun3_NCR5380.c4
-rw-r--r--drivers/scsi/sun3_scsi.h3
-rw-r--r--drivers/scsi/sym53c416.c4
-rw-r--r--drivers/scsi/sym53c416.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c6
-rw-r--r--drivers/scsi/t128.h3
-rw-r--r--drivers/scsi/tmscsim.c4
-rw-r--r--drivers/scsi/u14-34f.c6
-rw-r--r--drivers/scsi/ultrastor.c4
-rw-r--r--drivers/scsi/ultrastor.h3
-rw-r--r--drivers/scsi/vmw_pvscsi.c4
-rw-r--r--drivers/scsi/wd33c93.c6
-rw-r--r--drivers/scsi/wd33c93.h3
-rw-r--r--drivers/scsi/wd7000.c4
-rw-r--r--drivers/serial/8250.c137
-rw-r--r--drivers/serial/8250_pci.c41
-rw-r--r--drivers/serial/Kconfig97
-rw-r--r--drivers/serial/Makefile5
-rw-r--r--drivers/serial/amba-pl011.c592
-rw-r--r--drivers/serial/apbuart.c61
-rw-r--r--drivers/serial/atmel_serial.c5
-rw-r--r--drivers/serial/bfin_5xx.c651
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h6
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c19
-rw-r--r--drivers/serial/crisv10.c24
-rw-r--r--drivers/serial/ifx6x60.c1406
-rw-r--r--drivers/serial/ifx6x60.h129
-rw-r--r--drivers/serial/kgdboc.c60
-rw-r--r--drivers/serial/mfd.c24
-rw-r--r--drivers/serial/mpc52xx_uart.c6
-rw-r--r--drivers/serial/msm_serial.c2
-rw-r--r--drivers/serial/of_serial.c1
-rw-r--r--drivers/serial/omap-serial.c78
-rw-r--r--drivers/serial/pch_uart.c1451
-rw-r--r--drivers/serial/samsung.c4
-rw-r--r--drivers/serial/serial_core.c11
-rw-r--r--drivers/serial/sh-sci.c102
-rw-r--r--drivers/serial/sh-sci.h158
-rw-r--r--drivers/serial/vt8500_serial.c648
-rw-r--r--drivers/sfi/sfi_core.c2
-rw-r--r--drivers/sh/clk/core.c113
-rw-r--r--drivers/sh/clk/cpg.c7
-rw-r--r--drivers/sh/intc/core.c3
-rw-r--r--drivers/sh/intc/dynamic.c2
-rw-r--r--drivers/sh/intc/virq.c2
-rw-r--r--drivers/spi/Kconfig46
-rw-r--r--drivers/spi/Makefile6
-rw-r--r--drivers/spi/amba-pl022.c58
-rw-r--r--drivers/spi/atmel_spi.c10
-rw-r--r--drivers/spi/coldfire_qspi.c2
-rw-r--r--drivers/spi/davinci_spi.c1314
-rw-r--r--drivers/spi/dw_spi.c57
-rw-r--r--drivers/spi/dw_spi_mid.c223
-rw-r--r--drivers/spi/dw_spi_mmio.c5
-rw-r--r--drivers/spi/dw_spi_pci.c20
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c35
-rw-r--r--drivers/spi/mpc52xx_spi.c2
-rw-r--r--drivers/spi/omap2_mcspi.c50
-rw-r--r--drivers/spi/pxa2xx_spi.c190
-rw-r--r--drivers/spi/pxa2xx_spi_pci.c201
-rw-r--r--drivers/spi/spi.c187
-rw-r--r--drivers/spi/spi_bfin5xx.c22
-rw-r--r--drivers/spi/spi_fsl_espi.c35
-rw-r--r--drivers/spi/spi_imx.c38
-rw-r--r--drivers/spi/spi_nuc900.c2
-rw-r--r--drivers/spi/spi_tegra.c2
-rw-r--r--drivers/spi/spi_topcliff_pch.c12
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/spi/xilinx_spi.c133
-rw-r--r--drivers/spi/xilinx_spi.h32
-rw-r--r--drivers/spi/xilinx_spi_of.c133
-rw-r--r--drivers/spi/xilinx_spi_pltfm.c102
-rw-r--r--drivers/ssb/b43_pci_bridge.c1
-rw-r--r--drivers/ssb/main.c30
-rw-r--r--drivers/ssb/pci.c96
-rw-r--r--drivers/ssb/pcihost_wrapper.c7
-rw-r--r--drivers/ssb/scan.c14
-rw-r--r--drivers/staging/Kconfig20
-rw-r--r--drivers/staging/Makefile12
-rw-r--r--drivers/staging/adis16255/Kconfig11
-rw-r--r--drivers/staging/adis16255/Makefile1
-rw-r--r--drivers/staging/adis16255/adis16255.c468
-rw-r--r--drivers/staging/adis16255/adis16255.h12
-rw-r--r--drivers/staging/asus_oled/asus_oled.c10
-rw-r--r--drivers/staging/ath6kl/Kconfig2
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c4
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c4
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_drv.c7
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_raw_if.c4
-rw-r--r--drivers/staging/ath6kl/os/linux/cfg80211.c7
-rw-r--r--drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h0
-rw-r--r--drivers/staging/autofs/dirhash.c92
-rw-r--r--drivers/staging/autofs/root.c7
-rw-r--r--drivers/staging/batman-adv/Kconfig26
-rw-r--r--drivers/staging/batman-adv/Makefile22
-rw-r--r--drivers/staging/batman-adv/README240
-rw-r--r--drivers/staging/batman-adv/TODO14
-rw-r--r--drivers/staging/batman-adv/aggregation.c275
-rw-r--r--drivers/staging/batman-adv/aggregation.h43
-rw-r--r--drivers/staging/batman-adv/bat_debugfs.c343
-rw-r--r--drivers/staging/batman-adv/bat_debugfs.h33
-rw-r--r--drivers/staging/batman-adv/bat_sysfs.c558
-rw-r--r--drivers/staging/batman-adv/bat_sysfs.h42
-rw-r--r--drivers/staging/batman-adv/bitarray.c201
-rw-r--r--drivers/staging/batman-adv/bitarray.h47
-rw-r--r--drivers/staging/batman-adv/hard-interface.c635
-rw-r--r--drivers/staging/batman-adv/hard-interface.h58
-rw-r--r--drivers/staging/batman-adv/hash.c306
-rw-r--r--drivers/staging/batman-adv/hash.h100
-rw-r--r--drivers/staging/batman-adv/icmp_socket.c359
-rw-r--r--drivers/staging/batman-adv/icmp_socket.h34
-rw-r--r--drivers/staging/batman-adv/main.c217
-rw-r--r--drivers/staging/batman-adv/main.h183
-rw-r--r--drivers/staging/batman-adv/originator.c533
-rw-r--r--drivers/staging/batman-adv/originator.h36
-rw-r--r--drivers/staging/batman-adv/packet.h134
-rw-r--r--drivers/staging/batman-adv/ring_buffer.c52
-rw-r--r--drivers/staging/batman-adv/ring_buffer.h28
-rw-r--r--drivers/staging/batman-adv/routing.c1393
-rw-r--r--drivers/staging/batman-adv/routing.h46
-rw-r--r--drivers/staging/batman-adv/send.c580
-rw-r--r--drivers/staging/batman-adv/send.h41
-rw-r--r--drivers/staging/batman-adv/soft-interface.c392
-rw-r--r--drivers/staging/batman-adv/soft-interface.h32
-rw-r--r--drivers/staging/batman-adv/sysfs-class-net-batman-adv14
-rw-r--r--drivers/staging/batman-adv/sysfs-class-net-mesh41
-rw-r--r--drivers/staging/batman-adv/translation-table.c518
-rw-r--r--drivers/staging/batman-adv/translation-table.h45
-rw-r--r--drivers/staging/batman-adv/types.h241
-rw-r--r--drivers/staging/batman-adv/unicast.c269
-rw-r--r--drivers/staging/batman-adv/unicast.h39
-rw-r--r--drivers/staging/batman-adv/vis.c895
-rw-r--r--drivers/staging/batman-adv/vis.h37
-rw-r--r--drivers/staging/bcm/Adapter.h134
-rw-r--r--drivers/staging/bcm/Arp.c94
-rw-r--r--drivers/staging/bcm/Bcmchar.c992
-rw-r--r--drivers/staging/bcm/Bcmnet.c404
-rw-r--r--drivers/staging/bcm/CmHost.c139
-rw-r--r--drivers/staging/bcm/CmHost.h3
-rw-r--r--drivers/staging/bcm/DDRInit.c17
-rw-r--r--drivers/staging/bcm/Debug.c41
-rw-r--r--drivers/staging/bcm/Debug.h88
-rw-r--r--drivers/staging/bcm/HandleControlPacket.c39
-rw-r--r--drivers/staging/bcm/HostMibs.h7
-rw-r--r--drivers/staging/bcm/IPv6Protocol.c10
-rw-r--r--drivers/staging/bcm/IPv6ProtocolHdr.h3
-rw-r--r--drivers/staging/bcm/InterfaceDld.c136
-rw-r--r--drivers/staging/bcm/InterfaceIdleMode.c20
-rw-r--r--drivers/staging/bcm/InterfaceIdleMode.h2
-rw-r--r--drivers/staging/bcm/InterfaceInit.c856
-rw-r--r--drivers/staging/bcm/InterfaceInit.h28
-rw-r--r--drivers/staging/bcm/InterfaceIsr.c44
-rw-r--r--drivers/staging/bcm/InterfaceMisc.c29
-rw-r--r--drivers/staging/bcm/InterfaceMisc.h3
-rw-r--r--drivers/staging/bcm/InterfaceRx.c40
-rw-r--r--drivers/staging/bcm/InterfaceTx.c74
-rw-r--r--drivers/staging/bcm/InterfaceTx.h6
-rw-r--r--drivers/staging/bcm/Interfacemain.h10
-rw-r--r--drivers/staging/bcm/LeakyBucket.c72
-rw-r--r--drivers/staging/bcm/Macros.h40
-rw-r--r--drivers/staging/bcm/Makefile4
-rw-r--r--drivers/staging/bcm/Misc.c536
-rw-r--r--drivers/staging/bcm/Osal_Misc.c27
-rw-r--r--drivers/staging/bcm/PHSModule.c234
-rw-r--r--drivers/staging/bcm/PHSModule.h45
-rw-r--r--drivers/staging/bcm/Protocol.h6
-rw-r--r--drivers/staging/bcm/Prototypes.h122
-rw-r--r--drivers/staging/bcm/Qos.c106
-rw-r--r--drivers/staging/bcm/TODO25
-rw-r--r--drivers/staging/bcm/Transmit.c393
-rw-r--r--drivers/staging/bcm/cntrl_SignalingInterface.h254
-rw-r--r--drivers/staging/bcm/headers.h40
-rw-r--r--drivers/staging/bcm/hostmibs.c35
-rw-r--r--drivers/staging/bcm/led_control.c135
-rw-r--r--drivers/staging/bcm/nvm.c642
-rw-r--r--drivers/staging/bcm/nvm.h80
-rw-r--r--drivers/staging/bcm/osal_misc.h49
-rw-r--r--drivers/staging/brcm80211/README18
-rw-r--r--drivers/staging/brcm80211/TODO4
-rw-r--r--drivers/staging/brcm80211/brcmfmac/README5
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh.c12
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c270
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c59
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c4
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd.h19
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_bus.h6
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_cdc.c40
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_common.c18
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c36
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_linux.c154
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_proto.h7
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_sdio.c348
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c598
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h48
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_iw.c578
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_iw.h2
-rw-r--r--drivers/staging/brcm80211/include/bcm_rpc.h79
-rw-r--r--drivers/staging/brcm80211/include/bcm_rpc_tp.h137
-rw-r--r--drivers/staging/brcm80211/include/bcm_xdr.h60
-rw-r--r--drivers/staging/brcm80211/include/bcmdefs.h63
-rw-r--r--drivers/staging/brcm80211/include/bcmsdbus.h6
-rw-r--r--drivers/staging/brcm80211/include/bcmsdh.h12
-rw-r--r--drivers/staging/brcm80211/include/bcmsdh_sdmmc.h6
-rw-r--r--drivers/staging/brcm80211/include/bcmsrom.h8
-rw-r--r--drivers/staging/brcm80211/include/bcmutils.h60
-rw-r--r--drivers/staging/brcm80211/include/d11.h7
-rw-r--r--drivers/staging/brcm80211/include/dbus.h353
-rw-r--r--drivers/staging/brcm80211/include/epivers.h44
-rw-r--r--drivers/staging/brcm80211/include/hnddma.h91
-rw-r--r--drivers/staging/brcm80211/include/hndpmu.h44
-rw-r--r--drivers/staging/brcm80211/include/linux_osl.h407
-rw-r--r--drivers/staging/brcm80211/include/linuxver.h38
-rw-r--r--drivers/staging/brcm80211/include/nicpci.h12
-rw-r--r--drivers/staging/brcm80211/include/osl.h209
-rw-r--r--drivers/staging/brcm80211/include/proto/ethernet.h54
-rw-r--r--drivers/staging/brcm80211/include/proto/wpa.h94
-rw-r--r--drivers/staging/brcm80211/include/rpc_osl.h2
-rw-r--r--drivers/staging/brcm80211/include/siutils.h28
-rw-r--r--drivers/staging/brcm80211/include/wlioctl.h342
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phy_cmn.c63
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phy_hal.h6
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phy_int.h4
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phy_lcn.c13
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phy_n.c59
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c3
-rw-r--r--drivers/staging/brcm80211/phy/wlc_phytbl_n.c3
-rw-r--r--drivers/staging/brcm80211/sys/wl_dbg.h72
-rw-r--r--drivers/staging/brcm80211/sys/wl_export.h8
-rw-r--r--drivers/staging/brcm80211/sys/wl_mac80211.c1026
-rw-r--r--drivers/staging/brcm80211/sys/wl_mac80211.h50
-rw-r--r--drivers/staging/brcm80211/sys/wl_ucode.h12
-rw-r--r--drivers/staging/brcm80211/sys/wl_ucode_loader.c13
-rw-r--r--drivers/staging/brcm80211/sys/wlc_alloc.c70
-rw-r--r--drivers/staging/brcm80211/sys/wlc_alloc.h12
-rw-r--r--drivers/staging/brcm80211/sys/wlc_ampdu.c316
-rw-r--r--drivers/staging/brcm80211/sys/wlc_ampdu.h30
-rw-r--r--drivers/staging/brcm80211/sys/wlc_antsel.c49
-rw-r--r--drivers/staging/brcm80211/sys/wlc_antsel.h16
-rw-r--r--drivers/staging/brcm80211/sys/wlc_bmac.c806
-rw-r--r--drivers/staging/brcm80211/sys/wlc_bmac.h182
-rw-r--r--drivers/staging/brcm80211/sys/wlc_bsscfg.h3
-rw-r--r--drivers/staging/brcm80211/sys/wlc_cfg.h24
-rw-r--r--drivers/staging/brcm80211/sys/wlc_channel.c102
-rw-r--r--drivers/staging/brcm80211/sys/wlc_event.c16
-rw-r--r--drivers/staging/brcm80211/sys/wlc_event.h5
-rw-r--r--drivers/staging/brcm80211/sys/wlc_mac80211.c1297
-rw-r--r--drivers/staging/brcm80211/sys/wlc_mac80211.h312
-rw-r--r--drivers/staging/brcm80211/sys/wlc_phy_shim.c14
-rw-r--r--drivers/staging/brcm80211/sys/wlc_pub.h48
-rw-r--r--drivers/staging/brcm80211/sys/wlc_rate.c6
-rw-r--r--drivers/staging/brcm80211/sys/wlc_rpc.h527
-rw-r--r--drivers/staging/brcm80211/sys/wlc_rpctx.h71
-rw-r--r--drivers/staging/brcm80211/sys/wlc_scb.h2
-rw-r--r--drivers/staging/brcm80211/sys/wlc_stf.c72
-rw-r--r--drivers/staging/brcm80211/sys/wlc_stf.h31
-rw-r--r--drivers/staging/brcm80211/sys/wlc_types.h31
-rw-r--r--drivers/staging/brcm80211/util/aiutils.c25
-rw-r--r--drivers/staging/brcm80211/util/bcmotp.c22
-rw-r--r--drivers/staging/brcm80211/util/bcmsrom.c95
-rw-r--r--drivers/staging/brcm80211/util/bcmutils.c112
-rw-r--r--drivers/staging/brcm80211/util/bcmwifi.c4
-rw-r--r--drivers/staging/brcm80211/util/hnddma.c136
-rw-r--r--drivers/staging/brcm80211/util/hndpmu.c174
-rw-r--r--drivers/staging/brcm80211/util/linux_osl.c247
-rw-r--r--drivers/staging/brcm80211/util/nicpci.c125
-rw-r--r--drivers/staging/brcm80211/util/nvram/nvram_ro.c4
-rw-r--r--drivers/staging/brcm80211/util/sbutils.c13
-rw-r--r--drivers/staging/brcm80211/util/siutils.c206
-rw-r--r--drivers/staging/comedi/drivers.c30
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c2
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c2
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c66
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c71
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c2
-rw-r--r--drivers/staging/comedi/drivers/s526.c139
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c10
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c4
-rw-r--r--drivers/staging/cpia/Kconfig39
-rw-r--r--drivers/staging/cpia/Makefile5
-rw-r--r--drivers/staging/cpia/TODO8
-rw-r--r--drivers/staging/cpia/cpia.c4032
-rw-r--r--drivers/staging/cpia/cpia.h432
-rw-r--r--drivers/staging/cpia/cpia_pp.c869
-rw-r--r--drivers/staging/cpia/cpia_usb.c640
-rw-r--r--drivers/staging/cptm1217/Kconfig12
-rw-r--r--drivers/staging/cptm1217/Makefile2
-rw-r--r--drivers/staging/cptm1217/TODO5
-rw-r--r--drivers/staging/cptm1217/clearpad_tm1217.c675
-rw-r--r--drivers/staging/cptm1217/cp_tm1217.h9
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.c2
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c6
-rw-r--r--drivers/staging/cs5535_gpio/Kconfig11
-rw-r--r--drivers/staging/cs5535_gpio/Makefile1
-rw-r--r--drivers/staging/cs5535_gpio/TODO6
-rw-r--r--drivers/staging/cs5535_gpio/cs5535_gpio.c (renamed from drivers/char/cs5535_gpio.c)0
-rw-r--r--drivers/staging/cx25821/Kconfig4
-rw-r--r--drivers/staging/cx25821/cx25821-alsa.c73
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.c66
-rw-r--r--drivers/staging/cx25821/cx25821-cards.c2
-rw-r--r--drivers/staging/cx25821/cx25821-core.c191
-rw-r--r--drivers/staging/cx25821/cx25821-i2c.c19
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c7
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.c63
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.c90
-rw-r--r--drivers/staging/cx25821/cx25821-video.c124
-rw-r--r--drivers/staging/cx25821/cx25821-video.h17
-rw-r--r--drivers/staging/cx25821/cx25821.h9
-rw-r--r--drivers/staging/cxt1e1/comet.c8
-rw-r--r--drivers/staging/cxt1e1/functions.c8
-rw-r--r--drivers/staging/cxt1e1/hwprobe.c4
-rw-r--r--drivers/staging/cxt1e1/linux.c18
-rw-r--r--drivers/staging/cxt1e1/musycc.c58
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c38
-rw-r--r--drivers/staging/cxt1e1/sbecom_inline_linux.h4
-rw-r--r--drivers/staging/dabusb/Kconfig14
-rw-r--r--drivers/staging/dabusb/Makefile2
-rw-r--r--drivers/staging/dabusb/TODO5
-rw-r--r--drivers/staging/dabusb/dabusb.c (renamed from drivers/media/video/dabusb.c)0
-rw-r--r--drivers/staging/dabusb/dabusb.h (renamed from drivers/media/video/dabusb.h)0
-rw-r--r--drivers/staging/dt3155v4l/dt3155v4l.c3
-rw-r--r--drivers/staging/easycap/Kconfig1
-rw-r--r--drivers/staging/easycap/Makefile1
-rw-r--r--drivers/staging/easycap/README93
-rw-r--r--drivers/staging/easycap/easycap.h188
-rw-r--r--drivers/staging/easycap/easycap_debug.h2
-rw-r--r--drivers/staging/easycap/easycap_ioctl.c2286
-rw-r--r--drivers/staging/easycap/easycap_low.c895
-rw-r--r--drivers/staging/easycap/easycap_main.c2774
-rw-r--r--drivers/staging/easycap/easycap_settings.c272
-rw-r--r--drivers/staging/easycap/easycap_sound.c603
-rw-r--r--drivers/staging/easycap/easycap_testcard.c372
-rw-r--r--drivers/staging/et131x/et131x_initpci.c2
-rw-r--r--drivers/staging/frontier/alphatrack.c4
-rw-r--r--drivers/staging/frontier/tranzport.c2
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c54
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c8
-rw-r--r--drivers/staging/ft1000/ft1000-usb/Makefile2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_debug.c (renamed from drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c)436
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_download.c386
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c433
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.h4
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_proc.c373
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.c34
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.h62
-rw-r--r--drivers/staging/go7007/Kconfig4
-rw-r--r--drivers/staging/go7007/go7007-driver.c4
-rw-r--r--drivers/staging/hv/Makefile2
-rw-r--r--drivers/staging/hv/blkvsc.c52
-rw-r--r--drivers/staging/hv/blkvsc_drv.c117
-rw-r--r--drivers/staging/hv/channel.c338
-rw-r--r--drivers/staging/hv/channel_mgmt.c244
-rw-r--r--drivers/staging/hv/channel_mgmt.h245
-rw-r--r--drivers/staging/hv/connection.c56
-rw-r--r--drivers/staging/hv/hv.c346
-rw-r--r--drivers/staging/hv/hv.h36
-rw-r--r--drivers/staging/hv/hv_api.h278
-rw-r--r--drivers/staging/hv/hv_utils.c102
-rw-r--r--drivers/staging/hv/netvsc.c937
-rw-r--r--drivers/staging/hv/netvsc.h164
-rw-r--r--drivers/staging/hv/netvsc_api.h64
-rw-r--r--drivers/staging/hv/netvsc_drv.c83
-rw-r--r--drivers/staging/hv/osd.c108
-rw-r--r--drivers/staging/hv/osd.h22
-rw-r--r--drivers/staging/hv/ring_buffer.c404
-rw-r--r--drivers/staging/hv/ring_buffer.h56
-rw-r--r--drivers/staging/hv/rndis.h353
-rw-r--r--drivers/staging/hv/rndis_filter.c640
-rw-r--r--drivers/staging/hv/rndis_filter.h2
-rw-r--r--drivers/staging/hv/storvsc.c584
-rw-r--r--drivers/staging/hv/storvsc_api.h54
-rw-r--r--drivers/staging/hv/storvsc_drv.c102
-rw-r--r--drivers/staging/hv/vmbus.c274
-rw-r--r--drivers/staging/hv/vmbus_api.h24
-rw-r--r--drivers/staging/hv/vmbus_drv.c351
-rw-r--r--drivers/staging/hv/vmbus_private.h7
-rw-r--r--drivers/staging/hv/vstorage.h106
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio627
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-dds93
-rw-r--r--drivers/staging/iio/Kconfig6
-rw-r--r--drivers/staging/iio/Makefile7
-rw-r--r--drivers/staging/iio/TODO4
-rw-r--r--drivers/staging/iio/accel/Kconfig27
-rw-r--r--drivers/staging/iio/accel/Makefile12
-rw-r--r--drivers/staging/iio/accel/accel.h20
-rw-r--r--drivers/staging/iio/accel/adis16201.h150
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c659
-rw-r--r--drivers/staging/iio/accel/adis16201_ring.c218
-rw-r--r--drivers/staging/iio/accel/adis16201_trigger.c122
-rw-r--r--drivers/staging/iio/accel/adis16203.h143
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c568
-rw-r--r--drivers/staging/iio/accel/adis16203_ring.c211
-rw-r--r--drivers/staging/iio/accel/adis16203_trigger.c122
-rw-r--r--drivers/staging/iio/accel/adis16204.h151
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c613
-rw-r--r--drivers/staging/iio/accel/adis16204_ring.c206
-rw-r--r--drivers/staging/iio/accel/adis16204_trigger.c122
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c2
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c2
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c2
-rw-r--r--drivers/staging/iio/adc/Kconfig91
-rw-r--r--drivers/staging/iio/adc/Makefile15
-rw-r--r--drivers/staging/iio/adc/ad7150.c877
-rw-r--r--drivers/staging/iio/adc/ad7152.c610
-rw-r--r--drivers/staging/iio/adc/ad7291.c1039
-rw-r--r--drivers/staging/iio/adc/ad7298.c501
-rw-r--r--drivers/staging/iio/adc/ad7314.c308
-rw-r--r--drivers/staging/iio/adc/ad7745.c734
-rw-r--r--drivers/staging/iio/adc/ad7816.c535
-rw-r--r--drivers/staging/iio/adc/ad7887.h105
-rw-r--r--drivers/staging/iio/adc/ad7887_core.c305
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c266
-rw-r--r--drivers/staging/iio/adc/adt7310.c952
-rw-r--r--drivers/staging/iio/adc/adt7410.c915
-rw-r--r--drivers/staging/iio/adc/adt75.c732
-rw-r--r--drivers/staging/iio/addac/Kconfig25
-rw-r--r--drivers/staging/iio/addac/Makefile7
-rw-r--r--drivers/staging/iio/addac/adt7316-i2c.c170
-rw-r--r--drivers/staging/iio/addac/adt7316-spi.c180
-rw-r--r--drivers/staging/iio/addac/adt7316.c2402
-rw-r--r--drivers/staging/iio/addac/adt7316.h33
-rw-r--r--drivers/staging/iio/dac/Kconfig21
-rw-r--r--drivers/staging/iio/dac/Makefile6
-rw-r--r--drivers/staging/iio/dac/ad5446.c323
-rw-r--r--drivers/staging/iio/dac/ad5446.h96
-rw-r--r--drivers/staging/iio/dac/ad5624r.h21
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c300
-rw-r--r--drivers/staging/iio/dac/dac.h6
-rw-r--r--drivers/staging/iio/dds/Kconfig56
-rw-r--r--drivers/staging/iio/dds/Makefile11
-rw-r--r--drivers/staging/iio/dds/ad5930.c170
-rw-r--r--drivers/staging/iio/dds/ad9832.c264
-rw-r--r--drivers/staging/iio/dds/ad9834.c477
-rw-r--r--drivers/staging/iio/dds/ad9834.h112
-rw-r--r--drivers/staging/iio/dds/ad9850.c156
-rw-r--r--drivers/staging/iio/dds/ad9852.c305
-rw-r--r--drivers/staging/iio/dds/ad9910.c440
-rw-r--r--drivers/staging/iio/dds/ad9951.c249
-rw-r--r--drivers/staging/iio/dds/dds.h110
-rw-r--r--drivers/staging/iio/gyro/Kconfig38
-rw-r--r--drivers/staging/iio/gyro/Makefile12
-rw-r--r--drivers/staging/iio/gyro/adis16060.h101
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c319
-rw-r--r--drivers/staging/iio/gyro/adis16080.h102
-rw-r--r--drivers/staging/iio/gyro/adis16080_core.c271
-rw-r--r--drivers/staging/iio/gyro/adis16130.h108
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c313
-rw-r--r--drivers/staging/iio/gyro/adis16251.h185
-rw-r--r--drivers/staging/iio/gyro/adis16251_core.c777
-rw-r--r--drivers/staging/iio/gyro/adis16260.h3
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c142
-rw-r--r--drivers/staging/iio/gyro/adis16260_platform_data.h19
-rw-r--r--drivers/staging/iio/gyro/gyro.h9
-rw-r--r--drivers/staging/iio/imu/adis16350_core.c1
-rw-r--r--drivers/staging/iio/meter/Kconfig61
-rw-r--r--drivers/staging/iio/meter/Makefile15
-rw-r--r--drivers/staging/iio/meter/ade7753.c730
-rw-r--r--drivers/staging/iio/meter/ade7753.h140
-rw-r--r--drivers/staging/iio/meter/ade7754.c756
-rw-r--r--drivers/staging/iio/meter/ade7754.h161
-rw-r--r--drivers/staging/iio/meter/ade7758.h171
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c866
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c212
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c125
-rw-r--r--drivers/staging/iio/meter/ade7759.c670
-rw-r--r--drivers/staging/iio/meter/ade7759.h122
-rw-r--r--drivers/staging/iio/meter/ade7854-i2c.c272
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c360
-rw-r--r--drivers/staging/iio/meter/ade7854.c680
-rw-r--r--drivers/staging/iio/meter/ade7854.h245
-rw-r--r--drivers/staging/iio/meter/meter.h396
-rw-r--r--drivers/staging/iio/resolver/Kconfig54
-rw-r--r--drivers/staging/iio/resolver/Makefile7
-rw-r--r--drivers/staging/iio/resolver/ad2s120x.c310
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c872
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c159
-rw-r--r--drivers/staging/iio/sysfs.h6
-rw-r--r--drivers/staging/intel_sst/Kconfig1
-rw-r--r--drivers/staging/intel_sst/intel_sst.c116
-rw-r--r--drivers/staging/intel_sst/intel_sst.h8
-rw-r--r--drivers/staging/intel_sst/intel_sst_app_interface.c593
-rw-r--r--drivers/staging/intel_sst/intel_sst_common.h14
-rw-r--r--drivers/staging/intel_sst/intel_sst_drv_interface.c209
-rw-r--r--drivers/staging/intel_sst/intel_sst_dsp.c70
-rw-r--r--drivers/staging/intel_sst/intel_sst_fw_ipc.h113
-rw-r--r--drivers/staging/intel_sst/intel_sst_ioctl.h15
-rw-r--r--drivers/staging/intel_sst/intel_sst_ipc.c194
-rw-r--r--drivers/staging/intel_sst/intel_sst_pvt.c36
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream.c20
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream_encoded.c216
-rw-r--r--drivers/staging/intel_sst/intelmid.c192
-rw-r--r--drivers/staging/intel_sst/intelmid.h5
-rw-r--r--drivers/staging/intel_sst/intelmid_ctrl.c28
-rw-r--r--drivers/staging/intel_sst/intelmid_msic_control.c24
-rw-r--r--drivers/staging/intel_sst/intelmid_pvt.c54
-rw-r--r--drivers/staging/intel_sst/intelmid_v0_control.c32
-rw-r--r--drivers/staging/intel_sst/intelmid_v1_control.c70
-rw-r--r--drivers/staging/intel_sst/intelmid_v2_control.c96
-rw-r--r--drivers/staging/keucr/init.c436
-rw-r--r--drivers/staging/keucr/init.h3
-rw-r--r--drivers/staging/keucr/ms.c24
-rw-r--r--drivers/staging/keucr/msscsi.c6
-rw-r--r--drivers/staging/keucr/scsiglue.c4
-rw-r--r--drivers/staging/keucr/sdscsi.c4
-rw-r--r--drivers/staging/keucr/smilmain.c4
-rw-r--r--drivers/staging/keucr/smilsub.c22
-rw-r--r--drivers/staging/keucr/transport.c2
-rw-r--r--drivers/staging/line6/capture.c2
-rw-r--r--drivers/staging/line6/control.c204
-rw-r--r--drivers/staging/line6/midi.c8
-rw-r--r--drivers/staging/line6/pcm.c4
-rw-r--r--drivers/staging/line6/playback.c2
-rw-r--r--drivers/staging/line6/pod.c32
-rw-r--r--drivers/staging/line6/toneport.c4
-rw-r--r--drivers/staging/line6/variax.c12
-rw-r--r--drivers/staging/lirc/Kconfig29
-rw-r--r--drivers/staging/lirc/Makefile1
-rw-r--r--drivers/staging/lirc/TODO.lirc_i2c3
-rw-r--r--drivers/staging/lirc/TODO.lirc_zilog13
-rw-r--r--drivers/staging/lirc/lirc_i2c.c536
-rw-r--r--drivers/staging/lirc/lirc_serial.c4
-rw-r--r--drivers/staging/lirc/lirc_zilog.c48
-rw-r--r--drivers/staging/memrar/memrar.h19
-rw-r--r--drivers/staging/msm/Makefile4
-rw-r--r--drivers/staging/msm/lcdc_toshiba_wvga_pt.c2
-rw-r--r--drivers/staging/msm/msm_fb.c4
-rw-r--r--drivers/staging/msm/msm_fb_bl.c2
-rw-r--r--drivers/staging/msm/tvenc.c5
-rw-r--r--drivers/staging/olpc_dcon/TODO1
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c9
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.h20
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c168
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c4
-rw-r--r--drivers/staging/phison/phison.c2
-rw-r--r--drivers/staging/pohmelfs/crypto.c6
-rw-r--r--drivers/staging/pohmelfs/inode.c13
-rw-r--r--drivers/staging/pohmelfs/net.c2
-rw-r--r--drivers/staging/pohmelfs/path_entry.c17
-rw-r--r--drivers/staging/quickstart/quickstart.c10
-rw-r--r--drivers/staging/rt2860/chip/mac_pci.h7
-rw-r--r--drivers/staging/rt2860/chip/mac_usb.h5
-rw-r--r--drivers/staging/rt2860/chip/rtmp_mac.h19
-rw-r--r--drivers/staging/rt2860/chip/rtmp_phy.h14
-rw-r--r--drivers/staging/rt2860/chips/rt3090.c8
-rw-r--r--drivers/staging/rt2860/chips/rt30xx.c13
-rw-r--r--drivers/staging/rt2860/common/ba_action.c18
-rw-r--r--drivers/staging/rt2860/common/cmm_aes.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_data.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_data_pci.c4
-rw-r--r--drivers/staging/rt2860/common/cmm_mac_pci.c10
-rw-r--r--drivers/staging/rt2860/common/cmm_mac_usb.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_wpa.c22
-rw-r--r--drivers/staging/rt2860/common/ee_efuse.c15
-rw-r--r--drivers/staging/rt2860/common/mlme.c13
-rw-r--r--drivers/staging/rt2860/common/rt_rf.c3
-rw-r--r--drivers/staging/rt2860/common/rtmp_init.c24
-rw-r--r--drivers/staging/rt2860/common/rtmp_mcu.c4
-rw-r--r--drivers/staging/rt2860/common/spectrum.c2
-rw-r--r--drivers/staging/rt2860/mlme.h41
-rw-r--r--drivers/staging/rt2860/oid.h15
-rw-r--r--drivers/staging/rt2860/pci_main_dev.c22
-rw-r--r--drivers/staging/rt2860/rt_linux.c35
-rw-r--r--drivers/staging/rt2860/rt_linux.h11
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c18
-rw-r--r--drivers/staging/rt2860/rt_pci_rbus.c7
-rw-r--r--drivers/staging/rt2860/rt_usb.c45
-rw-r--r--drivers/staging/rt2860/rtmp.h71
-rw-r--r--drivers/staging/rt2860/rtmp_def.h37
-rw-r--r--drivers/staging/rt2860/rtmp_timer.h13
-rw-r--r--drivers/staging/rt2860/spectrum.h12
-rw-r--r--drivers/staging/rt2860/sta/assoc.c15
-rw-r--r--drivers/staging/rt2860/sta/auth.c10
-rw-r--r--drivers/staging/rt2860/sta/connect.c38
-rw-r--r--drivers/staging/rt2860/sta/rtmp_data.c35
-rw-r--r--drivers/staging/rt2860/sta/sanity.c5
-rw-r--r--drivers/staging/rt2860/sta/sync.c25
-rw-r--r--drivers/staging/rt2860/sta/wpa.c5
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c25
-rw-r--r--drivers/staging/rt2860/usb_main_dev.c22
-rw-r--r--drivers/staging/rt2860/wpa.h5
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c30
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c9
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.c2
-rw-r--r--drivers/staging/rtl8192u/Makefile1
-rw-r--r--drivers/staging/rtl8192u/dot11d.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/Makefile2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.h3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h8
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c12
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c47
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c27
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c6
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c6
-rw-r--r--drivers/staging/rtl8712/TODO1
-rw-r--r--drivers/staging/rtl8712/osdep_service.h28
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c2
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c2
-rw-r--r--drivers/staging/rtl8712/usb_intf.c2
-rw-r--r--drivers/staging/samsung-laptop/samsung-laptop.c4
-rw-r--r--drivers/staging/se401/Kconfig13
-rw-r--r--drivers/staging/se401/Makefile1
-rw-r--r--drivers/staging/se401/TODO5
-rw-r--r--drivers/staging/se401/se401.c (renamed from drivers/media/video/se401.c)7
-rw-r--r--drivers/staging/se401/se401.h (renamed from drivers/media/video/se401.h)2
-rw-r--r--drivers/staging/se401/videodev.h318
-rw-r--r--drivers/staging/sep/Kconfig10
-rw-r--r--drivers/staging/sep/Makefile2
-rw-r--r--drivers/staging/sep/TODO5
-rw-r--r--drivers/staging/sep/sep_dev.h156
-rw-r--r--drivers/staging/sep/sep_driver.c3577
-rw-r--r--drivers/staging/sep/sep_driver_api.h297
-rw-r--r--drivers/staging/sep/sep_driver_config.h239
-rw-r--r--drivers/staging/sep/sep_driver_hw_defs.h233
-rw-r--r--drivers/staging/sm7xx/smtcfb.c4
-rw-r--r--drivers/staging/smbfs/cache.c16
-rw-r--r--drivers/staging/smbfs/dir.c61
-rw-r--r--drivers/staging/smbfs/file.c5
-rw-r--r--drivers/staging/smbfs/inode.c15
-rw-r--r--drivers/staging/smbfs/proto.h2
-rw-r--r--drivers/staging/solo6x10/Kconfig4
-rw-r--r--drivers/staging/solo6x10/TODO4
-rw-r--r--drivers/staging/solo6x10/solo6010-core.c42
-rw-r--r--drivers/staging/solo6x10/solo6010-disp.c6
-rw-r--r--drivers/staging/solo6x10/solo6010-enc.c6
-rw-r--r--drivers/staging/solo6x10/solo6010-g723.c22
-rw-r--r--drivers/staging/solo6x10/solo6010-gpio.c4
-rw-r--r--drivers/staging/solo6x10/solo6010-i2c.c13
-rw-r--r--drivers/staging/solo6x10/solo6010-osd-font.h60
-rw-r--r--drivers/staging/solo6x10/solo6010-p2m.c156
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.c118
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2-enc.c370
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2.c197
-rw-r--r--drivers/staging/solo6x10/solo6010.h39
-rw-r--r--drivers/staging/speakup/buffers.c1
-rw-r--r--drivers/staging/speakup/fakekey.c12
-rw-r--r--drivers/staging/speakup/kobjects.c9
-rw-r--r--drivers/staging/speakup/main.c33
-rw-r--r--drivers/staging/speakup/spk_types.h2
-rw-r--r--drivers/staging/spectra/ffsport.c63
-rw-r--r--drivers/staging/spectra/ffsport.h1
-rw-r--r--drivers/staging/spectra/flash.c4
-rw-r--r--drivers/staging/spectra/lld_emu.c6
-rw-r--r--drivers/staging/spectra/lld_nand.c177
-rw-r--r--drivers/staging/ste_rmi4/Kconfig9
-rw-r--r--drivers/staging/ste_rmi4/Makefile4
-rw-r--r--drivers/staging/ste_rmi4/TODO7
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c1179
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h50
-rw-r--r--drivers/staging/stradis/Kconfig7
-rw-r--r--drivers/staging/stradis/Makefile3
-rw-r--r--drivers/staging/stradis/TODO6
-rw-r--r--drivers/staging/stradis/stradis.c2213
-rw-r--r--drivers/staging/tidspbridge/Kconfig1
-rw-r--r--drivers/staging/tidspbridge/Makefile7
-rw-r--r--drivers/staging/tidspbridge/core/_deh.h5
-rw-r--r--drivers/staging/tidspbridge/core/_tiomap.h34
-rw-r--r--drivers/staging/tidspbridge/core/dsp-mmu.c317
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c180
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c1085
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430_pwr.c4
-rw-r--r--drivers/staging/tidspbridge/core/tiomap_io.c17
-rw-r--r--drivers/staging/tidspbridge/core/ue_deh.c115
-rw-r--r--drivers/staging/tidspbridge/hw/EasiGlobal.h41
-rw-r--r--drivers/staging/tidspbridge/hw/MMUAccInt.h76
-rw-r--r--drivers/staging/tidspbridge/hw/MMURegAcM.h225
-rw-r--r--drivers/staging/tidspbridge/hw/hw_defs.h58
-rw-r--r--drivers/staging/tidspbridge/hw/hw_mmu.c562
-rw-r--r--drivers/staging/tidspbridge/hw/hw_mmu.h163
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h1
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dev.h24
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dmm.h75
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/drv.h10
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h67
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspdefs.h44
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspioctl.h7
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/proc.h46
-rw-r--r--drivers/staging/tidspbridge/pmgr/dev.c63
-rw-r--r--drivers/staging/tidspbridge/pmgr/dmm.c533
-rw-r--r--drivers/staging/tidspbridge/pmgr/dspapi.c34
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv.c15
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv_interface.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/nldr.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/node.c48
-rw-r--r--drivers/staging/tidspbridge/rmgr/proc.c197
-rw-r--r--drivers/staging/tm6000/Kconfig2
-rw-r--r--drivers/staging/tm6000/TODO2
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c52
-rw-r--r--drivers/staging/tm6000/tm6000-core.c29
-rw-r--r--drivers/staging/tm6000/tm6000-i2c.c40
-rw-r--r--drivers/staging/tm6000/tm6000-input.c287
-rw-r--r--drivers/staging/tm6000/tm6000-video.c18
-rw-r--r--drivers/staging/tm6000/tm6000.h3
-rw-r--r--drivers/staging/udlfb/Kconfig14
-rw-r--r--drivers/staging/udlfb/Makefile1
-rw-r--r--drivers/staging/udlfb/udlfb.h117
-rw-r--r--drivers/staging/udlfb/udlfb.txt144
-rw-r--r--drivers/staging/usbip/vhci_hcd.c14
-rw-r--r--drivers/staging/usbvideo/Kconfig15
-rw-r--r--drivers/staging/usbvideo/Makefile2
-rw-r--r--drivers/staging/usbvideo/TODO5
-rw-r--r--drivers/staging/usbvideo/usbvideo.c (renamed from drivers/media/video/usbvideo/usbvideo.c)0
-rw-r--r--drivers/staging/usbvideo/usbvideo.h (renamed from drivers/media/video/usbvideo/usbvideo.h)2
-rw-r--r--drivers/staging/usbvideo/vicam.c (renamed from drivers/media/video/usbvideo/vicam.c)31
-rw-r--r--drivers/staging/usbvideo/videodev.h318
-rw-r--r--drivers/staging/vme/bridges/Module.symvers (renamed from drivers/staging/ath6kl/os/linux/include/athendpack_linux.h)0
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c235
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.h2
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c264
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.h2
-rw-r--r--drivers/staging/vme/devices/vme_user.c79
-rw-r--r--drivers/staging/vme/vme.c116
-rw-r--r--drivers/staging/vme/vme_bridge.h2
-rw-r--r--drivers/staging/vt6655/card.c2
-rw-r--r--drivers/staging/vt6655/iwctl.c2
-rw-r--r--drivers/staging/vt6655/wpa2.c4
-rw-r--r--drivers/staging/vt6656/baseband.c2
-rw-r--r--drivers/staging/vt6656/card.c2
-rw-r--r--drivers/staging/vt6656/dpc.c4
-rw-r--r--drivers/staging/vt6656/iwctl.c2
-rw-r--r--drivers/staging/vt6656/main_usb.c3
-rw-r--r--drivers/staging/vt6656/power.c2
-rw-r--r--drivers/staging/vt6656/rxtx.c3
-rw-r--r--drivers/staging/vt6656/tkip.c37
-rw-r--r--drivers/staging/vt6656/wpa2.c4
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasusb.c1
-rw-r--r--drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c10
-rw-r--r--drivers/staging/westbridge/astoria/block/cyasblkdev_block.c2
-rw-r--r--drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c2
-rw-r--r--drivers/staging/winbond/Makefile1
-rw-r--r--drivers/staging/winbond/core.h2
-rw-r--r--drivers/staging/winbond/mac_structures.h545
-rw-r--r--drivers/staging/winbond/mds.c70
-rw-r--r--drivers/staging/winbond/mds_f.h3
-rw-r--r--drivers/staging/winbond/mds_s.h4
-rw-r--r--drivers/staging/winbond/mlmetxrx.c62
-rw-r--r--drivers/staging/winbond/mlmetxrx_f.h23
-rw-r--r--drivers/staging/winbond/mto.c5
-rw-r--r--drivers/staging/winbond/phy_calibration.c5
-rw-r--r--drivers/staging/winbond/phy_calibration.h2
-rw-r--r--drivers/staging/winbond/reg.c36
-rw-r--r--drivers/staging/winbond/sysdef.h28
-rw-r--r--drivers/staging/winbond/wb35reg.c33
-rw-r--r--drivers/staging/winbond/wb35reg_f.h2
-rw-r--r--drivers/staging/winbond/wb35reg_s.h77
-rw-r--r--drivers/staging/winbond/wb35rx.c30
-rw-r--r--drivers/staging/winbond/wb35rx_f.h2
-rw-r--r--drivers/staging/winbond/wb35tx.c31
-rw-r--r--drivers/staging/winbond/wb35tx_f.h1
-rw-r--r--drivers/staging/winbond/wbhal.h (renamed from drivers/staging/winbond/wbhal_s.h)14
-rw-r--r--drivers/staging/winbond/wbhal_f.h81
-rw-r--r--drivers/staging/winbond/wblinux_f.h17
-rw-r--r--drivers/staging/winbond/wbusb.c50
-rw-r--r--drivers/staging/winbond/wbusb_s.h18
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_sysfs.c4
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c6
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c45
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h6
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c8
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h10
-rw-r--r--drivers/staging/wlan-ng/p80211types.h4
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c26
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c9
-rw-r--r--drivers/staging/zram/xvmalloc.c6
-rw-r--r--drivers/staging/zram/zram_drv.c9
-rw-r--r--drivers/staging/zram/zram_sysfs.c4
-rw-r--r--drivers/target/Kconfig32
-rw-r--r--drivers/target/Makefile24
-rw-r--r--drivers/target/target_core_alua.c1991
-rw-r--r--drivers/target/target_core_alua.h126
-rw-r--r--drivers/target/target_core_cdb.c1131
-rw-r--r--drivers/target/target_core_configfs.c3225
-rw-r--r--drivers/target/target_core_device.c1694
-rw-r--r--drivers/target/target_core_fabric_configfs.c996
-rw-r--r--drivers/target/target_core_fabric_lib.c451
-rw-r--r--drivers/target/target_core_file.c688
-rw-r--r--drivers/target/target_core_file.h50
-rw-r--r--drivers/target/target_core_hba.c185
-rw-r--r--drivers/target/target_core_hba.h7
-rw-r--r--drivers/target/target_core_iblock.c808
-rw-r--r--drivers/target/target_core_iblock.h40
-rw-r--r--drivers/target/target_core_mib.c1078
-rw-r--r--drivers/target/target_core_mib.h28
-rw-r--r--drivers/target/target_core_pr.c4252
-rw-r--r--drivers/target/target_core_pr.h67
-rw-r--r--drivers/target/target_core_pscsi.c1470
-rw-r--r--drivers/target/target_core_pscsi.h65
-rw-r--r--drivers/target/target_core_rd.c1091
-rw-r--r--drivers/target/target_core_rd.h73
-rw-r--r--drivers/target/target_core_scdb.c105
-rw-r--r--drivers/target/target_core_scdb.h10
-rw-r--r--drivers/target/target_core_tmr.c404
-rw-r--r--drivers/target/target_core_tpg.c826
-rw-r--r--drivers/target/target_core_transport.c6134
-rw-r--r--drivers/target/target_core_ua.c332
-rw-r--r--drivers/target/target_core_ua.h36
-rw-r--r--drivers/telephony/ixj.c6
-rw-r--r--drivers/thermal/Kconfig1
-rw-r--r--drivers/thermal/thermal_sys.c120
-rw-r--r--drivers/tty/Makefile11
-rw-r--r--drivers/tty/n_gsm.c (renamed from drivers/char/n_gsm.c)220
-rw-r--r--drivers/tty/n_hdlc.c (renamed from drivers/char/n_hdlc.c)0
-rw-r--r--drivers/tty/n_r3964.c (renamed from drivers/char/n_r3964.c)0
-rw-r--r--drivers/tty/n_tty.c (renamed from drivers/char/n_tty.c)0
-rw-r--r--drivers/tty/pty.c (renamed from drivers/char/pty.c)0
-rw-r--r--drivers/tty/sysrq.c (renamed from drivers/char/sysrq.c)169
-rw-r--r--drivers/tty/tty_audit.c (renamed from drivers/char/tty_audit.c)38
-rw-r--r--drivers/tty/tty_buffer.c (renamed from drivers/char/tty_buffer.c)14
-rw-r--r--drivers/tty/tty_io.c (renamed from drivers/char/tty_io.c)65
-rw-r--r--drivers/tty/tty_ioctl.c (renamed from drivers/char/tty_ioctl.c)0
-rw-r--r--drivers/tty/tty_ldisc.c (renamed from drivers/char/tty_ldisc.c)51
-rw-r--r--drivers/tty/tty_mutex.c (renamed from drivers/char/tty_mutex.c)0
-rw-r--r--drivers/tty/tty_port.c (renamed from drivers/char/tty_port.c)0
-rw-r--r--drivers/tty/vt/.gitignore (renamed from drivers/char/.gitignore)0
-rw-r--r--drivers/tty/vt/Makefile34
-rw-r--r--drivers/tty/vt/consolemap.c (renamed from drivers/char/consolemap.c)0
-rw-r--r--drivers/tty/vt/cp437.uni (renamed from drivers/char/cp437.uni)0
-rw-r--r--drivers/tty/vt/defkeymap.c_shipped (renamed from drivers/char/defkeymap.c_shipped)0
-rw-r--r--drivers/tty/vt/defkeymap.map (renamed from drivers/char/defkeymap.map)0
-rw-r--r--drivers/tty/vt/keyboard.c (renamed from drivers/char/keyboard.c)0
-rw-r--r--drivers/tty/vt/selection.c (renamed from drivers/char/selection.c)0
-rw-r--r--drivers/tty/vt/vc_screen.c (renamed from drivers/char/vc_screen.c)6
-rw-r--r--drivers/tty/vt/vt.c (renamed from drivers/char/vt.c)23
-rw-r--r--drivers/tty/vt/vt_ioctl.c (renamed from drivers/char/vt_ioctl.c)0
-rw-r--r--drivers/uio/uio.c2
-rw-r--r--drivers/uio/uio_cif.c2
-rw-r--r--drivers/uio/uio_netx.c2
-rw-r--r--drivers/usb/Kconfig11
-rw-r--r--drivers/usb/atm/cxacru.c2
-rw-r--r--drivers/usb/atm/speedtch.c28
-rw-r--r--drivers/usb/atm/ueagle-atm.c29
-rw-r--r--drivers/usb/atm/usbatm.c15
-rw-r--r--drivers/usb/core/Kconfig12
-rw-r--r--drivers/usb/core/devices.c1
-rw-r--r--drivers/usb/core/devio.c8
-rw-r--r--drivers/usb/core/driver.c157
-rw-r--r--drivers/usb/core/file.c1
-rw-r--r--drivers/usb/core/hcd-pci.c1
-rw-r--r--drivers/usb/core/hcd.c3
-rw-r--r--drivers/usb/core/hub.c11
-rw-r--r--drivers/usb/core/inode.c13
-rw-r--r--drivers/usb/core/message.c1
-rw-r--r--drivers/usb/core/quirks.c15
-rw-r--r--drivers/usb/core/sysfs.c84
-rw-r--r--drivers/usb/core/usb.c3
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/gadget/Kconfig79
-rw-r--r--drivers/usb/gadget/Makefile8
-rw-r--r--drivers/usb/gadget/amd5536udc.c1
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c6
-rw-r--r--drivers/usb/gadget/ci13xxx_msm.c134
-rw-r--r--drivers/usb/gadget/ci13xxx_pci.c176
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c421
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h20
-rw-r--r--drivers/usb/gadget/composite.c28
-rw-r--r--drivers/usb/gadget/dummy_hcd.c251
-rw-r--r--drivers/usb/gadget/f_fs.c438
-rw-r--r--drivers/usb/gadget/f_hid.c1
-rw-r--r--drivers/usb/gadget/f_mass_storage.c524
-rw-r--r--drivers/usb/gadget/f_ncm.c1407
-rw-r--r--drivers/usb/gadget/file_storage.c29
-rw-r--r--drivers/usb/gadget/fsl_mxc_udc.c4
-rw-r--r--drivers/usb/gadget/g_ffs.c41
-rw-r--r--drivers/usb/gadget/gadget_chips.h25
-rw-r--r--drivers/usb/gadget/goku_udc.h3
-rw-r--r--drivers/usb/gadget/imx_udc.c10
-rw-r--r--drivers/usb/gadget/imx_udc.h3
-rw-r--r--drivers/usb/gadget/langwell_udc.c27
-rw-r--r--drivers/usb/gadget/mass_storage.c2
-rw-r--r--drivers/usb/gadget/mv_udc.h294
-rw-r--r--drivers/usb/gadget/mv_udc_core.c2149
-rw-r--r--drivers/usb/gadget/mv_udc_phy.c214
-rw-r--r--drivers/usb/gadget/ncm.c248
-rw-r--r--drivers/usb/gadget/pch_udc.c2947
-rw-r--r--drivers/usb/gadget/storage_common.c7
-rw-r--r--drivers/usb/gadget/u_audio.c10
-rw-r--r--drivers/usb/gadget/u_ether.c19
-rw-r--r--drivers/usb/gadget/u_ether.h5
-rw-r--r--drivers/usb/gadget/u_serial.c54
-rw-r--r--drivers/usb/host/Kconfig36
-rw-r--r--drivers/usb/host/ehci-atmel.c3
-rw-r--r--drivers/usb/host/ehci-cns3xxx.c171
-rw-r--r--drivers/usb/host/ehci-dbg.c4
-rw-r--r--drivers/usb/host/ehci-hcd.c45
-rw-r--r--drivers/usb/host/ehci-mem.c26
-rw-r--r--drivers/usb/host/ehci-msm.c345
-rw-r--r--drivers/usb/host/ehci-mxc.c69
-rw-r--r--drivers/usb/host/ehci-omap.c316
-rw-r--r--drivers/usb/host/ehci-pci.c64
-rw-r--r--drivers/usb/host/ehci-sched.c100
-rw-r--r--drivers/usb/host/ehci-sh.c243
-rw-r--r--drivers/usb/host/ehci-spear.c212
-rw-r--r--drivers/usb/host/ehci-vt8500.c172
-rw-r--r--drivers/usb/host/ehci-w90x900.c3
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c1
-rw-r--r--drivers/usb/host/ehci.h3
-rw-r--r--drivers/usb/host/fhci-hcd.c4
-rw-r--r--drivers/usb/host/fhci-tds.c4
-rw-r--r--drivers/usb/host/imx21-hcd.c2
-rw-r--r--drivers/usb/host/isp1362-hcd.c3
-rw-r--r--drivers/usb/host/ohci-cns3xxx.c165
-rw-r--r--drivers/usb/host/ohci-hcd.c13
-rw-r--r--drivers/usb/host/ohci-jz4740.c2
-rw-r--r--drivers/usb/host/ohci-omap3.c2
-rw-r--r--drivers/usb/host/ohci-sh.c2
-rw-r--r--drivers/usb/host/ohci-spear.c240
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c2
-rw-r--r--drivers/usb/host/uhci-debug.c1
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/uhci-q.c12
-rw-r--r--drivers/usb/host/whci/hcd.c2
-rw-r--r--drivers/usb/host/xhci-hub.c7
-rw-r--r--drivers/usb/host/xhci-mem.c173
-rw-r--r--drivers/usb/host/xhci-ring.c1
-rw-r--r--drivers/usb/host/xhci.c91
-rw-r--r--drivers/usb/host/xhci.h31
-rw-r--r--drivers/usb/image/microtek.c6
-rw-r--r--drivers/usb/misc/adutux.c2
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c6
-rw-r--r--drivers/usb/misc/iowarrior.c3
-rw-r--r--drivers/usb/misc/ldusb.c2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1
-rw-r--r--drivers/usb/misc/trancevibrator.c2
-rw-r--r--drivers/usb/misc/usbled.c120
-rw-r--r--drivers/usb/misc/usbsevseg.c10
-rw-r--r--drivers/usb/misc/uss720.c4
-rw-r--r--drivers/usb/misc/yurex.c1
-rw-r--r--drivers/usb/mon/mon_bin.c35
-rw-r--r--drivers/usb/mon/mon_stat.c1
-rw-r--r--drivers/usb/musb/Kconfig77
-rw-r--r--drivers/usb/musb/Makefile21
-rw-r--r--drivers/usb/musb/am35x.c410
-rw-r--r--drivers/usb/musb/blackfin.c237
-rw-r--r--drivers/usb/musb/cppi_dma.c2
-rw-r--r--drivers/usb/musb/da8xx.c170
-rw-r--r--drivers/usb/musb/davinci.c174
-rw-r--r--drivers/usb/musb/musb_core.c213
-rw-r--r--drivers/usb/musb/musb_core.h190
-rw-r--r--drivers/usb/musb/musb_debugfs.c1
-rw-r--r--drivers/usb/musb/musb_gadget.c182
-rw-r--r--drivers/usb/musb/musb_io.h4
-rw-r--r--drivers/usb/musb/musb_regs.h7
-rw-r--r--drivers/usb/musb/musb_virthub.c2
-rw-r--r--drivers/usb/musb/musbhsdma.c16
-rw-r--r--drivers/usb/musb/omap2430.c378
-rw-r--r--drivers/usb/musb/tusb6010.c181
-rw-r--r--drivers/usb/musb/ux500.c216
-rw-r--r--drivers/usb/otg/Kconfig32
-rw-r--r--drivers/usb/otg/Makefile3
-rw-r--r--drivers/usb/otg/ab8500-usb.c585
-rw-r--r--drivers/usb/otg/isp1301_omap.c2
-rw-r--r--drivers/usb/otg/langwell_otg.c9
-rw-r--r--drivers/usb/otg/msm72k_otg.c1125
-rw-r--r--drivers/usb/otg/twl4030-usb.c3
-rw-r--r--drivers/usb/otg/twl6030-usb.c493
-rw-r--r--drivers/usb/serial/ftdi_sio.c32
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h16
-rw-r--r--drivers/usb/serial/option.c4
-rw-r--r--drivers/usb/serial/oti6858.c5
-rw-r--r--drivers/usb/serial/ssu100.c56
-rw-r--r--drivers/usb/serial/usb-serial.c4
-rw-r--r--drivers/usb/serial/usb-wwan.h2
-rw-r--r--drivers/usb/serial/usb_wwan.c79
-rw-r--r--drivers/usb/storage/scsiglue.c4
-rw-r--r--drivers/usb/storage/sierra_ms.c2
-rw-r--r--drivers/usb/storage/uas.c91
-rw-r--r--drivers/usb/storage/unusual_devs.h7
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c2
-rw-r--r--drivers/uwb/allocator.c3
-rw-r--r--drivers/uwb/i1480/i1480-est.c2
-rw-r--r--drivers/uwb/umc-dev.c7
-rw-r--r--drivers/uwb/whc-rc.c2
-rw-r--r--drivers/vhost/net.c14
-rw-r--r--drivers/vhost/test.c320
-rw-r--r--drivers/vhost/test.h7
-rw-r--r--drivers/vhost/vhost.c62
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--drivers/video/Kconfig148
-rw-r--r--drivers/video/Makefile7
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/aty/aty128fb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c29
-rw-r--r--drivers/video/aty/radeon_backlight.c2
-rw-r--r--drivers/video/backlight/88pm860x_bl.c2
-rw-r--r--drivers/video/backlight/adp8860_bl.c8
-rw-r--r--drivers/video/backlight/backlight.c12
-rw-r--r--drivers/video/backlight/cr_bllcd.c1
-rw-r--r--drivers/video/backlight/l4f00242t03.c108
-rw-r--r--drivers/video/backlight/lms283gf05.c2
-rw-r--r--drivers/video/backlight/max8925_bl.c2
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c18
-rw-r--r--drivers/video/backlight/pwm_bl.c7
-rw-r--r--drivers/video/backlight/s6e63m0.c7
-rw-r--r--drivers/video/bf537-lq035.c914
-rw-r--r--drivers/video/bfin_adv7393fb.c832
-rw-r--r--drivers/video/bfin_adv7393fb.h321
-rw-r--r--drivers/video/carminefb.c6
-rw-r--r--drivers/video/console/vgacon.c4
-rw-r--r--drivers/video/da8xx-fb.c14
-rw-r--r--drivers/video/ep93xx-fb.c6
-rw-r--r--drivers/video/fb_defio.c2
-rw-r--r--drivers/video/fbcmap.c69
-rw-r--r--drivers/video/fbmem.c2
-rw-r--r--drivers/video/fbmon.c88
-rw-r--r--drivers/video/geode/lxfb.h4
-rw-r--r--drivers/video/geode/lxfb_ops.c24
-rw-r--r--drivers/video/hgafb.c22
-rw-r--r--drivers/video/i810/i810-i2c.c12
-rw-r--r--drivers/video/imxfb.c11
-rw-r--r--drivers/video/matrox/matroxfb_base.c70
-rw-r--r--drivers/video/modedb.c446
-rw-r--r--drivers/video/mx3fb.c7
-rw-r--r--drivers/video/nuc900fb.c5
-rw-r--r--drivers/video/nvidia/nv_backlight.c2
-rw-r--r--drivers/video/omap/Kconfig4
-rw-r--r--drivers/video/omap/lcd_mipid.c2
-rw-r--r--drivers/video/omap2/displays/Kconfig27
-rw-r--r--drivers/video/omap2/displays/Makefile5
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c365
-rw-r--r--drivers/video/omap2/displays/panel-generic.c174
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c325
-rw-r--r--drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c165
-rw-r--r--drivers/video/omap2/displays/panel-taal.c2
-rw-r--r--drivers/video/omap2/displays/panel-toppoly-tdo35s.c164
-rw-r--r--drivers/video/omap2/dss/dispc.c636
-rw-r--r--drivers/video/omap2/dss/dpi.c40
-rw-r--r--drivers/video/omap2/dss/dsi.c27
-rw-r--r--drivers/video/omap2/dss/dss.h35
-rw-r--r--drivers/video/omap2/dss/dss_features.c66
-rw-r--r--drivers/video/omap2/dss/dss_features.h10
-rw-r--r--drivers/video/omap2/dss/manager.c80
-rw-r--r--drivers/video/omap2/dss/overlay.c55
-rw-r--r--drivers/video/omap2/dss/rfbi.c20
-rw-r--r--drivers/video/omap2/dss/sdi.c24
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c5
-rw-r--r--drivers/video/omap2/vram.c19
-rw-r--r--drivers/video/pxa3xx-gcu.c772
-rw-r--r--drivers/video/pxa3xx-gcu.h38
-rw-r--r--drivers/video/riva/fbdev.c2
-rw-r--r--drivers/video/riva/rivafb-i2c.c1
-rw-r--r--drivers/video/s1d13xxxfb.c50
-rw-r--r--drivers/video/s3c-fb.c111
-rw-r--r--drivers/video/s3c2410fb.c5
-rw-r--r--drivers/video/sh_mipi_dsi.c129
-rw-r--r--drivers/video/sh_mobile_hdmi.c332
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c127
-rw-r--r--drivers/video/sis/init.c719
-rw-r--r--drivers/video/sis/init.h76
-rw-r--r--drivers/video/sis/init301.c475
-rw-r--r--drivers/video/sis/init301.h54
-rw-r--r--drivers/video/sis/initextlfb.c7
-rw-r--r--drivers/video/sis/osdef.h133
-rw-r--r--drivers/video/sis/sis.h66
-rw-r--r--drivers/video/sis/sis_main.c1232
-rw-r--r--drivers/video/sis/vgatypes.h11
-rw-r--r--drivers/video/sis/vstruct.h12
-rw-r--r--drivers/video/sstfb.c2
-rw-r--r--drivers/video/udlfb.c (renamed from drivers/staging/udlfb/udlfb.c)142
-rw-r--r--drivers/video/via/via-core.c96
-rw-r--r--drivers/video/via/via-gpio.c29
-rw-r--r--drivers/video/via/viafbdev.c34
-rw-r--r--drivers/video/via/viafbdev.h2
-rw-r--r--drivers/video/vt8500lcdfb.c475
-rw-r--r--drivers/video/vt8500lcdfb.h34
-rw-r--r--drivers/video/wm8505fb.c422
-rw-r--r--drivers/video/wm8505fb_regs.h76
-rw-r--r--drivers/video/wmt_ge_rops.c186
-rw-r--r--drivers/video/wmt_ge_rops.h5
-rw-r--r--drivers/video/xen-fbfront.c21
-rw-r--r--drivers/virtio/virtio.c6
-rw-r--r--drivers/virtio/virtio_ring.c3
-rw-r--r--drivers/w1/slaves/Kconfig11
-rw-r--r--drivers/w1/slaves/Makefile1
-rw-r--r--drivers/w1/slaves/w1_ds2423.c166
-rw-r--r--drivers/w1/w1_family.h1
-rw-r--r--drivers/watchdog/Kconfig59
-rw-r--r--drivers/watchdog/Makefile6
-rw-r--r--drivers/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/ath79_wdt.c305
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c42
-rw-r--r--drivers/watchdog/booke_wdt.c35
-rw-r--r--drivers/watchdog/f71808e_wdt.c78
-rw-r--r--drivers/watchdog/gef_wdt.c1
-rw-r--r--drivers/watchdog/hpwdt.c13
-rw-r--r--drivers/watchdog/iTCO_wdt.c20
-rw-r--r--drivers/watchdog/imx2_wdt.c2
-rw-r--r--drivers/watchdog/ks8695_wdt.c2
-rw-r--r--drivers/watchdog/m548x_wdt.c227
-rw-r--r--drivers/watchdog/nv_tco.c512
-rw-r--r--drivers/watchdog/nv_tco.h64
-rw-r--r--drivers/watchdog/rdc321x_wdt.c2
-rw-r--r--drivers/watchdog/sp5100_tco.c480
-rw-r--r--drivers/watchdog/sp5100_tco.h41
-rw-r--r--drivers/watchdog/w83627hf_wdt.c8
-rw-r--r--drivers/xen/Kconfig20
-rw-r--r--drivers/xen/Makefile10
-rw-r--r--drivers/xen/balloon.c42
-rw-r--r--drivers/xen/events.c178
-rw-r--r--drivers/xen/evtchn.c100
-rw-r--r--drivers/xen/gntdev.c665
-rw-r--r--drivers/xen/grant-table.c46
-rw-r--r--drivers/xen/manage.c1
-rw-r--r--drivers/xen/platform-pci.c21
-rw-r--r--drivers/xen/xenbus/Makefile5
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c351
-rw-r--r--drivers/xen/xenbus/xenbus_probe.h31
-rw-r--r--drivers/xen/xenbus/xenbus_probe_backend.c276
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c294
-rw-r--r--drivers/xen/xenfs/privcmd.c14
-rw-r--r--drivers/xen/xenfs/super.c46
-rw-r--r--drivers/zorro/proc.c1
3728 files changed, 311090 insertions, 140335 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a2b902f4d437..9bfb71ff3a6a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -26,6 +26,8 @@ source "drivers/ata/Kconfig"
source "drivers/md/Kconfig"
+source "drivers/target/Kconfig"
+
source "drivers/message/fusion/Kconfig"
source "drivers/firewire/Kconfig"
@@ -88,6 +90,8 @@ source "drivers/memstick/Kconfig"
source "drivers/leds/Kconfig"
+source "drivers/nfc/Kconfig"
+
source "drivers/accessibility/Kconfig"
source "drivers/infiniband/Kconfig"
@@ -111,4 +115,6 @@ source "drivers/xen/Kconfig"
source "drivers/staging/Kconfig"
source "drivers/platform/Kconfig"
+
+source "drivers/clk/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 14cf9077bb2b..7eb35f479461 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR) += regulator/
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
+obj-y += tty/
obj-y += char/
# gpu/ comes after char for AGP vs DRM startup
@@ -39,12 +40,13 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ mfd/
+obj-y += base/ block/ misc/ mfd/ nfc/
obj-$(CONFIG_NUBUS) += nubus/
obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
+obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
obj-y += net/
@@ -114,3 +116,5 @@ obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
obj-y += ieee802154/
+#common clk code
+obj-y += clk/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 3f3489c5ca8c..10c7ad59c0e1 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -51,12 +51,7 @@ config ACPI_PROCFS
For backwards compatibility, this option allows
deprecated /proc/acpi/ files to exist, even when
they have been replaced by functions in /sys.
- The deprecated files (and their replacements) include:
- /proc/acpi/processor/*/throttling (/sys/class/thermal/
- cooling_device*/*)
- /proc/acpi/video/*/brightness (/sys/class/backlight/)
- /proc/acpi/thermal_zone/*/* (/sys/class/thermal/)
This option has no effect on /proc/acpi/ files
and functions which do not yet exist in /sys.
@@ -74,6 +69,8 @@ config ACPI_PROCFS_POWER
/proc/acpi/ac_adapter/* (sys/class/power_supply/*)
This option has no effect on /proc/acpi/ directories
and functions, which do not yet exist in /sys
+ This option, together with the proc directories, will be
+ deleted in 2.6.39.
Say N to delete power /proc/acpi/ directories that have moved to /sys/
@@ -209,6 +206,17 @@ config ACPI_PROCESSOR
To compile this driver as a module, choose M here:
the module will be called processor.
+config ACPI_IPMI
+ tristate "IPMI"
+ depends on EXPERIMENTAL && IPMI_SI && IPMI_HANDLER
+ default n
+ help
+ This driver enables the ACPI to access the BMC controller. And it
+ uses the IPMI request/response message to communicate with BMC
+ controller, which can be found on on the server.
+
+ To compile this driver as a module, choose M here:
+ the module will be called as acpi_ipmi.
config ACPI_HOTPLUG_CPU
bool
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3d031d02e54b..d113fa5100b2 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -24,7 +24,7 @@ acpi-y += atomicio.o
# sleep related files
acpi-y += wakeup.o
acpi-y += sleep.o
-acpi-$(CONFIG_ACPI_SLEEP) += proc.o
+acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
#
@@ -69,5 +69,6 @@ processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
+obj-$(CONFIG_ACPI_IPMI) += acpi_ipmi.o
obj-$(CONFIG_ACPI_APEI) += apei/
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index ba9afeaa23ac..58c3f74bd84c 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -100,24 +100,7 @@ static const struct file_operations acpi_ac_fops = {
.release = single_release,
};
#endif
-static int get_ac_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct acpi_ac *ac = to_acpi_ac(psy);
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = ac->state;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-static enum power_supply_property ac_props[] = {
- POWER_SUPPLY_PROP_ONLINE,
-};
/* --------------------------------------------------------------------------
AC Adapter Management
-------------------------------------------------------------------------- */
@@ -140,6 +123,35 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
return 0;
}
+/* --------------------------------------------------------------------------
+ sysfs I/F
+ -------------------------------------------------------------------------- */
+static int get_ac_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct acpi_ac *ac = to_acpi_ac(psy);
+
+ if (!ac)
+ return -ENODEV;
+
+ if (acpi_ac_get_state(ac))
+ return -ENODEV;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = ac->state;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
#ifdef CONFIG_ACPI_PROCFS_POWER
/* --------------------------------------------------------------------------
FS Interface (/proc)
@@ -185,7 +197,8 @@ static int acpi_ac_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for AC is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ac_dir);
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
new file mode 100644
index 000000000000..f40acef80269
--- /dev/null
+++ b/drivers/acpi/acpi_ipmi.c
@@ -0,0 +1,525 @@
+/*
+ * acpi_ipmi.c - ACPI IPMI opregion
+ *
+ * Copyright (C) 2010 Intel Corporation
+ * Copyright (C) 2010 Zhao Yakui <yakui.zhao@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/ipmi.h>
+#include <linux/device.h>
+#include <linux/pnp.h>
+
+MODULE_AUTHOR("Zhao Yakui");
+MODULE_DESCRIPTION("ACPI IPMI Opregion driver");
+MODULE_LICENSE("GPL");
+
+#define IPMI_FLAGS_HANDLER_INSTALL 0
+
+#define ACPI_IPMI_OK 0
+#define ACPI_IPMI_TIMEOUT 0x10
+#define ACPI_IPMI_UNKNOWN 0x07
+/* the IPMI timeout is 5s */
+#define IPMI_TIMEOUT (5 * HZ)
+
+struct acpi_ipmi_device {
+ /* the device list attached to driver_data.ipmi_devices */
+ struct list_head head;
+ /* the IPMI request message list */
+ struct list_head tx_msg_list;
+ struct mutex tx_msg_lock;
+ acpi_handle handle;
+ struct pnp_dev *pnp_dev;
+ ipmi_user_t user_interface;
+ int ipmi_ifnum; /* IPMI interface number */
+ long curr_msgid;
+ unsigned long flags;
+ struct ipmi_smi_info smi_data;
+};
+
+struct ipmi_driver_data {
+ struct list_head ipmi_devices;
+ struct ipmi_smi_watcher bmc_events;
+ struct ipmi_user_hndl ipmi_hndlrs;
+ struct mutex ipmi_lock;
+};
+
+struct acpi_ipmi_msg {
+ struct list_head head;
+ /*
+ * General speaking the addr type should be SI_ADDR_TYPE. And
+ * the addr channel should be BMC.
+ * In fact it can also be IPMB type. But we will have to
+ * parse it from the Netfn command buffer. It is so complex
+ * that it is skipped.
+ */
+ struct ipmi_addr addr;
+ long tx_msgid;
+ /* it is used to track whether the IPMI message is finished */
+ struct completion tx_complete;
+ struct kernel_ipmi_msg tx_message;
+ int msg_done;
+ /* tx data . And copy it from ACPI object buffer */
+ u8 tx_data[64];
+ int tx_len;
+ u8 rx_data[64];
+ int rx_len;
+ struct acpi_ipmi_device *device;
+};
+
+/* IPMI request/response buffer per ACPI 4.0, sec 5.5.2.4.3.2 */
+struct acpi_ipmi_buffer {
+ u8 status;
+ u8 length;
+ u8 data[64];
+};
+
+static void ipmi_register_bmc(int iface, struct device *dev);
+static void ipmi_bmc_gone(int iface);
+static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device);
+static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device);
+
+static struct ipmi_driver_data driver_data = {
+ .ipmi_devices = LIST_HEAD_INIT(driver_data.ipmi_devices),
+ .bmc_events = {
+ .owner = THIS_MODULE,
+ .new_smi = ipmi_register_bmc,
+ .smi_gone = ipmi_bmc_gone,
+ },
+ .ipmi_hndlrs = {
+ .ipmi_recv_hndl = ipmi_msg_handler,
+ },
+};
+
+static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi)
+{
+ struct acpi_ipmi_msg *ipmi_msg;
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+
+ ipmi_msg = kzalloc(sizeof(struct acpi_ipmi_msg), GFP_KERNEL);
+ if (!ipmi_msg) {
+ dev_warn(&pnp_dev->dev, "Can't allocate memory for ipmi_msg\n");
+ return NULL;
+ }
+ init_completion(&ipmi_msg->tx_complete);
+ INIT_LIST_HEAD(&ipmi_msg->head);
+ ipmi_msg->device = ipmi;
+ return ipmi_msg;
+}
+
+#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff)
+#define IPMI_OP_RGN_CMD(offset) (offset & 0xff)
+static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
+ acpi_physical_address address,
+ acpi_integer *value)
+{
+ struct kernel_ipmi_msg *msg;
+ struct acpi_ipmi_buffer *buffer;
+ struct acpi_ipmi_device *device;
+
+ msg = &tx_msg->tx_message;
+ /*
+ * IPMI network function and command are encoded in the address
+ * within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3.
+ */
+ msg->netfn = IPMI_OP_RGN_NETFN(address);
+ msg->cmd = IPMI_OP_RGN_CMD(address);
+ msg->data = tx_msg->tx_data;
+ /*
+ * value is the parameter passed by the IPMI opregion space handler.
+ * It points to the IPMI request message buffer
+ */
+ buffer = (struct acpi_ipmi_buffer *)value;
+ /* copy the tx message data */
+ msg->data_len = buffer->length;
+ memcpy(tx_msg->tx_data, buffer->data, msg->data_len);
+ /*
+ * now the default type is SYSTEM_INTERFACE and channel type is BMC.
+ * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE,
+ * the addr type should be changed to IPMB. Then we will have to parse
+ * the IPMI request message buffer to get the IPMB address.
+ * If so, please fix me.
+ */
+ tx_msg->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ tx_msg->addr.channel = IPMI_BMC_CHANNEL;
+ tx_msg->addr.data[0] = 0;
+
+ /* Get the msgid */
+ device = tx_msg->device;
+ mutex_lock(&device->tx_msg_lock);
+ device->curr_msgid++;
+ tx_msg->tx_msgid = device->curr_msgid;
+ mutex_unlock(&device->tx_msg_lock);
+}
+
+static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
+ acpi_integer *value, int rem_time)
+{
+ struct acpi_ipmi_buffer *buffer;
+
+ /*
+ * value is also used as output parameter. It represents the response
+ * IPMI message returned by IPMI command.
+ */
+ buffer = (struct acpi_ipmi_buffer *)value;
+ if (!rem_time && !msg->msg_done) {
+ buffer->status = ACPI_IPMI_TIMEOUT;
+ return;
+ }
+ /*
+ * If the flag of msg_done is not set or the recv length is zero, it
+ * means that the IPMI command is not executed correctly.
+ * The status code will be ACPI_IPMI_UNKNOWN.
+ */
+ if (!msg->msg_done || !msg->rx_len) {
+ buffer->status = ACPI_IPMI_UNKNOWN;
+ return;
+ }
+ /*
+ * If the IPMI response message is obtained correctly, the status code
+ * will be ACPI_IPMI_OK
+ */
+ buffer->status = ACPI_IPMI_OK;
+ buffer->length = msg->rx_len;
+ memcpy(buffer->data, msg->rx_data, msg->rx_len);
+}
+
+static void ipmi_flush_tx_msg(struct acpi_ipmi_device *ipmi)
+{
+ struct acpi_ipmi_msg *tx_msg, *temp;
+ int count = HZ / 10;
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+
+ list_for_each_entry_safe(tx_msg, temp, &ipmi->tx_msg_list, head) {
+ /* wake up the sleep thread on the Tx msg */
+ complete(&tx_msg->tx_complete);
+ }
+
+ /* wait for about 100ms to flush the tx message list */
+ while (count--) {
+ if (list_empty(&ipmi->tx_msg_list))
+ break;
+ schedule_timeout(1);
+ }
+ if (!list_empty(&ipmi->tx_msg_list))
+ dev_warn(&pnp_dev->dev, "tx msg list is not NULL\n");
+}
+
+static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+ struct acpi_ipmi_device *ipmi_device = user_msg_data;
+ int msg_found = 0;
+ struct acpi_ipmi_msg *tx_msg;
+ struct pnp_dev *pnp_dev = ipmi_device->pnp_dev;
+
+ if (msg->user != ipmi_device->user_interface) {
+ dev_warn(&pnp_dev->dev, "Unexpected response is returned. "
+ "returned user %p, expected user %p\n",
+ msg->user, ipmi_device->user_interface);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) {
+ if (msg->msgid == tx_msg->tx_msgid) {
+ msg_found = 1;
+ break;
+ }
+ }
+
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ if (!msg_found) {
+ dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is "
+ "returned.\n", msg->msgid);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+
+ if (msg->msg.data_len) {
+ /* copy the response data to Rx_data buffer */
+ memcpy(tx_msg->rx_data, msg->msg_data, msg->msg.data_len);
+ tx_msg->rx_len = msg->msg.data_len;
+ tx_msg->msg_done = 1;
+ }
+ complete(&tx_msg->tx_complete);
+ ipmi_free_recv_msg(msg);
+};
+
+static void ipmi_register_bmc(int iface, struct device *dev)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+ struct pnp_dev *pnp_dev;
+ ipmi_user_t user;
+ int err;
+ struct ipmi_smi_info smi_data;
+ acpi_handle handle;
+
+ err = ipmi_get_smi_info(iface, &smi_data);
+
+ if (err)
+ return;
+
+ if (smi_data.addr_src != SI_ACPI) {
+ put_device(smi_data.dev);
+ return;
+ }
+
+ handle = smi_data.addr_info.acpi_info.acpi_handle;
+
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry(temp, &driver_data.ipmi_devices, head) {
+ /*
+ * if the corresponding ACPI handle is already added
+ * to the device list, don't add it again.
+ */
+ if (temp->handle == handle)
+ goto out;
+ }
+
+ ipmi_device = kzalloc(sizeof(*ipmi_device), GFP_KERNEL);
+
+ if (!ipmi_device)
+ goto out;
+
+ pnp_dev = to_pnp_dev(smi_data.dev);
+ ipmi_device->handle = handle;
+ ipmi_device->pnp_dev = pnp_dev;
+
+ err = ipmi_create_user(iface, &driver_data.ipmi_hndlrs,
+ ipmi_device, &user);
+ if (err) {
+ dev_warn(&pnp_dev->dev, "Can't create IPMI user interface\n");
+ kfree(ipmi_device);
+ goto out;
+ }
+ acpi_add_ipmi_device(ipmi_device);
+ ipmi_device->user_interface = user;
+ ipmi_device->ipmi_ifnum = iface;
+ mutex_unlock(&driver_data.ipmi_lock);
+ memcpy(&ipmi_device->smi_data, &smi_data, sizeof(struct ipmi_smi_info));
+ return;
+
+out:
+ mutex_unlock(&driver_data.ipmi_lock);
+ put_device(smi_data.dev);
+ return;
+}
+
+static void ipmi_bmc_gone(int iface)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry_safe(ipmi_device, temp,
+ &driver_data.ipmi_devices, head) {
+ if (ipmi_device->ipmi_ifnum != iface)
+ continue;
+
+ acpi_remove_ipmi_device(ipmi_device);
+ put_device(ipmi_device->smi_data.dev);
+ kfree(ipmi_device);
+ break;
+ }
+ mutex_unlock(&driver_data.ipmi_lock);
+}
+/* --------------------------------------------------------------------------
+ * Address Space Management
+ * -------------------------------------------------------------------------- */
+/*
+ * This is the IPMI opregion space handler.
+ * @function: indicates the read/write. In fact as the IPMI message is driven
+ * by command, only write is meaningful.
+ * @address: This contains the netfn/command of IPMI request message.
+ * @bits : not used.
+ * @value : it is an in/out parameter. It points to the IPMI message buffer.
+ * Before the IPMI message is sent, it represents the actual request
+ * IPMI message. After the IPMI message is finished, it represents
+ * the response IPMI message returned by IPMI command.
+ * @handler_context: IPMI device context.
+ */
+
+static acpi_status
+acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, acpi_integer *value,
+ void *handler_context, void *region_context)
+{
+ struct acpi_ipmi_msg *tx_msg;
+ struct acpi_ipmi_device *ipmi_device = handler_context;
+ int err, rem_time;
+ acpi_status status;
+ /*
+ * IPMI opregion message.
+ * IPMI message is firstly written to the BMC and system software
+ * can get the respsonse. So it is unmeaningful for the read access
+ * of IPMI opregion.
+ */
+ if ((function & ACPI_IO_MASK) == ACPI_READ)
+ return AE_TYPE;
+
+ if (!ipmi_device->user_interface)
+ return AE_NOT_EXIST;
+
+ tx_msg = acpi_alloc_ipmi_msg(ipmi_device);
+ if (!tx_msg)
+ return AE_NO_MEMORY;
+
+ acpi_format_ipmi_msg(tx_msg, address, value);
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ err = ipmi_request_settime(ipmi_device->user_interface,
+ &tx_msg->addr,
+ tx_msg->tx_msgid,
+ &tx_msg->tx_message,
+ NULL, 0, 0, 0);
+ if (err) {
+ status = AE_ERROR;
+ goto end_label;
+ }
+ rem_time = wait_for_completion_timeout(&tx_msg->tx_complete,
+ IPMI_TIMEOUT);
+ acpi_format_ipmi_response(tx_msg, value, rem_time);
+ status = AE_OK;
+
+end_label:
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_del(&tx_msg->head);
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ kfree(tx_msg);
+ return status;
+}
+
+static void ipmi_remove_space_handler(struct acpi_ipmi_device *ipmi)
+{
+ if (!test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags))
+ return;
+
+ acpi_remove_address_space_handler(ipmi->handle,
+ ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler);
+
+ clear_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags);
+}
+
+static int ipmi_install_space_handler(struct acpi_ipmi_device *ipmi)
+{
+ acpi_status status;
+
+ if (test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags))
+ return 0;
+
+ status = acpi_install_address_space_handler(ipmi->handle,
+ ACPI_ADR_SPACE_IPMI,
+ &acpi_ipmi_space_handler,
+ NULL, ipmi);
+ if (ACPI_FAILURE(status)) {
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+ dev_warn(&pnp_dev->dev, "Can't register IPMI opregion space "
+ "handle\n");
+ return -EINVAL;
+ }
+ set_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags);
+ return 0;
+}
+
+static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device)
+{
+
+ INIT_LIST_HEAD(&ipmi_device->head);
+
+ mutex_init(&ipmi_device->tx_msg_lock);
+ INIT_LIST_HEAD(&ipmi_device->tx_msg_list);
+ ipmi_install_space_handler(ipmi_device);
+
+ list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices);
+}
+
+static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device)
+{
+ /*
+ * If the IPMI user interface is created, it should be
+ * destroyed.
+ */
+ if (ipmi_device->user_interface) {
+ ipmi_destroy_user(ipmi_device->user_interface);
+ ipmi_device->user_interface = NULL;
+ }
+ /* flush the Tx_msg list */
+ if (!list_empty(&ipmi_device->tx_msg_list))
+ ipmi_flush_tx_msg(ipmi_device);
+
+ list_del(&ipmi_device->head);
+ ipmi_remove_space_handler(ipmi_device);
+}
+
+static int __init acpi_ipmi_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return result;
+
+ mutex_init(&driver_data.ipmi_lock);
+
+ result = ipmi_smi_watcher_register(&driver_data.bmc_events);
+
+ return result;
+}
+
+static void __exit acpi_ipmi_exit(void)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+
+ if (acpi_disabled)
+ return;
+
+ ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+
+ /*
+ * When one smi_watcher is unregistered, it is only deleted
+ * from the smi_watcher list. But the smi_gone callback function
+ * is not called. So explicitly uninstall the ACPI IPMI oregion
+ * handler and free it.
+ */
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry_safe(ipmi_device, temp,
+ &driver_data.ipmi_devices, head) {
+ acpi_remove_ipmi_device(ipmi_device);
+ put_device(ipmi_device->smi_data.dev);
+ kfree(ipmi_device);
+ }
+ mutex_unlock(&driver_data.ipmi_lock);
+}
+
+module_init(acpi_ipmi_init);
+module_exit(acpi_ipmi_exit);
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index a7e1d1aa4107..eec2eadd2431 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -14,7 +14,7 @@ acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \
evmisc.o evrgnini.o evxface.o evxfregn.o \
- evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o
+ evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evxfgpe.o
acpi-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index a6f99cc37a19..70e0b28801aa 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -51,8 +51,6 @@ acpi_status acpi_ev_initialize_events(void);
acpi_status acpi_ev_install_xrupt_handlers(void);
-acpi_status acpi_ev_install_fadt_gpes(void);
-
u32 acpi_ev_fixed_event_detect(void);
/*
@@ -82,9 +80,9 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info);
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
u32 gpe_number);
@@ -93,6 +91,8 @@ struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
struct acpi_gpe_block_info
*gpe_block);
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
/*
* evgpeblk - Upper-level GPE block support
*/
@@ -107,12 +107,13 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
acpi_status
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block,
- void *ignored);
+ void *context);
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
u32
-acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info,
+acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
+ struct acpi_gpe_event_info *gpe_event_info,
u32 gpe_number);
/*
@@ -126,10 +127,6 @@ acpi_status
acpi_ev_match_gpe_method(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
-acpi_status
-acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
- u32 level, void *context, void **return_value);
-
/*
* evgpeutil - GPE utilities
*/
@@ -138,6 +135,10 @@ acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context);
u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number);
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index ad88fcae4eb9..0e4dba0d0325 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -146,6 +146,9 @@ u8 acpi_gbl_system_awake_and_running;
extern u32 acpi_gbl_nesting_level;
+ACPI_EXTERN u32 acpi_gpe_count;
+ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
+
/* Support for dynamic control method tracing mechanism */
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
@@ -225,8 +228,10 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_present;
*/
ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock; /* For GPE data structs and registers */
ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
+ACPI_EXTERN spinlock_t _acpi_ev_global_lock_pending_lock; /* For global lock */
#define acpi_gbl_gpe_lock &_acpi_gbl_gpe_lock
#define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock
+#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
/*****************************************************************************
*
@@ -370,7 +375,9 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN u8 acpi_all_gpes_initialized;
+ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
+ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler;
+ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 167470ad2d21..258d628793ea 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -94,7 +94,7 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
struct acpi_gpe_register_info *gpe_register_info);
acpi_status
-acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action);
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action);
acpi_status
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 2ceb0c05b2d7..74000f5b7dab 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -408,17 +408,18 @@ struct acpi_predefined_data {
/* Dispatch info for each GPE -- either a method or handler, cannot be both */
-struct acpi_handler_info {
- acpi_event_handler address; /* Address of handler, if any */
+struct acpi_gpe_handler_info {
+ acpi_gpe_handler address; /* Address of handler, if any */
void *context; /* Context to be passed to handler */
struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */
- u8 orig_flags; /* Original misc info about this GPE */
- u8 orig_enabled; /* Set if the GPE was originally enabled */
+ u8 original_flags; /* Original (pre-handler) GPE info */
+ u8 originally_enabled; /* True if GPE was originally enabled */
};
union acpi_gpe_dispatch_info {
struct acpi_namespace_node *method_node; /* Method node for this GPE level */
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler; /* Installed GPE handler */
+ struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */
};
/*
@@ -458,7 +459,7 @@ struct acpi_gpe_block_info {
u32 register_count; /* Number of register pairs in block */
u16 gpe_count; /* Number of individual GPEs in block */
u8 block_base_number; /* Base GPE number for this block */
- u8 initialized; /* If set, the GPE block has been initialized */
+ u8 initialized; /* TRUE if this block is initialized */
};
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index bdbfaf22bd14..962a3ccff6fd 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -93,7 +93,7 @@
#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */
#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */
-#define AOPOBJ_DATA_VALID 0x04 /* Object is intialized and data is valid */
+#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */
#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */
#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */
#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index c61c3039c31a..e5e313c663a5 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -217,9 +217,17 @@ u32 acpi_ev_fixed_event_detect(void)
status_bit_mask)
&& (fixed_enable & acpi_gbl_fixed_event_info[i].
enable_bit_mask)) {
+ /*
+ * Found an active (signalled) event. Invoke global event
+ * handler if present.
+ */
+ acpi_fixed_event_count[i]++;
+ if (acpi_gbl_global_event_handler) {
+ acpi_gbl_global_event_handler
+ (ACPI_EVENT_TYPE_FIXED, NULL, i,
+ acpi_gbl_global_event_handler_context);
+ }
- /* Found an active (signalled) event */
- acpi_os_fixed_event_count(i);
int_status |= acpi_ev_fixed_event_dispatch(i);
}
}
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index f226eac314db..7c339d34ab42 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -52,6 +52,8 @@ ACPI_MODULE_NAME("evgpe")
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
+static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_update_gpe_enable_mask
@@ -102,7 +104,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
*
* RETURN: Status
*
- * DESCRIPTION: Clear the given GPE from stale events and enable it.
+ * DESCRIPTION: Clear a GPE of stale events and enable it.
*
******************************************************************************/
acpi_status
@@ -113,12 +115,13 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
ACPI_FUNCTION_TRACE(ev_enable_gpe);
/*
- * We will only allow a GPE to be enabled if it has either an
- * associated method (_Lxx/_Exx) or a handler. Otherwise, the
- * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
- * first time it fires.
+ * We will only allow a GPE to be enabled if it has either an associated
+ * method (_Lxx/_Exx) or a handler, or is using the implicit notify
+ * feature. Otherwise, the GPE will be immediately disabled by
+ * acpi_ev_gpe_dispatch the first time it fires.
*/
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE) {
return_ACPI_STATUS(AE_NO_HANDLER);
}
@@ -137,9 +140,9 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
- * FUNCTION: acpi_raw_enable_gpe
+ * FUNCTION: acpi_ev_add_gpe_reference
*
- * PARAMETERS: gpe_event_info - GPE to enable
+ * PARAMETERS: gpe_event_info - Add a reference to this GPE
*
* RETURN: Status
*
@@ -148,16 +151,21 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status = AE_OK;
+ ACPI_FUNCTION_TRACE(ev_add_gpe_reference);
+
if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
return_ACPI_STATUS(AE_LIMIT);
}
gpe_event_info->runtime_count++;
if (gpe_event_info->runtime_count == 1) {
+
+ /* Enable on first reference */
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_ev_enable_gpe(gpe_event_info);
@@ -173,9 +181,9 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
- * FUNCTION: acpi_raw_disable_gpe
+ * FUNCTION: acpi_ev_remove_gpe_reference
*
- * PARAMETERS: gpe_event_info - GPE to disable
+ * PARAMETERS: gpe_event_info - Remove a reference to this GPE
*
* RETURN: Status
*
@@ -184,16 +192,21 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status = AE_OK;
+ ACPI_FUNCTION_TRACE(ev_remove_gpe_reference);
+
if (!gpe_event_info->runtime_count) {
return_ACPI_STATUS(AE_LIMIT);
}
gpe_event_info->runtime_count--;
if (!gpe_event_info->runtime_count) {
+
+ /* Disable on last reference */
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_hw_low_set_gpe(gpe_event_info,
@@ -379,7 +392,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
}
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
- "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
+ "Read GPE Register at GPE%02X: Status=%02X, Enable=%02X\n",
gpe_register_info->base_gpe_number,
status_reg, enable_reg));
@@ -405,7 +418,9 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* or method.
*/
int_status |=
- acpi_ev_gpe_dispatch(&gpe_block->
+ acpi_ev_gpe_dispatch(gpe_block->
+ node,
+ &gpe_block->
event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
}
}
@@ -435,17 +450,25 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* an interrupt handler.
*
******************************************************************************/
-static void acpi_ev_asynch_enable_gpe(void *context);
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
- struct acpi_gpe_event_info *gpe_event_info = (void *)context;
+ struct acpi_gpe_event_info *gpe_event_info = context;
acpi_status status;
- struct acpi_gpe_event_info local_gpe_event_info;
+ struct acpi_gpe_event_info *local_gpe_event_info;
struct acpi_evaluate_info *info;
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
+ /* Allocate a local GPE block */
+
+ local_gpe_event_info =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info));
+ if (!local_gpe_event_info) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE"));
+ return_VOID;
+ }
+
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_VOID;
@@ -462,7 +485,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* Take a snapshot of the GPE info for this level - we copy the info to
* prevent a race condition with remove_handler/remove_block.
*/
- ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
+ ACPI_MEMCPY(local_gpe_event_info, gpe_event_info,
sizeof(struct acpi_gpe_event_info));
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
@@ -470,12 +493,26 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
return_VOID;
}
- /*
- * Must check for control method type dispatch one more time to avoid a
- * race with ev_gpe_install_handler
- */
- if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_METHOD) {
+ /* Do the correct dispatch - normal method or implicit notify */
+
+ switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
+ case ACPI_GPE_DISPATCH_NOTIFY:
+
+ /*
+ * Implicit notify.
+ * Dispatch a DEVICE_WAKE notify to the appropriate handler.
+ * NOTE: the request is queued for execution after this method
+ * completes. The notify handlers are NOT invoked synchronously
+ * from this thread -- because handlers may in turn run other
+ * control methods.
+ */
+ status =
+ acpi_ev_queue_notify_request(local_gpe_event_info->dispatch.
+ device_node,
+ ACPI_NOTIFY_DEVICE_WAKE);
+ break;
+
+ case ACPI_GPE_DISPATCH_METHOD:
/* Allocate the evaluation information block */
@@ -488,7 +525,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* control method that corresponds to this GPE
*/
info->prefix_node =
- local_gpe_event_info.dispatch.method_node;
+ local_gpe_event_info->dispatch.method_node;
info->flags = ACPI_IGNORE_RETURN_VALUE;
status = acpi_ns_evaluate(info);
@@ -499,46 +536,98 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
ACPI_EXCEPTION((AE_INFO, status,
"while evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
- (local_gpe_event_info.dispatch.
+ (local_gpe_event_info->dispatch.
method_node)));
}
+
+ break;
+
+ default:
+ return_VOID; /* Should never happen */
}
+
/* Defer enabling of GPE until all notify handlers are done */
- acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
- gpe_event_info);
+
+ status = acpi_os_execute(OSL_NOTIFY_HANDLER,
+ acpi_ev_asynch_enable_gpe,
+ local_gpe_event_info);
+ if (ACPI_FAILURE(status)) {
+ ACPI_FREE(local_gpe_event_info);
+ }
return_VOID;
}
-static void acpi_ev_asynch_enable_gpe(void *context)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_asynch_enable_gpe
+ *
+ * PARAMETERS: Context (gpe_event_info) - Info for this GPE
+ * Callback from acpi_os_execute
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
+ * complete (i.e., finish execution of Notify)
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
+
+ (void)acpi_ev_finish_gpe(gpe_event_info);
+
+ ACPI_FREE(gpe_event_info);
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_finish_gpe
+ *
+ * PARAMETERS: gpe_event_info - Info for this GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
+ * of a GPE method or a synchronous or asynchronous GPE handler.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
+{
acpi_status status;
+
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) {
/*
- * GPE is level-triggered, we clear the GPE status bit after handling
- * the event.
+ * GPE is level-triggered, we clear the GPE status bit after
+ * handling the event.
*/
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
- return_VOID;
+ return (status);
}
}
/*
- * Enable this GPE, conditionally. This means that the GPE will only be
- * physically enabled if the enable_for_run bit is set in the event_info
+ * Enable this GPE, conditionally. This means that the GPE will
+ * only be physically enabled if the enable_for_run bit is set
+ * in the event_info.
*/
- (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE);
-
- return_VOID;
+ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
+ return (AE_OK);
}
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_gpe_dispatch
*
- * PARAMETERS: gpe_event_info - Info for this GPE
+ * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
+ * gpe_event_info - Info for this GPE
* gpe_number - Number relative to the parent GPE block
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
@@ -551,13 +640,22 @@ static void acpi_ev_asynch_enable_gpe(void *context)
******************************************************************************/
u32
-acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
+ struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
acpi_status status;
+ u32 return_value;
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
- acpi_os_gpe_count(gpe_number);
+ /* Invoke global event handler if present */
+
+ acpi_gpe_count++;
+ if (acpi_gbl_global_event_handler) {
+ acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device,
+ gpe_number,
+ acpi_gbl_global_event_handler_context);
+ }
/*
* If edge-triggered, clear the GPE status bit now. Note that
@@ -568,59 +666,55 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to clear GPE[0x%2X]",
- gpe_number));
+ "Unable to clear GPE%02X", gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
}
/*
- * Dispatch the GPE to either an installed handler, or the control method
- * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
- * it and do not attempt to run the method. If there is neither a handler
- * nor a method, we disable this GPE to prevent further such pointless
- * events from firing.
+ * Always disable the GPE so that it does not keep firing before
+ * any asynchronous activity completes (either from the execution
+ * of a GPE method or an asynchronous GPE handler.)
+ *
+ * If there is no handler or method to run, just disable the
+ * GPE and leave it disabled permanently to prevent further such
+ * pointless events from firing.
+ */
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to disable GPE%02X", gpe_number));
+ return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Dispatch the GPE to either an installed handler or the control
+ * method associated with this GPE (_Lxx or _Exx). If a handler
+ * exists, we invoke it and do not attempt to run the method.
+ * If there is neither a handler nor a method, leave the GPE
+ * disabled.
*/
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_HANDLER:
- /*
- * Invoke the installed handler (at interrupt level)
- * Ignore return status for now.
- * TBD: leave GPE disabled on error?
- */
- (void)gpe_event_info->dispatch.handler->address(gpe_event_info->
- dispatch.
- handler->
- context);
+ /* Invoke the installed handler (at interrupt level) */
- /* It is now safe to clear level-triggered events. */
+ return_value =
+ gpe_event_info->dispatch.handler->address(gpe_device,
+ gpe_number,
+ gpe_event_info->
+ dispatch.handler->
+ context);
- if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
- ACPI_GPE_LEVEL_TRIGGERED) {
- status = acpi_hw_clear_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to clear GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
+ /* If requested, clear (if level-triggered) and reenable the GPE */
+
+ if (return_value & ACPI_REENABLE_GPE) {
+ (void)acpi_ev_finish_gpe(gpe_event_info);
}
break;
case ACPI_GPE_DISPATCH_METHOD:
-
- /*
- * Disable the GPE, so it doesn't keep firing before the method has a
- * chance to run (it runs asynchronously with interrupts enabled).
- */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to disable GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
+ case ACPI_GPE_DISPATCH_NOTIFY:
/*
* Execute the method associated with the GPE
@@ -631,7 +725,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to queue handler for GPE[0x%2X] - event disabled",
+ "Unable to queue handler for GPE%2X - event disabled",
gpe_number));
}
break;
@@ -644,20 +738,9 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
* a GPE to be enabled if it has no handler or method.
*/
ACPI_ERROR((AE_INFO,
- "No handler or method for GPE[0x%2X], disabling event",
+ "No handler or method for GPE%02X, disabling event",
gpe_number));
- /*
- * Disable the GPE. The GPE will remain disabled a handler
- * is installed or ACPICA is restarted.
- */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to disable GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
break;
}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 020add3eee1c..9acb86958c09 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -361,9 +361,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_block->node = gpe_device;
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
+ gpe_block->initialized = FALSE;
gpe_block->register_count = register_count;
gpe_block->block_base_number = gpe_block_base_number;
- gpe_block->initialized = FALSE;
ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
sizeof(struct acpi_generic_address));
@@ -386,7 +386,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
return_ACPI_STATUS(status);
}
- acpi_all_gpes_initialized = FALSE;
+ acpi_gbl_all_gpes_initialized = FALSE;
/* Find all GPE methods (_Lxx or_Exx) for this block */
@@ -423,14 +423,12 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
*
* FUNCTION: acpi_ev_initialize_gpe_block
*
- * PARAMETERS: gpe_device - Handle to the parent GPE block
- * gpe_block - Gpe Block info
+ * PARAMETERS: acpi_gpe_callback
*
* RETURN: Status
*
- * DESCRIPTION: Initialize and enable a GPE block. First find and run any
- * _PRT methods associated with the block, then enable the
- * appropriate GPEs.
+ * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
+ * associated methods.
* Note: Assumes namespace is locked.
*
******************************************************************************/
@@ -450,8 +448,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
/*
- * Ignore a null GPE block (e.g., if no GPE block 1 exists) and
- * GPE blocks that have been initialized already.
+ * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
+ * any GPE blocks that have been initialized already.
*/
if (!gpe_block || gpe_block->initialized) {
return_ACPI_STATUS(AE_OK);
@@ -459,8 +457,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/*
* Enable all GPEs that have a corresponding method and have the
- * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block must
- * be enabled via the acpi_enable_gpe() interface.
+ * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
+ * must be enabled via the acpi_enable_gpe() interface.
*/
gpe_enabled_count = 0;
@@ -472,14 +470,19 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
gpe_event_info = &gpe_block->event_info[gpe_index];
- /* Ignore GPEs that have no corresponding _Lxx/_Exx method */
-
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+ /*
+ * Ignore GPEs that have no corresponding _Lxx/_Exx method
+ * and GPEs that are used to wake the system
+ */
+ if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE)
+ || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
+ == ACPI_GPE_DISPATCH_HANDLER)
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}
- status = acpi_raw_enable_gpe(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 2c7def95f721..c59dc2340593 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -45,11 +45,27 @@
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
-#include "acinterp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evgpeinit")
+/*
+ * Note: History of _PRW support in ACPICA
+ *
+ * Originally (2000 - 2010), the GPE initialization code performed a walk of
+ * the entire namespace to execute the _PRW methods and detect all GPEs
+ * capable of waking the system.
+ *
+ * As of 10/2010, the _PRW method execution has been removed since it is
+ * actually unnecessary. The host OS must in fact execute all _PRW methods
+ * in order to identify the device/power-resource dependencies. We now put
+ * the onus on the host OS to identify the wake GPEs as part of this process
+ * and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This
+ * not only reduces the complexity of the ACPICA initialization code, but in
+ * some cases (on systems with very large namespaces) it should reduce the
+ * kernel boot time as well.
+ */
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_gpe_initialize
@@ -222,7 +238,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
acpi_status status = AE_OK;
/*
- * 2) Find any _Lxx/_Exx GPE methods that have just been loaded.
+ * Find any _Lxx/_Exx GPE methods that have just been loaded.
*
* Any GPEs that correspond to new _Lxx/_Exx methods are immediately
* enabled.
@@ -235,9 +251,9 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
return;
}
+ walk_info.count = 0;
walk_info.owner_id = table_owner_id;
walk_info.execute_by_owner_id = TRUE;
- walk_info.count = 0;
/* Walk the interrupt level descriptor list */
@@ -298,7 +314,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
* xx - is the GPE number [in HEX]
*
* If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
- * with that owner.
+ * with that owner.
*
******************************************************************************/
@@ -408,10 +424,14 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
return_ACPI_STATUS(AE_OK);
}
+ /* Disable the GPE in case it's been enabled already. */
+ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+
/*
* Add the GPE information from above to the gpe_event_info block for
* use during dispatch of this GPE.
*/
+ gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK);
gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
gpe_event_info->dispatch.method_node = method_node;
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 19a0e513ea48..10e477494dcf 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -154,6 +154,45 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_get_gpe_device
+ *
+ * PARAMETERS: GPE_WALK_CALLBACK
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
+ * block device. NULL if the GPE is one of the FADT-defined GPEs.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
+{
+ struct acpi_gpe_device_info *info = context;
+
+ /* Increment Index by the number of GPEs in this block */
+
+ info->next_block_base_index += gpe_block->gpe_count;
+
+ if (info->index < info->next_block_base_index) {
+ /*
+ * The GPE index is within this block, get the node. Leave the node
+ * NULL for the FADT-defined GPEs
+ */
+ if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
+ info->gpe_device = gpe_block->node;
+ }
+
+ info->status = AE_OK;
+ return (AE_CTRL_END);
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_get_gpe_xrupt_block
*
* PARAMETERS: interrupt_number - Interrupt for a GPE block
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index fcaed9fb44ff..38bba66fcce5 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -284,41 +284,39 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
* RETURN: ACPI_INTERRUPT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
- * release interrupt occurs. Attempt to acquire the global lock,
- * if successful, signal the thread waiting for the lock.
+ * release interrupt occurs. If there's a thread waiting for
+ * the global lock, signal it.
*
* NOTE: Assumes that the semaphore can be signaled from interrupt level. If
* this is not possible for some reason, a separate thread will have to be
* scheduled to do this.
*
******************************************************************************/
+static u8 acpi_ev_global_lock_pending;
static u32 acpi_ev_global_lock_handler(void *context)
{
- u8 acquired = FALSE;
+ acpi_status status;
+ acpi_cpu_flags flags;
- /*
- * Attempt to get the lock.
- *
- * If we don't get it now, it will be marked pending and we will
- * take another interrupt when it becomes free.
- */
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
- if (acquired) {
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
- /* Got the lock, now wake all threads waiting for it */
+ if (!acpi_ev_global_lock_pending) {
+ goto out;
+ }
- acpi_gbl_global_lock_acquired = TRUE;
- /* Send a unit to the semaphore */
+ /* Send a unit to the semaphore */
- if (ACPI_FAILURE
- (acpi_os_signal_semaphore
- (acpi_gbl_global_lock_semaphore, 1))) {
- ACPI_ERROR((AE_INFO,
- "Could not signal Global Lock semaphore"));
- }
+ status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
}
+ acpi_ev_global_lock_pending = FALSE;
+
+ out:
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
+
return (ACPI_INTERRUPT_HANDLED);
}
@@ -415,6 +413,7 @@ static int acpi_ev_global_lock_acquired;
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
{
+ acpi_cpu_flags flags;
acpi_status status = AE_OK;
u8 acquired = FALSE;
@@ -467,32 +466,47 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
return_ACPI_STATUS(AE_OK);
}
- /* Attempt to acquire the actual hardware lock */
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
+
+ do {
+
+ /* Attempt to acquire the actual hardware lock */
+
+ ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
+ if (acquired) {
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Acquired hardware Global Lock\n"));
+ break;
+ }
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
- if (acquired) {
+ acpi_ev_global_lock_pending = TRUE;
- /* We got the lock */
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
+ /*
+ * Did not get the lock. The pending bit was set above, and we
+ * must wait until we get the global lock released interrupt.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Acquired hardware Global Lock\n"));
+ "Waiting for hardware Global Lock\n"));
- acpi_gbl_global_lock_acquired = TRUE;
- return_ACPI_STATUS(AE_OK);
- }
+ /*
+ * Wait for handshake with the global lock interrupt handler.
+ * This interface releases the interpreter if we must wait.
+ */
+ status = acpi_ex_system_wait_semaphore(
+ acpi_gbl_global_lock_semaphore,
+ ACPI_WAIT_FOREVER);
- /*
- * Did not get the lock. The pending bit was set above, and we must now
- * wait until we get the global lock released interrupt.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
- /*
- * Wait for handshake with the global lock interrupt handler.
- * This interface releases the interpreter if we must wait.
- */
- status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- ACPI_WAIT_FOREVER);
+ } while (ACPI_SUCCESS(status));
+
+ acpi_ev_global_lock_pending = FALSE;
+
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 36af222cac65..1226689bdb1b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -92,6 +92,57 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
#endif /* ACPI_FUTURE_USAGE */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_global_event_handler
+ *
+ * PARAMETERS: Handler - Pointer to the global event handler function
+ * Context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function. The global handler
+ * is invoked upon each incoming GPE and Fixed Event. It is
+ * invoked at interrupt level at the time of the event dispatch.
+ * Can be used to update event counters, etc.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
+
+ /* Parameter validation */
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow two handlers. */
+
+ if (acpi_gbl_global_event_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ acpi_gbl_global_event_handler = handler;
+ acpi_gbl_global_event_handler_context = context;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
+
/*******************************************************************************
*
* FUNCTION: acpi_install_fixed_event_handler
@@ -671,10 +722,10 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
- u32 type, acpi_event_handler address, void *context)
+ u32 type, acpi_gpe_handler address, void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -693,7 +744,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
/* Allocate memory for the handler object */
- handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
+ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
@@ -722,7 +773,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
handler->address = address;
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
- handler->orig_flags = gpe_event_info->flags &
+ handler->original_flags = gpe_event_info->flags &
(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
/*
@@ -731,10 +782,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
* disabled now to avoid spurious execution of the handler.
*/
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
&& gpe_event_info->runtime_count) {
- handler->orig_enabled = 1;
- (void)acpi_raw_disable_gpe(gpe_event_info);
+ handler->originally_enabled = 1;
+ (void)acpi_ev_remove_gpe_reference(gpe_event_info);
}
/* Install the handler */
@@ -777,10 +828,10 @@ ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
******************************************************************************/
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_handler address)
+ u32 gpe_number, acpi_gpe_handler address)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -835,7 +886,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
gpe_event_info->dispatch.method_node = handler->method_node;
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
- gpe_event_info->flags |= handler->orig_flags;
+ gpe_event_info->flags |= handler->original_flags;
/*
* If the GPE was previously associated with a method and it was
@@ -843,9 +894,9 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
* post-initialization configuration.
*/
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
- && handler->orig_enabled)
- (void)acpi_raw_enable_gpe(gpe_event_info);
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
+ && handler->originally_enabled)
+ (void)acpi_ev_add_gpe_reference(gpe_event_info);
/* Now we can free the handler object */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index a1dabe3fd8ae..90488c1e0f3d 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -43,18 +43,11 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acevents.h"
-#include "acnamesp.h"
#include "actables.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
-/* Local prototypes */
-static acpi_status
-acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block, void *context);
-
/*******************************************************************************
*
* FUNCTION: acpi_enable
@@ -213,185 +206,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
/*******************************************************************************
*
- * FUNCTION: acpi_gpe_wakeup
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- * Action - Enable or Disable
- *
- * RETURN: Status
- *
- * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
- *
- ******************************************************************************/
-acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_gpe_register_info *gpe_register_info;
- acpi_cpu_flags flags;
- u32 register_bit;
-
- ACPI_FUNCTION_TRACE(acpi_gpe_wakeup);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- gpe_register_info = gpe_event_info->register_info;
- if (!gpe_register_info) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
-
- register_bit =
- acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
-
- /* Perform the action */
-
- switch (action) {
- case ACPI_GPE_ENABLE:
- ACPI_SET_BIT(gpe_register_info->enable_for_wake,
- (u8)register_bit);
- break;
-
- case ACPI_GPE_DISABLE:
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
- (u8)register_bit);
- break;
-
- default:
- ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
- status = AE_BAD_PARAMETER;
- break;
- }
-
-unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_enable_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
- * hardware-enabled.
- *
- ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_BAD_PARAMETER;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_enable_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- status = acpi_raw_enable_gpe(gpe_event_info);
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_disable_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Remove a reference to a GPE. When the last reference is
- * removed, only then is the GPE disabled (for runtime GPEs), or
- * the GPE mask bit disabled (for wake GPEs)
- *
- ******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_BAD_PARAMETER;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_disable_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- status = acpi_raw_disable_gpe(gpe_event_info) ;
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_gpe_can_wake
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE
- * has a corresponding method and is currently enabled, disable it
- * (GPEs with corresponding methods are enabled unconditionally
- * during initialization, but GPEs that can wake up are expected
- * to be initially disabled).
- *
- ******************************************************************************/
-acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
- } else {
- status = AE_BAD_PARAMETER;
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake)
-
-/*******************************************************************************
- *
* FUNCTION: acpi_disable_event
*
* PARAMETERS: Event - The fixed eventto be enabled
@@ -483,44 +297,6 @@ ACPI_EXPORT_SYMBOL(acpi_clear_event)
/*******************************************************************************
*
- * FUNCTION: acpi_clear_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear an ACPI event (general purpose)
- *
- ******************************************************************************/
-acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_clear_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- status = acpi_hw_clear_gpe(gpe_event_info);
-
- unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-/*******************************************************************************
- *
* FUNCTION: acpi_get_event_status
*
* PARAMETERS: Event - The fixed event
@@ -575,379 +351,3 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
}
ACPI_EXPORT_SYMBOL(acpi_get_event_status)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_gpe_status
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- * event_status - Where the current status of the event will
- * be returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get status of an event (general purpose)
- *
- ******************************************************************************/
-acpi_status
-acpi_get_gpe_status(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_status *event_status)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /* Obtain status on the requested GPE number */
-
- status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
-
- if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
- *event_status |= ACPI_EVENT_FLAG_HANDLE;
-
- unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
-/*******************************************************************************
- *
- * FUNCTION: acpi_install_gpe_block
- *
- * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
- * gpe_block_address - Address and space_iD
- * register_count - Number of GPE register pairs in the block
- * interrupt_number - H/W interrupt for the block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create and Install a block of GPE registers
- *
- ******************************************************************************/
-acpi_status
-acpi_install_gpe_block(acpi_handle gpe_device,
- struct acpi_generic_address *gpe_block_address,
- u32 register_count, u32 interrupt_number)
-{
- acpi_status status = AE_OK;
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- struct acpi_gpe_block_info *gpe_block;
-
- ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
-
- if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- node = acpi_ns_validate_handle(gpe_device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /*
- * For user-installed GPE Block Devices, the gpe_block_base_number
- * is always zero
- */
- status =
- acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
- interrupt_number, &gpe_block);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
-
- /* Install block in the device_object attached to the node */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
-
- /*
- * No object, create a new one (Device nodes do not always have
- * an attached object)
- */
- obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
- if (!obj_desc) {
- status = AE_NO_MEMORY;
- goto unlock_and_exit;
- }
-
- status =
- acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
-
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
- }
-
- /* Now install the GPE block in the device_object */
-
- obj_desc->device.gpe_block = gpe_block;
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_remove_gpe_block
- *
- * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
- *
- * RETURN: Status
- *
- * DESCRIPTION: Remove a previously installed block of GPE registers
- *
- ******************************************************************************/
-acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
- struct acpi_namespace_node *node;
-
- ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
-
- if (!gpe_device) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- node = acpi_ns_validate_handle(gpe_device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /* Get the device_object attached to the node */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc || !obj_desc->device.gpe_block) {
- return_ACPI_STATUS(AE_NULL_OBJECT);
- }
-
- /* Delete the GPE block (but not the device_object) */
-
- status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);
- if (ACPI_SUCCESS(status)) {
- obj_desc->device.gpe_block = NULL;
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_gpe_device
- *
- * PARAMETERS: Index - System GPE index (0-current_gpe_count)
- * gpe_device - Where the parent GPE Device is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
- * gpe device indicates that the gpe number is contained in one of
- * the FADT-defined gpe blocks. Otherwise, the GPE block device.
- *
- ******************************************************************************/
-acpi_status
-acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
-{
- struct acpi_gpe_device_info info;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
-
- if (!gpe_device) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- if (index >= acpi_current_gpe_count) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- /* Setup and walk the GPE list */
-
- info.index = index;
- info.status = AE_NOT_EXIST;
- info.gpe_device = NULL;
- info.next_block_base_index = 0;
-
- status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- *gpe_device = info.gpe_device;
- return_ACPI_STATUS(info.status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_get_gpe_device
- *
- * PARAMETERS: GPE_WALK_CALLBACK
- *
- * RETURN: Status
- *
- * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
- * block device. NULL if the GPE is one of the FADT-defined GPEs.
- *
- ******************************************************************************/
-static acpi_status
-acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block, void *context)
-{
- struct acpi_gpe_device_info *info = context;
-
- /* Increment Index by the number of GPEs in this block */
-
- info->next_block_base_index += gpe_block->gpe_count;
-
- if (info->index < info->next_block_base_index) {
- /*
- * The GPE index is within this block, get the node. Leave the node
- * NULL for the FADT-defined GPEs
- */
- if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
- info->gpe_device = gpe_block->node;
- }
-
- info->status = AE_OK;
- return (AE_CTRL_END);
- }
-
- return (AE_OK);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_disable_all_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
- *
- ******************************************************************************/
-
-acpi_status acpi_disable_all_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- status = acpi_hw_disable_all_gpes();
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_enable_all_runtime_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
- *
- ******************************************************************************/
-
-acpi_status acpi_enable_all_runtime_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- status = acpi_hw_enable_all_runtime_gpes();
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_update_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and
- * are not pointed to by any device _PRW methods indicating that
- * these GPEs are generally intended for system or device wakeup
- * (such GPEs have to be enabled directly when the devices whose
- * _PRW methods point to them are set up for wakeup signaling).
- *
- ******************************************************************************/
-
-acpi_status acpi_update_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_update_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- } else if (acpi_all_gpes_initialized) {
- goto unlock;
- }
-
- status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
- if (ACPI_SUCCESS(status)) {
- acpi_all_gpes_initialized = TRUE;
- }
-
-unlock:
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
new file mode 100644
index 000000000000..416845bc9c1f
--- /dev/null
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -0,0 +1,669 @@
+/******************************************************************************
+ *
+ * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_EVENTS
+ACPI_MODULE_NAME("evxfgpe")
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_update_all_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete GPE initialization and enable all GPEs that have
+ * associated _Lxx or _Exx methods and are not pointed to by any
+ * device _PRW methods (this indicates that these GPEs are
+ * generally intended for system or device wakeup. Such GPEs
+ * have to be enabled directly when the devices whose _PRW
+ * methods point to them are set up for wakeup signaling.)
+ *
+ * NOTE: Should be called after any GPEs are added to the system. Primarily,
+ * after the system _PRW methods have been run, but also after a GPE Block
+ * Device has been added or if any new GPE methods have been added via a
+ * dynamic table load.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_update_all_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_update_all_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (acpi_gbl_all_gpes_initialized) {
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+ if (ACPI_SUCCESS(status)) {
+ acpi_gbl_all_gpes_initialized = TRUE;
+ }
+
+unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
+ * hardware-enabled.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_enable_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ status = acpi_ev_add_gpe_reference(gpe_event_info);
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_disable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a reference to a GPE. When the last reference is
+ * removed, only then is the GPE disabled (for runtime GPEs), or
+ * the GPE mask bit disabled (for wake GPEs)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_disable_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ status = acpi_ev_remove_gpe_reference(gpe_event_info) ;
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_setup_gpe_for_wake
+ *
+ * PARAMETERS: wake_device - Device associated with the GPE (via _PRW)
+ * gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
+ * interface is intended to be used as the host executes the
+ * _PRW methods (Power Resources for Wake) in the system tables.
+ * Each _PRW appears under a Device Object (The wake_device), and
+ * contains the info for the wake GPE associated with the
+ * wake_device.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_setup_gpe_for_wake(acpi_handle wake_device,
+ acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_namespace_node *device_node;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
+
+ /* Parameter Validation */
+
+ if (!wake_device) {
+ /*
+ * By forcing wake_device to be valid, we automatically enable the
+ * implicit notify feature on all hosts.
+ */
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Validate wake_device is of type Device */
+
+ device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
+ if (device_node->type != ACPI_TYPE_DEVICE) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ /*
+ * If there is no method or handler for this GPE, then the
+ * wake_device will be notified whenever this GPE fires (aka
+ * "implicit notify") Note: The GPE is assumed to be
+ * level-triggered (for windows compatibility).
+ */
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE) {
+ gpe_event_info->flags =
+ (ACPI_GPE_DISPATCH_NOTIFY |
+ ACPI_GPE_LEVEL_TRIGGERED);
+ gpe_event_info->dispatch.device_node = device_node;
+ }
+
+ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+ status = AE_OK;
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_gpe_wake_mask
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ * Action - Enable or Disable
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must
+ * already be marked as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_gpe_register_info *gpe_register_info;
+ acpi_cpu_flags flags;
+ u32 register_bit;
+
+ ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /*
+ * Ensure that we have a valid GPE number and that this GPE is in
+ * fact a wake GPE
+ */
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ register_bit =
+ acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
+ /* Perform the action */
+
+ switch (action) {
+ case ACPI_GPE_ENABLE:
+ ACPI_SET_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
+ break;
+
+ case ACPI_GPE_DISABLE:
+ ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe_wake_mask)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_clear_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_clear_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_hw_clear_gpe(gpe_event_info);
+
+ unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_status
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ * event_status - Where the current status of the event will
+ * be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled)
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_gpe_status(acpi_handle gpe_device,
+ u32 gpe_number, acpi_event_status *event_status)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Obtain status on the requested GPE number */
+
+ status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
+
+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
+ *event_status |= ACPI_EVENT_FLAG_HANDLE;
+
+ unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_disable_all_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_disable_all_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_disable_all_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_disable_all_gpes)
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enable_all_runtime_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enable_all_runtime_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_enable_all_runtime_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ * gpe_block_address - Address and space_iD
+ * register_count - Number of GPE register pairs in the block
+ * interrupt_number - H/W interrupt for the block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not
+ * enabled here.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_gpe_block(acpi_handle gpe_device,
+ struct acpi_generic_address *gpe_block_address,
+ u32 register_count, u32 interrupt_number)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ struct acpi_gpe_block_info *gpe_block;
+
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
+
+ if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ node = acpi_ns_validate_handle(gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * For user-installed GPE Block Devices, the gpe_block_base_number
+ * is always zero
+ */
+ status =
+ acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
+ interrupt_number, &gpe_block);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Install block in the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+
+ /*
+ * No object, create a new one (Device nodes do not always have
+ * an attached object)
+ */
+ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ status =
+ acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference(obj_desc);
+
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Now install the GPE block in the device_object */
+
+ obj_desc->device.gpe_block = gpe_block;
+
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a previously installed block of GPE registers
+ *
+ ******************************************************************************/
+acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+ ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
+
+ if (!gpe_device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ node = acpi_ns_validate_handle(gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Get the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc || !obj_desc->device.gpe_block) {
+ return_ACPI_STATUS(AE_NULL_OBJECT);
+ }
+
+ /* Delete the GPE block (but not the device_object) */
+
+ status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);
+ if (ACPI_SUCCESS(status)) {
+ obj_desc->device.gpe_block = NULL;
+ }
+
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_device
+ *
+ * PARAMETERS: Index - System GPE index (0-current_gpe_count)
+ * gpe_device - Where the parent GPE Device is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
+ * gpe device indicates that the gpe number is contained in one of
+ * the FADT-defined gpe blocks. Otherwise, the GPE block device.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
+{
+ struct acpi_gpe_device_info info;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
+
+ if (!gpe_device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (index >= acpi_current_gpe_count) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Setup and walk the GPE list */
+
+ info.index = index;
+ info.status = AE_NOT_EXIST;
+ info.gpe_device = NULL;
+ info.next_block_base_index = 0;
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ *gpe_device = ACPI_CAST_PTR(acpi_handle, info.gpe_device);
+ return_ACPI_STATUS(info.status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 14750db2a1b8..85c3cbd4304d 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -62,10 +62,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
* PARAMETERS: gpe_event_info - Info block for the GPE
* gpe_register_info - Info block for the GPE register
*
- * RETURN: Status
+ * RETURN: Register mask with a one in the GPE bit position
*
- * DESCRIPTION: Compute GPE enable mask with one bit corresponding to the given
- * GPE set.
+ * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
+ * correct position for the input GPE.
*
******************************************************************************/
@@ -85,12 +85,12 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
*
* RETURN: Status
*
- * DESCRIPTION: Enable or disable a single GPE in its enable register.
+ * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
*
******************************************************************************/
acpi_status
-acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
{
struct acpi_gpe_register_info *gpe_register_info;
acpi_status status;
@@ -113,14 +113,20 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
return (status);
}
- /* Set ot clear just the bit that corresponds to this GPE */
+ /* Set or clear just the bit that corresponds to this GPE */
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
switch (action) {
- case ACPI_GPE_COND_ENABLE:
- if (!(register_bit & gpe_register_info->enable_for_run))
+ case ACPI_GPE_CONDITIONAL_ENABLE:
+
+ /* Only enable if the enable_for_run bit is set */
+
+ if (!(register_bit & gpe_register_info->enable_for_run)) {
return (AE_BAD_PARAMETER);
+ }
+
+ /*lint -fallthrough */
case ACPI_GPE_ENABLE:
ACPI_SET_BIT(enable_mask, register_bit);
@@ -131,7 +137,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
break;
default:
- ACPI_ERROR((AE_INFO, "Invalid action\n"));
+ ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action));
return (AE_BAD_PARAMETER);
}
@@ -168,13 +174,13 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
return (AE_NOT_EXIST);
}
- register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
- gpe_register_info);
-
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
+ register_bit =
+ acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
status = acpi_hw_write(register_bit,
&gpe_register_info->status_address);
@@ -201,8 +207,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
u32 in_byte;
u32 register_bit;
struct acpi_gpe_register_info *gpe_register_info;
- acpi_status status;
acpi_event_status local_event_status = 0;
+ acpi_status status;
ACPI_FUNCTION_ENTRY();
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 660a2728908d..0cac7ec0d2ec 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -577,9 +577,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
* as possible (without an NMI being received in the middle of
* this) - so disable NMIs and initialize the device:
*/
- acpi_nmi_disable();
status = acpi_ns_evaluate(info);
- acpi_nmi_enable();
if (ACPI_SUCCESS(status)) {
walk_info->num_INI++;
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index e87bc6760be6..508537f884ac 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -768,7 +768,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
acpi_current_gpe_count = 0;
- acpi_all_gpes_initialized = FALSE;
+ acpi_gbl_all_gpes_initialized = FALSE;
/* Global handlers */
@@ -778,6 +778,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL;
acpi_gbl_interface_handler = NULL;
+ acpi_gbl_global_event_handler = NULL;
/* Global Lock support */
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index d9efa495b433..199528ff7f1d 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -85,6 +85,7 @@ acpi_status acpi_ut_mutex_initialize(void)
spin_lock_init(acpi_gbl_gpe_lock);
spin_lock_init(acpi_gbl_hardware_lock);
+ spin_lock_init(acpi_ev_global_lock_pending_lock);
/* Mutex for _OSI support */
status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index 18df1e940276..ef0581f2094d 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -109,6 +109,8 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
return sizeof(*estatus) + estatus->data_length;
}
+void apei_estatus_print(const char *pfx,
+ const struct acpi_hest_generic_status *estatus);
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index f4cf2fc4c8c1..31464a006d76 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -46,6 +46,317 @@ u64 cper_next_record_id(void)
}
EXPORT_SYMBOL_GPL(cper_next_record_id);
+static const char *cper_severity_strs[] = {
+ "recoverable",
+ "fatal",
+ "corrected",
+ "info",
+};
+
+static const char *cper_severity_str(unsigned int severity)
+{
+ return severity < ARRAY_SIZE(cper_severity_strs) ?
+ cper_severity_strs[severity] : "unknown";
+}
+
+/*
+ * cper_print_bits - print strings for set bits
+ * @pfx: prefix for each line, including log level and prefix string
+ * @bits: bit mask
+ * @strs: string array, indexed by bit position
+ * @strs_size: size of the string array: @strs
+ *
+ * For each set bit in @bits, print the corresponding string in @strs.
+ * If the output length is longer than 80, multiple line will be
+ * printed, with @pfx is printed at the beginning of each line.
+ */
+static void cper_print_bits(const char *pfx, unsigned int bits,
+ const char *strs[], unsigned int strs_size)
+{
+ int i, len = 0;
+ const char *str;
+ char buf[84];
+
+ for (i = 0; i < strs_size; i++) {
+ if (!(bits & (1U << i)))
+ continue;
+ str = strs[i];
+ if (len && len + strlen(str) + 2 > 80) {
+ printk("%s\n", buf);
+ len = 0;
+ }
+ if (!len)
+ len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
+ else
+ len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
+ }
+ if (len)
+ printk("%s\n", buf);
+}
+
+static const char *cper_proc_type_strs[] = {
+ "IA32/X64",
+ "IA64",
+};
+
+static const char *cper_proc_isa_strs[] = {
+ "IA32",
+ "IA64",
+ "X64",
+};
+
+static const char *cper_proc_error_type_strs[] = {
+ "cache error",
+ "TLB error",
+ "bus error",
+ "micro-architectural error",
+};
+
+static const char *cper_proc_op_strs[] = {
+ "unknown or generic",
+ "data read",
+ "data write",
+ "instruction execution",
+};
+
+static const char *cper_proc_flag_strs[] = {
+ "restartable",
+ "precise IP",
+ "overflow",
+ "corrected",
+};
+
+static void cper_print_proc_generic(const char *pfx,
+ const struct cper_sec_proc_generic *proc)
+{
+ if (proc->validation_bits & CPER_PROC_VALID_TYPE)
+ printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
+ proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ?
+ cper_proc_type_strs[proc->proc_type] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_ISA)
+ printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
+ proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ?
+ cper_proc_isa_strs[proc->proc_isa] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
+ printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
+ cper_print_bits(pfx, proc->proc_error_type,
+ cper_proc_error_type_strs,
+ ARRAY_SIZE(cper_proc_error_type_strs));
+ }
+ if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
+ printk("%s""operation: %d, %s\n", pfx, proc->operation,
+ proc->operation < ARRAY_SIZE(cper_proc_op_strs) ?
+ cper_proc_op_strs[proc->operation] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
+ printk("%s""flags: 0x%02x\n", pfx, proc->flags);
+ cper_print_bits(pfx, proc->flags, cper_proc_flag_strs,
+ ARRAY_SIZE(cper_proc_flag_strs));
+ }
+ if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
+ printk("%s""level: %d\n", pfx, proc->level);
+ if (proc->validation_bits & CPER_PROC_VALID_VERSION)
+ printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
+ if (proc->validation_bits & CPER_PROC_VALID_ID)
+ printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
+ if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
+ printk("%s""target_address: 0x%016llx\n",
+ pfx, proc->target_addr);
+ if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
+ printk("%s""requestor_id: 0x%016llx\n",
+ pfx, proc->requestor_id);
+ if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
+ printk("%s""responder_id: 0x%016llx\n",
+ pfx, proc->responder_id);
+ if (proc->validation_bits & CPER_PROC_VALID_IP)
+ printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
+}
+
+static const char *cper_mem_err_type_strs[] = {
+ "unknown",
+ "no error",
+ "single-bit ECC",
+ "multi-bit ECC",
+ "single-symbol chipkill ECC",
+ "multi-symbol chipkill ECC",
+ "master abort",
+ "target abort",
+ "parity error",
+ "watchdog timeout",
+ "invalid address",
+ "mirror Broken",
+ "memory sparing",
+ "scrub corrected error",
+ "scrub uncorrected error",
+};
+
+static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
+{
+ if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
+ printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
+ if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)
+ printk("%s""physical_address: 0x%016llx\n",
+ pfx, mem->physical_addr);
+ if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK)
+ printk("%s""physical_address_mask: 0x%016llx\n",
+ pfx, mem->physical_addr_mask);
+ if (mem->validation_bits & CPER_MEM_VALID_NODE)
+ printk("%s""node: %d\n", pfx, mem->node);
+ if (mem->validation_bits & CPER_MEM_VALID_CARD)
+ printk("%s""card: %d\n", pfx, mem->card);
+ if (mem->validation_bits & CPER_MEM_VALID_MODULE)
+ printk("%s""module: %d\n", pfx, mem->module);
+ if (mem->validation_bits & CPER_MEM_VALID_BANK)
+ printk("%s""bank: %d\n", pfx, mem->bank);
+ if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
+ printk("%s""device: %d\n", pfx, mem->device);
+ if (mem->validation_bits & CPER_MEM_VALID_ROW)
+ printk("%s""row: %d\n", pfx, mem->row);
+ if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
+ printk("%s""column: %d\n", pfx, mem->column);
+ if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
+ printk("%s""bit_position: %d\n", pfx, mem->bit_pos);
+ if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
+ printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id);
+ if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
+ printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id);
+ if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
+ printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id);
+ if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
+ u8 etype = mem->error_type;
+ printk("%s""error_type: %d, %s\n", pfx, etype,
+ etype < ARRAY_SIZE(cper_mem_err_type_strs) ?
+ cper_mem_err_type_strs[etype] : "unknown");
+ }
+}
+
+static const char *cper_pcie_port_type_strs[] = {
+ "PCIe end point",
+ "legacy PCI end point",
+ "unknown",
+ "unknown",
+ "root port",
+ "upstream switch port",
+ "downstream switch port",
+ "PCIe to PCI/PCI-X bridge",
+ "PCI/PCI-X to PCIe bridge",
+ "root complex integrated endpoint device",
+ "root complex event collector",
+};
+
+static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
+{
+ if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
+ printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
+ pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
+ cper_pcie_port_type_strs[pcie->port_type] : "unknown");
+ if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
+ printk("%s""version: %d.%d\n", pfx,
+ pcie->version.major, pcie->version.minor);
+ if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
+ printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
+ pcie->command, pcie->status);
+ if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
+ const __u8 *p;
+ printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
+ pcie->device_id.segment, pcie->device_id.bus,
+ pcie->device_id.device, pcie->device_id.function);
+ printk("%s""slot: %d\n", pfx,
+ pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
+ printk("%s""secondary_bus: 0x%02x\n", pfx,
+ pcie->device_id.secondary_bus);
+ printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
+ pcie->device_id.vendor_id, pcie->device_id.device_id);
+ p = pcie->device_id.class_code;
+ printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
+ }
+ if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
+ printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
+ pcie->serial_number.lower, pcie->serial_number.upper);
+ if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
+ printk(
+ "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
+ pfx, pcie->bridge.secondary_status, pcie->bridge.control);
+}
+
+static const char *apei_estatus_section_flag_strs[] = {
+ "primary",
+ "containment warning",
+ "reset",
+ "threshold exceeded",
+ "resource not accessible",
+ "latent error",
+};
+
+static void apei_estatus_print_section(
+ const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
+{
+ uuid_le *sec_type = (uuid_le *)gdata->section_type;
+ __u16 severity;
+
+ severity = gdata->error_severity;
+ printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
+ cper_severity_str(severity));
+ printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
+ cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
+ ARRAY_SIZE(apei_estatus_section_flag_strs));
+ if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+ printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
+ if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+ printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
+
+ if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
+ struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
+ printk("%s""section_type: general processor error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*proc_err))
+ cper_print_proc_generic(pfx, proc_err);
+ else
+ goto err_section_too_small;
+ } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
+ struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
+ printk("%s""section_type: memory error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*mem_err))
+ cper_print_mem(pfx, mem_err);
+ else
+ goto err_section_too_small;
+ } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
+ struct cper_sec_pcie *pcie = (void *)(gdata + 1);
+ printk("%s""section_type: PCIe error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*pcie))
+ cper_print_pcie(pfx, pcie);
+ else
+ goto err_section_too_small;
+ } else
+ printk("%s""section type: unknown, %pUl\n", pfx, sec_type);
+
+ return;
+
+err_section_too_small:
+ pr_err(FW_WARN "error section length is too small\n");
+}
+
+void apei_estatus_print(const char *pfx,
+ const struct acpi_hest_generic_status *estatus)
+{
+ struct acpi_hest_generic_data *gdata;
+ unsigned int data_len, gedata_len;
+ int sec_no = 0;
+ __u16 severity;
+
+ printk("%s""APEI generic hardware error status\n", pfx);
+ severity = estatus->error_severity;
+ printk("%s""severity: %d, %s\n", pfx, severity,
+ cper_severity_str(severity));
+ data_len = estatus->data_length;
+ gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+ while (data_len > sizeof(*gdata)) {
+ gedata_len = gdata->error_data_length;
+ apei_estatus_print_section(pfx, gdata, sec_no);
+ data_len -= gedata_len + sizeof(*gdata);
+ sec_no++;
+ }
+}
+EXPORT_SYMBOL_GPL(apei_estatus_print);
+
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
{
if (estatus->data_length &&
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index cf29df69380b..096aebfe7f32 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -39,7 +39,7 @@
#define EINJ_PFX "EINJ: "
#define SPIN_UNIT 100 /* 100ns */
-/* Firmware should respond within 1 miliseconds */
+/* Firmware should respond within 1 milliseconds */
#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
/*
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 1211c03149e8..cf6db6b7662a 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -53,7 +53,7 @@
sizeof(struct acpi_table_erst)))
#define SPIN_UNIT 100 /* 100ns */
-/* Firmware should respond within 1 miliseconds */
+/* Firmware should respond within 1 milliseconds */
#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
#define FIRMWARE_MAX_STALL 50 /* 50us */
@@ -86,7 +86,7 @@ static struct erst_erange {
* It is used to provide exclusive accessing for ERST Error Log
* Address Range too.
*/
-static DEFINE_SPINLOCK(erst_lock);
+static DEFINE_RAW_SPINLOCK(erst_lock);
static inline int erst_errno(int command_status)
{
@@ -421,9 +421,9 @@ ssize_t erst_get_record_count(void)
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
count = __erst_get_record_count();
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return count;
}
@@ -456,9 +456,9 @@ int erst_get_next_record_id(u64 *record_id)
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
rc = __erst_get_next_record_id(record_id);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
@@ -624,17 +624,17 @@ int erst_write(const struct cper_record_header *record)
return -EINVAL;
if (erst_erange.attr & ERST_RANGE_NVRAM) {
- if (!spin_trylock_irqsave(&erst_lock, flags))
+ if (!raw_spin_trylock_irqsave(&erst_lock, flags))
return -EBUSY;
rc = __erst_write_to_nvram(record);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
if (record->record_length > erst_erange.size)
return -EINVAL;
- if (!spin_trylock_irqsave(&erst_lock, flags))
+ if (!raw_spin_trylock_irqsave(&erst_lock, flags))
return -EBUSY;
memcpy(erst_erange.vaddr, record, record->record_length);
rcd_erange = erst_erange.vaddr;
@@ -642,7 +642,7 @@ int erst_write(const struct cper_record_header *record)
memcpy(&rcd_erange->persistence_information, "ER", 2);
rc = __erst_write_to_storage(0);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
@@ -696,9 +696,9 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record,
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
len = __erst_read(record_id, record, buflen);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return len;
}
EXPORT_SYMBOL_GPL(erst_read);
@@ -719,20 +719,20 @@ ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
rc = __erst_get_next_record_id(&record_id);
if (rc) {
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
/* no more record */
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return 0;
}
len = __erst_read(record_id, record, buflen);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return len;
}
@@ -746,12 +746,12 @@ int erst_clear(u64 record_id)
if (erst_disable)
return -ENODEV;
- spin_lock_irqsave(&erst_lock, flags);
+ raw_spin_lock_irqsave(&erst_lock, flags);
if (erst_erange.attr & ERST_RANGE_NVRAM)
rc = __erst_clear_from_nvram(record_id);
else
rc = __erst_clear_from_storage(record_id);
- spin_unlock_irqrestore(&erst_lock, flags);
+ raw_spin_unlock_irqrestore(&erst_lock, flags);
return rc;
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 0d505e59214d..d1d484d4a06a 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -12,10 +12,6 @@
* For more information about Generic Hardware Error Source, please
* refer to ACPI Specification version 4.0, section 17.3.2.6
*
- * Now, only SCI notification type and memory errors are
- * supported. More notification type and hardware error type will be
- * added later.
- *
* Copyright 2010 Intel Corp.
* Author: Huang Ying <ying.huang@intel.com>
*
@@ -39,14 +35,18 @@
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/timer.h>
#include <linux/cper.h>
#include <linux/kdebug.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
#include <acpi/apei.h>
#include <acpi/atomicio.h>
#include <acpi/hed.h>
#include <asm/mce.h>
+#include <asm/tlbflush.h>
#include "apei-internal.h"
@@ -55,42 +55,131 @@
#define GHES_ESTATUS_MAX_SIZE 65536
/*
- * One struct ghes is created for each generic hardware error
- * source.
- *
+ * One struct ghes is created for each generic hardware error source.
* It provides the context for APEI hardware error timer/IRQ/SCI/NMI
- * handler. Handler for one generic hardware error source is only
- * triggered after the previous one is done. So handler can uses
- * struct ghes without locking.
+ * handler.
*
* estatus: memory buffer for error status block, allocated during
* HEST parsing.
*/
#define GHES_TO_CLEAR 0x0001
+#define GHES_EXITING 0x0002
struct ghes {
struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus;
- struct list_head list;
u64 buffer_paddr;
unsigned long flags;
+ union {
+ struct list_head list;
+ struct timer_list timer;
+ unsigned int irq;
+ };
};
+static int ghes_panic_timeout __read_mostly = 30;
+
/*
- * Error source lists, one list for each notification method. The
- * members in lists are struct ghes.
+ * All error sources notified with SCI shares one notifier function,
+ * so they need to be linked and checked one by one. This is applied
+ * to NMI too.
*
- * The list members are only added in HEST parsing and deleted during
- * module_exit, that is, single-threaded. So no lock is needed for
- * that.
- *
- * But the mutual exclusion is needed between members adding/deleting
- * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
- * used for that.
+ * RCU is used for these lists, so ghes_list_mutex is only used for
+ * list changing, not for traversing.
*/
static LIST_HEAD(ghes_sci);
+static LIST_HEAD(ghes_nmi);
static DEFINE_MUTEX(ghes_list_mutex);
+/*
+ * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
+ * mutual exclusion.
+ */
+static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
+
+/*
+ * Because the memory area used to transfer hardware error information
+ * from BIOS to Linux can be determined only in NMI, IRQ or timer
+ * handler, but general ioremap can not be used in atomic context, so
+ * a special version of atomic ioremap is implemented for that.
+ */
+
+/*
+ * Two virtual pages are used, one for NMI context, the other for
+ * IRQ/PROCESS context
+ */
+#define GHES_IOREMAP_PAGES 2
+#define GHES_IOREMAP_NMI_PAGE(base) (base)
+#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
+
+/* virtual memory area for atomic ioremap */
+static struct vm_struct *ghes_ioremap_area;
+/*
+ * These 2 spinlock is used to prevent atomic ioremap virtual memory
+ * area from being mapped simultaneously.
+ */
+static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
+static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
+
+static int ghes_ioremap_init(void)
+{
+ ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
+ VM_IOREMAP, VMALLOC_START, VMALLOC_END);
+ if (!ghes_ioremap_area) {
+ pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void ghes_ioremap_exit(void)
+{
+ free_vm_area(ghes_ioremap_area);
+}
+
+static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
+{
+ unsigned long vaddr;
+
+ vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
+ ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
+ pfn << PAGE_SHIFT, PAGE_KERNEL);
+
+ return (void __iomem *)vaddr;
+}
+
+static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
+{
+ unsigned long vaddr;
+
+ vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
+ ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
+ pfn << PAGE_SHIFT, PAGE_KERNEL);
+
+ return (void __iomem *)vaddr;
+}
+
+static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
+{
+ unsigned long vaddr = (unsigned long __force)vaddr_ptr;
+ void *base = ghes_ioremap_area->addr;
+
+ BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
+ unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
+ __flush_tlb_one(vaddr);
+}
+
+static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
+{
+ unsigned long vaddr = (unsigned long __force)vaddr_ptr;
+ void *base = ghes_ioremap_area->addr;
+
+ BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
+ unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
+ __flush_tlb_one(vaddr);
+}
+
static struct ghes *ghes_new(struct acpi_hest_generic *generic)
{
struct ghes *ghes;
@@ -101,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
if (!ghes)
return ERR_PTR(-ENOMEM);
ghes->generic = generic;
- INIT_LIST_HEAD(&ghes->list);
rc = acpi_pre_map_gar(&generic->error_status_address);
if (rc)
goto err_free;
@@ -158,22 +246,41 @@ static inline int ghes_severity(int severity)
}
}
-/* SCI handler run in work queue, so ioremap can be used here */
-static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
- int from_phys)
+static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
+ int from_phys)
{
- void *vaddr;
-
- vaddr = ioremap_cache(paddr, len);
- if (!vaddr)
- return -ENOMEM;
- if (from_phys)
- memcpy(buffer, vaddr, len);
- else
- memcpy(vaddr, buffer, len);
- iounmap(vaddr);
-
- return 0;
+ void __iomem *vaddr;
+ unsigned long flags = 0;
+ int in_nmi = in_nmi();
+ u64 offset;
+ u32 trunk;
+
+ while (len > 0) {
+ offset = paddr - (paddr & PAGE_MASK);
+ if (in_nmi) {
+ raw_spin_lock(&ghes_ioremap_lock_nmi);
+ vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT);
+ } else {
+ spin_lock_irqsave(&ghes_ioremap_lock_irq, flags);
+ vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT);
+ }
+ trunk = PAGE_SIZE - offset;
+ trunk = min(trunk, len);
+ if (from_phys)
+ memcpy_fromio(buffer, vaddr + offset, trunk);
+ else
+ memcpy_toio(vaddr + offset, buffer, trunk);
+ len -= trunk;
+ paddr += trunk;
+ buffer += trunk;
+ if (in_nmi) {
+ ghes_iounmap_nmi(vaddr);
+ raw_spin_unlock(&ghes_ioremap_lock_nmi);
+ } else {
+ ghes_iounmap_irq(vaddr);
+ spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
+ }
+ }
}
static int ghes_read_estatus(struct ghes *ghes, int silent)
@@ -194,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
if (!buf_paddr)
return -ENOENT;
- rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
- sizeof(*ghes->estatus), 1);
- if (rc)
- return rc;
+ ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
+ sizeof(*ghes->estatus), 1);
if (!ghes->estatus->block_status)
return -ENOENT;
@@ -212,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
goto err_read_block;
if (apei_estatus_check_header(ghes->estatus))
goto err_read_block;
- rc = ghes_copy_tofrom_phys(ghes->estatus + 1,
- buf_paddr + sizeof(*ghes->estatus),
- len - sizeof(*ghes->estatus), 1);
- if (rc)
- return rc;
+ ghes_copy_tofrom_phys(ghes->estatus + 1,
+ buf_paddr + sizeof(*ghes->estatus),
+ len - sizeof(*ghes->estatus), 1);
if (apei_estatus_check(ghes->estatus))
goto err_read_block;
rc = 0;
err_read_block:
- if (rc && !silent)
+ if (rc && !silent && printk_ratelimit())
pr_warning(FW_WARN GHES_PFX
"Failed to read error status block!\n");
return rc;
@@ -255,11 +358,26 @@ static void ghes_do_proc(struct ghes *ghes)
}
#endif
}
+}
- if (!processed && printk_ratelimit())
- pr_warning(GHES_PFX
- "Unknown error record from generic hardware error source: %d\n",
- ghes->generic->header.source_id);
+static void ghes_print_estatus(const char *pfx, struct ghes *ghes)
+{
+ /* Not more than 2 messages every 5 seconds */
+ static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2);
+
+ if (pfx == NULL) {
+ if (ghes_severity(ghes->estatus->error_severity) <=
+ GHES_SEV_CORRECTED)
+ pfx = KERN_WARNING HW_ERR;
+ else
+ pfx = KERN_ERR HW_ERR;
+ }
+ if (__ratelimit(&ratelimit)) {
+ printk(
+ "%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
+ pfx, ghes->generic->header.source_id);
+ apei_estatus_print(pfx, ghes->estatus);
+ }
}
static int ghes_proc(struct ghes *ghes)
@@ -269,6 +387,7 @@ static int ghes_proc(struct ghes *ghes)
rc = ghes_read_estatus(ghes, 0);
if (rc)
goto out;
+ ghes_print_estatus(NULL, ghes);
ghes_do_proc(ghes);
out:
@@ -276,6 +395,42 @@ out:
return 0;
}
+static void ghes_add_timer(struct ghes *ghes)
+{
+ struct acpi_hest_generic *g = ghes->generic;
+ unsigned long expire;
+
+ if (!g->notify.poll_interval) {
+ pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
+ g->header.source_id);
+ return;
+ }
+ expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
+ ghes->timer.expires = round_jiffies_relative(expire);
+ add_timer(&ghes->timer);
+}
+
+static void ghes_poll_func(unsigned long data)
+{
+ struct ghes *ghes = (void *)data;
+
+ ghes_proc(ghes);
+ if (!(ghes->flags & GHES_EXITING))
+ ghes_add_timer(ghes);
+}
+
+static irqreturn_t ghes_irq_func(int irq, void *data)
+{
+ struct ghes *ghes = data;
+ int rc;
+
+ rc = ghes_proc(ghes);
+ if (rc)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
static int ghes_notify_sci(struct notifier_block *this,
unsigned long event, void *data)
{
@@ -292,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this,
return ret;
}
+static int ghes_notify_nmi(struct notifier_block *this,
+ unsigned long cmd, void *data)
+{
+ struct ghes *ghes, *ghes_global = NULL;
+ int sev, sev_global = -1;
+ int ret = NOTIFY_DONE;
+
+ if (cmd != DIE_NMI)
+ return ret;
+
+ raw_spin_lock(&ghes_nmi_lock);
+ list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
+ if (ghes_read_estatus(ghes, 1)) {
+ ghes_clear_estatus(ghes);
+ continue;
+ }
+ sev = ghes_severity(ghes->estatus->error_severity);
+ if (sev > sev_global) {
+ sev_global = sev;
+ ghes_global = ghes;
+ }
+ ret = NOTIFY_STOP;
+ }
+
+ if (ret == NOTIFY_DONE)
+ goto out;
+
+ if (sev_global >= GHES_SEV_PANIC) {
+ oops_begin();
+ ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
+ /* reboot to log the error! */
+ if (panic_timeout == 0)
+ panic_timeout = ghes_panic_timeout;
+ panic("Fatal hardware error!");
+ }
+
+ list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
+ if (!(ghes->flags & GHES_TO_CLEAR))
+ continue;
+ /* Do not print estatus because printk is not NMI safe */
+ ghes_do_proc(ghes);
+ ghes_clear_estatus(ghes);
+ }
+
+out:
+ raw_spin_unlock(&ghes_nmi_lock);
+ return ret;
+}
+
static struct notifier_block ghes_notifier_sci = {
.notifier_call = ghes_notify_sci,
};
+static struct notifier_block ghes_notifier_nmi = {
+ .notifier_call = ghes_notify_nmi,
+};
+
static int __devinit ghes_probe(struct platform_device *ghes_dev)
{
struct acpi_hest_generic *generic;
@@ -306,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
if (!generic->enabled)
return -ENODEV;
- if (generic->error_block_length <
- sizeof(struct acpi_hest_generic_status)) {
- pr_warning(FW_BUG GHES_PFX
-"Invalid error block length: %u for generic hardware error source: %d\n",
- generic->error_block_length,
+ switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ case ACPI_HEST_NOTIFY_SCI:
+ case ACPI_HEST_NOTIFY_NMI:
+ break;
+ case ACPI_HEST_NOTIFY_LOCAL:
+ pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
generic->header.source_id);
goto err;
+ default:
+ pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
+ generic->notify.type, generic->header.source_id);
+ goto err;
}
- if (generic->records_to_preallocate == 0) {
- pr_warning(FW_BUG GHES_PFX
-"Invalid records to preallocate: %u for generic hardware error source: %d\n",
- generic->records_to_preallocate,
+
+ rc = -EIO;
+ if (generic->error_block_length <
+ sizeof(struct acpi_hest_generic_status)) {
+ pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
+ generic->error_block_length,
generic->header.source_id);
goto err;
}
@@ -327,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
ghes = NULL;
goto err;
}
- if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) {
+ switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ ghes->timer.function = ghes_poll_func;
+ ghes->timer.data = (unsigned long)ghes;
+ init_timer_deferrable(&ghes->timer);
+ ghes_add_timer(ghes);
+ break;
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ /* External interrupt vector is GSI */
+ if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
+ pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
+ generic->header.source_id);
+ goto err;
+ }
+ if (request_irq(ghes->irq, ghes_irq_func,
+ 0, "GHES IRQ", ghes)) {
+ pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
+ generic->header.source_id);
+ goto err;
+ }
+ break;
+ case ACPI_HEST_NOTIFY_SCI:
mutex_lock(&ghes_list_mutex);
if (list_empty(&ghes_sci))
register_acpi_hed_notifier(&ghes_notifier_sci);
list_add_rcu(&ghes->list, &ghes_sci);
mutex_unlock(&ghes_list_mutex);
- } else {
- unsigned char *notify = NULL;
-
- switch (generic->notify.type) {
- case ACPI_HEST_NOTIFY_POLLED:
- notify = "POLL";
- break;
- case ACPI_HEST_NOTIFY_EXTERNAL:
- case ACPI_HEST_NOTIFY_LOCAL:
- notify = "IRQ";
- break;
- case ACPI_HEST_NOTIFY_NMI:
- notify = "NMI";
- break;
- }
- if (notify) {
- pr_warning(GHES_PFX
-"Generic hardware error source: %d notified via %s is not supported!\n",
- generic->header.source_id, notify);
- } else {
- pr_warning(FW_WARN GHES_PFX
-"Unknown notification type: %u for generic hardware error source: %d\n",
- generic->notify.type, generic->header.source_id);
- }
- rc = -ENODEV;
- goto err;
+ break;
+ case ACPI_HEST_NOTIFY_NMI:
+ mutex_lock(&ghes_list_mutex);
+ if (list_empty(&ghes_nmi))
+ register_die_notifier(&ghes_notifier_nmi);
+ list_add_rcu(&ghes->list, &ghes_nmi);
+ mutex_unlock(&ghes_list_mutex);
+ break;
+ default:
+ BUG();
}
platform_set_drvdata(ghes_dev, ghes);
@@ -379,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
ghes = platform_get_drvdata(ghes_dev);
generic = ghes->generic;
+ ghes->flags |= GHES_EXITING;
switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ del_timer_sync(&ghes->timer);
+ break;
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ free_irq(ghes->irq, ghes);
+ break;
case ACPI_HEST_NOTIFY_SCI:
mutex_lock(&ghes_list_mutex);
list_del_rcu(&ghes->list);
@@ -387,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
unregister_acpi_hed_notifier(&ghes_notifier_sci);
mutex_unlock(&ghes_list_mutex);
break;
+ case ACPI_HEST_NOTIFY_NMI:
+ mutex_lock(&ghes_list_mutex);
+ list_del_rcu(&ghes->list);
+ if (list_empty(&ghes_nmi))
+ unregister_die_notifier(&ghes_notifier_nmi);
+ mutex_unlock(&ghes_list_mutex);
+ /*
+ * To synchronize with NMI handler, ghes can only be
+ * freed after NMI handler finishes.
+ */
+ synchronize_rcu();
+ break;
default:
BUG();
break;
}
- synchronize_rcu();
ghes_fini(ghes);
kfree(ghes);
@@ -412,6 +652,8 @@ static struct platform_driver ghes_platform_driver = {
static int __init ghes_init(void)
{
+ int rc;
+
if (acpi_disabled)
return -ENODEV;
@@ -420,12 +662,25 @@ static int __init ghes_init(void)
return -EINVAL;
}
- return platform_driver_register(&ghes_platform_driver);
+ rc = ghes_ioremap_init();
+ if (rc)
+ goto err;
+
+ rc = platform_driver_register(&ghes_platform_driver);
+ if (rc)
+ goto err_ioremap_exit;
+
+ return 0;
+err_ioremap_exit:
+ ghes_ioremap_exit();
+err:
+ return rc;
}
static void __exit ghes_exit(void)
{
platform_driver_unregister(&ghes_platform_driver);
+ ghes_ioremap_exit();
}
module_init(ghes_init);
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 1a3508a7fe03..abda3786a5d7 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -46,9 +46,9 @@ EXPORT_SYMBOL_GPL(hest_disable);
/* HEST table parsing */
-static struct acpi_table_hest *hest_tab;
+static struct acpi_table_hest *__read_mostly hest_tab;
-static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
+static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
[ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
[ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
[ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
@@ -126,7 +126,7 @@ struct ghes_arr {
unsigned int count;
};
-static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
{
int *count = data;
@@ -135,7 +135,7 @@ static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
return 0;
}
-static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
{
struct platform_device *ghes_dev;
struct ghes_arr *ghes_arr = data;
@@ -165,7 +165,7 @@ err:
return rc;
}
-static int hest_ghes_dev_register(unsigned int ghes_count)
+static int __init hest_ghes_dev_register(unsigned int ghes_count)
{
int rc, i;
struct ghes_arr ghes_arr;
@@ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str)
__setup("hest_disable", setup_hest_disable);
-static int __init hest_init(void)
+void __init acpi_hest_init(void)
{
acpi_status status;
int rc = -ENODEV;
unsigned int ghes_count = 0;
- if (acpi_disabled)
- goto err;
-
if (hest_disable) {
- pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
- goto err;
+ pr_info(HEST_PFX "Table parsing disabled.\n");
+ return;
}
+ if (acpi_disabled)
+ goto err;
+
status = acpi_get_table(ACPI_SIG_HEST, 0,
(struct acpi_table_header **)&hest_tab);
if (status == AE_NOT_FOUND) {
- pr_info(HEST_PFX "Table is not found!\n");
+ pr_info(HEST_PFX "Table not found.\n");
goto err;
} else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
@@ -226,15 +226,11 @@ static int __init hest_init(void)
goto err;
rc = hest_ghes_dev_register(ghes_count);
- if (rc)
- goto err;
-
- pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+ if (!rc) {
+ pr_info(HEST_PFX "Table parsing has been initialized.\n");
+ return;
+ }
- return 0;
err:
hest_disable = 1;
- return rc;
}
-
-subsys_initcall(hest_init);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 95649d373071..68bc227e7c4c 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -631,6 +631,17 @@ static int acpi_battery_update(struct acpi_battery *battery)
return result;
}
+static void acpi_battery_refresh(struct acpi_battery *battery)
+{
+ if (!battery->bat.dev)
+ return;
+
+ acpi_battery_get_info(battery);
+ /* The battery may have changed its reporting units. */
+ sysfs_remove_battery(battery);
+ sysfs_add_battery(battery);
+}
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -868,6 +879,8 @@ static int acpi_battery_add_fs(struct acpi_device *device)
struct proc_dir_entry *entry = NULL;
int i;
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_battery_dir);
@@ -914,6 +927,8 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
if (!battery)
return;
old = battery->bat.dev;
+ if (event == ACPI_BATTERY_NOTIFY_INFO)
+ acpi_battery_refresh(battery);
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
@@ -983,6 +998,7 @@ static int acpi_battery_resume(struct acpi_device *device)
if (!device)
return -EINVAL;
battery = acpi_driver_data(device);
+ acpi_battery_refresh(battery);
battery->update_time = 0;
acpi_battery_update(battery);
return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d68bd61072bb..7ced61f39492 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
-static int set_power_nocheck(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "disable power check in power transition\n", id->ident);
- acpi_power_nocheck = 1;
- return 0;
-}
-static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
- {
- set_power_nocheck, "HP Pavilion 05", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
- {},
-};
-
#ifdef CONFIG_X86
static int set_copy_dsdt(const struct dmi_system_id *id)
@@ -196,33 +180,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
Power Management
-------------------------------------------------------------------------- */
-int acpi_bus_get_power(acpi_handle handle, int *state)
+static int __acpi_bus_get_power(struct acpi_device *device, int *state)
{
int result = 0;
acpi_status status = 0;
- struct acpi_device *device = NULL;
unsigned long long psc = 0;
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
+ if (!device || !state)
+ return -EINVAL;
*state = ACPI_STATE_UNKNOWN;
- if (!device->flags.power_manageable) {
- /* TBD: Non-recursive algorithm for walking up hierarchy */
- if (device->parent)
- *state = device->parent->power.state;
- else
- *state = ACPI_STATE_D0;
- } else {
+ if (device->flags.power_manageable) {
/*
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if (device->power.flags.power_resources) {
- result = acpi_power_get_inferred_state(device);
+ result = acpi_power_get_inferred_state(device, state);
if (result)
return result;
} else if (device->power.flags.explicit_get) {
@@ -230,59 +205,33 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
- device->power.state = (int)psc;
+ *state = (int)psc;
}
-
- *state = device->power.state;
+ } else {
+ /* TBD: Non-recursive algorithm for walking up hierarchy. */
+ *state = device->parent ?
+ device->parent->power.state : ACPI_STATE_D0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
- device->pnp.bus_id, device->power.state));
+ device->pnp.bus_id, *state));
return 0;
}
-EXPORT_SYMBOL(acpi_bus_get_power);
-int acpi_bus_set_power(acpi_handle handle, int state)
+static int __acpi_bus_set_power(struct acpi_device *device, int state)
{
int result = 0;
acpi_status status = AE_OK;
- struct acpi_device *device = NULL;
char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
-
- if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+ if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return -EINVAL;
/* Make sure this is a valid target state */
- if (!device->flags.power_manageable) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- kobject_name(&device->dev.kobj)));
- return -ENODEV;
- }
- /*
- * Get device's current power state
- */
- if (!acpi_power_nocheck) {
- /*
- * Maybe the incorrect power state is returned on the bogus
- * bios, which is different with the real power state.
- * For example: the bios returns D0 state and the real power
- * state is D3. OS expects to set the device to D0 state. In
- * such case if OS uses the power state returned by the BIOS,
- * the device can't be transisted to the correct power state.
- * So if the acpi_power_nocheck is set, it is unnecessary to
- * get the power state by calling acpi_bus_get_power.
- */
- acpi_bus_get_power(device->handle, &device->power.state);
- }
- if ((state == device->power.state) && !device->flags.force_power_state) {
+ if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
return 0;
@@ -351,8 +300,75 @@ int acpi_bus_set_power(acpi_handle handle, int state)
return result;
}
+
+int acpi_bus_set_power(acpi_handle handle, int state)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ if (!device->flags.power_manageable) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device [%s] is not power manageable\n",
+ dev_name(&device->dev)));
+ return -ENODEV;
+ }
+
+ return __acpi_bus_set_power(device, state);
+}
EXPORT_SYMBOL(acpi_bus_set_power);
+
+int acpi_bus_init_power(struct acpi_device *device)
+{
+ int state;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ result = __acpi_bus_get_power(device, &state);
+ if (result)
+ return result;
+
+ if (device->power.flags.power_resources)
+ result = acpi_power_on_resources(device, state);
+
+ if (!result)
+ device->power.state = state;
+
+ return result;
+}
+
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+ struct acpi_device *device;
+ int state;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ result = __acpi_bus_get_power(device, &state);
+ if (result)
+ return result;
+
+ result = __acpi_bus_set_power(device, state);
+ if (!result && state_p)
+ *state_p = state;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_update_power);
+
+
bool acpi_bus_power_manageable(acpi_handle handle)
{
struct acpi_device *device;
@@ -1023,15 +1039,8 @@ static int __init acpi_init(void)
if (acpi_disabled)
return result;
- /*
- * If the laptop falls into the DMI check table, the power state check
- * will be disabled in the course of device power transition.
- */
- dmi_check_system(power_nocheck_dmi_table);
-
acpi_scan_init();
acpi_ec_init();
- acpi_power_init();
acpi_debugfs_init();
acpi_sleep_proc_init();
acpi_wakeup_device_init();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 71ef9cd0735f..76bbb78a5ad9 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -279,6 +279,9 @@ static int acpi_lid_send_state(struct acpi_device *device)
input_report_switch(button->input, SW_LID, !state);
input_sync(button->input);
+ if (state)
+ pm_wakeup_event(&device->dev, 0);
+
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
if (ret == NOTIFY_DONE)
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
@@ -314,6 +317,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
input_sync(input);
input_report_key(input, keycode, 0);
input_sync(input);
+
+ pm_wakeup_event(&device->dev, 0);
}
acpi_bus_generate_proc_event(device, event, ++button->pushed);
@@ -426,7 +431,7 @@ static int acpi_button_add(struct acpi_device *device)
acpi_enable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
device->wakeup.run_wake_count++;
- device->wakeup.state.enabled = 1;
+ device_set_wakeup_enable(&device->dev, true);
}
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
@@ -449,7 +454,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
acpi_disable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
device->wakeup.run_wake_count--;
- device->wakeup.state.enabled = 0;
+ device_set_wakeup_enable(&device->dev, false);
}
acpi_button_remove_fs(device);
diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c
index 6355b575ee5a..5df67f1d6c61 100644
--- a/drivers/acpi/debugfs.c
+++ b/drivers/acpi/debugfs.c
@@ -80,7 +80,7 @@ int __init acpi_debugfs_init(void)
if (!acpi_dir)
goto err;
- cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
+ cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
acpi_dir, NULL, &cm_fops);
if (!cm_dentry)
goto err;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 81514a4918cc..1864ad3cf895 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -725,7 +725,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
dock_lock(ds, 1);
- acpi_update_gpes();
+ acpi_update_all_gpes();
break;
}
if (dock_present(ds) || dock_in_progress(ds))
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 372ff80b7b0c..fa848c4116a8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -606,7 +606,8 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
return 0;
}
-static u32 acpi_ec_gpe_handler(void *data)
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number, void *data)
{
struct acpi_ec *ec = data;
@@ -618,7 +619,7 @@ static u32 acpi_ec_gpe_handler(void *data)
wake_up(&ec->wait);
ec_check_sci(ec, acpi_ec_read_status(ec));
}
- return ACPI_INTERRUPT_HANDLED;
+ return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
}
/* --------------------------------------------------------------------------
@@ -934,6 +935,9 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
ec_flag_msi, "MSI hardware", {
DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
{
+ ec_flag_msi, "MSI hardware", {
+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
+ {
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
{},
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 60049080c869..467479f07c1f 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -86,7 +86,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &acpi_state);
+ result = acpi_bus_update_power(device->handle, &acpi_state);
if (result)
return result;
@@ -123,7 +123,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = {
static int acpi_fan_add(struct acpi_device *device)
{
int result = 0;
- int state = 0;
struct thermal_cooling_device *cdev;
if (!device)
@@ -132,16 +131,12 @@ static int acpi_fan_add(struct acpi_device *device)
strcpy(acpi_device_name(device), "Fan");
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
- result = acpi_bus_get_power(device->handle, &state);
+ result = acpi_bus_update_power(device->handle, NULL);
if (result) {
- printk(KERN_ERR PREFIX "Reading power state\n");
+ printk(KERN_ERR PREFIX "Setting initial power state\n");
goto end;
}
- device->flags.force_power_state = 1;
- acpi_bus_set_power(device->handle, state);
- device->flags.force_power_state = 0;
-
cdev = thermal_cooling_device_register("Fan", device,
&fan_cooling_ops);
if (IS_ERR(cdev)) {
@@ -200,22 +195,14 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
static int acpi_fan_resume(struct acpi_device *device)
{
- int result = 0;
- int power_state = 0;
+ int result;
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &power_state);
- if (result) {
- printk(KERN_ERR PREFIX
- "Error reading fan power state\n");
- return result;
- }
-
- device->flags.force_power_state = 1;
- acpi_bus_set_power(device->handle, power_state);
- device->flags.force_power_state = 0;
+ result = acpi_bus_update_power(device->handle, NULL);
+ if (result)
+ printk(KERN_ERR PREFIX "Error updating fan power state\n");
return result;
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 78b0164c35b2..7c47ed55e528 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -167,11 +167,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
"firmware_node");
ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
"physical_node");
- if (acpi_dev->wakeup.flags.valid) {
+ if (acpi_dev->wakeup.flags.valid)
device_set_wakeup_capable(dev, true);
- device_set_wakeup_enable(dev,
- acpi_dev->wakeup.state.enabled);
- }
}
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index a212bfeddf8c..b1cc81a0431b 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,9 +41,10 @@ static inline int acpi_debugfs_init(void) { return 0; }
int acpi_power_init(void);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
-int acpi_power_get_inferred_state(struct acpi_device *device);
+int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
+int acpi_power_on_resources(struct acpi_device *device, int state);
int acpi_power_transition(struct acpi_device *device, int state);
-extern int acpi_power_nocheck;
+int acpi_bus_init_power(struct acpi_device *device);
int acpi_wakeup_device_init(void);
void acpi_early_processor_set_pdc(void);
@@ -82,8 +83,16 @@ extern int acpi_sleep_init(void);
#ifdef CONFIG_ACPI_SLEEP
int acpi_sleep_proc_init(void);
+int suspend_nvs_alloc(void);
+void suspend_nvs_free(void);
+int suspend_nvs_save(void);
+void suspend_nvs_restore(void);
#else
static inline int acpi_sleep_proc_init(void) { return 0; }
+static inline int suspend_nvs_alloc(void) { return 0; }
+static inline void suspend_nvs_free(void) {}
+static inline int suspend_nvs_save(void) { return 0; }
+static inline void suspend_nvs_restore(void) {}
#endif
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 5718566e00f9..5eb25eb3ea48 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -276,12 +276,18 @@ int __init acpi_numa_init(void)
{
int ret = 0;
+ /*
+ * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
+ * SRAT cpu entries could have different order with that in MADT.
+ * So go over all cpu entries in SRAT to get apicid to node mapping.
+ */
+
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
- acpi_parse_x2apic_affinity, nr_cpu_ids);
+ acpi_parse_x2apic_affinity, 0);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity, nr_cpu_ids);
+ acpi_parse_processor_affinity, 0);
ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
acpi_parse_memory_affinity,
NR_NODE_MEMBLKS);
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
new file mode 100644
index 000000000000..54b6ab8040a6
--- /dev/null
+++ b/drivers/acpi/nvs.c
@@ -0,0 +1,144 @@
+/*
+ * nvs.c - Routines for saving and restoring ACPI NVS memory region
+ *
+ * Copyright (C) 2008-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <acpi/acpiosxf.h>
+
+/*
+ * Platforms, like ACPI, may want us to save some memory used by them during
+ * suspend and to restore the contents of this memory during the subsequent
+ * resume. The code below implements a mechanism allowing us to do that.
+ */
+
+struct nvs_page {
+ unsigned long phys_start;
+ unsigned int size;
+ void *kaddr;
+ void *data;
+ struct list_head node;
+};
+
+static LIST_HEAD(nvs_list);
+
+/**
+ * suspend_nvs_register - register platform NVS memory region to save
+ * @start - physical address of the region
+ * @size - size of the region
+ *
+ * The NVS region need not be page-aligned (both ends) and we arrange
+ * things so that the data from page-aligned addresses in this region will
+ * be copied into separate RAM pages.
+ */
+int suspend_nvs_register(unsigned long start, unsigned long size)
+{
+ struct nvs_page *entry, *next;
+
+ while (size > 0) {
+ unsigned int nr_bytes;
+
+ entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
+ if (!entry)
+ goto Error;
+
+ list_add_tail(&entry->node, &nvs_list);
+ entry->phys_start = start;
+ nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
+ entry->size = (size < nr_bytes) ? size : nr_bytes;
+
+ start += entry->size;
+ size -= entry->size;
+ }
+ return 0;
+
+ Error:
+ list_for_each_entry_safe(entry, next, &nvs_list, node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ return -ENOMEM;
+}
+
+/**
+ * suspend_nvs_free - free data pages allocated for saving NVS regions
+ */
+void suspend_nvs_free(void)
+{
+ struct nvs_page *entry;
+
+ list_for_each_entry(entry, &nvs_list, node)
+ if (entry->data) {
+ free_page((unsigned long)entry->data);
+ entry->data = NULL;
+ if (entry->kaddr) {
+ acpi_os_unmap_memory(entry->kaddr, entry->size);
+ entry->kaddr = NULL;
+ }
+ }
+}
+
+/**
+ * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
+ */
+int suspend_nvs_alloc(void)
+{
+ struct nvs_page *entry;
+
+ list_for_each_entry(entry, &nvs_list, node) {
+ entry->data = (void *)__get_free_page(GFP_KERNEL);
+ if (!entry->data) {
+ suspend_nvs_free();
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * suspend_nvs_save - save NVS memory regions
+ */
+int suspend_nvs_save(void)
+{
+ struct nvs_page *entry;
+
+ printk(KERN_INFO "PM: Saving platform NVS memory\n");
+
+ list_for_each_entry(entry, &nvs_list, node)
+ if (entry->data) {
+ entry->kaddr = acpi_os_map_memory(entry->phys_start,
+ entry->size);
+ if (!entry->kaddr) {
+ suspend_nvs_free();
+ return -ENOMEM;
+ }
+ memcpy(entry->data, entry->kaddr, entry->size);
+ }
+
+ return 0;
+}
+
+/**
+ * suspend_nvs_restore - restore NVS memory regions
+ *
+ * This function is going to be called with interrupts disabled, so it
+ * cannot iounmap the virtual addresses used to access the NVS region.
+ */
+void suspend_nvs_restore(void)
+{
+ struct nvs_page *entry;
+
+ printk(KERN_INFO "PM: Restoring platform NVS memory\n");
+
+ list_for_each_entry(entry, &nvs_list, node)
+ if (entry->data)
+ memcpy(entry->kaddr, entry->data, entry->size);
+}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 966feddf6b1b..e2dd6de5d50c 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -110,9 +110,6 @@ struct acpi_ioremap {
static LIST_HEAD(acpi_ioremaps);
static DEFINE_SPINLOCK(acpi_ioremap_lock);
-#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
-static char osi_setup_string[OSI_STRING_LENGTH_MAX];
-
static void __init acpi_osi_setup_late(void);
/*
@@ -152,8 +149,7 @@ static struct osi_linux {
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
- unsigned int known:1;
-} osi_linux = { 0, 0, 0, 0};
+} osi_linux = {0, 0, 0};
static u32 acpi_osi_handler(acpi_string interface, u32 supported)
{
@@ -324,7 +320,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
pg_off = round_down(phys, PAGE_SIZE);
pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
- virt = ioremap(pg_off, pg_sz);
+ virt = ioremap_cache(pg_off, pg_sz);
if (!virt) {
kfree(map);
return NULL;
@@ -646,7 +642,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
rcu_read_unlock();
if (!virt_addr) {
- virt_addr = ioremap(phys_addr, size);
+ virt_addr = ioremap_cache(phys_addr, size);
unmap = 1;
}
if (!value)
@@ -682,7 +678,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
rcu_read_unlock();
if (!virt_addr) {
- virt_addr = ioremap(phys_addr, size);
+ virt_addr = ioremap_cache(phys_addr, size);
unmap = 1;
}
@@ -1055,13 +1051,53 @@ static int __init acpi_os_name_setup(char *str)
__setup("acpi_os_name=", acpi_os_name_setup);
+#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
+#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */
+
+struct osi_setup_entry {
+ char string[OSI_STRING_LENGTH_MAX];
+ bool enable;
+};
+
+static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX];
+
+void __init acpi_osi_setup(char *str)
+{
+ struct osi_setup_entry *osi;
+ bool enable = true;
+ int i;
+
+ if (!acpi_gbl_create_osi_method)
+ return;
+
+ if (str == NULL || *str == '\0') {
+ printk(KERN_INFO PREFIX "_OSI method disabled\n");
+ acpi_gbl_create_osi_method = FALSE;
+ return;
+ }
+
+ if (*str == '!') {
+ str++;
+ enable = false;
+ }
+
+ for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+ osi = &osi_setup_entries[i];
+ if (!strcmp(osi->string, str)) {
+ osi->enable = enable;
+ break;
+ } else if (osi->string[0] == '\0') {
+ osi->enable = enable;
+ strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
+ break;
+ }
+ }
+}
+
static void __init set_osi_linux(unsigned int enable)
{
- if (osi_linux.enable != enable) {
+ if (osi_linux.enable != enable)
osi_linux.enable = enable;
- printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
- enable ? "Add": "Delet");
- }
if (osi_linux.enable)
acpi_osi_setup("Linux");
@@ -1073,7 +1109,8 @@ static void __init set_osi_linux(unsigned int enable)
static void __init acpi_cmdline_osi_linux(unsigned int enable)
{
- osi_linux.cmdline = 1; /* cmdline set the default */
+ osi_linux.cmdline = 1; /* cmdline set the default and override DMI */
+ osi_linux.dmi = 0;
set_osi_linux(enable);
return;
@@ -1081,15 +1118,12 @@ static void __init acpi_cmdline_osi_linux(unsigned int enable)
void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
{
- osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
-
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
if (enable == -1)
return;
- osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */
-
+ osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
set_osi_linux(enable);
return;
@@ -1104,37 +1138,44 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
*/
static void __init acpi_osi_setup_late(void)
{
- char *str = osi_setup_string;
+ struct osi_setup_entry *osi;
+ char *str;
+ int i;
+ acpi_status status;
- if (*str == '\0')
- return;
+ for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+ osi = &osi_setup_entries[i];
+ str = osi->string;
- if (!strcmp("!Linux", str)) {
- acpi_cmdline_osi_linux(0); /* !enable */
- } else if (*str == '!') {
- if (acpi_remove_interface(++str) == AE_OK)
- printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
- } else if (!strcmp("Linux", str)) {
- acpi_cmdline_osi_linux(1); /* enable */
- } else {
- if (acpi_install_interface(str) == AE_OK)
- printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ if (*str == '\0')
+ break;
+ if (osi->enable) {
+ status = acpi_install_interface(str);
+
+ if (ACPI_SUCCESS(status))
+ printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ } else {
+ status = acpi_remove_interface(str);
+
+ if (ACPI_SUCCESS(status))
+ printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
+ }
}
}
-int __init acpi_osi_setup(char *str)
+static int __init osi_setup(char *str)
{
- if (str == NULL || *str == '\0') {
- printk(KERN_INFO PREFIX "_OSI method disabled\n");
- acpi_gbl_create_osi_method = FALSE;
- } else {
- strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
- }
+ if (str && !strcmp("Linux", str))
+ acpi_cmdline_osi_linux(1);
+ else if (str && !strcmp("!Linux", str))
+ acpi_cmdline_osi_linux(0);
+ else
+ acpi_osi_setup(str);
return 1;
}
-__setup("acpi_osi=", acpi_osi_setup);
+__setup("acpi_osi=", osi_setup);
/* enable serialization to combat AE_ALREADY_EXISTS errors */
static int __init acpi_serialize_setup(char *str)
@@ -1192,8 +1233,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
int acpi_check_resource_conflict(const struct resource *res)
{
struct acpi_res_list *res_list_elem;
- int ioport;
- int clash = 0;
+ int ioport = 0, clash = 0;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return 0;
@@ -1223,9 +1263,13 @@ int acpi_check_resource_conflict(const struct resource *res)
if (clash) {
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
printk(KERN_WARNING "ACPI: resource %s %pR"
- " conflicts with ACPI region %s %pR\n",
+ " conflicts with ACPI region %s "
+ "[%s 0x%zx-0x%zx]\n",
res->name, res, res_list_elem->name,
- res_list_elem);
+ (res_list_elem->resource_type ==
+ ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem",
+ (size_t) res_list_elem->start,
+ (size_t) res_list_elem->end);
if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
printk(KERN_NOTICE "ACPI: This conflict may"
" cause random problems and system"
@@ -1530,7 +1574,7 @@ acpi_status __init acpi_os_initialize(void)
return AE_OK;
}
-acpi_status acpi_os_initialize1(void)
+acpi_status __init acpi_os_initialize1(void)
{
kacpid_wq = create_workqueue("kacpid");
kacpi_notify_wq = create_workqueue("kacpi_notify");
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 96668ad09622..85249395623b 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/apei.h>
#define PREFIX "ACPI: "
@@ -47,6 +48,11 @@ 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);
+#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
+ | OSC_ACTIVE_STATE_PWR_SUPPORT \
+ | OSC_CLOCK_PWR_CAPABILITY_SUPPORT \
+ | OSC_MSI_SUPPORT)
+
static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
@@ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ if (!pcie_ports_disabled
+ && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
+ flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+ | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+ | OSC_PCI_EXPRESS_PME_CONTROL;
+
+ if (pci_aer_available()) {
+ if (aer_acpi_firmware_first())
+ dev_dbg(root->bus->bridge,
+ "PCIe errors handled by BIOS.\n");
+ else
+ flags |= OSC_PCI_EXPRESS_AER_CONTROL;
+ }
+
+ dev_info(root->bus->bridge,
+ "Requesting ACPI _OSC control (0x%02x)\n", flags);
+
+ status = acpi_pci_osc_control_set(device->handle, &flags,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_SUCCESS(status))
+ dev_info(root->bus->bridge,
+ "ACPI _OSC control (0x%02x) granted\n", flags);
+ else
+ dev_dbg(root->bus->bridge,
+ "ACPI _OSC request failed (code %d)\n", status);
+ }
+
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
@@ -600,6 +633,8 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
static int __init acpi_pci_root_init(void)
{
+ acpi_hest_init();
+
if (acpi_pci_disabled)
return 0;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 67dedeed144c..9ac2a9fa90ff 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
-int acpi_power_nocheck;
-module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
-
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
@@ -148,9 +145,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{
- int result = 0, state1;
- u32 i = 0;
-
+ int cur_state;
+ int i = 0;
if (!list || !state)
return -EINVAL;
@@ -158,25 +154,33 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
/* The state of the list is 'on' IFF all resources are 'on'. */
for (i = 0; i < list->count; i++) {
- /*
- * The state of the power resource can be obtained by
- * using the ACPI handle. In such case it is unnecessary to
- * get the Power resource first and then get its state again.
- */
- result = acpi_power_get_state(list->handles[i], &state1);
+ struct acpi_power_resource *resource;
+ acpi_handle handle = list->handles[i];
+ int result;
+
+ result = acpi_power_get_context(handle, &resource);
if (result)
return result;
- *state = state1;
+ mutex_lock(&resource->resource_lock);
+
+ result = acpi_power_get_state(handle, &cur_state);
+
+ mutex_unlock(&resource->resource_lock);
+
+ if (result)
+ return result;
- if (*state != ACPI_POWER_RESOURCE_STATE_ON)
+ if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
break;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
- *state ? "on" : "off"));
+ cur_state ? "on" : "off"));
- return result;
+ *state = cur_state;
+
+ return 0;
}
static int __acpi_power_on(struct acpi_power_resource *resource)
@@ -213,14 +217,16 @@ static int acpi_power_on(acpi_handle handle)
resource->name));
} else {
result = __acpi_power_on(resource);
+ if (result)
+ resource->ref_count--;
}
mutex_unlock(&resource->resource_lock);
- return 0;
+ return result;
}
-static int acpi_power_off_device(acpi_handle handle)
+static int acpi_power_off(acpi_handle handle)
{
int result = 0;
acpi_status status = AE_OK;
@@ -264,6 +270,35 @@ static int acpi_power_off_device(acpi_handle handle)
return result;
}
+static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
+{
+ int i;
+
+ for (i = num_res - 1; i >= 0 ; i--)
+ acpi_power_off(list->handles[i]);
+}
+
+static void acpi_power_off_list(struct acpi_handle_list *list)
+{
+ __acpi_power_off_list(list, list->count);
+}
+
+static int acpi_power_on_list(struct acpi_handle_list *list)
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < list->count; i++) {
+ result = acpi_power_on(list->handles[i]);
+ if (result) {
+ __acpi_power_off_list(list, i);
+ break;
+ }
+ }
+
+ return result;
+}
+
/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
* ACPI 3.0) _PSW (Power State Wake)
@@ -402,8 +437,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_off_device(
- dev->wakeup.resources.handles[i]);
+ int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -421,19 +455,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
Device Power Management
-------------------------------------------------------------------------- */
-int acpi_power_get_inferred_state(struct acpi_device *device)
+int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
{
int result = 0;
struct acpi_handle_list *list = NULL;
int list_state = 0;
int i = 0;
-
- if (!device)
+ if (!device || !state)
return -EINVAL;
- device->power.state = ACPI_STATE_UNKNOWN;
-
/*
* We know a device's inferred power state when all the resources
* required for a given D-state are 'on'.
@@ -448,66 +479,51 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
return result;
if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
- device->power.state = i;
+ *state = i;
return 0;
}
}
- device->power.state = ACPI_STATE_D3;
-
+ *state = ACPI_STATE_D3;
return 0;
}
-int acpi_power_transition(struct acpi_device *device, int state)
+int acpi_power_on_resources(struct acpi_device *device, int state)
{
- int result = 0;
- struct acpi_handle_list *cl = NULL; /* Current Resources */
- struct acpi_handle_list *tl = NULL; /* Target Resources */
- int i = 0;
+ if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
+ return -EINVAL;
+ return acpi_power_on_list(&device->power.states[state].resources);
+}
+
+int acpi_power_transition(struct acpi_device *device, int state)
+{
+ int result;
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return -EINVAL;
+ if (device->power.state == state)
+ return 0;
+
if ((device->power.state < ACPI_STATE_D0)
|| (device->power.state > ACPI_STATE_D3))
return -ENODEV;
- cl = &device->power.states[device->power.state].resources;
- tl = &device->power.states[state].resources;
-
/* TBD: Resources must be ordered. */
/*
* First we reference all power resources required in the target list
- * (e.g. so the device doesn't lose power while transitioning).
+ * (e.g. so the device doesn't lose power while transitioning). Then,
+ * we dereference all power resources used in the current list.
*/
- for (i = 0; i < tl->count; i++) {
- result = acpi_power_on(tl->handles[i]);
- if (result)
- goto end;
- }
+ result = acpi_power_on_list(&device->power.states[state].resources);
+ if (!result)
+ acpi_power_off_list(
+ &device->power.states[device->power.state].resources);
- if (device->power.state == state) {
- goto end;
- }
-
- /*
- * Then we dereference all power resources used in the current list.
- */
- for (i = 0; i < cl->count; i++) {
- result = acpi_power_off_device(cl->handles[i]);
- if (result)
- goto end;
- }
-
- end:
- if (result)
- device->power.state = ACPI_STATE_UNKNOWN;
- else {
- /* We shouldn't change the state till all above operations succeed */
- device->power.state = state;
- }
+ /* We shouldn't change the state unless the above operations succeed. */
+ device->power.state = result ? ACPI_STATE_UNKNOWN : state;
return result;
}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index afad67769db6..f5f986991b52 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -311,7 +311,9 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state,
dev->wakeup.flags.run_wake ? '*' : ' ',
- dev->wakeup.state.enabled ? "enabled" : "disabled");
+ (device_may_wakeup(&dev->dev)
+ || (ldev && device_may_wakeup(ldev))) ?
+ "enabled" : "disabled");
if (ldev)
seq_printf(seq, "%s:%s",
ldev->bus ? ldev->bus->name : "no-bus",
@@ -328,8 +330,10 @@ static void physical_device_enable_wakeup(struct acpi_device *adev)
{
struct device *dev = acpi_get_physical_device(adev->handle);
- if (dev && device_can_wakeup(dev))
- device_set_wakeup_enable(dev, adev->wakeup.state.enabled);
+ if (dev && device_can_wakeup(dev)) {
+ bool enable = !device_may_wakeup(dev);
+ device_set_wakeup_enable(dev, enable);
+ }
}
static ssize_t
@@ -341,7 +345,6 @@ acpi_system_write_wakeup_device(struct file *file,
char strbuf[5];
char str[5] = "";
unsigned int len = count;
- struct acpi_device *found_dev = NULL;
if (len > 4)
len = 4;
@@ -361,33 +364,13 @@ acpi_system_write_wakeup_device(struct file *file,
continue;
if (!strncmp(dev->pnp.bus_id, str, 4)) {
- dev->wakeup.state.enabled =
- dev->wakeup.state.enabled ? 0 : 1;
- found_dev = dev;
- break;
- }
- }
- if (found_dev) {
- physical_device_enable_wakeup(found_dev);
- list_for_each_safe(node, next, &acpi_wakeup_device_list) {
- struct acpi_device *dev = container_of(node,
- struct
- acpi_device,
- wakeup_list);
-
- if ((dev != found_dev) &&
- (dev->wakeup.gpe_number ==
- found_dev->wakeup.gpe_number)
- && (dev->wakeup.gpe_device ==
- found_dev->wakeup.gpe_device)) {
- printk(KERN_WARNING
- "ACPI: '%s' and '%s' have the same GPE, "
- "can't disable/enable one separately\n",
- dev->pnp.bus_id, found_dev->pnp.bus_id);
- dev->wakeup.state.enabled =
- found_dev->wakeup.state.enabled;
+ if (device_can_wakeup(&dev->dev)) {
+ bool enable = !device_may_wakeup(&dev->dev);
+ device_set_wakeup_enable(&dev->dev, enable);
+ } else {
physical_device_enable_wakeup(dev);
}
+ break;
}
}
mutex_unlock(&acpi_device_lock);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index bec561c14beb..3c1a2fec8cda 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -23,7 +23,7 @@ static int set_no_mwait(const struct dmi_system_id *id)
{
printk(KERN_NOTICE PREFIX "%s detected - "
"disabling mwait for CPU C-states\n", id->ident);
- idle_nomwait = 1;
+ boot_option_idle_override = IDLE_NOMWAIT;
return 0;
}
@@ -283,7 +283,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;
- if (idle_nomwait) {
+ if (boot_option_idle_override == IDLE_NOMWAIT) {
/*
* If mwait is disabled for CPU C-states, the C2C3_FFH access
* mode will be disabled in the parameter of _PDC object.
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 85e48047d7b0..360a74e6add0 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -40,10 +40,6 @@
#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/cpu.h>
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/cpuidle.h>
@@ -246,53 +242,6 @@ static int acpi_processor_errata(struct acpi_processor *pr)
return result;
}
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_processor_dir = NULL;
-
-static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_processor_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- /* 'throttling' [R/W] */
- entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_processor_throttling_fops,
- acpi_driver_data(device));
- if (!entry)
- return -EIO;
- return 0;
-}
-static int acpi_processor_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_processor_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static inline int acpi_processor_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_processor_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -478,8 +427,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
if (action == CPU_ONLINE && pr) {
acpi_processor_ppc_has_changed(pr, 0);
acpi_processor_cst_has_changed(pr);
+ acpi_processor_reevaluate_tstate(pr, action);
acpi_processor_tstate_has_changed(pr);
}
+ if (action == CPU_DEAD && pr) {
+ /* invalidate the flag.throttling after one CPU is offline */
+ acpi_processor_reevaluate_tstate(pr, action);
+ }
return NOTIFY_OK;
}
@@ -537,14 +491,10 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
per_cpu(processors, pr->id) = pr;
- result = acpi_processor_add_fs(device);
- if (result)
- goto err_free_cpumask;
-
sysdev = get_cpu_sysdev(pr->id);
if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
result = -EFAULT;
- goto err_remove_fs;
+ goto err_free_cpumask;
}
#ifdef CONFIG_CPU_FREQ
@@ -590,8 +540,6 @@ err_thermal_unregister:
thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
acpi_processor_power_exit(pr, device);
-err_remove_fs:
- acpi_processor_remove_fs(device);
err_free_cpumask:
free_cpumask_var(pr->throttling.shared_cpu_map);
@@ -620,8 +568,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
sysfs_remove_link(&device->dev.kobj, "sysdev");
- acpi_processor_remove_fs(device);
-
if (pr->cdev) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
@@ -854,12 +800,6 @@ static int __init acpi_processor_init(void)
memset(&errata, 0, sizeof(errata));
-#ifdef CONFIG_ACPI_PROCFS
- acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- if (!acpi_processor_dir)
- return -ENOMEM;
-#endif
-
if (!cpuidle_register_driver(&acpi_idle_driver)) {
printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
acpi_idle_driver.name);
@@ -885,10 +825,6 @@ static int __init acpi_processor_init(void)
out_cpuidle:
cpuidle_unregister_driver(&acpi_idle_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
return result;
}
@@ -907,10 +843,6 @@ static void __exit acpi_processor_exit(void)
cpuidle_unregister_driver(&acpi_idle_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
return;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index dcb38f8ddfda..d615b7d69bca 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -79,6 +79,13 @@ module_param(bm_check_disable, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
+static int disabled_by_idle_boot_param(void)
+{
+ return boot_option_idle_override == IDLE_POLL ||
+ boot_option_idle_override == IDLE_FORCE_MWAIT ||
+ boot_option_idle_override == IDLE_HALT;
+}
+
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
* For now disable this. Probably a bug somewhere else.
@@ -455,7 +462,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
continue;
}
if (cx.type == ACPI_STATE_C1 &&
- (idle_halt || idle_nomwait)) {
+ (boot_option_idle_override == IDLE_NOMWAIT)) {
/*
* In most cases the C1 space_id obtained from
* _CST object is FIXED_HARDWARE access mode.
@@ -746,7 +753,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct acpi_processor *pr;
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
- pr = __get_cpu_var(processors);
+ pr = __this_cpu_read(processors);
if (unlikely(!pr))
return 0;
@@ -787,7 +794,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
s64 idle_time_ns;
s64 idle_time;
- pr = __get_cpu_var(processors);
+ pr = __this_cpu_read(processors);
if (unlikely(!pr))
return 0;
@@ -864,7 +871,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
s64 idle_time;
- pr = __get_cpu_var(processors);
+ pr = __this_cpu_read(processors);
if (unlikely(!pr))
return 0;
@@ -1016,7 +1023,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
- state->flags |= CPUIDLE_FLAG_SHALLOW;
if (cx->entry_method == ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
@@ -1025,16 +1031,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- state->flags |= CPUIDLE_FLAG_BALANCED;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
dev->safe_state = state;
break;
case ACPI_STATE_C3:
- state->flags |= CPUIDLE_FLAG_DEEP;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->flags |= CPUIDLE_FLAG_CHECK_BM;
state->enter = pr->flags.bm_check ?
acpi_idle_enter_bm :
acpi_idle_enter_simple;
@@ -1058,7 +1061,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int ret = 0;
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
if (!pr)
@@ -1089,19 +1092,10 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_status status = 0;
static int first_run;
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
if (!first_run) {
- if (idle_halt) {
- /*
- * When the boot option of "idle=halt" is added, halt
- * is used for CPU IDLE.
- * In such case C2/C3 is meaningless. So the max_cstate
- * is set to one.
- */
- max_cstate = 1;
- }
dmi_check_system(processor_power_dmi_table);
max_cstate = acpi_processor_cstate_check(max_cstate);
if (max_cstate < ACPI_C_STATES_MAX)
@@ -1142,7 +1136,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
cpuidle_unregister_device(&pr->power.dev);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index fde49b9b1d99..79cb65332894 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -156,15 +156,6 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
return 0;
}
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
- return -ENODEV;
-}
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
- return -ENODEV;
-}
-
#endif
int acpi_processor_get_limit_info(struct acpi_processor *pr)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index ff3632717c51..fa84e9744330 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -32,10 +32,6 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -370,6 +366,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
}
/*
+ * This function is used to reevaluate whether the T-state is valid
+ * after one CPU is onlined/offlined.
+ * It is noted that it won't reevaluate the following properties for
+ * the T-state.
+ * 1. Control method.
+ * 2. the number of supported T-state
+ * 3. TSD domain
+ */
+void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
+ unsigned long action)
+{
+ int result = 0;
+
+ if (action == CPU_DEAD) {
+ /* When one CPU is offline, the T-state throttling
+ * will be invalidated.
+ */
+ pr->flags.throttling = 0;
+ return;
+ }
+ /* the following is to recheck whether the T-state is valid for
+ * the online CPU
+ */
+ if (!pr->throttling.state_count) {
+ /* If the number of T-state is invalid, it is
+ * invalidated.
+ */
+ pr->flags.throttling = 0;
+ return;
+ }
+ pr->flags.throttling = 1;
+
+ /* Disable throttling (if enabled). We'll let subsequent
+ * policy (e.g.thermal) decide to lower performance if it
+ * so chooses, but for now we'll crank up the speed.
+ */
+
+ result = acpi_processor_get_throttling(pr);
+ if (result)
+ goto end;
+
+ if (pr->throttling.state) {
+ result = acpi_processor_set_throttling(pr, 0, false);
+ if (result)
+ goto end;
+ }
+
+end:
+ if (result)
+ pr->flags.throttling = 0;
+}
+/*
* _PTC - Processor Throttling Control (and status) register location
*/
static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
@@ -876,7 +924,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
*/
cpumask_copy(saved_mask, &current->cpus_allowed);
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
+ if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
+ /* Can't migrate to the target pr->id CPU. Exit */
+ free_cpumask_var(saved_mask);
+ return -ENODEV;
+ }
ret = pr->throttling.acpi_processor_get_throttling(pr);
/* restore the previous state */
set_cpus_allowed_ptr(current, saved_mask);
@@ -1051,6 +1103,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
return -ENOMEM;
}
+ if (cpu_is_offline(pr->id)) {
+ /*
+ * the cpu pointed by pr->id is offline. Unnecessary to change
+ * the throttling state any more.
+ */
+ return -ENODEV;
+ }
+
cpumask_copy(saved_mask, &current->cpus_allowed);
t_state.target_state = state;
p_throttling = &(pr->throttling);
@@ -1074,7 +1134,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
+ if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
+ /* Can't migrate to the pr->id CPU. Exit */
+ ret = -ENODEV;
+ goto exit;
+ }
ret = p_throttling->acpi_processor_set_throttling(pr,
t_state.target_state, force);
} else {
@@ -1106,7 +1170,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
}
t_state.cpu = i;
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(i));
+ if (set_cpus_allowed_ptr(current, cpumask_of(i)))
+ continue;
ret = match_pr->throttling.
acpi_processor_set_throttling(
match_pr, t_state.target_state, force);
@@ -1126,6 +1191,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
/* restore the previous state */
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr(current, saved_mask);
+exit:
free_cpumask_var(online_throttling_cpus);
free_cpumask_var(saved_mask);
return ret;
@@ -1216,113 +1282,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return result;
}
-#ifdef CONFIG_ACPI_PROCFS
-/* proc interface */
-static int acpi_processor_throttling_seq_show(struct seq_file *seq,
- void *offset)
-{
- struct acpi_processor *pr = seq->private;
- int i = 0;
- int result = 0;
-
- if (!pr)
- goto end;
-
- if (!(pr->throttling.state_count > 0)) {
- seq_puts(seq, "<not supported>\n");
- goto end;
- }
-
- result = acpi_processor_get_throttling(pr);
-
- if (result) {
- seq_puts(seq,
- "Could not determine current throttling state.\n");
- goto end;
- }
-
- seq_printf(seq, "state count: %d\n"
- "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");
- 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;
-}
-
-static int acpi_processor_throttling_open_fs(struct inode *inode,
- struct file *file)
-{
- return single_open(file, acpi_processor_throttling_seq_show,
- PDE(inode)->data);
-}
-
-static ssize_t acpi_processor_write_throttling(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int result = 0;
- struct seq_file *m = file->private_data;
- struct acpi_processor *pr = m->private;
- char state_string[5] = "";
- char *charp = NULL;
- size_t state_val = 0;
- char tmpbuf[5] = "";
-
- if (!pr || (count > sizeof(state_string) - 1))
- return -EINVAL;
-
- if (copy_from_user(state_string, buffer, count))
- return -EFAULT;
-
- state_string[count] = '\0';
- if ((count > 0) && (state_string[count-1] == '\n'))
- state_string[count-1] = '\0';
-
- charp = state_string;
- if ((state_string[0] == 't') || (state_string[0] == 'T'))
- charp++;
-
- state_val = simple_strtoul(charp, NULL, 0);
- if (state_val >= pr->throttling.state_count)
- return -EINVAL;
-
- snprintf(tmpbuf, 5, "%zu", state_val);
-
- if (strcmp(tmpbuf, charp) != 0)
- return -EINVAL;
-
- result = acpi_processor_set_throttling(pr, state_val, false);
- if (result)
- return result;
-
- return count;
-}
-
-const struct file_operations acpi_processor_throttling_fops = {
- .owner = THIS_MODULE,
- .open = acpi_processor_throttling_open_fs,
- .read = seq_read,
- .write = acpi_processor_write_throttling,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index e5dbedb16bbf..51ae3794ec7f 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -484,6 +484,8 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
const struct file_operations *state_fops,
const struct file_operations *alarm_fops, void *data)
{
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for SBS is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 2b6c21d86b98..b99e62494607 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -705,54 +705,85 @@ static int acpi_bus_get_perf_flags(struct acpi_device *device)
}
static acpi_status
-acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
- union acpi_object *package)
+acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+ struct acpi_device_wakeup *wakeup)
{
- int i = 0;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *package = NULL;
union acpi_object *element = NULL;
+ acpi_status status;
+ int i = 0;
- if (!device || !package || (package->package.count < 2))
+ if (!wakeup)
return AE_BAD_PARAMETER;
+ /* _PRW */
+ status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
+ return status;
+ }
+
+ package = (union acpi_object *)buffer.pointer;
+
+ if (!package || (package->package.count < 2)) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+
element = &(package->package.elements[0]);
- if (!element)
- return AE_BAD_PARAMETER;
+ if (!element) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
if (element->type == ACPI_TYPE_PACKAGE) {
if ((element->package.count < 2) ||
(element->package.elements[0].type !=
ACPI_TYPE_LOCAL_REFERENCE)
- || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
- return AE_BAD_DATA;
- device->wakeup.gpe_device =
+ || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+ wakeup->gpe_device =
element->package.elements[0].reference.handle;
- device->wakeup.gpe_number =
+ wakeup->gpe_number =
(u32) element->package.elements[1].integer.value;
} else if (element->type == ACPI_TYPE_INTEGER) {
- device->wakeup.gpe_number = element->integer.value;
- } else
- return AE_BAD_DATA;
+ wakeup->gpe_device = NULL;
+ wakeup->gpe_number = element->integer.value;
+ } else {
+ status = AE_BAD_DATA;
+ goto out;
+ }
element = &(package->package.elements[1]);
if (element->type != ACPI_TYPE_INTEGER) {
- return AE_BAD_DATA;
+ status = AE_BAD_DATA;
+ goto out;
}
- device->wakeup.sleep_state = element->integer.value;
+ wakeup->sleep_state = element->integer.value;
if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
- return AE_NO_MEMORY;
+ status = AE_NO_MEMORY;
+ goto out;
}
- device->wakeup.resources.count = package->package.count - 2;
- for (i = 0; i < device->wakeup.resources.count; i++) {
+ wakeup->resources.count = package->package.count - 2;
+ for (i = 0; i < wakeup->resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
- return AE_BAD_DATA;
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
- device->wakeup.resources.handles[i] = element->reference.handle;
+ wakeup->resources.handles[i] = element->reference.handle;
}
- acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number);
+ acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
- return AE_OK;
+ out:
+ kfree(buffer.pointer);
+
+ return status;
}
static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
@@ -772,7 +803,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids)) {
device->wakeup.flags.run_wake = 1;
- device->wakeup.flags.always_enabled = 1;
+ device_set_wakeup_capable(&device->dev, true);
return;
}
@@ -784,29 +815,24 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
!!(event_status & ACPI_EVENT_FLAG_HANDLE);
}
-static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
+static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{
+ acpi_handle temp;
acpi_status status = 0;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *package = NULL;
int psw_error;
- /* _PRW */
- status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
- goto end;
- }
+ /* Presence of _PRW indicates wake capable */
+ status = acpi_get_handle(device->handle, "_PRW", &temp);
+ if (ACPI_FAILURE(status))
+ return;
- package = (union acpi_object *)buffer.pointer;
- status = acpi_bus_extract_wakeup_device_power_package(device, package);
+ status = acpi_bus_extract_wakeup_device_power_package(device->handle,
+ &device->wakeup);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
- goto end;
+ return;
}
- kfree(buffer.pointer);
-
device->wakeup.flags.valid = 1;
device->wakeup.prepare_count = 0;
acpi_bus_set_run_wake_flags(device);
@@ -820,13 +846,10 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
if (psw_error)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n"));
-
-end:
- if (ACPI_FAILURE(status))
- device->flags.wake_capable = 0;
- return 0;
}
+static void acpi_bus_add_power_resource(acpi_handle handle);
+
static int acpi_bus_get_power_flags(struct acpi_device *device)
{
acpi_status status = 0;
@@ -855,8 +878,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
acpi_evaluate_reference(device->handle, object_name, NULL,
&ps->resources);
if (ps->resources.count) {
+ int j;
+
device->power.flags.power_resources = 1;
ps->flags.valid = 1;
+ for (j = 0; j < ps->resources.count; j++)
+ acpi_bus_add_power_resource(ps->resources.handles[j]);
}
/* Evaluate "_PSx" to see if we can do explicit sets */
@@ -881,10 +908,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device->power.states[ACPI_STATE_D3].flags.valid = 1;
device->power.states[ACPI_STATE_D3].power = 0;
- /* TBD: System wake support and resource requirements. */
-
- device->power.state = ACPI_STATE_UNKNOWN;
- acpi_bus_get_power(device->handle, &(device->power.state));
+ acpi_bus_init_power(device);
return 0;
}
@@ -927,11 +951,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
if (ACPI_SUCCESS(status))
device->flags.power_manageable = 1;
- /* Presence of _PRW indicates wake capable */
- status = acpi_get_handle(device->handle, "_PRW", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.wake_capable = 1;
-
/* TBD: Performance management */
return 0;
@@ -1258,11 +1277,7 @@ static int acpi_add_single_object(struct acpi_device **child,
* Wakeup device management
*-----------------------
*/
- if (device->flags.wake_capable) {
- result = acpi_bus_get_wakeup_device_flags(device);
- if (result)
- goto end;
- }
+ acpi_bus_get_wakeup_device_flags(device);
/*
* Performance Management
@@ -1306,6 +1321,20 @@ end:
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
+static void acpi_bus_add_power_resource(acpi_handle handle)
+{
+ struct acpi_bus_ops ops = {
+ .acpi_op_add = 1,
+ .acpi_op_start = 1,
+ };
+ struct acpi_device *device = NULL;
+
+ acpi_bus_get_device(handle, &device);
+ if (!device)
+ acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
+ ACPI_STA_DEFAULT, &ops);
+}
+
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
unsigned long long *sta)
{
@@ -1360,8 +1389,16 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
return AE_OK;
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
- !(sta & ACPI_STA_DEVICE_FUNCTIONING))
+ !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
+ struct acpi_device_wakeup wakeup;
+ acpi_handle temp;
+
+ status = acpi_get_handle(handle, "_PRW", &temp);
+ if (ACPI_SUCCESS(status))
+ acpi_bus_extract_wakeup_device_power_package(handle,
+ &wakeup);
return AE_CTRL_DEPTH;
+ }
/*
* We may already have an acpi_device from a previous enumeration. If
@@ -1444,7 +1481,7 @@ int acpi_bus_start(struct acpi_device *device)
result = acpi_bus_scan(device->handle, &ops, NULL);
- acpi_update_gpes();
+ acpi_update_all_gpes();
return result;
}
@@ -1550,6 +1587,8 @@ int __init acpi_scan_init(void)
printk(KERN_ERR PREFIX "Could not register bus type\n");
}
+ acpi_power_init();
+
/*
* Enumerate devices in the ACPI namespace.
*/
@@ -1561,7 +1600,7 @@ int __init acpi_scan_init(void)
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
else
- acpi_update_gpes();
+ acpi_update_all_gpes();
return result;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 721d93b3ceee..fdd3aeeb6def 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -27,8 +27,6 @@
static u8 sleep_states[ACPI_S_STATE_COUNT];
-static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
static void acpi_sleep_tts_switch(u32 acpi_state)
{
union acpi_object in_arg = { ACPI_TYPE_INTEGER };
@@ -81,6 +79,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
}
#ifdef CONFIG_ACPI_SLEEP
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. Windows does that also for
@@ -124,8 +124,7 @@ static int acpi_pm_freeze(void)
static int acpi_pm_pre_suspend(void)
{
acpi_pm_freeze();
- suspend_nvs_save();
- return 0;
+ return suspend_nvs_save();
}
/**
@@ -151,7 +150,7 @@ static int acpi_pm_prepare(void)
{
int error = __acpi_pm_prepare();
if (!error)
- acpi_pm_pre_suspend();
+ error = acpi_pm_pre_suspend();
return error;
}
@@ -319,7 +318,7 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state)
}
}
-static struct platform_suspend_ops acpi_suspend_ops = {
+static const struct platform_suspend_ops acpi_suspend_ops = {
.valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin,
.prepare_late = acpi_pm_prepare,
@@ -347,7 +346,7 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
* The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
* been requested.
*/
-static struct platform_suspend_ops acpi_suspend_ops_old = {
+static const struct platform_suspend_ops acpi_suspend_ops_old = {
.valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin_old,
.prepare_late = acpi_pm_pre_suspend,
@@ -427,6 +426,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-NW130D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Averatec AV1020-ED2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
@@ -498,7 +513,7 @@ static void acpi_pm_thaw(void)
acpi_enable_all_runtime_gpes();
}
-static struct platform_hibernation_ops acpi_hibernation_ops = {
+static const struct platform_hibernation_ops acpi_hibernation_ops = {
.begin = acpi_hibernation_begin,
.end = acpi_pm_end,
.pre_snapshot = acpi_pm_prepare,
@@ -541,7 +556,7 @@ static int acpi_hibernation_begin_old(void)
* The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
* been requested.
*/
-static struct platform_hibernation_ops acpi_hibernation_ops_old = {
+static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
.begin = acpi_hibernation_begin_old,
.end = acpi_pm_end,
.pre_snapshot = acpi_pm_pre_suspend,
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index f8588f81048a..61891e75583d 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -438,7 +438,7 @@ static void delete_gpe_attr_array(void)
return;
}
-void acpi_os_gpe_count(u32 gpe_number)
+static void gpe_count(u32 gpe_number)
{
acpi_gpe_count++;
@@ -454,7 +454,7 @@ void acpi_os_gpe_count(u32 gpe_number)
return;
}
-void acpi_os_fixed_event_count(u32 event_number)
+static void fixed_event_count(u32 event_number)
{
if (!all_counters)
return;
@@ -468,6 +468,16 @@ void acpi_os_fixed_event_count(u32 event_number)
return;
}
+static void acpi_gbl_event_handler(u32 event_type, acpi_handle device,
+ u32 event_number, void *context)
+{
+ if (event_type == ACPI_EVENT_TYPE_GPE)
+ gpe_count(event_number);
+
+ if (event_type == ACPI_EVENT_TYPE_FIXED)
+ fixed_event_count(event_number);
+}
+
static int get_status(u32 index, acpi_event_status *status,
acpi_handle *handle)
{
@@ -601,6 +611,7 @@ end:
void acpi_irq_stats_init(void)
{
+ acpi_status status;
int i;
if (all_counters)
@@ -619,6 +630,10 @@ void acpi_irq_stats_init(void)
if (all_counters == NULL)
goto fail;
+ status = acpi_install_global_event_handler(acpi_gbl_event_handler, NULL);
+ if (ACPI_FAILURE(status))
+ goto fail;
+
counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
GFP_KERNEL);
if (counter_attrs == NULL)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5a27b0a31315..2607e17b520f 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -1059,8 +1059,9 @@ static int acpi_thermal_resume(struct acpi_device *device)
break;
tz->trips.active[i].flags.enabled = 1;
for (j = 0; j < tz->trips.active[i].devices.count; j++) {
- result = acpi_bus_get_power(tz->trips.active[i].devices.
- handles[j], &power_state);
+ result = acpi_bus_update_power(
+ tz->trips.active[i].devices.handles[j],
+ &power_state);
if (result || (power_state != ACPI_STATE_D0)) {
tz->trips.active[i].flags.enabled = 0;
break;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 5cd0228d2daa..90f8f7676d1f 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -33,7 +33,6 @@
#include <linux/input.h>
#include <linux/backlight.h>
#include <linux/thermal.h>
-#include <linux/video_output.h>
#include <linux/sort.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
@@ -81,6 +80,13 @@ module_param(brightness_switch_enabled, bool, 0644);
static int allow_duplicates;
module_param(allow_duplicates, bool, 0644);
+/*
+ * Some BIOSes claim they use minimum backlight at boot,
+ * and this may bring dimming screen after boot
+ */
+static int use_bios_initial_backlight = 1;
+module_param(use_bios_initial_backlight, bool, 0644);
+
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
@@ -172,9 +178,6 @@ struct acpi_video_device_cap {
u8 _BQC:1; /* Get current brightness level */
u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */
u8 _DDC:1; /*Return the EDID for this device */
- u8 _DCS:1; /*Return status of output device */
- u8 _DGS:1; /*Query graphics state */
- u8 _DSS:1; /*Device state set */
};
struct acpi_video_brightness_flags {
@@ -202,7 +205,6 @@ struct acpi_video_device {
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
struct thermal_cooling_device *cooling_dev;
- struct output_device *output_dev;
};
static const char device_decode[][30] = {
@@ -226,10 +228,6 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static int acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
-static int acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long 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)
@@ -260,35 +258,11 @@ static int acpi_video_set_brightness(struct backlight_device *bd)
vd->brightness->levels[request_level]);
}
-static struct backlight_ops acpi_backlight_ops = {
+static const struct backlight_ops acpi_backlight_ops = {
.get_brightness = acpi_video_get_brightness,
.update_status = acpi_video_set_brightness,
};
-/*video output device sysfs support*/
-static int acpi_video_output_get(struct output_device *od)
-{
- unsigned long 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,
-};
-
-
/* thermal cooling device callbacks */
static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
long *state)
@@ -344,34 +318,6 @@ static struct thermal_cooling_device_ops video_cooling_ops = {
Video Management
-------------------------------------------------------------------------- */
-/* device */
-
-static int
-acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long long *state)
-{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state);
-
- return status;
-}
-
-static int
-acpi_video_device_set_state(struct acpi_video_device *device, int state)
-{
- int status;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
- unsigned long long ret;
-
-
- arg0.integer.value = state;
- status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret);
-
- return status;
-}
-
static int
acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
union acpi_object **levels)
@@ -766,9 +712,11 @@ acpi_video_init_brightness(struct acpi_video_device *device)
* when invoked for the first time, i.e. level_old is invalid.
* set the backlight to max_level in this case
*/
- for (i = 2; i < br->count; i++)
- if (level_old == br->levels[i])
- level = level_old;
+ if (use_bios_initial_backlight) {
+ for (i = 2; i < br->count; i++)
+ if (level_old == br->levels[i])
+ level = level_old;
+ }
goto set_level;
}
@@ -831,15 +779,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) {
- device->cap._DCS = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) {
- device->cap._DGS = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) {
- device->cap._DSS = 1;
- }
if (acpi_video_backlight_support()) {
struct backlight_properties props;
@@ -904,21 +843,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
-
- if (acpi_video_display_switch_support()) {
-
- if (device->cap._DCS && device->cap._DSS) {
- static int count;
- char *name;
- name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
- if (!name)
- return;
- count++;
- device->output_dev = video_output_register(name,
- NULL, device, &acpi_output_properties);
- kfree(name);
- }
- }
}
/*
@@ -1360,6 +1284,9 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
if (!video_device)
continue;
+ if (!video_device->cap._DDC)
+ continue;
+
if (type) {
switch (type) {
case ACPI_VIDEO_DISPLAY_CRT:
@@ -1452,7 +1379,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
thermal_cooling_device_unregister(device->cooling_dev);
device->cooling_dev = NULL;
}
- video_output_unregister(device->output_dev);
return 0;
}
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index b83676126598..42d3d72dae85 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -17,15 +17,14 @@
* capabilities the graphics cards plugged in support. The check for general
* video capabilities will be triggered by the first caller of
* acpi_video_get_capabilities(NULL); which will happen when the first
- * backlight (or display output) switching supporting driver calls:
+ * backlight switching supporting driver calls:
* acpi_video_backlight_support();
*
* Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
* are available, video.ko should be used to handle the device.
*
* Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
- * sony_acpi,... can take care about backlight brightness and display output
- * switching.
+ * sony_acpi,... can take care about backlight brightness.
*
* If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
* this file will not be compiled, acpi_video_get_capabilities() and
@@ -83,11 +82,6 @@ long acpi_is_video_device(struct acpi_device *device)
if (!device)
return 0;
- /* Is this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
- video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
-
/* Is this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
@@ -161,8 +155,6 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle)
*
* if (dmi_name_in_vendors("XY")) {
* acpi_video_support |=
- * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
- * acpi_video_support |=
* ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
*}
*/
@@ -212,33 +204,8 @@ int acpi_video_backlight_support(void)
EXPORT_SYMBOL(acpi_video_backlight_support);
/*
- * Returns true if video.ko can do display output switching.
- * This does not work well/at all with binary graphics drivers
- * which disable system io ranges and do it on their own.
- */
-int acpi_video_display_switch_support(void)
-{
- if (!acpi_video_caps_checked)
- acpi_video_get_capabilities(NULL);
-
- if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
- return 1;
-
- if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
- return 1;
-
- return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
-}
-EXPORT_SYMBOL(acpi_video_display_switch_support);
-
-/*
- * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video
- * To force that backlight or display output switching is processed by vendor
- * specific acpi drivers or video.ko driver.
+ * Use acpi_backlight=vendor/video to force that backlight switching
+ * is processed by vendor specific acpi drivers or video.ko driver.
*/
static int __init acpi_backlight(char *str)
{
@@ -255,19 +222,3 @@ static int __init acpi_backlight(char *str)
return 1;
}
__setup("acpi_backlight=", acpi_backlight);
-
-static int __init acpi_display_output(char *str)
-{
- if (str == NULL || *str == '\0')
- return 1;
- else {
- if (!strcmp("vendor", str))
- acpi_video_support |=
- ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
- if (!strcmp("video", str))
- acpi_video_support |=
- ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
- }
- return 1;
-}
-__setup("acpi_display_output=", acpi_display_output);
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index f62a50c3ed34..ed6501452507 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -37,15 +37,16 @@ void acpi_enable_wakeup_devices(u8 sleep_state)
container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid
- || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
- || sleep_state > (u32) dev->wakeup.sleep_state)
+ || sleep_state > (u32) dev->wakeup.sleep_state
+ || !(device_may_wakeup(&dev->dev)
+ || dev->wakeup.prepare_count))
continue;
- if (dev->wakeup.state.enabled)
+ if (device_may_wakeup(&dev->dev))
acpi_enable_wakeup_device_power(dev, sleep_state);
/* The wake-up power should have been enabled already. */
- acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
ACPI_GPE_ENABLE);
}
}
@@ -63,14 +64,15 @@ void acpi_disable_wakeup_devices(u8 sleep_state)
container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid
- || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
- || (sleep_state > (u32) dev->wakeup.sleep_state))
+ || sleep_state > (u32) dev->wakeup.sleep_state
+ || !(device_may_wakeup(&dev->dev)
+ || dev->wakeup.prepare_count))
continue;
- acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
ACPI_GPE_DISABLE);
- if (dev->wakeup.state.enabled)
+ if (device_may_wakeup(&dev->dev))
acpi_disable_wakeup_device_power(dev);
}
}
@@ -84,8 +86,8 @@ int __init acpi_wakeup_device_init(void)
struct acpi_device *dev = container_of(node,
struct acpi_device,
wakeup_list);
- if (dev->wakeup.flags.always_enabled)
- dev->wakeup.state.enabled = 1;
+ if (device_can_wakeup(&dev->dev))
+ device_set_wakeup_enable(&dev->dev, true);
}
mutex_unlock(&acpi_device_lock);
return 0;
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 2737b9752205..e7df019d29d4 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -147,6 +147,39 @@ static void amba_put_disable_pclk(struct amba_device *pcdev)
clk_put(pclk);
}
+static int amba_get_enable_vcore(struct amba_device *pcdev)
+{
+ struct regulator *vcore = regulator_get(&pcdev->dev, "vcore");
+ int ret;
+
+ pcdev->vcore = vcore;
+
+ if (IS_ERR(vcore)) {
+ /* It is OK not to supply a vcore regulator */
+ if (PTR_ERR(vcore) == -ENODEV)
+ return 0;
+ return PTR_ERR(vcore);
+ }
+
+ ret = regulator_enable(vcore);
+ if (ret) {
+ regulator_put(vcore);
+ pcdev->vcore = ERR_PTR(-ENODEV);
+ }
+
+ return ret;
+}
+
+static void amba_put_disable_vcore(struct amba_device *pcdev)
+{
+ struct regulator *vcore = pcdev->vcore;
+
+ if (!IS_ERR(vcore)) {
+ regulator_disable(vcore);
+ regulator_put(vcore);
+ }
+}
+
/*
* These are the device model conversion veneers; they convert the
* device model structures to our more specific structures.
@@ -159,6 +192,10 @@ static int amba_probe(struct device *dev)
int ret;
do {
+ ret = amba_get_enable_vcore(pcdev);
+ if (ret)
+ break;
+
ret = amba_get_enable_pclk(pcdev);
if (ret)
break;
@@ -168,6 +205,7 @@ static int amba_probe(struct device *dev)
break;
amba_put_disable_pclk(pcdev);
+ amba_put_disable_vcore(pcdev);
} while (0);
return ret;
@@ -180,6 +218,7 @@ static int amba_remove(struct device *dev)
int ret = drv->remove(pcdev);
amba_put_disable_pclk(pcdev);
+ amba_put_disable_vcore(pcdev);
return ret;
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 11ec911016c6..c6b298d4c136 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -2,6 +2,14 @@
# SATA/PATA driver configuration
#
+config HAVE_PATA_PLATFORM
+ bool
+ help
+ This is an internal configuration node for any machine that
+ uses pata-platform driver to enable the relevant driver in the
+ configuration structure without having to submit endless patches
+ to update the PATA_PLATFORM entry.
+
menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers"
depends on HAS_IOMEM
@@ -90,6 +98,14 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
+config SATA_ACARD_AHCI
+ tristate "ACard AHCI variant (ATP 8620)"
+ depends on PCI
+ help
+ This option enables support for Acard.
+
+ If unsure, say N.
+
config SATA_SIL24
tristate "Silicon Image 3124/3132 SATA support"
depends on PCI
@@ -128,16 +144,6 @@ config PDC_ADMA
If unsure, say N.
-config PATA_MPC52xx
- tristate "Freescale MPC52xx SoC internal IDE"
- depends on PPC_MPC52xx && PPC_BESTCOMM
- select PPC_BESTCOMM_ATA
- help
- This option enables support for integrated IDE controller
- of the Freescale MPC52xx SoC.
-
- If unsure, say N.
-
config PATA_OCTEON_CF
tristate "OCTEON Boot Bus Compact Flash support"
depends on CPU_CAVIUM_OCTEON
@@ -366,7 +372,7 @@ config PATA_CS5535
config PATA_CS5536
tristate "CS5536 PATA support"
- depends on PCI && X86 && !X86_64
+ depends on PCI
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
@@ -410,11 +416,11 @@ config PATA_HPT37X
If unsure, say N.
config PATA_HPT3X2N
- tristate "HPT 372N/302N PATA support"
+ tristate "HPT 371N/372N/302N PATA support"
depends on PCI
help
This option enables support for the N variant HPT PATA
- controllers via the new ATA layer
+ controllers via the new ATA layer.
If unsure, say N.
@@ -491,6 +497,16 @@ config PATA_MARVELL
If unsure, say N.
+config PATA_MPC52xx
+ tristate "Freescale MPC52xx SoC internal IDE"
+ depends on PPC_MPC52xx && PPC_BESTCOMM
+ select PPC_BESTCOMM_ATA
+ help
+ This option enables support for integrated IDE controller
+ of the Freescale MPC52xx SoC.
+
+ If unsure, say N.
+
config PATA_NETCELL
tristate "NETCELL Revolution RAID support"
depends on PCI
@@ -765,14 +781,6 @@ config PATA_PCMCIA
If unsure, say N.
-config HAVE_PATA_PLATFORM
- bool
- help
- This is an internal configuration node for any machine that
- uses pata-platform driver to enable the relevant driver in the
- configuration structure without having to submit endless patches
- to update the PATA_PLATFORM entry.
-
config PATA_PLATFORM
tristate "Generic platform device PATA support"
depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index c501af5b12b9..27291aad6ca7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
+obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
-obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
obj-$(CONFIG_SATA_SX4) += sata_sx4.o
@@ -52,6 +52,7 @@ obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_MACIO) += pata_macio.o
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
+obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
new file mode 100644
index 000000000000..339c210f03a6
--- /dev/null
+++ b/drivers/ata/acard-ahci.c
@@ -0,0 +1,528 @@
+
+/*
+ * acard-ahci.c - ACard AHCI SATA support
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2010 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include "ahci.h"
+
+#define DRV_NAME "acard-ahci"
+#define DRV_VERSION "1.0"
+
+/*
+ Received FIS structure limited to 80h.
+*/
+
+#define ACARD_AHCI_RX_FIS_SZ 128
+
+enum {
+ AHCI_PCI_BAR = 5,
+};
+
+enum board_ids {
+ board_acard_ahci,
+};
+
+struct acard_sg {
+ __le32 addr;
+ __le32 addr_hi;
+ __le32 reserved;
+ __le32 size; /* bit 31 (EOT) max==0x10000 (64k) */
+};
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc);
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static int acard_ahci_port_start(struct ata_port *ap);
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+#ifdef CONFIG_PM
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev);
+#endif
+
+static struct scsi_host_template acard_ahci_sht = {
+ AHCI_SHT("acard-ahci"),
+};
+
+static struct ata_port_operations acard_ops = {
+ .inherits = &ahci_ops,
+ .qc_prep = acard_ahci_qc_prep,
+ .qc_fill_rtf = acard_ahci_qc_fill_rtf,
+ .port_start = acard_ahci_port_start,
+};
+
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
+static const struct ata_port_info acard_ahci_port_info[] = {
+ [board_acard_ahci] =
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &acard_ops,
+ },
+};
+
+static const struct pci_device_id acard_ahci_pci_tbl[] = {
+ /* ACard */
+ { PCI_VDEVICE(ARTOP, 0x000d), board_acard_ahci }, /* ATP8620 */
+
+ { } /* terminate list */
+};
+
+static struct pci_driver acard_ahci_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = acard_ahci_pci_tbl,
+ .probe = acard_ahci_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = acard_ahci_pci_device_suspend,
+ .resume = acard_ahci_pci_device_resume,
+#endif
+};
+
+#ifdef CONFIG_PM
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+
+ if (mesg.event & PM_EVENT_SUSPEND &&
+ hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ if (mesg.event & PM_EVENT_SLEEP) {
+ /* AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
+{
+ int rc;
+
+ if (using_dac &&
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static void acard_ahci_pci_print_info(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ u16 cc;
+ const char *scc_s;
+
+ pci_read_config_word(pdev, 0x0a, &cc);
+ if (cc == PCI_CLASS_STORAGE_IDE)
+ scc_s = "IDE";
+ else if (cc == PCI_CLASS_STORAGE_SATA)
+ scc_s = "SATA";
+ else if (cc == PCI_CLASS_STORAGE_RAID)
+ scc_s = "RAID";
+ else
+ scc_s = "unknown";
+
+ ahci_print_info(host, scc_s);
+}
+
+static unsigned int acard_ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+{
+ struct scatterlist *sg;
+ struct acard_sg *acard_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+ unsigned int si, last_si = 0;
+
+ VPRINTK("ENTER\n");
+
+ /*
+ * Next, the S/G list.
+ */
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ /*
+ * ACard note:
+ * We must set an end-of-table (EOT) bit,
+ * and the segment cannot exceed 64k (0x10000)
+ */
+ acard_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+ acard_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ acard_sg[si].size = cpu_to_le32(sg_len);
+ last_si = si;
+ }
+
+ acard_sg[last_si].size |= cpu_to_le32(1 << 31); /* set EOT */
+
+ return si;
+}
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ int is_atapi = ata_is_atapi(qc->tf.protocol);
+ void *cmd_tbl;
+ u32 opts;
+ const u32 cmd_fis_len = 5; /* five dwords */
+ unsigned int n_elem;
+
+ /*
+ * Fill in command table information. First, the header,
+ * a SATA Register - Host to Device command FIS.
+ */
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ 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);
+ }
+
+ n_elem = 0;
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ n_elem = acard_ahci_fill_sg(qc, cmd_tbl);
+
+ /*
+ * Fill in command slot information.
+ *
+ * ACard note: prd table length not filled in
+ */
+ opts = cmd_fis_len | (qc->dev->link->pmp << 12);
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ opts |= AHCI_CMD_WRITE;
+ if (is_atapi)
+ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
+}
+
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ahci_port_priv *pp = qc->ap->private_data;
+ u8 *rx_fis = pp->rx_fis;
+
+ if (pp->fbs_enabled)
+ rx_fis += qc->dev->link->pmp * ACARD_AHCI_RX_FIS_SZ;
+
+ /*
+ * After a successful execution of an ATA PIO data-in command,
+ * the device doesn't send D2H Reg FIS to update the TF and
+ * the host should take TF and E_Status from the preceding PIO
+ * Setup FIS.
+ */
+ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+ !(qc->flags & ATA_QCFLAG_FAILED)) {
+ ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+ qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+ } else
+ ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+
+ return true;
+}
+
+static int acard_ahci_port_start(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct device *dev = ap->host->dev;
+ struct ahci_port_priv *pp;
+ void *mem;
+ dma_addr_t mem_dma;
+ size_t dma_sz, rx_fis_sz;
+
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ /* check FBS capability */
+ if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd = readl(port_mmio + PORT_CMD);
+ if (cmd & PORT_CMD_FBSCP)
+ pp->fbs_supported = true;
+ else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
+ dev_printk(KERN_INFO, dev,
+ "port %d can do FBS, forcing FBSCP\n",
+ ap->port_no);
+ pp->fbs_supported = true;
+ } else
+ dev_printk(KERN_WARNING, dev,
+ "port %d is not capable of FBS\n",
+ ap->port_no);
+ }
+
+ if (pp->fbs_supported) {
+ dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+ rx_fis_sz = ACARD_AHCI_RX_FIS_SZ * 16;
+ } else {
+ dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+ rx_fis_sz = ACARD_AHCI_RX_FIS_SZ;
+ }
+
+ mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+ memset(mem, 0, dma_sz);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = mem;
+ pp->cmd_slot_dma = mem_dma;
+
+ mem += AHCI_CMD_SLOT_SZ;
+ mem_dma += AHCI_CMD_SLOT_SZ;
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ pp->rx_fis_dma = mem_dma;
+
+ mem += rx_fis_sz;
+ mem_dma += rx_fis_sz;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ 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 */
+ return ahci_port_resume(ap);
+}
+
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int board_id = ent->driver_data;
+ struct ata_port_info pi = acard_ahci_port_info[board_id];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct ata_host *host;
+ int n_ports, i, rc;
+
+ VPRINTK("ENTER\n");
+
+ WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /* acquire resources */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ /* AHCI controllers often implement SFF compatible interface.
+ * Grab all PCI BARs just in case.
+ */
+ rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+
+ 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);
+
+ hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+
+ /* save initial config */
+ ahci_save_initial_config(&pdev->dev, hpriv, 0, 0);
+
+ /* prepare host */
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ 0x100 + ap->port_no * 0x80, "port");
+
+ /* set initial link pm policy */
+ /*
+ ap->pm_policy = NOT_AVAILABLE;
+ */
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ /* initialize adapter */
+ rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
+ if (rc)
+ return rc;
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ acard_ahci_pci_print_info(host);
+
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+ &acard_ahci_sht);
+}
+
+static int __init acard_ahci_init(void)
+{
+ return pci_register_driver(&acard_ahci_pci_driver);
+}
+
+static void __exit acard_ahci_exit(void)
+{
+ pci_unregister_driver(&acard_ahci_pci_driver);
+}
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("ACard AHCI SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, acard_ahci_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(acard_ahci_init);
+module_exit(acard_ahci_exit);
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 329cbbb91284..3e606c34f57b 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -311,6 +311,8 @@ extern struct device_attribute *ahci_sdev_attrs[];
extern struct ata_port_operations ahci_ops;
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts);
void ahci_save_initial_config(struct device *dev,
struct ahci_host_priv *hpriv,
unsigned int force_port_map,
@@ -326,6 +328,7 @@ int ahci_stop_engine(struct ata_port *ap);
void ahci_start_engine(struct ata_port *ap);
int ahci_check_ready(struct ata_link *link);
int ahci_kick_engine(struct ata_port *ap);
+int ahci_port_resume(struct ata_port *ap);
void ahci_set_em_messages(struct ahci_host_priv *hpriv,
struct ata_port_info *pi);
int ahci_reset_em(struct ata_host *host);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index ebc08d65b3dd..26d452339e98 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -87,10 +87,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
static void ahci_postreset(struct ata_link *link, unsigned int *class);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
-static int ahci_port_resume(struct ata_port *ap);
static void ahci_dev_config(struct ata_device *dev);
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts);
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
#endif
@@ -1133,8 +1130,8 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts)
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts)
{
dma_addr_t cmd_tbl_dma;
@@ -1145,6 +1142,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
+EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);
int ahci_kick_engine(struct ata_port *ap)
{
@@ -1918,7 +1916,7 @@ static void ahci_pmp_detach(struct ata_port *ap)
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
-static int ahci_port_resume(struct ata_port *ap)
+int ahci_port_resume(struct ata_port *ap)
{
ahci_power_up(ap);
ahci_start_port(ap);
@@ -1930,6 +1928,7 @@ static int ahci_port_resume(struct ata_port *ap)
return 0;
}
+EXPORT_SYMBOL_GPL(ahci_port_resume);
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 7f77c67d267c..a31fe96f7de6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2240,7 +2240,7 @@ int ata_dev_configure(struct ata_device *dev)
if (id[ATA_ID_CFA_KEY_MGMT] & 1)
ata_dev_printk(dev, KERN_WARNING,
"supports DRM functions and may "
- "not be fully accessable.\n");
+ "not be fully accessible.\n");
snprintf(revbuf, 7, "CFA");
} else {
snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
@@ -2248,7 +2248,7 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_id_has_tpm(id))
ata_dev_printk(dev, KERN_WARNING,
"supports DRM functions and may "
- "not be fully accessable.\n");
+ "not be fully accessible.\n");
}
dev->n_sectors = ata_id_n_sectors(id);
@@ -4807,9 +4807,6 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
{
struct ata_device *dev = qc->dev;
- if (ata_tag_internal(qc->tag))
- return;
-
if (ata_is_nodata(qc->tf.protocol))
return;
@@ -4858,14 +4855,23 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
- if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- /* always fill result TF for failed qc */
+ /*
+ * Finish internal commands without any further processing
+ * and always with the result TF filled.
+ */
+ if (unlikely(ata_tag_internal(qc->tag))) {
fill_result_tf(qc);
+ __ata_qc_complete(qc);
+ return;
+ }
- if (!ata_tag_internal(qc->tag))
- ata_qc_schedule_eh(qc);
- else
- __ata_qc_complete(qc);
+ /*
+ * Non-internal qc has failed. Fill the result TF and
+ * summon EH.
+ */
+ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+ fill_result_tf(qc);
+ ata_qc_schedule_eh(qc);
return;
}
@@ -6122,7 +6128,7 @@ static void ata_port_detach(struct ata_port *ap)
/* it better be dead now */
WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
- cancel_rearming_delayed_work(&ap->hotplug_task);
+ cancel_delayed_work_sync(&ap->hotplug_task);
skip_eh:
if (ap->pmp_link) {
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 5e590504f3aa..17a637877d03 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -3275,6 +3275,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
+ enum ata_lpm_policy old_policy = link->lpm_policy;
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
unsigned int err_mask;
int rc;
@@ -3338,6 +3339,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
goto fail;
}
+ /*
+ * Low level driver acked the transition. Issue DIPM command
+ * with the new policy set.
+ */
+ link->lpm_policy = policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = policy;
+
/* host config updated, enable DIPM if transitioning to MIN_POWER */
ata_for_each_dev(dev, link, ENABLED) {
if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
@@ -3353,12 +3362,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
}
}
- link->lpm_policy = policy;
- if (ap && ap->slave_link)
- ap->slave_link->lpm_policy = policy;
return 0;
fail:
+ /* restore the old policy */
+ link->lpm_policy = old_policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = old_policy;
+
/* if no device or only one more chance is left, disable LPM */
if (!dev || ehc->tries[dev->devno] <= 2) {
ata_link_printk(link, KERN_WARNING,
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index d050e073e570..5defc74973d7 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -346,12 +346,11 @@ struct device_attribute *ata_common_sdev_attrs[] = {
};
EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+static void ata_scsi_invalid_field(struct scsi_cmnd *cmd)
{
ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
- done(cmd);
+ cmd->scsi_done(cmd);
}
/**
@@ -719,7 +718,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
* @dev: ATA device to which the new command is attached
* @cmd: SCSI command that originated this ATA command
- * @done: SCSI command completion function
*
* Obtain a reference to an unused ata_queued_cmd structure,
* which is the basic libata structure representing a single
@@ -736,21 +734,20 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
* Command allocated, or %NULL if none available.
*/
static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+ struct scsi_cmnd *cmd)
{
struct ata_queued_cmd *qc;
qc = ata_qc_new_init(dev);
if (qc) {
qc->scsicmd = cmd;
- qc->scsidone = done;
+ qc->scsidone = cmd->scsi_done;
qc->sg = scsi_sglist(cmd);
qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
- done(cmd);
+ cmd->scsi_done(cmd);
}
return qc;
@@ -1735,7 +1732,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* 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
- * @done: SCSI command completion function
* @xlat_func: Actor which translates @cmd to an ATA taskfile
*
* Our ->queuecommand() function has decided that the SCSI
@@ -1759,7 +1755,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* needs to be deferred.
*/
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;
@@ -1768,7 +1763,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
VPRINTK("ENTER\n");
- qc = ata_scsi_qc_new(dev, cmd, done);
+ qc = ata_scsi_qc_new(dev, cmd);
if (!qc)
goto err_mem;
@@ -1804,14 +1799,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
early_finish:
ata_qc_free(qc);
- qc->scsidone(cmd);
+ cmd->scsi_done(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
return 0;
err_did:
ata_qc_free(qc);
cmd->result = (DID_ERROR << 16);
- qc->scsidone(cmd);
+ cmd->scsi_done(cmd);
err_mem:
DPRINTK("EXIT - internal\n");
return 0;
@@ -2552,8 +2547,11 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
*
* If door lock fails, always clear sdev->locked to
* avoid this infinite loop.
+ *
+ * This may happen before SCSI scan is complete. Make
+ * sure qc->dev->sdev isn't NULL before dereferencing.
*/
- if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+ if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
@@ -3113,7 +3111,6 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
}
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];
@@ -3147,9 +3144,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
}
if (xlat_func)
- rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+ rc = ata_scsi_translate(dev, scmd, xlat_func);
else
- ata_scsi_simulate(dev, scmd, done);
+ ata_scsi_simulate(dev, scmd);
return rc;
@@ -3157,14 +3154,14 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
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);
+ scmd->scsi_done(scmd);
return 0;
}
/**
* ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ * @shost: SCSI host of command to be sent
* @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
*
* In some cases, this function translates SCSI commands into
* ATA taskfiles, and queues the taskfiles to be sent to
@@ -3174,37 +3171,36 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
* ATA and ATAPI devices appearing as SCSI devices.
*
* LOCKING:
- * Releases scsi-layer-held lock, and obtains host lock.
+ * ATA host lock
*
* RETURNS:
* Return value from __ata_scsi_queuecmd() if @cmd can be queued,
* 0 otherwise.
*/
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
struct ata_port *ap;
struct ata_device *dev;
struct scsi_device *scsidev = cmd->device;
- struct Scsi_Host *shost = scsidev->host;
int rc = 0;
+ unsigned long irq_flags;
ap = ata_shost_to_port(shost);
- spin_unlock(shost->host_lock);
- spin_lock(ap->lock);
+ spin_lock_irqsave(ap->lock, irq_flags);
ata_scsi_dump_cdb(ap, cmd);
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
- rc = __ata_scsi_queuecmd(cmd, done, dev);
+ rc = __ata_scsi_queuecmd(cmd, dev);
else {
cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
}
- spin_unlock(ap->lock);
- spin_lock(shost->host_lock);
+ spin_unlock_irqrestore(ap->lock, irq_flags);
+
return rc;
}
@@ -3212,7 +3208,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* ata_scsi_simulate - simulate SCSI command on ATA device
* @dev: the target device
* @cmd: SCSI command being sent to device.
- * @done: SCSI command completion function.
*
* Interprets and directly executes a select list of SCSI commands
* that can be handled internally.
@@ -3221,8 +3216,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* spin_lock_irqsave(host lock)
*/
-void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
@@ -3231,17 +3225,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
args.dev = dev;
args.id = dev->id;
args.cmd = cmd;
- args.done = done;
+ args.done = cmd->scsi_done;
switch(scsicmd[0]) {
/* TODO: worth improving? */
case FORMAT_UNIT:
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
case INQUIRY:
if (scsicmd[1] & 2) /* is CmdDt set? */
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
else switch (scsicmd[2]) {
@@ -3267,7 +3261,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
break;
default:
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
}
break;
@@ -3279,7 +3273,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
case MODE_SELECT: /* unconditionally return */
case MODE_SELECT_10: /* bad-field-in-cdb */
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
case READ_CAPACITY:
@@ -3290,7 +3284,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
else
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
case REPORT_LUNS:
@@ -3300,7 +3294,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
case REQUEST_SENSE:
ata_scsi_set_sense(cmd, 0, 0, 0);
cmd->result = (DRIVER_SENSE << 24);
- done(cmd);
+ cmd->scsi_done(cmd);
break;
/* if we reach this, then writeback caching is disabled,
@@ -3322,14 +3316,14 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
else
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
/* all other commands */
default:
ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
/* "Invalid command operation code" */
- done(cmd);
+ cmd->scsi_done(cmd);
break;
}
}
@@ -3856,7 +3850,6 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
/**
* ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
* @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
* @ap: ATA port to which the command is being sent
*
* RETURNS:
@@ -3864,18 +3857,17 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
* 0 otherwise.
*/
-int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
- struct ata_port *ap)
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
{
int rc = 0;
ata_scsi_dump_cdb(ap, cmd);
if (likely(ata_dev_enabled(ap->link.device)))
- rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
+ rc = __ata_scsi_queuecmd(cmd, ap->link.device);
else {
cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
}
return rc;
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index d05387d1e14b..af6141bb1ba3 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1320,7 +1320,7 @@ void ata_sff_flush_pio_task(struct ata_port *ap)
{
DPRINTK("ENTER\n");
- cancel_rearming_delayed_work(&ap->sff_pio_task);
+ cancel_delayed_work_sync(&ap->sff_pio_task);
ap->hsm_task_state = HSM_ST_IDLE;
if (ata_msg_ctl(ap))
@@ -1532,11 +1532,10 @@ static unsigned int __ata_sff_port_intr(struct ata_port *ap,
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
return ata_sff_idle_irq(ap);
break;
- case HSM_ST:
- case HSM_ST_LAST:
- break;
- default:
+ case HSM_ST_IDLE:
return ata_sff_idle_irq(ap);
+ default:
+ break;
}
/* check main status, clearing INTRQ if needed */
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 21ee23f89e88..628c8fae5937 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -37,10 +37,22 @@
#include <linux/delay.h>
#include <linux/libata.h>
#include <scsi/scsi_host.h>
+
+#ifdef CONFIG_X86_32
#include <asm/msr.h>
+static int use_msr;
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+#else
+#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
+#undef wrmsr
+#define rdmsr(x, y, z) do { } while (0)
+#define wrmsr(x, y, z) do { } while (0)
+#define use_msr 0
+#endif
#define DRV_NAME "pata_cs5536"
-#define DRV_VERSION "0.0.7"
+#define DRV_VERSION "0.0.8"
enum {
CFG = 0,
@@ -75,8 +87,6 @@ enum {
IDE_ETC_NODMA = 0x03,
};
-static int use_msr;
-
static const u32 msr_reg[4] = {
MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
};
@@ -88,7 +98,7 @@ static const u8 pci_reg[4] = {
static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
{
if (unlikely(use_msr)) {
- u32 dummy;
+ u32 dummy __maybe_unused;
rdmsr(msr_reg[reg], *val, dummy);
return 0;
@@ -294,8 +304,6 @@ MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cs5536);
MODULE_VERSION(DRV_VERSION);
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
module_init(cs5536_init);
module_exit(cs5536_exit);
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 7688868557b9..d7e57db36bc8 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.6.8"
+#define DRV_VERSION "0.6.9"
struct hpt_clock {
u8 xfer_mode;
@@ -110,18 +110,23 @@ static const struct hpt_clock hpt366_25[] = {
{ 0, 0x01208585 }
};
-static const char *bad_ata33[] = {
- "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
- "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
- "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+static const char * const bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+ "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+ "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+ "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
"Maxtor 90510D4",
"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
- "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
- "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+ "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+ "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
NULL
};
-static const char *bad_ata66_4[] = {
+static const char * const bad_ata66_4[] = {
"IBM-DTLA-307075",
"IBM-DTLA-307060",
"IBM-DTLA-307045",
@@ -140,12 +145,13 @@ static const char *bad_ata66_4[] = {
NULL
};
-static const char *bad_ata66_3[] = {
+static const char * const bad_ata66_3[] = {
"WDC AC310200R",
NULL
};
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+ const char * const list[])
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
@@ -288,6 +294,7 @@ static struct ata_port_operations hpt366_port_ops = {
static void hpt36x_init_chipset(struct pci_dev *dev)
{
u8 drive_fast;
+
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
@@ -349,16 +356,16 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* PCI clocking determines the ATA timing values to use */
/* info_hpt366 is safe against re-entry so we can scribble on it */
- switch((reg1 & 0x700) >> 8) {
- case 9:
- hpriv = &hpt366_40;
- break;
- case 5:
- hpriv = &hpt366_25;
- break;
- default:
- hpriv = &hpt366_33;
- break;
+ switch ((reg1 & 0x700) >> 8) {
+ case 9:
+ hpriv = &hpt366_40;
+ break;
+ case 5:
+ hpriv = &hpt366_25;
+ break;
+ default:
+ hpriv = &hpt366_33;
+ break;
}
/* Now kick off ATA set up */
return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
@@ -385,9 +392,9 @@ static const struct pci_device_id hpt36x[] = {
};
static struct pci_driver hpt36x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt36x,
- .probe = hpt36x_init_one,
+ .probe = hpt36x_init_one,
.remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 9ae4c0830577..efdd18bc8663 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.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-2009 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
*
* TODO
* Look into engine reset on timeout errors. Should not be required.
@@ -24,7 +24,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.15"
+#define DRV_VERSION "0.6.18"
struct hpt_clock {
u8 xfer_speed;
@@ -210,7 +210,7 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
{
struct hpt_clock *clocks = ap->host->private_data;
- while(clocks->xfer_speed) {
+ while (clocks->xfer_speed) {
if (clocks->xfer_speed == speed)
return clocks->timing;
clocks++;
@@ -219,7 +219,8 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
return 0xffffffffU; /* silence compiler warning */
}
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+ const char * const list[])
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
@@ -237,18 +238,23 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
return 0;
}
-static const char *bad_ata33[] = {
- "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
- "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
- "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+static const char * const bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+ "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+ "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+ "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
"Maxtor 90510D4",
"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
- "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
- "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+ "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+ "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
NULL
};
-static const char *bad_ata100_5[] = {
+static const char * const bad_ata100_5[] = {
"IBM-DTLA-307075",
"IBM-DTLA-307060",
"IBM-DTLA-307045",
@@ -302,6 +308,22 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
}
/**
+ * hpt372_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: mode mask
+ *
+ * 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 unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask)
+{
+ if (ata_id_is_sata(adev->id))
+ mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
+
+ return mask;
+}
+
+/**
* hpt37x_cable_detect - Detect the cable type
* @ap: ATA port to detect on
*
@@ -373,6 +395,7 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
{ 0x50, 1, 0x04, 0x04 },
{ 0x54, 1, 0x04, 0x04 }
};
+
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
@@ -586,11 +609,11 @@ static struct ata_port_operations hpt370a_port_ops = {
};
/*
- * Configuration for HPT372, HPT371, HPT302. Slightly different PIO
- * and DMA mode setting functionality.
+ * Configuration for HPT371 and HPT302. Slightly different PIO and DMA
+ * mode setting functionality.
*/
-static struct ata_port_operations hpt372_port_ops = {
+static struct ata_port_operations hpt302_port_ops = {
.inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt37x_bmdma_stop,
@@ -602,7 +625,17 @@ static struct ata_port_operations hpt372_port_ops = {
};
/*
- * Configuration for HPT374. Mode setting works like 372 and friends
+ * Configuration for HPT372. Mode setting works like 371 and 302
+ * but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372_port_ops = {
+ .inherits = &hpt302_port_ops,
+ .mode_filter = hpt372_filter,
+};
+
+/*
+ * Configuration for HPT374. Mode setting and filtering works like 372
* but we have a different cable detection procedure for function 1.
*/
@@ -647,12 +680,12 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
u32 reg5c;
int tries;
- for(tries = 0; tries < 0x5000; tries++) {
+ for (tries = 0; tries < 0x5000; tries++) {
udelay(50);
pci_read_config_byte(dev, 0x5b, &reg5b);
if (reg5b & 0x80) {
/* See if it stays set */
- for(tries = 0; tries < 0x1000; tries ++) {
+ for (tries = 0; tries < 0x1000; tries++) {
pci_read_config_byte(dev, 0x5b, &reg5b);
/* Failed ? */
if ((reg5b & 0x80) == 0)
@@ -660,7 +693,7 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
}
/* Turn off tuning, we have the DPLL set */
pci_read_config_dword(dev, 0x5c, &reg5c);
- pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
return 1;
}
}
@@ -672,6 +705,7 @@ static u32 hpt374_read_freq(struct pci_dev *pdev)
{
u32 freq;
unsigned long io_base = pci_resource_start(pdev, 4);
+
if (PCI_FUNC(pdev->devfn) & 1) {
struct pci_dev *pdev_0;
@@ -737,23 +771,23 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA5,
.port_ops = &hpt370a_port_ops
};
- /* HPT370 - UDMA100 */
+ /* HPT370 - UDMA66 */
static const struct ata_port_info info_hpt370_33 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
+ .udma_mask = ATA_UDMA4,
.port_ops = &hpt370_port_ops
};
- /* HPT370A - UDMA100 */
+ /* HPT370A - UDMA66 */
static const struct ata_port_info info_hpt370a_33 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
+ .udma_mask = ATA_UDMA4,
.port_ops = &hpt370a_port_ops
};
- /* HPT371, 372 and friends - UDMA133 */
+ /* HPT372 - UDMA133 */
static const struct ata_port_info info_hpt372 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
@@ -761,6 +795,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA6,
.port_ops = &hpt372_port_ops
};
+ /* HPT371, 302 - UDMA133 */
+ static const struct ata_port_info info_hpt302 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &hpt302_port_ops
+ };
/* HPT374 - UDMA100, function 1 uses different prereset method */
static const struct ata_port_info info_hpt374_fn0 = {
.flags = ATA_FLAG_SLAVE_POSS,
@@ -805,64 +847,68 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (rev == 6)
return -ENODEV;
- switch(rev) {
- case 3:
- ppi[0] = &info_hpt370;
- chip_table = &hpt370;
- prefer_dpll = 0;
- break;
- case 4:
- ppi[0] = &info_hpt370a;
- chip_table = &hpt370a;
- prefer_dpll = 0;
- break;
- case 5:
- ppi[0] = &info_hpt372;
- chip_table = &hpt372;
- break;
- default:
- printk(KERN_ERR "pata_hpt37x: Unknown HPT366 "
- "subtype, please report (%d).\n", rev);
- return -ENODEV;
+ switch (rev) {
+ case 3:
+ ppi[0] = &info_hpt370;
+ chip_table = &hpt370;
+ prefer_dpll = 0;
+ break;
+ case 4:
+ ppi[0] = &info_hpt370a;
+ chip_table = &hpt370a;
+ prefer_dpll = 0;
+ break;
+ case 5:
+ ppi[0] = &info_hpt372;
+ chip_table = &hpt372;
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, "
+ "please report (%d).\n", rev);
+ return -ENODEV;
}
} else {
- switch(dev->device) {
- case PCI_DEVICE_ID_TTI_HPT372:
- /* 372N if rev >= 2*/
- if (rev >= 2)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- chip_table = &hpt372a;
- break;
- case PCI_DEVICE_ID_TTI_HPT302:
- /* 302N if rev > 1 */
- if (rev > 1)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- /* Check this */
- chip_table = &hpt302;
- break;
- case PCI_DEVICE_ID_TTI_HPT371:
- if (rev > 1)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- chip_table = &hpt371;
- /* Single channel device, master is not present
- but the BIOS (or us for non x86) must mark it
- absent */
- pci_read_config_byte(dev, 0x50, &mcr1);
- mcr1 &= ~0x04;
- pci_write_config_byte(dev, 0x50, mcr1);
- break;
- case PCI_DEVICE_ID_TTI_HPT374:
- chip_table = &hpt374;
- if (!(PCI_FUNC(dev->devfn) & 1))
- *ppi = &info_hpt374_fn0;
- else
- *ppi = &info_hpt374_fn1;
- break;
- default:
- printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
+ switch (dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2 */
+ if (rev >= 2)
+ return -ENODEV;
+ ppi[0] = &info_hpt372;
+ chip_table = &hpt372a;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev > 1 */
+ if (rev > 1)
+ return -ENODEV;
+ ppi[0] = &info_hpt302;
+ /* Check this */
+ chip_table = &hpt302;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ if (rev > 1)
+ return -ENODEV;
+ ppi[0] = &info_hpt302;
+ chip_table = &hpt371;
+ /*
+ * Single channel device, master is not present
+ * but the BIOS (or us for non x86) must mark it
+ * absent
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ mcr1 &= ~0x04;
+ pci_write_config_byte(dev, 0x50, mcr1);
+ break;
+ case PCI_DEVICE_ID_TTI_HPT374:
+ chip_table = &hpt374;
+ if (!(PCI_FUNC(dev->devfn) & 1))
+ *ppi = &info_hpt374_fn0;
+ else
+ *ppi = &info_hpt374_fn1;
+ break;
+ default:
+ printk(KERN_ERR
+ "pata_hpt37x: PCI table is bogus, please report (%d).\n",
+ dev->device);
return -ENODEV;
}
}
@@ -893,9 +939,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (chip_table == &hpt372a)
outb(0x0e, iobase + 0x9c);
- /* Some devices do not let this value be accessed via PCI space
- according to the old driver. In addition we must use the value
- from FN 0 on the HPT374 */
+ /*
+ * Some devices do not let this value be accessed via PCI space
+ * according to the old driver. In addition we must use the value
+ * from FN 0 on the HPT374.
+ */
if (chip_table == &hpt374) {
freq = hpt374_read_freq(dev);
@@ -909,10 +957,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
u8 sr;
u32 total = 0;
- printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
+ printk(KERN_WARNING
+ "pata_hpt37x: BIOS has not set timing clocks.\n");
/* This is the process the HPT371 BIOS is reported to use */
- for(i = 0; i < 128; i++) {
+ for (i = 0; i < 128; i++) {
pci_read_config_byte(dev, 0x78, &sr);
total += sr & 0x1FF;
udelay(15);
@@ -947,17 +996,22 @@ 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 | 0x100);
+ pci_write_config_dword(dev, 0x5C,
+ (f_high << 16) | f_low | 0x100);
- for(adjust = 0; adjust < 8; adjust++) {
+ for (adjust = 0; adjust < 8; adjust++) {
if (hpt37x_calibrate_dpll(dev))
break;
- /* See if it'll settle at a fractionally different clock */
+ /*
+ * See if it'll settle at a fractionally
+ * different clock
+ */
if (adjust & 1)
f_low -= adjust >> 1;
else
f_high += adjust >> 1;
- pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+ pci_write_config_dword(dev, 0x5C,
+ (f_high << 16) | f_low | 0x100);
}
if (adjust == 8) {
printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
@@ -976,7 +1030,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
* Perform a final fixup. Note that we will have used the
* DPLL on the HPT372 which means we don't have to worry
* about lack of UDMA133 support on lower clocks
- */
+ */
if (clock_slot < 2 && ppi[0] == &info_hpt370)
ppi[0] = &info_hpt370_33;
@@ -1001,9 +1055,9 @@ static const struct pci_device_id hpt37x[] = {
};
static struct pci_driver hpt37x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt37x,
- .probe = hpt37x_init_one,
+ .probe = hpt37x_init_one,
.remove = ata_pci_remove_one
};
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 32f3463216b8..d2239bbdb798 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -1,5 +1,5 @@
/*
- * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
+ * Libata driver for the HighPoint 371N, 372N, and 302N UDMA66 ATA controllers.
*
* This driver is heavily based upon:
*
@@ -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-2009 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
*
*
* TODO
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.10"
+#define DRV_VERSION "0.3.13"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -103,7 +103,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
{
struct hpt_clock *clocks = hpt3x2n_clocks;
- while(clocks->xfer_speed) {
+ while (clocks->xfer_speed) {
if (clocks->xfer_speed == speed)
return clocks->timing;
clocks++;
@@ -113,6 +113,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
}
/**
+ * hpt372n_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: mode mask
+ *
+ * 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 unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask)
+{
+ if (ata_id_is_sata(adev->id))
+ mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
+
+ return mask;
+}
+
+/**
* hpt3x2n_cable_detect - Detect the cable type
* @ap: ATA port to detect on
*
@@ -153,6 +169,7 @@ static int hpt3x2n_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);
@@ -328,10 +345,10 @@ static struct scsi_host_template hpt3x2n_sht = {
};
/*
- * Configuration for HPT3x2n.
+ * Configuration for HPT302N/371N.
*/
-static struct ata_port_operations hpt3x2n_port_ops = {
+static struct ata_port_operations hpt3xxn_port_ops = {
.inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt3x2n_bmdma_stop,
@@ -345,6 +362,15 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.prereset = hpt3x2n_pre_reset,
};
+/*
+ * Configuration for HPT372N. Same as 302N/371N but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372n_port_ops = {
+ .inherits = &hpt3xxn_port_ops,
+ .mode_filter = &hpt372n_filter,
+};
+
/**
* hpt3xn_calibrate_dpll - Calibrate the DPLL loop
* @dev: PCI device
@@ -359,12 +385,12 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
u32 reg5c;
int tries;
- for(tries = 0; tries < 0x5000; tries++) {
+ for (tries = 0; tries < 0x5000; tries++) {
udelay(50);
pci_read_config_byte(dev, 0x5b, &reg5b);
if (reg5b & 0x80) {
/* See if it stays set */
- for(tries = 0; tries < 0x1000; tries ++) {
+ for (tries = 0; tries < 0x1000; tries++) {
pci_read_config_byte(dev, 0x5b, &reg5b);
/* Failed ? */
if ((reg5b & 0x80) == 0)
@@ -372,7 +398,7 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
}
/* Turn off tuning, we have the DPLL set */
pci_read_config_dword(dev, 0x5c, &reg5c);
- pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
return 1;
}
}
@@ -388,8 +414,19 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */
if ((fcnt >> 12) != 0xABCDE) {
- printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
- return 33; /* Not BIOS set */
+ int i;
+ u16 sr;
+ u32 total = 0;
+
+ printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n");
+
+ /* This is the process the HPT371 BIOS is reported to use */
+ for (i = 0; i < 128; i++) {
+ pci_read_config_word(pdev, 0x78, &sr);
+ total += sr & 0x1FF;
+ udelay(15);
+ }
+ fcnt = total / 128;
}
fcnt &= 0x1FF;
@@ -431,21 +468,27 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
* HPT372N 9 (HPT372N) * UDMA133
*
* (1) UDMA133 support depends on the bus clock
- *
- * To pin down HPT371N
*/
static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- /* HPT372N and friends - UDMA133 */
- static const struct ata_port_info info = {
+ /* HPT372N - UDMA133 */
+ static const struct ata_port_info info_hpt372n = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &hpt372n_port_ops
+ };
+ /* HPT302N and HPT371N - UDMA133 */
+ static const struct ata_port_info info_hpt3xxn = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
- .port_ops = &hpt3x2n_port_ops
+ .port_ops = &hpt3xxn_port_ops
};
- const struct ata_port_info *ppi[] = { &info, NULL };
+ const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL };
u8 rev = dev->revision;
u8 irqmask;
unsigned int pci_mhz;
@@ -459,30 +502,36 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (rc)
return rc;
- switch(dev->device) {
- case PCI_DEVICE_ID_TTI_HPT366:
- if (rev < 6)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT371:
- if (rev < 2)
- return -ENODEV;
- /* 371N if rev > 1 */
- break;
- case PCI_DEVICE_ID_TTI_HPT372:
- /* 372N if rev >= 2*/
- if (rev < 2)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT302:
- if (rev < 2)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT372N:
- break;
- default:
- printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
+ switch (dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT366:
+ /* 372N if rev >= 6 */
+ if (rev < 6)
return -ENODEV;
+ goto hpt372n;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ /* 371N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ goto hpt372n;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372N:
+hpt372n:
+ ppi[0] = &info_hpt372n;
+ break;
+ default:
+ printk(KERN_ERR
+ "pata_hpt3x2n: PCI table is bogus please report (%d).\n",
+ dev->device);
+ return -ENODEV;
}
/* Ok so this is a chip we support */
@@ -509,8 +558,10 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_write_config_byte(dev, 0x50, mcr1);
}
- /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
- 50 for UDMA100. Right now we always use 66 */
+ /*
+ * Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
+ * 50 for UDMA100. Right now we always use 66
+ */
pci_mhz = hpt3x2n_pci_clock(dev);
@@ -522,7 +573,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_write_config_byte(dev, 0x5B, 0x21);
/* Unlike the 37x we don't try jiggling the frequency */
- for(adjust = 0; adjust < 8; adjust++) {
+ for (adjust = 0; adjust < 8; adjust++) {
if (hpt3xn_calibrate_dpll(dev))
break;
pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
@@ -534,8 +585,11 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
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 */
+
+ /*
+ * Set our private data up. We only need a few flags
+ * so we use it directly.
+ */
if (pci_mhz > 60)
hpriv = (void *)(PCI66 | USE_DPLL);
@@ -562,9 +616,9 @@ static const struct pci_device_id hpt3x2n[] = {
};
static struct pci_driver hpt3x2n_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x2n,
- .probe = hpt3x2n_init_one,
+ .probe = hpt3x2n_init_one,
.remove = ata_pci_remove_one
};
@@ -579,7 +633,7 @@ static void __exit hpt3x2n_exit(void)
}
MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3xxN");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, hpt3x2n);
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index eaf194138f21..6bd9425ba5ab 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -142,7 +142,7 @@ static int autospeed; /* Chip present which snoops speed changes */
static int pio_mask = ATA_PIO4; /* PIO range for autospeed devices */
static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
-#ifdef PATA_WINBOND_VLB_MODULE
+#ifdef CONFIG_PATA_WINBOND_VLB_MODULE
static int winbond = 1; /* Set to probe Winbond controllers,
give I/O port if non standard */
#else
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index 74b829817891..fa1b95a9a7ff 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -653,8 +653,6 @@ static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
ap = host->ports[i];
ocd = ap->dev->platform_data;
-
- ocd = ap->dev->platform_data;
cf_port = ap->private_data;
dma_int.u64 =
cvmx_read_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine));
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c21589986c69..8b677bbf2d37 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -538,7 +538,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
return 0;
}
-static void svia_configure(struct pci_dev *pdev)
+static void svia_configure(struct pci_dev *pdev, int board_id)
{
u8 tmp8;
@@ -577,7 +577,7 @@ static void svia_configure(struct pci_dev *pdev)
}
/*
- * vt6421 has problems talking to some drives. The following
+ * vt6420/1 has problems talking to some drives. The following
* is the fix from Joseph Chan <JosephChan@via.com.tw>.
*
* When host issues HOLD, device may send up to 20DW of data
@@ -596,8 +596,9 @@ static void svia_configure(struct pci_dev *pdev)
*
* https://bugzilla.kernel.org/show_bug.cgi?id=15173
* http://article.gmane.org/gmane.linux.ide/46352
+ * http://thread.gmane.org/gmane.linux.kernel/1062139
*/
- if (pdev->device == 0x3249) {
+ if (board_id == vt6420 || board_id == vt6421) {
pci_read_config_byte(pdev, 0x52, &tmp8);
tmp8 |= 1 << 2;
pci_write_config_byte(pdev, 0x52, tmp8);
@@ -652,7 +653,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- svia_configure(pdev);
+ svia_configure(pdev, board_id);
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index b777176ff494..e079cf29ed5d 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -370,7 +370,7 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
if (pci_resource_len(pdev, 0) == 0)
return -ENODEV;
- /* map IO regions and intialize host accordingly */
+ /* map IO regions and initialize host accordingly */
rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 46b94762125b..f9b983ae6877 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -154,7 +154,7 @@ static int __init adummy_init(void)
err = -ENOMEM;
goto out;
}
- atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
+ atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL);
if (!atm_dev) {
printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
err = -ENODEV;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index a33896a482e6..9f47e8625266 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1926,8 +1926,9 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
const struct firmware *fw;
unsigned long start_address;
const struct ihex_binrec *rec;
+ const char *errmsg = 0;
int res;
-
+
res = request_ihex_firmware(&fw, "atmsar11.fw", &dev->pci_dev->dev);
if (res) {
PRINTK (KERN_ERR, "Cannot load microcode data");
@@ -1937,8 +1938,8 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
/* First record contains just the start address */
rec = (const struct ihex_binrec *)fw->data;
if (be16_to_cpu(rec->len) != sizeof(__be32) || be32_to_cpu(rec->addr)) {
- PRINTK (KERN_ERR, "Bad microcode data (no start record)");
- return -EINVAL;
+ errmsg = "no start record";
+ goto fail;
}
start_address = be32_to_cpup((__be32 *)rec->data);
@@ -1950,12 +1951,12 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
PRINTD (DBG_LOAD, "starting region (%x, %u)", be32_to_cpu(rec->addr),
be16_to_cpu(rec->len));
if (be16_to_cpu(rec->len) > 4 * MAX_TRANSFER_DATA) {
- PRINTK (KERN_ERR, "Bad microcode data (record too long)");
- return -EINVAL;
+ errmsg = "record too long";
+ goto fail;
}
if (be16_to_cpu(rec->len) & 3) {
- PRINTK (KERN_ERR, "Bad microcode data (odd number of bytes)");
- return -EINVAL;
+ errmsg = "odd number of bytes";
+ goto fail;
}
res = loader_write(lb, dev, rec);
if (res)
@@ -1970,6 +1971,10 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
res = loader_start(lb, dev, start_address);
return res;
+fail:
+ release_firmware(fw);
+ PRINTK(KERN_ERR, "Bad microcode data (%s)", errmsg);
+ return -EINVAL;
}
/********** give adapter parameters **********/
@@ -2244,7 +2249,8 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
goto out_reset;
}
- dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &pci_dev->dev, &amb_ops, -1,
+ NULL);
if (!dev->atm_dev) {
PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
err = -EINVAL;
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index b9101818b47b..0b0625054a87 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -366,7 +366,7 @@ static int atmtcp_create(int itf,int persist,struct atm_dev **result)
if (!dev_data)
return -ENOMEM;
- dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
+ dev = atm_dev_register(DEV_LABEL,NULL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
return itf == -1 ? -ENOMEM : -EBUSY;
@@ -392,7 +392,10 @@ static int atmtcp_attach(struct atm_vcc *vcc,int itf)
atm_dev_put(dev);
return -EMEDIUMTYPE;
}
- if (PRIV(dev)->vcc) return -EBUSY;
+ if (PRIV(dev)->vcc) {
+ atm_dev_put(dev);
+ return -EBUSY;
+ }
}
else {
int error;
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 97c5898cd76e..c495fae74200 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2244,7 +2244,7 @@ static int __devinit eni_init_one(struct pci_dev *pci_dev,
&zeroes);
if (!cpu_zeroes) goto out1;
}
- dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+ dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
if (!dev) goto out2;
pci_set_drvdata(pci_dev, dev);
eni_dev->pci_dev = pci_dev;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 5d86bb803e94..7d912baf01d4 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1911,7 +1911,7 @@ static int __devinit firestream_init_one (struct pci_dev *pci_dev,
fs_dev, sizeof (struct fs_dev));
if (!fs_dev)
goto err_out;
- atm_dev = atm_dev_register("fs", &ops, -1, NULL);
+ atm_dev = atm_dev_register("fs", &pci_dev->dev, &ops, -1, NULL);
if (!atm_dev)
goto err_out_free_fs_dev;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index c8fc69c85a06..44f778507770 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -92,7 +92,7 @@
#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ])
-#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo))
+#define FORE200E_NEXT_ENTRY(index, modulo) (index = ((index) + 1) % (modulo))
#if 1
#define ASSERT(expr) if (!(expr)) { \
@@ -2567,14 +2567,14 @@ release:
static int __devinit
-fore200e_register(struct fore200e* fore200e)
+fore200e_register(struct fore200e* fore200e, struct device *parent)
{
struct atm_dev* atm_dev;
DPRINTK(2, "device %s being registered\n", fore200e->name);
- atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
- NULL);
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, parent, &fore200e_ops,
+ -1, NULL);
if (atm_dev == NULL) {
printk(FORE200E "unable to register device %s\n", fore200e->name);
return -ENODEV;
@@ -2594,9 +2594,9 @@ fore200e_register(struct fore200e* fore200e)
static int __devinit
-fore200e_init(struct fore200e* fore200e)
+fore200e_init(struct fore200e* fore200e, struct device *parent)
{
- if (fore200e_register(fore200e) < 0)
+ if (fore200e_register(fore200e, parent) < 0)
return -ENODEV;
if (fore200e->bus->configure(fore200e) < 0)
@@ -2662,7 +2662,7 @@ static int __devinit fore200e_sba_probe(struct platform_device *op,
sprintf(fore200e->name, "%s-%d", bus->model_name, index);
- err = fore200e_init(fore200e);
+ err = fore200e_init(fore200e, &op->dev);
if (err < 0) {
fore200e_shutdown(fore200e);
kfree(fore200e);
@@ -2740,7 +2740,7 @@ fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent
sprintf(fore200e->name, "%s-%d", bus->model_name, index);
- err = fore200e_init(fore200e);
+ err = fore200e_init(fore200e, &pci_dev->dev);
if (err < 0) {
fore200e_shutdown(fore200e);
goto out_free;
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 801e8b6e9d1f..6cf59bf281dc 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -366,7 +366,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
goto init_one_failure;
}
- atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, NULL);
+ atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL);
if (!atm_dev) {
err = -ENODEV;
goto init_one_failure;
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index a95790452a68..24761e1d6642 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -2733,7 +2733,8 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_
PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
iobase, irq, membase);
- dev->atm_dev = atm_dev_register(DEV_LABEL, &hrz_ops, -1, NULL);
+ dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1,
+ NULL);
if (!(dev->atm_dev)) {
PRINTD(DBG_ERR, "failed to register Madge ATM adapter");
err = -EINVAL;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index bce57328ddde..bfb7feee0400 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3698,7 +3698,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
goto err_out_iounmap;
}
- dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL);
+ dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1,
+ NULL);
if (!dev) {
printk("%s: can't register atm device\n", card->name);
err = -EIO;
diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h
index 5042bb2dab15..f53a43ae2bbe 100644
--- a/drivers/atm/idt77252.h
+++ b/drivers/atm/idt77252.h
@@ -572,7 +572,7 @@ struct idt77252_dev
#define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */
#define SAR_STAT_TMROF 0x00000800 /* Timer overflow */
#define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */
-#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Comand Busy Flag */
+#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Command Busy Flag */
#define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */
#define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */
#define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 9309d4724e13..d80d51b62a1a 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2063,7 +2063,7 @@ static int tx_init(struct atm_dev *dev)
- UBR Table size is 4K
- UBR wait queue is 4K
since the table and wait queues are contiguous, all the bytes
- can be initialized by one memeset.
+ can be initialized by one memeset.
*/
vcsize_sel = 0;
@@ -2089,7 +2089,7 @@ static int tx_init(struct atm_dev *dev)
- ABR Table size is 2K
- ABR wait queue is 2K
since the table and wait queues are contiguous, all the bytes
- can be intialized by one memeset.
+ can be initialized by one memeset.
*/
i = ABR_SCHED_TABLE * iadev->memSize;
writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE);
@@ -3172,7 +3172,7 @@ static int __devinit ia_init_one(struct pci_dev *pdev,
ret = -ENODEV;
goto err_out_free_iadev;
}
- dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ dev = atm_dev_register(DEV_LABEL, &pdev->dev, &ops, -1, NULL);
if (!dev) {
ret = -ENOMEM;
goto err_out_disable_dev;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index cbe15a86c669..52880c8387d8 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -2241,11 +2241,8 @@ static int __devinit lanai_dev_open(struct atm_dev *atmdev)
memcpy(atmdev->esi, eeprom_mac(lanai), ESI_LEN);
lanai_timed_poll_start(lanai);
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=0x%lx, irq=%u "
- "(%02X-%02X-%02X-%02X-%02X-%02X)\n", lanai->number,
- (int) lanai->pci->revision, (unsigned long) lanai->base,
- lanai->pci->irq,
- atmdev->esi[0], atmdev->esi[1], atmdev->esi[2],
- atmdev->esi[3], atmdev->esi[4], atmdev->esi[5]);
+ "(%pMF)\n", lanai->number, (int) lanai->pci->revision,
+ (unsigned long) lanai->base, lanai->pci->irq, atmdev->esi);
printk(KERN_NOTICE DEV_LABEL "(itf %d): LANAI%s, serialno=%u(0x%X), "
"board_rev=%d\n", lanai->number,
lanai->type==lanai2 ? "2" : "HB", (unsigned int) lanai->serialno,
@@ -2591,7 +2588,7 @@ static int __devinit lanai_init_one(struct pci_dev *pci,
return -ENOMEM;
}
- atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ atmdev = atm_dev_register(DEV_LABEL, &pci->dev, &ops, -1, NULL);
if (atmdev == NULL) {
printk(KERN_ERR DEV_LABEL
": couldn't register atm device!\n");
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 2f3516b7f118..6b313ee9231b 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -771,7 +771,8 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
}
/* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+ card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops,
+ -1, NULL);
if (card->atmdev == NULL) {
printk("nicstar%d: can't register device.\n", i);
error = 17;
diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c
index 1a9332e4efe0..9a676ee30824 100644
--- a/drivers/atm/solos-attrlist.c
+++ b/drivers/atm/solos-attrlist.c
@@ -1,6 +1,7 @@
SOLOS_ATTR_RO(DriverVersion)
SOLOS_ATTR_RO(APIVersion)
SOLOS_ATTR_RO(FirmwareVersion)
+SOLOS_ATTR_RO(Version)
// SOLOS_ATTR_RO(DspVersion)
// SOLOS_ATTR_RO(CommonHandshake)
SOLOS_ATTR_RO(Connected)
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index f46138ab38b6..73fb1c4f4cd4 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -166,7 +166,7 @@ static irqreturn_t solos_irq(int irq, void *dev_id);
static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
static int list_vccs(int vci);
static void release_vccs(struct atm_dev *dev);
-static int atm_init(struct solos_card *);
+static int atm_init(struct solos_card *, struct device *);
static void atm_remove(struct solos_card *);
static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
static void solos_bh(unsigned long);
@@ -1161,6 +1161,14 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
major_ver, minor_ver, fpga_ver);
+ if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade ||
+ db_fpga_upgrade || db_firmware_upgrade)) {
+ dev_warn(&dev->dev,
+ "FPGA too old; cannot upgrade flash. Use JTAG.\n");
+ fpga_upgrade = firmware_upgrade = 0;
+ db_fpga_upgrade = db_firmware_upgrade = 0;
+ }
+
if (card->fpga_version >= DMA_SUPPORTED){
card->using_dma = 1;
} else {
@@ -1202,7 +1210,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (db_firmware_upgrade)
flash_upgrade(card, 3);
- err = atm_init(card);
+ err = atm_init(card, &dev->dev);
if (err)
goto out_free_irq;
@@ -1225,7 +1233,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
return err;
}
-static int atm_init(struct solos_card *card)
+static int atm_init(struct solos_card *card, struct device *parent)
{
int i;
@@ -1236,7 +1244,7 @@ static int atm_init(struct solos_card *card)
skb_queue_head_init(&card->tx_queue[i]);
skb_queue_head_init(&card->cli_queue[i]);
- card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL);
+ card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL);
if (!card->atmdev[i]) {
dev_err(&card->dev->dev, "Could not register ATM device %d\n", i);
atm_remove(card);
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 4e885d2da49c..624917902b65 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1597,7 +1597,7 @@ static int __devinit zatm_init_one(struct pci_dev *pci_dev,
goto out;
}
- dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+ dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
if (!dev)
goto out_free;
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 2ca7f5b7b824..19f49e41ce5d 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -1,31 +1,46 @@
/**
- * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
+ * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
*
- * @subsys - the struct kset that defines this bus. This is the main kobject
- * @drivers_kset - the list of drivers associated with this bus
- * @devices_kset - the list of devices associated with this bus
+ * @subsys - the struct kset that defines this subsystem
+ * @devices_kset - the list of devices associated
+ *
+ * @drivers_kset - the list of drivers associated
* @klist_devices - the klist to iterate over the @devices_kset
* @klist_drivers - the klist to iterate over the @drivers_kset
* @bus_notifier - the bus notifier list for anything that cares about things
- * on this bus.
+ * on this bus.
* @bus - pointer back to the struct bus_type that this structure is associated
- * with.
+ * with.
+ *
+ * @class_interfaces - list of class_interfaces associated
+ * @glue_dirs - "glue" directory to put in-between the parent device to
+ * avoid namespace conflicts
+ * @class_mutex - mutex to protect the children, devices, and interfaces lists.
+ * @class - pointer back to the struct class that this structure is associated
+ * with.
*
* This structure is the one that is the actual kobject allowing struct
- * bus_type to be statically allocated safely. Nothing outside of the driver
- * core should ever touch these fields.
+ * bus_type/class to be statically allocated safely. Nothing outside of the
+ * driver core should ever touch these fields.
*/
-struct bus_type_private {
+struct subsys_private {
struct kset subsys;
- struct kset *drivers_kset;
struct kset *devices_kset;
+
+ struct kset *drivers_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
+
+ struct list_head class_interfaces;
+ struct kset glue_dirs;
+ struct mutex class_mutex;
+ struct class *class;
};
+#define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj)
struct driver_private {
struct kobject kobj;
@@ -36,33 +51,6 @@ struct driver_private {
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)
-
-/**
- * struct class_private - structure to hold the private to the driver core portions of the class structure.
- *
- * @class_subsys - the struct kset that defines this class. This is the main kobject
- * @class_devices - list of devices associated with this class
- * @class_interfaces - list of class_interfaces associated with this class
- * @class_dirs - "glue" directory for virtual devices associated with this class
- * @class_mutex - mutex to protect the children, devices, and interfaces lists.
- * @class - pointer back to the struct class that this structure is associated
- * with.
- *
- * This structure is the one that is the actual kobject allowing struct
- * class to be statically allocated safely. Nothing outside of the driver
- * core should ever touch these fields.
- */
-struct class_private {
- struct kset class_subsys;
- struct klist class_devices;
- struct list_head class_interfaces;
- struct kset class_dirs;
- struct mutex class_mutex;
- struct class *class;
-};
-#define to_class(obj) \
- container_of(obj, struct class_private, class_subsys.kobj)
-
/**
* struct device_private - structure to hold the private to the driver core portions of the device structure.
*
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 33c270a64db7..000e7b2006f8 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -20,7 +20,6 @@
#include "power/power.h"
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)
/*
* sysfs bindings for drivers
@@ -96,11 +95,11 @@ static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
- struct bus_type_private *bus_priv = to_bus(kobj);
+ struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0;
if (bus_attr->show)
- ret = bus_attr->show(bus_priv->bus, buf);
+ ret = bus_attr->show(subsys_priv->bus, buf);
return ret;
}
@@ -108,11 +107,11 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
- struct bus_type_private *bus_priv = to_bus(kobj);
+ struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0;
if (bus_attr->store)
- ret = bus_attr->store(bus_priv->bus, buf, count);
+ ret = bus_attr->store(subsys_priv->bus, buf, count);
return ret;
}
@@ -858,9 +857,9 @@ static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
int bus_register(struct bus_type *bus)
{
int retval;
- struct bus_type_private *priv;
+ struct subsys_private *priv;
- priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
+ priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -976,7 +975,7 @@ struct klist *bus_get_device_klist(struct bus_type *bus)
EXPORT_SYMBOL_GPL(bus_get_device_klist);
/*
- * Yes, this forcably breaks the klist abstraction temporarily. It
+ * Yes, this forcibly breaks the klist abstraction temporarily. It
* just wants to sort the klist, not change reference counts and
* take/drop locks rapidly in the process. It does all this while
* holding the lock for the list, so objects can't otherwise be
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 9c63a5687d69..4f1df2e8fd74 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -27,7 +27,7 @@ static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct class_attribute *class_attr = to_class_attr(attr);
- struct class_private *cp = to_class(kobj);
+ struct subsys_private *cp = to_subsys_private(kobj);
ssize_t ret = -EIO;
if (class_attr->show)
@@ -39,7 +39,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct class_attribute *class_attr = to_class_attr(attr);
- struct class_private *cp = to_class(kobj);
+ struct subsys_private *cp = to_subsys_private(kobj);
ssize_t ret = -EIO;
if (class_attr->store)
@@ -49,7 +49,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
static void class_release(struct kobject *kobj)
{
- struct class_private *cp = to_class(kobj);
+ struct subsys_private *cp = to_subsys_private(kobj);
struct class *class = cp->class;
pr_debug("class '%s': release.\n", class->name);
@@ -65,7 +65,7 @@ static void class_release(struct kobject *kobj)
static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj)
{
- struct class_private *cp = to_class(kobj);
+ struct subsys_private *cp = to_subsys_private(kobj);
struct class *class = cp->class;
return class->ns_type;
@@ -82,7 +82,7 @@ static struct kobj_type class_ktype = {
.child_ns_type = class_child_ns_type,
};
-/* Hotplug events for classes go to the class class_subsys */
+/* Hotplug events for classes go to the class subsys */
static struct kset *class_kset;
@@ -90,7 +90,7 @@ int class_create_file(struct class *cls, const struct class_attribute *attr)
{
int error;
if (cls)
- error = sysfs_create_file(&cls->p->class_subsys.kobj,
+ error = sysfs_create_file(&cls->p->subsys.kobj,
&attr->attr);
else
error = -EINVAL;
@@ -100,20 +100,20 @@ int class_create_file(struct class *cls, const struct class_attribute *attr)
void class_remove_file(struct class *cls, const struct class_attribute *attr)
{
if (cls)
- sysfs_remove_file(&cls->p->class_subsys.kobj, &attr->attr);
+ sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr);
}
static struct class *class_get(struct class *cls)
{
if (cls)
- kset_get(&cls->p->class_subsys);
+ kset_get(&cls->p->subsys);
return cls;
}
static void class_put(struct class *cls)
{
if (cls)
- kset_put(&cls->p->class_subsys);
+ kset_put(&cls->p->subsys);
}
static int add_class_attrs(struct class *cls)
@@ -162,7 +162,7 @@ static void klist_class_dev_put(struct klist_node *n)
int __class_register(struct class *cls, struct lock_class_key *key)
{
- struct class_private *cp;
+ struct subsys_private *cp;
int error;
pr_debug("device class '%s': registering\n", cls->name);
@@ -170,11 +170,11 @@ int __class_register(struct class *cls, struct lock_class_key *key)
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
return -ENOMEM;
- klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
+ klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
INIT_LIST_HEAD(&cp->class_interfaces);
- kset_init(&cp->class_dirs);
+ kset_init(&cp->glue_dirs);
__mutex_init(&cp->class_mutex, "struct class mutex", key);
- error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
+ error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
if (error) {
kfree(cp);
return error;
@@ -187,15 +187,15 @@ int __class_register(struct class *cls, struct lock_class_key *key)
#if defined(CONFIG_BLOCK)
/* let the block class directory show up in the root of sysfs */
if (!sysfs_deprecated || cls != &block_class)
- cp->class_subsys.kobj.kset = class_kset;
+ cp->subsys.kobj.kset = class_kset;
#else
- cp->class_subsys.kobj.kset = class_kset;
+ cp->subsys.kobj.kset = class_kset;
#endif
- cp->class_subsys.kobj.ktype = &class_ktype;
+ cp->subsys.kobj.ktype = &class_ktype;
cp->class = cls;
cls->p = cp;
- error = kset_register(&cp->class_subsys);
+ error = kset_register(&cp->subsys);
if (error) {
kfree(cp);
return error;
@@ -210,7 +210,7 @@ void class_unregister(struct class *cls)
{
pr_debug("device class '%s': unregistering\n", cls->name);
remove_class_attrs(cls);
- kset_unregister(&cls->p->class_subsys);
+ kset_unregister(&cls->p->subsys);
}
static void class_create_release(struct class *cls)
@@ -295,7 +295,7 @@ void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
if (start)
start_knode = &start->knode_class;
- klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode);
+ klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode);
iter->type = type;
}
EXPORT_SYMBOL_GPL(class_dev_iter_init);
@@ -482,8 +482,8 @@ void class_interface_unregister(struct class_interface *class_intf)
class_put(parent);
}
-ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr,
- char *buf)
+ssize_t show_class_attr_string(struct class *class,
+ struct class_attribute *attr, char *buf)
{
struct class_attribute_string *cs;
cs = container_of(attr, struct class_attribute_string, attr);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 6ed645411c40..080e9ca11017 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -338,6 +338,35 @@ static void device_remove_attributes(struct device *dev,
device_remove_file(dev, &attrs[i]);
}
+static int device_add_bin_attributes(struct device *dev,
+ struct bin_attribute *attrs)
+{
+ int error = 0;
+ int i;
+
+ if (attrs) {
+ for (i = 0; attr_name(attrs[i]); i++) {
+ error = device_create_bin_file(dev, &attrs[i]);
+ if (error)
+ break;
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_bin_file(dev, &attrs[i]);
+ }
+ return error;
+}
+
+static void device_remove_bin_attributes(struct device *dev,
+ struct bin_attribute *attrs)
+{
+ int i;
+
+ if (attrs)
+ for (i = 0; attr_name(attrs[i]); i++)
+ device_remove_bin_file(dev, &attrs[i]);
+}
+
static int device_add_groups(struct device *dev,
const struct attribute_group **groups)
{
@@ -378,12 +407,15 @@ static int device_add_attrs(struct device *dev)
error = device_add_attributes(dev, class->dev_attrs);
if (error)
return error;
+ error = device_add_bin_attributes(dev, class->dev_bin_attrs);
+ if (error)
+ goto err_remove_class_attrs;
}
if (type) {
error = device_add_groups(dev, type->groups);
if (error)
- goto err_remove_class_attrs;
+ goto err_remove_class_bin_attrs;
}
error = device_add_groups(dev, dev->groups);
@@ -395,6 +427,9 @@ static int device_add_attrs(struct device *dev)
err_remove_type_groups:
if (type)
device_remove_groups(dev, type->groups);
+ err_remove_class_bin_attrs:
+ if (class)
+ device_remove_bin_attributes(dev, class->dev_bin_attrs);
err_remove_class_attrs:
if (class)
device_remove_attributes(dev, class->dev_attrs);
@@ -412,8 +447,10 @@ static void device_remove_attrs(struct device *dev)
if (type)
device_remove_groups(dev, type->groups);
- if (class)
+ if (class) {
device_remove_attributes(dev, class->dev_attrs);
+ device_remove_bin_attributes(dev, class->dev_bin_attrs);
+ }
}
@@ -610,7 +647,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
dir->class = class;
kobject_init(&dir->kobj, &class_dir_ktype);
- dir->kobj.kset = &class->p->class_dirs;
+ dir->kobj.kset = &class->p->glue_dirs;
retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
if (retval < 0) {
@@ -635,7 +672,7 @@ static struct kobject *get_device_parent(struct device *dev,
if (sysfs_deprecated && dev->class == &block_class) {
if (parent && parent->class == &block_class)
return &parent->kobj;
- return &block_class.p->class_subsys.kobj;
+ return &block_class.p->subsys.kobj;
}
#endif
@@ -654,13 +691,13 @@ static struct kobject *get_device_parent(struct device *dev,
mutex_lock(&gdp_mutex);
/* find our class-directory at the parent and reference it */
- spin_lock(&dev->class->p->class_dirs.list_lock);
- list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
+ spin_lock(&dev->class->p->glue_dirs.list_lock);
+ list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry)
if (k->parent == parent_kobj) {
kobj = kobject_get(k);
break;
}
- spin_unlock(&dev->class->p->class_dirs.list_lock);
+ spin_unlock(&dev->class->p->glue_dirs.list_lock);
if (kobj) {
mutex_unlock(&gdp_mutex);
return kobj;
@@ -682,7 +719,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
{
/* see if we live in a "glue" directory */
if (!glue_dir || !dev->class ||
- glue_dir->kset != &dev->class->p->class_dirs)
+ glue_dir->kset != &dev->class->p->glue_dirs)
return;
kobject_put(glue_dir);
@@ -709,7 +746,7 @@ static int device_add_class_symlinks(struct device *dev)
return 0;
error = sysfs_create_link(&dev->kobj,
- &dev->class->p->class_subsys.kobj,
+ &dev->class->p->subsys.kobj,
"subsystem");
if (error)
goto out;
@@ -728,7 +765,7 @@ static int device_add_class_symlinks(struct device *dev)
#endif
/* link in the class directory pointing to the device */
- error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
+ error = sysfs_create_link(&dev->class->p->subsys.kobj,
&dev->kobj, dev_name(dev));
if (error)
goto out_device;
@@ -756,7 +793,7 @@ static void device_remove_class_symlinks(struct device *dev)
if (sysfs_deprecated && dev->class == &block_class)
return;
#endif
- sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
+ sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
}
/**
@@ -947,7 +984,7 @@ int device_add(struct device *dev)
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
- &dev->class->p->class_devices);
+ &dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
@@ -1513,6 +1550,8 @@ EXPORT_SYMBOL_GPL(device_destroy);
* exclusion between two different calls of device_rename
* on the same device to ensure that new_name is valid and
* won't conflict with other devices.
+ *
+ * "Never use this function, bad things will happen" - gregkh
*/
int device_rename(struct device *dev, const char *new_name)
{
@@ -1535,7 +1574,7 @@ int device_rename(struct device *dev, const char *new_name)
}
if (dev->class) {
- error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
+ error = sysfs_rename_link(&dev->class->p->subsys.kobj,
&dev->kobj, old_device_name, new_name);
if (error)
goto out;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index ce012a9c6201..36b43052001d 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -117,12 +117,21 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
"Node %d WritebackTmp: %8lu kB\n"
"Node %d Slab: %8lu kB\n"
"Node %d SReclaimable: %8lu kB\n"
- "Node %d SUnreclaim: %8lu kB\n",
+ "Node %d SUnreclaim: %8lu kB\n"
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ "Node %d AnonHugePages: %8lu kB\n"
+#endif
+ ,
nid, K(node_page_state(nid, NR_FILE_DIRTY)),
nid, K(node_page_state(nid, NR_WRITEBACK)),
nid, K(node_page_state(nid, NR_FILE_PAGES)),
nid, K(node_page_state(nid, NR_FILE_MAPPED)),
- nid, K(node_page_state(nid, NR_ANON_PAGES)),
+ nid, K(node_page_state(nid, NR_ANON_PAGES)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
+ HPAGE_PMD_NR
+#endif
+ ),
nid, K(node_page_state(nid, NR_SHMEM)),
nid, node_page_state(nid, NR_KERNEL_STACK) *
THREAD_SIZE / 1024,
@@ -133,7 +142,13 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
- nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
+ nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ , nid,
+ K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
+ HPAGE_PMD_NR)
+#endif
+ );
n += hugetlb_report_node_meminfo(nid, buf + n);
return n;
}
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index 81f2c84697f4..42f97f925629 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
*
* If PM operations are defined for the @dev's driver and they include
* ->runtime_suspend(), execute it and return its error code. Otherwise,
- * return -EINVAL.
+ * return 0.
*/
int pm_generic_runtime_suspend(struct device *dev)
{
@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend);
*
* If PM operations are defined for the @dev's driver and they include
* ->runtime_resume(), execute it and return its error code. Otherwise,
- * return -EINVAL.
+ * return 0.
*/
int pm_generic_runtime_resume(struct device *dev)
{
@@ -185,7 +185,7 @@ static int __pm_generic_resume(struct device *dev, int event)
return 0;
ret = callback(dev);
- if (!ret) {
+ if (!ret && pm_runtime_enabled(dev)) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 31b526661ec4..83404973f97a 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -8,7 +8,7 @@
*
*
* The driver model core calls device_pm_add() when a device is registered.
- * This will intialize the embedded device_pm_info object in the device
+ * This will initialize the embedded device_pm_info object in the device
* and add it to the list of power-controlled devices. sysfs entries for
* controlling device power management will also be added.
*
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/async.h>
+#include <linux/suspend.h>
#include "../base.h"
#include "power.h"
@@ -41,16 +42,13 @@
*/
LIST_HEAD(dpm_list);
+LIST_HEAD(dpm_prepared_list);
+LIST_HEAD(dpm_suspended_list);
+LIST_HEAD(dpm_noirq_list);
static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;
-/*
- * Set once the preparation of devices for a PM transition has started, reset
- * before starting to resume devices. Protected by dpm_list_mtx.
- */
-static bool transition_started;
-
static int async_error;
/**
@@ -59,7 +57,7 @@ static int async_error;
*/
void device_pm_init(struct device *dev)
{
- dev->power.status = DPM_ON;
+ dev->power.in_suspend = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
@@ -90,22 +88,11 @@ void device_pm_unlock(void)
void device_pm_add(struct device *dev)
{
pr_debug("PM: Adding info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
+ dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
mutex_lock(&dpm_list_mtx);
- if (dev->parent) {
- if (dev->parent->power.status >= DPM_SUSPENDING)
- dev_warn(dev, "parent %s should not be sleeping\n",
- dev_name(dev->parent));
- } else if (transition_started) {
- /*
- * We refuse to register parentless devices while a PM
- * transition is in progress in order to avoid leaving them
- * unhandled down the road
- */
- dev_WARN(dev, "Parentless device registered during a PM transaction\n");
- }
-
+ if (dev->parent && dev->parent->power.in_suspend)
+ dev_warn(dev, "parent %s should not be sleeping\n",
+ dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
mutex_unlock(&dpm_list_mtx);
}
@@ -117,8 +104,7 @@ void device_pm_add(struct device *dev)
void device_pm_remove(struct device *dev)
{
pr_debug("PM: Removing info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
+ dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
@@ -135,10 +121,8 @@ void device_pm_remove(struct device *dev)
void device_pm_move_before(struct device *deva, struct device *devb)
{
pr_debug("PM: Moving %s:%s before %s:%s\n",
- deva->bus ? deva->bus->name : "No Bus",
- kobject_name(&deva->kobj),
- devb->bus ? devb->bus->name : "No Bus",
- kobject_name(&devb->kobj));
+ deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
+ devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
/* Delete deva from dpm_list and reinsert before devb. */
list_move_tail(&deva->power.entry, &devb->power.entry);
}
@@ -151,10 +135,8 @@ void device_pm_move_before(struct device *deva, struct device *devb)
void device_pm_move_after(struct device *deva, struct device *devb)
{
pr_debug("PM: Moving %s:%s after %s:%s\n",
- deva->bus ? deva->bus->name : "No Bus",
- kobject_name(&deva->kobj),
- devb->bus ? devb->bus->name : "No Bus",
- kobject_name(&devb->kobj));
+ deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
+ devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
/* Delete deva from dpm_list and reinsert after devb. */
list_move(&deva->power.entry, &devb->power.entry);
}
@@ -166,8 +148,7 @@ void device_pm_move_after(struct device *deva, struct device *devb)
void device_pm_move_last(struct device *dev)
{
pr_debug("PM: Moving %s:%s to end of list\n",
- dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
+ dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
list_move_tail(&dev->power.entry, &dpm_list);
}
@@ -303,7 +284,7 @@ static int pm_noirq_op(struct device *dev,
pm_message_t state)
{
int error = 0;
- ktime_t calltime, delta, rettime;
+ ktime_t calltime = ktime_set(0, 0), delta, rettime;
if (initcall_debug) {
pr_info("calling %s+ @ %i, parent: %s\n",
@@ -405,7 +386,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
int error)
{
printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n",
- kobject_name(&dev->kobj), pm_verb(state.event), info, error);
+ dev_name(dev), pm_verb(state.event), info, error);
}
static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
@@ -475,20 +456,24 @@ End:
*/
void dpm_resume_noirq(pm_message_t state)
{
- struct device *dev;
ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
- transition_started = false;
- list_for_each_entry(dev, &dpm_list, power.entry)
- if (dev->power.status > DPM_OFF) {
- int error;
+ while (!list_empty(&dpm_noirq_list)) {
+ struct device *dev = to_device(dpm_noirq_list.next);
+ int error;
- dev->power.status = DPM_OFF;
- error = device_resume_noirq(dev, state);
- if (error)
- pm_dev_err(dev, state, " early", error);
- }
+ get_device(dev);
+ list_move_tail(&dev->power.entry, &dpm_suspended_list);
+ mutex_unlock(&dpm_list_mtx);
+
+ error = device_resume_noirq(dev, state);
+ if (error)
+ pm_dev_err(dev, state, " early", error);
+
+ mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+ }
mutex_unlock(&dpm_list_mtx);
dpm_show_time(starttime, state, "early");
resume_device_irqs();
@@ -531,7 +516,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
dpm_wait(dev->parent, async);
device_lock(dev);
- dev->power.status = DPM_RESUMING;
+ dev->power.in_suspend = false;
if (dev->bus) {
if (dev->bus->pm) {
@@ -597,19 +582,14 @@ static bool is_async(struct device *dev)
*/
static void dpm_resume(pm_message_t state)
{
- struct list_head list;
struct device *dev;
ktime_t starttime = ktime_get();
- INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
- list_for_each_entry(dev, &dpm_list, power.entry) {
- if (dev->power.status < DPM_OFF)
- continue;
-
+ list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
INIT_COMPLETION(dev->power.completion);
if (is_async(dev)) {
get_device(dev);
@@ -617,28 +597,24 @@ static void dpm_resume(pm_message_t state)
}
}
- while (!list_empty(&dpm_list)) {
- dev = to_device(dpm_list.next);
+ while (!list_empty(&dpm_suspended_list)) {
+ dev = to_device(dpm_suspended_list.next);
get_device(dev);
- if (dev->power.status >= DPM_OFF && !is_async(dev)) {
+ if (!is_async(dev)) {
int error;
mutex_unlock(&dpm_list_mtx);
error = device_resume(dev, state, false);
-
- mutex_lock(&dpm_list_mtx);
if (error)
pm_dev_err(dev, state, "", error);
- } else if (dev->power.status == DPM_SUSPENDING) {
- /* Allow new children of the device to be registered */
- dev->power.status = DPM_RESUMING;
+
+ mutex_lock(&dpm_list_mtx);
}
if (!list_empty(&dev->power.entry))
- list_move_tail(&dev->power.entry, &list);
+ list_move_tail(&dev->power.entry, &dpm_prepared_list);
put_device(dev);
}
- list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
dpm_show_time(starttime, state, NULL);
@@ -684,22 +660,18 @@ static void dpm_complete(pm_message_t state)
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
- transition_started = false;
- while (!list_empty(&dpm_list)) {
- struct device *dev = to_device(dpm_list.prev);
+ while (!list_empty(&dpm_prepared_list)) {
+ struct device *dev = to_device(dpm_prepared_list.prev);
get_device(dev);
- if (dev->power.status > DPM_ON) {
- dev->power.status = DPM_ON;
- mutex_unlock(&dpm_list_mtx);
+ dev->power.in_suspend = false;
+ list_move(&dev->power.entry, &list);
+ mutex_unlock(&dpm_list_mtx);
- device_complete(dev, state);
- pm_runtime_put_sync(dev);
+ device_complete(dev, state);
+ pm_runtime_put_sync(dev);
- mutex_lock(&dpm_list_mtx);
- }
- if (!list_empty(&dev->power.entry))
- list_move(&dev->power.entry, &list);
+ mutex_lock(&dpm_list_mtx);
put_device(dev);
}
list_splice(&list, &dpm_list);
@@ -789,19 +761,28 @@ End:
*/
int dpm_suspend_noirq(pm_message_t state)
{
- struct device *dev;
ktime_t starttime = ktime_get();
int error = 0;
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
- list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
+ while (!list_empty(&dpm_suspended_list)) {
+ struct device *dev = to_device(dpm_suspended_list.prev);
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+
error = device_suspend_noirq(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " late", error);
+ put_device(dev);
break;
}
- dev->power.status = DPM_OFF_IRQ;
+ if (!list_empty(&dev->power.entry))
+ list_move(&dev->power.entry, &dpm_noirq_list);
+ put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
if (error)
@@ -850,6 +831,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (async_error)
goto End;
+ if (pm_wakeup_pending()) {
+ async_error = -EBUSY;
+ goto End;
+ }
+
if (dev->class) {
if (dev->class->pm) {
pm_dev_dbg(dev, state, "class ");
@@ -881,9 +867,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
}
}
- if (!error)
- dev->power.status = DPM_OFF;
-
End:
device_unlock(dev);
complete_all(&dev->power.completion);
@@ -925,16 +908,14 @@ static int device_suspend(struct device *dev)
*/
static int dpm_suspend(pm_message_t state)
{
- struct list_head list;
ktime_t starttime = ktime_get();
int error = 0;
- INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
- while (!list_empty(&dpm_list)) {
- struct device *dev = to_device(dpm_list.prev);
+ while (!list_empty(&dpm_prepared_list)) {
+ struct device *dev = to_device(dpm_prepared_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
@@ -948,12 +929,11 @@ static int dpm_suspend(pm_message_t state)
break;
}
if (!list_empty(&dev->power.entry))
- list_move(&dev->power.entry, &list);
+ list_move(&dev->power.entry, &dpm_suspended_list);
put_device(dev);
if (async_error)
break;
}
- list_splice(&list, dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
if (!error)
@@ -1012,22 +992,20 @@ static int device_prepare(struct device *dev, pm_message_t state)
*/
static int dpm_prepare(pm_message_t state)
{
- struct list_head list;
int error = 0;
- INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
- transition_started = true;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
get_device(dev);
- dev->power.status = DPM_PREPARING;
mutex_unlock(&dpm_list_mtx);
pm_runtime_get_noresume(dev);
- if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
- /* Wake-up requested during system sleep transition. */
+ if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
+ pm_wakeup_event(dev, 0);
+
+ if (pm_wakeup_pending()) {
pm_runtime_put_sync(dev);
error = -EBUSY;
} else {
@@ -1036,24 +1014,22 @@ static int dpm_prepare(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error) {
- dev->power.status = DPM_ON;
if (error == -EAGAIN) {
put_device(dev);
error = 0;
continue;
}
- printk(KERN_ERR "PM: Failed to prepare device %s "
- "for power transition: error %d\n",
- kobject_name(&dev->kobj), error);
+ printk(KERN_INFO "PM: Device %s not prepared "
+ "for power transition: code %d\n",
+ dev_name(dev), error);
put_device(dev);
break;
}
- dev->power.status = DPM_SUSPENDING;
+ dev->power.in_suspend = true;
if (!list_empty(&dev->power.entry))
- list_move_tail(&dev->power.entry, &list);
+ list_move_tail(&dev->power.entry, &dpm_prepared_list);
put_device(dev);
}
- list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
return error;
}
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 02c652be83e7..656493a5e073 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -250,13 +250,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
if (!cb)
return -ENOSYS;
- spin_unlock_irq(&dev->power.lock);
+ if (dev->power.irq_safe) {
+ retval = cb(dev);
+ } else {
+ spin_unlock_irq(&dev->power.lock);
- retval = cb(dev);
+ retval = cb(dev);
- spin_lock_irq(&dev->power.lock);
+ spin_lock_irq(&dev->power.lock);
+ }
dev->power.runtime_error = retval;
-
return retval;
}
@@ -404,7 +407,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto out;
}
- if (parent && !parent->power.ignore_children) {
+ if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
spin_unlock_irq(&dev->power.lock);
pm_request_idle(parent);
@@ -527,10 +530,13 @@ static int rpm_resume(struct device *dev, int rpmflags)
if (!parent && dev->parent) {
/*
- * Increment the parent's resume counter and resume it if
- * necessary.
+ * Increment the parent's usage counter and resume it if
+ * necessary. Not needed if dev is irq-safe; then the
+ * parent is permanently resumed.
*/
parent = dev->parent;
+ if (dev->power.irq_safe)
+ goto skip_parent;
spin_unlock(&dev->power.lock);
pm_runtime_get_noresume(parent);
@@ -553,6 +559,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
goto out;
goto repeat;
}
+ skip_parent:
if (dev->power.no_callbacks)
goto no_callback; /* Assume success. */
@@ -584,7 +591,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
rpm_idle(dev, RPM_ASYNC);
out:
- if (parent) {
+ if (parent && !dev->power.irq_safe) {
spin_unlock_irq(&dev->power.lock);
pm_runtime_put(parent);
@@ -1065,7 +1072,6 @@ EXPORT_SYMBOL_GPL(pm_runtime_allow);
* Set the power.no_callbacks flag, which tells the PM core that this
* device is power-managed through its parent and has no run-time PM
* callbacks of its own. The run-time sysfs attributes will be removed.
- *
*/
void pm_runtime_no_callbacks(struct device *dev)
{
@@ -1078,6 +1084,27 @@ void pm_runtime_no_callbacks(struct device *dev)
EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
/**
+ * pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
+ * @dev: Device to handle
+ *
+ * Set the power.irq_safe flag, which tells the PM core that the
+ * ->runtime_suspend() and ->runtime_resume() callbacks for this device should
+ * always be invoked with the spinlock held and interrupts disabled. It also
+ * causes the parent's usage counter to be permanently incremented, preventing
+ * the parent from runtime suspending -- otherwise an irq-safe child might have
+ * to wait for a non-irq-safe parent.
+ */
+void pm_runtime_irq_safe(struct device *dev)
+{
+ if (dev->parent)
+ pm_runtime_get_sync(dev->parent);
+ spin_lock_irq(&dev->power.lock);
+ dev->power.irq_safe = 1;
+ spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_irq_safe);
+
+/**
* update_autosuspend - Handle a change to a device's autosuspend settings.
* @dev: Device to handle.
* @old_delay: The former autosuspend_delay value.
@@ -1199,4 +1226,6 @@ void pm_runtime_remove(struct device *dev)
/* Change the status back to 'suspended' to match the initial status. */
if (dev->power.runtime_status == RPM_ACTIVE)
pm_runtime_set_suspended(dev);
+ if (dev->power.irq_safe && dev->parent)
+ pm_runtime_put_sync(dev->parent);
}
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 71c5528e1c35..8ec406d8f548 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -542,26 +542,26 @@ static void pm_wakeup_update_hit_counts(void)
}
/**
- * pm_check_wakeup_events - Check for new wakeup events.
+ * pm_wakeup_pending - Check if power transition in progress should be aborted.
*
* Compare the current number of registered wakeup events with its preserved
- * value from the past to check if new wakeup events have been registered since
- * the old value was stored. Check if the current number of wakeup events being
- * processed is zero.
+ * value from the past and return true if new wakeup events have been registered
+ * since the old value was stored. Also return true if the current number of
+ * wakeup events being processed is different from zero.
*/
-bool pm_check_wakeup_events(void)
+bool pm_wakeup_pending(void)
{
unsigned long flags;
- bool ret = true;
+ bool ret = false;
spin_lock_irqsave(&events_lock, flags);
if (events_check_enabled) {
- ret = ((unsigned int)atomic_read(&event_count) == saved_count)
- && !atomic_read(&events_in_progress);
- events_check_enabled = ret;
+ ret = ((unsigned int)atomic_read(&event_count) != saved_count)
+ || atomic_read(&events_in_progress);
+ events_check_enabled = !ret;
}
spin_unlock_irqrestore(&events_lock, flags);
- if (!ret)
+ if (ret)
pm_wakeup_update_hit_counts();
return ret;
}
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4b9359a6f6ca..83c32cb72582 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -464,6 +464,7 @@ config XEN_BLKDEV_FRONTEND
tristate "Xen virtual block device support"
depends on XEN
default y
+ select XEN_XENBUS_FRONTEND
help
This driver implements the front-end of the Xen virtual
block device driver. It communicates with a back-end driver
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index a1725e6488d3..7888501ad9ee 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1341,7 +1341,7 @@ static struct request *set_next_request(void)
{
struct request_queue *q;
int cnt = FD_MAX_UNITS;
- struct request *rq;
+ struct request *rq = NULL;
/* Find next queue we can dispatch from */
fdc_queue = fdc_queue + 1;
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 541e18879965..528f6318ded1 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -180,9 +180,6 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
BUG();
bio_endio(bio, -ENXIO);
return 0;
- } else if (bio->bi_rw & REQ_HARDBARRIER) {
- bio_endio(bio, -EOPNOTSUPP);
- return 0;
} else if (bio->bi_io_vec == NULL) {
printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
BUG();
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 5674bd01d96d..de0435e63b02 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -297,8 +297,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu
struct sk_buff *skb;
struct net_device *ifp;
- read_lock(&dev_base_lock);
- for_each_netdev(&init_net, ifp) {
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, ifp) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
goto cont;
@@ -325,7 +325,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu
cont:
dev_put(ifp);
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
}
static void
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 4e4cc6c828cb..605a67e40bbf 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1399,7 +1399,7 @@ static struct request *set_next_request(void)
{
struct request_queue *q;
int old_pos = fdc_queue;
- struct request *rq;
+ struct request *rq = NULL;
do {
q = unit[fdc_queue].disk->queue;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 2cc4dda46279..516d5bbec2b6 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -66,6 +66,7 @@ MODULE_VERSION("3.6.26");
MODULE_LICENSE("GPL");
static DEFINE_MUTEX(cciss_mutex);
+static struct proc_dir_entry *proc_cciss;
#include "cciss_cmd.h"
#include "cciss.h"
@@ -113,6 +114,8 @@ static struct board_type products[] = {
{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
{0x40910E11, "Smart Array 6i", &SA5_access},
{0x3225103C, "Smart Array P600", &SA5_access},
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
{0x3235103C, "Smart Array P400i", &SA5_access},
{0x3211103C, "Smart Array E200i", &SA5_access},
{0x3212103C, "Smart Array E200", &SA5_access},
@@ -235,9 +238,9 @@ static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c)
/*
* Enqueuing and dequeuing functions for cmdlists.
*/
-static inline void addQ(struct hlist_head *list, CommandList_struct *c)
+static inline void addQ(struct list_head *list, CommandList_struct *c)
{
- hlist_add_head(&c->list, list);
+ list_add_tail(&c->list, list);
}
static inline void removeQ(CommandList_struct *c)
@@ -250,12 +253,12 @@ static inline void removeQ(CommandList_struct *c)
* them off as 'stale' to prevent the driver from
* falling over.
*/
- if (WARN_ON(hlist_unhashed(&c->list))) {
+ if (WARN_ON(list_empty(&c->list))) {
c->cmd_type = CMD_MSG_STALE;
return;
}
- hlist_del_init(&c->list);
+ list_del_init(&c->list);
}
static void enqueue_cmd_and_start_io(ctlr_info_t *h,
@@ -361,8 +364,6 @@ static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define ENGAGE_SCSI "engage scsi"
-static struct proc_dir_entry *proc_cciss;
-
static void cciss_seq_show_header(struct seq_file *seq)
{
ctlr_info_t *h = seq->private;
@@ -904,7 +905,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h)
c->cmdindex = i;
- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (__u32) cmd_dma_handle;
temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -943,7 +944,7 @@ static CommandList_struct *cmd_special_alloc(ctlr_info_t *h)
}
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (__u32) cmd_dma_handle;
temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2833,6 +2834,8 @@ static int cciss_revalidate(struct gendisk *disk)
InquiryData_struct *inq_buff = NULL;
for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+ if (!h->drv[logvol])
+ continue;
if (memcmp(h->drv[logvol]->LunID, drv->LunID,
sizeof(drv->LunID)) == 0) {
FOUND = 1;
@@ -2885,8 +2888,8 @@ static void start_io(ctlr_info_t *h)
{
CommandList_struct *c;
- while (!hlist_empty(&h->reqQ)) {
- c = hlist_entry(h->reqQ.first, CommandList_struct, list);
+ while (!list_empty(&h->reqQ)) {
+ c = list_entry(h->reqQ.next, CommandList_struct, list);
/* can't do anything if fifo is full */
if ((h->access.fifo_full(h))) {
dev_warn(&h->pdev->dev, "fifo full\n");
@@ -3399,11 +3402,10 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
{
u32 tag;
CommandList_struct *c = NULL;
- struct hlist_node *tmp;
__u32 busaddr_masked, tag_masked;
tag = cciss_tag_discard_error_bits(raw_tag);
- hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+ list_for_each_entry(c, &h->cmpQ, list) {
busaddr_masked = cciss_tag_discard_error_bits(c->busaddr);
tag_masked = cciss_tag_discard_error_bits(tag);
if (busaddr_masked == tag_masked) {
@@ -3753,7 +3755,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
for (i = 0; i < MAX_CONFIG_WAIT; i++) {
if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
break;
- msleep(10);
+ usleep_range(10000, 20000);
}
}
@@ -3937,10 +3939,9 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
subsystem_vendor_id;
- for (i = 0; i < ARRAY_SIZE(products); i++) {
+ for (i = 0; i < ARRAY_SIZE(products); i++)
if (*board_id == products[i].board_id)
return i;
- }
dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
*board_id);
return -ENODEV;
@@ -3971,18 +3972,31 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
return -ENODEV;
}
-static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
+ void __iomem *vaddr, int wait_for_ready)
+#define BOARD_READY 1
+#define BOARD_NOT_READY 0
{
- int i;
+ int i, iterations;
u32 scratchpad;
- for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
- scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
- if (scratchpad == CCISS_FIRMWARE_READY)
- return 0;
+ if (wait_for_ready)
+ iterations = CCISS_BOARD_READY_ITERATIONS;
+ else
+ iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
+
+ for (i = 0; i < iterations; i++) {
+ scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+ if (wait_for_ready) {
+ if (scratchpad == CCISS_FIRMWARE_READY)
+ return 0;
+ } else {
+ if (scratchpad != CCISS_FIRMWARE_READY)
+ return 0;
+ }
msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
}
- dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+ dev_warn(&pdev->dev, "board not ready, timed out.\n");
return -ENODEV;
}
@@ -4031,6 +4045,11 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
{
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+ /* Limit commands in memory limited kdump scenario. */
+ if (reset_devices && h->max_commands > 32)
+ h->max_commands = 32;
+
if (h->max_commands < 16) {
dev_warn(&h->pdev->dev, "Controller reports "
"max supported commands of %d, an obvious lie. "
@@ -4148,7 +4167,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
err = -ENOMEM;
goto err_out_free_res;
}
- err = cciss_wait_for_board_ready(h);
+ err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
if (err)
goto err_out_free_res;
err = cciss_find_cfgtables(h);
@@ -4313,36 +4332,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
#define cciss_noop(p) cciss_message(p, 3, 0)
-static __devinit int cciss_reset_msi(struct pci_dev *pdev)
-{
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-
- int pos;
- u16 control = 0;
-
- pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
- if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos), &control);
- if (control & PCI_MSI_FLAGS_ENABLE) {
- dev_info(&pdev->dev, "resetting MSI\n");
- pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
- }
- }
-
- pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
- if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos), &control);
- if (control & PCI_MSIX_FLAGS_ENABLE) {
- dev_info(&pdev->dev, "resetting MSI-X\n");
- pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
- }
- }
-
- return 0;
-}
-
static int cciss_controller_hard_reset(struct pci_dev *pdev,
void * __iomem vaddr, bool use_doorbell)
{
@@ -4397,17 +4386,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
* states or using the doorbell register. */
static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
{
- u16 saved_config_space[32];
u64 cfg_offset;
u32 cfg_base_addr;
u64 cfg_base_addr_index;
void __iomem *vaddr;
unsigned long paddr;
u32 misc_fw_support, active_transport;
- int rc, i;
+ int rc;
CfgTable_struct __iomem *cfgtable;
bool use_doorbell;
u32 board_id;
+ u16 command_register;
/* For controllers as old a the p600, this is very nearly
* the same thing as
@@ -4417,14 +4406,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
* pci_set_power_state(pci_dev, PCI_D0);
* pci_restore_state(pci_dev);
*
- * but we can't use these nice canned kernel routines on
- * kexec, because they also check the MSI/MSI-X state in PCI
- * configuration space and do the wrong thing when it is
- * set/cleared. Also, the pci_save/restore_state functions
- * violate the ordering requirements for restoring the
- * configuration space from the CCISS document (see the
- * comment below). So we roll our own ....
- *
* For controllers newer than the P600, the pci power state
* method of resetting doesn't work so we have another way
* using the doorbell register.
@@ -4443,8 +4424,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
return -ENODEV;
}
- for (i = 0; i < 32; i++)
- pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+ /* Save the PCI command register */
+ pci_read_config_word(pdev, 4, &command_register);
+ /* Turn the board off. This is so that later pci_restore_state()
+ * won't turn the board on before the rest of config space is ready.
+ */
+ pci_disable_device(pdev);
+ pci_save_state(pdev);
/* find the first memory BAR, so we can find the cfg table */
rc = cciss_pci_find_memory_BAR(pdev, &paddr);
@@ -4479,26 +4465,32 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
if (rc)
goto unmap_cfgtable;
-
- /* Restore the PCI configuration space. The Open CISS
- * Specification says, "Restore the PCI Configuration
- * Registers, offsets 00h through 60h. It is important to
- * restore the command register, 16-bits at offset 04h,
- * last. Do not restore the configuration status register,
- * 16-bits at offset 06h." Note that the offset is 2*i.
- */
- for (i = 0; i < 32; i++) {
- if (i == 2 || i == 3)
- continue;
- pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+ pci_restore_state(pdev);
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_warn(&pdev->dev, "failed to enable device.\n");
+ goto unmap_cfgtable;
}
- wmb();
- pci_write_config_word(pdev, 4, saved_config_space[2]);
+ pci_write_config_word(pdev, 4, command_register);
/* Some devices (notably the HP Smart Array 5i Controller)
need a little pause here */
msleep(CCISS_POST_RESET_PAUSE_MSECS);
+ /* Wait for board to become not ready, then ready. */
+ dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+ rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+ if (rc) /* Don't bail, might be E500, etc. which can't be reset */
+ dev_warn(&pdev->dev,
+ "failed waiting for board to become not ready\n");
+ rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
+ if (rc) {
+ dev_warn(&pdev->dev,
+ "failed waiting for board to become ready\n");
+ goto unmap_cfgtable;
+ }
+ dev_info(&pdev->dev, "board ready.\n");
+
/* Controller should be in simple mode at this point. If it's not,
* It means we're on one of those controllers which doesn't support
* the doorbell reset method and on which the PCI power management reset
@@ -4539,8 +4531,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
return 0; /* just try to do the kdump anyhow. */
if (rc)
return -ENODEV;
- if (cciss_reset_msi(pdev))
- return -ENODEV;
/* Now try to get the controller to respond to a no-op */
for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
@@ -4581,8 +4571,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
h = hba[i];
h->pdev = pdev;
h->busy_initializing = 1;
- INIT_HLIST_HEAD(&h->cmpQ);
- INIT_HLIST_HEAD(&h->reqQ);
+ INIT_LIST_HEAD(&h->cmpQ);
+ INIT_LIST_HEAD(&h->reqQ);
mutex_init(&h->busy_shutting_down);
if (cciss_pci_init(h) != 0)
@@ -4936,7 +4926,8 @@ static void __exit cciss_cleanup(void)
}
}
kthread_stop(cciss_scan_thread);
- remove_proc_entry("driver/cciss", NULL);
+ if (proc_cciss)
+ remove_proc_entry("driver/cciss", NULL);
bus_unregister(&cciss_bus_type);
}
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index ae340ffc8f81..579f74918493 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -103,8 +103,8 @@ struct ctlr_info
struct access_method access;
/* queue and queue Info */
- struct hlist_head reqQ;
- struct hlist_head cmpQ;
+ struct list_head reqQ;
+ struct list_head cmpQ;
unsigned int Qdepth;
unsigned int maxQsinceinit;
unsigned int maxSG;
@@ -200,10 +200,14 @@ struct ctlr_info
* the above.
*/
#define CCISS_BOARD_READY_WAIT_SECS (120)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
#define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
#define CCISS_BOARD_READY_ITERATIONS \
((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
+#define CCISS_BOARD_NOT_READY_ITERATIONS \
+ ((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
+ CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
#define CCISS_POST_RESET_PAUSE_MSECS (3000)
#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
#define CCISS_POST_RESET_NOOP_RETRIES (12)
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index eb060f1b00b6..35463d2f0ee7 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -195,7 +195,7 @@ typedef struct _CommandList_struct {
int ctlr;
int cmd_type;
long cmdindex;
- struct hlist_node list;
+ struct list_head list;
struct request * rq;
struct completion *waiting;
int retry_count;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 575495f3c4b8..727d0225b7d0 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -62,8 +62,8 @@ static int cciss_scsi_proc_info(
int length, /* length of data in buffer */
int func); /* 0 == read, 1 == write */
-static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
- void (* done)(struct scsi_cmnd *));
+static int cciss_scsi_queue_command (struct Scsi_Host *h,
+ struct scsi_cmnd *cmd);
static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
static int cciss_eh_abort_handler(struct scsi_cmnd *);
@@ -1406,7 +1406,7 @@ static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *c,
static int
-cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+cciss_scsi_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
ctlr_info_t *h;
int rc;
@@ -1504,6 +1504,8 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
return 0;
}
+static DEF_SCSI_QCMD(cciss_scsi_queue_command)
+
static void cciss_unregister_scsi(ctlr_info_t *h)
{
struct cciss_scsi_adapter_data_t *sa;
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index ac04ef97eac2..ba95cba192be 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -78,11 +78,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
init_completion(&md_io.event);
md_io.error = 0;
- if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
- rw |= REQ_HARDBARRIER;
+ if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+ rw |= REQ_FUA;
rw |= REQ_UNPLUG | REQ_SYNC;
- retry:
bio = bio_alloc(GFP_NOIO, 1);
bio->bi_bdev = bdev->md_bdev;
bio->bi_sector = sector;
@@ -100,17 +99,6 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
wait_for_completion(&md_io.event);
ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
- /* check for unsupported barrier op.
- * would rather check on EOPNOTSUPP, but that is not reliable.
- * don't try again for ANY return value != 0 */
- if (unlikely((bio->bi_rw & REQ_HARDBARRIER) && !ok)) {
- /* Try again with no barrier */
- dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
- set_bit(MD_NO_BARRIER, &mdev->flags);
- rw &= ~REQ_HARDBARRIER;
- bio_put(bio);
- goto retry;
- }
out:
bio_put(bio);
return ok;
@@ -284,18 +272,32 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
u32 xor_sum = 0;
if (!get_ldev(mdev)) {
- dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+ dev_err(DEV,
+ "disk is %s, cannot start al transaction (-%d +%d)\n",
+ drbd_disk_str(mdev->state.disk), evicted, new_enr);
complete(&((struct update_al_work *)w)->event);
return 1;
}
/* do we have to do a bitmap write, first?
* TODO reduce maximum latency:
* submit both bios, then wait for both,
- * instead of doing two synchronous sector writes. */
+ * instead of doing two synchronous sector writes.
+ * For now, we must not write the transaction,
+ * if we cannot write out the bitmap of the evicted extent. */
if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
- mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+ /* The bitmap write may have failed, causing a state change. */
+ if (mdev->state.disk < D_INCONSISTENT) {
+ dev_err(DEV,
+ "disk is %s, cannot write al transaction (-%d +%d)\n",
+ drbd_disk_str(mdev->state.disk), evicted, new_enr);
+ complete(&((struct update_al_work *)w)->event);
+ put_ldev(mdev);
+ return 1;
+ }
+
+ mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
buffer = (struct al_transaction *)page_address(mdev->md_io_page);
buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
@@ -739,7 +741,7 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
unsigned int enr;
unsigned long add = 0;
char ppb[10];
- int i;
+ int i, tmp;
wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
@@ -747,7 +749,9 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
enr = lc_element_by_index(mdev->act_log, i)->lc_number;
if (enr == LC_FREE)
continue;
- add += drbd_bm_ALe_set_all(mdev, enr);
+ tmp = drbd_bm_ALe_set_all(mdev, enr);
+ dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
+ add += tmp;
}
lc_unlock(mdev->act_log);
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 9bdcf4393c0a..3803a0348937 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -114,11 +114,11 @@ struct drbd_conf;
#define D_ASSERT(exp) if (!(exp)) \
dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
-#define ERR_IF(exp) if (({ \
- int _b = (exp) != 0; \
- if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n", \
- __func__, #exp, __FILE__, __LINE__); \
- _b; \
+#define ERR_IF(exp) if (({ \
+ int _b = (exp) != 0; \
+ if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n", \
+ __func__, #exp, __FILE__, __LINE__); \
+ _b; \
}))
/* Defines to control fault insertion */
@@ -749,17 +749,12 @@ struct drbd_epoch {
/* drbd_epoch flag bits */
enum {
- DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
- DE_BARRIER_IN_NEXT_EPOCH_DONE,
- DE_CONTAINS_A_BARRIER,
DE_HAVE_BARRIER_NUMBER,
- DE_IS_FINISHING,
};
enum epoch_event {
EV_PUT,
EV_GOT_BARRIER_NR,
- EV_BARRIER_DONE,
EV_BECAME_LAST,
EV_CLEANUP = 32, /* used as flag */
};
@@ -801,11 +796,6 @@ enum {
__EE_CALL_AL_COMPLETE_IO,
__EE_MAY_SET_IN_SYNC,
- /* This epoch entry closes an epoch using a barrier.
- * On sucessful completion, the epoch is released,
- * and the P_BARRIER_ACK send. */
- __EE_IS_BARRIER,
-
/* In case a barrier failed,
* we need to resubmit without the barrier flag. */
__EE_RESUBMITTED,
@@ -820,7 +810,6 @@ enum {
};
#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC)
-#define EE_IS_BARRIER (1<<__EE_IS_BARRIER)
#define EE_RESUBMITTED (1<<__EE_RESUBMITTED)
#define EE_WAS_ERROR (1<<__EE_WAS_ERROR)
#define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST)
@@ -843,16 +832,15 @@ enum {
* Gets cleared when the state.conn
* goes into C_CONNECTED state. */
WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */
- NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */
CONSIDER_RESYNC,
- MD_NO_BARRIER, /* meta data device does not support barriers,
- so don't even try */
+ MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */
SUSPEND_IO, /* suspend application io */
BITMAP_IO, /* suspend application io;
once no more io in flight, start bitmap io */
BITMAP_IO_QUEUED, /* Started bitmap IO */
- GO_DISKLESS, /* Disk failed, local_cnt reached zero, we are going diskless */
+ GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */
+ WAS_IO_ERROR, /* Local disk failed returned IO error */
RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
NET_CONGESTED, /* The data socket is congested */
@@ -923,8 +911,6 @@ struct drbd_md {
struct drbd_backing_dev {
struct block_device *backing_bdev;
struct block_device *md_bdev;
- struct file *lo_file;
- struct file *md_file;
struct drbd_md md;
struct disk_conf dc; /* The user provided config... */
sector_t known_size; /* last known size of that backing device */
@@ -947,7 +933,6 @@ enum write_ordering_e {
WO_none,
WO_drain_io,
WO_bdev_flush,
- WO_bio_barrier
};
struct fifo_buffer {
@@ -1281,6 +1266,7 @@ extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
extern void drbd_go_diskless(struct drbd_conf *mdev);
+extern void drbd_ldev_destroy(struct drbd_conf *mdev);
/* Meta data layout
@@ -1798,17 +1784,17 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
case EP_PASS_ON:
if (!forcedetach) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Local IO failed in %s."
- "Passing error on...\n", where);
+ dev_err(DEV, "Local IO failed in %s.\n", where);
break;
}
/* NOTE fall through to detach case if forcedetach set */
case EP_DETACH:
case EP_CALL_HELPER:
+ set_bit(WAS_IO_ERROR, &mdev->flags);
if (mdev->state.disk > D_FAILED) {
_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
- dev_err(DEV, "Local IO failed in %s."
- "Detaching...\n", where);
+ dev_err(DEV,
+ "Local IO failed in %s. Detaching...\n", where);
}
break;
}
@@ -1874,7 +1860,7 @@ static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
static inline sector_t drbd_get_capacity(struct block_device *bdev)
{
/* return bdev ? get_capacity(bdev->bd_disk) : 0; */
- return bdev ? bdev->bd_inode->i_size >> 9 : 0;
+ return bdev ? i_size_read(bdev->bd_inode) >> 9 : 0;
}
/**
@@ -2127,7 +2113,11 @@ static inline void put_ldev(struct drbd_conf *mdev)
__release(local);
D_ASSERT(i >= 0);
if (i == 0) {
+ if (mdev->state.disk == D_DISKLESS)
+ /* even internal references gone, safe to destroy */
+ drbd_ldev_destroy(mdev);
if (mdev->state.disk == D_FAILED)
+ /* all application IO references gone. */
drbd_go_diskless(mdev);
wake_up(&mdev->misc_wait);
}
@@ -2138,6 +2128,10 @@ static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_stat
{
int io_allowed;
+ /* never get a reference while D_DISKLESS */
+ if (mdev->state.disk == D_DISKLESS)
+ return 0;
+
atomic_inc(&mdev->local_cnt);
io_allowed = (mdev->state.disk >= mins);
if (!io_allowed)
@@ -2406,12 +2400,12 @@ static inline void drbd_md_flush(struct drbd_conf *mdev)
{
int r;
- if (test_bit(MD_NO_BARRIER, &mdev->flags))
+ if (test_bit(MD_NO_FUA, &mdev->flags))
return;
r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
if (r) {
- set_bit(MD_NO_BARRIER, &mdev->flags);
+ set_bit(MD_NO_FUA, &mdev->flags);
dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
}
}
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 25c7a73c5062..29cd0dc9fe4f 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -835,6 +835,15 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
ns.conn = os.conn;
+ /* we cannot fail (again) if we already detached */
+ if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
+ ns.disk = D_DISKLESS;
+
+ /* if we are only D_ATTACHING yet,
+ * we can (and should) go directly to D_DISKLESS. */
+ if (ns.disk == D_FAILED && os.disk == D_ATTACHING)
+ ns.disk = D_DISKLESS;
+
/* After C_DISCONNECTING only C_STANDALONE may follow */
if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
ns.conn = os.conn;
@@ -1056,7 +1065,15 @@ int __drbd_set_state(struct drbd_conf *mdev,
!test_and_set_bit(CONFIG_PENDING, &mdev->flags))
set_bit(DEVICE_DYING, &mdev->flags);
- mdev->state.i = ns.i;
+ /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
+ * on the ldev here, to be sure the transition -> D_DISKLESS resp.
+ * drbd_ldev_destroy() won't happen before our corresponding
+ * after_state_ch works run, where we put_ldev again. */
+ if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
+ (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
+ atomic_inc(&mdev->local_cnt);
+
+ mdev->state = ns;
wake_up(&mdev->misc_wait);
wake_up(&mdev->state_wait);
@@ -1268,7 +1285,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
drbd_uuid_new_current(mdev);
clear_bit(NEW_CUR_UUID, &mdev->flags);
- drbd_md_sync(mdev);
}
spin_lock_irq(&mdev->req_lock);
_drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
@@ -1365,63 +1381,64 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
- /* first half of local IO error */
- if (os.disk > D_FAILED && ns.disk == D_FAILED) {
- enum drbd_io_error_p eh = EP_PASS_ON;
+ /* first half of local IO error, failure to attach,
+ * or administrative detach */
+ if (os.disk != D_FAILED && ns.disk == D_FAILED) {
+ enum drbd_io_error_p eh;
+ int was_io_error;
+ /* corresponding get_ldev was in __drbd_set_state, to serialize
+ * our cleanup here with the transition to D_DISKLESS,
+ * so it is safe to dreference ldev here. */
+ eh = mdev->ldev->dc.on_io_error;
+ was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
+
+ /* current state still has to be D_FAILED,
+ * there is only one way out: to D_DISKLESS,
+ * and that may only happen after our put_ldev below. */
+ if (mdev->state.disk != D_FAILED)
+ dev_err(DEV,
+ "ASSERT FAILED: disk is %s during detach\n",
+ drbd_disk_str(mdev->state.disk));
if (drbd_send_state(mdev))
- dev_warn(DEV, "Notified peer that my disk is broken.\n");
+ dev_warn(DEV, "Notified peer that I am detaching my disk\n");
else
- dev_err(DEV, "Sending state for drbd_io_error() failed\n");
+ dev_err(DEV, "Sending state for detaching disk failed\n");
drbd_rs_cancel_all(mdev);
- if (get_ldev_if_state(mdev, D_FAILED)) {
- eh = mdev->ldev->dc.on_io_error;
- put_ldev(mdev);
- }
- if (eh == EP_CALL_HELPER)
+ /* In case we want to get something to stable storage still,
+ * this may be the last chance.
+ * Following put_ldev may transition to D_DISKLESS. */
+ drbd_md_sync(mdev);
+ put_ldev(mdev);
+
+ if (was_io_error && eh == EP_CALL_HELPER)
drbd_khelper(mdev, "local-io-error");
}
+ /* second half of local IO error, failure to attach,
+ * or administrative detach,
+ * after local_cnt references have reached zero again */
+ if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+ /* We must still be diskless,
+ * re-attach has to be serialized with this! */
+ if (mdev->state.disk != D_DISKLESS)
+ dev_err(DEV,
+ "ASSERT FAILED: disk is %s while going diskless\n",
+ drbd_disk_str(mdev->state.disk));
- /* second half of local IO error handling,
- * after local_cnt references have reached zero: */
- if (os.disk == D_FAILED && ns.disk == D_DISKLESS) {
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
- }
-
- if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
- /* We must still be diskless,
- * re-attach has to be serialized with this! */
- if (mdev->state.disk != D_DISKLESS)
- dev_err(DEV,
- "ASSERT FAILED: disk is %s while going diskless\n",
- drbd_disk_str(mdev->state.disk));
+ mdev->rs_total = 0;
+ mdev->rs_failed = 0;
+ atomic_set(&mdev->rs_pending_cnt, 0);
- /* we cannot assert local_cnt == 0 here, as get_ldev_if_state
- * will inc/dec it frequently. Since we became D_DISKLESS, no
- * one has touched the protected members anymore, though, so we
- * are safe to free them here. */
if (drbd_send_state(mdev))
- dev_warn(DEV, "Notified peer that I detached my disk.\n");
+ dev_warn(DEV, "Notified peer that I'm now diskless.\n");
else
- dev_err(DEV, "Sending state for detach failed\n");
-
- lc_destroy(mdev->resync);
- mdev->resync = NULL;
- lc_destroy(mdev->act_log);
- mdev->act_log = NULL;
- __no_warn(local,
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;);
-
- if (mdev->md_io_tmpp) {
- __free_page(mdev->md_io_tmpp);
- mdev->md_io_tmpp = NULL;
- }
+ dev_err(DEV, "Sending state for being diskless failed\n");
+ /* corresponding get_ldev in __drbd_set_state
+ * this may finaly trigger drbd_ldev_destroy. */
+ put_ldev(mdev);
}
/* Disks got bigger while they were detached */
@@ -2772,11 +2789,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
drbd_set_defaults(mdev);
- /* for now, we do NOT yet support it,
- * even though we start some framework
- * to eventually support barriers */
- set_bit(NO_BARRIER_SUPP, &mdev->flags);
-
atomic_set(&mdev->ap_bio_cnt, 0);
atomic_set(&mdev->ap_pending_cnt, 0);
atomic_set(&mdev->rs_pending_cnt, 0);
@@ -2842,7 +2854,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
drbd_thread_init(mdev, &mdev->asender, drbd_asender);
mdev->agreed_pro_version = PRO_VERSION_MAX;
- mdev->write_ordering = WO_bio_barrier;
+ mdev->write_ordering = WO_bdev_flush;
mdev->resync_wenr = LC_FREE;
}
@@ -2899,7 +2911,6 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev)
D_ASSERT(list_empty(&mdev->resync_work.list));
D_ASSERT(list_empty(&mdev->unplug_work.list));
D_ASSERT(list_empty(&mdev->go_diskless.list));
-
}
@@ -3361,11 +3372,8 @@ void drbd_free_bc(struct drbd_backing_dev *ldev)
if (ldev == NULL)
return;
- bd_release(ldev->backing_bdev);
- bd_release(ldev->md_bdev);
-
- fput(ldev->lo_file);
- fput(ldev->md_file);
+ blkdev_put(ldev->backing_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+ blkdev_put(ldev->md_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
kfree(ldev);
}
@@ -3660,6 +3668,8 @@ void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
get_random_bytes(&val, sizeof(u64));
_drbd_uuid_set(mdev, UI_CURRENT, val);
+ /* get it to stable storage _now_ */
+ drbd_md_sync(mdev);
}
void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
@@ -3756,19 +3766,31 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
return 1;
}
+void drbd_ldev_destroy(struct drbd_conf *mdev)
+{
+ lc_destroy(mdev->resync);
+ mdev->resync = NULL;
+ lc_destroy(mdev->act_log);
+ mdev->act_log = NULL;
+ __no_warn(local,
+ drbd_free_bc(mdev->ldev);
+ mdev->ldev = NULL;);
+
+ if (mdev->md_io_tmpp) {
+ __free_page(mdev->md_io_tmpp);
+ mdev->md_io_tmpp = NULL;
+ }
+ clear_bit(GO_DISKLESS, &mdev->flags);
+}
+
static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
{
D_ASSERT(mdev->state.disk == D_FAILED);
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
* inc/dec it frequently. Once we are D_DISKLESS, no one will touch
- * the protected members anymore, though, so in the after_state_ch work
- * it will be safe to free them. */
+ * the protected members anymore, though, so once put_ldev reaches zero
+ * again, it will be safe to free them. */
drbd_force_state(mdev, NS(disk, D_DISKLESS));
- /* We need to wait for return of references checked out while we still
- * have been D_FAILED, though (drbd_md_sync, bitmap io). */
- wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
-
- clear_bit(GO_DISKLESS, &mdev->flags);
return 1;
}
@@ -3777,9 +3799,6 @@ void drbd_go_diskless(struct drbd_conf *mdev)
D_ASSERT(mdev->state.disk == D_FAILED);
if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
- /* don't drbd_queue_work_front,
- * we need to serialize with the after_state_ch work
- * of the -> D_FAILED transition. */
}
/**
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 87925e97e613..8cbfaa687d72 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -855,7 +855,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
sector_t max_possible_sectors;
sector_t min_md_device_sectors;
struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
- struct inode *inode, *inode2;
+ struct block_device *bdev;
struct lru_cache *resync_lru = NULL;
union drbd_state ns, os;
unsigned int max_seg_s;
@@ -870,6 +870,11 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
retcode = ERR_DISK_CONFIGURED;
goto fail;
}
+ /* It may just now have detached because of IO error. Make sure
+ * drbd_ldev_destroy is done already, we may end up here very fast,
+ * e.g. if someone calls attach from the on-io-error handler,
+ * to realize a "hot spare" feature (not that I'd recommend that) */
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
/* allocation not in the IO path, cqueue thread context */
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
@@ -902,46 +907,40 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
}
}
- nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
- if (IS_ERR(nbc->lo_file)) {
+ bdev = blkdev_get_by_path(nbc->dc.backing_dev,
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
+ if (IS_ERR(bdev)) {
dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
- PTR_ERR(nbc->lo_file));
- nbc->lo_file = NULL;
+ PTR_ERR(bdev));
retcode = ERR_OPEN_DISK;
goto fail;
}
+ nbc->backing_bdev = bdev;
- inode = nbc->lo_file->f_dentry->d_inode;
-
- if (!S_ISBLK(inode->i_mode)) {
- retcode = ERR_DISK_NOT_BDEV;
- goto fail;
- }
-
- nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0);
- if (IS_ERR(nbc->md_file)) {
+ /*
+ * meta_dev_idx >= 0: external fixed size, possibly multiple
+ * drbd sharing one meta device. TODO in that case, paranoia
+ * check that [md_bdev, meta_dev_idx] is not yet used by some
+ * other drbd minor! (if you use drbd.conf + drbdadm, that
+ * should check it for you already; but if you don't, or
+ * someone fooled it, we need to double check here)
+ */
+ bdev = blkdev_get_by_path(nbc->dc.meta_dev,
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL,
+ (nbc->dc.meta_dev_idx < 0) ?
+ (void *)mdev : (void *)drbd_m_holder);
+ if (IS_ERR(bdev)) {
dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev,
- PTR_ERR(nbc->md_file));
- nbc->md_file = NULL;
+ PTR_ERR(bdev));
retcode = ERR_OPEN_MD_DISK;
goto fail;
}
+ nbc->md_bdev = bdev;
- inode2 = nbc->md_file->f_dentry->d_inode;
-
- if (!S_ISBLK(inode2->i_mode)) {
- retcode = ERR_MD_NOT_BDEV;
- goto fail;
- }
-
- nbc->backing_bdev = inode->i_bdev;
- if (bd_claim(nbc->backing_bdev, mdev)) {
- printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n",
- nbc->backing_bdev, mdev,
- nbc->backing_bdev->bd_holder,
- nbc->backing_bdev->bd_contains->bd_holder,
- nbc->backing_bdev->bd_holders);
- retcode = ERR_BDCLAIM_DISK;
+ if ((nbc->backing_bdev == nbc->md_bdev) !=
+ (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
+ nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
+ retcode = ERR_MD_IDX_INVALID;
goto fail;
}
@@ -950,28 +949,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
offsetof(struct bm_extent, lce));
if (!resync_lru) {
retcode = ERR_NOMEM;
- goto release_bdev_fail;
- }
-
- /* meta_dev_idx >= 0: external fixed size,
- * possibly multiple drbd sharing one meta device.
- * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is
- * not yet used by some other drbd minor!
- * (if you use drbd.conf + drbdadm,
- * that should check it for you already; but if you don't, or someone
- * fooled it, we need to double check here) */
- nbc->md_bdev = inode2->i_bdev;
- if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev
- : (void *) drbd_m_holder)) {
- retcode = ERR_BDCLAIM_MD_DISK;
- goto release_bdev_fail;
- }
-
- if ((nbc->backing_bdev == nbc->md_bdev) !=
- (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
- nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
- retcode = ERR_MD_IDX_INVALID;
- goto release_bdev2_fail;
+ goto fail;
}
/* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */
@@ -982,7 +960,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
(unsigned long long) drbd_get_max_capacity(nbc),
(unsigned long long) nbc->dc.disk_size);
retcode = ERR_DISK_TO_SMALL;
- goto release_bdev2_fail;
+ goto fail;
}
if (nbc->dc.meta_dev_idx < 0) {
@@ -999,7 +977,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
dev_warn(DEV, "refusing attach: md-device too small, "
"at least %llu sectors needed for this meta-disk type\n",
(unsigned long long) min_md_device_sectors);
- goto release_bdev2_fail;
+ goto fail;
}
/* Make sure the new disk is big enough
@@ -1007,7 +985,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
if (drbd_get_max_capacity(nbc) <
drbd_get_capacity(mdev->this_bdev)) {
retcode = ERR_DISK_TO_SMALL;
- goto release_bdev2_fail;
+ goto fail;
}
nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
@@ -1030,7 +1008,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
drbd_resume_io(mdev);
if (retcode < SS_SUCCESS)
- goto release_bdev2_fail;
+ goto fail;
if (!get_ldev_if_state(mdev, D_ATTACHING))
goto force_diskless;
@@ -1098,9 +1076,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
/* Reset the "barriers don't work" bits here, then force meta data to
* be written, to ensure we determine if barriers are supported. */
if (nbc->dc.no_md_flush)
- set_bit(MD_NO_BARRIER, &mdev->flags);
+ set_bit(MD_NO_FUA, &mdev->flags);
else
- clear_bit(MD_NO_BARRIER, &mdev->flags);
+ clear_bit(MD_NO_FUA, &mdev->flags);
/* Point of no return reached.
* Devices and memory are no longer released by error cleanup below.
@@ -1112,8 +1090,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
nbc = NULL;
resync_lru = NULL;
- mdev->write_ordering = WO_bio_barrier;
- drbd_bump_write_ordering(mdev, WO_bio_barrier);
+ mdev->write_ordering = WO_bdev_flush;
+ drbd_bump_write_ordering(mdev, WO_bdev_flush);
if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
set_bit(CRASHED_PRIMARY, &mdev->flags);
@@ -1262,20 +1240,16 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
force_diskless_dec:
put_ldev(mdev);
force_diskless:
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ drbd_force_state(mdev, NS(disk, D_FAILED));
drbd_md_sync(mdev);
- release_bdev2_fail:
- if (nbc)
- bd_release(nbc->md_bdev);
- release_bdev_fail:
- if (nbc)
- bd_release(nbc->backing_bdev);
fail:
if (nbc) {
- if (nbc->lo_file)
- fput(nbc->lo_file);
- if (nbc->md_file)
- fput(nbc->md_file);
+ if (nbc->backing_bdev)
+ blkdev_put(nbc->backing_bdev,
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+ if (nbc->md_bdev)
+ blkdev_put(nbc->md_bdev,
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL);
kfree(nbc);
}
lc_destroy(resync_lru);
@@ -1285,10 +1259,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
return 0;
}
+/* Detaching the disk is a process in multiple stages. First we need to lock
+ * out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
+ * Then we transition to D_DISKLESS, and wait for put_ldev() to return all
+ * internal references as well.
+ * Only then we have finally detached. */
static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
struct drbd_nl_cfg_reply *reply)
{
+ drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+ if (mdev->state.disk == D_DISKLESS)
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+ drbd_resume_io(mdev);
return 0;
}
@@ -1953,7 +1936,6 @@ static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
drbd_uuid_new_current(mdev);
clear_bit(NEW_CUR_UUID, &mdev->flags);
- drbd_md_sync(mdev);
}
drbd_suspend_io(mdev);
reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index ad325c5d0ce1..7e6ac307e2de 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -158,7 +158,6 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
[WO_none] = 'n',
[WO_drain_io] = 'd',
[WO_bdev_flush] = 'f',
- [WO_bio_barrier] = 'b',
};
seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index efd6169acf2f..24487d4fb202 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -36,7 +36,6 @@
#include <linux/memcontrol.h>
#include <linux/mm_inline.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/pkt_sched.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -49,11 +48,6 @@
#include "drbd_vli.h"
-struct flush_work {
- struct drbd_work w;
- struct drbd_epoch *epoch;
-};
-
enum finish_epoch {
FE_STILL_LIVE,
FE_DESTROYED,
@@ -66,16 +60,6 @@ static int drbd_do_auth(struct drbd_conf *mdev);
static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
-static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
-{
- struct drbd_epoch *prev;
- spin_lock(&mdev->epoch_lock);
- prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
- if (prev == epoch || prev == mdev->current_epoch)
- prev = NULL;
- spin_unlock(&mdev->epoch_lock);
- return prev;
-}
#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
@@ -981,7 +965,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi
return TRUE;
}
-static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+static void drbd_flush(struct drbd_conf *mdev)
{
int rv;
@@ -997,24 +981,6 @@ static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct d
}
put_ldev(mdev);
}
-
- return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
-}
-
-static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
- struct flush_work *fw = (struct flush_work *)w;
- struct drbd_epoch *epoch = fw->epoch;
-
- kfree(w);
-
- if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
- drbd_flush_after_epoch(mdev, epoch);
-
- drbd_may_finish_epoch(mdev, epoch, EV_PUT |
- (mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
-
- return 1;
}
/**
@@ -1027,15 +993,13 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
struct drbd_epoch *epoch,
enum epoch_event ev)
{
- int finish, epoch_size;
+ int epoch_size;
struct drbd_epoch *next_epoch;
- int schedule_flush = 0;
enum finish_epoch rv = FE_STILL_LIVE;
spin_lock(&mdev->epoch_lock);
do {
next_epoch = NULL;
- finish = 0;
epoch_size = atomic_read(&epoch->epoch_size);
@@ -1045,16 +1009,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
break;
case EV_GOT_BARRIER_NR:
set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
-
- /* Special case: If we just switched from WO_bio_barrier to
- WO_bdev_flush we should not finish the current epoch */
- if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
- mdev->write_ordering != WO_bio_barrier &&
- epoch == mdev->current_epoch)
- clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
- break;
- case EV_BARRIER_DONE:
- set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
break;
case EV_BECAME_LAST:
/* nothing to do*/
@@ -1063,23 +1017,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
if (epoch_size != 0 &&
atomic_read(&epoch->active) == 0 &&
- test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
- epoch->list.prev == &mdev->current_epoch->list &&
- !test_bit(DE_IS_FINISHING, &epoch->flags)) {
- /* Nearly all conditions are met to finish that epoch... */
- if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
- mdev->write_ordering == WO_none ||
- (epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
- ev & EV_CLEANUP) {
- finish = 1;
- set_bit(DE_IS_FINISHING, &epoch->flags);
- } else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
- mdev->write_ordering == WO_bio_barrier) {
- atomic_inc(&epoch->active);
- schedule_flush = 1;
- }
- }
- if (finish) {
+ test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) {
if (!(ev & EV_CLEANUP)) {
spin_unlock(&mdev->epoch_lock);
drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
@@ -1102,6 +1040,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
/* atomic_set(&epoch->active, 0); is already zero */
if (rv == FE_STILL_LIVE)
rv = FE_RECYCLED;
+ wake_up(&mdev->ee_wait);
}
}
@@ -1113,22 +1052,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
spin_unlock(&mdev->epoch_lock);
- if (schedule_flush) {
- struct flush_work *fw;
- fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
- if (fw) {
- fw->w.cb = w_flush;
- fw->epoch = epoch;
- drbd_queue_work(&mdev->data.work, &fw->w);
- } else {
- dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
- set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
- /* That is not a recursion, only one level */
- drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
- drbd_may_finish_epoch(mdev, epoch, EV_PUT);
- }
- }
-
return rv;
}
@@ -1144,19 +1067,16 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo)
[WO_none] = "none",
[WO_drain_io] = "drain",
[WO_bdev_flush] = "flush",
- [WO_bio_barrier] = "barrier",
};
pwo = mdev->write_ordering;
wo = min(pwo, wo);
- if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
- wo = WO_bdev_flush;
if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
wo = WO_drain_io;
if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
wo = WO_none;
mdev->write_ordering = wo;
- if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
+ if (pwo != mdev->write_ordering || wo == WO_bdev_flush)
dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
}
@@ -1192,7 +1112,7 @@ next_bio:
bio->bi_sector = sector;
bio->bi_bdev = mdev->ldev->backing_bdev;
/* we special case some flags in the multi-bio case, see below
- * (REQ_UNPLUG, REQ_HARDBARRIER) */
+ * (REQ_UNPLUG) */
bio->bi_rw = rw;
bio->bi_private = e;
bio->bi_end_io = drbd_endio_sec;
@@ -1226,11 +1146,6 @@ next_bio:
bio->bi_rw &= ~REQ_UNPLUG;
drbd_generic_make_request(mdev, fault_type, bio);
-
- /* strip off REQ_HARDBARRIER,
- * unless it is the first or last bio */
- if (bios && bios->bi_next)
- bios->bi_rw &= ~REQ_HARDBARRIER;
} while (bios);
maybe_kick_lo(mdev);
return 0;
@@ -1244,45 +1159,9 @@ fail:
return -ENOMEM;
}
-/**
- * w_e_reissue() - Worker callback; Resubmit a bio, without REQ_HARDBARRIER set
- * @mdev: DRBD device.
- * @w: work object.
- * @cancel: The connection will be closed anyways (unused in this callback)
- */
-int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
-{
- struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
- /* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
- (and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
- so that we can finish that epoch in drbd_may_finish_epoch().
- That is necessary if we already have a long chain of Epochs, before
- we realize that REQ_HARDBARRIER is actually not supported */
-
- /* As long as the -ENOTSUPP on the barrier is reported immediately
- that will never trigger. If it is reported late, we will just
- print that warning and continue correctly for all future requests
- with WO_bdev_flush */
- if (previous_epoch(mdev, e->epoch))
- dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
-
- /* we still have a local reference,
- * get_ldev was done in receive_Data. */
-
- e->w.cb = e_end_block;
- if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_DT_WR) != 0) {
- /* drbd_submit_ee fails for one reason only:
- * if was not able to allocate sufficient bios.
- * requeue, try again later. */
- e->w.cb = w_e_reissue;
- drbd_queue_work(&mdev->data.work, &e->w);
- }
- return 1;
-}
-
static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
{
- int rv, issue_flush;
+ int rv;
struct p_barrier *p = &mdev->data.rbuf.barrier;
struct drbd_epoch *epoch;
@@ -1300,44 +1179,40 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign
* Therefore we must send the barrier_ack after the barrier request was
* completed. */
switch (mdev->write_ordering) {
- case WO_bio_barrier:
case WO_none:
if (rv == FE_RECYCLED)
return TRUE;
- break;
+
+ /* receiver context, in the writeout path of the other node.
+ * avoid potential distributed deadlock */
+ epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+ if (epoch)
+ break;
+ else
+ dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
+ /* Fall through */
case WO_bdev_flush:
case WO_drain_io:
- if (rv == FE_STILL_LIVE) {
- set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
- drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
- }
- if (rv == FE_RECYCLED)
- return TRUE;
-
- /* The asender will send all the ACKs and barrier ACKs out, since
- all EEs moved from the active_ee to the done_ee. We need to
- provide a new epoch object for the EEs that come in soon */
- break;
- }
-
- /* receiver context, in the writeout path of the other node.
- * avoid potential distributed deadlock */
- epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
- if (!epoch) {
- dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
- issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- if (issue_flush) {
- rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
- if (rv == FE_RECYCLED)
- return TRUE;
+ drbd_flush(mdev);
+
+ if (atomic_read(&mdev->current_epoch->epoch_size)) {
+ epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+ if (epoch)
+ break;
}
- drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
+ epoch = mdev->current_epoch;
+ wait_event(mdev->ee_wait, atomic_read(&epoch->epoch_size) == 0);
+
+ D_ASSERT(atomic_read(&epoch->active) == 0);
+ D_ASSERT(epoch->flags == 0);
return TRUE;
+ default:
+ dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering);
+ return FALSE;
}
epoch->flags = 0;
@@ -1652,15 +1527,8 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
{
struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
sector_t sector = e->sector;
- struct drbd_epoch *epoch;
int ok = 1, pcmd;
- if (e->flags & EE_IS_BARRIER) {
- epoch = previous_epoch(mdev, e->epoch);
- if (epoch)
- drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
- }
-
if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
if (likely((e->flags & EE_WAS_ERROR) == 0)) {
pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
@@ -1817,27 +1685,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
e->epoch = mdev->current_epoch;
atomic_inc(&e->epoch->epoch_size);
atomic_inc(&e->epoch->active);
-
- if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
- struct drbd_epoch *epoch;
- /* Issue a barrier if we start a new epoch, and the previous epoch
- was not a epoch containing a single request which already was
- a Barrier. */
- epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
- if (epoch == e->epoch) {
- set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
- rw |= REQ_HARDBARRIER;
- e->flags |= EE_IS_BARRIER;
- } else {
- if (atomic_read(&epoch->epoch_size) > 1 ||
- !test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
- set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
- set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
- rw |= REQ_HARDBARRIER;
- e->flags |= EE_IS_BARRIER;
- }
- }
- }
spin_unlock(&mdev->epoch_lock);
dp_flags = be32_to_cpu(p->dp_flags);
@@ -1995,10 +1842,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
break;
}
- if (mdev->state.pdsk == D_DISKLESS) {
+ if (mdev->state.pdsk < D_INCONSISTENT) {
/* In case we have the only disk of the cluster, */
drbd_set_out_of_sync(mdev, e->sector, e->size);
e->flags |= EE_CALL_AL_COMPLETE_IO;
+ e->flags &= ~EE_MAY_SET_IN_SYNC;
drbd_al_begin_io(mdev, e->sector);
}
@@ -3362,7 +3210,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
if (ns.conn == C_MASK) {
ns.conn = C_CONNECTED;
if (mdev->state.disk == D_NEGOTIATING) {
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ drbd_force_state(mdev, NS(disk, D_FAILED));
} else if (peer_state.disk == D_NEGOTIATING) {
dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
peer_state.disk = D_DISKLESS;
@@ -3779,17 +3627,19 @@ static void drbdd(struct drbd_conf *mdev)
}
shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header);
- rv = drbd_recv(mdev, &header->h80.payload, shs);
- if (unlikely(rv != shs)) {
- dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
- goto err_out;
- }
-
if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) {
dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size);
goto err_out;
}
+ if (shs) {
+ rv = drbd_recv(mdev, &header->h80.payload, shs);
+ if (unlikely(rv != shs)) {
+ dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
+ goto err_out;
+ }
+ }
+
rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs);
if (unlikely(!rv)) {
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 9e91a2545fc8..11a75d32a2e2 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -258,7 +258,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
if (!hlist_unhashed(&req->colision))
hlist_del(&req->colision);
else
- D_ASSERT((s & RQ_NET_MASK) == 0);
+ D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
/* for writes we need to do some extra housekeeping */
if (rw == WRITE)
@@ -813,7 +813,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
mdev->state.conn >= C_CONNECTED));
if (!(local || remote) && !is_susp(mdev->state)) {
- dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
goto fail_free_complete;
}
@@ -942,12 +943,21 @@ allocate_barrier:
if (local) {
req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
- if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
- : rw == READ ? DRBD_FAULT_DT_RD
- : DRBD_FAULT_DT_RA))
+ /* State may have changed since we grabbed our reference on the
+ * mdev->ldev member. Double check, and short-circuit to endio.
+ * In case the last activity log transaction failed to get on
+ * stable storage, and this is a WRITE, we may not even submit
+ * this bio. */
+ if (get_ldev(mdev)) {
+ if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
+ : rw == READ ? DRBD_FAULT_DT_RD
+ : DRBD_FAULT_DT_RA))
+ bio_endio(req->private_bio, -EIO);
+ else
+ generic_make_request(req->private_bio);
+ put_ldev(mdev);
+ } else
bio_endio(req->private_bio, -EIO);
- else
- generic_make_request(req->private_bio);
}
/* we need to plug ALWAYS since we possibly need to kick lo_dev.
@@ -1022,20 +1032,6 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio)
return 0;
}
- /* Reject barrier requests if we know the underlying device does
- * not support them.
- * XXX: Need to get this info from peer as well some how so we
- * XXX: reject if EITHER side/data/metadata area does not support them.
- *
- * because of those XXX, this is not yet enabled,
- * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
- */
- if (unlikely(bio->bi_rw & REQ_HARDBARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags)) {
- /* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
- bio_endio(bio, -EOPNOTSUPP);
- return 0;
- }
-
/*
* what we "blindly" assume:
*/
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 181ea0364822..ab2bd09d54b4 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -339,7 +339,8 @@ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what)
}
/* completion of master bio is outside of spinlock.
- * If you need it irqsave, do it your self! */
+ * If you need it irqsave, do it your self!
+ * Which means: don't use from bio endio callback. */
static inline int req_mod(struct drbd_request *req,
enum drbd_req_event what)
{
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 108d58015cd1..34f224b018b3 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/drbd.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/memcontrol.h>
@@ -102,12 +101,6 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local)
put_ldev(mdev);
}
-static int is_failed_barrier(int ee_flags)
-{
- return (ee_flags & (EE_IS_BARRIER|EE_WAS_ERROR|EE_RESUBMITTED))
- == (EE_IS_BARRIER|EE_WAS_ERROR);
-}
-
/* writes on behalf of the partner, or resync writes,
* "submitted" by the receiver, final stage. */
static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local)
@@ -119,21 +112,6 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
int is_syncer_req;
int do_al_complete_io;
- /* if this is a failed barrier request, disable use of barriers,
- * and schedule for resubmission */
- if (is_failed_barrier(e->flags)) {
- drbd_bump_write_ordering(mdev, WO_bdev_flush);
- spin_lock_irqsave(&mdev->req_lock, flags);
- list_del(&e->w.list);
- e->flags = (e->flags & ~EE_WAS_ERROR) | EE_RESUBMITTED;
- e->w.cb = w_e_reissue;
- /* put_ldev actually happens below, once we come here again. */
- __release(local);
- spin_unlock_irqrestore(&mdev->req_lock, flags);
- drbd_queue_work(&mdev->data.work, &e->w);
- return;
- }
-
D_ASSERT(e->block_id != ID_VACANT);
/* after we moved e to done_ee,
@@ -215,8 +193,10 @@ void drbd_endio_sec(struct bio *bio, int error)
*/
void drbd_endio_pri(struct bio *bio, int error)
{
+ unsigned long flags;
struct drbd_request *req = bio->bi_private;
struct drbd_conf *mdev = req->mdev;
+ struct bio_and_error m;
enum drbd_req_event what;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
@@ -242,7 +222,13 @@ void drbd_endio_pri(struct bio *bio, int error)
bio_put(req->private_bio);
req->private_bio = ERR_PTR(error);
- req_mod(req, what);
+ /* not req_mod(), we need irqsave here! */
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ __req_mod(req, what, &m);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (m.bio)
+ complete_master_bio(mdev, &m);
}
int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
@@ -925,7 +911,7 @@ out:
drbd_md_sync(mdev);
if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
- dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
+ dev_info(DEV, "Writing the whole bitmap\n");
drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 767107cce982..b9ba04fc2b34 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -597,6 +597,11 @@ static unsigned char fsector_t; /* sector in track */
static unsigned char in_sector_offset; /* offset within physical sector,
* expressed in units of 512 bytes */
+static inline bool drive_no_geom(int drive)
+{
+ return !current_type[drive] && !ITYPE(UDRS->fd_device);
+}
+
#ifndef fd_eject
static inline int fd_eject(int drive)
{
@@ -3782,7 +3787,7 @@ static int check_floppy_change(struct gendisk *disk)
if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
test_bit(drive, &fake_change) ||
- (!ITYPE(UDRS->fd_device) && !current_type[drive]))
+ drive_no_geom(drive))
return 1;
return 0;
}
@@ -3848,13 +3853,13 @@ static int __floppy_read_block_0(struct block_device *bdev)
static int floppy_revalidate(struct gendisk *disk)
{
int drive = (long)disk->private_data;
-#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
int cf;
int res = 0;
if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
- test_bit(drive, &fake_change) || NO_GEOM) {
+ test_bit(drive, &fake_change) ||
+ drive_no_geom(drive)) {
if (WARN(atomic_read(&usage_count) == 0,
"VFS: revalidate called on non-open device.\n"))
return -EFAULT;
@@ -3862,7 +3867,7 @@ static int floppy_revalidate(struct gendisk *disk)
lock_fdc(drive, false);
cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
test_bit(FD_VERIFY_BIT, &UDRS->flags));
- if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
+ if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
process_fd_request(); /*already done by another thread */
return 0;
}
@@ -3874,7 +3879,7 @@ static int floppy_revalidate(struct gendisk *disk)
clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
if (cf)
UDRS->generation++;
- if (NO_GEOM) {
+ if (drive_no_geom(drive)) {
/* auto-sensing */
res = __floppy_read_block_0(opened_bdev[drive]);
} else {
@@ -4352,7 +4357,7 @@ static int __init floppy_init(void)
out_unreg_platform_dev:
platform_device_unregister(&floppy_device[drive]);
out_flush_work:
- flush_scheduled_work();
+ flush_work_sync(&floppy_work);
if (atomic_read(&usage_count))
floppy_release_irq_and_dma();
out_unreg_region:
@@ -4363,9 +4368,9 @@ out_unreg_blkdev:
out_put_disk:
while (dr--) {
del_timer(&motor_off_timer[dr]);
- put_disk(disks[dr]);
if (disks[dr]->queue)
blk_cleanup_queue(disks[dr]->queue);
+ put_disk(disks[dr]);
}
return err;
}
@@ -4422,7 +4427,7 @@ static int floppy_grab_irq_and_dma(void)
* We might have scheduled a free_irq(), wait it to
* drain first:
*/
- flush_scheduled_work();
+ flush_work_sync(&floppy_work);
if (fd_request_irq()) {
DPRINT("Unable to grab IRQ%d for the floppy driver\n",
@@ -4573,8 +4578,8 @@ static void __exit floppy_module_exit(void)
device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
platform_device_unregister(&floppy_device[drive]);
}
- put_disk(disks[drive]);
blk_cleanup_queue(disks[drive]->queue);
+ put_disk(disks[drive]);
}
del_timer_sync(&fd_timeout);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1e5284ef65fa..44e18c073c44 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -395,11 +395,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct loop_device *lo = p->lo;
struct page *page = buf->page;
sector_t IV;
- int size, ret;
-
- ret = buf->ops->confirm(pipe, buf);
- if (unlikely(ret))
- return ret;
+ int size;
IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) +
(buf->offset >> 9);
@@ -481,12 +477,6 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
if (bio_rw(bio) == WRITE) {
struct file *file = lo->lo_backing_file;
- /* REQ_HARDBARRIER is deprecated */
- if (bio->bi_rw & REQ_HARDBARRIER) {
- ret = -EOPNOTSUPP;
- goto out;
- }
-
if (bio->bi_rw & REQ_FLUSH) {
ret = vfs_fsync(file, 0);
if (unlikely(ret && ret != -EINVAL)) {
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 19b3568e9326..77d70eebb6b2 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2296,15 +2296,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
* so bdget() can't fail.
*/
bdget(pd->bdev->bd_dev);
- if ((ret = blkdev_get(pd->bdev, FMODE_READ)))
+ if ((ret = blkdev_get(pd->bdev, FMODE_READ | FMODE_EXCL, pd)))
goto out;
- if ((ret = bd_claim(pd->bdev, pd)))
- goto out_putdev;
-
if ((ret = pkt_get_last_written(pd, &lba))) {
printk(DRIVER_NAME": pkt_get_last_written failed\n");
- goto out_unclaim;
+ goto out_putdev;
}
set_capacity(pd->disk, lba << 2);
@@ -2314,7 +2311,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
q = bdev_get_queue(pd->bdev);
if (write) {
if ((ret = pkt_open_write(pd)))
- goto out_unclaim;
+ goto out_putdev;
/*
* Some CDRW drives can not handle writes larger than one packet,
* even if the size is a multiple of the packet size.
@@ -2329,23 +2326,21 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
}
if ((ret = pkt_set_segment_merging(pd, q)))
- goto out_unclaim;
+ goto out_putdev;
if (write) {
if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
printk(DRIVER_NAME": not enough memory for buffers\n");
ret = -ENOMEM;
- goto out_unclaim;
+ goto out_putdev;
}
printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
}
return 0;
-out_unclaim:
- bd_release(pd->bdev);
out_putdev:
- blkdev_put(pd->bdev, FMODE_READ);
+ blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
out:
return ret;
}
@@ -2362,8 +2357,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
pkt_lock_door(pd, 0);
pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
- bd_release(pd->bdev);
- blkdev_put(pd->bdev, FMODE_READ);
+ blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
pkt_shrink_pktlist(pd);
}
@@ -2733,7 +2727,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
bdev = bdget(dev);
if (!bdev)
return -ENOMEM;
- ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY);
+ ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
if (ret)
return ret;
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 6ec9d53806c5..e1e38b11f48a 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -21,80 +21,9 @@
- Instructions for use
- --------------------
+ For usage instructions, please refer to:
- 1) Map a Linux block device to an existing rbd image.
-
- Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
-
- $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add
-
- The snapshot name can be "-" or omitted to map the image read/write.
-
- 2) List all active blkdev<->object mappings.
-
- In this example, we have performed step #1 twice, creating two blkdevs,
- mapped to two separate rados objects in the rados rbd pool
-
- $ cat /sys/class/rbd/list
- #id major client_name pool name snap KB
- 0 254 client4143 rbd foo - 1024000
-
- The columns, in order, are:
- - blkdev unique id
- - blkdev assigned major
- - rados client id
- - rados pool name
- - rados block device name
- - mapped snapshot ("-" if none)
- - device size in KB
-
-
- 3) Create a snapshot.
-
- Usage: <blkdev id> <snapname>
-
- $ echo "0 mysnap" > /sys/class/rbd/snap_create
-
-
- 4) Listing a snapshot.
-
- $ cat /sys/class/rbd/snaps_list
- #id snap KB
- 0 - 1024000 (*)
- 0 foo 1024000
-
- The columns, in order, are:
- - blkdev unique id
- - snapshot name, '-' means none (active read/write version)
- - size of device at time of snapshot
- - the (*) indicates this is the active version
-
- 5) Rollback to snapshot.
-
- Usage: <blkdev id> <snapname>
-
- $ echo "0 mysnap" > /sys/class/rbd/snap_rollback
-
-
- 6) Mapping an image using snapshot.
-
- A snapshot mapping is read-only. This is being done by passing
- snap=<snapname> to the options when adding a device.
-
- $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add
-
-
- 7) Remove an active blkdev<->rbd image mapping.
-
- In this example, we remove the mapping with blkdev unique id 1.
-
- $ echo 1 > /sys/class/rbd/remove
-
-
- NOTE: The actual creation and deletion of rados objects is outside the scope
- of this driver.
+ Documentation/ABI/testing/sysfs-bus-rbd
*/
@@ -163,6 +92,14 @@ struct rbd_request {
u64 len;
};
+struct rbd_snap {
+ struct device dev;
+ const char *name;
+ size_t size;
+ struct list_head node;
+ u64 id;
+};
+
/*
* a single device
*/
@@ -193,21 +130,60 @@ struct rbd_device {
int read_only;
struct list_head node;
+
+ /* list of snapshots */
+ struct list_head snaps;
+
+ /* sysfs related */
+ struct device dev;
+};
+
+static struct bus_type rbd_bus_type = {
+ .name = "rbd",
};
static spinlock_t node_lock; /* protects client get/put */
-static struct class *class_rbd; /* /sys/class/rbd */
static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
static LIST_HEAD(rbd_dev_list); /* devices */
static LIST_HEAD(rbd_client_list); /* clients */
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
+static void rbd_dev_release(struct device *dev);
+static ssize_t rbd_snap_rollback(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size);
+static ssize_t rbd_snap_add(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count);
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap);;
+
+
+static struct rbd_device *dev_to_rbd(struct device *dev)
+{
+ return container_of(dev, struct rbd_device, dev);
+}
+
+static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
+{
+ return get_device(&rbd_dev->dev);
+}
+
+static void rbd_put_dev(struct rbd_device *rbd_dev)
+{
+ put_device(&rbd_dev->dev);
+}
static int rbd_open(struct block_device *bdev, fmode_t mode)
{
struct gendisk *disk = bdev->bd_disk;
struct rbd_device *rbd_dev = disk->private_data;
+ rbd_get_dev(rbd_dev);
+
set_device_ro(bdev, rbd_dev->read_only);
if ((mode & FMODE_WRITE) && rbd_dev->read_only)
@@ -216,9 +192,19 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
return 0;
}
+static int rbd_release(struct gendisk *disk, fmode_t mode)
+{
+ struct rbd_device *rbd_dev = disk->private_data;
+
+ rbd_put_dev(rbd_dev);
+
+ return 0;
+}
+
static const struct block_device_operations rbd_bd_ops = {
.owner = THIS_MODULE,
.open = rbd_open,
+ .release = rbd_release,
};
/*
@@ -361,7 +347,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
int ret = -ENOMEM;
init_rwsem(&header->snap_rwsem);
-
header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
snap_count *
@@ -1256,10 +1241,20 @@ bad:
return -ERANGE;
}
+static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev)
+{
+ struct rbd_snap *snap;
+
+ while (!list_empty(&rbd_dev->snaps)) {
+ snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node);
+ __rbd_remove_snap_dev(rbd_dev, snap);
+ }
+}
+
/*
* only read the first part of the ondisk header, without the snaps info
*/
-static int rbd_update_snaps(struct rbd_device *rbd_dev)
+static int __rbd_update_snaps(struct rbd_device *rbd_dev)
{
int ret;
struct rbd_image_header h;
@@ -1280,12 +1275,15 @@ static int rbd_update_snaps(struct rbd_device *rbd_dev)
rbd_dev->header.total_snaps = h.total_snaps;
rbd_dev->header.snapc = h.snapc;
rbd_dev->header.snap_names = h.snap_names;
+ rbd_dev->header.snap_names_len = h.snap_names_len;
rbd_dev->header.snap_sizes = h.snap_sizes;
rbd_dev->header.snapc->seq = snap_seq;
+ ret = __rbd_init_snaps_header(rbd_dev);
+
up_write(&rbd_dev->header.snap_rwsem);
- return 0;
+ return ret;
}
static int rbd_init_disk(struct rbd_device *rbd_dev)
@@ -1300,6 +1298,11 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (rc)
return rc;
+ /* no need to lock here, as rbd_dev is not registered yet */
+ rc = __rbd_init_snaps_header(rbd_dev);
+ if (rc)
+ return rc;
+
rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
if (rc)
return rc;
@@ -1343,54 +1346,360 @@ out:
return rc;
}
-/********************************************************************
- * /sys/class/rbd/
- * add map rados objects to blkdev
- * remove unmap rados objects
- * list show mappings
- *******************************************************************/
+/*
+ sysfs
+*/
-static void class_rbd_release(struct class *cls)
+static ssize_t rbd_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- kfree(cls);
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
}
-static ssize_t class_rbd_list(struct class *c,
- struct class_attribute *attr,
- char *data)
+static ssize_t rbd_major_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int n = 0;
- struct list_head *tmp;
- int max = PAGE_SIZE;
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%d\n", rbd_dev->major);
+}
+
+static ssize_t rbd_client_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
+}
+
+static ssize_t rbd_pool_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->pool_name);
+}
+
+static ssize_t rbd_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->obj);
+}
+
+static ssize_t rbd_snap_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->snap_name);
+}
+
+static ssize_t rbd_image_refresh(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int rc;
+ int ret = size;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- n += snprintf(data, max,
- "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n");
+ rc = __rbd_update_snaps(rbd_dev);
+ if (rc < 0)
+ ret = rc;
- list_for_each(tmp, &rbd_dev_list) {
- struct rbd_device *rbd_dev;
+ mutex_unlock(&ctl_mutex);
+ return ret;
+}
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- n += snprintf(data+n, max-n,
- "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n",
- rbd_dev->id,
- rbd_dev->major,
- ceph_client_id(rbd_dev->client),
- rbd_dev->pool_name,
- rbd_dev->obj, rbd_dev->snap_name,
- rbd_dev->header.image_size >> 10);
- if (n == max)
+static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
+static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
+static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
+static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
+static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
+static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
+static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
+static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add);
+static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback);
+
+static struct attribute *rbd_attrs[] = {
+ &dev_attr_size.attr,
+ &dev_attr_major.attr,
+ &dev_attr_client_id.attr,
+ &dev_attr_pool.attr,
+ &dev_attr_name.attr,
+ &dev_attr_current_snap.attr,
+ &dev_attr_refresh.attr,
+ &dev_attr_create_snap.attr,
+ &dev_attr_rollback_snap.attr,
+ NULL
+};
+
+static struct attribute_group rbd_attr_group = {
+ .attrs = rbd_attrs,
+};
+
+static const struct attribute_group *rbd_attr_groups[] = {
+ &rbd_attr_group,
+ NULL
+};
+
+static void rbd_sysfs_dev_release(struct device *dev)
+{
+}
+
+static struct device_type rbd_device_type = {
+ .name = "rbd",
+ .groups = rbd_attr_groups,
+ .release = rbd_sysfs_dev_release,
+};
+
+
+/*
+ sysfs - snapshots
+*/
+
+static ssize_t rbd_snap_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+ return sprintf(buf, "%lld\n", (long long)snap->size);
+}
+
+static ssize_t rbd_snap_id_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+ return sprintf(buf, "%lld\n", (long long)snap->id);
+}
+
+static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
+static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL);
+
+static struct attribute *rbd_snap_attrs[] = {
+ &dev_attr_snap_size.attr,
+ &dev_attr_snap_id.attr,
+ NULL,
+};
+
+static struct attribute_group rbd_snap_attr_group = {
+ .attrs = rbd_snap_attrs,
+};
+
+static void rbd_snap_dev_release(struct device *dev)
+{
+ struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+ kfree(snap->name);
+ kfree(snap);
+}
+
+static const struct attribute_group *rbd_snap_attr_groups[] = {
+ &rbd_snap_attr_group,
+ NULL
+};
+
+static struct device_type rbd_snap_device_type = {
+ .groups = rbd_snap_attr_groups,
+ .release = rbd_snap_dev_release,
+};
+
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap)
+{
+ list_del(&snap->node);
+ device_unregister(&snap->dev);
+}
+
+static int rbd_register_snap_dev(struct rbd_device *rbd_dev,
+ struct rbd_snap *snap,
+ struct device *parent)
+{
+ struct device *dev = &snap->dev;
+ int ret;
+
+ dev->type = &rbd_snap_device_type;
+ dev->parent = parent;
+ dev->release = rbd_snap_dev_release;
+ dev_set_name(dev, "snap_%s", snap->name);
+ ret = device_register(dev);
+
+ return ret;
+}
+
+static int __rbd_add_snap_dev(struct rbd_device *rbd_dev,
+ int i, const char *name,
+ struct rbd_snap **snapp)
+{
+ int ret;
+ struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL);
+ if (!snap)
+ return -ENOMEM;
+ snap->name = kstrdup(name, GFP_KERNEL);
+ snap->size = rbd_dev->header.snap_sizes[i];
+ snap->id = rbd_dev->header.snapc->snaps[i];
+ if (device_is_registered(&rbd_dev->dev)) {
+ ret = rbd_register_snap_dev(rbd_dev, snap,
+ &rbd_dev->dev);
+ if (ret < 0)
+ goto err;
+ }
+ *snapp = snap;
+ return 0;
+err:
+ kfree(snap->name);
+ kfree(snap);
+ return ret;
+}
+
+/*
+ * search for the previous snap in a null delimited string list
+ */
+const char *rbd_prev_snap_name(const char *name, const char *start)
+{
+ if (name < start + 2)
+ return NULL;
+
+ name -= 2;
+ while (*name) {
+ if (name == start)
+ return start;
+ name--;
+ }
+ return name + 1;
+}
+
+/*
+ * compare the old list of snapshots that we have to what's in the header
+ * and update it accordingly. Note that the header holds the snapshots
+ * in a reverse order (from newest to oldest) and we need to go from
+ * older to new so that we don't get a duplicate snap name when
+ * doing the process (e.g., removed snapshot and recreated a new
+ * one with the same name.
+ */
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
+{
+ const char *name, *first_name;
+ int i = rbd_dev->header.total_snaps;
+ struct rbd_snap *snap, *old_snap = NULL;
+ int ret;
+ struct list_head *p, *n;
+
+ first_name = rbd_dev->header.snap_names;
+ name = first_name + rbd_dev->header.snap_names_len;
+
+ list_for_each_prev_safe(p, n, &rbd_dev->snaps) {
+ u64 cur_id;
+
+ old_snap = list_entry(p, struct rbd_snap, node);
+
+ if (i)
+ cur_id = rbd_dev->header.snapc->snaps[i - 1];
+
+ if (!i || old_snap->id < cur_id) {
+ /* old_snap->id was skipped, thus was removed */
+ __rbd_remove_snap_dev(rbd_dev, old_snap);
+ continue;
+ }
+ if (old_snap->id == cur_id) {
+ /* we have this snapshot already */
+ i--;
+ name = rbd_prev_snap_name(name, first_name);
+ continue;
+ }
+ for (; i > 0;
+ i--, name = rbd_prev_snap_name(name, first_name)) {
+ if (!name) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ cur_id = rbd_dev->header.snapc->snaps[i];
+ /* snapshot removal? handle it above */
+ if (cur_id >= old_snap->id)
+ break;
+ /* a new snapshot */
+ ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+ if (ret < 0)
+ return ret;
+
+ /* note that we add it backward so using n and not p */
+ list_add(&snap->node, n);
+ p = &snap->node;
+ }
+ }
+ /* we're done going over the old snap list, just add what's left */
+ for (; i > 0; i--) {
+ name = rbd_prev_snap_name(name, first_name);
+ if (!name) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+ if (ret < 0)
+ return ret;
+ list_add(&snap->node, &rbd_dev->snaps);
+ }
+
+ return 0;
+}
+
+
+static void rbd_root_dev_release(struct device *dev)
+{
+}
+
+static struct device rbd_root_dev = {
+ .init_name = "rbd",
+ .release = rbd_root_dev_release,
+};
+
+static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
+{
+ int ret = -ENOMEM;
+ struct device *dev;
+ struct rbd_snap *snap;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ dev = &rbd_dev->dev;
+
+ dev->bus = &rbd_bus_type;
+ dev->type = &rbd_device_type;
+ dev->parent = &rbd_root_dev;
+ dev->release = rbd_dev_release;
+ dev_set_name(dev, "%d", rbd_dev->id);
+ ret = device_register(dev);
+ if (ret < 0)
+ goto done_free;
+
+ list_for_each_entry(snap, &rbd_dev->snaps, node) {
+ ret = rbd_register_snap_dev(rbd_dev, snap,
+ &rbd_dev->dev);
+ if (ret < 0)
break;
}
mutex_unlock(&ctl_mutex);
- return n;
+ return 0;
+done_free:
+ mutex_unlock(&ctl_mutex);
+ return ret;
}
-static ssize_t class_rbd_add(struct class *c,
- struct class_attribute *attr,
- const char *buf, size_t count)
+static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
+{
+ device_unregister(&rbd_dev->dev);
+}
+
+static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count)
{
struct ceph_osd_client *osdc;
struct rbd_device *rbd_dev;
@@ -1419,6 +1728,7 @@ static ssize_t class_rbd_add(struct class *c,
/* static rbd_device initialization */
spin_lock_init(&rbd_dev->lock);
INIT_LIST_HEAD(&rbd_dev->node);
+ INIT_LIST_HEAD(&rbd_dev->snaps);
/* generate unique id: find highest unique id, add one */
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
@@ -1478,13 +1788,29 @@ static ssize_t class_rbd_add(struct class *c,
}
rbd_dev->major = irc;
+ rc = rbd_bus_add_dev(rbd_dev);
+ if (rc)
+ goto err_out_blkdev;
+
/* set up and announce blkdev mapping */
rc = rbd_init_disk(rbd_dev);
if (rc)
- goto err_out_blkdev;
+ goto err_out_bus;
return count;
+err_out_bus:
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ list_del_init(&rbd_dev->node);
+ mutex_unlock(&ctl_mutex);
+
+ /* this will also clean up rest of rbd_dev stuff */
+
+ rbd_bus_del_dev(rbd_dev);
+ kfree(options);
+ kfree(mon_dev_name);
+ return rc;
+
err_out_blkdev:
unregister_blkdev(rbd_dev->major, rbd_dev->name);
err_out_client:
@@ -1518,35 +1844,10 @@ static struct rbd_device *__rbd_get_dev(unsigned long id)
return NULL;
}
-static ssize_t class_rbd_remove(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static void rbd_dev_release(struct device *dev)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, rc;
- unsigned long ul;
-
- rc = strict_strtoul(buf, 10, &ul);
- if (rc)
- return rc;
-
- /* convert to int; abort if we lost anything in the conversion */
- target_id = (int) ul;
- if (target_id != ul)
- return -EINVAL;
-
- /* remove object from list immediately */
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- rbd_dev = __rbd_get_dev(target_id);
- if (rbd_dev)
- list_del_init(&rbd_dev->node);
-
- mutex_unlock(&ctl_mutex);
-
- if (!rbd_dev)
- return -ENOENT;
+ struct rbd_device *rbd_dev =
+ container_of(dev, struct rbd_device, dev);
rbd_put_client(rbd_dev);
@@ -1557,67 +1858,11 @@ static ssize_t class_rbd_remove(struct class *c,
/* release module ref */
module_put(THIS_MODULE);
-
- return count;
-}
-
-static ssize_t class_rbd_snaps_list(struct class *c,
- struct class_attribute *attr,
- char *data)
-{
- struct rbd_device *rbd_dev = NULL;
- struct list_head *tmp;
- struct rbd_image_header *header;
- int i, n = 0, max = PAGE_SIZE;
- int ret;
-
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- n += snprintf(data, max, "#id\tsnap\tKB\n");
-
- list_for_each(tmp, &rbd_dev_list) {
- char *names, *p;
- struct ceph_snap_context *snapc;
-
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- header = &rbd_dev->header;
-
- down_read(&header->snap_rwsem);
-
- names = header->snap_names;
- snapc = header->snapc;
-
- n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
- rbd_dev->id, RBD_SNAP_HEAD_NAME,
- header->image_size >> 10,
- (!rbd_dev->cur_snap ? " (*)" : ""));
- if (n == max)
- break;
-
- p = names;
- for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
- n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
- rbd_dev->id, p, header->snap_sizes[i] >> 10,
- (rbd_dev->cur_snap &&
- (snap_index(header, i) == rbd_dev->cur_snap) ?
- " (*)" : ""));
- if (n == max)
- break;
- }
-
- up_read(&header->snap_rwsem);
- }
-
-
- ret = n;
- mutex_unlock(&ctl_mutex);
- return ret;
}
-static ssize_t class_rbd_snaps_refresh(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_remove(struct bus_type *bus,
+ const char *buf,
+ size_t count)
{
struct rbd_device *rbd_dev = NULL;
int target_id, rc;
@@ -1641,95 +1886,70 @@ static ssize_t class_rbd_snaps_refresh(struct class *c,
goto done;
}
- rc = rbd_update_snaps(rbd_dev);
- if (rc < 0)
- ret = rc;
+ list_del_init(&rbd_dev->node);
+
+ __rbd_remove_all_snaps(rbd_dev);
+ rbd_bus_del_dev(rbd_dev);
done:
mutex_unlock(&ctl_mutex);
return ret;
}
-static ssize_t class_rbd_snap_create(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_snap_add(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, ret;
- char *name;
-
- name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL);
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int ret;
+ char *name = kmalloc(count + 1, GFP_KERNEL);
if (!name)
return -ENOMEM;
- /* parse snaps add command */
- if (sscanf(buf, "%d "
- "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
- &target_id,
- name) != 2) {
- ret = -EINVAL;
- goto done;
- }
+ snprintf(name, count, "%s", buf);
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- rbd_dev = __rbd_get_dev(target_id);
- if (!rbd_dev) {
- ret = -ENOENT;
- goto done_unlock;
- }
-
ret = rbd_header_add_snap(rbd_dev,
name, GFP_KERNEL);
if (ret < 0)
goto done_unlock;
- ret = rbd_update_snaps(rbd_dev);
+ ret = __rbd_update_snaps(rbd_dev);
if (ret < 0)
goto done_unlock;
ret = count;
done_unlock:
mutex_unlock(&ctl_mutex);
-done:
kfree(name);
return ret;
}
-static ssize_t class_rbd_rollback(struct class *c,
- struct class_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t rbd_snap_rollback(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
- struct rbd_device *rbd_dev = NULL;
- int target_id, ret;
+ struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ int ret;
u64 snapid;
- char snap_name[RBD_MAX_SNAP_NAME_LEN];
u64 cur_ofs;
- char *seg_name;
+ char *seg_name = NULL;
+ char *snap_name = kmalloc(count + 1, GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!snap_name)
+ return ret;
/* parse snaps add command */
- if (sscanf(buf, "%d "
- "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
- &target_id,
- snap_name) != 2) {
- return -EINVAL;
- }
-
- ret = -ENOMEM;
+ snprintf(snap_name, count, "%s", buf);
seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
if (!seg_name)
- return ret;
+ goto done;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- rbd_dev = __rbd_get_dev(target_id);
- if (!rbd_dev) {
- ret = -ENOENT;
- goto done_unlock;
- }
-
ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL);
if (ret < 0)
goto done_unlock;
@@ -1750,7 +1970,7 @@ static ssize_t class_rbd_rollback(struct class *c,
seg_name, ret);
}
- ret = rbd_update_snaps(rbd_dev);
+ ret = __rbd_update_snaps(rbd_dev);
if (ret < 0)
goto done_unlock;
@@ -1758,57 +1978,42 @@ static ssize_t class_rbd_rollback(struct class *c,
done_unlock:
mutex_unlock(&ctl_mutex);
+done:
kfree(seg_name);
+ kfree(snap_name);
return ret;
}
-static struct class_attribute class_rbd_attrs[] = {
- __ATTR(add, 0200, NULL, class_rbd_add),
- __ATTR(remove, 0200, NULL, class_rbd_remove),
- __ATTR(list, 0444, class_rbd_list, NULL),
- __ATTR(snaps_refresh, 0200, NULL, class_rbd_snaps_refresh),
- __ATTR(snap_create, 0200, NULL, class_rbd_snap_create),
- __ATTR(snaps_list, 0444, class_rbd_snaps_list, NULL),
- __ATTR(snap_rollback, 0200, NULL, class_rbd_rollback),
+static struct bus_attribute rbd_bus_attrs[] = {
+ __ATTR(add, S_IWUSR, NULL, rbd_add),
+ __ATTR(remove, S_IWUSR, NULL, rbd_remove),
__ATTR_NULL
};
/*
* create control files in sysfs
- * /sys/class/rbd/...
+ * /sys/bus/rbd/...
*/
static int rbd_sysfs_init(void)
{
- int ret = -ENOMEM;
+ int ret;
- class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL);
- if (!class_rbd)
- goto out;
+ rbd_bus_type.bus_attrs = rbd_bus_attrs;
- class_rbd->name = DRV_NAME;
- class_rbd->owner = THIS_MODULE;
- class_rbd->class_release = class_rbd_release;
- class_rbd->class_attrs = class_rbd_attrs;
+ ret = bus_register(&rbd_bus_type);
+ if (ret < 0)
+ return ret;
- ret = class_register(class_rbd);
- if (ret)
- goto out_class;
- return 0;
+ ret = device_register(&rbd_root_dev);
-out_class:
- kfree(class_rbd);
- class_rbd = NULL;
- pr_err(DRV_NAME ": failed to create class rbd\n");
-out:
return ret;
}
static void rbd_sysfs_cleanup(void)
{
- if (class_rbd)
- class_destroy(class_rbd);
- class_rbd = NULL;
+ device_unregister(&rbd_root_dev);
+ bus_unregister(&rbd_bus_type);
}
int __init rbd_init(void)
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 06e2812ba124..d7aa39e349a6 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -65,14 +65,14 @@ enum blkif_state {
struct blk_shadow {
struct blkif_request req;
- unsigned long request;
+ struct request *request;
unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
};
static DEFINE_MUTEX(blkfront_mutex);
static const struct block_device_operations xlvbd_block_fops;
-#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
/*
* We have one of these per vbd, whether ide, scsi or 'other'. They
@@ -136,7 +136,7 @@ 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[id].request = NULL;
info->shadow_free = id;
}
@@ -245,14 +245,11 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
}
/*
- * blkif_queue_request
+ * Generate a Xen blkfront IO request from a blk layer request. Reads
+ * and writes are handled as expected. Since we lack a loose flush
+ * request, we map flushes into a full ordered barrier.
*
- * 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.
+ * @req: a request struct
*/
static int blkif_queue_request(struct request *req)
{
@@ -281,7 +278,7 @@ static int blkif_queue_request(struct request *req)
/* 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;
+ info->shadow[id].request = req;
ring_req->id = id;
ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
@@ -289,8 +286,18 @@ static int blkif_queue_request(struct request *req)
ring_req->operation = rq_data_dir(req) ?
BLKIF_OP_WRITE : BLKIF_OP_READ;
- if (req->cmd_flags & REQ_HARDBARRIER)
+
+ if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+ /*
+ * Ideally we could just do an unordered
+ * flush-to-disk, but all we have is a full write
+ * barrier at the moment. However, a barrier write is
+ * a superset of FUA, so we can implement it the same
+ * way. (It's also a FLUSH+FUA, since it is
+ * guaranteed ordered WRT previous writes.)
+ */
ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+ }
ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
@@ -540,7 +547,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)
spin_unlock_irqrestore(&blkif_io_lock, flags);
/* Flush gnttab callback work. Must be done with no locks held. */
- flush_scheduled_work();
+ flush_work_sync(&info->work);
del_gendisk(info->gd);
@@ -589,7 +596,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
spin_unlock_irq(&blkif_io_lock);
/* Flush gnttab callback work. Must be done with no locks held. */
- flush_scheduled_work();
+ flush_work_sync(&info->work);
/* Free resources associated with old device channel. */
if (info->ring_ref != GRANT_INVALID_REF) {
@@ -636,7 +643,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
bret = RING_GET_RESPONSE(&info->ring, i);
id = bret->id;
- req = (struct request *)info->shadow[id].request;
+ req = info->shadow[id].request;
blkif_completion(&info->shadow[id]);
@@ -649,6 +656,16 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
info->gd->disk_name);
error = -EOPNOTSUPP;
+ }
+ if (unlikely(bret->status == BLKIF_RSP_ERROR &&
+ info->shadow[id].req.nr_segments == 0)) {
+ printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n",
+ info->gd->disk_name);
+ error = -EOPNOTSUPP;
+ }
+ if (unlikely(error)) {
+ if (error == -EOPNOTSUPP)
+ error = 0;
info->feature_flush = 0;
xlvbd_flush(info);
}
@@ -901,7 +918,7 @@ static int blkif_recover(struct blkfront_info *info)
/* Stage 3: Find pending requests and requeue them. */
for (i = 0; i < BLK_RING_SIZE; i++) {
/* Not in use? */
- if (copy[i].request == 0)
+ if (!copy[i].request)
continue;
/* Grab a request slot and copy shadow state into it. */
@@ -918,9 +935,7 @@ static int blkif_recover(struct blkfront_info *info)
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));
+ rq_data_dir(info->shadow[req->id].request));
info->shadow[req->id].req = *req;
info->ring.req_prod_pvt++;
@@ -1069,14 +1084,8 @@ static void blkfront_connect(struct blkfront_info *info)
*/
info->feature_flush = 0;
- /*
- * The driver doesn't properly handled empty flushes, so
- * lets disable barrier support for now.
- */
-#if 0
if (!err && barrier)
- info->feature_flush = REQ_FLUSH;
-#endif
+ info->feature_flush = REQ_FLUSH | REQ_FUA;
err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
if (err) {
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 128cae4e8629..949ed09c6361 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -35,6 +35,10 @@
static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */
{ USB_DEVICE(0x0CF3, 0x3000) },
+
+ /* Atheros AR3011 with sflash firmware*/
+ { USB_DEVICE(0x0CF3, 0x3002) },
+
{ } /* Terminating entry */
};
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d120a5c1c093..1da773f899a2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -68,6 +68,9 @@ static struct usb_device_id btusb_table[] = {
/* Apple MacBookPro6,2 */
{ USB_DEVICE(0x05ac, 0x8218) },
+ /* Apple MacBookAir3,1, MacBookAir3,2 */
+ { USB_DEVICE(0x05ac, 0x821b) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
@@ -96,6 +99,9 @@ static struct usb_device_id blacklist_table[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
+ /* Atheros 3011 with sflash firmware */
+ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -236,7 +242,8 @@ static void btusb_intr_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -320,7 +327,8 @@ static void btusb_bulk_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -409,7 +417,8 @@ static void btusb_isoc_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- BT_ERR("%s urb %p failed to resubmit (%d)",
+ if (err != -EPERM)
+ BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -1029,6 +1038,8 @@ static int btusb_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
+ usb_enable_autosuspend(interface_to_usbdev(intf));
+
return 0;
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 720148294e64..3c6cabcb7d84 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -311,8 +311,10 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
hu->proto->close(hu);
- hci_unregister_dev(hdev);
- hci_free_dev(hdev);
+ if (hdev) {
+ hci_unregister_dev(hdev);
+ hci_free_dev(hdev);
+ }
}
}
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index af13c62dc473..14033a36bcd0 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
if (!CDROM_CAN(CDC_SELECT_DISC))
return -EDRIVE_CANT_DO_THIS;
- (void) cdi->ops->media_changed(cdi, slot);
+ if (cdi->ops->check_events)
+ cdi->ops->check_events(cdi, 0, slot);
+ else
+ cdi->ops->media_changed(cdi, slot);
if (slot == CDSL_NONE) {
/* set media changed bits, on both queues */
@@ -1392,6 +1395,42 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
return slot;
}
+/*
+ * As cdrom implements an extra ioctl consumer for media changed
+ * event, it needs to buffer ->check_events() output, such that event
+ * is not lost for both the usual VFS and ioctl paths.
+ * cdi->{vfs|ioctl}_events are used to buffer pending events for each
+ * path.
+ *
+ * XXX: Locking is non-existent. cdi->ops->check_events() can be
+ * called in parallel and buffering fields are accessed without any
+ * exclusion. The original media_changed code had the same problem.
+ * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl
+ * and remove this cruft altogether. It doesn't have much usefulness
+ * at this point.
+ */
+static void cdrom_update_events(struct cdrom_device_info *cdi,
+ unsigned int clearing)
+{
+ unsigned int events;
+
+ events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT);
+ cdi->vfs_events |= events;
+ cdi->ioctl_events |= events;
+}
+
+unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
+ unsigned int clearing)
+{
+ unsigned int events;
+
+ cdrom_update_events(cdi, clearing);
+ events = cdi->vfs_events;
+ cdi->vfs_events = 0;
+ return events;
+}
+EXPORT_SYMBOL(cdrom_check_events);
+
/* We want to make media_changed accessible to the user through an
* ioctl. The main problem now is that we must double-buffer the
* low-level implementation, to assure that the VFS and the user both
@@ -1403,15 +1442,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
{
unsigned int mask = (1 << (queue & 1));
int ret = !!(cdi->mc_flags & mask);
+ bool changed;
if (!CDROM_CAN(CDC_MEDIA_CHANGED))
- return ret;
+ return ret;
+
/* changed since last call? */
- if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
+ if (cdi->ops->check_events) {
+ BUG_ON(!queue); /* shouldn't be called from VFS path */
+ cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
+ changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
+ cdi->ioctl_events = 0;
+ } else
+ changed = cdi->ops->media_changed(cdi, CDSL_CURRENT);
+
+ if (changed) {
cdi->mc_flags = 0x3; /* set bit on both queues */
ret |= 1;
cdi->media_written = 0;
}
+
cdi->mc_flags &= ~mask; /* clear bit */
return ret;
}
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index de65915308fb..64a21461c408 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -837,7 +837,7 @@ probe_fail_no_mem:
static int __devexit remove_gdrom(struct platform_device *devptr)
{
- flush_scheduled_work();
+ flush_work_sync(&work);
blk_cleanup_queue(gd.gdrom_rq);
free_irq(HW_EVENT_GDROM_CMD, &gd);
free_irq(HW_EVENT_GDROM_DMA, &gd);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d3395325c5..0f175a866ef0 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -682,6 +682,15 @@ config HVC_UDBG
select HVC_DRIVER
default n
+config HVC_DCC
+ bool "ARM JTAG DCC console"
+ depends on ARM
+ select HVC_DRIVER
+ help
+ This console uses the JTAG DCC on ARM to create a console under the HVC
+ driver. This console is used through a JTAG only on ARM. If you don't have
+ a JTAG then you probably don't want this option.
+
config VIRTIO_CONSOLE
tristate "Virtio console"
depends on VIRTIO
@@ -1038,15 +1047,6 @@ config NSC_GPIO
pc8736x_gpio drivers. If those drivers are built as
modules, this one will be too, named nsc_gpio
-config CS5535_GPIO
- tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
- depends on X86_32
- help
- Give userspace access to the GPIO pins on the AMD CS5535 and
- CS5536 Geode companion devices.
-
- If compiled as a module, it will be called cs5535_gpio.
-
config RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN)"
depends on BLOCK
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 3a9c01416839..1e9dffb33778 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -2,24 +2,10 @@
# Makefile for the kernel character device drivers.
#
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y += tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS) += pty.o
-obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-y += mem.o random.o
obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
-obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
-obj-$(CONFIG_AUDIT) += tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
@@ -41,8 +27,6 @@ obj-$(CONFIG_ISI) += isicom.o
obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
-obj-$(CONFIG_N_HDLC) += n_hdlc.o
-obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
@@ -50,6 +34,7 @@ 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_TILE) += hvc_tile.o
+obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
@@ -74,7 +59,6 @@ obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_APM_EMULATION) += apm-emulation.o
obj-$(CONFIG_DTLK) += dtlk.o
-obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
obj-$(CONFIG_SONYPI) += sonypi.o
obj-$(CONFIG_RTC) += rtc.o
@@ -98,7 +82,6 @@ obj-$(CONFIG_NWFLASH) += nwflash.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
-obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
@@ -115,28 +98,3 @@ obj-$(CONFIG_RAMOOPS) += ramoops.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
-
-quiet_cmd_conmk = CONMK $@
- cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
- $(call cmd,conmk)
-
-$(obj)/defkeymap.o: $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
- loadkeys --mktable $< > $@.tmp
- sed -e 's/^static *//' $@.tmp > $@
- rm $@.tmp
-
-endif
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 5259065f3c79..3e67ddde9e16 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -120,7 +120,6 @@ struct agp_bridge_driver {
void (*agp_destroy_page)(struct page *, int flags);
void (*agp_destroy_pages)(struct agp_memory *);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
- void (*chipset_flush)(struct agp_bridge_data *);
};
struct agp_bridge_data {
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 42396df55556..9252e85706ef 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -38,7 +38,7 @@ static int agp_bridges_found;
static void amd64_tlbflush(struct agp_memory *temp)
{
- k8_flush_garts();
+ amd_flush_garts();
}
static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
@@ -124,7 +124,7 @@ static int amd64_fetch_size(void)
u32 temp;
struct aper_size_info_32 *values;
- dev = k8_northbridges.nb_misc[0];
+ dev = node_to_amd_nb(0)->misc;
if (dev==NULL)
return 0;
@@ -181,16 +181,15 @@ static int amd_8151_configure(void)
unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
int i;
- if (!k8_northbridges.gart_supported)
+ if (!amd_nb_has_feature(AMD_NB_GART))
return 0;
/* Configure AGP regs in each x86-64 host bridge. */
- for (i = 0; i < k8_northbridges.num; i++) {
+ for (i = 0; i < amd_nb_num(); i++) {
agp_bridge->gart_bus_addr =
- amd64_configure(k8_northbridges.nb_misc[i],
- gatt_bus);
+ amd64_configure(node_to_amd_nb(i)->misc, gatt_bus);
}
- k8_flush_garts();
+ amd_flush_garts();
return 0;
}
@@ -200,11 +199,11 @@ static void amd64_cleanup(void)
u32 tmp;
int i;
- if (!k8_northbridges.gart_supported)
+ if (!amd_nb_has_feature(AMD_NB_GART))
return;
- for (i = 0; i < k8_northbridges.num; i++) {
- struct pci_dev *dev = k8_northbridges.nb_misc[i];
+ for (i = 0; i < amd_nb_num(); i++) {
+ struct pci_dev *dev = node_to_amd_nb(i)->misc;
/* disable gart translation */
pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
tmp &= ~GARTEN;
@@ -331,15 +330,15 @@ static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
{
int i;
- if (cache_k8_northbridges() < 0)
+ if (amd_cache_northbridges() < 0)
return -ENODEV;
- if (!k8_northbridges.gart_supported)
+ if (!amd_nb_has_feature(AMD_NB_GART))
return -ENODEV;
i = 0;
- for (i = 0; i < k8_northbridges.num; i++) {
- struct pci_dev *dev = k8_northbridges.nb_misc[i];
+ for (i = 0; i < amd_nb_num(); i++) {
+ struct pci_dev *dev = node_to_amd_nb(i)->misc;
if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
dev_err(&dev->dev, "no usable aperture found\n");
#ifdef __x86_64__
@@ -416,7 +415,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
}
/* shadow x86-64 registers into ULi registers */
- pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+ pci_read_config_dword (node_to_amd_nb(0)->misc, AMD64_GARTAPERTUREBASE,
&httfea);
/* if x86-64 aperture base is beyond 4G, exit here */
@@ -484,7 +483,7 @@ static int nforce3_agp_init(struct pci_dev *pdev)
pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
/* shadow x86-64 registers into NVIDIA registers */
- pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+ pci_read_config_dword (node_to_amd_nb(0)->misc, AMD64_GARTAPERTUREBASE,
&apbase);
/* if x86-64 aperture base is beyond 4G, exit here */
@@ -778,7 +777,7 @@ int __init agp_amd64_init(void)
}
/* First check that we have at least one AMD64 NB */
- if (!pci_dev_present(k8_nb_ids))
+ if (!pci_dev_present(amd_nb_misc_ids))
return -ENODEV;
/* Look for any AGP bridge */
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
index 9d2c97a69cdd..a48e05b31593 100644
--- a/drivers/char/agp/compat_ioctl.c
+++ b/drivers/char/agp/compat_ioctl.c
@@ -276,7 +276,6 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case AGPIOC_CHIPSET_FLUSH32:
- ret_val = agpioc_chipset_flush_wrap(curr_priv);
break;
}
diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h
index 0c9678ac0371..f30e0fd97963 100644
--- a/drivers/char/agp/compat_ioctl.h
+++ b/drivers/char/agp/compat_ioctl.h
@@ -102,6 +102,5 @@ void agp_free_memory_wrap(struct agp_memory *memory);
struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type);
struct agp_memory *agp_find_mem_by_key(int key);
struct agp_client *agp_find_client_by_pid(pid_t id);
-int agpioc_chipset_flush_wrap(struct agp_file_private *priv);
#endif /* _AGP_COMPAT_H */
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 43412c03969e..2e044338753c 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -39,7 +39,6 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include "agp.h"
@@ -958,13 +957,6 @@ static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg)
return agp_unbind_memory(memory);
}
-int agpioc_chipset_flush_wrap(struct agp_file_private *priv)
-{
- DBG("");
- agp_flush_chipset(agp_bridge);
- return 0;
-}
-
static long agp_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1040,7 +1032,6 @@ static long agp_ioctl(struct file *file,
break;
case AGPIOC_CHIPSET_FLUSH:
- ret_val = agpioc_chipset_flush_wrap(curr_priv);
break;
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 4956f1c8f9d5..012cba0d6d96 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -81,13 +81,6 @@ static int agp_get_key(void)
return -1;
}
-void agp_flush_chipset(struct agp_bridge_data *bridge)
-{
- if (bridge->driver->chipset_flush)
- bridge->driver->chipset_flush(bridge);
-}
-EXPORT_SYMBOL(agp_flush_chipset);
-
/*
* Use kmalloc if possible for the page list. Otherwise fall back to
* vmalloc. This speeds things up and also saves memory for small AGP
@@ -487,26 +480,6 @@ int agp_unbind_memory(struct agp_memory *curr)
}
EXPORT_SYMBOL(agp_unbind_memory);
-/**
- * agp_rebind_emmory - Rewrite the entire GATT, useful on resume
- */
-int agp_rebind_memory(void)
-{
- struct agp_memory *curr;
- int ret_val = 0;
-
- spin_lock(&agp_bridge->mapped_lock);
- list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) {
- ret_val = curr->bridge->driver->insert_memory(curr,
- curr->pg_start,
- curr->type);
- if (ret_val != 0)
- break;
- }
- spin_unlock(&agp_bridge->mapped_lock);
- return ret_val;
-}
-EXPORT_SYMBOL(agp_rebind_memory);
/* End - Routines for handling swapping of agp_memory into the GATT */
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index e72f49d52202..857df10c0428 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -717,8 +717,8 @@ static const struct intel_agp_driver_description {
{ PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
{ PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
{ PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
- { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
- { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
{ PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
@@ -828,14 +828,9 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
static int agp_intel_resume(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
- int ret_val;
bridge->driver->configure();
- ret_val = agp_rebind_memory();
- if (ret_val != 0)
- return ret_val;
-
return 0;
}
#endif
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 90539df02504..c195bfeade11 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -75,6 +75,8 @@
#define I810_GMS_DISABLE 0x00000000
#define I810_PGETBL_CTL 0x2020
#define I810_PGETBL_ENABLED 0x00000001
+/* Note: PGETBL_CTL2 has a different offset on G33. */
+#define I965_PGETBL_CTL2 0x20c4
#define I965_PGETBL_SIZE_MASK 0x0000000e
#define I965_PGETBL_SIZE_512KB (0 << 1)
#define I965_PGETBL_SIZE_256KB (1 << 1)
@@ -82,9 +84,17 @@
#define I965_PGETBL_SIZE_1MB (3 << 1)
#define I965_PGETBL_SIZE_2MB (4 << 1)
#define I965_PGETBL_SIZE_1_5MB (5 << 1)
-#define G33_PGETBL_SIZE_MASK (3 << 8)
-#define G33_PGETBL_SIZE_1M (1 << 8)
-#define G33_PGETBL_SIZE_2M (2 << 8)
+#define G33_GMCH_SIZE_MASK (3 << 8)
+#define G33_GMCH_SIZE_1M (1 << 8)
+#define G33_GMCH_SIZE_2M (2 << 8)
+#define G4x_GMCH_SIZE_MASK (0xf << 8)
+#define G4x_GMCH_SIZE_1M (0x1 << 8)
+#define G4x_GMCH_SIZE_2M (0x3 << 8)
+#define G4x_GMCH_SIZE_VT_1M (0x9 << 8)
+#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8)
+#define G4x_GMCH_SIZE_VT_2M (0xc << 8)
+
+#define GFX_FLSH_CNTL 0x2170 /* 915+ */
#define I810_DRAM_CTL 0x3000
#define I810_DRAM_ROW_0 0x00000001
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 6b6760ea2435..826ab0939a12 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -24,7 +24,6 @@
#include <asm/smp.h>
#include "agp.h"
#include "intel-agp.h"
-#include <linux/intel-gtt.h>
#include <drm/intel-gtt.h>
/*
@@ -39,40 +38,12 @@
#define USE_PCI_DMA_API 0
#endif
-/* Max amount of stolen space, anything above will be returned to Linux */
-int intel_max_stolen = 32 * 1024 * 1024;
-
-static const struct aper_size_info_fixed intel_i810_sizes[] =
-{
- {64, 16384, 4},
- /* The 32M mode still requires a 64k gatt */
- {32, 8192, 4}
-};
-
-#define AGP_DCACHE_MEMORY 1
-#define AGP_PHYS_MEMORY 2
-#define INTEL_AGP_CACHED_MEMORY 3
-
-static struct gatt_mask intel_i810_masks[] =
-{
- {.mask = I810_PTE_VALID, .type = 0},
- {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
- {.mask = I810_PTE_VALID, .type = 0},
- {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
- .type = INTEL_AGP_CACHED_MEMORY}
-};
-
-#define INTEL_AGP_UNCACHED_MEMORY 0
-#define INTEL_AGP_CACHED_MEMORY_LLC 1
-#define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2
-#define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3
-#define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4
-
struct intel_gtt_driver {
unsigned int gen : 8;
unsigned int is_g33 : 1;
unsigned int is_pineview : 1;
unsigned int is_ironlake : 1;
+ unsigned int has_pgtbl_enable : 1;
unsigned int dma_mask_size : 8;
/* Chipset specific GTT setup */
int (*setup)(void);
@@ -95,13 +66,14 @@ static struct _intel_private {
u8 __iomem *registers;
phys_addr_t gtt_bus_addr;
phys_addr_t gma_bus_addr;
- phys_addr_t pte_bus_addr;
+ u32 PGETBL_save;
u32 __iomem *gtt; /* I915G */
int num_dcache_entries;
union {
void __iomem *i9xx_flush_page;
void *i8xx_flush_page;
};
+ char *i81x_gtt_table;
struct page *i8xx_page;
struct resource ifp_resource;
int resource_valid;
@@ -113,42 +85,31 @@ static struct _intel_private {
#define IS_G33 intel_private.driver->is_g33
#define IS_PINEVIEW intel_private.driver->is_pineview
#define IS_IRONLAKE intel_private.driver->is_ironlake
+#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable
-static void intel_agp_free_sglist(struct agp_memory *mem)
-{
- struct sg_table st;
-
- st.sgl = mem->sg_list;
- st.orig_nents = st.nents = mem->page_count;
-
- sg_free_table(&st);
-
- mem->sg_list = NULL;
- mem->num_sg = 0;
-}
-
-static int intel_agp_map_memory(struct agp_memory *mem)
+int intel_gtt_map_memory(struct page **pages, unsigned int num_entries,
+ struct scatterlist **sg_list, int *num_sg)
{
struct sg_table st;
struct scatterlist *sg;
int i;
- if (mem->sg_list)
+ if (*sg_list)
return 0; /* already mapped (for e.g. resume */
- DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+ DBG("try mapping %lu pages\n", (unsigned long)num_entries);
- if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
+ if (sg_alloc_table(&st, num_entries, GFP_KERNEL))
goto err;
- mem->sg_list = sg = st.sgl;
+ *sg_list = sg = st.sgl;
- for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
- sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
+ for (i = 0 ; i < num_entries; i++, sg = sg_next(sg))
+ sg_set_page(sg, pages[i], PAGE_SIZE, 0);
- mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
- mem->page_count, PCI_DMA_BIDIRECTIONAL);
- if (unlikely(!mem->num_sg))
+ *num_sg = pci_map_sg(intel_private.pcidev, *sg_list,
+ num_entries, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(!*num_sg))
goto err;
return 0;
@@ -157,90 +118,22 @@ err:
sg_free_table(&st);
return -ENOMEM;
}
+EXPORT_SYMBOL(intel_gtt_map_memory);
-static void intel_agp_unmap_memory(struct agp_memory *mem)
+void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
{
+ struct sg_table st;
DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
- pci_unmap_sg(intel_private.pcidev, mem->sg_list,
- mem->page_count, PCI_DMA_BIDIRECTIONAL);
- intel_agp_free_sglist(mem);
-}
-
-static int intel_i810_fetch_size(void)
-{
- u32 smram_miscc;
- struct aper_size_info_fixed *values;
+ pci_unmap_sg(intel_private.pcidev, sg_list,
+ num_sg, PCI_DMA_BIDIRECTIONAL);
- pci_read_config_dword(intel_private.bridge_dev,
- I810_SMRAM_MISCC, &smram_miscc);
- values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
- if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
- dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
- return 0;
- }
- if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
- agp_bridge->current_size = (void *) (values + 1);
- agp_bridge->aperture_size_idx = 1;
- return values[1].size;
- } else {
- agp_bridge->current_size = (void *) (values);
- agp_bridge->aperture_size_idx = 0;
- return values[0].size;
- }
+ st.sgl = sg_list;
+ st.orig_nents = st.nents = num_sg;
- return 0;
-}
-
-static int intel_i810_configure(void)
-{
- struct aper_size_info_fixed *current_size;
- u32 temp;
- int i;
-
- current_size = A_SIZE_FIX(agp_bridge->current_size);
-
- if (!intel_private.registers) {
- pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
- temp &= 0xfff80000;
-
- intel_private.registers = ioremap(temp, 128 * 4096);
- if (!intel_private.registers) {
- dev_err(&intel_private.pcidev->dev,
- "can't remap memory\n");
- return -ENOMEM;
- }
- }
-
- if ((readl(intel_private.registers+I810_DRAM_CTL)
- & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
- /* This will need to be dynamically assigned */
- dev_info(&intel_private.pcidev->dev,
- "detected 4MB dedicated video ram\n");
- intel_private.num_dcache_entries = 1024;
- }
- pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
- readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
- if (agp_bridge->driver->needs_scratch_page) {
- for (i = 0; i < current_size->num_entries; i++) {
- writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
- }
- readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
- }
- global_cache_flush();
- return 0;
-}
-
-static void intel_i810_cleanup(void)
-{
- writel(0, intel_private.registers+I810_PGETBL_CTL);
- readl(intel_private.registers); /* PCI Posting. */
- iounmap(intel_private.registers);
+ sg_free_table(&st);
}
+EXPORT_SYMBOL(intel_gtt_unmap_memory);
static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
{
@@ -277,80 +170,64 @@ static void i8xx_destroy_pages(struct page *page)
atomic_dec(&agp_bridge->current_memory_agp);
}
-static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+#define I810_GTT_ORDER 4
+static int i810_setup(void)
{
- int i, j, num_entries;
- void *temp;
- int ret = -EINVAL;
- int mask_type;
-
- if (mem->page_count == 0)
- goto out;
-
- temp = agp_bridge->current_size;
- num_entries = A_SIZE_FIX(temp)->num_entries;
+ u32 reg_addr;
+ char *gtt_table;
- if ((pg_start + mem->page_count) > num_entries)
- goto out_err;
+ /* i81x does not preallocate the gtt. It's always 64kb in size. */
+ gtt_table = alloc_gatt_pages(I810_GTT_ORDER);
+ if (gtt_table == NULL)
+ return -ENOMEM;
+ intel_private.i81x_gtt_table = gtt_table;
+ pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+ reg_addr &= 0xfff80000;
- for (j = pg_start; j < (pg_start + mem->page_count); j++) {
- if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
- ret = -EBUSY;
- goto out_err;
- }
- }
+ intel_private.registers = ioremap(reg_addr, KB(64));
+ if (!intel_private.registers)
+ return -ENOMEM;
- if (type != mem->type)
- goto out_err;
+ writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED,
+ intel_private.registers+I810_PGETBL_CTL);
- mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+ intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
- switch (mask_type) {
- case AGP_DCACHE_MEMORY:
- if (!mem->is_flushed)
- global_cache_flush();
- for (i = pg_start; i < (pg_start + mem->page_count); i++) {
- writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
- intel_private.registers+I810_PTE_BASE+(i*4));
- }
- readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
- break;
- case AGP_PHYS_MEMORY:
- case AGP_NORMAL_MEMORY:
- if (!mem->is_flushed)
- global_cache_flush();
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- page_to_phys(mem->pages[i]), mask_type),
- intel_private.registers+I810_PTE_BASE+(j*4));
- }
- readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
- break;
- default:
- goto out_err;
+ if ((readl(intel_private.registers+I810_DRAM_CTL)
+ & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
+ dev_info(&intel_private.pcidev->dev,
+ "detected 4MB dedicated video ram\n");
+ intel_private.num_dcache_entries = 1024;
}
-out:
- ret = 0;
-out_err:
- mem->is_flushed = true;
- return ret;
+ return 0;
}
-static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+static void i810_cleanup(void)
+{
+ writel(0, intel_private.registers+I810_PGETBL_CTL);
+ free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER);
+}
+
+static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,
+ int type)
{
int i;
- if (mem->page_count == 0)
- return 0;
+ if ((pg_start + mem->page_count)
+ > intel_private.num_dcache_entries)
+ return -EINVAL;
+
+ if (!mem->is_flushed)
+ global_cache_flush();
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+ for (i = pg_start; i < (pg_start + mem->page_count); i++) {
+ dma_addr_t addr = i << PAGE_SHIFT;
+ intel_private.driver->write_entry(addr,
+ i, type);
}
- readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+ readl(intel_private.gtt+i-1);
return 0;
}
@@ -397,29 +274,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
return new;
}
-static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
-{
- struct agp_memory *new;
-
- if (type == AGP_DCACHE_MEMORY) {
- if (pg_count != intel_private.num_dcache_entries)
- return NULL;
-
- new = agp_create_memory(1);
- if (new == NULL)
- return NULL;
-
- new->type = AGP_DCACHE_MEMORY;
- new->page_count = pg_count;
- new->num_scratch_pages = 0;
- agp_free_page_array(new);
- return new;
- }
- if (type == AGP_PHYS_MEMORY)
- return alloc_agpphysmem_i8xx(pg_count, type);
- return NULL;
-}
-
static void intel_i810_free_by_type(struct agp_memory *curr)
{
agp_free_key(curr->key);
@@ -437,13 +291,6 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
kfree(curr);
}
-static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
- dma_addr_t addr, int type)
-{
- /* Type checking must be done elsewhere */
- return addr | bridge->driver->masks[type].mask;
-}
-
static int intel_gtt_setup_scratch_page(void)
{
struct page *page;
@@ -455,7 +302,7 @@ static int intel_gtt_setup_scratch_page(void)
get_page(page);
set_pages_uc(page, 1);
- if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+ if (intel_private.base.needs_dmar) {
dma_addr = pci_map_page(intel_private.pcidev, page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
@@ -470,34 +317,45 @@ static int intel_gtt_setup_scratch_page(void)
return 0;
}
-static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
+static void i810_write_entry(dma_addr_t addr, unsigned int entry,
+ unsigned int flags)
+{
+ u32 pte_flags = I810_PTE_VALID;
+
+ switch (flags) {
+ case AGP_DCACHE_MEMORY:
+ pte_flags |= I810_PTE_LOCAL;
+ break;
+ case AGP_USER_CACHED_MEMORY:
+ pte_flags |= I830_PTE_SYSTEM_CACHED;
+ break;
+ }
+
+ writel(addr | pte_flags, intel_private.gtt + entry);
+}
+
+static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
+ {32, 8192, 3},
+ {64, 16384, 4},
{128, 32768, 5},
- /* The 64M mode still requires a 128k gatt */
- {64, 16384, 5},
{256, 65536, 6},
{512, 131072, 7},
};
-static unsigned int intel_gtt_stolen_entries(void)
+static unsigned int intel_gtt_stolen_size(void)
{
u16 gmch_ctrl;
u8 rdct;
int local = 0;
static const int ddt[4] = { 0, 16, 32, 64 };
- unsigned int overhead_entries, stolen_entries;
unsigned int stolen_size = 0;
+ if (INTEL_GTT_GEN == 1)
+ return 0; /* no stolen mem on i81x */
+
pci_read_config_word(intel_private.bridge_dev,
I830_GMCH_CTRL, &gmch_ctrl);
- if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
- overhead_entries = 0;
- else
- overhead_entries = intel_private.base.gtt_mappable_entries
- / 1024;
-
- overhead_entries += 1; /* BIOS popup */
-
if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
@@ -623,12 +481,7 @@ static unsigned int intel_gtt_stolen_entries(void)
}
}
- if (!local && stolen_size > intel_max_stolen) {
- dev_info(&intel_private.bridge_dev->dev,
- "detected %dK stolen memory, trimming to %dK\n",
- stolen_size / KB(1), intel_max_stolen / KB(1));
- stolen_size = intel_max_stolen;
- } else if (stolen_size > 0) {
+ if (stolen_size > 0) {
dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
stolen_size / KB(1), local ? "local" : "stolen");
} else {
@@ -637,46 +490,88 @@ static unsigned int intel_gtt_stolen_entries(void)
stolen_size = 0;
}
- stolen_entries = stolen_size/KB(4) - overhead_entries;
+ return stolen_size;
+}
- return stolen_entries;
+static void i965_adjust_pgetbl_size(unsigned int size_flag)
+{
+ u32 pgetbl_ctl, pgetbl_ctl2;
+
+ /* ensure that ppgtt is disabled */
+ pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2);
+ pgetbl_ctl2 &= ~I810_PGETBL_ENABLED;
+ writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2);
+
+ /* write the new ggtt size */
+ pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+ pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK;
+ pgetbl_ctl |= size_flag;
+ writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL);
}
-static unsigned int intel_gtt_total_entries(void)
+static unsigned int i965_gtt_total_entries(void)
{
int size;
+ u32 pgetbl_ctl;
+ u16 gmch_ctl;
- if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
- u32 pgetbl_ctl;
- pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+ pci_read_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, &gmch_ctl);
- switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
- case I965_PGETBL_SIZE_128KB:
- size = KB(128);
+ if (INTEL_GTT_GEN == 5) {
+ switch (gmch_ctl & G4x_GMCH_SIZE_MASK) {
+ case G4x_GMCH_SIZE_1M:
+ case G4x_GMCH_SIZE_VT_1M:
+ i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB);
break;
- case I965_PGETBL_SIZE_256KB:
- size = KB(256);
+ case G4x_GMCH_SIZE_VT_1_5M:
+ i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB);
break;
- case I965_PGETBL_SIZE_512KB:
- size = KB(512);
+ case G4x_GMCH_SIZE_2M:
+ case G4x_GMCH_SIZE_VT_2M:
+ i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB);
break;
- case I965_PGETBL_SIZE_1MB:
- size = KB(1024);
- break;
- case I965_PGETBL_SIZE_2MB:
- size = KB(2048);
- break;
- case I965_PGETBL_SIZE_1_5MB:
- size = KB(1024 + 512);
- break;
- default:
- dev_info(&intel_private.pcidev->dev,
- "unknown page table size, assuming 512KB\n");
- size = KB(512);
}
+ }
- return size/4;
- } else if (INTEL_GTT_GEN == 6) {
+ pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+ switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+ case I965_PGETBL_SIZE_128KB:
+ size = KB(128);
+ break;
+ case I965_PGETBL_SIZE_256KB:
+ size = KB(256);
+ break;
+ case I965_PGETBL_SIZE_512KB:
+ size = KB(512);
+ break;
+ /* GTT pagetable sizes bigger than 512KB are not possible on G33! */
+ case I965_PGETBL_SIZE_1MB:
+ size = KB(1024);
+ break;
+ case I965_PGETBL_SIZE_2MB:
+ size = KB(2048);
+ break;
+ case I965_PGETBL_SIZE_1_5MB:
+ size = KB(1024 + 512);
+ break;
+ default:
+ dev_info(&intel_private.pcidev->dev,
+ "unknown page table size, assuming 512KB\n");
+ size = KB(512);
+ }
+
+ return size/4;
+}
+
+static unsigned int intel_gtt_total_entries(void)
+{
+ int size;
+
+ if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5)
+ return i965_gtt_total_entries();
+ else if (INTEL_GTT_GEN == 6) {
u16 snb_gmch_ctl;
pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
@@ -706,7 +601,18 @@ static unsigned int intel_gtt_mappable_entries(void)
{
unsigned int aperture_size;
- if (INTEL_GTT_GEN == 2) {
+ if (INTEL_GTT_GEN == 1) {
+ u32 smram_miscc;
+
+ pci_read_config_dword(intel_private.bridge_dev,
+ I810_SMRAM_MISCC, &smram_miscc);
+
+ if ((smram_miscc & I810_GFX_MEM_WIN_SIZE)
+ == I810_GFX_MEM_WIN_32M)
+ aperture_size = MB(32);
+ else
+ aperture_size = MB(64);
+ } else if (INTEL_GTT_GEN == 2) {
u16 gmch_ctrl;
pci_read_config_word(intel_private.bridge_dev,
@@ -739,7 +645,7 @@ static void intel_gtt_cleanup(void)
iounmap(intel_private.gtt);
iounmap(intel_private.registers);
-
+
intel_gtt_teardown_scratch_page();
}
@@ -755,6 +661,14 @@ static int intel_gtt_init(void)
intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+ /* save the PGETBL reg for resume */
+ intel_private.PGETBL_save =
+ readl(intel_private.registers+I810_PGETBL_CTL)
+ & ~I810_PGETBL_ENABLED;
+ /* we only ever restore the register when enabling the PGTBL... */
+ if (HAS_PGTBL_EN)
+ intel_private.PGETBL_save |= I810_PGETBL_ENABLED;
+
dev_info(&intel_private.bridge_dev->dev,
"detected gtt size: %dK total, %dK mappable\n",
intel_private.base.gtt_total_entries * 4,
@@ -772,14 +686,9 @@ static int intel_gtt_init(void)
global_cache_flush(); /* FIXME: ? */
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
- if (intel_private.base.gtt_stolen_entries == 0) {
- intel_private.driver->cleanup();
- iounmap(intel_private.registers);
- iounmap(intel_private.gtt);
- return -ENOMEM;
- }
+ intel_private.base.stolen_size = intel_gtt_stolen_size();
+
+ intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2;
ret = intel_gtt_setup_scratch_page();
if (ret != 0) {
@@ -812,8 +721,10 @@ static int intel_fake_agp_fetch_size(void)
static void i830_cleanup(void)
{
- kunmap(intel_private.i8xx_page);
- intel_private.i8xx_flush_page = NULL;
+ if (intel_private.i8xx_flush_page) {
+ kunmap(intel_private.i8xx_flush_page);
+ intel_private.i8xx_flush_page = NULL;
+ }
__free_page(intel_private.i8xx_page);
intel_private.i8xx_page = NULL;
@@ -860,25 +771,19 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry,
unsigned int flags)
{
u32 pte_flags = I810_PTE_VALID;
-
- switch (flags) {
- case AGP_DCACHE_MEMORY:
- pte_flags |= I810_PTE_LOCAL;
- break;
- case AGP_USER_CACHED_MEMORY:
+
+ if (flags == AGP_USER_CACHED_MEMORY)
pte_flags |= I830_PTE_SYSTEM_CACHED;
- break;
- }
writel(addr | pte_flags, intel_private.gtt + entry);
}
-static void intel_enable_gtt(void)
+static bool intel_enable_gtt(void)
{
u32 gma_addr;
- u16 gmch_ctrl;
+ u8 __iomem *reg;
- if (INTEL_GTT_GEN == 2)
+ if (INTEL_GTT_GEN <= 2)
pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
&gma_addr);
else
@@ -887,13 +792,47 @@ static void intel_enable_gtt(void)
intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
- pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
- gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+ if (INTEL_GTT_GEN >= 6)
+ return true;
- writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
- intel_private.registers+I810_PGETBL_CTL);
- readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+ if (INTEL_GTT_GEN == 2) {
+ u16 gmch_ctrl;
+
+ pci_read_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, &gmch_ctrl);
+ gmch_ctrl |= I830_GMCH_ENABLED;
+ pci_write_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, gmch_ctrl);
+
+ pci_read_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, &gmch_ctrl);
+ if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) {
+ dev_err(&intel_private.pcidev->dev,
+ "failed to enable the GTT: GMCH_CTRL=%x\n",
+ gmch_ctrl);
+ return false;
+ }
+ }
+
+ /* On the resume path we may be adjusting the PGTBL value, so
+ * be paranoid and flush all chipset write buffers...
+ */
+ if (INTEL_GTT_GEN >= 3)
+ writel(0, intel_private.registers+GFX_FLSH_CNTL);
+
+ reg = intel_private.registers+I810_PGETBL_CTL;
+ writel(intel_private.PGETBL_save, reg);
+ if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) {
+ dev_err(&intel_private.pcidev->dev,
+ "failed to enable the GTT: PGETBL=%x [expected %x]\n",
+ readl(reg), intel_private.PGETBL_save);
+ return false;
+ }
+
+ if (INTEL_GTT_GEN >= 3)
+ writel(0, intel_private.registers+GFX_FLSH_CNTL);
+
+ return true;
}
static int i830_setup(void)
@@ -908,8 +847,6 @@ static int i830_setup(void)
return -ENOMEM;
intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
- intel_private.pte_bus_addr =
- readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
intel_i830_setup_flush();
@@ -934,12 +871,12 @@ static int intel_fake_agp_configure(void)
{
int i;
- intel_enable_gtt();
+ if (!intel_enable_gtt())
+ return -EIO;
agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
- for (i = intel_private.base.gtt_stolen_entries;
- i < intel_private.base.gtt_total_entries; i++) {
+ for (i = 0; i < intel_private.base.gtt_total_entries; i++) {
intel_private.driver->write_entry(intel_private.scratch_page_dma,
i, 0);
}
@@ -963,10 +900,10 @@ static bool i830_check_flags(unsigned int flags)
return false;
}
-static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
- unsigned int sg_len,
- unsigned int pg_start,
- unsigned int flags)
+void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+ unsigned int sg_len,
+ unsigned int pg_start,
+ unsigned int flags)
{
struct scatterlist *sg;
unsigned int len, m;
@@ -987,27 +924,34 @@ static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
}
readl(intel_private.gtt+j-1);
}
+EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
+
+void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries,
+ struct page **pages, unsigned int flags)
+{
+ int i, j;
+
+ for (i = 0, j = first_entry; i < num_entries; i++, j++) {
+ dma_addr_t addr = page_to_phys(pages[i]);
+ intel_private.driver->write_entry(addr,
+ j, flags);
+ }
+ readl(intel_private.gtt+j-1);
+}
+EXPORT_SYMBOL(intel_gtt_insert_pages);
static int intel_fake_agp_insert_entries(struct agp_memory *mem,
off_t pg_start, int type)
{
- int i, j;
int ret = -EINVAL;
+ if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY)
+ return i810_insert_dcache_entries(mem, pg_start, type);
+
if (mem->page_count == 0)
goto out;
- if (pg_start < intel_private.base.gtt_stolen_entries) {
- dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
- "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
- pg_start, intel_private.base.gtt_stolen_entries);
-
- dev_info(&intel_private.pcidev->dev,
- "trying to insert into local/stolen memory\n");
- goto out_err;
- }
-
- if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
+ if (pg_start + mem->page_count > intel_private.base.gtt_total_entries)
goto out_err;
if (type != mem->type)
@@ -1019,21 +963,17 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
if (!mem->is_flushed)
global_cache_flush();
- if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
- ret = intel_agp_map_memory(mem);
+ if (intel_private.base.needs_dmar) {
+ ret = intel_gtt_map_memory(mem->pages, mem->page_count,
+ &mem->sg_list, &mem->num_sg);
if (ret != 0)
return ret;
intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
pg_start, type);
- } else {
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- dma_addr_t addr = page_to_phys(mem->pages[i]);
- intel_private.driver->write_entry(addr,
- j, type);
- }
- readl(intel_private.gtt+j-1);
- }
+ } else
+ intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages,
+ type);
out:
ret = 0;
@@ -1042,40 +982,54 @@ out_err:
return ret;
}
+void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
+{
+ unsigned int i;
+
+ for (i = first_entry; i < (first_entry + num_entries); i++) {
+ intel_private.driver->write_entry(intel_private.scratch_page_dma,
+ i, 0);
+ }
+ readl(intel_private.gtt+i-1);
+}
+EXPORT_SYMBOL(intel_gtt_clear_range);
+
static int intel_fake_agp_remove_entries(struct agp_memory *mem,
off_t pg_start, int type)
{
- int i;
-
if (mem->page_count == 0)
return 0;
- if (pg_start < intel_private.base.gtt_stolen_entries) {
- dev_info(&intel_private.pcidev->dev,
- "trying to disable local/stolen memory\n");
- return -EINVAL;
- }
+ intel_gtt_clear_range(pg_start, mem->page_count);
- if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
- intel_agp_unmap_memory(mem);
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- intel_private.driver->write_entry(intel_private.scratch_page_dma,
- i, 0);
+ if (intel_private.base.needs_dmar) {
+ intel_gtt_unmap_memory(mem->sg_list, mem->num_sg);
+ mem->sg_list = NULL;
+ mem->num_sg = 0;
}
- readl(intel_private.gtt+i-1);
return 0;
}
-static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
-{
- intel_private.driver->chipset_flush();
-}
-
static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
int type)
{
+ struct agp_memory *new;
+
+ if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) {
+ if (pg_count != intel_private.num_dcache_entries)
+ return NULL;
+
+ new = agp_create_memory(1);
+ if (new == NULL)
+ return NULL;
+
+ new->type = AGP_DCACHE_MEMORY;
+ new->page_count = pg_count;
+ new->num_scratch_pages = 0;
+ agp_free_page_array(new);
+ return new;
+ }
if (type == AGP_PHYS_MEMORY)
return alloc_agpphysmem_i8xx(pg_count, type);
/* always return NULL for other allocation types for now */
@@ -1190,12 +1144,19 @@ static void i9xx_chipset_flush(void)
writel(1, intel_private.i9xx_flush_page);
}
-static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+static void i965_write_entry(dma_addr_t addr,
+ unsigned int entry,
unsigned int flags)
{
+ u32 pte_flags;
+
+ pte_flags = I810_PTE_VALID;
+ if (flags == AGP_USER_CACHED_MEMORY)
+ pte_flags |= I830_PTE_SYSTEM_CACHED;
+
/* Shift high bits down */
addr |= (addr >> 28) & 0xf0;
- writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
+ writel(addr | pte_flags, intel_private.gtt + entry);
}
static bool gen6_check_flags(unsigned int flags)
@@ -1210,14 +1171,14 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
u32 pte_flags;
- if (type_mask == AGP_USER_UNCACHED_MEMORY)
+ if (type_mask == AGP_USER_MEMORY)
pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
- pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+ pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
if (gfdt)
pte_flags |= GEN6_PTE_GFDT;
} else { /* set 'normal'/'cached' to LLC by default */
- pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
+ pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
if (gfdt)
pte_flags |= GEN6_PTE_GFDT;
}
@@ -1265,40 +1226,11 @@ static int i9xx_setup(void)
intel_private.gtt_bus_addr = reg_addr + gtt_offset;
}
- intel_private.pte_bus_addr =
- readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-
intel_i9xx_setup_flush();
return 0;
}
-static const struct agp_bridge_driver intel_810_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i810_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 2,
- .needs_scratch_page = true,
- .configure = intel_i810_configure,
- .fetch_size = intel_i810_fetch_size,
- .cleanup = intel_i810_cleanup,
- .mask_memory = intel_i810_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_fake_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = agp_generic_create_gatt_table,
- .free_gatt_table = agp_generic_free_gatt_table,
- .insert_memory = intel_i810_insert_entries,
- .remove_memory = intel_i810_remove_entries,
- .alloc_by_type = intel_i810_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_alloc_pages = agp_generic_alloc_pages,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = agp_generic_type_to_mask_type,
-};
-
static const struct agp_bridge_driver intel_fake_agp_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
@@ -1319,15 +1251,20 @@ static const struct agp_bridge_driver intel_fake_agp_driver = {
.agp_alloc_pages = agp_generic_alloc_pages,
.agp_destroy_page = agp_generic_destroy_page,
.agp_destroy_pages = agp_generic_destroy_pages,
- .chipset_flush = intel_fake_agp_chipset_flush,
};
static const struct intel_gtt_driver i81x_gtt_driver = {
.gen = 1,
+ .has_pgtbl_enable = 1,
.dma_mask_size = 32,
+ .setup = i810_setup,
+ .cleanup = i810_cleanup,
+ .check_flags = i830_check_flags,
+ .write_entry = i810_write_entry,
};
static const struct intel_gtt_driver i8xx_gtt_driver = {
.gen = 2,
+ .has_pgtbl_enable = 1,
.setup = i830_setup,
.cleanup = i830_cleanup,
.write_entry = i830_write_entry,
@@ -1337,10 +1274,11 @@ static const struct intel_gtt_driver i8xx_gtt_driver = {
};
static const struct intel_gtt_driver i915_gtt_driver = {
.gen = 3,
+ .has_pgtbl_enable = 1,
.setup = i9xx_setup,
.cleanup = i9xx_cleanup,
/* i945 is the last gpu to need phys mem (for overlay and cursors). */
- .write_entry = i830_write_entry,
+ .write_entry = i830_write_entry,
.dma_mask_size = 32,
.check_flags = i830_check_flags,
.chipset_flush = i9xx_chipset_flush,
@@ -1367,6 +1305,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = {
};
static const struct intel_gtt_driver i965_gtt_driver = {
.gen = 4,
+ .has_pgtbl_enable = 1,
.setup = i9xx_setup,
.cleanup = i9xx_cleanup,
.write_entry = i965_write_entry,
@@ -1410,93 +1349,92 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = {
static const struct intel_gtt_driver_description {
unsigned int gmch_chip_id;
char *name;
- const struct agp_bridge_driver *gmch_driver;
const struct intel_gtt_driver *gtt_driver;
} intel_gtt_chipsets[] = {
- { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+ { PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
&i81x_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+ { PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
&i81x_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+ { PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
&i81x_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+ { PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
&i81x_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
- &intel_fake_agp_driver, &i8xx_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
- &intel_fake_agp_driver, &i8xx_gtt_driver},
+ &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82845G_IG, "845G",
+ &i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
- &intel_fake_agp_driver, &i8xx_gtt_driver},
+ &i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
- &intel_fake_agp_driver, &i8xx_gtt_driver},
+ &i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82865_IG, "865",
- &intel_fake_agp_driver, &i8xx_gtt_driver},
+ &i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
- &intel_fake_agp_driver, &i915_gtt_driver },
+ &i915_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
- &intel_fake_agp_driver, &i965_gtt_driver },
+ &i965_gtt_driver },
{ PCI_DEVICE_ID_INTEL_G33_IG, "G33",
- &intel_fake_agp_driver, &g33_gtt_driver },
+ &g33_gtt_driver },
{ PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
- &intel_fake_agp_driver, &g33_gtt_driver },
+ &g33_gtt_driver },
{ PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
- &intel_fake_agp_driver, &g33_gtt_driver },
+ &g33_gtt_driver },
{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
- &intel_fake_agp_driver, &pineview_gtt_driver },
+ &pineview_gtt_driver },
{ PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
- &intel_fake_agp_driver, &pineview_gtt_driver },
+ &pineview_gtt_driver },
{ PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_B43_IG, "B43",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_G41_IG, "G41",
- &intel_fake_agp_driver, &g4x_gtt_driver },
+ &g4x_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
- "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+ "HD Graphics", &ironlake_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
- "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+ "HD Graphics", &ironlake_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
- "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ "Sandybridge", &sandybridge_gtt_driver },
{ 0, NULL, NULL }
};
@@ -1521,21 +1459,20 @@ int intel_gmch_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge)
{
int i, mask;
- bridge->driver = NULL;
+ intel_private.driver = NULL;
for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
- bridge->driver =
- intel_gtt_chipsets[i].gmch_driver;
- intel_private.driver =
+ intel_private.driver =
intel_gtt_chipsets[i].gtt_driver;
break;
}
}
- if (!bridge->driver)
+ if (!intel_private.driver)
return 0;
+ bridge->driver = &intel_fake_agp_driver;
bridge->dev_private_data = &intel_private;
bridge->dev = pdev;
@@ -1551,8 +1488,8 @@ int intel_gmch_probe(struct pci_dev *pdev,
pci_set_consistent_dma_mask(intel_private.pcidev,
DMA_BIT_MASK(mask));
- if (bridge->driver == &intel_810_driver)
- return 1;
+ /*if (bridge->driver == &intel_810_driver)
+ return 1;*/
if (intel_gtt_init() != 0)
return 0;
@@ -1561,12 +1498,19 @@ int intel_gmch_probe(struct pci_dev *pdev,
}
EXPORT_SYMBOL(intel_gmch_probe);
-struct intel_gtt *intel_gtt_get(void)
+const struct intel_gtt *intel_gtt_get(void)
{
return &intel_private.base;
}
EXPORT_SYMBOL(intel_gtt_get);
+void intel_gtt_chipset_flush(void)
+{
+ if (intel_private.driver->chipset_flush)
+ intel_private.driver->chipset_flush();
+}
+EXPORT_SYMBOL(intel_gtt_chipset_flush);
+
void intel_gmch_remove(struct pci_dev *pdev)
{
if (intel_private.pcidev)
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index b0a70461a12c..6ee3348bc3e4 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -81,7 +81,6 @@ static char *serial_version = "4.30";
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
@@ -1299,7 +1298,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
{
struct async_struct * info = tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct icount;
void __user *argp = (void __user *)arg;
unsigned long flags;
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index f6718f05dad4..095ab90535ce 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 55b8667f739f..7066e801b9d3 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/major.h>
diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c
new file mode 100644
index 000000000000..6470f63deb4b
--- /dev/null
+++ b/drivers/char/hvc_dcc.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+
+#include "hvc_console.h"
+
+/* DCC Status Bits */
+#define DCC_STATUS_RX (1 << 30)
+#define DCC_STATUS_TX (1 << 29)
+
+static inline u32 __dcc_getstatus(void)
+{
+ u32 __ret;
+
+ asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
+ : "=r" (__ret) : : "cc");
+
+ return __ret;
+}
+
+
+#if defined(CONFIG_CPU_V7)
+static inline char __dcc_getchar(void)
+{
+ char __c;
+
+ asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\
+ bne get_wait \n\
+ mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
+ : "=r" (__c) : : "cc");
+
+ return __c;
+}
+#else
+static inline char __dcc_getchar(void)
+{
+ char __c;
+
+ asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
+ : "=r" (__c));
+
+ return __c;
+}
+#endif
+
+#if defined(CONFIG_CPU_V7)
+static inline void __dcc_putchar(char c)
+{
+ asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\
+ bcs put_wait \n\
+ mcr p14, 0, %0, c0, c5, 0 "
+ : : "r" (c) : "cc");
+}
+#else
+static inline void __dcc_putchar(char c)
+{
+ asm("mcr p14, 0, %0, c0, c5, 0 @ write a char"
+ : /* no output register */
+ : "r" (c));
+}
+#endif
+
+static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ while (__dcc_getstatus() & DCC_STATUS_TX)
+ cpu_relax();
+
+ __dcc_putchar((char)(buf[i] & 0xFF));
+ }
+
+ return count;
+}
+
+static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ int c = -1;
+
+ if (__dcc_getstatus() & DCC_STATUS_RX)
+ c = __dcc_getchar();
+ if (c < 0)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static const struct hv_ops hvc_dcc_get_put_ops = {
+ .get_chars = hvc_dcc_get_chars,
+ .put_chars = hvc_dcc_put_chars,
+};
+
+static int __init hvc_dcc_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+ return 0;
+}
+console_initcall(hvc_dcc_console_init);
+
+static int __init hvc_dcc_init(void)
+{
+ hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+ return 0;
+}
+device_initcall(hvc_dcc_init);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 27370e99c66f..5e2f52b33327 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -39,7 +39,7 @@
#include "hvc_console.h"
-char hvc_driver_name[] = "hvc_console";
+static const char hvc_driver_name[] = "hvc_console";
static struct vio_device_id hvc_driver_table[] __devinitdata = {
{"serial", "hvterm1"},
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index a2bc885ce60a..67a75a502c01 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -850,8 +850,8 @@ static void hvsi_flush_output(struct hvsi_struct *hp)
wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);
/* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
- cancel_delayed_work(&hp->writer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&hp->writer);
+ flush_work_sync(&hp->handshaker);
/*
* it's also possible that our timeout expired and hvsi_write_worker
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 788da05190cc..2016aad85203 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 794aacb715c1..d0387a84eec1 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -24,6 +24,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <crypto/padlock.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hw_random.h>
@@ -34,7 +35,6 @@
#include <asm/i387.h>
-#define PFX KBUILD_MODNAME ": "
enum {
@@ -81,8 +81,7 @@ static inline u32 xstore(u32 *addr, u32 edx_in)
ts_state = irq_ts_save();
asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
- :"=m"(*addr), "=a"(eax_out)
- :"D"(addr), "d"(edx_in));
+ : "=m" (*addr), "=a" (eax_out), "+d" (edx_in), "+D" (addr));
irq_ts_restore(ts_state);
return eax_out;
@@ -90,8 +89,10 @@ static inline u32 xstore(u32 *addr, u32 edx_in)
static int via_rng_data_present(struct hwrng *rng, int wait)
{
+ char buf[16 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ u32 *via_rng_datum = (u32 *)PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
u32 bytes_out;
- u32 *via_rng_datum = (u32 *)(&rng->priv);
int i;
/* We choose the recommended 1-byte-per-instruction RNG rate,
@@ -115,6 +116,7 @@ static int via_rng_data_present(struct hwrng *rng, int wait)
break;
udelay(10);
}
+ rng->priv = *via_rng_datum;
return bytes_out ? 1 : 0;
}
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 3bc0eef88717..d72433f2d310 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -120,7 +120,7 @@ static int i8k_smm(struct smm_regs *regs)
int eax = regs->eax;
#if defined(CONFIG_X86_64)
- asm("pushq %%rax\n\t"
+ asm volatile("pushq %%rax\n\t"
"movl 0(%%rax),%%edx\n\t"
"pushq %%rdx\n\t"
"movl 4(%%rax),%%ebx\n\t"
@@ -146,7 +146,7 @@ static int i8k_smm(struct smm_regs *regs)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
#else
- asm("pushl %%eax\n\t"
+ asm volatile("pushl %%eax\n\t"
"movl 0(%%eax),%%edx\n\t"
"push %%edx\n\t"
"movl 4(%%eax),%%ebx\n\t"
@@ -167,7 +167,8 @@ static int i8k_smm(struct smm_regs *regs)
"movl %%edx,0(%%eax)\n\t"
"lahf\n\t"
"shrl $8,%%eax\n\t"
- "andl $1,%%eax\n":"=a"(rc)
+ "andl $1,%%eax\n"
+ :"=a"(rc)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
#endif
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index fcd02baa7d65..c3a025356b8b 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -3224,7 +3224,7 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo
MODULE_LICENSE("GPL");
-static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
+static struct pci_device_id ip2main_pci_tbl[] __devinitdata __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
{ }
};
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 2fe72f8edf44..38223e93aa98 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -970,6 +970,33 @@ out_kfree:
}
EXPORT_SYMBOL(ipmi_create_user);
+int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
+{
+ int rv = 0;
+ ipmi_smi_t intf;
+ struct ipmi_smi_handlers *handlers;
+
+ mutex_lock(&ipmi_interfaces_mutex);
+ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
+ if (intf->intf_num == if_num)
+ goto found;
+ }
+ /* Not found, return an error */
+ rv = -EINVAL;
+ mutex_unlock(&ipmi_interfaces_mutex);
+ return rv;
+
+found:
+ handlers = intf->handlers;
+ rv = -ENOSYS;
+ if (handlers->get_smi_info)
+ rv = handlers->get_smi_info(intf->send_info, data);
+ mutex_unlock(&ipmi_interfaces_mutex);
+
+ return rv;
+}
+EXPORT_SYMBOL(ipmi_get_smi_info);
+
static void free_user(struct kref *ref)
{
ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 035da9e64a17..b6ae6e9a9c5f 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -57,6 +57,7 @@
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
+#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
@@ -69,6 +70,8 @@
#ifdef CONFIG_PPC_OF
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#endif
#define PFX "ipmi_si: "
@@ -107,10 +110,6 @@ enum si_type {
};
static char *si_to_str[] = { "kcs", "smic", "bt" };
-enum ipmi_addr_src {
- SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
- SI_PCI, SI_DEVICETREE, SI_DEFAULT
-};
static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI",
"ACPI", "SMBIOS", "PCI",
"device-tree", "default" };
@@ -291,6 +290,7 @@ struct smi_info {
struct task_struct *thread;
struct list_head link;
+ union ipmi_smi_info_union addr_info;
};
#define smi_inc_stat(smi, stat) \
@@ -1186,6 +1186,18 @@ static int smi_start_processing(void *send_info,
return 0;
}
+static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
+{
+ struct smi_info *smi = send_info;
+
+ data->addr_src = smi->addr_source;
+ data->dev = smi->dev;
+ data->addr_info = smi->addr_info;
+ get_device(smi->dev);
+
+ return 0;
+}
+
static void set_maintenance_mode(void *send_info, int enable)
{
struct smi_info *smi_info = send_info;
@@ -1197,6 +1209,7 @@ static void set_maintenance_mode(void *send_info, int enable)
static struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE,
.start_processing = smi_start_processing,
+ .get_smi_info = get_smi_info,
.sender = sender,
.request_events = request_events,
.set_maintenance_mode = set_maintenance_mode,
@@ -1928,7 +1941,8 @@ static void __devinit hardcode_find_bmc(void)
static int acpi_failure;
/* For GPE-type interrupts. */
-static u32 ipmi_acpi_gpe(void *context)
+static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
+ u32 gpe_number, void *context)
{
struct smi_info *smi_info = context;
unsigned long flags;
@@ -2156,6 +2170,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
printk(KERN_INFO PFX "probing via ACPI\n");
handle = acpi_dev->handle;
+ info->addr_info.acpi_info.acpi_handle = handle;
/* _IFT tells us the interface type: KCS, BT, etc */
status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
@@ -2546,7 +2561,7 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
{
struct smi_info *info;
struct resource resource;
- const int *regsize, *regspacing, *regshift;
+ const __be32 *regsize, *regspacing, *regshift;
struct device_node *np = dev->dev.of_node;
int ret;
int proplen;
@@ -2599,9 +2614,9 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
info->io.addr_data = resource.start;
- info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE;
- info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING;
- info->io.regshift = regshift ? *regshift : 0;
+ info->io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE;
+ info->io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING;
+ info->io.regshift = regshift ? be32_to_cpup(regshift) : 0;
info->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
info->dev = &dev->dev;
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index f4d334f2536e..320668f4c3aa 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -1081,7 +1081,7 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
{
struct die_args *args = data;
- if (val != DIE_NMI)
+ if (val != DIE_NMIUNKNOWN)
return NOTIFY_OK;
/* Hack, if it's a memory or I/O error, ignore it. */
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 667abd23ad6a..7c6de4c92458 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index dd3f9b1f11b4..294d03e8c61a 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -1828,7 +1828,6 @@ static int ntty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct port *port = tty->driver_data;
- void __user *argp = (void __user *)arg;
int rval = -ENOIOCTLCMD;
DBG1("******** IOCTL, cmd: %d", cmd);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index d962f25dcc2a..777181a2e603 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -979,8 +979,9 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
if (dev->flags0 & 1) {
set_bit(IS_CMM_ABSENT, &dev->flags);
rc = -ENODEV;
+ } else {
+ rc = -EIO;
}
- rc = -EIO;
goto release_io;
}
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index 99cffdab1056..0aeb5a38d296 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -1729,7 +1729,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
ipwireless_stop_interrupts(hw);
- flush_scheduled_work();
+ flush_work_sync(&hw->work_rx);
for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
if (hw->packet_assembler[i] != NULL)
diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c
index 9fe538347932..f7daeea598e4 100644
--- a/drivers/char/pcmcia/ipwireless/network.c
+++ b/drivers/char/pcmcia/ipwireless/network.c
@@ -430,7 +430,8 @@ void ipwireless_network_free(struct ipw_network *network)
network->shutting_down = 1;
ipwireless_ppp_close(network);
- flush_scheduled_work();
+ flush_work_sync(&network->work_go_online);
+ flush_work_sync(&network->work_go_offline);
ipwireless_stop_interrupts(network->hardware);
ipwireless_associate_network(network->hardware, NULL);
diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
index 1a2c2c3b068f..f5eb28b6cb0f 100644
--- a/drivers/char/pcmcia/ipwireless/tty.c
+++ b/drivers/char/pcmcia/ipwireless/tty.c
@@ -577,7 +577,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_hangup(ttyj->linux_tty);
/* Wait till the tty_hangup has completed */
- flush_scheduled_work();
+ flush_work_sync(&ttyj->linux_tty->hangup_work);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
mutex_lock(&ttyj->ipw_tty_mutex);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index bfc10f89d951..eaa41992fbe2 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2796,6 +2796,7 @@ static const struct tty_operations mgslpc_ops = {
.hangup = mgslpc_hangup,
.tiocmget = tiocmget,
.tiocmset = tiocmset,
+ .get_icount = mgslpc_get_icount,
.proc_fops = &mgslpc_proc_fops,
};
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
index 73dcb0ee41fd..1a9f5f6d6ac5 100644
--- a/drivers/char/ramoops.c
+++ b/drivers/char/ramoops.c
@@ -29,9 +29,8 @@
#include <linux/ramoops.h>
#define RAMOOPS_KERNMSG_HDR "===="
-#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval))
-#define RECORD_SIZE 4096
+#define RECORD_SIZE 4096UL
static ulong mem_address;
module_param(mem_address, ulong, 0400);
@@ -65,15 +64,22 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
struct ramoops_context, dump);
unsigned long s1_start, s2_start;
unsigned long l1_cpy, l2_cpy;
- int res;
- char *buf;
+ int res, hdr_size;
+ char *buf, *buf_orig;
struct timeval timestamp;
+ if (reason != KMSG_DUMP_OOPS &&
+ reason != KMSG_DUMP_PANIC &&
+ reason != KMSG_DUMP_KEXEC)
+ return;
+
/* Only dump oopses if dump_oops is set */
if (reason == KMSG_DUMP_OOPS && !dump_oops)
return;
- buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+ buf = cxt->virt_addr + (cxt->count * RECORD_SIZE);
+ buf_orig = buf;
+
memset(buf, '\0', RECORD_SIZE);
res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
buf += res;
@@ -81,8 +87,9 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
buf += res;
- l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
- l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+ hdr_size = buf - buf_orig;
+ l2_cpy = min(l2, RECORD_SIZE - hdr_size);
+ l1_cpy = min(l1, RECORD_SIZE - hdr_size - l2_cpy);
s2_start = l2 - l2_cpy;
s1_start = l1 - l1_cpy;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 5a1aa64f4e76..72a4fcb17745 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -626,7 +626,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
preempt_disable();
/* if over the trickle threshold, use only 1 in 4096 samples */
if (input_pool.entropy_count > trickle_thresh &&
- (__get_cpu_var(trickle_count)++ & 0xfff))
+ ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff))
goto out;
sample.jiffies = jiffies;
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index bfe25ea9766b..b4b9d5a47885 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -65,15 +65,12 @@ static int raw_open(struct inode *inode, struct file *filp)
if (!bdev)
goto out;
igrab(bdev->bd_inode);
- err = blkdev_get(bdev, filp->f_mode);
+ err = blkdev_get(bdev, filp->f_mode | FMODE_EXCL, raw_open);
if (err)
goto out;
- err = bd_claim(bdev, raw_open);
- if (err)
- goto out1;
err = set_blocksize(bdev, bdev_logical_block_size(bdev));
if (err)
- goto out2;
+ goto out1;
filp->f_flags |= O_DIRECT;
filp->f_mapping = bdev->bd_inode->i_mapping;
if (++raw_devices[minor].inuse == 1)
@@ -83,10 +80,8 @@ static int raw_open(struct inode *inode, struct file *filp)
mutex_unlock(&raw_mutex);
return 0;
-out2:
- bd_release(bdev);
out1:
- blkdev_put(bdev, filp->f_mode);
+ blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
out:
mutex_unlock(&raw_mutex);
return err;
@@ -110,8 +105,7 @@ static int raw_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&raw_mutex);
- bd_release(bdev);
- blkdev_put(bdev, filp->f_mode);
+ blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
return 0;
}
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 86308830ac42..3e4e73a0d7c1 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1764,7 +1764,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef CONFIG_PCI
-static struct pci_device_id __devinitdata rocket_pci_ids[] = {
+static struct pci_device_id __devinitdata __used rocket_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
{ }
};
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index f646725bd567..748c3b0ecd89 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -52,7 +52,6 @@
#include <linux/interrupt.h>
#include <linux/serial.h>
#include <linux/serialP.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h
index 4be62eda9fbc..e8c52c882b21 100644
--- a/drivers/char/snsc.h
+++ b/drivers/char/snsc.h
@@ -19,7 +19,6 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
-#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/semaphore.h>
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 73f66d03624d..79e36c878a4c 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1434,7 +1434,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
sonypi_disable();
synchronize_irq(sonypi_device.irq);
- flush_scheduled_work();
+ flush_work_sync(&sonypi_device.input_work);
if (useinput) {
input_unregister_device(sonypi_device.input_key_dev);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 9f8495b4fc8f..c2bca3f25ef3 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -87,7 +87,6 @@
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/serial.h>
-#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
@@ -2356,7 +2355,7 @@ static void __exit specialix_exit_module(void)
func_exit();
}
-static struct pci_device_id specialx_pci_tbl[] __devinitdata = {
+static struct pci_device_id specialx_pci_tbl[] __devinitdata __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
{ }
};
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 4bef6ab83622..461a5a045517 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -40,7 +40,6 @@
#include <linux/stallion.h>
#include <linux/ioport.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/ctype.h>
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index e53f16865397..a786326cea2f 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -216,7 +216,6 @@
#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/bitops.h>
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 7c4133582dba..1f46f1cd9225 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -736,7 +736,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
if (chip == NULL)
return -ENODEV;
rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
- module_put(chip->dev->driver->owner);
+ tpm_chip_put(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_pcr_read);
@@ -775,11 +775,27 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"attempting extend a PCR value");
- module_put(chip->dev->driver->owner);
+ tpm_chip_put(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_pcr_extend);
+int tpm_send(u32 chip_num, void *cmd, size_t buflen)
+{
+ struct tpm_chip *chip;
+ int rc;
+
+ chip = tpm_chip_find_get(chip_num);
+ if (chip == NULL)
+ return -ENODEV;
+
+ rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+
+ tpm_chip_put(chip);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_send);
+
ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -986,7 +1002,7 @@ int tpm_release(struct inode *inode, struct file *file)
struct tpm_chip *chip = file->private_data;
del_singleshot_timer_sync(&chip->user_read_timer);
- flush_scheduled_work();
+ flush_work_sync(&chip->work);
file->private_data = NULL;
atomic_set(&chip->data_pending, 0);
kfree(chip->data_buffer);
@@ -1038,7 +1054,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,
ssize_t ret_size;
del_singleshot_timer_sync(&chip->user_read_timer);
- flush_scheduled_work();
+ flush_work_sync(&chip->work);
ret_size = atomic_read(&chip->data_pending);
atomic_set(&chip->data_pending, 0);
if (ret_size > 0) { /* relay data */
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 792868d24f2a..72ddb031b69a 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -113,6 +113,11 @@ struct tpm_chip {
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
+static inline void tpm_chip_put(struct tpm_chip *chip)
+{
+ module_put(chip->dev->driver->owner);
+}
+
static inline int tpm_read_index(int base, int index)
{
outb(index, base);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 1030f8420137..c17a305ecb28 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
+#include <linux/acpi.h>
#include "tpm.h"
#define TPM_HEADER_SIZE 10
@@ -78,6 +79,26 @@ enum tis_defaults {
static LIST_HEAD(tis_chips);
static DEFINE_SPINLOCK(tis_lock);
+#ifdef CONFIG_ACPI
+static int is_itpm(struct pnp_dev *dev)
+{
+ struct acpi_device *acpi = pnp_acpi_device(dev);
+ struct acpi_hardware_id *id;
+
+ list_for_each_entry(id, &acpi->pnp.ids, list) {
+ if (!strcmp("INTC0102", id->id))
+ return 1;
+ }
+
+ return 0;
+}
+#else
+static int is_itpm(struct pnp_dev *dev)
+{
+ return 0;
+}
+#endif
+
static int check_locality(struct tpm_chip *chip, int l)
{
if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
@@ -472,6 +493,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
+ if (is_itpm(to_pnp_dev(dev)))
+ itpm = 1;
+
if (itpm)
dev_info(dev, "Intel iTPM workaround enabled\n");
diff --git a/drivers/char/uv_mmtimer.c b/drivers/char/uv_mmtimer.c
index 493b47a0d511..956ebe2080a5 100644
--- a/drivers/char/uv_mmtimer.c
+++ b/drivers/char/uv_mmtimer.c
@@ -23,7 +23,6 @@
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/math64.h>
-#include <linux/smp_lock.h>
#include <asm/genapic.h>
#include <asm/uv/uv_hub.h>
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 6c1b676643a9..896a2ced1d27 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1547,31 +1547,16 @@ static int init_vqs(struct ports_device *portdev)
nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
- if (!vqs) {
- err = -ENOMEM;
- goto fail;
- }
io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
- if (!io_callbacks) {
- err = -ENOMEM;
- goto free_vqs;
- }
io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
- if (!io_names) {
- err = -ENOMEM;
- goto free_callbacks;
- }
portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL);
- if (!portdev->in_vqs) {
- err = -ENOMEM;
- goto free_names;
- }
portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL);
- if (!portdev->out_vqs) {
+ if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
+ !portdev->out_vqs) {
err = -ENOMEM;
- goto free_invqs;
+ goto free;
}
/*
@@ -1605,7 +1590,7 @@ static int init_vqs(struct ports_device *portdev)
io_callbacks,
(const char **)io_names);
if (err)
- goto free_outvqs;
+ goto free;
j = 0;
portdev->in_vqs[0] = vqs[0];
@@ -1621,23 +1606,19 @@ static int init_vqs(struct ports_device *portdev)
portdev->out_vqs[i] = vqs[j + 1];
}
}
- kfree(io_callbacks);
kfree(io_names);
+ kfree(io_callbacks);
kfree(vqs);
return 0;
-free_names:
- kfree(io_names);
-free_callbacks:
- kfree(io_callbacks);
-free_outvqs:
+free:
kfree(portdev->out_vqs);
-free_invqs:
kfree(portdev->in_vqs);
-free_vqs:
+ kfree(io_names);
+ kfree(io_callbacks);
kfree(vqs);
-fail:
+
return err;
}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
new file mode 100644
index 000000000000..4168c8896e16
--- /dev/null
+++ b/drivers/clk/Kconfig
@@ -0,0 +1,4 @@
+
+config CLKDEV_LOOKUP
+ bool
+ select HAVE_CLK
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644
index 000000000000..07613fa172c9
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
new file mode 100644
index 000000000000..0fc0a79852de
--- /dev/null
+++ b/drivers/clk/clkdev.c
@@ -0,0 +1,176 @@
+/*
+ * drivers/clk/clkdev.c
+ *
+ * Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+/*
+ * Find the correct struct clk for the device and connection ID.
+ * We do slightly fuzzy matching here:
+ * An entry with a NULL ID is assumed to be a wildcard.
+ * If an entry has a device ID, it must match
+ * If an entry has a connection ID, it must match
+ * Then we take the most specific entry - with the following
+ * order of precedence: dev+con > dev only > con only.
+ */
+static struct clk *clk_find(const char *dev_id, const char *con_id)
+{
+ struct clk_lookup *p;
+ struct clk *clk = NULL;
+ int match, best = 0;
+
+ list_for_each_entry(p, &clocks, node) {
+ match = 0;
+ if (p->dev_id) {
+ if (!dev_id || strcmp(p->dev_id, dev_id))
+ continue;
+ match += 2;
+ }
+ if (p->con_id) {
+ if (!con_id || strcmp(p->con_id, con_id))
+ continue;
+ match += 1;
+ }
+
+ if (match > best) {
+ clk = p->clk;
+ if (match != 3)
+ best = match;
+ else
+ break;
+ }
+ }
+ return clk;
+}
+
+struct clk *clk_get_sys(const char *dev_id, const char *con_id)
+{
+ struct clk *clk;
+
+ mutex_lock(&clocks_mutex);
+ clk = clk_find(dev_id, con_id);
+ if (clk && !__clk_get(clk))
+ clk = NULL;
+ mutex_unlock(&clocks_mutex);
+
+ return clk ? clk : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get_sys);
+
+struct clk *clk_get(struct device *dev, const char *con_id)
+{
+ const char *dev_id = dev ? dev_name(dev) : NULL;
+
+ return clk_get_sys(dev_id, con_id);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ __clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+void clkdev_add(struct clk_lookup *cl)
+{
+ mutex_lock(&clocks_mutex);
+ list_add_tail(&cl->node, &clocks);
+ mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clkdev_add);
+
+void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+{
+ mutex_lock(&clocks_mutex);
+ while (num--) {
+ list_add_tail(&cl->node, &clocks);
+ cl++;
+ }
+ mutex_unlock(&clocks_mutex);
+}
+
+#define MAX_DEV_ID 20
+#define MAX_CON_ID 16
+
+struct clk_lookup_alloc {
+ struct clk_lookup cl;
+ char dev_id[MAX_DEV_ID];
+ char con_id[MAX_CON_ID];
+};
+
+struct clk_lookup * __init_refok
+clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
+{
+ struct clk_lookup_alloc *cla;
+
+ cla = __clkdev_alloc(sizeof(*cla));
+ if (!cla)
+ return NULL;
+
+ cla->cl.clk = clk;
+ if (con_id) {
+ strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
+ cla->cl.con_id = cla->con_id;
+ }
+
+ if (dev_fmt) {
+ va_list ap;
+
+ va_start(ap, dev_fmt);
+ vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
+ cla->cl.dev_id = cla->dev_id;
+ va_end(ap);
+ }
+
+ return &cla->cl;
+}
+EXPORT_SYMBOL(clkdev_alloc);
+
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+ struct device *dev)
+{
+ struct clk *r = clk_get(dev, id);
+ struct clk_lookup *l;
+
+ if (IS_ERR(r))
+ return PTR_ERR(r);
+
+ l = clkdev_alloc(r, alias, alias_dev_name);
+ clk_put(r);
+ if (!l)
+ return -ENODEV;
+ clkdev_add(l);
+ return 0;
+}
+EXPORT_SYMBOL(clk_add_alias);
+
+/*
+ * clkdev_drop - remove a clock dynamically allocated
+ */
+void clkdev_drop(struct clk_lookup *cl)
+{
+ mutex_lock(&clocks_mutex);
+ list_del(&cl->node);
+ mutex_unlock(&clocks_mutex);
+ kfree(cl);
+}
+EXPORT_SYMBOL(clkdev_drop);
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index a44611652282..f975d24890fa 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -283,16 +283,21 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,
} while (delay);
}
-static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
{
- unsigned long flags;
-
if (delta > p->max_match_value)
dev_warn(&p->pdev->dev, "delta out of range\n");
- spin_lock_irqsave(&p->lock, flags);
p->next_match_value = delta;
sh_cmt_clock_event_program_verify(p, 0);
+}
+
+static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ __sh_cmt_set_next(p, delta);
spin_unlock_irqrestore(&p->lock, flags);
}
@@ -359,7 +364,7 @@ static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag)
/* setup timeout if no clockevent */
if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT)))
- sh_cmt_set_next(p, p->max_match_value);
+ __sh_cmt_set_next(p, p->max_match_value);
out:
spin_unlock_irqrestore(&p->lock, flags);
@@ -381,7 +386,7 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
/* adjust the timeout to maximum if only clocksource left */
if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE))
- sh_cmt_set_next(p, p->max_match_value);
+ __sh_cmt_set_next(p, p->max_match_value);
spin_unlock_irqrestore(&p->lock, flags);
}
@@ -616,13 +621,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
/* get hold of clock */
p->clk = clk_get(&p->pdev->dev, "cmt_fck");
if (IS_ERR(p->clk)) {
- dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
- if (IS_ERR(p->clk)) {
- dev_err(&p->pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(p->clk);
- goto err1;
- }
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
}
if (resource_size(res) == 6) {
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index ef7a5be8a09f..40630cb98237 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -287,13 +287,9 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
/* get hold of clock */
p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
if (IS_ERR(p->clk)) {
- dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
- if (IS_ERR(p->clk)) {
- dev_err(&p->pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(p->clk);
- goto err1;
- }
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
}
return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index de715901b82a..36aba9923060 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -393,13 +393,9 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
/* get hold of clock */
p->clk = clk_get(&p->pdev->dev, "tmu_fck");
if (IS_ERR(p->clk)) {
- dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
- if (IS_ERR(p->clk)) {
- dev_err(&p->pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(p->clk);
- goto err1;
- }
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
}
return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index a7f046b0096c..2b46a7efa0ac 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -43,9 +43,10 @@ static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
static inline void get_seq(__u32 *ts, int *cpu)
{
- *ts = get_cpu_var(proc_event_counts)++;
+ preempt_disable();
+ *ts = __this_cpu_inc_return(proc_event_counts) -1;
*cpu = smp_processor_id();
- put_cpu_var(proc_event_counts);
+ preempt_enable();
}
void proc_fork_connector(struct task_struct *task)
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index e16c3fa8d2e3..05117f1ad867 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -36,6 +36,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR);
static struct cn_dev cdev;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index c63a43823744..1109f6848a43 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -355,6 +355,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
(unsigned long)freqs->cpu);
trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
+ trace_cpu_frequency(freqs->new, freqs->cpu);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index a50710843378..bf5092455a8f 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -49,7 +49,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
*/
static void cpuidle_idle_call(void)
{
- struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices);
+ struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_state *target_state;
int next_state;
@@ -96,7 +96,15 @@ static void cpuidle_idle_call(void)
/* enter the state and update stats */
dev->last_state = target_state;
+
+ trace_power_start(POWER_CSTATE, next_state, dev->cpu);
+ trace_cpu_idle(next_state, dev->cpu);
+
dev->last_residency = target_state->enter(dev, target_state);
+
+ trace_power_end(dev->cpu);
+ trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
+
if (dev->last_state)
target_state = dev->last_state;
@@ -106,7 +114,6 @@ static void cpuidle_idle_call(void)
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev);
- trace_power_end(smp_processor_id());
}
/**
@@ -154,6 +161,45 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+
+ t2 = ktime_get();
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ ret = (int) diff;
+ return ret;
+}
+
+static void poll_idle_init(struct cpuidle_device *dev)
+{
+ struct cpuidle_state *state = &dev->states[0];
+
+ cpuidle_set_statedata(state, NULL);
+
+ snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
+ state->exit_latency = 0;
+ state->target_residency = 0;
+ state->power_usage = -1;
+ state->flags = 0;
+ state->enter = poll_idle;
+}
+#else
+static void poll_idle_init(struct cpuidle_device *dev) {}
+#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
+
/**
* cpuidle_enable_device - enables idle PM for a CPU
* @dev: the CPU
@@ -178,6 +224,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret;
}
+ poll_idle_init(dev);
+
if ((ret = cpuidle_add_state_sysfs(dev)))
return ret;
@@ -232,45 +280,6 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
-#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
-{
- ktime_t t1, t2;
- s64 diff;
- int ret;
-
- t1 = ktime_get();
- local_irq_enable();
- while (!need_resched())
- cpu_relax();
-
- t2 = ktime_get();
- diff = ktime_to_us(ktime_sub(t2, t1));
- if (diff > INT_MAX)
- diff = INT_MAX;
-
- ret = (int) diff;
- return ret;
-}
-
-static void poll_idle_init(struct cpuidle_device *dev)
-{
- struct cpuidle_state *state = &dev->states[0];
-
- cpuidle_set_statedata(state, NULL);
-
- snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
- snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
- state->exit_latency = 0;
- state->target_residency = 0;
- state->power_usage = -1;
- state->flags = CPUIDLE_FLAG_POLL;
- state->enter = poll_idle;
-}
-#else
-static void poll_idle_init(struct cpuidle_device *dev) {}
-#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
-
/**
* __cpuidle_register_device - internal register function called before register
* and enable routines
@@ -291,8 +300,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
init_completion(&dev->kobj_unregister);
- poll_idle_init(dev);
-
/*
* cpuidle driver should set the dev->power_specified bit
* before registering the device if the driver provides
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index 7d279e578df5..c99305afa58a 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -857,7 +857,7 @@ static int mv_cra_hash_init(struct crypto_tfm *tfm, const char *base_hash_name,
printk(KERN_WARNING MV_CESA
"Base driver '%s' could not be loaded!\n",
base_hash_name);
- err = PTR_ERR(fallback_tfm);
+ err = PTR_ERR(base_hash);
goto err_bad_base;
}
}
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 88ee01510ec0..80dc094e78c6 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -1542,7 +1542,7 @@ out:
return err;
}
-static void __exit n2_unregister_algs(void)
+static void __devexit n2_unregister_algs(void)
{
mutex_lock(&spu_lock);
if (!--algs_registered)
@@ -1832,7 +1832,7 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
return -ENODEV;
ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
- if (!intr)
+ if (!ino)
return -ENODEV;
if (intr_len != ino_len)
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 799ca517c121..add2a1a72ba4 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -74,11 +74,9 @@
#define FLAGS_CBC BIT(1)
#define FLAGS_GIV BIT(2)
-#define FLAGS_NEW_KEY BIT(4)
-#define FLAGS_NEW_IV BIT(5)
-#define FLAGS_INIT BIT(6)
-#define FLAGS_FAST BIT(7)
-#define FLAGS_BUSY 8
+#define FLAGS_INIT BIT(4)
+#define FLAGS_FAST BIT(5)
+#define FLAGS_BUSY BIT(6)
struct omap_aes_ctx {
struct omap_aes_dev *dd;
@@ -98,19 +96,18 @@ struct omap_aes_reqctx {
struct omap_aes_dev {
struct list_head list;
unsigned long phys_base;
- void __iomem *io_base;
+ void __iomem *io_base;
struct clk *iclk;
struct omap_aes_ctx *ctx;
struct device *dev;
unsigned long flags;
+ int err;
- u32 *iv;
- u32 ctrl;
+ spinlock_t lock;
+ struct crypto_queue queue;
- spinlock_t lock;
- struct crypto_queue queue;
-
- struct tasklet_struct task;
+ struct tasklet_struct done_task;
+ struct tasklet_struct queue_task;
struct ablkcipher_request *req;
size_t total;
@@ -179,9 +176,13 @@ static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit)
static int omap_aes_hw_init(struct omap_aes_dev *dd)
{
- int err = 0;
-
+ /*
+ * clocks are enabled when request starts and disabled when finished.
+ * It may be long delays between requests.
+ * Device might go to off mode to save power.
+ */
clk_enable(dd->iclk);
+
if (!(dd->flags & FLAGS_INIT)) {
/* is it necessary to reset before every operation? */
omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET,
@@ -193,39 +194,26 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd)
__asm__ __volatile__("nop");
__asm__ __volatile__("nop");
- err = omap_aes_wait(dd, AES_REG_SYSSTATUS,
- AES_REG_SYSSTATUS_RESETDONE);
- if (!err)
- dd->flags |= FLAGS_INIT;
- }
+ if (omap_aes_wait(dd, AES_REG_SYSSTATUS,
+ AES_REG_SYSSTATUS_RESETDONE))
+ return -ETIMEDOUT;
- return err;
-}
+ dd->flags |= FLAGS_INIT;
+ dd->err = 0;
+ }
-static void omap_aes_hw_cleanup(struct omap_aes_dev *dd)
-{
- clk_disable(dd->iclk);
+ return 0;
}
-static void omap_aes_write_ctrl(struct omap_aes_dev *dd)
+static int omap_aes_write_ctrl(struct omap_aes_dev *dd)
{
unsigned int key32;
- int i;
+ int i, err;
u32 val, mask;
- val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
- if (dd->flags & FLAGS_CBC)
- val |= AES_REG_CTRL_CBC;
- if (dd->flags & FLAGS_ENCRYPT)
- val |= AES_REG_CTRL_DIRECTION;
-
- if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) &&
- !(dd->ctx->flags & FLAGS_NEW_KEY))
- goto out;
-
- /* only need to write control registers for new settings */
-
- dd->ctrl = val;
+ err = omap_aes_hw_init(dd);
+ if (err)
+ return err;
val = 0;
if (dd->dma_lch_out >= 0)
@@ -237,30 +225,43 @@ static void omap_aes_write_ctrl(struct omap_aes_dev *dd)
omap_aes_write_mask(dd, AES_REG_MASK, val, mask);
- pr_debug("Set key\n");
key32 = dd->ctx->keylen / sizeof(u32);
- /* set a key */
+
+ /* it seems a key should always be set even if it has not changed */
for (i = 0; i < key32; i++) {
omap_aes_write(dd, AES_REG_KEY(i),
__le32_to_cpu(dd->ctx->key[i]));
}
- dd->ctx->flags &= ~FLAGS_NEW_KEY;
- if (dd->flags & FLAGS_NEW_IV) {
- pr_debug("Set IV\n");
- omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4);
- dd->flags &= ~FLAGS_NEW_IV;
- }
+ if ((dd->flags & FLAGS_CBC) && dd->req->info)
+ omap_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4);
+
+ val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
+ if (dd->flags & FLAGS_CBC)
+ val |= AES_REG_CTRL_CBC;
+ if (dd->flags & FLAGS_ENCRYPT)
+ val |= AES_REG_CTRL_DIRECTION;
mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
AES_REG_CTRL_KEY_SIZE;
- omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask);
+ omap_aes_write_mask(dd, AES_REG_CTRL, val, mask);
-out:
- /* start DMA or disable idle mode */
- omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
- AES_REG_MASK_START);
+ /* IN */
+ omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
+ dd->phys_base + AES_REG_DATA, 0, 4);
+
+ omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+
+ /* OUT */
+ omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
+ dd->phys_base + AES_REG_DATA, 0, 4);
+
+ omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+
+ return 0;
}
static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
@@ -288,8 +289,16 @@ static void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
{
struct omap_aes_dev *dd = data;
- if (lch == dd->dma_lch_out)
- tasklet_schedule(&dd->task);
+ if (ch_status != OMAP_DMA_BLOCK_IRQ) {
+ pr_err("omap-aes DMA error status: 0x%hx\n", ch_status);
+ dd->err = -EIO;
+ dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
+ } else if (lch == dd->dma_lch_in) {
+ return;
+ }
+
+ /* dma_lch_out - completed */
+ tasklet_schedule(&dd->done_task);
}
static int omap_aes_dma_init(struct omap_aes_dev *dd)
@@ -339,18 +348,6 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
goto err_dma_out;
}
- omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + AES_REG_DATA, 0, 4);
-
- omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
- omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
-
- omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + AES_REG_DATA, 0, 4);
-
- omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
- omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
-
return 0;
err_dma_out:
@@ -406,6 +403,11 @@ static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
if (!count)
return off;
+ /*
+ * buflen and total are AES_BLOCK_SIZE size aligned,
+ * so count should be also aligned
+ */
+
sg_copy_buf(buf + off, *sg, *offset, count, out);
off += count;
@@ -461,7 +463,9 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
omap_start_dma(dd->dma_lch_in);
omap_start_dma(dd->dma_lch_out);
- omap_aes_write_ctrl(dd);
+ /* start DMA or disable idle mode */
+ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
+ AES_REG_MASK_START);
return 0;
}
@@ -488,8 +492,10 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
count = min(dd->total, sg_dma_len(dd->in_sg));
count = min(count, sg_dma_len(dd->out_sg));
- if (count != dd->total)
+ if (count != dd->total) {
+ pr_err("request length != buffer length\n");
return -EINVAL;
+ }
pr_debug("fast\n");
@@ -525,23 +531,25 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
dd->total -= count;
- err = omap_aes_hw_init(dd);
-
err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count);
+ if (err) {
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
+ }
return err;
}
static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
{
- struct omap_aes_ctx *ctx;
+ struct ablkcipher_request *req = dd->req;
pr_debug("err: %d\n", err);
- ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req));
+ clk_disable(dd->iclk);
+ dd->flags &= ~FLAGS_BUSY;
- if (!dd->total)
- dd->req->base.complete(&dd->req->base, err);
+ req->base.complete(&req->base, err);
}
static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
@@ -553,8 +561,6 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START);
- omap_aes_hw_cleanup(dd);
-
omap_stop_dma(dd->dma_lch_in);
omap_stop_dma(dd->dma_lch_out);
@@ -574,40 +580,39 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
}
}
- if (err || !dd->total)
- omap_aes_finish_req(dd, err);
-
return err;
}
-static int omap_aes_handle_req(struct omap_aes_dev *dd)
+static int omap_aes_handle_queue(struct omap_aes_dev *dd,
+ struct ablkcipher_request *req)
{
struct crypto_async_request *async_req, *backlog;
struct omap_aes_ctx *ctx;
struct omap_aes_reqctx *rctx;
- struct ablkcipher_request *req;
unsigned long flags;
-
- if (dd->total)
- goto start;
+ int err, ret = 0;
spin_lock_irqsave(&dd->lock, flags);
+ if (req)
+ ret = ablkcipher_enqueue_request(&dd->queue, req);
+ if (dd->flags & FLAGS_BUSY) {
+ spin_unlock_irqrestore(&dd->lock, flags);
+ return ret;
+ }
backlog = crypto_get_backlog(&dd->queue);
async_req = crypto_dequeue_request(&dd->queue);
- if (!async_req)
- clear_bit(FLAGS_BUSY, &dd->flags);
+ if (async_req)
+ dd->flags |= FLAGS_BUSY;
spin_unlock_irqrestore(&dd->lock, flags);
if (!async_req)
- return 0;
+ return ret;
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
req = ablkcipher_request_cast(async_req);
- pr_debug("get new req\n");
-
/* assign new request to device */
dd->req = req;
dd->total = req->nbytes;
@@ -621,27 +626,22 @@ static int omap_aes_handle_req(struct omap_aes_dev *dd)
rctx->mode &= FLAGS_MODE_MASK;
dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
- dd->iv = req->info;
- if ((dd->flags & FLAGS_CBC) && dd->iv)
- dd->flags |= FLAGS_NEW_IV;
- else
- dd->flags &= ~FLAGS_NEW_IV;
-
+ dd->ctx = ctx;
ctx->dd = dd;
- if (dd->ctx != ctx) {
- /* assign new context to device */
- dd->ctx = ctx;
- ctx->flags |= FLAGS_NEW_KEY;
- }
- if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE))
- pr_err("request size is not exact amount of AES blocks\n");
+ err = omap_aes_write_ctrl(dd);
+ if (!err)
+ err = omap_aes_crypt_dma_start(dd);
+ if (err) {
+ /* aes_task will not finish it, so do it here */
+ omap_aes_finish_req(dd, err);
+ tasklet_schedule(&dd->queue_task);
+ }
-start:
- return omap_aes_crypt_dma_start(dd);
+ return ret; /* return ret, which is enqueue return value */
}
-static void omap_aes_task(unsigned long data)
+static void omap_aes_done_task(unsigned long data)
{
struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
int err;
@@ -650,40 +650,50 @@ static void omap_aes_task(unsigned long data)
err = omap_aes_crypt_dma_stop(dd);
- err = omap_aes_handle_req(dd);
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+ err = omap_aes_crypt_dma_start(dd);
+ if (!err)
+ return; /* DMA started. Not fininishing. */
+ }
+
+ omap_aes_finish_req(dd, err);
+ omap_aes_handle_queue(dd, NULL);
pr_debug("exit\n");
}
+static void omap_aes_queue_task(unsigned long data)
+{
+ struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
+
+ omap_aes_handle_queue(dd, NULL);
+}
+
static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
{
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
struct omap_aes_dev *dd;
- unsigned long flags;
- int err;
pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
!!(mode & FLAGS_ENCRYPT),
!!(mode & FLAGS_CBC));
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of AES blocks\n");
+ return -EINVAL;
+ }
+
dd = omap_aes_find_dev(ctx);
if (!dd)
return -ENODEV;
rctx->mode = mode;
- spin_lock_irqsave(&dd->lock, flags);
- err = ablkcipher_enqueue_request(&dd->queue, req);
- spin_unlock_irqrestore(&dd->lock, flags);
-
- if (!test_and_set_bit(FLAGS_BUSY, &dd->flags))
- omap_aes_handle_req(dd);
-
- pr_debug("exit\n");
-
- return err;
+ return omap_aes_handle_queue(dd, req);
}
/* ********************** ALG API ************************************ */
@@ -701,7 +711,6 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
memcpy(ctx->key, key, keylen);
ctx->keylen = keylen;
- ctx->flags |= FLAGS_NEW_KEY;
return 0;
}
@@ -750,7 +759,7 @@ static struct crypto_alg algs[] = {
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_aes_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = omap_aes_cra_init,
@@ -770,7 +779,7 @@ static struct crypto_alg algs[] = {
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_aes_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = omap_aes_cra_init,
@@ -849,7 +858,8 @@ static int omap_aes_probe(struct platform_device *pdev)
(reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR);
clk_disable(dd->iclk);
- tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd);
+ tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
+ tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd);
err = omap_aes_dma_init(dd);
if (err)
@@ -876,7 +886,8 @@ err_algs:
crypto_unregister_alg(&algs[j]);
omap_aes_dma_cleanup(dd);
err_dma:
- tasklet_kill(&dd->task);
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
iounmap(dd->io_base);
err_io:
clk_put(dd->iclk);
@@ -903,7 +914,8 @@ static int omap_aes_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(algs); i++)
crypto_unregister_alg(&algs[i]);
- tasklet_kill(&dd->task);
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
omap_aes_dma_cleanup(dd);
iounmap(dd->io_base);
clk_put(dd->iclk);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index a081c7c7d03f..2e71123516e0 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -72,10 +72,9 @@
#define DEFAULT_TIMEOUT_INTERVAL HZ
-#define FLAGS_FIRST 0x0001
#define FLAGS_FINUP 0x0002
#define FLAGS_FINAL 0x0004
-#define FLAGS_FAST 0x0008
+#define FLAGS_SG 0x0008
#define FLAGS_SHA1 0x0010
#define FLAGS_DMA_ACTIVE 0x0020
#define FLAGS_OUTPUT_READY 0x0040
@@ -83,13 +82,17 @@
#define FLAGS_INIT 0x0100
#define FLAGS_CPU 0x0200
#define FLAGS_HMAC 0x0400
-
-/* 3rd byte */
-#define FLAGS_BUSY 16
+#define FLAGS_ERROR 0x0800
+#define FLAGS_BUSY 0x1000
#define OP_UPDATE 1
#define OP_FINAL 2
+#define OMAP_ALIGN_MASK (sizeof(u32)-1)
+#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32))))
+
+#define BUFLEN PAGE_SIZE
+
struct omap_sham_dev;
struct omap_sham_reqctx {
@@ -97,8 +100,8 @@ struct omap_sham_reqctx {
unsigned long flags;
unsigned long op;
+ u8 digest[SHA1_DIGEST_SIZE] OMAP_ALIGNED;
size_t digcnt;
- u8 *buffer;
size_t bufcnt;
size_t buflen;
dma_addr_t dma_addr;
@@ -107,6 +110,8 @@ struct omap_sham_reqctx {
struct scatterlist *sg;
unsigned int offset; /* offset in current sg */
unsigned int total; /* total request */
+
+ u8 buffer[0] OMAP_ALIGNED;
};
struct omap_sham_hmac_ctx {
@@ -136,6 +141,7 @@ struct omap_sham_dev {
int irq;
struct clk *iclk;
spinlock_t lock;
+ int err;
int dma;
int dma_lch;
struct tasklet_struct done_task;
@@ -194,53 +200,68 @@ static inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit)
static void omap_sham_copy_hash(struct ahash_request *req, int out)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ u32 *hash = (u32 *)ctx->digest;
+ int i;
+
+ /* MD5 is almost unused. So copy sha1 size to reduce code */
+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) {
+ if (out)
+ hash[i] = omap_sham_read(ctx->dd,
+ SHA_REG_DIGEST(i));
+ else
+ omap_sham_write(ctx->dd,
+ SHA_REG_DIGEST(i), hash[i]);
+ }
+}
+
+static void omap_sham_copy_ready_hash(struct ahash_request *req)
+{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ u32 *in = (u32 *)ctx->digest;
u32 *hash = (u32 *)req->result;
int i;
+ if (!hash)
+ return;
+
if (likely(ctx->flags & FLAGS_SHA1)) {
/* SHA1 results are in big endian */
for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
- if (out)
- hash[i] = be32_to_cpu(omap_sham_read(ctx->dd,
- SHA_REG_DIGEST(i)));
- else
- omap_sham_write(ctx->dd, SHA_REG_DIGEST(i),
- cpu_to_be32(hash[i]));
+ hash[i] = be32_to_cpu(in[i]);
} else {
/* MD5 results are in little endian */
for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++)
- if (out)
- hash[i] = le32_to_cpu(omap_sham_read(ctx->dd,
- SHA_REG_DIGEST(i)));
- else
- omap_sham_write(ctx->dd, SHA_REG_DIGEST(i),
- cpu_to_le32(hash[i]));
+ hash[i] = le32_to_cpu(in[i]);
}
}
-static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
- int final, int dma)
+static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- u32 val = length << 5, mask;
+ clk_enable(dd->iclk);
- if (unlikely(!ctx->digcnt)) {
+ if (!(dd->flags & FLAGS_INIT)) {
+ omap_sham_write_mask(dd, SHA_REG_MASK,
+ SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
- clk_enable(dd->iclk);
+ if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
+ SHA_REG_SYSSTATUS_RESETDONE))
+ return -ETIMEDOUT;
- if (!(dd->flags & FLAGS_INIT)) {
- omap_sham_write_mask(dd, SHA_REG_MASK,
- SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
+ dd->flags |= FLAGS_INIT;
+ dd->err = 0;
+ }
- if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
- SHA_REG_SYSSTATUS_RESETDONE))
- return -ETIMEDOUT;
+ return 0;
+}
- dd->flags |= FLAGS_INIT;
- }
- } else {
+static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
+ int final, int dma)
+{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
+ u32 val = length << 5, mask;
+
+ if (likely(ctx->digcnt))
omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt);
- }
omap_sham_write_mask(dd, SHA_REG_MASK,
SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0),
@@ -260,29 +281,26 @@ static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH;
omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask);
-
- return 0;
}
static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
size_t length, int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- int err, count, len32;
+ int count, len32;
const u32 *buffer = (const u32 *)buf;
dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
- err = omap_sham_write_ctrl(dd, length, final, 0);
- if (err)
- return err;
+ omap_sham_write_ctrl(dd, length, final, 0);
+
+ /* should be non-zero before next lines to disable clocks later */
+ ctx->digcnt += length;
if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY))
return -ETIMEDOUT;
- ctx->digcnt += length;
-
if (final)
ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
@@ -298,16 +316,11 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
size_t length, int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- int err, len32;
+ int len32;
dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
- /* flush cache entries related to our page */
- if (dma_addr == ctx->dma_addr)
- dma_sync_single_for_device(dd->dev, dma_addr, length,
- DMA_TO_DEVICE);
-
len32 = DIV_ROUND_UP(length, sizeof(u32));
omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32,
@@ -317,9 +330,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC,
dma_addr, 0, 0);
- err = omap_sham_write_ctrl(dd, length, final, 1);
- if (err)
- return err;
+ omap_sham_write_ctrl(dd, length, final, 1);
ctx->digcnt += length;
@@ -371,15 +382,29 @@ static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx)
return 0;
}
+static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
+ struct omap_sham_reqctx *ctx,
+ size_t length, int final)
+{
+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
+ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen);
+ return -EINVAL;
+ }
+
+ ctx->flags &= ~FLAGS_SG;
+
+ /* next call does not fail... so no unmap in the case of error */
+ return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final);
+}
+
static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
unsigned int final;
size_t count;
- if (!ctx->total)
- return 0;
-
omap_sham_append_sg(ctx);
final = (ctx->flags & FLAGS_FINUP) && !ctx->total;
@@ -390,30 +415,68 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
count = ctx->bufcnt;
ctx->bufcnt = 0;
- return omap_sham_xmit_dma(dd, ctx->dma_addr, count, final);
+ return omap_sham_xmit_dma_map(dd, ctx, count, final);
}
return 0;
}
-static int omap_sham_update_dma_fast(struct omap_sham_dev *dd)
+/* Start address alignment */
+#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32)))
+/* SHA1 block size alignment */
+#define SG_SA(sg) (IS_ALIGNED(sg->length, SHA1_MD5_BLOCK_SIZE))
+
+static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- unsigned int length;
+ unsigned int length, final, tail;
+ struct scatterlist *sg;
- ctx->flags |= FLAGS_FAST;
+ if (!ctx->total)
+ return 0;
+
+ if (ctx->bufcnt || ctx->offset)
+ return omap_sham_update_dma_slow(dd);
+
+ dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
+ ctx->digcnt, ctx->bufcnt, ctx->total);
+
+ sg = ctx->sg;
- length = min(ctx->total, sg_dma_len(ctx->sg));
- ctx->total = length;
+ if (!SG_AA(sg))
+ return omap_sham_update_dma_slow(dd);
+
+ if (!sg_is_last(sg) && !SG_SA(sg))
+ /* size is not SHA1_BLOCK_SIZE aligned */
+ return omap_sham_update_dma_slow(dd);
+
+ length = min(ctx->total, sg->length);
+
+ if (sg_is_last(sg)) {
+ if (!(ctx->flags & FLAGS_FINUP)) {
+ /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */
+ tail = length & (SHA1_MD5_BLOCK_SIZE - 1);
+ /* without finup() we need one block to close hash */
+ if (!tail)
+ tail = SHA1_MD5_BLOCK_SIZE;
+ length -= tail;
+ }
+ }
if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
dev_err(dd->dev, "dma_map_sg error\n");
return -EINVAL;
}
+ ctx->flags |= FLAGS_SG;
+
ctx->total -= length;
+ ctx->offset = length; /* offset where to start slow */
- return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1);
+ final = (ctx->flags & FLAGS_FINUP) && !ctx->total;
+
+ /* next call does not fail... so no unmap in the case of error */
+ return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final);
}
static int omap_sham_update_cpu(struct omap_sham_dev *dd)
@@ -433,8 +496,17 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
omap_stop_dma(dd->dma_lch);
- if (ctx->flags & FLAGS_FAST)
+ if (ctx->flags & FLAGS_SG) {
dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
+ if (ctx->sg->length == ctx->offset) {
+ ctx->sg = sg_next(ctx->sg);
+ if (ctx->sg)
+ ctx->offset = 0;
+ }
+ } else {
+ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
+ DMA_TO_DEVICE);
+ }
return 0;
}
@@ -454,14 +526,7 @@ static void omap_sham_cleanup(struct ahash_request *req)
spin_unlock_irqrestore(&dd->lock, flags);
if (ctx->digcnt)
- clk_disable(dd->iclk);
-
- if (ctx->dma_addr)
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
- DMA_TO_DEVICE);
-
- if (ctx->buffer)
- free_page((unsigned long)ctx->buffer);
+ omap_sham_copy_ready_hash(req);
dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt);
}
@@ -489,8 +554,6 @@ static int omap_sham_init(struct ahash_request *req)
ctx->flags = 0;
- ctx->flags |= FLAGS_FIRST;
-
dev_dbg(dd->dev, "init: digest size: %d\n",
crypto_ahash_digestsize(tfm));
@@ -499,21 +562,7 @@ static int omap_sham_init(struct ahash_request *req)
ctx->bufcnt = 0;
ctx->digcnt = 0;
-
- ctx->buflen = PAGE_SIZE;
- ctx->buffer = (void *)__get_free_page(
- (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC);
- if (!ctx->buffer)
- return -ENOMEM;
-
- ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
- dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen);
- free_page((unsigned long)ctx->buffer);
- return -EINVAL;
- }
+ ctx->buflen = BUFLEN;
if (tctx->flags & FLAGS_HMAC) {
struct omap_sham_hmac_ctx *bctx = tctx->base;
@@ -538,10 +587,8 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
if (ctx->flags & FLAGS_CPU)
err = omap_sham_update_cpu(dd);
- else if (ctx->flags & FLAGS_FAST)
- err = omap_sham_update_dma_fast(dd);
else
- err = omap_sham_update_dma_slow(dd);
+ err = omap_sham_update_dma_start(dd);
/* wait for dma completion before can take more data */
dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt);
@@ -560,15 +607,12 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
use_dma = 0;
if (use_dma)
- err = omap_sham_xmit_dma(dd, ctx->dma_addr, ctx->bufcnt, 1);
+ err = omap_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1);
else
err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1);
ctx->bufcnt = 0;
- if (err != -EINPROGRESS)
- omap_sham_cleanup(req);
-
dev_dbg(dd->dev, "final_req: err: %d\n", err);
return err;
@@ -576,6 +620,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
static int omap_sham_finish_req_hmac(struct ahash_request *req)
{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct omap_sham_hmac_ctx *bctx = tctx->base;
int bs = crypto_shash_blocksize(bctx->shash);
@@ -590,48 +635,56 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req)
return crypto_shash_init(&desc.shash) ?:
crypto_shash_update(&desc.shash, bctx->opad, bs) ?:
- crypto_shash_finup(&desc.shash, req->result, ds, req->result);
+ crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest);
}
static void omap_sham_finish_req(struct ahash_request *req, int err)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ struct omap_sham_dev *dd = ctx->dd;
if (!err) {
omap_sham_copy_hash(ctx->dd->req, 1);
if (ctx->flags & FLAGS_HMAC)
err = omap_sham_finish_req_hmac(req);
+ } else {
+ ctx->flags |= FLAGS_ERROR;
}
- if (ctx->flags & FLAGS_FINAL)
+ if ((ctx->flags & FLAGS_FINAL) || err)
omap_sham_cleanup(req);
- clear_bit(FLAGS_BUSY, &ctx->dd->flags);
+ clk_disable(dd->iclk);
+ dd->flags &= ~FLAGS_BUSY;
if (req->base.complete)
req->base.complete(&req->base, err);
}
-static int omap_sham_handle_queue(struct omap_sham_dev *dd)
+static int omap_sham_handle_queue(struct omap_sham_dev *dd,
+ struct ahash_request *req)
{
struct crypto_async_request *async_req, *backlog;
struct omap_sham_reqctx *ctx;
- struct ahash_request *req, *prev_req;
+ struct ahash_request *prev_req;
unsigned long flags;
- int err = 0;
-
- if (test_and_set_bit(FLAGS_BUSY, &dd->flags))
- return 0;
+ int err = 0, ret = 0;
spin_lock_irqsave(&dd->lock, flags);
+ if (req)
+ ret = ahash_enqueue_request(&dd->queue, req);
+ if (dd->flags & FLAGS_BUSY) {
+ spin_unlock_irqrestore(&dd->lock, flags);
+ return ret;
+ }
backlog = crypto_get_backlog(&dd->queue);
async_req = crypto_dequeue_request(&dd->queue);
- if (!async_req)
- clear_bit(FLAGS_BUSY, &dd->flags);
+ if (async_req)
+ dd->flags |= FLAGS_BUSY;
spin_unlock_irqrestore(&dd->lock, flags);
if (!async_req)
- return 0;
+ return ret;
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
@@ -646,7 +699,22 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd)
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
ctx->op, req->nbytes);
- if (req != prev_req && ctx->digcnt)
+
+ err = omap_sham_hw_init(dd);
+ if (err)
+ goto err1;
+
+ omap_set_dma_dest_params(dd->dma_lch, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ dd->phys_base + SHA_REG_DIN(0), 0, 16);
+
+ omap_set_dma_dest_burst_mode(dd->dma_lch,
+ OMAP_DMA_DATA_BURST_16);
+
+ omap_set_dma_src_burst_mode(dd->dma_lch,
+ OMAP_DMA_DATA_BURST_4);
+
+ if (ctx->digcnt)
/* request has changed - restore hash */
omap_sham_copy_hash(req, 0);
@@ -658,7 +726,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd)
} else if (ctx->op == OP_FINAL) {
err = omap_sham_final_req(dd);
}
-
+err1:
if (err != -EINPROGRESS) {
/* done_task will not finish it, so do it here */
omap_sham_finish_req(req, err);
@@ -667,7 +735,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd)
dev_dbg(dd->dev, "exit, err: %d\n", err);
- return err;
+ return ret;
}
static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
@@ -675,18 +743,10 @@ static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct omap_sham_dev *dd = tctx->dd;
- unsigned long flags;
- int err;
ctx->op = op;
- spin_lock_irqsave(&dd->lock, flags);
- err = ahash_enqueue_request(&dd->queue, req);
- spin_unlock_irqrestore(&dd->lock, flags);
-
- omap_sham_handle_queue(dd);
-
- return err;
+ return omap_sham_handle_queue(dd, req);
}
static int omap_sham_update(struct ahash_request *req)
@@ -709,21 +769,13 @@ static int omap_sham_update(struct ahash_request *req)
*/
omap_sham_append_sg(ctx);
return 0;
- } else if (ctx->bufcnt + ctx->total <= 64) {
+ } else if (ctx->bufcnt + ctx->total <= SHA1_MD5_BLOCK_SIZE) {
+ /*
+ * faster to use CPU for short transfers
+ */
ctx->flags |= FLAGS_CPU;
- } else if (!ctx->bufcnt && sg_is_last(ctx->sg)) {
- /* may be can use faster functions */
- int aligned = IS_ALIGNED((u32)ctx->sg->offset,
- sizeof(u32));
-
- if (aligned && (ctx->flags & FLAGS_FIRST))
- /* digest: first and final */
- ctx->flags |= FLAGS_FAST;
-
- ctx->flags &= ~FLAGS_FIRST;
}
- } else if (ctx->bufcnt + ctx->total <= ctx->buflen) {
- /* if not finaup -> not fast */
+ } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
omap_sham_append_sg(ctx);
return 0;
}
@@ -761,12 +813,14 @@ static int omap_sham_final(struct ahash_request *req)
ctx->flags |= FLAGS_FINUP;
- /* OMAP HW accel works only with buffers >= 9 */
- /* HMAC is always >= 9 because of ipad */
- if ((ctx->digcnt + ctx->bufcnt) < 9)
- err = omap_sham_final_shash(req);
- else if (ctx->bufcnt)
- return omap_sham_enqueue(req, OP_FINAL);
+ if (!(ctx->flags & FLAGS_ERROR)) {
+ /* OMAP HW accel works only with buffers >= 9 */
+ /* HMAC is always >= 9 because of ipad */
+ if ((ctx->digcnt + ctx->bufcnt) < 9)
+ err = omap_sham_final_shash(req);
+ else if (ctx->bufcnt)
+ return omap_sham_enqueue(req, OP_FINAL);
+ }
omap_sham_cleanup(req);
@@ -836,6 +890,8 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
const char *alg_name = crypto_tfm_alg_name(tfm);
+ pr_info("enter\n");
+
/* Allocate a fallback and abort if it failed. */
tctx->fallback = crypto_alloc_shash(alg_name, 0,
CRYPTO_ALG_NEED_FALLBACK);
@@ -846,7 +902,7 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
}
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
- sizeof(struct omap_sham_reqctx));
+ sizeof(struct omap_sham_reqctx) + BUFLEN);
if (alg_base) {
struct omap_sham_hmac_ctx *bctx = tctx->base;
@@ -932,7 +988,7 @@ static struct ahash_alg algs[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -956,7 +1012,7 @@ static struct ahash_alg algs[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx) +
sizeof(struct omap_sham_hmac_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha1_init,
.cra_exit = omap_sham_cra_exit,
@@ -980,7 +1036,7 @@ static struct ahash_alg algs[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx) +
sizeof(struct omap_sham_hmac_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_md5_init,
.cra_exit = omap_sham_cra_exit,
@@ -993,7 +1049,7 @@ static void omap_sham_done_task(unsigned long data)
struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
struct ahash_request *req = dd->req;
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
- int ready = 1;
+ int ready = 0, err = 0;
if (ctx->flags & FLAGS_OUTPUT_READY) {
ctx->flags &= ~FLAGS_OUTPUT_READY;
@@ -1003,15 +1059,18 @@ static void omap_sham_done_task(unsigned long data)
if (dd->flags & FLAGS_DMA_ACTIVE) {
dd->flags &= ~FLAGS_DMA_ACTIVE;
omap_sham_update_dma_stop(dd);
- omap_sham_update_dma_slow(dd);
+ if (!dd->err)
+ err = omap_sham_update_dma_start(dd);
}
- if (ready && !(dd->flags & FLAGS_DMA_ACTIVE)) {
- dev_dbg(dd->dev, "update done\n");
+ err = dd->err ? : err;
+
+ if (err != -EINPROGRESS && (ready || err)) {
+ dev_dbg(dd->dev, "update done: err: %d\n", err);
/* finish curent request */
- omap_sham_finish_req(req, 0);
+ omap_sham_finish_req(req, err);
/* start new request */
- omap_sham_handle_queue(dd);
+ omap_sham_handle_queue(dd, NULL);
}
}
@@ -1019,7 +1078,7 @@ static void omap_sham_queue_task(unsigned long data)
{
struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
- omap_sham_handle_queue(dd);
+ omap_sham_handle_queue(dd, NULL);
}
static irqreturn_t omap_sham_irq(int irq, void *dev_id)
@@ -1041,6 +1100,7 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id)
omap_sham_read(dd, SHA_REG_CTRL);
ctx->flags |= FLAGS_OUTPUT_READY;
+ dd->err = 0;
tasklet_schedule(&dd->done_task);
return IRQ_HANDLED;
@@ -1050,8 +1110,13 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
{
struct omap_sham_dev *dd = data;
- if (likely(lch == dd->dma_lch))
- tasklet_schedule(&dd->done_task);
+ if (ch_status != OMAP_DMA_BLOCK_IRQ) {
+ pr_err("omap-sham DMA error status: 0x%hx\n", ch_status);
+ dd->err = -EIO;
+ dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
+ }
+
+ tasklet_schedule(&dd->done_task);
}
static int omap_sham_dma_init(struct omap_sham_dev *dd)
@@ -1066,15 +1131,6 @@ static int omap_sham_dma_init(struct omap_sham_dev *dd)
dev_err(dd->dev, "Unable to request DMA channel\n");
return err;
}
- omap_set_dma_dest_params(dd->dma_lch, 0,
- OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + SHA_REG_DIN(0), 0, 16);
-
- omap_set_dma_dest_burst_mode(dd->dma_lch,
- OMAP_DMA_DATA_BURST_16);
-
- omap_set_dma_src_burst_mode(dd->dma_lch,
- OMAP_DMA_DATA_BURST_4);
return 0;
}
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 2e992bc8015b..db33d300aa23 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -9,6 +9,7 @@
#include <crypto/algapi.h>
#include <crypto/aes.h>
+#include <crypto/padlock.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -21,7 +22,6 @@
#include <asm/byteorder.h>
#include <asm/processor.h>
#include <asm/i387.h>
-#include "padlock.h"
/*
* Number of data blocks actually fetched for each xcrypt insn.
@@ -286,7 +286,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
if (initial)
asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */
: "+S" (input), "+D" (output), "+a" (iv)
- : "d" (control_word), "b" (key), "c" (count));
+ : "d" (control_word), "b" (key), "c" (initial));
asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */
: "+S" (input), "+D" (output), "+a" (iv)
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index d3a27e0119bc..adf075b6b9a8 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -13,6 +13,7 @@
*/
#include <crypto/internal/hash.h>
+#include <crypto/padlock.h>
#include <crypto/sha.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -22,13 +23,6 @@
#include <linux/kernel.h>
#include <linux/scatterlist.h>
#include <asm/i387.h>
-#include "padlock.h"
-
-#ifdef CONFIG_64BIT
-#define STACK_ALIGN 16
-#else
-#define STACK_ALIGN 4
-#endif
struct padlock_sha_desc {
struct shash_desc fallback;
diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h
deleted file mode 100644
index b728e4518bd1..000000000000
--- a/drivers/crypto/padlock.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Driver for VIA PadLock
- *
- * Copyright (c) 2004 Michal Ludvig <michal@logix.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 (at your option)
- * any later version.
- *
- */
-
-#ifndef _CRYPTO_PADLOCK_H
-#define _CRYPTO_PADLOCK_H
-
-#define PADLOCK_ALIGNMENT 16
-
-#define PFX "padlock: "
-
-#define PADLOCK_CRA_PRIORITY 300
-#define PADLOCK_COMPOSITE_PRIORITY 400
-
-#endif /* _CRYPTO_PADLOCK_H */
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index b98c67664ae7..c461eda62411 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -110,8 +110,6 @@ static void unregister_dca_providers(void)
/* at this point only one domain in the list is expected */
domain = list_first_entry(&dca_domains, struct dca_domain, node);
- if (!domain)
- return;
list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) {
list_del(&dca->node);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6ee23592700a..1c28816152fa 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -109,7 +109,7 @@ config FSL_DMA
config MPC512X_DMA
tristate "Freescale MPC512x built-in DMA engine support"
- depends on PPC_MPC512x
+ depends on PPC_MPC512x || PPC_MPC831x
select DMA_ENGINE
---help---
Enable support for the Freescale MPC512x built-in DMA engine.
@@ -200,11 +200,16 @@ config PL330_DMA
platform_data for a dma-pl330 device.
config PCH_DMA
- tristate "Topcliff (Intel EG20T) PCH DMA support"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH DMA support"
depends on PCI && X86
select DMA_ENGINE
help
- Enable support for the Topcliff (Intel EG20T) PCH DMA engine.
+ Enable support for Intel EG20T PCH DMA engine.
+
+ This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/
+ Output Hub) which is for IVI(In-Vehicle Infotainment) use.
+ ML7213 is companion chip for Intel Atom E6xx series.
+ ML7213 is completely compatible for Intel EG20T PCH.
config IMX_SDMA
tristate "i.MX SDMA support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a8a84f4587f2..64b21f5cd740 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -1,8 +1,8 @@
ifeq ($(CONFIG_DMADEVICES_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
+ ccflags-y += -DDEBUG
endif
ifeq ($(CONFIG_DMADEVICES_VDEBUG),y)
- EXTRA_CFLAGS += -DVERBOSE_DEBUG
+ ccflags-y += -DVERBOSE_DEBUG
endif
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index b605cc9ac3a2..297f48b0cba9 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -19,14 +19,14 @@
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * The full GNU General Public License is iin this distribution in the
- * file called COPYING.
+ * The full GNU General Public License is in this distribution in the file
+ * called COPYING.
*
* Documentation: ARM DDI 0196G == PL080
- * Documentation: ARM DDI 0218E == PL081
+ * Documentation: ARM DDI 0218E == PL081
*
- * PL080 & PL081 both have 16 sets of DMA signals that can be routed to
- * any channel.
+ * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any
+ * channel.
*
* The PL080 has 8 channels available for simultaneous use, and the PL081
* has only two channels. So on these DMA controllers the number of channels
@@ -53,7 +53,23 @@
*
* ASSUMES default (little) endianness for DMA transfers
*
- * Only DMAC flow control is implemented
+ * The PL08x has two flow control settings:
+ * - DMAC flow control: the transfer size defines the number of transfers
+ * which occur for the current LLI entry, and the DMAC raises TC at the
+ * end of every LLI entry. Observed behaviour shows the DMAC listening
+ * to both the BREQ and SREQ signals (contrary to documented),
+ * transferring data if either is active. The LBREQ and LSREQ signals
+ * are ignored.
+ *
+ * - Peripheral flow control: the transfer size is ignored (and should be
+ * zero). The data is transferred from the current LLI entry, until
+ * after the final transfer signalled by LBREQ or LSREQ. The DMAC
+ * will then move to the next LLI entry.
+ *
+ * Only the former works sanely with scatter lists, so we only implement
+ * the DMAC flow control method. However, peripherals which use the LBREQ
+ * and LSREQ signals (eg, MMCI) are unable to use this mode, which through
+ * these hardware restrictions prevents them from using scatter DMA.
*
* Global TODO:
* - Break out common code from arch/arm/mach-s3c64xx and share
@@ -61,50 +77,39 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/dmapool.h>
-#include <linux/amba/bus.h>
#include <linux/dmaengine.h>
+#include <linux/amba/bus.h>
#include <linux/amba/pl08x.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <asm/hardware/pl080.h>
-#include <asm/dma.h>
-#include <asm/mach/dma.h>
-#include <asm/atomic.h>
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
#define DRIVER_NAME "pl08xdmac"
/**
- * struct vendor_data - vendor-specific config parameters
- * for PL08x derivates
- * @name: the name of this specific variant
+ * struct vendor_data - vendor-specific config parameters for PL08x derivatives
* @channels: the number of channels available in this variant
- * @dualmaster: whether this version supports dual AHB masters
- * or not.
+ * @dualmaster: whether this version supports dual AHB masters or not.
*/
struct vendor_data {
- char *name;
u8 channels;
bool dualmaster;
};
/*
* PL08X private data structures
- * An LLI struct - see pl08x TRM
- * Note that next uses bit[0] as a bus bit,
- * start & end do not - their bus bit info
- * is in cctl
+ * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit,
+ * start & end do not - their bus bit info is in cctl. Also note that these
+ * are fixed 32-bit quantities.
*/
-struct lli {
- dma_addr_t src;
- dma_addr_t dst;
- dma_addr_t next;
+struct pl08x_lli {
+ u32 src;
+ u32 dst;
+ u32 lli;
u32 cctl;
};
@@ -119,6 +124,8 @@ struct lli {
* @phy_chans: array of data for the physical channels
* @pool: a pool for the LLI descriptors
* @pool_ctr: counter of LLIs in the pool
+ * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches
+ * @mem_buses: set to indicate memory transfers on AHB2.
* @lock: a spinlock for this struct
*/
struct pl08x_driver_data {
@@ -126,11 +133,13 @@ struct pl08x_driver_data {
struct dma_device memcpy;
void __iomem *base;
struct amba_device *adev;
- struct vendor_data *vd;
+ const struct vendor_data *vd;
struct pl08x_platform_data *pd;
struct pl08x_phy_chan *phy_chans;
struct dma_pool *pool;
int pool_ctr;
+ u8 lli_buses;
+ u8 mem_buses;
spinlock_t lock;
};
@@ -152,9 +161,9 @@ struct pl08x_driver_data {
/* Size (bytes) of each LLI buffer allocated for one transfer */
# define PL08X_LLI_TSFR_SIZE 0x2000
-/* Maximimum times we call dma_pool_alloc on this pool without freeing */
+/* Maximum times we call dma_pool_alloc on this pool without freeing */
#define PL08X_MAX_ALLOCS 0x40
-#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli))
+#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
#define PL08X_ALIGN 8
static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
@@ -162,6 +171,11 @@ static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
return container_of(chan, struct pl08x_dma_chan, chan);
}
+static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx)
+{
+ return container_of(tx, struct pl08x_txd, tx);
+}
+
/*
* Physical channel handling
*/
@@ -177,88 +191,47 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
/*
* Set the initial DMA register values i.e. those for the first LLI
- * The next lli pointer and the configuration interrupt bit have
- * been set when the LLIs were constructed
+ * The next LLI pointer and the configuration interrupt bit have
+ * been set when the LLIs were constructed. Poke them into the hardware
+ * and start the transfer.
*/
-static void pl08x_set_cregs(struct pl08x_driver_data *pl08x,
- struct pl08x_phy_chan *ch)
-{
- /* Wait for channel inactive */
- while (pl08x_phy_channel_busy(ch))
- ;
-
- dev_vdbg(&pl08x->adev->dev,
- "WRITE channel %d: csrc=%08x, cdst=%08x, "
- "cctl=%08x, clli=%08x, ccfg=%08x\n",
- ch->id,
- ch->csrc,
- ch->cdst,
- ch->cctl,
- ch->clli,
- ch->ccfg);
-
- writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR);
- writel(ch->cdst, ch->base + PL080_CH_DST_ADDR);
- writel(ch->clli, ch->base + PL080_CH_LLI);
- writel(ch->cctl, ch->base + PL080_CH_CONTROL);
- writel(ch->ccfg, ch->base + PL080_CH_CONFIG);
-}
-
-static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan)
+static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
{
- struct pl08x_channel_data *cd = plchan->cd;
+ struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_phy_chan *phychan = plchan->phychan;
- struct pl08x_txd *txd = plchan->at;
-
- /* Copy the basic control register calculated at transfer config */
- phychan->csrc = txd->csrc;
- phychan->cdst = txd->cdst;
- phychan->clli = txd->clli;
- phychan->cctl = txd->cctl;
-
- /* Assign the signal to the proper control registers */
- phychan->ccfg = cd->ccfg;
- phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK;
- phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK;
- /* If it wasn't set from AMBA, ignore it */
- if (txd->direction == DMA_TO_DEVICE)
- /* Select signal as destination */
- phychan->ccfg |=
- (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT);
- else if (txd->direction == DMA_FROM_DEVICE)
- /* Select signal as source */
- phychan->ccfg |=
- (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT);
- /* Always enable error interrupts */
- phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK;
- /* Always enable terminal interrupts */
- phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK;
-}
-
-/*
- * Enable the DMA channel
- * Assumes all other configuration bits have been set
- * as desired before this code is called
- */
-static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
- struct pl08x_phy_chan *ch)
-{
+ struct pl08x_lli *lli = &txd->llis_va[0];
u32 val;
- /*
- * Do not access config register until channel shows as disabled
- */
- while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id))
- ;
+ plchan->at = txd;
- /*
- * Do not access config register until channel shows as inactive
- */
- val = readl(ch->base + PL080_CH_CONFIG);
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(phychan))
+ cpu_relax();
+
+ dev_vdbg(&pl08x->adev->dev,
+ "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+ "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
+ phychan->id, lli->src, lli->dst, lli->lli, lli->cctl,
+ txd->ccfg);
+
+ writel(lli->src, phychan->base + PL080_CH_SRC_ADDR);
+ writel(lli->dst, phychan->base + PL080_CH_DST_ADDR);
+ writel(lli->lli, phychan->base + PL080_CH_LLI);
+ writel(lli->cctl, phychan->base + PL080_CH_CONTROL);
+ writel(txd->ccfg, phychan->base + PL080_CH_CONFIG);
+
+ /* Enable the DMA channel */
+ /* Do not access config register until channel shows as disabled */
+ while (readl(pl08x->base + PL080_EN_CHAN) & (1 << phychan->id))
+ cpu_relax();
+
+ /* Do not access config register until channel shows as inactive */
+ val = readl(phychan->base + PL080_CH_CONFIG);
while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
- val = readl(ch->base + PL080_CH_CONFIG);
+ val = readl(phychan->base + PL080_CH_CONFIG);
- writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG);
+ writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG);
}
/*
@@ -266,10 +239,8 @@ static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
*
* Disabling individual channels could lose data.
*
- * Disable the peripheral DMA after disabling the DMAC
- * in order to allow the DMAC FIFO to drain, and
- * hence allow the channel to show inactive
- *
+ * Disable the peripheral DMA after disabling the DMAC in order to allow
+ * the DMAC FIFO to drain, and hence allow the channel to show inactive
*/
static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
{
@@ -282,7 +253,7 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
/* Wait for channel inactive */
while (pl08x_phy_channel_busy(ch))
- ;
+ cpu_relax();
}
static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
@@ -333,54 +304,56 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
{
struct pl08x_phy_chan *ch;
- struct pl08x_txd *txdi = NULL;
struct pl08x_txd *txd;
unsigned long flags;
- u32 bytes = 0;
+ size_t bytes = 0;
spin_lock_irqsave(&plchan->lock, flags);
-
ch = plchan->phychan;
txd = plchan->at;
/*
- * Next follow the LLIs to get the number of pending bytes in the
- * currently active transaction.
+ * Follow the LLIs to get the number of remaining
+ * bytes in the currently active transaction.
*/
if (ch && txd) {
- struct lli *llis_va = txd->llis_va;
- struct lli *llis_bus = (struct lli *) txd->llis_bus;
- u32 clli = readl(ch->base + PL080_CH_LLI);
+ u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
- /* First get the bytes in the current active LLI */
+ /* First get the remaining bytes in the active transfer */
bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
if (clli) {
- int i = 0;
+ struct pl08x_lli *llis_va = txd->llis_va;
+ dma_addr_t llis_bus = txd->llis_bus;
+ int index;
+
+ BUG_ON(clli < llis_bus || clli >= llis_bus +
+ sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
+
+ /*
+ * Locate the next LLI - as this is an array,
+ * it's simple maths to find.
+ */
+ index = (clli - llis_bus) / sizeof(struct pl08x_lli);
- /* Forward to the LLI pointed to by clli */
- while ((clli != (u32) &(llis_bus[i])) &&
- (i < MAX_NUM_TSFR_LLIS))
- i++;
+ for (; index < MAX_NUM_TSFR_LLIS; index++) {
+ bytes += get_bytes_in_cctl(llis_va[index].cctl);
- while (clli) {
- bytes += get_bytes_in_cctl(llis_va[i].cctl);
/*
- * A clli of 0x00000000 will terminate the
- * LLI list
+ * A LLI pointer of 0 terminates the LLI list
*/
- clli = llis_va[i].next;
- i++;
+ if (!llis_va[index].lli)
+ break;
}
}
}
/* Sum up all queued transactions */
- if (!list_empty(&plchan->desc_list)) {
- list_for_each_entry(txdi, &plchan->desc_list, node) {
+ if (!list_empty(&plchan->pend_list)) {
+ struct pl08x_txd *txdi;
+ list_for_each_entry(txdi, &plchan->pend_list, node) {
bytes += txdi->len;
}
-
}
spin_unlock_irqrestore(&plchan->lock, flags);
@@ -390,6 +363,10 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
/*
* Allocate a physical channel for a virtual channel
+ *
+ * Try to locate a physical channel to be used for this transfer. If all
+ * are taken return NULL and the requester will have to cope by using
+ * some fallback PIO mode or retrying later.
*/
static struct pl08x_phy_chan *
pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
@@ -399,12 +376,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
unsigned long flags;
int i;
- /*
- * Try to locate a physical channel to be used for
- * this transfer. If all are taken return NULL and
- * the requester will have to cope by using some fallback
- * PIO mode or retrying later.
- */
for (i = 0; i < pl08x->vd->channels; i++) {
ch = &pl08x->phy_chans[i];
@@ -465,11 +436,11 @@ static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded)
}
static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
- u32 tsize)
+ size_t tsize)
{
u32 retbits = cctl;
- /* Remove all src, dst and transfersize bits */
+ /* Remove all src, dst and transfer size bits */
retbits &= ~PL080_CONTROL_DWIDTH_MASK;
retbits &= ~PL080_CONTROL_SWIDTH_MASK;
retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK;
@@ -509,95 +480,87 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
return retbits;
}
+struct pl08x_lli_build_data {
+ struct pl08x_txd *txd;
+ struct pl08x_driver_data *pl08x;
+ struct pl08x_bus_data srcbus;
+ struct pl08x_bus_data dstbus;
+ size_t remainder;
+};
+
/*
- * Autoselect a master bus to use for the transfer
- * this prefers the destination bus if both available
- * if fixed address on one bus the other will be chosen
+ * Autoselect a master bus to use for the transfer this prefers the
+ * destination bus if both available if fixed address on one bus the
+ * other will be chosen
*/
-void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
- struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus,
- struct pl08x_bus_data **sbus, u32 cctl)
+static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
+ struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl)
{
if (!(cctl & PL080_CONTROL_DST_INCR)) {
- *mbus = src_bus;
- *sbus = dst_bus;
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
} else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
- *mbus = dst_bus;
- *sbus = src_bus;
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
} else {
- if (dst_bus->buswidth == 4) {
- *mbus = dst_bus;
- *sbus = src_bus;
- } else if (src_bus->buswidth == 4) {
- *mbus = src_bus;
- *sbus = dst_bus;
- } else if (dst_bus->buswidth == 2) {
- *mbus = dst_bus;
- *sbus = src_bus;
- } else if (src_bus->buswidth == 2) {
- *mbus = src_bus;
- *sbus = dst_bus;
+ if (bd->dstbus.buswidth == 4) {
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
+ } else if (bd->srcbus.buswidth == 4) {
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
+ } else if (bd->dstbus.buswidth == 2) {
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
+ } else if (bd->srcbus.buswidth == 2) {
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
} else {
- /* src_bus->buswidth == 1 */
- *mbus = dst_bus;
- *sbus = src_bus;
+ /* bd->srcbus.buswidth == 1 */
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
}
}
}
/*
- * Fills in one LLI for a certain transfer descriptor
- * and advance the counter
+ * Fills in one LLI for a certain transfer descriptor and advance the counter
*/
-int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
- struct pl08x_txd *txd, int num_llis, int len,
- u32 cctl, u32 *remainder)
+static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
+ int num_llis, int len, u32 cctl)
{
- struct lli *llis_va = txd->llis_va;
- struct lli *llis_bus = (struct lli *) txd->llis_bus;
+ struct pl08x_lli *llis_va = bd->txd->llis_va;
+ dma_addr_t llis_bus = bd->txd->llis_bus;
BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
- llis_va[num_llis].cctl = cctl;
- llis_va[num_llis].src = txd->srcbus.addr;
- llis_va[num_llis].dst = txd->dstbus.addr;
-
- /*
- * On versions with dual masters, you can optionally AND on
- * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read
- * in new LLIs with that controller, but we always try to
- * choose AHB1 to point into memory. The idea is to have AHB2
- * fixed on the peripheral and AHB1 messing around in the
- * memory. So we don't manipulate this bit currently.
- */
-
- llis_va[num_llis].next =
- (dma_addr_t)((u32) &(llis_bus[num_llis + 1]));
+ llis_va[num_llis].cctl = cctl;
+ llis_va[num_llis].src = bd->srcbus.addr;
+ llis_va[num_llis].dst = bd->dstbus.addr;
+ llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli);
+ if (bd->pl08x->lli_buses & PL08X_AHB2)
+ llis_va[num_llis].lli |= PL080_LLI_LM_AHB2;
if (cctl & PL080_CONTROL_SRC_INCR)
- txd->srcbus.addr += len;
+ bd->srcbus.addr += len;
if (cctl & PL080_CONTROL_DST_INCR)
- txd->dstbus.addr += len;
+ bd->dstbus.addr += len;
- *remainder -= len;
+ BUG_ON(bd->remainder < len);
- return num_llis + 1;
+ bd->remainder -= len;
}
/*
- * Return number of bytes to fill to boundary, or len
+ * Return number of bytes to fill to boundary, or len.
+ * This calculation works for any value of addr.
*/
-static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
+static inline size_t pl08x_pre_boundary(u32 addr, size_t len)
{
- u32 boundary;
-
- boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1)
- << PL08X_BOUNDARY_SHIFT;
+ size_t boundary_len = PL08X_BOUNDARY_SIZE -
+ (addr & (PL08X_BOUNDARY_SIZE - 1));
- if (boundary < addr + len)
- return boundary - addr;
- else
- return len;
+ return min(boundary_len, len);
}
/*
@@ -608,20 +571,13 @@ static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txd)
{
- struct pl08x_channel_data *cd = txd->cd;
struct pl08x_bus_data *mbus, *sbus;
- u32 remainder;
+ struct pl08x_lli_build_data bd;
int num_llis = 0;
u32 cctl;
- int max_bytes_per_lli;
- int total_bytes = 0;
- struct lli *llis_va;
- struct lli *llis_bus;
-
- if (!txd) {
- dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__);
- return 0;
- }
+ size_t max_bytes_per_lli;
+ size_t total_bytes = 0;
+ struct pl08x_lli *llis_va;
txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT,
&txd->llis_bus);
@@ -632,121 +588,79 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
pl08x->pool_ctr++;
- /*
- * Initialize bus values for this transfer
- * from the passed optimal values
- */
- if (!cd) {
- dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__);
- return 0;
- }
+ /* Get the default CCTL */
+ cctl = txd->cctl;
- /* Get the default CCTL from the platform data */
- cctl = cd->cctl;
-
- /*
- * On the PL080 we have two bus masters and we
- * should select one for source and one for
- * destination. We try to use AHB2 for the
- * bus which does not increment (typically the
- * peripheral) else we just choose something.
- */
- cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
- if (pl08x->vd->dualmaster) {
- if (cctl & PL080_CONTROL_SRC_INCR)
- /* Source increments, use AHB2 for destination */
- cctl |= PL080_CONTROL_DST_AHB2;
- else if (cctl & PL080_CONTROL_DST_INCR)
- /* Destination increments, use AHB2 for source */
- cctl |= PL080_CONTROL_SRC_AHB2;
- else
- /* Just pick something, source AHB1 dest AHB2 */
- cctl |= PL080_CONTROL_DST_AHB2;
- }
+ bd.txd = txd;
+ bd.pl08x = pl08x;
+ bd.srcbus.addr = txd->src_addr;
+ bd.dstbus.addr = txd->dst_addr;
/* Find maximum width of the source bus */
- txd->srcbus.maxwidth =
+ bd.srcbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
PL080_CONTROL_SWIDTH_SHIFT);
/* Find maximum width of the destination bus */
- txd->dstbus.maxwidth =
+ bd.dstbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
PL080_CONTROL_DWIDTH_SHIFT);
/* Set up the bus widths to the maximum */
- txd->srcbus.buswidth = txd->srcbus.maxwidth;
- txd->dstbus.buswidth = txd->dstbus.maxwidth;
+ bd.srcbus.buswidth = bd.srcbus.maxwidth;
+ bd.dstbus.buswidth = bd.dstbus.maxwidth;
dev_vdbg(&pl08x->adev->dev,
"%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
- __func__, txd->srcbus.buswidth, txd->dstbus.buswidth);
+ __func__, bd.srcbus.buswidth, bd.dstbus.buswidth);
/*
* Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
*/
- max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) *
+ max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) *
PL080_CONTROL_TRANSFER_SIZE_MASK;
dev_vdbg(&pl08x->adev->dev,
- "%s max bytes per lli = %d\n",
+ "%s max bytes per lli = %zu\n",
__func__, max_bytes_per_lli);
/* We need to count this down to zero */
- remainder = txd->len;
+ bd.remainder = txd->len;
dev_vdbg(&pl08x->adev->dev,
- "%s remainder = %d\n",
- __func__, remainder);
+ "%s remainder = %zu\n",
+ __func__, bd.remainder);
/*
* Choose bus to align to
* - prefers destination bus if both available
* - if fixed address on one bus chooses other
- * - modifies cctl to choose an apropriate master
- */
- pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus,
- &mbus, &sbus, cctl);
-
-
- /*
- * The lowest bit of the LLI register
- * is also used to indicate which master to
- * use for reading the LLIs.
*/
+ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
if (txd->len < mbus->buswidth) {
- /*
- * Less than a bus width available
- * - send as single bytes
- */
- while (remainder) {
+ /* Less than a bus width available - send as single bytes */
+ while (bd.remainder) {
dev_vdbg(&pl08x->adev->dev,
"%s single byte LLIs for a transfer of "
- "less than a bus width (remain %08x)\n",
- __func__, remainder);
+ "less than a bus width (remain 0x%08x)\n",
+ __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
- num_llis =
- pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1,
- cctl, &remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
} else {
- /*
- * Make one byte LLIs until master bus is aligned
- * - slave will then be aligned also
- */
+ /* Make one byte LLIs until master bus is aligned */
while ((mbus->addr) % (mbus->buswidth)) {
dev_vdbg(&pl08x->adev->dev,
"%s adjustment lli for less than bus width "
- "(remain %08x)\n",
- __func__, remainder);
+ "(remain 0x%08x)\n",
+ __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
- num_llis = pl08x_fill_lli_for_desc
- (pl08x, txd, num_llis, 1, cctl, &remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
/*
- * Master now aligned
+ * Master now aligned
* - if slave is not then we must set its width down
*/
if (sbus->addr % sbus->buswidth) {
@@ -761,63 +675,51 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
* Make largest possible LLIs until less than one bus
* width left
*/
- while (remainder > (mbus->buswidth - 1)) {
- int lli_len, target_len;
- int tsize;
- int odd_bytes;
+ while (bd.remainder > (mbus->buswidth - 1)) {
+ size_t lli_len, target_len, tsize, odd_bytes;
/*
* If enough left try to send max possible,
* otherwise try to send the remainder
*/
- target_len = remainder;
- if (remainder > max_bytes_per_lli)
- target_len = max_bytes_per_lli;
+ target_len = min(bd.remainder, max_bytes_per_lli);
/*
- * Set bus lengths for incrementing busses
- * to number of bytes which fill to next memory
- * boundary
+ * Set bus lengths for incrementing buses to the
+ * number of bytes which fill to next memory boundary,
+ * limiting on the target length calculated above.
*/
if (cctl & PL080_CONTROL_SRC_INCR)
- txd->srcbus.fill_bytes =
- pl08x_pre_boundary(
- txd->srcbus.addr,
- remainder);
+ bd.srcbus.fill_bytes =
+ pl08x_pre_boundary(bd.srcbus.addr,
+ target_len);
else
- txd->srcbus.fill_bytes =
- max_bytes_per_lli;
+ bd.srcbus.fill_bytes = target_len;
if (cctl & PL080_CONTROL_DST_INCR)
- txd->dstbus.fill_bytes =
- pl08x_pre_boundary(
- txd->dstbus.addr,
- remainder);
+ bd.dstbus.fill_bytes =
+ pl08x_pre_boundary(bd.dstbus.addr,
+ target_len);
else
- txd->dstbus.fill_bytes =
- max_bytes_per_lli;
+ bd.dstbus.fill_bytes = target_len;
- /*
- * Find the nearest
- */
- lli_len = min(txd->srcbus.fill_bytes,
- txd->dstbus.fill_bytes);
+ /* Find the nearest */
+ lli_len = min(bd.srcbus.fill_bytes,
+ bd.dstbus.fill_bytes);
- BUG_ON(lli_len > remainder);
+ BUG_ON(lli_len > bd.remainder);
if (lli_len <= 0) {
dev_err(&pl08x->adev->dev,
- "%s lli_len is %d, <= 0\n",
+ "%s lli_len is %zu, <= 0\n",
__func__, lli_len);
return 0;
}
if (lli_len == target_len) {
/*
- * Can send what we wanted
- */
- /*
- * Maintain alignment
+ * Can send what we wanted.
+ * Maintain alignment
*/
lli_len = (lli_len/mbus->buswidth) *
mbus->buswidth;
@@ -825,17 +727,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
} else {
/*
* So now we know how many bytes to transfer
- * to get to the nearest boundary
- * The next lli will past the boundary
- * - however we may be working to a boundary
- * on the slave bus
- * We need to ensure the master stays aligned
+ * to get to the nearest boundary. The next
+ * LLI will past the boundary. However, we
+ * may be working to a boundary on the slave
+ * bus. We need to ensure the master stays
+ * aligned, and that we are working in
+ * multiples of the bus widths.
*/
odd_bytes = lli_len % mbus->buswidth;
- /*
- * - and that we are working in multiples
- * of the bus widths
- */
lli_len -= odd_bytes;
}
@@ -855,41 +754,38 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
if (target_len != lli_len) {
dev_vdbg(&pl08x->adev->dev,
- "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n",
+ "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n",
__func__, target_len, lli_len, txd->len);
}
cctl = pl08x_cctl_bits(cctl,
- txd->srcbus.buswidth,
- txd->dstbus.buswidth,
+ bd.srcbus.buswidth,
+ bd.dstbus.buswidth,
tsize);
dev_vdbg(&pl08x->adev->dev,
- "%s fill lli with single lli chunk of size %08x (remainder %08x)\n",
- __func__, lli_len, remainder);
- num_llis = pl08x_fill_lli_for_desc(pl08x, txd,
- num_llis, lli_len, cctl,
- &remainder);
+ "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n",
+ __func__, lli_len, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++,
+ lli_len, cctl);
total_bytes += lli_len;
}
if (odd_bytes) {
/*
- * Creep past the boundary,
- * maintaining master alignment
+ * Creep past the boundary, maintaining
+ * master alignment
*/
int j;
for (j = 0; (j < mbus->buswidth)
- && (remainder); j++) {
+ && (bd.remainder); j++) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev,
- "%s align with boundardy, single byte (remain %08x)\n",
- __func__, remainder);
- num_llis =
- pl08x_fill_lli_for_desc(pl08x,
- txd, num_llis, 1,
- cctl, &remainder);
+ "%s align with boundary, single byte (remain 0x%08zx)\n",
+ __func__, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd,
+ num_llis++, 1, cctl);
total_bytes++;
}
}
@@ -898,25 +794,18 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
/*
* Send any odd bytes
*/
- if (remainder < 0) {
- dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n",
- __func__, remainder);
- return 0;
- }
-
- while (remainder) {
+ while (bd.remainder) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev,
- "%s align with boundardy, single odd byte (remain %d)\n",
- __func__, remainder);
- num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis,
- 1, cctl, &remainder);
+ "%s align with boundary, single odd byte (remain %zu)\n",
+ __func__, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
}
if (total_bytes != txd->len) {
dev_err(&pl08x->adev->dev,
- "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n",
+ "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n",
__func__, total_bytes, txd->len);
return 0;
}
@@ -927,41 +816,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
__func__, (u32) MAX_NUM_TSFR_LLIS);
return 0;
}
- /*
- * Decide whether this is a loop or a terminated transfer
- */
- llis_va = txd->llis_va;
- llis_bus = (struct lli *) txd->llis_bus;
- if (cd->circular_buffer) {
- /*
- * Loop the circular buffer so that the next element
- * points back to the beginning of the LLI.
- */
- llis_va[num_llis - 1].next =
- (dma_addr_t)((unsigned int)&(llis_bus[0]));
- } else {
- /*
- * On non-circular buffers, the final LLI terminates
- * the LLI.
- */
- llis_va[num_llis - 1].next = 0;
- /*
- * The final LLI element shall also fire an interrupt
- */
- llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
- }
-
- /* Now store the channel register values */
- txd->csrc = llis_va[0].src;
- txd->cdst = llis_va[0].dst;
- if (num_llis > 1)
- txd->clli = llis_va[0].next;
- else
- txd->clli = 0;
-
- txd->cctl = llis_va[0].cctl;
- /* ccfg will be set at physical channel allocation time */
+ llis_va = txd->llis_va;
+ /* The final LLI terminates the LLI. */
+ llis_va[num_llis - 1].lli = 0;
+ /* The final LLI element shall also fire an interrupt. */
+ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
#ifdef VERBOSE_DEBUG
{
@@ -969,13 +829,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
for (i = 0; i < num_llis; i++) {
dev_vdbg(&pl08x->adev->dev,
- "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n",
+ "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n",
i,
&llis_va[i],
llis_va[i].src,
llis_va[i].dst,
llis_va[i].cctl,
- llis_va[i].next
+ llis_va[i].lli
);
}
}
@@ -988,14 +848,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txd)
{
- if (!txd)
- dev_err(&pl08x->adev->dev,
- "%s no descriptor to free\n",
- __func__);
-
/* Free the LLI */
- dma_pool_free(pl08x->pool, txd->llis_va,
- txd->llis_bus);
+ dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus);
pl08x->pool_ctr--;
@@ -1008,13 +862,12 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txdi = NULL;
struct pl08x_txd *next;
- if (!list_empty(&plchan->desc_list)) {
+ if (!list_empty(&plchan->pend_list)) {
list_for_each_entry_safe(txdi,
- next, &plchan->desc_list, node) {
+ next, &plchan->pend_list, node) {
list_del(&txdi->node);
pl08x_free_txd(pl08x, txdi);
}
-
}
}
@@ -1069,6 +922,12 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
return -EBUSY;
}
ch->signal = ret;
+
+ /* Assign the flow control signal to this channel */
+ if (txd->direction == DMA_TO_DEVICE)
+ txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT;
+ else if (txd->direction == DMA_FROM_DEVICE)
+ txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT;
}
dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
@@ -1076,19 +935,54 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
ch->signal,
plchan->name);
+ plchan->phychan_hold++;
plchan->phychan = ch;
return 0;
}
+static void release_phy_channel(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_driver_data *pl08x = plchan->host;
+
+ if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ plchan->phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, plchan->phychan);
+ plchan->phychan = NULL;
+}
+
static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
+ struct pl08x_txd *txd = to_pl08x_txd(tx);
+ unsigned long flags;
- atomic_inc(&plchan->last_issued);
- tx->cookie = atomic_read(&plchan->last_issued);
- /* This unlock follows the lock in the prep() function */
- spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ spin_lock_irqsave(&plchan->lock, flags);
+
+ plchan->chan.cookie += 1;
+ if (plchan->chan.cookie < 0)
+ plchan->chan.cookie = 1;
+ tx->cookie = plchan->chan.cookie;
+
+ /* Put this onto the pending list */
+ list_add_tail(&txd->node, &plchan->pend_list);
+
+ /*
+ * If there was no physical channel available for this memcpy,
+ * stack the request up and indicate that the channel is waiting
+ * for a free physical channel.
+ */
+ if (!plchan->slave && !plchan->phychan) {
+ /* Do this memcpy whenever there is a channel ready */
+ plchan->state = PL08X_CHAN_WAITING;
+ plchan->waiting = txd;
+ } else {
+ plchan->phychan_hold--;
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
return tx->cookie;
}
@@ -1102,10 +996,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
}
/*
- * Code accessing dma_async_is_complete() in a tight loop
- * may give problems - could schedule where indicated.
- * If slaves are relying on interrupts to signal completion this
- * function must not be called with interrupts disabled
+ * Code accessing dma_async_is_complete() in a tight loop may give problems.
+ * If slaves are relying on interrupts to signal completion this function
+ * must not be called with interrupts disabled.
*/
static enum dma_status
pl08x_dma_tx_status(struct dma_chan *chan,
@@ -1118,7 +1011,7 @@ pl08x_dma_tx_status(struct dma_chan *chan,
enum dma_status ret;
u32 bytesleft = 0;
- last_used = atomic_read(&plchan->last_issued);
+ last_used = plchan->chan.cookie;
last_complete = plchan->lc;
ret = dma_async_is_complete(cookie, last_complete, last_used);
@@ -1128,13 +1021,9 @@ pl08x_dma_tx_status(struct dma_chan *chan,
}
/*
- * schedule(); could be inserted here
- */
-
- /*
* This cookie not complete yet
*/
- last_used = atomic_read(&plchan->last_issued);
+ last_used = plchan->chan.cookie;
last_complete = plchan->lc;
/* Get number of bytes left in the active transactions and queue */
@@ -1199,37 +1088,35 @@ static const struct burst_table burst_sizes[] = {
},
};
-static void dma_set_runtime_config(struct dma_chan *chan,
- struct dma_slave_config *config)
+static int dma_set_runtime_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_channel_data *cd = plchan->cd;
enum dma_slave_buswidth addr_width;
+ dma_addr_t addr;
u32 maxburst;
u32 cctl = 0;
- /* Mask out all except src and dst channel */
- u32 ccfg = cd->ccfg & 0x000003DEU;
- int i = 0;
+ int i;
+
+ if (!plchan->slave)
+ return -EINVAL;
/* Transfer direction */
plchan->runtime_direction = config->direction;
if (config->direction == DMA_TO_DEVICE) {
- plchan->runtime_addr = config->dst_addr;
- cctl |= PL080_CONTROL_SRC_INCR;
- ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr = config->dst_addr;
addr_width = config->dst_addr_width;
maxburst = config->dst_maxburst;
} else if (config->direction == DMA_FROM_DEVICE) {
- plchan->runtime_addr = config->src_addr;
- cctl |= PL080_CONTROL_DST_INCR;
- ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr = config->src_addr;
addr_width = config->src_addr_width;
maxburst = config->src_maxburst;
} else {
dev_err(&pl08x->adev->dev,
"bad runtime_config: alien transfer direction\n");
- return;
+ return -EINVAL;
}
switch (addr_width) {
@@ -1248,42 +1135,40 @@ static void dma_set_runtime_config(struct dma_chan *chan,
default:
dev_err(&pl08x->adev->dev,
"bad runtime_config: alien address width\n");
- return;
+ return -EINVAL;
}
/*
* Now decide on a maxburst:
- * If this channel will only request single transfers, set
- * this down to ONE element.
+ * If this channel will only request single transfers, set this
+ * down to ONE element. Also select one element if no maxburst
+ * is specified.
*/
- if (plchan->cd->single) {
+ if (plchan->cd->single || maxburst == 0) {
cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
(PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
} else {
- while (i < ARRAY_SIZE(burst_sizes)) {
+ for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
if (burst_sizes[i].burstwords <= maxburst)
break;
- i++;
- }
cctl |= burst_sizes[i].reg;
}
- /* Access the cell in privileged mode, non-bufferable, non-cacheable */
- cctl &= ~PL080_CONTROL_PROT_MASK;
- cctl |= PL080_CONTROL_PROT_SYS;
+ plchan->runtime_addr = addr;
/* Modify the default channel data to fit PrimeCell request */
cd->cctl = cctl;
- cd->ccfg = ccfg;
dev_dbg(&pl08x->adev->dev,
"configured channel %s (%s) for %s, data width %d, "
- "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n",
+ "maxburst %d words, LE, CCTL=0x%08x\n",
dma_chan_name(chan), plchan->name,
(config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
addr_width,
maxburst,
- cctl, ccfg);
+ cctl);
+
+ return 0;
}
/*
@@ -1293,35 +1178,26 @@ static void dma_set_runtime_config(struct dma_chan *chan,
static void pl08x_issue_pending(struct dma_chan *chan)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
- struct pl08x_driver_data *pl08x = plchan->host;
unsigned long flags;
spin_lock_irqsave(&plchan->lock, flags);
- /* Something is already active */
- if (plchan->at) {
- spin_unlock_irqrestore(&plchan->lock, flags);
- return;
- }
-
- /* Didn't get a physical channel so waiting for it ... */
- if (plchan->state == PL08X_CHAN_WAITING)
+ /* Something is already active, or we're waiting for a channel... */
+ if (plchan->at || plchan->state == PL08X_CHAN_WAITING) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
return;
+ }
/* Take the first element in the queue and execute it */
- if (!list_empty(&plchan->desc_list)) {
+ if (!list_empty(&plchan->pend_list)) {
struct pl08x_txd *next;
- next = list_first_entry(&plchan->desc_list,
+ next = list_first_entry(&plchan->pend_list,
struct pl08x_txd,
node);
list_del(&next->node);
- plchan->at = next;
plchan->state = PL08X_CHAN_RUNNING;
- /* Configure the physical channel for the active txd */
- pl08x_config_phychan_for_txd(plchan);
- pl08x_set_cregs(pl08x, plchan->phychan);
- pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ pl08x_start_txd(plchan, next);
}
spin_unlock_irqrestore(&plchan->lock, flags);
@@ -1330,30 +1206,17 @@ static void pl08x_issue_pending(struct dma_chan *chan)
static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
struct pl08x_txd *txd)
{
- int num_llis;
struct pl08x_driver_data *pl08x = plchan->host;
- int ret;
+ unsigned long flags;
+ int num_llis, ret;
num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
-
- if (!num_llis)
+ if (!num_llis) {
+ kfree(txd);
return -EINVAL;
+ }
- spin_lock_irqsave(&plchan->lock, plchan->lockflags);
-
- /*
- * If this device is not using a circular buffer then
- * queue this new descriptor for transfer.
- * The descriptor for a circular buffer continues
- * to be used until the channel is freed.
- */
- if (txd->cd->circular_buffer)
- dev_err(&pl08x->adev->dev,
- "%s attempting to queue a circular buffer\n",
- __func__);
- else
- list_add_tail(&txd->node,
- &plchan->desc_list);
+ spin_lock_irqsave(&plchan->lock, flags);
/*
* See if we already have a physical channel allocated,
@@ -1362,45 +1225,74 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
ret = prep_phy_channel(plchan, txd);
if (ret) {
/*
- * No physical channel available, we will
- * stack up the memcpy channels until there is a channel
- * available to handle it whereas slave transfers may
- * have been denied due to platform channel muxing restrictions
- * and since there is no guarantee that this will ever be
- * resolved, and since the signal must be aquired AFTER
- * aquiring the physical channel, we will let them be NACK:ed
- * with -EBUSY here. The drivers can alway retry the prep()
- * call if they are eager on doing this using DMA.
+ * No physical channel was available.
+ *
+ * memcpy transfers can be sorted out at submission time.
+ *
+ * Slave transfers may have been denied due to platform
+ * channel muxing restrictions. Since there is no guarantee
+ * that this will ever be resolved, and the signal must be
+ * acquired AFTER acquiring the physical channel, we will let
+ * them be NACK:ed with -EBUSY here. The drivers can retry
+ * the prep() call if they are eager on doing this using DMA.
*/
if (plchan->slave) {
pl08x_free_txd_list(pl08x, plchan);
- spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ pl08x_free_txd(pl08x, txd);
+ spin_unlock_irqrestore(&plchan->lock, flags);
return -EBUSY;
}
- /* Do this memcpy whenever there is a channel ready */
- plchan->state = PL08X_CHAN_WAITING;
- plchan->waiting = txd;
} else
/*
- * Else we're all set, paused and ready to roll,
- * status will switch to PL08X_CHAN_RUNNING when
- * we call issue_pending(). If there is something
- * running on the channel already we don't change
- * its state.
+ * Else we're all set, paused and ready to roll, status
+ * will switch to PL08X_CHAN_RUNNING when we call
+ * issue_pending(). If there is something running on the
+ * channel already we don't change its state.
*/
if (plchan->state == PL08X_CHAN_IDLE)
plchan->state = PL08X_CHAN_PAUSED;
- /*
- * Notice that we leave plchan->lock locked on purpose:
- * it will be unlocked in the subsequent tx_submit()
- * call. This is a consequence of the current API.
- */
+ spin_unlock_irqrestore(&plchan->lock, flags);
return 0;
}
/*
+ * Given the source and destination available bus masks, select which
+ * will be routed to each port. We try to have source and destination
+ * on separate ports, but always respect the allowable settings.
+ */
+static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst)
+{
+ u32 cctl = 0;
+
+ if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
+ cctl |= PL080_CONTROL_DST_AHB2;
+ if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
+ cctl |= PL080_CONTROL_SRC_AHB2;
+
+ return cctl;
+}
+
+static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
+ unsigned long flags)
+{
+ struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+
+ if (txd) {
+ dma_async_tx_descriptor_init(&txd->tx, &plchan->chan);
+ txd->tx.flags = flags;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ INIT_LIST_HEAD(&txd->node);
+
+ /* Always enable error and terminal interrupts */
+ txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK |
+ PL080_CONFIG_TC_IRQ_MASK;
+ }
+ return txd;
+}
+
+/*
* Initialize a descriptor to be used by memcpy submit
*/
static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
@@ -1412,40 +1304,38 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
struct pl08x_txd *txd;
int ret;
- txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ txd = pl08x_get_txd(plchan, flags);
if (!txd) {
dev_err(&pl08x->adev->dev,
"%s no memory for descriptor\n", __func__);
return NULL;
}
- dma_async_tx_descriptor_init(&txd->tx, chan);
txd->direction = DMA_NONE;
- txd->srcbus.addr = src;
- txd->dstbus.addr = dest;
+ txd->src_addr = src;
+ txd->dst_addr = dest;
+ txd->len = len;
/* Set platform data for m2m */
- txd->cd = &pl08x->pd->memcpy_channel;
+ txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl = pl08x->pd->memcpy_channel.cctl &
+ ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
+
/* Both to be incremented or the code will break */
- txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
- txd->tx.tx_submit = pl08x_tx_submit;
- txd->tx.callback = NULL;
- txd->tx.callback_param = NULL;
- txd->len = len;
+ txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
+
+ if (pl08x->vd->dualmaster)
+ txd->cctl |= pl08x_select_bus(pl08x,
+ pl08x->mem_buses, pl08x->mem_buses);
- INIT_LIST_HEAD(&txd->node);
ret = pl08x_prep_channel_resources(plchan, txd);
if (ret)
return NULL;
- /*
- * NB: the channel lock is held at this point so tx_submit()
- * must be called in direct succession.
- */
return &txd->tx;
}
-struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags)
@@ -1453,6 +1343,7 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_txd *txd;
+ u8 src_buses, dst_buses;
int ret;
/*
@@ -1467,14 +1358,12 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
__func__, sgl->length, plchan->name);
- txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ txd = pl08x_get_txd(plchan, flags);
if (!txd) {
dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
return NULL;
}
- dma_async_tx_descriptor_init(&txd->tx, chan);
-
if (direction != plchan->runtime_direction)
dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
"the direction configured for the PrimeCell\n",
@@ -1486,37 +1375,47 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
* channel target address dynamically at runtime.
*/
txd->direction = direction;
+ txd->len = sgl->length;
+
+ txd->cctl = plchan->cd->cctl &
+ ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
+ PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
+ PL080_CONTROL_PROT_MASK);
+
+ /* Access the cell in privileged mode, non-bufferable, non-cacheable */
+ txd->cctl |= PL080_CONTROL_PROT_SYS;
+
if (direction == DMA_TO_DEVICE) {
- txd->srcbus.addr = sgl->dma_address;
+ txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl |= PL080_CONTROL_SRC_INCR;
+ txd->src_addr = sgl->dma_address;
if (plchan->runtime_addr)
- txd->dstbus.addr = plchan->runtime_addr;
+ txd->dst_addr = plchan->runtime_addr;
else
- txd->dstbus.addr = plchan->cd->addr;
+ txd->dst_addr = plchan->cd->addr;
+ src_buses = pl08x->mem_buses;
+ dst_buses = plchan->cd->periph_buses;
} else if (direction == DMA_FROM_DEVICE) {
+ txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl |= PL080_CONTROL_DST_INCR;
if (plchan->runtime_addr)
- txd->srcbus.addr = plchan->runtime_addr;
+ txd->src_addr = plchan->runtime_addr;
else
- txd->srcbus.addr = plchan->cd->addr;
- txd->dstbus.addr = sgl->dma_address;
+ txd->src_addr = plchan->cd->addr;
+ txd->dst_addr = sgl->dma_address;
+ src_buses = plchan->cd->periph_buses;
+ dst_buses = pl08x->mem_buses;
} else {
dev_err(&pl08x->adev->dev,
"%s direction unsupported\n", __func__);
return NULL;
}
- txd->cd = plchan->cd;
- txd->tx.tx_submit = pl08x_tx_submit;
- txd->tx.callback = NULL;
- txd->tx.callback_param = NULL;
- txd->len = sgl->length;
- INIT_LIST_HEAD(&txd->node);
+
+ txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses);
ret = pl08x_prep_channel_resources(plchan, txd);
if (ret)
return NULL;
- /*
- * NB: the channel lock is held at this point so tx_submit()
- * must be called in direct succession.
- */
return &txd->tx;
}
@@ -1531,10 +1430,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
/* Controls applicable to inactive channels */
if (cmd == DMA_SLAVE_CONFIG) {
- dma_set_runtime_config(chan,
- (struct dma_slave_config *)
- arg);
- return 0;
+ return dma_set_runtime_config(chan,
+ (struct dma_slave_config *)arg);
}
/*
@@ -1558,16 +1455,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
* Mark physical channel as free and free any slave
* signal
*/
- if ((plchan->phychan->signal >= 0) &&
- pl08x->pd->put_signal) {
- pl08x->pd->put_signal(plchan);
- plchan->phychan->signal = -1;
- }
- pl08x_put_phy_channel(pl08x, plchan->phychan);
- plchan->phychan = NULL;
+ release_phy_channel(plchan);
}
- /* Stop any pending tasklet */
- tasklet_disable(&plchan->tasklet);
/* Dequeue jobs and free LLIs */
if (plchan->at) {
pl08x_free_txd(pl08x, plchan->at);
@@ -1609,10 +1498,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
/*
* Just check that the device is there and active
- * TODO: turn this bit on/off depending on the number of
- * physical channels actually used, if it is zero... well
- * shut it off. That will save some power. Cut the clock
- * at the same time.
+ * TODO: turn this bit on/off depending on the number of physical channels
+ * actually used, if it is zero... well shut it off. That will save some
+ * power. Cut the clock at the same time.
*/
static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
{
@@ -1620,78 +1508,66 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
val = readl(pl08x->base + PL080_CONFIG);
val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE);
- /* We implictly clear bit 1 and that means little-endian mode */
+ /* We implicitly clear bit 1 and that means little-endian mode */
val |= PL080_CONFIG_ENABLE;
writel(val, pl08x->base + PL080_CONFIG);
}
+static void pl08x_unmap_buffers(struct pl08x_txd *txd)
+{
+ struct device *dev = txd->tx.chan->device->dev;
+
+ if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+ dma_unmap_single(dev, txd->src_addr, txd->len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_page(dev, txd->src_addr, txd->len,
+ DMA_TO_DEVICE);
+ }
+ if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+ dma_unmap_single(dev, txd->dst_addr, txd->len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_page(dev, txd->dst_addr, txd->len,
+ DMA_FROM_DEVICE);
+ }
+}
+
static void pl08x_tasklet(unsigned long data)
{
struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
- struct pl08x_phy_chan *phychan = plchan->phychan;
struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ unsigned long flags;
- if (!plchan)
- BUG();
-
- spin_lock(&plchan->lock);
-
- if (plchan->at) {
- dma_async_tx_callback callback =
- plchan->at->tx.callback;
- void *callback_param =
- plchan->at->tx.callback_param;
-
- /*
- * Update last completed
- */
- plchan->lc =
- (plchan->at->tx.cookie);
-
- /*
- * Callback to signal completion
- */
- if (callback)
- callback(callback_param);
+ spin_lock_irqsave(&plchan->lock, flags);
- /*
- * Device callbacks should NOT clear
- * the current transaction on the channel
- * Linus: sometimes they should?
- */
- if (!plchan->at)
- BUG();
+ txd = plchan->at;
+ plchan->at = NULL;
- /*
- * Free the descriptor if it's not for a device
- * using a circular buffer
- */
- if (!plchan->at->cd->circular_buffer) {
- pl08x_free_txd(pl08x, plchan->at);
- plchan->at = NULL;
- }
- /*
- * else descriptor for circular
- * buffers only freed when
- * client has disabled dma
- */
+ if (txd) {
+ /* Update last completed */
+ plchan->lc = txd->tx.cookie;
}
- /*
- * If a new descriptor is queued, set it up
- * plchan->at is NULL here
- */
- if (!list_empty(&plchan->desc_list)) {
+
+ /* If a new descriptor is queued, set it up plchan->at is NULL here */
+ if (!list_empty(&plchan->pend_list)) {
struct pl08x_txd *next;
- next = list_first_entry(&plchan->desc_list,
+ next = list_first_entry(&plchan->pend_list,
struct pl08x_txd,
node);
list_del(&next->node);
- plchan->at = next;
- /* Configure the physical channel for the next txd */
- pl08x_config_phychan_for_txd(plchan);
- pl08x_set_cregs(pl08x, plchan->phychan);
- pl08x_enable_phy_chan(pl08x, plchan->phychan);
+
+ pl08x_start_txd(plchan, next);
+ } else if (plchan->phychan_hold) {
+ /*
+ * This channel is still in use - we have a new txd being
+ * prepared and will soon be queued. Don't give up the
+ * physical channel.
+ */
} else {
struct pl08x_dma_chan *waiting = NULL;
@@ -1699,20 +1575,14 @@ static void pl08x_tasklet(unsigned long data)
* No more jobs, so free up the physical channel
* Free any allocated signal on slave transfers too
*/
- if ((phychan->signal >= 0) && pl08x->pd->put_signal) {
- pl08x->pd->put_signal(plchan);
- phychan->signal = -1;
- }
- pl08x_put_phy_channel(pl08x, phychan);
- plchan->phychan = NULL;
+ release_phy_channel(plchan);
plchan->state = PL08X_CHAN_IDLE;
/*
- * And NOW before anyone else can grab that free:d
- * up physical channel, see if there is some memcpy
- * pending that seriously needs to start because of
- * being stacked up while we were choking the
- * physical channels with data.
+ * And NOW before anyone else can grab that free:d up
+ * physical channel, see if there is some memcpy pending
+ * that seriously needs to start because of being stacked
+ * up while we were choking the physical channels with data.
*/
list_for_each_entry(waiting, &pl08x->memcpy.channels,
chan.device_node) {
@@ -1724,6 +1594,7 @@ static void pl08x_tasklet(unsigned long data)
ret = prep_phy_channel(waiting,
waiting->waiting);
BUG_ON(ret);
+ waiting->phychan_hold--;
waiting->state = PL08X_CHAN_RUNNING;
waiting->waiting = NULL;
pl08x_issue_pending(&waiting->chan);
@@ -1732,7 +1603,25 @@ static void pl08x_tasklet(unsigned long data)
}
}
- spin_unlock(&plchan->lock);
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ if (txd) {
+ dma_async_tx_callback callback = txd->tx.callback;
+ void *callback_param = txd->tx.callback_param;
+
+ /* Don't try to unmap buffers on slave channels */
+ if (!plchan->slave)
+ pl08x_unmap_buffers(txd);
+
+ /* Free the descriptor */
+ spin_lock_irqsave(&plchan->lock, flags);
+ pl08x_free_txd(pl08x, txd);
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ /* Callback to signal completion */
+ if (callback)
+ callback(callback_param);
+ }
}
static irqreturn_t pl08x_irq(int irq, void *dev)
@@ -1744,9 +1633,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
val = readl(pl08x->base + PL080_ERR_STATUS);
if (val) {
- /*
- * An error interrupt (on one or more channels)
- */
+ /* An error interrupt (on one or more channels) */
dev_err(&pl08x->adev->dev,
"%s error interrupt, register value 0x%08x\n",
__func__, val);
@@ -1770,9 +1657,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
mask |= (1 << i);
}
}
- /*
- * Clear only the terminal interrupts on channels we processed
- */
+ /* Clear only the terminal interrupts on channels we processed */
writel(mask, pl08x->base + PL080_TC_CLEAR);
return mask ? IRQ_HANDLED : IRQ_NONE;
@@ -1791,6 +1676,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
int i;
INIT_LIST_HEAD(&dmadev->channels);
+
/*
* Register as many many memcpy as we have physical channels,
* we won't always be able to use all but the code will have
@@ -1819,16 +1705,23 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
return -ENOMEM;
}
}
+ if (chan->cd->circular_buffer) {
+ dev_err(&pl08x->adev->dev,
+ "channel %s: circular buffers not supported\n",
+ chan->name);
+ kfree(chan);
+ continue;
+ }
dev_info(&pl08x->adev->dev,
"initialize virtual channel \"%s\"\n",
chan->name);
chan->chan.device = dmadev;
- atomic_set(&chan->last_issued, 0);
- chan->lc = atomic_read(&chan->last_issued);
+ chan->chan.cookie = 0;
+ chan->lc = 0;
spin_lock_init(&chan->lock);
- INIT_LIST_HEAD(&chan->desc_list);
+ INIT_LIST_HEAD(&chan->pend_list);
tasklet_init(&chan->tasklet, pl08x_tasklet,
(unsigned long) chan);
@@ -1898,7 +1791,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, "CHANNEL:\tSTATE:\n");
seq_printf(s, "--------\t------\n");
list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
- seq_printf(s, "%s\t\t\%s\n", chan->name,
+ seq_printf(s, "%s\t\t%s\n", chan->name,
pl08x_state_str(chan->state));
}
@@ -1906,7 +1799,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, "CHANNEL:\tSTATE:\n");
seq_printf(s, "--------\t------\n");
list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
- seq_printf(s, "%s\t\t\%s\n", chan->name,
+ seq_printf(s, "%s\t\t%s\n", chan->name,
pl08x_state_str(chan->state));
}
@@ -1942,7 +1835,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
{
struct pl08x_driver_data *pl08x;
- struct vendor_data *vd = id->data;
+ const struct vendor_data *vd = id->data;
int ret = 0;
int i;
@@ -1990,6 +1883,14 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
pl08x->adev = adev;
pl08x->vd = vd;
+ /* By default, AHB1 only. If dualmaster, from platform */
+ pl08x->lli_buses = PL08X_AHB1;
+ pl08x->mem_buses = PL08X_AHB1;
+ if (pl08x->vd->dualmaster) {
+ pl08x->lli_buses = pl08x->pd->lli_buses;
+ pl08x->mem_buses = pl08x->pd->mem_buses;
+ }
+
/* A DMA memory pool for LLIs, align on 1-byte boundary */
pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
@@ -2009,14 +1910,12 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
/* Turn on the PL08x */
pl08x_ensure_on(pl08x);
- /*
- * Attach the interrupt handler
- */
+ /* Attach the interrupt handler */
writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
writel(0x000000FF, pl08x->base + PL080_TC_CLEAR);
ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED,
- vd->name, pl08x);
+ DRIVER_NAME, pl08x);
if (ret) {
dev_err(&adev->dev, "%s failed to request interrupt %d\n",
__func__, adev->irq[0]);
@@ -2087,8 +1986,9 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
amba_set_drvdata(adev, pl08x);
init_pl08x_debugfs(pl08x);
- dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n",
- vd->name, adev->res.start);
+ dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n",
+ amba_part(adev), amba_rev(adev),
+ (unsigned long long)adev->res.start, adev->irq[0]);
return 0;
out_no_slave_reg:
@@ -2115,13 +2015,11 @@ out_no_pl08x:
/* PL080 has 8 channels and the PL080 have just 2 */
static struct vendor_data vendor_pl080 = {
- .name = "PL080",
.channels = 8,
.dualmaster = true,
};
static struct vendor_data vendor_pl081 = {
- .name = "PL081",
.channels = 2,
.dualmaster = false,
};
@@ -2160,7 +2058,7 @@ static int __init pl08x_init(void)
retval = amba_driver_register(&pl08x_amba_driver);
if (retval)
printk(KERN_WARNING DRIVER_NAME
- "failed to register as an amba device (%d)\n",
+ "failed to register as an AMBA device (%d)\n",
retval);
return retval;
}
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index a0f3e6a06e06..3d7d705f026f 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -253,7 +253,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
/* move myself to free_list */
list_move(&desc->desc_node, &atchan->free_list);
- /* unmap dma addresses */
+ /* unmap dma addresses (not on slave channels) */
if (!atchan->chan_common.private) {
struct device *parent = chan2parent(&atchan->chan_common);
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
@@ -583,7 +583,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
desc->lli.ctrlb = ctrlb;
desc->txd.cookie = 0;
- async_tx_ack(&desc->txd);
if (!first) {
first = desc;
@@ -604,7 +603,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
/* set end-of-link to the last link descriptor of list*/
set_desc_eol(desc);
- desc->txd.flags = flags; /* client is in control of this ack */
+ first->txd.flags = flags; /* client is in control of this ack */
return &first->txd;
@@ -670,7 +669,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (!desc)
goto err_desc_get;
- mem = sg_phys(sg);
+ mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
@@ -712,7 +711,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (!desc)
goto err_desc_get;
- mem = sg_phys(sg);
+ mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
@@ -722,7 +721,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc->lli.daddr = mem;
desc->lli.ctrla = ctrla
| ATC_DST_WIDTH(mem_width)
- | len >> mem_width;
+ | len >> reg_width;
desc->lli.ctrlb = ctrlb;
if (!first) {
@@ -749,8 +748,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
first->txd.cookie = -EBUSY;
first->len = total_len;
- /* last link descriptor of list is responsible of flags */
- prev->txd.flags = flags; /* client is in control of this ack */
+ /* first link descriptor of list is responsible of flags */
+ first->txd.flags = flags; /* client is in control of this ack */
return &first->txd;
@@ -854,11 +853,11 @@ static void atc_issue_pending(struct dma_chan *chan)
dev_vdbg(chan2dev(chan), "issue_pending\n");
+ spin_lock_bh(&atchan->lock);
if (!atc_chan_is_enabled(atchan)) {
- spin_lock_bh(&atchan->lock);
atc_advance_work(atchan);
- spin_unlock_bh(&atchan->lock);
}
+ spin_unlock_bh(&atchan->lock);
}
/**
@@ -1210,7 +1209,7 @@ static int __init at_dma_init(void)
{
return platform_driver_probe(&at_dma_driver, at_dma_probe);
}
-module_init(at_dma_init);
+subsys_initcall(at_dma_init);
static void __exit at_dma_exit(void)
{
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 286c3ac6bdcc..4de947a450fc 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1,7 +1,7 @@
/*
* Freescale MPC85xx, MPC83xx DMA Engine support
*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved.
*
* Author:
* Zhang Wei <wei.zhang@freescale.com>, Jul 2007
@@ -50,9 +50,11 @@ static void dma_init(struct fsldma_chan *chan)
* EIE - Error interrupt enable
* EOSIE - End of segments interrupt enable (basic mode)
* EOLNIE - End of links interrupt enable
+ * BWC - Bandwidth sharing among channels
*/
- DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE
- | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
+ DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+ | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
+ | FSL_DMA_MR_EOSIE, 32);
break;
case FSL_DMA_IP_83XX:
/* Set the channel to below modes:
@@ -1322,6 +1324,8 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
fdev->common.device_control = fsl_dma_device_control;
fdev->common.dev = &op->dev;
+ dma_set_mask(&(op->dev), DMA_BIT_MASK(36));
+
dev_set_drvdata(&op->dev, fdev);
/*
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index cb4d6ff51597..ba9f403c0fbe 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved.
*
* Author:
* Zhang Wei <wei.zhang@freescale.com>, Jul 2007
@@ -36,6 +36,13 @@
#define FSL_DMA_MR_DAHE 0x00002000
#define FSL_DMA_MR_SAHE 0x00001000
+/*
+ * Bandwidth/pause control determines how many bytes a given
+ * channel is allowed to transfer before the DMA engine pauses
+ * the current channel and switches to the next channel
+ */
+#define FSL_DMA_MR_BWC 0x08000000
+
/* Special MR definition for MPC8349 */
#define FSL_DMA_MR_EOTIE 0x00000080
#define FSL_DMA_MR_PRC_RM 0x00000800
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index f629e4961af5..e53d438142bb 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -379,7 +379,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
return 0;
err_init:
- while (i-- >= 0) {
+ while (--i >= 0) {
struct imxdma_channel *imxdmac = &imxdma->channel[i];
imx_dma_free(imxdmac->imxdma_channel);
}
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 0834323a0599..d5a5d4d9c19b 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -273,50 +273,6 @@ struct sdma_channel {
#define MXC_SDMA_MIN_PRIORITY 1
#define MXC_SDMA_MAX_PRIORITY 7
-/**
- * struct sdma_script_start_addrs - SDMA script start pointers
- *
- * start addresses of the different functions in the physical
- * address space of the SDMA engine.
- */
-struct sdma_script_start_addrs {
- u32 ap_2_ap_addr;
- u32 ap_2_bp_addr;
- u32 ap_2_ap_fixed_addr;
- u32 bp_2_ap_addr;
- u32 loopback_on_dsp_side_addr;
- u32 mcu_interrupt_only_addr;
- u32 firi_2_per_addr;
- u32 firi_2_mcu_addr;
- u32 per_2_firi_addr;
- u32 mcu_2_firi_addr;
- u32 uart_2_per_addr;
- u32 uart_2_mcu_addr;
- u32 per_2_app_addr;
- u32 mcu_2_app_addr;
- u32 per_2_per_addr;
- u32 uartsh_2_per_addr;
- u32 uartsh_2_mcu_addr;
- u32 per_2_shp_addr;
- u32 mcu_2_shp_addr;
- u32 ata_2_mcu_addr;
- u32 mcu_2_ata_addr;
- u32 app_2_per_addr;
- u32 app_2_mcu_addr;
- u32 shp_2_per_addr;
- u32 shp_2_mcu_addr;
- u32 mshc_2_mcu_addr;
- u32 mcu_2_mshc_addr;
- u32 spdif_2_mcu_addr;
- u32 mcu_2_spdif_addr;
- u32 asrc_2_mcu_addr;
- u32 ext_mem_2_ipu_addr;
- u32 descrambler_addr;
- u32 dptc_dvfs_addr;
- u32 utra_addr;
- u32 ram_code_start_addr;
-};
-
#define SDMA_FIRMWARE_MAGIC 0x414d4453
/**
@@ -951,7 +907,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
int param;
- bd->buffer_addr = sgl->dma_address;
+ bd->buffer_addr = sg->dma_address;
count = sg->length;
@@ -1127,8 +1083,74 @@ static void sdma_issue_pending(struct dma_chan *chan)
*/
}
-static int __init sdma_init(struct sdma_engine *sdma,
- void *ram_code, int ram_code_size)
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
+
+static void sdma_add_scripts(struct sdma_engine *sdma,
+ const struct sdma_script_start_addrs *addr)
+{
+ s32 *addr_arr = (u32 *)addr;
+ s32 *saddr_arr = (u32 *)sdma->script_addrs;
+ int i;
+
+ for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
+ if (addr_arr[i] > 0)
+ saddr_arr[i] = addr_arr[i];
+}
+
+static int __init sdma_get_firmware(struct sdma_engine *sdma,
+ const char *cpu_name, int to_version)
+{
+ const struct firmware *fw;
+ char *fwname;
+ const struct sdma_firmware_header *header;
+ int ret;
+ const struct sdma_script_start_addrs *addr;
+ unsigned short *ram_code;
+
+ fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version);
+ if (!fwname)
+ return -ENOMEM;
+
+ ret = request_firmware(&fw, fwname, sdma->dev);
+ if (ret) {
+ kfree(fwname);
+ return ret;
+ }
+ kfree(fwname);
+
+ if (fw->size < sizeof(*header))
+ goto err_firmware;
+
+ header = (struct sdma_firmware_header *)fw->data;
+
+ if (header->magic != SDMA_FIRMWARE_MAGIC)
+ goto err_firmware;
+ if (header->ram_code_start + header->ram_code_size > fw->size)
+ goto err_firmware;
+
+ addr = (void *)header + header->script_addrs_start;
+ ram_code = (void *)header + header->ram_code_start;
+
+ clk_enable(sdma->clk);
+ /* download the RAM image for SDMA */
+ sdma_load_script(sdma, ram_code,
+ header->ram_code_size,
+ sdma->script_addrs->ram_code_start_addr);
+ clk_disable(sdma->clk);
+
+ sdma_add_scripts(sdma, addr);
+
+ dev_info(sdma->dev, "loaded firmware %d.%d\n",
+ header->version_major,
+ header->version_minor);
+
+err_firmware:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int __init sdma_init(struct sdma_engine *sdma)
{
int i, ret;
dma_addr_t ccb_phys;
@@ -1192,11 +1214,6 @@ static int __init sdma_init(struct sdma_engine *sdma,
__raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
- /* download the RAM image for SDMA */
- sdma_load_script(sdma, ram_code,
- ram_code_size,
- sdma->script_addrs->ram_code_start_addr);
-
/* Set bits of CONFIG register with given context switching mode */
__raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
@@ -1216,14 +1233,9 @@ err_dma_alloc:
static int __init sdma_probe(struct platform_device *pdev)
{
int ret;
- const struct firmware *fw;
- const struct sdma_firmware_header *header;
- const struct sdma_script_start_addrs *addr;
int irq;
- unsigned short *ram_code;
struct resource *iores;
struct sdma_platform_data *pdata = pdev->dev.platform_data;
- char *fwname;
int i;
dma_cap_mask_t mask;
struct sdma_engine *sdma;
@@ -1262,38 +1274,9 @@ static int __init sdma_probe(struct platform_device *pdev)
if (ret)
goto err_request_irq;
- fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin",
- pdata->cpu_name, pdata->to_version);
- if (!fwname) {
- ret = -ENOMEM;
- goto err_cputype;
- }
-
- ret = request_firmware(&fw, fwname, &pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n",
- fwname, ret);
- kfree(fwname);
- goto err_cputype;
- }
- kfree(fwname);
-
- if (fw->size < sizeof(*header))
- goto err_firmware;
-
- header = (struct sdma_firmware_header *)fw->data;
-
- if (header->magic != SDMA_FIRMWARE_MAGIC)
- goto err_firmware;
- if (header->ram_code_start + header->ram_code_size > fw->size)
- goto err_firmware;
-
- addr = (void *)header + header->script_addrs_start;
- ram_code = (void *)header + header->ram_code_start;
- sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL);
+ sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
if (!sdma->script_addrs)
- goto err_firmware;
- memcpy(sdma->script_addrs, addr, sizeof(*addr));
+ goto err_alloc;
sdma->version = pdata->sdma_version;
@@ -1316,10 +1299,15 @@ static int __init sdma_probe(struct platform_device *pdev)
list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
}
- ret = sdma_init(sdma, ram_code, header->ram_code_size);
+ ret = sdma_init(sdma);
if (ret)
goto err_init;
+ if (pdata->script_addrs)
+ sdma_add_scripts(sdma, pdata->script_addrs);
+
+ sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version);
+
sdma->dma_device.dev = &pdev->dev;
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
@@ -1336,10 +1324,6 @@ static int __init sdma_probe(struct platform_device *pdev)
goto err_init;
}
- dev_info(&pdev->dev, "initialized (firmware %d.%d)\n",
- header->version_major,
- header->version_minor);
-
/* request channel 0. This is an internal control channel
* to the SDMA engine and not available to clients.
*/
@@ -1347,15 +1331,13 @@ static int __init sdma_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, mask);
dma_request_channel(mask, NULL, NULL);
- release_firmware(fw);
+ dev_info(sdma->dev, "initialized\n");
return 0;
err_init:
kfree(sdma->script_addrs);
-err_firmware:
- release_firmware(fw);
-err_cputype:
+err_alloc:
free_irq(irq, sdma);
err_request_irq:
iounmap(sdma->regs);
@@ -1385,7 +1367,7 @@ static int __init sdma_module_init(void)
{
return platform_driver_probe(&sdma_driver, sdma_probe);
}
-subsys_initcall(sdma_module_init);
+module_init(sdma_module_init);
MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX SDMA driver");
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 338bc4eed1f3..798f46a4590d 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -664,11 +664,20 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
/*calculate CTL_LO*/
ctl_lo.ctl_lo = 0;
ctl_lo.ctlx.int_en = 1;
- ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width;
- ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width;
ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
+ /*
+ * Here we need some translation from "enum dma_slave_buswidth"
+ * to the format for our dma controller
+ * standard intel_mid_dmac's format
+ * 1 Byte 0b000
+ * 2 Bytes 0b001
+ * 4 Bytes 0b010
+ */
+ ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
+ ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
+
if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
ctl_lo.ctlx.tt_fc = 0;
ctl_lo.ctlx.sinc = 0;
@@ -746,8 +755,18 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
BUG_ON(!mids);
if (!midc->dma->pimr_mask) {
- pr_debug("MDMA: SG list is not supported by this controller\n");
- return NULL;
+ /* We can still handle sg list with only one item */
+ if (sg_len == 1) {
+ txd = intel_mid_dma_prep_memcpy(chan,
+ mids->dma_slave.dst_addr,
+ mids->dma_slave.src_addr,
+ sgl->length,
+ flags);
+ return txd;
+ } else {
+ pr_warn("MDMA: SG list is not supported by this controller\n");
+ return NULL;
+ }
}
pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
@@ -758,6 +777,7 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
pr_err("MDMA: Prep memcpy failed\n");
return NULL;
}
+
desc = to_intel_mid_dma_desc(txd);
desc->dirn = direction;
ctl_lo.ctl_lo = desc->ctl_lo;
@@ -1021,11 +1041,6 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
/*DMA Interrupt*/
pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
- if (!mid) {
- pr_err("ERR_MDMA:null pointer mid\n");
- return -EINVAL;
- }
-
pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
tfr_status &= mid->intr_mask;
if (tfr_status) {
@@ -1060,8 +1075,8 @@ static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
* mid_setup_dma - Setup the DMA controller
* @pdev: Controller PCI device structure
*
- * Initilize the DMA controller, channels, registers with DMA engine,
- * ISR. Initilize DMA controller channels.
+ * Initialize the DMA controller, channels, registers with DMA engine,
+ * ISR. Initialize DMA controller channels.
*/
static int mid_setup_dma(struct pci_dev *pdev)
{
@@ -1075,7 +1090,6 @@ static int mid_setup_dma(struct pci_dev *pdev)
if (NULL == dma->dma_pool) {
pr_err("ERR_MDMA:pci_pool_create failed\n");
err = -ENOMEM;
- kfree(dma);
goto err_dma_pool;
}
@@ -1186,7 +1200,6 @@ err_engine:
free_irq(pdev->irq, dma);
err_irq:
pci_pool_destroy(dma->dma_pool);
- kfree(dma);
err_dma_pool:
pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
return err;
@@ -1219,7 +1232,7 @@ static void middma_shutdown(struct pci_dev *pdev)
* @pdev: Controller PCI device structure
* @id: pci device id structure
*
- * Initilize the PCI device, map BARs, query driver data.
+ * Initialize the PCI device, map BARs, query driver data.
* Call setup_dma to complete contoller and chan initilzation
*/
static int __devinit intel_mid_dma_probe(struct pci_dev *pdev,
@@ -1413,7 +1426,7 @@ static const struct dev_pm_ops intel_mid_dma_pm = {
.runtime_idle = dma_runtime_idle,
};
-static struct pci_driver intel_mid_dma_pci = {
+static struct pci_driver intel_mid_dma_pci_driver = {
.name = "Intel MID DMA",
.id_table = intel_mid_dma_ids,
.probe = intel_mid_dma_probe,
@@ -1431,13 +1444,13 @@ static int __init intel_mid_dma_init(void)
{
pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
INTEL_MID_DMA_DRIVER_VERSION);
- return pci_register_driver(&intel_mid_dma_pci);
+ return pci_register_driver(&intel_mid_dma_pci_driver);
}
fs_initcall(intel_mid_dma_init);
static void __exit intel_mid_dma_exit(void)
{
- pci_unregister_driver(&intel_mid_dma_pci);
+ pci_unregister_driver(&intel_mid_dma_pci_driver);
}
module_exit(intel_mid_dma_exit);
diff --git a/drivers/dma/ioat/Makefile b/drivers/dma/ioat/Makefile
index 8997d3fb9051..0ff7270af25b 100644
--- a/drivers/dma/ioat/Makefile
+++ b/drivers/dma/ioat/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
-ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o
+ioatdma-y := pci.o dma.o dma_v2.o dma_v3.o dca.o
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 161c452923b8..c6b01f535b29 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -1261,7 +1261,7 @@ out:
return err;
}
-#ifdef CONFIG_MD_RAID6_PQ
+#ifdef CONFIG_RAID6_PQ
static int __devinit
iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device)
{
@@ -1584,7 +1584,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) &&
dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) {
- #ifdef CONFIG_MD_RAID6_PQ
+ #ifdef CONFIG_RAID6_PQ
ret = iop_adma_pq_zero_sum_self_test(adev);
dev_dbg(&pdev->dev, "pq self test returned %d\n", ret);
#else
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 4e9cbf300594..59c270192ccc 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
* Copyright (C) Semihalf 2009
+ * Copyright (C) Ilya Yanok, Emcraft Systems 2010
*
* Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
* (defines, structures and comments) was taken from MPC5121 DMA driver
@@ -70,6 +71,8 @@
#define MPC_DMA_DMAES_SBE (1 << 1)
#define MPC_DMA_DMAES_DBE (1 << 0)
+#define MPC_DMA_DMAGPOR_SNOOP_ENABLE (1 << 6)
+
#define MPC_DMA_TSIZE_1 0x00
#define MPC_DMA_TSIZE_2 0x01
#define MPC_DMA_TSIZE_4 0x02
@@ -104,7 +107,10 @@ struct __attribute__ ((__packed__)) mpc_dma_regs {
/* 0x30 */
u32 dmahrsh; /* DMA hw request status high(ch63~32) */
u32 dmahrsl; /* DMA hardware request status low(ch31~0) */
- u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
+ union {
+ u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
+ u32 dmagpor; /* (General purpose register on MPC8308) */
+ };
u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */
/* 0x40 ~ 0xff */
u32 reserve0[48]; /* Reserved */
@@ -195,7 +201,9 @@ struct mpc_dma {
struct mpc_dma_regs __iomem *regs;
struct mpc_dma_tcd __iomem *tcd;
int irq;
+ int irq2;
uint error_status;
+ int is_mpc8308;
/* Lock for error_status field in this structure */
spinlock_t error_status_lock;
@@ -252,11 +260,13 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
prev = mdesc;
}
- prev->tcd->start = 0;
prev->tcd->int_maj = 1;
/* Send first descriptor in chain into hardware */
memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd));
+
+ if (first != prev)
+ mdma->tcd[cid].e_sg = 1;
out_8(&mdma->regs->dmassrt, cid);
}
@@ -274,6 +284,9 @@ static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off)
spin_lock(&mchan->lock);
+ out_8(&mdma->regs->dmacint, ch + off);
+ out_8(&mdma->regs->dmacerr, ch + off);
+
/* Check error status */
if (es & (1 << ch))
list_for_each_entry(mdesc, &mchan->active, node)
@@ -302,36 +315,68 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
spin_unlock(&mdma->error_status_lock);
/* Handle interrupt on each channel */
- mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
+ if (mdma->dma.chancnt > 32) {
+ mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
in_be32(&mdma->regs->dmaerrh), 32);
+ }
mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
in_be32(&mdma->regs->dmaerrl), 0);
- /* Ack interrupt on all channels */
- out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
-
/* Schedule tasklet */
tasklet_schedule(&mdma->tasklet);
return IRQ_HANDLED;
}
-/* DMA Tasklet */
-static void mpc_dma_tasklet(unsigned long data)
+/* proccess completed descriptors */
+static void mpc_dma_process_completed(struct mpc_dma *mdma)
{
- struct mpc_dma *mdma = (void *)data;
dma_cookie_t last_cookie = 0;
struct mpc_dma_chan *mchan;
struct mpc_dma_desc *mdesc;
struct dma_async_tx_descriptor *desc;
unsigned long flags;
LIST_HEAD(list);
- uint es;
int i;
+ for (i = 0; i < mdma->dma.chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (list_empty(&list))
+ continue;
+
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ desc = &mdesc->desc;
+
+ if (desc->callback)
+ desc->callback(desc->callback_param);
+
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
+
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ list_splice_tail_init(&list, &mchan->free);
+ mchan->completed_cookie = last_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+}
+
+/* DMA Tasklet */
+static void mpc_dma_tasklet(unsigned long data)
+{
+ struct mpc_dma *mdma = (void *)data;
+ unsigned long flags;
+ uint es;
+
spin_lock_irqsave(&mdma->error_status_lock, flags);
es = mdma->error_status;
mdma->error_status = 0;
@@ -370,35 +415,7 @@ static void mpc_dma_tasklet(unsigned long data)
dev_err(mdma->dma.dev, "- Destination Bus Error\n");
}
- for (i = 0; i < mdma->dma.chancnt; i++) {
- mchan = &mdma->channels[i];
-
- /* Get all completed descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- if (!list_empty(&mchan->completed))
- list_splice_tail_init(&mchan->completed, &list);
- spin_unlock_irqrestore(&mchan->lock, flags);
-
- if (list_empty(&list))
- continue;
-
- /* Execute callbacks and run dependencies */
- list_for_each_entry(mdesc, &list, node) {
- desc = &mdesc->desc;
-
- if (desc->callback)
- desc->callback(desc->callback_param);
-
- last_cookie = desc->cookie;
- dma_run_dependencies(desc);
- }
-
- /* Free descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- list_splice_tail_init(&list, &mchan->free);
- mchan->completed_cookie = last_cookie;
- spin_unlock_irqrestore(&mchan->lock, flags);
- }
+ mpc_dma_process_completed(mdma);
}
/* Submit descriptor to hardware */
@@ -563,6 +580,7 @@ static struct dma_async_tx_descriptor *
mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags)
{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
struct mpc_dma_desc *mdesc = NULL;
struct mpc_dma_tcd *tcd;
@@ -577,8 +595,11 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
}
spin_unlock_irqrestore(&mchan->lock, iflags);
- if (!mdesc)
+ if (!mdesc) {
+ /* try to free completed descriptors */
+ mpc_dma_process_completed(mdma);
return NULL;
+ }
mdesc->error = 0;
tcd = mdesc->tcd;
@@ -591,7 +612,8 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
tcd->dsize = MPC_DMA_TSIZE_32;
tcd->soff = 32;
tcd->doff = 32;
- } else if (IS_ALIGNED(src | dst | len, 16)) {
+ } else if (!mdma->is_mpc8308 && IS_ALIGNED(src | dst | len, 16)) {
+ /* MPC8308 doesn't support 16 byte transfers */
tcd->ssize = MPC_DMA_TSIZE_16;
tcd->dsize = MPC_DMA_TSIZE_16;
tcd->soff = 16;
@@ -651,6 +673,15 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
return -EINVAL;
}
+ if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
+ mdma->is_mpc8308 = 1;
+ mdma->irq2 = irq_of_parse_and_map(dn, 1);
+ if (mdma->irq2 == NO_IRQ) {
+ dev_err(dev, "Error mapping IRQ!\n");
+ return -EINVAL;
+ }
+ }
+
retval = of_address_to_resource(dn, 0, &res);
if (retval) {
dev_err(dev, "Error parsing memory region!\n");
@@ -681,11 +712,23 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
return -EINVAL;
}
+ if (mdma->is_mpc8308) {
+ retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0,
+ DRV_NAME, mdma);
+ if (retval) {
+ dev_err(dev, "Error requesting IRQ2!\n");
+ return -EINVAL;
+ }
+ }
+
spin_lock_init(&mdma->error_status_lock);
dma = &mdma->dma;
dma->dev = dev;
- dma->chancnt = MPC_DMA_CHANNELS;
+ if (!mdma->is_mpc8308)
+ dma->chancnt = MPC_DMA_CHANNELS;
+ else
+ dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */
dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
dma->device_free_chan_resources = mpc_dma_free_chan_resources;
dma->device_issue_pending = mpc_dma_issue_pending;
@@ -721,26 +764,40 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
* - Round-robin group arbitration,
* - Round-robin channel arbitration.
*/
- out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
- MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
-
- /* Disable hardware DMA requests */
- out_be32(&mdma->regs->dmaerqh, 0);
- out_be32(&mdma->regs->dmaerql, 0);
-
- /* Disable error interrupts */
- out_be32(&mdma->regs->dmaeeih, 0);
- out_be32(&mdma->regs->dmaeeil, 0);
-
- /* Clear interrupts status */
- out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
-
- /* Route interrupts to IPIC */
- out_be32(&mdma->regs->dmaihsa, 0);
- out_be32(&mdma->regs->dmailsa, 0);
+ if (!mdma->is_mpc8308) {
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
+ MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
+
+ /* Disable hardware DMA requests */
+ out_be32(&mdma->regs->dmaerqh, 0);
+ out_be32(&mdma->regs->dmaerql, 0);
+
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeih, 0);
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+ /* Route interrupts to IPIC */
+ out_be32(&mdma->regs->dmaihsa, 0);
+ out_be32(&mdma->regs->dmailsa, 0);
+ } else {
+ /* MPC8308 has 16 channels and lacks some registers */
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
+
+ /* enable snooping */
+ out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmaintl, 0xFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFF);
+ }
/* Register DMA engine */
dev_set_drvdata(dev, mdma);
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 411d5bf50fc4..a25f5f61e0e0 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -449,7 +449,7 @@ mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
static void mv_xor_tasklet(unsigned long data)
{
struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
- __mv_xor_slot_cleanup(chan);
+ mv_xor_slot_cleanup(chan);
}
static struct mv_xor_desc_slot *
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 92b679024fed..1c38418ae61f 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -1,6 +1,7 @@
/*
* Topcliff PCH DMA controller driver
* Copyright (c) 2010 Intel Corporation
+ * Copyright (C) 2011 OKI SEMICONDUCTOR CO., 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
@@ -259,11 +260,6 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc)
return;
}
- channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
- channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
- channel_writel(pd_chan, SIZE, desc->regs.size);
- channel_writel(pd_chan, NEXT, desc->regs.next);
-
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n",
pd_chan->chan.chan_id, desc->regs.dev_addr);
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n",
@@ -273,10 +269,16 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc)
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n",
pd_chan->chan.chan_id, desc->regs.next);
- if (list_empty(&desc->tx_list))
+ if (list_empty(&desc->tx_list)) {
+ channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
+ channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
+ channel_writel(pd_chan, SIZE, desc->regs.size);
+ channel_writel(pd_chan, NEXT, desc->regs.next);
pdc_set_mode(&pd_chan->chan, DMA_CTL0_ONESHOT);
- else
+ } else {
+ channel_writel(pd_chan, NEXT, desc->txd.phys);
pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG);
+ }
val = dma_readl(pd, CTL2);
val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id);
@@ -920,12 +922,19 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev)
}
/* PCI Device ID of DMA device */
-#define PCI_DEVICE_ID_PCH_DMA_8CH 0x8810
-#define PCI_DEVICE_ID_PCH_DMA_4CH 0x8815
+#define PCI_VENDOR_ID_ROHM 0x10DB
+#define PCI_DEVICE_ID_EG20T_PCH_DMA_8CH 0x8810
+#define PCI_DEVICE_ID_EG20T_PCH_DMA_4CH 0x8815
+#define PCI_DEVICE_ID_ML7213_DMA1_8CH 0x8026
+#define PCI_DEVICE_ID_ML7213_DMA2_8CH 0x802B
+#define PCI_DEVICE_ID_ML7213_DMA3_4CH 0x8034
static const struct pci_device_id pch_dma_id_table[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */
{ 0, },
};
@@ -953,6 +962,7 @@ static void __exit pch_dma_exit(void)
module_init(pch_dma_init);
module_exit(pch_dma_exit);
-MODULE_DESCRIPTION("Topcliff PCH DMA controller driver");
+MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH "
+ "DMA controller driver");
MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 0d58a4a4487f..cef584533ee8 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4449,9 +4449,8 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
if (!request_mem_region(res.start, resource_size(&res),
dev_driver_string(&ofdev->dev))) {
- dev_err(&ofdev->dev, "failed to request memory region "
- "(0x%016llx-0x%016llx)\n",
- (u64)res.start, (u64)res.end);
+ dev_err(&ofdev->dev, "failed to request memory region %pR\n",
+ &res);
initcode = PPC_ADMA_INIT_MEMREG;
ret = -EBUSY;
goto out;
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index eb6b54dbb806..28720d3103c4 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -27,7 +27,10 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
-
+#include <linux/notifier.h>
+#include <linux/kdebug.h>
+#include <linux/spinlock.h>
+#include <linux/rculist.h>
#include "shdma.h"
/* DMA descriptor control */
@@ -43,6 +46,13 @@ enum sh_dmae_desc_status {
/* Default MEMCPY transfer size = 2^2 = 4 bytes */
#define LOG2_DEFAULT_XFER_SIZE 2
+/*
+ * Used for write-side mutual exclusion for the global device list,
+ * read-side synchronization by way of RCU.
+ */
+static DEFINE_SPINLOCK(sh_dmae_lock);
+static LIST_HEAD(sh_dmae_devices);
+
/* A bitmask with bits enough for enum sh_dmae_slave_chan_id */
static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)];
@@ -817,10 +827,9 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
return ret;
}
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
-static irqreturn_t sh_dmae_err(int irq, void *data)
+static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
{
- struct sh_dmae_device *shdev = (struct sh_dmae_device *)data;
+ unsigned int handled = 0;
int i;
/* halt the dma controller */
@@ -829,25 +838,35 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
/* We cannot detect, which channel caused the error, have to reset all */
for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
- if (sh_chan) {
- struct sh_desc *desc;
- /* Stop the channel */
- dmae_halt(sh_chan);
- /* Complete all */
- list_for_each_entry(desc, &sh_chan->ld_queue, node) {
- struct dma_async_tx_descriptor *tx = &desc->async_tx;
- desc->mark = DESC_IDLE;
- if (tx->callback)
- tx->callback(tx->callback_param);
- }
- list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
+ struct sh_desc *desc;
+
+ if (!sh_chan)
+ continue;
+
+ /* Stop the channel */
+ dmae_halt(sh_chan);
+
+ /* Complete all */
+ list_for_each_entry(desc, &sh_chan->ld_queue, node) {
+ struct dma_async_tx_descriptor *tx = &desc->async_tx;
+ desc->mark = DESC_IDLE;
+ if (tx->callback)
+ tx->callback(tx->callback_param);
}
+
+ list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
+ handled++;
}
+
sh_dmae_rst(shdev);
- return IRQ_HANDLED;
+ return !!handled;
+}
+
+static irqreturn_t sh_dmae_err(int irq, void *data)
+{
+ return IRQ_RETVAL(sh_dmae_reset(data));
}
-#endif
static void dmae_do_tasklet(unsigned long data)
{
@@ -876,6 +895,60 @@ static void dmae_do_tasklet(unsigned long data)
sh_dmae_chan_ld_cleanup(sh_chan, false);
}
+static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
+{
+ unsigned int handled;
+
+ /* Fast path out if NMIF is not asserted for this controller */
+ if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
+ return false;
+
+ handled = sh_dmae_reset(shdev);
+ if (handled)
+ return true;
+
+ return false;
+}
+
+static int sh_dmae_nmi_handler(struct notifier_block *self,
+ unsigned long cmd, void *data)
+{
+ struct sh_dmae_device *shdev;
+ int ret = NOTIFY_DONE;
+ bool triggered;
+
+ /*
+ * Only concern ourselves with NMI events.
+ *
+ * Normally we would check the die chain value, but as this needs
+ * to be architecture independent, check for NMI context instead.
+ */
+ if (!in_nmi())
+ return NOTIFY_DONE;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(shdev, &sh_dmae_devices, node) {
+ /*
+ * Only stop if one of the controllers has NMIF asserted,
+ * we do not want to interfere with regular address error
+ * handling or NMI events that don't concern the DMACs.
+ */
+ triggered = sh_dmae_nmi_notify(shdev);
+ if (triggered == true)
+ ret = NOTIFY_OK;
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
+static struct notifier_block sh_dmae_nmi_notifier __read_mostly = {
+ .notifier_call = sh_dmae_nmi_handler,
+
+ /* Run before NMI debug handler and KGDB */
+ .priority = 1,
+};
+
static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
int irq, unsigned long flags)
{
@@ -967,6 +1040,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
unsigned long irqflags = IRQF_DISABLED,
chan_flag[SH_DMAC_MAX_CHANNELS] = {};
+ unsigned long flags;
int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
int err, i, irq_cnt = 0, irqres = 0;
struct sh_dmae_device *shdev;
@@ -1032,6 +1106,10 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
+ spin_lock_irqsave(&sh_dmae_lock, flags);
+ list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
/* reset dma controller */
err = sh_dmae_rst(shdev);
if (err)
@@ -1135,6 +1213,10 @@ eirqres:
eirq_err:
#endif
rst_err:
+ spin_lock_irqsave(&sh_dmae_lock, flags);
+ list_del_rcu(&shdev->node);
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
pm_runtime_put(&pdev->dev);
if (dmars)
iounmap(shdev->dmars);
@@ -1155,6 +1237,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
struct resource *res;
+ unsigned long flags;
int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(&shdev->common);
@@ -1162,6 +1245,10 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
if (errirq > 0)
free_irq(errirq, shdev);
+ spin_lock_irqsave(&sh_dmae_lock, flags);
+ list_del_rcu(&shdev->node);
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
/* channel data remove */
sh_dmae_chan_remove(shdev);
@@ -1200,6 +1287,11 @@ static struct platform_driver sh_dmae_driver = {
static int __init sh_dmae_init(void)
{
+ /* Wire up NMI handling */
+ int err = register_die_notifier(&sh_dmae_nmi_notifier);
+ if (err)
+ return err;
+
return platform_driver_probe(&sh_dmae_driver, sh_dmae_probe);
}
module_init(sh_dmae_init);
@@ -1207,9 +1299,12 @@ module_init(sh_dmae_init);
static void __exit sh_dmae_exit(void)
{
platform_driver_unregister(&sh_dmae_driver);
+
+ unregister_die_notifier(&sh_dmae_nmi_notifier);
}
module_exit(sh_dmae_exit);
MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>");
MODULE_DESCRIPTION("Renesas SH DMA Engine driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-dma-engine");
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 4021275a0a43..52e4fb173805 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -43,6 +43,7 @@ struct sh_dmae_device {
struct dma_device common;
struct sh_dmae_chan *chan[SH_DMAC_MAX_CHANNELS];
struct sh_dmae_pdata *pdata;
+ struct list_head node;
u32 __iomem *chan_reg;
u16 __iomem *dmars;
};
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index fab68a553205..6e1d46a65d0e 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) ST-Ericsson SA 2007-2010
+ * Copyright (C) Ericsson AB 2007-2008
+ * Copyright (C) ST-Ericsson SA 2008-2010
* Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
@@ -554,8 +555,66 @@ static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
return d;
}
-/* Support functions for logical channels */
+static int d40_psize_2_burst_size(bool is_log, int psize)
+{
+ if (is_log) {
+ if (psize == STEDMA40_PSIZE_LOG_1)
+ return 1;
+ } else {
+ if (psize == STEDMA40_PSIZE_PHY_1)
+ return 1;
+ }
+
+ return 2 << psize;
+}
+
+/*
+ * The dma only supports transmitting packages up to
+ * STEDMA40_MAX_SEG_SIZE << data_width. Calculate the total number of
+ * dma elements required to send the entire sg list
+ */
+static int d40_size_2_dmalen(int size, u32 data_width1, u32 data_width2)
+{
+ int dmalen;
+ u32 max_w = max(data_width1, data_width2);
+ u32 min_w = min(data_width1, data_width2);
+ u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
+
+ if (seg_max > STEDMA40_MAX_SEG_SIZE)
+ seg_max -= (1 << max_w);
+
+ if (!IS_ALIGNED(size, 1 << max_w))
+ return -EINVAL;
+
+ if (size <= seg_max)
+ dmalen = 1;
+ else {
+ dmalen = size / seg_max;
+ if (dmalen * seg_max < size)
+ dmalen++;
+ }
+ return dmalen;
+}
+
+static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len,
+ u32 data_width1, u32 data_width2)
+{
+ struct scatterlist *sg;
+ int i;
+ int len = 0;
+ int ret;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ ret = d40_size_2_dmalen(sg_dma_len(sg),
+ data_width1, data_width2);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+ return len;
+}
+/* Support functions for logical channels */
static int d40_channel_execute_command(struct d40_chan *d40c,
enum d40_command command)
@@ -1241,6 +1300,21 @@ static int d40_validate_conf(struct d40_chan *d40c,
res = -EINVAL;
}
+ if (d40_psize_2_burst_size(is_log, conf->src_info.psize) *
+ (1 << conf->src_info.data_width) !=
+ d40_psize_2_burst_size(is_log, conf->dst_info.psize) *
+ (1 << conf->dst_info.data_width)) {
+ /*
+ * The DMAC hardware only supports
+ * src (burst x width) == dst (burst x width)
+ */
+
+ dev_err(&d40c->chan.dev->device,
+ "[%s] src (burst x width) != dst (burst x width)\n",
+ __func__);
+ res = -EINVAL;
+ }
+
return res;
}
@@ -1638,13 +1712,21 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
if (d40d == NULL)
goto err;
- d40d->lli_len = sgl_len;
+ d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ goto err;
+ }
+
d40d->lli_current = 0;
d40d->txd.flags = dma_flags;
if (d40c->log_num != D40_PHY_CHAN) {
- if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
@@ -1654,15 +1736,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
d40d->lli_log.src,
d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width);
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
(void) d40_log_sg_to_lli(sgl_dst,
sgl_len,
d40d->lli_log.dst,
d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width);
+ d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width);
} else {
- if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
@@ -1675,6 +1759,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.src_info.psize);
if (res < 0)
@@ -1687,6 +1772,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.dst_info.psize);
if (res < 0)
@@ -1826,7 +1912,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
struct d40_chan *d40c = container_of(chan, struct d40_chan,
chan);
unsigned long flags;
- int err = 0;
if (d40c->phy_chan == NULL) {
dev_err(&d40c->chan.dev->device,
@@ -1844,6 +1929,15 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
}
d40d->txd.flags = dma_flags;
+ d40d->lli_len = d40_size_2_dmalen(size,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ goto err;
+ }
+
dma_async_tx_descriptor_init(&d40d->txd, chan);
@@ -1851,37 +1945,40 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
if (d40c->log_num != D40_PHY_CHAN) {
- if (d40_pool_lli_alloc(d40d, 1, true) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
}
- d40d->lli_len = 1;
d40d->lli_current = 0;
- d40_log_fill_lli(d40d->lli_log.src,
- src,
- size,
- d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width,
- true);
+ if (d40_log_buf_to_lli(d40d->lli_log.src,
+ src,
+ size,
+ d40c->log_def.lcsp1,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
+ true) == NULL)
+ goto err;
- d40_log_fill_lli(d40d->lli_log.dst,
- dst,
- size,
- d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width,
- true);
+ if (d40_log_buf_to_lli(d40d->lli_log.dst,
+ dst,
+ size,
+ d40c->log_def.lcsp3,
+ d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
+ true) == NULL)
+ goto err;
} else {
- if (d40_pool_lli_alloc(d40d, 1, false) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
}
- err = d40_phy_fill_lli(d40d->lli_phy.src,
+ if (d40_phy_buf_to_lli(d40d->lli_phy.src,
src,
size,
d40c->dma_cfg.src_info.psize,
@@ -1889,11 +1986,11 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
d40c->src_def_cfg,
true,
d40c->dma_cfg.src_info.data_width,
- false);
- if (err)
- goto err_fill_lli;
+ d40c->dma_cfg.dst_info.data_width,
+ false) == NULL)
+ goto err;
- err = d40_phy_fill_lli(d40d->lli_phy.dst,
+ if (d40_phy_buf_to_lli(d40d->lli_phy.dst,
dst,
size,
d40c->dma_cfg.dst_info.psize,
@@ -1901,10 +1998,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
d40c->dst_def_cfg,
true,
d40c->dma_cfg.dst_info.data_width,
- false);
-
- if (err)
- goto err_fill_lli;
+ d40c->dma_cfg.src_info.data_width,
+ false) == NULL)
+ goto err;
(void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
d40d->lli_pool.size, DMA_TO_DEVICE);
@@ -1913,9 +2009,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
-err_fill_lli:
- dev_err(&d40c->chan.dev->device,
- "[%s] Failed filling in PHY LLI\n", __func__);
err:
if (d40d)
d40_desc_free(d40c, d40d);
@@ -1945,13 +2038,21 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
dma_addr_t dev_addr = 0;
int total_size;
- if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) {
+ d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ return -EINVAL;
+ }
+
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
return -ENOMEM;
}
- d40d->lli_len = sg_len;
d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE)
@@ -1993,13 +2094,21 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
dma_addr_t dst_dev_addr;
int res;
- if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
+ d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ return -EINVAL;
+ }
+
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
return -ENOMEM;
}
- d40d->lli_len = sgl_len;
d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE) {
@@ -2024,6 +2133,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.src_info.psize);
if (res < 0)
return res;
@@ -2035,6 +2145,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.dst_info.psize);
if (res < 0)
return res;
@@ -2244,6 +2355,8 @@ static void d40_set_runtime_config(struct dma_chan *chan,
psize = STEDMA40_PSIZE_PHY_8;
else if (config_maxburst >= 4)
psize = STEDMA40_PSIZE_PHY_4;
+ else if (config_maxburst >= 2)
+ psize = STEDMA40_PSIZE_PHY_2;
else
psize = STEDMA40_PSIZE_PHY_1;
}
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c
index 8557cb88b255..0b096a38322d 100644
--- a/drivers/dma/ste_dma40_ll.c
+++ b/drivers/dma/ste_dma40_ll.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson SA 2007-2010
- * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
@@ -122,15 +122,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
*dst_cfg = dst;
}
-int d40_phy_fill_lli(struct d40_phy_lli *lli,
- dma_addr_t data,
- u32 data_size,
- int psize,
- dma_addr_t next_lli,
- u32 reg_cfg,
- bool term_int,
- u32 data_width,
- bool is_device)
+static int d40_phy_fill_lli(struct d40_phy_lli *lli,
+ dma_addr_t data,
+ u32 data_size,
+ int psize,
+ dma_addr_t next_lli,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width,
+ bool is_device)
{
int num_elems;
@@ -139,13 +139,6 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli,
else
num_elems = 2 << psize;
- /*
- * Size is 16bit. data_width is 8, 16, 32 or 64 bit
- * Block large than 64 KiB must be split.
- */
- if (data_size > (0xffff << data_width))
- return -EINVAL;
-
/* Must be aligned */
if (!IS_ALIGNED(data, 0x1 << data_width))
return -EINVAL;
@@ -187,55 +180,118 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli,
return 0;
}
+static int d40_seg_size(int size, int data_width1, int data_width2)
+{
+ u32 max_w = max(data_width1, data_width2);
+ u32 min_w = min(data_width1, data_width2);
+ u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
+
+ if (seg_max > STEDMA40_MAX_SEG_SIZE)
+ seg_max -= (1 << max_w);
+
+ if (size <= seg_max)
+ return size;
+
+ if (size <= 2 * seg_max)
+ return ALIGN(size / 2, 1 << max_w);
+
+ return seg_max;
+}
+
+struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
+ dma_addr_t addr,
+ u32 size,
+ int psize,
+ dma_addr_t lli_phys,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width1,
+ u32 data_width2,
+ bool is_device)
+{
+ int err;
+ dma_addr_t next = lli_phys;
+ int size_rest = size;
+ int size_seg = 0;
+
+ do {
+ size_seg = d40_seg_size(size_rest, data_width1, data_width2);
+ size_rest -= size_seg;
+
+ if (term_int && size_rest == 0)
+ next = 0;
+ else
+ next = ALIGN(next + sizeof(struct d40_phy_lli),
+ D40_LLI_ALIGN);
+
+ err = d40_phy_fill_lli(lli,
+ addr,
+ size_seg,
+ psize,
+ next,
+ reg_cfg,
+ !next,
+ data_width1,
+ is_device);
+
+ if (err)
+ goto err;
+
+ lli++;
+ if (!is_device)
+ addr += size_seg;
+ } while (size_rest);
+
+ return lli;
+
+ err:
+ return NULL;
+}
+
int d40_phy_sg_to_lli(struct scatterlist *sg,
int sg_len,
dma_addr_t target,
- struct d40_phy_lli *lli,
+ struct d40_phy_lli *lli_sg,
dma_addr_t lli_phys,
u32 reg_cfg,
- u32 data_width,
+ u32 data_width1,
+ u32 data_width2,
int psize)
{
int total_size = 0;
int i;
struct scatterlist *current_sg = sg;
- dma_addr_t next_lli_phys;
dma_addr_t dst;
- int err = 0;
+ struct d40_phy_lli *lli = lli_sg;
+ dma_addr_t l_phys = lli_phys;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /* If this scatter list entry is the last one, no next link */
- if (sg_len - 1 == i)
- next_lli_phys = 0;
- else
- next_lli_phys = ALIGN(lli_phys + (i + 1) *
- sizeof(struct d40_phy_lli),
- D40_LLI_ALIGN);
-
if (target)
dst = target;
else
dst = sg_phys(current_sg);
- err = d40_phy_fill_lli(&lli[i],
- dst,
- sg_dma_len(current_sg),
- psize,
- next_lli_phys,
- reg_cfg,
- !next_lli_phys,
- data_width,
- target == dst);
- if (err)
- goto err;
+ l_phys = ALIGN(lli_phys + (lli - lli_sg) *
+ sizeof(struct d40_phy_lli), D40_LLI_ALIGN);
+
+ lli = d40_phy_buf_to_lli(lli,
+ dst,
+ sg_dma_len(current_sg),
+ psize,
+ l_phys,
+ reg_cfg,
+ sg_len - 1 == i,
+ data_width1,
+ data_width2,
+ target == dst);
+ if (lli == NULL)
+ return -EINVAL;
}
return total_size;
-err:
- return err;
}
@@ -315,17 +371,20 @@ void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
writel(lli_dst->lcsp13, &lcla[1].lcsp13);
}
-void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data, u32 data_size,
- u32 reg_cfg,
- u32 data_width,
- bool addr_inc)
+static void d40_log_fill_lli(struct d40_log_lli *lli,
+ dma_addr_t data, u32 data_size,
+ u32 reg_cfg,
+ u32 data_width,
+ bool addr_inc)
{
lli->lcsp13 = reg_cfg;
/* The number of elements to transfer */
lli->lcsp02 = ((data_size >> data_width) <<
D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK;
+
+ BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE);
+
/* 16 LSBs address of the current element */
lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK;
/* 16 MSBs address of the current element */
@@ -348,55 +407,94 @@ int d40_log_sg_to_dev(struct scatterlist *sg,
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
+ struct d40_log_lli *lli_src = lli->src;
+ struct d40_log_lli *lli_dst = lli->dst;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
if (direction == DMA_TO_DEVICE) {
- d40_log_fill_lli(&lli->src[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp->lcsp1, src_data_width,
- true);
- d40_log_fill_lli(&lli->dst[i],
- dev_addr,
- sg_dma_len(current_sg),
- lcsp->lcsp3, dst_data_width,
- false);
+ lli_src =
+ d40_log_buf_to_lli(lli_src,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp->lcsp1, src_data_width,
+ dst_data_width,
+ true);
+ lli_dst =
+ d40_log_buf_to_lli(lli_dst,
+ dev_addr,
+ sg_dma_len(current_sg),
+ lcsp->lcsp3, dst_data_width,
+ src_data_width,
+ false);
} else {
- d40_log_fill_lli(&lli->dst[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp->lcsp3, dst_data_width,
- true);
- d40_log_fill_lli(&lli->src[i],
- dev_addr,
- sg_dma_len(current_sg),
- lcsp->lcsp1, src_data_width,
- false);
+ lli_dst =
+ d40_log_buf_to_lli(lli_dst,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp->lcsp3, dst_data_width,
+ src_data_width,
+ true);
+ lli_src =
+ d40_log_buf_to_lli(lli_src,
+ dev_addr,
+ sg_dma_len(current_sg),
+ lcsp->lcsp1, src_data_width,
+ dst_data_width,
+ false);
}
}
return total_size;
}
+struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
+ dma_addr_t addr,
+ int size,
+ u32 lcsp13, /* src or dst*/
+ u32 data_width1,
+ u32 data_width2,
+ bool addr_inc)
+{
+ struct d40_log_lli *lli = lli_sg;
+ int size_rest = size;
+ int size_seg = 0;
+
+ do {
+ size_seg = d40_seg_size(size_rest, data_width1, data_width2);
+ size_rest -= size_seg;
+
+ d40_log_fill_lli(lli,
+ addr,
+ size_seg,
+ lcsp13, data_width1,
+ addr_inc);
+ if (addr_inc)
+ addr += size_seg;
+ lli++;
+ } while (size_rest);
+
+ return lli;
+}
+
int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width)
+ u32 data_width1, u32 data_width2)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
+ struct d40_log_lli *lli = lli_sg;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
-
- d40_log_fill_lli(&lli_sg[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp13, data_width,
- true);
+ lli = d40_log_buf_to_lli(lli,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp13,
+ data_width1, data_width2, true);
}
return total_size;
}
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h
index 9e419b907544..9cc43495bea2 100644
--- a/drivers/dma/ste_dma40_ll.h
+++ b/drivers/dma/ste_dma40_ll.h
@@ -292,18 +292,20 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
struct d40_phy_lli *lli,
dma_addr_t lli_phys,
u32 reg_cfg,
- u32 data_width,
+ u32 data_width1,
+ u32 data_width2,
int psize);
-int d40_phy_fill_lli(struct d40_phy_lli *lli,
- dma_addr_t data,
- u32 data_size,
- int psize,
- dma_addr_t next_lli,
- u32 reg_cfg,
- bool term_int,
- u32 data_width,
- bool is_device);
+struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
+ dma_addr_t data,
+ u32 data_size,
+ int psize,
+ dma_addr_t next_lli,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width1,
+ u32 data_width2,
+ bool is_device);
void d40_phy_lli_write(void __iomem *virtbase,
u32 phy_chan_num,
@@ -312,12 +314,12 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* Logical channels */
-void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data,
- u32 data_size,
- u32 reg_cfg,
- u32 data_width,
- bool addr_inc);
+struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
+ dma_addr_t addr,
+ int size,
+ u32 lcsp13, /* src or dst*/
+ u32 data_width1, u32 data_width2,
+ bool addr_inc);
int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
@@ -332,7 +334,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width);
+ u32 data_width1, u32 data_width2);
void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
struct d40_log_lli *lli_dst,
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index f436a2fa9f38..fe70a341bd8b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -75,11 +75,11 @@ config EDAC_MCE
bool
config EDAC_AMD64
- tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
- depends on EDAC_MM_EDAC && AMD_NB && X86_64 && PCI && EDAC_DECODE_MCE
+ tristate "AMD64 (Opteron, Athlon64) K8, F10h"
+ depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE
help
- Support for error detection and correction on the AMD 64
- Families of Memory Controllers (K8, F10h and F11h)
+ Support for error detection and correction of DRAM ECC errors on
+ the AMD64 families of memory controllers (K8 and F10h)
config EDAC_AMD64_ERROR_INJECTION
bool "Sysfs HW Error injection facilities"
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index b3781399b38a..ba2898b3639b 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -10,16 +10,16 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
obj-$(CONFIG_EDAC_MCE) += edac_mce.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
+edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-y += edac_module.o edac_device_sysfs.o
ifdef CONFIG_PCI
-edac_core-objs += edac_pci.o edac_pci_sysfs.o
+edac_core-y += edac_pci.o edac_pci_sysfs.o
endif
obj-$(CONFIG_EDAC_MCE_INJ) += mce_amd_inj.o
-edac_mce_amd-objs := mce_amd.o
+edac_mce_amd-y := mce_amd.o
obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o
obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 8521401bbd75..4a5ecc58025d 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -15,10 +15,14 @@ module_param(ecc_enable_override, int, 0644);
static struct msr __percpu *msrs;
-/* Lookup table for all possible MC control instances */
-struct amd64_pvt;
-static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES];
-static struct amd64_pvt *pvt_lookup[EDAC_MAX_NUMNODES];
+/*
+ * count successfully initialized driver instances for setup_pci_device()
+ */
+static atomic_t drv_instances = ATOMIC_INIT(0);
+
+/* Per-node driver instances */
+static struct mem_ctl_info **mcis;
+static struct ecc_settings **ecc_stngs;
/*
* Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
@@ -62,7 +66,7 @@ static int ddr3_dbam[] = { [0] = -1,
[5 ... 6] = 1024,
[7 ... 8] = 2048,
[9 ... 10] = 4096,
- [11] = 8192,
+ [11] = 8192,
};
/*
@@ -73,7 +77,11 @@ static int ddr3_dbam[] = { [0] = -1,
*FIXME: Produce a better mapping/linearisation.
*/
-struct scrubrate scrubrates[] = {
+
+struct scrubrate {
+ u32 scrubval; /* bit pattern for scrub rate */
+ u32 bandwidth; /* bandwidth consumed (bytes/sec) */
+} scrubrates[] = {
{ 0x01, 1600000000UL},
{ 0x02, 800000000UL},
{ 0x03, 400000000UL},
@@ -117,8 +125,7 @@ struct scrubrate scrubrates[] = {
* scan the scrub rate mapping table for a close or matching bandwidth value to
* issue. If requested is too big, then use last maximum value found.
*/
-static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
- u32 min_scrubrate)
+static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
{
u32 scrubval;
int i;
@@ -134,7 +141,7 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
* skip scrub rates which aren't recommended
* (see F10 BKDG, F3x58)
*/
- if (scrubrates[i].scrubval < min_scrubrate)
+ if (scrubrates[i].scrubval < min_rate)
continue;
if (scrubrates[i].bandwidth <= new_bw)
@@ -148,64 +155,41 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
}
scrubval = scrubrates[i].scrubval;
- if (scrubval)
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Setting scrub rate bandwidth: %u\n",
- scrubrates[i].bandwidth);
- else
- edac_printk(KERN_DEBUG, EDAC_MC, "Turning scrubbing off.\n");
pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F);
+ if (scrubval)
+ return scrubrates[i].bandwidth;
+
return 0;
}
-static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u32 min_scrubrate = 0x0;
-
- switch (boot_cpu_data.x86) {
- case 0xf:
- min_scrubrate = K8_MIN_SCRUB_RATE_BITS;
- break;
- case 0x10:
- min_scrubrate = F10_MIN_SCRUB_RATE_BITS;
- break;
- case 0x11:
- min_scrubrate = F11_MIN_SCRUB_RATE_BITS;
- break;
- default:
- amd64_printk(KERN_ERR, "Unsupported family!\n");
- return -EINVAL;
- }
- return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, bandwidth,
- min_scrubrate);
+ return __amd64_set_scrub_rate(pvt->F3, bw, pvt->min_scrubrate);
}
-static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 scrubval = 0;
- int status = -1, i;
+ int i, retval = -EINVAL;
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_SCRCTRL, &scrubval);
+ amd64_read_pci_cfg(pvt->F3, K8_SCRCTRL, &scrubval);
scrubval = scrubval & 0x001F;
- edac_printk(KERN_DEBUG, EDAC_MC,
- "pci-read, sdram scrub control value: %d \n", scrubval);
+ amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval);
for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
if (scrubrates[i].scrubval == scrubval) {
- *bw = scrubrates[i].bandwidth;
- status = 0;
+ retval = scrubrates[i].bandwidth;
break;
}
}
-
- return status;
+ return retval;
}
/* Map from a CSROW entry to the mask entry that operates on it */
@@ -314,9 +298,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
if (unlikely((intlv_en != 0x01) &&
(intlv_en != 0x03) &&
(intlv_en != 0x07))) {
- amd64_printk(KERN_WARNING, "junk value of 0x%x extracted from "
- "IntlvEn field of DRAM Base Register for node 0: "
- "this probably indicates a BIOS bug.\n", intlv_en);
+ amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
return NULL;
}
@@ -332,11 +314,9 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
/* sanity test for sys_addr */
if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
- amd64_printk(KERN_WARNING,
- "%s(): sys_addr 0x%llx falls outside base/limit "
- "address range for node %d with node interleaving "
- "enabled.\n",
- __func__, sys_addr, node_id);
+ amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
+ "range for node %d with node interleaving enabled.\n",
+ __func__, sys_addr, node_id);
return NULL;
}
@@ -788,9 +768,8 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
if (csrow == -1)
- amd64_mc_printk(mci, KERN_ERR,
- "Failed to translate InputAddr to csrow for "
- "address 0x%lx\n", (unsigned long)sys_addr);
+ amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
+ "address 0x%lx\n", (unsigned long)sys_addr);
return csrow;
}
@@ -801,21 +780,6 @@ static u16 extract_syndrome(struct err_regs *err)
return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
}
-static void amd64_cpu_display_info(struct amd64_pvt *pvt)
-{
- if (boot_cpu_data.x86 == 0x11)
- edac_printk(KERN_DEBUG, EDAC_MC, "F11h CPU detected\n");
- else if (boot_cpu_data.x86 == 0x10)
- edac_printk(KERN_DEBUG, EDAC_MC, "F10h CPU detected\n");
- else if (boot_cpu_data.x86 == 0xf)
- edac_printk(KERN_DEBUG, EDAC_MC, "%s detected\n",
- (pvt->ext_model >= K8_REV_F) ?
- "Rev F or later" : "Rev E or earlier");
- else
- /* we'll hardly ever ever get here */
- edac_printk(KERN_ERR, EDAC_MC, "Unknown cpu!\n");
-}
-
/*
* Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
* are ECC capable.
@@ -893,8 +857,7 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
return;
}
- amd64_printk(KERN_INFO, "using %s syndromes.\n",
- ((pvt->syn_type == 8) ? "x8" : "x4"));
+ amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4"));
/* Only if NOT ganged does dclr1 have valid info */
if (!dct_ganging_enabled(pvt))
@@ -915,10 +878,10 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
/* Read in both of DBAM registers */
static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
{
- amd64_read_pci_cfg(pvt->dram_f2_ctl, DBAM0, &pvt->dbam0);
+ amd64_read_pci_cfg(pvt->F2, DBAM0, &pvt->dbam0);
if (boot_cpu_data.x86 >= 0x10)
- amd64_read_pci_cfg(pvt->dram_f2_ctl, DBAM1, &pvt->dbam1);
+ amd64_read_pci_cfg(pvt->F2, DBAM1, &pvt->dbam1);
}
/*
@@ -965,14 +928,8 @@ static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
pvt->dcsm_mask = REV_F_F1Xh_DCSM_MASK_BITS;
pvt->dcs_mask_notused = REV_F_F1Xh_DCS_NOTUSED_BITS;
pvt->dcs_shift = REV_F_F1Xh_DCS_SHIFT;
-
- if (boot_cpu_data.x86 == 0x11) {
- pvt->cs_count = 4;
- pvt->num_dcsm = 2;
- } else {
- pvt->cs_count = 8;
- pvt->num_dcsm = 4;
- }
+ pvt->cs_count = 8;
+ pvt->num_dcsm = 4;
}
}
@@ -987,14 +944,14 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
for (cs = 0; cs < pvt->cs_count; cs++) {
reg = K8_DCSB0 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg, &pvt->dcsb0[cs]))
+ if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsb0[cs]))
debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n",
cs, pvt->dcsb0[cs], reg);
/* If DCT are NOT ganged, then read in DCT1's base */
if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
reg = F10_DCSB1 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg,
+ if (!amd64_read_pci_cfg(pvt->F2, reg,
&pvt->dcsb1[cs]))
debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n",
cs, pvt->dcsb1[cs], reg);
@@ -1005,14 +962,14 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
for (cs = 0; cs < pvt->num_dcsm; cs++) {
reg = K8_DCSM0 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg, &pvt->dcsm0[cs]))
+ if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsm0[cs]))
debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n",
cs, pvt->dcsm0[cs], reg);
/* If DCT are NOT ganged, then read in DCT1's mask */
if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
reg = F10_DCSM1 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg,
+ if (!amd64_read_pci_cfg(pvt->F2, reg,
&pvt->dcsm1[cs]))
debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n",
cs, pvt->dcsm1[cs], reg);
@@ -1022,7 +979,7 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
}
}
-static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
+static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
{
enum mem_type type;
@@ -1035,7 +992,7 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
}
- debugf1(" Memory type is: %s\n", edac_mem_types[type]);
+ amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
return type;
}
@@ -1053,17 +1010,16 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
{
int flag, err = 0;
- err = amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
+ err = amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
if (err)
return err;
- if ((boot_cpu_data.x86_model >> 4) >= K8_REV_F) {
+ if (pvt->ext_model >= K8_REV_F)
/* RevF (NPT) and later */
flag = pvt->dclr0 & F10_WIDTH_128;
- } else {
+ else
/* RevE and earlier */
flag = pvt->dclr0 & REVE_WIDTH_128;
- }
/* not used */
pvt->dclr1 = 0;
@@ -1090,14 +1046,14 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
u32 low;
u32 off = dram << 3; /* 8 bytes between DRAM entries */
- amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DRAM_BASE_LOW + off, &low);
+ amd64_read_pci_cfg(pvt->F1, K8_DRAM_BASE_LOW + off, &low);
/* Extract parts into separate data entries */
pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8;
pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
pvt->dram_rw_en[dram] = (low & 0x3);
- amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DRAM_LIMIT_LOW + off, &low);
+ amd64_read_pci_cfg(pvt->F1, K8_DRAM_LIMIT_LOW + off, &low);
/*
* Extract parts into separate data entries. Limit is the HIGHEST memory
@@ -1127,9 +1083,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
* 2 DIMMs is in error. So we need to ID 'both' of them
* as suspect.
*/
- amd64_mc_printk(mci, KERN_WARNING,
- "unknown syndrome 0x%04x - possible "
- "error reporting race\n", syndrome);
+ amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible "
+ "error reporting race\n", syndrome);
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return;
}
@@ -1151,8 +1106,7 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
*/
src_mci = find_mc_by_sys_addr(mci, sys_addr);
if (!src_mci) {
- amd64_mc_printk(mci, KERN_ERR,
- "failed to map error address 0x%lx to a node\n",
+ amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
(unsigned long)sys_addr);
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return;
@@ -1220,7 +1174,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
* both controllers since DIMMs can be placed in either one.
*/
for (i = 0; i < ARRAY_SIZE(dbams); i++) {
- if (amd64_read_pci_cfg(pvt->dram_f2_ctl, dbams[i], &dbam))
+ if (amd64_read_pci_cfg(pvt->F2, dbams[i], &dbam))
goto err_reg;
for (j = 0; j < 4; j++) {
@@ -1234,7 +1188,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
if (channels > 2)
channels = 2;
- debugf0("MCT channel count: %d\n", channels);
+ amd64_info("MCT channel count: %d\n", channels);
return channels;
@@ -1255,31 +1209,6 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
return dbam_map[cs_mode];
}
-/* Enable extended configuration access via 0xCF8 feature */
-static void amd64_setup(struct amd64_pvt *pvt)
-{
- u32 reg;
-
- amd64_read_pci_cfg(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
-
- pvt->flags.cf8_extcfg = !!(reg & F10_NB_CFG_LOW_ENABLE_EXT_CFG);
- reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
- pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
-}
-
-/* Restore the extended configuration access via 0xCF8 feature */
-static void amd64_teardown(struct amd64_pvt *pvt)
-{
- u32 reg;
-
- amd64_read_pci_cfg(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
-
- reg &= ~F10_NB_CFG_LOW_ENABLE_EXT_CFG;
- if (pvt->flags.cf8_extcfg)
- reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
- pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
-}
-
static u64 f10_get_error_address(struct mem_ctl_info *mci,
struct err_regs *info)
{
@@ -1301,10 +1230,8 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
high_offset = F10_DRAM_BASE_HIGH + (dram << 3);
/* read the 'raw' DRAM BASE Address register */
- amd64_read_pci_cfg(pvt->addr_f1_ctl, low_offset, &low_base);
-
- /* Read from the ECS data register */
- amd64_read_pci_cfg(pvt->addr_f1_ctl, high_offset, &high_base);
+ amd64_read_pci_cfg(pvt->F1, low_offset, &low_base);
+ amd64_read_pci_cfg(pvt->F1, high_offset, &high_base);
/* Extract parts into separate data entries */
pvt->dram_rw_en[dram] = (low_base & 0x3);
@@ -1321,10 +1248,8 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
/* read the 'raw' LIMIT registers */
- amd64_read_pci_cfg(pvt->addr_f1_ctl, low_offset, &low_limit);
-
- /* Read from the ECS data register for the HIGH portion */
- amd64_read_pci_cfg(pvt->addr_f1_ctl, high_offset, &high_limit);
+ amd64_read_pci_cfg(pvt->F1, low_offset, &low_limit);
+ amd64_read_pci_cfg(pvt->F1, high_offset, &high_limit);
pvt->dram_DstNode[dram] = (low_limit & 0x7);
pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7;
@@ -1341,7 +1266,7 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
{
- if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCTL_SEL_LOW,
+ if (!amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_LOW,
&pvt->dram_ctl_select_low)) {
debugf0("F2x110 (DCTL Sel. Low): 0x%08x, "
"High range addresses at: 0x%x\n",
@@ -1367,7 +1292,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
dct_sel_interleave_addr(pvt));
}
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCTL_SEL_HIGH,
+ amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_HIGH,
&pvt->dram_ctl_select_high);
}
@@ -1496,7 +1421,7 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
int cs_found = -EINVAL;
int csrow;
- mci = mci_lookup[nid];
+ mci = mcis[nid];
if (!mci)
return cs_found;
@@ -1572,7 +1497,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n",
hole_off, hole_valid, intlv_sel);
- if (intlv_en ||
+ if (intlv_en &&
(intlv_sel != ((sys_addr >> 12) & intlv_en)))
return -EINVAL;
@@ -1738,28 +1663,17 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
- edac_printk(KERN_DEBUG, EDAC_MC, " %d: %5dMB %d: %5dMB\n",
- dimm * 2, size0 << factor,
- dimm * 2 + 1, size1 << factor);
+ amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
+ dimm * 2, size0 << factor,
+ dimm * 2 + 1, size1 << factor);
}
}
-/*
- * There currently are 3 types type of MC devices for AMD Athlon/Opterons
- * (as per PCI DEVICE_IDs):
- *
- * Family K8: That is the Athlon64 and Opteron CPUs. They all have the same PCI
- * DEVICE ID, even though there is differences between the different Revisions
- * (CG,D,E,F).
- *
- * Family F10h and F11h.
- *
- */
static struct amd64_family_type amd64_family_types[] = {
[K8_CPUS] = {
- .ctl_name = "RevF",
- .addr_f1_ctl = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
- .misc_f3_ctl = PCI_DEVICE_ID_AMD_K8_NB_MISC,
+ .ctl_name = "K8",
+ .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
+ .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
.ops = {
.early_channel_count = k8_early_channel_count,
.get_error_address = k8_get_error_address,
@@ -1769,22 +1683,9 @@ static struct amd64_family_type amd64_family_types[] = {
}
},
[F10_CPUS] = {
- .ctl_name = "Family 10h",
- .addr_f1_ctl = PCI_DEVICE_ID_AMD_10H_NB_MAP,
- .misc_f3_ctl = PCI_DEVICE_ID_AMD_10H_NB_MISC,
- .ops = {
- .early_channel_count = f10_early_channel_count,
- .get_error_address = f10_get_error_address,
- .read_dram_base_limit = f10_read_dram_base_limit,
- .read_dram_ctl_register = f10_read_dram_ctl_register,
- .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow,
- .dbam_to_cs = f10_dbam_to_chip_select,
- }
- },
- [F11_CPUS] = {
- .ctl_name = "Family 11h",
- .addr_f1_ctl = PCI_DEVICE_ID_AMD_11H_NB_MAP,
- .misc_f3_ctl = PCI_DEVICE_ID_AMD_11H_NB_MISC,
+ .ctl_name = "F10h",
+ .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
+ .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
.ops = {
.early_channel_count = f10_early_channel_count,
.get_error_address = f10_get_error_address,
@@ -1970,8 +1871,7 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
ARRAY_SIZE(x4_vectors),
pvt->syn_type);
else {
- amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
- __func__, pvt->syn_type);
+ amd64_warn("Illegal syndrome type: %u\n", pvt->syn_type);
return err_sym;
}
@@ -1989,17 +1889,15 @@ static void amd64_handle_ce(struct mem_ctl_info *mci,
u64 sys_addr;
/* Ensure that the Error Address is VALID */
- if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
- amd64_mc_printk(mci, KERN_ERR,
- "HW has no ERROR_ADDRESS available\n");
+ if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+ amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return;
}
sys_addr = pvt->ops->get_error_address(mci, info);
- amd64_mc_printk(mci, KERN_ERR,
- "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
+ amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
pvt->ops->map_sysaddr_to_csrow(mci, info, sys_addr);
}
@@ -2016,9 +1914,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
log_mci = mci;
- if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
- amd64_mc_printk(mci, KERN_CRIT,
- "HW has no ERROR_ADDRESS available\n");
+ if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+ amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
return;
}
@@ -2031,9 +1928,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
*/
src_mci = find_mc_by_sys_addr(mci, sys_addr);
if (!src_mci) {
- amd64_mc_printk(mci, KERN_CRIT,
- "ERROR ADDRESS (0x%lx) value NOT mapped to a MC\n",
- (unsigned long)sys_addr);
+ amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
+ (unsigned long)sys_addr);
edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
return;
}
@@ -2042,9 +1938,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
csrow = sys_addr_to_csrow(log_mci, sys_addr);
if (csrow < 0) {
- amd64_mc_printk(mci, KERN_CRIT,
- "ERROR_ADDRESS (0x%lx) value NOT mapped to 'csrow'\n",
- (unsigned long)sys_addr);
+ amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
+ (unsigned long)sys_addr);
edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
} else {
error_address_to_page_and_offset(sys_addr, &page, &offset);
@@ -2055,8 +1950,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
struct err_regs *info)
{
- u32 ec = ERROR_CODE(info->nbsl);
- u32 xec = EXT_ERROR_CODE(info->nbsl);
+ u16 ec = EC(info->nbsl);
+ u8 xec = XEC(info->nbsl, 0x1f);
int ecc_type = (info->nbsh >> 13) & 0x3;
/* Bail early out if this was an 'observed' error */
@@ -2075,7 +1970,7 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
{
- struct mem_ctl_info *mci = mci_lookup[node_id];
+ struct mem_ctl_info *mci = mcis[node_id];
struct err_regs regs;
regs.nbsl = (u32) m->status;
@@ -2099,75 +1994,50 @@ void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
}
/*
- * Input:
- * 1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
- * 2) AMD Family index value
- *
- * Ouput:
- * Upon return of 0, the following filled in:
- *
- * struct pvt->addr_f1_ctl
- * struct pvt->misc_f3_ctl
- *
- * Filled in with related device funcitions of 'dram_f2_ctl'
- * These devices are "reserved" via the pci_get_device()
- *
- * Upon return of 1 (error status):
- *
- * Nothing reserved
+ * Use pvt->F2 which contains the F2 CPU PCI device to get the related
+ * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
*/
-static int amd64_reserve_mc_sibling_devices(struct amd64_pvt *pvt, int mc_idx)
+static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
{
- const struct amd64_family_type *amd64_dev = &amd64_family_types[mc_idx];
-
/* Reserve the ADDRESS MAP Device */
- pvt->addr_f1_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
- amd64_dev->addr_f1_ctl,
- pvt->dram_f2_ctl);
-
- if (!pvt->addr_f1_ctl) {
- amd64_printk(KERN_ERR, "error address map device not found: "
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_AMD, amd64_dev->addr_f1_ctl);
- return 1;
+ pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
+ if (!pvt->F1) {
+ amd64_err("error address map device not found: "
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_AMD, f1_id);
+ return -ENODEV;
}
/* Reserve the MISC Device */
- pvt->misc_f3_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
- amd64_dev->misc_f3_ctl,
- pvt->dram_f2_ctl);
+ pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2);
+ if (!pvt->F3) {
+ pci_dev_put(pvt->F1);
+ pvt->F1 = NULL;
- if (!pvt->misc_f3_ctl) {
- pci_dev_put(pvt->addr_f1_ctl);
- pvt->addr_f1_ctl = NULL;
+ amd64_err("error F3 device not found: "
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_AMD, f3_id);
- amd64_printk(KERN_ERR, "error miscellaneous device not found: "
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_AMD, amd64_dev->misc_f3_ctl);
- return 1;
+ return -ENODEV;
}
-
- debugf1(" Addr Map device PCI Bus ID:\t%s\n",
- pci_name(pvt->addr_f1_ctl));
- debugf1(" DRAM MEM-CTL PCI Bus ID:\t%s\n",
- pci_name(pvt->dram_f2_ctl));
- debugf1(" Misc device PCI Bus ID:\t%s\n",
- pci_name(pvt->misc_f3_ctl));
+ debugf1("F1: %s\n", pci_name(pvt->F1));
+ debugf1("F2: %s\n", pci_name(pvt->F2));
+ debugf1("F3: %s\n", pci_name(pvt->F3));
return 0;
}
-static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
+static void free_mc_sibling_devs(struct amd64_pvt *pvt)
{
- pci_dev_put(pvt->addr_f1_ctl);
- pci_dev_put(pvt->misc_f3_ctl);
+ pci_dev_put(pvt->F1);
+ pci_dev_put(pvt->F3);
}
/*
* Retrieve the hardware registers of the memory controller (this includes the
* 'Address Map' and 'Misc' device regs)
*/
-static void amd64_read_mc_registers(struct amd64_pvt *pvt)
+static void read_mc_regs(struct amd64_pvt *pvt)
{
u64 msr_val;
u32 tmp;
@@ -2188,9 +2058,7 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
} else
debugf0(" TOP_MEM2 disabled.\n");
- amd64_cpu_display_info(pvt);
-
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCAP, &pvt->nbcap);
+ amd64_read_pci_cfg(pvt->F3, K8_NBCAP, &pvt->nbcap);
if (pvt->ops->read_dram_ctl_register)
pvt->ops->read_dram_ctl_register(pvt);
@@ -2227,21 +2095,20 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
amd64_read_dct_base_mask(pvt);
- amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DHAR, &pvt->dhar);
+ amd64_read_pci_cfg(pvt->F1, K8_DHAR, &pvt->dhar);
amd64_read_dbam_reg(pvt);
- amd64_read_pci_cfg(pvt->misc_f3_ctl,
- F10_ONLINE_SPARE, &pvt->online_spare);
+ amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);
+ amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
+ amd64_read_pci_cfg(pvt->F2, F10_DCHR_0, &pvt->dchr0);
if (boot_cpu_data.x86 >= 0x10) {
if (!dct_ganging_enabled(pvt)) {
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+ amd64_read_pci_cfg(pvt->F2, F10_DCLR_1, &pvt->dclr1);
+ amd64_read_pci_cfg(pvt->F2, F10_DCHR_1, &pvt->dchr1);
}
- amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
+ amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
}
if (boot_cpu_data.x86 == 0x10 &&
@@ -2321,21 +2188,22 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
* Initialize the array of csrow attribute instances, based on the values
* from pci config hardware registers.
*/
-static int amd64_init_csrows(struct mem_ctl_info *mci)
+static int init_csrows(struct mem_ctl_info *mci)
{
struct csrow_info *csrow;
- struct amd64_pvt *pvt;
+ struct amd64_pvt *pvt = mci->pvt_info;
u64 input_addr_min, input_addr_max, sys_addr;
+ u32 val;
int i, empty = 1;
- pvt = mci->pvt_info;
+ amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &val);
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &pvt->nbcfg);
+ pvt->nbcfg = val;
+ pvt->ctl_error_info.nbcfg = val;
- debugf0("NBCFG= 0x%x CHIPKILL= %s DRAM ECC= %s\n", pvt->nbcfg,
- (pvt->nbcfg & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
- (pvt->nbcfg & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"
- );
+ debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+ pvt->mc_node_id, val,
+ !!(val & K8_NBCFG_CHIPKILL), !!(val & K8_NBCFG_ECC_ENABLE));
for (i = 0; i < pvt->cs_count; i++) {
csrow = &mci->csrows[i];
@@ -2359,7 +2227,7 @@ static int amd64_init_csrows(struct mem_ctl_info *mci)
csrow->page_mask = ~mask_from_dct_mask(pvt, i);
/* 8 bytes of resolution */
- csrow->mtype = amd64_determine_memory_type(pvt);
+ csrow->mtype = amd64_determine_memory_type(pvt, i);
debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i);
debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
@@ -2404,8 +2272,7 @@ static bool amd64_nb_mce_bank_enabled_on_node(int nid)
bool ret = false;
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
- amd64_printk(KERN_WARNING, "%s: error allocating mask\n",
- __func__);
+ amd64_warn("%s: Error allocating mask\n", __func__);
return false;
}
@@ -2431,18 +2298,17 @@ out:
return ret;
}
-static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
{
cpumask_var_t cmask;
int cpu;
if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
- amd64_printk(KERN_WARNING, "%s: error allocating mask\n",
- __func__);
+ amd64_warn("%s: error allocating mask\n", __func__);
return false;
}
- get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id);
+ get_cpus_on_this_dct_cpumask(cmask, nid);
rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
@@ -2452,14 +2318,14 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
if (on) {
if (reg->l & K8_MSR_MCGCTL_NBE)
- pvt->flags.nb_mce_enable = 1;
+ s->flags.nb_mce_enable = 1;
reg->l |= K8_MSR_MCGCTL_NBE;
} else {
/*
* Turn off NB MCE reporting only when it was off before
*/
- if (!pvt->flags.nb_mce_enable)
+ if (!s->flags.nb_mce_enable)
reg->l &= ~K8_MSR_MCGCTL_NBE;
}
}
@@ -2470,92 +2336,92 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
return 0;
}
-static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+ struct pci_dev *F3)
{
- struct amd64_pvt *pvt = mci->pvt_info;
+ bool ret = true;
u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCTL, &value);
+ if (toggle_ecc_err_reporting(s, nid, ON)) {
+ amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
+ return false;
+ }
+
+ amd64_read_pci_cfg(F3, K8_NBCTL, &value);
- /* turn on UECCn and CECCEn bits */
- pvt->old_nbctl = value & mask;
- pvt->nbctl_mcgctl_saved = 1;
+ /* turn on UECCEn and CECCEn bits */
+ s->old_nbctl = value & mask;
+ s->nbctl_valid = true;
value |= mask;
- pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
-
- if (amd64_toggle_ecc_err_reporting(pvt, ON))
- amd64_printk(KERN_WARNING, "Error enabling ECC reporting over "
- "MCGCTL!\n");
+ pci_write_config_dword(F3, K8_NBCTL, value);
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, K8_NBCFG, &value);
- debugf0("NBCFG(1)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value,
- (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
- (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+ debugf0("1: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+ nid, value,
+ !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
if (!(value & K8_NBCFG_ECC_ENABLE)) {
- amd64_printk(KERN_WARNING,
- "This node reports that DRAM ECC is "
- "currently Disabled; ENABLING now\n");
+ amd64_warn("DRAM ECC disabled on this node, enabling...\n");
- pvt->flags.nb_ecc_prev = 0;
+ s->flags.nb_ecc_prev = 0;
/* Attempt to turn on DRAM ECC Enable */
value |= K8_NBCFG_ECC_ENABLE;
- pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+ pci_write_config_dword(F3, K8_NBCFG, value);
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, K8_NBCFG, &value);
if (!(value & K8_NBCFG_ECC_ENABLE)) {
- amd64_printk(KERN_WARNING,
- "Hardware rejects Enabling DRAM ECC checking\n"
- "Check memory DIMM configuration\n");
+ amd64_warn("Hardware rejected DRAM ECC enable,"
+ "check memory DIMM configuration.\n");
+ ret = false;
} else {
- amd64_printk(KERN_DEBUG,
- "Hardware accepted DRAM ECC Enable\n");
+ amd64_info("Hardware accepted DRAM ECC Enable\n");
}
} else {
- pvt->flags.nb_ecc_prev = 1;
+ s->flags.nb_ecc_prev = 1;
}
- debugf0("NBCFG(2)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value,
- (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
- (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+ debugf0("2: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+ nid, value,
+ !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
- pvt->ctl_error_info.nbcfg = value;
+ return ret;
}
-static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
+static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+ struct pci_dev *F3)
{
u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
- if (!pvt->nbctl_mcgctl_saved)
+ if (!s->nbctl_valid)
return;
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCTL, &value);
+ amd64_read_pci_cfg(F3, K8_NBCTL, &value);
value &= ~mask;
- value |= pvt->old_nbctl;
+ value |= s->old_nbctl;
- pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+ pci_write_config_dword(F3, K8_NBCTL, value);
- /* restore previous BIOS DRAM ECC "off" setting which we force-enabled */
- if (!pvt->flags.nb_ecc_prev) {
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+ /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
+ if (!s->flags.nb_ecc_prev) {
+ amd64_read_pci_cfg(F3, K8_NBCFG, &value);
value &= ~K8_NBCFG_ECC_ENABLE;
- pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+ pci_write_config_dword(F3, K8_NBCFG, value);
}
/* restore the NB Enable MCGCTL bit */
- if (amd64_toggle_ecc_err_reporting(pvt, OFF))
- amd64_printk(KERN_WARNING, "Error restoring NB MCGCTL settings!\n");
+ if (toggle_ecc_err_reporting(s, nid, OFF))
+ amd64_warn("Error restoring NB MCGCTL settings!\n");
}
/*
- * EDAC requires that the BIOS have ECC enabled before taking over the
- * processing of ECC errors. This is because the BIOS can properly initialize
- * the memory system completely. A command line option allows to force-enable
- * hardware ECC later in amd64_enable_ecc_error_reporting().
+ * EDAC requires that the BIOS have ECC enabled before
+ * taking over the processing of ECC errors. A command line
+ * option allows to force-enable hardware ECC later in
+ * enable_ecc_error_reporting().
*/
static const char *ecc_msg =
"ECC disabled in the BIOS or no ECC capability, module will not load.\n"
@@ -2563,38 +2429,28 @@ static const char *ecc_msg =
"'ecc_enable_override'.\n"
" (Note that use of the override may cause unknown side effects.)\n";
-static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
+static bool ecc_enabled(struct pci_dev *F3, u8 nid)
{
u32 value;
- u8 ecc_enabled = 0;
+ u8 ecc_en = 0;
bool nb_mce_en = false;
- amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, K8_NBCFG, &value);
- ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
- if (!ecc_enabled)
- amd64_printk(KERN_NOTICE, "This node reports that Memory ECC "
- "is currently disabled, set F3x%x[22] (%s).\n",
- K8_NBCFG, pci_name(pvt->misc_f3_ctl));
- else
- amd64_printk(KERN_INFO, "ECC is enabled by BIOS.\n");
+ ecc_en = !!(value & K8_NBCFG_ECC_ENABLE);
+ amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
- nb_mce_en = amd64_nb_mce_bank_enabled_on_node(pvt->mc_node_id);
+ nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
if (!nb_mce_en)
- amd64_printk(KERN_NOTICE, "NB MCE bank disabled, set MSR "
+ amd64_notice("NB MCE bank disabled, set MSR "
"0x%08x[4] on node %d to enable.\n",
- MSR_IA32_MCG_CTL, pvt->mc_node_id);
+ MSR_IA32_MCG_CTL, nid);
- if (!ecc_enabled || !nb_mce_en) {
- if (!ecc_enable_override) {
- amd64_printk(KERN_NOTICE, "%s", ecc_msg);
- return -ENODEV;
- } else {
- amd64_printk(KERN_WARNING, "Forcing ECC checking on!\n");
- }
+ if (!ecc_en || !nb_mce_en) {
+ amd64_notice("%s", ecc_msg);
+ return false;
}
-
- return 0;
+ return true;
}
struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
@@ -2603,22 +2459,23 @@ struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
-static void amd64_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
{
unsigned int i = 0, j = 0;
for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
sysfs_attrs[i] = amd64_dbg_attrs[i];
- for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
- sysfs_attrs[i] = amd64_inj_attrs[j];
+ if (boot_cpu_data.x86 >= 0x10)
+ for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
+ sysfs_attrs[i] = amd64_inj_attrs[j];
sysfs_attrs[i] = terminator;
mci->mc_driver_sysfs_attributes = sysfs_attrs;
}
-static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
+static void setup_mci_misc_attrs(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
@@ -2634,8 +2491,8 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
mci->edac_cap = amd64_determine_edac_cap(pvt);
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = EDAC_AMD64_VERSION;
- mci->ctl_name = get_amd_family_name(pvt->mc_type_index);
- mci->dev_name = pci_name(pvt->dram_f2_ctl);
+ mci->ctl_name = pvt->ctl_name;
+ mci->dev_name = pci_name(pvt->F2);
mci->ctl_page_to_phys = NULL;
/* memory scrubber interface */
@@ -2644,111 +2501,94 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
}
/*
- * Init stuff for this DRAM Controller device.
- *
- * Due to a hardware feature on Fam10h CPUs, the Enable Extended Configuration
- * Space feature MUST be enabled on ALL Processors prior to actually reading
- * from the ECS registers. Since the loading of the module can occur on any
- * 'core', and cores don't 'see' all the other processors ECS data when the
- * others are NOT enabled. Our solution is to first enable ECS access in this
- * routine on all processors, gather some data in a amd64_pvt structure and
- * later come back in a finish-setup function to perform that final
- * initialization. See also amd64_init_2nd_stage() for that.
+ * returns a pointer to the family descriptor on success, NULL otherwise.
*/
-static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
- int mc_type_index)
+static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
+{
+ u8 fam = boot_cpu_data.x86;
+ struct amd64_family_type *fam_type = NULL;
+
+ switch (fam) {
+ case 0xf:
+ fam_type = &amd64_family_types[K8_CPUS];
+ pvt->ops = &amd64_family_types[K8_CPUS].ops;
+ pvt->ctl_name = fam_type->ctl_name;
+ pvt->min_scrubrate = K8_MIN_SCRUB_RATE_BITS;
+ break;
+ case 0x10:
+ fam_type = &amd64_family_types[F10_CPUS];
+ pvt->ops = &amd64_family_types[F10_CPUS].ops;
+ pvt->ctl_name = fam_type->ctl_name;
+ pvt->min_scrubrate = F10_MIN_SCRUB_RATE_BITS;
+ break;
+
+ default:
+ amd64_err("Unsupported family!\n");
+ return NULL;
+ }
+
+ pvt->ext_model = boot_cpu_data.x86_model >> 4;
+
+ amd64_info("%s %sdetected (node %d).\n", pvt->ctl_name,
+ (fam == 0xf ?
+ (pvt->ext_model >= K8_REV_F ? "revF or later "
+ : "revE or earlier ")
+ : ""), pvt->mc_node_id);
+ return fam_type;
+}
+
+static int amd64_init_one_instance(struct pci_dev *F2)
{
struct amd64_pvt *pvt = NULL;
+ struct amd64_family_type *fam_type = NULL;
+ struct mem_ctl_info *mci = NULL;
int err = 0, ret;
+ u8 nid = get_node_id(F2);
ret = -ENOMEM;
pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
if (!pvt)
- goto err_exit;
+ goto err_ret;
- pvt->mc_node_id = get_node_id(dram_f2_ctl);
+ pvt->mc_node_id = nid;
+ pvt->F2 = F2;
- pvt->dram_f2_ctl = dram_f2_ctl;
- pvt->ext_model = boot_cpu_data.x86_model >> 4;
- pvt->mc_type_index = mc_type_index;
- pvt->ops = family_ops(mc_type_index);
+ ret = -EINVAL;
+ fam_type = amd64_per_family_init(pvt);
+ if (!fam_type)
+ goto err_free;
- /*
- * We have the dram_f2_ctl device as an argument, now go reserve its
- * sibling devices from the PCI system.
- */
ret = -ENODEV;
- err = amd64_reserve_mc_sibling_devices(pvt, mc_type_index);
+ err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id);
if (err)
goto err_free;
- ret = -EINVAL;
- err = amd64_check_ecc_enabled(pvt);
- if (err)
- goto err_put;
-
- /*
- * Key operation here: setup of HW prior to performing ops on it. Some
- * setup is required to access ECS data. After this is performed, the
- * 'teardown' function must be called upon error and normal exit paths.
- */
- if (boot_cpu_data.x86 >= 0x10)
- amd64_setup(pvt);
-
- /*
- * Save the pointer to the private data for use in 2nd initialization
- * stage
- */
- pvt_lookup[pvt->mc_node_id] = pvt;
-
- return 0;
-
-err_put:
- amd64_free_mc_sibling_devices(pvt);
-
-err_free:
- kfree(pvt);
-
-err_exit:
- return ret;
-}
-
-/*
- * This is the finishing stage of the init code. Needs to be performed after all
- * MCs' hardware have been prepped for accessing extended config space.
- */
-static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
-{
- int node_id = pvt->mc_node_id;
- struct mem_ctl_info *mci;
- int ret = -ENODEV;
-
- amd64_read_mc_registers(pvt);
+ read_mc_regs(pvt);
/*
* We need to determine how many memory channels there are. Then use
* that information for calculating the size of the dynamic instance
- * tables in the 'mci' structure
+ * tables in the 'mci' structure.
*/
+ ret = -EINVAL;
pvt->channel_count = pvt->ops->early_channel_count(pvt);
if (pvt->channel_count < 0)
- goto err_exit;
+ goto err_siblings;
ret = -ENOMEM;
- mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, node_id);
+ mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, nid);
if (!mci)
- goto err_exit;
+ goto err_siblings;
mci->pvt_info = pvt;
+ mci->dev = &pvt->F2->dev;
- mci->dev = &pvt->dram_f2_ctl->dev;
- amd64_setup_mci_misc_attributes(mci);
+ setup_mci_misc_attrs(mci);
- if (amd64_init_csrows(mci))
+ if (init_csrows(mci))
mci->edac_cap = EDAC_FLAG_NONE;
- amd64_enable_ecc_error_reporting(mci);
- amd64_set_mc_sysfs_attributes(mci);
+ set_mc_sysfs_attrs(mci);
ret = -ENODEV;
if (edac_mc_add_mc(mci)) {
@@ -2756,54 +2596,77 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
goto err_add_mc;
}
- mci_lookup[node_id] = mci;
- pvt_lookup[node_id] = NULL;
-
/* register stuff with EDAC MCE */
if (report_gart_errors)
amd_report_gart_errors(true);
amd_register_ecc_decoder(amd64_decode_bus_error);
+ mcis[nid] = mci;
+
+ atomic_inc(&drv_instances);
+
return 0;
err_add_mc:
edac_mc_free(mci);
-err_exit:
- debugf0("failure to init 2nd stage: ret=%d\n", ret);
-
- amd64_restore_ecc_error_reporting(pvt);
-
- if (boot_cpu_data.x86 > 0xf)
- amd64_teardown(pvt);
+err_siblings:
+ free_mc_sibling_devs(pvt);
- amd64_free_mc_sibling_devices(pvt);
-
- kfree(pvt_lookup[pvt->mc_node_id]);
- pvt_lookup[node_id] = NULL;
+err_free:
+ kfree(pvt);
+err_ret:
return ret;
}
-
-static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
- const struct pci_device_id *mc_type)
+static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
+ const struct pci_device_id *mc_type)
{
+ u8 nid = get_node_id(pdev);
+ struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
+ struct ecc_settings *s;
int ret = 0;
- debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev),
- get_amd_family_name(mc_type->driver_data));
-
ret = pci_enable_device(pdev);
- if (ret < 0)
- ret = -EIO;
- else
- ret = amd64_probe_one_instance(pdev, mc_type->driver_data);
-
- if (ret < 0)
+ if (ret < 0) {
debugf0("ret=%d\n", ret);
+ return -EIO;
+ }
+
+ ret = -ENOMEM;
+ s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
+ if (!s)
+ goto err_out;
+
+ ecc_stngs[nid] = s;
+
+ if (!ecc_enabled(F3, nid)) {
+ ret = -ENODEV;
+
+ if (!ecc_enable_override)
+ goto err_enable;
+
+ amd64_warn("Forcing ECC on!\n");
+
+ if (!enable_ecc_error_reporting(s, nid, F3))
+ goto err_enable;
+ }
+ ret = amd64_init_one_instance(pdev);
+ if (ret < 0) {
+ amd64_err("Error probing instance: %d\n", nid);
+ restore_ecc_error_reporting(s, nid, F3);
+ }
+
+ return ret;
+
+err_enable:
+ kfree(s);
+ ecc_stngs[nid] = NULL;
+
+err_out:
return ret;
}
@@ -2811,6 +2674,9 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
struct amd64_pvt *pvt;
+ u8 nid = get_node_id(pdev);
+ struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
+ struct ecc_settings *s = ecc_stngs[nid];
/* Remove from EDAC CORE tracking list */
mci = edac_mc_del_mc(&pdev->dev);
@@ -2819,20 +2685,20 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
pvt = mci->pvt_info;
- amd64_restore_ecc_error_reporting(pvt);
+ restore_ecc_error_reporting(s, nid, F3);
- if (boot_cpu_data.x86 > 0xf)
- amd64_teardown(pvt);
-
- amd64_free_mc_sibling_devices(pvt);
+ free_mc_sibling_devs(pvt);
/* unregister from EDAC MCE */
amd_report_gart_errors(false);
amd_unregister_ecc_decoder(amd64_decode_bus_error);
+ kfree(ecc_stngs[nid]);
+ ecc_stngs[nid] = NULL;
+
/* Free the EDAC CORE resources */
mci->pvt_info = NULL;
- mci_lookup[pvt->mc_node_id] = NULL;
+ mcis[nid] = NULL;
kfree(pvt);
edac_mc_free(mci);
@@ -2851,7 +2717,6 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = {
.subdevice = PCI_ANY_ID,
.class = 0,
.class_mask = 0,
- .driver_data = K8_CPUS
},
{
.vendor = PCI_VENDOR_ID_AMD,
@@ -2860,16 +2725,6 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = {
.subdevice = PCI_ANY_ID,
.class = 0,
.class_mask = 0,
- .driver_data = F10_CPUS
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_11H_NB_DRAM,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- .driver_data = F11_CPUS
},
{0, }
};
@@ -2877,12 +2732,12 @@ MODULE_DEVICE_TABLE(pci, amd64_pci_table);
static struct pci_driver amd64_pci_driver = {
.name = EDAC_MOD_STR,
- .probe = amd64_init_one_instance,
+ .probe = amd64_probe_one_instance,
.remove = __devexit_p(amd64_remove_one_instance),
.id_table = amd64_pci_table,
};
-static void amd64_setup_pci_device(void)
+static void setup_pci_device(void)
{
struct mem_ctl_info *mci;
struct amd64_pvt *pvt;
@@ -2890,13 +2745,12 @@ static void amd64_setup_pci_device(void)
if (amd64_ctl_pci)
return;
- mci = mci_lookup[0];
+ mci = mcis[0];
if (mci) {
pvt = mci->pvt_info;
amd64_ctl_pci =
- edac_pci_create_generic_ctl(&pvt->dram_f2_ctl->dev,
- EDAC_MOD_STR);
+ edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
if (!amd64_ctl_pci) {
pr_warning("%s(): Unable to create PCI control\n",
@@ -2910,51 +2764,50 @@ static void amd64_setup_pci_device(void)
static int __init amd64_edac_init(void)
{
- int nb, err = -ENODEV;
- bool load_ok = false;
+ int err = -ENODEV;
edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n");
opstate_init();
- if (cache_k8_northbridges() < 0)
+ if (amd_cache_northbridges() < 0)
+ goto err_ret;
+
+ err = -ENOMEM;
+ mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
+ ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
+ if (!(mcis && ecc_stngs))
goto err_ret;
msrs = msrs_alloc();
if (!msrs)
- goto err_ret;
+ goto err_free;
err = pci_register_driver(&amd64_pci_driver);
if (err)
goto err_pci;
- /*
- * At this point, the array 'pvt_lookup[]' contains pointers to alloc'd
- * amd64_pvt structs. These will be used in the 2nd stage init function
- * to finish initialization of the MC instances.
- */
err = -ENODEV;
- for (nb = 0; nb < k8_northbridges.num; nb++) {
- if (!pvt_lookup[nb])
- continue;
-
- err = amd64_init_2nd_stage(pvt_lookup[nb]);
- if (err)
- goto err_2nd_stage;
+ if (!atomic_read(&drv_instances))
+ goto err_no_instances;
- load_ok = true;
- }
-
- if (load_ok) {
- amd64_setup_pci_device();
- return 0;
- }
+ setup_pci_device();
+ return 0;
-err_2nd_stage:
+err_no_instances:
pci_unregister_driver(&amd64_pci_driver);
+
err_pci:
msrs_free(msrs);
msrs = NULL;
+
+err_free:
+ kfree(mcis);
+ mcis = NULL;
+
+ kfree(ecc_stngs);
+ ecc_stngs = NULL;
+
err_ret:
return err;
}
@@ -2966,6 +2819,12 @@ static void __exit amd64_edac_exit(void)
pci_unregister_driver(&amd64_pci_driver);
+ kfree(ecc_stngs);
+ ecc_stngs = NULL;
+
+ kfree(mcis);
+ mcis = NULL;
+
msrs_free(msrs);
msrs = NULL;
}
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 044aee4f944d..613ec72b0f65 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -74,11 +74,26 @@
#include "edac_core.h"
#include "mce_amd.h"
-#define amd64_printk(level, fmt, arg...) \
- edac_printk(level, "amd64", fmt, ##arg)
+#define amd64_debug(fmt, arg...) \
+ edac_printk(KERN_DEBUG, "amd64", fmt, ##arg)
-#define amd64_mc_printk(mci, level, fmt, arg...) \
- edac_mc_chipset_printk(mci, level, "amd64", fmt, ##arg)
+#define amd64_info(fmt, arg...) \
+ edac_printk(KERN_INFO, "amd64", fmt, ##arg)
+
+#define amd64_notice(fmt, arg...) \
+ edac_printk(KERN_NOTICE, "amd64", fmt, ##arg)
+
+#define amd64_warn(fmt, arg...) \
+ edac_printk(KERN_WARNING, "amd64", fmt, ##arg)
+
+#define amd64_err(fmt, arg...) \
+ edac_printk(KERN_ERR, "amd64", fmt, ##arg)
+
+#define amd64_mc_warn(mci, fmt, arg...) \
+ edac_mc_chipset_printk(mci, KERN_WARNING, "amd64", fmt, ##arg)
+
+#define amd64_mc_err(mci, fmt, arg...) \
+ edac_mc_chipset_printk(mci, KERN_ERR, "amd64", fmt, ##arg)
/*
* Throughout the comments in this code, the following terms are used:
@@ -129,11 +144,9 @@
* sections 3.5.4 and 3.5.5 for more information.
*/
-#define EDAC_AMD64_VERSION " Ver: 3.3.0 " __DATE__
+#define EDAC_AMD64_VERSION "v3.3.0"
#define EDAC_MOD_STR "amd64_edac"
-#define EDAC_MAX_NUMNODES 8
-
/* Extended Model from CPUID, for CPU Revision numbers */
#define K8_REV_D 1
#define K8_REV_E 2
@@ -322,9 +335,6 @@
#define K8_SCRCTRL 0x58
#define F10_NB_CFG_LOW 0x88
-#define F10_NB_CFG_LOW_ENABLE_EXT_CFG BIT(14)
-
-#define F10_NB_CFG_HIGH 0x8C
#define F10_ONLINE_SPARE 0xB0
#define F10_ONLINE_SPARE_SWAPDONE0(x) ((x) & BIT(1))
@@ -373,7 +383,6 @@ static inline int get_node_id(struct pci_dev *pdev)
enum amd64_chipset_families {
K8_CPUS = 0,
F10_CPUS,
- F11_CPUS,
};
/* Error injection control structure */
@@ -384,16 +393,13 @@ struct error_injection {
};
struct amd64_pvt {
+ struct low_ops *ops;
+
/* pci_device handles which we utilize */
- struct pci_dev *addr_f1_ctl;
- struct pci_dev *dram_f2_ctl;
- struct pci_dev *misc_f3_ctl;
+ struct pci_dev *F1, *F2, *F3;
int mc_node_id; /* MC index of this MC node */
int ext_model; /* extended model value of this node */
-
- struct low_ops *ops; /* pointer to per PCI Device ID func table */
-
int channel_count;
/* Raw registers */
@@ -455,27 +461,27 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */
struct error_injection injection;
- /* Save old hw registers' values before we modified them */
- u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */
- u32 old_nbctl;
+ /* DCT per-family scrubrate setting */
+ u32 min_scrubrate;
- /* MC Type Index value: socket F vs Family 10h */
- u32 mc_type_index;
+ /* family name this instance is running on */
+ const char *ctl_name;
+
+};
+
+/*
+ * per-node ECC settings descriptor
+ */
+struct ecc_settings {
+ u32 old_nbctl;
+ bool nbctl_valid;
- /* misc settings */
struct flags {
- unsigned long cf8_extcfg:1;
unsigned long nb_mce_enable:1;
unsigned long nb_ecc_prev:1;
} flags;
};
-struct scrubrate {
- u32 scrubval; /* bit pattern for scrub rate */
- u32 bandwidth; /* bandwidth consumed (bytes/sec) */
-};
-
-extern struct scrubrate scrubrates[23];
extern const char *tt_msgs[4];
extern const char *ll_msgs[4];
extern const char *rrrr_msgs[16];
@@ -517,23 +523,10 @@ struct low_ops {
struct amd64_family_type {
const char *ctl_name;
- u16 addr_f1_ctl;
- u16 misc_f3_ctl;
+ u16 f1_id, f3_id;
struct low_ops ops;
};
-static struct amd64_family_type amd64_family_types[];
-
-static inline const char *get_amd_family_name(int index)
-{
- return amd64_family_types[index].ctl_name;
-}
-
-static inline struct low_ops *family_ops(int index)
-{
- return &amd64_family_types[index].ops;
-}
-
static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
u32 *val, const char *func)
{
@@ -541,8 +534,8 @@ static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
err = pci_read_config_dword(pdev, offset, val);
if (err)
- amd64_printk(KERN_WARNING, "%s: error reading F%dx%x.\n",
- func, PCI_FUNC(pdev->devfn), offset);
+ amd64_warn("%s: error reading F%dx%x.\n",
+ func, PCI_FUNC(pdev->devfn), offset);
return err;
}
@@ -556,7 +549,6 @@ static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
*/
#define K8_MIN_SCRUB_RATE_BITS 0x0
#define F10_MIN_SCRUB_RATE_BITS 0x5
-#define F11_MIN_SCRUB_RATE_BITS 0x6
int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size);
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 29f1f7a612d9..688478de1cbd 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -23,9 +23,7 @@ static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value > 3) {
- amd64_printk(KERN_WARNING,
- "%s: invalid section 0x%lx\n",
- __func__, value);
+ amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
return -EINVAL;
}
@@ -58,9 +56,7 @@ static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value > 8) {
- amd64_printk(KERN_WARNING,
- "%s: invalid word 0x%lx\n",
- __func__, value);
+ amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
return -EINVAL;
}
@@ -92,9 +88,8 @@ static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value & 0xFFFF0000) {
- amd64_printk(KERN_WARNING,
- "%s: invalid EccVector: 0x%lx\n",
- __func__, value);
+ amd64_warn("%s: invalid EccVector: 0x%lx\n",
+ __func__, value);
return -EINVAL;
}
@@ -122,15 +117,13 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- pci_write_config_dword(pvt->misc_f3_ctl,
- F10_NB_ARRAY_ADDR, section);
+ pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
- pci_write_config_dword(pvt->misc_f3_ctl,
- F10_NB_ARRAY_DATA, word_bits);
+ pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
@@ -157,15 +150,13 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- pci_write_config_dword(pvt->misc_f3_ctl,
- F10_NB_ARRAY_ADDR, section);
+ pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
- pci_write_config_dword(pvt->misc_f3_ctl,
- F10_NB_ARRAY_DATA, word_bits);
+ pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h
index 60e0d1c72dee..6f8b07131ec4 100644
--- a/drivers/edac/amd8131_edac.h
+++ b/drivers/edac/amd8131_edac.h
@@ -99,7 +99,7 @@ struct amd8131_dev_info {
/*
* AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC
- * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are
+ * Controller, and ATCA-6101 has two AMD8131 chipsets, so there are
* four PCIX Bridges on ATCA-6101 altogether.
*
* These PCIX Bridges share the same PCI Device ID and are all of
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index c973004c002c..db1df59ae2b6 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
@@ -47,7 +47,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
offset = address & ~PAGE_MASK;
syndrome = (ar & 0x000000001fe00000ul) >> 21;
- /* TODO: Decoding of the error addresss */
+ /* TODO: Decoding of the error address */
edac_mc_handle_ce(mci, csrow->first_page + pfn, offset,
syndrome, 0, chan, "");
}
@@ -68,7 +68,7 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
pfn = address >> PAGE_SHIFT;
offset = address & ~PAGE_MASK;
- /* TODO: Decoding of the error addresss */
+ /* TODO: Decoding of the error address */
edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, "");
}
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 1609a19df495..b9a781c47e3c 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -818,9 +818,10 @@ static void cpc925_del_edac_devices(void)
}
/* Convert current back-ground scrub rate into byte/sec bandwith */
-static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci)
{
struct cpc925_mc_pdata *pdata = mci->pvt_info;
+ int bw;
u32 mscr;
u8 si;
@@ -832,11 +833,11 @@ static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) ||
(si == 0)) {
cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n");
- *bw = 0;
+ bw = 0;
} else
- *bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si;
+ bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si;
- return 0;
+ return bw;
}
/* Return 0 for single channel; 1 for dual channel */
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 073f5a06d238..ec302d426589 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -983,11 +983,11 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval);
- return 0;
+ return scrubrates[i].bandwidth;
}
/* Convert current scrub rate value into byte/sec bandwidth */
-static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
{
const struct scrubrate *scrubrates;
struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
@@ -1013,10 +1013,8 @@ static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
"Invalid sdram scrub control value: 0x%x\n", scrubval);
return -1;
}
+ return scrubrates[i].bandwidth;
- *bw = scrubrates[i].bandwidth;
-
- return 0;
}
/* Return 1 if dual channel mode is active. Else return 0. */
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index d7ca43a828bd..3d965347a673 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -41,10 +41,10 @@
#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
-#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
-#define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT))
+#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT))
+#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
#else /* PAGE_SHIFT > 20 */
-#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20))
#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20))
#endif
@@ -68,9 +68,10 @@
#define EDAC_PCI "PCI"
#define EDAC_DEBUG "DEBUG"
+extern const char *edac_mem_types[];
+
#ifdef CONFIG_EDAC_DEBUG
extern int edac_debug_level;
-extern const char *edac_mem_types[];
#define edac_debug_printk(level, fmt, arg...) \
do { \
@@ -258,7 +259,7 @@ enum scrub_type {
* for single channel are 64 bits, for dual channel 128
* bits.
*
- * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memmory.
+ * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory.
* Motherboards commonly drive two chip-select pins to
* a memory stick. A single-ranked stick, will occupy
* only one of those rows. The other will be unused.
@@ -386,7 +387,7 @@ struct mem_ctl_info {
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);
/* pointer to edac checking routine */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index ba6586a69ccc..a4e9db2d6524 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -76,6 +76,8 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
}
+#endif /* CONFIG_EDAC_DEBUG */
+
/*
* keep those in sync with the enum mem_type
*/
@@ -100,8 +102,6 @@ const char *edac_mem_types[] = {
};
EXPORT_SYMBOL_GPL(edac_mem_types);
-#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
* compiler would provide for X and return the aligned result.
@@ -586,14 +586,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
return NULL;
}
- /* marking MCI offline */
- mci->op_state = OP_OFFLINE;
-
del_mc_from_global_list(mci);
mutex_unlock(&mem_ctls_mutex);
- /* flush workq processes and remove sysfs */
+ /* flush workq processes */
edac_mc_workq_teardown(mci);
+
+ /* marking MCI offline */
+ mci->op_state = OP_OFFLINE;
+
+ /* remove from sysfs */
edac_remove_sysfs_mci_device(mci);
edac_printk(KERN_INFO, EDAC_MC,
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index dce61f7ba38b..39d97cfdf58c 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -436,56 +436,55 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
-/* memory scrubbing */
+/* Memory scrubbing interface:
+ *
+ * A MC driver can limit the scrubbing bandwidth based on the CPU type.
+ * Therefore, ->set_sdram_scrub_rate should be made to return the actual
+ * bandwidth that is accepted or 0 when scrubbing is to be disabled.
+ *
+ * Negative value still means that an error has occurred while setting
+ * the scrub rate.
+ */
static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
const char *data, size_t count)
{
unsigned long bandwidth = 0;
- int err;
+ int new_bw = 0;
- if (!mci->set_sdram_scrub_rate) {
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrub rate setting not implemented!\n");
+ if (!mci->set_sdram_scrub_rate)
return -EINVAL;
- }
if (strict_strtoul(data, 10, &bandwidth) < 0)
return -EINVAL;
- err = mci->set_sdram_scrub_rate(mci, (u32)bandwidth);
- if (err) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Failed setting scrub rate to %lu\n", bandwidth);
- return -EINVAL;
- }
- else {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set to: %lu\n", bandwidth);
+ new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
+ if (new_bw >= 0) {
+ edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw);
return count;
}
+
+ edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth);
+ return -EINVAL;
}
+/*
+ * ->get_sdram_scrub_rate() return value semantics same as above.
+ */
static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
{
- u32 bandwidth = 0;
- int err;
+ int bandwidth = 0;
- if (!mci->get_sdram_scrub_rate) {
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrub rate reading not implemented\n");
+ if (!mci->get_sdram_scrub_rate)
return -EINVAL;
- }
- err = mci->get_sdram_scrub_rate(mci, &bandwidth);
- if (err) {
+ bandwidth = mci->get_sdram_scrub_rate(mci);
+ if (bandwidth < 0) {
edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
- return err;
- }
- else {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Read scrub rate: %d\n", bandwidth);
- return sprintf(data, "%d\n", bandwidth);
+ return bandwidth;
}
+
+ edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth);
+ return sprintf(data, "%d\n", bandwidth);
}
/* default attribute files for the MCI object */
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index f459a6c0886b..0448da0af75d 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -611,20 +611,17 @@ static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
bandwidth = 5900000 * i5100_mc_scrben(dw);
- return 0;
+ return bandwidth;
}
-static int i5100_get_scrub_rate(struct mem_ctl_info *mci,
- u32 *bandwidth)
+static int i5100_get_scrub_rate(struct mem_ctl_info *mci)
{
struct i5100_priv *priv = mci->pvt_info;
u32 dw;
pci_read_config_dword(priv->mc, I5100_MC, &dw);
- *bandwidth = 5900000 * i5100_mc_scrben(dw);
-
- return 0;
+ return 5900000 * i5100_mc_scrben(dw);
}
static struct pci_dev *pci_get_device_func(unsigned vendor,
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 362861c15779..81154ab296b6 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -1,6 +1,6 @@
/* Intel i7 core/Nehalem Memory Controller kernel module
*
- * This driver supports yhe memory controllers found on the Intel
+ * This driver supports the memory controllers found on the Intel
* processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx,
* Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield
* and Westmere-EP.
@@ -1271,7 +1271,7 @@ static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table)
int i;
/*
- * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
+ * On Xeon 55xx, the Intel Quick Path Arch Generic Non-core pci buses
* aren't announced by acpi. So, we need to use a legacy scan probing
* to detect them
*/
@@ -1864,7 +1864,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
if (mce->mcgstatus & 1)
i7core_check_error(mci);
- /* Advice mcelog that the error were handled */
+ /* Advise mcelog that the errors were handled */
return 1;
}
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index c0181093b490..f6cf73d93359 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -5,6 +5,7 @@
static struct amd_decoder_ops *fam_ops;
+static u8 xec_mask = 0xf;
static u8 nb_err_cpumask = 0xf;
static bool report_gart_errors;
@@ -74,57 +75,104 @@ static const char *f10h_nb_mce_desc[] = {
"ECC Error in the Probe Filter directory"
};
-static bool f12h_dc_mce(u16 ec)
+static const char * const f15h_ic_mce_desc[] = {
+ "UC during a demand linefill from L2",
+ "Parity error during data load from IC",
+ "Parity error for IC valid bit",
+ "Main tag parity error",
+ "Parity error in prediction queue",
+ "PFB data/address parity error",
+ "Parity error in the branch status reg",
+ "PFB promotion address error",
+ "Tag error during probe/victimization",
+ "Parity error for IC probe tag valid bit",
+ "PFB non-cacheable bit parity error",
+ "PFB valid bit parity error", /* xec = 0xd */
+ "patch RAM", /* xec = 010 */
+ "uop queue",
+ "insn buffer",
+ "predecode buffer",
+ "fetch address FIFO"
+};
+
+static const char * const f15h_cu_mce_desc[] = {
+ "Fill ECC error on data fills", /* xec = 0x4 */
+ "Fill parity error on insn fills",
+ "Prefetcher request FIFO parity error",
+ "PRQ address parity error",
+ "PRQ data parity error",
+ "WCC Tag ECC error",
+ "WCC Data ECC error",
+ "WCB Data parity error",
+ "VB Data/ECC error",
+ "L2 Tag ECC error", /* xec = 0x10 */
+ "Hard L2 Tag ECC error",
+ "Multiple hits on L2 tag",
+ "XAB parity error",
+ "PRB address parity error"
+};
+
+static const char * const fr_ex_mce_desc[] = {
+ "CPU Watchdog timer expire",
+ "Wakeup array dest tag",
+ "AG payload array",
+ "EX payload array",
+ "IDRF array",
+ "Retire dispatch queue",
+ "Mapper checkpoint array",
+ "Physical register file EX0 port",
+ "Physical register file EX1 port",
+ "Physical register file AG0 port",
+ "Physical register file AG1 port",
+ "Flag register file",
+ "DE correctable error could not be corrected"
+};
+
+static bool f12h_dc_mce(u16 ec, u8 xec)
{
bool ret = false;
if (MEM_ERROR(ec)) {
- u8 ll = ec & 0x3;
+ u8 ll = LL(ec);
ret = true;
if (ll == LL_L2)
pr_cont("during L1 linefill from L2.\n");
else if (ll == LL_L1)
- pr_cont("Data/Tag %s error.\n", RRRR_MSG(ec));
+ pr_cont("Data/Tag %s error.\n", R4_MSG(ec));
else
ret = false;
}
return ret;
}
-static bool f10h_dc_mce(u16 ec)
+static bool f10h_dc_mce(u16 ec, u8 xec)
{
- u8 r4 = (ec >> 4) & 0xf;
- u8 ll = ec & 0x3;
-
- if (r4 == R4_GEN && ll == LL_L1) {
+ if (R4(ec) == R4_GEN && LL(ec) == LL_L1) {
pr_cont("during data scrub.\n");
return true;
}
- return f12h_dc_mce(ec);
+ return f12h_dc_mce(ec, xec);
}
-static bool k8_dc_mce(u16 ec)
+static bool k8_dc_mce(u16 ec, u8 xec)
{
if (BUS_ERROR(ec)) {
pr_cont("during system linefill.\n");
return true;
}
- return f10h_dc_mce(ec);
+ return f10h_dc_mce(ec, xec);
}
-static bool f14h_dc_mce(u16 ec)
+static bool f14h_dc_mce(u16 ec, u8 xec)
{
- u8 r4 = (ec >> 4) & 0xf;
- u8 ll = ec & 0x3;
- u8 tt = (ec >> 2) & 0x3;
- u8 ii = tt;
+ u8 r4 = R4(ec);
bool ret = true;
if (MEM_ERROR(ec)) {
- if (tt != TT_DATA || ll != LL_L1)
+ if (TT(ec) != TT_DATA || LL(ec) != LL_L1)
return false;
switch (r4) {
@@ -144,7 +192,7 @@ static bool f14h_dc_mce(u16 ec)
}
} else if (BUS_ERROR(ec)) {
- if ((ii != II_MEM && ii != II_IO) || ll != LL_LG)
+ if ((II(ec) != II_MEM && II(ec) != II_IO) || LL(ec) != LL_LG)
return false;
pr_cont("System read data error on a ");
@@ -169,39 +217,78 @@ static bool f14h_dc_mce(u16 ec)
return ret;
}
+static bool f15h_dc_mce(u16 ec, u8 xec)
+{
+ bool ret = true;
+
+ if (MEM_ERROR(ec)) {
+
+ switch (xec) {
+ case 0x0:
+ pr_cont("Data Array access error.\n");
+ break;
+
+ case 0x1:
+ pr_cont("UC error during a linefill from L2/NB.\n");
+ break;
+
+ case 0x2:
+ case 0x11:
+ pr_cont("STQ access error.\n");
+ break;
+
+ case 0x3:
+ pr_cont("SCB access error.\n");
+ break;
+
+ case 0x10:
+ pr_cont("Tag error.\n");
+ break;
+
+ case 0x12:
+ pr_cont("LDQ access error.\n");
+ break;
+
+ default:
+ ret = false;
+ }
+ } else if (BUS_ERROR(ec)) {
+
+ if (!xec)
+ pr_cont("during system linefill.\n");
+ else
+ pr_cont(" Internal %s condition.\n",
+ ((xec == 1) ? "livelock" : "deadlock"));
+ } else
+ ret = false;
+
+ return ret;
+}
+
static void amd_decode_dc_mce(struct mce *m)
{
- u16 ec = m->status & 0xffff;
- u8 xec = (m->status >> 16) & 0xf;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
pr_emerg(HW_ERR "Data Cache Error: ");
/* TLB error signatures are the same across families */
if (TLB_ERROR(ec)) {
- u8 tt = (ec >> 2) & 0x3;
-
- if (tt == TT_DATA) {
+ if (TT(ec) == TT_DATA) {
pr_cont("%s TLB %s.\n", LL_MSG(ec),
- (xec ? "multimatch" : "parity error"));
+ ((xec == 2) ? "locked miss"
+ : (xec ? "multimatch" : "parity")));
return;
}
- else
- goto wrong_dc_mce;
- }
-
- if (!fam_ops->dc_mce(ec))
- goto wrong_dc_mce;
-
- return;
-
-wrong_dc_mce:
- pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
+ } else if (fam_ops->dc_mce(ec, xec))
+ ;
+ else
+ pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
}
-static bool k8_ic_mce(u16 ec)
+static bool k8_ic_mce(u16 ec, u8 xec)
{
- u8 ll = ec & 0x3;
- u8 r4 = (ec >> 4) & 0xf;
+ u8 ll = LL(ec);
bool ret = true;
if (!MEM_ERROR(ec))
@@ -210,7 +297,7 @@ static bool k8_ic_mce(u16 ec)
if (ll == 0x2)
pr_cont("during a linefill from L2.\n");
else if (ll == 0x1) {
- switch (r4) {
+ switch (R4(ec)) {
case R4_IRD:
pr_cont("Parity error during data load.\n");
break;
@@ -233,15 +320,13 @@ static bool k8_ic_mce(u16 ec)
return ret;
}
-static bool f14h_ic_mce(u16 ec)
+static bool f14h_ic_mce(u16 ec, u8 xec)
{
- u8 ll = ec & 0x3;
- u8 tt = (ec >> 2) & 0x3;
- u8 r4 = (ec >> 4) & 0xf;
+ u8 r4 = R4(ec);
bool ret = true;
if (MEM_ERROR(ec)) {
- if (tt != 0 || ll != 1)
+ if (TT(ec) != 0 || LL(ec) != 1)
ret = false;
if (r4 == R4_IRD)
@@ -254,10 +339,36 @@ static bool f14h_ic_mce(u16 ec)
return ret;
}
+static bool f15h_ic_mce(u16 ec, u8 xec)
+{
+ bool ret = true;
+
+ if (!MEM_ERROR(ec))
+ return false;
+
+ switch (xec) {
+ case 0x0 ... 0xa:
+ pr_cont("%s.\n", f15h_ic_mce_desc[xec]);
+ break;
+
+ case 0xd:
+ pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]);
+ break;
+
+ case 0x10 ... 0x14:
+ pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]);
+ break;
+
+ default:
+ ret = false;
+ }
+ return ret;
+}
+
static void amd_decode_ic_mce(struct mce *m)
{
- u16 ec = m->status & 0xffff;
- u8 xec = (m->status >> 16) & 0xf;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
pr_emerg(HW_ERR "Instruction Cache Error: ");
@@ -268,7 +379,7 @@ static void amd_decode_ic_mce(struct mce *m)
bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
- } else if (fam_ops->ic_mce(ec))
+ } else if (fam_ops->ic_mce(ec, xec))
;
else
pr_emerg(HW_ERR "Corrupted IC MCE info?\n");
@@ -276,8 +387,8 @@ static void amd_decode_ic_mce(struct mce *m)
static void amd_decode_bu_mce(struct mce *m)
{
- u32 ec = m->status & 0xffff;
- u32 xec = (m->status >> 16) & 0xf;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
pr_emerg(HW_ERR "Bus Unit Error");
@@ -286,23 +397,23 @@ static void amd_decode_bu_mce(struct mce *m)
else if (xec == 0x3)
pr_cont(" in the victim data buffers.\n");
else if (xec == 0x2 && MEM_ERROR(ec))
- pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
+ pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec));
else if (xec == 0x0) {
if (TLB_ERROR(ec))
pr_cont(": %s error in a Page Descriptor Cache or "
"Guest TLB.\n", TT_MSG(ec));
else if (BUS_ERROR(ec))
pr_cont(": %s/ECC error in data read from NB: %s.\n",
- RRRR_MSG(ec), PP_MSG(ec));
+ R4_MSG(ec), PP_MSG(ec));
else if (MEM_ERROR(ec)) {
- u8 rrrr = (ec >> 4) & 0xf;
+ u8 r4 = R4(ec);
- if (rrrr >= 0x7)
+ if (r4 >= 0x7)
pr_cont(": %s error during data copyback.\n",
- RRRR_MSG(ec));
- else if (rrrr <= 0x1)
+ R4_MSG(ec));
+ else if (r4 <= 0x1)
pr_cont(": %s parity/ECC error during data "
- "access from L2.\n", RRRR_MSG(ec));
+ "access from L2.\n", R4_MSG(ec));
else
goto wrong_bu_mce;
} else
@@ -316,12 +427,52 @@ wrong_bu_mce:
pr_emerg(HW_ERR "Corrupted BU MCE info?\n");
}
+static void amd_decode_cu_mce(struct mce *m)
+{
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
+
+ pr_emerg(HW_ERR "Combined Unit Error: ");
+
+ if (TLB_ERROR(ec)) {
+ if (xec == 0x0)
+ pr_cont("Data parity TLB read error.\n");
+ else if (xec == 0x1)
+ pr_cont("Poison data provided for TLB fill.\n");
+ else
+ goto wrong_cu_mce;
+ } else if (BUS_ERROR(ec)) {
+ if (xec > 2)
+ goto wrong_cu_mce;
+
+ pr_cont("Error during attempted NB data read.\n");
+ } else if (MEM_ERROR(ec)) {
+ switch (xec) {
+ case 0x4 ... 0xc:
+ pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x4]);
+ break;
+
+ case 0x10 ... 0x14:
+ pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x7]);
+ break;
+
+ default:
+ goto wrong_cu_mce;
+ }
+ }
+
+ return;
+
+wrong_cu_mce:
+ pr_emerg(HW_ERR "Corrupted CU MCE info?\n");
+}
+
static void amd_decode_ls_mce(struct mce *m)
{
- u16 ec = m->status & 0xffff;
- u8 xec = (m->status >> 16) & 0xf;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
- if (boot_cpu_data.x86 == 0x14) {
+ if (boot_cpu_data.x86 >= 0x14) {
pr_emerg("You shouldn't be seeing an LS MCE on this cpu family,"
" please report on LKML.\n");
return;
@@ -330,12 +481,12 @@ static void amd_decode_ls_mce(struct mce *m)
pr_emerg(HW_ERR "Load Store Error");
if (xec == 0x0) {
- u8 r4 = (ec >> 4) & 0xf;
+ u8 r4 = R4(ec);
if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
goto wrong_ls_mce;
- pr_cont(" during %s.\n", RRRR_MSG(ec));
+ pr_cont(" during %s.\n", R4_MSG(ec));
} else
goto wrong_ls_mce;
@@ -410,6 +561,15 @@ static bool f10h_nb_mce(u16 ec, u8 xec)
goto out;
break;
+ case 0x19:
+ if (boot_cpu_data.x86 == 0x15)
+ pr_cont("Compute Unit Data Error.\n");
+ else
+ ret = false;
+
+ goto out;
+ break;
+
case 0x1c ... 0x1f:
offset = 24;
break;
@@ -434,27 +594,30 @@ static bool nb_noop_mce(u16 ec, u8 xec)
void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
{
- u8 xec = (m->status >> 16) & 0x1f;
- u16 ec = m->status & 0xffff;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, 0x1f);
u32 nbsh = (u32)(m->status >> 32);
+ int core = -1;
- pr_emerg(HW_ERR "Northbridge Error, node %d: ", node_id);
+ pr_emerg(HW_ERR "Northbridge Error (node %d", node_id);
- /*
- * F10h, revD can disable ErrCpu[3:0] so check that first and also the
- * value encoding has changed so interpret those differently
- */
+ /* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */
if ((boot_cpu_data.x86 == 0x10) &&
(boot_cpu_data.x86_model > 7)) {
if (nbsh & K8_NBSH_ERR_CPU_VAL)
- pr_cont(", core: %u", (u8)(nbsh & nb_err_cpumask));
+ core = nbsh & nb_err_cpumask;
} else {
u8 assoc_cpus = nbsh & nb_err_cpumask;
if (assoc_cpus > 0)
- pr_cont(", core: %d", fls(assoc_cpus) - 1);
+ core = fls(assoc_cpus) - 1;
}
+ if (core >= 0)
+ pr_cont(", core %d): ", core);
+ else
+ pr_cont("): ");
+
switch (xec) {
case 0x2:
pr_cont("Sync error (sync packets on HT link detected).\n");
@@ -496,35 +659,89 @@ EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
static void amd_decode_fr_mce(struct mce *m)
{
- if (boot_cpu_data.x86 == 0xf ||
- boot_cpu_data.x86 == 0x11)
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ u8 xec = XEC(m->status, xec_mask);
+
+ if (c->x86 == 0xf || c->x86 == 0x11)
goto wrong_fr_mce;
- /* we have only one error signature so match all fields at once. */
- if ((m->status & 0xffff) == 0x0f0f) {
- pr_emerg(HW_ERR "FR Error: CPU Watchdog timer expire.\n");
- return;
- }
+ if (c->x86 != 0x15 && xec != 0x0)
+ goto wrong_fr_mce;
+
+ pr_emerg(HW_ERR "%s Error: ",
+ (c->x86 == 0x15 ? "Execution Unit" : "FIROB"));
+
+ if (xec == 0x0 || xec == 0xc)
+ pr_cont("%s.\n", fr_ex_mce_desc[xec]);
+ else if (xec < 0xd)
+ pr_cont("%s parity error.\n", fr_ex_mce_desc[xec]);
+ else
+ goto wrong_fr_mce;
+
+ return;
wrong_fr_mce:
pr_emerg(HW_ERR "Corrupted FR MCE info?\n");
}
+static void amd_decode_fp_mce(struct mce *m)
+{
+ u8 xec = XEC(m->status, xec_mask);
+
+ pr_emerg(HW_ERR "Floating Point Unit Error: ");
+
+ switch (xec) {
+ case 0x1:
+ pr_cont("Free List");
+ break;
+
+ case 0x2:
+ pr_cont("Physical Register File");
+ break;
+
+ case 0x3:
+ pr_cont("Retire Queue");
+ break;
+
+ case 0x4:
+ pr_cont("Scheduler table");
+ break;
+
+ case 0x5:
+ pr_cont("Status Register File");
+ break;
+
+ default:
+ goto wrong_fp_mce;
+ break;
+ }
+
+ pr_cont(" parity error.\n");
+
+ return;
+
+wrong_fp_mce:
+ pr_emerg(HW_ERR "Corrupted FP MCE info?\n");
+}
+
static inline void amd_decode_err_code(u16 ec)
{
- if (TLB_ERROR(ec)) {
- pr_emerg(HW_ERR "Transaction: %s, Cache Level: %s\n",
- TT_MSG(ec), LL_MSG(ec));
- } else if (MEM_ERROR(ec)) {
- pr_emerg(HW_ERR "Transaction: %s, Type: %s, Cache Level: %s\n",
- RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
- } else if (BUS_ERROR(ec)) {
- pr_emerg(HW_ERR "Transaction: %s (%s), %s, Cache Level: %s, "
- "Participating Processor: %s\n",
- RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
- PP_MSG(ec));
- } else
- pr_emerg(HW_ERR "Huh? Unknown MCE error 0x%x\n", ec);
+
+ pr_emerg(HW_ERR "cache level: %s", LL_MSG(ec));
+
+ if (BUS_ERROR(ec))
+ pr_cont(", mem/io: %s", II_MSG(ec));
+ else
+ pr_cont(", tx: %s", TT_MSG(ec));
+
+ if (MEM_ERROR(ec) || BUS_ERROR(ec)) {
+ pr_cont(", mem-tx: %s", R4_MSG(ec));
+
+ if (BUS_ERROR(ec))
+ pr_cont(", part-proc: %s (%s)", PP_MSG(ec), TO_MSG(ec));
+ }
+
+ pr_cont("\n");
}
/*
@@ -546,25 +763,32 @@ static bool amd_filter_mce(struct mce *m)
int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
{
struct mce *m = (struct mce *)data;
+ struct cpuinfo_x86 *c = &boot_cpu_data;
int node, ecc;
if (amd_filter_mce(m))
return NOTIFY_STOP;
- pr_emerg(HW_ERR "MC%d_STATUS: ", m->bank);
+ pr_emerg(HW_ERR "MC%d_STATUS[%s|%s|%s|%s|%s",
+ m->bank,
+ ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
+ ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
+ ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
+ ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
+ ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
- pr_cont("%sorrected error, other errors lost: %s, "
- "CPU context corrupt: %s",
- ((m->status & MCI_STATUS_UC) ? "Unc" : "C"),
- ((m->status & MCI_STATUS_OVER) ? "yes" : "no"),
- ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
+ if (c->x86 == 0x15)
+ pr_cont("|%s|%s",
+ ((m->status & BIT_64(44)) ? "Deferred" : "-"),
+ ((m->status & BIT_64(43)) ? "Poison" : "-"));
/* do the two bits[14:13] together */
ecc = (m->status >> 45) & 0x3;
if (ecc)
- pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
+ pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
+
+ pr_cont("]: 0x%016llx\n", m->status);
- pr_cont("\n");
switch (m->bank) {
case 0:
@@ -576,7 +800,10 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
break;
case 2:
- amd_decode_bu_mce(m);
+ if (c->x86 == 0x15)
+ amd_decode_cu_mce(m);
+ else
+ amd_decode_bu_mce(m);
break;
case 3:
@@ -592,6 +819,10 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
amd_decode_fr_mce(m);
break;
+ case 6:
+ amd_decode_fp_mce(m);
+ break;
+
default:
break;
}
@@ -608,18 +839,21 @@ static struct notifier_block amd_mce_dec_nb = {
static int __init mce_amd_init(void)
{
- if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ if (c->x86_vendor != X86_VENDOR_AMD)
return 0;
- if ((boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x12) &&
- (boot_cpu_data.x86 != 0x14 || boot_cpu_data.x86_model > 0xf))
+ if ((c->x86 < 0xf || c->x86 > 0x12) &&
+ (c->x86 != 0x14 || c->x86_model > 0xf) &&
+ (c->x86 != 0x15 || c->x86_model > 0xf))
return 0;
fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
if (!fam_ops)
return -ENOMEM;
- switch (boot_cpu_data.x86) {
+ switch (c->x86) {
case 0xf:
fam_ops->dc_mce = k8_dc_mce;
fam_ops->ic_mce = k8_ic_mce;
@@ -651,9 +885,15 @@ static int __init mce_amd_init(void)
fam_ops->nb_mce = nb_noop_mce;
break;
+ case 0x15:
+ xec_mask = 0x1f;
+ fam_ops->dc_mce = f15h_dc_mce;
+ fam_ops->ic_mce = f15h_ic_mce;
+ fam_ops->nb_mce = f10h_nb_mce;
+ break;
+
default:
- printk(KERN_WARNING "Huh? What family is that: %d?!\n",
- boot_cpu_data.x86);
+ printk(KERN_WARNING "Huh? What family is that: %d?!\n", c->x86);
kfree(fam_ops);
return -EINVAL;
}
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 35f6e0e3b297..45dda47173f2 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -7,8 +7,8 @@
#define BIT_64(n) (U64_C(1) << (n))
-#define ERROR_CODE(x) ((x) & 0xffff)
-#define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f)
+#define EC(x) ((x) & 0xffff)
+#define XEC(x, mask) (((x) >> 16) & mask)
#define LOW_SYNDROME(x) (((x) >> 15) & 0xff)
#define HIGH_SYNDROME(x) (((x) >> 24) & 0xff)
@@ -21,15 +21,15 @@
#define TT_MSG(x) tt_msgs[TT(x)]
#define II(x) (((x) >> 2) & 0x3)
#define II_MSG(x) ii_msgs[II(x)]
-#define LL(x) (((x) >> 0) & 0x3)
+#define LL(x) ((x) & 0x3)
#define LL_MSG(x) ll_msgs[LL(x)]
#define TO(x) (((x) >> 8) & 0x1)
#define TO_MSG(x) to_msgs[TO(x)]
#define PP(x) (((x) >> 9) & 0x3)
#define PP_MSG(x) pp_msgs[PP(x)]
-#define RRRR(x) (((x) >> 4) & 0xf)
-#define RRRR_MSG(x) ((RRRR(x) < 9) ? rrrr_msgs[RRRR(x)] : "Wrong R4!")
+#define R4(x) (((x) >> 4) & 0xf)
+#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!")
#define K8_NBSH 0x4C
@@ -100,8 +100,8 @@ struct err_regs {
* per-family decoder ops
*/
struct amd_decoder_ops {
- bool (*dc_mce)(u16);
- bool (*ic_mce)(u16);
+ bool (*dc_mce)(u16, u8);
+ bool (*ic_mce)(u16, u8);
bool (*nb_mce)(u16, u8);
};
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 8d0688f36d4c..733a7e7a8d6f 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -88,10 +88,11 @@ static ssize_t edac_inject_bank_store(struct kobject *kobj,
return -EINVAL;
}
- if (value > 5) {
- printk(KERN_ERR "Non-existant MCE bank: %lu\n", value);
- return -EINVAL;
- }
+ if (value > 5)
+ if (boot_cpu_data.x86 != 0x15 || value > 6) {
+ printk(KERN_ERR "Non-existant MCE bank: %lu\n", value);
+ return -EINVAL;
+ }
i_mce.bank = value;
@@ -139,7 +140,7 @@ static int __init edac_init_mce_inject(void)
return 0;
err_sysfs_create:
- while (i-- >= 0)
+ while (--i >= 0)
sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
kobject_del(mce_kobj);
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 070cea41b661..b9f0c20df1aa 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -873,7 +873,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1)
}
/**
- * ppc4xx_edac_init_csrows - intialize driver instance rows
+ * ppc4xx_edac_init_csrows - initialize driver instance rows
* @mci: A pointer to the EDAC memory controller instance
* associated with the ibm,sdram-4xx-ddr2 controller for which
* the csrows (i.e. banks/ranks) are being initialized.
@@ -881,7 +881,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1)
* currently set for the controller, from which bank width
* and memory typ information is derived.
*
- * This routine intializes the virtual "chip select rows" associated
+ * This routine initializes the virtual "chip select rows" associated
* with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2
* controller bank/rank is mapped to a row.
*
@@ -992,7 +992,7 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
}
/**
- * ppc4xx_edac_mc_init - intialize driver instance
+ * ppc4xx_edac_mc_init - initialize driver instance
* @mci: A pointer to the EDAC memory controller instance being
* initialized.
* @op: A pointer to the OpenFirmware device tree node associated
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 40a222e19b2d..68f942cb30f2 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -19,7 +19,7 @@ config FIREWIRE
config FIREWIRE_OHCI
tristate "OHCI-1394 controllers"
- depends on PCI && FIREWIRE
+ depends on PCI && FIREWIRE && MMU
help
Enable this driver if you have a FireWire controller based
on the OHCI specification. For all practical purposes, this
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 14bb7b7b5dd7..48ae712e2101 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -1501,9 +1501,10 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
e->client = client;
e->p.speed = SCODE_100;
e->p.generation = a->generation;
- e->p.header[0] = a->data[0];
- e->p.header[1] = a->data[1];
- e->p.header_length = 8;
+ e->p.header[0] = TCODE_LINK_INTERNAL << 4;
+ e->p.header[1] = a->data[0];
+ e->p.header[2] = a->data[1];
+ e->p.header_length = 12;
e->p.callback = outbound_phy_packet_callback;
e->phy_packet.closure = a->closure;
e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT;
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index b42a0bde8494..d00f8ce902cc 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -72,6 +72,15 @@
#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
#define PHY_IDENTIFIER(id) ((id) << 30)
+/* returns 0 if the split timeout handler is already running */
+static int try_cancel_split_timeout(struct fw_transaction *t)
+{
+ if (t->is_split_transaction)
+ return del_timer(&t->split_timeout_timer);
+ else
+ return 1;
+}
+
static int close_transaction(struct fw_transaction *transaction,
struct fw_card *card, int rcode)
{
@@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction,
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) {
if (t == transaction) {
- if (!del_timer(&t->split_timeout_timer)) {
+ if (!try_cancel_split_timeout(t)) {
spin_unlock_irqrestore(&card->lock, flags);
goto timed_out;
}
@@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data)
card->tlabel_mask &= ~(1ULL << t->tlabel);
spin_unlock_irqrestore(&card->lock, flags);
- card->driver->cancel_packet(card, &t->packet);
-
- /*
- * At this point cancel_packet will never call the transaction
- * callback, since we just took the transaction out of the list.
- * So do it here.
- */
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
}
+static void start_split_transaction_timeout(struct fw_transaction *t,
+ struct fw_card *card)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
+ spin_unlock_irqrestore(&card->lock, flags);
+ return;
+ }
+
+ t->is_split_transaction = true;
+ mod_timer(&t->split_timeout_timer,
+ jiffies + card->split_timeout_jiffies);
+
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
static void transmit_complete_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
@@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
close_transaction(t, card, RCODE_COMPLETE);
break;
case ACK_PENDING:
- t->timestamp = packet->timestamp;
+ start_split_transaction_timeout(t, card);
break;
case ACK_BUSY_X:
case ACK_BUSY_A:
@@ -250,7 +271,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
break;
default:
- WARN(1, "wrong tcode %d", tcode);
+ WARN(1, "wrong tcode %d\n", tcode);
}
common:
packet->speed = speed;
@@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
t->node_id = destination_id;
t->tlabel = tlabel;
t->card = card;
+ t->is_split_transaction = false;
setup_timer(&t->split_timeout_timer,
split_transaction_timeout_callback, (unsigned long)t);
- /* FIXME: start this timer later, relative to t->timestamp */
- mod_timer(&t->split_timeout_timer,
- jiffies + card->split_timeout_jiffies);
t->callback = callback;
t->callback_data = callback_data;
@@ -423,7 +442,8 @@ static void transmit_phy_packet_callback(struct fw_packet *packet,
}
static struct fw_packet phy_config_packet = {
- .header_length = 8,
+ .header_length = 12,
+ .header[0] = TCODE_LINK_INTERNAL << 4,
.payload_length = 0,
.speed = SCODE_100,
.callback = transmit_phy_packet_callback,
@@ -451,8 +471,8 @@ void fw_send_phy_config(struct fw_card *card,
mutex_lock(&phy_config_mutex);
- phy_config_packet.header[0] = data;
- phy_config_packet.header[1] = ~data;
+ phy_config_packet.header[1] = data;
+ phy_config_packet.header[2] = ~data;
phy_config_packet.generation = generation;
INIT_COMPLETION(phy_config_done);
@@ -638,7 +658,7 @@ int fw_get_response_length(struct fw_request *r)
}
default:
- WARN(1, "wrong tcode %d", tcode);
+ WARN(1, "wrong tcode %d\n", tcode);
return 0;
}
}
@@ -694,7 +714,7 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
break;
default:
- WARN(1, "wrong tcode %d", tcode);
+ WARN(1, "wrong tcode %d\n", tcode);
}
response->payload_mapped = false;
@@ -925,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) {
if (t->node_id == source && t->tlabel == tlabel) {
- if (!del_timer(&t->split_timeout_timer)) {
+ if (!try_cancel_split_timeout(t)) {
spin_unlock_irqrestore(&card->lock, flags);
goto timed_out;
}
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index e6239f971be6..f8dfcf1c6cbe 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -215,9 +215,11 @@ static inline bool is_next_generation(int new_generation, int old_generation)
/* -transaction */
+#define TCODE_LINK_INTERNAL 0xe
+
#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
-#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe)
+#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == TCODE_LINK_INTERNAL)
#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 18fdd9703b48..c2e194c58667 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -7,7 +7,9 @@
*/
#include <linux/bug.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/ethtool.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/highmem.h>
@@ -26,8 +28,14 @@
#include <asm/unaligned.h>
#include <net/arp.h>
-#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */
-#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2)
+/* rx limits */
+#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */
+#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2)
+
+/* tx limits */
+#define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */
+#define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */
+#define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */
#define IEEE1394_BROADCAST_CHANNEL 31
#define IEEE1394_ALL_NODES (0xffc0 | 0x003f)
@@ -169,16 +177,10 @@ struct fwnet_device {
struct fw_address_handler handler;
u64 local_fifo;
- /* List of packets to be sent */
- struct list_head packet_list;
- /*
- * List of packets that were broadcasted. When we get an ISO interrupt
- * one of them has been sent
- */
- struct list_head broadcasted_list;
- /* List of packets that have been sent but not yet acked */
- struct list_head sent_list;
+ /* Number of tx datagrams that have been queued but not yet acked */
+ int queued_datagrams;
+ int peer_count;
struct list_head peer_list;
struct fw_card *card;
struct net_device *netdev;
@@ -195,7 +197,7 @@ struct fwnet_peer {
unsigned pdg_size; /* pd_list size */
u16 datagram_label; /* outgoing datagram label */
- unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */
+ u16 max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */
int node_id;
int generation;
unsigned speed;
@@ -203,22 +205,18 @@ struct fwnet_peer {
/* This is our task struct. It's used for the packet complete callback. */
struct fwnet_packet_task {
- /*
- * ptask can actually be on dev->packet_list, dev->broadcasted_list,
- * or dev->sent_list depending on its current state.
- */
- struct list_head pt_link;
struct fw_transaction transaction;
struct rfc2734_header hdr;
struct sk_buff *skb;
struct fwnet_device *dev;
int outstanding_pkts;
- unsigned max_payload;
u64 fifo_addr;
u16 dest_node;
+ u16 max_payload;
u8 generation;
u8 speed;
+ u8 enqueued;
};
/*
@@ -650,8 +648,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
net->stats.rx_packets++;
net->stats.rx_bytes += skb->len;
}
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
return 0;
@@ -660,8 +656,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
net->stats.rx_dropped++;
dev_kfree_skb_any(skb);
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
return -ENOENT;
}
@@ -793,15 +787,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
* Datagram is not complete, we're done for the
* moment.
*/
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
+ retval = 0;
fail:
spin_unlock_irqrestore(&dev->lock, flags);
- if (netif_queue_stopped(net))
- netif_wake_queue(net);
-
return retval;
}
@@ -901,11 +890,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask)
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
+/* Caller must hold dev->lock. */
+static void dec_queued_datagrams(struct fwnet_device *dev)
+{
+ if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS)
+ netif_wake_queue(dev->netdev);
+}
+
static int fwnet_send_packet(struct fwnet_packet_task *ptask);
static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
{
struct fwnet_device *dev = ptask->dev;
+ struct sk_buff *skb = ptask->skb;
unsigned long flags;
bool free;
@@ -914,10 +911,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
ptask->outstanding_pkts--;
/* Check whether we or the networking TX soft-IRQ is last user. */
- free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && ptask->enqueued);
+ if (free)
+ dec_queued_datagrams(dev);
- if (ptask->outstanding_pkts == 0)
- list_del(&ptask->pt_link);
+ if (ptask->outstanding_pkts == 0) {
+ dev->netdev->stats.tx_packets++;
+ dev->netdev->stats.tx_bytes += skb->len;
+ }
spin_unlock_irqrestore(&dev->lock, flags);
@@ -926,7 +927,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
u16 fg_off;
u16 datagram_label;
u16 lf;
- struct sk_buff *skb;
/* Update the ptask to point to the next fragment and send it */
lf = fwnet_get_hdr_lf(&ptask->hdr);
@@ -953,7 +953,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
break;
}
- skb = ptask->skb;
+
skb_pull(skb, ptask->max_payload);
if (ptask->outstanding_pkts > 1) {
fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
@@ -970,18 +970,52 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
fwnet_free_ptask(ptask);
}
+static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
+{
+ struct fwnet_device *dev = ptask->dev;
+ unsigned long flags;
+ bool free;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* One fragment failed; don't try to send remaining fragments. */
+ ptask->outstanding_pkts = 0;
+
+ /* Check whether we or the networking TX soft-IRQ is last user. */
+ free = ptask->enqueued;
+ if (free)
+ dec_queued_datagrams(dev);
+
+ dev->netdev->stats.tx_dropped++;
+ dev->netdev->stats.tx_errors++;
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (free)
+ fwnet_free_ptask(ptask);
+}
+
static void fwnet_write_complete(struct fw_card *card, int rcode,
void *payload, size_t length, void *data)
{
- struct fwnet_packet_task *ptask;
-
- ptask = data;
+ struct fwnet_packet_task *ptask = data;
+ static unsigned long j;
+ static int last_rcode, errors_skipped;
- if (rcode == RCODE_COMPLETE)
+ if (rcode == RCODE_COMPLETE) {
fwnet_transmit_packet_done(ptask);
- else
- fw_error("fwnet_write_complete: failed: %x\n", rcode);
- /* ??? error recovery */
+ } else {
+ fwnet_transmit_packet_failed(ptask);
+
+ if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) {
+ fw_error("fwnet_write_complete: "
+ "failed: %x (skipped %d)\n", rcode, errors_skipped);
+
+ errors_skipped = 0;
+ last_rcode = rcode;
+ } else
+ errors_skipped++;
+ }
}
static int fwnet_send_packet(struct fwnet_packet_task *ptask)
@@ -1039,9 +1073,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */
- free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
if (!free)
- list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
+ ptask->enqueued = true;
+ else
+ dec_queued_datagrams(dev);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1056,9 +1092,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
spin_lock_irqsave(&dev->lock, flags);
/* If the AT tasklet already ran, we may be last user. */
- free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
if (!free)
- list_add_tail(&ptask->pt_link, &dev->sent_list);
+ ptask->enqueued = true;
+ else
+ dec_queued_datagrams(dev);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1185,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
return retval;
}
+static void set_carrier_state(struct fwnet_device *dev)
+{
+ if (dev->peer_count > 1)
+ netif_carrier_on(dev->netdev);
+ else
+ netif_carrier_off(dev->netdev);
+}
+
/* ifup */
static int fwnet_open(struct net_device *net)
{
@@ -1198,6 +1244,10 @@ static int fwnet_open(struct net_device *net)
}
netif_start_queue(net);
+ spin_lock_irq(&dev->lock);
+ set_carrier_state(dev);
+ spin_unlock_irq(&dev->lock);
+
return 0;
}
@@ -1224,6 +1274,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
struct fwnet_peer *peer;
unsigned long flags;
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Can this happen? */
+ if (netif_queue_stopped(dev->netdev)) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return NETDEV_TX_BUSY;
+ }
+
ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
if (ptask == NULL)
goto fail;
@@ -1242,9 +1301,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
proto = hdr_buf.h_proto;
dg_size = skb->len;
- /* serialize access to peer, including peer->datagram_label */
- spin_lock_irqsave(&dev->lock, flags);
-
/*
* Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP.
@@ -1266,7 +1322,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
- goto fail_unlock;
+ goto fail;
generation = peer->generation;
dest_node = peer->node_id;
@@ -1320,18 +1376,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
max_payload += RFC2374_FRAG_HDR_SIZE;
}
+ if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS)
+ netif_stop_queue(dev->netdev);
+
spin_unlock_irqrestore(&dev->lock, flags);
ptask->max_payload = max_payload;
- INIT_LIST_HEAD(&ptask->pt_link);
+ ptask->enqueued = 0;
fwnet_send_packet(ptask);
return NETDEV_TX_OK;
- fail_unlock:
- spin_unlock_irqrestore(&dev->lock, flags);
fail:
+ spin_unlock_irqrestore(&dev->lock, flags);
+
if (ptask)
kmem_cache_free(fwnet_packet_task_cache, ptask);
@@ -1360,6 +1419,10 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)
return 0;
}
+static const struct ethtool_ops fwnet_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+};
+
static const struct net_device_ops fwnet_netdev_ops = {
.ndo_open = fwnet_open,
.ndo_stop = fwnet_stop,
@@ -1377,7 +1440,8 @@ static void fwnet_init_dev(struct net_device *net)
net->addr_len = FWNET_ALEN;
net->hard_header_len = FWNET_HLEN;
net->type = ARPHRD_IEEE1394;
- net->tx_queue_len = 10;
+ net->tx_queue_len = FWNET_TX_QUEUE_LEN;
+ net->ethtool_ops = &fwnet_ethtool_ops;
}
/* caller must hold fwnet_device_mutex */
@@ -1418,6 +1482,8 @@ static int fwnet_add_peer(struct fwnet_device *dev,
spin_lock_irq(&dev->lock);
list_add_tail(&peer->peer_link, &dev->peer_list);
+ dev->peer_count++;
+ set_carrier_state(dev);
spin_unlock_irq(&dev->lock);
return 0;
@@ -1457,14 +1523,9 @@ static int fwnet_probe(struct device *_dev)
dev->broadcast_rcv_context = NULL;
dev->broadcast_xmt_max_payload = 0;
dev->broadcast_xmt_datagramlabel = 0;
-
dev->local_fifo = FWNET_NO_FIFO_ADDR;
-
- INIT_LIST_HEAD(&dev->packet_list);
- INIT_LIST_HEAD(&dev->broadcasted_list);
- INIT_LIST_HEAD(&dev->sent_list);
+ dev->queued_datagrams = 0;
INIT_LIST_HEAD(&dev->peer_list);
-
dev->card = card;
dev->netdev = net;
@@ -1503,13 +1564,15 @@ static int fwnet_probe(struct device *_dev)
return ret;
}
-static void fwnet_remove_peer(struct fwnet_peer *peer)
+static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
{
struct fwnet_partial_datagram *pd, *pd_next;
- spin_lock_irq(&peer->dev->lock);
+ spin_lock_irq(&dev->lock);
list_del(&peer->peer_link);
- spin_unlock_irq(&peer->dev->lock);
+ dev->peer_count--;
+ set_carrier_state(dev);
+ spin_unlock_irq(&dev->lock);
list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
fwnet_pd_delete(pd);
@@ -1522,11 +1585,11 @@ static int fwnet_remove(struct device *_dev)
struct fwnet_peer *peer = dev_get_drvdata(_dev);
struct fwnet_device *dev = peer->dev;
struct net_device *net;
- struct fwnet_packet_task *ptask, *pt_next;
+ int i;
mutex_lock(&fwnet_device_mutex);
- fwnet_remove_peer(peer);
+ fwnet_remove_peer(peer, dev);
if (list_empty(&dev->peer_list)) {
net = dev->netdev;
@@ -1540,21 +1603,9 @@ static int fwnet_remove(struct device *_dev)
dev->card);
fw_iso_context_destroy(dev->broadcast_rcv_context);
}
- list_for_each_entry_safe(ptask, pt_next,
- &dev->packet_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
- list_for_each_entry_safe(ptask, pt_next,
- &dev->broadcasted_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
- list_for_each_entry_safe(ptask, pt_next,
- &dev->sent_list, pt_link) {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
- }
+ for (i = 0; dev->queued_datagrams && i < 5; i++)
+ ssleep(1);
+ WARN_ON(dev->queued_datagrams);
list_del(&dev->dev_link);
free_netdev(net);
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
index bf184fb59a5e..0618145376ad 100644
--- a/drivers/firewire/nosy.c
+++ b/drivers/firewire/nosy.c
@@ -302,7 +302,7 @@ nosy_open(struct inode *inode, struct file *file)
file->private_data = client;
- return 0;
+ return nonseekable_open(inode, file);
fail:
kfree(client);
lynx_put(lynx);
@@ -405,7 +405,6 @@ static const struct file_operations nosy_ops = {
.poll = nosy_poll,
.open = nosy_open,
.release = nosy_release,
- .llseek = noop_llseek,
};
#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 9dcb17d51aee..bd3c61b6dd8d 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -18,6 +18,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/delay.h>
@@ -40,6 +41,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/time.h>
+#include <linux/vmalloc.h>
#include <asm/byteorder.h>
#include <asm/page.h>
@@ -80,17 +82,23 @@ struct descriptor {
#define COMMAND_PTR(regs) ((regs) + 12)
#define CONTEXT_MATCH(regs) ((regs) + 16)
-struct ar_buffer {
- struct descriptor descriptor;
- struct ar_buffer *next;
- __le32 data[0];
-};
+#define AR_BUFFER_SIZE (32*1024)
+#define AR_BUFFERS_MIN DIV_ROUND_UP(AR_BUFFER_SIZE, PAGE_SIZE)
+/* we need at least two pages for proper list management */
+#define AR_BUFFERS (AR_BUFFERS_MIN >= 2 ? AR_BUFFERS_MIN : 2)
+
+#define MAX_ASYNC_PAYLOAD 4096
+#define MAX_AR_PACKET_SIZE (16 + MAX_ASYNC_PAYLOAD + 4)
+#define AR_WRAPAROUND_PAGES DIV_ROUND_UP(MAX_AR_PACKET_SIZE, PAGE_SIZE)
struct ar_context {
struct fw_ohci *ohci;
- struct ar_buffer *current_buffer;
- struct ar_buffer *last_buffer;
+ struct page *pages[AR_BUFFERS];
+ void *buffer;
+ struct descriptor *descriptors;
+ dma_addr_t descriptors_bus;
void *pointer;
+ unsigned int last_buffer_index;
u32 regs;
struct tasklet_struct tasklet;
};
@@ -117,6 +125,8 @@ struct context {
struct fw_ohci *ohci;
u32 regs;
int total_allocation;
+ bool running;
+ bool flushing;
/*
* List of page-sized buffers for storing DMA descriptors.
@@ -161,6 +171,9 @@ struct iso_context {
int excess_bytes;
void *header;
size_t header_length;
+
+ u8 sync;
+ u8 tags;
};
#define CONFIG_ROM_SIZE 1024
@@ -177,7 +190,8 @@ struct fw_ohci {
u32 bus_time;
bool is_root;
bool csr_state_setclear_abdicate;
-
+ int n_ir;
+ int n_it;
/*
* Spinlock for accessing fw_ohci data. Never call out of
* this driver with this lock held.
@@ -186,6 +200,9 @@ struct fw_ohci {
struct mutex phy_reg_mutex;
+ void *misc_buffer;
+ dma_addr_t misc_buffer_bus;
+
struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
struct context at_request_ctx;
@@ -242,6 +259,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define PCI_DEVICE_ID_AGERE_FW643 0x5901
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
@@ -253,18 +271,34 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
- unsigned short vendor, device, flags;
+ unsigned short vendor, device, revision, flags;
} ohci_quirks[] = {
- {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
- QUIRK_RESET_PACKET |
- QUIRK_NO_1394A},
- {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET},
- {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
- {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
- {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
+ {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID,
+ QUIRK_BE_HEADERS},
+
+ {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
+ QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER},
+
+ {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
+
+ {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_RESET_PACKET},
+
+ {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
};
/* This overrides anything that was found in ohci_quirks[]. */
@@ -394,10 +428,6 @@ static const char *tcodes[] = {
[0xc] = "-reserved-", [0xd] = "-reserved-",
[0xe] = "link internal", [0xf] = "-reserved-",
};
-static const char *phys[] = {
- [0x0] = "phy config packet", [0x1] = "link-on packet",
- [0x2] = "self-id packet", [0x3] = "-reserved-",
-};
static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
{
@@ -416,12 +446,6 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
return;
}
- if (header[0] == ~header[1]) {
- fw_notify("A%c %s, %s, %08x\n",
- dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
- return;
- }
-
switch (tcode) {
case 0x0: case 0x6: case 0x8:
snprintf(specific, sizeof(specific), " = %08x",
@@ -436,9 +460,13 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
}
switch (tcode) {
- case 0xe: case 0xa:
+ case 0xa:
fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
break;
+ case 0xe:
+ fw_notify("A%c %s, PHY %08x %08x\n",
+ dir, evts[evt], header[1], header[2]);
+ break;
case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
fw_notify("A%c spd %x tl %02x, "
"%04x -> %04x, %s, "
@@ -577,52 +605,150 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
return ret;
}
-static int ar_context_add_page(struct ar_context *ctx)
+static inline dma_addr_t ar_buffer_bus(struct ar_context *ctx, unsigned int i)
{
- struct device *dev = ctx->ohci->card.device;
- struct ar_buffer *ab;
- dma_addr_t uninitialized_var(ab_bus);
- size_t offset;
+ return page_private(ctx->pages[i]);
+}
- ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
- if (ab == NULL)
- return -ENOMEM;
+static void ar_context_link_page(struct ar_context *ctx, unsigned int index)
+{
+ struct descriptor *d;
- ab->next = NULL;
- memset(&ab->descriptor, 0, sizeof(ab->descriptor));
- ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
- DESCRIPTOR_STATUS |
- DESCRIPTOR_BRANCH_ALWAYS);
- offset = offsetof(struct ar_buffer, data);
- ab->descriptor.req_count = cpu_to_le16(PAGE_SIZE - offset);
- ab->descriptor.data_address = cpu_to_le32(ab_bus + offset);
- ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset);
- ab->descriptor.branch_address = 0;
+ d = &ctx->descriptors[index];
+ d->branch_address &= cpu_to_le32(~0xf);
+ d->res_count = cpu_to_le16(PAGE_SIZE);
+ d->transfer_status = 0;
wmb(); /* finish init of new descriptors before branch_address update */
- ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1);
- ctx->last_buffer->next = ab;
- ctx->last_buffer = ab;
+ d = &ctx->descriptors[ctx->last_buffer_index];
+ d->branch_address |= cpu_to_le32(1);
+
+ ctx->last_buffer_index = index;
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
flush_writes(ctx->ohci);
-
- return 0;
}
static void ar_context_release(struct ar_context *ctx)
{
- struct ar_buffer *ab, *ab_next;
- size_t offset;
- dma_addr_t ab_bus;
+ unsigned int i;
- for (ab = ctx->current_buffer; ab; ab = ab_next) {
- ab_next = ab->next;
- offset = offsetof(struct ar_buffer, data);
- ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
- dma_free_coherent(ctx->ohci->card.device, PAGE_SIZE,
- ab, ab_bus);
+ if (ctx->buffer)
+ vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES);
+
+ for (i = 0; i < AR_BUFFERS; i++)
+ if (ctx->pages[i]) {
+ dma_unmap_page(ctx->ohci->card.device,
+ ar_buffer_bus(ctx, i),
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ __free_page(ctx->pages[i]);
+ }
+}
+
+static void ar_context_abort(struct ar_context *ctx, const char *error_msg)
+{
+ if (reg_read(ctx->ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) {
+ reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+ flush_writes(ctx->ohci);
+
+ fw_error("AR error: %s; DMA stopped\n", error_msg);
}
+ /* FIXME: restart? */
+}
+
+static inline unsigned int ar_next_buffer_index(unsigned int index)
+{
+ return (index + 1) % AR_BUFFERS;
+}
+
+static inline unsigned int ar_prev_buffer_index(unsigned int index)
+{
+ return (index - 1 + AR_BUFFERS) % AR_BUFFERS;
+}
+
+static inline unsigned int ar_first_buffer_index(struct ar_context *ctx)
+{
+ return ar_next_buffer_index(ctx->last_buffer_index);
+}
+
+/*
+ * We search for the buffer that contains the last AR packet DMA data written
+ * by the controller.
+ */
+static unsigned int ar_search_last_active_buffer(struct ar_context *ctx,
+ unsigned int *buffer_offset)
+{
+ unsigned int i, next_i, last = ctx->last_buffer_index;
+ __le16 res_count, next_res_count;
+
+ i = ar_first_buffer_index(ctx);
+ res_count = ACCESS_ONCE(ctx->descriptors[i].res_count);
+
+ /* A buffer that is not yet completely filled must be the last one. */
+ while (i != last && res_count == 0) {
+
+ /* Peek at the next descriptor. */
+ next_i = ar_next_buffer_index(i);
+ rmb(); /* read descriptors in order */
+ next_res_count = ACCESS_ONCE(
+ ctx->descriptors[next_i].res_count);
+ /*
+ * If the next descriptor is still empty, we must stop at this
+ * descriptor.
+ */
+ if (next_res_count == cpu_to_le16(PAGE_SIZE)) {
+ /*
+ * The exception is when the DMA data for one packet is
+ * split over three buffers; in this case, the middle
+ * buffer's descriptor might be never updated by the
+ * controller and look still empty, and we have to peek
+ * at the third one.
+ */
+ if (MAX_AR_PACKET_SIZE > PAGE_SIZE && i != last) {
+ next_i = ar_next_buffer_index(next_i);
+ rmb();
+ next_res_count = ACCESS_ONCE(
+ ctx->descriptors[next_i].res_count);
+ if (next_res_count != cpu_to_le16(PAGE_SIZE))
+ goto next_buffer_is_active;
+ }
+
+ break;
+ }
+
+next_buffer_is_active:
+ i = next_i;
+ res_count = next_res_count;
+ }
+
+ rmb(); /* read res_count before the DMA data */
+
+ *buffer_offset = PAGE_SIZE - le16_to_cpu(res_count);
+ if (*buffer_offset > PAGE_SIZE) {
+ *buffer_offset = 0;
+ ar_context_abort(ctx, "corrupted descriptor");
+ }
+
+ return i;
+}
+
+static void ar_sync_buffers_for_cpu(struct ar_context *ctx,
+ unsigned int end_buffer_index,
+ unsigned int end_buffer_offset)
+{
+ unsigned int i;
+
+ i = ar_first_buffer_index(ctx);
+ while (i != end_buffer_index) {
+ dma_sync_single_for_cpu(ctx->ohci->card.device,
+ ar_buffer_bus(ctx, i),
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ i = ar_next_buffer_index(i);
+ }
+ if (end_buffer_offset > 0)
+ dma_sync_single_for_cpu(ctx->ohci->card.device,
+ ar_buffer_bus(ctx, i),
+ end_buffer_offset, DMA_FROM_DEVICE);
}
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
@@ -665,6 +791,10 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
p.header[3] = cond_le32_to_cpu(buffer[3]);
p.header_length = 16;
p.payload_length = p.header[3] >> 16;
+ if (p.payload_length > MAX_ASYNC_PAYLOAD) {
+ ar_context_abort(ctx, "invalid packet length");
+ return NULL;
+ }
break;
case TCODE_WRITE_RESPONSE:
@@ -675,9 +805,8 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
break;
default:
- /* FIXME: Stop context, discard everything, and restart? */
- p.header_length = 0;
- p.payload_length = 0;
+ ar_context_abort(ctx, "invalid tcode");
+ return NULL;
}
p.payload = (void *) buffer + p.header_length;
@@ -727,86 +856,147 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
return buffer + length + 1;
}
+static void *handle_ar_packets(struct ar_context *ctx, void *p, void *end)
+{
+ void *next;
+
+ while (p < end) {
+ next = handle_ar_packet(ctx, p);
+ if (!next)
+ return p;
+ p = next;
+ }
+
+ return p;
+}
+
+static void ar_recycle_buffers(struct ar_context *ctx, unsigned int end_buffer)
+{
+ unsigned int i;
+
+ i = ar_first_buffer_index(ctx);
+ while (i != end_buffer) {
+ dma_sync_single_for_device(ctx->ohci->card.device,
+ ar_buffer_bus(ctx, i),
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ ar_context_link_page(ctx, i);
+ i = ar_next_buffer_index(i);
+ }
+}
+
static void ar_context_tasklet(unsigned long data)
{
struct ar_context *ctx = (struct ar_context *)data;
- struct fw_ohci *ohci = ctx->ohci;
- struct ar_buffer *ab;
- struct descriptor *d;
- void *buffer, *end;
+ unsigned int end_buffer_index, end_buffer_offset;
+ void *p, *end;
- ab = ctx->current_buffer;
- d = &ab->descriptor;
+ p = ctx->pointer;
+ if (!p)
+ return;
- if (d->res_count == 0) {
- size_t size, rest, offset;
- dma_addr_t start_bus;
- void *start;
+ end_buffer_index = ar_search_last_active_buffer(ctx,
+ &end_buffer_offset);
+ ar_sync_buffers_for_cpu(ctx, end_buffer_index, end_buffer_offset);
+ end = ctx->buffer + end_buffer_index * PAGE_SIZE + end_buffer_offset;
+ if (end_buffer_index < ar_first_buffer_index(ctx)) {
/*
- * This descriptor is finished and we may have a
- * packet split across this and the next buffer. We
- * reuse the page for reassembling the split packet.
+ * The filled part of the overall buffer wraps around; handle
+ * all packets up to the buffer end here. If the last packet
+ * wraps around, its tail will be visible after the buffer end
+ * because the buffer start pages are mapped there again.
*/
+ void *buffer_end = ctx->buffer + AR_BUFFERS * PAGE_SIZE;
+ p = handle_ar_packets(ctx, p, buffer_end);
+ if (p < buffer_end)
+ goto error;
+ /* adjust p to point back into the actual buffer */
+ p -= AR_BUFFERS * PAGE_SIZE;
+ }
- offset = offsetof(struct ar_buffer, data);
- start = buffer = ab;
- start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
-
- ab = ab->next;
- d = &ab->descriptor;
- size = buffer + PAGE_SIZE - ctx->pointer;
- rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
- memmove(buffer, ctx->pointer, size);
- memcpy(buffer + size, ab->data, rest);
- ctx->current_buffer = ab;
- ctx->pointer = (void *) ab->data + rest;
- end = buffer + size + rest;
-
- while (buffer < end)
- buffer = handle_ar_packet(ctx, buffer);
-
- dma_free_coherent(ohci->card.device, PAGE_SIZE,
- start, start_bus);
- ar_context_add_page(ctx);
- } else {
- buffer = ctx->pointer;
- ctx->pointer = end =
- (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
-
- while (buffer < end)
- buffer = handle_ar_packet(ctx, buffer);
+ p = handle_ar_packets(ctx, p, end);
+ if (p != end) {
+ if (p > end)
+ ar_context_abort(ctx, "inconsistent descriptor");
+ goto error;
}
+
+ ctx->pointer = p;
+ ar_recycle_buffers(ctx, end_buffer_index);
+
+ return;
+
+error:
+ ctx->pointer = NULL;
}
-static int ar_context_init(struct ar_context *ctx,
- struct fw_ohci *ohci, u32 regs)
+static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
+ unsigned int descriptors_offset, u32 regs)
{
- struct ar_buffer ab;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES];
+ struct descriptor *d;
ctx->regs = regs;
ctx->ohci = ohci;
- ctx->last_buffer = &ab;
tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx);
- ar_context_add_page(ctx);
- ar_context_add_page(ctx);
- ctx->current_buffer = ab.next;
- ctx->pointer = ctx->current_buffer->data;
+ for (i = 0; i < AR_BUFFERS; i++) {
+ ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32);
+ if (!ctx->pages[i])
+ goto out_of_memory;
+ dma_addr = dma_map_page(ohci->card.device, ctx->pages[i],
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ohci->card.device, dma_addr)) {
+ __free_page(ctx->pages[i]);
+ ctx->pages[i] = NULL;
+ goto out_of_memory;
+ }
+ set_page_private(ctx->pages[i], dma_addr);
+ }
+
+ for (i = 0; i < AR_BUFFERS; i++)
+ pages[i] = ctx->pages[i];
+ for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
+ pages[AR_BUFFERS + i] = ctx->pages[i];
+ ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES,
+ -1, PAGE_KERNEL);
+ if (!ctx->buffer)
+ goto out_of_memory;
+
+ ctx->descriptors = ohci->misc_buffer + descriptors_offset;
+ ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset;
+
+ for (i = 0; i < AR_BUFFERS; i++) {
+ d = &ctx->descriptors[i];
+ d->req_count = cpu_to_le16(PAGE_SIZE);
+ d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
+ DESCRIPTOR_STATUS |
+ DESCRIPTOR_BRANCH_ALWAYS);
+ d->data_address = cpu_to_le32(ar_buffer_bus(ctx, i));
+ d->branch_address = cpu_to_le32(ctx->descriptors_bus +
+ ar_next_buffer_index(i) * sizeof(struct descriptor));
+ }
return 0;
+
+out_of_memory:
+ ar_context_release(ctx);
+
+ return -ENOMEM;
}
static void ar_context_run(struct ar_context *ctx)
{
- struct ar_buffer *ab = ctx->current_buffer;
- dma_addr_t ab_bus;
- size_t offset;
+ unsigned int i;
- offset = offsetof(struct ar_buffer, data);
- ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+ for (i = 0; i < AR_BUFFERS; i++)
+ ar_context_link_page(ctx, i);
- reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1);
+ ctx->pointer = ctx->buffer;
+
+ reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1);
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN);
flush_writes(ctx->ohci);
}
@@ -983,6 +1173,7 @@ static void context_run(struct context *ctx, u32 extra)
le32_to_cpu(ctx->last->branch_address));
reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
+ ctx->running = true;
flush_writes(ohci);
}
@@ -1010,6 +1201,7 @@ static void context_stop(struct context *ctx)
int i;
reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+ ctx->running = false;
flush_writes(ctx->ohci);
for (i = 0; i < 10; i++) {
@@ -1040,7 +1232,6 @@ static int at_context_queue_packet(struct context *ctx,
struct descriptor *d, *last;
__le32 *header;
int z, tcode;
- u32 reg;
d = context_get_descriptors(ctx, 4, &d_bus);
if (d == NULL) {
@@ -1054,21 +1245,27 @@ static int at_context_queue_packet(struct context *ctx,
/*
* The DMA format for asyncronous link packets is different
* from the IEEE1394 layout, so shift the fields around
- * accordingly. If header_length is 8, it's a PHY packet, to
- * which we need to prepend an extra quadlet.
+ * accordingly.
*/
+ tcode = (packet->header[0] >> 4) & 0x0f;
header = (__le32 *) &d[1];
- switch (packet->header_length) {
- case 16:
- case 12:
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ case TCODE_WRITE_BLOCK_REQUEST:
+ case TCODE_WRITE_RESPONSE:
+ case TCODE_READ_QUADLET_REQUEST:
+ case TCODE_READ_BLOCK_REQUEST:
+ case TCODE_READ_QUADLET_RESPONSE:
+ case TCODE_READ_BLOCK_RESPONSE:
+ case TCODE_LOCK_REQUEST:
+ case TCODE_LOCK_RESPONSE:
header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
(packet->speed << 16));
header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
(packet->header[0] & 0xffff0000));
header[2] = cpu_to_le32(packet->header[2]);
- tcode = (packet->header[0] >> 4) & 0x0f;
if (TCODE_IS_BLOCK_PACKET(tcode))
header[3] = cpu_to_le32(packet->header[3]);
else
@@ -1077,18 +1274,18 @@ static int at_context_queue_packet(struct context *ctx,
d[0].req_count = cpu_to_le16(packet->header_length);
break;
- case 8:
+ case TCODE_LINK_INTERNAL:
header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
(packet->speed << 16));
- header[1] = cpu_to_le32(packet->header[0]);
- header[2] = cpu_to_le32(packet->header[1]);
+ header[1] = cpu_to_le32(packet->header[1]);
+ header[2] = cpu_to_le32(packet->header[2]);
d[0].req_count = cpu_to_le16(12);
- if (is_ping_packet(packet->header))
+ if (is_ping_packet(&packet->header[1]))
d[0].control |= cpu_to_le16(DESCRIPTOR_PING);
break;
- case 4:
+ case TCODE_STREAM_DATA:
header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
(packet->speed << 16));
header[1] = cpu_to_le32(packet->header[0] & 0xffff0000);
@@ -1138,6 +1335,8 @@ static int at_context_queue_packet(struct context *ctx,
* some controllers (like a JMicron JMB381 PCI-e) misbehave and wind
* up stalling out. So we just bail out in software and try again
* later, and everyone is happy.
+ * FIXME: Test of IntEvent.busReset may no longer be necessary since we
+ * flush AT queues in bus_reset_tasklet.
* FIXME: Document how the locking works.
*/
if (ohci->generation != packet->generation ||
@@ -1151,14 +1350,23 @@ static int at_context_queue_packet(struct context *ctx,
context_append(ctx, d, z, 4 - z);
- /* If the context isn't already running, start it up. */
- reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
- if ((reg & CONTEXT_RUN) == 0)
+ if (!ctx->running)
context_run(ctx, 0);
return 0;
}
+static void at_context_flush(struct context *ctx)
+{
+ tasklet_disable(&ctx->tasklet);
+
+ ctx->flushing = true;
+ context_tasklet((unsigned long)ctx);
+ ctx->flushing = false;
+
+ tasklet_enable(&ctx->tasklet);
+}
+
static int handle_at_packet(struct context *context,
struct descriptor *d,
struct descriptor *last)
@@ -1168,7 +1376,7 @@ static int handle_at_packet(struct context *context,
struct fw_ohci *ohci = context->ohci;
int evt;
- if (last->transfer_status == 0)
+ if (last->transfer_status == 0 && !context->flushing)
/* This descriptor isn't done yet, stop iteration. */
return 0;
@@ -1202,11 +1410,15 @@ static int handle_at_packet(struct context *context,
break;
case OHCI1394_evt_missing_ack:
- /*
- * Using a valid (current) generation count, but the
- * node is not on the bus or not sending acks.
- */
- packet->ack = RCODE_NO_ACK;
+ if (context->flushing)
+ packet->ack = RCODE_GENERATION;
+ else {
+ /*
+ * Using a valid (current) generation count, but the
+ * node is not on the bus or not sending acks.
+ */
+ packet->ack = RCODE_NO_ACK;
+ }
break;
case ACK_COMPLETE + 0x10:
@@ -1219,6 +1431,13 @@ static int handle_at_packet(struct context *context,
packet->ack = evt - 0x10;
break;
+ case OHCI1394_evt_no_status:
+ if (context->flushing) {
+ packet->ack = RCODE_GENERATION;
+ break;
+ }
+ /* fall through */
+
default:
packet->ack = RCODE_SEND_ERROR;
break;
@@ -1524,9 +1743,23 @@ static void bus_reset_tasklet(unsigned long data)
/* FIXME: Document how the locking works. */
spin_lock_irqsave(&ohci->lock, flags);
- ohci->generation = generation;
+ ohci->generation = -1; /* prevent AT packet queueing */
context_stop(&ohci->at_request_ctx);
context_stop(&ohci->at_response_ctx);
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ /*
+ * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
+ * packets in the AT queues and software needs to drain them.
+ * Some OHCI 1.1 controllers (JMicron) apparently require this too.
+ */
+ at_context_flush(&ohci->at_request_ctx);
+ at_context_flush(&ohci->at_response_ctx);
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ ohci->generation = generation;
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
if (ohci->quirks & QUIRK_RESET_PACKET)
@@ -1594,8 +1827,12 @@ static irqreturn_t irq_handler(int irq, void *data)
if (!event || !~event)
return IRQ_NONE;
- /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */
- reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
+ /*
+ * busReset and postedWriteErr must not be cleared yet
+ * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1)
+ */
+ reg_write(ohci, OHCI1394_IntEventClear,
+ event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr));
log_irqs(event);
if (event & OHCI1394_selfIDComplete)
@@ -1613,30 +1850,41 @@ static irqreturn_t irq_handler(int irq, void *data)
if (event & OHCI1394_respTxComplete)
tasklet_schedule(&ohci->at_response_ctx.tasklet);
- iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
+ if (event & OHCI1394_isochRx) {
+ iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
+ reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
- while (iso_event) {
- i = ffs(iso_event) - 1;
- tasklet_schedule(&ohci->ir_context_list[i].context.tasklet);
- iso_event &= ~(1 << i);
+ while (iso_event) {
+ i = ffs(iso_event) - 1;
+ tasklet_schedule(
+ &ohci->ir_context_list[i].context.tasklet);
+ iso_event &= ~(1 << i);
+ }
}
- iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
+ if (event & OHCI1394_isochTx) {
+ iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
+ reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
- while (iso_event) {
- i = ffs(iso_event) - 1;
- tasklet_schedule(&ohci->it_context_list[i].context.tasklet);
- iso_event &= ~(1 << i);
+ while (iso_event) {
+ i = ffs(iso_event) - 1;
+ tasklet_schedule(
+ &ohci->it_context_list[i].context.tasklet);
+ iso_event &= ~(1 << i);
+ }
}
if (unlikely(event & OHCI1394_regAccessFail))
fw_error("Register access failure - "
"please notify linux1394-devel@lists.sf.net\n");
- if (unlikely(event & OHCI1394_postedWriteErr))
+ if (unlikely(event & OHCI1394_postedWriteErr)) {
+ reg_read(ohci, OHCI1394_PostedWriteAddressHi);
+ reg_read(ohci, OHCI1394_PostedWriteAddressLo);
+ reg_write(ohci, OHCI1394_IntEventClear,
+ OHCI1394_postedWriteErr);
fw_error("PCI posted write error\n");
+ }
if (unlikely(event & OHCI1394_cycleTooLong)) {
if (printk_ratelimit())
@@ -1660,7 +1908,8 @@ static irqreturn_t irq_handler(int irq, void *data)
spin_lock(&ohci->lock);
update_bus_time(ohci);
spin_unlock(&ohci->lock);
- }
+ } else
+ flush_writes(ohci);
return IRQ_HANDLED;
}
@@ -2436,6 +2685,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
context_run(&ctx->context, control);
+
+ ctx->sync = sync;
+ ctx->tags = tags;
+
break;
}
@@ -2533,6 +2786,26 @@ static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
return ret;
}
+#ifdef CONFIG_PM
+static void ohci_resume_iso_dma(struct fw_ohci *ohci)
+{
+ int i;
+ struct iso_context *ctx;
+
+ for (i = 0 ; i < ohci->n_ir ; i++) {
+ ctx = &ohci->ir_context_list[i];
+ if (ctx->context.running)
+ ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+ }
+
+ for (i = 0 ; i < ohci->n_it ; i++) {
+ ctx = &ohci->it_context_list[i];
+ if (ctx->context.running)
+ ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags);
+ }
+}
+#endif
+
static int queue_iso_transmit(struct iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
@@ -2842,7 +3115,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
struct fw_ohci *ohci;
u32 bus_options, max_receive, link_speed, version;
u64 guid;
- int i, err, n_ir, n_it;
+ int i, err;
size_t size;
ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
@@ -2885,40 +3158,66 @@ static int __devinit pci_probe(struct pci_dev *dev,
}
for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++)
- if (ohci_quirks[i].vendor == dev->vendor &&
- (ohci_quirks[i].device == dev->device ||
- ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) {
+ if ((ohci_quirks[i].vendor == dev->vendor) &&
+ (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID ||
+ ohci_quirks[i].device == dev->device) &&
+ (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID ||
+ ohci_quirks[i].revision >= dev->revision)) {
ohci->quirks = ohci_quirks[i].flags;
break;
}
if (param_quirks)
ohci->quirks = param_quirks;
- ar_context_init(&ohci->ar_request_ctx, ohci,
- OHCI1394_AsReqRcvContextControlSet);
+ /*
+ * Because dma_alloc_coherent() allocates at least one page,
+ * we save space by using a common buffer for the AR request/
+ * response descriptors and the self IDs buffer.
+ */
+ BUILD_BUG_ON(AR_BUFFERS * sizeof(struct descriptor) > PAGE_SIZE/4);
+ BUILD_BUG_ON(SELF_ID_BUF_SIZE > PAGE_SIZE/2);
+ ohci->misc_buffer = dma_alloc_coherent(ohci->card.device,
+ PAGE_SIZE,
+ &ohci->misc_buffer_bus,
+ GFP_KERNEL);
+ if (!ohci->misc_buffer) {
+ err = -ENOMEM;
+ goto fail_iounmap;
+ }
+
+ err = ar_context_init(&ohci->ar_request_ctx, ohci, 0,
+ OHCI1394_AsReqRcvContextControlSet);
+ if (err < 0)
+ goto fail_misc_buf;
- ar_context_init(&ohci->ar_response_ctx, ohci,
- OHCI1394_AsRspRcvContextControlSet);
+ err = ar_context_init(&ohci->ar_response_ctx, ohci, PAGE_SIZE/4,
+ OHCI1394_AsRspRcvContextControlSet);
+ if (err < 0)
+ goto fail_arreq_ctx;
- context_init(&ohci->at_request_ctx, ohci,
- OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+ err = context_init(&ohci->at_request_ctx, ohci,
+ OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+ if (err < 0)
+ goto fail_arrsp_ctx;
- context_init(&ohci->at_response_ctx, ohci,
- OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+ err = context_init(&ohci->at_response_ctx, ohci,
+ OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+ if (err < 0)
+ goto fail_atreq_ctx;
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
ohci->ir_context_channels = ~0ULL;
ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
- n_ir = hweight32(ohci->ir_context_mask);
- size = sizeof(struct iso_context) * n_ir;
+ ohci->n_ir = hweight32(ohci->ir_context_mask);
+ size = sizeof(struct iso_context) * ohci->n_ir;
ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
- n_it = hweight32(ohci->it_context_mask);
- size = sizeof(struct iso_context) * n_it;
+ ohci->n_it = hweight32(ohci->it_context_mask);
+ size = sizeof(struct iso_context) * ohci->n_it;
ohci->it_context_list = kzalloc(size, GFP_KERNEL);
if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
@@ -2926,15 +3225,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
goto fail_contexts;
}
- /* self-id dma buffer allocation */
- ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device,
- SELF_ID_BUF_SIZE,
- &ohci->self_id_bus,
- GFP_KERNEL);
- if (ohci->self_id_cpu == NULL) {
- err = -ENOMEM;
- goto fail_contexts;
- }
+ ohci->self_id_cpu = ohci->misc_buffer + PAGE_SIZE/2;
+ ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2;
bus_options = reg_read(ohci, OHCI1394_BusOptions);
max_receive = (bus_options >> 12) & 0xf;
@@ -2944,26 +3236,30 @@ static int __devinit pci_probe(struct pci_dev *dev,
err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
if (err)
- goto fail_self_id;
+ goto fail_contexts;
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
"%d IR + %d IT contexts, quirks 0x%x\n",
dev_name(&dev->dev), version >> 16, version & 0xff,
- n_ir, n_it, ohci->quirks);
+ ohci->n_ir, ohci->n_it, ohci->quirks);
return 0;
- fail_self_id:
- dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
- ohci->self_id_cpu, ohci->self_id_bus);
fail_contexts:
kfree(ohci->ir_context_list);
kfree(ohci->it_context_list);
context_release(&ohci->at_response_ctx);
+ fail_atreq_ctx:
context_release(&ohci->at_request_ctx);
+ fail_arrsp_ctx:
ar_context_release(&ohci->ar_response_ctx);
+ fail_arreq_ctx:
ar_context_release(&ohci->ar_request_ctx);
+ fail_misc_buf:
+ dma_free_coherent(ohci->card.device, PAGE_SIZE,
+ ohci->misc_buffer, ohci->misc_buffer_bus);
+ fail_iounmap:
pci_iounmap(dev, ohci->registers);
fail_iomem:
pci_release_region(dev, 0);
@@ -3002,10 +3298,10 @@ static void pci_remove(struct pci_dev *dev)
if (ohci->config_rom)
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
ohci->config_rom, ohci->config_rom_bus);
- dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
- ohci->self_id_cpu, ohci->self_id_bus);
ar_context_release(&ohci->ar_request_ctx);
ar_context_release(&ohci->ar_response_ctx);
+ dma_free_coherent(ohci->card.device, PAGE_SIZE,
+ ohci->misc_buffer, ohci->misc_buffer_bus);
context_release(&ohci->at_request_ctx);
context_release(&ohci->at_response_ctx);
kfree(ohci->it_context_list);
@@ -3056,7 +3352,20 @@ static int pci_resume(struct pci_dev *dev)
return err;
}
- return ohci_enable(&ohci->card, NULL, 0);
+ /* Some systems don't setup GUID register on resume from ram */
+ if (!reg_read(ohci, OHCI1394_GUIDLo) &&
+ !reg_read(ohci, OHCI1394_GUIDHi)) {
+ reg_write(ohci, OHCI1394_GUIDLo, (u32)ohci->card.guid);
+ reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32));
+ }
+
+ err = ohci_enable(&ohci->card, NULL, 0);
+ if (err)
+ return err;
+
+ ohci_resume_iso_dma(ohci);
+
+ return 0;
}
#endif
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index bfae4b309791..afa576a75a8e 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1468,7 +1468,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
/* SCSI stack integration */
-static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done)
{
struct sbp2_logical_unit *lu = cmd->device->hostdata;
struct fw_device *device = target_device(lu->tgt);
@@ -1534,6 +1534,8 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
return retval;
}
+static DEF_SCSI_QCMD(sbp2_scsi_queuecommand)
+
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
{
struct sbp2_logical_unit *lu = sdev->hostdata;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3143ac795eb0..664660e56335 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -118,7 +118,7 @@ config GPIO_SCH
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
- depends on GPIOLIB
+ depends on GPIOLIB && MFD_SUPPORT && PCI
select MFD_CORE
select MFD_VX855
help
@@ -230,11 +230,11 @@ config GPIO_STMPE
This enables support for the GPIOs found on the STMPE I/O
Expanders.
-config GPIO_TC35892
- bool "TC35892 GPIOs"
- depends on MFD_TC35892
+config GPIO_TC3589X
+ bool "TC3589X GPIOs"
+ depends on MFD_TC3589X
help
- This enables support for the GPIOs found on the TC35892
+ This enables support for the GPIOs found on the TC3589X
I/O Expander.
config GPIO_TWL4030
@@ -295,7 +295,7 @@ comment "PCI GPIO expanders:"
config GPIO_CS5535
tristate "AMD CS5535/CS5536 GPIO support"
- depends on PCI && !CS5535_GPIO
+ depends on PCI && X86 && !CS5535_GPIO
help
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
can be used for quite a number of things. The CS5535/6 is found on
@@ -333,6 +333,15 @@ config GPIO_PCH
which is an IOH(Input/Output Hub) for x86 embedded processor.
This driver can access PCH GPIO device.
+config GPIO_ML_IOH
+ tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
+ depends on PCI
+ help
+ ML7213 is companion chip for Intel Atom E6xx series.
+ This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
+ Hub) which is for IVI(In-Vehicle Infotainment) use.
+ This driver can access the IOH's GPIO device.
+
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
@@ -342,6 +351,7 @@ config GPIO_TIMBERDALE
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
depends on PCI && GPIOLIB
+ select MFD_SUPPORT
select MFD_CORE
select MFD_RDC321X
help
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index bdf3ddec0652..3351cf87b0ed 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PCH) += pch_gpio.o
obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o
-obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o
+obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o
obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o
@@ -41,3 +41,4 @@ obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o
obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o
obj-$(CONFIG_GPIO_SX150X) += sx150x.o
obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o
+obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o
diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c
index 0871f78af593..33fc685cb385 100644
--- a/drivers/gpio/adp5588-gpio.c
+++ b/drivers/gpio/adp5588-gpio.c
@@ -146,9 +146,10 @@ static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off)
return dev->irq_base + off;
}
-static void adp5588_irq_bus_lock(unsigned int irq)
+static void adp5588_irq_bus_lock(struct irq_data *d)
{
- struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
+
mutex_lock(&dev->irq_lock);
}
@@ -160,9 +161,9 @@ static void adp5588_irq_bus_lock(unsigned int irq)
* and unlocks the bus.
*/
-static void adp5588_irq_bus_sync_unlock(unsigned int irq)
+static void adp5588_irq_bus_sync_unlock(struct irq_data *d)
{
- struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
int i;
for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
@@ -175,31 +176,31 @@ static void adp5588_irq_bus_sync_unlock(unsigned int irq)
mutex_unlock(&dev->irq_lock);
}
-static void adp5588_irq_mask(unsigned int irq)
+static void adp5588_irq_mask(struct irq_data *d)
{
- struct adp5588_gpio *dev = get_irq_chip_data(irq);
- unsigned gpio = irq - dev->irq_base;
+ struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
+ unsigned gpio = d->irq - dev->irq_base;
dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio);
}
-static void adp5588_irq_unmask(unsigned int irq)
+static void adp5588_irq_unmask(struct irq_data *d)
{
- struct adp5588_gpio *dev = get_irq_chip_data(irq);
- unsigned gpio = irq - dev->irq_base;
+ struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
+ unsigned gpio = d->irq - dev->irq_base;
dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio);
}
-static int adp5588_irq_set_type(unsigned int irq, unsigned int type)
+static int adp5588_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct adp5588_gpio *dev = get_irq_chip_data(irq);
- uint16_t gpio = irq - dev->irq_base;
+ struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
+ uint16_t gpio = d->irq - dev->irq_base;
unsigned bank, bit;
if ((type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
- irq, type);
+ d->irq, type);
return -EINVAL;
}
@@ -222,11 +223,11 @@ static int adp5588_irq_set_type(unsigned int irq, unsigned int type)
static struct irq_chip adp5588_irq_chip = {
.name = "adp5588",
- .mask = adp5588_irq_mask,
- .unmask = adp5588_irq_unmask,
- .bus_lock = adp5588_irq_bus_lock,
- .bus_sync_unlock = adp5588_irq_bus_sync_unlock,
- .set_type = adp5588_irq_set_type,
+ .irq_mask = adp5588_irq_mask,
+ .irq_unmask = adp5588_irq_unmask,
+ .irq_bus_lock = adp5588_irq_bus_lock,
+ .irq_bus_sync_unlock = adp5588_irq_bus_sync_unlock,
+ .irq_set_type = adp5588_irq_set_type,
};
static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf)
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c
index e23c06893d19..0d05ea7d499b 100644
--- a/drivers/gpio/cs5535-gpio.c
+++ b/drivers/gpio/cs5535-gpio.c
@@ -11,13 +11,13 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/cs5535.h>
+#include <asm/msr.h>
#define DRV_NAME "cs5535-gpio"
-#define GPIO_BAR 1
/*
* Some GPIO pins
@@ -46,7 +46,7 @@ static struct cs5535_gpio_chip {
struct gpio_chip chip;
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
} cs5535_gpio_chip;
@@ -56,6 +56,29 @@ static struct cs5535_gpio_chip {
* registers, see include/linux/cs5535.h.
*/
+static void errata_outl(struct cs5535_gpio_chip *chip, u32 val,
+ unsigned int reg)
+{
+ unsigned long addr = chip->base + 0x80 + reg;
+
+ /*
+ * According to the CS5536 errata (#36), after suspend
+ * a write to the high bank GPIO register will clear all
+ * non-selected bits; the recommended workaround is a
+ * read-modify-write operation.
+ *
+ * Don't apply this errata to the edge status GPIOs, as writing
+ * to their lower bits will clear them.
+ */
+ if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) {
+ if (val & 0xffff)
+ val |= (inl(addr) & 0xffff); /* ignore the high bits */
+ else
+ val |= (inl(addr) ^ (val >> 16));
+ }
+ outl(val, addr);
+}
+
static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
unsigned int reg)
{
@@ -64,7 +87,7 @@ static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
outl(1 << offset, chip->base + reg);
else
/* high bank register */
- outl(1 << (offset - 16), chip->base + 0x80 + reg);
+ errata_outl(chip, 1 << (offset - 16), reg);
}
void cs5535_gpio_set(unsigned offset, unsigned int reg)
@@ -86,7 +109,7 @@ static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset,
outl(1 << (offset + 16), chip->base + reg);
else
/* high bank register */
- outl(1 << offset, chip->base + 0x80 + reg);
+ errata_outl(chip, 1 << offset, reg);
}
void cs5535_gpio_clear(unsigned offset, unsigned int reg)
@@ -121,6 +144,57 @@ int cs5535_gpio_isset(unsigned offset, unsigned int reg)
}
EXPORT_SYMBOL_GPL(cs5535_gpio_isset);
+int cs5535_gpio_set_irq(unsigned group, unsigned irq)
+{
+ uint32_t lo, hi;
+
+ if (group > 7 || irq > 15)
+ return -EINVAL;
+
+ rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+
+ lo &= ~(0xF << (group * 4));
+ lo |= (irq & 0xF) << (group * 4);
+
+ wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs5535_gpio_set_irq);
+
+void cs5535_gpio_setup_event(unsigned offset, int pair, int pme)
+{
+ struct cs5535_gpio_chip *chip = &cs5535_gpio_chip;
+ uint32_t shift = (offset % 8) * 4;
+ unsigned long flags;
+ uint32_t val;
+
+ if (offset >= 24)
+ offset = GPIO_MAP_W;
+ else if (offset >= 16)
+ offset = GPIO_MAP_Z;
+ else if (offset >= 8)
+ offset = GPIO_MAP_Y;
+ else
+ offset = GPIO_MAP_X;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ val = inl(chip->base + offset);
+
+ /* Clear whatever was there before */
+ val &= ~(0xF << shift);
+
+ /* Set the new value */
+ val |= ((pair & 7) << shift);
+
+ /* Set the PME bit if this is a PME event */
+ if (pme)
+ val |= (1 << (shift + 3));
+
+ outl(val, chip->base + offset);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event);
+
/*
* Generic gpio_chip API support.
*/
@@ -226,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
},
};
-static int __init cs5535_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
{
- int err;
+ struct resource *res;
+ int err = -EIO;
ulong mask_orig = mask;
/* There are two ways to get the GPIO base address; one is by
@@ -239,25 +313,23 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
+ cs5535_gpio_chip.base = res->start;
cs5535_gpio_chip.pdev = pdev;
spin_lock_init(&cs5535_gpio_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
- (unsigned long long) cs5535_gpio_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* mask out reserved pins */
mask &= 0x1F7FFFFF;
@@ -275,78 +347,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
if (err)
goto release_region;
- dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
+ dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
return 0;
release_region:
- pci_release_region(pdev, GPIO_BAR);
+ release_region(res->start, resource_size(res));
done:
return err;
}
-static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
+static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
{
+ struct resource *r;
int err;
err = gpiochip_remove(&cs5535_gpio_chip.chip);
if (err) {
/* uhh? */
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+ return err;
}
- pci_release_region(pdev, GPIO_BAR);
-}
-
-static struct pci_device_id cs5535_gpio_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
-/*
- * We can't use the standard PCI driver registration stuff here, since
- * that allows only one driver to bind to each PCI device (and we want
- * multiple drivers to be able to bind to the device). Instead, manually
- * scan for the PCI device, request a single region, and keep track of the
- * devices that we're using.
- */
-
-static int __init cs5535_gpio_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
- cs5535_gpio_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(r->start, resource_size(r));
+ return 0;
}
-static void __exit cs5535_gpio_free_pci(void)
-{
- cs5535_gpio_remove(cs5535_gpio_chip.pdev);
- pci_dev_put(cs5535_gpio_chip.pdev);
-}
+static struct platform_driver cs5535_gpio_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_gpio_probe,
+ .remove = __devexit_p(cs5535_gpio_remove),
+};
static int __init cs5535_gpio_init(void)
{
- return cs5535_gpio_scan_pci();
+ return platform_driver_register(&cs5535_gpio_drv);
}
static void __exit cs5535_gpio_exit(void)
{
- cs5535_gpio_free_pci();
+ platform_driver_unregister(&cs5535_gpio_drv);
}
module_init(cs5535_gpio_init);
@@ -355,3 +398,4 @@ module_exit(cs5535_gpio_exit);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 21da9c19a0cb..649550e2cae9 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1281,6 +1281,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
err = gpio_direction_output(gpio,
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
+ if (err)
+ gpio_free(gpio);
+
return err;
}
EXPORT_SYMBOL_GPL(gpio_request_one);
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c
index 64db9dc3a275..d81cc748e77f 100644
--- a/drivers/gpio/langwell_gpio.c
+++ b/drivers/gpio/langwell_gpio.c
@@ -134,10 +134,10 @@ static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return lnw->irq_base + offset;
}
-static int lnw_irq_type(unsigned irq, unsigned type)
+static int lnw_irq_type(struct irq_data *d, unsigned type)
{
- struct lnw_gpio *lnw = get_irq_chip_data(irq);
- u32 gpio = irq - lnw->irq_base;
+ struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
+ u32 gpio = d->irq - lnw->irq_base;
unsigned long flags;
u32 value;
void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
@@ -162,19 +162,19 @@ static int lnw_irq_type(unsigned irq, unsigned type)
return 0;
}
-static void lnw_irq_unmask(unsigned irq)
+static void lnw_irq_unmask(struct irq_data *d)
{
}
-static void lnw_irq_mask(unsigned irq)
+static void lnw_irq_mask(struct irq_data *d)
{
}
static struct irq_chip lnw_irqchip = {
.name = "LNW-GPIO",
- .mask = lnw_irq_mask,
- .unmask = lnw_irq_unmask,
- .set_type = lnw_irq_type,
+ .irq_mask = lnw_irq_mask,
+ .irq_unmask = lnw_irq_unmask,
+ .irq_set_type = lnw_irq_type,
};
static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */
diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c
index 9cad60f9e962..9e1d01f0071a 100644
--- a/drivers/gpio/max732x.c
+++ b/drivers/gpio/max732x.c
@@ -327,40 +327,40 @@ static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
return chip->irq_base + off;
}
-static void max732x_irq_mask(unsigned int irq)
+static void max732x_irq_mask(struct irq_data *d)
{
- struct max732x_chip *chip = get_irq_chip_data(irq);
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask_cur &= ~(1 << (irq - chip->irq_base));
+ chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base));
}
-static void max732x_irq_unmask(unsigned int irq)
+static void max732x_irq_unmask(struct irq_data *d)
{
- struct max732x_chip *chip = get_irq_chip_data(irq);
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask_cur |= 1 << (irq - chip->irq_base);
+ chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base);
}
-static void max732x_irq_bus_lock(unsigned int irq)
+static void max732x_irq_bus_lock(struct irq_data *d)
{
- struct max732x_chip *chip = get_irq_chip_data(irq);
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
mutex_lock(&chip->irq_lock);
chip->irq_mask_cur = chip->irq_mask;
}
-static void max732x_irq_bus_sync_unlock(unsigned int irq)
+static void max732x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct max732x_chip *chip = get_irq_chip_data(irq);
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
max732x_irq_update_mask(chip);
mutex_unlock(&chip->irq_lock);
}
-static int max732x_irq_set_type(unsigned int irq, unsigned int type)
+static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct max732x_chip *chip = get_irq_chip_data(irq);
- uint16_t off = irq - chip->irq_base;
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ uint16_t off = d->irq - chip->irq_base;
uint16_t mask = 1 << off;
if (!(mask & chip->dir_input)) {
@@ -371,7 +371,7 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type)
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
- irq, type);
+ d->irq, type);
return -EINVAL;
}
@@ -390,11 +390,11 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type)
static struct irq_chip max732x_irq_chip = {
.name = "max732x",
- .mask = max732x_irq_mask,
- .unmask = max732x_irq_unmask,
- .bus_lock = max732x_irq_bus_lock,
- .bus_sync_unlock = max732x_irq_bus_sync_unlock,
- .set_type = max732x_irq_set_type,
+ .irq_mask = max732x_irq_mask,
+ .irq_unmask = max732x_irq_unmask,
+ .irq_bus_lock = max732x_irq_bus_lock,
+ .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
+ .irq_set_type = max732x_irq_set_type,
};
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c
new file mode 100644
index 000000000000..cead8e6ff345
--- /dev/null
+++ b/drivers/gpio/ml_ioh_gpio.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+
+#define PCI_VENDOR_ID_ROHM 0x10DB
+
+struct ioh_reg_comn {
+ u32 ien;
+ u32 istatus;
+ u32 idisp;
+ u32 iclr;
+ u32 imask;
+ u32 imaskclr;
+ u32 po;
+ u32 pi;
+ u32 pm;
+ u32 im_0;
+ u32 im_1;
+ u32 reserved;
+};
+
+struct ioh_regs {
+ struct ioh_reg_comn regs[8];
+ u32 reserve1[16];
+ u32 ioh_sel_reg[4];
+ u32 reserve2[11];
+ u32 srst;
+};
+
+/**
+ * struct ioh_gpio_reg_data - The register store data.
+ * @po_reg: To store contents of PO register.
+ * @pm_reg: To store contents of PM register.
+ */
+struct ioh_gpio_reg_data {
+ u32 po_reg;
+ u32 pm_reg;
+};
+
+/**
+ * struct ioh_gpio - GPIO private data structure.
+ * @base: PCI base address of Memory mapped I/O register.
+ * @reg: Memory mapped IOH GPIO register list.
+ * @dev: Pointer to device structure.
+ * @gpio: Data for GPIO infrastructure.
+ * @ioh_gpio_reg: Memory mapped Register data is saved here
+ * when suspend.
+ * @ch: Indicate GPIO channel
+ */
+struct ioh_gpio {
+ void __iomem *base;
+ struct ioh_regs __iomem *reg;
+ struct device *dev;
+ struct gpio_chip gpio;
+ struct ioh_gpio_reg_data ioh_gpio_reg;
+ struct mutex lock;
+ int ch;
+};
+
+static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
+
+static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
+{
+ u32 reg_val;
+ struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+
+ mutex_lock(&chip->lock);
+ reg_val = ioread32(&chip->reg->regs[chip->ch].po);
+ if (val)
+ reg_val |= (1 << nr);
+ else
+ reg_val &= ~(1 << nr);
+
+ iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
+ mutex_unlock(&chip->lock);
+}
+
+static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
+{
+ struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+
+ return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr);
+}
+
+static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
+ int val)
+{
+ struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ u32 pm;
+ u32 reg_val;
+
+ mutex_lock(&chip->lock);
+ pm = ioread32(&chip->reg->regs[chip->ch].pm) &
+ ((1 << num_ports[chip->ch]) - 1);
+ pm |= (1 << nr);
+ iowrite32(pm, &chip->reg->regs[chip->ch].pm);
+
+ reg_val = ioread32(&chip->reg->regs[chip->ch].po);
+ if (val)
+ reg_val |= (1 << nr);
+ else
+ reg_val &= ~(1 << nr);
+
+ mutex_unlock(&chip->lock);
+
+ return 0;
+}
+
+static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
+{
+ struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+ u32 pm;
+
+ mutex_lock(&chip->lock);
+ pm = ioread32(&chip->reg->regs[chip->ch].pm) &
+ ((1 << num_ports[chip->ch]) - 1);
+ pm &= ~(1 << nr);
+ iowrite32(pm, &chip->reg->regs[chip->ch].pm);
+ mutex_unlock(&chip->lock);
+
+ return 0;
+}
+
+/*
+ * Save register configuration and disable interrupts.
+ */
+static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
+{
+ chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po);
+ chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm);
+}
+
+/*
+ * This function restores the register configuration of the GPIO device.
+ */
+static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
+{
+ /* to store contents of PO register */
+ iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po);
+ /* to store contents of PM register */
+ iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
+}
+
+static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
+{
+ struct gpio_chip *gpio = &chip->gpio;
+
+ gpio->label = dev_name(chip->dev);
+ gpio->owner = THIS_MODULE;
+ gpio->direction_input = ioh_gpio_direction_input;
+ gpio->get = ioh_gpio_get;
+ gpio->direction_output = ioh_gpio_direction_output;
+ gpio->set = ioh_gpio_set;
+ gpio->dbg_show = NULL;
+ gpio->base = -1;
+ gpio->ngpio = num_port;
+ gpio->can_sleep = 0;
+}
+
+static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret;
+ int i;
+ struct ioh_gpio *chip;
+ void __iomem *base;
+ void __iomem *chip_save;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__);
+ goto err_pci_enable;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_request_regions failed-%d", ret);
+ goto err_request_regions;
+ }
+
+ base = pci_iomap(pdev, 1, 0);
+ if (base == 0) {
+ dev_err(&pdev->dev, "%s : pci_iomap failed", __func__);
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL);
+ if (chip_save == NULL) {
+ dev_err(&pdev->dev, "%s : kzalloc failed", __func__);
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ chip = chip_save;
+ for (i = 0; i < 8; i++, chip++) {
+ chip->dev = &pdev->dev;
+ chip->base = base;
+ chip->reg = chip->base;
+ chip->ch = i;
+ mutex_init(&chip->lock);
+ ioh_gpio_setup(chip, num_ports[i]);
+ ret = gpiochip_add(&chip->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n");
+ goto err_gpiochip_add;
+ }
+ }
+
+ chip = chip_save;
+ pci_set_drvdata(pdev, chip);
+
+ return 0;
+
+err_gpiochip_add:
+ for (; i != 0; i--) {
+ chip--;
+ ret = gpiochip_remove(&chip->gpio);
+ if (ret)
+ dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
+ }
+ kfree(chip_save);
+
+err_kzalloc:
+ pci_iounmap(pdev, base);
+
+err_iomap:
+ pci_release_regions(pdev);
+
+err_request_regions:
+ pci_disable_device(pdev);
+
+err_pci_enable:
+
+ dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret);
+ return ret;
+}
+
+static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
+{
+ int err;
+ int i;
+ struct ioh_gpio *chip = pci_get_drvdata(pdev);
+ void __iomem *chip_save;
+
+ chip_save = chip;
+ for (i = 0; i < 8; i++, chip++) {
+ err = gpiochip_remove(&chip->gpio);
+ if (err)
+ dev_err(&pdev->dev, "Failed gpiochip_remove\n");
+ }
+
+ chip = chip_save;
+ pci_iounmap(pdev, chip->base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(chip);
+}
+
+#ifdef CONFIG_PM
+static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ s32 ret;
+ struct ioh_gpio *chip = pci_get_drvdata(pdev);
+
+ ioh_gpio_save_reg_conf(chip);
+ ioh_gpio_restore_reg_conf(chip);
+
+ ret = pci_save_state(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
+ return ret;
+ }
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_wake(pdev, PCI_D0, 1);
+ if (ret)
+ dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
+
+ return 0;
+}
+
+static int ioh_gpio_resume(struct pci_dev *pdev)
+{
+ s32 ret;
+ struct ioh_gpio *chip = pci_get_drvdata(pdev);
+
+ ret = pci_enable_wake(pdev, PCI_D0, 0);
+
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
+ return ret;
+ }
+ pci_restore_state(pdev);
+
+ iowrite32(0x01, &chip->reg->srst);
+ iowrite32(0x00, &chip->reg->srst);
+ ioh_gpio_restore_reg_conf(chip);
+
+ return 0;
+}
+#else
+#define ioh_gpio_suspend NULL
+#define ioh_gpio_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
+ { 0, }
+};
+
+static struct pci_driver ioh_gpio_driver = {
+ .name = "ml_ioh_gpio",
+ .id_table = ioh_gpio_pcidev_id,
+ .probe = ioh_gpio_probe,
+ .remove = __devexit_p(ioh_gpio_remove),
+ .suspend = ioh_gpio_suspend,
+ .resume = ioh_gpio_resume
+};
+
+static int __init ioh_gpio_pci_init(void)
+{
+ return pci_register_driver(&ioh_gpio_driver);
+}
+module_init(ioh_gpio_pci_init);
+
+static void __exit ioh_gpio_pci_exit(void)
+{
+ pci_unregister_driver(&ioh_gpio_driver);
+}
+module_exit(ioh_gpio_pci_exit);
+
+MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 501866662e05..a261972f603d 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -228,30 +228,30 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
return chip->irq_base + off;
}
-static void pca953x_irq_mask(unsigned int irq)
+static void pca953x_irq_mask(struct irq_data *d)
{
- struct pca953x_chip *chip = get_irq_chip_data(irq);
+ struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask &= ~(1 << (irq - chip->irq_base));
+ chip->irq_mask &= ~(1 << (d->irq - chip->irq_base));
}
-static void pca953x_irq_unmask(unsigned int irq)
+static void pca953x_irq_unmask(struct irq_data *d)
{
- struct pca953x_chip *chip = get_irq_chip_data(irq);
+ struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask |= 1 << (irq - chip->irq_base);
+ chip->irq_mask |= 1 << (d->irq - chip->irq_base);
}
-static void pca953x_irq_bus_lock(unsigned int irq)
+static void pca953x_irq_bus_lock(struct irq_data *d)
{
- struct pca953x_chip *chip = get_irq_chip_data(irq);
+ struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
mutex_lock(&chip->irq_lock);
}
-static void pca953x_irq_bus_sync_unlock(unsigned int irq)
+static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct pca953x_chip *chip = get_irq_chip_data(irq);
+ struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
uint16_t new_irqs;
uint16_t level;
@@ -268,15 +268,15 @@ static void pca953x_irq_bus_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static int pca953x_irq_set_type(unsigned int irq, unsigned int type)
+static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct pca953x_chip *chip = get_irq_chip_data(irq);
- uint16_t level = irq - chip->irq_base;
+ struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ uint16_t level = d->irq - chip->irq_base;
uint16_t mask = 1 << level;
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
- irq, type);
+ d->irq, type);
return -EINVAL;
}
@@ -295,11 +295,11 @@ static int pca953x_irq_set_type(unsigned int irq, unsigned int type)
static struct irq_chip pca953x_irq_chip = {
.name = "pca953x",
- .mask = pca953x_irq_mask,
- .unmask = pca953x_irq_unmask,
- .bus_lock = pca953x_irq_bus_lock,
- .bus_sync_unlock = pca953x_irq_bus_sync_unlock,
- .set_type = pca953x_irq_set_type,
+ .irq_mask = pca953x_irq_mask,
+ .irq_unmask = pca953x_irq_unmask,
+ .irq_bus_lock = pca953x_irq_bus_lock,
+ .irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock,
+ .irq_set_type = pca953x_irq_set_type,
};
static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c
index 5005990f751f..2975d22daffe 100644
--- a/drivers/gpio/pl061.c
+++ b/drivers/gpio/pl061.c
@@ -129,10 +129,10 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
/*
* PL061 GPIO IRQ
*/
-static void pl061_irq_disable(unsigned irq)
+static void pl061_irq_disable(struct irq_data *d)
{
- struct pl061_gpio *chip = get_irq_chip_data(irq);
- int offset = irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - chip->irq_base;
unsigned long flags;
u8 gpioie;
@@ -143,10 +143,10 @@ static void pl061_irq_disable(unsigned irq)
spin_unlock_irqrestore(&chip->irq_lock, flags);
}
-static void pl061_irq_enable(unsigned irq)
+static void pl061_irq_enable(struct irq_data *d)
{
- struct pl061_gpio *chip = get_irq_chip_data(irq);
- int offset = irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - chip->irq_base;
unsigned long flags;
u8 gpioie;
@@ -157,10 +157,10 @@ static void pl061_irq_enable(unsigned irq)
spin_unlock_irqrestore(&chip->irq_lock, flags);
}
-static int pl061_irq_type(unsigned irq, unsigned trigger)
+static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct pl061_gpio *chip = get_irq_chip_data(irq);
- int offset = irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - chip->irq_base;
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
@@ -203,9 +203,9 @@ static int pl061_irq_type(unsigned irq, unsigned trigger)
static struct irq_chip pl061_irqchip = {
.name = "GPIO",
- .enable = pl061_irq_enable,
- .disable = pl061_irq_disable,
- .set_type = pl061_irq_type,
+ .irq_enable = pl061_irq_enable,
+ .irq_disable = pl061_irq_disable,
+ .irq_set_type = pl061_irq_type,
};
static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
@@ -214,7 +214,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
struct list_head *ptr;
struct pl061_gpio *chip;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
list_for_each(ptr, chip_list) {
unsigned long pending;
int offset;
@@ -229,7 +229,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
generic_handle_irq(pl061_to_irq(&chip->gc, offset));
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static int pl061_probe(struct amba_device *dev, struct amba_id *id)
diff --git a/drivers/gpio/rdc321x-gpio.c b/drivers/gpio/rdc321x-gpio.c
index 2762698e0204..897e0577e65e 100644
--- a/drivers/gpio/rdc321x-gpio.c
+++ b/drivers/gpio/rdc321x-gpio.c
@@ -135,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
struct rdc321x_gpio *rdc321x_gpio_dev;
struct rdc321x_gpio_pdata *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = platform_get_drvdata(pdev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c
index 7c9e6a052c45..eb2901f8ab5e 100644
--- a/drivers/gpio/stmpe-gpio.c
+++ b/drivers/gpio/stmpe-gpio.c
@@ -122,10 +122,10 @@ static struct gpio_chip template_chip = {
.can_sleep = 1,
};
-static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type)
+static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
- int offset = irq - stmpe_gpio->irq_base;
+ struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -145,16 +145,16 @@ static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type)
return 0;
}
-static void stmpe_gpio_irq_lock(unsigned int irq)
+static void stmpe_gpio_irq_lock(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
mutex_lock(&stmpe_gpio->irq_lock);
}
-static void stmpe_gpio_irq_sync_unlock(unsigned int irq)
+static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
static const u8 regmap[] = {
@@ -180,20 +180,20 @@ static void stmpe_gpio_irq_sync_unlock(unsigned int irq)
mutex_unlock(&stmpe_gpio->irq_lock);
}
-static void stmpe_gpio_irq_mask(unsigned int irq)
+static void stmpe_gpio_irq_mask(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
- int offset = irq - stmpe_gpio->irq_base;
+ struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
}
-static void stmpe_gpio_irq_unmask(unsigned int irq)
+static void stmpe_gpio_irq_unmask(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
- int offset = irq - stmpe_gpio->irq_base;
+ struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -202,11 +202,11 @@ static void stmpe_gpio_irq_unmask(unsigned int irq)
static struct irq_chip stmpe_gpio_irq_chip = {
.name = "stmpe-gpio",
- .bus_lock = stmpe_gpio_irq_lock,
- .bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
- .mask = stmpe_gpio_irq_mask,
- .unmask = stmpe_gpio_irq_unmask,
- .set_type = stmpe_gpio_irq_set_type,
+ .irq_bus_lock = stmpe_gpio_irq_lock,
+ .irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
+ .irq_mask = stmpe_gpio_irq_mask,
+ .irq_unmask = stmpe_gpio_irq_unmask,
+ .irq_set_type = stmpe_gpio_irq_set_type,
};
static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c
index 823559ab0e24..e60be0015c9b 100644
--- a/drivers/gpio/sx150x.c
+++ b/drivers/gpio/sx150x.c
@@ -304,36 +304,36 @@ static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return chip->irq_base + offset;
}
-static void sx150x_irq_mask(unsigned int irq)
+static void sx150x_irq_mask(struct irq_data *d)
{
- struct irq_chip *ic = get_irq_chip(irq);
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
struct sx150x_chip *chip;
unsigned n;
chip = container_of(ic, struct sx150x_chip, irq_chip);
- n = irq - chip->irq_base;
+ n = d->irq - chip->irq_base;
sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1);
sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0);
}
-static void sx150x_irq_unmask(unsigned int irq)
+static void sx150x_irq_unmask(struct irq_data *d)
{
- struct irq_chip *ic = get_irq_chip(irq);
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
struct sx150x_chip *chip;
unsigned n;
chip = container_of(ic, struct sx150x_chip, irq_chip);
- n = irq - chip->irq_base;
+ n = d->irq - chip->irq_base;
sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0);
sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense,
chip->irq_sense >> (n * 2));
}
-static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct irq_chip *ic = get_irq_chip(irq);
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
struct sx150x_chip *chip;
unsigned n, val = 0;
@@ -341,7 +341,7 @@ static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type)
return -EINVAL;
chip = container_of(ic, struct sx150x_chip, irq_chip);
- n = irq - chip->irq_base;
+ n = d->irq - chip->irq_base;
if (flow_type & IRQ_TYPE_EDGE_RISING)
val |= 0x1;
@@ -386,9 +386,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}
-static void sx150x_irq_bus_lock(unsigned int irq)
+static void sx150x_irq_bus_lock(struct irq_data *d)
{
- struct irq_chip *ic = get_irq_chip(irq);
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
struct sx150x_chip *chip;
chip = container_of(ic, struct sx150x_chip, irq_chip);
@@ -396,9 +396,9 @@ static void sx150x_irq_bus_lock(unsigned int irq)
mutex_lock(&chip->lock);
}
-static void sx150x_irq_bus_sync_unlock(unsigned int irq)
+static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct irq_chip *ic = get_irq_chip(irq);
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
struct sx150x_chip *chip;
unsigned n;
@@ -437,16 +437,16 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
if (pdata->oscio_is_gpo)
++chip->gpio_chip.ngpio;
- chip->irq_chip.name = client->name;
- chip->irq_chip.mask = sx150x_irq_mask;
- chip->irq_chip.unmask = sx150x_irq_unmask;
- chip->irq_chip.set_type = sx150x_irq_set_type;
- chip->irq_chip.bus_lock = sx150x_irq_bus_lock;
- chip->irq_chip.bus_sync_unlock = sx150x_irq_bus_sync_unlock;
- chip->irq_summary = -1;
- chip->irq_base = -1;
- chip->irq_sense = 0;
- chip->irq_set_type_pending = 0;
+ chip->irq_chip.name = client->name;
+ chip->irq_chip.irq_mask = sx150x_irq_mask;
+ chip->irq_chip.irq_unmask = sx150x_irq_unmask;
+ chip->irq_chip.irq_set_type = sx150x_irq_set_type;
+ chip->irq_chip.irq_bus_lock = sx150x_irq_bus_lock;
+ chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock;
+ chip->irq_summary = -1;
+ chip->irq_base = -1;
+ chip->irq_sense = 0;
+ chip->irq_set_type_pending = 0;
}
static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg)
diff --git a/drivers/gpio/tc35892-gpio.c b/drivers/gpio/tc35892-gpio.c
deleted file mode 100644
index 7e10c935a047..000000000000
--- a/drivers/gpio/tc35892-gpio.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License, version 2
- * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/tc35892.h>
-
-/*
- * These registers are modified under the irq bus lock and cached to avoid
- * unnecessary writes in bus_sync_unlock.
- */
-enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
-
-#define CACHE_NR_REGS 4
-#define CACHE_NR_BANKS 3
-
-struct tc35892_gpio {
- struct gpio_chip chip;
- struct tc35892 *tc35892;
- struct device *dev;
- struct mutex irq_lock;
-
- int irq_base;
-
- /* Caches of interrupt control registers for bus_lock */
- u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
- u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
-};
-
-static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct tc35892_gpio, chip);
-}
-
-static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
- u8 mask = 1 << (offset % 8);
- int ret;
-
- ret = tc35892_reg_read(tc35892, reg);
- if (ret < 0)
- return ret;
-
- return ret & mask;
-}
-
-static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
- unsigned pos = offset % 8;
- u8 data[] = {!!val << pos, 1 << pos};
-
- tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data);
-}
-
-static int tc35892_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int val)
-{
- struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- u8 reg = TC35892_GPIODIR0 + offset / 8;
- unsigned pos = offset % 8;
-
- tc35892_gpio_set(chip, offset, val);
-
- return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos);
-}
-
-static int tc35892_gpio_direction_input(struct gpio_chip *chip,
- unsigned offset)
-{
- struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- u8 reg = TC35892_GPIODIR0 + offset / 8;
- unsigned pos = offset % 8;
-
- return tc35892_set_bits(tc35892, reg, 1 << pos, 0);
-}
-
-static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
-
- return tc35892_gpio->irq_base + offset;
-}
-
-static struct gpio_chip template_chip = {
- .label = "tc35892",
- .owner = THIS_MODULE,
- .direction_input = tc35892_gpio_direction_input,
- .get = tc35892_gpio_get,
- .direction_output = tc35892_gpio_direction_output,
- .set = tc35892_gpio_set,
- .to_irq = tc35892_gpio_to_irq,
- .can_sleep = 1,
-};
-
-static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type)
-{
- struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
- int offset = irq - tc35892_gpio->irq_base;
- int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
-
- if (type == IRQ_TYPE_EDGE_BOTH) {
- tc35892_gpio->regs[REG_IBE][regoffset] |= mask;
- return 0;
- }
-
- tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask;
-
- if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
- tc35892_gpio->regs[REG_IS][regoffset] |= mask;
- else
- tc35892_gpio->regs[REG_IS][regoffset] &= ~mask;
-
- if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
- tc35892_gpio->regs[REG_IEV][regoffset] |= mask;
- else
- tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask;
-
- return 0;
-}
-
-static void tc35892_gpio_irq_lock(unsigned int irq)
-{
- struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
-
- mutex_lock(&tc35892_gpio->irq_lock);
-}
-
-static void tc35892_gpio_irq_sync_unlock(unsigned int irq)
-{
- struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- static const u8 regmap[] = {
- [REG_IBE] = TC35892_GPIOIBE0,
- [REG_IEV] = TC35892_GPIOIEV0,
- [REG_IS] = TC35892_GPIOIS0,
- [REG_IE] = TC35892_GPIOIE0,
- };
- int i, j;
-
- for (i = 0; i < CACHE_NR_REGS; i++) {
- for (j = 0; j < CACHE_NR_BANKS; j++) {
- u8 old = tc35892_gpio->oldregs[i][j];
- u8 new = tc35892_gpio->regs[i][j];
-
- if (new == old)
- continue;
-
- tc35892_gpio->oldregs[i][j] = new;
- tc35892_reg_write(tc35892, regmap[i] + j * 8, new);
- }
- }
-
- mutex_unlock(&tc35892_gpio->irq_lock);
-}
-
-static void tc35892_gpio_irq_mask(unsigned int irq)
-{
- struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
- int offset = irq - tc35892_gpio->irq_base;
- int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
-
- tc35892_gpio->regs[REG_IE][regoffset] &= ~mask;
-}
-
-static void tc35892_gpio_irq_unmask(unsigned int irq)
-{
- struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
- int offset = irq - tc35892_gpio->irq_base;
- int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
-
- tc35892_gpio->regs[REG_IE][regoffset] |= mask;
-}
-
-static struct irq_chip tc35892_gpio_irq_chip = {
- .name = "tc35892-gpio",
- .bus_lock = tc35892_gpio_irq_lock,
- .bus_sync_unlock = tc35892_gpio_irq_sync_unlock,
- .mask = tc35892_gpio_irq_mask,
- .unmask = tc35892_gpio_irq_unmask,
- .set_type = tc35892_gpio_irq_set_type,
-};
-
-static irqreturn_t tc35892_gpio_irq(int irq, void *dev)
-{
- struct tc35892_gpio *tc35892_gpio = dev;
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- u8 status[CACHE_NR_BANKS];
- int ret;
- int i;
-
- ret = tc35892_block_read(tc35892, TC35892_GPIOMIS0,
- ARRAY_SIZE(status), status);
- if (ret < 0)
- return IRQ_NONE;
-
- for (i = 0; i < ARRAY_SIZE(status); i++) {
- unsigned int stat = status[i];
- if (!stat)
- continue;
-
- while (stat) {
- int bit = __ffs(stat);
- int line = i * 8 + bit;
-
- handle_nested_irq(tc35892_gpio->irq_base + line);
- stat &= ~(1 << bit);
- }
-
- tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]);
- }
-
- return IRQ_HANDLED;
-}
-
-static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio)
-{
- int base = tc35892_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) {
- set_irq_chip_data(irq, tc35892_gpio);
- set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip,
- handle_simple_irq);
- set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- set_irq_noprobe(irq);
-#endif
- }
-
- return 0;
-}
-
-static void tc35892_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio)
-{
- int base = tc35892_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- set_irq_chip_and_handler(irq, NULL, NULL);
- set_irq_chip_data(irq, NULL);
- }
-}
-
-static int __devinit tc35892_gpio_probe(struct platform_device *pdev)
-{
- struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent);
- struct tc35892_gpio_platform_data *pdata;
- struct tc35892_gpio *tc35892_gpio;
- int ret;
- int irq;
-
- pdata = tc35892->pdata->gpio;
- if (!pdata)
- return -ENODEV;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL);
- if (!tc35892_gpio)
- return -ENOMEM;
-
- mutex_init(&tc35892_gpio->irq_lock);
-
- tc35892_gpio->dev = &pdev->dev;
- tc35892_gpio->tc35892 = tc35892;
-
- tc35892_gpio->chip = template_chip;
- tc35892_gpio->chip.ngpio = tc35892->num_gpio;
- tc35892_gpio->chip.dev = &pdev->dev;
- tc35892_gpio->chip.base = pdata->gpio_base;
-
- tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0);
-
- /* Bring the GPIO module out of reset */
- ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL,
- TC35892_RSTCTRL_GPIRST, 0);
- if (ret < 0)
- goto out_free;
-
- ret = tc35892_gpio_irq_init(tc35892_gpio);
- if (ret)
- goto out_free;
-
- ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT,
- "tc35892-gpio", tc35892_gpio);
- if (ret) {
- dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_removeirq;
- }
-
- ret = gpiochip_add(&tc35892_gpio->chip);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- goto out_freeirq;
- }
-
- if (pdata->setup)
- pdata->setup(tc35892, tc35892_gpio->chip.base);
-
- platform_set_drvdata(pdev, tc35892_gpio);
-
- return 0;
-
-out_freeirq:
- free_irq(irq, tc35892_gpio);
-out_removeirq:
- tc35892_gpio_irq_remove(tc35892_gpio);
-out_free:
- kfree(tc35892_gpio);
- return ret;
-}
-
-static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
-{
- struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
- struct tc35892 *tc35892 = tc35892_gpio->tc35892;
- struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
- int irq = platform_get_irq(pdev, 0);
- int ret;
-
- if (pdata->remove)
- pdata->remove(tc35892, tc35892_gpio->chip.base);
-
- ret = gpiochip_remove(&tc35892_gpio->chip);
- if (ret < 0) {
- dev_err(tc35892_gpio->dev,
- "unable to remove gpiochip: %d\n", ret);
- return ret;
- }
-
- free_irq(irq, tc35892_gpio);
- tc35892_gpio_irq_remove(tc35892_gpio);
-
- platform_set_drvdata(pdev, NULL);
- kfree(tc35892_gpio);
-
- return 0;
-}
-
-static struct platform_driver tc35892_gpio_driver = {
- .driver.name = "tc35892-gpio",
- .driver.owner = THIS_MODULE,
- .probe = tc35892_gpio_probe,
- .remove = __devexit_p(tc35892_gpio_remove),
-};
-
-static int __init tc35892_gpio_init(void)
-{
- return platform_driver_register(&tc35892_gpio_driver);
-}
-subsys_initcall(tc35892_gpio_init);
-
-static void __exit tc35892_gpio_exit(void)
-{
- platform_driver_unregister(&tc35892_gpio_driver);
-}
-module_exit(tc35892_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("TC35892 GPIO driver");
-MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c
new file mode 100644
index 000000000000..27200af1a595
--- /dev/null
+++ b/drivers/gpio/tc3589x-gpio.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/tc3589x.h>
+
+/*
+ * These registers are modified under the irq bus lock and cached to avoid
+ * unnecessary writes in bus_sync_unlock.
+ */
+enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
+
+#define CACHE_NR_REGS 4
+#define CACHE_NR_BANKS 3
+
+struct tc3589x_gpio {
+ struct gpio_chip chip;
+ struct tc3589x *tc3589x;
+ struct device *dev;
+ struct mutex irq_lock;
+
+ int irq_base;
+
+ /* Caches of interrupt control registers for bus_lock */
+ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
+ u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
+};
+
+static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct tc3589x_gpio, chip);
+}
+
+static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
+ u8 mask = 1 << (offset % 8);
+ int ret;
+
+ ret = tc3589x_reg_read(tc3589x, reg);
+ if (ret < 0)
+ return ret;
+
+ return ret & mask;
+}
+
+static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
+ unsigned pos = offset % 8;
+ u8 data[] = {!!val << pos, 1 << pos};
+
+ tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
+}
+
+static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int val)
+{
+ struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ u8 reg = TC3589x_GPIODIR0 + offset / 8;
+ unsigned pos = offset % 8;
+
+ tc3589x_gpio_set(chip, offset, val);
+
+ return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos);
+}
+
+static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ u8 reg = TC3589x_GPIODIR0 + offset / 8;
+ unsigned pos = offset % 8;
+
+ return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
+}
+
+static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+
+ return tc3589x_gpio->irq_base + offset;
+}
+
+static struct gpio_chip template_chip = {
+ .label = "tc3589x",
+ .owner = THIS_MODULE,
+ .direction_input = tc3589x_gpio_direction_input,
+ .get = tc3589x_gpio_get,
+ .direction_output = tc3589x_gpio_direction_output,
+ .set = tc3589x_gpio_set,
+ .to_irq = tc3589x_gpio_to_irq,
+ .can_sleep = 1,
+};
+
+static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tc3589x_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ if (type == IRQ_TYPE_EDGE_BOTH) {
+ tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
+ return 0;
+ }
+
+ tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask;
+
+ if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+ tc3589x_gpio->regs[REG_IS][regoffset] |= mask;
+ else
+ tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask;
+
+ if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
+ tc3589x_gpio->regs[REG_IEV][regoffset] |= mask;
+ else
+ tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask;
+
+ return 0;
+}
+
+static void tc3589x_gpio_irq_lock(struct irq_data *d)
+{
+ struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+
+ mutex_lock(&tc3589x_gpio->irq_lock);
+}
+
+static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
+{
+ struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ static const u8 regmap[] = {
+ [REG_IBE] = TC3589x_GPIOIBE0,
+ [REG_IEV] = TC3589x_GPIOIEV0,
+ [REG_IS] = TC3589x_GPIOIS0,
+ [REG_IE] = TC3589x_GPIOIE0,
+ };
+ int i, j;
+
+ for (i = 0; i < CACHE_NR_REGS; i++) {
+ for (j = 0; j < CACHE_NR_BANKS; j++) {
+ u8 old = tc3589x_gpio->oldregs[i][j];
+ u8 new = tc3589x_gpio->regs[i][j];
+
+ if (new == old)
+ continue;
+
+ tc3589x_gpio->oldregs[i][j] = new;
+ tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
+ }
+ }
+
+ mutex_unlock(&tc3589x_gpio->irq_lock);
+}
+
+static void tc3589x_gpio_irq_mask(struct irq_data *d)
+{
+ struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tc3589x_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
+}
+
+static void tc3589x_gpio_irq_unmask(struct irq_data *d)
+{
+ struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tc3589x_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
+}
+
+static struct irq_chip tc3589x_gpio_irq_chip = {
+ .name = "tc3589x-gpio",
+ .irq_bus_lock = tc3589x_gpio_irq_lock,
+ .irq_bus_sync_unlock = tc3589x_gpio_irq_sync_unlock,
+ .irq_mask = tc3589x_gpio_irq_mask,
+ .irq_unmask = tc3589x_gpio_irq_unmask,
+ .irq_set_type = tc3589x_gpio_irq_set_type,
+};
+
+static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
+{
+ struct tc3589x_gpio *tc3589x_gpio = dev;
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ u8 status[CACHE_NR_BANKS];
+ int ret;
+ int i;
+
+ ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0,
+ ARRAY_SIZE(status), status);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(status); i++) {
+ unsigned int stat = status[i];
+ if (!stat)
+ continue;
+
+ while (stat) {
+ int bit = __ffs(stat);
+ int line = i * 8 + bit;
+
+ handle_nested_irq(tc3589x_gpio->irq_base + line);
+ stat &= ~(1 << bit);
+ }
+
+ tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
+{
+ int base = tc3589x_gpio->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
+ set_irq_chip_data(irq, tc3589x_gpio);
+ set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
+ handle_simple_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ return 0;
+}
+
+static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio)
+{
+ int base = tc3589x_gpio->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ set_irq_chip_and_handler(irq, NULL, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
+}
+
+static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
+{
+ struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
+ struct tc3589x_gpio_platform_data *pdata;
+ struct tc3589x_gpio *tc3589x_gpio;
+ int ret;
+ int irq;
+
+ pdata = tc3589x->pdata->gpio;
+ if (!pdata)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL);
+ if (!tc3589x_gpio)
+ return -ENOMEM;
+
+ mutex_init(&tc3589x_gpio->irq_lock);
+
+ tc3589x_gpio->dev = &pdev->dev;
+ tc3589x_gpio->tc3589x = tc3589x;
+
+ tc3589x_gpio->chip = template_chip;
+ tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
+ tc3589x_gpio->chip.dev = &pdev->dev;
+ tc3589x_gpio->chip.base = pdata->gpio_base;
+
+ tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0);
+
+ /* Bring the GPIO module out of reset */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
+ TC3589x_RSTCTRL_GPIRST, 0);
+ if (ret < 0)
+ goto out_free;
+
+ ret = tc3589x_gpio_irq_init(tc3589x_gpio);
+ if (ret)
+ goto out_free;
+
+ ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT,
+ "tc3589x-gpio", tc3589x_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+ goto out_removeirq;
+ }
+
+ ret = gpiochip_add(&tc3589x_gpio->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+ goto out_freeirq;
+ }
+
+ if (pdata->setup)
+ pdata->setup(tc3589x, tc3589x_gpio->chip.base);
+
+ platform_set_drvdata(pdev, tc3589x_gpio);
+
+ return 0;
+
+out_freeirq:
+ free_irq(irq, tc3589x_gpio);
+out_removeirq:
+ tc3589x_gpio_irq_remove(tc3589x_gpio);
+out_free:
+ kfree(tc3589x_gpio);
+ return ret;
+}
+
+static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
+{
+ struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
+ int irq = platform_get_irq(pdev, 0);
+ int ret;
+
+ if (pdata->remove)
+ pdata->remove(tc3589x, tc3589x_gpio->chip.base);
+
+ ret = gpiochip_remove(&tc3589x_gpio->chip);
+ if (ret < 0) {
+ dev_err(tc3589x_gpio->dev,
+ "unable to remove gpiochip: %d\n", ret);
+ return ret;
+ }
+
+ free_irq(irq, tc3589x_gpio);
+ tc3589x_gpio_irq_remove(tc3589x_gpio);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(tc3589x_gpio);
+
+ return 0;
+}
+
+static struct platform_driver tc3589x_gpio_driver = {
+ .driver.name = "tc3589x-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = tc3589x_gpio_probe,
+ .remove = __devexit_p(tc3589x_gpio_remove),
+};
+
+static int __init tc3589x_gpio_init(void)
+{
+ return platform_driver_register(&tc3589x_gpio_driver);
+}
+subsys_initcall(tc3589x_gpio_init);
+
+static void __exit tc3589x_gpio_exit(void)
+{
+ platform_driver_unregister(&tc3589x_gpio_driver);
+}
+module_exit(tc3589x_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TC3589x GPIO driver");
+MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index 45293662e950..58c8f30352dd 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -109,10 +109,10 @@ static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)
/*
* GPIO IRQ
*/
-static void timbgpio_irq_disable(unsigned irq)
+static void timbgpio_irq_disable(struct irq_data *d)
{
- struct timbgpio *tgpio = get_irq_chip_data(irq);
- int offset = irq - tgpio->irq_base;
+ struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tgpio->irq_base;
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
@@ -121,10 +121,10 @@ static void timbgpio_irq_disable(unsigned irq)
spin_unlock_irqrestore(&tgpio->lock, flags);
}
-static void timbgpio_irq_enable(unsigned irq)
+static void timbgpio_irq_enable(struct irq_data *d)
{
- struct timbgpio *tgpio = get_irq_chip_data(irq);
- int offset = irq - tgpio->irq_base;
+ struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tgpio->irq_base;
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
@@ -133,10 +133,10 @@ static void timbgpio_irq_enable(unsigned irq)
spin_unlock_irqrestore(&tgpio->lock, flags);
}
-static int timbgpio_irq_type(unsigned irq, unsigned trigger)
+static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
{
- struct timbgpio *tgpio = get_irq_chip_data(irq);
- int offset = irq - tgpio->irq_base;
+ struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - tgpio->irq_base;
unsigned long flags;
u32 lvr, flr, bflr = 0;
u32 ver;
@@ -199,7 +199,7 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
unsigned long ipr;
int offset;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(irq_get_irq_data(irq));
ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR);
@@ -217,9 +217,9 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
static struct irq_chip timbgpio_irqchip = {
.name = "GPIO",
- .enable = timbgpio_irq_enable,
- .disable = timbgpio_irq_disable,
- .set_type = timbgpio_irq_type,
+ .irq_enable = timbgpio_irq_enable,
+ .irq_disable = timbgpio_irq_disable,
+ .irq_set_type = timbgpio_irq_type,
};
static int __devinit timbgpio_probe(struct platform_device *pdev)
diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c
index b16c9a8c03f5..cffa3bd7ad3b 100644
--- a/drivers/gpio/vr41xx_giu.c
+++ b/drivers/gpio/vr41xx_giu.c
@@ -111,69 +111,69 @@ static inline u16 giu_clear(u16 offset, u16 clear)
return data;
}
-static void ack_giuint_low(unsigned int irq)
+static void ack_giuint_low(struct irq_data *d)
{
- giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
+ giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
-static void mask_giuint_low(unsigned int irq)
+static void mask_giuint_low(struct irq_data *d)
{
- giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+ giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
-static void mask_ack_giuint_low(unsigned int irq)
+static void mask_ack_giuint_low(struct irq_data *d)
{
unsigned int pin;
- pin = GPIO_PIN_OF_IRQ(irq);
+ pin = GPIO_PIN_OF_IRQ(d->irq);
giu_clear(GIUINTENL, 1 << pin);
giu_write(GIUINTSTATL, 1 << pin);
}
-static void unmask_giuint_low(unsigned int irq)
+static void unmask_giuint_low(struct irq_data *d)
{
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+ giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
static struct irq_chip giuint_low_irq_chip = {
.name = "GIUINTL",
- .ack = ack_giuint_low,
- .mask = mask_giuint_low,
- .mask_ack = mask_ack_giuint_low,
- .unmask = unmask_giuint_low,
+ .irq_ack = ack_giuint_low,
+ .irq_mask = mask_giuint_low,
+ .irq_mask_ack = mask_ack_giuint_low,
+ .irq_unmask = unmask_giuint_low,
};
-static void ack_giuint_high(unsigned int irq)
+static void ack_giuint_high(struct irq_data *d)
{
giu_write(GIUINTSTATH,
- 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+ 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
-static void mask_giuint_high(unsigned int irq)
+static void mask_giuint_high(struct irq_data *d)
{
- giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+ giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
-static void mask_ack_giuint_high(unsigned int irq)
+static void mask_ack_giuint_high(struct irq_data *d)
{
unsigned int pin;
- pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+ pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET;
giu_clear(GIUINTENH, 1 << pin);
giu_write(GIUINTSTATH, 1 << pin);
}
-static void unmask_giuint_high(unsigned int irq)
+static void unmask_giuint_high(struct irq_data *d)
{
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+ giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
static struct irq_chip giuint_high_irq_chip = {
.name = "GIUINTH",
- .ack = ack_giuint_high,
- .mask = mask_giuint_high,
- .mask_ack = mask_ack_giuint_high,
- .unmask = unmask_giuint_high,
+ .irq_ack = ack_giuint_high,
+ .irq_mask = mask_giuint_high,
+ .irq_mask_ack = mask_ack_giuint_high,
+ .irq_unmask = unmask_giuint_high,
};
static int giu_get_irq(unsigned int irq)
diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c
index 618398e4ed8e..c822baacd8fc 100644
--- a/drivers/gpio/wm8994-gpio.c
+++ b/drivers/gpio/wm8994-gpio.c
@@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
return container_of(chip, struct wm8994_gpio, gpio_chip);
}
+static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+ switch (wm8994->type) {
+ case WM8958:
+ switch (offset) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ return -EINVAL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
@@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static struct gpio_chip template_chip = {
.label = "wm8994",
.owner = THIS_MODULE,
+ .request = wm8994_gpio_request,
.direction_input = wm8994_gpio_direction_in,
.get = wm8994_gpio_get,
.direction_output = wm8994_gpio_direction_out,
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 7af443672626..64828a7db77b 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -107,7 +107,6 @@ config DRM_I915
select FB_CFB_IMAGEBLIT
# i915 depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
- select VIDEO_OUTPUT_CONTROL if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select ACPI_VIDEO if ACPI
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c
index 252fdb98b73a..0cb2ba50af53 100644
--- a/drivers/gpu/drm/drm_agpsupport.c
+++ b/drivers/gpu/drm/drm_agpsupport.c
@@ -466,10 +466,4 @@ drm_agp_bind_pages(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_agp_bind_pages);
-void drm_agp_chipset_flush(struct drm_device *dev)
-{
- agp_flush_chipset(dev->agp->bridge);
-}
-EXPORT_SYMBOL(drm_agp_chipset_flush);
-
#endif /* __OS_HAS_AGP */
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 6985cb1da72c..2baa6708e44c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -156,12 +156,12 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
{ DRM_MODE_CONNECTOR_Component, "Component", 0 },
- { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 },
- { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
- { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
- { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
+ { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
+ { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
+ { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
+ { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
{ DRM_MODE_CONNECTOR_TV, "TV", 0 },
- { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort", 0 },
+ { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
};
static struct drm_prop_enum_list drm_encoder_enum_list[] =
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index dcbeb98f195a..952b3d4fb2a6 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -276,7 +276,7 @@ static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
struct drm_crtc *tmp;
int crtc_mask = 1;
- WARN(!crtc, "checking null crtc?");
+ WARN(!crtc, "checking null crtc?\n");
dev = crtc->dev;
@@ -336,7 +336,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode, saved_mode;
+ struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_encoder_helper_funcs *encoder_funcs;
int saved_x, saved_y;
@@ -350,6 +350,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!crtc->enabled)
return true;
+ saved_hwmode = crtc->hwmode;
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
@@ -427,11 +428,21 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
}
+ /* Store real post-adjustment hardware mode. */
+ crtc->hwmode = *adjusted_mode;
+
+ /* Calculate and store various constants which
+ * are later needed by vblank and swap-completion
+ * timestamping. They are derived from true hwmode.
+ */
+ drm_calc_timestamping_constants(crtc);
+
/* XXX free adjustedmode */
drm_mode_destroy(dev, adjusted_mode);
/* FIXME: add subpixel order */
done:
if (!ret) {
+ crtc->hwmode = saved_hwmode;
crtc->mode = saved_mode;
crtc->x = saved_x;
crtc->y = saved_y;
@@ -471,6 +482,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs;
int ret = 0;
+ int i;
DRM_DEBUG_KMS("\n");
@@ -649,6 +661,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
old_fb)) {
DRM_ERROR("failed to set mode on [CRTC:%d]\n",
set->crtc->base.id);
+ set->crtc->fb = old_fb;
ret = -EINVAL;
goto fail;
}
@@ -663,8 +676,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
set->crtc->fb = set->fb;
ret = crtc_funcs->mode_set_base(set->crtc,
set->x, set->y, old_fb);
- if (ret != 0)
+ if (ret != 0) {
+ set->crtc->fb = old_fb;
goto fail;
+ }
+ }
+ DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+ for (i = 0; i < set->num_connectors; i++) {
+ DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+ drm_get_connector_name(set->connectors[i]));
+ set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
}
kfree(save_connectors);
@@ -841,7 +862,7 @@ static void output_poll_execute(struct work_struct *work)
struct delayed_work *delayed_work = to_delayed_work(work);
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
- enum drm_connector_status old_status, status;
+ enum drm_connector_status old_status;
bool repoll = false, changed = false;
if (!drm_kms_helper_poll)
@@ -866,8 +887,12 @@ static void output_poll_execute(struct work_struct *work)
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
- status = connector->funcs->detect(connector, false);
- if (old_status != status)
+ connector->status = connector->funcs->detect(connector, false);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ connector->base.id,
+ drm_get_connector_name(connector),
+ old_status, connector->status);
+ if (old_status != connector->status)
changed = true;
}
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index c1a26217a530..a245d17165ae 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -240,7 +240,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
.addr = DDC_ADDR,
.flags = I2C_M_RD,
.len = len,
- .buf = buf + start,
+ .buf = buf,
}
};
@@ -253,7 +253,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
static u8 *
drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
{
- int i, j = 0;
+ int i, j = 0, valid_extensions = 0;
u8 *block, *new;
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
@@ -280,14 +280,28 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
for (j = 1; j <= block[0x7e]; j++) {
for (i = 0; i < 4; i++) {
- if (drm_do_probe_ddc_edid(adapter, block, j,
- EDID_LENGTH))
+ if (drm_do_probe_ddc_edid(adapter,
+ block + (valid_extensions + 1) * EDID_LENGTH,
+ j, EDID_LENGTH))
goto out;
- if (drm_edid_block_valid(block + j * EDID_LENGTH))
+ if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
+ valid_extensions++;
break;
+ }
}
if (i == 4)
- goto carp;
+ dev_warn(connector->dev->dev,
+ "%s: Ignoring invalid EDID block %d.\n",
+ drm_get_connector_name(connector), j);
+ }
+
+ if (valid_extensions != block[0x7e]) {
+ block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
+ block[0x7e] = valid_extensions;
+ new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+ if (!new)
+ goto out;
+ block = new;
}
return block;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d2849e4ea4d0..5c4f9b9ecdc0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -985,6 +985,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
FB_VISUAL_TRUECOLOR;
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
info->fix.type_aux = 0;
info->fix.xpanstep = 1; /* doing it in hw */
info->fix.ypanstep = 1; /* doing it in hw */
@@ -1005,6 +1007,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
info->var.xres_virtual = fb->width;
info->var.yres_virtual = fb->height;
info->var.bits_per_pixel = fb->bits_per_pixel;
+ info->var.accel_flags = FB_ACCELF_TEXT;
info->var.xoffset = 0;
info->var.yoffset = 0;
info->var.activate = FB_ACTIVATE_NOW;
@@ -1530,3 +1533,24 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
}
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
+/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EMBEDDED)
+ * but the module doesn't depend on any fb console symbols. At least
+ * attempt to load fbcon to avoid leaving the system without a usable console.
+ */
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EMBEDDED)
+static int __init drm_fb_helper_modinit(void)
+{
+ const char *name = "fbcon";
+ struct module *fbcon;
+
+ mutex_lock(&module_mutex);
+ fbcon = find_module(name);
+ mutex_unlock(&module_mutex);
+
+ if (!fbcon)
+ request_module_nowait(name);
+ return 0;
+}
+
+module_init(drm_fb_helper_modinit);
+#endif
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index b744dad5c237..2ec7d48fc4a8 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -37,7 +37,6 @@
#include "drmP.h"
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
/* from BKL pushdown: note that nothing else serializes idr_find() */
DEFINE_MUTEX(drm_global_mutex);
@@ -237,6 +236,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
return -EBUSY; /* No exclusive opens */
if (!drm_cpu_valid())
return -EINVAL;
+ if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
+ return -EINVAL;
DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 9d3a5030b6e1..0054e957203f 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -40,6 +40,22 @@
#include <linux/slab.h>
#include <linux/vgaarb.h>
+
+/* Access macro for slots in vblank timestamp ringbuffer. */
+#define vblanktimestamp(dev, crtc, count) ( \
+ (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
+ ((count) % DRM_VBLANKTIME_RBSIZE)])
+
+/* Retry timestamp calculation up to 3 times to satisfy
+ * drm_timestamp_precision before giving up.
+ */
+#define DRM_TIMESTAMP_MAXRETRIES 3
+
+/* Threshold in nanoseconds for detection of redundant
+ * vblank irq in drm_handle_vblank(). 1 msec should be ok.
+ */
+#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
+
/**
* Get interrupt from bus id.
*
@@ -77,6 +93,87 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
return 0;
}
+/*
+ * Clear vblank timestamp buffer for a crtc.
+ */
+static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
+{
+ memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
+ DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
+}
+
+/*
+ * Disable vblank irq's on crtc, make sure that last vblank count
+ * of hardware and corresponding consistent software vblank counter
+ * are preserved, even if there are any spurious vblank irq's after
+ * disable.
+ */
+static void vblank_disable_and_save(struct drm_device *dev, int crtc)
+{
+ unsigned long irqflags;
+ u32 vblcount;
+ s64 diff_ns;
+ int vblrc;
+ struct timeval tvblank;
+
+ /* Prevent vblank irq processing while disabling vblank irqs,
+ * so no updates of timestamps or count can happen after we've
+ * disabled. Needed to prevent races in case of delayed irq's.
+ * Disable preemption, so vblank_time_lock is held as short as
+ * possible, even under a kernel with PREEMPT_RT patches.
+ */
+ preempt_disable();
+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
+
+ dev->driver->disable_vblank(dev, crtc);
+ dev->vblank_enabled[crtc] = 0;
+
+ /* No further vblank irq's will be processed after
+ * this point. Get current hardware vblank count and
+ * vblank timestamp, repeat until they are consistent.
+ *
+ * FIXME: There is still a race condition here and in
+ * drm_update_vblank_count() which can cause off-by-one
+ * reinitialization of software vblank counter. If gpu
+ * vblank counter doesn't increment exactly at the leading
+ * edge of a vblank interval, then we can lose 1 count if
+ * we happen to execute between start of vblank and the
+ * delayed gpu counter increment.
+ */
+ do {
+ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+ vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
+ } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc));
+
+ /* Compute time difference to stored timestamp of last vblank
+ * as updated by last invocation of drm_handle_vblank() in vblank irq.
+ */
+ vblcount = atomic_read(&dev->_vblank_count[crtc]);
+ diff_ns = timeval_to_ns(&tvblank) -
+ timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+ /* If there is at least 1 msec difference between the last stored
+ * timestamp and tvblank, then we are currently executing our
+ * disable inside a new vblank interval, the tvblank timestamp
+ * corresponds to this new vblank interval and the irq handler
+ * for this vblank didn't run yet and won't run due to our disable.
+ * Therefore we need to do the job of drm_handle_vblank() and
+ * increment the vblank counter by one to account for this vblank.
+ *
+ * Skip this step if there isn't any high precision timestamp
+ * available. In that case we can't account for this and just
+ * hope for the best.
+ */
+ if ((vblrc > 0) && (abs(diff_ns) > 1000000))
+ atomic_inc(&dev->_vblank_count[crtc]);
+
+ /* Invalidate all timestamps while vblank irq's are off. */
+ clear_vblank_timestamps(dev, crtc);
+
+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+ preempt_enable();
+}
+
static void vblank_disable_fn(unsigned long arg)
{
struct drm_device *dev = (struct drm_device *)arg;
@@ -91,10 +188,7 @@ static void vblank_disable_fn(unsigned long arg)
if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
dev->vblank_enabled[i]) {
DRM_DEBUG("disabling vblank on crtc %d\n", i);
- dev->last_vblank[i] =
- dev->driver->get_vblank_counter(dev, i);
- dev->driver->disable_vblank(dev, i);
- dev->vblank_enabled[i] = 0;
+ vblank_disable_and_save(dev, i);
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
@@ -117,6 +211,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
kfree(dev->last_vblank);
kfree(dev->last_vblank_wait);
kfree(dev->vblank_inmodeset);
+ kfree(dev->_vblank_time);
dev->num_crtcs = 0;
}
@@ -129,6 +224,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
(unsigned long)dev);
spin_lock_init(&dev->vbl_lock);
+ spin_lock_init(&dev->vblank_time_lock);
+
dev->num_crtcs = num_crtcs;
dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
@@ -161,6 +258,19 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
if (!dev->vblank_inmodeset)
goto err;
+ dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
+ sizeof(struct timeval), GFP_KERNEL);
+ if (!dev->_vblank_time)
+ goto err;
+
+ DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
+
+ /* Driver specific high-precision vblank timestamping supported? */
+ if (dev->driver->get_vblank_timestamp)
+ DRM_INFO("Driver supports precise vblank timestamp query.\n");
+ else
+ DRM_INFO("No driver support for vblank timestamp query.\n");
+
/* Zero per-crtc vblank stuff */
for (i = 0; i < num_crtcs; i++) {
init_waitqueue_head(&dev->vbl_queue[i]);
@@ -279,7 +389,7 @@ EXPORT_SYMBOL(drm_irq_install);
*
* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
*/
-int drm_irq_uninstall(struct drm_device * dev)
+int drm_irq_uninstall(struct drm_device *dev)
{
unsigned long irqflags;
int irq_enabled, i;
@@ -335,7 +445,9 @@ int drm_control(struct drm_device *dev, void *data,
{
struct drm_control *ctl = data;
- /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
+ /* if we haven't irq we fallback for compatibility reasons -
+ * this used to be a separate function in drm_dma.h
+ */
switch (ctl->func) {
@@ -360,6 +472,287 @@ int drm_control(struct drm_device *dev, void *data,
}
/**
+ * drm_calc_timestamping_constants - Calculate and
+ * store various constants which are later needed by
+ * vblank and swap-completion timestamping, e.g, by
+ * drm_calc_vbltimestamp_from_scanoutpos().
+ * They are derived from crtc's true scanout timing,
+ * so they take things like panel scaling or other
+ * adjustments into account.
+ *
+ * @crtc drm_crtc whose timestamp constants should be updated.
+ *
+ */
+void drm_calc_timestamping_constants(struct drm_crtc *crtc)
+{
+ s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
+ u64 dotclock;
+
+ /* Dot clock in Hz: */
+ dotclock = (u64) crtc->hwmode.clock * 1000;
+
+ /* Valid dotclock? */
+ if (dotclock > 0) {
+ /* Convert scanline length in pixels and video dot clock to
+ * line duration, frame duration and pixel duration in
+ * nanoseconds:
+ */
+ pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
+ linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
+ 1000000000), dotclock);
+ framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns;
+ } else
+ DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
+ crtc->base.id);
+
+ crtc->pixeldur_ns = pixeldur_ns;
+ crtc->linedur_ns = linedur_ns;
+ crtc->framedur_ns = framedur_ns;
+
+ DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
+ crtc->base.id, crtc->hwmode.crtc_htotal,
+ crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
+ DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
+ crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
+ (int) linedur_ns, (int) pixeldur_ns);
+}
+EXPORT_SYMBOL(drm_calc_timestamping_constants);
+
+/**
+ * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
+ * drivers. Implements calculation of exact vblank timestamps from
+ * given drm_display_mode timings and current video scanout position
+ * of a crtc. This can be called from within get_vblank_timestamp()
+ * implementation of a kms driver to implement the actual timestamping.
+ *
+ * Should return timestamps conforming to the OML_sync_control OpenML
+ * extension specification. The timestamp corresponds to the end of
+ * the vblank interval, aka start of scanout of topmost-leftmost display
+ * pixel in the following video frame.
+ *
+ * Requires support for optional dev->driver->get_scanout_position()
+ * in kms driver, plus a bit of setup code to provide a drm_display_mode
+ * that corresponds to the true scanout timing.
+ *
+ * The current implementation only handles standard video modes. It
+ * returns as no operation if a doublescan or interlaced video mode is
+ * active. Higher level code is expected to handle this.
+ *
+ * @dev: DRM device.
+ * @crtc: Which crtc's vblank timestamp to retrieve.
+ * @max_error: Desired maximum allowable error in timestamps (nanosecs).
+ * On return contains true maximum error of timestamp.
+ * @vblank_time: Pointer to struct timeval which should receive the timestamp.
+ * @flags: Flags to pass to driver:
+ * 0 = Default.
+ * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ * @refcrtc: drm_crtc* of crtc which defines scanout timing.
+ *
+ * Returns negative value on error, failure or if not supported in current
+ * video mode:
+ *
+ * -EINVAL - Invalid crtc.
+ * -EAGAIN - Temporary unavailable, e.g., called before initial modeset.
+ * -ENOTSUPP - Function not supported in current display mode.
+ * -EIO - Failed, e.g., due to failed scanout position query.
+ *
+ * Returns or'ed positive status flags on success:
+ *
+ * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
+ * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
+ *
+ */
+int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags,
+ struct drm_crtc *refcrtc)
+{
+ struct timeval stime, raw_time;
+ struct drm_display_mode *mode;
+ int vbl_status, vtotal, vdisplay;
+ int vpos, hpos, i;
+ s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
+ bool invbl;
+
+ if (crtc < 0 || crtc >= dev->num_crtcs) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
+ return -EINVAL;
+ }
+
+ /* Scanout position query not supported? Should not happen. */
+ if (!dev->driver->get_scanout_position) {
+ DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
+ return -EIO;
+ }
+
+ mode = &refcrtc->hwmode;
+ vtotal = mode->crtc_vtotal;
+ vdisplay = mode->crtc_vdisplay;
+
+ /* Durations of frames, lines, pixels in nanoseconds. */
+ framedur_ns = refcrtc->framedur_ns;
+ linedur_ns = refcrtc->linedur_ns;
+ pixeldur_ns = refcrtc->pixeldur_ns;
+
+ /* If mode timing undefined, just return as no-op:
+ * Happens during initial modesetting of a crtc.
+ */
+ if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
+ DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
+ return -EAGAIN;
+ }
+
+ /* Don't know yet how to handle interlaced or
+ * double scan modes. Just no-op for now.
+ */
+ if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) {
+ DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc);
+ return -ENOTSUPP;
+ }
+
+ /* Get current scanout position with system timestamp.
+ * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
+ * if single query takes longer than max_error nanoseconds.
+ *
+ * This guarantees a tight bound on maximum error if
+ * code gets preempted or delayed for some reason.
+ */
+ for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {
+ /* Disable preemption to make it very likely to
+ * succeed in the first iteration even on PREEMPT_RT kernel.
+ */
+ preempt_disable();
+
+ /* Get system timestamp before query. */
+ do_gettimeofday(&stime);
+
+ /* Get vertical and horizontal scanout pos. vpos, hpos. */
+ vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos);
+
+ /* Get system timestamp after query. */
+ do_gettimeofday(&raw_time);
+
+ preempt_enable();
+
+ /* Return as no-op if scanout query unsupported or failed. */
+ if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
+ DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
+ crtc, vbl_status);
+ return -EIO;
+ }
+
+ duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime);
+
+ /* Accept result with < max_error nsecs timing uncertainty. */
+ if (duration_ns <= (s64) *max_error)
+ break;
+ }
+
+ /* Noisy system timing? */
+ if (i == DRM_TIMESTAMP_MAXRETRIES) {
+ DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
+ crtc, (int) duration_ns/1000, *max_error/1000, i);
+ }
+
+ /* Return upper bound of timestamp precision error. */
+ *max_error = (int) duration_ns;
+
+ /* Check if in vblank area:
+ * vpos is >=0 in video scanout area, but negative
+ * within vblank area, counting down the number of lines until
+ * start of scanout.
+ */
+ invbl = vbl_status & DRM_SCANOUTPOS_INVBL;
+
+ /* Convert scanout position into elapsed time at raw_time query
+ * since start of scanout at first display scanline. delta_ns
+ * can be negative if start of scanout hasn't happened yet.
+ */
+ delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
+
+ /* Is vpos outside nominal vblank area, but less than
+ * 1/100 of a frame height away from start of vblank?
+ * If so, assume this isn't a massively delayed vblank
+ * interrupt, but a vblank interrupt that fired a few
+ * microseconds before true start of vblank. Compensate
+ * by adding a full frame duration to the final timestamp.
+ * Happens, e.g., on ATI R500, R600.
+ *
+ * We only do this if DRM_CALLED_FROM_VBLIRQ.
+ */
+ if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
+ ((vdisplay - vpos) < vtotal / 100)) {
+ delta_ns = delta_ns - framedur_ns;
+
+ /* Signal this correction as "applied". */
+ vbl_status |= 0x8;
+ }
+
+ /* Subtract time delta from raw timestamp to get final
+ * vblank_time timestamp for end of vblank.
+ */
+ *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
+
+ DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n",
+ crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec,
+ raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec,
+ (int) duration_ns/1000, i);
+
+ vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
+ if (invbl)
+ vbl_status |= DRM_VBLANKTIME_INVBL;
+
+ return vbl_status;
+}
+EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
+
+/**
+ * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
+ * vblank interval.
+ *
+ * @dev: DRM device
+ * @crtc: which crtc's vblank timestamp to retrieve
+ * @tvblank: Pointer to target struct timeval which should receive the timestamp
+ * @flags: Flags to pass to driver:
+ * 0 = Default.
+ * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ *
+ * Fetches the system timestamp corresponding to the time of the most recent
+ * vblank interval on specified crtc. May call into kms-driver to
+ * compute the timestamp with a high-precision GPU specific method.
+ *
+ * Returns zero if timestamp originates from uncorrected do_gettimeofday()
+ * call, i.e., it isn't very precisely locked to the true vblank.
+ *
+ * Returns non-zero if timestamp is considered to be very precise.
+ */
+u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+ struct timeval *tvblank, unsigned flags)
+{
+ int ret = 0;
+
+ /* Define requested maximum error on timestamps (nanoseconds). */
+ int max_error = (int) drm_timestamp_precision * 1000;
+
+ /* Query driver if possible and precision timestamping enabled. */
+ if (dev->driver->get_vblank_timestamp && (max_error > 0)) {
+ ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
+ tvblank, flags);
+ if (ret > 0)
+ return (u32) ret;
+ }
+
+ /* GPU high precision timestamp query unsupported or failed.
+ * Return gettimeofday timestamp as best estimate.
+ */
+ do_gettimeofday(tvblank);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_get_last_vbltimestamp);
+
+/**
* drm_vblank_count - retrieve "cooked" vblank counter value
* @dev: DRM device
* @crtc: which counter to retrieve
@@ -375,6 +768,40 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
EXPORT_SYMBOL(drm_vblank_count);
/**
+ * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
+ * and the system timestamp corresponding to that vblank counter value.
+ *
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity. Returns corresponding system timestamp of the time
+ * of the vblank interval that corresponds to the current value vblank counter
+ * value.
+ */
+u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+ struct timeval *vblanktime)
+{
+ u32 cur_vblank;
+
+ /* Read timestamp from slot of _vblank_time ringbuffer
+ * that corresponds to current vblank count. Retry if
+ * count has incremented during readout. This works like
+ * a seqlock.
+ */
+ do {
+ cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
+ *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
+ smp_rmb();
+ } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
+
+ return cur_vblank;
+}
+EXPORT_SYMBOL(drm_vblank_count_and_time);
+
+/**
* drm_update_vblank_count - update the master vblank counter
* @dev: DRM device
* @crtc: counter to update
@@ -392,7 +819,8 @@ EXPORT_SYMBOL(drm_vblank_count);
*/
static void drm_update_vblank_count(struct drm_device *dev, int crtc)
{
- u32 cur_vblank, diff;
+ u32 cur_vblank, diff, tslot, rc;
+ struct timeval t_vblank;
/*
* Interrupts were disabled prior to this call, so deal with counter
@@ -400,8 +828,18 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
* NOTE! It's possible we lost a full dev->max_vblank_count events
* here if the register is small or we had vblank interrupts off for
* a long time.
+ *
+ * We repeat the hardware vblank counter & timestamp query until
+ * we get consistent results. This to prevent races between gpu
+ * updating its hardware counter while we are retrieving the
+ * corresponding vblank timestamp.
*/
- cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+ do {
+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+ rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
+ } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
+
+ /* Deal with counter wrap */
diff = cur_vblank - dev->last_vblank[crtc];
if (cur_vblank < dev->last_vblank[crtc]) {
diff += dev->max_vblank_count;
@@ -413,6 +851,16 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
crtc, diff);
+ /* Reinitialize corresponding vblank timestamp if high-precision query
+ * available. Skip this step if query unsupported or failed. Will
+ * reinitialize delayed at next vblank interrupt in that case.
+ */
+ if (rc) {
+ tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
+ vblanktimestamp(dev, crtc, tslot) = t_vblank;
+ smp_wmb();
+ }
+
atomic_add(diff, &dev->_vblank_count[crtc]);
}
@@ -429,15 +877,27 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
*/
int drm_vblank_get(struct drm_device *dev, int crtc)
{
- unsigned long irqflags;
+ unsigned long irqflags, irqflags2;
int ret = 0;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+ /* Disable preemption while holding vblank_time_lock. Do
+ * it explicitely to guard against PREEMPT_RT kernel.
+ */
+ preempt_disable();
+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
if (!dev->vblank_enabled[crtc]) {
+ /* Enable vblank irqs under vblank_time_lock protection.
+ * All vblank count & timestamp updates are held off
+ * until we are done reinitializing master counter and
+ * timestamps. Filtercode in drm_handle_vblank() will
+ * prevent double-accounting of same vblank interval.
+ */
ret = dev->driver->enable_vblank(dev, crtc);
- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
+ crtc, ret);
if (ret)
atomic_dec(&dev->vblank_refcount[crtc]);
else {
@@ -445,6 +905,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
drm_update_vblank_count(dev, crtc);
}
}
+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
+ preempt_enable();
} else {
if (!dev->vblank_enabled[crtc]) {
atomic_dec(&dev->vblank_refcount[crtc]);
@@ -463,15 +925,17 @@ EXPORT_SYMBOL(drm_vblank_get);
* @crtc: which counter to give up
*
* Release ownership of a given vblank counter, turning off interrupts
- * if possible.
+ * if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
*/
void drm_vblank_put(struct drm_device *dev, int crtc)
{
- BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
+ BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
/* Last user schedules interrupt disable */
- if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
- mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
+ (drm_vblank_offdelay > 0))
+ mod_timer(&dev->vblank_disable_timer,
+ jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
}
EXPORT_SYMBOL(drm_vblank_put);
@@ -480,10 +944,8 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
unsigned long irqflags;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- dev->driver->disable_vblank(dev, crtc);
+ vblank_disable_and_save(dev, crtc);
DRM_WAKEUP(&dev->vbl_queue[crtc]);
- dev->vblank_enabled[crtc] = 0;
- dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
EXPORT_SYMBOL(drm_vblank_off);
@@ -585,10 +1047,13 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
struct timeval now;
unsigned long flags;
unsigned int seq;
+ int ret;
e = kzalloc(sizeof *e, GFP_KERNEL);
- if (e == NULL)
- return -ENOMEM;
+ if (e == NULL) {
+ ret = -ENOMEM;
+ goto err_put;
+ }
e->pipe = pipe;
e->base.pid = current->pid;
@@ -599,17 +1064,16 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
e->base.file_priv = file_priv;
e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
- do_gettimeofday(&now);
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < sizeof e->event) {
- spin_unlock_irqrestore(&dev->event_lock, flags);
- kfree(e);
- return -ENOMEM;
+ ret = -EBUSY;
+ goto err_unlock;
}
file_priv->event_space -= sizeof e->event;
- seq = drm_vblank_count(dev, pipe);
+ seq = drm_vblank_count_and_time(dev, pipe, &now);
+
if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
(seq - vblwait->request.sequence) <= (1 << 23)) {
vblwait->request.sequence = seq + 1;
@@ -624,20 +1088,30 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
e->event.sequence = vblwait->request.sequence;
if ((seq - vblwait->request.sequence) <= (1 << 23)) {
+ e->event.sequence = seq;
e->event.tv_sec = now.tv_sec;
e->event.tv_usec = now.tv_usec;
- drm_vblank_put(dev, e->pipe);
+ drm_vblank_put(dev, pipe);
list_add_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
+ vblwait->reply.sequence = seq;
trace_drm_vblank_event_delivered(current->pid, pipe,
vblwait->request.sequence);
} else {
list_add_tail(&e->base.link, &dev->vblank_event_list);
+ vblwait->reply.sequence = vblwait->request.sequence;
}
spin_unlock_irqrestore(&dev->event_lock, flags);
return 0;
+
+err_unlock:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(e);
+err_put:
+ drm_vblank_put(dev, pipe);
+ return ret;
}
/**
@@ -718,11 +1192,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
if (ret != -EINTR) {
struct timeval now;
- do_gettimeofday(&now);
-
+ vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now);
vblwait->reply.tval_sec = now.tv_sec;
vblwait->reply.tval_usec = now.tv_usec;
- vblwait->reply.sequence = drm_vblank_count(dev, crtc);
+
DRM_DEBUG("returning %d to client\n",
vblwait->reply.sequence);
} else {
@@ -741,8 +1214,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
unsigned long flags;
unsigned int seq;
- do_gettimeofday(&now);
- seq = drm_vblank_count(dev, crtc);
+ seq = drm_vblank_count_and_time(dev, crtc, &now);
spin_lock_irqsave(&dev->event_lock, flags);
@@ -780,11 +1252,64 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
*/
void drm_handle_vblank(struct drm_device *dev, int crtc)
{
+ u32 vblcount;
+ s64 diff_ns;
+ struct timeval tvblank;
+ unsigned long irqflags;
+
if (!dev->num_crtcs)
return;
- atomic_inc(&dev->_vblank_count[crtc]);
+ /* Need timestamp lock to prevent concurrent execution with
+ * vblank enable/disable, as this would cause inconsistent
+ * or corrupted timestamps and vblank counts.
+ */
+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
+
+ /* Vblank irq handling disabled. Nothing to do. */
+ if (!dev->vblank_enabled[crtc]) {
+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+ return;
+ }
+
+ /* Fetch corresponding timestamp for this vblank interval from
+ * driver and store it in proper slot of timestamp ringbuffer.
+ */
+
+ /* Get current timestamp and count. */
+ vblcount = atomic_read(&dev->_vblank_count[crtc]);
+ drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
+
+ /* Compute time difference to timestamp of last vblank */
+ diff_ns = timeval_to_ns(&tvblank) -
+ timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+ /* Update vblank timestamp and count if at least
+ * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds
+ * difference between last stored timestamp and current
+ * timestamp. A smaller difference means basically
+ * identical timestamps. Happens if this vblank has
+ * been already processed and this is a redundant call,
+ * e.g., due to spurious vblank interrupts. We need to
+ * ignore those for accounting.
+ */
+ if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
+ /* Store new timestamp in ringbuffer. */
+ vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
+ smp_wmb();
+
+ /* Increment cooked vblank count. This also atomically commits
+ * the timestamp computed above.
+ */
+ atomic_inc(&dev->_vblank_count[crtc]);
+ } else {
+ DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
+ crtc, (int) diff_ns);
+ }
+
DRM_WAKEUP(&dev->vbl_queue[crtc]);
drm_handle_vblank_events(dev, crtc);
+
+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
}
EXPORT_SYMBOL(drm_handle_vblank);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index a6bfc302ed90..c59515ba7e69 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -392,10 +392,36 @@ void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
mm->scanned_blocks = 0;
mm->scan_hit_start = 0;
mm->scan_hit_size = 0;
+ mm->scan_check_range = 0;
}
EXPORT_SYMBOL(drm_mm_init_scan);
/**
+ * Initializa lru scanning.
+ *
+ * This simply sets up the scanning routines with the parameters for the desired
+ * hole. This version is for range-restricted scans.
+ *
+ * Warning: As long as the scan list is non-empty, no other operations than
+ * adding/removing nodes to/from the scan list are allowed.
+ */
+void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
+ unsigned alignment,
+ unsigned long start,
+ unsigned long end)
+{
+ mm->scan_alignment = alignment;
+ mm->scan_size = size;
+ mm->scanned_blocks = 0;
+ mm->scan_hit_start = 0;
+ mm->scan_hit_size = 0;
+ mm->scan_start = start;
+ mm->scan_end = end;
+ mm->scan_check_range = 1;
+}
+EXPORT_SYMBOL(drm_mm_init_scan_with_range);
+
+/**
* Add a node to the scan list that might be freed to make space for the desired
* hole.
*
@@ -406,6 +432,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
struct drm_mm *mm = node->mm;
struct list_head *prev_free, *next_free;
struct drm_mm_node *prev_node, *next_node;
+ unsigned long adj_start;
+ unsigned long adj_end;
mm->scanned_blocks++;
@@ -452,7 +480,17 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
node->free_stack.prev = prev_free;
node->free_stack.next = next_free;
- if (check_free_hole(node->start, node->start + node->size,
+ if (mm->scan_check_range) {
+ adj_start = node->start < mm->scan_start ?
+ mm->scan_start : node->start;
+ adj_end = node->start + node->size > mm->scan_end ?
+ mm->scan_end : node->start + node->size;
+ } else {
+ adj_start = node->start;
+ adj_end = node->start + node->size;
+ }
+
+ if (check_free_hole(adj_start , adj_end,
mm->scan_size, mm->scan_alignment)) {
mm->scan_hit_start = node->start;
mm->scan_hit_size = node->size;
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index cdc89ee042cc..d59edc18301f 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -40,12 +40,22 @@
unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug);
+unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
+EXPORT_SYMBOL(drm_vblank_offdelay);
+
+unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
+EXPORT_SYMBOL(drm_timestamp_precision);
+
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
+MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
module_param_named(debug, drm_debug, int, 0600);
+module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
+module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
struct idr drm_minors_idr;
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index fdc833d5cc7b..0ae6a7c5020f 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -9,6 +9,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
i915_gem.o \
i915_gem_debug.o \
i915_gem_evict.o \
+ i915_gem_execbuffer.o \
+ i915_gem_gtt.o \
i915_gem_tiling.o \
i915_trace_points.o \
intel_display.o \
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index af70337567ce..d3e8c540f778 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -242,7 +242,7 @@ fail:
static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
{
- return connector_status_unknown;
+ return connector_status_connected;
}
static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1f4f3ceb63c7..3601466c5502 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -32,6 +32,7 @@
#include "drmP.h"
#include "drm.h"
#include "intel_drv.h"
+#include "intel_ringbuffer.h"
#include "i915_drm.h"
#include "i915_drv.h"
@@ -72,7 +73,6 @@ static int i915_capabilities(struct seq_file *m, void *data)
B(is_broadwater);
B(is_crestline);
B(has_fbc);
- B(has_rc6);
B(has_pipe_cxsr);
B(has_hotplug);
B(cursor_needs_physical);
@@ -86,19 +86,19 @@ static int i915_capabilities(struct seq_file *m, void *data)
return 0;
}
-static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
+static const char *get_pin_flag(struct drm_i915_gem_object *obj)
{
- if (obj_priv->user_pin_count > 0)
+ if (obj->user_pin_count > 0)
return "P";
- else if (obj_priv->pin_count > 0)
+ else if (obj->pin_count > 0)
return "p";
else
return " ";
}
-static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
+static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
{
- switch (obj_priv->tiling_mode) {
+ switch (obj->tiling_mode) {
default:
case I915_TILING_NONE: return " ";
case I915_TILING_X: return "X";
@@ -106,10 +106,19 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
}
}
+static const char *agp_type_str(int type)
+{
+ switch (type) {
+ case 0: return " uncached";
+ case 1: return " snooped";
+ default: return "";
+ }
+}
+
static void
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
{
- seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+ seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s%s",
&obj->base,
get_pin_flag(obj),
get_tiling_flag(obj),
@@ -117,6 +126,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->base.read_domains,
obj->base.write_domain,
obj->last_rendering_seqno,
+ obj->last_fenced_seqno,
+ agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY),
obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
if (obj->base.name)
@@ -124,7 +135,17 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
if (obj->fence_reg != I915_FENCE_REG_NONE)
seq_printf(m, " (fence: %d)", obj->fence_reg);
if (obj->gtt_space != NULL)
- seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+ seq_printf(m, " (gtt offset: %08x, size: %08x)",
+ obj->gtt_offset, (unsigned int)obj->gtt_space->size);
+ if (obj->pin_mappable || obj->fault_mappable) {
+ char s[3], *t = s;
+ if (obj->pin_mappable)
+ *t++ = 'p';
+ if (obj->fault_mappable)
+ *t++ = 'f';
+ *t = '\0';
+ seq_printf(m, " (%s mappable)", s);
+ }
if (obj->ring != NULL)
seq_printf(m, " (%s)", obj->ring->name);
}
@@ -136,7 +157,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
struct list_head *head;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
size_t total_obj_size, total_gtt_size;
int count, ret;
@@ -171,12 +192,12 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
}
total_obj_size = total_gtt_size = count = 0;
- list_for_each_entry(obj_priv, head, mm_list) {
+ list_for_each_entry(obj, head, mm_list) {
seq_printf(m, " ");
- describe_obj(m, obj_priv);
+ describe_obj(m, obj);
seq_printf(m, "\n");
- total_obj_size += obj_priv->base.size;
- total_gtt_size += obj_priv->gtt_space->size;
+ total_obj_size += obj->base.size;
+ total_gtt_size += obj->gtt_space->size;
count++;
}
mutex_unlock(&dev->struct_mutex);
@@ -186,30 +207,116 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
return 0;
}
+#define count_objects(list, member) do { \
+ list_for_each_entry(obj, list, member) { \
+ size += obj->gtt_space->size; \
+ ++count; \
+ if (obj->map_and_fenceable) { \
+ mappable_size += obj->gtt_space->size; \
+ ++mappable_count; \
+ } \
+ } \
+} while(0)
+
static int i915_gem_object_info(struct seq_file *m, void* data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 count, mappable_count;
+ size_t size, mappable_size;
+ struct drm_i915_gem_object *obj;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
- seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
- seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
- seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
- seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
- seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
- seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+ seq_printf(m, "%u objects, %zu bytes\n",
+ dev_priv->mm.object_count,
+ dev_priv->mm.object_memory);
+
+ size = count = mappable_size = mappable_count = 0;
+ count_objects(&dev_priv->mm.gtt_list, gtt_list);
+ seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n",
+ count, mappable_count, size, mappable_size);
+
+ size = count = mappable_size = mappable_count = 0;
+ count_objects(&dev_priv->mm.active_list, mm_list);
+ count_objects(&dev_priv->mm.flushing_list, mm_list);
+ seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n",
+ count, mappable_count, size, mappable_size);
+
+ size = count = mappable_size = mappable_count = 0;
+ count_objects(&dev_priv->mm.pinned_list, mm_list);
+ seq_printf(m, " %u [%u] pinned objects, %zu [%zu] bytes\n",
+ count, mappable_count, size, mappable_size);
+
+ size = count = mappable_size = mappable_count = 0;
+ count_objects(&dev_priv->mm.inactive_list, mm_list);
+ seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n",
+ count, mappable_count, size, mappable_size);
+
+ size = count = mappable_size = mappable_count = 0;
+ count_objects(&dev_priv->mm.deferred_free_list, mm_list);
+ seq_printf(m, " %u [%u] freed objects, %zu [%zu] bytes\n",
+ count, mappable_count, size, mappable_size);
+
+ size = count = mappable_size = mappable_count = 0;
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ if (obj->fault_mappable) {
+ size += obj->gtt_space->size;
+ ++count;
+ }
+ if (obj->pin_mappable) {
+ mappable_size += obj->gtt_space->size;
+ ++mappable_count;
+ }
+ }
+ seq_printf(m, "%u pinned mappable objects, %zu bytes\n",
+ mappable_count, mappable_size);
+ seq_printf(m, "%u fault mappable objects, %zu bytes\n",
+ count, size);
+
+ seq_printf(m, "%zu [%zu] gtt total\n",
+ dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total);
mutex_unlock(&dev->struct_mutex);
return 0;
}
+static int i915_gem_gtt_info(struct seq_file *m, void* data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+ size_t total_obj_size, total_gtt_size;
+ int count, ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ total_obj_size = total_gtt_size = count = 0;
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ seq_printf(m, " ");
+ describe_obj(m, obj);
+ seq_printf(m, "\n");
+ total_obj_size += obj->base.size;
+ total_gtt_size += obj->gtt_space->size;
+ count++;
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+ count, total_obj_size, total_gtt_size);
+
+ return 0;
+}
+
static int i915_gem_pageflip_info(struct seq_file *m, void *data)
{
@@ -243,14 +350,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
seq_printf(m, "%d prepares\n", work->pending);
if (work->old_fb_obj) {
- struct drm_i915_gem_object *obj_priv = to_intel_bo(work->old_fb_obj);
- if(obj_priv)
- seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset );
+ struct drm_i915_gem_object *obj = work->old_fb_obj;
+ if (obj)
+ seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj->gtt_offset);
}
if (work->pending_flip_obj) {
- struct drm_i915_gem_object *obj_priv = to_intel_bo(work->pending_flip_obj);
- if(obj_priv)
- seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset );
+ struct drm_i915_gem_object *obj = work->pending_flip_obj;
+ if (obj)
+ seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj->gtt_offset);
}
}
spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -265,44 +372,80 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_request *gem_request;
- int ret;
+ int ret, count;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- seq_printf(m, "Request:\n");
- list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
- list) {
- seq_printf(m, " %d @ %d\n",
- gem_request->seqno,
- (int) (jiffies - gem_request->emitted_jiffies));
+ count = 0;
+ if (!list_empty(&dev_priv->ring[RCS].request_list)) {
+ seq_printf(m, "Render requests:\n");
+ list_for_each_entry(gem_request,
+ &dev_priv->ring[RCS].request_list,
+ list) {
+ seq_printf(m, " %d @ %d\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies));
+ }
+ count++;
+ }
+ if (!list_empty(&dev_priv->ring[VCS].request_list)) {
+ seq_printf(m, "BSD requests:\n");
+ list_for_each_entry(gem_request,
+ &dev_priv->ring[VCS].request_list,
+ list) {
+ seq_printf(m, " %d @ %d\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies));
+ }
+ count++;
+ }
+ if (!list_empty(&dev_priv->ring[BCS].request_list)) {
+ seq_printf(m, "BLT requests:\n");
+ list_for_each_entry(gem_request,
+ &dev_priv->ring[BCS].request_list,
+ list) {
+ seq_printf(m, " %d @ %d\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies));
+ }
+ count++;
}
mutex_unlock(&dev->struct_mutex);
+ if (count == 0)
+ seq_printf(m, "No requests\n");
+
return 0;
}
+static void i915_ring_seqno_info(struct seq_file *m,
+ struct intel_ring_buffer *ring)
+{
+ if (ring->get_seqno) {
+ seq_printf(m, "Current sequence (%s): %d\n",
+ ring->name, ring->get_seqno(ring));
+ seq_printf(m, "Waiter sequence (%s): %d\n",
+ ring->name, ring->waiting_seqno);
+ seq_printf(m, "IRQ sequence (%s): %d\n",
+ ring->name, ring->irq_seqno);
+ }
+}
+
static int i915_gem_seqno_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
+ int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- if (dev_priv->render_ring.status_page.page_addr != NULL) {
- seq_printf(m, "Current sequence: %d\n",
- dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
- } else {
- seq_printf(m, "Current sequence: hws uninitialized\n");
- }
- seq_printf(m, "Waiter sequence: %d\n",
- dev_priv->mm.waiting_gem_seqno);
- seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ i915_ring_seqno_info(m, &dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
@@ -315,7 +458,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
+ int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
@@ -354,16 +497,14 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
- if (dev_priv->render_ring.status_page.page_addr != NULL) {
- seq_printf(m, "Current sequence: %d\n",
- dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
- } else {
- seq_printf(m, "Current sequence: hws uninitialized\n");
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ if (IS_GEN6(dev)) {
+ seq_printf(m, "Graphics Interrupt mask (%s): %08x\n",
+ dev_priv->ring[i].name,
+ I915_READ_IMR(&dev_priv->ring[i]));
+ }
+ i915_ring_seqno_info(m, &dev_priv->ring[i]);
}
- seq_printf(m, "Waiter sequence: %d\n",
- dev_priv->mm.waiting_gem_seqno);
- seq_printf(m, "IRQ sequence: %d\n",
- dev_priv->mm.irq_gem_seqno);
mutex_unlock(&dev->struct_mutex);
return 0;
@@ -383,29 +524,17 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
for (i = 0; i < dev_priv->num_fence_regs; i++) {
- struct drm_gem_object *obj = dev_priv->fence_regs[i].obj;
+ struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
- if (obj == NULL) {
- seq_printf(m, "Fenced object[%2d] = unused\n", i);
- } else {
- struct drm_i915_gem_object *obj_priv;
-
- obj_priv = to_intel_bo(obj);
- seq_printf(m, "Fenced object[%2d] = %p: %s "
- "%08x %08zx %08x %s %08x %08x %d",
- i, obj, get_pin_flag(obj_priv),
- obj_priv->gtt_offset,
- obj->size, obj_priv->stride,
- get_tiling_flag(obj_priv),
- obj->read_domains, obj->write_domain,
- obj_priv->last_rendering_seqno);
- if (obj->name)
- seq_printf(m, " (name: %d)", obj->name);
- seq_printf(m, "\n");
- }
+ seq_printf(m, "Fenced object[%2d] = ", i);
+ if (obj == NULL)
+ seq_printf(m, "unused");
+ else
+ describe_obj(m, obj);
+ seq_printf(m, "\n");
}
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -414,10 +543,12 @@ static int i915_hws_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int i;
+ struct intel_ring_buffer *ring;
volatile u32 *hws;
+ int i;
- hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr;
+ ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
+ hws = (volatile u32 *)ring->status_page.page_addr;
if (hws == NULL)
return 0;
@@ -431,14 +562,14 @@ static int i915_hws_info(struct seq_file *m, void *data)
static void i915_dump_object(struct seq_file *m,
struct io_mapping *mapping,
- struct drm_i915_gem_object *obj_priv)
+ struct drm_i915_gem_object *obj)
{
int page, page_count, i;
- page_count = obj_priv->base.size / PAGE_SIZE;
+ page_count = obj->base.size / PAGE_SIZE;
for (page = 0; page < page_count; page++) {
u32 *mem = io_mapping_map_wc(mapping,
- obj_priv->gtt_offset + page * PAGE_SIZE);
+ obj->gtt_offset + page * PAGE_SIZE);
for (i = 0; i < PAGE_SIZE; i += 4)
seq_printf(m, "%08x : %08x\n", i, mem[i / 4]);
io_mapping_unmap(mem);
@@ -450,25 +581,21 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
- obj = &obj_priv->base;
- if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
- seq_printf(m, "--- gtt_offset = 0x%08x\n",
- obj_priv->gtt_offset);
- i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+ if (obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) {
+ seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
+ i915_dump_object(m, dev_priv->mm.gtt_mapping, obj);
}
}
mutex_unlock(&dev->struct_mutex);
-
return 0;
}
@@ -477,19 +604,21 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- if (!dev_priv->render_ring.gem_object) {
+ ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
+ if (!ring->obj) {
seq_printf(m, "No ringbuffer setup\n");
} else {
- u8 *virt = dev_priv->render_ring.virtual_start;
+ u8 *virt = ring->virtual_start;
uint32_t off;
- for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+ for (off = 0; off < ring->size; off += 4) {
uint32_t *ptr = (uint32_t *)(virt + off);
seq_printf(m, "%08x : %08x\n", off, *ptr);
}
@@ -504,19 +633,38 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int head, tail;
+ struct intel_ring_buffer *ring;
- head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+ ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
+ if (ring->size == 0)
+ return 0;
- seq_printf(m, "RingHead : %08x\n", head);
- seq_printf(m, "RingTail : %08x\n", tail);
- seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size);
- seq_printf(m, "Acthd : %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
+ seq_printf(m, "Ring %s:\n", ring->name);
+ seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR);
+ seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR);
+ seq_printf(m, " Size : %08x\n", ring->size);
+ seq_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring));
+ seq_printf(m, " NOPID : %08x\n", I915_READ_NOPID(ring));
+ if (IS_GEN6(dev)) {
+ seq_printf(m, " Sync 0 : %08x\n", I915_READ_SYNC_0(ring));
+ seq_printf(m, " Sync 1 : %08x\n", I915_READ_SYNC_1(ring));
+ }
+ seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring));
+ seq_printf(m, " Start : %08x\n", I915_READ_START(ring));
return 0;
}
+static const char *ring_str(int ring)
+{
+ switch (ring) {
+ case RING_RENDER: return " render";
+ case RING_BSD: return " bsd";
+ case RING_BLT: return " blt";
+ default: return "";
+ }
+}
+
static const char *pin_flag(int pinned)
{
if (pinned > 0)
@@ -547,6 +695,37 @@ static const char *purgeable_flag(int purgeable)
return purgeable ? " purgeable" : "";
}
+static void print_error_buffers(struct seq_file *m,
+ const char *name,
+ struct drm_i915_error_buffer *err,
+ int count)
+{
+ seq_printf(m, "%s [%d]:\n", name, count);
+
+ while (count--) {
+ seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s",
+ err->gtt_offset,
+ err->size,
+ err->read_domains,
+ err->write_domain,
+ err->seqno,
+ pin_flag(err->pinned),
+ tiling_flag(err->tiling),
+ dirty_flag(err->dirty),
+ purgeable_flag(err->purgeable),
+ ring_str(err->ring),
+ agp_type_str(err->agp_type));
+
+ if (err->name)
+ seq_printf(m, " (name: %d)", err->name);
+ if (err->fence_reg != I915_FENCE_REG_NONE)
+ seq_printf(m, " (fence: %d)", err->fence_reg);
+
+ seq_printf(m, "\n");
+ err++;
+ }
+}
+
static int i915_error_state(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -568,47 +747,54 @@ static int i915_error_state(struct seq_file *m, void *unused)
error->time.tv_usec);
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
seq_printf(m, "EIR: 0x%08x\n", error->eir);
- seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
- seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
+ seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+ if (INTEL_INFO(dev)->gen >= 6) {
+ seq_printf(m, "ERROR: 0x%08x\n", error->error);
+ seq_printf(m, "Blitter command stream:\n");
+ seq_printf(m, " ACTHD: 0x%08x\n", error->bcs_acthd);
+ seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir);
+ seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr);
+ seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone);
+ seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno);
+ seq_printf(m, "Video (BSD) command stream:\n");
+ seq_printf(m, " ACTHD: 0x%08x\n", error->vcs_acthd);
+ seq_printf(m, " IPEIR: 0x%08x\n", error->vcs_ipeir);
+ seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr);
+ seq_printf(m, " INSTDONE: 0x%08x\n", error->vcs_instdone);
+ seq_printf(m, " seqno: 0x%08x\n", error->vcs_seqno);
+ }
+ seq_printf(m, "Render command stream:\n");
+ seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir);
seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
- seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
if (INTEL_INFO(dev)->gen >= 4) {
- seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
+ seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
}
- seq_printf(m, "seqno: 0x%08x\n", error->seqno);
-
- if (error->active_bo_count) {
- seq_printf(m, "Buffers [%d]:\n", error->active_bo_count);
-
- for (i = 0; i < error->active_bo_count; i++) {
- seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s",
- error->active_bo[i].gtt_offset,
- error->active_bo[i].size,
- error->active_bo[i].read_domains,
- error->active_bo[i].write_domain,
- error->active_bo[i].seqno,
- pin_flag(error->active_bo[i].pinned),
- tiling_flag(error->active_bo[i].tiling),
- dirty_flag(error->active_bo[i].dirty),
- purgeable_flag(error->active_bo[i].purgeable));
-
- if (error->active_bo[i].name)
- seq_printf(m, " (name: %d)", error->active_bo[i].name);
- if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE)
- seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg);
-
- seq_printf(m, "\n");
- }
- }
+ seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
+ seq_printf(m, " seqno: 0x%08x\n", error->seqno);
+
+ for (i = 0; i < 16; i++)
+ seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
+
+ if (error->active_bo)
+ print_error_buffers(m, "Active",
+ error->active_bo,
+ error->active_bo_count);
+
+ if (error->pinned_bo)
+ print_error_buffers(m, "Pinned",
+ error->pinned_bo,
+ error->pinned_bo_count);
for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
if (error->batchbuffer[i]) {
struct drm_i915_error_object *obj = error->batchbuffer[i];
- seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
+ seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
+ dev_priv->ring[i].name,
+ obj->gtt_offset);
offset = 0;
for (page = 0; page < obj->page_count; page++) {
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
@@ -635,6 +821,9 @@ static int i915_error_state(struct seq_file *m, void *unused)
if (error->overlay)
intel_overlay_print_error_state(m, error->overlay);
+ if (error->display)
+ intel_display_print_error_state(m, dev, error->display);
+
out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
@@ -658,15 +847,51 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u16 rgvswctl = I915_READ16(MEMSWCTL);
- u16 rgvstat = I915_READ16(MEMSTAT_ILK);
- seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
- seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
- seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
- MEMSTAT_VID_SHIFT);
- seq_printf(m, "Current P-state: %d\n",
- (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
+ if (IS_GEN5(dev)) {
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
+ u16 rgvstat = I915_READ16(MEMSTAT_ILK);
+
+ seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
+ seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
+ seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
+ MEMSTAT_VID_SHIFT);
+ seq_printf(m, "Current P-state: %d\n",
+ (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
+ } else if (IS_GEN6(dev)) {
+ u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
+ u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
+ u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ int max_freq;
+
+ /* RPSTAT1 is in the GT power well */
+ __gen6_force_wake_get(dev_priv);
+
+ seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
+ seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1));
+ seq_printf(m, "Render p-state ratio: %d\n",
+ (gt_perf_status & 0xff00) >> 8);
+ seq_printf(m, "Render p-state VID: %d\n",
+ gt_perf_status & 0xff);
+ seq_printf(m, "Render p-state limit: %d\n",
+ rp_state_limits & 0xff);
+
+ max_freq = (rp_state_cap & 0xff0000) >> 16;
+ seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
+ max_freq * 100);
+
+ max_freq = (rp_state_cap & 0xff00) >> 8;
+ seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
+ max_freq * 100);
+
+ max_freq = rp_state_cap & 0xff;
+ seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
+ max_freq * 100);
+
+ __gen6_force_wake_put(dev_priv);
+ } else {
+ seq_printf(m, "no P-state info available\n");
+ }
return 0;
}
@@ -715,7 +940,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL);
- u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY);
+ u32 rstdbyctl = I915_READ(RSTDBYCTL);
u16 crstandvid = I915_READ16(CRSTANDVID);
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
@@ -738,6 +963,30 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
seq_printf(m, "Render standby enabled: %s\n",
(rstdbyctl & RCX_SW_EXIT) ? "no" : "yes");
+ seq_printf(m, "Current RS state: ");
+ switch (rstdbyctl & RSX_STATUS_MASK) {
+ case RSX_STATUS_ON:
+ seq_printf(m, "on\n");
+ break;
+ case RSX_STATUS_RC1:
+ seq_printf(m, "RC1\n");
+ break;
+ case RSX_STATUS_RC1E:
+ seq_printf(m, "RC1E\n");
+ break;
+ case RSX_STATUS_RS1:
+ seq_printf(m, "RS1\n");
+ break;
+ case RSX_STATUS_RS2:
+ seq_printf(m, "RS2 (RC6)\n");
+ break;
+ case RSX_STATUS_RS3:
+ seq_printf(m, "RC3 (RC6+)\n");
+ break;
+ default:
+ seq_printf(m, "unknown\n");
+ break;
+ }
return 0;
}
@@ -794,7 +1043,7 @@ static int i915_sr_status(struct seq_file *m, void *unused)
drm_i915_private_t *dev_priv = dev->dev_private;
bool sr_enabled = false;
- if (IS_GEN5(dev))
+ if (HAS_PCH_SPLIT(dev))
sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
@@ -886,7 +1135,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
fb->base.height,
fb->base.depth,
fb->base.bits_per_pixel);
- describe_obj(m, to_intel_bo(fb->obj));
+ describe_obj(m, fb->obj);
seq_printf(m, "\n");
list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
@@ -898,7 +1147,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
fb->base.height,
fb->base.depth,
fb->base.bits_per_pixel);
- describe_obj(m, to_intel_bo(fb->obj));
+ describe_obj(m, fb->obj);
seq_printf(m, "\n");
}
@@ -943,7 +1192,6 @@ i915_wedged_write(struct file *filp,
loff_t *ppos)
{
struct drm_device *dev = filp->private_data;
- drm_i915_private_t *dev_priv = dev->dev_private;
char buf[20];
int val = 1;
@@ -959,12 +1207,7 @@ i915_wedged_write(struct file *filp,
}
DRM_INFO("Manually setting wedged to %d\n", val);
-
- atomic_set(&dev_priv->mm.wedged, val);
- if (val) {
- wake_up_all(&dev_priv->irq_queue);
- queue_work(dev_priv->wq, &dev_priv->error_work);
- }
+ i915_handle_error(dev, val);
return cnt;
}
@@ -1018,6 +1261,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
static struct drm_info_list i915_debugfs_list[] = {
{"i915_capabilities", i915_capabilities, 0, 0},
{"i915_gem_objects", i915_gem_object_info, 0},
+ {"i915_gem_gtt", i915_gem_gtt_info, 0},
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
@@ -1028,9 +1272,15 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_seqno", i915_gem_seqno_info, 0},
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
{"i915_gem_interrupt", i915_interrupt_info, 0},
- {"i915_gem_hws", i915_hws_info, 0},
- {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
- {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
+ {"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
+ {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
+ {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
+ {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RCS},
+ {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RCS},
+ {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)VCS},
+ {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS},
+ {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS},
+ {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS},
{"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7a26f4dd21ae..844f3c972b04 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -34,6 +34,7 @@
#include "i915_drm.h"
#include "i915_drv.h"
#include "i915_trace.h"
+#include "../../../platform/x86/intel_ips.h"
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/acpi.h>
@@ -49,6 +50,8 @@
static int i915_init_phys_hws(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
+
/* Program Hardware Status Page */
dev_priv->status_page_dmah =
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE);
@@ -57,11 +60,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
}
- dev_priv->render_ring.status_page.page_addr
- = dev_priv->status_page_dmah->vaddr;
+ ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
- memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
+ memset(ring->status_page.page_addr, 0, PAGE_SIZE);
if (INTEL_INFO(dev)->gen >= 4)
dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
@@ -79,13 +81,15 @@ static int i915_init_phys_hws(struct drm_device *dev)
static void i915_free_hws(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
+
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
dev_priv->status_page_dmah = NULL;
}
- if (dev_priv->render_ring.status_page.gfx_addr) {
- dev_priv->render_ring.status_page.gfx_addr = 0;
+ if (ring->status_page.gfx_addr) {
+ ring->status_page.gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
}
@@ -97,7 +101,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
- struct intel_ring_buffer *ring = &dev_priv->render_ring;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
/*
* We should never lose context on the ring with modesetting
@@ -106,8 +110,8 @@ void i915_kernel_lost_context(struct drm_device * dev)
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+ ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
@@ -123,6 +127,8 @@ void i915_kernel_lost_context(struct drm_device * dev)
static int i915_dma_cleanup(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
+
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed, it's too late.
@@ -131,9 +137,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
drm_irq_uninstall(dev);
mutex_lock(&dev->struct_mutex);
- intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
- intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
- intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ intel_cleanup_ring_buffer(&dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
/* Clear the HWS virtual address at teardown */
@@ -147,6 +152,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
master_priv->sarea = drm_getsarea(dev);
if (master_priv->sarea) {
@@ -157,24 +163,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
if (init->ring_size != 0) {
- if (dev_priv->render_ring.gem_object != NULL) {
+ if (ring->obj != NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("Client tried to initialize ringbuffer in "
"GEM mode\n");
return -EINVAL;
}
- dev_priv->render_ring.size = init->ring_size;
+ ring->size = init->ring_size;
- dev_priv->render_ring.map.offset = init->ring_start;
- dev_priv->render_ring.map.size = init->ring_size;
- dev_priv->render_ring.map.type = 0;
- dev_priv->render_ring.map.flags = 0;
- dev_priv->render_ring.map.mtrr = 0;
+ ring->map.offset = init->ring_start;
+ ring->map.size = init->ring_size;
+ ring->map.type = 0;
+ ring->map.flags = 0;
+ ring->map.mtrr = 0;
- drm_core_ioremap_wc(&dev_priv->render_ring.map, dev);
+ drm_core_ioremap_wc(&ring->map, dev);
- if (dev_priv->render_ring.map.handle == NULL) {
+ if (ring->map.handle == NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -182,7 +188,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
}
- dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle;
+ ring->virtual_start = ring->map.handle;
dev_priv->cpp = init->cpp;
dev_priv->back_offset = init->back_offset;
@@ -201,12 +207,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
- struct intel_ring_buffer *ring;
DRM_DEBUG_DRIVER("%s\n", __func__);
- ring = &dev_priv->render_ring;
-
if (ring->map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -221,7 +225,7 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_DEBUG_DRIVER("hw status page @ %p\n",
ring->status_page.page_addr);
if (ring->status_page.gfx_addr != 0)
- intel_ring_setup_status_page(dev, ring);
+ intel_ring_setup_status_page(ring);
else
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
@@ -263,7 +267,7 @@ static int i915_dma_init(struct drm_device *dev, void *data,
* instruction detected will be given a size of zero, which is a
* signal to abort the rest of the buffer.
*/
-static int do_validate_cmd(int cmd)
+static int validate_cmd(int cmd)
{
switch (((cmd >> 29) & 0x7)) {
case 0x0:
@@ -321,40 +325,27 @@ static int do_validate_cmd(int cmd)
return 0;
}
-static int validate_cmd(int cmd)
-{
- int ret = do_validate_cmd(cmd);
-
-/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
-
- return ret;
-}
-
static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int i;
+ int i, ret;
- if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
+ if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8)
return -EINVAL;
- BEGIN_LP_RING((dwords+1)&~1);
-
for (i = 0; i < dwords;) {
- int cmd, sz;
-
- cmd = buffer[i];
-
- if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
+ int sz = validate_cmd(buffer[i]);
+ if (sz == 0 || i + sz > dwords)
return -EINVAL;
-
- OUT_RING(cmd);
-
- while (++i, --sz) {
- OUT_RING(buffer[i]);
- }
+ i += sz;
}
+ ret = BEGIN_LP_RING((dwords+1)&~1);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < dwords; i++)
+ OUT_RING(buffer[i]);
if (dwords & 1)
OUT_RING(0);
@@ -365,34 +356,41 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
int
i915_emit_box(struct drm_device *dev,
- struct drm_clip_rect *boxes,
- int i, int DR1, int DR4)
+ struct drm_clip_rect *box,
+ int DR1, int DR4)
{
- struct drm_clip_rect box = boxes[i];
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
- if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
+ if (box->y2 <= box->y1 || box->x2 <= box->x1 ||
+ box->y2 <= 0 || box->x2 <= 0) {
DRM_ERROR("Bad box %d,%d..%d,%d\n",
- box.x1, box.y1, box.x2, box.y2);
+ box->x1, box->y1, box->x2, box->y2);
return -EINVAL;
}
if (INTEL_INFO(dev)->gen >= 4) {
- BEGIN_LP_RING(4);
+ ret = BEGIN_LP_RING(4);
+ if (ret)
+ return ret;
+
OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
- OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
- OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+ OUT_RING((box->x1 & 0xffff) | (box->y1 << 16));
+ OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16));
OUT_RING(DR4);
- ADVANCE_LP_RING();
} else {
- BEGIN_LP_RING(6);
+ ret = BEGIN_LP_RING(6);
+ if (ret)
+ return ret;
+
OUT_RING(GFX_OP_DRAWRECT_INFO);
OUT_RING(DR1);
- OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
- OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+ OUT_RING((box->x1 & 0xffff) | (box->y1 << 16));
+ OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16));
OUT_RING(DR4);
OUT_RING(0);
- ADVANCE_LP_RING();
}
+ ADVANCE_LP_RING();
return 0;
}
@@ -412,12 +410,13 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_enqueue = dev_priv->counter;
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ if (BEGIN_LP_RING(4) == 0) {
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ }
}
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
@@ -439,7 +438,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
for (i = 0; i < count; i++) {
if (i < nbox) {
- ret = i915_emit_box(dev, cliprects, i,
+ ret = i915_emit_box(dev, &cliprects[i],
cmd->DR1, cmd->DR4);
if (ret)
return ret;
@@ -458,8 +457,9 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
drm_i915_batchbuffer_t * batch,
struct drm_clip_rect *cliprects)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
int nbox = batch->num_cliprects;
- int i = 0, count;
+ int i, count, ret;
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment");
@@ -469,17 +469,19 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
i915_kernel_lost_context(dev);
count = nbox ? nbox : 1;
-
for (i = 0; i < count; i++) {
if (i < nbox) {
- int ret = i915_emit_box(dev, cliprects, i,
- batch->DR1, batch->DR4);
+ ret = i915_emit_box(dev, &cliprects[i],
+ batch->DR1, batch->DR4);
if (ret)
return ret;
}
if (!IS_I830(dev) && !IS_845G(dev)) {
- BEGIN_LP_RING(2);
+ ret = BEGIN_LP_RING(2);
+ if (ret)
+ return ret;
+
if (INTEL_INFO(dev)->gen >= 4) {
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
OUT_RING(batch->start);
@@ -487,26 +489,29 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
}
- ADVANCE_LP_RING();
} else {
- BEGIN_LP_RING(4);
+ ret = BEGIN_LP_RING(4);
+ if (ret)
+ return ret;
+
OUT_RING(MI_BATCH_BUFFER);
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
OUT_RING(batch->start + batch->used - 4);
OUT_RING(0);
- ADVANCE_LP_RING();
}
+ ADVANCE_LP_RING();
}
if (IS_G4X(dev) || IS_GEN5(dev)) {
- BEGIN_LP_RING(2);
- OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
+ if (BEGIN_LP_RING(2) == 0) {
+ OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
+ OUT_RING(MI_NOOP);
+ ADVANCE_LP_RING();
+ }
}
- i915_emit_breadcrumb(dev);
+ i915_emit_breadcrumb(dev);
return 0;
}
@@ -515,6 +520,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv =
dev->primary->master->driver_priv;
+ int ret;
if (!master_priv->sarea_priv)
return -EINVAL;
@@ -526,12 +532,13 @@ static int i915_dispatch_flip(struct drm_device * dev)
i915_kernel_lost_context(dev);
- BEGIN_LP_RING(2);
+ ret = BEGIN_LP_RING(10);
+ if (ret)
+ return ret;
+
OUT_RING(MI_FLUSH | MI_READ_FLUSH);
OUT_RING(0);
- ADVANCE_LP_RING();
- BEGIN_LP_RING(6);
OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
OUT_RING(0);
if (dev_priv->current_page == 0) {
@@ -542,33 +549,32 @@ static int i915_dispatch_flip(struct drm_device * dev)
dev_priv->current_page = 0;
}
OUT_RING(0);
- ADVANCE_LP_RING();
- BEGIN_LP_RING(2);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
OUT_RING(0);
+
ADVANCE_LP_RING();
master_priv->sarea_priv->last_enqueue = dev_priv->counter++;
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ if (BEGIN_LP_RING(4) == 0) {
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ }
master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
return 0;
}
-static int i915_quiescent(struct drm_device * dev)
+static int i915_quiescent(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
i915_kernel_lost_context(dev);
- return intel_wait_ring_buffer(dev, &dev_priv->render_ring,
- dev_priv->render_ring.size - 8);
+ return intel_wait_ring_buffer(ring, ring->size - 8);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -767,6 +773,15 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_BLT:
value = HAS_BLT(dev);
break;
+ case I915_PARAM_HAS_RELAXED_FENCING:
+ value = 1;
+ break;
+ case I915_PARAM_HAS_COHERENT_RINGS:
+ value = 1;
+ break;
+ case I915_PARAM_HAS_EXEC_CONSTANTS:
+ value = INTEL_INFO(dev)->gen >= 4;
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -822,7 +837,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_hws_addr_t *hws = data;
- struct intel_ring_buffer *ring = &dev_priv->render_ring;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
if (!I915_NEED_GFX_HWS(dev))
return -EINVAL;
@@ -1001,73 +1016,47 @@ intel_teardown_mchbar(struct drm_device *dev)
#define PTE_VALID (1 << 0)
/**
- * i915_gtt_to_phys - take a GTT address and turn it into a physical one
+ * i915_stolen_to_phys - take an offset into stolen memory and turn it into
+ * a physical one
* @dev: drm device
- * @gtt_addr: address to translate
+ * @offset: address to translate
*
- * Some chip functions require allocations from stolen space but need the
- * physical address of the memory in question. We use this routine
- * to get a physical address suitable for register programming from a given
- * GTT address.
+ * Some chip functions require allocations from stolen space and need the
+ * physical address of the memory in question.
*/
-static unsigned long i915_gtt_to_phys(struct drm_device *dev,
- unsigned long gtt_addr)
+static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
{
- unsigned long *gtt;
- unsigned long entry, phys;
- int gtt_bar = IS_GEN2(dev) ? 1 : 0;
- int gtt_offset, gtt_size;
-
- if (INTEL_INFO(dev)->gen >= 4) {
- if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
- gtt_offset = 2*1024*1024;
- gtt_size = 2*1024*1024;
- } else {
- gtt_offset = 512*1024;
- gtt_size = 512*1024;
- }
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct pci_dev *pdev = dev_priv->bridge_dev;
+ u32 base;
+
+#if 0
+ /* On the machines I have tested the Graphics Base of Stolen Memory
+ * is unreliable, so compute the base by subtracting the stolen memory
+ * from the Top of Low Usable DRAM which is where the BIOS places
+ * the graphics stolen memory.
+ */
+ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
+ /* top 32bits are reserved = 0 */
+ pci_read_config_dword(pdev, 0xA4, &base);
} else {
- gtt_bar = 3;
- gtt_offset = 0;
- gtt_size = pci_resource_len(dev->pdev, gtt_bar);
- }
-
- gtt = ioremap_wc(pci_resource_start(dev->pdev, gtt_bar) + gtt_offset,
- gtt_size);
- if (!gtt) {
- DRM_ERROR("ioremap of GTT failed\n");
- return 0;
- }
-
- entry = *(volatile u32 *)(gtt + (gtt_addr / 1024));
-
- DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
-
- /* Mask out these reserved bits on this hardware. */
- if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
- entry &= ~PTE_ADDRESS_MASK_HIGH;
-
- /* If it's not a mapping type we know, then bail. */
- if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
- (entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_CACHED) {
- iounmap(gtt);
- return 0;
- }
-
- if (!(entry & PTE_VALID)) {
- DRM_ERROR("bad GTT entry in stolen space\n");
- iounmap(gtt);
- return 0;
+ /* XXX presume 8xx is the same as i915 */
+ pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
+ }
+#else
+ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
+ u16 val;
+ pci_read_config_word(pdev, 0xb0, &val);
+ base = val >> 4 << 20;
+ } else {
+ u8 val;
+ pci_read_config_byte(pdev, 0x9c, &val);
+ base = val >> 3 << 27;
}
+ base -= dev_priv->mm.gtt->stolen_size;
+#endif
- iounmap(gtt);
-
- phys =(entry & PTE_ADDRESS_MASK) |
- ((uint64_t)(entry & PTE_ADDRESS_MASK_HIGH) << (32 - 4));
-
- DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, phys addr: 0x%08lx\n", gtt_addr, phys);
-
- return phys;
+ return base + offset;
}
static void i915_warn_stolen(struct drm_device *dev)
@@ -1083,54 +1072,35 @@ static void i915_setup_compression(struct drm_device *dev, int size)
unsigned long cfb_base;
unsigned long ll_base = 0;
- /* Leave 1M for line length buffer & misc. */
- compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
- if (!compressed_fb) {
- dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- i915_warn_stolen(dev);
- return;
- }
-
- compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
- if (!compressed_fb) {
- i915_warn_stolen(dev);
- dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- return;
- }
+ compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
+ if (compressed_fb)
+ compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
+ if (!compressed_fb)
+ goto err;
- cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
- if (!cfb_base) {
- DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
- drm_mm_put_block(compressed_fb);
- }
+ cfb_base = i915_stolen_to_phys(dev, compressed_fb->start);
+ if (!cfb_base)
+ goto err_fb;
- if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
- compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
- 4096, 0);
- if (!compressed_llb) {
- i915_warn_stolen(dev);
- return;
- }
+ if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
+ compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
+ 4096, 4096, 0);
+ if (compressed_llb)
+ compressed_llb = drm_mm_get_block(compressed_llb,
+ 4096, 4096);
+ if (!compressed_llb)
+ goto err_fb;
- compressed_llb = drm_mm_get_block(compressed_llb, 4096, 4096);
- if (!compressed_llb) {
- i915_warn_stolen(dev);
- return;
- }
-
- ll_base = i915_gtt_to_phys(dev, compressed_llb->start);
- if (!ll_base) {
- DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
- drm_mm_put_block(compressed_fb);
- drm_mm_put_block(compressed_llb);
- }
+ ll_base = i915_stolen_to_phys(dev, compressed_llb->start);
+ if (!ll_base)
+ goto err_llb;
}
dev_priv->cfb_size = size;
intel_disable_fbc(dev);
dev_priv->compressed_fb = compressed_fb;
- if (IS_IRONLAKE_M(dev))
+ if (HAS_PCH_SPLIT(dev))
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
else if (IS_GM45(dev)) {
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
@@ -1140,8 +1110,17 @@ static void i915_setup_compression(struct drm_device *dev, int size)
dev_priv->compressed_llb = compressed_llb;
}
- DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
- ll_base, size >> 20);
+ DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
+ cfb_base, ll_base, size >> 20);
+ return;
+
+err_llb:
+ drm_mm_put_block(compressed_llb);
+err_fb:
+ drm_mm_put_block(compressed_fb);
+err:
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
+ i915_warn_stolen(dev);
}
static void i915_cleanup_compression(struct drm_device *dev)
@@ -1172,12 +1151,16 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "i915: switched on\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
printk(KERN_ERR "i915: switched off\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
i915_suspend(dev, pmm);
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
@@ -1192,17 +1175,20 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch;
}
-static int i915_load_modeset_init(struct drm_device *dev,
- unsigned long prealloc_size,
- unsigned long agp_size)
+static int i915_load_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long prealloc_size, gtt_size, mappable_size;
int ret = 0;
- /* Basic memrange allocator for stolen space (aka mm.vram) */
- drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
+ prealloc_size = dev_priv->mm.gtt->stolen_size;
+ gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
+ mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
- /* Let GEM Manage from end of prealloc space to end of aperture.
+ /* Basic memrange allocator for stolen space */
+ drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
+
+ /* Let GEM Manage all of the aperture.
*
* However, leave one page at the end still bound to the scratch page.
* There are a number of places where the hardware apparently
@@ -1211,7 +1197,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
* at the last page of the aperture. One page should be enough to
* keep any prefetching inside of the aperture.
*/
- i915_gem_do_init(dev, prealloc_size, agp_size - 4096);
+ i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
mutex_lock(&dev->struct_mutex);
ret = i915_gem_init_ringbuffer(dev);
@@ -1223,16 +1209,17 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (I915_HAS_FBC(dev) && i915_powersave) {
int cfb_size;
- /* Try to get an 8M buffer... */
- if (prealloc_size > (9*1024*1024))
- cfb_size = 8*1024*1024;
+ /* Leave 1M for line length buffer & misc. */
+
+ /* Try to get a 32M buffer... */
+ if (prealloc_size > (36*1024*1024))
+ cfb_size = 32*1024*1024;
else /* fall back to 7/8 of the stolen space */
cfb_size = prealloc_size * 7 / 8;
i915_setup_compression(dev, cfb_size);
}
- /* Allow hardware batchbuffers unless told otherwise.
- */
+ /* Allow hardware batchbuffers unless told otherwise. */
dev_priv->allow_batchbuffer = 1;
ret = intel_parse_bios(dev);
@@ -1248,6 +1235,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
ret = vga_switcheroo_register_client(dev->pdev,
i915_switcheroo_set_state,
+ NULL,
i915_switcheroo_can_switch);
if (ret)
goto cleanup_vga_client;
@@ -1422,152 +1410,12 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev)
}
}
-struct v_table {
- u8 vid;
- unsigned long vd; /* in .1 mil */
- unsigned long vm; /* in .1 mil */
- u8 pvid;
-};
-
-static struct v_table v_table[] = {
- { 0, 16125, 15000, 0x7f, },
- { 1, 16000, 14875, 0x7e, },
- { 2, 15875, 14750, 0x7d, },
- { 3, 15750, 14625, 0x7c, },
- { 4, 15625, 14500, 0x7b, },
- { 5, 15500, 14375, 0x7a, },
- { 6, 15375, 14250, 0x79, },
- { 7, 15250, 14125, 0x78, },
- { 8, 15125, 14000, 0x77, },
- { 9, 15000, 13875, 0x76, },
- { 10, 14875, 13750, 0x75, },
- { 11, 14750, 13625, 0x74, },
- { 12, 14625, 13500, 0x73, },
- { 13, 14500, 13375, 0x72, },
- { 14, 14375, 13250, 0x71, },
- { 15, 14250, 13125, 0x70, },
- { 16, 14125, 13000, 0x6f, },
- { 17, 14000, 12875, 0x6e, },
- { 18, 13875, 12750, 0x6d, },
- { 19, 13750, 12625, 0x6c, },
- { 20, 13625, 12500, 0x6b, },
- { 21, 13500, 12375, 0x6a, },
- { 22, 13375, 12250, 0x69, },
- { 23, 13250, 12125, 0x68, },
- { 24, 13125, 12000, 0x67, },
- { 25, 13000, 11875, 0x66, },
- { 26, 12875, 11750, 0x65, },
- { 27, 12750, 11625, 0x64, },
- { 28, 12625, 11500, 0x63, },
- { 29, 12500, 11375, 0x62, },
- { 30, 12375, 11250, 0x61, },
- { 31, 12250, 11125, 0x60, },
- { 32, 12125, 11000, 0x5f, },
- { 33, 12000, 10875, 0x5e, },
- { 34, 11875, 10750, 0x5d, },
- { 35, 11750, 10625, 0x5c, },
- { 36, 11625, 10500, 0x5b, },
- { 37, 11500, 10375, 0x5a, },
- { 38, 11375, 10250, 0x59, },
- { 39, 11250, 10125, 0x58, },
- { 40, 11125, 10000, 0x57, },
- { 41, 11000, 9875, 0x56, },
- { 42, 10875, 9750, 0x55, },
- { 43, 10750, 9625, 0x54, },
- { 44, 10625, 9500, 0x53, },
- { 45, 10500, 9375, 0x52, },
- { 46, 10375, 9250, 0x51, },
- { 47, 10250, 9125, 0x50, },
- { 48, 10125, 9000, 0x4f, },
- { 49, 10000, 8875, 0x4e, },
- { 50, 9875, 8750, 0x4d, },
- { 51, 9750, 8625, 0x4c, },
- { 52, 9625, 8500, 0x4b, },
- { 53, 9500, 8375, 0x4a, },
- { 54, 9375, 8250, 0x49, },
- { 55, 9250, 8125, 0x48, },
- { 56, 9125, 8000, 0x47, },
- { 57, 9000, 7875, 0x46, },
- { 58, 8875, 7750, 0x45, },
- { 59, 8750, 7625, 0x44, },
- { 60, 8625, 7500, 0x43, },
- { 61, 8500, 7375, 0x42, },
- { 62, 8375, 7250, 0x41, },
- { 63, 8250, 7125, 0x40, },
- { 64, 8125, 7000, 0x3f, },
- { 65, 8000, 6875, 0x3e, },
- { 66, 7875, 6750, 0x3d, },
- { 67, 7750, 6625, 0x3c, },
- { 68, 7625, 6500, 0x3b, },
- { 69, 7500, 6375, 0x3a, },
- { 70, 7375, 6250, 0x39, },
- { 71, 7250, 6125, 0x38, },
- { 72, 7125, 6000, 0x37, },
- { 73, 7000, 5875, 0x36, },
- { 74, 6875, 5750, 0x35, },
- { 75, 6750, 5625, 0x34, },
- { 76, 6625, 5500, 0x33, },
- { 77, 6500, 5375, 0x32, },
- { 78, 6375, 5250, 0x31, },
- { 79, 6250, 5125, 0x30, },
- { 80, 6125, 5000, 0x2f, },
- { 81, 6000, 4875, 0x2e, },
- { 82, 5875, 4750, 0x2d, },
- { 83, 5750, 4625, 0x2c, },
- { 84, 5625, 4500, 0x2b, },
- { 85, 5500, 4375, 0x2a, },
- { 86, 5375, 4250, 0x29, },
- { 87, 5250, 4125, 0x28, },
- { 88, 5125, 4000, 0x27, },
- { 89, 5000, 3875, 0x26, },
- { 90, 4875, 3750, 0x25, },
- { 91, 4750, 3625, 0x24, },
- { 92, 4625, 3500, 0x23, },
- { 93, 4500, 3375, 0x22, },
- { 94, 4375, 3250, 0x21, },
- { 95, 4250, 3125, 0x20, },
- { 96, 4125, 3000, 0x1f, },
- { 97, 4125, 3000, 0x1e, },
- { 98, 4125, 3000, 0x1d, },
- { 99, 4125, 3000, 0x1c, },
- { 100, 4125, 3000, 0x1b, },
- { 101, 4125, 3000, 0x1a, },
- { 102, 4125, 3000, 0x19, },
- { 103, 4125, 3000, 0x18, },
- { 104, 4125, 3000, 0x17, },
- { 105, 4125, 3000, 0x16, },
- { 106, 4125, 3000, 0x15, },
- { 107, 4125, 3000, 0x14, },
- { 108, 4125, 3000, 0x13, },
- { 109, 4125, 3000, 0x12, },
- { 110, 4125, 3000, 0x11, },
- { 111, 4125, 3000, 0x10, },
- { 112, 4125, 3000, 0x0f, },
- { 113, 4125, 3000, 0x0e, },
- { 114, 4125, 3000, 0x0d, },
- { 115, 4125, 3000, 0x0c, },
- { 116, 4125, 3000, 0x0b, },
- { 117, 4125, 3000, 0x0a, },
- { 118, 4125, 3000, 0x09, },
- { 119, 4125, 3000, 0x08, },
- { 120, 1125, 0, 0x07, },
- { 121, 1000, 0, 0x06, },
- { 122, 875, 0, 0x05, },
- { 123, 750, 0, 0x04, },
- { 124, 625, 0, 0x03, },
- { 125, 500, 0, 0x02, },
- { 126, 375, 0, 0x01, },
- { 127, 0, 0, 0x00, },
-};
-
-struct cparams {
- int i;
- int t;
- int m;
- int c;
-};
-
-static struct cparams cparams[] = {
+static const struct cparams {
+ u16 i;
+ u16 t;
+ u16 m;
+ u16 c;
+} cparams[] = {
{ 1, 1333, 301, 28664 },
{ 1, 1066, 294, 24460 },
{ 1, 800, 294, 25192 },
@@ -1633,21 +1481,145 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
return ((m * x) / 127) - b;
}
-static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
+static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
{
- unsigned long val = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(v_table); i++) {
- if (v_table[i].pvid == pxvid) {
- if (IS_MOBILE(dev_priv->dev))
- val = v_table[i].vm;
- else
- val = v_table[i].vd;
- }
- }
-
- return val;
+ static const struct v_table {
+ u16 vd; /* in .1 mil */
+ u16 vm; /* in .1 mil */
+ } v_table[] = {
+ { 0, 0, },
+ { 375, 0, },
+ { 500, 0, },
+ { 625, 0, },
+ { 750, 0, },
+ { 875, 0, },
+ { 1000, 0, },
+ { 1125, 0, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4250, 3125, },
+ { 4375, 3250, },
+ { 4500, 3375, },
+ { 4625, 3500, },
+ { 4750, 3625, },
+ { 4875, 3750, },
+ { 5000, 3875, },
+ { 5125, 4000, },
+ { 5250, 4125, },
+ { 5375, 4250, },
+ { 5500, 4375, },
+ { 5625, 4500, },
+ { 5750, 4625, },
+ { 5875, 4750, },
+ { 6000, 4875, },
+ { 6125, 5000, },
+ { 6250, 5125, },
+ { 6375, 5250, },
+ { 6500, 5375, },
+ { 6625, 5500, },
+ { 6750, 5625, },
+ { 6875, 5750, },
+ { 7000, 5875, },
+ { 7125, 6000, },
+ { 7250, 6125, },
+ { 7375, 6250, },
+ { 7500, 6375, },
+ { 7625, 6500, },
+ { 7750, 6625, },
+ { 7875, 6750, },
+ { 8000, 6875, },
+ { 8125, 7000, },
+ { 8250, 7125, },
+ { 8375, 7250, },
+ { 8500, 7375, },
+ { 8625, 7500, },
+ { 8750, 7625, },
+ { 8875, 7750, },
+ { 9000, 7875, },
+ { 9125, 8000, },
+ { 9250, 8125, },
+ { 9375, 8250, },
+ { 9500, 8375, },
+ { 9625, 8500, },
+ { 9750, 8625, },
+ { 9875, 8750, },
+ { 10000, 8875, },
+ { 10125, 9000, },
+ { 10250, 9125, },
+ { 10375, 9250, },
+ { 10500, 9375, },
+ { 10625, 9500, },
+ { 10750, 9625, },
+ { 10875, 9750, },
+ { 11000, 9875, },
+ { 11125, 10000, },
+ { 11250, 10125, },
+ { 11375, 10250, },
+ { 11500, 10375, },
+ { 11625, 10500, },
+ { 11750, 10625, },
+ { 11875, 10750, },
+ { 12000, 10875, },
+ { 12125, 11000, },
+ { 12250, 11125, },
+ { 12375, 11250, },
+ { 12500, 11375, },
+ { 12625, 11500, },
+ { 12750, 11625, },
+ { 12875, 11750, },
+ { 13000, 11875, },
+ { 13125, 12000, },
+ { 13250, 12125, },
+ { 13375, 12250, },
+ { 13500, 12375, },
+ { 13625, 12500, },
+ { 13750, 12625, },
+ { 13875, 12750, },
+ { 14000, 12875, },
+ { 14125, 13000, },
+ { 14250, 13125, },
+ { 14375, 13250, },
+ { 14500, 13375, },
+ { 14625, 13500, },
+ { 14750, 13625, },
+ { 14875, 13750, },
+ { 15000, 13875, },
+ { 15125, 14000, },
+ { 15250, 14125, },
+ { 15375, 14250, },
+ { 15500, 14375, },
+ { 15625, 14500, },
+ { 15750, 14625, },
+ { 15875, 14750, },
+ { 16000, 14875, },
+ { 16125, 15000, },
+ };
+ if (dev_priv->info->is_mobile)
+ return v_table[pxvid].vm;
+ else
+ return v_table[pxvid].vd;
}
void i915_update_gfx_val(struct drm_i915_private *dev_priv)
@@ -1868,6 +1840,26 @@ out_unlock:
EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
/**
+ * Tells the intel_ips driver that the i915 driver is now loaded, if
+ * IPS got loaded first.
+ *
+ * This awkward dance is so that neither module has to depend on the
+ * other in order for IPS to do the appropriate communication of
+ * GPU turbo limits to i915.
+ */
+static void
+ips_ping_for_i915_load(void)
+{
+ void (*link)(void);
+
+ link = symbol_get(ips_link_to_i915_driver);
+ if (link) {
+ link();
+ symbol_put(ips_link_to_i915_driver);
+ }
+}
+
+/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
* @flags: startup flags
@@ -1881,9 +1873,9 @@ EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv;
- resource_size_t base, size;
int ret = 0, mmio_bar;
- uint32_t agp_size, prealloc_size;
+ uint32_t agp_size;
+
/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
@@ -1899,11 +1891,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->dev = dev;
dev_priv->info = (struct intel_device_info *) flags;
- /* Add register map (needed for suspend/resume) */
- mmio_bar = IS_GEN2(dev) ? 1 : 0;
- base = pci_resource_start(dev->pdev, mmio_bar);
- size = pci_resource_len(dev->pdev, mmio_bar);
-
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
goto free_priv;
@@ -1913,16 +1900,25 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (IS_GEN2(dev))
dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
- dev_priv->regs = ioremap(base, size);
+ mmio_bar = IS_GEN2(dev) ? 1 : 0;
+ dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
if (!dev_priv->regs) {
DRM_ERROR("failed to map registers\n");
ret = -EIO;
goto put_bridge;
}
+ dev_priv->mm.gtt = intel_gtt_get();
+ if (!dev_priv->mm.gtt) {
+ DRM_ERROR("Failed to initialize GTT\n");
+ ret = -ENODEV;
+ goto out_iomapfree;
+ }
+
+ agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
dev_priv->mm.gtt_mapping =
- io_mapping_create_wc(dev->agp->base,
- dev->agp->agp_info.aper_size * 1024*1024);
+ io_mapping_create_wc(dev->agp->base, agp_size);
if (dev_priv->mm.gtt_mapping == NULL) {
ret = -EIO;
goto out_rmmap;
@@ -1934,24 +1930,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
* MTRR if present. Even if a UC MTRR isn't present.
*/
dev_priv->mm.gtt_mtrr = mtrr_add(dev->agp->base,
- dev->agp->agp_info.aper_size *
- 1024 * 1024,
+ agp_size,
MTRR_TYPE_WRCOMB, 1);
if (dev_priv->mm.gtt_mtrr < 0) {
DRM_INFO("MTRR allocation failed. Graphics "
"performance may suffer.\n");
}
- dev_priv->mm.gtt = intel_gtt_get();
- if (!dev_priv->mm.gtt) {
- DRM_ERROR("Failed to initialize GTT\n");
- ret = -ENODEV;
- goto out_iomapfree;
- }
-
- prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
- agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
-
/* The i915 workqueue is primarily used for batched retirement of
* requests (and thus managing bo) once the task has been completed
* by the GPU. i915_gem_retire_requests() is called directly when we
@@ -1959,7 +1944,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
* bo.
*
* It is also used for periodic low-priority events, such as
- * idle-timers and hangcheck.
+ * idle-timers and recording error state.
*
* All tasks on the workqueue are expected to acquire the dev mutex
* so there is no point in running more than one instance of the
@@ -1977,22 +1962,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* enable GEM by default */
dev_priv->has_gem = 1;
- if (prealloc_size > agp_size * 3 / 4) {
- DRM_ERROR("Detected broken video BIOS with %d/%dkB of video "
- "memory stolen.\n",
- prealloc_size / 1024, agp_size / 1024);
- DRM_ERROR("Disabling GEM. (try reducing stolen memory or "
- "updating the BIOS to fix).\n");
- dev_priv->has_gem = 0;
- }
-
- if (dev_priv->has_gem == 0 &&
- drm_core_check_feature(dev, DRIVER_MODESET)) {
- DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n");
- ret = -ENODEV;
- goto out_iomapfree;
- }
-
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
@@ -2013,8 +1982,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Init HWS */
if (!I915_NEED_GFX_HWS(dev)) {
ret = i915_init_phys_hws(dev);
- if (ret != 0)
- goto out_workqueue_free;
+ if (ret)
+ goto out_gem_unload;
}
if (IS_PINEVIEW(dev))
@@ -2036,16 +2005,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!IS_I945G(dev) && !IS_I945GM(dev))
pci_enable_msi(dev->pdev);
- spin_lock_init(&dev_priv->user_irq_lock);
+ spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock);
dev_priv->trace_irq_seqno = 0;
ret = drm_vblank_init(dev, I915_NUM_PIPE);
-
- if (ret) {
- (void) i915_driver_unload(dev);
- return ret;
- }
+ if (ret)
+ goto out_gem_unload;
/* Start out suspended */
dev_priv->mm.suspended = 1;
@@ -2053,10 +2019,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_detect_pch(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
+ ret = i915_load_modeset_init(dev);
if (ret < 0) {
DRM_ERROR("failed to init modeset\n");
- goto out_workqueue_free;
+ goto out_gem_unload;
}
}
@@ -2072,14 +2038,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->mchdev_lock = &mchdev_lock;
spin_unlock(&mchdev_lock);
+ ips_ping_for_i915_load();
+
return 0;
-out_workqueue_free:
+out_gem_unload:
+ if (dev->pdev->msi_enabled)
+ pci_disable_msi(dev->pdev);
+
+ intel_teardown_gmbus(dev);
+ intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->wq);
out_iomapfree:
io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap:
- iounmap(dev_priv->regs);
+ pci_iounmap(dev->pdev, dev_priv->regs);
put_bridge:
pci_dev_put(dev_priv->bridge_dev);
free_priv:
@@ -2096,6 +2069,9 @@ int i915_driver_unload(struct drm_device *dev)
i915_mch_dev = NULL;
spin_unlock(&mchdev_lock);
+ if (dev_priv->mm.inactive_shrinker.shrink)
+ unregister_shrinker(&dev_priv->mm.inactive_shrinker);
+
mutex_lock(&dev->struct_mutex);
ret = i915_gpu_idle(dev);
if (ret)
@@ -2153,7 +2129,7 @@ int i915_driver_unload(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
if (I915_HAS_FBC(dev) && i915_powersave)
i915_cleanup_compression(dev);
- drm_mm_takedown(&dev_priv->mm.vram);
+ drm_mm_takedown(&dev_priv->mm.stolen);
intel_cleanup_overlay(dev);
@@ -2162,7 +2138,7 @@ int i915_driver_unload(struct drm_device *dev)
}
if (dev_priv->regs != NULL)
- iounmap(dev_priv->regs);
+ pci_iounmap(dev->pdev, dev_priv->regs);
intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3467dd420760..72fea2bcfc4f 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -44,11 +44,17 @@ unsigned int i915_fbpercrtc = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
unsigned int i915_powersave = 1;
-module_param_named(powersave, i915_powersave, int, 0400);
+module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+unsigned int i915_panel_use_ssc = 1;
+module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
+
+bool i915_try_reset = true;
+module_param_named(reset, i915_try_reset, bool, 0600);
+
static struct drm_driver driver;
extern int intel_agp_enabled;
@@ -111,7 +117,7 @@ static const struct intel_device_info intel_i965g_info = {
static const struct intel_device_info intel_i965gm_info = {
.gen = 4, .is_crestline = 1,
- .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
.has_overlay = 1,
.supports_tv = 1,
};
@@ -130,7 +136,7 @@ static const struct intel_device_info intel_g45_info = {
static const struct intel_device_info intel_gm45_info = {
.gen = 4, .is_g4x = 1,
- .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
+ .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
.has_pipe_cxsr = 1, .has_hotplug = 1,
.supports_tv = 1,
.has_bsd_ring = 1,
@@ -150,7 +156,8 @@ static const struct intel_device_info intel_ironlake_d_info = {
static const struct intel_device_info intel_ironlake_m_info = {
.gen = 5, .is_mobile = 1,
- .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_fbc = 0, /* disabled due to buggy hardware */
.has_bsd_ring = 1,
};
@@ -164,6 +171,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
static const struct intel_device_info intel_sandybridge_m_info = {
.gen = 6, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
+ .has_fbc = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
};
@@ -243,10 +251,34 @@ void intel_detect_pch (struct drm_device *dev)
}
}
+void __gen6_force_wake_get(struct drm_i915_private *dev_priv)
+{
+ int count;
+
+ count = 0;
+ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
+ udelay(10);
+
+ I915_WRITE_NOTRACE(FORCEWAKE, 1);
+ POSTING_READ(FORCEWAKE);
+
+ count = 0;
+ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0)
+ udelay(10);
+}
+
+void __gen6_force_wake_put(struct drm_i915_private *dev_priv)
+{
+ I915_WRITE_NOTRACE(FORCEWAKE, 0);
+ POSTING_READ(FORCEWAKE);
+}
+
static int i915_drm_freeze(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ drm_kms_helper_poll_disable(dev);
+
pci_save_state(dev->pdev);
/* If KMS is active, we do the leavevt stuff here */
@@ -283,7 +315,9 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
if (state.event == PM_EVENT_PRETHAW)
return 0;
- drm_kms_helper_poll_disable(dev);
+
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
error = i915_drm_freeze(dev);
if (error)
@@ -303,6 +337,12 @@ static int i915_drm_thaw(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int error = 0;
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_restore_gtt_mappings(dev);
+ mutex_unlock(&dev->struct_mutex);
+ }
+
i915_restore_state(dev);
intel_opregion_setup(dev);
@@ -318,6 +358,9 @@ static int i915_drm_thaw(struct drm_device *dev)
/* Resume the modeset for every activated CRTC */
drm_helper_resume_force_mode(dev);
+
+ if (dev_priv->renderctx && dev_priv->pwrctx)
+ ironlake_enable_rc6(dev);
}
intel_opregion_init(dev);
@@ -331,6 +374,9 @@ int i915_resume(struct drm_device *dev)
{
int ret;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
if (pci_enable_device(dev->pdev))
return -EIO;
@@ -404,6 +450,14 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags)
return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
}
+static int gen6_do_reset(struct drm_device *dev, u8 flags)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(GEN6_GDRST, GEN6_GRDOM_FULL);
+ return wait_for((I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
+}
+
/**
* i965_reset - reset chip after a hang
* @dev: drm device to reset
@@ -430,7 +484,11 @@ int i915_reset(struct drm_device *dev, u8 flags)
bool need_display = true;
int ret;
- mutex_lock(&dev->struct_mutex);
+ if (!i915_try_reset)
+ return 0;
+
+ if (!mutex_trylock(&dev->struct_mutex))
+ return -EBUSY;
i915_gem_reset(dev);
@@ -438,6 +496,9 @@ int i915_reset(struct drm_device *dev, u8 flags)
if (get_seconds() - dev_priv->last_gpu_reset < 5) {
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
} else switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ ret = gen6_do_reset(dev, flags);
+ break;
case 5:
ret = ironlake_do_reset(dev, flags);
break;
@@ -471,9 +532,14 @@ int i915_reset(struct drm_device *dev, u8 flags)
*/
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
!dev_priv->mm.suspended) {
- struct intel_ring_buffer *ring = &dev_priv->render_ring;
dev_priv->mm.suspended = 0;
- ring->init(dev, ring);
+
+ dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
+ if (HAS_BSD(dev))
+ dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
+ if (HAS_BLT(dev))
+ dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
+
mutex_unlock(&dev->struct_mutex);
drm_irq_uninstall(dev);
drm_irq_install(dev);
@@ -522,6 +588,9 @@ static int i915_pm_suspend(struct device *dev)
return -ENODEV;
}
+ if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
error = i915_drm_freeze(drm_dev);
if (error)
return error;
@@ -605,6 +674,8 @@ static struct drm_driver driver = {
.device_is_agp = i915_driver_device_is_agp,
.enable_vblank = i915_enable_vblank,
.disable_vblank = i915_disable_vblank,
+ .get_vblank_timestamp = i915_get_vblank_timestamp,
+ .get_scanout_position = i915_get_crtc_scanoutpos,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
@@ -660,8 +731,6 @@ static int __init i915_init(void)
driver.num_ioctls = i915_max_ioctl;
- i915_gem_shrinker_init();
-
/*
* If CONFIG_DRM_I915_KMS is set, default to KMS unless
* explicitly disabled with the module pararmeter.
@@ -683,17 +752,11 @@ static int __init i915_init(void)
driver.driver_features &= ~DRIVER_MODESET;
#endif
- if (!(driver.driver_features & DRIVER_MODESET)) {
- driver.suspend = i915_suspend;
- driver.resume = i915_resume;
- }
-
return drm_init(&driver);
}
static void __exit i915_exit(void)
{
- i915_gem_shrinker_exit();
drm_exit(&driver);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2c2c19b6285e..5969f46ac2d6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -89,7 +89,7 @@ struct drm_i915_gem_phys_object {
int id;
struct page **page_list;
drm_dma_handle_t *handle;
- struct drm_gem_object *cur_obj;
+ struct drm_i915_gem_object *cur_obj;
};
struct mem_block {
@@ -124,9 +124,9 @@ struct drm_i915_master_private {
#define I915_FENCE_REG_NONE -1
struct drm_i915_fence_reg {
- struct drm_gem_object *obj;
struct list_head lru_list;
- bool gpu;
+ struct drm_i915_gem_object *obj;
+ uint32_t setup_seqno;
};
struct sdvo_device_mapping {
@@ -139,6 +139,8 @@ struct sdvo_device_mapping {
u8 ddc_pin;
};
+struct intel_display_error_state;
+
struct drm_i915_error_state {
u32 eir;
u32 pgtbl_er;
@@ -148,32 +150,47 @@ struct drm_i915_error_state {
u32 ipehr;
u32 instdone;
u32 acthd;
+ u32 error; /* gen6+ */
+ u32 bcs_acthd; /* gen6+ blt engine */
+ u32 bcs_ipehr;
+ u32 bcs_ipeir;
+ u32 bcs_instdone;
+ u32 bcs_seqno;
+ u32 vcs_acthd; /* gen6+ bsd engine */
+ u32 vcs_ipehr;
+ u32 vcs_ipeir;
+ u32 vcs_instdone;
+ u32 vcs_seqno;
u32 instpm;
u32 instps;
u32 instdone1;
u32 seqno;
u64 bbaddr;
+ u64 fence[16];
struct timeval time;
struct drm_i915_error_object {
int page_count;
u32 gtt_offset;
u32 *pages[0];
- } *ringbuffer, *batchbuffer[2];
+ } *ringbuffer, *batchbuffer[I915_NUM_RINGS];
struct drm_i915_error_buffer {
- size_t size;
+ u32 size;
u32 name;
u32 seqno;
u32 gtt_offset;
u32 read_domains;
u32 write_domain;
- u32 fence_reg;
+ s32 fence_reg:5;
s32 pinned:2;
u32 tiling:2;
u32 dirty:1;
u32 purgeable:1;
- } *active_bo;
- u32 active_bo_count;
+ u32 ring:4;
+ u32 agp_type:1;
+ } *active_bo, *pinned_bo;
+ u32 active_bo_count, pinned_bo_count;
struct intel_overlay_error_state *overlay;
+ struct intel_display_error_state *display;
};
struct drm_i915_display_funcs {
@@ -207,7 +224,6 @@ struct intel_device_info {
u8 is_broadwater : 1;
u8 is_crestline : 1;
u8 has_fbc : 1;
- u8 has_rc6 : 1;
u8 has_pipe_cxsr : 1;
u8 has_hotplug : 1;
u8 cursor_needs_physical : 1;
@@ -243,6 +259,7 @@ typedef struct drm_i915_private {
const struct intel_device_info *info;
int has_gem;
+ int relative_constants_mode;
void __iomem *regs;
@@ -253,20 +270,15 @@ typedef struct drm_i915_private {
} *gmbus;
struct pci_dev *bridge_dev;
- struct intel_ring_buffer render_ring;
- struct intel_ring_buffer bsd_ring;
- struct intel_ring_buffer blt_ring;
+ struct intel_ring_buffer ring[I915_NUM_RINGS];
uint32_t next_seqno;
drm_dma_handle_t *status_page_dmah;
- void *seqno_page;
dma_addr_t dma_status_page;
uint32_t counter;
- unsigned int seqno_gfx_addr;
drm_local_map_t hws_map;
- struct drm_gem_object *seqno_obj;
- struct drm_gem_object *pwrctx;
- struct drm_gem_object *renderctx;
+ struct drm_i915_gem_object *pwrctx;
+ struct drm_i915_gem_object *renderctx;
struct resource mch_res;
@@ -275,25 +287,17 @@ typedef struct drm_i915_private {
int front_offset;
int current_page;
int page_flipping;
-#define I915_DEBUG_READ (1<<0)
-#define I915_DEBUG_WRITE (1<<1)
- unsigned long debug_flags;
- wait_queue_head_t irq_queue;
atomic_t irq_received;
- /** Protects user_irq_refcount and irq_mask_reg */
- spinlock_t user_irq_lock;
u32 trace_irq_seqno;
+
+ /* protects the irq masks */
+ spinlock_t irq_lock;
/** Cached value of IMR to avoid reads in updating the bitfield */
- u32 irq_mask_reg;
u32 pipestat[2];
- /** splitted irq regs for graphics and display engine on Ironlake,
- irq_mask_reg is still used for display irq. */
- u32 gt_irq_mask_reg;
- u32 gt_irq_enable_reg;
- u32 de_irq_enable_reg;
- u32 pch_irq_mask_reg;
- u32 pch_irq_enable_reg;
+ u32 irq_mask;
+ u32 gt_irq_mask;
+ u32 pch_irq_mask;
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
@@ -306,7 +310,7 @@ typedef struct drm_i915_private {
int num_pipe;
/* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
+#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
struct timer_list hangcheck_timer;
int hangcheck_count;
uint32_t last_acthd;
@@ -329,6 +333,7 @@ typedef struct drm_i915_private {
/* LVDS info */
int backlight_level; /* restore backlight to this value */
+ bool backlight_enabled;
struct drm_display_mode *panel_fixed_mode;
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -530,23 +535,21 @@ typedef struct drm_i915_private {
struct {
/** Bridge to intel-gtt-ko */
- struct intel_gtt *gtt;
+ const struct intel_gtt *gtt;
/** Memory allocator for GTT stolen memory */
- struct drm_mm vram;
+ struct drm_mm stolen;
/** Memory allocator for GTT */
struct drm_mm gtt_space;
+ /** List of all objects in gtt_space. Used to restore gtt
+ * mappings on resume */
+ struct list_head gtt_list;
+ /** End of mappable part of GTT */
+ unsigned long gtt_mappable_end;
struct io_mapping *gtt_mapping;
int gtt_mtrr;
- /**
- * Membership on list of all loaded devices, used to evict
- * inactive buffers under memory pressure.
- *
- * Modifications should only be done whilst holding the
- * shrink_list_lock spinlock.
- */
- struct list_head shrink_list;
+ struct shrinker inactive_shrinker;
/**
* List of objects currently involved in rendering.
@@ -609,16 +612,6 @@ typedef struct drm_i915_private {
struct delayed_work retire_work;
/**
- * Waiting sequence number, if any
- */
- uint32_t waiting_gem_seqno;
-
- /**
- * Last seq seen at irq time
- */
- uint32_t irq_gem_seqno;
-
- /**
* Flag if the X Server, and thus DRM, is not currently in
* control of the device.
*
@@ -645,16 +638,11 @@ typedef struct drm_i915_private {
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
- uint32_t flush_rings;
-
/* accounting, useful for userland debugging */
- size_t object_memory;
- size_t pin_memory;
- size_t gtt_memory;
size_t gtt_total;
+ size_t mappable_gtt_total;
+ size_t object_memory;
u32 object_count;
- u32 pin_count;
- u32 gtt_count;
} mm;
struct sdvo_device_mapping sdvo_mappings[2];
/* indicate whether the LVDS_BORDER should be enabled or not */
@@ -688,14 +676,14 @@ typedef struct drm_i915_private {
u8 fmax;
u8 fstart;
- u64 last_count1;
- unsigned long last_time1;
- u64 last_count2;
- struct timespec last_time2;
- unsigned long gfx_power;
- int c_m;
- int r_t;
- u8 corr;
+ u64 last_count1;
+ unsigned long last_time1;
+ u64 last_count2;
+ struct timespec last_time2;
+ unsigned long gfx_power;
+ int c_m;
+ int r_t;
+ u8 corr;
spinlock_t *mchdev_lock;
enum no_fbc_reason no_fbc_reason;
@@ -709,20 +697,20 @@ typedef struct drm_i915_private {
struct intel_fbdev *fbdev;
} drm_i915_private_t;
-/** driver private structure attached to each drm_gem_object */
struct drm_i915_gem_object {
struct drm_gem_object base;
/** Current space allocated to this object in the GTT, if any. */
struct drm_mm_node *gtt_space;
+ struct list_head gtt_list;
/** This object's place on the active/flushing/inactive lists */
struct list_head ring_list;
struct list_head mm_list;
/** This object's place on GPU write list */
struct list_head gpu_write_list;
- /** This object's place on eviction list */
- struct list_head evict_list;
+ /** This object's place in the batchbuffer or on the eviction list */
+ struct list_head exec_list;
/**
* This is set if the object is on the active or flushing lists
@@ -738,6 +726,12 @@ struct drm_i915_gem_object {
unsigned int dirty : 1;
/**
+ * This is set if the object has been written to since the last
+ * GPU flush.
+ */
+ unsigned int pending_gpu_write : 1;
+
+ /**
* Fence register bits (if any) for this object. Will be set
* as needed when mapped into the GTT.
* Protected by dev->struct_mutex.
@@ -747,29 +741,15 @@ struct drm_i915_gem_object {
signed int fence_reg : 5;
/**
- * Used for checking the object doesn't appear more than once
- * in an execbuffer object list.
- */
- unsigned int in_execbuffer : 1;
-
- /**
* Advice: are the backing pages purgeable?
*/
unsigned int madv : 2;
/**
- * Refcount for the pages array. With the current locking scheme, there
- * are at most two concurrent users: Binding a bo to the gtt and
- * pwrite/pread using physical addresses. So two bits for a maximum
- * of two users are enough.
- */
- unsigned int pages_refcount : 2;
-#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3
-
- /**
* Current tiling mode for the object.
*/
unsigned int tiling_mode : 2;
+ unsigned int tiling_changed : 1;
/** How many users have pinned this object in GTT space. The following
* users can each hold at most one reference: pwrite/pread, pin_ioctl
@@ -783,28 +763,55 @@ struct drm_i915_gem_object {
unsigned int pin_count : 4;
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
- /** AGP memory structure for our GTT binding. */
- DRM_AGP_MEM *agp_mem;
+ /**
+ * Is the object at the current location in the gtt mappable and
+ * fenceable? Used to avoid costly recalculations.
+ */
+ unsigned int map_and_fenceable : 1;
+
+ /**
+ * Whether the current gtt mapping needs to be mappable (and isn't just
+ * mappable by accident). Track pin and fault separate for a more
+ * accurate mappable working set.
+ */
+ unsigned int fault_mappable : 1;
+ unsigned int pin_mappable : 1;
+
+ /*
+ * Is the GPU currently using a fence to access this buffer,
+ */
+ unsigned int pending_fenced_gpu_access:1;
+ unsigned int fenced_gpu_access:1;
struct page **pages;
/**
- * Current offset of the object in GTT space.
- *
- * This is the same as gtt_space->start
+ * DMAR support
*/
- uint32_t gtt_offset;
+ struct scatterlist *sg_list;
+ int num_sg;
- /* Which ring is refering to is this object */
- struct intel_ring_buffer *ring;
+ /**
+ * Used for performing relocations during execbuffer insertion.
+ */
+ struct hlist_node exec_node;
+ unsigned long exec_handle;
+ struct drm_i915_gem_exec_object2 *exec_entry;
/**
- * Fake offset for use by mmap(2)
+ * Current offset of the object in GTT space.
+ *
+ * This is the same as gtt_space->start
*/
- uint64_t mmap_offset;
+ uint32_t gtt_offset;
/** Breadcrumb of last rendering to the buffer. */
uint32_t last_rendering_seqno;
+ struct intel_ring_buffer *ring;
+
+ /** Breadcrumb of last fenced GPU access to the buffer. */
+ uint32_t last_fenced_seqno;
+ struct intel_ring_buffer *last_fenced_ring;
/** Current tiling stride for the object, if it's tiled. */
uint32_t stride;
@@ -880,11 +887,74 @@ enum intel_chip_family {
CHIP_I965 = 0x08,
};
+#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info)
+
+#define IS_I830(dev) ((dev)->pci_device == 0x3577)
+#define IS_845G(dev) ((dev)->pci_device == 0x2562)
+#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x)
+#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
+#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g)
+#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
+#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
+#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm)
+#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater)
+#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline)
+#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
+#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x)
+#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001)
+#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011)
+#define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview)
+#define IS_G33(dev) (INTEL_INFO(dev)->is_g33)
+#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
+#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
+#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
+
+#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2)
+#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3)
+#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4)
+#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5)
+#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6)
+
+#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
+#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
+#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+
+#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
+
+/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
+ * rows, which changed the alignment requirements and fence programming.
+ */
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
+ IS_I915GM(dev)))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev))
+#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv)
+#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug)
+/* dsparb controlled by hw only */
+#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
+
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
+#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
+#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
+
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+
+#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
+#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
+#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
+
+#include "i915_trace.h"
+
extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock;
+extern unsigned int i915_panel_use_ssc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
@@ -907,8 +977,8 @@ extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
extern int i915_emit_box(struct drm_device *dev,
- struct drm_clip_rect *boxes,
- int i, int DR1, int DR4);
+ struct drm_clip_rect *box,
+ int DR1, int DR4);
extern int i915_reset(struct drm_device *dev, u8 flags);
extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
@@ -918,6 +988,7 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
/* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data);
+void i915_handle_error(struct drm_device *dev, bool wedged);
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -939,12 +1010,6 @@ extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
-extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask);
-extern void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv,
- u32 mask);
-extern void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv,
- u32 mask);
void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
@@ -953,6 +1018,13 @@ void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
void intel_enable_asle (struct drm_device *dev);
+int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags);
+
+int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+ int *vpos, int *hpos);
#ifdef CONFIG_DEBUG_FS
extern void i915_destroy_error_state(struct drm_device *dev);
@@ -1017,15 +1089,28 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void i915_gem_load(struct drm_device *dev);
int i915_gem_init_object(struct drm_gem_object *obj);
-struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
- size_t size);
+int __must_check i915_gem_flush_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains);
+struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
+ size_t size);
void i915_gem_free_object(struct drm_gem_object *obj);
-int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
-void i915_gem_object_unpin(struct drm_gem_object *obj);
-int i915_gem_object_unbind(struct drm_gem_object *obj);
-void i915_gem_release_mmap(struct drm_gem_object *obj);
+int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
+ uint32_t alignment,
+ bool map_and_fenceable);
+void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
+int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
+void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);
+int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
+int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
+ bool interruptible);
+void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring,
+ u32 seqno);
+
/**
* Returns true if seq1 is later than seq2.
*/
@@ -1035,71 +1120,88 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1 - seq2) >= 0;
}
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
- bool interruptible);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
- bool interruptible);
+static inline u32
+i915_gem_next_request_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return ring->outstanding_lazy_request = dev_priv->next_seqno;
+}
+
+int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined,
+ bool interruptible);
+int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
+
void i915_gem_retire_requests(struct drm_device *dev);
void i915_gem_reset(struct drm_device *dev);
-void i915_gem_clflush_object(struct drm_gem_object *obj);
-int i915_gem_object_set_domain(struct drm_gem_object *obj,
- uint32_t read_domains,
- uint32_t write_domain);
-int i915_gem_init_ringbuffer(struct drm_device *dev);
+void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
+int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
+ uint32_t read_domains,
+ uint32_t write_domain);
+int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+ bool interruptible);
+int __must_check i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
- unsigned long end);
-int i915_gpu_idle(struct drm_device *dev);
-int i915_gem_idle(struct drm_device *dev);
-uint32_t i915_add_request(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_i915_gem_request *request,
- struct intel_ring_buffer *ring);
-int i915_do_wait_request(struct drm_device *dev,
- uint32_t seqno,
- bool interruptible,
- struct intel_ring_buffer *ring);
+void i915_gem_do_init(struct drm_device *dev,
+ unsigned long start,
+ unsigned long mappable_end,
+ unsigned long end);
+int __must_check i915_gpu_idle(struct drm_device *dev);
+int __must_check i915_gem_idle(struct drm_device *dev);
+int __must_check i915_add_request(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_request *request,
+ struct intel_ring_buffer *ring);
+int __must_check i915_do_wait_request(struct drm_device *dev,
+ uint32_t seqno,
+ bool interruptible,
+ struct intel_ring_buffer *ring);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
-int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
- int write);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
- bool pipelined);
+int __must_check
+i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
+ bool write);
+int __must_check
+i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined);
int i915_gem_attach_phys_object(struct drm_device *dev,
- struct drm_gem_object *obj,
+ struct drm_i915_gem_object *obj,
int id,
int align);
void i915_gem_detach_phys_object(struct drm_device *dev,
- struct drm_gem_object *obj);
+ struct drm_i915_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
+void i915_gem_release(struct drm_device *dev, struct drm_file *file);
-void i915_gem_shrinker_init(void);
-void i915_gem_shrinker_exit(void);
+/* i915_gem_gtt.c */
+void i915_gem_restore_gtt_mappings(struct drm_device *dev);
+int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
+void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
/* i915_gem_evict.c */
-int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment);
-int i915_gem_evict_everything(struct drm_device *dev);
-int i915_gem_evict_inactive(struct drm_device *dev);
+int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size,
+ unsigned alignment, bool mappable);
+int __must_check i915_gem_evict_everything(struct drm_device *dev,
+ bool purgeable_only);
+int __must_check i915_gem_evict_inactive(struct drm_device *dev,
+ bool purgeable_only);
/* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
-void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
-void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
-bool i915_tiling_ok(struct drm_device *dev, int stride, int size,
- int tiling_mode);
-bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
- int tiling_mode);
+void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj);
+void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
/* i915_gem_debug.c */
-void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
const char *where, uint32_t mark);
#if WATCH_LISTS
int i915_verify_lists(struct drm_device *dev);
#else
#define i915_verify_lists(dev) 0
#endif
-void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
-void i915_gem_dump_object(struct drm_gem_object *obj, int len,
+void i915_gem_object_check_coherency(struct drm_i915_gem_object *obj,
+ int handle);
+void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
const char *where, uint32_t mark);
/* i915_debugfs.c */
@@ -1161,6 +1263,8 @@ extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
+extern void ironlake_enable_rc6(struct drm_device *dev);
+extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch (struct drm_device *dev);
extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
@@ -1168,79 +1272,120 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
#ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+
+extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev);
+extern void intel_display_print_error_state(struct seq_file *m,
+ struct drm_device *dev,
+ struct intel_display_error_state *error);
#endif
+#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
+
+#define BEGIN_LP_RING(n) \
+ intel_ring_begin(LP_RING(dev_priv), (n))
+
+#define OUT_RING(x) \
+ intel_ring_emit(LP_RING(dev_priv), x)
+
+#define ADVANCE_LP_RING() \
+ intel_ring_advance(LP_RING(dev_priv))
+
/**
* Lock test for when it's just for synchronization of ring access.
*
* In that case, we don't need to do it when GEM is initialized as nobody else
* has access to the ring.
*/
-#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \
- if (((drm_i915_private_t *)dev->dev_private)->render_ring.gem_object \
- == NULL) \
- LOCK_TEST_WITH_RETURN(dev, file_priv); \
+#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \
+ if (LP_RING(dev->dev_private)->obj == NULL) \
+ LOCK_TEST_WITH_RETURN(dev, file); \
} while (0)
-static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+
+#define __i915_read(x, y) \
+static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
+ u##x val = read##y(dev_priv->regs + reg); \
+ trace_i915_reg_rw('R', reg, val, sizeof(val)); \
+ return val; \
+}
+__i915_read(8, b)
+__i915_read(16, w)
+__i915_read(32, l)
+__i915_read(64, q)
+#undef __i915_read
+
+#define __i915_write(x, y) \
+static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+ trace_i915_reg_rw('W', reg, val, sizeof(val)); \
+ write##y(val, dev_priv->regs + reg); \
+}
+__i915_write(8, b)
+__i915_write(16, w)
+__i915_write(32, l)
+__i915_write(64, q)
+#undef __i915_write
+
+#define I915_READ8(reg) i915_read8(dev_priv, (reg))
+#define I915_WRITE8(reg, val) i915_write8(dev_priv, (reg), (val))
+
+#define I915_READ16(reg) i915_read16(dev_priv, (reg))
+#define I915_WRITE16(reg, val) i915_write16(dev_priv, (reg), (val))
+#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg))
+#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg))
+
+#define I915_READ(reg) i915_read32(dev_priv, (reg))
+#define I915_WRITE(reg, val) i915_write32(dev_priv, (reg), (val))
+#define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg))
+#define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg))
+
+#define I915_WRITE64(reg, val) i915_write64(dev_priv, (reg), (val))
+#define I915_READ64(reg) i915_read64(dev_priv, (reg))
+
+#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg)
+#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
+
+
+/* On SNB platform, before reading ring registers forcewake bit
+ * must be set to prevent GT core from power down and stale values being
+ * returned.
+ */
+void __gen6_force_wake_get(struct drm_i915_private *dev_priv);
+void __gen6_force_wake_put (struct drm_i915_private *dev_priv);
+static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val;
- val = readl(dev_priv->regs + reg);
- if (dev_priv->debug_flags & I915_DEBUG_READ)
- printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+ if (dev_priv->info->gen >= 6) {
+ __gen6_force_wake_get(dev_priv);
+ val = I915_READ(reg);
+ __gen6_force_wake_put(dev_priv);
+ } else
+ val = I915_READ(reg);
+
return val;
}
-static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
- u32 val)
+static inline void
+i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
{
- writel(val, dev_priv->regs + reg);
- if (dev_priv->debug_flags & I915_DEBUG_WRITE)
- printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+ /* Trace down the write operation before the real write */
+ trace_i915_reg_rw('W', reg, val, len);
+ switch (len) {
+ case 8:
+ writeq(val, dev_priv->regs + reg);
+ break;
+ case 4:
+ writel(val, dev_priv->regs + reg);
+ break;
+ case 2:
+ writew(val, dev_priv->regs + reg);
+ break;
+ case 1:
+ writeb(val, dev_priv->regs + reg);
+ break;
+ }
}
-#define I915_READ(reg) i915_read(dev_priv, (reg))
-#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val))
-#define I915_READ16(reg) readw(dev_priv->regs + (reg))
-#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
-#define I915_READ8(reg) readb(dev_priv->regs + (reg))
-#define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg))
-#define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg))
-#define I915_READ64(reg) readq(dev_priv->regs + (reg))
-#define POSTING_READ(reg) (void)I915_READ(reg)
-#define POSTING_READ16(reg) (void)I915_READ16(reg)
-
-#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
- I915_DEBUG_WRITE)
-#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
- I915_DEBUG_WRITE))
-
-#define I915_VERBOSE 0
-
-#define BEGIN_LP_RING(n) do { \
- drm_i915_private_t *dev_priv__ = dev->dev_private; \
- if (I915_VERBOSE) \
- DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \
- intel_ring_begin(dev, &dev_priv__->render_ring, (n)); \
-} while (0)
-
-
-#define OUT_RING(x) do { \
- drm_i915_private_t *dev_priv__ = dev->dev_private; \
- if (I915_VERBOSE) \
- DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \
- intel_ring_emit(dev, &dev_priv__->render_ring, x); \
-} while (0)
-
-#define ADVANCE_LP_RING() do { \
- drm_i915_private_t *dev_priv__ = dev->dev_private; \
- if (I915_VERBOSE) \
- DRM_DEBUG("ADVANCE_LP_RING %x\n", \
- dev_priv__->render_ring.tail); \
- intel_ring_advance(dev, &dev_priv__->render_ring); \
-} while(0)
-
/**
* Reads a dword out of the status page, which is written to from the command
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
@@ -1257,71 +1402,9 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
* The area from dword 0x20 to 0x3ff is available for driver usage.
*/
#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\
- (dev_priv->render_ring.status_page.page_addr))[reg])
+ (LP_RING(dev_priv)->status_page.page_addr))[reg])
#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
#define I915_GEM_HWS_INDEX 0x20
#define I915_BREADCRUMB_INDEX 0x21
-#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info)
-
-#define IS_I830(dev) ((dev)->pci_device == 0x3577)
-#define IS_845G(dev) ((dev)->pci_device == 0x2562)
-#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x)
-#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
-#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g)
-#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
-#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
-#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm)
-#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater)
-#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline)
-#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
-#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x)
-#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001)
-#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011)
-#define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview)
-#define IS_G33(dev) (INTEL_INFO(dev)->is_g33)
-#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
-#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
-#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
-
-#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2)
-#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3)
-#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4)
-#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5)
-#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6)
-
-#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
-#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
-#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
-
-#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
-#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
-
-/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
- * rows, which changed the alignment requirements and fence programming.
- */
-#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
- IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
-#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev))
-#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev))
-#define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv)
-#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug)
-/* dsparb controlled by hw only */
-#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
-
-#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
-#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
-#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
-#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
-
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-
-#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
-#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
-
-#define PRIMARY_RINGBUFFER_SIZE (128*1024)
-
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 8eb8453208b5..3dfc848ff755 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -34,39 +34,31 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/pci.h>
-#include <linux/intel-gtt.h>
-
-static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
- bool pipelined);
-static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
-static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
-static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
- int write);
-static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
- uint64_t offset,
- uint64_t size);
-static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
- bool interruptible);
-static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
- unsigned alignment);
-static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
-static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+
+static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
+static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
+static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
+static __must_check int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj,
+ bool write);
+static __must_check int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj,
+ uint64_t offset,
+ uint64_t size);
+static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj);
+static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
+ unsigned alignment,
+ bool map_and_fenceable);
+static void i915_gem_clear_fence_reg(struct drm_device *dev,
+ struct drm_i915_fence_reg *reg);
+static int i915_gem_phys_pwrite(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv);
-static void i915_gem_free_object_tail(struct drm_gem_object *obj);
+ struct drm_file *file);
+static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
-static int
-i915_gem_object_get_pages(struct drm_gem_object *obj,
- gfp_t gfpmask);
+static int i915_gem_inactive_shrink(struct shrinker *shrinker,
+ int nr_to_scan,
+ gfp_t gfp_mask);
-static void
-i915_gem_object_put_pages(struct drm_gem_object *obj);
-
-static LIST_HEAD(shrink_list);
-static DEFINE_SPINLOCK(shrink_list_lock);
/* some bookkeeping */
static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -83,34 +75,6 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
dev_priv->mm.object_memory -= size;
}
-static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
- size_t size)
-{
- dev_priv->mm.gtt_count++;
- dev_priv->mm.gtt_memory += size;
-}
-
-static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
- size_t size)
-{
- dev_priv->mm.gtt_count--;
- dev_priv->mm.gtt_memory -= size;
-}
-
-static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
- size_t size)
-{
- dev_priv->mm.pin_count++;
- dev_priv->mm.pin_memory += size;
-}
-
-static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
- size_t size)
-{
- dev_priv->mm.pin_count--;
- dev_priv->mm.pin_memory -= size;
-}
-
int
i915_gem_check_is_wedged(struct drm_device *dev)
{
@@ -141,7 +105,7 @@ i915_gem_check_is_wedged(struct drm_device *dev)
return -EIO;
}
-static int i915_mutex_lock_interruptible(struct drm_device *dev)
+int i915_mutex_lock_interruptible(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
@@ -164,75 +128,76 @@ static int i915_mutex_lock_interruptible(struct drm_device *dev)
}
static inline bool
-i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
+i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
{
- return obj_priv->gtt_space &&
- !obj_priv->active &&
- obj_priv->pin_count == 0;
+ return obj->gtt_space && !obj->active && obj->pin_count == 0;
}
-int i915_gem_do_init(struct drm_device *dev,
- unsigned long start,
- unsigned long end)
+void i915_gem_do_init(struct drm_device *dev,
+ unsigned long start,
+ unsigned long mappable_end,
+ unsigned long end)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- if (start >= end ||
- (start & (PAGE_SIZE - 1)) != 0 ||
- (end & (PAGE_SIZE - 1)) != 0) {
- return -EINVAL;
- }
-
drm_mm_init(&dev_priv->mm.gtt_space, start,
end - start);
dev_priv->mm.gtt_total = end - start;
-
- return 0;
+ dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
+ dev_priv->mm.gtt_mappable_end = mappable_end;
}
int
i915_gem_init_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_init *args = data;
- int ret;
+
+ if (args->gtt_start >= args->gtt_end ||
+ (args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1))
+ return -EINVAL;
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end);
+ i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end);
mutex_unlock(&dev->struct_mutex);
- return ret;
+ return 0;
}
int
i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_get_aperture *args = data;
+ struct drm_i915_gem_object *obj;
+ size_t pinned;
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
+ pinned = 0;
mutex_lock(&dev->struct_mutex);
- args->aper_size = dev_priv->mm.gtt_total;
- args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+ list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
+ pinned += obj->gtt_space->size;
mutex_unlock(&dev->struct_mutex);
+ args->aper_size = dev_priv->mm.gtt_total;
+ args->aper_available_size = args->aper_size -pinned;
+
return 0;
}
-
/**
* Creates a new mm object and returns a handle to it.
*/
int
i915_gem_create_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_create *args = data;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
int ret;
u32 handle;
@@ -243,45 +208,28 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
if (obj == NULL)
return -ENOMEM;
- ret = drm_gem_handle_create(file_priv, obj, &handle);
+ ret = drm_gem_handle_create(file, &obj->base, &handle);
if (ret) {
- drm_gem_object_release(obj);
- i915_gem_info_remove_obj(dev->dev_private, obj->size);
+ drm_gem_object_release(&obj->base);
+ i915_gem_info_remove_obj(dev->dev_private, obj->base.size);
kfree(obj);
return ret;
}
/* drop reference from allocate - handle holds it now */
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
trace_i915_gem_object_create(obj);
args->handle = handle;
return 0;
}
-static inline int
-fast_shmem_read(struct page **pages,
- loff_t page_base, int page_offset,
- char __user *data,
- int length)
-{
- char *vaddr;
- int ret;
-
- vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
- ret = __copy_to_user_inatomic(data, vaddr + page_offset, length);
- kunmap_atomic(vaddr);
-
- return ret;
-}
-
-static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
+static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
{
- drm_i915_private_t *dev_priv = obj->dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
- obj_priv->tiling_mode != I915_TILING_NONE;
+ obj->tiling_mode != I915_TILING_NONE;
}
static inline void
@@ -357,38 +305,51 @@ slow_shmem_bit17_copy(struct page *gpu_page,
* fault, it fails so we can fall back to i915_gem_shmem_pwrite_slow().
*/
static int
-i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_shmem_pread_fast(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pread *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
ssize_t remain;
- loff_t offset, page_base;
+ loff_t offset;
char __user *user_data;
int page_offset, page_length;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- obj_priv = to_intel_bo(obj);
offset = args->offset;
while (remain > 0) {
+ struct page *page;
+ char *vaddr;
+ int ret;
+
/* Operation in this page
*
- * page_base = page offset within aperture
* page_offset = offset within page
* page_length = bytes to copy for this page
*/
- page_base = (offset & ~(PAGE_SIZE-1));
page_offset = offset & (PAGE_SIZE-1);
page_length = remain;
if ((page_offset + remain) > PAGE_SIZE)
page_length = PAGE_SIZE - page_offset;
- if (fast_shmem_read(obj_priv->pages,
- page_base, page_offset,
- user_data, page_length))
+ page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ vaddr = kmap_atomic(page);
+ ret = __copy_to_user_inatomic(user_data,
+ vaddr + page_offset,
+ page_length);
+ kunmap_atomic(vaddr);
+
+ mark_page_accessed(page);
+ page_cache_release(page);
+ if (ret)
return -EFAULT;
remain -= page_length;
@@ -399,30 +360,6 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
return 0;
}
-static int
-i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj)
-{
- int ret;
-
- ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN);
-
- /* If we've insufficient memory to map in the pages, attempt
- * to make some space by throwing out some old buffers.
- */
- if (ret == -ENOMEM) {
- struct drm_device *dev = obj->dev;
-
- ret = i915_gem_evict_something(dev, obj->size,
- i915_gem_get_gtt_alignment(obj));
- if (ret)
- return ret;
-
- ret = i915_gem_object_get_pages(obj, 0);
- }
-
- return ret;
-}
-
/**
* This is the fallback shmem pread path, which allocates temporary storage
* in kernel space to copy_to_user into outside of the struct_mutex, so we
@@ -430,18 +367,19 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj)
* and not take page faults.
*/
static int
-i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_shmem_pread_slow(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pread *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
struct mm_struct *mm = current->mm;
struct page **user_pages;
ssize_t remain;
loff_t offset, pinned_pages, i;
loff_t first_data_page, last_data_page, num_pages;
- int shmem_page_index, shmem_page_offset;
- int data_page_index, data_page_offset;
+ int shmem_page_offset;
+ int data_page_index, data_page_offset;
int page_length;
int ret;
uint64_t data_ptr = args->data_ptr;
@@ -480,19 +418,18 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
- obj_priv = to_intel_bo(obj);
offset = args->offset;
while (remain > 0) {
+ struct page *page;
+
/* Operation in this page
*
- * shmem_page_index = page number within shmem file
* shmem_page_offset = offset within page in shmem file
* data_page_index = page number in get_user_pages return
* data_page_offset = offset with data_page_index page.
* page_length = bytes to copy for this page
*/
- shmem_page_index = offset / PAGE_SIZE;
shmem_page_offset = offset & ~PAGE_MASK;
data_page_index = data_ptr / PAGE_SIZE - first_data_page;
data_page_offset = data_ptr & ~PAGE_MASK;
@@ -503,8 +440,13 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
if ((data_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - data_page_offset;
+ page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
if (do_bit17_swizzling) {
- slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
+ slow_shmem_bit17_copy(page,
shmem_page_offset,
user_pages[data_page_index],
data_page_offset,
@@ -513,11 +455,14 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
} else {
slow_shmem_copy(user_pages[data_page_index],
data_page_offset,
- obj_priv->pages[shmem_page_index],
+ page,
shmem_page_offset,
page_length);
}
+ mark_page_accessed(page);
+ page_cache_release(page);
+
remain -= page_length;
data_ptr += page_length;
offset += page_length;
@@ -526,6 +471,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
out:
for (i = 0; i < pinned_pages; i++) {
SetPageDirty(user_pages[i]);
+ mark_page_accessed(user_pages[i]);
page_cache_release(user_pages[i]);
}
drm_free_large(user_pages);
@@ -540,67 +486,56 @@ out:
*/
int
i915_gem_pread_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_pread *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret = 0;
+ if (args->size == 0)
+ return 0;
+
+ if (!access_ok(VERIFY_WRITE,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size))
+ return -EFAULT;
+
+ ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret)
+ return -EFAULT;
+
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
/* Bounds check source. */
- if (args->offset > obj->size || args->size > obj->size - args->offset) {
+ if (args->offset > obj->base.size ||
+ args->size > obj->base.size - args->offset) {
ret = -EINVAL;
goto out;
}
- if (args->size == 0)
- goto out;
-
- if (!access_ok(VERIFY_WRITE,
- (char __user *)(uintptr_t)args->data_ptr,
- args->size)) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
- if (ret) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = i915_gem_object_get_pages_or_evict(obj);
- if (ret)
- goto out;
-
ret = i915_gem_object_set_cpu_read_domain_range(obj,
args->offset,
args->size);
if (ret)
- goto out_put;
+ goto out;
ret = -EFAULT;
if (!i915_gem_object_needs_bit17_swizzle(obj))
- ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
+ ret = i915_gem_shmem_pread_fast(dev, obj, args, file);
if (ret == -EFAULT)
- ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
+ ret = i915_gem_shmem_pread_slow(dev, obj, args, file);
-out_put:
- i915_gem_object_put_pages(obj);
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -650,32 +585,16 @@ slow_kernel_write(struct io_mapping *mapping,
io_mapping_unmap(dst_vaddr);
}
-static inline int
-fast_shmem_write(struct page **pages,
- loff_t page_base, int page_offset,
- char __user *data,
- int length)
-{
- char *vaddr;
- int ret;
-
- vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
- ret = __copy_from_user_inatomic(vaddr + page_offset, data, length);
- kunmap_atomic(vaddr);
-
- return ret;
-}
-
/**
* This is the fast pwrite path, where we copy the data directly from the
* user into the GTT, uncached.
*/
static int
-i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_gtt_pwrite_fast(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
drm_i915_private_t *dev_priv = dev->dev_private;
ssize_t remain;
loff_t offset, page_base;
@@ -685,8 +604,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- obj_priv = to_intel_bo(obj);
- offset = obj_priv->gtt_offset + args->offset;
+ offset = obj->gtt_offset + args->offset;
while (remain > 0) {
/* Operation in this page
@@ -726,11 +644,11 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
* than using i915_gem_gtt_pwrite_fast on a G45 (32-bit).
*/
static int
-i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_gtt_pwrite_slow(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
drm_i915_private_t *dev_priv = dev->dev_private;
ssize_t remain;
loff_t gtt_page_base, offset;
@@ -767,12 +685,15 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
goto out_unpin_pages;
}
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
if (ret)
goto out_unpin_pages;
- obj_priv = to_intel_bo(obj);
- offset = obj_priv->gtt_offset + args->offset;
+ ret = i915_gem_object_put_fence(obj);
+ if (ret)
+ goto out_unpin_pages;
+
+ offset = obj->gtt_offset + args->offset;
while (remain > 0) {
/* Operation in this page
@@ -818,39 +739,58 @@ out_unpin_pages:
* copy_from_user into the kmapped pages backing the object.
*/
static int
-i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_shmem_pwrite_fast(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
ssize_t remain;
- loff_t offset, page_base;
+ loff_t offset;
char __user *user_data;
int page_offset, page_length;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- obj_priv = to_intel_bo(obj);
offset = args->offset;
- obj_priv->dirty = 1;
+ obj->dirty = 1;
while (remain > 0) {
+ struct page *page;
+ char *vaddr;
+ int ret;
+
/* Operation in this page
*
- * page_base = page offset within aperture
* page_offset = offset within page
* page_length = bytes to copy for this page
*/
- page_base = (offset & ~(PAGE_SIZE-1));
page_offset = offset & (PAGE_SIZE-1);
page_length = remain;
if ((page_offset + remain) > PAGE_SIZE)
page_length = PAGE_SIZE - page_offset;
- if (fast_shmem_write(obj_priv->pages,
- page_base, page_offset,
- user_data, page_length))
+ page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ vaddr = kmap_atomic(page, KM_USER0);
+ ret = __copy_from_user_inatomic(vaddr + page_offset,
+ user_data,
+ page_length);
+ kunmap_atomic(vaddr, KM_USER0);
+
+ set_page_dirty(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+
+ /* If we get a fault while copying data, then (presumably) our
+ * source page isn't available. Return the error and we'll
+ * retry in the slow path.
+ */
+ if (ret)
return -EFAULT;
remain -= page_length;
@@ -869,17 +809,18 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
* struct_mutex is held.
*/
static int
-i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_shmem_pwrite_slow(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
struct mm_struct *mm = current->mm;
struct page **user_pages;
ssize_t remain;
loff_t offset, pinned_pages, i;
loff_t first_data_page, last_data_page, num_pages;
- int shmem_page_index, shmem_page_offset;
+ int shmem_page_offset;
int data_page_index, data_page_offset;
int page_length;
int ret;
@@ -917,20 +858,19 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
- obj_priv = to_intel_bo(obj);
offset = args->offset;
- obj_priv->dirty = 1;
+ obj->dirty = 1;
while (remain > 0) {
+ struct page *page;
+
/* Operation in this page
*
- * shmem_page_index = page number within shmem file
* shmem_page_offset = offset within page in shmem file
* data_page_index = page number in get_user_pages return
* data_page_offset = offset with data_page_index page.
* page_length = bytes to copy for this page
*/
- shmem_page_index = offset / PAGE_SIZE;
shmem_page_offset = offset & ~PAGE_MASK;
data_page_index = data_ptr / PAGE_SIZE - first_data_page;
data_page_offset = data_ptr & ~PAGE_MASK;
@@ -941,21 +881,32 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
if ((data_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - data_page_offset;
+ page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+
if (do_bit17_swizzling) {
- slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
+ slow_shmem_bit17_copy(page,
shmem_page_offset,
user_pages[data_page_index],
data_page_offset,
page_length,
0);
} else {
- slow_shmem_copy(obj_priv->pages[shmem_page_index],
+ slow_shmem_copy(page,
shmem_page_offset,
user_pages[data_page_index],
data_page_offset,
page_length);
}
+ set_page_dirty(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+
remain -= page_length;
data_ptr += page_length;
offset += page_length;
@@ -979,61 +930,58 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_i915_gem_pwrite *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
- int ret = 0;
+ struct drm_i915_gem_object *obj;
+ int ret;
+
+ if (args->size == 0)
+ return 0;
+
+ if (!access_ok(VERIFY_READ,
+ (char __user *)(uintptr_t)args->data_ptr,
+ args->size))
+ return -EFAULT;
+
+ ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret)
+ return -EFAULT;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
-
/* Bounds check destination. */
- if (args->offset > obj->size || args->size > obj->size - args->offset) {
+ if (args->offset > obj->base.size ||
+ args->size > obj->base.size - args->offset) {
ret = -EINVAL;
goto out;
}
- if (args->size == 0)
- goto out;
-
- if (!access_ok(VERIFY_READ,
- (char __user *)(uintptr_t)args->data_ptr,
- args->size)) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
- if (ret) {
- ret = -EFAULT;
- goto out;
- }
-
/* We can only do the GTT pwrite on untiled buffers, as otherwise
* it would end up going through the fenced access, and we'll get
* different detiling behavior between reading and writing.
* pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client.
*/
- if (obj_priv->phys_obj)
+ if (obj->phys_obj)
ret = i915_gem_phys_pwrite(dev, obj, args, file);
- else if (obj_priv->tiling_mode == I915_TILING_NONE &&
- obj_priv->gtt_space &&
- obj->write_domain != I915_GEM_DOMAIN_CPU) {
- ret = i915_gem_object_pin(obj, 0);
+ else if (obj->gtt_space &&
+ obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+ ret = i915_gem_object_pin(obj, 0, true);
if (ret)
goto out;
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret)
+ goto out_unpin;
+
+ ret = i915_gem_object_put_fence(obj);
if (ret)
goto out_unpin;
@@ -1044,26 +992,19 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
out_unpin:
i915_gem_object_unpin(obj);
} else {
- ret = i915_gem_object_get_pages_or_evict(obj);
- if (ret)
- goto out;
-
ret = i915_gem_object_set_to_cpu_domain(obj, 1);
if (ret)
- goto out_put;
+ goto out;
ret = -EFAULT;
if (!i915_gem_object_needs_bit17_swizzle(obj))
ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
if (ret == -EFAULT)
ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
-
-out_put:
- i915_gem_object_put_pages(obj);
}
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -1075,12 +1016,10 @@ unlock:
*/
int
i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_set_domain *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
uint32_t read_domains = args->read_domains;
uint32_t write_domain = args->write_domain;
int ret;
@@ -1105,28 +1044,15 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
-
- intel_mark_busy(dev, obj);
if (read_domains & I915_GEM_DOMAIN_GTT) {
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
- /* Update the LRU on the fence for the CPU access that's
- * about to occur.
- */
- if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
- struct drm_i915_fence_reg *reg =
- &dev_priv->fence_regs[obj_priv->fence_reg];
- list_move_tail(&reg->lru_list,
- &dev_priv->mm.fence_list);
- }
-
/* Silently promote "you're not bound, there was nothing to do"
* to success, since the client was just asking us to
* make sure everything was done.
@@ -1137,11 +1063,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
}
- /* Maintain LRU order of "inactive" objects */
- if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
-
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -1152,10 +1074,10 @@ unlock:
*/
int
i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_sw_finish *args = data;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
int ret = 0;
if (!(dev->driver->driver_features & DRIVER_GEM))
@@ -1165,17 +1087,17 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
/* Pinned buffers may be scanout, so flush the cache */
- if (to_intel_bo(obj)->pin_count)
+ if (obj->pin_count)
i915_gem_object_flush_cpu_write_domain(obj);
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -1190,8 +1112,9 @@ unlock:
*/
int
i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_mmap *args = data;
struct drm_gem_object *obj;
loff_t offset;
@@ -1200,10 +1123,15 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = drm_gem_object_lookup(dev, file, args->handle);
if (obj == NULL)
return -ENOENT;
+ if (obj->size > dev_priv->mm.gtt_mappable_end) {
+ drm_gem_object_unreference_unlocked(obj);
+ return -E2BIG;
+ }
+
offset = args->offset;
down_write(&current->mm->mmap_sem);
@@ -1238,10 +1166,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
*/
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- struct drm_gem_object *obj = vma->vm_private_data;
- struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data);
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
pgoff_t page_offset;
unsigned long pfn;
int ret = 0;
@@ -1253,27 +1180,35 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Now bind it into the GTT if needed */
mutex_lock(&dev->struct_mutex);
- if (!obj_priv->gtt_space) {
- ret = i915_gem_object_bind_to_gtt(obj, 0);
- if (ret)
- goto unlock;
- ret = i915_gem_object_set_to_gtt_domain(obj, write);
+ if (!obj->map_and_fenceable) {
+ ret = i915_gem_object_unbind(obj);
if (ret)
goto unlock;
}
-
- /* Need a new fence register? */
- if (obj_priv->tiling_mode != I915_TILING_NONE) {
- ret = i915_gem_object_get_fence_reg(obj, true);
+ if (!obj->gtt_space) {
+ ret = i915_gem_object_bind_to_gtt(obj, 0, true);
if (ret)
goto unlock;
}
- if (i915_gem_object_is_inactive(obj_priv))
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+ ret = i915_gem_object_set_to_gtt_domain(obj, write);
+ if (ret)
+ goto unlock;
+
+ if (obj->tiling_mode == I915_TILING_NONE)
+ ret = i915_gem_object_put_fence(obj);
+ else
+ ret = i915_gem_object_get_fence(obj, NULL, true);
+ if (ret)
+ goto unlock;
+
+ if (i915_gem_object_is_inactive(obj))
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
+ obj->fault_mappable = true;
- pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
+ pfn = ((dev->agp->base + obj->gtt_offset) >> PAGE_SHIFT) +
page_offset;
/* Finally, remap it using the new GTT offset */
@@ -1282,11 +1217,12 @@ unlock:
mutex_unlock(&dev->struct_mutex);
switch (ret) {
+ case -EAGAIN:
+ set_need_resched();
case 0:
case -ERESTARTSYS:
return VM_FAULT_NOPAGE;
case -ENOMEM:
- case -EAGAIN:
return VM_FAULT_OOM;
default:
return VM_FAULT_SIGBUS;
@@ -1305,37 +1241,39 @@ unlock:
* This routine allocates and attaches a fake offset for @obj.
*/
static int
-i915_gem_create_mmap_offset(struct drm_gem_object *obj)
+i915_gem_create_mmap_offset(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
struct drm_gem_mm *mm = dev->mm_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_map_list *list;
struct drm_local_map *map;
int ret = 0;
/* Set the object up for mmap'ing */
- list = &obj->map_list;
+ list = &obj->base.map_list;
list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
if (!list->map)
return -ENOMEM;
map = list->map;
map->type = _DRM_GEM;
- map->size = obj->size;
+ map->size = obj->base.size;
map->handle = obj;
/* Get a DRM GEM mmap offset allocated... */
list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
- obj->size / PAGE_SIZE, 0, 0);
+ obj->base.size / PAGE_SIZE,
+ 0, 0);
if (!list->file_offset_node) {
- DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
+ DRM_ERROR("failed to allocate offset for bo %d\n",
+ obj->base.name);
ret = -ENOSPC;
goto out_free_list;
}
list->file_offset_node = drm_mm_get_block(list->file_offset_node,
- obj->size / PAGE_SIZE, 0);
+ obj->base.size / PAGE_SIZE,
+ 0);
if (!list->file_offset_node) {
ret = -ENOMEM;
goto out_free_list;
@@ -1348,16 +1286,13 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
goto out_free_mm;
}
- /* By now we should be all set, any drm_mmap request on the offset
- * below will get to our mmap & fault handler */
- obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
-
return 0;
out_free_mm:
drm_mm_put_block(list->file_offset_node);
out_free_list:
kfree(list->map);
+ list->map = NULL;
return ret;
}
@@ -1377,38 +1312,51 @@ out_free_list:
* fixup by i915_gem_fault().
*/
void
-i915_gem_release_mmap(struct drm_gem_object *obj)
+i915_gem_release_mmap(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ if (!obj->fault_mappable)
+ return;
+
+ unmap_mapping_range(obj->base.dev->dev_mapping,
+ (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
+ obj->base.size, 1);
- if (dev->dev_mapping)
- unmap_mapping_range(dev->dev_mapping,
- obj_priv->mmap_offset, obj->size, 1);
+ obj->fault_mappable = false;
}
static void
-i915_gem_free_mmap_offset(struct drm_gem_object *obj)
+i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_device *dev = obj->base.dev;
struct drm_gem_mm *mm = dev->mm_private;
- struct drm_map_list *list;
+ struct drm_map_list *list = &obj->base.map_list;
- list = &obj->map_list;
drm_ht_remove_item(&mm->offset_hash, &list->hash);
+ drm_mm_put_block(list->file_offset_node);
+ kfree(list->map);
+ list->map = NULL;
+}
- if (list->file_offset_node) {
- drm_mm_put_block(list->file_offset_node);
- list->file_offset_node = NULL;
- }
+static uint32_t
+i915_gem_get_gtt_size(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *dev = obj->base.dev;
+ uint32_t size;
- if (list->map) {
- kfree(list->map);
- list->map = NULL;
- }
+ if (INTEL_INFO(dev)->gen >= 4 ||
+ obj->tiling_mode == I915_TILING_NONE)
+ return obj->base.size;
- obj_priv->mmap_offset = 0;
+ /* Previous chips need a power-of-two fence region when tiling */
+ if (INTEL_INFO(dev)->gen == 3)
+ size = 1024*1024;
+ else
+ size = 512*1024;
+
+ while (size < obj->base.size)
+ size <<= 1;
+
+ return size;
}
/**
@@ -1416,42 +1364,68 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj)
* @obj: object to check
*
* Return the required GTT alignment for an object, taking into account
- * potential fence register mapping if needed.
+ * potential fence register mapping.
*/
static uint32_t
-i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
+i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int start, i;
+ struct drm_device *dev = obj->base.dev;
/*
* Minimum alignment is 4k (GTT page size), but might be greater
* if a fence register is needed for the object.
*/
- if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
+ if (INTEL_INFO(dev)->gen >= 4 ||
+ obj->tiling_mode == I915_TILING_NONE)
return 4096;
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object.
*/
- if (INTEL_INFO(dev)->gen == 3)
- start = 1024*1024;
- else
- start = 512*1024;
+ return i915_gem_get_gtt_size(obj);
+}
+
+/**
+ * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an
+ * unfenced object
+ * @obj: object to check
+ *
+ * Return the required GTT alignment for an object, only taking into account
+ * unfenced tiled surface requirements.
+ */
+static uint32_t
+i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *dev = obj->base.dev;
+ int tile_height;
- for (i = start; i < obj->size; i <<= 1)
- ;
+ /*
+ * Minimum alignment is 4k (GTT page size) for sane hw.
+ */
+ if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) ||
+ obj->tiling_mode == I915_TILING_NONE)
+ return 4096;
- return i;
+ /*
+ * Older chips need unfenced tiled buffers to be aligned to the left
+ * edge of an even tile row (where tile rows are counted as if the bo is
+ * placed in a fenced gtt region).
+ */
+ if (IS_GEN2(dev) ||
+ (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
+ tile_height = 32;
+ else
+ tile_height = 8;
+
+ return tile_height * obj->stride * 2;
}
/**
* i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
* @dev: DRM device
* @data: GTT mapping ioctl data
- * @file_priv: GEM object info
+ * @file: GEM object info
*
* Simply returns the fake offset to userspace so it can mmap it.
* The mmap call will end up in drm_gem_mmap(), which will set things
@@ -1464,11 +1438,11 @@ i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
*/
int
i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_mmap_gtt *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
if (!(dev->driver->driver_features & DRIVER_GEM))
@@ -1478,130 +1452,196 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
- if (obj_priv->madv != I915_MADV_WILLNEED) {
+ if (obj->base.size > dev_priv->mm.gtt_mappable_end) {
+ ret = -E2BIG;
+ goto unlock;
+ }
+
+ if (obj->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to mmap a purgeable buffer\n");
ret = -EINVAL;
goto out;
}
- if (!obj_priv->mmap_offset) {
+ if (!obj->base.map_list.map) {
ret = i915_gem_create_mmap_offset(obj);
if (ret)
goto out;
}
- args->offset = obj_priv->mmap_offset;
-
- /*
- * Pull it into the GTT so that we have a page list (makes the
- * initial fault faster and any subsequent flushing possible).
- */
- if (!obj_priv->agp_mem) {
- ret = i915_gem_object_bind_to_gtt(obj, 0);
- if (ret)
- goto out;
- }
+ args->offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
+static int
+i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
+ gfp_t gfpmask)
+{
+ int page_count, i;
+ struct address_space *mapping;
+ struct inode *inode;
+ struct page *page;
+
+ /* Get the list of pages out of our struct file. They'll be pinned
+ * at this point until we release them.
+ */
+ page_count = obj->base.size / PAGE_SIZE;
+ BUG_ON(obj->pages != NULL);
+ obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
+ if (obj->pages == NULL)
+ return -ENOMEM;
+
+ inode = obj->base.filp->f_path.dentry->d_inode;
+ mapping = inode->i_mapping;
+ for (i = 0; i < page_count; i++) {
+ page = read_cache_page_gfp(mapping, i,
+ GFP_HIGHUSER |
+ __GFP_COLD |
+ __GFP_RECLAIMABLE |
+ gfpmask);
+ if (IS_ERR(page))
+ goto err_pages;
+
+ obj->pages[i] = page;
+ }
+
+ if (obj->tiling_mode != I915_TILING_NONE)
+ i915_gem_object_do_bit_17_swizzle(obj);
+
+ return 0;
+
+err_pages:
+ while (i--)
+ page_cache_release(obj->pages[i]);
+
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+ return PTR_ERR(page);
+}
+
static void
-i915_gem_object_put_pages(struct drm_gem_object *obj)
+i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int page_count = obj->size / PAGE_SIZE;
+ int page_count = obj->base.size / PAGE_SIZE;
int i;
- BUG_ON(obj_priv->pages_refcount == 0);
- BUG_ON(obj_priv->madv == __I915_MADV_PURGED);
+ BUG_ON(obj->madv == __I915_MADV_PURGED);
- if (--obj_priv->pages_refcount != 0)
- return;
-
- if (obj_priv->tiling_mode != I915_TILING_NONE)
+ if (obj->tiling_mode != I915_TILING_NONE)
i915_gem_object_save_bit_17_swizzle(obj);
- if (obj_priv->madv == I915_MADV_DONTNEED)
- obj_priv->dirty = 0;
+ if (obj->madv == I915_MADV_DONTNEED)
+ obj->dirty = 0;
for (i = 0; i < page_count; i++) {
- if (obj_priv->dirty)
- set_page_dirty(obj_priv->pages[i]);
+ if (obj->dirty)
+ set_page_dirty(obj->pages[i]);
- if (obj_priv->madv == I915_MADV_WILLNEED)
- mark_page_accessed(obj_priv->pages[i]);
+ if (obj->madv == I915_MADV_WILLNEED)
+ mark_page_accessed(obj->pages[i]);
- page_cache_release(obj_priv->pages[i]);
+ page_cache_release(obj->pages[i]);
}
- obj_priv->dirty = 0;
+ obj->dirty = 0;
- drm_free_large(obj_priv->pages);
- obj_priv->pages = NULL;
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
}
-static uint32_t
-i915_gem_next_request_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- ring->outstanding_lazy_request = true;
- return dev_priv->next_seqno;
-}
-
-static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj,
- struct intel_ring_buffer *ring)
+void
+i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring,
+ u32 seqno)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
BUG_ON(ring == NULL);
- obj_priv->ring = ring;
+ obj->ring = ring;
/* Add a reference if we're newly entering the active list. */
- if (!obj_priv->active) {
- drm_gem_object_reference(obj);
- obj_priv->active = 1;
+ if (!obj->active) {
+ drm_gem_object_reference(&obj->base);
+ obj->active = 1;
}
/* Move from whatever list we were on to the tail of execution. */
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.active_list);
- list_move_tail(&obj_priv->ring_list, &ring->active_list);
- obj_priv->last_rendering_seqno = seqno;
+ list_move_tail(&obj->mm_list, &dev_priv->mm.active_list);
+ list_move_tail(&obj->ring_list, &ring->active_list);
+
+ obj->last_rendering_seqno = seqno;
+ if (obj->fenced_gpu_access) {
+ struct drm_i915_fence_reg *reg;
+
+ BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE);
+
+ obj->last_fenced_seqno = seqno;
+ obj->last_fenced_ring = ring;
+
+ reg = &dev_priv->fence_regs[obj->fence_reg];
+ list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+ }
+}
+
+static void
+i915_gem_object_move_off_active(struct drm_i915_gem_object *obj)
+{
+ list_del_init(&obj->ring_list);
+ obj->last_rendering_seqno = 0;
}
static void
-i915_gem_object_move_to_flushing(struct drm_gem_object *obj)
+i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- BUG_ON(!obj_priv->active);
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.flushing_list);
- list_del_init(&obj_priv->ring_list);
- obj_priv->last_rendering_seqno = 0;
+ BUG_ON(!obj->active);
+ list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list);
+
+ i915_gem_object_move_off_active(obj);
+}
+
+static void
+i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (obj->pin_count != 0)
+ list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list);
+ else
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
+ BUG_ON(!list_empty(&obj->gpu_write_list));
+ BUG_ON(!obj->active);
+ obj->ring = NULL;
+
+ i915_gem_object_move_off_active(obj);
+ obj->fenced_gpu_access = false;
+
+ obj->active = 0;
+ obj->pending_gpu_write = false;
+ drm_gem_object_unreference(&obj->base);
+
+ WARN_ON(i915_verify_lists(dev));
}
/* Immediately discard the backing storage */
static void
-i915_gem_object_truncate(struct drm_gem_object *obj)
+i915_gem_object_truncate(struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct inode *inode;
/* Our goal here is to return as much of the memory as
@@ -1610,42 +1650,18 @@ i915_gem_object_truncate(struct drm_gem_object *obj)
* backing pages, *now*. Here we mirror the actions taken
* when by shmem_delete_inode() to release the backing store.
*/
- inode = obj->filp->f_path.dentry->d_inode;
+ inode = obj->base.filp->f_path.dentry->d_inode;
truncate_inode_pages(inode->i_mapping, 0);
if (inode->i_op->truncate_range)
inode->i_op->truncate_range(inode, 0, (loff_t)-1);
- obj_priv->madv = __I915_MADV_PURGED;
+ obj->madv = __I915_MADV_PURGED;
}
static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv)
+i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
{
- return obj_priv->madv == I915_MADV_DONTNEED;
-}
-
-static void
-i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
-{
- struct drm_device *dev = obj->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-
- if (obj_priv->pin_count != 0)
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list);
- else
- list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
- list_del_init(&obj_priv->ring_list);
-
- BUG_ON(!list_empty(&obj_priv->gpu_write_list));
-
- obj_priv->last_rendering_seqno = 0;
- obj_priv->ring = NULL;
- if (obj_priv->active) {
- obj_priv->active = 0;
- drm_gem_object_unreference(obj);
- }
- WARN_ON(i915_verify_lists(dev));
+ return obj->madv == I915_MADV_DONTNEED;
}
static void
@@ -1653,37 +1669,27 @@ i915_gem_process_flushing_list(struct drm_device *dev,
uint32_t flush_domains,
struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv, *next;
+ struct drm_i915_gem_object *obj, *next;
- list_for_each_entry_safe(obj_priv, next,
+ list_for_each_entry_safe(obj, next,
&ring->gpu_write_list,
gpu_write_list) {
- struct drm_gem_object *obj = &obj_priv->base;
+ if (obj->base.write_domain & flush_domains) {
+ uint32_t old_write_domain = obj->base.write_domain;
- if (obj->write_domain & flush_domains) {
- uint32_t old_write_domain = obj->write_domain;
-
- obj->write_domain = 0;
- list_del_init(&obj_priv->gpu_write_list);
- i915_gem_object_move_to_active(obj, ring);
-
- /* update the fence lru list */
- if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
- struct drm_i915_fence_reg *reg =
- &dev_priv->fence_regs[obj_priv->fence_reg];
- list_move_tail(&reg->lru_list,
- &dev_priv->mm.fence_list);
- }
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
+ i915_gem_object_move_to_active(obj, ring,
+ i915_gem_next_request_seqno(dev, ring));
trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
+ obj->base.read_domains,
old_write_domain);
}
}
}
-uint32_t
+int
i915_add_request(struct drm_device *dev,
struct drm_file *file,
struct drm_i915_gem_request *request,
@@ -1693,17 +1699,17 @@ i915_add_request(struct drm_device *dev,
struct drm_i915_file_private *file_priv = NULL;
uint32_t seqno;
int was_empty;
+ int ret;
+
+ BUG_ON(request == NULL);
if (file != NULL)
file_priv = file->driver_priv;
- if (request == NULL) {
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return 0;
- }
+ ret = ring->add_request(ring, &seqno);
+ if (ret)
+ return ret;
- seqno = ring->add_request(dev, ring, 0);
ring->outstanding_lazy_request = false;
request->seqno = seqno;
@@ -1727,26 +1733,7 @@ i915_add_request(struct drm_device *dev,
queue_delayed_work(dev_priv->wq,
&dev_priv->mm.retire_work, HZ);
}
- return seqno;
-}
-
-/**
- * Command execution barrier
- *
- * Ensures that all commands in the ring are finished
- * before signalling the CPU
- */
-static void
-i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
-{
- uint32_t flush_domains = 0;
-
- /* The sampler always gets flushed on i965 (sigh) */
- if (INTEL_INFO(dev)->gen >= 4)
- flush_domains |= I915_GEM_DOMAIN_SAMPLER;
-
- ring->flush(dev, ring,
- I915_GEM_DOMAIN_COMMAND, flush_domains);
+ return 0;
}
static inline void
@@ -1779,62 +1766,76 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
}
while (!list_empty(&ring->active_list)) {
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
- obj_priv = list_first_entry(&ring->active_list,
- struct drm_i915_gem_object,
- ring_list);
+ obj = list_first_entry(&ring->active_list,
+ struct drm_i915_gem_object,
+ ring_list);
- obj_priv->base.write_domain = 0;
- list_del_init(&obj_priv->gpu_write_list);
- i915_gem_object_move_to_inactive(&obj_priv->base);
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
+ i915_gem_object_move_to_inactive(obj);
+ }
+}
+
+static void i915_gem_reset_fences(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
+ struct drm_i915_gem_object *obj = reg->obj;
+
+ if (!obj)
+ continue;
+
+ if (obj->tiling_mode)
+ i915_gem_release_mmap(obj);
+
+ reg->obj->fence_reg = I915_FENCE_REG_NONE;
+ reg->obj->fenced_gpu_access = false;
+ reg->obj->last_fenced_seqno = 0;
+ reg->obj->last_fenced_ring = NULL;
+ i915_gem_clear_fence_reg(dev, reg);
}
}
void i915_gem_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int i;
- i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
- i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
- i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]);
/* Remove anything from the flushing lists. The GPU cache is likely
* to be lost on reset along with the data, so simply move the
* lost bo to the inactive list.
*/
while (!list_empty(&dev_priv->mm.flushing_list)) {
- obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
- struct drm_i915_gem_object,
- mm_list);
+ obj= list_first_entry(&dev_priv->mm.flushing_list,
+ struct drm_i915_gem_object,
+ mm_list);
- obj_priv->base.write_domain = 0;
- list_del_init(&obj_priv->gpu_write_list);
- i915_gem_object_move_to_inactive(&obj_priv->base);
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
+ i915_gem_object_move_to_inactive(obj);
}
/* Move everything out of the GPU domains to ensure we do any
* necessary invalidation upon reuse.
*/
- list_for_each_entry(obj_priv,
+ list_for_each_entry(obj,
&dev_priv->mm.inactive_list,
mm_list)
{
- obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+ obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
}
/* The fence registers are invalidated so clear them out */
- for (i = 0; i < 16; i++) {
- struct drm_i915_fence_reg *reg;
-
- reg = &dev_priv->fence_regs[i];
- if (!reg->obj)
- continue;
-
- i915_gem_clear_fence_reg(reg->obj);
- }
+ i915_gem_reset_fences(dev);
}
/**
@@ -1846,6 +1847,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
{
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
+ int i;
if (!ring->status_page.page_addr ||
list_empty(&ring->request_list))
@@ -1853,7 +1855,12 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
WARN_ON(i915_verify_lists(dev));
- seqno = ring->get_seqno(dev, ring);
+ seqno = ring->get_seqno(ring);
+
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ if (seqno >= ring->sync_seqno[i])
+ ring->sync_seqno[i] = 0;
+
while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
@@ -1875,18 +1882,16 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
* by the ringbuffer to the flushing/inactive lists as appropriate.
*/
while (!list_empty(&ring->active_list)) {
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
- obj_priv = list_first_entry(&ring->active_list,
- struct drm_i915_gem_object,
- ring_list);
+ obj= list_first_entry(&ring->active_list,
+ struct drm_i915_gem_object,
+ ring_list);
- if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
+ if (!i915_seqno_passed(seqno, obj->last_rendering_seqno))
break;
- obj = &obj_priv->base;
- if (obj->write_domain != 0)
+ if (obj->base.write_domain != 0)
i915_gem_object_move_to_flushing(obj);
else
i915_gem_object_move_to_inactive(obj);
@@ -1894,7 +1899,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
if (unlikely (dev_priv->trace_irq_seqno &&
i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
- ring->user_irq_put(dev, ring);
+ ring->irq_put(ring);
dev_priv->trace_irq_seqno = 0;
}
@@ -1905,24 +1910,24 @@ void
i915_gem_retire_requests(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
if (!list_empty(&dev_priv->mm.deferred_free_list)) {
- struct drm_i915_gem_object *obj_priv, *tmp;
+ struct drm_i915_gem_object *obj, *next;
/* We must be careful that during unbind() we do not
* accidentally infinitely recurse into retire requests.
* Currently:
* retire -> free -> unbind -> wait -> retire_ring
*/
- list_for_each_entry_safe(obj_priv, tmp,
+ list_for_each_entry_safe(obj, next,
&dev_priv->mm.deferred_free_list,
mm_list)
- i915_gem_free_object_tail(&obj_priv->base);
+ i915_gem_free_object_tail(obj);
}
- i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
- i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
- i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ i915_gem_retire_requests_ring(dev, &dev_priv->ring[i]);
}
static void
@@ -1930,6 +1935,8 @@ i915_gem_retire_work_handler(struct work_struct *work)
{
drm_i915_private_t *dev_priv;
struct drm_device *dev;
+ bool idle;
+ int i;
dev_priv = container_of(work, drm_i915_private_t,
mm.retire_work.work);
@@ -1943,11 +1950,31 @@ i915_gem_retire_work_handler(struct work_struct *work)
i915_gem_retire_requests(dev);
- if (!dev_priv->mm.suspended &&
- (!list_empty(&dev_priv->render_ring.request_list) ||
- !list_empty(&dev_priv->bsd_ring.request_list) ||
- !list_empty(&dev_priv->blt_ring.request_list)))
+ /* Send a periodic flush down the ring so we don't hold onto GEM
+ * objects indefinitely.
+ */
+ idle = true;
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ struct intel_ring_buffer *ring = &dev_priv->ring[i];
+
+ if (!list_empty(&ring->gpu_write_list)) {
+ struct drm_i915_gem_request *request;
+ int ret;
+
+ ret = i915_gem_flush_ring(dev, ring, 0,
+ I915_GEM_GPU_DOMAINS);
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (ret || request == NULL ||
+ i915_add_request(dev, NULL, request, ring))
+ kfree(request);
+ }
+
+ idle &= list_empty(&ring->request_list);
+ }
+
+ if (!dev_priv->mm.suspended && !idle)
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+
mutex_unlock(&dev->struct_mutex);
}
@@ -1964,14 +1991,23 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
if (atomic_read(&dev_priv->mm.wedged))
return -EAGAIN;
- if (ring->outstanding_lazy_request) {
- seqno = i915_add_request(dev, NULL, NULL, ring);
- if (seqno == 0)
+ if (seqno == ring->outstanding_lazy_request) {
+ struct drm_i915_gem_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
return -ENOMEM;
+
+ ret = i915_add_request(dev, NULL, request, ring);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+
+ seqno = request->seqno;
}
- BUG_ON(seqno == dev_priv->next_seqno);
- if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+ if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
if (HAS_PCH_SPLIT(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER);
else
@@ -1985,21 +2021,23 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
trace_i915_gem_request_wait_begin(dev, seqno);
- ring->waiting_gem_seqno = seqno;
- ring->user_irq_get(dev, ring);
- if (interruptible)
- ret = wait_event_interruptible(ring->irq_queue,
- i915_seqno_passed(
- ring->get_seqno(dev, ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
- else
- wait_event(ring->irq_queue,
- i915_seqno_passed(
- ring->get_seqno(dev, ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
+ ring->waiting_seqno = seqno;
+ if (ring->irq_get(ring)) {
+ if (interruptible)
+ ret = wait_event_interruptible(ring->irq_queue,
+ i915_seqno_passed(ring->get_seqno(ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
+ else
+ wait_event(ring->irq_queue,
+ i915_seqno_passed(ring->get_seqno(ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
- ring->user_irq_put(dev, ring);
- ring->waiting_gem_seqno = 0;
+ ring->irq_put(ring);
+ } else if (wait_for(i915_seqno_passed(ring->get_seqno(ring),
+ seqno) ||
+ atomic_read(&dev_priv->mm.wedged), 3000))
+ ret = -EBUSY;
+ ring->waiting_seqno = 0;
trace_i915_gem_request_wait_end(dev, seqno);
}
@@ -2008,7 +2046,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
if (ret && ret != -ERESTARTSYS)
DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
- __func__, ret, seqno, ring->get_seqno(dev, ring),
+ __func__, ret, seqno, ring->get_seqno(ring),
dev_priv->next_seqno);
/* Directly dispatch request retiring. While we have the work queue
@@ -2033,70 +2071,30 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno,
return i915_do_wait_request(dev, seqno, 1, ring);
}
-static void
-i915_gem_flush_ring(struct drm_device *dev,
- struct drm_file *file_priv,
- struct intel_ring_buffer *ring,
- uint32_t invalidate_domains,
- uint32_t flush_domains)
-{
- ring->flush(dev, ring, invalidate_domains, flush_domains);
- i915_gem_process_flushing_list(dev, flush_domains, ring);
-}
-
-static void
-i915_gem_flush(struct drm_device *dev,
- struct drm_file *file_priv,
- uint32_t invalidate_domains,
- uint32_t flush_domains,
- uint32_t flush_rings)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- if (flush_domains & I915_GEM_DOMAIN_CPU)
- drm_agp_chipset_flush(dev);
-
- if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
- if (flush_rings & RING_RENDER)
- i915_gem_flush_ring(dev, file_priv,
- &dev_priv->render_ring,
- invalidate_domains, flush_domains);
- if (flush_rings & RING_BSD)
- i915_gem_flush_ring(dev, file_priv,
- &dev_priv->bsd_ring,
- invalidate_domains, flush_domains);
- if (flush_rings & RING_BLT)
- i915_gem_flush_ring(dev, file_priv,
- &dev_priv->blt_ring,
- invalidate_domains, flush_domains);
- }
-}
-
/**
* Ensures that all rendering to the object has completed and the object is
* safe to unbind from the GTT or access from the CPU.
*/
-static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+int
+i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
bool interruptible)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_device *dev = obj->base.dev;
int ret;
/* This function only exists to support waiting for existing rendering,
* not for emitting required flushes.
*/
- BUG_ON((obj->write_domain & I915_GEM_GPU_DOMAINS) != 0);
+ BUG_ON((obj->base.write_domain & I915_GEM_GPU_DOMAINS) != 0);
/* If there is rendering queued on the buffer being evicted, wait for
* it.
*/
- if (obj_priv->active) {
+ if (obj->active) {
ret = i915_do_wait_request(dev,
- obj_priv->last_rendering_seqno,
+ obj->last_rendering_seqno,
interruptible,
- obj_priv->ring);
+ obj->ring);
if (ret)
return ret;
}
@@ -2108,17 +2106,14 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj,
* Unbinds an object from the GTT aperture.
*/
int
-i915_gem_object_unbind(struct drm_gem_object *obj)
+i915_gem_object_unbind(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret = 0;
- if (obj_priv->gtt_space == NULL)
+ if (obj->gtt_space == NULL)
return 0;
- if (obj_priv->pin_count != 0) {
+ if (obj->pin_count != 0) {
DRM_ERROR("Attempting to unbind pinned buffer\n");
return -EINVAL;
}
@@ -2141,27 +2136,27 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
*/
if (ret) {
i915_gem_clflush_object(obj);
- obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+ obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
}
/* release the fence reg _after_ flushing */
- if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
- i915_gem_clear_fence_reg(obj);
-
- drm_unbind_agp(obj_priv->agp_mem);
- drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
+ ret = i915_gem_object_put_fence(obj);
+ if (ret == -ERESTARTSYS)
+ return ret;
- i915_gem_object_put_pages(obj);
- BUG_ON(obj_priv->pages_refcount);
+ i915_gem_gtt_unbind_object(obj);
+ i915_gem_object_put_pages_gtt(obj);
- i915_gem_info_remove_gtt(dev_priv, obj->size);
- list_del_init(&obj_priv->mm_list);
+ list_del_init(&obj->gtt_list);
+ list_del_init(&obj->mm_list);
+ /* Avoid an unnecessary call to unbind on rebind. */
+ obj->map_and_fenceable = true;
- drm_mm_put_block(obj_priv->gtt_space);
- obj_priv->gtt_space = NULL;
- obj_priv->gtt_offset = 0;
+ drm_mm_put_block(obj->gtt_space);
+ obj->gtt_space = NULL;
+ obj->gtt_offset = 0;
- if (i915_gem_object_is_purgeable(obj_priv))
+ if (i915_gem_object_is_purgeable(obj))
i915_gem_object_truncate(obj);
trace_i915_gem_object_unbind(obj);
@@ -2169,14 +2164,37 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
return ret;
}
+int
+i915_gem_flush_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains)
+{
+ int ret;
+
+ ret = ring->flush(ring, invalidate_domains, flush_domains);
+ if (ret)
+ return ret;
+
+ i915_gem_process_flushing_list(dev, flush_domains, ring);
+ return 0;
+}
+
static int i915_ring_idle(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
- if (list_empty(&ring->gpu_write_list))
+ int ret;
+
+ if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
return 0;
- i915_gem_flush_ring(dev, NULL, ring,
- I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+ if (!list_empty(&ring->gpu_write_list)) {
+ ret = i915_gem_flush_ring(dev, ring,
+ I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+ if (ret)
+ return ret;
+ }
+
return i915_wait_request(dev,
i915_gem_next_request_seqno(dev, ring),
ring);
@@ -2187,268 +2205,313 @@ i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
bool lists_empty;
- int ret;
+ int ret, i;
lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list) &&
- list_empty(&dev_priv->bsd_ring.active_list) &&
- list_empty(&dev_priv->blt_ring.active_list));
+ list_empty(&dev_priv->mm.active_list));
if (lists_empty)
return 0;
/* Flush everything onto the inactive list. */
- ret = i915_ring_idle(dev, &dev_priv->render_ring);
- if (ret)
- return ret;
-
- ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
- if (ret)
- return ret;
-
- ret = i915_ring_idle(dev, &dev_priv->blt_ring);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int
-i915_gem_object_get_pages(struct drm_gem_object *obj,
- gfp_t gfpmask)
-{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int page_count, i;
- struct address_space *mapping;
- struct inode *inode;
- struct page *page;
-
- BUG_ON(obj_priv->pages_refcount
- == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT);
-
- if (obj_priv->pages_refcount++ != 0)
- return 0;
-
- /* Get the list of pages out of our struct file. They'll be pinned
- * at this point until we release them.
- */
- page_count = obj->size / PAGE_SIZE;
- BUG_ON(obj_priv->pages != NULL);
- obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *));
- if (obj_priv->pages == NULL) {
- obj_priv->pages_refcount--;
- return -ENOMEM;
- }
-
- inode = obj->filp->f_path.dentry->d_inode;
- mapping = inode->i_mapping;
- for (i = 0; i < page_count; i++) {
- page = read_cache_page_gfp(mapping, i,
- GFP_HIGHUSER |
- __GFP_COLD |
- __GFP_RECLAIMABLE |
- gfpmask);
- if (IS_ERR(page))
- goto err_pages;
-
- obj_priv->pages[i] = page;
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ ret = i915_ring_idle(dev, &dev_priv->ring[i]);
+ if (ret)
+ return ret;
}
- if (obj_priv->tiling_mode != I915_TILING_NONE)
- i915_gem_object_do_bit_17_swizzle(obj);
-
return 0;
-
-err_pages:
- while (i--)
- page_cache_release(obj_priv->pages[i]);
-
- drm_free_large(obj_priv->pages);
- obj_priv->pages = NULL;
- obj_priv->pages_refcount--;
- return PTR_ERR(page);
}
-static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)
+static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_gem_object *obj = reg->obj;
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int regnum = obj_priv->fence_reg;
+ u32 size = obj->gtt_space->size;
+ int regnum = obj->fence_reg;
uint64_t val;
- val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
- 0xfffff000) << 32;
- val |= obj_priv->gtt_offset & 0xfffff000;
- val |= (uint64_t)((obj_priv->stride / 128) - 1) <<
+ val = (uint64_t)((obj->gtt_offset + size - 4096) &
+ 0xfffff000) << 32;
+ val |= obj->gtt_offset & 0xfffff000;
+ val |= (uint64_t)((obj->stride / 128) - 1) <<
SANDYBRIDGE_FENCE_PITCH_SHIFT;
- if (obj_priv->tiling_mode == I915_TILING_Y)
+ if (obj->tiling_mode == I915_TILING_Y)
val |= 1 << I965_FENCE_TILING_Y_SHIFT;
val |= I965_FENCE_REG_VALID;
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val);
+ if (pipelined) {
+ int ret = intel_ring_begin(pipelined, 6);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(pipelined, MI_NOOP);
+ intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2));
+ intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8);
+ intel_ring_emit(pipelined, (u32)val);
+ intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8 + 4);
+ intel_ring_emit(pipelined, (u32)(val >> 32));
+ intel_ring_advance(pipelined);
+ } else
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val);
+
+ return 0;
}
-static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
+static int i965_write_fence_reg(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_gem_object *obj = reg->obj;
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int regnum = obj_priv->fence_reg;
+ u32 size = obj->gtt_space->size;
+ int regnum = obj->fence_reg;
uint64_t val;
- val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+ val = (uint64_t)((obj->gtt_offset + size - 4096) &
0xfffff000) << 32;
- val |= obj_priv->gtt_offset & 0xfffff000;
- val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
- if (obj_priv->tiling_mode == I915_TILING_Y)
+ val |= obj->gtt_offset & 0xfffff000;
+ val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
+ if (obj->tiling_mode == I915_TILING_Y)
val |= 1 << I965_FENCE_TILING_Y_SHIFT;
val |= I965_FENCE_REG_VALID;
- I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val);
+ if (pipelined) {
+ int ret = intel_ring_begin(pipelined, 6);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(pipelined, MI_NOOP);
+ intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2));
+ intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8);
+ intel_ring_emit(pipelined, (u32)val);
+ intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8 + 4);
+ intel_ring_emit(pipelined, (u32)(val >> 32));
+ intel_ring_advance(pipelined);
+ } else
+ I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val);
+
+ return 0;
}
-static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
+static int i915_write_fence_reg(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_gem_object *obj = reg->obj;
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int regnum = obj_priv->fence_reg;
+ u32 size = obj->gtt_space->size;
+ u32 fence_reg, val, pitch_val;
int tile_width;
- uint32_t fence_reg, val;
- uint32_t pitch_val;
- if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
- (obj_priv->gtt_offset & (obj->size - 1))) {
- WARN(1, "%s: object 0x%08x not 1M or size (0x%zx) aligned\n",
- __func__, obj_priv->gtt_offset, obj->size);
- return;
- }
+ if (WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) ||
+ (size & -size) != size ||
+ (obj->gtt_offset & (size - 1)),
+ "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
+ obj->gtt_offset, obj->map_and_fenceable, size))
+ return -EINVAL;
- if (obj_priv->tiling_mode == I915_TILING_Y &&
- HAS_128_BYTE_Y_TILING(dev))
+ if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
tile_width = 128;
else
tile_width = 512;
/* Note: pitch better be a power of two tile widths */
- pitch_val = obj_priv->stride / tile_width;
+ pitch_val = obj->stride / tile_width;
pitch_val = ffs(pitch_val) - 1;
- if (obj_priv->tiling_mode == I915_TILING_Y &&
- HAS_128_BYTE_Y_TILING(dev))
- WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL);
- else
- WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL);
-
- val = obj_priv->gtt_offset;
- if (obj_priv->tiling_mode == I915_TILING_Y)
+ val = obj->gtt_offset;
+ if (obj->tiling_mode == I915_TILING_Y)
val |= 1 << I830_FENCE_TILING_Y_SHIFT;
- val |= I915_FENCE_SIZE_BITS(obj->size);
+ val |= I915_FENCE_SIZE_BITS(size);
val |= pitch_val << I830_FENCE_PITCH_SHIFT;
val |= I830_FENCE_REG_VALID;
- if (regnum < 8)
- fence_reg = FENCE_REG_830_0 + (regnum * 4);
+ fence_reg = obj->fence_reg;
+ if (fence_reg < 8)
+ fence_reg = FENCE_REG_830_0 + fence_reg * 4;
else
- fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4);
- I915_WRITE(fence_reg, val);
+ fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;
+
+ if (pipelined) {
+ int ret = intel_ring_begin(pipelined, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(pipelined, MI_NOOP);
+ intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(pipelined, fence_reg);
+ intel_ring_emit(pipelined, val);
+ intel_ring_advance(pipelined);
+ } else
+ I915_WRITE(fence_reg, val);
+
+ return 0;
}
-static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
+static int i830_write_fence_reg(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_gem_object *obj = reg->obj;
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int regnum = obj_priv->fence_reg;
+ u32 size = obj->gtt_space->size;
+ int regnum = obj->fence_reg;
uint32_t val;
uint32_t pitch_val;
- uint32_t fence_size_bits;
- if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) ||
- (obj_priv->gtt_offset & (obj->size - 1))) {
- WARN(1, "%s: object 0x%08x not 512K or size aligned\n",
- __func__, obj_priv->gtt_offset);
- return;
- }
+ if (WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) ||
+ (size & -size) != size ||
+ (obj->gtt_offset & (size - 1)),
+ "object 0x%08x not 512K or pot-size 0x%08x aligned\n",
+ obj->gtt_offset, size))
+ return -EINVAL;
- pitch_val = obj_priv->stride / 128;
+ pitch_val = obj->stride / 128;
pitch_val = ffs(pitch_val) - 1;
- WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL);
- val = obj_priv->gtt_offset;
- if (obj_priv->tiling_mode == I915_TILING_Y)
+ val = obj->gtt_offset;
+ if (obj->tiling_mode == I915_TILING_Y)
val |= 1 << I830_FENCE_TILING_Y_SHIFT;
- fence_size_bits = I830_FENCE_SIZE_BITS(obj->size);
- WARN_ON(fence_size_bits & ~0x00000f00);
- val |= fence_size_bits;
+ val |= I830_FENCE_SIZE_BITS(size);
val |= pitch_val << I830_FENCE_PITCH_SHIFT;
val |= I830_FENCE_REG_VALID;
- I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
+ if (pipelined) {
+ int ret = intel_ring_begin(pipelined, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(pipelined, MI_NOOP);
+ intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(pipelined, FENCE_REG_830_0 + regnum*4);
+ intel_ring_emit(pipelined, val);
+ intel_ring_advance(pipelined);
+ } else
+ I915_WRITE(FENCE_REG_830_0 + regnum * 4, val);
+
+ return 0;
}
-static int i915_find_fence_reg(struct drm_device *dev,
- bool interruptible)
+static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno)
+{
+ return i915_seqno_passed(ring->get_seqno(ring), seqno);
+}
+
+static int
+i915_gem_object_flush_fence(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined,
+ bool interruptible)
+{
+ int ret;
+
+ if (obj->fenced_gpu_access) {
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(obj->base.dev,
+ obj->last_fenced_ring,
+ 0, obj->base.write_domain);
+ if (ret)
+ return ret;
+ }
+
+ obj->fenced_gpu_access = false;
+ }
+
+ if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) {
+ if (!ring_passed_seqno(obj->last_fenced_ring,
+ obj->last_fenced_seqno)) {
+ ret = i915_do_wait_request(obj->base.dev,
+ obj->last_fenced_seqno,
+ interruptible,
+ obj->last_fenced_ring);
+ if (ret)
+ return ret;
+ }
+
+ obj->last_fenced_seqno = 0;
+ obj->last_fenced_ring = NULL;
+ }
+
+ /* Ensure that all CPU reads are completed before installing a fence
+ * and all writes before removing the fence.
+ */
+ if (obj->base.read_domains & I915_GEM_DOMAIN_GTT)
+ mb();
+
+ return 0;
+}
+
+int
+i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
+{
+ int ret;
+
+ if (obj->tiling_mode)
+ i915_gem_release_mmap(obj);
+
+ ret = i915_gem_object_flush_fence(obj, NULL, true);
+ if (ret)
+ return ret;
+
+ if (obj->fence_reg != I915_FENCE_REG_NONE) {
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ i915_gem_clear_fence_reg(obj->base.dev,
+ &dev_priv->fence_regs[obj->fence_reg]);
+
+ obj->fence_reg = I915_FENCE_REG_NONE;
+ }
+
+ return 0;
+}
+
+static struct drm_i915_fence_reg *
+i915_find_fence_reg(struct drm_device *dev,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_i915_fence_reg *reg = NULL;
- struct drm_i915_gem_object *obj_priv = NULL;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_gem_object *obj = NULL;
- int i, avail, ret;
+ struct drm_i915_fence_reg *reg, *first, *avail;
+ int i;
/* First try to find a free reg */
- avail = 0;
+ avail = NULL;
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
reg = &dev_priv->fence_regs[i];
if (!reg->obj)
- return i;
+ return reg;
- obj_priv = to_intel_bo(reg->obj);
- if (!obj_priv->pin_count)
- avail++;
+ if (!reg->obj->pin_count)
+ avail = reg;
}
- if (avail == 0)
- return -ENOSPC;
+ if (avail == NULL)
+ return NULL;
/* None available, try to steal one or wait for a user to finish */
- i = I915_FENCE_REG_NONE;
- list_for_each_entry(reg, &dev_priv->mm.fence_list,
- lru_list) {
- obj = reg->obj;
- obj_priv = to_intel_bo(obj);
-
- if (obj_priv->pin_count)
+ avail = first = NULL;
+ list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
+ if (reg->obj->pin_count)
continue;
- /* found one! */
- i = obj_priv->fence_reg;
- break;
- }
+ if (first == NULL)
+ first = reg;
- BUG_ON(i == I915_FENCE_REG_NONE);
+ if (!pipelined ||
+ !reg->obj->last_fenced_ring ||
+ reg->obj->last_fenced_ring == pipelined) {
+ avail = reg;
+ break;
+ }
+ }
- /* We only have a reference on obj from the active list. put_fence_reg
- * might drop that one, causing a use-after-free in it. So hold a
- * private reference to obj like the other callers of put_fence_reg
- * (set_tiling ioctl) do. */
- drm_gem_object_reference(obj);
- ret = i915_gem_object_put_fence_reg(obj, interruptible);
- drm_gem_object_unreference(obj);
- if (ret != 0)
- return ret;
+ if (avail == NULL)
+ avail = first;
- return i;
+ return avail;
}
/**
- * i915_gem_object_get_fence_reg - set up a fence reg for an object
+ * i915_gem_object_get_fence - set up a fence reg for an object
* @obj: object to map through a fence reg
+ * @pipelined: ring on which to queue the change, or NULL for CPU access
+ * @interruptible: must we wait uninterruptibly for the register to retire?
*
* When mapping objects through the GTT, userspace wants to be able to write
* to them without having to worry about swizzling if the object is tiled.
@@ -2460,72 +2523,141 @@ static int i915_find_fence_reg(struct drm_device *dev,
* and tiling format.
*/
int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
- bool interruptible)
+i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined,
+ bool interruptible)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- struct drm_i915_fence_reg *reg = NULL;
+ struct drm_i915_fence_reg *reg;
int ret;
- /* Just update our place in the LRU if our fence is getting used. */
- if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
- reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+ /* XXX disable pipelining. There are bugs. Shocking. */
+ pipelined = NULL;
+
+ /* Just update our place in the LRU if our fence is getting reused. */
+ if (obj->fence_reg != I915_FENCE_REG_NONE) {
+ reg = &dev_priv->fence_regs[obj->fence_reg];
list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+
+ if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
+ pipelined = NULL;
+
+ if (!pipelined) {
+ if (reg->setup_seqno) {
+ if (!ring_passed_seqno(obj->last_fenced_ring,
+ reg->setup_seqno)) {
+ ret = i915_do_wait_request(obj->base.dev,
+ reg->setup_seqno,
+ interruptible,
+ obj->last_fenced_ring);
+ if (ret)
+ return ret;
+ }
+
+ reg->setup_seqno = 0;
+ }
+ } else if (obj->last_fenced_ring &&
+ obj->last_fenced_ring != pipelined) {
+ ret = i915_gem_object_flush_fence(obj,
+ pipelined,
+ interruptible);
+ if (ret)
+ return ret;
+ } else if (obj->tiling_changed) {
+ if (obj->fenced_gpu_access) {
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(obj->base.dev, obj->ring,
+ 0, obj->base.write_domain);
+ if (ret)
+ return ret;
+ }
+
+ obj->fenced_gpu_access = false;
+ }
+ }
+
+ if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
+ pipelined = NULL;
+ BUG_ON(!pipelined && reg->setup_seqno);
+
+ if (obj->tiling_changed) {
+ if (pipelined) {
+ reg->setup_seqno =
+ i915_gem_next_request_seqno(dev, pipelined);
+ obj->last_fenced_seqno = reg->setup_seqno;
+ obj->last_fenced_ring = pipelined;
+ }
+ goto update;
+ }
+
return 0;
}
- switch (obj_priv->tiling_mode) {
- case I915_TILING_NONE:
- WARN(1, "allocating a fence for non-tiled object?\n");
- break;
- case I915_TILING_X:
- if (!obj_priv->stride)
- return -EINVAL;
- WARN((obj_priv->stride & (512 - 1)),
- "object 0x%08x is X tiled but has non-512B pitch\n",
- obj_priv->gtt_offset);
- break;
- case I915_TILING_Y:
- if (!obj_priv->stride)
- return -EINVAL;
- WARN((obj_priv->stride & (128 - 1)),
- "object 0x%08x is Y tiled but has non-128B pitch\n",
- obj_priv->gtt_offset);
- break;
- }
+ reg = i915_find_fence_reg(dev, pipelined);
+ if (reg == NULL)
+ return -ENOSPC;
- ret = i915_find_fence_reg(dev, interruptible);
- if (ret < 0)
+ ret = i915_gem_object_flush_fence(obj, pipelined, interruptible);
+ if (ret)
return ret;
- obj_priv->fence_reg = ret;
- reg = &dev_priv->fence_regs[obj_priv->fence_reg];
- list_add_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+ if (reg->obj) {
+ struct drm_i915_gem_object *old = reg->obj;
+
+ drm_gem_object_reference(&old->base);
+
+ if (old->tiling_mode)
+ i915_gem_release_mmap(old);
+
+ ret = i915_gem_object_flush_fence(old,
+ pipelined,
+ interruptible);
+ if (ret) {
+ drm_gem_object_unreference(&old->base);
+ return ret;
+ }
+
+ if (old->last_fenced_seqno == 0 && obj->last_fenced_seqno == 0)
+ pipelined = NULL;
+
+ old->fence_reg = I915_FENCE_REG_NONE;
+ old->last_fenced_ring = pipelined;
+ old->last_fenced_seqno =
+ pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0;
+
+ drm_gem_object_unreference(&old->base);
+ } else if (obj->last_fenced_seqno == 0)
+ pipelined = NULL;
reg->obj = obj;
+ list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+ obj->fence_reg = reg - dev_priv->fence_regs;
+ obj->last_fenced_ring = pipelined;
+
+ reg->setup_seqno =
+ pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0;
+ obj->last_fenced_seqno = reg->setup_seqno;
+update:
+ obj->tiling_changed = false;
switch (INTEL_INFO(dev)->gen) {
case 6:
- sandybridge_write_fence_reg(reg);
+ ret = sandybridge_write_fence_reg(obj, pipelined);
break;
case 5:
case 4:
- i965_write_fence_reg(reg);
+ ret = i965_write_fence_reg(obj, pipelined);
break;
case 3:
- i915_write_fence_reg(reg);
+ ret = i915_write_fence_reg(obj, pipelined);
break;
case 2:
- i830_write_fence_reg(reg);
+ ret = i830_write_fence_reg(obj, pipelined);
break;
}
- trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg,
- obj_priv->tiling_mode);
-
- return 0;
+ return ret;
}
/**
@@ -2533,154 +2665,125 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
* @obj: object to clear
*
* Zeroes out the fence register itself and clears out the associated
- * data structures in dev_priv and obj_priv.
+ * data structures in dev_priv and obj.
*/
static void
-i915_gem_clear_fence_reg(struct drm_gem_object *obj)
+i915_gem_clear_fence_reg(struct drm_device *dev,
+ struct drm_i915_fence_reg *reg)
{
- struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- struct drm_i915_fence_reg *reg =
- &dev_priv->fence_regs[obj_priv->fence_reg];
- uint32_t fence_reg;
+ uint32_t fence_reg = reg - dev_priv->fence_regs;
switch (INTEL_INFO(dev)->gen) {
case 6:
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 +
- (obj_priv->fence_reg * 8), 0);
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
break;
case 5:
case 4:
- I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
+ I915_WRITE64(FENCE_REG_965_0 + fence_reg*8, 0);
break;
case 3:
- if (obj_priv->fence_reg >= 8)
- fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4;
+ if (fence_reg >= 8)
+ fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;
else
case 2:
- fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4;
+ fence_reg = FENCE_REG_830_0 + fence_reg * 4;
I915_WRITE(fence_reg, 0);
break;
}
- reg->obj = NULL;
- obj_priv->fence_reg = I915_FENCE_REG_NONE;
list_del_init(&reg->lru_list);
-}
-
-/**
- * i915_gem_object_put_fence_reg - waits on outstanding fenced access
- * to the buffer to finish, and then resets the fence register.
- * @obj: tiled object holding a fence register.
- * @bool: whether the wait upon the fence is interruptible
- *
- * Zeroes out the fence register itself and clears out the associated
- * data structures in dev_priv and obj_priv.
- */
-int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
- bool interruptible)
-{
- struct drm_device *dev = obj->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- struct drm_i915_fence_reg *reg;
-
- if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
- return 0;
-
- /* If we've changed tiling, GTT-mappings of the object
- * need to re-fault to ensure that the correct fence register
- * setup is in place.
- */
- i915_gem_release_mmap(obj);
-
- /* On the i915, GPU access to tiled buffers is via a fence,
- * therefore we must wait for any outstanding access to complete
- * before clearing the fence.
- */
- reg = &dev_priv->fence_regs[obj_priv->fence_reg];
- if (reg->gpu) {
- int ret;
-
- ret = i915_gem_object_flush_gpu_write_domain(obj, true);
- if (ret)
- return ret;
-
- ret = i915_gem_object_wait_rendering(obj, interruptible);
- if (ret)
- return ret;
-
- reg->gpu = false;
- }
-
- i915_gem_object_flush_gtt_write_domain(obj);
- i915_gem_clear_fence_reg(obj);
-
- return 0;
+ reg->obj = NULL;
+ reg->setup_seqno = 0;
}
/**
* Finds free space in the GTT aperture and binds the object there.
*/
static int
-i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
+i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
+ unsigned alignment,
+ bool map_and_fenceable)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_mm_node *free_space;
- gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
+ gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
+ u32 size, fence_size, fence_alignment, unfenced_alignment;
+ bool mappable, fenceable;
int ret;
- if (obj_priv->madv != I915_MADV_WILLNEED) {
+ if (obj->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to bind a purgeable object\n");
return -EINVAL;
}
+ fence_size = i915_gem_get_gtt_size(obj);
+ fence_alignment = i915_gem_get_gtt_alignment(obj);
+ unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj);
+
if (alignment == 0)
- alignment = i915_gem_get_gtt_alignment(obj);
- if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) {
+ alignment = map_and_fenceable ? fence_alignment :
+ unfenced_alignment;
+ if (map_and_fenceable && alignment & (fence_alignment - 1)) {
DRM_ERROR("Invalid object alignment requested %u\n", alignment);
return -EINVAL;
}
+ size = map_and_fenceable ? fence_size : obj->base.size;
+
/* If the object is bigger than the entire aperture, reject it early
* before evicting everything in a vain attempt to find space.
*/
- if (obj->size > dev_priv->mm.gtt_total) {
+ if (obj->base.size >
+ (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) {
DRM_ERROR("Attempting to bind an object larger than the aperture\n");
return -E2BIG;
}
search_free:
- free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
- obj->size, alignment, 0);
- if (free_space != NULL)
- obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
- alignment);
- if (obj_priv->gtt_space == NULL) {
+ if (map_and_fenceable)
+ free_space =
+ drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
+ size, alignment, 0,
+ dev_priv->mm.gtt_mappable_end,
+ 0);
+ else
+ free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
+ size, alignment, 0);
+
+ if (free_space != NULL) {
+ if (map_and_fenceable)
+ obj->gtt_space =
+ drm_mm_get_block_range_generic(free_space,
+ size, alignment, 0,
+ dev_priv->mm.gtt_mappable_end,
+ 0);
+ else
+ obj->gtt_space =
+ drm_mm_get_block(free_space, size, alignment);
+ }
+ if (obj->gtt_space == NULL) {
/* If the gtt is empty and we're still having trouble
* fitting our object in, we're out of memory.
*/
- ret = i915_gem_evict_something(dev, obj->size, alignment);
+ ret = i915_gem_evict_something(dev, size, alignment,
+ map_and_fenceable);
if (ret)
return ret;
goto search_free;
}
- ret = i915_gem_object_get_pages(obj, gfpmask);
+ ret = i915_gem_object_get_pages_gtt(obj, gfpmask);
if (ret) {
- drm_mm_put_block(obj_priv->gtt_space);
- obj_priv->gtt_space = NULL;
+ drm_mm_put_block(obj->gtt_space);
+ obj->gtt_space = NULL;
if (ret == -ENOMEM) {
- /* first try to clear up some space from the GTT */
- ret = i915_gem_evict_something(dev, obj->size,
- alignment);
+ /* first try to reclaim some memory by clearing the GTT */
+ ret = i915_gem_evict_everything(dev, false);
if (ret) {
/* now try to shrink everyone else */
if (gfpmask) {
@@ -2688,7 +2791,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
goto search_free;
}
- return ret;
+ return -ENOMEM;
}
goto search_free;
@@ -2697,126 +2800,116 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
return ret;
}
- /* Create an AGP memory structure pointing at our pages, and bind it
- * into the GTT.
- */
- obj_priv->agp_mem = drm_agp_bind_pages(dev,
- obj_priv->pages,
- obj->size >> PAGE_SHIFT,
- obj_priv->gtt_space->start,
- obj_priv->agp_type);
- if (obj_priv->agp_mem == NULL) {
- i915_gem_object_put_pages(obj);
- drm_mm_put_block(obj_priv->gtt_space);
- obj_priv->gtt_space = NULL;
-
- ret = i915_gem_evict_something(dev, obj->size, alignment);
- if (ret)
+ ret = i915_gem_gtt_bind_object(obj);
+ if (ret) {
+ i915_gem_object_put_pages_gtt(obj);
+ drm_mm_put_block(obj->gtt_space);
+ obj->gtt_space = NULL;
+
+ if (i915_gem_evict_everything(dev, false))
return ret;
goto search_free;
}
- /* keep track of bounds object by adding it to the inactive list */
- list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
- i915_gem_info_add_gtt(dev_priv, obj->size);
+ list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list);
+ list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
/* Assert that the object is not currently in any GPU domain. As it
* wasn't in the GTT, there shouldn't be any way it could have been in
* a GPU cache
*/
- BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
- BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
+ BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
+ BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
- obj_priv->gtt_offset = obj_priv->gtt_space->start;
- trace_i915_gem_object_bind(obj, obj_priv->gtt_offset);
+ obj->gtt_offset = obj->gtt_space->start;
+ fenceable =
+ obj->gtt_space->size == fence_size &&
+ (obj->gtt_space->start & (fence_alignment -1)) == 0;
+
+ mappable =
+ obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end;
+
+ obj->map_and_fenceable = mappable && fenceable;
+
+ trace_i915_gem_object_bind(obj, obj->gtt_offset, map_and_fenceable);
return 0;
}
void
-i915_gem_clflush_object(struct drm_gem_object *obj)
+i915_gem_clflush_object(struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-
/* If we don't have a page list set up, then we're not pinned
* to GPU, and we can ignore the cache flush because it'll happen
* again at bind time.
*/
- if (obj_priv->pages == NULL)
+ if (obj->pages == NULL)
return;
trace_i915_gem_object_clflush(obj);
- drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE);
+ drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
}
/** Flushes any GPU write domain for the object if it's dirty. */
static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
- bool pipelined)
+i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
- uint32_t old_write_domain;
+ struct drm_device *dev = obj->base.dev;
- if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
+ if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0)
return 0;
/* Queue the GPU write cache flushing we need. */
- old_write_domain = obj->write_domain;
- i915_gem_flush_ring(dev, NULL,
- to_intel_bo(obj)->ring,
- 0, obj->write_domain);
- BUG_ON(obj->write_domain);
-
- trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
- old_write_domain);
-
- if (pipelined)
- return 0;
-
- return i915_gem_object_wait_rendering(obj, true);
+ return i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain);
}
/** Flushes the GTT write domain for the object if it's dirty. */
static void
-i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
{
uint32_t old_write_domain;
- if (obj->write_domain != I915_GEM_DOMAIN_GTT)
+ if (obj->base.write_domain != I915_GEM_DOMAIN_GTT)
return;
- /* No actual flushing is required for the GTT write domain. Writes
+ /* No actual flushing is required for the GTT write domain. Writes
* to it immediately go to main memory as far as we know, so there's
* no chipset flush. It also doesn't land in render cache.
+ *
+ * However, we do have to enforce the order so that all writes through
+ * the GTT land before any writes to the device, such as updates to
+ * the GATT itself.
*/
- old_write_domain = obj->write_domain;
- obj->write_domain = 0;
+ wmb();
+
+ i915_gem_release_mmap(obj);
+
+ old_write_domain = obj->base.write_domain;
+ obj->base.write_domain = 0;
trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
+ obj->base.read_domains,
old_write_domain);
}
/** Flushes the CPU write domain for the object if it's dirty. */
static void
-i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
uint32_t old_write_domain;
- if (obj->write_domain != I915_GEM_DOMAIN_CPU)
+ if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
return;
i915_gem_clflush_object(obj);
- drm_agp_chipset_flush(dev);
- old_write_domain = obj->write_domain;
- obj->write_domain = 0;
+ intel_gtt_chipset_flush();
+ old_write_domain = obj->base.write_domain;
+ obj->base.write_domain = 0;
trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
+ obj->base.read_domains,
old_write_domain);
}
@@ -2827,40 +2920,39 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
* flushes to occur.
*/
int
-i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
+i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_write_domain, old_read_domains;
int ret;
/* Not valid to be called on unbound objects. */
- if (obj_priv->gtt_space == NULL)
+ if (obj->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
- if (ret != 0)
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
return ret;
- i915_gem_object_flush_cpu_write_domain(obj);
-
- if (write) {
+ if (obj->pending_gpu_write || write) {
ret = i915_gem_object_wait_rendering(obj, true);
if (ret)
return ret;
}
- old_write_domain = obj->write_domain;
- old_read_domains = obj->read_domains;
+ i915_gem_object_flush_cpu_write_domain(obj);
+
+ old_write_domain = obj->base.write_domain;
+ old_read_domains = obj->base.read_domains;
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
- BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
- obj->read_domains |= I915_GEM_DOMAIN_GTT;
+ BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
+ obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
if (write) {
- obj->read_domains = I915_GEM_DOMAIN_GTT;
- obj->write_domain = I915_GEM_DOMAIN_GTT;
- obj_priv->dirty = 1;
+ obj->base.read_domains = I915_GEM_DOMAIN_GTT;
+ obj->base.write_domain = I915_GEM_DOMAIN_GTT;
+ obj->dirty = 1;
}
trace_i915_gem_object_change_domain(obj,
@@ -2875,23 +2967,23 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
* wait, as in modesetting process we're not supposed to be interrupted.
*/
int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
- bool pipelined)
+i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_read_domains;
int ret;
/* Not valid to be called on unbound objects. */
- if (obj_priv->gtt_space == NULL)
+ if (obj->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
+
/* Currently, we are always called from an non-interruptible context. */
- if (!pipelined) {
+ if (pipelined != obj->ring) {
ret = i915_gem_object_wait_rendering(obj, false);
if (ret)
return ret;
@@ -2899,16 +2991,35 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
i915_gem_object_flush_cpu_write_domain(obj);
- old_read_domains = obj->read_domains;
- obj->read_domains |= I915_GEM_DOMAIN_GTT;
+ old_read_domains = obj->base.read_domains;
+ obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
- obj->write_domain);
+ obj->base.write_domain);
return 0;
}
+int
+i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+ bool interruptible)
+{
+ int ret;
+
+ if (!obj->active)
+ return 0;
+
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(obj->base.dev, obj->ring,
+ 0, obj->base.write_domain);
+ if (ret)
+ return ret;
+ }
+
+ return i915_gem_object_wait_rendering(obj, interruptible);
+}
+
/**
* Moves a single object to the CPU read, and possibly write domain.
*
@@ -2916,13 +3027,17 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
* flushes to occur.
*/
static int
-i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
+i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
{
uint32_t old_write_domain, old_read_domains;
int ret;
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
- if (ret != 0)
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
return ret;
i915_gem_object_flush_gtt_write_domain(obj);
@@ -2932,33 +3047,27 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
*/
i915_gem_object_set_to_full_cpu_read_domain(obj);
- if (write) {
- ret = i915_gem_object_wait_rendering(obj, true);
- if (ret)
- return ret;
- }
-
- old_write_domain = obj->write_domain;
- old_read_domains = obj->read_domains;
+ old_write_domain = obj->base.write_domain;
+ old_read_domains = obj->base.read_domains;
/* Flush the CPU cache if it's still invalid. */
- if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) {
+ if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) {
i915_gem_clflush_object(obj);
- obj->read_domains |= I915_GEM_DOMAIN_CPU;
+ obj->base.read_domains |= I915_GEM_DOMAIN_CPU;
}
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
- BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_CPU) != 0);
+ BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0);
/* If we're writing through the CPU, then the GPU read domains will
* need to be invalidated at next use.
*/
if (write) {
- obj->read_domains = I915_GEM_DOMAIN_CPU;
- obj->write_domain = I915_GEM_DOMAIN_CPU;
+ obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+ obj->base.write_domain = I915_GEM_DOMAIN_CPU;
}
trace_i915_gem_object_change_domain(obj,
@@ -2968,183 +3077,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
return 0;
}
-/*
- * Set the next domain for the specified object. This
- * may not actually perform the necessary flushing/invaliding though,
- * as that may want to be batched with other set_domain operations
- *
- * This is (we hope) the only really tricky part of gem. The goal
- * is fairly simple -- track which caches hold bits of the object
- * and make sure they remain coherent. A few concrete examples may
- * help to explain how it works. For shorthand, we use the notation
- * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
- * a pair of read and write domain masks.
- *
- * Case 1: the batch buffer
- *
- * 1. Allocated
- * 2. Written by CPU
- * 3. Mapped to GTT
- * 4. Read by GPU
- * 5. Unmapped from GTT
- * 6. Freed
- *
- * Let's take these a step at a time
- *
- * 1. Allocated
- * Pages allocated from the kernel may still have
- * cache contents, so we set them to (CPU, CPU) always.
- * 2. Written by CPU (using pwrite)
- * The pwrite function calls set_domain (CPU, CPU) and
- * this function does nothing (as nothing changes)
- * 3. Mapped by GTT
- * This function asserts that the object is not
- * currently in any GPU-based read or write domains
- * 4. Read by GPU
- * i915_gem_execbuffer calls set_domain (COMMAND, 0).
- * As write_domain is zero, this function adds in the
- * current read domains (CPU+COMMAND, 0).
- * flush_domains is set to CPU.
- * invalidate_domains is set to COMMAND
- * clflush is run to get data out of the CPU caches
- * then i915_dev_set_domain calls i915_gem_flush to
- * emit an MI_FLUSH and drm_agp_chipset_flush
- * 5. Unmapped from GTT
- * i915_gem_object_unbind calls set_domain (CPU, CPU)
- * flush_domains and invalidate_domains end up both zero
- * so no flushing/invalidating happens
- * 6. Freed
- * yay, done
- *
- * Case 2: The shared render buffer
- *
- * 1. Allocated
- * 2. Mapped to GTT
- * 3. Read/written by GPU
- * 4. set_domain to (CPU,CPU)
- * 5. Read/written by CPU
- * 6. Read/written by GPU
- *
- * 1. Allocated
- * Same as last example, (CPU, CPU)
- * 2. Mapped to GTT
- * Nothing changes (assertions find that it is not in the GPU)
- * 3. Read/written by GPU
- * execbuffer calls set_domain (RENDER, RENDER)
- * flush_domains gets CPU
- * invalidate_domains gets GPU
- * clflush (obj)
- * MI_FLUSH and drm_agp_chipset_flush
- * 4. set_domain (CPU, CPU)
- * flush_domains gets GPU
- * invalidate_domains gets CPU
- * wait_rendering (obj) to make sure all drawing is complete.
- * This will include an MI_FLUSH to get the data from GPU
- * to memory
- * clflush (obj) to invalidate the CPU cache
- * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
- * 5. Read/written by CPU
- * cache lines are loaded and dirtied
- * 6. Read written by GPU
- * Same as last GPU access
- *
- * Case 3: The constant buffer
- *
- * 1. Allocated
- * 2. Written by CPU
- * 3. Read by GPU
- * 4. Updated (written) by CPU again
- * 5. Read by GPU
- *
- * 1. Allocated
- * (CPU, CPU)
- * 2. Written by CPU
- * (CPU, CPU)
- * 3. Read by GPU
- * (CPU+RENDER, 0)
- * flush_domains = CPU
- * invalidate_domains = RENDER
- * clflush (obj)
- * MI_FLUSH
- * drm_agp_chipset_flush
- * 4. Updated (written) by CPU again
- * (CPU, CPU)
- * flush_domains = 0 (no previous write domain)
- * invalidate_domains = 0 (no new read domains)
- * 5. Read by GPU
- * (CPU+RENDER, 0)
- * flush_domains = CPU
- * invalidate_domains = RENDER
- * clflush (obj)
- * MI_FLUSH
- * drm_agp_chipset_flush
- */
-static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
- struct intel_ring_buffer *ring)
-{
- struct drm_device *dev = obj->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- uint32_t invalidate_domains = 0;
- uint32_t flush_domains = 0;
- uint32_t old_read_domains;
-
- intel_mark_busy(dev, obj);
-
- /*
- * If the object isn't moving to a new write domain,
- * let the object stay in multiple read domains
- */
- if (obj->pending_write_domain == 0)
- obj->pending_read_domains |= obj->read_domains;
- else
- obj_priv->dirty = 1;
-
- /*
- * Flush the current write domain if
- * the new read domains don't match. Invalidate
- * any read domains which differ from the old
- * write domain
- */
- if (obj->write_domain &&
- obj->write_domain != obj->pending_read_domains) {
- flush_domains |= obj->write_domain;
- invalidate_domains |=
- obj->pending_read_domains & ~obj->write_domain;
- }
- /*
- * Invalidate any read caches which may have
- * stale data. That is, any new read domains.
- */
- invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
- if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
- i915_gem_clflush_object(obj);
-
- old_read_domains = obj->read_domains;
-
- /* The actual obj->write_domain will be updated with
- * pending_write_domain after we emit the accumulated flush for all
- * of our domain changes in execbuffers (which clears objects'
- * write_domains). So if we have a current write domain that we
- * aren't changing, set pending_write_domain to that.
- */
- if (flush_domains == 0 && obj->pending_write_domain == 0)
- obj->pending_write_domain = obj->write_domain;
- obj->read_domains = obj->pending_read_domains;
-
- dev->invalidate_domains |= invalidate_domains;
- dev->flush_domains |= flush_domains;
- if (flush_domains & I915_GEM_GPU_DOMAINS)
- dev_priv->mm.flush_rings |= obj_priv->ring->id;
- if (invalidate_domains & I915_GEM_GPU_DOMAINS)
- dev_priv->mm.flush_rings |= ring->id;
-
- trace_i915_gem_object_change_domain(obj,
- old_read_domains,
- obj->write_domain);
-}
-
/**
* Moves the object from a partially CPU read to a full one.
*
@@ -3152,30 +3084,28 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
* and doesn't handle transitioning from !(read_domains & I915_GEM_DOMAIN_CPU).
*/
static void
-i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj)
+i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-
- if (!obj_priv->page_cpu_valid)
+ if (!obj->page_cpu_valid)
return;
/* If we're partially in the CPU read domain, finish moving it in.
*/
- if (obj->read_domains & I915_GEM_DOMAIN_CPU) {
+ if (obj->base.read_domains & I915_GEM_DOMAIN_CPU) {
int i;
- for (i = 0; i <= (obj->size - 1) / PAGE_SIZE; i++) {
- if (obj_priv->page_cpu_valid[i])
+ for (i = 0; i <= (obj->base.size - 1) / PAGE_SIZE; i++) {
+ if (obj->page_cpu_valid[i])
continue;
- drm_clflush_pages(obj_priv->pages + i, 1);
+ drm_clflush_pages(obj->pages + i, 1);
}
}
/* Free the page_cpu_valid mappings which are now stale, whether
* or not we've got I915_GEM_DOMAIN_CPU.
*/
- kfree(obj_priv->page_cpu_valid);
- obj_priv->page_cpu_valid = NULL;
+ kfree(obj->page_cpu_valid);
+ obj->page_cpu_valid = NULL;
}
/**
@@ -3191,308 +3121,65 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj)
* flushes to occur.
*/
static int
-i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
+i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj,
uint64_t offset, uint64_t size)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_read_domains;
int i, ret;
- if (offset == 0 && size == obj->size)
+ if (offset == 0 && size == obj->base.size)
return i915_gem_object_set_to_cpu_domain(obj, 0);
- ret = i915_gem_object_flush_gpu_write_domain(obj, false);
- if (ret != 0)
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
return ret;
+
i915_gem_object_flush_gtt_write_domain(obj);
/* If we're already fully in the CPU read domain, we're done. */
- if (obj_priv->page_cpu_valid == NULL &&
- (obj->read_domains & I915_GEM_DOMAIN_CPU) != 0)
+ if (obj->page_cpu_valid == NULL &&
+ (obj->base.read_domains & I915_GEM_DOMAIN_CPU) != 0)
return 0;
/* Otherwise, create/clear the per-page CPU read domain flag if we're
* newly adding I915_GEM_DOMAIN_CPU
*/
- if (obj_priv->page_cpu_valid == NULL) {
- obj_priv->page_cpu_valid = kzalloc(obj->size / PAGE_SIZE,
- GFP_KERNEL);
- if (obj_priv->page_cpu_valid == NULL)
+ if (obj->page_cpu_valid == NULL) {
+ obj->page_cpu_valid = kzalloc(obj->base.size / PAGE_SIZE,
+ GFP_KERNEL);
+ if (obj->page_cpu_valid == NULL)
return -ENOMEM;
- } else if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0)
- memset(obj_priv->page_cpu_valid, 0, obj->size / PAGE_SIZE);
+ } else if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0)
+ memset(obj->page_cpu_valid, 0, obj->base.size / PAGE_SIZE);
/* Flush the cache on any pages that are still invalid from the CPU's
* perspective.
*/
for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE;
i++) {
- if (obj_priv->page_cpu_valid[i])
+ if (obj->page_cpu_valid[i])
continue;
- drm_clflush_pages(obj_priv->pages + i, 1);
+ drm_clflush_pages(obj->pages + i, 1);
- obj_priv->page_cpu_valid[i] = 1;
+ obj->page_cpu_valid[i] = 1;
}
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
- BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_CPU) != 0);
+ BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0);
- old_read_domains = obj->read_domains;
- obj->read_domains |= I915_GEM_DOMAIN_CPU;
+ old_read_domains = obj->base.read_domains;
+ obj->base.read_domains |= I915_GEM_DOMAIN_CPU;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
- obj->write_domain);
-
- return 0;
-}
-
-/**
- * Pin an object to the GTT and evaluate the relocations landing in it.
- */
-static int
-i915_gem_execbuffer_relocate(struct drm_i915_gem_object *obj,
- struct drm_file *file_priv,
- struct drm_i915_gem_exec_object2 *entry)
-{
- struct drm_device *dev = obj->base.dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_relocation_entry __user *user_relocs;
- struct drm_gem_object *target_obj = NULL;
- uint32_t target_handle = 0;
- int i, ret = 0;
-
- user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
- for (i = 0; i < entry->relocation_count; i++) {
- struct drm_i915_gem_relocation_entry reloc;
- uint32_t target_offset;
-
- if (__copy_from_user_inatomic(&reloc,
- user_relocs+i,
- sizeof(reloc))) {
- ret = -EFAULT;
- break;
- }
-
- if (reloc.target_handle != target_handle) {
- drm_gem_object_unreference(target_obj);
-
- target_obj = drm_gem_object_lookup(dev, file_priv,
- reloc.target_handle);
- if (target_obj == NULL) {
- ret = -ENOENT;
- break;
- }
-
- target_handle = reloc.target_handle;
- }
- target_offset = to_intel_bo(target_obj)->gtt_offset;
-
-#if WATCH_RELOC
- DRM_INFO("%s: obj %p offset %08x target %d "
- "read %08x write %08x gtt %08x "
- "presumed %08x delta %08x\n",
- __func__,
- obj,
- (int) reloc.offset,
- (int) reloc.target_handle,
- (int) reloc.read_domains,
- (int) reloc.write_domain,
- (int) target_offset,
- (int) reloc.presumed_offset,
- reloc.delta);
-#endif
-
- /* The target buffer should have appeared before us in the
- * exec_object list, so it should have a GTT space bound by now.
- */
- if (target_offset == 0) {
- DRM_ERROR("No GTT space found for object %d\n",
- reloc.target_handle);
- ret = -EINVAL;
- break;
- }
-
- /* Validate that the target is in a valid r/w GPU domain */
- if (reloc.write_domain & (reloc.write_domain - 1)) {
- DRM_ERROR("reloc with multiple write domains: "
- "obj %p target %d offset %d "
- "read %08x write %08x",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.read_domains,
- reloc.write_domain);
- ret = -EINVAL;
- break;
- }
- if (reloc.write_domain & I915_GEM_DOMAIN_CPU ||
- reloc.read_domains & I915_GEM_DOMAIN_CPU) {
- DRM_ERROR("reloc with read/write CPU domains: "
- "obj %p target %d offset %d "
- "read %08x write %08x",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.read_domains,
- reloc.write_domain);
- ret = -EINVAL;
- break;
- }
- if (reloc.write_domain && target_obj->pending_write_domain &&
- reloc.write_domain != target_obj->pending_write_domain) {
- DRM_ERROR("Write domain conflict: "
- "obj %p target %d offset %d "
- "new %08x old %08x\n",
- obj, reloc.target_handle,
- (int) reloc.offset,
- reloc.write_domain,
- target_obj->pending_write_domain);
- ret = -EINVAL;
- break;
- }
-
- target_obj->pending_read_domains |= reloc.read_domains;
- target_obj->pending_write_domain |= reloc.write_domain;
-
- /* If the relocation already has the right value in it, no
- * more work needs to be done.
- */
- if (target_offset == reloc.presumed_offset)
- continue;
-
- /* Check that the relocation address is valid... */
- if (reloc.offset > obj->base.size - 4) {
- DRM_ERROR("Relocation beyond object bounds: "
- "obj %p target %d offset %d size %d.\n",
- obj, reloc.target_handle,
- (int) reloc.offset, (int) obj->base.size);
- ret = -EINVAL;
- break;
- }
- if (reloc.offset & 3) {
- DRM_ERROR("Relocation not 4-byte aligned: "
- "obj %p target %d offset %d.\n",
- obj, reloc.target_handle,
- (int) reloc.offset);
- ret = -EINVAL;
- break;
- }
-
- /* and points to somewhere within the target object. */
- if (reloc.delta >= target_obj->size) {
- DRM_ERROR("Relocation beyond target object bounds: "
- "obj %p target %d delta %d size %d.\n",
- obj, reloc.target_handle,
- (int) reloc.delta, (int) target_obj->size);
- ret = -EINVAL;
- break;
- }
-
- reloc.delta += target_offset;
- if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
- uint32_t page_offset = reloc.offset & ~PAGE_MASK;
- char *vaddr;
-
- vaddr = kmap_atomic(obj->pages[reloc.offset >> PAGE_SHIFT]);
- *(uint32_t *)(vaddr + page_offset) = reloc.delta;
- kunmap_atomic(vaddr);
- } else {
- uint32_t __iomem *reloc_entry;
- void __iomem *reloc_page;
-
- ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
- if (ret)
- break;
-
- /* Map the page containing the relocation we're going to perform. */
- reloc.offset += obj->gtt_offset;
- reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- reloc.offset & PAGE_MASK);
- reloc_entry = (uint32_t __iomem *)
- (reloc_page + (reloc.offset & ~PAGE_MASK));
- iowrite32(reloc.delta, reloc_entry);
- io_mapping_unmap_atomic(reloc_page);
- }
-
- /* and update the user's relocation entry */
- reloc.presumed_offset = target_offset;
- if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
- &reloc.presumed_offset,
- sizeof(reloc.presumed_offset))) {
- ret = -EFAULT;
- break;
- }
- }
-
- drm_gem_object_unreference(target_obj);
- return ret;
-}
-
-static int
-i915_gem_execbuffer_pin(struct drm_device *dev,
- struct drm_file *file,
- struct drm_gem_object **object_list,
- struct drm_i915_gem_exec_object2 *exec_list,
- int count)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret, i, retry;
-
- /* attempt to pin all of the buffers into the GTT */
- for (retry = 0; retry < 2; retry++) {
- ret = 0;
- for (i = 0; i < count; i++) {
- struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
- struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]);
- bool need_fence =
- entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
- obj->tiling_mode != I915_TILING_NONE;
-
- /* Check fence reg constraints and rebind if necessary */
- if (need_fence &&
- !i915_gem_object_fence_offset_ok(&obj->base,
- obj->tiling_mode)) {
- ret = i915_gem_object_unbind(&obj->base);
- if (ret)
- break;
- }
-
- ret = i915_gem_object_pin(&obj->base, entry->alignment);
- if (ret)
- break;
-
- /*
- * Pre-965 chips need a fence register set up in order
- * to properly handle blits to/from tiled surfaces.
- */
- if (need_fence) {
- ret = i915_gem_object_get_fence_reg(&obj->base, true);
- if (ret) {
- i915_gem_object_unpin(&obj->base);
- break;
- }
-
- dev_priv->fence_regs[obj->fence_reg].gpu = true;
- }
-
- entry->offset = obj->gtt_offset;
- }
-
- while (i--)
- i915_gem_object_unpin(object_list[i]);
-
- if (ret == 0)
- break;
-
- if (ret != -ENOSPC || retry)
- return ret;
-
- ret = i915_gem_evict_everything(dev);
- if (ret)
- return ret;
- }
+ obj->base.write_domain);
return 0;
}
@@ -3532,610 +3219,129 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
return 0;
ret = 0;
- if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+ if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
/* And wait for the seqno passing without holding any locks and
* causing extra latency for others. This is safe as the irq
* generation is designed to be run atomically and so is
* lockless.
*/
- ring->user_irq_get(dev, ring);
- ret = wait_event_interruptible(ring->irq_queue,
- i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
- ring->user_irq_put(dev, ring);
-
- if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
- ret = -EIO;
- }
-
- if (ret == 0)
- queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
-
- return ret;
-}
-
-static int
-i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec,
- uint64_t exec_offset)
-{
- uint32_t exec_start, exec_len;
-
- exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
- exec_len = (uint32_t) exec->batch_len;
-
- if ((exec_start | exec_len) & 0x7)
- return -EINVAL;
-
- if (!exec_start)
- return -EINVAL;
-
- return 0;
-}
-
-static int
-validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
- int count)
-{
- int i;
-
- for (i = 0; i < count; i++) {
- char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
- size_t length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry);
-
- if (!access_ok(VERIFY_READ, ptr, length))
- return -EFAULT;
-
- /* we may also need to update the presumed offsets */
- if (!access_ok(VERIFY_WRITE, ptr, length))
- return -EFAULT;
-
- if (fault_in_pages_readable(ptr, length))
- return -EFAULT;
- }
-
- return 0;
-}
-
-static int
-i915_gem_do_execbuffer(struct drm_device *dev, void *data,
- struct drm_file *file,
- struct drm_i915_gem_execbuffer2 *args,
- struct drm_i915_gem_exec_object2 *exec_list)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object **object_list = NULL;
- struct drm_gem_object *batch_obj;
- struct drm_i915_gem_object *obj_priv;
- struct drm_clip_rect *cliprects = NULL;
- struct drm_i915_gem_request *request = NULL;
- int ret, i, flips;
- uint64_t exec_offset;
-
- struct intel_ring_buffer *ring = NULL;
-
- ret = i915_gem_check_is_wedged(dev);
- if (ret)
- return ret;
-
- ret = validate_exec_list(exec_list, args->buffer_count);
- if (ret)
- return ret;
-
-#if WATCH_EXEC
- DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
- (int) args->buffers_ptr, args->buffer_count, args->batch_len);
-#endif
- switch (args->flags & I915_EXEC_RING_MASK) {
- case I915_EXEC_DEFAULT:
- case I915_EXEC_RENDER:
- ring = &dev_priv->render_ring;
- break;
- case I915_EXEC_BSD:
- if (!HAS_BSD(dev)) {
- DRM_ERROR("execbuf with invalid ring (BSD)\n");
- return -EINVAL;
- }
- ring = &dev_priv->bsd_ring;
- break;
- case I915_EXEC_BLT:
- if (!HAS_BLT(dev)) {
- DRM_ERROR("execbuf with invalid ring (BLT)\n");
- return -EINVAL;
- }
- ring = &dev_priv->blt_ring;
- break;
- default:
- DRM_ERROR("execbuf with unknown ring: %d\n",
- (int)(args->flags & I915_EXEC_RING_MASK));
- return -EINVAL;
- }
-
- if (args->buffer_count < 1) {
- DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
- return -EINVAL;
- }
- object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count);
- if (object_list == NULL) {
- DRM_ERROR("Failed to allocate object list for %d buffers\n",
- args->buffer_count);
- ret = -ENOMEM;
- goto pre_mutex_err;
- }
-
- if (args->num_cliprects != 0) {
- cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects),
- GFP_KERNEL);
- if (cliprects == NULL) {
- ret = -ENOMEM;
- goto pre_mutex_err;
- }
-
- ret = copy_from_user(cliprects,
- (struct drm_clip_rect __user *)
- (uintptr_t) args->cliprects_ptr,
- sizeof(*cliprects) * args->num_cliprects);
- if (ret != 0) {
- DRM_ERROR("copy %d cliprects failed: %d\n",
- args->num_cliprects, ret);
- ret = -EFAULT;
- goto pre_mutex_err;
- }
- }
-
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL) {
- ret = -ENOMEM;
- goto pre_mutex_err;
- }
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- goto pre_mutex_err;
-
- if (dev_priv->mm.suspended) {
- mutex_unlock(&dev->struct_mutex);
- ret = -EBUSY;
- goto pre_mutex_err;
- }
-
- /* Look up object handles */
- for (i = 0; i < args->buffer_count; i++) {
- object_list[i] = drm_gem_object_lookup(dev, file,
- exec_list[i].handle);
- if (object_list[i] == NULL) {
- DRM_ERROR("Invalid object handle %d at index %d\n",
- exec_list[i].handle, i);
- /* prevent error path from reading uninitialized data */
- args->buffer_count = i + 1;
- ret = -ENOENT;
- goto err;
- }
-
- obj_priv = to_intel_bo(object_list[i]);
- if (obj_priv->in_execbuffer) {
- DRM_ERROR("Object %p appears more than once in object list\n",
- object_list[i]);
- /* prevent error path from reading uninitialized data */
- args->buffer_count = i + 1;
- ret = -EINVAL;
- goto err;
- }
- obj_priv->in_execbuffer = true;
- }
-
- /* Move the objects en-masse into the GTT, evicting if necessary. */
- ret = i915_gem_execbuffer_pin(dev, file,
- object_list, exec_list,
- args->buffer_count);
- if (ret)
- goto err;
-
- /* The objects are in their final locations, apply the relocations. */
- for (i = 0; i < args->buffer_count; i++) {
- struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
- ret = i915_gem_execbuffer_relocate(obj, file, &exec_list[i]);
- if (ret)
- goto err;
- }
-
- /* Set the pending read domains for the batch buffer to COMMAND */
- batch_obj = object_list[args->buffer_count-1];
- if (batch_obj->pending_write_domain) {
- DRM_ERROR("Attempting to use self-modifying batch buffer\n");
- ret = -EINVAL;
- goto err;
- }
- batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
-
- /* Sanity check the batch buffer */
- exec_offset = to_intel_bo(batch_obj)->gtt_offset;
- ret = i915_gem_check_execbuffer(args, exec_offset);
- if (ret != 0) {
- DRM_ERROR("execbuf with invalid offset/length\n");
- goto err;
- }
-
- /* Zero the global flush/invalidate flags. These
- * will be modified as new domains are computed
- * for each object
- */
- dev->invalidate_domains = 0;
- dev->flush_domains = 0;
- dev_priv->mm.flush_rings = 0;
-
- for (i = 0; i < args->buffer_count; i++) {
- struct drm_gem_object *obj = object_list[i];
-
- /* Compute new gpu domains and update invalidate/flush */
- i915_gem_object_set_to_gpu_domain(obj, ring);
- }
-
- if (dev->invalidate_domains | dev->flush_domains) {
-#if WATCH_EXEC
- DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
- __func__,
- dev->invalidate_domains,
- dev->flush_domains);
-#endif
- i915_gem_flush(dev, file,
- dev->invalidate_domains,
- dev->flush_domains,
- dev_priv->mm.flush_rings);
- }
-
- for (i = 0; i < args->buffer_count; i++) {
- struct drm_gem_object *obj = object_list[i];
- uint32_t old_write_domain = obj->write_domain;
- obj->write_domain = obj->pending_write_domain;
- trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
- old_write_domain);
- }
-
-#if WATCH_COHERENCY
- for (i = 0; i < args->buffer_count; i++) {
- i915_gem_object_check_coherency(object_list[i],
- exec_list[i].handle);
- }
-#endif
-
-#if WATCH_EXEC
- i915_gem_dump_object(batch_obj,
- args->batch_len,
- __func__,
- ~0);
-#endif
-
- /* Check for any pending flips. As we only maintain a flip queue depth
- * of 1, we can simply insert a WAIT for the next display flip prior
- * to executing the batch and avoid stalling the CPU.
- */
- flips = 0;
- for (i = 0; i < args->buffer_count; i++) {
- if (object_list[i]->write_domain)
- flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
- }
- if (flips) {
- int plane, flip_mask;
-
- for (plane = 0; flips >> plane; plane++) {
- if (((flips >> plane) & 1) == 0)
- continue;
-
- if (plane)
- flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
- else
- flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring,
- MI_WAIT_FOR_EVENT | flip_mask);
- intel_ring_emit(dev, ring, MI_NOOP);
- intel_ring_advance(dev, ring);
- }
- }
-
- /* Exec the batchbuffer */
- ret = ring->dispatch_gem_execbuffer(dev, ring, args,
- cliprects, exec_offset);
- if (ret) {
- DRM_ERROR("dispatch failed %d\n", ret);
- goto err;
- }
-
- /*
- * Ensure that the commands in the batch buffer are
- * finished before the interrupt fires
- */
- i915_retire_commands(dev, ring);
-
- for (i = 0; i < args->buffer_count; i++) {
- struct drm_gem_object *obj = object_list[i];
-
- i915_gem_object_move_to_active(obj, ring);
- if (obj->write_domain)
- list_move_tail(&to_intel_bo(obj)->gpu_write_list,
- &ring->gpu_write_list);
- }
-
- i915_add_request(dev, file, request, ring);
- request = NULL;
-
-err:
- for (i = 0; i < args->buffer_count; i++) {
- if (object_list[i]) {
- obj_priv = to_intel_bo(object_list[i]);
- obj_priv->in_execbuffer = false;
- }
- drm_gem_object_unreference(object_list[i]);
- }
-
- mutex_unlock(&dev->struct_mutex);
-
-pre_mutex_err:
- drm_free_large(object_list);
- kfree(cliprects);
- kfree(request);
-
- return ret;
-}
-
-/*
- * Legacy execbuffer just creates an exec2 list from the original exec object
- * list array and passes it to the real function.
- */
-int
-i915_gem_execbuffer(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_i915_gem_execbuffer *args = data;
- struct drm_i915_gem_execbuffer2 exec2;
- struct drm_i915_gem_exec_object *exec_list = NULL;
- struct drm_i915_gem_exec_object2 *exec2_list = NULL;
- int ret, i;
-
-#if WATCH_EXEC
- DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
- (int) args->buffers_ptr, args->buffer_count, args->batch_len);
-#endif
-
- if (args->buffer_count < 1) {
- DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
- return -EINVAL;
- }
-
- /* Copy in the exec list from userland */
- exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count);
- exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
- if (exec_list == NULL || exec2_list == NULL) {
- DRM_ERROR("Failed to allocate exec list for %d buffers\n",
- args->buffer_count);
- drm_free_large(exec_list);
- drm_free_large(exec2_list);
- return -ENOMEM;
- }
- ret = copy_from_user(exec_list,
- (struct drm_i915_relocation_entry __user *)
- (uintptr_t) args->buffers_ptr,
- sizeof(*exec_list) * args->buffer_count);
- if (ret != 0) {
- DRM_ERROR("copy %d exec entries failed %d\n",
- args->buffer_count, ret);
- drm_free_large(exec_list);
- drm_free_large(exec2_list);
- return -EFAULT;
- }
-
- for (i = 0; i < args->buffer_count; i++) {
- exec2_list[i].handle = exec_list[i].handle;
- exec2_list[i].relocation_count = exec_list[i].relocation_count;
- exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
- exec2_list[i].alignment = exec_list[i].alignment;
- exec2_list[i].offset = exec_list[i].offset;
- if (INTEL_INFO(dev)->gen < 4)
- exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
- else
- exec2_list[i].flags = 0;
- }
+ if (ring->irq_get(ring)) {
+ ret = wait_event_interruptible(ring->irq_queue,
+ i915_seqno_passed(ring->get_seqno(ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
+ ring->irq_put(ring);
- exec2.buffers_ptr = args->buffers_ptr;
- exec2.buffer_count = args->buffer_count;
- exec2.batch_start_offset = args->batch_start_offset;
- exec2.batch_len = args->batch_len;
- exec2.DR1 = args->DR1;
- exec2.DR4 = args->DR4;
- exec2.num_cliprects = args->num_cliprects;
- exec2.cliprects_ptr = args->cliprects_ptr;
- exec2.flags = I915_EXEC_RENDER;
-
- ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list);
- if (!ret) {
- /* Copy the new buffer offsets back to the user's exec list. */
- for (i = 0; i < args->buffer_count; i++)
- exec_list[i].offset = exec2_list[i].offset;
- /* ... and back out to userspace */
- ret = copy_to_user((struct drm_i915_relocation_entry __user *)
- (uintptr_t) args->buffers_ptr,
- exec_list,
- sizeof(*exec_list) * args->buffer_count);
- if (ret) {
- ret = -EFAULT;
- DRM_ERROR("failed to copy %d exec entries "
- "back to user (%d)\n",
- args->buffer_count, ret);
+ if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+ ret = -EIO;
}
}
- drm_free_large(exec_list);
- drm_free_large(exec2_list);
- return ret;
-}
-
-int
-i915_gem_execbuffer2(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_i915_gem_execbuffer2 *args = data;
- struct drm_i915_gem_exec_object2 *exec2_list = NULL;
- int ret;
-
-#if WATCH_EXEC
- DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
- (int) args->buffers_ptr, args->buffer_count, args->batch_len);
-#endif
-
- if (args->buffer_count < 1) {
- DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count);
- return -EINVAL;
- }
-
- exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
- if (exec2_list == NULL) {
- DRM_ERROR("Failed to allocate exec list for %d buffers\n",
- args->buffer_count);
- return -ENOMEM;
- }
- ret = copy_from_user(exec2_list,
- (struct drm_i915_relocation_entry __user *)
- (uintptr_t) args->buffers_ptr,
- sizeof(*exec2_list) * args->buffer_count);
- if (ret != 0) {
- DRM_ERROR("copy %d exec entries failed %d\n",
- args->buffer_count, ret);
- drm_free_large(exec2_list);
- return -EFAULT;
- }
-
- ret = i915_gem_do_execbuffer(dev, data, file_priv, args, exec2_list);
- if (!ret) {
- /* Copy the new buffer offsets back to the user's exec list. */
- ret = copy_to_user((struct drm_i915_relocation_entry __user *)
- (uintptr_t) args->buffers_ptr,
- exec2_list,
- sizeof(*exec2_list) * args->buffer_count);
- if (ret) {
- ret = -EFAULT;
- DRM_ERROR("failed to copy %d exec entries "
- "back to user (%d)\n",
- args->buffer_count, ret);
- }
- }
+ if (ret == 0)
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
- drm_free_large(exec2_list);
return ret;
}
int
-i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
+ uint32_t alignment,
+ bool map_and_fenceable)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
- BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+ BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
WARN_ON(i915_verify_lists(dev));
- if (obj_priv->gtt_space != NULL) {
- if (alignment == 0)
- alignment = i915_gem_get_gtt_alignment(obj);
- if (obj_priv->gtt_offset & (alignment - 1)) {
- WARN(obj_priv->pin_count,
+ if (obj->gtt_space != NULL) {
+ if ((alignment && obj->gtt_offset & (alignment - 1)) ||
+ (map_and_fenceable && !obj->map_and_fenceable)) {
+ WARN(obj->pin_count,
"bo is already pinned with incorrect alignment:"
- " offset=%x, req.alignment=%x\n",
- obj_priv->gtt_offset, alignment);
+ " offset=%x, req.alignment=%x, req.map_and_fenceable=%d,"
+ " obj->map_and_fenceable=%d\n",
+ obj->gtt_offset, alignment,
+ map_and_fenceable,
+ obj->map_and_fenceable);
ret = i915_gem_object_unbind(obj);
if (ret)
return ret;
}
}
- if (obj_priv->gtt_space == NULL) {
- ret = i915_gem_object_bind_to_gtt(obj, alignment);
+ if (obj->gtt_space == NULL) {
+ ret = i915_gem_object_bind_to_gtt(obj, alignment,
+ map_and_fenceable);
if (ret)
return ret;
}
- obj_priv->pin_count++;
-
- /* If the object is not active and not pending a flush,
- * remove it from the inactive list
- */
- if (obj_priv->pin_count == 1) {
- i915_gem_info_add_pin(dev_priv, obj->size);
- if (!obj_priv->active)
- list_move_tail(&obj_priv->mm_list,
+ if (obj->pin_count++ == 0) {
+ if (!obj->active)
+ list_move_tail(&obj->mm_list,
&dev_priv->mm.pinned_list);
}
+ obj->pin_mappable |= map_and_fenceable;
WARN_ON(i915_verify_lists(dev));
return 0;
}
void
-i915_gem_object_unpin(struct drm_gem_object *obj)
+i915_gem_object_unpin(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
WARN_ON(i915_verify_lists(dev));
- obj_priv->pin_count--;
- BUG_ON(obj_priv->pin_count < 0);
- BUG_ON(obj_priv->gtt_space == NULL);
+ BUG_ON(obj->pin_count == 0);
+ BUG_ON(obj->gtt_space == NULL);
- /* If the object is no longer pinned, and is
- * neither active nor being flushed, then stick it on
- * the inactive list
- */
- if (obj_priv->pin_count == 0) {
- if (!obj_priv->active)
- list_move_tail(&obj_priv->mm_list,
+ if (--obj->pin_count == 0) {
+ if (!obj->active)
+ list_move_tail(&obj->mm_list,
&dev_priv->mm.inactive_list);
- i915_gem_info_remove_pin(dev_priv, obj->size);
+ obj->pin_mappable = false;
}
WARN_ON(i915_verify_lists(dev));
}
int
i915_gem_pin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_pin *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
- if (obj_priv->madv != I915_MADV_WILLNEED) {
+ if (obj->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to pin a purgeable buffer\n");
ret = -EINVAL;
goto out;
}
- if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
+ if (obj->pin_filp != NULL && obj->pin_filp != file) {
DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
args->handle);
ret = -EINVAL;
goto out;
}
- obj_priv->user_pin_count++;
- obj_priv->pin_filp = file_priv;
- if (obj_priv->user_pin_count == 1) {
- ret = i915_gem_object_pin(obj, args->alignment);
+ obj->user_pin_count++;
+ obj->pin_filp = file;
+ if (obj->user_pin_count == 1) {
+ ret = i915_gem_object_pin(obj, args->alignment, true);
if (ret)
goto out;
}
@@ -4144,9 +3350,9 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
* as the X server doesn't manage domains yet
*/
i915_gem_object_flush_cpu_write_domain(obj);
- args->offset = obj_priv->gtt_offset;
+ args->offset = obj->gtt_offset;
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -4154,38 +3360,36 @@ unlock:
int
i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_pin *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
- if (obj_priv->pin_filp != file_priv) {
+ if (obj->pin_filp != file) {
DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
args->handle);
ret = -EINVAL;
goto out;
}
- obj_priv->user_pin_count--;
- if (obj_priv->user_pin_count == 0) {
- obj_priv->pin_filp = NULL;
+ obj->user_pin_count--;
+ if (obj->user_pin_count == 0) {
+ obj->pin_filp = NULL;
i915_gem_object_unpin(obj);
}
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -4193,52 +3397,64 @@ unlock:
int
i915_gem_busy_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_busy *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
/* Count all active objects as busy, even if they are currently not used
* by the gpu. Users of this interface expect objects to eventually
* become non-busy without any further actions, therefore emit any
* necessary flushes here.
*/
- args->busy = obj_priv->active;
+ args->busy = obj->active;
if (args->busy) {
/* Unconditionally flush objects, even when the gpu still uses this
* object. Userspace calling this function indicates that it wants to
* use this buffer rather sooner than later, so issuing the required
* flush earlier is beneficial.
*/
- if (obj->write_domain & I915_GEM_GPU_DOMAINS)
- i915_gem_flush_ring(dev, file_priv,
- obj_priv->ring,
- 0, obj->write_domain);
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(dev, obj->ring,
+ 0, obj->base.write_domain);
+ } else if (obj->ring->outstanding_lazy_request ==
+ obj->last_rendering_seqno) {
+ struct drm_i915_gem_request *request;
+
+ /* This ring is not being cleared by active usage,
+ * so emit a request to do so.
+ */
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request)
+ ret = i915_add_request(dev,
+ NULL, request,
+ obj->ring);
+ else
+ ret = -ENOMEM;
+ }
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs
* are actually unmasked, and our working set ends up being
* larger than required.
*/
- i915_gem_retire_requests_ring(dev, obj_priv->ring);
+ i915_gem_retire_requests_ring(dev, obj->ring);
- args->busy = obj_priv->active;
+ args->busy = obj->active;
}
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -4256,8 +3472,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_i915_gem_madvise *args = data;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
switch (args->madv) {
@@ -4272,37 +3487,36 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file_priv, args->handle));
if (obj == NULL) {
ret = -ENOENT;
goto unlock;
}
- obj_priv = to_intel_bo(obj);
- if (obj_priv->pin_count) {
+ if (obj->pin_count) {
ret = -EINVAL;
goto out;
}
- if (obj_priv->madv != __I915_MADV_PURGED)
- obj_priv->madv = args->madv;
+ if (obj->madv != __I915_MADV_PURGED)
+ obj->madv = args->madv;
/* if the object is no longer bound, discard its backing storage */
- if (i915_gem_object_is_purgeable(obj_priv) &&
- obj_priv->gtt_space == NULL)
+ if (i915_gem_object_is_purgeable(obj) &&
+ obj->gtt_space == NULL)
i915_gem_object_truncate(obj);
- args->retained = obj_priv->madv != __I915_MADV_PURGED;
+ args->retained = obj->madv != __I915_MADV_PURGED;
out:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
-struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
- size_t size)
+struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
+ size_t size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
@@ -4325,11 +3539,15 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
obj->base.driver_private = NULL;
obj->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj->mm_list);
+ INIT_LIST_HEAD(&obj->gtt_list);
INIT_LIST_HEAD(&obj->ring_list);
+ INIT_LIST_HEAD(&obj->exec_list);
INIT_LIST_HEAD(&obj->gpu_write_list);
obj->madv = I915_MADV_WILLNEED;
+ /* Avoid an unnecessary call to unbind on the first bind. */
+ obj->map_and_fenceable = true;
- return &obj->base;
+ return obj;
}
int i915_gem_init_object(struct drm_gem_object *obj)
@@ -4339,42 +3557,41 @@ int i915_gem_init_object(struct drm_gem_object *obj)
return 0;
}
-static void i915_gem_free_object_tail(struct drm_gem_object *obj)
+static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
ret = i915_gem_object_unbind(obj);
if (ret == -ERESTARTSYS) {
- list_move(&obj_priv->mm_list,
+ list_move(&obj->mm_list,
&dev_priv->mm.deferred_free_list);
return;
}
- if (obj_priv->mmap_offset)
+ if (obj->base.map_list.map)
i915_gem_free_mmap_offset(obj);
- drm_gem_object_release(obj);
- i915_gem_info_remove_obj(dev_priv, obj->size);
+ drm_gem_object_release(&obj->base);
+ i915_gem_info_remove_obj(dev_priv, obj->base.size);
- kfree(obj_priv->page_cpu_valid);
- kfree(obj_priv->bit_17);
- kfree(obj_priv);
+ kfree(obj->page_cpu_valid);
+ kfree(obj->bit_17);
+ kfree(obj);
}
-void i915_gem_free_object(struct drm_gem_object *obj)
+void i915_gem_free_object(struct drm_gem_object *gem_obj)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+ struct drm_device *dev = obj->base.dev;
trace_i915_gem_object_destroy(obj);
- while (obj_priv->pin_count > 0)
+ while (obj->pin_count > 0)
i915_gem_object_unpin(obj);
- if (obj_priv->phys_obj)
+ if (obj->phys_obj)
i915_gem_detach_phys_object(dev, obj);
i915_gem_free_object_tail(obj);
@@ -4401,13 +3618,15 @@ i915_gem_idle(struct drm_device *dev)
/* Under UMS, be paranoid and evict. */
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = i915_gem_evict_inactive(dev);
+ ret = i915_gem_evict_inactive(dev, false);
if (ret) {
mutex_unlock(&dev->struct_mutex);
return ret;
}
}
+ i915_gem_reset_fences(dev);
+
/* Hack! Don't let anybody do execbuf while we don't control the chip.
* We need to replace this with a semaphore, or something.
* And not confound mm.suspended!
@@ -4426,82 +3645,15 @@ i915_gem_idle(struct drm_device *dev)
return 0;
}
-/*
- * 965+ support PIPE_CONTROL commands, which provide finer grained control
- * over cache flushing.
- */
-static int
-i915_gem_init_pipe_control(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
- int ret;
-
- obj = i915_gem_alloc_object(dev, 4096);
- if (obj == NULL) {
- DRM_ERROR("Failed to allocate seqno page\n");
- ret = -ENOMEM;
- goto err;
- }
- obj_priv = to_intel_bo(obj);
- obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
-
- ret = i915_gem_object_pin(obj, 4096);
- if (ret)
- goto err_unref;
-
- dev_priv->seqno_gfx_addr = obj_priv->gtt_offset;
- dev_priv->seqno_page = kmap(obj_priv->pages[0]);
- if (dev_priv->seqno_page == NULL)
- goto err_unpin;
-
- dev_priv->seqno_obj = obj;
- memset(dev_priv->seqno_page, 0, PAGE_SIZE);
-
- return 0;
-
-err_unpin:
- i915_gem_object_unpin(obj);
-err_unref:
- drm_gem_object_unreference(obj);
-err:
- return ret;
-}
-
-
-static void
-i915_gem_cleanup_pipe_control(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
-
- obj = dev_priv->seqno_obj;
- obj_priv = to_intel_bo(obj);
- kunmap(obj_priv->pages[0]);
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- dev_priv->seqno_obj = NULL;
-
- dev_priv->seqno_page = NULL;
-}
-
int
i915_gem_init_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
- if (HAS_PIPE_CONTROL(dev)) {
- ret = i915_gem_init_pipe_control(dev);
- if (ret)
- return ret;
- }
-
ret = intel_init_render_ring_buffer(dev);
if (ret)
- goto cleanup_pipe_control;
+ return ret;
if (HAS_BSD(dev)) {
ret = intel_init_bsd_ring_buffer(dev);
@@ -4520,12 +3672,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
return 0;
cleanup_bsd_ring:
- intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ intel_cleanup_ring_buffer(&dev_priv->ring[VCS]);
cleanup_render_ring:
- intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-cleanup_pipe_control:
- if (HAS_PIPE_CONTROL(dev))
- i915_gem_cleanup_pipe_control(dev);
+ intel_cleanup_ring_buffer(&dev_priv->ring[RCS]);
return ret;
}
@@ -4533,12 +3682,10 @@ void
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
- intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
- intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
- intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
- if (HAS_PIPE_CONTROL(dev))
- i915_gem_cleanup_pipe_control(dev);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ intel_cleanup_ring_buffer(&dev_priv->ring[i]);
}
int
@@ -4546,7 +3693,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
+ int ret, i;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
@@ -4566,14 +3713,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
}
BUG_ON(!list_empty(&dev_priv->mm.active_list));
- BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
- BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list));
- BUG_ON(!list_empty(&dev_priv->blt_ring.active_list));
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
- BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
- BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list));
- BUG_ON(!list_empty(&dev_priv->blt_ring.request_list));
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ BUG_ON(!list_empty(&dev_priv->ring[i].active_list));
+ BUG_ON(!list_empty(&dev_priv->ring[i].request_list));
+ }
mutex_unlock(&dev->struct_mutex);
ret = drm_irq_install(dev);
@@ -4635,17 +3780,14 @@ i915_gem_load(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
- init_ring_lists(&dev_priv->render_ring);
- init_ring_lists(&dev_priv->bsd_ring);
- init_ring_lists(&dev_priv->blt_ring);
+ INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ init_ring_lists(&dev_priv->ring[i]);
for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
i915_gem_retire_work_handler);
init_completion(&dev_priv->error_completion);
- spin_lock(&shrink_list_lock);
- list_add(&dev_priv->mm.shrink_list, &shrink_list);
- spin_unlock(&shrink_list_lock);
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
if (IS_GEN3(dev)) {
@@ -4657,6 +3799,8 @@ i915_gem_load(struct drm_device *dev)
}
}
+ dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
+
/* Old X drivers will take 0-2 for front, back, depth buffers */
if (!drm_core_check_feature(dev, DRIVER_MODESET))
dev_priv->fence_reg_start = 3;
@@ -4688,6 +3832,10 @@ i915_gem_load(struct drm_device *dev)
}
i915_gem_detect_bit_6_swizzle(dev);
init_waitqueue_head(&dev_priv->pending_flip_queue);
+
+ dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink;
+ dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS;
+ register_shrinker(&dev_priv->mm.inactive_shrinker);
}
/*
@@ -4757,47 +3905,47 @@ void i915_gem_free_all_phys_object(struct drm_device *dev)
}
void i915_gem_detach_phys_object(struct drm_device *dev,
- struct drm_gem_object *obj)
+ struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv;
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+ char *vaddr;
int i;
- int ret;
int page_count;
- obj_priv = to_intel_bo(obj);
- if (!obj_priv->phys_obj)
+ if (!obj->phys_obj)
return;
+ vaddr = obj->phys_obj->handle->vaddr;
- ret = i915_gem_object_get_pages(obj, 0);
- if (ret)
- goto out;
-
- page_count = obj->size / PAGE_SIZE;
-
+ page_count = obj->base.size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
- char *dst = kmap_atomic(obj_priv->pages[i]);
- char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
-
- memcpy(dst, src, PAGE_SIZE);
- kunmap_atomic(dst);
+ struct page *page = read_cache_page_gfp(mapping, i,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (!IS_ERR(page)) {
+ char *dst = kmap_atomic(page);
+ memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE);
+ kunmap_atomic(dst);
+
+ drm_clflush_pages(&page, 1);
+
+ set_page_dirty(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+ }
}
- drm_clflush_pages(obj_priv->pages, page_count);
- drm_agp_chipset_flush(dev);
+ intel_gtt_chipset_flush();
- i915_gem_object_put_pages(obj);
-out:
- obj_priv->phys_obj->cur_obj = NULL;
- obj_priv->phys_obj = NULL;
+ obj->phys_obj->cur_obj = NULL;
+ obj->phys_obj = NULL;
}
int
i915_gem_attach_phys_object(struct drm_device *dev,
- struct drm_gem_object *obj,
+ struct drm_i915_gem_object *obj,
int id,
int align)
{
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
int ret = 0;
int page_count;
int i;
@@ -4805,10 +3953,8 @@ i915_gem_attach_phys_object(struct drm_device *dev,
if (id > I915_MAX_PHYS_OBJECT)
return -EINVAL;
- obj_priv = to_intel_bo(obj);
-
- if (obj_priv->phys_obj) {
- if (obj_priv->phys_obj->id == id)
+ if (obj->phys_obj) {
+ if (obj->phys_obj->id == id)
return 0;
i915_gem_detach_phys_object(dev, obj);
}
@@ -4816,59 +3962,65 @@ i915_gem_attach_phys_object(struct drm_device *dev,
/* create a new object */
if (!dev_priv->mm.phys_objs[id - 1]) {
ret = i915_gem_init_phys_object(dev, id,
- obj->size, align);
+ obj->base.size, align);
if (ret) {
- DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size);
- goto out;
+ DRM_ERROR("failed to init phys object %d size: %zu\n",
+ id, obj->base.size);
+ return ret;
}
}
/* bind to the object */
- obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
- obj_priv->phys_obj->cur_obj = obj;
+ obj->phys_obj = dev_priv->mm.phys_objs[id - 1];
+ obj->phys_obj->cur_obj = obj;
- ret = i915_gem_object_get_pages(obj, 0);
- if (ret) {
- DRM_ERROR("failed to get page list\n");
- goto out;
- }
-
- page_count = obj->size / PAGE_SIZE;
+ page_count = obj->base.size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
- char *src = kmap_atomic(obj_priv->pages[i]);
- char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+ struct page *page;
+ char *dst, *src;
+
+ page = read_cache_page_gfp(mapping, i,
+ GFP_HIGHUSER | __GFP_RECLAIMABLE);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+ src = kmap_atomic(page);
+ dst = obj->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
kunmap_atomic(src);
- }
- i915_gem_object_put_pages(obj);
+ mark_page_accessed(page);
+ page_cache_release(page);
+ }
return 0;
-out:
- return ret;
}
static int
-i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+i915_gem_phys_pwrite(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- void *obj_addr;
- int ret;
- char __user *user_data;
+ void *vaddr = obj->phys_obj->handle->vaddr + args->offset;
+ char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
- user_data = (char __user *) (uintptr_t) args->data_ptr;
- obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+ if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
+ unsigned long unwritten;
- DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size);
- ret = copy_from_user(obj_addr, user_data, args->size);
- if (ret)
- return -EFAULT;
+ /* The physical object once assigned is fixed for the lifetime
+ * of the obj, so we can safely drop the lock and continue
+ * to access vaddr.
+ */
+ mutex_unlock(&dev->struct_mutex);
+ unwritten = copy_from_user(vaddr, user_data, args->size);
+ mutex_lock(&dev->struct_mutex);
+ if (unwritten)
+ return -EFAULT;
+ }
- drm_agp_chipset_flush(dev);
+ intel_gtt_chipset_flush();
return 0;
}
@@ -4900,152 +4052,74 @@ i915_gpu_is_active(struct drm_device *dev)
int lists_empty;
lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list) &&
- list_empty(&dev_priv->bsd_ring.active_list) &&
- list_empty(&dev_priv->blt_ring.active_list);
+ list_empty(&dev_priv->mm.active_list);
return !lists_empty;
}
static int
-i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+i915_gem_inactive_shrink(struct shrinker *shrinker,
+ int nr_to_scan,
+ gfp_t gfp_mask)
{
- drm_i915_private_t *dev_priv, *next_dev;
- struct drm_i915_gem_object *obj_priv, *next_obj;
- int cnt = 0;
- int would_deadlock = 1;
+ struct drm_i915_private *dev_priv =
+ container_of(shrinker,
+ struct drm_i915_private,
+ mm.inactive_shrinker);
+ struct drm_device *dev = dev_priv->dev;
+ struct drm_i915_gem_object *obj, *next;
+ int cnt;
+
+ if (!mutex_trylock(&dev->struct_mutex))
+ return 0;
/* "fast-path" to count number of available objects */
if (nr_to_scan == 0) {
- spin_lock(&shrink_list_lock);
- list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) {
- struct drm_device *dev = dev_priv->dev;
-
- if (mutex_trylock(&dev->struct_mutex)) {
- list_for_each_entry(obj_priv,
- &dev_priv->mm.inactive_list,
- mm_list)
- cnt++;
- mutex_unlock(&dev->struct_mutex);
- }
- }
- spin_unlock(&shrink_list_lock);
-
- return (cnt / 100) * sysctl_vfs_cache_pressure;
+ cnt = 0;
+ list_for_each_entry(obj,
+ &dev_priv->mm.inactive_list,
+ mm_list)
+ cnt++;
+ mutex_unlock(&dev->struct_mutex);
+ return cnt / 100 * sysctl_vfs_cache_pressure;
}
- spin_lock(&shrink_list_lock);
-
rescan:
/* first scan for clean buffers */
- list_for_each_entry_safe(dev_priv, next_dev,
- &shrink_list, mm.shrink_list) {
- struct drm_device *dev = dev_priv->dev;
-
- if (! mutex_trylock(&dev->struct_mutex))
- continue;
-
- spin_unlock(&shrink_list_lock);
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev);
- list_for_each_entry_safe(obj_priv, next_obj,
- &dev_priv->mm.inactive_list,
- mm_list) {
- if (i915_gem_object_is_purgeable(obj_priv)) {
- i915_gem_object_unbind(&obj_priv->base);
- if (--nr_to_scan <= 0)
- break;
- }
+ list_for_each_entry_safe(obj, next,
+ &dev_priv->mm.inactive_list,
+ mm_list) {
+ if (i915_gem_object_is_purgeable(obj)) {
+ if (i915_gem_object_unbind(obj) == 0 &&
+ --nr_to_scan == 0)
+ break;
}
-
- spin_lock(&shrink_list_lock);
- mutex_unlock(&dev->struct_mutex);
-
- would_deadlock = 0;
-
- if (nr_to_scan <= 0)
- break;
}
/* second pass, evict/count anything still on the inactive list */
- list_for_each_entry_safe(dev_priv, next_dev,
- &shrink_list, mm.shrink_list) {
- struct drm_device *dev = dev_priv->dev;
-
- if (! mutex_trylock(&dev->struct_mutex))
- continue;
-
- spin_unlock(&shrink_list_lock);
-
- list_for_each_entry_safe(obj_priv, next_obj,
- &dev_priv->mm.inactive_list,
- mm_list) {
- if (nr_to_scan > 0) {
- i915_gem_object_unbind(&obj_priv->base);
- nr_to_scan--;
- } else
- cnt++;
- }
-
- spin_lock(&shrink_list_lock);
- mutex_unlock(&dev->struct_mutex);
-
- would_deadlock = 0;
+ cnt = 0;
+ list_for_each_entry_safe(obj, next,
+ &dev_priv->mm.inactive_list,
+ mm_list) {
+ if (nr_to_scan &&
+ i915_gem_object_unbind(obj) == 0)
+ nr_to_scan--;
+ else
+ cnt++;
}
- if (nr_to_scan) {
- int active = 0;
-
+ if (nr_to_scan && i915_gpu_is_active(dev)) {
/*
* We are desperate for pages, so as a last resort, wait
* for the GPU to finish and discard whatever we can.
* This has a dramatic impact to reduce the number of
* OOM-killer events whilst running the GPU aggressively.
*/
- list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) {
- struct drm_device *dev = dev_priv->dev;
-
- if (!mutex_trylock(&dev->struct_mutex))
- continue;
-
- spin_unlock(&shrink_list_lock);
-
- if (i915_gpu_is_active(dev)) {
- i915_gpu_idle(dev);
- active++;
- }
-
- spin_lock(&shrink_list_lock);
- mutex_unlock(&dev->struct_mutex);
- }
-
- if (active)
+ if (i915_gpu_idle(dev) == 0)
goto rescan;
}
-
- spin_unlock(&shrink_list_lock);
-
- if (would_deadlock)
- return -1;
- else if (cnt > 0)
- return (cnt / 100) * sysctl_vfs_cache_pressure;
- else
- return 0;
-}
-
-static struct shrinker shrinker = {
- .shrink = i915_gem_shrink,
- .seeks = DEFAULT_SEEKS,
-};
-
-__init void
-i915_gem_shrinker_init(void)
-{
- register_shrinker(&shrinker);
-}
-
-__exit void
-i915_gem_shrinker_exit(void)
-{
- unregister_shrinker(&shrinker);
+ mutex_unlock(&dev->struct_mutex);
+ return cnt / 100 * sysctl_vfs_cache_pressure;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index 48644b840a8d..29d014c48ca2 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -152,13 +152,12 @@ i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
}
void
-i915_gem_dump_object(struct drm_gem_object *obj, int len,
+i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
const char *where, uint32_t mark)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page;
- DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
+ DRM_INFO("%s: object at offset %08x\n", where, obj->gtt_offset);
for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) {
int page_len, chunk, chunk_len;
@@ -170,9 +169,9 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
chunk_len = page_len - chunk;
if (chunk_len > 128)
chunk_len = 128;
- i915_gem_dump_page(obj_priv->pages[page],
+ i915_gem_dump_page(obj->pages[page],
chunk, chunk + chunk_len,
- obj_priv->gtt_offset +
+ obj->gtt_offset +
page * PAGE_SIZE,
mark);
}
@@ -182,21 +181,19 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
#if WATCH_COHERENCY
void
-i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
+i915_gem_object_check_coherency(struct drm_i915_gem_object *obj, int handle)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_device *dev = obj->base.dev;
int page;
uint32_t *gtt_mapping;
uint32_t *backing_map = NULL;
int bad_count = 0;
DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n",
- __func__, obj, obj_priv->gtt_offset, handle,
+ __func__, obj, obj->gtt_offset, handle,
obj->size / 1024);
- gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset,
- obj->size);
+ gtt_mapping = ioremap(dev->agp->base + obj->gtt_offset, obj->base.size);
if (gtt_mapping == NULL) {
DRM_ERROR("failed to map GTT space\n");
return;
@@ -205,7 +202,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
for (page = 0; page < obj->size / PAGE_SIZE; page++) {
int i;
- backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0);
+ backing_map = kmap_atomic(obj->pages[page], KM_USER0);
if (backing_map == NULL) {
DRM_ERROR("failed to map backing page\n");
@@ -220,7 +217,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
if (cpuval != gttval) {
DRM_INFO("incoherent CPU vs GPU at 0x%08x: "
"0x%08x vs 0x%08x\n",
- (int)(obj_priv->gtt_offset +
+ (int)(obj->gtt_offset +
page * PAGE_SIZE + i * 4),
cpuval, gttval);
if (bad_count++ >= 8) {
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 43a4013f53fa..3d39005540aa 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -32,28 +32,36 @@
#include "i915_drm.h"
static bool
-mark_free(struct drm_i915_gem_object *obj_priv,
- struct list_head *unwind)
+mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
{
- list_add(&obj_priv->evict_list, unwind);
- drm_gem_object_reference(&obj_priv->base);
- return drm_mm_scan_add_block(obj_priv->gtt_space);
+ list_add(&obj->exec_list, unwind);
+ drm_gem_object_reference(&obj->base);
+ return drm_mm_scan_add_block(obj->gtt_space);
}
int
-i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
+i915_gem_evict_something(struct drm_device *dev, int min_size,
+ unsigned alignment, bool mappable)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret = 0;
i915_gem_retire_requests(dev);
/* Re-check for free space after retiring requests */
- if (drm_mm_search_free(&dev_priv->mm.gtt_space,
- min_size, alignment, 0))
- return 0;
+ if (mappable) {
+ if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
+ min_size, alignment, 0,
+ dev_priv->mm.gtt_mappable_end,
+ 0))
+ return 0;
+ } else {
+ if (drm_mm_search_free(&dev_priv->mm.gtt_space,
+ min_size, alignment, 0))
+ return 0;
+ }
/*
* The goal is to evict objects and amalgamate space in LRU order.
@@ -79,45 +87,56 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
*/
INIT_LIST_HEAD(&unwind_list);
- drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
+ if (mappable)
+ drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size,
+ alignment, 0,
+ dev_priv->mm.gtt_mappable_end);
+ else
+ drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
/* First see if there is a large enough contiguous idle region... */
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
- if (mark_free(obj_priv, &unwind_list))
+ list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
+ if (mark_free(obj, &unwind_list))
goto found;
}
/* Now merge in the soon-to-be-expired objects... */
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
/* Does the object require an outstanding flush? */
- if (obj_priv->base.write_domain || obj_priv->pin_count)
+ if (obj->base.write_domain || obj->pin_count)
continue;
- if (mark_free(obj_priv, &unwind_list))
+ if (mark_free(obj, &unwind_list))
goto found;
}
/* Finally add anything with a pending flush (in order of retirement) */
- list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
- if (obj_priv->pin_count)
+ list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
+ if (obj->pin_count)
continue;
- if (mark_free(obj_priv, &unwind_list))
+ if (mark_free(obj, &unwind_list))
goto found;
}
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
- if (! obj_priv->base.write_domain || obj_priv->pin_count)
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+ if (! obj->base.write_domain || obj->pin_count)
continue;
- if (mark_free(obj_priv, &unwind_list))
+ if (mark_free(obj, &unwind_list))
goto found;
}
/* Nothing found, clean up and bail out! */
- list_for_each_entry(obj_priv, &unwind_list, evict_list) {
- ret = drm_mm_scan_remove_block(obj_priv->gtt_space);
+ while (!list_empty(&unwind_list)) {
+ obj = list_first_entry(&unwind_list,
+ struct drm_i915_gem_object,
+ exec_list);
+
+ ret = drm_mm_scan_remove_block(obj->gtt_space);
BUG_ON(ret);
- drm_gem_object_unreference(&obj_priv->base);
+
+ list_del_init(&obj->exec_list);
+ drm_gem_object_unreference(&obj->base);
}
/* We expect the caller to unpin, evict all and try again, or give up.
@@ -131,33 +150,34 @@ found:
* temporary list. */
INIT_LIST_HEAD(&eviction_list);
while (!list_empty(&unwind_list)) {
- obj_priv = list_first_entry(&unwind_list,
- struct drm_i915_gem_object,
- evict_list);
- if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
- list_move(&obj_priv->evict_list, &eviction_list);
+ obj = list_first_entry(&unwind_list,
+ struct drm_i915_gem_object,
+ exec_list);
+ if (drm_mm_scan_remove_block(obj->gtt_space)) {
+ list_move(&obj->exec_list, &eviction_list);
continue;
}
- list_del(&obj_priv->evict_list);
- drm_gem_object_unreference(&obj_priv->base);
+ list_del_init(&obj->exec_list);
+ drm_gem_object_unreference(&obj->base);
}
/* Unbinding will emit any required flushes */
while (!list_empty(&eviction_list)) {
- obj_priv = list_first_entry(&eviction_list,
- struct drm_i915_gem_object,
- evict_list);
+ obj = list_first_entry(&eviction_list,
+ struct drm_i915_gem_object,
+ exec_list);
if (ret == 0)
- ret = i915_gem_object_unbind(&obj_priv->base);
- list_del(&obj_priv->evict_list);
- drm_gem_object_unreference(&obj_priv->base);
+ ret = i915_gem_object_unbind(obj);
+
+ list_del_init(&obj->exec_list);
+ drm_gem_object_unreference(&obj->base);
}
return ret;
}
int
-i915_gem_evict_everything(struct drm_device *dev)
+i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
@@ -165,9 +185,7 @@ i915_gem_evict_everything(struct drm_device *dev)
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list) &&
- list_empty(&dev_priv->bsd_ring.active_list) &&
- list_empty(&dev_priv->blt_ring.active_list));
+ list_empty(&dev_priv->mm.active_list));
if (lists_empty)
return -ENOSPC;
@@ -178,38 +196,22 @@ i915_gem_evict_everything(struct drm_device *dev)
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
- ret = i915_gem_evict_inactive(dev);
- if (ret)
- return ret;
-
- lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
- list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list) &&
- list_empty(&dev_priv->bsd_ring.active_list) &&
- list_empty(&dev_priv->blt_ring.active_list));
- BUG_ON(!lists_empty);
-
- return 0;
+ return i915_gem_evict_inactive(dev, purgeable_only);
}
/** Unbinds all inactive objects. */
int
-i915_gem_evict_inactive(struct drm_device *dev)
+i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only)
{
drm_i915_private_t *dev_priv = dev->dev_private;
-
- while (!list_empty(&dev_priv->mm.inactive_list)) {
- struct drm_gem_object *obj;
- int ret;
-
- obj = &list_first_entry(&dev_priv->mm.inactive_list,
- struct drm_i915_gem_object,
- mm_list)->base;
-
- ret = i915_gem_object_unbind(obj);
- if (ret != 0) {
- DRM_ERROR("Error unbinding object: %d\n", ret);
- return ret;
+ struct drm_i915_gem_object *obj, *next;
+
+ list_for_each_entry_safe(obj, next,
+ &dev_priv->mm.inactive_list, mm_list) {
+ if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
+ int ret = i915_gem_object_unbind(obj);
+ if (ret)
+ return ret;
}
}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
new file mode 100644
index 000000000000..dcfdf4151b6d
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -0,0 +1,1377 @@
+/*
+ * Copyright © 2008,2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND 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.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "i915_trace.h"
+#include "intel_drv.h"
+
+struct change_domains {
+ uint32_t invalidate_domains;
+ uint32_t flush_domains;
+ uint32_t flush_rings;
+};
+
+/*
+ * Set the next domain for the specified object. This
+ * may not actually perform the necessary flushing/invaliding though,
+ * as that may want to be batched with other set_domain operations
+ *
+ * This is (we hope) the only really tricky part of gem. The goal
+ * is fairly simple -- track which caches hold bits of the object
+ * and make sure they remain coherent. A few concrete examples may
+ * help to explain how it works. For shorthand, we use the notation
+ * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
+ * a pair of read and write domain masks.
+ *
+ * Case 1: the batch buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Mapped to GTT
+ * 4. Read by GPU
+ * 5. Unmapped from GTT
+ * 6. Freed
+ *
+ * Let's take these a step at a time
+ *
+ * 1. Allocated
+ * Pages allocated from the kernel may still have
+ * cache contents, so we set them to (CPU, CPU) always.
+ * 2. Written by CPU (using pwrite)
+ * The pwrite function calls set_domain (CPU, CPU) and
+ * this function does nothing (as nothing changes)
+ * 3. Mapped by GTT
+ * This function asserts that the object is not
+ * currently in any GPU-based read or write domains
+ * 4. Read by GPU
+ * i915_gem_execbuffer calls set_domain (COMMAND, 0).
+ * As write_domain is zero, this function adds in the
+ * current read domains (CPU+COMMAND, 0).
+ * flush_domains is set to CPU.
+ * invalidate_domains is set to COMMAND
+ * clflush is run to get data out of the CPU caches
+ * then i915_dev_set_domain calls i915_gem_flush to
+ * emit an MI_FLUSH and drm_agp_chipset_flush
+ * 5. Unmapped from GTT
+ * i915_gem_object_unbind calls set_domain (CPU, CPU)
+ * flush_domains and invalidate_domains end up both zero
+ * so no flushing/invalidating happens
+ * 6. Freed
+ * yay, done
+ *
+ * Case 2: The shared render buffer
+ *
+ * 1. Allocated
+ * 2. Mapped to GTT
+ * 3. Read/written by GPU
+ * 4. set_domain to (CPU,CPU)
+ * 5. Read/written by CPU
+ * 6. Read/written by GPU
+ *
+ * 1. Allocated
+ * Same as last example, (CPU, CPU)
+ * 2. Mapped to GTT
+ * Nothing changes (assertions find that it is not in the GPU)
+ * 3. Read/written by GPU
+ * execbuffer calls set_domain (RENDER, RENDER)
+ * flush_domains gets CPU
+ * invalidate_domains gets GPU
+ * clflush (obj)
+ * MI_FLUSH and drm_agp_chipset_flush
+ * 4. set_domain (CPU, CPU)
+ * flush_domains gets GPU
+ * invalidate_domains gets CPU
+ * wait_rendering (obj) to make sure all drawing is complete.
+ * This will include an MI_FLUSH to get the data from GPU
+ * to memory
+ * clflush (obj) to invalidate the CPU cache
+ * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
+ * 5. Read/written by CPU
+ * cache lines are loaded and dirtied
+ * 6. Read written by GPU
+ * Same as last GPU access
+ *
+ * Case 3: The constant buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Read by GPU
+ * 4. Updated (written) by CPU again
+ * 5. Read by GPU
+ *
+ * 1. Allocated
+ * (CPU, CPU)
+ * 2. Written by CPU
+ * (CPU, CPU)
+ * 3. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ * 4. Updated (written) by CPU again
+ * (CPU, CPU)
+ * flush_domains = 0 (no previous write domain)
+ * invalidate_domains = 0 (no new read domains)
+ * 5. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ */
+static void
+i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring,
+ struct change_domains *cd)
+{
+ uint32_t invalidate_domains = 0, flush_domains = 0;
+
+ /*
+ * If the object isn't moving to a new write domain,
+ * let the object stay in multiple read domains
+ */
+ if (obj->base.pending_write_domain == 0)
+ obj->base.pending_read_domains |= obj->base.read_domains;
+
+ /*
+ * Flush the current write domain if
+ * the new read domains don't match. Invalidate
+ * any read domains which differ from the old
+ * write domain
+ */
+ if (obj->base.write_domain &&
+ (((obj->base.write_domain != obj->base.pending_read_domains ||
+ obj->ring != ring)) ||
+ (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) {
+ flush_domains |= obj->base.write_domain;
+ invalidate_domains |=
+ obj->base.pending_read_domains & ~obj->base.write_domain;
+ }
+ /*
+ * Invalidate any read caches which may have
+ * stale data. That is, any new read domains.
+ */
+ invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains;
+ if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
+ i915_gem_clflush_object(obj);
+
+ /* blow away mappings if mapped through GTT */
+ if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT)
+ i915_gem_release_mmap(obj);
+
+ /* The actual obj->write_domain will be updated with
+ * pending_write_domain after we emit the accumulated flush for all
+ * of our domain changes in execbuffers (which clears objects'
+ * write_domains). So if we have a current write domain that we
+ * aren't changing, set pending_write_domain to that.
+ */
+ if (flush_domains == 0 && obj->base.pending_write_domain == 0)
+ obj->base.pending_write_domain = obj->base.write_domain;
+
+ cd->invalidate_domains |= invalidate_domains;
+ cd->flush_domains |= flush_domains;
+ if (flush_domains & I915_GEM_GPU_DOMAINS)
+ cd->flush_rings |= obj->ring->id;
+ if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+ cd->flush_rings |= ring->id;
+}
+
+struct eb_objects {
+ int and;
+ struct hlist_head buckets[0];
+};
+
+static struct eb_objects *
+eb_create(int size)
+{
+ struct eb_objects *eb;
+ int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
+ while (count > size)
+ count >>= 1;
+ eb = kzalloc(count*sizeof(struct hlist_head) +
+ sizeof(struct eb_objects),
+ GFP_KERNEL);
+ if (eb == NULL)
+ return eb;
+
+ eb->and = count - 1;
+ return eb;
+}
+
+static void
+eb_reset(struct eb_objects *eb)
+{
+ memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head));
+}
+
+static void
+eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj)
+{
+ hlist_add_head(&obj->exec_node,
+ &eb->buckets[obj->exec_handle & eb->and]);
+}
+
+static struct drm_i915_gem_object *
+eb_get_object(struct eb_objects *eb, unsigned long handle)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct drm_i915_gem_object *obj;
+
+ head = &eb->buckets[handle & eb->and];
+ hlist_for_each(node, head) {
+ obj = hlist_entry(node, struct drm_i915_gem_object, exec_node);
+ if (obj->exec_handle == handle)
+ return obj;
+ }
+
+ return NULL;
+}
+
+static void
+eb_destroy(struct eb_objects *eb)
+{
+ kfree(eb);
+}
+
+static int
+i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
+ struct eb_objects *eb,
+ struct drm_i915_gem_relocation_entry *reloc)
+{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_gem_object *target_obj;
+ uint32_t target_offset;
+ int ret = -EINVAL;
+
+ /* we've already hold a reference to all valid objects */
+ target_obj = &eb_get_object(eb, reloc->target_handle)->base;
+ if (unlikely(target_obj == NULL))
+ return -ENOENT;
+
+ target_offset = to_intel_bo(target_obj)->gtt_offset;
+
+#if WATCH_RELOC
+ DRM_INFO("%s: obj %p offset %08x target %d "
+ "read %08x write %08x gtt %08x "
+ "presumed %08x delta %08x\n",
+ __func__,
+ obj,
+ (int) reloc->offset,
+ (int) reloc->target_handle,
+ (int) reloc->read_domains,
+ (int) reloc->write_domain,
+ (int) target_offset,
+ (int) reloc->presumed_offset,
+ reloc->delta);
+#endif
+
+ /* The target buffer should have appeared before us in the
+ * exec_object list, so it should have a GTT space bound by now.
+ */
+ if (unlikely(target_offset == 0)) {
+ DRM_ERROR("No GTT space found for object %d\n",
+ reloc->target_handle);
+ return ret;
+ }
+
+ /* Validate that the target is in a valid r/w GPU domain */
+ if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
+ DRM_ERROR("reloc with multiple write domains: "
+ "obj %p target %d offset %d "
+ "read %08x write %08x",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->read_domains,
+ reloc->write_domain);
+ return ret;
+ }
+ if (unlikely((reloc->write_domain | reloc->read_domains) & I915_GEM_DOMAIN_CPU)) {
+ DRM_ERROR("reloc with read/write CPU domains: "
+ "obj %p target %d offset %d "
+ "read %08x write %08x",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->read_domains,
+ reloc->write_domain);
+ return ret;
+ }
+ if (unlikely(reloc->write_domain && target_obj->pending_write_domain &&
+ reloc->write_domain != target_obj->pending_write_domain)) {
+ DRM_ERROR("Write domain conflict: "
+ "obj %p target %d offset %d "
+ "new %08x old %08x\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->write_domain,
+ target_obj->pending_write_domain);
+ return ret;
+ }
+
+ target_obj->pending_read_domains |= reloc->read_domains;
+ target_obj->pending_write_domain |= reloc->write_domain;
+
+ /* If the relocation already has the right value in it, no
+ * more work needs to be done.
+ */
+ if (target_offset == reloc->presumed_offset)
+ return 0;
+
+ /* Check that the relocation address is valid... */
+ if (unlikely(reloc->offset > obj->base.size - 4)) {
+ DRM_ERROR("Relocation beyond object bounds: "
+ "obj %p target %d offset %d size %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ (int) obj->base.size);
+ return ret;
+ }
+ if (unlikely(reloc->offset & 3)) {
+ DRM_ERROR("Relocation not 4-byte aligned: "
+ "obj %p target %d offset %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->offset);
+ return ret;
+ }
+
+ /* and points to somewhere within the target object. */
+ if (unlikely(reloc->delta >= target_obj->size)) {
+ DRM_ERROR("Relocation beyond target object bounds: "
+ "obj %p target %d delta %d size %d.\n",
+ obj, reloc->target_handle,
+ (int) reloc->delta,
+ (int) target_obj->size);
+ return ret;
+ }
+
+ reloc->delta += target_offset;
+ if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+ uint32_t page_offset = reloc->offset & ~PAGE_MASK;
+ char *vaddr;
+
+ vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
+ *(uint32_t *)(vaddr + page_offset) = reloc->delta;
+ kunmap_atomic(vaddr);
+ } else {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t __iomem *reloc_entry;
+ void __iomem *reloc_page;
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ if (ret)
+ return ret;
+
+ /* Map the page containing the relocation we're going to perform. */
+ reloc->offset += obj->gtt_offset;
+ reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+ reloc->offset & PAGE_MASK);
+ reloc_entry = (uint32_t __iomem *)
+ (reloc_page + (reloc->offset & ~PAGE_MASK));
+ iowrite32(reloc->delta, reloc_entry);
+ io_mapping_unmap_atomic(reloc_page);
+ }
+
+ /* and update the user's relocation entry */
+ reloc->presumed_offset = target_offset;
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
+ struct eb_objects *eb)
+{
+ struct drm_i915_gem_relocation_entry __user *user_relocs;
+ struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ int i, ret;
+
+ user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+ for (i = 0; i < entry->relocation_count; i++) {
+ struct drm_i915_gem_relocation_entry reloc;
+
+ if (__copy_from_user_inatomic(&reloc,
+ user_relocs+i,
+ sizeof(reloc)))
+ return -EFAULT;
+
+ ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc);
+ if (ret)
+ return ret;
+
+ if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
+ &reloc.presumed_offset,
+ sizeof(reloc.presumed_offset)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
+ struct eb_objects *eb,
+ struct drm_i915_gem_relocation_entry *relocs)
+{
+ const struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ int i, ret;
+
+ for (i = 0; i < entry->relocation_count; i++) {
+ ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_relocate(struct drm_device *dev,
+ struct eb_objects *eb,
+ struct list_head *objects)
+{
+ struct drm_i915_gem_object *obj;
+ int ret;
+
+ list_for_each_entry(obj, objects, exec_list) {
+ ret = i915_gem_execbuffer_relocate_object(obj, eb);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ struct list_head *objects)
+{
+ struct drm_i915_gem_object *obj;
+ int ret, retry;
+ bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
+ struct list_head ordered_objects;
+
+ INIT_LIST_HEAD(&ordered_objects);
+ while (!list_empty(objects)) {
+ struct drm_i915_gem_exec_object2 *entry;
+ bool need_fence, need_mappable;
+
+ obj = list_first_entry(objects,
+ struct drm_i915_gem_object,
+ exec_list);
+ entry = obj->exec_entry;
+
+ need_fence =
+ has_fenced_gpu_access &&
+ entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode != I915_TILING_NONE;
+ need_mappable =
+ entry->relocation_count ? true : need_fence;
+
+ if (need_mappable)
+ list_move(&obj->exec_list, &ordered_objects);
+ else
+ list_move_tail(&obj->exec_list, &ordered_objects);
+
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
+ }
+ list_splice(&ordered_objects, objects);
+
+ /* Attempt to pin all of the buffers into the GTT.
+ * This is done in 3 phases:
+ *
+ * 1a. Unbind all objects that do not match the GTT constraints for
+ * the execbuffer (fenceable, mappable, alignment etc).
+ * 1b. Increment pin count for already bound objects.
+ * 2. Bind new objects.
+ * 3. Decrement pin count.
+ *
+ * This avoid unnecessary unbinding of later objects in order to makr
+ * room for the earlier objects *unless* we need to defragment.
+ */
+ retry = 0;
+ do {
+ ret = 0;
+
+ /* Unbind any ill-fitting objects or pin. */
+ list_for_each_entry(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ bool need_fence, need_mappable;
+ if (!obj->gtt_space)
+ continue;
+
+ need_fence =
+ has_fenced_gpu_access &&
+ entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode != I915_TILING_NONE;
+ need_mappable =
+ entry->relocation_count ? true : need_fence;
+
+ if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) ||
+ (need_mappable && !obj->map_and_fenceable))
+ ret = i915_gem_object_unbind(obj);
+ else
+ ret = i915_gem_object_pin(obj,
+ entry->alignment,
+ need_mappable);
+ if (ret)
+ goto err;
+
+ entry++;
+ }
+
+ /* Bind fresh objects */
+ list_for_each_entry(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ bool need_fence;
+
+ need_fence =
+ has_fenced_gpu_access &&
+ entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode != I915_TILING_NONE;
+
+ if (!obj->gtt_space) {
+ bool need_mappable =
+ entry->relocation_count ? true : need_fence;
+
+ ret = i915_gem_object_pin(obj,
+ entry->alignment,
+ need_mappable);
+ if (ret)
+ break;
+ }
+
+ if (has_fenced_gpu_access) {
+ if (need_fence) {
+ ret = i915_gem_object_get_fence(obj, ring, 1);
+ if (ret)
+ break;
+ } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode == I915_TILING_NONE) {
+ /* XXX pipelined! */
+ ret = i915_gem_object_put_fence(obj);
+ if (ret)
+ break;
+ }
+ obj->pending_fenced_gpu_access = need_fence;
+ }
+
+ entry->offset = obj->gtt_offset;
+ }
+
+ /* Decrement pin count for bound objects */
+ list_for_each_entry(obj, objects, exec_list) {
+ if (obj->gtt_space)
+ i915_gem_object_unpin(obj);
+ }
+
+ if (ret != -ENOSPC || retry > 1)
+ return ret;
+
+ /* First attempt, just clear anything that is purgeable.
+ * Second attempt, clear the entire GTT.
+ */
+ ret = i915_gem_evict_everything(ring->dev, retry == 0);
+ if (ret)
+ return ret;
+
+ retry++;
+ } while (1);
+
+err:
+ obj = list_entry(obj->exec_list.prev,
+ struct drm_i915_gem_object,
+ exec_list);
+ while (objects != &obj->exec_list) {
+ if (obj->gtt_space)
+ i915_gem_object_unpin(obj);
+
+ obj = list_entry(obj->exec_list.prev,
+ struct drm_i915_gem_object,
+ exec_list);
+ }
+
+ return ret;
+}
+
+static int
+i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
+ struct drm_file *file,
+ struct intel_ring_buffer *ring,
+ struct list_head *objects,
+ struct eb_objects *eb,
+ struct drm_i915_gem_exec_object2 *exec,
+ int count)
+{
+ struct drm_i915_gem_relocation_entry *reloc;
+ struct drm_i915_gem_object *obj;
+ int *reloc_offset;
+ int i, total, ret;
+
+ /* We may process another execbuffer during the unlock... */
+ while (!list_empty(objects)) {
+ obj = list_first_entry(objects,
+ struct drm_i915_gem_object,
+ exec_list);
+ list_del_init(&obj->exec_list);
+ drm_gem_object_unreference(&obj->base);
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ total += exec[i].relocation_count;
+
+ reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset));
+ reloc = drm_malloc_ab(total, sizeof(*reloc));
+ if (reloc == NULL || reloc_offset == NULL) {
+ drm_free_large(reloc);
+ drm_free_large(reloc_offset);
+ mutex_lock(&dev->struct_mutex);
+ return -ENOMEM;
+ }
+
+ total = 0;
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_relocation_entry __user *user_relocs;
+
+ user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr;
+
+ if (copy_from_user(reloc+total, user_relocs,
+ exec[i].relocation_count * sizeof(*reloc))) {
+ ret = -EFAULT;
+ mutex_lock(&dev->struct_mutex);
+ goto err;
+ }
+
+ reloc_offset[i] = total;
+ total += exec[i].relocation_count;
+ }
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret) {
+ mutex_lock(&dev->struct_mutex);
+ goto err;
+ }
+
+ /* reacquire the objects */
+ eb_reset(eb);
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_object *obj;
+
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file,
+ exec[i].handle));
+ if (obj == NULL) {
+ DRM_ERROR("Invalid object handle %d at index %d\n",
+ exec[i].handle, i);
+ ret = -ENOENT;
+ goto err;
+ }
+
+ list_add_tail(&obj->exec_list, objects);
+ obj->exec_handle = exec[i].handle;
+ obj->exec_entry = &exec[i];
+ eb_add_object(eb, obj);
+ }
+
+ ret = i915_gem_execbuffer_reserve(ring, file, objects);
+ if (ret)
+ goto err;
+
+ list_for_each_entry(obj, objects, exec_list) {
+ int offset = obj->exec_entry - exec;
+ ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
+ reloc + reloc_offset[offset]);
+ if (ret)
+ goto err;
+ }
+
+ /* Leave the user relocations as are, this is the painfully slow path,
+ * and we want to avoid the complication of dropping the lock whilst
+ * having buffers reserved in the aperture and so causing spurious
+ * ENOSPC for random operations.
+ */
+
+err:
+ drm_free_large(reloc);
+ drm_free_large(reloc_offset);
+ return ret;
+}
+
+static int
+i915_gem_execbuffer_flush(struct drm_device *dev,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains,
+ uint32_t flush_rings)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i, ret;
+
+ if (flush_domains & I915_GEM_DOMAIN_CPU)
+ intel_gtt_chipset_flush();
+
+ if (flush_domains & I915_GEM_DOMAIN_GTT)
+ wmb();
+
+ if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ if (flush_rings & (1 << i)) {
+ ret = i915_gem_flush_ring(dev,
+ &dev_priv->ring[i],
+ invalidate_domains,
+ flush_domains);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *to)
+{
+ struct intel_ring_buffer *from = obj->ring;
+ u32 seqno;
+ int ret, idx;
+
+ if (from == NULL || to == from)
+ return 0;
+
+ /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */
+ if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev))
+ return i915_gem_object_wait_rendering(obj, true);
+
+ idx = intel_ring_sync_index(from, to);
+
+ seqno = obj->last_rendering_seqno;
+ if (seqno <= from->sync_seqno[idx])
+ return 0;
+
+ if (seqno == from->outstanding_lazy_request) {
+ struct drm_i915_gem_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+
+ ret = i915_add_request(obj->base.dev, NULL, request, from);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+
+ seqno = request->seqno;
+ }
+
+ from->sync_seqno[idx] = seqno;
+ return intel_ring_sync(to, from, seqno - 1);
+}
+
+static int
+i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
+ struct list_head *objects)
+{
+ struct drm_i915_gem_object *obj;
+ struct change_domains cd;
+ int ret;
+
+ cd.invalidate_domains = 0;
+ cd.flush_domains = 0;
+ cd.flush_rings = 0;
+ list_for_each_entry(obj, objects, exec_list)
+ i915_gem_object_set_to_gpu_domain(obj, ring, &cd);
+
+ if (cd.invalidate_domains | cd.flush_domains) {
+#if WATCH_EXEC
+ DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
+ __func__,
+ cd.invalidate_domains,
+ cd.flush_domains);
+#endif
+ ret = i915_gem_execbuffer_flush(ring->dev,
+ cd.invalidate_domains,
+ cd.flush_domains,
+ cd.flush_rings);
+ if (ret)
+ return ret;
+ }
+
+ list_for_each_entry(obj, objects, exec_list) {
+ ret = i915_gem_execbuffer_sync_rings(obj, ring);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool
+i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
+{
+ return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0;
+}
+
+static int
+validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+ int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+ int length; /* limited by fault_in_pages_readable() */
+
+ /* First check for malicious input causing overflow */
+ if (exec[i].relocation_count >
+ INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
+ return -EINVAL;
+
+ length = exec[i].relocation_count *
+ sizeof(struct drm_i915_gem_relocation_entry);
+ if (!access_ok(VERIFY_READ, ptr, length))
+ return -EFAULT;
+
+ /* we may also need to update the presumed offsets */
+ if (!access_ok(VERIFY_WRITE, ptr, length))
+ return -EFAULT;
+
+ if (fault_in_pages_readable(ptr, length))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring,
+ struct list_head *objects)
+{
+ struct drm_i915_gem_object *obj;
+ int flips;
+
+ /* Check for any pending flips. As we only maintain a flip queue depth
+ * of 1, we can simply insert a WAIT for the next display flip prior
+ * to executing the batch and avoid stalling the CPU.
+ */
+ flips = 0;
+ list_for_each_entry(obj, objects, exec_list) {
+ if (obj->base.write_domain)
+ flips |= atomic_read(&obj->pending_flip);
+ }
+ if (flips) {
+ int plane, flip_mask, ret;
+
+ for (plane = 0; flips >> plane; plane++) {
+ if (((flips >> plane) & 1) == 0)
+ continue;
+
+ if (plane)
+ flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+ else
+ flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+ }
+ }
+
+ return 0;
+}
+
+static void
+i915_gem_execbuffer_move_to_active(struct list_head *objects,
+ struct intel_ring_buffer *ring,
+ u32 seqno)
+{
+ struct drm_i915_gem_object *obj;
+
+ list_for_each_entry(obj, objects, exec_list) {
+ obj->base.read_domains = obj->base.pending_read_domains;
+ obj->base.write_domain = obj->base.pending_write_domain;
+ obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
+
+ i915_gem_object_move_to_active(obj, ring, seqno);
+ if (obj->base.write_domain) {
+ obj->dirty = 1;
+ obj->pending_gpu_write = true;
+ list_move_tail(&obj->gpu_write_list,
+ &ring->gpu_write_list);
+ intel_mark_busy(ring->dev, obj);
+ }
+
+ trace_i915_gem_object_change_domain(obj,
+ obj->base.read_domains,
+ obj->base.write_domain);
+ }
+}
+
+static void
+i915_gem_execbuffer_retire_commands(struct drm_device *dev,
+ struct drm_file *file,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_gem_request *request;
+ u32 invalidate;
+
+ /*
+ * Ensure that the commands in the batch buffer are
+ * finished before the interrupt fires.
+ *
+ * The sampler always gets flushed on i965 (sigh).
+ */
+ invalidate = I915_GEM_DOMAIN_COMMAND;
+ if (INTEL_INFO(dev)->gen >= 4)
+ invalidate |= I915_GEM_DOMAIN_SAMPLER;
+ if (ring->flush(ring, invalidate, 0)) {
+ i915_gem_next_request_seqno(dev, ring);
+ return;
+ }
+
+ /* Add a breadcrumb for the completion of the batch buffer */
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL || i915_add_request(dev, file, request, ring)) {
+ i915_gem_next_request_seqno(dev, ring);
+ kfree(request);
+ }
+}
+
+static int
+i915_gem_do_execbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file,
+ struct drm_i915_gem_execbuffer2 *args,
+ struct drm_i915_gem_exec_object2 *exec)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct list_head objects;
+ struct eb_objects *eb;
+ struct drm_i915_gem_object *batch_obj;
+ struct drm_clip_rect *cliprects = NULL;
+ struct intel_ring_buffer *ring;
+ u32 exec_start, exec_len;
+ u32 seqno;
+ int ret, mode, i;
+
+ if (!i915_gem_check_execbuffer(args)) {
+ DRM_ERROR("execbuf with invalid offset/length\n");
+ return -EINVAL;
+ }
+
+ ret = validate_exec_list(exec, args->buffer_count);
+ if (ret)
+ return ret;
+
+#if WATCH_EXEC
+ DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
+ (int) args->buffers_ptr, args->buffer_count, args->batch_len);
+#endif
+ switch (args->flags & I915_EXEC_RING_MASK) {
+ case I915_EXEC_DEFAULT:
+ case I915_EXEC_RENDER:
+ ring = &dev_priv->ring[RCS];
+ break;
+ case I915_EXEC_BSD:
+ if (!HAS_BSD(dev)) {
+ DRM_ERROR("execbuf with invalid ring (BSD)\n");
+ return -EINVAL;
+ }
+ ring = &dev_priv->ring[VCS];
+ break;
+ case I915_EXEC_BLT:
+ if (!HAS_BLT(dev)) {
+ DRM_ERROR("execbuf with invalid ring (BLT)\n");
+ return -EINVAL;
+ }
+ ring = &dev_priv->ring[BCS];
+ break;
+ default:
+ DRM_ERROR("execbuf with unknown ring: %d\n",
+ (int)(args->flags & I915_EXEC_RING_MASK));
+ return -EINVAL;
+ }
+
+ mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+ switch (mode) {
+ case I915_EXEC_CONSTANTS_REL_GENERAL:
+ case I915_EXEC_CONSTANTS_ABSOLUTE:
+ case I915_EXEC_CONSTANTS_REL_SURFACE:
+ if (ring == &dev_priv->ring[RCS] &&
+ mode != dev_priv->relative_constants_mode) {
+ if (INTEL_INFO(dev)->gen < 4)
+ return -EINVAL;
+
+ if (INTEL_INFO(dev)->gen > 5 &&
+ mode == I915_EXEC_CONSTANTS_REL_SURFACE)
+ return -EINVAL;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(ring, INSTPM);
+ intel_ring_emit(ring,
+ I915_EXEC_CONSTANTS_MASK << 16 | mode);
+ intel_ring_advance(ring);
+
+ dev_priv->relative_constants_mode = mode;
+ }
+ break;
+ default:
+ DRM_ERROR("execbuf with unknown constants: %d\n", mode);
+ return -EINVAL;
+ }
+
+ if (args->buffer_count < 1) {
+ DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+ return -EINVAL;
+ }
+
+ if (args->num_cliprects != 0) {
+ if (ring != &dev_priv->ring[RCS]) {
+ DRM_ERROR("clip rectangles are only valid with the render ring\n");
+ return -EINVAL;
+ }
+
+ cliprects = kmalloc(args->num_cliprects * sizeof(*cliprects),
+ GFP_KERNEL);
+ if (cliprects == NULL) {
+ ret = -ENOMEM;
+ goto pre_mutex_err;
+ }
+
+ if (copy_from_user(cliprects,
+ (struct drm_clip_rect __user *)(uintptr_t)
+ args->cliprects_ptr,
+ sizeof(*cliprects)*args->num_cliprects)) {
+ ret = -EFAULT;
+ goto pre_mutex_err;
+ }
+ }
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ goto pre_mutex_err;
+
+ if (dev_priv->mm.suspended) {
+ mutex_unlock(&dev->struct_mutex);
+ ret = -EBUSY;
+ goto pre_mutex_err;
+ }
+
+ eb = eb_create(args->buffer_count);
+ if (eb == NULL) {
+ mutex_unlock(&dev->struct_mutex);
+ ret = -ENOMEM;
+ goto pre_mutex_err;
+ }
+
+ /* Look up object handles */
+ INIT_LIST_HEAD(&objects);
+ for (i = 0; i < args->buffer_count; i++) {
+ struct drm_i915_gem_object *obj;
+
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file,
+ exec[i].handle));
+ if (obj == NULL) {
+ DRM_ERROR("Invalid object handle %d at index %d\n",
+ exec[i].handle, i);
+ /* prevent error path from reading uninitialized data */
+ ret = -ENOENT;
+ goto err;
+ }
+
+ if (!list_empty(&obj->exec_list)) {
+ DRM_ERROR("Object %p [handle %d, index %d] appears more than once in object list\n",
+ obj, exec[i].handle, i);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ list_add_tail(&obj->exec_list, &objects);
+ obj->exec_handle = exec[i].handle;
+ obj->exec_entry = &exec[i];
+ eb_add_object(eb, obj);
+ }
+
+ /* take note of the batch buffer before we might reorder the lists */
+ batch_obj = list_entry(objects.prev,
+ struct drm_i915_gem_object,
+ exec_list);
+
+ /* Move the objects en-masse into the GTT, evicting if necessary. */
+ ret = i915_gem_execbuffer_reserve(ring, file, &objects);
+ if (ret)
+ goto err;
+
+ /* The objects are in their final locations, apply the relocations. */
+ ret = i915_gem_execbuffer_relocate(dev, eb, &objects);
+ if (ret) {
+ if (ret == -EFAULT) {
+ ret = i915_gem_execbuffer_relocate_slow(dev, file, ring,
+ &objects, eb,
+ exec,
+ args->buffer_count);
+ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+ }
+ if (ret)
+ goto err;
+ }
+
+ /* Set the pending read domains for the batch buffer to COMMAND */
+ if (batch_obj->base.pending_write_domain) {
+ DRM_ERROR("Attempting to use self-modifying batch buffer\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
+ ret = i915_gem_execbuffer_move_to_gpu(ring, &objects);
+ if (ret)
+ goto err;
+
+ ret = i915_gem_execbuffer_wait_for_flips(ring, &objects);
+ if (ret)
+ goto err;
+
+ seqno = i915_gem_next_request_seqno(dev, ring);
+ for (i = 0; i < I915_NUM_RINGS-1; i++) {
+ if (seqno < ring->sync_seqno[i]) {
+ /* The GPU can not handle its semaphore value wrapping,
+ * so every billion or so execbuffers, we need to stall
+ * the GPU in order to reset the counters.
+ */
+ ret = i915_gpu_idle(dev);
+ if (ret)
+ goto err;
+
+ BUG_ON(ring->sync_seqno[i]);
+ }
+ }
+
+ exec_start = batch_obj->gtt_offset + args->batch_start_offset;
+ exec_len = args->batch_len;
+ if (cliprects) {
+ for (i = 0; i < args->num_cliprects; i++) {
+ ret = i915_emit_box(dev, &cliprects[i],
+ args->DR1, args->DR4);
+ if (ret)
+ goto err;
+
+ ret = ring->dispatch_execbuffer(ring,
+ exec_start, exec_len);
+ if (ret)
+ goto err;
+ }
+ } else {
+ ret = ring->dispatch_execbuffer(ring, exec_start, exec_len);
+ if (ret)
+ goto err;
+ }
+
+ i915_gem_execbuffer_move_to_active(&objects, ring, seqno);
+ i915_gem_execbuffer_retire_commands(dev, file, ring);
+
+err:
+ eb_destroy(eb);
+ while (!list_empty(&objects)) {
+ struct drm_i915_gem_object *obj;
+
+ obj = list_first_entry(&objects,
+ struct drm_i915_gem_object,
+ exec_list);
+ list_del_init(&obj->exec_list);
+ drm_gem_object_unreference(&obj->base);
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+pre_mutex_err:
+ kfree(cliprects);
+ return ret;
+}
+
+/*
+ * Legacy execbuffer just creates an exec2 list from the original exec object
+ * list array and passes it to the real function.
+ */
+int
+i915_gem_execbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_i915_gem_execbuffer *args = data;
+ struct drm_i915_gem_execbuffer2 exec2;
+ struct drm_i915_gem_exec_object *exec_list = NULL;
+ struct drm_i915_gem_exec_object2 *exec2_list = NULL;
+ int ret, i;
+
+#if WATCH_EXEC
+ DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
+ (int) args->buffers_ptr, args->buffer_count, args->batch_len);
+#endif
+
+ if (args->buffer_count < 1) {
+ DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+ return -EINVAL;
+ }
+
+ /* Copy in the exec list from userland */
+ exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count);
+ exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
+ if (exec_list == NULL || exec2_list == NULL) {
+ DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+ args->buffer_count);
+ drm_free_large(exec_list);
+ drm_free_large(exec2_list);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(exec_list,
+ (struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ sizeof(*exec_list) * args->buffer_count);
+ if (ret != 0) {
+ DRM_ERROR("copy %d exec entries failed %d\n",
+ args->buffer_count, ret);
+ drm_free_large(exec_list);
+ drm_free_large(exec2_list);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < args->buffer_count; i++) {
+ exec2_list[i].handle = exec_list[i].handle;
+ exec2_list[i].relocation_count = exec_list[i].relocation_count;
+ exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
+ exec2_list[i].alignment = exec_list[i].alignment;
+ exec2_list[i].offset = exec_list[i].offset;
+ if (INTEL_INFO(dev)->gen < 4)
+ exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
+ else
+ exec2_list[i].flags = 0;
+ }
+
+ exec2.buffers_ptr = args->buffers_ptr;
+ exec2.buffer_count = args->buffer_count;
+ exec2.batch_start_offset = args->batch_start_offset;
+ exec2.batch_len = args->batch_len;
+ exec2.DR1 = args->DR1;
+ exec2.DR4 = args->DR4;
+ exec2.num_cliprects = args->num_cliprects;
+ exec2.cliprects_ptr = args->cliprects_ptr;
+ exec2.flags = I915_EXEC_RENDER;
+
+ ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
+ if (!ret) {
+ /* Copy the new buffer offsets back to the user's exec list. */
+ for (i = 0; i < args->buffer_count; i++)
+ exec_list[i].offset = exec2_list[i].offset;
+ /* ... and back out to userspace */
+ ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ exec_list,
+ sizeof(*exec_list) * args->buffer_count);
+ if (ret) {
+ ret = -EFAULT;
+ DRM_ERROR("failed to copy %d exec entries "
+ "back to user (%d)\n",
+ args->buffer_count, ret);
+ }
+ }
+
+ drm_free_large(exec_list);
+ drm_free_large(exec2_list);
+ return ret;
+}
+
+int
+i915_gem_execbuffer2(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_i915_gem_execbuffer2 *args = data;
+ struct drm_i915_gem_exec_object2 *exec2_list = NULL;
+ int ret;
+
+#if WATCH_EXEC
+ DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
+ (int) args->buffers_ptr, args->buffer_count, args->batch_len);
+#endif
+
+ if (args->buffer_count < 1) {
+ DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count);
+ return -EINVAL;
+ }
+
+ exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
+ if (exec2_list == NULL) {
+ DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+ args->buffer_count);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(exec2_list,
+ (struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ sizeof(*exec2_list) * args->buffer_count);
+ if (ret != 0) {
+ DRM_ERROR("copy %d exec entries failed %d\n",
+ args->buffer_count, ret);
+ drm_free_large(exec2_list);
+ return -EFAULT;
+ }
+
+ ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
+ if (!ret) {
+ /* Copy the new buffer offsets back to the user's exec list. */
+ ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
+ exec2_list,
+ sizeof(*exec2_list) * args->buffer_count);
+ if (ret) {
+ ret = -EFAULT;
+ DRM_ERROR("failed to copy %d exec entries "
+ "back to user (%d)\n",
+ args->buffer_count, ret);
+ }
+ }
+
+ drm_free_large(exec2_list);
+ return ret;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
new file mode 100644
index 000000000000..70433ae50ac8
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2010 Daniel Vetter
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND 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 "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "i915_trace.h"
+#include "intel_drv.h"
+
+void i915_gem_restore_gtt_mappings(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ i915_gem_clflush_object(obj);
+
+ if (dev_priv->mm.gtt->needs_dmar) {
+ BUG_ON(!obj->sg_list);
+
+ intel_gtt_insert_sg_entries(obj->sg_list,
+ obj->num_sg,
+ obj->gtt_space->start
+ >> PAGE_SHIFT,
+ obj->agp_type);
+ } else
+ intel_gtt_insert_pages(obj->gtt_space->start
+ >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT,
+ obj->pages,
+ obj->agp_type);
+ }
+
+ intel_gtt_chipset_flush();
+}
+
+int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (dev_priv->mm.gtt->needs_dmar) {
+ ret = intel_gtt_map_memory(obj->pages,
+ obj->base.size >> PAGE_SHIFT,
+ &obj->sg_list,
+ &obj->num_sg);
+ if (ret != 0)
+ return ret;
+
+ intel_gtt_insert_sg_entries(obj->sg_list,
+ obj->num_sg,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ obj->agp_type);
+ } else
+ intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT,
+ obj->pages,
+ obj->agp_type);
+
+ return 0;
+}
+
+void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
+{
+ intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT);
+
+ if (obj->sg_list) {
+ intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
+ obj->sg_list = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index af352de70be1..22a32b9932c5 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -181,7 +181,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
}
/* Check pitch constriants for all chips & tiling formats */
-bool
+static bool
i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
{
int tile_width;
@@ -232,32 +232,44 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
return true;
}
-bool
-i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
+/* Is the current GTT allocation valid for the change in tiling? */
+static bool
+i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
{
- struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-
- if (obj_priv->gtt_space == NULL)
- return true;
+ u32 size;
if (tiling_mode == I915_TILING_NONE)
return true;
- if (INTEL_INFO(dev)->gen >= 4)
+ if (INTEL_INFO(obj->base.dev)->gen >= 4)
return true;
- if (obj_priv->gtt_offset & (obj->size - 1))
- return false;
-
- if (IS_GEN3(dev)) {
- if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+ if (INTEL_INFO(obj->base.dev)->gen == 3) {
+ if (obj->gtt_offset & ~I915_FENCE_START_MASK)
return false;
} else {
- if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
+ if (obj->gtt_offset & ~I830_FENCE_START_MASK)
return false;
}
+ /*
+ * Previous chips need to be aligned to the size of the smallest
+ * fence register that can contain the object.
+ */
+ if (INTEL_INFO(obj->base.dev)->gen == 3)
+ size = 1024*1024;
+ else
+ size = 512*1024;
+
+ while (size < obj->base.size)
+ size <<= 1;
+
+ if (obj->gtt_space->size != size)
+ return false;
+
+ if (obj->gtt_offset & (size - 1))
+ return false;
+
return true;
}
@@ -267,30 +279,29 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
*/
int
i915_gem_set_tiling(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_set_tiling *args = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
ret = i915_gem_check_is_wedged(dev);
if (ret)
return ret;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL)
return -ENOENT;
- obj_priv = to_intel_bo(obj);
- if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
- drm_gem_object_unreference_unlocked(obj);
+ if (!i915_tiling_ok(dev,
+ args->stride, obj->base.size, args->tiling_mode)) {
+ drm_gem_object_unreference_unlocked(&obj->base);
return -EINVAL;
}
- if (obj_priv->pin_count) {
- drm_gem_object_unreference_unlocked(obj);
+ if (obj->pin_count) {
+ drm_gem_object_unreference_unlocked(&obj->base);
return -EBUSY;
}
@@ -324,34 +335,28 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
mutex_lock(&dev->struct_mutex);
- if (args->tiling_mode != obj_priv->tiling_mode ||
- args->stride != obj_priv->stride) {
+ if (args->tiling_mode != obj->tiling_mode ||
+ args->stride != obj->stride) {
/* We need to rebind the object if its current allocation
* no longer meets the alignment restrictions for its new
* tiling mode. Otherwise we can just leave it alone, but
* need to ensure that any fence register is cleared.
*/
- if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
- ret = i915_gem_object_unbind(obj);
- else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
- ret = i915_gem_object_put_fence_reg(obj, true);
- else
- i915_gem_release_mmap(obj);
+ i915_gem_release_mmap(obj);
- if (ret != 0) {
- args->tiling_mode = obj_priv->tiling_mode;
- args->stride = obj_priv->stride;
- goto err;
- }
+ obj->map_and_fenceable =
+ obj->gtt_space == NULL ||
+ (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end &&
+ i915_gem_object_fence_ok(obj, args->tiling_mode));
- obj_priv->tiling_mode = args->tiling_mode;
- obj_priv->stride = args->stride;
+ obj->tiling_changed = true;
+ obj->tiling_mode = args->tiling_mode;
+ obj->stride = args->stride;
}
-err:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
- return ret;
+ return 0;
}
/**
@@ -359,22 +364,20 @@ err:
*/
int
i915_gem_get_tiling(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_get_tiling *args = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (obj == NULL)
return -ENOENT;
- obj_priv = to_intel_bo(obj);
mutex_lock(&dev->struct_mutex);
- args->tiling_mode = obj_priv->tiling_mode;
- switch (obj_priv->tiling_mode) {
+ args->tiling_mode = obj->tiling_mode;
+ switch (obj->tiling_mode) {
case I915_TILING_X:
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
break;
@@ -394,7 +397,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
return 0;
@@ -424,46 +427,44 @@ i915_gem_swizzle_page(struct page *page)
}
void
-i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
+i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int page_count = obj->size >> PAGE_SHIFT;
+ int page_count = obj->base.size >> PAGE_SHIFT;
int i;
if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
return;
- if (obj_priv->bit_17 == NULL)
+ if (obj->bit_17 == NULL)
return;
for (i = 0; i < page_count; i++) {
- char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
+ char new_bit_17 = page_to_phys(obj->pages[i]) >> 17;
if ((new_bit_17 & 0x1) !=
- (test_bit(i, obj_priv->bit_17) != 0)) {
- i915_gem_swizzle_page(obj_priv->pages[i]);
- set_page_dirty(obj_priv->pages[i]);
+ (test_bit(i, obj->bit_17) != 0)) {
+ i915_gem_swizzle_page(obj->pages[i]);
+ set_page_dirty(obj->pages[i]);
}
}
}
void
-i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj)
+i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int page_count = obj->size >> PAGE_SHIFT;
+ int page_count = obj->base.size >> PAGE_SHIFT;
int i;
if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
return;
- if (obj_priv->bit_17 == NULL) {
- obj_priv->bit_17 = kmalloc(BITS_TO_LONGS(page_count) *
+ if (obj->bit_17 == NULL) {
+ obj->bit_17 = kmalloc(BITS_TO_LONGS(page_count) *
sizeof(long), GFP_KERNEL);
- if (obj_priv->bit_17 == NULL) {
+ if (obj->bit_17 == NULL) {
DRM_ERROR("Failed to allocate memory for bit 17 "
"record\n");
return;
@@ -471,9 +472,9 @@ i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj)
}
for (i = 0; i < page_count; i++) {
- if (page_to_phys(obj_priv->pages[i]) & (1 << 17))
- __set_bit(i, obj_priv->bit_17);
+ if (page_to_phys(obj->pages[i]) & (1 << 17))
+ __set_bit(i, obj->bit_17);
else
- __clear_bit(i, obj_priv->bit_17);
+ __clear_bit(i, obj->bit_17);
}
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 729fd0c91d7b..b8e509ae065e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -64,64 +64,24 @@
#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \
DRM_I915_VBLANK_PIPE_B)
-void
-ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
-{
- if ((dev_priv->gt_irq_mask_reg & mask) != 0) {
- dev_priv->gt_irq_mask_reg &= ~mask;
- I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
- (void) I915_READ(GTIMR);
- }
-}
-
-void
-ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
-{
- if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
- dev_priv->gt_irq_mask_reg |= mask;
- I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
- (void) I915_READ(GTIMR);
- }
-}
-
/* For display hotplug interrupt */
static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
- if ((dev_priv->irq_mask_reg & mask) != 0) {
- dev_priv->irq_mask_reg &= ~mask;
- I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
- (void) I915_READ(DEIMR);
+ if ((dev_priv->irq_mask & mask) != 0) {
+ dev_priv->irq_mask &= ~mask;
+ I915_WRITE(DEIMR, dev_priv->irq_mask);
+ POSTING_READ(DEIMR);
}
}
static inline void
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
- if ((dev_priv->irq_mask_reg & mask) != mask) {
- dev_priv->irq_mask_reg |= mask;
- I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
- (void) I915_READ(DEIMR);
- }
-}
-
-void
-i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
-{
- if ((dev_priv->irq_mask_reg & mask) != 0) {
- dev_priv->irq_mask_reg &= ~mask;
- I915_WRITE(IMR, dev_priv->irq_mask_reg);
- (void) I915_READ(IMR);
- }
-}
-
-void
-i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
-{
- if ((dev_priv->irq_mask_reg & mask) != mask) {
- dev_priv->irq_mask_reg |= mask;
- I915_WRITE(IMR, dev_priv->irq_mask_reg);
- (void) I915_READ(IMR);
+ if ((dev_priv->irq_mask & mask) != mask) {
+ dev_priv->irq_mask |= mask;
+ I915_WRITE(DEIMR, dev_priv->irq_mask);
+ POSTING_READ(DEIMR);
}
}
@@ -144,7 +104,7 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
dev_priv->pipestat[pipe] |= mask;
/* Enable the interrupt, clear any pending status */
I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
- (void) I915_READ(reg);
+ POSTING_READ(reg);
}
}
@@ -156,16 +116,19 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
dev_priv->pipestat[pipe] &= ~mask;
I915_WRITE(reg, dev_priv->pipestat[pipe]);
- (void) I915_READ(reg);
+ POSTING_READ(reg);
}
}
/**
* intel_enable_asle - enable ASLE interrupt for OpRegion
*/
-void intel_enable_asle (struct drm_device *dev)
+void intel_enable_asle(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
ironlake_enable_display_irq(dev_priv, DE_GSE);
@@ -176,6 +139,8 @@ void intel_enable_asle (struct drm_device *dev)
i915_enable_pipestat(dev_priv, 0,
PIPE_LEGACY_BLC_EVENT_ENABLE);
}
+
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
/**
@@ -243,6 +208,92 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
return I915_READ(reg);
}
+int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+ int *vpos, int *hpos)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 vbl = 0, position = 0;
+ int vbl_start, vbl_end, htotal, vtotal;
+ bool in_vbl = true;
+ int ret = 0;
+
+ if (!i915_pipe_enabled(dev, pipe)) {
+ DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
+ "pipe %d\n", pipe);
+ return 0;
+ }
+
+ /* Get vtotal. */
+ vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff);
+
+ if (INTEL_INFO(dev)->gen >= 4) {
+ /* No obvious pixelcount register. Only query vertical
+ * scanout position from Display scan line register.
+ */
+ position = I915_READ(PIPEDSL(pipe));
+
+ /* Decode into vertical scanout position. Don't have
+ * horizontal scanout position.
+ */
+ *vpos = position & 0x1fff;
+ *hpos = 0;
+ } else {
+ /* Have access to pixelcount since start of frame.
+ * We can split this into vertical and horizontal
+ * scanout position.
+ */
+ position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
+
+ htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff);
+ *vpos = position / htotal;
+ *hpos = position - (*vpos * htotal);
+ }
+
+ /* Query vblank area. */
+ vbl = I915_READ(VBLANK(pipe));
+
+ /* Test position against vblank region. */
+ vbl_start = vbl & 0x1fff;
+ vbl_end = (vbl >> 16) & 0x1fff;
+
+ if ((*vpos < vbl_start) || (*vpos > vbl_end))
+ in_vbl = false;
+
+ /* Inside "upper part" of vblank area? Apply corrective offset: */
+ if (in_vbl && (*vpos >= vbl_start))
+ *vpos = *vpos - vtotal;
+
+ /* Readouts valid? */
+ if (vbl > 0)
+ ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+ /* In vblank? */
+ if (in_vbl)
+ ret |= DRM_SCANOUTPOS_INVBL;
+
+ return ret;
+}
+
+int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags)
+{
+ struct drm_crtc *drmcrtc;
+
+ if (crtc < 0 || crtc >= dev->num_crtcs) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
+ return -EINVAL;
+ }
+
+ /* Get drm_crtc to timestamp: */
+ drmcrtc = intel_get_crtc_for_pipe(dev, crtc);
+
+ /* Helper routine in DRM core does all the work: */
+ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+ vblank_time, flags, drmcrtc);
+}
+
/*
* Handle hotplug events outside the interrupt handler proper.
*/
@@ -297,20 +348,105 @@ static void notify_ring(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 seqno = ring->get_seqno(dev, ring);
- ring->irq_gem_seqno = seqno;
+ u32 seqno = ring->get_seqno(ring);
+
trace_i915_gem_request_complete(dev, seqno);
+
+ ring->irq_seqno = seqno;
wake_up_all(&ring->irq_queue);
+
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
+static void gen6_pm_irq_handler(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u8 new_delay = dev_priv->cur_delay;
+ u32 pm_iir;
+
+ pm_iir = I915_READ(GEN6_PMIIR);
+ if (!pm_iir)
+ return;
+
+ if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
+ if (dev_priv->cur_delay != dev_priv->max_delay)
+ new_delay = dev_priv->cur_delay + 1;
+ if (new_delay > dev_priv->max_delay)
+ new_delay = dev_priv->max_delay;
+ } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
+ if (dev_priv->cur_delay != dev_priv->min_delay)
+ new_delay = dev_priv->cur_delay - 1;
+ if (new_delay < dev_priv->min_delay) {
+ new_delay = dev_priv->min_delay;
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+ I915_READ(GEN6_RP_INTERRUPT_LIMITS) |
+ ((new_delay << 16) & 0x3f0000));
+ } else {
+ /* Make sure we continue to get down interrupts
+ * until we hit the minimum frequency */
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+ I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
+ }
+
+ }
+
+ gen6_set_rps(dev, new_delay);
+ dev_priv->cur_delay = new_delay;
+
+ I915_WRITE(GEN6_PMIIR, pm_iir);
+}
+
+static void pch_irq_handler(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 pch_iir;
+
+ pch_iir = I915_READ(SDEIIR);
+
+ if (pch_iir & SDE_AUDIO_POWER_MASK)
+ DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
+ (pch_iir & SDE_AUDIO_POWER_MASK) >>
+ SDE_AUDIO_POWER_SHIFT);
+
+ if (pch_iir & SDE_GMBUS)
+ DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+
+ if (pch_iir & SDE_AUDIO_HDCP_MASK)
+ DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
+
+ if (pch_iir & SDE_AUDIO_TRANS_MASK)
+ DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
+
+ if (pch_iir & SDE_POISON)
+ DRM_ERROR("PCH poison interrupt\n");
+
+ if (pch_iir & SDE_FDI_MASK) {
+ u32 fdia, fdib;
+
+ fdia = I915_READ(FDI_RXA_IIR);
+ fdib = I915_READ(FDI_RXB_IIR);
+ DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib);
+ }
+
+ if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
+ DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
+
+ if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
+ DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
+
+ if (pch_iir & SDE_TRANSB_FIFO_UNDER)
+ DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
+ if (pch_iir & SDE_TRANSA_FIFO_UNDER)
+ DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
+}
+
static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
- u32 de_iir, gt_iir, de_ier, pch_iir;
+ u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
u32 hotplug_mask;
struct drm_i915_master_private *master_priv;
u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
@@ -321,13 +457,15 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
- (void)I915_READ(DEIER);
+ POSTING_READ(DEIER);
de_iir = I915_READ(DEIIR);
gt_iir = I915_READ(GTIIR);
pch_iir = I915_READ(SDEIIR);
+ pm_iir = I915_READ(GEN6_PMIIR);
- if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
+ if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
+ (!IS_GEN6(dev) || pm_iir == 0))
goto done;
if (HAS_PCH_CPT(dev))
@@ -344,12 +482,12 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
READ_BREADCRUMB(dev_priv);
}
- if (gt_iir & GT_PIPE_NOTIFY)
- notify_ring(dev, &dev_priv->render_ring);
+ if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+ notify_ring(dev, &dev_priv->ring[RCS]);
if (gt_iir & bsd_usr_interrupt)
- notify_ring(dev, &dev_priv->bsd_ring);
- if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->blt_ring);
+ notify_ring(dev, &dev_priv->ring[VCS]);
+ if (gt_iir & GT_BLT_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[BCS]);
if (de_iir & DE_GSE)
intel_opregion_gse_intr(dev);
@@ -371,14 +509,20 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
drm_handle_vblank(dev, 1);
/* check event from PCH */
- if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+ if (de_iir & DE_PCH_EVENT) {
+ if (pch_iir & hotplug_mask)
+ queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+ pch_irq_handler(dev);
+ }
if (de_iir & DE_PCU_EVENT) {
I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
i915_handle_rps_change(dev);
}
+ if (IS_GEN6(dev))
+ gen6_pm_irq_handler(dev);
+
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir);
@@ -386,7 +530,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
done:
I915_WRITE(DEIER, de_ier);
- (void)I915_READ(DEIER);
+ POSTING_READ(DEIER);
return ret;
}
@@ -422,29 +566,23 @@ static void i915_error_work_func(struct work_struct *work)
#ifdef CONFIG_DEBUG_FS
static struct drm_i915_error_object *
-i915_error_object_create(struct drm_device *dev,
- struct drm_gem_object *src)
+i915_error_object_create(struct drm_i915_private *dev_priv,
+ struct drm_i915_gem_object *src)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_object *dst;
- struct drm_i915_gem_object *src_priv;
int page, page_count;
u32 reloc_offset;
- if (src == NULL)
+ if (src == NULL || src->pages == NULL)
return NULL;
- src_priv = to_intel_bo(src);
- if (src_priv->pages == NULL)
- return NULL;
-
- page_count = src->size / PAGE_SIZE;
+ page_count = src->base.size / PAGE_SIZE;
dst = kmalloc(sizeof(*dst) + page_count * sizeof (u32 *), GFP_ATOMIC);
if (dst == NULL)
return NULL;
- reloc_offset = src_priv->gtt_offset;
+ reloc_offset = src->gtt_offset;
for (page = 0; page < page_count; page++) {
unsigned long flags;
void __iomem *s;
@@ -466,7 +604,7 @@ i915_error_object_create(struct drm_device *dev,
reloc_offset += PAGE_SIZE;
}
dst->page_count = page_count;
- dst->gtt_offset = src_priv->gtt_offset;
+ dst->gtt_offset = src->gtt_offset;
return dst;
@@ -503,53 +641,98 @@ i915_error_state_free(struct drm_device *dev,
kfree(error);
}
-static u32
-i915_get_bbaddr(struct drm_device *dev, u32 *ring)
+static u32 capture_bo_list(struct drm_i915_error_buffer *err,
+ int count,
+ struct list_head *head)
{
- u32 cmd;
+ struct drm_i915_gem_object *obj;
+ int i = 0;
+
+ list_for_each_entry(obj, head, mm_list) {
+ err->size = obj->base.size;
+ err->name = obj->base.name;
+ err->seqno = obj->last_rendering_seqno;
+ err->gtt_offset = obj->gtt_offset;
+ err->read_domains = obj->base.read_domains;
+ err->write_domain = obj->base.write_domain;
+ err->fence_reg = obj->fence_reg;
+ err->pinned = 0;
+ if (obj->pin_count > 0)
+ err->pinned = 1;
+ if (obj->user_pin_count > 0)
+ err->pinned = -1;
+ err->tiling = obj->tiling_mode;
+ err->dirty = obj->dirty;
+ err->purgeable = obj->madv != I915_MADV_WILLNEED;
+ err->ring = obj->ring ? obj->ring->id : 0;
+ err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY;
+
+ if (++i == count)
+ break;
- if (IS_I830(dev) || IS_845G(dev))
- cmd = MI_BATCH_BUFFER;
- else if (INTEL_INFO(dev)->gen >= 4)
- cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
- MI_BATCH_NON_SECURE_I965);
- else
- cmd = (MI_BATCH_BUFFER_START | (2 << 6));
+ err++;
+ }
- return ring[0] == cmd ? ring[1] : 0;
+ return i;
}
-static u32
-i915_ringbuffer_last_batch(struct drm_device *dev)
+static void i915_gem_record_fences(struct drm_device *dev,
+ struct drm_i915_error_state *error)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 head, bbaddr;
- u32 *ring;
-
- /* Locate the current position in the ringbuffer and walk back
- * to find the most recently dispatched batch buffer.
- */
- bbaddr = 0;
- head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring = (u32 *)(dev_priv->render_ring.virtual_start + head);
+ int i;
+
+ /* Fences */
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
+ break;
+ case 5:
+ case 4:
+ for (i = 0; i < 16; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
+ break;
+ case 3:
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ for (i = 0; i < 8; i++)
+ error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+ case 2:
+ for (i = 0; i < 8; i++)
+ error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+ break;
- while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
- bbaddr = i915_get_bbaddr(dev, ring);
- if (bbaddr)
- break;
}
+}
- if (bbaddr == 0) {
- ring = (u32 *)(dev_priv->render_ring.virtual_start
- + dev_priv->render_ring.size);
- while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
- bbaddr = i915_get_bbaddr(dev, ring);
- if (bbaddr)
- break;
- }
+static struct drm_i915_error_object *
+i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_gem_object *obj;
+ u32 seqno;
+
+ if (!ring->get_seqno)
+ return NULL;
+
+ seqno = ring->get_seqno(ring);
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+ if (obj->ring != ring)
+ continue;
+
+ if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
+ continue;
+
+ if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
+ continue;
+
+ /* We need to copy these to an anonymous buffer as the simplest
+ * method to avoid being overwritten by userspace.
+ */
+ return i915_error_object_create(dev_priv, obj);
}
- return bbaddr;
+ return NULL;
}
/**
@@ -564,12 +747,10 @@ i915_ringbuffer_last_batch(struct drm_device *dev)
static void i915_capture_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
struct drm_i915_error_state *error;
- struct drm_gem_object *batchbuffer[2];
unsigned long flags;
- u32 bbaddr;
- int count;
+ int i;
spin_lock_irqsave(&dev_priv->error_lock, flags);
error = dev_priv->first_error;
@@ -585,20 +766,33 @@ static void i915_capture_error_state(struct drm_device *dev)
DRM_DEBUG_DRIVER("generating error event\n");
- error->seqno =
- dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
+ error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT);
error->pipebstat = I915_READ(PIPEBSTAT);
error->instpm = I915_READ(INSTPM);
- if (INTEL_INFO(dev)->gen < 4) {
- error->ipeir = I915_READ(IPEIR);
- error->ipehr = I915_READ(IPEHR);
- error->instdone = I915_READ(INSTDONE);
- error->acthd = I915_READ(ACTHD);
- error->bbaddr = 0;
- } else {
+ error->error = 0;
+ if (INTEL_INFO(dev)->gen >= 6) {
+ error->error = I915_READ(ERROR_GEN6);
+
+ error->bcs_acthd = I915_READ(BCS_ACTHD);
+ error->bcs_ipehr = I915_READ(BCS_IPEHR);
+ error->bcs_ipeir = I915_READ(BCS_IPEIR);
+ error->bcs_instdone = I915_READ(BCS_INSTDONE);
+ error->bcs_seqno = 0;
+ if (dev_priv->ring[BCS].get_seqno)
+ error->bcs_seqno = dev_priv->ring[BCS].get_seqno(&dev_priv->ring[BCS]);
+
+ error->vcs_acthd = I915_READ(VCS_ACTHD);
+ error->vcs_ipehr = I915_READ(VCS_IPEHR);
+ error->vcs_ipeir = I915_READ(VCS_IPEIR);
+ error->vcs_instdone = I915_READ(VCS_INSTDONE);
+ error->vcs_seqno = 0;
+ if (dev_priv->ring[VCS].get_seqno)
+ error->vcs_seqno = dev_priv->ring[VCS].get_seqno(&dev_priv->ring[VCS]);
+ }
+ if (INTEL_INFO(dev)->gen >= 4) {
error->ipeir = I915_READ(IPEIR_I965);
error->ipehr = I915_READ(IPEHR_I965);
error->instdone = I915_READ(INSTDONE_I965);
@@ -606,118 +800,61 @@ static void i915_capture_error_state(struct drm_device *dev)
error->instdone1 = I915_READ(INSTDONE1);
error->acthd = I915_READ(ACTHD_I965);
error->bbaddr = I915_READ64(BB_ADDR);
+ } else {
+ error->ipeir = I915_READ(IPEIR);
+ error->ipehr = I915_READ(IPEHR);
+ error->instdone = I915_READ(INSTDONE);
+ error->acthd = I915_READ(ACTHD);
+ error->bbaddr = 0;
}
+ i915_gem_record_fences(dev, error);
- bbaddr = i915_ringbuffer_last_batch(dev);
-
- /* Grab the current batchbuffer, most likely to have crashed. */
- batchbuffer[0] = NULL;
- batchbuffer[1] = NULL;
- count = 0;
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
- struct drm_gem_object *obj = &obj_priv->base;
-
- if (batchbuffer[0] == NULL &&
- bbaddr >= obj_priv->gtt_offset &&
- bbaddr < obj_priv->gtt_offset + obj->size)
- batchbuffer[0] = obj;
-
- if (batchbuffer[1] == NULL &&
- error->acthd >= obj_priv->gtt_offset &&
- error->acthd < obj_priv->gtt_offset + obj->size)
- batchbuffer[1] = obj;
-
- count++;
- }
- /* Scan the other lists for completeness for those bizarre errors. */
- if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
- list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
- struct drm_gem_object *obj = &obj_priv->base;
-
- if (batchbuffer[0] == NULL &&
- bbaddr >= obj_priv->gtt_offset &&
- bbaddr < obj_priv->gtt_offset + obj->size)
- batchbuffer[0] = obj;
-
- if (batchbuffer[1] == NULL &&
- error->acthd >= obj_priv->gtt_offset &&
- error->acthd < obj_priv->gtt_offset + obj->size)
- batchbuffer[1] = obj;
-
- if (batchbuffer[0] && batchbuffer[1])
- break;
- }
- }
- if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
- struct drm_gem_object *obj = &obj_priv->base;
-
- if (batchbuffer[0] == NULL &&
- bbaddr >= obj_priv->gtt_offset &&
- bbaddr < obj_priv->gtt_offset + obj->size)
- batchbuffer[0] = obj;
-
- if (batchbuffer[1] == NULL &&
- error->acthd >= obj_priv->gtt_offset &&
- error->acthd < obj_priv->gtt_offset + obj->size)
- batchbuffer[1] = obj;
-
- if (batchbuffer[0] && batchbuffer[1])
- break;
- }
- }
-
- /* We need to copy these to an anonymous buffer as the simplest
- * method to avoid being overwritten by userspace.
- */
- error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
- if (batchbuffer[1] != batchbuffer[0])
- error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
- else
- error->batchbuffer[1] = NULL;
+ /* Record the active batchbuffers */
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ error->batchbuffer[i] =
+ i915_error_first_batchbuffer(dev_priv,
+ &dev_priv->ring[i]);
/* Record the ringbuffer */
- error->ringbuffer = i915_error_object_create(dev,
- dev_priv->render_ring.gem_object);
+ error->ringbuffer = i915_error_object_create(dev_priv,
+ dev_priv->ring[RCS].obj);
- /* Record buffers on the active list. */
+ /* Record buffers on the active and pinned lists. */
error->active_bo = NULL;
- error->active_bo_count = 0;
-
- if (count)
- error->active_bo = kmalloc(sizeof(*error->active_bo)*count,
+ error->pinned_bo = NULL;
+
+ i = 0;
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
+ i++;
+ error->active_bo_count = i;
+ list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
+ i++;
+ error->pinned_bo_count = i - error->active_bo_count;
+
+ if (i) {
+ error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
GFP_ATOMIC);
-
- if (error->active_bo) {
- int i = 0;
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
- struct drm_gem_object *obj = &obj_priv->base;
-
- error->active_bo[i].size = obj->size;
- error->active_bo[i].name = obj->name;
- error->active_bo[i].seqno = obj_priv->last_rendering_seqno;
- error->active_bo[i].gtt_offset = obj_priv->gtt_offset;
- error->active_bo[i].read_domains = obj->read_domains;
- error->active_bo[i].write_domain = obj->write_domain;
- error->active_bo[i].fence_reg = obj_priv->fence_reg;
- error->active_bo[i].pinned = 0;
- if (obj_priv->pin_count > 0)
- error->active_bo[i].pinned = 1;
- if (obj_priv->user_pin_count > 0)
- error->active_bo[i].pinned = -1;
- error->active_bo[i].tiling = obj_priv->tiling_mode;
- error->active_bo[i].dirty = obj_priv->dirty;
- error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
-
- if (++i == count)
- break;
- }
- error->active_bo_count = i;
+ if (error->active_bo)
+ error->pinned_bo =
+ error->active_bo + error->active_bo_count;
}
+ if (error->active_bo)
+ error->active_bo_count =
+ capture_bo_list(error->active_bo,
+ error->active_bo_count,
+ &dev_priv->mm.active_list);
+
+ if (error->pinned_bo)
+ error->pinned_bo_count =
+ capture_bo_list(error->pinned_bo,
+ error->pinned_bo_count,
+ &dev_priv->mm.pinned_list);
+
do_gettimeofday(&error->time);
error->overlay = intel_overlay_capture_error_state(dev);
+ error->display = intel_display_capture_error_state(dev);
spin_lock_irqsave(&dev_priv->error_lock, flags);
if (dev_priv->first_error == NULL) {
@@ -775,7 +912,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR " ACTHD: 0x%08x\n",
I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
- (void)I915_READ(IPEIR_I965);
+ POSTING_READ(IPEIR_I965);
}
if (eir & GM45_ERROR_PAGE_TABLE) {
u32 pgtbl_err = I915_READ(PGTBL_ER);
@@ -783,7 +920,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
pgtbl_err);
I915_WRITE(PGTBL_ER, pgtbl_err);
- (void)I915_READ(PGTBL_ER);
+ POSTING_READ(PGTBL_ER);
}
}
@@ -794,7 +931,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
pgtbl_err);
I915_WRITE(PGTBL_ER, pgtbl_err);
- (void)I915_READ(PGTBL_ER);
+ POSTING_READ(PGTBL_ER);
}
}
@@ -825,7 +962,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR " ACTHD: 0x%08x\n",
I915_READ(ACTHD));
I915_WRITE(IPEIR, ipeir);
- (void)I915_READ(IPEIR);
+ POSTING_READ(IPEIR);
} else {
u32 ipeir = I915_READ(IPEIR_I965);
@@ -842,12 +979,12 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR " ACTHD: 0x%08x\n",
I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
- (void)I915_READ(IPEIR_I965);
+ POSTING_READ(IPEIR_I965);
}
}
I915_WRITE(EIR, eir);
- (void)I915_READ(EIR);
+ POSTING_READ(EIR);
eir = I915_READ(EIR);
if (eir) {
/*
@@ -870,7 +1007,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
* so userspace knows something bad happened (should trigger collection
* of a ring dump etc.).
*/
-static void i915_handle_error(struct drm_device *dev, bool wedged)
+void i915_handle_error(struct drm_device *dev, bool wedged)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -884,11 +1021,11 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
/*
* Wakeup waiting processes so they don't hang
*/
- wake_up_all(&dev_priv->render_ring.irq_queue);
+ wake_up_all(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
- wake_up_all(&dev_priv->bsd_ring.irq_queue);
+ wake_up_all(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
- wake_up_all(&dev_priv->blt_ring.irq_queue);
+ wake_up_all(&dev_priv->ring[BCS].irq_queue);
}
queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -899,7 +1036,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
struct intel_unpin_work *work;
unsigned long flags;
bool stall_detected;
@@ -918,13 +1055,13 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
}
/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
- obj_priv = to_intel_bo(work->pending_flip_obj);
+ obj = work->pending_flip_obj;
if (INTEL_INFO(dev)->gen >= 4) {
int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
- stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
+ stall_detected = I915_READ(dspsurf) == obj->gtt_offset;
} else {
int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR;
- stall_detected = I915_READ(dspaddr) == (obj_priv->gtt_offset +
+ stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
crtc->y * crtc->fb->pitch +
crtc->x * crtc->fb->bits_per_pixel/8);
}
@@ -970,7 +1107,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
* It doesn't set the bit in iir again, but it still produces
* interrupts (for non-MSI).
*/
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
pipea_stats = I915_READ(PIPEASTAT);
pipeb_stats = I915_READ(PIPEBSTAT);
@@ -993,7 +1130,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
I915_WRITE(PIPEBSTAT, pipeb_stats);
irq_received = 1;
}
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
if (!irq_received)
break;
@@ -1026,9 +1163,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
}
if (iir & I915_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->render_ring);
- if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
- notify_ring(dev, &dev_priv->bsd_ring);
+ notify_ring(dev, &dev_priv->ring[RCS]);
+ if (iir & I915_BSD_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[VCS]);
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
intel_prepare_page_flip(dev, 0);
@@ -1101,12 +1238,13 @@ static int i915_emit_irq(struct drm_device * dev)
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_enqueue = dev_priv->counter;
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(dev_priv->counter);
- OUT_RING(MI_USER_INTERRUPT);
- ADVANCE_LP_RING();
+ if (BEGIN_LP_RING(4) == 0) {
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(MI_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+ }
return dev_priv->counter;
}
@@ -1114,12 +1252,11 @@ static int i915_emit_irq(struct drm_device * dev)
void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
-
- if (dev_priv->trace_irq_seqno == 0)
- render_ring->user_irq_get(dev, render_ring);
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
- dev_priv->trace_irq_seqno = seqno;
+ if (dev_priv->trace_irq_seqno == 0 &&
+ ring->irq_get(ring))
+ dev_priv->trace_irq_seqno = seqno;
}
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
@@ -1127,7 +1264,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
int ret = 0;
- struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv));
@@ -1141,10 +1278,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
if (master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
- render_ring->user_irq_get(dev, render_ring);
- DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ,
- READ_BREADCRUMB(dev_priv) >= irq_nr);
- render_ring->user_irq_put(dev, render_ring);
+ ret = -ENODEV;
+ if (ring->irq_get(ring)) {
+ DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
+ READ_BREADCRUMB(dev_priv) >= irq_nr);
+ ring->irq_put(ring);
+ }
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
@@ -1163,7 +1302,7 @@ int i915_irq_emit(struct drm_device *dev, void *data,
drm_i915_irq_emit_t *emit = data;
int result;
- if (!dev_priv || !dev_priv->render_ring.virtual_start) {
+ if (!dev_priv || !LP_RING(dev_priv)->virtual_start) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
@@ -1209,9 +1348,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
if (!i915_pipe_enabled(dev, pipe))
return -EINVAL;
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
- ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+ ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
else if (INTEL_INFO(dev)->gen >= 4)
i915_enable_pipestat(dev_priv, pipe,
@@ -1219,7 +1358,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
else
i915_enable_pipestat(dev_priv, pipe,
PIPE_VBLANK_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
}
@@ -1231,15 +1370,15 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
- ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+ ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
else
i915_disable_pipestat(dev_priv, pipe,
PIPE_VBLANK_INTERRUPT_ENABLE |
PIPE_START_VBLANK_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
void i915_enable_interrupt (struct drm_device *dev)
@@ -1306,12 +1445,50 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
return -EINVAL;
}
-static struct drm_i915_gem_request *
-i915_get_tail_request(struct drm_device *dev)
+static u32
+ring_last_seqno(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- return list_entry(dev_priv->render_ring.request_list.prev,
- struct drm_i915_gem_request, list);
+ return list_entry(ring->request_list.prev,
+ struct drm_i915_gem_request, list)->seqno;
+}
+
+static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+{
+ if (list_empty(&ring->request_list) ||
+ i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
+ /* Issue a wake-up to catch stuck h/w. */
+ if (ring->waiting_seqno && waitqueue_active(&ring->irq_queue)) {
+ DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
+ ring->name,
+ ring->waiting_seqno,
+ ring->get_seqno(ring));
+ wake_up_all(&ring->irq_queue);
+ *err = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool kick_ring(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 tmp = I915_READ_CTL(ring);
+ if (tmp & RING_WAIT) {
+ DRM_ERROR("Kicking stuck wait on %s\n",
+ ring->name);
+ I915_WRITE_CTL(ring, tmp);
+ return true;
+ }
+ if (IS_GEN6(dev) &&
+ (tmp & RING_WAIT_SEMAPHORE)) {
+ DRM_ERROR("Kicking stuck semaphore on %s\n",
+ ring->name);
+ I915_WRITE_CTL(ring, tmp);
+ return true;
+ }
+ return false;
}
/**
@@ -1325,6 +1502,17 @@ void i915_hangcheck_elapsed(unsigned long data)
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd, instdone, instdone1;
+ bool err = false;
+
+ /* If all work is done then ACTHD clearly hasn't advanced. */
+ if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
+ i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
+ i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
+ dev_priv->hangcheck_count = 0;
+ if (err)
+ goto repeat;
+ return;
+ }
if (INTEL_INFO(dev)->gen < 4) {
acthd = I915_READ(ACTHD);
@@ -1336,38 +1524,6 @@ void i915_hangcheck_elapsed(unsigned long data)
instdone1 = I915_READ(INSTDONE1);
}
- /* If all work is done then ACTHD clearly hasn't advanced. */
- if (list_empty(&dev_priv->render_ring.request_list) ||
- i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
- i915_get_tail_request(dev)->seqno)) {
- bool missed_wakeup = false;
-
- dev_priv->hangcheck_count = 0;
-
- /* Issue a wake-up to catch stuck h/w. */
- if (dev_priv->render_ring.waiting_gem_seqno &&
- waitqueue_active(&dev_priv->render_ring.irq_queue)) {
- wake_up_all(&dev_priv->render_ring.irq_queue);
- missed_wakeup = true;
- }
-
- if (dev_priv->bsd_ring.waiting_gem_seqno &&
- waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
- wake_up_all(&dev_priv->bsd_ring.irq_queue);
- missed_wakeup = true;
- }
-
- if (dev_priv->blt_ring.waiting_gem_seqno &&
- waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
- wake_up_all(&dev_priv->blt_ring.irq_queue);
- missed_wakeup = true;
- }
-
- if (missed_wakeup)
- DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n");
- return;
- }
-
if (dev_priv->last_acthd == acthd &&
dev_priv->last_instdone == instdone &&
dev_priv->last_instdone1 == instdone1) {
@@ -1380,12 +1536,17 @@ void i915_hangcheck_elapsed(unsigned long data)
* and break the hang. This should work on
* all but the second generation chipsets.
*/
- u32 tmp = I915_READ(PRB0_CTL);
- if (tmp & RING_WAIT) {
- I915_WRITE(PRB0_CTL, tmp);
- POSTING_READ(PRB0_CTL);
- goto out;
- }
+
+ if (kick_ring(&dev_priv->ring[RCS]))
+ goto repeat;
+
+ if (HAS_BSD(dev) &&
+ kick_ring(&dev_priv->ring[VCS]))
+ goto repeat;
+
+ if (HAS_BLT(dev) &&
+ kick_ring(&dev_priv->ring[BCS]))
+ goto repeat;
}
i915_handle_error(dev, true);
@@ -1399,7 +1560,7 @@ void i915_hangcheck_elapsed(unsigned long data)
dev_priv->last_instdone1 = instdone1;
}
-out:
+repeat:
/* Reset timer case chip hangs without another request being added */
mod_timer(&dev_priv->hangcheck_timer,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
@@ -1417,17 +1578,17 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
I915_WRITE(DEIMR, 0xffffffff);
I915_WRITE(DEIER, 0x0);
- (void) I915_READ(DEIER);
+ POSTING_READ(DEIER);
/* and GT */
I915_WRITE(GTIMR, 0xffffffff);
I915_WRITE(GTIER, 0x0);
- (void) I915_READ(GTIER);
+ POSTING_READ(GTIER);
/* south display irq */
I915_WRITE(SDEIMR, 0xffffffff);
I915_WRITE(SDEIER, 0x0);
- (void) I915_READ(SDEIER);
+ POSTING_READ(SDEIER);
}
static int ironlake_irq_postinstall(struct drm_device *dev)
@@ -1436,38 +1597,34 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
- u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
+ u32 render_irqs;
u32 hotplug_mask;
- dev_priv->irq_mask_reg = ~display_mask;
- dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
+ dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
- I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
- I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
- (void) I915_READ(DEIER);
-
- if (IS_GEN6(dev)) {
- render_mask =
- GT_PIPE_NOTIFY |
- GT_GEN6_BSD_USER_INTERRUPT |
- GT_BLT_USER_INTERRUPT;
- }
+ I915_WRITE(DEIMR, dev_priv->irq_mask);
+ I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
+ POSTING_READ(DEIER);
- dev_priv->gt_irq_mask_reg = ~render_mask;
- dev_priv->gt_irq_enable_reg = render_mask;
+ dev_priv->gt_irq_mask = ~0;
I915_WRITE(GTIIR, I915_READ(GTIIR));
- I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
- if (IS_GEN6(dev)) {
- I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
- I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
- I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT);
- }
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
- (void) I915_READ(GTIER);
+ if (IS_GEN6(dev))
+ render_irqs =
+ GT_USER_INTERRUPT |
+ GT_GEN6_BSD_USER_INTERRUPT |
+ GT_BLT_USER_INTERRUPT;
+ else
+ render_irqs =
+ GT_USER_INTERRUPT |
+ GT_PIPE_NOTIFY |
+ GT_BSD_USER_INTERRUPT;
+ I915_WRITE(GTIER, render_irqs);
+ POSTING_READ(GTIER);
if (HAS_PCH_CPT(dev)) {
hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT |
@@ -1475,15 +1632,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
} else {
hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+ hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK;
+ I915_WRITE(FDI_RXA_IMR, 0);
+ I915_WRITE(FDI_RXB_IMR, 0);
}
- dev_priv->pch_irq_mask_reg = ~hotplug_mask;
- dev_priv->pch_irq_enable_reg = hotplug_mask;
+ dev_priv->pch_irq_mask = ~hotplug_mask;
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
- I915_WRITE(SDEIMR, dev_priv->pch_irq_mask_reg);
- I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
- (void) I915_READ(SDEIER);
+ I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
+ I915_WRITE(SDEIER, hotplug_mask);
+ POSTING_READ(SDEIER);
if (IS_IRONLAKE_M(dev)) {
/* Clear & enable PCU event interrupts */
@@ -1519,7 +1678,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
I915_WRITE(PIPEBSTAT, 0);
I915_WRITE(IMR, 0xffffffff);
I915_WRITE(IER, 0x0);
- (void) I915_READ(IER);
+ POSTING_READ(IER);
}
/*
@@ -1532,11 +1691,11 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
u32 error_mask;
- DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
if (HAS_BSD(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
if (HAS_BLT(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue);
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
@@ -1544,7 +1703,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
return ironlake_irq_postinstall(dev);
/* Unmask the interrupts that we always want on. */
- dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
+ dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
dev_priv->pipestat[0] = 0;
dev_priv->pipestat[1] = 0;
@@ -1553,7 +1712,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
/* Enable in IER... */
enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */
- dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT;
+ dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
}
/*
@@ -1571,9 +1730,9 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
}
I915_WRITE(EMR, error_mask);
- I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IMR, dev_priv->irq_mask);
I915_WRITE(IER, enable_mask);
- (void) I915_READ(IER);
+ POSTING_READ(IER);
if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 25ed911a3112..40a407f41f61 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -78,6 +78,12 @@
#define GRDOM_RENDER (1<<2)
#define GRDOM_MEDIA (3<<2)
+#define GEN6_GDRST 0x941c
+#define GEN6_GRDOM_FULL (1 << 0)
+#define GEN6_GRDOM_RENDER (1 << 1)
+#define GEN6_GRDOM_MEDIA (1 << 2)
+#define GEN6_GRDOM_BLT (1 << 3)
+
/* VGA stuff */
#define VGA_ST01_MDA 0x3ba
@@ -139,6 +145,8 @@
#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */
#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
+#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0)
+#define MI_SUSPEND_FLUSH_EN (1<<0)
#define MI_REPORT_HEAD MI_INSTR(0x07, 0)
#define MI_OVERLAY_FLIP MI_INSTR(0x11,0)
#define MI_OVERLAY_CONTINUE (0x0<<21)
@@ -153,17 +161,29 @@
#define MI_MM_SPACE_PHYSICAL (0<<8)
#define MI_SAVE_EXT_STATE_EN (1<<3)
#define MI_RESTORE_EXT_STATE_EN (1<<2)
+#define MI_FORCE_RESTORE (1<<1)
#define MI_RESTORE_INHIBIT (1<<0)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
#define MI_STORE_DWORD_INDEX_SHIFT 2
-#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1)
+/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM:
+ * - Always issue a MI_NOOP _before_ the MI_LOAD_REGISTER_IMM - otherwise hw
+ * simply ignores the register load under certain conditions.
+ * - One can actually load arbitrary many arbitrary registers: Simply issue x
+ * address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
+ */
+#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1)
#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */
#define MI_BATCH_BUFFER MI_INSTR(0x30, 1)
#define MI_BATCH_NON_SECURE (1)
#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
+#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */
+#define MI_SEMAPHORE_GLOBAL_GTT (1<<22)
+#define MI_SEMAPHORE_UPDATE (1<<21)
+#define MI_SEMAPHORE_COMPARE (1<<20)
+#define MI_SEMAPHORE_REGISTER (1<<18)
/*
* 3D instructions used by the kernel
*/
@@ -256,10 +276,6 @@
* Instruction and interrupt control regs
*/
#define PGTBL_ER 0x02024
-#define PRB0_TAIL 0x02030
-#define PRB0_HEAD 0x02034
-#define PRB0_START 0x02038
-#define PRB0_CTL 0x0203c
#define RENDER_RING_BASE 0x02000
#define BSD_RING_BASE 0x04000
#define GEN6_BSD_RING_BASE 0x12000
@@ -268,9 +284,14 @@
#define RING_HEAD(base) ((base)+0x34)
#define RING_START(base) ((base)+0x38)
#define RING_CTL(base) ((base)+0x3c)
+#define RING_SYNC_0(base) ((base)+0x40)
+#define RING_SYNC_1(base) ((base)+0x44)
+#define RING_MAX_IDLE(base) ((base)+0x54)
#define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
#define RING_ACTHD(base) ((base)+0x74)
+#define RING_NOPID(base) ((base)+0x94)
+#define RING_IMR(base) ((base)+0xa8)
#define TAIL_ADDR 0x001FFFF8
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
@@ -285,10 +306,17 @@
#define RING_INVALID 0x00000000
#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */
#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */
+#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */
+#if 0
+#define PRB0_TAIL 0x02030
+#define PRB0_HEAD 0x02034
+#define PRB0_START 0x02038
+#define PRB0_CTL 0x0203c
#define PRB1_TAIL 0x02040 /* 915+ only */
#define PRB1_HEAD 0x02044 /* 915+ only */
#define PRB1_START 0x02048 /* 915+ only */
#define PRB1_CTL 0x0204c /* 915+ only */
+#endif
#define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068
#define INSTDONE_I965 0x0206c
@@ -305,11 +333,42 @@
#define INSTDONE 0x02090
#define NOPID 0x02094
#define HWSTAM 0x02098
+#define VCS_INSTDONE 0x1206C
+#define VCS_IPEIR 0x12064
+#define VCS_IPEHR 0x12068
+#define VCS_ACTHD 0x12074
+#define BCS_INSTDONE 0x2206C
+#define BCS_IPEIR 0x22064
+#define BCS_IPEHR 0x22068
+#define BCS_ACTHD 0x22074
+
+#define ERROR_GEN6 0x040a0
+
+/* GM45+ chicken bits -- debug workaround bits that may be required
+ * for various sorts of correct behavior. The top 16 bits of each are
+ * the enables for writing to the corresponding low bit.
+ */
+#define _3D_CHICKEN 0x02084
+#define _3D_CHICKEN2 0x0208c
+/* Disables pipelining of read flushes past the SF-WIZ interface.
+ * Required on all Ironlake steppings according to the B-Spec, but the
+ * particular danger of not doing so is not specified.
+ */
+# define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14)
+#define _3D_CHICKEN3 0x02090
#define MI_MODE 0x0209c
# define VS_TIMER_DISPATCH (1 << 6)
# define MI_FLUSH_ENABLE (1 << 11)
+#define GFX_MODE 0x02520
+#define GFX_RUN_LIST_ENABLE (1<<15)
+#define GFX_TLB_INVALIDATE_ALWAYS (1<<13)
+#define GFX_SURFACE_FAULT_ENABLE (1<<12)
+#define GFX_REPLAY_MODE (1<<11)
+#define GFX_PSMI_GRANULARITY (1<<10)
+#define GFX_PPGTT_ENABLE (1<<9)
+
#define SCPD0 0x0209c /* 915+ only */
#define IER 0x020a0
#define IIR 0x020a4
@@ -461,7 +520,7 @@
#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3)
#define GEN6_BSD_IMR 0x120a8
-#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12)
+#define GEN6_BSD_USER_INTERRUPT (1 << 12)
#define GEN6_BSD_RNCID 0x12198
@@ -541,6 +600,18 @@
#define ILK_DISPLAY_CHICKEN1 0x42000
#define ILK_FBCQ_DIS (1<<22)
+#define ILK_PABSTRETCH_DIS (1<<21)
+
+
+/*
+ * Framebuffer compression for Sandybridge
+ *
+ * The following two registers are of type GTTMMADR
+ */
+#define SNB_DPFC_CTL_SA 0x100100
+#define SNB_CPU_FENCE_ENABLE (1<<29)
+#define DPFC_CPU_FENCE_OFFSET 0x100104
+
/*
* GPIO regs
@@ -900,6 +971,8 @@
*/
#define MCHBAR_MIRROR_BASE 0x10000
+#define MCHBAR_MIRROR_BASE_SNB 0x140000
+
/** 915-945 and GM965 MCH register controlling DRAM channel access */
#define DCC 0x10200
#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0)
@@ -1061,9 +1134,50 @@
#define RCBMINAVG 0x111a0
#define RCUPEI 0x111b0
#define RCDNEI 0x111b4
-#define MCHBAR_RENDER_STANDBY 0x111b8
-#define RCX_SW_EXIT (1<<23)
-#define RSX_STATUS_MASK 0x00700000
+#define RSTDBYCTL 0x111b8
+#define RS1EN (1<<31)
+#define RS2EN (1<<30)
+#define RS3EN (1<<29)
+#define D3RS3EN (1<<28) /* Display D3 imlies RS3 */
+#define SWPROMORSX (1<<27) /* RSx promotion timers ignored */
+#define RCWAKERW (1<<26) /* Resetwarn from PCH causes wakeup */
+#define DPRSLPVREN (1<<25) /* Fast voltage ramp enable */
+#define GFXTGHYST (1<<24) /* Hysteresis to allow trunk gating */
+#define RCX_SW_EXIT (1<<23) /* Leave RSx and prevent re-entry */
+#define RSX_STATUS_MASK (7<<20)
+#define RSX_STATUS_ON (0<<20)
+#define RSX_STATUS_RC1 (1<<20)
+#define RSX_STATUS_RC1E (2<<20)
+#define RSX_STATUS_RS1 (3<<20)
+#define RSX_STATUS_RS2 (4<<20) /* aka rc6 */
+#define RSX_STATUS_RSVD (5<<20) /* deep rc6 unsupported on ilk */
+#define RSX_STATUS_RS3 (6<<20) /* rs3 unsupported on ilk */
+#define RSX_STATUS_RSVD2 (7<<20)
+#define UWRCRSXE (1<<19) /* wake counter limit prevents rsx */
+#define RSCRP (1<<18) /* rs requests control on rs1/2 reqs */
+#define JRSC (1<<17) /* rsx coupled to cpu c-state */
+#define RS2INC0 (1<<16) /* allow rs2 in cpu c0 */
+#define RS1CONTSAV_MASK (3<<14)
+#define RS1CONTSAV_NO_RS1 (0<<14) /* rs1 doesn't save/restore context */
+#define RS1CONTSAV_RSVD (1<<14)
+#define RS1CONTSAV_SAVE_RS1 (2<<14) /* rs1 saves context */
+#define RS1CONTSAV_FULL_RS1 (3<<14) /* rs1 saves and restores context */
+#define NORMSLEXLAT_MASK (3<<12)
+#define SLOW_RS123 (0<<12)
+#define SLOW_RS23 (1<<12)
+#define SLOW_RS3 (2<<12)
+#define NORMAL_RS123 (3<<12)
+#define RCMODE_TIMEOUT (1<<11) /* 0 is eval interval method */
+#define IMPROMOEN (1<<10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */
+#define RCENTSYNC (1<<9) /* rs coupled to cpu c-state (3/6/7) */
+#define STATELOCK (1<<7) /* locked to rs_cstate if 0 */
+#define RS_CSTATE_MASK (3<<4)
+#define RS_CSTATE_C367_RS1 (0<<4)
+#define RS_CSTATE_C36_RS1_C7_RS2 (1<<4)
+#define RS_CSTATE_RSVD (2<<4)
+#define RS_CSTATE_C367_RS2 (3<<4)
+#define REDSAVES (1<<3) /* no context save if was idle during rs0 */
+#define REDRESTORES (1<<2) /* no restore if was idle during rs0 */
#define VIDCTL 0x111c0
#define VIDSTS 0x111c8
#define VIDSTART 0x111cc /* 8 bits */
@@ -1119,6 +1233,10 @@
#define DDRMPLL1 0X12c20
#define PEG_BAND_GAP_DATA 0x14d68
+#define GEN6_GT_PERF_STATUS 0x145948
+#define GEN6_RP_STATE_LIMITS 0x145994
+#define GEN6_RP_STATE_CAP 0x145998
+
/*
* Logical Context regs
*/
@@ -1168,7 +1286,6 @@
#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
-#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
/* VGA port control */
@@ -2182,8 +2299,10 @@
#define PIPE_6BPC (2 << 5)
#define PIPE_12BPC (3 << 5)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL)
+#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL)
#define DSPARB 0x70030
#define DSPARB_CSTART_MASK (0x7f << 7)
@@ -2271,8 +2390,13 @@
/* Memory latency timer register */
#define MLTR_ILK 0x11222
+#define MLTR_WM1_SHIFT 0
+#define MLTR_WM2_SHIFT 8
/* the unit of memory self-refresh latency time is 0.5us */
#define ILK_SRLT_MASK 0x3f
+#define ILK_LATENCY(shift) (I915_READ(MLTR_ILK) >> (shift) & ILK_SRLT_MASK)
+#define ILK_READ_WM1_LATENCY() ILK_LATENCY(MLTR_WM1_SHIFT)
+#define ILK_READ_WM2_LATENCY() ILK_LATENCY(MLTR_WM2_SHIFT)
/* define the fifo size on Ironlake */
#define ILK_DISPLAY_FIFO 128
@@ -2291,6 +2415,40 @@
#define ILK_FIFO_LINE_SIZE 64
+/* define the WM info on Sandybridge */
+#define SNB_DISPLAY_FIFO 128
+#define SNB_DISPLAY_MAXWM 0x7f /* bit 16:22 */
+#define SNB_DISPLAY_DFTWM 8
+#define SNB_CURSOR_FIFO 32
+#define SNB_CURSOR_MAXWM 0x1f /* bit 4:0 */
+#define SNB_CURSOR_DFTWM 8
+
+#define SNB_DISPLAY_SR_FIFO 512
+#define SNB_DISPLAY_MAX_SRWM 0x1ff /* bit 16:8 */
+#define SNB_DISPLAY_DFT_SRWM 0x3f
+#define SNB_CURSOR_SR_FIFO 64
+#define SNB_CURSOR_MAX_SRWM 0x3f /* bit 5:0 */
+#define SNB_CURSOR_DFT_SRWM 8
+
+#define SNB_FBC_MAX_SRWM 0xf /* bit 23:20 */
+
+#define SNB_FIFO_LINE_SIZE 64
+
+
+/* the address where we get all kinds of latency value */
+#define SSKPD 0x5d10
+#define SSKPD_WM_MASK 0x3f
+#define SSKPD_WM0_SHIFT 0
+#define SSKPD_WM1_SHIFT 8
+#define SSKPD_WM2_SHIFT 16
+#define SSKPD_WM3_SHIFT 24
+
+#define SNB_LATENCY(shift) (I915_READ(MCHBAR_MIRROR_BASE_SNB + SSKPD) >> (shift) & SSKPD_WM_MASK)
+#define SNB_READ_WM0_LATENCY() SNB_LATENCY(SSKPD_WM0_SHIFT)
+#define SNB_READ_WM1_LATENCY() SNB_LATENCY(SSKPD_WM1_SHIFT)
+#define SNB_READ_WM2_LATENCY() SNB_LATENCY(SSKPD_WM2_SHIFT)
+#define SNB_READ_WM3_LATENCY() SNB_LATENCY(SSKPD_WM3_SHIFT)
+
/*
* The two pipe frame counter registers are not synchronized, so
* reading a stable value is somewhat tricky. The following code
@@ -2351,6 +2509,10 @@
#define CURBBASE 0x700c4
#define CURBPOS 0x700c8
+#define CURCNTR(pipe) _PIPE(pipe, CURACNTR, CURBCNTR)
+#define CURBASE(pipe) _PIPE(pipe, CURABASE, CURBBASE)
+#define CURPOS(pipe) _PIPE(pipe, CURAPOS, CURBPOS)
+
/* Display A control */
#define DSPACNTR 0x70180
#define DISPLAY_PLANE_ENABLE (1<<31)
@@ -2471,6 +2633,9 @@
# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18)
# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1)
+#define PCH_3DCGDIS1 0x46024
+# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11)
+
#define FDI_PLL_FREQ_CTL 0x46030
#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
@@ -2586,10 +2751,21 @@
#define GTIER 0x4401c
#define ILK_DISPLAY_CHICKEN2 0x42004
+/* Required on all Ironlake and Sandybridge according to the B-Spec. */
+#define ILK_ELPIN_409_SELECT (1 << 25)
#define ILK_DPARB_GATE (1<<22)
#define ILK_VSDPFD_FULL (1<<21)
+#define ILK_DISPLAY_CHICKEN_FUSES 0x42014
+#define ILK_INTERNAL_GRAPHICS_DISABLE (1<<31)
+#define ILK_INTERNAL_DISPLAY_DISABLE (1<<30)
+#define ILK_DISPLAY_DEBUG_DISABLE (1<<29)
+#define ILK_HDCP_DISABLE (1<<25)
+#define ILK_eDP_A_DISABLE (1<<24)
+#define ILK_DESKTOP (1<<23)
#define ILK_DSPCLK_GATE 0x42020
#define ILK_DPARB_CLK_GATE (1<<5)
+#define ILK_DPFD_CLK_GATE (1<<7)
+
/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
#define ILK_CLK_FBC (1<<7)
#define ILK_DPFC_DIS1 (1<<8)
@@ -2602,12 +2778,41 @@
/* PCH */
/* south display engine interrupt */
+#define SDE_AUDIO_POWER_D (1 << 27)
+#define SDE_AUDIO_POWER_C (1 << 26)
+#define SDE_AUDIO_POWER_B (1 << 25)
+#define SDE_AUDIO_POWER_SHIFT (25)
+#define SDE_AUDIO_POWER_MASK (7 << SDE_AUDIO_POWER_SHIFT)
+#define SDE_GMBUS (1 << 24)
+#define SDE_AUDIO_HDCP_TRANSB (1 << 23)
+#define SDE_AUDIO_HDCP_TRANSA (1 << 22)
+#define SDE_AUDIO_HDCP_MASK (3 << 22)
+#define SDE_AUDIO_TRANSB (1 << 21)
+#define SDE_AUDIO_TRANSA (1 << 20)
+#define SDE_AUDIO_TRANS_MASK (3 << 20)
+#define SDE_POISON (1 << 19)
+/* 18 reserved */
+#define SDE_FDI_RXB (1 << 17)
+#define SDE_FDI_RXA (1 << 16)
+#define SDE_FDI_MASK (3 << 16)
+#define SDE_AUXD (1 << 15)
+#define SDE_AUXC (1 << 14)
+#define SDE_AUXB (1 << 13)
+#define SDE_AUX_MASK (7 << 13)
+/* 12 reserved */
#define SDE_CRT_HOTPLUG (1 << 11)
#define SDE_PORTD_HOTPLUG (1 << 10)
#define SDE_PORTC_HOTPLUG (1 << 9)
#define SDE_PORTB_HOTPLUG (1 << 8)
#define SDE_SDVOB_HOTPLUG (1 << 6)
#define SDE_HOTPLUG_MASK (0xf << 8)
+#define SDE_TRANSB_CRC_DONE (1 << 5)
+#define SDE_TRANSB_CRC_ERR (1 << 4)
+#define SDE_TRANSB_FIFO_UNDER (1 << 3)
+#define SDE_TRANSA_CRC_DONE (1 << 2)
+#define SDE_TRANSA_CRC_ERR (1 << 1)
+#define SDE_TRANSA_FIFO_UNDER (1 << 0)
+#define SDE_TRANS_MASK (0x3f)
/* CPT */
#define SDE_CRT_HOTPLUG_CPT (1 << 19)
#define SDE_PORTD_HOTPLUG_CPT (1 << 23)
@@ -2669,6 +2874,7 @@
#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
#define PCH_FPA0 0xc6040
+#define FP_CB_TUNE (0x3<<22)
#define PCH_FPA1 0xc6044
#define PCH_FPB0 0xc6048
#define PCH_FPB1 0xc604c
@@ -3033,6 +3239,7 @@
#define TRANS_DP_10BPC (1<<9)
#define TRANS_DP_6BPC (2<<9)
#define TRANS_DP_12BPC (3<<9)
+#define TRANS_DP_BPC_MASK (3<<9)
#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4)
#define TRANS_DP_VSYNC_ACTIVE_LOW 0
#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3)
@@ -3046,10 +3253,74 @@
#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22)
#define EDP_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22)
/* SNB B-stepping */
-#define EDP_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22)
-#define EDP_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22)
-#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22)
-#define EDP_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22)
+#define EDP_LINK_TRAIN_400_600MV_0DB_SNB_B (0x0<<22)
+#define EDP_LINK_TRAIN_400MV_3_5DB_SNB_B (0x1<<22)
+#define EDP_LINK_TRAIN_400_600MV_6DB_SNB_B (0x3a<<22)
+#define EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B (0x39<<22)
+#define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38<<22)
#define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22)
+#define FORCEWAKE 0xA18C
+#define FORCEWAKE_ACK 0x130090
+
+#define GEN6_RPNSWREQ 0xA008
+#define GEN6_TURBO_DISABLE (1<<31)
+#define GEN6_FREQUENCY(x) ((x)<<25)
+#define GEN6_OFFSET(x) ((x)<<19)
+#define GEN6_AGGRESSIVE_TURBO (0<<15)
+#define GEN6_RC_VIDEO_FREQ 0xA00C
+#define GEN6_RC_CONTROL 0xA090
+#define GEN6_RC_CTL_RC6pp_ENABLE (1<<16)
+#define GEN6_RC_CTL_RC6p_ENABLE (1<<17)
+#define GEN6_RC_CTL_RC6_ENABLE (1<<18)
+#define GEN6_RC_CTL_RC1e_ENABLE (1<<20)
+#define GEN6_RC_CTL_RC7_ENABLE (1<<22)
+#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27)
+#define GEN6_RC_CTL_HW_ENABLE (1<<31)
+#define GEN6_RP_DOWN_TIMEOUT 0xA010
+#define GEN6_RP_INTERRUPT_LIMITS 0xA014
+#define GEN6_RPSTAT1 0xA01C
+#define GEN6_RP_CONTROL 0xA024
+#define GEN6_RP_MEDIA_TURBO (1<<11)
+#define GEN6_RP_USE_NORMAL_FREQ (1<<9)
+#define GEN6_RP_MEDIA_IS_GFX (1<<8)
+#define GEN6_RP_ENABLE (1<<7)
+#define GEN6_RP_UP_BUSY_MAX (0x2<<3)
+#define GEN6_RP_DOWN_BUSY_MIN (0x2<<0)
+#define GEN6_RP_UP_THRESHOLD 0xA02C
+#define GEN6_RP_DOWN_THRESHOLD 0xA030
+#define GEN6_RP_UP_EI 0xA068
+#define GEN6_RP_DOWN_EI 0xA06C
+#define GEN6_RP_IDLE_HYSTERSIS 0xA070
+#define GEN6_RC_STATE 0xA094
+#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098
+#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C
+#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0
+#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8
+#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC
+#define GEN6_RC_SLEEP 0xA0B0
+#define GEN6_RC1e_THRESHOLD 0xA0B4
+#define GEN6_RC6_THRESHOLD 0xA0B8
+#define GEN6_RC6p_THRESHOLD 0xA0BC
+#define GEN6_RC6pp_THRESHOLD 0xA0C0
+#define GEN6_PMINTRMSK 0xA168
+
+#define GEN6_PMISR 0x44020
+#define GEN6_PMIMR 0x44024
+#define GEN6_PMIIR 0x44028
+#define GEN6_PMIER 0x4402C
+#define GEN6_PM_MBOX_EVENT (1<<25)
+#define GEN6_PM_THERMAL_EVENT (1<<24)
+#define GEN6_PM_RP_DOWN_TIMEOUT (1<<6)
+#define GEN6_PM_RP_UP_THRESHOLD (1<<5)
+#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4)
+#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2)
+#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1)
+
+#define GEN6_PCODE_MAILBOX 0x138124
+#define GEN6_PCODE_READY (1<<31)
+#define GEN6_READ_OC_PARAMS 0xc
+#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x9
+#define GEN6_PCODE_DATA 0x138128
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 989c19d2d959..0521ecf26017 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -235,10 +235,21 @@ static void i915_restore_vga(struct drm_device *dev)
static void i915_save_modeset_reg(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
+ /* Cursor state */
+ dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+ dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+ dev_priv->saveCURABASE = I915_READ(CURABASE);
+ dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+ dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+ dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+ if (IS_GEN2(dev))
+ dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
@@ -357,6 +368,28 @@ static void i915_save_modeset_reg(struct drm_device *dev)
}
i915_save_palette(dev, PIPE_B);
dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+
+ /* Fences */
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
+ break;
+ case 5:
+ case 4:
+ for (i = 0; i < 16; i++)
+ dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
+ break;
+ case 3:
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ for (i = 0; i < 8; i++)
+ dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+ case 2:
+ for (i = 0; i < 8; i++)
+ dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+ break;
+ }
+
return;
}
@@ -365,10 +398,33 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int dpll_a_reg, fpa0_reg, fpa1_reg;
int dpll_b_reg, fpb0_reg, fpb1_reg;
+ int i;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
+ /* Fences */
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]);
+ break;
+ case 5:
+ case 4:
+ for (i = 0; i < 16; i++)
+ I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]);
+ break;
+ case 3:
+ case 2:
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
+ break;
+ }
+
+
if (HAS_PCH_SPLIT(dev)) {
dpll_a_reg = PCH_DPLL_A;
dpll_b_reg = PCH_DPLL_B;
@@ -529,6 +585,16 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
+ /* Cursor state */
+ I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+ I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+ I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+ I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+ I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+ I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+ if (IS_GEN2(dev))
+ I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
return;
}
@@ -543,16 +609,6 @@ void i915_save_display(struct drm_device *dev)
/* Don't save them in KMS mode */
i915_save_modeset_reg(dev);
- /* Cursor state */
- dev_priv->saveCURACNTR = I915_READ(CURACNTR);
- dev_priv->saveCURAPOS = I915_READ(CURAPOS);
- dev_priv->saveCURABASE = I915_READ(CURABASE);
- dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
- dev_priv->saveCURBPOS = I915_READ(CURBPOS);
- dev_priv->saveCURBBASE = I915_READ(CURBBASE);
- if (IS_GEN2(dev))
- dev_priv->saveCURSIZE = I915_READ(CURSIZE);
-
/* CRT state */
if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveADPA = I915_READ(PCH_ADPA);
@@ -657,16 +713,6 @@ void i915_restore_display(struct drm_device *dev)
/* Don't restore them in KMS mode */
i915_restore_modeset_reg(dev);
- /* Cursor state */
- I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
- I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
- I915_WRITE(CURABASE, dev_priv->saveCURABASE);
- I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
- I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
- I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
- if (IS_GEN2(dev))
- I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
-
/* CRT state */
if (HAS_PCH_SPLIT(dev))
I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
@@ -694,7 +740,7 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
- I915_WRITE(MCHBAR_RENDER_STANDBY,
+ I915_WRITE(RSTDBYCTL,
dev_priv->saveMCHBAR_RENDER_STANDBY);
} else {
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
@@ -765,14 +811,16 @@ int i915_save_state(struct drm_device *dev)
dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
dev_priv->saveMCHBAR_RENDER_STANDBY =
- I915_READ(MCHBAR_RENDER_STANDBY);
+ I915_READ(RSTDBYCTL);
} else {
dev_priv->saveIER = I915_READ(IER);
dev_priv->saveIMR = I915_READ(IMR);
}
- if (HAS_PCH_SPLIT(dev))
+ if (IS_IRONLAKE_M(dev))
ironlake_disable_drps(dev);
+ if (IS_GEN6(dev))
+ gen6_disable_rps(dev);
/* Cache mode state */
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
@@ -788,28 +836,6 @@ int i915_save_state(struct drm_device *dev)
for (i = 0; i < 3; i++)
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
- /* Fences */
- switch (INTEL_INFO(dev)->gen) {
- case 6:
- for (i = 0; i < 16; i++)
- dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
- break;
- case 5:
- case 4:
- for (i = 0; i < 16; i++)
- dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
- break;
- case 3:
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- for (i = 0; i < 8; i++)
- dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
- case 2:
- for (i = 0; i < 8; i++)
- dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
- break;
-
- }
-
return 0;
}
@@ -823,27 +849,6 @@ int i915_restore_state(struct drm_device *dev)
/* Hardware status page */
I915_WRITE(HWS_PGA, dev_priv->saveHWS);
- /* Fences */
- switch (INTEL_INFO(dev)->gen) {
- case 6:
- for (i = 0; i < 16; i++)
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]);
- break;
- case 5:
- case 4:
- for (i = 0; i < 16; i++)
- I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]);
- break;
- case 3:
- case 2:
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
- break;
- }
-
i915_restore_display(dev);
/* Interrupt state */
@@ -860,10 +865,15 @@ int i915_restore_state(struct drm_device *dev)
}
/* Clock gating state */
- intel_init_clock_gating(dev);
+ intel_enable_clock_gating(dev);
- if (HAS_PCH_SPLIT(dev))
+ if (IS_IRONLAKE_M(dev)) {
ironlake_enable_drps(dev);
+ intel_init_emon(dev);
+ }
+
+ if (IS_GEN6(dev))
+ gen6_enable_rps(dev_priv);
/* Cache mode state */
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index fea97a21cc14..7f0fc3ed61aa 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -6,6 +6,7 @@
#include <linux/tracepoint.h>
#include <drm/drmP.h>
+#include "i915_drv.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM i915
@@ -16,18 +17,18 @@
TRACE_EVENT(i915_gem_object_create,
- TP_PROTO(struct drm_gem_object *obj),
+ TP_PROTO(struct drm_i915_gem_object *obj),
TP_ARGS(obj),
TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
__field(u32, size)
),
TP_fast_assign(
__entry->obj = obj;
- __entry->size = obj->size;
+ __entry->size = obj->base.size;
),
TP_printk("obj=%p, size=%u", __entry->obj, __entry->size)
@@ -35,40 +36,43 @@ TRACE_EVENT(i915_gem_object_create,
TRACE_EVENT(i915_gem_object_bind,
- TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset),
+ TP_PROTO(struct drm_i915_gem_object *obj, u32 gtt_offset, bool mappable),
- TP_ARGS(obj, gtt_offset),
+ TP_ARGS(obj, gtt_offset, mappable),
TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
__field(u32, gtt_offset)
+ __field(bool, mappable)
),
TP_fast_assign(
__entry->obj = obj;
__entry->gtt_offset = gtt_offset;
+ __entry->mappable = mappable;
),
- TP_printk("obj=%p, gtt_offset=%08x",
- __entry->obj, __entry->gtt_offset)
+ TP_printk("obj=%p, gtt_offset=%08x%s",
+ __entry->obj, __entry->gtt_offset,
+ __entry->mappable ? ", mappable" : "")
);
TRACE_EVENT(i915_gem_object_change_domain,
- TP_PROTO(struct drm_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain),
+ TP_PROTO(struct drm_i915_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain),
TP_ARGS(obj, old_read_domains, old_write_domain),
TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
__field(u32, read_domains)
__field(u32, write_domain)
),
TP_fast_assign(
__entry->obj = obj;
- __entry->read_domains = obj->read_domains | (old_read_domains << 16);
- __entry->write_domain = obj->write_domain | (old_write_domain << 16);
+ __entry->read_domains = obj->base.read_domains | (old_read_domains << 16);
+ __entry->write_domain = obj->base.write_domain | (old_write_domain << 16);
),
TP_printk("obj=%p, read=%04x, write=%04x",
@@ -76,36 +80,14 @@ TRACE_EVENT(i915_gem_object_change_domain,
__entry->read_domains, __entry->write_domain)
);
-TRACE_EVENT(i915_gem_object_get_fence,
-
- TP_PROTO(struct drm_gem_object *obj, int fence, int tiling_mode),
-
- TP_ARGS(obj, fence, tiling_mode),
-
- TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
- __field(int, fence)
- __field(int, tiling_mode)
- ),
-
- TP_fast_assign(
- __entry->obj = obj;
- __entry->fence = fence;
- __entry->tiling_mode = tiling_mode;
- ),
-
- TP_printk("obj=%p, fence=%d, tiling=%d",
- __entry->obj, __entry->fence, __entry->tiling_mode)
-);
-
DECLARE_EVENT_CLASS(i915_gem_object,
- TP_PROTO(struct drm_gem_object *obj),
+ TP_PROTO(struct drm_i915_gem_object *obj),
TP_ARGS(obj),
TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
),
TP_fast_assign(
@@ -117,21 +99,21 @@ DECLARE_EVENT_CLASS(i915_gem_object,
DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush,
- TP_PROTO(struct drm_gem_object *obj),
+ TP_PROTO(struct drm_i915_gem_object *obj),
TP_ARGS(obj)
);
DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind,
- TP_PROTO(struct drm_gem_object *obj),
+ TP_PROTO(struct drm_i915_gem_object *obj),
TP_ARGS(obj)
);
DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy,
- TP_PROTO(struct drm_gem_object *obj),
+ TP_PROTO(struct drm_i915_gem_object *obj),
TP_ARGS(obj)
);
@@ -263,13 +245,13 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end,
);
TRACE_EVENT(i915_flip_request,
- TP_PROTO(int plane, struct drm_gem_object *obj),
+ TP_PROTO(int plane, struct drm_i915_gem_object *obj),
TP_ARGS(plane, obj),
TP_STRUCT__entry(
__field(int, plane)
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
),
TP_fast_assign(
@@ -281,13 +263,13 @@ TRACE_EVENT(i915_flip_request,
);
TRACE_EVENT(i915_flip_complete,
- TP_PROTO(int plane, struct drm_gem_object *obj),
+ TP_PROTO(int plane, struct drm_i915_gem_object *obj),
TP_ARGS(plane, obj),
TP_STRUCT__entry(
__field(int, plane)
- __field(struct drm_gem_object *, obj)
+ __field(struct drm_i915_gem_object *, obj)
),
TP_fast_assign(
@@ -298,6 +280,29 @@ TRACE_EVENT(i915_flip_complete,
TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
);
+TRACE_EVENT(i915_reg_rw,
+ TP_PROTO(int cmd, uint32_t reg, uint64_t val, int len),
+
+ TP_ARGS(cmd, reg, val, len),
+
+ TP_STRUCT__entry(
+ __field(int, cmd)
+ __field(uint32_t, reg)
+ __field(uint64_t, val)
+ __field(int, len)
+ ),
+
+ TP_fast_assign(
+ __entry->cmd = cmd;
+ __entry->reg = reg;
+ __entry->val = (uint64_t)val;
+ __entry->len = len;
+ ),
+
+ TP_printk("cmd=%c, reg=0x%x, val=0x%llx, len=%d",
+ __entry->cmd, __entry->reg, __entry->val, __entry->len)
+);
+
#endif /* _I915_TRACE_H_ */
/* This part must be outside protection */
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index 65c88f9ba12c..2cb8e0b9f1ee 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -190,37 +190,6 @@ out:
kfree(output.pointer);
}
-static int intel_dsm_switchto(enum vga_switcheroo_client_id id)
-{
- return 0;
-}
-
-static int intel_dsm_power_state(enum vga_switcheroo_client_id id,
- enum vga_switcheroo_state state)
-{
- return 0;
-}
-
-static int intel_dsm_init(void)
-{
- return 0;
-}
-
-static int intel_dsm_get_client_id(struct pci_dev *pdev)
-{
- if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
- return VGA_SWITCHEROO_IGD;
- else
- return VGA_SWITCHEROO_DIS;
-}
-
-static struct vga_switcheroo_handler intel_dsm_handler = {
- .switchto = intel_dsm_switchto,
- .power_state = intel_dsm_power_state,
- .init = intel_dsm_init,
- .get_client_id = intel_dsm_get_client_id,
-};
-
static bool intel_dsm_pci_probe(struct pci_dev *pdev)
{
acpi_handle dhandle, intel_handle;
@@ -276,11 +245,8 @@ void intel_register_dsm_handler(void)
{
if (!intel_dsm_detect())
return;
-
- vga_switcheroo_register_handler(&intel_dsm_handler);
}
void intel_unregister_dsm_handler(void)
{
- vga_switcheroo_unregister_handler();
}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b0b1200ed650..0b44956c336b 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -264,17 +264,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->int_crt_support = general->int_crt_support;
dev_priv->lvds_use_ssc = general->enable_ssc;
- if (dev_priv->lvds_use_ssc) {
- if (IS_I85X(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 66 : 48;
- else if (IS_GEN5(dev) || IS_GEN6(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 120;
- else
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 96;
- }
+ if (IS_I85X(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120;
+ else
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
}
}
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index c55c77043357..17035b87ee46 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -30,10 +30,30 @@
#include "drm.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
+#include "drm_edid.h"
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
+/* Here's the desired hotplug mode */
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \
+ ADPA_CRT_HOTPLUG_WARMUP_10MS | \
+ ADPA_CRT_HOTPLUG_SAMPLE_4S | \
+ ADPA_CRT_HOTPLUG_VOLTAGE_50 | \
+ ADPA_CRT_HOTPLUG_VOLREF_325MV | \
+ ADPA_CRT_HOTPLUG_ENABLE)
+
+struct intel_crt {
+ struct intel_encoder base;
+ bool force_hotplug_required;
+};
+
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_crt, base);
+}
+
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
@@ -129,7 +149,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
}
- adpa = 0;
+ adpa = ADPA_HOTPLUG_BITS;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -157,53 +177,44 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
+ struct intel_crt *crt = intel_attached_crt(connector);
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 adpa, temp;
+ u32 adpa;
bool ret;
- bool turn_off_dac = false;
- temp = adpa = I915_READ(PCH_ADPA);
+ /* The first time through, trigger an explicit detection cycle */
+ if (crt->force_hotplug_required) {
+ bool turn_off_dac = HAS_PCH_SPLIT(dev);
+ u32 save_adpa;
- if (HAS_PCH_SPLIT(dev))
- turn_off_dac = true;
-
- adpa &= ~ADPA_CRT_HOTPLUG_MASK;
- if (turn_off_dac)
- adpa &= ~ADPA_DAC_ENABLE;
-
- /* disable HPD first */
- I915_WRITE(PCH_ADPA, adpa);
- (void)I915_READ(PCH_ADPA);
-
- adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
- ADPA_CRT_HOTPLUG_WARMUP_10MS |
- ADPA_CRT_HOTPLUG_SAMPLE_4S |
- ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
- ADPA_CRT_HOTPLUG_VOLREF_325MV |
- ADPA_CRT_HOTPLUG_ENABLE |
- ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
-
- DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
- I915_WRITE(PCH_ADPA, adpa);
-
- if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
- 1000))
- DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
-
- if (turn_off_dac) {
- /* Make sure hotplug is enabled */
- I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
- (void)I915_READ(PCH_ADPA);
+ crt->force_hotplug_required = 0;
+
+ save_adpa = adpa = I915_READ(PCH_ADPA);
+ DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
+
+ adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+ if (turn_off_dac)
+ adpa &= ~ADPA_DAC_ENABLE;
+
+ I915_WRITE(PCH_ADPA, adpa);
+
+ if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
+ 1000))
+ DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+
+ if (turn_off_dac) {
+ I915_WRITE(PCH_ADPA, save_adpa);
+ POSTING_READ(PCH_ADPA);
+ }
}
/* Check the status to see if both blue and green are on now */
adpa = I915_READ(PCH_ADPA);
- adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
- if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
- (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
+ if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
ret = true;
else
ret = false;
+ DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
return ret;
}
@@ -277,13 +288,13 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
}
-static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
+static bool intel_crt_detect_ddc(struct drm_connector *connector)
{
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
- struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+ struct intel_crt *crt = intel_attached_crt(connector);
+ struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
/* CRT should always be at 0, but check anyway */
- if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
+ if (crt->base.type != INTEL_OUTPUT_ANALOG)
return false;
if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
@@ -291,18 +302,36 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
return true;
}
- if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
- DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
- return true;
+ if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
+ struct edid *edid;
+ bool is_digital = false;
+
+ edid = drm_get_edid(connector,
+ &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ /*
+ * This may be a DVI-I connector with a shared DDC
+ * link between analog and digital outputs, so we
+ * have to check the EDID input spec of the attached device.
+ */
+ if (edid != NULL) {
+ is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
+ }
+
+ if (!is_digital) {
+ DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+ return true;
+ }
}
return false;
}
static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
{
- struct drm_encoder *encoder = &intel_encoder->base;
+ struct drm_encoder *encoder = &crt->base.base;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -434,7 +463,7 @@ static enum drm_connector_status
intel_crt_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
- struct intel_encoder *encoder = intel_attached_encoder(connector);
+ struct intel_crt *crt = intel_attached_crt(connector);
struct drm_crtc *crtc;
int dpms_mode;
enum drm_connector_status status;
@@ -443,28 +472,31 @@ intel_crt_detect(struct drm_connector *connector, bool force)
if (intel_crt_detect_hotplug(connector)) {
DRM_DEBUG_KMS("CRT detected via hotplug\n");
return connector_status_connected;
- } else
+ } else {
+ DRM_DEBUG_KMS("CRT not detected via hotplug\n");
return connector_status_disconnected;
+ }
}
- if (intel_crt_detect_ddc(&encoder->base))
+ if (intel_crt_detect_ddc(connector))
return connector_status_connected;
if (!force)
return connector->status;
/* for pre-945g platforms use load detect */
- if (encoder->base.crtc && encoder->base.crtc->enabled) {
- status = intel_crt_load_detect(encoder->base.crtc, encoder);
+ crtc = crt->base.base.crtc;
+ if (crtc && crtc->enabled) {
+ status = intel_crt_load_detect(crtc, crt);
} else {
- crtc = intel_get_load_detect_pipe(encoder, connector,
+ crtc = intel_get_load_detect_pipe(&crt->base, connector,
NULL, &dpms_mode);
if (crtc) {
- if (intel_crt_detect_ddc(&encoder->base))
+ if (intel_crt_detect_ddc(connector))
status = connector_status_connected;
else
- status = intel_crt_load_detect(crtc, encoder);
- intel_release_load_detect_pipe(encoder,
+ status = intel_crt_load_detect(crtc, crt);
+ intel_release_load_detect_pipe(&crt->base,
connector, dpms_mode);
} else
status = connector_status_unknown;
@@ -536,17 +568,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
- struct intel_encoder *intel_encoder;
+ struct intel_crt *crt;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
- intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
- if (!intel_encoder)
+ crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
+ if (!crt)
return;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
- kfree(intel_encoder);
+ kfree(crt);
return;
}
@@ -554,20 +586,20 @@ void intel_crt_init(struct drm_device *dev)
drm_connector_init(dev, &intel_connector->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
- drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
+ drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC);
- intel_connector_attach_encoder(intel_connector, intel_encoder);
+ intel_connector_attach_encoder(intel_connector, &crt->base);
- intel_encoder->type = INTEL_OUTPUT_ANALOG;
- intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
- (1 << INTEL_ANALOG_CLONE_BIT) |
- (1 << INTEL_SDVO_LVDS_CLONE_BIT);
- intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+ crt->base.type = INTEL_OUTPUT_ANALOG;
+ crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
+ 1 << INTEL_ANALOG_CLONE_BIT |
+ 1 << INTEL_SDVO_LVDS_CLONE_BIT);
+ crt->base.crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
- drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
+ drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
@@ -577,5 +609,22 @@ void intel_crt_init(struct drm_device *dev)
else
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ /*
+ * Configure the automatic hotplug detection stuff
+ */
+ crt->force_hotplug_required = 0;
+ if (HAS_PCH_SPLIT(dev)) {
+ u32 adpa;
+
+ adpa = I915_READ(PCH_ADPA);
+ adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+ adpa |= ADPA_HOTPLUG_BITS;
+ I915_WRITE(PCH_ADPA, adpa);
+ POSTING_READ(PCH_ADPA);
+
+ DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
+ crt->force_hotplug_required = 1;
+ }
+
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 990f065374b2..98967f3b7724 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -642,26 +642,23 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
.find_pll = intel_find_pll_ironlake_dp,
};
-static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
+static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
+ int refclk)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
const intel_limit_t *limit;
- int refclk = 120;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100)
- refclk = 100;
-
if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP) {
/* LVDS dual channel */
- if (refclk == 100)
+ if (refclk == 100000)
limit = &intel_limits_ironlake_dual_lvds_100m;
else
limit = &intel_limits_ironlake_dual_lvds;
} else {
- if (refclk == 100)
+ if (refclk == 100000)
limit = &intel_limits_ironlake_single_lvds_100m;
else
limit = &intel_limits_ironlake_single_lvds;
@@ -702,13 +699,13 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
return limit;
}
-static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
+static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk)
{
struct drm_device *dev = crtc->dev;
const intel_limit_t *limit;
if (HAS_PCH_SPLIT(dev))
- limit = intel_ironlake_limit(crtc);
+ limit = intel_ironlake_limit(crtc, refclk);
else if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc);
} else if (IS_PINEVIEW(dev)) {
@@ -773,11 +770,10 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
* the given connectors.
*/
-static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
+static bool intel_PLL_is_valid(struct drm_device *dev,
+ const intel_limit_t *limit,
+ const intel_clock_t *clock)
{
- const intel_limit_t *limit = intel_limit (crtc);
- struct drm_device *dev = crtc->dev;
-
if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
INTELPllInvalid ("p1 out of range\n");
if (clock->p < limit->p.min || limit->p.max < clock->p)
@@ -849,8 +845,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int this_err;
intel_clock(dev, refclk, &clock);
-
- if (!intel_PLL_is_valid(crtc, &clock))
+ if (!intel_PLL_is_valid(dev, limit,
+ &clock))
continue;
this_err = abs(clock.dot - target);
@@ -912,9 +908,11 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int this_err;
intel_clock(dev, refclk, &clock);
- if (!intel_PLL_is_valid(crtc, &clock))
+ if (!intel_PLL_is_valid(dev, limit,
+ &clock))
continue;
- this_err = abs(clock.dot - target) ;
+
+ this_err = abs(clock.dot - target);
if (this_err < err_most) {
*best_clock = clock;
err_most = this_err;
@@ -1066,13 +1064,13 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane, i;
u32 fbc_ctl, fbc_ctl2;
if (fb->pitch == dev_priv->cfb_pitch &&
- obj_priv->fence_reg == dev_priv->cfb_fence &&
+ obj->fence_reg == dev_priv->cfb_fence &&
intel_crtc->plane == dev_priv->cfb_plane &&
I915_READ(FBC_CONTROL) & FBC_CTL_EN)
return;
@@ -1086,7 +1084,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
/* FBC_CTL wants 64B units */
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
- dev_priv->cfb_fence = obj_priv->fence_reg;
+ dev_priv->cfb_fence = obj->fence_reg;
dev_priv->cfb_plane = intel_crtc->plane;
plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
@@ -1096,7 +1094,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
/* Set it up... */
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane;
- if (obj_priv->tiling_mode != I915_TILING_NONE)
+ if (obj->tiling_mode != I915_TILING_NONE)
fbc_ctl2 |= FBC_CTL_CPU_FENCE;
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
I915_WRITE(FBC_FENCE_OFF, crtc->y);
@@ -1107,7 +1105,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
- if (obj_priv->tiling_mode != I915_TILING_NONE)
+ if (obj->tiling_mode != I915_TILING_NONE)
fbc_ctl |= dev_priv->cfb_fence;
I915_WRITE(FBC_CONTROL, fbc_ctl);
@@ -1150,7 +1148,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
unsigned long stall_watermark = 200;
@@ -1159,7 +1157,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
dpfc_ctl = I915_READ(DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
- dev_priv->cfb_fence == obj_priv->fence_reg &&
+ dev_priv->cfb_fence == obj->fence_reg &&
dev_priv->cfb_plane == intel_crtc->plane &&
dev_priv->cfb_y == crtc->y)
return;
@@ -1170,12 +1168,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
}
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
- dev_priv->cfb_fence = obj_priv->fence_reg;
+ dev_priv->cfb_fence = obj->fence_reg;
dev_priv->cfb_plane = intel_crtc->plane;
dev_priv->cfb_y = crtc->y;
dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
- if (obj_priv->tiling_mode != I915_TILING_NONE) {
+ if (obj->tiling_mode != I915_TILING_NONE) {
dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
} else {
@@ -1221,7 +1219,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
unsigned long stall_watermark = 200;
@@ -1230,9 +1228,9 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
- dev_priv->cfb_fence == obj_priv->fence_reg &&
+ dev_priv->cfb_fence == obj->fence_reg &&
dev_priv->cfb_plane == intel_crtc->plane &&
- dev_priv->cfb_offset == obj_priv->gtt_offset &&
+ dev_priv->cfb_offset == obj->gtt_offset &&
dev_priv->cfb_y == crtc->y)
return;
@@ -1242,14 +1240,14 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
}
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
- dev_priv->cfb_fence = obj_priv->fence_reg;
+ dev_priv->cfb_fence = obj->fence_reg;
dev_priv->cfb_plane = intel_crtc->plane;
- dev_priv->cfb_offset = obj_priv->gtt_offset;
+ dev_priv->cfb_offset = obj->gtt_offset;
dev_priv->cfb_y = crtc->y;
dpfc_ctl &= DPFC_RESERVED;
dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
- if (obj_priv->tiling_mode != I915_TILING_NONE) {
+ if (obj->tiling_mode != I915_TILING_NONE) {
dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
} else {
@@ -1260,10 +1258,16 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
(interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
- I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
+ I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+ if (IS_GEN6(dev)) {
+ I915_WRITE(SNB_DPFC_CTL_SA,
+ SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+ }
+
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
}
@@ -1345,7 +1349,7 @@ static void intel_update_fbc(struct drm_device *dev)
struct intel_crtc *intel_crtc;
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
DRM_DEBUG_KMS("\n");
@@ -1384,9 +1388,9 @@ static void intel_update_fbc(struct drm_device *dev)
intel_crtc = to_intel_crtc(crtc);
fb = crtc->fb;
intel_fb = to_intel_framebuffer(fb);
- obj_priv = to_intel_bo(intel_fb->obj);
+ obj = intel_fb->obj;
- if (intel_fb->obj->size > dev_priv->cfb_size) {
+ if (intel_fb->obj->base.size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling "
"compression\n");
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
@@ -1410,7 +1414,7 @@ static void intel_update_fbc(struct drm_device *dev)
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
goto out_disable;
}
- if (obj_priv->tiling_mode != I915_TILING_X) {
+ if (obj->tiling_mode != I915_TILING_X) {
DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
dev_priv->no_fbc_reason = FBC_NOT_TILED;
goto out_disable;
@@ -1433,14 +1437,13 @@ out_disable:
int
intel_pin_and_fence_fb_obj(struct drm_device *dev,
- struct drm_gem_object *obj,
- bool pipelined)
+ struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
u32 alignment;
int ret;
- switch (obj_priv->tiling_mode) {
+ switch (obj->tiling_mode) {
case I915_TILING_NONE:
if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
alignment = 128 * 1024;
@@ -1461,7 +1464,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
BUG();
}
- ret = i915_gem_object_pin(obj, alignment);
+ ret = i915_gem_object_pin(obj, alignment, true);
if (ret)
return ret;
@@ -1474,9 +1477,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
* framebuffer compression. For simplicity, we always install
* a fence as the cost is not that onerous.
*/
- if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
- obj_priv->tiling_mode != I915_TILING_NONE) {
- ret = i915_gem_object_get_fence_reg(obj, false);
+ if (obj->tiling_mode != I915_TILING_NONE) {
+ ret = i915_gem_object_get_fence(obj, pipelined, false);
if (ret)
goto err_unpin;
}
@@ -1497,8 +1499,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_framebuffer *intel_fb;
- struct drm_i915_gem_object *obj_priv;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
int plane = intel_crtc->plane;
unsigned long Start, Offset;
u32 dspcntr;
@@ -1515,7 +1516,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
- obj_priv = to_intel_bo(obj);
reg = DSPCNTR(plane);
dspcntr = I915_READ(reg);
@@ -1540,7 +1540,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
return -EINVAL;
}
if (INTEL_INFO(dev)->gen >= 4) {
- if (obj_priv->tiling_mode != I915_TILING_NONE)
+ if (obj->tiling_mode != I915_TILING_NONE)
dspcntr |= DISPPLANE_TILED;
else
dspcntr &= ~DISPPLANE_TILED;
@@ -1552,7 +1552,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
I915_WRITE(reg, dspcntr);
- Start = obj_priv->gtt_offset;
+ Start = obj->gtt_offset;
Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
@@ -1598,7 +1598,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev,
to_intel_framebuffer(crtc->fb)->obj,
- false);
+ NULL);
if (ret != 0) {
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -1606,11 +1606,22 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (old_fb) {
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
wait_event(dev_priv->pending_flip_queue,
- atomic_read(&obj_priv->pending_flip) == 0);
+ atomic_read(&obj->pending_flip) == 0);
+
+ /* Big Hammer, we also need to ensure that any pending
+ * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+ * current scanout is retired before unpinning the old
+ * framebuffer.
+ */
+ ret = i915_gem_object_flush_gpu(obj, false);
+ if (ret) {
+ i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
}
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
@@ -1621,8 +1632,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
- if (old_fb)
+ if (old_fb) {
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
+ }
mutex_unlock(&dev->struct_mutex);
@@ -1681,6 +1694,37 @@ static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
udelay(500);
}
+static void intel_fdi_normal_train(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 reg, temp;
+
+ /* enable normal train */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+ I915_WRITE(reg, temp);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ if (HAS_PCH_CPT(dev)) {
+ temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+ temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+ } else {
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_NONE;
+ }
+ I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+ /* wait one idle pattern time */
+ POSTING_READ(reg);
+ udelay(1000);
+}
+
/* The FDI link training functions for ILK/Ibexpeak. */
static void ironlake_fdi_link_train(struct drm_crtc *crtc)
{
@@ -1767,27 +1811,6 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
DRM_DEBUG_KMS("FDI train done\n");
- /* enable normal train */
- reg = FDI_TX_CTL(pipe);
- temp = I915_READ(reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
- I915_WRITE(reg, temp);
-
- reg = FDI_RX_CTL(pipe);
- temp = I915_READ(reg);
- if (HAS_PCH_CPT(dev)) {
- temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
- temp |= FDI_LINK_TRAIN_NORMAL_CPT;
- } else {
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_NONE;
- }
- I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-
- /* wait one idle pattern time */
- POSTING_READ(reg);
- udelay(1000);
}
static const int const snb_b_fdi_train_param [] = {
@@ -1974,31 +1997,31 @@ static void intel_flush_display_plane(struct drm_device *dev,
static void intel_clear_scanline_wait(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
u32 tmp;
if (IS_GEN2(dev))
/* Can't break the hang on i8xx */
return;
- tmp = I915_READ(PRB0_CTL);
- if (tmp & RING_WAIT) {
- I915_WRITE(PRB0_CTL, tmp);
- POSTING_READ(PRB0_CTL);
- }
+ ring = LP_RING(dev_priv);
+ tmp = I915_READ_CTL(ring);
+ if (tmp & RING_WAIT)
+ I915_WRITE_CTL(ring, tmp);
}
static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
{
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
struct drm_i915_private *dev_priv;
if (crtc->fb == NULL)
return;
- obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+ obj = to_intel_framebuffer(crtc->fb)->obj;
dev_priv = crtc->dev->dev_private;
wait_event(dev_priv->pending_flip_queue,
- atomic_read(&obj_priv->pending_flip) == 0);
+ atomic_read(&obj->pending_flip) == 0);
}
static void ironlake_crtc_enable(struct drm_crtc *crtc)
@@ -2090,15 +2113,19 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
+ intel_fdi_normal_train(crtc);
+
/* For PCH DP, enable TRANS_DP_CTL */
if (HAS_PCH_CPT(dev) &&
intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
reg = TRANS_DP_CTL(pipe);
temp = I915_READ(reg);
temp &= ~(TRANS_DP_PORT_SEL_MASK |
- TRANS_DP_SYNC_MASK);
+ TRANS_DP_SYNC_MASK |
+ TRANS_DP_BPC_MASK);
temp |= (TRANS_DP_OUTPUT_ENABLE |
TRANS_DP_ENH_FRAMING);
+ temp |= TRANS_DP_8BPC;
if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
@@ -2200,9 +2227,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
udelay(100);
/* Ironlake workaround, disable clock pointer after downing FDI */
- I915_WRITE(FDI_RX_CHICKEN(pipe),
- I915_READ(FDI_RX_CHICKEN(pipe) &
- ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+ if (HAS_PCH_IBX(dev))
+ I915_WRITE(FDI_RX_CHICKEN(pipe),
+ I915_READ(FDI_RX_CHICKEN(pipe) &
+ ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
/* still set train pattern 1 */
reg = FDI_TX_CTL(pipe);
@@ -2687,27 +2715,19 @@ fdi_reduce_ratio(u32 *num, u32 *den)
}
}
-#define DATA_N 0x800000
-#define LINK_N 0x80000
-
static void
ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
int link_clock, struct fdi_m_n *m_n)
{
- u64 temp;
-
m_n->tu = 64; /* default size */
- temp = (u64) DATA_N * pixel_clock;
- temp = div_u64(temp, link_clock);
- m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes);
- m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */
- m_n->gmch_n = DATA_N;
+ /* BUG_ON(pixel_clock > INT_MAX / 36); */
+ m_n->gmch_m = bits_per_pixel * pixel_clock;
+ m_n->gmch_n = link_clock * nlanes * 8;
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
- temp = (u64) LINK_N * pixel_clock;
- m_n->link_m = div_u64(temp, link_clock);
- m_n->link_n = LINK_N;
+ m_n->link_m = pixel_clock;
+ m_n->link_n = link_clock;
fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
@@ -2831,6 +2851,39 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = {
ILK_FIFO_LINE_SIZE
};
+static struct intel_watermark_params sandybridge_display_wm_info = {
+ SNB_DISPLAY_FIFO,
+ SNB_DISPLAY_MAXWM,
+ SNB_DISPLAY_DFTWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params sandybridge_cursor_wm_info = {
+ SNB_CURSOR_FIFO,
+ SNB_CURSOR_MAXWM,
+ SNB_CURSOR_DFTWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params sandybridge_display_srwm_info = {
+ SNB_DISPLAY_SR_FIFO,
+ SNB_DISPLAY_MAX_SRWM,
+ SNB_DISPLAY_DFT_SRWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+
+static struct intel_watermark_params sandybridge_cursor_srwm_info = {
+ SNB_CURSOR_SR_FIFO,
+ SNB_CURSOR_MAX_SRWM,
+ SNB_CURSOR_DFT_SRWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+
+
/**
* intel_calculate_wm - calculate watermark level
* @clock_in_khz: pixel clock
@@ -3364,12 +3417,17 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
static bool ironlake_compute_wm0(struct drm_device *dev,
int pipe,
+ const struct intel_watermark_params *display,
+ int display_latency_ns,
+ const struct intel_watermark_params *cursor,
+ int cursor_latency_ns,
int *plane_wm,
int *cursor_wm)
{
struct drm_crtc *crtc;
- int htotal, hdisplay, clock, pixel_size = 0;
- int line_time_us, line_count, entries;
+ int htotal, hdisplay, clock, pixel_size;
+ int line_time_us, line_count;
+ int entries, tlb_miss;
crtc = intel_get_crtc_for_pipe(dev, pipe);
if (crtc->fb == NULL || !crtc->enabled)
@@ -3381,37 +3439,141 @@ static bool ironlake_compute_wm0(struct drm_device *dev,
pixel_size = crtc->fb->bits_per_pixel / 8;
/* Use the small buffer method to calculate plane watermark */
- entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
- entries = DIV_ROUND_UP(entries,
- ironlake_display_wm_info.cacheline_size);
- *plane_wm = entries + ironlake_display_wm_info.guard_size;
- if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
- *plane_wm = ironlake_display_wm_info.max_wm;
+ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
+ tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
+ if (tlb_miss > 0)
+ entries += tlb_miss;
+ entries = DIV_ROUND_UP(entries, display->cacheline_size);
+ *plane_wm = entries + display->guard_size;
+ if (*plane_wm > (int)display->max_wm)
+ *plane_wm = display->max_wm;
/* Use the large buffer method to calculate cursor watermark */
line_time_us = ((htotal * 1000) / clock);
- line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+ line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
entries = line_count * 64 * pixel_size;
- entries = DIV_ROUND_UP(entries,
- ironlake_cursor_wm_info.cacheline_size);
- *cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
- if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
- *cursor_wm = ironlake_cursor_wm_info.max_wm;
+ tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
+ if (tlb_miss > 0)
+ entries += tlb_miss;
+ entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
+ *cursor_wm = entries + cursor->guard_size;
+ if (*cursor_wm > (int)cursor->max_wm)
+ *cursor_wm = (int)cursor->max_wm;
+
+ return true;
+}
+
+/*
+ * Check the wm result.
+ *
+ * If any calculated watermark values is larger than the maximum value that
+ * can be programmed into the associated watermark register, that watermark
+ * must be disabled.
+ */
+static bool ironlake_check_srwm(struct drm_device *dev, int level,
+ int fbc_wm, int display_wm, int cursor_wm,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
+ " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
+
+ if (fbc_wm > SNB_FBC_MAX_SRWM) {
+ DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
+ fbc_wm, SNB_FBC_MAX_SRWM, level);
+
+ /* fbc has it's own way to disable FBC WM */
+ I915_WRITE(DISP_ARB_CTL,
+ I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
+ return false;
+ }
+
+ if (display_wm > display->max_wm) {
+ DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
+ display_wm, SNB_DISPLAY_MAX_SRWM, level);
+ return false;
+ }
+
+ if (cursor_wm > cursor->max_wm) {
+ DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
+ cursor_wm, SNB_CURSOR_MAX_SRWM, level);
+ return false;
+ }
+
+ if (!(fbc_wm || display_wm || cursor_wm)) {
+ DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
+ return false;
+ }
return true;
}
+/*
+ * Compute watermark values of WM[1-3],
+ */
+static bool ironlake_compute_srwm(struct drm_device *dev, int level,
+ int hdisplay, int htotal,
+ int pixel_size, int clock, int latency_ns,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor,
+ int *fbc_wm, int *display_wm, int *cursor_wm)
+{
+
+ unsigned long line_time_us;
+ int line_count, line_size;
+ int small, large;
+ int entries;
+
+ if (!latency_ns) {
+ *fbc_wm = *display_wm = *cursor_wm = 0;
+ return false;
+ }
+
+ line_time_us = (htotal * 1000) / clock;
+ line_count = (latency_ns / line_time_us + 1000) / 1000;
+ line_size = hdisplay * pixel_size;
+
+ /* Use the minimum of the small and large buffer method for primary */
+ small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
+ large = line_count * line_size;
+
+ entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
+ *display_wm = entries + display->guard_size;
+
+ /*
+ * Spec says:
+ * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
+ */
+ *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
+
+ /* calculate the self-refresh watermark for display cursor */
+ entries = line_count * pixel_size * 64;
+ entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
+ *cursor_wm = entries + cursor->guard_size;
+
+ return ironlake_check_srwm(dev, level,
+ *fbc_wm, *display_wm, *cursor_wm,
+ display, cursor);
+}
+
static void ironlake_update_wm(struct drm_device *dev,
int planea_clock, int planeb_clock,
- int sr_hdisplay, int sr_htotal,
+ int hdisplay, int htotal,
int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int plane_wm, cursor_wm, enabled;
- int tmp;
+ int fbc_wm, plane_wm, cursor_wm, enabled;
+ int clock;
enabled = 0;
- if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+ if (ironlake_compute_wm0(dev, 0,
+ &ironlake_display_wm_info,
+ ILK_LP0_PLANE_LATENCY,
+ &ironlake_cursor_wm_info,
+ ILK_LP0_CURSOR_LATENCY,
+ &plane_wm, &cursor_wm)) {
I915_WRITE(WM0_PIPEA_ILK,
(plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
@@ -3420,7 +3582,12 @@ static void ironlake_update_wm(struct drm_device *dev,
enabled++;
}
- if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+ if (ironlake_compute_wm0(dev, 1,
+ &ironlake_display_wm_info,
+ ILK_LP0_PLANE_LATENCY,
+ &ironlake_cursor_wm_info,
+ ILK_LP0_CURSOR_LATENCY,
+ &plane_wm, &cursor_wm)) {
I915_WRITE(WM0_PIPEB_ILK,
(plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
@@ -3433,57 +3600,151 @@ static void ironlake_update_wm(struct drm_device *dev,
* Calculate and update the self-refresh watermark only when one
* display plane is used.
*/
- tmp = 0;
- if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
- unsigned long line_time_us;
- int small, large, plane_fbc;
- int sr_clock, entries;
- int line_count, line_size;
- /* Read the self-refresh latency. The unit is 0.5us */
- int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
- sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = (sr_htotal * 1000) / sr_clock;
+ if (enabled != 1)
+ return;
- /* Use ns/us then divide to preserve precision */
- line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
- / 1000;
- line_size = sr_hdisplay * pixel_size;
+ clock = planea_clock ? planea_clock : planeb_clock;
- /* Use the minimum of the small and large buffer method for primary */
- small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
- large = line_count * line_size;
+ /* WM1 */
+ if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size,
+ clock, ILK_READ_WM1_LATENCY() * 500,
+ &ironlake_display_srwm_info,
+ &ironlake_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
- entries = DIV_ROUND_UP(min(small, large),
- ironlake_display_srwm_info.cacheline_size);
+ I915_WRITE(WM1_LP_ILK,
+ WM1_LP_SR_EN |
+ (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM2 */
+ if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size,
+ clock, ILK_READ_WM2_LATENCY() * 500,
+ &ironlake_display_srwm_info,
+ &ironlake_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
- plane_fbc = entries * 64;
- plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
+ I915_WRITE(WM2_LP_ILK,
+ WM2_LP_EN |
+ (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
- plane_wm = entries + ironlake_display_srwm_info.guard_size;
- if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
- plane_wm = ironlake_display_srwm_info.max_wm;
+ /*
+ * WM3 is unsupported on ILK, probably because we don't have latency
+ * data for that power state
+ */
+}
- /* calculate the self-refresh watermark for display cursor */
- entries = line_count * pixel_size * 64;
- entries = DIV_ROUND_UP(entries,
- ironlake_cursor_srwm_info.cacheline_size);
+static void sandybridge_update_wm(struct drm_device *dev,
+ int planea_clock, int planeb_clock,
+ int hdisplay, int htotal,
+ int pixel_size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ int fbc_wm, plane_wm, cursor_wm, enabled;
+ int clock;
- cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
- if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
- cursor_wm = ironlake_cursor_srwm_info.max_wm;
+ enabled = 0;
+ if (ironlake_compute_wm0(dev, 0,
+ &sandybridge_display_wm_info, latency,
+ &sandybridge_cursor_wm_info, latency,
+ &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEA_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+ " plane %d, " "cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled++;
+ }
- /* configure watermark and enable self-refresh */
- tmp = (WM1_LP_SR_EN |
- (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
- (plane_fbc << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
- DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
- " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
+ if (ironlake_compute_wm0(dev, 1,
+ &sandybridge_display_wm_info, latency,
+ &sandybridge_cursor_wm_info, latency,
+ &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEB_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+ " plane %d, cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled++;
}
- I915_WRITE(WM1_LP_ILK, tmp);
- /* XXX setup WM2 and WM3 */
+
+ /*
+ * Calculate and update the self-refresh watermark only when one
+ * display plane is used.
+ *
+ * SNB support 3 levels of watermark.
+ *
+ * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
+ * and disabled in the descending order
+ *
+ */
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ if (enabled != 1)
+ return;
+
+ clock = planea_clock ? planea_clock : planeb_clock;
+
+ /* WM1 */
+ if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size,
+ clock, SNB_READ_WM1_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM1_LP_ILK,
+ WM1_LP_SR_EN |
+ (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM2 */
+ if (!ironlake_compute_srwm(dev, 2,
+ hdisplay, htotal, pixel_size,
+ clock, SNB_READ_WM2_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM2_LP_ILK,
+ WM2_LP_EN |
+ (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM3 */
+ if (!ironlake_compute_srwm(dev, 3,
+ hdisplay, htotal, pixel_size,
+ clock, SNB_READ_WM3_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM3_LP_ILK,
+ WM3_LP_EN |
+ (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
}
/**
@@ -3561,6 +3822,11 @@ static void intel_update_watermarks(struct drm_device *dev)
sr_hdisplay, sr_htotal, pixel_size);
}
+static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+ return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
+}
+
static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -3623,7 +3889,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
+ if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
refclk = dev_priv->lvds_ssc_freq * 1000;
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
refclk / 1000);
@@ -3641,7 +3907,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
- limit = intel_limit(crtc);
+ limit = intel_limit(crtc, refclk);
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
@@ -3691,10 +3957,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* FDI link */
if (HAS_PCH_SPLIT(dev)) {
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
int lane = 0, link_bw, bpp;
/* CPU eDP doesn't require FDI link, so just set DP M/N
according to current link config */
- if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
+ if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
target_clock = mode->clock;
intel_edp_link_config(has_edp_encoder,
&lane, &link_bw);
@@ -3774,6 +4041,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc->fdi_lanes = lane;
+ if (pixel_multiplier > 1)
+ link_bw *= pixel_multiplier;
ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
}
@@ -3795,7 +4064,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
udelay(200);
if (has_edp_encoder) {
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
temp |= DREF_SSC1_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
@@ -3806,13 +4075,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Enable CPU source on CPU attached eDP */
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- if (dev_priv->lvds_use_ssc)
+ if (intel_panel_use_ssc(dev_priv))
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
else
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else {
/* Enable SSC on PCH eDP if needed */
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
DRM_ERROR("enabling SSC on PCH\n");
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
}
@@ -3835,6 +4104,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
reduced_clock.m2;
}
+ /* Enable autotuning of the PLL clock (if permissible) */
+ if (HAS_PCH_SPLIT(dev)) {
+ int factor = 21;
+
+ if (is_lvds) {
+ if ((intel_panel_use_ssc(dev_priv) &&
+ dev_priv->lvds_ssc_freq == 100) ||
+ (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+ factor = 25;
+ } else if (is_sdvo && is_tv)
+ factor = 20;
+
+ if (clock.m1 < factor * clock.n)
+ fp |= FP_CB_TUNE;
+ }
+
dpll = 0;
if (!HAS_PCH_SPLIT(dev))
dpll = DPLL_VGA_MODE_DIS;
@@ -3903,7 +4188,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
- else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
+ else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
dpll |= PLL_REF_INPUT_DREFCLK;
@@ -4049,7 +4334,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll);
/* Wait for the clocks to stabilize. */
@@ -4067,13 +4351,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
I915_WRITE(DPLL_MD(pipe), temp);
} else {
- /* write it again -- the BIOS does, after all */
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
I915_WRITE(dpll_reg, dpll);
}
-
- /* Wait for the clocks to stabilize. */
- POSTING_READ(dpll_reg);
- udelay(150);
}
intel_crtc->lowfreq_avail = false;
@@ -4309,15 +4593,14 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
}
static int intel_crtc_cursor_set(struct drm_crtc *crtc,
- struct drm_file *file_priv,
+ struct drm_file *file,
uint32_t handle,
uint32_t width, uint32_t height)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_gem_object *bo;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
uint32_t addr;
int ret;
@@ -4327,7 +4610,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
if (!handle) {
DRM_DEBUG_KMS("cursor off\n");
addr = 0;
- bo = NULL;
+ obj = NULL;
mutex_lock(&dev->struct_mutex);
goto finish;
}
@@ -4338,13 +4621,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
return -EINVAL;
}
- bo = drm_gem_object_lookup(dev, file_priv, handle);
- if (!bo)
+ obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle));
+ if (!obj)
return -ENOENT;
- obj_priv = to_intel_bo(bo);
-
- if (bo->size < width * height * 4) {
+ if (obj->base.size < width * height * 4) {
DRM_ERROR("buffer is to small\n");
ret = -ENOMEM;
goto fail;
@@ -4353,29 +4634,41 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
/* we only need to pin inside GTT if cursor is non-phy */
mutex_lock(&dev->struct_mutex);
if (!dev_priv->info->cursor_needs_physical) {
- ret = i915_gem_object_pin(bo, PAGE_SIZE);
+ if (obj->tiling_mode) {
+ DRM_ERROR("cursor cannot be tiled\n");
+ ret = -EINVAL;
+ goto fail_locked;
+ }
+
+ ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
if (ret) {
DRM_ERROR("failed to pin cursor bo\n");
goto fail_locked;
}
- ret = i915_gem_object_set_to_gtt_domain(bo, 0);
+ ret = i915_gem_object_set_to_gtt_domain(obj, 0);
+ if (ret) {
+ DRM_ERROR("failed to move cursor bo into the GTT\n");
+ goto fail_unpin;
+ }
+
+ ret = i915_gem_object_put_fence(obj);
if (ret) {
DRM_ERROR("failed to move cursor bo into the GTT\n");
goto fail_unpin;
}
- addr = obj_priv->gtt_offset;
+ addr = obj->gtt_offset;
} else {
int align = IS_I830(dev) ? 16 * 1024 : 256;
- ret = i915_gem_attach_phys_object(dev, bo,
+ ret = i915_gem_attach_phys_object(dev, obj,
(intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1,
align);
if (ret) {
DRM_ERROR("failed to attach phys object\n");
goto fail_locked;
}
- addr = obj_priv->phys_obj->handle->busaddr;
+ addr = obj->phys_obj->handle->busaddr;
}
if (IS_GEN2(dev))
@@ -4384,17 +4677,17 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
finish:
if (intel_crtc->cursor_bo) {
if (dev_priv->info->cursor_needs_physical) {
- if (intel_crtc->cursor_bo != bo)
+ if (intel_crtc->cursor_bo != obj)
i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
} else
i915_gem_object_unpin(intel_crtc->cursor_bo);
- drm_gem_object_unreference(intel_crtc->cursor_bo);
+ drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
}
mutex_unlock(&dev->struct_mutex);
intel_crtc->cursor_addr = addr;
- intel_crtc->cursor_bo = bo;
+ intel_crtc->cursor_bo = obj;
intel_crtc->cursor_width = width;
intel_crtc->cursor_height = height;
@@ -4402,11 +4695,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
return 0;
fail_unpin:
- i915_gem_object_unpin(bo);
+ i915_gem_object_unpin(obj);
fail_locked:
mutex_unlock(&dev->struct_mutex);
fail:
- drm_gem_object_unreference_unlocked(bo);
+ drm_gem_object_unreference_unlocked(&obj->base);
return ret;
}
@@ -4717,8 +5010,14 @@ static void intel_gpu_idle_timer(unsigned long arg)
struct drm_device *dev = (struct drm_device *)arg;
drm_i915_private_t *dev_priv = dev->dev_private;
- dev_priv->busy = false;
+ if (!list_empty(&dev_priv->mm.active_list)) {
+ /* Still processing requests, so just re-arm the timer. */
+ mod_timer(&dev_priv->idle_timer, jiffies +
+ msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+ return;
+ }
+ dev_priv->busy = false;
queue_work(dev_priv->wq, &dev_priv->idle_work);
}
@@ -4729,9 +5028,17 @@ static void intel_crtc_idle_timer(unsigned long arg)
struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
struct drm_crtc *crtc = &intel_crtc->base;
drm_i915_private_t *dev_priv = crtc->dev->dev_private;
+ struct intel_framebuffer *intel_fb;
- intel_crtc->busy = false;
+ intel_fb = to_intel_framebuffer(crtc->fb);
+ if (intel_fb && intel_fb->obj->active) {
+ /* The framebuffer is still being accessed by the GPU. */
+ mod_timer(&intel_crtc->idle_timer, jiffies +
+ msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+ return;
+ }
+ intel_crtc->busy = false;
queue_work(dev_priv->wq, &dev_priv->idle_work);
}
@@ -4741,8 +5048,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dpll = I915_READ(dpll_reg);
+ int dpll_reg = DPLL(pipe);
+ int dpll;
if (HAS_PCH_SPLIT(dev))
return;
@@ -4750,17 +5057,19 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
if (!dev_priv->lvds_downclock_avail)
return;
+ dpll = I915_READ(dpll_reg);
if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
DRM_DEBUG_DRIVER("upclocking LVDS\n");
/* Unlock panel regs */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
- PANEL_UNLOCK_REGS);
+ I915_WRITE(PP_CONTROL,
+ I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
dpll &= ~DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
- dpll = I915_READ(dpll_reg);
+ POSTING_READ(dpll_reg);
intel_wait_for_vblank(dev, pipe);
+
dpll = I915_READ(dpll_reg);
if (dpll & DISPLAY_RATE_SELECT_FPA1)
DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
@@ -4866,7 +5175,7 @@ static void intel_idle_update(struct work_struct *work)
* buffer), we'll also mark the display as busy, so we know to increase its
* clock frequency.
*/
-void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
+void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = NULL;
@@ -4947,8 +5256,9 @@ static void intel_unpin_work_fn(struct work_struct *__work)
mutex_lock(&work->dev->struct_mutex);
i915_gem_object_unpin(work->old_fb_obj);
- drm_gem_object_unreference(work->pending_flip_obj);
- drm_gem_object_unreference(work->old_fb_obj);
+ drm_gem_object_unreference(&work->pending_flip_obj->base);
+ drm_gem_object_unreference(&work->old_fb_obj->base);
+
mutex_unlock(&work->dev->struct_mutex);
kfree(work);
}
@@ -4959,15 +5269,17 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
struct drm_pending_vblank_event *e;
- struct timeval now;
+ struct timeval tnow, tvbl;
unsigned long flags;
/* Ignore early vblank irqs */
if (intel_crtc == NULL)
return;
+ do_gettimeofday(&tnow);
+
spin_lock_irqsave(&dev->event_lock, flags);
work = intel_crtc->unpin_work;
if (work == NULL || !work->pending) {
@@ -4976,26 +5288,49 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
}
intel_crtc->unpin_work = NULL;
- drm_vblank_put(dev, intel_crtc->pipe);
if (work->event) {
e = work->event;
- do_gettimeofday(&now);
- e->event.sequence = drm_vblank_count(dev, intel_crtc->pipe);
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
+ e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl);
+
+ /* Called before vblank count and timestamps have
+ * been updated for the vblank interval of flip
+ * completion? Need to increment vblank count and
+ * add one videorefresh duration to returned timestamp
+ * to account for this. We assume this happened if we
+ * get called over 0.9 frame durations after the last
+ * timestamped vblank.
+ *
+ * This calculation can not be used with vrefresh rates
+ * below 5Hz (10Hz to be on the safe side) without
+ * promoting to 64 integers.
+ */
+ if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+ 9 * crtc->framedur_ns) {
+ e->event.sequence++;
+ tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+ crtc->framedur_ns);
+ }
+
+ e->event.tv_sec = tvbl.tv_sec;
+ e->event.tv_usec = tvbl.tv_usec;
+
list_add_tail(&e->base.link,
&e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
}
+ drm_vblank_put(dev, intel_crtc->pipe);
+
spin_unlock_irqrestore(&dev->event_lock, flags);
- obj_priv = to_intel_bo(work->old_fb_obj);
+ obj = work->old_fb_obj;
+
atomic_clear_mask(1 << intel_crtc->plane,
- &obj_priv->pending_flip.counter);
- if (atomic_read(&obj_priv->pending_flip) == 0)
+ &obj->pending_flip.counter);
+ if (atomic_read(&obj->pending_flip) == 0)
wake_up(&dev_priv->pending_flip_queue);
+
schedule_work(&work->work);
trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5041,8 +5376,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_framebuffer *intel_fb;
- struct drm_i915_gem_object *obj_priv;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
unsigned long flags, offset;
@@ -5076,13 +5410,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
obj = intel_fb->obj;
mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(dev, obj, true);
+ ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
if (ret)
goto cleanup_work;
/* Reference the objects for the scheduled work. */
- drm_gem_object_reference(work->old_fb_obj);
- drm_gem_object_reference(obj);
+ drm_gem_object_reference(&work->old_fb_obj->base);
+ drm_gem_object_reference(&obj->base);
crtc->fb = fb;
@@ -5090,22 +5424,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
if (ret)
goto cleanup_objs;
- /* Block clients from rendering to the new back buffer until
- * the flip occurs and the object is no longer visible.
- */
- atomic_add(1 << intel_crtc->plane,
- &to_intel_bo(work->old_fb_obj)->pending_flip);
-
- work->pending_flip_obj = obj;
- obj_priv = to_intel_bo(obj);
-
if (IS_GEN3(dev) || IS_GEN2(dev)) {
u32 flip_mask;
/* Can't queue multiple flips, so wait for the previous
* one to finish before executing the next.
*/
- BEGIN_LP_RING(2);
+ ret = BEGIN_LP_RING(2);
+ if (ret)
+ goto cleanup_objs;
+
if (intel_crtc->plane)
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
@@ -5115,18 +5443,28 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
ADVANCE_LP_RING();
}
+ work->pending_flip_obj = obj;
+
work->enable_stall_check = true;
/* Offset into the new buffer for cases of shared fbs between CRTCs */
offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;
- BEGIN_LP_RING(4);
- switch(INTEL_INFO(dev)->gen) {
+ ret = BEGIN_LP_RING(4);
+ if (ret)
+ goto cleanup_objs;
+
+ /* Block clients from rendering to the new back buffer until
+ * the flip occurs and the object is no longer visible.
+ */
+ atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
+
+ switch (INTEL_INFO(dev)->gen) {
case 2:
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
- OUT_RING(obj_priv->gtt_offset + offset);
+ OUT_RING(obj->gtt_offset + offset);
OUT_RING(MI_NOOP);
break;
@@ -5134,7 +5472,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
OUT_RING(MI_DISPLAY_FLIP_I915 |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
- OUT_RING(obj_priv->gtt_offset + offset);
+ OUT_RING(obj->gtt_offset + offset);
OUT_RING(MI_NOOP);
break;
@@ -5147,7 +5485,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
- OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
+ OUT_RING(obj->gtt_offset | obj->tiling_mode);
/* XXX Enabling the panel-fitter across page-flip is so far
* untested on non-native modes, so ignore it for now.
@@ -5161,8 +5499,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
case 6:
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
- OUT_RING(fb->pitch | obj_priv->tiling_mode);
- OUT_RING(obj_priv->gtt_offset);
+ OUT_RING(fb->pitch | obj->tiling_mode);
+ OUT_RING(obj->gtt_offset);
pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
@@ -5178,8 +5516,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
return 0;
cleanup_objs:
- drm_gem_object_unreference(work->old_fb_obj);
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&work->old_fb_obj->base);
+ drm_gem_object_unreference(&obj->base);
cleanup_work:
mutex_unlock(&dev->struct_mutex);
@@ -5211,6 +5549,55 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.page_flip = intel_crtc_page_flip,
};
+static void intel_sanitize_modesetting(struct drm_device *dev,
+ int pipe, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg, val;
+
+ if (HAS_PCH_SPLIT(dev))
+ return;
+
+ /* Who knows what state these registers were left in by the BIOS or
+ * grub?
+ *
+ * If we leave the registers in a conflicting state (e.g. with the
+ * display plane reading from the other pipe than the one we intend
+ * to use) then when we attempt to teardown the active mode, we will
+ * not disable the pipes and planes in the correct order -- leaving
+ * a plane reading from a disabled pipe and possibly leading to
+ * undefined behaviour.
+ */
+
+ reg = DSPCNTR(plane);
+ val = I915_READ(reg);
+
+ if ((val & DISPLAY_PLANE_ENABLE) == 0)
+ return;
+ if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
+ return;
+
+ /* This display plane is active and attached to the other CPU pipe. */
+ pipe = !pipe;
+
+ /* Disable the plane and wait for it to stop reading from the pipe. */
+ I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
+ intel_flush_display_plane(dev, plane);
+
+ if (IS_GEN2(dev))
+ intel_wait_for_vblank(dev, pipe);
+
+ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+ return;
+
+ /* Switch off the pipe. */
+ reg = PIPECONF(pipe);
+ val = I915_READ(reg);
+ if (val & PIPECONF_ENABLE) {
+ I915_WRITE(reg, val & ~PIPECONF_ENABLE);
+ intel_wait_for_pipe_off(dev, pipe);
+ }
+}
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
@@ -5262,10 +5649,12 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
(unsigned long)intel_crtc);
+
+ intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
}
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
@@ -5306,19 +5695,41 @@ static int intel_encoder_clones(struct drm_device *dev, int type_mask)
return index_mask;
}
+static bool has_edp_a(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!IS_MOBILE(dev))
+ return false;
+
+ if ((I915_READ(DP_A) & DP_DETECTED) == 0)
+ return false;
+
+ if (IS_GEN5(dev) &&
+ (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
+ return false;
+
+ return true;
+}
+
static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
bool dpd_is_edp = false;
+ bool has_lvds = false;
if (IS_MOBILE(dev) && !IS_I830(dev))
- intel_lvds_init(dev);
+ has_lvds = intel_lvds_init(dev);
+ if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
+ /* disable the panel fitter on everything but LVDS */
+ I915_WRITE(PFIT_CONTROL, 0);
+ }
if (HAS_PCH_SPLIT(dev)) {
dpd_is_edp = intel_dpd_is_edp(dev);
- if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
+ if (has_edp_a(dev))
intel_dp_init(dev, DP_A);
if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
@@ -5403,6 +5814,8 @@ static void intel_setup_outputs(struct drm_device *dev)
encoder->base.possible_clones =
intel_encoder_clones(dev, encoder->clone_mask);
}
+
+ intel_panel_setup_backlight(dev);
}
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -5410,19 +5823,19 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
drm_framebuffer_cleanup(fb);
- drm_gem_object_unreference_unlocked(intel_fb->obj);
+ drm_gem_object_unreference_unlocked(&intel_fb->obj->base);
kfree(intel_fb);
}
static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
- struct drm_file *file_priv,
+ struct drm_file *file,
unsigned int *handle)
{
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_gem_object *object = intel_fb->obj;
+ struct drm_i915_gem_object *obj = intel_fb->obj;
- return drm_gem_handle_create(file_priv, object, handle);
+ return drm_gem_handle_create(file, &obj->base, handle);
}
static const struct drm_framebuffer_funcs intel_fb_funcs = {
@@ -5433,12 +5846,11 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *intel_fb,
struct drm_mode_fb_cmd *mode_cmd,
- struct drm_gem_object *obj)
+ struct drm_i915_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
- if (obj_priv->tiling_mode == I915_TILING_Y)
+ if (obj->tiling_mode == I915_TILING_Y)
return -EINVAL;
if (mode_cmd->pitch & 63)
@@ -5470,11 +5882,11 @@ intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
struct drm_mode_fb_cmd *mode_cmd)
{
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
struct intel_framebuffer *intel_fb;
int ret;
- obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
+ obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle));
if (!obj)
return ERR_PTR(-ENOENT);
@@ -5482,10 +5894,9 @@ intel_user_framebuffer_create(struct drm_device *dev,
if (!intel_fb)
return ERR_PTR(-ENOMEM);
- ret = intel_framebuffer_init(dev, intel_fb,
- mode_cmd, obj);
+ ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
if (ret) {
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_unreference_unlocked(&obj->base);
kfree(intel_fb);
return ERR_PTR(ret);
}
@@ -5498,10 +5909,10 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
.output_poll_changed = intel_fb_output_poll_changed,
};
-static struct drm_gem_object *
+static struct drm_i915_gem_object *
intel_alloc_context_page(struct drm_device *dev)
{
- struct drm_gem_object *ctx;
+ struct drm_i915_gem_object *ctx;
int ret;
ctx = i915_gem_alloc_object(dev, 4096);
@@ -5511,7 +5922,7 @@ intel_alloc_context_page(struct drm_device *dev)
}
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_pin(ctx, 4096);
+ ret = i915_gem_object_pin(ctx, 4096, true);
if (ret) {
DRM_ERROR("failed to pin power context: %d\n", ret);
goto err_unref;
@@ -5529,7 +5940,7 @@ intel_alloc_context_page(struct drm_device *dev)
err_unpin:
i915_gem_object_unpin(ctx);
err_unref:
- drm_gem_object_unreference(ctx);
+ drm_gem_object_unreference(&ctx->base);
mutex_unlock(&dev->struct_mutex);
return NULL;
}
@@ -5581,20 +5992,19 @@ void ironlake_enable_drps(struct drm_device *dev)
fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
MEMMODE_FSTART_SHIFT;
- fstart = fmax;
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
- dev_priv->fmax = fstart; /* IPS callback will increase this */
+ dev_priv->fmax = fmax; /* IPS callback will increase this */
dev_priv->fstart = fstart;
- dev_priv->max_delay = fmax;
+ dev_priv->max_delay = fstart;
dev_priv->min_delay = fmin;
dev_priv->cur_delay = fstart;
- DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
- fstart);
+ DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
+ fmax, fmin, fstart);
I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
@@ -5642,6 +6052,25 @@ void ironlake_disable_drps(struct drm_device *dev)
}
+void gen6_set_rps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 swreq;
+
+ swreq = (val & 0x3ff) << 25;
+ I915_WRITE(GEN6_RPNSWREQ, swreq);
+}
+
+void gen6_disable_rps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
+ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+ I915_WRITE(GEN6_PMIER, 0);
+ I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+}
+
static unsigned long intel_pxfreq(u32 vidfreq)
{
unsigned long freq;
@@ -5728,7 +6157,123 @@ void intel_init_emon(struct drm_device *dev)
dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}
-void intel_init_clock_gating(struct drm_device *dev)
+void gen6_enable_rps(struct drm_i915_private *dev_priv)
+{
+ u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
+ u32 pcu_mbox;
+ int cur_freq, min_freq, max_freq;
+ int i;
+
+ /* Here begins a magic sequence of register writes to enable
+ * auto-downclocking.
+ *
+ * Perhaps there might be some value in exposing these to
+ * userspace...
+ */
+ I915_WRITE(GEN6_RC_STATE, 0);
+ __gen6_force_wake_get(dev_priv);
+
+ /* disable the counters and set deterministic thresholds */
+ I915_WRITE(GEN6_RC_CONTROL, 0);
+
+ I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
+ I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
+ I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
+ I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
+
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
+
+ I915_WRITE(GEN6_RC_SLEEP, 0);
+ I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
+ I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
+ I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
+ I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
+
+ I915_WRITE(GEN6_RC_CONTROL,
+ GEN6_RC_CTL_RC6p_ENABLE |
+ GEN6_RC_CTL_RC6_ENABLE |
+ GEN6_RC_CTL_EI_MODE(1) |
+ GEN6_RC_CTL_HW_ENABLE);
+
+ I915_WRITE(GEN6_RPNSWREQ,
+ GEN6_FREQUENCY(10) |
+ GEN6_OFFSET(0) |
+ GEN6_AGGRESSIVE_TURBO);
+ I915_WRITE(GEN6_RC_VIDEO_FREQ,
+ GEN6_FREQUENCY(12));
+
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+ 18 << 24 |
+ 6 << 16);
+ I915_WRITE(GEN6_RP_UP_THRESHOLD, 90000);
+ I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 100000);
+ I915_WRITE(GEN6_RP_UP_EI, 100000);
+ I915_WRITE(GEN6_RP_DOWN_EI, 300000);
+ I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
+ I915_WRITE(GEN6_RP_CONTROL,
+ GEN6_RP_MEDIA_TURBO |
+ GEN6_RP_USE_NORMAL_FREQ |
+ GEN6_RP_MEDIA_IS_GFX |
+ GEN6_RP_ENABLE |
+ GEN6_RP_UP_BUSY_MAX |
+ GEN6_RP_DOWN_BUSY_MIN);
+
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+
+ I915_WRITE(GEN6_PCODE_DATA, 0);
+ I915_WRITE(GEN6_PCODE_MAILBOX,
+ GEN6_PCODE_READY |
+ GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+
+ min_freq = (rp_state_cap & 0xff0000) >> 16;
+ max_freq = rp_state_cap & 0xff;
+ cur_freq = (gt_perf_status & 0xff00) >> 8;
+
+ /* Check for overclock support */
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+ I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
+ pcu_mbox = I915_READ(GEN6_PCODE_DATA);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+ if (pcu_mbox & (1<<31)) { /* OC supported */
+ max_freq = pcu_mbox & 0xff;
+ DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100);
+ }
+
+ /* In units of 100MHz */
+ dev_priv->max_delay = max_freq;
+ dev_priv->min_delay = min_freq;
+ dev_priv->cur_delay = cur_freq;
+
+ /* requires MSI enabled */
+ I915_WRITE(GEN6_PMIER,
+ GEN6_PM_MBOX_EVENT |
+ GEN6_PM_THERMAL_EVENT |
+ GEN6_PM_RP_DOWN_TIMEOUT |
+ GEN6_PM_RP_UP_THRESHOLD |
+ GEN6_PM_RP_DOWN_THRESHOLD |
+ GEN6_PM_RP_UP_EI_EXPIRED |
+ GEN6_PM_RP_DOWN_EI_EXPIRED);
+ I915_WRITE(GEN6_PMIMR, 0);
+ /* enable all PM interrupts */
+ I915_WRITE(GEN6_PMINTRMSK, 0);
+
+ __gen6_force_wake_put(dev_priv);
+}
+
+void intel_enable_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5748,6 +6293,8 @@ void intel_init_clock_gating(struct drm_device *dev)
I915_WRITE(PCH_3DCGDIS0,
MARIUNIT_CLOCK_GATE_DISABLE |
SVSMUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_3DCGDIS1,
+ VFMUNIT_CLOCK_GATE_DISABLE);
}
I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
@@ -5776,9 +6323,9 @@ void intel_init_clock_gating(struct drm_device *dev)
I915_WRITE(DISP_ARB_CTL,
(I915_READ(DISP_ARB_CTL) |
DISP_FBC_WM_DIS));
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
}
/*
* Based on the document from hardware guys the following bits
@@ -5800,7 +6347,49 @@ void intel_init_clock_gating(struct drm_device *dev)
ILK_DPFC_DIS2 |
ILK_CLK_FBC);
}
- return;
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+
+ if (IS_GEN5(dev)) {
+ I915_WRITE(_3D_CHICKEN2,
+ _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+ _3D_CHICKEN2_WM_READ_PIPELINED);
+ }
+
+ if (IS_GEN6(dev)) {
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /*
+ * According to the spec the following bits should be
+ * set in order to enable memory self-refresh and fbc:
+ * The bit21 and bit22 of 0x42000
+ * The bit21 and bit22 of 0x42004
+ * The bit5 and bit7 of 0x42020
+ * The bit14 of 0x70180
+ * The bit14 of 0x71180
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE |
+ ILK_DPFD_CLK_GATE);
+
+ I915_WRITE(DSPACNTR,
+ I915_READ(DSPACNTR) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ I915_WRITE(DSPBCNTR,
+ I915_READ(DSPBCNTR) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ }
} else if (IS_G4X(dev)) {
uint32_t dspclk_gate;
I915_WRITE(RENCLK_GATE_D1, 0);
@@ -5838,55 +6427,84 @@ void intel_init_clock_gating(struct drm_device *dev)
} else if (IS_I830(dev)) {
I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
}
+}
- /*
- * GPU can automatically power down the render unit if given a page
- * to save state.
- */
- if (IS_IRONLAKE_M(dev)) {
- if (dev_priv->renderctx == NULL)
- dev_priv->renderctx = intel_alloc_context_page(dev);
- if (dev_priv->renderctx) {
- struct drm_i915_gem_object *obj_priv;
- obj_priv = to_intel_bo(dev_priv->renderctx);
- if (obj_priv) {
- BEGIN_LP_RING(4);
- OUT_RING(MI_SET_CONTEXT);
- OUT_RING(obj_priv->gtt_offset |
- MI_MM_SPACE_GTT |
- MI_SAVE_EXT_STATE_EN |
- MI_RESTORE_EXT_STATE_EN |
- MI_RESTORE_INHIBIT);
- OUT_RING(MI_NOOP);
- OUT_RING(MI_FLUSH);
- ADVANCE_LP_RING();
- }
- } else
- DRM_DEBUG_KMS("Failed to allocate render context."
- "Disable RC6\n");
+void intel_disable_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->renderctx) {
+ struct drm_i915_gem_object *obj = dev_priv->renderctx;
+
+ I915_WRITE(CCID, 0);
+ POSTING_READ(CCID);
+
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(&obj->base);
+ dev_priv->renderctx = NULL;
}
- if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) {
- struct drm_i915_gem_object *obj_priv = NULL;
+ if (dev_priv->pwrctx) {
+ struct drm_i915_gem_object *obj = dev_priv->pwrctx;
- if (dev_priv->pwrctx) {
- obj_priv = to_intel_bo(dev_priv->pwrctx);
- } else {
- struct drm_gem_object *pwrctx;
+ I915_WRITE(PWRCTXA, 0);
+ POSTING_READ(PWRCTXA);
- pwrctx = intel_alloc_context_page(dev);
- if (pwrctx) {
- dev_priv->pwrctx = pwrctx;
- obj_priv = to_intel_bo(pwrctx);
- }
- }
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(&obj->base);
+ dev_priv->pwrctx = NULL;
+ }
+}
- if (obj_priv) {
- I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
- I915_WRITE(MCHBAR_RENDER_STANDBY,
- I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
- }
+static void ironlake_disable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+ wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+ 10);
+ POSTING_READ(CCID);
+ I915_WRITE(PWRCTXA, 0);
+ POSTING_READ(PWRCTXA);
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ POSTING_READ(RSTDBYCTL);
+ i915_gem_object_unpin(dev_priv->renderctx);
+ drm_gem_object_unreference(&dev_priv->renderctx->base);
+ dev_priv->renderctx = NULL;
+ i915_gem_object_unpin(dev_priv->pwrctx);
+ drm_gem_object_unreference(&dev_priv->pwrctx->base);
+ dev_priv->pwrctx = NULL;
+}
+
+void ironlake_enable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ /*
+ * GPU can automatically power down the render unit if given a page
+ * to save state.
+ */
+ ret = BEGIN_LP_RING(6);
+ if (ret) {
+ ironlake_disable_rc6(dev);
+ return;
}
+ OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
+ OUT_RING(MI_SET_CONTEXT);
+ OUT_RING(dev_priv->renderctx->gtt_offset |
+ MI_MM_SPACE_GTT |
+ MI_SAVE_EXT_STATE_EN |
+ MI_RESTORE_EXT_STATE_EN |
+ MI_RESTORE_INHIBIT);
+ OUT_RING(MI_SUSPEND_FLUSH);
+ OUT_RING(MI_NOOP);
+ OUT_RING(MI_FLUSH);
+ ADVANCE_LP_RING();
+
+ I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
}
/* Set up chip specific display functions */
@@ -5901,7 +6519,7 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.dpms = i9xx_crtc_dpms;
if (I915_HAS_FBC(dev)) {
- if (IS_IRONLAKE_M(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
dev_priv->display.enable_fbc = ironlake_enable_fbc;
dev_priv->display.disable_fbc = ironlake_disable_fbc;
@@ -5950,6 +6568,14 @@ static void intel_init_display(struct drm_device *dev)
"Disable CxSR\n");
dev_priv->display.update_wm = NULL;
}
+ } else if (IS_GEN6(dev)) {
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
} else
dev_priv->display.update_wm = NULL;
} else if (IS_PINEVIEW(dev)) {
@@ -6095,12 +6721,7 @@ void intel_modeset_init(struct drm_device *dev)
dev->mode_config.max_width = 8192;
dev->mode_config.max_height = 8192;
}
-
- /* set memory base */
- if (IS_GEN2(dev))
- dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
- else
- dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
+ dev->mode_config.fb_base = dev->agp->base;
if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2;
@@ -6115,7 +6736,7 @@ void intel_modeset_init(struct drm_device *dev)
intel_setup_outputs(dev);
- intel_init_clock_gating(dev);
+ intel_enable_clock_gating(dev);
/* Just disable it once at startup */
i915_disable_vga(dev);
@@ -6125,6 +6746,24 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_emon(dev);
}
+ if (IS_GEN6(dev))
+ gen6_enable_rps(dev_priv);
+
+ if (IS_IRONLAKE_M(dev)) {
+ dev_priv->renderctx = intel_alloc_context_page(dev);
+ if (!dev_priv->renderctx)
+ goto skip_rc6;
+ dev_priv->pwrctx = intel_alloc_context_page(dev);
+ if (!dev_priv->pwrctx) {
+ i915_gem_object_unpin(dev_priv->renderctx);
+ drm_gem_object_unreference(&dev_priv->renderctx->base);
+ dev_priv->renderctx = NULL;
+ goto skip_rc6;
+ }
+ ironlake_enable_rc6(dev);
+ }
+
+skip_rc6:
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
(unsigned long)dev);
@@ -6156,28 +6795,13 @@ void intel_modeset_cleanup(struct drm_device *dev)
if (dev_priv->display.disable_fbc)
dev_priv->display.disable_fbc(dev);
- if (dev_priv->renderctx) {
- struct drm_i915_gem_object *obj_priv;
-
- obj_priv = to_intel_bo(dev_priv->renderctx);
- I915_WRITE(CCID, obj_priv->gtt_offset &~ CCID_EN);
- I915_READ(CCID);
- i915_gem_object_unpin(dev_priv->renderctx);
- drm_gem_object_unreference(dev_priv->renderctx);
- }
-
- if (dev_priv->pwrctx) {
- struct drm_i915_gem_object *obj_priv;
-
- obj_priv = to_intel_bo(dev_priv->pwrctx);
- I915_WRITE(PWRCTXA, obj_priv->gtt_offset &~ PWRCTX_EN);
- I915_READ(PWRCTXA);
- i915_gem_object_unpin(dev_priv->pwrctx);
- drm_gem_object_unreference(dev_priv->pwrctx);
- }
-
if (IS_IRONLAKE_M(dev))
ironlake_disable_drps(dev);
+ if (IS_GEN6(dev))
+ gen6_disable_rps(dev);
+
+ if (IS_IRONLAKE_M(dev))
+ ironlake_disable_rc6(dev);
mutex_unlock(&dev->struct_mutex);
@@ -6229,3 +6853,113 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
pci_write_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, gmch_ctrl);
return 0;
}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+struct intel_display_error_state {
+ struct intel_cursor_error_state {
+ u32 control;
+ u32 position;
+ u32 base;
+ u32 size;
+ } cursor[2];
+
+ struct intel_pipe_error_state {
+ u32 conf;
+ u32 source;
+
+ u32 htotal;
+ u32 hblank;
+ u32 hsync;
+ u32 vtotal;
+ u32 vblank;
+ u32 vsync;
+ } pipe[2];
+
+ struct intel_plane_error_state {
+ u32 control;
+ u32 stride;
+ u32 size;
+ u32 pos;
+ u32 addr;
+ u32 surface;
+ u32 tile_offset;
+ } plane[2];
+};
+
+struct intel_display_error_state *
+intel_display_capture_error_state(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_display_error_state *error;
+ int i;
+
+ error = kmalloc(sizeof(*error), GFP_ATOMIC);
+ if (error == NULL)
+ return NULL;
+
+ for (i = 0; i < 2; i++) {
+ error->cursor[i].control = I915_READ(CURCNTR(i));
+ error->cursor[i].position = I915_READ(CURPOS(i));
+ error->cursor[i].base = I915_READ(CURBASE(i));
+
+ error->plane[i].control = I915_READ(DSPCNTR(i));
+ error->plane[i].stride = I915_READ(DSPSTRIDE(i));
+ error->plane[i].size = I915_READ(DSPSIZE(i));
+ error->plane[i].pos= I915_READ(DSPPOS(i));
+ error->plane[i].addr = I915_READ(DSPADDR(i));
+ if (INTEL_INFO(dev)->gen >= 4) {
+ error->plane[i].surface = I915_READ(DSPSURF(i));
+ error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i));
+ }
+
+ error->pipe[i].conf = I915_READ(PIPECONF(i));
+ error->pipe[i].source = I915_READ(PIPESRC(i));
+ error->pipe[i].htotal = I915_READ(HTOTAL(i));
+ error->pipe[i].hblank = I915_READ(HBLANK(i));
+ error->pipe[i].hsync = I915_READ(HSYNC(i));
+ error->pipe[i].vtotal = I915_READ(VTOTAL(i));
+ error->pipe[i].vblank = I915_READ(VBLANK(i));
+ error->pipe[i].vsync = I915_READ(VSYNC(i));
+ }
+
+ return error;
+}
+
+void
+intel_display_print_error_state(struct seq_file *m,
+ struct drm_device *dev,
+ struct intel_display_error_state *error)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ seq_printf(m, "Pipe [%d]:\n", i);
+ seq_printf(m, " CONF: %08x\n", error->pipe[i].conf);
+ seq_printf(m, " SRC: %08x\n", error->pipe[i].source);
+ seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal);
+ seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank);
+ seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync);
+ seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal);
+ seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank);
+ seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync);
+
+ seq_printf(m, "Plane [%d]:\n", i);
+ seq_printf(m, " CNTR: %08x\n", error->plane[i].control);
+ seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
+ seq_printf(m, " SIZE: %08x\n", error->plane[i].size);
+ seq_printf(m, " POS: %08x\n", error->plane[i].pos);
+ seq_printf(m, " ADDR: %08x\n", error->plane[i].addr);
+ if (INTEL_INFO(dev)->gen >= 4) {
+ seq_printf(m, " SURF: %08x\n", error->plane[i].surface);
+ seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
+ }
+
+ seq_printf(m, "Cursor [%d]:\n", i);
+ seq_printf(m, " CNTR: %08x\n", error->cursor[i].control);
+ seq_printf(m, " POS: %08x\n", error->cursor[i].position);
+ seq_printf(m, " BASE: %08x\n", error->cursor[i].base);
+ }
+}
+#endif
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 891f4f1d63b1..1f4242b682c8 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -479,6 +479,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
uint16_t address = algo_data->address;
uint8_t msg[5];
uint8_t reply[2];
+ unsigned retry;
int msg_bytes;
int reply_bytes;
int ret;
@@ -513,14 +514,33 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
break;
}
- for (;;) {
- ret = intel_dp_aux_ch(intel_dp,
- msg, msg_bytes,
- reply, reply_bytes);
+ for (retry = 0; retry < 5; retry++) {
+ ret = intel_dp_aux_ch(intel_dp,
+ msg, msg_bytes,
+ reply, reply_bytes);
if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
return ret;
}
+
+ switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
+ case AUX_NATIVE_REPLY_ACK:
+ /* I2C-over-AUX Reply field is only valid
+ * when paired with AUX ACK.
+ */
+ break;
+ case AUX_NATIVE_REPLY_NACK:
+ DRM_DEBUG_KMS("aux_ch native nack\n");
+ return -EREMOTEIO;
+ case AUX_NATIVE_REPLY_DEFER:
+ udelay(100);
+ continue;
+ default:
+ DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
+ reply[0]);
+ return -EREMOTEIO;
+ }
+
switch (reply[0] & AUX_I2C_REPLY_MASK) {
case AUX_I2C_REPLY_ACK:
if (mode == MODE_I2C_READ) {
@@ -528,17 +548,20 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
}
return reply_bytes - 1;
case AUX_I2C_REPLY_NACK:
- DRM_DEBUG_KMS("aux_ch nack\n");
+ DRM_DEBUG_KMS("aux_i2c nack\n");
return -EREMOTEIO;
case AUX_I2C_REPLY_DEFER:
- DRM_DEBUG_KMS("aux_ch defer\n");
+ DRM_DEBUG_KMS("aux_i2c defer\n");
udelay(100);
break;
default:
- DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
+ DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
return -EREMOTEIO;
}
}
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EREMOTEIO;
}
static int
@@ -584,17 +607,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
mode->clock = dev_priv->panel_fixed_mode->clock;
}
- /* Just use VBT values for eDP */
- if (is_edp(intel_dp)) {
- intel_dp->lane_count = dev_priv->edp.lanes;
- intel_dp->link_bw = dev_priv->edp.rate;
- adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
- return true;
- }
-
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
@@ -613,6 +625,19 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
}
+ if (is_edp(intel_dp)) {
+ /* okay we failed just pick the highest */
+ intel_dp->lane_count = max_lane_count;
+ intel_dp->link_bw = bws[max_clock];
+ adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
+ DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
+ "count %d clock %d\n",
+ intel_dp->link_bw, intel_dp->lane_count,
+ adjusted_mode->clock);
+
+ return true;
+ }
+
return false;
}
@@ -1087,21 +1112,11 @@ intel_get_adjust_train(struct intel_dp *intel_dp)
}
static uint32_t
-intel_dp_signal_levels(struct intel_dp *intel_dp)
+intel_dp_signal_levels(uint8_t train_set, int lane_count)
{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t signal_levels = 0;
- u8 train_set = intel_dp->train_set[0];
- u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
- u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
+ uint32_t signal_levels = 0;
- if (is_edp(intel_dp)) {
- vswing = dev_priv->edp.vswing;
- preemphasis = dev_priv->edp.preemphasis;
- }
-
- switch (vswing) {
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_400:
default:
signal_levels |= DP_VOLTAGE_0_4;
@@ -1116,7 +1131,7 @@ intel_dp_signal_levels(struct intel_dp *intel_dp)
signal_levels |= DP_VOLTAGE_1_2;
break;
}
- switch (preemphasis) {
+ switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
case DP_TRAIN_PRE_EMPHASIS_0:
default:
signal_levels |= DP_PRE_EMPHASIS_0;
@@ -1138,18 +1153,27 @@ intel_dp_signal_levels(struct intel_dp *intel_dp)
static uint32_t
intel_gen6_edp_signal_levels(uint8_t train_set)
{
- switch (train_set & (DP_TRAIN_VOLTAGE_SWING_MASK|DP_TRAIN_PRE_EMPHASIS_MASK)) {
+ int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+ DP_TRAIN_PRE_EMPHASIS_MASK);
+ switch (signal_levels) {
case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
- return EDP_LINK_TRAIN_400MV_0DB_SNB_B;
+ case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+ return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
+ case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+ return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
- return EDP_LINK_TRAIN_400MV_6DB_SNB_B;
+ case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
+ return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
- return EDP_LINK_TRAIN_600MV_3_5DB_SNB_B;
+ case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+ return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
- return EDP_LINK_TRAIN_800MV_0DB_SNB_B;
+ case DP_TRAIN_VOLTAGE_SWING_1200 | DP_TRAIN_PRE_EMPHASIS_0:
+ return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
default:
- DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level\n");
- return EDP_LINK_TRAIN_400MV_0DB_SNB_B;
+ DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
+ "0x%x\n", signal_levels);
+ return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
}
}
@@ -1203,18 +1227,6 @@ intel_channel_eq_ok(struct intel_dp *intel_dp)
}
static bool
-intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
-{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
- return false;
-
- return true;
-}
-
-static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value,
uint8_t dp_train_pat)
@@ -1226,9 +1238,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg);
- if (!intel_dp_aux_handshake_required(intel_dp))
- return true;
-
intel_dp_aux_native_write_1(intel_dp,
DP_TRAINING_PATTERN_SET,
dp_train_pat);
@@ -1261,11 +1270,10 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
POSTING_READ(intel_dp->output_reg);
intel_wait_for_vblank(dev, intel_crtc->pipe);
- if (intel_dp_aux_handshake_required(intel_dp))
- /* Write the link configuration data */
- intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
- intel_dp->link_configuration,
- DP_LINK_CONFIGURATION_SIZE);
+ /* Write the link configuration data */
+ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
+ intel_dp->link_configuration,
+ DP_LINK_CONFIGURATION_SIZE);
DP |= DP_PORT_EN;
if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
@@ -1283,7 +1291,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(intel_dp);
+ signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
@@ -1297,37 +1305,33 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
break;
/* Set training pattern 1 */
- udelay(500);
- if (intel_dp_aux_handshake_required(intel_dp)) {
+ udelay(100);
+ if (!intel_dp_get_link_status(intel_dp))
break;
- } else {
- if (!intel_dp_get_link_status(intel_dp))
- break;
- if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
- clock_recovery = true;
- break;
- }
+ if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+ clock_recovery = true;
+ break;
+ }
- /* Check to see if we've tried the max voltage */
- for (i = 0; i < intel_dp->lane_count; i++)
- if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
- break;
- if (i == intel_dp->lane_count)
+ /* Check to see if we've tried the max voltage */
+ for (i = 0; i < intel_dp->lane_count; i++)
+ if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
break;
+ if (i == intel_dp->lane_count)
+ break;
- /* Check to see if we've tried the same voltage 5 times */
- if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++tries;
- if (tries == 5)
- break;
- } else
- tries = 0;
- voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+ /* Check to see if we've tried the same voltage 5 times */
+ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++tries;
+ if (tries == 5)
+ break;
+ } else
+ tries = 0;
+ voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
- /* Compute new intel_dp->train_set as requested by target */
- intel_get_adjust_train(intel_dp);
- }
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
}
intel_dp->DP = DP;
@@ -1339,22 +1343,29 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
bool channel_eq = false;
- int tries;
+ int tries, cr_tries;
u32 reg;
uint32_t DP = intel_dp->DP;
/* channel equalization */
tries = 0;
+ cr_tries = 0;
channel_eq = false;
for (;;) {
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
uint32_t signal_levels;
+ if (cr_tries > 5) {
+ DRM_ERROR("failed to train DP, aborting\n");
+ intel_dp_link_down(intel_dp);
+ break;
+ }
+
if (IS_GEN6(dev) && is_edp(intel_dp)) {
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(intel_dp);
+ signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
@@ -1368,28 +1379,36 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
DP_TRAINING_PATTERN_2))
break;
- udelay(500);
-
- if (!intel_dp_aux_handshake_required(intel_dp)) {
+ udelay(400);
+ if (!intel_dp_get_link_status(intel_dp))
break;
- } else {
- if (!intel_dp_get_link_status(intel_dp))
- break;
- if (intel_channel_eq_ok(intel_dp)) {
- channel_eq = true;
- break;
- }
+ /* Make sure clock is still ok */
+ if (!intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+ intel_dp_start_link_train(intel_dp);
+ cr_tries++;
+ continue;
+ }
- /* Try 5 times */
- if (tries > 5)
- break;
+ if (intel_channel_eq_ok(intel_dp)) {
+ channel_eq = true;
+ break;
+ }
- /* Compute new intel_dp->train_set as requested by target */
- intel_get_adjust_train(intel_dp);
- ++tries;
+ /* Try 5 times, then try clock recovery if that fails */
+ if (tries > 5) {
+ intel_dp_link_down(intel_dp);
+ intel_dp_start_link_train(intel_dp);
+ tries = 0;
+ cr_tries++;
+ continue;
}
+
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
+ ++tries;
}
+
if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
reg = DP | DP_LINK_TRAIN_OFF_CPT;
else
@@ -1408,6 +1427,9 @@ intel_dp_link_down(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t DP = intel_dp->DP;
+ if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+ return;
+
DRM_DEBUG_KMS("\n");
if (is_edp(intel_dp)) {
@@ -1430,6 +1452,27 @@ intel_dp_link_down(struct intel_dp *intel_dp)
if (is_edp(intel_dp))
DP |= DP_LINK_TRAIN_OFF;
+
+ if (!HAS_PCH_CPT(dev) &&
+ I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+ /* Hardware workaround: leaving our transcoder select
+ * set to transcoder B while it's off will prevent the
+ * corresponding HDMI output on transcoder A.
+ *
+ * Combine this with another hardware workaround:
+ * transcoder select bit can only be cleared while the
+ * port is enabled.
+ */
+ DP &= ~DP_PIPEB_SELECT;
+ I915_WRITE(intel_dp->output_reg, DP);
+
+ /* Changes to enable or select take place the vblank
+ * after being written.
+ */
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg);
}
@@ -1517,7 +1560,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
status = connector_status_connected;
}
- return bit;
+ return status;
}
/**
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9af9f86a8765..74db2557d644 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -127,7 +127,7 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
struct intel_framebuffer {
struct drm_framebuffer base;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
};
struct intel_fbdev {
@@ -166,7 +166,7 @@ struct intel_crtc {
struct intel_unpin_work *unpin_work;
int fdi_lanes;
- struct drm_gem_object *cursor_bo;
+ struct drm_i915_gem_object *cursor_bo;
uint32_t cursor_addr;
int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height;
@@ -220,8 +220,8 @@ intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
struct intel_unpin_work {
struct work_struct work;
struct drm_device *dev;
- struct drm_gem_object *old_fb_obj;
- struct drm_gem_object *pending_flip_obj;
+ struct drm_i915_gem_object *old_fb_obj;
+ struct drm_i915_gem_object *pending_flip_obj;
struct drm_pending_vblank_event *event;
int pending;
bool enable_stall_check;
@@ -236,8 +236,9 @@ void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
-extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
-extern void intel_lvds_init(struct drm_device *dev);
+extern void intel_mark_busy(struct drm_device *dev,
+ struct drm_i915_gem_object *obj);
+extern bool intel_lvds_init(struct drm_device *dev);
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
@@ -256,6 +257,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
extern u32 intel_panel_get_backlight(struct drm_device *dev);
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
+extern void intel_panel_setup_backlight(struct drm_device *dev);
+extern void intel_panel_enable_backlight(struct drm_device *dev);
+extern void intel_panel_disable_backlight(struct drm_device *dev);
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder);
@@ -293,18 +297,22 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
-extern void intel_init_clock_gating(struct drm_device *dev);
+extern void intel_enable_clock_gating(struct drm_device *dev);
+extern void intel_disable_clock_gating(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
+extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
+extern void gen6_disable_rps(struct drm_device *dev);
+extern void intel_init_emon(struct drm_device *dev);
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
- struct drm_gem_object *obj,
- bool pipelined);
+ struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *pipelined);
extern int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
struct drm_mode_fb_cmd *mode_cmd,
- struct drm_gem_object *obj);
+ struct drm_i915_gem_object *obj);
extern int intel_fbdev_init(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index af2a1dddc28e..512782728e51 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -62,13 +62,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_device *dev = ifbdev->helper.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct fb_info *info;
struct drm_framebuffer *fb;
struct drm_mode_fb_cmd mode_cmd;
- struct drm_gem_object *fbo = NULL;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
struct device *device = &dev->pdev->dev;
- int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
+ int size, ret;
/* we don't do packed 24bpp */
if (sizes->surface_bpp == 24)
@@ -78,23 +78,22 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
mode_cmd.height = sizes->surface_height;
mode_cmd.bpp = sizes->surface_bpp;
- mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
+ mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64);
mode_cmd.depth = sizes->surface_depth;
size = mode_cmd.pitch * mode_cmd.height;
size = ALIGN(size, PAGE_SIZE);
- fbo = i915_gem_alloc_object(dev, size);
- if (!fbo) {
+ obj = i915_gem_alloc_object(dev, size);
+ if (!obj) {
DRM_ERROR("failed to allocate framebuffer\n");
ret = -ENOMEM;
goto out;
}
- obj_priv = to_intel_bo(fbo);
mutex_lock(&dev->struct_mutex);
/* Flush everything out, we'll be doing GTT only from now on */
- ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
+ ret = intel_pin_and_fence_fb_obj(dev, obj, false);
if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref;
@@ -108,7 +107,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
info->par = ifbdev;
- ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
+ ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
if (ret)
goto out_unpin;
@@ -122,6 +121,11 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &intelfb_ops;
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto out_unpin;
+ }
/* setup aperture base/size for vesafb takeover */
info->apertures = alloc_apertures(1);
if (!info->apertures) {
@@ -129,26 +133,17 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
goto out_unpin;
}
info->apertures->ranges[0].base = dev->mode_config.fb_base;
- if (!IS_GEN2(dev))
- info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
- else
- info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+ info->apertures->ranges[0].size =
+ dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
- info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
+ info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
info->fix.smem_len = size;
- info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset,
- size);
+ info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
if (!info->screen_base) {
ret = -ENOSPC;
goto out_unpin;
}
-
- ret = fb_alloc_cmap(&info->cmap, 256, 0);
- if (ret) {
- ret = -ENOMEM;
- goto out_unpin;
- }
info->screen_size = size;
// memset(info->screen_base, 0, size);
@@ -156,10 +151,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
- /* FIXME: we really shouldn't expose mmio space at all */
- info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
- info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar);
-
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
info->pixmap.access_align = 32;
@@ -168,7 +159,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
fb->width, fb->height,
- obj_priv->gtt_offset, fbo);
+ obj->gtt_offset, obj);
mutex_unlock(&dev->struct_mutex);
@@ -176,9 +167,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
return 0;
out_unpin:
- i915_gem_object_unpin(fbo);
+ i915_gem_object_unpin(obj);
out_unref:
- drm_gem_object_unreference(fbo);
+ drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
out:
return ret;
@@ -225,7 +216,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
drm_framebuffer_cleanup(&ifb->base);
if (ifb->obj) {
- drm_gem_object_unreference_unlocked(ifb->obj);
+ drm_gem_object_unreference_unlocked(&ifb->obj->base);
ifb->obj = NULL;
}
}
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 2be4f728ed0c..58040f68ed7a 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -85,8 +85,9 @@ static u32 get_reserved(struct intel_gpio *gpio)
/* On most chips, these bits must be preserved in software. */
if (!IS_I830(dev) && !IS_845G(dev))
- reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
- GPIO_CLOCK_PULLUP_DISABLE);
+ reserved = I915_READ_NOTRACE(gpio->reg) &
+ (GPIO_DATA_PULLUP_DISABLE |
+ GPIO_CLOCK_PULLUP_DISABLE);
return reserved;
}
@@ -96,9 +97,9 @@ static int get_clock(void *data)
struct intel_gpio *gpio = data;
struct drm_i915_private *dev_priv = gpio->dev_priv;
u32 reserved = get_reserved(gpio);
- I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
- I915_WRITE(gpio->reg, reserved);
- return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
+ I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+ I915_WRITE_NOTRACE(gpio->reg, reserved);
+ return (I915_READ_NOTRACE(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
}
static int get_data(void *data)
@@ -106,9 +107,9 @@ static int get_data(void *data)
struct intel_gpio *gpio = data;
struct drm_i915_private *dev_priv = gpio->dev_priv;
u32 reserved = get_reserved(gpio);
- I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
- I915_WRITE(gpio->reg, reserved);
- return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
+ I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+ I915_WRITE_NOTRACE(gpio->reg, reserved);
+ return (I915_READ_NOTRACE(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
}
static void set_clock(void *data, int state_high)
@@ -124,7 +125,7 @@ static void set_clock(void *data, int state_high)
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK;
- I915_WRITE(gpio->reg, reserved | clock_bits);
+ I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits);
POSTING_READ(gpio->reg);
}
@@ -141,7 +142,7 @@ static void set_data(void *data, int state_high)
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK;
- I915_WRITE(gpio->reg, reserved | data_bits);
+ I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits);
POSTING_READ(gpio->reg);
}
@@ -160,7 +161,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
};
struct intel_gpio *gpio;
- if (pin < 1 || pin > 7)
+ if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
return NULL;
gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
@@ -172,7 +173,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
gpio->reg += PCH_GPIOA - GPIOA;
gpio->dev_priv = dev_priv;
- snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+ snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
+ "i915 GPIO%c", "?BACDE?F"[pin]);
gpio->adapter.owner = THIS_MODULE;
gpio->adapter.algo_data = &gpio->algo;
gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
@@ -349,7 +351,7 @@ int intel_setup_gmbus(struct drm_device *dev)
"panel",
"dpc",
"dpb",
- "reserved"
+ "reserved",
"dpd",
};
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -366,8 +368,8 @@ int intel_setup_gmbus(struct drm_device *dev)
bus->adapter.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC;
snprintf(bus->adapter.name,
- I2C_NAME_SIZE,
- "gmbus %s",
+ sizeof(bus->adapter.name),
+ "i915 gmbus %s",
names[i]);
bus->adapter.dev.parent = &dev->pdev->dev;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f1a649990ea9..ace8d5d30dd2 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -68,7 +68,7 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
/**
* Sets the power state for the panel.
*/
-static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
+static void intel_lvds_enable(struct intel_lvds *intel_lvds)
{
struct drm_device *dev = intel_lvds->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -82,26 +82,60 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
lvds_reg = LVDS;
}
- if (on) {
- I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
- intel_panel_set_backlight(dev, dev_priv->backlight_level);
- } else {
- dev_priv->backlight_level = intel_panel_get_backlight(dev);
-
- intel_panel_set_backlight(dev, 0);
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
- if (intel_lvds->pfit_control) {
- if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
- DRM_ERROR("timed out waiting for panel to power off\n");
- I915_WRITE(PFIT_CONTROL, 0);
- intel_lvds->pfit_control = 0;
+ if (intel_lvds->pfit_dirty) {
+ /*
+ * Enable automatic panel scaling so that non-native modes
+ * fill the screen. The panel fitter should only be
+ * adjusted whilst the pipe is disabled, according to
+ * register description and PRM.
+ */
+ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+ intel_lvds->pfit_control,
+ intel_lvds->pfit_pgm_ratios);
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
+ DRM_ERROR("timed out waiting for panel to power off\n");
+ } else {
+ I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+ I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
intel_lvds->pfit_dirty = false;
}
+ }
+
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+ POSTING_READ(lvds_reg);
+
+ intel_panel_enable_backlight(dev);
+}
+
+static void intel_lvds_disable(struct intel_lvds *intel_lvds)
+{
+ struct drm_device *dev = intel_lvds->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 ctl_reg, lvds_reg;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ ctl_reg = PCH_PP_CONTROL;
+ lvds_reg = PCH_LVDS;
+ } else {
+ ctl_reg = PP_CONTROL;
+ lvds_reg = LVDS;
+ }
+
+ intel_panel_disable_backlight(dev);
- I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+
+ if (intel_lvds->pfit_control) {
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+ DRM_ERROR("timed out waiting for panel to power off\n");
+
+ I915_WRITE(PFIT_CONTROL, 0);
+ intel_lvds->pfit_dirty = true;
}
+
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
POSTING_READ(lvds_reg);
}
@@ -110,9 +144,9 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
if (mode == DRM_MODE_DPMS_ON)
- intel_lvds_set_power(intel_lvds, true);
+ intel_lvds_enable(intel_lvds);
else
- intel_lvds_set_power(intel_lvds, false);
+ intel_lvds_disable(intel_lvds);
/* XXX: We never power down the LVDS pairs. */
}
@@ -269,14 +303,13 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
- pfit_control |= PFIT_ENABLE;
/* 965+ is easy, it does everything in hw */
if (scaled_width > scaled_height)
- pfit_control |= PFIT_SCALING_PILLAR;
+ pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR;
else if (scaled_width < scaled_height)
- pfit_control |= PFIT_SCALING_LETTER;
- else
- pfit_control |= PFIT_SCALING_AUTO;
+ pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER;
+ else if (adjusted_mode->hdisplay != mode->hdisplay)
+ pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
} else {
u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
@@ -323,13 +356,17 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* Full scaling, even if it changes the aspect ratio.
* Fortunately this is all done for us in hw.
*/
- pfit_control |= PFIT_ENABLE;
- if (INTEL_INFO(dev)->gen >= 4)
- pfit_control |= PFIT_SCALING_AUTO;
- else
- pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
+ if (mode->vdisplay != adjusted_mode->vdisplay ||
+ mode->hdisplay != adjusted_mode->hdisplay) {
+ pfit_control |= PFIT_ENABLE;
+ if (INTEL_INFO(dev)->gen >= 4)
+ pfit_control |= PFIT_SCALING_AUTO;
+ else
+ pfit_control |= (VERT_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_AUTO_SCALE |
+ HORIZ_INTERP_BILINEAR);
+ }
break;
default:
@@ -337,6 +374,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
}
out:
+ if ((pfit_control & PFIT_ENABLE) == 0) {
+ pfit_control = 0;
+ pfit_pgm_ratios = 0;
+ }
if (pfit_control != intel_lvds->pfit_control ||
pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
intel_lvds->pfit_control = pfit_control;
@@ -360,8 +401,6 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
- dev_priv->backlight_level = intel_panel_get_backlight(dev);
-
/* We try to do the minimum that is necessary in order to unlock
* the registers for mode setting.
*
@@ -392,9 +431,6 @@ static void intel_lvds_commit(struct drm_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
- if (dev_priv->backlight_level == 0)
- dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
-
/* Undo any unlocking done in prepare to prevent accidental
* adjustment of the registers.
*/
@@ -411,43 +447,18 @@ static void intel_lvds_commit(struct drm_encoder *encoder)
/* Always do a full power on as we do not know what state
* we were left in.
*/
- intel_lvds_set_power(intel_lvds, true);
+ intel_lvds_enable(intel_lvds);
}
static void intel_lvds_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
-
/*
* The LVDS pin pair will already have been turned on in the
* intel_crtc_mode_set since it has a large impact on the DPLL
* settings.
*/
-
- if (HAS_PCH_SPLIT(dev))
- return;
-
- if (!intel_lvds->pfit_dirty)
- return;
-
- /*
- * Enable automatic panel scaling so that non-native modes fill the
- * screen. Should be enabled before the pipe is enabled, according to
- * register description and PRM.
- */
- DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
- intel_lvds->pfit_control,
- intel_lvds->pfit_pgm_ratios);
- if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
- DRM_ERROR("timed out waiting for panel to power off\n");
-
- I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
- I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
- intel_lvds->pfit_dirty = false;
}
/**
@@ -481,11 +492,8 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
- if (intel_lvds->edid) {
- drm_mode_connector_update_edid_property(connector,
- intel_lvds->edid);
+ if (intel_lvds->edid)
return drm_add_edid_modes(connector, intel_lvds->edid);
- }
mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
if (mode == 0)
@@ -696,6 +704,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
},
{
.callback = intel_no_lvds_dmi_callback,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = intel_no_lvds_dmi_callback,
.ident = "Aopen i945GTt-VFA",
.matches = {
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
@@ -840,7 +856,7 @@ static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
* Create the connector, register the LVDS DDC bus, and try to figure out what
* modes we can display on the LVDS panel (if present).
*/
-void intel_lvds_init(struct drm_device *dev)
+bool intel_lvds_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds *intel_lvds;
@@ -856,37 +872,37 @@ void intel_lvds_init(struct drm_device *dev)
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
- return;
+ return false;
pin = GMBUS_PORT_PANEL;
if (!lvds_is_present_in_vbt(dev, &pin)) {
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
- return;
+ return false;
}
if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
- return;
+ return false;
if (dev_priv->edp.support) {
DRM_DEBUG_KMS("disable LVDS for eDP support\n");
- return;
+ return false;
}
}
if (!intel_lvds_ddc_probe(dev, pin)) {
DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
- return;
+ return false;
}
intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
if (!intel_lvds) {
- return;
+ return false;
}
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
kfree(intel_lvds);
- return;
+ return false;
}
if (!HAS_PCH_SPLIT(dev)) {
@@ -907,6 +923,8 @@ void intel_lvds_init(struct drm_device *dev)
intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
intel_encoder->crtc_mask = (1 << 1);
+ if (INTEL_INFO(dev)->gen >= 5)
+ intel_encoder->crtc_mask |= (1 << 0);
drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
@@ -939,7 +957,16 @@ void intel_lvds_init(struct drm_device *dev)
*/
intel_lvds->edid = drm_get_edid(connector,
&dev_priv->gmbus[pin].adapter);
-
+ if (intel_lvds->edid) {
+ if (drm_add_edid_modes(connector,
+ intel_lvds->edid)) {
+ drm_mode_connector_update_edid_property(connector,
+ intel_lvds->edid);
+ } else {
+ kfree(intel_lvds->edid);
+ intel_lvds->edid = NULL;
+ }
+ }
if (!intel_lvds->edid) {
/* Didn't get an EDID, so
* Set wide sync ranges so we get all modes
@@ -1003,10 +1030,18 @@ void intel_lvds_init(struct drm_device *dev)
out:
if (HAS_PCH_SPLIT(dev)) {
u32 pwm;
- /* make sure PWM is enabled */
+
+ pipe = (I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT) ? 1 : 0;
+
+ /* make sure PWM is enabled and locked to the LVDS pipe */
pwm = I915_READ(BLC_PWM_CPU_CTL2);
- pwm |= (PWM_ENABLE | PWM_PIPE_B);
- I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
+ if (pipe == 0 && (pwm & PWM_PIPE_B))
+ I915_WRITE(BLC_PWM_CPU_CTL2, pwm & ~PWM_ENABLE);
+ if (pipe)
+ pwm |= PWM_PIPE_B;
+ else
+ pwm &= ~PWM_PIPE_B;
+ I915_WRITE(BLC_PWM_CPU_CTL2, pwm | PWM_ENABLE);
pwm = I915_READ(BLC_PWM_PCH_CTL1);
pwm |= PWM_PCH_ENABLE;
@@ -1020,7 +1055,7 @@ out:
/* keep the LVDS connector */
dev_priv->int_lvds_connector = connector;
drm_sysfs_connector_add(connector);
- return;
+ return true;
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
@@ -1028,4 +1063,5 @@ failed:
drm_encoder_cleanup(encoder);
kfree(intel_lvds);
kfree(intel_connector);
+ return false;
}
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 917c7dc3cd6b..f295a7aaadf9 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -273,14 +273,8 @@ void intel_opregion_enable_asle(struct drm_device *dev)
struct opregion_asle *asle = dev_priv->opregion.asle;
if (asle) {
- if (IS_MOBILE(dev)) {
- unsigned long irqflags;
-
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ if (IS_MOBILE(dev))
intel_enable_asle(dev);
- spin_unlock_irqrestore(&dev_priv->user_irq_lock,
- irqflags);
- }
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
ASLE_PFMB_EN;
@@ -512,6 +506,6 @@ int intel_opregion_setup(struct drm_device *dev)
return 0;
err_out:
- iounmap(opregion->header);
+ iounmap(base);
return err;
}
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index afb96d25219a..3fbb98b948d6 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -221,15 +221,16 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
int ret;
BUG_ON(overlay->last_flip_req);
- overlay->last_flip_req =
- i915_add_request(dev, NULL, request, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
-
+ ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv));
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+ overlay->last_flip_req = request->seqno;
overlay->flip_tail = tail;
ret = i915_do_wait_request(dev,
overlay->last_flip_req, true,
- &dev_priv->render_ring);
+ LP_RING(dev_priv));
if (ret)
return ret;
@@ -289,6 +290,7 @@ i830_deactivate_pipe_a(struct drm_device *dev)
static int intel_overlay_on(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_request *request;
int pipe_a_quirk = 0;
int ret;
@@ -308,7 +310,12 @@ static int intel_overlay_on(struct intel_overlay *overlay)
goto out;
}
- BEGIN_LP_RING(4);
+ ret = BEGIN_LP_RING(4);
+ if (ret) {
+ kfree(request);
+ goto out;
+ }
+
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
OUT_RING(overlay->flip_addr | OFC_UPDATE);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -332,6 +339,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
struct drm_i915_gem_request *request;
u32 flip_addr = overlay->flip_addr;
u32 tmp;
+ int ret;
BUG_ON(!overlay->active);
@@ -347,36 +355,44 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
if (tmp & (1 << 17))
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
- BEGIN_LP_RING(2);
+ ret = BEGIN_LP_RING(2);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr);
ADVANCE_LP_RING();
- overlay->last_flip_req =
- i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+ ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv));
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+
+ overlay->last_flip_req = request->seqno;
return 0;
}
static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
{
- struct drm_gem_object *obj = &overlay->old_vid_bo->base;
+ struct drm_i915_gem_object *obj = overlay->old_vid_bo;
i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
overlay->old_vid_bo = NULL;
}
static void intel_overlay_off_tail(struct intel_overlay *overlay)
{
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj = overlay->vid_bo;
/* never have the overlay hw on without showing a frame */
BUG_ON(!overlay->vid_bo);
- obj = &overlay->vid_bo->base;
i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
overlay->vid_bo = NULL;
overlay->crtc->overlay = NULL;
@@ -389,8 +405,10 @@ static int intel_overlay_off(struct intel_overlay *overlay,
bool interruptible)
{
struct drm_device *dev = overlay->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
u32 flip_addr = overlay->flip_addr;
struct drm_i915_gem_request *request;
+ int ret;
BUG_ON(!overlay->active);
@@ -404,7 +422,11 @@ static int intel_overlay_off(struct intel_overlay *overlay,
* of the hw. Do it in both cases */
flip_addr |= OFC_UPDATE;
- BEGIN_LP_RING(6);
+ ret = BEGIN_LP_RING(6);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
/* wait for overlay to go idle */
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr);
@@ -432,7 +454,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
return 0;
ret = i915_do_wait_request(dev, overlay->last_flip_req,
- interruptible, &dev_priv->render_ring);
+ interruptible, LP_RING(dev_priv));
if (ret)
return ret;
@@ -467,7 +489,12 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
if (request == NULL)
return -ENOMEM;
- BEGIN_LP_RING(2);
+ ret = BEGIN_LP_RING(2);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
@@ -736,13 +763,12 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
}
static int intel_overlay_do_put_image(struct intel_overlay *overlay,
- struct drm_gem_object *new_bo,
+ struct drm_i915_gem_object *new_bo,
struct put_image_params *params)
{
int ret, tmp_width;
struct overlay_registers *regs;
bool scale_changed = false;
- struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo);
struct drm_device *dev = overlay->dev;
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
@@ -753,7 +779,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
if (ret != 0)
return ret;
- ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
+ ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true);
if (ret != 0)
return ret;
@@ -761,6 +787,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
if (ret != 0)
goto out_unpin;
+ ret = i915_gem_object_put_fence(new_bo);
+ if (ret)
+ goto out_unpin;
+
if (!overlay->active) {
regs = intel_overlay_map_regs(overlay);
if (!regs) {
@@ -797,7 +827,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
regs->SWIDTHSW = calc_swidthsw(overlay->dev,
params->offset_Y, tmp_width);
regs->SHEIGHT = params->src_h;
- regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
+ regs->OBUF_0Y = new_bo->gtt_offset + params-> offset_Y;
regs->OSTRIDE = params->stride_Y;
if (params->format & I915_OVERLAY_YUV_PLANAR) {
@@ -811,8 +841,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
params->src_w/uv_hscale);
regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
- regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
- regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
+ regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;
+ regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;
regs->OSTRIDE |= params->stride_UV << 16;
}
@@ -829,7 +859,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
goto out_unpin;
overlay->old_vid_bo = overlay->vid_bo;
- overlay->vid_bo = to_intel_bo(new_bo);
+ overlay->vid_bo = new_bo;
return 0;
@@ -942,11 +972,13 @@ static int check_overlay_scaling(struct put_image_params *rec)
static int check_overlay_src(struct drm_device *dev,
struct drm_intel_overlay_put_image *rec,
- struct drm_gem_object *new_bo)
+ struct drm_i915_gem_object *new_bo)
{
int uv_hscale = uv_hsubsampling(rec->flags);
int uv_vscale = uv_vsubsampling(rec->flags);
- u32 stride_mask, depth, tmp;
+ u32 stride_mask;
+ int depth;
+ u32 tmp;
/* check src dimensions */
if (IS_845G(dev) || IS_I830(dev)) {
@@ -1025,7 +1057,7 @@ static int check_overlay_src(struct drm_device *dev,
return -EINVAL;
tmp = rec->stride_Y*rec->src_height;
- if (rec->offset_Y + tmp > new_bo->size)
+ if (rec->offset_Y + tmp > new_bo->base.size)
return -EINVAL;
break;
@@ -1036,12 +1068,12 @@ static int check_overlay_src(struct drm_device *dev,
return -EINVAL;
tmp = rec->stride_Y * rec->src_height;
- if (rec->offset_Y + tmp > new_bo->size)
+ if (rec->offset_Y + tmp > new_bo->base.size)
return -EINVAL;
tmp = rec->stride_UV * (rec->src_height / uv_vscale);
- if (rec->offset_U + tmp > new_bo->size ||
- rec->offset_V + tmp > new_bo->size)
+ if (rec->offset_U + tmp > new_bo->base.size ||
+ rec->offset_V + tmp > new_bo->base.size)
return -EINVAL;
break;
}
@@ -1084,7 +1116,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
struct intel_overlay *overlay;
struct drm_mode_object *drmmode_obj;
struct intel_crtc *crtc;
- struct drm_gem_object *new_bo;
+ struct drm_i915_gem_object *new_bo;
struct put_image_params *params;
int ret;
@@ -1123,8 +1155,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
}
crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
- new_bo = drm_gem_object_lookup(dev, file_priv,
- put_image_rec->bo_handle);
+ new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,
+ put_image_rec->bo_handle));
if (!new_bo) {
ret = -ENOENT;
goto out_free;
@@ -1133,6 +1165,12 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
mutex_lock(&dev->mode_config.mutex);
mutex_lock(&dev->struct_mutex);
+ if (new_bo->tiling_mode) {
+ DRM_ERROR("buffer used for overlay image can not be tiled\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
ret = intel_overlay_recover_from_interrupt(overlay, true);
if (ret != 0)
goto out_unlock;
@@ -1215,7 +1253,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
out_unlock:
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
- drm_gem_object_unreference_unlocked(new_bo);
+ drm_gem_object_unreference_unlocked(&new_bo->base);
out_free:
kfree(params);
@@ -1368,7 +1406,7 @@ void intel_setup_overlay(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_overlay *overlay;
- struct drm_gem_object *reg_bo;
+ struct drm_i915_gem_object *reg_bo;
struct overlay_registers *regs;
int ret;
@@ -1383,7 +1421,7 @@ void intel_setup_overlay(struct drm_device *dev)
reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
if (!reg_bo)
goto out_free;
- overlay->reg_bo = to_intel_bo(reg_bo);
+ overlay->reg_bo = reg_bo;
if (OVERLAY_NEEDS_PHYSICAL(dev)) {
ret = i915_gem_attach_phys_object(dev, reg_bo,
@@ -1393,14 +1431,14 @@ void intel_setup_overlay(struct drm_device *dev)
DRM_ERROR("failed to attach phys overlay regs\n");
goto out_free_bo;
}
- overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+ overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
} else {
- ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+ ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
if (ret) {
DRM_ERROR("failed to pin overlay register bo\n");
goto out_free_bo;
}
- overlay->flip_addr = overlay->reg_bo->gtt_offset;
+ overlay->flip_addr = reg_bo->gtt_offset;
ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
if (ret) {
@@ -1432,7 +1470,7 @@ void intel_setup_overlay(struct drm_device *dev)
out_unpin_bo:
i915_gem_object_unpin(reg_bo);
out_free_bo:
- drm_gem_object_unreference(reg_bo);
+ drm_gem_object_unreference(&reg_bo->base);
out_free:
kfree(overlay);
return;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 92ff8f385278..c65992df458d 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -125,15 +125,55 @@ static int is_backlight_combination_mode(struct drm_device *dev)
return 0;
}
+static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
+{
+ u32 val;
+
+ /* Restore the CTL value if it lost, e.g. GPU reset */
+
+ if (HAS_PCH_SPLIT(dev_priv->dev)) {
+ val = I915_READ(BLC_PWM_PCH_CTL2);
+ if (dev_priv->saveBLC_PWM_CTL2 == 0) {
+ dev_priv->saveBLC_PWM_CTL2 = val;
+ } else if (val == 0) {
+ I915_WRITE(BLC_PWM_PCH_CTL2,
+ dev_priv->saveBLC_PWM_CTL);
+ val = dev_priv->saveBLC_PWM_CTL;
+ }
+ } else {
+ val = I915_READ(BLC_PWM_CTL);
+ if (dev_priv->saveBLC_PWM_CTL == 0) {
+ dev_priv->saveBLC_PWM_CTL = val;
+ dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+ } else if (val == 0) {
+ I915_WRITE(BLC_PWM_CTL,
+ dev_priv->saveBLC_PWM_CTL);
+ I915_WRITE(BLC_PWM_CTL2,
+ dev_priv->saveBLC_PWM_CTL2);
+ val = dev_priv->saveBLC_PWM_CTL;
+ }
+ }
+
+ return val;
+}
+
u32 intel_panel_get_max_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 max;
+ max = i915_read_blc_pwm_ctl(dev_priv);
+ if (max == 0) {
+ /* XXX add code here to query mode clock or hardware clock
+ * and program max PWM appropriately.
+ */
+ printk_once(KERN_WARNING "fixme: max PWM is zero.\n");
+ return 1;
+ }
+
if (HAS_PCH_SPLIT(dev)) {
- max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+ max >>= 16;
} else {
- max = I915_READ(BLC_PWM_CTL);
if (IS_PINEVIEW(dev)) {
max >>= 17;
} else {
@@ -146,14 +186,6 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
max *= 0xff;
}
- if (max == 0) {
- /* XXX add code here to query mode clock or hardware clock
- * and program max PWM appropriately.
- */
- DRM_ERROR("fixme: max PWM is zero.\n");
- max = 1;
- }
-
DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
return max;
}
@@ -218,3 +250,34 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(BLC_PWM_CTL, tmp | level);
}
+
+void intel_panel_disable_backlight(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->backlight_enabled) {
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+ dev_priv->backlight_enabled = false;
+ }
+
+ intel_panel_set_backlight(dev, 0);
+}
+
+void intel_panel_enable_backlight(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->backlight_level == 0)
+ dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+
+ intel_panel_set_backlight(dev, dev_priv->backlight_level);
+ dev_priv->backlight_enabled = true;
+}
+
+void intel_panel_setup_backlight(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+ dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 09f2dc353ae2..03e337072517 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -48,14 +48,15 @@ static u32 i915_gem_get_seqno(struct drm_device *dev)
return seqno;
}
-static void
-render_ring_flush(struct drm_device *dev,
- struct intel_ring_buffer *ring,
+static int
+render_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate_domains,
u32 flush_domains)
{
+ struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 cmd;
+ int ret;
#if WATCH_EXEC
DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
@@ -109,79 +110,87 @@ render_ring_flush(struct drm_device *dev,
if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
cmd |= MI_EXE_FLUSH;
+ if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
+ (IS_G4X(dev) || IS_GEN5(dev)))
+ cmd |= MI_INVALIDATE_ISP;
+
#if WATCH_EXEC
DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
#endif
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring, cmd);
- intel_ring_emit(dev, ring, MI_NOOP);
- intel_ring_advance(dev, ring);
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, cmd);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
}
+
+ return 0;
}
-static void ring_write_tail(struct drm_device *dev,
- struct intel_ring_buffer *ring,
+static void ring_write_tail(struct intel_ring_buffer *ring,
u32 value)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
I915_WRITE_TAIL(ring, value);
}
-u32 intel_ring_get_active_head(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ u32 acthd_reg = INTEL_INFO(ring->dev)->gen >= 4 ?
RING_ACTHD(ring->mmio_base) : ACTHD;
return I915_READ(acthd_reg);
}
-static int init_ring_common(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static int init_ring_common(struct intel_ring_buffer *ring)
{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ struct drm_i915_gem_object *obj = ring->obj;
u32 head;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
- obj_priv = to_intel_bo(ring->gem_object);
/* Stop the ring if it's running. */
I915_WRITE_CTL(ring, 0);
I915_WRITE_HEAD(ring, 0);
- ring->write_tail(dev, ring, 0);
+ ring->write_tail(ring, 0);
/* Initialize the ring. */
- I915_WRITE_START(ring, obj_priv->gtt_offset);
+ I915_WRITE_START(ring, obj->gtt_offset);
head = I915_READ_HEAD(ring) & HEAD_ADDR;
/* G45 ring initialization fails to reset head to zero */
if (head != 0) {
- DRM_ERROR("%s head not reset to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- ring->name,
- I915_READ_CTL(ring),
- I915_READ_HEAD(ring),
- I915_READ_TAIL(ring),
- I915_READ_START(ring));
+ DRM_DEBUG_KMS("%s head not reset to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
I915_WRITE_HEAD(ring, 0);
- DRM_ERROR("%s head forced to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- ring->name,
- I915_READ_CTL(ring),
- I915_READ_HEAD(ring),
- I915_READ_TAIL(ring),
- I915_READ_START(ring));
+ if (I915_READ_HEAD(ring) & HEAD_ADDR) {
+ DRM_ERROR("failed to set %s head to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
+ }
}
I915_WRITE_CTL(ring,
- ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
- | RING_NO_REPORT | RING_VALID);
+ ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
+ | RING_REPORT_64K | RING_VALID);
- head = I915_READ_HEAD(ring) & HEAD_ADDR;
/* If the head is still not zero, the ring is dead */
- if (head != 0) {
+ if ((I915_READ_CTL(ring) & RING_VALID) == 0 ||
+ I915_READ_START(ring) != obj->gtt_offset ||
+ (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) {
DRM_ERROR("%s initialization failed "
"ctl %08x head %08x tail %08x start %08x\n",
ring->name,
@@ -192,8 +201,8 @@ static int init_ring_common(struct drm_device *dev,
return -EIO;
}
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_kernel_lost_context(dev);
+ if (!drm_core_check_feature(ring->dev, DRIVER_MODESET))
+ i915_kernel_lost_context(ring->dev);
else {
ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
@@ -201,335 +210,562 @@ static int init_ring_common(struct drm_device *dev,
if (ring->space < 0)
ring->space += ring->size;
}
+
return 0;
}
-static int init_render_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+/*
+ * 965+ support PIPE_CONTROL commands, which provide finer grained control
+ * over cache flushing.
+ */
+struct pipe_control {
+ struct drm_i915_gem_object *obj;
+ volatile u32 *cpu_page;
+ u32 gtt_offset;
+};
+
+static int
+init_pipe_control(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int ret = init_ring_common(dev, ring);
- int mode;
+ struct pipe_control *pc;
+ struct drm_i915_gem_object *obj;
+ int ret;
+
+ if (ring->private)
+ return 0;
+
+ pc = kmalloc(sizeof(*pc), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ obj = i915_gem_alloc_object(ring->dev, 4096);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate seqno page\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ obj->agp_type = AGP_USER_CACHED_MEMORY;
+
+ ret = i915_gem_object_pin(obj, 4096, true);
+ if (ret)
+ goto err_unref;
+
+ pc->gtt_offset = obj->gtt_offset;
+ pc->cpu_page = kmap(obj->pages[0]);
+ if (pc->cpu_page == NULL)
+ goto err_unpin;
+
+ pc->obj = obj;
+ ring->private = pc;
+ return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+err_unref:
+ drm_gem_object_unreference(&obj->base);
+err:
+ kfree(pc);
+ return ret;
+}
+
+static void
+cleanup_pipe_control(struct intel_ring_buffer *ring)
+{
+ struct pipe_control *pc = ring->private;
+ struct drm_i915_gem_object *obj;
+
+ if (!ring->private)
+ return;
+
+ obj = pc->obj;
+ kunmap(obj->pages[0]);
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(&obj->base);
+
+ kfree(pc);
+ ring->private = NULL;
+}
+
+static int init_render_ring(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret = init_ring_common(ring);
if (INTEL_INFO(dev)->gen > 3) {
- mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
+ int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
if (IS_GEN6(dev))
mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
I915_WRITE(MI_MODE, mode);
}
+
+ if (INTEL_INFO(dev)->gen >= 6) {
+ } else if (IS_GEN5(dev)) {
+ ret = init_pipe_control(ring);
+ if (ret)
+ return ret;
+ }
+
return ret;
}
-#define PIPE_CONTROL_FLUSH(addr) \
+static void render_ring_cleanup(struct intel_ring_buffer *ring)
+{
+ if (!ring->private)
+ return;
+
+ cleanup_pipe_control(ring);
+}
+
+static void
+update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int id;
+
+ /*
+ * cs -> 1 = vcs, 0 = bcs
+ * vcs -> 1 = bcs, 0 = cs,
+ * bcs -> 1 = cs, 0 = vcs.
+ */
+ id = ring - dev_priv->ring;
+ id += 2 - i;
+ id %= 3;
+
+ intel_ring_emit(ring,
+ MI_SEMAPHORE_MBOX |
+ MI_SEMAPHORE_REGISTER |
+ MI_SEMAPHORE_UPDATE);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring,
+ RING_SYNC_0(dev_priv->ring[id].mmio_base) + 4*i);
+}
+
+static int
+gen6_add_request(struct intel_ring_buffer *ring,
+ u32 *result)
+{
+ u32 seqno;
+ int ret;
+
+ ret = intel_ring_begin(ring, 10);
+ if (ret)
+ return ret;
+
+ seqno = i915_gem_get_seqno(ring->dev);
+ update_semaphore(ring, 0, seqno);
+ update_semaphore(ring, 1, seqno);
+
+ intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+ intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, MI_USER_INTERRUPT);
+ intel_ring_advance(ring);
+
+ *result = seqno;
+ return 0;
+}
+
+int
+intel_ring_sync(struct intel_ring_buffer *ring,
+ struct intel_ring_buffer *to,
+ u32 seqno)
+{
+ int ret;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring,
+ MI_SEMAPHORE_MBOX |
+ MI_SEMAPHORE_REGISTER |
+ intel_ring_sync_index(ring, to) << 17 |
+ MI_SEMAPHORE_COMPARE);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+
+ return 0;
+}
+
+#define PIPE_CONTROL_FLUSH(ring__, addr__) \
do { \
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
+ intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
PIPE_CONTROL_DEPTH_STALL | 2); \
- OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
- OUT_RING(0); \
- OUT_RING(0); \
+ intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT); \
+ intel_ring_emit(ring__, 0); \
+ intel_ring_emit(ring__, 0); \
} while (0)
-/**
- * Creates a new sequence number, emitting a write of it to the status page
- * plus an interrupt, which will trigger i915_user_interrupt_handler.
- *
- * Must be called with struct_lock held.
- *
- * Returned sequence numbers are nonzero on success.
- */
-static u32
-render_ring_add_request(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 flush_domains)
+static int
+pc_render_add_request(struct intel_ring_buffer *ring,
+ u32 *result)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- u32 seqno;
+ struct drm_device *dev = ring->dev;
+ u32 seqno = i915_gem_get_seqno(dev);
+ struct pipe_control *pc = ring->private;
+ u32 scratch_addr = pc->gtt_offset + 128;
+ int ret;
- seqno = i915_gem_get_seqno(dev);
-
- if (IS_GEN6(dev)) {
- BEGIN_LP_RING(6);
- OUT_RING(GFX_OP_PIPE_CONTROL | 3);
- OUT_RING(PIPE_CONTROL_QW_WRITE |
- PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH |
- PIPE_CONTROL_NOTIFY);
- OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
- OUT_RING(seqno);
- OUT_RING(0);
- OUT_RING(0);
- ADVANCE_LP_RING();
- } else if (HAS_PIPE_CONTROL(dev)) {
- u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
+ /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
+ * incoherent with writes to memory, i.e. completely fubar,
+ * so we need to use PIPE_NOTIFY instead.
+ *
+ * However, we also need to workaround the qword write
+ * incoherence by flushing the 6 PIPE_NOTIFY buffers out to
+ * memory before requesting an interrupt.
+ */
+ ret = intel_ring_begin(ring, 32);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
+ intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, 0);
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ scratch_addr += 128; /* write to separate cachelines */
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(ring, scratch_addr);
+ intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
+ PIPE_CONTROL_NOTIFY);
+ intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, 0);
+ intel_ring_advance(ring);
+
+ *result = seqno;
+ return 0;
+}
- /*
- * Workaround qword write incoherence by flushing the
- * PIPE_NOTIFY buffers out to memory before requesting
- * an interrupt.
- */
- BEGIN_LP_RING(32);
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
- PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
- OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
- OUT_RING(seqno);
- OUT_RING(0);
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128; /* write to separate cachelines */
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
- PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
- PIPE_CONTROL_NOTIFY);
- OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
- OUT_RING(seqno);
- OUT_RING(0);
- ADVANCE_LP_RING();
- } else {
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(seqno);
+static int
+render_ring_add_request(struct intel_ring_buffer *ring,
+ u32 *result)
+{
+ struct drm_device *dev = ring->dev;
+ u32 seqno = i915_gem_get_seqno(dev);
+ int ret;
- OUT_RING(MI_USER_INTERRUPT);
- ADVANCE_LP_RING();
- }
- return seqno;
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+ intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, MI_USER_INTERRUPT);
+ intel_ring_advance(ring);
+
+ *result = seqno;
+ return 0;
}
static u32
-render_ring_get_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ring_get_seqno(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- if (HAS_PIPE_CONTROL(dev))
- return ((volatile u32 *)(dev_priv->seqno_page))[0];
- else
- return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+ return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static u32
+pc_render_get_seqno(struct intel_ring_buffer *ring)
+{
+ struct pipe_control *pc = ring->private;
+ return pc->cpu_page[0];
}
static void
-render_ring_get_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ironlake_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long irqflags;
+ dev_priv->gt_irq_mask &= ~mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
+}
+
+static void
+ironlake_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ dev_priv->gt_irq_mask |= mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
+}
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- if (dev->irq_enabled && (++ring->user_irq_refcount == 1)) {
+static void
+i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ dev_priv->irq_mask &= ~mask;
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+}
+
+static void
+i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ dev_priv->irq_mask |= mask;
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+}
+
+static bool
+render_ring_get_irq(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock(&ring->irq_lock);
+ if (ring->irq_refcount++ == 0) {
if (HAS_PCH_SPLIT(dev))
- ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
+ ironlake_enable_irq(dev_priv,
+ GT_PIPE_NOTIFY | GT_USER_INTERRUPT);
else
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
}
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock(&ring->irq_lock);
+
+ return true;
}
static void
-render_ring_put_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+render_ring_put_irq(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long irqflags;
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- BUG_ON(dev->irq_enabled && ring->user_irq_refcount <= 0);
- if (dev->irq_enabled && (--ring->user_irq_refcount == 0)) {
+ spin_lock(&ring->irq_lock);
+ if (--ring->irq_refcount == 0) {
if (HAS_PCH_SPLIT(dev))
- ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
+ ironlake_disable_irq(dev_priv,
+ GT_USER_INTERRUPT |
+ GT_PIPE_NOTIFY);
else
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
}
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock(&ring->irq_lock);
}
-void intel_ring_setup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- if (IS_GEN6(dev)) {
- I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
- ring->status_page.gfx_addr);
- I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
- } else {
- I915_WRITE(RING_HWS_PGA(ring->mmio_base),
- ring->status_page.gfx_addr);
- I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
- }
-
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ u32 mmio = IS_GEN6(ring->dev) ?
+ RING_HWS_PGA_GEN6(ring->mmio_base) :
+ RING_HWS_PGA(ring->mmio_base);
+ I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
+ POSTING_READ(mmio);
}
-static void
-bsd_ring_flush(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 invalidate_domains,
- u32 flush_domains)
+static int
+bsd_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
{
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring, MI_FLUSH);
- intel_ring_emit(dev, ring, MI_NOOP);
- intel_ring_advance(dev, ring);
-}
+ int ret;
-static int init_bsd_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- return init_ring_common(dev, ring);
+ if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+ return 0;
+
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_FLUSH);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+ return 0;
}
-static u32
-ring_add_request(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 flush_domains)
+static int
+ring_add_request(struct intel_ring_buffer *ring,
+ u32 *result)
{
u32 seqno;
+ int ret;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
- seqno = i915_gem_get_seqno(dev);
+ seqno = i915_gem_get_seqno(ring->dev);
- intel_ring_begin(dev, ring, 4);
- intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
- intel_ring_emit(dev, ring,
- I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- intel_ring_emit(dev, ring, seqno);
- intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
- intel_ring_advance(dev, ring);
+ intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
+ intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ intel_ring_emit(ring, seqno);
+ intel_ring_emit(ring, MI_USER_INTERRUPT);
+ intel_ring_advance(ring);
DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+ *result = seqno;
+ return 0;
+}
- return seqno;
+static bool
+ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
+{
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock(&ring->irq_lock);
+ if (ring->irq_refcount++ == 0)
+ ironlake_enable_irq(dev_priv, flag);
+ spin_unlock(&ring->irq_lock);
+
+ return true;
}
static void
-bsd_ring_get_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ring_put_irq(struct intel_ring_buffer *ring, u32 flag)
{
- /* do nothing */
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ spin_lock(&ring->irq_lock);
+ if (--ring->irq_refcount == 0)
+ ironlake_disable_irq(dev_priv, flag);
+ spin_unlock(&ring->irq_lock);
}
+
+static bool
+gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+{
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock(&ring->irq_lock);
+ if (ring->irq_refcount++ == 0) {
+ ring->irq_mask &= ~rflag;
+ I915_WRITE_IMR(ring, ring->irq_mask);
+ ironlake_enable_irq(dev_priv, gflag);
+ }
+ spin_unlock(&ring->irq_lock);
+
+ return true;
+}
+
static void
-bsd_ring_put_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
{
- /* do nothing */
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ spin_lock(&ring->irq_lock);
+ if (--ring->irq_refcount == 0) {
+ ring->irq_mask |= rflag;
+ I915_WRITE_IMR(ring, ring->irq_mask);
+ ironlake_disable_irq(dev_priv, gflag);
+ }
+ spin_unlock(&ring->irq_lock);
}
-static u32
-ring_status_page_get_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static bool
+bsd_ring_get_irq(struct intel_ring_buffer *ring)
{
- return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+ return ring_get_irq(ring, GT_BSD_USER_INTERRUPT);
+}
+static void
+bsd_ring_put_irq(struct intel_ring_buffer *ring)
+{
+ ring_put_irq(ring, GT_BSD_USER_INTERRUPT);
}
static int
-ring_dispatch_gem_execbuffer(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
-{
- uint32_t exec_start;
- exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START |
- (2 << 6) | MI_BATCH_NON_SECURE_I965);
- intel_ring_emit(dev, ring, exec_start);
- intel_ring_advance(dev, ring);
+ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
+{
+ int ret;
+
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring,
+ MI_BATCH_BUFFER_START | (2 << 6) |
+ MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(ring, offset);
+ intel_ring_advance(ring);
+
return 0;
}
static int
-render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
+render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+ u32 offset, u32 len)
{
+ struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int nbox = exec->num_cliprects;
- int i = 0, count;
- uint32_t exec_start, exec_len;
- exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
- exec_len = (uint32_t) exec->batch_len;
+ int ret;
trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1);
- count = nbox ? nbox : 1;
+ if (IS_I830(dev) || IS_845G(dev)) {
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
- for (i = 0; i < count; i++) {
- if (i < nbox) {
- int ret = i915_emit_box(dev, cliprects, i,
- exec->DR1, exec->DR4);
- if (ret)
- return ret;
- }
+ intel_ring_emit(ring, MI_BATCH_BUFFER);
+ intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
+ intel_ring_emit(ring, offset + len - 8);
+ intel_ring_emit(ring, 0);
+ } else {
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
- if (IS_I830(dev) || IS_845G(dev)) {
- intel_ring_begin(dev, ring, 4);
- intel_ring_emit(dev, ring, MI_BATCH_BUFFER);
- intel_ring_emit(dev, ring,
- exec_start | MI_BATCH_NON_SECURE);
- intel_ring_emit(dev, ring, exec_start + exec_len - 4);
- intel_ring_emit(dev, ring, 0);
+ if (INTEL_INFO(dev)->gen >= 4) {
+ intel_ring_emit(ring,
+ MI_BATCH_BUFFER_START | (2 << 6) |
+ MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(ring, offset);
} else {
- intel_ring_begin(dev, ring, 2);
- if (INTEL_INFO(dev)->gen >= 4) {
- intel_ring_emit(dev, ring,
- MI_BATCH_BUFFER_START | (2 << 6)
- | MI_BATCH_NON_SECURE_I965);
- intel_ring_emit(dev, ring, exec_start);
- } else {
- intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START
- | (2 << 6));
- intel_ring_emit(dev, ring, exec_start |
- MI_BATCH_NON_SECURE);
- }
+ intel_ring_emit(ring,
+ MI_BATCH_BUFFER_START | (2 << 6));
+ intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
}
- intel_ring_advance(dev, ring);
}
-
- if (IS_G4X(dev) || IS_GEN5(dev)) {
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring, MI_FLUSH |
- MI_NO_WRITE_FLUSH |
- MI_INVALIDATE_ISP );
- intel_ring_emit(dev, ring, MI_NOOP);
- intel_ring_advance(dev, ring);
- }
- /* XXX breadcrumb */
+ intel_ring_advance(ring);
return 0;
}
-static void cleanup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static void cleanup_status_page(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ struct drm_i915_gem_object *obj;
obj = ring->status_page.obj;
if (obj == NULL)
return;
- obj_priv = to_intel_bo(obj);
- kunmap(obj_priv->pages[0]);
+ kunmap(obj->pages[0]);
i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
ring->status_page.obj = NULL;
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
}
-static int init_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static int init_status_page(struct intel_ring_buffer *ring)
{
+ struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_gem_object *obj;
int ret;
obj = i915_gem_alloc_object(dev, 4096);
@@ -538,16 +774,15 @@ static int init_status_page(struct drm_device *dev,
ret = -ENOMEM;
goto err;
}
- obj_priv = to_intel_bo(obj);
- obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+ obj->agp_type = AGP_USER_CACHED_MEMORY;
- ret = i915_gem_object_pin(obj, 4096);
+ ret = i915_gem_object_pin(obj, 4096, true);
if (ret != 0) {
goto err_unref;
}
- ring->status_page.gfx_addr = obj_priv->gtt_offset;
- ring->status_page.page_addr = kmap(obj_priv->pages[0]);
+ ring->status_page.gfx_addr = obj->gtt_offset;
+ ring->status_page.page_addr = kmap(obj->pages[0]);
if (ring->status_page.page_addr == NULL) {
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
goto err_unpin;
@@ -555,7 +790,7 @@ static int init_status_page(struct drm_device *dev,
ring->status_page.obj = obj;
memset(ring->status_page.page_addr, 0, PAGE_SIZE);
- intel_ring_setup_status_page(dev, ring);
+ intel_ring_setup_status_page(ring);
DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
ring->name, ring->status_page.gfx_addr);
@@ -564,7 +799,7 @@ static int init_status_page(struct drm_device *dev,
err_unpin:
i915_gem_object_unpin(obj);
err_unref:
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference(&obj->base);
err:
return ret;
}
@@ -572,9 +807,7 @@ err:
int intel_init_ring_buffer(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
int ret;
ring->dev = dev;
@@ -582,8 +815,11 @@ int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->gpu_write_list);
+ spin_lock_init(&ring->irq_lock);
+ ring->irq_mask = ~0;
+
if (I915_NEED_GFX_HWS(dev)) {
- ret = init_status_page(dev, ring);
+ ret = init_status_page(ring);
if (ret)
return ret;
}
@@ -595,15 +831,14 @@ int intel_init_ring_buffer(struct drm_device *dev,
goto err_hws;
}
- ring->gem_object = obj;
+ ring->obj = obj;
- ret = i915_gem_object_pin(obj, PAGE_SIZE);
+ ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
if (ret)
goto err_unref;
- obj_priv = to_intel_bo(obj);
ring->map.size = ring->size;
- ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
+ ring->map.offset = dev->agp->base + obj->gtt_offset;
ring->map.type = 0;
ring->map.flags = 0;
ring->map.mtrr = 0;
@@ -616,56 +851,64 @@ int intel_init_ring_buffer(struct drm_device *dev,
}
ring->virtual_start = ring->map.handle;
- ret = ring->init(dev, ring);
+ ret = ring->init(ring);
if (ret)
goto err_unmap;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_kernel_lost_context(dev);
- else {
- ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
- ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->size;
- }
- return ret;
+ /* Workaround an erratum on the i830 which causes a hang if
+ * the TAIL pointer points to within the last 2 cachelines
+ * of the buffer.
+ */
+ ring->effective_size = ring->size;
+ if (IS_I830(ring->dev))
+ ring->effective_size -= 128;
+
+ return 0;
err_unmap:
drm_core_ioremapfree(&ring->map, dev);
err_unpin:
i915_gem_object_unpin(obj);
err_unref:
- drm_gem_object_unreference(obj);
- ring->gem_object = NULL;
+ drm_gem_object_unreference(&obj->base);
+ ring->obj = NULL;
err_hws:
- cleanup_status_page(dev, ring);
+ cleanup_status_page(ring);
return ret;
}
-void intel_cleanup_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
{
- if (ring->gem_object == NULL)
+ struct drm_i915_private *dev_priv;
+ int ret;
+
+ if (ring->obj == NULL)
return;
- drm_core_ioremapfree(&ring->map, dev);
+ /* Disable the ring buffer. The ring must be idle at this point */
+ dev_priv = ring->dev->dev_private;
+ ret = intel_wait_ring_buffer(ring, ring->size - 8);
+ I915_WRITE_CTL(ring, 0);
+
+ drm_core_ioremapfree(&ring->map, ring->dev);
- i915_gem_object_unpin(ring->gem_object);
- drm_gem_object_unreference(ring->gem_object);
- ring->gem_object = NULL;
- cleanup_status_page(dev, ring);
+ i915_gem_object_unpin(ring->obj);
+ drm_gem_object_unreference(&ring->obj->base);
+ ring->obj = NULL;
+
+ if (ring->cleanup)
+ ring->cleanup(ring);
+
+ cleanup_status_page(ring);
}
-static int intel_wrap_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
{
unsigned int *virt;
- int rem;
- rem = ring->size - ring->tail;
+ int rem = ring->size - ring->tail;
if (ring->space < rem) {
- int ret = intel_wait_ring_buffer(dev, ring, rem);
+ int ret = intel_wait_ring_buffer(ring, rem);
if (ret)
return ret;
}
@@ -683,21 +926,29 @@ static int intel_wrap_ring_buffer(struct drm_device *dev,
return 0;
}
-int intel_wait_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n)
+int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long end;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 head;
trace_i915_ring_wait_begin (dev);
end = jiffies + 3 * HZ;
do {
- ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ /* If the reported head position has wrapped or hasn't advanced,
+ * fallback to the slow and accurate path.
+ */
+ head = intel_read_status_page(ring, 4);
+ if (head < ring->actual_head)
+ head = I915_READ_HEAD(ring);
+ ring->actual_head = head;
+ ring->head = head & HEAD_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
if (ring->space >= n) {
- trace_i915_ring_wait_end (dev);
+ trace_i915_ring_wait_end(dev);
return 0;
}
@@ -708,29 +959,39 @@ int intel_wait_ring_buffer(struct drm_device *dev,
}
msleep(1);
+ if (atomic_read(&dev_priv->mm.wedged))
+ return -EAGAIN;
} while (!time_after(jiffies, end));
trace_i915_ring_wait_end (dev);
return -EBUSY;
}
-void intel_ring_begin(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- int num_dwords)
+int intel_ring_begin(struct intel_ring_buffer *ring,
+ int num_dwords)
{
int n = 4*num_dwords;
- if (unlikely(ring->tail + n > ring->size))
- intel_wrap_ring_buffer(dev, ring);
- if (unlikely(ring->space < n))
- intel_wait_ring_buffer(dev, ring, n);
+ int ret;
+
+ if (unlikely(ring->tail + n > ring->effective_size)) {
+ ret = intel_wrap_ring_buffer(ring);
+ if (unlikely(ret))
+ return ret;
+ }
+
+ if (unlikely(ring->space < n)) {
+ ret = intel_wait_ring_buffer(ring, n);
+ if (unlikely(ret))
+ return ret;
+ }
ring->space -= n;
+ return 0;
}
-void intel_ring_advance(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+void intel_ring_advance(struct intel_ring_buffer *ring)
{
ring->tail &= ring->size - 1;
- ring->write_tail(dev, ring, ring->tail);
+ ring->write_tail(ring, ring->tail);
}
static const struct intel_ring_buffer render_ring = {
@@ -742,10 +1003,11 @@ static const struct intel_ring_buffer render_ring = {
.write_tail = ring_write_tail,
.flush = render_ring_flush,
.add_request = render_ring_add_request,
- .get_seqno = render_ring_get_seqno,
- .user_irq_get = render_ring_get_user_irq,
- .user_irq_put = render_ring_put_user_irq,
- .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
+ .get_seqno = ring_get_seqno,
+ .irq_get = render_ring_get_irq,
+ .irq_put = render_ring_put_irq,
+ .dispatch_execbuffer = render_ring_dispatch_execbuffer,
+ .cleanup = render_ring_cleanup,
};
/* ring buffer for bit-stream decoder */
@@ -755,22 +1017,21 @@ static const struct intel_ring_buffer bsd_ring = {
.id = RING_BSD,
.mmio_base = BSD_RING_BASE,
.size = 32 * PAGE_SIZE,
- .init = init_bsd_ring,
+ .init = init_ring_common,
.write_tail = ring_write_tail,
.flush = bsd_ring_flush,
.add_request = ring_add_request,
- .get_seqno = ring_status_page_get_seqno,
- .user_irq_get = bsd_ring_get_user_irq,
- .user_irq_put = bsd_ring_put_user_irq,
- .dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer,
+ .get_seqno = ring_get_seqno,
+ .irq_get = bsd_ring_get_irq,
+ .irq_put = bsd_ring_put_irq,
+ .dispatch_execbuffer = ring_dispatch_execbuffer,
};
-static void gen6_bsd_ring_write_tail(struct drm_device *dev,
- struct intel_ring_buffer *ring,
+static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
u32 value)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
/* Every tail move must follow the sequence below */
I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
@@ -789,69 +1050,206 @@ static void gen6_bsd_ring_write_tail(struct drm_device *dev,
GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
}
-static void gen6_ring_flush(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 invalidate_domains,
- u32 flush_domains)
+static int gen6_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
{
- intel_ring_begin(dev, ring, 4);
- intel_ring_emit(dev, ring, MI_FLUSH_DW);
- intel_ring_emit(dev, ring, 0);
- intel_ring_emit(dev, ring, 0);
- intel_ring_emit(dev, ring, 0);
- intel_ring_advance(dev, ring);
+ int ret;
+
+ if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+ return 0;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_FLUSH_DW);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, 0);
+ intel_ring_advance(ring);
+ return 0;
}
static int
-gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
+gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+ u32 offset, u32 len)
{
- uint32_t exec_start;
+ int ret;
- exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
- intel_ring_begin(dev, ring, 2);
- intel_ring_emit(dev, ring,
- MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
/* bit0-7 is the length on GEN6+ */
- intel_ring_emit(dev, ring, exec_start);
- intel_ring_advance(dev, ring);
+ intel_ring_emit(ring, offset);
+ intel_ring_advance(ring);
return 0;
}
+static bool
+gen6_render_ring_get_irq(struct intel_ring_buffer *ring)
+{
+ return gen6_ring_get_irq(ring,
+ GT_USER_INTERRUPT,
+ GEN6_RENDER_USER_INTERRUPT);
+}
+
+static void
+gen6_render_ring_put_irq(struct intel_ring_buffer *ring)
+{
+ return gen6_ring_put_irq(ring,
+ GT_USER_INTERRUPT,
+ GEN6_RENDER_USER_INTERRUPT);
+}
+
+static bool
+gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring)
+{
+ return gen6_ring_get_irq(ring,
+ GT_GEN6_BSD_USER_INTERRUPT,
+ GEN6_BSD_USER_INTERRUPT);
+}
+
+static void
+gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring)
+{
+ return gen6_ring_put_irq(ring,
+ GT_GEN6_BSD_USER_INTERRUPT,
+ GEN6_BSD_USER_INTERRUPT);
+}
+
/* ring buffer for Video Codec for Gen6+ */
static const struct intel_ring_buffer gen6_bsd_ring = {
- .name = "gen6 bsd ring",
- .id = RING_BSD,
- .mmio_base = GEN6_BSD_RING_BASE,
- .size = 32 * PAGE_SIZE,
- .init = init_bsd_ring,
- .write_tail = gen6_bsd_ring_write_tail,
- .flush = gen6_ring_flush,
- .add_request = ring_add_request,
- .get_seqno = ring_status_page_get_seqno,
- .user_irq_get = bsd_ring_get_user_irq,
- .user_irq_put = bsd_ring_put_user_irq,
- .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer,
+ .name = "gen6 bsd ring",
+ .id = RING_BSD,
+ .mmio_base = GEN6_BSD_RING_BASE,
+ .size = 32 * PAGE_SIZE,
+ .init = init_ring_common,
+ .write_tail = gen6_bsd_ring_write_tail,
+ .flush = gen6_ring_flush,
+ .add_request = gen6_add_request,
+ .get_seqno = ring_get_seqno,
+ .irq_get = gen6_bsd_ring_get_irq,
+ .irq_put = gen6_bsd_ring_put_irq,
+ .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
};
/* Blitter support (SandyBridge+) */
-static void
-blt_ring_get_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static bool
+blt_ring_get_irq(struct intel_ring_buffer *ring)
{
- /* do nothing */
+ return gen6_ring_get_irq(ring,
+ GT_BLT_USER_INTERRUPT,
+ GEN6_BLITTER_USER_INTERRUPT);
}
+
static void
-blt_ring_put_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+blt_ring_put_irq(struct intel_ring_buffer *ring)
{
- /* do nothing */
+ gen6_ring_put_irq(ring,
+ GT_BLT_USER_INTERRUPT,
+ GEN6_BLITTER_USER_INTERRUPT);
+}
+
+
+/* Workaround for some stepping of SNB,
+ * each time when BLT engine ring tail moved,
+ * the first command in the ring to be parsed
+ * should be MI_BATCH_BUFFER_START
+ */
+#define NEED_BLT_WORKAROUND(dev) \
+ (IS_GEN6(dev) && (dev->pdev->revision < 8))
+
+static inline struct drm_i915_gem_object *
+to_blt_workaround(struct intel_ring_buffer *ring)
+{
+ return ring->private;
+}
+
+static int blt_ring_init(struct intel_ring_buffer *ring)
+{
+ if (NEED_BLT_WORKAROUND(ring->dev)) {
+ struct drm_i915_gem_object *obj;
+ u32 *ptr;
+ int ret;
+
+ obj = i915_gem_alloc_object(ring->dev, 4096);
+ if (obj == NULL)
+ return -ENOMEM;
+
+ ret = i915_gem_object_pin(obj, 4096, true);
+ if (ret) {
+ drm_gem_object_unreference(&obj->base);
+ return ret;
+ }
+
+ ptr = kmap(obj->pages[0]);
+ *ptr++ = MI_BATCH_BUFFER_END;
+ *ptr++ = MI_NOOP;
+ kunmap(obj->pages[0]);
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, false);
+ if (ret) {
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(&obj->base);
+ return ret;
+ }
+
+ ring->private = obj;
+ }
+
+ return init_ring_common(ring);
+}
+
+static int blt_ring_begin(struct intel_ring_buffer *ring,
+ int num_dwords)
+{
+ if (ring->private) {
+ int ret = intel_ring_begin(ring, num_dwords+2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_BATCH_BUFFER_START);
+ intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset);
+
+ return 0;
+ } else
+ return intel_ring_begin(ring, 4);
+}
+
+static int blt_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+ int ret;
+
+ if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+ return 0;
+
+ ret = blt_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_FLUSH_DW);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, 0);
+ intel_ring_emit(ring, 0);
+ intel_ring_advance(ring);
+ return 0;
+}
+
+static void blt_ring_cleanup(struct intel_ring_buffer *ring)
+{
+ if (!ring->private)
+ return;
+
+ i915_gem_object_unpin(ring->private);
+ drm_gem_object_unreference(ring->private);
+ ring->private = NULL;
}
static const struct intel_ring_buffer gen6_blt_ring = {
@@ -859,49 +1257,59 @@ static const struct intel_ring_buffer gen6_blt_ring = {
.id = RING_BLT,
.mmio_base = BLT_RING_BASE,
.size = 32 * PAGE_SIZE,
- .init = init_ring_common,
+ .init = blt_ring_init,
.write_tail = ring_write_tail,
- .flush = gen6_ring_flush,
- .add_request = ring_add_request,
- .get_seqno = ring_status_page_get_seqno,
- .user_irq_get = blt_ring_get_user_irq,
- .user_irq_put = blt_ring_put_user_irq,
- .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer,
+ .flush = blt_ring_flush,
+ .add_request = gen6_add_request,
+ .get_seqno = ring_get_seqno,
+ .irq_get = blt_ring_get_irq,
+ .irq_put = blt_ring_put_irq,
+ .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
+ .cleanup = blt_ring_cleanup,
};
int intel_init_render_ring_buffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
-
- dev_priv->render_ring = render_ring;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+
+ *ring = render_ring;
+ if (INTEL_INFO(dev)->gen >= 6) {
+ ring->add_request = gen6_add_request;
+ ring->irq_get = gen6_render_ring_get_irq;
+ ring->irq_put = gen6_render_ring_put_irq;
+ } else if (IS_GEN5(dev)) {
+ ring->add_request = pc_render_add_request;
+ ring->get_seqno = pc_render_get_seqno;
+ }
if (!I915_NEED_GFX_HWS(dev)) {
- dev_priv->render_ring.status_page.page_addr
- = dev_priv->status_page_dmah->vaddr;
- memset(dev_priv->render_ring.status_page.page_addr,
- 0, PAGE_SIZE);
+ ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
+ memset(ring->status_page.page_addr, 0, PAGE_SIZE);
}
- return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+ return intel_init_ring_buffer(dev, ring);
}
int intel_init_bsd_ring_buffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
if (IS_GEN6(dev))
- dev_priv->bsd_ring = gen6_bsd_ring;
+ *ring = gen6_bsd_ring;
else
- dev_priv->bsd_ring = bsd_ring;
+ *ring = bsd_ring;
- return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+ return intel_init_ring_buffer(dev, ring);
}
int intel_init_blt_ring_buffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
- dev_priv->blt_ring = gen6_blt_ring;
+ *ring = gen6_blt_ring;
- return intel_init_ring_buffer(dev, &dev_priv->blt_ring);
+ return intel_init_ring_buffer(dev, ring);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index a05aff0e5764..be9087e4c9be 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -1,22 +1,40 @@
#ifndef _INTEL_RINGBUFFER_H_
#define _INTEL_RINGBUFFER_H_
+enum {
+ RCS = 0x0,
+ VCS,
+ BCS,
+ I915_NUM_RINGS,
+};
+
struct intel_hw_status_page {
- void *page_addr;
+ u32 __iomem *page_addr;
unsigned int gfx_addr;
- struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj;
};
-#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
-#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
-#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
-#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
-#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+#define I915_RING_READ(reg) i915_safe_read(dev_priv, reg)
+
+#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
+
+#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
+
+#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD((ring)->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
+
+#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
+
+#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
+#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base))
+
+#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base))
+#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base))
+#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base))
-struct drm_i915_gem_execbuffer2;
struct intel_ring_buffer {
const char *name;
enum intel_ring_id {
@@ -25,44 +43,40 @@ struct intel_ring_buffer {
RING_BLT = 0x4,
} id;
u32 mmio_base;
- unsigned long size;
void *virtual_start;
struct drm_device *dev;
- struct drm_gem_object *gem_object;
+ struct drm_i915_gem_object *obj;
- unsigned int head;
- unsigned int tail;
+ u32 actual_head;
+ u32 head;
+ u32 tail;
int space;
+ int size;
+ int effective_size;
struct intel_hw_status_page status_page;
- u32 irq_gem_seqno; /* last seq seem at irq time */
- u32 waiting_gem_seqno;
- int user_irq_refcount;
- void (*user_irq_get)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
- void (*user_irq_put)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ spinlock_t irq_lock;
+ u32 irq_refcount;
+ u32 irq_mask;
+ u32 irq_seqno; /* last seq seem at irq time */
+ u32 waiting_seqno;
+ u32 sync_seqno[I915_NUM_RINGS-1];
+ bool __must_check (*irq_get)(struct intel_ring_buffer *ring);
+ void (*irq_put)(struct intel_ring_buffer *ring);
- int (*init)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ int (*init)(struct intel_ring_buffer *ring);
- void (*write_tail)(struct drm_device *dev,
- struct intel_ring_buffer *ring,
+ void (*write_tail)(struct intel_ring_buffer *ring,
u32 value);
- void (*flush)(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 invalidate_domains,
- u32 flush_domains);
- u32 (*add_request)(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 flush_domains);
- u32 (*get_seqno)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
- int (*dispatch_gem_execbuffer)(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset);
+ int __must_check (*flush)(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains);
+ int (*add_request)(struct intel_ring_buffer *ring,
+ u32 *seqno);
+ u32 (*get_seqno)(struct intel_ring_buffer *ring);
+ int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
+ u32 offset, u32 length);
+ void (*cleanup)(struct intel_ring_buffer *ring);
/**
* List of objects currently involved in rendering from the
@@ -94,51 +108,63 @@ struct intel_ring_buffer {
/**
* Do we have some not yet emitted requests outstanding?
*/
- bool outstanding_lazy_request;
+ u32 outstanding_lazy_request;
wait_queue_head_t irq_queue;
drm_local_map_t map;
+
+ void *private;
};
static inline u32
+intel_ring_sync_index(struct intel_ring_buffer *ring,
+ struct intel_ring_buffer *other)
+{
+ int idx;
+
+ /*
+ * cs -> 0 = vcs, 1 = bcs
+ * vcs -> 0 = bcs, 1 = cs,
+ * bcs -> 0 = cs, 1 = vcs.
+ */
+
+ idx = (other - ring) - 1;
+ if (idx < 0)
+ idx += I915_NUM_RINGS;
+
+ return idx;
+}
+
+static inline u32
intel_read_status_page(struct intel_ring_buffer *ring,
- int reg)
+ int reg)
{
- u32 *regs = ring->status_page.page_addr;
- return regs[reg];
+ return ioread32(ring->status_page.page_addr + reg);
}
-int intel_init_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring);
-void intel_cleanup_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring);
-int intel_wait_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n);
-void intel_ring_begin(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n);
-
-static inline void intel_ring_emit(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- unsigned int data)
+void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
+int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
+int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
+
+static inline void intel_ring_emit(struct intel_ring_buffer *ring,
+ u32 data)
{
- unsigned int *virt = ring->virtual_start + ring->tail;
- *virt = data;
+ iowrite32(data, ring->virtual_start + ring->tail);
ring->tail += 4;
}
-void intel_ring_advance(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+void intel_ring_advance(struct intel_ring_buffer *ring);
-u32 intel_ring_get_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+u32 intel_ring_get_seqno(struct intel_ring_buffer *ring);
+int intel_ring_sync(struct intel_ring_buffer *ring,
+ struct intel_ring_buffer *to,
+ u32 seqno);
int intel_init_render_ring_buffer(struct drm_device *dev);
int intel_init_bsd_ring_buffer(struct drm_device *dev);
int intel_init_blt_ring_buffer(struct drm_device *dev);
-u32 intel_ring_get_active_head(struct drm_device *dev,
- struct intel_ring_buffer *ring);
-void intel_ring_setup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index de158b76bcd5..45cd37652a37 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -107,7 +107,8 @@ struct intel_sdvo {
* This is set if we treat the device as HDMI, instead of DVI.
*/
bool is_hdmi;
- bool has_audio;
+ bool has_hdmi_monitor;
+ bool has_hdmi_audio;
/**
* This is set if we detect output of sdvo device as LVDS and
@@ -1023,9 +1024,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
if (!intel_sdvo_set_target_input(intel_sdvo))
return;
- if (intel_sdvo->is_hdmi &&
- !intel_sdvo_set_avi_infoframe(intel_sdvo))
- return;
+ if (intel_sdvo->has_hdmi_monitor) {
+ intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
+ intel_sdvo_set_colorimetry(intel_sdvo,
+ SDVO_COLORIMETRY_RGB256);
+ intel_sdvo_set_avi_infoframe(intel_sdvo);
+ } else
+ intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
if (intel_sdvo->is_tv &&
!intel_sdvo_set_tv_format(intel_sdvo))
@@ -1044,7 +1049,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
/* Set the SDVO control regs. */
if (INTEL_INFO(dev)->gen >= 4) {
- sdvox = SDVO_BORDER_ENABLE;
+ sdvox = 0;
+ if (INTEL_INFO(dev)->gen < 5)
+ sdvox |= SDVO_BORDER_ENABLE;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1063,7 +1070,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
}
if (intel_crtc->pipe == 1)
sdvox |= SDVO_PIPE_B_SELECT;
- if (intel_sdvo->has_audio)
+ if (intel_sdvo->has_hdmi_audio)
sdvox |= SDVO_AUDIO_ENABLE;
if (INTEL_INFO(dev)->gen >= 4) {
@@ -1074,7 +1081,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
}
- if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
+ if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL &&
+ INTEL_INFO(dev)->gen < 5)
sdvox |= SDVO_STALL_SELECT;
intel_sdvo_write_sdvox(intel_sdvo, sdvox);
}
@@ -1295,55 +1303,14 @@ intel_sdvo_get_edid(struct drm_connector *connector)
return drm_get_edid(connector, &sdvo->ddc);
}
-static struct drm_connector *
-intel_find_analog_connector(struct drm_device *dev)
-{
- struct drm_connector *connector;
- struct intel_sdvo *encoder;
-
- list_for_each_entry(encoder,
- &dev->mode_config.encoder_list,
- base.base.head) {
- if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
- list_for_each_entry(connector,
- &dev->mode_config.connector_list,
- head) {
- if (&encoder->base ==
- intel_attached_encoder(connector))
- return connector;
- }
- }
- }
-
- return NULL;
-}
-
-static int
-intel_analog_is_connected(struct drm_device *dev)
-{
- struct drm_connector *analog_connector;
-
- analog_connector = intel_find_analog_connector(dev);
- if (!analog_connector)
- return false;
-
- if (analog_connector->funcs->detect(analog_connector, false) ==
- connector_status_disconnected)
- return false;
-
- return true;
-}
-
/* Mac mini hack -- use the same DDC as the analog connector */
static struct edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
- if (!intel_analog_is_connected(connector->dev))
- return NULL;
-
- return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ return drm_get_edid(connector,
+ &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
}
enum drm_connector_status
@@ -1388,8 +1355,10 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
/* DDC bus is shared, match EDID to connector type */
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
- intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
- intel_sdvo->has_audio = drm_detect_monitor_audio(edid);
+ if (intel_sdvo->is_hdmi) {
+ intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
+ intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
+ }
}
connector->display_info.raw_edid = NULL;
kfree(edid);
@@ -1398,7 +1367,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
if (status == connector_status_connected) {
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
if (intel_sdvo_connector->force_audio)
- intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0;
+ intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0;
}
return status;
@@ -1415,10 +1384,12 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
if (!intel_sdvo_write_cmd(intel_sdvo,
SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
return connector_status_unknown;
- if (intel_sdvo->is_tv) {
- /* add 30ms delay when the output type is SDVO-TV */
+
+ /* add 30ms delay when the output type might be TV */
+ if (intel_sdvo->caps.output_flags &
+ (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0))
mdelay(30);
- }
+
if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
return connector_status_unknown;
@@ -1431,6 +1402,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
intel_sdvo->attached_output = response;
+ intel_sdvo->has_hdmi_monitor = false;
+ intel_sdvo->has_hdmi_audio = false;
+
if ((intel_sdvo_connector->output_flag & response) == 0)
ret = connector_status_disconnected;
else if (response & SDVO_TMDS_MASK)
@@ -1472,8 +1446,10 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
edid = intel_sdvo_get_analog_edid(connector);
if (edid != NULL) {
- drm_mode_connector_update_edid_property(connector, edid);
- drm_add_edid_modes(connector, edid);
+ if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ drm_add_edid_modes(connector, edid);
+ }
connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -1713,12 +1689,12 @@ intel_sdvo_set_property(struct drm_connector *connector,
intel_sdvo_connector->force_audio = val;
- if (val > 0 && intel_sdvo->has_audio)
+ if (val > 0 && intel_sdvo->has_hdmi_audio)
return 0;
- if (val < 0 && !intel_sdvo->has_audio)
+ if (val < 0 && !intel_sdvo->has_hdmi_audio)
return 0;
- intel_sdvo->has_audio = val > 0;
+ intel_sdvo->has_hdmi_audio = val > 0;
goto done;
}
@@ -1942,28 +1918,18 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
speed = mapping->i2c_speed;
}
- sdvo->i2c = &dev_priv->gmbus[pin].adapter;
- intel_gmbus_set_speed(sdvo->i2c, speed);
- intel_gmbus_force_bit(sdvo->i2c, true);
+ if (pin < GMBUS_NUM_PORTS) {
+ sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+ intel_gmbus_set_speed(sdvo->i2c, speed);
+ intel_gmbus_force_bit(sdvo->i2c, true);
+ } else
+ sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;
}
static bool
intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
{
- int is_hdmi;
-
- if (!intel_sdvo_check_supp_encode(intel_sdvo))
- return false;
-
- if (!intel_sdvo_set_target_output(intel_sdvo,
- device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1))
- return false;
-
- is_hdmi = 0;
- if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1))
- return false;
-
- return !!is_hdmi;
+ return intel_sdvo_check_supp_encode(intel_sdvo);
}
static u8
@@ -2065,10 +2031,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
- /* enable hdmi encoding mode if supported */
- intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
- intel_sdvo_set_colorimetry(intel_sdvo,
- SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
intel_sdvo->is_hdmi = true;
}
@@ -2076,8 +2038,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
(1 << INTEL_ANALOG_CLONE_BIT));
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
-
- intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
+ if (intel_sdvo->is_hdmi)
+ intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 2f7681989316..93206e4eaa6f 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1245,10 +1245,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
int type;
/* Disable TV interrupts around load detect or we'll recurse */
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ i915_disable_pipestat(dev_priv, 0,
+ PIPE_HOTPLUG_INTERRUPT_ENABLE |
PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
save_tv_dac = tv_dac = I915_READ(TV_DAC);
save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
@@ -1301,10 +1302,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
I915_WRITE(TV_CTL, save_tv_ctl);
/* Restore interrupt config */
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ i915_enable_pipestat(dev_priv, 0,
+ PIPE_HOTPLUG_INTERRUPT_ENABLE |
PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return type;
}
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 72730e9ca06c..21d6c29c2d21 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -10,7 +10,7 @@ config DRM_NOUVEAU
select FB
select FRAMEBUFFER_CONSOLE if !EMBEDDED
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
- select ACPI_VIDEO if ACPI
+ select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
help
Choose this option for open-source nVidia support.
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 23fa82d667d6..e12c97fd8db8 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -5,27 +5,32 @@
ccflags-y := -Iinclude/drm
nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o nouveau_notifier.o \
- nouveau_sgdma.o nouveau_dma.o \
+ nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
nouveau_dp.o nouveau_ramht.o \
nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
+ nouveau_mm.o nouveau_vm.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o nvc0_graph.o \
- nv40_grctx.o nv50_grctx.o \
+ nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
+ nv84_crypt.o \
nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
- nv50_crtc.o nv50_dac.o nv50_sor.o \
- nv50_cursor.o nv50_display.o nv50_fbcon.o \
+ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
+ nv50_cursor.o nv50_display.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
- nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
+ nv04_crtc.o nv04_display.o nv04_cursor.o \
+ nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
nv10_gpio.o nv50_gpio.o \
nv50_calc.o \
- nv04_pm.o nv50_pm.o nva3_pm.o
+ nv04_pm.o nv50_pm.o nva3_pm.o \
+ nv50_vram.o nvc0_vram.o \
+ nv50_vm.o nvc0_vm.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 119152606e4c..a54238058dc5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -130,10 +130,15 @@ static int nouveau_dsm_init(void)
static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
{
- if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+ /* easy option one - intel vendor ID means Integrated */
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
return VGA_SWITCHEROO_IGD;
- else
- return VGA_SWITCHEROO_DIS;
+
+ /* is this device on Bus 0? - this may need improving */
+ if (pdev->bus->number == 0)
+ return VGA_SWITCHEROO_IGD;
+
+ return VGA_SWITCHEROO_DIS;
}
static struct vga_switcheroo_handler nouveau_dsm_handler = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 406228f4a2a0..d3a9c6e02477 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -31,6 +31,7 @@
*/
#include <linux/backlight.h>
+#include <linux/acpi.h>
#include "drmP.h"
#include "nouveau_drv.h"
@@ -58,7 +59,7 @@ static int nv40_set_intensity(struct backlight_device *bd)
return 0;
}
-static struct backlight_ops nv40_bl_ops = {
+static const struct backlight_ops nv40_bl_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = nv40_get_intensity,
.update_status = nv40_set_intensity,
@@ -81,7 +82,7 @@ static int nv50_set_intensity(struct backlight_device *bd)
return 0;
}
-static struct backlight_ops nv50_bl_ops = {
+static const struct backlight_ops nv50_bl_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = nv50_get_intensity,
.update_status = nv50_set_intensity,
@@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+#ifdef CONFIG_ACPI
+ if (acpi_video_backlight_support()) {
+ NV_INFO(dev, "ACPI backlight interface available, "
+ "not registering our own\n");
+ return 0;
+ }
+#endif
+
switch (dev_priv->card_type) {
case NV_40:
return nouveau_nv40_backlight_init(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 5f21030a293b..2aef5cd3acf5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -1927,7 +1927,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* offset (8 bit): opcode
* offset + 1 (16 bit): time
*
- * Sleep for "time" miliseconds.
+ * Sleep for "time" milliseconds.
*/
unsigned time = ROM16(bios->data[offset + 1]);
@@ -1935,7 +1935,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
if (!iexec->execute)
return 3;
- BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
+ BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n",
offset, time);
msleep(time);
@@ -6053,52 +6053,17 @@ static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
return entry;
}
-static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
+static void fabricate_dcb_output(struct dcb_table *dcb, int type, int i2c,
+ int heads, int or)
{
struct dcb_entry *entry = new_dcb_entry(dcb);
- entry->type = 0;
+ entry->type = type;
entry->i2c_index = i2c;
entry->heads = heads;
- entry->location = DCB_LOC_ON_CHIP;
- entry->or = 1;
-}
-
-static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
-{
- struct dcb_entry *entry = new_dcb_entry(dcb);
-
- entry->type = 2;
- entry->i2c_index = LEGACY_I2C_PANEL;
- entry->heads = twoHeads ? 3 : 1;
- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
- entry->or = 1; /* means |0x10 gets set on CRE_LCD__INDEX */
- entry->duallink_possible = false; /* SiI164 and co. are single link */
-
-#if 0
- /*
- * For dvi-a either crtc probably works, but my card appears to only
- * support dvi-d. "nvidia" still attempts to program it for dvi-a,
- * doing the full fp output setup (program 0x6808.. fp dimension regs,
- * setting 0x680848 to 0x10000111 to enable, maybe setting 0x680880);
- * the monitor picks up the mode res ok and lights up, but no pixel
- * data appears, so the board manufacturer probably connected up the
- * sync lines, but missed the video traces / components
- *
- * with this introduction, dvi-a left as an exercise for the reader.
- */
- fabricate_vga_output(dcb, LEGACY_I2C_PANEL, entry->heads);
-#endif
-}
-
-static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads)
-{
- struct dcb_entry *entry = new_dcb_entry(dcb);
-
- entry->type = 1;
- entry->i2c_index = LEGACY_I2C_TV;
- entry->heads = twoHeads ? 3 : 1;
- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
+ if (type != OUTPUT_ANALOG)
+ entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */
+ entry->or = or;
}
static bool
@@ -6365,8 +6330,36 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
return true;
}
+static void
+fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios)
+{
+ struct dcb_table *dcb = &bios->dcb;
+ int all_heads = (nv_two_heads(dev) ? 3 : 1);
+
+#ifdef __powerpc__
+ /* Apple iMac G4 NV17 */
+ if (of_machine_is_compatible("PowerMac4,5")) {
+ fabricate_dcb_output(dcb, OUTPUT_TMDS, 0, all_heads, 1);
+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, 1, all_heads, 2);
+ return;
+ }
+#endif
+
+ /* Make up some sane defaults */
+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, LEGACY_I2C_CRT, 1, 1);
+
+ if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
+ fabricate_dcb_output(dcb, OUTPUT_TV, LEGACY_I2C_TV,
+ all_heads, 0);
+
+ else if (bios->tmds.output0_script_ptr ||
+ bios->tmds.output1_script_ptr)
+ fabricate_dcb_output(dcb, OUTPUT_TMDS, LEGACY_I2C_PANEL,
+ all_heads, 1);
+}
+
static int
-parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &bios->dcb;
@@ -6386,12 +6379,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
/* this situation likely means a really old card, pre DCB */
if (dcbptr == 0x0) {
- NV_INFO(dev, "Assuming a CRT output exists\n");
- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1);
-
- if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
- fabricate_tv_output(dcb, twoHeads);
-
+ fabricate_dcb_encoder_table(dev, bios);
return 0;
}
@@ -6451,21 +6439,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
*/
NV_TRACEWARN(dev, "No useful information in BIOS output table; "
"adding all possible outputs\n");
- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1);
-
- /*
- * Attempt to detect TV before DVI because the test
- * for the former is more accurate and it rules the
- * latter out.
- */
- if (nv04_tv_identify(dev,
- bios->legacy.i2c_indices.tv) >= 0)
- fabricate_tv_output(dcb, twoHeads);
-
- else if (bios->tmds.output0_script_ptr ||
- bios->tmds.output1_script_ptr)
- fabricate_dvi_i_output(dcb, twoHeads);
-
+ fabricate_dcb_encoder_table(dev, bios);
return 0;
}
@@ -6829,7 +6803,7 @@ nouveau_bios_posted(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned htotal;
- if (dev_priv->chipset >= NV_50) {
+ if (dev_priv->card_type >= NV_50) {
if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
NVReadVgaCrtc(dev, 0, 0x1a) == 0)
return false;
@@ -6859,7 +6833,7 @@ nouveau_bios_init(struct drm_device *dev)
if (ret)
return ret;
- ret = parse_dcb_table(dev, bios, nv_two_heads(dev));
+ ret = parse_dcb_table(dev, bios);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 80353e2b8409..a7fae26f4654 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -32,6 +32,8 @@
#include "nouveau_drm.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
+#include "nouveau_mm.h"
+#include "nouveau_vm.h"
#include <linux/log2.h>
#include <linux/slab.h>
@@ -46,82 +48,51 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
if (unlikely(nvbo->gem))
DRM_ERROR("bo %p still attached to GEM object\n", bo);
- if (nvbo->tile)
- nv10_mem_expire_tiling(dev, nvbo->tile, NULL);
-
+ nv10_mem_put_tile_region(dev, nvbo->tile, NULL);
+ nouveau_vm_put(&nvbo->vma);
kfree(nvbo);
}
static void
-nouveau_bo_fixup_align(struct drm_device *dev,
- uint32_t tile_mode, uint32_t tile_flags,
- int *align, int *size)
+nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, int *size,
+ int *page_shift)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- /*
- * Some of the tile_flags have a periodic structure of N*4096 bytes,
- * align to to that as well as the page size. Align the size to the
- * appropriate boundaries. This does imply that sizes are rounded up
- * 3-7 pages, so be aware of this and do not waste memory by allocating
- * many small buffers.
- */
- if (dev_priv->card_type == NV_50) {
- uint32_t block_size = dev_priv->vram_size >> 15;
- int i;
-
- switch (tile_flags) {
- case 0x1800:
- case 0x2800:
- case 0x4800:
- case 0x7a00:
- if (is_power_of_2(block_size)) {
- for (i = 1; i < 10; i++) {
- *align = 12 * i * block_size;
- if (!(*align % 65536))
- break;
- }
- } else {
- for (i = 1; i < 10; i++) {
- *align = 8 * i * block_size;
- if (!(*align % 65536))
- break;
- }
- }
- *size = roundup(*size, *align);
- break;
- default:
- break;
- }
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
- } else {
- if (tile_mode) {
+ if (dev_priv->card_type < NV_50) {
+ if (nvbo->tile_mode) {
if (dev_priv->chipset >= 0x40) {
*align = 65536;
- *size = roundup(*size, 64 * tile_mode);
+ *size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x30) {
*align = 32768;
- *size = roundup(*size, 64 * tile_mode);
+ *size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x20) {
*align = 16384;
- *size = roundup(*size, 64 * tile_mode);
+ *size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x10) {
*align = 16384;
- *size = roundup(*size, 32 * tile_mode);
+ *size = roundup(*size, 32 * nvbo->tile_mode);
}
}
+ } else {
+ if (likely(dev_priv->chan_vm)) {
+ if (*size > 256 * 1024)
+ *page_shift = dev_priv->chan_vm->lpg_shift;
+ else
+ *page_shift = dev_priv->chan_vm->spg_shift;
+ } else {
+ *page_shift = 12;
+ }
+
+ *size = roundup(*size, (1 << *page_shift));
+ *align = max((1 << *page_shift), *align);
}
- /* ALIGN works only on powers of two. */
*size = roundup(*size, PAGE_SIZE);
-
- if (dev_priv->card_type == NV_50) {
- *size = roundup(*size, 65536);
- *align = max(65536, *align);
- }
}
int
@@ -132,7 +103,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *nvbo;
- int ret = 0;
+ int ret = 0, page_shift = 0;
nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
if (!nvbo)
@@ -143,10 +114,20 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
nvbo->no_vm = no_vm;
nvbo->tile_mode = tile_mode;
nvbo->tile_flags = tile_flags;
+ nvbo->bo.bdev = &dev_priv->ttm.bdev;
- nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
+ nouveau_bo_fixup_align(nvbo, &align, &size, &page_shift);
align >>= PAGE_SHIFT;
+ if (!nvbo->no_vm && dev_priv->chan_vm) {
+ ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift,
+ NV_MEM_ACCESS_RW, &nvbo->vma);
+ if (ret) {
+ kfree(nvbo);
+ return ret;
+ }
+ }
+
nouveau_bo_placement_set(nvbo, flags, 0);
nvbo->channel = chan;
@@ -159,6 +140,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
}
nvbo->channel = NULL;
+ if (nvbo->vma.node) {
+ if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
+ nvbo->bo.offset = nvbo->vma.offset;
+ }
+
*pnvbo = nvbo;
return 0;
}
@@ -176,6 +162,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
}
+static void
+set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+
+ if (dev_priv->card_type == NV_10 &&
+ nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+ /*
+ * Make sure that the color and depth buffers are handled
+ * by independent memory controller units. Up to a 9x
+ * speed up when alpha-blending and depth-test are enabled
+ * at the same time.
+ */
+ int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
+
+ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
+ nvbo->placement.fpfn = vram_pages / 2;
+ nvbo->placement.lpfn = ~0;
+ } else {
+ nvbo->placement.fpfn = 0;
+ nvbo->placement.lpfn = vram_pages / 2;
+ }
+ }
+}
+
void
nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
{
@@ -190,6 +201,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
pl->busy_placement = nvbo->busy_placements;
set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
type | busy, flags);
+
+ set_placement_range(nvbo, type);
}
int
@@ -215,7 +228,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
nouveau_bo_placement_set(nvbo, memtype, 0);
- ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false);
+ ret = nouveau_bo_validate(nvbo, false, false, false);
if (ret == 0) {
switch (bo->mem.mem_type) {
case TTM_PL_VRAM:
@@ -251,7 +264,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
- ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false);
+ ret = nouveau_bo_validate(nvbo, false, false, false);
if (ret == 0) {
switch (bo->mem.mem_type) {
case TTM_PL_VRAM:
@@ -290,6 +303,25 @@ nouveau_bo_unmap(struct nouveau_bo *nvbo)
ttm_bo_kunmap(&nvbo->kmap);
}
+int
+nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
+ bool no_wait_reserve, bool no_wait_gpu)
+{
+ int ret;
+
+ ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, interruptible,
+ no_wait_reserve, no_wait_gpu);
+ if (ret)
+ return ret;
+
+ if (nvbo->vma.node) {
+ if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
+ nvbo->bo.offset = nvbo->vma.offset;
+ }
+
+ return 0;
+}
+
u16
nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index)
{
@@ -381,37 +413,40 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_VRAM:
- man->func = &ttm_bo_manager_func;
+ if (dev_priv->card_type >= NV_50) {
+ man->func = &nouveau_vram_manager;
+ man->io_reserve_fastpath = false;
+ man->use_io_reserve_lru = true;
+ } else {
+ man->func = &ttm_bo_manager_func;
+ }
man->flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_MAPPABLE;
man->available_caching = TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_WC;
man->default_caching = TTM_PL_FLAG_WC;
- if (dev_priv->card_type == NV_50)
- man->gpu_offset = 0x40000000;
- else
- man->gpu_offset = 0;
break;
case TTM_PL_TT:
man->func = &ttm_bo_manager_func;
switch (dev_priv->gart_info.type) {
case NOUVEAU_GART_AGP:
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_FLAG_UNCACHED;
- man->default_caching = TTM_PL_FLAG_UNCACHED;
+ man->available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
break;
case NOUVEAU_GART_SGDMA:
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
TTM_MEMTYPE_FLAG_CMA;
man->available_caching = TTM_PL_MASK_CACHING;
man->default_caching = TTM_PL_FLAG_CACHED;
+ man->gpu_offset = dev_priv->gart_info.aper_base;
break;
default:
NV_ERROR(dev, "Unknown GART type: %d\n",
dev_priv->gart_info.type);
return -EINVAL;
}
- man->gpu_offset = dev_priv->vm_gart_base;
break;
default:
NV_ERROR(dev, "Unsupported memory type %u\n", (unsigned)type);
@@ -456,16 +491,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
if (ret)
return ret;
- if (nvbo->channel) {
- ret = nouveau_fence_sync(fence, nvbo->channel);
- if (ret)
- goto out;
- }
-
ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict,
no_wait_reserve, no_wait_gpu, new_mem);
-out:
- nouveau_fence_unref((void *)&fence);
+ nouveau_fence_unref(&fence);
return ret;
}
@@ -487,6 +515,58 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
}
static int
+nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+ u64 src_offset = old_mem->start << PAGE_SHIFT;
+ u64 dst_offset = new_mem->start << PAGE_SHIFT;
+ u32 page_count = new_mem->num_pages;
+ int ret;
+
+ if (!nvbo->no_vm) {
+ if (old_mem->mem_type == TTM_PL_VRAM)
+ src_offset = nvbo->vma.offset;
+ else
+ src_offset += dev_priv->gart_info.aper_base;
+
+ if (new_mem->mem_type == TTM_PL_VRAM)
+ dst_offset = nvbo->vma.offset;
+ else
+ dst_offset += dev_priv->gart_info.aper_base;
+ }
+
+ page_count = new_mem->num_pages;
+ while (page_count) {
+ int line_count = (page_count > 2047) ? 2047 : page_count;
+
+ ret = RING_SPACE(chan, 12);
+ if (ret)
+ return ret;
+
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0238, 2);
+ OUT_RING (chan, upper_32_bits(dst_offset));
+ OUT_RING (chan, lower_32_bits(dst_offset));
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x030c, 6);
+ OUT_RING (chan, upper_32_bits(src_offset));
+ OUT_RING (chan, lower_32_bits(src_offset));
+ OUT_RING (chan, PAGE_SIZE); /* src_pitch */
+ OUT_RING (chan, PAGE_SIZE); /* dst_pitch */
+ OUT_RING (chan, PAGE_SIZE); /* line_length */
+ OUT_RING (chan, line_count);
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0300, 1);
+ OUT_RING (chan, 0x00100110);
+
+ page_count -= line_count;
+ src_offset += (PAGE_SIZE * line_count);
+ dst_offset += (PAGE_SIZE * line_count);
+ }
+
+ return 0;
+}
+
+static int
nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
@@ -500,14 +580,14 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
dst_offset = new_mem->start << PAGE_SHIFT;
if (!nvbo->no_vm) {
if (old_mem->mem_type == TTM_PL_VRAM)
- src_offset += dev_priv->vm_vram_base;
+ src_offset = nvbo->vma.offset;
else
- src_offset += dev_priv->vm_gart_base;
+ src_offset += dev_priv->gart_info.aper_base;
if (new_mem->mem_type == TTM_PL_VRAM)
- dst_offset += dev_priv->vm_vram_base;
+ dst_offset = nvbo->vma.offset;
else
- dst_offset += dev_priv->vm_gart_base;
+ dst_offset += dev_priv->gart_info.aper_base;
}
ret = RING_SPACE(chan, 3);
@@ -525,7 +605,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
stride = 16 * 4;
height = amount / stride;
- if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ if (new_mem->mem_type == TTM_PL_VRAM &&
+ nouveau_bo_tile_layout(nvbo)) {
ret = RING_SPACE(chan, 8);
if (ret)
return ret;
@@ -546,7 +627,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
OUT_RING (chan, 1);
}
- if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ if (old_mem->mem_type == TTM_PL_VRAM &&
+ nouveau_bo_tile_layout(nvbo)) {
ret = RING_SPACE(chan, 8);
if (ret)
return ret;
@@ -652,17 +734,27 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
int ret;
chan = nvbo->channel;
- if (!chan || nvbo->no_vm)
+ if (!chan || nvbo->no_vm) {
chan = dev_priv->channel;
+ mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX);
+ }
if (dev_priv->card_type < NV_50)
ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
else
+ if (dev_priv->card_type < NV_C0)
ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
- if (ret)
- return ret;
+ else
+ ret = nvc0_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+ if (ret == 0) {
+ ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
+ no_wait_reserve,
+ no_wait_gpu, new_mem);
+ }
- return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+ if (chan == dev_priv->channel)
+ mutex_unlock(&chan->mutex);
+ return ret;
}
static int
@@ -740,7 +832,6 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
struct drm_device *dev = dev_priv->dev;
struct nouveau_bo *nvbo = nouveau_bo(bo);
uint64_t offset;
- int ret;
if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) {
/* Nothing to do. */
@@ -750,17 +841,12 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
offset = new_mem->start << PAGE_SHIFT;
- if (dev_priv->card_type == NV_50) {
- ret = nv50_mem_vm_bind_linear(dev,
- offset + dev_priv->vm_vram_base,
- new_mem->size, nvbo->tile_flags,
- offset);
- if (ret)
- return ret;
-
+ if (dev_priv->chan_vm) {
+ nouveau_vm_map(&nvbo->vma, new_mem->mm_node);
} else if (dev_priv->card_type >= NV_10) {
*new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size,
- nvbo->tile_mode);
+ nvbo->tile_mode,
+ nvbo->tile_flags);
}
return 0;
@@ -776,9 +862,7 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
if (dev_priv->card_type >= NV_10 &&
dev_priv->card_type < NV_50) {
- if (*old_tile)
- nv10_mem_expire_tiling(dev, *old_tile, bo->sync_obj);
-
+ nv10_mem_put_tile_region(dev, *old_tile, bo->sync_obj);
*old_tile = new_tile;
}
}
@@ -847,6 +931,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
struct drm_device *dev = dev_priv->dev;
+ int ret;
mem->bus.addr = NULL;
mem->bus.offset = 0;
@@ -869,9 +954,40 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
#endif
break;
case TTM_PL_VRAM:
- mem->bus.offset = mem->start << PAGE_SHIFT;
+ {
+ struct nouveau_vram *vram = mem->mm_node;
+ u8 page_shift;
+
+ if (!dev_priv->bar1_vm) {
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ mem->bus.base = pci_resource_start(dev->pdev, 1);
+ mem->bus.is_iomem = true;
+ break;
+ }
+
+ if (dev_priv->card_type == NV_C0)
+ page_shift = vram->page_shift;
+ else
+ page_shift = 12;
+
+ ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size,
+ page_shift, NV_MEM_ACCESS_RW,
+ &vram->bar_vma);
+ if (ret)
+ return ret;
+
+ nouveau_vm_map(&vram->bar_vma, vram);
+ if (ret) {
+ nouveau_vm_put(&vram->bar_vma);
+ return ret;
+ }
+
+ mem->bus.offset = vram->bar_vma.offset;
+ if (dev_priv->card_type == NV_50) /*XXX*/
+ mem->bus.offset -= 0x0020000000ULL;
mem->bus.base = pci_resource_start(dev->pdev, 1);
mem->bus.is_iomem = true;
+ }
break;
default:
return -EINVAL;
@@ -882,6 +998,17 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
static void
nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
+ struct nouveau_vram *vram = mem->mm_node;
+
+ if (!dev_priv->bar1_vm || mem->mem_type != TTM_PL_VRAM)
+ return;
+
+ if (!vram->bar_vma.node)
+ return;
+
+ nouveau_vm_unmap(&vram->bar_vma);
+ nouveau_vm_put(&vram->bar_vma);
}
static int
@@ -894,7 +1021,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
* nothing to do here.
*/
if (bo->mem.mem_type != TTM_PL_VRAM) {
- if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
+ if (dev_priv->card_type < NV_50 ||
+ !nouveau_bo_tile_layout(nvbo))
return 0;
}
@@ -906,7 +1034,23 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
nvbo->placement.fpfn = 0;
nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0);
- return ttm_bo_validate(bo, &nvbo->placement, false, true, false);
+ return nouveau_bo_validate(nvbo, false, true, false);
+}
+
+void
+nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
+{
+ struct nouveau_fence *old_fence;
+
+ if (likely(fence))
+ nouveau_fence_ref(fence);
+
+ spin_lock(&nvbo->bo.bdev->fence_lock);
+ old_fence = nvbo->bo.sync_obj;
+ nvbo->bo.sync_obj = fence;
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
+
+ nouveau_fence_unref(&old_fence);
}
struct ttm_bo_driver nouveau_bo_driver = {
@@ -916,11 +1060,11 @@ struct ttm_bo_driver nouveau_bo_driver = {
.evict_flags = nouveau_bo_evict_flags,
.move = nouveau_bo_move,
.verify_access = nouveau_bo_verify_access,
- .sync_obj_signaled = nouveau_fence_signalled,
- .sync_obj_wait = nouveau_fence_wait,
- .sync_obj_flush = nouveau_fence_flush,
- .sync_obj_unref = nouveau_fence_unref,
- .sync_obj_ref = nouveau_fence_ref,
+ .sync_obj_signaled = __nouveau_fence_signalled,
+ .sync_obj_wait = __nouveau_fence_wait,
+ .sync_obj_flush = __nouveau_fence_flush,
+ .sync_obj_unref = __nouveau_fence_unref,
+ .sync_obj_ref = __nouveau_fence_ref,
.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
.io_mem_free = &nouveau_ttm_io_mem_free,
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 373950e34814..3960d66d7aba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -38,23 +38,28 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
int ret;
if (dev_priv->card_type >= NV_50) {
- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
- dev_priv->vm_end, NV_DMA_ACCESS_RO,
- NV_DMA_TARGET_AGP, &pushbuf);
+ if (dev_priv->card_type < NV_C0) {
+ ret = nouveau_gpuobj_dma_new(chan,
+ NV_CLASS_DMA_IN_MEMORY, 0,
+ (1ULL << 40),
+ NV_MEM_ACCESS_RO,
+ NV_MEM_TARGET_VM,
+ &pushbuf);
+ }
chan->pushbuf_base = pb->bo.offset;
} else
if (pb->bo.mem.mem_type == TTM_PL_TT) {
- ret = nouveau_gpuobj_gart_dma_new(chan, 0,
- dev_priv->gart_info.aper_size,
- NV_DMA_ACCESS_RO, &pushbuf,
- NULL);
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
+ dev_priv->gart_info.aper_size,
+ NV_MEM_ACCESS_RO,
+ NV_MEM_TARGET_GART, &pushbuf);
chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
} else
if (dev_priv->card_type != NV_04) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->fb_available_size,
- NV_DMA_ACCESS_RO,
- NV_DMA_TARGET_VIDMEM, &pushbuf);
+ NV_MEM_ACCESS_RO,
+ NV_MEM_TARGET_VRAM, &pushbuf);
chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
} else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's
@@ -62,17 +67,16 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
* VRAM.
*/
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- pci_resource_start(dev->pdev,
- 1),
+ pci_resource_start(dev->pdev, 1),
dev_priv->fb_available_size,
- NV_DMA_ACCESS_RO,
- NV_DMA_TARGET_PCI, &pushbuf);
+ NV_MEM_ACCESS_RO,
+ NV_MEM_TARGET_PCI, &pushbuf);
chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
}
nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
nouveau_gpuobj_ref(NULL, &pushbuf);
- return 0;
+ return ret;
}
static struct nouveau_bo *
@@ -100,6 +104,13 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev)
return NULL;
}
+ ret = nouveau_bo_map(pushbuf);
+ if (ret) {
+ nouveau_bo_unpin(pushbuf);
+ nouveau_bo_ref(NULL, &pushbuf);
+ return NULL;
+ }
+
return pushbuf;
}
@@ -107,74 +118,59 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev)
int
nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
struct drm_file *file_priv,
- uint32_t vram_handle, uint32_t tt_handle)
+ uint32_t vram_handle, uint32_t gart_handle)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
- int channel, user;
+ unsigned long flags;
int ret;
- /*
- * Alright, here is the full story
- * Nvidia cards have multiple hw fifo contexts (praise them for that,
- * no complicated crash-prone context switches)
- * We allocate a new context for each app and let it write to it
- * directly (woo, full userspace command submission !)
- * When there are no more contexts, you lost
- */
- for (channel = 0; channel < pfifo->channels; channel++) {
- if (dev_priv->fifos[channel] == NULL)
+ /* allocate and lock channel structure */
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+ chan->dev = dev;
+ chan->file_priv = file_priv;
+ chan->vram_handle = vram_handle;
+ chan->gart_handle = gart_handle;
+
+ kref_init(&chan->ref);
+ atomic_set(&chan->users, 1);
+ mutex_init(&chan->mutex);
+ mutex_lock(&chan->mutex);
+
+ /* allocate hw channel id */
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (chan->id = 0; chan->id < pfifo->channels; chan->id++) {
+ if (!dev_priv->channels.ptr[chan->id]) {
+ nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]);
break;
+ }
}
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
- /* no more fifos. you lost. */
- if (channel == pfifo->channels)
- return -EINVAL;
+ if (chan->id == pfifo->channels) {
+ mutex_unlock(&chan->mutex);
+ kfree(chan);
+ return -ENODEV;
+ }
- dev_priv->fifos[channel] = kzalloc(sizeof(struct nouveau_channel),
- GFP_KERNEL);
- if (!dev_priv->fifos[channel])
- return -ENOMEM;
- chan = dev_priv->fifos[channel];
+ NV_DEBUG(dev, "initialising channel %d\n", chan->id);
INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
+ INIT_LIST_HEAD(&chan->nvsw.flip);
INIT_LIST_HEAD(&chan->fence.pending);
- chan->dev = dev;
- chan->id = channel;
- chan->file_priv = file_priv;
- chan->vram_handle = vram_handle;
- chan->gart_handle = tt_handle;
-
- NV_INFO(dev, "Allocating FIFO number %d\n", channel);
/* Allocate DMA push buffer */
chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev);
if (!chan->pushbuf_bo) {
ret = -ENOMEM;
NV_ERROR(dev, "pushbuf %d\n", ret);
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
nouveau_dma_pre_init(chan);
-
- /* Locate channel's user control regs */
- if (dev_priv->card_type < NV_40)
- user = NV03_USER(channel);
- else
- if (dev_priv->card_type < NV_50)
- user = NV40_USER(channel);
- else
- user = NV50_USER(channel);
-
- chan->user = ioremap(pci_resource_start(dev->pdev, 0) + user,
- PAGE_SIZE);
- if (!chan->user) {
- NV_ERROR(dev, "ioremap of regs failed.\n");
- nouveau_channel_free(chan);
- return -ENOMEM;
- }
chan->user_put = 0x40;
chan->user_get = 0x44;
@@ -182,15 +178,15 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
ret = nouveau_notifier_init_channel(chan);
if (ret) {
NV_ERROR(dev, "ntfy %d\n", ret);
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
/* Setup channel's default objects */
- ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle);
+ ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle);
if (ret) {
NV_ERROR(dev, "gpuobj %d\n", ret);
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
@@ -198,24 +194,17 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
ret = nouveau_channel_pushbuf_ctxdma_init(chan);
if (ret) {
NV_ERROR(dev, "pbctxdma %d\n", ret);
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
/* disable the fifo caches */
pfifo->reassign(dev, false);
- /* Create a graphics context for new channel */
- ret = pgraph->create_context(chan);
- if (ret) {
- nouveau_channel_free(chan);
- return ret;
- }
-
/* Construct inital RAMFC for new channel */
ret = pfifo->create_context(chan);
if (ret) {
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
@@ -225,83 +214,111 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
if (!ret)
ret = nouveau_fence_channel_init(chan);
if (ret) {
- nouveau_channel_free(chan);
+ nouveau_channel_put(&chan);
return ret;
}
nouveau_debugfs_channel_init(chan);
- NV_INFO(dev, "%s: initialised FIFO %d\n", __func__, channel);
+ NV_DEBUG(dev, "channel %d initialised\n", chan->id);
*chan_ret = chan;
return 0;
}
-/* stops a fifo */
+struct nouveau_channel *
+nouveau_channel_get_unlocked(struct nouveau_channel *ref)
+{
+ struct nouveau_channel *chan = NULL;
+
+ if (likely(ref && atomic_inc_not_zero(&ref->users)))
+ nouveau_channel_ref(ref, &chan);
+
+ return chan;
+}
+
+struct nouveau_channel *
+nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ unsigned long flags;
+
+ if (unlikely(id < 0 || id >= NOUVEAU_MAX_CHANNEL_NR))
+ return ERR_PTR(-EINVAL);
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ chan = nouveau_channel_get_unlocked(dev_priv->channels.ptr[id]);
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+
+ if (unlikely(!chan))
+ return ERR_PTR(-EINVAL);
+
+ if (unlikely(file_priv && chan->file_priv != file_priv)) {
+ nouveau_channel_put_unlocked(&chan);
+ return ERR_PTR(-EINVAL);
+ }
+
+ mutex_lock(&chan->mutex);
+ return chan;
+}
+
void
-nouveau_channel_free(struct nouveau_channel *chan)
+nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
{
+ struct nouveau_channel *chan = *pchan;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
unsigned long flags;
- int ret;
- NV_INFO(dev, "%s: freeing fifo %d\n", __func__, chan->id);
+ /* decrement the refcount, and we're done if there's still refs */
+ if (likely(!atomic_dec_and_test(&chan->users))) {
+ nouveau_channel_ref(NULL, pchan);
+ return;
+ }
+ /* noone wants the channel anymore */
+ NV_DEBUG(dev, "freeing channel %d\n", chan->id);
nouveau_debugfs_channel_fini(chan);
- /* Give outstanding push buffers a chance to complete */
- nouveau_fence_update(chan);
- if (chan->fence.sequence != chan->fence.sequence_ack) {
- struct nouveau_fence *fence = NULL;
+ /* give it chance to idle */
+ nouveau_channel_idle(chan);
- ret = nouveau_fence_new(chan, &fence, true);
- if (ret == 0) {
- ret = nouveau_fence_wait(fence, NULL, false, false);
- nouveau_fence_unref((void *)&fence);
- }
-
- if (ret)
- NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
- }
-
- /* Ensure all outstanding fences are signaled. They should be if the
+ /* ensure all outstanding fences are signaled. they should be if the
* above attempts at idling were OK, but if we failed this'll tell TTM
* we're done with the buffers.
*/
nouveau_fence_channel_fini(chan);
- /* This will prevent pfifo from switching channels. */
+ /* boot it off the hardware */
pfifo->reassign(dev, false);
- /* We want to give pgraph a chance to idle and get rid of all potential
- * errors. We need to do this before the lock, otherwise the irq handler
- * is unable to process them.
+ /* We want to give pgraph a chance to idle and get rid of all
+ * potential errors. We need to do this without the context
+ * switch lock held, otherwise the irq handler is unable to
+ * process them.
*/
if (pgraph->channel(dev) == chan)
nouveau_wait_for_idle(dev);
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-
- pgraph->fifo_access(dev, false);
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
- pgraph->destroy_context(chan);
- pgraph->fifo_access(dev, true);
-
- if (pfifo->channel_id(dev) == chan->id) {
- pfifo->disable(dev);
- pfifo->unload_context(dev);
- pfifo->enable(dev);
- }
+ /* destroy the engine specific contexts */
pfifo->destroy_context(chan);
+ pgraph->destroy_context(chan);
+ if (pcrypt->destroy_context)
+ pcrypt->destroy_context(chan);
pfifo->reassign(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ /* aside from its resources, the channel should now be dead,
+ * remove it from the channel list
+ */
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ nouveau_channel_ref(NULL, &dev_priv->channels.ptr[chan->id]);
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
- /* Release the channel's resources */
+ /* destroy any resources the channel owned */
nouveau_gpuobj_ref(NULL, &chan->pushbuf);
if (chan->pushbuf_bo) {
nouveau_bo_unmap(chan->pushbuf_bo);
@@ -310,44 +327,80 @@ nouveau_channel_free(struct nouveau_channel *chan)
}
nouveau_gpuobj_channel_takedown(chan);
nouveau_notifier_takedown_channel(chan);
- if (chan->user)
- iounmap(chan->user);
- dev_priv->fifos[chan->id] = NULL;
+ nouveau_channel_ref(NULL, pchan);
+}
+
+void
+nouveau_channel_put(struct nouveau_channel **pchan)
+{
+ mutex_unlock(&(*pchan)->mutex);
+ nouveau_channel_put_unlocked(pchan);
+}
+
+static void
+nouveau_channel_del(struct kref *ref)
+{
+ struct nouveau_channel *chan =
+ container_of(ref, struct nouveau_channel, ref);
+
kfree(chan);
}
+void
+nouveau_channel_ref(struct nouveau_channel *chan,
+ struct nouveau_channel **pchan)
+{
+ if (chan)
+ kref_get(&chan->ref);
+
+ if (*pchan)
+ kref_put(&(*pchan)->ref, nouveau_channel_del);
+
+ *pchan = chan;
+}
+
+void
+nouveau_channel_idle(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_fence *fence = NULL;
+ int ret;
+
+ nouveau_fence_update(chan);
+
+ if (chan->fence.sequence != chan->fence.sequence_ack) {
+ ret = nouveau_fence_new(chan, &fence, true);
+ if (!ret) {
+ ret = nouveau_fence_wait(fence, false, false);
+ nouveau_fence_unref(&fence);
+ }
+
+ if (ret)
+ NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
+ }
+}
+
/* cleans up all the fifos from file_priv */
void
nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
+ struct nouveau_channel *chan;
int i;
NV_DEBUG(dev, "clearing FIFO enables from file_priv\n");
for (i = 0; i < engine->fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->fifos[i];
+ chan = nouveau_channel_get(dev, file_priv, i);
+ if (IS_ERR(chan))
+ continue;
- if (chan && chan->file_priv == file_priv)
- nouveau_channel_free(chan);
+ atomic_dec(&chan->users);
+ nouveau_channel_put(&chan);
}
}
-int
-nouveau_channel_owner(struct drm_device *dev, struct drm_file *file_priv,
- int channel)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
-
- if (channel >= engine->fifo.channels)
- return 0;
- if (dev_priv->fifos[channel] == NULL)
- return 0;
-
- return (dev_priv->fifos[channel]->file_priv == file_priv);
-}
/***********************************
* ioctls wrapping the functions
@@ -383,36 +436,44 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
else
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
- init->subchan[0].handle = NvM2MF;
- if (dev_priv->card_type < NV_50)
- init->subchan[0].grclass = 0x0039;
- else
- init->subchan[0].grclass = 0x5039;
- init->subchan[1].handle = NvSw;
- init->subchan[1].grclass = NV_SW;
- init->nr_subchan = 2;
+ if (dev_priv->card_type < NV_C0) {
+ init->subchan[0].handle = NvM2MF;
+ if (dev_priv->card_type < NV_50)
+ init->subchan[0].grclass = 0x0039;
+ else
+ init->subchan[0].grclass = 0x5039;
+ init->subchan[1].handle = NvSw;
+ init->subchan[1].grclass = NV_SW;
+ init->nr_subchan = 2;
+ } else {
+ init->subchan[0].handle = 0x9039;
+ init->subchan[0].grclass = 0x9039;
+ init->nr_subchan = 1;
+ }
/* Named memory object area */
ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem,
&init->notifier_handle);
- if (ret) {
- nouveau_channel_free(chan);
- return ret;
- }
- return 0;
+ if (ret == 0)
+ atomic_inc(&chan->users); /* userspace reference */
+ nouveau_channel_put(&chan);
+ return ret;
}
static int
nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct drm_nouveau_channel_free *cfree = data;
+ struct drm_nouveau_channel_free *req = data;
struct nouveau_channel *chan;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);
+ chan = nouveau_channel_get(dev, file_priv, req->channel);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
- nouveau_channel_free(chan);
+ atomic_dec(&chan->users);
+ nouveau_channel_put(&chan);
return 0;
}
@@ -421,18 +482,18 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
***********************************/
struct drm_ioctl_desc nouveau_ioctls[] = {
- DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH),
};
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 0871495096fa..a21e00076839 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -37,6 +37,8 @@
#include "nouveau_connector.h"
#include "nouveau_hw.h"
+static void nouveau_connector_hotplug(void *, int);
+
static struct nouveau_encoder *
find_encoder_by_type(struct drm_connector *connector, int type)
{
@@ -94,22 +96,30 @@ nouveau_connector_bpp(struct drm_connector *connector)
}
static void
-nouveau_connector_destroy(struct drm_connector *drm_connector)
+nouveau_connector_destroy(struct drm_connector *connector)
{
- struct nouveau_connector *nv_connector =
- nouveau_connector(drm_connector);
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct drm_nouveau_private *dev_priv;
+ struct nouveau_gpio_engine *pgpio;
struct drm_device *dev;
if (!nv_connector)
return;
dev = nv_connector->base.dev;
+ dev_priv = dev->dev_private;
NV_DEBUG_KMS(dev, "\n");
+ pgpio = &dev_priv->engine.gpio;
+ if (pgpio->irq_unregister) {
+ pgpio->irq_unregister(dev, nv_connector->dcb->gpio_tag,
+ nouveau_connector_hotplug, connector);
+ }
+
kfree(nv_connector->edid);
- drm_sysfs_connector_remove(drm_connector);
- drm_connector_cleanup(drm_connector);
- kfree(drm_connector);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
}
static struct nouveau_i2c_chan *
@@ -281,7 +291,7 @@ detect_analog:
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
if (!nv_encoder && !nouveau_tv_disable)
nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
- if (nv_encoder) {
+ if (nv_encoder && force) {
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_encoder_helper_funcs *helper =
encoder->helper_private;
@@ -641,11 +651,28 @@ nouveau_connector_get_modes(struct drm_connector *connector)
return ret;
}
+static unsigned
+get_tmds_link_bandwidth(struct drm_connector *connector)
+{
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+ struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
+
+ if (dcb->location != DCB_LOC_ON_CHIP ||
+ dev_priv->chipset >= 0x46)
+ return 165000;
+ else if (dev_priv->chipset >= 0x40)
+ return 155000;
+ else if (dev_priv->chipset >= 0x18)
+ return 135000;
+ else
+ return 112000;
+}
+
static int
nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
@@ -663,11 +690,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
max_clock = 400000;
break;
case OUTPUT_TMDS:
- if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
- !nv_encoder->dcb->duallink_possible)
- max_clock = 165000;
- else
- max_clock = 330000;
+ max_clock = get_tmds_link_bandwidth(connector);
+ if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
+ max_clock *= 2;
break;
case OUTPUT_ANALOG:
max_clock = nv_encoder->dcb->crtconf.maxfreq;
@@ -709,44 +734,6 @@ nouveau_connector_best_encoder(struct drm_connector *connector)
return NULL;
}
-void
-nouveau_connector_set_polling(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- bool spare_crtc = false;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- spare_crtc |= !crtc->enabled;
-
- connector->polled = 0;
-
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_VGA:
- case DRM_MODE_CONNECTOR_TV:
- if (dev_priv->card_type >= NV_50 ||
- (nv_gf4_disp_arch(dev) && spare_crtc))
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- break;
-
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_DVID:
- case DRM_MODE_CONNECTOR_HDMIA:
- case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_eDP:
- if (dev_priv->card_type >= NV_50)
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
- spare_crtc)
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- break;
-
- default:
- break;
- }
-}
-
static const struct drm_connector_helper_funcs
nouveau_connector_helper_funcs = {
.get_modes = nouveau_connector_get_modes,
@@ -783,6 +770,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
{
const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_connector *nv_connector = NULL;
struct dcb_connector_table_entry *dcb = NULL;
struct drm_connector *connector;
@@ -872,6 +860,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
}
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
/* fall-through */
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
@@ -888,10 +877,20 @@ nouveau_connector_create(struct drm_device *dev, int index)
dev->mode_config.dithering_mode_property,
nv_connector->use_dithering ?
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+
+ if (dcb->type != DCB_CONNECTOR_LVDS) {
+ if (dev_priv->card_type >= NV_50)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ else
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ }
break;
}
- nouveau_connector_set_polling(connector);
+ if (pgpio->irq_register) {
+ pgpio->irq_register(dev, nv_connector->dcb->gpio_tag,
+ nouveau_connector_hotplug, connector);
+ }
drm_sysfs_connector_add(connector);
dcb->drm = connector;
@@ -903,3 +902,29 @@ fail:
return ERR_PTR(ret);
}
+
+static void
+nouveau_connector_hotplug(void *data, int plugged)
+{
+ struct drm_connector *connector = data;
+ struct drm_device *dev = connector->dev;
+
+ NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",
+ drm_get_connector_name(connector));
+
+ if (connector->encoder && connector->encoder->crtc &&
+ connector->encoder->crtc->enabled) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder);
+ struct drm_encoder_helper_funcs *helper =
+ connector->encoder->helper_private;
+
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ if (plugged)
+ helper->dpms(connector->encoder, DRM_MODE_DPMS_ON);
+ else
+ helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
+ }
+ }
+
+ drm_helper_hpd_irq_event(dev);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index c21ed6b16f88..711b1e9203af 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector(
struct drm_connector *
nouveau_connector_create(struct drm_device *, int index);
-void
-nouveau_connector_set_polling(struct drm_connector *);
-
int
nouveau_connector_bpp(struct drm_connector *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 2e11fd65b4dd..505c6bfb4d75 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -29,6 +29,9 @@
#include "nouveau_drv.h"
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
+#include "nouveau_hw.h"
+#include "nouveau_crtc.h"
+#include "nouveau_dma.h"
static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
@@ -104,3 +107,207 @@ const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.output_poll_changed = nouveau_fbcon_output_poll_changed,
};
+int
+nouveau_vblank_enable(struct drm_device *dev, int crtc)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->card_type >= NV_50)
+ nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
+ NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
+ else
+ NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
+ NV_PCRTC_INTR_0_VBLANK);
+
+ return 0;
+}
+
+void
+nouveau_vblank_disable(struct drm_device *dev, int crtc)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->card_type >= NV_50)
+ nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
+ NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
+ else
+ NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
+}
+
+static int
+nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
+ struct nouveau_bo *new_bo)
+{
+ int ret;
+
+ ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ return ret;
+
+ ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+ if (ret)
+ goto fail;
+
+ ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
+ if (ret)
+ goto fail_unreserve;
+
+ return 0;
+
+fail_unreserve:
+ ttm_bo_unreserve(&new_bo->bo);
+fail:
+ nouveau_bo_unpin(new_bo);
+ return ret;
+}
+
+static void
+nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
+ struct nouveau_bo *new_bo,
+ struct nouveau_fence *fence)
+{
+ nouveau_bo_fence(new_bo, fence);
+ ttm_bo_unreserve(&new_bo->bo);
+
+ nouveau_bo_fence(old_bo, fence);
+ ttm_bo_unreserve(&old_bo->bo);
+
+ nouveau_bo_unpin(old_bo);
+}
+
+static int
+nouveau_page_flip_emit(struct nouveau_channel *chan,
+ struct nouveau_bo *old_bo,
+ struct nouveau_bo *new_bo,
+ struct nouveau_page_flip_state *s,
+ struct nouveau_fence **pfence)
+{
+ struct drm_device *dev = chan->dev;
+ unsigned long flags;
+ int ret;
+
+ /* Queue it to the pending list */
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_add_tail(&s->head, &chan->nvsw.flip);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ /* Synchronize with the old framebuffer */
+ ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
+ if (ret)
+ goto fail;
+
+ /* Emit the pageflip */
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ goto fail;
+
+ BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
+ OUT_RING(chan, 0);
+ FIRE_RING(chan);
+
+ ret = nouveau_fence_new(chan, pfence, true);
+ if (ret)
+ goto fail;
+
+ return 0;
+fail:
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_del(&s->head);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return ret;
+}
+
+int
+nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
+ struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
+ struct nouveau_page_flip_state *s;
+ struct nouveau_channel *chan;
+ struct nouveau_fence *fence;
+ int ret;
+
+ if (dev_priv->engine.graph.accel_blocked)
+ return -ENODEV;
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ /* Don't let the buffers go away while we flip */
+ ret = nouveau_page_flip_reserve(old_bo, new_bo);
+ if (ret)
+ goto fail_free;
+
+ /* Initialize a page flip struct */
+ *s = (struct nouveau_page_flip_state)
+ { { }, s->event, nouveau_crtc(crtc)->index,
+ fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
+ new_bo->bo.offset };
+
+ /* Choose the channel the flip will be handled in */
+ chan = nouveau_fence_channel(new_bo->bo.sync_obj);
+ if (!chan)
+ chan = nouveau_channel_get_unlocked(dev_priv->channel);
+ mutex_lock(&chan->mutex);
+
+ /* Emit a page flip */
+ ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
+ nouveau_channel_put(&chan);
+ if (ret)
+ goto fail_unreserve;
+
+ /* Update the crtc struct and cleanup */
+ crtc->fb = fb;
+
+ nouveau_page_flip_unreserve(old_bo, new_bo, fence);
+ nouveau_fence_unref(&fence);
+ return 0;
+
+fail_unreserve:
+ nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
+fail_free:
+ kfree(s);
+ return ret;
+}
+
+int
+nouveau_finish_page_flip(struct nouveau_channel *chan,
+ struct nouveau_page_flip_state *ps)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_page_flip_state *s;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ if (list_empty(&chan->nvsw.flip)) {
+ NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return -EINVAL;
+ }
+
+ s = list_first_entry(&chan->nvsw.flip,
+ struct nouveau_page_flip_state, head);
+ if (s->event) {
+ struct drm_pending_vblank_event *e = s->event;
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ e->event.sequence = 0;
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ }
+
+ list_del(&s->head);
+ *ps = *s;
+ kfree(s);
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 82581e600dcd..65699bfaaaea 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -36,7 +36,7 @@ nouveau_dma_pre_init(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_bo *pushbuf = chan->pushbuf_bo;
- if (dev_priv->card_type == NV_50) {
+ if (dev_priv->card_type >= NV_50) {
const int ib_size = pushbuf->bo.mem.size / 2;
chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2;
@@ -59,17 +59,26 @@ nouveau_dma_init(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *obj = NULL;
int ret, i;
- /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
- ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
- 0x0039 : 0x5039, &obj);
- if (ret)
- return ret;
+ if (dev_priv->card_type >= NV_C0) {
+ ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039);
+ if (ret)
+ return ret;
+
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1);
+ OUT_RING (chan, 0x00009039);
+ FIRE_RING (chan);
+ return 0;
+ }
- ret = nouveau_ramht_insert(chan, NvM2MF, obj);
- nouveau_gpuobj_ref(NULL, &obj);
+ /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
+ ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ?
+ 0x0039 : 0x5039);
if (ret)
return ret;
@@ -78,11 +87,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
if (ret)
return ret;
- /* Map push buffer */
- ret = nouveau_bo_map(chan->pushbuf_bo);
- if (ret)
- return ret;
-
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index d578c21d3c8d..c36f1763feaa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -77,7 +77,8 @@ enum {
/* G80+ display objects */
NvEvoVRAM = 0x01000000,
NvEvoFB16 = 0x01000001,
- NvEvoFB32 = 0x01000002
+ NvEvoFB32 = 0x01000002,
+ NvEvoVRAM_LP = 0x01000003
};
#define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039
@@ -125,6 +126,12 @@ extern void
OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords);
static inline void
+BEGIN_NVC0(struct nouveau_channel *chan, int op, int subc, int mthd, int size)
+{
+ OUT_RING(chan, (op << 28) | (size << 16) | (subc << 13) | (mthd >> 2));
+}
+
+static inline void
BEGIN_RING(struct nouveau_channel *chan, int subc, int mthd, int size)
{
OUT_RING(chan, (subc << 13) | (size << 18) | mthd);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 4562f309ae3d..38d599554bce 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -279,7 +279,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder)
struct bit_displayport_encoder_table *dpe;
int dpe_headerlen;
uint8_t config[4], status[3];
- bool cr_done, cr_max_vs, eq_done;
+ bool cr_done, cr_max_vs, eq_done, hpd_state;
int ret = 0, i, tries, voltage;
NV_DEBUG_KMS(dev, "link training!!\n");
@@ -297,7 +297,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder)
/* disable hotplug detect, this flips around on some panels during
* link training.
*/
- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
+ hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
if (dpe->script0) {
NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
@@ -439,7 +439,7 @@ stop:
}
/* re-enable hotplug detect */
- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state);
return eq_done;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 90875494a65a..13bb672a16f4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -115,6 +115,10 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
int nouveau_perflvl_wr;
module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
+MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n");
+int nouveau_msi;
+module_param_named(msi, nouveau_msi, int, 0400);
+
int nouveau_fbpercrtc;
#if 0
module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
@@ -167,6 +171,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
NV_INFO(dev, "Disabling fbcon acceleration...\n");
nouveau_fbcon_save_disable_accel(dev);
@@ -193,23 +200,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
NV_INFO(dev, "Idling channels...\n");
for (i = 0; i < pfifo->channels; i++) {
- struct nouveau_fence *fence = NULL;
-
- chan = dev_priv->fifos[i];
- if (!chan || (dev_priv->card_type >= NV_50 &&
- chan == dev_priv->fifos[0]))
- continue;
-
- ret = nouveau_fence_new(chan, &fence, true);
- if (ret == 0) {
- ret = nouveau_fence_wait(fence, NULL, false, false);
- nouveau_fence_unref((void *)&fence);
- }
+ chan = dev_priv->channels.ptr[i];
- if (ret) {
- NV_ERROR(dev, "Failed to idle channel %d for suspend\n",
- chan->id);
- }
+ if (chan && chan->pushbuf_bo)
+ nouveau_channel_idle(chan);
}
pgraph->fifo_access(dev, false);
@@ -219,17 +213,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
pfifo->unload_context(dev);
pgraph->unload_context(dev);
- NV_INFO(dev, "Suspending GPU objects...\n");
- ret = nouveau_gpuobj_suspend(dev);
+ ret = pinstmem->suspend(dev);
if (ret) {
NV_ERROR(dev, "... failed: %d\n", ret);
goto out_abort;
}
- ret = pinstmem->suspend(dev);
+ NV_INFO(dev, "Suspending GPU objects...\n");
+ ret = nouveau_gpuobj_suspend(dev);
if (ret) {
NV_ERROR(dev, "... failed: %d\n", ret);
- nouveau_gpuobj_suspend_cleanup(dev);
+ pinstmem->resume(dev);
goto out_abort;
}
@@ -263,6 +257,9 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct drm_crtc *crtc;
int ret, i;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
nouveau_fbcon_save_disable_accel(dev);
NV_INFO(dev, "We're back, enabling device...\n");
@@ -294,17 +291,18 @@ nouveau_pci_resume(struct pci_dev *pdev)
}
}
+ NV_INFO(dev, "Restoring GPU objects...\n");
+ nouveau_gpuobj_resume(dev);
+
NV_INFO(dev, "Reinitialising engines...\n");
engine->instmem.resume(dev);
engine->mc.init(dev);
engine->timer.init(dev);
engine->fb.init(dev);
engine->graph.init(dev);
+ engine->crypt.init(dev);
engine->fifo.init(dev);
- NV_INFO(dev, "Restoring GPU objects...\n");
- nouveau_gpuobj_resume(dev);
-
nouveau_irq_postinstall(dev);
/* Re-write SKIPS, they'll have been lost over the suspend */
@@ -313,7 +311,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
int j;
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- chan = dev_priv->fifos[i];
+ chan = dev_priv->channels.ptr[i];
if (!chan || !chan->pushbuf_bo)
continue;
@@ -347,13 +345,11 @@ nouveau_pci_resume(struct pci_dev *pdev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ u32 offset = nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT;
- nv_crtc->cursor.set_offset(nv_crtc,
- nv_crtc->cursor.nvbo->bo.offset -
- dev_priv->vm_vram_base);
-
+ nv_crtc->cursor.set_offset(nv_crtc, offset);
nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
- nv_crtc->cursor_saved_y);
+ nv_crtc->cursor_saved_y);
}
/* Force CLUT to get re-loaded during modeset */
@@ -393,6 +389,9 @@ static struct drm_driver driver = {
.irq_postinstall = nouveau_irq_postinstall,
.irq_uninstall = nouveau_irq_uninstall,
.irq_handler = nouveau_irq_handler,
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = nouveau_vblank_enable,
+ .disable_vblank = nouveau_vblank_disable,
.reclaim_buffers = drm_core_reclaim_buffers,
.ioctls = nouveau_ioctls,
.fops = {
@@ -403,6 +402,7 @@ static struct drm_driver driver = {
.mmap = nouveau_ttm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+ .read = drm_read,
#if defined(CONFIG_COMPAT)
.compat_ioctl = nouveau_compat_ioctl,
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 3a07e580d27a..01bffc4412d2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -54,22 +54,37 @@ struct nouveau_fpriv {
#include "nouveau_drm.h"
#include "nouveau_reg.h"
#include "nouveau_bios.h"
+#include "nouveau_util.h"
+
struct nouveau_grctx;
+struct nouveau_vram;
+#include "nouveau_vm.h"
#define MAX_NUM_DCB_ENTRIES 16
#define NOUVEAU_MAX_CHANNEL_NR 128
#define NOUVEAU_MAX_TILE_NR 15
-#define NV50_VM_MAX_VRAM (2*1024*1024*1024ULL)
-#define NV50_VM_BLOCK (512*1024*1024ULL)
-#define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK)
+struct nouveau_vram {
+ struct drm_device *dev;
+
+ struct nouveau_vma bar_vma;
+ u8 page_shift;
+
+ struct list_head regions;
+ u32 memtype;
+ u64 offset;
+ u64 size;
+};
struct nouveau_tile_reg {
- struct nouveau_fence *fence;
- uint32_t addr;
- uint32_t size;
bool used;
+ uint32_t addr;
+ uint32_t limit;
+ uint32_t pitch;
+ uint32_t zcomp;
+ struct drm_mm_node *tag_mem;
+ struct nouveau_fence *fence;
};
struct nouveau_bo {
@@ -88,6 +103,7 @@ struct nouveau_bo {
struct nouveau_channel *channel;
+ struct nouveau_vma vma;
bool mappable;
bool no_vm;
@@ -96,10 +112,12 @@ struct nouveau_bo {
struct nouveau_tile_reg *tile;
struct drm_gem_object *gem;
- struct drm_file *cpu_filp;
int pin_refcnt;
};
+#define nouveau_bo_tile_layout(nvbo) \
+ ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
+
static inline struct nouveau_bo *
nouveau_bo(struct ttm_buffer_object *bo)
{
@@ -130,20 +148,29 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_SW 0
#define NVOBJ_ENGINE_GR 1
-#define NVOBJ_ENGINE_DISPLAY 2
+#define NVOBJ_ENGINE_PPP 2
+#define NVOBJ_ENGINE_COPY 3
+#define NVOBJ_ENGINE_VP 4
+#define NVOBJ_ENGINE_CRYPT 5
+#define NVOBJ_ENGINE_BSP 6
+#define NVOBJ_ENGINE_DISPLAY 0xcafe0001
#define NVOBJ_ENGINE_INT 0xdeadbeef
+#define NVOBJ_FLAG_DONT_MAP (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
#define NVOBJ_FLAG_ZERO_FREE (1 << 2)
+#define NVOBJ_FLAG_VM (1 << 3)
+#define NVOBJ_FLAG_VM_USER (1 << 4)
+
+#define NVOBJ_CINST_GLOBAL 0xdeadbeef
+
struct nouveau_gpuobj {
struct drm_device *dev;
struct kref refcount;
struct list_head list;
- struct drm_mm_node *im_pramin;
- struct nouveau_bo *im_backing;
- uint32_t *im_backing_suspend;
- int im_bound;
+ void *node;
+ u32 *suspend;
uint32_t flags;
@@ -159,10 +186,29 @@ struct nouveau_gpuobj {
void *priv;
};
+struct nouveau_page_flip_state {
+ struct list_head head;
+ struct drm_pending_vblank_event *event;
+ int crtc, bpp, pitch, x, y;
+ uint64_t offset;
+};
+
+enum nouveau_channel_mutex_class {
+ NOUVEAU_UCHANNEL_MUTEX,
+ NOUVEAU_KCHANNEL_MUTEX
+};
+
struct nouveau_channel {
struct drm_device *dev;
int id;
+ /* references to the channel data structure */
+ struct kref ref;
+ /* users of the hardware channel resources, the hardware
+ * context will be kicked off when it reaches zero. */
+ atomic_t users;
+ struct mutex mutex;
+
/* owner of this fifo */
struct drm_file *file_priv;
/* mapping of the fifo itself */
@@ -195,16 +241,17 @@ struct nouveau_channel {
/* PFIFO context */
struct nouveau_gpuobj *ramfc;
struct nouveau_gpuobj *cache;
+ void *fifo_priv;
/* PGRAPH context */
/* XXX may be merge 2 pointers as private data ??? */
struct nouveau_gpuobj *ramin_grctx;
+ struct nouveau_gpuobj *crypt_ctx;
void *pgraph_ctx;
/* NV50 VM */
+ struct nouveau_vm *vm;
struct nouveau_gpuobj *vm_pd;
- struct nouveau_gpuobj *vm_gart_pt;
- struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
/* Objects */
struct nouveau_gpuobj *ramin; /* Private instmem */
@@ -235,9 +282,11 @@ struct nouveau_channel {
struct {
struct nouveau_gpuobj *vblsem;
+ uint32_t vblsem_head;
uint32_t vblsem_offset;
uint32_t vblsem_rval;
struct list_head vbl_wait;
+ struct list_head flip;
} nvsw;
struct {
@@ -255,11 +304,11 @@ struct nouveau_instmem_engine {
int (*suspend)(struct drm_device *dev);
void (*resume)(struct drm_device *dev);
- int (*populate)(struct drm_device *, struct nouveau_gpuobj *,
- uint32_t *size);
- void (*clear)(struct drm_device *, struct nouveau_gpuobj *);
- int (*bind)(struct drm_device *, struct nouveau_gpuobj *);
- int (*unbind)(struct drm_device *, struct nouveau_gpuobj *);
+ int (*get)(struct nouveau_gpuobj *, u32 size, u32 align);
+ void (*put)(struct nouveau_gpuobj *);
+ int (*map)(struct nouveau_gpuobj *);
+ void (*unmap)(struct nouveau_gpuobj *);
+
void (*flush)(struct drm_device *);
};
@@ -276,15 +325,21 @@ struct nouveau_timer_engine {
struct nouveau_fb_engine {
int num_tiles;
+ struct drm_mm tag_heap;
+ void *priv;
int (*init)(struct drm_device *dev);
void (*takedown)(struct drm_device *dev);
- void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch);
+ void (*init_tile_region)(struct drm_device *dev, int i,
+ uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags);
+ void (*set_tile_region)(struct drm_device *dev, int i);
+ void (*free_tile_region)(struct drm_device *dev, int i);
};
struct nouveau_fifo_engine {
+ void *priv;
int channels;
struct nouveau_gpuobj *playlist[2];
@@ -304,24 +359,14 @@ struct nouveau_fifo_engine {
void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *);
-};
-
-struct nouveau_pgraph_object_method {
- int id;
- int (*exec)(struct nouveau_channel *chan, int grclass, int mthd,
- uint32_t data);
-};
-
-struct nouveau_pgraph_object_class {
- int id;
- bool software;
- struct nouveau_pgraph_object_method *methods;
+ void (*tlb_flush)(struct drm_device *dev);
};
struct nouveau_pgraph_engine {
- struct nouveau_pgraph_object_class *grclass;
bool accel_blocked;
+ bool registered;
int grctx_size;
+ void *priv;
/* NV2x/NV3x context table (0x400780) */
struct nouveau_gpuobj *ctx_table;
@@ -336,9 +381,9 @@ struct nouveau_pgraph_engine {
void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *);
+ void (*tlb_flush)(struct drm_device *dev);
- void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch);
+ void (*set_tile_region)(struct drm_device *dev, int i);
};
struct nouveau_display_engine {
@@ -350,13 +395,19 @@ struct nouveau_display_engine {
};
struct nouveau_gpio_engine {
+ void *priv;
+
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
int (*get)(struct drm_device *, enum dcb_gpio_tag);
int (*set)(struct drm_device *, enum dcb_gpio_tag, int state);
- void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
+ int (*irq_register)(struct drm_device *, enum dcb_gpio_tag,
+ void (*)(void *, int), void *);
+ void (*irq_unregister)(struct drm_device *, enum dcb_gpio_tag,
+ void (*)(void *, int), void *);
+ bool (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
};
struct nouveau_pm_voltage_level {
@@ -432,6 +483,7 @@ struct nouveau_pm_engine {
struct nouveau_pm_level *cur;
struct device *hwmon;
+ struct notifier_block acpi_nb;
int (*clock_get)(struct drm_device *, u32 id);
void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *,
@@ -444,6 +496,25 @@ struct nouveau_pm_engine {
int (*temp_get)(struct drm_device *);
};
+struct nouveau_crypt_engine {
+ bool registered;
+
+ int (*init)(struct drm_device *);
+ void (*takedown)(struct drm_device *);
+ int (*create_context)(struct nouveau_channel *);
+ void (*destroy_context)(struct nouveau_channel *);
+ void (*tlb_flush)(struct drm_device *dev);
+};
+
+struct nouveau_vram_engine {
+ int (*init)(struct drm_device *);
+ int (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
+ u32 type, struct nouveau_vram **);
+ void (*put)(struct drm_device *, struct nouveau_vram **);
+
+ bool (*flags_valid)(struct drm_device *, u32 tile_flags);
+};
+
struct nouveau_engine {
struct nouveau_instmem_engine instmem;
struct nouveau_mc_engine mc;
@@ -454,6 +525,8 @@ struct nouveau_engine {
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
struct nouveau_pm_engine pm;
+ struct nouveau_crypt_engine crypt;
+ struct nouveau_vram_engine vram;
};
struct nouveau_pll_vals {
@@ -485,13 +558,13 @@ enum nv04_fp_display_regs {
};
struct nv04_crtc_reg {
- unsigned char MiscOutReg; /* */
+ unsigned char MiscOutReg;
uint8_t CRTC[0xa0];
uint8_t CR58[0x10];
uint8_t Sequencer[5];
uint8_t Graphics[9];
uint8_t Attribute[21];
- unsigned char DAC[768]; /* Internal Colorlookuptable */
+ unsigned char DAC[768];
/* PCRTC regs */
uint32_t fb_start;
@@ -539,43 +612,9 @@ struct nv04_output_reg {
};
struct nv04_mode_state {
- uint32_t bpp;
- uint32_t width;
- uint32_t height;
- uint32_t interlace;
- uint32_t repaint0;
- uint32_t repaint1;
- uint32_t screen;
- uint32_t scale;
- uint32_t dither;
- uint32_t extra;
- uint32_t fifo;
- uint32_t pixel;
- uint32_t horiz;
- int arbitration0;
- int arbitration1;
- uint32_t pll;
- uint32_t pllB;
- uint32_t vpll;
- uint32_t vpll2;
- uint32_t vpllB;
- uint32_t vpll2B;
+ struct nv04_crtc_reg crtc_reg[2];
uint32_t pllsel;
uint32_t sel_clk;
- uint32_t general;
- uint32_t crtcOwner;
- uint32_t head;
- uint32_t head2;
- uint32_t cursorConfig;
- uint32_t cursor0;
- uint32_t cursor1;
- uint32_t cursor2;
- uint32_t timingH;
- uint32_t timingV;
- uint32_t displayV;
- uint32_t crtcSync;
-
- struct nv04_crtc_reg crtc_reg[2];
};
enum nouveau_card_type {
@@ -606,12 +645,15 @@ struct drm_nouveau_private {
bool ramin_available;
struct drm_mm ramin_heap;
struct list_head gpuobj_list;
+ struct list_head classes;
struct nouveau_bo *vga_ram;
+ /* interrupt handling */
+ void (*irq_handler[32])(struct drm_device *);
+ bool msi_enabled;
struct workqueue_struct *wq;
struct work_struct irq_work;
- struct work_struct hpd_work;
struct list_head vbl_waiting;
@@ -628,8 +670,10 @@ struct drm_nouveau_private {
struct nouveau_bo *bo;
} fence;
- int fifo_alloc_count;
- struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
+ struct {
+ spinlock_t lock;
+ struct nouveau_channel *ptr[NOUVEAU_MAX_CHANNEL_NR];
+ } channels;
struct nouveau_engine engine;
struct nouveau_channel *channel;
@@ -655,12 +699,14 @@ struct drm_nouveau_private {
uint64_t aper_free;
struct nouveau_gpuobj *sg_ctxdma;
- struct page *sg_dummy_page;
- dma_addr_t sg_dummy_bus;
+ struct nouveau_vma vma;
} gart_info;
/* nv10-nv40 tiling regions */
- struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR];
+ struct {
+ struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
+ spinlock_t lock;
+ } tile;
/* VRAM/fb configuration */
uint64_t vram_size;
@@ -673,14 +719,12 @@ struct drm_nouveau_private {
uint64_t fb_aper_free;
int fb_mtrr;
+ /* BAR control (NV50-) */
+ struct nouveau_vm *bar1_vm;
+ struct nouveau_vm *bar3_vm;
+
/* G8x/G9x virtual address space */
- uint64_t vm_gart_base;
- uint64_t vm_gart_size;
- uint64_t vm_vram_base;
- uint64_t vm_vram_size;
- uint64_t vm_end;
- struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
- int vm_vram_pt_nr;
+ struct nouveau_vm *chan_vm;
struct nvbios vbios;
@@ -697,6 +741,7 @@ struct drm_nouveau_private {
struct backlight_device *backlight;
struct nouveau_channel *evo;
+ u32 evo_alloc;
struct {
struct dcb_entry *dcb;
u16 script;
@@ -709,6 +754,8 @@ struct drm_nouveau_private {
struct nouveau_fbdev *nfbdev;
struct apertures_struct *apertures;
+
+ bool powered_down;
};
static inline struct drm_nouveau_private *
@@ -742,16 +789,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
return 0;
}
-#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \
- struct drm_nouveau_private *nv = dev->dev_private; \
- if (!nouveau_channel_owner(dev, (cl), (id))) { \
- NV_ERROR(dev, "pid %d doesn't own channel %d\n", \
- DRM_CURRENTPID, (id)); \
- return -EPERM; \
- } \
- (ch) = nv->fifos[(id)]; \
-} while (0)
-
/* nouveau_drv.c */
extern int nouveau_agpmode;
extern int nouveau_duallink;
@@ -771,6 +808,7 @@ extern int nouveau_force_post;
extern int nouveau_override_conntype;
extern char *nouveau_perflvl;
extern int nouveau_perflvl_wr;
+extern int nouveau_msi;
extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
extern int nouveau_pci_resume(struct pci_dev *pdev);
@@ -785,8 +823,10 @@ extern int nouveau_ioctl_getparam(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_setparam(struct drm_device *, void *data,
struct drm_file *);
-extern bool nouveau_wait_until(struct drm_device *, uint64_t timeout,
- uint32_t reg, uint32_t mask, uint32_t val);
+extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout,
+ uint32_t reg, uint32_t mask, uint32_t val);
+extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout,
+ uint32_t reg, uint32_t mask, uint32_t val);
extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
@@ -798,18 +838,18 @@ extern void nouveau_mem_gart_fini(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *);
extern int nouveau_mem_reset_agp(struct drm_device *);
extern void nouveau_mem_close(struct drm_device *);
-extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
- uint32_t addr,
- uint32_t size,
- uint32_t pitch);
-extern void nv10_mem_expire_tiling(struct drm_device *dev,
- struct nouveau_tile_reg *tile,
- struct nouveau_fence *fence);
-extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt,
- uint32_t size, uint32_t flags,
- uint64_t phys);
-extern void nv50_mem_vm_unbind(struct drm_device *, uint64_t virt,
- uint32_t size);
+extern int nouveau_mem_detect(struct drm_device *);
+extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags);
+extern struct nouveau_tile_reg *nv10_mem_set_tiling(
+ struct drm_device *dev, uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags);
+extern void nv10_mem_put_tile_region(struct drm_device *dev,
+ struct nouveau_tile_reg *tile,
+ struct nouveau_fence *fence);
+extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
+
+/* nvc0_vram.c */
+extern const struct ttm_mem_type_manager_func nvc0_vram_manager;
/* nouveau_notifier.c */
extern int nouveau_notifier_init_channel(struct nouveau_channel *);
@@ -826,21 +866,44 @@ extern int nouveau_ioctl_notifier_free(struct drm_device *, void *data,
extern struct drm_ioctl_desc nouveau_ioctls[];
extern int nouveau_max_ioctl;
extern void nouveau_channel_cleanup(struct drm_device *, struct drm_file *);
-extern int nouveau_channel_owner(struct drm_device *, struct drm_file *,
- int channel);
extern int nouveau_channel_alloc(struct drm_device *dev,
struct nouveau_channel **chan,
struct drm_file *file_priv,
uint32_t fb_ctxdma, uint32_t tt_ctxdma);
-extern void nouveau_channel_free(struct nouveau_channel *);
+extern struct nouveau_channel *
+nouveau_channel_get_unlocked(struct nouveau_channel *);
+extern struct nouveau_channel *
+nouveau_channel_get(struct drm_device *, struct drm_file *, int id);
+extern void nouveau_channel_put_unlocked(struct nouveau_channel **);
+extern void nouveau_channel_put(struct nouveau_channel **);
+extern void nouveau_channel_ref(struct nouveau_channel *chan,
+ struct nouveau_channel **pchan);
+extern void nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
+#define NVOBJ_CLASS(d,c,e) do { \
+ int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \
+ if (ret) \
+ return ret; \
+} while(0)
+
+#define NVOBJ_MTHD(d,c,m,e) do { \
+ int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \
+ if (ret) \
+ return ret; \
+} while(0)
+
extern int nouveau_gpuobj_early_init(struct drm_device *);
extern int nouveau_gpuobj_init(struct drm_device *);
extern void nouveau_gpuobj_takedown(struct drm_device *);
extern int nouveau_gpuobj_suspend(struct drm_device *dev);
-extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev);
extern void nouveau_gpuobj_resume(struct drm_device *dev);
+extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
+extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
+ int (*exec)(struct nouveau_channel *,
+ u32 class, u32 mthd, u32 data));
+extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
+extern int nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
uint32_t vram_h, uint32_t tt_h);
extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
@@ -855,21 +918,25 @@ extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
uint64_t offset, uint64_t size, int access,
int target, struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *,
- uint64_t offset, uint64_t size,
- int access, struct nouveau_gpuobj **,
- uint32_t *o_ret);
-extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class,
- struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_sw_new(struct nouveau_channel *, int class,
- struct nouveau_gpuobj **);
+extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, u32 handle, int class);
+extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base,
+ u64 size, int target, int access, u32 type,
+ u32 comp, struct nouveau_gpuobj **pobj);
+extern void nv50_gpuobj_dma_init(struct nouveau_gpuobj *, u32 offset,
+ int class, u64 base, u64 size, int target,
+ int access, u32 type, u32 comp);
extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data,
struct drm_file *);
/* nouveau_irq.c */
+extern int nouveau_irq_init(struct drm_device *);
+extern void nouveau_irq_fini(struct drm_device *);
extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
+extern void nouveau_irq_register(struct drm_device *, int status_bit,
+ void (*)(struct drm_device *));
+extern void nouveau_irq_unregister(struct drm_device *, int status_bit);
extern void nouveau_irq_preinstall(struct drm_device *);
extern int nouveau_irq_postinstall(struct drm_device *);
extern void nouveau_irq_uninstall(struct drm_device *);
@@ -877,8 +944,8 @@ extern void nouveau_irq_uninstall(struct drm_device *);
/* nouveau_sgdma.c */
extern int nouveau_sgdma_init(struct drm_device *);
extern void nouveau_sgdma_takedown(struct drm_device *);
-extern int nouveau_sgdma_get_page(struct drm_device *, uint32_t offset,
- uint32_t *page);
+extern uint32_t nouveau_sgdma_get_physical(struct drm_device *,
+ uint32_t offset);
extern struct ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *);
/* nouveau_debugfs.c */
@@ -989,18 +1056,25 @@ extern void nv04_fb_takedown(struct drm_device *);
/* nv10_fb.c */
extern int nv10_fb_init(struct drm_device *);
extern void nv10_fb_takedown(struct drm_device *);
-extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
- uint32_t, uint32_t);
+extern void nv10_fb_init_tile_region(struct drm_device *dev, int i,
+ uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags);
+extern void nv10_fb_set_tile_region(struct drm_device *dev, int i);
+extern void nv10_fb_free_tile_region(struct drm_device *dev, int i);
/* nv30_fb.c */
extern int nv30_fb_init(struct drm_device *);
extern void nv30_fb_takedown(struct drm_device *);
+extern void nv30_fb_init_tile_region(struct drm_device *dev, int i,
+ uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags);
+extern void nv30_fb_free_tile_region(struct drm_device *dev, int i);
/* nv40_fb.c */
extern int nv40_fb_init(struct drm_device *);
extern void nv40_fb_takedown(struct drm_device *);
-extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
- uint32_t, uint32_t);
+extern void nv40_fb_set_tile_region(struct drm_device *dev, int i);
+
/* nv50_fb.c */
extern int nv50_fb_init(struct drm_device *);
extern void nv50_fb_takedown(struct drm_device *);
@@ -1012,6 +1086,7 @@ extern void nvc0_fb_takedown(struct drm_device *);
/* nv04_fifo.c */
extern int nv04_fifo_init(struct drm_device *);
+extern void nv04_fifo_fini(struct drm_device *);
extern void nv04_fifo_disable(struct drm_device *);
extern void nv04_fifo_enable(struct drm_device *);
extern bool nv04_fifo_reassign(struct drm_device *, bool);
@@ -1021,19 +1096,18 @@ extern int nv04_fifo_create_context(struct nouveau_channel *);
extern void nv04_fifo_destroy_context(struct nouveau_channel *);
extern int nv04_fifo_load_context(struct nouveau_channel *);
extern int nv04_fifo_unload_context(struct drm_device *);
+extern void nv04_fifo_isr(struct drm_device *);
/* nv10_fifo.c */
extern int nv10_fifo_init(struct drm_device *);
extern int nv10_fifo_channel_id(struct drm_device *);
extern int nv10_fifo_create_context(struct nouveau_channel *);
-extern void nv10_fifo_destroy_context(struct nouveau_channel *);
extern int nv10_fifo_load_context(struct nouveau_channel *);
extern int nv10_fifo_unload_context(struct drm_device *);
/* nv40_fifo.c */
extern int nv40_fifo_init(struct drm_device *);
extern int nv40_fifo_create_context(struct nouveau_channel *);
-extern void nv40_fifo_destroy_context(struct nouveau_channel *);
extern int nv40_fifo_load_context(struct nouveau_channel *);
extern int nv40_fifo_unload_context(struct drm_device *);
@@ -1045,6 +1119,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *);
extern void nv50_fifo_destroy_context(struct nouveau_channel *);
extern int nv50_fifo_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *);
+extern void nv50_fifo_tlb_flush(struct drm_device *dev);
/* nvc0_fifo.c */
extern int nvc0_fifo_init(struct drm_device *);
@@ -1060,7 +1135,6 @@ extern int nvc0_fifo_load_context(struct nouveau_channel *);
extern int nvc0_fifo_unload_context(struct drm_device *);
/* nv04_graph.c */
-extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
extern int nv04_graph_init(struct drm_device *);
extern void nv04_graph_takedown(struct drm_device *);
extern void nv04_graph_fifo_access(struct drm_device *, bool);
@@ -1069,10 +1143,11 @@ extern int nv04_graph_create_context(struct nouveau_channel *);
extern void nv04_graph_destroy_context(struct nouveau_channel *);
extern int nv04_graph_load_context(struct nouveau_channel *);
extern int nv04_graph_unload_context(struct drm_device *);
-extern void nv04_graph_context_switch(struct drm_device *);
+extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data);
+extern struct nouveau_bitfield nv04_graph_nsource[];
/* nv10_graph.c */
-extern struct nouveau_pgraph_object_class nv10_graph_grclass[];
extern int nv10_graph_init(struct drm_device *);
extern void nv10_graph_takedown(struct drm_device *);
extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
@@ -1080,13 +1155,11 @@ extern int nv10_graph_create_context(struct nouveau_channel *);
extern void nv10_graph_destroy_context(struct nouveau_channel *);
extern int nv10_graph_load_context(struct nouveau_channel *);
extern int nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_context_switch(struct drm_device *);
-extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t,
- uint32_t, uint32_t);
+extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
+extern struct nouveau_bitfield nv10_graph_intr[];
+extern struct nouveau_bitfield nv10_graph_nstatus[];
/* nv20_graph.c */
-extern struct nouveau_pgraph_object_class nv20_graph_grclass[];
-extern struct nouveau_pgraph_object_class nv30_graph_grclass[];
extern int nv20_graph_create_context(struct nouveau_channel *);
extern void nv20_graph_destroy_context(struct nouveau_channel *);
extern int nv20_graph_load_context(struct nouveau_channel *);
@@ -1094,11 +1167,9 @@ extern int nv20_graph_unload_context(struct drm_device *);
extern int nv20_graph_init(struct drm_device *);
extern void nv20_graph_takedown(struct drm_device *);
extern int nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t,
- uint32_t, uint32_t);
+extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
/* nv40_graph.c */
-extern struct nouveau_pgraph_object_class nv40_graph_grclass[];
extern int nv40_graph_init(struct drm_device *);
extern void nv40_graph_takedown(struct drm_device *);
extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
@@ -1107,11 +1178,9 @@ extern void nv40_graph_destroy_context(struct nouveau_channel *);
extern int nv40_graph_load_context(struct nouveau_channel *);
extern int nv40_graph_unload_context(struct drm_device *);
extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t,
- uint32_t, uint32_t);
+extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
/* nv50_graph.c */
-extern struct nouveau_pgraph_object_class nv50_graph_grclass[];
extern int nv50_graph_init(struct drm_device *);
extern void nv50_graph_takedown(struct drm_device *);
extern void nv50_graph_fifo_access(struct drm_device *, bool);
@@ -1120,8 +1189,10 @@ extern int nv50_graph_create_context(struct nouveau_channel *);
extern void nv50_graph_destroy_context(struct nouveau_channel *);
extern int nv50_graph_load_context(struct nouveau_channel *);
extern int nv50_graph_unload_context(struct drm_device *);
-extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
+extern void nv50_graph_tlb_flush(struct drm_device *dev);
+extern void nv86_graph_tlb_flush(struct drm_device *dev);
+extern struct nouveau_enum nv50_data_error_names[];
/* nvc0_graph.c */
extern int nvc0_graph_init(struct drm_device *);
@@ -1133,16 +1204,22 @@ extern void nvc0_graph_destroy_context(struct nouveau_channel *);
extern int nvc0_graph_load_context(struct nouveau_channel *);
extern int nvc0_graph_unload_context(struct drm_device *);
+/* nv84_crypt.c */
+extern int nv84_crypt_init(struct drm_device *dev);
+extern void nv84_crypt_fini(struct drm_device *dev);
+extern int nv84_crypt_create_context(struct nouveau_channel *);
+extern void nv84_crypt_destroy_context(struct nouveau_channel *);
+extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
extern void nv04_instmem_takedown(struct drm_device *);
extern int nv04_instmem_suspend(struct drm_device *);
extern void nv04_instmem_resume(struct drm_device *);
-extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
- uint32_t *size);
-extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
-extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
-extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+extern int nv04_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align);
+extern void nv04_instmem_put(struct nouveau_gpuobj *);
+extern int nv04_instmem_map(struct nouveau_gpuobj *);
+extern void nv04_instmem_unmap(struct nouveau_gpuobj *);
extern void nv04_instmem_flush(struct drm_device *);
/* nv50_instmem.c */
@@ -1150,26 +1227,18 @@ extern int nv50_instmem_init(struct drm_device *);
extern void nv50_instmem_takedown(struct drm_device *);
extern int nv50_instmem_suspend(struct drm_device *);
extern void nv50_instmem_resume(struct drm_device *);
-extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
- uint32_t *size);
-extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
-extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
-extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+extern int nv50_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align);
+extern void nv50_instmem_put(struct nouveau_gpuobj *);
+extern int nv50_instmem_map(struct nouveau_gpuobj *);
+extern void nv50_instmem_unmap(struct nouveau_gpuobj *);
extern void nv50_instmem_flush(struct drm_device *);
extern void nv84_instmem_flush(struct drm_device *);
-extern void nv50_vm_flush(struct drm_device *, int engine);
/* nvc0_instmem.c */
extern int nvc0_instmem_init(struct drm_device *);
extern void nvc0_instmem_takedown(struct drm_device *);
extern int nvc0_instmem_suspend(struct drm_device *);
extern void nvc0_instmem_resume(struct drm_device *);
-extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
- uint32_t *size);
-extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
-extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
-extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
-extern void nvc0_instmem_flush(struct drm_device *);
/* nv04_mc.c */
extern int nv04_mc_init(struct drm_device *);
@@ -1239,7 +1308,9 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
-extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
+extern void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *);
+extern int nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
+ bool no_wait_reserve, bool no_wait_gpu);
/* nouveau_fence.c */
struct nouveau_fence;
@@ -1255,12 +1326,35 @@ extern void nouveau_fence_work(struct nouveau_fence *fence,
void (*work)(void *priv, bool signalled),
void *priv);
struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
-extern bool nouveau_fence_signalled(void *obj, void *arg);
-extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+
+extern bool __nouveau_fence_signalled(void *obj, void *arg);
+extern int __nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+extern int __nouveau_fence_flush(void *obj, void *arg);
+extern void __nouveau_fence_unref(void **obj);
+extern void *__nouveau_fence_ref(void *obj);
+
+static inline bool nouveau_fence_signalled(struct nouveau_fence *obj)
+{
+ return __nouveau_fence_signalled(obj, NULL);
+}
+static inline int
+nouveau_fence_wait(struct nouveau_fence *obj, bool lazy, bool intr)
+{
+ return __nouveau_fence_wait(obj, NULL, lazy, intr);
+}
extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
-extern int nouveau_fence_flush(void *obj, void *arg);
-extern void nouveau_fence_unref(void **obj);
-extern void *nouveau_fence_ref(void *obj);
+static inline int nouveau_fence_flush(struct nouveau_fence *obj)
+{
+ return __nouveau_fence_flush(obj, NULL);
+}
+static inline void nouveau_fence_unref(struct nouveau_fence **obj)
+{
+ __nouveau_fence_unref((void **)obj);
+}
+static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj)
+{
+ return __nouveau_fence_ref(obj);
+}
/* nouveau_gem.c */
extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
@@ -1280,15 +1374,28 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
+/* nouveau_display.c */
+int nouveau_vblank_enable(struct drm_device *dev, int crtc);
+void nouveau_vblank_disable(struct drm_device *dev, int crtc);
+int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event);
+int nouveau_finish_page_flip(struct nouveau_channel *,
+ struct nouveau_page_flip_state *);
+
/* nv10_gpio.c */
int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
/* nv50_gpio.c */
int nv50_gpio_init(struct drm_device *dev);
+void nv50_gpio_fini(struct drm_device *dev);
int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
-void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
+int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag,
+ void (*)(void *, int), void *);
+void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag,
+ void (*)(void *, int), void *);
+bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
/* nv50_calc. */
int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
@@ -1355,7 +1462,9 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val)
}
#define nv_wait(dev, reg, mask, val) \
- nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val))
+ nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val))
+#define nv_wait_ne(dev, reg, mask, val) \
+ nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val))
/* PRAMIN access */
static inline u32 nv_ri32(struct drm_device *dev, unsigned offset)
@@ -1468,6 +1577,37 @@ nv_match_device(struct drm_device *dev, unsigned device,
dev->pdev->subsystem_device == sub_device;
}
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_graph_class(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if ((dev_priv->chipset & 0xf0) == 0x60)
+ return 1;
+
+ return !(0x0baf & (1 << (dev_priv->chipset & 0x0f)));
+}
+
+/* memory type/access flags, do not match hardware values */
+#define NV_MEM_ACCESS_RO 1
+#define NV_MEM_ACCESS_WO 2
+#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
+#define NV_MEM_ACCESS_SYS 4
+#define NV_MEM_ACCESS_VM 8
+
+#define NV_MEM_TARGET_VRAM 0
+#define NV_MEM_TARGET_PCI 1
+#define NV_MEM_TARGET_PCI_NOSNOOP 2
+#define NV_MEM_TARGET_VM 3
+#define NV_MEM_TARGET_GART 4
+
+#define NV_MEM_TYPE_VM 0x7f
+#define NV_MEM_COMP_VM 0x03
+
+/* NV_SW object class */
#define NV_SW 0x0000506e
#define NV_SW_DMA_SEMAPHORE 0x00000060
#define NV_SW_SEMAPHORE_OFFSET 0x00000064
@@ -1478,5 +1618,6 @@ nv_match_device(struct drm_device *dev, unsigned device,
#define NV_SW_VBLSEM_OFFSET 0x00000400
#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404
#define NV_SW_VBLSEM_RELEASE 0x00000408
+#define NV_SW_PAGE_FLIP 0x00000500
#endif /* __NOUVEAU_DRV_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 02a4d1fd4845..60769d2f9a66 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -49,6 +49,102 @@
#include "nouveau_fbcon.h"
#include "nouveau_dma.h"
+static void
+nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
+ ret = -ENODEV;
+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
+ mutex_trylock(&dev_priv->channel->mutex)) {
+ if (dev_priv->card_type < NV_50)
+ ret = nv04_fbcon_fillrect(info, rect);
+ else
+ if (dev_priv->card_type < NV_C0)
+ ret = nv50_fbcon_fillrect(info, rect);
+ else
+ ret = nvc0_fbcon_fillrect(info, rect);
+ mutex_unlock(&dev_priv->channel->mutex);
+ }
+
+ if (ret == 0)
+ return;
+
+ if (ret != -ENODEV)
+ nouveau_fbcon_gpu_lockup(info);
+ cfb_fillrect(info, rect);
+}
+
+static void
+nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
+ ret = -ENODEV;
+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
+ mutex_trylock(&dev_priv->channel->mutex)) {
+ if (dev_priv->card_type < NV_50)
+ ret = nv04_fbcon_copyarea(info, image);
+ else
+ if (dev_priv->card_type < NV_C0)
+ ret = nv50_fbcon_copyarea(info, image);
+ else
+ ret = nvc0_fbcon_copyarea(info, image);
+ mutex_unlock(&dev_priv->channel->mutex);
+ }
+
+ if (ret == 0)
+ return;
+
+ if (ret != -ENODEV)
+ nouveau_fbcon_gpu_lockup(info);
+ cfb_copyarea(info, image);
+}
+
+static void
+nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
+ ret = -ENODEV;
+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
+ mutex_trylock(&dev_priv->channel->mutex)) {
+ if (dev_priv->card_type < NV_50)
+ ret = nv04_fbcon_imageblit(info, image);
+ else
+ if (dev_priv->card_type < NV_C0)
+ ret = nv50_fbcon_imageblit(info, image);
+ else
+ ret = nvc0_fbcon_imageblit(info, image);
+ mutex_unlock(&dev_priv->channel->mutex);
+ }
+
+ if (ret == 0)
+ return;
+
+ if (ret != -ENODEV)
+ nouveau_fbcon_gpu_lockup(info);
+ cfb_imageblit(info, image);
+}
+
static int
nouveau_fbcon_sync(struct fb_info *info)
{
@@ -58,22 +154,36 @@ nouveau_fbcon_sync(struct fb_info *info)
struct nouveau_channel *chan = dev_priv->channel;
int ret, i;
- if (!chan || !chan->accel_done ||
+ if (!chan || !chan->accel_done || in_interrupt() ||
info->state != FBINFO_STATE_RUNNING ||
info->flags & FBINFO_HWACCEL_DISABLED)
return 0;
- if (RING_SPACE(chan, 4)) {
+ if (!mutex_trylock(&chan->mutex))
+ return 0;
+
+ ret = RING_SPACE(chan, 4);
+ if (ret) {
+ mutex_unlock(&chan->mutex);
nouveau_fbcon_gpu_lockup(info);
return 0;
}
- BEGIN_RING(chan, 0, 0x0104, 1);
- OUT_RING(chan, 0);
- BEGIN_RING(chan, 0, 0x0100, 1);
- OUT_RING(chan, 0);
+ if (dev_priv->card_type >= NV_C0) {
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1);
+ OUT_RING (chan, 0);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1);
+ OUT_RING (chan, 0);
+ } else {
+ BEGIN_RING(chan, 0, 0x0104, 1);
+ OUT_RING (chan, 0);
+ BEGIN_RING(chan, 0, 0x0100, 1);
+ OUT_RING (chan, 0);
+ }
+
nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff);
FIRE_RING(chan);
+ mutex_unlock(&chan->mutex);
ret = -EBUSY;
for (i = 0; i < 100000; i++) {
@@ -97,9 +207,9 @@ static struct fb_ops nouveau_fbcon_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
+ .fb_fillrect = nouveau_fbcon_fillrect,
+ .fb_copyarea = nouveau_fbcon_copyarea,
+ .fb_imageblit = nouveau_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
@@ -108,29 +218,13 @@ static struct fb_ops nouveau_fbcon_ops = {
.fb_debug_leave = drm_fb_helper_debug_leave,
};
-static struct fb_ops nv04_fbcon_ops = {
+static struct fb_ops nouveau_fbcon_sw_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
- .fb_fillrect = nv04_fbcon_fillrect,
- .fb_copyarea = nv04_fbcon_copyarea,
- .fb_imageblit = nv04_fbcon_imageblit,
- .fb_sync = nouveau_fbcon_sync,
- .fb_pan_display = drm_fb_helper_pan_display,
- .fb_blank = drm_fb_helper_blank,
- .fb_setcmap = drm_fb_helper_setcmap,
- .fb_debug_enter = drm_fb_helper_debug_enter,
- .fb_debug_leave = drm_fb_helper_debug_leave,
-};
-
-static struct fb_ops nv50_fbcon_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = drm_fb_helper_check_var,
- .fb_set_par = drm_fb_helper_set_par,
- .fb_fillrect = nv50_fbcon_fillrect,
- .fb_copyarea = nv50_fbcon_copyarea,
- .fb_imageblit = nv50_fbcon_imageblit,
- .fb_sync = nouveau_fbcon_sync,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
@@ -257,9 +351,9 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
info->flags |= FBINFO_CAN_FORCE_OUTPUT;
- info->fbops = &nouveau_fbcon_ops;
- info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset -
- dev_priv->vm_vram_base;
+ info->fbops = &nouveau_fbcon_sw_ops;
+ info->fix.smem_start = nvbo->bo.mem.bus.base +
+ nvbo->bo.mem.bus.offset;
info->fix.smem_len = size;
info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo);
@@ -268,10 +362,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
- /* FIXME: we really shouldn't expose mmio space at all */
- info->fix.mmio_start = pci_resource_start(pdev, 1);
- info->fix.mmio_len = pci_resource_len(pdev, 1);
-
/* Set aperture base/size for vesafb takeover */
info->apertures = dev_priv->apertures;
if (!info->apertures) {
@@ -285,19 +375,20 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
info->pixmap.flags = FB_PIXMAP_SYSTEM;
info->pixmap.scan_align = 1;
+ mutex_unlock(&dev->struct_mutex);
+
if (dev_priv->channel && !nouveau_nofbaccel) {
- switch (dev_priv->card_type) {
- case NV_C0:
- break;
- case NV_50:
- nv50_fbcon_accel_init(info);
- info->fbops = &nv50_fbcon_ops;
- break;
- default:
- nv04_fbcon_accel_init(info);
- info->fbops = &nv04_fbcon_ops;
- break;
- };
+ ret = -ENODEV;
+ if (dev_priv->card_type < NV_50)
+ ret = nv04_fbcon_accel_init(info);
+ else
+ if (dev_priv->card_type < NV_C0)
+ ret = nv50_fbcon_accel_init(info);
+ else
+ ret = nvc0_fbcon_accel_init(info);
+
+ if (ret == 0)
+ info->fbops = &nouveau_fbcon_ops;
}
nouveau_fbcon_zfill(dev, nfbdev);
@@ -308,7 +399,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
nouveau_fb->base.height,
nvbo->bo.offset, nvbo);
- mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(dev->pdev, info);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index e7e12684c37e..b73c29f87fc3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -40,15 +40,21 @@ struct nouveau_fbdev {
void nouveau_fbcon_restore(void);
-void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
-void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
+int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
+int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info);
-void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
-void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
+
+int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
+int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info);
+int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
+int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
+int nvc0_fbcon_accel_init(struct fb_info *info);
+
void nouveau_fbcon_gpu_lockup(struct fb_info *info);
int nouveau_fbcon_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 441b12420bb1..221b8462ea37 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -32,7 +32,8 @@
#include "nouveau_dma.h"
#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
-#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \
+ nouveau_private(dev)->card_type < NV_C0)
struct nouveau_fence {
struct nouveau_channel *channel;
@@ -64,6 +65,7 @@ nouveau_fence_del(struct kref *ref)
struct nouveau_fence *fence =
container_of(ref, struct nouveau_fence, refcount);
+ nouveau_channel_ref(NULL, &fence->channel);
kfree(fence);
}
@@ -76,14 +78,17 @@ nouveau_fence_update(struct nouveau_channel *chan)
spin_lock(&chan->fence.lock);
- if (USE_REFCNT(dev))
- sequence = nvchan_rd32(chan, 0x48);
- else
- sequence = atomic_read(&chan->fence.last_sequence_irq);
+ /* Fetch the last sequence if the channel is still up and running */
+ if (likely(!list_empty(&chan->fence.pending))) {
+ if (USE_REFCNT(dev))
+ sequence = nvchan_rd32(chan, 0x48);
+ else
+ sequence = atomic_read(&chan->fence.last_sequence_irq);
- if (chan->fence.sequence_ack == sequence)
- goto out;
- chan->fence.sequence_ack = sequence;
+ if (chan->fence.sequence_ack == sequence)
+ goto out;
+ chan->fence.sequence_ack = sequence;
+ }
list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
sequence = fence->sequence;
@@ -113,13 +118,13 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
if (!fence)
return -ENOMEM;
kref_init(&fence->refcount);
- fence->channel = chan;
+ nouveau_channel_ref(chan, &fence->channel);
if (emit)
ret = nouveau_fence_emit(fence);
if (ret)
- nouveau_fence_unref((void *)&fence);
+ nouveau_fence_unref(&fence);
*pfence = fence;
return ret;
}
@@ -127,7 +132,7 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
struct nouveau_channel *
nouveau_fence_channel(struct nouveau_fence *fence)
{
- return fence ? fence->channel : NULL;
+ return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
}
int
@@ -135,6 +140,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel *chan = fence->channel;
struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
ret = RING_SPACE(chan, 2);
@@ -155,8 +161,15 @@ nouveau_fence_emit(struct nouveau_fence *fence)
list_add_tail(&fence->entry, &chan->fence.pending);
spin_unlock(&chan->fence.lock);
- BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1);
- OUT_RING(chan, fence->sequence);
+ if (USE_REFCNT(dev)) {
+ if (dev_priv->card_type < NV_C0)
+ BEGIN_RING(chan, NvSubSw, 0x0050, 1);
+ else
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1);
+ } else {
+ BEGIN_RING(chan, NvSubSw, 0x0150, 1);
+ }
+ OUT_RING (chan, fence->sequence);
FIRE_RING(chan);
return 0;
@@ -182,7 +195,7 @@ nouveau_fence_work(struct nouveau_fence *fence,
}
void
-nouveau_fence_unref(void **sync_obj)
+__nouveau_fence_unref(void **sync_obj)
{
struct nouveau_fence *fence = nouveau_fence(*sync_obj);
@@ -192,7 +205,7 @@ nouveau_fence_unref(void **sync_obj)
}
void *
-nouveau_fence_ref(void *sync_obj)
+__nouveau_fence_ref(void *sync_obj)
{
struct nouveau_fence *fence = nouveau_fence(sync_obj);
@@ -201,7 +214,7 @@ nouveau_fence_ref(void *sync_obj)
}
bool
-nouveau_fence_signalled(void *sync_obj, void *sync_arg)
+__nouveau_fence_signalled(void *sync_obj, void *sync_arg)
{
struct nouveau_fence *fence = nouveau_fence(sync_obj);
struct nouveau_channel *chan = fence->channel;
@@ -214,13 +227,14 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg)
}
int
-nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
+__nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
{
unsigned long timeout = jiffies + (3 * DRM_HZ);
+ unsigned long sleep_time = jiffies + 1;
int ret = 0;
while (1) {
- if (nouveau_fence_signalled(sync_obj, sync_arg))
+ if (__nouveau_fence_signalled(sync_obj, sync_arg))
break;
if (time_after_eq(jiffies, timeout)) {
@@ -230,7 +244,7 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
__set_current_state(intr ? TASK_INTERRUPTIBLE
: TASK_UNINTERRUPTIBLE);
- if (lazy)
+ if (lazy && time_after_eq(jiffies, sleep_time))
schedule_timeout(1);
if (intr && signal_pending(current)) {
@@ -249,6 +263,7 @@ alloc_semaphore(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_semaphore *sema;
+ int ret;
if (!USE_SEMA(dev))
return NULL;
@@ -257,10 +272,14 @@ alloc_semaphore(struct drm_device *dev)
if (!sema)
goto fail;
+ ret = drm_mm_pre_get(&dev_priv->fence.heap);
+ if (ret)
+ goto fail;
+
spin_lock(&dev_priv->fence.lock);
sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
if (sema->mem)
- sema->mem = drm_mm_get_block(sema->mem, 4, 0);
+ sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0);
spin_unlock(&dev_priv->fence.lock);
if (!sema->mem)
@@ -363,7 +382,7 @@ emit_semaphore(struct nouveau_channel *chan, int method,
kref_get(&sema->ref);
nouveau_fence_work(fence, semaphore_work, sema);
- nouveau_fence_unref((void *)&fence);
+ nouveau_fence_unref(&fence);
return 0;
}
@@ -375,33 +394,49 @@ nouveau_fence_sync(struct nouveau_fence *fence,
struct nouveau_channel *chan = nouveau_fence_channel(fence);
struct drm_device *dev = wchan->dev;
struct nouveau_semaphore *sema;
- int ret;
+ int ret = 0;
- if (likely(!fence || chan == wchan ||
- nouveau_fence_signalled(fence, NULL)))
- return 0;
+ if (likely(!chan || chan == wchan ||
+ nouveau_fence_signalled(fence)))
+ goto out;
sema = alloc_semaphore(dev);
if (!sema) {
/* Early card or broken userspace, fall back to
* software sync. */
- return nouveau_fence_wait(fence, NULL, false, false);
+ ret = nouveau_fence_wait(fence, true, false);
+ goto out;
+ }
+
+ /* try to take chan's mutex, if we can't take it right away
+ * we have to fallback to software sync to prevent locking
+ * order issues
+ */
+ if (!mutex_trylock(&chan->mutex)) {
+ ret = nouveau_fence_wait(fence, true, false);
+ goto out_unref;
}
/* Make wchan wait until it gets signalled */
ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema);
if (ret)
- goto out;
+ goto out_unlock;
/* Signal the semaphore from chan */
ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema);
-out:
+
+out_unlock:
+ mutex_unlock(&chan->mutex);
+out_unref:
kref_put(&sema->ref, free_semaphore);
+out:
+ if (chan)
+ nouveau_channel_put_unlocked(&chan);
return ret;
}
int
-nouveau_fence_flush(void *sync_obj, void *sync_arg)
+__nouveau_fence_flush(void *sync_obj, void *sync_arg)
{
return 0;
}
@@ -415,30 +450,27 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
int ret;
/* Create an NV_SW object for various sync purposes */
- ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
- if (ret)
- return ret;
-
- ret = nouveau_ramht_insert(chan, NvSw, obj);
- nouveau_gpuobj_ref(NULL, &obj);
+ ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
if (ret)
return ret;
- ret = RING_SPACE(chan, 2);
- if (ret)
- return ret;
- BEGIN_RING(chan, NvSubSw, 0, 1);
- OUT_RING(chan, NvSw);
+ /* we leave subchannel empty for nvc0 */
+ if (dev_priv->card_type < NV_C0) {
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+ BEGIN_RING(chan, NvSubSw, 0, 1);
+ OUT_RING(chan, NvSw);
+ }
/* Create a DMA object for the shared cross-channel sync area. */
if (USE_SEMA(dev)) {
- struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node;
+ struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
mem->start << PAGE_SHIFT,
- mem->size << PAGE_SHIFT,
- NV_DMA_ACCESS_RW,
- NV_DMA_TARGET_VIDMEM, &obj);
+ mem->size, NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
if (ret)
return ret;
@@ -468,6 +500,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan)
{
struct nouveau_fence *tmp, *fence;
+ spin_lock(&chan->fence.lock);
+
list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
fence->signalled = true;
list_del(&fence->entry);
@@ -477,6 +511,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan)
kref_put(&fence->refcount, nouveau_fence_del);
}
+
+ spin_unlock(&chan->fence.lock);
}
int
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 5c4c929d7f74..506c508b7eda 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -48,9 +48,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
return;
nvbo->gem = NULL;
- if (unlikely(nvbo->cpu_filp))
- ttm_bo_synccpu_write_release(bo);
-
if (unlikely(nvbo->pin_refcnt)) {
nvbo->pin_refcnt = 1;
nouveau_bo_unpin(nvbo);
@@ -106,26 +103,6 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep)
return 0;
}
-static bool
-nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
- switch (tile_flags) {
- case 0x0000:
- case 0x1800:
- case 0x2800:
- case 0x4800:
- case 0x7000:
- case 0x7400:
- case 0x7a00:
- case 0xe000:
- break;
- default:
- NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
- return false;
- }
-
- return true;
-}
-
int
nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
struct drm_file *file_priv)
@@ -140,11 +117,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
- if (req->channel_hint) {
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel_hint,
- file_priv, chan);
- }
-
if (req->info.domain & NOUVEAU_GEM_DOMAIN_VRAM)
flags |= TTM_PL_FLAG_VRAM;
if (req->info.domain & NOUVEAU_GEM_DOMAIN_GART)
@@ -152,13 +124,23 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU)
flags |= TTM_PL_FLAG_SYSTEM;
- if (!nouveau_gem_tile_flags_valid(dev, req->info.tile_flags))
+ if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) {
+ NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags);
return -EINVAL;
+ }
+
+ if (req->channel_hint) {
+ chan = nouveau_channel_get(dev, file_priv, req->channel_hint);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+ }
ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags,
req->info.tile_mode, req->info.tile_flags, false,
(req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE),
&nvbo);
+ if (chan)
+ nouveau_channel_put(&chan);
if (ret)
return ret;
@@ -225,15 +207,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
list_for_each_safe(entry, tmp, list) {
nvbo = list_entry(entry, struct nouveau_bo, entry);
- if (likely(fence)) {
- struct nouveau_fence *prev_fence;
-
- spin_lock(&nvbo->bo.lock);
- prev_fence = nvbo->bo.sync_obj;
- nvbo->bo.sync_obj = nouveau_fence_ref(fence);
- spin_unlock(&nvbo->bo.lock);
- nouveau_fence_unref((void *)&prev_fence);
- }
+
+ nouveau_bo_fence(nvbo, fence);
if (unlikely(nvbo->validate_mapped)) {
ttm_bo_kunmap(&nvbo->kmap);
@@ -293,14 +268,15 @@ retry:
return -EINVAL;
}
- ret = ttm_bo_reserve(&nvbo->bo, false, false, true, sequence);
+ ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence);
if (ret) {
validate_fini(op, NULL);
- if (ret == -EAGAIN)
- ret = ttm_bo_wait_unreserved(&nvbo->bo, false);
+ if (unlikely(ret == -EAGAIN))
+ ret = ttm_bo_wait_unreserved(&nvbo->bo, true);
drm_gem_object_unreference_unlocked(gem);
- if (ret) {
- NV_ERROR(dev, "fail reserve\n");
+ if (unlikely(ret)) {
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "fail reserve\n");
return ret;
}
goto retry;
@@ -325,25 +301,6 @@ retry:
validate_fini(op, NULL);
return -EINVAL;
}
-
- if (unlikely(atomic_read(&nvbo->bo.cpu_writers) > 0)) {
- validate_fini(op, NULL);
-
- if (nvbo->cpu_filp == file_priv) {
- NV_ERROR(dev, "bo %p mapped by process trying "
- "to validate it!\n", nvbo);
- return -EINVAL;
- }
-
- mutex_unlock(&drm_global_mutex);
- ret = ttm_bo_wait_cpu(&nvbo->bo, false);
- mutex_lock(&drm_global_mutex);
- if (ret) {
- NV_ERROR(dev, "fail wait_cpu\n");
- return ret;
- }
- goto retry;
- }
}
return 0;
@@ -377,11 +334,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
}
nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan;
- ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
- false, false, false);
+ ret = nouveau_bo_validate(nvbo, true, false, false);
nvbo->channel = NULL;
if (unlikely(ret)) {
- NV_ERROR(dev, "fail ttm_validate\n");
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "fail ttm_validate\n");
return ret;
}
@@ -433,13 +390,15 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
if (unlikely(ret)) {
- NV_ERROR(dev, "validate_init\n");
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "validate_init\n");
return ret;
}
ret = validate_list(chan, &op->vram_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
- NV_ERROR(dev, "validate vram_list\n");
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "validate vram_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -447,7 +406,8 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->gart_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
- NV_ERROR(dev, "validate gart_list\n");
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "validate gart_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -455,7 +415,8 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->both_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
- NV_ERROR(dev, "validate both_list\n");
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "validate both_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -551,9 +512,9 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev,
data |= r->vor;
}
- spin_lock(&nvbo->bo.lock);
+ spin_lock(&nvbo->bo.bdev->fence_lock);
ret = ttm_bo_wait(&nvbo->bo, false, false, false);
- spin_unlock(&nvbo->bo.lock);
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
if (ret) {
NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret);
break;
@@ -579,7 +540,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct nouveau_fence *fence = NULL;
int i, j, ret = 0, do_reloc = 0;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
+ chan = nouveau_channel_get(dev, file_priv, req->channel);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
req->vram_available = dev_priv->fb_aper_free;
req->gart_available = dev_priv->gart_info.aper_free;
@@ -589,28 +552,34 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n",
req->nr_push, NOUVEAU_GEM_MAX_PUSH);
+ nouveau_channel_put(&chan);
return -EINVAL;
}
if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n",
req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
+ nouveau_channel_put(&chan);
return -EINVAL;
}
if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n",
req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
+ nouveau_channel_put(&chan);
return -EINVAL;
}
push = u_memcpya(req->push, req->nr_push, sizeof(*push));
- if (IS_ERR(push))
+ if (IS_ERR(push)) {
+ nouveau_channel_put(&chan);
return PTR_ERR(push);
+ }
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
if (IS_ERR(bo)) {
kfree(push);
+ nouveau_channel_put(&chan);
return PTR_ERR(bo);
}
@@ -633,7 +602,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
req->nr_buffers, &op, &do_reloc);
if (ret) {
- NV_ERROR(dev, "validate: %d\n", ret);
+ if (ret != -ERESTARTSYS)
+ NV_ERROR(dev, "validate: %d\n", ret);
goto out;
}
@@ -726,7 +696,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
out:
validate_fini(&op, fence);
- nouveau_fence_unref((void**)&fence);
+ nouveau_fence_unref(&fence);
kfree(bo);
kfree(push);
@@ -744,6 +714,7 @@ out_next:
req->suffix1 = 0x00000000;
}
+ nouveau_channel_put(&chan);
return ret;
}
@@ -775,26 +746,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
return -ENOENT;
nvbo = nouveau_gem_object(gem);
- if (nvbo->cpu_filp) {
- if (nvbo->cpu_filp == file_priv)
- goto out;
-
- ret = ttm_bo_wait_cpu(&nvbo->bo, no_wait);
- if (ret)
- goto out;
- }
-
- if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) {
- spin_lock(&nvbo->bo.lock);
- ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait);
- spin_unlock(&nvbo->bo.lock);
- } else {
- ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait);
- if (ret == 0)
- nvbo->cpu_filp = file_priv;
- }
-
-out:
+ spin_lock(&nvbo->bo.bdev->fence_lock);
+ ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait);
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
drm_gem_object_unreference_unlocked(gem);
return ret;
}
@@ -803,26 +757,7 @@ int
nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct drm_nouveau_gem_cpu_prep *req = data;
- struct drm_gem_object *gem;
- struct nouveau_bo *nvbo;
- int ret = -EINVAL;
-
- gem = drm_gem_object_lookup(dev, file_priv, req->handle);
- if (!gem)
- return -ENOENT;
- nvbo = nouveau_gem_object(gem);
-
- if (nvbo->cpu_filp != file_priv)
- goto out;
- nvbo->cpu_filp = NULL;
-
- ttm_bo_synccpu_write_release(&nvbo->bo);
- ret = 0;
-
-out:
- drm_gem_object_unreference_unlocked(gem);
- return ret;
+ return 0;
}
int
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index bed669a54a2d..053edf9d2f67 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
struct pll_lims pll_lim;
struct nouveau_pll_vals pv;
- uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
+ enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
- if (get_pll_limits(dev, pllreg, &pll_lim))
+ if (get_pll_limits(dev, pll, &pll_lim))
return;
- nouveau_hw_get_pllvals(dev, pllreg, &pv);
+ nouveau_hw_get_pllvals(dev, pll, &pv);
if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
pv.M1 = pll_lim.vco1.max_m;
pv.N1 = pll_lim.vco1.min_n;
pv.log2P = pll_lim.max_usable_log2p;
- nouveau_hw_setpll(dev, pllreg, &pv);
+ nouveau_hw_setpll(dev, pll_lim.reg, &pv);
}
/*
@@ -953,7 +953,7 @@ nv_load_state_ext(struct drm_device *dev, int head,
NVWriteCRTC(dev, head, NV_PCRTC_850, regp->crtc_850);
reg900 = NVReadRAMDAC(dev, head, NV_PRAMDAC_900);
- if (regp->crtc_cfg == NV_PCRTC_CONFIG_START_ADDRESS_HSYNC)
+ if (regp->crtc_cfg == NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC)
NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 | 0x10000);
else
NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 & ~0x10000);
@@ -999,8 +999,8 @@ nv_load_state_ext(struct drm_device *dev, int head,
if (dev_priv->card_type == NV_10) {
/* Not waiting for vertical retrace before modifying
CRE_53/CRE_54 causes lockups. */
- nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
- nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
+ nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
+ nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
}
wr_cio_state(dev, head, regp, NV_CIO_CRE_53);
@@ -1017,8 +1017,9 @@ nv_load_state_ext(struct drm_device *dev, int head,
NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start);
- /* Setting 1 on this value gives you interrupts for every vblank period. */
- NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, 0);
+ /* Enable vblank interrupts. */
+ NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0,
+ (dev->vblank_enabled[head] ? 1 : 0));
NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.h b/drivers/gpu/drm/nouveau/nouveau_hw.h
index 869130f83602..2989090b9434 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.h
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.h
@@ -416,6 +416,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
}
static inline void
+nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
+
+ if (dev_priv->card_type == NV_04) {
+ /*
+ * Hilarious, the 24th bit doesn't want to stick to
+ * PCRTC_START...
+ */
+ int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
+
+ NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
+ (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
+ }
+}
+
+static inline void
nv_show_cursor(struct drm_device *dev, int head, bool show)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index fdd7e3de79c8..cb389d014326 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL;
- if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
+ if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
uint32_t reg = 0xe500, val;
if (i2c->port_type == 6) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 6fd51a51c608..2ba7265bc967 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -36,11 +36,7 @@
#include "nouveau_drv.h"
#include "nouveau_reg.h"
#include "nouveau_ramht.h"
-#include <linux/ratelimit.h>
-
-/* needed for hotplug irq */
-#include "nouveau_connector.h"
-#include "nv50_display.h"
+#include "nouveau_util.h"
void
nouveau_irq_preinstall(struct drm_device *dev)
@@ -50,18 +46,19 @@ nouveau_irq_preinstall(struct drm_device *dev)
/* Master disable */
nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
- if (dev_priv->card_type >= NV_50) {
- INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
- INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
- INIT_LIST_HEAD(&dev_priv->vbl_waiting);
- }
+ INIT_LIST_HEAD(&dev_priv->vbl_waiting);
}
int
nouveau_irq_postinstall(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
/* Master enable */
nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
+ if (dev_priv->msi_enabled)
+ nv_wr08(dev, 0x00088068, 0xff);
+
return 0;
}
@@ -72,1182 +69,83 @@ nouveau_irq_uninstall(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
}
-static int
-nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data)
-{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nouveau_pgraph_object_method *grm;
- struct nouveau_pgraph_object_class *grc;
-
- grc = dev_priv->engine.graph.grclass;
- while (grc->id) {
- if (grc->id == class)
- break;
- grc++;
- }
-
- if (grc->id != class || !grc->methods)
- return -ENOENT;
-
- grm = grc->methods;
- while (grm->id) {
- if (grm->id == mthd)
- return grm->exec(chan, class, mthd, data);
- grm++;
- }
-
- return -ENOENT;
-}
-
-static bool
-nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
-{
- struct drm_device *dev = chan->dev;
- const int subc = (addr >> 13) & 0x7;
- const int mthd = addr & 0x1ffc;
-
- if (mthd == 0x0000) {
- struct nouveau_gpuobj *gpuobj;
-
- gpuobj = nouveau_ramht_find(chan, data);
- if (!gpuobj)
- return false;
-
- if (gpuobj->engine != NVOBJ_ENGINE_SW)
- return false;
-
- chan->sw_subchannel[subc] = gpuobj->class;
- nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
- NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
- return true;
- }
-
- /* hw object */
- if (nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE) & (1 << (subc*4)))
- return false;
-
- if (nouveau_call_method(chan, chan->sw_subchannel[subc], mthd, data))
- return false;
-
- return true;
-}
-
-static void
-nouveau_fifo_irq_handler(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
- uint32_t status, reassign;
- int cnt = 0;
-
- reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
- while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
- struct nouveau_channel *chan = NULL;
- uint32_t chid, get;
-
- nv_wr32(dev, NV03_PFIFO_CACHES, 0);
-
- chid = engine->fifo.channel_id(dev);
- if (chid >= 0 && chid < engine->fifo.channels)
- chan = dev_priv->fifos[chid];
- get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
-
- if (status & NV_PFIFO_INTR_CACHE_ERROR) {
- uint32_t mthd, data;
- int ptr;
-
- /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
- * wrapping on my G80 chips, but CACHE1 isn't big
- * enough for this much data.. Tests show that it
- * wraps around to the start at GET=0x800.. No clue
- * as to why..
- */
- ptr = (get & 0x7ff) >> 2;
-
- if (dev_priv->card_type < NV_40) {
- mthd = nv_rd32(dev,
- NV04_PFIFO_CACHE1_METHOD(ptr));
- data = nv_rd32(dev,
- NV04_PFIFO_CACHE1_DATA(ptr));
- } else {
- mthd = nv_rd32(dev,
- NV40_PFIFO_CACHE1_METHOD(ptr));
- data = nv_rd32(dev,
- NV40_PFIFO_CACHE1_DATA(ptr));
- }
-
- if (!chan || !nouveau_fifo_swmthd(chan, mthd, data)) {
- NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
- "Mthd 0x%04x Data 0x%08x\n",
- chid, (mthd >> 13) & 7, mthd & 0x1ffc,
- data);
- }
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
- nv_wr32(dev, NV03_PFIFO_INTR_0,
- NV_PFIFO_INTR_CACHE_ERROR);
-
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
- nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
- nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
- nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
- nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-
- status &= ~NV_PFIFO_INTR_CACHE_ERROR;
- }
-
- if (status & NV_PFIFO_INTR_DMA_PUSHER) {
- u32 get = nv_rd32(dev, 0x003244);
- u32 put = nv_rd32(dev, 0x003240);
- u32 push = nv_rd32(dev, 0x003220);
- u32 state = nv_rd32(dev, 0x003228);
-
- if (dev_priv->card_type == NV_50) {
- u32 ho_get = nv_rd32(dev, 0x003328);
- u32 ho_put = nv_rd32(dev, 0x003320);
- u32 ib_get = nv_rd32(dev, 0x003334);
- u32 ib_put = nv_rd32(dev, 0x003330);
-
- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
- "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
- "State 0x%08x Push 0x%08x\n",
- chid, ho_get, get, ho_put, put, ib_get, ib_put,
- state, push);
-
- /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
- nv_wr32(dev, 0x003364, 0x00000000);
- if (get != put || ho_get != ho_put) {
- nv_wr32(dev, 0x003244, put);
- nv_wr32(dev, 0x003328, ho_put);
- } else
- if (ib_get != ib_put) {
- nv_wr32(dev, 0x003334, ib_put);
- }
- } else {
- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
- "Put 0x%08x State 0x%08x Push 0x%08x\n",
- chid, get, put, state, push);
-
- if (get != put)
- nv_wr32(dev, 0x003244, put);
- }
-
- nv_wr32(dev, 0x003228, 0x00000000);
- nv_wr32(dev, 0x003220, 0x00000001);
- nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
- status &= ~NV_PFIFO_INTR_DMA_PUSHER;
- }
-
- if (status & NV_PFIFO_INTR_SEMAPHORE) {
- uint32_t sem;
-
- status &= ~NV_PFIFO_INTR_SEMAPHORE;
- nv_wr32(dev, NV03_PFIFO_INTR_0,
- NV_PFIFO_INTR_SEMAPHORE);
-
- sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
- nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
-
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
- }
-
- if (dev_priv->card_type == NV_50) {
- if (status & 0x00000010) {
- nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
- status &= ~0x00000010;
- nv_wr32(dev, 0x002100, 0x00000010);
- }
- }
-
- if (status) {
- NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
- status, chid);
- nv_wr32(dev, NV03_PFIFO_INTR_0, status);
- status = 0;
- }
-
- nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
- }
-
- if (status) {
- NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
- nv_wr32(dev, 0x2140, 0);
- nv_wr32(dev, 0x140, 0);
- }
-
- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
-}
-
-struct nouveau_bitfield_names {
- uint32_t mask;
- const char *name;
-};
-
-static struct nouveau_bitfield_names nstatus_names[] =
-{
- { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
-};
-
-static struct nouveau_bitfield_names nstatus_names_nv10[] =
-{
- { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
-};
-
-static struct nouveau_bitfield_names nsource_names[] =
-{
- { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
- { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
- { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
- { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
- { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
- { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
- { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
- { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
- { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
- { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
-};
-
-static void
-nouveau_print_bitfield_names_(uint32_t value,
- const struct nouveau_bitfield_names *namelist,
- const int namelist_len)
-{
- /*
- * Caller must have already printed the KERN_* log level for us.
- * Also the caller is responsible for adding the newline.
- */
- int i;
- for (i = 0; i < namelist_len; ++i) {
- uint32_t mask = namelist[i].mask;
- if (value & mask) {
- printk(" %s", namelist[i].name);
- value &= ~mask;
- }
- }
- if (value)
- printk(" (unknown bits 0x%08x)", value);
-}
-#define nouveau_print_bitfield_names(val, namelist) \
- nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
-
-struct nouveau_enum_names {
- uint32_t value;
- const char *name;
-};
-
-static void
-nouveau_print_enum_names_(uint32_t value,
- const struct nouveau_enum_names *namelist,
- const int namelist_len)
-{
- /*
- * Caller must have already printed the KERN_* log level for us.
- * Also the caller is responsible for adding the newline.
- */
- int i;
- for (i = 0; i < namelist_len; ++i) {
- if (value == namelist[i].value) {
- printk("%s", namelist[i].name);
- return;
- }
- }
- printk("unknown value 0x%08x", value);
-}
-#define nouveau_print_enum_names(val, namelist) \
- nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist))
-
-static int
-nouveau_graph_chid_from_grctx(struct drm_device *dev)
+irqreturn_t
+nouveau_irq_handler(DRM_IRQ_ARGS)
{
+ struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t inst;
+ unsigned long flags;
+ u32 stat;
int i;
- if (dev_priv->card_type < NV_40)
- return dev_priv->engine.fifo.channels;
- else
- if (dev_priv->card_type < NV_50) {
- inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4;
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->fifos[i];
-
- if (!chan || !chan->ramin_grctx)
- continue;
-
- if (inst == chan->ramin_grctx->pinst)
- break;
- }
- } else {
- inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12;
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->fifos[i];
-
- if (!chan || !chan->ramin)
- continue;
-
- if (inst == chan->ramin->vinst)
- break;
- }
- }
-
-
- return i;
-}
-
-static int
-nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
- int channel;
-
- if (dev_priv->card_type < NV_10)
- channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf;
- else
- if (dev_priv->card_type < NV_40)
- channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
- else
- channel = nouveau_graph_chid_from_grctx(dev);
-
- if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) {
- NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel);
- return -EINVAL;
- }
-
- *channel_ret = channel;
- return 0;
-}
-
-struct nouveau_pgraph_trap {
- int channel;
- int class;
- int subc, mthd, size;
- uint32_t data, data2;
- uint32_t nsource, nstatus;
-};
-
-static void
-nouveau_graph_trap_info(struct drm_device *dev,
- struct nouveau_pgraph_trap *trap)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t address;
-
- trap->nsource = trap->nstatus = 0;
- if (dev_priv->card_type < NV_50) {
- trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
- trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
- }
-
- if (nouveau_graph_trapped_channel(dev, &trap->channel))
- trap->channel = -1;
- address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-
- trap->mthd = address & 0x1FFC;
- trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
- if (dev_priv->card_type < NV_10) {
- trap->subc = (address >> 13) & 0x7;
- } else {
- trap->subc = (address >> 16) & 0x7;
- trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH);
- }
-
- if (dev_priv->card_type < NV_10)
- trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF;
- else if (dev_priv->card_type < NV_40)
- trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF;
- else if (dev_priv->card_type < NV_50)
- trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF;
- else
- trap->class = nv_rd32(dev, 0x400814);
-}
-
-static void
-nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
- struct nouveau_pgraph_trap *trap)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
-
- if (dev_priv->card_type < NV_50) {
- NV_INFO(dev, "%s - nSource:", id);
- nouveau_print_bitfield_names(nsource, nsource_names);
- printk(", nStatus:");
- if (dev_priv->card_type < NV_10)
- nouveau_print_bitfield_names(nstatus, nstatus_names);
- else
- nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
- printk("\n");
- }
-
- NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
- "Data 0x%08x:0x%08x\n",
- id, trap->channel, trap->subc,
- trap->class, trap->mthd,
- trap->data2, trap->data);
-}
-
-static int
-nouveau_pgraph_intr_swmthd(struct drm_device *dev,
- struct nouveau_pgraph_trap *trap)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (trap->channel < 0 ||
- trap->channel >= dev_priv->engine.fifo.channels ||
- !dev_priv->fifos[trap->channel])
- return -ENODEV;
-
- return nouveau_call_method(dev_priv->fifos[trap->channel],
- trap->class, trap->mthd, trap->data);
-}
-
-static inline void
-nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource)
-{
- struct nouveau_pgraph_trap trap;
- int unhandled = 0;
+ stat = nv_rd32(dev, NV03_PMC_INTR_0);
+ if (!stat)
+ return IRQ_NONE;
- nouveau_graph_trap_info(dev, &trap);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ for (i = 0; i < 32 && stat; i++) {
+ if (!(stat & (1 << i)) || !dev_priv->irq_handler[i])
+ continue;
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- if (nouveau_pgraph_intr_swmthd(dev, &trap))
- unhandled = 1;
- } else {
- unhandled = 1;
+ dev_priv->irq_handler[i](dev);
+ stat &= ~(1 << i);
}
- if (unhandled)
- nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
-}
-
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-static int nouveau_ratelimit(void)
-{
- return __ratelimit(&nouveau_ratelimit_state);
-}
-
-
-static inline void
-nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
-{
- struct nouveau_pgraph_trap trap;
- int unhandled = 0;
-
- nouveau_graph_trap_info(dev, &trap);
- trap.nsource = nsource;
-
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- if (nouveau_pgraph_intr_swmthd(dev, &trap))
- unhandled = 1;
- } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
- uint32_t v = nv_rd32(dev, 0x402000);
- nv_wr32(dev, 0x402000, v);
-
- /* dump the error anyway for now: it's useful for
- Gallium development */
- unhandled = 1;
- } else {
- unhandled = 1;
- }
+ if (dev_priv->msi_enabled)
+ nv_wr08(dev, 0x00088068, 0xff);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- if (unhandled && nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap);
+ if (stat && nouveau_ratelimit())
+ NV_ERROR(dev, "PMC - unhandled INTR 0x%08x\n", stat);
+ return IRQ_HANDLED;
}
-static inline void
-nouveau_pgraph_intr_context_switch(struct drm_device *dev)
+int
+nouveau_irq_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
- uint32_t chid;
-
- chid = engine->fifo.channel_id(dev);
- NV_DEBUG(dev, "PGRAPH context switch interrupt channel %x\n", chid);
-
- switch (dev_priv->card_type) {
- case NV_04:
- nv04_graph_context_switch(dev);
- break;
- case NV_10:
- nv10_graph_context_switch(dev);
- break;
- default:
- NV_ERROR(dev, "Context switch not implemented\n");
- break;
- }
-}
-
-static void
-nouveau_pgraph_irq_handler(struct drm_device *dev)
-{
- uint32_t status;
-
- while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
- uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-
- if (status & NV_PGRAPH_INTR_NOTIFY) {
- nouveau_pgraph_intr_notify(dev, nsource);
-
- status &= ~NV_PGRAPH_INTR_NOTIFY;
- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
- }
-
- if (status & NV_PGRAPH_INTR_ERROR) {
- nouveau_pgraph_intr_error(dev, nsource);
+ int ret;
- status &= ~NV_PGRAPH_INTR_ERROR;
- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
+ if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) {
+ ret = pci_enable_msi(dev->pdev);
+ if (ret == 0) {
+ NV_INFO(dev, "enabled MSI\n");
+ dev_priv->msi_enabled = true;
}
-
- if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- nv_wr32(dev, NV03_PGRAPH_INTR,
- NV_PGRAPH_INTR_CONTEXT_SWITCH);
-
- nouveau_pgraph_intr_context_switch(dev);
- }
-
- if (status) {
- NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status);
- nv_wr32(dev, NV03_PGRAPH_INTR, status);
- }
-
- if ((nv_rd32(dev, NV04_PGRAPH_FIFO) & (1 << 0)) == 0)
- nv_wr32(dev, NV04_PGRAPH_FIFO, 1);
}
- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
-}
-
-static struct nouveau_enum_names nv50_mp_exec_error_names[] =
-{
- { 3, "STACK_UNDERFLOW" },
- { 4, "QUADON_ACTIVE" },
- { 8, "TIMEOUT" },
- { 0x10, "INVALID_OPCODE" },
- { 0x40, "BREAKPOINT" },
-};
-
-static void
-nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t units = nv_rd32(dev, 0x1540);
- uint32_t addr, mp10, status, pc, oplow, ophigh;
- int i;
- int mps = 0;
- for (i = 0; i < 4; i++) {
- if (!(units & 1 << (i+24)))
- continue;
- if (dev_priv->chipset < 0xa0)
- addr = 0x408200 + (tpid << 12) + (i << 7);
- else
- addr = 0x408100 + (tpid << 11) + (i << 7);
- mp10 = nv_rd32(dev, addr + 0x10);
- status = nv_rd32(dev, addr + 0x14);
- if (!status)
- continue;
- if (display) {
- nv_rd32(dev, addr + 0x20);
- pc = nv_rd32(dev, addr + 0x24);
- oplow = nv_rd32(dev, addr + 0x70);
- ophigh= nv_rd32(dev, addr + 0x74);
- NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
- "TP %d MP %d: ", tpid, i);
- nouveau_print_enum_names(status,
- nv50_mp_exec_error_names);
- printk(" at %06x warp %d, opcode %08x %08x\n",
- pc&0xffffff, pc >> 24,
- oplow, ophigh);
- }
- nv_wr32(dev, addr + 0x10, mp10);
- nv_wr32(dev, addr + 0x14, 0);
- mps++;
- }
- if (!mps && display)
- NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
- "No MPs claiming errors?\n", tpid);
+ return drm_irq_install(dev);
}
-static void
-nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
- uint32_t ustatus_new, int display, const char *name)
+void
+nouveau_irq_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int tps = 0;
- uint32_t units = nv_rd32(dev, 0x1540);
- int i, r;
- uint32_t ustatus_addr, ustatus;
- for (i = 0; i < 16; i++) {
- if (!(units & (1 << i)))
- continue;
- if (dev_priv->chipset < 0xa0)
- ustatus_addr = ustatus_old + (i << 12);
- else
- ustatus_addr = ustatus_new + (i << 11);
- ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
- if (!ustatus)
- continue;
- tps++;
- switch (type) {
- case 6: /* texture error... unknown for now */
- nv50_fb_vm_trap(dev, display, name);
- if (display) {
- NV_ERROR(dev, "magic set %d:\n", i);
- for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
- nv_rd32(dev, r));
- }
- break;
- case 7: /* MP error */
- if (ustatus & 0x00010000) {
- nv50_pgraph_mp_trap(dev, i, display);
- ustatus &= ~0x00010000;
- }
- break;
- case 8: /* TPDMA error */
- {
- uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
- uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
- uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
- uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
- uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
- uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
- uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
- nv50_fb_vm_trap(dev, display, name);
- /* 2d engine destination */
- if (ustatus & 0x00000010) {
- if (display) {
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
- i, e14, e10);
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
- i, e0c, e18, e1c, e20, e24);
- }
- ustatus &= ~0x00000010;
- }
- /* Render target */
- if (ustatus & 0x00000040) {
- if (display) {
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
- i, e14, e10);
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
- i, e0c, e18, e1c, e20, e24);
- }
- ustatus &= ~0x00000040;
- }
- /* CUDA memory: l[], g[] or stack. */
- if (ustatus & 0x00000080) {
- if (display) {
- if (e18 & 0x80000000) {
- /* g[] read fault? */
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
- i, e14, e10 | ((e18 >> 24) & 0x1f));
- e18 &= ~0x1f000000;
- } else if (e18 & 0xc) {
- /* g[] write fault? */
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
- i, e14, e10 | ((e18 >> 7) & 0x1f));
- e18 &= ~0x00000f80;
- } else {
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
- i, e14, e10);
- }
- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
- i, e0c, e18, e1c, e20, e24);
- }
- ustatus &= ~0x00000080;
- }
- }
- break;
- }
- if (ustatus) {
- if (display)
- NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
- }
- nv_wr32(dev, ustatus_addr, 0xc0000000);
- }
-
- if (!tps && display)
- NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
-}
-
-static void
-nv50_pgraph_trap_handler(struct drm_device *dev)
-{
- struct nouveau_pgraph_trap trap;
- uint32_t status = nv_rd32(dev, 0x400108);
- uint32_t ustatus;
- int display = nouveau_ratelimit();
-
-
- if (!status && display) {
- nouveau_graph_trap_info(dev, &trap);
- nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap);
- NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n");
- }
-
- /* DISPATCH: Relays commands to other units and handles NOTIFY,
- * COND, QUERY. If you get a trap from it, the command is still stuck
- * in DISPATCH and you need to do something about it. */
- if (status & 0x001) {
- ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
- if (!ustatus && display) {
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
- }
-
- /* Known to be triggered by screwed up NOTIFY and COND... */
- if (ustatus & 0x00000001) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
- nv_wr32(dev, 0x400500, 0);
- if (nv_rd32(dev, 0x400808) & 0x80000000) {
- if (display) {
- if (nouveau_graph_trapped_channel(dev, &trap.channel))
- trap.channel = -1;
- trap.class = nv_rd32(dev, 0x400814);
- trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc;
- trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7;
- trap.data = nv_rd32(dev, 0x40080c);
- trap.data2 = nv_rd32(dev, 0x400810);
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_TRAP_DISPATCH_FAULT", &trap);
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808));
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848));
- }
- nv_wr32(dev, 0x400808, 0);
- } else if (display) {
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n");
- }
- nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
- nv_wr32(dev, 0x400848, 0);
- ustatus &= ~0x00000001;
- }
- if (ustatus & 0x00000002) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
- nv_wr32(dev, 0x400500, 0);
- if (nv_rd32(dev, 0x40084c) & 0x80000000) {
- if (display) {
- if (nouveau_graph_trapped_channel(dev, &trap.channel))
- trap.channel = -1;
- trap.class = nv_rd32(dev, 0x400814);
- trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc;
- trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7;
- trap.data = nv_rd32(dev, 0x40085c);
- trap.data2 = 0;
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_TRAP_DISPATCH_QUERY", &trap);
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c));
- }
- nv_wr32(dev, 0x40084c, 0);
- } else if (display) {
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n");
- }
- ustatus &= ~0x00000002;
- }
- if (ustatus && display)
- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus);
- nv_wr32(dev, 0x400804, 0xc0000000);
- nv_wr32(dev, 0x400108, 0x001);
- status &= ~0x001;
- }
-
- /* TRAPs other than dispatch use the "normal" trap regs. */
- if (status && display) {
- nouveau_graph_trap_info(dev, &trap);
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_TRAP", &trap);
- }
-
- /* M2MF: Memory to memory copy engine. */
- if (status & 0x002) {
- ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
- if (!ustatus && display) {
- NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
- }
- if (ustatus & 0x00000001) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
- ustatus &= ~0x00000001;
- }
- if (ustatus & 0x00000002) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
- ustatus &= ~0x00000002;
- }
- if (ustatus & 0x00000004) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
- ustatus &= ~0x00000004;
- }
- NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
- nv_rd32(dev, 0x406804),
- nv_rd32(dev, 0x406808),
- nv_rd32(dev, 0x40680c),
- nv_rd32(dev, 0x406810));
- if (ustatus && display)
- NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus);
- /* No sane way found yet -- just reset the bugger. */
- nv_wr32(dev, 0x400040, 2);
- nv_wr32(dev, 0x400040, 0);
- nv_wr32(dev, 0x406800, 0xc0000000);
- nv_wr32(dev, 0x400108, 0x002);
- status &= ~0x002;
- }
-
- /* VFETCH: Fetches data from vertex buffers. */
- if (status & 0x004) {
- ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
- if (!ustatus && display) {
- NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
- }
- if (ustatus & 0x00000001) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
- NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
- nv_rd32(dev, 0x400c00),
- nv_rd32(dev, 0x400c08),
- nv_rd32(dev, 0x400c0c),
- nv_rd32(dev, 0x400c10));
- ustatus &= ~0x00000001;
- }
- if (ustatus && display)
- NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus);
- nv_wr32(dev, 0x400c04, 0xc0000000);
- nv_wr32(dev, 0x400108, 0x004);
- status &= ~0x004;
- }
-
- /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
- if (status & 0x008) {
- ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
- if (!ustatus && display) {
- NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
- }
- if (ustatus & 0x00000001) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
- NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
- nv_rd32(dev, 0x401804),
- nv_rd32(dev, 0x401808),
- nv_rd32(dev, 0x40180c),
- nv_rd32(dev, 0x401810));
- ustatus &= ~0x00000001;
- }
- if (ustatus && display)
- NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus);
- /* No sane way found yet -- just reset the bugger. */
- nv_wr32(dev, 0x400040, 0x80);
- nv_wr32(dev, 0x400040, 0);
- nv_wr32(dev, 0x401800, 0xc0000000);
- nv_wr32(dev, 0x400108, 0x008);
- status &= ~0x008;
- }
-
- /* CCACHE: Handles code and c[] caches and fills them. */
- if (status & 0x010) {
- ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
- if (!ustatus && display) {
- NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
- }
- if (ustatus & 0x00000001) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
- NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
- nv_rd32(dev, 0x405800),
- nv_rd32(dev, 0x405804),
- nv_rd32(dev, 0x405808),
- nv_rd32(dev, 0x40580c),
- nv_rd32(dev, 0x405810),
- nv_rd32(dev, 0x405814),
- nv_rd32(dev, 0x40581c));
- ustatus &= ~0x00000001;
- }
- if (ustatus && display)
- NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus);
- nv_wr32(dev, 0x405018, 0xc0000000);
- nv_wr32(dev, 0x400108, 0x010);
- status &= ~0x010;
- }
-
- /* Unknown, not seen yet... 0x402000 is the only trap status reg
- * remaining, so try to handle it anyway. Perhaps related to that
- * unknown DMA slot on tesla? */
- if (status & 0x20) {
- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
- ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
- if (display)
- NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
- nv_wr32(dev, 0x402000, 0xc0000000);
- /* no status modifiction on purpose */
- }
-
- /* TEXTURE: CUDA texturing units */
- if (status & 0x040) {
- nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display,
- "PGRAPH_TRAP_TEXTURE");
- nv_wr32(dev, 0x400108, 0x040);
- status &= ~0x040;
- }
-
- /* MP: CUDA execution engines. */
- if (status & 0x080) {
- nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display,
- "PGRAPH_TRAP_MP");
- nv_wr32(dev, 0x400108, 0x080);
- status &= ~0x080;
- }
-
- /* TPDMA: Handles TP-initiated uncached memory accesses:
- * l[], g[], stack, 2d surfaces, render targets. */
- if (status & 0x100) {
- nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display,
- "PGRAPH_TRAP_TPDMA");
- nv_wr32(dev, 0x400108, 0x100);
- status &= ~0x100;
- }
-
- if (status) {
- if (display)
- NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n",
- status);
- nv_wr32(dev, 0x400108, status);
- }
-}
-
-/* There must be a *lot* of these. Will take some time to gather them up. */
-static struct nouveau_enum_names nv50_data_error_names[] =
-{
- { 4, "INVALID_VALUE" },
- { 5, "INVALID_ENUM" },
- { 8, "INVALID_OBJECT" },
- { 0xc, "INVALID_BITFIELD" },
- { 0x28, "MP_NO_REG_SPACE" },
- { 0x2b, "MP_BLOCK_SIZE_MISMATCH" },
-};
-
-static void
-nv50_pgraph_irq_handler(struct drm_device *dev)
-{
- struct nouveau_pgraph_trap trap;
- int unhandled = 0;
- uint32_t status;
-
- while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
- /* NOTIFY: You've set a NOTIFY an a command and it's done. */
- if (status & 0x00000001) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_NOTIFY", &trap);
- status &= ~0x00000001;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
- }
-
- /* COMPUTE_QUERY: Purpose and exact cause unknown, happens
- * when you write 0x200 to 0x50c0 method 0x31c. */
- if (status & 0x00000002) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_COMPUTE_QUERY", &trap);
- status &= ~0x00000002;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002);
- }
-
- /* Unknown, never seen: 0x4 */
-
- /* ILLEGAL_MTHD: You used a wrong method for this class. */
- if (status & 0x00000010) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_pgraph_intr_swmthd(dev, &trap))
- unhandled = 1;
- if (unhandled && nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_ILLEGAL_MTHD", &trap);
- status &= ~0x00000010;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
- }
-
- /* ILLEGAL_CLASS: You used a wrong class. */
- if (status & 0x00000020) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_ILLEGAL_CLASS", &trap);
- status &= ~0x00000020;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020);
- }
-
- /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */
- if (status & 0x00000040) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_DOUBLE_NOTIFY", &trap);
- status &= ~0x00000040;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040);
- }
-
- /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */
- if (status & 0x00001000) {
- nv_wr32(dev, 0x400500, 0x00000000);
- nv_wr32(dev, NV03_PGRAPH_INTR,
- NV_PGRAPH_INTR_CONTEXT_SWITCH);
- nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
- NV40_PGRAPH_INTR_EN) &
- ~NV_PGRAPH_INTR_CONTEXT_SWITCH);
- nv_wr32(dev, 0x400500, 0x00010001);
-
- nv50_graph_context_switch(dev);
-
- status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- }
-
- /* BUFFER_NOTIFY: Your m2mf transfer finished */
- if (status & 0x00010000) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_BUFFER_NOTIFY", &trap);
- status &= ~0x00010000;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000);
- }
-
- /* DATA_ERROR: Invalid value for this method, or invalid
- * state in current PGRAPH context for this operation */
- if (status & 0x00100000) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit()) {
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_DATA_ERROR", &trap);
- NV_INFO (dev, "PGRAPH_DATA_ERROR - ");
- nouveau_print_enum_names(nv_rd32(dev, 0x400110),
- nv50_data_error_names);
- printk("\n");
- }
- status &= ~0x00100000;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
- }
- /* TRAP: Something bad happened in the middle of command
- * execution. Has a billion types, subtypes, and even
- * subsubtypes. */
- if (status & 0x00200000) {
- nv50_pgraph_trap_handler(dev);
- status &= ~0x00200000;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
- }
-
- /* Unknown, never seen: 0x00400000 */
-
- /* SINGLE_STEP: Happens on every method if you turned on
- * single stepping in 40008c */
- if (status & 0x01000000) {
- nouveau_graph_trap_info(dev, &trap);
- if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_SINGLE_STEP", &trap);
- status &= ~0x01000000;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000);
- }
-
- /* 0x02000000 happens when you pause a ctxprog...
- * but the only way this can happen that I know is by
- * poking the relevant MMIO register, and we don't
- * do that. */
-
- if (status) {
- NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n",
- status);
- nv_wr32(dev, NV03_PGRAPH_INTR, status);
- }
-
- {
- const int isb = (1 << 16) | (1 << 0);
-
- if ((nv_rd32(dev, 0x400500) & isb) != isb)
- nv_wr32(dev, 0x400500,
- nv_rd32(dev, 0x400500) | isb);
- }
- }
-
- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
- if (nv_rd32(dev, 0x400824) & (1 << 31))
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+ drm_irq_uninstall(dev);
+ if (dev_priv->msi_enabled)
+ pci_disable_msi(dev->pdev);
}
-static void
-nouveau_crtc_irq_handler(struct drm_device *dev, int crtc)
+void
+nouveau_irq_register(struct drm_device *dev, int status_bit,
+ void (*handler)(struct drm_device *))
{
- if (crtc & 1)
- nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
- if (crtc & 2)
- nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ dev_priv->irq_handler[status_bit] = handler;
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
-irqreturn_t
-nouveau_irq_handler(DRM_IRQ_ARGS)
+void
+nouveau_irq_unregister(struct drm_device *dev, int status_bit)
{
- struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t status;
unsigned long flags;
- status = nv_rd32(dev, NV03_PMC_INTR_0);
- if (!status)
- return IRQ_NONE;
-
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-
- if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
- nouveau_fifo_irq_handler(dev);
- status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
- }
-
- if (status & NV_PMC_INTR_0_PGRAPH_PENDING) {
- if (dev_priv->card_type >= NV_50)
- nv50_pgraph_irq_handler(dev);
- else
- nouveau_pgraph_irq_handler(dev);
-
- status &= ~NV_PMC_INTR_0_PGRAPH_PENDING;
- }
-
- if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
- nouveau_crtc_irq_handler(dev, (status>>24)&3);
- status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
- }
-
- if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
- NV_PMC_INTR_0_NV50_I2C_PENDING)) {
- nv50_display_irq_handler(dev);
- status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
- NV_PMC_INTR_0_NV50_I2C_PENDING);
- }
-
- if (status)
- NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
-
+ dev_priv->irq_handler[status_bit] = NULL;
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
- return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index a163c7c612e7..26347b7cd872 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -33,188 +33,115 @@
#include "drmP.h"
#include "drm.h"
#include "drm_sarea.h"
-#include "nouveau_drv.h"
-#define MIN(a,b) a < b ? a : b
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+#include "nouveau_mm.h"
+#include "nouveau_vm.h"
/*
* NV10-NV40 tiling helpers
*/
static void
-nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv10_mem_update_tile_region(struct drm_device *dev,
+ struct nouveau_tile_reg *tile, uint32_t addr,
+ uint32_t size, uint32_t pitch, uint32_t flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+ int i = tile - dev_priv->tile.reg;
+ unsigned long save;
+
+ nouveau_fence_unref(&tile->fence);
- tile->addr = addr;
- tile->size = size;
- tile->used = !!pitch;
- nouveau_fence_unref((void **)&tile->fence);
+ if (tile->pitch)
+ pfb->free_tile_region(dev, i);
+ if (pitch)
+ pfb->init_tile_region(dev, i, addr, size, pitch, flags);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, save);
pfifo->reassign(dev, false);
pfifo->cache_pull(dev, false);
nouveau_wait_for_idle(dev);
- pgraph->set_region_tiling(dev, i, addr, size, pitch);
- pfb->set_region_tiling(dev, i, addr, size, pitch);
+ pfb->set_tile_region(dev, i);
+ pgraph->set_tile_region(dev, i);
pfifo->cache_pull(dev, true);
pfifo->reassign(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, save);
}
-struct nouveau_tile_reg *
-nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
- uint32_t pitch)
+static struct nouveau_tile_reg *
+nv10_mem_get_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_tile_reg *found = NULL;
- unsigned long i, flags;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-
- for (i = 0; i < pfb->num_tiles; i++) {
- struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- if (tile->used)
- /* Tile region in use. */
- continue;
-
- if (tile->fence &&
- !nouveau_fence_signalled(tile->fence, NULL))
- /* Pending tile region. */
- continue;
-
- if (max(tile->addr, addr) <
- min(tile->addr + tile->size, addr + size))
- /* Kill an intersecting tile region. */
- nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
-
- if (pitch && !found) {
- /* Free tile region. */
- nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
- found = tile;
- }
- }
+ spin_lock(&dev_priv->tile.lock);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ if (!tile->used &&
+ (!tile->fence || nouveau_fence_signalled(tile->fence)))
+ tile->used = true;
+ else
+ tile = NULL;
- return found;
+ spin_unlock(&dev_priv->tile.lock);
+ return tile;
}
void
-nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile,
- struct nouveau_fence *fence)
-{
- if (fence) {
- /* Mark it as pending. */
- tile->fence = fence;
- nouveau_fence_ref(fence);
- }
-
- tile->used = false;
-}
-
-/*
- * NV50 VM helpers
- */
-int
-nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
- uint32_t flags, uint64_t phys)
+nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile,
+ struct nouveau_fence *fence)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *pgt;
- unsigned block;
- int i;
- virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1;
- size = (size >> 16) << 1;
-
- phys |= ((uint64_t)flags << 32);
- phys |= 1;
- if (dev_priv->vram_sys_base) {
- phys += dev_priv->vram_sys_base;
- phys |= 0x30;
- }
-
- while (size) {
- unsigned offset_h = upper_32_bits(phys);
- unsigned offset_l = lower_32_bits(phys);
- unsigned pte, end;
-
- for (i = 7; i >= 0; i--) {
- block = 1 << (i + 1);
- if (size >= block && !(virt & (block - 1)))
- break;
+ if (tile) {
+ spin_lock(&dev_priv->tile.lock);
+ if (fence) {
+ /* Mark it as pending. */
+ tile->fence = fence;
+ nouveau_fence_ref(fence);
}
- offset_l |= (i << 7);
-
- phys += block << 15;
- size -= block;
-
- while (block) {
- pgt = dev_priv->vm_vram_pt[virt >> 14];
- pte = virt & 0x3ffe;
-
- end = pte + block;
- if (end > 16384)
- end = 16384;
- block -= (end - pte);
- virt += (end - pte);
-
- while (pte < end) {
- nv_wo32(pgt, (pte * 4) + 0, offset_l);
- nv_wo32(pgt, (pte * 4) + 4, offset_h);
- pte += 2;
- }
- }
- }
- dev_priv->engine.instmem.flush(dev);
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
- nv50_vm_flush(dev, 4);
- nv50_vm_flush(dev, 6);
- return 0;
+ tile->used = false;
+ spin_unlock(&dev_priv->tile.lock);
+ }
}
-void
-nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
+struct nouveau_tile_reg *
+nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *pgt;
- unsigned pages, pte, end;
-
- virt -= dev_priv->vm_vram_base;
- pages = (size >> 16) << 1;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ struct nouveau_tile_reg *tile, *found = NULL;
+ int i;
- while (pages) {
- pgt = dev_priv->vm_vram_pt[virt >> 29];
- pte = (virt & 0x1ffe0000ULL) >> 15;
+ for (i = 0; i < pfb->num_tiles; i++) {
+ tile = nv10_mem_get_tile_region(dev, i);
- end = pte + pages;
- if (end > 16384)
- end = 16384;
- pages -= (end - pte);
- virt += (end - pte) << 15;
+ if (pitch && !found) {
+ found = tile;
+ continue;
- while (pte < end) {
- nv_wo32(pgt, (pte * 4), 0);
- pte++;
+ } else if (tile && tile->pitch) {
+ /* Kill an unused tile region. */
+ nv10_mem_update_tile_region(dev, tile, 0, 0, 0, 0);
}
+
+ nv10_mem_put_tile_region(dev, tile, NULL);
}
- dev_priv->engine.instmem.flush(dev);
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
- nv50_vm_flush(dev, 4);
- nv50_vm_flush(dev, 6);
+ if (found)
+ nv10_mem_update_tile_region(dev, found, addr, size,
+ pitch, flags);
+ return found;
}
/*
@@ -314,62 +241,7 @@ nouveau_mem_detect_nforce(struct drm_device *dev)
return 0;
}
-static void
-nv50_vram_preinit(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i, parts, colbits, rowbitsa, rowbitsb, banks;
- u64 rowsize, predicted;
- u32 r0, r4, rt, ru;
-
- r0 = nv_rd32(dev, 0x100200);
- r4 = nv_rd32(dev, 0x100204);
- rt = nv_rd32(dev, 0x100250);
- ru = nv_rd32(dev, 0x001540);
- NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
- for (i = 0, parts = 0; i < 8; i++) {
- if (ru & (0x00010000 << i))
- parts++;
- }
-
- colbits = (r4 & 0x0000f000) >> 12;
- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
- banks = ((r4 & 0x01000000) ? 8 : 4);
-
- rowsize = parts * banks * (1 << colbits) * 8;
- predicted = rowsize << rowbitsa;
- if (r0 & 0x00000004)
- predicted += rowsize << rowbitsb;
-
- if (predicted != dev_priv->vram_size) {
- NV_WARN(dev, "memory controller reports %dMiB VRAM\n",
- (u32)(dev_priv->vram_size >> 20));
- NV_WARN(dev, "we calculated %dMiB VRAM\n",
- (u32)(predicted >> 20));
- }
-
- dev_priv->vram_rblock_size = rowsize >> 12;
- if (rt & 1)
- dev_priv->vram_rblock_size *= 3;
-
- NV_DEBUG(dev, "rblock %lld bytes\n",
- (u64)dev_priv->vram_rblock_size << 12);
-}
-
-static void
-nvaa_vram_preinit(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- /* To our knowledge, there's no large scale reordering of pages
- * that occurs on IGP chipsets.
- */
- dev_priv->vram_rblock_size = 1;
-}
-
-static int
+int
nouveau_mem_detect(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -383,33 +255,6 @@ nouveau_mem_detect(struct drm_device *dev)
if (dev_priv->card_type < NV_50) {
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
- } else
- if (dev_priv->card_type < NV_C0) {
- dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
- dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
- dev_priv->vram_size &= 0xffffffff00ll;
-
- switch (dev_priv->chipset) {
- case 0xaa:
- case 0xac:
- case 0xaf:
- dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
- dev_priv->vram_sys_base <<= 12;
- nvaa_vram_preinit(dev);
- break;
- default:
- nv50_vram_preinit(dev);
- break;
- }
- } else {
- dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20;
- dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
- }
-
- NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
- if (dev_priv->vram_sys_base) {
- NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
- dev_priv->vram_sys_base);
}
if (dev_priv->vram_size)
@@ -417,6 +262,15 @@ nouveau_mem_detect(struct drm_device *dev)
return -ENOMEM;
}
+bool
+nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags)
+{
+ if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))
+ return true;
+
+ return false;
+}
+
#if __OS_HAS_AGP
static unsigned long
get_agp_mode(struct drm_device *dev, unsigned long mode)
@@ -549,10 +403,6 @@ nouveau_mem_vram_init(struct drm_device *dev)
if (ret)
return ret;
- ret = nouveau_mem_detect(dev);
- if (ret)
- return ret;
-
dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
ret = nouveau_ttm_global_init(dev_priv);
@@ -568,13 +418,6 @@ nouveau_mem_vram_init(struct drm_device *dev)
return ret;
}
- dev_priv->fb_available_size = dev_priv->vram_size;
- dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
- if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
- dev_priv->fb_mappable_pages =
- pci_resource_len(dev->pdev, 1);
- dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
-
/* reserve space at end of VRAM for PRAMIN */
if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 ||
dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b)
@@ -585,6 +428,22 @@ nouveau_mem_vram_init(struct drm_device *dev)
else
dev_priv->ramin_rsvd_vram = (512 * 1024);
+ ret = dev_priv->engine.vram.init(dev);
+ if (ret)
+ return ret;
+
+ NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
+ if (dev_priv->vram_sys_base) {
+ NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
+ dev_priv->vram_sys_base);
+ }
+
+ dev_priv->fb_available_size = dev_priv->vram_size;
+ dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
+ if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
+ dev_priv->fb_mappable_pages = pci_resource_len(dev->pdev, 1);
+ dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
+
dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
dev_priv->fb_aper_free = dev_priv->fb_available_size;
@@ -653,6 +512,7 @@ nouveau_mem_gart_init(struct drm_device *dev)
void
nouveau_mem_timing_init(struct drm_device *dev)
{
+ /* cards < NVC0 only */
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
@@ -719,14 +579,14 @@ nouveau_mem_timing_init(struct drm_device *dev)
tUNK_19 = 1;
tUNK_20 = 0;
tUNK_21 = 0;
- switch (MIN(recordlen,21)) {
- case 21:
+ switch (min(recordlen, 22)) {
+ case 22:
tUNK_21 = entry[21];
- case 20:
+ case 21:
tUNK_20 = entry[20];
- case 19:
+ case 20:
tUNK_19 = entry[19];
- case 18:
+ case 19:
tUNK_18 = entry[18];
default:
tUNK_0 = entry[0];
@@ -756,24 +616,30 @@ nouveau_mem_timing_init(struct drm_device *dev)
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
if(recordlen > 19) {
timing->reg_100228 += (tUNK_19 - 1) << 24;
- } else {
+ }/* I cannot back-up this else-statement right now
+ else {
timing->reg_100228 += tUNK_12 << 24;
- }
+ }*/
/* XXX: reg_10022c */
+ timing->reg_10022c = tUNK_2 - 1;
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
tUNK_13 << 8 | tUNK_13);
/* XXX: +6? */
timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
- if(tUNK_10 > tUNK_11) {
- timing->reg_100234 += tUNK_10 << 16;
- } else {
- timing->reg_100234 += tUNK_11 << 16;
+ timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+
+ /* XXX; reg_100238, reg_10023c
+ * reg: 0x00??????
+ * reg_10023c:
+ * 0 for pre-NV50 cards
+ * 0x????0202 for NV50+ cards (empirical evidence) */
+ if(dev_priv->card_type >= NV_50) {
+ timing->reg_10023c = 0x202;
}
- /* XXX; reg_100238, reg_10023c */
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
timing->reg_100220, timing->reg_100224,
timing->reg_100228, timing->reg_10022c);
@@ -794,3 +660,112 @@ nouveau_mem_timing_fini(struct drm_device *dev)
kfree(mem->timing);
}
+
+static int
+nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
+ struct nouveau_mm *mm;
+ u32 b_size;
+ int ret;
+
+ p_size = (p_size << PAGE_SHIFT) >> 12;
+ b_size = dev_priv->vram_rblock_size >> 12;
+
+ ret = nouveau_mm_init(&mm, 0, p_size, b_size);
+ if (ret)
+ return ret;
+
+ man->priv = mm;
+ return 0;
+}
+
+static int
+nouveau_vram_manager_fini(struct ttm_mem_type_manager *man)
+{
+ struct nouveau_mm *mm = man->priv;
+ int ret;
+
+ ret = nouveau_mm_fini(&mm);
+ if (ret)
+ return ret;
+
+ man->priv = NULL;
+ return 0;
+}
+
+static void
+nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
+ struct ttm_mem_reg *mem)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
+ struct drm_device *dev = dev_priv->dev;
+
+ vram->put(dev, (struct nouveau_vram **)&mem->mm_node);
+}
+
+static int
+nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
+ struct ttm_buffer_object *bo,
+ struct ttm_placement *placement,
+ struct ttm_mem_reg *mem)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
+ struct drm_device *dev = dev_priv->dev;
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+ struct nouveau_vram *node;
+ u32 size_nc = 0;
+ int ret;
+
+ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
+ size_nc = 1 << nvbo->vma.node->type;
+
+ ret = vram->get(dev, mem->num_pages << PAGE_SHIFT,
+ mem->page_alignment << PAGE_SHIFT, size_nc,
+ (nvbo->tile_flags >> 8) & 0xff, &node);
+ if (ret)
+ return ret;
+
+ node->page_shift = 12;
+ if (nvbo->vma.node)
+ node->page_shift = nvbo->vma.node->type;
+
+ mem->mm_node = node;
+ mem->start = node->offset >> PAGE_SHIFT;
+ return 0;
+}
+
+void
+nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
+{
+ struct nouveau_mm *mm = man->priv;
+ struct nouveau_mm_node *r;
+ u32 total = 0, free = 0;
+
+ mutex_lock(&mm->mutex);
+ list_for_each_entry(r, &mm->nodes, nl_entry) {
+ printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n",
+ prefix, r->type, ((u64)r->offset << 12),
+ (((u64)r->offset + r->length) << 12));
+
+ total += r->length;
+ if (!r->type)
+ free += r->length;
+ }
+ mutex_unlock(&mm->mutex);
+
+ printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n",
+ prefix, (u64)total << 12, (u64)free << 12);
+ printk(KERN_DEBUG "%s block: 0x%08x\n",
+ prefix, mm->block_size << 12);
+}
+
+const struct ttm_mem_type_manager_func nouveau_vram_manager = {
+ nouveau_vram_manager_init,
+ nouveau_vram_manager_fini,
+ nouveau_vram_manager_new,
+ nouveau_vram_manager_del,
+ nouveau_vram_manager_debug
+};
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c
new file mode 100644
index 000000000000..8844b50c3e54
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_mm.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+
+static inline void
+region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a)
+{
+ list_del(&a->nl_entry);
+ list_del(&a->fl_entry);
+ kfree(a);
+}
+
+static struct nouveau_mm_node *
+region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
+{
+ struct nouveau_mm_node *b;
+
+ if (a->length == size)
+ return a;
+
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (unlikely(b == NULL))
+ return NULL;
+
+ b->offset = a->offset;
+ b->length = size;
+ b->type = a->type;
+ a->offset += size;
+ a->length -= size;
+ list_add_tail(&b->nl_entry, &a->nl_entry);
+ if (b->type == 0)
+ list_add_tail(&b->fl_entry, &a->fl_entry);
+ return b;
+}
+
+#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \
+ list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
+
+void
+nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
+{
+ struct nouveau_mm_node *prev = node(this, prev);
+ struct nouveau_mm_node *next = node(this, next);
+
+ list_add(&this->fl_entry, &rmm->free);
+ this->type = 0;
+
+ if (prev && prev->type == 0) {
+ prev->length += this->length;
+ region_put(rmm, this);
+ this = prev;
+ }
+
+ if (next && next->type == 0) {
+ next->offset = this->offset;
+ next->length += this->length;
+ region_put(rmm, this);
+ }
+}
+
+int
+nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
+ u32 align, struct nouveau_mm_node **pnode)
+{
+ struct nouveau_mm_node *prev, *this, *next;
+ u32 min = size_nc ? size_nc : size;
+ u32 align_mask = align - 1;
+ u32 splitoff;
+ u32 s, e;
+
+ list_for_each_entry(this, &rmm->free, fl_entry) {
+ e = this->offset + this->length;
+ s = this->offset;
+
+ prev = node(this, prev);
+ if (prev && prev->type != type)
+ s = roundup(s, rmm->block_size);
+
+ next = node(this, next);
+ if (next && next->type != type)
+ e = rounddown(e, rmm->block_size);
+
+ s = (s + align_mask) & ~align_mask;
+ e &= ~align_mask;
+ if (s > e || e - s < min)
+ continue;
+
+ splitoff = s - this->offset;
+ if (splitoff && !region_split(rmm, this, splitoff))
+ return -ENOMEM;
+
+ this = region_split(rmm, this, min(size, e - s));
+ if (!this)
+ return -ENOMEM;
+
+ this->type = type;
+ list_del(&this->fl_entry);
+ *pnode = this;
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
+int
+nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block)
+{
+ struct nouveau_mm *rmm;
+ struct nouveau_mm_node *heap;
+
+ heap = kzalloc(sizeof(*heap), GFP_KERNEL);
+ if (!heap)
+ return -ENOMEM;
+ heap->offset = roundup(offset, block);
+ heap->length = rounddown(offset + length, block) - heap->offset;
+
+ rmm = kzalloc(sizeof(*rmm), GFP_KERNEL);
+ if (!rmm) {
+ kfree(heap);
+ return -ENOMEM;
+ }
+ rmm->block_size = block;
+ mutex_init(&rmm->mutex);
+ INIT_LIST_HEAD(&rmm->nodes);
+ INIT_LIST_HEAD(&rmm->free);
+ list_add(&heap->nl_entry, &rmm->nodes);
+ list_add(&heap->fl_entry, &rmm->free);
+
+ *prmm = rmm;
+ return 0;
+}
+
+int
+nouveau_mm_fini(struct nouveau_mm **prmm)
+{
+ struct nouveau_mm *rmm = *prmm;
+ struct nouveau_mm_node *heap =
+ list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry);
+
+ if (!list_is_singular(&rmm->nodes))
+ return -EBUSY;
+
+ kfree(heap);
+ kfree(rmm);
+ *prmm = NULL;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h
new file mode 100644
index 000000000000..798eaf39691c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_mm.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_REGION_H__
+#define __NOUVEAU_REGION_H__
+
+struct nouveau_mm_node {
+ struct list_head nl_entry;
+ struct list_head fl_entry;
+ struct list_head rl_entry;
+
+ u8 type;
+ u32 offset;
+ u32 length;
+};
+
+struct nouveau_mm {
+ struct list_head nodes;
+ struct list_head free;
+
+ struct mutex mutex;
+
+ u32 block_size;
+};
+
+int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block);
+int nouveau_mm_fini(struct nouveau_mm **);
+int nouveau_mm_pre(struct nouveau_mm *);
+int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc,
+ u32 align, struct nouveau_mm_node **);
+void nouveau_mm_put(struct nouveau_mm *, struct nouveau_mm_node *);
+
+int nv50_vram_init(struct drm_device *);
+int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc,
+ u32 memtype, struct nouveau_vram **);
+void nv50_vram_del(struct drm_device *, struct nouveau_vram **);
+bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags);
+
+int nvc0_vram_init(struct drm_device *);
+int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nouveau_vram **);
+bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index 2cc59f8c658b..fe29d604b820 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -99,7 +99,6 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
int size, uint32_t *b_offset)
{
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *nobj = NULL;
struct drm_mm_node *mem;
uint32_t offset;
@@ -113,31 +112,15 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
return -ENOMEM;
}
- offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
- if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) {
- target = NV_DMA_TARGET_VIDMEM;
- } else
- if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_TT) {
- if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA &&
- dev_priv->card_type < NV_50) {
- ret = nouveau_sgdma_get_page(dev, offset, &offset);
- if (ret)
- return ret;
- target = NV_DMA_TARGET_PCI;
- } else {
- target = NV_DMA_TARGET_AGP;
- if (dev_priv->card_type >= NV_50)
- offset += dev_priv->vm_gart_base;
- }
- } else {
- NV_ERROR(dev, "Bad DMA target, mem_type %d!\n",
- chan->notifier_bo->bo.mem.mem_type);
- return -EINVAL;
- }
+ if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)
+ target = NV_MEM_TARGET_VRAM;
+ else
+ target = NV_MEM_TARGET_GART;
+ offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
offset += mem->start;
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,
- mem->size, NV_DMA_ACCESS_RW, target,
+ mem->size, NV_MEM_ACCESS_RW, target,
&nobj);
if (ret) {
drm_mm_put_block(mem);
@@ -181,15 +164,20 @@ int
nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_notifierobj_alloc *na = data;
struct nouveau_channel *chan;
int ret;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
+ /* completely unnecessary for these chipsets... */
+ if (unlikely(dev_priv->card_type >= NV_C0))
+ return -EINVAL;
+
+ chan = nouveau_channel_get(dev, file_priv, na->channel);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
- if (ret)
- return ret;
-
- return 0;
+ nouveau_channel_put(&chan);
+ return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 896cf8634144..30b6544467ca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -35,6 +35,102 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_ramht.h"
+#include "nouveau_vm.h"
+
+struct nouveau_gpuobj_method {
+ struct list_head head;
+ u32 mthd;
+ int (*exec)(struct nouveau_channel *, u32 class, u32 mthd, u32 data);
+};
+
+struct nouveau_gpuobj_class {
+ struct list_head head;
+ struct list_head methods;
+ u32 id;
+ u32 engine;
+};
+
+int
+nouveau_gpuobj_class_new(struct drm_device *dev, u32 class, u32 engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj_class *oc;
+
+ oc = kzalloc(sizeof(*oc), GFP_KERNEL);
+ if (!oc)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&oc->methods);
+ oc->id = class;
+ oc->engine = engine;
+ list_add(&oc->head, &dev_priv->classes);
+ return 0;
+}
+
+int
+nouveau_gpuobj_mthd_new(struct drm_device *dev, u32 class, u32 mthd,
+ int (*exec)(struct nouveau_channel *, u32, u32, u32))
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj_method *om;
+ struct nouveau_gpuobj_class *oc;
+
+ list_for_each_entry(oc, &dev_priv->classes, head) {
+ if (oc->id == class)
+ goto found;
+ }
+
+ return -EINVAL;
+
+found:
+ om = kzalloc(sizeof(*om), GFP_KERNEL);
+ if (!om)
+ return -ENOMEM;
+
+ om->mthd = mthd;
+ om->exec = exec;
+ list_add(&om->head, &oc->methods);
+ return 0;
+}
+
+int
+nouveau_gpuobj_mthd_call(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj_method *om;
+ struct nouveau_gpuobj_class *oc;
+
+ list_for_each_entry(oc, &dev_priv->classes, head) {
+ if (oc->id != class)
+ continue;
+
+ list_for_each_entry(om, &oc->methods, head) {
+ if (om->mthd == mthd)
+ return om->exec(chan, class, mthd, data);
+ }
+ }
+
+ return -ENOENT;
+}
+
+int
+nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid,
+ u32 class, u32 mthd, u32 data)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = NULL;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ if (chid > 0 && chid < dev_priv->engine.fifo.channels)
+ chan = dev_priv->channels.ptr[chid];
+ if (chan)
+ ret = nouveau_gpuobj_mthd_call(chan, class, mthd, data);
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return ret;
+}
/* NVidia uses context objects to drive drawing operations.
@@ -73,17 +169,14 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct nouveau_gpuobj **gpuobj_ret)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
struct nouveau_gpuobj *gpuobj;
struct drm_mm_node *ramin = NULL;
- int ret;
+ int ret, i;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
chan ? chan->id : -1, size, align, flags);
- if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL)
- return -EINVAL;
-
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
return -ENOMEM;
@@ -98,88 +191,41 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
spin_unlock(&dev_priv->ramin_lock);
if (chan) {
- NV_DEBUG(dev, "channel heap\n");
-
ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
if (ramin)
ramin = drm_mm_get_block(ramin, size, align);
-
if (!ramin) {
nouveau_gpuobj_ref(NULL, &gpuobj);
return -ENOMEM;
}
- } else {
- NV_DEBUG(dev, "global heap\n");
-
- /* allocate backing pages, sets vinst */
- ret = engine->instmem.populate(dev, gpuobj, &size);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
- }
-
- /* try and get aperture space */
- do {
- if (drm_mm_pre_get(&dev_priv->ramin_heap))
- return -ENOMEM;
- spin_lock(&dev_priv->ramin_lock);
- ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
- align, 0);
- if (ramin == NULL) {
- spin_unlock(&dev_priv->ramin_lock);
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
- }
-
- ramin = drm_mm_get_block_atomic(ramin, size, align);
- spin_unlock(&dev_priv->ramin_lock);
- } while (ramin == NULL);
-
- /* on nv50 it's ok to fail, we have a fallback path */
- if (!ramin && dev_priv->card_type < NV_50) {
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return -ENOMEM;
- }
- }
+ gpuobj->pinst = chan->ramin->pinst;
+ if (gpuobj->pinst != ~0)
+ gpuobj->pinst += ramin->start;
- /* if we got a chunk of the aperture, map pages into it */
- gpuobj->im_pramin = ramin;
- if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) {
- ret = engine->instmem.bind(dev, gpuobj);
+ gpuobj->cinst = ramin->start;
+ gpuobj->vinst = ramin->start + chan->ramin->vinst;
+ gpuobj->node = ramin;
+ } else {
+ ret = instmem->get(gpuobj, size, align);
if (ret) {
nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
- }
-
- /* calculate the various different addresses for the object */
- if (chan) {
- gpuobj->pinst = chan->ramin->pinst;
- if (gpuobj->pinst != ~0)
- gpuobj->pinst += gpuobj->im_pramin->start;
- if (dev_priv->card_type < NV_50) {
- gpuobj->cinst = gpuobj->pinst;
- } else {
- gpuobj->cinst = gpuobj->im_pramin->start;
- gpuobj->vinst = gpuobj->im_pramin->start +
- chan->ramin->vinst;
- }
- } else {
- if (gpuobj->im_pramin)
- gpuobj->pinst = gpuobj->im_pramin->start;
- else
+ ret = -ENOSYS;
+ if (!(flags & NVOBJ_FLAG_DONT_MAP))
+ ret = instmem->map(gpuobj);
+ if (ret)
gpuobj->pinst = ~0;
- gpuobj->cinst = 0xdeadbeef;
+
+ gpuobj->cinst = NVOBJ_CINST_GLOBAL;
}
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
- int i;
-
for (i = 0; i < gpuobj->size; i += 4)
nv_wo32(gpuobj, i, 0);
- engine->instmem.flush(dev);
+ instmem->flush(dev);
}
@@ -195,6 +241,7 @@ nouveau_gpuobj_init(struct drm_device *dev)
NV_DEBUG(dev, "\n");
INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+ INIT_LIST_HEAD(&dev_priv->classes);
spin_lock_init(&dev_priv->ramin_lock);
dev_priv->ramin_base = ~0;
@@ -205,9 +252,20 @@ void
nouveau_gpuobj_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj_method *om, *tm;
+ struct nouveau_gpuobj_class *oc, *tc;
NV_DEBUG(dev, "\n");
+ list_for_each_entry_safe(oc, tc, &dev_priv->classes, head) {
+ list_for_each_entry_safe(om, tm, &oc->methods, head) {
+ list_del(&om->head);
+ kfree(om);
+ }
+ list_del(&oc->head);
+ kfree(oc);
+ }
+
BUG_ON(!list_empty(&dev_priv->gpuobj_list));
}
@@ -219,26 +277,34 @@ nouveau_gpuobj_del(struct kref *ref)
container_of(ref, struct nouveau_gpuobj, refcount);
struct drm_device *dev = gpuobj->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
int i;
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
- if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
+ if (gpuobj->node && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
for (i = 0; i < gpuobj->size; i += 4)
nv_wo32(gpuobj, i, 0);
- engine->instmem.flush(dev);
+ instmem->flush(dev);
}
if (gpuobj->dtor)
gpuobj->dtor(dev, gpuobj);
- if (gpuobj->im_backing)
- engine->instmem.clear(dev, gpuobj);
+ if (gpuobj->cinst == NVOBJ_CINST_GLOBAL) {
+ if (gpuobj->node) {
+ instmem->unmap(gpuobj);
+ instmem->put(gpuobj);
+ }
+ } else {
+ if (gpuobj->node) {
+ spin_lock(&dev_priv->ramin_lock);
+ drm_mm_put_block(gpuobj->node);
+ spin_unlock(&dev_priv->ramin_lock);
+ }
+ }
spin_lock(&dev_priv->ramin_lock);
- if (gpuobj->im_pramin)
- drm_mm_put_block(gpuobj->im_pramin);
list_del(&gpuobj->list);
spin_unlock(&dev_priv->ramin_lock);
@@ -278,7 +344,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
kref_init(&gpuobj->refcount);
gpuobj->size = size;
gpuobj->pinst = pinst;
- gpuobj->cinst = 0xdeadbeef;
+ gpuobj->cinst = NVOBJ_CINST_GLOBAL;
gpuobj->vinst = vinst;
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
@@ -335,113 +401,150 @@ nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
The method below creates a DMA object in instance RAM and returns a handle
to it that can be used to set up context objects.
*/
-int
-nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
- uint64_t offset, uint64_t size, int access,
- int target, struct nouveau_gpuobj **gpuobj)
+
+void
+nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class,
+ u64 base, u64 size, int target, int access,
+ u32 type, u32 comp)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
- int ret;
+ struct drm_nouveau_private *dev_priv = obj->dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ u32 flags0;
- NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
- chan->id, class, offset, size);
- NV_DEBUG(dev, "access=%d target=%d\n", access, target);
+ flags0 = (comp << 29) | (type << 22) | class;
+ flags0 |= 0x00100000;
+
+ switch (access) {
+ case NV_MEM_ACCESS_RO: flags0 |= 0x00040000; break;
+ case NV_MEM_ACCESS_RW:
+ case NV_MEM_ACCESS_WO: flags0 |= 0x00080000; break;
+ default:
+ break;
+ }
switch (target) {
- case NV_DMA_TARGET_AGP:
- offset += dev_priv->gart_info.aper_base;
+ case NV_MEM_TARGET_VRAM:
+ flags0 |= 0x00010000;
+ break;
+ case NV_MEM_TARGET_PCI:
+ flags0 |= 0x00020000;
break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ flags0 |= 0x00030000;
+ break;
+ case NV_MEM_TARGET_GART:
+ base += dev_priv->gart_info.aper_base;
default:
+ flags0 &= ~0x00100000;
break;
}
- ret = nouveau_gpuobj_new(dev, chan,
- nouveau_gpuobj_class_instmem_size(dev, class),
- 16, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, gpuobj);
- if (ret) {
- NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
- return ret;
- }
+ /* convert to base + limit */
+ size = (base + size) - 1;
- if (dev_priv->card_type < NV_50) {
- uint32_t frame, adjust, pte_flags = 0;
-
- if (access != NV_DMA_ACCESS_RO)
- pte_flags |= (1<<1);
- adjust = offset & 0x00000fff;
- frame = offset & ~0x00000fff;
-
- nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) |
- (access << 14) | (target << 16) |
- class));
- nv_wo32(*gpuobj, 4, size - 1);
- nv_wo32(*gpuobj, 8, frame | pte_flags);
- nv_wo32(*gpuobj, 12, frame | pte_flags);
- } else {
- uint64_t limit = offset + size - 1;
- uint32_t flags0, flags5;
+ nv_wo32(obj, offset + 0x00, flags0);
+ nv_wo32(obj, offset + 0x04, lower_32_bits(size));
+ nv_wo32(obj, offset + 0x08, lower_32_bits(base));
+ nv_wo32(obj, offset + 0x0c, upper_32_bits(size) << 24 |
+ upper_32_bits(base));
+ nv_wo32(obj, offset + 0x10, 0x00000000);
+ nv_wo32(obj, offset + 0x14, 0x00000000);
- if (target == NV_DMA_TARGET_VIDMEM) {
- flags0 = 0x00190000;
- flags5 = 0x00010000;
- } else {
- flags0 = 0x7fc00000;
- flags5 = 0x00080000;
- }
+ pinstmem->flush(obj->dev);
+}
- nv_wo32(*gpuobj, 0, flags0 | class);
- nv_wo32(*gpuobj, 4, lower_32_bits(limit));
- nv_wo32(*gpuobj, 8, lower_32_bits(offset));
- nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
- (upper_32_bits(offset) & 0xff));
- nv_wo32(*gpuobj, 20, flags5);
- }
+int
+nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size,
+ int target, int access, u32 type, u32 comp,
+ struct nouveau_gpuobj **pobj)
+{
+ struct drm_device *dev = chan->dev;
+ int ret;
- instmem->flush(dev);
+ ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_FREE, pobj);
+ if (ret)
+ return ret;
- (*gpuobj)->engine = NVOBJ_ENGINE_SW;
- (*gpuobj)->class = class;
+ nv50_gpuobj_dma_init(*pobj, 0, class, base, size, target,
+ access, type, comp);
return 0;
}
int
-nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
- uint64_t offset, uint64_t size, int access,
- struct nouveau_gpuobj **gpuobj,
- uint32_t *o_ret)
+nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
+ u64 size, int access, int target,
+ struct nouveau_gpuobj **pobj)
{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj;
+ u32 flags0, flags2;
int ret;
- if (dev_priv->gart_info.type == NOUVEAU_GART_AGP ||
- (dev_priv->card_type >= NV_50 &&
- dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) {
- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- offset + dev_priv->vm_gart_base,
- size, access, NV_DMA_TARGET_AGP,
- gpuobj);
- if (o_ret)
- *o_ret = 0;
- } else
- if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
- if (offset & ~0xffffffffULL) {
- NV_ERROR(dev, "obj offset exceeds 32-bits\n");
- return -EINVAL;
+ if (dev_priv->card_type >= NV_50) {
+ u32 comp = (target == NV_MEM_TARGET_VM) ? NV_MEM_COMP_VM : 0;
+ u32 type = (target == NV_MEM_TARGET_VM) ? NV_MEM_TYPE_VM : 0;
+
+ return nv50_gpuobj_dma_new(chan, class, base, size,
+ target, access, type, comp, pobj);
+ }
+
+ if (target == NV_MEM_TARGET_GART) {
+ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
+ target = NV_MEM_TARGET_PCI_NOSNOOP;
+ base += dev_priv->gart_info.aper_base;
+ } else
+ if (base != 0) {
+ base = nouveau_sgdma_get_physical(dev, base);
+ target = NV_MEM_TARGET_PCI;
+ } else {
+ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj);
+ return 0;
}
- if (o_ret)
- *o_ret = (uint32_t)offset;
- ret = (*gpuobj != NULL) ? 0 : -EINVAL;
- } else {
- NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
- return -EINVAL;
}
- return ret;
+ flags0 = class;
+ flags0 |= 0x00003000; /* PT present, PT linear */
+ flags2 = 0;
+
+ switch (target) {
+ case NV_MEM_TARGET_PCI:
+ flags0 |= 0x00020000;
+ break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ flags0 |= 0x00030000;
+ break;
+ default:
+ break;
+ }
+
+ switch (access) {
+ case NV_MEM_ACCESS_RO:
+ flags0 |= 0x00004000;
+ break;
+ case NV_MEM_ACCESS_WO:
+ flags0 |= 0x00008000;
+ default:
+ flags2 |= 0x00000002;
+ break;
+ }
+
+ flags0 |= (base & 0x00000fff) << 20;
+ flags2 |= (base & 0xfffff000);
+
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, flags0);
+ nv_wo32(obj, 0x04, size - 1);
+ nv_wo32(obj, 0x08, flags2);
+ nv_wo32(obj, 0x0c, flags2);
+
+ obj->engine = NVOBJ_ENGINE_SW;
+ obj->class = class;
+ *pobj = obj;
+ return 0;
}
/* Context objects in the instance RAM have the following structure.
@@ -495,82 +598,130 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
entry[5]:
set to 0?
*/
+static int
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
+ struct nouveau_gpuobj **gpuobj_ret)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj *gpuobj;
+
+ gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
+ if (!gpuobj)
+ return -ENOMEM;
+ gpuobj->dev = chan->dev;
+ gpuobj->engine = NVOBJ_ENGINE_SW;
+ gpuobj->class = class;
+ kref_init(&gpuobj->refcount);
+ gpuobj->cinst = 0x40;
+
+ spin_lock(&dev_priv->ramin_lock);
+ list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+ spin_unlock(&dev_priv->ramin_lock);
+ *gpuobj_ret = gpuobj;
+ return 0;
+}
+
int
-nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
- struct nouveau_gpuobj **gpuobj)
+nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj_class *oc;
+ struct nouveau_gpuobj *gpuobj;
int ret;
NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
+ list_for_each_entry(oc, &dev_priv->classes, head) {
+ if (oc->id == class)
+ goto found;
+ }
+
+ NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+ return -EINVAL;
+
+found:
+ switch (oc->engine) {
+ case NVOBJ_ENGINE_SW:
+ if (dev_priv->card_type < NV_C0) {
+ ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
+ if (ret)
+ return ret;
+ goto insert;
+ }
+ break;
+ case NVOBJ_ENGINE_GR:
+ if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
+ (dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) {
+ struct nouveau_pgraph_engine *pgraph =
+ &dev_priv->engine.graph;
+
+ ret = pgraph->create_context(chan);
+ if (ret)
+ return ret;
+ }
+ break;
+ case NVOBJ_ENGINE_CRYPT:
+ if (!chan->crypt_ctx) {
+ struct nouveau_crypt_engine *pcrypt =
+ &dev_priv->engine.crypt;
+
+ ret = pcrypt->create_context(chan);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+
+ /* we're done if this is fermi */
+ if (dev_priv->card_type >= NV_C0)
+ return 0;
+
ret = nouveau_gpuobj_new(dev, chan,
nouveau_gpuobj_class_instmem_size(dev, class),
16,
NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
- gpuobj);
+ &gpuobj);
if (ret) {
- NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
+ NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
return ret;
}
if (dev_priv->card_type >= NV_50) {
- nv_wo32(*gpuobj, 0, class);
- nv_wo32(*gpuobj, 20, 0x00010000);
+ nv_wo32(gpuobj, 0, class);
+ nv_wo32(gpuobj, 20, 0x00010000);
} else {
switch (class) {
case NV_CLASS_NULL:
- nv_wo32(*gpuobj, 0, 0x00001030);
- nv_wo32(*gpuobj, 4, 0xFFFFFFFF);
+ nv_wo32(gpuobj, 0, 0x00001030);
+ nv_wo32(gpuobj, 4, 0xFFFFFFFF);
break;
default:
if (dev_priv->card_type >= NV_40) {
- nv_wo32(*gpuobj, 0, class);
+ nv_wo32(gpuobj, 0, class);
#ifdef __BIG_ENDIAN
- nv_wo32(*gpuobj, 8, 0x01000000);
+ nv_wo32(gpuobj, 8, 0x01000000);
#endif
} else {
#ifdef __BIG_ENDIAN
- nv_wo32(*gpuobj, 0, class | 0x00080000);
+ nv_wo32(gpuobj, 0, class | 0x00080000);
#else
- nv_wo32(*gpuobj, 0, class);
+ nv_wo32(gpuobj, 0, class);
#endif
}
}
}
dev_priv->engine.instmem.flush(dev);
- (*gpuobj)->engine = NVOBJ_ENGINE_GR;
- (*gpuobj)->class = class;
- return 0;
-}
-
-int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
- struct nouveau_gpuobj **gpuobj_ret)
-{
- struct drm_nouveau_private *dev_priv;
- struct nouveau_gpuobj *gpuobj;
-
- if (!chan || !gpuobj_ret || *gpuobj_ret != NULL)
- return -EINVAL;
- dev_priv = chan->dev->dev_private;
-
- gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
- if (!gpuobj)
- return -ENOMEM;
- gpuobj->dev = chan->dev;
- gpuobj->engine = NVOBJ_ENGINE_SW;
- gpuobj->class = class;
- kref_init(&gpuobj->refcount);
- gpuobj->cinst = 0x40;
+ gpuobj->engine = oc->engine;
+ gpuobj->class = oc->id;
- spin_lock(&dev_priv->ramin_lock);
- list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
- spin_unlock(&dev_priv->ramin_lock);
- *gpuobj_ret = gpuobj;
- return 0;
+insert:
+ ret = nouveau_ramht_insert(chan, handle, gpuobj);
+ if (ret)
+ NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return ret;
}
static int
@@ -585,7 +736,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
/* Base amount for object storage (4KiB enough?) */
- size = 0x1000;
+ size = 0x2000;
base = 0;
/* PGRAPH context */
@@ -624,12 +775,30 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
struct nouveau_gpuobj *vram = NULL, *tt = NULL;
- int ret, i;
+ int ret;
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
+ if (dev_priv->card_type == NV_C0) {
+ struct nouveau_vm *vm = dev_priv->chan_vm;
+ struct nouveau_vm_pgd *vpgd;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0,
+ &chan->ramin);
+ if (ret)
+ return ret;
+
+ nouveau_vm_ref(vm, &chan->vm, NULL);
+
+ vpgd = list_first_entry(&vm->pgd_list, struct nouveau_vm_pgd, head);
+ nv_wo32(chan->ramin, 0x0200, lower_32_bits(vpgd->obj->vinst));
+ nv_wo32(chan->ramin, 0x0204, upper_32_bits(vpgd->obj->vinst));
+ nv_wo32(chan->ramin, 0x0208, 0xffffffff);
+ nv_wo32(chan->ramin, 0x020c, 0x000000ff);
+ return 0;
+ }
+
/* Allocate a chunk of memory for per-channel object storage */
ret = nouveau_gpuobj_channel_init_pramin(chan);
if (ret) {
@@ -639,14 +808,12 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
/* NV50 VM
* - Allocate per-channel page-directory
- * - Map GART and VRAM into the channel's address space at the
- * locations determined during init.
+ * - Link with shared channel VM
*/
- if (dev_priv->card_type >= NV_50) {
+ if (dev_priv->chan_vm) {
u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
u64 vm_vinst = chan->ramin->vinst + pgd_offs;
u32 vm_pinst = chan->ramin->pinst;
- u32 pde;
if (vm_pinst != ~0)
vm_pinst += pgd_offs;
@@ -655,29 +822,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
0, &chan->vm_pd);
if (ret)
return ret;
- for (i = 0; i < 0x4000; i += 8) {
- nv_wo32(chan->vm_pd, i + 0, 0x00000000);
- nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
- }
- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma,
- &chan->vm_gart_pt);
- pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
- nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3);
- nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
-
- pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i],
- &chan->vm_vram_pt[i]);
-
- nv_wo32(chan->vm_pd, pde + 0,
- chan->vm_vram_pt[i]->vinst | 0x61);
- nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
- pde += 8;
- }
-
- instmem->flush(dev);
+ nouveau_vm_ref(dev_priv->chan_vm, &chan->vm, chan->vm_pd);
}
/* RAMHT */
@@ -700,9 +846,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
/* VRAM ctxdma */
if (dev_priv->card_type >= NV_50) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- 0, dev_priv->vm_end,
- NV_DMA_ACCESS_RW,
- NV_DMA_TARGET_AGP, &vram);
+ 0, (1ULL << 40), NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VM, &vram);
if (ret) {
NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
return ret;
@@ -710,8 +855,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
} else {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->fb_available_size,
- NV_DMA_ACCESS_RW,
- NV_DMA_TARGET_VIDMEM, &vram);
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &vram);
if (ret) {
NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
return ret;
@@ -728,21 +873,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
/* TT memory ctxdma */
if (dev_priv->card_type >= NV_50) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- 0, dev_priv->vm_end,
- NV_DMA_ACCESS_RW,
- NV_DMA_TARGET_AGP, &tt);
- if (ret) {
- NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
- return ret;
- }
- } else
- if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
- ret = nouveau_gpuobj_gart_dma_new(chan, 0,
- dev_priv->gart_info.aper_size,
- NV_DMA_ACCESS_RW, &tt, NULL);
+ 0, (1ULL << 40), NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VM, &tt);
} else {
- NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
- ret = -EINVAL;
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->gart_info.aper_size,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_GART, &tt);
}
if (ret) {
@@ -763,21 +900,14 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
void
nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
- int i;
NV_DEBUG(dev, "ch%d\n", chan->id);
- if (!chan->ramht)
- return;
-
nouveau_ramht_ref(NULL, &chan->ramht, chan);
+ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
nouveau_gpuobj_ref(NULL, &chan->vm_pd);
- nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt);
- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
- nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
if (chan->ramin_heap.free_stack.next)
drm_mm_takedown(&chan->ramin_heap);
@@ -791,147 +921,91 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
struct nouveau_gpuobj *gpuobj;
int i;
- if (dev_priv->card_type < NV_50) {
- dev_priv->susres.ramin_copy = vmalloc(dev_priv->ramin_rsvd_vram);
- if (!dev_priv->susres.ramin_copy)
- return -ENOMEM;
-
- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4)
- dev_priv->susres.ramin_copy[i/4] = nv_ri32(dev, i);
- return 0;
- }
-
list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
- if (!gpuobj->im_backing)
+ if (gpuobj->cinst != NVOBJ_CINST_GLOBAL)
continue;
- gpuobj->im_backing_suspend = vmalloc(gpuobj->size);
- if (!gpuobj->im_backing_suspend) {
+ gpuobj->suspend = vmalloc(gpuobj->size);
+ if (!gpuobj->suspend) {
nouveau_gpuobj_resume(dev);
return -ENOMEM;
}
for (i = 0; i < gpuobj->size; i += 4)
- gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
+ gpuobj->suspend[i/4] = nv_ro32(gpuobj, i);
}
return 0;
}
void
-nouveau_gpuobj_suspend_cleanup(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *gpuobj;
-
- if (dev_priv->card_type < NV_50) {
- vfree(dev_priv->susres.ramin_copy);
- dev_priv->susres.ramin_copy = NULL;
- return;
- }
-
- list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
- if (!gpuobj->im_backing_suspend)
- continue;
-
- vfree(gpuobj->im_backing_suspend);
- gpuobj->im_backing_suspend = NULL;
- }
-}
-
-void
nouveau_gpuobj_resume(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj;
int i;
- if (dev_priv->card_type < NV_50) {
- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4)
- nv_wi32(dev, i, dev_priv->susres.ramin_copy[i/4]);
- nouveau_gpuobj_suspend_cleanup(dev);
- return;
- }
-
list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
- if (!gpuobj->im_backing_suspend)
+ if (!gpuobj->suspend)
continue;
for (i = 0; i < gpuobj->size; i += 4)
- nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
- dev_priv->engine.instmem.flush(dev);
+ nv_wo32(gpuobj, i, gpuobj->suspend[i/4]);
+
+ vfree(gpuobj->suspend);
+ gpuobj->suspend = NULL;
}
- nouveau_gpuobj_suspend_cleanup(dev);
+ dev_priv->engine.instmem.flush(dev);
}
int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_grobj_alloc *init = data;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_pgraph_object_class *grc;
- struct nouveau_gpuobj *gr = NULL;
struct nouveau_channel *chan;
int ret;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
-
if (init->handle == ~0)
return -EINVAL;
- grc = pgraph->grclass;
- while (grc->id) {
- if (grc->id == init->class)
- break;
- grc++;
- }
+ chan = nouveau_channel_get(dev, file_priv, init->channel);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
- if (!grc->id) {
- NV_ERROR(dev, "Illegal object class: 0x%x\n", init->class);
- return -EPERM;
+ if (nouveau_ramht_find(chan, init->handle)) {
+ ret = -EEXIST;
+ goto out;
}
- if (nouveau_ramht_find(chan, init->handle))
- return -EEXIST;
-
- if (!grc->software)
- ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
- else
- ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
+ ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class);
if (ret) {
NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
ret, init->channel, init->handle);
- return ret;
}
- ret = nouveau_ramht_insert(chan, init->handle, gr);
- nouveau_gpuobj_ref(NULL, &gr);
- if (ret) {
- NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
- ret, init->channel, init->handle);
- return ret;
- }
-
- return 0;
+out:
+ nouveau_channel_put(&chan);
+ return ret;
}
int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_gpuobj_free *objfree = data;
- struct nouveau_gpuobj *gpuobj;
struct nouveau_channel *chan;
+ int ret;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
+ chan = nouveau_channel_get(dev, file_priv, objfree->channel);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
- gpuobj = nouveau_ramht_find(chan, objfree->handle);
- if (!gpuobj)
- return -ENOENT;
+ /* Synchronize with the user channel */
+ nouveau_channel_idle(chan);
- nouveau_ramht_remove(chan, objfree->handle);
- return 0;
+ ret = nouveau_ramht_remove(chan, objfree->handle);
+ nouveau_channel_put(&chan);
+ return ret;
}
u32
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 1c99c55d6d46..fb846a3fef15 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -27,6 +27,10 @@
#include "nouveau_drv.h"
#include "nouveau_pm.h"
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
+#include <linux/power_supply.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@@ -284,6 +288,7 @@ nouveau_sysfs_fini(struct drm_device *dev)
}
}
+#ifdef CONFIG_HWMON
static ssize_t
nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
{
@@ -395,10 +400,12 @@ static struct attribute *hwmon_attributes[] = {
static const struct attribute_group hwmon_attrgroup = {
.attrs = hwmon_attributes,
};
+#endif
static int
nouveau_hwmon_init(struct drm_device *dev)
{
+#ifdef CONFIG_HWMON
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct device *hwmon_dev;
@@ -415,8 +422,7 @@ nouveau_hwmon_init(struct drm_device *dev)
return ret;
}
dev_set_drvdata(hwmon_dev, dev);
- ret = sysfs_create_group(&hwmon_dev->kobj,
- &hwmon_attrgroup);
+ ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
if (ret) {
NV_ERROR(dev,
"Unable to create hwmon sysfs file: %d\n", ret);
@@ -425,13 +431,14 @@ nouveau_hwmon_init(struct drm_device *dev)
}
pm->hwmon = hwmon_dev;
-
+#endif
return 0;
}
static void
nouveau_hwmon_fini(struct drm_device *dev)
{
+#ifdef CONFIG_HWMON
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
@@ -439,7 +446,27 @@ nouveau_hwmon_fini(struct drm_device *dev)
sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
hwmon_device_unregister(pm->hwmon);
}
+#endif
+}
+
+#ifdef CONFIG_ACPI
+static int
+nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct drm_nouveau_private *dev_priv =
+ container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb);
+ struct drm_device *dev = dev_priv->dev;
+ struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
+
+ if (strcmp(entry->device_class, "ac_adapter") == 0) {
+ bool ac = power_supply_is_system_supplied();
+
+ NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC");
+ }
+
+ return NOTIFY_OK;
}
+#endif
int
nouveau_pm_init(struct drm_device *dev)
@@ -480,6 +507,10 @@ nouveau_pm_init(struct drm_device *dev)
nouveau_sysfs_init(dev);
nouveau_hwmon_init(dev);
+#ifdef CONFIG_ACPI
+ pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
+ register_acpi_notifier(&pm->acpi_nb);
+#endif
return 0;
}
@@ -498,6 +529,9 @@ nouveau_pm_fini(struct drm_device *dev)
nouveau_perf_fini(dev);
nouveau_volt_fini(dev);
+#ifdef CONFIG_ACPI
+ unregister_acpi_notifier(&pm->acpi_nb);
+#endif
nouveau_hwmon_fini(dev);
nouveau_sysfs_fini(dev);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
index 7f16697cc96c..bef3e6910418 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c
@@ -104,17 +104,17 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
if (dev_priv->card_type < NV_40) {
- ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
+ ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->pinst >> 4) |
(chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
(gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
} else
if (dev_priv->card_type < NV_50) {
- ctx = (gpuobj->cinst >> 4) |
+ ctx = (gpuobj->pinst >> 4) |
(chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
(gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
} else {
if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
- ctx = (gpuobj->cinst << 10) | 2;
+ ctx = (gpuobj->cinst << 10) | chan->id;
} else {
ctx = (gpuobj->cinst >> 4) |
((gpuobj->engine <<
@@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
return -ENOMEM;
}
+static struct nouveau_ramht_entry *
+nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
+{
+ struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
+ struct nouveau_ramht_entry *entry;
+ unsigned long flags;
+
+ if (!ramht)
+ return NULL;
+
+ spin_lock_irqsave(&ramht->lock, flags);
+ list_for_each_entry(entry, &ramht->entries, head) {
+ if (entry->channel == chan &&
+ (!handle || entry->handle == handle)) {
+ list_del(&entry->head);
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ return NULL;
+}
+
static void
-nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
+nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
- struct nouveau_ramht_entry *entry, *tmp;
+ unsigned long flags;
u32 co, ho;
- list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
- if (entry->channel != chan || entry->handle != handle)
- continue;
-
- nouveau_gpuobj_ref(NULL, &entry->gpuobj);
- list_del(&entry->head);
- kfree(entry);
- break;
- }
-
+ spin_lock_irqsave(&chan->ramht->lock, flags);
co = ho = nouveau_ramht_hash_handle(chan, handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
@@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
nv_wo32(ramht, co + 0, 0x00000000);
nv_wo32(ramht, co + 4, 0x00000000);
instmem->flush(dev);
- return;
+ goto out;
}
co += 8;
@@ -194,17 +210,23 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, handle);
+out:
+ spin_unlock_irqrestore(&chan->ramht->lock, flags);
}
-void
+int
nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
{
- struct nouveau_ramht *ramht = chan->ramht;
- unsigned long flags;
+ struct nouveau_ramht_entry *entry;
- spin_lock_irqsave(&ramht->lock, flags);
- nouveau_ramht_remove_locked(chan, handle);
- spin_unlock_irqrestore(&ramht->lock, flags);
+ entry = nouveau_ramht_remove_entry(chan, handle);
+ if (!entry)
+ return -ENOENT;
+
+ nouveau_ramht_remove_hash(chan, entry->handle);
+ nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+ kfree(entry);
+ return 0;
}
struct nouveau_gpuobj *
@@ -265,23 +287,19 @@ void
nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
struct nouveau_channel *chan)
{
- struct nouveau_ramht_entry *entry, *tmp;
+ struct nouveau_ramht_entry *entry;
struct nouveau_ramht *ramht;
- unsigned long flags;
if (ref)
kref_get(&ref->refcount);
ramht = *ptr;
if (ramht) {
- spin_lock_irqsave(&ramht->lock, flags);
- list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
- if (entry->channel != chan)
- continue;
-
- nouveau_ramht_remove_locked(chan, entry->handle);
+ while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
+ nouveau_ramht_remove_hash(chan, entry->handle);
+ nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+ kfree(entry);
}
- spin_unlock_irqrestore(&ramht->lock, flags);
kref_put(&ramht->refcount, nouveau_ramht_del);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h
index b79cb5e1a8f1..c82de98fee0e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.h
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h
@@ -48,7 +48,7 @@ extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
struct nouveau_gpuobj *);
-extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
+extern int nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
extern struct nouveau_gpuobj *
nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 1b42541ca9e5..04e8fb795269 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -45,6 +45,11 @@
# define NV04_PFB_REF_CMD_REFRESH (1 << 0)
#define NV04_PFB_PRE 0x001002d4
# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0)
+#define NV20_PFB_ZCOMP(i) (0x00100300 + 4*(i))
+# define NV20_PFB_ZCOMP_MODE_32 (4 << 24)
+# define NV20_PFB_ZCOMP_EN (1 << 31)
+# define NV25_PFB_ZCOMP_MODE_16 (1 << 20)
+# define NV25_PFB_ZCOMP_MODE_32 (2 << 20)
#define NV10_PFB_CLOSE_PAGE2 0x0010033c
#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
@@ -74,17 +79,6 @@
# define NV40_RAMHT_CONTEXT_ENGINE_SHIFT 20
# define NV40_RAMHT_CONTEXT_INSTANCE_SHIFT 0
-/* DMA object defines */
-#define NV_DMA_ACCESS_RW 0
-#define NV_DMA_ACCESS_RO 1
-#define NV_DMA_ACCESS_WO 2
-#define NV_DMA_TARGET_VIDMEM 0
-#define NV_DMA_TARGET_PCI 2
-#define NV_DMA_TARGET_AGP 3
-/* The following is not a real value used by the card, it's changed by
- * nouveau_object_dma_create */
-#define NV_DMA_TARGET_PCI_NONLINEAR 8
-
/* Some object classes we care about in the drm */
#define NV_CLASS_DMA_FROM_MEMORY 0x00000002
#define NV_CLASS_DMA_TO_MEMORY 0x00000003
@@ -332,6 +326,7 @@
#define NV04_PGRAPH_BSWIZZLE5 0x004006A0
#define NV03_PGRAPH_STATUS 0x004006B0
#define NV04_PGRAPH_STATUS 0x00400700
+# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000
#define NV04_PGRAPH_TRAPPED_ADDR 0x00400704
#define NV04_PGRAPH_TRAPPED_DATA 0x00400708
#define NV04_PGRAPH_SURFACE 0x0040070C
@@ -378,6 +373,7 @@
#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16))
#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16))
#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16))
+#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i))
#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16))
#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16))
#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16))
@@ -714,31 +710,32 @@
#define NV50_PDISPLAY_INTR_1_CLK_UNK10 0x00000010
#define NV50_PDISPLAY_INTR_1_CLK_UNK20 0x00000020
#define NV50_PDISPLAY_INTR_1_CLK_UNK40 0x00000040
-#define NV50_PDISPLAY_INTR_EN 0x0061002c
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC 0x0000000c
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(n) (1 << ((n) + 2))
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_0 0x00000004
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_1 0x00000008
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK10 0x00000010
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK20 0x00000020
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK40 0x00000040
+#define NV50_PDISPLAY_INTR_EN_0 0x00610028
+#define NV50_PDISPLAY_INTR_EN_1 0x0061002c
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC 0x0000000c
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(n) (1 << ((n) + 2))
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_0 0x00000004
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_1 0x00000008
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 0x00000010
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 0x00000020
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK40 0x00000040
#define NV50_PDISPLAY_UNK30_CTRL 0x00610030
#define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 0x00000200
#define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 0x00000400
#define NV50_PDISPLAY_UNK30_CTRL_PENDING 0x80000000
-#define NV50_PDISPLAY_TRAPPED_ADDR 0x00610080
-#define NV50_PDISPLAY_TRAPPED_DATA 0x00610084
-#define NV50_PDISPLAY_CHANNEL_STAT(i) ((i) * 0x10 + 0x00610200)
-#define NV50_PDISPLAY_CHANNEL_STAT_DMA 0x00000010
-#define NV50_PDISPLAY_CHANNEL_STAT_DMA_DISABLED 0x00000000
-#define NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED 0x00000010
-#define NV50_PDISPLAY_CHANNEL_DMA_CB(i) ((i) * 0x10 + 0x00610204)
-#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION 0x00000002
-#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM 0x00000000
-#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_SYSTEM 0x00000002
-#define NV50_PDISPLAY_CHANNEL_DMA_CB_VALID 0x00000001
-#define NV50_PDISPLAY_CHANNEL_UNK2(i) ((i) * 0x10 + 0x00610208)
-#define NV50_PDISPLAY_CHANNEL_UNK3(i) ((i) * 0x10 + 0x0061020c)
+#define NV50_PDISPLAY_TRAPPED_ADDR(i) ((i) * 0x08 + 0x00610080)
+#define NV50_PDISPLAY_TRAPPED_DATA(i) ((i) * 0x08 + 0x00610084)
+#define NV50_PDISPLAY_EVO_CTRL(i) ((i) * 0x10 + 0x00610200)
+#define NV50_PDISPLAY_EVO_CTRL_DMA 0x00000010
+#define NV50_PDISPLAY_EVO_CTRL_DMA_DISABLED 0x00000000
+#define NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED 0x00000010
+#define NV50_PDISPLAY_EVO_DMA_CB(i) ((i) * 0x10 + 0x00610204)
+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION 0x00000002
+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM 0x00000000
+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_SYSTEM 0x00000002
+#define NV50_PDISPLAY_EVO_DMA_CB_VALID 0x00000001
+#define NV50_PDISPLAY_EVO_UNK2(i) ((i) * 0x10 + 0x00610208)
+#define NV50_PDISPLAY_EVO_HASH_TAG(i) ((i) * 0x10 + 0x0061020c)
#define NV50_PDISPLAY_CURSOR 0x00610270
#define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) ((i) * 0x10 + 0x00610270)
@@ -746,15 +743,11 @@
#define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS 0x00030000
#define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE 0x00010000
-#define NV50_PDISPLAY_CTRL_STATE 0x00610300
-#define NV50_PDISPLAY_CTRL_STATE_PENDING 0x80000000
-#define NV50_PDISPLAY_CTRL_STATE_METHOD 0x00001ffc
-#define NV50_PDISPLAY_CTRL_STATE_ENABLE 0x00000001
-#define NV50_PDISPLAY_CTRL_VAL 0x00610304
-#define NV50_PDISPLAY_UNK_380 0x00610380
-#define NV50_PDISPLAY_RAM_AMOUNT 0x00610384
-#define NV50_PDISPLAY_UNK_388 0x00610388
-#define NV50_PDISPLAY_UNK_38C 0x0061038c
+#define NV50_PDISPLAY_PIO_CTRL 0x00610300
+#define NV50_PDISPLAY_PIO_CTRL_PENDING 0x80000000
+#define NV50_PDISPLAY_PIO_CTRL_MTHD 0x00001ffc
+#define NV50_PDISPLAY_PIO_CTRL_ENABLED 0x00000001
+#define NV50_PDISPLAY_PIO_DATA 0x00610304
#define NV50_PDISPLAY_CRTC_P(i, r) ((i) * 0x540 + NV50_PDISPLAY_CRTC_##r)
#define NV50_PDISPLAY_CRTC_C(i, r) (4 + (i) * 0x540 + NV50_PDISPLAY_CRTC_##r)
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 288bacac7e5a..9a250eb53098 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -14,7 +14,7 @@ struct nouveau_sgdma_be {
dma_addr_t *pages;
unsigned nr_pages;
- unsigned pte_start;
+ u64 offset;
bool bound;
};
@@ -74,18 +74,6 @@ nouveau_sgdma_clear(struct ttm_backend *be)
}
}
-static inline unsigned
-nouveau_sgdma_pte(struct drm_device *dev, uint64_t offset)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- unsigned pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
-
- if (dev_priv->card_type < NV_50)
- return pte + 2;
-
- return pte << 1;
-}
-
static int
nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
{
@@ -97,32 +85,17 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
NV_DEBUG(dev, "pg=0x%lx\n", mem->start);
- pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT);
- nvbe->pte_start = pte;
+ nvbe->offset = mem->start << PAGE_SHIFT;
+ pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
for (i = 0; i < nvbe->nr_pages; i++) {
dma_addr_t dma_offset = nvbe->pages[i];
uint32_t offset_l = lower_32_bits(dma_offset);
- uint32_t offset_h = upper_32_bits(dma_offset);
-
- for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
- if (dev_priv->card_type < NV_50) {
- nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
- pte += 1;
- } else {
- nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21);
- nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff);
- pte += 2;
- }
+ for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) {
+ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
- dev_priv->engine.instmem.flush(nvbe->dev);
-
- if (dev_priv->card_type == NV_50) {
- nv50_vm_flush(dev, 5); /* PGRAPH */
- nv50_vm_flush(dev, 0); /* PFIFO */
- }
nvbe->bound = true;
return 0;
@@ -142,28 +115,10 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
if (!nvbe->bound)
return 0;
- pte = nvbe->pte_start;
+ pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
for (i = 0; i < nvbe->nr_pages; i++) {
- dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
-
- for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
- if (dev_priv->card_type < NV_50) {
- nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3);
- pte += 1;
- } else {
- nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
- nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000);
- pte += 2;
- }
-
- dma_offset += NV_CTXDMA_PAGE_SIZE;
- }
- }
- dev_priv->engine.instmem.flush(nvbe->dev);
-
- if (dev_priv->card_type == NV_50) {
- nv50_vm_flush(dev, 5);
- nv50_vm_flush(dev, 0);
+ for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++)
+ nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
}
nvbe->bound = false;
@@ -186,6 +141,35 @@ nouveau_sgdma_destroy(struct ttm_backend *be)
}
}
+static int
+nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
+{
+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;
+
+ nvbe->offset = mem->start << PAGE_SHIFT;
+
+ nouveau_vm_map_sg(&dev_priv->gart_info.vma, nvbe->offset,
+ nvbe->nr_pages << PAGE_SHIFT, nvbe->pages);
+ nvbe->bound = true;
+ return 0;
+}
+
+static int
+nv50_sgdma_unbind(struct ttm_backend *be)
+{
+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;
+
+ if (!nvbe->bound)
+ return 0;
+
+ nouveau_vm_unmap_at(&dev_priv->gart_info.vma, nvbe->offset,
+ nvbe->nr_pages << PAGE_SHIFT);
+ nvbe->bound = false;
+ return 0;
+}
+
static struct ttm_backend_func nouveau_sgdma_backend = {
.populate = nouveau_sgdma_populate,
.clear = nouveau_sgdma_clear,
@@ -194,23 +178,30 @@ static struct ttm_backend_func nouveau_sgdma_backend = {
.destroy = nouveau_sgdma_destroy
};
+static struct ttm_backend_func nv50_sgdma_backend = {
+ .populate = nouveau_sgdma_populate,
+ .clear = nouveau_sgdma_clear,
+ .bind = nv50_sgdma_bind,
+ .unbind = nv50_sgdma_unbind,
+ .destroy = nouveau_sgdma_destroy
+};
+
struct ttm_backend *
nouveau_sgdma_init_ttm(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_sgdma_be *nvbe;
- if (!dev_priv->gart_info.sg_ctxdma)
- return NULL;
-
nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL);
if (!nvbe)
return NULL;
nvbe->dev = dev;
- nvbe->backend.func = &nouveau_sgdma_backend;
-
+ if (dev_priv->card_type < NV_50)
+ nvbe->backend.func = &nouveau_sgdma_backend;
+ else
+ nvbe->backend.func = &nv50_sgdma_backend;
return &nvbe->backend;
}
@@ -218,77 +209,52 @@ int
nouveau_sgdma_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct pci_dev *pdev = dev->pdev;
struct nouveau_gpuobj *gpuobj = NULL;
uint32_t aper_size, obj_size;
int i, ret;
if (dev_priv->card_type < NV_50) {
- aper_size = (64 * 1024 * 1024);
+ if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
+ aper_size = 64 * 1024 * 1024;
+ else
+ aper_size = 512 * 1024 * 1024;
+
obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
obj_size += 8; /* ctxdma header */
- } else {
- /* 1 entire VM page table */
- aper_size = (512 * 1024 * 1024);
- obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 8;
- }
-
- ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &gpuobj);
- if (ret) {
- NV_ERROR(dev, "Error creating sgdma object: %d\n", ret);
- return ret;
- }
-
- dev_priv->gart_info.sg_dummy_page =
- alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO);
- if (!dev_priv->gart_info.sg_dummy_page) {
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return -ENOMEM;
- }
- set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags);
- dev_priv->gart_info.sg_dummy_bus =
- pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return -EFAULT;
- }
+ ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &gpuobj);
+ if (ret) {
+ NV_ERROR(dev, "Error creating sgdma object: %d\n", ret);
+ return ret;
+ }
- if (dev_priv->card_type < NV_50) {
- /* special case, allocated from global instmem heap so
- * cinst is invalid, we use it on all channels though so
- * cinst needs to be valid, set it the same as pinst
- */
- gpuobj->cinst = gpuobj->pinst;
-
- /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
- * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
- * on those cards? */
nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
(1 << 12) /* PT present */ |
(0 << 13) /* PT *not* linear */ |
- (NV_DMA_ACCESS_RW << 14) |
- (NV_DMA_TARGET_PCI << 16));
+ (0 << 14) /* RW */ |
+ (2 << 16) /* PCI */);
nv_wo32(gpuobj, 4, aper_size - 1);
- for (i = 2; i < 2 + (aper_size >> 12); i++) {
- nv_wo32(gpuobj, i * 4,
- dev_priv->gart_info.sg_dummy_bus | 3);
- }
- } else {
- for (i = 0; i < obj_size; i += 8) {
- nv_wo32(gpuobj, i + 0, 0x00000000);
- nv_wo32(gpuobj, i + 4, 0x00000000);
- }
+ for (i = 2; i < 2 + (aper_size >> 12); i++)
+ nv_wo32(gpuobj, i * 4, 0x00000000);
+
+ dev_priv->gart_info.sg_ctxdma = gpuobj;
+ dev_priv->gart_info.aper_base = 0;
+ dev_priv->gart_info.aper_size = aper_size;
+ } else
+ if (dev_priv->chan_vm) {
+ ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024,
+ 12, NV_MEM_ACCESS_RW,
+ &dev_priv->gart_info.vma);
+ if (ret)
+ return ret;
+
+ dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset;
+ dev_priv->gart_info.aper_size = 512 * 1024 * 1024;
}
- dev_priv->engine.instmem.flush(dev);
dev_priv->gart_info.type = NOUVEAU_GART_SGDMA;
- dev_priv->gart_info.aper_base = 0;
- dev_priv->gart_info.aper_size = aper_size;
- dev_priv->gart_info.sg_ctxdma = gpuobj;
return 0;
}
@@ -297,31 +263,19 @@ nouveau_sgdma_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- if (dev_priv->gart_info.sg_dummy_page) {
- pci_unmap_page(dev->pdev, dev_priv->gart_info.sg_dummy_bus,
- NV_CTXDMA_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- unlock_page(dev_priv->gart_info.sg_dummy_page);
- __free_page(dev_priv->gart_info.sg_dummy_page);
- dev_priv->gart_info.sg_dummy_page = NULL;
- dev_priv->gart_info.sg_dummy_bus = 0;
- }
-
nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
+ nouveau_vm_put(&dev_priv->gart_info.vma);
}
-int
-nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
+uint32_t
+nouveau_sgdma_get_physical(struct drm_device *dev, uint32_t offset)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
- int pte;
+ int pte = (offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
- pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2;
- if (dev_priv->card_type < NV_50) {
- *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK;
- return 0;
- }
+ BUG_ON(dev_priv->card_type >= NV_50);
- NV_ERROR(dev, "Unimplemented on NV50\n");
- return -EINVAL;
+ return (nv_ro32(gpuobj, 4 * pte) & ~NV_CTXDMA_PAGE_MASK) |
+ (offset & NV_CTXDMA_PAGE_MASK);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index ed7757f14083..a54fc431fe98 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -53,10 +53,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.takedown = nv04_instmem_takedown;
engine->instmem.suspend = nv04_instmem_suspend;
engine->instmem.resume = nv04_instmem_resume;
- engine->instmem.populate = nv04_instmem_populate;
- engine->instmem.clear = nv04_instmem_clear;
- engine->instmem.bind = nv04_instmem_bind;
- engine->instmem.unbind = nv04_instmem_unbind;
+ engine->instmem.get = nv04_instmem_get;
+ engine->instmem.put = nv04_instmem_put;
+ engine->instmem.map = nv04_instmem_map;
+ engine->instmem.unmap = nv04_instmem_unmap;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
@@ -65,7 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv04_fb_init;
engine->fb.takedown = nv04_fb_takedown;
- engine->graph.grclass = nv04_graph_grclass;
engine->graph.init = nv04_graph_init;
engine->graph.takedown = nv04_graph_takedown;
engine->graph.fifo_access = nv04_graph_fifo_access;
@@ -76,7 +75,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.unload_context = nv04_graph_unload_context;
engine->fifo.channels = 16;
engine->fifo.init = nv04_fifo_init;
- engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.takedown = nv04_fifo_fini;
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
@@ -99,16 +98,20 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nouveau_mem_detect;
+ engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
case 0x10:
engine->instmem.init = nv04_instmem_init;
engine->instmem.takedown = nv04_instmem_takedown;
engine->instmem.suspend = nv04_instmem_suspend;
engine->instmem.resume = nv04_instmem_resume;
- engine->instmem.populate = nv04_instmem_populate;
- engine->instmem.clear = nv04_instmem_clear;
- engine->instmem.bind = nv04_instmem_bind;
- engine->instmem.unbind = nv04_instmem_unbind;
+ engine->instmem.get = nv04_instmem_get;
+ engine->instmem.put = nv04_instmem_put;
+ engine->instmem.map = nv04_instmem_map;
+ engine->instmem.unmap = nv04_instmem_unmap;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
@@ -117,8 +120,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
- engine->fb.set_region_tiling = nv10_fb_set_region_tiling;
- engine->graph.grclass = nv10_graph_grclass;
+ engine->fb.init_tile_region = nv10_fb_init_tile_region;
+ engine->fb.set_tile_region = nv10_fb_set_tile_region;
+ engine->fb.free_tile_region = nv10_fb_free_tile_region;
engine->graph.init = nv10_graph_init;
engine->graph.takedown = nv10_graph_takedown;
engine->graph.channel = nv10_graph_channel;
@@ -127,17 +131,17 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.fifo_access = nv04_graph_fifo_access;
engine->graph.load_context = nv10_graph_load_context;
engine->graph.unload_context = nv10_graph_unload_context;
- engine->graph.set_region_tiling = nv10_graph_set_region_tiling;
+ engine->graph.set_tile_region = nv10_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.takedown = nv04_fifo_fini;
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
@@ -153,16 +157,20 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nouveau_mem_detect;
+ engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
case 0x20:
engine->instmem.init = nv04_instmem_init;
engine->instmem.takedown = nv04_instmem_takedown;
engine->instmem.suspend = nv04_instmem_suspend;
engine->instmem.resume = nv04_instmem_resume;
- engine->instmem.populate = nv04_instmem_populate;
- engine->instmem.clear = nv04_instmem_clear;
- engine->instmem.bind = nv04_instmem_bind;
- engine->instmem.unbind = nv04_instmem_unbind;
+ engine->instmem.get = nv04_instmem_get;
+ engine->instmem.put = nv04_instmem_put;
+ engine->instmem.map = nv04_instmem_map;
+ engine->instmem.unmap = nv04_instmem_unmap;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
@@ -171,8 +179,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
- engine->fb.set_region_tiling = nv10_fb_set_region_tiling;
- engine->graph.grclass = nv20_graph_grclass;
+ engine->fb.init_tile_region = nv10_fb_init_tile_region;
+ engine->fb.set_tile_region = nv10_fb_set_tile_region;
+ engine->fb.free_tile_region = nv10_fb_free_tile_region;
engine->graph.init = nv20_graph_init;
engine->graph.takedown = nv20_graph_takedown;
engine->graph.channel = nv10_graph_channel;
@@ -181,17 +190,17 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.fifo_access = nv04_graph_fifo_access;
engine->graph.load_context = nv20_graph_load_context;
engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_region_tiling = nv20_graph_set_region_tiling;
+ engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.takedown = nv04_fifo_fini;
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
@@ -207,16 +216,20 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nouveau_mem_detect;
+ engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
case 0x30:
engine->instmem.init = nv04_instmem_init;
engine->instmem.takedown = nv04_instmem_takedown;
engine->instmem.suspend = nv04_instmem_suspend;
engine->instmem.resume = nv04_instmem_resume;
- engine->instmem.populate = nv04_instmem_populate;
- engine->instmem.clear = nv04_instmem_clear;
- engine->instmem.bind = nv04_instmem_bind;
- engine->instmem.unbind = nv04_instmem_unbind;
+ engine->instmem.get = nv04_instmem_get;
+ engine->instmem.put = nv04_instmem_put;
+ engine->instmem.map = nv04_instmem_map;
+ engine->instmem.unmap = nv04_instmem_unmap;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
@@ -225,8 +238,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv30_fb_init;
engine->fb.takedown = nv30_fb_takedown;
- engine->fb.set_region_tiling = nv10_fb_set_region_tiling;
- engine->graph.grclass = nv30_graph_grclass;
+ engine->fb.init_tile_region = nv30_fb_init_tile_region;
+ engine->fb.set_tile_region = nv10_fb_set_tile_region;
+ engine->fb.free_tile_region = nv30_fb_free_tile_region;
engine->graph.init = nv30_graph_init;
engine->graph.takedown = nv20_graph_takedown;
engine->graph.fifo_access = nv04_graph_fifo_access;
@@ -235,17 +249,17 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.destroy_context = nv20_graph_destroy_context;
engine->graph.load_context = nv20_graph_load_context;
engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_region_tiling = nv20_graph_set_region_tiling;
+ engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.takedown = nv04_fifo_fini;
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
@@ -263,6 +277,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_set = nv04_pm_clock_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nouveau_mem_detect;
+ engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
case 0x40:
case 0x60:
@@ -270,10 +288,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.takedown = nv04_instmem_takedown;
engine->instmem.suspend = nv04_instmem_suspend;
engine->instmem.resume = nv04_instmem_resume;
- engine->instmem.populate = nv04_instmem_populate;
- engine->instmem.clear = nv04_instmem_clear;
- engine->instmem.bind = nv04_instmem_bind;
- engine->instmem.unbind = nv04_instmem_unbind;
+ engine->instmem.get = nv04_instmem_get;
+ engine->instmem.put = nv04_instmem_put;
+ engine->instmem.map = nv04_instmem_map;
+ engine->instmem.unmap = nv04_instmem_unmap;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv40_mc_init;
engine->mc.takedown = nv40_mc_takedown;
@@ -282,8 +300,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv40_fb_init;
engine->fb.takedown = nv40_fb_takedown;
- engine->fb.set_region_tiling = nv40_fb_set_region_tiling;
- engine->graph.grclass = nv40_graph_grclass;
+ engine->fb.init_tile_region = nv30_fb_init_tile_region;
+ engine->fb.set_tile_region = nv40_fb_set_tile_region;
+ engine->fb.free_tile_region = nv30_fb_free_tile_region;
engine->graph.init = nv40_graph_init;
engine->graph.takedown = nv40_graph_takedown;
engine->graph.fifo_access = nv04_graph_fifo_access;
@@ -292,17 +311,17 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.destroy_context = nv40_graph_destroy_context;
engine->graph.load_context = nv40_graph_load_context;
engine->graph.unload_context = nv40_graph_unload_context;
- engine->graph.set_region_tiling = nv40_graph_set_region_tiling;
+ engine->graph.set_tile_region = nv40_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv40_fifo_init;
- engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.takedown = nv04_fifo_fini;
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv40_fifo_create_context;
- engine->fifo.destroy_context = nv40_fifo_destroy_context;
+ engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv40_fifo_load_context;
engine->fifo.unload_context = nv40_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
@@ -321,6 +340,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->pm.temp_get = nv40_temp_get;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nouveau_mem_detect;
+ engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
case 0x50:
case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -330,10 +353,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.takedown = nv50_instmem_takedown;
engine->instmem.suspend = nv50_instmem_suspend;
engine->instmem.resume = nv50_instmem_resume;
- engine->instmem.populate = nv50_instmem_populate;
- engine->instmem.clear = nv50_instmem_clear;
- engine->instmem.bind = nv50_instmem_bind;
- engine->instmem.unbind = nv50_instmem_unbind;
+ engine->instmem.get = nv50_instmem_get;
+ engine->instmem.put = nv50_instmem_put;
+ engine->instmem.map = nv50_instmem_map;
+ engine->instmem.unmap = nv50_instmem_unmap;
if (dev_priv->chipset == 0x50)
engine->instmem.flush = nv50_instmem_flush;
else
@@ -345,7 +368,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv50_fb_init;
engine->fb.takedown = nv50_fb_takedown;
- engine->graph.grclass = nv50_graph_grclass;
engine->graph.init = nv50_graph_init;
engine->graph.takedown = nv50_graph_takedown;
engine->graph.fifo_access = nv50_graph_fifo_access;
@@ -354,6 +376,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.destroy_context = nv50_graph_destroy_context;
engine->graph.load_context = nv50_graph_load_context;
engine->graph.unload_context = nv50_graph_unload_context;
+ if (dev_priv->chipset != 0x86)
+ engine->graph.tlb_flush = nv50_graph_tlb_flush;
+ else {
+ /* from what i can see nvidia do this on every
+ * pre-NVA3 board except NVAC, but, we've only
+ * ever seen problems on NV86
+ */
+ engine->graph.tlb_flush = nv86_graph_tlb_flush;
+ }
engine->fifo.channels = 128;
engine->fifo.init = nv50_fifo_init;
engine->fifo.takedown = nv50_fifo_takedown;
@@ -365,30 +396,39 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv50_fifo_destroy_context;
engine->fifo.load_context = nv50_fifo_load_context;
engine->fifo.unload_context = nv50_fifo_unload_context;
+ engine->fifo.tlb_flush = nv50_fifo_tlb_flush;
engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create;
engine->display.init = nv50_display_init;
engine->display.destroy = nv50_display_destroy;
engine->gpio.init = nv50_gpio_init;
- engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.takedown = nv50_gpio_fini;
engine->gpio.get = nv50_gpio_get;
engine->gpio.set = nv50_gpio_set;
+ engine->gpio.irq_register = nv50_gpio_irq_register;
+ engine->gpio.irq_unregister = nv50_gpio_irq_unregister;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
switch (dev_priv->chipset) {
- case 0xa3:
- case 0xa5:
- case 0xa8:
- case 0xaf:
- engine->pm.clock_get = nva3_pm_clock_get;
- engine->pm.clock_pre = nva3_pm_clock_pre;
- engine->pm.clock_set = nva3_pm_clock_set;
- break;
- default:
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ case 0x50:
engine->pm.clock_get = nv50_pm_clock_get;
engine->pm.clock_pre = nv50_pm_clock_pre;
engine->pm.clock_set = nv50_pm_clock_set;
break;
+ default:
+ engine->pm.clock_get = nva3_pm_clock_get;
+ engine->pm.clock_pre = nva3_pm_clock_pre;
+ engine->pm.clock_set = nva3_pm_clock_set;
+ break;
}
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
@@ -396,17 +436,39 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv84_temp_get;
else
engine->pm.temp_get = nv40_temp_get;
+ switch (dev_priv->chipset) {
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa0:
+ engine->crypt.init = nv84_crypt_init;
+ engine->crypt.takedown = nv84_crypt_fini;
+ engine->crypt.create_context = nv84_crypt_create_context;
+ engine->crypt.destroy_context = nv84_crypt_destroy_context;
+ engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
+ break;
+ default:
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ break;
+ }
+ engine->vram.init = nv50_vram_init;
+ engine->vram.get = nv50_vram_new;
+ engine->vram.put = nv50_vram_del;
+ engine->vram.flags_valid = nv50_vram_flags_valid;
break;
case 0xC0:
engine->instmem.init = nvc0_instmem_init;
engine->instmem.takedown = nvc0_instmem_takedown;
engine->instmem.suspend = nvc0_instmem_suspend;
engine->instmem.resume = nvc0_instmem_resume;
- engine->instmem.populate = nvc0_instmem_populate;
- engine->instmem.clear = nvc0_instmem_clear;
- engine->instmem.bind = nvc0_instmem_bind;
- engine->instmem.unbind = nvc0_instmem_unbind;
- engine->instmem.flush = nvc0_instmem_flush;
+ engine->instmem.get = nv50_instmem_get;
+ engine->instmem.put = nv50_instmem_put;
+ engine->instmem.map = nv50_instmem_map;
+ engine->instmem.unmap = nv50_instmem_unmap;
+ engine->instmem.flush = nv84_instmem_flush;
engine->mc.init = nv50_mc_init;
engine->mc.takedown = nv50_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -414,7 +476,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->graph.grclass = NULL; //nvc0_graph_grclass;
engine->graph.init = nvc0_graph_init;
engine->graph.takedown = nvc0_graph_takedown;
engine->graph.fifo_access = nvc0_graph_fifo_access;
@@ -443,7 +504,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv50_gpio_get;
engine->gpio.set = nv50_gpio_set;
+ engine->gpio.irq_register = nv50_gpio_irq_register;
+ engine->gpio.irq_unregister = nv50_gpio_irq_unregister;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
+ engine->crypt.init = nouveau_stub_init;
+ engine->crypt.takedown = nouveau_stub_takedown;
+ engine->vram.init = nvc0_vram_init;
+ engine->vram.get = nvc0_vram_new;
+ engine->vram.put = nv50_vram_del;
+ engine->vram.flags_valid = nvc0_vram_flags_valid;
break;
default:
NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
@@ -483,9 +552,13 @@ nouveau_card_init_channel(struct drm_device *dev)
if (ret)
return ret;
+ /* no dma objects on fermi... */
+ if (dev_priv->card_type >= NV_C0)
+ goto out_done;
+
ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->vram_size,
- NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
+ NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM,
&gpuobj);
if (ret)
goto out_err;
@@ -495,9 +568,10 @@ nouveau_card_init_channel(struct drm_device *dev)
if (ret)
goto out_err;
- ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
- dev_priv->gart_info.aper_size,
- NV_DMA_ACCESS_RW, &gpuobj, NULL);
+ ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->gart_info.aper_size,
+ NV_MEM_ACCESS_RW, NV_MEM_TARGET_GART,
+ &gpuobj);
if (ret)
goto out_err;
@@ -506,11 +580,12 @@ nouveau_card_init_channel(struct drm_device *dev)
if (ret)
goto out_err;
+out_done:
+ mutex_unlock(&dev_priv->channel->mutex);
return 0;
out_err:
- nouveau_channel_free(dev_priv->channel);
- dev_priv->channel = NULL;
+ nouveau_channel_put(&dev_priv->channel);
return ret;
}
@@ -521,15 +596,25 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
nouveau_pci_resume(pdev);
drm_kms_helper_poll_enable(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(dev);
nouveau_pci_suspend(pdev, pmm);
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
+static void nouveau_switcheroo_reprobe(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ nouveau_fbcon_output_poll_changed(dev);
+}
+
static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
@@ -550,6 +635,7 @@ nouveau_card_init(struct drm_device *dev)
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
+ nouveau_switcheroo_reprobe,
nouveau_switcheroo_can_switch);
/* Initialise internal driver API hooks */
@@ -557,6 +643,8 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out;
engine = &dev_priv->engine;
+ spin_lock_init(&dev_priv->channels.lock);
+ spin_lock_init(&dev_priv->tile.lock);
spin_lock_init(&dev_priv->context_switch_lock);
/* Make the CRTCs and I2C buses accessible */
@@ -615,26 +703,28 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_fb;
+ /* PCRYPT */
+ ret = engine->crypt.init(dev);
+ if (ret)
+ goto out_graph;
+
/* PFIFO */
ret = engine->fifo.init(dev);
if (ret)
- goto out_graph;
+ goto out_crypt;
}
ret = engine->display.create(dev);
if (ret)
goto out_fifo;
- /* this call irq_preinstall, register irq handler and
- * call irq_postinstall
- */
- ret = drm_irq_install(dev);
+ ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);
if (ret)
- goto out_display;
+ goto out_vblank;
- ret = drm_vblank_init(dev, 0);
+ ret = nouveau_irq_init(dev);
if (ret)
- goto out_irq;
+ goto out_vblank;
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
@@ -659,12 +749,16 @@ nouveau_card_init(struct drm_device *dev)
out_fence:
nouveau_fence_fini(dev);
out_irq:
- drm_irq_uninstall(dev);
-out_display:
+ nouveau_irq_fini(dev);
+out_vblank:
+ drm_vblank_cleanup(dev);
engine->display.destroy(dev);
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
+out_crypt:
+ if (!nouveau_noaccel)
+ engine->crypt.takedown(dev);
out_graph:
if (!nouveau_noaccel)
engine->graph.takedown(dev);
@@ -703,12 +797,12 @@ static void nouveau_card_takedown(struct drm_device *dev)
if (!engine->graph.accel_blocked) {
nouveau_fence_fini(dev);
- nouveau_channel_free(dev_priv->channel);
- dev_priv->channel = NULL;
+ nouveau_channel_put_unlocked(&dev_priv->channel);
}
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
+ engine->crypt.takedown(dev);
engine->graph.takedown(dev);
}
engine->fb.takedown(dev);
@@ -727,7 +821,8 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_gpuobj_takedown(dev);
nouveau_mem_vram_fini(dev);
- drm_irq_uninstall(dev);
+ nouveau_irq_fini(dev);
+ drm_vblank_cleanup(dev);
nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
@@ -970,6 +1065,7 @@ err_out:
void nouveau_lastclose(struct drm_device *dev)
{
+ vga_switcheroo_process_delayed_switch();
}
int nouveau_unload(struct drm_device *dev)
@@ -1014,21 +1110,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
else
getparam->value = NV_PCI;
break;
- case NOUVEAU_GETPARAM_FB_PHYSICAL:
- getparam->value = dev_priv->fb_phys;
- break;
- case NOUVEAU_GETPARAM_AGP_PHYSICAL:
- getparam->value = dev_priv->gart_info.aper_base;
- break;
- case NOUVEAU_GETPARAM_PCI_PHYSICAL:
- if (dev->sg) {
- getparam->value = (unsigned long)dev->sg->virtual;
- } else {
- NV_ERROR(dev, "Requested PCIGART address, "
- "while no PCIGART was created\n");
- return -EINVAL;
- }
- break;
case NOUVEAU_GETPARAM_FB_SIZE:
getparam->value = dev_priv->fb_available_size;
break;
@@ -1036,11 +1117,17 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
getparam->value = dev_priv->gart_info.aper_size;
break;
case NOUVEAU_GETPARAM_VM_VRAM_BASE:
- getparam->value = dev_priv->vm_vram_base;
+ getparam->value = 0; /* deprecated */
break;
case NOUVEAU_GETPARAM_PTIMER_TIME:
getparam->value = dev_priv->engine.timer.read(dev);
break;
+ case NOUVEAU_GETPARAM_HAS_BO_USAGE:
+ getparam->value = 1;
+ break;
+ case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
+ getparam->value = (dev_priv->card_type < NV_50);
+ break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
/* NV40 and NV50 versions are quite different, but register
* address is the same. User is supposed to know the card
@@ -1051,7 +1138,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
}
/* FALLTHRU */
default:
- NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
+ NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
return -EINVAL;
}
@@ -1066,7 +1153,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
switch (setparam->param) {
default:
- NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
+ NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);
return -EINVAL;
}
@@ -1074,8 +1161,9 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
}
/* Wait until (value(reg) & mask) == val, up until timeout has hit */
-bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout,
- uint32_t reg, uint32_t mask, uint32_t val)
+bool
+nouveau_wait_eq(struct drm_device *dev, uint64_t timeout,
+ uint32_t reg, uint32_t mask, uint32_t val)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -1089,10 +1177,33 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout,
return false;
}
+/* Wait until (value(reg) & mask) != val, up until timeout has hit */
+bool
+nouveau_wait_ne(struct drm_device *dev, uint64_t timeout,
+ uint32_t reg, uint32_t mask, uint32_t val)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ uint64_t start = ptimer->read(dev);
+
+ do {
+ if ((nv_rd32(dev, reg) & mask) != val)
+ return true;
+ } while (ptimer->read(dev) - start < timeout);
+
+ return false;
+}
+
/* Waits for PGRAPH to go completely idle */
bool nouveau_wait_for_idle(struct drm_device *dev)
{
- if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t mask = ~0;
+
+ if (dev_priv->card_type == NV_40)
+ mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
+
+ if (!nv_wait(dev, NV04_PGRAPH_STATUS, mask, 0)) {
NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
nv_rd32(dev, NV04_PGRAPH_STATUS));
return false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
index 16bbbf1eff63..7ecc4adc1e45 100644
--- a/drivers/gpu/drm/nouveau/nouveau_temp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_temp.c
@@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev)
int offset = sensor->offset_mult / sensor->offset_div;
int core_temp;
- if (dev_priv->chipset >= 0x50) {
+ if (dev_priv->card_type >= NV_50) {
core_temp = nv_rd32(dev, 0x20008);
} else {
core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c
new file mode 100644
index 000000000000..fbe0fb13bc1e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_util.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Nouveau Project
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/ratelimit.h>
+
+#include "nouveau_util.h"
+
+static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
+
+void
+nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
+{
+ while (bf->name) {
+ if (value & bf->mask) {
+ printk(" %s", bf->name);
+ value &= ~bf->mask;
+ }
+
+ bf++;
+ }
+
+ if (value)
+ printk(" (unknown bits 0x%08x)", value);
+}
+
+void
+nouveau_enum_print(const struct nouveau_enum *en, u32 value)
+{
+ while (en->name) {
+ if (value == en->value) {
+ printk("%s", en->name);
+ return;
+ }
+
+ en++;
+ }
+
+ printk("(unknown enum 0x%08x)", value);
+}
+
+int
+nouveau_ratelimit(void)
+{
+ return __ratelimit(&nouveau_ratelimit_state);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h
new file mode 100644
index 000000000000..d9ceaea26f4b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_util.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Nouveau Project
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, 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 (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __NOUVEAU_UTIL_H__
+#define __NOUVEAU_UTIL_H__
+
+struct nouveau_bitfield {
+ u32 mask;
+ const char *name;
+};
+
+struct nouveau_enum {
+ u32 value;
+ const char *name;
+};
+
+void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value);
+void nouveau_enum_print(const struct nouveau_enum *, u32 value);
+int nouveau_ratelimit(void);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c
new file mode 100644
index 000000000000..97d82aedf86b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nouveau_vm.h"
+
+void
+nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram)
+{
+ struct nouveau_vm *vm = vma->vm;
+ struct nouveau_mm_node *r;
+ int big = vma->node->type != vm->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (vm->pgt_bits - bits);
+ u32 end, len;
+
+ list_for_each_entry(r, &vram->regions, rl_entry) {
+ u64 phys = (u64)r->offset << 12;
+ u32 num = r->length >> bits;
+
+ while (num) {
+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ vm->map(vma, pgt, vram, pte, len, phys);
+
+ num -= len;
+ pte += len;
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ }
+ }
+
+ vm->flush(vm);
+}
+
+void
+nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_vram *vram)
+{
+ nouveau_vm_map_at(vma, 0, vram);
+}
+
+void
+nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
+ dma_addr_t *list)
+{
+ struct nouveau_vm *vm = vma->vm;
+ int big = vma->node->type != vm->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (vm->pgt_bits - bits);
+ u32 end, len;
+
+ while (num) {
+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ vm->map_sg(vma, pgt, pte, list, len);
+
+ num -= len;
+ pte += len;
+ list += len;
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ }
+
+ vm->flush(vm);
+}
+
+void
+nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length)
+{
+ struct nouveau_vm *vm = vma->vm;
+ int big = vma->node->type != vm->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (vm->pgt_bits - bits);
+ u32 end, len;
+
+ while (num) {
+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ vm->unmap(pgt, pte, len);
+
+ num -= len;
+ pte += len;
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ }
+
+ vm->flush(vm);
+}
+
+void
+nouveau_vm_unmap(struct nouveau_vma *vma)
+{
+ nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
+}
+
+static void
+nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
+{
+ struct nouveau_vm_pgd *vpgd;
+ struct nouveau_vm_pgt *vpgt;
+ struct nouveau_gpuobj *pgt;
+ u32 pde;
+
+ for (pde = fpde; pde <= lpde; pde++) {
+ vpgt = &vm->pgt[pde - vm->fpde];
+ if (--vpgt->refcount[big])
+ continue;
+
+ pgt = vpgt->obj[big];
+ vpgt->obj[big] = NULL;
+
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ vm->map_pgt(vpgd->obj, pde, vpgt->obj);
+ }
+
+ mutex_unlock(&vm->mm->mutex);
+ nouveau_gpuobj_ref(NULL, &pgt);
+ mutex_lock(&vm->mm->mutex);
+ }
+}
+
+static int
+nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
+{
+ struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+ struct nouveau_vm_pgd *vpgd;
+ struct nouveau_gpuobj *pgt;
+ int big = (type != vm->spg_shift);
+ u32 pgt_size;
+ int ret;
+
+ pgt_size = (1 << (vm->pgt_bits + 12)) >> type;
+ pgt_size *= 8;
+
+ mutex_unlock(&vm->mm->mutex);
+ ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &pgt);
+ mutex_lock(&vm->mm->mutex);
+ if (unlikely(ret))
+ return ret;
+
+ /* someone beat us to filling the PDE while we didn't have the lock */
+ if (unlikely(vpgt->refcount[big]++)) {
+ mutex_unlock(&vm->mm->mutex);
+ nouveau_gpuobj_ref(NULL, &pgt);
+ mutex_lock(&vm->mm->mutex);
+ return 0;
+ }
+
+ vpgt->obj[big] = pgt;
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ vm->map_pgt(vpgd->obj, pde, vpgt->obj);
+ }
+
+ return 0;
+}
+
+int
+nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
+ u32 access, struct nouveau_vma *vma)
+{
+ u32 align = (1 << page_shift) >> 12;
+ u32 msize = size >> 12;
+ u32 fpde, lpde, pde;
+ int ret;
+
+ mutex_lock(&vm->mm->mutex);
+ ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node);
+ if (unlikely(ret != 0)) {
+ mutex_unlock(&vm->mm->mutex);
+ return ret;
+ }
+
+ fpde = (vma->node->offset >> vm->pgt_bits);
+ lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits;
+ for (pde = fpde; pde <= lpde; pde++) {
+ struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+ int big = (vma->node->type != vm->spg_shift);
+
+ if (likely(vpgt->refcount[big])) {
+ vpgt->refcount[big]++;
+ continue;
+ }
+
+ ret = nouveau_vm_map_pgt(vm, pde, vma->node->type);
+ if (ret) {
+ if (pde != fpde)
+ nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
+ nouveau_mm_put(vm->mm, vma->node);
+ mutex_unlock(&vm->mm->mutex);
+ vma->node = NULL;
+ return ret;
+ }
+ }
+ mutex_unlock(&vm->mm->mutex);
+
+ vma->vm = vm;
+ vma->offset = (u64)vma->node->offset << 12;
+ vma->access = access;
+ return 0;
+}
+
+void
+nouveau_vm_put(struct nouveau_vma *vma)
+{
+ struct nouveau_vm *vm = vma->vm;
+ u32 fpde, lpde;
+
+ if (unlikely(vma->node == NULL))
+ return;
+ fpde = (vma->node->offset >> vm->pgt_bits);
+ lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits;
+
+ mutex_lock(&vm->mm->mutex);
+ nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde);
+ nouveau_mm_put(vm->mm, vma->node);
+ vma->node = NULL;
+ mutex_unlock(&vm->mm->mutex);
+}
+
+int
+nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset,
+ struct nouveau_vm **pvm)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_vm *vm;
+ u64 mm_length = (offset + length) - mm_offset;
+ u32 block, pgt_bits;
+ int ret;
+
+ vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+ if (!vm)
+ return -ENOMEM;
+
+ if (dev_priv->card_type == NV_50) {
+ vm->map_pgt = nv50_vm_map_pgt;
+ vm->map = nv50_vm_map;
+ vm->map_sg = nv50_vm_map_sg;
+ vm->unmap = nv50_vm_unmap;
+ vm->flush = nv50_vm_flush;
+ vm->spg_shift = 12;
+ vm->lpg_shift = 16;
+
+ pgt_bits = 29;
+ block = (1 << pgt_bits);
+ if (length < block)
+ block = length;
+
+ } else
+ if (dev_priv->card_type == NV_C0) {
+ vm->map_pgt = nvc0_vm_map_pgt;
+ vm->map = nvc0_vm_map;
+ vm->map_sg = nvc0_vm_map_sg;
+ vm->unmap = nvc0_vm_unmap;
+ vm->flush = nvc0_vm_flush;
+ vm->spg_shift = 12;
+ vm->lpg_shift = 17;
+ pgt_bits = 27;
+
+ /* Should be 4096 everywhere, this is a hack that's
+ * currently necessary to avoid an elusive bug that
+ * causes corruption when mixing small/large pages
+ */
+ if (length < (1ULL << 40))
+ block = 4096;
+ else {
+ block = (1 << pgt_bits);
+ if (length < block)
+ block = length;
+ }
+ } else {
+ kfree(vm);
+ return -ENOSYS;
+ }
+
+ vm->fpde = offset >> pgt_bits;
+ vm->lpde = (offset + length - 1) >> pgt_bits;
+ vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL);
+ if (!vm->pgt) {
+ kfree(vm);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vm->pgd_list);
+ vm->dev = dev;
+ vm->refcount = 1;
+ vm->pgt_bits = pgt_bits - 12;
+
+ ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
+ block >> 12);
+ if (ret) {
+ kfree(vm);
+ return ret;
+ }
+
+ *pvm = vm;
+ return 0;
+}
+
+static int
+nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
+{
+ struct nouveau_vm_pgd *vpgd;
+ int i;
+
+ if (!pgd)
+ return 0;
+
+ vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
+ if (!vpgd)
+ return -ENOMEM;
+
+ nouveau_gpuobj_ref(pgd, &vpgd->obj);
+
+ mutex_lock(&vm->mm->mutex);
+ for (i = vm->fpde; i <= vm->lpde; i++)
+ vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
+ list_add(&vpgd->head, &vm->pgd_list);
+ mutex_unlock(&vm->mm->mutex);
+ return 0;
+}
+
+static void
+nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
+{
+ struct nouveau_vm_pgd *vpgd, *tmp;
+
+ if (!pgd)
+ return;
+
+ mutex_lock(&vm->mm->mutex);
+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+ if (vpgd->obj != pgd)
+ continue;
+
+ list_del(&vpgd->head);
+ nouveau_gpuobj_ref(NULL, &vpgd->obj);
+ kfree(vpgd);
+ }
+ mutex_unlock(&vm->mm->mutex);
+}
+
+static void
+nouveau_vm_del(struct nouveau_vm *vm)
+{
+ struct nouveau_vm_pgd *vpgd, *tmp;
+
+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+ nouveau_vm_unlink(vm, vpgd->obj);
+ }
+ WARN_ON(nouveau_mm_fini(&vm->mm) != 0);
+
+ kfree(vm->pgt);
+ kfree(vm);
+}
+
+int
+nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
+ struct nouveau_gpuobj *pgd)
+{
+ struct nouveau_vm *vm;
+ int ret;
+
+ vm = ref;
+ if (vm) {
+ ret = nouveau_vm_link(vm, pgd);
+ if (ret)
+ return ret;
+
+ vm->refcount++;
+ }
+
+ vm = *ptr;
+ *ptr = ref;
+
+ if (vm) {
+ nouveau_vm_unlink(vm, pgd);
+
+ if (--vm->refcount == 0)
+ nouveau_vm_del(vm);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h
new file mode 100644
index 000000000000..e1193515771b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_VM_H__
+#define __NOUVEAU_VM_H__
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+
+struct nouveau_vm_pgt {
+ struct nouveau_gpuobj *obj[2];
+ u32 refcount[2];
+};
+
+struct nouveau_vm_pgd {
+ struct list_head head;
+ struct nouveau_gpuobj *obj;
+};
+
+struct nouveau_vma {
+ struct nouveau_vm *vm;
+ struct nouveau_mm_node *node;
+ u64 offset;
+ u32 access;
+};
+
+struct nouveau_vm {
+ struct drm_device *dev;
+ struct nouveau_mm *mm;
+ int refcount;
+
+ struct list_head pgd_list;
+ atomic_t pgraph_refs;
+ atomic_t pcrypt_refs;
+
+ struct nouveau_vm_pgt *pgt;
+ u32 fpde;
+ u32 lpde;
+
+ u32 pgt_bits;
+ u8 spg_shift;
+ u8 lpg_shift;
+
+ void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde,
+ struct nouveau_gpuobj *pgt[2]);
+ void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *,
+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys);
+ void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *,
+ u32 pte, dma_addr_t *, u32 cnt);
+ void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt);
+ void (*flush)(struct nouveau_vm *);
+};
+
+/* nouveau_vm.c */
+int nouveau_vm_new(struct drm_device *, u64 offset, u64 length, u64 mm_offset,
+ struct nouveau_vm **);
+int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **,
+ struct nouveau_gpuobj *pgd);
+int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift,
+ u32 access, struct nouveau_vma *);
+void nouveau_vm_put(struct nouveau_vma *);
+void nouveau_vm_map(struct nouveau_vma *, struct nouveau_vram *);
+void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_vram *);
+void nouveau_vm_unmap(struct nouveau_vma *);
+void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
+void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length,
+ dma_addr_t *);
+
+/* nv50_vm.c */
+void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
+ struct nouveau_gpuobj *pgt[2]);
+void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *,
+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys);
+void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *,
+ u32 pte, dma_addr_t *, u32 cnt);
+void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt);
+void nv50_vm_flush(struct nouveau_vm *);
+void nv50_vm_flush_engine(struct drm_device *, int engine);
+
+/* nvc0_vm.c */
+void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
+ struct nouveau_gpuobj *pgt[2]);
+void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *,
+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys);
+void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *,
+ u32 pte, dma_addr_t *, u32 cnt);
+void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt);
+void nvc0_vm_flush(struct nouveau_vm *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index c71abc2a34d5..297505eb98d5 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -158,7 +158,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
- struct drm_connector *connector;
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
@@ -213,10 +212,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
NVVgaSeqReset(dev, nv_crtc->index, false);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
-
- /* Update connector polling modes */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- nouveau_connector_set_polling(connector);
}
static bool
@@ -556,7 +551,10 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
if (dev_priv->card_type >= NV_30)
regp->gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT);
- regp->crtc_cfg = NV_PCRTC_CONFIG_START_ADDRESS_HSYNC;
+ if (dev_priv->card_type >= NV_10)
+ regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC;
+ else
+ regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC;
/* Some misc regs */
if (dev_priv->card_type == NV_40) {
@@ -674,6 +672,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc)
if (nv_two_heads(dev))
NVSetOwner(dev, nv_crtc->index);
+ drm_vblank_pre_modeset(dev, nv_crtc->index);
funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
NVBlankScreen(dev, nv_crtc->index, true);
@@ -706,6 +705,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc)
#endif
funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+ drm_vblank_post_modeset(dev, nv_crtc->index);
}
static void nv_crtc_destroy(struct drm_crtc *crtc)
@@ -831,7 +831,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
/* Update the framebuffer location. */
regp->fb_start = nv_crtc->fb.offset & ~3;
regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
- NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
+ nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
/* Update the arbitration parameters. */
nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
@@ -991,6 +991,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
.cursor_move = nv04_crtc_cursor_move,
.gamma_set = nv_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
+ .page_flip = nouveau_crtc_page_flip,
.destroy = nv_crtc_destroy,
};
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index ba6423f2ffcc..e000455e06d0 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -74,14 +74,14 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2])
* use a 10ms timeout (guards against crtc being inactive, in
* which case blank state would never change)
*/
- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000000))
+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000000))
return -EBUSY;
- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000001))
+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000001))
return -EBUSY;
- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000000))
+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000000))
return -EBUSY;
udelay(100);
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index c936403b26e2..ef23550407b5 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
- /* For internal panels and gpu scaling on DVI we need the native mode */
- if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
- if (!nv_connector->native_mode)
- return false;
+ if (!nv_connector->native_mode ||
+ nv_connector->scaling_mode == DRM_MODE_SCALE_NONE ||
+ mode->hdisplay > nv_connector->native_mode->hdisplay ||
+ mode->vdisplay > nv_connector->native_mode->vdisplay) {
+ nv_encoder->mode = *adjusted_mode;
+
+ } else {
nv_encoder->mode = *nv_connector->native_mode;
adjusted_mode->clock = nv_connector->native_mode->clock;
- } else {
- nv_encoder->mode = *adjusted_mode;
}
return true;
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index 9e28cf772e3c..1715e1464b7d 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -32,6 +32,9 @@
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
+static void nv04_vblank_crtc0_isr(struct drm_device *);
+static void nv04_vblank_crtc1_isr(struct drm_device *);
+
static void
nv04_display_store_initial_head_owner(struct drm_device *dev)
{
@@ -197,6 +200,8 @@ nv04_display_create(struct drm_device *dev)
func->save(encoder);
}
+ nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr);
+ nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr);
return 0;
}
@@ -208,6 +213,9 @@ nv04_display_destroy(struct drm_device *dev)
NV_DEBUG_KMS(dev, "\n");
+ nouveau_irq_unregister(dev, 24);
+ nouveau_irq_unregister(dev, 25);
+
/* Turn every CRTC off. */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_mode_set modeset = {
@@ -258,3 +266,16 @@ nv04_display_init(struct drm_device *dev)
return 0;
}
+static void
+nv04_vblank_crtc0_isr(struct drm_device *dev)
+{
+ nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
+ drm_handle_vblank(dev, 0);
+}
+
+static void
+nv04_vblank_crtc1_isr(struct drm_device *dev)
+{
+ nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
+ drm_handle_vblank(dev, 1);
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 33e4c9388bc1..7a1189371096 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -28,52 +28,39 @@
#include "nouveau_ramht.h"
#include "nouveau_fbcon.h"
-void
+int
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) {
- nouveau_fbcon_gpu_lockup(info);
- }
-
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_copyarea(info, region);
- return;
- }
+ ret = RING_SPACE(chan, 4);
+ if (ret)
+ return ret;
BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3);
OUT_RING(chan, (region->sy << 16) | region->sx);
OUT_RING(chan, (region->dy << 16) | region->dx);
OUT_RING(chan, (region->height << 16) | region->width);
FIRE_RING(chan);
+ return 0;
}
-void
+int
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) {
- nouveau_fbcon_gpu_lockup(info);
- }
-
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_fillrect(info, rect);
- return;
- }
+ ret = RING_SPACE(chan, 7);
+ if (ret)
+ return ret;
BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1);
OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
@@ -87,9 +74,10 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
OUT_RING(chan, (rect->dx << 16) | rect->dy);
OUT_RING(chan, (rect->width << 16) | rect->height);
FIRE_RING(chan);
+ return 0;
}
-void
+int
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
@@ -101,23 +89,14 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
uint32_t dsize;
uint32_t width;
uint32_t *data = (uint32_t *)image->data;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (image->depth != 1) {
- cfb_imageblit(info, image);
- return;
- }
-
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) {
- nouveau_fbcon_gpu_lockup(info);
- }
+ if (image->depth != 1)
+ return -ENODEV;
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_imageblit(info, image);
- return;
- }
+ ret = RING_SPACE(chan, 8);
+ if (ret)
+ return ret;
width = ALIGN(image->width, 8);
dsize = ALIGN(width * image->height, 32) >> 5;
@@ -144,11 +123,9 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
while (dsize) {
int iter_len = dsize > 128 ? 128 : dsize;
- if (RING_SPACE(chan, iter_len + 1)) {
- nouveau_fbcon_gpu_lockup(info);
- cfb_imageblit(info, image);
- return;
- }
+ ret = RING_SPACE(chan, iter_len + 1);
+ if (ret)
+ return ret;
BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len);
OUT_RINGp(chan, data, iter_len);
@@ -157,22 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
}
FIRE_RING(chan);
-}
-
-static int
-nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *obj = NULL;
- int ret;
-
- ret = nouveau_gpuobj_gr_new(dev_priv->channel, class, &obj);
- if (ret)
- return ret;
-
- ret = nouveau_ramht_insert(dev_priv->channel, handle, obj);
- nouveau_gpuobj_ref(NULL, &obj);
- return ret;
+ return 0;
}
int
@@ -214,29 +176,31 @@ nv04_fbcon_accel_init(struct fb_info *info)
return -EINVAL;
}
- ret = nv04_fbcon_grobj_new(dev, dev_priv->card_type >= NV_10 ?
- 0x0062 : 0x0042, NvCtxSurf2D);
+ ret = nouveau_gpuobj_gr_new(chan, NvCtxSurf2D,
+ dev_priv->card_type >= NV_10 ?
+ 0x0062 : 0x0042);
if (ret)
return ret;
- ret = nv04_fbcon_grobj_new(dev, 0x0019, NvClipRect);
+ ret = nouveau_gpuobj_gr_new(chan, NvClipRect, 0x0019);
if (ret)
return ret;
- ret = nv04_fbcon_grobj_new(dev, 0x0043, NvRop);
+ ret = nouveau_gpuobj_gr_new(chan, NvRop, 0x0043);
if (ret)
return ret;
- ret = nv04_fbcon_grobj_new(dev, 0x0044, NvImagePatt);
+ ret = nouveau_gpuobj_gr_new(chan, NvImagePatt, 0x0044);
if (ret)
return ret;
- ret = nv04_fbcon_grobj_new(dev, 0x004a, NvGdiRect);
+ ret = nouveau_gpuobj_gr_new(chan, NvGdiRect, 0x004a);
if (ret)
return ret;
- ret = nv04_fbcon_grobj_new(dev, dev_priv->chipset >= 0x11 ?
- 0x009f : 0x005f, NvImageBlit);
+ ret = nouveau_gpuobj_gr_new(chan, NvImageBlit,
+ dev_priv->chipset >= 0x11 ?
+ 0x009f : 0x005f);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 708293b7ddcd..f89d104698df 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -28,6 +28,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_ramht.h"
+#include "nouveau_util.h"
#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
#define NV04_RAMFC__SIZE 32
@@ -128,6 +129,11 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV03_USER(chan->id), PAGE_SIZE);
+ if (!chan->user)
+ return -ENOMEM;
+
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
/* Setup initial state */
@@ -151,10 +157,31 @@ void
nv04_fifo_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ unsigned long flags;
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pfifo->reassign(dev, false);
+ /* Unload the context if it's the currently active one */
+ if (pfifo->channel_id(dev) == chan->id) {
+ pfifo->disable(dev);
+ pfifo->unload_context(dev);
+ pfifo->enable(dev);
+ }
+
+ /* Keep it from being rescheduled */
+ nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0);
+
+ pfifo->reassign(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the channel resources */
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
+ }
nouveau_gpuobj_ref(NULL, &chan->ramfc);
}
@@ -208,7 +235,7 @@ nv04_fifo_unload_context(struct drm_device *dev)
if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
return 0;
- chan = dev_priv->fifos[chid];
+ chan = dev_priv->channels.ptr[chid];
if (!chan) {
NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid);
return -EINVAL;
@@ -267,6 +294,7 @@ nv04_fifo_init_ramxx(struct drm_device *dev)
static void
nv04_fifo_init_intr(struct drm_device *dev)
{
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xffffffff);
}
@@ -289,7 +317,7 @@ nv04_fifo_init(struct drm_device *dev)
pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->fifos[i]) {
+ if (dev_priv->channels.ptr[i]) {
uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
}
@@ -298,3 +326,207 @@ nv04_fifo_init(struct drm_device *dev)
return 0;
}
+void
+nv04_fifo_fini(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x2140, 0x00000000);
+ nouveau_irq_unregister(dev, 8);
+}
+
+static bool
+nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = NULL;
+ struct nouveau_gpuobj *obj;
+ unsigned long flags;
+ const int subc = (addr >> 13) & 0x7;
+ const int mthd = addr & 0x1ffc;
+ bool handled = false;
+ u32 engine;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels))
+ chan = dev_priv->channels.ptr[chid];
+ if (unlikely(!chan))
+ goto out;
+
+ switch (mthd) {
+ case 0x0000: /* bind object to subchannel */
+ obj = nouveau_ramht_find(chan, data);
+ if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW))
+ break;
+
+ chan->sw_subchannel[subc] = obj->class;
+ engine = 0x0000000f << (subc * 4);
+
+ nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000);
+ handled = true;
+ break;
+ default:
+ engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE);
+ if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
+ break;
+
+ if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc],
+ mthd, data))
+ handled = true;
+ break;
+ }
+
+out:
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return handled;
+}
+
+void
+nv04_fifo_isr(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_engine *engine = &dev_priv->engine;
+ uint32_t status, reassign;
+ int cnt = 0;
+
+ reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
+ while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
+ uint32_t chid, get;
+
+ nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+
+ chid = engine->fifo.channel_id(dev);
+ get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
+
+ if (status & NV_PFIFO_INTR_CACHE_ERROR) {
+ uint32_t mthd, data;
+ int ptr;
+
+ /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
+ * wrapping on my G80 chips, but CACHE1 isn't big
+ * enough for this much data.. Tests show that it
+ * wraps around to the start at GET=0x800.. No clue
+ * as to why..
+ */
+ ptr = (get & 0x7ff) >> 2;
+
+ if (dev_priv->card_type < NV_40) {
+ mthd = nv_rd32(dev,
+ NV04_PFIFO_CACHE1_METHOD(ptr));
+ data = nv_rd32(dev,
+ NV04_PFIFO_CACHE1_DATA(ptr));
+ } else {
+ mthd = nv_rd32(dev,
+ NV40_PFIFO_CACHE1_METHOD(ptr));
+ data = nv_rd32(dev,
+ NV40_PFIFO_CACHE1_DATA(ptr));
+ }
+
+ if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) {
+ NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
+ "Mthd 0x%04x Data 0x%08x\n",
+ chid, (mthd >> 13) & 7, mthd & 0x1ffc,
+ data);
+ }
+
+ nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
+ nv_wr32(dev, NV03_PFIFO_INTR_0,
+ NV_PFIFO_INTR_CACHE_ERROR);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
+ nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
+ nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
+
+ nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
+ nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+
+ status &= ~NV_PFIFO_INTR_CACHE_ERROR;
+ }
+
+ if (status & NV_PFIFO_INTR_DMA_PUSHER) {
+ u32 dma_get = nv_rd32(dev, 0x003244);
+ u32 dma_put = nv_rd32(dev, 0x003240);
+ u32 push = nv_rd32(dev, 0x003220);
+ u32 state = nv_rd32(dev, 0x003228);
+
+ if (dev_priv->card_type == NV_50) {
+ u32 ho_get = nv_rd32(dev, 0x003328);
+ u32 ho_put = nv_rd32(dev, 0x003320);
+ u32 ib_get = nv_rd32(dev, 0x003334);
+ u32 ib_put = nv_rd32(dev, 0x003330);
+
+ if (nouveau_ratelimit())
+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+ "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
+ "State 0x%08x Push 0x%08x\n",
+ chid, ho_get, dma_get, ho_put,
+ dma_put, ib_get, ib_put, state,
+ push);
+
+ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+ nv_wr32(dev, 0x003364, 0x00000000);
+ if (dma_get != dma_put || ho_get != ho_put) {
+ nv_wr32(dev, 0x003244, dma_put);
+ nv_wr32(dev, 0x003328, ho_put);
+ } else
+ if (ib_get != ib_put) {
+ nv_wr32(dev, 0x003334, ib_put);
+ }
+ } else {
+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
+ "Put 0x%08x State 0x%08x Push 0x%08x\n",
+ chid, dma_get, dma_put, state, push);
+
+ if (dma_get != dma_put)
+ nv_wr32(dev, 0x003244, dma_put);
+ }
+
+ nv_wr32(dev, 0x003228, 0x00000000);
+ nv_wr32(dev, 0x003220, 0x00000001);
+ nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+ status &= ~NV_PFIFO_INTR_DMA_PUSHER;
+ }
+
+ if (status & NV_PFIFO_INTR_SEMAPHORE) {
+ uint32_t sem;
+
+ status &= ~NV_PFIFO_INTR_SEMAPHORE;
+ nv_wr32(dev, NV03_PFIFO_INTR_0,
+ NV_PFIFO_INTR_SEMAPHORE);
+
+ sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
+ nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+ }
+
+ if (dev_priv->card_type == NV_50) {
+ if (status & 0x00000010) {
+ nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
+ status &= ~0x00000010;
+ nv_wr32(dev, 0x002100, 0x00000010);
+ }
+ }
+
+ if (status) {
+ if (nouveau_ratelimit())
+ NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
+ status, chid);
+ nv_wr32(dev, NV03_PFIFO_INTR_0, status);
+ status = 0;
+ }
+
+ nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
+ }
+
+ if (status) {
+ NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
+ nv_wr32(dev, 0x2140, 0);
+ nv_wr32(dev, 0x140, 0);
+ }
+
+ nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index c8973421b635..af75015068d6 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -26,6 +26,11 @@
#include "drm.h"
#include "nouveau_drm.h"
#include "nouveau_drv.h"
+#include "nouveau_hw.h"
+#include "nouveau_util.h"
+
+static int nv04_graph_register(struct drm_device *dev);
+static void nv04_graph_isr(struct drm_device *dev);
static uint32_t nv04_graph_ctx_regs[] = {
0x0040053c,
@@ -357,10 +362,10 @@ nv04_graph_channel(struct drm_device *dev)
if (chid >= dev_priv->engine.fifo.channels)
return NULL;
- return dev_priv->fifos[chid];
+ return dev_priv->channels.ptr[chid];
}
-void
+static void
nv04_graph_context_switch(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -368,7 +373,6 @@ nv04_graph_context_switch(struct drm_device *dev)
struct nouveau_channel *chan = NULL;
int chid;
- pgraph->fifo_access(dev, false);
nouveau_wait_for_idle(dev);
/* If previous context is valid, we need to save it */
@@ -376,11 +380,9 @@ nv04_graph_context_switch(struct drm_device *dev)
/* Load context for next channel */
chid = dev_priv->engine.fifo.channel_id(dev);
- chan = dev_priv->fifos[chid];
+ chan = dev_priv->channels.ptr[chid];
if (chan)
nv04_graph_load_context(chan);
-
- pgraph->fifo_access(dev, true);
}
static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
@@ -412,10 +414,25 @@ int nv04_graph_create_context(struct nouveau_channel *chan)
void nv04_graph_destroy_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pgraph->fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (pgraph->channel(dev) == chan)
+ pgraph->unload_context(dev);
+ /* Free the context resources */
kfree(pgraph_ctx);
chan->pgraph_ctx = NULL;
+
+ pgraph->fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
int nv04_graph_load_context(struct nouveau_channel *chan)
@@ -468,13 +485,19 @@ int nv04_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t tmp;
+ int ret;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
+ ret = nv04_graph_register(dev);
+ if (ret)
+ return ret;
+
/* Enable PGRAPH interrupts */
+ nouveau_irq_register(dev, 12, nv04_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -510,6 +533,8 @@ int nv04_graph_init(struct drm_device *dev)
void nv04_graph_takedown(struct drm_device *dev)
{
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
+ nouveau_irq_unregister(dev, 12);
}
void
@@ -524,13 +549,27 @@ nv04_graph_fifo_access(struct drm_device *dev, bool enabled)
}
static int
-nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
atomic_set(&chan->fence.last_sequence_irq, data);
return 0;
}
+int
+nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_page_flip_state s;
+
+ if (!nouveau_finish_page_flip(chan, &s))
+ nv_set_crtc_base(dev, s.crtc,
+ s.offset + s.y * s.pitch + s.x * s.bpp / 8);
+
+ return 0;
+}
+
/*
* Software methods, why they are needed, and how they all work:
*
@@ -606,12 +645,12 @@ nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
*/
static void
-nv04_graph_set_ctx1(struct nouveau_channel *chan, uint32_t mask, uint32_t value)
+nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value)
{
struct drm_device *dev = chan->dev;
- uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
+ u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
- uint32_t tmp;
+ u32 tmp;
tmp = nv_ri32(dev, instance);
tmp &= ~mask;
@@ -623,11 +662,11 @@ nv04_graph_set_ctx1(struct nouveau_channel *chan, uint32_t mask, uint32_t value)
}
static void
-nv04_graph_set_ctx_val(struct nouveau_channel *chan, uint32_t mask, uint32_t value)
+nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value)
{
struct drm_device *dev = chan->dev;
- uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
- uint32_t tmp, ctx1;
+ u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
+ u32 tmp, ctx1;
int class, op, valid = 1;
ctx1 = nv_ri32(dev, instance);
@@ -672,13 +711,13 @@ nv04_graph_set_ctx_val(struct nouveau_channel *chan, uint32_t mask, uint32_t val
}
static int
-nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_set_operation(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
if (data > 5)
return 1;
/* Old versions of the objects only accept first three operations. */
- if (data > 2 && grclass < 0x40)
+ if (data > 2 && class < 0x40)
return 1;
nv04_graph_set_ctx1(chan, 0x00038000, data << 15);
/* changing operation changes set of objects needed for validation */
@@ -687,8 +726,8 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
uint32_t min = data & 0xffff, max;
uint32_t w = data >> 16;
@@ -706,8 +745,8 @@ nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
uint32_t min = data & 0xffff, max;
uint32_t w = data >> 16;
@@ -725,8 +764,8 @@ nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -742,8 +781,8 @@ nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -763,8 +802,8 @@ nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -778,8 +817,8 @@ nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -793,8 +832,8 @@ nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_rop(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -808,8 +847,8 @@ nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -823,8 +862,8 @@ nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -838,8 +877,8 @@ nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -853,8 +892,8 @@ nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -868,8 +907,8 @@ nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -883,8 +922,8 @@ nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -898,8 +937,8 @@ nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_clip(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -913,8 +952,8 @@ nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, int grclass,
}
static int
-nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
switch (nv_ri32(chan->dev, data << 4) & 0xff) {
case 0x30:
@@ -930,194 +969,346 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, int grclass,
return 1;
}
-static struct nouveau_pgraph_object_method nv04_graph_mthds_sw[] = {
- { 0x0150, nv04_graph_mthd_set_ref },
- {}
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_gdirect[] = {
- { 0x0184, nv04_graph_mthd_bind_nv01_patt },
- { 0x0188, nv04_graph_mthd_bind_rop },
- { 0x018c, nv04_graph_mthd_bind_beta1 },
- { 0x0190, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_gdirect[] = {
- { 0x0188, nv04_graph_mthd_bind_nv04_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_imageblit[] = {
- { 0x0184, nv04_graph_mthd_bind_chroma },
- { 0x0188, nv04_graph_mthd_bind_clip },
- { 0x018c, nv04_graph_mthd_bind_nv01_patt },
- { 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x019c, nv04_graph_mthd_bind_surf_src },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_imageblit_ifc[] = {
- { 0x0184, nv04_graph_mthd_bind_chroma },
- { 0x0188, nv04_graph_mthd_bind_clip },
- { 0x018c, nv04_graph_mthd_bind_nv04_patt },
- { 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, nv04_graph_mthd_bind_beta4 },
- { 0x019c, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_iifc[] = {
- { 0x0188, nv04_graph_mthd_bind_chroma },
- { 0x018c, nv04_graph_mthd_bind_clip },
- { 0x0190, nv04_graph_mthd_bind_nv04_patt },
- { 0x0194, nv04_graph_mthd_bind_rop },
- { 0x0198, nv04_graph_mthd_bind_beta1 },
- { 0x019c, nv04_graph_mthd_bind_beta4 },
- { 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
- { 0x03e4, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_ifc[] = {
- { 0x0184, nv04_graph_mthd_bind_chroma },
- { 0x0188, nv04_graph_mthd_bind_clip },
- { 0x018c, nv04_graph_mthd_bind_nv01_patt },
- { 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifc[] = {
- { 0x0184, nv04_graph_mthd_bind_chroma },
- { 0x0188, nv04_graph_mthd_bind_nv01_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifc[] = {
- { 0x0184, nv04_graph_mthd_bind_chroma },
- { 0x0188, nv04_graph_mthd_bind_nv04_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifm[] = {
- { 0x0188, nv04_graph_mthd_bind_nv01_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x0304, nv04_graph_mthd_set_operation },
- {},
-};
-
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifm[] = {
- { 0x0188, nv04_graph_mthd_bind_nv04_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf },
- { 0x0304, nv04_graph_mthd_set_operation },
- {},
-};
+static int
+nv04_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_shape[] = {
- { 0x0184, nv04_graph_mthd_bind_clip },
- { 0x0188, nv04_graph_mthd_bind_nv01_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
-};
+ if (dev_priv->engine.graph.registered)
+ return 0;
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_shape[] = {
- { 0x0184, nv04_graph_mthd_bind_clip },
- { 0x0188, nv04_graph_mthd_bind_nv04_patt },
- { 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, nv04_graph_mthd_set_operation },
- {},
+ /* dvd subpicture */
+ NVOBJ_CLASS(dev, 0x0038, GR);
+
+ /* m2mf */
+ NVOBJ_CLASS(dev, 0x0039, GR);
+
+ /* nv03 gdirect */
+ NVOBJ_CLASS(dev, 0x004b, GR);
+ NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 gdirect */
+ NVOBJ_CLASS(dev, 0x004a, GR);
+ NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv01 imageblit */
+ NVOBJ_CLASS(dev, 0x001f, GR);
+ NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src);
+ NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 imageblit */
+ NVOBJ_CLASS(dev, 0x005f, GR);
+ NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 iifc */
+ NVOBJ_CLASS(dev, 0x0060, GR);
+ NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf);
+ NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation);
+
+ /* nv05 iifc */
+ NVOBJ_CLASS(dev, 0x0064, GR);
+
+ /* nv01 ifc */
+ NVOBJ_CLASS(dev, 0x0021, GR);
+ NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 ifc */
+ NVOBJ_CLASS(dev, 0x0061, GR);
+ NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv05 ifc */
+ NVOBJ_CLASS(dev, 0x0065, GR);
+
+ /* nv03 sifc */
+ NVOBJ_CLASS(dev, 0x0036, GR);
+ NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 sifc */
+ NVOBJ_CLASS(dev, 0x0076, GR);
+ NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma);
+ NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv05 sifc */
+ NVOBJ_CLASS(dev, 0x0066, GR);
+
+ /* nv03 sifm */
+ NVOBJ_CLASS(dev, 0x0037, GR);
+ NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation);
+
+ /* nv04 sifm */
+ NVOBJ_CLASS(dev, 0x0077, GR);
+ NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf);
+ NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation);
+
+ /* null */
+ NVOBJ_CLASS(dev, 0x0030, GR);
+
+ /* surf2d */
+ NVOBJ_CLASS(dev, 0x0042, GR);
+
+ /* rop */
+ NVOBJ_CLASS(dev, 0x0043, GR);
+
+ /* beta1 */
+ NVOBJ_CLASS(dev, 0x0012, GR);
+
+ /* beta4 */
+ NVOBJ_CLASS(dev, 0x0072, GR);
+
+ /* cliprect */
+ NVOBJ_CLASS(dev, 0x0019, GR);
+
+ /* nv01 pattern */
+ NVOBJ_CLASS(dev, 0x0018, GR);
+
+ /* nv04 pattern */
+ NVOBJ_CLASS(dev, 0x0044, GR);
+
+ /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0052, GR);
+
+ /* surf3d */
+ NVOBJ_CLASS(dev, 0x0053, GR);
+ NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h);
+ NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v);
+
+ /* nv03 tex_tri */
+ NVOBJ_CLASS(dev, 0x0048, GR);
+ NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color);
+ NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta);
+
+ /* tex_tri */
+ NVOBJ_CLASS(dev, 0x0054, GR);
+
+ /* multitex_tri */
+ NVOBJ_CLASS(dev, 0x0055, GR);
+
+ /* nv01 chroma */
+ NVOBJ_CLASS(dev, 0x0017, GR);
+
+ /* nv04 chroma */
+ NVOBJ_CLASS(dev, 0x0057, GR);
+
+ /* surf_dst */
+ NVOBJ_CLASS(dev, 0x0058, GR);
+
+ /* surf_src */
+ NVOBJ_CLASS(dev, 0x0059, GR);
+
+ /* surf_color */
+ NVOBJ_CLASS(dev, 0x005a, GR);
+
+ /* surf_zeta */
+ NVOBJ_CLASS(dev, 0x005b, GR);
+
+ /* nv01 line */
+ NVOBJ_CLASS(dev, 0x001c, GR);
+ NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 line */
+ NVOBJ_CLASS(dev, 0x005c, GR);
+ NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv01 tri */
+ NVOBJ_CLASS(dev, 0x001d, GR);
+ NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 tri */
+ NVOBJ_CLASS(dev, 0x005d, GR);
+ NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv01 rect */
+ NVOBJ_CLASS(dev, 0x001e, GR);
+ NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt);
+ NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst);
+ NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nv04 rect */
+ NVOBJ_CLASS(dev, 0x005e, GR);
+ NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip);
+ NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt);
+ NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop);
+ NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1);
+ NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4);
+ NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d);
+ NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ dev_priv->engine.graph.registered = true;
+ return 0;
};
-static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_tex_tri[] = {
- { 0x0188, nv04_graph_mthd_bind_clip },
- { 0x018c, nv04_graph_mthd_bind_surf_color },
- { 0x0190, nv04_graph_mthd_bind_surf_zeta },
- {},
+static struct nouveau_bitfield nv04_graph_intr[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ {}
};
-static struct nouveau_pgraph_object_method nv04_graph_mthds_surf3d[] = {
- { 0x02f8, nv04_graph_mthd_surf3d_clip_h },
- { 0x02fc, nv04_graph_mthd_surf3d_clip_v },
- {},
+static struct nouveau_bitfield nv04_graph_nstatus[] =
+{
+ { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
+ {}
};
-struct nouveau_pgraph_object_class nv04_graph_grclass[] = {
- { 0x0038, false, NULL }, /* dvd subpicture */
- { 0x0039, false, NULL }, /* m2mf */
- { 0x004b, false, nv04_graph_mthds_nv03_gdirect }, /* nv03 gdirect */
- { 0x004a, false, nv04_graph_mthds_nv04_gdirect }, /* nv04 gdirect */
- { 0x001f, false, nv04_graph_mthds_nv01_imageblit }, /* nv01 imageblit */
- { 0x005f, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 imageblit */
- { 0x0060, false, nv04_graph_mthds_nv04_iifc }, /* nv04 iifc */
- { 0x0064, false, NULL }, /* nv05 iifc */
- { 0x0021, false, nv04_graph_mthds_nv01_ifc }, /* nv01 ifc */
- { 0x0061, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 ifc */
- { 0x0065, false, NULL }, /* nv05 ifc */
- { 0x0036, false, nv04_graph_mthds_nv03_sifc }, /* nv03 sifc */
- { 0x0076, false, nv04_graph_mthds_nv04_sifc }, /* nv04 sifc */
- { 0x0066, false, NULL }, /* nv05 sifc */
- { 0x0037, false, nv04_graph_mthds_nv03_sifm }, /* nv03 sifm */
- { 0x0077, false, nv04_graph_mthds_nv04_sifm }, /* nv04 sifm */
- { 0x0030, false, NULL }, /* null */
- { 0x0042, false, NULL }, /* surf2d */
- { 0x0043, false, NULL }, /* rop */
- { 0x0012, false, NULL }, /* beta1 */
- { 0x0072, false, NULL }, /* beta4 */
- { 0x0019, false, NULL }, /* cliprect */
- { 0x0018, false, NULL }, /* nv01 pattern */
- { 0x0044, false, NULL }, /* nv04 pattern */
- { 0x0052, false, NULL }, /* swzsurf */
- { 0x0053, false, nv04_graph_mthds_surf3d }, /* surf3d */
- { 0x0048, false, nv04_graph_mthds_nv03_tex_tri }, /* nv03 tex_tri */
- { 0x0054, false, NULL }, /* tex_tri */
- { 0x0055, false, NULL }, /* multitex_tri */
- { 0x0017, false, NULL }, /* nv01 chroma */
- { 0x0057, false, NULL }, /* nv04 chroma */
- { 0x0058, false, NULL }, /* surf_dst */
- { 0x0059, false, NULL }, /* surf_src */
- { 0x005a, false, NULL }, /* surf_color */
- { 0x005b, false, NULL }, /* surf_zeta */
- { 0x001c, false, nv04_graph_mthds_nv01_shape }, /* nv01 line */
- { 0x005c, false, nv04_graph_mthds_nv04_shape }, /* nv04 line */
- { 0x001d, false, nv04_graph_mthds_nv01_shape }, /* nv01 tri */
- { 0x005d, false, nv04_graph_mthds_nv04_shape }, /* nv04 tri */
- { 0x001e, false, nv04_graph_mthds_nv01_shape }, /* nv01 rect */
- { 0x005e, false, nv04_graph_mthds_nv04_shape }, /* nv04 rect */
- { 0x506e, true, nv04_graph_mthds_sw },
+struct nouveau_bitfield nv04_graph_nsource[] =
+{
+ { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
+ { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
+ { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
+ { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
+ { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
+ { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
+ { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
+ { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
+ { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
{}
};
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x0f000000) >> 24;
+ u32 subc = (addr & 0x0000e000) >> 13;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_NOTIFY) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_NOTIFY;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv04_graph_context_switch(dev);
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv04_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, subc, class, mthd, data);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index 0b5ae297abde..b8e3edb5c063 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -98,42 +98,66 @@ nv04_instmem_takedown(struct drm_device *dev)
}
int
-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
- uint32_t *sz)
+nv04_instmem_suspend(struct drm_device *dev)
{
return 0;
}
void
-nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
-{
-}
-
-int
-nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+nv04_instmem_resume(struct drm_device *dev)
{
- return 0;
}
int
-nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+nv04_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align)
{
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct drm_mm_node *ramin = NULL;
+
+ do {
+ if (drm_mm_pre_get(&dev_priv->ramin_heap))
+ return -ENOMEM;
+
+ spin_lock(&dev_priv->ramin_lock);
+ ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0);
+ if (ramin == NULL) {
+ spin_unlock(&dev_priv->ramin_lock);
+ return -ENOMEM;
+ }
+
+ ramin = drm_mm_get_block_atomic(ramin, size, align);
+ spin_unlock(&dev_priv->ramin_lock);
+ } while (ramin == NULL);
+
+ gpuobj->node = ramin;
+ gpuobj->vinst = ramin->start;
return 0;
}
void
-nv04_instmem_flush(struct drm_device *dev)
+nv04_instmem_put(struct nouveau_gpuobj *gpuobj)
{
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+
+ spin_lock(&dev_priv->ramin_lock);
+ drm_mm_put_block(gpuobj->node);
+ gpuobj->node = NULL;
+ spin_unlock(&dev_priv->ramin_lock);
}
int
-nv04_instmem_suspend(struct drm_device *dev)
+nv04_instmem_map(struct nouveau_gpuobj *gpuobj)
{
+ gpuobj->pinst = gpuobj->vinst;
return 0;
}
void
-nv04_instmem_resume(struct drm_device *dev)
+nv04_instmem_unmap(struct nouveau_gpuobj *gpuobj)
{
}
+void
+nv04_instmem_flush(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
index 6a6eb697d38e..eb1c70dd82ed 100644
--- a/drivers/gpu/drm/nouveau/nv04_pm.c
+++ b/drivers/gpu/drm/nouveau/nv04_pm.c
@@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
reg += 4;
nouveau_hw_setpll(dev, reg, &state->calc);
+
+ if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
+ if (dev_priv->card_type == NV_20)
+ nv_mask(dev, 0x1002c4, 0, 1 << 20);
+
+ /* Reset the DLLs */
+ nv_mask(dev, 0x1002c0, 0, 1 << 8);
+ }
+
kfree(state);
}
diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c
index cc5cda44e501..f78181a59b4a 100644
--- a/drivers/gpu/drm/nouveau/nv10_fb.c
+++ b/drivers/gpu/drm/nouveau/nv10_fb.c
@@ -3,23 +3,109 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+static struct drm_mm_node *
+nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ struct drm_mm_node *mem;
+ int ret;
+
+ ret = drm_mm_pre_get(&pfb->tag_heap);
+ if (ret)
+ return NULL;
+
+ spin_lock(&dev_priv->tile.lock);
+ mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
+ if (mem)
+ mem = drm_mm_get_block_atomic(mem, size, 0);
+ spin_unlock(&dev_priv->tile.lock);
+
+ return mem;
+}
+
+static void
+nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ spin_lock(&dev_priv->tile.lock);
+ drm_mm_put_block(mem);
+ spin_unlock(&dev_priv->tile.lock);
+}
+
+void
+nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
+ uint32_t size, uint32_t pitch, uint32_t flags)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+ int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
+
+ tile->addr = addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+
+ if (dev_priv->card_type == NV_20) {
+ if (flags & NOUVEAU_GEM_TILE_ZETA) {
+ /*
+ * Allocate some of the on-die tag memory,
+ * used to store Z compression meta-data (most
+ * likely just a bitmap determining if a given
+ * tile is compressed or not).
+ */
+ tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
+
+ if (tile->tag_mem) {
+ /* Enable Z compression */
+ if (dev_priv->chipset >= 0x25)
+ tile->zcomp = tile->tag_mem->start |
+ (bpp == 16 ?
+ NV25_PFB_ZCOMP_MODE_16 :
+ NV25_PFB_ZCOMP_MODE_32);
+ else
+ tile->zcomp = tile->tag_mem->start |
+ NV20_PFB_ZCOMP_EN |
+ (bpp == 16 ? 0 :
+ NV20_PFB_ZCOMP_MODE_32);
+ }
+
+ tile->addr |= 3;
+ } else {
+ tile->addr |= 1;
+ }
+
+ } else {
+ tile->addr |= 1 << 31;
+ }
+}
+
void
-nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv10_fb_free_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t limit = max(1u, addr + size) - 1;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- if (pitch) {
- if (dev_priv->card_type >= NV_20)
- addr |= 1;
- else
- addr |= 1 << 31;
+ if (tile->tag_mem) {
+ nv20_fb_free_tag(dev, tile->tag_mem);
+ tile->tag_mem = NULL;
}
- nv_wr32(dev, NV10_PFB_TLIMIT(i), limit);
- nv_wr32(dev, NV10_PFB_TSIZE(i), pitch);
- nv_wr32(dev, NV10_PFB_TILE(i), addr);
+ tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
+}
+
+void
+nv10_fb_set_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
+
+ if (dev_priv->card_type == NV_20)
+ nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
}
int
@@ -31,9 +117,14 @@ nv10_fb_init(struct drm_device *dev)
pfb->num_tiles = NV10_PFB_TILE__SIZE;
+ if (dev_priv->card_type == NV_20)
+ drm_mm_init(&pfb->tag_heap, 0,
+ (dev_priv->chipset >= 0x25 ?
+ 64 * 1024 : 32 * 1024));
+
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->num_tiles; i++)
- pfb->set_region_tiling(dev, i, 0, 0, 0);
+ pfb->set_tile_region(dev, i);
return 0;
}
@@ -41,4 +132,13 @@ nv10_fb_init(struct drm_device *dev)
void
nv10_fb_takedown(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ int i;
+
+ for (i = 0; i < pfb->num_tiles; i++)
+ pfb->free_tile_region(dev, i);
+
+ if (dev_priv->card_type == NV_20)
+ drm_mm_takedown(&pfb->tag_heap);
}
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index f1b03ad58fd5..d2ecbff4bee1 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -53,6 +53,11 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV03_USER(chan->id), PAGE_SIZE);
+ if (!chan->user)
+ return -ENOMEM;
+
/* Fill entries that are seen filled in dumps of nvidia driver just
* after channel's is put into DMA mode
*/
@@ -73,17 +78,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
return 0;
}
-void
-nv10_fifo_destroy_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
-
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
-
- nouveau_gpuobj_ref(NULL, &chan->ramfc);
-}
-
static void
nv10_fifo_do_load_context(struct drm_device *dev, int chid)
{
@@ -219,6 +213,7 @@ nv10_fifo_init_ramxx(struct drm_device *dev)
static void
nv10_fifo_init_intr(struct drm_device *dev)
{
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xffffffff);
}
@@ -241,7 +236,7 @@ nv10_fifo_init(struct drm_device *dev)
pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->fifos[i]) {
+ if (dev_priv->channels.ptr[i]) {
uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
}
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 8e68c9731159..8c92edb7bbcd 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -26,6 +26,10 @@
#include "drm.h"
#include "nouveau_drm.h"
#include "nouveau_drv.h"
+#include "nouveau_util.h"
+
+static int nv10_graph_register(struct drm_device *);
+static void nv10_graph_isr(struct drm_device *);
#define NV10_FIFO_NUMBER 32
@@ -786,15 +790,13 @@ nv10_graph_unload_context(struct drm_device *dev)
return 0;
}
-void
+static void
nv10_graph_context_switch(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_channel *chan = NULL;
int chid;
- pgraph->fifo_access(dev, false);
nouveau_wait_for_idle(dev);
/* If previous context is valid, we need to save it */
@@ -802,11 +804,9 @@ nv10_graph_context_switch(struct drm_device *dev)
/* Load context for next channel */
chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
- chan = dev_priv->fifos[chid];
+ chan = dev_priv->channels.ptr[chid];
if (chan && chan->pgraph_ctx)
nv10_graph_load_context(chan);
-
- pgraph->fifo_access(dev, true);
}
#define NV_WRITE_CTX(reg, val) do { \
@@ -833,7 +833,7 @@ nv10_graph_channel(struct drm_device *dev)
if (chid >= dev_priv->engine.fifo.channels)
return NULL;
- return dev_priv->fifos[chid];
+ return dev_priv->channels.ptr[chid];
}
int nv10_graph_create_context(struct nouveau_channel *chan)
@@ -875,37 +875,54 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
void nv10_graph_destroy_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pgraph->fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (pgraph->channel(dev) == chan)
+ pgraph->unload_context(dev);
+ /* Free the context resources */
kfree(pgraph_ctx);
chan->pgraph_ctx = NULL;
+
+ pgraph->fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
void
-nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv10_graph_set_tile_region(struct drm_device *dev, int i)
{
- uint32_t limit = max(1u, addr + size) - 1;
-
- if (pitch)
- addr |= 1 << 31;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit);
- nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch);
- nv_wr32(dev, NV10_PGRAPH_TILE(i), addr);
+ nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
}
int nv10_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t tmp;
- int i;
+ int ret, i;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
+ ret = nv10_graph_register(dev);
+ if (ret)
+ return ret;
+
+ nouveau_irq_register(dev, 12, nv10_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -928,7 +945,7 @@ int nv10_graph_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
- nv10_graph_set_region_tiling(dev, i, 0, 0, 0);
+ nv10_graph_set_tile_region(dev, i);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
@@ -948,17 +965,17 @@ int nv10_graph_init(struct drm_device *dev)
void nv10_graph_takedown(struct drm_device *dev)
{
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
+ nouveau_irq_unregister(dev, 12);
}
static int
-nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
struct drm_device *dev = chan->dev;
struct graph_state *ctx = chan->pgraph_ctx;
struct pipe_state *pipe = &ctx->pipe_state;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
uint32_t xfmode0, xfmode1;
int i;
@@ -1025,18 +1042,14 @@ nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
nouveau_wait_for_idle(dev);
- pgraph->fifo_access(dev, true);
-
return 0;
}
static int
-nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
nouveau_wait_for_idle(dev);
@@ -1045,40 +1058,118 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
nv_wr32(dev, 0x004006b0,
nv_rd32(dev, 0x004006b0) | 0x8 << 24);
- pgraph->fifo_access(dev, true);
+ return 0;
+}
+
+static int
+nv10_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->engine.graph.registered)
+ return 0;
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+ NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+ NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+ /* celcius */
+ if (dev_priv->chipset <= 0x10) {
+ NVOBJ_CLASS(dev, 0x0056, GR);
+ } else
+ if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+ NVOBJ_CLASS(dev, 0x0096, GR);
+ } else {
+ NVOBJ_CLASS(dev, 0x0099, GR);
+ NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+ }
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ dev_priv->engine.graph.registered = true;
return 0;
}
-static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = {
- { 0x1638, nv17_graph_mthd_lma_window },
- { 0x163c, nv17_graph_mthd_lma_window },
- { 0x1640, nv17_graph_mthd_lma_window },
- { 0x1644, nv17_graph_mthd_lma_window },
- { 0x1658, nv17_graph_mthd_lma_enable },
+struct nouveau_bitfield nv10_graph_intr[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ { NV_PGRAPH_INTR_ERROR, "ERROR" },
{}
};
-struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
- { 0x0030, false, NULL }, /* null */
- { 0x0039, false, NULL }, /* m2mf */
- { 0x004a, false, NULL }, /* gdirect */
- { 0x005f, false, NULL }, /* imageblit */
- { 0x009f, false, NULL }, /* imageblit (nv12) */
- { 0x008a, false, NULL }, /* ifc */
- { 0x0089, false, NULL }, /* sifm */
- { 0x0062, false, NULL }, /* surf2d */
- { 0x0043, false, NULL }, /* rop */
- { 0x0012, false, NULL }, /* beta1 */
- { 0x0072, false, NULL }, /* beta4 */
- { 0x0019, false, NULL }, /* cliprect */
- { 0x0044, false, NULL }, /* pattern */
- { 0x0052, false, NULL }, /* swzsurf */
- { 0x0093, false, NULL }, /* surf3d */
- { 0x0094, false, NULL }, /* tex_tri */
- { 0x0095, false, NULL }, /* multitex_tri */
- { 0x0056, false, NULL }, /* celcius (nv10) */
- { 0x0096, false, NULL }, /* celcius (nv11) */
- { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */
+struct nouveau_bitfield nv10_graph_nstatus[] =
+{
+ { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
{}
};
+
+static void
+nv10_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x01f00000) >> 20;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv10_graph_context_switch(dev);
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv10_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, subc, class, mthd, data);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 12ab9cd56eca..8464b76798d5 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -32,6 +32,10 @@
#define NV34_GRCTX_SIZE (18140)
#define NV35_36_GRCTX_SIZE (22396)
+static int nv20_graph_register(struct drm_device *);
+static int nv30_graph_register(struct drm_device *);
+static void nv20_graph_isr(struct drm_device *);
+
static void
nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
@@ -425,9 +429,21 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ unsigned long flags;
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pgraph->fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (pgraph->channel(dev) == chan)
+ pgraph->unload_context(dev);
+
+ pgraph->fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
+ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
}
int
@@ -496,24 +512,27 @@ nv20_graph_rdi(struct drm_device *dev)
}
void
-nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv20_graph_set_tile_region(struct drm_device *dev, int i)
{
- uint32_t limit = max(1u, addr + size) - 1;
-
- if (pitch)
- addr |= 1;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit);
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch);
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr);
+
+ if (dev_priv->card_type == NV_20) {
+ nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp);
+ }
}
int
@@ -560,6 +579,13 @@ nv20_graph_init(struct drm_device *dev)
nv20_graph_rdi(dev);
+ ret = nv20_graph_register(dev);
+ if (ret) {
+ nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
+ return ret;
+ }
+
+ nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -571,16 +597,17 @@ nv20_graph_init(struct drm_device *dev)
nv_wr32(dev, 0x40009C , 0x00000040);
if (dev_priv->chipset >= 0x25) {
- nv_wr32(dev, 0x400890, 0x00080000);
+ nv_wr32(dev, 0x400890, 0x00a8cfff);
nv_wr32(dev, 0x400610, 0x304B1FB6);
- nv_wr32(dev, 0x400B80, 0x18B82880);
+ nv_wr32(dev, 0x400B80, 0x1cbd3883);
nv_wr32(dev, 0x400B84, 0x44000000);
nv_wr32(dev, 0x400098, 0x40000080);
nv_wr32(dev, 0x400B88, 0x000000ff);
+
} else {
- nv_wr32(dev, 0x400880, 0x00080000); /* 0x0008c7df */
+ nv_wr32(dev, 0x400880, 0x0008c7df);
nv_wr32(dev, 0x400094, 0x00000005);
- nv_wr32(dev, 0x400B80, 0x45CAA208); /* 0x45eae20e */
+ nv_wr32(dev, 0x400B80, 0x45eae20e);
nv_wr32(dev, 0x400B84, 0x24000000);
nv_wr32(dev, 0x400098, 0x00000040);
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
@@ -591,14 +618,8 @@ nv20_graph_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
- nv20_graph_set_region_tiling(dev, i, 0, 0, 0);
+ nv20_graph_set_tile_region(dev, i);
- for (i = 0; i < 8; i++) {
- nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4));
- nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4);
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
- nv_rd32(dev, 0x100300 + i * 4));
- }
nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324));
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324));
@@ -642,6 +663,9 @@ nv20_graph_takedown(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
+ nouveau_irq_unregister(dev, 12);
+
nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
}
@@ -684,9 +708,16 @@ nv30_graph_init(struct drm_device *dev)
return ret;
}
+ ret = nv30_graph_register(dev);
+ if (ret) {
+ nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
+ return ret;
+ }
+
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
pgraph->ctx_table->pinst >> 4);
+ nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -724,7 +755,7 @@ nv30_graph_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
- nv20_graph_set_region_tiling(dev, i, 0, 0, 0);
+ nv20_graph_set_tile_region(dev, i);
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF);
@@ -744,46 +775,125 @@ nv30_graph_init(struct drm_device *dev)
return 0;
}
-struct nouveau_pgraph_object_class nv20_graph_grclass[] = {
- { 0x0030, false, NULL }, /* null */
- { 0x0039, false, NULL }, /* m2mf */
- { 0x004a, false, NULL }, /* gdirect */
- { 0x009f, false, NULL }, /* imageblit (nv12) */
- { 0x008a, false, NULL }, /* ifc */
- { 0x0089, false, NULL }, /* sifm */
- { 0x0062, false, NULL }, /* surf2d */
- { 0x0043, false, NULL }, /* rop */
- { 0x0012, false, NULL }, /* beta1 */
- { 0x0072, false, NULL }, /* beta4 */
- { 0x0019, false, NULL }, /* cliprect */
- { 0x0044, false, NULL }, /* pattern */
- { 0x009e, false, NULL }, /* swzsurf */
- { 0x0096, false, NULL }, /* celcius */
- { 0x0097, false, NULL }, /* kelvin (nv20) */
- { 0x0597, false, NULL }, /* kelvin (nv25) */
- {}
-};
-
-struct nouveau_pgraph_object_class nv30_graph_grclass[] = {
- { 0x0030, false, NULL }, /* null */
- { 0x0039, false, NULL }, /* m2mf */
- { 0x004a, false, NULL }, /* gdirect */
- { 0x009f, false, NULL }, /* imageblit (nv12) */
- { 0x008a, false, NULL }, /* ifc */
- { 0x038a, false, NULL }, /* ifc (nv30) */
- { 0x0089, false, NULL }, /* sifm */
- { 0x0389, false, NULL }, /* sifm (nv30) */
- { 0x0062, false, NULL }, /* surf2d */
- { 0x0362, false, NULL }, /* surf2d (nv30) */
- { 0x0043, false, NULL }, /* rop */
- { 0x0012, false, NULL }, /* beta1 */
- { 0x0072, false, NULL }, /* beta4 */
- { 0x0019, false, NULL }, /* cliprect */
- { 0x0044, false, NULL }, /* pattern */
- { 0x039e, false, NULL }, /* swzsurf */
- { 0x0397, false, NULL }, /* rankine (nv30) */
- { 0x0497, false, NULL }, /* rankine (nv35) */
- { 0x0697, false, NULL }, /* rankine (nv34) */
- {}
-};
+static int
+nv20_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->engine.graph.registered)
+ return 0;
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+ /* kelvin */
+ if (dev_priv->chipset < 0x25)
+ NVOBJ_CLASS(dev, 0x0097, GR);
+ else
+ NVOBJ_CLASS(dev, 0x0597, GR);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ dev_priv->engine.graph.registered = true;
+ return 0;
+}
+
+static int
+nv30_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ if (dev_priv->engine.graph.registered)
+ return 0;
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+ /* rankine */
+ if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0397, GR);
+ else
+ if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0697, GR);
+ else
+ if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0497, GR);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ dev_priv->engine.graph.registered = true;
+ return 0;
+}
+
+static void
+nv20_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x01f00000) >> 20;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ }
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv10_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, subc, class, mthd, data);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c
index 4a3f2f095128..e0135f0e2144 100644
--- a/drivers/gpu/drm/nouveau/nv30_fb.c
+++ b/drivers/gpu/drm/nouveau/nv30_fb.c
@@ -29,6 +29,27 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+void
+nv30_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
+ uint32_t size, uint32_t pitch, uint32_t flags)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ tile->addr = addr | 1;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+}
+
+void
+nv30_fb_free_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ tile->addr = tile->limit = tile->pitch = 0;
+}
+
static int
calc_bias(struct drm_device *dev, int k, int i, int j)
{
@@ -65,7 +86,7 @@ nv30_fb_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->num_tiles; i++)
- pfb->set_region_tiling(dev, i, 0, 0, 0);
+ pfb->set_tile_region(dev, i);
/* Init the memory timing regs at 0x10037c/0x1003ac */
if (dev_priv->chipset == 0x30 ||
diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c
index 3cd07d8d5bd7..f3d9c0505f7b 100644
--- a/drivers/gpu/drm/nouveau/nv40_fb.c
+++ b/drivers/gpu/drm/nouveau/nv40_fb.c
@@ -4,26 +4,22 @@
#include "nouveau_drm.h"
void
-nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv40_fb_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t limit = max(1u, addr + size) - 1;
-
- if (pitch)
- addr |= 1;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
switch (dev_priv->chipset) {
case 0x40:
- nv_wr32(dev, NV10_PFB_TLIMIT(i), limit);
- nv_wr32(dev, NV10_PFB_TSIZE(i), pitch);
- nv_wr32(dev, NV10_PFB_TILE(i), addr);
+ nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
break;
default:
- nv_wr32(dev, NV40_PFB_TLIMIT(i), limit);
- nv_wr32(dev, NV40_PFB_TSIZE(i), pitch);
- nv_wr32(dev, NV40_PFB_TILE(i), addr);
+ nv_wr32(dev, NV40_PFB_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV40_PFB_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV40_PFB_TILE(i), tile->addr);
break;
}
}
@@ -64,7 +60,7 @@ nv40_fb_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->num_tiles; i++)
- pfb->set_region_tiling(dev, i, 0, 0, 0);
+ pfb->set_tile_region(dev, i);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index d337b8b28cdd..49b9a35a9cd6 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -47,6 +47,11 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV40_USER(chan->id), PAGE_SIZE);
+ if (!chan->user)
+ return -ENOMEM;
+
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
@@ -59,7 +64,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0x30000000 /* no idea.. */);
- nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4);
nv_wi32(dev, fc + 60, 0x0001FFFF);
/* enable the fifo dma operation */
@@ -70,17 +74,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
return 0;
}
-void
-nv40_fifo_destroy_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
-
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
-
- nouveau_gpuobj_ref(NULL, &chan->ramfc);
-}
-
static void
nv40_fifo_do_load_context(struct drm_device *dev, int chid)
{
@@ -279,6 +272,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
static void
nv40_fifo_init_intr(struct drm_device *dev)
{
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xffffffff);
}
@@ -301,7 +295,7 @@ nv40_fifo_init(struct drm_device *dev)
pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->fifos[i]) {
+ if (dev_priv->channels.ptr[i]) {
uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
}
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 7ee1b91569b8..8870d72388c8 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -29,6 +29,9 @@
#include "nouveau_drv.h"
#include "nouveau_grctx.h"
+static int nv40_graph_register(struct drm_device *);
+static void nv40_graph_isr(struct drm_device *);
+
struct nouveau_channel *
nv40_graph_channel(struct drm_device *dev)
{
@@ -42,7 +45,7 @@ nv40_graph_channel(struct drm_device *dev)
inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->fifos[i];
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan && chan->ramin_grctx &&
chan->ramin_grctx->pinst == inst)
@@ -59,6 +62,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_grctx ctx = {};
+ unsigned long flags;
int ret;
ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
@@ -73,12 +77,39 @@ nv40_graph_create_context(struct nouveau_channel *chan)
nv40_grctx_init(&ctx);
nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
+
+ /* init grctx pointer in ramfc, and on PFIFO if channel is
+ * already active there
+ */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+ if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+ nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
void
nv40_graph_destroy_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pgraph->fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (pgraph->channel(dev) == chan)
+ pgraph->unload_context(dev);
+
+ pgraph->fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
}
@@ -174,43 +205,39 @@ nv40_graph_unload_context(struct drm_device *dev)
}
void
-nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv40_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t limit = max(1u, addr + size) - 1;
-
- if (pitch)
- addr |= 1;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
switch (dev_priv->chipset) {
case 0x44:
case 0x4a:
case 0x4e:
- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
break;
case 0x46:
case 0x47:
case 0x49:
case 0x4b:
- nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch);
- nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit);
- nv_wr32(dev, NV47_PGRAPH_TILE(i), addr);
- nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch);
- nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit);
- nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr);
+ nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
+ nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+ nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+ nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
break;
default:
- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
- nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch);
- nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit);
- nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr);
+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
+ nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+ nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+ nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
break;
}
}
@@ -232,7 +259,7 @@ nv40_graph_init(struct drm_device *dev)
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_grctx ctx = {};
uint32_t vramsz, *cp;
- int i, j;
+ int ret, i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
@@ -256,9 +283,14 @@ nv40_graph_init(struct drm_device *dev)
kfree(cp);
+ ret = nv40_graph_register(dev);
+ if (ret)
+ return ret;
+
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
+ nouveau_irq_register(dev, 12, nv40_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -347,7 +379,7 @@ nv40_graph_init(struct drm_device *dev)
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->num_tiles; i++)
- nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
+ nv40_graph_set_tile_region(dev, i);
/* begin RAM config */
vramsz = pci_resource_len(dev->pdev, 0) - 1;
@@ -390,26 +422,110 @@ nv40_graph_init(struct drm_device *dev)
void nv40_graph_takedown(struct drm_device *dev)
{
+ nouveau_irq_unregister(dev, 12);
}
-struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
- { 0x0030, false, NULL }, /* null */
- { 0x0039, false, NULL }, /* m2mf */
- { 0x004a, false, NULL }, /* gdirect */
- { 0x009f, false, NULL }, /* imageblit (nv12) */
- { 0x008a, false, NULL }, /* ifc */
- { 0x0089, false, NULL }, /* sifm */
- { 0x3089, false, NULL }, /* sifm (nv40) */
- { 0x0062, false, NULL }, /* surf2d */
- { 0x3062, false, NULL }, /* surf2d (nv40) */
- { 0x0043, false, NULL }, /* rop */
- { 0x0012, false, NULL }, /* beta1 */
- { 0x0072, false, NULL }, /* beta4 */
- { 0x0019, false, NULL }, /* cliprect */
- { 0x0044, false, NULL }, /* pattern */
- { 0x309e, false, NULL }, /* swzsurf */
- { 0x4097, false, NULL }, /* curie (nv40) */
- { 0x4497, false, NULL }, /* curie (nv44) */
- {}
-};
+static int
+nv40_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->engine.graph.registered)
+ return 0;
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+ /* curie */
+ if (nv44_graph_class(dev))
+ NVOBJ_CLASS(dev, 0x4497, GR);
+ else
+ NVOBJ_CLASS(dev, 0x4097, GR);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ dev_priv->engine.graph.registered = true;
+ return 0;
+}
+
+static int
+nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->ramin_grctx)
+ continue;
+
+ if (inst == chan->ramin_grctx->pinst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nv40_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4;
+ u32 chid = nv40_graph_isr_chid(dev, inst);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ } else
+ if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+ nv_mask(dev, 0x402000, 0, 0);
+ }
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv10_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d "
+ "class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
index ce585093264e..f70447d131d7 100644
--- a/drivers/gpu/drm/nouveau/nv40_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv40_grctx.c
@@ -118,17 +118,6 @@
*/
static int
-nv40_graph_4097(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if ((dev_priv->chipset & 0xf0) == 0x60)
- return 0;
-
- return !!(0x0baf & (1 << dev_priv->chipset));
-}
-
-static int
nv40_graph_vs_count(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -219,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x4009dc, 0x80000000);
} else {
cp_ctx(ctx, 0x400840, 20);
- if (!nv40_graph_4097(ctx->dev)) {
+ if (nv44_graph_class(ctx->dev)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
}
@@ -228,7 +217,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x400888, 0x00000040);
cp_ctx(ctx, 0x400894, 11);
gr_def(ctx, 0x400894, 0x00000040);
- if (nv40_graph_4097(ctx->dev)) {
+ if (!nv44_graph_class(ctx->dev)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
}
@@ -546,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
{
- int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084;
+ int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
cp_out (ctx, 0x300000);
cp_lsr (ctx, len - 4);
@@ -582,11 +571,11 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx)
} else {
b0_offset = 0x1d40/4; /* 2200 */
b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
- vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4;
+ vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
}
cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
- cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029);
+ cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
offset = ctx->ctxvals_pos;
ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c
index e4e72c12ab6a..03c0d4c3f355 100644
--- a/drivers/gpu/drm/nouveau/nv40_mc.c
+++ b/drivers/gpu/drm/nouveau/nv40_mc.c
@@ -6,27 +6,17 @@
int
nv40_mc_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
-
/* Power up everything, resetting each individual unit will
* be done later if needed.
*/
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
- switch (dev_priv->chipset) {
- case 0x44:
- case 0x46: /* G72 */
- case 0x4e:
- case 0x4c: /* C51_G7X */
- tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+ if (nv44_graph_class(dev)) {
+ u32 tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
nv_wr32(dev, NV40_PMC_1700, tmp);
nv_wr32(dev, NV40_PMC_1704, 0);
nv_wr32(dev, NV40_PMC_1708, 0);
nv_wr32(dev, NV40_PMC_170C, tmp);
- break;
- default:
- break;
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c
index 2cdc2bfe7179..de81151648f8 100644
--- a/drivers/gpu/drm/nouveau/nv50_calc.c
+++ b/drivers/gpu/drm/nouveau/nv50_calc.c
@@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
int *N, int *fN, int *M, int *P)
{
fixed20_12 fb_div, a, b;
+ u32 refclk = pll->refclk / 10;
+ u32 max_vco_freq = pll->vco1.maxfreq / 10;
+ u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
+ clk /= 10;
- *P = pll->vco1.maxfreq / clk;
+ *P = max_vco_freq / clk;
if (*P > pll->max_p)
*P = pll->max_p;
if (*P < pll->min_p)
*P = pll->min_p;
- /* *M = ceil(refclk / pll->vco.max_inputfreq); */
- a.full = dfixed_const(pll->refclk);
- b.full = dfixed_const(pll->vco1.max_inputfreq);
+ /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
+ a.full = dfixed_const(refclk + max_vco_inputfreq);
+ b.full = dfixed_const(max_vco_inputfreq);
a.full = dfixed_div(a, b);
- a.full = dfixed_ceil(a);
+ a.full = dfixed_floor(a);
*M = dfixed_trunc(a);
/* fb_div = (vco * *M) / refclk; */
fb_div.full = dfixed_const(clk * *P);
fb_div.full = dfixed_mul(fb_div, a);
- a.full = dfixed_const(pll->refclk);
+ a.full = dfixed_const(refclk);
fb_div.full = dfixed_div(fb_div, a);
/* *N = floor(fb_div); */
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 16380d52cd88..9023c4dbb449 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -115,15 +115,16 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
OUT_RING(evo, 0);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
if (dev_priv->chipset != 0x50)
- if (nv_crtc->fb.tile_flags == 0x7a00)
+ if (nv_crtc->fb.tile_flags == 0x7a00 ||
+ nv_crtc->fb.tile_flags == 0xfe00)
OUT_RING(evo, NvEvoFB32);
else
if (nv_crtc->fb.tile_flags == 0x7000)
OUT_RING(evo, NvEvoFB16);
else
- OUT_RING(evo, NvEvoVRAM);
+ OUT_RING(evo, NvEvoVRAM_LP);
else
- OUT_RING(evo, NvEvoVRAM);
+ OUT_RING(evo, NvEvoVRAM_LP);
}
nv_crtc->fb.blanked = blanked;
@@ -345,7 +346,6 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t buffer_handle, uint32_t width, uint32_t height)
{
struct drm_device *dev = crtc->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nouveau_bo *cursor = NULL;
struct drm_gem_object *gem;
@@ -374,8 +374,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
nouveau_bo_unmap(cursor);
- nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset -
- dev_priv->vm_vram_base);
+ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT);
nv_crtc->cursor.show(nv_crtc, true);
out:
@@ -437,6 +436,7 @@ static const struct drm_crtc_funcs nv50_crtc_funcs = {
.cursor_move = nv50_crtc_cursor_move,
.gamma_set = nv50_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
+ .page_flip = nouveau_crtc_page_flip,
.destroy = nv50_crtc_destroy,
};
@@ -453,6 +453,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+ drm_vblank_pre_modeset(dev, nv_crtc->index);
nv50_crtc_blank(nv_crtc, true);
}
@@ -468,6 +469,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
nv50_crtc_blank(nv_crtc, false);
+ drm_vblank_post_modeset(dev, nv_crtc->index);
ret = RING_SPACE(evo, 2);
if (ret) {
@@ -545,8 +547,8 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
return -EINVAL;
}
- nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
- nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
+ nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT;
+ nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
ret = RING_SPACE(evo, 2);
@@ -554,13 +556,14 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
return ret;
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
- if (nv_crtc->fb.tile_flags == 0x7a00)
+ if (nv_crtc->fb.tile_flags == 0x7a00 ||
+ nv_crtc->fb.tile_flags == 0xfe00)
OUT_RING(evo, NvEvoFB32);
else
if (nv_crtc->fb.tile_flags == 0x7000)
OUT_RING(evo, NvEvoFB16);
else
- OUT_RING(evo, NvEvoVRAM);
+ OUT_RING(evo, NvEvoVRAM_LP);
}
ret = RING_SPACE(evo, 12);
@@ -574,11 +577,13 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (!nv_crtc->fb.tile_flags) {
OUT_RING(evo, drm_fb->pitch | (1 << 20));
} else {
- OUT_RING(evo, ((drm_fb->pitch / 4) << 4) |
- fb->nvbo->tile_mode);
+ u32 tile_mode = fb->nvbo->tile_mode;
+ if (dev_priv->card_type >= NV_C0)
+ tile_mode >>= 4;
+ OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | tile_mode);
}
if (dev_priv->chipset == 0x50)
- OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
+ OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
else
OUT_RING(evo, format);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 55c9663ef2bf..7cc94ed9ed95 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -33,6 +33,8 @@
#include "nouveau_ramht.h"
#include "drm_crtc_helper.h"
+static void nv50_display_isr(struct drm_device *);
+
static inline int
nv50_sor_nr(struct drm_device *dev)
{
@@ -46,159 +48,6 @@ nv50_sor_nr(struct drm_device *dev)
return 4;
}
-static void
-nv50_evo_channel_del(struct nouveau_channel **pchan)
-{
- struct nouveau_channel *chan = *pchan;
-
- if (!chan)
- return;
- *pchan = NULL;
-
- nouveau_gpuobj_channel_takedown(chan);
- nouveau_bo_unmap(chan->pushbuf_bo);
- nouveau_bo_ref(NULL, &chan->pushbuf_bo);
-
- if (chan->user)
- iounmap(chan->user);
-
- kfree(chan);
-}
-
-static int
-nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
- uint32_t tile_flags, uint32_t magic_flags,
- uint32_t offset, uint32_t limit)
-{
- struct drm_nouveau_private *dev_priv = evo->dev->dev_private;
- struct drm_device *dev = evo->dev;
- struct nouveau_gpuobj *obj = NULL;
- int ret;
-
- ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj);
- if (ret)
- return ret;
- obj->engine = NVOBJ_ENGINE_DISPLAY;
-
- nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
- nv_wo32(obj, 4, limit);
- nv_wo32(obj, 8, offset);
- nv_wo32(obj, 12, 0x00000000);
- nv_wo32(obj, 16, 0x00000000);
- if (dev_priv->card_type < NV_C0)
- nv_wo32(obj, 20, 0x00010000);
- else
- nv_wo32(obj, 20, 0x00020000);
- dev_priv->engine.instmem.flush(dev);
-
- ret = nouveau_ramht_insert(evo, name, obj);
- nouveau_gpuobj_ref(NULL, &obj);
- if (ret) {
- return ret;
- }
-
- return 0;
-}
-
-static int
-nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ramht = NULL;
- struct nouveau_channel *chan;
- int ret;
-
- chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL);
- if (!chan)
- return -ENOMEM;
- *pchan = chan;
-
- chan->id = -1;
- chan->dev = dev;
- chan->user_get = 4;
- chan->user_put = 0;
-
- ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
- if (ret) {
- NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- ret = drm_mm_init(&chan->ramin_heap, 0, 32768);
- if (ret) {
- NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht);
- if (ret) {
- NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
- nouveau_gpuobj_ref(NULL, &ramht);
- if (ret) {
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- if (dev_priv->chipset != 0x50) {
- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19,
- 0, 0xffffffff);
- if (ret) {
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
-
- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19,
- 0, 0xffffffff);
- if (ret) {
- nv50_evo_channel_del(pchan);
- return ret;
- }
- }
-
- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19,
- 0, dev_priv->vram_size);
- if (ret) {
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0,
- false, true, &chan->pushbuf_bo);
- if (ret == 0)
- ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM);
- if (ret) {
- NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret);
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- ret = nouveau_bo_map(chan->pushbuf_bo);
- if (ret) {
- NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret);
- nv50_evo_channel_del(pchan);
- return ret;
- }
-
- chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
- NV50_PDISPLAY_USER(0), PAGE_SIZE);
- if (!chan->user) {
- NV_ERROR(dev, "Error mapping EVO control regs.\n");
- nv50_evo_channel_del(pchan);
- return -ENOMEM;
- }
-
- return 0;
-}
-
int
nv50_display_early_init(struct drm_device *dev)
{
@@ -214,17 +63,16 @@ int
nv50_display_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
- struct nouveau_channel *evo = dev_priv->evo;
struct drm_connector *connector;
- uint32_t val, ram_amount;
- uint64_t start;
+ struct nouveau_channel *evo;
int ret, i;
+ u32 val;
NV_DEBUG_KMS(dev, "\n");
nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
+
/*
* I think the 0x006101XX range is some kind of main control area
* that enables things.
@@ -240,16 +88,19 @@ nv50_display_init(struct drm_device *dev)
val = nv_rd32(dev, 0x0061610c + (i * 0x800));
nv_wr32(dev, 0x0061019c + (i * 0x10), val);
}
+
/* DAC */
for (i = 0; i < 3; i++) {
val = nv_rd32(dev, 0x0061a000 + (i * 0x800));
nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
}
+
/* SOR */
for (i = 0; i < nv50_sor_nr(dev); i++) {
val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
}
+
/* EXT */
for (i = 0; i < 3; i++) {
val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
@@ -262,17 +113,6 @@ nv50_display_init(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
}
- /* This used to be in crtc unblank, but seems out of place there. */
- nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
- /* RAM is clamped to 256 MiB. */
- ram_amount = dev_priv->vram_size;
- NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
- if (ram_amount > 256*1024*1024)
- ram_amount = 256*1024*1024;
- nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1);
- nv_wr32(dev, NV50_PDISPLAY_UNK_388, 0x150000);
- nv_wr32(dev, NV50_PDISPLAY_UNK_38C, 0);
-
/* The precise purpose is unknown, i suspect it has something to do
* with text mode.
*/
@@ -287,37 +127,6 @@ nv50_display_init(struct drm_device *dev)
}
}
- /* taken from nv bug #12637, attempts to un-wedge the hw if it's
- * stuck in some unspecified state
- */
- start = ptimer->read(dev);
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x2b00);
- while ((val = nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))) & 0x1e0000) {
- if ((val & 0x9f0000) == 0x20000)
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
- val | 0x800000);
-
- if ((val & 0x3f0000) == 0x30000)
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
- val | 0x200000);
-
- if (ptimer->read(dev) - start > 1000000000ULL) {
- NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n");
- NV_ERROR(dev, "0x610200 = 0x%08x\n", val);
- return -EBUSY;
- }
- }
-
- nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE);
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03);
- if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
- 0x40000000, 0x40000000)) {
- NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n");
- NV_ERROR(dev, "0x610200 = 0x%08x\n",
- nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
- return -EBUSY;
- }
-
for (i = 0; i < 2; i++) {
nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
@@ -341,39 +150,31 @@ nv50_display_init(struct drm_device *dev)
}
}
- nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
+ nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
+ nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
+ nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1,
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
- /* initialise fifo */
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0),
- ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) |
- NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM |
- NV50_PDISPLAY_CHANNEL_DMA_CB_VALID);
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000);
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002);
- if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n");
- NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200));
- return -EBUSY;
+ /* enable hotplug interrupts */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct nouveau_connector *conn = nouveau_connector(connector);
+
+ if (conn->dcb->gpio_tag == 0xff)
+ continue;
+
+ pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
}
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
- (nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)) & ~0x00000003) |
- NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED);
- nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0);
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x01000003 |
- NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED);
- nv_wr32(dev, 0x610300, nv_rd32(dev, 0x610300) & ~1);
-
- evo->dma.max = (4096/4) - 2;
- evo->dma.put = 0;
- evo->dma.cur = evo->dma.put;
- evo->dma.free = evo->dma.max - evo->dma.cur;
-
- ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS);
+
+ ret = nv50_evo_init(dev);
if (ret)
return ret;
+ evo = dev_priv->evo;
- for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
- OUT_RING(evo, 0);
+ nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
ret = RING_SPACE(evo, 11);
if (ret)
@@ -393,21 +194,6 @@ nv50_display_init(struct drm_device *dev)
if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
NV_ERROR(dev, "evo pushbuf stalled\n");
- /* enable clock change interrupts. */
- nv_wr32(dev, 0x610028, 0x00010001);
- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, (NV50_PDISPLAY_INTR_EN_CLK_UNK10 |
- NV50_PDISPLAY_INTR_EN_CLK_UNK20 |
- NV50_PDISPLAY_INTR_EN_CLK_UNK40));
-
- /* enable hotplug interrupts */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct nouveau_connector *conn = nouveau_connector(connector);
-
- if (conn->dcb->gpio_tag == 0xff)
- continue;
-
- pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
- }
return 0;
}
@@ -452,13 +238,7 @@ static int nv50_display_disable(struct drm_device *dev)
}
}
- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0);
- nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0);
- if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
- NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n");
- NV_ERROR(dev, "0x610200 = 0x%08x\n",
- nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
- }
+ nv50_evo_fini(dev);
for (i = 0; i < 3; i++) {
if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
@@ -470,7 +250,7 @@ static int nv50_display_disable(struct drm_device *dev)
}
/* disable interrupts. */
- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000);
+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
/* disable hotplug interrupts */
nv_wr32(dev, 0xe054, 0xffffffff);
@@ -508,13 +288,6 @@ int nv50_display_create(struct drm_device *dev)
dev->mode_config.fb_base = dev_priv->fb_phys;
- /* Create EVO channel */
- ret = nv50_evo_channel_new(dev, &dev_priv->evo);
- if (ret) {
- NV_ERROR(dev, "Error creating EVO channel: %d\n", ret);
- return ret;
- }
-
/* Create CRTC objects */
for (i = 0; i < 2; i++)
nv50_crtc_create(dev, i);
@@ -557,6 +330,9 @@ int nv50_display_create(struct drm_device *dev)
}
}
+ INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
+ nouveau_irq_register(dev, 26, nv50_display_isr);
+
ret = nv50_display_init(dev);
if (ret) {
nv50_display_destroy(dev);
@@ -569,14 +345,12 @@ int nv50_display_create(struct drm_device *dev)
void
nv50_display_destroy(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
NV_DEBUG_KMS(dev, "\n");
drm_mode_config_cleanup(dev);
nv50_display_disable(dev);
- nv50_evo_channel_del(&dev_priv->evo);
+ nouveau_irq_unregister(dev, 26);
}
static u16
@@ -660,32 +434,32 @@ static void
nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan;
- struct list_head *entry, *tmp;
+ struct nouveau_channel *chan, *tmp;
- list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) {
- chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait);
+ list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
+ nvsw.vbl_wait) {
+ if (chan->nvsw.vblsem_head != crtc)
+ continue;
nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
chan->nvsw.vblsem_rval);
list_del(&chan->nvsw.vbl_wait);
+ drm_vblank_put(dev, crtc);
}
+
+ drm_handle_vblank(dev, crtc);
}
static void
nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
{
- intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
-
if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
nv50_display_vblank_crtc_handler(dev, 0);
if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
nv50_display_vblank_crtc_handler(dev, 1);
- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev,
- NV50_PDISPLAY_INTR_EN) & ~intr);
- nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr);
+ nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
}
static void
@@ -1011,91 +785,31 @@ nv50_display_irq_handler_bh(struct work_struct *work)
static void
nv50_display_error_handler(struct drm_device *dev)
{
- uint32_t addr, data;
-
- nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000);
- addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR);
- data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA);
-
- NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x (0x%04x 0x%02x)\n",
- 0, addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
-
- nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000);
-}
-
-void
-nv50_display_irq_hotplug_bh(struct work_struct *work)
-{
- struct drm_nouveau_private *dev_priv =
- container_of(work, struct drm_nouveau_private, hpd_work);
- struct drm_device *dev = dev_priv->dev;
- struct drm_connector *connector;
- const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
- uint32_t unplug_mask, plug_mask, change_mask;
- uint32_t hpd0, hpd1 = 0;
-
- hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
- if (dev_priv->chipset >= 0x90)
- hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
+ u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
+ u32 addr, data;
+ int chid;
- plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16);
- unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
- change_mask = plug_mask | unplug_mask;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct drm_encoder_helper_funcs *helper;
- struct nouveau_connector *nv_connector =
- nouveau_connector(connector);
- struct nouveau_encoder *nv_encoder;
- struct dcb_gpio_entry *gpio;
- uint32_t reg;
- bool plugged;
-
- if (!nv_connector->dcb)
- continue;
-
- gpio = nouveau_bios_gpio_entry(dev, nv_connector->dcb->gpio_tag);
- if (!gpio || !(change_mask & (1 << gpio->line)))
+ for (chid = 0; chid < 5; chid++) {
+ if (!(channels & (1 << chid)))
continue;
- reg = nv_rd32(dev, gpio_reg[gpio->line >> 3]);
- plugged = !!(reg & (4 << ((gpio->line & 7) << 2)));
- NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",
- drm_get_connector_name(connector)) ;
-
- if (!connector->encoder || !connector->encoder->crtc ||
- !connector->encoder->crtc->enabled)
- continue;
- nv_encoder = nouveau_encoder(connector->encoder);
- helper = connector->encoder->helper_private;
-
- if (nv_encoder->dcb->type != OUTPUT_DP)
- continue;
+ nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
+ addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid));
+ data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid));
+ NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x "
+ "(0x%04x 0x%02x)\n", chid,
+ addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
- if (plugged)
- helper->dpms(connector->encoder, DRM_MODE_DPMS_ON);
- else
- helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
+ nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
}
-
- nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
- if (dev_priv->chipset >= 0x90)
- nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
-
- drm_helper_hpd_irq_event(dev);
}
-void
-nv50_display_irq_handler(struct drm_device *dev)
+static void
+nv50_display_isr(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t delayed = 0;
- if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
- if (!work_pending(&dev_priv->hpd_work))
- queue_work(dev_priv->wq, &dev_priv->hpd_work);
- }
-
while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
@@ -1106,9 +820,9 @@ nv50_display_irq_handler(struct drm_device *dev)
if (!intr0 && !(intr1 & ~delayed))
break;
- if (intr0 & 0x00010000) {
+ if (intr0 & 0x001f0000) {
nv50_display_error_handler(dev);
- intr0 &= ~0x00010000;
+ intr0 &= ~0x001f0000;
}
if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
@@ -1139,4 +853,3 @@ nv50_display_irq_handler(struct drm_device *dev)
}
}
}
-
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index c551f0b85ee0..f0e30b78ef6b 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -35,9 +35,7 @@
#include "nouveau_crtc.h"
#include "nv50_evo.h"
-void nv50_display_irq_handler(struct drm_device *dev);
void nv50_display_irq_handler_bh(struct work_struct *work);
-void nv50_display_irq_hotplug_bh(struct work_struct *work);
int nv50_display_early_init(struct drm_device *dev);
void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev);
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
new file mode 100644
index 000000000000..14e24e906ee8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
+
+static void
+nv50_evo_channel_del(struct nouveau_channel **pevo)
+{
+ struct drm_nouveau_private *dev_priv;
+ struct nouveau_channel *evo = *pevo;
+
+ if (!evo)
+ return;
+ *pevo = NULL;
+
+ dev_priv = evo->dev->dev_private;
+ dev_priv->evo_alloc &= ~(1 << evo->id);
+
+ nouveau_gpuobj_channel_takedown(evo);
+ nouveau_bo_unmap(evo->pushbuf_bo);
+ nouveau_bo_ref(NULL, &evo->pushbuf_bo);
+
+ if (evo->user)
+ iounmap(evo->user);
+
+ kfree(evo);
+}
+
+int
+nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name,
+ u32 tile_flags, u32 magic_flags, u32 offset, u32 limit,
+ u32 flags5)
+{
+ struct drm_nouveau_private *dev_priv = evo->dev->dev_private;
+ struct drm_device *dev = evo->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, dev_priv->evo, 6*4, 32, 0, &obj);
+ if (ret)
+ return ret;
+ obj->engine = NVOBJ_ENGINE_DISPLAY;
+
+ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
+ nv_wo32(obj, 4, limit);
+ nv_wo32(obj, 8, offset);
+ nv_wo32(obj, 12, 0x00000000);
+ nv_wo32(obj, 16, 0x00000000);
+ nv_wo32(obj, 20, flags5);
+ dev_priv->engine.instmem.flush(dev);
+
+ ret = nouveau_ramht_insert(evo, name, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pevo)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *evo;
+ int ret;
+
+ evo = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL);
+ if (!evo)
+ return -ENOMEM;
+ *pevo = evo;
+
+ for (evo->id = 0; evo->id < 5; evo->id++) {
+ if (dev_priv->evo_alloc & (1 << evo->id))
+ continue;
+
+ dev_priv->evo_alloc |= (1 << evo->id);
+ break;
+ }
+
+ if (evo->id == 5) {
+ kfree(evo);
+ return -ENODEV;
+ }
+
+ evo->dev = dev;
+ evo->user_get = 4;
+ evo->user_put = 0;
+
+ ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0,
+ false, true, &evo->pushbuf_bo);
+ if (ret == 0)
+ ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM);
+ if (ret) {
+ NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret);
+ nv50_evo_channel_del(pevo);
+ return ret;
+ }
+
+ ret = nouveau_bo_map(evo->pushbuf_bo);
+ if (ret) {
+ NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret);
+ nv50_evo_channel_del(pevo);
+ return ret;
+ }
+
+ evo->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV50_PDISPLAY_USER(evo->id), PAGE_SIZE);
+ if (!evo->user) {
+ NV_ERROR(dev, "Error mapping EVO control regs.\n");
+ nv50_evo_channel_del(pevo);
+ return -ENOMEM;
+ }
+
+ /* bind primary evo channel's ramht to the channel */
+ if (dev_priv->evo && evo != dev_priv->evo)
+ nouveau_ramht_ref(dev_priv->evo->ramht, &evo->ramht, NULL);
+
+ return 0;
+}
+
+static int
+nv50_evo_channel_init(struct nouveau_channel *evo)
+{
+ struct drm_device *dev = evo->dev;
+ int id = evo->id, ret, i;
+ u64 pushbuf = evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT;
+ u32 tmp;
+
+ tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id));
+ if ((tmp & 0x009f0000) == 0x00020000)
+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000);
+
+ tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id));
+ if ((tmp & 0x003f0000) == 0x00030000)
+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000);
+
+ /* initialise fifo */
+ nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 |
+ NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM |
+ NV50_PDISPLAY_EVO_DMA_CB_VALID);
+ nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000);
+ nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(id), id);
+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA,
+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
+
+ nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0x00000000);
+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 |
+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED);
+ if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) {
+ NV_ERROR(dev, "EvoCh %d init timeout: 0x%08x\n", id,
+ nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)));
+ return -EBUSY;
+ }
+
+ /* enable error reporting on the channel */
+ nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id);
+
+ evo->dma.max = (4096/4) - 2;
+ evo->dma.put = 0;
+ evo->dma.cur = evo->dma.put;
+ evo->dma.free = evo->dma.max - evo->dma.cur;
+
+ ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
+ OUT_RING(evo, 0);
+
+ return 0;
+}
+
+static void
+nv50_evo_channel_fini(struct nouveau_channel *evo)
+{
+ struct drm_device *dev = evo->dev;
+ int id = evo->id;
+
+ nv_mask(dev, 0x610028, 0x00010001 << id, 0x00000000);
+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000);
+ nv_wr32(dev, NV50_PDISPLAY_INTR_0, (1 << id));
+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000);
+ if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) {
+ NV_ERROR(dev, "EvoCh %d takedown timeout: 0x%08x\n", id,
+ nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)));
+ }
+}
+
+static int
+nv50_evo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramht = NULL;
+ struct nouveau_channel *evo;
+ int ret;
+
+ /* create primary evo channel, the one we use for modesetting
+ * purporses
+ */
+ ret = nv50_evo_channel_new(dev, &dev_priv->evo);
+ if (ret)
+ return ret;
+ evo = dev_priv->evo;
+
+ /* setup object management on it, any other evo channel will
+ * use this also as there's no per-channel support on the
+ * hardware
+ */
+ ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536,
+ NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin);
+ if (ret) {
+ NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = drm_mm_init(&evo->ramin_heap, 0, 32768);
+ if (ret) {
+ NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht);
+ if (ret) {
+ NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nouveau_ramht_new(dev, ramht, &evo->ramht);
+ nouveau_gpuobj_ref(NULL, &ramht);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ /* create some default objects for the scanout memtypes we support */
+ if (dev_priv->card_type >= NV_C0) {
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19,
+ 0, 0xffffffff, 0x00000000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19,
+ 0, dev_priv->vram_size, 0x00020000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19,
+ 0, dev_priv->vram_size, 0x00000000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+ } else
+ if (dev_priv->chipset != 0x50) {
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19,
+ 0, 0xffffffff, 0x00010000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0x7a, 0x19,
+ 0, 0xffffffff, 0x00010000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19,
+ 0, dev_priv->vram_size, 0x00010000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+
+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19,
+ 0, dev_priv->vram_size, 0x00010000);
+ if (ret) {
+ nv50_evo_channel_del(&dev_priv->evo);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+nv50_evo_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (!dev_priv->evo) {
+ ret = nv50_evo_create(dev);
+ if (ret)
+ return ret;
+ }
+
+ return nv50_evo_channel_init(dev_priv->evo);
+}
+
+void
+nv50_evo_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->evo) {
+ nv50_evo_channel_fini(dev_priv->evo);
+ nv50_evo_channel_del(&dev_priv->evo);
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.h b/drivers/gpu/drm/nouveau/nv50_evo.h
index aae13343bcec..aa4f0d3cea8e 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.h
+++ b/drivers/gpu/drm/nouveau/nv50_evo.h
@@ -24,6 +24,15 @@
*
*/
+#ifndef __NV50_EVO_H__
+#define __NV50_EVO_H__
+
+int nv50_evo_init(struct drm_device *dev);
+void nv50_evo_fini(struct drm_device *dev);
+int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name,
+ u32 tile_flags, u32 magic_flags,
+ u32 offset, u32 limit);
+
#define NV50_EVO_UPDATE 0x00000080
#define NV50_EVO_UNK84 0x00000084
#define NV50_EVO_UNK84_NOTIFY 0x40000000
@@ -111,3 +120,4 @@
#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8
#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc
+#endif
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
index cd1988b15d2c..50290dea0ac4 100644
--- a/drivers/gpu/drm/nouveau/nv50_fb.c
+++ b/drivers/gpu/drm/nouveau/nv50_fb.c
@@ -3,30 +3,75 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+struct nv50_fb_priv {
+ struct page *r100c08_page;
+ dma_addr_t r100c08;
+};
+
+static int
+nv50_fb_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_fb_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!priv->r100c08_page) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) {
+ __free_page(priv->r100c08_page);
+ kfree(priv);
+ return -EFAULT;
+ }
+
+ dev_priv->engine.fb.priv = priv;
+ return 0;
+}
+
int
nv50_fb_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_fb_priv *priv;
+ int ret;
+
+ if (!dev_priv->engine.fb.priv) {
+ ret = nv50_fb_create(dev);
+ if (ret)
+ return ret;
+ }
+ priv = dev_priv->engine.fb.priv;
/* Not a clue what this is exactly. Without pointing it at a
* scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
* cause IOMMU "read from address 0" errors (rh#561267)
*/
- nv_wr32(dev, 0x100c08, dev_priv->gart_info.sg_dummy_bus >> 8);
+ nv_wr32(dev, 0x100c08, priv->r100c08 >> 8);
/* This is needed to get meaningful information from 100c90
* on traps. No idea what these values mean exactly. */
switch (dev_priv->chipset) {
case 0x50:
- nv_wr32(dev, 0x100c90, 0x0707ff);
+ nv_wr32(dev, 0x100c90, 0x000707ff);
break;
case 0xa3:
case 0xa5:
case 0xa8:
- nv_wr32(dev, 0x100c90, 0x0d0fff);
+ nv_wr32(dev, 0x100c90, 0x000d0fff);
+ break;
+ case 0xaf:
+ nv_wr32(dev, 0x100c90, 0x089d1fff);
break;
default:
- nv_wr32(dev, 0x100c90, 0x1d07ff);
+ nv_wr32(dev, 0x100c90, 0x001d07ff);
break;
}
@@ -36,12 +81,25 @@ nv50_fb_init(struct drm_device *dev)
void
nv50_fb_takedown(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_fb_priv *priv;
+
+ priv = dev_priv->engine.fb.priv;
+ if (!priv)
+ return;
+ dev_priv->engine.fb.priv = NULL;
+
+ pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ __free_page(priv->r100c08_page);
+ kfree(priv);
}
void
nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
u32 trap[6], idx, chinst;
int i, ch;
@@ -60,8 +118,10 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
return;
chinst = (trap[2] << 16) | trap[1];
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
- struct nouveau_channel *chan = dev_priv->fifos[ch];
+ struct nouveau_channel *chan = dev_priv->channels.ptr[ch];
if (!chan || !chan->ramin)
continue;
@@ -69,6 +129,7 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
if (chinst == chan->ramin->vinst >> 12)
break;
}
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x "
"channel %d (0x%08x)\n",
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index 6dcf048eddbc..791ded1c5c6d 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -1,29 +1,46 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_ramht.h"
#include "nouveau_fbcon.h"
+#include "nouveau_mm.h"
-void
+int
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) &&
- RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) {
- nouveau_fbcon_gpu_lockup(info);
- }
-
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_fillrect(info, rect);
- return;
- }
+ ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
+ if (ret)
+ return ret;
if (rect->rop != ROP_COPY) {
BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
@@ -45,27 +62,21 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
OUT_RING(chan, 3);
}
FIRE_RING(chan);
+ return 0;
}
-void
+int
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) {
- nouveau_fbcon_gpu_lockup(info);
- }
-
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_copyarea(info, region);
- return;
- }
+ ret = RING_SPACE(chan, 12);
+ if (ret)
+ return ret;
BEGIN_RING(chan, NvSub2D, 0x0110, 1);
OUT_RING(chan, 0);
@@ -80,9 +91,10 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
OUT_RING(chan, 0);
OUT_RING(chan, region->sy);
FIRE_RING(chan);
+ return 0;
}
-void
+int
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
@@ -92,23 +104,14 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
uint32_t width, dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette;
+ int ret;
- if (info->state != FBINFO_STATE_RUNNING)
- return;
-
- if (image->depth != 1) {
- cfb_imageblit(info, image);
- return;
- }
+ if (image->depth != 1)
+ return -ENODEV;
- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) {
- nouveau_fbcon_gpu_lockup(info);
- }
-
- if (info->flags & FBINFO_HWACCEL_DISABLED) {
- cfb_imageblit(info, image);
- return;
- }
+ ret = RING_SPACE(chan, 11);
+ if (ret)
+ return ret;
width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5;
@@ -134,11 +137,9 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
while (dwords) {
int push = dwords > 2047 ? 2047 : dwords;
- if (RING_SPACE(chan, push + 1)) {
- nouveau_fbcon_gpu_lockup(info);
- cfb_imageblit(info, image);
- return;
- }
+ ret = RING_SPACE(chan, push + 1);
+ if (ret)
+ return ret;
dwords -= push;
@@ -148,6 +149,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
}
FIRE_RING(chan);
+ return 0;
}
int
@@ -157,12 +159,9 @@ nv50_fbcon_accel_init(struct fb_info *info)
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
- struct nouveau_gpuobj *eng2d = NULL;
- uint64_t fb;
+ struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo;
int ret, format;
- fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base;
-
switch (info->var.bits_per_pixel) {
case 8:
format = 0xf3;
@@ -190,12 +189,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
return -EINVAL;
}
- ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d);
- if (ret)
- return ret;
-
- ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
- nouveau_gpuobj_ref(NULL, &eng2d);
+ ret = nouveau_gpuobj_gr_new(dev_priv->channel, Nv2D, 0x502d);
if (ret)
return ret;
@@ -253,8 +247,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
OUT_RING(chan, info->fix.line_length);
OUT_RING(chan, info->var.xres_virtual);
OUT_RING(chan, info->var.yres_virtual);
- OUT_RING(chan, upper_32_bits(fb));
- OUT_RING(chan, lower_32_bits(fb));
+ OUT_RING(chan, upper_32_bits(nvbo->vma.offset));
+ OUT_RING(chan, lower_32_bits(nvbo->vma.offset));
BEGIN_RING(chan, NvSub2D, 0x0230, 2);
OUT_RING(chan, format);
OUT_RING(chan, 1);
@@ -262,8 +256,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
OUT_RING(chan, info->fix.line_length);
OUT_RING(chan, info->var.xres_virtual);
OUT_RING(chan, info->var.yres_virtual);
- OUT_RING(chan, upper_32_bits(fb));
- OUT_RING(chan, lower_32_bits(fb));
+ OUT_RING(chan, upper_32_bits(nvbo->vma.offset));
+ OUT_RING(chan, lower_32_bits(nvbo->vma.offset));
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index a46a961102f3..8dd04c5dac67 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -28,6 +28,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_ramht.h"
+#include "nouveau_vm.h"
static void
nv50_fifo_playlist_update(struct drm_device *dev)
@@ -44,7 +45,8 @@ nv50_fifo_playlist_update(struct drm_device *dev)
/* We never schedule channel 0 or 127 */
for (i = 1, nr = 0; i < 127; i++) {
- if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) {
+ if (dev_priv->channels.ptr[i] &&
+ dev_priv->channels.ptr[i]->ramfc) {
nv_wo32(cur, (nr * 4), i);
nr++;
}
@@ -60,7 +62,7 @@ static void
nv50_fifo_channel_enable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan = dev_priv->fifos[channel];
+ struct nouveau_channel *chan = dev_priv->channels.ptr[channel];
uint32_t inst;
NV_DEBUG(dev, "ch%d\n", channel);
@@ -105,6 +107,7 @@ nv50_fifo_init_intr(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF);
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF);
}
@@ -118,7 +121,7 @@ nv50_fifo_init_context_table(struct drm_device *dev)
NV_DEBUG(dev, "\n");
for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
- if (dev_priv->fifos[i])
+ if (dev_priv->channels.ptr[i])
nv50_fifo_channel_enable(dev, i);
else
nv50_fifo_channel_disable(dev, i);
@@ -206,6 +209,9 @@ nv50_fifo_takedown(struct drm_device *dev)
if (!pfifo->playlist[0])
return;
+ nv_wr32(dev, 0x2140, 0x00000000);
+ nouveau_irq_unregister(dev, 8);
+
nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
}
@@ -256,6 +262,11 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
}
ramfc = chan->ramfc;
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV50_USER(chan->id), PAGE_SIZE);
+ if (!chan->user)
+ return -ENOMEM;
+
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
@@ -291,10 +302,23 @@ void
nv50_fifo_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_gpuobj *ramfc = NULL;
+ unsigned long flags;
NV_DEBUG(dev, "ch%d\n", chan->id);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pfifo->reassign(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (pfifo->channel_id(dev) == chan->id) {
+ pfifo->disable(dev);
+ pfifo->unload_context(dev);
+ pfifo->enable(dev);
+ }
+
/* This will ensure the channel is seen as disabled. */
nouveau_gpuobj_ref(chan->ramfc, &ramfc);
nouveau_gpuobj_ref(NULL, &chan->ramfc);
@@ -305,6 +329,14 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
nv50_fifo_channel_disable(dev, 127);
nv50_fifo_playlist_update(dev);
+ pfifo->reassign(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the channel resources */
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
+ }
nouveau_gpuobj_ref(NULL, &ramfc);
nouveau_gpuobj_ref(NULL, &chan->cache);
}
@@ -392,7 +424,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1)
return 0;
- chan = dev_priv->fifos[chid];
+ chan = dev_priv->channels.ptr[chid];
if (!chan) {
NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid);
return -EINVAL;
@@ -464,3 +496,8 @@ nv50_fifo_unload_context(struct drm_device *dev)
return 0;
}
+void
+nv50_fifo_tlb_flush(struct drm_device *dev)
+{
+ nv50_vm_flush_engine(dev, 5);
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
index b2fab2bf3d61..6b149c0cc06d 100644
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -26,6 +26,28 @@
#include "nouveau_drv.h"
#include "nouveau_hw.h"
+#include "nv50_display.h"
+
+static void nv50_gpio_isr(struct drm_device *dev);
+static void nv50_gpio_isr_bh(struct work_struct *work);
+
+struct nv50_gpio_priv {
+ struct list_head handlers;
+ spinlock_t lock;
+};
+
+struct nv50_gpio_handler {
+ struct drm_device *dev;
+ struct list_head head;
+ struct work_struct work;
+ bool inhibit;
+
+ struct dcb_gpio_entry *gpio;
+
+ void (*handler)(void *data, int state);
+ void *data;
+};
+
static int
nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift)
{
@@ -75,29 +97,123 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
return 0;
}
+int
+nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag,
+ void (*handler)(void *, int), void *data)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv = pgpio->priv;
+ struct nv50_gpio_handler *gpioh;
+ struct dcb_gpio_entry *gpio;
+ unsigned long flags;
+
+ gpio = nouveau_bios_gpio_entry(dev, tag);
+ if (!gpio)
+ return -ENOENT;
+
+ gpioh = kzalloc(sizeof(*gpioh), GFP_KERNEL);
+ if (!gpioh)
+ return -ENOMEM;
+
+ INIT_WORK(&gpioh->work, nv50_gpio_isr_bh);
+ gpioh->dev = dev;
+ gpioh->gpio = gpio;
+ gpioh->handler = handler;
+ gpioh->data = data;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ list_add(&gpioh->head, &priv->handlers);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
void
-nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on)
+nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag,
+ void (*handler)(void *, int), void *data)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv = pgpio->priv;
+ struct nv50_gpio_handler *gpioh, *tmp;
struct dcb_gpio_entry *gpio;
- u32 reg, mask;
+ unsigned long flags;
gpio = nouveau_bios_gpio_entry(dev, tag);
- if (!gpio) {
- NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag);
+ if (!gpio)
return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ list_for_each_entry_safe(gpioh, tmp, &priv->handlers, head) {
+ if (gpioh->gpio != gpio ||
+ gpioh->handler != handler ||
+ gpioh->data != data)
+ continue;
+ list_del(&gpioh->head);
+ kfree(gpioh);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+bool
+nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on)
+{
+ struct dcb_gpio_entry *gpio;
+ u32 reg, mask;
+
+ gpio = nouveau_bios_gpio_entry(dev, tag);
+ if (!gpio)
+ return false;
reg = gpio->line < 16 ? 0xe050 : 0xe070;
mask = 0x00010001 << (gpio->line & 0xf);
nv_wr32(dev, reg + 4, mask);
- nv_mask(dev, reg + 0, mask, on ? mask : 0);
+ reg = nv_mask(dev, reg + 0, mask, on ? mask : 0);
+ return (reg & mask) == mask;
+}
+
+static int
+nv50_gpio_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&priv->handlers);
+ spin_lock_init(&priv->lock);
+ pgpio->priv = priv;
+ return 0;
+}
+
+static void
+nv50_gpio_destroy(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+
+ kfree(pgpio->priv);
+ pgpio->priv = NULL;
}
int
nv50_gpio_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv;
+ int ret;
+
+ if (!pgpio->priv) {
+ ret = nv50_gpio_create(dev);
+ if (ret)
+ return ret;
+ }
+ priv = pgpio->priv;
/* disable, and ack any pending gpio interrupts */
nv_wr32(dev, 0xe050, 0x00000000);
@@ -107,5 +223,77 @@ nv50_gpio_init(struct drm_device *dev)
nv_wr32(dev, 0xe074, 0xffffffff);
}
+ nouveau_irq_register(dev, 21, nv50_gpio_isr);
return 0;
}
+
+void
+nv50_gpio_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ nv_wr32(dev, 0xe050, 0x00000000);
+ if (dev_priv->chipset >= 0x90)
+ nv_wr32(dev, 0xe070, 0x00000000);
+ nouveau_irq_unregister(dev, 21);
+
+ nv50_gpio_destroy(dev);
+}
+
+static void
+nv50_gpio_isr_bh(struct work_struct *work)
+{
+ struct nv50_gpio_handler *gpioh =
+ container_of(work, struct nv50_gpio_handler, work);
+ struct drm_nouveau_private *dev_priv = gpioh->dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv = pgpio->priv;
+ unsigned long flags;
+ int state;
+
+ state = pgpio->get(gpioh->dev, gpioh->gpio->tag);
+ if (state < 0)
+ return;
+
+ gpioh->handler(gpioh->data, state);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ gpioh->inhibit = false;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nv50_gpio_isr(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
+ struct nv50_gpio_priv *priv = pgpio->priv;
+ struct nv50_gpio_handler *gpioh;
+ u32 intr0, intr1 = 0;
+ u32 hi, lo, ch;
+
+ intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
+ if (dev_priv->chipset >= 0x90)
+ intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
+
+ hi = (intr0 & 0x0000ffff) | (intr1 << 16);
+ lo = (intr0 >> 16) | (intr1 & 0xffff0000);
+ ch = hi | lo;
+
+ nv_wr32(dev, 0xe054, intr0);
+ if (dev_priv->chipset >= 0x90)
+ nv_wr32(dev, 0xe074, intr1);
+
+ spin_lock(&priv->lock);
+ list_for_each_entry(gpioh, &priv->handlers, head) {
+ if (!(ch & (1 << gpioh->gpio->line)))
+ continue;
+
+ if (gpioh->inhibit)
+ continue;
+ gpioh->inhibit = true;
+
+ queue_work(dev_priv->wq, &gpioh->work);
+ }
+ spin_unlock(&priv->lock);
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index cbf5ae2f67d4..2d7ea75a09d4 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -29,6 +29,12 @@
#include "nouveau_drv.h"
#include "nouveau_ramht.h"
#include "nouveau_grctx.h"
+#include "nouveau_dma.h"
+#include "nouveau_vm.h"
+#include "nv50_evo.h"
+
+static int nv50_graph_register(struct drm_device *);
+static void nv50_graph_isr(struct drm_device *);
static void
nv50_graph_init_reset(struct drm_device *dev)
@@ -46,6 +52,7 @@ nv50_graph_init_intr(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
+ nouveau_irq_register(dev, 12, nv50_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
nv_wr32(dev, 0x400138, 0xffffffff);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -145,12 +152,15 @@ nv50_graph_init(struct drm_device *dev)
nv50_graph_init_reset(dev);
nv50_graph_init_regs__nv(dev);
nv50_graph_init_regs(dev);
- nv50_graph_init_intr(dev);
ret = nv50_graph_init_ctxctl(dev);
if (ret)
return ret;
+ ret = nv50_graph_register(dev);
+ if (ret)
+ return ret;
+ nv50_graph_init_intr(dev);
return 0;
}
@@ -158,6 +168,8 @@ void
nv50_graph_takedown(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
+ nv_wr32(dev, 0x40013c, 0x00000000);
+ nouveau_irq_unregister(dev, 12);
}
void
@@ -190,7 +202,7 @@ nv50_graph_channel(struct drm_device *dev)
inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->fifos[i];
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan && chan->ramin && chan->ramin->vinst == inst)
return chan;
@@ -211,7 +223,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000,
+ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
@@ -234,6 +246,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
dev_priv->engine.instmem.flush(dev);
+ atomic_inc(&chan->vm->pgraph_refs);
return 0;
}
@@ -242,18 +255,31 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
+ unsigned long flags;
NV_DEBUG(dev, "ch%d\n", chan->id);
if (!chan->ramin)
return;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ pgraph->fifo_access(dev, false);
+
+ if (pgraph->channel(dev) == chan)
+ pgraph->unload_context(dev);
+
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(chan->ramin, i, 0);
dev_priv->engine.instmem.flush(dev);
+ pgraph->fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+
+ atomic_dec(&chan->vm->pgraph_refs);
}
static int
@@ -306,7 +332,7 @@ nv50_graph_unload_context(struct drm_device *dev)
return 0;
}
-void
+static void
nv50_graph_context_switch(struct drm_device *dev)
{
uint32_t inst;
@@ -322,8 +348,8 @@ nv50_graph_context_switch(struct drm_device *dev)
}
static int
-nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
struct nouveau_gpuobj *gpuobj;
@@ -340,8 +366,8 @@ nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
}
static int
-nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
if (nouveau_notifier_offset(chan->nvsw.vblsem, &data))
return -ERANGE;
@@ -351,16 +377,16 @@ nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass,
}
static int
-nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
chan->nvsw.vblsem_rval = data;
return 0;
}
static int
-nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass,
- int mthd, uint32_t data)
+nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -368,37 +394,656 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass,
if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
return -EINVAL;
- if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN) &
- NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data))) {
- nv_wr32(dev, NV50_PDISPLAY_INTR_1,
- NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data));
- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev,
- NV50_PDISPLAY_INTR_EN) |
- NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data));
- }
+ drm_vblank_get(dev, data);
+ chan->nvsw.vblsem_head = data;
list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
+
+ return 0;
+}
+
+static int
+nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
+ u32 class, u32 mthd, u32 data)
+{
+ struct nouveau_page_flip_state s;
+
+ if (!nouveau_finish_page_flip(chan, &s)) {
+ /* XXX - Do something here */
+ }
+
return 0;
}
-static struct nouveau_pgraph_object_method nv50_graph_nvsw_methods[] = {
- { 0x018c, nv50_graph_nvsw_dma_vblsem },
- { 0x0400, nv50_graph_nvsw_vblsem_offset },
- { 0x0404, nv50_graph_nvsw_vblsem_release_val },
- { 0x0408, nv50_graph_nvsw_vblsem_release },
+static int
+nv50_graph_register(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->engine.graph.registered)
+ return 0;
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+ NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+ NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+ NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+ /* tesla */
+ if (dev_priv->chipset == 0x50)
+ NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+ else
+ if (dev_priv->chipset < 0xa0)
+ NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+ else {
+ switch (dev_priv->chipset) {
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ NVOBJ_CLASS(dev, 0x8397, GR);
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ NVOBJ_CLASS(dev, 0x8597, GR);
+ break;
+ case 0xaf:
+ NVOBJ_CLASS(dev, 0x8697, GR);
+ break;
+ }
+ }
+
+ /* compute */
+ NVOBJ_CLASS(dev, 0x50c0, GR);
+ if (dev_priv->chipset > 0xa0 &&
+ dev_priv->chipset != 0xaa &&
+ dev_priv->chipset != 0xac)
+ NVOBJ_CLASS(dev, 0x85c0, GR);
+
+ dev_priv->engine.graph.registered = true;
+ return 0;
+}
+
+void
+nv50_graph_tlb_flush(struct drm_device *dev)
+{
+ nv50_vm_flush_engine(dev, 0);
+}
+
+void
+nv86_graph_tlb_flush(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ bool idle, timeout = false;
+ unsigned long flags;
+ u64 start;
+ u32 tmp;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+
+ start = ptimer->read(dev);
+ do {
+ idle = true;
+
+ for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+ } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
+
+ if (timeout) {
+ NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
+ nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+ }
+
+ nv50_vm_flush_engine(dev, 0);
+
+ nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+}
+
+static struct nouveau_enum nv50_mp_exec_error_names[] =
+{
+ { 3, "STACK_UNDERFLOW" },
+ { 4, "QUADON_ACTIVE" },
+ { 8, "TIMEOUT" },
+ { 0x10, "INVALID_OPCODE" },
+ { 0x40, "BREAKPOINT" },
+ {}
+};
+
+static struct nouveau_bitfield nv50_graph_trap_m2mf[] = {
+ { 0x00000001, "NOTIFY" },
+ { 0x00000002, "IN" },
+ { 0x00000004, "OUT" },
+ {}
+};
+
+static struct nouveau_bitfield nv50_graph_trap_vfetch[] = {
+ { 0x00000001, "FAULT" },
+ {}
+};
+
+static struct nouveau_bitfield nv50_graph_trap_strmout[] = {
+ { 0x00000001, "FAULT" },
{}
};
-struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
- { 0x506e, true, nv50_graph_nvsw_methods }, /* nvsw */
- { 0x0030, false, NULL }, /* null */
- { 0x5039, false, NULL }, /* m2mf */
- { 0x502d, false, NULL }, /* 2d */
- { 0x50c0, false, NULL }, /* compute */
- { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */
- { 0x5097, false, NULL }, /* tesla (nv50) */
- { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */
- { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */
- { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
+static struct nouveau_bitfield nv50_graph_trap_ccache[] = {
+ { 0x00000001, "FAULT" },
{}
};
+
+/* There must be a *lot* of these. Will take some time to gather them up. */
+struct nouveau_enum nv50_data_error_names[] = {
+ { 0x00000003, "INVALID_QUERY_OR_TEXTURE" },
+ { 0x00000004, "INVALID_VALUE" },
+ { 0x00000005, "INVALID_ENUM" },
+ { 0x00000008, "INVALID_OBJECT" },
+ { 0x00000009, "READ_ONLY_OBJECT" },
+ { 0x0000000a, "SUPERVISOR_OBJECT" },
+ { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" },
+ { 0x0000000c, "INVALID_BITFIELD" },
+ { 0x0000000d, "BEGIN_END_ACTIVE" },
+ { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" },
+ { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" },
+ { 0x00000010, "RT_DOUBLE_BIND" },
+ { 0x00000011, "RT_TYPES_MISMATCH" },
+ { 0x00000012, "RT_LINEAR_WITH_ZETA" },
+ { 0x00000015, "FP_TOO_FEW_REGS" },
+ { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" },
+ { 0x00000017, "RT_LINEAR_WITH_MSAA" },
+ { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" },
+ { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" },
+ { 0x0000001a, "RT_INVALID_ALIGNMENT" },
+ { 0x0000001b, "SAMPLER_OVER_LIMIT" },
+ { 0x0000001c, "TEXTURE_OVER_LIMIT" },
+ { 0x0000001e, "GP_TOO_MANY_OUTPUTS" },
+ { 0x0000001f, "RT_BPP128_WITH_MS8" },
+ { 0x00000021, "Z_OUT_OF_BOUNDS" },
+ { 0x00000023, "XY_OUT_OF_BOUNDS" },
+ { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" },
+ { 0x00000028, "CP_NO_REG_SPACE_STRIPED" },
+ { 0x00000029, "CP_NO_REG_SPACE_PACKED" },
+ { 0x0000002a, "CP_NOT_ENOUGH_WARPS" },
+ { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" },
+ { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" },
+ { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" },
+ { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" },
+ { 0x00000031, "ENG2D_FORMAT_MISMATCH" },
+ { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" },
+ { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" },
+ { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" },
+ { 0x00000046, "LAYER_ID_NEEDS_GP" },
+ { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" },
+ { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" },
+ {}
+};
+
+static struct nouveau_bitfield nv50_graph_intr[] = {
+ { 0x00000001, "NOTIFY" },
+ { 0x00000002, "COMPUTE_QUERY" },
+ { 0x00000010, "ILLEGAL_MTHD" },
+ { 0x00000020, "ILLEGAL_CLASS" },
+ { 0x00000040, "DOUBLE_NOTIFY" },
+ { 0x00001000, "CONTEXT_SWITCH" },
+ { 0x00010000, "BUFFER_NOTIFY" },
+ { 0x00100000, "DATA_ERROR" },
+ { 0x00200000, "TRAP" },
+ { 0x01000000, "SINGLE_STEP" },
+ {}
+};
+
+static void
+nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t units = nv_rd32(dev, 0x1540);
+ uint32_t addr, mp10, status, pc, oplow, ophigh;
+ int i;
+ int mps = 0;
+ for (i = 0; i < 4; i++) {
+ if (!(units & 1 << (i+24)))
+ continue;
+ if (dev_priv->chipset < 0xa0)
+ addr = 0x408200 + (tpid << 12) + (i << 7);
+ else
+ addr = 0x408100 + (tpid << 11) + (i << 7);
+ mp10 = nv_rd32(dev, addr + 0x10);
+ status = nv_rd32(dev, addr + 0x14);
+ if (!status)
+ continue;
+ if (display) {
+ nv_rd32(dev, addr + 0x20);
+ pc = nv_rd32(dev, addr + 0x24);
+ oplow = nv_rd32(dev, addr + 0x70);
+ ophigh= nv_rd32(dev, addr + 0x74);
+ NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
+ "TP %d MP %d: ", tpid, i);
+ nouveau_enum_print(nv50_mp_exec_error_names, status);
+ printk(" at %06x warp %d, opcode %08x %08x\n",
+ pc&0xffffff, pc >> 24,
+ oplow, ophigh);
+ }
+ nv_wr32(dev, addr + 0x10, mp10);
+ nv_wr32(dev, addr + 0x14, 0);
+ mps++;
+ }
+ if (!mps && display)
+ NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
+ "No MPs claiming errors?\n", tpid);
+}
+
+static void
+nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
+ uint32_t ustatus_new, int display, const char *name)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int tps = 0;
+ uint32_t units = nv_rd32(dev, 0x1540);
+ int i, r;
+ uint32_t ustatus_addr, ustatus;
+ for (i = 0; i < 16; i++) {
+ if (!(units & (1 << i)))
+ continue;
+ if (dev_priv->chipset < 0xa0)
+ ustatus_addr = ustatus_old + (i << 12);
+ else
+ ustatus_addr = ustatus_new + (i << 11);
+ ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
+ if (!ustatus)
+ continue;
+ tps++;
+ switch (type) {
+ case 6: /* texture error... unknown for now */
+ nv50_fb_vm_trap(dev, display, name);
+ if (display) {
+ NV_ERROR(dev, "magic set %d:\n", i);
+ for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(dev, r));
+ }
+ break;
+ case 7: /* MP error */
+ if (ustatus & 0x00010000) {
+ nv50_pgraph_mp_trap(dev, i, display);
+ ustatus &= ~0x00010000;
+ }
+ break;
+ case 8: /* TPDMA error */
+ {
+ uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
+ uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
+ uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
+ uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
+ uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
+ uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
+ uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
+ nv50_fb_vm_trap(dev, display, name);
+ /* 2d engine destination */
+ if (ustatus & 0x00000010) {
+ if (display) {
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
+ i, e14, e10);
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+ i, e0c, e18, e1c, e20, e24);
+ }
+ ustatus &= ~0x00000010;
+ }
+ /* Render target */
+ if (ustatus & 0x00000040) {
+ if (display) {
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
+ i, e14, e10);
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+ i, e0c, e18, e1c, e20, e24);
+ }
+ ustatus &= ~0x00000040;
+ }
+ /* CUDA memory: l[], g[] or stack. */
+ if (ustatus & 0x00000080) {
+ if (display) {
+ if (e18 & 0x80000000) {
+ /* g[] read fault? */
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
+ i, e14, e10 | ((e18 >> 24) & 0x1f));
+ e18 &= ~0x1f000000;
+ } else if (e18 & 0xc) {
+ /* g[] write fault? */
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
+ i, e14, e10 | ((e18 >> 7) & 0x1f));
+ e18 &= ~0x00000f80;
+ } else {
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
+ i, e14, e10);
+ }
+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+ i, e0c, e18, e1c, e20, e24);
+ }
+ ustatus &= ~0x00000080;
+ }
+ }
+ break;
+ }
+ if (ustatus) {
+ if (display)
+ NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+ }
+ nv_wr32(dev, ustatus_addr, 0xc0000000);
+ }
+
+ if (!tps && display)
+ NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
+}
+
+static int
+nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid)
+{
+ u32 status = nv_rd32(dev, 0x400108);
+ u32 ustatus;
+
+ if (!status && display) {
+ NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n");
+ return 1;
+ }
+
+ /* DISPATCH: Relays commands to other units and handles NOTIFY,
+ * COND, QUERY. If you get a trap from it, the command is still stuck
+ * in DISPATCH and you need to do something about it. */
+ if (status & 0x001) {
+ ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
+ if (!ustatus && display) {
+ NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
+ }
+
+ nv_wr32(dev, 0x400500, 0x00000000);
+
+ /* Known to be triggered by screwed up NOTIFY and COND... */
+ if (ustatus & 0x00000001) {
+ u32 addr = nv_rd32(dev, 0x400808);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 datal = nv_rd32(dev, 0x40080c);
+ u32 datah = nv_rd32(dev, 0x400810);
+ u32 class = nv_rd32(dev, 0x400814);
+ u32 r848 = nv_rd32(dev, 0x400848);
+
+ NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n");
+ if (display && (addr & 0x80000000)) {
+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+ "subc %d class 0x%04x mthd 0x%04x "
+ "data 0x%08x%08x "
+ "400808 0x%08x 400848 0x%08x\n",
+ chid, inst, subc, class, mthd, datah,
+ datal, addr, r848);
+ } else
+ if (display) {
+ NV_INFO(dev, "PGRAPH - no stuck command?\n");
+ }
+
+ nv_wr32(dev, 0x400808, 0);
+ nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
+ nv_wr32(dev, 0x400848, 0);
+ ustatus &= ~0x00000001;
+ }
+
+ if (ustatus & 0x00000002) {
+ u32 addr = nv_rd32(dev, 0x40084c);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, 0x40085c);
+ u32 class = nv_rd32(dev, 0x400814);
+
+ NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n");
+ if (display && (addr & 0x80000000)) {
+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+ "subc %d class 0x%04x mthd 0x%04x "
+ "data 0x%08x 40084c 0x%08x\n",
+ chid, inst, subc, class, mthd,
+ data, addr);
+ } else
+ if (display) {
+ NV_INFO(dev, "PGRAPH - no stuck command?\n");
+ }
+
+ nv_wr32(dev, 0x40084c, 0);
+ ustatus &= ~0x00000002;
+ }
+
+ if (ustatus && display) {
+ NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown "
+ "0x%08x)\n", ustatus);
+ }
+
+ nv_wr32(dev, 0x400804, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x001);
+ status &= ~0x001;
+ if (!status)
+ return 0;
+ }
+
+ /* M2MF: Memory to memory copy engine. */
+ if (status & 0x002) {
+ u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
+ if (display) {
+ NV_INFO(dev, "PGRAPH - TRAP_M2MF");
+ nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n",
+ nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808),
+ nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810));
+
+ }
+
+ /* No sane way found yet -- just reset the bugger. */
+ nv_wr32(dev, 0x400040, 2);
+ nv_wr32(dev, 0x400040, 0);
+ nv_wr32(dev, 0x406800, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x002);
+ status &= ~0x002;
+ }
+
+ /* VFETCH: Fetches data from vertex buffers. */
+ if (status & 0x004) {
+ u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
+ if (display) {
+ NV_INFO(dev, "PGRAPH - TRAP_VFETCH");
+ nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n",
+ nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08),
+ nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10));
+ }
+
+ nv_wr32(dev, 0x400c04, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x004);
+ status &= ~0x004;
+ }
+
+ /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
+ if (status & 0x008) {
+ ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
+ if (display) {
+ NV_INFO(dev, "PGRAPH - TRAP_STRMOUT");
+ nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n",
+ nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808),
+ nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810));
+
+ }
+
+ /* No sane way found yet -- just reset the bugger. */
+ nv_wr32(dev, 0x400040, 0x80);
+ nv_wr32(dev, 0x400040, 0);
+ nv_wr32(dev, 0x401800, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x008);
+ status &= ~0x008;
+ }
+
+ /* CCACHE: Handles code and c[] caches and fills them. */
+ if (status & 0x010) {
+ ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
+ if (display) {
+ NV_INFO(dev, "PGRAPH - TRAP_CCACHE");
+ nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x"
+ " %08x %08x %08x\n",
+ nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804),
+ nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c),
+ nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814),
+ nv_rd32(dev, 0x40581c));
+
+ }
+
+ nv_wr32(dev, 0x405018, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x010);
+ status &= ~0x010;
+ }
+
+ /* Unknown, not seen yet... 0x402000 is the only trap status reg
+ * remaining, so try to handle it anyway. Perhaps related to that
+ * unknown DMA slot on tesla? */
+ if (status & 0x20) {
+ ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
+ if (display)
+ NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus);
+ nv_wr32(dev, 0x402000, 0xc0000000);
+ /* no status modifiction on purpose */
+ }
+
+ /* TEXTURE: CUDA texturing units */
+ if (status & 0x040) {
+ nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display,
+ "PGRAPH - TRAP_TEXTURE");
+ nv_wr32(dev, 0x400108, 0x040);
+ status &= ~0x040;
+ }
+
+ /* MP: CUDA execution engines. */
+ if (status & 0x080) {
+ nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display,
+ "PGRAPH - TRAP_MP");
+ nv_wr32(dev, 0x400108, 0x080);
+ status &= ~0x080;
+ }
+
+ /* TPDMA: Handles TP-initiated uncached memory accesses:
+ * l[], g[], stack, 2d surfaces, render targets. */
+ if (status & 0x100) {
+ nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display,
+ "PGRAPH - TRAP_TPDMA");
+ nv_wr32(dev, 0x400108, 0x100);
+ status &= ~0x100;
+ }
+
+ if (status) {
+ if (display)
+ NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status);
+ nv_wr32(dev, 0x400108, status);
+ }
+
+ return 1;
+}
+
+static int
+nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->ramin)
+ continue;
+
+ if (inst == chan->ramin->vinst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nv50_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, 0x400100))) {
+ u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12;
+ u32 chid = nv50_graph_isr_chid(dev, inst);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400814);
+ u32 show = stat;
+
+ if (stat & 0x00000010) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class,
+ mthd, data))
+ show &= ~0x00000010;
+ }
+
+ if (stat & 0x00001000) {
+ nv_wr32(dev, 0x400500, 0x00000000);
+ nv_wr32(dev, 0x400100, 0x00001000);
+ nv_mask(dev, 0x40013c, 0x00001000, 0x00000000);
+ nv50_graph_context_switch(dev);
+ stat &= ~0x00001000;
+ show &= ~0x00001000;
+ }
+
+ show = (show && nouveau_ratelimit()) ? show : 0;
+
+ if (show & 0x00100000) {
+ u32 ecode = nv_rd32(dev, 0x400110);
+ NV_INFO(dev, "PGRAPH - DATA_ERROR ");
+ nouveau_enum_print(nv50_data_error_names, ecode);
+ printk("\n");
+ }
+
+ if (stat & 0x00200000) {
+ if (!nv50_pgraph_trap_handler(dev, show, inst, chid))
+ show &= ~0x00200000;
+ }
+
+ nv_wr32(dev, 0x400100, stat);
+ nv_wr32(dev, 0x400500, 0x00010001);
+
+ if (show) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv50_graph_intr, show);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d "
+ "class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ }
+ }
+
+ if (nv_rd32(dev, 0x400824) & (1 << 31))
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index a53fc974332b..ea0041810ae3 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -27,14 +27,20 @@
#include "drmP.h"
#include "drm.h"
+
#include "nouveau_drv.h"
+#include "nouveau_vm.h"
+
+#define BAR1_VM_BASE 0x0020000000ULL
+#define BAR1_VM_SIZE pci_resource_len(dev->pdev, 1)
+#define BAR3_VM_BASE 0x0000000000ULL
+#define BAR3_VM_SIZE pci_resource_len(dev->pdev, 3)
struct nv50_instmem_priv {
uint32_t save1700[5]; /* 0x1700->0x1710 */
- struct nouveau_gpuobj *pramin_pt;
- struct nouveau_gpuobj *pramin_bar;
- struct nouveau_gpuobj *fb_bar;
+ struct nouveau_gpuobj *bar1_dmaobj;
+ struct nouveau_gpuobj *bar3_dmaobj;
};
static void
@@ -48,6 +54,7 @@ nv50_channel_del(struct nouveau_channel **pchan)
return;
nouveau_gpuobj_ref(NULL, &chan->ramfc);
+ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
nouveau_gpuobj_ref(NULL, &chan->vm_pd);
if (chan->ramin_heap.free_stack.next)
drm_mm_takedown(&chan->ramin_heap);
@@ -56,14 +63,14 @@ nv50_channel_del(struct nouveau_channel **pchan)
}
static int
-nv50_channel_new(struct drm_device *dev, u32 size,
+nv50_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm,
struct nouveau_channel **pchan)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200;
struct nouveau_channel *chan;
- int ret;
+ int ret, i;
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
@@ -92,6 +99,17 @@ nv50_channel_new(struct drm_device *dev, u32 size,
return ret;
}
+ for (i = 0; i < 0x4000; i += 8) {
+ nv_wo32(chan->vm_pd, i + 0, 0x00000000);
+ nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
+ }
+
+ ret = nouveau_vm_ref(vm, &chan->vm, chan->vm_pd);
+ if (ret) {
+ nv50_channel_del(&chan);
+ return ret;
+ }
+
ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
chan->ramin->pinst + fc,
chan->ramin->vinst + fc, 0x100,
@@ -111,6 +129,7 @@ nv50_instmem_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv;
struct nouveau_channel *chan;
+ struct nouveau_vm *vm;
int ret, i;
u32 tmp;
@@ -127,112 +146,87 @@ nv50_instmem_init(struct drm_device *dev)
ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size);
if (ret) {
NV_ERROR(dev, "Failed to init RAMIN heap\n");
- return -ENOMEM;
+ goto error;
}
- /* we need a channel to plug into the hw to control the BARs */
- ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]);
+ /* BAR3 */
+ ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE,
+ &dev_priv->bar3_vm);
if (ret)
- return ret;
- chan = dev_priv->fifos[127] = dev_priv->fifos[0];
+ goto error;
- /* allocate page table for PRAMIN BAR */
- ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
- &priv->pramin_pt);
+ ret = nouveau_gpuobj_new(dev, NULL, (BAR3_VM_SIZE >> 12) * 8,
+ 0x1000, NVOBJ_FLAG_DONT_MAP |
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->bar3_vm->pgt[0].obj[0]);
if (ret)
- return ret;
+ goto error;
+ dev_priv->bar3_vm->pgt[0].refcount[0] = 1;
- nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63);
- nv_wo32(chan->vm_pd, 0x0004, 0);
+ nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]);
- /* DMA object for PRAMIN BAR */
- ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar);
+ ret = nv50_channel_new(dev, 128 * 1024, dev_priv->bar3_vm, &chan);
if (ret)
- return ret;
- nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000);
- nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1);
- nv_wo32(priv->pramin_bar, 0x08, 0x00000000);
- nv_wo32(priv->pramin_bar, 0x0c, 0x00000000);
- nv_wo32(priv->pramin_bar, 0x10, 0x00000000);
- nv_wo32(priv->pramin_bar, 0x14, 0x00000000);
-
- /* map channel into PRAMIN, gpuobj didn't do it for us */
- ret = nv50_instmem_bind(dev, chan->ramin);
+ goto error;
+ dev_priv->channels.ptr[0] = dev_priv->channels.ptr[127] = chan;
+
+ ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR3_VM_BASE, BAR3_VM_SIZE,
+ NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM,
+ NV_MEM_TYPE_VM, NV_MEM_COMP_VM,
+ &priv->bar3_dmaobj);
if (ret)
- return ret;
+ goto error;
- /* poke regs... */
nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12));
nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
- nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4));
-
- tmp = nv_ri32(dev, 0);
- nv_wi32(dev, 0, ~tmp);
- if (nv_ri32(dev, 0) != ~tmp) {
- NV_ERROR(dev, "PRAMIN readback failed\n");
- return -EIO;
- }
- nv_wi32(dev, 0, tmp);
+ nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4));
+ dev_priv->engine.instmem.flush(dev);
dev_priv->ramin_available = true;
- /* Determine VM layout */
- dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
- dev_priv->vm_gart_size = NV50_VM_BLOCK;
-
- dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
- dev_priv->vm_vram_size = dev_priv->vram_size;
- if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
- dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
- dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
- dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
-
- dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
-
- NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
- dev_priv->vm_gart_base,
- dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
- NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
- dev_priv->vm_vram_base,
- dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
-
- /* VRAM page table(s), mapped into VM at +1GiB */
- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8,
- 0, NVOBJ_FLAG_ZERO_ALLOC,
- &chan->vm_vram_pt[i]);
- if (ret) {
- NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret);
- dev_priv->vm_vram_pt_nr = i;
- return ret;
- }
- dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i];
-
- nv_wo32(chan->vm_pd, 0x10 + (i*8),
- chan->vm_vram_pt[i]->vinst | 0x61);
- nv_wo32(chan->vm_pd, 0x14 + (i*8), 0);
+ tmp = nv_ro32(chan->ramin, 0);
+ nv_wo32(chan->ramin, 0, ~tmp);
+ if (nv_ro32(chan->ramin, 0) != ~tmp) {
+ NV_ERROR(dev, "PRAMIN readback failed\n");
+ ret = -EIO;
+ goto error;
}
+ nv_wo32(chan->ramin, 0, tmp);
- /* DMA object for FB BAR */
- ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar);
+ /* BAR1 */
+ ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, &vm);
if (ret)
- return ret;
- nv_wo32(priv->fb_bar, 0x00, 0x7fc00000);
- nv_wo32(priv->fb_bar, 0x04, 0x40000000 +
- pci_resource_len(dev->pdev, 1) - 1);
- nv_wo32(priv->fb_bar, 0x08, 0x40000000);
- nv_wo32(priv->fb_bar, 0x0c, 0x00000000);
- nv_wo32(priv->fb_bar, 0x10, 0x00000000);
- nv_wo32(priv->fb_bar, 0x14, 0x00000000);
+ goto error;
- dev_priv->engine.instmem.flush(dev);
+ ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, chan->vm_pd);
+ if (ret)
+ goto error;
+ nouveau_vm_ref(NULL, &vm, NULL);
- nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4));
+ ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR1_VM_BASE, BAR1_VM_SIZE,
+ NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM,
+ NV_MEM_TYPE_VM, NV_MEM_COMP_VM,
+ &priv->bar1_dmaobj);
+ if (ret)
+ goto error;
+
+ nv_wr32(dev, 0x001708, 0x80000000 | (priv->bar1_dmaobj->cinst >> 4));
for (i = 0; i < 8; i++)
nv_wr32(dev, 0x1900 + (i*4), 0);
+ /* Create shared channel VM, space is reserved at the beginning
+ * to catch "NULL pointer" references
+ */
+ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL,
+ &dev_priv->chan_vm);
+ if (ret)
+ return ret;
+
return 0;
+
+error:
+ nv50_instmem_takedown(dev);
+ return ret;
}
void
@@ -240,7 +234,7 @@ nv50_instmem_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- struct nouveau_channel *chan = dev_priv->fifos[0];
+ struct nouveau_channel *chan = dev_priv->channels.ptr[0];
int i;
NV_DEBUG(dev, "\n");
@@ -250,23 +244,23 @@ nv50_instmem_takedown(struct drm_device *dev)
dev_priv->ramin_available = false;
- /* Restore state from before init */
+ nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL);
+
for (i = 0x1700; i <= 0x1710; i += 4)
nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]);
- nouveau_gpuobj_ref(NULL, &priv->fb_bar);
- nouveau_gpuobj_ref(NULL, &priv->pramin_bar);
- nouveau_gpuobj_ref(NULL, &priv->pramin_pt);
+ nouveau_gpuobj_ref(NULL, &priv->bar3_dmaobj);
+ nouveau_gpuobj_ref(NULL, &priv->bar1_dmaobj);
- /* Destroy dummy channel */
- if (chan) {
- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
- nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
- dev_priv->vm_vram_pt_nr = 0;
+ nouveau_vm_ref(NULL, &dev_priv->bar1_vm, chan->vm_pd);
+ dev_priv->channels.ptr[127] = 0;
+ nv50_channel_del(&dev_priv->channels.ptr[0]);
- nv50_channel_del(&dev_priv->fifos[0]);
- dev_priv->fifos[127] = NULL;
- }
+ nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]);
+ nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL);
+
+ if (dev_priv->ramin_heap.free_stack.next)
+ drm_mm_takedown(&dev_priv->ramin_heap);
dev_priv->engine.instmem.priv = NULL;
kfree(priv);
@@ -276,16 +270,8 @@ int
nv50_instmem_suspend(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan = dev_priv->fifos[0];
- struct nouveau_gpuobj *ramin = chan->ramin;
- int i;
- ramin->im_backing_suspend = vmalloc(ramin->size);
- if (!ramin->im_backing_suspend)
- return -ENOMEM;
-
- for (i = 0; i < ramin->size; i += 4)
- ramin->im_backing_suspend[i/4] = nv_ri32(dev, i);
+ dev_priv->ramin_available = false;
return 0;
}
@@ -294,147 +280,124 @@ nv50_instmem_resume(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- struct nouveau_channel *chan = dev_priv->fifos[0];
- struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_channel *chan = dev_priv->channels.ptr[0];
int i;
- dev_priv->ramin_available = false;
- dev_priv->ramin_base = ~0;
- for (i = 0; i < ramin->size; i += 4)
- nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]);
- dev_priv->ramin_available = true;
- vfree(ramin->im_backing_suspend);
- ramin->im_backing_suspend = NULL;
-
/* Poke the relevant regs, and pray it works :) */
nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12));
nv_wr32(dev, NV50_PUNK_UNK1710, 0);
nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) |
NV50_PUNK_BAR_CFG_BASE_VALID);
- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) |
+ nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->bar1_dmaobj->cinst >> 4) |
NV50_PUNK_BAR1_CTXDMA_VALID);
- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) |
+ nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->bar3_dmaobj->cinst >> 4) |
NV50_PUNK_BAR3_CTXDMA_VALID);
for (i = 0; i < 8; i++)
nv_wr32(dev, 0x1900 + (i*4), 0);
+
+ dev_priv->ramin_available = true;
}
+struct nv50_gpuobj_node {
+ struct nouveau_vram *vram;
+ struct nouveau_vma chan_vma;
+ u32 align;
+};
+
+
int
-nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
- uint32_t *sz)
+nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align)
{
+ struct drm_device *dev = gpuobj->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
+ struct nv50_gpuobj_node *node = NULL;
int ret;
- if (gpuobj->im_backing)
- return -EINVAL;
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+ node->align = align;
- *sz = ALIGN(*sz, 4096);
- if (*sz == 0)
- return -EINVAL;
+ size = (size + 4095) & ~4095;
+ align = max(align, (u32)4096);
- ret = nouveau_bo_new(dev, NULL, *sz, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
- true, false, &gpuobj->im_backing);
+ ret = vram->get(dev, size, align, 0, 0, &node->vram);
if (ret) {
- NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
+ kfree(node);
return ret;
}
- ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
- if (ret) {
- NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
- nouveau_bo_ref(NULL, &gpuobj->im_backing);
- return ret;
+ gpuobj->vinst = node->vram->offset;
+
+ if (gpuobj->flags & NVOBJ_FLAG_VM) {
+ u32 flags = NV_MEM_ACCESS_RW;
+ if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER))
+ flags |= NV_MEM_ACCESS_SYS;
+
+ ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags,
+ &node->chan_vma);
+ if (ret) {
+ vram->put(dev, &node->vram);
+ kfree(node);
+ return ret;
+ }
+
+ nouveau_vm_map(&node->chan_vma, node->vram);
+ gpuobj->vinst = node->chan_vma.offset;
}
- gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
+ gpuobj->size = size;
+ gpuobj->node = node;
return 0;
}
void
-nv50_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+nv50_instmem_put(struct nouveau_gpuobj *gpuobj)
{
+ struct drm_device *dev = gpuobj->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
+ struct nv50_gpuobj_node *node;
+
+ node = gpuobj->node;
+ gpuobj->node = NULL;
- if (gpuobj && gpuobj->im_backing) {
- if (gpuobj->im_bound)
- dev_priv->engine.instmem.unbind(dev, gpuobj);
- nouveau_bo_unpin(gpuobj->im_backing);
- nouveau_bo_ref(NULL, &gpuobj->im_backing);
- gpuobj->im_backing = NULL;
+ if (node->chan_vma.node) {
+ nouveau_vm_unmap(&node->chan_vma);
+ nouveau_vm_put(&node->chan_vma);
}
+ vram->put(dev, &node->vram);
+ kfree(node);
}
int
-nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+nv50_instmem_map(struct nouveau_gpuobj *gpuobj)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- struct nouveau_gpuobj *pramin_pt = priv->pramin_pt;
- uint32_t pte, pte_end;
- uint64_t vram;
-
- if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
- return -EINVAL;
-
- NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
- gpuobj->im_pramin->start, gpuobj->im_pramin->size);
-
- pte = (gpuobj->im_pramin->start >> 12) << 1;
- pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
- vram = gpuobj->vinst;
-
- NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
- gpuobj->im_pramin->start, pte, pte_end);
- NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
-
- vram |= 1;
- if (dev_priv->vram_sys_base) {
- vram += dev_priv->vram_sys_base;
- vram |= 0x30;
- }
-
- while (pte < pte_end) {
- nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
- nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
- vram += 0x1000;
- pte += 2;
- }
- dev_priv->engine.instmem.flush(dev);
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct nv50_gpuobj_node *node = gpuobj->node;
+ int ret;
- nv50_vm_flush(dev, 4);
- nv50_vm_flush(dev, 6);
+ ret = nouveau_vm_get(dev_priv->bar3_vm, gpuobj->size, 12,
+ NV_MEM_ACCESS_RW, &node->vram->bar_vma);
+ if (ret)
+ return ret;
- gpuobj->im_bound = 1;
+ nouveau_vm_map(&node->vram->bar_vma, node->vram);
+ gpuobj->pinst = node->vram->bar_vma.offset;
return 0;
}
-int
-nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+void
+nv50_instmem_unmap(struct nouveau_gpuobj *gpuobj)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- uint32_t pte, pte_end;
-
- if (gpuobj->im_bound == 0)
- return -EINVAL;
-
- /* can happen during late takedown */
- if (unlikely(!dev_priv->ramin_available))
- return 0;
+ struct nv50_gpuobj_node *node = gpuobj->node;
- pte = (gpuobj->im_pramin->start >> 12) << 1;
- pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
-
- while (pte < pte_end) {
- nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000);
- nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000);
- pte += 2;
+ if (node->vram->bar_vma.node) {
+ nouveau_vm_unmap(&node->vram->bar_vma);
+ nouveau_vm_put(&node->vram->bar_vma);
}
- dev_priv->engine.instmem.flush(dev);
-
- gpuobj->im_bound = 0;
- return 0;
}
void
@@ -453,11 +416,3 @@ nv84_instmem_flush(struct drm_device *dev)
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
-void
-nv50_vm_flush(struct drm_device *dev, int engine)
-{
- nv_wr32(dev, 0x100c80, (engine << 16) | 1);
- if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
- NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
-}
-
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
new file mode 100644
index 000000000000..38e523e10995
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_vm.h"
+
+void
+nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
+ struct nouveau_gpuobj *pgt[2])
+{
+ struct drm_nouveau_private *dev_priv = pgd->dev->dev_private;
+ u64 phys = 0xdeadcafe00000000ULL;
+ u32 coverage = 0;
+
+ if (pgt[0]) {
+ phys = 0x00000003 | pgt[0]->vinst; /* present, 4KiB pages */
+ coverage = (pgt[0]->size >> 3) << 12;
+ } else
+ if (pgt[1]) {
+ phys = 0x00000001 | pgt[1]->vinst; /* present */
+ coverage = (pgt[1]->size >> 3) << 16;
+ }
+
+ if (phys & 1) {
+ if (dev_priv->vram_sys_base) {
+ phys += dev_priv->vram_sys_base;
+ phys |= 0x30;
+ }
+
+ if (coverage <= 32 * 1024 * 1024)
+ phys |= 0x60;
+ else if (coverage <= 64 * 1024 * 1024)
+ phys |= 0x40;
+ else if (coverage < 128 * 1024 * 1024)
+ phys |= 0x20;
+ }
+
+ nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys));
+ nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys));
+}
+
+static inline u64
+nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ u64 phys, u32 memtype, u32 target)
+{
+ struct drm_nouveau_private *dev_priv = pgt->dev->dev_private;
+
+ phys |= 1; /* present */
+ phys |= (u64)memtype << 40;
+
+ /* IGPs don't have real VRAM, re-target to stolen system memory */
+ if (target == 0 && dev_priv->vram_sys_base) {
+ phys += dev_priv->vram_sys_base;
+ target = 3;
+ }
+
+ phys |= target << 4;
+
+ if (vma->access & NV_MEM_ACCESS_SYS)
+ phys |= (1 << 6);
+
+ if (!(vma->access & NV_MEM_ACCESS_WO))
+ phys |= (1 << 3);
+
+ return phys;
+}
+
+void
+nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys)
+{
+ u32 block;
+ int i;
+
+ phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0);
+ pte <<= 3;
+ cnt <<= 3;
+
+ while (cnt) {
+ u32 offset_h = upper_32_bits(phys);
+ u32 offset_l = lower_32_bits(phys);
+
+ for (i = 7; i >= 0; i--) {
+ block = 1 << (i + 3);
+ if (cnt >= block && !(pte & (block - 1)))
+ break;
+ }
+ offset_l |= (i << 7);
+
+ phys += block << (vma->node->type - 3);
+ cnt -= block;
+
+ while (block) {
+ nv_wo32(pgt, pte + 0, offset_l);
+ nv_wo32(pgt, pte + 4, offset_h);
+ pte += 8;
+ block -= 8;
+ }
+ }
+}
+
+void
+nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ u32 pte, dma_addr_t *list, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ u64 phys = nv50_vm_addr(vma, pgt, (u64)*list++, 0, 2);
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ pte += 8;
+ }
+}
+
+void
+nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, 0x00000000);
+ nv_wo32(pgt, pte + 4, 0x00000000);
+ pte += 8;
+ }
+}
+
+void
+nv50_vm_flush(struct nouveau_vm *vm)
+{
+ struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+
+ pinstmem->flush(vm->dev);
+
+ /* BAR */
+ if (vm != dev_priv->chan_vm) {
+ nv50_vm_flush_engine(vm->dev, 6);
+ return;
+ }
+
+ pfifo->tlb_flush(vm->dev);
+
+ if (atomic_read(&vm->pgraph_refs))
+ pgraph->tlb_flush(vm->dev);
+ if (atomic_read(&vm->pcrypt_refs))
+ pcrypt->tlb_flush(vm->dev);
+}
+
+void
+nv50_vm_flush_engine(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x100c80, (engine << 16) | 1);
+ if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c
new file mode 100644
index 000000000000..58e98ad36347
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_vram.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+
+static int types[0x80] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
+};
+
+bool
+nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags)
+{
+ int type = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8;
+
+ if (likely(type < ARRAY_SIZE(types) && types[type]))
+ return true;
+ return false;
+}
+
+void
+nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
+ struct nouveau_mm *mm = man->priv;
+ struct nouveau_mm_node *this;
+ struct nouveau_vram *vram;
+
+ vram = *pvram;
+ *pvram = NULL;
+ if (unlikely(vram == NULL))
+ return;
+
+ mutex_lock(&mm->mutex);
+ while (!list_empty(&vram->regions)) {
+ this = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry);
+
+ list_del(&this->rl_entry);
+ nouveau_mm_put(mm, this);
+ }
+ mutex_unlock(&mm->mutex);
+
+ kfree(vram);
+}
+
+int
+nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc,
+ u32 type, struct nouveau_vram **pvram)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
+ struct nouveau_mm *mm = man->priv;
+ struct nouveau_mm_node *r;
+ struct nouveau_vram *vram;
+ int ret;
+
+ if (!types[type])
+ return -EINVAL;
+ size >>= 12;
+ align >>= 12;
+ size_nc >>= 12;
+
+ vram = kzalloc(sizeof(*vram), GFP_KERNEL);
+ if (!vram)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&vram->regions);
+ vram->dev = dev_priv->dev;
+ vram->memtype = type;
+ vram->size = size;
+
+ mutex_lock(&mm->mutex);
+ do {
+ ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r);
+ if (ret) {
+ mutex_unlock(&mm->mutex);
+ nv50_vram_del(dev, &vram);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &vram->regions);
+ size -= r->length;
+ } while (size);
+ mutex_unlock(&mm->mutex);
+
+ r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry);
+ vram->offset = (u64)r->offset << 12;
+ *pvram = vram;
+ return 0;
+}
+
+static u32
+nv50_vram_rblock(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int i, parts, colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, ru, rblock_size;
+
+ r0 = nv_rd32(dev, 0x100200);
+ r4 = nv_rd32(dev, 0x100204);
+ rt = nv_rd32(dev, 0x100250);
+ ru = nv_rd32(dev, 0x001540);
+ NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+ for (i = 0, parts = 0; i < 8; i++) {
+ if (ru & (0x00010000 << i))
+ parts++;
+ }
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = ((r4 & 0x01000000) ? 8 : 4);
+
+ rowsize = parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != dev_priv->vram_size) {
+ NV_WARN(dev, "memory controller reports %dMiB VRAM\n",
+ (u32)(dev_priv->vram_size >> 20));
+ NV_WARN(dev, "we calculated %dMiB VRAM\n",
+ (u32)(predicted >> 20));
+ }
+
+ rblock_size = rowsize;
+ if (rt & 1)
+ rblock_size *= 3;
+
+ NV_DEBUG(dev, "rblock %d bytes\n", rblock_size);
+ return rblock_size;
+}
+
+int
+nv50_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ dev_priv->vram_size = nv_rd32(dev, 0x10020c);
+ dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
+ dev_priv->vram_size &= 0xffffffff00ULL;
+
+ switch (dev_priv->chipset) {
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ dev_priv->vram_sys_base = (u64)nv_rd32(dev, 0x100e10) << 12;
+ dev_priv->vram_rblock_size = 4096;
+ break;
+ default:
+ dev_priv->vram_rblock_size = nv50_vram_rblock(dev);
+ break;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
new file mode 100644
index 000000000000..ec18ae1c3886
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+
+static void nv84_crypt_isr(struct drm_device *);
+
+int
+nv84_crypt_create_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0,
+ NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
+ &chan->crypt_ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, 0xa0, 0x00190000);
+ nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
+ nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+ nv_wo32(ramin, 0xac, 0);
+ nv_wo32(ramin, 0xb0, 0);
+ nv_wo32(ramin, 0xb4, 0);
+
+ dev_priv->engine.instmem.flush(dev);
+ atomic_inc(&chan->vm->pcrypt_refs);
+ return 0;
+}
+
+void
+nv84_crypt_destroy_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+ u32 inst;
+
+ if (!chan->crypt_ctx)
+ return;
+
+ inst = (chan->ramin->vinst >> 12);
+ inst |= 0x80000000;
+
+ /* mark context as invalid if still on the hardware, not
+ * doing this causes issues the next time PCRYPT is used,
+ * unsurprisingly :)
+ */
+ nv_wr32(dev, 0x10200c, 0x00000000);
+ if (nv_rd32(dev, 0x102188) == inst)
+ nv_mask(dev, 0x102188, 0x80000000, 0x00000000);
+ if (nv_rd32(dev, 0x10218c) == inst)
+ nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
+ nv_wr32(dev, 0x10200c, 0x00000010);
+
+ nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
+ atomic_dec(&chan->vm->pcrypt_refs);
+}
+
+void
+nv84_crypt_tlb_flush(struct drm_device *dev)
+{
+ nv50_vm_flush_engine(dev, 0x0a);
+}
+
+int
+nv84_crypt_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+
+ if (!pcrypt->registered) {
+ NVOBJ_CLASS(dev, 0x74c1, CRYPT);
+ pcrypt->registered = true;
+ }
+
+ nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+ nouveau_irq_register(dev, 14, nv84_crypt_isr);
+ nv_wr32(dev, 0x102130, 0xffffffff);
+ nv_wr32(dev, 0x102140, 0xffffffbf);
+
+ nv_wr32(dev, 0x10200c, 0x00000010);
+ return 0;
+}
+
+void
+nv84_crypt_fini(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x102140, 0x00000000);
+ nouveau_irq_unregister(dev, 14);
+}
+
+static void
+nv84_crypt_isr(struct drm_device *dev)
+{
+ u32 stat = nv_rd32(dev, 0x102130);
+ u32 mthd = nv_rd32(dev, 0x102190);
+ u32 data = nv_rd32(dev, 0x102194);
+ u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff;
+ int show = nouveau_ratelimit();
+
+ if (show) {
+ NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ stat, mthd, data, inst);
+ }
+
+ nv_wr32(dev, 0x102130, stat);
+ nv_wr32(dev, 0x10200c, 0x10);
+
+ nv50_fb_vm_trap(dev, show, "PCRYPT");
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
new file mode 100644
index 000000000000..fa5d4c234383
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fbcon.h"
+#include "nouveau_mm.h"
+
+int
+nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
+
+ ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
+ if (ret)
+ return ret;
+
+ if (rect->rop != ROP_COPY) {
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ OUT_RING (chan, 1);
+ }
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0588, 1);
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR)
+ OUT_RING (chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
+ else
+ OUT_RING (chan, rect->color);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0600, 4);
+ OUT_RING (chan, rect->dx);
+ OUT_RING (chan, rect->dy);
+ OUT_RING (chan, rect->dx + rect->width);
+ OUT_RING (chan, rect->dy + rect->height);
+ if (rect->rop != ROP_COPY) {
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ OUT_RING (chan, 3);
+ }
+ FIRE_RING(chan);
+ return 0;
+}
+
+int
+nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = dev_priv->channel;
+ int ret;
+
+ ret = RING_SPACE(chan, 12);
+ if (ret)
+ return ret;
+
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0110, 1);
+ OUT_RING (chan, 0);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08b0, 4);
+ OUT_RING (chan, region->dx);
+ OUT_RING (chan, region->dy);
+ OUT_RING (chan, region->width);
+ OUT_RING (chan, region->height);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08d0, 4);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, region->sx);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, region->sy);
+ FIRE_RING(chan);
+ return 0;
+}
+
+int
+nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = dev_priv->channel;
+ uint32_t width, dwords, *data = (uint32_t *)image->data;
+ uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
+ uint32_t *palette = info->pseudo_palette;
+ int ret;
+
+ if (image->depth != 1)
+ return -ENODEV;
+
+ ret = RING_SPACE(chan, 11);
+ if (ret)
+ return ret;
+
+ width = ALIGN(image->width, 32);
+ dwords = (width * image->height) >> 5;
+
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0814, 2);
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ OUT_RING (chan, palette[image->bg_color] | mask);
+ OUT_RING (chan, palette[image->fg_color] | mask);
+ } else {
+ OUT_RING (chan, image->bg_color);
+ OUT_RING (chan, image->fg_color);
+ }
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0838, 2);
+ OUT_RING (chan, image->width);
+ OUT_RING (chan, image->height);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0850, 4);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, image->dx);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, image->dy);
+
+ while (dwords) {
+ int push = dwords > 2047 ? 2047 : dwords;
+
+ ret = RING_SPACE(chan, push + 1);
+ if (ret)
+ return ret;
+
+ dwords -= push;
+
+ BEGIN_NVC0(chan, 6, NvSub2D, 0x0860, push);
+ OUT_RINGp(chan, data, push);
+ data += push;
+ }
+
+ FIRE_RING(chan);
+ return 0;
+}
+
+int
+nvc0_fbcon_accel_init(struct fb_info *info)
+{
+ struct nouveau_fbdev *nfbdev = info->par;
+ struct drm_device *dev = nfbdev->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = dev_priv->channel;
+ struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo;
+ int ret, format;
+
+ ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d);
+ if (ret)
+ return ret;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ format = 0xf3;
+ break;
+ case 15:
+ format = 0xf8;
+ break;
+ case 16:
+ format = 0xe8;
+ break;
+ case 32:
+ switch (info->var.transp.length) {
+ case 0: /* depth 24 */
+ case 8: /* depth 32, just use 24.. */
+ format = 0xe6;
+ break;
+ case 2: /* depth 30 */
+ format = 0xd1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = RING_SPACE(chan, 60);
+ if (ret) {
+ WARN_ON(1);
+ nouveau_fbcon_gpu_lockup(info);
+ return ret;
+ }
+
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1);
+ OUT_RING (chan, 0x0000902d);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2);
+ OUT_RING (chan, upper_32_bits(chan->notifier_bo->bo.offset));
+ OUT_RING (chan, lower_32_bits(chan->notifier_bo->bo.offset));
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1);
+ OUT_RING (chan, 0);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ OUT_RING (chan, 3);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02a0, 1);
+ OUT_RING (chan, 0x55);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08c0, 4);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0580, 2);
+ OUT_RING (chan, 4);
+ OUT_RING (chan, format);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02e8, 2);
+ OUT_RING (chan, 2);
+ OUT_RING (chan, 1);
+
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0804, 1);
+ OUT_RING (chan, format);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0800, 1);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0808, 3);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x081c, 1);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0840, 4);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0200, 10);
+ OUT_RING (chan, format);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, info->fix.line_length);
+ OUT_RING (chan, info->var.xres_virtual);
+ OUT_RING (chan, info->var.yres_virtual);
+ OUT_RING (chan, upper_32_bits(nvbo->vma.offset));
+ OUT_RING (chan, lower_32_bits(nvbo->vma.offset));
+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10);
+ OUT_RING (chan, format);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, info->fix.line_length);
+ OUT_RING (chan, info->var.xres_virtual);
+ OUT_RING (chan, info->var.yres_virtual);
+ OUT_RING (chan, upper_32_bits(nvbo->vma.offset));
+ OUT_RING (chan, lower_32_bits(nvbo->vma.offset));
+ FIRE_RING (chan);
+
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 890c2b95fbc1..e6f92c541dba 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -25,6 +25,49 @@
#include "drmP.h"
#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+
+static void nvc0_fifo_isr(struct drm_device *);
+
+struct nvc0_fifo_priv {
+ struct nouveau_gpuobj *playlist[2];
+ int cur_playlist;
+ struct nouveau_vma user_vma;
+ int spoon_nr;
+};
+
+struct nvc0_fifo_chan {
+ struct nouveau_bo *user;
+ struct nouveau_gpuobj *ramfc;
+};
+
+static void
+nvc0_fifo_playlist_update(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv = pfifo->priv;
+ struct nouveau_gpuobj *cur;
+ int i, p;
+
+ cur = priv->playlist[priv->cur_playlist];
+ priv->cur_playlist = !priv->cur_playlist;
+
+ for (i = 0, p = 0; i < 128; i++) {
+ if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1))
+ continue;
+ nv_wo32(cur, p + 0, i);
+ nv_wo32(cur, p + 4, 0x00000004);
+ p += 8;
+ }
+ pinstmem->flush(dev);
+
+ nv_wr32(dev, 0x002270, cur->vinst >> 12);
+ nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3));
+ if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000))
+ NV_ERROR(dev, "PFIFO - playlist update failed\n");
+}
void
nvc0_fifo_disable(struct drm_device *dev)
@@ -57,12 +100,135 @@ nvc0_fifo_channel_id(struct drm_device *dev)
int
nvc0_fifo_create_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv = pfifo->priv;
+ struct nvc0_fifo_chan *fifoch;
+ u64 ib_virt, user_vinst;
+ int ret;
+
+ chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
+ if (!chan->fifo_priv)
+ return -ENOMEM;
+ fifoch = chan->fifo_priv;
+
+ /* allocate vram for control regs, map into polling area */
+ ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
+ 0, 0, true, true, &fifoch->user);
+ if (ret)
+ goto error;
+
+ ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
+ if (ret) {
+ nouveau_bo_ref(NULL, &fifoch->user);
+ goto error;
+ }
+
+ user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
+
+ ret = nouveau_bo_map(fifoch->user);
+ if (ret) {
+ nouveau_bo_unpin(fifoch->user);
+ nouveau_bo_ref(NULL, &fifoch->user);
+ goto error;
+ }
+
+ nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
+ fifoch->user->bo.mem.mm_node);
+
+ chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
+ priv->user_vma.offset + (chan->id * 0x1000),
+ PAGE_SIZE);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
+
+ /* zero channel regs */
+ nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
+ nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
+
+ /* ramfc */
+ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
+ chan->ramin->vinst, 0x100,
+ NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc);
+ if (ret)
+ goto error;
+
+ nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
+ nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+ nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
+ nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
+ nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
+ nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
+ upper_32_bits(ib_virt));
+ nv_wo32(fifoch->ramfc, 0x54, 0x00000002);
+ nv_wo32(fifoch->ramfc, 0x84, 0x20400000);
+ nv_wo32(fifoch->ramfc, 0x94, 0x30000001);
+ nv_wo32(fifoch->ramfc, 0x9c, 0x00000100);
+ nv_wo32(fifoch->ramfc, 0xa4, 0x1f1f1f1f);
+ nv_wo32(fifoch->ramfc, 0xa8, 0x1f1f1f1f);
+ nv_wo32(fifoch->ramfc, 0xac, 0x0000001f);
+ nv_wo32(fifoch->ramfc, 0xb8, 0xf8000000);
+ nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */
+ pinstmem->flush(dev);
+
+ nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 |
+ (chan->ramin->vinst >> 12));
+ nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001);
+ nvc0_fifo_playlist_update(dev);
return 0;
+
+error:
+ pfifo->destroy_context(chan);
+ return ret;
}
void
nvc0_fifo_destroy_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct nvc0_fifo_chan *fifoch;
+
+ nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x002634, chan->id);
+ if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
+ NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
+
+ nvc0_fifo_playlist_update(dev);
+
+ nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000);
+
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
+ }
+
+ fifoch = chan->fifo_priv;
+ chan->fifo_priv = NULL;
+ if (!fifoch)
+ return;
+
+ nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
+ if (fifoch->user) {
+ nouveau_bo_unmap(fifoch->user);
+ nouveau_bo_unpin(fifoch->user);
+ nouveau_bo_ref(NULL, &fifoch->user);
+ }
+ kfree(fifoch);
}
int
@@ -77,14 +243,213 @@ nvc0_fifo_unload_context(struct drm_device *dev)
return 0;
}
+static void
+nvc0_fifo_destroy(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv;
+
+ priv = pfifo->priv;
+ if (!priv)
+ return;
+
+ nouveau_vm_put(&priv->user_vma);
+ nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
+ nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+ kfree(priv);
+}
+
void
nvc0_fifo_takedown(struct drm_device *dev)
{
+ nv_wr32(dev, 0x002140, 0x00000000);
+ nvc0_fifo_destroy(dev);
+}
+
+static int
+nvc0_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ pfifo->priv = priv;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0,
+ &priv->playlist[0]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0,
+ &priv->playlist[1]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_get(dev_priv->bar1_vm, pfifo->channels * 0x1000,
+ 12, NV_MEM_ACCESS_RW, &priv->user_vma);
+ if (ret)
+ goto error;
+
+ nouveau_irq_register(dev, 8, nvc0_fifo_isr);
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ return 0;
+
+error:
+ nvc0_fifo_destroy(dev);
+ return ret;
}
int
nvc0_fifo_init(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv;
+ int ret, i;
+
+ if (!pfifo->priv) {
+ ret = nvc0_fifo_create(dev);
+ if (ret)
+ return ret;
+ }
+ priv = pfifo->priv;
+
+ /* reset PFIFO, enable all available PSUBFIFO areas */
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(dev, 0x000204, 0xffffffff);
+ nv_wr32(dev, 0x002204, 0xffffffff);
+
+ priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204));
+ NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
+
+ /* assign engines to subfifos */
+ if (priv->spoon_nr >= 3) {
+ nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */
+ nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */
+ nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */
+ nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */
+ nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */
+ nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */
+ }
+
+ /* PSUBFIFO[n] */
+ for (i = 0; i < 3; i++) {
+ nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+ nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+ nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
+ }
+
+ nv_mask(dev, 0x002200, 0x00000001, 0x00000001);
+ nv_wr32(dev, 0x002254, 0x10000000 | priv->user_vma.offset >> 12);
+
+ nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
+ nv_wr32(dev, 0x002100, 0xffffffff);
+ nv_wr32(dev, 0x002140, 0xbfffffff);
return 0;
}
+struct nouveau_enum nvc0_fifo_fault_unit[] = {
+ { 0, "PGRAPH" },
+ { 3, "PEEPHOLE" },
+ { 4, "BAR1" },
+ { 5, "BAR3" },
+ { 7, "PFIFO" },
+ {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_reason[] = {
+ { 0, "PT_NOT_PRESENT" },
+ { 1, "PT_TOO_SHORT" },
+ { 2, "PAGE_NOT_PRESENT" },
+ { 3, "VM_LIMIT_EXCEEDED" },
+ {}
+};
+
+struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = {
+/* { 0x00008000, "" } seen with null ib push */
+ { 0x00200000, "ILLEGAL_MTHD" },
+ { 0x00800000, "EMPTY_SUBC" },
+ {}
+};
+
+static void
+nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
+{
+ u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
+ u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
+ u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
+ u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+
+ NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
+ (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
+ nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
+ printk("] from ");
+ nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+ printk(" on channel 0x%010llx\n", (u64)inst << 12);
+}
+
+static void
+nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
+{
+ u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
+ u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
+ u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
+ u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
+ u32 subc = (addr & 0x00070000);
+ u32 mthd = (addr & 0x00003ffc);
+
+ NV_INFO(dev, "PSUBFIFO %d:", unit);
+ nouveau_bitfield_print(nvc0_fifo_subfifo_intr, stat);
+ NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
+ unit, chid, subc, mthd, data);
+
+ nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
+ nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
+}
+
+static void
+nvc0_fifo_isr(struct drm_device *dev)
+{
+ u32 stat = nv_rd32(dev, 0x002100);
+
+ if (stat & 0x10000000) {
+ u32 units = nv_rd32(dev, 0x00259c);
+ u32 u = units;
+
+ while (u) {
+ int i = ffs(u) - 1;
+ nvc0_fifo_isr_vm_fault(dev, i);
+ u &= ~(1 << i);
+ }
+
+ nv_wr32(dev, 0x00259c, units);
+ stat &= ~0x10000000;
+ }
+
+ if (stat & 0x20000000) {
+ u32 units = nv_rd32(dev, 0x0025a0);
+ u32 u = units;
+
+ while (u) {
+ int i = ffs(u) - 1;
+ nvc0_fifo_isr_subfifo_intr(dev, i);
+ u &= ~(1 << i);
+ }
+
+ nv_wr32(dev, 0x0025a0, units);
+ stat &= ~0x20000000;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
+ nv_wr32(dev, 0x002100, stat);
+ }
+
+ nv_wr32(dev, 0x2140, 0);
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 717a5177a8d8..e6ea7d83187f 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -22,9 +22,16 @@
* Authors: Ben Skeggs
*/
+#include <linux/firmware.h>
+
#include "drmP.h"
#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nvc0_graph.h"
+
+static void nvc0_graph_isr(struct drm_device *);
+static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
void
nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
@@ -37,39 +44,736 @@ nvc0_graph_channel(struct drm_device *dev)
return NULL;
}
+static int
+nvc0_graph_construct_context(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct drm_device *dev = chan->dev;
+ int ret, i;
+ u32 *ctx;
+
+ ctx = kmalloc(priv->grctx_size, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ nvc0_graph_load_context(chan);
+
+ nv_wo32(grch->grctx, 0x1c, 1);
+ nv_wo32(grch->grctx, 0x20, 0);
+ nv_wo32(grch->grctx, 0x28, 0);
+ nv_wo32(grch->grctx, 0x2c, 0);
+ dev_priv->engine.instmem.flush(dev);
+
+ ret = nvc0_grctx_generate(chan);
+ if (ret) {
+ kfree(ctx);
+ return ret;
+ }
+
+ ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst);
+ if (ret) {
+ kfree(ctx);
+ return ret;
+ }
+
+ for (i = 0; i < priv->grctx_size; i += 4)
+ ctx[i / 4] = nv_ro32(grch->grctx, i);
+
+ priv->grctx_vals = ctx;
+ return 0;
+}
+
+static int
+nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct drm_device *dev = chan->dev;
+ int i = 0, gpc, tp, ret;
+ u32 magic;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x2000, 256, NVOBJ_FLAG_VM,
+ &grch->unk408004);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 256, NVOBJ_FLAG_VM,
+ &grch->unk40800c);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER,
+ &grch->unk418810);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0, NVOBJ_FLAG_VM,
+ &grch->mmio);
+ if (ret)
+ return ret;
+
+
+ nv_wo32(grch->mmio, i++ * 4, 0x00408004);
+ nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8);
+ nv_wo32(grch->mmio, i++ * 4, 0x00408008);
+ nv_wo32(grch->mmio, i++ * 4, 0x80000018);
+
+ nv_wo32(grch->mmio, i++ * 4, 0x0040800c);
+ nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8);
+ nv_wo32(grch->mmio, i++ * 4, 0x00408010);
+ nv_wo32(grch->mmio, i++ * 4, 0x80000000);
+
+ nv_wo32(grch->mmio, i++ * 4, 0x00418810);
+ nv_wo32(grch->mmio, i++ * 4, 0x80000000 | grch->unk418810->vinst >> 12);
+ nv_wo32(grch->mmio, i++ * 4, 0x00419848);
+ nv_wo32(grch->mmio, i++ * 4, 0x10000000 | grch->unk418810->vinst >> 12);
+
+ nv_wo32(grch->mmio, i++ * 4, 0x00419004);
+ nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8);
+ nv_wo32(grch->mmio, i++ * 4, 0x00419008);
+ nv_wo32(grch->mmio, i++ * 4, 0x00000000);
+
+ nv_wo32(grch->mmio, i++ * 4, 0x00418808);
+ nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8);
+ nv_wo32(grch->mmio, i++ * 4, 0x0041880c);
+ nv_wo32(grch->mmio, i++ * 4, 0x80000018);
+
+ magic = 0x02180000;
+ nv_wo32(grch->mmio, i++ * 4, 0x00405830);
+ nv_wo32(grch->mmio, i++ * 4, magic);
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x02fc) {
+ u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800);
+ nv_wo32(grch->mmio, i++ * 4, reg);
+ nv_wo32(grch->mmio, i++ * 4, magic);
+ }
+ }
+
+ grch->mmio_nr = i / 2;
+ return 0;
+}
+
int
nvc0_graph_create_context(struct nouveau_channel *chan)
{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nvc0_graph_priv *priv = pgraph->priv;
+ struct nvc0_graph_chan *grch;
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *grctx;
+ int ret, i;
+
+ chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
+ if (!chan->pgraph_ctx)
+ return -ENOMEM;
+ grch = chan->pgraph_ctx;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
+ &grch->grctx);
+ if (ret)
+ goto error;
+ chan->ramin_grctx = grch->grctx;
+ grctx = grch->grctx;
+
+ ret = nvc0_graph_create_context_mmio_list(chan);
+ if (ret)
+ goto error;
+
+ nv_wo32(chan->ramin, 0x0210, lower_32_bits(grctx->vinst) | 4);
+ nv_wo32(chan->ramin, 0x0214, upper_32_bits(grctx->vinst));
+ pinstmem->flush(dev);
+
+ if (!priv->grctx_vals) {
+ ret = nvc0_graph_construct_context(chan);
+ if (ret)
+ goto error;
+ }
+
+ for (i = 0; i < priv->grctx_size; i += 4)
+ nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
+
+ nv_wo32(grctx, 0xf4, 0);
+ nv_wo32(grctx, 0xf8, 0);
+ nv_wo32(grctx, 0x10, grch->mmio_nr);
+ nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x1c, 1);
+ nv_wo32(grctx, 0x20, 0);
+ nv_wo32(grctx, 0x28, 0);
+ nv_wo32(grctx, 0x2c, 0);
+ pinstmem->flush(dev);
return 0;
+
+error:
+ pgraph->destroy_context(chan);
+ return ret;
}
void
nvc0_graph_destroy_context(struct nouveau_channel *chan)
{
+ struct nvc0_graph_chan *grch;
+
+ grch = chan->pgraph_ctx;
+ chan->pgraph_ctx = NULL;
+ if (!grch)
+ return;
+
+ nouveau_gpuobj_ref(NULL, &grch->mmio);
+ nouveau_gpuobj_ref(NULL, &grch->unk418810);
+ nouveau_gpuobj_ref(NULL, &grch->unk40800c);
+ nouveau_gpuobj_ref(NULL, &grch->unk408004);
+ nouveau_gpuobj_ref(NULL, &grch->grctx);
+ chan->ramin_grctx = NULL;
}
int
nvc0_graph_load_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+
+ nv_wr32(dev, 0x409840, 0x00000030);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+ nv_wr32(dev, 0x409504, 0x00000003);
+ if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+ NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+ return 0;
+}
+
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+{
+ nv_wr32(dev, 0x409840, 0x00000003);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+ nv_wr32(dev, 0x409504, 0x00000009);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+ return -EBUSY;
+ }
+
return 0;
}
int
nvc0_graph_unload_context(struct drm_device *dev)
{
- return 0;
+ u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
+ return nvc0_graph_unload_context_to(dev, inst);
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nvc0_graph_priv *priv;
+
+ priv = pgraph->priv;
+ if (!priv)
+ return;
+
+ nouveau_irq_unregister(dev, 12);
+
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ if (priv->grctx_vals)
+ kfree(priv->grctx_vals);
+ kfree(priv);
}
void
nvc0_graph_takedown(struct drm_device *dev)
{
+ nvc0_graph_destroy(dev);
+}
+
+static int
+nvc0_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nvc0_graph_priv *priv;
+ int ret, gpc, i;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ pgraph->priv = priv;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
+ priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+ priv->tp_total += priv->tp_nr[gpc];
+ }
+
+ /*XXX: these need figuring out... */
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+ priv->magic_not_rop_nr = 0x07;
+ /* filled values up to tp_total, the rest 0 */
+ priv->magicgpc980[0] = 0x22111000;
+ priv->magicgpc980[1] = 0x00000233;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x000ba2e9;
+ } else
+ if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+ priv->magic_not_rop_nr = 0x05;
+ priv->magicgpc980[0] = 0x11110000;
+ priv->magicgpc980[1] = 0x00233222;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x00092493;
+ } else
+ if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+ priv->magic_not_rop_nr = 0x06;
+ priv->magicgpc980[0] = 0x11110000;
+ priv->magicgpc980[1] = 0x03332222;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x00088889;
+ }
+ break;
+ case 0xc3: /* 450, 4/0/0/0, 2 */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc980[0] = 0x00003210;
+ priv->magicgpc980[1] = 0x00000000;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x00200000;
+ break;
+ case 0xc4: /* 460, 3/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x01;
+ priv->magicgpc980[0] = 0x02321100;
+ priv->magicgpc980[1] = 0x00000000;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x00124925;
+ break;
+ }
+
+ if (!priv->magic_not_rop_nr) {
+ NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+ priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+ priv->tp_nr[3], priv->rop_nr);
+ /* use 0xc3's values... */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc980[0] = 0x00003210;
+ priv->magicgpc980[1] = 0x00000000;
+ priv->magicgpc980[2] = 0x00000000;
+ priv->magicgpc980[3] = 0x00000000;
+ priv->magicgpc918 = 0x00200000;
+ }
+
+ nouveau_irq_register(dev, 12, nvc0_graph_isr);
+ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+ NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+ return 0;
+
+error:
+ nvc0_graph_destroy(dev);
+ return ret;
+}
+
+static void
+nvc0_graph_init_obj418880(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nvc0_graph_priv *priv = pgraph->priv;
+ int i;
+
+ nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
+ nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->vinst >> 8);
+ nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->vinst >> 8);
+}
+
+static void
+nvc0_graph_init_regs(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x400080, 0x003083c2);
+ nv_wr32(dev, 0x400088, 0x00006fe7);
+ nv_wr32(dev, 0x40008c, 0x00000000);
+ nv_wr32(dev, 0x400090, 0x00000030);
+ nv_wr32(dev, 0x40013c, 0x013901f7);
+ nv_wr32(dev, 0x400140, 0x00000100);
+ nv_wr32(dev, 0x400144, 0x00000000);
+ nv_wr32(dev, 0x400148, 0x00000110);
+ nv_wr32(dev, 0x400138, 0x00000000);
+ nv_wr32(dev, 0x400130, 0x00000000);
+ nv_wr32(dev, 0x400134, 0x00000000);
+ nv_wr32(dev, 0x400124, 0x00000002);
+}
+
+static void
+nvc0_graph_init_gpc_0(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ int gpc;
+
+ // TP ROP UNKVAL(magic_not_rop_nr)
+ // 450: 4/0/0/0 2 3
+ // 460: 3/4/0/0 4 1
+ // 465: 3/4/4/0 4 7
+ // 470: 3/3/4/4 5 5
+ // 480: 3/4/4/4 6 6
+
+ // magicgpc918
+ // 450: 00200000 00000000001000000000000000000000
+ // 460: 00124925 00000000000100100100100100100101
+ // 465: 000ba2e9 00000000000010111010001011101001
+ // 470: 00092493 00000000000010010010010010010011
+ // 480: 00088889 00000000000010001000100010001001
+
+ /* filled values up to tp_total, remainder 0 */
+ // 450: 00003210 00000000 00000000 00000000
+ // 460: 02321100 00000000 00000000 00000000
+ // 465: 22111000 00000233 00000000 00000000
+ // 470: 11110000 00233222 00000000 00000000
+ // 480: 11110000 03332222 00000000 00000000
+
+ nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
+ nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
+ nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
+ nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
+ priv->tp_nr[gpc]);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tp_total);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0918), priv->magicgpc918);
+ }
+
+ nv_wr32(dev, GPC_BCAST(0x1bd4), priv->magicgpc918);
+ nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr);
+}
+
+static void
+nvc0_graph_init_units(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x409c24, 0x000f0000);
+ nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */
+ nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */
+ nv_wr32(dev, 0x408030, 0xc0000000);
+ nv_wr32(dev, 0x40601c, 0xc0000000);
+ nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */
+ nv_wr32(dev, 0x406018, 0xc0000000);
+ nv_wr32(dev, 0x405840, 0xc0000000);
+ nv_wr32(dev, 0x405844, 0x00ffffff);
+ nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
+}
+
+static void
+nvc0_graph_init_gpc_1(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ int gpc, tp;
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tp = 0; tp < priv->tp_nr[gpc]; tp++) {
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x508), 0xffffffff);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x50c), 0xffffffff);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f);
+ }
+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+}
+
+static void
+nvc0_graph_init_rop(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ int rop;
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+}
+
+static int
+nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
+ const char *code_fw, const char *data_fw)
+{
+ const struct firmware *fw;
+ char name[32];
+ int ret, i;
+
+ snprintf(name, sizeof(name), "nouveau/%s", data_fw);
+ ret = request_firmware(&fw, name, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "failed to load %s\n", data_fw);
+ return ret;
+ }
+
+ nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
+ for (i = 0; i < fw->size / 4; i++)
+ nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
+ release_firmware(fw);
+
+ snprintf(name, sizeof(name), "nouveau/%s", code_fw);
+ ret = request_firmware(&fw, name, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "failed to load %s\n", code_fw);
+ return ret;
+ }
+
+ nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
+ for (i = 0; i < fw->size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, fuc_base + 0x0188, i >> 6);
+ nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+ }
+ release_firmware(fw);
+
+ return 0;
+}
+
+static int
+nvc0_graph_init_ctxctl(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ u32 r000260;
+ int ret;
+
+ /* load fuc microcode */
+ r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
+ ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
+ if (ret == 0)
+ ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+ nv_wr32(dev, 0x000260, r000260);
+
+ if (ret)
+ return ret;
+
+ /* start both of them running */
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x41a10c, 0x00000000);
+ nv_wr32(dev, 0x40910c, 0x00000000);
+ nv_wr32(dev, 0x41a100, 0x00000002);
+ nv_wr32(dev, 0x409100, 0x00000002);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
+ NV_INFO(dev, "0x409800 wait failed\n");
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x7fffffff);
+ nv_wr32(dev, 0x409504, 0x00000021);
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000010);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
+ return -EBUSY;
+ }
+ priv->grctx_size = nv_rd32(dev, 0x409800);
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000016);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000025);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
+ return -EBUSY;
+ }
+
+ return 0;
}
int
nvc0_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nvc0_graph_priv *priv;
+ int ret;
+
dev_priv->engine.graph.accel_blocked = true;
+
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ case 0xc3:
+ case 0xc4:
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+ if (nouveau_noaccel != 0)
+ return 0;
+ break;
+ }
+
+ nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
+
+ if (!pgraph->priv) {
+ ret = nvc0_graph_create(dev);
+ if (ret)
+ return ret;
+ }
+ priv = pgraph->priv;
+
+ nvc0_graph_init_obj418880(dev);
+ nvc0_graph_init_regs(dev);
+ //nvc0_graph_init_unitplemented_magics(dev);
+ nvc0_graph_init_gpc_0(dev);
+ //nvc0_graph_init_unitplemented_c242(dev);
+
+ nv_wr32(dev, 0x400500, 0x00010001);
+ nv_wr32(dev, 0x400100, 0xffffffff);
+ nv_wr32(dev, 0x40013c, 0xffffffff);
+
+ nvc0_graph_init_units(dev);
+ nvc0_graph_init_gpc_1(dev);
+ nvc0_graph_init_rop(dev);
+
+ nv_wr32(dev, 0x400108, 0xffffffff);
+ nv_wr32(dev, 0x400138, 0xffffffff);
+ nv_wr32(dev, 0x400118, 0xffffffff);
+ nv_wr32(dev, 0x400130, 0xffffffff);
+ nv_wr32(dev, 0x40011c, 0xffffffff);
+ nv_wr32(dev, 0x400134, 0xffffffff);
+ nv_wr32(dev, 0x400054, 0x34ce3464);
+
+ ret = nvc0_graph_init_ctxctl(dev);
+ if (ret == 0)
+ dev_priv->engine.graph.accel_blocked = false;
return 0;
}
+static int
+nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->ramin)
+ continue;
+
+ if (inst == chan->ramin->vinst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nvc0_graph_isr(struct drm_device *dev)
+{
+ u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
+ u32 chid = nvc0_graph_isr_chid(dev, inst);
+ u32 stat = nv_rd32(dev, 0x400100);
+ u32 addr = nv_rd32(dev, 0x400704);
+ u32 mthd = (addr & 0x00003ffc);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 data = nv_rd32(dev, 0x400708);
+ u32 code = nv_rd32(dev, 0x400110);
+ u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+
+ if (stat & 0x00000010) {
+ NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] subc %d "
+ "class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ nv_wr32(dev, 0x400100, 0x00000010);
+ stat &= ~0x00000010;
+ }
+
+ if (stat & 0x00000020) {
+ NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+ "class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ nv_wr32(dev, 0x400100, 0x00000020);
+ stat &= ~0x00000020;
+ }
+
+ if (stat & 0x00100000) {
+ NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+ nouveau_enum_print(nv50_data_error_names, code);
+ printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ nv_wr32(dev, 0x400100, 0x00100000);
+ stat &= ~0x00100000;
+ }
+
+ if (stat & 0x00200000) {
+ u32 trap = nv_rd32(dev, 0x400108);
+ NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap);
+ nv_wr32(dev, 0x400108, trap);
+ nv_wr32(dev, 0x400100, 0x00200000);
+ stat &= ~0x00200000;
+ }
+
+ if (stat & 0x00080000) {
+ u32 ustat = nv_rd32(dev, 0x409c18);
+
+ NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat);
+
+ nv_wr32(dev, 0x409c20, ustat);
+ nv_wr32(dev, 0x400100, 0x00080000);
+ stat &= ~0x00080000;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
+ nv_wr32(dev, 0x400100, stat);
+ }
+
+ nv_wr32(dev, 0x400500, 0x00010001);
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h
new file mode 100644
index 000000000000..40e26f9c56c4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NVC0_GRAPH_H__
+#define __NVC0_GRAPH_H__
+
+#define GPC_MAX 4
+#define TP_MAX 32
+
+#define ROP_BCAST(r) (0x408800 + (r))
+#define ROP_UNIT(u,r) (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r) (0x418000 + (r))
+#define GPC_UNIT(t,r) (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_priv {
+ u8 gpc_nr;
+ u8 rop_nr;
+ u8 tp_nr[GPC_MAX];
+ u8 tp_total;
+
+ u32 grctx_size;
+ u32 *grctx_vals;
+ struct nouveau_gpuobj *unk4188b4;
+ struct nouveau_gpuobj *unk4188b8;
+
+ u8 magic_not_rop_nr;
+ u32 magicgpc980[4];
+ u32 magicgpc918;
+};
+
+struct nvc0_graph_chan {
+ struct nouveau_gpuobj *grctx;
+ struct nouveau_gpuobj *unk408004; // 0x418810 too
+ struct nouveau_gpuobj *unk40800c; // 0x419004 too
+ struct nouveau_gpuobj *unk418810; // 0x419848 too
+ struct nouveau_gpuobj *mmio;
+ int mmio_nr;
+};
+
+int nvc0_grctx_generate(struct nouveau_channel *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c
new file mode 100644
index 000000000000..b9e68b2d30aa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c
@@ -0,0 +1,2874 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nvc0_graph.h"
+
+static void
+nv_icmd(struct drm_device *dev, u32 icmd, u32 data)
+{
+ nv_wr32(dev, 0x400204, data);
+ nv_wr32(dev, 0x400200, icmd);
+ while (nv_rd32(dev, 0x400700) & 2) {}
+}
+
+static void
+nv_mthd(struct drm_device *dev, u32 class, u32 mthd, u32 data)
+{
+ nv_wr32(dev, 0x40448c, data);
+ nv_wr32(dev, 0x404488, 0x80000000 | (mthd << 14) | class);
+}
+
+static void
+nvc0_grctx_generate_9097(struct drm_device *dev)
+{
+ nv_mthd(dev, 0x9097, 0x0800, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0840, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0880, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0900, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0940, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0980, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0804, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0844, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0884, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0904, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0944, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0984, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0808, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x0848, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x0888, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x08c8, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x0908, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x0948, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x0988, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x09c8, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x080c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x084c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x088c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x08cc, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x090c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x094c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x098c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x09cc, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x0810, 0x000000cf);
+ nv_mthd(dev, 0x9097, 0x0850, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0890, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0910, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0950, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0990, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0814, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0854, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0894, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x08d4, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0914, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0954, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0994, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x09d4, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0818, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0858, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0898, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x08d8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0918, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0958, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0998, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x09d8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x081c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x085c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x089c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x091c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x095c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x099c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0820, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0860, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x08e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0920, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0960, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x09e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2700, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2720, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2740, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2760, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2780, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2704, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2724, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2744, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2764, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2784, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2708, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2728, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2748, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2768, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2788, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x270c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x272c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x274c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x276c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x278c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x27ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2710, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x2730, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x2750, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x2770, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x2790, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x27b0, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x27d0, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x27f0, 0x00014000);
+ nv_mthd(dev, 0x9097, 0x2714, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x2734, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x2754, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x2774, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x2794, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x27b4, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x27d4, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x27f4, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x1c00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ca0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ce0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cf0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ca4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cb4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cd4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ce4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cf4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c18, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c38, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c78, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c98, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ca8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cb8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cd8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ce8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cf8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c1c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c2c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c3c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c5c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c6c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c7c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1c9c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cbc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ccc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cdc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1cfc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1da0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1db0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1de0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1df0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1da4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1db4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dd4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1de4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1df4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d18, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d38, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d78, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d98, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1da8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1db8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dd8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1de8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1df8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d1c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d2c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d3c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d5c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d6c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d7c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1d9c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dbc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dcc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ddc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1dfc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f18, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f38, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f78, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f1c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f2c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f3c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f5c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f6c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f7c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f98, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fa0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fa8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fb8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fd8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fe0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fe8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ff0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ff8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1f9c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fa4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fb4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fbc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fcc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fd4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fdc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fe4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1fec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ff4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1ffc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2200, 0x00000022);
+ nv_mthd(dev, 0x9097, 0x2210, 0x00000022);
+ nv_mthd(dev, 0x9097, 0x2220, 0x00000022);
+ nv_mthd(dev, 0x9097, 0x2230, 0x00000022);
+ nv_mthd(dev, 0x9097, 0x2240, 0x00000022);
+ nv_mthd(dev, 0x9097, 0x2000, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2040, 0x00000011);
+ nv_mthd(dev, 0x9097, 0x2080, 0x00000020);
+ nv_mthd(dev, 0x9097, 0x20c0, 0x00000030);
+ nv_mthd(dev, 0x9097, 0x2100, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x2140, 0x00000051);
+ nv_mthd(dev, 0x9097, 0x200c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x204c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x208c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x20cc, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x210c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x214c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x2010, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2050, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2090, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x20d0, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x2110, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x2150, 0x00000004);
+ nv_mthd(dev, 0x9097, 0x0380, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0384, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0388, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x038c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x03ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0700, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0710, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0720, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0730, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0704, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0714, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0724, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0734, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0708, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0718, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0728, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0738, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2800, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2804, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2808, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x280c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2810, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2814, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2818, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x281c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2820, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2824, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2828, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x282c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2830, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2834, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2838, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x283c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2840, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2844, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2848, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x284c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2850, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2854, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2858, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x285c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2860, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2864, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2868, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x286c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2870, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2874, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2878, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x287c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2880, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2884, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2888, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x288c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2890, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2894, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2898, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x289c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28b0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28b4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28d4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x28fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2900, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2904, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2908, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x290c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2910, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2914, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2918, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x291c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2920, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2924, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2928, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x292c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2930, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2934, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2938, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x293c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2940, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2944, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2948, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x294c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2950, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2954, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2958, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x295c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2960, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2964, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2968, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x296c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2970, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2974, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2978, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x297c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2980, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2984, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2988, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x298c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2990, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2994, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2998, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x299c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29b0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29b4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29d4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x29fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0aa0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ac0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ae0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ba0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0be0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0aa4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ac4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ae4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ba4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0be4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0aa8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ac8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ae8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ba8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0be8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a2c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a6c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0aac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0acc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0aec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b2c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b6c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bcc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ab0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ad0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0af0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bf0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0a94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ab4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ad4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0af4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0b94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bb4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bd4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0bf4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ca0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ce0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cf0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c24, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c34, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c64, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c94, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ca4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cb4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cd4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ce4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cf4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c18, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c28, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c38, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c68, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c78, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c98, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ca8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cb8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cd8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ce8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0cf8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0c0c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c1c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c2c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c3c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c4c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c5c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c6c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c7c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c8c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0c9c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0cac, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0cbc, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0ccc, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0cdc, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0cec, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0cfc, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0d00, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d08, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d10, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d18, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d20, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d28, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d30, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d38, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d04, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d0c, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d14, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d1c, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d24, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d2c, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d34, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d3c, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e00, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e20, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e30, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e60, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e70, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ea0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0eb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ec0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ed0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ee0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ef0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0e04, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e14, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e24, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e34, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e44, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e54, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e64, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e74, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e84, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e94, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ea4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0eb4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ec4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ed4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ee4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ef4, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e08, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e18, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e28, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e38, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e48, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e58, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e68, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e78, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e88, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0e98, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ea8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0eb8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ec8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ed8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ee8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0ef8, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d40, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d48, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d50, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d44, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d4c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d5c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1e00, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e20, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e40, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e60, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e80, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ea0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ec0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ee0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e04, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e24, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e44, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e64, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e84, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ea4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ec4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ee4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e08, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e28, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e48, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e68, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e88, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1ea8, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1ec8, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1ee8, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e0c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e2c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e4c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e6c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e8c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1eac, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ecc, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1eec, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e10, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e30, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e50, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e70, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e90, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1eb0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ed0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ef0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e14, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e34, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e54, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e74, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e94, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1eb4, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1ed4, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1ef4, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1e18, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e38, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e58, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e78, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1e98, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1eb8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ed8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1ef8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x3400, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3404, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3408, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x340c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3410, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3414, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3418, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x341c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3420, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3424, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3428, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x342c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3430, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3434, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3438, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x343c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3440, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3444, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3448, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x344c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3450, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3454, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3458, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x345c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3460, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3464, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3468, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x346c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3470, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3474, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3478, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x347c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3480, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3484, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3488, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x348c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3490, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3494, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3498, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x349c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34b0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34b4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34d4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x34fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3500, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3504, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3508, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x350c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3510, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3514, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3518, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x351c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3520, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3524, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3528, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x352c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3530, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3534, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3538, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x353c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3540, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3544, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3548, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x354c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3550, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3554, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3558, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x355c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3560, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3564, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3568, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x356c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3570, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3574, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3578, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x357c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3580, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3584, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3588, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x358c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3590, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3594, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x3598, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x359c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35b0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35b4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35d4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x35fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x030c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1944, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1514, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d68, 0x0000ffff);
+ nv_mthd(dev, 0x9097, 0x121c, 0x0fac6881);
+ nv_mthd(dev, 0x9097, 0x0fac, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1538, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0fe0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fe4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fe8, 0x00000014);
+ nv_mthd(dev, 0x9097, 0x0fec, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x0ff0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x179c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1228, 0x00000400);
+ nv_mthd(dev, 0x9097, 0x122c, 0x00000300);
+ nv_mthd(dev, 0x9097, 0x1230, 0x00010001);
+ nv_mthd(dev, 0x9097, 0x07f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15b4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x15cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1534, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fb0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x153c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x16b4, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x0fbc, 0x0000ffff);
+ nv_mthd(dev, 0x9097, 0x0fc0, 0x0000ffff);
+ nv_mthd(dev, 0x9097, 0x0fc4, 0x0000ffff);
+ nv_mthd(dev, 0x9097, 0x0fc8, 0x0000ffff);
+ nv_mthd(dev, 0x9097, 0x0df8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0dfc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1948, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1970, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x161c, 0x000009f0);
+ nv_mthd(dev, 0x9097, 0x0dcc, 0x00000010);
+ nv_mthd(dev, 0x9097, 0x163c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1160, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1164, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1168, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x116c, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1170, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1174, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1178, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x117c, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1180, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1184, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1188, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x118c, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1190, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1194, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1198, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x119c, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11a0, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11a4, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11a8, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11ac, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11b0, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11b4, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11b8, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11bc, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11c0, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11c4, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11c8, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11cc, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11d0, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11d4, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11d8, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x11dc, 0x25e00040);
+ nv_mthd(dev, 0x9097, 0x1880, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1884, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1888, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x188c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1890, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1894, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1898, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x189c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18b0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18b4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18d0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18d4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18e0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x18fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x17c8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x17cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x17d0, 0x000000ff);
+ nv_mthd(dev, 0x9097, 0x17d4, 0xffffffff);
+ nv_mthd(dev, 0x9097, 0x17d8, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x17dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15f8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1434, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1438, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d74, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0dec, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x13a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1318, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1644, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0748, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0de8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1648, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12a4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1120, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1124, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1128, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x112c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1118, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x164c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1658, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1910, 0x00000290);
+ nv_mthd(dev, 0x9097, 0x1518, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x165c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1520, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1604, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1570, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x13b0, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x13b4, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x020c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1670, 0x30201000);
+ nv_mthd(dev, 0x9097, 0x1674, 0x70605040);
+ nv_mthd(dev, 0x9097, 0x1678, 0xb8a89888);
+ nv_mthd(dev, 0x9097, 0x167c, 0xf8e8d8c8);
+ nv_mthd(dev, 0x9097, 0x166c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1680, 0x00ffff00);
+ nv_mthd(dev, 0x9097, 0x12d0, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x12d4, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1684, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1688, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0dac, 0x00001b02);
+ nv_mthd(dev, 0x9097, 0x0db0, 0x00001b02);
+ nv_mthd(dev, 0x9097, 0x0db4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x168c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x15bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x156c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x187c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1110, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0dc0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0dc4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0dc8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1234, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1690, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12ac, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x02c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0790, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0794, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0798, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x079c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x07a0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x077c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1000, 0x00000010);
+ nv_mthd(dev, 0x9097, 0x10fc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1290, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0218, 0x00000010);
+ nv_mthd(dev, 0x9097, 0x12d8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12dc, 0x00000010);
+ nv_mthd(dev, 0x9097, 0x0d94, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x155c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1560, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1564, 0x00001fff);
+ nv_mthd(dev, 0x9097, 0x1574, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1578, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x157c, 0x003fffff);
+ nv_mthd(dev, 0x9097, 0x1354, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1664, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1610, 0x00000012);
+ nv_mthd(dev, 0x9097, 0x1608, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x160c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x162c, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x0210, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0320, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0324, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0328, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x032c, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0330, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0334, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0338, 0x3f800000);
+ nv_mthd(dev, 0x9097, 0x0750, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0760, 0x39291909);
+ nv_mthd(dev, 0x9097, 0x0764, 0x79695949);
+ nv_mthd(dev, 0x9097, 0x0768, 0xb9a99989);
+ nv_mthd(dev, 0x9097, 0x076c, 0xf9e9d9c9);
+ nv_mthd(dev, 0x9097, 0x0770, 0x30201000);
+ nv_mthd(dev, 0x9097, 0x0774, 0x70605040);
+ nv_mthd(dev, 0x9097, 0x0778, 0x00009080);
+ nv_mthd(dev, 0x9097, 0x0780, 0x39291909);
+ nv_mthd(dev, 0x9097, 0x0784, 0x79695949);
+ nv_mthd(dev, 0x9097, 0x0788, 0xb9a99989);
+ nv_mthd(dev, 0x9097, 0x078c, 0xf9e9d9c9);
+ nv_mthd(dev, 0x9097, 0x07d0, 0x30201000);
+ nv_mthd(dev, 0x9097, 0x07d4, 0x70605040);
+ nv_mthd(dev, 0x9097, 0x07d8, 0x00009080);
+ nv_mthd(dev, 0x9097, 0x037c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0740, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0744, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x2600, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1918, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x191c, 0x00000900);
+ nv_mthd(dev, 0x9097, 0x1920, 0x00000405);
+ nv_mthd(dev, 0x9097, 0x1308, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1924, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x13ac, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x192c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x193c, 0x00002c1c);
+ nv_mthd(dev, 0x9097, 0x0d7c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x02c0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1510, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1940, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ff4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0ff8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x194c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1950, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1968, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1590, 0x0000003f);
+ nv_mthd(dev, 0x9097, 0x07e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x07ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x07f0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x07f4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x196c, 0x00000011);
+ nv_mthd(dev, 0x9097, 0x197c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fcc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fd0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x02d8, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x1980, 0x00000080);
+ nv_mthd(dev, 0x9097, 0x1504, 0x00000080);
+ nv_mthd(dev, 0x9097, 0x1984, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0300, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x13a8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12ec, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1310, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1314, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1380, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1384, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1388, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x138c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1390, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1394, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x139c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1398, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1594, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1598, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x159c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x15a0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x15a4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x0f54, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f58, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f5c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x19bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f9c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0fa0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12cc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x12e8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x130c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1360, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1364, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1368, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x136c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1370, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1374, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1378, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x137c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x133c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1340, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1344, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1348, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x134c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1350, 0x00000002);
+ nv_mthd(dev, 0x9097, 0x1358, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x12e4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x131c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1320, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1324, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1328, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x19c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1140, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x19c4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x19c8, 0x00001500);
+ nv_mthd(dev, 0x9097, 0x135c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x19e0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19e4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19e8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19ec, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19f0, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19f4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19f8, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19fc, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x19cc, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x15b8, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a00, 0x00001111);
+ nv_mthd(dev, 0x9097, 0x1a04, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a08, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a0c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a10, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a14, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a18, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1a1c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d6c, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x0d70, 0xffff0000);
+ nv_mthd(dev, 0x9097, 0x10f8, 0x00001010);
+ nv_mthd(dev, 0x9097, 0x0d80, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d84, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d88, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d8c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0d90, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0da0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1508, 0x80000000);
+ nv_mthd(dev, 0x9097, 0x150c, 0x40000000);
+ nv_mthd(dev, 0x9097, 0x1668, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0318, 0x00000008);
+ nv_mthd(dev, 0x9097, 0x031c, 0x00000008);
+ nv_mthd(dev, 0x9097, 0x0d9c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x07dc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x074c, 0x00000055);
+ nv_mthd(dev, 0x9097, 0x1420, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x17bc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x17c0, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x17c4, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1008, 0x00000008);
+ nv_mthd(dev, 0x9097, 0x100c, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x1010, 0x0000012c);
+ nv_mthd(dev, 0x9097, 0x0d60, 0x00000040);
+ nv_mthd(dev, 0x9097, 0x075c, 0x00000003);
+ nv_mthd(dev, 0x9097, 0x1018, 0x00000020);
+ nv_mthd(dev, 0x9097, 0x101c, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1020, 0x00000020);
+ nv_mthd(dev, 0x9097, 0x1024, 0x00000001);
+ nv_mthd(dev, 0x9097, 0x1444, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x1448, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x144c, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0360, 0x20164010);
+ nv_mthd(dev, 0x9097, 0x0364, 0x00000020);
+ nv_mthd(dev, 0x9097, 0x0368, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0de4, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0204, 0x00000006);
+ nv_mthd(dev, 0x9097, 0x0208, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x02cc, 0x003fffff);
+ nv_mthd(dev, 0x9097, 0x02d0, 0x00000c48);
+ nv_mthd(dev, 0x9097, 0x1220, 0x00000005);
+ nv_mthd(dev, 0x9097, 0x0fdc, 0x00000000);
+ nv_mthd(dev, 0x9097, 0x0f98, 0x00300008);
+ nv_mthd(dev, 0x9097, 0x1284, 0x04000080);
+ nv_mthd(dev, 0x9097, 0x1450, 0x00300008);
+ nv_mthd(dev, 0x9097, 0x1454, 0x04000080);
+ nv_mthd(dev, 0x9097, 0x0214, 0x00000000);
+ /* in trace, right after 0x90c0, not here */
+ nv_mthd(dev, 0x9097, 0x3410, 0x80002006);
+}
+
+static void
+nvc0_grctx_generate_902d(struct drm_device *dev)
+{
+ nv_mthd(dev, 0x902d, 0x0200, 0x000000cf);
+ nv_mthd(dev, 0x902d, 0x0204, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0208, 0x00000020);
+ nv_mthd(dev, 0x902d, 0x020c, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0210, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0214, 0x00000080);
+ nv_mthd(dev, 0x902d, 0x0218, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x021c, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x0220, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0224, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0230, 0x000000cf);
+ nv_mthd(dev, 0x902d, 0x0234, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0238, 0x00000020);
+ nv_mthd(dev, 0x902d, 0x023c, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0244, 0x00000080);
+ nv_mthd(dev, 0x902d, 0x0248, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x024c, 0x00000100);
+}
+
+static void
+nvc0_grctx_generate_9039(struct drm_device *dev)
+{
+ nv_mthd(dev, 0x9039, 0x030c, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x0310, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x0314, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x0320, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x0238, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x023c, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x0318, 0x00000000);
+ nv_mthd(dev, 0x9039, 0x031c, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_90c0(struct drm_device *dev)
+{
+ nv_mthd(dev, 0x90c0, 0x270c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x272c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x274c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x276c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x278c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x27ac, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x27cc, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x27ec, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x030c, 0x00000001);
+ nv_mthd(dev, 0x90c0, 0x1944, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0758, 0x00000100);
+ nv_mthd(dev, 0x90c0, 0x02c4, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0790, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0794, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0798, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x079c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x07a0, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x077c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0204, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0208, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x020c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0214, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x024c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x0d94, 0x00000001);
+ nv_mthd(dev, 0x90c0, 0x1608, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x160c, 0x00000000);
+ nv_mthd(dev, 0x90c0, 0x1664, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_dispatch(struct drm_device *dev)
+{
+ int i;
+
+ nv_wr32(dev, 0x404004, 0x00000000);
+ nv_wr32(dev, 0x404008, 0x00000000);
+ nv_wr32(dev, 0x40400c, 0x00000000);
+ nv_wr32(dev, 0x404010, 0x00000000);
+ nv_wr32(dev, 0x404014, 0x00000000);
+ nv_wr32(dev, 0x404018, 0x00000000);
+ nv_wr32(dev, 0x40401c, 0x00000000);
+ nv_wr32(dev, 0x404020, 0x00000000);
+ nv_wr32(dev, 0x404024, 0x00000000);
+ nv_wr32(dev, 0x404028, 0x00000000);
+ nv_wr32(dev, 0x40402c, 0x00000000);
+ nv_wr32(dev, 0x404044, 0x00000000);
+ nv_wr32(dev, 0x404094, 0x00000000);
+ nv_wr32(dev, 0x404098, 0x00000000);
+ nv_wr32(dev, 0x40409c, 0x00000000);
+ nv_wr32(dev, 0x4040a0, 0x00000000);
+ nv_wr32(dev, 0x4040a4, 0x00000000);
+ nv_wr32(dev, 0x4040a8, 0x00000000);
+ nv_wr32(dev, 0x4040ac, 0x00000000);
+ nv_wr32(dev, 0x4040b0, 0x00000000);
+ nv_wr32(dev, 0x4040b4, 0x00000000);
+ nv_wr32(dev, 0x4040b8, 0x00000000);
+ nv_wr32(dev, 0x4040bc, 0x00000000);
+ nv_wr32(dev, 0x4040c0, 0x00000000);
+ nv_wr32(dev, 0x4040c4, 0x00000000);
+ nv_wr32(dev, 0x4040c8, 0xf0000087);
+ nv_wr32(dev, 0x4040d4, 0x00000000);
+ nv_wr32(dev, 0x4040d8, 0x00000000);
+ nv_wr32(dev, 0x4040dc, 0x00000000);
+ nv_wr32(dev, 0x4040e0, 0x00000000);
+ nv_wr32(dev, 0x4040e4, 0x00000000);
+ nv_wr32(dev, 0x4040e8, 0x00001000);
+ nv_wr32(dev, 0x4040f8, 0x00000000);
+ nv_wr32(dev, 0x404130, 0x00000000);
+ nv_wr32(dev, 0x404134, 0x00000000);
+ nv_wr32(dev, 0x404138, 0x20000040);
+ nv_wr32(dev, 0x404150, 0x0000002e);
+ nv_wr32(dev, 0x404154, 0x00000400);
+ nv_wr32(dev, 0x404158, 0x00000200);
+ nv_wr32(dev, 0x404164, 0x00000055);
+ nv_wr32(dev, 0x404168, 0x00000000);
+ nv_wr32(dev, 0x404174, 0x00000000);
+ nv_wr32(dev, 0x404178, 0x00000000);
+ nv_wr32(dev, 0x40417c, 0x00000000);
+ for (i = 0; i < 8; i++)
+ nv_wr32(dev, 0x404200 + (i * 4), 0x00000000); /* subc */
+}
+
+static void
+nvc0_grctx_generate_macro(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404404, 0x00000000);
+ nv_wr32(dev, 0x404408, 0x00000000);
+ nv_wr32(dev, 0x40440c, 0x00000000);
+ nv_wr32(dev, 0x404410, 0x00000000);
+ nv_wr32(dev, 0x404414, 0x00000000);
+ nv_wr32(dev, 0x404418, 0x00000000);
+ nv_wr32(dev, 0x40441c, 0x00000000);
+ nv_wr32(dev, 0x404420, 0x00000000);
+ nv_wr32(dev, 0x404424, 0x00000000);
+ nv_wr32(dev, 0x404428, 0x00000000);
+ nv_wr32(dev, 0x40442c, 0x00000000);
+ nv_wr32(dev, 0x404430, 0x00000000);
+ nv_wr32(dev, 0x404434, 0x00000000);
+ nv_wr32(dev, 0x404438, 0x00000000);
+ nv_wr32(dev, 0x404460, 0x00000000);
+ nv_wr32(dev, 0x404464, 0x00000000);
+ nv_wr32(dev, 0x404468, 0x00ffffff);
+ nv_wr32(dev, 0x40446c, 0x00000000);
+ nv_wr32(dev, 0x404480, 0x00000001);
+ nv_wr32(dev, 0x404498, 0x00000001);
+}
+
+static void
+nvc0_grctx_generate_m2mf(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404604, 0x00000015);
+ nv_wr32(dev, 0x404608, 0x00000000);
+ nv_wr32(dev, 0x40460c, 0x00002e00);
+ nv_wr32(dev, 0x404610, 0x00000100);
+ nv_wr32(dev, 0x404618, 0x00000000);
+ nv_wr32(dev, 0x40461c, 0x00000000);
+ nv_wr32(dev, 0x404620, 0x00000000);
+ nv_wr32(dev, 0x404624, 0x00000000);
+ nv_wr32(dev, 0x404628, 0x00000000);
+ nv_wr32(dev, 0x40462c, 0x00000000);
+ nv_wr32(dev, 0x404630, 0x00000000);
+ nv_wr32(dev, 0x404634, 0x00000000);
+ nv_wr32(dev, 0x404638, 0x00000004);
+ nv_wr32(dev, 0x40463c, 0x00000000);
+ nv_wr32(dev, 0x404640, 0x00000000);
+ nv_wr32(dev, 0x404644, 0x00000000);
+ nv_wr32(dev, 0x404648, 0x00000000);
+ nv_wr32(dev, 0x40464c, 0x00000000);
+ nv_wr32(dev, 0x404650, 0x00000000);
+ nv_wr32(dev, 0x404654, 0x00000000);
+ nv_wr32(dev, 0x404658, 0x00000000);
+ nv_wr32(dev, 0x40465c, 0x007f0100);
+ nv_wr32(dev, 0x404660, 0x00000000);
+ nv_wr32(dev, 0x404664, 0x00000000);
+ nv_wr32(dev, 0x404668, 0x00000000);
+ nv_wr32(dev, 0x40466c, 0x00000000);
+ nv_wr32(dev, 0x404670, 0x00000000);
+ nv_wr32(dev, 0x404674, 0x00000000);
+ nv_wr32(dev, 0x404678, 0x00000000);
+ nv_wr32(dev, 0x40467c, 0x00000002);
+ nv_wr32(dev, 0x404680, 0x00000000);
+ nv_wr32(dev, 0x404684, 0x00000000);
+ nv_wr32(dev, 0x404688, 0x00000000);
+ nv_wr32(dev, 0x40468c, 0x00000000);
+ nv_wr32(dev, 0x404690, 0x00000000);
+ nv_wr32(dev, 0x404694, 0x00000000);
+ nv_wr32(dev, 0x404698, 0x00000000);
+ nv_wr32(dev, 0x40469c, 0x00000000);
+ nv_wr32(dev, 0x4046a0, 0x007f0080);
+ nv_wr32(dev, 0x4046a4, 0x00000000);
+ nv_wr32(dev, 0x4046a8, 0x00000000);
+ nv_wr32(dev, 0x4046ac, 0x00000000);
+ nv_wr32(dev, 0x4046b0, 0x00000000);
+ nv_wr32(dev, 0x4046b4, 0x00000000);
+ nv_wr32(dev, 0x4046b8, 0x00000000);
+ nv_wr32(dev, 0x4046bc, 0x00000000);
+ nv_wr32(dev, 0x4046c0, 0x00000000);
+ nv_wr32(dev, 0x4046c4, 0x00000000);
+ nv_wr32(dev, 0x4046c8, 0x00000000);
+ nv_wr32(dev, 0x4046cc, 0x00000000);
+ nv_wr32(dev, 0x4046d0, 0x00000000);
+ nv_wr32(dev, 0x4046d4, 0x00000000);
+ nv_wr32(dev, 0x4046d8, 0x00000000);
+ nv_wr32(dev, 0x4046dc, 0x00000000);
+ nv_wr32(dev, 0x4046e0, 0x00000000);
+ nv_wr32(dev, 0x4046e4, 0x00000000);
+ nv_wr32(dev, 0x4046e8, 0x00000000);
+ nv_wr32(dev, 0x4046f0, 0x00000000);
+ nv_wr32(dev, 0x4046f4, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_unk47xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404700, 0x00000000);
+ nv_wr32(dev, 0x404704, 0x00000000);
+ nv_wr32(dev, 0x404708, 0x00000000);
+ nv_wr32(dev, 0x40470c, 0x00000000);
+ nv_wr32(dev, 0x404710, 0x00000000);
+ nv_wr32(dev, 0x404714, 0x00000000);
+ nv_wr32(dev, 0x404718, 0x00000000);
+ nv_wr32(dev, 0x40471c, 0x00000000);
+ nv_wr32(dev, 0x404720, 0x00000000);
+ nv_wr32(dev, 0x404724, 0x00000000);
+ nv_wr32(dev, 0x404728, 0x00000000);
+ nv_wr32(dev, 0x40472c, 0x00000000);
+ nv_wr32(dev, 0x404730, 0x00000000);
+ nv_wr32(dev, 0x404734, 0x00000100);
+ nv_wr32(dev, 0x404738, 0x00000000);
+ nv_wr32(dev, 0x40473c, 0x00000000);
+ nv_wr32(dev, 0x404740, 0x00000000);
+ nv_wr32(dev, 0x404744, 0x00000000);
+ nv_wr32(dev, 0x404748, 0x00000000);
+ nv_wr32(dev, 0x40474c, 0x00000000);
+ nv_wr32(dev, 0x404750, 0x00000000);
+ nv_wr32(dev, 0x404754, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_shaders(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x405800, 0x078000bf);
+ nv_wr32(dev, 0x405830, 0x02180000);
+ nv_wr32(dev, 0x405834, 0x00000000);
+ nv_wr32(dev, 0x405838, 0x00000000);
+ nv_wr32(dev, 0x405854, 0x00000000);
+ nv_wr32(dev, 0x405870, 0x00000001);
+ nv_wr32(dev, 0x405874, 0x00000001);
+ nv_wr32(dev, 0x405878, 0x00000001);
+ nv_wr32(dev, 0x40587c, 0x00000001);
+ nv_wr32(dev, 0x405a00, 0x00000000);
+ nv_wr32(dev, 0x405a04, 0x00000000);
+ nv_wr32(dev, 0x405a18, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_unk60xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x406020, 0x000103c1);
+ nv_wr32(dev, 0x406028, 0x00000001);
+ nv_wr32(dev, 0x40602c, 0x00000001);
+ nv_wr32(dev, 0x406030, 0x00000001);
+ nv_wr32(dev, 0x406034, 0x00000001);
+}
+
+static void
+nvc0_grctx_generate_unk64xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x4064a8, 0x00000000);
+ nv_wr32(dev, 0x4064ac, 0x00003fff);
+ nv_wr32(dev, 0x4064b4, 0x00000000);
+ nv_wr32(dev, 0x4064b8, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_tpbus(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x407804, 0x00000023);
+ nv_wr32(dev, 0x40780c, 0x0a418820);
+ nv_wr32(dev, 0x407810, 0x062080e6);
+ nv_wr32(dev, 0x407814, 0x020398a4);
+ nv_wr32(dev, 0x407818, 0x0e629062);
+ nv_wr32(dev, 0x40781c, 0x0a418820);
+ nv_wr32(dev, 0x407820, 0x000000e6);
+ nv_wr32(dev, 0x4078bc, 0x00000103);
+}
+
+static void
+nvc0_grctx_generate_ccache(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x408000, 0x00000000);
+ nv_wr32(dev, 0x408004, 0x00000000);
+ nv_wr32(dev, 0x408008, 0x00000018);
+ nv_wr32(dev, 0x40800c, 0x00000000);
+ nv_wr32(dev, 0x408010, 0x00000000);
+ nv_wr32(dev, 0x408014, 0x00000069);
+ nv_wr32(dev, 0x408018, 0xe100e100);
+ nv_wr32(dev, 0x408064, 0x00000000);
+}
+
+static void
+nvc0_grctx_generate_rop(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ // ROPC_BROADCAST
+ nv_wr32(dev, 0x408800, 0x02802a3c);
+ nv_wr32(dev, 0x408804, 0x00000040);
+ nv_wr32(dev, 0x408808, 0x0003e00d);
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ nv_wr32(dev, 0x408900, 0x0080b801);
+ break;
+ case 0xc3:
+ case 0xc4:
+ nv_wr32(dev, 0x408900, 0x3080b801);
+ break;
+ }
+ nv_wr32(dev, 0x408904, 0x02000001);
+ nv_wr32(dev, 0x408908, 0x00c80929);
+ nv_wr32(dev, 0x40890c, 0x00000000);
+ nv_wr32(dev, 0x408980, 0x0000011d);
+}
+
+static void
+nvc0_grctx_generate_gpc(struct drm_device *dev)
+{
+ int i;
+
+ // GPC_BROADCAST
+ nv_wr32(dev, 0x418380, 0x00000016);
+ nv_wr32(dev, 0x418400, 0x38004e00);
+ nv_wr32(dev, 0x418404, 0x71e0ffff);
+ nv_wr32(dev, 0x418408, 0x00000000);
+ nv_wr32(dev, 0x41840c, 0x00001008);
+ nv_wr32(dev, 0x418410, 0x0fff0fff);
+ nv_wr32(dev, 0x418414, 0x00200fff);
+ nv_wr32(dev, 0x418450, 0x00000000);
+ nv_wr32(dev, 0x418454, 0x00000000);
+ nv_wr32(dev, 0x418458, 0x00000000);
+ nv_wr32(dev, 0x41845c, 0x00000000);
+ nv_wr32(dev, 0x418460, 0x00000000);
+ nv_wr32(dev, 0x418464, 0x00000000);
+ nv_wr32(dev, 0x418468, 0x00000001);
+ nv_wr32(dev, 0x41846c, 0x00000000);
+ nv_wr32(dev, 0x418470, 0x00000000);
+ nv_wr32(dev, 0x418600, 0x0000001f);
+ nv_wr32(dev, 0x418684, 0x0000000f);
+ nv_wr32(dev, 0x418700, 0x00000002);
+ nv_wr32(dev, 0x418704, 0x00000080);
+ nv_wr32(dev, 0x418708, 0x00000000);
+ nv_wr32(dev, 0x41870c, 0x07c80000);
+ nv_wr32(dev, 0x418710, 0x00000000);
+ nv_wr32(dev, 0x418800, 0x0006860a);
+ nv_wr32(dev, 0x418808, 0x00000000);
+ nv_wr32(dev, 0x41880c, 0x00000000);
+ nv_wr32(dev, 0x418810, 0x00000000);
+ nv_wr32(dev, 0x418828, 0x00008442);
+ nv_wr32(dev, 0x418830, 0x00000001);
+ nv_wr32(dev, 0x4188d8, 0x00000008);
+ nv_wr32(dev, 0x4188e0, 0x01000000);
+ nv_wr32(dev, 0x4188e8, 0x00000000);
+ nv_wr32(dev, 0x4188ec, 0x00000000);
+ nv_wr32(dev, 0x4188f0, 0x00000000);
+ nv_wr32(dev, 0x4188f4, 0x00000000);
+ nv_wr32(dev, 0x4188f8, 0x00000000);
+ nv_wr32(dev, 0x4188fc, 0x00100000);
+ nv_wr32(dev, 0x41891c, 0x00ff00ff);
+ nv_wr32(dev, 0x418924, 0x00000000);
+ nv_wr32(dev, 0x418928, 0x00ffff00);
+ nv_wr32(dev, 0x41892c, 0x0000ff00);
+ for (i = 0; i < 8; i++) {
+ nv_wr32(dev, 0x418a00 + (i * 0x20), 0x00000000);
+ nv_wr32(dev, 0x418a04 + (i * 0x20), 0x00000000);
+ nv_wr32(dev, 0x418a08 + (i * 0x20), 0x00000000);
+ nv_wr32(dev, 0x418a0c + (i * 0x20), 0x00010000);
+ nv_wr32(dev, 0x418a10 + (i * 0x20), 0x00000000);
+ nv_wr32(dev, 0x418a14 + (i * 0x20), 0x00000000);
+ nv_wr32(dev, 0x418a18 + (i * 0x20), 0x00000000);
+ }
+ nv_wr32(dev, 0x418b00, 0x00000000);
+ nv_wr32(dev, 0x418b08, 0x0a418820);
+ nv_wr32(dev, 0x418b0c, 0x062080e6);
+ nv_wr32(dev, 0x418b10, 0x020398a4);
+ nv_wr32(dev, 0x418b14, 0x0e629062);
+ nv_wr32(dev, 0x418b18, 0x0a418820);
+ nv_wr32(dev, 0x418b1c, 0x000000e6);
+ nv_wr32(dev, 0x418bb8, 0x00000103);
+ nv_wr32(dev, 0x418c08, 0x00000001);
+ nv_wr32(dev, 0x418c10, 0x00000000);
+ nv_wr32(dev, 0x418c14, 0x00000000);
+ nv_wr32(dev, 0x418c18, 0x00000000);
+ nv_wr32(dev, 0x418c1c, 0x00000000);
+ nv_wr32(dev, 0x418c20, 0x00000000);
+ nv_wr32(dev, 0x418c24, 0x00000000);
+ nv_wr32(dev, 0x418c28, 0x00000000);
+ nv_wr32(dev, 0x418c2c, 0x00000000);
+ nv_wr32(dev, 0x418c80, 0x20200004);
+ nv_wr32(dev, 0x418c8c, 0x00000001);
+ nv_wr32(dev, 0x419000, 0x00000780);
+ nv_wr32(dev, 0x419004, 0x00000000);
+ nv_wr32(dev, 0x419008, 0x00000000);
+ nv_wr32(dev, 0x419014, 0x00000004);
+}
+
+static void
+nvc0_grctx_generate_tp(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ // GPC_BROADCAST.TP_BROADCAST
+ nv_wr32(dev, 0x419848, 0x00000000);
+ nv_wr32(dev, 0x419864, 0x0000012a);
+ nv_wr32(dev, 0x419888, 0x00000000);
+ nv_wr32(dev, 0x419a00, 0x000001f0);
+ nv_wr32(dev, 0x419a04, 0x00000001);
+ nv_wr32(dev, 0x419a08, 0x00000023);
+ nv_wr32(dev, 0x419a0c, 0x00020000);
+ nv_wr32(dev, 0x419a10, 0x00000000);
+ nv_wr32(dev, 0x419a14, 0x00000200);
+ nv_wr32(dev, 0x419a1c, 0x00000000);
+ nv_wr32(dev, 0x419a20, 0x00000800);
+ if (dev_priv->chipset != 0xc0)
+ nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+ nv_wr32(dev, 0x419b00, 0x0a418820);
+ nv_wr32(dev, 0x419b04, 0x062080e6);
+ nv_wr32(dev, 0x419b08, 0x020398a4);
+ nv_wr32(dev, 0x419b0c, 0x0e629062);
+ nv_wr32(dev, 0x419b10, 0x0a418820);
+ nv_wr32(dev, 0x419b14, 0x000000e6);
+ nv_wr32(dev, 0x419bd0, 0x00900103);
+ nv_wr32(dev, 0x419be0, 0x00000001);
+ nv_wr32(dev, 0x419be4, 0x00000000);
+ nv_wr32(dev, 0x419c00, 0x00000002);
+ nv_wr32(dev, 0x419c04, 0x00000006);
+ nv_wr32(dev, 0x419c08, 0x00000002);
+ nv_wr32(dev, 0x419c20, 0x00000000);
+ nv_wr32(dev, 0x419cbc, 0x28137606);
+ nv_wr32(dev, 0x419ce8, 0x00000000);
+ nv_wr32(dev, 0x419cf4, 0x00000183);
+ nv_wr32(dev, 0x419d20, 0x02180000);
+ nv_wr32(dev, 0x419d24, 0x00001fff);
+ nv_wr32(dev, 0x419e04, 0x00000000);
+ nv_wr32(dev, 0x419e08, 0x00000000);
+ nv_wr32(dev, 0x419e0c, 0x00000000);
+ nv_wr32(dev, 0x419e10, 0x00000002);
+ nv_wr32(dev, 0x419e44, 0x001beff2);
+ nv_wr32(dev, 0x419e48, 0x00000000);
+ nv_wr32(dev, 0x419e4c, 0x0000000f);
+ nv_wr32(dev, 0x419e50, 0x00000000);
+ nv_wr32(dev, 0x419e54, 0x00000000);
+ nv_wr32(dev, 0x419e58, 0x00000000);
+ nv_wr32(dev, 0x419e5c, 0x00000000);
+ nv_wr32(dev, 0x419e60, 0x00000000);
+ nv_wr32(dev, 0x419e64, 0x00000000);
+ nv_wr32(dev, 0x419e68, 0x00000000);
+ nv_wr32(dev, 0x419e6c, 0x00000000);
+ nv_wr32(dev, 0x419e70, 0x00000000);
+ nv_wr32(dev, 0x419e74, 0x00000000);
+ nv_wr32(dev, 0x419e78, 0x00000000);
+ nv_wr32(dev, 0x419e7c, 0x00000000);
+ nv_wr32(dev, 0x419e80, 0x00000000);
+ nv_wr32(dev, 0x419e84, 0x00000000);
+ nv_wr32(dev, 0x419e88, 0x00000000);
+ nv_wr32(dev, 0x419e8c, 0x00000000);
+ nv_wr32(dev, 0x419e90, 0x00000000);
+ nv_wr32(dev, 0x419e98, 0x00000000);
+ if (dev_priv->chipset != 0xc0)
+ nv_wr32(dev, 0x419ee0, 0x00011110);
+ nv_wr32(dev, 0x419f50, 0x00000000);
+ nv_wr32(dev, 0x419f54, 0x00000000);
+ if (dev_priv->chipset != 0xc0)
+ nv_wr32(dev, 0x419f58, 0x00000000);
+}
+
+int
+nvc0_grctx_generate(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct drm_device *dev = chan->dev;
+ int i, gpc, tp, id;
+ u32 r000260, tmp;
+
+ r000260 = nv_rd32(dev, 0x000260);
+ nv_wr32(dev, 0x000260, r000260 & ~1);
+ nv_wr32(dev, 0x400208, 0x00000000);
+
+ nvc0_grctx_generate_dispatch(dev);
+ nvc0_grctx_generate_macro(dev);
+ nvc0_grctx_generate_m2mf(dev);
+ nvc0_grctx_generate_unk47xx(dev);
+ nvc0_grctx_generate_shaders(dev);
+ nvc0_grctx_generate_unk60xx(dev);
+ nvc0_grctx_generate_unk64xx(dev);
+ nvc0_grctx_generate_tpbus(dev);
+ nvc0_grctx_generate_ccache(dev);
+ nvc0_grctx_generate_rop(dev);
+ nvc0_grctx_generate_gpc(dev);
+ nvc0_grctx_generate_tp(dev);
+
+ nv_wr32(dev, 0x404154, 0x00000000);
+
+ /* fuc "mmio list" writes */
+ for (i = 0; i < grch->mmio_nr * 8; i += 8) {
+ u32 reg = nv_ro32(grch->mmio, i + 0);
+ nv_wr32(dev, reg, nv_ro32(grch->mmio, i + 4));
+ }
+
+ for (tp = 0, id = 0; tp < 4; tp++) {
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ if (tp <= priv->tp_nr[gpc]) {
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id);
+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x088), id);
+ id++;
+ }
+
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c08), priv->tp_nr[gpc]);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c8c), priv->tp_nr[gpc]);
+ }
+ }
+
+ tmp = 0;
+ for (i = 0; i < priv->gpc_nr; i++)
+ tmp |= priv->tp_nr[i] << (i * 4);
+ nv_wr32(dev, 0x406028, tmp);
+ nv_wr32(dev, 0x405870, tmp);
+
+ nv_wr32(dev, 0x40602c, 0x00000000);
+ nv_wr32(dev, 0x405874, 0x00000000);
+ nv_wr32(dev, 0x406030, 0x00000000);
+ nv_wr32(dev, 0x405878, 0x00000000);
+ nv_wr32(dev, 0x406034, 0x00000000);
+ nv_wr32(dev, 0x40587c, 0x00000000);
+
+ if (1) {
+ const u8 chipset_tp_max[] = { 16, 0, 0, 4, 8 };
+ u8 max = chipset_tp_max[dev_priv->chipset & 0x0f];
+ u8 tpnr[GPC_MAX];
+ u8 data[32];
+
+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+ memset(data, 0x1f, sizeof(data));
+
+ gpc = -1;
+ for (tp = 0; tp < priv->tp_total; tp++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpnr[gpc]);
+ tpnr[gpc]--;
+ data[tp] = gpc;
+ }
+
+ for (i = 0; i < max / 4; i++)
+ nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+ }
+
+ if (1) {
+ u32 data[6] = {}, data2[2] = {};
+ u8 tpnr[GPC_MAX];
+ u8 shift, ntpcv;
+
+ /* calculate first set of magics */
+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+
+ for (tp = 0; tp < priv->tp_total; tp++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpnr[gpc]);
+ tpnr[gpc]--;
+
+ data[tp / 6] |= gpc << ((tp % 6) * 5);
+ }
+
+ for (; tp < 32; tp++)
+ data[tp / 6] |= 7 << ((tp % 6) * 5);
+
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tp_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
+
+ data2[0] = (ntpcv << 16);
+ data2[0] |= (shift << 21);
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+ // GPC_BROADCAST
+ nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
+
+ // GPC_BROADCAST.TP_BROADCAST
+ nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
+ priv->magic_not_rop_nr |
+ data2[0]);
+ nv_wr32(dev, 0x419be4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
+
+ // UNK78xx
+ nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x40780c + (i * 4), data[i]);
+ }
+
+ if (1) {
+ u32 tp_mask = 0, tp_set = 0;
+ u8 tpnr[GPC_MAX];
+
+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+ tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8);
+
+ gpc = -1;
+ for (i = 0, gpc = -1; i < 32; i++) {
+ int ltp = i * (priv->tp_total - 1) / 32;
+
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpnr[gpc]);
+ tp = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+ tp_set |= 1 << ((gpc * 8) + tp);
+
+ do {
+ nv_wr32(dev, 0x406800 + (i * 0x20), tp_set);
+ tp_set ^= tp_mask;
+ nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set);
+ tp_set ^= tp_mask;
+ } while (ltp == (++i * (priv->tp_total - 1) / 32));
+ i--;
+ }
+ }
+
+ nv_wr32(dev, 0x400208, 0x80000000);
+
+ nv_icmd(dev, 0x00001000, 0x00000004);
+ nv_icmd(dev, 0x000000a9, 0x0000ffff);
+ nv_icmd(dev, 0x00000038, 0x0fac6881);
+ nv_icmd(dev, 0x0000003d, 0x00000001);
+ nv_icmd(dev, 0x000000e8, 0x00000400);
+ nv_icmd(dev, 0x000000e9, 0x00000400);
+ nv_icmd(dev, 0x000000ea, 0x00000400);
+ nv_icmd(dev, 0x000000eb, 0x00000400);
+ nv_icmd(dev, 0x000000ec, 0x00000400);
+ nv_icmd(dev, 0x000000ed, 0x00000400);
+ nv_icmd(dev, 0x000000ee, 0x00000400);
+ nv_icmd(dev, 0x000000ef, 0x00000400);
+ nv_icmd(dev, 0x00000078, 0x00000300);
+ nv_icmd(dev, 0x00000079, 0x00000300);
+ nv_icmd(dev, 0x0000007a, 0x00000300);
+ nv_icmd(dev, 0x0000007b, 0x00000300);
+ nv_icmd(dev, 0x0000007c, 0x00000300);
+ nv_icmd(dev, 0x0000007d, 0x00000300);
+ nv_icmd(dev, 0x0000007e, 0x00000300);
+ nv_icmd(dev, 0x0000007f, 0x00000300);
+ nv_icmd(dev, 0x00000050, 0x00000011);
+ nv_icmd(dev, 0x00000058, 0x00000008);
+ nv_icmd(dev, 0x00000059, 0x00000008);
+ nv_icmd(dev, 0x0000005a, 0x00000008);
+ nv_icmd(dev, 0x0000005b, 0x00000008);
+ nv_icmd(dev, 0x0000005c, 0x00000008);
+ nv_icmd(dev, 0x0000005d, 0x00000008);
+ nv_icmd(dev, 0x0000005e, 0x00000008);
+ nv_icmd(dev, 0x0000005f, 0x00000008);
+ nv_icmd(dev, 0x00000208, 0x00000001);
+ nv_icmd(dev, 0x00000209, 0x00000001);
+ nv_icmd(dev, 0x0000020a, 0x00000001);
+ nv_icmd(dev, 0x0000020b, 0x00000001);
+ nv_icmd(dev, 0x0000020c, 0x00000001);
+ nv_icmd(dev, 0x0000020d, 0x00000001);
+ nv_icmd(dev, 0x0000020e, 0x00000001);
+ nv_icmd(dev, 0x0000020f, 0x00000001);
+ nv_icmd(dev, 0x00000081, 0x00000001);
+ nv_icmd(dev, 0x00000085, 0x00000004);
+ nv_icmd(dev, 0x00000088, 0x00000400);
+ nv_icmd(dev, 0x00000090, 0x00000300);
+ nv_icmd(dev, 0x00000098, 0x00001001);
+ nv_icmd(dev, 0x000000e3, 0x00000001);
+ nv_icmd(dev, 0x000000da, 0x00000001);
+ nv_icmd(dev, 0x000000f8, 0x00000003);
+ nv_icmd(dev, 0x000000fa, 0x00000001);
+ nv_icmd(dev, 0x0000009f, 0x0000ffff);
+ nv_icmd(dev, 0x000000a0, 0x0000ffff);
+ nv_icmd(dev, 0x000000a1, 0x0000ffff);
+ nv_icmd(dev, 0x000000a2, 0x0000ffff);
+ nv_icmd(dev, 0x000000b1, 0x00000001);
+ nv_icmd(dev, 0x000000b2, 0x00000000);
+ nv_icmd(dev, 0x000000b3, 0x00000000);
+ nv_icmd(dev, 0x000000b4, 0x00000000);
+ nv_icmd(dev, 0x000000b5, 0x00000000);
+ nv_icmd(dev, 0x000000b6, 0x00000000);
+ nv_icmd(dev, 0x000000b7, 0x00000000);
+ nv_icmd(dev, 0x000000b8, 0x00000000);
+ nv_icmd(dev, 0x000000b9, 0x00000000);
+ nv_icmd(dev, 0x000000ba, 0x00000000);
+ nv_icmd(dev, 0x000000bb, 0x00000000);
+ nv_icmd(dev, 0x000000bc, 0x00000000);
+ nv_icmd(dev, 0x000000bd, 0x00000000);
+ nv_icmd(dev, 0x000000be, 0x00000000);
+ nv_icmd(dev, 0x000000bf, 0x00000000);
+ nv_icmd(dev, 0x000000c0, 0x00000000);
+ nv_icmd(dev, 0x000000c1, 0x00000000);
+ nv_icmd(dev, 0x000000c2, 0x00000000);
+ nv_icmd(dev, 0x000000c3, 0x00000000);
+ nv_icmd(dev, 0x000000c4, 0x00000000);
+ nv_icmd(dev, 0x000000c5, 0x00000000);
+ nv_icmd(dev, 0x000000c6, 0x00000000);
+ nv_icmd(dev, 0x000000c7, 0x00000000);
+ nv_icmd(dev, 0x000000c8, 0x00000000);
+ nv_icmd(dev, 0x000000c9, 0x00000000);
+ nv_icmd(dev, 0x000000ca, 0x00000000);
+ nv_icmd(dev, 0x000000cb, 0x00000000);
+ nv_icmd(dev, 0x000000cc, 0x00000000);
+ nv_icmd(dev, 0x000000cd, 0x00000000);
+ nv_icmd(dev, 0x000000ce, 0x00000000);
+ nv_icmd(dev, 0x000000cf, 0x00000000);
+ nv_icmd(dev, 0x000000d0, 0x00000000);
+ nv_icmd(dev, 0x000000d1, 0x00000000);
+ nv_icmd(dev, 0x000000d2, 0x00000000);
+ nv_icmd(dev, 0x000000d3, 0x00000000);
+ nv_icmd(dev, 0x000000d4, 0x00000000);
+ nv_icmd(dev, 0x000000d5, 0x00000000);
+ nv_icmd(dev, 0x000000d6, 0x00000000);
+ nv_icmd(dev, 0x000000d7, 0x00000000);
+ nv_icmd(dev, 0x000000d8, 0x00000000);
+ nv_icmd(dev, 0x000000d9, 0x00000000);
+ nv_icmd(dev, 0x00000210, 0x00000040);
+ nv_icmd(dev, 0x00000211, 0x00000040);
+ nv_icmd(dev, 0x00000212, 0x00000040);
+ nv_icmd(dev, 0x00000213, 0x00000040);
+ nv_icmd(dev, 0x00000214, 0x00000040);
+ nv_icmd(dev, 0x00000215, 0x00000040);
+ nv_icmd(dev, 0x00000216, 0x00000040);
+ nv_icmd(dev, 0x00000217, 0x00000040);
+ nv_icmd(dev, 0x00000218, 0x0000c080);
+ nv_icmd(dev, 0x00000219, 0x0000c080);
+ nv_icmd(dev, 0x0000021a, 0x0000c080);
+ nv_icmd(dev, 0x0000021b, 0x0000c080);
+ nv_icmd(dev, 0x0000021c, 0x0000c080);
+ nv_icmd(dev, 0x0000021d, 0x0000c080);
+ nv_icmd(dev, 0x0000021e, 0x0000c080);
+ nv_icmd(dev, 0x0000021f, 0x0000c080);
+ nv_icmd(dev, 0x000000ad, 0x0000013e);
+ nv_icmd(dev, 0x000000e1, 0x00000010);
+ nv_icmd(dev, 0x00000290, 0x00000000);
+ nv_icmd(dev, 0x00000291, 0x00000000);
+ nv_icmd(dev, 0x00000292, 0x00000000);
+ nv_icmd(dev, 0x00000293, 0x00000000);
+ nv_icmd(dev, 0x00000294, 0x00000000);
+ nv_icmd(dev, 0x00000295, 0x00000000);
+ nv_icmd(dev, 0x00000296, 0x00000000);
+ nv_icmd(dev, 0x00000297, 0x00000000);
+ nv_icmd(dev, 0x00000298, 0x00000000);
+ nv_icmd(dev, 0x00000299, 0x00000000);
+ nv_icmd(dev, 0x0000029a, 0x00000000);
+ nv_icmd(dev, 0x0000029b, 0x00000000);
+ nv_icmd(dev, 0x0000029c, 0x00000000);
+ nv_icmd(dev, 0x0000029d, 0x00000000);
+ nv_icmd(dev, 0x0000029e, 0x00000000);
+ nv_icmd(dev, 0x0000029f, 0x00000000);
+ nv_icmd(dev, 0x000003b0, 0x00000000);
+ nv_icmd(dev, 0x000003b1, 0x00000000);
+ nv_icmd(dev, 0x000003b2, 0x00000000);
+ nv_icmd(dev, 0x000003b3, 0x00000000);
+ nv_icmd(dev, 0x000003b4, 0x00000000);
+ nv_icmd(dev, 0x000003b5, 0x00000000);
+ nv_icmd(dev, 0x000003b6, 0x00000000);
+ nv_icmd(dev, 0x000003b7, 0x00000000);
+ nv_icmd(dev, 0x000003b8, 0x00000000);
+ nv_icmd(dev, 0x000003b9, 0x00000000);
+ nv_icmd(dev, 0x000003ba, 0x00000000);
+ nv_icmd(dev, 0x000003bb, 0x00000000);
+ nv_icmd(dev, 0x000003bc, 0x00000000);
+ nv_icmd(dev, 0x000003bd, 0x00000000);
+ nv_icmd(dev, 0x000003be, 0x00000000);
+ nv_icmd(dev, 0x000003bf, 0x00000000);
+ nv_icmd(dev, 0x000002a0, 0x00000000);
+ nv_icmd(dev, 0x000002a1, 0x00000000);
+ nv_icmd(dev, 0x000002a2, 0x00000000);
+ nv_icmd(dev, 0x000002a3, 0x00000000);
+ nv_icmd(dev, 0x000002a4, 0x00000000);
+ nv_icmd(dev, 0x000002a5, 0x00000000);
+ nv_icmd(dev, 0x000002a6, 0x00000000);
+ nv_icmd(dev, 0x000002a7, 0x00000000);
+ nv_icmd(dev, 0x000002a8, 0x00000000);
+ nv_icmd(dev, 0x000002a9, 0x00000000);
+ nv_icmd(dev, 0x000002aa, 0x00000000);
+ nv_icmd(dev, 0x000002ab, 0x00000000);
+ nv_icmd(dev, 0x000002ac, 0x00000000);
+ nv_icmd(dev, 0x000002ad, 0x00000000);
+ nv_icmd(dev, 0x000002ae, 0x00000000);
+ nv_icmd(dev, 0x000002af, 0x00000000);
+ nv_icmd(dev, 0x00000420, 0x00000000);
+ nv_icmd(dev, 0x00000421, 0x00000000);
+ nv_icmd(dev, 0x00000422, 0x00000000);
+ nv_icmd(dev, 0x00000423, 0x00000000);
+ nv_icmd(dev, 0x00000424, 0x00000000);
+ nv_icmd(dev, 0x00000425, 0x00000000);
+ nv_icmd(dev, 0x00000426, 0x00000000);
+ nv_icmd(dev, 0x00000427, 0x00000000);
+ nv_icmd(dev, 0x00000428, 0x00000000);
+ nv_icmd(dev, 0x00000429, 0x00000000);
+ nv_icmd(dev, 0x0000042a, 0x00000000);
+ nv_icmd(dev, 0x0000042b, 0x00000000);
+ nv_icmd(dev, 0x0000042c, 0x00000000);
+ nv_icmd(dev, 0x0000042d, 0x00000000);
+ nv_icmd(dev, 0x0000042e, 0x00000000);
+ nv_icmd(dev, 0x0000042f, 0x00000000);
+ nv_icmd(dev, 0x000002b0, 0x00000000);
+ nv_icmd(dev, 0x000002b1, 0x00000000);
+ nv_icmd(dev, 0x000002b2, 0x00000000);
+ nv_icmd(dev, 0x000002b3, 0x00000000);
+ nv_icmd(dev, 0x000002b4, 0x00000000);
+ nv_icmd(dev, 0x000002b5, 0x00000000);
+ nv_icmd(dev, 0x000002b6, 0x00000000);
+ nv_icmd(dev, 0x000002b7, 0x00000000);
+ nv_icmd(dev, 0x000002b8, 0x00000000);
+ nv_icmd(dev, 0x000002b9, 0x00000000);
+ nv_icmd(dev, 0x000002ba, 0x00000000);
+ nv_icmd(dev, 0x000002bb, 0x00000000);
+ nv_icmd(dev, 0x000002bc, 0x00000000);
+ nv_icmd(dev, 0x000002bd, 0x00000000);
+ nv_icmd(dev, 0x000002be, 0x00000000);
+ nv_icmd(dev, 0x000002bf, 0x00000000);
+ nv_icmd(dev, 0x00000430, 0x00000000);
+ nv_icmd(dev, 0x00000431, 0x00000000);
+ nv_icmd(dev, 0x00000432, 0x00000000);
+ nv_icmd(dev, 0x00000433, 0x00000000);
+ nv_icmd(dev, 0x00000434, 0x00000000);
+ nv_icmd(dev, 0x00000435, 0x00000000);
+ nv_icmd(dev, 0x00000436, 0x00000000);
+ nv_icmd(dev, 0x00000437, 0x00000000);
+ nv_icmd(dev, 0x00000438, 0x00000000);
+ nv_icmd(dev, 0x00000439, 0x00000000);
+ nv_icmd(dev, 0x0000043a, 0x00000000);
+ nv_icmd(dev, 0x0000043b, 0x00000000);
+ nv_icmd(dev, 0x0000043c, 0x00000000);
+ nv_icmd(dev, 0x0000043d, 0x00000000);
+ nv_icmd(dev, 0x0000043e, 0x00000000);
+ nv_icmd(dev, 0x0000043f, 0x00000000);
+ nv_icmd(dev, 0x000002c0, 0x00000000);
+ nv_icmd(dev, 0x000002c1, 0x00000000);
+ nv_icmd(dev, 0x000002c2, 0x00000000);
+ nv_icmd(dev, 0x000002c3, 0x00000000);
+ nv_icmd(dev, 0x000002c4, 0x00000000);
+ nv_icmd(dev, 0x000002c5, 0x00000000);
+ nv_icmd(dev, 0x000002c6, 0x00000000);
+ nv_icmd(dev, 0x000002c7, 0x00000000);
+ nv_icmd(dev, 0x000002c8, 0x00000000);
+ nv_icmd(dev, 0x000002c9, 0x00000000);
+ nv_icmd(dev, 0x000002ca, 0x00000000);
+ nv_icmd(dev, 0x000002cb, 0x00000000);
+ nv_icmd(dev, 0x000002cc, 0x00000000);
+ nv_icmd(dev, 0x000002cd, 0x00000000);
+ nv_icmd(dev, 0x000002ce, 0x00000000);
+ nv_icmd(dev, 0x000002cf, 0x00000000);
+ nv_icmd(dev, 0x000004d0, 0x00000000);
+ nv_icmd(dev, 0x000004d1, 0x00000000);
+ nv_icmd(dev, 0x000004d2, 0x00000000);
+ nv_icmd(dev, 0x000004d3, 0x00000000);
+ nv_icmd(dev, 0x000004d4, 0x00000000);
+ nv_icmd(dev, 0x000004d5, 0x00000000);
+ nv_icmd(dev, 0x000004d6, 0x00000000);
+ nv_icmd(dev, 0x000004d7, 0x00000000);
+ nv_icmd(dev, 0x000004d8, 0x00000000);
+ nv_icmd(dev, 0x000004d9, 0x00000000);
+ nv_icmd(dev, 0x000004da, 0x00000000);
+ nv_icmd(dev, 0x000004db, 0x00000000);
+ nv_icmd(dev, 0x000004dc, 0x00000000);
+ nv_icmd(dev, 0x000004dd, 0x00000000);
+ nv_icmd(dev, 0x000004de, 0x00000000);
+ nv_icmd(dev, 0x000004df, 0x00000000);
+ nv_icmd(dev, 0x00000720, 0x00000000);
+ nv_icmd(dev, 0x00000721, 0x00000000);
+ nv_icmd(dev, 0x00000722, 0x00000000);
+ nv_icmd(dev, 0x00000723, 0x00000000);
+ nv_icmd(dev, 0x00000724, 0x00000000);
+ nv_icmd(dev, 0x00000725, 0x00000000);
+ nv_icmd(dev, 0x00000726, 0x00000000);
+ nv_icmd(dev, 0x00000727, 0x00000000);
+ nv_icmd(dev, 0x00000728, 0x00000000);
+ nv_icmd(dev, 0x00000729, 0x00000000);
+ nv_icmd(dev, 0x0000072a, 0x00000000);
+ nv_icmd(dev, 0x0000072b, 0x00000000);
+ nv_icmd(dev, 0x0000072c, 0x00000000);
+ nv_icmd(dev, 0x0000072d, 0x00000000);
+ nv_icmd(dev, 0x0000072e, 0x00000000);
+ nv_icmd(dev, 0x0000072f, 0x00000000);
+ nv_icmd(dev, 0x000008c0, 0x00000000);
+ nv_icmd(dev, 0x000008c1, 0x00000000);
+ nv_icmd(dev, 0x000008c2, 0x00000000);
+ nv_icmd(dev, 0x000008c3, 0x00000000);
+ nv_icmd(dev, 0x000008c4, 0x00000000);
+ nv_icmd(dev, 0x000008c5, 0x00000000);
+ nv_icmd(dev, 0x000008c6, 0x00000000);
+ nv_icmd(dev, 0x000008c7, 0x00000000);
+ nv_icmd(dev, 0x000008c8, 0x00000000);
+ nv_icmd(dev, 0x000008c9, 0x00000000);
+ nv_icmd(dev, 0x000008ca, 0x00000000);
+ nv_icmd(dev, 0x000008cb, 0x00000000);
+ nv_icmd(dev, 0x000008cc, 0x00000000);
+ nv_icmd(dev, 0x000008cd, 0x00000000);
+ nv_icmd(dev, 0x000008ce, 0x00000000);
+ nv_icmd(dev, 0x000008cf, 0x00000000);
+ nv_icmd(dev, 0x00000890, 0x00000000);
+ nv_icmd(dev, 0x00000891, 0x00000000);
+ nv_icmd(dev, 0x00000892, 0x00000000);
+ nv_icmd(dev, 0x00000893, 0x00000000);
+ nv_icmd(dev, 0x00000894, 0x00000000);
+ nv_icmd(dev, 0x00000895, 0x00000000);
+ nv_icmd(dev, 0x00000896, 0x00000000);
+ nv_icmd(dev, 0x00000897, 0x00000000);
+ nv_icmd(dev, 0x00000898, 0x00000000);
+ nv_icmd(dev, 0x00000899, 0x00000000);
+ nv_icmd(dev, 0x0000089a, 0x00000000);
+ nv_icmd(dev, 0x0000089b, 0x00000000);
+ nv_icmd(dev, 0x0000089c, 0x00000000);
+ nv_icmd(dev, 0x0000089d, 0x00000000);
+ nv_icmd(dev, 0x0000089e, 0x00000000);
+ nv_icmd(dev, 0x0000089f, 0x00000000);
+ nv_icmd(dev, 0x000008e0, 0x00000000);
+ nv_icmd(dev, 0x000008e1, 0x00000000);
+ nv_icmd(dev, 0x000008e2, 0x00000000);
+ nv_icmd(dev, 0x000008e3, 0x00000000);
+ nv_icmd(dev, 0x000008e4, 0x00000000);
+ nv_icmd(dev, 0x000008e5, 0x00000000);
+ nv_icmd(dev, 0x000008e6, 0x00000000);
+ nv_icmd(dev, 0x000008e7, 0x00000000);
+ nv_icmd(dev, 0x000008e8, 0x00000000);
+ nv_icmd(dev, 0x000008e9, 0x00000000);
+ nv_icmd(dev, 0x000008ea, 0x00000000);
+ nv_icmd(dev, 0x000008eb, 0x00000000);
+ nv_icmd(dev, 0x000008ec, 0x00000000);
+ nv_icmd(dev, 0x000008ed, 0x00000000);
+ nv_icmd(dev, 0x000008ee, 0x00000000);
+ nv_icmd(dev, 0x000008ef, 0x00000000);
+ nv_icmd(dev, 0x000008a0, 0x00000000);
+ nv_icmd(dev, 0x000008a1, 0x00000000);
+ nv_icmd(dev, 0x000008a2, 0x00000000);
+ nv_icmd(dev, 0x000008a3, 0x00000000);
+ nv_icmd(dev, 0x000008a4, 0x00000000);
+ nv_icmd(dev, 0x000008a5, 0x00000000);
+ nv_icmd(dev, 0x000008a6, 0x00000000);
+ nv_icmd(dev, 0x000008a7, 0x00000000);
+ nv_icmd(dev, 0x000008a8, 0x00000000);
+ nv_icmd(dev, 0x000008a9, 0x00000000);
+ nv_icmd(dev, 0x000008aa, 0x00000000);
+ nv_icmd(dev, 0x000008ab, 0x00000000);
+ nv_icmd(dev, 0x000008ac, 0x00000000);
+ nv_icmd(dev, 0x000008ad, 0x00000000);
+ nv_icmd(dev, 0x000008ae, 0x00000000);
+ nv_icmd(dev, 0x000008af, 0x00000000);
+ nv_icmd(dev, 0x000008f0, 0x00000000);
+ nv_icmd(dev, 0x000008f1, 0x00000000);
+ nv_icmd(dev, 0x000008f2, 0x00000000);
+ nv_icmd(dev, 0x000008f3, 0x00000000);
+ nv_icmd(dev, 0x000008f4, 0x00000000);
+ nv_icmd(dev, 0x000008f5, 0x00000000);
+ nv_icmd(dev, 0x000008f6, 0x00000000);
+ nv_icmd(dev, 0x000008f7, 0x00000000);
+ nv_icmd(dev, 0x000008f8, 0x00000000);
+ nv_icmd(dev, 0x000008f9, 0x00000000);
+ nv_icmd(dev, 0x000008fa, 0x00000000);
+ nv_icmd(dev, 0x000008fb, 0x00000000);
+ nv_icmd(dev, 0x000008fc, 0x00000000);
+ nv_icmd(dev, 0x000008fd, 0x00000000);
+ nv_icmd(dev, 0x000008fe, 0x00000000);
+ nv_icmd(dev, 0x000008ff, 0x00000000);
+ nv_icmd(dev, 0x0000094c, 0x000000ff);
+ nv_icmd(dev, 0x0000094d, 0xffffffff);
+ nv_icmd(dev, 0x0000094e, 0x00000002);
+ nv_icmd(dev, 0x000002ec, 0x00000001);
+ nv_icmd(dev, 0x00000303, 0x00000001);
+ nv_icmd(dev, 0x000002e6, 0x00000001);
+ nv_icmd(dev, 0x00000466, 0x00000052);
+ nv_icmd(dev, 0x00000301, 0x3f800000);
+ nv_icmd(dev, 0x00000304, 0x30201000);
+ nv_icmd(dev, 0x00000305, 0x70605040);
+ nv_icmd(dev, 0x00000306, 0xb8a89888);
+ nv_icmd(dev, 0x00000307, 0xf8e8d8c8);
+ nv_icmd(dev, 0x0000030a, 0x00ffff00);
+ nv_icmd(dev, 0x0000030b, 0x0000001a);
+ nv_icmd(dev, 0x0000030c, 0x00000001);
+ nv_icmd(dev, 0x00000318, 0x00000001);
+ nv_icmd(dev, 0x00000340, 0x00000000);
+ nv_icmd(dev, 0x00000375, 0x00000001);
+ nv_icmd(dev, 0x00000351, 0x00000100);
+ nv_icmd(dev, 0x0000037d, 0x00000006);
+ nv_icmd(dev, 0x000003a0, 0x00000002);
+ nv_icmd(dev, 0x000003aa, 0x00000001);
+ nv_icmd(dev, 0x000003a9, 0x00000001);
+ nv_icmd(dev, 0x00000380, 0x00000001);
+ nv_icmd(dev, 0x00000360, 0x00000040);
+ nv_icmd(dev, 0x00000366, 0x00000000);
+ nv_icmd(dev, 0x00000367, 0x00000000);
+ nv_icmd(dev, 0x00000368, 0x00001fff);
+ nv_icmd(dev, 0x00000370, 0x00000000);
+ nv_icmd(dev, 0x00000371, 0x00000000);
+ nv_icmd(dev, 0x00000372, 0x003fffff);
+ nv_icmd(dev, 0x0000037a, 0x00000012);
+ nv_icmd(dev, 0x000005e0, 0x00000022);
+ nv_icmd(dev, 0x000005e1, 0x00000022);
+ nv_icmd(dev, 0x000005e2, 0x00000022);
+ nv_icmd(dev, 0x000005e3, 0x00000022);
+ nv_icmd(dev, 0x000005e4, 0x00000022);
+ nv_icmd(dev, 0x00000619, 0x00000003);
+ nv_icmd(dev, 0x00000811, 0x00000003);
+ nv_icmd(dev, 0x00000812, 0x00000004);
+ nv_icmd(dev, 0x00000813, 0x00000006);
+ nv_icmd(dev, 0x00000814, 0x00000008);
+ nv_icmd(dev, 0x00000815, 0x0000000b);
+ nv_icmd(dev, 0x00000800, 0x00000001);
+ nv_icmd(dev, 0x00000801, 0x00000001);
+ nv_icmd(dev, 0x00000802, 0x00000001);
+ nv_icmd(dev, 0x00000803, 0x00000001);
+ nv_icmd(dev, 0x00000804, 0x00000001);
+ nv_icmd(dev, 0x00000805, 0x00000001);
+ nv_icmd(dev, 0x00000632, 0x00000001);
+ nv_icmd(dev, 0x00000633, 0x00000002);
+ nv_icmd(dev, 0x00000634, 0x00000003);
+ nv_icmd(dev, 0x00000635, 0x00000004);
+ nv_icmd(dev, 0x00000654, 0x3f800000);
+ nv_icmd(dev, 0x00000657, 0x3f800000);
+ nv_icmd(dev, 0x00000655, 0x3f800000);
+ nv_icmd(dev, 0x00000656, 0x3f800000);
+ nv_icmd(dev, 0x000006cd, 0x3f800000);
+ nv_icmd(dev, 0x000007f5, 0x3f800000);
+ nv_icmd(dev, 0x000007dc, 0x39291909);
+ nv_icmd(dev, 0x000007dd, 0x79695949);
+ nv_icmd(dev, 0x000007de, 0xb9a99989);
+ nv_icmd(dev, 0x000007df, 0xf9e9d9c9);
+ nv_icmd(dev, 0x000007e8, 0x00003210);
+ nv_icmd(dev, 0x000007e9, 0x00007654);
+ nv_icmd(dev, 0x000007ea, 0x00000098);
+ nv_icmd(dev, 0x000007ec, 0x39291909);
+ nv_icmd(dev, 0x000007ed, 0x79695949);
+ nv_icmd(dev, 0x000007ee, 0xb9a99989);
+ nv_icmd(dev, 0x000007ef, 0xf9e9d9c9);
+ nv_icmd(dev, 0x000007f0, 0x00003210);
+ nv_icmd(dev, 0x000007f1, 0x00007654);
+ nv_icmd(dev, 0x000007f2, 0x00000098);
+ nv_icmd(dev, 0x000005a5, 0x00000001);
+ nv_icmd(dev, 0x00000980, 0x00000000);
+ nv_icmd(dev, 0x00000981, 0x00000000);
+ nv_icmd(dev, 0x00000982, 0x00000000);
+ nv_icmd(dev, 0x00000983, 0x00000000);
+ nv_icmd(dev, 0x00000984, 0x00000000);
+ nv_icmd(dev, 0x00000985, 0x00000000);
+ nv_icmd(dev, 0x00000986, 0x00000000);
+ nv_icmd(dev, 0x00000987, 0x00000000);
+ nv_icmd(dev, 0x00000988, 0x00000000);
+ nv_icmd(dev, 0x00000989, 0x00000000);
+ nv_icmd(dev, 0x0000098a, 0x00000000);
+ nv_icmd(dev, 0x0000098b, 0x00000000);
+ nv_icmd(dev, 0x0000098c, 0x00000000);
+ nv_icmd(dev, 0x0000098d, 0x00000000);
+ nv_icmd(dev, 0x0000098e, 0x00000000);
+ nv_icmd(dev, 0x0000098f, 0x00000000);
+ nv_icmd(dev, 0x00000990, 0x00000000);
+ nv_icmd(dev, 0x00000991, 0x00000000);
+ nv_icmd(dev, 0x00000992, 0x00000000);
+ nv_icmd(dev, 0x00000993, 0x00000000);
+ nv_icmd(dev, 0x00000994, 0x00000000);
+ nv_icmd(dev, 0x00000995, 0x00000000);
+ nv_icmd(dev, 0x00000996, 0x00000000);
+ nv_icmd(dev, 0x00000997, 0x00000000);
+ nv_icmd(dev, 0x00000998, 0x00000000);
+ nv_icmd(dev, 0x00000999, 0x00000000);
+ nv_icmd(dev, 0x0000099a, 0x00000000);
+ nv_icmd(dev, 0x0000099b, 0x00000000);
+ nv_icmd(dev, 0x0000099c, 0x00000000);
+ nv_icmd(dev, 0x0000099d, 0x00000000);
+ nv_icmd(dev, 0x0000099e, 0x00000000);
+ nv_icmd(dev, 0x0000099f, 0x00000000);
+ nv_icmd(dev, 0x000009a0, 0x00000000);
+ nv_icmd(dev, 0x000009a1, 0x00000000);
+ nv_icmd(dev, 0x000009a2, 0x00000000);
+ nv_icmd(dev, 0x000009a3, 0x00000000);
+ nv_icmd(dev, 0x000009a4, 0x00000000);
+ nv_icmd(dev, 0x000009a5, 0x00000000);
+ nv_icmd(dev, 0x000009a6, 0x00000000);
+ nv_icmd(dev, 0x000009a7, 0x00000000);
+ nv_icmd(dev, 0x000009a8, 0x00000000);
+ nv_icmd(dev, 0x000009a9, 0x00000000);
+ nv_icmd(dev, 0x000009aa, 0x00000000);
+ nv_icmd(dev, 0x000009ab, 0x00000000);
+ nv_icmd(dev, 0x000009ac, 0x00000000);
+ nv_icmd(dev, 0x000009ad, 0x00000000);
+ nv_icmd(dev, 0x000009ae, 0x00000000);
+ nv_icmd(dev, 0x000009af, 0x00000000);
+ nv_icmd(dev, 0x000009b0, 0x00000000);
+ nv_icmd(dev, 0x000009b1, 0x00000000);
+ nv_icmd(dev, 0x000009b2, 0x00000000);
+ nv_icmd(dev, 0x000009b3, 0x00000000);
+ nv_icmd(dev, 0x000009b4, 0x00000000);
+ nv_icmd(dev, 0x000009b5, 0x00000000);
+ nv_icmd(dev, 0x000009b6, 0x00000000);
+ nv_icmd(dev, 0x000009b7, 0x00000000);
+ nv_icmd(dev, 0x000009b8, 0x00000000);
+ nv_icmd(dev, 0x000009b9, 0x00000000);
+ nv_icmd(dev, 0x000009ba, 0x00000000);
+ nv_icmd(dev, 0x000009bb, 0x00000000);
+ nv_icmd(dev, 0x000009bc, 0x00000000);
+ nv_icmd(dev, 0x000009bd, 0x00000000);
+ nv_icmd(dev, 0x000009be, 0x00000000);
+ nv_icmd(dev, 0x000009bf, 0x00000000);
+ nv_icmd(dev, 0x000009c0, 0x00000000);
+ nv_icmd(dev, 0x000009c1, 0x00000000);
+ nv_icmd(dev, 0x000009c2, 0x00000000);
+ nv_icmd(dev, 0x000009c3, 0x00000000);
+ nv_icmd(dev, 0x000009c4, 0x00000000);
+ nv_icmd(dev, 0x000009c5, 0x00000000);
+ nv_icmd(dev, 0x000009c6, 0x00000000);
+ nv_icmd(dev, 0x000009c7, 0x00000000);
+ nv_icmd(dev, 0x000009c8, 0x00000000);
+ nv_icmd(dev, 0x000009c9, 0x00000000);
+ nv_icmd(dev, 0x000009ca, 0x00000000);
+ nv_icmd(dev, 0x000009cb, 0x00000000);
+ nv_icmd(dev, 0x000009cc, 0x00000000);
+ nv_icmd(dev, 0x000009cd, 0x00000000);
+ nv_icmd(dev, 0x000009ce, 0x00000000);
+ nv_icmd(dev, 0x000009cf, 0x00000000);
+ nv_icmd(dev, 0x000009d0, 0x00000000);
+ nv_icmd(dev, 0x000009d1, 0x00000000);
+ nv_icmd(dev, 0x000009d2, 0x00000000);
+ nv_icmd(dev, 0x000009d3, 0x00000000);
+ nv_icmd(dev, 0x000009d4, 0x00000000);
+ nv_icmd(dev, 0x000009d5, 0x00000000);
+ nv_icmd(dev, 0x000009d6, 0x00000000);
+ nv_icmd(dev, 0x000009d7, 0x00000000);
+ nv_icmd(dev, 0x000009d8, 0x00000000);
+ nv_icmd(dev, 0x000009d9, 0x00000000);
+ nv_icmd(dev, 0x000009da, 0x00000000);
+ nv_icmd(dev, 0x000009db, 0x00000000);
+ nv_icmd(dev, 0x000009dc, 0x00000000);
+ nv_icmd(dev, 0x000009dd, 0x00000000);
+ nv_icmd(dev, 0x000009de, 0x00000000);
+ nv_icmd(dev, 0x000009df, 0x00000000);
+ nv_icmd(dev, 0x000009e0, 0x00000000);
+ nv_icmd(dev, 0x000009e1, 0x00000000);
+ nv_icmd(dev, 0x000009e2, 0x00000000);
+ nv_icmd(dev, 0x000009e3, 0x00000000);
+ nv_icmd(dev, 0x000009e4, 0x00000000);
+ nv_icmd(dev, 0x000009e5, 0x00000000);
+ nv_icmd(dev, 0x000009e6, 0x00000000);
+ nv_icmd(dev, 0x000009e7, 0x00000000);
+ nv_icmd(dev, 0x000009e8, 0x00000000);
+ nv_icmd(dev, 0x000009e9, 0x00000000);
+ nv_icmd(dev, 0x000009ea, 0x00000000);
+ nv_icmd(dev, 0x000009eb, 0x00000000);
+ nv_icmd(dev, 0x000009ec, 0x00000000);
+ nv_icmd(dev, 0x000009ed, 0x00000000);
+ nv_icmd(dev, 0x000009ee, 0x00000000);
+ nv_icmd(dev, 0x000009ef, 0x00000000);
+ nv_icmd(dev, 0x000009f0, 0x00000000);
+ nv_icmd(dev, 0x000009f1, 0x00000000);
+ nv_icmd(dev, 0x000009f2, 0x00000000);
+ nv_icmd(dev, 0x000009f3, 0x00000000);
+ nv_icmd(dev, 0x000009f4, 0x00000000);
+ nv_icmd(dev, 0x000009f5, 0x00000000);
+ nv_icmd(dev, 0x000009f6, 0x00000000);
+ nv_icmd(dev, 0x000009f7, 0x00000000);
+ nv_icmd(dev, 0x000009f8, 0x00000000);
+ nv_icmd(dev, 0x000009f9, 0x00000000);
+ nv_icmd(dev, 0x000009fa, 0x00000000);
+ nv_icmd(dev, 0x000009fb, 0x00000000);
+ nv_icmd(dev, 0x000009fc, 0x00000000);
+ nv_icmd(dev, 0x000009fd, 0x00000000);
+ nv_icmd(dev, 0x000009fe, 0x00000000);
+ nv_icmd(dev, 0x000009ff, 0x00000000);
+ nv_icmd(dev, 0x00000468, 0x00000004);
+ nv_icmd(dev, 0x0000046c, 0x00000001);
+ nv_icmd(dev, 0x00000470, 0x00000000);
+ nv_icmd(dev, 0x00000471, 0x00000000);
+ nv_icmd(dev, 0x00000472, 0x00000000);
+ nv_icmd(dev, 0x00000473, 0x00000000);
+ nv_icmd(dev, 0x00000474, 0x00000000);
+ nv_icmd(dev, 0x00000475, 0x00000000);
+ nv_icmd(dev, 0x00000476, 0x00000000);
+ nv_icmd(dev, 0x00000477, 0x00000000);
+ nv_icmd(dev, 0x00000478, 0x00000000);
+ nv_icmd(dev, 0x00000479, 0x00000000);
+ nv_icmd(dev, 0x0000047a, 0x00000000);
+ nv_icmd(dev, 0x0000047b, 0x00000000);
+ nv_icmd(dev, 0x0000047c, 0x00000000);
+ nv_icmd(dev, 0x0000047d, 0x00000000);
+ nv_icmd(dev, 0x0000047e, 0x00000000);
+ nv_icmd(dev, 0x0000047f, 0x00000000);
+ nv_icmd(dev, 0x00000480, 0x00000000);
+ nv_icmd(dev, 0x00000481, 0x00000000);
+ nv_icmd(dev, 0x00000482, 0x00000000);
+ nv_icmd(dev, 0x00000483, 0x00000000);
+ nv_icmd(dev, 0x00000484, 0x00000000);
+ nv_icmd(dev, 0x00000485, 0x00000000);
+ nv_icmd(dev, 0x00000486, 0x00000000);
+ nv_icmd(dev, 0x00000487, 0x00000000);
+ nv_icmd(dev, 0x00000488, 0x00000000);
+ nv_icmd(dev, 0x00000489, 0x00000000);
+ nv_icmd(dev, 0x0000048a, 0x00000000);
+ nv_icmd(dev, 0x0000048b, 0x00000000);
+ nv_icmd(dev, 0x0000048c, 0x00000000);
+ nv_icmd(dev, 0x0000048d, 0x00000000);
+ nv_icmd(dev, 0x0000048e, 0x00000000);
+ nv_icmd(dev, 0x0000048f, 0x00000000);
+ nv_icmd(dev, 0x00000490, 0x00000000);
+ nv_icmd(dev, 0x00000491, 0x00000000);
+ nv_icmd(dev, 0x00000492, 0x00000000);
+ nv_icmd(dev, 0x00000493, 0x00000000);
+ nv_icmd(dev, 0x00000494, 0x00000000);
+ nv_icmd(dev, 0x00000495, 0x00000000);
+ nv_icmd(dev, 0x00000496, 0x00000000);
+ nv_icmd(dev, 0x00000497, 0x00000000);
+ nv_icmd(dev, 0x00000498, 0x00000000);
+ nv_icmd(dev, 0x00000499, 0x00000000);
+ nv_icmd(dev, 0x0000049a, 0x00000000);
+ nv_icmd(dev, 0x0000049b, 0x00000000);
+ nv_icmd(dev, 0x0000049c, 0x00000000);
+ nv_icmd(dev, 0x0000049d, 0x00000000);
+ nv_icmd(dev, 0x0000049e, 0x00000000);
+ nv_icmd(dev, 0x0000049f, 0x00000000);
+ nv_icmd(dev, 0x000004a0, 0x00000000);
+ nv_icmd(dev, 0x000004a1, 0x00000000);
+ nv_icmd(dev, 0x000004a2, 0x00000000);
+ nv_icmd(dev, 0x000004a3, 0x00000000);
+ nv_icmd(dev, 0x000004a4, 0x00000000);
+ nv_icmd(dev, 0x000004a5, 0x00000000);
+ nv_icmd(dev, 0x000004a6, 0x00000000);
+ nv_icmd(dev, 0x000004a7, 0x00000000);
+ nv_icmd(dev, 0x000004a8, 0x00000000);
+ nv_icmd(dev, 0x000004a9, 0x00000000);
+ nv_icmd(dev, 0x000004aa, 0x00000000);
+ nv_icmd(dev, 0x000004ab, 0x00000000);
+ nv_icmd(dev, 0x000004ac, 0x00000000);
+ nv_icmd(dev, 0x000004ad, 0x00000000);
+ nv_icmd(dev, 0x000004ae, 0x00000000);
+ nv_icmd(dev, 0x000004af, 0x00000000);
+ nv_icmd(dev, 0x000004b0, 0x00000000);
+ nv_icmd(dev, 0x000004b1, 0x00000000);
+ nv_icmd(dev, 0x000004b2, 0x00000000);
+ nv_icmd(dev, 0x000004b3, 0x00000000);
+ nv_icmd(dev, 0x000004b4, 0x00000000);
+ nv_icmd(dev, 0x000004b5, 0x00000000);
+ nv_icmd(dev, 0x000004b6, 0x00000000);
+ nv_icmd(dev, 0x000004b7, 0x00000000);
+ nv_icmd(dev, 0x000004b8, 0x00000000);
+ nv_icmd(dev, 0x000004b9, 0x00000000);
+ nv_icmd(dev, 0x000004ba, 0x00000000);
+ nv_icmd(dev, 0x000004bb, 0x00000000);
+ nv_icmd(dev, 0x000004bc, 0x00000000);
+ nv_icmd(dev, 0x000004bd, 0x00000000);
+ nv_icmd(dev, 0x000004be, 0x00000000);
+ nv_icmd(dev, 0x000004bf, 0x00000000);
+ nv_icmd(dev, 0x000004c0, 0x00000000);
+ nv_icmd(dev, 0x000004c1, 0x00000000);
+ nv_icmd(dev, 0x000004c2, 0x00000000);
+ nv_icmd(dev, 0x000004c3, 0x00000000);
+ nv_icmd(dev, 0x000004c4, 0x00000000);
+ nv_icmd(dev, 0x000004c5, 0x00000000);
+ nv_icmd(dev, 0x000004c6, 0x00000000);
+ nv_icmd(dev, 0x000004c7, 0x00000000);
+ nv_icmd(dev, 0x000004c8, 0x00000000);
+ nv_icmd(dev, 0x000004c9, 0x00000000);
+ nv_icmd(dev, 0x000004ca, 0x00000000);
+ nv_icmd(dev, 0x000004cb, 0x00000000);
+ nv_icmd(dev, 0x000004cc, 0x00000000);
+ nv_icmd(dev, 0x000004cd, 0x00000000);
+ nv_icmd(dev, 0x000004ce, 0x00000000);
+ nv_icmd(dev, 0x000004cf, 0x00000000);
+ nv_icmd(dev, 0x00000510, 0x3f800000);
+ nv_icmd(dev, 0x00000511, 0x3f800000);
+ nv_icmd(dev, 0x00000512, 0x3f800000);
+ nv_icmd(dev, 0x00000513, 0x3f800000);
+ nv_icmd(dev, 0x00000514, 0x3f800000);
+ nv_icmd(dev, 0x00000515, 0x3f800000);
+ nv_icmd(dev, 0x00000516, 0x3f800000);
+ nv_icmd(dev, 0x00000517, 0x3f800000);
+ nv_icmd(dev, 0x00000518, 0x3f800000);
+ nv_icmd(dev, 0x00000519, 0x3f800000);
+ nv_icmd(dev, 0x0000051a, 0x3f800000);
+ nv_icmd(dev, 0x0000051b, 0x3f800000);
+ nv_icmd(dev, 0x0000051c, 0x3f800000);
+ nv_icmd(dev, 0x0000051d, 0x3f800000);
+ nv_icmd(dev, 0x0000051e, 0x3f800000);
+ nv_icmd(dev, 0x0000051f, 0x3f800000);
+ nv_icmd(dev, 0x00000520, 0x000002b6);
+ nv_icmd(dev, 0x00000529, 0x00000001);
+ nv_icmd(dev, 0x00000530, 0xffff0000);
+ nv_icmd(dev, 0x00000531, 0xffff0000);
+ nv_icmd(dev, 0x00000532, 0xffff0000);
+ nv_icmd(dev, 0x00000533, 0xffff0000);
+ nv_icmd(dev, 0x00000534, 0xffff0000);
+ nv_icmd(dev, 0x00000535, 0xffff0000);
+ nv_icmd(dev, 0x00000536, 0xffff0000);
+ nv_icmd(dev, 0x00000537, 0xffff0000);
+ nv_icmd(dev, 0x00000538, 0xffff0000);
+ nv_icmd(dev, 0x00000539, 0xffff0000);
+ nv_icmd(dev, 0x0000053a, 0xffff0000);
+ nv_icmd(dev, 0x0000053b, 0xffff0000);
+ nv_icmd(dev, 0x0000053c, 0xffff0000);
+ nv_icmd(dev, 0x0000053d, 0xffff0000);
+ nv_icmd(dev, 0x0000053e, 0xffff0000);
+ nv_icmd(dev, 0x0000053f, 0xffff0000);
+ nv_icmd(dev, 0x00000585, 0x0000003f);
+ nv_icmd(dev, 0x00000576, 0x00000003);
+ nv_icmd(dev, 0x00000586, 0x00000040);
+ nv_icmd(dev, 0x00000582, 0x00000080);
+ nv_icmd(dev, 0x00000583, 0x00000080);
+ nv_icmd(dev, 0x000005c2, 0x00000001);
+ nv_icmd(dev, 0x00000638, 0x00000001);
+ nv_icmd(dev, 0x00000639, 0x00000001);
+ nv_icmd(dev, 0x0000063a, 0x00000002);
+ nv_icmd(dev, 0x0000063b, 0x00000001);
+ nv_icmd(dev, 0x0000063c, 0x00000001);
+ nv_icmd(dev, 0x0000063d, 0x00000002);
+ nv_icmd(dev, 0x0000063e, 0x00000001);
+ nv_icmd(dev, 0x000008b8, 0x00000001);
+ nv_icmd(dev, 0x000008b9, 0x00000001);
+ nv_icmd(dev, 0x000008ba, 0x00000001);
+ nv_icmd(dev, 0x000008bb, 0x00000001);
+ nv_icmd(dev, 0x000008bc, 0x00000001);
+ nv_icmd(dev, 0x000008bd, 0x00000001);
+ nv_icmd(dev, 0x000008be, 0x00000001);
+ nv_icmd(dev, 0x000008bf, 0x00000001);
+ nv_icmd(dev, 0x00000900, 0x00000001);
+ nv_icmd(dev, 0x00000901, 0x00000001);
+ nv_icmd(dev, 0x00000902, 0x00000001);
+ nv_icmd(dev, 0x00000903, 0x00000001);
+ nv_icmd(dev, 0x00000904, 0x00000001);
+ nv_icmd(dev, 0x00000905, 0x00000001);
+ nv_icmd(dev, 0x00000906, 0x00000001);
+ nv_icmd(dev, 0x00000907, 0x00000001);
+ nv_icmd(dev, 0x00000908, 0x00000002);
+ nv_icmd(dev, 0x00000909, 0x00000002);
+ nv_icmd(dev, 0x0000090a, 0x00000002);
+ nv_icmd(dev, 0x0000090b, 0x00000002);
+ nv_icmd(dev, 0x0000090c, 0x00000002);
+ nv_icmd(dev, 0x0000090d, 0x00000002);
+ nv_icmd(dev, 0x0000090e, 0x00000002);
+ nv_icmd(dev, 0x0000090f, 0x00000002);
+ nv_icmd(dev, 0x00000910, 0x00000001);
+ nv_icmd(dev, 0x00000911, 0x00000001);
+ nv_icmd(dev, 0x00000912, 0x00000001);
+ nv_icmd(dev, 0x00000913, 0x00000001);
+ nv_icmd(dev, 0x00000914, 0x00000001);
+ nv_icmd(dev, 0x00000915, 0x00000001);
+ nv_icmd(dev, 0x00000916, 0x00000001);
+ nv_icmd(dev, 0x00000917, 0x00000001);
+ nv_icmd(dev, 0x00000918, 0x00000001);
+ nv_icmd(dev, 0x00000919, 0x00000001);
+ nv_icmd(dev, 0x0000091a, 0x00000001);
+ nv_icmd(dev, 0x0000091b, 0x00000001);
+ nv_icmd(dev, 0x0000091c, 0x00000001);
+ nv_icmd(dev, 0x0000091d, 0x00000001);
+ nv_icmd(dev, 0x0000091e, 0x00000001);
+ nv_icmd(dev, 0x0000091f, 0x00000001);
+ nv_icmd(dev, 0x00000920, 0x00000002);
+ nv_icmd(dev, 0x00000921, 0x00000002);
+ nv_icmd(dev, 0x00000922, 0x00000002);
+ nv_icmd(dev, 0x00000923, 0x00000002);
+ nv_icmd(dev, 0x00000924, 0x00000002);
+ nv_icmd(dev, 0x00000925, 0x00000002);
+ nv_icmd(dev, 0x00000926, 0x00000002);
+ nv_icmd(dev, 0x00000927, 0x00000002);
+ nv_icmd(dev, 0x00000928, 0x00000001);
+ nv_icmd(dev, 0x00000929, 0x00000001);
+ nv_icmd(dev, 0x0000092a, 0x00000001);
+ nv_icmd(dev, 0x0000092b, 0x00000001);
+ nv_icmd(dev, 0x0000092c, 0x00000001);
+ nv_icmd(dev, 0x0000092d, 0x00000001);
+ nv_icmd(dev, 0x0000092e, 0x00000001);
+ nv_icmd(dev, 0x0000092f, 0x00000001);
+ nv_icmd(dev, 0x00000648, 0x00000001);
+ nv_icmd(dev, 0x00000649, 0x00000001);
+ nv_icmd(dev, 0x0000064a, 0x00000001);
+ nv_icmd(dev, 0x0000064b, 0x00000001);
+ nv_icmd(dev, 0x0000064c, 0x00000001);
+ nv_icmd(dev, 0x0000064d, 0x00000001);
+ nv_icmd(dev, 0x0000064e, 0x00000001);
+ nv_icmd(dev, 0x0000064f, 0x00000001);
+ nv_icmd(dev, 0x00000650, 0x00000001);
+ nv_icmd(dev, 0x00000658, 0x0000000f);
+ nv_icmd(dev, 0x000007ff, 0x0000000a);
+ nv_icmd(dev, 0x0000066a, 0x40000000);
+ nv_icmd(dev, 0x0000066b, 0x10000000);
+ nv_icmd(dev, 0x0000066c, 0xffff0000);
+ nv_icmd(dev, 0x0000066d, 0xffff0000);
+ nv_icmd(dev, 0x000007af, 0x00000008);
+ nv_icmd(dev, 0x000007b0, 0x00000008);
+ nv_icmd(dev, 0x000007f6, 0x00000001);
+ nv_icmd(dev, 0x000006b2, 0x00000055);
+ nv_icmd(dev, 0x000007ad, 0x00000003);
+ nv_icmd(dev, 0x00000937, 0x00000001);
+ nv_icmd(dev, 0x00000971, 0x00000008);
+ nv_icmd(dev, 0x00000972, 0x00000040);
+ nv_icmd(dev, 0x00000973, 0x0000012c);
+ nv_icmd(dev, 0x0000097c, 0x00000040);
+ nv_icmd(dev, 0x00000979, 0x00000003);
+ nv_icmd(dev, 0x00000975, 0x00000020);
+ nv_icmd(dev, 0x00000976, 0x00000001);
+ nv_icmd(dev, 0x00000977, 0x00000020);
+ nv_icmd(dev, 0x00000978, 0x00000001);
+ nv_icmd(dev, 0x00000957, 0x00000003);
+ nv_icmd(dev, 0x0000095e, 0x20164010);
+ nv_icmd(dev, 0x0000095f, 0x00000020);
+ nv_icmd(dev, 0x00000683, 0x00000006);
+ nv_icmd(dev, 0x00000685, 0x003fffff);
+ nv_icmd(dev, 0x00000687, 0x00000c48);
+ nv_icmd(dev, 0x000006a0, 0x00000005);
+ nv_icmd(dev, 0x00000840, 0x00300008);
+ nv_icmd(dev, 0x00000841, 0x04000080);
+ nv_icmd(dev, 0x00000842, 0x00300008);
+ nv_icmd(dev, 0x00000843, 0x04000080);
+ nv_icmd(dev, 0x00000818, 0x00000000);
+ nv_icmd(dev, 0x00000819, 0x00000000);
+ nv_icmd(dev, 0x0000081a, 0x00000000);
+ nv_icmd(dev, 0x0000081b, 0x00000000);
+ nv_icmd(dev, 0x0000081c, 0x00000000);
+ nv_icmd(dev, 0x0000081d, 0x00000000);
+ nv_icmd(dev, 0x0000081e, 0x00000000);
+ nv_icmd(dev, 0x0000081f, 0x00000000);
+ nv_icmd(dev, 0x00000848, 0x00000000);
+ nv_icmd(dev, 0x00000849, 0x00000000);
+ nv_icmd(dev, 0x0000084a, 0x00000000);
+ nv_icmd(dev, 0x0000084b, 0x00000000);
+ nv_icmd(dev, 0x0000084c, 0x00000000);
+ nv_icmd(dev, 0x0000084d, 0x00000000);
+ nv_icmd(dev, 0x0000084e, 0x00000000);
+ nv_icmd(dev, 0x0000084f, 0x00000000);
+ nv_icmd(dev, 0x00000850, 0x00000000);
+ nv_icmd(dev, 0x00000851, 0x00000000);
+ nv_icmd(dev, 0x00000852, 0x00000000);
+ nv_icmd(dev, 0x00000853, 0x00000000);
+ nv_icmd(dev, 0x00000854, 0x00000000);
+ nv_icmd(dev, 0x00000855, 0x00000000);
+ nv_icmd(dev, 0x00000856, 0x00000000);
+ nv_icmd(dev, 0x00000857, 0x00000000);
+ nv_icmd(dev, 0x00000738, 0x00000000);
+ nv_icmd(dev, 0x000006aa, 0x00000001);
+ nv_icmd(dev, 0x000006ab, 0x00000002);
+ nv_icmd(dev, 0x000006ac, 0x00000080);
+ nv_icmd(dev, 0x000006ad, 0x00000100);
+ nv_icmd(dev, 0x000006ae, 0x00000100);
+ nv_icmd(dev, 0x000006b1, 0x00000011);
+ nv_icmd(dev, 0x000006bb, 0x000000cf);
+ nv_icmd(dev, 0x000006ce, 0x2a712488);
+ nv_icmd(dev, 0x00000739, 0x4085c000);
+ nv_icmd(dev, 0x0000073a, 0x00000080);
+ nv_icmd(dev, 0x00000786, 0x80000100);
+ nv_icmd(dev, 0x0000073c, 0x00010100);
+ nv_icmd(dev, 0x0000073d, 0x02800000);
+ nv_icmd(dev, 0x00000787, 0x000000cf);
+ nv_icmd(dev, 0x0000078c, 0x00000008);
+ nv_icmd(dev, 0x00000792, 0x00000001);
+ nv_icmd(dev, 0x00000794, 0x00000001);
+ nv_icmd(dev, 0x00000795, 0x00000001);
+ nv_icmd(dev, 0x00000796, 0x00000001);
+ nv_icmd(dev, 0x00000797, 0x000000cf);
+ nv_icmd(dev, 0x00000836, 0x00000001);
+ nv_icmd(dev, 0x0000079a, 0x00000002);
+ nv_icmd(dev, 0x00000833, 0x04444480);
+ nv_icmd(dev, 0x000007a1, 0x00000001);
+ nv_icmd(dev, 0x000007a3, 0x00000001);
+ nv_icmd(dev, 0x000007a4, 0x00000001);
+ nv_icmd(dev, 0x000007a5, 0x00000001);
+ nv_icmd(dev, 0x00000831, 0x00000004);
+ nv_icmd(dev, 0x0000080c, 0x00000002);
+ nv_icmd(dev, 0x0000080d, 0x00000100);
+ nv_icmd(dev, 0x0000080e, 0x00000100);
+ nv_icmd(dev, 0x0000080f, 0x00000001);
+ nv_icmd(dev, 0x00000823, 0x00000002);
+ nv_icmd(dev, 0x00000824, 0x00000100);
+ nv_icmd(dev, 0x00000825, 0x00000100);
+ nv_icmd(dev, 0x00000826, 0x00000001);
+ nv_icmd(dev, 0x0000095d, 0x00000001);
+ nv_icmd(dev, 0x0000082b, 0x00000004);
+ nv_icmd(dev, 0x00000942, 0x00010001);
+ nv_icmd(dev, 0x00000943, 0x00000001);
+ nv_icmd(dev, 0x00000944, 0x00000022);
+ nv_icmd(dev, 0x000007c5, 0x00010001);
+ nv_icmd(dev, 0x00000834, 0x00000001);
+ nv_icmd(dev, 0x000007c7, 0x00000001);
+ nv_icmd(dev, 0x0000c1b0, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b1, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b2, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b3, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b4, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b5, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b6, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b7, 0x0000000f);
+ nv_icmd(dev, 0x0000c1b8, 0x0fac6881);
+ nv_icmd(dev, 0x0000c1b9, 0x00fac688);
+ nv_icmd(dev, 0x0001e100, 0x00000001);
+ nv_icmd(dev, 0x00001000, 0x00000002);
+ nv_icmd(dev, 0x000006aa, 0x00000001);
+ nv_icmd(dev, 0x000006ad, 0x00000100);
+ nv_icmd(dev, 0x000006ae, 0x00000100);
+ nv_icmd(dev, 0x000006b1, 0x00000011);
+ nv_icmd(dev, 0x0000078c, 0x00000008);
+ nv_icmd(dev, 0x00000792, 0x00000001);
+ nv_icmd(dev, 0x00000794, 0x00000001);
+ nv_icmd(dev, 0x00000795, 0x00000001);
+ nv_icmd(dev, 0x00000796, 0x00000001);
+ nv_icmd(dev, 0x00000797, 0x000000cf);
+ nv_icmd(dev, 0x0000079a, 0x00000002);
+ nv_icmd(dev, 0x00000833, 0x04444480);
+ nv_icmd(dev, 0x000007a1, 0x00000001);
+ nv_icmd(dev, 0x000007a3, 0x00000001);
+ nv_icmd(dev, 0x000007a4, 0x00000001);
+ nv_icmd(dev, 0x000007a5, 0x00000001);
+ nv_icmd(dev, 0x00000831, 0x00000004);
+ nv_icmd(dev, 0x0001e100, 0x00000001);
+ nv_icmd(dev, 0x00001000, 0x00000014);
+ nv_icmd(dev, 0x00000351, 0x00000100);
+ nv_icmd(dev, 0x00000957, 0x00000003);
+ nv_icmd(dev, 0x0000095d, 0x00000001);
+ nv_icmd(dev, 0x0000082b, 0x00000004);
+ nv_icmd(dev, 0x00000942, 0x00010001);
+ nv_icmd(dev, 0x00000943, 0x00000001);
+ nv_icmd(dev, 0x000007c5, 0x00010001);
+ nv_icmd(dev, 0x00000834, 0x00000001);
+ nv_icmd(dev, 0x000007c7, 0x00000001);
+ nv_icmd(dev, 0x0001e100, 0x00000001);
+ nv_icmd(dev, 0x00001000, 0x00000001);
+ nv_icmd(dev, 0x0000080c, 0x00000002);
+ nv_icmd(dev, 0x0000080d, 0x00000100);
+ nv_icmd(dev, 0x0000080e, 0x00000100);
+ nv_icmd(dev, 0x0000080f, 0x00000001);
+ nv_icmd(dev, 0x00000823, 0x00000002);
+ nv_icmd(dev, 0x00000824, 0x00000100);
+ nv_icmd(dev, 0x00000825, 0x00000100);
+ nv_icmd(dev, 0x00000826, 0x00000001);
+ nv_icmd(dev, 0x0001e100, 0x00000001);
+ nv_wr32(dev, 0x400208, 0x00000000);
+ nv_wr32(dev, 0x404154, 0x00000400);
+
+ nvc0_grctx_generate_9097(dev);
+ nvc0_grctx_generate_902d(dev);
+ nvc0_grctx_generate_9039(dev);
+ nvc0_grctx_generate_90c0(dev);
+
+ nv_wr32(dev, 0x000260, r000260);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
index 13a0f78a9088..c09091749054 100644
--- a/drivers/gpu/drm/nouveau/nvc0_instmem.c
+++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c
@@ -25,206 +25,207 @@
#include "drmP.h"
#include "nouveau_drv.h"
+#include "nouveau_vm.h"
+
+struct nvc0_instmem_priv {
+ struct nouveau_gpuobj *bar1_pgd;
+ struct nouveau_channel *bar1;
+ struct nouveau_gpuobj *bar3_pgd;
+ struct nouveau_channel *bar3;
+ struct nouveau_gpuobj *chan_pgd;
+};
int
-nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
- uint32_t *size)
+nvc0_instmem_suspend(struct drm_device *dev)
{
- int ret;
-
- *size = ALIGN(*size, 4096);
- if (*size == 0)
- return -EINVAL;
-
- ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
- true, false, &gpuobj->im_backing);
- if (ret) {
- NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
- return ret;
- }
-
- ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
- if (ret) {
- NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
- nouveau_bo_ref(NULL, &gpuobj->im_backing);
- return ret;
- }
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
- gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
+ dev_priv->ramin_available = false;
return 0;
}
void
-nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+nvc0_instmem_resume(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv;
- if (gpuobj && gpuobj->im_backing) {
- if (gpuobj->im_bound)
- dev_priv->engine.instmem.unbind(dev, gpuobj);
- nouveau_bo_unpin(gpuobj->im_backing);
- nouveau_bo_ref(NULL, &gpuobj->im_backing);
- gpuobj->im_backing = NULL;
- }
+ nv_mask(dev, 0x100c80, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12);
+ nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12);
+ dev_priv->ramin_available = true;
}
-int
-nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+static void
+nvc0_channel_del(struct nouveau_channel **pchan)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t pte, pte_end;
- uint64_t vram;
-
- if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
- return -EINVAL;
-
- NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
- gpuobj->im_pramin->start, gpuobj->im_pramin->size);
+ struct nouveau_channel *chan;
+
+ chan = *pchan;
+ *pchan = NULL;
+ if (!chan)
+ return;
+
+ nouveau_vm_ref(NULL, &chan->vm, NULL);
+ if (chan->ramin_heap.free_stack.next)
+ drm_mm_takedown(&chan->ramin_heap);
+ nouveau_gpuobj_ref(NULL, &chan->ramin);
+ kfree(chan);
+}
- pte = gpuobj->im_pramin->start >> 12;
- pte_end = (gpuobj->im_pramin->size >> 12) + pte;
- vram = gpuobj->vinst;
+static int
+nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm,
+ struct nouveau_channel **pchan,
+ struct nouveau_gpuobj *pgd, u64 vm_size)
+{
+ struct nouveau_channel *chan;
+ int ret;
- NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
- gpuobj->im_pramin->start, pte, pte_end);
- NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+ chan->dev = dev;
- while (pte < pte_end) {
- nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
- nv_wr32(dev, 0x702004 + (pte * 8), 0);
- vram += 4096;
- pte++;
+ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
+ if (ret) {
+ nvc0_channel_del(&chan);
+ return ret;
}
- dev_priv->engine.instmem.flush(dev);
- if (1) {
- u32 chan = nv_rd32(dev, 0x1700) << 16;
- nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8);
- nv_wr32(dev, 0x100cbc, 0x80000005);
+ ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000);
+ if (ret) {
+ nvc0_channel_del(&chan);
+ return ret;
}
- gpuobj->im_bound = 1;
- return 0;
-}
-
-int
-nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t pte, pte_end;
-
- if (gpuobj->im_bound == 0)
- return -EINVAL;
-
- pte = gpuobj->im_pramin->start >> 12;
- pte_end = (gpuobj->im_pramin->size >> 12) + pte;
- while (pte < pte_end) {
- nv_wr32(dev, 0x702000 + (pte * 8), 0);
- nv_wr32(dev, 0x702004 + (pte * 8), 0);
- pte++;
+ ret = nouveau_vm_ref(vm, &chan->vm, NULL);
+ if (ret) {
+ nvc0_channel_del(&chan);
+ return ret;
}
- dev_priv->engine.instmem.flush(dev);
- gpuobj->im_bound = 0;
- return 0;
-}
+ nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst));
+ nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst));
+ nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1));
+ nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1));
-void
-nvc0_instmem_flush(struct drm_device *dev)
-{
- nv_wr32(dev, 0x070000, 1);
- if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
- NV_ERROR(dev, "PRAMIN flush timeout\n");
+ *pchan = chan;
+ return 0;
}
int
-nvc0_instmem_suspend(struct drm_device *dev)
+nvc0_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- u32 *buf;
- int i;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct pci_dev *pdev = dev->pdev;
+ struct nvc0_instmem_priv *priv;
+ struct nouveau_vm *vm = NULL;
+ int ret;
- dev_priv->susres.ramin_copy = vmalloc(65536);
- if (!dev_priv->susres.ramin_copy)
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- buf = dev_priv->susres.ramin_copy;
-
- for (i = 0; i < 65536; i += 4)
- buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i);
+ pinstmem->priv = priv;
+
+ /* BAR3 VM */
+ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0,
+ &dev_priv->bar3_vm);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL,
+ (pci_resource_len(pdev, 3) >> 12) * 8, 0,
+ NVOBJ_FLAG_DONT_MAP |
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->bar3_vm->pgt[0].obj[0]);
+ if (ret)
+ goto error;
+ dev_priv->bar3_vm->pgt[0].refcount[0] = 1;
+
+ nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]);
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd);
+ if (ret)
+ goto error;
+ nouveau_vm_ref(NULL, &vm, NULL);
+
+ ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3,
+ priv->bar3_pgd, pci_resource_len(dev->pdev, 3));
+ if (ret)
+ goto error;
+
+ /* BAR1 VM */
+ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd);
+ if (ret)
+ goto error;
+ nouveau_vm_ref(NULL, &vm, NULL);
+
+ ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1,
+ priv->bar1_pgd, pci_resource_len(dev->pdev, 1));
+ if (ret)
+ goto error;
+
+ /* channel vm */
+ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd);
+ if (ret)
+ goto error;
+
+ nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd);
+ nouveau_vm_ref(NULL, &vm, NULL);
+
+ nvc0_instmem_resume(dev);
return 0;
+error:
+ nvc0_instmem_takedown(dev);
+ return ret;
}
void
-nvc0_instmem_resume(struct drm_device *dev)
+nvc0_instmem_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- u32 *buf = dev_priv->susres.ramin_copy;
- u64 chan;
- int i;
+ struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv;
+ struct nouveau_vm *vm = NULL;
- chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
- nv_wr32(dev, 0x001700, chan >> 16);
+ nvc0_instmem_suspend(dev);
- for (i = 0; i < 65536; i += 4)
- nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]);
- vfree(dev_priv->susres.ramin_copy);
- dev_priv->susres.ramin_copy = NULL;
+ nv_wr32(dev, 0x1704, 0x00000000);
+ nv_wr32(dev, 0x1714, 0x00000000);
- nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
-}
+ nouveau_vm_ref(NULL, &dev_priv->chan_vm, priv->chan_pgd);
+ nouveau_gpuobj_ref(NULL, &priv->chan_pgd);
-int
-nvc0_instmem_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1;
- int ret, i;
-
- dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024;
- chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
- imem = 4096 + 4096 + 32768;
-
- nv_wr32(dev, 0x001700, chan >> 16);
-
- /* channel setup */
- nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000));
- nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000));
- nv_wr32(dev, 0x700208, lower_32_bits(lim3));
- nv_wr32(dev, 0x70020c, upper_32_bits(lim3));
-
- /* point pgd -> pgt */
- nv_wr32(dev, 0x701000, 0);
- nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1);
-
- /* point pgt -> physical vram for channel */
- pgt3 = 0x2000;
- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) {
- nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1);
- nv_wr32(dev, 0x700004 + pgt3, 0);
- }
-
- /* clear rest of pgt */
- for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) {
- nv_wr32(dev, 0x700000 + pgt3, 0);
- nv_wr32(dev, 0x700004 + pgt3, 0);
- }
-
- /* point bar3 at the channel */
- nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
-
- /* Global PRAMIN heap */
- ret = drm_mm_init(&dev_priv->ramin_heap, imem,
- dev_priv->ramin_size - imem);
- if (ret) {
- NV_ERROR(dev, "Failed to init RAMIN heap\n");
- return -ENOMEM;
- }
+ nvc0_channel_del(&priv->bar1);
+ nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd);
+ nouveau_gpuobj_ref(NULL, &priv->bar1_pgd);
- return 0;
-}
+ nvc0_channel_del(&priv->bar3);
+ nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL);
+ nouveau_vm_ref(NULL, &vm, priv->bar3_pgd);
+ nouveau_gpuobj_ref(NULL, &priv->bar3_pgd);
+ nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]);
+ nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL);
-void
-nvc0_instmem_takedown(struct drm_device *dev)
-{
+ dev_priv->engine.instmem.priv = NULL;
+ kfree(priv);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c
new file mode 100644
index 000000000000..e4e83c2caf5b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_vm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_vm.h"
+
+void
+nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index,
+ struct nouveau_gpuobj *pgt[2])
+{
+ u32 pde[2] = { 0, 0 };
+
+ if (pgt[0])
+ pde[1] = 0x00000001 | (pgt[0]->vinst >> 8);
+ if (pgt[1])
+ pde[0] = 0x00000001 | (pgt[1]->vinst >> 8);
+
+ nv_wo32(pgd, (index * 8) + 0, pde[0]);
+ nv_wo32(pgd, (index * 8) + 4, pde[1]);
+}
+
+static inline u64
+nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
+{
+ phys >>= 8;
+
+ phys |= 0x00000001; /* present */
+ if (vma->access & NV_MEM_ACCESS_SYS)
+ phys |= 0x00000002;
+
+ phys |= ((u64)target << 32);
+ phys |= ((u64)memtype << 36);
+
+ return phys;
+}
+
+void
+nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys)
+{
+ u32 next = 1 << (vma->node->type - 8);
+
+ phys = nvc0_vm_addr(vma, phys, mem->memtype, 0);
+ pte <<= 3;
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ phys += next;
+ pte += 8;
+ }
+}
+
+void
+nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ u32 pte, dma_addr_t *list, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ u64 phys = nvc0_vm_addr(vma, *list++, 0, 5);
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ pte += 8;
+ }
+}
+
+void
+nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, 0x00000000);
+ nv_wo32(pgt, pte + 4, 0x00000000);
+ pte += 8;
+ }
+}
+
+void
+nvc0_vm_flush(struct nouveau_vm *vm)
+{
+ struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct drm_device *dev = vm->dev;
+ struct nouveau_vm_pgd *vpgd;
+ u32 r100c80, engine;
+
+ pinstmem->flush(vm->dev);
+
+ if (vm == dev_priv->chan_vm)
+ engine = 1;
+ else
+ engine = 5;
+
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ r100c80 = nv_rd32(dev, 0x100c80);
+ nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8);
+ nv_wr32(dev, 0x100cbc, 0x80000000 | engine);
+ if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80))
+ NV_ERROR(dev, "vm flush timeout eng %d\n", engine);
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c
new file mode 100644
index 000000000000..858eda5dedd1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_vram.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+
+bool
+nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags)
+{
+ switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) {
+ case 0x0000:
+ case 0xfe00:
+ case 0xdb00:
+ case 0x1100:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+int
+nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin,
+ u32 type, struct nouveau_vram **pvram)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
+ struct nouveau_mm *mm = man->priv;
+ struct nouveau_mm_node *r;
+ struct nouveau_vram *vram;
+ int ret;
+
+ size >>= 12;
+ align >>= 12;
+ ncmin >>= 12;
+
+ vram = kzalloc(sizeof(*vram), GFP_KERNEL);
+ if (!vram)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&vram->regions);
+ vram->dev = dev_priv->dev;
+ vram->memtype = type;
+ vram->size = size;
+
+ mutex_lock(&mm->mutex);
+ do {
+ ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r);
+ if (ret) {
+ mutex_unlock(&mm->mutex);
+ nv50_vram_del(dev, &vram);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &vram->regions);
+ size -= r->length;
+ } while (size);
+ mutex_unlock(&mm->mutex);
+
+ r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry);
+ vram->offset = (u64)r->offset << 12;
+ *pvram = vram;
+ return 0;
+}
+
+int
+nvc0_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20;
+ dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
+ dev_priv->vram_rblock_size = 4096;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index 881f8a585613..fe0f253089ac 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -153,7 +153,8 @@
#define NV_PCRTC_START 0x00600800
#define NV_PCRTC_CONFIG 0x00600804
# define NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA (1 << 0)
-# define NV_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0)
+# define NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC (4 << 0)
+# define NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0)
#define NV_PCRTC_CURSOR_CONFIG 0x00600810
# define NV_PCRTC_CURSOR_CONFIG_ENABLE_ENABLE (1 << 0)
# define NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE (1 << 4)
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 6cae4f2028d2..e47eecfc2df4 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -65,10 +65,13 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
- evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o
+ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
+ radeon_trace_points.o ni.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
radeon-$(CONFIG_ACPI) += radeon_acpi.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o
+
+CFLAGS_radeon_trace_points.o := -I$(src) \ No newline at end of file
diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h
index c714179d1bfa..c61c3fe9fb98 100644
--- a/drivers/gpu/drm/radeon/ObjectID.h
+++ b/drivers/gpu/drm/radeon/ObjectID.h
@@ -37,6 +37,8 @@
#define GRAPH_OBJECT_TYPE_CONNECTOR 0x3
#define GRAPH_OBJECT_TYPE_ROUTER 0x4
/* deleted */
+#define GRAPH_OBJECT_TYPE_DISPLAY_PATH 0x6
+#define GRAPH_OBJECT_TYPE_GENERIC 0x7
/****************************************************/
/* Encoder Object ID Definition */
@@ -64,6 +66,9 @@
#define ENCODER_OBJECT_ID_VT1623 0x10
#define ENCODER_OBJECT_ID_HDMI_SI1930 0x11
#define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12
+#define ENCODER_OBJECT_ID_ALMOND 0x22
+#define ENCODER_OBJECT_ID_TRAVIS 0x23
+#define ENCODER_OBJECT_ID_NUTMEG 0x22
/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */
#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13
#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14
@@ -108,6 +113,7 @@
#define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13
#define CONNECTOR_OBJECT_ID_eDP 0x14
#define CONNECTOR_OBJECT_ID_MXM 0x15
+#define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16
/* deleted */
@@ -124,6 +130,7 @@
#define GENERIC_OBJECT_ID_GLSYNC 0x01
#define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02
#define GENERIC_OBJECT_ID_MXM_OPM 0x03
+#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin
/****************************************************/
/* Graphics Object ENUM ID Definition */
@@ -360,6 +367,26 @@
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT)
+#define ENCODER_ALMOND_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT)
+
+#define ENCODER_ALMOND_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT)
+
+#define ENCODER_TRAVIS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT)
+
+#define ENCODER_TRAVIS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT)
+
+#define ENCODER_NUTMEG_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_NUTMEG << OBJECT_ID_SHIFT)
+
/****************************************************/
/* Connector Object ID definition - Shared with BIOS */
/****************************************************/
@@ -421,6 +448,14 @@
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
@@ -512,6 +547,7 @@
#define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT)
+
#define CONNECTOR_7PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT)
@@ -593,6 +629,14 @@
GRAPH_OBJECT_ENUM_ID7 << ENUM_ID_SHIFT |\
CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DAC
+#define CONNECTOR_LVDS_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_LVDS_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT)
+
/****************************************************/
/* Router Object ID definition - Shared with BIOS */
/****************************************************/
@@ -621,6 +665,10 @@
GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
GENERIC_OBJECT_ID_MXM_OPM << OBJECT_ID_SHIFT)
+#define GENERICOBJECT_STEREO_PIN_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT)
+
/****************************************************/
/* Object Cap definition - Shared with BIOS */
/****************************************************/
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index 8e421f644a54..258fa5e7a2d9 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -112,6 +112,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
base += 3;
break;
case ATOM_IIO_WRITE:
+ (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
base += 3;
break;
@@ -733,16 +734,16 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
{
uint8_t attr = U8((*ptr)++);
- uint32_t dst, src1, src2, saved;
+ uint32_t dst, mask, src, saved;
int dptr = *ptr;
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
- SDEBUG(" src1: ");
- src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
- SDEBUG(" src2: ");
- src2 = atom_get_src(ctx, attr, ptr);
- dst &= src1;
- dst |= src2;
+ mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
+ SDEBUG(" mask: 0x%08x", mask);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst &= mask;
+ dst |= src;
SDEBUG(" dst: ");
atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
}
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index fe359a239df3..04b269d14a59 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -73,8 +73,18 @@
#define ATOM_PPLL1 0
#define ATOM_PPLL2 1
#define ATOM_DCPLL 2
+#define ATOM_PPLL0 2
+#define ATOM_EXT_PLL1 8
+#define ATOM_EXT_PLL2 9
+#define ATOM_EXT_CLOCK 10
#define ATOM_PPLL_INVALID 0xFF
+#define ENCODER_REFCLK_SRC_P1PLL 0
+#define ENCODER_REFCLK_SRC_P2PLL 1
+#define ENCODER_REFCLK_SRC_DCPLL 2
+#define ENCODER_REFCLK_SRC_EXTCLK 3
+#define ENCODER_REFCLK_SRC_INVALID 0xFF
+
#define ATOM_SCALER1 0
#define ATOM_SCALER2 1
@@ -192,6 +202,9 @@ typedef struct _ATOM_COMMON_TABLE_HEADER
/*Image can't be updated, while Driver needs to carry the new table! */
}ATOM_COMMON_TABLE_HEADER;
+/****************************************************************************/
+// Structure stores the ROM header.
+/****************************************************************************/
typedef struct _ATOM_ROM_HEADER
{
ATOM_COMMON_TABLE_HEADER sHeader;
@@ -221,6 +234,9 @@ typedef struct _ATOM_ROM_HEADER
#define USHORT void*
#endif
+/****************************************************************************/
+// Structures used in Command.mtb
+/****************************************************************************/
typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1
USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON
@@ -312,6 +328,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange
#define HPDInterruptService ReadHWAssistedI2CStatus
#define EnableVGA_Access GetSCLKOverMCLKRatio
+#define GetDispObjectInfo EnableYUV
typedef struct _ATOM_MASTER_COMMAND_TABLE
{
@@ -357,6 +374,24 @@ typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER
/****************************************************************************/
#define COMPUTE_MEMORY_PLL_PARAM 1
#define COMPUTE_ENGINE_PLL_PARAM 2
+#define ADJUST_MC_SETTING_PARAM 3
+
+/****************************************************************************/
+// Structures used by AdjustMemoryControllerTable
+/****************************************************************************/
+typedef struct _ATOM_ADJUST_MEMORY_CLOCK_FREQ
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block
+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0]
+ ULONG ulClockFreq:24;
+#else
+ ULONG ulClockFreq:24;
+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0]
+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block
+#endif
+}ATOM_ADJUST_MEMORY_CLOCK_FREQ;
+#define POINTER_RETURN_FLAG 0x80
typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
{
@@ -440,6 +475,26 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
#endif
}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
+{
+ union
+ {
+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
+ };
+ UCHAR ucRefDiv; //Output Parameter
+ UCHAR ucPostDiv; //Output Parameter
+ union
+ {
+ UCHAR ucCntlFlag; //Output Flags
+ UCHAR ucInputFlag; //Input Flags. ucInputFlag[0] - Strobe(1)/Performance(0) mode
+ };
+ UCHAR ucReserved;
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5;
+
+// ucInputFlag
+#define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN 1 // 1-StrobeMode, 0-PerformanceMode
+
typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
{
ATOM_COMPUTE_CLOCK_FREQ ulClock;
@@ -583,6 +638,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS
#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01
#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00
#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_5_40GHZ 0x02
#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04
#define ATOM_ENCODER_CONFIG_LINKA 0x00
#define ATOM_ENCODER_CONFIG_LINKB 0x04
@@ -608,6 +664,9 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS
#define ATOM_ENCODER_MODE_TV 13
#define ATOM_ENCODER_MODE_CV 14
#define ATOM_ENCODER_MODE_CRT 15
+#define ATOM_ENCODER_MODE_DVO 16
+#define ATOM_ENCODER_MODE_DP_SST ATOM_ENCODER_MODE_DP // For DP1.2
+#define ATOM_ENCODER_MODE_DP_MST 5 // For DP1.2
typedef struct _ATOM_DIG_ENCODER_CONFIG_V2
{
@@ -661,6 +720,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08
#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09
#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3 0x13
#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b
#define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c
#define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d
@@ -671,24 +731,34 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
#define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10
#define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00
+//ucTableFormatRevision=1
+//ucTableContentRevision=3
// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver
typedef struct _ATOM_DIG_ENCODER_CONFIG_V3
{
#if ATOM_BIG_ENDIAN
UCHAR ucReserved1:1;
- UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F)
UCHAR ucReserved:3;
UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
#else
UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
UCHAR ucReserved:3;
- UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F)
UCHAR ucReserved1:1;
#endif
}ATOM_DIG_ENCODER_CONFIG_V3;
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01
#define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70
-
+#define ATOM_ENCODER_CONFIG_V3_DIG0_ENCODER 0x00
+#define ATOM_ENCODER_CONFIG_V3_DIG1_ENCODER 0x10
+#define ATOM_ENCODER_CONFIG_V3_DIG2_ENCODER 0x20
+#define ATOM_ENCODER_CONFIG_V3_DIG3_ENCODER 0x30
+#define ATOM_ENCODER_CONFIG_V3_DIG4_ENCODER 0x40
+#define ATOM_ENCODER_CONFIG_V3_DIG5_ENCODER 0x50
typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
{
@@ -707,6 +777,56 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
UCHAR ucReserved;
}DIG_ENCODER_CONTROL_PARAMETERS_V3;
+//ucTableFormatRevision=1
+//ucTableContentRevision=4
+// start from NI
+// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V4
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReserved1:1;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F)
+ UCHAR ucReserved:2;
+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version
+#else
+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version
+ UCHAR ucReserved:2;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F)
+ UCHAR ucReserved1:1;
+#endif
+}ATOM_DIG_ENCODER_CONFIG_V4;
+
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_MASK 0x03
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ 0x02
+#define ATOM_ENCODER_CONFIG_V4_ENCODER_SEL 0x70
+#define ATOM_ENCODER_CONFIG_V4_DIG0_ENCODER 0x00
+#define ATOM_ENCODER_CONFIG_V4_DIG1_ENCODER 0x10
+#define ATOM_ENCODER_CONFIG_V4_DIG2_ENCODER 0x20
+#define ATOM_ENCODER_CONFIG_V4_DIG3_ENCODER 0x30
+#define ATOM_ENCODER_CONFIG_V4_DIG4_ENCODER 0x40
+#define ATOM_ENCODER_CONFIG_V4_DIG5_ENCODER 0x50
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ union{
+ ATOM_DIG_ENCODER_CONFIG_V4 acConfig;
+ UCHAR ucConfig;
+ };
+ UCHAR ucAction;
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ // =5: DP audio
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
+ UCHAR ucHPD_ID; // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version
+}DIG_ENCODER_CONTROL_PARAMETERS_V4;
// define ucBitPerColor:
#define PANEL_BPC_UNDEFINE 0x00
@@ -893,6 +1013,7 @@ typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V3
#endif
}ATOM_DIG_TRANSMITTER_CONFIG_V3;
+
typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3
{
union
@@ -936,6 +1057,149 @@ typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3
#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD
#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF
+
+/****************************************************************************/
+// Structures used by UNIPHYTransmitterControlTable V1.4
+// ASIC Families: NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=4
+/****************************************************************************/
+typedef struct _ATOM_DP_VS_MODE_V4
+{
+ UCHAR ucLaneSel;
+ union
+ {
+ UCHAR ucLaneSet;
+ struct {
+#if ATOM_BIG_ENDIAN
+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4
+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level
+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level
+#else
+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level
+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level
+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4
+#endif
+ };
+ };
+}ATOM_DP_VS_MODE_V4;
+
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V4
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+#else
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V4;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V4
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE_V4 asMode; // DP Voltage swing mode Redefined comparing to previous version
+ };
+ union
+ {
+ ATOM_DIG_TRANSMITTER_CONFIG_V4 acConfig;
+ UCHAR ucConfig;
+ };
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucLaneNum;
+ UCHAR ucReserved[3];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V4;
+
+//ucConfig
+//Bit0
+#define ATOM_TRANSMITTER_CONFIG_V4_DUAL_LINK_CONNECTOR 0x01
+//Bit1
+#define ATOM_TRANSMITTER_CONFIG_V4_COHERENT 0x02
+//Bit2
+#define ATOM_TRANSMITTER_CONFIG_V4_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_V4_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_LINKB 0x04
+// Bit3
+#define ATOM_TRANSMITTER_CONFIG_V4_ENCODER_SEL_MASK 0x08
+#define ATOM_TRANSMITTER_CONFIG_V4_DIG1_ENCODER 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_DIG2_ENCODER 0x08
+// Bit5:4
+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SEL_MASK 0x30
+#define ATOM_TRANSMITTER_CONFIG_V4_P1PLL 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_P2PLL 0x10
+#define ATOM_TRANSMITTER_CONFIG_V4_DCPLL 0x20 // New in _V4
+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SRC_EXT 0x30 // Changed comparing to V3
+// Bit7:6
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER_SEL_MASK 0xC0
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER3 0x80 //EF
+
+
+/****************************************************************************/
+// Structures used by ExternalEncoderControlTable V1.3
+// ASIC Families: Evergreen, Llano, NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=3
+/****************************************************************************/
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3
+{
+ union{
+ USHORT usPixelClock; // pixel clock in 10Khz, valid when ucAction=SETUP/ENABLE_OUTPUT
+ USHORT usConnectorId; // connector id, valid when ucAction = INIT
+ };
+ UCHAR ucConfig; // indicate which encoder, and DP link rate when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucAction; //
+ UCHAR ucEncoderMode; // encoder mode, only used when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucLaneNum; // lane number, only used when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucBitPerColor; // output bit per color, only valid when ucAction = SETUP/ENABLE_OUTPUT and ucEncodeMode= DP
+ UCHAR ucReserved;
+}EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3;
+
+// ucAction
+#define EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT 0x00
+#define EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT 0x01
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT 0x07
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP 0x0f
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF 0x10
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING 0x11
+#define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION 0x12
+
+// ucConfig
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ 0x02
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER_SEL_MASK 0x70
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER1 0x00
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER2 0x10
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER3 0x20
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3
+{
+ EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 sExtEncoder;
+ ULONG ulReserved[2];
+}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3;
+
+
/****************************************************************************/
// Structures used by DAC1OuputControlTable
// DAC2OuputControlTable
@@ -1142,6 +1406,7 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V2
#define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10
#define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20
+
typedef struct _PIXEL_CLOCK_PARAMETERS_V3
{
USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
@@ -1202,6 +1467,55 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V5
#define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08
#define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10
+typedef struct _CRTC_PIXEL_CLOCK_FREQ
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing.
+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version.
+#else
+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing.
+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version.
+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+#endif
+}CRTC_PIXEL_CLOCK_FREQ;
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V6
+{
+ union{
+ CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; // pixel clock and CRTC id frequency
+ ULONG ulDispEngClkFreq; // dispclk frequency
+ };
+ USHORT usFbDiv; // feedback divider integer part.
+ UCHAR ucPostDiv; // post divider.
+ UCHAR ucRefDiv; // Reference divider
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL
+ UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h,
+ // indicate which graphic encoder will be used.
+ UCHAR ucEncoderMode; // Encoder mode:
+ UCHAR ucMiscInfo; // bit[0]= Force program PPLL
+ // bit[1]= when VGA timing is used.
+ // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp
+ // bit[4]= RefClock source for PPLL.
+ // =0: XTLAIN( default mode )
+ // =1: other external clock source, which is pre-defined
+ // by VBIOS depend on the feature required.
+ // bit[7:5]: reserved.
+ ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 )
+
+}PIXEL_CLOCK_PARAMETERS_V6;
+
+#define PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL 0x01
+#define PIXEL_CLOCK_V6_MISC_VGA_MODE 0x02
+#define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK 0x0c
+#define PIXEL_CLOCK_V6_MISC_HDMI_24BPP 0x00
+#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP 0x04
+#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP 0x08
+#define PIXEL_CLOCK_V6_MISC_HDMI_48BPP 0x0c
+#define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC 0x10
+
typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
{
PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput;
@@ -1241,10 +1555,11 @@ typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS
typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3
{
USHORT usPixelClock; // target pixel clock
- UCHAR ucTransmitterID; // transmitter id defined in objectid.h
+ UCHAR ucTransmitterID; // GPU transmitter id defined in objectid.h
UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI
UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX
- UCHAR ucReserved[3];
+ UCHAR ucExtTransmitterID; // external encoder id.
+ UCHAR ucReserved[2];
}ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3;
// usDispPllConfig v1.2 for RoadRunner
@@ -1314,7 +1629,7 @@ typedef struct _GET_ENGINE_CLOCK_PARAMETERS
typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
{
USHORT usPrescale; //Ratio between Engine clock and I2C clock
- USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID
+ USHORT usVRAMAddress; //Address in Frame Buffer where to pace raw EDID
USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status
//WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte
UCHAR ucSlaveAddr; //Read from which slave
@@ -1358,6 +1673,7 @@ typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS
/**************************************************************************/
#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
/****************************************************************************/
// Structures used by PowerConnectorDetectionTable
/****************************************************************************/
@@ -1438,6 +1754,31 @@ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2
#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00
#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8
+// Used by DCE5.0
+ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3
+{
+ USHORT usSpreadSpectrumAmountFrac; // SS_AMOUNT_DSFRAC New in DCE5.0
+ UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread.
+ // Bit[1]: 1-Ext. 0-Int.
+ // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL
+ // Bits[7:4] reserved
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8]
+ USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3;
+
+#define ATOM_PPLL_SS_TYPE_V3_DOWN_SPREAD 0x00
+#define ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD 0x01
+#define ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD 0x02
+#define ATOM_PPLL_SS_TYPE_V3_PPLL_SEL_MASK 0x0c
+#define ATOM_PPLL_SS_TYPE_V3_P1PLL 0x00
+#define ATOM_PPLL_SS_TYPE_V3_P2PLL 0x04
+#define ATOM_PPLL_SS_TYPE_V3_DCPLL 0x08
+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK 0x00FF
+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT 0
+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK 0x0F00
+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT 8
+
#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL
/**************************************************************************/
@@ -1706,7 +2047,7 @@ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES
USHORT StandardVESA_Timing; // Only used by Bios
USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4
USHORT DAC_Info; // Will be obsolete from R600
- USHORT LVDS_Info; // Shared by various SW components,latest version 1.1
+ USHORT LCD_Info; // Shared by various SW components,latest version 1.3, was called LVDS_Info
USHORT TMDS_Info; // Will be obsolete from R600
USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1
USHORT SupportedDevicesInfo; // Will be obsolete from R600
@@ -1736,12 +2077,16 @@ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES
USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1
}ATOM_MASTER_LIST_OF_DATA_TABLES;
+// For backward compatible
+#define LVDS_Info LCD_Info
+
typedef struct _ATOM_MASTER_DATA_TABLE
{
ATOM_COMMON_TABLE_HEADER sHeader;
ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables;
}ATOM_MASTER_DATA_TABLE;
+
/****************************************************************************/
// Structure used in MultimediaCapabilityInfoTable
/****************************************************************************/
@@ -1776,6 +2121,7 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO
UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
}ATOM_MULTIMEDIA_CONFIG_INFO;
+
/****************************************************************************/
// Structures used in FirmwareInfoTable
/****************************************************************************/
@@ -2031,8 +2377,47 @@ typedef struct _ATOM_FIRMWARE_INFO_V2_1
UCHAR ucReserved4[3];
}ATOM_FIRMWARE_INFO_V2_1;
+//the structure below to be used from NI
+//ucTableFormatRevision=2
+//ucTableContentRevision=2
+typedef struct _ATOM_FIRMWARE_INFO_V2_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulReserved[2];
+ ULONG ulReserved1; //Was ulMaxEngineClockPLL_Output; //In 10Khz unit*
+ ULONG ulReserved2; //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit*
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock ?
+ ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit. This is the frequency before DCDTO, corresponding to usBootUpVDDCVoltage.
+ UCHAR ucReserved3; //Was ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ulReserved4; //Was ulAsicMaximumVoltage
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulReserved5; //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input
+ ULONG ulReserved6; //Was usMinEngineClockPLL_Output and usMinMemoryClockPLL_Input
+ ULONG ulReserved7; //Was usMaxMemoryClockPLL_Input and usMinMemoryClockPLL_Output
+ USHORT usReserved11; //Was usMaxPixelClock; //In 10Khz unit, Max. Pclk used only for DAC
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usBootUpVDDCIVoltage; //In unit of mv; Was usMinPixelClockPLL_Output;
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usCoreReferenceClock; //In 10Khz unit
+ USHORT usMemoryReferenceClock; //In 10Khz unit
+ USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+ UCHAR ucReserved9[3];
+ USHORT usBootUpMVDDCVoltage; //In unit of mv; Was usMinPixelClockPLL_Output;
+ USHORT usReserved12;
+ ULONG ulReserved10[3]; // New added comparing to previous version
+}ATOM_FIRMWARE_INFO_V2_2;
-#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_1
+#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_2
/****************************************************************************/
// Structures used in IntegratedSystemInfoTable
@@ -2212,7 +2597,7 @@ ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pi
ucDockingPinBit: which bit in this register to read the pin status;
ucDockingPinPolarity:Polarity of the pin when docked;
-ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0
+ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, [7:0]=4:Pharaoh, other bits reserved for now and must be 0x0
usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%.
@@ -2250,6 +2635,14 @@ usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to rep
usMinDownStreamHTLinkWidth: same as above.
*/
+// ATOM_INTEGRATED_SYSTEM_INFO::ulCPUCapInfo - CPU type definition
+#define INTEGRATED_SYSTEM_INFO__UNKNOWN_CPU 0
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GRIFFIN 1
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GREYHOUND 2
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__K8 3
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH 4
+
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH // this deff reflects max defined CPU code
#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001
#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002
@@ -2778,8 +3171,88 @@ typedef struct _ATOM_LVDS_INFO_V12
#define PANEL_RANDOM_DITHER 0x80
#define PANEL_RANDOM_DITHER_MASK 0x80
+#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 // no need to change this
+
+/****************************************************************************/
+// Structures used by LCD_InfoTable V1.3 Note: previous version was called ATOM_LVDS_INFO_V12
+// ASIC Families: NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=3
+/****************************************************************************/
+typedef struct _ATOM_LCD_INFO_V13
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usExtInfoTableOffset;
+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec.
+ ULONG ulReserved0;
+ UCHAR ucLCD_Misc; // Reorganized in V13
+ // Bit0: {=0:single, =1:dual},
+ // Bit1: {=0:LDI format for RGB888, =1 FPDI format for RGB888} // was {=0:666RGB, =1:888RGB},
+ // Bit3:2: {Grey level}
+ // Bit6:4 Color Bit Depth definition (see below definition in EDID V1.4 @BYTE 14h)
+ // Bit7 Reserved. was for ATOM_PANEL_MISC_API_ENABLED, still need it?
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+ USHORT usLCDVenderID;
+ USHORT usLCDProductID;
+ UCHAR ucLCDPanel_SpecialHandlingCap; // Reorganized in V13
+ // Bit0: Once DAL sees this CAP is set, it will read EDID from LCD on its own
+ // Bit1: See LCDPANEL_CAP_DRR_SUPPORTED
+ // Bit2: a quick reference whether an embadded panel (LCD1 ) is LVDS (0) or eDP (1)
+ // Bit7-3: Reserved
+ UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable
+ USHORT usBacklightPWM; // Backlight PWM in Hz. New in _V13
+
+ UCHAR ucPowerSequenceDIGONtoDE_in4Ms;
+ UCHAR ucPowerSequenceDEtoVARY_BL_in4Ms;
+ UCHAR ucPowerSequenceDEtoDIGON_in4Ms;
+ UCHAR ucPowerSequenceVARY_BLtoDE_in4Ms;
+
+ UCHAR ucOffDelay_in4Ms;
+ UCHAR ucPowerSequenceVARY_BLtoBLON_in4Ms;
+ UCHAR ucPowerSequenceBLONtoVARY_BL_in4Ms;
+ UCHAR ucReserved1;
+
+ ULONG ulReserved[4];
+}ATOM_LCD_INFO_V13;
+
+#define ATOM_LCD_INFO_LAST ATOM_LCD_INFO_V13
+
+//Definitions for ucLCD_Misc
+#define ATOM_PANEL_MISC_V13_DUAL 0x00000001
+#define ATOM_PANEL_MISC_V13_FPDI 0x00000002
+#define ATOM_PANEL_MISC_V13_GREY_LEVEL 0x0000000C
+#define ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT 2
+#define ATOM_PANEL_MISC_V13_COLOR_BIT_DEPTH_MASK 0x70
+#define ATOM_PANEL_MISC_V13_6BIT_PER_COLOR 0x10
+#define ATOM_PANEL_MISC_V13_8BIT_PER_COLOR 0x20
+
+//Color Bit Depth definition in EDID V1.4 @BYTE 14h
+//Bit 6 5 4
+ // 0 0 0 - Color bit depth is undefined
+ // 0 0 1 - 6 Bits per Primary Color
+ // 0 1 0 - 8 Bits per Primary Color
+ // 0 1 1 - 10 Bits per Primary Color
+ // 1 0 0 - 12 Bits per Primary Color
+ // 1 0 1 - 14 Bits per Primary Color
+ // 1 1 0 - 16 Bits per Primary Color
+ // 1 1 1 - Reserved
+
+//Definitions for ucLCDPanel_SpecialHandlingCap:
+
+//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12.
+//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL
+#define LCDPANEL_CAP_V13_READ_EDID 0x1 // = LCDPANEL_CAP_READ_EDID no change comparing to previous version
+
+//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together
+//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static
+//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12
+#define LCDPANEL_CAP_V13_DRR_SUPPORTED 0x2 // = LCDPANEL_CAP_DRR_SUPPORTED no change comparing to previous version
-#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12
+//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP.
+#define LCDPANEL_CAP_V13_eDP 0x4 // = LCDPANEL_CAP_eDP no change comparing to previous version
typedef struct _ATOM_PATCH_RECORD_MODE
{
@@ -2944,9 +3417,9 @@ typedef struct _ATOM_DPCD_INFO
#define MAX_DTD_MODE_IN_VRAM 6
#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT)
#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT)
-#define DFP_ENCODER_TYPE_OFFSET 0x80
-#define DP_ENCODER_LANE_NUM_OFFSET 0x84
-#define DP_ENCODER_LINK_RATE_OFFSET 0x88
+//20 bytes for Encoder Type and DPCD in STD EDID area
+#define DFP_ENCODER_TYPE_OFFSET (ATOM_EDID_RAW_DATASIZE + ATOM_DTD_MODE_SUPPORT_TBL_SIZE + ATOM_STD_MODE_SUPPORT_TBL_SIZE - 20)
+#define ATOM_DP_DPCD_OFFSET (DFP_ENCODER_TYPE_OFFSET + 4 )
#define ATOM_HWICON1_SURFACE_ADDR 0
#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE)
@@ -2997,14 +3470,16 @@ typedef struct _ATOM_DPCD_INFO
#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256)
-#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512
+#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 1024)
+#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START + 512
//The size below is in Kb!
#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC)
+#define ATOM_VRAM_RESERVE_V2_SIZE 32
+
#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L
#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30
#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1
@@ -3206,6 +3681,15 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH
USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
}ATOM_DISPLAY_OBJECT_PATH;
+typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH
+{
+ USHORT usDeviceTag; //supported device
+ USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
+ USHORT usConnObjectId; //Connector Object ID
+ USHORT usGPUObjectId; //GPU ID
+ USHORT usGraphicObjIds[2]; //usGraphicObjIds[0]= GPU internal encoder, usGraphicObjIds[1]= external encoder
+}ATOM_DISPLAY_EXTERNAL_OBJECT_PATH;
+
typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE
{
UCHAR ucNumOfDispPath;
@@ -3261,6 +3745,47 @@ typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset
#define EXT_AUXDDC_LUTINDEX_7 7
#define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1)
+//ucChannelMapping are defined as following
+//for DP connector, eDP, DP to VGA/LVDS
+//Bit[1:0]: Define which pin connect to DP connector DP_Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[3:2]: Define which pin connect to DP connector DP_Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[5:4]: Define which pin connect to DP connector DP_Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[7:6]: Define which pin connect to DP connector DP_Lane3, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+typedef struct _ATOM_DP_CONN_CHANNEL_MAPPING
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucDP_Lane3_Source:2;
+ UCHAR ucDP_Lane2_Source:2;
+ UCHAR ucDP_Lane1_Source:2;
+ UCHAR ucDP_Lane0_Source:2;
+#else
+ UCHAR ucDP_Lane0_Source:2;
+ UCHAR ucDP_Lane1_Source:2;
+ UCHAR ucDP_Lane2_Source:2;
+ UCHAR ucDP_Lane3_Source:2;
+#endif
+}ATOM_DP_CONN_CHANNEL_MAPPING;
+
+//for DVI/HDMI, in dual link case, both links have to have same mapping.
+//Bit[1:0]: Define which pin connect to DVI connector data Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[3:2]: Define which pin connect to DVI connector data Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[5:4]: Define which pin connect to DVI connector data Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[7:6]: Define which pin connect to DVI connector clock lane, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+typedef struct _ATOM_DVI_CONN_CHANNEL_MAPPING
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucDVI_CLK_Source:2;
+ UCHAR ucDVI_DATA0_Source:2;
+ UCHAR ucDVI_DATA1_Source:2;
+ UCHAR ucDVI_DATA2_Source:2;
+#else
+ UCHAR ucDVI_DATA2_Source:2;
+ UCHAR ucDVI_DATA1_Source:2;
+ UCHAR ucDVI_DATA0_Source:2;
+ UCHAR ucDVI_CLK_Source:2;
+#endif
+}ATOM_DVI_CONN_CHANNEL_MAPPING;
+
typedef struct _EXT_DISPLAY_PATH
{
USHORT usDeviceTag; //A bit vector to show what devices are supported
@@ -3269,7 +3794,13 @@ typedef struct _EXT_DISPLAY_PATH
UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT
UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT
USHORT usExtEncoderObjId; //external encoder object id
- USHORT usReserved[3];
+ union{
+ UCHAR ucChannelMapping; // if ucChannelMapping=0, using default one to one mapping
+ ATOM_DP_CONN_CHANNEL_MAPPING asDPMapping;
+ ATOM_DVI_CONN_CHANNEL_MAPPING asDVIMapping;
+ };
+ UCHAR ucReserved;
+ USHORT usReserved[2];
}EXT_DISPLAY_PATH;
#define NUMBER_OF_UCHAR_FOR_GUID 16
@@ -3281,7 +3812,8 @@ typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string
EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0.
- UCHAR Reserved [7]; // for potential expansion
+ UCHAR uc3DStereoPinId; // use for eDP panel
+ UCHAR Reserved [6]; // for potential expansion
}ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
//Related definitions, all records are differnt but they have a commond header
@@ -3311,10 +3843,11 @@ typedef struct _ATOM_COMMON_RECORD_HEADER
#define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table
#define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record
#define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19
+#define ATOM_ENCODER_CAP_RECORD_TYPE 20
//Must be updated when new record type is added,equal to that record definition!
-#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE
+#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_ENCODER_CAP_RECORD_TYPE
typedef struct _ATOM_I2C_RECORD
{
@@ -3441,6 +3974,26 @@ typedef struct _ATOM_ENCODER_DVO_CF_RECORD
UCHAR ucPadding[2];
}ATOM_ENCODER_DVO_CF_RECORD;
+// Bit maps for ATOM_ENCODER_CAP_RECORD.ucEncoderCap
+#define ATOM_ENCODER_CAP_RECORD_HBR2 0x01 // DP1.2 HBR2 is supported by this path
+
+typedef struct _ATOM_ENCODER_CAP_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ union {
+ USHORT usEncoderCap;
+ struct {
+#if ATOM_BIG_ENDIAN
+ USHORT usReserved:15; // Bit1-15 may be defined for other capability in future
+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability.
+#else
+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability.
+ USHORT usReserved:15; // Bit1-15 may be defined for other capability in future
+#endif
+ };
+ };
+}ATOM_ENCODER_CAP_RECORD;
+
// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle
#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1
#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2
@@ -3580,6 +4133,11 @@ typedef struct _ATOM_VOLTAGE_CONTROL
#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI
#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage
#define VOLTAGE_CONTROL_ID_DS4402 0x04
+#define VOLTAGE_CONTROL_ID_UP6266 0x05
+#define VOLTAGE_CONTROL_ID_SCORPIO 0x06
+#define VOLTAGE_CONTROL_ID_VT1556M 0x07
+#define VOLTAGE_CONTROL_ID_CHL822x 0x08
+#define VOLTAGE_CONTROL_ID_VT1586M 0x09
typedef struct _ATOM_VOLTAGE_OBJECT
{
@@ -3670,66 +4228,157 @@ typedef struct _ATOM_POWER_SOURCE_INFO
#define POWER_SENSOR_GPIO 0x01
#define POWER_SENSOR_I2C 0x02
+typedef struct _ATOM_CLK_VOLT_CAPABILITY
+{
+ ULONG ulVoltageIndex; // The Voltage Index indicated by FUSE, same voltage index shared with SCLK DPM fuse table
+ ULONG ulMaximumSupportedCLK; // Maximum clock supported with specified voltage index, unit in 10kHz
+}ATOM_CLK_VOLT_CAPABILITY;
+
+typedef struct _ATOM_AVAILABLE_SCLK_LIST
+{
+ ULONG ulSupportedSCLK; // Maximum clock supported with specified voltage index, unit in 10kHz
+ USHORT usVoltageIndex; // The Voltage Index indicated by FUSE for specified SCLK
+ USHORT usVoltageID; // The Voltage ID indicated by FUSE for specified SCLK
+}ATOM_AVAILABLE_SCLK_LIST;
+
+// ATOM_INTEGRATED_SYSTEM_INFO_V6 ulSystemConfig cap definition
+#define ATOM_IGP_INFO_V6_SYSTEM_CONFIG__PCIE_POWER_GATING_ENABLE 1 // refer to ulSystemConfig bit[0]
+
+// this IntegrateSystemInfoTable is used for Liano/Ontario APU
typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
{
ATOM_COMMON_TABLE_HEADER sHeader;
ULONG ulBootUpEngineClock;
ULONG ulDentistVCOFreq;
ULONG ulBootUpUMAClock;
- ULONG ulReserved1[8];
+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4];
ULONG ulBootUpReqDisplayVector;
ULONG ulOtherDisplayMisc;
ULONG ulGPUCapInfo;
- ULONG ulReserved2[3];
+ ULONG ulSB_MMIO_Base_Addr;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulMinEngineClock;
ULONG ulSystemConfig;
ULONG ulCPUCapInfo;
- USHORT usMaxNBVoltage;
- USHORT usMinNBVoltage;
- USHORT usBootUpNBVoltage;
- USHORT usExtDispConnInfoOffset;
- UCHAR ucHtcTmpLmt;
- UCHAR ucTjOffset;
+ USHORT usNBP0Voltage;
+ USHORT usNBP1Voltage;
+ USHORT usBootUpNBVoltage;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
UCHAR ucMemoryType;
UCHAR ucUMAChannelNumber;
ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];
ULONG ulCSR_M3_ARB_CNTL_UVD[10];
ULONG ulCSR_M3_ARB_CNTL_FS3D[10];
- ULONG ulReserved3[42];
+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5];
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulMinimumNClk;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG ulReserved3[21];
ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
}ATOM_INTEGRATED_SYSTEM_INFO_V6;
+// ulGPUCapInfo
+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01
+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__DISABLE_AUX_HW_MODE_DETECTION 0x08
+
+// ulOtherDisplayMisc
+#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT 0x01
+
+
/**********************************************************************************************************************
-// ATOM_INTEGRATED_SYSTEM_INFO_V6 Description
-//ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit.
-//ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
-//ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
-//ulReserved1[8] Reserved by now, must be 0x0.
-//ulBootUpReqDisplayVector VBIOS boot up display IDs
-// ATOM_DEVICE_CRT1_SUPPORT 0x0001
-// ATOM_DEVICE_CRT2_SUPPORT 0x0010
-// ATOM_DEVICE_DFP1_SUPPORT 0x0008
-// ATOM_DEVICE_DFP6_SUPPORT 0x0040
-// ATOM_DEVICE_DFP2_SUPPORT 0x0080
-// ATOM_DEVICE_DFP3_SUPPORT 0x0200
-// ATOM_DEVICE_DFP4_SUPPORT 0x0400
-// ATOM_DEVICE_DFP5_SUPPORT 0x0800
-// ATOM_DEVICE_LCD1_SUPPORT 0x0002
-//ulOtherDisplayMisc Other display related flags, not defined yet.
-//ulGPUCapInfo TBD
-//ulReserved2[3] must be 0x0 for the reserved.
-//ulSystemConfig TBD
-//ulCPUCapInfo TBD
-//usMaxNBVoltage High NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse.
-//usMinNBVoltage Low NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse.
-//usBootUpNBVoltage Boot up NB voltage in unit of mv.
-//ucHtcTmpLmt Bit [22:16] of D24F3x64 Thermal Control (HTC) Register.
-//ucTjOffset Bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed.
-//ucMemoryType [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
-//ucUMAChannelNumber System memory channel numbers.
-//usExtDispConnectionInfoOffset ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO offset relative to beginning of this table.
-//ulCSR_M3_ARB_CNTL_DEFAULT[10] Arrays with values for CSR M3 arbiter for default
-//ulCSR_M3_ARB_CNTL_UVD[10] Arrays with values for CSR M3 arbiter for UVD playback.
-//ulCSR_M3_ARB_CNTL_FS3D[10] Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+ ATOM_INTEGRATED_SYSTEM_INFO_V6 Description
+ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
+ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
+sDISPCLK_Voltage: Report Display clock voltage requirement.
+
+ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Liano/Ontaio projects:
+ ATOM_DEVICE_CRT1_SUPPORT 0x0001
+ ATOM_DEVICE_CRT2_SUPPORT 0x0010
+ ATOM_DEVICE_DFP1_SUPPORT 0x0008
+ ATOM_DEVICE_DFP6_SUPPORT 0x0040
+ ATOM_DEVICE_DFP2_SUPPORT 0x0080
+ ATOM_DEVICE_DFP3_SUPPORT 0x0200
+ ATOM_DEVICE_DFP4_SUPPORT 0x0400
+ ATOM_DEVICE_DFP5_SUPPORT 0x0800
+ ATOM_DEVICE_LCD1_SUPPORT 0x0002
+ulOtherDisplayMisc: Other display related flags, not defined yet.
+ulGPUCapInfo: bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode.
+ =1: TMDS/HDMI Coherent Mode use signel PLL mode.
+ bit[3]=0: Enable HW AUX mode detection logic
+ =1: Disable HW AUX mode dettion logic
+ulSB_MMIO_Base_Addr: Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage.
+
+usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW).
+ Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+
+ When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+ 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+ VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+ Changing BL using VBIOS function is functional in both driver and non-driver present environment;
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+ that BL control from GPU is expected.
+ VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+ Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+ it's per platform
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt.
+ Threshold on value to enter HTC_active state.
+ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt.
+ To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+ulMinEngineClock: Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings.
+ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled
+ =1: PCIE Power Gating Enabled
+ Bit[1]=0: DDR-DLL shut-down feature disabled.
+ 1: DDR-DLL shut-down feature enabled.
+ Bit[2]=0: DDR-PLL Power down feature disabled.
+ 1: DDR-PLL Power down feature enabled.
+ulCPUCapInfo: TBD
+usNBP0Voltage: VID for voltage on NB P0 State
+usNBP1Voltage: VID for voltage on NB P1 State
+usBootUpNBVoltage: Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement.
+usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+ to indicate a range.
+ SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
+ SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
+ SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
+ SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
+ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
+ucUMAChannelNumber: System memory channel numbers.
+ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default
+ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback.
+ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high
+ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns.
+ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz.
+ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns.
+usPCIEClkSSPercentage: PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType: PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting.
+usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
**********************************************************************************************************************/
/**************************************************************************/
@@ -3790,6 +4439,7 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT
#define ASIC_INTERNAL_SS_ON_LVDS 6
#define ASIC_INTERNAL_SS_ON_DP 7
#define ASIC_INTERNAL_SS_ON_DCPLL 8
+#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9
typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
{
@@ -3903,6 +4553,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LIT2AC 4
//Byte aligned defintion for BIOS usage
#define ATOM_S0_CRT1_MONOb0 0x01
@@ -4529,7 +5180,8 @@ typedef struct _ATOM_INIT_REG_BLOCK{
#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1)
#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1)
#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1)
-
+//#define ACCESS_MCIODEBUGIND 0x40 //defined in BIOS code
+#define ACCESS_PLACEHOLDER 0x80
typedef struct _ATOM_MC_INIT_PARAM_TABLE
{
@@ -4554,6 +5206,10 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
#define _32Mx32 0x33
#define _64Mx8 0x41
#define _64Mx16 0x42
+#define _64Mx32 0x43
+#define _128Mx8 0x51
+#define _128Mx16 0x52
+#define _256Mx8 0x61
#define SAMSUNG 0x1
#define INFINEON 0x2
@@ -4569,10 +5225,11 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
#define QIMONDA INFINEON
#define PROMOS MOSEL
#define KRETON INFINEON
+#define ELIXIR NANYA
/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
-#define UCODE_ROM_START_ADDRESS 0x1c000
+#define UCODE_ROM_START_ADDRESS 0x1b800
#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode
//uCode block header for reference
@@ -4903,7 +5560,34 @@ typedef struct _ATOM_VRAM_MODULE_V6
ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
}ATOM_VRAM_MODULE_V6;
-
+typedef struct _ATOM_VRAM_MODULE_V7
+{
+// Design Specific Values
+ ULONG ulChannelMapCfg; // mmMC_SHARED_CHREMAP
+ USHORT usModuleSize; // Size of ATOM_VRAM_MODULE_V7
+ USHORT usPrivateReserved; // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // Current memory module ID
+ UCHAR ucMemoryType; // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5
+ UCHAR ucChannelNum; // Number of mem. channels supported in this module
+ UCHAR ucChannelWidth; // CHANNEL_16BIT/CHANNEL_32BIT/CHANNEL_64BIT
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucReserve; // Former container for Mx_FLAGS like DBI_AC_MODE_ENABLE_ASIC for GDDR4. Not used now.
+ UCHAR ucMisc; // RANK_OF_THISMEMORY etc.
+ UCHAR ucVREFI; // Not used.
+ UCHAR ucNPL_RT; // Round trip delay (MC_SEQ_CAS_TIMING [28:24]:TCL=CL+NPL_RT-2). Always 2.
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+// Memory Module specific values
+ USHORT usEMRS2Value; // EMRS2/MR2 Value.
+ USHORT usEMRS3Value; // EMRS3/MR3 Value.
+ UCHAR ucMemoryVenderID; // [7:4] Revision, [3:0] Vendor code
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth can be detected during vendor detection, here is hardcoded per memory
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ char strMemPNString[20]; // part number end with '0'.
+}ATOM_VRAM_MODULE_V7;
typedef struct _ATOM_VRAM_INFO_V2
{
@@ -4942,6 +5626,20 @@ typedef struct _ATOM_VRAM_INFO_V4
// ATOM_INIT_REG_BLOCK aMemAdjust;
}ATOM_VRAM_INFO_V4;
+typedef struct _ATOM_VRAM_INFO_HEADER_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usReserved[4];
+ UCHAR ucNumOfVRAMModule; // indicate number of VRAM module
+ UCHAR ucMemoryClkPatchTblVer; // version of memory AC timing register list
+ UCHAR ucVramModuleVer; // indicate ATOM_VRAM_MODUE version
+ UCHAR ucReserved;
+ ATOM_VRAM_MODULE_V7 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+}ATOM_VRAM_INFO_HEADER_V2_1;
+
+
typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO
{
ATOM_COMMON_TABLE_HEADER sHeader;
@@ -5182,6 +5880,16 @@ typedef struct _ASIC_TRANSMITTER_INFO
UCHAR ucReserved;
}ASIC_TRANSMITTER_INFO;
+#define ASIC_TRANSMITTER_INFO_CONFIG__DVO_SDR_MODE 0x01
+#define ASIC_TRANSMITTER_INFO_CONFIG__COHERENT_MODE 0x02
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODEROBJ_ID_MASK 0xc4
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_A 0x00
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_B 0x04
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_C 0x40
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_D 0x44
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_E 0x80
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_F 0x84
+
typedef struct _ASIC_ENCODER_INFO
{
UCHAR ucEncoderID;
@@ -5284,6 +5992,28 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS
/* /obselete */
#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+typedef struct _DP_ENCODER_SERVICE_PARAMETERS_V2
+{
+ USHORT usExtEncoderObjId; // External Encoder Object Id, output parameter only, use when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION
+ UCHAR ucAuxId;
+ UCHAR ucAction;
+ UCHAR ucSinkType; // Iput and Output parameters.
+ UCHAR ucHPDId; // Input parameter, used when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION
+ UCHAR ucReserved[2];
+}DP_ENCODER_SERVICE_PARAMETERS_V2;
+
+typedef struct _DP_ENCODER_SERVICE_PS_ALLOCATION_V2
+{
+ DP_ENCODER_SERVICE_PARAMETERS_V2 asDPServiceParam;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 asAuxParam;
+}DP_ENCODER_SERVICE_PS_ALLOCATION_V2;
+
+// ucAction
+#define DP_SERVICE_V2_ACTION_GET_SINK_TYPE 0x01
+#define DP_SERVICE_V2_ACTION_DET_LCD_CONNECTION 0x02
+
+
// DP_TRAINING_TABLE
#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR
#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 )
@@ -5339,6 +6069,7 @@ typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2
#define SELECT_DCIO_IMPCAL 4
#define SELECT_DCIO_DIG 6
#define SELECT_CRTC_PIXEL_RATE 7
+#define SELECT_VGA_BLK 8
/****************************************************************************/
//Portion VI: Definitinos for vbios MC scratch registers that driver used
@@ -5744,7 +6475,17 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER
#define ATOM_PP_THERMALCONTROLLER_ADT7473 9
#define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11
#define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12
+#define ATOM_PP_THERMALCONTROLLER_EMC2103 13 /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen.
+#define ATOM_PP_THERMALCONTROLLER_SUMO 14 /* 0x0E */ // Sumo type, used internally
+#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15
+
+// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
+// We probably should reserve the bit 0x80 for this use.
+// To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
+// The driver can pick the correct internal controller based on the ASIC.
+
#define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller
+#define ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D // EMC2103 Fan Control + Internal Thermal Controller
typedef struct _ATOM_PPLIB_STATE
{
@@ -5841,6 +6582,29 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3
USHORT usExtendendedHeaderOffset;
} ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3;
+typedef struct _ATOM_PPLIB_POWERPLAYTABLE4
+{
+ ATOM_PPLIB_POWERPLAYTABLE3 basicTable3;
+ ULONG ulGoldenPPID; // PPGen use only
+ ULONG ulGoldenRevision; // PPGen use only
+ USHORT usVddcDependencyOnSCLKOffset;
+ USHORT usVddciDependencyOnMCLKOffset;
+ USHORT usVddcDependencyOnMCLKOffset;
+ USHORT usMaxClockVoltageOnDCOffset;
+ USHORT usReserved[2];
+} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4;
+
+typedef struct _ATOM_PPLIB_POWERPLAYTABLE5
+{
+ ATOM_PPLIB_POWERPLAYTABLE4 basicTable4;
+ ULONG ulTDPLimit;
+ ULONG ulNearTDPLimit;
+ ULONG ulSQRampingThreshold;
+ USHORT usCACLeakageTableOffset; // Points to ATOM_PPLIB_CAC_Leakage_Table
+ ULONG ulCACLeakage; // TBD, this parameter is still under discussion. Change to ulReserved if not needed.
+ ULONG ulReserved;
+} ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5;
+
//// ATOM_PPLIB_NONCLOCK_INFO::usClassification
#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007
#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0
@@ -5864,6 +6628,10 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3
#define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000
#define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000
+//// ATOM_PPLIB_NONCLOCK_INFO::usClassification2
+#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
+#define ATOM_PPLIB_CLASSIFICATION2_ULV 0x0002
+
//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings
#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001
#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002
@@ -5896,9 +6664,21 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3
#define ATOM_PPLIB_M3ARB_MASK 0x00060000
#define ATOM_PPLIB_M3ARB_SHIFT 17
+#define ATOM_PPLIB_ENABLE_DRR 0x00080000
+
+// remaining 16 bits are reserved
+typedef struct _ATOM_PPLIB_THERMAL_STATE
+{
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucThermalAction;
+}ATOM_PPLIB_THERMAL_STATE, *LPATOM_PPLIB_THERMAL_STATE;
+
// Contained in an array starting at the offset
// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset.
// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex
+#define ATOM_PPLIB_NONCLOCKINFO_VER1 12
+#define ATOM_PPLIB_NONCLOCKINFO_VER2 24
typedef struct _ATOM_PPLIB_NONCLOCK_INFO
{
USHORT usClassification;
@@ -5906,15 +6686,15 @@ typedef struct _ATOM_PPLIB_NONCLOCK_INFO
UCHAR ucMaxTemperature;
ULONG ulCapsAndSettings;
UCHAR ucRequiredPower;
- UCHAR ucUnused1[3];
+ USHORT usClassification2;
+ ULONG ulVCLK;
+ ULONG ulDCLK;
+ UCHAR ucUnused[5];
} ATOM_PPLIB_NONCLOCK_INFO;
// Contained in an array starting at the offset
// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset.
// referenced from ATOM_PPLIB_STATE::ucClockStateIndices
-#define ATOM_PPLIB_NONCLOCKINFO_VER1 12
-#define ATOM_PPLIB_NONCLOCKINFO_VER2 24
-
typedef struct _ATOM_PPLIB_R600_CLOCK_INFO
{
USHORT usEngineClockLow;
@@ -5985,6 +6765,93 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1
#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2
+typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{
+ USHORT usEngineClockLow; //clockfrequency & 0xFFFF. The unit is in 10khz
+ UCHAR ucEngineClockHigh; //clockfrequency >> 16.
+ UCHAR vddcIndex; //2-bit vddc index;
+ UCHAR leakage; //please use 8-bit absolute value, not the 6-bit % value
+ //please initalize to 0
+ UCHAR rsv;
+ //please initalize to 0
+ USHORT rsv1;
+ //please initialize to 0s
+ ULONG rsv2[2];
+}ATOM_PPLIB_SUMO_CLOCK_INFO;
+
+
+
+typedef struct _ATOM_PPLIB_STATE_V2
+{
+ //number of valid dpm levels in this state; Driver uses it to calculate the whole
+ //size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR)
+ UCHAR ucNumDPMLevels;
+
+ //a index to the array of nonClockInfos
+ UCHAR nonClockInfoIndex;
+ /**
+ * Driver will read the first ucNumDPMLevels in this array
+ */
+ UCHAR clockInfoIndex[1];
+} ATOM_PPLIB_STATE_V2;
+
+typedef struct StateArray{
+ //how many states we have
+ UCHAR ucNumEntries;
+
+ ATOM_PPLIB_STATE_V2 states[1];
+}StateArray;
+
+
+typedef struct ClockInfoArray{
+ //how many clock levels we have
+ UCHAR ucNumEntries;
+
+ //sizeof(ATOM_PPLIB_SUMO_CLOCK_INFO)
+ UCHAR ucEntrySize;
+
+ //this is for Sumo
+ ATOM_PPLIB_SUMO_CLOCK_INFO clockInfo[1];
+}ClockInfoArray;
+
+typedef struct NonClockInfoArray{
+
+ //how many non-clock levels we have. normally should be same as number of states
+ UCHAR ucNumEntries;
+ //sizeof(ATOM_PPLIB_NONCLOCK_INFO)
+ UCHAR ucEntrySize;
+
+ ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1];
+}NonClockInfoArray;
+
+typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record
+{
+ USHORT usClockLow;
+ UCHAR ucClockHigh;
+ USHORT usVoltage;
+}ATOM_PPLIB_Clock_Voltage_Dependency_Record;
+
+typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Table
+{
+ UCHAR ucNumEntries; // Number of entries.
+ ATOM_PPLIB_Clock_Voltage_Dependency_Record entries[1]; // Dynamically allocate entries.
+}ATOM_PPLIB_Clock_Voltage_Dependency_Table;
+
+typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Record
+{
+ USHORT usSclkLow;
+ UCHAR ucSclkHigh;
+ USHORT usMclkLow;
+ UCHAR ucMclkHigh;
+ USHORT usVddc;
+ USHORT usVddci;
+}ATOM_PPLIB_Clock_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table
+{
+ UCHAR ucNumEntries; // Number of entries.
+ ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1]; // Dynamically allocate entries.
+}ATOM_PPLIB_Clock_Voltage_Limit_Table;
+
/**************************************************************************/
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index df2b6f2b35f8..b0ab185b86f6 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -253,7 +253,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
- atombios_blank_crtc(crtc, ATOM_ENABLE);
+ if (radeon_crtc->enabled)
+ atombios_blank_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
atombios_enable_crtc(crtc, ATOM_DISABLE);
@@ -402,6 +403,7 @@ union atom_enable_ss {
ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
};
static void atombios_crtc_program_ss(struct drm_crtc *crtc,
@@ -416,7 +418,30 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
memset(&args, 0, sizeof(args));
- if (ASIC_IS_DCE4(rdev)) {
+ if (ASIC_IS_DCE5(rdev)) {
+ args.v3.usSpreadSpectrumAmountFrac = 0;
+ args.v3.ucSpreadSpectrumType = ss->type;
+ switch (pll_id) {
+ case ATOM_PPLL1:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
+ args.v3.usSpreadSpectrumAmount = ss->amount;
+ args.v3.usSpreadSpectrumStep = ss->step;
+ break;
+ case ATOM_PPLL2:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
+ args.v3.usSpreadSpectrumAmount = ss->amount;
+ args.v3.usSpreadSpectrumStep = ss->step;
+ break;
+ case ATOM_DCPLL:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
+ args.v3.usSpreadSpectrumAmount = 0;
+ args.v3.usSpreadSpectrumStep = 0;
+ break;
+ case ATOM_PPLL_INVALID:
+ return;
+ }
+ args.v2.ucEnable = enable;
+ } else if (ASIC_IS_DCE4(rdev)) {
args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
args.v2.ucSpreadSpectrumType = ss->type;
switch (pll_id) {
@@ -530,7 +555,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
dp_clock = dig_connector->dp_clock;
}
}
-
+#if 0 /* doesn't work properly on some laptops */
/* use recommended ref_div for ss */
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (ss_enabled) {
@@ -540,7 +565,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
}
}
}
-
+#endif
if (ASIC_IS_AVIVO(rdev)) {
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
@@ -672,9 +697,14 @@ union set_pixel_clock {
PIXEL_CLOCK_PARAMETERS_V2 v2;
PIXEL_CLOCK_PARAMETERS_V3 v3;
PIXEL_CLOCK_PARAMETERS_V5 v5;
+ PIXEL_CLOCK_PARAMETERS_V6 v6;
};
-static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
+/* on DCE5, make sure the voltage is high enough to support the
+ * required disp clk.
+ */
+static void atombios_crtc_set_dcpll(struct drm_crtc *crtc,
+ u32 dispclk)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -697,9 +727,16 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
* SetPixelClock provides the dividers
*/
args.v5.ucCRTC = ATOM_CRTC_INVALID;
- args.v5.usPixelClock = rdev->clock.default_dispclk;
+ args.v5.usPixelClock = dispclk;
args.v5.ucPpll = ATOM_DCPLL;
break;
+ case 6:
+ /* if the default dcpll clock is specified,
+ * SetPixelClock provides the dividers
+ */
+ args.v6.ulDispEngClkFreq = dispclk;
+ args.v6.ucPpll = ATOM_DCPLL;
+ break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return;
@@ -783,6 +820,18 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
args.v5.ucEncoderMode = encoder_mode;
args.v5.ucPpll = pll_id;
break;
+ case 6:
+ args.v6.ulCrtcPclkFreq.ucCRTC = crtc_id;
+ args.v6.ulCrtcPclkFreq.ulPixelClock = cpu_to_le32(clock / 10);
+ args.v6.ucRefDiv = ref_div;
+ args.v6.usFbDiv = cpu_to_le16(fb_div);
+ args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
+ args.v6.ucPostDiv = post_div;
+ args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
+ args.v6.ucTransmitterID = encoder_id;
+ args.v6.ucEncoderMode = encoder_mode;
+ args.v6.ucPpll = pll_id;
+ break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return;
@@ -1376,7 +1425,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
rdev->clock.default_dispclk);
if (ss_enabled)
atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss);
- atombios_crtc_set_dcpll(crtc);
+ /* XXX: DCE5, make sure voltage, dispclk is high enough */
+ atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk);
if (ss_enabled)
atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss);
}
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index f12a5b3ec050..a8973acb3987 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -39,6 +39,62 @@
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
+static void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+
+void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ u32 tmp;
+
+ /* make sure flip is at vb rather than hb */
+ tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset);
+ tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN;
+ WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp);
+
+ /* set pageflip to happen anywhere in vblank interval */
+ WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
+
+ /* enable the pflip int */
+ radeon_irq_kms_pflip_irq_get(rdev, crtc);
+}
+
+void evergreen_post_page_flip(struct radeon_device *rdev, int crtc)
+{
+ /* disable the pflip int */
+ radeon_irq_kms_pflip_irq_put(rdev, crtc);
+}
+
+u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+ u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset);
+
+ /* Lock the graphics update lock */
+ tmp |= EVERGREEN_GRPH_UPDATE_LOCK;
+ WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* update the scanout addresses */
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+
+ /* Wait for update_pending to go high. */
+ while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING));
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK;
+ WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* Return current update_pending status: */
+ return RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING;
+}
/* get temperature in millidegrees */
u32 evergreen_get_temp(struct radeon_device *rdev)
@@ -57,6 +113,14 @@ u32 evergreen_get_temp(struct radeon_device *rdev)
return actual_temp * 1000;
}
+u32 sumo_get_temp(struct radeon_device *rdev)
+{
+ u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff;
+ u32 actual_temp = (temp >> 1) & 0xff;
+
+ return actual_temp * 1000;
+}
+
void evergreen_pm_misc(struct radeon_device *rdev)
{
int req_ps_idx = rdev->pm.requested_power_state_index;
@@ -337,16 +401,28 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
case 0:
case 4:
default:
- return 3840 * 2;
+ if (ASIC_IS_DCE5(rdev))
+ return 4096 * 2;
+ else
+ return 3840 * 2;
case 1:
case 5:
- return 5760 * 2;
+ if (ASIC_IS_DCE5(rdev))
+ return 6144 * 2;
+ else
+ return 5760 * 2;
case 2:
case 6:
- return 7680 * 2;
+ if (ASIC_IS_DCE5(rdev))
+ return 8192 * 2;
+ else
+ return 7680 * 2;
case 3:
case 7:
- return 1920 * 2;
+ if (ASIC_IS_DCE5(rdev))
+ return 2048 * 2;
+ else
+ return 1920 * 2;
}
}
@@ -748,6 +824,8 @@ void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev)
unsigned i;
u32 tmp;
+ WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+
WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1));
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
@@ -888,31 +966,39 @@ static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_sa
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
- save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
- save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
- save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
- save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ }
/* Stop all video */
WREG32(VGA_RENDER_CONTROL, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ }
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
WREG32(D1VGA_CONTROL, 0);
WREG32(D2VGA_CONTROL, 0);
@@ -942,41 +1028,43 @@ static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
-
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
-
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
-
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
- upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
- (u32)rdev->mc.vram_start);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ }
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
@@ -992,22 +1080,28 @@ static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_
WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ }
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
+ }
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
}
@@ -1055,11 +1149,17 @@ static void evergreen_mc_program(struct radeon_device *rdev)
rdev->mc.vram_end >> 12);
}
WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
+ if (rdev->flags & RADEON_IS_IGP) {
+ tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF;
+ tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24;
+ tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20;
+ WREG32(MC_FUS_VM_FB_OFFSET, tmp);
+ }
tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
WREG32(MC_VM_FB_LOCATION, tmp);
WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
- WREG32(HDP_NONSURFACE_INFO, (2 << 7));
+ WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
if (rdev->flags & RADEON_IS_AGP) {
WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 16);
@@ -1283,11 +1383,15 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
switch (rdev->family) {
case CHIP_CEDAR:
case CHIP_REDWOOD:
+ case CHIP_PALM:
+ case CHIP_TURKS:
+ case CHIP_CAICOS:
force_no_swizzle = false;
break;
case CHIP_CYPRESS:
case CHIP_HEMLOCK:
case CHIP_JUNIPER:
+ case CHIP_BARTS:
default:
force_no_swizzle = true;
break;
@@ -1382,6 +1486,46 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
+static void evergreen_program_channel_remap(struct radeon_device *rdev)
+{
+ u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
+
+ tmp = RREG32(MC_SHARED_CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ default:
+ /* default mapping */
+ mc_shared_chremap = 0x00fac688;
+ break;
+ }
+
+ switch (rdev->family) {
+ case CHIP_HEMLOCK:
+ case CHIP_CYPRESS:
+ case CHIP_BARTS:
+ tcp_chan_steer_lo = 0x54763210;
+ tcp_chan_steer_hi = 0x0000ba98;
+ break;
+ case CHIP_JUNIPER:
+ case CHIP_REDWOOD:
+ case CHIP_CEDAR:
+ case CHIP_PALM:
+ case CHIP_TURKS:
+ case CHIP_CAICOS:
+ default:
+ tcp_chan_steer_lo = 0x76543210;
+ tcp_chan_steer_hi = 0x0000ba98;
+ break;
+ }
+
+ WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
+ WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
+ WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
+}
+
static void evergreen_gpu_init(struct radeon_device *rdev)
{
u32 cc_rb_backend_disable = 0;
@@ -1493,6 +1637,90 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
break;
+ case CHIP_PALM:
+ rdev->config.evergreen.num_ses = 1;
+ rdev->config.evergreen.max_pipes = 2;
+ rdev->config.evergreen.max_tile_pipes = 2;
+ rdev->config.evergreen.max_simds = 2;
+ rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses;
+ rdev->config.evergreen.max_gprs = 256;
+ rdev->config.evergreen.max_threads = 192;
+ rdev->config.evergreen.max_gs_threads = 16;
+ rdev->config.evergreen.max_stack_entries = 256;
+ rdev->config.evergreen.sx_num_of_sets = 4;
+ rdev->config.evergreen.sx_max_export_size = 128;
+ rdev->config.evergreen.sx_max_export_pos_size = 32;
+ rdev->config.evergreen.sx_max_export_smx_size = 96;
+ rdev->config.evergreen.max_hw_contexts = 4;
+ rdev->config.evergreen.sq_num_cf_insts = 1;
+
+ rdev->config.evergreen.sc_prim_fifo_size = 0x40;
+ rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+ break;
+ case CHIP_BARTS:
+ rdev->config.evergreen.num_ses = 2;
+ rdev->config.evergreen.max_pipes = 4;
+ rdev->config.evergreen.max_tile_pipes = 8;
+ rdev->config.evergreen.max_simds = 7;
+ rdev->config.evergreen.max_backends = 4 * rdev->config.evergreen.num_ses;
+ rdev->config.evergreen.max_gprs = 256;
+ rdev->config.evergreen.max_threads = 248;
+ rdev->config.evergreen.max_gs_threads = 32;
+ rdev->config.evergreen.max_stack_entries = 512;
+ rdev->config.evergreen.sx_num_of_sets = 4;
+ rdev->config.evergreen.sx_max_export_size = 256;
+ rdev->config.evergreen.sx_max_export_pos_size = 64;
+ rdev->config.evergreen.sx_max_export_smx_size = 192;
+ rdev->config.evergreen.max_hw_contexts = 8;
+ rdev->config.evergreen.sq_num_cf_insts = 2;
+
+ rdev->config.evergreen.sc_prim_fifo_size = 0x100;
+ rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+ break;
+ case CHIP_TURKS:
+ rdev->config.evergreen.num_ses = 1;
+ rdev->config.evergreen.max_pipes = 4;
+ rdev->config.evergreen.max_tile_pipes = 4;
+ rdev->config.evergreen.max_simds = 6;
+ rdev->config.evergreen.max_backends = 2 * rdev->config.evergreen.num_ses;
+ rdev->config.evergreen.max_gprs = 256;
+ rdev->config.evergreen.max_threads = 248;
+ rdev->config.evergreen.max_gs_threads = 32;
+ rdev->config.evergreen.max_stack_entries = 256;
+ rdev->config.evergreen.sx_num_of_sets = 4;
+ rdev->config.evergreen.sx_max_export_size = 256;
+ rdev->config.evergreen.sx_max_export_pos_size = 64;
+ rdev->config.evergreen.sx_max_export_smx_size = 192;
+ rdev->config.evergreen.max_hw_contexts = 8;
+ rdev->config.evergreen.sq_num_cf_insts = 2;
+
+ rdev->config.evergreen.sc_prim_fifo_size = 0x100;
+ rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+ break;
+ case CHIP_CAICOS:
+ rdev->config.evergreen.num_ses = 1;
+ rdev->config.evergreen.max_pipes = 4;
+ rdev->config.evergreen.max_tile_pipes = 2;
+ rdev->config.evergreen.max_simds = 2;
+ rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses;
+ rdev->config.evergreen.max_gprs = 256;
+ rdev->config.evergreen.max_threads = 192;
+ rdev->config.evergreen.max_gs_threads = 16;
+ rdev->config.evergreen.max_stack_entries = 256;
+ rdev->config.evergreen.sx_num_of_sets = 4;
+ rdev->config.evergreen.sx_max_export_size = 128;
+ rdev->config.evergreen.sx_max_export_pos_size = 32;
+ rdev->config.evergreen.sx_max_export_smx_size = 96;
+ rdev->config.evergreen.max_hw_contexts = 4;
+ rdev->config.evergreen.sq_num_cf_insts = 1;
+
+ rdev->config.evergreen.sc_prim_fifo_size = 0x40;
+ rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+ break;
}
/* Initialize HDP */
@@ -1634,6 +1862,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
switch (rdev->family) {
case CHIP_CYPRESS:
case CHIP_HEMLOCK:
+ case CHIP_BARTS:
gb_backend_map = 0x66442200;
break;
case CHIP_JUNIPER:
@@ -1650,12 +1879,43 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
}
}
- rdev->config.evergreen.tile_config = gb_addr_config;
+ /* setup tiling info dword. gb_addr_config is not adequate since it does
+ * not have bank info, so create a custom tiling dword.
+ * bits 3:0 num_pipes
+ * bits 7:4 num_banks
+ * bits 11:8 group_size
+ * bits 15:12 row_size
+ */
+ rdev->config.evergreen.tile_config = 0;
+ switch (rdev->config.evergreen.max_tile_pipes) {
+ case 1:
+ default:
+ rdev->config.evergreen.tile_config |= (0 << 0);
+ break;
+ case 2:
+ rdev->config.evergreen.tile_config |= (1 << 0);
+ break;
+ case 4:
+ rdev->config.evergreen.tile_config |= (2 << 0);
+ break;
+ case 8:
+ rdev->config.evergreen.tile_config |= (3 << 0);
+ break;
+ }
+ rdev->config.evergreen.tile_config |=
+ ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+ rdev->config.evergreen.tile_config |=
+ ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
+ rdev->config.evergreen.tile_config |=
+ ((gb_addr_config & 0x30000000) >> 28) << 12;
+
WREG32(GB_BACKEND_MAP, gb_backend_map);
WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
+ evergreen_program_channel_remap(rdev);
+
num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1;
grbm_gfx_index = INSTANCE_BROADCAST_WRITES;
@@ -1738,9 +1998,16 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
GS_PRIO(2) |
ES_PRIO(3));
- if (rdev->family == CHIP_CEDAR)
+ switch (rdev->family) {
+ case CHIP_CEDAR:
+ case CHIP_PALM:
+ case CHIP_CAICOS:
/* no vertex cache */
sq_config &= ~VC_ENABLE;
+ break;
+ default:
+ break;
+ }
sq_lds_resource_mgmt = RREG32(SQ_LDS_RESOURCE_MGMT);
@@ -1752,10 +2019,15 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
sq_gpr_resource_mgmt_3 = NUM_HS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32);
sq_gpr_resource_mgmt_3 |= NUM_LS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32);
- if (rdev->family == CHIP_CEDAR)
+ switch (rdev->family) {
+ case CHIP_CEDAR:
+ case CHIP_PALM:
ps_thread_count = 96;
- else
+ break;
+ default:
ps_thread_count = 128;
+ break;
+ }
sq_thread_resource_mgmt = NUM_PS_THREADS(ps_thread_count);
sq_thread_resource_mgmt |= NUM_VS_THREADS((((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8);
@@ -1786,10 +2058,16 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) |
FORCE_EOV_MAX_REZ_CNT(255)));
- if (rdev->family == CHIP_CEDAR)
+ switch (rdev->family) {
+ case CHIP_CEDAR:
+ case CHIP_PALM:
+ case CHIP_CAICOS:
vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY);
- else
+ break;
+ default:
vgt_cache_invalidation = CACHE_INVALIDATION(VC_AND_TC);
+ break;
+ }
vgt_cache_invalidation |= AUTO_INVLD_EN(ES_AND_GS_AUTO);
WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation);
@@ -1873,12 +2151,18 @@ int evergreen_mc_init(struct radeon_device *rdev)
rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
/* Setup GPU memory space */
- /* size in MB on evergreen */
- rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
- rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ if (rdev->flags & RADEON_IS_IGP) {
+ /* size in bytes on fusion */
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
+ } else {
+ /* size in MB on evergreen */
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ }
rdev->mc.visible_vram_size = rdev->mc.aper_size;
rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
- r600_vram_gtt_location(rdev, &rdev->mc);
+ r700_vram_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
return 0;
@@ -1886,14 +2170,35 @@ int evergreen_mc_init(struct radeon_device *rdev)
bool evergreen_gpu_is_lockup(struct radeon_device *rdev)
{
- /* FIXME: implement for evergreen */
- return false;
+ u32 srbm_status;
+ u32 grbm_status;
+ u32 grbm_status_se0, grbm_status_se1;
+ struct r100_gpu_lockup *lockup = &rdev->config.evergreen.lockup;
+ int r;
+
+ srbm_status = RREG32(SRBM_STATUS);
+ grbm_status = RREG32(GRBM_STATUS);
+ grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+ grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+ if (!(grbm_status & GUI_ACTIVE)) {
+ r100_gpu_lockup_update(lockup, &rdev->cp);
+ return false;
+ }
+ /* force CP activities */
+ r = radeon_ring_lock(rdev, 2);
+ if (!r) {
+ /* PACKET2 NOP */
+ radeon_ring_write(rdev, 0x80000000);
+ radeon_ring_write(rdev, 0x80000000);
+ radeon_ring_unlock_commit(rdev);
+ }
+ rdev->cp.rptr = RREG32(CP_RB_RPTR);
+ return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp);
}
static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
- u32 srbm_reset = 0;
u32 grbm_reset = 0;
dev_info(rdev->dev, "GPU softreset \n");
@@ -1932,16 +2237,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
udelay(50);
WREG32(GRBM_SOFT_RESET, 0);
(void)RREG32(GRBM_SOFT_RESET);
-
- /* reset all the system blocks */
- srbm_reset = SRBM_SOFT_RESET_ALL_MASK;
-
- dev_info(rdev->dev, " SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
- WREG32(SRBM_SOFT_RESET, srbm_reset);
- (void)RREG32(SRBM_SOFT_RESET);
- udelay(50);
- WREG32(SRBM_SOFT_RESET, 0);
- (void)RREG32(SRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
@@ -1952,10 +2247,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
RREG32(SRBM_STATUS));
- /* After reset we need to reinit the asic as GPU often endup in an
- * incoherent state.
- */
- atom_asic_init(rdev->mode_info.atom_context);
evergreen_mc_resume(rdev, &save);
return 0;
}
@@ -1995,17 +2286,21 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
WREG32(GRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
@@ -2031,9 +2326,10 @@ int evergreen_irq_set(struct radeon_device *rdev)
u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
u32 grbm_int_cntl = 0;
+ u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
if (!rdev->irq.installed) {
- WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+ WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
return -EINVAL;
}
/* don't enable anything if the ih is disabled */
@@ -2056,27 +2352,33 @@ int evergreen_irq_set(struct radeon_device *rdev)
cp_int_cntl |= RB_INT_ENABLE;
cp_int_cntl |= TIME_STAMP_INT_ENABLE;
}
- if (rdev->irq.crtc_vblank_int[0]) {
+ if (rdev->irq.crtc_vblank_int[0] ||
+ rdev->irq.pflip[0]) {
DRM_DEBUG("evergreen_irq_set: vblank 0\n");
crtc1 |= VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[1]) {
+ if (rdev->irq.crtc_vblank_int[1] ||
+ rdev->irq.pflip[1]) {
DRM_DEBUG("evergreen_irq_set: vblank 1\n");
crtc2 |= VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[2]) {
+ if (rdev->irq.crtc_vblank_int[2] ||
+ rdev->irq.pflip[2]) {
DRM_DEBUG("evergreen_irq_set: vblank 2\n");
crtc3 |= VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[3]) {
+ if (rdev->irq.crtc_vblank_int[3] ||
+ rdev->irq.pflip[3]) {
DRM_DEBUG("evergreen_irq_set: vblank 3\n");
crtc4 |= VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[4]) {
+ if (rdev->irq.crtc_vblank_int[4] ||
+ rdev->irq.pflip[4]) {
DRM_DEBUG("evergreen_irq_set: vblank 4\n");
crtc5 |= VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[5]) {
+ if (rdev->irq.crtc_vblank_int[5] ||
+ rdev->irq.pflip[5]) {
DRM_DEBUG("evergreen_irq_set: vblank 5\n");
crtc6 |= VBLANK_INT_MASK;
}
@@ -2114,10 +2416,19 @@ int evergreen_irq_set(struct radeon_device *rdev)
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
- WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
- WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
- WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
- WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
+ WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+ WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
+ WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+ }
+
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6);
WREG32(DC_HPD1_INT_CONTROL, hpd1);
WREG32(DC_HPD2_INT_CONTROL, hpd2);
@@ -2129,79 +2440,92 @@ int evergreen_irq_set(struct radeon_device *rdev)
return 0;
}
-static inline void evergreen_irq_ack(struct radeon_device *rdev,
- u32 *disp_int,
- u32 *disp_int_cont,
- u32 *disp_int_cont2,
- u32 *disp_int_cont3,
- u32 *disp_int_cont4,
- u32 *disp_int_cont5)
+static inline void evergreen_irq_ack(struct radeon_device *rdev)
{
u32 tmp;
- *disp_int = RREG32(DISP_INTERRUPT_STATUS);
- *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
- *disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
- *disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
- *disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
- *disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
-
- if (*disp_int & LB_D1_VBLANK_INTERRUPT)
+ rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+ rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+ rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
+ rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
+ rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
+ rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+ rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+
+ if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+
+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int & LB_D1_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int_cont & LB_D2_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int_cont & LB_D2_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
- if (*disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
- if (*disp_int & DC_HPD1_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD1_INT_CONTROL, tmp);
}
- if (*disp_int_cont & DC_HPD2_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD2_INT_CONTROL, tmp);
}
- if (*disp_int_cont2 & DC_HPD3_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD3_INT_CONTROL, tmp);
}
- if (*disp_int_cont3 & DC_HPD4_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
- if (*disp_int_cont4 & DC_HPD5_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
- if (*disp_int_cont5 & DC_HPD6_INTERRUPT) {
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
@@ -2210,14 +2534,10 @@ static inline void evergreen_irq_ack(struct radeon_device *rdev,
void evergreen_irq_disable(struct radeon_device *rdev)
{
- u32 disp_int, disp_int_cont, disp_int_cont2;
- u32 disp_int_cont3, disp_int_cont4, disp_int_cont5;
-
r600_disable_interrupts(rdev);
/* Wait and acknowledge irq */
mdelay(1);
- evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2,
- &disp_int_cont3, &disp_int_cont4, &disp_int_cont5);
+ evergreen_irq_ack(rdev);
evergreen_disable_interrupt_state(rdev);
}
@@ -2257,8 +2577,6 @@ int evergreen_irq_process(struct radeon_device *rdev)
u32 rptr = rdev->ih.rptr;
u32 src_id, src_data;
u32 ring_index;
- u32 disp_int, disp_int_cont, disp_int_cont2;
- u32 disp_int_cont3, disp_int_cont4, disp_int_cont5;
unsigned long flags;
bool queue_hotplug = false;
@@ -2279,8 +2597,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
restart_ih:
/* display interrupts */
- evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2,
- &disp_int_cont3, &disp_int_cont4, &disp_int_cont5);
+ evergreen_irq_ack(rdev);
rdev->ih.wptr = wptr;
while (rptr != wptr) {
@@ -2293,16 +2610,21 @@ restart_ih:
case 1: /* D1 vblank/vline */
switch (src_data) {
case 0: /* D1 vblank */
- if (disp_int & LB_D1_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 0);
- wake_up(&rdev->irq.vblank_queue);
- disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[0]) {
+ drm_handle_vblank(rdev->ddev, 0);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[0])
+ radeon_crtc_handle_flip(rdev, 0);
+ rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n");
}
break;
case 1: /* D1 vline */
- if (disp_int & LB_D1_VLINE_INTERRUPT) {
- disp_int &= ~LB_D1_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
DRM_DEBUG("IH: D1 vline\n");
}
break;
@@ -2314,16 +2636,21 @@ restart_ih:
case 2: /* D2 vblank/vline */
switch (src_data) {
case 0: /* D2 vblank */
- if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 1);
- wake_up(&rdev->irq.vblank_queue);
- disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[1]) {
+ drm_handle_vblank(rdev->ddev, 1);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[1])
+ radeon_crtc_handle_flip(rdev, 1);
+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n");
}
break;
case 1: /* D2 vline */
- if (disp_int_cont & LB_D2_VLINE_INTERRUPT) {
- disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
DRM_DEBUG("IH: D2 vline\n");
}
break;
@@ -2335,16 +2662,21 @@ restart_ih:
case 3: /* D3 vblank/vline */
switch (src_data) {
case 0: /* D3 vblank */
- if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 2);
- wake_up(&rdev->irq.vblank_queue);
- disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[2]) {
+ drm_handle_vblank(rdev->ddev, 2);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[2])
+ radeon_crtc_handle_flip(rdev, 2);
+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D3 vblank\n");
}
break;
case 1: /* D3 vline */
- if (disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
- disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
DRM_DEBUG("IH: D3 vline\n");
}
break;
@@ -2356,16 +2688,21 @@ restart_ih:
case 4: /* D4 vblank/vline */
switch (src_data) {
case 0: /* D4 vblank */
- if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 3);
- wake_up(&rdev->irq.vblank_queue);
- disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[3]) {
+ drm_handle_vblank(rdev->ddev, 3);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[3])
+ radeon_crtc_handle_flip(rdev, 3);
+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D4 vblank\n");
}
break;
case 1: /* D4 vline */
- if (disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
- disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
DRM_DEBUG("IH: D4 vline\n");
}
break;
@@ -2377,16 +2714,21 @@ restart_ih:
case 5: /* D5 vblank/vline */
switch (src_data) {
case 0: /* D5 vblank */
- if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 4);
- wake_up(&rdev->irq.vblank_queue);
- disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[4]) {
+ drm_handle_vblank(rdev->ddev, 4);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[4])
+ radeon_crtc_handle_flip(rdev, 4);
+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D5 vblank\n");
}
break;
case 1: /* D5 vline */
- if (disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
- disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
DRM_DEBUG("IH: D5 vline\n");
}
break;
@@ -2398,16 +2740,21 @@ restart_ih:
case 6: /* D6 vblank/vline */
switch (src_data) {
case 0: /* D6 vblank */
- if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 5);
- wake_up(&rdev->irq.vblank_queue);
- disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[5]) {
+ drm_handle_vblank(rdev->ddev, 5);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[5])
+ radeon_crtc_handle_flip(rdev, 5);
+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D6 vblank\n");
}
break;
case 1: /* D6 vline */
- if (disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
- disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
DRM_DEBUG("IH: D6 vline\n");
}
break;
@@ -2419,43 +2766,43 @@ restart_ih:
case 42: /* HPD hotplug */
switch (src_data) {
case 0:
- if (disp_int & DC_HPD1_INTERRUPT) {
- disp_int &= ~DC_HPD1_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD1\n");
}
break;
case 1:
- if (disp_int_cont & DC_HPD2_INTERRUPT) {
- disp_int_cont &= ~DC_HPD2_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD2\n");
}
break;
case 2:
- if (disp_int_cont2 & DC_HPD3_INTERRUPT) {
- disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD3\n");
}
break;
case 3:
- if (disp_int_cont3 & DC_HPD4_INTERRUPT) {
- disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD4\n");
}
break;
case 4:
- if (disp_int_cont4 & DC_HPD5_INTERRUPT) {
- disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD5\n");
}
break;
case 5:
- if (disp_int_cont5 & DC_HPD6_INTERRUPT) {
- disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD6\n");
}
@@ -2494,7 +2841,7 @@ restart_ih:
if (wptr != rdev->ih.wptr)
goto restart_ih;
if (queue_hotplug)
- queue_work(rdev->wq, &rdev->hotplug_work);
+ schedule_work(&rdev->hotplug_work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
spin_unlock_irqrestore(&rdev->ih.lock, flags);
@@ -2505,12 +2852,31 @@ static int evergreen_startup(struct radeon_device *rdev)
{
int r;
- if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
- r = r600_init_microcode(rdev);
+ /* enable pcie gen2 link */
+ if (!ASIC_IS_DCE5(rdev))
+ evergreen_pcie_gen2_enable(rdev);
+
+ if (ASIC_IS_DCE5(rdev)) {
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
+ r = ni_init_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load firmware!\n");
+ return r;
+ }
+ }
+ r = btc_mc_load_microcode(rdev);
if (r) {
- DRM_ERROR("Failed to load firmware!\n");
+ DRM_ERROR("Failed to load MC firmware!\n");
return r;
}
+ } else {
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+ r = r600_init_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load firmware!\n");
+ return r;
+ }
+ }
}
evergreen_mc_program(rdev);
@@ -2529,6 +2895,11 @@ static int evergreen_startup(struct radeon_device *rdev)
rdev->asic->copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
+ /* XXX: ontario has problems blitting to gart at the moment */
+ if (rdev->family == CHIP_PALM) {
+ rdev->asic->copy = NULL;
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+ }
/* allocate wb buffer */
r = radeon_wb_init(rdev);
@@ -2561,6 +2932,11 @@ int evergreen_resume(struct radeon_device *rdev)
{
int r;
+ /* reset the asic, the gfx blocks are often in a bad state
+ * after the driver is unloaded or after a resume
+ */
+ if (radeon_asic_reset(rdev))
+ dev_warn(rdev->dev, "GPU reset failed !\n");
/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
* posting will perform necessary task to bring back GPU into good
* shape.
@@ -2626,27 +3002,6 @@ int evergreen_copy_blit(struct radeon_device *rdev,
return 0;
}
-static bool evergreen_card_posted(struct radeon_device *rdev)
-{
- u32 reg;
-
- /* first check CRTCs */
- reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
- if (reg & EVERGREEN_CRTC_MASTER_EN)
- return true;
-
- /* then check MEM_SIZE, in case the crtcs are off */
- if (RREG32(CONFIG_MEMSIZE))
- return true;
-
- return false;
-}
-
/* Plan is to move initialization in that function and use
* helper function so that radeon_device_init pretty much
* do nothing more than calling asic specific function. This
@@ -2677,8 +3032,13 @@ int evergreen_init(struct radeon_device *rdev)
r = radeon_atombios_init(rdev);
if (r)
return r;
+ /* reset the asic, the gfx blocks are often in a bad state
+ * after the driver is unloaded or after a resume
+ */
+ if (radeon_asic_reset(rdev))
+ dev_warn(rdev->dev, "GPU reset failed !\n");
/* Post card if necessary */
- if (!evergreen_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -2768,3 +3128,55 @@ void evergreen_fini(struct radeon_device *rdev)
rdev->bios = NULL;
radeon_dummy_page_fini(rdev);
}
+
+static void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
+{
+ u32 link_width_cntl, speed_cntl;
+
+ if (radeon_pcie_gen2 == 0)
+ return;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ /* x2 cards have a special sequence */
+ if (ASIC_IS_X2(rdev))
+ return;
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+ (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_GEN2_EN_STRAP;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ } else {
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */
+ if (1)
+ link_width_cntl |= LC_UPCONFIGURE_DIS;
+ else
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ }
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index ac3b6dde23db..b758dc7f2f2c 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -147,7 +147,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30);
- if (rdev->family == CHIP_CEDAR)
+ if ((rdev->family == CHIP_CEDAR) ||
+ (rdev->family == CHIP_PALM) ||
+ (rdev->family == CHIP_CAICOS))
cp_set_surface_sync(rdev,
PACKET3_TC_ACTION_ENA, 48, gpu_addr);
else
@@ -331,9 +333,95 @@ set_default_state(struct radeon_device *rdev)
num_hs_stack_entries = 85;
num_ls_stack_entries = 85;
break;
+ case CHIP_PALM:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 96;
+ num_vs_threads = 16;
+ num_gs_threads = 16;
+ num_es_threads = 16;
+ num_hs_threads = 16;
+ num_ls_threads = 16;
+ num_ps_stack_entries = 42;
+ num_vs_stack_entries = 42;
+ num_gs_stack_entries = 42;
+ num_es_stack_entries = 42;
+ num_hs_stack_entries = 42;
+ num_ls_stack_entries = 42;
+ break;
+ case CHIP_BARTS:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 20;
+ num_gs_threads = 20;
+ num_es_threads = 20;
+ num_hs_threads = 20;
+ num_ls_threads = 20;
+ num_ps_stack_entries = 85;
+ num_vs_stack_entries = 85;
+ num_gs_stack_entries = 85;
+ num_es_stack_entries = 85;
+ num_hs_stack_entries = 85;
+ num_ls_stack_entries = 85;
+ break;
+ case CHIP_TURKS:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 20;
+ num_gs_threads = 20;
+ num_es_threads = 20;
+ num_hs_threads = 20;
+ num_ls_threads = 20;
+ num_ps_stack_entries = 42;
+ num_vs_stack_entries = 42;
+ num_gs_stack_entries = 42;
+ num_es_stack_entries = 42;
+ num_hs_stack_entries = 42;
+ num_ls_stack_entries = 42;
+ break;
+ case CHIP_CAICOS:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 10;
+ num_gs_threads = 10;
+ num_es_threads = 10;
+ num_hs_threads = 10;
+ num_ls_threads = 10;
+ num_ps_stack_entries = 42;
+ num_vs_stack_entries = 42;
+ num_gs_stack_entries = 42;
+ num_es_stack_entries = 42;
+ num_hs_stack_entries = 42;
+ num_ls_stack_entries = 42;
+ break;
}
- if (rdev->family == CHIP_CEDAR)
+ if ((rdev->family == CHIP_CEDAR) ||
+ (rdev->family == CHIP_PALM) ||
+ (rdev->family == CHIP_CAICOS))
sq_config = 0;
else
sq_config = VC_ENABLE;
@@ -459,7 +547,7 @@ int evergreen_blit_init(struct radeon_device *rdev)
obj_size += evergreen_ps_size * 4;
obj_size = ALIGN(obj_size, 256);
- r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("evergreen failed to allocate shader\n");
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 2330f3a36fd5..c781c92c3451 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -105,6 +105,11 @@
#define EVERGREEN_GRPH_Y_START 0x6830
#define EVERGREEN_GRPH_X_END 0x6834
#define EVERGREEN_GRPH_Y_END 0x6838
+#define EVERGREEN_GRPH_UPDATE 0x6844
+# define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING (1 << 2)
+# define EVERGREEN_GRPH_UPDATE_LOCK (1 << 16)
+#define EVERGREEN_GRPH_FLIP_CONTROL 0x6848
+# define EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0)
/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
#define EVERGREEN_CUR_CONTROL 0x6998
@@ -178,6 +183,7 @@
# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
#define EVERGREEN_CRTC_STATUS 0x6e8c
#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90
+#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
#define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 113c70cc8b39..36d32d83d866 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -164,22 +164,26 @@
#define SE_SC_BUSY (1 << 29)
#define SE_DB_BUSY (1 << 30)
#define SE_CB_BUSY (1 << 31)
-
+/* evergreen */
#define CG_MULT_THERMAL_STATUS 0x740
#define ASIC_T(x) ((x) << 16)
#define ASIC_T_MASK 0x7FF0000
#define ASIC_T_SHIFT 16
+/* APU */
+#define CG_THERMAL_STATUS 0x678
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
#define HDP_NONSURFACE_SIZE 0x2C0C
+#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
#define HDP_TILING_CONFIG 0x2F3C
#define MC_SHARED_CHMAP 0x2004
#define NOOFCHAN_SHIFT 12
#define NOOFCHAN_MASK 0x00003000
+#define MC_SHARED_CHREMAP 0x2008
#define MC_ARB_RAMCFG 0x2760
#define NOOFBANK_SHIFT 0
@@ -199,6 +203,7 @@
#define MC_VM_AGP_BOT 0x202C
#define MC_VM_AGP_BASE 0x2030
#define MC_VM_FB_LOCATION 0x2024
+#define MC_FUS_VM_FB_OFFSET 0x2898
#define MC_VM_MB_L1_TLB0_CNTL 0x2234
#define MC_VM_MB_L1_TLB1_CNTL 0x2238
#define MC_VM_MB_L1_TLB2_CNTL 0x223C
@@ -348,6 +353,9 @@
#define SYNC_WALKER (1 << 25)
#define SYNC_ALIGNER (1 << 26)
+#define TCP_CHAN_STEER_LO 0x960c
+#define TCP_CHAN_STEER_HI 0x9610
+
#define VGT_CACHE_INVALIDATION 0x88C4
#define CACHE_INVALIDATION(x) ((x) << 0)
#define VC_ONLY 0
@@ -573,6 +581,44 @@
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
# define DC_HPDx_EN (1 << 28)
+/* PCIE link stuff */
+#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
+#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
+# define LC_LINK_WIDTH_SHIFT 0
+# define LC_LINK_WIDTH_MASK 0x7
+# define LC_LINK_WIDTH_X0 0
+# define LC_LINK_WIDTH_X1 1
+# define LC_LINK_WIDTH_X2 2
+# define LC_LINK_WIDTH_X4 3
+# define LC_LINK_WIDTH_X8 4
+# define LC_LINK_WIDTH_X16 6
+# define LC_LINK_WIDTH_RD_SHIFT 4
+# define LC_LINK_WIDTH_RD_MASK 0x70
+# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define LC_RECONFIG_NOW (1 << 8)
+# define LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define LC_RENEGOTIATE_EN (1 << 10)
+# define LC_SHORT_RECONFIG_EN (1 << 11)
+# define LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define LC_UPCONFIGURE_DIS (1 << 13)
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+#define MM_CFGREGS_CNTL 0x544c
+# define MM_WR_TO_CFG_EN (1 << 3)
+#define LINK_CNTL2 0x88 /* F0 */
+# define TARGET_LINK_SPEED_MASK (0xf << 0)
+# define SELECTABLE_DEEMPHASIS (1 << 6)
+
/*
* PM4
*/
@@ -602,7 +648,7 @@
#define PACKET3_NOP 0x10
#define PACKET3_SET_BASE 0x11
#define PACKET3_CLEAR_STATE 0x12
-#define PACKET3_INDIRECT_BUFFER_SIZE 0x13
+#define PACKET3_INDEX_BUFFER_SIZE 0x13
#define PACKET3_DISPATCH_DIRECT 0x15
#define PACKET3_DISPATCH_INDIRECT 0x16
#define PACKET3_INDIRECT_BUFFER_END 0x17
@@ -643,14 +689,14 @@
# define PACKET3_CB8_DEST_BASE_ENA (1 << 15)
# define PACKET3_CB9_DEST_BASE_ENA (1 << 16)
# define PACKET3_CB10_DEST_BASE_ENA (1 << 17)
-# define PACKET3_CB11_DEST_BASE_ENA (1 << 17)
+# define PACKET3_CB11_DEST_BASE_ENA (1 << 18)
# define PACKET3_FULL_CACHE_ENA (1 << 20)
# define PACKET3_TC_ACTION_ENA (1 << 23)
# define PACKET3_VC_ACTION_ENA (1 << 24)
# define PACKET3_CB_ACTION_ENA (1 << 25)
# define PACKET3_DB_ACTION_ENA (1 << 26)
# define PACKET3_SH_ACTION_ENA (1 << 27)
-# define PACKET3_SMX_ACTION_ENA (1 << 28)
+# define PACKET3_SX_ACTION_ENA (1 << 28)
#define PACKET3_ME_INITIALIZE 0x44
#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
#define PACKET3_COND_WRITE 0x45
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
new file mode 100644
index 000000000000..5e0bef80ad7f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "radeon_drm.h"
+#include "nid.h"
+#include "atom.h"
+#include "ni_reg.h"
+
+#define EVERGREEN_PFP_UCODE_SIZE 1120
+#define EVERGREEN_PM4_UCODE_SIZE 1376
+#define EVERGREEN_RLC_UCODE_SIZE 768
+#define BTC_MC_UCODE_SIZE 6024
+
+/* Firmware Names */
+MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
+MODULE_FIRMWARE("radeon/BARTS_me.bin");
+MODULE_FIRMWARE("radeon/BARTS_mc.bin");
+MODULE_FIRMWARE("radeon/BTC_rlc.bin");
+MODULE_FIRMWARE("radeon/TURKS_pfp.bin");
+MODULE_FIRMWARE("radeon/TURKS_me.bin");
+MODULE_FIRMWARE("radeon/TURKS_mc.bin");
+MODULE_FIRMWARE("radeon/CAICOS_pfp.bin");
+MODULE_FIRMWARE("radeon/CAICOS_me.bin");
+MODULE_FIRMWARE("radeon/CAICOS_mc.bin");
+
+#define BTC_IO_MC_REGS_SIZE 29
+
+static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
+ {0x00000077, 0xff010100},
+ {0x00000078, 0x00000000},
+ {0x00000079, 0x00001434},
+ {0x0000007a, 0xcc08ec08},
+ {0x0000007b, 0x00040000},
+ {0x0000007c, 0x000080c0},
+ {0x0000007d, 0x09000000},
+ {0x0000007e, 0x00210404},
+ {0x00000081, 0x08a8e800},
+ {0x00000082, 0x00030444},
+ {0x00000083, 0x00000000},
+ {0x00000085, 0x00000001},
+ {0x00000086, 0x00000002},
+ {0x00000087, 0x48490000},
+ {0x00000088, 0x20244647},
+ {0x00000089, 0x00000005},
+ {0x0000008b, 0x66030000},
+ {0x0000008c, 0x00006603},
+ {0x0000008d, 0x00000100},
+ {0x0000008f, 0x00001c0a},
+ {0x00000090, 0xff000001},
+ {0x00000094, 0x00101101},
+ {0x00000095, 0x00000fff},
+ {0x00000096, 0x00116fff},
+ {0x00000097, 0x60010000},
+ {0x00000098, 0x10010000},
+ {0x00000099, 0x00006000},
+ {0x0000009a, 0x00001000},
+ {0x0000009f, 0x00946a00}
+};
+
+static const u32 turks_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
+ {0x00000077, 0xff010100},
+ {0x00000078, 0x00000000},
+ {0x00000079, 0x00001434},
+ {0x0000007a, 0xcc08ec08},
+ {0x0000007b, 0x00040000},
+ {0x0000007c, 0x000080c0},
+ {0x0000007d, 0x09000000},
+ {0x0000007e, 0x00210404},
+ {0x00000081, 0x08a8e800},
+ {0x00000082, 0x00030444},
+ {0x00000083, 0x00000000},
+ {0x00000085, 0x00000001},
+ {0x00000086, 0x00000002},
+ {0x00000087, 0x48490000},
+ {0x00000088, 0x20244647},
+ {0x00000089, 0x00000005},
+ {0x0000008b, 0x66030000},
+ {0x0000008c, 0x00006603},
+ {0x0000008d, 0x00000100},
+ {0x0000008f, 0x00001c0a},
+ {0x00000090, 0xff000001},
+ {0x00000094, 0x00101101},
+ {0x00000095, 0x00000fff},
+ {0x00000096, 0x00116fff},
+ {0x00000097, 0x60010000},
+ {0x00000098, 0x10010000},
+ {0x00000099, 0x00006000},
+ {0x0000009a, 0x00001000},
+ {0x0000009f, 0x00936a00}
+};
+
+static const u32 caicos_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
+ {0x00000077, 0xff010100},
+ {0x00000078, 0x00000000},
+ {0x00000079, 0x00001434},
+ {0x0000007a, 0xcc08ec08},
+ {0x0000007b, 0x00040000},
+ {0x0000007c, 0x000080c0},
+ {0x0000007d, 0x09000000},
+ {0x0000007e, 0x00210404},
+ {0x00000081, 0x08a8e800},
+ {0x00000082, 0x00030444},
+ {0x00000083, 0x00000000},
+ {0x00000085, 0x00000001},
+ {0x00000086, 0x00000002},
+ {0x00000087, 0x48490000},
+ {0x00000088, 0x20244647},
+ {0x00000089, 0x00000005},
+ {0x0000008b, 0x66030000},
+ {0x0000008c, 0x00006603},
+ {0x0000008d, 0x00000100},
+ {0x0000008f, 0x00001c0a},
+ {0x00000090, 0xff000001},
+ {0x00000094, 0x00101101},
+ {0x00000095, 0x00000fff},
+ {0x00000096, 0x00116fff},
+ {0x00000097, 0x60010000},
+ {0x00000098, 0x10010000},
+ {0x00000099, 0x00006000},
+ {0x0000009a, 0x00001000},
+ {0x0000009f, 0x00916a00}
+};
+
+int btc_mc_load_microcode(struct radeon_device *rdev)
+{
+ const __be32 *fw_data;
+ u32 mem_type, running, blackout = 0;
+ u32 *io_mc_regs;
+ int i;
+
+ if (!rdev->mc_fw)
+ return -EINVAL;
+
+ switch (rdev->family) {
+ case CHIP_BARTS:
+ io_mc_regs = (u32 *)&barts_io_mc_regs;
+ break;
+ case CHIP_TURKS:
+ io_mc_regs = (u32 *)&turks_io_mc_regs;
+ break;
+ case CHIP_CAICOS:
+ default:
+ io_mc_regs = (u32 *)&caicos_io_mc_regs;
+ break;
+ }
+
+ mem_type = (RREG32(MC_SEQ_MISC0) & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT;
+ running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+ if ((mem_type == MC_SEQ_MISC0_GDDR5_VALUE) && (running == 0)) {
+ if (running) {
+ blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+ WREG32(MC_SHARED_BLACKOUT_CNTL, 1);
+ }
+
+ /* reset the engine and set to writable */
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+ /* load mc io regs */
+ for (i = 0; i < BTC_IO_MC_REGS_SIZE; i++) {
+ WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]);
+ WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
+ }
+ /* load the MC ucode */
+ fw_data = (const __be32 *)rdev->mc_fw->data;
+ for (i = 0; i < BTC_MC_UCODE_SIZE; i++)
+ WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++));
+
+ /* put the engine back into the active state */
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+ /* wait for training to complete */
+ while (!(RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD))
+ udelay(10);
+
+ if (running)
+ WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
+ }
+
+ return 0;
+}
+
+int ni_init_microcode(struct radeon_device *rdev)
+{
+ struct platform_device *pdev;
+ const char *chip_name;
+ const char *rlc_chip_name;
+ size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size;
+ char fw_name[30];
+ int err;
+
+ DRM_DEBUG("\n");
+
+ pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
+ err = IS_ERR(pdev);
+ if (err) {
+ printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
+ return -EINVAL;
+ }
+
+ switch (rdev->family) {
+ case CHIP_BARTS:
+ chip_name = "BARTS";
+ rlc_chip_name = "BTC";
+ break;
+ case CHIP_TURKS:
+ chip_name = "TURKS";
+ rlc_chip_name = "BTC";
+ break;
+ case CHIP_CAICOS:
+ chip_name = "CAICOS";
+ rlc_chip_name = "BTC";
+ break;
+ default: BUG();
+ }
+
+ pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4;
+ me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
+ rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
+ mc_req_size = BTC_MC_UCODE_SIZE * 4;
+
+ DRM_INFO("Loading %s Microcode\n", chip_name);
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+ err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->pfp_fw->size != pfp_req_size) {
+ printk(KERN_ERR
+ "ni_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->pfp_fw->size, fw_name);
+ err = -EINVAL;
+ goto out;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+ err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->me_fw->size != me_req_size) {
+ printk(KERN_ERR
+ "ni_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->me_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name);
+ err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->rlc_fw->size != rlc_req_size) {
+ printk(KERN_ERR
+ "ni_rlc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->rlc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+ err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->mc_fw->size != mc_req_size) {
+ printk(KERN_ERR
+ "ni_mc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->mc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+out:
+ platform_device_unregister(pdev);
+
+ if (err) {
+ if (err != -EINVAL)
+ printk(KERN_ERR
+ "ni_cp: Failed to load firmware \"%s\"\n",
+ fw_name);
+ release_firmware(rdev->pfp_fw);
+ rdev->pfp_fw = NULL;
+ release_firmware(rdev->me_fw);
+ rdev->me_fw = NULL;
+ release_firmware(rdev->rlc_fw);
+ rdev->rlc_fw = NULL;
+ release_firmware(rdev->mc_fw);
+ rdev->mc_fw = NULL;
+ }
+ return err;
+}
+
diff --git a/drivers/gpu/drm/radeon/ni_reg.h b/drivers/gpu/drm/radeon/ni_reg.h
new file mode 100644
index 000000000000..5db7b7d6feb0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni_reg.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef __NI_REG_H__
+#define __NI_REG_H__
+
+/* northern islands - DCE5 */
+
+#define NI_INPUT_GAMMA_CONTROL 0x6840
+# define NI_GRPH_INPUT_GAMMA_MODE(x) (((x) & 0x3) << 0)
+# define NI_INPUT_GAMMA_USE_LUT 0
+# define NI_INPUT_GAMMA_BYPASS 1
+# define NI_INPUT_GAMMA_SRGB_24 2
+# define NI_INPUT_GAMMA_XVYCC_222 3
+# define NI_OVL_INPUT_GAMMA_MODE(x) (((x) & 0x3) << 4)
+
+#define NI_PRESCALE_GRPH_CONTROL 0x68b4
+# define NI_GRPH_PRESCALE_BYPASS (1 << 4)
+
+#define NI_PRESCALE_OVL_CONTROL 0x68c4
+# define NI_OVL_PRESCALE_BYPASS (1 << 4)
+
+#define NI_INPUT_CSC_CONTROL 0x68d4
+# define NI_INPUT_CSC_GRPH_MODE(x) (((x) & 0x3) << 0)
+# define NI_INPUT_CSC_BYPASS 0
+# define NI_INPUT_CSC_PROG_COEFF 1
+# define NI_INPUT_CSC_PROG_SHARED_MATRIXA 2
+# define NI_INPUT_CSC_OVL_MODE(x) (((x) & 0x3) << 4)
+
+#define NI_OUTPUT_CSC_CONTROL 0x68f0
+# define NI_OUTPUT_CSC_GRPH_MODE(x) (((x) & 0x7) << 0)
+# define NI_OUTPUT_CSC_BYPASS 0
+# define NI_OUTPUT_CSC_TV_RGB 1
+# define NI_OUTPUT_CSC_YCBCR_601 2
+# define NI_OUTPUT_CSC_YCBCR_709 3
+# define NI_OUTPUT_CSC_PROG_COEFF 4
+# define NI_OUTPUT_CSC_PROG_SHARED_MATRIXB 5
+# define NI_OUTPUT_CSC_OVL_MODE(x) (((x) & 0x7) << 4)
+
+#define NI_DEGAMMA_CONTROL 0x6960
+# define NI_GRPH_DEGAMMA_MODE(x) (((x) & 0x3) << 0)
+# define NI_DEGAMMA_BYPASS 0
+# define NI_DEGAMMA_SRGB_24 1
+# define NI_DEGAMMA_XVYCC_222 2
+# define NI_OVL_DEGAMMA_MODE(x) (((x) & 0x3) << 4)
+# define NI_ICON_DEGAMMA_MODE(x) (((x) & 0x3) << 8)
+# define NI_CURSOR_DEGAMMA_MODE(x) (((x) & 0x3) << 12)
+
+#define NI_GAMUT_REMAP_CONTROL 0x6964
+# define NI_GRPH_GAMUT_REMAP_MODE(x) (((x) & 0x3) << 0)
+# define NI_GAMUT_REMAP_BYPASS 0
+# define NI_GAMUT_REMAP_PROG_COEFF 1
+# define NI_GAMUT_REMAP_PROG_SHARED_MATRIXA 2
+# define NI_GAMUT_REMAP_PROG_SHARED_MATRIXB 3
+# define NI_OVL_GAMUT_REMAP_MODE(x) (((x) & 0x3) << 4)
+
+#define NI_REGAMMA_CONTROL 0x6a80
+# define NI_GRPH_REGAMMA_MODE(x) (((x) & 0x7) << 0)
+# define NI_REGAMMA_BYPASS 0
+# define NI_REGAMMA_SRGB_24 1
+# define NI_REGAMMA_XVYCC_222 2
+# define NI_REGAMMA_PROG_A 3
+# define NI_REGAMMA_PROG_B 4
+# define NI_OVL_REGAMMA_MODE(x) (((x) & 0x7) << 4)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
new file mode 100644
index 000000000000..f7b445390e02
--- /dev/null
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef NI_H
+#define NI_H
+
+#define MC_SHARED_BLACKOUT_CNTL 0x20ac
+#define MC_SEQ_SUP_CNTL 0x28c8
+#define RUN_MASK (1 << 0)
+#define MC_SEQ_SUP_PGM 0x28cc
+#define MC_IO_PAD_CNTL_D0 0x29d0
+#define MEM_FALL_OUT_CMD (1 << 8)
+#define MC_SEQ_MISC0 0x2a00
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+#define MC_SEQ_IO_DEBUG_INDEX 0x2a44
+#define MC_SEQ_IO_DEBUG_DATA 0x2a48
+
+#endif
+
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 0e8f28a68927..46da5142b131 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -68,6 +68,56 @@ MODULE_FIRMWARE(FIRMWARE_R520);
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
*/
+void r100_pre_page_flip(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ u32 tmp;
+
+ /* make sure flip is at vb rather than hb */
+ tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset);
+ tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
+ /* make sure pending bit is asserted */
+ tmp |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
+ WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp);
+
+ /* set pageflip to happen as late as possible in the vblank interval.
+ * same field for crtc1/2
+ */
+ tmp = RREG32(RADEON_CRTC_GEN_CNTL);
+ tmp &= ~RADEON_CRTC_VSTAT_MODE_MASK;
+ WREG32(RADEON_CRTC_GEN_CNTL, tmp);
+
+ /* enable the pflip int */
+ radeon_irq_kms_pflip_irq_get(rdev, crtc);
+}
+
+void r100_post_page_flip(struct radeon_device *rdev, int crtc)
+{
+ /* disable the pflip int */
+ radeon_irq_kms_pflip_irq_put(rdev, crtc);
+}
+
+u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+ u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK;
+
+ /* Lock the graphics update lock */
+ /* update the scanout addresses */
+ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
+
+ /* Wait for update_pending to go high. */
+ while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET));
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK;
+ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
+
+ /* Return current update_pending status: */
+ return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET;
+}
+
void r100_pm_get_dynpm_state(struct radeon_device *rdev)
{
int i;
@@ -442,7 +492,7 @@ int r100_pci_gart_init(struct radeon_device *rdev)
int r;
if (rdev->gart.table.ram.ptr) {
- WARN(1, "R100 PCI GART already initialized.\n");
+ WARN(1, "R100 PCI GART already initialized\n");
return 0;
}
/* Initialize common gart structure */
@@ -516,7 +566,7 @@ int r100_irq_set(struct radeon_device *rdev)
uint32_t tmp = 0;
if (!rdev->irq.installed) {
- WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+ WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
WREG32(R_000040_GEN_INT_CNTL, 0);
return -EINVAL;
}
@@ -526,10 +576,12 @@ int r100_irq_set(struct radeon_device *rdev)
if (rdev->irq.gui_idle) {
tmp |= RADEON_GUI_IDLE_MASK;
}
- if (rdev->irq.crtc_vblank_int[0]) {
+ if (rdev->irq.crtc_vblank_int[0] ||
+ rdev->irq.pflip[0]) {
tmp |= RADEON_CRTC_VBLANK_MASK;
}
- if (rdev->irq.crtc_vblank_int[1]) {
+ if (rdev->irq.crtc_vblank_int[1] ||
+ rdev->irq.pflip[1]) {
tmp |= RADEON_CRTC2_VBLANK_MASK;
}
if (rdev->irq.hpd[0]) {
@@ -600,14 +652,22 @@ int r100_irq_process(struct radeon_device *rdev)
}
/* Vertical blank interrupts */
if (status & RADEON_CRTC_VBLANK_STAT) {
- drm_handle_vblank(rdev->ddev, 0);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
+ if (rdev->irq.crtc_vblank_int[0]) {
+ drm_handle_vblank(rdev->ddev, 0);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[0])
+ radeon_crtc_handle_flip(rdev, 0);
}
if (status & RADEON_CRTC2_VBLANK_STAT) {
- drm_handle_vblank(rdev->ddev, 1);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
+ if (rdev->irq.crtc_vblank_int[1]) {
+ drm_handle_vblank(rdev->ddev, 1);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[1])
+ radeon_crtc_handle_flip(rdev, 1);
}
if (status & RADEON_FP_DETECT_STAT) {
queue_hotplug = true;
@@ -622,7 +682,7 @@ int r100_irq_process(struct radeon_device *rdev)
/* reset gui idle ack. the status bit is broken */
rdev->irq.gui_idle_acked = false;
if (queue_hotplug)
- queue_work(rdev->wq, &rdev->hotplug_work);
+ schedule_work(&rdev->hotplug_work);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS400:
@@ -2026,12 +2086,13 @@ int r100_asic_reset(struct radeon_device *rdev)
{
struct r100_mc_save save;
u32 status, tmp;
+ int ret = 0;
- r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -2071,11 +2132,11 @@ int r100_asic_reset(struct radeon_device *rdev)
G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
r100_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
void r100_set_common_regs(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h
index b121b6c678d4..eab91760fae0 100644
--- a/drivers/gpu/drm/radeon/r100d.h
+++ b/drivers/gpu/drm/radeon/r100d.h
@@ -551,7 +551,7 @@
#define S_000360_CUR2_LOCK(x) (((x) & 0x1) << 31)
#define G_000360_CUR2_LOCK(x) (((x) >> 31) & 0x1)
#define C_000360_CUR2_LOCK 0x7FFFFFFF
-#define R_0003C2_GENMO_WT 0x0003C0
+#define R_0003C2_GENMO_WT 0x0003C2
#define S_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) & 0x1) << 0)
#define G_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) >> 0) & 0x1)
#define C_0003C2_GENMO_MONO_ADDRESS_B 0xFE
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 34527e600fe9..cf862ca580bf 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -91,7 +91,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev)
int r;
if (rdev->gart.table.vram.robj) {
- WARN(1, "RV370 PCIE GART already initialized.\n");
+ WARN(1, "RV370 PCIE GART already initialized\n");
return 0;
}
/* Initialize common gart structure */
@@ -405,12 +405,13 @@ int r300_asic_reset(struct radeon_device *rdev)
{
struct r100_mc_save save;
u32 status, tmp;
+ int ret = 0;
- r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -451,11 +452,11 @@ int r300_asic_reset(struct radeon_device *rdev)
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
r100_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
/*
@@ -558,10 +559,7 @@ int rv370_get_pcie_lanes(struct radeon_device *rdev)
/* FIXME wait for idle */
- if (rdev->family < CHIP_R600)
- link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
- else
- link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+ link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) {
case RADEON_PCIE_LC_LINK_WIDTH_X0:
@@ -745,6 +743,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
break;
case 0x4E00:
/* RB3D_CCTL */
+ if ((idx_value & (1 << 10)) && /* CMASK_ENABLE */
+ p->rdev->cmask_filp != p->filp) {
+ DRM_ERROR("Invalid RB3D_CCTL: Cannot enable CMASK.\n");
+ return -EINVAL;
+ }
track->num_cb = ((idx_value >> 5) & 0x3) + 1;
break;
case 0x4E38:
@@ -787,6 +790,13 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
case 15:
track->cb[i].cpp = 2;
break;
+ case 5:
+ if (p->rdev->family < CHIP_RV515) {
+ DRM_ERROR("Invalid color buffer format (%d)!\n",
+ ((idx_value >> 21) & 0xF));
+ return -EINVAL;
+ }
+ /* Pass through. */
case 6:
track->cb[i].cpp = 4;
break;
@@ -1199,6 +1209,10 @@ static int r300_packet3_check(struct radeon_cs_parser *p,
if (p->rdev->hyperz_filp != p->filp)
return -EINVAL;
break;
+ case PACKET3_3D_CLEAR_CMASK:
+ if (p->rdev->cmask_filp != p->filp)
+ return -EINVAL;
+ break;
case PACKET3_NOP:
break;
default:
diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h
index 0c036c60d9df..1f519a5ffb8c 100644
--- a/drivers/gpu/drm/radeon/r300d.h
+++ b/drivers/gpu/drm/radeon/r300d.h
@@ -54,6 +54,7 @@
#define PACKET3_3D_DRAW_IMMD_2 0x35
#define PACKET3_3D_DRAW_INDX_2 0x36
#define PACKET3_3D_CLEAR_HIZ 0x37
+#define PACKET3_3D_CLEAR_CMASK 0x38
#define PACKET3_BITBLT_MULTI 0x9B
#define PACKET0(reg, n) (CP_PACKET0 | \
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 6ac1f604e29b..fc437059918f 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -355,6 +355,8 @@
#define AVIVO_D1CRTC_FRAME_COUNT 0x60a4
#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4
+#define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4
+
/* master controls */
#define AVIVO_DC_CRTC_MASTER_EN 0x60f8
#define AVIVO_DC_CRTC_TV_CONTROL 0x60fc
@@ -409,8 +411,10 @@
#define AVIVO_D1GRPH_X_END 0x6134
#define AVIVO_D1GRPH_Y_END 0x6138
#define AVIVO_D1GRPH_UPDATE 0x6144
+# define AVIVO_D1GRPH_SURFACE_UPDATE_PENDING (1 << 2)
# define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16)
#define AVIVO_D1GRPH_FLIP_CONTROL 0x6148
+# define AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0)
#define AVIVO_D1CUR_CONTROL 0x6400
# define AVIVO_D1CURSOR_EN (1 << 0)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 33952a12f0a3..aca2236268fa 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -83,6 +83,9 @@ MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin");
MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin");
MODULE_FIRMWARE("radeon/CYPRESS_me.bin");
MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin");
+MODULE_FIRMWARE("radeon/PALM_pfp.bin");
+MODULE_FIRMWARE("radeon/PALM_me.bin");
+MODULE_FIRMWARE("radeon/SUMO_rlc.bin");
int r600_debugfs_mc_info_init(struct radeon_device *rdev);
@@ -91,20 +94,15 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
void r600_irq_disable(struct radeon_device *rdev);
+static void r600_pcie_gen2_enable(struct radeon_device *rdev);
/* get temperature in millidegrees */
u32 rv6xx_get_temp(struct radeon_device *rdev)
{
u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
ASIC_T_SHIFT;
- u32 actual_temp = 0;
- if ((temp >> 7) & 1)
- actual_temp = 0;
- else
- actual_temp = (temp >> 1) & 0xff;
-
- return actual_temp * 1000;
+ return temp * 1000;
}
void r600_pm_get_dynpm_state(struct radeon_device *rdev)
@@ -884,12 +882,15 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev)
u32 tmp;
/* flush hdp cache so updates hit vram */
- if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
+ !(rdev->flags & RADEON_IS_AGP)) {
void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
u32 tmp;
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
* rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ * This seems to cause problems on some AGP cards. Just use the old
+ * method for them.
*/
WREG32(HDP_DEBUG1, 0);
tmp = readl((void __iomem *)ptr);
@@ -919,7 +920,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev)
int r;
if (rdev->gart.table.vram.robj) {
- WARN(1, "R600 PCIE GART already initialized.\n");
+ WARN(1, "R600 PCIE GART already initialized\n");
return 0;
}
/* Initialize common gart structure */
@@ -1167,7 +1168,7 @@ static void r600_mc_program(struct radeon_device *rdev)
* Note: GTT start, end, size should be initialized before calling this
* function on AGP platform.
*/
-void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
+static void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
{
u64 size_bf, size_af;
@@ -1201,8 +1202,10 @@ void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
mc->vram_end, mc->real_vram_size >> 20);
} else {
u64 base = 0;
- if (rdev->flags & RADEON_IS_IGP)
- base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
+ if (rdev->flags & RADEON_IS_IGP) {
+ base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF;
+ base <<= 24;
+ }
radeon_vram_location(rdev, &rdev->mc, base);
rdev->mc.gtt_base_align = 0;
radeon_gtt_location(rdev, mc);
@@ -1343,13 +1346,19 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev)
u32 srbm_status;
u32 grbm_status;
u32 grbm_status2;
+ struct r100_gpu_lockup *lockup;
int r;
+ if (rdev->family >= CHIP_RV770)
+ lockup = &rdev->config.rv770.lockup;
+ else
+ lockup = &rdev->config.r600.lockup;
+
srbm_status = RREG32(R_000E50_SRBM_STATUS);
grbm_status = RREG32(R_008010_GRBM_STATUS);
grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
if (!G_008010_GUI_ACTIVE(grbm_status)) {
- r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+ r100_gpu_lockup_update(lockup, &rdev->cp);
return false;
}
/* force CP activities */
@@ -1361,7 +1370,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev)
radeon_ring_unlock_commit(rdev);
}
rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
- return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+ return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp);
}
int r600_asic_reset(struct radeon_device *rdev)
@@ -2004,6 +2013,10 @@ int r600_init_microcode(struct radeon_device *rdev)
chip_name = "CYPRESS";
rlc_chip_name = "CYPRESS";
break;
+ case CHIP_PALM:
+ chip_name = "PALM";
+ rlc_chip_name = "SUMO";
+ break;
default: BUG();
}
@@ -2345,28 +2358,13 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg)
/* FIXME: implement */
}
-
-bool r600_card_posted(struct radeon_device *rdev)
-{
- uint32_t reg;
-
- /* first check CRTCs */
- reg = RREG32(D1CRTC_CONTROL) |
- RREG32(D2CRTC_CONTROL);
- if (reg & CRTC_EN)
- return true;
-
- /* then check MEM_SIZE, in case the crtcs are off */
- if (RREG32(CONFIG_MEMSIZE))
- return true;
-
- return false;
-}
-
int r600_startup(struct radeon_device *rdev)
{
int r;
+ /* enable pcie gen2 link */
+ r600_pcie_gen2_enable(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
@@ -2520,7 +2518,7 @@ int r600_init(struct radeon_device *rdev)
if (r)
return r;
/* Post card if necessary */
- if (!r600_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -2724,7 +2722,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev)
/* Allocate ring buffer */
if (rdev->ih.ring_obj == NULL) {
r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size,
- true,
+ PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT,
&rdev->ih.ring_obj);
if (r) {
@@ -2869,6 +2867,8 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(GRBM_INT_CNTL, 0);
WREG32(DxMODE_INT_MASK, 0);
+ WREG32(D1GRPH_INTERRUPT_CONTROL, 0);
+ WREG32(D2GRPH_INTERRUPT_CONTROL, 0);
if (ASIC_IS_DCE3(rdev)) {
WREG32(DCE3_DACA_AUTODETECT_INT_CONTROL, 0);
WREG32(DCE3_DACB_AUTODETECT_INT_CONTROL, 0);
@@ -2993,9 +2993,10 @@ int r600_irq_set(struct radeon_device *rdev)
u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
u32 grbm_int_cntl = 0;
u32 hdmi1, hdmi2;
+ u32 d1grph = 0, d2grph = 0;
if (!rdev->irq.installed) {
- WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+ WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
return -EINVAL;
}
/* don't enable anything if the ih is disabled */
@@ -3029,11 +3030,13 @@ int r600_irq_set(struct radeon_device *rdev)
cp_int_cntl |= RB_INT_ENABLE;
cp_int_cntl |= TIME_STAMP_INT_ENABLE;
}
- if (rdev->irq.crtc_vblank_int[0]) {
+ if (rdev->irq.crtc_vblank_int[0] ||
+ rdev->irq.pflip[0]) {
DRM_DEBUG("r600_irq_set: vblank 0\n");
mode_int |= D1MODE_VBLANK_INT_MASK;
}
- if (rdev->irq.crtc_vblank_int[1]) {
+ if (rdev->irq.crtc_vblank_int[1] ||
+ rdev->irq.pflip[1]) {
DRM_DEBUG("r600_irq_set: vblank 1\n");
mode_int |= D2MODE_VBLANK_INT_MASK;
}
@@ -3076,6 +3079,8 @@ int r600_irq_set(struct radeon_device *rdev)
WREG32(CP_INT_CNTL, cp_int_cntl);
WREG32(DxMODE_INT_MASK, mode_int);
+ WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
+ WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1);
if (ASIC_IS_DCE3(rdev)) {
@@ -3098,32 +3103,35 @@ int r600_irq_set(struct radeon_device *rdev)
return 0;
}
-static inline void r600_irq_ack(struct radeon_device *rdev,
- u32 *disp_int,
- u32 *disp_int_cont,
- u32 *disp_int_cont2)
+static inline void r600_irq_ack(struct radeon_device *rdev)
{
u32 tmp;
if (ASIC_IS_DCE3(rdev)) {
- *disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
- *disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
- *disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
+ rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
+ rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
+ rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
} else {
- *disp_int = RREG32(DISP_INTERRUPT_STATUS);
- *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
- *disp_int_cont2 = 0;
- }
-
- if (*disp_int & LB_D1_VBLANK_INTERRUPT)
+ rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+ rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+ rdev->irq.stat_regs.r600.disp_int_cont2 = 0;
+ }
+ rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS);
+ rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS);
+
+ if (rdev->irq.stat_regs.r600.d1grph_int & DxGRPH_PFLIP_INT_OCCURRED)
+ WREG32(D1GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.r600.d2grph_int & DxGRPH_PFLIP_INT_OCCURRED)
+ WREG32(D2GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR);
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT)
WREG32(D1MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK);
- if (*disp_int & LB_D1_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT)
WREG32(D1MODE_VLINE_STATUS, DxMODE_VLINE_ACK);
- if (*disp_int & LB_D2_VBLANK_INTERRUPT)
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT)
WREG32(D2MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK);
- if (*disp_int & LB_D2_VLINE_INTERRUPT)
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT)
WREG32(D2MODE_VLINE_STATUS, DxMODE_VLINE_ACK);
- if (*disp_int & DC_HPD1_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
@@ -3134,7 +3142,7 @@ static inline void r600_irq_ack(struct radeon_device *rdev,
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
}
}
- if (*disp_int & DC_HPD2_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
@@ -3145,7 +3153,7 @@ static inline void r600_irq_ack(struct radeon_device *rdev,
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
}
}
- if (*disp_int_cont & DC_HPD3_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
@@ -3156,18 +3164,18 @@ static inline void r600_irq_ack(struct radeon_device *rdev,
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
}
}
- if (*disp_int_cont & DC_HPD4_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
if (ASIC_IS_DCE32(rdev)) {
- if (*disp_int_cont2 & DC_HPD5_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
- if (*disp_int_cont2 & DC_HPD6_INTERRUPT) {
+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
@@ -3189,12 +3197,10 @@ static inline void r600_irq_ack(struct radeon_device *rdev,
void r600_irq_disable(struct radeon_device *rdev)
{
- u32 disp_int, disp_int_cont, disp_int_cont2;
-
r600_disable_interrupts(rdev);
/* Wait and acknowledge irq */
mdelay(1);
- r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2);
+ r600_irq_ack(rdev);
r600_disable_interrupt_state(rdev);
}
@@ -3257,7 +3263,7 @@ int r600_irq_process(struct radeon_device *rdev)
u32 wptr = r600_get_ih_wptr(rdev);
u32 rptr = rdev->ih.rptr;
u32 src_id, src_data;
- u32 ring_index, disp_int, disp_int_cont, disp_int_cont2;
+ u32 ring_index;
unsigned long flags;
bool queue_hotplug = false;
@@ -3278,7 +3284,7 @@ int r600_irq_process(struct radeon_device *rdev)
restart_ih:
/* display interrupts */
- r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2);
+ r600_irq_ack(rdev);
rdev->ih.wptr = wptr;
while (rptr != wptr) {
@@ -3291,17 +3297,21 @@ restart_ih:
case 1: /* D1 vblank/vline */
switch (src_data) {
case 0: /* D1 vblank */
- if (disp_int & LB_D1_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 0);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
- disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[0]) {
+ drm_handle_vblank(rdev->ddev, 0);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[0])
+ radeon_crtc_handle_flip(rdev, 0);
+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n");
}
break;
case 1: /* D1 vline */
- if (disp_int & LB_D1_VLINE_INTERRUPT) {
- disp_int &= ~LB_D1_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT;
DRM_DEBUG("IH: D1 vline\n");
}
break;
@@ -3313,17 +3323,21 @@ restart_ih:
case 5: /* D2 vblank/vline */
switch (src_data) {
case 0: /* D2 vblank */
- if (disp_int & LB_D2_VBLANK_INTERRUPT) {
- drm_handle_vblank(rdev->ddev, 1);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
- disp_int &= ~LB_D2_VBLANK_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[1]) {
+ drm_handle_vblank(rdev->ddev, 1);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[1])
+ radeon_crtc_handle_flip(rdev, 1);
+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n");
}
break;
case 1: /* D1 vline */
- if (disp_int & LB_D2_VLINE_INTERRUPT) {
- disp_int &= ~LB_D2_VLINE_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT;
DRM_DEBUG("IH: D2 vline\n");
}
break;
@@ -3335,43 +3349,43 @@ restart_ih:
case 19: /* HPD/DAC hotplug */
switch (src_data) {
case 0:
- if (disp_int & DC_HPD1_INTERRUPT) {
- disp_int &= ~DC_HPD1_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD1\n");
}
break;
case 1:
- if (disp_int & DC_HPD2_INTERRUPT) {
- disp_int &= ~DC_HPD2_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD2\n");
}
break;
case 4:
- if (disp_int_cont & DC_HPD3_INTERRUPT) {
- disp_int_cont &= ~DC_HPD3_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD3\n");
}
break;
case 5:
- if (disp_int_cont & DC_HPD4_INTERRUPT) {
- disp_int_cont &= ~DC_HPD4_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD4\n");
}
break;
case 10:
- if (disp_int_cont2 & DC_HPD5_INTERRUPT) {
- disp_int_cont2 &= ~DC_HPD5_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD5\n");
}
break;
case 12:
- if (disp_int_cont2 & DC_HPD6_INTERRUPT) {
- disp_int_cont2 &= ~DC_HPD6_INTERRUPT;
+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
+ rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD6\n");
}
@@ -3414,7 +3428,7 @@ restart_ih:
if (wptr != rdev->ih.wptr)
goto restart_ih;
if (queue_hotplug)
- queue_work(rdev->wq, &rdev->hotplug_work);
+ schedule_work(&rdev->hotplug_work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
spin_unlock_irqrestore(&rdev->ih.lock, flags);
@@ -3489,10 +3503,12 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev)
void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
{
/* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
- * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL.
+ * This seems to cause problems on some AGP cards. Just use the old
+ * method for them.
*/
if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
- rdev->vram_scratch.ptr) {
+ rdev->vram_scratch.ptr && !(rdev->flags & RADEON_IS_AGP)) {
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp;
@@ -3501,3 +3517,222 @@ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
} else
WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
}
+
+void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes)
+{
+ u32 link_width_cntl, mask, target_reg;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ /* x2 cards have a special sequence */
+ if (ASIC_IS_X2(rdev))
+ return;
+
+ /* FIXME wait for idle */
+
+ switch (lanes) {
+ case 0:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X0;
+ break;
+ case 1:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X1;
+ break;
+ case 2:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X2;
+ break;
+ case 4:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X4;
+ break;
+ case 8:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X8;
+ break;
+ case 12:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X12;
+ break;
+ case 16:
+ default:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X16;
+ break;
+ }
+
+ link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+ (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+ return;
+
+ if (link_width_cntl & R600_PCIE_LC_UPCONFIGURE_DIS)
+ return;
+
+ link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+ RADEON_PCIE_LC_RECONFIG_NOW |
+ R600_PCIE_LC_RENEGOTIATE_EN |
+ R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE);
+ link_width_cntl |= mask;
+
+ WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+
+ /* some northbridges can renegotiate the link rather than requiring
+ * a complete re-config.
+ * e.g., AMD 780/790 northbridges (pci ids: 0x5956, 0x5957, 0x5958, etc.)
+ */
+ if (link_width_cntl & R600_PCIE_LC_RENEGOTIATION_SUPPORT)
+ link_width_cntl |= R600_PCIE_LC_RENEGOTIATE_EN | R600_PCIE_LC_UPCONFIGURE_SUPPORT;
+ else
+ link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE;
+
+ WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl |
+ RADEON_PCIE_LC_RECONFIG_NOW));
+
+ if (rdev->family >= CHIP_RV770)
+ target_reg = R700_TARGET_AND_CURRENT_PROFILE_INDEX;
+ else
+ target_reg = R600_TARGET_AND_CURRENT_PROFILE_INDEX;
+
+ /* wait for lane set to complete */
+ link_width_cntl = RREG32(target_reg);
+ while (link_width_cntl == 0xffffffff)
+ link_width_cntl = RREG32(target_reg);
+
+}
+
+int r600_get_pcie_lanes(struct radeon_device *rdev)
+{
+ u32 link_width_cntl;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return 0;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return 0;
+
+ /* x2 cards have a special sequence */
+ if (ASIC_IS_X2(rdev))
+ return 0;
+
+ /* FIXME wait for idle */
+
+ link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) {
+ case RADEON_PCIE_LC_LINK_WIDTH_X0:
+ return 0;
+ case RADEON_PCIE_LC_LINK_WIDTH_X1:
+ return 1;
+ case RADEON_PCIE_LC_LINK_WIDTH_X2:
+ return 2;
+ case RADEON_PCIE_LC_LINK_WIDTH_X4:
+ return 4;
+ case RADEON_PCIE_LC_LINK_WIDTH_X8:
+ return 8;
+ case RADEON_PCIE_LC_LINK_WIDTH_X16:
+ default:
+ return 16;
+ }
+}
+
+static void r600_pcie_gen2_enable(struct radeon_device *rdev)
+{
+ u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp;
+ u16 link_cntl2;
+
+ if (radeon_pcie_gen2 == 0)
+ return;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ /* x2 cards have a special sequence */
+ if (ASIC_IS_X2(rdev))
+ return;
+
+ /* only RV6xx+ chips are supported */
+ if (rdev->family <= CHIP_R600)
+ return;
+
+ /* 55 nm r6xx asics */
+ if ((rdev->family == CHIP_RV670) ||
+ (rdev->family == CHIP_RV620) ||
+ (rdev->family == CHIP_RV635)) {
+ /* advertise upconfig capability */
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) {
+ lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT;
+ link_width_cntl &= ~(LC_LINK_WIDTH_MASK |
+ LC_RECONFIG_ARC_MISSING_ESCAPE);
+ link_width_cntl |= lanes | LC_RECONFIG_NOW | LC_RENEGOTIATE_EN;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ } else {
+ link_width_cntl |= LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ }
+ }
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+
+ /* 55 nm r6xx asics */
+ if ((rdev->family == CHIP_RV670) ||
+ (rdev->family == CHIP_RV620) ||
+ (rdev->family == CHIP_RV635)) {
+ WREG32(MM_CFGREGS_CNTL, 0x8);
+ link_cntl2 = RREG32(0x4088);
+ WREG32(MM_CFGREGS_CNTL, 0);
+ /* not supported yet */
+ if (link_cntl2 & SELECTABLE_DEEMPHASIS)
+ return;
+ }
+
+ speed_cntl &= ~LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK;
+ speed_cntl |= (0x3 << LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT);
+ speed_cntl &= ~LC_VOLTAGE_TIMER_SEL_MASK;
+ speed_cntl &= ~LC_FORCE_DIS_HW_SPEED_CHANGE;
+ speed_cntl |= LC_FORCE_EN_HW_SPEED_CHANGE;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ tmp = RREG32(0x541c);
+ WREG32(0x541c, tmp | 0x8);
+ WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN);
+ link_cntl2 = RREG16(0x4088);
+ link_cntl2 &= ~TARGET_LINK_SPEED_MASK;
+ link_cntl2 |= 0x2;
+ WREG16(0x4088, link_cntl2);
+ WREG32(MM_CFGREGS_CNTL, 0);
+
+ if ((rdev->family == CHIP_RV670) ||
+ (rdev->family == CHIP_RV620) ||
+ (rdev->family == CHIP_RV635)) {
+ training_cntl = RREG32_PCIE_P(PCIE_LC_TRAINING_CNTL);
+ training_cntl &= ~LC_POINT_7_PLUS_EN;
+ WREG32_PCIE_P(PCIE_LC_TRAINING_CNTL, training_cntl);
+ } else {
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+ }
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_GEN2_EN_STRAP;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ } else {
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */
+ if (1)
+ link_width_cntl |= LC_UPCONFIGURE_DIS;
+ else
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ }
+}
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index 8362974ef41a..86e5aa07f0db 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -501,7 +501,7 @@ int r600_blit_init(struct radeon_device *rdev)
obj_size += r6xx_ps_size * 4;
obj_size = ALIGN(obj_size, 256);
- r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("r600 failed to allocate shader\n");
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 37cc2aa9f923..7831e0890210 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -50,6 +50,7 @@ struct r600_cs_track {
u32 nsamples;
u32 cb_color_base_last[8];
struct radeon_bo *cb_color_bo[8];
+ u64 cb_color_bo_mc[8];
u32 cb_color_bo_offset[8];
struct radeon_bo *cb_color_frag_bo[8];
struct radeon_bo *cb_color_tile_bo[8];
@@ -67,6 +68,7 @@ struct r600_cs_track {
u32 db_depth_size;
u32 db_offset;
struct radeon_bo *db_bo;
+ u64 db_bo_mc;
};
static inline int r600_bpe_from_format(u32 *bpe, u32 format)
@@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format)
return 0;
}
+struct array_mode_checker {
+ int array_mode;
+ u32 group_size;
+ u32 nbanks;
+ u32 npipes;
+ u32 nsamples;
+ u32 bpe;
+};
+
+/* returns alignment in pixels for pitch/height/depth and bytes for base */
+static inline int r600_get_array_mode_alignment(struct array_mode_checker *values,
+ u32 *pitch_align,
+ u32 *height_align,
+ u32 *depth_align,
+ u64 *base_align)
+{
+ u32 tile_width = 8;
+ u32 tile_height = 8;
+ u32 macro_tile_width = values->nbanks;
+ u32 macro_tile_height = values->npipes;
+ u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples;
+ u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes;
+
+ switch (values->array_mode) {
+ case ARRAY_LINEAR_GENERAL:
+ /* technically tile_width/_height for pitch/height */
+ *pitch_align = 1; /* tile_width */
+ *height_align = 1; /* tile_height */
+ *depth_align = 1;
+ *base_align = 1;
+ break;
+ case ARRAY_LINEAR_ALIGNED:
+ *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe));
+ *height_align = tile_height;
+ *depth_align = 1;
+ *base_align = values->group_size;
+ break;
+ case ARRAY_1D_TILED_THIN1:
+ *pitch_align = max((u32)tile_width,
+ (u32)(values->group_size /
+ (tile_height * values->bpe * values->nsamples)));
+ *height_align = tile_height;
+ *depth_align = 1;
+ *base_align = values->group_size;
+ break;
+ case ARRAY_2D_TILED_THIN1:
+ *pitch_align = max((u32)macro_tile_width,
+ (u32)(((values->group_size / tile_height) /
+ (values->bpe * values->nsamples)) *
+ values->nbanks)) * tile_width;
+ *height_align = macro_tile_height * tile_height;
+ *depth_align = 1;
+ *base_align = max(macro_tile_bytes,
+ (*pitch_align) * values->bpe * (*height_align) * values->nsamples);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void r600_cs_track_init(struct r600_cs_track *track)
{
int i;
@@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track)
track->cb_color_info[i] = 0;
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+ track->cb_color_bo_mc[i] = 0xFFFFFFFF;
}
track->cb_target_mask = 0xFFFFFFFF;
track->cb_shader_mask = 0xFFFFFFFF;
track->db_bo = NULL;
+ track->db_bo_mc = 0xFFFFFFFF;
/* assume the biggest format and that htile is enabled */
track->db_depth_info = 7 | (1 << 25);
track->db_depth_view = 0xFFFFC000;
@@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track)
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
{
struct r600_cs_track *track = p->track;
- u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
+ u32 bpe = 0, slice_tile_max, size, tmp;
+ u32 height, height_align, pitch, pitch_align, depth_align;
+ u64 base_offset, base_align;
+ struct array_mode_checker array_check;
volatile u32 *ib = p->ib->ptr;
unsigned array_mode;
@@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
i, track->cb_color_info[i]);
return -EINVAL;
}
- /* pitch is the number of 8x8 tiles per row */
- pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
+ /* pitch in pixels */
+ pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8;
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
slice_tile_max *= 64;
- height = slice_tile_max / (pitch * 8);
+ height = slice_tile_max / pitch;
if (height > 8192)
height = 8192;
array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+
+ base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i];
+ array_check.array_mode = array_mode;
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = track->nsamples;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
+ G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
+ track->cb_color_info[i]);
+ return -EINVAL;
+ }
switch (array_mode) {
case V_0280A0_ARRAY_LINEAR_GENERAL:
- /* technically height & 0x7 */
break;
case V_0280A0_ARRAY_LINEAR_ALIGNED:
- pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_0280A0_ARRAY_1D_TILED_THIN1:
- pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
/* avoid breaking userspace */
if (height > 7)
height &= ~0x7;
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_0280A0_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED((height / 8), track->npipes)) {
- dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
default:
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -244,31 +293,42 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
track->cb_color_info[i]);
return -EINVAL;
}
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, height_align)) {
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+ __func__, __LINE__, height);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+ return -EINVAL;
+ }
+
/* check offset */
- tmp = height * pitch * 8 * bpe;
+ tmp = height * pitch * bpe;
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
/* the initial DDX does bad things with the CB size occasionally */
/* it rounds up height too far for slice tile max but the BO is smaller */
- tmp = (height - 7) * 8 * bpe;
- if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
- dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
- return -EINVAL;
- }
+ /* r600c,g also seem to flush at bad times in some apps resulting in
+ * bogus values here. So for linear just allow anything to avoid breaking
+ * broken userspace.
+ */
} else {
dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
return -EINVAL;
}
}
- if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
- dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
- return -EINVAL;
- }
/* limit max tile */
- tmp = (height * pitch * 8) >> 6;
+ tmp = (height * pitch) >> 6;
if (tmp < slice_tile_max)
slice_tile_max = tmp;
- tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
+ tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
ib[track->cb_color_size_idx[i]] = tmp;
return 0;
@@ -310,7 +370,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
/* Check depth buffer */
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
G_028800_Z_ENABLE(track->db_depth_control)) {
- u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max;
+ u32 nviews, bpe, ntiles, size, slice_tile_max;
+ u32 height, height_align, pitch, pitch_align, depth_align;
+ u64 base_offset, base_align;
+ struct array_mode_checker array_check;
+ int array_mode;
+
if (track->db_bo == NULL) {
dev_warn(p->dev, "z/stencil with no depth buffer\n");
return -EINVAL;
@@ -353,41 +418,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
} else {
size = radeon_bo_size(track->db_bo);
- pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
+ /* pitch in pixels */
+ pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
slice_tile_max *= 64;
- height = slice_tile_max / (pitch * 8);
+ height = slice_tile_max / pitch;
if (height > 8192)
height = 8192;
- switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+ base_offset = track->db_bo_mc + track->db_offset;
+ array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+ array_check.array_mode = array_mode;
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = track->nsamples;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_028010_ARRAY_MODE(track->db_depth_info),
+ track->db_depth_info);
+ return -EINVAL;
+ }
+ switch (array_mode) {
case V_028010_ARRAY_1D_TILED_THIN1:
- pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
/* don't break userspace */
height &= ~0x7;
- if (!IS_ALIGNED(height, 8)) {
- dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
case V_028010_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- if (!IS_ALIGNED((height / 8), track->npipes)) {
- dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
- __func__, __LINE__, height);
- return -EINVAL;
- }
break;
default:
dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
@@ -395,15 +453,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
track->db_depth_info);
return -EINVAL;
}
- if (!IS_ALIGNED(track->db_offset, track->group_size)) {
- dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, height_align)) {
+ dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+ __func__, __LINE__, height);
return -EINVAL;
}
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+ return -EINVAL;
+ }
+
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
tmp = ntiles * bpe * 64 * nviews;
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
- dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
radeon_bo_size(track->db_bo));
return -EINVAL;
@@ -954,6 +1024,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_base_last[tmp] = ib[idx];
track->cb_color_bo[tmp] = reloc->robj;
+ track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
break;
case DB_DEPTH_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
@@ -965,6 +1036,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
track->db_offset = radeon_get_ib_value(p, idx) << 8;
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->db_bo = reloc->robj;
+ track->db_bo_mc = reloc->lobj.gpu_offset;
break;
case DB_HTILE_DATA_BASE:
case SQ_PGM_START_FS:
@@ -1086,16 +1158,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
struct radeon_bo *texture,
struct radeon_bo *mipmap,
+ u64 base_offset,
+ u64 mip_offset,
u32 tiling_flags)
{
struct r600_cs_track *track = p->track;
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
- u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
+ u32 word0, word1, l0_size, mipmap_size;
+ u32 height_align, pitch, pitch_align, depth_align;
+ u64 base_align;
+ struct array_mode_checker array_check;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
+ /* convert to bytes */
+ base_offset <<= 8;
+ mip_offset <<= 8;
+
word0 = radeon_get_ib_value(p, idx + 0);
if (tiling_flags & RADEON_TILING_MACRO)
word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
@@ -1128,46 +1209,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
return -EINVAL;
}
- pitch = G_038000_PITCH(word0) + 1;
- switch (G_038000_TILE_MODE(word0)) {
- case V_038000_ARRAY_LINEAR_GENERAL:
- pitch_align = 1;
- /* XXX check height align */
- break;
- case V_038000_ARRAY_LINEAR_ALIGNED:
- pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- case V_038000_ARRAY_1D_TILED_THIN1:
- pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- case V_038000_ARRAY_2D_TILED_THIN1:
- pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
- return -EINVAL;
- }
- /* XXX check height align */
- break;
- default:
- dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
- G_038000_TILE_MODE(word0), word0);
+ /* pitch in texels */
+ pitch = (G_038000_PITCH(word0) + 1) * 8;
+ array_check.array_mode = G_038000_TILE_MODE(word0);
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = 1;
+ array_check.bpe = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
+ __func__, __LINE__, G_038000_TILE_MODE(word0));
+ return -EINVAL;
+ }
+
+ /* XXX check height as well... */
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
+ __func__, __LINE__, base_offset);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(mip_offset, base_align)) {
+ dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
+ __func__, __LINE__, mip_offset);
return -EINVAL;
}
- /* XXX check offset align */
word0 = radeon_get_ib_value(p, idx + 4);
word1 = radeon_get_ib_value(p, idx + 5);
@@ -1402,7 +1475,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
mipmap = reloc->robj;
r = r600_check_texture_resource(p, idx+(i*7)+1,
- texture, mipmap, reloc->lobj.tiling_flags);
+ texture, mipmap,
+ base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
+ mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
+ reloc->lobj.tiling_flags);
if (r)
return r;
ib[idx+1+(i*7)+2] += base_offset;
diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h
index d84612ae47e0..33cda016b083 100644
--- a/drivers/gpu/drm/radeon/r600_reg.h
+++ b/drivers/gpu/drm/radeon/r600_reg.h
@@ -86,6 +86,7 @@
#define R600_HDP_NONSURFACE_BASE 0x2c04
#define R600_BUS_CNTL 0x5420
+# define R600_BIOS_ROM_DIS (1 << 1)
#define R600_CONFIG_CNTL 0x5424
#define R600_CONFIG_MEMSIZE 0x5428
#define R600_CONFIG_F0_BASE 0x542C
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 966a793e225b..a5d898b4bad2 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -51,6 +51,12 @@
#define PTE_READABLE (1 << 5)
#define PTE_WRITEABLE (1 << 6)
+/* tiling bits */
+#define ARRAY_LINEAR_GENERAL 0x00000000
+#define ARRAY_LINEAR_ALIGNED 0x00000001
+#define ARRAY_1D_TILED_THIN1 0x00000002
+#define ARRAY_2D_TILED_THIN1 0x00000004
+
/* Registers */
#define ARB_POP 0x2418
#define ENABLE_TC128 (1 << 30)
@@ -722,6 +728,54 @@
/* DCE 3.2 */
# define DC_HPDx_EN (1 << 28)
+#define D1GRPH_INTERRUPT_STATUS 0x6158
+#define D2GRPH_INTERRUPT_STATUS 0x6958
+# define DxGRPH_PFLIP_INT_OCCURRED (1 << 0)
+# define DxGRPH_PFLIP_INT_CLEAR (1 << 8)
+#define D1GRPH_INTERRUPT_CONTROL 0x615c
+#define D2GRPH_INTERRUPT_CONTROL 0x695c
+# define DxGRPH_PFLIP_INT_MASK (1 << 0)
+# define DxGRPH_PFLIP_INT_TYPE (1 << 8)
+
+/* PCIE link stuff */
+#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
+# define LC_POINT_7_PLUS_EN (1 << 6)
+#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
+# define LC_LINK_WIDTH_SHIFT 0
+# define LC_LINK_WIDTH_MASK 0x7
+# define LC_LINK_WIDTH_X0 0
+# define LC_LINK_WIDTH_X1 1
+# define LC_LINK_WIDTH_X2 2
+# define LC_LINK_WIDTH_X4 3
+# define LC_LINK_WIDTH_X8 4
+# define LC_LINK_WIDTH_X16 6
+# define LC_LINK_WIDTH_RD_SHIFT 4
+# define LC_LINK_WIDTH_RD_MASK 0x70
+# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define LC_RECONFIG_NOW (1 << 8)
+# define LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define LC_RENEGOTIATE_EN (1 << 10)
+# define LC_SHORT_RECONFIG_EN (1 << 11)
+# define LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define LC_UPCONFIGURE_DIS (1 << 13)
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+#define MM_CFGREGS_CNTL 0x544c
+# define MM_WR_TO_CFG_EN (1 << 3)
+#define LINK_CNTL2 0x88 /* F0 */
+# define TARGET_LINK_SPEED_MASK (0xf << 0)
+# define SELECTABLE_DEEMPHASIS (1 << 6)
+
/*
* PM4
*/
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 73f600d39ad4..71d2a554bbe6 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -69,6 +69,7 @@
#include <ttm/ttm_bo_driver.h>
#include <ttm/ttm_placement.h>
#include <ttm/ttm_module.h>
+#include <ttm/ttm_execbuf_util.h>
#include "radeon_family.h"
#include "radeon_mode.h"
@@ -91,6 +92,7 @@ extern int radeon_tv;
extern int radeon_audio;
extern int radeon_disp_priority;
extern int radeon_hw_i2c;
+extern int radeon_pcie_gen2;
/*
* Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -180,6 +182,7 @@ void rs690_pm_info(struct radeon_device *rdev);
extern u32 rv6xx_get_temp(struct radeon_device *rdev);
extern u32 rv770_get_temp(struct radeon_device *rdev);
extern u32 evergreen_get_temp(struct radeon_device *rdev);
+extern u32 sumo_get_temp(struct radeon_device *rdev);
/*
* Fences.
@@ -259,13 +262,12 @@ struct radeon_bo {
};
struct radeon_bo_list {
- struct list_head list;
+ struct ttm_validate_buffer tv;
struct radeon_bo *bo;
uint64_t gpu_offset;
unsigned rdomain;
unsigned wdomain;
u32 tiling_flags;
- bool reserved;
};
/*
@@ -377,11 +379,56 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
/*
* IRQS.
*/
+
+struct radeon_unpin_work {
+ struct work_struct work;
+ struct radeon_device *rdev;
+ int crtc_id;
+ struct radeon_fence *fence;
+ struct drm_pending_vblank_event *event;
+ struct radeon_bo *old_rbo;
+ u64 new_crtc_base;
+};
+
+struct r500_irq_stat_regs {
+ u32 disp_int;
+};
+
+struct r600_irq_stat_regs {
+ u32 disp_int;
+ u32 disp_int_cont;
+ u32 disp_int_cont2;
+ u32 d1grph_int;
+ u32 d2grph_int;
+};
+
+struct evergreen_irq_stat_regs {
+ u32 disp_int;
+ u32 disp_int_cont;
+ u32 disp_int_cont2;
+ u32 disp_int_cont3;
+ u32 disp_int_cont4;
+ u32 disp_int_cont5;
+ u32 d1grph_int;
+ u32 d2grph_int;
+ u32 d3grph_int;
+ u32 d4grph_int;
+ u32 d5grph_int;
+ u32 d6grph_int;
+};
+
+union radeon_irq_stat_regs {
+ struct r500_irq_stat_regs r500;
+ struct r600_irq_stat_regs r600;
+ struct evergreen_irq_stat_regs evergreen;
+};
+
struct radeon_irq {
bool installed;
bool sw_int;
/* FIXME: use a define max crtc rather than hardcode it */
bool crtc_vblank_int[6];
+ bool pflip[6];
wait_queue_head_t vblank_queue;
/* FIXME: use defines for max hpd/dacs */
bool hpd[6];
@@ -392,12 +439,17 @@ struct radeon_irq {
bool hdmi[2];
spinlock_t sw_lock;
int sw_refcount;
+ union radeon_irq_stat_regs stat_regs;
+ spinlock_t pflip_lock[6];
+ int pflip_refcount[6];
};
int radeon_irq_kms_init(struct radeon_device *rdev);
void radeon_irq_kms_fini(struct radeon_device *rdev);
void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev);
void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev);
+void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc);
+void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
/*
* CP & ring.
@@ -687,6 +739,8 @@ enum radeon_int_thermal_type {
THERMAL_TYPE_RV6XX,
THERMAL_TYPE_RV770,
THERMAL_TYPE_EVERGREEN,
+ THERMAL_TYPE_SUMO,
+ THERMAL_TYPE_NI,
};
struct radeon_voltage {
@@ -770,6 +824,9 @@ struct radeon_pm {
u32 current_sclk;
u32 current_mclk;
u32 current_vddc;
+ u32 default_sclk;
+ u32 default_mclk;
+ u32 default_vddc;
struct radeon_i2c_chan *i2c_bus;
/* selected pm method */
enum radeon_pm_method pm_method;
@@ -881,6 +938,10 @@ struct radeon_asic {
void (*pm_finish)(struct radeon_device *rdev);
void (*pm_init_profile)(struct radeon_device *rdev);
void (*pm_get_dynpm_state)(struct radeon_device *rdev);
+ /* pageflipping */
+ void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
+ u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
+ void (*post_page_flip)(struct radeon_device *rdev, int crtc);
};
/*
@@ -975,6 +1036,7 @@ struct evergreen_asic {
unsigned tiling_npipes;
unsigned tiling_group_size;
unsigned tile_config;
+ struct r100_gpu_lockup lockup;
};
union radeon_asic_config {
@@ -1091,11 +1153,11 @@ struct radeon_device {
const struct firmware *me_fw; /* all family ME firmware */
const struct firmware *pfp_fw; /* r6/700 PFP firmware */
const struct firmware *rlc_fw; /* r6/700 RLC firmware */
+ const struct firmware *mc_fw; /* NI MC firmware */
struct r600_blit r600_blit;
struct r700_vram_scratch vram_scratch;
int msi_enabled; /* msi enabled */
struct r600_ih ih; /* r6/700 interrupt ring */
- struct workqueue_struct *wq;
struct work_struct hotplug_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@@ -1110,10 +1172,10 @@ struct radeon_device {
uint8_t audio_status_bits;
uint8_t audio_category_code;
- bool powered_down;
struct notifier_block acpi_nb;
- /* only one userspace can use Hyperz features at a time */
+ /* only one userspace can use Hyperz features or CMASK at a time */
struct drm_file *hyperz_filp;
+ struct drm_file *cmask_filp;
/* i2c buses */
struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS];
};
@@ -1188,6 +1250,8 @@ static inline void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v)
*/
#define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg))
#define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg))
+#define RREG16(reg) readw(((void __iomem *)rdev->rmmio) + (reg))
+#define WREG16(reg, v) writew(v, ((void __iomem *)rdev->rmmio) + (reg))
#define RREG32(reg) r100_mm_rreg(rdev, (reg))
#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg)))
#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v))
@@ -1261,10 +1325,25 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
(rdev->family == CHIP_RV410) || \
(rdev->family == CHIP_RS400) || \
(rdev->family == CHIP_RS480))
+#define ASIC_IS_X2(rdev) ((rdev->ddev->pdev->device == 0x9441) || \
+ (rdev->ddev->pdev->device == 0x9443) || \
+ (rdev->ddev->pdev->device == 0x944B) || \
+ (rdev->ddev->pdev->device == 0x9506) || \
+ (rdev->ddev->pdev->device == 0x9509) || \
+ (rdev->ddev->pdev->device == 0x950F) || \
+ (rdev->ddev->pdev->device == 0x689C) || \
+ (rdev->ddev->pdev->device == 0x689D))
#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
+#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \
+ (rdev->family == CHIP_RS690) || \
+ (rdev->family == CHIP_RS740) || \
+ (rdev->family >= CHIP_R600))
#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
#define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
+#define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM) && \
+ (rdev->flags & RADEON_IS_IGP))
+#define ASIC_IS_DCE5(rdev) ((rdev->family >= CHIP_BARTS))
/*
* BIOS helpers.
@@ -1340,6 +1419,9 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))
#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev))
#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev))
+#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pre_page_flip((rdev), (crtc))
+#define radeon_page_flip(rdev, crtc, base) rdev->asic->page_flip((rdev), (crtc), (base))
+#define radeon_post_page_flip(rdev, crtc) rdev->asic->post_page_flip((rdev), (crtc))
/* Common functions */
/* AGP */
@@ -1368,67 +1450,7 @@ extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc
extern int radeon_resume_kms(struct drm_device *dev);
extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
-/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
-extern void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
-extern bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp);
-
-/* rv200,rv250,rv280 */
-extern void r200_set_safe_registers(struct radeon_device *rdev);
-
-/* r300,r350,rv350,rv370,rv380 */
-extern void r300_set_reg_safe(struct radeon_device *rdev);
-extern void r300_mc_program(struct radeon_device *rdev);
-extern void r300_mc_init(struct radeon_device *rdev);
-extern void r300_clock_startup(struct radeon_device *rdev);
-extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
-extern int rv370_pcie_gart_init(struct radeon_device *rdev);
-extern void rv370_pcie_gart_fini(struct radeon_device *rdev);
-extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
-extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
-
-/* r420,r423,rv410 */
-extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg);
-extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v);
-extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
-extern void r420_pipes_init(struct radeon_device *rdev);
-
-/* rv515 */
-struct rv515_mc_save {
- u32 d1vga_control;
- u32 d2vga_control;
- u32 vga_render_control;
- u32 vga_hdp_control;
- u32 d1crtc_control;
- u32 d2crtc_control;
-};
-extern void rv515_bandwidth_avivo_update(struct radeon_device *rdev);
-extern void rv515_vga_render_disable(struct radeon_device *rdev);
-extern void rv515_set_safe_registers(struct radeon_device *rdev);
-extern void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save);
-extern void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save);
-extern void rv515_clock_startup(struct radeon_device *rdev);
-extern void rv515_debugfs(struct radeon_device *rdev);
-extern int rv515_suspend(struct radeon_device *rdev);
-
-/* rs400 */
-extern int rs400_gart_init(struct radeon_device *rdev);
-extern int rs400_gart_enable(struct radeon_device *rdev);
-extern void rs400_gart_adjust_size(struct radeon_device *rdev);
-extern void rs400_gart_disable(struct radeon_device *rdev);
-extern void rs400_gart_fini(struct radeon_device *rdev);
-
-/* rs600 */
-extern void rs600_set_safe_registers(struct radeon_device *rdev);
-extern int rs600_irq_set(struct radeon_device *rdev);
-extern void rs600_irq_disable(struct radeon_device *rdev);
-
-/* rs690, rs740 */
-extern void rs690_line_buffer_adjust(struct radeon_device *rdev,
- struct drm_display_mode *mode1,
- struct drm_display_mode *mode2);
-
/* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */
-extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern bool r600_card_posted(struct radeon_device *rdev);
extern void r600_cp_stop(struct radeon_device *rdev);
extern int r600_cp_start(struct radeon_device *rdev);
@@ -1474,6 +1496,7 @@ extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mo
extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
+extern void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern void r700_cp_stop(struct radeon_device *rdev);
extern void r700_cp_fini(struct radeon_device *rdev);
extern void evergreen_disable_interrupt_state(struct radeon_device *rdev);
@@ -1481,6 +1504,9 @@ extern int evergreen_irq_set(struct radeon_device *rdev);
extern int evergreen_blit_init(struct radeon_device *rdev);
extern void evergreen_blit_fini(struct radeon_device *rdev);
+extern int ni_init_microcode(struct radeon_device *rdev);
+extern int btc_mc_load_microcode(struct radeon_device *rdev);
+
/* radeon_acpi.c */
#if defined(CONFIG_ACPI)
extern int radeon_acpi_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 64fb89ecbf74..3a1b16186224 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
rdev->mc_rreg = &rs600_mc_rreg;
rdev->mc_wreg = &rs600_mc_wreg;
}
- if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) {
+ if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) {
rdev->pciep_rreg = &r600_pciep_rreg;
rdev->pciep_wreg = &r600_pciep_wreg;
}
@@ -171,6 +171,9 @@ static struct radeon_asic r100_asic = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r100_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic r200_asic = {
@@ -215,6 +218,9 @@ static struct radeon_asic r200_asic = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r100_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic r300_asic = {
@@ -260,6 +266,9 @@ static struct radeon_asic r300_asic = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r100_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic r300_asic_pcie = {
@@ -304,6 +313,9 @@ static struct radeon_asic r300_asic_pcie = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r100_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic r420_asic = {
@@ -349,6 +361,9 @@ static struct radeon_asic r420_asic = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r420_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic rs400_asic = {
@@ -394,6 +409,9 @@ static struct radeon_asic rs400_asic = {
.pm_finish = &r100_pm_finish,
.pm_init_profile = &r100_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
};
static struct radeon_asic rs600_asic = {
@@ -439,6 +457,9 @@ static struct radeon_asic rs600_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r420_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic rs690_asic = {
@@ -484,6 +505,9 @@ static struct radeon_asic rs690_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r420_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic rv515_asic = {
@@ -529,6 +553,9 @@ static struct radeon_asic rv515_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r420_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic r520_asic = {
@@ -574,6 +601,9 @@ static struct radeon_asic r520_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r420_pm_init_profile,
.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic r600_asic = {
@@ -601,8 +631,8 @@ static struct radeon_asic r600_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = NULL,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_surface_reg = r600_set_surface_reg,
.clear_surface_reg = r600_clear_surface_reg,
@@ -618,6 +648,9 @@ static struct radeon_asic r600_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r600_pm_init_profile,
.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic rs780_asic = {
@@ -662,6 +695,9 @@ static struct radeon_asic rs780_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &rs780_pm_init_profile,
.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic rv770_asic = {
@@ -689,8 +725,8 @@ static struct radeon_asic rv770_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = NULL,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r600_set_surface_reg,
.clear_surface_reg = r600_clear_surface_reg,
@@ -706,6 +742,9 @@ static struct radeon_asic rv770_asic = {
.pm_finish = &rs600_pm_finish,
.pm_init_profile = &r600_pm_init_profile,
.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rv770_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
};
static struct radeon_asic evergreen_asic = {
@@ -733,6 +772,95 @@ static struct radeon_asic evergreen_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
+ .set_clock_gating = NULL,
+ .set_surface_reg = r600_set_surface_reg,
+ .clear_surface_reg = r600_clear_surface_reg,
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .hpd_init = &evergreen_hpd_init,
+ .hpd_fini = &evergreen_hpd_fini,
+ .hpd_sense = &evergreen_hpd_sense,
+ .hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .gui_idle = &r600_gui_idle,
+ .pm_misc = &evergreen_pm_misc,
+ .pm_prepare = &evergreen_pm_prepare,
+ .pm_finish = &evergreen_pm_finish,
+ .pm_init_profile = &r600_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+};
+
+static struct radeon_asic sumo_asic = {
+ .init = &evergreen_init,
+ .fini = &evergreen_fini,
+ .suspend = &evergreen_suspend,
+ .resume = &evergreen_resume,
+ .cp_commit = &r600_cp_commit,
+ .gpu_is_lockup = &evergreen_gpu_is_lockup,
+ .asic_reset = &evergreen_asic_reset,
+ .vga_set_state = &r600_vga_set_state,
+ .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
+ .gart_set_page = &rs600_gart_set_page,
+ .ring_test = &r600_ring_test,
+ .ring_ib_execute = &r600_ring_ib_execute,
+ .irq_set = &evergreen_irq_set,
+ .irq_process = &evergreen_irq_process,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .fence_ring_emit = &r600_fence_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .copy_blit = &evergreen_copy_blit,
+ .copy_dma = &evergreen_copy_blit,
+ .copy = &evergreen_copy_blit,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = NULL,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ .set_surface_reg = r600_set_surface_reg,
+ .clear_surface_reg = r600_clear_surface_reg,
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .hpd_init = &evergreen_hpd_init,
+ .hpd_fini = &evergreen_hpd_fini,
+ .hpd_sense = &evergreen_hpd_sense,
+ .hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .gui_idle = &r600_gui_idle,
+ .pm_misc = &evergreen_pm_misc,
+ .pm_prepare = &evergreen_pm_prepare,
+ .pm_finish = &evergreen_pm_finish,
+ .pm_init_profile = &rs780_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+};
+
+static struct radeon_asic btc_asic = {
+ .init = &evergreen_init,
+ .fini = &evergreen_fini,
+ .suspend = &evergreen_suspend,
+ .resume = &evergreen_resume,
+ .cp_commit = &r600_cp_commit,
+ .gpu_is_lockup = &evergreen_gpu_is_lockup,
+ .asic_reset = &evergreen_asic_reset,
+ .vga_set_state = &r600_vga_set_state,
+ .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
+ .gart_set_page = &rs600_gart_set_page,
+ .ring_test = &r600_ring_test,
+ .ring_ib_execute = &r600_ring_ib_execute,
+ .irq_set = &evergreen_irq_set,
+ .irq_process = &evergreen_irq_process,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .fence_ring_emit = &r600_fence_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .copy_blit = &evergreen_copy_blit,
+ .copy_dma = &evergreen_copy_blit,
+ .copy = &evergreen_copy_blit,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
@@ -749,6 +877,9 @@ static struct radeon_asic evergreen_asic = {
.pm_finish = &evergreen_pm_finish,
.pm_init_profile = &r600_pm_init_profile,
.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
};
int radeon_asic_init(struct radeon_device *rdev)
@@ -835,6 +966,14 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_HEMLOCK:
rdev->asic = &evergreen_asic;
break;
+ case CHIP_PALM:
+ rdev->asic = &sumo_asic;
+ break;
+ case CHIP_BARTS:
+ case CHIP_TURKS:
+ case CHIP_CAICOS:
+ rdev->asic = &btc_asic;
+ break;
default:
/* FIXME: not supported yet */
return -EINVAL;
@@ -849,7 +988,9 @@ int radeon_asic_init(struct radeon_device *rdev)
if (rdev->flags & RADEON_SINGLE_CRTC)
rdev->num_crtc = 1;
else {
- if (ASIC_IS_DCE4(rdev))
+ if (ASIC_IS_DCE41(rdev))
+ rdev->num_crtc = 2;
+ else if (ASIC_IS_DCE4(rdev))
rdev->num_crtc = 6;
else
rdev->num_crtc = 2;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 740988244143..e01f07718539 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -102,6 +102,11 @@ int r100_pci_gart_enable(struct radeon_device *rdev);
void r100_pci_gart_disable(struct radeon_device *rdev);
int r100_debugfs_mc_info_init(struct radeon_device *rdev);
int r100_gui_wait_for_idle(struct radeon_device *rdev);
+void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup,
+ struct radeon_cp *cp);
+bool r100_gpu_cp_is_lockup(struct radeon_device *rdev,
+ struct r100_gpu_lockup *lockup,
+ struct radeon_cp *cp);
void r100_ib_fini(struct radeon_device *rdev);
int r100_ib_init(struct radeon_device *rdev);
void r100_irq_disable(struct radeon_device *rdev);
@@ -130,15 +135,19 @@ extern void r100_pm_prepare(struct radeon_device *rdev);
extern void r100_pm_finish(struct radeon_device *rdev);
extern void r100_pm_init_profile(struct radeon_device *rdev);
extern void r100_pm_get_dynpm_state(struct radeon_device *rdev);
+extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc);
+extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
+extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
/*
* r200,rv250,rs300,rv280
*/
extern int r200_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_pages,
struct radeon_fence *fence);
+void r200_set_safe_registers(struct radeon_device *rdev);
/*
* r300,r350,rv350,rv380
@@ -159,6 +168,15 @@ extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
+extern void r300_set_reg_safe(struct radeon_device *rdev);
+extern void r300_mc_program(struct radeon_device *rdev);
+extern void r300_mc_init(struct radeon_device *rdev);
+extern void r300_clock_startup(struct radeon_device *rdev);
+extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
+extern int rv370_pcie_gart_init(struct radeon_device *rdev);
+extern void rv370_pcie_gart_fini(struct radeon_device *rdev);
+extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
+extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
/*
* r420,r423,rv410
@@ -168,6 +186,10 @@ extern void r420_fini(struct radeon_device *rdev);
extern int r420_suspend(struct radeon_device *rdev);
extern int r420_resume(struct radeon_device *rdev);
extern void r420_pm_init_profile(struct radeon_device *rdev);
+extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg);
+extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v);
+extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
+extern void r420_pipes_init(struct radeon_device *rdev);
/*
* rs400,rs480
@@ -180,6 +202,12 @@ void rs400_gart_tlb_flush(struct radeon_device *rdev);
int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+int rs400_gart_init(struct radeon_device *rdev);
+int rs400_gart_enable(struct radeon_device *rdev);
+void rs400_gart_adjust_size(struct radeon_device *rdev);
+void rs400_gart_disable(struct radeon_device *rdev);
+void rs400_gart_fini(struct radeon_device *rdev);
+
/*
* rs600.
@@ -191,6 +219,7 @@ extern int rs600_suspend(struct radeon_device *rdev);
extern int rs600_resume(struct radeon_device *rdev);
int rs600_irq_set(struct radeon_device *rdev);
int rs600_irq_process(struct radeon_device *rdev);
+void rs600_irq_disable(struct radeon_device *rdev);
u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);
void rs600_gart_tlb_flush(struct radeon_device *rdev);
int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
@@ -205,6 +234,11 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev,
extern void rs600_pm_misc(struct radeon_device *rdev);
extern void rs600_pm_prepare(struct radeon_device *rdev);
extern void rs600_pm_finish(struct radeon_device *rdev);
+extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc);
+extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
+extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc);
+void rs600_set_safe_registers(struct radeon_device *rdev);
+
/*
* rs690,rs740
@@ -216,10 +250,21 @@ int rs690_suspend(struct radeon_device *rdev);
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rs690_bandwidth_update(struct radeon_device *rdev);
+void rs690_line_buffer_adjust(struct radeon_device *rdev,
+ struct drm_display_mode *mode1,
+ struct drm_display_mode *mode2);
/*
* rv515
*/
+struct rv515_mc_save {
+ u32 d1vga_control;
+ u32 d2vga_control;
+ u32 vga_render_control;
+ u32 vga_hdp_control;
+ u32 d1crtc_control;
+ u32 d2crtc_control;
+};
int rv515_init(struct radeon_device *rdev);
void rv515_fini(struct radeon_device *rdev);
uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
@@ -230,6 +275,14 @@ void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rv515_bandwidth_update(struct radeon_device *rdev);
int rv515_resume(struct radeon_device *rdev);
int rv515_suspend(struct radeon_device *rdev);
+void rv515_bandwidth_avivo_update(struct radeon_device *rdev);
+void rv515_vga_render_disable(struct radeon_device *rdev);
+void rv515_set_safe_registers(struct radeon_device *rdev);
+void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save);
+void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save);
+void rv515_clock_startup(struct radeon_device *rdev);
+void rv515_debugfs(struct radeon_device *rdev);
+
/*
* r520,rv530,rv560,rv570,r580
@@ -278,6 +331,8 @@ extern void r600_pm_misc(struct radeon_device *rdev);
extern void r600_pm_init_profile(struct radeon_device *rdev);
extern void rs780_pm_init_profile(struct radeon_device *rdev);
extern void r600_pm_get_dynpm_state(struct radeon_device *rdev);
+extern void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes);
+extern int r600_get_pcie_lanes(struct radeon_device *rdev);
/*
* rv770,rv730,rv710,rv740
@@ -287,6 +342,7 @@ void rv770_fini(struct radeon_device *rdev);
int rv770_suspend(struct radeon_device *rdev);
int rv770_resume(struct radeon_device *rdev);
extern void rv770_pm_misc(struct radeon_device *rdev);
+extern u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
/*
* evergreen
@@ -314,5 +370,8 @@ extern int evergreen_cs_parse(struct radeon_cs_parser *p);
extern void evergreen_pm_misc(struct radeon_device *rdev);
extern void evergreen_pm_prepare(struct radeon_device *rdev);
extern void evergreen_pm_finish(struct radeon_device *rdev);
+extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc);
+extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
+extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc);
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 04cac7ec9039..1573202a6418 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -37,7 +37,7 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
extern void radeon_link_encoder_connector(struct drm_device *dev);
extern void
radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum,
- uint32_t supported_device);
+ uint32_t supported_device, u16 caps);
/* from radeon_connector.c */
extern void
@@ -98,6 +98,14 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
}
}
+ /* some DCE3 boards have bad data for this entry */
+ if (ASIC_IS_DCE3(rdev)) {
+ if ((i == 4) &&
+ (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+ (gpio->sucI2cId.ucAccess == 0x94))
+ gpio->sucI2cId.ucAccess = 0x14;
+ }
+
if (gpio->sucI2cId.ucAccess == id) {
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
@@ -174,6 +182,14 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
}
}
+ /* some DCE3 boards have bad data for this entry */
+ if (ASIC_IS_DCE3(rdev)) {
+ if ((i == 4) &&
+ (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+ (gpio->sucI2cId.ucAccess == 0x94))
+ gpio->sucI2cId.ucAccess = 0x14;
+ }
+
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
@@ -297,7 +313,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
uint16_t *line_mux,
struct radeon_hpd *hpd)
{
- struct radeon_device *rdev = dev->dev_private;
/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
if ((dev->pdev->device == 0x791e) &&
@@ -372,6 +387,17 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
*line_mux = 0x90;
}
+ /* mac rv630 */
+ if ((dev->pdev->device == 0x9588) &&
+ (dev->pdev->subsystem_vendor == 0x106b) &&
+ (dev->pdev->subsystem_device == 0x00a6)) {
+ if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
+ (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
+ *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
+ *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
+ }
+ }
+
/* ASUS HD 3600 XT board lists the DVI port as HDMI */
if ((dev->pdev->device == 0x9598) &&
(dev->pdev->subsystem_vendor == 0x1043) &&
@@ -409,21 +435,23 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
}
}
- /* Acer laptop reports DVI-D as DVI-I and hpd pins reversed */
+ /* Acer laptop (Acer TravelMate 5730G) has an HDMI port
+ * on the laptop and a DVI port on the docking station and
+ * both share the same encoder, hpd pin, and ddc line.
+ * So while the bios table is technically correct,
+ * we drop the DVI port here since xrandr has no concept of
+ * encoders and will try and drive both connectors
+ * with different crtcs which isn't possible on the hardware
+ * side and leaves no crtcs for LVDS or VGA.
+ */
if ((dev->pdev->device == 0x95c4) &&
(dev->pdev->subsystem_vendor == 0x1025) &&
(dev->pdev->subsystem_device == 0x013c)) {
- struct radeon_gpio_rec gpio;
-
if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
(supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
- gpio = radeon_lookup_gpio(rdev, 6);
- *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
+ /* actually it's a DVI-D port not DVI-I */
*connector_type = DRM_MODE_CONNECTOR_DVID;
- } else if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
- (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
- gpio = radeon_lookup_gpio(rdev, 7);
- *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
+ return false;
}
}
@@ -509,6 +537,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
u16 size, data_offset;
u8 frev, crev;
ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+ ATOM_ENCODER_OBJECT_TABLE *enc_obj;
ATOM_OBJECT_TABLE *router_obj;
ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
ATOM_OBJECT_HEADER *obj_header;
@@ -526,8 +555,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
if (crev < 2)
return false;
- router.valid = false;
-
obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
(ctx->bios + data_offset +
@@ -535,6 +562,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
(ctx->bios + data_offset +
le16_to_cpu(obj_header->usConnectorObjectTableOffset));
+ enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(obj_header->usEncoderObjectTableOffset));
router_obj = (ATOM_OBJECT_TABLE *)
(ctx->bios + data_offset +
le16_to_cpu(obj_header->usRouterObjectTableOffset));
@@ -624,6 +654,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
continue;
+ router.ddc_valid = false;
+ router.cd_valid = false;
for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
@@ -638,18 +670,38 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
- u16 encoder_obj = le16_to_cpu(path->usGraphicObjIds[j]);
-
- radeon_add_atom_encoder(dev,
- encoder_obj,
- le16_to_cpu
- (path->
- usDeviceTag));
+ for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {
+ u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);
+ if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {
+ ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));
+ ATOM_ENCODER_CAP_RECORD *cap_record;
+ u16 caps = 0;
+ while (record->ucRecordType > 0 &&
+ record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+ switch (record->ucRecordType) {
+ case ATOM_ENCODER_CAP_RECORD_TYPE:
+ cap_record =(ATOM_ENCODER_CAP_RECORD *)
+ record;
+ caps = le16_to_cpu(cap_record->usEncoderCap);
+ break;
+ }
+ record = (ATOM_COMMON_RECORD_HEADER *)
+ ((char *)record + record->ucRecordSize);
+ }
+ radeon_add_atom_encoder(dev,
+ encoder_obj,
+ le16_to_cpu
+ (path->
+ usDeviceTag),
+ caps);
+ }
+ }
} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
- router.valid = false;
for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
- u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
+ u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
(ctx->bios + data_offset +
@@ -657,6 +709,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
ATOM_I2C_RECORD *i2c_record;
ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+ ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
(ctx->bios + data_offset +
@@ -690,10 +743,18 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
record;
- router.valid = true;
- router.mux_type = ddc_path->ucMuxType;
- router.mux_control_pin = ddc_path->ucMuxControlPin;
- router.mux_state = ddc_path->ucMuxState[enum_id];
+ router.ddc_valid = true;
+ router.ddc_mux_type = ddc_path->ucMuxType;
+ router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
+ router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
+ break;
+ case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
+ cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
+ record;
+ router.cd_valid = true;
+ router.cd_mux_type = cd_path->ucMuxType;
+ router.cd_mux_control_pin = cd_path->ucMuxControlPin;
+ router.cd_mux_state = cd_path->ucMuxState[enum_id];
break;
}
record = (ATOM_COMMON_RECORD_HEADER *)
@@ -860,7 +921,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
struct radeon_router router;
- router.valid = false;
+ router.ddc_valid = false;
+ router.cd_valid = false;
bios_connectors = kzalloc(bc_size, GFP_KERNEL);
if (!bios_connectors)
@@ -970,7 +1032,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
radeon_get_encoder_enum(dev,
(1 << i),
dac),
- (1 << i));
+ (1 << i),
+ 0);
else
radeon_add_legacy_encoder(dev,
radeon_get_encoder_enum(dev,
@@ -1049,6 +1112,7 @@ union firmware_info {
ATOM_FIRMWARE_INFO_V1_3 info_13;
ATOM_FIRMWARE_INFO_V1_4 info_14;
ATOM_FIRMWARE_INFO_V2_1 info_21;
+ ATOM_FIRMWARE_INFO_V2_2 info_22;
};
bool radeon_atom_get_clock_info(struct drm_device *dev)
@@ -1123,8 +1187,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
*p2pll = *p1pll;
/* system clock */
- spll->reference_freq =
- le16_to_cpu(firmware_info->info.usReferenceClock);
+ if (ASIC_IS_DCE4(rdev))
+ spll->reference_freq =
+ le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
+ else
+ spll->reference_freq =
+ le16_to_cpu(firmware_info->info.usReferenceClock);
spll->reference_div = 0;
spll->pll_out_min =
@@ -1146,8 +1214,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
/* memory clock */
- mpll->reference_freq =
- le16_to_cpu(firmware_info->info.usReferenceClock);
+ if (ASIC_IS_DCE4(rdev))
+ mpll->reference_freq =
+ le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
+ else
+ mpll->reference_freq =
+ le16_to_cpu(firmware_info->info.usReferenceClock);
mpll->reference_div = 0;
mpll->pll_out_min =
@@ -1176,8 +1248,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
if (ASIC_IS_DCE4(rdev)) {
rdev->clock.default_dispclk =
le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
- if (rdev->clock.default_dispclk == 0)
- rdev->clock.default_dispclk = 60000; /* 600 Mhz */
+ if (rdev->clock.default_dispclk == 0) {
+ if (ASIC_IS_DCE5(rdev))
+ rdev->clock.default_dispclk = 54000; /* 540 Mhz */
+ else
+ rdev->clock.default_dispclk = 60000; /* 600 Mhz */
+ }
rdev->clock.dp_extclk =
le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
}
@@ -1312,6 +1388,43 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
return false;
}
+static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
+ struct radeon_atom_ss *ss,
+ int id)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ u16 data_offset, size;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info;
+ u8 frev, crev;
+ u16 percentage = 0, rate = 0;
+
+ /* get any igp specific overrides */
+ if (atom_parse_data_header(mode_info->atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *)
+ (mode_info->atom_context->bios + data_offset);
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_TMDS:
+ percentage = le16_to_cpu(igp_info->usDVISSPercentage);
+ rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_HDMI:
+ percentage = le16_to_cpu(igp_info->usHDMISSPercentage);
+ rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ percentage = le16_to_cpu(igp_info->usLvdsSSPercentage);
+ rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz);
+ break;
+ }
+ if (percentage)
+ ss->percentage = percentage;
+ if (rate)
+ ss->rate = rate;
+ }
+}
+
union asic_ss_info {
struct _ATOM_ASIC_INTERNAL_SS_INFO info;
struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
@@ -1376,6 +1489,8 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+ if (rdev->flags & RADEON_IS_IGP)
+ radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
return true;
}
}
@@ -1452,6 +1567,9 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
if (misc & ATOM_DOUBLE_CLOCK_MODE)
lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
+ lvds->native_mode.width_mm = lvds_info->info.sLCDTiming.usImageHSize;
+ lvds->native_mode.height_mm = lvds_info->info.sLCDTiming.usImageVSize;
+
/* set crtc values */
drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
@@ -1464,6 +1582,59 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
else
lvds->linkb = false;
+ /* parse the lcd record table */
+ if (lvds_info->info.usModePatchTableOffset) {
+ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
+ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
+ bool bad_record = false;
+ u8 *record = (u8 *)(mode_info->atom_context->bios +
+ data_offset +
+ lvds_info->info.usModePatchTableOffset);
+ while (*record != ATOM_RECORD_END_TYPE) {
+ switch (*record) {
+ case LCD_MODE_PATCH_RECORD_MODE_TYPE:
+ record += sizeof(ATOM_PATCH_RECORD_MODE);
+ break;
+ case LCD_RTS_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_RTS_RECORD);
+ break;
+ case LCD_CAP_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
+ break;
+ case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
+ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
+ if (fake_edid_record->ucFakeEDIDLength) {
+ struct edid *edid;
+ int edid_size =
+ max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
+ edid = kmalloc(edid_size, GFP_KERNEL);
+ if (edid) {
+ memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
+ fake_edid_record->ucFakeEDIDLength);
+
+ if (drm_edid_is_valid(edid))
+ rdev->mode_info.bios_hardcoded_edid = edid;
+ else
+ kfree(edid);
+ }
+ }
+ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
+ break;
+ case LCD_PANEL_RESOLUTION_RECORD_TYPE:
+ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
+ lvds->native_mode.width_mm = panel_res_record->usHSize;
+ lvds->native_mode.height_mm = panel_res_record->usVSize;
+ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
+ break;
+ default:
+ DRM_ERROR("Bad LCD record %d\n", *record);
+ bad_record = true;
+ break;
+ }
+ if (bad_record)
+ break;
+ }
+ }
}
return lvds;
}
@@ -1715,496 +1886,614 @@ static const char *pp_lib_thermal_controller_names[] = {
"RV6xx",
"RV770",
"adt7473",
+ "NONE",
"External GPIO",
"Evergreen",
- "adt7473 with internal",
-
+ "emc2103",
+ "Sumo",
+ "Northern Islands",
};
union power_info {
struct _ATOM_POWERPLAY_INFO info;
struct _ATOM_POWERPLAY_INFO_V2 info_2;
struct _ATOM_POWERPLAY_INFO_V3 info_3;
- struct _ATOM_PPLIB_POWERPLAYTABLE info_4;
+ struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+ struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+ struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
};
-void radeon_atombios_get_power_modes(struct radeon_device *rdev)
+union pplib_clock_info {
+ struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+ struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+ struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+ struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
+ int state_index,
+ u32 misc, u32 misc2)
+{
+ rdev->pm.power_state[state_index].misc = misc;
+ rdev->pm.power_state[state_index].misc2 = misc2;
+ /* order matters! */
+ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_POWERSAVE;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ rdev->pm.power_state[state_index].flags &=
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ }
+ if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state_index = state_index;
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[0];
+ } else if (state_index == 0) {
+ rdev->pm.power_state[state_index].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
+ }
+}
+
+static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
{
struct radeon_mode_info *mode_info = &rdev->mode_info;
+ u32 misc, misc2 = 0;
+ int num_modes = 0, i;
+ int state_index = 0;
+ struct radeon_i2c_bus_rec i2c_bus;
+ union power_info *power_info;
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
- u16 data_offset;
+ u16 data_offset;
u8 frev, crev;
- u32 misc, misc2 = 0, sclk, mclk;
- union power_info *power_info;
- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
- struct _ATOM_PPLIB_STATE *power_state;
- int num_modes = 0, i, j;
- int state_index = 0, mode_index = 0;
- struct radeon_i2c_bus_rec i2c_bus;
-
- rdev->pm.default_power_state_index = -1;
- if (atom_parse_data_header(mode_info->atom_context, index, NULL,
- &frev, &crev, &data_offset)) {
- power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
- if (frev < 4) {
- /* add the i2c bus for thermal/fan chip */
- if (power_info->info.ucOverdriveThermalController > 0) {
- DRM_INFO("Possible %s thermal controller at 0x%02x\n",
- thermal_controller_names[power_info->info.ucOverdriveThermalController],
- power_info->info.ucOverdriveControllerAddress >> 1);
- i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
- rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
- if (rdev->pm.i2c_bus) {
- struct i2c_board_info info = { };
- const char *name = thermal_controller_names[power_info->info.
- ucOverdriveThermalController];
- info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
- strlcpy(info.type, name, sizeof(info.type));
- i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
- }
+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return state_index;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ /* add the i2c bus for thermal/fan chip */
+ if (power_info->info.ucOverdriveThermalController > 0) {
+ DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+ thermal_controller_names[power_info->info.ucOverdriveThermalController],
+ power_info->info.ucOverdriveControllerAddress >> 1);
+ i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
+ rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+ if (rdev->pm.i2c_bus) {
+ struct i2c_board_info info = { };
+ const char *name = thermal_controller_names[power_info->info.
+ ucOverdriveThermalController];
+ info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
+ strlcpy(info.type, name, sizeof(info.type));
+ i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+ }
+ }
+ num_modes = power_info->info.ucNumOfPowerModeEntries;
+ if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
+ num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
+ /* last mode is usually default, array is low to high */
+ for (i = 0; i < num_modes; i++) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ switch (frev) {
+ case 1:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ rdev->pm.power_state[state_index].pcie_lanes =
+ power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
}
- num_modes = power_info->info.ucNumOfPowerModeEntries;
- if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
- num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
- /* last mode is usually default, array is low to high */
- for (i = 0; i < num_modes; i++) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
- switch (frev) {
- case 1:
- rdev->pm.power_state[state_index].num_clock_modes = 1;
- rdev->pm.power_state[state_index].clock_info[0].mclk =
- le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
- rdev->pm.power_state[state_index].clock_info[0].sclk =
- le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
- /* skip invalid modes */
- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
- continue;
- rdev->pm.power_state[state_index].pcie_lanes =
- power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
- misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_GPIO;
- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
- radeon_lookup_gpio(rdev,
- power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- true;
- else
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- false;
- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_VDDC;
- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
- power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
- }
- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- rdev->pm.power_state[state_index].misc = misc;
- /* order matters! */
- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_POWERSAVE;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_PERFORMANCE;
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- }
- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = state_index;
- rdev->pm.power_state[state_index].default_clock_mode =
- &rdev->pm.power_state[state_index].clock_info[0];
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- } else if (state_index == 0) {
- rdev->pm.power_state[state_index].clock_info[0].flags |=
- RADEON_PM_MODE_NO_DISPLAY;
- }
- state_index++;
- break;
- case 2:
- rdev->pm.power_state[state_index].num_clock_modes = 1;
- rdev->pm.power_state[state_index].clock_info[0].mclk =
- le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
- rdev->pm.power_state[state_index].clock_info[0].sclk =
- le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
- /* skip invalid modes */
- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
- continue;
- rdev->pm.power_state[state_index].pcie_lanes =
- power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
- misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
- misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_GPIO;
- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
- radeon_lookup_gpio(rdev,
- power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- true;
- else
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- false;
- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_VDDC;
- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
- power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
- }
- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- rdev->pm.power_state[state_index].misc = misc;
- rdev->pm.power_state[state_index].misc2 = misc2;
- /* order matters! */
- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_POWERSAVE;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_PERFORMANCE;
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- }
- if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT)
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = state_index;
- rdev->pm.power_state[state_index].default_clock_mode =
- &rdev->pm.power_state[state_index].clock_info[0];
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- } else if (state_index == 0) {
- rdev->pm.power_state[state_index].clock_info[0].flags |=
- RADEON_PM_MODE_NO_DISPLAY;
- }
- state_index++;
- break;
- case 3:
- rdev->pm.power_state[state_index].num_clock_modes = 1;
- rdev->pm.power_state[state_index].clock_info[0].mclk =
- le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
- rdev->pm.power_state[state_index].clock_info[0].sclk =
- le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
- /* skip invalid modes */
- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
- continue;
- rdev->pm.power_state[state_index].pcie_lanes =
- power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
- misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
- misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_GPIO;
- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
- radeon_lookup_gpio(rdev,
- power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- true;
- else
- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
- false;
- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.type =
- VOLTAGE_VDDC;
- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
- power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
- if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
- rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
- true;
- rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
- power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
- }
- }
- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- rdev->pm.power_state[state_index].misc = misc;
- rdev->pm.power_state[state_index].misc2 = misc2;
- /* order matters! */
- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_POWERSAVE;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_PERFORMANCE;
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- }
- if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = state_index;
- rdev->pm.power_state[state_index].default_clock_mode =
- &rdev->pm.power_state[state_index].clock_info[0];
- } else if (state_index == 0) {
- rdev->pm.power_state[state_index].clock_info[0].flags |=
- RADEON_PM_MODE_NO_DISPLAY;
- }
- state_index++;
- break;
- }
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
+ state_index++;
+ break;
+ case 2:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ rdev->pm.power_state[state_index].pcie_lanes =
+ power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
+ misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
}
- /* last mode is usually default */
- if (rdev->pm.default_power_state_index == -1) {
- rdev->pm.power_state[state_index - 1].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = state_index - 1;
- rdev->pm.power_state[state_index - 1].default_clock_mode =
- &rdev->pm.power_state[state_index - 1].clock_info[0];
- rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- rdev->pm.power_state[state_index].misc = 0;
- rdev->pm.power_state[state_index].misc2 = 0;
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
+ state_index++;
+ break;
+ case 3:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ rdev->pm.power_state[state_index].pcie_lanes =
+ power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
+ misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
+ if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
+ true;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
+ power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
+ }
}
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
+ state_index++;
+ break;
+ }
+ }
+ /* last mode is usually default */
+ if (rdev->pm.default_power_state_index == -1) {
+ rdev->pm.power_state[state_index - 1].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state_index = state_index - 1;
+ rdev->pm.power_state[state_index - 1].default_clock_mode =
+ &rdev->pm.power_state[state_index - 1].clock_info[0];
+ rdev->pm.power_state[state_index].flags &=
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ rdev->pm.power_state[state_index].misc = 0;
+ rdev->pm.power_state[state_index].misc2 = 0;
+ }
+ return state_index;
+}
+
+static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
+ ATOM_PPLIB_THERMALCONTROLLER *controller)
+{
+ struct radeon_i2c_bus_rec i2c_bus;
+
+ /* add the i2c bus for thermal/fan chip */
+ if (controller->ucType > 0) {
+ if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_NI;
+ } else if ((controller->ucType ==
+ ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
+ (controller->ucType ==
+ ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) ||
+ (controller->ucType ==
+ ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) {
+ DRM_INFO("Special thermal controller config\n");
} else {
- int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
- uint8_t fw_frev, fw_crev;
- uint16_t fw_data_offset, vddc = 0;
- union firmware_info *firmware_info;
- ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController;
-
- if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL,
- &fw_frev, &fw_crev, &fw_data_offset)) {
- firmware_info =
- (union firmware_info *)(mode_info->atom_context->bios +
- fw_data_offset);
- vddc = firmware_info->info_14.usBootUpVDDCVoltage;
+ DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
+ pp_lib_thermal_controller_names[controller->ucType],
+ controller->ucI2cAddress >> 1,
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
+ rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+ if (rdev->pm.i2c_bus) {
+ struct i2c_board_info info = { };
+ const char *name = pp_lib_thermal_controller_names[controller->ucType];
+ info.addr = controller->ucI2cAddress >> 1;
+ strlcpy(info.type, name, sizeof(info.type));
+ i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
}
+ }
+ }
+}
- /* add the i2c bus for thermal/fan chip */
- if (controller->ucType > 0) {
- if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
- DRM_INFO("Internal thermal controller %s fan control\n",
- (controller->ucFanParameters &
- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
- rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
- } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
- DRM_INFO("Internal thermal controller %s fan control\n",
- (controller->ucFanParameters &
- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
- rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
- } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
- DRM_INFO("Internal thermal controller %s fan control\n",
- (controller->ucFanParameters &
- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
- rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
- } else if ((controller->ucType ==
- ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
- (controller->ucType ==
- ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) {
- DRM_INFO("Special thermal controller config\n");
- } else {
- DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
- pp_lib_thermal_controller_names[controller->ucType],
- controller->ucI2cAddress >> 1,
- (controller->ucFanParameters &
- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
- i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
- rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
- if (rdev->pm.i2c_bus) {
- struct i2c_board_info info = { };
- const char *name = pp_lib_thermal_controller_names[controller->ucType];
- info.addr = controller->ucI2cAddress >> 1;
- strlcpy(info.type, name, sizeof(info.type));
- i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
- }
+static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+ u8 frev, crev;
+ u16 data_offset;
+ union firmware_info *firmware_info;
+ u16 vddc = 0;
- }
- }
- /* first mode is usually default, followed by low to high */
- for (i = 0; i < power_info->info_4.ucNumStates; i++) {
- mode_index = 0;
- power_state = (struct _ATOM_PPLIB_STATE *)
- (mode_info->atom_context->bios +
- data_offset +
- le16_to_cpu(power_info->info_4.usStateArrayOffset) +
- i * power_info->info_4.ucStateEntrySize);
- non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
- (mode_info->atom_context->bios +
- data_offset +
- le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) +
- (power_state->ucNonClockStateIndex *
- power_info->info_4.ucNonClockSize));
- for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) {
- if (rdev->flags & RADEON_IS_IGP) {
- struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info =
- (struct _ATOM_PPLIB_RS780_CLOCK_INFO *)
- (mode_info->atom_context->bios +
- data_offset +
- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
- (power_state->ucClockStateIndices[j] *
- power_info->info_4.ucClockInfoSize));
- sclk = le16_to_cpu(clock_info->usLowEngineClockLow);
- sclk |= clock_info->ucLowEngineClockHigh << 16;
- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
- /* skip invalid modes */
- if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
- continue;
- /* voltage works differently on IGPs */
- mode_index++;
- } else if (ASIC_IS_DCE4(rdev)) {
- struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info =
- (struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *)
- (mode_info->atom_context->bios +
- data_offset +
- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
- (power_state->ucClockStateIndices[j] *
- power_info->info_4.ucClockInfoSize));
- sclk = le16_to_cpu(clock_info->usEngineClockLow);
- sclk |= clock_info->ucEngineClockHigh << 16;
- mclk = le16_to_cpu(clock_info->usMemoryClockLow);
- mclk |= clock_info->ucMemoryClockHigh << 16;
- rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
- /* skip invalid modes */
- if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
- (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
- continue;
- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
- VOLTAGE_SW;
- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
- clock_info->usVDDC;
- /* XXX usVDDCI */
- mode_index++;
- } else {
- struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info =
- (struct _ATOM_PPLIB_R600_CLOCK_INFO *)
- (mode_info->atom_context->bios +
- data_offset +
- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
- (power_state->ucClockStateIndices[j] *
- power_info->info_4.ucClockInfoSize));
- sclk = le16_to_cpu(clock_info->usEngineClockLow);
- sclk |= clock_info->ucEngineClockHigh << 16;
- mclk = le16_to_cpu(clock_info->usMemoryClockLow);
- mclk |= clock_info->ucMemoryClockHigh << 16;
- rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
- /* skip invalid modes */
- if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
- (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
- continue;
- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
- VOLTAGE_SW;
- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
- clock_info->usVDDC;
- mode_index++;
- }
- }
- rdev->pm.power_state[state_index].num_clock_modes = mode_index;
- if (mode_index) {
- misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
- misc2 = le16_to_cpu(non_clock_info->usClassification);
- rdev->pm.power_state[state_index].misc = misc;
- rdev->pm.power_state[state_index].misc2 = misc2;
- rdev->pm.power_state[state_index].pcie_lanes =
- ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
- ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
- switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
- case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BATTERY;
- break;
- case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_BALANCED;
- break;
- case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_PERFORMANCE;
- break;
- case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
- if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_PERFORMANCE;
- break;
- }
- rdev->pm.power_state[state_index].flags = 0;
- if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
- rdev->pm.power_state[state_index].flags |=
- RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
- if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
- rdev->pm.power_state[state_index].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = state_index;
- rdev->pm.power_state[state_index].default_clock_mode =
- &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
- /* patch the table values with the default slck/mclk from firmware info */
- for (j = 0; j < mode_index; j++) {
- rdev->pm.power_state[state_index].clock_info[j].mclk =
- rdev->clock.default_mclk;
- rdev->pm.power_state[state_index].clock_info[j].sclk =
- rdev->clock.default_sclk;
- if (vddc)
- rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
- vddc;
- }
- }
- state_index++;
- }
- }
- /* if multiple clock modes, mark the lowest as no display */
- for (i = 0; i < state_index; i++) {
- if (rdev->pm.power_state[i].num_clock_modes > 1)
- rdev->pm.power_state[i].clock_info[0].flags |=
- RADEON_PM_MODE_NO_DISPLAY;
- }
- /* first mode is usually default */
- if (rdev->pm.default_power_state_index == -1) {
- rdev->pm.power_state[0].type =
- POWER_STATE_TYPE_DEFAULT;
- rdev->pm.default_power_state_index = 0;
- rdev->pm.power_state[0].default_clock_mode =
- &rdev->pm.power_state[0].clock_info[0];
+ if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ firmware_info =
+ (union firmware_info *)(mode_info->atom_context->bios +
+ data_offset);
+ vddc = firmware_info->info_14.usBootUpVDDCVoltage;
+ }
+
+ return vddc;
+}
+
+static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ int state_index, int mode_index,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
+{
+ int j;
+ u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+ u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
+ u16 vddc = radeon_atombios_get_default_vddc(rdev);
+
+ rdev->pm.power_state[state_index].misc = misc;
+ rdev->pm.power_state[state_index].misc2 = misc2;
+ rdev->pm.power_state[state_index].pcie_lanes =
+ ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
+ ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
+ switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
+ case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
+ if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ break;
+ }
+ rdev->pm.power_state[state_index].flags = 0;
+ if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
+ rdev->pm.power_state[state_index].flags |=
+ RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state_index = state_index;
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
+ if (ASIC_IS_DCE5(rdev)) {
+ /* NI chips post without MC ucode, so default clocks are strobe mode only */
+ rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
+ rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
+ rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
+ } else {
+ /* patch the table values with the default slck/mclk from firmware info */
+ for (j = 0; j < mode_index; j++) {
+ rdev->pm.power_state[state_index].clock_info[j].mclk =
+ rdev->clock.default_mclk;
+ rdev->pm.power_state[state_index].clock_info[j].sclk =
+ rdev->clock.default_sclk;
+ if (vddc)
+ rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
+ vddc;
}
}
+ }
+}
+
+static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
+ int state_index, int mode_index,
+ union pplib_clock_info *clock_info)
+{
+ u32 sclk, mclk;
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ if (rdev->family >= CHIP_PALM) {
+ sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+ sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ } else {
+ sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
+ sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ }
+ } else if (ASIC_IS_DCE4(rdev)) {
+ sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+ sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+ mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+ VOLTAGE_SW;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
+ clock_info->evergreen.usVDDC;
+ } else {
+ sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+ sclk |= clock_info->r600.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+ mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+ VOLTAGE_SW;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
+ clock_info->r600.usVDDC;
+ }
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ /* skip invalid modes */
+ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
+ return false;
+ } else {
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
+ return false;
+ }
+ return true;
+}
+
+static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j;
+ int state_index = 0, mode_index = 0;
+ union pplib_clock_info *clock_info;
+ bool valid;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+
+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return state_index;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
+ /* first mode is usually default, followed by low to high */
+ for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+ mode_index = 0;
+ power_state = (union pplib_power_state *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+ i * power_info->pplib.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+ (power_state->v1.ucNonClockStateIndex *
+ power_info->pplib.ucNonClockSize));
+ for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+ clock_info = (union pplib_clock_info *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+ (power_state->v1.ucClockStateIndices[j] *
+ power_info->pplib.ucClockInfoSize));
+ valid = radeon_atombios_parse_pplib_clock_info(rdev,
+ state_index, mode_index,
+ clock_info);
+ if (valid)
+ mode_index++;
+ }
+ rdev->pm.power_state[state_index].num_clock_modes = mode_index;
+ if (mode_index) {
+ radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
+ non_clock_info);
+ state_index++;
+ }
+ }
+ /* if multiple clock modes, mark the lowest as no display */
+ for (i = 0; i < state_index; i++) {
+ if (rdev->pm.power_state[i].num_clock_modes > 1)
+ rdev->pm.power_state[i].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
+ }
+ /* first mode is usually default */
+ if (rdev->pm.default_power_state_index == -1) {
+ rdev->pm.power_state[0].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state_index = 0;
+ rdev->pm.power_state[0].default_clock_mode =
+ &rdev->pm.power_state[0].clock_info[0];
+ }
+ return state_index;
+}
+
+static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j, non_clock_array_index, clock_array_index;
+ int state_index = 0, mode_index = 0;
+ union pplib_clock_info *clock_info;
+ struct StateArray *state_array;
+ struct ClockInfoArray *clock_info_array;
+ struct NonClockInfoArray *non_clock_info_array;
+ bool valid;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+
+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return state_index;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
+ state_array = (struct StateArray *)
+ (mode_info->atom_context->bios + data_offset +
+ power_info->pplib.usStateArrayOffset);
+ clock_info_array = (struct ClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ power_info->pplib.usClockInfoArrayOffset);
+ non_clock_info_array = (struct NonClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ power_info->pplib.usNonClockInfoArrayOffset);
+ for (i = 0; i < state_array->ucNumEntries; i++) {
+ mode_index = 0;
+ power_state = (union pplib_power_state *)&state_array->states[i];
+ /* XXX this might be an inagua bug... */
+ non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ &non_clock_info_array->nonClockInfo[non_clock_array_index];
+ for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+ clock_array_index = power_state->v2.clockInfoIndex[j];
+ /* XXX this might be an inagua bug... */
+ if (clock_array_index >= clock_info_array->ucNumEntries)
+ continue;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index];
+ valid = radeon_atombios_parse_pplib_clock_info(rdev,
+ state_index, mode_index,
+ clock_info);
+ if (valid)
+ mode_index++;
+ }
+ rdev->pm.power_state[state_index].num_clock_modes = mode_index;
+ if (mode_index) {
+ radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
+ non_clock_info);
+ state_index++;
+ }
+ }
+ /* if multiple clock modes, mark the lowest as no display */
+ for (i = 0; i < state_index; i++) {
+ if (rdev->pm.power_state[i].num_clock_modes > 1)
+ rdev->pm.power_state[i].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
+ }
+ /* first mode is usually default */
+ if (rdev->pm.default_power_state_index == -1) {
+ rdev->pm.power_state[0].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state_index = 0;
+ rdev->pm.power_state[0].default_clock_mode =
+ &rdev->pm.power_state[0].clock_info[0];
+ }
+ return state_index;
+}
+
+void radeon_atombios_get_power_modes(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ int state_index = 0;
+
+ rdev->pm.default_power_state_index = -1;
+
+ if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ switch (frev) {
+ case 1:
+ case 2:
+ case 3:
+ state_index = radeon_atombios_parse_power_table_1_3(rdev);
+ break;
+ case 4:
+ case 5:
+ state_index = radeon_atombios_parse_power_table_4_5(rdev);
+ break;
+ case 6:
+ state_index = radeon_atombios_parse_power_table_6(rdev);
+ break;
+ default:
+ break;
+ }
} else {
/* add the default mode */
rdev->pm.power_state[state_index].type =
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 7932dc4d6b90..c558685cc637 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -41,7 +41,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
size = bsize;
n = 1024;
- r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj);
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj);
if (r) {
goto out_cleanup;
}
@@ -53,7 +53,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj);
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj);
if (r) {
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 654787ec43f4..1aba85cad1a8 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -130,6 +130,46 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
}
return true;
}
+
+static bool ni_read_disabled_bios(struct radeon_device *rdev)
+{
+ u32 bus_cntl;
+ u32 d1vga_control;
+ u32 d2vga_control;
+ u32 vga_render_control;
+ u32 rom_cntl;
+ bool r;
+
+ bus_cntl = RREG32(R600_BUS_CNTL);
+ d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
+ d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
+ vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
+ rom_cntl = RREG32(R600_ROM_CNTL);
+
+ /* enable the rom */
+ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
+ /* Disable VGA mode */
+ WREG32(AVIVO_D1VGA_CONTROL,
+ (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+ AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+ WREG32(AVIVO_D2VGA_CONTROL,
+ (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+ AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+ WREG32(AVIVO_VGA_RENDER_CONTROL,
+ (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+ WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);
+
+ r = radeon_read_bios(rdev);
+
+ /* restore regs */
+ WREG32(R600_BUS_CNTL, bus_cntl);
+ WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+ WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+ WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+ WREG32(R600_ROM_CNTL, rom_cntl);
+ return r;
+}
+
static bool r700_read_disabled_bios(struct radeon_device *rdev)
{
uint32_t viph_control;
@@ -143,7 +183,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev)
bool r;
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(R600_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -152,7 +192,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev)
/* disable VIP */
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
(d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
@@ -191,7 +231,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev)
cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
}
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(R600_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
@@ -216,7 +256,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev)
bool r;
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(R600_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -231,7 +271,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev)
/* disable VIP */
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
(d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
@@ -262,7 +302,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev)
/* restore regs */
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(R600_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
@@ -415,6 +455,8 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
{
if (rdev->flags & RADEON_IS_IGP)
return igp_read_bios_from_vram(rdev);
+ else if (rdev->family >= CHIP_BARTS)
+ return ni_read_disabled_bios(rdev);
else if (rdev->family >= CHIP_RV770)
return r700_read_disabled_bios(rdev);
else if (rdev->family >= CHIP_R600)
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 7b7ea269549c..591fcae8f224 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -471,8 +471,9 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
return true;
}
+/* this is used for atom LCDs as well */
struct edid *
-radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
+radeon_bios_get_hardcoded_edid(struct radeon_device *rdev)
{
if (rdev->mode_info.bios_hardcoded_edid)
return rdev->mode_info.bios_hardcoded_edid;
@@ -571,6 +572,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
}
if (clk_mask && data_mask) {
+ /* system specific masks */
i2c.mask_clk_mask = clk_mask;
i2c.mask_data_mask = data_mask;
i2c.a_clk_mask = clk_mask;
@@ -579,7 +581,19 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
i2c.en_data_mask = data_mask;
i2c.y_clk_mask = clk_mask;
i2c.y_data_mask = data_mask;
+ } else if ((ddc_line == RADEON_GPIOPAD_MASK) ||
+ (ddc_line == RADEON_MDGPIO_MASK)) {
+ /* default gpiopad masks */
+ i2c.mask_clk_mask = (0x20 << 8);
+ i2c.mask_data_mask = 0x80;
+ i2c.a_clk_mask = (0x20 << 8);
+ i2c.a_data_mask = 0x80;
+ i2c.en_clk_mask = (0x20 << 8);
+ i2c.en_data_mask = 0x80;
+ i2c.y_clk_mask = (0x20 << 8);
+ i2c.y_data_mask = 0x80;
} else {
+ /* default masks for ddc pads */
i2c.mask_clk_mask = RADEON_GPIO_EN_1;
i2c.mask_data_mask = RADEON_GPIO_EN_0;
i2c.a_clk_mask = RADEON_GPIO_A_1;
@@ -716,7 +730,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
clk = RBIOS8(offset + 3 + (i * 5) + 3);
data = RBIOS8(offset + 3 + (i * 5) + 4);
i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
- clk, data);
+ (1 << clk), (1 << data));
rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
break;
}
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 4dac4b0a02ee..22b7e3dc0eca 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -183,13 +183,13 @@ radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
continue;
if (priority == true) {
- DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
- DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
+ DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
+ DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector));
conflict->status = connector_status_disconnected;
radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
} else {
- DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
- DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
+ DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
+ DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict));
current_status = connector_status_disconnected;
}
break;
@@ -432,13 +432,13 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
mode->vdisplay == native_mode->vdisplay) {
*native_mode = *mode;
drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
- DRM_INFO("Determined LVDS native mode details from EDID\n");
+ DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
break;
}
}
}
if (!native_mode->clock) {
- DRM_INFO("No LVDS native mode details, disabling RMX\n");
+ DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
radeon_encoder->rmx_type = RMX_OFF;
}
}
@@ -472,6 +472,9 @@ static int radeon_lvds_get_modes(struct drm_connector *connector)
if (mode) {
ret = 1;
drm_mode_probed_add(connector, mode);
+ /* add the width/height from vbios tables if available */
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
/* add scaled modes */
radeon_add_common_modes(encoder, connector);
}
@@ -1008,9 +1011,21 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
static int radeon_dp_get_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
int ret;
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ }
ret = radeon_ddc_get_modes(radeon_connector);
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ }
+
return ret;
}
@@ -1029,8 +1044,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
/* eDP is always DP */
radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected;
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
} else {
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
@@ -1116,7 +1137,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->shared_ddc = true;
shared_ddc = true;
}
- if (radeon_connector->router_bus && router->valid &&
+ if (radeon_connector->router_bus && router->ddc_valid &&
(radeon_connector->router.router_id == router->router_id)) {
radeon_connector->shared_ddc = false;
shared_ddc = false;
@@ -1136,7 +1157,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
radeon_connector->router = *router;
- if (router->valid) {
+ if (router->ddc_valid || router->cd_valid) {
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
if (!radeon_connector->router_bus)
goto failed;
@@ -1157,6 +1178,8 @@ radeon_add_atom_connector(struct drm_device *dev,
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1172,6 +1195,8 @@ radeon_add_atom_connector(struct drm_device *dev,
1);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
@@ -1194,7 +1219,7 @@ radeon_add_atom_connector(struct drm_device *dev,
if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
- UNDERSCAN_AUTO);
+ UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_hborder_property,
0);
@@ -1208,6 +1233,11 @@ radeon_add_atom_connector(struct drm_device *dev,
rdev->mode_info.load_detect_property,
1);
}
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_HDMIB:
@@ -1229,7 +1259,7 @@ radeon_add_atom_connector(struct drm_device *dev,
if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
- UNDERSCAN_AUTO);
+ UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_hborder_property,
0);
@@ -1238,6 +1268,11 @@ radeon_add_atom_connector(struct drm_device *dev,
0);
}
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
case DRM_MODE_CONNECTOR_eDP:
@@ -1267,7 +1302,7 @@ radeon_add_atom_connector(struct drm_device *dev,
if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
- UNDERSCAN_AUTO);
+ UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_hborder_property,
0);
@@ -1275,6 +1310,9 @@ radeon_add_atom_connector(struct drm_device *dev,
rdev->mode_info.underscan_vborder_property,
0);
}
+ connector->interlace_allowed = true;
+ /* in theory with a DP to VGA converter... */
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
@@ -1290,6 +1328,8 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_atombios_get_tv_info(rdev));
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_LVDS:
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
@@ -1308,6 +1348,8 @@ radeon_add_atom_connector(struct drm_device *dev,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
}
@@ -1385,6 +1427,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1400,6 +1444,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
1);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
@@ -1417,6 +1463,11 @@ radeon_add_legacy_connector(struct drm_device *dev,
1);
}
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
@@ -1439,6 +1490,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
radeon_combios_get_tv_info(rdev));
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
case DRM_MODE_CONNECTOR_LVDS:
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
@@ -1452,6 +1505,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
break;
}
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 6d64a2705f12..35b5eb8fbe2a 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -77,13 +77,13 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
p->relocs_ptr[i] = &p->relocs[i];
p->relocs[i].robj = p->relocs[i].gobj->driver_private;
p->relocs[i].lobj.bo = p->relocs[i].robj;
- p->relocs[i].lobj.rdomain = r->read_domains;
p->relocs[i].lobj.wdomain = r->write_domain;
+ p->relocs[i].lobj.rdomain = r->read_domains;
+ p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo;
p->relocs[i].handle = r->handle;
p->relocs[i].flags = r->flags;
- INIT_LIST_HEAD(&p->relocs[i].lobj.list);
radeon_bo_list_add_object(&p->relocs[i].lobj,
- &p->validated);
+ &p->validated);
}
}
return radeon_bo_list_validate(&p->validated);
@@ -189,10 +189,13 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
{
unsigned i;
- if (!error && parser->ib) {
- radeon_bo_list_fence(&parser->validated, parser->ib->fence);
- }
- radeon_bo_list_unreserve(&parser->validated);
+
+ if (!error && parser->ib)
+ ttm_eu_fence_buffer_objects(&parser->validated,
+ parser->ib->fence);
+ else
+ ttm_eu_backoff_reservation(&parser->validated);
+
if (parser->relocs != NULL) {
for (i = 0; i < parser->nrelocs; i++) {
if (parser->relocs[i].gobj)
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 8adfedfe547f..26091d602b84 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -81,6 +81,10 @@ static const char radeon_family_name[][16] = {
"JUNIPER",
"CYPRESS",
"HEMLOCK",
+ "PALM",
+ "BARTS",
+ "TURKS",
+ "CAICOS",
"LAST",
};
@@ -180,7 +184,7 @@ int radeon_wb_init(struct radeon_device *rdev)
int r;
if (rdev->wb.wb_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
+ r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
@@ -224,6 +228,11 @@ int radeon_wb_init(struct radeon_device *rdev)
rdev->wb.use_event = true;
}
}
+ /* always use writeback/events on NI */
+ if (ASIC_IS_DCE5(rdev)) {
+ rdev->wb.enabled = true;
+ rdev->wb.use_event = true;
+ }
dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
@@ -286,7 +295,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64
mc->mc_vram_size = mc->aper_size;
}
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
- dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+ dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
mc->mc_vram_size >> 20, mc->vram_start,
mc->vram_end, mc->real_vram_size >> 20);
}
@@ -323,7 +332,7 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
}
mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
- dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+ dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
}
@@ -335,7 +344,12 @@ bool radeon_card_posted(struct radeon_device *rdev)
uint32_t reg;
/* first check CRTCs */
- if (ASIC_IS_DCE4(rdev)) {
+ if (ASIC_IS_DCE41(rdev)) {
+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
+ if (reg & EVERGREEN_CRTC_MASTER_EN)
+ return true;
+ } else if (ASIC_IS_DCE4(rdev)) {
reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
@@ -636,20 +650,20 @@ void radeon_check_arguments(struct radeon_device *rdev)
static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
- struct radeon_device *rdev = dev->dev_private;
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "radeon: switched on\n");
/* don't suspend or resume card normally */
- rdev->powered_down = false;
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
radeon_resume_kms(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_INFO "radeon: switched off\n");
drm_kms_helper_poll_disable(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
radeon_suspend_kms(dev, pmm);
- /* don't suspend or resume card normally */
- rdev->powered_down = true;
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
@@ -704,11 +718,6 @@ int radeon_device_init(struct radeon_device *rdev,
init_waitqueue_head(&rdev->irq.vblank_queue);
init_waitqueue_head(&rdev->irq.idle_queue);
- /* setup workqueue */
- rdev->wq = create_workqueue("radeon");
- if (rdev->wq == NULL)
- return -ENOMEM;
-
/* Set asic functions */
r = radeon_asic_init(rdev);
if (r)
@@ -773,6 +782,7 @@ int radeon_device_init(struct radeon_device *rdev,
vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
vga_switcheroo_register_client(rdev->pdev,
radeon_switcheroo_set_state,
+ NULL,
radeon_switcheroo_can_switch);
r = radeon_init(rdev);
@@ -806,7 +816,6 @@ void radeon_device_fini(struct radeon_device *rdev)
/* evict vram memory */
radeon_bo_evict_vram(rdev);
radeon_fini(rdev);
- destroy_workqueue(rdev->wq);
vga_switcheroo_unregister_client(rdev->pdev);
vga_client_register(rdev->pdev, NULL, NULL, NULL);
if (rdev->rio_mem)
@@ -835,7 +844,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
}
rdev = dev->dev_private;
- if (rdev->powered_down)
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
/* turn off display hw */
@@ -893,7 +902,7 @@ int radeon_resume_kms(struct drm_device *dev)
struct drm_connector *connector;
struct radeon_device *rdev = dev->dev_private;
- if (rdev->powered_down)
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
acquire_console_sem();
@@ -910,11 +919,6 @@ int radeon_resume_kms(struct drm_device *dev)
radeon_pm_resume(rdev);
radeon_restore_bios_scratch_regs(rdev);
- /* turn on display hw */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
- }
-
radeon_fbdev_set_suspend(rdev, 0);
release_console_sem();
@@ -922,6 +926,10 @@ int radeon_resume_kms(struct drm_device *dev)
radeon_hpd_init(rdev);
/* blat the mode back in */
drm_helper_resume_force_mode(dev);
+ /* turn on display hw */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 0383631da69c..d26dabf878d9 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -68,7 +68,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
}
-static void evergreen_crtc_load_lut(struct drm_crtc *crtc)
+static void dce4_crtc_load_lut(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -98,6 +98,66 @@ static void evergreen_crtc_load_lut(struct drm_crtc *crtc)
}
}
+static void dce5_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ int i;
+
+ DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
+
+ WREG32(NI_INPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
+ (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) |
+ NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS)));
+ WREG32(NI_PRESCALE_GRPH_CONTROL + radeon_crtc->crtc_offset,
+ NI_GRPH_PRESCALE_BYPASS);
+ WREG32(NI_PRESCALE_OVL_CONTROL + radeon_crtc->crtc_offset,
+ NI_OVL_PRESCALE_BYPASS);
+ WREG32(NI_INPUT_GAMMA_CONTROL + radeon_crtc->crtc_offset,
+ (NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) |
+ NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT)));
+
+ WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0);
+
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0);
+
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff);
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff);
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff);
+
+ WREG32(EVERGREEN_DC_LUT_RW_MODE + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 0x00000007);
+
+ WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0);
+ for (i = 0; i < 256; i++) {
+ WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset,
+ (radeon_crtc->lut_r[i] << 20) |
+ (radeon_crtc->lut_g[i] << 10) |
+ (radeon_crtc->lut_b[i] << 0));
+ }
+
+ WREG32(NI_DEGAMMA_CONTROL + radeon_crtc->crtc_offset,
+ (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+ NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+ NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
+ NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)));
+ WREG32(NI_GAMUT_REMAP_CONTROL + radeon_crtc->crtc_offset,
+ (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) |
+ NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS)));
+ WREG32(NI_REGAMMA_CONTROL + radeon_crtc->crtc_offset,
+ (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
+ NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
+ WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
+ (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
+ NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
+ /* XXX match this to the depth of the crtc fmt block, move to modeset? */
+ WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
+
+}
+
static void legacy_crtc_load_lut(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -130,8 +190,10 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc)
if (!crtc->enabled)
return;
- if (ASIC_IS_DCE4(rdev))
- evergreen_crtc_load_lut(crtc);
+ if (ASIC_IS_DCE5(rdev))
+ dce5_crtc_load_lut(crtc);
+ else if (ASIC_IS_DCE4(rdev))
+ dce4_crtc_load_lut(crtc);
else if (ASIC_IS_AVIVO(rdev))
avivo_crtc_load_lut(crtc);
else
@@ -183,12 +245,272 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc)
kfree(radeon_crtc);
}
+/*
+ * Handle unpin events outside the interrupt handler proper.
+ */
+static void radeon_unpin_work_func(struct work_struct *__work)
+{
+ struct radeon_unpin_work *work =
+ container_of(__work, struct radeon_unpin_work, work);
+ int r;
+
+ /* unpin of the old buffer */
+ r = radeon_bo_reserve(work->old_rbo, false);
+ if (likely(r == 0)) {
+ r = radeon_bo_unpin(work->old_rbo);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to unpin buffer after flip\n");
+ }
+ radeon_bo_unreserve(work->old_rbo);
+ } else
+ DRM_ERROR("failed to reserve buffer after flip\n");
+ kfree(work);
+}
+
+void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+ struct radeon_unpin_work *work;
+ struct drm_pending_vblank_event *e;
+ struct timeval now;
+ unsigned long flags;
+ u32 update_pending;
+ int vpos, hpos;
+
+ spin_lock_irqsave(&rdev->ddev->event_lock, flags);
+ work = radeon_crtc->unpin_work;
+ if (work == NULL ||
+ !radeon_fence_signaled(work->fence)) {
+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
+ return;
+ }
+ /* New pageflip, or just completion of a previous one? */
+ if (!radeon_crtc->deferred_flip_completion) {
+ /* do the flip (mmio) */
+ update_pending = radeon_page_flip(rdev, crtc_id, work->new_crtc_base);
+ } else {
+ /* This is just a completion of a flip queued in crtc
+ * at last invocation. Make sure we go directly to
+ * completion routine.
+ */
+ update_pending = 0;
+ radeon_crtc->deferred_flip_completion = 0;
+ }
+
+ /* Has the pageflip already completed in crtc, or is it certain
+ * to complete in this vblank?
+ */
+ if (update_pending &&
+ (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
+ &vpos, &hpos)) &&
+ (vpos >=0) &&
+ (vpos < (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100)) {
+ /* crtc didn't flip in this target vblank interval,
+ * but flip is pending in crtc. It will complete it
+ * in next vblank interval, so complete the flip at
+ * next vblank irq.
+ */
+ radeon_crtc->deferred_flip_completion = 1;
+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
+ return;
+ }
+
+ /* Pageflip (will be) certainly completed in this vblank. Clean up. */
+ radeon_crtc->unpin_work = NULL;
+
+ /* wakeup userspace */
+ if (work->event) {
+ e = work->event;
+ e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now);
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ }
+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
+
+ drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id);
+ radeon_fence_unref(&work->fence);
+ radeon_post_page_flip(work->rdev, work->crtc_id);
+ schedule_work(&work->work);
+}
+
+static int radeon_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct radeon_framebuffer *old_radeon_fb;
+ struct radeon_framebuffer *new_radeon_fb;
+ struct drm_gem_object *obj;
+ struct radeon_bo *rbo;
+ struct radeon_fence *fence;
+ struct radeon_unpin_work *work;
+ unsigned long flags;
+ u32 tiling_flags, pitch_pixels;
+ u64 base;
+ int r;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (work == NULL)
+ return -ENOMEM;
+
+ r = radeon_fence_create(rdev, &fence);
+ if (unlikely(r != 0)) {
+ kfree(work);
+ DRM_ERROR("flip queue: failed to create fence.\n");
+ return -ENOMEM;
+ }
+ work->event = event;
+ work->rdev = rdev;
+ work->crtc_id = radeon_crtc->crtc_id;
+ work->fence = radeon_fence_ref(fence);
+ old_radeon_fb = to_radeon_framebuffer(crtc->fb);
+ new_radeon_fb = to_radeon_framebuffer(fb);
+ /* schedule unpin of the old buffer */
+ obj = old_radeon_fb->obj;
+ rbo = obj->driver_private;
+ work->old_rbo = rbo;
+ INIT_WORK(&work->work, radeon_unpin_work_func);
+
+ /* We borrow the event spin lock for protecting unpin_work */
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (radeon_crtc->unpin_work) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(work);
+ radeon_fence_unref(&fence);
+
+ DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
+ return -EBUSY;
+ }
+ radeon_crtc->unpin_work = work;
+ radeon_crtc->deferred_flip_completion = 0;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ /* pin the new buffer */
+ obj = new_radeon_fb->obj;
+ rbo = obj->driver_private;
+
+ DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n",
+ work->old_rbo, rbo);
+
+ r = radeon_bo_reserve(rbo, false);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to reserve new rbo buffer before flip\n");
+ goto pflip_cleanup;
+ }
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ r = -EINVAL;
+ DRM_ERROR("failed to pin new rbo buffer before flip\n");
+ goto pflip_cleanup;
+ }
+ radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
+ radeon_bo_unreserve(rbo);
+
+ if (!ASIC_IS_AVIVO(rdev)) {
+ /* crtc offset is from display base addr not FB location */
+ base -= radeon_crtc->legacy_display_base_addr;
+ pitch_pixels = fb->pitch / (fb->bits_per_pixel / 8);
+
+ if (tiling_flags & RADEON_TILING_MACRO) {
+ if (ASIC_IS_R300(rdev)) {
+ base &= ~0x7ff;
+ } else {
+ int byteshift = fb->bits_per_pixel >> 4;
+ int tile_addr = (((crtc->y >> 3) * pitch_pixels + crtc->x) >> (8 - byteshift)) << 11;
+ base += tile_addr + ((crtc->x << byteshift) % 256) + ((crtc->y % 8) << 8);
+ }
+ } else {
+ int offset = crtc->y * pitch_pixels + crtc->x;
+ switch (fb->bits_per_pixel) {
+ case 8:
+ default:
+ offset *= 1;
+ break;
+ case 15:
+ case 16:
+ offset *= 2;
+ break;
+ case 24:
+ offset *= 3;
+ break;
+ case 32:
+ offset *= 4;
+ break;
+ }
+ base += offset;
+ }
+ base &= ~7;
+ }
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ work->new_crtc_base = base;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ /* update crtc fb */
+ crtc->fb = fb;
+
+ r = drm_vblank_get(dev, radeon_crtc->crtc_id);
+ if (r) {
+ DRM_ERROR("failed to get vblank before flip\n");
+ goto pflip_cleanup1;
+ }
+
+ /* 32 ought to cover us */
+ r = radeon_ring_lock(rdev, 32);
+ if (r) {
+ DRM_ERROR("failed to lock the ring before flip\n");
+ goto pflip_cleanup2;
+ }
+
+ /* emit the fence */
+ radeon_fence_emit(rdev, fence);
+ /* set the proper interrupt */
+ radeon_pre_page_flip(rdev, radeon_crtc->crtc_id);
+ /* fire the ring */
+ radeon_ring_unlock_commit(rdev);
+
+ return 0;
+
+pflip_cleanup2:
+ drm_vblank_put(dev, radeon_crtc->crtc_id);
+
+pflip_cleanup1:
+ r = radeon_bo_reserve(rbo, false);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to reserve new rbo in error path\n");
+ goto pflip_cleanup;
+ }
+ r = radeon_bo_unpin(rbo);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ r = -EINVAL;
+ DRM_ERROR("failed to unpin new rbo in error path\n");
+ goto pflip_cleanup;
+ }
+ radeon_bo_unreserve(rbo);
+
+pflip_cleanup:
+ spin_lock_irqsave(&dev->event_lock, flags);
+ radeon_crtc->unpin_work = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ radeon_fence_unref(&fence);
+ kfree(work);
+
+ return r;
+}
+
static const struct drm_crtc_funcs radeon_crtc_funcs = {
.cursor_set = radeon_crtc_cursor_set,
.cursor_move = radeon_crtc_cursor_move,
.gamma_set = radeon_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = radeon_crtc_destroy,
+ .page_flip = radeon_crtc_page_flip,
};
static void radeon_crtc_init(struct drm_device *dev, int index)
@@ -225,7 +547,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
radeon_legacy_init_crtc(dev, radeon_crtc);
}
-static const char *encoder_names[34] = {
+static const char *encoder_names[36] = {
"NONE",
"INTERNAL_LVDS",
"INTERNAL_TMDS1",
@@ -260,6 +582,8 @@ static const char *encoder_names[34] = {
"INTERNAL_KLDSCP_LVTMA",
"INTERNAL_UNIPHY1",
"INTERNAL_UNIPHY2",
+ "NUTMEG",
+ "TRAVIS",
};
static const char *connector_names[15] = {
@@ -315,10 +639,14 @@ static void radeon_print_display_setup(struct drm_device *dev)
radeon_connector->ddc_bus->rec.en_data_reg,
radeon_connector->ddc_bus->rec.y_clk_reg,
radeon_connector->ddc_bus->rec.y_data_reg);
- if (radeon_connector->router_bus)
+ if (radeon_connector->router.ddc_valid)
DRM_INFO(" DDC Router 0x%x/0x%x\n",
- radeon_connector->router.mux_control_pin,
- radeon_connector->router.mux_state);
+ radeon_connector->router.ddc_mux_control_pin,
+ radeon_connector->router.ddc_mux_state);
+ if (radeon_connector->router.cd_valid)
+ DRM_INFO(" Clock/Data Router 0x%x/0x%x\n",
+ radeon_connector->router.cd_mux_control_pin,
+ radeon_connector->router.cd_mux_state);
} else {
if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
@@ -398,8 +726,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
int ret = 0;
/* on hw with routers, select right port */
- if (radeon_connector->router.valid)
- radeon_router_select_port(radeon_connector);
+ if (radeon_connector->router.ddc_valid)
+ radeon_router_select_ddc_port(radeon_connector);
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
@@ -413,9 +741,17 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
if (!radeon_connector->edid) {
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
}
- /* some servers provide a hardcoded edid in rom for KVMs */
- if (!radeon_connector->edid)
- radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev);
+
+ if (!radeon_connector->edid) {
+ if (rdev->is_atom_bios) {
+ /* some laptops provide a hardcoded edid in rom for LCDs */
+ if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) ||
+ (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)))
+ radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
+ } else
+ /* some servers provide a hardcoded edid in rom for KVMs */
+ radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
+ }
if (radeon_connector->edid) {
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
@@ -432,8 +768,8 @@ static int radeon_ddc_dump(struct drm_connector *connector)
int ret = 0;
/* on hw with routers, select right port */
- if (radeon_connector->router.valid)
- radeon_router_select_port(radeon_connector);
+ if (radeon_connector->router.ddc_valid)
+ radeon_router_select_ddc_port(radeon_connector);
if (!radeon_connector->ddc_bus)
return -1;
@@ -845,7 +1181,10 @@ int radeon_modeset_init(struct radeon_device *rdev)
rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs;
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE5(rdev)) {
+ rdev->ddev->mode_config.max_width = 16384;
+ rdev->ddev->mode_config.max_height = 16384;
+ } else if (ASIC_IS_AVIVO(rdev)) {
rdev->ddev->mode_config.max_width = 8192;
rdev->ddev->mode_config.max_height = 8192;
} else {
@@ -1015,7 +1354,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
/*
* Retrieve current video scanout position of crtc on a given gpu.
*
- * \param rdev Device to query.
+ * \param dev Device to query.
* \param crtc Crtc to query.
* \param *vpos Location where vertical scanout position should be stored.
* \param *hpos Location where horizontal scanout position should go.
@@ -1027,72 +1366,74 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
*
* \return Flags, or'ed together as follows:
*
- * RADEON_SCANOUTPOS_VALID = Query successfull.
- * RADEON_SCANOUTPOS_INVBL = Inside vblank.
- * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
+ * DRM_SCANOUTPOS_VALID = Query successfull.
+ * DRM_SCANOUTPOS_INVBL = Inside vblank.
+ * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
* this flag means that returned position may be offset by a constant but
* unknown small number of scanlines wrt. real scanout position.
*
*/
-int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
+int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
{
u32 stat_crtc = 0, vbl = 0, position = 0;
int vbl_start, vbl_end, vtotal, ret = 0;
bool in_vbl = true;
+ struct radeon_device *rdev = dev->dev_private;
+
if (ASIC_IS_DCE4(rdev)) {
if (crtc == 0) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC0_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC0_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 1) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC1_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC1_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 2) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC2_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC2_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 3) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC3_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC3_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 4) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC4_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC4_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 5) {
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
EVERGREEN_CRTC5_REGISTER_OFFSET);
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
EVERGREEN_CRTC5_REGISTER_OFFSET);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
} else if (ASIC_IS_AVIVO(rdev)) {
if (crtc == 0) {
vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 1) {
vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
} else {
/* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
@@ -1108,7 +1449,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
if (!(stat_crtc & 1))
in_vbl = false;
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
if (crtc == 1) {
vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
@@ -1118,7 +1459,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
if (!(stat_crtc & 1))
in_vbl = false;
- ret |= RADEON_SCANOUTPOS_VALID;
+ ret |= DRM_SCANOUTPOS_VALID;
}
}
@@ -1129,13 +1470,13 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
/* Valid vblank area boundaries from gpu retrieved? */
if (vbl > 0) {
/* Yes: Decode. */
- ret |= RADEON_SCANOUTPOS_ACCURATE;
+ ret |= DRM_SCANOUTPOS_ACCURATE;
vbl_start = vbl & 0x1fff;
vbl_end = (vbl >> 16) & 0x1fff;
}
else {
/* No: Fake something reasonable which gives at least ok results. */
- vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
+ vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
vbl_end = 0;
}
@@ -1151,7 +1492,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
/* Inside "upper part" of vblank area? Apply corrective offset if so: */
if (in_vbl && (*vpos >= vbl_start)) {
- vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
+ vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
*vpos = *vpos - vtotal;
}
@@ -1160,7 +1501,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
/* In vblank? */
if (in_vbl)
- ret |= RADEON_SCANOUTPOS_INVBL;
+ ret |= DRM_SCANOUTPOS_INVBL;
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 88e4ea925900..d5680a0c87af 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -48,9 +48,10 @@
* - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
* - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
* 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
+ * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 7
+#define KMS_DRIVER_MINOR 8
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
@@ -66,6 +67,10 @@ int radeon_resume_kms(struct drm_device *dev);
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc);
int radeon_enable_vblank_kms(struct drm_device *dev, int crtc);
void radeon_disable_vblank_kms(struct drm_device *dev, int crtc);
+int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags);
void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
@@ -74,6 +79,8 @@ int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int radeon_gem_object_init(struct drm_gem_object *obj);
void radeon_gem_object_free(struct drm_gem_object *obj);
+extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
+ int *vpos, int *hpos);
extern struct drm_ioctl_desc radeon_ioctls_kms[];
extern int radeon_max_kms_ioctl;
int radeon_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -97,6 +104,7 @@ int radeon_tv = 1;
int radeon_audio = 1;
int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
+int radeon_pcie_gen2 = 0;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -140,6 +148,9 @@ module_param_named(disp_priority, radeon_disp_priority, int, 0444);
MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)");
module_param_named(hw_i2c, radeon_hw_i2c, int, 0444);
+MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)");
+module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
+
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -232,9 +243,28 @@ static struct drm_driver driver_old = {
static struct drm_driver kms_driver;
+static void radeon_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+ struct apertures_struct *ap;
+ bool primary = false;
+
+ ap = alloc_apertures(1);
+ ap->ranges[0].base = pci_resource_start(pdev, 0);
+ ap->ranges[0].size = pci_resource_len(pdev, 0);
+
+#ifdef CONFIG_X86
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+ remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
+ kfree(ap);
+}
+
static int __devinit
radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ /* Get rid of things like offb */
+ radeon_kick_out_firmware_fb(pdev);
+
return drm_get_pci_dev(pdev, ent, &kms_driver);
}
@@ -277,6 +307,8 @@ static struct drm_driver kms_driver = {
.get_vblank_counter = radeon_get_vblank_counter_kms,
.enable_vblank = radeon_enable_vblank_kms,
.disable_vblank = radeon_disable_vblank_kms,
+ .get_vblank_timestamp = radeon_get_vblank_timestamp_kms,
+ .get_scanout_position = radeon_get_crtc_scanoutpos,
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = radeon_debugfs_init,
.debugfs_cleanup = radeon_debugfs_cleanup,
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index ae58b6849a2e..8fd184286c0b 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -176,6 +176,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
return false;
}
}
+
void
radeon_link_encoder_connector(struct drm_device *dev)
{
@@ -228,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
return NULL;
}
+struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *other_encoder;
+ struct radeon_encoder *other_radeon_encoder;
+
+ if (radeon_encoder->is_ext_encoder)
+ return NULL;
+
+ list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+ if (other_encoder == encoder)
+ continue;
+ other_radeon_encoder = to_radeon_encoder(other_encoder);
+ if (other_radeon_encoder->is_ext_encoder &&
+ (radeon_encoder->devices & other_radeon_encoder->devices))
+ return other_encoder;
+ }
+ return NULL;
+}
+
void radeon_panel_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
@@ -426,52 +448,49 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
}
-void
-atombios_external_tmds_setup(struct drm_encoder *encoder, int action)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args;
- int index = 0;
-
- memset(&args, 0, sizeof(args));
-
- index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
-
- args.sXTmdsEncoder.ucEnable = action;
-
- if (radeon_encoder->pixel_clock > 165000)
- args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
-
- /*if (pScrn->rgbBits == 8)*/
- args.sXTmdsEncoder.ucMisc |= (1 << 1);
-
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-}
+union dvo_encoder_control {
+ ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+};
-static void
-atombios_ddia_setup(struct drm_encoder *encoder, int action)
+void
+atombios_dvo_setup(struct drm_encoder *encoder, int action)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DVO_ENCODER_CONTROL_PS_ALLOCATION args;
- int index = 0;
+ union dvo_encoder_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
memset(&args, 0, sizeof(args));
- index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+ if (ASIC_IS_DCE3(rdev)) {
+ /* DCE3+ */
+ args.dvo_v3.ucAction = action;
+ args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.dvo_v3.ucDVOConfig = 0; /* XXX */
+ } else if (ASIC_IS_DCE2(rdev)) {
+ /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */
+ args.dvo.sDVOEncoder.ucAction = action;
+ args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ /* DFP1, CRT1, TV1 depending on the type of port */
+ args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
+
+ if (radeon_encoder->pixel_clock > 165000)
+ args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
+ } else {
+ /* R4xx, R5xx */
+ args.ext_tmds.sXTmdsEncoder.ucEnable = action;
- args.sDVOEncoder.ucAction = action;
- args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ if (radeon_encoder->pixel_clock > 165000)
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (radeon_encoder->pixel_clock > 165000)
- args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
+ /*if (pScrn->rgbBits == 8)*/
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
+ }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
}
union lvds_encoder_control {
@@ -532,14 +551,14 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
- args.v1.ucMisc |= (1 << 1);
+ args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
} else {
if (dig->linkb)
args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
if (radeon_encoder->pixel_clock > 165000)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
/*if (pScrn->rgbBits == 8) */
- args.v1.ucMisc |= (1 << 1);
+ args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
}
break;
case 2:
@@ -595,6 +614,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
int
atombios_get_encoder_mode(struct drm_encoder *encoder)
{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
@@ -602,15 +622,26 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
struct radeon_connector_atom_dig *dig_connector;
connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
- return 0;
-
+ if (!connector) {
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ return ATOM_ENCODER_MODE_DVI;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ default:
+ return ATOM_ENCODER_MODE_CRT;
+ }
+ }
radeon_connector = to_radeon_connector(connector);
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
- if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (drm_detect_monitor_audio(radeon_connector->edid)) {
/* fix me */
if (ASIC_IS_DCE4(rdev))
return ATOM_ENCODER_MODE_DVI;
@@ -624,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_HDMIA:
default:
- if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (drm_detect_monitor_audio(radeon_connector->edid)) {
/* fix me */
if (ASIC_IS_DCE4(rdev))
return ATOM_ENCODER_MODE_DVI;
@@ -642,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
return ATOM_ENCODER_MODE_DP;
- else if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ else if (drm_detect_monitor_audio(radeon_connector->edid)) {
/* fix me */
if (ASIC_IS_DCE4(rdev))
return ATOM_ENCODER_MODE_DVI;
@@ -681,8 +712,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
* - 2 DIG encoder blocks.
* DIG1/2 can drive UNIPHY0/1/2 link A or link B
*
- * DCE 4.0
- * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B).
+ * DCE 4.0/5.0
+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
* Supports up to 6 digital outputs
* - 6 DIG encoder blocks.
* - DIG to PHY mapping is hardcoded
@@ -693,6 +724,12 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
* DIG5 drives UNIPHY2 link A, A+B
* DIG6 drives UNIPHY2 link B
*
+ * DCE 4.1
+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
+ * Supports up to 6 digital outputs
+ * - 2 DIG encoder blocks.
+ * DIG1/2 can drive UNIPHY0/1/2 link A or link B
+ *
* Routing
* crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
* Examples:
@@ -706,6 +743,7 @@ union dig_encoder_control {
DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
+ DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
};
void
@@ -721,6 +759,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
uint8_t frev, crev;
int dp_clock = 0;
int dp_lane_count = 0;
+ int hpd_id = RADEON_HPD_NONE;
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -729,6 +768,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
dp_clock = dig_connector->dp_clock;
dp_lane_count = dig_connector->dp_lane_count;
+ hpd_id = radeon_connector->hpd.hpd;
}
/* no dig encoder assigned */
@@ -753,19 +793,36 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
- if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
- if (dp_clock == 270000)
- args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
+ (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
args.v1.ucLaneNum = dp_lane_count;
- } else if (radeon_encoder->pixel_clock > 165000)
+ else if (radeon_encoder->pixel_clock > 165000)
args.v1.ucLaneNum = 8;
else
args.v1.ucLaneNum = 4;
- if (ASIC_IS_DCE4(rdev)) {
+ if (ASIC_IS_DCE5(rdev)) {
+ if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
+ (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) {
+ if (dp_clock == 270000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
+ else if (dp_clock == 540000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
+ }
+ args.v4.acConfig.ucDigSel = dig->dig_encoder;
+ args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ if (hpd_id == RADEON_HPD_NONE)
+ args.v4.ucHPD_ID = 0;
+ else
+ args.v4.ucHPD_ID = hpd_id + 1;
+ } else if (ASIC_IS_DCE4(rdev)) {
+ if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
args.v3.acConfig.ucDigSel = dig->dig_encoder;
args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
} else {
+ if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
@@ -792,6 +849,7 @@ union dig_transmitter_control {
DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
};
void
@@ -834,6 +892,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
memset(&args, 0, sizeof(args));
switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+ break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
@@ -883,10 +944,18 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
pll_id = radeon_crtc->pll_id;
}
- if (is_dp && rdev->clock.dp_extclk)
- args.v3.acConfig.ucRefClkSource = 2; /* external src */
- else
- args.v3.acConfig.ucRefClkSource = pll_id;
+
+ if (ASIC_IS_DCE5(rdev)) {
+ if (is_dp && rdev->clock.dp_extclk)
+ args.v4.acConfig.ucRefClkSource = 3; /* external src */
+ else
+ args.v4.acConfig.ucRefClkSource = pll_id;
+ } else {
+ if (is_dp && rdev->clock.dp_extclk)
+ args.v3.acConfig.ucRefClkSource = 2; /* external src */
+ else
+ args.v3.acConfig.ucRefClkSource = pll_id;
+ }
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
@@ -978,6 +1047,139 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+void
+atombios_set_edp_panel_power(struct drm_connector *connector, int action)
+{
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct drm_device *dev = radeon_connector->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
+ union dig_transmitter_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+ uint8_t frev, crev;
+
+ if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+ return;
+
+ if (!ASIC_IS_DCE4(rdev))
+ return;
+
+ if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+ (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
+ return;
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ memset(&args, 0, sizeof(args));
+
+ args.v1.ucAction = action;
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union external_encoder_control {
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
+};
+
+static void
+atombios_external_encoder_setup(struct drm_encoder *encoder,
+ struct drm_encoder *ext_encoder,
+ int action)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
+ union external_encoder_control args;
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
+ u8 frev, crev;
+ int dp_clock = 0;
+ int dp_lane_count = 0;
+ int connector_object_id = 0;
+ u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+
+ if (connector) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_connector->con_priv;
+
+ dp_clock = dig_connector->dp_clock;
+ dp_lane_count = dig_connector->dp_lane_count;
+ connector_object_id =
+ (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ /* no params on frev 1 */
+ break;
+ case 2:
+ switch (crev) {
+ case 1:
+ case 2:
+ args.v1.sDigEncoder.ucAction = action;
+ args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+ if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+ if (dp_clock == 270000)
+ args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
+ } else if (radeon_encoder->pixel_clock > 165000)
+ args.v1.sDigEncoder.ucLaneNum = 8;
+ else
+ args.v1.sDigEncoder.ucLaneNum = 4;
+ break;
+ case 3:
+ args.v3.sExtEncoder.ucAction = action;
+ if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+ args.v3.sExtEncoder.usConnectorId = connector_object_id;
+ else
+ args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+ if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+ if (dp_clock == 270000)
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
+ else if (dp_clock == 540000)
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
+ args.v3.sExtEncoder.ucLaneNum = dp_lane_count;
+ } else if (radeon_encoder->pixel_clock > 165000)
+ args.v3.sExtEncoder.ucLaneNum = 8;
+ else
+ args.v3.sExtEncoder.ucLaneNum = 4;
+ switch (ext_enum) {
+ case GRAPH_OBJECT_ENUM_ID1:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
+ break;
+ case GRAPH_OBJECT_ENUM_ID2:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
+ break;
+ case GRAPH_OBJECT_ENUM_ID3:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
+ break;
+ }
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
static void
atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
{
@@ -1021,9 +1223,12 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
int index = 0;
bool is_dig = false;
+ bool is_dce5_dac = false;
+ bool is_dce5_dvo = false;
memset(&args, 0, sizeof(args));
@@ -1043,9 +1248,16 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ if (ASIC_IS_DCE5(rdev))
+ is_dce5_dvo = true;
+ else if (ASIC_IS_DCE3(rdev))
+ is_dig = true;
+ else
+ index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+ break;
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
break;
@@ -1057,12 +1269,16 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
- if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
- index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
- else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
- index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
- else
- index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
+ if (ASIC_IS_DCE5(rdev))
+ is_dce5_dac = true;
+ else {
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
+ else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
+ else
+ index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
+ }
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
@@ -1082,34 +1298,113 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ if (connector &&
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector =
+ radeon_connector->con_priv;
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ radeon_dig_connector->edp_on = true;
+ }
dp_link_train(encoder, connector);
if (ASIC_IS_DCE4(rdev))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
}
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+
if (ASIC_IS_DCE4(rdev))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+ if (connector &&
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *radeon_dig_connector =
+ radeon_connector->con_priv;
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ radeon_dig_connector->edp_on = false;
+ }
}
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
+ break;
+ }
+ } else if (is_dce5_dac) {
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ atombios_dac_setup(encoder, ATOM_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ atombios_dac_setup(encoder, ATOM_DISABLE);
+ break;
+ }
+ } else if (is_dce5_dvo) {
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ atombios_dvo_setup(encoder, ATOM_DISABLE);
break;
}
} else {
switch (mode) {
case DRM_MODE_DPMS_ON:
args.ucAction = ATOM_ENABLE;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.ucAction = ATOM_LCD_BLON;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ }
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
args.ucAction = ATOM_DISABLE;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.ucAction = ATOM_LCD_BLOFF;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ }
break;
}
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+
+ if (ext_encoder) {
+ int action;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ default:
+ if (ASIC_IS_DCE41(rdev))
+ action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT;
+ else
+ action = ATOM_ENABLE;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ if (ASIC_IS_DCE41(rdev))
+ action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT;
+ else
+ action = ATOM_DISABLE;
+ break;
+ }
+ atombios_external_encoder_setup(encoder, ext_encoder, action);
+ }
+
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
}
@@ -1242,7 +1537,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
break;
default:
DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
- break;
+ return;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -1293,27 +1588,35 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
struct radeon_encoder_atom_dig *dig;
uint32_t dig_enc_in_use = 0;
+ /* DCE4/5 */
if (ASIC_IS_DCE4(rdev)) {
dig = radeon_encoder->enc_priv;
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ if (ASIC_IS_DCE41(rdev)) {
if (dig->linkb)
return 1;
else
return 0;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
- if (dig->linkb)
- return 3;
- else
- return 2;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
- if (dig->linkb)
- return 5;
- else
- return 4;
- break;
+ } else {
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ if (dig->linkb)
+ return 1;
+ else
+ return 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ if (dig->linkb)
+ return 3;
+ else
+ return 2;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ if (dig->linkb)
+ return 5;
+ else
+ return 4;
+ break;
+ }
}
}
@@ -1357,6 +1660,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -1400,11 +1704,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- atombios_ddia_setup(encoder, ATOM_ENABLE);
- break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
- atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1419,6 +1721,17 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
break;
}
+
+ if (ext_encoder) {
+ if (ASIC_IS_DCE41(rdev)) {
+ atombios_external_encoder_setup(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+ atombios_external_encoder_setup(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
+ } else
+ atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
+ }
+
atombios_apply_encoder_quirks(encoder, adjusted_mode);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
@@ -1520,6 +1833,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
if (radeon_encoder->active_device &
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
@@ -1531,6 +1845,13 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
radeon_atom_output_lock(encoder, true);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+ /* select the clock/data port if it uses a router */
+ if (connector) {
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ if (radeon_connector->router.cd_valid)
+ radeon_router_select_cd_port(radeon_connector);
+ }
+
/* this is needed for the pll/ss setup to work correctly in some cases */
atombios_set_encoder_crtc_source(encoder);
}
@@ -1547,6 +1868,23 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig;
+
+ /* check for pre-DCE3 cards with shared encoders;
+ * can't really use the links individually, so don't disable
+ * the encoder if it's in use by another connector
+ */
+ if (!ASIC_IS_DCE3(rdev)) {
+ struct drm_encoder *other_encoder;
+ struct radeon_encoder *other_radeon_encoder;
+
+ list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+ other_radeon_encoder = to_radeon_encoder(other_encoder);
+ if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) &&
+ drm_helper_encoder_in_use(other_encoder))
+ goto disable_done;
+ }
+ }
+
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
switch (radeon_encoder->encoder_id) {
@@ -1570,11 +1908,9 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
- atombios_ddia_setup(encoder, ATOM_DISABLE);
- break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
- atombios_external_tmds_setup(encoder, ATOM_DISABLE);
+ atombios_dvo_setup(encoder, ATOM_DISABLE);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1586,6 +1922,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
break;
}
+disable_done:
if (radeon_encoder_is_digital(encoder)) {
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
r600_hdmi_disable(encoder);
@@ -1595,6 +1932,53 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
radeon_encoder->active_device = 0;
}
+/* these are handled by the primary encoders */
+static void radeon_atom_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void radeon_atom_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void radeon_atom_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
+ .dpms = radeon_atom_ext_dpms,
+ .mode_fixup = radeon_atom_ext_mode_fixup,
+ .prepare = radeon_atom_ext_prepare,
+ .mode_set = radeon_atom_ext_mode_set,
+ .commit = radeon_atom_ext_commit,
+ .disable = radeon_atom_ext_disable,
+ /* no detect for TMDS/LVDS yet */
+};
+
static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
.dpms = radeon_atom_encoder_dpms,
.mode_fixup = radeon_atom_mode_fixup,
@@ -1662,7 +2046,10 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
}
void
-radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device)
+radeon_add_atom_encoder(struct drm_device *dev,
+ uint32_t encoder_enum,
+ uint32_t supported_device,
+ u16 caps)
{
struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder;
@@ -1704,6 +2091,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
radeon_encoder->devices = supported_device;
radeon_encoder->rmx_type = RMX_OFF;
radeon_encoder->underscan_type = UNDERSCAN_OFF;
+ radeon_encoder->is_ext_encoder = false;
+ radeon_encoder->caps = caps;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
@@ -1745,6 +2134,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
radeon_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+ } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
} else {
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
@@ -1753,5 +2145,24 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break;
+ case ENCODER_OBJECT_ID_SI170B:
+ case ENCODER_OBJECT_ID_CH7303:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+ case ENCODER_OBJECT_ID_TITFP513:
+ case ENCODER_OBJECT_ID_VT1623:
+ case ENCODER_OBJECT_ID_HDMI_SI1930:
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ /* these are handled by the primary encoders */
+ radeon_encoder->is_ext_encoder = true;
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+ else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+ else
+ drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
+ break;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index e329066dcabd..1ca55eb09ad3 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -80,6 +80,10 @@ enum radeon_family {
CHIP_JUNIPER,
CHIP_CYPRESS,
CHIP_HEMLOCK,
+ CHIP_PALM,
+ CHIP_BARTS,
+ CHIP_TURKS,
+ CHIP_CAICOS,
CHIP_LAST,
};
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index efa211898fe6..66324b5bb5ba 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -245,10 +245,8 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
goto out_unref;
}
info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
- info->apertures->ranges[0].size = rdev->mc.real_vram_size;
+ info->apertures->ranges[0].size = rdev->mc.aper_size;
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
info->pixmap.access_align = 32;
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 216392d0353b..171b0b2e3a64 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -38,6 +38,7 @@
#include "drm.h"
#include "radeon_reg.h"
#include "radeon.h"
+#include "radeon_trace.h"
int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
{
@@ -57,6 +58,7 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
} else
radeon_fence_ring_emit(rdev, fence);
+ trace_radeon_fence_emit(rdev->ddev, fence->seq);
fence->emited = true;
list_del(&fence->list);
list_add_tail(&fence->list, &rdev->fence_drv.emited);
@@ -213,6 +215,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
retry:
/* save current sequence used to check for GPU lockup */
seq = rdev->fence_drv.last_seq;
+ trace_radeon_fence_wait_begin(rdev->ddev, seq);
if (intr) {
radeon_irq_kms_sw_irq_get(rdev);
r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
@@ -227,6 +230,7 @@ retry:
radeon_fence_signaled(fence), timeout);
radeon_irq_kms_sw_irq_put(rdev);
}
+ trace_radeon_fence_wait_end(rdev->ddev, seq);
if (unlikely(!radeon_fence_signaled(fence))) {
/* we were interrupted for some reason and fence isn't
* isn't signaled yet, resume wait
@@ -240,7 +244,8 @@ retry:
*/
if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
/* good news we believe it's a lockup */
- WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
+ WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n",
+ fence->seq, seq);
/* FIXME: what should we do ? marking everyone
* as signaled for now
*/
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index e65b90317fab..65016117d95f 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -79,8 +79,8 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
if (rdev->gart.table.vram.robj == NULL) {
r = radeon_bo_create(rdev, NULL, rdev->gart.table_size,
- true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->gart.table.vram.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->gart.table.vram.robj);
if (r) {
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index d1e595d91723..df95eb83dac6 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size,
if (alignment < PAGE_SIZE) {
alignment = PAGE_SIZE;
}
- r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj);
+ r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 6a13ee38a5b9..ded2a45bc95c 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -53,8 +53,8 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
};
/* on hw with routers, select right port */
- if (radeon_connector->router.valid)
- radeon_router_select_port(radeon_connector);
+ if (radeon_connector->router.ddc_valid)
+ radeon_router_select_ddc_port(radeon_connector);
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
if (ret == 2)
@@ -896,7 +896,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
((rdev->family <= CHIP_RS480) ||
((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
/* set the radeon hw i2c adapter */
- sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon i2c hw bus %s", name);
i2c->adapter.algo = &radeon_i2c_algo;
ret = i2c_add_adapter(&i2c->adapter);
if (ret) {
@@ -905,7 +906,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
}
} else {
/* set the radeon bit adapter */
- sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon i2c bit bus %s", name);
i2c->adapter.algo_data = &i2c->algo.bit;
i2c->algo.bit.pre_xfer = pre_xfer;
i2c->algo.bit.post_xfer = post_xfer;
@@ -946,6 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
i2c->rec = *rec;
i2c->adapter.owner = THIS_MODULE;
i2c->dev = dev;
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon aux bus %s", name);
i2c_set_adapdata(&i2c->adapter, i2c);
i2c->adapter.algo_data = &i2c->algo.dp;
i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch;
@@ -1084,26 +1088,51 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
addr, val);
}
-/* router switching */
-void radeon_router_select_port(struct radeon_connector *radeon_connector)
+/* ddc router switching */
+void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
{
u8 val;
- if (!radeon_connector->router.valid)
+ if (!radeon_connector->router.ddc_valid)
return;
radeon_i2c_get_byte(radeon_connector->router_bus,
radeon_connector->router.i2c_addr,
0x3, &val);
- val &= radeon_connector->router.mux_control_pin;
+ val &= ~radeon_connector->router.ddc_mux_control_pin;
radeon_i2c_put_byte(radeon_connector->router_bus,
radeon_connector->router.i2c_addr,
0x3, val);
radeon_i2c_get_byte(radeon_connector->router_bus,
radeon_connector->router.i2c_addr,
0x1, &val);
- val &= radeon_connector->router.mux_control_pin;
- val |= radeon_connector->router.mux_state;
+ val &= ~radeon_connector->router.ddc_mux_control_pin;
+ val |= radeon_connector->router.ddc_mux_state;
+ radeon_i2c_put_byte(radeon_connector->router_bus,
+ radeon_connector->router.i2c_addr,
+ 0x1, val);
+}
+
+/* clock/data router switching */
+void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
+{
+ u8 val;
+
+ if (!radeon_connector->router.cd_valid)
+ return;
+
+ radeon_i2c_get_byte(radeon_connector->router_bus,
+ radeon_connector->router.i2c_addr,
+ 0x3, &val);
+ val &= ~radeon_connector->router.cd_mux_control_pin;
+ radeon_i2c_put_byte(radeon_connector->router_bus,
+ radeon_connector->router.i2c_addr,
+ 0x3, val);
+ radeon_i2c_get_byte(radeon_connector->router_bus,
+ radeon_connector->router.i2c_addr,
+ 0x1, &val);
+ val &= ~radeon_connector->router.cd_mux_control_pin;
+ val |= radeon_connector->router.cd_mux_state;
radeon_i2c_put_byte(radeon_connector->router_bus,
radeon_connector->router.i2c_addr,
0x1, val);
diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c
index 2f349a300195..465746bd51b7 100644
--- a/drivers/gpu/drm/radeon/radeon_irq.c
+++ b/drivers/gpu/drm/radeon/radeon_irq.c
@@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
default:
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
crtc);
- return EINVAL;
+ return -EINVAL;
}
} else {
switch (crtc) {
@@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
default:
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
crtc);
- return EINVAL;
+ return -EINVAL;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index a108c7ed14f5..a289646e8aa4 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -64,15 +64,15 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
struct radeon_device *rdev = dev->dev_private;
unsigned i;
- INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
-
/* Disable *all* interrupts */
rdev->irq.sw_int = false;
rdev->irq.gui_idle = false;
for (i = 0; i < rdev->num_crtc; i++)
rdev->irq.crtc_vblank_int[i] = false;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++) {
rdev->irq.hpd[i] = false;
+ rdev->irq.pflip[i] = false;
+ }
radeon_irq_set(rdev);
/* Clear bits */
radeon_irq_process(rdev);
@@ -101,8 +101,10 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
rdev->irq.gui_idle = false;
for (i = 0; i < rdev->num_crtc; i++)
rdev->irq.crtc_vblank_int[i] = false;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++) {
rdev->irq.hpd[i] = false;
+ rdev->irq.pflip[i] = false;
+ }
radeon_irq_set(rdev);
}
@@ -110,6 +112,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
{
int r = 0;
+ INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+
spin_lock_init(&rdev->irq.sw_lock);
r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
if (r) {
@@ -121,7 +125,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
* chips. Disable MSI on them for now.
*/
if ((rdev->family >= CHIP_RV380) &&
- (!(rdev->flags & RADEON_IS_IGP)) &&
+ ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) &&
(!(rdev->flags & RADEON_IS_AGP))) {
int ret = pci_enable_msi(rdev->pdev);
if (!ret) {
@@ -148,6 +152,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
if (rdev->msi_enabled)
pci_disable_msi(rdev->pdev);
}
+ flush_work_sync(&rdev->hotplug_work);
}
void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev)
@@ -175,3 +180,34 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev)
spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
}
+void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
+{
+ unsigned long irqflags;
+
+ if (crtc < 0 || crtc >= rdev->num_crtc)
+ return;
+
+ spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
+ if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) {
+ rdev->irq.pflip[crtc] = true;
+ radeon_irq_set(rdev);
+ }
+ spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
+}
+
+void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
+{
+ unsigned long irqflags;
+
+ if (crtc < 0 || crtc >= rdev->num_crtc)
+ return;
+
+ spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
+ BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0);
+ if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) {
+ rdev->irq.pflip[crtc] = false;
+ radeon_irq_set(rdev);
+ }
+ spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
+}
+
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 8fbbe1c6ebbd..28a53e4a925f 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -96,9 +96,27 @@ out:
return r;
}
+static void radeon_set_filp_rights(struct drm_device *dev,
+ struct drm_file **owner,
+ struct drm_file *applier,
+ uint32_t *value)
+{
+ mutex_lock(&dev->struct_mutex);
+ if (*value == 1) {
+ /* wants rights */
+ if (!*owner)
+ *owner = applier;
+ } else if (*value == 0) {
+ /* revokes rights */
+ if (*owner == applier)
+ *owner = NULL;
+ }
+ *value = *owner == applier ? 1 : 0;
+ mutex_unlock(&dev->struct_mutex);
+}
/*
- * Userspace get informations ioctl
+ * Userspace get information ioctl
*/
int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
@@ -173,18 +191,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
return -EINVAL;
}
- mutex_lock(&dev->struct_mutex);
- if (value == 1) {
- /* wants hyper-z */
- if (!rdev->hyperz_filp)
- rdev->hyperz_filp = filp;
- } else if (value == 0) {
- /* revokes hyper-z */
- if (rdev->hyperz_filp == filp)
- rdev->hyperz_filp = NULL;
+ radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, &value);
+ break;
+ case RADEON_INFO_WANT_CMASK:
+ /* The same logic as Hyper-Z. */
+ if (value >= 2) {
+ DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", value);
+ return -EINVAL;
}
- value = rdev->hyperz_filp == filp ? 1 : 0;
- mutex_unlock(&dev->struct_mutex);
+ radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value);
break;
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->request);
@@ -203,10 +218,6 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*/
int radeon_driver_firstopen_kms(struct drm_device *dev)
{
- struct radeon_device *rdev = dev->dev_private;
-
- if (rdev->powered_down)
- return -EINVAL;
return 0;
}
@@ -277,6 +288,27 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
radeon_irq_set(rdev);
}
+int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags)
+{
+ struct drm_crtc *drmcrtc;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (crtc < 0 || crtc >= dev->num_crtcs) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
+ return -EINVAL;
+ }
+
+ /* Get associated drm_crtc: */
+ drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
+
+ /* Helper routine in DRM core does all the work: */
+ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+ vblank_time, flags,
+ drmcrtc);
+}
/*
* IOCTL.
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0b8397000f4c..59f834ba283d 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -670,7 +670,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
if (rdev->is_atom_bios) {
radeon_encoder->pixel_clock = adjusted_mode->clock;
- atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+ atombios_dvo_setup(encoder, ATOM_ENABLE);
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
} else {
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 92457163d070..12bdeab91c86 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -277,6 +277,9 @@ struct radeon_crtc {
fixed20_12 hsc;
struct drm_display_mode native_mode;
int pll_id;
+ /* page flipping */
+ struct radeon_unpin_work *unpin_work;
+ int deferred_flip_completion;
};
struct radeon_encoder_primary_dac {
@@ -375,6 +378,8 @@ struct radeon_encoder {
int hdmi_config_offset;
int hdmi_audio_workaround;
int hdmi_buffer_status;
+ bool is_ext_encoder;
+ u16 caps;
};
struct radeon_connector_atom_dig {
@@ -385,6 +390,7 @@ struct radeon_connector_atom_dig {
u8 dp_sink_type;
int dp_clock;
int dp_lane_count;
+ bool edp_on;
};
struct radeon_gpio_rec {
@@ -401,13 +407,19 @@ struct radeon_hpd {
};
struct radeon_router {
- bool valid;
u32 router_id;
struct radeon_i2c_bus_rec i2c_info;
u8 i2c_addr;
- u8 mux_type;
- u8 mux_control_pin;
- u8 mux_state;
+ /* i2c mux */
+ bool ddc_valid;
+ u8 ddc_mux_type;
+ u8 ddc_mux_control_pin;
+ u8 ddc_mux_state;
+ /* clock/data mux */
+ bool cd_valid;
+ u8 cd_mux_type;
+ u8 cd_mux_control_pin;
+ u8 cd_mux_state;
};
struct radeon_connector {
@@ -434,10 +446,6 @@ struct radeon_framebuffer {
struct drm_gem_object *obj;
};
-/* radeon_get_crtc_scanoutpos() return flags */
-#define RADEON_SCANOUTPOS_VALID (1 << 0)
-#define RADEON_SCANOUTPOS_INVBL (1 << 1)
-#define RADEON_SCANOUTPOS_ACCURATE (1 << 2)
extern enum radeon_tv_std
radeon_combios_get_tv_info(struct radeon_device *rdev);
@@ -488,7 +496,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
u8 slave_addr,
u8 addr,
u8 val);
-extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
@@ -516,9 +525,10 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev
struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
-extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
+extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
@@ -552,11 +562,12 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y);
-extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos);
+extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
+ int *vpos, int *hpos);
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
extern struct edid *
-radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
+radeon_bios_get_hardcoded_edid(struct radeon_device *rdev);
extern bool radeon_atom_get_clock_info(struct drm_device *dev);
extern bool radeon_combios_get_clock_info(struct drm_device *dev);
extern struct radeon_encoder_atom_dig *
@@ -652,4 +663,7 @@ int radeon_fbdev_total_size(struct radeon_device *rdev);
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
void radeon_fb_output_poll_changed(struct radeon_device *rdev);
+
+void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
+
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index d7ab91416410..7d6b8e88f746 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -34,6 +34,7 @@
#include <drm/drmP.h>
#include "radeon_drm.h"
#include "radeon.h"
+#include "radeon_trace.h"
int radeon_ttm_init(struct radeon_device *rdev);
@@ -69,7 +70,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
u32 c = 0;
rbo->placement.fpfn = 0;
- rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT;
+ rbo->placement.lpfn = 0;
rbo->placement.placement = rbo->placements;
rbo->placement.busy_placement = rbo->placements;
if (domain & RADEON_GEM_DOMAIN_VRAM)
@@ -86,11 +87,13 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
}
int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
- unsigned long size, bool kernel, u32 domain,
- struct radeon_bo **bo_ptr)
+ unsigned long size, int byte_align, bool kernel, u32 domain,
+ struct radeon_bo **bo_ptr)
{
struct radeon_bo *bo;
enum ttm_bo_type type;
+ unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
+ unsigned long max_size = 0;
int r;
if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
@@ -102,6 +105,16 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
type = ttm_bo_type_device;
}
*bo_ptr = NULL;
+
+ /* maximun bo size is the minimun btw visible vram and gtt size */
+ max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size);
+ if ((page_align << PAGE_SHIFT) >= max_size) {
+ printk(KERN_WARNING "%s:%d alloc size %ldM bigger than %ldMb limit\n",
+ __func__, __LINE__, page_align >> (20 - PAGE_SHIFT), max_size >> 20);
+ return -ENOMEM;
+ }
+
+retry:
bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
if (bo == NULL)
return -ENOMEM;
@@ -109,13 +122,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
bo->gobj = gobj;
bo->surface_reg = -1;
INIT_LIST_HEAD(&bo->list);
-
-retry:
radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */
mutex_lock(&rdev->vram_mutex);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
- &bo->placement, 0, 0, !kernel, NULL, size,
+ &bo->placement, page_align, 0, !kernel, NULL, size,
&radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) {
@@ -136,6 +147,7 @@ retry:
list_add_tail(&bo->list, &rdev->gem.objects);
mutex_unlock(&bo->rdev->gem.mutex);
}
+ trace_radeon_bo_create(bo);
return 0;
}
@@ -292,34 +304,9 @@ void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
struct list_head *head)
{
if (lobj->wdomain) {
- list_add(&lobj->list, head);
+ list_add(&lobj->tv.head, head);
} else {
- list_add_tail(&lobj->list, head);
- }
-}
-
-int radeon_bo_list_reserve(struct list_head *head)
-{
- struct radeon_bo_list *lobj;
- int r;
-
- list_for_each_entry(lobj, head, list){
- r = radeon_bo_reserve(lobj->bo, false);
- if (unlikely(r != 0))
- return r;
- lobj->reserved = true;
- }
- return 0;
-}
-
-void radeon_bo_list_unreserve(struct list_head *head)
-{
- struct radeon_bo_list *lobj;
-
- list_for_each_entry(lobj, head, list) {
- /* only unreserve object we successfully reserved */
- if (lobj->reserved && radeon_bo_is_reserved(lobj->bo))
- radeon_bo_unreserve(lobj->bo);
+ list_add_tail(&lobj->tv.head, head);
}
}
@@ -330,14 +317,11 @@ int radeon_bo_list_validate(struct list_head *head)
u32 domain;
int r;
- list_for_each_entry(lobj, head, list) {
- lobj->reserved = false;
- }
- r = radeon_bo_list_reserve(head);
+ r = ttm_eu_reserve_buffers(head);
if (unlikely(r != 0)) {
return r;
}
- list_for_each_entry(lobj, head, list) {
+ list_for_each_entry(lobj, head, tv.head) {
bo = lobj->bo;
if (!bo->pin_count) {
domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain;
@@ -360,25 +344,6 @@ int radeon_bo_list_validate(struct list_head *head)
return 0;
}
-void radeon_bo_list_fence(struct list_head *head, void *fence)
-{
- struct radeon_bo_list *lobj;
- struct radeon_bo *bo;
- struct radeon_fence *old_fence = NULL;
-
- list_for_each_entry(lobj, head, list) {
- bo = lobj->bo;
- spin_lock(&bo->tbo.lock);
- old_fence = (struct radeon_fence *)bo->tbo.sync_obj;
- bo->tbo.sync_obj = radeon_fence_ref(fence);
- bo->tbo.sync_obj_arg = NULL;
- spin_unlock(&bo->tbo.lock);
- if (old_fence) {
- radeon_fence_unref(&old_fence);
- }
- }
-}
-
int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma)
{
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 3481bc7f6f58..22d4c237dea5 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -126,20 +126,21 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
if (unlikely(r != 0))
return r;
- spin_lock(&bo->tbo.lock);
+ spin_lock(&bo->tbo.bdev->fence_lock);
if (mem_type)
*mem_type = bo->tbo.mem.mem_type;
if (bo->tbo.sync_obj)
r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
- spin_unlock(&bo->tbo.lock);
+ spin_unlock(&bo->tbo.bdev->fence_lock);
ttm_bo_unreserve(&bo->tbo);
return r;
}
extern int radeon_bo_create(struct radeon_device *rdev,
- struct drm_gem_object *gobj, unsigned long size,
- bool kernel, u32 domain,
- struct radeon_bo **bo_ptr);
+ struct drm_gem_object *gobj, unsigned long size,
+ int byte_align,
+ bool kernel, u32 domain,
+ struct radeon_bo **bo_ptr);
extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
extern void radeon_bo_kunmap(struct radeon_bo *bo);
extern void radeon_bo_unref(struct radeon_bo **bo);
@@ -151,10 +152,7 @@ extern int radeon_bo_init(struct radeon_device *rdev);
extern void radeon_bo_fini(struct radeon_device *rdev);
extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
struct list_head *head);
-extern int radeon_bo_list_reserve(struct list_head *head);
-extern void radeon_bo_list_unreserve(struct list_head *head);
extern int radeon_bo_list_validate(struct list_head *head);
-extern void radeon_bo_list_fence(struct list_head *head, void *fence);
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 8c9b2ef32c68..3b1b2bf9cdd5 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -167,13 +167,13 @@ static void radeon_set_power_state(struct radeon_device *rdev)
if (radeon_gui_idle(rdev)) {
sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
clock_info[rdev->pm.requested_clock_mode_index].sclk;
- if (sclk > rdev->clock.default_sclk)
- sclk = rdev->clock.default_sclk;
+ if (sclk > rdev->pm.default_sclk)
+ sclk = rdev->pm.default_sclk;
mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
clock_info[rdev->pm.requested_clock_mode_index].mclk;
- if (mclk > rdev->clock.default_mclk)
- mclk = rdev->clock.default_mclk;
+ if (mclk > rdev->pm.default_mclk)
+ mclk = rdev->pm.default_mclk;
/* upvolt before raising clocks, downvolt after lowering clocks */
if (sclk < rdev->pm.current_sclk)
@@ -405,20 +405,13 @@ static ssize_t radeon_set_pm_method(struct device *dev,
rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
mutex_unlock(&rdev->pm.mutex);
} else if (strncmp("profile", buf, strlen("profile")) == 0) {
- bool flush_wq = false;
-
mutex_lock(&rdev->pm.mutex);
- if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
- cancel_delayed_work(&rdev->pm.dynpm_idle_work);
- flush_wq = true;
- }
/* disable dynpm */
rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
rdev->pm.pm_method = PM_METHOD_PROFILE;
mutex_unlock(&rdev->pm.mutex);
- if (flush_wq)
- flush_workqueue(rdev->wq);
+ cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
} else {
DRM_ERROR("invalid power method!\n");
goto fail;
@@ -447,8 +440,12 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
temp = rv770_get_temp(rdev);
break;
case THERMAL_TYPE_EVERGREEN:
+ case THERMAL_TYPE_NI:
temp = evergreen_get_temp(rdev);
break;
+ case THERMAL_TYPE_SUMO:
+ temp = sumo_get_temp(rdev);
+ break;
default:
temp = 0;
break;
@@ -487,6 +484,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
case THERMAL_TYPE_RV6XX:
case THERMAL_TYPE_RV770:
case THERMAL_TYPE_EVERGREEN:
+ case THERMAL_TYPE_SUMO:
rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
if (IS_ERR(rdev->pm.int_hwmon_dev)) {
err = PTR_ERR(rdev->pm.int_hwmon_dev);
@@ -520,34 +518,39 @@ static void radeon_hwmon_fini(struct radeon_device *rdev)
void radeon_pm_suspend(struct radeon_device *rdev)
{
- bool flush_wq = false;
-
mutex_lock(&rdev->pm.mutex);
if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
- cancel_delayed_work(&rdev->pm.dynpm_idle_work);
if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE)
rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED;
- flush_wq = true;
}
mutex_unlock(&rdev->pm.mutex);
- if (flush_wq)
- flush_workqueue(rdev->wq);
+
+ cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
}
void radeon_pm_resume(struct radeon_device *rdev)
{
+ /* set up the default clocks if the MC ucode is loaded */
+ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
+ if (rdev->pm.default_vddc)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddc);
+ if (rdev->pm.default_sclk)
+ radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+ if (rdev->pm.default_mclk)
+ radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+ }
/* asic init will reset the default power state */
mutex_lock(&rdev->pm.mutex);
rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
rdev->pm.current_clock_mode_index = 0;
- rdev->pm.current_sclk = rdev->clock.default_sclk;
- rdev->pm.current_mclk = rdev->clock.default_mclk;
+ rdev->pm.current_sclk = rdev->pm.default_sclk;
+ rdev->pm.current_mclk = rdev->pm.default_mclk;
rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
if (rdev->pm.pm_method == PM_METHOD_DYNPM
&& rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
- queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ schedule_delayed_work(&rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
}
mutex_unlock(&rdev->pm.mutex);
radeon_pm_compute_clocks(rdev);
@@ -564,6 +567,8 @@ int radeon_pm_init(struct radeon_device *rdev)
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
rdev->pm.dynpm_can_upclock = true;
rdev->pm.dynpm_can_downclock = true;
+ rdev->pm.default_sclk = rdev->clock.default_sclk;
+ rdev->pm.default_mclk = rdev->clock.default_mclk;
rdev->pm.current_sclk = rdev->clock.default_sclk;
rdev->pm.current_mclk = rdev->clock.default_mclk;
rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
@@ -575,12 +580,24 @@ int radeon_pm_init(struct radeon_device *rdev)
radeon_combios_get_power_modes(rdev);
radeon_pm_print_states(rdev);
radeon_pm_init_profile(rdev);
+ /* set up the default clocks if the MC ucode is loaded */
+ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) {
+ if (rdev->pm.default_vddc)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddc);
+ if (rdev->pm.default_sclk)
+ radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+ if (rdev->pm.default_mclk)
+ radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+ }
}
/* set up the internal thermal sensor if applicable */
ret = radeon_hwmon_init(rdev);
if (ret)
return ret;
+
+ INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler);
+
if (rdev->pm.num_power_states > 1) {
/* where's the best place to put these? */
ret = device_create_file(rdev->dev, &dev_attr_power_profile);
@@ -594,8 +611,6 @@ int radeon_pm_init(struct radeon_device *rdev)
rdev->acpi_nb.notifier_call = radeon_acpi_event;
register_acpi_notifier(&rdev->acpi_nb);
#endif
- INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler);
-
if (radeon_debugfs_pm_init(rdev)) {
DRM_ERROR("Failed to register debugfs file for PM!\n");
}
@@ -609,25 +624,20 @@ int radeon_pm_init(struct radeon_device *rdev)
void radeon_pm_fini(struct radeon_device *rdev)
{
if (rdev->pm.num_power_states > 1) {
- bool flush_wq = false;
-
mutex_lock(&rdev->pm.mutex);
if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
rdev->pm.profile = PM_PROFILE_DEFAULT;
radeon_pm_update_profile(rdev);
radeon_pm_set_clocks(rdev);
} else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
- /* cancel work */
- cancel_delayed_work(&rdev->pm.dynpm_idle_work);
- flush_wq = true;
/* reset default clocks */
rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
radeon_pm_set_clocks(rdev);
}
mutex_unlock(&rdev->pm.mutex);
- if (flush_wq)
- flush_workqueue(rdev->wq);
+
+ cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
device_remove_file(rdev->dev, &dev_attr_power_profile);
device_remove_file(rdev->dev, &dev_attr_power_method);
@@ -686,12 +696,12 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
radeon_pm_get_dynpm_state(rdev);
radeon_pm_set_clocks(rdev);
- queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ schedule_delayed_work(&rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
} else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) {
rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
- queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ schedule_delayed_work(&rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n");
}
} else { /* count == 0 */
@@ -720,9 +730,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
*/
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
if (rdev->pm.active_crtcs & (1 << crtc)) {
- vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos);
- if ((vbl_status & RADEON_SCANOUTPOS_VALID) &&
- !(vbl_status & RADEON_SCANOUTPOS_INVBL))
+ vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos);
+ if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
+ !(vbl_status & DRM_SCANOUTPOS_INVBL))
in_vbl = false;
}
}
@@ -796,8 +806,8 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
radeon_pm_set_clocks(rdev);
}
- queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ schedule_delayed_work(&rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
}
mutex_unlock(&rdev->pm.mutex);
ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
@@ -814,9 +824,9 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk);
+ seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
- seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk);
+ seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
if (rdev->asic->get_memory_clock)
seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
if (rdev->pm.current_vddc)
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index 64928814de53..3cd4dace57c7 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -55,6 +55,7 @@
#include "r500_reg.h"
#include "r600_reg.h"
#include "evergreen_reg.h"
+#include "ni_reg.h"
#define RADEON_MC_AGP_LOCATION 0x014c
#define RADEON_MC_AGP_START_MASK 0x0000FFFF
@@ -320,6 +321,15 @@
# define RADEON_PCIE_LC_RECONFIG_NOW (1 << 8)
# define RADEON_PCIE_LC_RECONFIG_LATER (1 << 9)
# define RADEON_PCIE_LC_SHORT_RECONFIG_EN (1 << 10)
+# define R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define R600_PCIE_LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define R600_PCIE_LC_RENEGOTIATE_EN (1 << 10)
+# define R600_PCIE_LC_SHORT_RECONFIG_EN (1 << 11)
+# define R600_PCIE_LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define R600_PCIE_LC_UPCONFIGURE_DIS (1 << 13)
+
+#define R600_TARGET_AND_CURRENT_PROFILE_INDEX 0x70c
+#define R700_TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
#define RADEON_CACHE_CNTL 0x1724
#define RADEON_CACHE_LINE 0x0f0c /* PCI */
@@ -422,6 +432,7 @@
# define RADEON_CRTC_CSYNC_EN (1 << 4)
# define RADEON_CRTC_ICON_EN (1 << 15)
# define RADEON_CRTC_CUR_EN (1 << 16)
+# define RADEON_CRTC_VSTAT_MODE_MASK (3 << 17)
# define RADEON_CRTC_CUR_MODE_MASK (7 << 20)
# define RADEON_CRTC_CUR_MODE_SHIFT 20
# define RADEON_CRTC_CUR_MODE_MONO 0
@@ -509,6 +520,8 @@
# define RADEON_CRTC_TILE_EN (1 << 15)
# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16)
# define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17)
+# define RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN (1 << 28)
+# define RADEON_CRTC_GUI_TRIG_OFFSET_RIGHT_EN (1 << 29)
#define R300_CRTC_TILE_X0_Y0 0x0350
#define R300_CRTC2_TILE_X0_Y0 0x0358
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 6ea798ce8218..06e79822a2bf 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -176,8 +176,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
/* Allocate 1M object buffer */
r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024,
- true, RADEON_GEM_DOMAIN_GTT,
- &rdev->ib_pool.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+ &rdev->ib_pool.robj);
if (r) {
DRM_ERROR("radeon: failed to ib pool (%d).\n", r);
return r;
@@ -332,7 +332,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size)
rdev->cp.ring_size = ring_size;
/* Allocate ring buffer */
if (rdev->cp.ring_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true,
+ r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT,
&rdev->cp.ring_obj);
if (r) {
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index 313c96bc09da..5b44f652145c 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -52,7 +52,7 @@ void radeon_test_moves(struct radeon_device *rdev)
goto out_cleanup;
}
- r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM,
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
&vram_obj);
if (r) {
DRM_ERROR("Failed to create VRAM object\n");
@@ -71,7 +71,7 @@ void radeon_test_moves(struct radeon_device *rdev)
void **gtt_start, **gtt_end;
void **vram_start, **vram_end;
- r = radeon_bo_create(rdev, NULL, size, true,
+ r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, gtt_obj + i);
if (r) {
DRM_ERROR("Failed to create GTT object %d\n", i);
diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h
new file mode 100644
index 000000000000..eafd8160a155
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_trace.h
@@ -0,0 +1,82 @@
+#if !defined(_RADEON_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _RADEON_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include <drm/drmP.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM radeon
+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
+#define TRACE_INCLUDE_FILE radeon_trace
+
+TRACE_EVENT(radeon_bo_create,
+ TP_PROTO(struct radeon_bo *bo),
+ TP_ARGS(bo),
+ TP_STRUCT__entry(
+ __field(struct radeon_bo *, bo)
+ __field(u32, pages)
+ ),
+
+ TP_fast_assign(
+ __entry->bo = bo;
+ __entry->pages = bo->tbo.num_pages;
+ ),
+ TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages)
+);
+
+DECLARE_EVENT_CLASS(radeon_fence_request,
+
+ TP_PROTO(struct drm_device *dev, u32 seqno),
+
+ TP_ARGS(dev, seqno),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(u32, seqno)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->seqno = seqno;
+ ),
+
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
+);
+
+DEFINE_EVENT(radeon_fence_request, radeon_fence_emit,
+
+ TP_PROTO(struct drm_device *dev, u32 seqno),
+
+ TP_ARGS(dev, seqno)
+);
+
+DEFINE_EVENT(radeon_fence_request, radeon_fence_retire,
+
+ TP_PROTO(struct drm_device *dev, u32 seqno),
+
+ TP_ARGS(dev, seqno)
+);
+
+DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin,
+
+ TP_PROTO(struct drm_device *dev, u32 seqno),
+
+ TP_ARGS(dev, seqno)
+);
+
+DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end,
+
+ TP_PROTO(struct drm_device *dev, u32 seqno),
+
+ TP_ARGS(dev, seqno)
+);
+
+#endif
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/radeon/radeon_trace_points.c b/drivers/gpu/drm/radeon/radeon_trace_points.c
new file mode 100644
index 000000000000..8175993df84d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_trace_points.c
@@ -0,0 +1,9 @@
+/* Copyright Red Hat Inc 2010.
+ * Author : Dave Airlie <airlied@redhat.com>
+ */
+#include <drm/drmP.h>
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#define CREATE_TRACE_POINTS
+#include "radeon_trace.h"
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index fe95bb35317e..1272e4b6a1d4 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -529,7 +529,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
}
- r = radeon_bo_create(rdev, NULL, 256 * 1024, true,
+ r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM,
&rdev->stollen_vga_memory);
if (r) {
@@ -689,7 +689,8 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
gtt = container_of(backend, struct radeon_ttm_backend, backend);
gtt->offset = bo_mem->start << PAGE_SHIFT;
if (!gtt->num_pages) {
- WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
+ WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
+ gtt->num_pages, bo_mem, backend);
}
r = radeon_gart_bind(gtt->rdev, gtt->offset,
gtt->num_pages, gtt->pages);
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index ac40fd39d787..9177f9191837 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -439,7 +439,7 @@ evergreen 0x9400
0x000286EC SPI_COMPUTE_NUM_THREAD_X
0x000286F0 SPI_COMPUTE_NUM_THREAD_Y
0x000286F4 SPI_COMPUTE_NUM_THREAD_Z
-0x000286F8 GDS_ADDR_SIZE
+0x00028724 GDS_ADDR_SIZE
0x00028780 CB_BLEND0_CONTROL
0x00028784 CB_BLEND1_CONTROL
0x00028788 CB_BLEND2_CONTROL
diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515
index b3f9f1d92005..ef422bbacfc1 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/rv515
+++ b/drivers/gpu/drm/radeon/reg_srcs/rv515
@@ -304,6 +304,22 @@ rv515 0x6d40
0x4630 US_CODE_ADDR
0x4634 US_CODE_RANGE
0x4638 US_CODE_OFFSET
+0x4640 US_FORMAT0_0
+0x4644 US_FORMAT0_1
+0x4648 US_FORMAT0_2
+0x464C US_FORMAT0_3
+0x4650 US_FORMAT0_4
+0x4654 US_FORMAT0_5
+0x4658 US_FORMAT0_6
+0x465C US_FORMAT0_7
+0x4660 US_FORMAT0_8
+0x4664 US_FORMAT0_9
+0x4668 US_FORMAT0_10
+0x466C US_FORMAT0_11
+0x4670 US_FORMAT0_12
+0x4674 US_FORMAT0_13
+0x4678 US_FORMAT0_14
+0x467C US_FORMAT0_15
0x46A4 US_OUT_FMT_0
0x46A8 US_OUT_FMT_1
0x46AC US_OUT_FMT_2
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index f683e51a2a06..5512e4e5e636 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -78,7 +78,7 @@ int rs400_gart_init(struct radeon_device *rdev)
int r;
if (rdev->gart.table.ram.ptr) {
- WARN(1, "RS400 GART already initialized.\n");
+ WARN(1, "RS400 GART already initialized\n");
return 0;
}
/* Check gart size */
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index b091a1f6fa4e..5afe294ed51f 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -46,6 +46,56 @@
void rs600_gpu_init(struct radeon_device *rdev);
int rs600_mc_wait_for_idle(struct radeon_device *rdev);
+void rs600_pre_page_flip(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ u32 tmp;
+
+ /* make sure flip is at vb rather than hb */
+ tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset);
+ tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;
+ WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp);
+
+ /* set pageflip to happen anywhere in vblank interval */
+ WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
+
+ /* enable the pflip int */
+ radeon_irq_kms_pflip_irq_get(rdev, crtc);
+}
+
+void rs600_post_page_flip(struct radeon_device *rdev, int crtc)
+{
+ /* disable the pflip int */
+ radeon_irq_kms_pflip_irq_put(rdev, crtc);
+}
+
+u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+ u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
+
+ /* Lock the graphics update lock */
+ tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* update the scanout addresses */
+ WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+ WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+
+ /* Wait for update_pending to go high. */
+ while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING));
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* Return current update_pending status: */
+ return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING;
+}
+
void rs600_pm_misc(struct radeon_device *rdev)
{
int requested_index = rdev->pm.requested_power_state_index;
@@ -289,16 +339,16 @@ void rs600_bm_disable(struct radeon_device *rdev)
int rs600_asic_reset(struct radeon_device *rdev)
{
- u32 status, tmp;
-
struct rv515_mc_save save;
+ u32 status, tmp;
+ int ret = 0;
- /* Stops all mc clients */
- rv515_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ /* Stops all mc clients */
+ rv515_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -342,11 +392,11 @@ int rs600_asic_reset(struct radeon_device *rdev)
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
rv515_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
/*
@@ -375,7 +425,7 @@ int rs600_gart_init(struct radeon_device *rdev)
int r;
if (rdev->gart.table.vram.robj) {
- WARN(1, "RS600 GART already initialized.\n");
+ WARN(1, "RS600 GART already initialized\n");
return 0;
}
/* Initialize common gart structure */
@@ -505,7 +555,7 @@ int rs600_irq_set(struct radeon_device *rdev)
~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
if (!rdev->irq.installed) {
- WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+ WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
WREG32(R_000040_GEN_INT_CNTL, 0);
return -EINVAL;
}
@@ -515,10 +565,12 @@ int rs600_irq_set(struct radeon_device *rdev)
if (rdev->irq.gui_idle) {
tmp |= S_000040_GUI_IDLE(1);
}
- if (rdev->irq.crtc_vblank_int[0]) {
+ if (rdev->irq.crtc_vblank_int[0] ||
+ rdev->irq.pflip[0]) {
mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1);
}
- if (rdev->irq.crtc_vblank_int[1]) {
+ if (rdev->irq.crtc_vblank_int[1] ||
+ rdev->irq.pflip[1]) {
mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1);
}
if (rdev->irq.hpd[0]) {
@@ -534,7 +586,7 @@ int rs600_irq_set(struct radeon_device *rdev)
return 0;
}
-static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int)
+static inline u32 rs600_irq_ack(struct radeon_device *rdev)
{
uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS);
uint32_t irq_mask = S_000044_SW_INT(1);
@@ -547,27 +599,27 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_
}
if (G_000044_DISPLAY_INT_STAT(irqs)) {
- *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
- if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) {
+ rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
WREG32(R_006534_D1MODE_VBLANK_STATUS,
S_006534_D1MODE_VBLANK_ACK(1));
}
- if (G_007EDC_LB_D2_VBLANK_INTERRUPT(*r500_disp_int)) {
+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
WREG32(R_006D34_D2MODE_VBLANK_STATUS,
S_006D34_D2MODE_VBLANK_ACK(1));
}
- if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(*r500_disp_int)) {
+ if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL);
tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(1);
WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
}
- if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(*r500_disp_int)) {
+ if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL);
tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(1);
WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
}
} else {
- *r500_disp_int = 0;
+ rdev->irq.stat_regs.r500.disp_int = 0;
}
if (irqs) {
@@ -578,32 +630,30 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_
void rs600_irq_disable(struct radeon_device *rdev)
{
- u32 tmp;
-
WREG32(R_000040_GEN_INT_CNTL, 0);
WREG32(R_006540_DxMODE_INT_MASK, 0);
/* Wait and acknowledge irq */
mdelay(1);
- rs600_irq_ack(rdev, &tmp);
+ rs600_irq_ack(rdev);
}
int rs600_irq_process(struct radeon_device *rdev)
{
- uint32_t status, msi_rearm;
- uint32_t r500_disp_int;
+ u32 status, msi_rearm;
bool queue_hotplug = false;
/* reset gui idle ack. the status bit is broken */
rdev->irq.gui_idle_acked = false;
- status = rs600_irq_ack(rdev, &r500_disp_int);
- if (!status && !r500_disp_int) {
+ status = rs600_irq_ack(rdev);
+ if (!status && !rdev->irq.stat_regs.r500.disp_int) {
return IRQ_NONE;
}
- while (status || r500_disp_int) {
+ while (status || rdev->irq.stat_regs.r500.disp_int) {
/* SW interrupt */
- if (G_000044_SW_INT(status))
+ if (G_000044_SW_INT(status)) {
radeon_fence_process(rdev);
+ }
/* GUI idle */
if (G_000040_GUI_IDLE(status)) {
rdev->irq.gui_idle_acked = true;
@@ -611,30 +661,38 @@ int rs600_irq_process(struct radeon_device *rdev)
wake_up(&rdev->irq.idle_queue);
}
/* Vertical blank interrupts */
- if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
- drm_handle_vblank(rdev->ddev, 0);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
+ if (rdev->irq.crtc_vblank_int[0]) {
+ drm_handle_vblank(rdev->ddev, 0);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[0])
+ radeon_crtc_handle_flip(rdev, 0);
}
- if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
- drm_handle_vblank(rdev->ddev, 1);
- rdev->pm.vblank_sync = true;
- wake_up(&rdev->irq.vblank_queue);
+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
+ if (rdev->irq.crtc_vblank_int[1]) {
+ drm_handle_vblank(rdev->ddev, 1);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (rdev->irq.pflip[1])
+ radeon_crtc_handle_flip(rdev, 1);
}
- if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
+ if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
queue_hotplug = true;
DRM_DEBUG("HPD1\n");
}
- if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) {
+ if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
queue_hotplug = true;
DRM_DEBUG("HPD2\n");
}
- status = rs600_irq_ack(rdev, &r500_disp_int);
+ status = rs600_irq_ack(rdev);
}
/* reset gui idle ack. the status bit is broken */
rdev->irq.gui_idle_acked = false;
if (queue_hotplug)
- queue_work(rdev->wq, &rdev->hotplug_work);
+ schedule_work(&rdev->hotplug_work);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS600:
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 245374e2b778..491dc9000655 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -41,6 +41,41 @@
static void rv770_gpu_init(struct radeon_device *rdev);
void rv770_fini(struct radeon_device *rdev);
+static void rv770_pcie_gen2_enable(struct radeon_device *rdev);
+
+u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+ u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
+
+ /* Lock the graphics update lock */
+ tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* update the scanout addresses */
+ if (radeon_crtc->crtc_id) {
+ WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base));
+ WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base));
+ } else {
+ WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base));
+ WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base));
+ }
+ WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+ WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)crtc_base);
+
+ /* Wait for update_pending to go high. */
+ while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING));
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
+
+ /* Return current update_pending status: */
+ return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING;
+}
/* get temperature in millidegrees */
u32 rv770_get_temp(struct radeon_device *rdev)
@@ -489,6 +524,49 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
+static void rv770_program_channel_remap(struct radeon_device *rdev)
+{
+ u32 tcp_chan_steer, mc_shared_chremap, tmp;
+ bool force_no_swizzle;
+
+ switch (rdev->family) {
+ case CHIP_RV770:
+ case CHIP_RV730:
+ force_no_swizzle = false;
+ break;
+ case CHIP_RV710:
+ case CHIP_RV740:
+ default:
+ force_no_swizzle = true;
+ break;
+ }
+
+ tmp = RREG32(MC_SHARED_CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ case 1:
+ default:
+ /* default mapping */
+ mc_shared_chremap = 0x00fac688;
+ break;
+ case 2:
+ case 3:
+ if (force_no_swizzle)
+ mc_shared_chremap = 0x00fac688;
+ else
+ mc_shared_chremap = 0x00bbc298;
+ break;
+ }
+
+ if (rdev->family == CHIP_RV740)
+ tcp_chan_steer = 0x00ef2a60;
+ else
+ tcp_chan_steer = 0x00fac688;
+
+ WREG32(TCP_CHAN_STEER, tcp_chan_steer);
+ WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
+}
+
static void rv770_gpu_init(struct radeon_device *rdev)
{
int i, j, num_qd_pipes;
@@ -688,6 +766,8 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
+ rv770_program_channel_remap(rdev);
+
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
@@ -915,8 +995,8 @@ static int rv770_vram_scratch_init(struct radeon_device *rdev)
if (rdev->vram_scratch.robj == NULL) {
r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
- true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->vram_scratch.robj);
+ PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->vram_scratch.robj);
if (r) {
return r;
}
@@ -956,6 +1036,45 @@ static void rv770_vram_scratch_fini(struct radeon_device *rdev)
radeon_bo_unref(&rdev->vram_scratch.robj);
}
+void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
+{
+ u64 size_bf, size_af;
+
+ if (mc->mc_vram_size > 0xE0000000) {
+ /* leave room for at least 512M GTT */
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = 0xE0000000;
+ mc->mc_vram_size = 0xE0000000;
+ }
+ if (rdev->flags & RADEON_IS_AGP) {
+ size_bf = mc->gtt_start;
+ size_af = 0xFFFFFFFF - mc->gtt_end + 1;
+ if (size_bf > size_af) {
+ if (mc->mc_vram_size > size_bf) {
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = size_bf;
+ mc->mc_vram_size = size_bf;
+ }
+ mc->vram_start = mc->gtt_start - mc->mc_vram_size;
+ } else {
+ if (mc->mc_vram_size > size_af) {
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = size_af;
+ mc->mc_vram_size = size_af;
+ }
+ mc->vram_start = mc->gtt_end;
+ }
+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+ mc->mc_vram_size >> 20, mc->vram_start,
+ mc->vram_end, mc->real_vram_size >> 20);
+ } else {
+ radeon_vram_location(rdev, &rdev->mc, 0);
+ rdev->mc.gtt_base_align = 0;
+ radeon_gtt_location(rdev, mc);
+ }
+}
+
int rv770_mc_init(struct radeon_device *rdev)
{
u32 tmp;
@@ -996,7 +1115,7 @@ int rv770_mc_init(struct radeon_device *rdev)
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
- r600_vram_gtt_location(rdev, &rdev->mc);
+ r700_vram_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
return 0;
@@ -1006,6 +1125,9 @@ static int rv770_startup(struct radeon_device *rdev)
{
int r;
+ /* enable pcie gen2 link */
+ rv770_pcie_gen2_enable(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
@@ -1146,7 +1268,7 @@ int rv770_init(struct radeon_device *rdev)
if (r)
return r;
/* Post card if necessary */
- if (!r600_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -1244,3 +1366,78 @@ void rv770_fini(struct radeon_device *rdev)
rdev->bios = NULL;
radeon_dummy_page_fini(rdev);
}
+
+static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
+{
+ u32 link_width_cntl, lanes, speed_cntl, tmp;
+ u16 link_cntl2;
+
+ if (radeon_pcie_gen2 == 0)
+ return;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ /* x2 cards have a special sequence */
+ if (ASIC_IS_X2(rdev))
+ return;
+
+ /* advertise upconfig capability */
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) {
+ lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT;
+ link_width_cntl &= ~(LC_LINK_WIDTH_MASK |
+ LC_RECONFIG_ARC_MISSING_ESCAPE);
+ link_width_cntl |= lanes | LC_RECONFIG_NOW |
+ LC_RENEGOTIATE_EN | LC_UPCONFIGURE_SUPPORT;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ } else {
+ link_width_cntl |= LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ }
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+
+ tmp = RREG32(0x541c);
+ WREG32(0x541c, tmp | 0x8);
+ WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN);
+ link_cntl2 = RREG16(0x4088);
+ link_cntl2 &= ~TARGET_LINK_SPEED_MASK;
+ link_cntl2 |= 0x2;
+ WREG16(0x4088, link_cntl2);
+ WREG32(MM_CFGREGS_CNTL, 0);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_GEN2_EN_STRAP;
+ WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ } else {
+ link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL);
+ /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */
+ if (1)
+ link_width_cntl |= LC_UPCONFIGURE_DIS;
+ else
+ link_width_cntl &= ~LC_UPCONFIGURE_DIS;
+ WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ }
+}
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index b7a5a20e81dc..abc8cf5a3672 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -138,6 +138,7 @@
#define MC_SHARED_CHMAP 0x2004
#define NOOFCHAN_SHIFT 12
#define NOOFCHAN_MASK 0x00003000
+#define MC_SHARED_CHREMAP 0x2008
#define MC_ARB_RAMCFG 0x2760
#define NOOFBANK_SHIFT 0
@@ -303,6 +304,7 @@
#define BILINEAR_PRECISION_8_BIT (1 << 31)
#define TCP_CNTL 0x9610
+#define TCP_CHAN_STEER 0x9614
#define VGT_CACHE_INVALIDATION 0x88C4
#define CACHE_INVALIDATION(x) ((x)<<0)
@@ -351,4 +353,49 @@
#define SRBM_STATUS 0x0E50
+#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
+#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914
+#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114
+#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118
+#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c
+#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c
+
+/* PCIE link stuff */
+#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
+#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
+# define LC_LINK_WIDTH_SHIFT 0
+# define LC_LINK_WIDTH_MASK 0x7
+# define LC_LINK_WIDTH_X0 0
+# define LC_LINK_WIDTH_X1 1
+# define LC_LINK_WIDTH_X2 2
+# define LC_LINK_WIDTH_X4 3
+# define LC_LINK_WIDTH_X8 4
+# define LC_LINK_WIDTH_X16 6
+# define LC_LINK_WIDTH_RD_SHIFT 4
+# define LC_LINK_WIDTH_RD_MASK 0x70
+# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define LC_RECONFIG_NOW (1 << 8)
+# define LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define LC_RENEGOTIATE_EN (1 << 10)
+# define LC_SHORT_RECONFIG_EN (1 << 11)
+# define LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define LC_UPCONFIGURE_DIS (1 << 13)
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+#define MM_CFGREGS_CNTL 0x544c
+# define MM_WR_TO_CFG_EN (1 << 3)
+#define LINK_CNTL2 0x88 /* F0 */
+# define TARGET_LINK_SPEED_MASK (0xf << 0)
+# define SELECTABLE_DEEMPHASIS (1 << 6)
+
#endif
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index a1cb783c7131..af61fc29e843 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -27,14 +27,6 @@
/*
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/
-/* Notes:
- *
- * We store bo pointer in drm_mm_node struct so we know which bo own a
- * specific node. There is no protection on the pointer, thus to make
- * sure things don't go berserk you have to access this pointer while
- * holding the global lru lock and make sure anytime you free a node you
- * reset the pointer to NULL.
- */
#include "ttm/ttm_module.h"
#include "ttm/ttm_bo_driver.h"
@@ -45,6 +37,7 @@
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/module.h>
+#include <asm/atomic.h>
#define TTM_ASSERT_LOCKED(param)
#define TTM_DEBUG(fmt, arg...)
@@ -176,7 +169,7 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
}
EXPORT_SYMBOL(ttm_bo_wait_unreserved);
-static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
+void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_mem_type_manager *man;
@@ -198,11 +191,7 @@ static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
}
}
-/**
- * Call with the lru_lock held.
- */
-
-static int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
+int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
{
int put_count = 0;
@@ -231,9 +220,21 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
int ret;
while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
- if (use_sequence && bo->seq_valid &&
- (sequence - bo->val_seq < (1 << 31))) {
- return -EAGAIN;
+ /**
+ * Deadlock avoidance for multi-bo reserving.
+ */
+ if (use_sequence && bo->seq_valid) {
+ /**
+ * We've already reserved this one.
+ */
+ if (unlikely(sequence == bo->val_seq))
+ return -EDEADLK;
+ /**
+ * Already reserved by a thread that will not back
+ * off for us. We need to back off.
+ */
+ if (unlikely(sequence - bo->val_seq < (1 << 31)))
+ return -EAGAIN;
}
if (no_wait)
@@ -248,6 +249,14 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
}
if (use_sequence) {
+ /**
+ * Wake up waiters that may need to recheck for deadlock,
+ * if we decreased the sequence number.
+ */
+ if (unlikely((bo->val_seq - sequence < (1 << 31))
+ || !bo->seq_valid))
+ wake_up_all(&bo->event_queue);
+
bo->val_seq = sequence;
bo->seq_valid = true;
} else {
@@ -263,6 +272,13 @@ static void ttm_bo_ref_bug(struct kref *list_kref)
BUG();
}
+void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count,
+ bool never_free)
+{
+ kref_sub(&bo->list_kref, count,
+ (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list);
+}
+
int ttm_bo_reserve(struct ttm_buffer_object *bo,
bool interruptible,
bool no_wait, bool use_sequence, uint32_t sequence)
@@ -278,20 +294,24 @@ int ttm_bo_reserve(struct ttm_buffer_object *bo,
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
- while (put_count--)
- kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ ttm_bo_list_ref_sub(bo, put_count, true);
return ret;
}
+void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo)
+{
+ ttm_bo_add_to_lru(bo);
+ atomic_set(&bo->reserved, 0);
+ wake_up_all(&bo->event_queue);
+}
+
void ttm_bo_unreserve(struct ttm_buffer_object *bo)
{
struct ttm_bo_global *glob = bo->glob;
spin_lock(&glob->lru_lock);
- ttm_bo_add_to_lru(bo);
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
+ ttm_bo_unreserve_locked(bo);
spin_unlock(&glob->lru_lock);
}
EXPORT_SYMBOL(ttm_bo_unreserve);
@@ -358,8 +378,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
int ret = 0;
if (old_is_pci || new_is_pci ||
- ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0))
- ttm_bo_unmap_virtual(bo);
+ ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) {
+ ret = ttm_mem_io_lock(old_man, true);
+ if (unlikely(ret != 0))
+ goto out_err;
+ ttm_bo_unmap_virtual_locked(bo);
+ ttm_mem_io_unlock(old_man);
+ }
/*
* Create and bind a ttm if required.
@@ -412,11 +437,9 @@ moved:
}
if (bo->mem.mm_node) {
- spin_lock(&bo->lock);
bo->offset = (bo->mem.start << PAGE_SHIFT) +
bdev->man[bo->mem.mem_type].gpu_offset;
bo->cur_placement = bo->mem.placement;
- spin_unlock(&bo->lock);
} else
bo->offset = 0;
@@ -448,10 +471,14 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
-
ttm_bo_mem_put(bo, &bo->mem);
atomic_set(&bo->reserved, 0);
+
+ /*
+ * Make processes trying to reserve really pick it up.
+ */
+ smp_mb__after_atomic_dec();
wake_up_all(&bo->event_queue);
}
@@ -460,19 +487,19 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bo->glob;
struct ttm_bo_driver *driver;
- void *sync_obj;
+ void *sync_obj = NULL;
void *sync_obj_arg;
int put_count;
int ret;
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
(void) ttm_bo_wait(bo, false, false, true);
if (!bo->sync_obj) {
spin_lock(&glob->lru_lock);
/**
- * Lock inversion between bo::reserve and bo::lock here,
+ * Lock inversion between bo:reserve and bdev::fence_lock here,
* but that's OK, since we're only trylocking.
*/
@@ -481,31 +508,33 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
if (unlikely(ret == -EBUSY))
goto queue;
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
ttm_bo_cleanup_memtype_use(bo);
- while (put_count--)
- kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ ttm_bo_list_ref_sub(bo, put_count, true);
return;
} else {
spin_lock(&glob->lru_lock);
}
queue:
- sync_obj = bo->sync_obj;
- sync_obj_arg = bo->sync_obj_arg;
driver = bdev->driver;
+ if (bo->sync_obj)
+ sync_obj = driver->sync_obj_ref(bo->sync_obj);
+ sync_obj_arg = bo->sync_obj_arg;
kref_get(&bo->list_kref);
list_add_tail(&bo->ddestroy, &bdev->ddestroy);
spin_unlock(&glob->lru_lock);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
- if (sync_obj)
+ if (sync_obj) {
driver->sync_obj_flush(sync_obj, sync_obj_arg);
+ driver->sync_obj_unref(&sync_obj);
+ }
schedule_delayed_work(&bdev->wq,
((HZ / 100) < 1) ? 1 : HZ / 100);
}
@@ -525,14 +554,15 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
bool no_wait_reserve,
bool no_wait_gpu)
{
+ struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bo->glob;
int put_count;
int ret = 0;
retry:
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (unlikely(ret != 0))
return ret;
@@ -568,8 +598,7 @@ retry:
spin_unlock(&glob->lru_lock);
ttm_bo_cleanup_memtype_use(bo);
- while (put_count--)
- kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ ttm_bo_list_ref_sub(bo, put_count, true);
return 0;
}
@@ -640,6 +669,7 @@ static void ttm_bo_release(struct kref *kref)
struct ttm_buffer_object *bo =
container_of(kref, struct ttm_buffer_object, kref);
struct ttm_bo_device *bdev = bo->bdev;
+ struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
if (likely(bo->vm_node != NULL)) {
rb_erase(&bo->vm_rb, &bdev->addr_space_rb);
@@ -647,6 +677,9 @@ static void ttm_bo_release(struct kref *kref)
bo->vm_node = NULL;
}
write_unlock(&bdev->vm_lock);
+ ttm_mem_io_lock(man, false);
+ ttm_mem_io_free_vm(bo);
+ ttm_mem_io_unlock(man);
ttm_bo_cleanup_refs_or_queue(bo);
kref_put(&bo->list_kref, ttm_bo_release_list);
write_lock(&bdev->vm_lock);
@@ -686,9 +719,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
struct ttm_placement placement;
int ret = 0;
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (unlikely(ret != 0)) {
if (ret != -ERESTARTSYS) {
@@ -703,7 +736,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
evict_mem = bo->mem;
evict_mem.mm_node = NULL;
- evict_mem.bus.io_reserved = false;
+ evict_mem.bus.io_reserved_vm = false;
+ evict_mem.bus.io_reserved_count = 0;
placement.fpfn = 0;
placement.lpfn = 0;
@@ -790,8 +824,7 @@ retry:
BUG_ON(ret != 0);
- while (put_count--)
- kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ ttm_bo_list_ref_sub(bo, put_count, true);
ret = ttm_bo_evict(bo, interruptible, no_wait_reserve, no_wait_gpu);
ttm_bo_unreserve(bo);
@@ -822,7 +855,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
bool no_wait_gpu)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_bo_global *glob = bdev->glob;
struct ttm_mem_type_manager *man = &bdev->man[mem_type];
int ret;
@@ -832,12 +864,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
return ret;
if (mem->mm_node)
break;
- spin_lock(&glob->lru_lock);
- if (list_empty(&man->lru)) {
- spin_unlock(&glob->lru_lock);
- break;
- }
- spin_unlock(&glob->lru_lock);
ret = ttm_mem_evict_first(bdev, mem_type, interruptible,
no_wait_reserve, no_wait_gpu);
if (unlikely(ret != 0))
@@ -1031,6 +1057,7 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
{
int ret = 0;
struct ttm_mem_reg mem;
+ struct ttm_bo_device *bdev = bo->bdev;
BUG_ON(!atomic_read(&bo->reserved));
@@ -1039,15 +1066,16 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
* Have the driver move function wait for idle when necessary,
* instead of doing it here.
*/
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (ret)
return ret;
mem.num_pages = bo->num_pages;
mem.size = mem.num_pages << PAGE_SHIFT;
mem.page_alignment = bo->mem.page_alignment;
- mem.bus.io_reserved = false;
+ mem.bus.io_reserved_vm = false;
+ mem.bus.io_reserved_count = 0;
/*
* Determine where to move the buffer.
*/
@@ -1125,35 +1153,9 @@ EXPORT_SYMBOL(ttm_bo_validate);
int ttm_bo_check_placement(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
- int i;
+ BUG_ON((placement->fpfn || placement->lpfn) &&
+ (bo->mem.num_pages > (placement->lpfn - placement->fpfn)));
- if (placement->fpfn || placement->lpfn) {
- if (bo->mem.num_pages > (placement->lpfn - placement->fpfn)) {
- printk(KERN_ERR TTM_PFX "Page number range to small "
- "Need %lu pages, range is [%u, %u]\n",
- bo->mem.num_pages, placement->fpfn,
- placement->lpfn);
- return -EINVAL;
- }
- }
- for (i = 0; i < placement->num_placement; i++) {
- if (!capable(CAP_SYS_ADMIN)) {
- if (placement->placement[i] & TTM_PL_FLAG_NO_EVICT) {
- printk(KERN_ERR TTM_PFX "Need to be root to "
- "modify NO_EVICT status.\n");
- return -EINVAL;
- }
- }
- }
- for (i = 0; i < placement->num_busy_placement; i++) {
- if (!capable(CAP_SYS_ADMIN)) {
- if (placement->busy_placement[i] & TTM_PL_FLAG_NO_EVICT) {
- printk(KERN_ERR TTM_PFX "Need to be root to "
- "modify NO_EVICT status.\n");
- return -EINVAL;
- }
- }
- }
return 0;
}
@@ -1176,11 +1178,14 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (num_pages == 0) {
printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n");
+ if (destroy)
+ (*destroy)(bo);
+ else
+ kfree(bo);
return -EINVAL;
}
bo->destroy = destroy;
- spin_lock_init(&bo->lock);
kref_init(&bo->kref);
kref_init(&bo->list_kref);
atomic_set(&bo->cpu_writers, 0);
@@ -1189,6 +1194,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
INIT_LIST_HEAD(&bo->lru);
INIT_LIST_HEAD(&bo->ddestroy);
INIT_LIST_HEAD(&bo->swap);
+ INIT_LIST_HEAD(&bo->io_reserve_lru);
bo->bdev = bdev;
bo->glob = bdev->glob;
bo->type = type;
@@ -1198,7 +1204,8 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bo->mem.num_pages = bo->num_pages;
bo->mem.mm_node = NULL;
bo->mem.page_alignment = page_alignment;
- bo->mem.bus.io_reserved = false;
+ bo->mem.bus.io_reserved_vm = false;
+ bo->mem.bus.io_reserved_count = 0;
bo->buffer_start = buffer_start & PAGE_MASK;
bo->priv_flags = 0;
bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
@@ -1369,18 +1376,13 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
int ret = -EINVAL;
struct ttm_mem_type_manager *man;
- if (type >= TTM_NUM_MEM_TYPES) {
- printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type);
- return ret;
- }
-
+ BUG_ON(type >= TTM_NUM_MEM_TYPES);
man = &bdev->man[type];
- if (man->has_type) {
- printk(KERN_ERR TTM_PFX
- "Memory manager already initialized for type %d\n",
- type);
- return ret;
- }
+ BUG_ON(man->has_type);
+ man->io_reserve_fastpath = true;
+ man->use_io_reserve_lru = false;
+ mutex_init(&man->io_reserve_mutex);
+ INIT_LIST_HEAD(&man->io_reserve_lru);
ret = bdev->driver->init_mem_type(bdev, type, man);
if (ret)
@@ -1389,13 +1391,6 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
ret = 0;
if (type != TTM_PL_SYSTEM) {
- if (!p_size) {
- printk(KERN_ERR TTM_PFX
- "Zero size memory manager type %d\n",
- type);
- return ret;
- }
-
ret = (*man->func->init)(man, p_size);
if (ret)
return ret;
@@ -1505,8 +1500,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
list_del(&bdev->device_list);
mutex_unlock(&glob->device_list_mutex);
- if (!cancel_delayed_work(&bdev->wq))
- flush_scheduled_work();
+ cancel_delayed_work_sync(&bdev->wq);
while (ttm_bo_delayed_delete(bdev, true))
;
@@ -1560,7 +1554,8 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
bdev->dev_mapping = NULL;
bdev->glob = glob;
bdev->need_dma32 = need_dma32;
-
+ bdev->val_seq = 0;
+ spin_lock_init(&bdev->fence_lock);
mutex_lock(&glob->device_list_mutex);
list_add_tail(&bdev->device_list, &glob->device_list);
mutex_unlock(&glob->device_list_mutex);
@@ -1594,7 +1589,7 @@ bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
return true;
}
-void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
+void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
loff_t offset = (loff_t) bo->addr_space_offset;
@@ -1603,8 +1598,20 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
if (!bdev->dev_mapping)
return;
unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);
- ttm_mem_io_free(bdev, &bo->mem);
+ ttm_mem_io_free_vm(bo);
}
+
+void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
+{
+ struct ttm_bo_device *bdev = bo->bdev;
+ struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
+
+ ttm_mem_io_lock(man, false);
+ ttm_bo_unmap_virtual_locked(bo);
+ ttm_mem_io_unlock(man);
+}
+
+
EXPORT_SYMBOL(ttm_bo_unmap_virtual);
static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
@@ -1684,6 +1691,7 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
bool lazy, bool interruptible, bool no_wait)
{
struct ttm_bo_driver *driver = bo->bdev->driver;
+ struct ttm_bo_device *bdev = bo->bdev;
void *sync_obj;
void *sync_obj_arg;
int ret = 0;
@@ -1697,9 +1705,9 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
void *tmp_obj = bo->sync_obj;
bo->sync_obj = NULL;
clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
driver->sync_obj_unref(&tmp_obj);
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
continue;
}
@@ -1708,29 +1716,29 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
sync_obj = driver->sync_obj_ref(bo->sync_obj);
sync_obj_arg = bo->sync_obj_arg;
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
ret = driver->sync_obj_wait(sync_obj, sync_obj_arg,
lazy, interruptible);
if (unlikely(ret != 0)) {
driver->sync_obj_unref(&sync_obj);
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
return ret;
}
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
if (likely(bo->sync_obj == sync_obj &&
bo->sync_obj_arg == sync_obj_arg)) {
void *tmp_obj = bo->sync_obj;
bo->sync_obj = NULL;
clear_bit(TTM_BO_PRIV_FLAG_MOVING,
&bo->priv_flags);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
driver->sync_obj_unref(&sync_obj);
driver->sync_obj_unref(&tmp_obj);
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
} else {
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
driver->sync_obj_unref(&sync_obj);
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
}
}
return 0;
@@ -1739,6 +1747,7 @@ EXPORT_SYMBOL(ttm_bo_wait);
int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
{
+ struct ttm_bo_device *bdev = bo->bdev;
int ret = 0;
/*
@@ -1748,9 +1757,9 @@ int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
if (unlikely(ret != 0))
return ret;
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
ret = ttm_bo_wait(bo, false, true, no_wait);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (likely(ret == 0))
atomic_inc(&bo->cpu_writers);
ttm_bo_unreserve(bo);
@@ -1816,16 +1825,15 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
- while (put_count--)
- kref_put(&bo->list_kref, ttm_bo_ref_bug);
+ ttm_bo_list_ref_sub(bo, put_count, true);
/**
* Wait for GPU, then move to system cached.
*/
- spin_lock(&bo->lock);
+ spin_lock(&bo->bdev->fence_lock);
ret = ttm_bo_wait(bo, false, false, false);
- spin_unlock(&bo->lock);
+ spin_unlock(&bo->bdev->fence_lock);
if (unlikely(ret != 0))
goto out;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
index 7410c190c891..038e947d00f9 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -31,20 +31,29 @@
#include "ttm/ttm_module.h"
#include "ttm/ttm_bo_driver.h"
#include "ttm/ttm_placement.h"
-#include <linux/jiffies.h>
+#include "drm_mm.h"
#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/file.h>
+#include <linux/spinlock.h>
#include <linux/module.h>
+/**
+ * Currently we use a spinlock for the lock, but a mutex *may* be
+ * more appropriate to reduce scheduling latency if the range manager
+ * ends up with very fragmented allocation patterns.
+ */
+
+struct ttm_range_manager {
+ struct drm_mm mm;
+ spinlock_t lock;
+};
+
static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
struct ttm_buffer_object *bo,
struct ttm_placement *placement,
struct ttm_mem_reg *mem)
{
- struct ttm_bo_global *glob = man->bdev->glob;
- struct drm_mm *mm = man->priv;
+ struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct drm_mm *mm = &rman->mm;
struct drm_mm_node *node = NULL;
unsigned long lpfn;
int ret;
@@ -57,19 +66,19 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
if (unlikely(ret))
return ret;
- spin_lock(&glob->lru_lock);
+ spin_lock(&rman->lock);
node = drm_mm_search_free_in_range(mm,
mem->num_pages, mem->page_alignment,
placement->fpfn, lpfn, 1);
if (unlikely(node == NULL)) {
- spin_unlock(&glob->lru_lock);
+ spin_unlock(&rman->lock);
return 0;
}
node = drm_mm_get_block_atomic_range(node, mem->num_pages,
- mem->page_alignment,
- placement->fpfn,
- lpfn);
- spin_unlock(&glob->lru_lock);
+ mem->page_alignment,
+ placement->fpfn,
+ lpfn);
+ spin_unlock(&rman->lock);
} while (node == NULL);
mem->mm_node = node;
@@ -80,12 +89,12 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
- struct ttm_bo_global *glob = man->bdev->glob;
+ struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
if (mem->mm_node) {
- spin_lock(&glob->lru_lock);
+ spin_lock(&rman->lock);
drm_mm_put_block(mem->mm_node);
- spin_unlock(&glob->lru_lock);
+ spin_unlock(&rman->lock);
mem->mm_node = NULL;
}
}
@@ -93,49 +102,49 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
unsigned long p_size)
{
- struct drm_mm *mm;
+ struct ttm_range_manager *rman;
int ret;
- mm = kzalloc(sizeof(*mm), GFP_KERNEL);
- if (!mm)
+ rman = kzalloc(sizeof(*rman), GFP_KERNEL);
+ if (!rman)
return -ENOMEM;
- ret = drm_mm_init(mm, 0, p_size);
+ ret = drm_mm_init(&rman->mm, 0, p_size);
if (ret) {
- kfree(mm);
+ kfree(rman);
return ret;
}
- man->priv = mm;
+ spin_lock_init(&rman->lock);
+ man->priv = rman;
return 0;
}
static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
{
- struct ttm_bo_global *glob = man->bdev->glob;
- struct drm_mm *mm = man->priv;
- int ret = 0;
+ struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct drm_mm *mm = &rman->mm;
- spin_lock(&glob->lru_lock);
+ spin_lock(&rman->lock);
if (drm_mm_clean(mm)) {
drm_mm_takedown(mm);
- kfree(mm);
+ spin_unlock(&rman->lock);
+ kfree(rman);
man->priv = NULL;
- } else
- ret = -EBUSY;
- spin_unlock(&glob->lru_lock);
- return ret;
+ return 0;
+ }
+ spin_unlock(&rman->lock);
+ return -EBUSY;
}
static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
const char *prefix)
{
- struct ttm_bo_global *glob = man->bdev->glob;
- struct drm_mm *mm = man->priv;
+ struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
- spin_lock(&glob->lru_lock);
- drm_mm_debug_table(mm, prefix);
- spin_unlock(&glob->lru_lock);
+ spin_lock(&rman->lock);
+ drm_mm_debug_table(&rman->mm, prefix);
+ spin_unlock(&rman->lock);
}
const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 3106d5bcce32..77dbf408c0d0 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -75,37 +75,123 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
}
EXPORT_SYMBOL(ttm_bo_move_ttm);
-int ttm_mem_io_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible)
{
- int ret;
+ if (likely(man->io_reserve_fastpath))
+ return 0;
+
+ if (interruptible)
+ return mutex_lock_interruptible(&man->io_reserve_mutex);
+
+ mutex_lock(&man->io_reserve_mutex);
+ return 0;
+}
- if (!mem->bus.io_reserved) {
- mem->bus.io_reserved = true;
+void ttm_mem_io_unlock(struct ttm_mem_type_manager *man)
+{
+ if (likely(man->io_reserve_fastpath))
+ return;
+
+ mutex_unlock(&man->io_reserve_mutex);
+}
+
+static int ttm_mem_io_evict(struct ttm_mem_type_manager *man)
+{
+ struct ttm_buffer_object *bo;
+
+ if (!man->use_io_reserve_lru || list_empty(&man->io_reserve_lru))
+ return -EAGAIN;
+
+ bo = list_first_entry(&man->io_reserve_lru,
+ struct ttm_buffer_object,
+ io_reserve_lru);
+ list_del_init(&bo->io_reserve_lru);
+ ttm_bo_unmap_virtual_locked(bo);
+
+ return 0;
+}
+
+static int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ int ret = 0;
+
+ if (!bdev->driver->io_mem_reserve)
+ return 0;
+ if (likely(man->io_reserve_fastpath))
+ return bdev->driver->io_mem_reserve(bdev, mem);
+
+ if (bdev->driver->io_mem_reserve &&
+ mem->bus.io_reserved_count++ == 0) {
+retry:
ret = bdev->driver->io_mem_reserve(bdev, mem);
+ if (ret == -EAGAIN) {
+ ret = ttm_mem_io_evict(man);
+ if (ret == 0)
+ goto retry;
+ }
+ }
+ return ret;
+}
+
+static void ttm_mem_io_free(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+
+ if (likely(man->io_reserve_fastpath))
+ return;
+
+ if (bdev->driver->io_mem_reserve &&
+ --mem->bus.io_reserved_count == 0 &&
+ bdev->driver->io_mem_free)
+ bdev->driver->io_mem_free(bdev, mem);
+
+}
+
+int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
+{
+ struct ttm_mem_reg *mem = &bo->mem;
+ int ret;
+
+ if (!mem->bus.io_reserved_vm) {
+ struct ttm_mem_type_manager *man =
+ &bo->bdev->man[mem->mem_type];
+
+ ret = ttm_mem_io_reserve(bo->bdev, mem);
if (unlikely(ret != 0))
return ret;
+ mem->bus.io_reserved_vm = true;
+ if (man->use_io_reserve_lru)
+ list_add_tail(&bo->io_reserve_lru,
+ &man->io_reserve_lru);
}
return 0;
}
-void ttm_mem_io_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
{
- if (bdev->driver->io_mem_reserve) {
- if (mem->bus.io_reserved) {
- mem->bus.io_reserved = false;
- bdev->driver->io_mem_free(bdev, mem);
- }
+ struct ttm_mem_reg *mem = &bo->mem;
+
+ if (mem->bus.io_reserved_vm) {
+ mem->bus.io_reserved_vm = false;
+ list_del_init(&bo->io_reserve_lru);
+ ttm_mem_io_free(bo->bdev, mem);
}
}
int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
void **virtual)
{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
int ret;
void *addr;
*virtual = NULL;
+ (void) ttm_mem_io_lock(man, false);
ret = ttm_mem_io_reserve(bdev, mem);
+ ttm_mem_io_unlock(man);
if (ret || !mem->bus.is_iomem)
return ret;
@@ -117,7 +203,9 @@ int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
else
addr = ioremap_nocache(mem->bus.base + mem->bus.offset, mem->bus.size);
if (!addr) {
+ (void) ttm_mem_io_lock(man, false);
ttm_mem_io_free(bdev, mem);
+ ttm_mem_io_unlock(man);
return -ENOMEM;
}
}
@@ -134,7 +222,9 @@ void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
if (virtual && mem->bus.addr == NULL)
iounmap(virtual);
+ (void) ttm_mem_io_lock(man, false);
ttm_mem_io_free(bdev, mem);
+ ttm_mem_io_unlock(man);
}
static int ttm_copy_io_page(void *dst, void *src, unsigned long page)
@@ -231,7 +321,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
struct ttm_tt *ttm = bo->ttm;
struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg old_copy = *old_mem;
+ struct ttm_mem_reg old_copy;
void *old_iomap;
void *new_iomap;
int ret;
@@ -280,8 +370,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
}
mb();
out2:
- ttm_bo_free_old_node(bo);
-
+ old_copy = *old_mem;
*old_mem = *new_mem;
new_mem->mm_node = NULL;
@@ -292,9 +381,10 @@ out2:
}
out1:
- ttm_mem_reg_iounmap(bdev, new_mem, new_iomap);
+ ttm_mem_reg_iounmap(bdev, old_mem, new_iomap);
out:
ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap);
+ ttm_bo_mem_put(bo, &old_copy);
return ret;
}
EXPORT_SYMBOL(ttm_bo_move_memcpy);
@@ -337,11 +427,11 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
* TODO: Explicit member copy would probably be better here.
*/
- spin_lock_init(&fbo->lock);
init_waitqueue_head(&fbo->event_queue);
INIT_LIST_HEAD(&fbo->ddestroy);
INIT_LIST_HEAD(&fbo->lru);
INIT_LIST_HEAD(&fbo->swap);
+ INIT_LIST_HEAD(&fbo->io_reserve_lru);
fbo->vm_node = NULL;
atomic_set(&fbo->cpu_writers, 0);
@@ -453,6 +543,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
unsigned long start_page, unsigned long num_pages,
struct ttm_bo_kmap_obj *map)
{
+ struct ttm_mem_type_manager *man =
+ &bo->bdev->man[bo->mem.mem_type];
unsigned long offset, size;
int ret;
@@ -467,7 +559,9 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC))
return -EPERM;
#endif
+ (void) ttm_mem_io_lock(man, false);
ret = ttm_mem_io_reserve(bo->bdev, &bo->mem);
+ ttm_mem_io_unlock(man);
if (ret)
return ret;
if (!bo->mem.bus.is_iomem) {
@@ -482,12 +576,15 @@ EXPORT_SYMBOL(ttm_bo_kmap);
void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
{
+ struct ttm_buffer_object *bo = map->bo;
+ struct ttm_mem_type_manager *man =
+ &bo->bdev->man[bo->mem.mem_type];
+
if (!map->virtual)
return;
switch (map->bo_kmap_type) {
case ttm_bo_map_iomap:
iounmap(map->virtual);
- ttm_mem_io_free(map->bo->bdev, &map->bo->mem);
break;
case ttm_bo_map_vmap:
vunmap(map->virtual);
@@ -500,6 +597,9 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
default:
BUG();
}
+ (void) ttm_mem_io_lock(man, false);
+ ttm_mem_io_free(map->bo->bdev, &map->bo->mem);
+ ttm_mem_io_unlock(man);
map->virtual = NULL;
map->page = NULL;
}
@@ -520,7 +620,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
struct ttm_buffer_object *ghost_obj;
void *tmp_obj = NULL;
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
if (bo->sync_obj) {
tmp_obj = bo->sync_obj;
bo->sync_obj = NULL;
@@ -529,7 +629,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
bo->sync_obj_arg = sync_obj_arg;
if (evict) {
ret = ttm_bo_wait(bo, false, false, false);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (tmp_obj)
driver->sync_obj_unref(&tmp_obj);
if (ret)
@@ -552,7 +652,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
*/
set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (tmp_obj)
driver->sync_obj_unref(&tmp_obj);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index fe6cb77899f4..221b924acebe 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -83,6 +83,8 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
int i;
unsigned long address = (unsigned long)vmf->virtual_address;
int retval = VM_FAULT_NOPAGE;
+ struct ttm_mem_type_manager *man =
+ &bdev->man[bo->mem.mem_type];
/*
* Work around locking order reversal in fault / nopfn
@@ -118,24 +120,28 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
* move.
*/
- spin_lock(&bo->lock);
+ spin_lock(&bdev->fence_lock);
if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) {
ret = ttm_bo_wait(bo, false, true, false);
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
if (unlikely(ret != 0)) {
retval = (ret != -ERESTARTSYS) ?
VM_FAULT_SIGBUS : VM_FAULT_NOPAGE;
goto out_unlock;
}
} else
- spin_unlock(&bo->lock);
+ spin_unlock(&bdev->fence_lock);
-
- ret = ttm_mem_io_reserve(bdev, &bo->mem);
- if (ret) {
- retval = VM_FAULT_SIGBUS;
+ ret = ttm_mem_io_lock(man, true);
+ if (unlikely(ret != 0)) {
+ retval = VM_FAULT_NOPAGE;
goto out_unlock;
}
+ ret = ttm_mem_io_reserve_vm(bo);
+ if (unlikely(ret != 0)) {
+ retval = VM_FAULT_SIGBUS;
+ goto out_io_unlock;
+ }
page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
bo->vm_node->start - vma->vm_pgoff;
@@ -144,7 +150,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (unlikely(page_offset >= bo->num_pages)) {
retval = VM_FAULT_SIGBUS;
- goto out_unlock;
+ goto out_io_unlock;
}
/*
@@ -182,7 +188,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
page = ttm_tt_get_page(ttm, page_offset);
if (unlikely(!page && i == 0)) {
retval = VM_FAULT_OOM;
- goto out_unlock;
+ goto out_io_unlock;
} else if (unlikely(!page)) {
break;
}
@@ -200,14 +206,15 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
else if (unlikely(ret != 0)) {
retval =
(ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS;
- goto out_unlock;
+ goto out_io_unlock;
}
address += PAGE_SIZE;
if (unlikely(++page_offset >= page_last))
break;
}
-
+out_io_unlock:
+ ttm_mem_io_unlock(man);
out_unlock:
ttm_bo_unreserve(bo);
return retval;
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index c285c2902d15..3832fe10b4df 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -32,7 +32,7 @@
#include <linux/sched.h>
#include <linux/module.h>
-void ttm_eu_backoff_reservation(struct list_head *list)
+static void ttm_eu_backoff_reservation_locked(struct list_head *list)
{
struct ttm_validate_buffer *entry;
@@ -41,10 +41,77 @@ void ttm_eu_backoff_reservation(struct list_head *list)
if (!entry->reserved)
continue;
+ if (entry->removed) {
+ ttm_bo_add_to_lru(bo);
+ entry->removed = false;
+
+ }
entry->reserved = false;
- ttm_bo_unreserve(bo);
+ atomic_set(&bo->reserved, 0);
+ wake_up_all(&bo->event_queue);
+ }
+}
+
+static void ttm_eu_del_from_lru_locked(struct list_head *list)
+{
+ struct ttm_validate_buffer *entry;
+
+ list_for_each_entry(entry, list, head) {
+ struct ttm_buffer_object *bo = entry->bo;
+ if (!entry->reserved)
+ continue;
+
+ if (!entry->removed) {
+ entry->put_count = ttm_bo_del_from_lru(bo);
+ entry->removed = true;
+ }
}
}
+
+static void ttm_eu_list_ref_sub(struct list_head *list)
+{
+ struct ttm_validate_buffer *entry;
+
+ list_for_each_entry(entry, list, head) {
+ struct ttm_buffer_object *bo = entry->bo;
+
+ if (entry->put_count) {
+ ttm_bo_list_ref_sub(bo, entry->put_count, true);
+ entry->put_count = 0;
+ }
+ }
+}
+
+static int ttm_eu_wait_unreserved_locked(struct list_head *list,
+ struct ttm_buffer_object *bo)
+{
+ struct ttm_bo_global *glob = bo->glob;
+ int ret;
+
+ ttm_eu_del_from_lru_locked(list);
+ spin_unlock(&glob->lru_lock);
+ ret = ttm_bo_wait_unreserved(bo, true);
+ spin_lock(&glob->lru_lock);
+ if (unlikely(ret != 0))
+ ttm_eu_backoff_reservation_locked(list);
+ return ret;
+}
+
+
+void ttm_eu_backoff_reservation(struct list_head *list)
+{
+ struct ttm_validate_buffer *entry;
+ struct ttm_bo_global *glob;
+
+ if (list_empty(list))
+ return;
+
+ entry = list_first_entry(list, struct ttm_validate_buffer, head);
+ glob = entry->bo->glob;
+ spin_lock(&glob->lru_lock);
+ ttm_eu_backoff_reservation_locked(list);
+ spin_unlock(&glob->lru_lock);
+}
EXPORT_SYMBOL(ttm_eu_backoff_reservation);
/*
@@ -59,37 +126,76 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation);
* buffers in different orders.
*/
-int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq)
+int ttm_eu_reserve_buffers(struct list_head *list)
{
+ struct ttm_bo_global *glob;
struct ttm_validate_buffer *entry;
int ret;
+ uint32_t val_seq;
+
+ if (list_empty(list))
+ return 0;
+
+ list_for_each_entry(entry, list, head) {
+ entry->reserved = false;
+ entry->put_count = 0;
+ entry->removed = false;
+ }
+
+ entry = list_first_entry(list, struct ttm_validate_buffer, head);
+ glob = entry->bo->glob;
retry:
+ spin_lock(&glob->lru_lock);
+ val_seq = entry->bo->bdev->val_seq++;
+
list_for_each_entry(entry, list, head) {
struct ttm_buffer_object *bo = entry->bo;
- entry->reserved = false;
- ret = ttm_bo_reserve(bo, true, false, true, val_seq);
- if (ret != 0) {
- ttm_eu_backoff_reservation(list);
- if (ret == -EAGAIN) {
- ret = ttm_bo_wait_unreserved(bo, true);
- if (unlikely(ret != 0))
- return ret;
- goto retry;
- } else
+retry_this_bo:
+ ret = ttm_bo_reserve_locked(bo, true, true, true, val_seq);
+ switch (ret) {
+ case 0:
+ break;
+ case -EBUSY:
+ ret = ttm_eu_wait_unreserved_locked(list, bo);
+ if (unlikely(ret != 0)) {
+ spin_unlock(&glob->lru_lock);
+ ttm_eu_list_ref_sub(list);
return ret;
+ }
+ goto retry_this_bo;
+ case -EAGAIN:
+ ttm_eu_backoff_reservation_locked(list);
+ spin_unlock(&glob->lru_lock);
+ ttm_eu_list_ref_sub(list);
+ ret = ttm_bo_wait_unreserved(bo, true);
+ if (unlikely(ret != 0))
+ return ret;
+ goto retry;
+ default:
+ ttm_eu_backoff_reservation_locked(list);
+ spin_unlock(&glob->lru_lock);
+ ttm_eu_list_ref_sub(list);
+ return ret;
}
entry->reserved = true;
if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
- ttm_eu_backoff_reservation(list);
+ ttm_eu_backoff_reservation_locked(list);
+ spin_unlock(&glob->lru_lock);
+ ttm_eu_list_ref_sub(list);
ret = ttm_bo_wait_cpu(bo, false);
if (ret)
return ret;
goto retry;
}
}
+
+ ttm_eu_del_from_lru_locked(list);
+ spin_unlock(&glob->lru_lock);
+ ttm_eu_list_ref_sub(list);
+
return 0;
}
EXPORT_SYMBOL(ttm_eu_reserve_buffers);
@@ -97,21 +203,36 @@ EXPORT_SYMBOL(ttm_eu_reserve_buffers);
void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj)
{
struct ttm_validate_buffer *entry;
+ struct ttm_buffer_object *bo;
+ struct ttm_bo_global *glob;
+ struct ttm_bo_device *bdev;
+ struct ttm_bo_driver *driver;
- list_for_each_entry(entry, list, head) {
- struct ttm_buffer_object *bo = entry->bo;
- struct ttm_bo_driver *driver = bo->bdev->driver;
- void *old_sync_obj;
+ if (list_empty(list))
+ return;
+
+ bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo;
+ bdev = bo->bdev;
+ driver = bdev->driver;
+ glob = bo->glob;
- spin_lock(&bo->lock);
- old_sync_obj = bo->sync_obj;
+ spin_lock(&bdev->fence_lock);
+ spin_lock(&glob->lru_lock);
+
+ list_for_each_entry(entry, list, head) {
+ bo = entry->bo;
+ entry->old_sync_obj = bo->sync_obj;
bo->sync_obj = driver->sync_obj_ref(sync_obj);
bo->sync_obj_arg = entry->new_sync_obj_arg;
- spin_unlock(&bo->lock);
- ttm_bo_unreserve(bo);
+ ttm_bo_unreserve_locked(bo);
entry->reserved = false;
- if (old_sync_obj)
- driver->sync_obj_unref(&old_sync_obj);
+ }
+ spin_unlock(&glob->lru_lock);
+ spin_unlock(&bdev->fence_lock);
+
+ list_for_each_entry(entry, list, head) {
+ if (entry->old_sync_obj)
+ driver->sync_obj_unref(&entry->old_sync_obj);
}
}
EXPORT_SYMBOL(ttm_eu_fence_buffer_objects);
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index a7bab87a548b..af789dc869b9 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -440,10 +440,8 @@ int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
return ret;
ret = be->func->bind(be, bo_mem);
- if (ret) {
- printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n");
+ if (unlikely(ret != 0))
return ret;
- }
ttm->state = tt_bound;
diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
index 9b5b4d9dd62c..3e038a394c51 100644
--- a/drivers/gpu/drm/via/via_dmablit.c
+++ b/drivers/gpu/drm/via/via_dmablit.c
@@ -235,9 +235,9 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) -
first_pfn + 1;
- if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
+ vsg->pages = vzalloc(sizeof(struct page *) * vsg->num_pages);
+ if (NULL == vsg->pages)
return -ENOMEM;
- memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
down_read(&current->mm->mmap_sem);
ret = get_user_pages(current, current->mm,
(unsigned long)xfer->mem_addr,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index e7a58d055041..10fc01f69c40 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -264,7 +264,6 @@ struct vmw_private {
*/
struct vmw_sw_context ctx;
- uint32_t val_seq;
struct mutex cmdbuf_mutex;
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 51d9f9f1d7f2..41b95ed6dbcd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -653,8 +653,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size);
if (unlikely(ret != 0))
goto out_err;
- ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes,
- dev_priv->val_seq++);
+ ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes);
if (unlikely(ret != 0))
goto out_err;
@@ -691,6 +690,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
fence_rep.error = ret;
fence_rep.fence_seq = (uint64_t) sequence;
+ fence_rep.pad64 = 0;
user_fence_rep = (struct drm_vmw_fence_rep __user *)
(unsigned long)arg->fence_rep;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 41d9a5b73c03..bfab60c938ac 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -480,9 +480,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
info->fix.smem_start = 0;
info->fix.smem_len = fb_size;
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
-
info->pseudo_palette = par->pseudo_palette;
info->screen_base = par->vmalloc;
info->screen_size = fb_size;
@@ -659,7 +656,7 @@ int vmw_fb_off(struct vmw_private *vmw_priv)
par->dirty.active = false;
spin_unlock_irqrestore(&par->dirty.lock, flags);
- flush_scheduled_work();
+ flush_delayed_work_sync(&info->deferred_work);
par->bo_ptr = NULL;
ttm_bo_kunmap(&par->map);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 87c6e6156d7d..cceeb42789b6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -720,6 +720,8 @@ static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb)
&vmw_vram_ne_placement,
false, &vmw_dmabuf_bo_free);
vmw_overlay_resume_all(dev_priv);
+ if (unlikely(ret != 0))
+ vfbs->buffer = NULL;
return ret;
}
@@ -730,6 +732,9 @@ static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb)
struct vmw_framebuffer_surface *vfbs =
vmw_framebuffer_to_vfbs(&vfb->base);
+ if (unlikely(vfbs->buffer == NULL))
+ return 0;
+
bo = &vfbs->buffer->base;
ttm_bo_unref(&bo);
vfbs->buffer = NULL;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index a01c47ddb5bc..29113c9b26a8 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -557,7 +557,7 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
return -EINVAL;
}
- dev_priv->ldu_priv = kmalloc(GFP_KERNEL, sizeof(*dev_priv->ldu_priv));
+ dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL);
if (!dev_priv->ldu_priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
index df2036ed18d5..f1a52f9e7298 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
@@ -585,7 +585,7 @@ int vmw_overlay_init(struct vmw_private *dev_priv)
return -ENOSYS;
}
- overlay = kmalloc(GFP_KERNEL, sizeof(*overlay));
+ overlay = kmalloc(sizeof(*overlay), GFP_KERNEL);
if (!overlay)
return -ENOMEM;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 36e129f0023f..5408b1b7996f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -862,7 +862,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
&vmw_vram_sys_placement, true,
&vmw_user_dmabuf_destroy);
if (unlikely(ret != 0))
- return ret;
+ goto out_no_dmabuf;
tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
@@ -870,19 +870,21 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
false,
ttm_buffer_type,
&vmw_user_dmabuf_release, NULL);
- if (unlikely(ret != 0)) {
- ttm_bo_unref(&tmp);
- } else {
+ if (unlikely(ret != 0))
+ goto out_no_base_object;
+ else {
rep->handle = vmw_user_bo->base.hash.key;
rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
rep->cur_gmr_id = vmw_user_bo->base.hash.key;
rep->cur_gmr_offset = 0;
}
- ttm_bo_unref(&tmp);
+out_no_base_object:
+ ttm_bo_unref(&tmp);
+out_no_dmabuf:
ttm_read_unlock(&vmaster->lock);
- return 0;
+ return ret;
}
int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig
index 742c423567cf..09aea5f1556d 100644
--- a/drivers/gpu/stub/Kconfig
+++ b/drivers/gpu/stub/Kconfig
@@ -3,6 +3,8 @@ config STUB_POULSBO
depends on PCI
# Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
+ select BACKLIGHT_CLASS_DEVICE if ACPI
+ select INPUT if ACPI
select ACPI_VIDEO if ACPI
help
Choose this option if you have a system that has Intel GMA500
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index c8768f38511e..e01cacba685f 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -33,6 +33,7 @@ struct vga_switcheroo_client {
struct fb_info *fb_info;
int pwr_state;
void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state);
+ void (*reprobe)(struct pci_dev *pdev);
bool (*can_switch)(struct pci_dev *pdev);
int id;
bool active;
@@ -103,6 +104,7 @@ static void vga_switcheroo_enable(void)
int vga_switcheroo_register_client(struct pci_dev *pdev,
void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state),
+ void (*reprobe)(struct pci_dev *pdev),
bool (*can_switch)(struct pci_dev *pdev))
{
int index;
@@ -117,6 +119,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON;
vgasr_priv.clients[index].pdev = pdev;
vgasr_priv.clients[index].set_gpu_state = set_gpu_state;
+ vgasr_priv.clients[index].reprobe = reprobe;
vgasr_priv.clients[index].can_switch = can_switch;
vgasr_priv.clients[index].id = -1;
if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
@@ -174,7 +177,8 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
int i;
mutex_lock(&vgasr_mutex);
for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- seq_printf(m, "%d:%c:%s:%s\n", i,
+ seq_printf(m, "%d:%s:%c:%s:%s\n", i,
+ vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
vgasr_priv.clients[i].active ? '+' : ' ',
vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off",
pci_name(vgasr_priv.clients[i].pdev));
@@ -190,9 +194,8 @@ static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file)
static int vga_switchon(struct vga_switcheroo_client *client)
{
- int ret;
-
- ret = vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
+ if (vgasr_priv.handler->power_state)
+ vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
/* call the driver callback to turn on device */
client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
client->pwr_state = VGA_SWITCHEROO_ON;
@@ -203,12 +206,14 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
{
/* call the driver callback to turn off device */
client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
- vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
+ if (vgasr_priv.handler->power_state)
+ vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
client->pwr_state = VGA_SWITCHEROO_OFF;
return 0;
}
-static int vga_switchto(struct vga_switcheroo_client *new_client)
+/* stage one happens before delay */
+static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
{
int ret;
int i;
@@ -235,10 +240,28 @@ static int vga_switchto(struct vga_switcheroo_client *new_client)
vga_switchon(new_client);
/* swap shadow resource to denote boot VGA device has changed so X starts on new device */
- active->active = false;
-
active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ return 0;
+}
+
+/* post delay */
+static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
+{
+ int ret;
+ int i;
+ struct vga_switcheroo_client *active = NULL;
+
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].active == true) {
+ active = &vgasr_priv.clients[i];
+ break;
+ }
+ }
+ if (!active)
+ return 0;
+
+ active->active = false;
if (new_client->fb_info) {
struct fb_event event;
@@ -250,6 +273,9 @@ static int vga_switchto(struct vga_switcheroo_client *new_client)
if (ret)
return ret;
+ if (new_client->reprobe)
+ new_client->reprobe(new_client->pdev);
+
if (active->pwr_state == VGA_SWITCHEROO_ON)
vga_switchoff(active);
@@ -265,6 +291,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
const char *pdev_name;
int i, ret;
bool delay = false, can_switch;
+ bool just_mux = false;
int client_id = -1;
struct vga_switcheroo_client *client = NULL;
@@ -319,6 +346,15 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
if (strncmp(usercmd, "DIS", 3) == 0)
client_id = VGA_SWITCHEROO_DIS;
+ if (strncmp(usercmd, "MIGD", 4) == 0) {
+ just_mux = true;
+ client_id = VGA_SWITCHEROO_IGD;
+ }
+ if (strncmp(usercmd, "MDIS", 4) == 0) {
+ just_mux = true;
+ client_id = VGA_SWITCHEROO_DIS;
+ }
+
if (client_id == -1)
goto out;
@@ -330,6 +366,12 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
}
vgasr_priv.delayed_switch_active = false;
+
+ if (just_mux) {
+ ret = vgasr_priv.handler->switchto(client_id);
+ goto out;
+ }
+
/* okay we want a switch - test if devices are willing to switch */
can_switch = true;
for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
@@ -345,18 +387,22 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
if (can_switch == true) {
pdev_name = pci_name(client->pdev);
- ret = vga_switchto(client);
+ ret = vga_switchto_stage1(client);
if (ret)
- printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret);
+ printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret);
+
+ ret = vga_switchto_stage2(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret);
+
} else {
printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
vgasr_priv.delayed_switch_active = true;
vgasr_priv.delayed_client_id = client_id;
- /* we should at least power up the card to
- make the switch faster */
- if (client->pwr_state == VGA_SWITCHEROO_OFF)
- vga_switchon(client);
+ ret = vga_switchto_stage1(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret);
}
out:
@@ -438,9 +484,9 @@ int vga_switcheroo_process_delayed_switch(void)
goto err;
pdev_name = pci_name(client->pdev);
- ret = vga_switchto(client);
+ ret = vga_switchto_stage2(client);
if (ret)
- printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret);
+ printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret);
vgasr_priv.delayed_switch_active = false;
err = 0;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3052e2969ad0..24cca2f69dfc 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -150,11 +150,22 @@ config DRAGONRISE_FF
Say Y here if you want to enable force feedback support for DragonRise Inc.
game controllers.
+config HID_EMS_FF
+ tristate "EMS Production Inc. force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback support for devices by
+ EMS Production Ltd.
+ Currently the following devices are known to be supported:
+ - Trio Linker Plus II
+
config HID_EGALAX
tristate "eGalax multi-touch panel"
depends on USB_HID
---help---
- Support for the eGalax dual-touch panel.
+ Support for the eGalax dual-touch panels, including the
+ Joojoo and Wetab tablets.
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
@@ -284,6 +295,23 @@ config HID_MONTEREY
---help---
Support for Monterey Genius KB29E.
+config HID_MULTITOUCH
+ tristate "HID Multitouch panels"
+ depends on USB_HID
+ ---help---
+ Generic support for HID multitouch panels.
+
+ Say Y here if you have one of the following devices:
+ - Cypress TrueTouch panels
+ - Hanvon dual touch panels
+ - Pixcir dual touch panels
+ - 'Sensing Win7-TwoFinger' panel by GeneralTouch
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-multitouch.
+
config HID_NTRIG
tristate "N-Trig touch screen"
depends on USB_HID
@@ -396,6 +424,13 @@ config HID_ROCCAT_KONE
---help---
Support for Roccat Kone mouse.
+config HID_ROCCAT_KONEPLUS
+ tristate "Roccat Kone[+] mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ ---help---
+ Support for Roccat Kone[+] mouse.
+
config HID_ROCCAT_PYRA
tristate "Roccat Pyra mouse support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index c335605b9200..6efc2a0370ad 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the HID driver
#
-hid-objs := hid-core.o hid-input.o
+hid-y := hid-core.o hid-input.o
ifdef CONFIG_DEBUG_FS
hid-objs += hid-debug.o
@@ -11,18 +11,18 @@ obj-$(CONFIG_HID) += hid.o
hid-$(CONFIG_HIDRAW) += hidraw.o
-hid-logitech-objs := hid-lg.o
+hid-logitech-y := hid-lg.o
ifdef CONFIG_LOGITECH_FF
- hid-logitech-objs += hid-lgff.o
+ hid-logitech-y += hid-lgff.o
endif
ifdef CONFIG_LOGIRUMBLEPAD2_FF
- hid-logitech-objs += hid-lg2ff.o
+ hid-logitech-y += hid-lg2ff.o
endif
ifdef CONFIG_LOGIG940_FF
- hid-logitech-objs += hid-lg3ff.o
+ hid-logitech-y += hid-lg3ff.o
endif
ifdef CONFIG_LOGIWII_FF
- hid-logitech-objs += hid-lg4ff.o
+ hid-logitech-y += hid-lg4ff.o
endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
@@ -35,6 +35,7 @@ obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o
+obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_EGALAX) += hid-egalax.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MOSART) += hid-mosart.o
+obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
@@ -55,6 +57,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
+obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index 02d8cd3b1b1b..5243ae2d3730 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/input/mt.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("3M PCT multitouch panels");
@@ -27,8 +28,6 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
-#define MAX_TRKID USHRT_MAX
-#define MAX_EVENTS 360
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");
struct mmm_finger {
__s32 x, y, w, h;
- __u16 id;
- bool prev_touch;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
- __u16 id;
__u8 curid;
__u8 nexp, nreal;
bool touch, valid;
@@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
- field->logical_maximum = MAX_TRKID;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
- 0, MAX_TRKID, 0, 0);
- if (!hi->input->mt)
- input_mt_create_slots(hi->input, MAX_SLOTS);
- input_set_events_per_packet(hi->input, MAX_EVENTS);
+ input_mt_init_slots(hi->input, MAX_SLOTS);
return 1;
}
/* let hid-input decide for the others */
@@ -154,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
- struct mmm_finger *oldest = 0;
int i;
for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i];
@@ -163,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
continue;
}
input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
@@ -170,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
int major = max(f->w, f->h) >> 1;
int minor = min(f->w, f->h) >> 1;
- if (!f->prev_touch)
- f->id = md->id++;
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
- /* touchscreen emulation: pick the oldest contact */
- if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
- oldest = f;
- } else {
- /* this finger took off the screen */
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
- f->prev_touch = f->touch;
f->valid = 0;
}
- /* touchscreen emulation */
- if (oldest) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- input_event(input, EV_ABS, ABS_X, oldest->x);
- input_event(input, EV_ABS, ABS_Y, oldest->y);
- } else {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- }
+ input_mt_report_pointer_emulation(input, true);
input_sync(input);
}
@@ -274,7 +246,7 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
if (!md) {
- dev_err(&hdev->dev, "cannot allocate 3M data\n");
+ hid_err(hdev, "cannot allocate 3M data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, md);
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 1666c1684e79..902d1dfeb1b5 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -93,7 +93,7 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
if (a4 == NULL) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
ret = -ENOMEM;
goto err_free;
}
@@ -104,13 +104,13 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index eaeca564a8d3..61aa71233392 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -16,6 +16,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -59,6 +61,27 @@ struct apple_key_translation {
u8 flags;
};
+static const struct apple_key_translation macbookair_fn_keys[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_ENTER, KEY_INSERT },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
+ { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_NEXTSONG, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F11, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_F12, KEY_EJECTCD, APPLE_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
+ { }
+};
+
static const struct apple_key_translation apple_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
@@ -146,7 +169,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
struct hid_usage *usage, __s32 value)
{
struct apple_sc *asc = hid_get_drvdata(hid);
- const struct apple_key_translation *trans;
+ const struct apple_key_translation *trans, *table;
if (usage->code == KEY_FN) {
asc->fn_on = !!value;
@@ -157,10 +180,16 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
if (fnmode) {
int do_translate;
- trans = apple_find_translation((hid->product < 0x21d ||
- hid->product >= 0x300) ?
- powerbook_fn_keys : apple_fn_keys,
- usage->code);
+ if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+ hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
+ table = macbookair_fn_keys;
+ else if (hid->product < 0x21d || hid->product >= 0x300)
+ table = powerbook_fn_keys;
+ else
+ table = apple_fn_keys;
+
+ trans = apple_find_translation (table, usage->code);
+
if (trans) {
if (test_bit(usage->code, asc->pressed_fn))
do_translate = 1;
@@ -253,8 +282,8 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
rdesc[53] == 0x65 && rdesc[59] == 0x65) {
- dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up MacBook JIS keyboard report descriptor\n");
rdesc[53] = rdesc[59] = 0xe7;
}
return rdesc;
@@ -324,7 +353,7 @@ static int apple_probe(struct hid_device *hdev,
asc = kzalloc(sizeof(*asc), GFP_KERNEL);
if (asc == NULL) {
- dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+ hid_err(hdev, "can't alloc apple descriptor\n");
return -ENOMEM;
}
@@ -334,7 +363,7 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -345,7 +374,7 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -440,6 +469,18 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@@ -473,7 +514,7 @@ static int __init apple_init(void)
ret = hid_register_driver(&apple_driver);
if (ret)
- printk(KERN_ERR "can't register apple driver\n");
+ pr_err("can't register apple driver\n");
return ret;
}
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index f42ee140738a..e5b961d6ff22 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -73,14 +73,14 @@ static int axff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report = list_first_entry(report_list, struct hid_report, list);
if (report->maxfield < 4) {
- dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
+ hid_err(hid, "no fields in the report: %d\n", report->maxfield);
return -ENODEV;
}
@@ -101,7 +101,7 @@ static int axff_init(struct hid_device *hid)
axff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
+ hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
return 0;
@@ -114,17 +114,17 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int error;
- dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
+ dev_dbg(&hdev->dev, "ACRUX HID hardware probe...\n");
error = hid_parse(hdev);
if (error) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
return error;
}
error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (error) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
return error;
}
@@ -134,7 +134,7 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
* Do not fail device initialization completely as device
* may still be partially operable, just warn.
*/
- dev_warn(&hdev->dev,
+ hid_warn(hdev,
"Failed to enable force feedback support, error: %d\n",
error);
}
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index 4ce7aa3a519f..a1a765a5b08a 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -56,14 +56,14 @@ static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
index 5925bdcd417d..1ea066c55201 100644
--- a/drivers/hid/hid-cando.c
+++ b/drivers/hid/hid-cando.c
@@ -207,7 +207,7 @@ static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate Cando Touch data\n");
+ hid_err(hdev, "cannot allocate Cando Touch data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, td);
@@ -236,6 +236,8 @@ static const struct hid_device_id cando_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index e880086c2311..888ece68a47c 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -30,8 +30,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
- dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
- "descriptor\n");
+ hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
rdesc[11] = rdesc[16] = 0xff;
rdesc[12] = rdesc[17] = 0x03;
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 515345b11ac9..d678cf3d33d5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -14,6 +14,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -59,7 +61,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
if (report_enum->report_id_hash[id])
return report_enum->report_id_hash[id];
- if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+ report = kzalloc(sizeof(struct hid_report), GFP_KERNEL);
+ if (!report)
return NULL;
if (id != 0)
@@ -90,8 +93,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
return NULL;
}
- if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
- + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+ field = kzalloc((sizeof(struct hid_field) +
+ usages * sizeof(struct hid_usage) +
+ values * sizeof(unsigned)), GFP_KERNEL);
+ if (!field)
+ return NULL;
field->index = report->maxfield++;
report->field[field->index] = field;
@@ -172,10 +178,14 @@ static int close_collection(struct hid_parser *parser)
static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
{
+ struct hid_collection *collection = parser->device->collection;
int n;
- for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
- if (parser->device->collection[parser->collection_stack[n]].type == type)
- return parser->device->collection[parser->collection_stack[n]].usage;
+
+ for (n = parser->collection_stack_ptr - 1; n >= 0; n--) {
+ unsigned index = parser->collection_stack[n];
+ if (collection[index].type == type)
+ return collection[index].usage;
+ }
return 0; /* we know nothing about this usage type */
}
@@ -209,7 +219,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
unsigned offset;
int i;
- if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+ report = hid_register_report(parser->device, report_type, parser->global.report_id);
+ if (!report) {
dbg_hid("hid_register_report failed\n");
return -1;
}
@@ -227,7 +238,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
usages = max_t(int, parser->local.usage_index, parser->global.report_count);
- if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+ field = hid_register_field(report, usages, parser->global.report_count);
+ if (!field)
return 0;
field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
@@ -652,13 +664,12 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
return -ENOMEM;
device->rsize = size;
- parser = vmalloc(sizeof(struct hid_parser));
+ parser = vzalloc(sizeof(struct hid_parser));
if (!parser) {
ret = -ENOMEM;
goto err;
}
- memset(parser, 0, sizeof(struct hid_parser));
parser->device = device;
end = start + size;
@@ -672,7 +683,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
if (dispatch_type[item.type](parser, &item)) {
dbg_hid("item %u %u %u %u parsing failed\n",
- item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+ item.format, (unsigned)item.size,
+ (unsigned)item.type, (unsigned)item.tag);
goto err;
}
@@ -737,13 +749,14 @@ static u32 s32ton(__s32 value, unsigned n)
* Search linux-kernel and linux-usb-devel archives for "hid-core extract".
*/
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+static __u32 extract(const struct hid_device *hid, __u8 *report,
+ unsigned offset, unsigned n)
{
u64 x;
if (n > 32)
- printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
- n, current->comm);
+ hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n",
+ n, current->comm);
report += offset >> 3; /* adjust byte index */
offset &= 7; /* now only need bit offset into one byte */
@@ -760,18 +773,19 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
* endianness of register values by considering a register
* a "cached" copy of the little endiad bit stream.
*/
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+static void implement(const struct hid_device *hid, __u8 *report,
+ unsigned offset, unsigned n, __u32 value)
{
u64 x;
u64 m = (1ULL << n) - 1;
if (n > 32)
- printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
- n, current->comm);
+ hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n",
+ __func__, n, current->comm);
if (value > m)
- printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
- value, current->comm);
+ hid_warn(hid, "%s() called with too large value %d! (%s)\n",
+ __func__, value, current->comm);
WARN_ON(value > m);
value &= m;
@@ -788,7 +802,7 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
* Search an array for a value.
*/
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+static int search(__s32 *array, __s32 value, unsigned n)
{
while (n--) {
if (*array++ == value)
@@ -887,18 +901,22 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
__s32 max = field->logical_maximum;
__s32 *value;
- if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+ value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC);
+ if (!value)
return;
for (n = 0; n < count; n++) {
- value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
- extract(data, offset + n * size, size);
+ value[n] = min < 0 ?
+ snto32(extract(hid, data, offset + n * size, size),
+ size) :
+ extract(hid, data, offset + n * size, size);
- if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
- && value[n] >= min && value[n] <= max
- && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
- goto exit;
+ /* Ignore report if ErrorRollOver */
+ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
+ value[n] >= min && value[n] <= max &&
+ field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+ goto exit;
}
for (n = 0; n < count; n++) {
@@ -928,7 +946,8 @@ exit:
* Output the field into the report.
*/
-static void hid_output_field(struct hid_field *field, __u8 *data)
+static void hid_output_field(const struct hid_device *hid,
+ struct hid_field *field, __u8 *data)
{
unsigned count = field->report_count;
unsigned offset = field->report_offset;
@@ -937,9 +956,11 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */
- implement(data, offset + n * size, size, s32ton(field->value[n], size));
+ implement(hid, data, offset + n * size, size,
+ s32ton(field->value[n], size));
else /* unsigned values */
- implement(data, offset + n * size, size, field->value[n]);
+ implement(hid, data, offset + n * size, size,
+ field->value[n]);
}
}
@@ -956,7 +977,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
memset(data, 0, ((report->size - 1) >> 3) + 1);
for (n = 0; n < report->maxfield; n++)
- hid_output_field(report->field[n], data);
+ hid_output_field(report->device, report->field[n], data);
}
EXPORT_SYMBOL_GPL(hid_output_report);
@@ -1169,8 +1190,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
hdev->claimed |= HID_CLAIMED_HIDRAW;
if (!hdev->claimed) {
- dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
- "hidraw\n");
+ hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n");
return -ENODEV;
}
@@ -1210,9 +1230,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
bus = "<UNKNOWN>";
}
- dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
- buf, bus, hdev->version >> 8, hdev->version & 0xff,
- type, hdev->name, hdev->phys);
+ hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+ buf, bus, hdev->version >> 8, hdev->version & 0xff,
+ type, hdev->name, hdev->phys);
return 0;
}
@@ -1230,7 +1250,7 @@ void hid_disconnect(struct hid_device *hdev)
EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
-static const struct hid_device_id hid_blacklist[] = {
+static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
@@ -1276,6 +1296,12 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1286,29 +1312,39 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
@@ -1369,6 +1405,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
@@ -1386,9 +1423,11 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
@@ -1495,9 +1534,9 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
if (!hid_match_device(hdev, hdrv))
return 0;
- /* generic wants all non-blacklisted */
+ /* generic wants all that don't have specialized driver */
if (!strncmp(hdrv->name, "generic-", 8))
- return !hid_match_id(hdev, hid_blacklist);
+ return !hid_match_id(hdev, hid_have_special_driver);
return 1;
}
@@ -1603,10 +1642,10 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
@@ -1756,6 +1795,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
@@ -1947,12 +1992,12 @@ static int __init hid_init(void)
int ret;
if (hid_debug)
- printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
- "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
+ pr_warn("hid_debug is now used solely for parser and driver debugging.\n"
+ "debugfs is now used for inspecting the device (report descriptor, reports)\n");
ret = bus_register(&hid_bus_type);
if (ret) {
- printk(KERN_ERR "HID: can't register hid bus\n");
+ pr_err("can't register hid bus\n");
goto err;
}
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 4cd0e2345991..2f0be4c66af7 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -107,13 +107,13 @@ static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 75c5e23d09d2..555382fc7417 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
@@ -393,7 +395,7 @@ char *hid_resolv_usage(unsigned usage, struct seq_file *f) {
buf = resolv_usage_page(usage >> 16, f);
if (IS_ERR(buf)) {
- printk(KERN_ERR "error allocating HID debug buffer\n");
+ pr_err("error allocating HID debug buffer\n");
return NULL;
}
diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-drff.c
index 968b04f9b796..afcf3d67eb02 100644
--- a/drivers/hid/hid-drff.c
+++ b/drivers/hid/hid-drff.c
@@ -96,18 +96,18 @@ static int drff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report = list_first_entry(report_list, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -133,8 +133,8 @@ static int drff_init(struct hid_device *hid)
drff->report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force Feedback for DragonRise Inc. game "
- "controllers by Richard Walmsley <richwalm@gmail.com>\n");
+ hid_info(hid, "Force Feedback for DragonRise Inc. "
+ "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
return 0;
}
@@ -153,13 +153,13 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
index 54b017ad258d..03bee1970d70 100644
--- a/drivers/hid/hid-egalax.c
+++ b/drivers/hid/hid-egalax.c
@@ -2,6 +2,8 @@
* HID driver for eGalax dual-touch panels
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
*
*/
@@ -16,6 +18,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/input/mt.h>
#include <linux/slab.h>
#include "usbhid/usbhid.h"
@@ -25,38 +28,53 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#define MAX_SLOTS 2
+
+/* estimated signal-to-noise ratios */
+#define SN_MOVE 4096
+#define SN_PRESSURE 32
+
struct egalax_data {
- __u16 x, y, z;
- __u8 id;
- bool first; /* is this the first finger in the frame? */
- bool valid; /* valid finger data, or just placeholder? */
- bool activity; /* at least one active finger previously? */
- __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
+ int valid;
+ int slot;
+ int touch;
+ int x, y, z;
};
+static void set_abs(struct input_dev *input, unsigned int code,
+ struct hid_field *field, int snratio)
+{
+ int fmin = field->logical_minimum;
+ int fmax = field->logical_maximum;
+ int fuzz = snratio ? (fmax - fmin) / snratio : 0;
+ input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+}
+
static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ struct input_dev *input = hi->input;
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
+ field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
+ set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
/* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ set_abs(input, ABS_X, field, SN_MOVE);
return 1;
case HID_GD_Y:
+ field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
+ set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
/* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ set_abs(input, ABS_Y, field, SN_MOVE);
return 1;
}
return 0;
@@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_INRANGE:
case HID_DG_CONFIDENCE:
@@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_CONTACTID:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
+ input_mt_init_slots(input, MAX_SLOTS);
return 1;
case HID_DG_TIPPRESSURE:
+ field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
+ set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
/* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_PRESSURE,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
return 1;
}
return 0;
@@ -96,10 +114,10 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ /* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
+ set_bit(usage->type, hi->input->evbit);
+ return -1;
}
/*
@@ -108,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/
static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
{
- td->first = !td->first; /* touchscreen emulation */
-
- if (td->valid) {
- /* emit multitouch events */
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
+ input_mt_slot(input, td->slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
+ if (td->touch) {
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
-
- input_mt_sync(input);
-
- /*
- * touchscreen emulation: store (x, y) as
- * the last valid values in this frame
- */
- td->lastx = td->x;
- td->lasty = td->y;
- td->lastz = td->z;
- }
-
- /*
- * touchscreen emulation: if this is the second finger and at least
- * one in this frame is valid, the latest valid in the frame is
- * the oldest on the panel, the one we want for single touch
- */
- if (!td->first && td->activity) {
- input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
- input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
- input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
- }
-
- if (!td->valid) {
- /*
- * touchscreen emulation: if the first finger is invalid
- * and there previously was finger activity, this is a release
- */
- if (td->first && td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- td->activity = false;
- }
- return;
- }
-
-
- /* touchscreen emulation: if no previous activity, emit touch event */
- if (!td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- td->activity = true;
}
+ input_mt_report_pointer_emulation(input, true);
}
-
static int egalax_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
@@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
* uses a standard parallel multitouch protocol (product ID ==
* 48xx). The second is capacitive and uses an unusual "serial"
* protocol with a different message for each multitouch finger
- * (product ID == 72xx). We do not yet generate a correct event
- * sequence for the capacitive/serial protocol.
+ * (product ID == 72xx).
*/
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
+ td->valid = value;
+ break;
case HID_DG_CONFIDENCE:
/* avoid interference from generic hidinput handling */
break;
case HID_DG_TIPSWITCH:
- td->valid = value;
+ td->touch = value;
break;
case HID_DG_TIPPRESSURE:
td->z = value;
break;
case HID_DG_CONTACTID:
- td->id = value;
+ td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
break;
case HID_GD_X:
td->x = value;
@@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
case HID_GD_Y:
td->y = value;
/* this is the last field in a finger */
- egalax_filter_event(td, input);
+ if (td->valid)
+ egalax_filter_event(td, input);
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
- td->first = false;
break;
default:
@@ -221,9 +198,9 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct egalax_data *td;
struct hid_report *report;
- td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL);
+ td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate eGalax data\n");
+ hid_err(hdev, "cannot allocate eGalax data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, td);
@@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = {
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ }
};
MODULE_DEVICE_TABLE(hid, egalax_devices);
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
index 6e31f305397d..79d0c61e7214 100644
--- a/drivers/hid/hid-elecom.c
+++ b/drivers/hid/hid-elecom.c
@@ -24,8 +24,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
- dev_info(&hdev->dev, "Fixing up Elecom BM084 "
- "report descriptor.\n");
+ hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
rdesc[47] = 0x00;
}
return rdesc;
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
new file mode 100644
index 000000000000..81877c67caea
--- /dev/null
+++ b/drivers/hid/hid-emsff.c
@@ -0,0 +1,161 @@
+/*
+ * Force feedback support for EMS Trio Linker Plus II
+ *
+ * Copyright (c) 2010 Ignaz Forster <ignaz.forster@gmx.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/hid.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct emsff_device {
+ struct hid_report *report;
+};
+
+static int emsff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct emsff_device *emsff = data;
+ int weak, strong;
+
+ weak = effect->u.rumble.weak_magnitude;
+ strong = effect->u.rumble.strong_magnitude;
+
+ dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
+
+ weak = weak * 0xff / 0xffff;
+ strong = strong * 0xff / 0xffff;
+
+ emsff->report->field[0]->value[1] = weak;
+ emsff->report->field[0]->value[2] = strong;
+
+ dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
+ usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+static int emsff_init(struct hid_device *hid)
+{
+ struct emsff_device *emsff;
+ struct hid_report *report;
+ struct hid_input *hidinput = list_first_entry(&hid->inputs,
+ struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+ if (list_empty(report_list)) {
+ hid_err(hid, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+ if (report->maxfield < 1) {
+ hid_err(hid, "no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 7) {
+ hid_err(hid, "not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL);
+ if (!emsff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, emsff, emsff_play);
+ if (error) {
+ kfree(emsff);
+ return error;
+ }
+
+ emsff->report = report;
+ emsff->report->field[0]->value[0] = 0x01;
+ emsff->report->field[0]->value[1] = 0x00;
+ emsff->report->field[0]->value[2] = 0x00;
+ emsff->report->field[0]->value[3] = 0x00;
+ emsff->report->field[0]->value[4] = 0x00;
+ emsff->report->field[0]->value[5] = 0x00;
+ emsff->report->field[0]->value[6] = 0x00;
+ usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+ hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
+
+ return 0;
+}
+
+static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ emsff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id ems_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_EMS, 0x118) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ems_devices);
+
+static struct hid_driver ems_driver = {
+ .name = "hkems",
+ .id_table = ems_devices,
+ .probe = ems_probe,
+};
+
+static int ems_init(void)
+{
+ return hid_register_driver(&ems_driver);
+}
+
+static void ems_exit(void)
+{
+ hid_unregister_driver(&ems_driver);
+}
+
+module_init(ems_init);
+module_exit(ems_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 88dfcf49a5d7..279ba530003c 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -87,7 +87,7 @@ static int gaff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
@@ -95,12 +95,12 @@ static int gaff_init(struct hid_device *hid)
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 6) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -128,8 +128,7 @@ static int gaff_init(struct hid_device *hid)
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12"
- " devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
+ hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
return 0;
}
@@ -148,13 +147,13 @@ static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3341baa86a30..92a0d61a7379 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -97,6 +97,12 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
@@ -134,7 +140,9 @@
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
#define USB_VENDOR_ID_CANDO 0x2087
+#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01
@@ -156,6 +164,7 @@
#define USB_VENDOR_ID_CHICONY 0x04f2
#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
+#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_VENDOR_ID_CIDC 0x1677
@@ -179,6 +188,7 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1
+#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
@@ -196,13 +206,21 @@
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
+#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
+
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2700 0x0020
+#define USB_VENDOR_ID_EMS 0x2006
+#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
@@ -221,6 +239,7 @@
#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002
#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
@@ -303,6 +322,9 @@
#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
+#define USB_VENDOR_ID_HANVON 0x20b3
+#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18
+
#define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
@@ -475,6 +497,7 @@
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
+#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index bb0b3659437b..7f552bfad32c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -174,7 +174,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
clear_bit(*old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
+ dbg_hid("Assigned keycode %d to HID usage code %x\n",
usage->code, usage->hid);
/*
@@ -203,8 +203,8 @@ static int hidinput_setkeycode(struct input_dev *dev,
*
* as seen in the HID specification v1.11 6.2.2.7 Global Items.
*
- * Only exponent 1 length units are processed. Centimeters are converted to
- * inches. Degrees are converted to radians.
+ * Only exponent 1 length units are processed. Centimeters and inches are
+ * converted to millimeters. Degrees are converted to radians.
*/
static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
{
@@ -225,13 +225,16 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
*/
if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
if (field->unit == 0x11) { /* If centimeters */
- /* Convert to inches */
- prev = logical_extents;
- logical_extents *= 254;
- if (logical_extents < prev)
+ /* Convert to millimeters */
+ unit_exponent += 1;
+ } else if (field->unit == 0x13) { /* If inches */
+ /* Convert to millimeters */
+ prev = physical_extents;
+ physical_extents *= 254;
+ if (physical_extents < prev)
return 0;
- unit_exponent += 2;
- } else if (field->unit != 0x13) { /* If not inches */
+ unit_exponent -= 1;
+ } else {
return 0;
}
} else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
@@ -287,6 +290,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
}
+ if (field->report_type == HID_FEATURE_REPORT) {
+ if (device->driver->feature_mapping) {
+ device->driver->feature_mapping(device, hidinput, field,
+ usage);
+ }
+ goto ignore;
+ }
+
if (device->driver->input_mapping) {
int ret = device->driver->input_mapping(device, hidinput, field,
usage, &bit, &max);
@@ -316,21 +327,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
switch (field->application) {
case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
+ case HID_GD_POINTER: code += BTN_MOUSE; break;
case HID_GD_JOYSTICK:
if (code <= 0xf)
code += BTN_JOYSTICK;
else
code += BTN_TRIGGER_HAPPY;
break;
- case HID_GD_GAMEPAD: code += 0x130; break;
+ case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
default:
switch (field->physical) {
case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
- case HID_GD_JOYSTICK: code += 0x120; break;
- case HID_GD_GAMEPAD: code += 0x130; break;
- default: code += 0x100;
+ case HID_GD_POINTER: code += BTN_MOUSE; break;
+ case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break;
+ case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
+ default: code += BTN_MISC;
}
}
@@ -814,14 +825,14 @@ static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- return hid->ll_driver->open(hid);
+ return hid_hw_open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- hid->ll_driver->close(hid);
+ hid_hw_close(hid);
}
/*
@@ -836,7 +847,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
- int max_report_type = HID_OUTPUT_REPORT;
INIT_LIST_HEAD(&hid->inputs);
@@ -853,10 +863,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return -1;
}
- if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
- max_report_type = HID_INPUT_REPORT;
+ for (k = HID_INPUT_REPORT; k <= HID_FEATURE_REPORT; k++) {
+ if (k == HID_OUTPUT_REPORT &&
+ hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ continue;
- for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
if (!report->maxfield)
@@ -868,7 +879,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (!hidinput || !input_dev) {
kfree(hidinput);
input_free_device(input_dev);
- err_hid("Out of memory during hid input probe");
+ hid_err(hid, "Out of memory during hid input probe\n");
goto out_unwind;
}
@@ -909,6 +920,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hidinput = NULL;
}
}
+ }
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index 817247ee006c..f2ba9efc3a53 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -32,8 +32,8 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
rdesc[73] == 0x95 && rdesc[74] == 0x01) {
- dev_info(&hdev->dev, "fixing up Kye/Genius Ergo Mouse report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up Kye/Genius Ergo Mouse report descriptor\n");
rdesc[62] = 0x09;
rdesc[64] = 0x04;
rdesc[66] = 0x07;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index b629fba5a057..aef4104da141 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -53,23 +53,22 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
- dev_info(&hdev->dev, "fixing up Logitech keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
- dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
- "report descriptor\n");
+ hid_info(hdev,
+ "fixing up rel/abs in Logitech report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
if ((quirks & LG_FF4) && *rsize >= 101 &&
rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
rdesc[47] == 0x05 && rdesc[48] == 0x09) {
- dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
- "button descriptor\n");
+ hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
rdesc[41] = 0x05;
rdesc[42] = 0x09;
rdesc[47] = 0x95;
@@ -288,7 +287,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -297,7 +296,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index 4258253c36b3..3c31bc650e5d 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -72,18 +72,18 @@ int lg2ff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output report found\n");
+ hid_err(hid, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "output report is empty\n");
+ hid_err(hid, "output report is empty\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -110,8 +110,7 @@ int lg2ff_init(struct hid_device *hid)
usbhid_submit_report(hid, report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index 4002832ee4af..f98644c26c1d 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -141,20 +141,20 @@ int lg3ff_init(struct hid_device *hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list);
if (!report) {
- err_hid("NULL output report");
+ hid_err(hid, "NULL output report\n");
return -1;
}
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -169,8 +169,7 @@ int lg3ff_init(struct hid_device *hid)
if (test_bit(FF_AUTOCENTER, dev->ffbit))
dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
- dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by "
- "Gary Stein <LordCnidarian@gmail.com>\n");
+ hid_info(hid, "Force feedback for Logitech Flight System G940 by Gary Stein <LordCnidarian@gmail.com>\n");
return 0;
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 7eef5a2ce948..fa550c8e1d1b 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -101,20 +101,20 @@ int lg4ff_init(struct hid_device *hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list);
if (!report) {
- err_hid("NULL output report");
+ hid_err(hid, "NULL output report\n");
return -1;
}
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -129,8 +129,7 @@ int lg4ff_init(struct hid_device *hid)
if (test_bit(FF_AUTOCENTER, dev->ffbit))
dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
- dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by "
- "Simon Wood <simon@mungewell.org>\n");
+ hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
return 0;
}
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 61142b76a9b1..90d0ef2c92be 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -27,6 +27,8 @@
* e-mail - mail your message to <johann.deneux@it.uu.se>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
@@ -146,7 +148,7 @@ int lgff_init(struct hid_device* hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
@@ -154,7 +156,7 @@ int lgff_init(struct hid_device* hid)
report = list_entry(report_list->next, struct hid_report, list);
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -176,7 +178,7 @@ int lgff_init(struct hid_device* hid)
if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
dev->ff->set_autocenter = hid_lgff_set_autocenter;
- printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+ pr_info("Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
return 0;
}
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index e6dc15171664..698e6459fd0b 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -12,6 +12,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -433,6 +435,11 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
if (!msc->input)
msc->input = hi->input;
+ /* Magic Trackpad does not give relative data after switching to MT */
+ if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+ field->flags & HID_MAIN_ITEM_RELATIVE)
+ return -1;
+
return 0;
}
@@ -446,7 +453,7 @@ static int magicmouse_probe(struct hid_device *hdev,
msc = kzalloc(sizeof(*msc), GFP_KERNEL);
if (msc == NULL) {
- dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n");
+ hid_err(hdev, "can't alloc magicmouse descriptor\n");
return -ENOMEM;
}
@@ -459,13 +466,13 @@ static int magicmouse_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "magicmouse hid parse failed\n");
+ hid_err(hdev, "magicmouse hid parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "magicmouse hw start failed\n");
+ hid_err(hdev, "magicmouse hw start failed\n");
goto err_free;
}
@@ -486,7 +493,7 @@ static int magicmouse_probe(struct hid_device *hdev,
}
if (!report) {
- dev_err(&hdev->dev, "unable to register touch report\n");
+ hid_err(hdev, "unable to register touch report\n");
ret = -ENOMEM;
goto err_stop_hw;
}
@@ -495,8 +502,7 @@ static int magicmouse_probe(struct hid_device *hdev,
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
if (ret != sizeof(feature)) {
- dev_err(&hdev->dev, "unable to request touch data (%d)\n",
- ret);
+ hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
@@ -540,7 +546,7 @@ static int __init magicmouse_init(void)
ret = hid_register_driver(&magicmouse_driver);
if (ret)
- printk(KERN_ERR "can't register magicmouse driver\n");
+ pr_err("can't register magicmouse driver\n");
return ret;
}
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index dc618c33d0a2..0f6fc54dc196 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -40,8 +40,7 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
rdesc[559] == 0x29) {
- dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
- "Model 1028 report descriptor\n");
+ hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
rdesc[557] = 0x35;
rdesc[559] = 0x45;
}
@@ -155,14 +154,14 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
HID_CONNECT_HIDINPUT_FORCE : 0));
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index c95c31e2d869..dedf757781ae 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -26,8 +26,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
- dev_info(&hdev->dev, "fixing up button/consumer in HID report "
- "descriptor\n");
+ hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
rdesc[30] = 0x0c;
}
return rdesc;
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
index ac5421d568f1..aed7ffe36283 100644
--- a/drivers/hid/hid-mosart.c
+++ b/drivers/hid/hid-mosart.c
@@ -90,6 +90,10 @@ static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0xff000000:
/* ignore HID features */
return -1;
+
+ case HID_UP_BUTTON:
+ /* ignore buttons */
+ return -1;
}
return 0;
@@ -199,7 +203,7 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+ hid_err(hdev, "cannot allocate MosArt data\n");
return -ENOMEM;
}
td->valid = false;
@@ -230,6 +234,19 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
+#ifdef CONFIG_PM
+static int mosart_reset_resume(struct hid_device *hdev)
+{
+ struct hid_report_enum *re = hdev->report_enum
+ + HID_FEATURE_REPORT;
+ struct hid_report *r = re->report_id_hash[7];
+
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ return 0;
+}
+#endif
+
static void mosart_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
@@ -240,6 +257,7 @@ static void mosart_remove(struct hid_device *hdev)
static const struct hid_device_id mosart_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ }
};
MODULE_DEVICE_TABLE(hid, mosart_devices);
@@ -258,6 +276,9 @@ static struct hid_driver mosart_driver = {
.input_mapped = mosart_input_mapped,
.usage_table = mosart_grabbed_usages,
.event = mosart_event,
+#ifdef CONFIG_PM
+ .reset_resume = mosart_reset_resume,
+#endif
};
static int __init mosart_init(void)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
new file mode 100644
index 000000000000..07d3183fdde5
--- /dev/null
+++ b/drivers/hid/hid-multitouch.c
@@ -0,0 +1,516 @@
+/*
+ * HID driver for multitouch panels
+ *
+ * Copyright (c) 2010-2011 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/input/mt.h>
+#include "usbhid/usbhid.h"
+
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("HID multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+/* quirks to control the device */
+#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
+#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
+#define MT_QUIRK_CYPRESS (1 << 2)
+#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
+#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
+#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
+
+struct mt_slot {
+ __s32 x, y, p, w, h;
+ __s32 contactid; /* the device ContactID assigned to this slot */
+ bool touch_state; /* is the touch valid? */
+ bool seen_in_this_frame;/* has this slot been updated */
+};
+
+struct mt_device {
+ struct mt_slot curdata; /* placeholder of incoming data */
+ struct mt_class *mtclass; /* our mt device class */
+ unsigned last_field_index; /* last field index of the report */
+ unsigned last_slot_field; /* the last field of a slot */
+ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
+ __u8 num_received; /* how many contacts we received */
+ __u8 num_expected; /* expected last contact index */
+ bool curvalid; /* is the current contact valid? */
+ struct mt_slot slots[0]; /* first slot */
+};
+
+struct mt_class {
+ __s32 name; /* MT_CLS */
+ __s32 quirks;
+ __s32 sn_move; /* Signal/noise ratio for move events */
+ __s32 sn_pressure; /* Signal/noise ratio for pressure events */
+ __u8 maxcontacts;
+};
+
+/* classes of device behavior */
+#define MT_CLS_DEFAULT 1
+#define MT_CLS_DUAL1 2
+#define MT_CLS_DUAL2 3
+#define MT_CLS_CYPRESS 4
+
+/*
+ * these device-dependent functions determine what slot corresponds
+ * to a valid contact that was just read.
+ */
+
+static int cypress_compute_slot(struct mt_device *td)
+{
+ if (td->curdata.contactid != 0 || td->num_received == 0)
+ return td->curdata.contactid;
+ else
+ return -1;
+}
+
+static int find_slot_from_contactid(struct mt_device *td)
+{
+ int i;
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ if (td->slots[i].contactid == td->curdata.contactid &&
+ td->slots[i].touch_state)
+ return i;
+ }
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ if (!td->slots[i].seen_in_this_frame &&
+ !td->slots[i].touch_state)
+ return i;
+ }
+ /* should not occurs. If this happens that means
+ * that the device sent more touches that it says
+ * in the report descriptor. It is ignored then. */
+ return -1;
+}
+
+struct mt_class mt_classes[] = {
+ { .name = MT_CLS_DEFAULT,
+ .quirks = MT_QUIRK_VALID_IS_INRANGE,
+ .maxcontacts = 10 },
+ { .name = MT_CLS_DUAL1,
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_SLOT_IS_CONTACTID,
+ .maxcontacts = 2 },
+ { .name = MT_CLS_DUAL2,
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+ .maxcontacts = 2 },
+ { .name = MT_CLS_CYPRESS,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+ MT_QUIRK_CYPRESS,
+ .maxcontacts = 10 },
+
+ { }
+};
+
+static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ if (usage->hid == HID_DG_INPUTMODE) {
+ struct mt_device *td = hid_get_drvdata(hdev);
+ td->inputmode = field->report->id;
+ }
+}
+
+static void set_abs(struct input_dev *input, unsigned int code,
+ struct hid_field *field, int snratio)
+{
+ int fmin = field->logical_minimum;
+ int fmax = field->logical_maximum;
+ int fuzz = snratio ? (fmax - fmin) / snratio : 0;
+ input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+}
+
+static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_class *cls = td->mtclass;
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ set_abs(hi->input, ABS_MT_POSITION_X, field,
+ cls->sn_move);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_X, field, cls->sn_move);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ set_abs(hi->input, ABS_MT_POSITION_Y, field,
+ cls->sn_move);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_Y, field, cls->sn_move);
+ td->last_slot_field = usage->hid;
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONFIDENCE:
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_TIPSWITCH:
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONTACTID:
+ input_mt_init_slots(hi->input,
+ td->mtclass->maxcontacts);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_WIDTH:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_HEIGHT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MINOR);
+ field->logical_maximum = 1;
+ field->logical_minimum = 0;
+ set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_TIPPRESSURE:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_PRESSURE);
+ set_abs(hi->input, ABS_MT_PRESSURE, field,
+ cls->sn_pressure);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_PRESSURE, field,
+ cls->sn_pressure);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONTACTCOUNT:
+ td->last_field_index = field->report->maxfield - 1;
+ return 1;
+ case HID_DG_CONTACTMAX:
+ /* we don't set td->last_slot_field as contactcount and
+ * contact max are global to the report */
+ return -1;
+ }
+ /* let hid-input decide for the others */
+ return 0;
+
+ case 0xff000000:
+ /* we do not want to map these: no input-oriented meaning */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ set_bit(usage->type, hi->input->evbit);
+
+ return -1;
+}
+
+static int mt_compute_slot(struct mt_device *td)
+{
+ __s32 quirks = td->mtclass->quirks;
+
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
+ return td->curdata.contactid;
+
+ if (quirks & MT_QUIRK_CYPRESS)
+ return cypress_compute_slot(td);
+
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
+ return td->num_received;
+
+ return find_slot_from_contactid(td);
+}
+
+/*
+ * this function is called when a whole contact has been processed,
+ * so that it can assign it to a slot and store the data there
+ */
+static void mt_complete_slot(struct mt_device *td)
+{
+ td->curdata.seen_in_this_frame = true;
+ if (td->curvalid) {
+ int slotnum = mt_compute_slot(td);
+
+ if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts)
+ td->slots[slotnum] = td->curdata;
+ }
+ td->num_received++;
+}
+
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mt_emit_event(struct mt_device *td, struct input_dev *input)
+{
+ int i;
+
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ struct mt_slot *s = &(td->slots[i]);
+ if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
+ !s->seen_in_this_frame) {
+ s->touch_state = false;
+ }
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER,
+ s->touch_state);
+ if (s->touch_state) {
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
+ }
+ s->seen_in_this_frame = false;
+
+ }
+
+ input_mt_report_pointer_emulation(input, true);
+ input_sync(input);
+ td->num_received = 0;
+}
+
+
+
+static int mt_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mt_device *td = hid_get_drvdata(hid);
+ __s32 quirks = td->mtclass->quirks;
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+ td->curvalid = value;
+ break;
+ case HID_DG_TIPSWITCH:
+ if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ td->curvalid = value;
+ td->curdata.touch_state = value;
+ break;
+ case HID_DG_CONFIDENCE:
+ if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
+ td->curvalid = value;
+ break;
+ case HID_DG_CONTACTID:
+ td->curdata.contactid = value;
+ break;
+ case HID_DG_TIPPRESSURE:
+ td->curdata.p = value;
+ break;
+ case HID_GD_X:
+ td->curdata.x = value;
+ break;
+ case HID_GD_Y:
+ td->curdata.y = value;
+ break;
+ case HID_DG_WIDTH:
+ td->curdata.w = value;
+ break;
+ case HID_DG_HEIGHT:
+ td->curdata.h = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ /*
+ * Includes multi-packet support where subsequent
+ * packets are sent with zero contactcount.
+ */
+ if (value)
+ td->num_expected = value;
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+
+ if (usage->hid == td->last_slot_field)
+ mt_complete_slot(td);
+
+ if (field->index == td->last_field_index
+ && td->num_received >= td->num_expected)
+ mt_emit_event(td, field->hidinput->input);
+
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static void mt_set_input_mode(struct hid_device *hdev)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct hid_report *r;
+ struct hid_report_enum *re;
+
+ if (td->inputmode < 0)
+ return;
+
+ re = &(hdev->report_enum[HID_FEATURE_REPORT]);
+ r = re->report_id_hash[td->inputmode];
+ if (r) {
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ }
+}
+
+static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret, i;
+ struct mt_device *td;
+ struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+
+ for (i = 0; mt_classes[i].name ; i++) {
+ if (id->driver_data == mt_classes[i].name) {
+ mtclass = &(mt_classes[i]);
+ break;
+ }
+ }
+
+ /* This allows the driver to correctly support devices
+ * that emit events over several HID messages.
+ */
+ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+
+ td = kzalloc(sizeof(struct mt_device) +
+ mtclass->maxcontacts * sizeof(struct mt_slot),
+ GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate multitouch data\n");
+ return -ENOMEM;
+ }
+ td->mtclass = mtclass;
+ td->inputmode = -1;
+ hid_set_drvdata(hdev, td);
+
+ ret = hid_parse(hdev);
+ if (ret != 0)
+ goto fail;
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret)
+ goto fail;
+
+ mt_set_input_mode(hdev);
+
+ return 0;
+
+fail:
+ kfree(td);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int mt_reset_resume(struct hid_device *hdev)
+{
+ mt_set_input_mode(hdev);
+ return 0;
+}
+#endif
+
+static void mt_remove(struct hid_device *hdev)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ hid_hw_stop(hdev);
+ kfree(td);
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mt_devices[] = {
+
+ /* Cypress panel */
+ { .driver_data = MT_CLS_CYPRESS,
+ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
+ USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
+
+ /* GeneralTouch panel */
+ { .driver_data = MT_CLS_DUAL2,
+ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+ USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+
+ /* PixCir-based panels */
+ { .driver_data = MT_CLS_DUAL1,
+ HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+ USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { .driver_data = MT_CLS_DUAL1,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mt_devices);
+
+static const struct hid_usage_id mt_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mt_driver = {
+ .name = "hid-multitouch",
+ .id_table = mt_devices,
+ .probe = mt_probe,
+ .remove = mt_remove,
+ .input_mapping = mt_input_mapping,
+ .input_mapped = mt_input_mapped,
+ .feature_mapping = mt_feature_mapping,
+ .usage_table = mt_grabbed_usages,
+ .event = mt_event,
+#ifdef CONFIG_PM
+ .reset_resume = mt_reset_resume,
+#endif
+};
+
+static int __init mt_init(void)
+{
+ return hid_register_driver(&mt_driver);
+}
+
+static void __exit mt_exit(void)
+{
+ hid_unregister_driver(&mt_driver);
+}
+
+module_init(mt_init);
+module_exit(mt_exit);
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 69169efa1e16..beb403421e72 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -130,8 +130,7 @@ static void ntrig_report_version(struct hid_device *hdev)
if (ret == 8) {
ret = ntrig_version_string(&data[2], buf);
- dev_info(&hdev->dev,
- "Firmware version: %s (%02x%02x %02x%02x)\n",
+ hid_info(hdev, "Firmware version: %s (%02x%02x %02x%02x)\n",
buf, data[2], data[3], data[4], data[5]);
}
@@ -831,7 +830,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
if (!nd) {
- dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+ hid_err(hdev, "cannot allocate N-Trig data\n");
return -ENOMEM;
}
@@ -850,13 +849,13 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
index 2e79716dca31..e90edfc63051 100644
--- a/drivers/hid/hid-ortek.c
+++ b/drivers/hid/hid-ortek.c
@@ -23,8 +23,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
- dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
- "report descriptor.\n");
+ hid_info(hdev, "Fixing up Ortek WKB-2000 report descriptor\n");
rdesc[55] = 0x92;
}
return rdesc;
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 308d6ae48a3e..f1ea3ff8a98d 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -29,8 +29,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
- dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
- "descriptor\n");
+ hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
rdesc[60] = 0xfa;
rdesc[40] = 0xfa;
}
@@ -77,13 +76,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index bc2e07740628..de9cf21b3494 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -253,7 +253,7 @@ static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int di
if (report->id == id)
return report;
}
- dev_warn(&hdev->dev, "No report with id 0x%x found\n", id);
+ hid_warn(hdev, "No report with id 0x%x found\n", id);
return NULL;
}
@@ -1329,7 +1329,7 @@ static int picolcd_check_version(struct hid_device *hdev)
verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
if (!verinfo) {
- dev_err(&hdev->dev, "no version response from PicoLCD");
+ hid_err(hdev, "no version response from PicoLCD\n");
return -ENODEV;
}
@@ -1337,14 +1337,14 @@ static int picolcd_check_version(struct hid_device *hdev)
data->version[0] = verinfo->raw_data[1];
data->version[1] = verinfo->raw_data[0];
if (data->status & PICOLCD_BOOTLOADER) {
- dev_info(&hdev->dev, "PicoLCD, bootloader version %d.%d\n",
- verinfo->raw_data[1], verinfo->raw_data[0]);
+ hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+ verinfo->raw_data[1], verinfo->raw_data[0]);
} else {
- dev_info(&hdev->dev, "PicoLCD, firmware version %d.%d\n",
- verinfo->raw_data[1], verinfo->raw_data[0]);
+ hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+ verinfo->raw_data[1], verinfo->raw_data[0]);
}
} else {
- dev_err(&hdev->dev, "confused, got unexpected version response from PicoLCD\n");
+ hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
ret = -EINVAL;
}
kfree(verinfo);
@@ -1544,7 +1544,7 @@ static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
/* prepare buffer with info about what we want to read (addr & len) */
raw_data[0] = *off & 0xff;
- raw_data[1] = (*off >> 8) && 0xff;
+ raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
@@ -1583,7 +1583,7 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
memset(raw_data, 0, sizeof(raw_data));
raw_data[0] = *off & 0xff;
- raw_data[1] = (*off >> 8) && 0xff;
+ raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
@@ -1867,6 +1867,7 @@ static void picolcd_debug_out_report(struct picolcd_data *data,
report->id, raw_size);
hid_debug_event(hdev, buff);
if (raw_size + 5 > sizeof(raw_data)) {
+ kfree(buff);
hid_debug_event(hdev, " TOO BIG\n");
return;
} else {
@@ -2328,8 +2329,7 @@ static void picolcd_init_devfs(struct picolcd_data *data,
(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
hdev->debug_dir, data, &picolcd_debug_flash_fops);
} else if (flash_r || flash_w)
- dev_warn(&hdev->dev, "Unexpected FLASH access reports, "
- "please submit rdesc for review\n");
+ hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
}
static void picolcd_exit_devfs(struct picolcd_data *data)
@@ -2457,13 +2457,13 @@ static int picolcd_init_keys(struct picolcd_data *data,
return -ENODEV;
if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
report->field[0]->report_size != 8) {
- dev_err(&hdev->dev, "unsupported KEY_STATE report");
+ hid_err(hdev, "unsupported KEY_STATE report\n");
return -EINVAL;
}
idev = input_allocate_device();
if (idev == NULL) {
- dev_err(&hdev->dev, "failed to allocate input device");
+ hid_err(hdev, "failed to allocate input device\n");
return -ENOMEM;
}
input_set_drvdata(idev, hdev);
@@ -2485,7 +2485,7 @@ static int picolcd_init_keys(struct picolcd_data *data,
input_set_capability(idev, EV_KEY, data->keycode[i]);
error = input_register_device(idev);
if (error) {
- dev_err(&hdev->dev, "error registering the input device");
+ hid_err(hdev, "error registering the input device\n");
input_free_device(idev);
return error;
}
@@ -2522,9 +2522,8 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
return error;
if (data->version[0] != 0 && data->version[1] != 3)
- dev_info(&hdev->dev, "Device with untested firmware revision, "
- "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
- dev_name(&hdev->dev));
+ hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+ dev_name(&hdev->dev));
/* Setup keypad input device */
error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
@@ -2581,9 +2580,8 @@ static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data
return error;
if (data->version[0] != 1 && data->version[1] != 0)
- dev_info(&hdev->dev, "Device with untested bootloader revision, "
- "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
- dev_name(&hdev->dev));
+ hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+ dev_name(&hdev->dev));
picolcd_init_devfs(data, NULL, NULL,
picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
@@ -2605,7 +2603,7 @@ static int picolcd_probe(struct hid_device *hdev,
*/
data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
if (data == NULL) {
- dev_err(&hdev->dev, "can't allocate space for Minibox PicoLCD device data\n");
+ hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
error = -ENOMEM;
goto err_no_cleanup;
}
@@ -2621,7 +2619,7 @@ static int picolcd_probe(struct hid_device *hdev,
/* Parse the device reports and start it up */
error = hid_parse(hdev);
if (error) {
- dev_err(&hdev->dev, "device report parse failed\n");
+ hid_err(hdev, "device report parse failed\n");
goto err_cleanup_data;
}
@@ -2631,25 +2629,25 @@ static int picolcd_probe(struct hid_device *hdev,
error = hid_hw_start(hdev, 0);
hdev->claimed = 0;
if (error) {
- dev_err(&hdev->dev, "hardware start failed\n");
+ hid_err(hdev, "hardware start failed\n");
goto err_cleanup_data;
}
- error = hdev->ll_driver->open(hdev);
+ error = hid_hw_open(hdev);
if (error) {
- dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n");
+ hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
goto err_cleanup_hid_hw;
}
error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
if (error) {
- dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+ hid_err(hdev, "failed to create sysfs attributes\n");
goto err_cleanup_hid_ll;
}
error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
if (error) {
- dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+ hid_err(hdev, "failed to create sysfs attributes\n");
goto err_cleanup_sysfs1;
}
@@ -2668,7 +2666,7 @@ err_cleanup_sysfs2:
err_cleanup_sysfs1:
device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
err_cleanup_hid_ll:
- hdev->ll_driver->close(hdev);
+ hid_hw_close(hdev);
err_cleanup_hid_hw:
hid_hw_stop(hdev);
err_cleanup_data:
@@ -2699,7 +2697,7 @@ static void picolcd_remove(struct hid_device *hdev)
picolcd_exit_devfs(data);
device_remove_file(&hdev->dev, &dev_attr_operation_mode);
device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
- hdev->ll_driver->close(hdev);
+ hid_hw_close(hdev);
hid_hw_stop(hdev);
hid_set_drvdata(hdev, NULL);
@@ -2753,7 +2751,7 @@ static void __exit picolcd_exit(void)
{
hid_unregister_driver(&picolcd_driver);
#ifdef CONFIG_HID_PICOLCD_FB
- flush_scheduled_work();
+ flush_work_sync(&picolcd_fb_cleanup);
WARN_ON(fb_pending);
#endif
}
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 9f41e2bd8483..06e5300d43d2 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -103,7 +103,7 @@ static int plff_init(struct hid_device *hid)
*/
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
@@ -112,14 +112,13 @@ static int plff_init(struct hid_device *hid)
report_ptr = report_ptr->next;
if (report_ptr == report_list) {
- dev_err(&hid->dev, "required output report is "
- "missing\n");
+ hid_err(hid, "required output report is missing\n");
return -ENODEV;
}
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
@@ -137,7 +136,7 @@ static int plff_init(struct hid_device *hid)
weak = &report->field[3]->value[0];
debug("detected 4-field device");
} else {
- dev_err(&hid->dev, "not enough fields or values\n");
+ hid_err(hid, "not enough fields or values\n");
return -ENODEV;
}
@@ -164,8 +163,7 @@ static int plff_init(struct hid_device *hid)
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
}
- dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
- "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
@@ -185,13 +183,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 48eab84f53b5..ab19f2905d27 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -16,6 +16,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -130,7 +132,7 @@ static ssize_t store_channel(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(channel, S_IRUGO | S_IWUGO, show_channel,
+static DEVICE_ATTR(channel, S_IRUGO | S_IWUSR | S_IWGRP , show_channel,
store_channel);
static struct device_attribute *sysfs_device_attr_channel = {
@@ -169,7 +171,7 @@ static ssize_t store_sustain(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(sustain, S_IRUGO | S_IWUGO, show_sustain,
+static DEVICE_ATTR(sustain, S_IRUGO | S_IWUSR | S_IWGRP, show_sustain,
store_sustain);
static struct device_attribute *sysfs_device_attr_sustain = {
@@ -207,7 +209,7 @@ static ssize_t store_octave(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(octave, S_IRUGO | S_IWUGO, show_octave,
+static DEVICE_ATTR(octave, S_IRUGO | S_IWUSR | S_IWGRP, show_octave,
store_octave);
static struct device_attribute *sysfs_device_attr_octave = {
@@ -285,11 +287,11 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm)
continue;
if (report->maxfield < 1) {
- dev_err(&hdev->dev, "output report is empty\n");
+ hid_err(hdev, "output report is empty\n");
break;
}
if (report->field[0]->report_count != 2) {
- dev_err(&hdev->dev, "field count too low\n");
+ hid_err(hdev, "field count too low\n");
break;
}
pm->pcmidi_report6 = report;
@@ -746,8 +748,8 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (*rsize == 178 &&
rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
rdesc[113] == 0xff) {
- dev_info(&hdev->dev, "fixing up pc-midi keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up pc-midi keyboard report descriptor\n");
rdesc[144] = 0x18; /* report 4: was 0x10 report count */
}
@@ -805,7 +807,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
pk = kzalloc(sizeof(*pk), GFP_KERNEL);
if (pk == NULL) {
- dev_err(&hdev->dev, "prodikeys: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
}
@@ -813,8 +815,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
pm = kzalloc(sizeof(*pm), GFP_KERNEL);
if (pm == NULL) {
- dev_err(&hdev->dev,
- "prodikeys: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
ret = -ENOMEM;
goto err_free;
}
@@ -827,7 +828,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "prodikeys: hid parse failed\n");
+ hid_err(hdev, "hid parse failed\n");
goto err_free;
}
@@ -837,7 +838,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "prodikeys: hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -896,7 +897,7 @@ static int pk_init(void)
ret = hid_register_driver(&pk_driver);
if (ret)
- printk(KERN_ERR "can't register prodikeys driver\n");
+ pr_err("can't register prodikeys driver\n");
return ret;
}
diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c
index 54d3db50605b..87a54df4d4ac 100644
--- a/drivers/hid/hid-quanta.c
+++ b/drivers/hid/hid-quanta.c
@@ -195,7 +195,7 @@ static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n");
+ hid_err(hdev, "cannot allocate Quanta Touch data\n");
return -ENOMEM;
}
td->valid = false;
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index f77695762cb5..cbd8cc42e75a 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -35,6 +35,11 @@
#include "hid-roccat.h"
#include "hid-roccat-kone.h"
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* kone_class is used for creating sysfs attributes via roccat char device */
+static struct class *kone_class;
+
static void kone_set_settings_checksum(struct kone_settings *settings)
{
uint16_t checksum = 0;
@@ -90,8 +95,7 @@ static int kone_check_write(struct usb_device *usb_dev)
kfree(data);
return 0;
} else { /* unknown answer */
- dev_err(&usb_dev->dev, "got retval %d when checking write\n",
- *data);
+ hid_err(usb_dev, "got retval %d when checking write\n", *data);
kfree(data);
return -EIO;
}
@@ -262,7 +266,8 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_settings))
@@ -286,7 +291,8 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0, difference;
@@ -319,10 +325,11 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
return sizeof(struct kone_settings);
}
-static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number) {
- struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_read_profilex(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count) {
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_profile))
@@ -332,47 +339,18 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
count = sizeof(struct kone_profile) - off;
mutex_lock(&kone->kone_lock);
- memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
+ memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count);
mutex_unlock(&kone->kone_lock);
return count;
}
-static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5);
-}
-
/* Writes data only if different to stored data */
-static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number) {
- struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_write_profilex(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count) {
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct kone_profile *profile;
@@ -382,13 +360,14 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
if (off != 0 || count != sizeof(struct kone_profile))
return -EINVAL;
- profile = &kone->profiles[number - 1];
+ profile = &kone->profiles[*(uint *)(attr->private)];
mutex_lock(&kone->kone_lock);
difference = memcmp(buf, profile, sizeof(struct kone_profile));
if (difference) {
retval = kone_set_profile(usb_dev,
- (struct kone_profile const *)buf, number);
+ (struct kone_profile const *)buf,
+ *(uint *)(attr->private) + 1);
if (!retval)
memcpy(profile, buf, sizeof(struct kone_profile));
}
@@ -400,47 +379,19 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
return sizeof(struct kone_profile);
}
-static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5);
-}
-
static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
}
static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
}
@@ -448,11 +399,15 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
static ssize_t kone_sysfs_show_weight(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int weight = 0;
int retval;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
mutex_lock(&kone->kone_lock);
retval = kone_get_weight(usb_dev, &weight);
mutex_unlock(&kone->kone_lock);
@@ -465,14 +420,16 @@ static ssize_t kone_sysfs_show_weight(struct device *dev,
static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
}
static ssize_t kone_sysfs_show_tcu(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu);
}
@@ -504,11 +461,15 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number)
static ssize_t kone_sysfs_set_tcu(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int retval;
unsigned long state;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
retval = strict_strtoul(buf, 10, &state);
if (retval)
return retval;
@@ -556,7 +517,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
retval = kone_set_settings(usb_dev, &kone->settings);
if (retval) {
- dev_err(&usb_dev->dev, "couldn't set tcu state\n");
+ hid_err(usb_dev, "couldn't set tcu state\n");
/*
* try to reread valid settings into buffer overwriting
* first error code
@@ -570,7 +531,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
retval = size;
exit_no_settings:
- dev_err(&usb_dev->dev, "couldn't read settings\n");
+ hid_err(usb_dev, "couldn't read settings\n");
exit_unlock:
mutex_unlock(&kone->kone_lock);
return retval;
@@ -579,18 +540,23 @@ exit_unlock:
static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile);
}
static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int retval;
unsigned long new_startup_profile;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
retval = strict_strtoul(buf, 10, &new_startup_profile);
if (retval)
return retval;
@@ -617,160 +583,92 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
return size;
}
-/*
- * Read actual dpi settings.
- * Returns raw value for further processing. Refer to enum kone_polling_rates to
- * get real value.
- */
-static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
-
-/*
- * The mouse can be equipped with one of four supplied weights from 5 to 20
- * grams which are recognized and its value can be read out.
- * This returns the raw value reported by the mouse for easy evaluation by
- * software. Refer to enum kone_weights to get corresponding real weight.
- */
-static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
-
-/*
- * Prints firmware version stored in mouse as integer.
- * The raw value reported by the mouse is returned for easy evaluation, to get
- * the real version number the decimal point has to be shifted 2 positions to
- * the left. E.g. a value of 138 means 1.38.
- */
-static DEVICE_ATTR(firmware_version, 0440,
- kone_sysfs_show_firmware_version, NULL);
-
-/*
- * Prints state of Tracking Control Unit as number where 0 = off and 1 = on
- * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu
- */
-static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
-
-/* Prints and takes the number of the profile the mouse starts with */
-static DEVICE_ATTR(startup_profile, 0660,
- kone_sysfs_show_startup_profile,
- kone_sysfs_set_startup_profile);
-
-static struct attribute *kone_attributes[] = {
- &dev_attr_actual_dpi.attr,
- &dev_attr_actual_profile.attr,
- &dev_attr_weight.attr,
- &dev_attr_firmware_version.attr,
- &dev_attr_tcu.attr,
- &dev_attr_startup_profile.attr,
- NULL
-};
-
-static struct attribute_group kone_attribute_group = {
- .attrs = kone_attributes
-};
-
-static struct bin_attribute kone_settings_attr = {
- .attr = { .name = "settings", .mode = 0660 },
- .size = sizeof(struct kone_settings),
- .read = kone_sysfs_read_settings,
- .write = kone_sysfs_write_settings
-};
+static struct device_attribute kone_attributes[] = {
+ /*
+ * Read actual dpi settings.
+ * Returns raw value for further processing. Refer to enum
+ * kone_polling_rates to get real value.
+ */
+ __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
+ __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
-static struct bin_attribute kone_profile1_attr = {
- .attr = { .name = "profile1", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile1,
- .write = kone_sysfs_write_profile1
-};
+ /*
+ * The mouse can be equipped with one of four supplied weights from 5
+ * to 20 grams which are recognized and its value can be read out.
+ * This returns the raw value reported by the mouse for easy evaluation
+ * by software. Refer to enum kone_weights to get corresponding real
+ * weight.
+ */
+ __ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
-static struct bin_attribute kone_profile2_attr = {
- .attr = { .name = "profile2", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile2,
- .write = kone_sysfs_write_profile2
-};
+ /*
+ * Prints firmware version stored in mouse as integer.
+ * The raw value reported by the mouse is returned for easy evaluation,
+ * to get the real version number the decimal point has to be shifted 2
+ * positions to the left. E.g. a value of 138 means 1.38.
+ */
+ __ATTR(firmware_version, 0440,
+ kone_sysfs_show_firmware_version, NULL),
-static struct bin_attribute kone_profile3_attr = {
- .attr = { .name = "profile3", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile3,
- .write = kone_sysfs_write_profile3
-};
+ /*
+ * Prints state of Tracking Control Unit as number where 0 = off and
+ * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
+ * activates the tcu
+ */
+ __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
-static struct bin_attribute kone_profile4_attr = {
- .attr = { .name = "profile4", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile4,
- .write = kone_sysfs_write_profile4
+ /* Prints and takes the number of the profile the mouse starts with */
+ __ATTR(startup_profile, 0660,
+ kone_sysfs_show_startup_profile,
+ kone_sysfs_set_startup_profile),
+ __ATTR_NULL
};
-static struct bin_attribute kone_profile5_attr = {
- .attr = { .name = "profile5", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile5,
- .write = kone_sysfs_write_profile5
+static struct bin_attribute kone_bin_attributes[] = {
+ {
+ .attr = { .name = "settings", .mode = 0660 },
+ .size = sizeof(struct kone_settings),
+ .read = kone_sysfs_read_settings,
+ .write = kone_sysfs_write_settings
+ },
+ {
+ .attr = { .name = "profile1", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[4]
+ },
+ __ATTR_NULL
};
-static int kone_create_sysfs_attributes(struct usb_interface *intf)
-{
- int retval;
-
- retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group);
- if (retval)
- goto exit_1;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr);
- if (retval)
- goto exit_2;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr);
- if (retval)
- goto exit_3;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr);
- if (retval)
- goto exit_4;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr);
- if (retval)
- goto exit_5;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr);
- if (retval)
- goto exit_6;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr);
- if (retval)
- goto exit_7;
-
- return 0;
-
-exit_7:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-exit_6:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-exit_5:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-exit_4:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-exit_3:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-exit_2:
- sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-exit_1:
- return retval;
-}
-
-static void kone_remove_sysfs_attributes(struct usb_interface *intf)
-{
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
- sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-}
-
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
struct kone_device *kone)
{
@@ -818,32 +716,25 @@ static int kone_init_specials(struct hid_device *hdev)
kone = kzalloc(sizeof(*kone), GFP_KERNEL);
if (!kone) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, kone);
retval = kone_init_kone_device_struct(usb_dev, kone);
if (retval) {
- dev_err(&hdev->dev,
- "couldn't init struct kone_device\n");
+ hid_err(hdev, "couldn't init struct kone_device\n");
goto exit_free;
}
- retval = roccat_connect(hdev);
+ retval = roccat_connect(kone_class, hdev);
if (retval < 0) {
- dev_err(&hdev->dev, "couldn't init char dev\n");
+ hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */
} else {
kone->roccat_claimed = 1;
kone->chrdev_minor = retval;
}
-
- retval = kone_create_sysfs_attributes(intf);
- if (retval) {
- dev_err(&hdev->dev, "cannot create sysfs files\n");
- goto exit_free;
- }
} else {
hid_set_drvdata(hdev, NULL);
}
@@ -854,7 +745,6 @@ exit_free:
return retval;
}
-
static void kone_remove_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
@@ -862,7 +752,6 @@ static void kone_remove_specials(struct hid_device *hdev)
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
- kone_remove_sysfs_attributes(intf);
kone = hid_get_drvdata(hdev);
if (kone->roccat_claimed)
roccat_disconnect(kone->chrdev_minor);
@@ -876,19 +765,19 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
retval = hid_parse(hdev);
if (retval) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = kone_init_specials(hdev);
if (retval) {
- dev_err(&hdev->dev, "couldn't install mouse\n");
+ hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
@@ -1006,11 +895,24 @@ static struct hid_driver kone_driver = {
static int __init kone_init(void)
{
- return hid_register_driver(&kone_driver);
+ int retval;
+
+ /* class name has to be same as driver name */
+ kone_class = class_create(THIS_MODULE, "kone");
+ if (IS_ERR(kone_class))
+ return PTR_ERR(kone_class);
+ kone_class->dev_attrs = kone_attributes;
+ kone_class->dev_bin_attrs = kone_bin_attributes;
+
+ retval = hid_register_driver(&kone_driver);
+ if (retval)
+ class_destroy(kone_class);
+ return retval;
}
static void __exit kone_exit(void)
{
+ class_destroy(kone_class);
hid_unregister_driver(&kone_driver);
}
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 130d6566ea82..64abb5b8a59a 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -14,14 +14,11 @@
#include <linux/types.h>
-#pragma pack(push)
-#pragma pack(1)
-
struct kone_keystroke {
uint8_t key;
uint8_t action;
uint16_t period; /* in milliseconds */
-};
+} __attribute__ ((__packed__));
enum kone_keystroke_buttons {
kone_keystroke_button_1 = 0xf0, /* left mouse button */
@@ -44,7 +41,7 @@ struct kone_button_info {
uint8_t macro_name[16]; /* can be max 15 chars long */
uint8_t count;
struct kone_keystroke keystrokes[20];
-};
+} __attribute__ ((__packed__));
enum kone_button_info_types {
/* valid button types until firmware 1.32 */
@@ -95,7 +92,7 @@ struct kone_light_info {
uint8_t red; /* range 0x00-0xff */
uint8_t green; /* range 0x00-0xff */
uint8_t blue; /* range 0x00-0xff */
-};
+} __attribute__ ((__packed__));
struct kone_profile {
uint16_t size; /* always 975 */
@@ -130,7 +127,7 @@ struct kone_profile {
struct kone_button_info button_infos[8];
uint16_t checksum; /* \brief holds checksum of struct */
-};
+} __attribute__ ((__packed__));
enum kone_polling_rates {
kone_polling_rate_125 = 1,
@@ -147,7 +144,7 @@ struct kone_settings {
uint8_t calibration_data[4];
uint8_t unknown3[2];
uint16_t checksum;
-};
+} __attribute__ ((__packed__));
/*
* 12 byte mouse event read by interrupt_read
@@ -163,7 +160,7 @@ struct kone_mouse_event {
uint8_t event;
uint8_t value; /* press = 0, release = 1 */
uint8_t macro_key; /* 0 to 8 */
-};
+} __attribute__ ((__packed__));
enum kone_mouse_events {
/* osd events are thought to be display on screen */
@@ -191,9 +188,7 @@ struct kone_roccat_report {
uint8_t event;
uint8_t value; /* holds dpi or profile value */
uint8_t key; /* macro key on overlong macro execution */
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
struct kone_device {
/*
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
new file mode 100644
index 000000000000..1608c8d1efd6
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -0,0 +1,837 @@
+/*
+ * Roccat Kone[+] driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Roccat Kone[+] is an updated/improved version of the Kone with more memory
+ * and functionality and without the non-standard behaviours the Kone had.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "hid-ids.h"
+#include "hid-roccat.h"
+#include "hid-roccat-koneplus.h"
+
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+static struct class *koneplus_class;
+
+static void koneplus_profile_activated(struct koneplus_device *koneplus,
+ uint new_profile)
+{
+ koneplus->actual_profile = new_profile;
+}
+
+static int koneplus_send_control(struct usb_device *usb_dev, uint value,
+ enum koneplus_control_requests request)
+{
+ int len;
+ struct koneplus_control *control;
+
+ if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
+ request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+ value > 4)
+ return -EINVAL;
+
+ control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
+ if (!control)
+ return -ENOMEM;
+
+ control->command = KONEPLUS_COMMAND_CONTROL;
+ control->value = value;
+ control->request = request;
+
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ KONEPLUS_USB_COMMAND_CONTROL, 0, control,
+ sizeof(struct koneplus_control),
+ USB_CTRL_SET_TIMEOUT);
+
+ kfree(control);
+
+ if (len != sizeof(struct koneplus_control))
+ return len;
+
+ return 0;
+}
+
+static int koneplus_receive(struct usb_device *usb_dev, uint usb_command,
+ void *buf, uint size) {
+ int len;
+
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ return (len != size) ? -EIO : 0;
+}
+
+static int koneplus_receive_control_status(struct usb_device *usb_dev)
+{
+ int retval;
+ struct koneplus_control *control;
+
+ control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
+ if (!control)
+ return -ENOMEM;
+
+ do {
+ retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+ control, sizeof(struct koneplus_control));
+
+ /* check if we get a completely wrong answer */
+ if (retval)
+ goto out;
+
+ if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) {
+ retval = 0;
+ goto out;
+ }
+
+ /* indicates that hardware needs some more time to complete action */
+ if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+ msleep(500); /* windows driver uses 1000 */
+ continue;
+ }
+
+ /* seems to be critical - replug necessary */
+ if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ dev_err(&usb_dev->dev, "koneplus_receive_control_status: "
+ "unknown response value 0x%x\n", control->value);
+ retval = -EINVAL;
+ goto out;
+
+ } while (1);
+out:
+ kfree(control);
+ return retval;
+}
+
+static int koneplus_send(struct usb_device *usb_dev, uint command,
+ void *buf, uint size) {
+ int len;
+
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ if (len != size)
+ return -EIO;
+
+ if (koneplus_receive_control_status(usb_dev))
+ return -EIO;
+
+ return 0;
+}
+
+static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
+ enum koneplus_control_requests request)
+{
+ int retval;
+
+ retval = koneplus_send_control(usb_dev, number, request);
+ if (retval)
+ return retval;
+
+ /* allow time to settle things - windows driver uses 500 */
+ msleep(100);
+
+ retval = koneplus_receive_control_status(usb_dev);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+static int koneplus_get_info(struct usb_device *usb_dev,
+ struct koneplus_info *buf)
+{
+ return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
+ buf, sizeof(struct koneplus_info));
+}
+
+static int koneplus_get_profile_settings(struct usb_device *usb_dev,
+ struct koneplus_profile_settings *buf, uint number)
+{
+ int retval;
+
+ retval = koneplus_select_profile(usb_dev, number,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
+ if (retval)
+ return retval;
+
+ return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_set_profile_settings(struct usb_device *usb_dev,
+ struct koneplus_profile_settings const *settings)
+{
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ (void *)settings, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
+ struct koneplus_profile_buttons *buf, int number)
+{
+ int retval;
+
+ retval = koneplus_select_profile(usb_dev, number,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
+ if (retval)
+ return retval;
+
+ return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
+ struct koneplus_profile_buttons const *buttons)
+{
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ (void *)buttons, sizeof(struct koneplus_profile_buttons));
+}
+
+/* retval is 0-4 on success, < 0 on error */
+static int koneplus_get_startup_profile(struct usb_device *usb_dev)
+{
+ struct koneplus_startup_profile *buf;
+ int retval;
+
+ buf = kmalloc(sizeof(struct koneplus_startup_profile), GFP_KERNEL);
+
+ retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+ buf, sizeof(struct koneplus_startup_profile));
+
+ if (retval)
+ goto out;
+
+ retval = buf->startup_profile;
+out:
+ kfree(buf);
+ return retval;
+}
+
+static int koneplus_set_startup_profile(struct usb_device *usb_dev,
+ int startup_profile)
+{
+ struct koneplus_startup_profile buf;
+
+ buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
+ buf.size = sizeof(struct koneplus_startup_profile);
+ buf.startup_profile = startup_profile;
+
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+ (char *)&buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
+ char *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = koneplus_receive(usb_dev, command, buf, real_size);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return real_size;
+}
+
+static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
+ void const *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = koneplus_send(usb_dev, command, (void *)buf, real_size);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return real_size;
+}
+
+static ssize_t koneplus_sysfs_write_macro(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO);
+}
+
+static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct koneplus_profile_settings))
+ return 0;
+
+ if (off + count > sizeof(struct koneplus_profile_settings))
+ count = sizeof(struct koneplus_profile_settings) - off;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ memcpy(buf, ((void const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_number;
+ struct koneplus_profile_settings *profile_settings;
+
+ if (off != 0 || count != sizeof(struct koneplus_profile_settings))
+ return -EINVAL;
+
+ profile_number = ((struct koneplus_profile_settings const *)buf)->number;
+ profile_settings = &koneplus->profile_settings[profile_number];
+
+ mutex_lock(&koneplus->koneplus_lock);
+ difference = memcmp(buf, profile_settings,
+ sizeof(struct koneplus_profile_settings));
+ if (difference) {
+ retval = koneplus_set_profile_settings(usb_dev,
+ (struct koneplus_profile_settings const *)buf);
+ if (!retval)
+ memcpy(profile_settings, buf,
+ sizeof(struct koneplus_profile_settings));
+ }
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct koneplus_profile_settings);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct koneplus_profile_buttons))
+ return 0;
+
+ if (off + count > sizeof(struct koneplus_profile_buttons))
+ count = sizeof(struct koneplus_profile_buttons) - off;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ memcpy(buf, ((void const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ uint profile_number;
+ struct koneplus_profile_buttons *profile_buttons;
+
+ if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
+ return -EINVAL;
+
+ profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
+ profile_buttons = &koneplus->profile_buttons[profile_number];
+
+ mutex_lock(&koneplus->koneplus_lock);
+ difference = memcmp(buf, profile_buttons,
+ sizeof(struct koneplus_profile_buttons));
+ if (difference) {
+ retval = koneplus_set_profile_buttons(usb_dev,
+ (struct koneplus_profile_buttons const *)buf);
+ if (!retval)
+ memcpy(profile_buttons, buf,
+ sizeof(struct koneplus_profile_buttons));
+ }
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct koneplus_profile_buttons);
+}
+
+static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
+}
+
+static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct koneplus_device *koneplus;
+ struct usb_device *usb_dev;
+ unsigned long profile;
+ int retval;
+
+ dev = dev->parent->parent;
+ koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = koneplus_set_startup_profile(usb_dev, profile);
+ mutex_unlock(&koneplus->koneplus_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
+}
+
+static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version);
+}
+
+static struct device_attribute koneplus_attributes[] = {
+ __ATTR(startup_profile, 0660,
+ koneplus_sysfs_show_startup_profile,
+ koneplus_sysfs_set_startup_profile),
+ __ATTR(actual_profile, 0440,
+ koneplus_sysfs_show_actual_profile, NULL),
+ __ATTR(firmware_version, 0440,
+ koneplus_sysfs_show_firmware_version, NULL),
+ __ATTR_NULL
+};
+
+static struct bin_attribute koneplus_bin_attributes[] = {
+ {
+ .attr = { .name = "sensor", .mode = 0220 },
+ .size = sizeof(struct koneplus_sensor),
+ .read = koneplus_sysfs_read_sensor,
+ .write = koneplus_sysfs_write_sensor
+ },
+ {
+ .attr = { .name = "tcu", .mode = 0220 },
+ .size = sizeof(struct koneplus_tcu),
+ .write = koneplus_sysfs_write_tcu
+ },
+ {
+ .attr = { .name = "tcu_image", .mode = 0440 },
+ .size = sizeof(struct koneplus_tcu_image),
+ .read = koneplus_sysfs_read_tcu_image
+ },
+ {
+ .attr = { .name = "profile_settings", .mode = 0220 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .write = koneplus_sysfs_write_profile_settings
+ },
+ {
+ .attr = { .name = "profile1_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "profile_buttons", .mode = 0220 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .write = koneplus_sysfs_write_profile_buttons
+ },
+ {
+ .attr = { .name = "profile1_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "macro", .mode = 0220 },
+ .size = sizeof(struct koneplus_macro),
+ .write = koneplus_sysfs_write_macro
+ },
+ __ATTR_NULL
+};
+
+static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
+ struct koneplus_device *koneplus)
+{
+ int retval, i;
+ static uint wait = 70; /* device will freeze with just 60 */
+
+ mutex_init(&koneplus->koneplus_lock);
+
+ koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
+
+ msleep(wait);
+ retval = koneplus_get_info(usb_dev, &koneplus->info);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < 5; ++i) {
+ msleep(wait);
+ retval = koneplus_get_profile_settings(usb_dev,
+ &koneplus->profile_settings[i], i);
+ if (retval)
+ return retval;
+
+ msleep(wait);
+ retval = koneplus_get_profile_buttons(usb_dev,
+ &koneplus->profile_buttons[i], i);
+ if (retval)
+ return retval;
+ }
+
+ koneplus_profile_activated(koneplus, koneplus->startup_profile);
+
+ return 0;
+}
+
+static int koneplus_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct koneplus_device *koneplus;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+ koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
+ if (!koneplus) {
+ dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, koneplus);
+
+ retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
+ if (retval) {
+ dev_err(&hdev->dev,
+ "couldn't init struct koneplus_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(koneplus_class, hdev);
+ if (retval < 0) {
+ dev_err(&hdev->dev, "couldn't init char dev\n");
+ } else {
+ koneplus->chrdev_minor = retval;
+ koneplus->roccat_claimed = 1;
+ }
+ } else {
+ hid_set_drvdata(hdev, NULL);
+ }
+
+ return 0;
+exit_free:
+ kfree(koneplus);
+ return retval;
+}
+
+static void koneplus_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct koneplus_device *koneplus;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+ koneplus = hid_get_drvdata(hdev);
+ if (koneplus->roccat_claimed)
+ roccat_disconnect(koneplus->chrdev_minor);
+ kfree(koneplus);
+ }
+}
+
+static int koneplus_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = koneplus_init_specials(hdev);
+ if (retval) {
+ dev_err(&hdev->dev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void koneplus_remove(struct hid_device *hdev)
+{
+ koneplus_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
+ u8 const *data)
+{
+ struct koneplus_mouse_report_button const *button_report;
+
+ switch (data[0]) {
+ case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
+ button_report = (struct koneplus_mouse_report_button const *)data;
+ switch (button_report->type) {
+ case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
+ koneplus_profile_activated(koneplus, button_report->data1 - 1);
+ break;
+ }
+ break;
+ }
+}
+
+static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
+ u8 const *data)
+{
+ struct koneplus_roccat_report roccat_report;
+ struct koneplus_mouse_report_button const *button_report;
+
+ if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct koneplus_mouse_report_button const *)data;
+
+ if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
+ button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
+ button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
+ return;
+
+ roccat_report.type = button_report->type;
+ roccat_report.data1 = button_report->data1;
+ roccat_report.data2 = button_report->data2;
+ roccat_report.profile = koneplus->actual_profile + 1;
+ roccat_report_event(koneplus->chrdev_minor,
+ (uint8_t const *)&roccat_report,
+ sizeof(struct koneplus_roccat_report));
+}
+
+static int koneplus_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct koneplus_device *koneplus = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ koneplus_keep_values_up_to_date(koneplus, data);
+
+ if (koneplus->roccat_claimed)
+ koneplus_report_to_chrdev(koneplus, data);
+
+ return 0;
+}
+
+static const struct hid_device_id koneplus_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, koneplus_devices);
+
+static struct hid_driver koneplus_driver = {
+ .name = "koneplus",
+ .id_table = koneplus_devices,
+ .probe = koneplus_probe,
+ .remove = koneplus_remove,
+ .raw_event = koneplus_raw_event
+};
+
+static int __init koneplus_init(void)
+{
+ int retval;
+
+ /* class name has to be same as driver name */
+ koneplus_class = class_create(THIS_MODULE, "koneplus");
+ if (IS_ERR(koneplus_class))
+ return PTR_ERR(koneplus_class);
+ koneplus_class->dev_attrs = koneplus_attributes;
+ koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
+
+ retval = hid_register_driver(&koneplus_driver);
+ if (retval)
+ class_destroy(koneplus_class);
+ return retval;
+}
+
+static void __exit koneplus_exit(void)
+{
+ class_destroy(koneplus_class);
+ hid_unregister_driver(&koneplus_driver);
+}
+
+module_init(koneplus_init);
+module_exit(koneplus_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Kone[+] driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h
new file mode 100644
index 000000000000..57a5c1ab7b05
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.h
@@ -0,0 +1,224 @@
+#ifndef __HID_ROCCAT_KONEPLUS_H
+#define __HID_ROCCAT_KONEPLUS_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/types.h>
+
+/*
+ * case 1: writes request 80 and reads value 1
+ *
+ */
+struct koneplus_control {
+ uint8_t command; /* KONEPLUS_COMMAND_CONTROL */
+ /*
+ * value is profile number in range 0-4 for requesting settings and buttons
+ * 1 if status ok for requesting status
+ */
+ uint8_t value;
+ uint8_t request;
+} __attribute__ ((__packed__));
+
+enum koneplus_control_requests {
+ KONEPLUS_CONTROL_REQUEST_STATUS = 0x00,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90,
+};
+
+enum koneplus_control_values {
+ KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0,
+ KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1,
+ KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
+};
+
+struct koneplus_startup_profile {
+ uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
+ uint8_t size; /* always 3 */
+ uint8_t startup_profile; /* Range 0-4! */
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_settings {
+ uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */
+ uint8_t size; /* always 43 */
+ uint8_t number; /* range 0-4 */
+ uint8_t advanced_sensitivity;
+ uint8_t sensitivity_x;
+ uint8_t sensitivity_y;
+ uint8_t cpi_levels_enabled;
+ uint8_t cpi_levels_x[5];
+ uint8_t cpi_startup_level; /* range 0-4 */
+ uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */
+ uint8_t unknown1;
+ uint8_t polling_rate;
+ uint8_t lights_enabled;
+ uint8_t light_effect_mode;
+ uint8_t color_flow_effect;
+ uint8_t light_effect_type;
+ uint8_t light_effect_speed;
+ uint8_t lights[16];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_buttons {
+ uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */
+ uint8_t size; /* always 77 */
+ uint8_t number; /* range 0-4 */
+ uint8_t data[72];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_macro {
+ uint8_t command; /* KONEPLUS_COMMAND_MACRO */
+ uint16_t size; /* always 0x822 little endian */
+ uint8_t profile; /* range 0-4 */
+ uint8_t button; /* range 0-23 */
+ uint8_t data[2075];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_info {
+ uint8_t command; /* KONEPLUS_COMMAND_INFO */
+ uint8_t size; /* always 6 */
+ uint8_t firmware_version;
+ uint8_t unknown[3];
+} __attribute__ ((__packed__));
+
+struct koneplus_e {
+ uint8_t command; /* KONEPLUS_COMMAND_E */
+ uint8_t size; /* always 3 */
+ uint8_t unknown; /* TODO 1; 0 before firmware update */
+} __attribute__ ((__packed__));
+
+struct koneplus_sensor {
+ uint8_t command; /* KONEPLUS_COMMAND_SENSOR */
+ uint8_t size; /* always 6 */
+ uint8_t data[4];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write {
+ uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */
+ uint8_t unknown[1025];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write_control {
+ uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */
+ /*
+ * value is 1 on success
+ * 3 means "not finished yet"
+ */
+ uint8_t value;
+ uint8_t unknown; /* always 0x75 */
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu {
+ uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+ uint8_t data[2];
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu_image {
+ uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+ uint8_t data[1024];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+enum koneplus_commands {
+ KONEPLUS_COMMAND_CONTROL = 0x4,
+ KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
+ KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
+ KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
+ KONEPLUS_COMMAND_MACRO = 0x8,
+ KONEPLUS_COMMAND_INFO = 0x9,
+ KONEPLUS_COMMAND_E = 0xe,
+ KONEPLUS_COMMAND_SENSOR = 0xf,
+ KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b,
+ KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
+};
+
+enum koneplus_usb_commands {
+ KONEPLUS_USB_COMMAND_CONTROL = 0x304,
+ KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
+ KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+ KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+ KONEPLUS_USB_COMMAND_MACRO = 0x308,
+ KONEPLUS_USB_COMMAND_INFO = 0x309,
+ KONEPLUS_USB_COMMAND_TCU = 0x30c,
+ KONEPLUS_USB_COMMAND_E = 0x30e,
+ KONEPLUS_USB_COMMAND_SENSOR = 0x30f,
+ KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b,
+ KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c,
+};
+
+enum koneplus_mouse_report_numbers {
+ KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1,
+ KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
+ KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct koneplus_mouse_report_button {
+ uint8_t report_number; /* always KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON */
+ uint8_t zero1;
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+ uint8_t zero2;
+ uint8_t unknown[2];
+} __attribute__ ((__packed__));
+
+enum koneplus_mouse_report_button_types {
+ /* data1 = new profile range 1-5 */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20,
+
+ /* data1 = button number range 1-24; data2 = action */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+
+ /* data1 = button number range 1-24; data2 = action */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
+
+ /* data1 = setting number range 1-5 */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
+
+ /* data1 and data2 = range 0x1-0xb */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+
+ /* data1 = 22 = next track...
+ * data2 = action
+ */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum koneplus_mouse_report_button_action {
+ KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
+ KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
+};
+
+struct koneplus_roccat_report {
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+ uint8_t profile;
+} __attribute__ ((__packed__));
+
+struct koneplus_device {
+ int actual_profile;
+
+ int roccat_claimed;
+ int chrdev_minor;
+
+ struct mutex koneplus_lock;
+
+ int startup_profile;
+ struct koneplus_info info;
+ struct koneplus_profile_settings profile_settings[5];
+ struct koneplus_profile_buttons profile_buttons[5];
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 9bf23047892a..02c58e015bee 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -27,6 +27,11 @@
#include "hid-roccat.h"
#include "hid-roccat-pyra.h"
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* pyra_class is used for creating sysfs attributes via roccat char device */
+static struct class *pyra_class;
+
static void profile_activated(struct pyra_device *pyra,
unsigned int new_profile)
{
@@ -87,9 +92,8 @@ static int pyra_receive_control_status(struct usb_device *usb_dev)
control.value == 1)
return 0;
else {
- dev_err(&usb_dev->dev, "receive control status: "
- "unknown response 0x%x 0x%x\n",
- control.request, control.value);
+ hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n",
+ control.request, control.value);
return -EINVAL;
}
}
@@ -221,9 +225,10 @@ static int pyra_set_settings(struct usb_device *usb_dev,
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number)
+ loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_settings))
@@ -233,58 +238,19 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
count = sizeof(struct pyra_profile_settings) - off;
mutex_lock(&pyra->pyra_lock);
- memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off,
+ memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&pyra->pyra_lock);
return count;
}
-static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 4);
-}
-
static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number)
+ loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_buttons))
@@ -294,58 +260,19 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
count = sizeof(struct pyra_profile_buttons) - off;
mutex_lock(&pyra->pyra_lock);
- memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off,
+ memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&pyra->pyra_lock);
return count;
}
-static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 4);
-}
-
static ssize_t pyra_sysfs_write_profile_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -381,7 +308,8 @@ static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -417,7 +345,8 @@ static ssize_t pyra_sysfs_read_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_settings))
@@ -437,7 +366,8 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -469,255 +399,125 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
}
static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
}
static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
}
static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
}
-static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
-
-static DEVICE_ATTR(firmware_version, 0440,
- pyra_sysfs_show_firmware_version, NULL);
-
-static DEVICE_ATTR(startup_profile, 0440,
- pyra_sysfs_show_startup_profile, NULL);
-
-static struct attribute *pyra_attributes[] = {
- &dev_attr_actual_cpi.attr,
- &dev_attr_actual_profile.attr,
- &dev_attr_firmware_version.attr,
- &dev_attr_startup_profile.attr,
- NULL
-};
-
-static struct attribute_group pyra_attribute_group = {
- .attrs = pyra_attributes
+static struct device_attribute pyra_attributes[] = {
+ __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
+ __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
+ __ATTR(firmware_version, 0440,
+ pyra_sysfs_show_firmware_version, NULL),
+ __ATTR(startup_profile, 0440,
+ pyra_sysfs_show_startup_profile, NULL),
+ __ATTR_NULL
};
-static struct bin_attribute pyra_profile_settings_attr = {
+static struct bin_attribute pyra_bin_attributes[] = {
+ {
.attr = { .name = "profile_settings", .mode = 0220 },
.size = sizeof(struct pyra_profile_settings),
.write = pyra_sysfs_write_profile_settings
-};
-
-static struct bin_attribute pyra_profile1_settings_attr = {
+ },
+ {
.attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile1_settings
-};
-
-static struct bin_attribute pyra_profile2_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
.attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile2_settings
-};
-
-static struct bin_attribute pyra_profile3_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
.attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile3_settings
-};
-
-static struct bin_attribute pyra_profile4_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
.attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile4_settings
-};
-
-static struct bin_attribute pyra_profile5_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
.attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile5_settings
-};
-
-static struct bin_attribute pyra_profile_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct pyra_profile_buttons),
.write = pyra_sysfs_write_profile_buttons
-};
-
-static struct bin_attribute pyra_profile1_buttons_attr = {
+ },
+ {
.attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile1_buttons
-};
-
-static struct bin_attribute pyra_profile2_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
.attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile2_buttons
-};
-
-static struct bin_attribute pyra_profile3_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
.attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile3_buttons
-};
-
-static struct bin_attribute pyra_profile4_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
.attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile4_buttons
-};
-
-static struct bin_attribute pyra_profile5_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
.attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile5_buttons
-};
-
-static struct bin_attribute pyra_settings_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ {
.attr = { .name = "settings", .mode = 0660 },
.size = sizeof(struct pyra_settings),
.read = pyra_sysfs_read_settings,
.write = pyra_sysfs_write_settings
+ },
+ __ATTR_NULL
};
-static int pyra_create_sysfs_attributes(struct usb_interface *intf)
-{
- int retval;
-
- retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
- if (retval)
- goto exit_1;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile_settings_attr);
- if (retval)
- goto exit_2;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile1_settings_attr);
- if (retval)
- goto exit_3;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile2_settings_attr);
- if (retval)
- goto exit_4;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile3_settings_attr);
- if (retval)
- goto exit_5;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile4_settings_attr);
- if (retval)
- goto exit_6;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile5_settings_attr);
- if (retval)
- goto exit_7;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile_buttons_attr);
- if (retval)
- goto exit_8;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile1_buttons_attr);
- if (retval)
- goto exit_9;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile2_buttons_attr);
- if (retval)
- goto exit_10;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile3_buttons_attr);
- if (retval)
- goto exit_11;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile4_buttons_attr);
- if (retval)
- goto exit_12;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile5_buttons_attr);
- if (retval)
- goto exit_13;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_settings_attr);
- if (retval)
- goto exit_14;
-
- return 0;
-
-exit_14:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
-exit_13:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
-exit_12:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
-exit_11:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
-exit_10:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
-exit_9:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
-exit_8:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
-exit_7:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
-exit_6:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
-exit_5:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
-exit_4:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
-exit_3:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
-exit_2:
- sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-exit_1:
- return retval;
-}
-
-static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
-{
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
- sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-}
-
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra)
{
@@ -770,31 +570,24 @@ static int pyra_init_specials(struct hid_device *hdev)
pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
if (!pyra) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, pyra);
retval = pyra_init_pyra_device_struct(usb_dev, pyra);
if (retval) {
- dev_err(&hdev->dev,
- "couldn't init struct pyra_device\n");
+ hid_err(hdev, "couldn't init struct pyra_device\n");
goto exit_free;
}
- retval = roccat_connect(hdev);
+ retval = roccat_connect(pyra_class, hdev);
if (retval < 0) {
- dev_err(&hdev->dev, "couldn't init char dev\n");
+ hid_err(hdev, "couldn't init char dev\n");
} else {
pyra->chrdev_minor = retval;
pyra->roccat_claimed = 1;
}
-
- retval = pyra_create_sysfs_attributes(intf);
- if (retval) {
- dev_err(&hdev->dev, "cannot create sysfs files\n");
- goto exit_free;
- }
} else {
hid_set_drvdata(hdev, NULL);
}
@@ -812,7 +605,6 @@ static void pyra_remove_specials(struct hid_device *hdev)
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
- pyra_remove_sysfs_attributes(intf);
pyra = hid_get_drvdata(hdev);
if (pyra->roccat_claimed)
roccat_disconnect(pyra->chrdev_minor);
@@ -826,19 +618,19 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
retval = hid_parse(hdev);
if (retval) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = pyra_init_specials(hdev);
if (retval) {
- dev_err(&hdev->dev, "couldn't install mouse\n");
+ hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
return 0;
@@ -952,11 +744,24 @@ static struct hid_driver pyra_driver = {
static int __init pyra_init(void)
{
- return hid_register_driver(&pyra_driver);
+ int retval;
+
+ /* class name has to be same as driver name */
+ pyra_class = class_create(THIS_MODULE, "pyra");
+ if (IS_ERR(pyra_class))
+ return PTR_ERR(pyra_class);
+ pyra_class->dev_attrs = pyra_attributes;
+ pyra_class->dev_bin_attrs = pyra_bin_attributes;
+
+ retval = hid_register_driver(&pyra_driver);
+ if (retval)
+ class_destroy(pyra_class);
+ return retval;
}
static void __exit pyra_exit(void)
{
+ class_destroy(pyra_class);
hid_unregister_driver(&pyra_driver);
}
diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h
index 22f80a8f26f9..14cbbe1621e0 100644
--- a/drivers/hid/hid-roccat-pyra.h
+++ b/drivers/hid/hid-roccat-pyra.h
@@ -14,14 +14,11 @@
#include <linux/types.h>
-#pragma pack(push)
-#pragma pack(1)
-
struct pyra_b {
uint8_t command; /* PYRA_COMMAND_B */
uint8_t size; /* always 3 */
uint8_t unknown; /* 1 */
-};
+} __attribute__ ((__packed__));
struct pyra_control {
uint8_t command; /* PYRA_COMMAND_CONTROL */
@@ -31,7 +28,7 @@ struct pyra_control {
*/
uint8_t value; /* Range 0-4 */
uint8_t request;
-};
+} __attribute__ ((__packed__));
enum pyra_control_requests {
PYRA_CONTROL_REQUEST_STATUS = 0x00,
@@ -43,7 +40,7 @@ struct pyra_settings {
uint8_t command; /* PYRA_COMMAND_SETTINGS */
uint8_t size; /* always 3 */
uint8_t startup_profile; /* Range 0-4! */
-};
+} __attribute__ ((__packed__));
struct pyra_profile_settings {
uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */
@@ -58,7 +55,7 @@ struct pyra_profile_settings {
uint8_t light_effect;
uint8_t handedness;
uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
struct pyra_profile_buttons {
uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
@@ -66,7 +63,7 @@ struct pyra_profile_buttons {
uint8_t number; /* Range 0-4 */
uint8_t buttons[14];
uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
struct pyra_info {
uint8_t command; /* PYRA_COMMAND_INFO */
@@ -75,7 +72,7 @@ struct pyra_info {
uint8_t unknown1; /* always 0 */
uint8_t unknown2; /* always 1 */
uint8_t unknown3; /* always 0 */
-};
+} __attribute__ ((__packed__));
enum pyra_commands {
PYRA_COMMAND_CONTROL = 0x4,
@@ -107,13 +104,13 @@ struct pyra_mouse_event_button {
uint8_t type;
uint8_t data1;
uint8_t data2;
-};
+} __attribute__ ((__packed__));
struct pyra_mouse_event_audio {
uint8_t report_number; /* always 2 */
uint8_t type;
uint8_t unused; /* always 0 */
-};
+} __attribute__ ((__packed__));
/* hid audio controls */
enum pyra_mouse_event_audio_types {
@@ -167,9 +164,7 @@ struct pyra_roccat_report {
uint8_t type;
uint8_t value;
uint8_t key;
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
struct pyra_device {
int actual_profile;
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index 5a6879e235ac..a14c579ea781 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -21,6 +21,8 @@
* It is inspired by hidraw, but uses only one circular buffer for all readers.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/sched.h>
@@ -65,7 +67,6 @@ struct roccat_reader {
};
static int roccat_major;
-static struct class *roccat_class;
static struct cdev roccat_cdev;
static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
@@ -165,27 +166,22 @@ static int roccat_open(struct inode *inode, struct file *file)
mutex_lock(&device->readers_lock);
if (!device) {
- printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
- minor);
+ pr_emerg("roccat device with minor %d doesn't exist\n", minor);
error = -ENODEV;
goto exit_err;
}
if (!device->open++) {
/* power on device on adding first reader */
- if (device->hid->ll_driver->power) {
- error = device->hid->ll_driver->power(device->hid,
- PM_HINT_FULLON);
- if (error < 0) {
- --device->open;
- goto exit_err;
- }
+ error = hid_hw_power(device->hid, PM_HINT_FULLON);
+ if (error < 0) {
+ --device->open;
+ goto exit_err;
}
- error = device->hid->ll_driver->open(device->hid);
+
+ error = hid_hw_open(device->hid);
if (error < 0) {
- if (device->hid->ll_driver->power)
- device->hid->ll_driver->power(device->hid,
- PM_HINT_NORMAL);
+ hid_hw_power(device->hid, PM_HINT_NORMAL);
--device->open;
goto exit_err;
}
@@ -218,8 +214,7 @@ static int roccat_release(struct inode *inode, struct file *file)
device = devices[minor];
if (!device) {
mutex_unlock(&devices_lock);
- printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
- minor);
+ pr_emerg("roccat device with minor %d doesn't exist\n", minor);
return -ENODEV;
}
@@ -231,10 +226,8 @@ static int roccat_release(struct inode *inode, struct file *file)
if (!--device->open) {
/* removing last reader */
if (device->exist) {
- if (device->hid->ll_driver->power)
- device->hid->ll_driver->power(device->hid,
- PM_HINT_NORMAL);
- device->hid->ll_driver->close(device->hid);
+ hid_hw_power(device->hid, PM_HINT_NORMAL);
+ hid_hw_close(device->hid);
} else {
kfree(device);
}
@@ -295,12 +288,14 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
/*
* roccat_connect() - create a char device for special event output
+ * @class: the class thats used to create the device. Meant to hold device
+ * specific sysfs attributes.
* @hid: the hid device the char device should be connected to.
*
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.
*/
-int roccat_connect(struct hid_device *hid)
+int roccat_connect(struct class *klass, struct hid_device *hid)
{
unsigned int minor;
struct roccat_device *device;
@@ -326,7 +321,7 @@ int roccat_connect(struct hid_device *hid)
return -EINVAL;
}
- device->dev = device_create(roccat_class, &hid->dev,
+ device->dev = device_create(klass, &hid->dev,
MKDEV(roccat_major, minor), NULL,
"%s%s%d", "roccat", hid->driver->name, minor);
@@ -367,10 +362,10 @@ void roccat_disconnect(int minor)
device->exist = 0; /* TODO exist maybe not needed */
- device_destroy(roccat_class, MKDEV(roccat_major, minor));
+ device_destroy(device->dev->class, MKDEV(roccat_major, minor));
if (device->open) {
- device->hid->ll_driver->close(device->hid);
+ hid_hw_close(device->hid);
wake_up_interruptible(&device->wait);
} else {
kfree(device);
@@ -398,14 +393,7 @@ static int __init roccat_init(void)
roccat_major = MAJOR(dev_id);
if (retval < 0) {
- printk(KERN_WARNING "roccat: can't get major number\n");
- return retval;
- }
-
- roccat_class = class_create(THIS_MODULE, "roccat");
- if (IS_ERR(roccat_class)) {
- retval = PTR_ERR(roccat_class);
- unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+ pr_warn("can't get major number\n");
return retval;
}
@@ -420,7 +408,6 @@ static void __exit roccat_exit(void)
dev_t dev_id = MKDEV(roccat_major, 0);
cdev_del(&roccat_cdev);
- class_destroy(roccat_class);
unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
}
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
index 09e864e9f79d..5784281d613f 100644
--- a/drivers/hid/hid-roccat.h
+++ b/drivers/hid/hid-roccat.h
@@ -16,11 +16,12 @@
#include <linux/types.h>
#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
-int roccat_connect(struct hid_device *hid);
+int roccat_connect(struct class *klass, struct hid_device *hid);
void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data, int len);
#else
-static inline int roccat_connect(struct hid_device *hid) { return -1; }
+static inline int roccat_connect(struct class *klass,
+ struct hid_device *hid) { return -1; }
static inline void roccat_disconnect(int minor) {}
static inline int roccat_report_event(int minor, u8 const *data, int len)
{
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 35894444e000..3c1fd8af5e0c 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -57,8 +57,8 @@
static inline void samsung_irda_dev_trace(struct hid_device *hdev,
unsigned int rsize)
{
- dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
- "descriptor\n", rsize);
+ hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n",
+ rsize);
}
static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -160,7 +160,7 @@ static int samsung_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -174,7 +174,7 @@ static int samsung_probe(struct hid_device *hdev,
ret = hid_hw_start(hdev, cmask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index e10a7687ebf2..16f7cafc9695 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -74,26 +74,25 @@ static int sjoyff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report_ptr = report_ptr->next;
if (report_ptr == report_list) {
- dev_err(&hid->dev, "required output report is "
- "missing\n");
+ hid_err(hid, "required output report is missing\n");
return -ENODEV;
}
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 3) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -117,8 +116,7 @@ static int sjoyff_init(struct hid_device *hid)
sjoyff->report->field[0]->value[2] = 0x00;
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
- dev_info(&hid->dev,
- "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+ hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
return 0;
}
@@ -135,13 +133,13 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 677bb3da10e8..68d7b36e31e4 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -40,8 +40,7 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
*rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
- dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
- "descriptor\n");
+ hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
rdesc[55] = 0x06;
}
return rdesc;
@@ -89,7 +88,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
(3 << 8) | 0xf2, ifnum, buf, 17,
USB_CTRL_GET_TIMEOUT);
if (ret < 0)
- dev_err(&hdev->dev, "can't set operational mode\n");
+ hid_err(hdev, "can't set operational mode\n");
kfree(buf);
@@ -110,7 +109,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
sc = kzalloc(sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
- dev_err(&hdev->dev, "can't alloc sony descriptor\n");
+ hid_err(hdev, "can't alloc sony descriptor\n");
return -ENOMEM;
}
@@ -119,14 +118,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
HID_CONNECT_HIDDEV_FORCE);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
index 3171be28c3d5..b2be1d11916b 100644
--- a/drivers/hid/hid-stantum.c
+++ b/drivers/hid/hid-stantum.c
@@ -222,7 +222,7 @@ static int stantum_probe(struct hid_device *hdev,
sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
if (!sd) {
- dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+ hid_err(hdev, "cannot allocate Stantum data\n");
return -ENOMEM;
}
sd->valid = false;
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index 164ed568f6cf..d484a0043dd4 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -27,8 +27,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
{
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
rdesc[106] == 0x03) {
- dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
- "report descriptor\n");
+ hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
rdesc[105] = rdesc[110] = 0x03;
rdesc[106] = rdesc[111] = 0x21;
}
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index 15434c814793..575862b0688e 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -151,28 +151,23 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
switch (field->usage[0].hid) {
case THRUSTMASTER_USAGE_FF:
if (field->report_count < 2) {
- dev_warn(&hid->dev, "ignoring FF field "
- "with report_count < 2\n");
+ hid_warn(hid, "ignoring FF field with report_count < 2\n");
continue;
}
if (field->logical_maximum ==
field->logical_minimum) {
- dev_warn(&hid->dev, "ignoring FF field "
- "with logical_maximum "
- "== logical_minimum\n");
+ hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n");
continue;
}
if (tmff->report && tmff->report != report) {
- dev_warn(&hid->dev, "ignoring FF field "
- "in other report\n");
+ hid_warn(hid, "ignoring FF field in other report\n");
continue;
}
if (tmff->ff_field && tmff->ff_field != field) {
- dev_warn(&hid->dev, "ignoring "
- "duplicate FF field\n");
+ hid_warn(hid, "ignoring duplicate FF field\n");
continue;
}
@@ -185,16 +180,15 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
break;
default:
- dev_warn(&hid->dev, "ignoring unknown output "
- "usage %08x\n",
- field->usage[0].hid);
+ hid_warn(hid, "ignoring unknown output usage %08x\n",
+ field->usage[0].hid);
continue;
}
}
}
if (!tmff->report) {
- dev_err(&hid->dev, "can't find FF field in output reports\n");
+ hid_err(hid, "can't find FF field in output reports\n");
error = -ENODEV;
goto fail;
}
@@ -203,8 +197,7 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
if (error)
goto fail;
- dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
- "Verituse <zinx@epicsol.org>");
+ hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>\n");
return 0;
fail:
@@ -224,13 +217,13 @@ static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
@@ -256,6 +249,8 @@ static const struct hid_device_id tm_devices[] = {
.driver_data = (unsigned long)ff_joystick },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */
.driver_data = (unsigned long)ff_joystick },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a), /* F430 Force Feedback Wheel */
+ .driver_data = (unsigned long)ff_joystick },
{ }
};
MODULE_DEVICE_TABLE(hid, tm_devices);
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 956ed9ac19d4..613ff7b1d746 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -66,6 +66,7 @@ static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ }
};
MODULE_DEVICE_TABLE(hid, ts_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 724f46ed612f..06888323828c 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -18,6 +18,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -141,8 +143,8 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
* Note that if the raw queries fail, it's not a hard failure and it
* is safe to continue
*/
- dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n",
- rep_data[0], ret);
+ hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+ rep_data[0], ret);
return;
}
@@ -172,7 +174,7 @@ static ssize_t wacom_store_speed(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
wacom_show_speed, wacom_store_speed);
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -312,7 +314,7 @@ static int wacom_probe(struct hid_device *hdev,
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (wdata == NULL) {
- dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ hid_err(hdev, "can't alloc wacom descriptor\n");
return -ENOMEM;
}
@@ -321,20 +323,20 @@ static int wacom_probe(struct hid_device *hdev,
/* Parse the HID report now */
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
ret = device_create_file(&hdev->dev, &dev_attr_speed);
if (ret)
- dev_warn(&hdev->dev,
- "can't create sysfs speed attribute err: %d\n", ret);
+ hid_warn(hdev,
+ "can't create sysfs speed attribute err: %d\n", ret);
/* Set Wacom mode 2 with high reporting speed */
wacom_poke(hdev, 1);
@@ -349,8 +351,8 @@ static int wacom_probe(struct hid_device *hdev,
ret = power_supply_register(&hdev->dev, &wdata->battery);
if (ret) {
- dev_warn(&hdev->dev,
- "can't create sysfs battery attribute, err: %d\n", ret);
+ hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
+ ret);
/*
* battery attribute is not critical for the tablet, but if it
* failed then there is no need to create ac attribute
@@ -367,8 +369,8 @@ static int wacom_probe(struct hid_device *hdev,
ret = power_supply_register(&hdev->dev, &wdata->ac);
if (ret) {
- dev_warn(&hdev->dev,
- "can't create ac battery attribute, err: %d\n", ret);
+ hid_warn(hdev,
+ "can't create ac battery attribute, err: %d\n", ret);
/*
* ac attribute is not critical for the tablet, but if it
* failed then we don't want to battery attribute to exist
@@ -454,7 +456,7 @@ static int __init wacom_init(void)
ret = hid_register_driver(&wacom_driver);
if (ret)
- printk(KERN_ERR "can't register wacom driver\n");
+ pr_err("can't register wacom driver\n");
return ret;
}
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index b7acceabba80..f31fab012f2f 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -75,14 +75,14 @@ static int zpff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output report found\n");
+ hid_err(hid, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 4) {
- dev_err(&hid->dev, "not enough fields in report\n");
+ hid_err(hid, "not enough fields in report\n");
return -ENODEV;
}
@@ -105,8 +105,7 @@ static int zpff_init(struct hid_device *hid)
zpff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
@@ -123,13 +122,13 @@ static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index aac1f9273149..e90371508fd2 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -34,9 +34,8 @@ static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
- dev_info(&hdev->dev,
- "fixing up zydacron remote control report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up zydacron remote control report descriptor\n");
rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
}
@@ -172,7 +171,7 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
zc = kzalloc(sizeof(*zc), GFP_KERNEL);
if (zc == NULL) {
- dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
}
@@ -180,13 +179,13 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "zydacron: parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "zydacron: hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 8a4b32dca9f7..468e87b53ed2 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -19,6 +19,8 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -32,7 +34,6 @@
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/hidraw.h>
@@ -123,15 +124,15 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
}
if (count > HID_MAX_BUFFER_SIZE) {
- printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
- task_pid_nr(current));
+ hid_warn(dev, "pid %d passed too large report\n",
+ task_pid_nr(current));
ret = -EINVAL;
goto out;
}
if (count < 2) {
- printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
- task_pid_nr(current));
+ hid_warn(dev, "pid %d passed too short report\n",
+ task_pid_nr(current));
ret = -EINVAL;
goto out;
}
@@ -193,15 +194,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
dev = hidraw_table[minor];
if (!dev->open++) {
- if (dev->hid->ll_driver->power) {
- err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
- if (err < 0)
- goto out_unlock;
- }
- err = dev->hid->ll_driver->open(dev->hid);
+ err = hid_hw_power(dev->hid, PM_HINT_FULLON);
+ if (err < 0)
+ goto out_unlock;
+
+ err = hid_hw_open(dev->hid);
if (err < 0) {
- if (dev->hid->ll_driver->power)
- dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
+ hid_hw_power(dev->hid, PM_HINT_NORMAL);
dev->open--;
}
}
@@ -230,9 +229,8 @@ static int hidraw_release(struct inode * inode, struct file * file)
dev = hidraw_table[minor];
if (!--dev->open) {
if (list->hidraw->exist) {
- if (dev->hid->ll_driver->power)
- dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
- dev->hid->ll_driver->close(dev->hid);
+ hid_hw_power(dev->hid, PM_HINT_NORMAL);
+ hid_hw_close(dev->hid);
} else {
kfree(list->hidraw);
}
@@ -346,6 +344,9 @@ static const struct file_operations hidraw_ops = {
.open = hidraw_open,
.release = hidraw_release,
.unlocked_ioctl = hidraw_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hidraw_ioctl,
+#endif
.llseek = noop_llseek,
};
@@ -434,7 +435,7 @@ void hidraw_disconnect(struct hid_device *hid)
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
if (hidraw->open) {
- hid->ll_driver->close(hid);
+ hid_hw_close(hid);
wake_up_interruptible(&hidraw->wait);
} else {
kfree(hidraw);
@@ -453,7 +454,7 @@ int __init hidraw_init(void)
hidraw_major = MAJOR(dev_id);
if (result < 0) {
- printk(KERN_WARNING "hidraw: can't get major number\n");
+ pr_warn("can't get major number\n");
result = 0;
goto out;
}
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 1329ecb37a1c..db3cf31c6fa1 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -3,15 +3,15 @@
#
# Multipart objects.
-usbhid-objs := hid-core.o hid-quirks.o
+usbhid-y := hid-core.o hid-quirks.o
# Optional parts of multipart objects.
ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-objs += hiddev.o
+ usbhid-y += hiddev.o
endif
ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += hid-pidff.o
+ usbhid-y += hid-pidff.o
endif
obj-$(CONFIG_USB_HID) += usbhid.o
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5489eab3a6bd..b336dd84036f 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -67,7 +67,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
* Input submission and I/O error handler.
*/
static DEFINE_MUTEX(hid_open_mut);
-static struct workqueue_struct *resumption_waker;
static void hid_io_error(struct hid_device *hid);
static int hid_submit_out(struct hid_device *hid);
@@ -136,10 +135,10 @@ static void hid_reset(struct work_struct *work)
hid_io_error(hid);
break;
default:
- err_hid("can't reset device, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, rc);
+ hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
@@ -278,18 +277,18 @@ static void hid_irq_in(struct urb *urb)
hid_io_error(hid);
return;
default: /* error */
- dev_warn(&urb->dev->dev, "input irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "input irq status %d received\n",
+ urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
- err_hid("can't resubmit intr, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, status);
+ hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, status);
hid_io_error(hid);
}
}
@@ -300,10 +299,19 @@ static int hid_submit_out(struct hid_device *hid)
struct hid_report *report;
char *raw_report;
struct usbhid_device *usbhid = hid->driver_data;
+ int r;
report = usbhid->out[usbhid->outtail].report;
raw_report = usbhid->out[usbhid->outtail].raw_report;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
+
+ /*
+ * if the device hasn't been woken, we leave the output
+ * to resume()
+ */
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
@@ -313,17 +321,11 @@ static int hid_submit_out(struct hid_device *hid)
dbg_hid("submitting out urb\n");
if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(out) failed");
+ hid_err(hid, "usb_submit_urb(out) failed\n");
+ usb_autopm_put_interface_async(usbhid->intf);
return -1;
}
usbhid->last_out = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
@@ -334,13 +336,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
struct hid_report *report;
unsigned char dir;
char *raw_report;
- int len;
+ int len, r;
struct usbhid_device *usbhid = hid->driver_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
dir = usbhid->ctrl[usbhid->ctrltail].dir;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
@@ -375,17 +380,11 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(ctrl) failed");
+ usb_autopm_put_interface_async(usbhid->intf);
+ hid_err(hid, "usb_submit_urb(ctrl) failed\n");
return -1;
}
usbhid->last_ctrl = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
@@ -413,8 +412,8 @@ static void hid_irq_out(struct urb *urb)
case -ENOENT:
break;
default: /* error */
- dev_warn(&urb->dev->dev, "output irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "output irq status %d received\n",
+ urb->status);
}
spin_lock_irqsave(&usbhid->lock, flags);
@@ -435,6 +434,7 @@ static void hid_irq_out(struct urb *urb)
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
spin_unlock_irqrestore(&usbhid->lock, flags);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
@@ -466,8 +466,7 @@ static void hid_ctrl(struct urb *urb)
case -EPIPE: /* report not available */
break;
default: /* error */
- dev_warn(&urb->dev->dev, "ctrl urb status %d "
- "received\n", status);
+ hid_warn(urb->dev, "ctrl urb status %d received\n", status);
}
if (unplug)
@@ -481,11 +480,13 @@ static void hid_ctrl(struct urb *urb)
wake_up(&usbhid->wait);
}
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
return;
}
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
@@ -501,13 +502,13 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
- dev_warn(&hid->dev, "output queue full\n");
+ hid_warn(hid, "output queue full\n");
return;
}
usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
- dev_warn(&hid->dev, "output queueing failed\n");
+ hid_warn(hid, "output queueing failed\n");
return;
}
hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
@@ -532,14 +533,14 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
}
if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
- dev_warn(&hid->dev, "control queue full\n");
+ hid_warn(hid, "control queue full\n");
return;
}
if (dir == USB_DIR_OUT) {
usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
- dev_warn(&hid->dev, "control queueing failed\n");
+ hid_warn(hid, "control queueing failed\n");
return;
}
hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
@@ -590,7 +591,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return -1;
if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- dev_warn(&dev->dev, "event field not found\n");
+ hid_warn(dev, "event field not found\n");
return -1;
}
@@ -656,7 +657,7 @@ int usbhid_open(struct hid_device *hid)
mutex_lock(&hid_open_mut);
if (!hid->open++) {
res = usb_autopm_get_interface(usbhid->intf);
- /* the device must be awake to reliable request remote wakeup */
+ /* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
mutex_unlock(&hid_open_mut);
@@ -722,7 +723,7 @@ void usbhid_init_reports(struct hid_device *hid)
}
if (err)
- dev_warn(&hid->dev, "timeout initializing reports\n");
+ hid_warn(hid, "timeout initializing reports\n");
}
/*
@@ -857,18 +858,6 @@ static void usbhid_restart_queues(struct usbhid_device *usbhid)
usbhid_restart_ctrl_queue(usbhid);
}
-static void __usbhid_restart_queues(struct work_struct *work)
-{
- struct usbhid_device *usbhid =
- container_of(work, struct usbhid_device, restart_work);
- int r;
-
- r = usb_autopm_get_interface(usbhid->intf);
- if (r < 0)
- return;
- usb_autopm_put_interface(usbhid->intf);
-}
-
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -1140,8 +1129,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
has_in++;
if (!has_in) {
- dev_err(&intf->dev, "couldn't find an input interrupt "
- "endpoint\n");
+ hid_err(intf, "couldn't find an input interrupt endpoint\n");
return -ENODEV;
}
@@ -1206,14 +1194,13 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
init_waitqueue_head(&usbhid->wait);
INIT_WORK(&usbhid->reset_work, hid_reset);
- INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
- dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+ hid_err(intf, "can't add hid device: %d\n", ret);
goto err_free;
}
@@ -1241,7 +1228,6 @@ static void usbhid_disconnect(struct usb_interface *intf)
static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
{
del_timer_sync(&usbhid->io_retry);
- cancel_work_sync(&usbhid->restart_work);
cancel_work_sync(&usbhid->reset_work);
}
@@ -1262,7 +1248,6 @@ static int hid_pre_reset(struct usb_interface *intf)
spin_lock_irq(&usbhid->lock);
set_bit(HID_RESET_PENDING, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
- cancel_work_sync(&usbhid->restart_work);
hid_cease_io(usbhid);
return 0;
@@ -1461,9 +1446,6 @@ static int __init hid_init(void)
{
int retval = -ENOMEM;
- resumption_waker = create_freezeable_workqueue("usbhid_resumer");
- if (!resumption_waker)
- goto no_queue;
retval = hid_register_driver(&hid_usb_driver);
if (retval)
goto hid_register_fail;
@@ -1481,8 +1463,6 @@ usb_register_fail:
usbhid_quirks_init_fail:
hid_unregister_driver(&hid_usb_driver);
hid_register_fail:
- destroy_workqueue(resumption_waker);
-no_queue:
return retval;
}
@@ -1491,7 +1471,6 @@ static void __exit hid_exit(void)
usb_deregister(&hid_driver);
usbhid_quirks_exit();
hid_unregister_driver(&hid_usb_driver);
- destroy_workqueue(resumption_waker);
}
module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index ef381d79cfa8..f91c136821f7 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -22,7 +22,7 @@
/* #define DEBUG */
-#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
#include <linux/slab.h>
@@ -220,7 +220,7 @@ static int pidff_rescale_signed(int i, struct hid_field *field)
static void pidff_set(struct pidff_usage *usage, u16 value)
{
usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
static void pidff_set_signed(struct pidff_usage *usage, s16 value)
@@ -235,7 +235,7 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
usage->value[0] =
pidff_rescale(value, 0x7fff, usage->field);
}
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
/*
@@ -259,8 +259,9 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
- debug("attack %u => %d", envelope->attack_level,
- pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+ hid_dbg(pidff->hid, "attack %u => %d\n",
+ envelope->attack_level,
+ pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT);
@@ -466,33 +467,33 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
pidff->create_new_effect_type->value[0] = efnum;
usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
USB_DIR_OUT);
- debug("create_new_effect sent, type: %d", efnum);
+ hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0;
usbhid_wait_io(pidff->hid);
for (j = 0; j < 60; j++) {
- debug("pid_block_load requested");
+ hid_dbg(pidff->hid, "pid_block_load requested\n");
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
USB_DIR_IN);
usbhid_wait_io(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
- debug("device reported free memory: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+ hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return 0;
}
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_FULL]) {
- debug("not enough memory free: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ hid_dbg(pidff->hid, "not enough memory free: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return -ENOSPC;
}
}
- printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+ hid_err(pidff->hid, "pid_block_load failed 60 times\n");
return -EIO;
}
@@ -546,7 +547,8 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
struct pidff_device *pidff = dev->ff->private;
int pid_id = pidff->pid_id[effect_id];
- debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+ hid_dbg(pidff->hid, "starting to erase %d/%d\n",
+ effect_id, pidff->pid_id[effect_id]);
/* Wait for the queue to clear. We do not want a full fifo to
prevent the effect removal. */
usbhid_wait_io(pidff->hid);
@@ -604,8 +606,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
type_id = PID_SAW_DOWN;
break;
default:
- printk(KERN_ERR
- "hid-pidff: invalid waveform\n");
+ hid_err(pidff->hid, "invalid waveform\n");
return -EINVAL;
}
@@ -696,7 +697,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
break;
default:
- printk(KERN_ERR "hid-pidff: invalid type\n");
+ hid_err(pidff->hid, "invalid type\n");
return -EINVAL;
}
@@ -704,7 +705,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff->pid_id[effect->id] =
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
- debug("uploaded");
+ hid_dbg(pidff->hid, "uploaded\n");
return 0;
}
@@ -770,14 +771,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
for (i = 0; i < report->maxfield; i++) {
if (report->field[i]->maxusage !=
report->field[i]->report_count) {
- debug("maxusage and report_count do not match, "
- "skipping");
+ pr_debug("maxusage and report_count do not match, skipping\n");
continue;
}
for (j = 0; j < report->field[i]->maxusage; j++) {
if (report->field[i]->usage[j].hid ==
(HID_UP_PID | table[k])) {
- debug("found %d at %d->%d", k, i, j);
+ pr_debug("found %d at %d->%d\n",
+ k, i, j);
usage[k].field = report->field[i];
usage[k].value =
&report->field[i]->value[j];
@@ -789,7 +790,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
break;
}
if (!found && strict) {
- debug("failed to locate %d", k);
+ pr_debug("failed to locate %d\n", k);
return -1;
}
}
@@ -826,8 +827,8 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(report->field[0]->logical);
if (ret != -1) {
- debug("found usage 0x%02x from field->logical",
- pidff_reports[ret]);
+ hid_dbg(hid, "found usage 0x%02x from field->logical\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
continue;
}
@@ -845,8 +846,9 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(hid->collection[i - 1].usage);
if (ret != -1 && !pidff->reports[ret]) {
- debug("found usage 0x%02x from collection array",
- pidff_reports[ret]);
+ hid_dbg(hid,
+ "found usage 0x%02x from collection array\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
}
}
@@ -861,7 +863,7 @@ static int pidff_reports_ok(struct pidff_device *pidff)
for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
if (!pidff->reports[i]) {
- debug("%d missing", i);
+ hid_dbg(pidff->hid, "%d missing\n", i);
return 0;
}
}
@@ -884,8 +886,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
report->field[i]->logical_minimum == 1)
return report->field[i];
else {
- printk(KERN_ERR "hid-pidff: logical_minimum "
- "is not 1 as it should be\n");
+ pr_err("logical_minimum is not 1 as it should be\n");
return NULL;
}
}
@@ -924,7 +925,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld,
*/
static int pidff_find_special_fields(struct pidff_device *pidff)
{
- debug("finding special fields");
+ hid_dbg(pidff->hid, "finding special fields\n");
pidff->create_new_effect_type =
pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
@@ -945,32 +946,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
0x78, 1);
- debug("search done");
+ hid_dbg(pidff->hid, "search done\n");
if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
- printk(KERN_ERR "hid-pidff: effect lists not found\n");
+ hid_err(pidff->hid, "effect lists not found\n");
return -1;
}
if (!pidff->effect_direction) {
- printk(KERN_ERR "hid-pidff: direction field not found\n");
+ hid_err(pidff->hid, "direction field not found\n");
return -1;
}
if (!pidff->device_control) {
- printk(KERN_ERR "hid-pidff: device control field not found\n");
+ hid_err(pidff->hid, "device control field not found\n");
return -1;
}
if (!pidff->block_load_status) {
- printk(KERN_ERR
- "hid-pidff: block load status field not found\n");
+ hid_err(pidff->hid, "block load status field not found\n");
return -1;
}
if (!pidff->effect_operation_status) {
- printk(KERN_ERR
- "hid-pidff: effect operation field not found\n");
+ hid_err(pidff->hid, "effect operation field not found\n");
return -1;
}
@@ -982,23 +981,22 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
effect_types)) {
- printk(KERN_ERR "hid-pidff: no effect types found\n");
+ hid_err(pidff->hid, "no effect types found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
block_load_status) !=
sizeof(pidff_block_load_status)) {
- printk(KERN_ERR
- "hidpidff: block load status identifiers not found\n");
+ hid_err(pidff->hid,
+ "block load status identifiers not found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
effect_operation_status) !=
sizeof(pidff_effect_operation_status)) {
- printk(KERN_ERR
- "hidpidff: effect operation identifiers not found\n");
+ hid_err(pidff->hid, "effect operation identifiers not found\n");
return -1;
}
@@ -1017,8 +1015,8 @@ static int pidff_find_effects(struct pidff_device *pidff,
int pidff_type = pidff->type_id[i];
if (pidff->set_effect_type->usage[pidff_type].hid !=
pidff->create_new_effect_type->usage[pidff_type].hid) {
- printk(KERN_ERR "hid-pidff: "
- "effect type number %d is invalid\n", i);
+ hid_err(pidff->hid,
+ "effect type number %d is invalid\n", i);
return -1;
}
}
@@ -1073,27 +1071,23 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
int envelope_ok = 0;
if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown set_effect report layout\n");
+ hid_err(pidff->hid, "unknown set_effect report layout\n");
return -ENODEV;
}
PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_load report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_load report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown effect_operation report layout\n");
+ hid_err(pidff->hid, "unknown effect_operation report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_free report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_free report layout\n");
return -ENODEV;
}
@@ -1105,27 +1099,26 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (!envelope_ok) {
if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has constant effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has constant effect but no envelope\n");
if (test_and_clear_bit(FF_RAMP, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has ramp effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has ramp effect but no envelope\n");
if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has periodic effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has periodic effect but no envelope\n");
}
if (test_bit(FF_CONSTANT, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown constant effect layout\n");
+ hid_warn(pidff->hid, "unknown constant effect layout\n");
clear_bit(FF_CONSTANT, dev->ffbit);
}
if (test_bit(FF_RAMP, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
- printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+ hid_warn(pidff->hid, "unknown ramp effect layout\n");
clear_bit(FF_RAMP, dev->ffbit);
}
@@ -1134,8 +1127,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
test_bit(FF_FRICTION, dev->ffbit) ||
test_bit(FF_INERTIA, dev->ffbit)) &&
PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown condition effect layout\n");
+ hid_warn(pidff->hid, "unknown condition effect layout\n");
clear_bit(FF_SPRING, dev->ffbit);
clear_bit(FF_DAMPER, dev->ffbit);
clear_bit(FF_FRICTION, dev->ffbit);
@@ -1144,8 +1136,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (test_bit(FF_PERIODIC, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown periodic effect layout\n");
+ hid_warn(pidff->hid, "unknown periodic effect layout\n");
clear_bit(FF_PERIODIC, dev->ffbit);
}
@@ -1184,12 +1175,12 @@ static void pidff_reset(struct pidff_device *pidff)
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
if (i++ > 20) {
- printk(KERN_WARNING "hid-pidff: device reports "
- "%d simultaneous effects\n",
- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+ hid_warn(pidff->hid,
+ "device reports %d simultaneous effects\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
break;
}
- debug("pid_pool requested again");
+ hid_dbg(pidff->hid, "pid_pool requested again\n");
usbhid_submit_report(hid, pidff->reports[PID_POOL],
USB_DIR_IN);
usbhid_wait_io(hid);
@@ -1215,7 +1206,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
error = pidff_request_effect_upload(pidff, 1);
if (error) {
- printk(KERN_ERR "hid-pidff: upload request failed\n");
+ hid_err(pidff->hid, "upload request failed\n");
return error;
}
@@ -1224,8 +1215,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
pidff_autocenter(pidff, 0xffff);
set_bit(FF_AUTOCENTER, dev->ffbit);
} else {
- printk(KERN_NOTICE "hid-pidff: "
- "device has unknown autocenter control method\n");
+ hid_notice(pidff->hid,
+ "device has unknown autocenter control method\n");
}
pidff_erase_pid(pidff,
@@ -1248,10 +1239,10 @@ int hid_pidff_init(struct hid_device *hid)
int max_effects;
int error;
- debug("starting pid init");
+ hid_dbg(hid, "starting pid init\n");
if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
- debug("not a PID device, no output report");
+ hid_dbg(hid, "not a PID device, no output report\n");
return -ENODEV;
}
@@ -1265,7 +1256,7 @@ int hid_pidff_init(struct hid_device *hid)
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
if (!pidff_reports_ok(pidff)) {
- debug("reports not ok, aborting");
+ hid_dbg(hid, "reports not ok, aborting\n");
error = -ENODEV;
goto fail;
}
@@ -1278,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN],
+ USB_DIR_OUT);
}
error = pidff_check_autocenter(pidff, dev);
@@ -1290,23 +1281,23 @@ int hid_pidff_init(struct hid_device *hid)
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
1;
- debug("max effects is %d", max_effects);
+ hid_dbg(hid, "max effects is %d\n", max_effects);
if (max_effects > PID_EFFECTS_MAX)
max_effects = PID_EFFECTS_MAX;
if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
- debug("max simultaneous effects is %d",
- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+ hid_dbg(hid, "max simultaneous effects is %d\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
if (pidff->pool[PID_RAM_POOL_SIZE].value)
- debug("device memory size is %d bytes",
- pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+ hid_dbg(hid, "device memory size is %d bytes\n",
+ pidff->pool[PID_RAM_POOL_SIZE].value[0]);
if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
- printk(KERN_NOTICE "hid-pidff: "
- "device does not support device managed pool\n");
+ hid_notice(hid,
+ "device does not support device managed pool\n");
goto fail;
}
@@ -1322,8 +1313,7 @@ int hid_pidff_init(struct hid_device *hid)
ff->set_autocenter = pidff_set_autocenter;
ff->playback = pidff_playback;
- printk(KERN_INFO "Force feedback for USB HID PID devices by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 2c185477eeb3..9a94b643ccde 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -35,7 +35,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -85,7 +84,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
-
+ { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index fedd88df9a18..af0a7c1002af 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
@@ -586,163 +585,168 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct hiddev_list *list = file->private_data;
struct hiddev *hiddev = list->hiddev;
- struct hid_device *hid = hiddev->hid;
- struct usb_device *dev;
+ struct hid_device *hid;
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
- struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
- int i, r;
-
+ int i, r = -EINVAL;
+
/* Called without BKL by compat methods so no BKL taken */
- /* FIXME: Who or what stop this racing with a disconnect ?? */
- if (!hiddev->exist || !hid)
- return -EIO;
+ mutex_lock(&hiddev->existancelock);
+ if (!hiddev->exist) {
+ r = -ENODEV;
+ goto ret_unlock;
+ }
- dev = hid_to_usb_dev(hid);
+ hid = hiddev->hid;
switch (cmd) {
case HIDIOCGVERSION:
- return put_user(HID_VERSION, (int __user *)arg);
+ r = put_user(HID_VERSION, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCAPPLICATION:
if (arg < 0 || arg >= hid->maxapplication)
- return -EINVAL;
+ break;
for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && arg-- == 0)
break;
- if (i == hid->maxcollection)
- return -EINVAL;
-
- return hid->collection[i].usage;
+ if (i < hid->maxcollection)
+ r = hid->collection[i].usage;
+ break;
case HIDIOCGDEVINFO:
- dinfo.bustype = BUS_USB;
- dinfo.busnum = dev->bus->busnum;
- dinfo.devnum = dev->devnum;
- dinfo.ifnum = usbhid->ifnum;
- dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
- dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
- dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
- dinfo.num_applications = hid->maxapplication;
- if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
- return -EFAULT;
-
- return 0;
+ {
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ dinfo.bustype = BUS_USB;
+ dinfo.busnum = dev->bus->busnum;
+ dinfo.devnum = dev->devnum;
+ dinfo.ifnum = usbhid->ifnum;
+ dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+ dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+ dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+ dinfo.num_applications = hid->maxapplication;
+
+ r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
+ -EFAULT : 0;
+ break;
+ }
case HIDIOCGFLAG:
- if (put_user(list->flags, (int __user *)arg))
- return -EFAULT;
-
- return 0;
+ r = put_user(list->flags, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCSFLAG:
{
int newflags;
- if (get_user(newflags, (int __user *)arg))
- return -EFAULT;
+
+ if (get_user(newflags, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
if ((newflags & ~HIDDEV_FLAGS) != 0 ||
((newflags & HIDDEV_FLAG_REPORT) != 0 &&
(newflags & HIDDEV_FLAG_UREF) == 0))
- return -EINVAL;
+ break;
list->flags = newflags;
- return 0;
+ r = 0;
+ break;
}
case HIDIOCGSTRING:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_string(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_string(hiddev, cmd, user_arg);
+ break;
case HIDIOCINITREPORT:
- mutex_lock(&hiddev->existancelock);
- if (!hiddev->exist) {
- mutex_unlock(&hiddev->existancelock);
- return -ENODEV;
- }
usbhid_init_reports(hid);
- mutex_unlock(&hiddev->existancelock);
-
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_IN);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_wait_io(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCSREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_OUT);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_wait_io(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORTINFO:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
rinfo.num_fields = report->maxfield;
- if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGFIELDINFO:
- if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
- return -EFAULT;
+ if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
+ r = -EFAULT;
+ break;
+ }
+
rinfo.report_type = finfo.report_type;
rinfo.report_id = finfo.report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
if (finfo.field_index >= report->maxfield)
- return -EINVAL;
+ break;
field = report->field[finfo.field_index];
memset(&finfo, 0, sizeof(finfo));
@@ -761,10 +765,9 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
finfo.unit_exponent = field->unit_exponent;
finfo.unit = field->unit;
- if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGUCODE:
/* fall through */
@@ -773,57 +776,66 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
+ break;
case HIDIOCGCOLLECTIONINFO:
- if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
- return -EFAULT;
+ if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (cinfo.index >= hid->maxcollection)
- return -EINVAL;
+ break;
cinfo.type = hid->collection[cinfo.index].type;
cinfo.usage = hid->collection[cinfo.index].usage;
cinfo.level = hid->collection[cinfo.index].level;
- if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
+ r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
+ -EFAULT : 0;
+ break;
default:
-
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
- return -EINVAL;
+ break;
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
int len;
- if (!hid->name)
- return 0;
+
+ if (!hid->name) {
+ r = 0;
+ break;
+ }
+
len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->name, len) ?
+ r = copy_to_user(user_arg, hid->name, len) ?
-EFAULT : len;
+ break;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
int len;
- if (!hid->phys)
- return 0;
+
+ if (!hid->phys) {
+ r = 0;
+ break;
+ }
+
len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->phys, len) ?
+ r = copy_to_user(user_arg, hid->phys, len) ?
-EFAULT : len;
+ break;
}
}
- return -EINVAL;
+
+ret_unlock:
+ mutex_unlock(&hiddev->existancelock);
+ return r;
}
#ifdef CONFIG_COMPAT
@@ -893,7 +905,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
hiddev->exist = 1;
retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
- err_hid("Not able to get a minor for this device.");
+ hid_err(hid, "Not able to get a minor for this device\n");
hid->hiddev = NULL;
kfree(hiddev);
return -1;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 89d2e847dcc6..1673cac93d77 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -95,7 +95,6 @@ struct usbhid_device {
unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */
struct work_struct reset_work; /* Task context for resets */
- struct work_struct restart_work; /* waking up for output to be done in a task */
wait_queue_head_t wait; /* For sleeping */
int ledcount; /* counting the number of active leds */
};
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index a948605564fb..065817329f03 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -24,6 +24,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -104,16 +106,18 @@ static void usb_kbd_irq(struct urb *urb)
if (usb_kbd_keycode[kbd->old[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->old[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) released.\n",
+ kbd->old[i]);
}
if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
if (usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->new[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) released.\n",
+ kbd->new[i]);
}
}
@@ -124,9 +128,9 @@ static void usb_kbd_irq(struct urb *urb)
resubmit:
i = usb_submit_urb (urb, GFP_ATOMIC);
if (i)
- err_hid ("can't resubmit intr, %s-%s/input0, status %d",
- kbd->usbdev->bus->bus_name,
- kbd->usbdev->devpath, i);
+ hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
+ kbd->usbdev->bus->bus_name,
+ kbd->usbdev->devpath, i);
}
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
@@ -150,7 +154,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
+ pr_err("usb_submit_urb(leds) failed\n");
return 0;
}
@@ -160,7 +164,7 @@ static void usb_kbd_led(struct urb *urb)
struct usb_kbd *kbd = urb->context;
if (urb->status)
- dev_warn(&urb->dev->dev, "led urb status %d received\n",
+ hid_warn(urb->dev, "led urb status %d received\n",
urb->status);
if (*(kbd->leds) == kbd->newleds)
@@ -169,7 +173,7 @@ static void usb_kbd_led(struct urb *urb)
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
+ hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
}
static int usb_kbd_open(struct input_dev *dev)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a56f6adf3b76..35f00dae3676 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -274,6 +274,16 @@ config SENSORS_ATXP1
This driver can also be built as a module. If so, the module
will be called atxp1.
+config SENSORS_DS620
+ tristate "Dallas Semiconductor DS620"
+ depends on I2C
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS620 sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called ds620.
+
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
depends on I2C
@@ -734,6 +744,16 @@ config SENSORS_SHT15
This driver can also be built as a module. If so, the module
will be called sht15.
+config SENSORS_SHT21
+ tristate "Sensiron humidity and temperature sensors. SHT21 and compat."
+ depends on I2C
+ help
+ If you say yes here you get support for the Sensiron SHT21, SHT25
+ humidity and temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called sht21.
+
config SENSORS_S3C
tristate "Samsung built-in ADC"
depends on S3C_ADC
@@ -789,10 +809,10 @@ config SENSORS_DME1737
will be called dme1737.
config SENSORS_EMC1403
- tristate "SMSC EMC1403 thermal sensor"
+ tristate "SMSC EMC1403/23 thermal sensor"
depends on I2C
help
- If you say yes here you get support for the SMSC EMC1403
+ If you say yes here you get support for the SMSC EMC1403/23
temperature monitoring chip.
Threshold values can be configured using sysfs.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2479b3da272c..dde02d99c238 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_PKGTEMP) += pkgtemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
+obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
@@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
obj-$(CONFIG_SENSORS_SHT15) += sht15.o
+obj-$(CONFIG_SENSORS_SHT21) += sht21.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMM665) += smm665.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 03694cc17a32..8f07a9dda152 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -20,6 +20,9 @@
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!
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
@@ -220,6 +223,10 @@ struct abituguru_data {
u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
};
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+ "Please report this to the abituguru maintainer (see MAINTAINERS)";
+
/* wait till the uguru is in the specified state */
static int abituguru_wait(struct abituguru_data *data, u8 state)
{
@@ -438,8 +445,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
/* Test val is sane / usable for sensor type detection. */
if ((val < 10u) || (val > 250u)) {
- printk(KERN_WARNING ABIT_UGURU_NAME
- ": bank1-sensor: %d reading (%d) too close to limits, "
+ pr_warn("bank1-sensor: %d reading (%d) too close to limits, "
"unable to determine sensor type, skipping sensor\n",
(int)sensor_addr, (int)val);
/* assume no sensor is there for sensors for which we can't
@@ -535,10 +541,8 @@ abituguru_detect_bank1_sensor_type_exit:
3) == 3)
break;
if (i == 3) {
- printk(KERN_ERR ABIT_UGURU_NAME
- ": Fatal error could not restore original settings. "
- "This should never happen please report this to the "
- "abituguru maintainer (see MAINTAINERS)\n");
+ pr_err("Fatal error could not restore original settings. %s %s\n",
+ never_happen, report_this);
return -ENODEV;
}
return ret;
@@ -1268,14 +1272,12 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
}
/* Fail safe check, this should never happen! */
if (sysfs_names_free < 0) {
- printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of "
- "space for sysfs attr names. This should never "
- "happen please report to the abituguru maintainer "
- "(see MAINTAINERS)\n");
+ pr_err("Fatal error ran out of space for sysfs attr names. %s %s",
+ never_happen, report_this);
res = -ENAMETOOLONG;
goto abituguru_probe_error;
}
- printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
+ pr_info("found Abit uGuru\n");
/* Register sysfs hooks */
for (i = 0; i < sysfs_attr_i; i++)
@@ -1432,8 +1434,7 @@ static int __init abituguru_detect(void)
"0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
if (force) {
- printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is "
- "present because of \"force\" parameter\n");
+ pr_info("Assuming Abit uGuru is present because of \"force\" parameter\n");
return ABIT_UGURU_BASE;
}
@@ -1467,8 +1468,7 @@ static int __init abituguru_init(void)
abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
if (!abituguru_pdev) {
- printk(KERN_ERR ABIT_UGURU_NAME
- ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
err = -ENOMEM;
goto exit_driver_unregister;
}
@@ -1479,15 +1479,13 @@ static int __init abituguru_init(void)
err = platform_device_add_resources(abituguru_pdev, &res, 1);
if (err) {
- printk(KERN_ERR ABIT_UGURU_NAME
- ": Device resource addition failed (%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(abituguru_pdev);
if (err) {
- printk(KERN_ERR ABIT_UGURU_NAME
- ": Device addition failed (%d)\n", err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 3cf28af614b5..48d21e22e930 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -23,6 +23,9 @@
chip found on newer Abit uGuru motherboards. Note: because of lack of specs
only reading the sensors and their settings is supported.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -608,6 +611,9 @@ static int verbose = 1;
module_param(verbose, bool, 0644);
MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+static const char *never_happen = "This should never happen.";
+static const char *report_this =
+ "Please report this to the abituguru3 maintainer (see MAINTAINERS)";
/* wait while the uguru is busy (usually after a write) */
static int abituguru3_wait_while_busy(struct abituguru3_data *data)
@@ -940,15 +946,13 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
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);
+ pr_err("error unknown motherboard ID: %04X. %s\n",
+ (unsigned int)id, report_this);
goto abituguru3_probe_error;
}
data->sensors = abituguru3_motherboards[i].sensors;
- printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
- "ID: %04X\n", (unsigned int)id);
+ pr_info("found Abit uGuru3, motherboard ID: %04X\n", (unsigned int)id);
/* Fill the sysfs attr array */
sysfs_attr_i = 0;
@@ -957,11 +961,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
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");
+ pr_err("Fatal error motherboard has more sensors then ABIT_UGURU3_MAX_NO_SENSORS. %s %s\n",
+ never_happen, report_this);
res = -ENAMETOOLONG;
goto abituguru3_probe_error;
}
@@ -983,10 +984,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
}
/* 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");
+ pr_err("Fatal error ran out of space for sysfs attr names. %s %s\n",
+ never_happen, report_this);
res = -ENAMETOOLONG;
goto abituguru3_probe_error;
}
@@ -1189,8 +1188,7 @@ static int __init abituguru3_detect(void)
"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");
+ pr_info("Assuming Abit uGuru3 is present because of \"force\" parameter\n");
return 0;
}
@@ -1219,10 +1217,8 @@ static int __init abituguru3_init(void)
return err;
#ifdef CONFIG_DMI
- printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was "
- "not detected using DMI. Please send the output of "
- "\"dmidecode\" to the abituguru3 maintainer "
- "(see MAINTAINERS)\n");
+ pr_warn("this motherboard was not detected using DMI. "
+ "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
#endif
}
@@ -1233,8 +1229,7 @@ static int __init abituguru3_init(void)
abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME,
ABIT_UGURU3_BASE);
if (!abituguru3_pdev) {
- printk(KERN_ERR ABIT_UGURU3_NAME
- ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
err = -ENOMEM;
goto exit_driver_unregister;
}
@@ -1245,15 +1240,13 @@ static int __init abituguru3_init(void)
err = platform_device_add_resources(abituguru3_pdev, &res, 1);
if (err) {
- printk(KERN_ERR ABIT_UGURU3_NAME
- ": Device resource addition failed (%d)\n", err);
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index 1e4c21fc1a89..86d822aa9bbf 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -178,11 +178,13 @@ static int ad7414_probe(struct i2c_client *client,
{
struct ad7414_data *data;
int conf;
- int err = 0;
+ int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_READ_WORD_DATA))
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ err = -EOPNOTSUPP;
goto exit;
+ }
data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
if (!data) {
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 4bf969c0a32b..be0fdd58aa29 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -916,27 +916,27 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
- int val, orig_div, new_div, shift;
+ int val, orig_div, new_div;
val = simple_strtol(buf, NULL, 10);
new_div = DIV_TO_REG(val);
- if (new_div == 0) {
- return -EINVAL;
- }
+
mutex_lock(&data->update_lock);
orig_div = data->fan_div[nr];
data->fan_div[nr] = DIV_FROM_REG(new_div);
if (nr < 4) { /* 0 <= nr < 4 */
- shift = 2 * nr;
adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
- ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) |
- (new_div << shift)));
+ (DIV_TO_REG(data->fan_div[0]) << 0) |
+ (DIV_TO_REG(data->fan_div[1]) << 2) |
+ (DIV_TO_REG(data->fan_div[2]) << 4) |
+ (DIV_TO_REG(data->fan_div[3]) << 6));
} else { /* 3 < nr < 8 */
- shift = 2 * (nr - 4);
adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
- ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) |
- (new_div << shift)));
+ (DIV_TO_REG(data->fan_div[4]) << 0) |
+ (DIV_TO_REG(data->fan_div[5]) << 2) |
+ (DIV_TO_REG(data->fan_div[6]) << 4) |
+ (DIV_TO_REG(data->fan_div[7]) << 6));
}
if (data->fan_div[nr] != orig_div) {
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 0727ad250793..9e234b981b83 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -20,7 +20,7 @@
* Alarms 16-bit map of active alarms
* Analog Out 0..1250 mV output
*
- * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear'
+ * Chassis Intrusion: clear CI latch with 'echo 0 > intrusion0_alarm'
*
* Test hardware: Intel SE440BX-2 desktop motherboard --Grant
*
@@ -476,13 +476,16 @@ static ssize_t set_aout(struct device *dev,
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
/* chassis_clear */
-static ssize_t chassis_clear(struct device *dev,
+static ssize_t chassis_clear_legacy(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
unsigned long val = simple_strtol(buf, NULL, 10);
+ dev_warn(dev, "Attribute chassis_clear is deprecated, "
+ "use intrusion0_alarm instead\n");
+
if (val == 1) {
i2c_smbus_write_byte_data(client,
ADM9240_REG_CHASSIS_CLEAR, 0x80);
@@ -490,7 +493,29 @@ static ssize_t chassis_clear(struct device *dev,
}
return count;
}
-static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
+static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear_legacy);
+
+static ssize_t chassis_clear(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
+ data->valid = 0; /* Force cache refresh */
+ mutex_unlock(&data->update_lock);
+ dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
+
+ return count;
+}
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, show_alarm,
+ chassis_clear, 12);
static struct attribute *adm9240_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
@@ -532,6 +557,7 @@ static struct attribute *adm9240_attributes[] = {
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
&dev_attr_chassis_clear.attr,
+ &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index aac85f3aed50..c42c5a69a664 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -4,7 +4,7 @@
This driver is based on the lm75 and other lm_sensors/hwmon drivers
- Written by Steve Hardy <steve@linuxrealtime.co.uk>
+ Written by Steve Hardy <shardy@redhat.com>
Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
@@ -271,7 +271,7 @@ static void __exit sensors_ads7828_exit(void)
i2c_del_driver(&ads7828_driver);
}
-MODULE_AUTHOR("Steve Hardy <steve@linuxrealtime.co.uk>");
+MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
MODULE_DESCRIPTION("ADS7828 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 9e775717abb7..c6d1ce059aea 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
@@ -274,7 +276,7 @@ static int adt7470_read_temperatures(struct i2c_client *client,
i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
if (res) {
- printk(KERN_ERR "ha ha, interrupted");
+ pr_err("ha ha, interrupted\n");
return -EAGAIN;
}
@@ -1286,8 +1288,10 @@ static int adt7470_probe(struct i2c_client *client,
init_completion(&data->auto_update_stop);
data->auto_update = kthread_run(adt7470_update_thread, client,
dev_name(data->hwmon_dev));
- if (IS_ERR(data->auto_update))
+ if (IS_ERR(data->auto_update)) {
+ err = PTR_ERR(data->auto_update);
goto exit_unregister;
+ }
return 0;
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index fa9708c2d723..4033974d1bb3 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -4,7 +4,7 @@
Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
Based on max6650.c:
- Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.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
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index b6598aa557a0..ce0372f0615e 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -4,6 +4,7 @@
* computers.
*
* Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
*
* Based on hdaps.c driver:
* Copyright (C) 2005 Robert Love <rml@novell.com>
@@ -26,10 +27,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input-polldev.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/dmi.h>
@@ -49,6 +53,7 @@
#define APPLESMC_MAX_DATA_LENGTH 32
+/* wait up to 32 ms for a status change. */
#define APPLESMC_MIN_WAIT 0x0040
#define APPLESMC_MAX_WAIT 0x8000
@@ -73,104 +78,15 @@
#define FANS_COUNT "FNum" /* r-o ui8 */
#define FANS_MANUAL "FS! " /* r-w ui16 */
-#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
-#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
-#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
-#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
-#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
-#define FAN_POSITION "F0ID" /* r-o char[16] */
-
-/*
- * Temperature sensors keys (sp78 - 2 bytes).
- */
-static const char *temperature_sensors_sets[][41] = {
-/* Set 0: Macbook Pro */
- { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
- "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
-/* Set 1: Macbook2 set */
- { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
- "Th0S", "Th1H", NULL },
-/* Set 2: Macbook set */
- { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
- "Th1H", "Ts0P", NULL },
-/* Set 3: Macmini set */
- { "TC0D", "TC0P", NULL },
-/* Set 4: Mac Pro (2 x Quad-Core) */
- { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
- "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
- "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
- "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
- "TM9S", "TN0H", "TS0C", NULL },
-/* Set 5: iMac */
- { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
- "Tp0C", NULL },
-/* Set 6: Macbook3 set */
- { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
- "Th0S", "Th1H", NULL },
-/* Set 7: Macbook Air */
- { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
- "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
-/* Set 8: Macbook Pro 4,1 (Penryn) */
- { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
- "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
-/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
- { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
- "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
-/* Set 10: iMac 5,1 */
- { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
-/* Set 11: Macbook 5,1 */
- { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
- "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
-/* Set 12: Macbook Pro 5,1 */
- { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
- "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
- "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
-/* Set 13: iMac 8,1 */
- { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
- "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
-/* Set 14: iMac 6,1 */
- { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
- "TO0P", "Tp0P", NULL },
-/* Set 15: MacBook Air 2,1 */
- { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
- "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
- "Ts0S", NULL },
-/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
- { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
- "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
- "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
- "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
- "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
- NULL },
-/* Set 17: iMac 9,1 */
- { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
- "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
-/* Set 18: MacBook Pro 2,2 */
- { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
- "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
-/* Set 19: Macbook Pro 5,3 */
- { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
- "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
- "Tm0P", "Ts0P", "Ts0S", NULL },
-/* Set 20: MacBook Pro 5,4 */
- { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
- "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
-/* Set 21: MacBook Pro 6,2 */
- { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
- "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
- "Ts0P", "Ts0S", NULL },
-/* Set 22: MacBook Pro 7,1 */
- { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
- "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
-};
+#define FAN_ID_FMT "F%dID" /* r-o char[16] */
/* List of keys used to read/write fan speeds */
-static const char* fan_speed_keys[] = {
- FAN_ACTUAL_SPEED,
- FAN_MIN_SPEED,
- FAN_MAX_SPEED,
- FAN_SAFE_SPEED,
- FAN_TARGET_SPEED
+static const char *const fan_speed_fmt[] = {
+ "F%dAc", /* actual speed */
+ "F%dMn", /* minimum speed (rw) */
+ "F%dMx", /* maximum speed */
+ "F%dSf", /* safe speed - not all models */
+ "F%dTg", /* target speed (manual: rw) */
};
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
@@ -184,14 +100,48 @@ static const char* fan_speed_keys[] = {
#define SENSOR_Y 1
#define SENSOR_Z 2
-/* Structure to be passed to DMI_MATCH function */
-struct dmi_match_data {
-/* Indicates whether this computer has an accelerometer. */
- int accelerometer;
-/* Indicates whether this computer has light sensors and keyboard backlight. */
- int light;
-/* Indicates which temperature sensors set to use. */
- int temperature_set;
+#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
+#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
+
+/* Dynamic device node attributes */
+struct applesmc_dev_attr {
+ struct sensor_device_attribute sda; /* hwmon attributes */
+ char name[32]; /* room for node file name */
+};
+
+/* Dynamic device node group */
+struct applesmc_node_group {
+ char *format; /* format string */
+ void *show; /* show function */
+ void *store; /* store function */
+ int option; /* function argument */
+ struct applesmc_dev_attr *nodes; /* dynamic node array */
+};
+
+/* AppleSMC entry - cached register information */
+struct applesmc_entry {
+ char key[5]; /* four-letter key code */
+ u8 valid; /* set when entry is successfully read once */
+ u8 len; /* bounded by APPLESMC_MAX_DATA_LENGTH */
+ char type[5]; /* four-letter type code */
+ u8 flags; /* 0x10: func; 0x40: write; 0x80: read */
+};
+
+/* Register lookup and registers common to all SMCs */
+static struct applesmc_registers {
+ struct mutex mutex; /* register read/write mutex */
+ unsigned int key_count; /* number of SMC registers */
+ unsigned int fan_count; /* number of fans */
+ unsigned int temp_count; /* number of temperature registers */
+ unsigned int temp_begin; /* temperature lower index bound */
+ unsigned int temp_end; /* temperature upper index bound */
+ int num_light_sensors; /* number of light sensors */
+ bool has_accelerometer; /* has motion sensor */
+ bool has_key_backlight; /* has keyboard backlight */
+ bool init_complete; /* true when fully initialized */
+ struct applesmc_entry *cache; /* cached key entries */
+} smcreg = {
+ .mutex = __MUTEX_INITIALIZER(smcreg.mutex),
};
static const int debug;
@@ -203,20 +153,6 @@ static u8 backlight_state[2];
static struct device *hwmon_dev;
static struct input_polled_dev *applesmc_idev;
-/* Indicates whether this computer has an accelerometer. */
-static unsigned int applesmc_accelerometer;
-
-/* Indicates whether this computer has light sensors and keyboard backlight. */
-static unsigned int applesmc_light;
-
-/* The number of fans handled by the driver */
-static unsigned int fans_handled;
-
-/* Indicates which temperature sensors set to use. */
-static unsigned int applesmc_temperature_set;
-
-static DEFINE_MUTEX(applesmc_lock);
-
/*
* Last index written to key_at_index sysfs file, and value to use for all other
* key_at_index_* sysfs files.
@@ -238,18 +174,10 @@ static int __wait_status(u8 val)
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
udelay(us);
- if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
- if (debug)
- printk(KERN_DEBUG
- "Waited %d us for status %x\n",
- 2 * us - APPLESMC_MIN_WAIT, val);
+ if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val)
return 0;
- }
}
- printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
- val, inb(APPLESMC_CMD_PORT));
-
return -EIO;
}
@@ -267,159 +195,242 @@ static int send_command(u8 cmd)
if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
return 0;
}
- printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
- cmd, inb(APPLESMC_CMD_PORT));
return -EIO;
}
-/*
- * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_read_key(const char* key, u8* buffer, u8 len)
+static int send_argument(const char *key)
{
int i;
- if (len > APPLESMC_MAX_DATA_LENGTH) {
- printk(KERN_ERR "applesmc_read_key: cannot read more than "
- "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
- return -EINVAL;
- }
-
- if (send_command(APPLESMC_READ_CMD))
- return -EIO;
-
for (i = 0; i < 4; i++) {
outb(key[i], APPLESMC_DATA_PORT);
if (__wait_status(0x04))
return -EIO;
}
- if (debug)
- printk(KERN_DEBUG "<%s", key);
+ return 0;
+}
+
+static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
+{
+ int i;
+
+ if (send_command(cmd) || send_argument(key)) {
+ pr_warn("%s: read arg fail\n", key);
+ return -EIO;
+ }
outb(len, APPLESMC_DATA_PORT);
- if (debug)
- printk(KERN_DEBUG ">%x", len);
for (i = 0; i < len; i++) {
- if (__wait_status(0x05))
+ if (__wait_status(0x05)) {
+ pr_warn("%s: read data fail\n", key);
return -EIO;
+ }
buffer[i] = inb(APPLESMC_DATA_PORT);
- if (debug)
- printk(KERN_DEBUG "<%x", buffer[i]);
}
- if (debug)
- printk(KERN_DEBUG "\n");
return 0;
}
-/*
- * applesmc_write_key - writes len bytes from buffer to a given key.
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_write_key(const char* key, u8* buffer, u8 len)
+static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
{
int i;
- if (len > APPLESMC_MAX_DATA_LENGTH) {
- printk(KERN_ERR "applesmc_write_key: cannot write more than "
- "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
- return -EINVAL;
- }
-
- if (send_command(APPLESMC_WRITE_CMD))
+ if (send_command(cmd) || send_argument(key)) {
+ pr_warn("%s: write arg fail\n", key);
return -EIO;
-
- for (i = 0; i < 4; i++) {
- outb(key[i], APPLESMC_DATA_PORT);
- if (__wait_status(0x04))
- return -EIO;
}
outb(len, APPLESMC_DATA_PORT);
for (i = 0; i < len; i++) {
- if (__wait_status(0x04))
+ if (__wait_status(0x04)) {
+ pr_warn("%s: write data fail\n", key);
return -EIO;
+ }
outb(buffer[i], APPLESMC_DATA_PORT);
}
return 0;
}
+static int read_register_count(unsigned int *count)
+{
+ __be32 be;
+ int ret;
+
+ ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
+ if (ret)
+ return ret;
+
+ *count = be32_to_cpu(be);
+ return 0;
+}
+
/*
- * applesmc_get_key_at_index - get key at index, and put the result in key
- * (char[6]). Returns zero on success or a negative error on failure. Callers
- * must hold applesmc_lock.
+ * Serialized I/O
+ *
+ * Returns zero on success or a negative error on failure.
+ * All functions below are concurrency safe - callers should NOT hold lock.
*/
-static int applesmc_get_key_at_index(int index, char* key)
+
+static int applesmc_read_entry(const struct applesmc_entry *entry,
+ u8 *buf, u8 len)
{
- int i;
- u8 readkey[4];
- readkey[0] = index >> 24;
- readkey[1] = index >> 16;
- readkey[2] = index >> 8;
- readkey[3] = index;
+ int ret;
- if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
- return -EIO;
+ if (entry->len != len)
+ return -EINVAL;
+ mutex_lock(&smcreg.mutex);
+ ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
+ mutex_unlock(&smcreg.mutex);
- for (i = 0; i < 4; i++) {
- outb(readkey[i], APPLESMC_DATA_PORT);
- if (__wait_status(0x04))
- return -EIO;
+ return ret;
+}
+
+static int applesmc_write_entry(const struct applesmc_entry *entry,
+ const u8 *buf, u8 len)
+{
+ int ret;
+
+ if (entry->len != len)
+ return -EINVAL;
+ mutex_lock(&smcreg.mutex);
+ ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
+ mutex_unlock(&smcreg.mutex);
+ return ret;
+}
+
+static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
+{
+ struct applesmc_entry *cache = &smcreg.cache[index];
+ u8 key[4], info[6];
+ __be32 be;
+ int ret = 0;
+
+ if (cache->valid)
+ return cache;
+
+ mutex_lock(&smcreg.mutex);
+
+ if (cache->valid)
+ goto out;
+ be = cpu_to_be32(index);
+ ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
+ if (ret)
+ goto out;
+ ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
+ if (ret)
+ goto out;
+
+ memcpy(cache->key, key, 4);
+ cache->len = info[0];
+ memcpy(cache->type, &info[1], 4);
+ cache->flags = info[5];
+ cache->valid = 1;
+
+out:
+ mutex_unlock(&smcreg.mutex);
+ if (ret)
+ return ERR_PTR(ret);
+ return cache;
+}
+
+static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
+{
+ int begin = 0, end = smcreg.key_count;
+ const struct applesmc_entry *entry;
+
+ while (begin != end) {
+ int middle = begin + (end - begin) / 2;
+ entry = applesmc_get_entry_by_index(middle);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ if (strcmp(entry->key, key) < 0)
+ begin = middle + 1;
+ else
+ end = middle;
}
- outb(4, APPLESMC_DATA_PORT);
+ *lo = begin;
+ return 0;
+}
- for (i = 0; i < 4; i++) {
- if (__wait_status(0x05))
- return -EIO;
- key[i] = inb(APPLESMC_DATA_PORT);
+static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
+{
+ int begin = 0, end = smcreg.key_count;
+ const struct applesmc_entry *entry;
+
+ while (begin != end) {
+ int middle = begin + (end - begin) / 2;
+ entry = applesmc_get_entry_by_index(middle);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ if (strcmp(key, entry->key) < 0)
+ end = middle;
+ else
+ begin = middle + 1;
}
- key[4] = 0;
+ *hi = begin;
return 0;
}
-/*
- * applesmc_get_key_type - get key type, and put the result in type (char[6]).
- * Returns zero on success or a negative error on failure. Callers must
- * hold applesmc_lock.
- */
-static int applesmc_get_key_type(char* key, char* type)
+static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
{
- int i;
+ int begin, end;
+ int ret;
- if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
- return -EIO;
+ ret = applesmc_get_lower_bound(&begin, key);
+ if (ret)
+ return ERR_PTR(ret);
+ ret = applesmc_get_upper_bound(&end, key);
+ if (ret)
+ return ERR_PTR(ret);
+ if (end - begin != 1)
+ return ERR_PTR(-EINVAL);
- for (i = 0; i < 4; i++) {
- outb(key[i], APPLESMC_DATA_PORT);
- if (__wait_status(0x04))
- return -EIO;
- }
+ return applesmc_get_entry_by_index(begin);
+}
- outb(6, APPLESMC_DATA_PORT);
+static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
+{
+ const struct applesmc_entry *entry;
- for (i = 0; i < 6; i++) {
- if (__wait_status(0x05))
- return -EIO;
- type[i] = inb(APPLESMC_DATA_PORT);
- }
- type[5] = 0;
+ entry = applesmc_get_entry_by_key(key);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ return applesmc_read_entry(entry, buffer, len);
+}
+
+static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
+{
+ const struct applesmc_entry *entry;
+ entry = applesmc_get_entry_by_key(key);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ return applesmc_write_entry(entry, buffer, len);
+}
+
+static int applesmc_has_key(const char *key, bool *value)
+{
+ const struct applesmc_entry *entry;
+
+ entry = applesmc_get_entry_by_key(key);
+ if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
+ return PTR_ERR(entry);
+
+ *value = !IS_ERR(entry);
return 0;
}
/*
- * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
- * hold applesmc_lock.
+ * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z).
*/
-static int applesmc_read_motion_sensor(int index, s16* value)
+static int applesmc_read_motion_sensor(int index, s16 *value)
{
u8 buffer[2];
int ret;
@@ -444,69 +455,120 @@ static int applesmc_read_motion_sensor(int index, s16* value)
}
/*
- * applesmc_device_init - initialize the accelerometer. Returns zero on success
- * and negative error code on failure. Can sleep.
+ * applesmc_device_init - initialize the accelerometer. Can sleep.
*/
-static int applesmc_device_init(void)
+static void applesmc_device_init(void)
{
- int total, ret = -ENXIO;
+ int total;
u8 buffer[2];
- if (!applesmc_accelerometer)
- return 0;
-
- mutex_lock(&applesmc_lock);
+ if (!smcreg.has_accelerometer)
+ return;
for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
- if (debug)
- printk(KERN_DEBUG "applesmc try %d\n", total);
if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
- (buffer[0] != 0x00 || buffer[1] != 0x00)) {
- if (total == INIT_TIMEOUT_MSECS) {
- printk(KERN_DEBUG "applesmc: device has"
- " already been initialized"
- " (0x%02x, 0x%02x).\n",
- buffer[0], buffer[1]);
- } else {
- printk(KERN_DEBUG "applesmc: device"
- " successfully initialized"
- " (0x%02x, 0x%02x).\n",
- buffer[0], buffer[1]);
- }
- ret = 0;
- goto out;
- }
+ (buffer[0] != 0x00 || buffer[1] != 0x00))
+ return;
buffer[0] = 0xe0;
buffer[1] = 0x00;
applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
msleep(INIT_WAIT_MSECS);
}
- printk(KERN_WARNING "applesmc: failed to init the device\n");
-
-out:
- mutex_unlock(&applesmc_lock);
- return ret;
+ pr_warn("failed to init the device\n");
}
/*
- * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
- * applesmc_lock.
+ * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
*/
-static int applesmc_get_fan_count(void)
+static int applesmc_init_smcreg_try(void)
{
+ struct applesmc_registers *s = &smcreg;
+ bool left_light_sensor, right_light_sensor;
+ u8 tmp[1];
int ret;
- u8 buffer[1];
- mutex_lock(&applesmc_lock);
+ if (s->init_complete)
+ return 0;
- ret = applesmc_read_key(FANS_COUNT, buffer, 1);
+ ret = read_register_count(&s->key_count);
+ if (ret)
+ return ret;
+
+ if (!s->cache)
+ s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
+ if (!s->cache)
+ return -ENOMEM;
- mutex_unlock(&applesmc_lock);
+ ret = applesmc_read_key(FANS_COUNT, tmp, 1);
if (ret)
return ret;
- else
- return buffer[0];
+ s->fan_count = tmp[0];
+
+ ret = applesmc_get_lower_bound(&s->temp_begin, "T");
+ if (ret)
+ return ret;
+ ret = applesmc_get_lower_bound(&s->temp_end, "U");
+ if (ret)
+ return ret;
+ s->temp_count = s->temp_end - s->temp_begin;
+
+ ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
+ if (ret)
+ return ret;
+ ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
+ if (ret)
+ return ret;
+ ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
+ if (ret)
+ return ret;
+ ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
+ if (ret)
+ return ret;
+
+ s->num_light_sensors = left_light_sensor + right_light_sensor;
+ s->init_complete = true;
+
+ pr_info("key=%d fan=%d temp=%d acc=%d lux=%d kbd=%d\n",
+ s->key_count, s->fan_count, s->temp_count,
+ s->has_accelerometer,
+ s->num_light_sensors,
+ s->has_key_backlight);
+
+ return 0;
+}
+
+/*
+ * applesmc_init_smcreg - Initialize register cache.
+ *
+ * Retries until initialization is successful, or the operation times out.
+ *
+ */
+static int applesmc_init_smcreg(void)
+{
+ int ms, ret;
+
+ for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
+ ret = applesmc_init_smcreg_try();
+ if (!ret) {
+ if (ms)
+ pr_info("init_smcreg() took %d ms\n", ms);
+ return 0;
+ }
+ msleep(INIT_WAIT_MSECS);
+ }
+
+ kfree(smcreg.cache);
+ smcreg.cache = NULL;
+
+ return ret;
+}
+
+static void applesmc_destroy_smcreg(void)
+{
+ kfree(smcreg.cache);
+ smcreg.cache = NULL;
+ smcreg.init_complete = false;
}
/* Device model stuff */
@@ -514,30 +576,27 @@ static int applesmc_probe(struct platform_device *dev)
{
int ret;
- ret = applesmc_device_init();
+ ret = applesmc_init_smcreg();
if (ret)
return ret;
- printk(KERN_INFO "applesmc: device successfully initialized.\n");
+ applesmc_device_init();
+
return 0;
}
/* Synchronize device with memorized backlight state */
static int applesmc_pm_resume(struct device *dev)
{
- mutex_lock(&applesmc_lock);
- if (applesmc_light)
+ if (smcreg.has_key_backlight)
applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
- mutex_unlock(&applesmc_lock);
return 0;
}
/* Reinitialize device on resume from hibernation */
static int applesmc_pm_restore(struct device *dev)
{
- int ret = applesmc_device_init();
- if (ret)
- return ret;
+ applesmc_device_init();
return applesmc_pm_resume(dev);
}
@@ -571,20 +630,15 @@ static void applesmc_idev_poll(struct input_polled_dev *dev)
struct input_dev *idev = dev->input;
s16 x, y;
- mutex_lock(&applesmc_lock);
-
if (applesmc_read_motion_sensor(SENSOR_X, &x))
- goto out;
+ return;
if (applesmc_read_motion_sensor(SENSOR_Y, &y))
- goto out;
+ return;
x = -x;
input_report_abs(idev, ABS_X, x - rest_x);
input_report_abs(idev, ABS_Y, y - rest_y);
input_sync(idev);
-
-out:
- mutex_unlock(&applesmc_lock);
}
/* Sysfs Files */
@@ -601,8 +655,6 @@ static ssize_t applesmc_position_show(struct device *dev,
int ret;
s16 x, y, z;
- mutex_lock(&applesmc_lock);
-
ret = applesmc_read_motion_sensor(SENSOR_X, &x);
if (ret)
goto out;
@@ -614,7 +666,6 @@ static ssize_t applesmc_position_show(struct device *dev,
goto out;
out:
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -624,20 +675,20 @@ out:
static ssize_t applesmc_light_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
+ const struct applesmc_entry *entry;
static int data_length;
int ret;
u8 left = 0, right = 0;
- u8 buffer[10], query[6];
-
- mutex_lock(&applesmc_lock);
+ u8 buffer[10];
if (!data_length) {
- ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
- if (ret)
- goto out;
- data_length = clamp_val(query[0], 0, 10);
- printk(KERN_INFO "applesmc: light sensor data length set to "
- "%d\n", data_length);
+ entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ if (entry->len > 10)
+ return -ENXIO;
+ data_length = entry->len;
+ pr_info("light sensor data length set to %d\n", data_length);
}
ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
@@ -653,7 +704,6 @@ static ssize_t applesmc_light_show(struct device *dev,
right = buffer[2];
out:
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -664,36 +714,44 @@ out:
static ssize_t applesmc_show_sensor_label(struct device *dev,
struct device_attribute *devattr, char *sysfsbuf)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- const char *key =
- temperature_sensors_sets[applesmc_temperature_set][attr->index];
+ int index = smcreg.temp_begin + to_index(devattr);
+ const struct applesmc_entry *entry;
+
+ entry = applesmc_get_entry_by_index(index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
}
/* Displays degree Celsius * 1000 */
static ssize_t applesmc_show_temperature(struct device *dev,
struct device_attribute *devattr, char *sysfsbuf)
{
+ int index = smcreg.temp_begin + to_index(devattr);
+ const struct applesmc_entry *entry;
int ret;
u8 buffer[2];
unsigned int temp;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- const char* key =
- temperature_sensors_sets[applesmc_temperature_set][attr->index];
-
- mutex_lock(&applesmc_lock);
- ret = applesmc_read_key(key, buffer, 2);
- temp = buffer[0]*1000;
- temp += (buffer[1] >> 6) * 250;
-
- mutex_unlock(&applesmc_lock);
+ entry = applesmc_get_entry_by_index(index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ if (entry->len > 2)
+ return -EINVAL;
+ ret = applesmc_read_entry(entry, buffer, entry->len);
if (ret)
return ret;
- else
- return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
+
+ if (entry->len == 2) {
+ temp = buffer[0] * 1000;
+ temp += (buffer[1] >> 6) * 250;
+ } else {
+ temp = buffer[0] * 4000;
+ }
+
+ return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
}
static ssize_t applesmc_show_fan_speed(struct device *dev,
@@ -703,21 +761,12 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
unsigned int speed = 0;
char newkey[5];
u8 buffer[2];
- struct sensor_device_attribute_2 *sensor_attr =
- to_sensor_dev_attr_2(attr);
-
- newkey[0] = fan_speed_keys[sensor_attr->nr][0];
- newkey[1] = '0' + sensor_attr->index;
- newkey[2] = fan_speed_keys[sensor_attr->nr][2];
- newkey[3] = fan_speed_keys[sensor_attr->nr][3];
- newkey[4] = 0;
- mutex_lock(&applesmc_lock);
+ sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
ret = applesmc_read_key(newkey, buffer, 2);
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -729,30 +778,19 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
const char *sysfsbuf, size_t count)
{
int ret;
- u32 speed;
+ unsigned long speed;
char newkey[5];
u8 buffer[2];
- struct sensor_device_attribute_2 *sensor_attr =
- to_sensor_dev_attr_2(attr);
-
- speed = simple_strtoul(sysfsbuf, NULL, 10);
-
- if (speed > 0x4000) /* Bigger than a 14-bit value */
- return -EINVAL;
- newkey[0] = fan_speed_keys[sensor_attr->nr][0];
- newkey[1] = '0' + sensor_attr->index;
- newkey[2] = fan_speed_keys[sensor_attr->nr][2];
- newkey[3] = fan_speed_keys[sensor_attr->nr][3];
- newkey[4] = 0;
+ if (strict_strtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
+ return -EINVAL; /* Bigger than a 14-bit value */
- mutex_lock(&applesmc_lock);
+ sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
buffer[0] = (speed >> 6) & 0xff;
buffer[1] = (speed << 2) & 0xff;
ret = applesmc_write_key(newkey, buffer, 2);
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -760,19 +798,15 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
}
static ssize_t applesmc_show_fan_manual(struct device *dev,
- struct device_attribute *devattr, char *sysfsbuf)
+ struct device_attribute *attr, char *sysfsbuf)
{
int ret;
u16 manual = 0;
u8 buffer[2];
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-
- mutex_lock(&applesmc_lock);
ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
- manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
+ manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -780,18 +814,16 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
}
static ssize_t applesmc_store_fan_manual(struct device *dev,
- struct device_attribute *devattr,
+ struct device_attribute *attr,
const char *sysfsbuf, size_t count)
{
int ret;
u8 buffer[2];
- u32 input;
+ unsigned long input;
u16 val;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-
- input = simple_strtoul(sysfsbuf, NULL, 10);
- mutex_lock(&applesmc_lock);
+ if (strict_strtoul(sysfsbuf, 10, &input) < 0)
+ return -EINVAL;
ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
val = (buffer[0] << 8 | buffer[1]);
@@ -799,9 +831,9 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
goto out;
if (input)
- val = val | (0x01 << attr->index);
+ val = val | (0x01 << to_index(attr));
else
- val = val & ~(0x01 << attr->index);
+ val = val & ~(0x01 << to_index(attr));
buffer[0] = (val >> 8) & 0xFF;
buffer[1] = val & 0xFF;
@@ -809,7 +841,6 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
out:
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -822,21 +853,12 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
int ret;
char newkey[5];
u8 buffer[17];
- struct sensor_device_attribute_2 *sensor_attr =
- to_sensor_dev_attr_2(attr);
-
- newkey[0] = FAN_POSITION[0];
- newkey[1] = '0' + sensor_attr->index;
- newkey[2] = FAN_POSITION[2];
- newkey[3] = FAN_POSITION[3];
- newkey[4] = 0;
- mutex_lock(&applesmc_lock);
+ sprintf(newkey, FAN_ID_FMT, to_index(attr));
ret = applesmc_read_key(newkey, buffer, 16);
buffer[16] = 0;
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -852,18 +874,14 @@ static ssize_t applesmc_calibrate_show(struct device *dev,
static ssize_t applesmc_calibrate_store(struct device *dev,
struct device_attribute *attr, const char *sysfsbuf, size_t count)
{
- mutex_lock(&applesmc_lock);
applesmc_calibrate();
- mutex_unlock(&applesmc_lock);
return count;
}
static void applesmc_backlight_set(struct work_struct *work)
{
- mutex_lock(&applesmc_lock);
applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
- mutex_unlock(&applesmc_lock);
}
static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
@@ -886,13 +904,10 @@ static ssize_t applesmc_key_count_show(struct device *dev,
u8 buffer[4];
u32 count;
- mutex_lock(&applesmc_lock);
-
ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
((u32)buffer[2]<<8) + buffer[3];
- mutex_unlock(&applesmc_lock);
if (ret)
return ret;
else
@@ -902,113 +917,53 @@ static ssize_t applesmc_key_count_show(struct device *dev,
static ssize_t applesmc_key_at_index_read_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- char key[5];
- char info[6];
+ const struct applesmc_entry *entry;
int ret;
- mutex_lock(&applesmc_lock);
-
- ret = applesmc_get_key_at_index(key_at_index, key);
-
- if (ret || !key[0]) {
- mutex_unlock(&applesmc_lock);
-
- return -EINVAL;
- }
-
- ret = applesmc_get_key_type(key, info);
-
- if (ret) {
- mutex_unlock(&applesmc_lock);
-
+ entry = applesmc_get_entry_by_index(key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
+ if (ret)
return ret;
- }
-
- /*
- * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
- * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
- */
- ret = applesmc_read_key(key, sysfsbuf, info[0]);
-
- mutex_unlock(&applesmc_lock);
- if (!ret) {
- return info[0];
- } else {
- return ret;
- }
+ return entry->len;
}
static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- char key[5];
- char info[6];
- int ret;
-
- mutex_lock(&applesmc_lock);
-
- ret = applesmc_get_key_at_index(key_at_index, key);
+ const struct applesmc_entry *entry;
- if (ret || !key[0]) {
- mutex_unlock(&applesmc_lock);
+ entry = applesmc_get_entry_by_index(key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
- return -EINVAL;
- }
-
- ret = applesmc_get_key_type(key, info);
-
- mutex_unlock(&applesmc_lock);
-
- if (!ret)
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
- else
- return ret;
+ return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
}
static ssize_t applesmc_key_at_index_type_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- char key[5];
- char info[6];
- int ret;
-
- mutex_lock(&applesmc_lock);
-
- ret = applesmc_get_key_at_index(key_at_index, key);
-
- if (ret || !key[0]) {
- mutex_unlock(&applesmc_lock);
-
- return -EINVAL;
- }
-
- ret = applesmc_get_key_type(key, info);
+ const struct applesmc_entry *entry;
- mutex_unlock(&applesmc_lock);
+ entry = applesmc_get_entry_by_index(key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
- if (!ret)
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
- else
- return ret;
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
}
static ssize_t applesmc_key_at_index_name_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- char key[5];
- int ret;
+ const struct applesmc_entry *entry;
- mutex_lock(&applesmc_lock);
+ entry = applesmc_get_entry_by_index(key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
- ret = applesmc_get_key_at_index(key_at_index, key);
-
- mutex_unlock(&applesmc_lock);
-
- if (!ret && key[0])
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
- else
- return -EINVAL;
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
}
static ssize_t applesmc_key_at_index_show(struct device *dev,
@@ -1020,12 +975,13 @@ static ssize_t applesmc_key_at_index_show(struct device *dev,
static ssize_t applesmc_key_at_index_store(struct device *dev,
struct device_attribute *attr, const char *sysfsbuf, size_t count)
{
- mutex_lock(&applesmc_lock);
-
- key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
+ unsigned long newkey;
- mutex_unlock(&applesmc_lock);
+ if (strict_strtoul(sysfsbuf, 10, &newkey) < 0
+ || newkey >= smcreg.key_count)
+ return -EINVAL;
+ key_at_index = newkey;
return count;
}
@@ -1035,387 +991,101 @@ static struct led_classdev applesmc_backlight = {
.brightness_set = applesmc_brightness_set,
};
-static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
-
-static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
-static DEVICE_ATTR(calibrate, 0644,
- applesmc_calibrate_show, applesmc_calibrate_store);
-
-static struct attribute *accelerometer_attributes[] = {
- &dev_attr_position.attr,
- &dev_attr_calibrate.attr,
- NULL
-};
-
-static const struct attribute_group accelerometer_attributes_group =
- { .attrs = accelerometer_attributes };
-
-static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
-
-static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
-static DEVICE_ATTR(key_at_index, 0644,
- applesmc_key_at_index_show, applesmc_key_at_index_store);
-static DEVICE_ATTR(key_at_index_name, 0444,
- applesmc_key_at_index_name_show, NULL);
-static DEVICE_ATTR(key_at_index_type, 0444,
- applesmc_key_at_index_type_show, NULL);
-static DEVICE_ATTR(key_at_index_data_length, 0444,
- applesmc_key_at_index_data_length_show, NULL);
-static DEVICE_ATTR(key_at_index_data, 0444,
- applesmc_key_at_index_read_show, NULL);
-
-static struct attribute *key_enumeration_attributes[] = {
- &dev_attr_key_count.attr,
- &dev_attr_key_at_index.attr,
- &dev_attr_key_at_index_name.attr,
- &dev_attr_key_at_index_type.attr,
- &dev_attr_key_at_index_data_length.attr,
- &dev_attr_key_at_index_data.attr,
- NULL
-};
-
-static const struct attribute_group key_enumeration_group =
- { .attrs = key_enumeration_attributes };
-
-/*
- * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
- * - show actual speed
- * - show/store minimum speed
- * - show maximum speed
- * - show safe speed
- * - show/store target speed
- * - show/store manual mode
- */
-#define sysfs_fan_speeds_offset(offset) \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
- applesmc_show_fan_speed, NULL, 0, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
- applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
- applesmc_show_fan_speed, NULL, 2, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
- applesmc_show_fan_speed, NULL, 3, offset-1); \
-\
-static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
- applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
-\
-static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
- applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
-\
-static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
- applesmc_show_fan_position, NULL, offset-1); \
-\
-static struct attribute *fan##offset##_attributes[] = { \
- &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
- &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
- NULL \
+static struct applesmc_node_group info_group[] = {
+ { "name", applesmc_name_show },
+ { "key_count", applesmc_key_count_show },
+ { "key_at_index", applesmc_key_at_index_show, applesmc_key_at_index_store },
+ { "key_at_index_name", applesmc_key_at_index_name_show },
+ { "key_at_index_type", applesmc_key_at_index_type_show },
+ { "key_at_index_data_length", applesmc_key_at_index_data_length_show },
+ { "key_at_index_data", applesmc_key_at_index_read_show },
+ { }
};
-/*
- * Create the needed functions for each fan using the macro defined above
- * (4 fans are supported)
- */
-sysfs_fan_speeds_offset(1);
-sysfs_fan_speeds_offset(2);
-sysfs_fan_speeds_offset(3);
-sysfs_fan_speeds_offset(4);
-
-static const struct attribute_group fan_attribute_groups[] = {
- { .attrs = fan1_attributes },
- { .attrs = fan2_attributes },
- { .attrs = fan3_attributes },
- { .attrs = fan4_attributes },
+static struct applesmc_node_group accelerometer_group[] = {
+ { "position", applesmc_position_show },
+ { "calibrate", applesmc_calibrate_show, applesmc_calibrate_store },
+ { }
};
-/*
- * Temperature sensors sysfs entries.
- */
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 5);
-static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 6);
-static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 7);
-static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 8);
-static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 10);
-static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 11);
-static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 13);
-static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 14);
-static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 15);
-static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 16);
-static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 17);
-static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 18);
-static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 19);
-static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 20);
-static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 21);
-static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 22);
-static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 23);
-static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 24);
-static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 25);
-static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 26);
-static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 27);
-static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 28);
-static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 29);
-static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 30);
-static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 31);
-static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 32);
-static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 33);
-static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 34);
-static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 35);
-static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 36);
-static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 37);
-static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 38);
-static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
- applesmc_show_sensor_label, NULL, 39);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
- applesmc_show_temperature, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
- applesmc_show_temperature, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
- applesmc_show_temperature, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
- applesmc_show_temperature, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
- applesmc_show_temperature, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
- applesmc_show_temperature, NULL, 5);
-static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
- applesmc_show_temperature, NULL, 6);
-static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
- applesmc_show_temperature, NULL, 7);
-static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
- applesmc_show_temperature, NULL, 8);
-static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
- applesmc_show_temperature, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
- applesmc_show_temperature, NULL, 10);
-static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
- applesmc_show_temperature, NULL, 11);
-static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
- applesmc_show_temperature, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
- applesmc_show_temperature, NULL, 13);
-static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
- applesmc_show_temperature, NULL, 14);
-static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
- applesmc_show_temperature, NULL, 15);
-static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
- applesmc_show_temperature, NULL, 16);
-static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
- applesmc_show_temperature, NULL, 17);
-static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
- applesmc_show_temperature, NULL, 18);
-static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
- applesmc_show_temperature, NULL, 19);
-static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
- applesmc_show_temperature, NULL, 20);
-static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
- applesmc_show_temperature, NULL, 21);
-static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
- applesmc_show_temperature, NULL, 22);
-static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
- applesmc_show_temperature, NULL, 23);
-static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
- applesmc_show_temperature, NULL, 24);
-static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
- applesmc_show_temperature, NULL, 25);
-static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
- applesmc_show_temperature, NULL, 26);
-static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
- applesmc_show_temperature, NULL, 27);
-static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
- applesmc_show_temperature, NULL, 28);
-static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
- applesmc_show_temperature, NULL, 29);
-static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
- applesmc_show_temperature, NULL, 30);
-static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
- applesmc_show_temperature, NULL, 31);
-static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
- applesmc_show_temperature, NULL, 32);
-static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
- applesmc_show_temperature, NULL, 33);
-static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
- applesmc_show_temperature, NULL, 34);
-static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
- applesmc_show_temperature, NULL, 35);
-static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
- applesmc_show_temperature, NULL, 36);
-static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
- applesmc_show_temperature, NULL, 37);
-static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
- applesmc_show_temperature, NULL, 38);
-static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
- applesmc_show_temperature, NULL, 39);
-
-static struct attribute *label_attributes[] = {
- &sensor_dev_attr_temp1_label.dev_attr.attr,
- &sensor_dev_attr_temp2_label.dev_attr.attr,
- &sensor_dev_attr_temp3_label.dev_attr.attr,
- &sensor_dev_attr_temp4_label.dev_attr.attr,
- &sensor_dev_attr_temp5_label.dev_attr.attr,
- &sensor_dev_attr_temp6_label.dev_attr.attr,
- &sensor_dev_attr_temp7_label.dev_attr.attr,
- &sensor_dev_attr_temp8_label.dev_attr.attr,
- &sensor_dev_attr_temp9_label.dev_attr.attr,
- &sensor_dev_attr_temp10_label.dev_attr.attr,
- &sensor_dev_attr_temp11_label.dev_attr.attr,
- &sensor_dev_attr_temp12_label.dev_attr.attr,
- &sensor_dev_attr_temp13_label.dev_attr.attr,
- &sensor_dev_attr_temp14_label.dev_attr.attr,
- &sensor_dev_attr_temp15_label.dev_attr.attr,
- &sensor_dev_attr_temp16_label.dev_attr.attr,
- &sensor_dev_attr_temp17_label.dev_attr.attr,
- &sensor_dev_attr_temp18_label.dev_attr.attr,
- &sensor_dev_attr_temp19_label.dev_attr.attr,
- &sensor_dev_attr_temp20_label.dev_attr.attr,
- &sensor_dev_attr_temp21_label.dev_attr.attr,
- &sensor_dev_attr_temp22_label.dev_attr.attr,
- &sensor_dev_attr_temp23_label.dev_attr.attr,
- &sensor_dev_attr_temp24_label.dev_attr.attr,
- &sensor_dev_attr_temp25_label.dev_attr.attr,
- &sensor_dev_attr_temp26_label.dev_attr.attr,
- &sensor_dev_attr_temp27_label.dev_attr.attr,
- &sensor_dev_attr_temp28_label.dev_attr.attr,
- &sensor_dev_attr_temp29_label.dev_attr.attr,
- &sensor_dev_attr_temp30_label.dev_attr.attr,
- &sensor_dev_attr_temp31_label.dev_attr.attr,
- &sensor_dev_attr_temp32_label.dev_attr.attr,
- &sensor_dev_attr_temp33_label.dev_attr.attr,
- &sensor_dev_attr_temp34_label.dev_attr.attr,
- &sensor_dev_attr_temp35_label.dev_attr.attr,
- &sensor_dev_attr_temp36_label.dev_attr.attr,
- &sensor_dev_attr_temp37_label.dev_attr.attr,
- &sensor_dev_attr_temp38_label.dev_attr.attr,
- &sensor_dev_attr_temp39_label.dev_attr.attr,
- &sensor_dev_attr_temp40_label.dev_attr.attr,
- NULL
+static struct applesmc_node_group light_sensor_group[] = {
+ { "light", applesmc_light_show },
+ { }
};
-static struct attribute *temperature_attributes[] = {
- &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_temp4_input.dev_attr.attr,
- &sensor_dev_attr_temp5_input.dev_attr.attr,
- &sensor_dev_attr_temp6_input.dev_attr.attr,
- &sensor_dev_attr_temp7_input.dev_attr.attr,
- &sensor_dev_attr_temp8_input.dev_attr.attr,
- &sensor_dev_attr_temp9_input.dev_attr.attr,
- &sensor_dev_attr_temp10_input.dev_attr.attr,
- &sensor_dev_attr_temp11_input.dev_attr.attr,
- &sensor_dev_attr_temp12_input.dev_attr.attr,
- &sensor_dev_attr_temp13_input.dev_attr.attr,
- &sensor_dev_attr_temp14_input.dev_attr.attr,
- &sensor_dev_attr_temp15_input.dev_attr.attr,
- &sensor_dev_attr_temp16_input.dev_attr.attr,
- &sensor_dev_attr_temp17_input.dev_attr.attr,
- &sensor_dev_attr_temp18_input.dev_attr.attr,
- &sensor_dev_attr_temp19_input.dev_attr.attr,
- &sensor_dev_attr_temp20_input.dev_attr.attr,
- &sensor_dev_attr_temp21_input.dev_attr.attr,
- &sensor_dev_attr_temp22_input.dev_attr.attr,
- &sensor_dev_attr_temp23_input.dev_attr.attr,
- &sensor_dev_attr_temp24_input.dev_attr.attr,
- &sensor_dev_attr_temp25_input.dev_attr.attr,
- &sensor_dev_attr_temp26_input.dev_attr.attr,
- &sensor_dev_attr_temp27_input.dev_attr.attr,
- &sensor_dev_attr_temp28_input.dev_attr.attr,
- &sensor_dev_attr_temp29_input.dev_attr.attr,
- &sensor_dev_attr_temp30_input.dev_attr.attr,
- &sensor_dev_attr_temp31_input.dev_attr.attr,
- &sensor_dev_attr_temp32_input.dev_attr.attr,
- &sensor_dev_attr_temp33_input.dev_attr.attr,
- &sensor_dev_attr_temp34_input.dev_attr.attr,
- &sensor_dev_attr_temp35_input.dev_attr.attr,
- &sensor_dev_attr_temp36_input.dev_attr.attr,
- &sensor_dev_attr_temp37_input.dev_attr.attr,
- &sensor_dev_attr_temp38_input.dev_attr.attr,
- &sensor_dev_attr_temp39_input.dev_attr.attr,
- &sensor_dev_attr_temp40_input.dev_attr.attr,
- NULL
+static struct applesmc_node_group fan_group[] = {
+ { "fan%d_label", applesmc_show_fan_position },
+ { "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
+ { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
+ { "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
+ { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
+ { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
+ { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
+ { }
};
-static const struct attribute_group temperature_attributes_group =
- { .attrs = temperature_attributes };
-
-static const struct attribute_group label_attributes_group = {
- .attrs = label_attributes
+static struct applesmc_node_group temp_group[] = {
+ { "temp%d_label", applesmc_show_sensor_label },
+ { "temp%d_input", applesmc_show_temperature },
+ { }
};
/* Module stuff */
/*
- * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
+ * applesmc_destroy_nodes - remove files and free associated memory
*/
-static int applesmc_dmi_match(const struct dmi_system_id *id)
+static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
{
- int i = 0;
- struct dmi_match_data* dmi_data = id->driver_data;
- printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
- applesmc_accelerometer = dmi_data->accelerometer;
- printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
- applesmc_accelerometer ? "with" : "without");
- applesmc_light = dmi_data->light;
- printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
- applesmc_light ? "with" : "without");
-
- applesmc_temperature_set = dmi_data->temperature_set;
- while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
- i++;
- printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
- return 1;
+ struct applesmc_node_group *grp;
+ struct applesmc_dev_attr *node;
+
+ for (grp = groups; grp->nodes; grp++) {
+ for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
+ sysfs_remove_file(&pdev->dev.kobj,
+ &node->sda.dev_attr.attr);
+ kfree(grp->nodes);
+ grp->nodes = NULL;
+ }
+}
+
+/*
+ * applesmc_create_nodes - create a two-dimensional group of sysfs files
+ */
+static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
+{
+ struct applesmc_node_group *grp;
+ struct applesmc_dev_attr *node;
+ struct attribute *attr;
+ int ret, i;
+
+ for (grp = groups; grp->format; grp++) {
+ grp->nodes = kcalloc(num + 1, sizeof(*node), GFP_KERNEL);
+ if (!grp->nodes) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < num; i++) {
+ node = &grp->nodes[i];
+ sprintf(node->name, grp->format, i + 1);
+ node->sda.index = (grp->option << 16) | (i & 0xffff);
+ node->sda.dev_attr.show = grp->show;
+ node->sda.dev_attr.store = grp->store;
+ attr = &node->sda.dev_attr.attr;
+ attr->name = node->name;
+ attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
+ ret = sysfs_create_file(&pdev->dev.kobj, attr);
+ if (ret) {
+ attr->name = NULL;
+ goto out;
+ }
+ }
+ }
+
+ return 0;
+out:
+ applesmc_destroy_nodes(groups);
+ return ret;
}
/* Create accelerometer ressources */
@@ -1424,8 +1094,10 @@ static int applesmc_create_accelerometer(void)
struct input_dev *idev;
int ret;
- ret = sysfs_create_group(&pdev->dev.kobj,
- &accelerometer_attributes_group);
+ if (!smcreg.has_accelerometer)
+ return 0;
+
+ ret = applesmc_create_nodes(accelerometer_group, 1);
if (ret)
goto out;
@@ -1462,184 +1134,96 @@ out_idev:
input_free_polled_device(applesmc_idev);
out_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+ applesmc_destroy_nodes(accelerometer_group);
out:
- printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+ pr_warn("driver init failed (ret=%d)!\n", ret);
return ret;
}
/* Release all ressources used by the accelerometer */
static void applesmc_release_accelerometer(void)
{
+ if (!smcreg.has_accelerometer)
+ return;
input_unregister_polled_device(applesmc_idev);
input_free_polled_device(applesmc_idev);
- sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+ applesmc_destroy_nodes(accelerometer_group);
}
-static __initdata struct dmi_match_data applesmc_dmi_data[] = {
-/* MacBook Pro: accelerometer, backlight and temperature set 0 */
- { .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook2: accelerometer and temperature set 1 */
- { .accelerometer = 1, .light = 0, .temperature_set = 1 },
-/* MacBook: accelerometer and temperature set 2 */
- { .accelerometer = 1, .light = 0, .temperature_set = 2 },
-/* MacMini: temperature set 3 */
- { .accelerometer = 0, .light = 0, .temperature_set = 3 },
-/* MacPro: temperature set 4 */
- { .accelerometer = 0, .light = 0, .temperature_set = 4 },
-/* iMac: temperature set 5 */
- { .accelerometer = 0, .light = 0, .temperature_set = 5 },
-/* MacBook3, MacBook4: accelerometer and temperature set 6 */
- { .accelerometer = 1, .light = 0, .temperature_set = 6 },
-/* MacBook Air: accelerometer, backlight and temperature set 7 */
- { .accelerometer = 1, .light = 1, .temperature_set = 7 },
-/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
- { .accelerometer = 1, .light = 1, .temperature_set = 8 },
-/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
- { .accelerometer = 1, .light = 1, .temperature_set = 9 },
-/* iMac 5: light sensor only, temperature set 10 */
- { .accelerometer = 0, .light = 0, .temperature_set = 10 },
-/* MacBook 5: accelerometer, backlight and temperature set 11 */
- { .accelerometer = 1, .light = 1, .temperature_set = 11 },
-/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
- { .accelerometer = 1, .light = 1, .temperature_set = 12 },
-/* iMac 8: light sensor only, temperature set 13 */
- { .accelerometer = 0, .light = 0, .temperature_set = 13 },
-/* iMac 6: light sensor only, temperature set 14 */
- { .accelerometer = 0, .light = 0, .temperature_set = 14 },
-/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
- { .accelerometer = 1, .light = 1, .temperature_set = 15 },
-/* MacPro3,1: temperature set 16 */
- { .accelerometer = 0, .light = 0, .temperature_set = 16 },
-/* iMac 9,1: light sensor only, temperature set 17 */
- { .accelerometer = 0, .light = 0, .temperature_set = 17 },
-/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
- { .accelerometer = 1, .light = 1, .temperature_set = 18 },
-/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
- { .accelerometer = 1, .light = 1, .temperature_set = 19 },
-/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
- { .accelerometer = 1, .light = 1, .temperature_set = 20 },
-/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
- { .accelerometer = 1, .light = 1, .temperature_set = 21 },
-/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
- { .accelerometer = 1, .light = 1, .temperature_set = 22 },
-};
+static int applesmc_create_light_sensor(void)
+{
+ if (!smcreg.num_light_sensors)
+ return 0;
+ return applesmc_create_nodes(light_sensor_group, 1);
+}
+
+static void applesmc_release_light_sensor(void)
+{
+ if (!smcreg.num_light_sensors)
+ return;
+ applesmc_destroy_nodes(light_sensor_group);
+}
+
+static int applesmc_create_key_backlight(void)
+{
+ if (!smcreg.has_key_backlight)
+ return 0;
+ applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+ if (!applesmc_led_wq)
+ return -ENOMEM;
+ return led_classdev_register(&pdev->dev, &applesmc_backlight);
+}
+
+static void applesmc_release_key_backlight(void)
+{
+ if (!smcreg.has_key_backlight)
+ return;
+ led_classdev_unregister(&applesmc_backlight);
+ destroy_workqueue(applesmc_led_wq);
+}
+
+static int applesmc_dmi_match(const struct dmi_system_id *id)
+{
+ return 1;
+}
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
* So we need to put "Apple MacBook Pro" before "Apple MacBook". */
static __initdata struct dmi_system_id applesmc_whitelist[] = {
- { applesmc_dmi_match, "Apple MacBook Air 2", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
- &applesmc_dmi_data[15]},
{ applesmc_dmi_match, "Apple MacBook Air", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
- &applesmc_dmi_data[7]},
- { applesmc_dmi_match, "Apple MacBook Pro 7", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
- &applesmc_dmi_data[22]},
- { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
- &applesmc_dmi_data[20]},
- { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
- &applesmc_dmi_data[19]},
- { applesmc_dmi_match, "Apple MacBook Pro 6", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
- &applesmc_dmi_data[21]},
- { applesmc_dmi_match, "Apple MacBook Pro 5", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
- &applesmc_dmi_data[12]},
- { applesmc_dmi_match, "Apple MacBook Pro 4", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
- &applesmc_dmi_data[8]},
- { applesmc_dmi_match, "Apple MacBook Pro 3", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
- &applesmc_dmi_data[9]},
- { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
- &applesmc_dmi_data[18]},
+ },
{ applesmc_dmi_match, "Apple MacBook Pro", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
- &applesmc_dmi_data[0]},
- { applesmc_dmi_match, "Apple MacBook (v2)", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
- &applesmc_dmi_data[1]},
- { applesmc_dmi_match, "Apple MacBook (v3)", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
- &applesmc_dmi_data[6]},
- { applesmc_dmi_match, "Apple MacBook 4", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
- &applesmc_dmi_data[6]},
- { applesmc_dmi_match, "Apple MacBook 5", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
- &applesmc_dmi_data[11]},
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro") },
+ },
{ applesmc_dmi_match, "Apple MacBook", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
- &applesmc_dmi_data[2]},
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
+ },
{ applesmc_dmi_match, "Apple Macmini", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
- &applesmc_dmi_data[3]},
- { applesmc_dmi_match, "Apple MacPro2", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
- &applesmc_dmi_data[4]},
- { applesmc_dmi_match, "Apple MacPro3", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
- &applesmc_dmi_data[16]},
+ DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
+ },
{ applesmc_dmi_match, "Apple MacPro", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
- &applesmc_dmi_data[4]},
- { applesmc_dmi_match, "Apple iMac 9,1", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
- &applesmc_dmi_data[17]},
- { applesmc_dmi_match, "Apple iMac 8", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
- &applesmc_dmi_data[13]},
- { applesmc_dmi_match, "Apple iMac 6", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
- &applesmc_dmi_data[14]},
- { applesmc_dmi_match, "Apple iMac 5", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
- &applesmc_dmi_data[10]},
+ },
{ applesmc_dmi_match, "Apple iMac", {
- DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
- &applesmc_dmi_data[5]},
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac") },
+ },
{ .ident = NULL }
};
static int __init applesmc_init(void)
{
int ret;
- int count;
- int i;
if (!dmi_check_system(applesmc_whitelist)) {
- printk(KERN_WARNING "applesmc: supported laptop not found!\n");
+ pr_warn("supported laptop not found!\n");
ret = -ENODEV;
goto out;
}
@@ -1661,83 +1245,34 @@ static int __init applesmc_init(void)
goto out_driver;
}
- ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
+ /* create register cache */
+ ret = applesmc_init_smcreg();
if (ret)
goto out_device;
- /* Create key enumeration sysfs files */
- ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
+ ret = applesmc_create_nodes(info_group, 1);
if (ret)
- goto out_name;
-
- /* create fan files */
- count = applesmc_get_fan_count();
- if (count < 0)
- printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
- else
- printk(KERN_INFO "applesmc: %d fans found.\n", count);
+ goto out_smcreg;
- if (count > 4) {
- count = 4;
- printk(KERN_WARNING "applesmc: More than 4 fans found,"
- " but at most 4 fans are supported"
- " by the driver.\n");
- }
-
- while (fans_handled < count) {
- ret = sysfs_create_group(&pdev->dev.kobj,
- &fan_attribute_groups[fans_handled]);
- if (ret)
- goto out_fans;
- fans_handled++;
- }
-
- for (i = 0;
- temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
- i++) {
- if (temperature_attributes[i] == NULL ||
- label_attributes[i] == NULL) {
- printk(KERN_ERR "applesmc: More temperature sensors "
- "in temperature_sensors_sets (at least %i)"
- "than available sysfs files in "
- "temperature_attributes (%i), please report "
- "this bug.\n", i, i-1);
- goto out_temperature;
- }
- ret = sysfs_create_file(&pdev->dev.kobj,
- temperature_attributes[i]);
- if (ret)
- goto out_temperature;
- ret = sysfs_create_file(&pdev->dev.kobj,
- label_attributes[i]);
- if (ret)
- goto out_temperature;
- }
+ ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
+ if (ret)
+ goto out_info;
- if (applesmc_accelerometer) {
- ret = applesmc_create_accelerometer();
- if (ret)
- goto out_temperature;
- }
+ ret = applesmc_create_nodes(temp_group, smcreg.temp_count);
+ if (ret)
+ goto out_fans;
- if (applesmc_light) {
- /* Add light sensor file */
- ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
- if (ret)
- goto out_accelerometer;
+ ret = applesmc_create_accelerometer();
+ if (ret)
+ goto out_temperature;
- /* Create the workqueue */
- applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
- if (!applesmc_led_wq) {
- ret = -ENOMEM;
- goto out_light_sysfs;
- }
+ ret = applesmc_create_light_sensor();
+ if (ret)
+ goto out_accelerometer;
- /* register as a led device */
- ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
- if (ret < 0)
- goto out_light_wq;
- }
+ ret = applesmc_create_key_backlight();
+ if (ret)
+ goto out_light_sysfs;
hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(hwmon_dev)) {
@@ -1745,32 +1280,22 @@ static int __init applesmc_init(void)
goto out_light_ledclass;
}
- printk(KERN_INFO "applesmc: driver successfully loaded.\n");
-
return 0;
out_light_ledclass:
- if (applesmc_light)
- led_classdev_unregister(&applesmc_backlight);
-out_light_wq:
- if (applesmc_light)
- destroy_workqueue(applesmc_led_wq);
+ applesmc_release_key_backlight();
out_light_sysfs:
- if (applesmc_light)
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+ applesmc_release_light_sensor();
out_accelerometer:
- if (applesmc_accelerometer)
- applesmc_release_accelerometer();
+ applesmc_release_accelerometer();
out_temperature:
- sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
- sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+ applesmc_destroy_nodes(temp_group);
out_fans:
- while (fans_handled)
- sysfs_remove_group(&pdev->dev.kobj,
- &fan_attribute_groups[--fans_handled]);
- sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
-out_name:
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
+ applesmc_destroy_nodes(fan_group);
+out_info:
+ applesmc_destroy_nodes(info_group);
+out_smcreg:
+ applesmc_destroy_smcreg();
out_device:
platform_device_unregister(pdev);
out_driver:
@@ -1778,32 +1303,23 @@ out_driver:
out_region:
release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
out:
- printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+ pr_warn("driver init failed (ret=%d)!\n", ret);
return ret;
}
static void __exit applesmc_exit(void)
{
hwmon_device_unregister(hwmon_dev);
- if (applesmc_light) {
- led_classdev_unregister(&applesmc_backlight);
- destroy_workqueue(applesmc_led_wq);
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
- }
- if (applesmc_accelerometer)
- applesmc_release_accelerometer();
- sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
- sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
- while (fans_handled)
- sysfs_remove_group(&pdev->dev.kobj,
- &fan_attribute_groups[--fans_handled]);
- sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
+ applesmc_release_key_backlight();
+ applesmc_release_light_sensor();
+ applesmc_release_accelerometer();
+ applesmc_destroy_nodes(temp_group);
+ applesmc_destroy_nodes(fan_group);
+ applesmc_destroy_nodes(info_group);
+ applesmc_destroy_smcreg();
platform_device_unregister(pdev);
platform_driver_unregister(&applesmc_driver);
release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
-
- printk(KERN_INFO "applesmc: driver unloaded.\n");
}
module_init(applesmc_init);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 7dada559b3a1..c02a052d3085 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -36,6 +36,8 @@
asb100 7 3 1 4 0x31 0x0694 yes no
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
@@ -701,8 +703,7 @@ static int asb100_detect(struct i2c_client *client,
int val1, val2;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_debug("asb100.o: detect failed, "
- "smbus byte data not supported!\n");
+ pr_debug("detect failed, smbus byte data not supported!\n");
return -ENODEV;
}
@@ -715,7 +716,7 @@ static int asb100_detect(struct i2c_client *client,
(((!(val1 & 0x80)) && (val2 != 0x94)) ||
/* Check for ASB100 ID (high byte ) */
((val1 & 0x80) && (val2 != 0x06)))) {
- pr_debug("asb100: detect failed, bad chip id 0x%02x!\n", val2);
+ pr_debug("detect failed, bad chip id 0x%02x!\n", val2);
return -ENODEV;
}
@@ -744,7 +745,7 @@ static int asb100_probe(struct i2c_client *client,
data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
if (!data) {
- pr_debug("asb100.o: probe failed, kzalloc failed!\n");
+ pr_debug("probe failed, kzalloc failed!\n");
err = -ENOMEM;
goto ERROR0;
}
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 23b8555215d2..2d68cf3c223b 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -5,6 +5,8 @@
* See COPYING in the top level directory of the kernel tree.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
@@ -1414,14 +1416,13 @@ static int __init atk0110_init(void)
/* Make sure it's safe to access the device through ACPI */
if (!acpi_resources_are_enforced()) {
- pr_err("atk: Resources not safely usable due to "
- "acpi_enforce_resources kernel parameter\n");
+ pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
return -EBUSY;
}
ret = acpi_bus_register_driver(&atk_driver);
if (ret)
- pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
+ pr_info("acpi_bus_register_driver failed: %d\n", ret);
return ret;
}
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 42de98d73ff5..194ca0aa8b0c 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -20,6 +20,8 @@
* 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -445,8 +447,8 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
* without thermal sensors will be filtered out.
*/
if (!cpu_has(c, X86_FEATURE_DTS)) {
- printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
- " has no thermal sensor.\n", c->x86_model);
+ pr_info("CPU (model=0x%x) has no thermal sensor\n",
+ c->x86_model);
return 0;
}
@@ -466,7 +468,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
pdev = platform_device_alloc(DRVNAME, cpu);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
@@ -478,8 +480,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_free;
}
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 980c17d5eeae..d9c592713919 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -25,6 +25,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -75,12 +77,14 @@ enum chips { dme1737, sch5027, sch311x, sch5127 };
* in4 +12V
* in5 VTR (+3.3V stby)
* in6 Vbat
+ * in7 Vtrip (sch5127 only)
*
* --------------------------------------------------------------------- */
-/* Voltages (in) numbered 0-6 (ix) */
-#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) \
- : 0x94 + (ix))
+/* Voltages (in) numbered 0-7 (ix) */
+#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \
+ (ix) < 7 ? 0x94 + (ix) : \
+ 0x1f)
#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 \
@@ -99,10 +103,11 @@ enum chips { dme1737, sch5027, sch311x, sch5127 };
* IN_TEMP_LSB(1) = [temp3, temp1]
* IN_TEMP_LSB(2) = [in4, temp2]
* IN_TEMP_LSB(3) = [in3, in0]
- * IN_TEMP_LSB(4) = [in2, in1] */
+ * IN_TEMP_LSB(4) = [in2, in1]
+ * IN_TEMP_LSB(5) = [res, in7] */
#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_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4};
static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
@@ -143,7 +148,7 @@ static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
#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_IN[] = {0, 1, 2, 3, 8, 16, 17, 18};
static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
@@ -188,6 +193,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define HAS_PWM_MIN (1 << 4) /* bit 4 */
#define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */
#define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */
+#define HAS_IN7 (1 << 17) /* bit 17 */
/* ---------------------------------------------------------------------
* Data structures and manipulation thereof
@@ -211,9 +217,9 @@ struct dme1737_data {
u32 has_features;
/* Register values */
- u16 in[7];
- u8 in_min[7];
- u8 in_max[7];
+ u16 in[8];
+ u8 in_min[8];
+ u8 in_max[8];
s16 temp[3];
s8 temp_min[3];
s8 temp_max[3];
@@ -245,7 +251,7 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
3300};
static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
- 3300};
+ 3300, 1500};
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
(type) == sch5127 ? IN_NOMINAL_SCH5127 : \
@@ -578,7 +584,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
{
struct dme1737_data *data = dev_get_drvdata(dev);
int ix;
- u8 lsb[5];
+ u8 lsb[6];
mutex_lock(&data->update_lock);
@@ -601,6 +607,9 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* 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. */
+ if (ix == 7 && !(data->has_features & HAS_IN7)) {
+ continue;
+ }
data->in[ix] = dme1737_read(data,
DME1737_REG_IN(ix)) << 8;
data->in_min[ix] = dme1737_read(data,
@@ -633,10 +642,16 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
* which the registers are read (MSB first, then LSB) is
* important! */
for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+ if (ix == 5 && !(data->has_features & HAS_IN7)) {
+ continue;
+ }
lsb[ix] = dme1737_read(data,
DME1737_REG_IN_TEMP_LSB(ix));
}
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ if (ix == 7 && !(data->has_features & HAS_IN7)) {
+ continue;
+ }
data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
}
@@ -760,7 +775,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* ---------------------------------------------------------------------
* Voltage sysfs attributes
- * ix = [0-5]
+ * ix = [0-7]
* --------------------------------------------------------------------- */
#define SYS_IN_INPUT 0
@@ -1437,7 +1452,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
* Sysfs device attribute defines and structs
* --------------------------------------------------------------------- */
-/* Voltages 0-6 */
+/* Voltages 0-7 */
#define SENSOR_DEVICE_ATTR_IN(ix) \
static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
@@ -1456,6 +1471,7 @@ SENSOR_DEVICE_ATTR_IN(3);
SENSOR_DEVICE_ATTR_IN(4);
SENSOR_DEVICE_ATTR_IN(5);
SENSOR_DEVICE_ATTR_IN(6);
+SENSOR_DEVICE_ATTR_IN(7);
/* Temperatures 1-3 */
@@ -1574,7 +1590,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */
* 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[] ={
+static struct attribute *dme1737_attr[] = {
/* Voltages */
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
@@ -1679,7 +1695,7 @@ static const struct attribute_group dme1737_zone3_group = {
};
-/* The following struct holds temp zone hysteresis related attributes, which
+/* The following struct holds temp zone hysteresis related attributes, which
* are not available in all chips. The following chips support them:
* DME1737, SCH311x */
static struct attribute *dme1737_zone_hyst_attr[] = {
@@ -1693,6 +1709,21 @@ static const struct attribute_group dme1737_zone_hyst_group = {
.attrs = dme1737_zone_hyst_attr,
};
+/* The following struct holds voltage in7 related attributes, which
+ * are not available in all chips. The following chips support them:
+ * SCH5127 */
+static struct attribute *dme1737_in7_attr[] = {
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group dme1737_in7_group = {
+ .attrs = dme1737_in7_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. */
@@ -1984,6 +2015,9 @@ static void dme1737_remove_files(struct device *dev)
if (data->has_features & HAS_ZONE_HYST) {
sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
}
+ if (data->has_features & HAS_IN7) {
+ sysfs_remove_group(&dev->kobj, &dme1737_in7_group);
+ }
sysfs_remove_group(&dev->kobj, &dme1737_group);
if (!data->client) {
@@ -1997,43 +2031,58 @@ static int dme1737_create_files(struct device *dev)
int err, ix;
/* Create a name attribute for ISA devices */
- if (!data->client &&
- (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
- goto exit;
+ if (!data->client) {
+ err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr);
+ if (err) {
+ goto exit;
+ }
}
/* Create standard sysfs attributes */
- if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) {
+ err = sysfs_create_group(&dev->kobj, &dme1737_group);
+ if (err) {
goto exit_remove;
}
/* Create chip-dependent sysfs attributes */
- if ((data->has_features & HAS_TEMP_OFFSET) &&
- (err = sysfs_create_group(&dev->kobj,
- &dme1737_temp_offset_group))) {
- goto exit_remove;
+ if (data->has_features & HAS_TEMP_OFFSET) {
+ err = sysfs_create_group(&dev->kobj,
+ &dme1737_temp_offset_group);
+ if (err) {
+ goto exit_remove;
+ }
}
- if ((data->has_features & HAS_VID) &&
- (err = sysfs_create_group(&dev->kobj,
- &dme1737_vid_group))) {
- goto exit_remove;
+ if (data->has_features & HAS_VID) {
+ err = sysfs_create_group(&dev->kobj, &dme1737_vid_group);
+ if (err) {
+ goto exit_remove;
+ }
}
- if ((data->has_features & HAS_ZONE3) &&
- (err = sysfs_create_group(&dev->kobj,
- &dme1737_zone3_group))) {
- goto exit_remove;
+ if (data->has_features & HAS_ZONE3) {
+ err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group);
+ if (err) {
+ goto exit_remove;
+ }
}
- if ((data->has_features & HAS_ZONE_HYST) &&
- (err = sysfs_create_group(&dev->kobj,
- &dme1737_zone_hyst_group))) {
- goto exit_remove;
+ if (data->has_features & HAS_ZONE_HYST) {
+ err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group);
+ if (err) {
+ goto exit_remove;
+ }
+ }
+ if (data->has_features & HAS_IN7) {
+ err = sysfs_create_group(&dev->kobj, &dme1737_in7_group);
+ if (err) {
+ goto exit_remove;
+ }
}
/* Create fan sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
if (data->has_features & HAS_FAN(ix)) {
- if ((err = sysfs_create_group(&dev->kobj,
- &dme1737_fan_group[ix]))) {
+ err = sysfs_create_group(&dev->kobj,
+ &dme1737_fan_group[ix]);
+ if (err) {
goto exit_remove;
}
}
@@ -2042,14 +2091,17 @@ static int dme1737_create_files(struct device *dev)
/* Create PWM sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
if (data->has_features & HAS_PWM(ix)) {
- if ((err = sysfs_create_group(&dev->kobj,
- &dme1737_pwm_group[ix]))) {
+ err = sysfs_create_group(&dev->kobj,
+ &dme1737_pwm_group[ix]);
+ if (err) {
goto exit_remove;
}
- if ((data->has_features & HAS_PWM_MIN) && ix < 3 &&
- (err = sysfs_create_file(&dev->kobj,
- dme1737_auto_pwm_min_attr[ix]))) {
- goto exit_remove;
+ if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) {
+ err = sysfs_create_file(&dev->kobj,
+ dme1737_auto_pwm_min_attr[ix]);
+ if (err) {
+ goto exit_remove;
+ }
}
}
}
@@ -2186,7 +2238,7 @@ static int dme1737_init_device(struct device *dev)
data->has_features |= HAS_ZONE3;
break;
case sch5127:
- data->has_features |= HAS_FAN(2) | HAS_PWM(2);
+ data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7;
break;
default:
break;
@@ -2279,8 +2331,9 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
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))) {
+ addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61);
+ if (!addr) {
err = -ENODEV;
goto exit;
}
@@ -2361,13 +2414,15 @@ static int dme1737_i2c_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
/* Initialize the DME1737 chip */
- if ((err = dme1737_init_device(dev))) {
+ err = dme1737_init_device(dev);
+ if (err) {
dev_err(dev, "Failed to initialize device.\n");
goto exit_kfree;
}
/* Create sysfs files */
- if ((err = dme1737_create_files(dev))) {
+ err = dme1737_create_files(dev);
+ if (err) {
dev_err(dev, "Failed to create sysfs files.\n");
goto exit_kfree;
}
@@ -2444,9 +2499,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
dme1737_sio_outb(sio_cip, 0x07, 0x0a);
/* Get the base address of the runtime registers */
- if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
- dme1737_sio_inb(sio_cip, 0x61))) {
- printk(KERN_ERR "dme1737: Base address not set.\n");
+ base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61);
+ if (!base_addr) {
+ pr_err("Base address not set\n");
err = -ENODEV;
goto exit;
}
@@ -2474,21 +2530,22 @@ static int __init dme1737_isa_device_add(unsigned short addr)
if (err)
goto exit;
- if (!(pdev = platform_device_alloc("dme1737", addr))) {
- printk(KERN_ERR "dme1737: Failed to allocate device.\n");
+ pdev = platform_device_alloc("dme1737", addr);
+ if (!pdev) {
+ pr_err("Failed to allocate device\n");
err = -ENOMEM;
goto exit;
}
- if ((err = platform_device_add_resources(pdev, &res, 1))) {
- printk(KERN_ERR "dme1737: Failed to add device resource "
- "(err = %d).\n", err);
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ pr_err("Failed to add device resource (err = %d)\n", err);
goto exit_device_put;
}
- if ((err = platform_device_add(pdev))) {
- printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n",
- err);
+ err = platform_device_add(pdev);
+ if (err) {
+ pr_err("Failed to add device (err = %d)\n", err);
goto exit_device_put;
}
@@ -2514,11 +2571,12 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
(unsigned short)res->start,
(unsigned short)res->start + DME1737_EXTENT - 1);
- err = -EBUSY;
- goto exit;
- }
+ err = -EBUSY;
+ goto exit;
+ }
- if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+ data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
+ if (!data) {
err = -ENOMEM;
goto exit_release_region;
}
@@ -2565,13 +2623,15 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
/* Initialize the chip */
- if ((err = dme1737_init_device(dev))) {
+ err = dme1737_init_device(dev);
+ if (err) {
dev_err(dev, "Failed to initialize device.\n");
goto exit_kfree;
}
/* Create sysfs files */
- if ((err = dme1737_create_files(dev))) {
+ err = dme1737_create_files(dev);
+ if (err) {
dev_err(dev, "Failed to create sysfs files.\n");
goto exit_kfree;
}
@@ -2628,7 +2688,8 @@ static int __init dme1737_init(void)
int err;
unsigned short addr;
- if ((err = i2c_add_driver(&dme1737_i2c_driver))) {
+ err = i2c_add_driver(&dme1737_i2c_driver);
+ if (err) {
goto exit;
}
@@ -2641,12 +2702,14 @@ static int __init dme1737_init(void)
return 0;
}
- if ((err = platform_driver_register(&dme1737_isa_driver))) {
+ err = platform_driver_register(&dme1737_isa_driver);
+ if (err) {
goto exit_del_i2c_driver;
}
/* Sets global pdev as a side effect */
- if ((err = dme1737_isa_device_add(addr))) {
+ err = dme1737_isa_device_add(addr);
+ if (err) {
goto exit_del_isa_driver;
}
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
new file mode 100644
index 000000000000..257957c69d92
--- /dev/null
+++ b/drivers/hwmon/ds620.c
@@ -0,0 +1,337 @@
+/*
+ * ds620.c - Support for temperature sensor and thermostat DS620
+ *
+ * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * based on ds1621.c by Christian W. Zuckschwerdt <zany@triq.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/i2c/ds620.h>
+
+/*
+ * Many DS620 constants specified below
+ * 15 14 13 12 11 10 09 08
+ * |Done|NVB |THF |TLF |R1 |R0 |AUTOC|1SHOT|
+ *
+ * 07 06 05 04 03 02 01 00
+ * |PO2 |PO1 |A2 |A1 |A0 | | | |
+ */
+#define DS620_REG_CONFIG_DONE 0x8000
+#define DS620_REG_CONFIG_NVB 0x4000
+#define DS620_REG_CONFIG_THF 0x2000
+#define DS620_REG_CONFIG_TLF 0x1000
+#define DS620_REG_CONFIG_R1 0x0800
+#define DS620_REG_CONFIG_R0 0x0400
+#define DS620_REG_CONFIG_AUTOC 0x0200
+#define DS620_REG_CONFIG_1SHOT 0x0100
+#define DS620_REG_CONFIG_PO2 0x0080
+#define DS620_REG_CONFIG_PO1 0x0040
+#define DS620_REG_CONFIG_A2 0x0020
+#define DS620_REG_CONFIG_A1 0x0010
+#define DS620_REG_CONFIG_A0 0x0008
+
+/* The DS620 registers */
+static const u8 DS620_REG_TEMP[3] = {
+ 0xAA, /* input, word, RO */
+ 0xA2, /* min, word, RW */
+ 0xA0, /* max, word, RW */
+};
+
+#define DS620_REG_CONF 0xAC /* word, RW */
+#define DS620_COM_START 0x51 /* no data */
+#define DS620_COM_STOP 0x22 /* no data */
+
+/* Each client has this additional data */
+struct ds620_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ u16 temp[3]; /* Register values, word */
+};
+
+/*
+ * Temperature registers are word-sized.
+ * DS620 uses a high-byte first convention, which is exactly opposite to
+ * the SMBus standard.
+ */
+static int ds620_read_temp(struct i2c_client *client, u8 reg)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+ return swab16(ret);
+}
+
+static int ds620_write_temp(struct i2c_client *client, u8 reg, u16 value)
+{
+ return i2c_smbus_write_word_data(client, reg, swab16(value));
+}
+
+static void ds620_init_client(struct i2c_client *client)
+{
+ struct ds620_platform_data *ds620_info = client->dev.platform_data;
+ u16 conf, new_conf;
+
+ new_conf = conf =
+ swab16(i2c_smbus_read_word_data(client, DS620_REG_CONF));
+
+ /* switch to continuous conversion mode */
+ new_conf &= ~DS620_REG_CONFIG_1SHOT;
+ /* already high at power-on, but don't trust the BIOS! */
+ new_conf |= DS620_REG_CONFIG_PO2;
+ /* thermostat mode according to platform data */
+ if (ds620_info && ds620_info->pomode == 1)
+ new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
+ else if (ds620_info && ds620_info->pomode == 2)
+ new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
+ else
+ new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
+ /* with highest precision */
+ new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
+
+ if (conf != new_conf)
+ i2c_smbus_write_word_data(client, DS620_REG_CONF,
+ swab16(new_conf));
+
+ /* start conversion */
+ i2c_smbus_write_byte(client, DS620_COM_START);
+}
+
+static struct ds620_data *ds620_update_client(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds620_data *data = i2c_get_clientdata(client);
+ struct ds620_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ int i;
+ int res;
+
+ dev_dbg(&client->dev, "Starting ds620 update\n");
+
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ res = ds620_read_temp(client,
+ DS620_REG_TEMP[i]);
+ if (res < 0) {
+ ret = ERR_PTR(res);
+ goto abort;
+ }
+
+ data->temp[i] = res;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+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 ds620_data *data = ds620_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ int res;
+ long val;
+
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds620_data *data = i2c_get_clientdata(client);
+
+ res = strict_strtol(buf, 10, &val);
+
+ if (res)
+ return res;
+
+ val = (val * 10 / 625) * 8;
+
+ mutex_lock(&data->update_lock);
+ data->temp[attr->index] = val;
+ ds620_write_temp(client, DS620_REG_TEMP[attr->index],
+ data->temp[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+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 ds620_data *data = ds620_update_client(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+ u16 conf, new_conf;
+ int res;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /* reset alarms if necessary */
+ res = i2c_smbus_read_word_data(client, DS620_REG_CONF);
+ if (res < 0)
+ return res;
+
+ conf = swab16(res);
+ new_conf = conf;
+ new_conf &= ~attr->index;
+ if (conf != new_conf) {
+ res = i2c_smbus_write_word_data(client, DS620_REG_CONF,
+ swab16(new_conf));
+ if (res < 0)
+ return res;
+ }
+
+ return sprintf(buf, "%d\n", !!(conf & attr->index));
+}
+
+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,
+ DS620_REG_CONFIG_TLF);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+ DS620_REG_CONFIG_THF);
+
+static struct attribute *ds620_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ds620_group = {
+ .attrs = ds620_attributes,
+};
+
+static int ds620_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ds620_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the DS620 chip */
+ ds620_init_client(client);
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &ds620_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ dev_info(&client->dev, "temperature sensor found\n");
+
+ return 0;
+
+exit_remove_files:
+ sysfs_remove_group(&client->dev.kobj, &ds620_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int ds620_remove(struct i2c_client *client)
+{
+ struct ds620_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ds620_group);
+
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id ds620_id[] = {
+ {"ds620", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ds620_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds620_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "ds620",
+ },
+ .probe = ds620_probe,
+ .remove = ds620_remove,
+ .id_table = ds620_id,
+};
+
+static int __init ds620_init(void)
+{
+ return i2c_add_driver(&ds620_driver);
+}
+
+static void __exit ds620_exit(void)
+{
+ i2c_del_driver(&ds620_driver);
+}
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("DS620 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds620_init);
+module_exit(ds620_exit);
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 8dee3f38fdfb..5dea9faa1656 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -269,23 +269,30 @@ static int emc1403_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
int id;
- /* Check if thermal chip is SMSC and EMC1403 */
+ /* Check if thermal chip is SMSC and EMC1403 or EMC1423 */
id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
if (id != 0x5d)
return -ENODEV;
+ id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
+ switch (id) {
+ case 0x21:
+ strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
+ break;
+ case 0x23:
+ strlcpy(info->type, "emc1423", I2C_NAME_SIZE);
+ break;
/* Note: 0x25 is the 1404 which is very similar and this
driver could be extended */
- id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
- if (id != 0x21)
+ default:
return -ENODEV;
+ }
id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
if (id != 0x01)
return -ENODEV;
- strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
return 0;
}
@@ -342,6 +349,7 @@ static const unsigned short emc1403_address_list[] = {
static const struct i2c_device_id emc1403_idtable[] = {
{ "emc1403", 0 },
+ { "emc1423", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 525a00bd70b1..92f949767ece 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -28,6 +28,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1309,7 +1311,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Out of memory\n");
+ pr_err("Out of memory\n");
goto exit;
}
@@ -1451,7 +1453,7 @@ static int __init f71805f_device_add(unsigned short address,
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
@@ -1462,22 +1464,20 @@ static int __init f71805f_device_add(unsigned short address,
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add_data(pdev, sio_data,
sizeof(struct f71805f_sio_data));
if (err) {
- printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
@@ -1516,30 +1516,27 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1);
break;
default:
- printk(KERN_INFO DRVNAME ": Unsupported Fintek device, "
- "skipping\n");
+ pr_info("Unsupported Fintek device, skipping\n");
goto exit;
}
superio_select(sioaddr, F71805F_LD_HWM);
if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
- printk(KERN_WARNING DRVNAME ": Device not activated, "
- "skipping\n");
+ pr_warn("Device not activated, skipping\n");
goto exit;
}
*address = superio_inw(sioaddr, SIO_REG_ADDR);
if (*address == 0) {
- printk(KERN_WARNING DRVNAME ": Base address not set, "
- "skipping\n");
+ pr_warn("Base address not set, skipping\n");
goto exit;
}
*address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
err = 0;
- printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n",
- names[sio_data->kind], *address,
- superio_inb(sioaddr, SIO_REG_DEVREV));
+ pr_info("Found %s chip at %#x, revision %u\n",
+ names[sio_data->kind], *address,
+ superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
superio_exit(sioaddr);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 75afb3b0e076..3f49dd376f02 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -18,6 +18,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -865,8 +867,7 @@ static inline int superio_enter(int base)
{
/* Don't step on other drivers' I/O space by accident */
if (!request_muxed_region(base, 2, DRVNAME)) {
- printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
- base);
+ pr_err("I/O address 0x%04x already in use\n", base);
return -EBUSY;
}
@@ -2192,7 +2193,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
devid = superio_inw(sioaddr, SIO_REG_MANID);
if (devid != SIO_FINTEK_ID) {
- pr_debug(DRVNAME ": Not a Fintek device\n");
+ pr_debug("Not a Fintek device\n");
err = -ENODEV;
goto exit;
}
@@ -2215,8 +2216,8 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
sio_data->type = f8000;
break;
default:
- printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
- (unsigned int)devid);
+ pr_info("Unsupported Fintek device: %04x\n",
+ (unsigned int)devid);
err = -ENODEV;
goto exit;
}
@@ -2227,21 +2228,21 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
superio_select(sioaddr, SIO_F71882FG_LD_HWM);
if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
- printk(KERN_WARNING DRVNAME ": Device not activated\n");
+ pr_warn("Device not activated\n");
err = -ENODEV;
goto exit;
}
*address = superio_inw(sioaddr, SIO_REG_ADDR);
if (*address == 0) {
- printk(KERN_WARNING DRVNAME ": Base address not set\n");
+ pr_warn("Base address not set\n");
err = -ENODEV;
goto exit;
}
*address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
err = 0;
- printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
+ pr_info("Found %s chip at %#x, revision %d\n",
f71882fg_names[sio_data->type], (unsigned int)*address,
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
@@ -2270,20 +2271,20 @@ static int __init f71882fg_device_add(unsigned short address,
err = platform_device_add_resources(f71882fg_pdev, &res, 1);
if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
+ pr_err("Device resource addition failed\n");
goto exit_device_put;
}
err = platform_device_add_data(f71882fg_pdev, sio_data,
sizeof(struct f71882fg_sio_data));
if (err) {
- printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ pr_err("Platform data allocation failed\n");
goto exit_device_put;
}
err = platform_device_add(f71882fg_pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed\n");
+ pr_err("Device addition failed\n");
goto exit_device_put;
}
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index d4d4ca65d371..aa6d8b686f82 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -49,7 +49,6 @@
#include <linux/kref.h>
/* Addresses to scan */
-static DEFINE_MUTEX(watchdog_mutex);
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/* Insmod parameters */
@@ -850,7 +849,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- static struct watchdog_info ident = {
+ struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_CARDRESET,
.identity = "FSC watchdog"
@@ -858,7 +857,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar
int i, ret = 0;
struct fschmd_data *data = filp->private_data;
- mutex_lock(&watchdog_mutex);
switch (cmd) {
case WDIOC_GETSUPPORT:
ident.firmware_version = data->revision;
@@ -915,7 +913,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar
default:
ret = -ENOTTY;
}
- mutex_unlock(&watchdog_mutex);
return ret;
}
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index aa701a183707..f141a1de519c 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -376,10 +376,6 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
}
}
- err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
- if (err)
- goto err_free_gpio;
-
fan_data->num_ctrl = num_ctrl;
fan_data->ctrl = ctrl;
fan_data->num_speed = pdata->num_speed;
@@ -391,6 +387,10 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
goto err_free_gpio;
}
+ err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+ if (err)
+ goto err_free_gpio;
+
return 0;
err_free_gpio:
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
index a56a78412fcb..3d21fa2b97cd 100644
--- a/drivers/hwmon/hp_accel.c
+++ b/drivers/hwmon/hp_accel.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dmi.h>
@@ -147,7 +149,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
{
lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
- printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
+ pr_info("hardware type %s found\n", dmi->ident);
return 1;
}
@@ -303,11 +305,10 @@ static int lis3lv02d_add(struct acpi_device *device)
/* If possible use a "standard" axes order */
if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
- printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
- lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+ pr_info("Using custom axes %d,%d,%d\n",
+ lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
} else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
- printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
- "using default axes configuration\n");
+ pr_info("laptop model unknown, using default axes configuration\n");
lis3_dev.ac = lis3lv02d_axis_normal;
}
@@ -385,7 +386,7 @@ static int __init lis3lv02d_init_module(void)
if (ret < 0)
return ret;
- printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
+ pr_info("driver loaded\n");
return 0;
}
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index 2b2ca1694f95..2582bfef6ccb 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -22,6 +22,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hwmon-vid.h>
@@ -146,8 +148,8 @@ int vid_from_reg(int val, u8 vrm)
return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000);
default: /* report 0 for unknown */
if (vrm)
- printk(KERN_WARNING "hwmon-vid: Requested unsupported "
- "VRM version (%u)\n", (unsigned int)vrm);
+ pr_warn("Requested unsupported VRM version (%u)\n",
+ (unsigned int)vrm);
return 0;
}
}
@@ -246,8 +248,7 @@ u8 vid_which_vrm(void)
}
vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor);
if (vrm_ret == 0)
- printk(KERN_INFO "hwmon-vid: Unknown VRM version of your "
- "x86 CPU\n");
+ pr_info("Unknown VRM version of your x86 CPU\n");
return vrm_ret;
}
@@ -255,7 +256,7 @@ u8 vid_which_vrm(void)
#else
u8 vid_which_vrm(void)
{
- printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n");
+ pr_info("Unknown VRM version of your CPU\n");
return 0;
}
#endif
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 29ea6753f3bb..a61e7815a2a9 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -10,6 +10,8 @@
the Free Software Foundation; version 2 of the License.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -119,7 +121,7 @@ static int __init hwmon_init(void)
hwmon_class = class_create(THIS_MODULE, "hwmon");
if (IS_ERR(hwmon_class)) {
- printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
+ pr_err("couldn't create sysfs class\n");
return PTR_ERR(hwmon_class);
}
return 0;
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index 937983407e2a..c4c40be0edbf 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -497,12 +497,14 @@ static unsigned long chipset_ids[] = {
0
};
+#ifdef MODULE
static struct pci_device_id i5k_amb_ids[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+#endif
static int __devinit i5k_amb_probe(struct platform_device *pdev)
{
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index eaee546af19a..bc6e2ab3a361 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/ipmi.h>
#include <linux/module.h>
#include <linux/hwmon.h>
@@ -1090,7 +1092,7 @@ static int __init aem_init(void)
res = driver_register(&aem_driver.driver);
if (res) {
- printk(KERN_ERR "Can't register aem driver\n");
+ pr_err("Can't register aem driver\n");
return res;
}
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 14a5d981be7d..316b64823f7b 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -38,6 +38,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -187,6 +189,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr))
+#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8)
#define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr))
@@ -251,12 +254,16 @@ struct it87_data {
u8 fan_main_ctrl; /* Register value */
u8 fan_ctl; /* Register value */
- /* The following 3 arrays correspond to the same registers. The
- * meaning of bits 6-0 depends on the value of bit 7, and we want
- * to preserve settings on mode changes, so we have to track all
- * values separately. */
+ /* The following 3 arrays correspond to the same registers up to
+ * the IT8720F. The meaning of bits 6-0 depends on the value of bit
+ * 7, and we want to preserve settings on mode changes, so we have
+ * to track all values separately.
+ * Starting with the IT8721F, the manual PWM duty cycles are stored
+ * in separate registers (8-bit values), so the separate tracking
+ * is no longer needed, but it is still done to keep the driver
+ * simple. */
u8 pwm_ctrl[3]; /* Register value */
- u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */
+ u8 pwm_duty[3]; /* Manual PWM value set by user */
u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
/* Automatic fan speed control registers */
@@ -832,7 +839,9 @@ static ssize_t set_pwm_enable(struct device *dev,
data->fan_main_ctrl);
} else {
if (val == 1) /* Manual mode */
- data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ data->pwm_ctrl[nr] = data->type == it8721 ?
+ data->pwm_temp_map[nr] :
+ data->pwm_duty[nr];
else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
@@ -858,12 +867,25 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&data->update_lock);
- data->pwm_duty[nr] = pwm_to_reg(data, val);
- /* If we are in manual mode, write the duty cycle immediately;
- * otherwise, just store it for later use. */
- if (!(data->pwm_ctrl[nr] & 0x80)) {
- data->pwm_ctrl[nr] = data->pwm_duty[nr];
- it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ if (data->type == it8721) {
+ /* If we are in automatic mode, the PWM duty cycle register
+ * is read-only so we can't write the value */
+ if (data->pwm_ctrl[nr] & 0x80) {
+ mutex_unlock(&data->update_lock);
+ return -EBUSY;
+ }
+ data->pwm_duty[nr] = pwm_to_reg(data, val);
+ it87_write_value(data, IT87_REG_PWM_DUTY(nr),
+ data->pwm_duty[nr]);
+ } else {
+ data->pwm_duty[nr] = pwm_to_reg(data, val);
+ /* If we are in manual mode, write the duty cycle immediately;
+ * otherwise, just store it for later use. */
+ if (!(data->pwm_ctrl[nr] & 0x80)) {
+ data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ it87_write_value(data, IT87_REG_PWM(nr),
+ data->pwm_ctrl[nr]);
+ }
}
mutex_unlock(&data->update_lock);
return count;
@@ -1550,26 +1572,25 @@ static int __init it87_find(unsigned short *address,
case 0xffff: /* No device at all */
goto exit;
default:
- pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n",
- chip_type);
+ pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type);
goto exit;
}
superio_select(PME);
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
- pr_info("it87: Device not activated, skipping\n");
+ pr_info("Device not activated, skipping\n");
goto exit;
}
*address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1);
if (*address == 0) {
- pr_info("it87: Base address not set, skipping\n");
+ pr_info("Base address not set, skipping\n");
goto exit;
}
err = 0;
sio_data->revision = superio_inb(DEVREV) & 0x0f;
- pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
+ pr_info("Found IT%04xF chip at 0x%x, revision %d\n",
chip_type, *address, sio_data->revision);
/* in8 (Vbat) is always internal */
@@ -1595,7 +1616,7 @@ static int __init it87_find(unsigned short *address,
} else {
/* We need at least 4 VID pins */
if (reg & 0x0f) {
- pr_info("it87: VID is disabled (pins used for GPIO)\n");
+ pr_info("VID is disabled (pins used for GPIO)\n");
sio_data->skip_vid = 1;
}
}
@@ -1631,7 +1652,7 @@ static int __init it87_find(unsigned short *address,
if (sio_data->type == it8720 && !(reg & (1 << 1))) {
reg |= (1 << 1);
superio_outb(IT87_SIO_PINX2_REG, reg);
- pr_notice("it87: Routing internal VCCH to in7\n");
+ pr_notice("Routing internal VCCH to in7\n");
}
if (reg & (1 << 0))
sio_data->internal |= (1 << 0);
@@ -1641,7 +1662,7 @@ static int __init it87_find(unsigned short *address,
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
}
if (sio_data->beep_pin)
- pr_info("it87: Beeping is supported\n");
+ pr_info("Beeping is supported\n");
/* Disable specific features based on DMI strings */
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
@@ -1655,8 +1676,7 @@ static int __init it87_find(unsigned short *address,
the PWM2 duty cycle, so we disable it.
I use the board name string as the trigger in case
the same board is ever used in other systems. */
- pr_info("it87: Disabling pwm2 due to "
- "hardware constraints\n");
+ pr_info("Disabling pwm2 due to hardware constraints\n");
sio_data->skip_pwm = (1 << 1);
}
}
@@ -1958,7 +1978,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
* channels to use when later setting to automatic mode later.
* Use a 1:1 mapping by default (we are clueless.)
* In both cases, the value can (and should) be changed by the user
- * prior to switching to a different mode. */
+ * prior to switching to a different mode.
+ * Note that this is no longer needed for the IT8721F and later, as
+ * these have separate registers for the temperature mapping and the
+ * manual duty cycle. */
for (i = 0; i < 3; i++) {
data->pwm_temp_map[i] = i;
data->pwm_duty[i] = 0x7f; /* Full speed */
@@ -2034,10 +2057,16 @@ static void __devinit it87_init_device(struct platform_device *pdev)
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
- if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ if (data->type == it8721) {
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
- else /* Manual mode */
- data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ data->pwm_duty[nr] = it87_read_value(data,
+ IT87_REG_PWM_DUTY(nr));
+ } else {
+ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ else /* Manual mode */
+ data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ }
if (has_old_autopwm(data)) {
int i;
@@ -2160,28 +2189,26 @@ static int __init it87_device_add(unsigned short address,
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("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);
+ pr_err("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");
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index 0cee73a6124e..1b674b7d4584 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dmi.h>
@@ -860,8 +862,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
(p->irq_flags2 & IRQF_TRIGGER_MASK),
DRIVER_NAME, &lis3_dev);
if (err < 0)
- printk(KERN_ERR DRIVER_NAME
- "No second IRQ. Limited functionality\n");
+ pr_err("No second IRQ. Limited functionality\n");
}
}
@@ -879,7 +880,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
switch (dev->whoami) {
case WAI_12B:
- printk(KERN_INFO DRIVER_NAME ": 12 bits sensor found\n");
+ pr_info("12 bits sensor found\n");
dev->read_data = lis3lv02d_read_12;
dev->mdps_max_val = 2048;
dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
@@ -890,7 +891,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
break;
case WAI_8B:
- printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
+ pr_info("8 bits sensor found\n");
dev->read_data = lis3lv02d_read_8;
dev->mdps_max_val = 128;
dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
@@ -901,7 +902,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
break;
case WAI_3DC:
- printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n");
+ pr_info("8 bits 3DC sensor found\n");
dev->read_data = lis3lv02d_read_8;
dev->mdps_max_val = 128;
dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
@@ -910,8 +911,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
dev->scale = LIS3_SENSITIVITY_8B;
break;
default:
- printk(KERN_ERR DRIVER_NAME
- ": unknown sensor type 0x%X\n", dev->whoami);
+ pr_err("unknown sensor type 0x%X\n", dev->whoami);
return -EINVAL;
}
@@ -935,7 +935,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
}
if (lis3lv02d_joystick_enable())
- printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
+ pr_err("joystick initialization failed\n");
/* passing in platform specific data is purely optional and only
* used by the SPI transport layer at the moment */
@@ -957,8 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
/* bail if we did not get an IRQ from the bus layer */
if (!dev->irq) {
- printk(KERN_ERR DRIVER_NAME
- ": No IRQ. Disabling /dev/freefall\n");
+ pr_err("No IRQ. Disabling /dev/freefall\n");
goto out;
}
@@ -985,12 +984,12 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
DRIVER_NAME, &lis3_dev);
if (err < 0) {
- printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n");
+ pr_err("Cannot get IRQ\n");
goto out;
}
if (misc_register(&lis3lv02d_misc_device))
- printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
+ pr_err("misc_register failed\n");
out:
return 0;
}
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
index 9f4bae07f719..8853afce85ce 100644
--- a/drivers/hwmon/lis3lv02d_i2c.c
+++ b/drivers/hwmon/lis3lv02d_i2c.c
@@ -186,7 +186,7 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int lis3lv02d_i2c_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -213,12 +213,9 @@ static int lis3lv02d_i2c_resume(struct device *dev)
return 0;
}
-#else
-#define lis3lv02d_i2c_suspend NULL
-#define lis3lv02d_i2c_resume NULL
-#define lis3lv02d_i2c_shutdown NULL
-#endif
+#endif /* CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM_RUNTIME
static int lis3_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -236,6 +233,7 @@ static int lis3_i2c_runtime_resume(struct device *dev)
lis3lv02d_poweron(lis3);
return 0;
}
+#endif /* CONFIG_PM_RUNTIME */
static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", 0 },
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index fd108cfc05c7..3b84fb503053 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -24,6 +24,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -67,8 +69,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
*/
status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
if (status < 0) {
- printk(KERN_WARNING
- "spi_write_then_read failed with status %d\n", status);
+ pr_warn("spi_write_then_read failed with status %d\n", status);
goto out;
}
raw = (rxbuf[0] << 8) + rxbuf[1];
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 72ff2c4e757d..4cb24eafe318 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -19,6 +19,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -858,7 +860,7 @@ static int __init lm78_isa_found(unsigned short address)
* individually for the probing phase. */
for (port = address; port < address + LM78_EXTENT; port++) {
if (!request_region(port, 1, "lm78")) {
- pr_debug("lm78: Failed to request port 0x%x\n", port);
+ pr_debug("Failed to request port 0x%x\n", port);
goto release;
}
}
@@ -920,7 +922,7 @@ static int __init lm78_isa_found(unsigned short address)
found = 1;
if (found)
- pr_info("lm78: Found an %s chip at %#x\n",
+ pr_info("Found an %s chip at %#x\n",
val & 0x80 ? "LM79" : "LM78", (int)address);
release:
@@ -942,21 +944,19 @@ static int __init lm78_isa_device_add(unsigned short address)
pdev = platform_device_alloc("lm78", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "lm78: Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
- printk(KERN_ERR "lm78: Device resource addition failed "
- "(%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR "lm78: Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 6669255aadcf..c9ed14eba5a6 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -20,7 +20,7 @@
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>
+ Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
This program is free software; you can redistribute it and/or modify
@@ -2629,7 +2629,7 @@ static void __exit lm93_exit(void)
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
- "Hans J. Koch <hjk@linutronix.de");
+ "Hans J. Koch <hjk@hansjkoch.de>");
MODULE_DESCRIPTION("LM93 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 464340f25496..1a6dfb6df1e7 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -1,13 +1,9 @@
/*
- * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware
- * monitoring
- * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com>
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
*
- * Based on the max1619 driver. The LM95241 is a sensor chip made by National
- * Semiconductors.
- * It reports up to three temperatures (its own plus up to
- * two external ones). Complete datasheet can be
- * obtained from National's website at:
+ * The LM95241 is a sensor chip made by National Semiconductors.
+ * It reports up to three temperatures (its own plus up to two external ones).
+ * Complete datasheet can be obtained from National's website at:
* http://www.national.com/ds.cgi/LM/LM95241.pdf
*
* This program is free software; you can redistribute it and/or modify
@@ -36,8 +32,10 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#define DEVNAME "lm95241"
+
static const unsigned short normal_i2c[] = {
- 0x19, 0x2a, 0x2b, I2C_CLIENT_END};
+ 0x19, 0x2a, 0x2b, I2C_CLIENT_END };
/* LM95241 registers */
#define LM95241_REG_R_MAN_ID 0xFE
@@ -46,7 +44,7 @@ static const unsigned short normal_i2c[] = {
#define LM95241_REG_RW_CONFIG 0x03
#define LM95241_REG_RW_REM_FILTER 0x06
#define LM95241_REG_RW_TRUTHERM 0x07
-#define LM95241_REG_W_ONE_SHOT 0x0F
+#define LM95241_REG_W_ONE_SHOT 0x0F
#define LM95241_REG_R_LOCAL_TEMPH 0x10
#define LM95241_REG_R_REMOTE1_TEMPH 0x11
#define LM95241_REG_R_REMOTE2_TEMPH 0x12
@@ -79,226 +77,246 @@ static const unsigned short normal_i2c[] = {
#define MANUFACTURER_ID 0x01
#define DEFAULT_REVISION 0xA4
-/* Conversions and various macros */
-#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \
- (val_h)) * 1000 + (val_l) * 1000 / 256)
-
-/* Functions declaration */
-static void lm95241_init_client(struct i2c_client *client);
-static struct lm95241_data *lm95241_update_device(struct device *dev);
+static const u8 lm95241_reg_address[] = {
+ LM95241_REG_R_LOCAL_TEMPH,
+ LM95241_REG_R_LOCAL_TEMPL,
+ LM95241_REG_R_REMOTE1_TEMPH,
+ LM95241_REG_R_REMOTE1_TEMPL,
+ LM95241_REG_R_REMOTE2_TEMPH,
+ LM95241_REG_R_REMOTE2_TEMPL
+};
/* Client data (each client gets its own) */
struct lm95241_data {
struct device *hwmon_dev;
struct mutex update_lock;
- unsigned long last_updated, interval; /* in jiffies */
- char valid; /* zero until following fields are valid */
+ unsigned long last_updated, interval; /* in jiffies */
+ char valid; /* zero until following fields are valid */
/* registers values */
- u8 local_h, local_l; /* local */
- u8 remote1_h, remote1_l; /* remote1 */
- u8 remote2_h, remote2_l; /* remote2 */
+ u8 temp[ARRAY_SIZE(lm95241_reg_address)];
u8 config, model, trutherm;
};
+/* Conversions */
+static int TempFromReg(u8 val_h, u8 val_l)
+{
+ if (val_h & 0x80)
+ return val_h - 0x100;
+ return val_h * 1000 + val_l * 1000 / 256;
+}
+
+static struct lm95241_data *lm95241_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + data->interval) ||
+ !data->valid) {
+ int i;
+
+ dev_dbg(&client->dev, "Updating lm95241 data.\n");
+ for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
+ data->temp[i]
+ = i2c_smbus_read_byte_data(client,
+ lm95241_reg_address[i]);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
/* Sysfs stuff */
-#define show_temp(value) \
-static ssize_t show_##value(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct lm95241_data *data = lm95241_update_device(dev); \
- snprintf(buf, PAGE_SIZE - 1, "%d\n", \
- TEMP_FROM_REG(data->value##_h, data->value##_l)); \
- return strlen(buf); \
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm95241_data *data = lm95241_update_device(dev);
+
+ return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+ TempFromReg(data->temp[to_sensor_dev_attr(attr)->index],
+ data->temp[to_sensor_dev_attr(attr)->index + 1]));
}
-show_temp(local);
-show_temp(remote1);
-show_temp(remote2);
-static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct lm95241_data *data = lm95241_update_device(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
- snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ);
- return strlen(buf);
+ return snprintf(buf, PAGE_SIZE - 1,
+ data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
}
-static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm95241_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ int shift;
+ u8 mask = to_sensor_dev_attr(attr)->index;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
+ if (val != 1 && val != 2)
+ return -EINVAL;
- strict_strtol(buf, 10, &data->interval);
- data->interval = data->interval * HZ / 1000;
+ shift = mask == R1MS_MASK ? TT1_SHIFT : TT2_SHIFT;
+
+ mutex_lock(&data->update_lock);
+
+ data->trutherm &= ~(TT_MASK << shift);
+ if (val == 1) {
+ data->model |= mask;
+ data->trutherm |= (TT_ON << shift);
+ } else {
+ data->model &= ~mask;
+ data->trutherm |= (TT_OFF << shift);
+ }
+ data->valid = 0;
+
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+ data->model);
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+ data->trutherm);
+
+ mutex_unlock(&data->update_lock);
return count;
}
-#define show_type(flag) \
-static ssize_t show_type##flag(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- snprintf(buf, PAGE_SIZE - 1, \
- data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \
- return strlen(buf); \
+static ssize_t show_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE - 1,
+ data->config & to_sensor_dev_attr(attr)->index ?
+ "-127000\n" : "0\n");
}
-show_type(1);
-show_type(2);
-
-#define show_min(flag) \
-static ssize_t show_min##flag(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- snprintf(buf, PAGE_SIZE - 1, \
- data->config & R##flag##DF_MASK ? \
- "-127000\n" : "0\n"); \
- return strlen(buf); \
+
+static ssize_t set_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
+ if (val < -128000)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ if (val < 0)
+ data->config |= to_sensor_dev_attr(attr)->index;
+ else
+ data->config &= ~to_sensor_dev_attr(attr)->index;
+ data->valid = 0;
+
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
}
-show_min(1);
-show_min(2);
-
-#define show_max(flag) \
-static ssize_t show_max##flag(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- snprintf(buf, PAGE_SIZE - 1, \
- data->config & R##flag##DF_MASK ? \
- "127000\n" : "255000\n"); \
- return strlen(buf); \
+
+static ssize_t show_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE - 1,
+ data->config & to_sensor_dev_attr(attr)->index ?
+ "127000\n" : "255000\n");
}
-show_max(1);
-show_max(2);
-
-#define set_type(flag) \
-static ssize_t set_type##flag(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- long val; \
- strict_strtol(buf, 10, &val); \
-\
- if ((val == 1) || (val == 2)) { \
-\
- mutex_lock(&data->update_lock); \
-\
- data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \
- if (val == 1) { \
- data->model |= R##flag##MS_MASK; \
- data->trutherm |= (TT_ON << TT##flag##_SHIFT); \
- } \
- else { \
- data->model &= ~R##flag##MS_MASK; \
- data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \
- } \
-\
- data->valid = 0; \
-\
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \
- data->model); \
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \
- data->trutherm); \
-\
- mutex_unlock(&data->update_lock); \
-\
- } \
- return count; \
+
+static ssize_t set_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
+ if (val >= 256000)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ if (val <= 127000)
+ data->config |= to_sensor_dev_attr(attr)->index;
+ else
+ data->config &= ~to_sensor_dev_attr(attr)->index;
+ data->valid = 0;
+
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
}
-set_type(1);
-set_type(2);
-
-#define set_min(flag) \
-static ssize_t set_min##flag(struct device *dev, \
- struct device_attribute *devattr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- long val; \
- strict_strtol(buf, 10, &val); \
-\
- mutex_lock(&data->update_lock); \
-\
- if (val < 0) \
- data->config |= R##flag##DF_MASK; \
- else \
- data->config &= ~R##flag##DF_MASK; \
-\
- data->valid = 0; \
-\
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
- data->config); \
-\
- mutex_unlock(&data->update_lock); \
-\
- return count; \
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm95241_data *data = lm95241_update_device(dev);
+
+ return snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval
+ / HZ);
}
-set_min(1);
-set_min(2);
-
-#define set_max(flag) \
-static ssize_t set_max##flag(struct device *dev, \
- struct device_attribute *devattr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm95241_data *data = i2c_get_clientdata(client); \
-\
- long val; \
- strict_strtol(buf, 10, &val); \
-\
- mutex_lock(&data->update_lock); \
-\
- if (val <= 127000) \
- data->config |= R##flag##DF_MASK; \
- else \
- data->config &= ~R##flag##DF_MASK; \
-\
- data->valid = 0; \
-\
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \
- data->config); \
-\
- mutex_unlock(&data->update_lock); \
-\
- return count; \
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95241_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ data->interval = val * HZ / 1000;
+
+ return count;
}
-set_max(1);
-set_max(2);
-
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL);
-static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL);
-static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1);
-static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1);
-static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1);
-static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ R1MS_MASK);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ R2MS_MASK);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min,
+ R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min,
+ R2DF_MASK);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max,
+ R1DF_MASK);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
+ R2DF_MASK);
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
static struct attribute *lm95241_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp2_type.attr,
- &dev_attr_temp3_type.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp3_min.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp3_max.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_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
&dev_attr_update_interval.attr,
NULL
};
@@ -320,9 +338,9 @@ static int lm95241_detect(struct i2c_client *new_client,
if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
== MANUFACTURER_ID)
- && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
- >= DEFAULT_REVISION)) {
- name = "lm95241";
+ && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+ >= DEFAULT_REVISION)) {
+ name = DEVNAME;
} else {
dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
address);
@@ -334,6 +352,25 @@ static int lm95241_detect(struct i2c_client *new_client,
return 0;
}
+static void lm95241_init_client(struct i2c_client *client)
+{
+ struct lm95241_data *data = i2c_get_clientdata(client);
+
+ data->interval = HZ; /* 1 sec default */
+ data->valid = 0;
+ data->config = CFG_CR0076;
+ data->model = 0;
+ data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
+
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
+ R1FE_MASK | R2FE_MASK);
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
+ data->trutherm);
+ i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
+ data->model);
+}
+
static int lm95241_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
@@ -373,26 +410,6 @@ exit:
return err;
}
-static void lm95241_init_client(struct i2c_client *client)
-{
- struct lm95241_data *data = i2c_get_clientdata(client);
-
- data->interval = HZ; /* 1 sec default */
- data->valid = 0;
- data->config = CFG_CR0076;
- data->model = 0;
- data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
-
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
- data->config);
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER,
- R1FE_MASK | R2FE_MASK);
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM,
- data->trutherm);
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL,
- data->model);
-}
-
static int lm95241_remove(struct i2c_client *client)
{
struct lm95241_data *data = i2c_get_clientdata(client);
@@ -404,46 +421,9 @@ static int lm95241_remove(struct i2c_client *client)
return 0;
}
-static struct lm95241_data *lm95241_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + data->interval) ||
- !data->valid) {
- dev_dbg(&client->dev, "Updating lm95241 data.\n");
- data->local_h =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_LOCAL_TEMPH);
- data->local_l =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_LOCAL_TEMPL);
- data->remote1_h =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_REMOTE1_TEMPH);
- data->remote1_l =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_REMOTE1_TEMPL);
- data->remote2_h =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_REMOTE2_TEMPH);
- data->remote2_l =
- i2c_smbus_read_byte_data(client,
- LM95241_REG_R_REMOTE2_TEMPL);
- data->last_updated = jiffies;
- data->valid = 1;
- }
-
- mutex_unlock(&data->update_lock);
-
- return data;
-}
-
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95241_id[] = {
- { "lm95241", 0 },
+ { DEVNAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95241_id);
@@ -451,7 +431,7 @@ MODULE_DEVICE_TABLE(i2c, lm95241_id);
static struct i2c_driver lm95241_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
- .name = "lm95241",
+ .name = DEVNAME,
},
.probe = lm95241_probe,
.remove = lm95241_remove,
@@ -470,7 +450,7 @@ static void __exit sensors_lm95241_exit(void)
i2c_del_driver(&lm95241_driver);
}
-MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>");
+MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
MODULE_DESCRIPTION("LM95241 sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 00d975eb5b83..c7e6d8e81656 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -205,7 +205,6 @@ LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS);
/* Power (virtual) */
LTC4215_POWER(power1_input);
-LTC4215_ALARM(power1_alarm, (1 << 3), LTC4215_STATUS);
/* Input Voltage */
LTC4215_VOLTAGE(in1_input, LTC4215_ADIN);
@@ -214,6 +213,7 @@ LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS);
/* Output Voltage */
LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE);
+LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS);
/* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
@@ -223,13 +223,13 @@ static struct attribute *ltc4215_attributes[] = {
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
- &sensor_dev_attr_power1_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
NULL,
};
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
index 267626178678..4b50601027d3 100644
--- a/drivers/hwmon/ltc4261.c
+++ b/drivers/hwmon/ltc4261.c
@@ -82,7 +82,7 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
val = i2c_smbus_read_byte_data(client, i);
if (unlikely(val < 0)) {
dev_dbg(dev,
- "Failed to read ADC value: error %d",
+ "Failed to read ADC value: error %d\n",
val);
ret = ERR_PTR(val);
goto abort;
@@ -230,8 +230,7 @@ static int ltc4261_probe(struct i2c_client *client,
return -ENODEV;
if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
- dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
- adapter->id, client->addr, LTC4261_STATUS);
+ dev_err(&client->dev, "Failed to read status register\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index a0160ee5caef..9a11532ecae8 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -2,7 +2,7 @@
* max6650.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring.
*
- * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
*
* based on code written by John Morris <john.morris@spirentcom.com>
* Copyright (c) 2003 Spirent Communications
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 68e69a49633c..3d99b8854d7c 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -33,6 +33,8 @@
* the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1031,16 +1033,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
val = superio_inb(sioaddr, ACT);
if (!(val & 0x01)) {
- printk(KERN_INFO "pc87360: Device 0x%02x not "
- "activated\n", logdev[i]);
+ pr_info("Device 0x%02x not activated\n", logdev[i]);
continue;
}
val = (superio_inb(sioaddr, BASE) << 8)
| superio_inb(sioaddr, BASE + 1);
if (!val) {
- printk(KERN_INFO "pc87360: Base address not set for "
- "device 0x%02x\n", logdev[i]);
+ pr_info("Base address not set for device 0x%02x\n",
+ logdev[i]);
continue;
}
@@ -1050,17 +1051,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
confreg[0] = superio_inb(sioaddr, 0xF0);
confreg[1] = superio_inb(sioaddr, 0xF1);
-#ifdef DEBUG
- printk(KERN_DEBUG "pc87360: Fan 1: mon=%d "
- "ctrl=%d inv=%d\n", (confreg[0]>>2)&1,
- (confreg[0]>>3)&1, (confreg[0]>>4)&1);
- printk(KERN_DEBUG "pc87360: Fan 2: mon=%d "
- "ctrl=%d inv=%d\n", (confreg[0]>>5)&1,
- (confreg[0]>>6)&1, (confreg[0]>>7)&1);
- printk(KERN_DEBUG "pc87360: Fan 3: mon=%d "
- "ctrl=%d inv=%d\n", confreg[1]&1,
- (confreg[1]>>1)&1, (confreg[1]>>2)&1);
-#endif
+ pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1,
+ (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1,
+ (confreg[0] >> 4) & 1);
+ pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2,
+ (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1,
+ (confreg[0] >> 7) & 1);
+ pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3,
+ confreg[1] & 1, (confreg[1] >> 1) & 1,
+ (confreg[1] >> 2) & 1);
} else if (i==1) { /* Voltages */
/* Are we using thermistors? */
if (*devid == 0xE9) { /* PC87366 */
@@ -1071,14 +1070,12 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
confreg[3] = superio_inb(sioaddr, 0x25);
if (confreg[2] & 0x40) {
- printk(KERN_INFO "pc87360: Using "
- "thermistors for temperature "
- "monitoring\n");
+ pr_info("Using thermistors for "
+ "temperature monitoring\n");
}
if (confreg[3] & 0xE0) {
- printk(KERN_INFO "pc87360: VID "
- "inputs routed (mode %u)\n",
- confreg[3] >> 5);
+ pr_info("VID inputs routed (mode %u)\n",
+ confreg[3] >> 5);
}
}
}
@@ -1616,7 +1613,7 @@ static int __init pc87360_device_add(unsigned short address)
pdev = platform_device_alloc("pc87360", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "pc87360: Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
@@ -1639,15 +1636,13 @@ static int __init pc87360_device_add(unsigned short address)
err = platform_device_add_resources(pdev, res, res_count);
if (err) {
- printk(KERN_ERR "pc87360: Device resources addition failed "
- "(%d)\n", err);
+ pr_err("Device resources addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
@@ -1666,8 +1661,7 @@ static int __init pc87360_init(void)
if (pc87360_find(0x2e, &devid, extra_isa)
&& pc87360_find(0x4e, &devid, extra_isa)) {
- printk(KERN_WARNING "pc87360: PC8736x not detected, "
- "module not inserted.\n");
+ pr_warn("PC8736x not detected, module not inserted\n");
return -ENODEV;
}
@@ -1680,8 +1674,7 @@ static int __init pc87360_init(void)
}
if (address == 0x0000) {
- printk(KERN_WARNING "pc87360: No active logical device, "
- "module not inserted.\n");
+ pr_warn("No active logical device, module not inserted\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 9ec4daaf6ca6..8da2181630b1 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -22,6 +22,8 @@
* mode, and voltages aren't supported at all.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1077,7 +1079,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Out of memory\n");
+ pr_err("Out of memory\n");
goto exit;
}
@@ -1196,28 +1198,26 @@ static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data)
pdev = platform_device_alloc(DRVNAME, res[0].start);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, res, res_count);
if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add_data(pdev, sio_data,
sizeof(struct pc87427_sio_data));
if (err) {
- printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
@@ -1249,23 +1249,23 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
val = superio_inb(sioaddr, SIOREG_ACT);
if (!(val & 0x01)) {
- printk(KERN_INFO DRVNAME ": Logical device 0x%02x "
- "not activated\n", logdev[i]);
+ pr_info("Logical device 0x%02x not activated\n",
+ logdev[i]);
continue;
}
val = superio_inb(sioaddr, SIOREG_MAP);
if (val & 0x01) {
- printk(KERN_WARNING DRVNAME ": Logical device 0x%02x "
- "is memory-mapped, can't use\n", logdev[i]);
+ pr_warn("Logical device 0x%02x is memory-mapped, "
+ "can't use\n", logdev[i]);
continue;
}
val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
| superio_inb(sioaddr, SIOREG_IOBASE + 1);
if (!val) {
- printk(KERN_INFO DRVNAME ": I/O base address not set "
- "for logical device 0x%02x\n", logdev[i]);
+ pr_info("I/O base address not set for logical device "
+ "0x%02x\n", logdev[i]);
continue;
}
sio_data->address[i] = val;
diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c
index dc7259d69812..731b09af76b9 100644
--- a/drivers/hwmon/pcf8591.c
+++ b/drivers/hwmon/pcf8591.c
@@ -18,6 +18,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -290,8 +292,7 @@ static struct i2c_driver pcf8591_driver = {
static int __init pcf8591_init(void)
{
if (input_mode < 0 || input_mode > 3) {
- printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n",
- input_mode);
+ pr_warn("invalid input_mode (%d)\n", input_mode);
input_mode = 0;
}
return i2c_add_driver(&pcf8591_driver);
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
index 0798210590bc..21c817d98123 100644
--- a/drivers/hwmon/pkgtemp.c
+++ b/drivers/hwmon/pkgtemp.c
@@ -20,6 +20,8 @@
* 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -303,7 +305,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
pdev = platform_device_alloc(DRVNAME, cpu);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
@@ -315,8 +317,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_free;
}
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index 05248f2d7581..92b42db43bcf 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -234,7 +234,6 @@ static int s3c_hwmon_create_attr(struct device *dev,
attr->index = channel;
attr->dev_attr.attr.name = attrs->in_name;
attr->dev_attr.attr.mode = S_IRUGO;
- attr->dev_attr.attr.owner = THIS_MODULE;
attr->dev_attr.show = s3c_hwmon_ch_show;
ret = device_create_file(dev, &attr->dev_attr);
@@ -252,7 +251,6 @@ static int s3c_hwmon_create_attr(struct device *dev,
attr->index = channel;
attr->dev_attr.attr.name = attrs->label_name;
attr->dev_attr.attr.mode = S_IRUGO;
- attr->dev_attr.attr.owner = THIS_MODULE;
attr->dev_attr.show = s3c_hwmon_label_show;
ret = device_create_file(dev, &attr->dev_attr);
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
new file mode 100644
index 000000000000..1c8c9812f244
--- /dev/null
+++ b/drivers/hwmon/sht21.c
@@ -0,0 +1,307 @@
+/* Sensirion SHT21 humidity and temperature sensor driver
+ *
+ * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Data sheet available (5/2010) at
+ * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+ */
+
+#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>
+#include <linux/device.h>
+
+/* I2C command bytes */
+#define SHT21_TRIG_T_MEASUREMENT_HM 0xe3
+#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
+
+/**
+ * struct sht21 - SHT21 device specific data
+ * @hwmon_dev: device registered with hwmon
+ * @lock: mutex to protect measurement values
+ * @valid: only 0 before first measurement is taken
+ * @last_update: time of last update (jiffies)
+ * @temperature: cached temperature measurement value
+ * @humidity: cached humidity measurement value
+ */
+struct sht21 {
+ struct device *hwmon_dev;
+ struct mutex lock;
+ char valid;
+ unsigned long last_update;
+ int temperature;
+ int humidity;
+};
+
+/**
+ * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to
+ * milli celsius
+ * @ticks: temperature ticks value received from sensor
+ */
+static inline int sht21_temp_ticks_to_millicelsius(int ticks)
+{
+ ticks &= ~0x0003; /* clear status bits */
+ /*
+ * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
+ * optimized for integer fixed point (3 digits) arithmetic
+ */
+ return ((21965 * ticks) >> 13) - 46850;
+}
+
+/**
+ * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
+ * one-thousandths of a percent relative humidity
+ * @ticks: humidity ticks value received from sensor
+ */
+static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
+{
+ ticks &= ~0x0003; /* clear status bits */
+ /*
+ * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
+ * optimized for integer fixed point (3 digits) arithmetic
+ */
+ return ((15625 * ticks) >> 13) - 6000;
+}
+
+/**
+ * sht21_read_word_data() - read word from register
+ * @client: I2C client device
+ * @reg: I2C command byte
+ *
+ * Returns value, negative errno on error.
+ */
+static inline int sht21_read_word_data(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+ /*
+ * SMBus specifies low byte first, but the SHT21 returns MSB
+ * first, so we have to swab16 the values
+ */
+ return swab16(ret);
+}
+
+/**
+ * sht21_update_measurements() - get updated measurements from device
+ * @client: I2C client device
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int sht21_update_measurements(struct i2c_client *client)
+{
+ int ret = 0;
+ struct sht21 *sht21 = i2c_get_clientdata(client);
+
+ mutex_lock(&sht21->lock);
+ /*
+ * Data sheet 2.4:
+ * SHT2x should not be active for more than 10% of the time - e.g.
+ * maximum two measurements per second at 12bit accuracy shall be made.
+ */
+ if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) {
+ ret = sht21_read_word_data(client, SHT21_TRIG_T_MEASUREMENT_HM);
+ if (ret < 0)
+ goto out;
+ sht21->temperature = sht21_temp_ticks_to_millicelsius(ret);
+ ret = sht21_read_word_data(client,
+ SHT21_TRIG_RH_MEASUREMENT_HM);
+ if (ret < 0)
+ goto out;
+ sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret);
+ sht21->last_update = jiffies;
+ sht21->valid = 1;
+ }
+out:
+ mutex_unlock(&sht21->lock);
+
+ return ret >= 0 ? 0 : ret;
+}
+
+/**
+ * sht21_show_temperature() - show temperature measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
+ *
+ * Will be called on read access to temp1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht21_show_temperature(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct sht21 *sht21 = i2c_get_clientdata(client);
+ int ret = sht21_update_measurements(client);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%d\n", sht21->temperature);
+}
+
+/**
+ * sht21_show_humidity() - show humidity measurement value in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
+ *
+ * Will be called on read access to humidity1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht21_show_humidity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct sht21 *sht21 = i2c_get_clientdata(client);
+ int ret = sht21_update_measurements(client);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%d\n", sht21->humidity);
+}
+
+/* sysfs attributes */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
+ NULL, 0);
+
+static struct attribute *sht21_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_humidity1_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group sht21_attr_group = {
+ .attrs = sht21_attributes,
+};
+
+/**
+ * sht21_probe() - probe device
+ * @client: I2C client device
+ * @id: device ID
+ *
+ * Called by the I2C core when an entry in the ID table matches a
+ * device's name.
+ * Returns 0 on success.
+ */
+static int __devinit sht21_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct sht21 *sht21;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(&client->dev,
+ "adapter does not support SMBus word transactions\n");
+ return -ENODEV;
+ }
+
+ sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
+ if (!sht21) {
+ dev_dbg(&client->dev, "kzalloc failed\n");
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(client, sht21);
+
+ mutex_init(&sht21->lock);
+
+ err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
+ if (err) {
+ dev_dbg(&client->dev, "could not create sysfs files\n");
+ goto fail_free;
+ }
+ sht21->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(sht21->hwmon_dev)) {
+ dev_dbg(&client->dev, "unable to register hwmon device\n");
+ err = PTR_ERR(sht21->hwmon_dev);
+ goto fail_remove_sysfs;
+ }
+
+ dev_info(&client->dev, "initialized\n");
+
+ return 0;
+
+fail_remove_sysfs:
+ sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
+fail_free:
+ kfree(sht21);
+
+ return err;
+}
+
+/**
+ * sht21_remove() - remove device
+ * @client: I2C client device
+ */
+static int __devexit sht21_remove(struct i2c_client *client)
+{
+ struct sht21 *sht21 = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(sht21->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
+ kfree(sht21);
+
+ return 0;
+}
+
+/* Device ID table */
+static const struct i2c_device_id sht21_id[] = {
+ { "sht21", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sht21_id);
+
+static struct i2c_driver sht21_driver = {
+ .driver.name = "sht21",
+ .probe = sht21_probe,
+ .remove = __devexit_p(sht21_remove),
+ .id_table = sht21_id,
+};
+
+/**
+ * sht21_init() - initialize driver
+ *
+ * Called when kernel is booted or module is inserted.
+ * Returns 0 on success.
+ */
+static int __init sht21_init(void)
+{
+ return i2c_add_driver(&sht21_driver);
+}
+module_init(sht21_init);
+
+/**
+ * sht21_init() - clean up driver
+ *
+ * Called when module is removed.
+ */
+static void __exit sht21_exit(void)
+{
+ i2c_del_driver(&sht21_driver);
+}
+module_exit(sht21_exit);
+
+MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>");
+MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 79c2931e3008..47d7ce9af8fb 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -50,6 +50,8 @@
735 0008 0735
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
@@ -735,21 +737,19 @@ static int __devinit sis5595_device_add(unsigned short address)
pdev = platform_device_alloc("sis5595", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "sis5595: Device allocation failed\n");
+ pr_err("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);
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index f46d936c12da..9fb7516e6f45 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -26,6 +26,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
@@ -311,21 +313,19 @@ static int __init smsc47b397_device_add(unsigned short address)
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("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);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
@@ -367,8 +367,7 @@ static int __init smsc47b397_find(unsigned short *addr)
*addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
| superio_inb(SUPERIO_REG_BASE_LSB);
- printk(KERN_INFO DRVNAME ": found SMSC %s "
- "(base address 0x%04x, revision %u)\n",
+ pr_info("found SMSC %s (base address 0x%04x, revision %u)\n",
name, *addr, rev);
superio_exit();
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 8fa462f2b570..f44a89aac381 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -26,6 +26,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
@@ -435,30 +437,29 @@ static int __init smsc47m1_find(unsigned short *addr,
*/
switch (val) {
case 0x51:
- pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
+ pr_info("Found SMSC LPC47B27x\n");
sio_data->type = smsc47m1;
break;
case 0x59:
- pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
+ pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
sio_data->type = smsc47m1;
break;
case 0x5F:
- pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
+ pr_info("Found SMSC LPC47M14x\n");
sio_data->type = smsc47m1;
break;
case 0x60:
- pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
+ pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
sio_data->type = smsc47m1;
break;
case 0x6B:
if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
- pr_debug(DRVNAME ": "
- "Found SMSC LPC47M233, unsupported\n");
+ pr_debug("Found SMSC LPC47M233, unsupported\n");
superio_exit();
return -ENODEV;
}
- pr_info(DRVNAME ": Found SMSC LPC47M292\n");
+ pr_info("Found SMSC LPC47M292\n");
sio_data->type = smsc47m2;
break;
default:
@@ -470,7 +471,7 @@ static int __init smsc47m1_find(unsigned short *addr,
*addr = (superio_inb(SUPERIO_REG_BASE) << 8)
| superio_inb(SUPERIO_REG_BASE + 1);
if (*addr == 0) {
- pr_info(DRVNAME ": Device address not set, will not use\n");
+ pr_info("Device address not set, will not use\n");
superio_exit();
return -ENODEV;
}
@@ -479,7 +480,7 @@ static int __init smsc47m1_find(unsigned short *addr,
* Compaq Presario S4000NX) */
sio_data->activate = superio_inb(SUPERIO_REG_ACT);
if ((sio_data->activate & 0x01) == 0) {
- pr_info(DRVNAME ": Enabling device\n");
+ pr_info("Enabling device\n");
superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
}
@@ -494,7 +495,7 @@ static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
superio_enter();
superio_select();
- pr_info(DRVNAME ": Disabling device\n");
+ pr_info("Disabling device\n");
superio_outb(SUPERIO_REG_ACT, sio_data->activate);
superio_exit();
@@ -823,28 +824,26 @@ static int __init smsc47m1_device_add(unsigned short address,
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("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);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add_data(pdev, sio_data,
sizeof(struct smsc47m1_sio_data));
if (err) {
- printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index ec7fad747adc..0d18de424c66 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -21,6 +21,8 @@
* 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -202,7 +204,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu)
pdev = platform_device_alloc(DRVNAME, cpu);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
@@ -214,8 +216,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu)
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_free;
}
@@ -237,13 +238,16 @@ exit:
static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
{
- struct pdev_entry *p, *n;
+ struct pdev_entry *p;
+
mutex_lock(&pdev_list_mutex);
- list_for_each_entry_safe(p, n, &pdev_list, list) {
+ list_for_each_entry(p, &pdev_list, list) {
if (p->cpu == cpu) {
platform_device_unregister(p->pdev);
list_del(&p->list);
+ mutex_unlock(&pdev_list_mutex);
kfree(p);
+ return;
}
}
mutex_unlock(&pdev_list_mutex);
@@ -273,7 +277,6 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = {
static int __init via_cputemp_init(void)
{
int i, err;
- struct pdev_entry *p, *n;
if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
@@ -295,33 +298,27 @@ static int __init via_cputemp_init(void)
continue;
if (c->x86_model > 0x0f) {
- printk(KERN_WARNING DRVNAME ": Unknown CPU "
- "model 0x%x\n", c->x86_model);
+ pr_warn("Unknown CPU model 0x%x\n", c->x86_model);
continue;
}
- err = via_cputemp_device_add(i);
- if (err)
- goto exit_devices_unreg;
+ via_cputemp_device_add(i);
}
+
+#ifndef CONFIG_HOTPLUG_CPU
if (list_empty(&pdev_list)) {
err = -ENODEV;
goto exit_driver_unreg;
}
+#endif
register_hotcpu_notifier(&via_cputemp_cpu_notifier);
return 0;
-exit_devices_unreg:
- mutex_lock(&pdev_list_mutex);
- list_for_each_entry_safe(p, n, &pdev_list, list) {
- platform_device_unregister(p->pdev);
- list_del(&p->list);
- kfree(p);
- }
- mutex_unlock(&pdev_list_mutex);
+#ifndef CONFIG_HOTPLUG_CPU
exit_driver_unreg:
platform_driver_unregister(&via_cputemp_driver);
+#endif
exit:
return err;
}
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index f397ce7ad598..25e91665a0a2 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -30,6 +30,8 @@
Warning - only supports a single device.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
@@ -687,6 +689,13 @@ static int __devexit via686a_remove(struct platform_device *pdev)
return 0;
}
+static void via686a_update_fan_div(struct via686a_data *data)
+{
+ int reg = via686a_read_value(data, VIA686A_REG_FANDIV);
+ data->fan_div[0] = (reg >> 4) & 0x03;
+ data->fan_div[1] = reg >> 6;
+}
+
static void __devinit via686a_init_device(struct via686a_data *data)
{
u8 reg;
@@ -700,6 +709,9 @@ static void __devinit via686a_init_device(struct via686a_data *data)
via686a_write_value(data, VIA686A_REG_TEMP_MODE,
(reg & ~VIA686A_TEMP_MODE_MASK)
| VIA686A_TEMP_MODE_CONTINUOUS);
+
+ /* Pre-read fan clock divisor values */
+ via686a_update_fan_div(data);
}
static struct via686a_data *via686a_update_device(struct device *dev)
@@ -751,9 +763,7 @@ static struct via686a_data *via686a_update_device(struct device *dev)
(via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0xc0) >> 6;
- i = via686a_read_value(data, VIA686A_REG_FANDIV);
- data->fan_div[0] = (i >> 4) & 0x03;
- data->fan_div[1] = i >> 6;
+ via686a_update_fan_div(data);
data->alarms =
via686a_read_value(data,
VIA686A_REG_ALARM1) |
@@ -791,21 +801,19 @@ static int __devinit via686a_device_add(unsigned short address)
pdev = platform_device_alloc("via686a", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "via686a: Device allocation failed\n");
+ pr_err("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);
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index ae33bbb577c7..49163d48e966 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1254,8 +1256,7 @@ static int __init vt1211_device_add(unsigned short address)
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",
- err);
+ pr_err("Device allocation failed (%d)\n", err);
goto EXIT;
}
@@ -1266,15 +1267,13 @@ static int __init vt1211_device_add(unsigned short address)
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto EXIT_DEV_PUT;
}
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto EXIT_DEV_PUT;
}
@@ -1301,23 +1300,20 @@ static int __init vt1211_find(int sio_cip, unsigned short *address)
superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
- printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
- "skipping\n");
+ pr_warn("HW monitor is disabled, skipping\n");
goto EXIT;
}
*address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
(superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
if (*address == 0) {
- printk(KERN_WARNING DRVNAME ": Base address is not set, "
- "skipping\n");
+ pr_warn("Base address is not set, skipping\n");
goto EXIT;
}
err = 0;
- printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
- "revision %u\n", *address,
- superio_inb(sio_cip, SIO_VT1211_DEVREV));
+ pr_info("Found VT1211 chip at 0x%04x, revision %u\n",
+ *address, superio_inb(sio_cip, SIO_VT1211_DEVREV));
EXIT:
superio_exit(sio_cip);
@@ -1336,15 +1332,15 @@ static int __init vt1211_init(void)
if ((uch_config < -1) || (uch_config > 31)) {
err = -EINVAL;
- printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "
- "Choose a value between 0 and 31.\n", uch_config);
+ pr_warn("Invalid UCH configuration %d. "
+ "Choose a value between 0 and 31.\n", uch_config);
goto EXIT;
}
if ((int_mode < -1) || (int_mode > 0)) {
err = -EINVAL;
- printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "
- "Only mode 0 is supported.\n", int_mode);
+ pr_warn("Invalid interrupt mode %d. "
+ "Only mode 0 is supported.\n", int_mode);
goto EXIT;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index e6078c9f0e27..db3b2e8d2a67 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -24,6 +24,8 @@
/* Supports VIA VT8231 South Bridge embedded sensors
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -902,21 +904,19 @@ static int __devinit vt8231_device_add(unsigned short address)
pdev = platform_device_alloc("vt8231", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "vt8231: Device allocation failed\n");
+ pr_err("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);
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 072c58008a63..073eabedc432 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -42,6 +42,8 @@
w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1668,8 +1670,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
break;
default:
if (val != 0xffff)
- pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
- val);
+ pr_debug("unsupported chip ID: 0x%04x\n", val);
superio_exit(sioaddr);
return -ENODEV;
}
@@ -1680,8 +1681,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
| superio_inb(sioaddr, SIO_REG_ADDR + 1);
*addr = val & IOREGION_ALIGNMENT;
if (*addr == 0) {
- printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
- "device with a base I/O port 0.\n");
+ pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
superio_exit(sioaddr);
return -ENODEV;
}
@@ -1689,13 +1689,12 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
/* Activate logical device if needed */
val = superio_inb(sioaddr, SIO_REG_ENABLE);
if (!(val & 0x01)) {
- printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
- "Sensor is probably unusable.\n");
+ pr_warn("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);
+ pr_info("Found %s chip at %#x\n", sio_name, *addr);
sio_data->sioreg = sioaddr;
return 0;
@@ -1729,14 +1728,14 @@ static int __init sensors_w83627ehf_init(void)
if (!(pdev = platform_device_alloc(DRVNAME, address))) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("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");
+ pr_err("Platform data allocation failed\n");
goto exit_device_put;
}
@@ -1752,16 +1751,14 @@ static int __init sensors_w83627ehf_init(void)
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 38e280523071..bde50e34d013 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -39,6 +39,8 @@
supported yet.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1166,14 +1168,13 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
superio_inb(sio_data, WINB_BASE_REG + 1);
*addr = val & WINB_ALIGNMENT;
if (*addr == 0) {
- printk(KERN_WARNING DRVNAME ": Base address not set, "
- "skipping\n");
+ pr_warn("Base address not set, skipping\n");
goto exit;
}
val = superio_inb(sio_data, WINB_ACT_REG);
if (!(val & 0x01)) {
- printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+ pr_warn("Enabling HWM logical device\n");
superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
}
@@ -1789,28 +1790,26 @@ static int __init w83627hf_device_add(unsigned short address,
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ pr_err("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);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add_data(pdev, sio_data,
sizeof(struct w83627hf_sio_data));
if (err) {
- printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ pr_err("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);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index c84b9b4e6960..eed43a008be1 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -33,6 +33,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1798,8 +1800,7 @@ w83781d_isa_found(unsigned short address)
* individually for the probing phase. */
for (port = address; port < address + W83781D_EXTENT; port++) {
if (!request_region(port, 1, "w83781d")) {
- pr_debug("w83781d: Failed to request port 0x%x\n",
- port);
+ pr_debug("Failed to request port 0x%x\n", port);
goto release;
}
}
@@ -1811,7 +1812,7 @@ w83781d_isa_found(unsigned short address)
if (inb_p(address + 2) != val
|| inb_p(address + 3) != val
|| inb_p(address + 7) != val) {
- pr_debug("w83781d: Detection failed at step 1\n");
+ pr_debug("Detection failed at step %d\n", 1);
goto release;
}
#undef REALLY_SLOW_IO
@@ -1820,14 +1821,14 @@ w83781d_isa_found(unsigned short address)
MSB (busy flag) should be clear initially, set after the write. */
save = inb_p(address + W83781D_ADDR_REG_OFFSET);
if (save & 0x80) {
- pr_debug("w83781d: Detection failed at step 2\n");
+ pr_debug("Detection failed at step %d\n", 2);
goto release;
}
val = ~save & 0x7f;
outb_p(val, address + W83781D_ADDR_REG_OFFSET);
if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
outb_p(save, address + W83781D_ADDR_REG_OFFSET);
- pr_debug("w83781d: Detection failed at step 3\n");
+ pr_debug("Detection failed at step %d\n", 3);
goto release;
}
@@ -1835,7 +1836,7 @@ w83781d_isa_found(unsigned short address)
outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
val = inb_p(address + W83781D_DATA_REG_OFFSET);
if (val & 0x80) {
- pr_debug("w83781d: Detection failed at step 4\n");
+ pr_debug("Detection failed at step %d\n", 4);
goto release;
}
outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
@@ -1844,19 +1845,19 @@ w83781d_isa_found(unsigned short address)
val = inb_p(address + W83781D_DATA_REG_OFFSET);
if ((!(save & 0x80) && (val != 0xa3))
|| ((save & 0x80) && (val != 0x5c))) {
- pr_debug("w83781d: Detection failed at step 5\n");
+ pr_debug("Detection failed at step %d\n", 5);
goto release;
}
outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
val = inb_p(address + W83781D_DATA_REG_OFFSET);
if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
- pr_debug("w83781d: Detection failed at step 6\n");
+ pr_debug("Detection failed at step %d\n", 6);
goto release;
}
/* The busy flag should be clear again */
if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
- pr_debug("w83781d: Detection failed at step 7\n");
+ pr_debug("Detection failed at step %d\n", 7);
goto release;
}
@@ -1871,7 +1872,7 @@ w83781d_isa_found(unsigned short address)
found = 1;
if (found)
- pr_info("w83781d: Found a %s chip at %#x\n",
+ pr_info("Found a %s chip at %#x\n",
val == 0x30 ? "W83782D" : "W83781D", (int)address);
release:
@@ -1894,21 +1895,19 @@ w83781d_isa_device_add(unsigned short address)
pdev = platform_device_alloc("w83781d", address);
if (!pdev) {
err = -ENOMEM;
- printk(KERN_ERR "w83781d: Device allocation failed\n");
+ pr_err("Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
- printk(KERN_ERR "w83781d: Device resource addition failed "
- "(%d)\n", err);
+ pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
- printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
- err);
+ pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 679718e6b017..63841f8cec07 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -691,7 +691,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-show_regs_chassis(struct device *dev, struct device_attribute *attr,
+show_chassis(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct w83792d_data *data = w83792d_update_device(dev);
@@ -699,6 +699,16 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+show_regs_chassis(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ dev_warn(dev,
+ "Attribute %s is deprecated, use intrusion0_alarm instead\n",
+ "chassis");
+ return show_chassis(dev, attr, buf);
+}
+
+static ssize_t
show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83792d_data *data = w83792d_update_device(dev);
@@ -706,7 +716,7 @@ show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
-store_chassis_clear(struct device *dev, struct device_attribute *attr,
+store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -714,6 +724,10 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
u32 val;
u8 temp1 = 0, temp2 = 0;
+ dev_warn(dev,
+ "Attribute %s is deprecated, use intrusion0_alarm instead\n",
+ "chassis_clear");
+
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
@@ -726,6 +740,27 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t
+store_chassis_clear(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ u8 reg;
+
+ if (strict_strtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ reg = w83792d_read_value(client, W83792D_REG_CHASSIS_CLR);
+ w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, reg | 0x80);
+ data->valid = 0; /* Force cache refresh */
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
/* For Smart Fan I / Thermal Cruise */
static ssize_t
show_thermal_cruise(struct device *dev, struct device_attribute *attr,
@@ -1012,7 +1047,9 @@ static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
- show_chassis_clear, store_chassis_clear);
+ show_chassis_clear, store_chassis_clear_legacy);
+static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
+ show_chassis, store_chassis_clear);
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 SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
@@ -1214,6 +1251,7 @@ static struct attribute *w83792d_attributes[] = {
&dev_attr_alarms.attr,
&dev_attr_chassis.attr,
&dev_attr_chassis_clear.attr,
+ &dev_attr_intrusion0_alarm.attr,
&sensor_dev_attr_tolerance1.dev_attr.attr,
&sensor_dev_attr_thermal_cruise1.dev_attr.attr,
&sensor_dev_attr_tolerance2.dev_attr.attr,
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 8e540ada47d2..e3bdedfb5347 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -51,7 +51,6 @@
#define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */
/* Addresses to scan */
-static DEFINE_MUTEX(watchdog_mutex);
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
I2C_CLIENT_END };
@@ -421,14 +420,17 @@ store_beep_enable(struct device *dev, struct device_attribute *attr,
/* Write any value to clear chassis alarm */
static ssize_t
-store_chassis_clear(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
+store_chassis_clear_legacy(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83793_data *data = i2c_get_clientdata(client);
u8 val;
+ dev_warn(dev, "Attribute chassis is deprecated, "
+ "use intrusion0_alarm instead\n");
+
mutex_lock(&data->update_lock);
val = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
val |= 0x80;
@@ -437,6 +439,28 @@ store_chassis_clear(struct device *dev,
return count;
}
+/* Write 0 to clear chassis alarm */
+static ssize_t
+store_chassis_clear(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ u8 reg;
+
+ if (strict_strtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
+ w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80);
+ data->valid = 0; /* Force cache refresh */
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
#define FAN_INPUT 0
#define FAN_MIN 1
static ssize_t
@@ -1102,6 +1126,8 @@ static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
static struct sensor_device_attribute_2 sda_single_files[] = {
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
+ store_chassis_clear_legacy, ALARM_STATUS, 30),
+ SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 30),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
store_beep_enable, NOT_USED, NOT_USED),
@@ -1323,7 +1349,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
static long watchdog_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
- static struct watchdog_info ident = {
+ struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_CARDRESET,
@@ -1333,7 +1359,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd,
int val, ret = 0;
struct w83793_data *data = filp->private_data;
- mutex_lock(&watchdog_mutex);
switch (cmd) {
case WDIOC_GETSUPPORT:
if (!nowayout)
@@ -1387,7 +1412,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd,
default:
ret = -ENOTTY;
}
- mutex_unlock(&watchdog_mutex);
return ret;
}
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index 1d840aa83782..845232d7f611 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -165,10 +165,14 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = {
#define W83795_REG_VID_CTRL 0x6A
+#define W83795_REG_ALARM_CTRL 0x40
+#define ALARM_CTRL_RTSACS (1 << 7)
#define W83795_REG_ALARM(index) (0x41 + (index))
+#define W83795_REG_CLR_CHASSIS 0x4D
#define W83795_REG_BEEP(index) (0x50 + (index))
-#define W83795_REG_CLR_CHASSIS 0x4D
+#define W83795_REG_OVT_CFG 0x58
+#define OVT_CFG_SEL (1 << 7)
#define W83795_REG_FCMS1 0x201
@@ -178,6 +182,14 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = {
#define W83795_REG_TSS(index) (0x209 + (index))
+#define TSS_MAP_RESERVED 0xff
+static const u8 tss_map[4][6] = {
+ { 0, 1, 2, 3, 4, 5},
+ { 6, 7, 8, 9, 0, 1},
+ {10, 11, 12, 13, 2, 3},
+ { 4, 5, 4, 5, TSS_MAP_RESERVED, TSS_MAP_RESERVED},
+};
+
#define PWM_OUTPUT 0
#define PWM_FREQ 1
#define PWM_START 2
@@ -369,6 +381,7 @@ struct w83795_data {
u8 setup_pwm[3]; /* Register value */
u8 alarms[6]; /* Register value */
+ u8 enable_beep;
u8 beeps[6]; /* Register value */
char valid;
@@ -445,6 +458,7 @@ static void w83795_update_limits(struct i2c_client *client)
{
struct w83795_data *data = i2c_get_clientdata(client);
int i, limit;
+ u8 lsb;
/* Read the voltage limits */
for (i = 0; i < ARRAY_SIZE(data->in); i++) {
@@ -466,9 +480,8 @@ static void w83795_update_limits(struct i2c_client *client)
}
/* Read the fan limits */
+ lsb = 0; /* Silent false gcc warning */
for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
- u8 lsb;
-
/* Each register contains LSB for 2 fans, but we want to
* read it only once to save time */
if ((i & 1) == 0 && (data->has_fan & (3 << i)))
@@ -499,8 +512,11 @@ static void w83795_update_limits(struct i2c_client *client)
}
/* Read beep settings */
- for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
- data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i));
+ if (data->enable_beep) {
+ for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
+ data->beeps[i] =
+ w83795_read(client, W83795_REG_BEEP(i));
+ }
data->valid_limits = 1;
}
@@ -577,6 +593,7 @@ static struct w83795_data *w83795_update_device(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u16 tmp;
+ u8 intrusion;
int i;
mutex_lock(&data->update_lock);
@@ -648,9 +665,24 @@ static struct w83795_data *w83795_update_device(struct device *dev)
w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
}
- /* update alarm */
+ /* Update intrusion and alarms
+ * It is important to read intrusion first, because reading from
+ * register SMI STS6 clears the interrupt status temporarily. */
+ tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
+ /* Switch to interrupt status for intrusion if needed */
+ if (tmp & ALARM_CTRL_RTSACS)
+ w83795_write(client, W83795_REG_ALARM_CTRL,
+ tmp & ~ALARM_CTRL_RTSACS);
+ intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6);
+ /* Switch to real-time alarms */
+ w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS);
for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
+ data->alarms[5] |= intrusion;
+ /* Restore original configuration if needed */
+ if (!(tmp & ALARM_CTRL_RTSACS))
+ w83795_write(client, W83795_REG_ALARM_CTRL,
+ tmp & ~ALARM_CTRL_RTSACS);
data->last_updated = jiffies;
data->valid = 1;
@@ -730,6 +762,10 @@ store_chassis_clear(struct device *dev,
val = w83795_read(client, W83795_REG_CLR_CHASSIS);
val |= 0x80;
w83795_write(client, W83795_REG_CLR_CHASSIS, val);
+
+ /* Clear status and force cache refresh */
+ w83795_read(client, W83795_REG_ALARM(5));
+ data->valid = 0;
mutex_unlock(&data->update_lock);
return count;
}
@@ -857,20 +893,20 @@ show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
int index = sensor_attr->index;
u8 tmp;
- if (1 == (data->pwm_fcms[0] & (1 << index))) {
+ /* Speed cruise mode */
+ if (data->pwm_fcms[0] & (1 << index)) {
tmp = 2;
goto out;
}
+ /* Thermal cruise or SmartFan IV mode */
for (tmp = 0; tmp < 6; tmp++) {
if (data->pwm_tfmr[tmp] & (1 << index)) {
tmp = 3;
goto out;
}
}
- if (data->pwm_fomc & (1 << index))
- tmp = 0;
- else
- tmp = 1;
+ /* Manual mode */
+ tmp = 1;
out:
return sprintf(buf, "%u\n", tmp);
@@ -890,23 +926,21 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
if (strict_strtoul(buf, 10, &val) < 0)
return -EINVAL;
- if (val > 2)
+ if (val < 1 || val > 2)
return -EINVAL;
mutex_lock(&data->update_lock);
switch (val) {
- case 0:
case 1:
+ /* Clear speed cruise mode bits */
data->pwm_fcms[0] &= ~(1 << index);
w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+ /* Clear thermal cruise mode bits */
for (i = 0; i < 6; i++) {
data->pwm_tfmr[i] &= ~(1 << index);
w83795_write(client, W83795_REG_TFMR(i),
data->pwm_tfmr[i]);
}
- data->pwm_fomc |= 1 << index;
- data->pwm_fomc ^= val << index;
- w83795_write(client, W83795_REG_FOMC, data->pwm_fomc);
break;
case 2:
data->pwm_fcms[0] |= (1 << index);
@@ -918,23 +952,60 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83795_data *data = w83795_update_pwm_config(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ unsigned int mode;
+
+ if (data->pwm_fomc & (1 << index))
+ mode = 0; /* DC */
+ else
+ mode = 1; /* PWM */
+
+ return sprintf(buf, "%u\n", mode);
+}
+
+/*
+ * Check whether a given temperature source can ever be useful.
+ * Returns the number of selectable temperature channels which are
+ * enabled.
+ */
+static int w83795_tss_useful(const struct w83795_data *data, int tsrc)
+{
+ int useful = 0, i;
+
+ for (i = 0; i < 4; i++) {
+ if (tss_map[i][tsrc] == TSS_MAP_RESERVED)
+ continue;
+ if (tss_map[i][tsrc] < 6) /* Analog */
+ useful += (data->has_temp >> tss_map[i][tsrc]) & 1;
+ else /* Digital */
+ useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
+ }
+
+ return useful;
+}
+
+static ssize_t
show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
struct w83795_data *data = w83795_update_pwm_config(dev);
int index = sensor_attr->index;
- u8 val = index / 2;
- u8 tmp = data->temp_src[val];
+ u8 tmp = data->temp_src[index / 2];
if (index & 1)
- val = 4;
+ tmp >>= 4; /* Pick high nibble */
else
- val = 0;
- tmp >>= val;
- tmp &= 0x0f;
+ tmp &= 0x0f; /* Pick low nibble */
- return sprintf(buf, "%u\n", tmp);
+ /* Look-up the actual temperature channel number */
+ if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED)
+ return -EINVAL; /* Shouldn't happen */
+
+ return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1);
}
static ssize_t
@@ -946,12 +1017,21 @@ store_temp_src(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
- unsigned long tmp;
+ int tmp;
+ unsigned long channel;
u8 val = index / 2;
- if (strict_strtoul(buf, 10, &tmp) < 0)
+ if (strict_strtoul(buf, 10, &channel) < 0 ||
+ channel < 1 || channel > 14)
+ return -EINVAL;
+
+ /* Check if request can be fulfilled */
+ for (tmp = 0; tmp < 4; tmp++) {
+ if (tss_map[tmp][index] == channel - 1)
+ break;
+ }
+ if (tmp == 4) /* No match */
return -EINVAL;
- tmp = SENSORS_LIMIT(tmp, 0, 15);
mutex_lock(&data->update_lock);
if (index & 1) {
@@ -1515,7 +1595,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
#define NOT_USED -1
-/* Don't change the attribute order, _max and _min are accessed by index
+/* Don't change the attribute order, _max, _min and _beep are accessed by index
* somewhere else in the code */
#define SENSOR_ATTR_IN(index) { \
SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
@@ -1530,6 +1610,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
show_alarm_beep, store_beep, BEEP_ENABLE, \
index + ((index > 14) ? 1 : 0)) }
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
#define SENSOR_ATTR_FAN(index) { \
SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \
NULL, FAN_INPUT, index - 1), \
@@ -1553,9 +1635,13 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
show_pwm, store_pwm, PWM_FREQ, index - 1), \
SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \
show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+ SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \
+ show_pwm_mode, NULL, NOT_USED, index - 1), \
SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
show_fanin, store_fanin, FANIN_TARGET, index - 1) }
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
#define SENSOR_ATTR_DTS(index) { \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \
show_dts_mode, NULL, NOT_USED, index - 7), \
@@ -1574,6 +1660,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
#define SENSOR_ATTR_TEMP(index) { \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
show_temp_mode, store_temp_mode, NOT_USED, index - 1), \
@@ -1593,8 +1681,6 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, \
index + (index > 4 ? 11 : 17)), \
- SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \
- show_temp_src, store_temp_src, NOT_USED, index - 1), \
SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \
show_temp_pwm_enable, store_temp_pwm_enable, \
TEMP_PWM_ENABLE, index - 1), \
@@ -1680,7 +1766,7 @@ static const struct sensor_device_attribute_2 w83795_fan[][4] = {
SENSOR_ATTR_FAN(14),
};
-static const struct sensor_device_attribute_2 w83795_temp[][29] = {
+static const struct sensor_device_attribute_2 w83795_temp[][28] = {
SENSOR_ATTR_TEMP(1),
SENSOR_ATTR_TEMP(2),
SENSOR_ATTR_TEMP(3),
@@ -1700,7 +1786,7 @@ static const struct sensor_device_attribute_2 w83795_dts[][8] = {
SENSOR_ATTR_DTS(14),
};
-static const struct sensor_device_attribute_2 w83795_pwm[][7] = {
+static const struct sensor_device_attribute_2 w83795_pwm[][8] = {
SENSOR_ATTR_PWM(1),
SENSOR_ATTR_PWM(2),
SENSOR_ATTR_PWM(3),
@@ -1711,13 +1797,24 @@ static const struct sensor_device_attribute_2 w83795_pwm[][7] = {
SENSOR_ATTR_PWM(8),
};
+static const struct sensor_device_attribute_2 w83795_tss[6] = {
+ SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 0),
+ SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 1),
+ SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 2),
+ SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 3),
+ SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 4),
+ SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO,
+ show_temp_src, store_temp_src, NOT_USED, 5),
+};
+
static const struct sensor_device_attribute_2 sda_single_files[] = {
SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 46),
- SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
- store_beep, BEEP_ENABLE, 46),
- SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
- store_beep, BEEP_ENABLE, 47),
#ifdef CONFIG_SENSORS_W83795_FANCTRL
SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
store_fanin, FANIN_TOL, NOT_USED),
@@ -1730,6 +1827,13 @@ static const struct sensor_device_attribute_2 sda_single_files[] = {
#endif
};
+static const struct sensor_device_attribute_2 sda_beep_files[] = {
+ SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
+ store_beep, BEEP_ENABLE, 46),
+ SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
+ store_beep, BEEP_ENABLE, 47),
+};
+
/*
* Driver interface
*/
@@ -1859,6 +1963,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
if (!(data->has_in & (1 << i)))
continue;
for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) {
+ if (j == 4 && !data->enable_beep)
+ continue;
err = fn(dev, &w83795_in[i][j].dev_attr);
if (err)
return err;
@@ -1869,18 +1975,37 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
if (!(data->has_fan & (1 << i)))
continue;
for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) {
+ if (j == 3 && !data->enable_beep)
+ continue;
err = fn(dev, &w83795_fan[i][j].dev_attr);
if (err)
return err;
}
}
+ for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
+ j = w83795_tss_useful(data, i);
+ if (!j)
+ continue;
+ err = fn(dev, &w83795_tss[i].dev_attr);
+ if (err)
+ return err;
+ }
+
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = fn(dev, &sda_single_files[i].dev_attr);
if (err)
return err;
}
+ if (data->enable_beep) {
+ for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
+ err = fn(dev, &sda_beep_files[i].dev_attr);
+ if (err)
+ return err;
+ }
+ }
+
#ifdef CONFIG_SENSORS_W83795_FANCTRL
for (i = 0; i < data->has_pwm; i++) {
for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
@@ -1899,6 +2024,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
#else
for (j = 0; j < 8; j++) {
#endif
+ if (j == 7 && !data->enable_beep)
+ continue;
err = fn(dev, &w83795_temp[i][j].dev_attr);
if (err)
return err;
@@ -1910,6 +2037,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
if (!(data->has_dts & (1 << i)))
continue;
for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) {
+ if (j == 7 && !data->enable_beep)
+ continue;
err = fn(dev, &w83795_dts[i][j].dev_attr);
if (err)
return err;
@@ -2049,6 +2178,18 @@ static int w83795_probe(struct i2c_client *client,
else
data->has_pwm = 2;
+ /* Check if BEEP pin is available */
+ if (data->chip_type == w83795g) {
+ /* The W83795G has a dedicated BEEP pin */
+ data->enable_beep = 1;
+ } else {
+ /* The W83795ADG has a shared pin for OVT# and BEEP, so you
+ * can't have both */
+ tmp = w83795_read(client, W83795_REG_OVT_CFG);
+ if ((tmp & OVT_CFG_SEL) == 0)
+ data->enable_beep = 1;
+ }
+
err = w83795_handle_files(dev, device_create_file);
if (err)
goto exit_remove;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index b923074b2cbe..30f06e956bfb 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -75,8 +75,7 @@ config I2C_HELPER_AUTO
In doubt, say Y.
config I2C_SMBUS
- tristate
- prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
help
Say Y here if you want support for SMBus extensions to the I2C
specification. At the moment, the only supported extension is
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 3998dd620a03..f1cfe7e5508b 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -3,7 +3,7 @@
#
menu "I2C Algorithms"
- depends on !I2C_HELPER_AUTO
+ visible if !I2C_HELPER_AUTO
config I2C_ALGOBIT
tristate "I2C bit-banging interfaces"
@@ -15,15 +15,3 @@ config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
endmenu
-
-# In automatic configuration mode, we still have to define the
-# symbols to avoid unmet dependencies.
-
-if I2C_HELPER_AUTO
-config I2C_ALGOBIT
- tristate
-config I2C_ALGOPCF
- tristate
-config I2C_ALGOPCA
- tristate
-endif
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index a39e6cff86e7..38319a69bd0a 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -600,12 +600,14 @@ static const struct i2c_algorithm i2c_bit_algo = {
/*
* registering functions to load algorithms at runtime
*/
-static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
+static int __i2c_bit_add_bus(struct i2c_adapter *adap,
+ int (*add_adapter)(struct i2c_adapter *))
{
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+ int ret;
if (bit_test) {
- int ret = test_bus(bit_adap, adap->name);
+ ret = test_bus(bit_adap, adap->name);
if (ret < 0)
return -ENODEV;
}
@@ -614,30 +616,27 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
adap->algo = &i2c_bit_algo;
adap->retries = 3;
+ ret = add_adapter(adap);
+ if (ret < 0)
+ return ret;
+
+ /* Complain if SCL can't be read */
+ if (bit_adap->getscl == NULL) {
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+ dev_warn(&adap->dev, "Bus may be unreliable\n");
+ }
return 0;
}
int i2c_bit_add_bus(struct i2c_adapter *adap)
{
- int err;
-
- err = i2c_bit_prepare_bus(adap);
- if (err)
- return err;
-
- return i2c_add_adapter(adap);
+ return __i2c_bit_add_bus(adap, i2c_add_adapter);
}
EXPORT_SYMBOL(i2c_bit_add_bus);
int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{
- int err;
-
- err = i2c_bit_prepare_bus(adap);
- if (err)
- return err;
-
- return i2c_add_numbered_adapter(adap);
+ return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}
EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c950be3cce21..113505a6434e 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -99,6 +99,7 @@ config I2C_I801
ICH10
5/3400 Series (PCH)
Cougar Point (PCH)
+ Patsburg (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -637,6 +638,14 @@ config I2C_XILINX
This driver can also be built as a module. If so, the module
will be called xilinx_i2c.
+config I2C_EG20T
+ tristate "PCH I2C of Intel EG20T"
+ depends on PCI
+ help
+ This driver is for PCH(Platform controller Hub) I2C of EG20T which
+ is an IOH(Input/Output Hub) for x86 embedded processor.
+ This driver can access PCH I2C bus device.
+
comment "External I2C/SMBus adapter drivers"
config I2C_PARPORT
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 84cb16ae6f9e..9d2d0ec7fb23 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
+obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index fb26e5c67515..52b545a795f2 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -20,6 +20,7 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include <asm/blackfin.h>
#include <asm/portmux.h>
@@ -159,6 +160,27 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
if (mast_stat & BUFWRERR)
dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+ /* Faulty slave devices, may drive SDA low after a transfer
+ * finishes. To release the bus this code generates up to 9
+ * extra clocks until SDA is released.
+ */
+
+ if (read_MASTER_STAT(iface) & SDASEN) {
+ int cnt = 9;
+ do {
+ write_MASTER_CTL(iface, SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ udelay(6);
+ } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--);
+
+ write_MASTER_CTL(iface, SDAOVR | SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, SDAOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ }
+
/* If it is a quick transfer, only address without data,
* not an err, return 1.
*/
@@ -760,7 +782,7 @@ static void __exit i2c_bfin_twi_exit(void)
platform_driver_unregister(&i2c_bfin_twi_driver);
}
-module_init(i2c_bfin_twi_init);
+subsys_initcall(i2c_bfin_twi_init);
module_exit(i2c_bfin_twi_exit);
MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
new file mode 100644
index 000000000000..2e067dd2ee51
--- /dev/null
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/ktime.h>
+
+#define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */
+#define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */
+#define PCH_MAX_CLK 100000 /* Maximum Clock speed in MHz */
+#define PCH_BUFFER_MODE_ENABLE 0x0002 /* flag for Buffer mode enable */
+#define PCH_EEPROM_SW_RST_MODE_ENABLE 0x0008 /* EEPROM SW RST enable flag */
+
+#define PCH_I2CSADR 0x00 /* I2C slave address register */
+#define PCH_I2CCTL 0x04 /* I2C control register */
+#define PCH_I2CSR 0x08 /* I2C status register */
+#define PCH_I2CDR 0x0C /* I2C data register */
+#define PCH_I2CMON 0x10 /* I2C bus monitor register */
+#define PCH_I2CBC 0x14 /* I2C bus transfer rate setup counter */
+#define PCH_I2CMOD 0x18 /* I2C mode register */
+#define PCH_I2CBUFSLV 0x1C /* I2C buffer mode slave address register */
+#define PCH_I2CBUFSUB 0x20 /* I2C buffer mode subaddress register */
+#define PCH_I2CBUFFOR 0x24 /* I2C buffer mode format register */
+#define PCH_I2CBUFCTL 0x28 /* I2C buffer mode control register */
+#define PCH_I2CBUFMSK 0x2C /* I2C buffer mode interrupt mask register */
+#define PCH_I2CBUFSTA 0x30 /* I2C buffer mode status register */
+#define PCH_I2CBUFLEV 0x34 /* I2C buffer mode level register */
+#define PCH_I2CESRFOR 0x38 /* EEPROM software reset mode format register */
+#define PCH_I2CESRCTL 0x3C /* EEPROM software reset mode ctrl register */
+#define PCH_I2CESRMSK 0x40 /* EEPROM software reset mode */
+#define PCH_I2CESRSTA 0x44 /* EEPROM software reset mode status register */
+#define PCH_I2CTMR 0x48 /* I2C timer register */
+#define PCH_I2CSRST 0xFC /* I2C reset register */
+#define PCH_I2CNF 0xF8 /* I2C noise filter register */
+
+#define BUS_IDLE_TIMEOUT 20
+#define PCH_I2CCTL_I2CMEN 0x0080
+#define TEN_BIT_ADDR_DEFAULT 0xF000
+#define TEN_BIT_ADDR_MASK 0xF0
+#define PCH_START 0x0020
+#define PCH_ESR_START 0x0001
+#define PCH_BUFF_START 0x1
+#define PCH_REPSTART 0x0004
+#define PCH_ACK 0x0008
+#define PCH_GETACK 0x0001
+#define CLR_REG 0x0
+#define I2C_RD 0x1
+#define I2CMCF_BIT 0x0080
+#define I2CMIF_BIT 0x0002
+#define I2CMAL_BIT 0x0010
+#define I2CBMFI_BIT 0x0001
+#define I2CBMAL_BIT 0x0002
+#define I2CBMNA_BIT 0x0004
+#define I2CBMTO_BIT 0x0008
+#define I2CBMIS_BIT 0x0010
+#define I2CESRFI_BIT 0X0001
+#define I2CESRTO_BIT 0x0002
+#define I2CESRFIIE_BIT 0x1
+#define I2CESRTOIE_BIT 0x2
+#define I2CBMDZ_BIT 0x0040
+#define I2CBMAG_BIT 0x0020
+#define I2CMBB_BIT 0x0020
+#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
+ I2CBMTO_BIT | I2CBMIS_BIT)
+#define I2C_ADDR_MSK 0xFF
+#define I2C_MSB_2B_MSK 0x300
+#define FAST_MODE_CLK 400
+#define FAST_MODE_EN 0x0001
+#define SUB_ADDR_LEN_MAX 4
+#define BUF_LEN_MAX 32
+#define PCH_BUFFER_MODE 0x1
+#define EEPROM_SW_RST_MODE 0x0002
+#define NORMAL_INTR_ENBL 0x0300
+#define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT)
+#define EEPROM_RST_INTR_DISBL 0x0
+#define BUFFER_MODE_INTR_ENBL 0x001F
+#define BUFFER_MODE_INTR_DISBL 0x0
+#define NORMAL_MODE 0x0
+#define BUFFER_MODE 0x1
+#define EEPROM_SR_MODE 0x2
+#define I2C_TX_MODE 0x0010
+#define PCH_BUF_TX 0xFFF7
+#define PCH_BUF_RD 0x0008
+#define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
+ I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
+#define I2CMAL_EVENT 0x0001
+#define I2CMCF_EVENT 0x0002
+#define I2CBMFI_EVENT 0x0004
+#define I2CBMAL_EVENT 0x0008
+#define I2CBMNA_EVENT 0x0010
+#define I2CBMTO_EVENT 0x0020
+#define I2CBMIS_EVENT 0x0040
+#define I2CESRFI_EVENT 0x0080
+#define I2CESRTO_EVENT 0x0100
+#define PCI_DEVICE_ID_PCH_I2C 0x8817
+
+#define pch_dbg(adap, fmt, arg...) \
+ dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_err(adap, fmt, arg...) \
+ dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_err(pdev, fmt, arg...) \
+ dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_dbg(pdev, fmt, arg...) \
+ dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+/**
+ * struct i2c_algo_pch_data - for I2C driver functionalities
+ * @pch_adapter: stores the reference to i2c_adapter structure
+ * @p_adapter_info: stores the reference to adapter_info structure
+ * @pch_base_address: specifies the remapped base address
+ * @pch_buff_mode_en: specifies if buffer mode is enabled
+ * @pch_event_flag: specifies occurrence of interrupt events
+ * @pch_i2c_xfer_in_progress: specifies whether the transfer is completed
+ */
+struct i2c_algo_pch_data {
+ struct i2c_adapter pch_adapter;
+ struct adapter_info *p_adapter_info;
+ void __iomem *pch_base_address;
+ int pch_buff_mode_en;
+ u32 pch_event_flag;
+ bool pch_i2c_xfer_in_progress;
+};
+
+/**
+ * struct adapter_info - This structure holds the adapter information for the
+ PCH i2c controller
+ * @pch_data: stores a list of i2c_algo_pch_data
+ * @pch_i2c_suspended: specifies whether the system is suspended or not
+ * perhaps with more lines and words.
+ *
+ * pch_data has as many elements as maximum I2C channels
+ */
+struct adapter_info {
+ struct i2c_algo_pch_data pch_data;
+ bool pch_i2c_suspended;
+};
+
+
+static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */
+static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
+static wait_queue_head_t pch_event;
+static DEFINE_MUTEX(pch_mutex);
+
+static struct pci_device_id __devinitdata pch_pcidev_id[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)},
+ {0,}
+};
+
+static irqreturn_t pch_i2c_handler(int irq, void *pData);
+
+static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val |= bitmask;
+ iowrite32(val, addr + offset);
+}
+
+static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val &= (~bitmask);
+ iowrite32(val, addr + offset);
+}
+
+/**
+ * pch_i2c_init() - hardware initialization of I2C module
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_init(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ u32 pch_i2cbc;
+ u32 pch_i2ctmr;
+ u32 reg_value;
+
+ /* reset I2C controller */
+ iowrite32(0x01, p + PCH_I2CSRST);
+ msleep(20);
+ iowrite32(0x0, p + PCH_I2CSRST);
+
+ /* Initialize I2C registers */
+ iowrite32(0x21, p + PCH_I2CNF);
+
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL,
+ PCH_I2CCTL_I2CMEN);
+
+ if (pch_i2c_speed != 400)
+ pch_i2c_speed = 100;
+
+ reg_value = PCH_I2CCTL_I2CMEN;
+ if (pch_i2c_speed == FAST_MODE_CLK) {
+ reg_value |= FAST_MODE_EN;
+ pch_dbg(adap, "Fast mode enabled\n");
+ }
+
+ if (pch_clk > PCH_MAX_CLK)
+ pch_clk = 62500;
+
+ pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8;
+ /* Set transfer speed in I2CBC */
+ iowrite32(pch_i2cbc, p + PCH_I2CBC);
+
+ pch_i2ctmr = (pch_clk) / 8;
+ iowrite32(pch_i2ctmr, p + PCH_I2CTMR);
+
+ reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */
+ iowrite32(reg_value, p + PCH_I2CCTL);
+
+ pch_dbg(adap,
+ "I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n",
+ ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr);
+
+ init_waitqueue_head(&pch_event);
+}
+
+static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return cmp1.tv64 < cmp2.tv64;
+}
+
+/**
+ * pch_i2c_wait_for_bus_idle() - check the status of bus.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ * @timeout: waiting time counter (us).
+ */
+static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
+ s32 timeout)
+{
+ void __iomem *p = adap->pch_base_address;
+
+ /* MAX timeout value is timeout*1000*1000nsec */
+ ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
+ do {
+ if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
+ break;
+ msleep(20);
+ } while (ktime_lt(ktime_get(), ns_val));
+
+ pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+ if (timeout == 0) {
+ pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_start() - Generate I2C start condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1.
+ */
+static void pch_i2c_start(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_wait_for_xfer_complete() - initiates a wait for the tx complete event
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap)
+{
+ s32 ret;
+ ret = wait_event_timeout(pch_event,
+ (adap->pch_event_flag != 0), msecs_to_jiffies(50));
+ if (ret < 0) {
+ pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+ return ret;
+ }
+
+ if (ret == 0) {
+ pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+ return -ETIMEDOUT;
+ }
+
+ if (adap->pch_event_flag & I2C_ERROR_MASK) {
+ pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
+ return -EIO;
+ }
+
+ adap->pch_event_flag = 0;
+
+ return 0;
+}
+
+/**
+ * pch_i2c_getack() - to confirm ACK/NACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap)
+{
+ u32 reg_val;
+ void __iomem *p = adap->pch_base_address;
+ reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK;
+
+ if (reg_val != 0) {
+ pch_err(adap, "return%d\n", -EPROTO);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_stop() - generate stop condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_stop(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ /* clear the start bit */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_repstart() - generate repeated start condition in normal mode
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_repstart(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART);
+}
+
+/**
+ * pch_i2c_writebytes() - write data to I2C bus in normal mode
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @last: specifies whether last message or not.
+ * In the case of compound mode it will be 1 for last message,
+ * otherwise 0.
+ * @first: specifies whether first message or not.
+ * 1 for first message otherwise 0.
+ */
+static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+ u8 *buf;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ u32 addr_8_lsb;
+ s32 wrcount;
+ void __iomem *p = adap->pch_base_address;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master tx */
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL),
+ length);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ if (pch_i2c_wait_for_xfer_complete(adap) == 0 &&
+ pch_i2c_getack(adap) == 0) {
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ } else {
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
+ } else {
+ /* set 7 bit slave address and R/W bit as 0 */
+ iowrite32(addr << 1, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ }
+
+ if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
+ (pch_i2c_getack(adap) == 0)) {
+ for (wrcount = 0; wrcount < length; ++wrcount) {
+ /* write buffer value to I2C data register */
+ iowrite32(buf[wrcount], p + PCH_I2CDR);
+ pch_dbg(adap, "writing %x to Data register\n",
+ buf[wrcount]);
+
+ if (pch_i2c_wait_for_xfer_complete(adap) != 0)
+ return -ETIME;
+
+ if (pch_i2c_getack(adap))
+ return -EIO;
+ }
+
+ /* check if this is the last message */
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+ } else {
+ pch_i2c_stop(adap);
+ return -EIO;
+ }
+
+ pch_dbg(adap, "return=%d\n", wrcount);
+
+ return wrcount;
+}
+
+/**
+ * pch_i2c_sendack() - send ACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_sendnack() - send NACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_readbytes() - read data from I2C bus in normal mode.
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @last: specifies whether last message or not.
+ * @first: specifies whether first message or not.
+ */
+s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ u8 *buf;
+ u32 count;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ void __iomem *p = adap->pch_base_address;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master reception */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD));
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+
+ } else {
+ /* 7 address bits + R/W bit */
+ addr = (((addr) << 1) | (I2C_RD));
+ iowrite32(addr, p + PCH_I2CDR);
+ }
+
+ /* check if it is the first message */
+ if (first)
+ pch_i2c_start(adap);
+
+ if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
+ (pch_i2c_getack(adap) == 0)) {
+ pch_dbg(adap, "return %d\n", 0);
+
+ if (length == 0) {
+ pch_i2c_stop(adap);
+ ioread32(p + PCH_I2CDR); /* Dummy read needs */
+
+ count = length;
+ } else {
+ int read_index;
+ int loop;
+ pch_i2c_sendack(adap);
+
+ /* Dummy read */
+ for (loop = 1, read_index = 0; loop < length; loop++) {
+ buf[read_index] = ioread32(p + PCH_I2CDR);
+
+ if (loop != 1)
+ read_index++;
+
+ if (pch_i2c_wait_for_xfer_complete(adap) != 0) {
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
+ } /* end for */
+
+ pch_i2c_sendnack(adap);
+
+ buf[read_index] = ioread32(p + PCH_I2CDR);
+
+ if (length != 1)
+ read_index++;
+
+ if (pch_i2c_wait_for_xfer_complete(adap) == 0) {
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+
+ buf[read_index++] = ioread32(p + PCH_I2CDR);
+ count = read_index;
+ } else {
+ count = -ETIME;
+ }
+
+ }
+ } else {
+ count = -ETIME;
+ pch_i2c_stop(adap);
+ }
+
+ return count;
+}
+
+/**
+ * pch_i2c_cb_ch0() - Interrupt handler Call back function
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
+{
+ u32 sts;
+ void __iomem *p = adap->pch_base_address;
+
+ sts = ioread32(p + PCH_I2CSR);
+ sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
+ if (sts & I2CMAL_BIT)
+ adap->pch_event_flag |= I2CMAL_EVENT;
+
+ if (sts & I2CMCF_BIT)
+ adap->pch_event_flag |= I2CMCF_EVENT;
+
+ /* clear the applicable bits */
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts);
+
+ pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+ wake_up(&pch_event);
+}
+
+/**
+ * pch_i2c_handler() - interrupt handler for the PCH I2C controller
+ * @irq: irq number.
+ * @pData: cookie passed back to the handler function.
+ */
+static irqreturn_t pch_i2c_handler(int irq, void *pData)
+{
+ s32 reg_val;
+
+ struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData;
+ void __iomem *p = adap_data->pch_base_address;
+ u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE);
+
+ if (mode != NORMAL_MODE) {
+ pch_err(adap_data, "I2C mode is not supported\n");
+ return IRQ_NONE;
+ }
+
+ reg_val = ioread32(p + PCH_I2CSR);
+ if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT))
+ pch_i2c_cb_ch0(adap_data);
+ else
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * pch_i2c_xfer() - Reading adnd writing data through I2C bus
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @num: number of messages.
+ */
+static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, s32 num)
+{
+ struct i2c_msg *pmsg;
+ u32 i = 0;
+ u32 status;
+ u32 msglen;
+ u32 subaddrlen;
+ s32 ret;
+
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ ret = mutex_lock_interruptible(&pch_mutex);
+ if (ret)
+ return -ERESTARTSYS;
+
+ if (adap->p_adapter_info->pch_i2c_suspended) {
+ mutex_unlock(&pch_mutex);
+ return -EBUSY;
+ }
+
+ pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n",
+ adap->p_adapter_info->pch_i2c_suspended);
+ /* transfer not completed */
+ adap->pch_i2c_xfer_in_progress = true;
+
+ pmsg = &msgs[0];
+ pmsg->flags |= adap->pch_buff_mode_en;
+ status = pmsg->flags;
+ pch_dbg(adap,
+ "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
+ /* calculate sub address length and message length */
+ /* these are applicable only for buffer mode */
+ subaddrlen = pmsg->buf[0];
+ /* calculate actual message length excluding
+ * the sub address fields */
+ msglen = (pmsg->len) - (subaddrlen + 1);
+ if (status & (I2C_M_RD)) {
+ pch_dbg(adap, "invoking pch_i2c_readbytes\n");
+ ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ } else {
+ pch_dbg(adap, "invoking pch_i2c_writebytes\n");
+ ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ }
+
+ adap->pch_i2c_xfer_in_progress = false; /* transfer completed */
+
+ mutex_unlock(&pch_mutex);
+
+ return ret;
+}
+
+/**
+ * pch_i2c_func() - return the functionality of the I2C driver
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static u32 pch_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm pch_algorithm = {
+ .master_xfer = pch_i2c_xfer,
+ .functionality = pch_i2c_func
+};
+
+/**
+ * pch_i2c_disbl_int() - Disable PCH I2C interrupts
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL);
+
+ iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK);
+
+ iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
+}
+
+static int __devinit pch_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *base_addr;
+ s32 ret;
+ struct adapter_info *adap_info;
+
+ pch_pci_dbg(pdev, "Entered.\n");
+
+ adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
+ if (adap_info == NULL) {
+ pch_pci_err(pdev, "Memory allocation FAILED\n");
+ return -ENOMEM;
+ }
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ pch_pci_err(pdev, "pci_enable_device FAILED\n");
+ goto err_pci_enable;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ pch_pci_err(pdev, "pci_request_regions FAILED\n");
+ goto err_pci_req;
+ }
+
+ base_addr = pci_iomap(pdev, 1, 0);
+
+ if (base_addr == NULL) {
+ pch_pci_err(pdev, "pci_iomap FAILED\n");
+ ret = -ENOMEM;
+ goto err_pci_iomap;
+ }
+
+ adap_info->pch_i2c_suspended = false;
+
+ adap_info->pch_data.p_adapter_info = adap_info;
+
+ adap_info->pch_data.pch_adapter.owner = THIS_MODULE;
+ adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON;
+ strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME);
+ adap_info->pch_data.pch_adapter.algo = &pch_algorithm;
+ adap_info->pch_data.pch_adapter.algo_data =
+ &adap_info->pch_data;
+
+ /* (i * 0x80) + base_addr; */
+ adap_info->pch_data.pch_base_address = base_addr;
+
+ adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev;
+
+ ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter));
+
+ if (ret) {
+ pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
+ goto err_i2c_add_adapter;
+ }
+
+ pch_i2c_init(&adap_info->pch_data);
+ ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+ KBUILD_MODNAME, &adap_info->pch_data);
+ if (ret) {
+ pch_pci_err(pdev, "request_irq FAILED\n");
+ goto err_request_irq;
+ }
+
+ pci_set_drvdata(pdev, adap_info);
+ pch_pci_dbg(pdev, "returns %d.\n", ret);
+ return 0;
+
+err_request_irq:
+ i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
+err_i2c_add_adapter:
+ pci_iounmap(pdev, base_addr);
+err_pci_iomap:
+ pci_release_regions(pdev);
+err_pci_req:
+ pci_disable_device(pdev);
+err_pci_enable:
+ kfree(adap_info);
+ return ret;
+}
+
+static void __devexit pch_i2c_remove(struct pci_dev *pdev)
+{
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ pch_i2c_disbl_int(&adap_info->pch_data);
+ free_irq(pdev->irq, &adap_info->pch_data);
+ i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
+
+ if (adap_info->pch_data.pch_base_address) {
+ pci_iounmap(pdev, adap_info->pch_data.pch_base_address);
+ adap_info->pch_data.pch_base_address = 0;
+ }
+
+ pci_set_drvdata(pdev, NULL);
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+ kfree(adap_info);
+}
+
+#ifdef CONFIG_PM
+static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int ret;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+ void __iomem *p = adap_info->pch_data.pch_base_address;
+
+ adap_info->pch_i2c_suspended = true;
+
+ while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) {
+ /* Wait until all channel transfers are completed */
+ msleep(20);
+ }
+ /* Disable the i2c interrupts */
+ pch_i2c_disbl_int(&adap_info->pch_data);
+
+ pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
+ "invoked function pch_i2c_disbl_int successfully\n",
+ ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
+ ioread32(p + PCH_I2CESRSTA));
+
+ ret = pci_save_state(pdev);
+
+ if (ret) {
+ pch_pci_err(pdev, "pci_save_state\n");
+ return ret;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int pch_i2c_resume(struct pci_dev *pdev)
+{
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (pci_enable_device(pdev) < 0) {
+ pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n");
+ return -EIO;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ pch_i2c_init(&adap_info->pch_data);
+
+ adap_info->pch_i2c_suspended = false;
+
+ return 0;
+}
+#else
+#define pch_i2c_suspend NULL
+#define pch_i2c_resume NULL
+#endif
+
+static struct pci_driver pch_pcidriver = {
+ .name = KBUILD_MODNAME,
+ .id_table = pch_pcidev_id,
+ .probe = pch_i2c_probe,
+ .remove = __devexit_p(pch_i2c_remove),
+ .suspend = pch_i2c_suspend,
+ .resume = pch_i2c_resume
+};
+
+static int __init pch_pci_init(void)
+{
+ return pci_register_driver(&pch_pcidriver);
+}
+module_init(pch_pci_init);
+
+static void __exit pch_pci_exit(void)
+{
+ pci_unregister_driver(&pch_pcidriver);
+}
+module_exit(pch_pci_exit);
+
+MODULE_DESCRIPTION("PCH I2C PCI Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>");
+module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
+module_param(pch_clk, int, (S_IRUSR | S_IWUSR));
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 59d65981eed7..7979aef7ee7b 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -3,6 +3,8 @@
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
<mdsxyz123@yahoo.com>
Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2010 Intel Corporation,
+ David Woodhouse <dwmw2@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
@@ -43,6 +45,10 @@
ICH10 0x3a60 32 hard yes yes yes
5/3400 Series (PCH) 0x3b30 32 hard yes yes yes
Cougar Point (PCH) 0x1c22 32 hard yes yes yes
+ Patsburg (PCH) 0x1d22 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
+ Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -50,12 +56,11 @@
Block buffer yes
Block process call transaction no
I2C block read transaction yes (doesn't use the block buffer)
+ Slave mode no
See the file Documentation/i2c/busses/i2c-i801 for details.
*/
-/* Note: we assume there can only be one I801, with one SMBus interface */
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -67,18 +72,19 @@
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/dmi.h>
+#include <linux/slab.h>
/* I801 SMBus address offsets */
-#define SMBHSTSTS (0 + i801_smba)
-#define SMBHSTCNT (2 + i801_smba)
-#define SMBHSTCMD (3 + i801_smba)
-#define SMBHSTADD (4 + i801_smba)
-#define SMBHSTDAT0 (5 + i801_smba)
-#define SMBHSTDAT1 (6 + i801_smba)
-#define SMBBLKDAT (7 + i801_smba)
-#define SMBPEC (8 + i801_smba) /* ICH3 and later */
-#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */
-#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */
+#define SMBHSTSTS(p) (0 + (p)->smba)
+#define SMBHSTCNT(p) (2 + (p)->smba)
+#define SMBHSTCMD(p) (3 + (p)->smba)
+#define SMBHSTADD(p) (4 + (p)->smba)
+#define SMBHSTDAT0(p) (5 + (p)->smba)
+#define SMBHSTDAT1(p) (6 + (p)->smba)
+#define SMBBLKDAT(p) (7 + (p)->smba)
+#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
+#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
+#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */
/* PCI Address Constants */
#define SMBBAR 4
@@ -127,16 +133,25 @@
SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
SMBHSTSTS_INTR)
-static unsigned long i801_smba;
-static unsigned char i801_original_hstcfg;
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
+
+struct i801_priv {
+ struct i2c_adapter adapter;
+ unsigned long smba;
+ unsigned char original_hstcfg;
+ struct pci_dev *pci_dev;
+ unsigned int features;
+};
+
static struct pci_driver i801_driver;
-static struct pci_dev *I801_dev;
#define FEATURE_SMBUS_PEC (1 << 0)
#define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3)
-static unsigned int i801_features;
static const char *i801_feature_names[] = {
"SMBus PEC",
@@ -151,24 +166,24 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features");
/* Make sure the SMBus host is ready to start transmitting.
Return 0 if it is, -EBUSY if it is not. */
-static int i801_check_pre(void)
+static int i801_check_pre(struct i801_priv *priv)
{
int status;
- status = inb_p(SMBHSTSTS);
+ status = inb_p(SMBHSTSTS(priv));
if (status & SMBHSTSTS_HOST_BUSY) {
- dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
+ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
return -EBUSY;
}
status &= STATUS_FLAGS;
if (status) {
- dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
+ dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
status);
- outb_p(status, SMBHSTSTS);
- status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+ outb_p(status, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
if (status) {
- dev_err(&I801_dev->dev,
+ dev_err(&priv->pci_dev->dev,
"Failed clearing status flags (%02x)\n",
status);
return -EBUSY;
@@ -179,48 +194,50 @@ static int i801_check_pre(void)
}
/* Convert the status register to an error code, and clear it. */
-static int i801_check_post(int status, int timeout)
+static int i801_check_post(struct i801_priv *priv, int status, int timeout)
{
int result = 0;
/* If the SMBus is still busy, we give up */
if (timeout) {
- dev_err(&I801_dev->dev, "Transaction timeout\n");
+ dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
/* try to stop the current command */
- dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
- outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+ outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
+ SMBHSTCNT(priv));
msleep(1);
- outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
+ outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
+ SMBHSTCNT(priv));
/* Check if it worked */
- status = inb_p(SMBHSTSTS);
+ status = inb_p(SMBHSTSTS(priv));
if ((status & SMBHSTSTS_HOST_BUSY) ||
!(status & SMBHSTSTS_FAILED))
- dev_err(&I801_dev->dev,
+ dev_err(&priv->pci_dev->dev,
"Failed terminating the transaction\n");
- outb_p(STATUS_FLAGS, SMBHSTSTS);
+ outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
return -ETIMEDOUT;
}
if (status & SMBHSTSTS_FAILED) {
result = -EIO;
- dev_err(&I801_dev->dev, "Transaction failed\n");
+ dev_err(&priv->pci_dev->dev, "Transaction failed\n");
}
if (status & SMBHSTSTS_DEV_ERR) {
result = -ENXIO;
- dev_dbg(&I801_dev->dev, "No response\n");
+ dev_dbg(&priv->pci_dev->dev, "No response\n");
}
if (status & SMBHSTSTS_BUS_ERR) {
result = -EAGAIN;
- dev_dbg(&I801_dev->dev, "Lost arbitration\n");
+ dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
}
if (result) {
/* Clear error flags */
- outb_p(status & STATUS_FLAGS, SMBHSTSTS);
- status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+ outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
if (status) {
- dev_warn(&I801_dev->dev, "Failed clearing status "
+ dev_warn(&priv->pci_dev->dev, "Failed clearing status "
"flags at end of transaction (%02x)\n",
status);
}
@@ -229,86 +246,88 @@ static int i801_check_post(int status, int timeout)
return result;
}
-static int i801_transaction(int xact)
+static int i801_transaction(struct i801_priv *priv, int xact)
{
int status;
int result;
int timeout = 0;
- result = i801_check_pre();
+ result = i801_check_pre(priv);
if (result < 0)
return result;
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
* INTREN, SMBSCMD are passed in xact */
- outb_p(xact | I801_START, SMBHSTCNT);
+ outb_p(xact | I801_START, SMBHSTCNT(priv));
/* We will always wait for a fraction of a second! */
do {
msleep(1);
- status = inb_p(SMBHSTSTS);
+ status = inb_p(SMBHSTSTS(priv));
} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
- result = i801_check_post(status, timeout > MAX_TIMEOUT);
+ result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
if (result < 0)
return result;
- outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
return 0;
}
/* wait for INTR bit as advised by Intel */
-static void i801_wait_hwpec(void)
+static void i801_wait_hwpec(struct i801_priv *priv)
{
int timeout = 0;
int status;
do {
msleep(1);
- status = inb_p(SMBHSTSTS);
+ status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_INTR))
&& (timeout++ < MAX_TIMEOUT));
if (timeout > MAX_TIMEOUT)
- dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+ dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
- outb_p(status, SMBHSTSTS);
+ outb_p(status, SMBHSTSTS(priv));
}
-static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+ union i2c_smbus_data *data,
char read_write, int hwpec)
{
int i, len;
int status;
- inb_p(SMBHSTCNT); /* reset the data buffer index */
+ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
/* Use 32-byte buffer to process this transaction */
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
- outb_p(len, SMBHSTDAT0);
+ outb_p(len, SMBHSTDAT0(priv));
for (i = 0; i < len; i++)
- outb_p(data->block[i+1], SMBBLKDAT);
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
}
- status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
+ status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
I801_PEC_EN * hwpec);
if (status)
return status;
if (read_write == I2C_SMBUS_READ) {
- len = inb_p(SMBHSTDAT0);
+ len = inb_p(SMBHSTDAT0(priv));
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
data->block[0] = len;
for (i = 0; i < len; i++)
- data->block[i + 1] = inb_p(SMBBLKDAT);
+ data->block[i + 1] = inb_p(SMBBLKDAT(priv));
}
return 0;
}
-static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+ union i2c_smbus_data *data,
char read_write, int command,
int hwpec)
{
@@ -318,15 +337,15 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
int result;
int timeout;
- result = i801_check_pre();
+ result = i801_check_pre(priv);
if (result < 0)
return result;
len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
- outb_p(len, SMBHSTDAT0);
- outb_p(data->block[1], SMBBLKDAT);
+ outb_p(len, SMBHSTDAT0(priv));
+ outb_p(data->block[1], SMBBLKDAT(priv));
}
for (i = 1; i <= len; i++) {
@@ -342,34 +361,37 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
else
smbcmd = I801_BLOCK_DATA;
}
- outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+ outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
if (i == 1)
- outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+ outb_p(inb(SMBHSTCNT(priv)) | I801_START,
+ SMBHSTCNT(priv));
/* We will always wait for a fraction of a second! */
timeout = 0;
do {
msleep(1);
- status = inb_p(SMBHSTSTS);
+ status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_BYTE_DONE))
&& (timeout++ < MAX_TIMEOUT));
- result = i801_check_post(status, timeout > MAX_TIMEOUT);
+ result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
if (result < 0)
return result;
if (i == 1 && read_write == I2C_SMBUS_READ
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
- len = inb_p(SMBHSTDAT0);
+ len = inb_p(SMBHSTDAT0(priv));
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
- dev_err(&I801_dev->dev,
+ dev_err(&priv->pci_dev->dev,
"Illegal SMBus block read size %d\n",
len);
/* Recover */
- while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
- outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
- outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+ while (inb_p(SMBHSTSTS(priv)) &
+ SMBHSTSTS_HOST_BUSY)
+ outb_p(SMBHSTSTS_BYTE_DONE,
+ SMBHSTSTS(priv));
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
return -EPROTO;
}
data->block[0] = len;
@@ -377,27 +399,28 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
/* Retrieve/store value in SMBBLKDAT */
if (read_write == I2C_SMBUS_READ)
- data->block[i] = inb_p(SMBBLKDAT);
+ data->block[i] = inb_p(SMBBLKDAT(priv));
if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
- outb_p(data->block[i+1], SMBBLKDAT);
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
/* signals SMBBLKDAT ready */
- outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
+ outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
}
return 0;
}
-static int i801_set_block_buffer_mode(void)
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
{
- outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
- if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
return -EIO;
return 0;
}
/* Block transaction function */
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+static int i801_block_transaction(struct i801_priv *priv,
+ union i2c_smbus_data *data, char read_write,
int command, int hwpec)
{
int result = 0;
@@ -406,11 +429,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
- pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
- pci_write_config_byte(I801_dev, SMBHSTCFG,
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
hostc | SMBHSTCFG_I2C_EN);
- } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
- dev_err(&I801_dev->dev,
+ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+ dev_err(&priv->pci_dev->dev,
"I2C block read is unsupported!\n");
return -EOPNOTSUPP;
}
@@ -429,22 +452,23 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* Experience has shown that the block buffer can only be used for
SMBus (not I2C) block transactions, even though the datasheet
doesn't mention this limitation. */
- if ((i801_features & FEATURE_BLOCK_BUFFER)
+ if ((priv->features & FEATURE_BLOCK_BUFFER)
&& command != I2C_SMBUS_I2C_BLOCK_DATA
- && i801_set_block_buffer_mode() == 0)
- result = i801_block_transaction_by_block(data, read_write,
- hwpec);
+ && i801_set_block_buffer_mode(priv) == 0)
+ result = i801_block_transaction_by_block(priv, data,
+ read_write, hwpec);
else
- result = i801_block_transaction_byte_by_byte(data, read_write,
+ result = i801_block_transaction_byte_by_byte(priv, data,
+ read_write,
command, hwpec);
if (result == 0 && hwpec)
- i801_wait_hwpec();
+ i801_wait_hwpec(priv);
if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_WRITE) {
/* restore saved configuration register value */
- pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
}
return result;
}
@@ -457,81 +481,85 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
int hwpec;
int block = 0;
int ret, xact = 0;
+ struct i801_priv *priv = i2c_get_adapdata(adap);
- hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
switch (size) {
case I2C_SMBUS_QUICK:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
+ SMBHSTADD(priv));
xact = I801_QUICK;
break;
case I2C_SMBUS_BYTE:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
+ SMBHSTADD(priv));
if (read_write == I2C_SMBUS_WRITE)
- outb_p(command, SMBHSTCMD);
+ outb_p(command, SMBHSTCMD(priv));
xact = I801_BYTE;
break;
case I2C_SMBUS_BYTE_DATA:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
if (read_write == I2C_SMBUS_WRITE)
- outb_p(data->byte, SMBHSTDAT0);
+ outb_p(data->byte, SMBHSTDAT0(priv));
xact = I801_BYTE_DATA;
break;
case I2C_SMBUS_WORD_DATA:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0);
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
}
xact = I801_WORD_DATA;
break;
case I2C_SMBUS_BLOCK_DATA:
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
block = 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
/* NB: page 240 of ICH5 datasheet shows that the R/#W
* bit should be cleared here, even when reading */
- outb_p((addr & 0x7f) << 1, SMBHSTADD);
+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
if (read_write == I2C_SMBUS_READ) {
/* NB: page 240 of ICH5 datasheet also shows
* that DATA1 is the cmd field when reading */
- outb_p(command, SMBHSTDAT1);
+ outb_p(command, SMBHSTDAT1(priv));
} else
- outb_p(command, SMBHSTCMD);
+ outb_p(command, SMBHSTCMD(priv));
block = 1;
break;
default:
- dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
+ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+ size);
return -EOPNOTSUPP;
}
if (hwpec) /* enable/disable hardware PEC */
- outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
else
- outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
+ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+ SMBAUXCTL(priv));
if (block)
- ret = i801_block_transaction(data, read_write, size, hwpec);
+ ret = i801_block_transaction(priv, data, read_write, size,
+ hwpec);
else
- ret = i801_transaction(xact | ENABLE_INT9);
+ ret = i801_transaction(priv, xact | ENABLE_INT9);
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
time, so we forcibly disable it after every transaction. Turn off
E32B for the same reason. */
if (hwpec || block)
- outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
- SMBAUXCTL);
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
if (block)
return ret;
@@ -543,10 +571,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
switch (xact & 0x7f) {
case I801_BYTE: /* Result put in SMBHSTDAT0 */
case I801_BYTE_DATA:
- data->byte = inb_p(SMBHSTDAT0);
+ data->byte = inb_p(SMBHSTDAT0(priv));
break;
case I801_WORD_DATA:
- data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ data->word = inb_p(SMBHSTDAT0(priv)) +
+ (inb_p(SMBHSTDAT1(priv)) << 8);
break;
}
return 0;
@@ -555,11 +584,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
static u32 i801_func(struct i2c_adapter *adapter)
{
+ struct i801_priv *priv = i2c_get_adapdata(adapter);
+
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
- ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
- ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ ((priv->features & FEATURE_I2C_BLOCK_READ) ?
I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
}
@@ -568,12 +599,6 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = i801_func,
};
-static struct i2c_adapter i801_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
- .algo = &smbus_algorithm,
-};
-
static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
@@ -592,6 +617,10 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
{ 0, }
};
@@ -704,16 +733,25 @@ static int __devinit i801_probe(struct pci_dev *dev,
{
unsigned char temp;
int err, i;
+ struct i801_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_adapdata(&priv->adapter, priv);
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ priv->adapter.algo = &smbus_algorithm;
- I801_dev = dev;
- i801_features = 0;
+ priv->pci_dev = dev;
switch (dev->device) {
default:
- i801_features |= FEATURE_I2C_BLOCK_READ;
+ priv->features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
- i801_features |= FEATURE_SMBUS_PEC;
- i801_features |= FEATURE_BLOCK_BUFFER;
+ priv->features |= FEATURE_SMBUS_PEC;
+ priv->features |= FEATURE_BLOCK_BUFFER;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801CA_3:
case PCI_DEVICE_ID_INTEL_82801BA_2:
@@ -724,11 +762,11 @@ static int __devinit i801_probe(struct pci_dev *dev,
/* Disable features on user request */
for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
- if (i801_features & disable_features & (1 << i))
+ if (priv->features & disable_features & (1 << i))
dev_notice(&dev->dev, "%s disabled by user\n",
i801_feature_names[i]);
}
- i801_features &= ~disable_features;
+ priv->features &= ~disable_features;
err = pci_enable_device(dev);
if (err) {
@@ -738,8 +776,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
}
/* Determine the address of the SMBus area */
- i801_smba = pci_resource_start(dev, SMBBAR);
- if (!i801_smba) {
+ priv->smba = pci_resource_start(dev, SMBBAR);
+ if (!priv->smba) {
dev_err(&dev->dev, "SMBus base address uninitialized, "
"upgrade BIOS\n");
err = -ENODEV;
@@ -755,19 +793,19 @@ static int __devinit i801_probe(struct pci_dev *dev,
err = pci_request_region(dev, SMBBAR, i801_driver.name);
if (err) {
dev_err(&dev->dev, "Failed to request SMBus region "
- "0x%lx-0x%Lx\n", i801_smba,
+ "0x%lx-0x%Lx\n", priv->smba,
(unsigned long long)pci_resource_end(dev, SMBBAR));
goto exit;
}
- pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
- i801_original_hstcfg = temp;
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
+ priv->original_hstcfg = temp;
temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
if (!(temp & SMBHSTCFG_HST_EN)) {
dev_info(&dev->dev, "Enabling SMBus device\n");
temp |= SMBHSTCFG_HST_EN;
}
- pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
if (temp & SMBHSTCFG_SMB_SMI_EN)
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
@@ -775,19 +813,19 @@ static int __devinit i801_probe(struct pci_dev *dev,
dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
/* Clear special mode bits */
- if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
- outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
- SMBAUXCTL);
+ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
/* set up the sysfs linkage to our parent device */
- i801_adapter.dev.parent = &dev->dev;
+ priv->adapter.dev.parent = &dev->dev;
/* Retry up to 3 times on lost arbitration */
- i801_adapter.retries = 3;
+ priv->adapter.retries = 3;
- snprintf(i801_adapter.name, sizeof(i801_adapter.name),
- "SMBus I801 adapter at %04lx", i801_smba);
- err = i2c_add_adapter(&i801_adapter);
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+ "SMBus I801 adapter at %04lx", priv->smba);
+ err = i2c_add_adapter(&priv->adapter);
if (err) {
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
goto exit_release;
@@ -801,27 +839,33 @@ static int __devinit i801_probe(struct pci_dev *dev,
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = apanel_addr;
strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
- i2c_new_device(&i801_adapter, &info);
+ i2c_new_device(&priv->adapter, &info);
}
#endif
#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
if (dmi_name_in_vendors("FUJITSU"))
- dmi_walk(dmi_check_onboard_devices, &i801_adapter);
+ dmi_walk(dmi_check_onboard_devices, &priv->adapter);
#endif
+ pci_set_drvdata(dev, priv);
return 0;
exit_release:
pci_release_region(dev, SMBBAR);
exit:
+ kfree(priv);
return err;
}
static void __devexit i801_remove(struct pci_dev *dev)
{
- i2c_del_adapter(&i801_adapter);
- pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&priv->adapter);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
pci_release_region(dev, SMBBAR);
+ pci_set_drvdata(dev, NULL);
+ kfree(priv);
/*
* do not call pci_disable_device(dev) since it can cause hard hangs on
* some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
@@ -831,8 +875,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
#ifdef CONFIG_PM
static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
{
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
pci_save_state(dev);
- pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
pci_set_power_state(dev, pci_choose_state(dev, mesg));
return 0;
}
diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
index 80f70d3a744d..c71492782bbd 100644
--- a/drivers/i2c/busses/i2c-intel-mid.c
+++ b/drivers/i2c/busses/i2c-intel-mid.c
@@ -999,7 +999,7 @@ static int __devinit intel_mid_i2c_probe(struct pci_dev *dev,
/* Initialize struct members */
snprintf(mrst->adap.name, sizeof(mrst->adap.name),
- "MRST/Medfield I2C at %lx", start);
+ "Intel MID I2C at %lx", start);
mrst->adap.owner = THIS_MODULE;
mrst->adap.algo = &intel_mid_i2c_algorithm;
mrst->adap.dev.parent = &dev->dev;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 112c61f7b8cd..f09c9319a2ba 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -409,7 +409,7 @@ iop3xx_i2c_remove(struct platform_device *pdev)
IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
__raw_writel(cr, adapter_data->ioaddr + CR_OFFSET);
- iounmap((void __iomem*)adapter_data->ioaddr);
+ iounmap(adapter_data->ioaddr);
release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
kfree(adapter_data);
kfree(padapter);
@@ -453,7 +453,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
/* set the adapter enumeration # */
adapter_data->id = i2c_id++;
- adapter_data->ioaddr = (u32)ioremap(res->start, IOP3XX_I2C_IO_SIZE);
+ adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE);
if (!adapter_data->ioaddr) {
ret = -ENOMEM;
goto release_region;
@@ -498,7 +498,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
return 0;
unmap:
- iounmap((void __iomem*)adapter_data->ioaddr);
+ iounmap(adapter_data->ioaddr);
release_region:
release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index 8485861f6a36..097e270955d0 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -97,7 +97,7 @@
#define IOP3XX_I2C_IO_SIZE 0x18
struct i2c_algo_iop3xx_data {
- u32 ioaddr;
+ void __iomem *ioaddr;
wait_queue_head_t waitq;
spinlock_t lock;
u32 SR_enabled, SR_received;
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 16242063144f..a9941c65f226 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -59,6 +59,7 @@ enum {
MV64XXX_I2C_STATE_INVALID,
MV64XXX_I2C_STATE_IDLE,
MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
@@ -70,6 +71,7 @@ enum {
MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_SEND_START,
+ MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1,
MV64XXX_I2C_ACTION_SEND_ADDR_2,
MV64XXX_I2C_ACTION_SEND_DATA,
@@ -91,6 +93,7 @@ struct mv64xxx_i2c_data {
u32 addr2;
u32 bytes_left;
u32 byte_posn;
+ u32 send_stop;
u32 block;
int rc;
u32 freq_m;
@@ -159,8 +162,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
if ((drv_data->bytes_left == 0)
|| (drv_data->aborting
&& (drv_data->byte_posn != 0))) {
- drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
- drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ if (drv_data->send_stop) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ } else {
+ drv_data->action =
+ MV64XXX_I2C_ACTION_SEND_RESTART;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
+ }
} else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
drv_data->state =
@@ -228,6 +238,15 @@ static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
switch(drv_data->action) {
+ case MV64XXX_I2C_ACTION_SEND_RESTART:
+ drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->block = 0;
+ wake_up_interruptible(&drv_data->waitq);
+ break;
+
case MV64XXX_I2C_ACTION_CONTINUE:
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
@@ -386,7 +405,8 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
}
static int
-mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
+ int is_first, int is_last)
{
unsigned long flags;
@@ -406,10 +426,18 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg)
drv_data->bytes_left--;
}
} else {
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ if (is_first) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+ }
}
+ drv_data->send_stop = is_last;
drv_data->block = 1;
mv64xxx_i2c_do_action(drv_data);
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -437,9 +465,12 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
int i, rc;
- for (i=0; i<num; i++)
- if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0)
+ for (i = 0; i < num; i++) {
+ rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
+ i == 0, i + 1 == num);
+ if (rc < 0)
return rc;
+ }
return num;
}
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index a605a5029cfe..ff1e127dfea8 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -432,7 +432,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
static void __devexit nforce2_remove(struct pci_dev *dev)
{
- struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
+ struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
nforce2_set_reference(NULL);
if (smbuses[0].base) {
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index c9fffd0389fe..594ed5059c4a 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -434,7 +434,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
}
if (timeout == 0) {
- /* controler has timedout, re-init the h/w */
+ /* controller has timedout, re-init the h/w */
dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
(void) init_hw(dev);
status = -ETIMEDOUT;
@@ -498,7 +498,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
}
if (timeout == 0) {
- /* controler has timedout, re-init the h/w */
+ /* controller has timedout, re-init the h/w */
dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
(void) init_hw(dev);
status = -ETIMEDOUT;
@@ -872,6 +872,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &nmk_i2c_algo;
+ snprintf(adap->name, sizeof(adap->name),
+ "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
/* fetch the controller id */
adap->nr = pdev->id;
@@ -891,8 +893,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
goto err_init_hw;
}
- dev_dbg(&pdev->dev, "initialize I2C%d bus on virtual "
- "base %p\n", pdev->id, dev->virtbase);
+ dev_info(&pdev->dev, "initialize %s on virtual "
+ "base %p\n", adap->name, dev->virtbase);
ret = i2c_add_numbered_adapter(adap);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 0070371b29f3..ef3bcb1ce864 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -9,6 +9,41 @@
* kind, whether express or implied.
*/
+/*
+ * Device tree configuration:
+ *
+ * Required properties:
+ * - compatible : "opencores,i2c-ocores"
+ * - reg : bus address start and address range size of device
+ * - interrupts : interrupt number
+ * - regstep : size of device registers in bytes
+ * - clock-frequency : frequency of bus clock in Hz
+ *
+ * Example:
+ *
+ * i2c0: ocores@a0000000 {
+ * compatible = "opencores,i2c-ocores";
+ * reg = <0xa0000000 0x8>;
+ * interrupts = <10>;
+ *
+ * regstep = <1>;
+ * clock-frequency = <20000000>;
+ *
+ * -- Devices connected on this I2C bus get
+ * -- defined here; address- and size-cells
+ * -- apply to these child devices
+ *
+ * #address-cells = <1>;
+ * #size-cells = <0>;
+ *
+ * dummy@60 {
+ * compatible = "dummy";
+ * reg = <60>;
+ * };
+ * };
+ *
+ */
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -210,6 +245,32 @@ static struct i2c_adapter ocores_adapter = {
.algo = &ocores_algorithm,
};
+#ifdef CONFIG_OF
+static int ocores_i2c_of_probe(struct platform_device* pdev,
+ struct ocores_i2c* i2c)
+{
+ __be32* val;
+
+ val = of_get_property(pdev->dev.of_node, "regstep", NULL);
+ if (!val) {
+ dev_err(&pdev->dev, "Missing required parameter 'regstep'");
+ return -ENODEV;
+ }
+ i2c->regstep = be32_to_cpup(val);
+
+ val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
+ if (!val) {
+ dev_err(&pdev->dev,
+ "Missing required parameter 'clock-frequency'");
+ return -ENODEV;
+ }
+ i2c->clock_khz = be32_to_cpup(val) / 1000;
+
+ return 0;
+}
+#else
+#define ocores_i2c_of_probe(pdev,i2c) -ENODEV
+#endif
static int __devinit ocores_i2c_probe(struct platform_device *pdev)
{
@@ -227,37 +288,41 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
if (!res2)
return -ENODEV;
- pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
- if (!pdata)
- return -ENODEV;
-
- i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
- if (!request_mem_region(res->start, resource_size(res),
- pdev->name)) {
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "Memory region busy\n");
- ret = -EBUSY;
- goto request_mem_failed;
+ return -EBUSY;
}
- i2c->base = ioremap(res->start, resource_size(res));
+ i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
if (!i2c->base) {
dev_err(&pdev->dev, "Unable to map registers\n");
- ret = -EIO;
- goto map_failed;
+ return -EIO;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (pdata) {
+ i2c->regstep = pdata->regstep;
+ i2c->clock_khz = pdata->clock_khz;
+ } else {
+ ret = ocores_i2c_of_probe(pdev, i2c);
+ if (ret)
+ return ret;
}
- i2c->regstep = pdata->regstep;
- i2c->clock_khz = pdata->clock_khz;
ocores_init(i2c);
init_waitqueue_head(&i2c->wait);
- ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c);
+ ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,
+ pdev->name, i2c);
if (ret) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
- goto request_irq_failed;
+ return ret;
}
/* hook up driver to tree */
@@ -265,36 +330,29 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
i2c->adap = ocores_adapter;
i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &pdev->dev;
+#ifdef CONFIG_OF
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+#endif
/* add i2c adapter to i2c tree */
ret = i2c_add_adapter(&i2c->adap);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter\n");
- goto add_adapter_failed;
+ return ret;
}
/* add in known devices to the bus */
- for (i = 0; i < pdata->num_devices; i++)
- i2c_new_device(&i2c->adap, pdata->devices + i);
+ if (pdata) {
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+ }
return 0;
-
-add_adapter_failed:
- free_irq(res2->start, i2c);
-request_irq_failed:
- iounmap(i2c->base);
-map_failed:
- release_mem_region(res->start, resource_size(res));
-request_mem_failed:
- kfree(i2c);
-
- return ret;
}
static int __devexit ocores_i2c_remove(struct platform_device* pdev)
{
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
- struct resource *res;
/* disable i2c logic */
oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
@@ -304,18 +362,6 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
i2c_del_adapter(&i2c->adap);
platform_set_drvdata(pdev, NULL);
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res)
- free_irq(res->start, i2c);
-
- iounmap(i2c->base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
-
- kfree(i2c);
-
return 0;
}
@@ -344,6 +390,16 @@ static int ocores_i2c_resume(struct platform_device *pdev)
#define ocores_i2c_resume NULL
#endif
+#ifdef CONFIG_OF
+static struct of_device_id ocores_i2c_match[] = {
+ {
+ .compatible = "opencores,i2c-ocores",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ocores_i2c_match);
+#endif
+
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:ocores-i2c");
@@ -355,6 +411,9 @@ static struct platform_driver ocores_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ocores-i2c",
+#ifdef CONFIG_OF
+ .of_match_table = ocores_i2c_match,
+#endif
},
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index b33c78586bfc..b605ff3a1fa0 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -39,6 +39,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/i2c-omap.h>
+#include <linux/pm_runtime.h>
/* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20
@@ -175,8 +176,6 @@ struct omap_i2c_dev {
void __iomem *base; /* virtual */
int irq;
int reg_shift; /* bit shift for I2C register addresses */
- struct clk *iclk; /* Interface clock */
- struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
struct resource *ioarea;
u32 latency; /* maximum mpu wkup latency */
@@ -265,45 +264,18 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
}
-static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+static void omap_i2c_unidle(struct omap_i2c_dev *dev)
{
- int ret;
-
- dev->iclk = clk_get(dev->dev, "ick");
- if (IS_ERR(dev->iclk)) {
- ret = PTR_ERR(dev->iclk);
- dev->iclk = NULL;
- return ret;
- }
+ struct platform_device *pdev;
+ struct omap_i2c_bus_platform_data *pdata;
- dev->fclk = clk_get(dev->dev, "fck");
- if (IS_ERR(dev->fclk)) {
- ret = PTR_ERR(dev->fclk);
- if (dev->iclk != NULL) {
- clk_put(dev->iclk);
- dev->iclk = NULL;
- }
- dev->fclk = NULL;
- return ret;
- }
-
- return 0;
-}
+ WARN_ON(!dev->idle);
-static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
-{
- clk_put(dev->fclk);
- dev->fclk = NULL;
- clk_put(dev->iclk);
- dev->iclk = NULL;
-}
+ pdev = to_platform_device(dev->dev);
+ pdata = pdev->dev.platform_data;
-static void omap_i2c_unidle(struct omap_i2c_dev *dev)
-{
- WARN_ON(!dev->idle);
+ pm_runtime_get_sync(&pdev->dev);
- clk_enable(dev->iclk);
- clk_enable(dev->fclk);
if (cpu_is_omap34xx()) {
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
@@ -326,10 +298,15 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
static void omap_i2c_idle(struct omap_i2c_dev *dev)
{
+ struct platform_device *pdev;
+ struct omap_i2c_bus_platform_data *pdata;
u16 iv;
WARN_ON(dev->idle);
+ pdev = to_platform_device(dev->dev);
+ pdata = pdev->dev.platform_data;
+
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
if (dev->rev >= OMAP_I2C_REV_ON_4430)
omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
@@ -345,8 +322,8 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
}
dev->idle = 1;
- clk_disable(dev->fclk);
- clk_disable(dev->iclk);
+
+ pm_runtime_put_sync(&pdev->dev);
}
static int omap_i2c_init(struct omap_i2c_dev *dev)
@@ -356,6 +333,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
unsigned long fclk_rate = 12000000;
unsigned long timeout;
unsigned long internal_clk = 0;
+ struct clk *fclk;
if (dev->rev >= OMAP_I2C_REV_2) {
/* Disable I2C controller before soft reset */
@@ -414,7 +392,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* always returns 12MHz for the functional clock, we can
* do this bit unconditionally.
*/
- fclk_rate = clk_get_rate(dev->fclk);
+ fclk = clk_get(dev->dev, "fck");
+ fclk_rate = clk_get_rate(fclk);
+ clk_put(fclk);
/* TRM for 5912 says the I2C clock must be prescaled to be
* between 7 - 12 MHz. The XOR input clock is typically
@@ -443,7 +423,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
internal_clk = 9600;
else
internal_clk = 4000;
- fclk_rate = clk_get_rate(dev->fclk) / 1000;
+ fclk = clk_get(dev->dev, "fck");
+ fclk_rate = clk_get_rate(fclk) / 1000;
+ clk_put(fclk);
/* Compute prescaler divisor */
psc = fclk_rate / internal_clk;
@@ -616,12 +598,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, dev->latency);
r = wait_for_completion_timeout(&dev->cmd_complete,
OMAP_I2C_TIMEOUT);
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, -1);
dev->buf_len = 0;
if (r < 0)
return r;
@@ -672,12 +650,18 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (r < 0)
goto out;
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+
for (i = 0; i < num; i++) {
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
if (r != 0)
break;
}
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, -1);
+
if (r == 0)
r = num;
@@ -1048,14 +1032,12 @@ omap_i2c_probe(struct platform_device *pdev)
else
dev->reg_shift = 2;
- if ((r = omap_i2c_get_clocks(dev)) != 0)
- goto err_iounmap;
-
if (cpu_is_omap44xx())
dev->regs = (u8 *) omap4_reg_map;
else
dev->regs = (u8 *) reg_map;
+ pm_runtime_enable(&pdev->dev);
omap_i2c_unidle(dev);
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
@@ -1127,8 +1109,6 @@ err_free_irq:
err_unuse_clocks:
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
omap_i2c_idle(dev);
- omap_i2c_put_clocks(dev);
-err_iounmap:
iounmap(dev->base);
err_free_mem:
platform_set_drvdata(pdev, NULL);
@@ -1150,7 +1130,6 @@ omap_i2c_remove(struct platform_device *pdev)
free_irq(dev->irq, dev);
i2c_del_adapter(&dev->adapter);
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
- omap_i2c_put_clocks(dev);
iounmap(dev->base);
kfree(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1162,7 +1141,7 @@ static struct platform_driver omap_i2c_driver = {
.probe = omap_i2c_probe,
.remove = omap_i2c_remove,
.driver = {
- .name = "i2c_omap",
+ .name = "omap_i2c",
.owner = THIS_MODULE,
},
};
@@ -1184,4 +1163,4 @@ module_exit(omap_i2c_exit_driver);
MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:i2c_omap");
+MODULE_ALIAS("platform:omap_i2c");
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 53fab518b3da..986e5f62debe 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -40,6 +41,7 @@
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
MODULE_LICENSE("GPL");
#define MAX_DEVICES 4
@@ -84,10 +86,6 @@ struct scx200_acb_iface {
u8 *ptr;
char needs_reset;
unsigned len;
-
- /* PCI device info */
- struct pci_dev *pdev;
- int bar;
};
/* Register Definitions */
@@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
static struct scx200_acb_iface *scx200_acb_list;
static DEFINE_MUTEX(scx200_acb_list_mutex);
-static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
{
u8 val;
@@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
return 0;
}
-static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
struct device *dev, int index)
{
struct scx200_acb_iface *iface;
@@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
return iface;
}
-static int __init scx200_acb_create(struct scx200_acb_iface *iface)
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
{
struct i2c_adapter *adapter;
int rc;
@@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
return -ENODEV;
}
- mutex_lock(&scx200_acb_list_mutex);
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- mutex_unlock(&scx200_acb_list_mutex);
+ if (!adapter->dev.parent) {
+ /* If there's no dev, we're tracking (ISA) ifaces manually */
+ mutex_lock(&scx200_acb_list_mutex);
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ mutex_unlock(&scx200_acb_list_mutex);
+ }
return 0;
}
-static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
- int bar)
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+ unsigned long base, int index, struct device *dev)
{
struct scx200_acb_iface *iface;
int rc;
- iface = scx200_create_iface(text, &pdev->dev, 0);
+ iface = scx200_create_iface(text, dev, index);
if (iface == NULL)
- return -ENOMEM;
-
- iface->pdev = pdev;
- iface->bar = bar;
-
- rc = pci_enable_device_io(iface->pdev);
- if (rc)
- goto errout_free;
+ return NULL;
- rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
- if (rc) {
- printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
- iface->bar);
+ if (!request_region(base, 8, iface->adapter.name)) {
+ printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+ base, base + 8 - 1);
goto errout_free;
}
- iface->base = pci_resource_start(iface->pdev, iface->bar);
+ iface->base = base;
rc = scx200_acb_create(iface);
if (rc == 0)
- return 0;
+ return iface;
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
+ release_region(base, 8);
errout_free:
kfree(iface);
- return rc;
+ return NULL;
}
-static int __init scx200_create_isa(const char *text, unsigned long base,
- int index)
+static int __devinit scx200_probe(struct platform_device *pdev)
{
struct scx200_acb_iface *iface;
- int rc;
-
- iface = scx200_create_iface(text, NULL, index);
-
- if (iface == NULL)
- return -ENOMEM;
+ struct resource *res;
- if (!request_region(base, 8, iface->adapter.name)) {
- printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
- base, base + 8 - 1);
- rc = -EBUSY;
- goto errout_free;
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -ENODEV;
}
- iface->base = base;
- rc = scx200_acb_create(iface);
+ iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+ if (!iface)
+ return -EIO;
- if (rc == 0)
- return 0;
+ dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+ iface->adapter.name);
+ platform_set_drvdata(pdev, iface);
- release_region(base, 8);
- errout_free:
- kfree(iface);
- return rc;
+ return 0;
}
-/* Driver data is an index into the scx200_data array that indicates
- * the name and the BAR where the I/O address resource is located. ISA
- * devices are flagged with a bar value of -1 */
-
-static const struct pci_device_id scx200_pci[] __initconst = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
- .driver_data = 1 },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
- .driver_data = 2 },
- { 0, }
-};
-
-static struct {
- const char *name;
- int bar;
-} scx200_data[] = {
- { "SCx200", -1 },
- { "CS5535", 0 },
- { "CS5536", 0 }
-};
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+}
-static __init int scx200_scan_pci(void)
+static int __devexit scx200_remove(struct platform_device *pdev)
{
- int data, dev;
- int rc = -ENODEV;
- struct pci_dev *pdev;
+ struct scx200_acb_iface *iface;
- for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
- pdev = pci_get_device(scx200_pci[dev].vendor,
- scx200_pci[dev].device, NULL);
+ iface = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+ scx200_cleanup_iface(iface);
- if (pdev == NULL)
- continue;
+ return 0;
+}
- data = scx200_pci[dev].driver_data;
+static struct platform_driver scx200_pci_drv = {
+ .driver = {
+ .name = "cs5535-smb",
+ .owner = THIS_MODULE,
+ },
+ .probe = scx200_probe,
+ .remove = __devexit_p(scx200_remove),
+};
- /* if .bar is greater or equal to zero, this is a
- * PCI device - otherwise, we assume
- that the ports are ISA based
- */
+static const struct pci_device_id scx200_isa[] __initconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+ { 0, }
+};
- if (scx200_data[data].bar >= 0)
- rc = scx200_create_pci(scx200_data[data].name, pdev,
- scx200_data[data].bar);
- else {
- int i;
+static __init void scx200_scan_isa(void)
+{
+ int i;
- pci_dev_put(pdev);
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] == 0)
- continue;
+ if (!pci_dev_present(scx200_isa))
+ return;
- rc = scx200_create_isa(scx200_data[data].name,
- base[i],
- i);
- }
- }
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
- break;
+ /* XXX: should we care about failures? */
+ scx200_create_dev("SCx200", base[i], i, NULL);
}
-
- return rc;
}
static int __init scx200_acb_init(void)
{
- int rc;
-
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
- rc = scx200_scan_pci();
+ /* First scan for ISA-based devices */
+ scx200_scan_isa(); /* XXX: should we care about errors? */
/* If at least one bus was created, init must succeed */
if (scx200_acb_list)
return 0;
- return rc;
+
+ /* No ISA devices; register the platform driver for PCI-based devices */
+ return platform_driver_register(&scx200_pci_drv);
}
static void __exit scx200_acb_cleanup(void)
{
struct scx200_acb_iface *iface;
+ platform_driver_unregister(&scx200_pci_drv);
+
mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) {
scx200_acb_list = iface->next;
mutex_unlock(&scx200_acb_list_mutex);
- i2c_del_adapter(&iface->adapter);
-
- if (iface->pdev) {
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
- }
- else
- release_region(iface->base, 8);
+ scx200_cleanup_iface(iface);
- kfree(iface);
mutex_lock(&scx200_acb_list_mutex);
}
mutex_unlock(&scx200_acb_list_mutex);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d231f683f576..f0bd5bcdf563 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -196,88 +196,60 @@ static int i2c_device_pm_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->suspend ? pm->suspend(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_SUSPEND);
+ if (pm)
+ return pm_generic_suspend(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}
static int i2c_device_pm_resume(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- int ret;
if (pm)
- ret = pm->resume ? pm->resume(dev) : 0;
+ return pm_generic_resume(dev);
else
- ret = i2c_legacy_resume(dev);
-
- return ret;
+ return i2c_legacy_resume(dev);
}
static int i2c_device_pm_freeze(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->freeze ? pm->freeze(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_FREEZE);
+ if (pm)
+ return pm_generic_freeze(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_FREEZE);
}
static int i2c_device_pm_thaw(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->thaw ? pm->thaw(dev) : 0;
- }
-
- return i2c_legacy_resume(dev);
+ if (pm)
+ return pm_generic_thaw(dev);
+ else
+ return i2c_legacy_resume(dev);
}
static int i2c_device_pm_poweroff(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->poweroff ? pm->poweroff(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
+ if (pm)
+ return pm_generic_poweroff(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
}
static int i2c_device_pm_restore(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- int ret;
if (pm)
- ret = pm->restore ? pm->restore(dev) : 0;
+ return pm_generic_restore(dev);
else
- ret = i2c_legacy_resume(dev);
-
- if (!ret) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
- return ret;
+ return i2c_legacy_resume(dev);
}
#else /* !CONFIG_PM_SLEEP */
#define i2c_device_pm_suspend NULL
@@ -848,6 +820,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
+ /* Sanity checks */
+ if (unlikely(adap->name[0] == '\0')) {
+ pr_err("i2c-core: Attempt to register an adapter with "
+ "no name!\n");
+ return -EINVAL;
+ }
+ if (unlikely(!adap->algo)) {
+ pr_err("i2c-core: Attempt to register adapter '%s' with "
+ "no algo!\n", adap->name);
+ return -EINVAL;
+ }
+
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
@@ -1009,6 +993,14 @@ static int i2c_do_del_adapter(struct i2c_driver *driver,
static int __unregister_client(struct device *dev, void *dummy)
{
struct i2c_client *client = i2c_verify_client(dev);
+ if (client && strcmp(client->name, "dummy"))
+ i2c_unregister_device(client);
+ return 0;
+}
+
+static int __unregister_dummy(struct device *dev, void *dummy)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
if (client)
i2c_unregister_device(client);
return 0;
@@ -1063,8 +1055,12 @@ int i2c_del_adapter(struct i2c_adapter *adap)
mutex_unlock(&adap->userspace_clients_lock);
/* Detach any active clients. This can't fail, thus we do not
- checking the returned value. */
+ * check the returned value. This is a two-pass process, because
+ * we can't remove the dummy devices during the first pass: they
+ * could have been instantiated by real devices wishing to clean
+ * them up properly, so we give them a chance to do that first. */
res = device_for_each_child(&adap->dev, NULL, __unregister_client);
+ res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);
#ifdef CONFIG_I2C_COMPAT
class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
@@ -1128,6 +1124,14 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
if (res)
return res;
+ /* Drivers should switch to dev_pm_ops instead. */
+ if (driver->suspend)
+ pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
+ driver->driver.name);
+ if (driver->resume)
+ pr_warn("i2c-core: driver [%s] using legacy resume method\n",
+ driver->driver.name);
+
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
@@ -1350,7 +1354,7 @@ EXPORT_SYMBOL(i2c_transfer);
*
* Returns negative errno, or else the number of bytes written.
*/
-int i2c_master_send(struct i2c_client *client, const char *buf, int count)
+int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
int ret;
struct i2c_adapter *adap = client->adapter;
@@ -1377,7 +1381,7 @@ EXPORT_SYMBOL(i2c_master_send);
*
* Returns negative errno, or else the number of bytes read.
*/
-int i2c_master_recv(struct i2c_client *client, char *buf, int count)
+int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
@@ -1667,7 +1671,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
* This executes the SMBus "receive byte" protocol, returning negative errno
* else the byte received from the device.
*/
-s32 i2c_smbus_read_byte(struct i2c_client *client)
+s32 i2c_smbus_read_byte(const struct i2c_client *client)
{
union i2c_smbus_data data;
int status;
@@ -1687,7 +1691,7 @@ EXPORT_SYMBOL(i2c_smbus_read_byte);
* This executes the SMBus "send byte" protocol, returning negative errno
* else zero on success.
*/
-s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
+s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
@@ -1702,7 +1706,7 @@ EXPORT_SYMBOL(i2c_smbus_write_byte);
* This executes the SMBus "read byte" protocol, returning negative errno
* else a data byte received from the device.
*/
-s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
+s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
{
union i2c_smbus_data data;
int status;
@@ -1723,7 +1727,8 @@ EXPORT_SYMBOL(i2c_smbus_read_byte_data);
* This executes the SMBus "write byte" protocol, returning negative errno
* else zero on success.
*/
-s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
+s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
+ u8 value)
{
union i2c_smbus_data data;
data.byte = value;
@@ -1741,7 +1746,7 @@ EXPORT_SYMBOL(i2c_smbus_write_byte_data);
* This executes the SMBus "read word" protocol, returning negative errno
* else a 16-bit unsigned "word" received from the device.
*/
-s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
+s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
{
union i2c_smbus_data data;
int status;
@@ -1762,7 +1767,8 @@ EXPORT_SYMBOL(i2c_smbus_read_word_data);
* This executes the SMBus "write word" protocol, returning negative errno
* else zero on success.
*/
-s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
+s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
+ u16 value)
{
union i2c_smbus_data data;
data.word = value;
@@ -1781,7 +1787,8 @@ EXPORT_SYMBOL(i2c_smbus_write_word_data);
* This executes the SMBus "process call" protocol, returning negative errno
* else a 16-bit unsigned "word" received from the device.
*/
-s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
+s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command,
+ u16 value)
{
union i2c_smbus_data data;
int status;
@@ -1809,7 +1816,7 @@ EXPORT_SYMBOL(i2c_smbus_process_call);
* support this; its emulation through I2C messaging relies on a specific
* mechanism (I2C_M_RECV_LEN) which may not be implemented.
*/
-s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
+s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command,
u8 *values)
{
union i2c_smbus_data data;
@@ -1836,7 +1843,7 @@ EXPORT_SYMBOL(i2c_smbus_read_block_data);
* This executes the SMBus "block write" protocol, returning negative errno
* else zero on success.
*/
-s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
+s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
union i2c_smbus_data data;
@@ -1852,7 +1859,7 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
EXPORT_SYMBOL(i2c_smbus_write_block_data);
/* Returns the number of read bytes */
-s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
+s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command,
u8 length, u8 *values)
{
union i2c_smbus_data data;
@@ -1872,7 +1879,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
}
EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
-s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
+s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
union i2c_smbus_data data;
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index d32a4843fc3a..d7a4833be416 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -120,7 +120,6 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
snprintf(priv->adap.name, sizeof(priv->adap.name),
"i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
priv->adap.owner = THIS_MODULE;
- priv->adap.id = parent->id;
priv->adap.algo = &priv->algo;
priv->adap.algo_data = priv;
priv->adap.dev.parent = &parent->dev;
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 4d91d80bfd23..90b7a0163899 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -5,6 +5,18 @@
menu "Multiplexer I2C Chip support"
depends on I2C_MUX
+config I2C_MUX_GPIO
+ tristate "GPIO-based I2C multiplexer"
+ depends on GENERIC_GPIO
+ help
+ If you say yes to this option, support will be included for a
+ GPIO based I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which is controlled
+ through GPIO pins.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-i2cmux.
+
config I2C_MUX_PCA9541
tristate "NXP PCA9541 I2C Master Selector"
depends on EXPERIMENTAL
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index d743806d9b42..4640436ea61f 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -1,6 +1,7 @@
#
# Makefile for multiplexer I2C chip drivers.
+obj-$(CONFIG_I2C_MUX_GPIO) += gpio-i2cmux.o
obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c
new file mode 100644
index 000000000000..7b6ce624cd6e
--- /dev/null
+++ b/drivers/i2c/muxes/gpio-i2cmux.c
@@ -0,0 +1,184 @@
+/*
+ * I2C multiplexer using GPIO API
+ *
+ * Peter Korsgaard <peter.korsgaard@barco.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/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/gpio-i2cmux.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+struct gpiomux {
+ struct i2c_adapter *parent;
+ struct i2c_adapter **adap; /* child busses */
+ struct gpio_i2cmux_platform_data data;
+};
+
+static void gpiomux_set(const struct gpiomux *mux, unsigned val)
+{
+ int i;
+
+ for (i = 0; i < mux->data.n_gpios; i++)
+ gpio_set_value(mux->data.gpios[i], val & (1 << i));
+}
+
+static int gpiomux_select(struct i2c_adapter *adap, void *data, u32 chan)
+{
+ struct gpiomux *mux = data;
+
+ gpiomux_set(mux, mux->data.values[chan]);
+
+ return 0;
+}
+
+static int gpiomux_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+{
+ struct gpiomux *mux = data;
+
+ gpiomux_set(mux, mux->data.idle);
+
+ return 0;
+}
+
+static int __devinit gpiomux_probe(struct platform_device *pdev)
+{
+ struct gpiomux *mux;
+ struct gpio_i2cmux_platform_data *pdata;
+ struct i2c_adapter *parent;
+ int (*deselect) (struct i2c_adapter *, void *, u32);
+ unsigned initial_state;
+ int i, ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(pdata->parent);
+ if (!parent) {
+ dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
+ pdata->parent);
+ return -ENODEV;
+ }
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ mux->parent = parent;
+ mux->data = *pdata;
+ mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values,
+ GFP_KERNEL);
+ if (!mux->adap) {
+ ret = -ENOMEM;
+ goto alloc_failed2;
+ }
+
+ if (pdata->idle != GPIO_I2CMUX_NO_IDLE) {
+ initial_state = pdata->idle;
+ deselect = gpiomux_deselect;
+ } else {
+ initial_state = pdata->values[0];
+ deselect = NULL;
+ }
+
+ for (i = 0; i < pdata->n_gpios; i++) {
+ ret = gpio_request(pdata->gpios[i], "gpio-i2cmux");
+ if (ret)
+ goto err_request_gpio;
+ gpio_direction_output(pdata->gpios[i],
+ initial_state & (1 << i));
+ }
+
+ for (i = 0; i < pdata->n_values; i++) {
+ u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
+
+ mux->adap[i] = i2c_add_mux_adapter(parent, mux, nr, i,
+ gpiomux_select, deselect);
+ if (!mux->adap[i]) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
+ goto add_adapter_failed;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d port mux on %s adapter\n",
+ pdata->n_values, parent->name);
+
+ platform_set_drvdata(pdev, mux);
+
+ return 0;
+
+add_adapter_failed:
+ for (; i > 0; i--)
+ i2c_del_mux_adapter(mux->adap[i - 1]);
+ i = pdata->n_gpios;
+err_request_gpio:
+ for (; i > 0; i--)
+ gpio_free(pdata->gpios[i - 1]);
+ kfree(mux->adap);
+alloc_failed2:
+ kfree(mux);
+alloc_failed:
+ i2c_put_adapter(parent);
+
+ return ret;
+}
+
+static int __devexit gpiomux_remove(struct platform_device *pdev)
+{
+ struct gpiomux *mux = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < mux->data.n_values; i++)
+ i2c_del_mux_adapter(mux->adap[i]);
+
+ for (i = 0; i < mux->data.n_gpios; i++)
+ gpio_free(mux->data.gpios[i]);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_put_adapter(mux->parent);
+ kfree(mux->adap);
+ kfree(mux);
+
+ return 0;
+}
+
+static struct platform_driver gpiomux_driver = {
+ .probe = gpiomux_probe,
+ .remove = __devexit_p(gpiomux_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "gpio-i2cmux",
+ },
+};
+
+static int __init gpiomux_init(void)
+{
+ return platform_driver_register(&gpiomux_driver);
+}
+
+static void __exit gpiomux_exit(void)
+{
+ platform_driver_unregister(&gpiomux_driver);
+}
+
+module_init(gpiomux_init);
+module_exit(gpiomux_exit);
+
+MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
+MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-i2cmux");
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 41665d2f9f93..7acb32e7f817 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -59,6 +59,8 @@
#include <linux/hrtimer.h> /* ktime_get_real() */
#include <trace/events/power.h>
#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
#include <asm/mwait.h>
#define INTEL_IDLE_VERSION "0.4"
@@ -73,6 +75,7 @@ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
static unsigned int mwait_substates;
+#define LAPIC_TIMER_ALWAYS_RELIABLE 0xFFFFFFFF
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
@@ -82,6 +85,14 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
static struct cpuidle_state *cpuidle_state_table;
/*
+ * Set this flag for states where the HW flushes the TLB for us
+ * and so we don't need cross-calls to keep it consistent.
+ * If this flag is set, SW flushes the TLB, so even if the
+ * HW doesn't do the flushing, this flag is safe to use.
+ */
+#define CPUIDLE_FLAG_TLB_FLUSHED 0x10000
+
+/*
* States are indexed by the cstate number,
* which is also the index into the MWAIT hint array.
* Thus C0 is a dummy.
@@ -122,7 +133,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
- .target_residency = 4,
+ .target_residency = 1,
.enter = &intel_idle },
{ /* MWAIT C2 */
.name = "SNB-C3",
@@ -130,7 +141,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
- .target_residency = 160,
+ .target_residency = 211,
.enter = &intel_idle },
{ /* MWAIT C3 */
.name = "SNB-C6",
@@ -138,7 +149,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
- .target_residency = 208,
+ .target_residency = 345,
.enter = &intel_idle },
{ /* MWAIT C4 */
.name = "SNB-C7",
@@ -146,7 +157,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
- .target_residency = 300,
+ .target_residency = 345,
.enter = &intel_idle },
};
@@ -220,9 +231,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
kt_before = ktime_get_real();
stop_critical_timings();
-#ifndef MODULE
- trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu);
-#endif
if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -244,6 +252,39 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
return usec_delta;
}
+static void __setup_broadcast_timer(void *arg)
+{
+ unsigned long reason = (unsigned long)arg;
+ int cpu = smp_processor_id();
+
+ reason = reason ?
+ CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+ clockevents_notify(reason, &cpu);
+}
+
+static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n,
+ unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+
+ switch (action & 0xf) {
+ case CPU_ONLINE:
+ smp_call_function_single(hotcpu, __setup_broadcast_timer,
+ (void *)true, 1);
+ break;
+ case CPU_DOWN_PREPARE:
+ smp_call_function_single(hotcpu, __setup_broadcast_timer,
+ (void *)false, 1);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata setup_broadcast_notifier = {
+ .notifier_call = setup_broadcast_cpuhp_notify,
+};
+
/*
* intel_idle_probe()
*/
@@ -273,8 +314,6 @@ static int intel_idle_probe(void)
pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
- if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
- lapic_timer_reliable_states = 0xFFFFFFFF;
if (boot_cpu_data.x86 != 6) /* family 6 */
return -ENODEV;
@@ -286,8 +325,6 @@ static int intel_idle_probe(void)
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
case 0x2E: /* Nehalem-EX Xeon */
case 0x2F: /* Westmere-EX Xeon */
- lapic_timer_reliable_states = (1 << 1); /* C1 */
-
case 0x25: /* Westmere */
case 0x2C: /* Westmere */
cpuidle_state_table = nehalem_cstates;
@@ -295,7 +332,6 @@ static int intel_idle_probe(void)
case 0x1C: /* 28 - Atom Processor */
case 0x26: /* 38 - Lincroft Atom Processor */
- lapic_timer_reliable_states = (1 << 1); /* C1 */
cpuidle_state_table = atom_cstates;
break;
@@ -303,10 +339,6 @@ static int intel_idle_probe(void)
case 0x2D: /* SNB Xeon */
cpuidle_state_table = snb_cstates;
break;
-#ifdef FUTURE_USE
- case 0x17: /* 23 - Core 2 Duo */
- lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
-#endif
default:
pr_debug(PREFIX "does not run on family %d model %d\n",
@@ -314,6 +346,13 @@ static int intel_idle_probe(void)
return -ENODEV;
}
+ if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
+ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
+ else {
+ smp_call_function(__setup_broadcast_timer, (void *)true, 1);
+ register_cpu_notifier(&setup_broadcast_notifier);
+ }
+
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
" model 0x%X\n", boot_cpu_data.x86_model);
@@ -410,6 +449,10 @@ static int __init intel_idle_init(void)
{
int retval;
+ /* Do not load intel_idle at all for now if idle= is passed */
+ if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+ return -ENODEV;
+
retval = intel_idle_probe();
if (retval)
return retval;
@@ -435,6 +478,11 @@ static void __exit intel_idle_exit(void)
intel_idle_cpuidle_devices_uninit();
cpuidle_unregister_driver(&intel_idle_driver);
+ if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
+ smp_call_function(__setup_broadcast_timer, (void *)false, 1);
+ unregister_cpu_notifier(&setup_broadcast_notifier);
+ }
+
return;
}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index a5ea1bce9689..8aba0ba57de5 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -130,8 +130,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
- read_lock(&dev_base_lock);
- for_each_netdev(&init_net, dev) {
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
if (ipv6_chk_addr(&init_net,
&((struct sockaddr_in6 *) addr)->sin6_addr,
dev, 1)) {
@@ -139,7 +139,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
break;
}
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
break;
#endif
}
@@ -200,7 +200,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,
src_in->sin_family = AF_INET;
src_in->sin_addr.s_addr = rt->rt_src;
- if (rt->idev->dev->flags & IFF_LOOPBACK) {
+ if (rt->dst.dev->flags & IFF_LOOPBACK) {
ret = rdma_translate_ip((struct sockaddr *) dst_in, addr);
if (!ret)
memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
@@ -208,12 +208,12 @@ static int addr4_resolve(struct sockaddr_in *src_in,
}
/* If the device does ARP internally, return 'done' */
- if (rt->idev->dev->flags & IFF_NOARP) {
- rdma_copy_addr(addr, rt->idev->dev, NULL);
+ if (rt->dst.dev->flags & IFF_NOARP) {
+ rdma_copy_addr(addr, rt->dst.dev, NULL);
goto put;
}
- neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
+ neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
neigh_event_send(rt->dst.neighbour, NULL);
ret = -ENODATA;
diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c
index bb7e19280821..9b737ff133e2 100644
--- a/drivers/infiniband/core/ud_header.c
+++ b/drivers/infiniband/core/ud_header.c
@@ -278,36 +278,6 @@ void ib_ud_header_init(int payload_bytes,
EXPORT_SYMBOL(ib_ud_header_init);
/**
- * ib_lrh_header_pack - Pack LRH header struct into wire format
- * @lrh:unpacked LRH header struct
- * @buf:Buffer to pack into
- *
- * ib_lrh_header_pack() packs the LRH header structure @lrh into
- * wire format in the buffer @buf.
- */
-int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf)
-{
- ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf);
- return 0;
-}
-EXPORT_SYMBOL(ib_lrh_header_pack);
-
-/**
- * ib_lrh_header_unpack - Unpack LRH structure from wire format
- * @lrh:unpacked LRH header struct
- * @buf:Buffer to pack into
- *
- * ib_lrh_header_unpack() unpacks the LRH header structure from
- * wire format (in buf) into @lrh.
- */
-int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh)
-{
- ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh);
- return 0;
-}
-EXPORT_SYMBOL(ib_lrh_header_unpack);
-
-/**
* ib_ud_header_pack - Pack UD header struct into wire format
* @header:UD header struct
* @buf:Buffer to pack into
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index b342248aec05..c42699285f8e 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -893,68 +893,81 @@ out:
return ret ? ret : in_len;
}
+static int copy_wc_to_user(void __user *dest, struct ib_wc *wc)
+{
+ struct ib_uverbs_wc tmp;
+
+ tmp.wr_id = wc->wr_id;
+ tmp.status = wc->status;
+ tmp.opcode = wc->opcode;
+ tmp.vendor_err = wc->vendor_err;
+ tmp.byte_len = wc->byte_len;
+ tmp.ex.imm_data = (__u32 __force) wc->ex.imm_data;
+ tmp.qp_num = wc->qp->qp_num;
+ tmp.src_qp = wc->src_qp;
+ tmp.wc_flags = wc->wc_flags;
+ tmp.pkey_index = wc->pkey_index;
+ tmp.slid = wc->slid;
+ tmp.sl = wc->sl;
+ tmp.dlid_path_bits = wc->dlid_path_bits;
+ tmp.port_num = wc->port_num;
+ tmp.reserved = 0;
+
+ if (copy_to_user(dest, &tmp, sizeof tmp))
+ return -EFAULT;
+
+ return 0;
+}
+
ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_poll_cq cmd;
- struct ib_uverbs_poll_cq_resp *resp;
+ struct ib_uverbs_poll_cq_resp resp;
+ u8 __user *header_ptr;
+ u8 __user *data_ptr;
struct ib_cq *cq;
- struct ib_wc *wc;
- int ret = 0;
- int i;
- int rsize;
+ struct ib_wc wc;
+ int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
- if (!wc)
- return -ENOMEM;
-
- rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
- resp = kmalloc(rsize, GFP_KERNEL);
- if (!resp) {
- ret = -ENOMEM;
- goto out_wc;
- }
-
cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
- if (!cq) {
- ret = -EINVAL;
- goto out;
- }
+ if (!cq)
+ return -EINVAL;
- resp->count = ib_poll_cq(cq, cmd.ne, wc);
+ /* we copy a struct ib_uverbs_poll_cq_resp to user space */
+ header_ptr = (void __user *)(unsigned long) cmd.response;
+ data_ptr = header_ptr + sizeof resp;
- put_cq_read(cq);
+ memset(&resp, 0, sizeof resp);
+ while (resp.count < cmd.ne) {
+ ret = ib_poll_cq(cq, 1, &wc);
+ if (ret < 0)
+ goto out_put;
+ if (!ret)
+ break;
+
+ ret = copy_wc_to_user(data_ptr, &wc);
+ if (ret)
+ goto out_put;
- for (i = 0; i < resp->count; i++) {
- resp->wc[i].wr_id = wc[i].wr_id;
- resp->wc[i].status = wc[i].status;
- resp->wc[i].opcode = wc[i].opcode;
- resp->wc[i].vendor_err = wc[i].vendor_err;
- resp->wc[i].byte_len = wc[i].byte_len;
- resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data;
- resp->wc[i].qp_num = wc[i].qp->qp_num;
- resp->wc[i].src_qp = wc[i].src_qp;
- resp->wc[i].wc_flags = wc[i].wc_flags;
- resp->wc[i].pkey_index = wc[i].pkey_index;
- resp->wc[i].slid = wc[i].slid;
- resp->wc[i].sl = wc[i].sl;
- resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
- resp->wc[i].port_num = wc[i].port_num;
+ data_ptr += sizeof(struct ib_uverbs_wc);
+ ++resp.count;
}
- if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
+ if (copy_to_user(header_ptr, &resp, sizeof resp)) {
ret = -EFAULT;
+ goto out_put;
+ }
-out:
- kfree(resp);
+ ret = in_len;
-out_wc:
- kfree(wc);
- return ret ? ret : in_len;
+out_put:
+ put_cq_read(cq);
+ return ret;
}
ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c
index 5440da0e59b4..1b1146f87124 100644
--- a/drivers/infiniband/core/uverbs_marshall.c
+++ b/drivers/infiniband/core/uverbs_marshall.c
@@ -40,18 +40,21 @@ void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
dst->grh.sgid_index = src->grh.sgid_index;
dst->grh.hop_limit = src->grh.hop_limit;
dst->grh.traffic_class = src->grh.traffic_class;
+ memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved));
dst->dlid = src->dlid;
dst->sl = src->sl;
dst->src_path_bits = src->src_path_bits;
dst->static_rate = src->static_rate;
dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0;
dst->port_num = src->port_num;
+ dst->reserved = 0;
}
EXPORT_SYMBOL(ib_copy_ah_attr_to_user);
void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
struct ib_qp_attr *src)
{
+ dst->qp_state = src->qp_state;
dst->cur_qp_state = src->cur_qp_state;
dst->path_mtu = src->path_mtu;
dst->path_mig_state = src->path_mig_state;
@@ -83,6 +86,7 @@ void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
dst->rnr_retry = src->rnr_retry;
dst->alt_port_num = src->alt_port_num;
dst->alt_timeout = src->alt_timeout;
+ memset(dst->reserved, 0, sizeof(dst->reserved));
}
EXPORT_SYMBOL(ib_copy_qp_attr_to_user);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 09dda0b8740e..c3f5aca4ef00 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -189,6 +189,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
}
+#ifdef notyet
int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
{
struct rdma_cq_setup setup;
@@ -200,6 +201,7 @@ int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
setup.ovfl_mode = 1;
return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
}
+#endif
static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
{
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index 4bb997aa39d0..83d2e19d31ae 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -689,7 +689,7 @@ struct t3_swrq {
* A T3 WQ implements both the SQ and RQ.
*/
struct t3_wq {
- union t3_wr *queue; /* DMA accessable memory */
+ union t3_wr *queue; /* DMA accessible memory */
dma_addr_t dma_addr; /* DMA address for HW */
DEFINE_DMA_UNMAP_ADDR(mapping); /* unmap kruft */
u32 error; /* 1 once we go to ERROR */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index a237d49bdcc9..c5406da3f4cd 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -335,8 +335,6 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg);
int iwch_post_zb_read(struct iwch_qp *qhp);
int iwch_register_device(struct iwch_dev *dev);
void iwch_unregister_device(struct iwch_dev *dev);
-int iwch_quiesce_qps(struct iwch_cq *chp);
-int iwch_resume_qps(struct iwch_cq *chp);
void stop_read_rep_timer(struct iwch_qp *qhp);
int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
struct iwch_mr *mhp, int shift);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 0993137181d7..1b4cd09f74dc 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -1149,59 +1149,3 @@ out:
PDBG("%s exit state %d\n", __func__, qhp->attr.state);
return ret;
}
-
-static int quiesce_qp(struct iwch_qp *qhp)
-{
- spin_lock_irq(&qhp->lock);
- iwch_quiesce_tid(qhp->ep);
- qhp->flags |= QP_QUIESCED;
- spin_unlock_irq(&qhp->lock);
- return 0;
-}
-
-static int resume_qp(struct iwch_qp *qhp)
-{
- spin_lock_irq(&qhp->lock);
- iwch_resume_tid(qhp->ep);
- qhp->flags &= ~QP_QUIESCED;
- spin_unlock_irq(&qhp->lock);
- return 0;
-}
-
-int iwch_quiesce_qps(struct iwch_cq *chp)
-{
- int i;
- struct iwch_qp *qhp;
-
- for (i=0; i < T3_MAX_NUM_QP; i++) {
- qhp = get_qhp(chp->rhp, i);
- if (!qhp)
- continue;
- if ((qhp->attr.rcq == chp->cq.cqid) && !qp_quiesced(qhp)) {
- quiesce_qp(qhp);
- continue;
- }
- if ((qhp->attr.scq == chp->cq.cqid) && !qp_quiesced(qhp))
- quiesce_qp(qhp);
- }
- return 0;
-}
-
-int iwch_resume_qps(struct iwch_cq *chp)
-{
- int i;
- struct iwch_qp *qhp;
-
- for (i=0; i < T3_MAX_NUM_QP; i++) {
- qhp = get_qhp(chp->rhp, i);
- if (!qhp)
- continue;
- if ((qhp->attr.rcq == chp->cq.cqid) && qp_quiesced(qhp)) {
- resume_qp(qhp);
- continue;
- }
- if ((qhp->attr.scq == chp->cq.cqid) && qp_quiesced(qhp))
- resume_qp(qhp);
- }
- return 0;
-}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 16032cdb4337..2fe19ec9ba60 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -46,7 +46,6 @@
#include <linux/timer.h>
#include <linux/io.h>
#include <linux/kfifo.h>
-#include <linux/mutex.h>
#include <asm/byteorder.h>
@@ -760,7 +759,6 @@ int c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count);
int c4iw_flush_sq(struct t4_wq *wq, struct t4_cq *cq, int count);
int c4iw_ev_handler(struct c4iw_dev *rnicp, u32 qid);
u16 c4iw_rqes_posted(struct c4iw_qp *qhp);
-int c4iw_post_zb_read(struct c4iw_qp *qhp);
int c4iw_post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe);
u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx);
void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid,
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 057cb2505ea1..20800900ef3f 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -892,36 +892,6 @@ static inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type,
}
}
-int c4iw_post_zb_read(struct c4iw_qp *qhp)
-{
- union t4_wr *wqe;
- struct sk_buff *skb;
- u8 len16;
-
- PDBG("%s enter\n", __func__);
- skb = alloc_skb(40, GFP_KERNEL);
- if (!skb) {
- printk(KERN_ERR "%s cannot send zb_read!!\n", __func__);
- return -ENOMEM;
- }
- set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
-
- wqe = (union t4_wr *)skb_put(skb, sizeof wqe->read);
- memset(wqe, 0, sizeof wqe->read);
- wqe->read.r2 = cpu_to_be64(0);
- wqe->read.stag_sink = cpu_to_be32(1);
- wqe->read.to_sink_hi = cpu_to_be32(0);
- wqe->read.to_sink_lo = cpu_to_be32(1);
- wqe->read.stag_src = cpu_to_be32(1);
- wqe->read.plen = cpu_to_be32(0);
- wqe->read.to_src_hi = cpu_to_be32(0);
- wqe->read.to_src_lo = cpu_to_be32(1);
- len16 = DIV_ROUND_UP(sizeof wqe->read, 16);
- init_wr_hdr(wqe, 0, FW_RI_RDMA_READ_WR, FW_RI_COMPLETION_FLAG, len16);
-
- return c4iw_ofld_send(&qhp->rhp->rdev, skb);
-}
-
static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
gfp_t gfp)
{
@@ -1029,7 +999,6 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
wqe->cookie = (unsigned long) &ep->com.wr_wait;
wqe->u.fini.type = FW_RI_TYPE_FINI;
- c4iw_init_wr_wait(&ep->com.wr_wait);
ret = c4iw_ofld_send(&rhp->rdev, skb);
if (ret)
goto out;
@@ -1125,7 +1094,6 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
if (qhp->attr.mpa_attr.initiator)
build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
- c4iw_init_wr_wait(&qhp->ep->com.wr_wait);
ret = c4iw_ofld_send(&rhp->rdev, skb);
if (ret)
goto out;
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 765f0fc1da76..b33f0457a1ff 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -530,9 +530,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
for (j = 0; j < 6; j++) {
if (!pdev->resource[j].start)
continue;
- ipath_cdbg(VERBOSE, "BAR %d start %llx, end %llx, len %llx\n",
- j, (unsigned long long)pdev->resource[j].start,
- (unsigned long long)pdev->resource[j].end,
+ ipath_cdbg(VERBOSE, "BAR %d %pR, len %llx\n",
+ j, &pdev->resource[j],
(unsigned long long)pci_resource_len(pdev, j));
}
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 6078992da3f0..9292a15ad7c4 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -40,7 +40,6 @@
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h>
#include <asm/pgtable.h>
#include "ipath_kernel.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 8c8afc716b98..31ae1b108aea 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -277,18 +277,14 @@ static int remove_file(struct dentry *parent, char *name)
goto bail;
}
- spin_lock(&dcache_lock);
spin_lock(&tmp->d_lock);
if (!(d_unhashed(tmp) && tmp->d_inode)) {
- dget_locked(tmp);
+ dget_dlock(tmp);
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
- spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, tmp);
- } else {
+ } else
spin_unlock(&tmp->d_lock);
- spin_unlock(&dcache_lock);
- }
ret = 0;
bail:
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 5a219a2fdf16..e8df155bc3b0 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -397,10 +397,14 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
cq->resize_buf = NULL;
cq->resize_umem = NULL;
} else {
+ struct mlx4_ib_cq_buf tmp_buf;
+ int tmp_cqe = 0;
+
spin_lock_irq(&cq->lock);
if (cq->resize_buf) {
mlx4_ib_cq_resize_copy_cqes(cq);
- mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
+ tmp_buf = cq->buf;
+ tmp_cqe = cq->ibcq.cqe;
cq->buf = cq->resize_buf->buf;
cq->ibcq.cqe = cq->resize_buf->cqe;
@@ -408,6 +412,9 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
cq->resize_buf = NULL;
}
spin_unlock_irq(&cq->lock);
+
+ if (tmp_cqe)
+ mlx4_ib_free_cq_buf(dev, &tmp_buf, tmp_cqe);
}
goto out;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index c9a8dd63b9e2..57ffa50f509e 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -211,6 +211,8 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
if (agent) {
send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
IB_MGMT_MAD_DATA, GFP_ATOMIC);
+ if (IS_ERR(send_buf))
+ return;
/*
* We rely here on the fact that MLX QPs don't use the
* address handle after the send is posted (this is
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index bf3e20cd0298..4c85224aeaa7 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -219,7 +219,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
struct net_device *ndev;
enum ib_mtu tmp;
- props->active_width = IB_WIDTH_4X;
+ props->active_width = IB_WIDTH_1X;
props->active_speed = 4;
props->port_cap_flags = IB_PORT_CM_SUP;
props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port];
@@ -242,7 +242,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
tmp = iboe_get_mtu(ndev->mtu);
props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
- props->state = netif_running(ndev) && netif_oper_up(ndev) ?
+ props->state = (netif_running(ndev) && netif_carrier_ok(ndev)) ?
IB_PORT_ACTIVE : IB_PORT_DOWN;
props->phys_state = state_to_phys_state(props->state);
@@ -848,8 +848,8 @@ static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear)
goto out;
}
- read_lock(&dev_base_lock);
- for_each_netdev(&init_net, tmp) {
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, tmp) {
if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
vid = rdma_vlan_dev_vlan_id(tmp);
@@ -884,7 +884,7 @@ static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear)
}
}
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
for (i = 0; i < 128; ++i)
if (!hits[i]) {
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 9a7794ac34c1..2001f20a4361 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1816,6 +1816,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
+ if (be16_to_cpu(vlan) < 0x1000) {
+ ctrl->ins_vlan = 1 << 6;
+ ctrl->vlan_tag = vlan;
+ }
+
/*
* Make sure descriptor is fully written before
* setting ownership bit (because HW can start
@@ -1831,11 +1836,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
(ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh;
- if (be16_to_cpu(vlan) < 0x1000) {
- ctrl->ins_vlan = 1 << 6;
- ctrl->vlan_tag = vlan;
- }
-
stamp = ind + qp->sq_spare_wqes;
ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift);
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 5648659ff0b0..03a59534f59e 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -171,6 +171,8 @@ static void forward_trap(struct mthca_dev *dev,
if (agent) {
send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
IB_MGMT_MAD_DATA, GFP_ATOMIC);
+ if (IS_ERR(send_buf))
+ return;
/*
* We rely here on the fact that MLX QPs don't use the
* address handle after the send is posted (this is
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 3892e2c0e95a..5a4c36484722 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -908,8 +908,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
nesvnic->nic_index &&
mc_index < max_pft_entries_avaiable) {
nes_debug(NES_DBG_NIC_RX,
- "mc_index=%d skipping nic_index=%d,\
- used for=%d \n", mc_index,
+ "mc_index=%d skipping nic_index=%d, "
+ "used for=%d \n", mc_index,
nesvnic->nic_index,
nesadapter->pft_mcast_map[mc_index]);
mc_index++;
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 64c9e7d02d4a..73225eee3cc6 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -766,7 +766,7 @@ struct qib_devdata {
void (*f_sdma_hw_start_up)(struct qib_pportdata *);
void (*f_sdma_init_early)(struct qib_pportdata *);
void (*f_set_cntr_sample)(struct qib_pportdata *, u32, u32);
- void (*f_update_usrhead)(struct qib_ctxtdata *, u64, u32, u32);
+ void (*f_update_usrhead)(struct qib_ctxtdata *, u64, u32, u32, u32);
u32 (*f_hdrqempty)(struct qib_ctxtdata *);
u64 (*f_portcntr)(struct qib_pportdata *, u32);
u32 (*f_read_cntrs)(struct qib_devdata *, loff_t, char **,
diff --git a/drivers/infiniband/hw/qib/qib_cq.c b/drivers/infiniband/hw/qib/qib_cq.c
index a86cbf880f98..5246aa486bbe 100644
--- a/drivers/infiniband/hw/qib/qib_cq.c
+++ b/drivers/infiniband/hw/qib/qib_cq.c
@@ -100,7 +100,8 @@ void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited)
wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
- (cq->notify == IB_CQ_SOLICITED && solicited)) {
+ (cq->notify == IB_CQ_SOLICITED &&
+ (solicited || entry->status != IB_WC_SUCCESS))) {
cq->notify = IB_CQ_NONE;
cq->triggered++;
/*
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 9cd193603fb1..23e584f4c36c 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -71,6 +71,11 @@ MODULE_DESCRIPTION("QLogic IB driver");
*/
#define QIB_PIO_MAXIBHDR 128
+/*
+ * QIB_MAX_PKT_RCV is the max # if packets processed per receive interrupt.
+ */
+#define QIB_MAX_PKT_RECV 64
+
struct qlogic_ib_stats qib_stats;
const char *qib_get_unit_name(int unit)
@@ -284,14 +289,147 @@ static inline void *qib_get_egrbuf(const struct qib_ctxtdata *rcd, u32 etail)
* Returns 1 if error was a CRC, else 0.
* Needed for some chip's synthesized error counters.
*/
-static u32 qib_rcv_hdrerr(struct qib_pportdata *ppd, u32 ctxt,
- u32 eflags, u32 l, u32 etail, __le32 *rhf_addr,
- struct qib_message_header *hdr)
+static u32 qib_rcv_hdrerr(struct qib_ctxtdata *rcd, struct qib_pportdata *ppd,
+ u32 ctxt, u32 eflags, u32 l, u32 etail,
+ __le32 *rhf_addr, struct qib_message_header *rhdr)
{
u32 ret = 0;
if (eflags & (QLOGIC_IB_RHF_H_ICRCERR | QLOGIC_IB_RHF_H_VCRCERR))
ret = 1;
+ else if (eflags == QLOGIC_IB_RHF_H_TIDERR) {
+ /* For TIDERR and RC QPs premptively schedule a NAK */
+ struct qib_ib_header *hdr = (struct qib_ib_header *) rhdr;
+ struct qib_other_headers *ohdr = NULL;
+ struct qib_ibport *ibp = &ppd->ibport_data;
+ struct qib_qp *qp = NULL;
+ u32 tlen = qib_hdrget_length_in_bytes(rhf_addr);
+ u16 lid = be16_to_cpu(hdr->lrh[1]);
+ int lnh = be16_to_cpu(hdr->lrh[0]) & 3;
+ u32 qp_num;
+ u32 opcode;
+ u32 psn;
+ int diff;
+ unsigned long flags;
+
+ /* Sanity check packet */
+ if (tlen < 24)
+ goto drop;
+
+ if (lid < QIB_MULTICAST_LID_BASE) {
+ lid &= ~((1 << ppd->lmc) - 1);
+ if (unlikely(lid != ppd->lid))
+ goto drop;
+ }
+
+ /* Check for GRH */
+ if (lnh == QIB_LRH_BTH)
+ ohdr = &hdr->u.oth;
+ else if (lnh == QIB_LRH_GRH) {
+ u32 vtf;
+
+ ohdr = &hdr->u.l.oth;
+ if (hdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR)
+ goto drop;
+ vtf = be32_to_cpu(hdr->u.l.grh.version_tclass_flow);
+ if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION)
+ goto drop;
+ } else
+ goto drop;
+
+ /* Get opcode and PSN from packet */
+ opcode = be32_to_cpu(ohdr->bth[0]);
+ opcode >>= 24;
+ psn = be32_to_cpu(ohdr->bth[2]);
+
+ /* Get the destination QP number. */
+ qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
+ if (qp_num != QIB_MULTICAST_QPN) {
+ int ruc_res;
+ qp = qib_lookup_qpn(ibp, qp_num);
+ if (!qp)
+ goto drop;
+
+ /*
+ * Handle only RC QPs - for other QP types drop error
+ * packet.
+ */
+ spin_lock(&qp->r_lock);
+
+ /* Check for valid receive state. */
+ if (!(ib_qib_state_ops[qp->state] &
+ QIB_PROCESS_RECV_OK)) {
+ ibp->n_pkt_drops++;
+ goto unlock;
+ }
+
+ switch (qp->ibqp.qp_type) {
+ case IB_QPT_RC:
+ spin_lock_irqsave(&qp->s_lock, flags);
+ ruc_res =
+ qib_ruc_check_hdr(
+ ibp, hdr,
+ lnh == QIB_LRH_GRH,
+ qp,
+ be32_to_cpu(ohdr->bth[0]));
+ if (ruc_res) {
+ spin_unlock_irqrestore(&qp->s_lock,
+ flags);
+ goto unlock;
+ }
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ /* Only deal with RDMA Writes for now */
+ if (opcode <
+ IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) {
+ diff = qib_cmp24(psn, qp->r_psn);
+ if (!qp->r_nak_state && diff >= 0) {
+ ibp->n_rc_seqnak++;
+ qp->r_nak_state =
+ IB_NAK_PSN_ERROR;
+ /* Use the expected PSN. */
+ qp->r_ack_psn = qp->r_psn;
+ /*
+ * Wait to send the sequence
+ * NAK until all packets
+ * in the receive queue have
+ * been processed.
+ * Otherwise, we end up
+ * propagating congestion.
+ */
+ if (list_empty(&qp->rspwait)) {
+ qp->r_flags |=
+ QIB_R_RSP_NAK;
+ atomic_inc(
+ &qp->refcount);
+ list_add_tail(
+ &qp->rspwait,
+ &rcd->qp_wait_list);
+ }
+ } /* Out of sequence NAK */
+ } /* QP Request NAKs */
+ break;
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ case IB_QPT_UD:
+ case IB_QPT_UC:
+ default:
+ /* For now don't handle any other QP types */
+ break;
+ }
+
+unlock:
+ spin_unlock(&qp->r_lock);
+ /*
+ * Notify qib_destroy_qp() if it is waiting
+ * for us to finish.
+ */
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+ } /* Unicast QP */
+ } /* Valid packet with TIDErr */
+
+drop:
return ret;
}
@@ -335,7 +473,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
smp_rmb(); /* prevent speculative reads of dma'ed hdrq */
}
- for (last = 0, i = 1; !last && i <= 64; i += !last) {
+ for (last = 0, i = 1; !last; i += !last) {
hdr = dd->f_get_msgheader(dd, rhf_addr);
eflags = qib_hdrget_err_flags(rhf_addr);
etype = qib_hdrget_rcv_type(rhf_addr);
@@ -371,7 +509,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
* packets; only qibhdrerr should be set.
*/
if (unlikely(eflags))
- crcs += qib_rcv_hdrerr(ppd, rcd->ctxt, eflags, l,
+ crcs += qib_rcv_hdrerr(rcd, ppd, rcd->ctxt, eflags, l,
etail, rhf_addr, hdr);
else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
qib_ib_rcv(rcd, hdr, ebuf, tlen);
@@ -384,6 +522,9 @@ move_along:
l += rsize;
if (l >= maxcnt)
l = 0;
+ if (i == QIB_MAX_PKT_RECV)
+ last = 1;
+
rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset;
if (dd->flags & QIB_NODMA_RTAIL) {
u32 seq = qib_hdrget_seq(rhf_addr);
@@ -402,7 +543,7 @@ move_along:
*/
lval = l;
if (!last && !(i & 0xf)) {
- dd->f_update_usrhead(rcd, lval, updegr, etail);
+ dd->f_update_usrhead(rcd, lval, updegr, etail, i);
updegr = 0;
}
}
@@ -444,7 +585,7 @@ bail:
* if no packets were processed.
*/
lval = (u64)rcd->head | dd->rhdrhead_intr_off;
- dd->f_update_usrhead(rcd, lval, updegr, etail);
+ dd->f_update_usrhead(rcd, lval, updegr, etail, i);
return crcs;
}
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index 79d9971aff1f..75bfad16c114 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1379,17 +1379,17 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
/* find device (with ACTIVE ports) with fewest ctxts in use */
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
- unsigned cused = 0, cfree = 0;
+ unsigned cused = 0, cfree = 0, pusable = 0;
if (!dd)
continue;
if (port && port <= dd->num_pports &&
usable(dd->pport + port - 1))
- dusable = 1;
+ pusable = 1;
else
for (i = 0; i < dd->num_pports; i++)
if (usable(dd->pport + i))
- dusable++;
- if (!dusable)
+ pusable++;
+ if (!pusable)
continue;
for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts;
ctxt++)
@@ -1397,7 +1397,7 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
cused++;
else
cfree++;
- if (cfree && cused < inuse) {
+ if (pusable && cfree && cused < inuse) {
udd = dd;
inuse = cused;
}
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index f99bddc01716..df7fa251dcdc 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -453,17 +453,14 @@ static int remove_file(struct dentry *parent, char *name)
goto bail;
}
- spin_lock(&dcache_lock);
spin_lock(&tmp->d_lock);
if (!(d_unhashed(tmp) && tmp->d_inode)) {
- dget_locked(tmp);
+ dget_dlock(tmp);
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
- spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, tmp);
} else {
spin_unlock(&tmp->d_lock);
- spin_unlock(&dcache_lock);
}
ret = 0;
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index a5e29dbb9537..774dea897e9c 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -2074,7 +2074,7 @@ static void qib_6120_config_ctxts(struct qib_devdata *dd)
}
static void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd,
- u32 updegr, u32 egrhd)
+ u32 updegr, u32 egrhd, u32 npkts)
{
qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
if (updegr)
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 6fd8d74e7392..127a0d5069f0 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -2297,7 +2297,7 @@ static void qib_7220_config_ctxts(struct qib_devdata *dd)
nchipctxts = qib_read_kreg32(dd, kr_portcnt);
dd->cspec->numctxts = nchipctxts;
if (qib_n_krcv_queues > 1) {
- dd->qpn_mask = 0x3f;
+ dd->qpn_mask = 0x3e;
dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
if (dd->first_user_ctxt > nchipctxts)
dd->first_user_ctxt = nchipctxts;
@@ -2703,7 +2703,7 @@ static int qib_7220_set_loopback(struct qib_pportdata *ppd, const char *what)
}
static void qib_update_7220_usrhead(struct qib_ctxtdata *rcd, u64 hd,
- u32 updegr, u32 egrhd)
+ u32 updegr, u32 egrhd, u32 npkts)
{
qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
if (updegr)
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 584d443b5335..abd409d592ef 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -71,6 +71,9 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *);
static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32);
static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
+static void serdes_7322_los_enable(struct qib_pportdata *, int);
+static int serdes_7322_init_old(struct qib_pportdata *);
+static int serdes_7322_init_new(struct qib_pportdata *);
#define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
@@ -111,6 +114,21 @@ static ushort qib_singleport;
module_param_named(singleport, qib_singleport, ushort, S_IRUGO);
MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space");
+/*
+ * Receive header queue sizes
+ */
+static unsigned qib_rcvhdrcnt;
+module_param_named(rcvhdrcnt, qib_rcvhdrcnt, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrcnt, "receive header count");
+
+static unsigned qib_rcvhdrsize;
+module_param_named(rcvhdrsize, qib_rcvhdrsize, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrsize, "receive header size in 32-bit words");
+
+static unsigned qib_rcvhdrentsize;
+module_param_named(rcvhdrentsize, qib_rcvhdrentsize, uint, S_IRUGO);
+MODULE_PARM_DESC(rcvhdrentsize, "receive header entry size in 32-bit words");
+
#define MAX_ATTEN_LEN 64 /* plenty for any real system */
/* for read back, default index is ~5m copper cable */
static char txselect_list[MAX_ATTEN_LEN] = "10";
@@ -314,7 +332,7 @@ MODULE_PARM_DESC(txselect, \
#define krp_serdesctrl KREG_IBPORT_IDX(IBSerdesCtrl)
/*
- * Per-context kernel registers. Acess only with qib_read_kreg_ctxt()
+ * Per-context kernel registers. Access only with qib_read_kreg_ctxt()
* or qib_write_kreg_ctxt()
*/
#define krc_rcvhdraddr KREG_IDX(RcvHdrAddr0)
@@ -544,6 +562,7 @@ static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
#define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
#define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */
+#define TXDDS_MFG_SZ 2 /* number of mfg tx settings entries */
#define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
#define H1_FORCE_VAL 8
@@ -604,6 +623,7 @@ struct qib_chippport_specific {
u8 ibmalfusesnap;
struct qib_qsfp_data qsfp_data;
char epmsgbuf[192]; /* for port error interrupt msg buffer */
+ u8 bounced;
};
static struct {
@@ -1677,6 +1697,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
(ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) {
force_h1(ppd);
ppd->cpspec->qdr_reforce = 1;
+ if (!ppd->dd->cspec->r1)
+ serdes_7322_los_enable(ppd, 0);
} else if (ppd->cpspec->qdr_reforce &&
(ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) &&
(ibclt == IB_7322_LT_STATE_CFGENH ||
@@ -1692,18 +1714,37 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
ibclt <= IB_7322_LT_STATE_SLEEPQUIET)))
adj_tx_serdes(ppd);
- if (!ppd->cpspec->qdr_dfe_on && ibclt != IB_7322_LT_STATE_LINKUP &&
- ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
- ppd->cpspec->qdr_dfe_on = 1;
- ppd->cpspec->qdr_dfe_time = 0;
- /* On link down, reenable QDR adaptation */
- qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
- ppd->dd->cspec->r1 ?
- QDR_STATIC_ADAPT_DOWN_R1 :
- QDR_STATIC_ADAPT_DOWN);
+ if (ibclt != IB_7322_LT_STATE_LINKUP) {
+ u8 ltstate = qib_7322_phys_portstate(ibcst);
+ u8 pibclt = (u8)SYM_FIELD(ppd->lastibcstat, IBCStatusA_0,
+ LinkTrainingState);
+ if (!ppd->dd->cspec->r1 &&
+ pibclt == IB_7322_LT_STATE_LINKUP &&
+ ltstate != IB_PHYSPORTSTATE_LINK_ERR_RECOVER &&
+ ltstate != IB_PHYSPORTSTATE_RECOVERY_RETRAIN &&
+ ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
+ ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
+ /* If the link went down (but no into recovery,
+ * turn LOS back on */
+ serdes_7322_los_enable(ppd, 1);
+ if (!ppd->cpspec->qdr_dfe_on &&
+ ibclt <= IB_7322_LT_STATE_SLEEPQUIET) {
+ ppd->cpspec->qdr_dfe_on = 1;
+ ppd->cpspec->qdr_dfe_time = 0;
+ /* On link down, reenable QDR adaptation */
+ qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+ ppd->dd->cspec->r1 ?
+ QDR_STATIC_ADAPT_DOWN_R1 :
+ QDR_STATIC_ADAPT_DOWN);
+ printk(KERN_INFO QIB_DRV_NAME
+ " IB%u:%u re-enabled QDR adaptation "
+ "ibclt %x\n", ppd->dd->unit, ppd->port, ibclt);
+ }
}
}
+static int qib_7322_set_ib_cfg(struct qib_pportdata *, int, u32);
+
/*
* This is per-pport error handling.
* will likely get it's own MSIx interrupt (one for each port,
@@ -1840,7 +1881,23 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
IB_PHYSPORTSTATE_DISABLED)
qib_set_ib_7322_lstate(ppd, 0,
QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
- else
+ else {
+ u32 lstate;
+ /*
+ * We need the current logical link state before
+ * lflags are set in handle_e_ibstatuschanged.
+ */
+ lstate = qib_7322_iblink_state(ibcs);
+
+ if (IS_QMH(dd) && !ppd->cpspec->bounced &&
+ ltstate == IB_PHYSPORTSTATE_LINKUP &&
+ (lstate >= IB_PORT_INIT &&
+ lstate <= IB_PORT_ACTIVE)) {
+ ppd->cpspec->bounced = 1;
+ qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
+ IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL);
+ }
+
/*
* Since going into a recovery state causes the link
* state to go down and since recovery is transitory,
@@ -1854,6 +1911,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
qib_handle_e_ibstatuschanged(ppd, ibcs);
+ }
}
if (*msg && iserr)
qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
@@ -2785,7 +2843,6 @@ static irqreturn_t qib_7322intr(int irq, void *data)
ctxtrbits &= ~rmask;
if (dd->rcd[i]) {
qib_kreceive(dd->rcd[i], NULL, &npkts);
- adjust_rcv_timeout(dd->rcd[i], npkts);
}
}
rmask <<= 1;
@@ -2835,7 +2892,6 @@ static irqreturn_t qib_7322pintr(int irq, void *data)
(1ULL << QIB_I_RCVURG_LSB)) << rcd->ctxt);
qib_kreceive(rcd, NULL, &npkts);
- adjust_rcv_timeout(rcd, npkts);
return IRQ_HANDLED;
}
@@ -3157,6 +3213,10 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd)
case BOARD_QME7342:
n = "InfiniPath_QME7342";
break;
+ case 8:
+ n = "InfiniPath_QME7362";
+ dd->flags |= QIB_HAS_QSFP;
+ break;
case 15:
n = "InfiniPath_QLE7342_TEST";
dd->flags |= QIB_HAS_QSFP;
@@ -3475,11 +3535,6 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
nchipctxts = qib_read_kreg32(dd, kr_contextcnt);
dd->cspec->numctxts = nchipctxts;
if (qib_n_krcv_queues > 1 && dd->num_pports) {
- /*
- * Set the mask for which bits from the QPN are used
- * to select a context number.
- */
- dd->qpn_mask = 0x3f;
dd->first_user_ctxt = NUM_IB_PORTS +
(qib_n_krcv_queues - 1) * dd->num_pports;
if (dd->first_user_ctxt > nchipctxts)
@@ -3530,8 +3585,11 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
/* kr_rcvegrcnt changes based on the number of contexts enabled */
dd->cspec->rcvegrcnt = qib_read_kreg32(dd, kr_rcvegrcnt);
- dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt,
- dd->num_pports > 1 ? 1024U : 2048U);
+ if (qib_rcvhdrcnt)
+ dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, qib_rcvhdrcnt);
+ else
+ dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt,
+ dd->num_pports > 1 ? 1024U : 2048U);
}
static int qib_7322_get_ib_cfg(struct qib_pportdata *ppd, int which)
@@ -4002,8 +4060,14 @@ static int qib_7322_set_ib_table(struct qib_pportdata *ppd, int which, void *t)
}
static void qib_update_7322_usrhead(struct qib_ctxtdata *rcd, u64 hd,
- u32 updegr, u32 egrhd)
+ u32 updegr, u32 egrhd, u32 npkts)
{
+ /*
+ * Need to write timeout register before updating rcvhdrhead to ensure
+ * that the timer is enabled on reception of a packet.
+ */
+ if (hd >> IBA7322_HDRHEAD_PKTINT_SHIFT)
+ adjust_rcv_timeout(rcd, npkts);
qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt);
if (updegr)
@@ -5522,7 +5586,7 @@ static void qsfp_7322_event(struct work_struct *work)
u64 now = get_jiffies_64();
if (time_after64(now, pwrup))
break;
- msleep(1);
+ msleep(20);
}
ret = qib_refresh_qsfp_cache(ppd, &qd->cache);
/*
@@ -5579,6 +5643,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
u32 pidx, unit, port, deflt, h1;
unsigned long val;
int any = 0, seth1;
+ int txdds_size;
str = txselect_list;
@@ -5587,6 +5652,10 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
for (pidx = 0; pidx < dd->num_pports; ++pidx)
dd->pport[pidx].cpspec->no_eep = deflt;
+ txdds_size = TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ;
+ if (IS_QME(dd) || IS_QMH(dd))
+ txdds_size += TXDDS_MFG_SZ;
+
while (*nxt && nxt[1]) {
str = ++nxt;
unit = simple_strtoul(str, &nxt, 0);
@@ -5609,7 +5678,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
;
continue;
}
- if (val >= TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)
+ if (val >= txdds_size)
continue;
seth1 = 0;
h1 = 0; /* gcc thinks it might be used uninitted */
@@ -5661,10 +5730,11 @@ static int setup_txselect(const char *str, struct kernel_param *kp)
return -ENOSPC;
}
val = simple_strtoul(str, &n, 0);
- if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) {
+ if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ +
+ TXDDS_MFG_SZ)) {
printk(KERN_INFO QIB_DRV_NAME
"txselect_values must start with a number < %d\n",
- TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
+ TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ + TXDDS_MFG_SZ);
return -EINVAL;
}
strcpy(txselect_list, str);
@@ -5810,7 +5880,8 @@ static void write_7322_initregs(struct qib_devdata *dd)
unsigned n, regno;
unsigned long flags;
- if (!dd->qpn_mask || !dd->pport[pidx].link_speed_supported)
+ if (dd->n_krcv_queues < 2 ||
+ !dd->pport[pidx].link_speed_supported)
continue;
ppd = &dd->pport[pidx];
@@ -6097,8 +6168,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
ppd++;
}
- dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
- dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
+ dd->rcvhdrentsize = qib_rcvhdrentsize ?
+ qib_rcvhdrentsize : QIB_RCVHDR_ENTSIZE;
+ dd->rcvhdrsize = qib_rcvhdrsize ?
+ qib_rcvhdrsize : QIB_DFLT_RCVHDRSIZE;
dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
/* we always allocate at least 2048 bytes for eager buffers */
@@ -6495,7 +6568,7 @@ static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start,
/* make sure we see an updated copy next time around */
sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
sleeps++;
- msleep(1);
+ msleep(20);
}
switch (which) {
@@ -6993,6 +7066,12 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
{ 0, 1, 0, 12 }, /* QMH7342 backplane settings */
};
+static const struct txdds_ent txdds_extra_mfg[TXDDS_MFG_SZ] = {
+ /* amp, pre, main, post */
+ { 0, 0, 0, 0 }, /* QME7342 mfg settings */
+ { 0, 0, 0, 6 }, /* QME7342 P2 mfg settings */
+};
+
static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds,
unsigned atten)
{
@@ -7066,6 +7145,16 @@ static void find_best_ent(struct qib_pportdata *ppd,
*sdr_dds = &txdds_extra_sdr[idx];
*ddr_dds = &txdds_extra_ddr[idx];
*qdr_dds = &txdds_extra_qdr[idx];
+ } else if ((IS_QME(ppd->dd) || IS_QMH(ppd->dd)) &&
+ ppd->cpspec->no_eep < (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ +
+ TXDDS_MFG_SZ)) {
+ idx = ppd->cpspec->no_eep - (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ);
+ printk(KERN_INFO QIB_DRV_NAME
+ " IB%u:%u use idx %u into txdds_mfg\n",
+ ppd->dd->unit, ppd->port, idx);
+ *sdr_dds = &txdds_extra_mfg[idx];
+ *ddr_dds = &txdds_extra_mfg[idx];
+ *qdr_dds = &txdds_extra_mfg[idx];
} else {
/* this shouldn't happen, it's range checked */
*sdr_dds = txdds_sdr + qib_long_atten;
@@ -7210,9 +7299,30 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data,
}
}
+static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable)
+{
+ u64 data = qib_read_kreg_port(ppd, krp_serdesctrl);
+ printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS %s\n",
+ ppd->dd->unit, ppd->port, (enable ? "on" : "off"));
+ if (enable)
+ data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
+ else
+ data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
+ qib_write_kreg_port(ppd, krp_serdesctrl, data);
+}
+
static int serdes_7322_init(struct qib_pportdata *ppd)
{
- u64 data;
+ int ret = 0;
+ if (ppd->dd->cspec->r1)
+ ret = serdes_7322_init_old(ppd);
+ else
+ ret = serdes_7322_init_new(ppd);
+ return ret;
+}
+
+static int serdes_7322_init_old(struct qib_pportdata *ppd)
+{
u32 le_val;
/*
@@ -7270,11 +7380,7 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
- data = qib_read_kreg_port(ppd, krp_serdesctrl);
- /* Turn off IB latency mode */
- data &= ~SYM_MASK(IBSerdesCtrl_0, IB_LAT_MODE);
- qib_write_kreg_port(ppd, krp_serdesctrl, data |
- SYM_MASK(IBSerdesCtrl_0, RXLOSEN));
+ serdes_7322_los_enable(ppd, 1);
/* rxbistena; set 0 to avoid effects of it switch later */
ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15);
@@ -7314,6 +7420,205 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
return 0;
}
+static int serdes_7322_init_new(struct qib_pportdata *ppd)
+{
+ u64 tstart;
+ u32 le_val, rxcaldone;
+ int chan, chan_done = (1 << SERDES_CHANS) - 1;
+
+ /*
+ * Initialize the Tx DDS tables. Also done every QSFP event,
+ * for adapters with QSFP
+ */
+ init_txdds_table(ppd, 0);
+
+ /* Clear cmode-override, may be set from older driver */
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14);
+
+ /* ensure no tx overrides from earlier driver loads */
+ qib_write_kreg_port(ppd, krp_tx_deemph_override,
+ SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+ reset_tx_deemphasis_override));
+
+ /* START OF LSI SUGGESTED SERDES BRINGUP */
+ /* Reset - Calibration Setup */
+ /* Stop DFE adaptaion */
+ ibsd_wr_allchans(ppd, 1, 0, BMASK(9, 1));
+ /* Disable LE1 */
+ ibsd_wr_allchans(ppd, 13, 0, BMASK(5, 5));
+ /* Disable autoadapt for LE1 */
+ ibsd_wr_allchans(ppd, 1, 0, BMASK(15, 15));
+ /* Disable LE2 */
+ ibsd_wr_allchans(ppd, 13, 0, BMASK(6, 6));
+ /* Disable VGA */
+ ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
+ /* Disable AFE Offset Cancel */
+ ibsd_wr_allchans(ppd, 12, 0, BMASK(12, 12));
+ /* Disable Timing Loop */
+ ibsd_wr_allchans(ppd, 2, 0, BMASK(3, 3));
+ /* Disable Frequency Loop */
+ ibsd_wr_allchans(ppd, 2, 0, BMASK(4, 4));
+ /* Disable Baseline Wander Correction */
+ ibsd_wr_allchans(ppd, 13, 0, BMASK(13, 13));
+ /* Disable RX Calibration */
+ ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
+ /* Disable RX Offset Calibration */
+ ibsd_wr_allchans(ppd, 12, 0, BMASK(4, 4));
+ /* Select BB CDR */
+ ibsd_wr_allchans(ppd, 2, (1 << 15), BMASK(15, 15));
+ /* CDR Step Size */
+ ibsd_wr_allchans(ppd, 5, 0, BMASK(9, 8));
+ /* Enable phase Calibration */
+ ibsd_wr_allchans(ppd, 12, (1 << 5), BMASK(5, 5));
+ /* DFE Bandwidth [2:14-12] */
+ ibsd_wr_allchans(ppd, 2, (4 << 12), BMASK(14, 12));
+ /* DFE Config (4 taps only) */
+ ibsd_wr_allchans(ppd, 16, 0, BMASK(1, 0));
+ /* Gain Loop Bandwidth */
+ if (!ppd->dd->cspec->r1) {
+ ibsd_wr_allchans(ppd, 12, 1 << 12, BMASK(12, 12));
+ ibsd_wr_allchans(ppd, 12, 2 << 8, BMASK(11, 8));
+ } else {
+ ibsd_wr_allchans(ppd, 19, (3 << 11), BMASK(13, 11));
+ }
+ /* Baseline Wander Correction Gain [13:4-0] (leave as default) */
+ /* Baseline Wander Correction Gain [3:7-5] (leave as default) */
+ /* Data Rate Select [5:7-6] (leave as default) */
+ /* RX Parralel Word Width [3:10-8] (leave as default) */
+
+ /* RX REST */
+ /* Single- or Multi-channel reset */
+ /* RX Analog reset */
+ /* RX Digital reset */
+ ibsd_wr_allchans(ppd, 0, 0, BMASK(15, 13));
+ msleep(20);
+ /* RX Analog reset */
+ ibsd_wr_allchans(ppd, 0, (1 << 14), BMASK(14, 14));
+ msleep(20);
+ /* RX Digital reset */
+ ibsd_wr_allchans(ppd, 0, (1 << 13), BMASK(13, 13));
+ msleep(20);
+
+ /* setup LoS params; these are subsystem, so chan == 5 */
+ /* LoS filter threshold_count on, ch 0-3, set to 8 */
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 5, 8 << 11, BMASK(14, 11));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 8 << 4, BMASK(7, 4));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 8, 8 << 11, BMASK(14, 11));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 8 << 4, BMASK(7, 4));
+
+ /* LoS filter threshold_count off, ch 0-3, set to 4 */
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 6, 4 << 0, BMASK(3, 0));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 4 << 8, BMASK(11, 8));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 4 << 0, BMASK(3, 0));
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 4 << 8, BMASK(11, 8));
+
+ /* LoS filter select enabled */
+ ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 1 << 15, 1 << 15);
+
+ /* LoS target data: SDR=4, DDR=2, QDR=1 */
+ ibsd_wr_allchans(ppd, 14, (1 << 3), BMASK(5, 3)); /* QDR */
+ ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */
+ ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
+
+ /* Turn on LOS on initial SERDES init */
+ serdes_7322_los_enable(ppd, 1);
+ /* FLoop LOS gate: PPM filter enabled */
+ ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10);
+
+ /* RX LATCH CALIBRATION */
+ /* Enable Eyefinder Phase Calibration latch */
+ ibsd_wr_allchans(ppd, 15, 1, BMASK(0, 0));
+ /* Enable RX Offset Calibration latch */
+ ibsd_wr_allchans(ppd, 12, (1 << 4), BMASK(4, 4));
+ msleep(20);
+ /* Start Calibration */
+ ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10));
+ tstart = get_jiffies_64();
+ while (chan_done &&
+ !time_after64(tstart, tstart + msecs_to_jiffies(500))) {
+ msleep(20);
+ for (chan = 0; chan < SERDES_CHANS; ++chan) {
+ rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
+ (chan + (chan >> 1)),
+ 25, 0, 0);
+ if ((~rxcaldone & (u32)BMASK(9, 9)) == 0 &&
+ (~chan_done & (1 << chan)) == 0)
+ chan_done &= ~(1 << chan);
+ }
+ }
+ if (chan_done) {
+ printk(KERN_INFO QIB_DRV_NAME
+ " Serdes %d calibration not done after .5 sec: 0x%x\n",
+ IBSD(ppd->hw_pidx), chan_done);
+ } else {
+ for (chan = 0; chan < SERDES_CHANS; ++chan) {
+ rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
+ (chan + (chan >> 1)),
+ 25, 0, 0);
+ if ((~rxcaldone & (u32)BMASK(10, 10)) == 0)
+ printk(KERN_INFO QIB_DRV_NAME
+ " Serdes %d chan %d calibration "
+ "failed\n", IBSD(ppd->hw_pidx), chan);
+ }
+ }
+
+ /* Turn off Calibration */
+ ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10));
+ msleep(20);
+
+ /* BRING RX UP */
+ /* Set LE2 value (May be overridden in qsfp_7322_event) */
+ le_val = IS_QME(ppd->dd) ? LE2_QME : LE2_DEFAULT;
+ ibsd_wr_allchans(ppd, 13, (le_val << 7), BMASK(9, 7));
+ /* Set LE2 Loop bandwidth */
+ ibsd_wr_allchans(ppd, 3, (7 << 5), BMASK(7, 5));
+ /* Enable LE2 */
+ ibsd_wr_allchans(ppd, 13, (1 << 6), BMASK(6, 6));
+ msleep(20);
+ /* Enable H0 only */
+ ibsd_wr_allchans(ppd, 1, 1, BMASK(9, 1));
+ /* gain hi stop 32 (22) (6:1) lo stop 7 (10:7) target 22 (13) (15:11) */
+ le_val = (ppd->dd->cspec->r1 || IS_QME(ppd->dd)) ? 0xb6c0 : 0x6bac;
+ ibsd_wr_allchans(ppd, 21, le_val, 0xfffe);
+ /* Enable VGA */
+ ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0));
+ msleep(20);
+ /* Set Frequency Loop Bandwidth */
+ ibsd_wr_allchans(ppd, 2, (7 << 5), BMASK(8, 5));
+ /* Enable Frequency Loop */
+ ibsd_wr_allchans(ppd, 2, (1 << 4), BMASK(4, 4));
+ /* Set Timing Loop Bandwidth */
+ ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9));
+ /* Enable Timing Loop */
+ ibsd_wr_allchans(ppd, 2, (1 << 3), BMASK(3, 3));
+ msleep(50);
+ /* Enable DFE
+ * Set receive adaptation mode. SDR and DDR adaptation are
+ * always on, and QDR is initially enabled; later disabled.
+ */
+ qib_write_kreg_port(ppd, krp_static_adapt_dis(0), 0ULL);
+ qib_write_kreg_port(ppd, krp_static_adapt_dis(1), 0ULL);
+ qib_write_kreg_port(ppd, krp_static_adapt_dis(2),
+ ppd->dd->cspec->r1 ?
+ QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN);
+ ppd->cpspec->qdr_dfe_on = 1;
+ /* Disable LE1 */
+ ibsd_wr_allchans(ppd, 13, (0 << 5), (1 << 5));
+ /* Disable auto adapt for LE1 */
+ ibsd_wr_allchans(ppd, 1, (0 << 15), BMASK(15, 15));
+ msleep(20);
+ /* Enable AFE Offset Cancel */
+ ibsd_wr_allchans(ppd, 12, (1 << 12), BMASK(12, 12));
+ /* Enable Baseline Wander Correction */
+ ibsd_wr_allchans(ppd, 12, (1 << 13), BMASK(13, 13));
+ /* Termination: rxtermctrl_r2d addr 11 bits [12:11] = 1 */
+ ibsd_wr_allchans(ppd, 11, (1 << 11), BMASK(12, 11));
+ /* VGA output common mode */
+ ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2));
+
+ return 0;
+}
+
/* start adjust QMH serdes parameters */
static void set_man_code(struct qib_pportdata *ppd, int chan, int code)
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index f3b503936043..7896afbb9ce8 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -92,9 +92,11 @@ unsigned long *qib_cpulist;
/* set number of contexts we'll actually use */
void qib_set_ctxtcnt(struct qib_devdata *dd)
{
- if (!qib_cfgctxts)
+ if (!qib_cfgctxts) {
dd->cfgctxts = dd->first_user_ctxt + num_online_cpus();
- else if (qib_cfgctxts < dd->num_pports)
+ if (dd->cfgctxts > dd->ctxtcnt)
+ dd->cfgctxts = dd->ctxtcnt;
+ } else if (qib_cfgctxts < dd->num_pports)
dd->cfgctxts = dd->ctxtcnt;
else if (qib_cfgctxts <= dd->ctxtcnt)
dd->cfgctxts = qib_cfgctxts;
diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c
index 54a40828a106..a693c56ec8a6 100644
--- a/drivers/infiniband/hw/qib/qib_intr.c
+++ b/drivers/infiniband/hw/qib/qib_intr.c
@@ -131,7 +131,8 @@ void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs)
/* start a 75msec timer to clear symbol errors */
mod_timer(&ppd->symerr_clear_timer,
msecs_to_jiffies(75));
- } else if (ltstate == IB_PHYSPORTSTATE_LINKUP) {
+ } else if (ltstate == IB_PHYSPORTSTATE_LINKUP &&
+ !(ppd->lflags & QIBL_LINKACTIVE)) {
/* active, but not active defered */
qib_hol_up(ppd); /* useful only for 6120 now */
*ppd->statusp |=
diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c
index 4b80eb153d57..8fd19a47df0c 100644
--- a/drivers/infiniband/hw/qib/qib_keys.c
+++ b/drivers/infiniband/hw/qib/qib_keys.c
@@ -136,7 +136,6 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
struct qib_mregion *mr;
unsigned n, m;
size_t off;
- int ret = 0;
unsigned long flags;
/*
@@ -152,6 +151,8 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
if (!dev->dma_mr)
goto bail;
atomic_inc(&dev->dma_mr->refcount);
+ spin_unlock_irqrestore(&rkt->lock, flags);
+
isge->mr = dev->dma_mr;
isge->vaddr = (void *) sge->addr;
isge->length = sge->length;
@@ -170,19 +171,34 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
off + sge->length > mr->length ||
(mr->access_flags & acc) != acc))
goto bail;
+ atomic_inc(&mr->refcount);
+ spin_unlock_irqrestore(&rkt->lock, flags);
off += mr->offset;
- m = 0;
- n = 0;
- while (off >= mr->map[m]->segs[n].length) {
- off -= mr->map[m]->segs[n].length;
- n++;
- if (n >= QIB_SEGSZ) {
- m++;
- n = 0;
+ if (mr->page_shift) {
+ /*
+ page sizes are uniform power of 2 so no loop is necessary
+ entries_spanned_by_off is the number of times the loop below
+ would have executed.
+ */
+ size_t entries_spanned_by_off;
+
+ entries_spanned_by_off = off >> mr->page_shift;
+ off -= (entries_spanned_by_off << mr->page_shift);
+ m = entries_spanned_by_off/QIB_SEGSZ;
+ n = entries_spanned_by_off%QIB_SEGSZ;
+ } else {
+ m = 0;
+ n = 0;
+ while (off >= mr->map[m]->segs[n].length) {
+ off -= mr->map[m]->segs[n].length;
+ n++;
+ if (n >= QIB_SEGSZ) {
+ m++;
+ n = 0;
+ }
}
}
- atomic_inc(&mr->refcount);
isge->mr = mr;
isge->vaddr = mr->map[m]->segs[n].vaddr + off;
isge->length = mr->map[m]->segs[n].length - off;
@@ -190,10 +206,10 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd,
isge->m = m;
isge->n = n;
ok:
- ret = 1;
+ return 1;
bail:
spin_unlock_irqrestore(&rkt->lock, flags);
- return ret;
+ return 0;
}
/**
@@ -214,7 +230,6 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
struct qib_mregion *mr;
unsigned n, m;
size_t off;
- int ret = 0;
unsigned long flags;
/*
@@ -231,6 +246,8 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
if (!dev->dma_mr)
goto bail;
atomic_inc(&dev->dma_mr->refcount);
+ spin_unlock_irqrestore(&rkt->lock, flags);
+
sge->mr = dev->dma_mr;
sge->vaddr = (void *) vaddr;
sge->length = len;
@@ -248,19 +265,34 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
if (unlikely(vaddr < mr->iova || off + len > mr->length ||
(mr->access_flags & acc) == 0))
goto bail;
+ atomic_inc(&mr->refcount);
+ spin_unlock_irqrestore(&rkt->lock, flags);
off += mr->offset;
- m = 0;
- n = 0;
- while (off >= mr->map[m]->segs[n].length) {
- off -= mr->map[m]->segs[n].length;
- n++;
- if (n >= QIB_SEGSZ) {
- m++;
- n = 0;
+ if (mr->page_shift) {
+ /*
+ page sizes are uniform power of 2 so no loop is necessary
+ entries_spanned_by_off is the number of times the loop below
+ would have executed.
+ */
+ size_t entries_spanned_by_off;
+
+ entries_spanned_by_off = off >> mr->page_shift;
+ off -= (entries_spanned_by_off << mr->page_shift);
+ m = entries_spanned_by_off/QIB_SEGSZ;
+ n = entries_spanned_by_off%QIB_SEGSZ;
+ } else {
+ m = 0;
+ n = 0;
+ while (off >= mr->map[m]->segs[n].length) {
+ off -= mr->map[m]->segs[n].length;
+ n++;
+ if (n >= QIB_SEGSZ) {
+ m++;
+ n = 0;
+ }
}
}
- atomic_inc(&mr->refcount);
sge->mr = mr;
sge->vaddr = mr->map[m]->segs[n].vaddr + off;
sge->length = mr->map[m]->segs[n].length - off;
@@ -268,10 +300,10 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge,
sge->m = m;
sge->n = n;
ok:
- ret = 1;
+ return 1;
bail:
spin_unlock_irqrestore(&rkt->lock, flags);
- return ret;
+ return 0;
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index 94b0d1f3a8f0..5ad224e4a38b 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -668,8 +668,8 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
lid = be16_to_cpu(pip->lid);
/* Must be a valid unicast LID address. */
if (lid == 0 || lid >= QIB_MULTICAST_LID_BASE)
- goto err;
- if (ppd->lid != lid || ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) {
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else if (ppd->lid != lid || ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) {
if (ppd->lid != lid)
qib_set_uevent_bits(ppd, _QIB_EVENT_LID_CHANGE_BIT);
if (ppd->lmc != (pip->mkeyprot_resv_lmc & 7))
@@ -683,8 +683,8 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
msl = pip->neighbormtu_mastersmsl & 0xF;
/* Must be a valid unicast LID address. */
if (smlid == 0 || smlid >= QIB_MULTICAST_LID_BASE)
- goto err;
- if (smlid != ibp->sm_lid || msl != ibp->sm_sl) {
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else if (smlid != ibp->sm_lid || msl != ibp->sm_sl) {
spin_lock_irqsave(&ibp->lock, flags);
if (ibp->sm_ah) {
if (smlid != ibp->sm_lid)
@@ -707,8 +707,9 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
if (lwe == 0xFF)
lwe = ppd->link_width_supported;
else if (lwe >= 16 || (lwe & ~ppd->link_width_supported))
- goto err;
- set_link_width_enabled(ppd, lwe);
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else if (lwe != ppd->link_width_enabled)
+ set_link_width_enabled(ppd, lwe);
}
lse = pip->linkspeedactive_enabled & 0xF;
@@ -721,8 +722,9 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
if (lse == 15)
lse = ppd->link_speed_supported;
else if (lse >= 8 || (lse & ~ppd->link_speed_supported))
- goto err;
- set_link_speed_enabled(ppd, lse);
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else if (lse != ppd->link_speed_enabled)
+ set_link_speed_enabled(ppd, lse);
}
/* Set link down default state. */
@@ -738,7 +740,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
IB_LINKINITCMD_POLL);
break;
default:
- goto err;
+ smp->status |= IB_SMP_INVALID_FIELD;
}
ibp->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
@@ -748,15 +750,17 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
mtu = ib_mtu_enum_to_int((pip->neighbormtu_mastersmsl >> 4) & 0xF);
if (mtu == -1)
- goto err;
- qib_set_mtu(ppd, mtu);
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else
+ qib_set_mtu(ppd, mtu);
/* Set operational VLs */
vls = (pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF;
if (vls) {
if (vls > ppd->vls_supported)
- goto err;
- (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OP_VLS, vls);
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else
+ (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OP_VLS, vls);
}
if (pip->mkey_violations == 0)
@@ -770,10 +774,10 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
ore = pip->localphyerrors_overrunerrors;
if (set_phyerrthreshold(ppd, (ore >> 4) & 0xF))
- goto err;
+ smp->status |= IB_SMP_INVALID_FIELD;
if (set_overrunthreshold(ppd, (ore & 0xF)))
- goto err;
+ smp->status |= IB_SMP_INVALID_FIELD;
ibp->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
@@ -792,7 +796,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
state = pip->linkspeed_portstate & 0xF;
lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
- goto err;
+ smp->status |= IB_SMP_INVALID_FIELD;
/*
* Only state changes of DOWN, ARM, and ACTIVE are valid
@@ -812,8 +816,10 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
lstate = QIB_IB_LINKDOWN;
else if (lstate == 3)
lstate = QIB_IB_LINKDOWN_DISABLE;
- else
- goto err;
+ else {
+ smp->status |= IB_SMP_INVALID_FIELD;
+ break;
+ }
spin_lock_irqsave(&ppd->lflags_lock, flags);
ppd->lflags &= ~QIBL_LINKV;
spin_unlock_irqrestore(&ppd->lflags_lock, flags);
@@ -835,8 +841,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
qib_set_linkstate(ppd, QIB_IB_LINKACTIVE);
break;
default:
- /* XXX We have already partially updated our state! */
- goto err;
+ smp->status |= IB_SMP_INVALID_FIELD;
}
ret = subn_get_portinfo(smp, ibdev, port);
diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c
index 5f95f0f6385d..08944e2ee334 100644
--- a/drivers/infiniband/hw/qib/qib_mr.c
+++ b/drivers/infiniband/hw/qib/qib_mr.c
@@ -39,7 +39,6 @@
/* Fast memory region */
struct qib_fmr {
struct ib_fmr ibfmr;
- u8 page_shift;
struct qib_mregion mr; /* must be last */
};
@@ -107,6 +106,7 @@ static struct qib_mr *alloc_mr(int count, struct qib_lkey_table *lk_table)
goto bail;
}
mr->mr.mapsz = m;
+ mr->mr.page_shift = 0;
mr->mr.max_segs = count;
/*
@@ -231,6 +231,8 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
mr->mr.access_flags = mr_access_flags;
mr->umem = umem;
+ if (is_power_of_2(umem->page_size))
+ mr->mr.page_shift = ilog2(umem->page_size);
m = 0;
n = 0;
list_for_each_entry(chunk, &umem->chunk_list, list) {
@@ -390,7 +392,7 @@ struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
fmr->mr.offset = 0;
fmr->mr.access_flags = mr_access_flags;
fmr->mr.max_segs = fmr_attr->max_pages;
- fmr->page_shift = fmr_attr->page_shift;
+ fmr->mr.page_shift = fmr_attr->page_shift;
atomic_set(&fmr->mr.refcount, 0);
ret = &fmr->ibfmr;
@@ -437,7 +439,7 @@ int qib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
spin_lock_irqsave(&rkt->lock, flags);
fmr->mr.user_base = iova;
fmr->mr.iova = iova;
- ps = 1 << fmr->page_shift;
+ ps = 1 << fmr->mr.page_shift;
fmr->mr.length = list_len * ps;
m = 0;
n = 0;
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 6c39851d2ded..e16751f8639e 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -48,13 +48,12 @@ static inline unsigned mk_qpn(struct qib_qpn_table *qpt,
static inline unsigned find_next_offset(struct qib_qpn_table *qpt,
struct qpn_map *map, unsigned off,
- unsigned r)
+ unsigned n)
{
if (qpt->mask) {
off++;
- if ((off & qpt->mask) >> 1 != r)
- off = ((off & qpt->mask) ?
- (off | qpt->mask) + 1 : off) | (r << 1);
+ if (((off & qpt->mask) >> 1) >= n)
+ off = (off | qpt->mask) + 2;
} else
off = find_next_zero_bit(map->page, BITS_PER_PAGE, off);
return off;
@@ -123,7 +122,6 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
u32 i, offset, max_scan, qpn;
struct qpn_map *map;
u32 ret;
- int r;
if (type == IB_QPT_SMI || type == IB_QPT_GSI) {
unsigned n;
@@ -139,15 +137,11 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
goto bail;
}
- r = smp_processor_id();
- if (r >= dd->n_krcv_queues)
- r %= dd->n_krcv_queues;
- qpn = qpt->last + 1;
+ qpn = qpt->last + 2;
if (qpn >= QPN_MAX)
qpn = 2;
- if (qpt->mask && ((qpn & qpt->mask) >> 1) != r)
- qpn = ((qpn & qpt->mask) ? (qpn | qpt->mask) + 1 : qpn) |
- (r << 1);
+ if (qpt->mask && ((qpn & qpt->mask) >> 1) >= dd->n_krcv_queues)
+ qpn = (qpn | qpt->mask) + 2;
offset = qpn & BITS_PER_PAGE_MASK;
map = &qpt->map[qpn / BITS_PER_PAGE];
max_scan = qpt->nmaps - !offset;
@@ -163,7 +157,8 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
ret = qpn;
goto bail;
}
- offset = find_next_offset(qpt, map, offset, r);
+ offset = find_next_offset(qpt, map, offset,
+ dd->n_krcv_queues);
qpn = mk_qpn(qpt, map, offset);
/*
* This test differs from alloc_pidmap().
@@ -183,13 +178,13 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
if (qpt->nmaps == QPNMAP_ENTRIES)
break;
map = &qpt->map[qpt->nmaps++];
- offset = qpt->mask ? (r << 1) : 0;
+ offset = 0;
} else if (map < &qpt->map[qpt->nmaps]) {
++map;
- offset = qpt->mask ? (r << 1) : 0;
+ offset = 0;
} else {
map = &qpt->map[0];
- offset = qpt->mask ? (r << 1) : 2;
+ offset = 2;
}
qpn = mk_qpn(qpt, map, offset);
}
@@ -468,6 +463,10 @@ int qib_error_qp(struct qib_qp *qp, enum ib_wc_status err)
qp->s_flags &= ~(QIB_S_TIMER | QIB_S_WAIT_RNR);
del_timer(&qp->s_timer);
}
+
+ if (qp->s_flags & QIB_S_ANY_WAIT_SEND)
+ qp->s_flags &= ~QIB_S_ANY_WAIT_SEND;
+
spin_lock(&dev->pending_lock);
if (!list_empty(&qp->iowait) && !(qp->s_flags & QIB_S_BUSY)) {
qp->s_flags &= ~QIB_S_ANY_WAIT_IO;
@@ -1061,7 +1060,6 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
}
qp->ibqp.qp_num = err;
qp->port_num = init_attr->port_num;
- qp->processor_id = smp_processor_id();
qib_reset_qp(qp, init_attr->qp_type);
break;
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 955fb7157793..8245237b67ce 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -1407,6 +1407,7 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp,
struct qib_ctxtdata *rcd)
{
struct qib_swqe *wqe;
+ struct qib_pportdata *ppd = ppd_from_ibp(ibp);
enum ib_wc_status status;
unsigned long flags;
int diff;
@@ -1414,6 +1415,29 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp,
u32 aeth;
u64 val;
+ if (opcode != OP(RDMA_READ_RESPONSE_MIDDLE)) {
+ /*
+ * If ACK'd PSN on SDMA busy list try to make progress to
+ * reclaim SDMA credits.
+ */
+ if ((qib_cmp24(psn, qp->s_sending_psn) >= 0) &&
+ (qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)) {
+
+ /*
+ * If send tasklet not running attempt to progress
+ * SDMA queue.
+ */
+ if (!(qp->s_flags & QIB_S_BUSY)) {
+ /* Acquire SDMA Lock */
+ spin_lock_irqsave(&ppd->sdma_lock, flags);
+ /* Invoke sdma make progress */
+ qib_sdma_make_progress(ppd);
+ /* Release SDMA Lock */
+ spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+ }
+ }
+ }
+
spin_lock_irqsave(&qp->s_lock, flags);
/* Ignore invalid responses. */
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index e1b3da2a1f85..4a51fd1e9cb7 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -445,13 +445,14 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
qkey = be32_to_cpu(ohdr->u.ud.deth[0]);
src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & QIB_QPN_MASK;
- /* Get the number of bytes the message was padded by. */
+ /*
+ * Get the number of bytes the message was padded by
+ * and drop incomplete packets.
+ */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
- if (unlikely(tlen < (hdrsize + pad + 4))) {
- /* Drop incomplete packets. */
- ibp->n_pkt_drops++;
- goto bail;
- }
+ if (unlikely(tlen < (hdrsize + pad + 4)))
+ goto drop;
+
tlen -= hdrsize + pad + 4;
/*
@@ -460,10 +461,8 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
*/
if (qp->ibqp.qp_num) {
if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE ||
- hdr->lrh[3] == IB_LID_PERMISSIVE)) {
- ibp->n_pkt_drops++;
- goto bail;
- }
+ hdr->lrh[3] == IB_LID_PERMISSIVE))
+ goto drop;
if (qp->ibqp.qp_num > 1) {
u16 pkey1, pkey2;
@@ -476,7 +475,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
0xF,
src_qp, qp->ibqp.qp_num,
hdr->lrh[3], hdr->lrh[1]);
- goto bail;
+ return;
}
}
if (unlikely(qkey != qp->qkey)) {
@@ -484,30 +483,24 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
src_qp, qp->ibqp.qp_num,
hdr->lrh[3], hdr->lrh[1]);
- goto bail;
+ return;
}
/* Drop invalid MAD packets (see 13.5.3.1). */
if (unlikely(qp->ibqp.qp_num == 1 &&
(tlen != 256 ||
- (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) {
- ibp->n_pkt_drops++;
- goto bail;
- }
+ (be16_to_cpu(hdr->lrh[0]) >> 12) == 15)))
+ goto drop;
} else {
struct ib_smp *smp;
/* Drop invalid MAD packets (see 13.5.3.1). */
- if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15) {
- ibp->n_pkt_drops++;
- goto bail;
- }
+ if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15)
+ goto drop;
smp = (struct ib_smp *) data;
if ((hdr->lrh[1] == IB_LID_PERMISSIVE ||
hdr->lrh[3] == IB_LID_PERMISSIVE) &&
- smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
- ibp->n_pkt_drops++;
- goto bail;
- }
+ smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+ goto drop;
}
/*
@@ -519,14 +512,12 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
wc.ex.imm_data = ohdr->u.ud.imm_data;
wc.wc_flags = IB_WC_WITH_IMM;
- hdrsize += sizeof(u32);
+ tlen -= sizeof(u32);
} else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
wc.ex.imm_data = 0;
wc.wc_flags = 0;
- } else {
- ibp->n_pkt_drops++;
- goto bail;
- }
+ } else
+ goto drop;
/*
* A GRH is expected to preceed the data even if not
@@ -556,8 +547,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
/* Silently drop packets which are too big. */
if (unlikely(wc.byte_len > qp->r_len)) {
qp->r_flags |= QIB_R_REUSE_SGE;
- ibp->n_pkt_drops++;
- return;
+ goto drop;
}
if (has_grh) {
qib_copy_sge(&qp->r_sge, &hdr->u.l.grh,
@@ -594,5 +584,8 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
cpu_to_be32(IB_BTH_SOLICITED)) != 0);
-bail:;
+ return;
+
+drop:
+ ibp->n_pkt_drops++;
}
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
index 4c19e06b5e85..66208bcd7c13 100644
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -382,6 +382,7 @@ static void qib_user_sdma_free_pkt_list(struct device *dev,
kmem_cache_free(pq->pkt_slab, pkt);
}
+ INIT_LIST_HEAD(list);
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index bd57c1273225..63b22a9a7feb 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -301,6 +301,7 @@ struct qib_mregion {
int access_flags;
u32 max_segs; /* number of qib_segs in all the arrays */
u32 mapsz; /* size of the map array */
+ u8 page_shift; /* 0 - non unform/non powerof2 sizes */
atomic_t refcount;
struct qib_segarray *map[0]; /* the segments */
};
@@ -435,7 +436,6 @@ struct qib_qp {
spinlock_t r_lock; /* used for APM */
spinlock_t s_lock;
atomic_t s_dma_busy;
- unsigned processor_id; /* Processor ID QP is bound to */
u32 s_flags;
u32 s_cur_size; /* size of send packet in bytes */
u32 s_len; /* total length of s_sge */
@@ -813,13 +813,8 @@ extern struct workqueue_struct *qib_cq_wq;
*/
static inline void qib_schedule_send(struct qib_qp *qp)
{
- if (qib_send_ok(qp)) {
- if (qp->processor_id == smp_processor_id())
- queue_work(qib_wq, &qp->s_work);
- else
- queue_work_on(qp->processor_id,
- qib_wq, &qp->s_work);
- }
+ if (qib_send_ok(qp))
+ queue_work(qib_wq, &qp->s_work);
}
static inline int qib_pkey_ok(u16 pkey1, u16 pkey2)
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 9d9a9dc51f18..55855eeabae7 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -1,7 +1,6 @@
config INFINIBAND_IPOIB
tristate "IP-over-InfiniBand"
depends on NETDEVICES && INET && (IPV6 || IPV6=n)
- select INET_LRO
---help---
Support for the IP-over-InfiniBand protocol (IPoIB). This
transports IP packets over InfiniBand so you can use your IB
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 753a983a5fdc..ab97f92fc257 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -50,7 +50,7 @@
#include <rdma/ib_verbs.h>
#include <rdma/ib_pack.h>
#include <rdma/ib_sa.h>
-#include <linux/inet_lro.h>
+#include <linux/sched.h>
/* constants */
@@ -100,9 +100,6 @@ enum {
IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */
IPOIB_MCAST_FLAG_ATTACHED = 3,
- IPOIB_MAX_LRO_DESCRIPTORS = 8,
- IPOIB_LRO_MAX_AGGR = 64,
-
MAX_SEND_CQE = 16,
IPOIB_CM_COPYBREAK = 256,
};
@@ -262,11 +259,6 @@ struct ipoib_ethtool_st {
u16 max_coalesced_frames;
};
-struct ipoib_lro {
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[IPOIB_MAX_LRO_DESCRIPTORS];
-};
-
/*
* Device private locking: network stack tx_lock protects members used
* in TX fast path, lock protects everything else. lock nests inside
@@ -352,8 +344,6 @@ struct ipoib_dev_priv {
int hca_caps;
struct ipoib_ethtool_st ethtool;
struct timer_list poll_timer;
-
- struct ipoib_lro lro;
};
struct ipoib_ah {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index bb1004114dec..c1c49f2d35b5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1480,6 +1480,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ priv->dev->features |= NETIF_F_GRO;
if (priv->hca_caps & IB_DEVICE_UD_TSO)
dev->features |= NETIF_F_TSO;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 1a1657c82edd..19f7f5206f78 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -106,63 +106,12 @@ static int ipoib_set_coalesce(struct net_device *dev,
return 0;
}
-static const char ipoib_stats_keys[][ETH_GSTRING_LEN] = {
- "LRO aggregated", "LRO flushed",
- "LRO avg aggr", "LRO no desc"
-};
-
-static void ipoib_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
-{
- switch (stringset) {
- case ETH_SS_STATS:
- memcpy(data, *ipoib_stats_keys, sizeof(ipoib_stats_keys));
- break;
- }
-}
-
-static int ipoib_get_sset_count(struct net_device *dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS:
- return ARRAY_SIZE(ipoib_stats_keys);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static void ipoib_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, uint64_t *data)
-{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- int index = 0;
-
- /* Get LRO statistics */
- data[index++] = priv->lro.lro_mgr.stats.aggregated;
- data[index++] = priv->lro.lro_mgr.stats.flushed;
- if (priv->lro.lro_mgr.stats.flushed)
- data[index++] = priv->lro.lro_mgr.stats.aggregated /
- priv->lro.lro_mgr.stats.flushed;
- else
- data[index++] = 0;
- data[index++] = priv->lro.lro_mgr.stats.no_desc;
-}
-
-static int ipoib_set_flags(struct net_device *dev, u32 flags)
-{
- return ethtool_op_set_flags(dev, flags, ETH_FLAG_LRO);
-}
-
static const struct ethtool_ops ipoib_ethtool_ops = {
.get_drvinfo = ipoib_get_drvinfo,
.get_rx_csum = ipoib_get_rx_csum,
.set_tso = ipoib_set_tso,
.get_coalesce = ipoib_get_coalesce,
.set_coalesce = ipoib_set_coalesce,
- .get_flags = ethtool_op_get_flags,
- .set_flags = ipoib_set_flags,
- .get_strings = ipoib_get_strings,
- .get_sset_count = ipoib_get_sset_count,
- .get_ethtool_stats = ipoib_get_ethtool_stats,
};
void ipoib_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index dfa71903d6e4..806d0292dc39 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -295,10 +295,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok))
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (dev->features & NETIF_F_LRO)
- lro_receive_skb(&priv->lro.lro_mgr, skb, NULL);
- else
- netif_receive_skb(skb);
+ napi_gro_receive(&priv->napi, skb);
repost:
if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
@@ -450,9 +447,6 @@ poll_more:
}
if (done < budget) {
- if (dev->features & NETIF_F_LRO)
- lro_flush_all(&priv->lro.lro_mgr);
-
napi_complete(napi);
if (unlikely(ib_req_notify_cq(priv->recv_cq,
IB_CQ_NEXT_COMP |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 9ff7bc73ed95..7a07a728fe0d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -60,15 +60,6 @@ MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue");
module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444);
MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue");
-static int lro;
-module_param(lro, bool, 0444);
-MODULE_PARM_DESC(lro, "Enable LRO (Large Receive Offload)");
-
-static int lro_max_aggr = IPOIB_LRO_MAX_AGGR;
-module_param(lro_max_aggr, int, 0644);
-MODULE_PARM_DESC(lro_max_aggr, "LRO: Max packets to be aggregated "
- "(default = 64)");
-
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
int ipoib_debug_level;
@@ -976,54 +967,6 @@ static const struct header_ops ipoib_header_ops = {
.create = ipoib_hard_header,
};
-static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
- void **tcph, u64 *hdr_flags, void *priv)
-{
- unsigned int ip_len;
- struct iphdr *iph;
-
- if (unlikely(skb->protocol != htons(ETH_P_IP)))
- return -1;
-
- /*
- * In the future we may add an else clause that verifies the
- * checksum and allows devices which do not calculate checksum
- * to use LRO.
- */
- if (unlikely(skb->ip_summed != CHECKSUM_UNNECESSARY))
- return -1;
-
- /* Check for 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 (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
- return -1;
-
- *hdr_flags = LRO_IPV4 | LRO_TCP;
- *iphdr = iph;
-
- return 0;
-}
-
-static void ipoib_lro_setup(struct ipoib_dev_priv *priv)
-{
- priv->lro.lro_mgr.max_aggr = lro_max_aggr;
- priv->lro.lro_mgr.max_desc = IPOIB_MAX_LRO_DESCRIPTORS;
- priv->lro.lro_mgr.lro_arr = priv->lro.lro_desc;
- priv->lro.lro_mgr.get_skb_header = get_skb_hdr;
- priv->lro.lro_mgr.features = LRO_F_NAPI;
- priv->lro.lro_mgr.dev = priv->dev;
- priv->lro.lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-}
-
static const struct net_device_ops ipoib_netdev_ops = {
.ndo_open = ipoib_open,
.ndo_stop = ipoib_stop,
@@ -1067,8 +1010,6 @@ static void ipoib_setup(struct net_device *dev)
priv->dev = dev;
- ipoib_lro_setup(priv);
-
spin_lock_init(&priv->lock);
mutex_init(&priv->vlan_mutex);
@@ -1218,8 +1159,7 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca)
priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
}
- if (lro)
- priv->dev->features |= NETIF_F_LRO;
+ priv->dev->features |= NETIF_F_GRO;
if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO)
priv->dev->features |= NETIF_F_TSO;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index cfc1d65c4577..4b62105ed1e8 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -441,18 +441,28 @@ static void srp_disconnect_target(struct srp_target_port *target)
wait_for_completion(&target->done);
}
+static bool srp_change_state(struct srp_target_port *target,
+ enum srp_target_state old,
+ enum srp_target_state new)
+{
+ bool changed = false;
+
+ spin_lock_irq(&target->lock);
+ if (target->state == old) {
+ target->state = new;
+ changed = true;
+ }
+ spin_unlock_irq(&target->lock);
+ return changed;
+}
+
static void srp_remove_work(struct work_struct *work)
{
struct srp_target_port *target =
container_of(work, struct srp_target_port, work);
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state != SRP_TARGET_DEAD) {
- spin_unlock_irq(target->scsi_host->host_lock);
+ if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED))
return;
- }
- target->state = SRP_TARGET_REMOVED;
- spin_unlock_irq(target->scsi_host->host_lock);
spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
@@ -539,33 +549,34 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
scsi_sg_count(scmnd), scmnd->sc_data_direction);
}
-static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
+static void srp_remove_req(struct srp_target_port *target,
+ struct srp_request *req, s32 req_lim_delta)
{
+ unsigned long flags;
+
srp_unmap_data(req->scmnd, target, req);
- list_move_tail(&req->list, &target->free_reqs);
+ spin_lock_irqsave(&target->lock, flags);
+ target->req_lim += req_lim_delta;
+ req->scmnd = NULL;
+ list_add_tail(&req->list, &target->free_reqs);
+ spin_unlock_irqrestore(&target->lock, flags);
}
static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
{
req->scmnd->result = DID_RESET << 16;
req->scmnd->scsi_done(req->scmnd);
- srp_remove_req(target, req);
+ srp_remove_req(target, req, 0);
}
static int srp_reconnect_target(struct srp_target_port *target)
{
struct ib_qp_attr qp_attr;
- struct srp_request *req, *tmp;
struct ib_wc wc;
- int ret;
+ int i, ret;
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state != SRP_TARGET_LIVE) {
- spin_unlock_irq(target->scsi_host->host_lock);
+ if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING))
return -EAGAIN;
- }
- target->state = SRP_TARGET_CONNECTING;
- spin_unlock_irq(target->scsi_host->host_lock);
srp_disconnect_target(target);
/*
@@ -590,27 +601,23 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->send_cq, 1, &wc) > 0)
; /* nothing */
- spin_lock_irq(target->scsi_host->host_lock);
- list_for_each_entry_safe(req, tmp, &target->req_queue, list)
- srp_reset_req(target, req);
- spin_unlock_irq(target->scsi_host->host_lock);
+ for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
+ struct srp_request *req = &target->req_ring[i];
+ if (req->scmnd)
+ srp_reset_req(target, req);
+ }
- target->rx_head = 0;
- target->tx_head = 0;
- target->tx_tail = 0;
+ INIT_LIST_HEAD(&target->free_tx);
+ for (i = 0; i < SRP_SQ_SIZE; ++i)
+ list_add(&target->tx_ring[i]->list, &target->free_tx);
target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret)
goto err;
- spin_lock_irq(target->scsi_host->host_lock);
- if (target->state == SRP_TARGET_CONNECTING) {
- ret = 0;
- target->state = SRP_TARGET_LIVE;
- } else
+ if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE))
ret = -EAGAIN;
- spin_unlock_irq(target->scsi_host->host_lock);
return ret;
@@ -620,17 +627,20 @@ err:
/*
* We couldn't reconnect, so kill our target port off.
- * However, we have to defer the real removal because we might
- * be in the context of the SCSI error handler now, which
- * would deadlock if we call scsi_remove_host().
+ * However, we have to defer the real removal because we
+ * are in the context of the SCSI error handler now, which
+ * will deadlock if we call scsi_remove_host().
+ *
+ * Schedule our work inside the lock to avoid a race with
+ * the flush_scheduled_work() in srp_remove_one().
*/
- spin_lock_irq(target->scsi_host->host_lock);
+ spin_lock_irq(&target->lock);
if (target->state == SRP_TARGET_CONNECTING) {
target->state = SRP_TARGET_DEAD;
INIT_WORK(&target->work, srp_remove_work);
schedule_work(&target->work);
}
- spin_unlock_irq(target->scsi_host->host_lock);
+ spin_unlock_irq(&target->lock);
return ret;
}
@@ -758,7 +768,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
struct srp_direct_buf *buf = (void *) cmd->add_data;
buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
- buf->key = cpu_to_be32(dev->mr->rkey);
+ buf->key = cpu_to_be32(target->rkey);
buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
} else if (srp_map_fmr(target, scat, count, req,
(void *) cmd->add_data)) {
@@ -783,7 +793,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
buf->desc_list[i].va =
cpu_to_be64(ib_sg_dma_address(ibdev, sg));
buf->desc_list[i].key =
- cpu_to_be32(dev->mr->rkey);
+ cpu_to_be32(target->rkey);
buf->desc_list[i].len = cpu_to_be32(dma_len);
datalen += dma_len;
}
@@ -796,7 +806,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
buf->table_desc.va =
cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf);
buf->table_desc.key =
- cpu_to_be32(target->srp_host->srp_dev->mr->rkey);
+ cpu_to_be32(target->rkey);
buf->table_desc.len =
cpu_to_be32(count * sizeof (struct srp_direct_buf));
@@ -812,9 +822,23 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
}
/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head. Lock cannot be dropped between call here and
- * call to __srp_post_send().
+ * Return an IU and possible credit to the free pool
+ */
+static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu,
+ enum srp_iu_type iu_type)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_add(&iu->list, &target->free_tx);
+ if (iu_type != SRP_IU_RSP)
+ ++target->req_lim;
+ spin_unlock_irqrestore(&target->lock, flags);
+}
+
+/*
+ * Must be called with target->lock held to protect req_lim and free_tx.
+ * If IU is not sent, it must be returned using srp_put_tx_iu().
*
* Note:
* An upper limit for the number of allocated information units for each
@@ -833,83 +857,59 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
srp_send_completion(target->send_cq, target);
- if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
+ if (list_empty(&target->free_tx))
return NULL;
/* Initiator responses to target requests do not consume credits */
- if (target->req_lim <= rsv && iu_type != SRP_IU_RSP) {
- ++target->zero_req_lim;
- return NULL;
+ if (iu_type != SRP_IU_RSP) {
+ if (target->req_lim <= rsv) {
+ ++target->zero_req_lim;
+ return NULL;
+ }
+
+ --target->req_lim;
}
- iu = target->tx_ring[target->tx_head & SRP_SQ_MASK];
- iu->type = iu_type;
+ iu = list_first_entry(&target->free_tx, struct srp_iu, list);
+ list_del(&iu->list);
return iu;
}
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.
- */
-static int __srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len)
+static int srp_post_send(struct srp_target_port *target,
+ struct srp_iu *iu, int len)
{
struct ib_sge list;
struct ib_send_wr wr, *bad_wr;
- int ret = 0;
list.addr = iu->dma;
list.length = len;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
+ list.lkey = target->lkey;
wr.next = NULL;
- wr.wr_id = target->tx_head & SRP_SQ_MASK;
+ wr.wr_id = (uintptr_t) iu;
wr.sg_list = &list;
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
wr.send_flags = IB_SEND_SIGNALED;
- ret = ib_post_send(target->qp, &wr, &bad_wr);
-
- if (!ret) {
- ++target->tx_head;
- if (iu->type != SRP_IU_RSP)
- --target->req_lim;
- }
-
- return ret;
+ return ib_post_send(target->qp, &wr, &bad_wr);
}
-static int srp_post_recv(struct srp_target_port *target)
+static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu)
{
- unsigned long flags;
- struct srp_iu *iu;
- struct ib_sge list;
struct ib_recv_wr wr, *bad_wr;
- unsigned int next;
- int ret;
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
-
- next = target->rx_head & SRP_RQ_MASK;
- wr.wr_id = next;
- iu = target->rx_ring[next];
+ struct ib_sge list;
list.addr = iu->dma;
list.length = iu->size;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
+ list.lkey = target->lkey;
wr.next = NULL;
+ wr.wr_id = (uintptr_t) iu;
wr.sg_list = &list;
wr.num_sge = 1;
- ret = ib_post_recv(target->qp, &wr, &bad_wr);
- if (!ret)
- ++target->rx_head;
-
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
-
- return ret;
+ return ib_post_recv(target->qp, &wr, &bad_wr);
}
static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
@@ -917,23 +917,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
struct srp_request *req;
struct scsi_cmnd *scmnd;
unsigned long flags;
- s32 delta;
-
- delta = (s32) be32_to_cpu(rsp->req_lim_delta);
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
-
- target->req_lim += delta;
-
- req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT];
if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
- if (be32_to_cpu(rsp->resp_data_len) < 4)
- req->tsk_status = -1;
- else
- req->tsk_status = rsp->data[3];
- complete(&req->done);
+ spin_lock_irqsave(&target->lock, flags);
+ target->req_lim += be32_to_cpu(rsp->req_lim_delta);
+ spin_unlock_irqrestore(&target->lock, flags);
+
+ target->tsk_mgmt_status = -1;
+ if (be32_to_cpu(rsp->resp_data_len) >= 4)
+ target->tsk_mgmt_status = rsp->data[3];
+ complete(&target->tsk_mgmt_done);
} else {
+ req = &target->req_ring[rsp->tag];
scmnd = req->scmnd;
if (!scmnd)
shost_printk(KERN_ERR, target->scsi_host,
@@ -953,49 +948,42 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
- if (!req->tsk_mgmt) {
- scmnd->host_scribble = (void *) -1L;
- scmnd->scsi_done(scmnd);
-
- srp_remove_req(target, req);
- } else
- req->cmd_done = 1;
+ srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta));
+ scmnd->host_scribble = NULL;
+ scmnd->scsi_done(scmnd);
}
-
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
static int srp_response_common(struct srp_target_port *target, s32 req_delta,
void *rsp, int len)
{
- struct ib_device *dev;
+ struct ib_device *dev = target->srp_host->srp_dev->dev;
unsigned long flags;
struct srp_iu *iu;
- int err = 1;
+ int err;
- dev = target->srp_host->srp_dev->dev;
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
+ spin_lock_irqsave(&target->lock, flags);
target->req_lim += req_delta;
-
iu = __srp_get_tx_iu(target, SRP_IU_RSP);
+ spin_unlock_irqrestore(&target->lock, flags);
+
if (!iu) {
shost_printk(KERN_ERR, target->scsi_host, PFX
"no IU available to send response\n");
- goto out;
+ return 1;
}
ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE);
memcpy(iu->buf, rsp, len);
ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
- err = __srp_post_send(target, iu, len);
- if (err)
+ err = srp_post_send(target, iu, len);
+ if (err) {
shost_printk(KERN_ERR, target->scsi_host, PFX
"unable to post response: %d\n", err);
+ srp_put_tx_iu(target, iu, SRP_IU_RSP);
+ }
-out:
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
return err;
}
@@ -1032,14 +1020,11 @@ static void srp_process_aer_req(struct srp_target_port *target,
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
- struct ib_device *dev;
- struct srp_iu *iu;
+ struct ib_device *dev = target->srp_host->srp_dev->dev;
+ struct srp_iu *iu = (struct srp_iu *) wc->wr_id;
int res;
u8 opcode;
- iu = target->rx_ring[wc->wr_id];
-
- dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
DMA_FROM_DEVICE);
@@ -1080,7 +1065,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
DMA_FROM_DEVICE);
- res = srp_post_recv(target);
+ res = srp_post_recv(target, iu);
if (res != 0)
shost_printk(KERN_ERR, target->scsi_host,
PFX "Recv failed with error code %d\n", res);
@@ -1109,6 +1094,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
struct ib_wc wc;
+ struct srp_iu *iu;
while (ib_poll_cq(cq, 1, &wc) > 0) {
if (wc.status) {
@@ -1119,18 +1105,19 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
break;
}
- ++target->tx_tail;
+ iu = (struct srp_iu *) wc.wr_id;
+ list_add(&iu->list, &target->free_tx);
}
}
-static int srp_queuecommand(struct scsi_cmnd *scmnd,
- void (*done)(struct scsi_cmnd *))
+static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
{
- struct srp_target_port *target = host_to_target(scmnd->device->host);
+ struct srp_target_port *target = host_to_target(shost);
struct srp_request *req;
struct srp_iu *iu;
struct srp_cmd *cmd;
struct ib_device *dev;
+ unsigned long flags;
int len;
if (target->state == SRP_TARGET_CONNECTING)
@@ -1139,11 +1126,19 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
if (target->state == SRP_TARGET_DEAD ||
target->state == SRP_TARGET_REMOVED) {
scmnd->result = DID_BAD_TARGET << 16;
- done(scmnd);
+ scmnd->scsi_done(scmnd);
return 0;
}
+ spin_lock_irqsave(&target->lock, flags);
iu = __srp_get_tx_iu(target, SRP_IU_CMD);
+ if (iu) {
+ req = list_first_entry(&target->free_reqs, struct srp_request,
+ list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(&target->lock, flags);
+
if (!iu)
goto err;
@@ -1151,11 +1146,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
- req = list_first_entry(&target->free_reqs, struct srp_request, list);
-
- scmnd->scsi_done = done;
scmnd->result = 0;
- scmnd->host_scribble = (void *) (long) req->index;
+ scmnd->host_scribble = (void *) req;
cmd = iu->buf;
memset(cmd, 0, sizeof *cmd);
@@ -1167,31 +1159,34 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
req->scmnd = scmnd;
req->cmd = iu;
- req->cmd_done = 0;
- req->tsk_mgmt = NULL;
len = srp_map_data(scmnd, target, req);
if (len < 0) {
shost_printk(KERN_ERR, target->scsi_host,
PFX "Failed to map data\n");
- goto err;
+ goto err_iu;
}
ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
- if (__srp_post_send(target, iu, len)) {
+ if (srp_post_send(target, iu, len)) {
shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
goto err_unmap;
}
- list_move_tail(&req->list, &target->req_queue);
-
return 0;
err_unmap:
srp_unmap_data(scmnd, target, req);
+err_iu:
+ srp_put_tx_iu(target, iu, SRP_IU_CMD);
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_add(&req->list, &target->free_reqs);
+ spin_unlock_irqrestore(&target->lock, flags);
+
err:
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1214,6 +1209,8 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
GFP_KERNEL, DMA_TO_DEVICE);
if (!target->tx_ring[i])
goto err;
+
+ list_add(&target->tx_ring[i]->list, &target->free_tx);
}
return 0;
@@ -1375,7 +1372,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
break;
for (i = 0; i < SRP_RQ_SIZE; i++) {
- target->status = srp_post_recv(target);
+ struct srp_iu *iu = target->rx_ring[i];
+ target->status = srp_post_recv(target, iu);
if (target->status)
break;
}
@@ -1440,25 +1438,24 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
}
static int srp_send_tsk_mgmt(struct srp_target_port *target,
- struct srp_request *req, u8 func)
+ u64 req_tag, unsigned int lun, u8 func)
{
struct ib_device *dev = target->srp_host->srp_dev->dev;
struct srp_iu *iu;
struct srp_tsk_mgmt *tsk_mgmt;
- spin_lock_irq(target->scsi_host->host_lock);
-
if (target->state == SRP_TARGET_DEAD ||
- target->state == SRP_TARGET_REMOVED) {
- req->scmnd->result = DID_BAD_TARGET << 16;
- goto out;
- }
+ target->state == SRP_TARGET_REMOVED)
+ return -1;
- init_completion(&req->done);
+ init_completion(&target->tsk_mgmt_done);
+ spin_lock_irq(&target->lock);
iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT);
+ spin_unlock_irq(&target->lock);
+
if (!iu)
- goto out;
+ return -1;
ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt,
DMA_TO_DEVICE);
@@ -1466,70 +1463,46 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
tsk_mgmt->opcode = SRP_TSK_MGMT;
- tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48);
- tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT;
+ tsk_mgmt->lun = cpu_to_be64((u64) lun << 48);
+ tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT;
tsk_mgmt->tsk_mgmt_func = func;
- tsk_mgmt->task_tag = req->index;
+ tsk_mgmt->task_tag = req_tag;
ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
DMA_TO_DEVICE);
- if (__srp_post_send(target, iu, sizeof *tsk_mgmt))
- goto out;
-
- req->tsk_mgmt = iu;
-
- spin_unlock_irq(target->scsi_host->host_lock);
-
- if (!wait_for_completion_timeout(&req->done,
- msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
+ if (srp_post_send(target, iu, sizeof *tsk_mgmt)) {
+ srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT);
return -1;
+ }
- return 0;
-
-out:
- spin_unlock_irq(target->scsi_host->host_lock);
- return -1;
-}
-
-static int srp_find_req(struct srp_target_port *target,
- struct scsi_cmnd *scmnd,
- struct srp_request **req)
-{
- if (scmnd->host_scribble == (void *) -1L)
+ if (!wait_for_completion_timeout(&target->tsk_mgmt_done,
+ msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
return -1;
- *req = &target->req_ring[(long) scmnd->host_scribble];
-
return 0;
}
static int srp_abort(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
- struct srp_request *req;
+ struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
int ret = SUCCESS;
shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
- if (target->qp_in_error)
+ if (!req || target->qp_in_error)
return FAILED;
- if (srp_find_req(target, scmnd, &req))
+ if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+ SRP_TSK_ABORT_TASK))
return FAILED;
- if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
- return FAILED;
-
- spin_lock_irq(target->scsi_host->host_lock);
- if (req->cmd_done) {
- srp_remove_req(target, req);
- scmnd->scsi_done(scmnd);
- } else if (!req->tsk_status) {
- srp_remove_req(target, req);
- scmnd->result = DID_ABORT << 16;
- } else
- ret = FAILED;
-
- spin_unlock_irq(target->scsi_host->host_lock);
+ if (req->scmnd) {
+ if (!target->tsk_mgmt_status) {
+ srp_remove_req(target, req, 0);
+ scmnd->result = DID_ABORT << 16;
+ } else
+ ret = FAILED;
+ }
return ret;
}
@@ -1537,26 +1510,23 @@ static int srp_abort(struct scsi_cmnd *scmnd)
static int srp_reset_device(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
- struct srp_request *req, *tmp;
+ int i;
shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
if (target->qp_in_error)
return FAILED;
- if (srp_find_req(target, scmnd, &req))
+ if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun,
+ SRP_TSK_LUN_RESET))
return FAILED;
- if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
+ if (target->tsk_mgmt_status)
return FAILED;
- if (req->tsk_status)
- return FAILED;
-
- spin_lock_irq(target->scsi_host->host_lock);
- list_for_each_entry_safe(req, tmp, &target->req_queue, list)
- if (req->scmnd->device == scmnd->device)
+ for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
+ struct srp_request *req = &target->req_ring[i];
+ if (req->scmnd && req->scmnd->device == scmnd->device)
srp_reset_req(target, req);
-
- spin_unlock_irq(target->scsi_host->host_lock);
+ }
return SUCCESS;
}
@@ -1985,9 +1955,12 @@ static ssize_t srp_create_target(struct device *dev,
target->io_class = SRP_REV16A_IB_IO_CLASS;
target->scsi_host = target_host;
target->srp_host = host;
+ target->lkey = host->srp_dev->mr->lkey;
+ target->rkey = host->srp_dev->mr->rkey;
+ spin_lock_init(&target->lock);
+ INIT_LIST_HEAD(&target->free_tx);
INIT_LIST_HEAD(&target->free_reqs);
- INIT_LIST_HEAD(&target->req_queue);
for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
target->req_ring[i].index = i;
list_add_tail(&target->req_ring[i].list, &target->free_reqs);
@@ -2215,9 +2188,9 @@ static void srp_remove_one(struct ib_device *device)
*/
spin_lock(&host->target_lock);
list_for_each_entry(target, &host->target_list, list) {
- spin_lock_irq(target->scsi_host->host_lock);
+ spin_lock_irq(&target->lock);
target->state = SRP_TARGET_REMOVED;
- spin_unlock_irq(target->scsi_host->host_lock);
+ spin_unlock_irq(&target->lock);
}
spin_unlock(&host->target_lock);
@@ -2256,8 +2229,7 @@ static int __init srp_init_module(void)
{
int ret;
- BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE);
- BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *));
if (srp_sg_tablesize > 255) {
printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index ed0dce9e479f..9dc6fc3fd894 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -59,16 +59,15 @@ enum {
SRP_RQ_SHIFT = 6,
SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT,
- SRP_RQ_MASK = SRP_RQ_SIZE - 1,
SRP_SQ_SIZE = SRP_RQ_SIZE,
- SRP_SQ_MASK = SRP_SQ_SIZE - 1,
SRP_RSP_SQ_SIZE = 1,
SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE,
SRP_TSK_MGMT_SQ_SIZE = 1,
SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE,
- SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1),
+ SRP_TAG_NO_REQ = ~0U,
+ SRP_TAG_TSK_MGMT = 1U << 31,
SRP_FMR_SIZE = 256,
SRP_FMR_POOL_SIZE = 1024,
@@ -113,15 +112,29 @@ struct srp_request {
struct list_head list;
struct scsi_cmnd *scmnd;
struct srp_iu *cmd;
- struct srp_iu *tsk_mgmt;
struct ib_pool_fmr *fmr;
- struct completion done;
short index;
- u8 cmd_done;
- u8 tsk_status;
};
struct srp_target_port {
+ /* These are RW in the hot path, and commonly used together */
+ struct list_head free_tx;
+ struct list_head free_reqs;
+ spinlock_t lock;
+ s32 req_lim;
+
+ /* These are read-only in the hot path */
+ struct ib_cq *send_cq ____cacheline_aligned_in_smp;
+ struct ib_cq *recv_cq;
+ struct ib_qp *qp;
+ u32 lkey;
+ u32 rkey;
+ enum srp_target_state state;
+
+ /* Everything above this point is used in the hot path of
+ * command processing. Try to keep them packed into cachelines.
+ */
+
__be64 id_ext;
__be64 ioc_guid;
__be64 service_id;
@@ -138,24 +151,13 @@ struct srp_target_port {
int path_query_id;
struct ib_cm_id *cm_id;
- struct ib_cq *recv_cq;
- struct ib_cq *send_cq;
- struct ib_qp *qp;
int max_ti_iu_len;
- s32 req_lim;
int zero_req_lim;
- unsigned rx_head;
- struct srp_iu *rx_ring[SRP_RQ_SIZE];
-
- unsigned tx_head;
- unsigned tx_tail;
struct srp_iu *tx_ring[SRP_SQ_SIZE];
-
- struct list_head free_reqs;
- struct list_head req_queue;
+ struct srp_iu *rx_ring[SRP_RQ_SIZE];
struct srp_request req_ring[SRP_CMD_SQ_SIZE];
struct work_struct work;
@@ -163,16 +165,18 @@ struct srp_target_port {
struct list_head list;
struct completion done;
int status;
- enum srp_target_state state;
int qp_in_error;
+
+ struct completion tsk_mgmt_done;
+ u8 tsk_mgmt_status;
};
struct srp_iu {
+ struct list_head list;
u64 dma;
void *buf;
size_t size;
enum dma_data_direction direction;
- enum srp_iu_type type;
};
#endif /* IB_SRP_H */
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 7ad212d31f99..09614ce74961 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -5,7 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o
-input-core-objs := input.o input-compat.o ff-core.o
+input-core-y := input.o input-compat.o input-mt.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c
index 7d61a9660806..e90ee3d30613 100644
--- a/drivers/input/apm-power.c
+++ b/drivers/input/apm-power.c
@@ -9,6 +9,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode)
switch (keycode) {
case KEY_SUSPEND:
apm_queue_event(APM_USER_SUSPEND);
-
- printk(KERN_INFO "apm-power: Requesting system suspend...\n");
+ pr_info("Requesting system suspend...\n");
break;
default:
break;
@@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler,
error = input_register_handle(handle);
if (error) {
- printk(KERN_ERR
- "apm-power: Failed to register input power handler, "
- "error %d\n", error);
+ pr_err("Failed to register input power handler, error %d\n",
+ error);
kfree(handle);
return error;
}
error = input_open_device(handle);
if (error) {
- printk(KERN_ERR
- "apm-power: Failed to open input power device, "
- "error %d\n", error);
+ pr_err("Failed to open input power device, error %d\n", error);
input_unregister_handle(handle);
kfree(handle);
return error;
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index f7c5c14ec12a..cd4e6679d61a 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -38,8 +40,8 @@ MODULE_LICENSE("GPL");
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
- printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
- dev_name(&handle->dev->dev), type, code, value);
+ printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"),
+ dev_name(&handle->dev->dev), type, code, value);
}
static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
@@ -64,10 +66,10 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
if (error)
goto err_unregister_handle;
- printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n",
- dev_name(&dev->dev),
- dev->name ?: "unknown",
- dev->phys ?: "unknown");
+ printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"),
+ dev_name(&dev->dev),
+ dev->name ?: "unknown",
+ dev->phys ?: "unknown");
return 0;
@@ -80,8 +82,8 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
static void evbug_disconnect(struct input_handle *handle)
{
- printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n",
- dev_name(&handle->dev->dev));
+ printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"),
+ dev_name(&handle->dev->dev));
input_close_device(handle);
input_unregister_handle(handle);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index e3f7fc6f9565..c8471a2552e7 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -8,6 +8,8 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
#define EVDEV_MIN_BUFFER_SIZE 64U
@@ -522,88 +524,84 @@ static int handle_eviocgbit(struct input_dev *dev,
if (type == EV_KEY && size == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
- printk(KERN_WARNING
- "evdev.c(EVIOCGBIT): Suspicious buffer size %u, "
- "limiting output to %zu bytes. See "
- "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
- OLD_KEY_MAX,
- BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
+ pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
+ "limiting output to %zu bytes. See "
+ "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
+ OLD_KEY_MAX,
+ BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}
return bits_to_user(bits, len, size, p, compat_mode);
}
#undef OLD_KEY_MAX
-static int evdev_handle_get_keycode(struct input_dev *dev,
- void __user *p, size_t size)
+static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
{
- struct input_keymap_entry ke;
+ struct input_keymap_entry ke = {
+ .len = sizeof(unsigned int),
+ .flags = 0,
+ };
+ int __user *ip = (int __user *)p;
int error;
- memset(&ke, 0, sizeof(ke));
+ /* legacy case */
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
- if (size == sizeof(unsigned int[2])) {
- /* legacy case */
- int __user *ip = (int __user *)p;
-
- if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
- return -EFAULT;
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
- ke.len = sizeof(unsigned int);
- ke.flags = 0;
+ if (put_user(ke.keycode, ip + 1))
+ return -EFAULT;
- error = input_get_keycode(dev, &ke);
- if (error)
- return error;
+ return 0;
+}
- if (put_user(ke.keycode, ip + 1))
- return -EFAULT;
+static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p)
+{
+ struct input_keymap_entry ke;
+ int error;
- } else {
- size = min(size, sizeof(ke));
+ if (copy_from_user(&ke, p, sizeof(ke)))
+ return -EFAULT;
- if (copy_from_user(&ke, p, size))
- return -EFAULT;
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
- error = input_get_keycode(dev, &ke);
- if (error)
- return error;
+ if (copy_to_user(p, &ke, sizeof(ke)))
+ return -EFAULT;
- if (copy_to_user(p, &ke, size))
- return -EFAULT;
- }
return 0;
}
-static int evdev_handle_set_keycode(struct input_dev *dev,
- void __user *p, size_t size)
+static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p)
{
- struct input_keymap_entry ke;
-
- memset(&ke, 0, sizeof(ke));
+ struct input_keymap_entry ke = {
+ .len = sizeof(unsigned int),
+ .flags = 0,
+ };
+ int __user *ip = (int __user *)p;
- if (size == sizeof(unsigned int[2])) {
- /* legacy case */
- int __user *ip = (int __user *)p;
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
- if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
- return -EFAULT;
-
- if (get_user(ke.keycode, ip + 1))
- return -EFAULT;
+ if (get_user(ke.keycode, ip + 1))
+ return -EFAULT;
- ke.len = sizeof(unsigned int);
- ke.flags = 0;
+ return input_set_keycode(dev, &ke);
+}
- } else {
- size = min(size, sizeof(ke));
+static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
+{
+ struct input_keymap_entry ke;
- if (copy_from_user(&ke, p, size))
- return -EFAULT;
+ if (copy_from_user(&ke, p, sizeof(ke)))
+ return -EFAULT;
- if (ke.len > sizeof(ke.scancode))
- return -EINVAL;
- }
+ if (ke.len > sizeof(ke.scancode))
+ return -EINVAL;
return input_set_keycode(dev, &ke);
}
@@ -669,6 +667,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_grab(evdev, client);
else
return evdev_ungrab(evdev, client);
+
+ case EVIOCGKEYCODE:
+ return evdev_handle_get_keycode(dev, p);
+
+ case EVIOCSKEYCODE:
+ return evdev_handle_set_keycode(dev, p);
+
+ case EVIOCGKEYCODE_V2:
+ return evdev_handle_get_keycode_v2(dev, p);
+
+ case EVIOCSKEYCODE_V2:
+ return evdev_handle_set_keycode_v2(dev, p);
}
size = _IOC_SIZE(cmd);
@@ -677,6 +687,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
switch (EVIOC_MASK_SIZE(cmd)) {
+ case EVIOCGPROP(0):
+ return bits_to_user(dev->propbit, INPUT_PROP_MAX,
+ size, p, compat_mode);
+
case EVIOCGKEY(0):
return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
@@ -708,12 +722,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
return error;
-
- case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
- return evdev_handle_get_keycode(dev, p, size);
-
- case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
- return evdev_handle_set_keycode(dev, p, size);
}
/* Multi-number variable-length handlers */
@@ -894,7 +902,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
break;
if (minor == EVDEV_MINORS) {
- printk(KERN_ERR "evdev: no more free evdev devices\n");
+ pr_err("no more free evdev devices\n");
return -ENFILE;
}
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 03078c08309a..3367f760d75a 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -23,7 +23,7 @@
/* #define DEBUG */
-#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg)
+#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/input.h>
#include <linux/module.h>
@@ -116,7 +116,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
!test_bit(effect->type, dev->ffbit)) {
- debug("invalid or not supported effect type in upload");
+ pr_debug("invalid or not supported effect type in upload\n");
return -EINVAL;
}
@@ -124,7 +124,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
(effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
!test_bit(effect->u.periodic.waveform, dev->ffbit))) {
- debug("invalid or not supported wave form in upload");
+ pr_debug("invalid or not supported wave form in upload\n");
return -EINVAL;
}
@@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
struct ff_device *ff = dev->ff;
int i;
- debug("flushing now");
+ pr_debug("flushing now\n");
mutex_lock(&ff->mutex);
@@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
int i;
if (!max_effects) {
- printk(KERN_ERR
- "ff-core: cannot allocate device without any effects\n");
+ pr_err("cannot allocate device without any effects\n");
return -EINVAL;
}
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 1d881c96ba8f..117a59aaa70e 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -23,7 +23,7 @@
/* #define DEBUG */
-#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
#include <linux/input.h>
@@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml)
int events = 0;
int i;
- debug("calculating next timer");
+ pr_debug("calculating next timer\n");
for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
@@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml)
}
if (!events) {
- debug("no actions");
+ pr_debug("no actions\n");
del_timer(&ml->timer);
} else {
- debug("timer set");
+ pr_debug("timer set\n");
mod_timer(&ml->timer, earliest);
}
}
@@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value,
if (envelope->attack_length &&
time_before(now,
state->play_at + msecs_to_jiffies(envelope->attack_length))) {
- debug("value = 0x%x, attack_level = 0x%x", value,
- envelope->attack_level);
+ pr_debug("value = 0x%x, attack_level = 0x%x\n",
+ value, envelope->attack_level);
time_from_level = jiffies_to_msecs(now - state->play_at);
time_of_envelope = envelope->attack_length;
envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
@@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value,
difference = abs(value) - envelope_level;
- debug("difference = %d", difference);
- debug("time_from_level = 0x%x", time_from_level);
- debug("time_of_envelope = 0x%x", time_of_envelope);
+ pr_debug("difference = %d\n", difference);
+ pr_debug("time_from_level = 0x%x\n", time_from_level);
+ pr_debug("time_of_envelope = 0x%x\n", time_of_envelope);
difference = difference * time_from_level / time_of_envelope;
- debug("difference = %d", difference);
+ pr_debug("difference = %d\n", difference);
return value < 0 ?
-(difference + envelope_level) : (difference + envelope_level);
@@ -215,8 +215,7 @@ static int get_compatible_type(struct ff_device *ff, int effect_type)
if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit))
return FF_RUMBLE;
- printk(KERN_ERR
- "ff-memless: invalid type in get_compatible_type()\n");
+ pr_err("invalid type in get_compatible_type()\n");
return 0;
}
@@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect,
break;
default:
- printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n");
+ pr_err("invalid type in ml_combine_effects()\n");
break;
}
@@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data)
struct ml_device *ml = dev->ff->private;
unsigned long flags;
- debug("timer: updating effects");
+ pr_debug("timer: updating effects\n");
spin_lock_irqsave(&dev->event_lock, flags);
ml_play_effects(ml);
@@ -438,7 +437,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
struct ml_effect_state *state = &ml->states[effect_id];
if (value > 0) {
- debug("initiated play");
+ pr_debug("initiated play\n");
__set_bit(FF_EFFECT_STARTED, &state->flags);
state->count = value;
@@ -449,7 +448,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
state->adj_at = state->play_at;
} else {
- debug("initiated stop");
+ pr_debug("initiated stop\n");
if (test_bit(FF_EFFECT_PLAYING, &state->flags))
__set_bit(FF_EFFECT_ABORTING, &state->flags);
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 46239e47a260..23cf8fc933ec 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -18,13 +18,11 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/gameport.h>
-#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
#include <linux/sched.h> /* HZ */
#include <linux/mutex.h>
-#include <linux/freezer.h>
/*#include <asm/io.h>*/
@@ -123,7 +121,7 @@ static int gameport_measure_speed(struct gameport *gameport)
}
gameport_close(gameport);
- return (cpu_data(raw_smp_processor_id()).loops_per_jiffy *
+ return (this_cpu_read(cpu_info.loops_per_jiffy) *
(unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
#else
@@ -234,58 +232,22 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
static LIST_HEAD(gameport_event_list);
-static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static struct task_struct *gameport_task;
-static int gameport_queue_event(void *object, struct module *owner,
- enum gameport_event_type event_type)
+static struct gameport_event *gameport_get_event(void)
{
+ struct gameport_event *event = NULL;
unsigned long flags;
- struct gameport_event *event;
- int retval = 0;
spin_lock_irqsave(&gameport_event_lock, flags);
- /*
- * Scan event list for the other events for the same gameport port,
- * starting with the most recent one. If event is the same we
- * do not need add new one. If event is of different type we
- * need to add this event and should not look further because
- * we need to preseve sequence of distinct events.
- */
- list_for_each_entry_reverse(event, &gameport_event_list, node) {
- if (event->object == object) {
- if (event->type == event_type)
- goto out;
- break;
- }
- }
-
- event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
- if (!event) {
- pr_err("Not enough memory to queue event %d\n", event_type);
- retval = -ENOMEM;
- goto out;
- }
-
- if (!try_module_get(owner)) {
- pr_warning("Can't get module reference, dropping event %d\n",
- event_type);
- kfree(event);
- retval = -EINVAL;
- goto out;
+ if (!list_empty(&gameport_event_list)) {
+ event = list_first_entry(&gameport_event_list,
+ struct gameport_event, node);
+ list_del_init(&event->node);
}
- event->type = event_type;
- event->object = object;
- event->owner = owner;
-
- list_add_tail(&event->node, &gameport_event_list);
- wake_up(&gameport_wait);
-
-out:
spin_unlock_irqrestore(&gameport_event_lock, flags);
- return retval;
+ return event;
}
static void gameport_free_event(struct gameport_event *event)
@@ -319,24 +281,8 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
spin_unlock_irqrestore(&gameport_event_lock, flags);
}
-static struct gameport_event *gameport_get_event(void)
-{
- struct gameport_event *event = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&gameport_event_lock, flags);
-
- if (!list_empty(&gameport_event_list)) {
- event = list_first_entry(&gameport_event_list,
- struct gameport_event, node);
- list_del_init(&event->node);
- }
-
- spin_unlock_irqrestore(&gameport_event_lock, flags);
- return event;
-}
-static void gameport_handle_event(void)
+static void gameport_handle_events(struct work_struct *work)
{
struct gameport_event *event;
@@ -368,6 +314,59 @@ static void gameport_handle_event(void)
mutex_unlock(&gameport_mutex);
}
+static DECLARE_WORK(gameport_event_work, gameport_handle_events);
+
+static int gameport_queue_event(void *object, struct module *owner,
+ enum gameport_event_type event_type)
+{
+ unsigned long flags;
+ struct gameport_event *event;
+ int retval = 0;
+
+ spin_lock_irqsave(&gameport_event_lock, flags);
+
+ /*
+ * Scan event list for the other events for the same gameport port,
+ * starting with the most recent one. If event is the same we
+ * do not need add new one. If event is of different type we
+ * need to add this event and should not look further because
+ * we need to preserve sequence of distinct events.
+ */
+ list_for_each_entry_reverse(event, &gameport_event_list, node) {
+ if (event->object == object) {
+ if (event->type == event_type)
+ goto out;
+ break;
+ }
+ }
+
+ event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
+ if (!event) {
+ pr_err("Not enough memory to queue event %d\n", event_type);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (!try_module_get(owner)) {
+ pr_warning("Can't get module reference, dropping event %d\n",
+ event_type);
+ kfree(event);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ event->type = event_type;
+ event->object = object;
+ event->owner = owner;
+
+ list_add_tail(&event->node, &gameport_event_list);
+ schedule_work(&gameport_event_work);
+
+out:
+ spin_unlock_irqrestore(&gameport_event_lock, flags);
+ return retval;
+}
+
/*
* Remove all events that have been submitted for a given object,
* be it a gameport port or a driver.
@@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
return child;
}
-static int gameport_thread(void *nothing)
-{
- set_freezable();
- do {
- gameport_handle_event();
- wait_event_freezable(gameport_wait,
- kthread_should_stop() || !list_empty(&gameport_event_list));
- } while (!kthread_should_stop());
-
- return 0;
-}
-
-
/*
* Gameport port operations
*/
@@ -814,13 +800,6 @@ static int __init gameport_init(void)
return error;
}
- gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
- if (IS_ERR(gameport_task)) {
- bus_unregister(&gameport_bus);
- error = PTR_ERR(gameport_task);
- pr_err("Failed to start kgameportd, error: %d\n", error);
- return error;
- }
return 0;
}
@@ -828,7 +807,12 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void)
{
bus_unregister(&gameport_bus);
- kthread_stop(gameport_task);
+
+ /*
+ * There should not be any outstanding events but work may
+ * still be scheduled so simply cancel it.
+ */
+ cancel_work_sync(&gameport_event_work);
}
subsys_initcall(gameport_init);
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
new file mode 100644
index 000000000000..c48c81f0308d
--- /dev/null
+++ b/drivers/input/input-mt.c
@@ -0,0 +1,170 @@
+/*
+ * Input Multitouch Library
+ *
+ * Copyright (c) 2008-2010 Henrik Rydberg
+ *
+ * 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/input/mt.h>
+#include <linux/slab.h>
+
+#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
+
+/**
+ * input_mt_init_slots() - initialize MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, prepares the ABS_MT_SLOT and
+ * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
+ * May be called repeatedly. Returns -EINVAL if attempting to
+ * reinitialize with a different number of slots.
+ */
+int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
+{
+ int i;
+
+ if (!num_slots)
+ return 0;
+ if (dev->mt)
+ return dev->mtsize != num_slots ? -EINVAL : 0;
+
+ dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+ if (!dev->mt)
+ return -ENOMEM;
+
+ dev->mtsize = num_slots;
+ input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
+ input_set_events_per_packet(dev, 6 * num_slots);
+
+ /* Mark slots as 'unused' */
+ for (i = 0; i < num_slots; i++)
+ input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
+
+ return 0;
+}
+EXPORT_SYMBOL(input_mt_init_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+ kfree(dev->mt);
+ dev->mt = NULL;
+ dev->mtsize = 0;
+ dev->slot = 0;
+ dev->trkid = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
+ * input_mt_report_slot_state() - report contact state
+ * @dev: input device with allocated MT slots
+ * @tool_type: the tool type to use in this slot
+ * @active: true if contact is active, false otherwise
+ *
+ * Reports a contact via ABS_MT_TRACKING_ID, and optionally
+ * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
+ * inactive, or if the tool type is changed, a new tracking id is
+ * assigned to the slot. The tool type is only reported if the
+ * corresponding absbit field is set.
+ */
+void input_mt_report_slot_state(struct input_dev *dev,
+ unsigned int tool_type, bool active)
+{
+ struct input_mt_slot *mt;
+ int id;
+
+ if (!dev->mt || !active) {
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ return;
+ }
+
+ mt = &dev->mt[dev->slot];
+ id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
+ if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
+ id = input_mt_new_trkid(dev);
+
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
+ input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
+}
+EXPORT_SYMBOL(input_mt_report_slot_state);
+
+/**
+ * input_mt_report_finger_count() - report contact count
+ * @dev: input device with allocated MT slots
+ * @count: the number of contacts
+ *
+ * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
+ * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
+ *
+ * The input core ensures only the KEY events already setup for
+ * this device will produce output.
+ */
+void input_mt_report_finger_count(struct input_dev *dev, int count)
+{
+ input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
+ input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
+ input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
+ input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
+}
+EXPORT_SYMBOL(input_mt_report_finger_count);
+
+/**
+ * input_mt_report_pointer_emulation() - common pointer emulation
+ * @dev: input device with allocated MT slots
+ * @use_count: report number of active contacts as finger count
+ *
+ * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
+ * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
+ *
+ * The input core ensures only the KEY and ABS axes already setup for
+ * this device will produce output.
+ */
+void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
+{
+ struct input_mt_slot *oldest = 0;
+ int oldid = dev->trkid;
+ int count = 0;
+ int i;
+
+ for (i = 0; i < dev->mtsize; ++i) {
+ struct input_mt_slot *ps = &dev->mt[i];
+ int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+
+ if (id < 0)
+ continue;
+ if ((id - oldid) & TRKID_SGN) {
+ oldest = ps;
+ oldid = id;
+ }
+ count++;
+ }
+
+ input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
+ if (use_count)
+ input_mt_report_finger_count(dev, count);
+
+ if (oldest) {
+ int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
+ int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
+ int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
+
+ input_event(dev, EV_ABS, ABS_X, x);
+ input_event(dev, EV_ABS, ABS_Y, y);
+ input_event(dev, EV_ABS, ABS_PRESSURE, p);
+ } else {
+ input_event(dev, EV_ABS, ABS_PRESSURE, 0);
+ }
+}
+EXPORT_SYMBOL(input_mt_report_pointer_emulation);
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 10c9b0a845f0..0559e309bac9 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -8,6 +8,8 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -33,8 +35,7 @@ static int input_polldev_start_workqueue(void)
if (!polldev_users) {
polldev_wq = create_singlethread_workqueue("ipolldevd");
if (!polldev_wq) {
- printk(KERN_ERR "input-polldev: failed to create "
- "ipolldevd workqueue\n");
+ pr_err("failed to create ipolldevd workqueue\n");
retval = -ENOMEM;
goto out;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index d092ef9291da..7985114beac7 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -10,9 +10,11 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
+
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
@@ -24,7 +26,6 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/rcupdate.h>
-#include <linux/smp_lock.h>
#include "input-compat.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -74,6 +75,7 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
+ struct input_handler *src_handler,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
@@ -92,6 +94,15 @@ static void input_pass_event(struct input_dev *dev,
continue;
handler = handle->handler;
+
+ /*
+ * If this is the handler that injected this
+ * particular event we want to skip it to avoid
+ * filters firing again and again.
+ */
+ if (handler == src_handler)
+ continue;
+
if (!handler->filter) {
if (filtered)
break;
@@ -121,7 +132,7 @@ static void input_repeat_key(unsigned long data)
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
- input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+ input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
if (dev->sync) {
/*
@@ -130,7 +141,7 @@ static void input_repeat_key(unsigned long data)
* Otherwise assume that the driver will send
* SYN_REPORT once it's done.
*/
- input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
}
if (dev->rep[REP_PERIOD])
@@ -163,6 +174,7 @@ static void input_stop_autorepeat(struct input_dev *dev)
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
static int input_handle_abs_event(struct input_dev *dev,
+ struct input_handler *src_handler,
unsigned int code, int *pval)
{
bool is_mt_event;
@@ -206,13 +218,15 @@ static int input_handle_abs_event(struct input_dev *dev,
/* Flush pending "slot" event */
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
- input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+ input_pass_event(dev, src_handler,
+ EV_ABS, ABS_MT_SLOT, dev->slot);
}
return INPUT_PASS_TO_HANDLERS;
}
static void input_handle_event(struct input_dev *dev,
+ struct input_handler *src_handler,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
@@ -265,7 +279,8 @@ static void input_handle_event(struct input_dev *dev,
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
- disposition = input_handle_abs_event(dev, code, &value);
+ disposition = input_handle_abs_event(dev, src_handler,
+ code, &value);
break;
@@ -323,7 +338,7 @@ static void input_handle_event(struct input_dev *dev,
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)
- input_pass_event(dev, type, code, value);
+ input_pass_event(dev, src_handler, type, code, value);
}
/**
@@ -352,7 +367,7 @@ void input_event(struct input_dev *dev,
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);
- input_handle_event(dev, type, code, value);
+ input_handle_event(dev, NULL, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
@@ -382,7 +397,8 @@ void input_inject_event(struct input_handle *handle,
rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
- input_handle_event(dev, type, code, value);
+ input_handle_event(dev, handle->handler,
+ type, code, value);
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -595,10 +611,10 @@ static void input_dev_release_keys(struct input_dev *dev)
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(code, dev->key)) {
- input_pass_event(dev, EV_KEY, code, 0);
+ input_pass_event(dev, NULL, EV_KEY, code, 0);
}
}
- input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
}
}
@@ -738,7 +754,7 @@ static int input_default_setkeycode(struct input_dev *dev,
if (index >= dev->keycodemax)
return -EINVAL;
- if (dev->keycodesize < sizeof(dev->keycode) &&
+ if (dev->keycodesize < sizeof(ke->keycode) &&
(ke->keycode >> (dev->keycodesize * 8)))
return -EINVAL;
@@ -873,9 +889,9 @@ int input_set_keycode(struct input_dev *dev,
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) {
- input_pass_event(dev, EV_KEY, old_keycode, 0);
+ input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
if (dev->sync)
- input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
}
out:
@@ -944,10 +960,8 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
- printk(KERN_ERR
- "input: failed to attach handler %s to device %s, "
- "error: %d\n",
- handler->name, kobject_name(&dev->dev.kobj), error);
+ pr_err("failed to attach handler %s to device %s, error: %d\n",
+ handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
@@ -1095,6 +1109,8 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s ", handle->name);
seq_putc(seq, '\n');
+ input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX);
+
input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
@@ -1318,11 +1334,26 @@ static ssize_t input_dev_show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
+static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
+ int max, int add_cr);
+
+static ssize_t input_dev_show_properties(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ int len = input_print_bitmap(buf, PAGE_SIZE, input_dev->propbit,
+ INPUT_PROP_MAX, true);
+ return min_t(int, len, PAGE_SIZE);
+}
+static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);
+
static struct attribute *input_dev_attrs[] = {
&dev_attr_name.attr,
&dev_attr_phys.attr,
&dev_attr_uniq.attr,
&dev_attr_modalias.attr,
+ &dev_attr_properties.attr,
NULL
};
@@ -1456,7 +1487,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
{
int len;
- if (add_uevent_var(env, "%s=", name))
+ if (add_uevent_var(env, "%s", name))
return -ENOMEM;
len = input_print_bitmap(&env->buf[env->buflen - 1],
@@ -1522,6 +1553,8 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
if (dev->uniq)
INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
+ INPUT_ADD_HOTPLUG_BM_VAR("PROP=", dev->propbit, INPUT_PROP_MAX);
+
INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX);
@@ -1565,8 +1598,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
} \
} while (0)
-#ifdef CONFIG_PM
-static void input_dev_reset(struct input_dev *dev, bool activate)
+static void input_dev_toggle(struct input_dev *dev, bool activate)
{
if (!dev->event)
return;
@@ -1580,12 +1612,44 @@ static void input_dev_reset(struct input_dev *dev, bool activate)
}
}
+/**
+ * input_reset_device() - reset/restore the state of input device
+ * @dev: input device whose state needs to be reset
+ *
+ * This function tries to reset the state of an opened input device and
+ * bring internal state and state if the hardware in sync with each other.
+ * We mark all keys as released, restore LED state, repeat rate, etc.
+ */
+void input_reset_device(struct input_dev *dev)
+{
+ mutex_lock(&dev->mutex);
+
+ if (dev->users) {
+ input_dev_toggle(dev, true);
+
+ /*
+ * Keys that have been pressed at suspend time are unlikely
+ * to be still pressed when we resume.
+ */
+ spin_lock_irq(&dev->event_lock);
+ input_dev_release_keys(dev);
+ spin_unlock_irq(&dev->event_lock);
+ }
+
+ mutex_unlock(&dev->mutex);
+}
+EXPORT_SYMBOL(input_reset_device);
+
+#ifdef CONFIG_PM
static int input_dev_suspend(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
mutex_lock(&input_dev->mutex);
- input_dev_reset(input_dev, false);
+
+ if (input_dev->users)
+ input_dev_toggle(input_dev, false);
+
mutex_unlock(&input_dev->mutex);
return 0;
@@ -1595,18 +1659,7 @@ static int input_dev_resume(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- mutex_lock(&input_dev->mutex);
- input_dev_reset(input_dev, true);
-
- /*
- * Keys that have been pressed at suspend time are unlikely
- * to be still pressed when we resume.
- */
- spin_lock_irq(&input_dev->event_lock);
- input_dev_release_keys(input_dev);
- spin_unlock_irq(&input_dev->event_lock);
-
- mutex_unlock(&input_dev->mutex);
+ input_reset_device(input_dev);
return 0;
}
@@ -1691,52 +1744,6 @@ void input_free_device(struct input_dev *dev)
EXPORT_SYMBOL(input_free_device);
/**
- * input_mt_create_slots() - create MT input slots
- * @dev: input device supporting MT events and finger tracking
- * @num_slots: number of slots used by the device
- *
- * This function allocates all necessary memory for MT slot handling in the
- * input device, and adds ABS_MT_SLOT to the device capabilities. All slots
- * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
- */
-int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
-{
- int i;
-
- if (!num_slots)
- return 0;
-
- dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
- if (!dev->mt)
- return -ENOMEM;
-
- dev->mtsize = num_slots;
- input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
-
- /* Mark slots as 'unused' */
- for (i = 0; i < num_slots; i++)
- dev->mt[i].abs[ABS_MT_TRACKING_ID - ABS_MT_FIRST] = -1;
-
- return 0;
-}
-EXPORT_SYMBOL(input_mt_create_slots);
-
-/**
- * input_mt_destroy_slots() - frees the MT slots of the input device
- * @dev: input device with allocated MT slots
- *
- * This function is only needed in error path as the input core will
- * automatically free the MT slots when the device is destroyed.
- */
-void input_mt_destroy_slots(struct input_dev *dev)
-{
- kfree(dev->mt);
- dev->mt = NULL;
- dev->mtsize = 0;
-}
-EXPORT_SYMBOL(input_mt_destroy_slots);
-
-/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
@@ -1785,9 +1792,8 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
break;
default:
- printk(KERN_ERR
- "input_set_capability: unknown type %u (code %u)\n",
- type, code);
+ pr_err("input_set_capability: unknown type %u (code %u)\n",
+ type, code);
dump_stack();
return;
}
@@ -1869,8 +1875,9 @@ int input_register_device(struct input_dev *dev)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "input: %s as %s\n",
- dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
+ pr_info("%s as %s\n",
+ dev->name ? dev->name : "Unspecified device",
+ path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
@@ -2152,7 +2159,7 @@ static int __init input_init(void)
err = class_register(&input_class);
if (err) {
- printk(KERN_ERR "input: unable to register input_dev class\n");
+ pr_err("unable to register input_dev class\n");
return err;
}
@@ -2162,7 +2169,7 @@ static int __init input_init(void)
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
if (err) {
- printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+ pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2;
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 9d424cebfd2c..3182c9cd1b0e 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -10,6 +10,8 @@
* (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
@@ -806,7 +808,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
break;
if (minor == JOYDEV_MINORS) {
- printk(KERN_ERR "joydev: no more free joydev devices\n");
+ pr_err("no more free joydev devices\n");
return -ENFILE;
}
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 5b596165b571..56eb471b5576 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -255,6 +255,16 @@ config JOYSTICK_AMIGA
To compile this driver as a module, choose M here: the
module will be called amijoy.
+config JOYSTICK_AS5011
+ tristate "Austria Microsystem AS5011 joystick"
+ depends on I2C
+ help
+ Say Y here if you have an AS5011 digital joystick connected to your
+ system.
+
+ To compile this driver as a module, choose M here: the
+ module will be called as5011.
+
config JOYSTICK_JOYDUMP
tristate "Gameport data dumper"
select GAMEPORT
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index f3a8cbe2abb6..92dc0de9dfed 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
obj-$(CONFIG_JOYSTICK_ADI) += adi.o
obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
+obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o
obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
obj-$(CONFIG_JOYSTICK_DB9) += db9.o
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
new file mode 100644
index 000000000000..f6732b57ca07
--- /dev/null
+++ b/drivers/input/joystick/as5011.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
+ * Sponsored by ARMadeus Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Driver for Austria Microsystems joysticks AS5011
+ *
+ * TODO:
+ * - Power on the chip when open() and power down when close()
+ * - Manage power mode
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/input/as5011.h>
+#include <linux/slab.h>
+
+#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick"
+#define MODULE_DEVICE_ALIAS "as5011"
+
+MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* registers */
+#define AS5011_CTRL1 0x76
+#define AS5011_CTRL2 0x75
+#define AS5011_XP 0x43
+#define AS5011_XN 0x44
+#define AS5011_YP 0x53
+#define AS5011_YN 0x54
+#define AS5011_X_REG 0x41
+#define AS5011_Y_REG 0x42
+#define AS5011_X_RES_INT 0x51
+#define AS5011_Y_RES_INT 0x52
+
+/* CTRL1 bits */
+#define AS5011_CTRL1_LP_PULSED 0x80
+#define AS5011_CTRL1_LP_ACTIVE 0x40
+#define AS5011_CTRL1_LP_CONTINUE 0x20
+#define AS5011_CTRL1_INT_WUP_EN 0x10
+#define AS5011_CTRL1_INT_ACT_EN 0x08
+#define AS5011_CTRL1_EXT_CLK_EN 0x04
+#define AS5011_CTRL1_SOFT_RST 0x02
+#define AS5011_CTRL1_DATA_VALID 0x01
+
+/* CTRL2 bits */
+#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08
+#define AS5011_CTRL2_RC_BIAS_ON 0x04
+#define AS5011_CTRL2_INV_SPINNING 0x02
+
+#define AS5011_MAX_AXIS 80
+#define AS5011_MIN_AXIS (-80)
+#define AS5011_FUZZ 8
+#define AS5011_FLAT 40
+
+struct as5011_device {
+ struct input_dev *input_dev;
+ struct i2c_client *i2c_client;
+ unsigned int button_gpio;
+ unsigned int button_irq;
+ unsigned int axis_irq;
+};
+
+static int as5011_i2c_write(struct i2c_client *client,
+ uint8_t aregaddr,
+ uint8_t avalue)
+{
+ uint8_t data[2] = { aregaddr, avalue };
+ struct i2c_msg msg = {
+ client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data
+ };
+ int error;
+
+ error = i2c_transfer(client->adapter, &msg, 1);
+ return error < 0 ? error : 0;
+}
+
+static int as5011_i2c_read(struct i2c_client *client,
+ uint8_t aregaddr, signed char *value)
+{
+ uint8_t data[2] = { aregaddr };
+ struct i2c_msg msg_set[2] = {
+ { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data },
+ { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data }
+ };
+ int error;
+
+ error = i2c_transfer(client->adapter, msg_set, 2);
+ if (error < 0)
+ return error;
+
+ *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0];
+ return 0;
+}
+
+static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
+{
+ struct as5011_device *as5011 = dev_id;
+ int val = gpio_get_value_cansleep(as5011->button_gpio);
+
+ input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
+ input_sync(as5011->input_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id)
+{
+ struct as5011_device *as5011 = dev_id;
+ int error;
+ signed char x, y;
+
+ error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x);
+ if (error < 0)
+ goto out;
+
+ error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y);
+ if (error < 0)
+ goto out;
+
+ input_report_abs(as5011->input_dev, ABS_X, x);
+ input_report_abs(as5011->input_dev, ABS_Y, y);
+ input_sync(as5011->input_dev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int __devinit as5011_configure_chip(struct as5011_device *as5011,
+ const struct as5011_platform_data *plat_dat)
+{
+ struct i2c_client *client = as5011->i2c_client;
+ int error;
+ signed char value;
+
+ /* chip soft reset */
+ error = as5011_i2c_write(client, AS5011_CTRL1,
+ AS5011_CTRL1_SOFT_RST);
+ if (error < 0) {
+ dev_err(&client->dev, "Soft reset failed\n");
+ return error;
+ }
+
+ mdelay(10);
+
+ error = as5011_i2c_write(client, AS5011_CTRL1,
+ AS5011_CTRL1_LP_PULSED |
+ AS5011_CTRL1_LP_ACTIVE |
+ AS5011_CTRL1_INT_ACT_EN);
+ if (error < 0) {
+ dev_err(&client->dev, "Power config failed\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_CTRL2,
+ AS5011_CTRL2_INV_SPINNING);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't invert spinning\n");
+ return error;
+ }
+
+ /* write threshold */
+ error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't write threshold\n");
+ return error;
+ }
+
+ /* to free irq gpio in chip */
+ error = as5011_i2c_read(client, AS5011_X_RES_INT, &value);
+ if (error < 0) {
+ dev_err(&client->dev, "Can't read i2c X resolution value\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int __devinit as5011_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct as5011_platform_data *plat_data;
+ struct as5011_device *as5011;
+ struct input_dev *input_dev;
+ int irq;
+ int error;
+
+ plat_data = client->dev.platform_data;
+ if (!plat_data)
+ return -EINVAL;
+
+ if (!plat_data->axis_irq) {
+ dev_err(&client->dev, "No axis IRQ?\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_PROTOCOL_MANGLING)) {
+ dev_err(&client->dev,
+ "need i2c bus that supports protocol mangling\n");
+ return -ENODEV;
+ }
+
+ as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!as5011 || !input_dev) {
+ dev_err(&client->dev,
+ "Can't allocate memory for device structure\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ as5011->i2c_client = client;
+ as5011->input_dev = input_dev;
+ as5011->button_gpio = plat_data->button_gpio;
+ as5011->axis_irq = plat_data->axis_irq;
+
+ input_dev->name = "Austria Microsystem as5011 joystick";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_JOYSTICK, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_X,
+ AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
+ input_set_abs_params(as5011->input_dev, ABS_Y,
+ AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
+
+ error = gpio_request(as5011->button_gpio, "AS5011 button");
+ if (error < 0) {
+ dev_err(&client->dev, "Failed to request button gpio\n");
+ goto err_free_mem;
+ }
+
+ irq = gpio_to_irq(as5011->button_gpio);
+ if (irq < 0) {
+ dev_err(&client->dev,
+ "Failed to get irq number for button gpio\n");
+ goto err_free_button_gpio;
+ }
+
+ as5011->button_irq = irq;
+
+ error = request_threaded_irq(as5011->button_irq,
+ NULL, as5011_button_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "as5011_button", as5011);
+ if (error < 0) {
+ dev_err(&client->dev,
+ "Can't allocate button irq %d\n", as5011->button_irq);
+ goto err_free_button_gpio;
+ }
+
+ error = as5011_configure_chip(as5011, plat_data);
+ if (error)
+ goto err_free_button_irq;
+
+ error = request_threaded_irq(as5011->axis_irq, NULL,
+ as5011_axis_interrupt,
+ plat_data->axis_irqflags,
+ "as5011_joystick", as5011);
+ if (error) {
+ dev_err(&client->dev,
+ "Can't allocate axis irq %d\n", plat_data->axis_irq);
+ goto err_free_button_irq;
+ }
+
+ error = input_register_device(as5011->input_dev);
+ if (error) {
+ dev_err(&client->dev, "Failed to register input device\n");
+ goto err_free_axis_irq;
+ }
+
+ i2c_set_clientdata(client, as5011);
+
+ return 0;
+
+err_free_axis_irq:
+ free_irq(as5011->axis_irq, as5011);
+err_free_button_irq:
+ free_irq(as5011->button_irq, as5011);
+err_free_button_gpio:
+ gpio_free(as5011->button_gpio);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(as5011);
+
+ return error;
+}
+
+static int __devexit as5011_remove(struct i2c_client *client)
+{
+ struct as5011_device *as5011 = i2c_get_clientdata(client);
+
+ free_irq(as5011->axis_irq, as5011);
+ free_irq(as5011->button_irq, as5011);
+ gpio_free(as5011->button_gpio);
+
+ input_unregister_device(as5011->input_dev);
+ kfree(as5011);
+
+ return 0;
+}
+
+static const struct i2c_device_id as5011_id[] = {
+ { MODULE_DEVICE_ALIAS, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, as5011_id);
+
+static struct i2c_driver as5011_driver = {
+ .driver = {
+ .name = "as5011",
+ },
+ .probe = as5011_probe,
+ .remove = __devexit_p(as5011_remove),
+ .id_table = as5011_id,
+};
+
+static int __init as5011_init(void)
+{
+ return i2c_add_driver(&as5011_driver);
+}
+module_init(as5011_init);
+
+static void __exit as5011_exit(void)
+{
+ i2c_del_driver(&as5011_driver);
+}
+module_exit(as5011_exit);
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
index 74daff49ab6e..bc5bda22f15e 100644
--- a/drivers/input/joystick/iforce/Makefile
+++ b/drivers/input/joystick/iforce/Makefile
@@ -4,17 +4,8 @@
# By Johann Deneux <johann.deneux@gmail.com>
#
-# Goal definition
-iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o
-
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
-ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
- iforce-objs += iforce-serio.o
-endif
-
-ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
- iforce-objs += iforce-usb.o
-endif
-
-EXTRA_CFLAGS = -Werror-implicit-function-declaration
+iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
+iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
+iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index d53b9e900234..27b6a3ce18ca 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -245,6 +245,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
goto err_free_tgfx;
}
+ parport_put_port(pp);
return tgfx;
err_free_dev:
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index f9fb7fa10af3..56abf3d0e911 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -543,21 +543,25 @@ exit:
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
{
struct usb_endpoint_descriptor *ep_irq_out;
- int error = -ENOMEM;
+ int error;
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
return 0;
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma);
- if (!xpad->odata)
+ if (!xpad->odata) {
+ error = -ENOMEM;
goto fail1;
+ }
mutex_init(&xpad->odata_mutex);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
- if (!xpad->irq_out)
+ if (!xpad->irq_out) {
+ error = -ENOMEM;
goto fail2;
+ }
ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
usb_fill_int_urb(xpad->irq_out, xpad->udev,
@@ -728,7 +732,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
if (xpad_led) {
led_classdev_unregister(&xpad_led->led_cdev);
- kfree(xpad_led->name);
+ kfree(xpad_led);
}
}
#else
@@ -756,8 +760,9 @@ static void xpad_close(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
- if(xpad->xtype != XTYPE_XBOX360W)
+ if (xpad->xtype != XTYPE_XBOX360W)
usb_kill_urb(xpad->irq_in);
+
xpad_stop_output(xpad);
}
@@ -789,8 +794,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_xpad *xpad;
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
- int i;
- int error = -ENOMEM;
+ int i, error;
for (i = 0; xpad_device[i].idVendor; i++) {
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
@@ -800,17 +804,23 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!xpad || !input_dev)
+ if (!xpad || !input_dev) {
+ error = -ENOMEM;
goto fail1;
+ }
xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->idata_dma);
- if (!xpad->idata)
+ if (!xpad->idata) {
+ error = -ENOMEM;
goto fail1;
+ }
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
- if (!xpad->irq_in)
+ if (!xpad->irq_in) {
+ error = -ENOMEM;
goto fail2;
+ }
xpad->udev = udev;
xpad->mapping = xpad_device[i].mapping;
@@ -887,15 +897,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = xpad_init_output(intf, xpad);
if (error)
- goto fail2;
+ goto fail3;
error = xpad_init_ff(xpad);
if (error)
- goto fail3;
+ goto fail4;
error = xpad_led_probe(xpad);
if (error)
- goto fail3;
+ goto fail5;
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev,
@@ -907,34 +917,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = input_register_device(xpad->dev);
if (error)
- goto fail4;
+ goto fail6;
usb_set_intfdata(intf, xpad);
- /*
- * Submit the int URB immediatly rather than waiting for open
- * because we get status messages from the device whether
- * or not any controllers are attached. In fact, it's
- * exactly the message that a controller has arrived that
- * we're waiting for.
- */
if (xpad->xtype == XTYPE_XBOX360W) {
- xpad->irq_in->dev = xpad->udev;
- error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
- if (error)
- goto fail4;
-
/*
* Setup the message to set the LEDs on the
* controller when it shows up
*/
xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
- if(!xpad->bulk_out)
- goto fail5;
+ if (!xpad->bulk_out) {
+ error = -ENOMEM;
+ goto fail7;
+ }
xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
- if(!xpad->bdata)
- goto fail6;
+ if (!xpad->bdata) {
+ error = -ENOMEM;
+ goto fail8;
+ }
xpad->bdata[2] = 0x08;
switch (intf->cur_altsetting->desc.bInterfaceNumber) {
@@ -955,14 +957,31 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
usb_fill_bulk_urb(xpad->bulk_out, udev,
usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
+
+ /*
+ * Submit the int URB immediately rather than waiting for open
+ * because we get status messages from the device whether
+ * or not any controllers are attached. In fact, it's
+ * exactly the message that a controller has arrived that
+ * we're waiting for.
+ */
+ xpad->irq_in->dev = xpad->udev;
+ error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+ if (error)
+ goto fail9;
}
return 0;
- fail6: usb_free_urb(xpad->bulk_out);
- fail5: usb_kill_urb(xpad->irq_in);
- fail4: usb_free_urb(xpad->irq_in);
- fail3: xpad_deinit_output(xpad);
+ fail9: kfree(xpad->bdata);
+ fail8: usb_free_urb(xpad->bulk_out);
+ fail7: input_unregister_device(input_dev);
+ input_dev = NULL;
+ fail6: xpad_led_disconnect(xpad);
+ fail5: if (input_dev)
+ input_ff_destroy(input_dev);
+ fail4: xpad_deinit_output(xpad);
+ fail3: usb_free_urb(xpad->irq_in);
fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
fail1: input_free_device(input_dev);
kfree(xpad);
@@ -974,21 +993,24 @@ static void xpad_disconnect(struct usb_interface *intf)
{
struct usb_xpad *xpad = usb_get_intfdata (intf);
- usb_set_intfdata(intf, NULL);
- if (xpad) {
- xpad_led_disconnect(xpad);
- input_unregister_device(xpad->dev);
- xpad_deinit_output(xpad);
- if (xpad->xtype == XTYPE_XBOX360W) {
- usb_kill_urb(xpad->bulk_out);
- usb_free_urb(xpad->bulk_out);
- usb_kill_urb(xpad->irq_in);
- }
- usb_free_urb(xpad->irq_in);
- usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
- xpad->idata, xpad->idata_dma);
- kfree(xpad);
+ xpad_led_disconnect(xpad);
+ input_unregister_device(xpad->dev);
+ xpad_deinit_output(xpad);
+
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ usb_kill_urb(xpad->bulk_out);
+ usb_free_urb(xpad->bulk_out);
+ usb_kill_urb(xpad->irq_in);
}
+
+ usb_free_urb(xpad->irq_in);
+ usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
+ xpad->idata, xpad->idata_dma);
+
+ kfree(xpad->bdata);
+ kfree(xpad);
+
+ usb_set_intfdata(intf, NULL);
}
static struct usb_driver xpad_driver = {
@@ -1000,10 +1022,7 @@ static struct usb_driver xpad_driver = {
static int __init usb_xpad_init(void)
{
- int result = usb_register(&xpad_driver);
- if (result == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
- return result;
+ return usb_register(&xpad_driver);
}
static void __exit usb_xpad_exit(void)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index b8c51b9781db..7b3c0b8fa432 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -12,18 +12,6 @@ menuconfig INPUT_KEYBOARD
if INPUT_KEYBOARD
-config KEYBOARD_AAED2000
- tristate "AAED-2000 keyboard"
- depends on MACH_AAED2000
- select INPUT_POLLDEV
- default y
- help
- Say Y here to enable the keyboard on the Agilent AAED-2000
- development board.
-
- To compile this driver as a module, choose M here: the
- module will be called aaed2000_kbd.
-
config KEYBOARD_ADP5520
tristate "Keypad Support for ADP5520 PMIC"
depends on PMIC_ADP5520
@@ -179,21 +167,39 @@ config KEYBOARD_GPIO
To compile this driver as a module, choose M here: the
module will be called gpio_keys.
+config KEYBOARD_GPIO_POLLED
+ tristate "Polled GPIO buttons"
+ depends on GENERIC_GPIO
+ select INPUT_POLLDEV
+ help
+ This driver implements support for buttons connected
+ to GPIO pins that are not capable of generating interrupts.
+
+ Say Y here if your device has buttons connected
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio_keys_polled.
+
config KEYBOARD_TCA6416
- tristate "TCA6416 Keypad Support"
+ tristate "TCA6416/TCA6408A Keypad Support"
depends on I2C
help
This driver implements basic keypad functionality
- for keys connected through TCA6416 IO expander
+ for keys connected through TCA6416/TCA6408A IO expanders.
Say Y here if your device has keys connected to
- TCA6416 IO expander. Your board-specific setup logic
+ TCA6416/TCA6408A IO expander. Your board-specific setup logic
must also provide pin-mask details(of which TCA6416 pins
are used for keypad).
- If enabled the complete TCA6416 device will be managed through
+ If enabled the entire TCA6416 device will be managed through
this driver.
+ To compile this driver as a module, choose M here: the
+ module will be called tca6416_keypad.
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
@@ -443,6 +449,25 @@ config KEYBOARD_OMAP4
To compile this driver as a module, choose M here: the
module will be called omap4-keypad.
+config KEYBOARD_SPEAR
+ tristate "ST SPEAR keyboard support"
+ depends on PLAT_SPEAR
+ help
+ Say Y here if you want to use the SPEAR keyboard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called spear-keboard.
+
+config KEYBOARD_TC3589X
+ tristate "TC3589X Keypad support"
+ depends on MFD_TC3589X
+ help
+ Say Y here if you want to use the keypad controller on
+ TC35892/3 I/O expander.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tc3589x-keypad.
+
config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index a34452e8ebe2..4e5571b72cda 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -4,7 +4,6 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
@@ -14,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
+obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
@@ -37,9 +37,11 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
+obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
deleted file mode 100644
index 18222a689a03..000000000000
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Keyboard driver for the AAED-2000 dev board
- *
- * Copyright (c) 2006 Nicolas Bellido Y Ortega
- *
- * Based on corgikbd.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/input-polldev.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <mach/hardware.h>
-#include <mach/aaed2000.h>
-
-#define KB_ROWS 12
-#define KB_COLS 8
-#define KB_ROWMASK(r) (1 << (r))
-#define SCANCODE(r,c) (((c) * KB_ROWS) + (r))
-#define NR_SCANCODES (KB_COLS * KB_ROWS)
-
-#define SCAN_INTERVAL (50) /* ms */
-#define KB_ACTIVATE_DELAY (20) /* us */
-
-static unsigned char aaedkbd_keycode[NR_SCANCODES] = {
- KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0,
- KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0,
- KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0,
- KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0,
- KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK,
- KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB,
- KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE,
- 0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL
-};
-
-struct aaedkbd {
- unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
- struct input_polled_dev *poll_dev;
- int kbdscan_state[KB_COLS];
- int kbdscan_count[KB_COLS];
-};
-
-#define KBDSCAN_STABLE_COUNT 2
-
-static void aaedkbd_report_col(struct aaedkbd *aaedkbd,
- unsigned int col, unsigned int rowd)
-{
- unsigned int scancode, pressed;
- unsigned int row;
-
- for (row = 0; row < KB_ROWS; row++) {
- scancode = SCANCODE(row, col);
- pressed = rowd & KB_ROWMASK(row);
-
- input_report_key(aaedkbd->poll_dev->input,
- aaedkbd->keycode[scancode], pressed);
- }
-}
-
-/* Scan the hardware keyboard and push any changes up through the input layer */
-static void aaedkbd_poll(struct input_polled_dev *dev)
-{
- struct aaedkbd *aaedkbd = dev->private;
- unsigned int col, rowd;
-
- col = 0;
- do {
- AAEC_GPIO_KSCAN = col + 8;
- udelay(KB_ACTIVATE_DELAY);
- rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN;
-
- if (rowd != aaedkbd->kbdscan_state[col]) {
- aaedkbd->kbdscan_count[col] = 0;
- aaedkbd->kbdscan_state[col] = rowd;
- } else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) {
- aaedkbd_report_col(aaedkbd, col, rowd);
- col++;
- }
- } while (col < KB_COLS);
-
- AAEC_GPIO_KSCAN = 0x07;
- input_sync(dev->input);
-}
-
-static int __devinit aaedkbd_probe(struct platform_device *pdev)
-{
- struct aaedkbd *aaedkbd;
- struct input_polled_dev *poll_dev;
- struct input_dev *input_dev;
- int i;
- int error;
-
- aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
- poll_dev = input_allocate_polled_device();
- if (!aaedkbd || !poll_dev) {
- error = -ENOMEM;
- goto fail;
- }
-
- platform_set_drvdata(pdev, aaedkbd);
-
- aaedkbd->poll_dev = poll_dev;
- memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
-
- poll_dev->private = aaedkbd;
- poll_dev->poll = aaedkbd_poll;
- poll_dev->poll_interval = SCAN_INTERVAL;
-
- input_dev = poll_dev->input;
- input_dev->name = "AAED-2000 Keyboard";
- input_dev->phys = "aaedkbd/input0";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &pdev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- input_dev->keycode = aaedkbd->keycode;
- input_dev->keycodesize = sizeof(unsigned char);
- input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode);
-
- for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++)
- set_bit(aaedkbd->keycode[i], input_dev->keybit);
- clear_bit(0, input_dev->keybit);
-
- error = input_register_polled_device(aaedkbd->poll_dev);
- if (error)
- goto fail;
-
- return 0;
-
- fail: kfree(aaedkbd);
- input_free_polled_device(poll_dev);
- return error;
-}
-
-static int __devexit aaedkbd_remove(struct platform_device *pdev)
-{
- struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
-
- input_unregister_polled_device(aaedkbd->poll_dev);
- input_free_polled_device(aaedkbd->poll_dev);
- kfree(aaedkbd);
-
- return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:aaed2000-keyboard");
-
-static struct platform_driver aaedkbd_driver = {
- .probe = aaedkbd_probe,
- .remove = __devexit_p(aaedkbd_remove),
- .driver = {
- .name = "aaed2000-keyboard",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init aaedkbd_init(void)
-{
- return platform_driver_register(&aaedkbd_driver);
-}
-
-static void __exit aaedkbd_exit(void)
-{
- platform_driver_unregister(&aaedkbd_driver);
-}
-
-module_init(aaedkbd_init);
-module_exit(aaedkbd_exit);
-
-MODULE_AUTHOR("Nicolas Bellido Y Ortega");
-MODULE_DESCRIPTION("AAED-2000 Keyboard Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index b92d1cd5cba1..af45d275f686 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -4,7 +4,7 @@
* I2C QWERTY Keypad and IO Expander
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
- * Copyright (C) 2008-2009 Analog Devices Inc.
+ * Copyright (C) 2008-2010 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
@@ -24,29 +24,6 @@
#include <linux/i2c/adp5588.h>
- /* Configuration Register1 */
-#define AUTO_INC (1 << 7)
-#define GPIEM_CFG (1 << 6)
-#define OVR_FLOW_M (1 << 5)
-#define INT_CFG (1 << 4)
-#define OVR_FLOW_IEN (1 << 3)
-#define K_LCK_IM (1 << 2)
-#define GPI_IEN (1 << 1)
-#define KE_IEN (1 << 0)
-
-/* Interrupt Status Register */
-#define CMP2_INT (1 << 5)
-#define CMP1_INT (1 << 4)
-#define OVR_FLOW_INT (1 << 3)
-#define K_LCK_INT (1 << 2)
-#define GPI_INT (1 << 1)
-#define KE_INT (1 << 0)
-
-/* Key Lock and Event Counter Register */
-#define K_LCK_EN (1 << 6)
-#define LCK21 0x30
-#define KEC 0xF
-
/* Key Event Register xy */
#define KEY_EV_PRESSED (1 << 7)
#define KEY_EV_MASK (0x7F)
@@ -55,10 +32,6 @@
#define KEYP_MAX_EVENT 10
-#define MAXGPIO 18
-#define ADP_BANK(offs) ((offs) >> 3)
-#define ADP_BIT(offs) (1u << ((offs) & 0x7))
-
/*
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
* since the Event Counter Register updated 25ms after the interrupt
@@ -75,7 +48,7 @@ struct adp5588_kpad {
const struct adp5588_gpi_map *gpimap;
unsigned short gpimapsize;
#ifdef CONFIG_GPIOLIB
- unsigned char gpiomap[MAXGPIO];
+ unsigned char gpiomap[ADP5588_MAXGPIO];
bool export_gpio;
struct gpio_chip gc;
struct mutex gpio_lock; /* Protect cached dir, dat_out */
@@ -103,8 +76,8 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
- unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
- unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
}
@@ -113,8 +86,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
- unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
- unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
mutex_lock(&kpad->gpio_lock);
@@ -132,8 +105,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
- unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
- unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
mutex_lock(&kpad->gpio_lock);
@@ -150,8 +123,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
- unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
- unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
mutex_lock(&kpad->gpio_lock);
@@ -176,7 +149,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
const struct adp5588_kpad_platform_data *pdata)
{
- bool pin_used[MAXGPIO];
+ bool pin_used[ADP5588_MAXGPIO];
int n_unused = 0;
int i;
@@ -191,7 +164,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
for (i = 0; i < kpad->gpimapsize; i++)
pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
- for (i = 0; i < MAXGPIO; i++)
+ for (i = 0; i < ADP5588_MAXGPIO; i++)
if (!pin_used[i])
kpad->gpiomap[n_unused++] = i;
@@ -234,7 +207,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
return error;
}
- for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
kpad->dat_out[i] = adp5588_read(kpad->client,
GPIO_DAT_OUT1 + i);
kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
@@ -318,11 +291,11 @@ static void adp5588_work(struct work_struct *work)
status = adp5588_read(client, INT_STAT);
- if (status & OVR_FLOW_INT) /* Unlikely and should never happen */
+ if (status & ADP5588_OVR_FLOW_INT) /* Unlikely and should never happen */
dev_err(&client->dev, "Event Overflow Error\n");
- if (status & KE_INT) {
- ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
+ if (status & ADP5588_KE_INT) {
+ ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & ADP5588_KEC;
if (ev_cnt) {
adp5588_report_events(kpad, ev_cnt);
input_sync(kpad->input);
@@ -360,7 +333,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
if (pdata->en_keylock) {
ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
- ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
+ ret |= adp5588_write(client, KEY_LCK_EC_STAT, ADP5588_K_LCK_EN);
}
for (i = 0; i < KEYP_MAX_EVENT; i++)
@@ -384,7 +357,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
}
if (gpio_data) {
- for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
int pull_mask = gpio_data->pullup_dis_mask;
ret |= adp5588_write(client, GPIO_PULL1 + i,
@@ -392,11 +365,14 @@ static int __devinit adp5588_setup(struct i2c_client *client)
}
}
- ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
- OVR_FLOW_INT | K_LCK_INT |
- GPI_INT | KE_INT); /* Status is W1C */
+ ret |= adp5588_write(client, INT_STAT,
+ ADP5588_CMP2_INT | ADP5588_CMP1_INT |
+ ADP5588_OVR_FLOW_INT | ADP5588_K_LCK_INT |
+ ADP5588_GPI_INT | ADP5588_KE_INT); /* Status is W1C */
- ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
+ ret |= adp5588_write(client, CFG, ADP5588_INT_CFG |
+ ADP5588_OVR_FLOW_IEN |
+ ADP5588_KE_IEN);
if (ret < 0) {
dev_err(&client->dev, "Write Error\n");
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index d358ef8623f4..11478eb2c27d 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -63,6 +63,10 @@ static bool atkbd_extra;
module_param_named(extra, atkbd_extra, bool, 0);
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
+static bool atkbd_terminal;
+module_param_named(terminal, atkbd_terminal, bool, 0);
+MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
+
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via a userland utility.
@@ -136,7 +140,8 @@ static const unsigned short atkbd_unxlate_table[128] = {
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5 /* Reset to defaults and disable */
#define ATKBD_CMD_RESET_DEF 0x00f6 /* Reset to defaults */
-#define ATKBD_CMD_SETALL_MBR 0x00fa
+#define ATKBD_CMD_SETALL_MB 0x00f8 /* Set all keys to give break codes */
+#define ATKBD_CMD_SETALL_MBR 0x00fa /* ... and repeat */
#define ATKBD_CMD_RESET_BAT 0x02ff
#define ATKBD_CMD_RESEND 0x00fe
#define ATKBD_CMD_EX_ENABLE 0x10ea
@@ -764,6 +769,11 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
}
}
+ if (atkbd_terminal) {
+ ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
+ return 3;
+ }
+
if (target_set != 3)
return 2;
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
new file mode 100644
index 000000000000..4c17aff20657
--- /dev/null
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -0,0 +1,261 @@
+/*
+ * Driver for buttons on GPIO lines not capable of generating interrupts
+ *
+ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
+ *
+ * This file was based on: /drivers/input/misc/cobalt_btns.c
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * also was based on: /drivers/input/keyboard/gpio_keys.c
+ * Copyright 2005 Phil Blundell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+
+#define DRV_NAME "gpio-keys-polled"
+
+struct gpio_keys_button_data {
+ int last_state;
+ int count;
+ int threshold;
+ int can_sleep;
+};
+
+struct gpio_keys_polled_dev {
+ struct input_polled_dev *poll_dev;
+ struct device *dev;
+ struct gpio_keys_platform_data *pdata;
+ struct gpio_keys_button_data data[0];
+};
+
+static void gpio_keys_polled_check_state(struct input_dev *input,
+ struct gpio_keys_button *button,
+ struct gpio_keys_button_data *bdata)
+{
+ int state;
+
+ if (bdata->can_sleep)
+ state = !!gpio_get_value_cansleep(button->gpio);
+ else
+ state = !!gpio_get_value(button->gpio);
+
+ if (state != bdata->last_state) {
+ unsigned int type = button->type ?: EV_KEY;
+
+ input_event(input, type, button->code,
+ !!(state ^ button->active_low));
+ input_sync(input);
+ bdata->count = 0;
+ bdata->last_state = state;
+ }
+}
+
+static void gpio_keys_polled_poll(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+ struct input_dev *input = dev->input;
+ int i;
+
+ for (i = 0; i < bdev->pdata->nbuttons; i++) {
+ struct gpio_keys_button_data *bdata = &bdev->data[i];
+
+ if (bdata->count < bdata->threshold)
+ bdata->count++;
+ else
+ gpio_keys_polled_check_state(input, &pdata->buttons[i],
+ bdata);
+ }
+}
+
+static void gpio_keys_polled_open(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+
+ if (pdata->enable)
+ pdata->enable(bdev->dev);
+}
+
+static void gpio_keys_polled_close(struct input_polled_dev *dev)
+{
+ struct gpio_keys_polled_dev *bdev = dev->private;
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+
+ if (pdata->disable)
+ pdata->disable(bdev->dev);
+}
+
+static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct gpio_keys_polled_dev *bdev;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input;
+ int error;
+ int i;
+
+ if (!pdata || !pdata->poll_interval)
+ return -EINVAL;
+
+ bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
+ pdata->nbuttons * sizeof(struct gpio_keys_button_data),
+ GFP_KERNEL);
+ if (!bdev) {
+ dev_err(dev, "no memory for private data\n");
+ return -ENOMEM;
+ }
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ dev_err(dev, "no memory for polled device\n");
+ error = -ENOMEM;
+ goto err_free_bdev;
+ }
+
+ poll_dev->private = bdev;
+ poll_dev->poll = gpio_keys_polled_poll;
+ poll_dev->poll_interval = pdata->poll_interval;
+ poll_dev->open = gpio_keys_polled_open;
+ poll_dev->close = gpio_keys_polled_close;
+
+ input = poll_dev->input;
+
+ input->evbit[0] = BIT(EV_KEY);
+ input->name = pdev->name;
+ input->phys = DRV_NAME"/input0";
+ input->dev.parent = &pdev->dev;
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ struct gpio_keys_button_data *bdata = &bdev->data[i];
+ unsigned int gpio = button->gpio;
+ unsigned int type = button->type ?: EV_KEY;
+
+ if (button->wakeup) {
+ dev_err(dev, DRV_NAME " does not support wakeup\n");
+ error = -EINVAL;
+ goto err_free_gpio;
+ }
+
+ error = gpio_request(gpio,
+ button->desc ? button->desc : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ gpio, error);
+ goto err_free_gpio;
+ }
+
+ error = gpio_direction_input(gpio);
+ if (error) {
+ dev_err(dev,
+ "unable to set direction on gpio %u, err=%d\n",
+ gpio, error);
+ goto err_free_gpio;
+ }
+
+ bdata->can_sleep = gpio_cansleep(gpio);
+ bdata->last_state = -1;
+ bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
+ pdata->poll_interval);
+
+ input_set_capability(input, type, button->code);
+ }
+
+ bdev->poll_dev = poll_dev;
+ bdev->dev = dev;
+ bdev->pdata = pdata;
+ platform_set_drvdata(pdev, bdev);
+
+ error = input_register_polled_device(poll_dev);
+ if (error) {
+ dev_err(dev, "unable to register polled device, err=%d\n",
+ error);
+ goto err_free_gpio;
+ }
+
+ /* report initial state of the buttons */
+ for (i = 0; i < pdata->nbuttons; i++)
+ gpio_keys_polled_check_state(input, &pdata->buttons[i],
+ &bdev->data[i]);
+
+ return 0;
+
+err_free_gpio:
+ while (--i >= 0)
+ gpio_free(pdata->buttons[i].gpio);
+
+ input_free_polled_device(poll_dev);
+
+err_free_bdev:
+ kfree(bdev);
+
+ platform_set_drvdata(pdev, NULL);
+ return error;
+}
+
+static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
+{
+ struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
+ struct gpio_keys_platform_data *pdata = bdev->pdata;
+ int i;
+
+ input_unregister_polled_device(bdev->poll_dev);
+
+ for (i = 0; i < pdata->nbuttons; i++)
+ gpio_free(pdata->buttons[i].gpio);
+
+ input_free_polled_device(bdev->poll_dev);
+
+ kfree(bdev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver gpio_keys_polled_driver = {
+ .probe = gpio_keys_polled_probe,
+ .remove = __devexit_p(gpio_keys_polled_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_keys_polled_init(void)
+{
+ return platform_driver_register(&gpio_keys_polled_driver);
+}
+
+static void __exit gpio_keys_polled_exit(void)
+{
+ platform_driver_unregister(&gpio_keys_polled_driver);
+}
+
+module_init(gpio_keys_polled_init);
+module_exit(gpio_keys_polled_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Polled GPIO Buttons driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index a72e61ddca91..0e2a19cb43d8 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -65,7 +65,6 @@ struct omap_kp {
static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
-static int *keymap;
static unsigned int *row_gpios;
static unsigned int *col_gpios;
@@ -162,20 +161,11 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
}
}
-static inline int omap_kp_find_key(int col, int row)
-{
- int i, key;
-
- key = KEY(col, row, 0);
- for (i = 0; keymap[i] != 0; i++)
- if ((keymap[i] & 0xff000000) == key)
- return keymap[i] & 0x00ffffff;
- return -1;
-}
-
static void omap_kp_tasklet(unsigned long data)
{
struct omap_kp *omap_kp_data = (struct omap_kp *) data;
+ unsigned short *keycodes = omap_kp_data->input->keycode;
+ unsigned int row_shift = get_count_order(omap_kp_data->cols);
unsigned char new_state[8], changed, key_down = 0;
int col, row;
int spurious = 0;
@@ -199,7 +189,7 @@ static void omap_kp_tasklet(unsigned long data)
row, (new_state[col] & (1 << row)) ?
"pressed" : "released");
#else
- key = omap_kp_find_key(col, row);
+ key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
if (key < 0) {
printk(KERN_WARNING
"omap-keypad: Spurious key event %d-%d\n",
@@ -298,13 +288,18 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
struct input_dev *input_dev;
struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
int i, col_idx, row_idx, irq_idx, ret;
+ unsigned int row_shift, keycodemax;
- if (!pdata->rows || !pdata->cols || !pdata->keymap) {
- printk(KERN_ERR "No rows, cols or keymap from pdata\n");
+ if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
+ printk(KERN_ERR "No rows, cols or keymap_data from pdata\n");
return -EINVAL;
}
- omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
+ row_shift = get_count_order(pdata->cols);
+ keycodemax = pdata->rows << row_shift;
+
+ omap_kp = kzalloc(sizeof(struct omap_kp) +
+ keycodemax * sizeof(unsigned short), GFP_KERNEL);
input_dev = input_allocate_device();
if (!omap_kp || !input_dev) {
kfree(omap_kp);
@@ -320,7 +315,9 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
if (!cpu_is_omap24xx())
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- keymap = pdata->keymap;
+ input_dev->keycode = &omap_kp[1];
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = keycodemax;
if (pdata->rep)
__set_bit(EV_REP, input_dev->evbit);
@@ -374,8 +371,8 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
/* setup input device */
__set_bit(EV_KEY, input_dev->evbit);
- for (i = 0; keymap[i] != 0; i++)
- __set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
+ input_dev->keycode, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
input_dev->dev.parent = &pdev->dev;
@@ -416,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
return 0;
err5:
for (i = irq_idx - 1; i >=0; i--)
- free_irq(row_gpios[i], 0);
+ free_irq(row_gpios[i], NULL);
err4:
input_unregister_device(omap_kp->input);
input_dev = NULL;
@@ -447,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
gpio_free(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
gpio_free(row_gpios[i]);
- free_irq(gpio_to_irq(row_gpios[i]), 0);
+ free_irq(gpio_to_irq(row_gpios[i]), NULL);
}
} else {
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- free_irq(omap_kp->irq, 0);
+ free_irq(omap_kp->irq, NULL);
}
del_timer_sync(&omap_kp->timer);
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
new file mode 100644
index 000000000000..bee03d64c453
--- /dev/null
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -0,0 +1,344 @@
+/*
+ * SPEAr Keyboard Driver
+ * Based on omap-keypad driver
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.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/clk.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <plat/keyboard.h>
+
+/* Keyboard Registers */
+#define MODE_REG 0x00 /* 16 bit reg */
+#define STATUS_REG 0x0C /* 2 bit reg */
+#define DATA_REG 0x10 /* 8 bit reg */
+#define INTR_MASK 0x54
+
+/* Register Values */
+/*
+ * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
+ * control register as 1010010(82MHZ)
+ */
+#define PCLK_FREQ_MSK 0xA400 /* 82 MHz */
+#define START_SCAN 0x0100
+#define SCAN_RATE_10 0x0000
+#define SCAN_RATE_20 0x0004
+#define SCAN_RATE_40 0x0008
+#define SCAN_RATE_80 0x000C
+#define MODE_KEYBOARD 0x0002
+#define DATA_AVAIL 0x2
+
+#define KEY_MASK 0xFF000000
+#define KEY_VALUE 0x00FFFFFF
+#define ROW_MASK 0xF0
+#define COLUMN_MASK 0x0F
+#define ROW_SHIFT 4
+
+struct spear_kbd {
+ struct input_dev *input;
+ struct resource *res;
+ void __iomem *io_base;
+ struct clk *clk;
+ unsigned int irq;
+ unsigned short last_key;
+ unsigned short keycodes[256];
+};
+
+static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
+{
+ struct spear_kbd *kbd = dev_id;
+ struct input_dev *input = kbd->input;
+ unsigned int key;
+ u8 sts, val;
+
+ sts = readb(kbd->io_base + STATUS_REG);
+ if (sts & DATA_AVAIL)
+ return IRQ_NONE;
+
+ if (kbd->last_key != KEY_RESERVED) {
+ input_report_key(input, kbd->last_key, 0);
+ kbd->last_key = KEY_RESERVED;
+ }
+
+ /* following reads active (row, col) pair */
+ val = readb(kbd->io_base + DATA_REG);
+ key = kbd->keycodes[val];
+
+ input_event(input, EV_MSC, MSC_SCAN, val);
+ input_report_key(input, key, 1);
+ input_sync(input);
+
+ kbd->last_key = key;
+
+ /* clear interrupt */
+ writeb(0, kbd->io_base + STATUS_REG);
+
+ return IRQ_HANDLED;
+}
+
+static int spear_kbd_open(struct input_dev *dev)
+{
+ struct spear_kbd *kbd = input_get_drvdata(dev);
+ int error;
+ u16 val;
+
+ kbd->last_key = KEY_RESERVED;
+
+ error = clk_enable(kbd->clk);
+ if (error)
+ return error;
+
+ /* program keyboard */
+ val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
+ writew(val, kbd->io_base + MODE_REG);
+ writeb(1, kbd->io_base + STATUS_REG);
+
+ /* start key scan */
+ val = readw(kbd->io_base + MODE_REG);
+ val |= START_SCAN;
+ writew(val, kbd->io_base + MODE_REG);
+
+ return 0;
+}
+
+static void spear_kbd_close(struct input_dev *dev)
+{
+ struct spear_kbd *kbd = input_get_drvdata(dev);
+ u16 val;
+
+ /* stop key scan */
+ val = readw(kbd->io_base + MODE_REG);
+ val &= ~START_SCAN;
+ writew(val, kbd->io_base + MODE_REG);
+
+ clk_disable(kbd->clk);
+
+ kbd->last_key = KEY_RESERVED;
+}
+
+static int __devinit spear_kbd_probe(struct platform_device *pdev)
+{
+ const struct kbd_platform_data *pdata = pdev->dev.platform_data;
+ const struct matrix_keymap_data *keymap;
+ struct spear_kbd *kbd;
+ struct input_dev *input_dev;
+ struct resource *res;
+ int irq;
+ int error;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Invalid platform data\n");
+ return -EINVAL;
+ }
+
+ keymap = pdata->keymap;
+ if (!keymap) {
+ dev_err(&pdev->dev, "no keymap defined\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no keyboard resource defined\n");
+ return -EBUSY;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "not able to get irq for the device\n");
+ return irq;
+ }
+
+ kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!kbd || !input_dev) {
+ dev_err(&pdev->dev, "out of memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ kbd->input = input_dev;
+ kbd->irq = irq;
+ kbd->res = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!kbd->res) {
+ dev_err(&pdev->dev, "keyboard region already claimed\n");
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ kbd->io_base = ioremap(res->start, resource_size(res));
+ if (!kbd->io_base) {
+ dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
+ error = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ kbd->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(kbd->clk)) {
+ error = PTR_ERR(kbd->clk);
+ goto err_iounmap;
+ }
+
+ input_dev->name = "Spear Keyboard";
+ input_dev->phys = "keyboard/input0";
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->open = spear_kbd_open;
+ input_dev->close = spear_kbd_close;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ if (pdata->rep)
+ __set_bit(EV_REP, input_dev->evbit);
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ input_dev->keycode = kbd->keycodes;
+ input_dev->keycodesize = sizeof(kbd->keycodes[0]);
+ input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
+
+ matrix_keypad_build_keymap(keymap, ROW_SHIFT,
+ input_dev->keycode, input_dev->keybit);
+
+ input_set_drvdata(input_dev, kbd);
+
+ error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
+ if (error) {
+ dev_err(&pdev->dev, "request_irq fail\n");
+ goto err_put_clk;
+ }
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "Unable to register keyboard device\n");
+ goto err_free_irq;
+ }
+
+ device_init_wakeup(&pdev->dev, 1);
+ platform_set_drvdata(pdev, kbd);
+
+ return 0;
+
+err_free_irq:
+ free_irq(kbd->irq, kbd);
+err_put_clk:
+ clk_put(kbd->clk);
+err_iounmap:
+ iounmap(kbd->io_base);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(kbd);
+
+ return error;
+}
+
+static int __devexit spear_kbd_remove(struct platform_device *pdev)
+{
+ struct spear_kbd *kbd = platform_get_drvdata(pdev);
+
+ free_irq(kbd->irq, kbd);
+ input_unregister_device(kbd->input);
+ clk_put(kbd->clk);
+ iounmap(kbd->io_base);
+ release_mem_region(kbd->res->start, resource_size(kbd->res));
+ kfree(kbd);
+
+ device_init_wakeup(&pdev->dev, 1);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int spear_kbd_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct spear_kbd *kbd = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = kbd->input;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ clk_enable(kbd->clk);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(kbd->irq);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static int spear_kbd_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct spear_kbd *kbd = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = kbd->input;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(kbd->irq);
+
+ if (input_dev->users)
+ clk_enable(kbd->clk);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops spear_kbd_pm_ops = {
+ .suspend = spear_kbd_suspend,
+ .resume = spear_kbd_resume,
+};
+#endif
+
+static struct platform_driver spear_kbd_driver = {
+ .probe = spear_kbd_probe,
+ .remove = __devexit_p(spear_kbd_remove),
+ .driver = {
+ .name = "keyboard",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &spear_kbd_pm_ops,
+#endif
+ },
+};
+
+static int __init spear_kbd_init(void)
+{
+ return platform_driver_register(&spear_kbd_driver);
+}
+module_init(spear_kbd_init);
+
+static void __exit spear_kbd_exit(void)
+{
+ platform_driver_unregister(&spear_kbd_driver);
+}
+module_exit(spear_kbd_exit);
+
+MODULE_AUTHOR("Rajeev Kumar");
+MODULE_DESCRIPTION("SPEAr Keyboard Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
new file mode 100644
index 000000000000..dbbe761778d2
--- /dev/null
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * License Terms: GNU General Public License, version 2
+ *
+ * TC35893 MFD Keypad Controller driver
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mfd/tc3589x.h>
+
+/* Maximum supported keypad matrix row/columns size */
+#define TC3589x_MAX_KPROW 8
+#define TC3589x_MAX_KPCOL 12
+
+/* keypad related Constants */
+#define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF
+#define DEDICATED_KEY_VAL 0xFF
+
+/* Pull up/down masks */
+#define TC3589x_NO_PULL_MASK 0x0
+#define TC3589x_PULL_DOWN_MASK 0x1
+#define TC3589x_PULL_UP_MASK 0x2
+#define TC3589x_PULLUP_ALL_MASK 0xAA
+#define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2))
+
+/* Bit masks for IOCFG register */
+#define IOCFG_BALLCFG 0x01
+#define IOCFG_IG 0x08
+
+#define KP_EVCODE_COL_MASK 0x0F
+#define KP_EVCODE_ROW_MASK 0x70
+#define KP_RELEASE_EVT_MASK 0x80
+
+#define KP_ROW_SHIFT 4
+
+#define KP_NO_VALID_KEY_MASK 0x7F
+
+/* bit masks for RESTCTRL register */
+#define TC3589x_KBDRST 0x2
+#define TC3589x_IRQRST 0x10
+#define TC3589x_RESET_ALL 0x1B
+
+/* KBDMFS register bit mask */
+#define TC3589x_KBDMFS_EN 0x1
+
+/* CLKEN register bitmask */
+#define KPD_CLK_EN 0x1
+
+/* RSTINTCLR register bit mask */
+#define IRQ_CLEAR 0x1
+
+/* bit masks for keyboard interrupts*/
+#define TC3589x_EVT_LOSS_INT 0x8
+#define TC3589x_EVT_INT 0x4
+#define TC3589x_KBD_LOSS_INT 0x2
+#define TC3589x_KBD_INT 0x1
+
+/* bit masks for keyboard interrupt clear*/
+#define TC3589x_EVT_INT_CLR 0x2
+#define TC3589x_KBD_INT_CLR 0x1
+
+#define TC3589x_KBD_KEYMAP_SIZE 64
+
+/**
+ * struct tc_keypad - data structure used by keypad driver
+ * @input: pointer to input device object
+ * @board: keypad platform device
+ * @krow: number of rows
+ * @kcol: number of coloumns
+ * @keymap: matrix scan code table for keycodes
+ */
+struct tc_keypad {
+ struct tc3589x *tc3589x;
+ struct input_dev *input;
+ const struct tc3589x_keypad_platform_data *board;
+ unsigned int krow;
+ unsigned int kcol;
+ unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE];
+ bool keypad_stopped;
+};
+
+static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
+{
+ int ret;
+ struct tc3589x *tc3589x = keypad->tc3589x;
+ u8 settle_time = keypad->board->settle_time;
+ u8 dbounce_period = keypad->board->debounce_period;
+ u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */
+ u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */
+
+ /* validate platform configurations */
+ if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
+ keypad->board->krow > TC3589x_MAX_KPROW ||
+ keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
+ keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
+ return -EINVAL;
+
+ /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
+ (rows << KP_ROW_SHIFT) | column);
+ if (ret < 0)
+ return ret;
+
+ /* configure dedicated key config, no dedicated key selected */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL);
+ if (ret < 0)
+ return ret;
+
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL);
+ if (ret < 0)
+ return ret;
+
+ /* Configure settle time */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
+ if (ret < 0)
+ return ret;
+
+ /* Configure debounce time */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
+ if (ret < 0)
+ return ret;
+
+ /* Start of initialise keypad GPIOs */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG);
+ if (ret < 0)
+ return ret;
+
+ /* Configure pull-up resistors for all row GPIOs */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB,
+ TC3589x_PULLUP_ALL_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB,
+ TC3589x_PULLUP_ALL_MASK);
+ if (ret < 0)
+ return ret;
+
+ /* Configure pull-up resistors for all column GPIOs */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB,
+ TC3589x_PULLUP_ALL_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB,
+ TC3589x_PULLUP_ALL_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB,
+ TC3589x_PULLUP_ALL_MASK);
+
+ return ret;
+}
+
+#define TC35893_DATA_REGS 4
+#define TC35893_KEYCODE_FIFO_EMPTY 0x7f
+#define TC35893_KEYCODE_FIFO_CLEAR 0xff
+#define TC35893_KEYPAD_ROW_SHIFT 0x3
+
+static irqreturn_t tc3589x_keypad_irq(int irq, void *dev)
+{
+ struct tc_keypad *keypad = dev;
+ struct tc3589x *tc3589x = keypad->tc3589x;
+ u8 i, row_index, col_index, kbd_code, up;
+ u8 code;
+
+ for (i = 0; i < TC35893_DATA_REGS * 2; i++) {
+ kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO);
+
+ /* loop till fifo is empty and no more keys are pressed */
+ if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY ||
+ kbd_code == TC35893_KEYCODE_FIFO_CLEAR)
+ continue;
+
+ /* valid key is found */
+ col_index = kbd_code & KP_EVCODE_COL_MASK;
+ row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT;
+ code = MATRIX_SCAN_CODE(row_index, col_index,
+ TC35893_KEYPAD_ROW_SHIFT);
+ up = kbd_code & KP_RELEASE_EVT_MASK;
+
+ input_event(keypad->input, EV_MSC, MSC_SCAN, code);
+ input_report_key(keypad->input, keypad->keymap[code], !up);
+ input_sync(keypad->input);
+ }
+
+ /* clear IRQ */
+ tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
+ 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
+ /* enable IRQ */
+ tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
+ 0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
+
+ return IRQ_HANDLED;
+}
+
+static int tc3589x_keypad_enable(struct tc_keypad *keypad)
+{
+ struct tc3589x *tc3589x = keypad->tc3589x;
+ int ret;
+
+ /* pull the keypad module out of reset */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0);
+ if (ret < 0)
+ return ret;
+
+ /* configure KBDMFS */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN);
+ if (ret < 0)
+ return ret;
+
+ /* enable the keypad clock */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN);
+ if (ret < 0)
+ return ret;
+
+ /* clear pending IRQs */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1);
+ if (ret < 0)
+ return ret;
+
+ /* enable the IRQs */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0,
+ TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
+ if (ret < 0)
+ return ret;
+
+ keypad->keypad_stopped = false;
+
+ return ret;
+}
+
+static int tc3589x_keypad_disable(struct tc_keypad *keypad)
+{
+ struct tc3589x *tc3589x = keypad->tc3589x;
+ int ret;
+
+ /* clear IRQ */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
+ 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
+ if (ret < 0)
+ return ret;
+
+ /* disable all interrupts */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
+ ~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0);
+ if (ret < 0)
+ return ret;
+
+ /* disable the keypad module */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0);
+ if (ret < 0)
+ return ret;
+
+ /* put the keypad module into reset */
+ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1);
+
+ keypad->keypad_stopped = true;
+
+ return ret;
+}
+
+static int tc3589x_keypad_open(struct input_dev *input)
+{
+ int error;
+ struct tc_keypad *keypad = input_get_drvdata(input);
+
+ /* enable the keypad module */
+ error = tc3589x_keypad_enable(keypad);
+ if (error < 0) {
+ dev_err(&input->dev, "failed to enable keypad module\n");
+ return error;
+ }
+
+ error = tc3589x_keypad_init_key_hardware(keypad);
+ if (error < 0) {
+ dev_err(&input->dev, "failed to configure keypad module\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void tc3589x_keypad_close(struct input_dev *input)
+{
+ struct tc_keypad *keypad = input_get_drvdata(input);
+
+ /* disable the keypad module */
+ tc3589x_keypad_disable(keypad);
+}
+
+static int __devinit tc3589x_keypad_probe(struct platform_device *pdev)
+{
+ struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
+ struct tc_keypad *keypad;
+ struct input_dev *input;
+ const struct tc3589x_keypad_platform_data *plat;
+ int error, irq;
+
+ plat = tc3589x->pdata->keypad;
+ if (!plat) {
+ dev_err(&pdev->dev, "invalid keypad platform data\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!keypad || !input) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ keypad->board = plat;
+ keypad->input = input;
+ keypad->tc3589x = tc3589x;
+
+ input->id.bustype = BUS_I2C;
+ input->name = pdev->name;
+ input->dev.parent = &pdev->dev;
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ input->open = tc3589x_keypad_open;
+ input->close = tc3589x_keypad_close;
+
+ input_set_drvdata(input, keypad);
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ matrix_keypad_build_keymap(plat->keymap_data, 0x3,
+ input->keycode, input->keybit);
+
+ error = request_threaded_irq(irq, NULL,
+ tc3589x_keypad_irq, plat->irqtype,
+ "tc3589x-keypad", keypad);
+ if (error < 0) {
+ dev_err(&pdev->dev,
+ "Could not allocate irq %d,error %d\n",
+ irq, error);
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "Could not register input device\n");
+ goto err_free_irq;
+ }
+
+ /* let platform decide if keypad is a wakeup source or not */
+ device_init_wakeup(&pdev->dev, plat->enable_wakeup);
+ device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup);
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+err_free_irq:
+ free_irq(irq, keypad);
+err_free_mem:
+ input_free_device(input);
+ kfree(keypad);
+ return error;
+}
+
+static int __devexit tc3589x_keypad_remove(struct platform_device *pdev)
+{
+ struct tc_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (!keypad->keypad_stopped)
+ tc3589x_keypad_disable(keypad);
+
+ free_irq(irq, keypad);
+
+ input_unregister_device(keypad->input);
+
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tc3589x_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tc_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ /* keypad is already off; we do nothing */
+ if (keypad->keypad_stopped)
+ return 0;
+
+ /* if device is not a wakeup source, disable it for powersave */
+ if (!device_may_wakeup(&pdev->dev))
+ tc3589x_keypad_disable(keypad);
+ else
+ enable_irq_wake(irq);
+
+ return 0;
+}
+
+static int tc3589x_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tc_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (!keypad->keypad_stopped)
+ return 0;
+
+ /* enable the device to resume normal operations */
+ if (!device_may_wakeup(&pdev->dev))
+ tc3589x_keypad_enable(keypad);
+ else
+ disable_irq_wake(irq);
+
+ return 0;
+}
+
+static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
+ tc3589x_keypad_suspend, tc3589x_keypad_resume);
+#endif
+
+static struct platform_driver tc3589x_keypad_driver = {
+ .driver.name = "tc3589x-keypad",
+ .driver.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .driver.pm = &tc3589x_keypad_dev_pm_ops,
+#endif
+ .probe = tc3589x_keypad_probe,
+ .remove = __devexit_p(tc3589x_keypad_remove),
+};
+
+static int __init tc3589x_keypad_init(void)
+{
+ return platform_driver_register(&tc3589x_keypad_driver);
+}
+module_init(tc3589x_keypad_init);
+
+static void __exit tc3589x_keypad_exit(void)
+{
+ return platform_driver_unregister(&tc3589x_keypad_driver);
+}
+module_exit(tc3589x_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer");
+MODULE_DESCRIPTION("TC35893 Keypad Driver");
+MODULE_ALIAS("platform:tc3589x-keypad");
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
index 00137bebcf97..800fbccf1f0f 100644
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ b/drivers/input/keyboard/tca6416-keypad.c
@@ -29,6 +29,7 @@
static const struct i2c_device_id tca6416_id[] = {
{ "tca6416-keys", 16, },
+ { "tca6408-keys", 8, },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca6416_id);
@@ -46,8 +47,9 @@ struct tca6416_keypad_chip {
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
- u16 pinmask;
+ int io_size;
int irqnum;
+ u16 pinmask;
bool use_polling;
struct tca6416_button buttons[0];
};
@@ -56,7 +58,9 @@ static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
{
int error;
- error = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+ error = chip->io_size > 8 ?
+ i2c_smbus_write_word_data(chip->client, reg << 1, val) :
+ i2c_smbus_write_byte_data(chip->client, reg, val);
if (error < 0) {
dev_err(&chip->client->dev,
"%s failed, reg: %d, val: %d, error: %d\n",
@@ -71,7 +75,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
{
int retval;
- retval = i2c_smbus_read_word_data(chip->client, reg << 1);
+ retval = chip->io_size > 8 ?
+ i2c_smbus_read_word_data(chip->client, reg << 1) :
+ i2c_smbus_read_byte_data(chip->client, reg);
if (retval < 0) {
dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
__func__, reg, retval);
@@ -224,6 +230,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
chip->client = client;
chip->input = input;
+ chip->io_size = id->driver_data;
chip->pinmask = pdata->pinmask;
chip->use_polling = pdata->use_polling;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b99b8cbde02f..b0c6772851a9 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -294,24 +294,6 @@ config INPUT_SGI_BTNS
To compile this driver as a module, choose M here: the
module will be called sgi_btns.
-config INPUT_WINBOND_CIR
- tristate "Winbond IR remote control"
- depends on X86 && PNP
- select NEW_LEDS
- select LEDS_CLASS
- select LEDS_TRIGGERS
- select BITREVERSE
- help
- Say Y here if you want to use the IR remote functionality found
- in some Winbond SuperI/O chips. Currently only the WPCD376I
- chip is supported (included in some Intel Media series motherboards).
-
- IR Receive and wake-on-IR from suspend and power-off is currently
- supported.
-
- To compile this driver as a module, choose M here: the module will be
- called winbond_cir.
-
config HP_SDC_RTC
tristate "HP SDC Real Time Clock"
depends on (GSC || HP300) && SERIO
@@ -448,4 +430,28 @@ config INPUT_ADXL34X_SPI
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
+config INPUT_CMA3000
+ tristate "VTI CMA3000 Tri-axis accelerometer"
+ help
+ Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+ driver
+
+ This driver currently only supports I2C interface to the
+ controller. Also select the I2C method.
+
+ If unsure, say N
+
+ To compile this driver as a module, choose M here: the
+ module will be called cma3000_d0x.
+
+config INPUT_CMA3000_I2C
+ tristate "Support I2C bus connection"
+ depends on INPUT_CMA3000 && I2C
+ help
+ Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+ through I2C interface.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cma3000_d0x_i2c.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 1fe1f6c8b737..9b4797112c9a 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
+obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
+obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
@@ -38,7 +40,6 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
-obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
new file mode 100644
index 000000000000..1633b6342267
--- /dev/null
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -0,0 +1,398 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/cma3000.h>
+
+#include "cma3000_d0x.h"
+
+#define CMA3000_WHOAMI 0x00
+#define CMA3000_REVID 0x01
+#define CMA3000_CTRL 0x02
+#define CMA3000_STATUS 0x03
+#define CMA3000_RSTR 0x04
+#define CMA3000_INTSTATUS 0x05
+#define CMA3000_DOUTX 0x06
+#define CMA3000_DOUTY 0x07
+#define CMA3000_DOUTZ 0x08
+#define CMA3000_MDTHR 0x09
+#define CMA3000_MDFFTMR 0x0A
+#define CMA3000_FFTHR 0x0B
+
+#define CMA3000_RANGE2G (1 << 7)
+#define CMA3000_RANGE8G (0 << 7)
+#define CMA3000_BUSI2C (0 << 4)
+#define CMA3000_MODEMASK (7 << 1)
+#define CMA3000_GRANGEMASK (1 << 7)
+
+#define CMA3000_STATUS_PERR 1
+#define CMA3000_INTSTATUS_FFDET (1 << 2)
+
+/* Settling time delay in ms */
+#define CMA3000_SETDELAY 30
+
+/* Delay for clearing interrupt in us */
+#define CMA3000_INTDELAY 44
+
+
+/*
+ * Bit weights in mg for bit 0, other bits need
+ * multipy factor 2^n. Eight bit is the sign bit.
+ */
+#define BIT_TO_2G 18
+#define BIT_TO_8G 71
+
+struct cma3000_accl_data {
+ const struct cma3000_bus_ops *bus_ops;
+ const struct cma3000_platform_data *pdata;
+
+ struct device *dev;
+ struct input_dev *input_dev;
+
+ int bit_to_mg;
+ int irq;
+
+ int g_range;
+ u8 mode;
+
+ struct mutex mutex;
+ bool opened;
+ bool suspended;
+};
+
+#define CMA3000_READ(data, reg, msg) \
+ (data->bus_ops->read(data->dev, reg, msg))
+#define CMA3000_SET(data, reg, val, msg) \
+ ((data)->bus_ops->write(data->dev, reg, val, msg))
+
+/*
+ * Conversion for each of the eight modes to g, depending
+ * on G range i.e 2G or 8G. Some modes always operate in
+ * 8G.
+ */
+
+static int mode_to_mg[8][2] = {
+ { 0, 0 },
+ { BIT_TO_8G, BIT_TO_2G },
+ { BIT_TO_8G, BIT_TO_2G },
+ { BIT_TO_8G, BIT_TO_8G },
+ { BIT_TO_8G, BIT_TO_8G },
+ { BIT_TO_8G, BIT_TO_2G },
+ { BIT_TO_8G, BIT_TO_2G },
+ { 0, 0},
+};
+
+static void decode_mg(struct cma3000_accl_data *data, int *datax,
+ int *datay, int *dataz)
+{
+ /* Data in 2's complement, convert to mg */
+ *datax = ((s8)*datax) * data->bit_to_mg;
+ *datay = ((s8)*datay) * data->bit_to_mg;
+ *dataz = ((s8)*dataz) * data->bit_to_mg;
+}
+
+static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
+{
+ struct cma3000_accl_data *data = dev_id;
+ int datax, datay, dataz;
+ u8 ctrl, mode, range, intr_status;
+
+ intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
+ if (intr_status < 0)
+ return IRQ_NONE;
+
+ /* Check if free fall is detected, report immediately */
+ if (intr_status & CMA3000_INTSTATUS_FFDET) {
+ input_report_abs(data->input_dev, ABS_MISC, 1);
+ input_sync(data->input_dev);
+ } else {
+ input_report_abs(data->input_dev, ABS_MISC, 0);
+ }
+
+ datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
+ datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
+ dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
+
+ ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
+ mode = (ctrl & CMA3000_MODEMASK) >> 1;
+ range = (ctrl & CMA3000_GRANGEMASK) >> 7;
+
+ data->bit_to_mg = mode_to_mg[mode][range];
+
+ /* Interrupt not for this device */
+ if (data->bit_to_mg == 0)
+ return IRQ_NONE;
+
+ /* Decode register values to milli g */
+ decode_mg(data, &datax, &datay, &dataz);
+
+ input_report_abs(data->input_dev, ABS_X, datax);
+ input_report_abs(data->input_dev, ABS_Y, datay);
+ input_report_abs(data->input_dev, ABS_Z, dataz);
+ input_sync(data->input_dev);
+
+ return IRQ_HANDLED;
+}
+
+static int cma3000_reset(struct cma3000_accl_data *data)
+{
+ int val;
+
+ /* Reset sequence */
+ CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
+ CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
+ CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
+
+ /* Settling time delay */
+ mdelay(10);
+
+ val = CMA3000_READ(data, CMA3000_STATUS, "Status");
+ if (val < 0) {
+ dev_err(data->dev, "Reset failed\n");
+ return val;
+ }
+
+ if (val & CMA3000_STATUS_PERR) {
+ dev_err(data->dev, "Parity Error\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cma3000_poweron(struct cma3000_accl_data *data)
+{
+ const struct cma3000_platform_data *pdata = data->pdata;
+ u8 ctrl = 0;
+ int ret;
+
+ if (data->g_range == CMARANGE_2G) {
+ ctrl = (data->mode << 1) | CMA3000_RANGE2G;
+ } else if (data->g_range == CMARANGE_8G) {
+ ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+ } else {
+ dev_info(data->dev,
+ "Invalid G range specified, assuming 8G\n");
+ ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+ }
+
+ ctrl |= data->bus_ops->ctrl_mod;
+
+ CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
+ "Motion Detect Threshold");
+ CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
+ "Time register");
+ CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
+ "Free fall threshold");
+ ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
+ if (ret < 0)
+ return -EIO;
+
+ msleep(CMA3000_SETDELAY);
+
+ return 0;
+}
+
+static int cma3000_poweroff(struct cma3000_accl_data *data)
+{
+ int ret;
+
+ ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
+ msleep(CMA3000_SETDELAY);
+
+ return ret;
+}
+
+static int cma3000_open(struct input_dev *input_dev)
+{
+ struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+ mutex_lock(&data->mutex);
+
+ if (!data->suspended)
+ cma3000_poweron(data);
+
+ data->opened = true;
+
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static void cma3000_close(struct input_dev *input_dev)
+{
+ struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+ mutex_lock(&data->mutex);
+
+ if (!data->suspended)
+ cma3000_poweroff(data);
+
+ data->opened = false;
+
+ mutex_unlock(&data->mutex);
+}
+
+void cma3000_suspend(struct cma3000_accl_data *data)
+{
+ mutex_lock(&data->mutex);
+
+ if (!data->suspended && data->opened)
+ cma3000_poweroff(data);
+
+ data->suspended = true;
+
+ mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_suspend);
+
+
+void cma3000_resume(struct cma3000_accl_data *data)
+{
+ mutex_lock(&data->mutex);
+
+ if (data->suspended && data->opened)
+ cma3000_poweron(data);
+
+ data->suspended = false;
+
+ mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_resume);
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+ const struct cma3000_bus_ops *bops)
+{
+ const struct cma3000_platform_data *pdata = dev->platform_data;
+ struct cma3000_accl_data *data;
+ struct input_dev *input_dev;
+ int rev;
+ int error;
+
+ if (!pdata) {
+ dev_err(dev, "platform data not found\n");
+ error = -EINVAL;
+ goto err_out;
+ }
+
+
+ /* if no IRQ return error */
+ if (irq == 0) {
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!data || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ data->dev = dev;
+ data->input_dev = input_dev;
+ data->bus_ops = bops;
+ data->pdata = pdata;
+ data->irq = irq;
+ mutex_init(&data->mutex);
+
+ data->mode = pdata->mode;
+ if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+ data->mode = CMAMODE_MOTDET;
+ dev_warn(dev,
+ "Invalid mode specified, assuming Motion Detect\n");
+ }
+
+ data->g_range = pdata->g_range;
+ if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
+ dev_info(dev,
+ "Invalid G range specified, assuming 8G\n");
+ data->g_range = CMARANGE_8G;
+ }
+
+ input_dev->name = "cma3000-accelerometer";
+ input_dev->id.bustype = bops->bustype;
+ input_dev->open = cma3000_open;
+ input_dev->close = cma3000_close;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_X,
+ -data->g_range, data->g_range, pdata->fuzz_x, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ -data->g_range, data->g_range, pdata->fuzz_y, 0);
+ input_set_abs_params(input_dev, ABS_Z,
+ -data->g_range, data->g_range, pdata->fuzz_z, 0);
+ input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
+
+ input_set_drvdata(input_dev, data);
+
+ error = cma3000_reset(data);
+ if (error)
+ goto err_free_mem;
+
+ rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
+ if (rev < 0) {
+ error = rev;
+ goto err_free_mem;
+ }
+
+ pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
+
+ error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
+ pdata->irqflags | IRQF_ONESHOT,
+ "cma3000_d0x", data);
+ if (error) {
+ dev_err(dev, "request_threaded_irq failed\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(data->input_dev);
+ if (error) {
+ dev_err(dev, "Unable to register input device\n");
+ goto err_free_irq;
+ }
+
+ return data;
+
+err_free_irq:
+ free_irq(irq, data);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(data);
+err_out:
+ return ERR_PTR(error);
+}
+EXPORT_SYMBOL(cma3000_init);
+
+void cma3000_exit(struct cma3000_accl_data *data)
+{
+ free_irq(data->irq, data);
+ input_unregister_device(data->input_dev);
+ kfree(data);
+}
+EXPORT_SYMBOL(cma3000_exit);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h
new file mode 100644
index 000000000000..2304ce306e1c
--- /dev/null
+++ b/drivers/input/misc/cma3000_d0x.h
@@ -0,0 +1,42 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _INPUT_CMA3000_H
+#define _INPUT_CMA3000_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+struct device;
+struct cma3000_accl_data;
+
+struct cma3000_bus_ops {
+ u16 bustype;
+ u8 ctrl_mod;
+ int (*read)(struct device *, u8, char *);
+ int (*write)(struct device *, u8, u8, char *);
+};
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+ const struct cma3000_bus_ops *bops);
+void cma3000_exit(struct cma3000_accl_data *);
+void cma3000_suspend(struct cma3000_accl_data *);
+void cma3000_resume(struct cma3000_accl_data *);
+
+#endif
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
new file mode 100644
index 000000000000..d100cc5c5783
--- /dev/null
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -0,0 +1,143 @@
+/*
+ * Implements I2C interface for VTI CMA300_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input/cma3000.h>
+#include "cma3000_d0x.h"
+
+static int cma3000_i2c_set(struct device *dev,
+ u8 reg, u8 val, char *msg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "%s failed (%s, %d)\n", __func__, msg, ret);
+ return ret;
+}
+
+static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "%s failed (%s, %d)\n", __func__, msg, ret);
+ return ret;
+}
+
+static const struct cma3000_bus_ops cma3000_i2c_bops = {
+ .bustype = BUS_I2C,
+#define CMA3000_BUSI2C (0 << 4)
+ .ctrl_mod = CMA3000_BUSI2C,
+ .read = cma3000_i2c_read,
+ .write = cma3000_i2c_set,
+};
+
+static int __devinit cma3000_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cma3000_accl_data *data;
+
+ data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ i2c_set_clientdata(client, data);
+
+ return 0;
+}
+
+static int __devexit cma3000_i2c_remove(struct i2c_client *client)
+{
+ struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+ cma3000_exit(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int cma3000_i2c_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+ cma3000_suspend(data);
+
+ return 0;
+}
+
+static int cma3000_i2c_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+ cma3000_resume(data);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cma3000_i2c_pm_ops = {
+ .suspend = cma3000_i2c_suspend,
+ .resume = cma3000_i2c_resume,
+};
+#endif
+
+static const struct i2c_device_id cma3000_i2c_id[] = {
+ { "cma3000_d01", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
+
+static struct i2c_driver cma3000_i2c_driver = {
+ .probe = cma3000_i2c_probe,
+ .remove = __devexit_p(cma3000_i2c_remove),
+ .id_table = cma3000_i2c_id,
+ .driver = {
+ .name = "cma3000_i2c_accl",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &cma3000_i2c_pm_ops,
+#endif
+ },
+};
+
+static int __init cma3000_i2c_init(void)
+{
+ return i2c_add_driver(&cma3000_i2c_driver);
+}
+
+static void __exit cma3000_i2c_exit(void)
+{
+ i2c_del_driver(&cma3000_i2c_driver);
+}
+
+module_init(cma3000_i2c_init);
+module_exit(cma3000_i2c_exit);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index 4b42ffc0532a..08be1a355956 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -127,14 +127,6 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
idev->id.product = 0x0001;
idev->id.version = 0x0100;
- input_set_drvdata(idev, lp);
-
- ret = input_register_device(idev);
- if (ret) {
- dev_err(&client->dev, "input_register_device() failed\n");
- goto fail_register;
- }
-
lp->laststate = read_state(lp);
ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
@@ -142,16 +134,21 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
DRV_NAME, lp);
if (ret) {
dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
- goto fail_irq;
+ goto fail_free_device;
+ }
+
+ ret = input_register_device(idev);
+ if (ret) {
+ dev_err(&client->dev, "input_register_device() failed\n");
+ goto fail_free_irq;
}
i2c_set_clientdata(client, lp);
return 0;
- fail_irq:
- input_unregister_device(idev);
- fail_register:
- input_set_drvdata(idev, NULL);
+ fail_free_irq:
+ free_irq(client->irq, lp);
+ fail_free_device:
input_free_device(idev);
fail_allocate:
kfree(lp);
@@ -172,19 +169,29 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int pcf8574_kp_resume(struct i2c_client *client)
+static int pcf8574_kp_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
enable_irq(client->irq);
return 0;
}
-static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg)
+static int pcf8574_kp_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
disable_irq(client->irq);
return 0;
}
+
+static const struct dev_pm_ops pcf8574_kp_pm_ops = {
+ .suspend = pcf8574_kp_suspend,
+ .resume = pcf8574_kp_resume,
+};
+
#else
# define pcf8574_kp_resume NULL
# define pcf8574_kp_suspend NULL
@@ -200,11 +207,12 @@ static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pcf8574_kp_pm_ops,
+#endif
},
.probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove),
- .suspend = pcf8574_kp_suspend,
- .resume = pcf8574_kp_resume,
.id_table = pcf8574_kp_id,
};
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index b9410784e6a1..82542a1c1098 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -37,6 +37,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uinput.h>
+#include <linux/input/mt.h>
#include "../input-compat.h"
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -406,8 +407,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
- input_mt_create_slots(dev, nslot);
- input_set_events_per_packet(dev, 6 * nslot);
+ input_mt_init_slots(dev, nslot);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
@@ -680,6 +680,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
retval = uinput_set_bit(arg, swbit, SW_MAX);
break;
+ case UI_SET_PROPBIT:
+ retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
+ break;
+
case UI_SET_PHYS:
if (udev->state == UIST_CREATED) {
retval = -EINVAL;
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index a9cf76831634..b77f9991278e 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -630,7 +630,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
/* Just update the base values (i.e. touchpad in untouched state) */
if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
- dprintk(KERN_DEBUG "appletouch: updated base values\n");
+ dprintk("appletouch: updated base values\n");
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
goto exit;
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index b95231763911..ee82851afe3e 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -55,6 +55,14 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
+/* MacbookAir3,2 (unibody), aka wellspring5 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
+/* MacbookAir3,1 (unibody), aka wellspring4 */
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -80,6 +88,14 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
+ /* MacbookAir3,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+ /* MacbookAir3,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
/* Terminating entry */
{}
};
@@ -234,6 +250,30 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ DIM_X, DIM_X / SN_COORD, -4460, 5166 },
{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING4_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
+ { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
+ },
{}
};
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 1d2205b24800..95577c15ae56 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -40,6 +40,8 @@
#include "psmouse.h"
#include "hgpk.h"
+#define ILLEGAL_XY 999999
+
static bool tpdebug;
module_param(tpdebug, bool, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
@@ -47,48 +49,150 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100;
module_param(recalib_delta, int, 0644);
MODULE_PARM_DESC(recalib_delta,
- "packets containing a delta this large will cause a recalibration.");
+ "packets containing a delta this large will be discarded, and a "
+ "recalibration may be scheduled.");
-static int jumpy_delay = 1000;
+static int jumpy_delay = 20;
module_param(jumpy_delay, int, 0644);
MODULE_PARM_DESC(jumpy_delay,
"delay (ms) before recal after jumpiness detected");
-static int spew_delay = 1000;
+static int spew_delay = 1;
module_param(spew_delay, int, 0644);
MODULE_PARM_DESC(spew_delay,
"delay (ms) before recal after packet spew detected");
-static int recal_guard_time = 2000;
+static int recal_guard_time;
module_param(recal_guard_time, int, 0644);
MODULE_PARM_DESC(recal_guard_time,
"interval (ms) during which recal will be restarted if packet received");
-static int post_interrupt_delay = 1000;
+static int post_interrupt_delay = 40;
module_param(post_interrupt_delay, int, 0644);
MODULE_PARM_DESC(post_interrupt_delay,
"delay (ms) before recal after recal interrupt detected");
+static bool autorecal = true;
+module_param(autorecal, bool, 0644);
+MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
+
+static char hgpk_mode_name[16];
+module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644);
+MODULE_PARM_DESC(hgpk_mode,
+ "default hgpk mode: mouse, glidesensor or pentablet");
+
+static int hgpk_default_mode = HGPK_MODE_MOUSE;
+
+static const char * const hgpk_mode_names[] = {
+ [HGPK_MODE_MOUSE] = "Mouse",
+ [HGPK_MODE_GLIDESENSOR] = "GlideSensor",
+ [HGPK_MODE_PENTABLET] = "PenTablet",
+};
+
+static int hgpk_mode_from_name(const char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) {
+ const char *name = hgpk_mode_names[i];
+ if (strlen(name) == len && !strncasecmp(name, buf, len))
+ return i;
+ }
+
+ return HGPK_MODE_INVALID;
+}
+
+/*
+ * see if new value is within 20% of half of old value
+ */
+static int approx_half(int curr, int prev)
+{
+ int belowhalf, abovehalf;
+
+ if (curr < 5 || prev < 5)
+ return 0;
+
+ belowhalf = (prev * 8) / 20;
+ abovehalf = (prev * 12) / 20;
+
+ return belowhalf < curr && curr <= abovehalf;
+}
+
/*
- * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
- * above the pad and still have it send packets. This causes a jump cursor
- * when one places their finger on the pad. We can probably detect the
- * jump as we see a large deltas (>= 100px). In mouse mode, I've been
- * unable to even come close to 100px deltas during normal usage, so I think
- * this threshold is safe. If a large delta occurs, trigger a recalibration.
+ * Throw out oddly large delta packets, and any that immediately follow whose
+ * values are each approximately half of the previous. It seems that the ALPS
+ * firmware emits errant packets, and they get averaged out slowly.
*/
-static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
+static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
{
struct hgpk_data *priv = psmouse->private;
+ int avx, avy;
+ bool do_recal = false;
+
+ avx = abs(x);
+ avy = abs(y);
+
+ /* discard if too big, or half that but > 4 times the prev delta */
+ if (avx > recalib_delta ||
+ (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
+ hgpk_err(psmouse, "detected %dpx jump in x\n", x);
+ priv->xbigj = avx;
+ } else if (approx_half(avx, priv->xbigj)) {
+ hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
+ priv->xbigj = avx;
+ priv->xsaw_secondary++;
+ } else {
+ if (priv->xbigj && priv->xsaw_secondary > 1)
+ do_recal = true;
+ priv->xbigj = 0;
+ priv->xsaw_secondary = 0;
+ }
+
+ if (avy > recalib_delta ||
+ (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
+ hgpk_err(psmouse, "detected %dpx jump in y\n", y);
+ priv->ybigj = avy;
+ } else if (approx_half(avy, priv->ybigj)) {
+ hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
+ priv->ybigj = avy;
+ priv->ysaw_secondary++;
+ } else {
+ if (priv->ybigj && priv->ysaw_secondary > 1)
+ do_recal = true;
+ priv->ybigj = 0;
+ priv->ysaw_secondary = 0;
+ }
- if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
- hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
- recalib_delta, x, y);
- /* My car gets forty rods to the hogshead and that's the
- * way I likes it! */
+ priv->xlast = avx;
+ priv->ylast = avy;
+
+ if (do_recal && jumpy_delay) {
+ hgpk_err(psmouse, "scheduling recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(jumpy_delay));
}
+
+ return priv->xbigj || priv->ybigj;
+}
+
+static void hgpk_reset_spew_detection(struct hgpk_data *priv)
+{
+ priv->spew_count = 0;
+ priv->dupe_count = 0;
+ priv->x_tally = 0;
+ priv->y_tally = 0;
+ priv->spew_flag = NO_SPEW;
+}
+
+static void hgpk_reset_hack_state(struct psmouse *psmouse)
+{
+ struct hgpk_data *priv = psmouse->private;
+
+ priv->abs_x = priv->abs_y = -1;
+ priv->xlast = priv->ylast = ILLEGAL_XY;
+ priv->xbigj = priv->ybigj = 0;
+ priv->xsaw_secondary = priv->ysaw_secondary = 0;
+ hgpk_reset_spew_detection(priv);
}
/*
@@ -116,20 +220,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
if (l || r)
return;
+ /* don't track spew if the workaround feature has been turned off */
+ if (!spew_delay)
+ return;
+
+ if (abs(x) > 3 || abs(y) > 3) {
+ /* no spew, or spew ended */
+ hgpk_reset_spew_detection(priv);
+ return;
+ }
+
+ /* Keep a tally of the overall delta to the cursor position caused by
+ * the spew */
priv->x_tally += x;
priv->y_tally += y;
- if (++priv->count > 100) {
+ switch (priv->spew_flag) {
+ case NO_SPEW:
+ /* we're not spewing, but this packet might be the start */
+ priv->spew_flag = MAYBE_SPEWING;
+
+ /* fall-through */
+
+ case MAYBE_SPEWING:
+ priv->spew_count++;
+
+ if (priv->spew_count < SPEW_WATCH_COUNT)
+ break;
+
+ /* excessive spew detected, request recalibration */
+ priv->spew_flag = SPEW_DETECTED;
+
+ /* fall-through */
+
+ case SPEW_DETECTED:
+ /* only recalibrate when the overall delta to the cursor
+ * is really small. if the spew is causing significant cursor
+ * movement, it is probably a case of the user moving the
+ * cursor very slowly across the screen. */
if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
- hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
+ hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
priv->x_tally, priv->y_tally);
+ priv->spew_flag = RECALIBRATING;
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(spew_delay));
}
- /* reset every 100 packets */
- priv->count = 0;
- priv->x_tally = 0;
- priv->y_tally = 0;
+
+ break;
+ case RECALIBRATING:
+ /* we already detected a spew and requested a recalibration,
+ * just wait for the queue to kick into action. */
+ break;
}
}
@@ -143,25 +284,168 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
* swr/swl are the left/right buttons.
* x-neg/y-neg are the x and y delta negative bits
* x-over/y-over are the x and y overflow bits
+ *
+ * ---
+ *
+ * HGPK Advanced Mode - single-mode format
+ *
+ * byte 0(PT): 1 1 0 0 1 1 1 1
+ * byte 0(GS): 1 1 1 1 1 1 1 1
+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
+ * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
+ * byte 3: 0 y9 y8 y7 1 0 swr swl
+ * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
+ * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+ *
+ * ?'s are not defined in the protocol spec, may vary between models.
+ *
+ * swr/swl are the left/right buttons.
+ *
+ * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
+ * pen/finger
*/
-static int hgpk_validate_byte(unsigned char *packet)
+static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
{
- return (packet[0] & 0x0C) != 0x08;
+ struct hgpk_data *priv = psmouse->private;
+ int pktcnt = psmouse->pktcnt;
+ bool valid;
+
+ switch (priv->mode) {
+ case HGPK_MODE_MOUSE:
+ valid = (packet[0] & 0x0C) == 0x08;
+ break;
+
+ case HGPK_MODE_GLIDESENSOR:
+ valid = pktcnt == 1 ?
+ packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80);
+ break;
+
+ case HGPK_MODE_PENTABLET:
+ valid = pktcnt == 1 ?
+ packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80);
+ break;
+
+ default:
+ valid = false;
+ break;
+ }
+
+ if (!valid)
+ hgpk_dbg(psmouse,
+ "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
+ priv->mode, pktcnt,
+ psmouse->packet[0], psmouse->packet[1],
+ psmouse->packet[2], psmouse->packet[3],
+ psmouse->packet[4], psmouse->packet[5]);
+
+ return valid;
}
-static void hgpk_process_packet(struct psmouse *psmouse)
+static void hgpk_process_advanced_packet(struct psmouse *psmouse)
{
- struct input_dev *dev = psmouse->dev;
+ struct hgpk_data *priv = psmouse->private;
+ struct input_dev *idev = psmouse->dev;
unsigned char *packet = psmouse->packet;
- int x, y, left, right;
+ int down = !!(packet[2] & 2);
+ int left = !!(packet[3] & 1);
+ int right = !!(packet[3] & 2);
+ int x = packet[1] | ((packet[2] & 0x78) << 4);
+ int y = packet[4] | ((packet[3] & 0x70) << 3);
+
+ if (priv->mode == HGPK_MODE_GLIDESENSOR) {
+ int pt_down = !!(packet[2] & 1);
+ int finger_down = !!(packet[2] & 2);
+ int z = packet[5];
+
+ input_report_abs(idev, ABS_PRESSURE, z);
+ if (tpdebug)
+ hgpk_dbg(psmouse, "pd=%d fd=%d z=%d",
+ pt_down, finger_down, z);
+ } else {
+ /*
+ * PenTablet mode does not report pressure, so we don't
+ * report it here
+ */
+ if (tpdebug)
+ hgpk_dbg(psmouse, "pd=%d ", down);
+ }
+
+ if (tpdebug)
+ hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
+
+ input_report_key(idev, BTN_TOUCH, down);
+ input_report_key(idev, BTN_LEFT, left);
+ input_report_key(idev, BTN_RIGHT, right);
+
+ /*
+ * If this packet says that the finger was removed, reset our position
+ * tracking so that we don't erroneously detect a jump on next press.
+ */
+ if (!down) {
+ hgpk_reset_hack_state(psmouse);
+ goto done;
+ }
+
+ /*
+ * Weed out duplicate packets (we get quite a few, and they mess up
+ * our jump detection)
+ */
+ if (x == priv->abs_x && y == priv->abs_y) {
+ if (++priv->dupe_count > SPEW_WATCH_COUNT) {
+ if (tpdebug)
+ hgpk_dbg(psmouse, "hard spew detected\n");
+ priv->spew_flag = RECALIBRATING;
+ psmouse_queue_work(psmouse, &priv->recalib_wq,
+ msecs_to_jiffies(spew_delay));
+ }
+ goto done;
+ }
- left = packet[0] & 1;
- right = (packet[0] >> 1) & 1;
+ /* not a duplicate, continue with position reporting */
+ priv->dupe_count = 0;
+
+ /* Don't apply hacks in PT mode, it seems reliable */
+ if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
+ int x_diff = priv->abs_x - x;
+ int y_diff = priv->abs_y - y;
+ if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
+ if (tpdebug)
+ hgpk_dbg(psmouse, "discarding\n");
+ goto done;
+ }
+ hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
+ }
- x = packet[1] - ((packet[0] << 4) & 0x100);
- y = ((packet[0] << 3) & 0x100) - packet[2];
+ input_report_abs(idev, ABS_X, x);
+ input_report_abs(idev, ABS_Y, y);
+ priv->abs_x = x;
+ priv->abs_y = y;
+
+done:
+ input_sync(idev);
+}
+
+static void hgpk_process_simple_packet(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+ unsigned char *packet = psmouse->packet;
+ int left = packet[0] & 1;
+ int right = (packet[0] >> 1) & 1;
+ int x = packet[1] - ((packet[0] << 4) & 0x100);
+ int y = ((packet[0] << 3) & 0x100) - packet[2];
+
+ if (packet[0] & 0xc0)
+ hgpk_dbg(psmouse,
+ "overflow -- 0x%02x 0x%02x 0x%02x\n",
+ packet[0], packet[1], packet[2]);
+
+ if (hgpk_discard_decay_hack(psmouse, x, y)) {
+ if (tpdebug)
+ hgpk_dbg(psmouse, "discarding\n");
+ return;
+ }
- hgpk_jumpy_hack(psmouse, x, y);
hgpk_spewing_hack(psmouse, left, right, x, y);
if (tpdebug)
@@ -180,15 +464,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
{
struct hgpk_data *priv = psmouse->private;
- if (hgpk_validate_byte(psmouse->packet)) {
- hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
- __func__, psmouse->pktcnt, psmouse->packet[0],
- psmouse->packet[1], psmouse->packet[2]);
+ if (!hgpk_is_byte_valid(psmouse, psmouse->packet))
return PSMOUSE_BAD_DATA;
- }
if (psmouse->pktcnt >= psmouse->pktsize) {
- hgpk_process_packet(psmouse);
+ if (priv->mode == HGPK_MODE_MOUSE)
+ hgpk_process_simple_packet(psmouse);
+ else
+ hgpk_process_advanced_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
@@ -210,33 +493,176 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA;
}
+static int hgpk_select_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ struct hgpk_data *priv = psmouse->private;
+ int i;
+ int cmd;
+
+ /*
+ * 4 disables to enable advanced mode
+ * then 3 0xf2 bytes as the preamble for GS/PT selection
+ */
+ const int advanced_init[] = {
+ PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
+ PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
+ 0xf2, 0xf2, 0xf2,
+ };
+
+ switch (priv->mode) {
+ case HGPK_MODE_MOUSE:
+ psmouse->pktsize = 3;
+ break;
+
+ case HGPK_MODE_GLIDESENSOR:
+ case HGPK_MODE_PENTABLET:
+ psmouse->pktsize = 6;
+
+ /* Switch to 'Advanced mode.', four disables in a row. */
+ for (i = 0; i < ARRAY_SIZE(advanced_init); i++)
+ if (ps2_command(ps2dev, NULL, advanced_init[i]))
+ return -EIO;
+
+ /* select between GlideSensor (mouse) or PenTablet */
+ cmd = priv->mode == HGPK_MODE_GLIDESENSOR ?
+ PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21;
+
+ if (ps2_command(ps2dev, NULL, cmd))
+ return -EIO;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void hgpk_setup_input_device(struct input_dev *input,
+ struct input_dev *old_input,
+ enum hgpk_mode mode)
+{
+ if (old_input) {
+ input->name = old_input->name;
+ input->phys = old_input->phys;
+ input->id = old_input->id;
+ input->dev.parent = old_input->dev.parent;
+ }
+
+ memset(input->evbit, 0, sizeof(input->evbit));
+ memset(input->relbit, 0, sizeof(input->relbit));
+ memset(input->keybit, 0, sizeof(input->keybit));
+
+ /* All modes report left and right buttons */
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+
+ switch (mode) {
+ case HGPK_MODE_MOUSE:
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(REL_X, input->relbit);
+ __set_bit(REL_Y, input->relbit);
+ break;
+
+ case HGPK_MODE_GLIDESENSOR:
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ __set_bit(EV_ABS, input->evbit);
+
+ /* GlideSensor has pressure sensor, PenTablet does not */
+ input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0);
+
+ /* From device specs */
+ input_set_abs_params(input, ABS_X, 0, 399, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, 290, 0, 0);
+
+ /* Calculated by hand based on usable size (52mm x 38mm) */
+ input_abs_set_res(input, ABS_X, 8);
+ input_abs_set_res(input, ABS_Y, 8);
+ break;
+
+ case HGPK_MODE_PENTABLET:
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ __set_bit(EV_ABS, input->evbit);
+
+ /* From device specs */
+ input_set_abs_params(input, ABS_X, 0, 999, 0, 0);
+ input_set_abs_params(input, ABS_Y, 5, 239, 0, 0);
+
+ /* Calculated by hand based on usable size (156mm x 38mm) */
+ input_abs_set_res(input, ABS_X, 6);
+ input_abs_set_res(input, ABS_Y, 8);
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
+{
+ int err;
+
+ psmouse_reset(psmouse);
+
+ if (recalibrate) {
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ /* send the recalibrate request */
+ if (ps2_command(ps2dev, NULL, 0xf5) ||
+ ps2_command(ps2dev, NULL, 0xf5) ||
+ ps2_command(ps2dev, NULL, 0xe6) ||
+ ps2_command(ps2dev, NULL, 0xf5)) {
+ return -1;
+ }
+
+ /* according to ALPS, 150mS is required for recalibration */
+ msleep(150);
+ }
+
+ err = hgpk_select_mode(psmouse);
+ if (err) {
+ hgpk_err(psmouse, "failed to select mode\n");
+ return err;
+ }
+
+ hgpk_reset_hack_state(psmouse);
+
+ return 0;
+}
+
static int hgpk_force_recalibrate(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
struct hgpk_data *priv = psmouse->private;
+ int err;
/* C-series touchpads added the recalibrate command */
if (psmouse->model < HGPK_MODEL_C)
return 0;
+ if (!autorecal) {
+ hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n");
+ return 0;
+ }
+
+ hgpk_dbg(psmouse, "recalibrating touchpad..\n");
+
/* we don't want to race with the irq handler, nor with resyncs */
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
/* start by resetting the device */
- psmouse_reset(psmouse);
-
- /* send the recalibrate request */
- if (ps2_command(ps2dev, NULL, 0xf5) ||
- ps2_command(ps2dev, NULL, 0xf5) ||
- ps2_command(ps2dev, NULL, 0xe6) ||
- ps2_command(ps2dev, NULL, 0xf5)) {
- return -1;
- }
-
- /* according to ALPS, 150mS is required for recalibration */
- msleep(150);
+ err = hgpk_reset_device(psmouse, true);
+ if (err)
+ return err;
- /* XXX: If a finger is down during this delay, recalibration will
+ /*
+ * XXX: If a finger is down during this delay, recalibration will
* detect capacitance incorrectly. This is a hardware bug, and
* we don't have a good way to deal with it. The 2s window stuff
* (below) is our best option for now.
@@ -247,25 +673,35 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
- /* After we recalibrate, we shouldn't get any packets for 2s. If
- * we do, it's likely that someone's finger was on the touchpad.
- * If someone's finger *was* on the touchpad, it's probably
- * miscalibrated. So, we should schedule another recalibration
+ if (tpdebug)
+ hgpk_dbg(psmouse, "touchpad reactivated\n");
+
+ /*
+ * If we get packets right away after recalibrating, it's likely
+ * that a finger was on the touchpad. If so, it's probably
+ * miscalibrated, so we optionally schedule another.
*/
- priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time);
+ if (recal_guard_time)
+ priv->recalib_window = jiffies +
+ msecs_to_jiffies(recal_guard_time);
return 0;
}
/*
- * This kills power to the touchpad; according to ALPS, current consumption
- * goes down to 50uA after running this. To turn power back on, we drive
- * MS-DAT low.
+ * This puts the touchpad in a power saving mode; according to ALPS, current
+ * consumption goes down to 50uA after running this. To turn power back on,
+ * we drive MS-DAT low. Measuring with a 1mA resolution ammeter says that
+ * the current on the SUS_3.3V rail drops from 3mA or 4mA to 0 when we do this.
+ *
+ * We have no formal spec that details this operation -- the low-power
+ * sequence came from a long-lost email trail.
*/
-static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
+static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int timeo;
+ int err;
/* Added on D-series touchpads */
if (psmouse->model < HGPK_MODEL_D)
@@ -279,24 +715,27 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
* the controller. Once we get an ACK back from it, it
* means we can continue with the touchpad re-init. ALPS
* tells us that 1s should be long enough, so set that as
- * the upper bound.
+ * the upper bound. (in practice, it takes about 3 loops.)
*/
for (timeo = 20; timeo > 0; timeo--) {
if (!ps2_sendbyte(&psmouse->ps2dev,
PSMOUSE_CMD_DISABLE, 20))
break;
- msleep(50);
+ msleep(25);
}
- psmouse_reset(psmouse);
+ err = hgpk_reset_device(psmouse, false);
+ if (err) {
+ hgpk_err(psmouse, "Failed to reset device!\n");
+ return err;
+ }
/* should be all set, enable the touchpad */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-
+ hgpk_dbg(psmouse, "Touchpad powered up.\n");
} else {
hgpk_dbg(psmouse, "Powering off touchpad.\n");
- psmouse_set_state(psmouse, PSMOUSE_IGNORE);
if (ps2_command(ps2dev, NULL, 0xec) ||
ps2_command(ps2dev, NULL, 0xec) ||
@@ -304,6 +743,8 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
return -1;
}
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+
/* probably won't see an ACK, the touchpad will be off */
ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
}
@@ -319,17 +760,20 @@ static int hgpk_poll(struct psmouse *psmouse)
static int hgpk_reconnect(struct psmouse *psmouse)
{
- /* During suspend/resume the ps2 rails remain powered. We don't want
+ struct hgpk_data *priv = psmouse->private;
+
+ /*
+ * During suspend/resume the ps2 rails remain powered. We don't want
* to do a reset because it's flush data out of buffers; however,
- * earlier prototypes (B1) had some brokenness that required a reset. */
+ * earlier prototypes (B1) had some brokenness that required a reset.
+ */
if (olpc_board_at_least(olpc_board(0xb2)))
if (psmouse->ps2dev.serio->dev.power.power_state.event !=
PM_EVENT_ON)
return 0;
- psmouse_reset(psmouse);
-
- return 0;
+ priv->powered = 1;
+ return hgpk_reset_device(psmouse, false);
}
static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
@@ -355,7 +799,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
* hgpk_toggle_power will deal w/ state so
* we're not racing w/ irq
*/
- err = hgpk_toggle_power(psmouse, value);
+ err = hgpk_toggle_powersave(psmouse, value);
if (!err)
priv->powered = value;
}
@@ -366,6 +810,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
hgpk_show_powered, hgpk_set_powered, false);
+static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct hgpk_data *priv = psmouse->private;
+
+ return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]);
+}
+
+static ssize_t attr_set_mode(struct psmouse *psmouse, void *data,
+ const char *buf, size_t len)
+{
+ struct hgpk_data *priv = psmouse->private;
+ enum hgpk_mode old_mode = priv->mode;
+ enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len);
+ struct input_dev *old_dev = psmouse->dev;
+ struct input_dev *new_dev;
+ int err;
+
+ if (new_mode == HGPK_MODE_INVALID)
+ return -EINVAL;
+
+ if (old_mode == new_mode)
+ return len;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
+ return -ENOMEM;
+
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ /* Switch device into the new mode */
+ priv->mode = new_mode;
+ err = hgpk_reset_device(psmouse, false);
+ if (err)
+ goto err_try_restore;
+
+ hgpk_setup_input_device(new_dev, old_dev, new_mode);
+
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ err = input_register_device(new_dev);
+ if (err)
+ goto err_try_restore;
+
+ psmouse->dev = new_dev;
+ input_unregister_device(old_dev);
+
+ return len;
+
+err_try_restore:
+ input_free_device(new_dev);
+ priv->mode = old_mode;
+ hgpk_reset_device(psmouse, false);
+
+ return err;
+}
+
+PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL,
+ attr_show_mode, attr_set_mode);
+
static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
void *data, char *buf)
{
@@ -401,6 +904,8 @@ static void hgpk_disconnect(struct psmouse *psmouse)
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_hgpk_mode.dattr);
if (psmouse->model >= HGPK_MODEL_C)
device_remove_file(&psmouse->ps2dev.serio->dev,
@@ -416,14 +921,13 @@ static void hgpk_recalib_work(struct work_struct *work)
struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
struct psmouse *psmouse = priv->psmouse;
- hgpk_dbg(psmouse, "recalibrating touchpad..\n");
-
if (hgpk_force_recalibrate(psmouse))
hgpk_err(psmouse, "recalibration failed!\n");
}
static int hgpk_register(struct psmouse *psmouse)
{
+ struct hgpk_data *priv = psmouse->private;
int err;
/* register handlers */
@@ -431,13 +935,14 @@ static int hgpk_register(struct psmouse *psmouse)
psmouse->poll = hgpk_poll;
psmouse->disconnect = hgpk_disconnect;
psmouse->reconnect = hgpk_reconnect;
- psmouse->pktsize = 3;
/* Disable the idle resync. */
psmouse->resync_time = 0;
/* Reset after a lot of bad bytes. */
psmouse->resetafter = 1024;
+ hgpk_setup_input_device(psmouse->dev, NULL, priv->mode);
+
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
if (err) {
@@ -445,6 +950,13 @@ static int hgpk_register(struct psmouse *psmouse)
return err;
}
+ err = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_hgpk_mode.dattr);
+ if (err) {
+ hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n");
+ goto err_remove_powered;
+ }
+
/* C-series touchpads added the recalibrate command */
if (psmouse->model >= HGPK_MODEL_C) {
err = device_create_file(&psmouse->ps2dev.serio->dev,
@@ -452,30 +964,40 @@ static int hgpk_register(struct psmouse *psmouse)
if (err) {
hgpk_err(psmouse,
"Failed creating 'recalibrate' sysfs node\n");
- device_remove_file(&psmouse->ps2dev.serio->dev,
- &psmouse_attr_powered.dattr);
- return err;
+ goto err_remove_mode;
}
}
return 0;
+
+err_remove_mode:
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_hgpk_mode.dattr);
+err_remove_powered:
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_powered.dattr);
+ return err;
}
int hgpk_init(struct psmouse *psmouse)
{
struct hgpk_data *priv;
- int err = -ENOMEM;
+ int err;
priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
- if (!priv)
+ if (!priv) {
+ err = -ENOMEM;
goto alloc_fail;
+ }
psmouse->private = priv;
+
priv->psmouse = psmouse;
priv->powered = true;
+ priv->mode = hgpk_default_mode;
INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
- err = psmouse_reset(psmouse);
+ err = hgpk_reset_device(psmouse, false);
if (err)
goto init_fail;
@@ -531,3 +1053,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
+
+void hgpk_module_init(void)
+{
+ hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name,
+ strlen(hgpk_mode_name));
+ if (hgpk_default_mode == HGPK_MODE_INVALID) {
+ hgpk_default_mode = HGPK_MODE_MOUSE;
+ strlcpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE],
+ sizeof(hgpk_mode_name));
+ }
+}
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
index d61cfd3ee9cb..311c0e87fcbf 100644
--- a/drivers/input/mouse/hgpk.h
+++ b/drivers/input/mouse/hgpk.h
@@ -5,6 +5,9 @@
#ifndef _HGPK_H
#define _HGPK_H
+#define HGPK_GS 0xff /* The GlideSensor */
+#define HGPK_PT 0xcf /* The PenTablet */
+
enum hgpk_model_t {
HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
@@ -13,12 +16,34 @@ enum hgpk_model_t {
HGPK_MODEL_D = 0x50, /* C1, mass production */
};
+enum hgpk_spew_flag {
+ NO_SPEW,
+ MAYBE_SPEWING,
+ SPEW_DETECTED,
+ RECALIBRATING,
+};
+
+#define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */
+
+enum hgpk_mode {
+ HGPK_MODE_MOUSE,
+ HGPK_MODE_GLIDESENSOR,
+ HGPK_MODE_PENTABLET,
+ HGPK_MODE_INVALID
+};
+
struct hgpk_data {
struct psmouse *psmouse;
+ enum hgpk_mode mode;
bool powered;
- int count, x_tally, y_tally; /* hardware workaround stuff */
+ enum hgpk_spew_flag spew_flag;
+ int spew_count, x_tally, y_tally; /* spew detection */
unsigned long recalib_window;
struct delayed_work recalib_wq;
+ int abs_x, abs_y;
+ int dupe_count;
+ int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
+ int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
};
#define hgpk_dbg(psmouse, format, arg...) \
@@ -33,9 +58,13 @@ struct hgpk_data {
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC
+void hgpk_module_init(void);
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse);
#else
+static inline void hgpk_module_init(void)
+{
+}
static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENODEV;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index cd9d0c97e429..3f74baee102b 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void)
lifebook_module_init();
synaptics_module_init();
+ hgpk_module_init();
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 2e300a460556..da392c22fc6c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -25,7 +25,7 @@
#include <linux/module.h>
#include <linux/dmi.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <linux/slab.h>
@@ -279,6 +279,25 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
synaptics_mode_cmd(psmouse, priv->mode);
}
+static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
+{
+ static unsigned char param = 0xc8;
+ struct synaptics_data *priv = psmouse->private;
+
+ if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
+ return 0;
+
+ if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
+ return -1;
+ if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
+ return -1;
+
+ /* Advanced gesture mode also sends multi finger data */
+ priv->capabilities |= BIT(1);
+
+ return 0;
+}
+
/*****************************************************************************
* Synaptics pass-through PS/2 port support
****************************************************************************/
@@ -380,7 +399,9 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets
****************************************************************************/
-static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
+static int synaptics_parse_hw_state(const unsigned char buf[],
+ struct synaptics_data *priv,
+ struct synaptics_hw_state *hw)
{
memset(hw, 0, sizeof(struct synaptics_hw_state));
@@ -397,6 +418,14 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
((buf[0] & 0x04) >> 1) |
((buf[3] & 0x04) >> 2));
+ if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
+ /* Gesture packet: (x, y, z) at half resolution */
+ priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
+ priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
+ priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
+ return 1;
+ }
+
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
@@ -452,6 +481,36 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
}
+
+ return 0;
+}
+
+static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y)
+{
+ input_mt_slot(dev, slot);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y,
+ YMAX_NOMINAL + YMIN_NOMINAL - y);
+ }
+}
+
+static void synaptics_report_semi_mt_data(struct input_dev *dev,
+ const struct synaptics_hw_state *a,
+ const struct synaptics_hw_state *b,
+ int num_fingers)
+{
+ if (num_fingers >= 2) {
+ set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y));
+ set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y));
+ } else if (num_fingers == 1) {
+ set_slot(dev, 0, true, a->x, a->y);
+ set_slot(dev, 1, false, 0, 0);
+ } else {
+ set_slot(dev, 0, false, 0, 0);
+ set_slot(dev, 1, false, 0, 0);
+ }
}
/*
@@ -466,7 +525,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
int finger_width;
int i;
- synaptics_parse_hw_state(psmouse->packet, priv, &hw);
+ if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
+ return;
if (hw.scroll) {
priv->scroll += hw.scroll;
@@ -488,7 +548,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
return;
}
- if (hw.z > 0) {
+ if (hw.z > 0 && hw.x > 1) {
num_fingers = 1;
finger_width = 5;
if (SYN_CAP_EXTENDED(priv->capabilities)) {
@@ -512,6 +572,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
finger_width = 0;
}
+ if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
+ synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers);
+
/* Post events
* BTN_TOUCH has to be first as mousedev relies on it when doing
* absolute -> relative conversion
@@ -519,7 +582,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
- if (hw.z > 0) {
+ if (num_fingers > 0) {
input_report_abs(dev, ABS_X, hw.x);
input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
}
@@ -622,6 +685,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
+ __set_bit(INPUT_PROP_POINTER, dev->propbit);
+
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X,
XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
@@ -629,6 +694,15 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+ if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
+ priv->x_max ?: XMAX_NOMINAL, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
+ priv->y_max ?: YMAX_NOMINAL, 0, 0);
+ }
+
if (SYN_CAP_PALMDETECT(priv->capabilities))
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
@@ -663,6 +737,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_abs_set_res(dev, ABS_Y, priv->y_res);
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
/* Clickpads report only left button */
__clear_bit(BTN_RIGHT, dev->keybit);
__clear_bit(BTN_MIDDLE, dev->keybit);
@@ -702,6 +777,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1;
}
+ if (synaptics_set_advanced_gesture_mode(psmouse)) {
+ printk(KERN_ERR "Advanced gesture mode reconnect failed.\n");
+ return -1;
+ }
+
return 0;
}
@@ -744,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
#endif
};
+static bool broken_olpc_ec;
+
+static const struct dmi_system_id __initconst olpc_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
+ {
+ /* OLPC XO-1 or XO-1.5 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
+ },
+ },
+ { }
+#endif
+};
+
void __init synaptics_module_init(void)
{
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
+ broken_olpc_ec = dmi_check_system(olpc_dmi_table);
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
+ /*
+ * The OLPC XO has issues with Synaptics' absolute mode; similarly to
+ * the HGPK, it quickly degrades and the hardware becomes jumpy and
+ * overly sensitive. Not only that, but the constant packet spew
+ * (even at a lowered 40pps rate) overloads the EC such that key
+ * presses on the keyboard are missed. Given all of that, don't
+ * even attempt to use Synaptics mode. Relative mode seems to work
+ * just fine.
+ */
+ if (broken_olpc_ec) {
+ printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n");
+ return -ENODEV;
+ }
+
psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -769,6 +879,11 @@ int synaptics_init(struct psmouse *psmouse)
goto init_fail;
}
+ if (synaptics_set_advanced_gesture_mode(psmouse)) {
+ printk(KERN_ERR "Advanced gesture mode init failed.\n");
+ goto init_fail;
+ }
+
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
@@ -802,8 +917,8 @@ int synaptics_init(struct psmouse *psmouse)
/*
* Toshiba's KBC seems to have trouble handling data from
- * Synaptics as full rate, switch to lower rate which is roughly
- * thye same as rate of standard PS/2 mouse.
+ * Synaptics at full rate. Switch to a lower rate (roughly
+ * the same rate as a standard PS/2 mouse).
*/
if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 613a3652f98f..25e5d042a72c 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -51,8 +51,10 @@
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
-#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
+#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
+#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
+#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -112,6 +114,8 @@ struct synaptics_data {
int scroll;
struct serio *pt_port; /* Pass-through serio port */
+
+ struct synaptics_hw_state mt; /* current gesture packet */
};
void synaptics_module_init(void);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 2a00ddf4f23a..7630273e9474 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -9,6 +9,8 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define MOUSEDEV_MINOR_BASE 32
#define MOUSEDEV_MINORS 32
#define MOUSEDEV_MIX 31
@@ -977,7 +979,7 @@ static int mousedev_connect(struct input_handler *handler,
break;
if (minor == MOUSEDEV_MINORS) {
- printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+ pr_err("no more free mousedev devices\n");
return -ENFILE;
}
@@ -1087,13 +1089,13 @@ static int __init mousedev_init(void)
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
error = misc_register(&psaux_mouse);
if (error)
- printk(KERN_WARNING "mice: could not register psaux device, "
- "error: %d\n", error);
+ pr_warning("could not register psaux device, error: %d\n",
+ error);
else
psaux_registered = 1;
#endif
- printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
+ pr_info("PS/2 mouse device common for all mice\n");
return 0;
}
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 6256233d2bfb..307eef77a172 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -214,7 +214,6 @@ config SERIO_AMS_DELTA
tristate "Amstrad Delta (E3) mailboard support"
depends on MACH_AMS_DELTA
default y
- select AMS_DELTA_FIQ
---help---
Say Y here if you have an E3 and want to use its mailboard,
or any standard AT keyboard connected to the mailboard port.
@@ -230,7 +229,7 @@ config SERIO_PS2MULT
tristate "TQC PS/2 multiplexer"
help
Say Y here if you have the PS/2 line multiplexer like the one
- present on TQC boads.
+ present on TQC boards.
To compile this driver as a module, choose M here: the
module will be called ps2mult.
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index 8f1770e1e08b..ebe955325677 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -172,6 +172,5 @@ static void __exit ams_delta_serio_exit(void)
free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
- kfree(ams_delta_serio);
}
module_exit(ams_delta_serio_exit);
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 4a3084695c00..448c7724beb9 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -191,6 +191,9 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
serio_register_port(ct82c710_port);
+ printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
+ (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
+
return 0;
}
@@ -237,11 +240,6 @@ static int __init ct82c710_init(void)
if (error)
goto err_free_device;
- serio_register_port(ct82c710_port);
-
- printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
- (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
-
return 0;
err_free_device:
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 3c287dd879d3..4225f5d6b15f 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -358,7 +358,7 @@ static int __devinit gscps2_probe(struct parisc_device *dev)
gscps2_reset(ps2port);
ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f;
- snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
+ snprintf(serio->name, sizeof(serio->name), "gsc-ps2-%s",
(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
serio->id.type = SERIO_8042;
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index e5624d8f1709..bfd3865d886b 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -932,6 +932,11 @@ int hil_mlc_register(hil_mlc *mlc)
hil_mlc_copy_di_scratch(mlc, i);
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
mlc->serio[i] = mlc_serio;
+ if (!mlc->serio[i]) {
+ for (; i >= 0; i--)
+ kfree(mlc->serio[i]);
+ return -ENOMEM;
+ }
snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
mlc_serio->id = hil_mlc_serio_id;
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index 7d2b820ef58d..d50f0678bf47 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -305,6 +305,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
static int __init hp_sdc_mlc_init(void)
{
hil_mlc *mlc = &hp_sdc_mlc;
+ int err;
#ifdef __mc68000__
if (!MACH_IS_HP300)
@@ -323,22 +324,21 @@ static int __init hp_sdc_mlc_init(void)
mlc->out = &hp_sdc_mlc_out;
mlc->priv = &hp_sdc_mlc_priv;
- if (hil_mlc_register(mlc)) {
+ err = hil_mlc_register(mlc);
+ if (err) {
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
- goto err0;
+ return err;
}
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
- goto err1;
+ if (hil_mlc_unregister(mlc))
+ printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+ "This is bad. Could cause an oops.\n");
+ return -EBUSY;
}
+
return 0;
- err1:
- if (hil_mlc_unregister(mlc))
- printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
- "This is bad. Could cause an oops.\n");
- err0:
- return -EBUSY;
}
static void __exit hp_sdc_mlc_exit(void)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index ed7ad7416b24..bb9f5d31f0d0 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -351,6 +351,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
},
},
{
+ /*
+ * Most (all?) VAIOs do not have external PS/2 ports nor
+ * they implement active multiplexing properly, and
+ * MUX discovery usually messes up keyboard/touchpad.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+ },
+ },
+ {
/* Amoi M636/A737 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
@@ -413,6 +424,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
},
},
+ {
+ /* Dell Vostro V13 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+ },
+ },
{ }
};
@@ -534,6 +552,17 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
};
#endif
+static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
+ {
+ /* Dell Vostro V13 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+ },
+ },
+ { }
+};
+
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
@@ -542,6 +571,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
*/
static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
{
+ /* Acer Aspire 5100 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+ },
+ },
+ {
/* Acer Aspire 5610 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -741,7 +777,7 @@ static int __init i8042_pnp_init(void)
#endif
if (i8042_nopnp) {
- printk(KERN_INFO "i8042: PNP detection disabled\n");
+ pr_info("PNP detection disabled\n");
return 0;
}
@@ -758,7 +794,7 @@ static int __init i8042_pnp_init(void)
#if defined(__ia64__)
return -ENODEV;
#else
- printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
+ pr_info("PNP: No PS/2 controller found. Probing ports directly.\n");
return 0;
#endif
}
@@ -770,7 +806,7 @@ static int __init i8042_pnp_init(void)
snprintf(aux_irq_str, sizeof(aux_irq_str),
"%d", i8042_pnp_aux_irq);
- printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
+ pr_info("PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "",
i8042_pnp_aux_name,
i8042_pnp_data_reg, i8042_pnp_command_reg,
@@ -787,9 +823,7 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
i8042_pnp_data_reg != i8042_data_reg) ||
!i8042_pnp_data_reg) {
- printk(KERN_WARNING
- "PNP: PS/2 controller has invalid data port %#x; "
- "using default %#x\n",
+ pr_warn("PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
i8042_pnp_data_reg, i8042_data_reg);
i8042_pnp_data_reg = i8042_data_reg;
pnp_data_busted = true;
@@ -798,33 +832,27 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
i8042_pnp_command_reg != i8042_command_reg) ||
!i8042_pnp_command_reg) {
- printk(KERN_WARNING
- "PNP: PS/2 controller has invalid command port %#x; "
- "using default %#x\n",
+ pr_warn("PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
i8042_pnp_command_reg, i8042_command_reg);
i8042_pnp_command_reg = i8042_command_reg;
pnp_data_busted = true;
}
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
- printk(KERN_WARNING
- "PNP: PS/2 controller doesn't have KBD irq; "
- "using default %d\n", i8042_kbd_irq);
+ pr_warn("PNP: PS/2 controller doesn't have KBD irq; using default %d\n",
+ i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq;
pnp_data_busted = true;
}
if (!i8042_noaux && !i8042_pnp_aux_irq) {
if (!pnp_data_busted && i8042_pnp_kbd_irq) {
- printk(KERN_WARNING
- "PNP: PS/2 appears to have AUX port disabled, "
- "if this is incorrect please boot with "
- "i8042.nopnp\n");
+ pr_warn("PNP: PS/2 appears to have AUX port disabled, "
+ "if this is incorrect please boot with i8042.nopnp\n");
i8042_noaux = true;
} else {
- printk(KERN_WARNING
- "PNP: PS/2 controller doesn't have AUX irq; "
- "using default %d\n", i8042_aux_irq);
+ pr_warn("PNP: PS/2 controller doesn't have AUX irq; using default %d\n",
+ i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq;
}
}
@@ -886,6 +914,9 @@ static int __init i8042_platform_init(void)
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = true;
+ if (dmi_check_system(i8042_dmi_notimeout_table))
+ i8042_notimeout = true;
+
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = true;
#endif /* CONFIG_X86 */
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 18db5a8c7478..ac4c93689ab9 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -10,6 +10,8 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -61,6 +63,10 @@ static bool i8042_noloop;
module_param_named(noloop, i8042_noloop, bool, 0);
MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
+static bool i8042_notimeout;
+module_param_named(notimeout, i8042_notimeout, bool, 0);
+MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
+
#ifdef CONFIG_X86
static bool i8042_dritek;
module_param_named(dritek, i8042_dritek, bool, 0);
@@ -225,8 +231,8 @@ static int i8042_flush(void)
udelay(50);
data = i8042_read_data();
i++;
- dbg("%02x <- i8042 (flush, %s)", data,
- str & I8042_STR_AUXDATA ? "aux" : "kbd");
+ dbg("%02x <- i8042 (flush, %s)\n",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
}
spin_unlock_irqrestore(&i8042_lock, flags);
@@ -253,32 +259,32 @@ static int __i8042_command(unsigned char *param, int command)
if (error)
return error;
- dbg("%02x -> i8042 (command)", command & 0xff);
+ dbg("%02x -> i8042 (command)\n", command & 0xff);
i8042_write_command(command & 0xff);
for (i = 0; i < ((command >> 12) & 0xf); i++) {
error = i8042_wait_write();
if (error)
return error;
- dbg("%02x -> i8042 (parameter)", param[i]);
+ dbg("%02x -> i8042 (parameter)\n", param[i]);
i8042_write_data(param[i]);
}
for (i = 0; i < ((command >> 8) & 0xf); i++) {
error = i8042_wait_read();
if (error) {
- dbg(" -- i8042 (timeout)");
+ dbg(" -- i8042 (timeout)\n");
return error;
}
if (command == I8042_CMD_AUX_LOOP &&
!(i8042_read_status() & I8042_STR_AUXDATA)) {
- dbg(" -- i8042 (auxerr)");
+ dbg(" -- i8042 (auxerr)\n");
return -1;
}
param[i] = i8042_read_data();
- dbg("%02x <- i8042 (return)", param[i]);
+ dbg("%02x <- i8042 (return)\n", param[i]);
}
return 0;
@@ -309,7 +315,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
spin_lock_irqsave(&i8042_lock, flags);
if (!(retval = i8042_wait_write())) {
- dbg("%02x -> i8042 (kbd-data)", c);
+ dbg("%02x -> i8042 (kbd-data)\n", c);
i8042_write_data(c);
}
@@ -355,17 +361,14 @@ static void i8042_port_close(struct serio *serio)
i8042_ctr &= ~irq_bit;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
- printk(KERN_WARNING
- "i8042.c: Can't write CTR while closing %s port.\n",
- port_name);
+ pr_warn("Can't write CTR while closing %s port\n", port_name);
udelay(50);
i8042_ctr &= ~disable_bit;
i8042_ctr |= irq_bit;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
- printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n",
- port_name);
+ pr_err("Can't reactivate %s port\n", port_name);
/*
* See if there is any data appeared while we were messing with
@@ -456,7 +459,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
str = i8042_read_status();
if (unlikely(~str & I8042_STR_OBF)) {
spin_unlock_irqrestore(&i8042_lock, flags);
- if (irq) dbg("Interrupt %d, without any data", irq);
+ if (irq)
+ dbg("Interrupt %d, without any data\n", irq);
ret = 0;
goto out;
}
@@ -469,7 +473,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
dfl = 0;
if (str & I8042_STR_MUXERR) {
- dbg("MUX error, status is %02x, data is %02x", str, data);
+ dbg("MUX error, status is %02x, data is %02x\n",
+ str, data);
/*
* When MUXERR condition is signalled the data register can only contain
* 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
@@ -503,7 +508,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
} else {
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
- ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+ ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
port_no = (str & I8042_STR_AUXDATA) ?
I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
@@ -512,7 +517,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
port = &i8042_ports[port_no];
serio = port->exists ? port->serio : NULL;
- dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
+ dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
data, port_no, irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
@@ -540,7 +545,7 @@ static int i8042_enable_kbd_port(void)
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
i8042_ctr &= ~I8042_CTR_KBDINT;
i8042_ctr |= I8042_CTR_KBDDIS;
- printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
+ pr_err("Failed to enable KBD port\n");
return -EIO;
}
@@ -559,7 +564,7 @@ static int i8042_enable_aux_port(void)
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
i8042_ctr &= ~I8042_CTR_AUXINT;
i8042_ctr |= I8042_CTR_AUXDIS;
- printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
+ pr_err("Failed to enable AUX port\n");
return -EIO;
}
@@ -641,7 +646,7 @@ static int __init i8042_check_mux(void)
if (i8042_set_mux_mode(true, &mux_version))
return -1;
- printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
+ pr_info("Detected active multiplexing controller, rev %d.%d\n",
(mux_version >> 4) & 0xf, mux_version & 0xf);
/*
@@ -651,7 +656,7 @@ static int __init i8042_check_mux(void)
i8042_ctr &= ~I8042_CTR_AUXINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
+ pr_err("Failed to disable AUX port, can't use MUX\n");
return -EIO;
}
@@ -676,8 +681,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
str = i8042_read_status();
if (str & I8042_STR_OBF) {
data = i8042_read_data();
- dbg("%02x <- i8042 (aux_test_irq, %s)",
- data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+ dbg("%02x <- i8042 (aux_test_irq, %s)\n",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
if (i8042_irq_being_tested &&
data == 0xa5 && (str & I8042_STR_AUXDATA))
complete(&i8042_aux_irq_delivered);
@@ -770,8 +775,8 @@ static int __init i8042_check_aux(void)
*/
if (i8042_toggle_aux(false)) {
- printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
- printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
+ pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
+ pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
}
if (i8042_toggle_aux(true))
@@ -819,7 +824,7 @@ static int __init i8042_check_aux(void)
* AUX IRQ was never delivered so we need to flush the controller to
* get rid of the byte we put there; otherwise keyboard may not work.
*/
- dbg(" -- i8042 (aux irq test timeout)");
+ dbg(" -- i8042 (aux irq test timeout)\n");
i8042_flush();
retval = -1;
}
@@ -845,7 +850,7 @@ static int __init i8042_check_aux(void)
static int i8042_controller_check(void)
{
if (i8042_flush() == I8042_BUFFER_SIZE) {
- printk(KERN_ERR "i8042.c: No controller found.\n");
+ pr_err("No controller found\n");
return -ENODEV;
}
@@ -864,15 +869,15 @@ static int i8042_controller_selftest(void)
do {
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
- printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+ pr_err("i8042 controller self test timeout\n");
return -ENODEV;
}
if (param == I8042_RET_CTL_TEST)
return 0;
- printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
- param, I8042_RET_CTL_TEST);
+ pr_err("i8042 controller selftest failed. (%#x != %#x)\n",
+ param, I8042_RET_CTL_TEST);
msleep(50);
} while (i++ < 5);
@@ -883,8 +888,7 @@ static int i8042_controller_selftest(void)
* and user will still get a working keyboard. This is especially
* important on netbooks. On other arches we trust hardware more.
*/
- printk(KERN_INFO
- "i8042: giving up on controller selftest, continuing anyway...\n");
+ pr_info("giving up on controller selftest, continuing anyway...\n");
return 0;
#else
return -EIO;
@@ -909,8 +913,7 @@ static int i8042_controller_init(void)
do {
if (n >= 10) {
- printk(KERN_ERR
- "i8042.c: Unable to get stable CTR read.\n");
+ pr_err("Unable to get stable CTR read\n");
return -EIO;
}
@@ -918,8 +921,7 @@ static int i8042_controller_init(void)
udelay(50);
if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
- printk(KERN_ERR
- "i8042.c: Can't read CTR while initializing i8042.\n");
+ pr_err("Can't read CTR while initializing i8042\n");
return -EIO;
}
@@ -943,7 +945,7 @@ static int i8042_controller_init(void)
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
- printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
+ pr_warn("Warning: Keylock active\n");
}
spin_unlock_irqrestore(&i8042_lock, flags);
@@ -970,7 +972,7 @@ static int i8042_controller_init(void)
*/
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
+ pr_err("Can't write CTR while initializing i8042\n");
return -EIO;
}
@@ -1000,7 +1002,7 @@ static void i8042_controller_reset(void)
i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
- printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n");
+ pr_warn("Can't write CTR while resetting\n");
/*
* Disable MUX mode if present.
@@ -1021,7 +1023,7 @@ static void i8042_controller_reset(void)
*/
if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
- printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
+ pr_warn("Can't restore CTR\n");
}
@@ -1045,14 +1047,14 @@ static long i8042_panic_blink(int state)
led = (state) ? 0x01 | 0x04 : 0;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
- dbg("%02x -> i8042 (panic blink)", 0xed);
+ dbg("%02x -> i8042 (panic blink)\n", 0xed);
i8042_suppress_kbd_ack = 2;
i8042_write_data(0xed); /* set leds */
DELAY;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
DELAY;
- dbg("%02x -> i8042 (panic blink)", led);
+ dbg("%02x -> i8042 (panic blink)\n", led);
i8042_write_data(led);
DELAY;
return delay;
@@ -1068,9 +1070,7 @@ static void i8042_dritek_enable(void)
error = i8042_command(&param, 0x1059);
if (error)
- printk(KERN_WARNING
- "Failed to enable DRITEK extension: %d\n",
- error);
+ pr_warn("Failed to enable DRITEK extension: %d\n", error);
}
#endif
@@ -1105,10 +1105,10 @@ static int i8042_controller_resume(bool force_reset)
i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n");
+ pr_warn("Can't write CTR to resume, retrying...\n");
msleep(50);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042: CTR write retry failed\n");
+ pr_err("CTR write retry failed\n");
return -EIO;
}
}
@@ -1121,9 +1121,7 @@ static int i8042_controller_resume(bool force_reset)
if (i8042_mux_present) {
if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
- printk(KERN_WARNING
- "i8042: failed to resume active multiplexor, "
- "mouse won't work.\n");
+ pr_warn("failed to resume active multiplexor, mouse won't work\n");
} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
i8042_enable_aux_port();
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index cbc1beb66574..ac1d759d0f55 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -89,15 +89,19 @@
#ifdef DEBUG
static unsigned long i8042_start_time;
#define dbg_init() do { i8042_start_time = jiffies; } while (0)
-#define dbg(format, arg...) \
- do { \
+#define dbg(format, arg...) \
+ do { \
if (i8042_debug) \
- printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \
- ## arg, (int) (jiffies - i8042_start_time)); \
+ printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format, \
+ (int) (jiffies - i8042_start_time), ##arg); \
} while (0)
#else
#define dbg_init() do { } while (0)
-#define dbg(format, arg...) do {} while (0)
+#define dbg(format, arg...) \
+ do { \
+ if (0) \
+ printk(KERN_DEBUG pr_fmt(format), ##arg); \
+ } while (0)
#endif
#endif /* _I8042_H */
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index 6bce22e4e495..15aa81c9f1fb 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -207,7 +207,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
err_out:
while (--i >= 0)
kfree(psm->ports[i].serio);
- kfree(serio);
+ kfree(psm);
return error;
}
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 405bf214527c..db5b0bca1a1a 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -32,10 +32,9 @@
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
-#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
#include <linux/mutex.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL");
/*
* serio_mutex protects entire serio subsystem and is taken every time
- * serio port or driver registrered or unregistered.
+ * serio port or driver registered or unregistered.
*/
static DEFINE_MUTEX(serio_mutex);
@@ -165,58 +164,22 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
static LIST_HEAD(serio_event_list);
-static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static struct task_struct *serio_task;
-static int serio_queue_event(void *object, struct module *owner,
- enum serio_event_type event_type)
+static struct serio_event *serio_get_event(void)
{
+ struct serio_event *event = NULL;
unsigned long flags;
- struct serio_event *event;
- int retval = 0;
spin_lock_irqsave(&serio_event_lock, flags);
- /*
- * Scan event list for the other events for the same serio port,
- * starting with the most recent one. If event is the same we
- * do not need add new one. If event is of different type we
- * need to add this event and should not look further because
- * we need to preseve sequence of distinct events.
- */
- list_for_each_entry_reverse(event, &serio_event_list, node) {
- if (event->object == object) {
- if (event->type == event_type)
- goto out;
- break;
- }
- }
-
- event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
- if (!event) {
- pr_err("Not enough memory to queue event %d\n", event_type);
- retval = -ENOMEM;
- goto out;
- }
-
- if (!try_module_get(owner)) {
- pr_warning("Can't get module reference, dropping event %d\n",
- event_type);
- kfree(event);
- retval = -EINVAL;
- goto out;
+ if (!list_empty(&serio_event_list)) {
+ event = list_first_entry(&serio_event_list,
+ struct serio_event, node);
+ list_del_init(&event->node);
}
- event->type = event_type;
- event->object = object;
- event->owner = owner;
-
- list_add_tail(&event->node, &serio_event_list);
- wake_up(&serio_wait);
-
-out:
spin_unlock_irqrestore(&serio_event_lock, flags);
- return retval;
+ return event;
}
static void serio_free_event(struct serio_event *event)
@@ -250,25 +213,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
spin_unlock_irqrestore(&serio_event_lock, flags);
}
-
-static struct serio_event *serio_get_event(void)
-{
- struct serio_event *event = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&serio_event_lock, flags);
-
- if (!list_empty(&serio_event_list)) {
- event = list_first_entry(&serio_event_list,
- struct serio_event, node);
- list_del_init(&event->node);
- }
-
- spin_unlock_irqrestore(&serio_event_lock, flags);
- return event;
-}
-
-static void serio_handle_event(void)
+static void serio_handle_event(struct work_struct *work)
{
struct serio_event *event;
@@ -307,6 +252,59 @@ static void serio_handle_event(void)
mutex_unlock(&serio_mutex);
}
+static DECLARE_WORK(serio_event_work, serio_handle_event);
+
+static int serio_queue_event(void *object, struct module *owner,
+ enum serio_event_type event_type)
+{
+ unsigned long flags;
+ struct serio_event *event;
+ int retval = 0;
+
+ spin_lock_irqsave(&serio_event_lock, flags);
+
+ /*
+ * Scan event list for the other events for the same serio port,
+ * starting with the most recent one. If event is the same we
+ * do not need add new one. If event is of different type we
+ * need to add this event and should not look further because
+ * we need to preseve sequence of distinct events.
+ */
+ list_for_each_entry_reverse(event, &serio_event_list, node) {
+ if (event->object == object) {
+ if (event->type == event_type)
+ goto out;
+ break;
+ }
+ }
+
+ event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
+ if (!event) {
+ pr_err("Not enough memory to queue event %d\n", event_type);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (!try_module_get(owner)) {
+ pr_warning("Can't get module reference, dropping event %d\n",
+ event_type);
+ kfree(event);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ event->type = event_type;
+ event->object = object;
+ event->owner = owner;
+
+ list_add_tail(&event->node, &serio_event_list);
+ schedule_work(&serio_event_work);
+
+out:
+ spin_unlock_irqrestore(&serio_event_lock, flags);
+ return retval;
+}
+
/*
* Remove all events that have been submitted for a given
* object, be it serio port or driver.
@@ -356,18 +354,6 @@ static struct serio *serio_get_pending_child(struct serio *parent)
return child;
}
-static int serio_thread(void *nothing)
-{
- do {
- serio_handle_event();
- wait_event_interruptible(serio_wait,
- kthread_should_stop() || !list_empty(&serio_event_list));
- } while (!kthread_should_stop());
-
- return 0;
-}
-
-
/*
* Serio port operations
*/
@@ -1040,21 +1026,18 @@ static int __init serio_init(void)
return error;
}
- serio_task = kthread_run(serio_thread, NULL, "kseriod");
- if (IS_ERR(serio_task)) {
- bus_unregister(&serio_bus);
- error = PTR_ERR(serio_task);
- pr_err("Failed to start kseriod, error: %d\n", error);
- return error;
- }
-
return 0;
}
static void __exit serio_exit(void)
{
bus_unregister(&serio_bus);
- kthread_stop(serio_task);
+
+ /*
+ * There should not be any outstanding events but work may
+ * still be scheduled so simply cancel it.
+ */
+ cancel_work_sync(&serio_event_work);
}
subsys_initcall(serio_init);
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index cd82bb125915..b7ba4597f7f0 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serio.h>
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index aea9a9399a36..d94f7e9aa997 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -229,12 +229,13 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
err = input_register_device(acecad->input);
if (err)
- goto fail2;
+ goto fail3;
usb_set_intfdata(intf, acecad);
return 0;
+ fail3: usb_free_urb(acecad->irq);
fail2: usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
fail1: input_free_device(input_dev);
kfree(acecad);
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 57b25b84d1fc..0a619c558bfb 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1097,7 +1097,7 @@ store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(pointer_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletPointerMode, store_tabletPointerMode);
/***********************************************************************
@@ -1134,7 +1134,7 @@ store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, co
}
static DEVICE_ATTR(coordinate_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletCoordinateMode, store_tabletCoordinateMode);
/***********************************************************************
@@ -1176,7 +1176,7 @@ store_tabletToolMode(struct device *dev, struct device_attribute *attr, const ch
}
static DEVICE_ATTR(tool_mode,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletToolMode, store_tabletToolMode);
/***********************************************************************
@@ -1219,7 +1219,7 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char
}
static DEVICE_ATTR(xtilt,
- S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
+ S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt);
/***********************************************************************
* support routines for the 'ytilt' file. Note that this file
@@ -1261,7 +1261,7 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char
}
static DEVICE_ATTR(ytilt,
- S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
+ S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt);
/***********************************************************************
* support routines for the 'jitter' file. Note that this file
@@ -1288,7 +1288,7 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(jitter,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletJitterDelay, store_tabletJitterDelay);
/***********************************************************************
@@ -1317,7 +1317,7 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(delay,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletProgrammableDelay, store_tabletProgrammableDelay);
/***********************************************************************
@@ -1406,7 +1406,7 @@ store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(stylus_upper,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletStylusUpper, store_tabletStylusUpper);
/***********************************************************************
@@ -1437,7 +1437,7 @@ store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(stylus_lower,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletStylusLower, store_tabletStylusLower);
/***********************************************************************
@@ -1475,7 +1475,7 @@ store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const c
}
static DEVICE_ATTR(mouse_left,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseLeft, store_tabletMouseLeft);
/***********************************************************************
@@ -1505,7 +1505,7 @@ store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(mouse_middle,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseMiddle, store_tabletMouseMiddle);
/***********************************************************************
@@ -1535,7 +1535,7 @@ store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(mouse_right,
- S_IRUGO | S_IWUGO,
+ S_IRUGO | S_IWUSR,
show_tabletMouseRight, store_tabletMouseRight);
/***********************************************************************
@@ -1567,7 +1567,7 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char
}
static DEVICE_ATTR(wheel,
- S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
+ S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel);
/***********************************************************************
* support routines for the 'execute' file. Note that this file
@@ -1600,7 +1600,7 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha
}
static DEVICE_ATTR(execute,
- S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
+ S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute);
/***********************************************************************
* support routines for the 'odm_code' file. Note that this file
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index de5adb109030..23317bd09c82 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -103,6 +103,7 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_VENDOR_ID_LENOVO 0x17ef
struct wacom {
dma_addr_t data_dma;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index b3252ef1e279..518782999fea 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -14,6 +14,7 @@
#include "wacom_wac.h"
#include "wacom.h"
+#include <linux/input/mt.h>
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
@@ -862,19 +863,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
- int sp = 0, sx = 0, sy = 0, count = 0;
int i;
for (i = 0; i < 2; i++) {
int p = data[9 * i + 2];
+ bool touch = p && !wacom->shared->stylus_in_proximity;
+
input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/*
* Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons
* to continue working though.
*/
- if (p && !wacom->shared->stylus_in_proximity) {
+ if (touch) {
int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
@@ -884,23 +887,10 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- if (wacom->id[i] < 0)
- wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
- if (!count++)
- sp = p, sx = x, sy = y;
- } else {
- wacom->id[i] = -1;
}
- input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
}
- input_report_key(input, BTN_TOUCH, count > 0);
- input_report_key(input, BTN_TOOL_FINGER, count == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
-
- input_report_abs(input, ABS_PRESSURE, sp);
- input_report_abs(input, ABS_X, sx);
- input_report_abs(input, ABS_Y, sy);
+ input_mt_report_pointer_emulation(input, true);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
@@ -1272,7 +1262,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- input_mt_create_slots(input_dev, 2);
+ input_mt_init_slots(input_dev, 2);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max,
features->x_fuzz, 0);
@@ -1282,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
features->pressure_fuzz, 0);
- input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
- MAX_TRACKING_ID, 0, 0);
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1436,11 +1424,25 @@ static struct wacom_features wacom_features_0xD2 =
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
static struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
+static const struct wacom_features wacom_features_0xD4 =
+ { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD8 =
+ { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xDA =
+ { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xDB =
+ { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
+static const struct wacom_features wacom_features_0x6004 =
+ { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC };
#define USB_DEVICE_WACOM(prod) \
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
.driver_info = (kernel_ulong_t)&wacom_features_##prod
+#define USB_DEVICE_LENOVO(prod) \
+ USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \
+ .driver_info = (kernel_ulong_t)&wacom_features_##prod
+
const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x00) },
{ USB_DEVICE_WACOM(0x10) },
@@ -1504,6 +1506,10 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xD1) },
{ USB_DEVICE_WACOM(0xD2) },
{ USB_DEVICE_WACOM(0xD3) },
+ { USB_DEVICE_WACOM(0xD4) },
+ { USB_DEVICE_WACOM(0xD8) },
+ { USB_DEVICE_WACOM(0xDA) },
+ { USB_DEVICE_WACOM(0xDB) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
@@ -1513,6 +1519,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xE2) },
{ USB_DEVICE_WACOM(0xE3) },
{ USB_DEVICE_WACOM(0x47) },
+ { USB_DEVICE_LENOVO(0x6004) },
{ }
};
MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 00ca01541d89..b1310ec9720c 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -42,9 +42,6 @@
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
-/* largest reported tracking id */
-#define MAX_TRACKING_ID 0xfff
-
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -100,7 +97,6 @@ struct wacom_wac {
int id[3];
__u32 serial[2];
int last_finger;
- int trk_id;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 06ea8da95c62..0c9f4b158ff0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -610,7 +610,7 @@ config TOUCHSCREEN_USB_ZYTRONIC
config TOUCHSCREEN_USB_ETT_TC45USB
default y
- bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
+ bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
@@ -659,17 +659,17 @@ config TOUCHSCREEN_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
-config TOUCHSCREEN_TPS6507X
- tristate "TPS6507x based touchscreens"
+config TOUCHSCREEN_ST1232
+ tristate "Sitronix ST1232 touchscreen controllers"
depends on I2C
help
- Say Y here if you have a TPS6507x based touchscreen
- controller.
+ Say Y here if you want to support Sitronix ST1232
+ touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
- module will be called tps6507x_ts.
+ module will be called st1232_ts.
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
@@ -681,4 +681,16 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
+config TOUCHSCREEN_TPS6507X
+ tristate "TPS6507x based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a TPS6507x based touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tps6507x_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7cc1b4f4b677..718bcc814952 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index d82a38ee9a3e..4e4e58cec6c8 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -10,14 +10,16 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/pm.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM
-static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int ad7879_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_suspend(ts);
@@ -25,17 +27,17 @@ static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
return 0;
}
-static int ad7879_i2c_resume(struct i2c_client *client)
+static int ad7879_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_resume(ts);
return 0;
}
-#else
-# define ad7879_i2c_suspend NULL
-# define ad7879_i2c_resume NULL
+
+static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
#endif
/* All registers are word-sized.
@@ -117,11 +119,12 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ad7879_i2c_pm,
+#endif
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),
- .suspend = ad7879_i2c_suspend,
- .resume = ad7879_i2c_resume,
.id_table = ad7879_id,
};
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index ba6f0bd1e762..bc3b5187f3a3 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -129,6 +129,9 @@ struct ad7879 {
u16 cmd_crtl1;
u16 cmd_crtl2;
u16 cmd_crtl3;
+ int x;
+ int y;
+ int Rt;
};
static int ad7879_read(struct ad7879 *ts, u8 reg)
@@ -175,13 +178,32 @@ static int ad7879_report(struct ad7879 *ts)
Rt /= z1;
Rt = (Rt + 2047) >> 12;
- if (!timer_pending(&ts->timer))
+ /*
+ * Sample found inconsistent, pressure is beyond
+ * the maximum. Don't report it to user space.
+ */
+ if (Rt > ts->pressure_max)
+ return -EINVAL;
+
+ /*
+ * Note that we delay reporting events by one sample.
+ * This is done to avoid reporting last sample of the
+ * touch sequence, which may be incomplete if finger
+ * leaves the surface before last reading is taken.
+ */
+ if (timer_pending(&ts->timer)) {
+ /* Touch continues */
input_report_key(input_dev, BTN_TOUCH, 1);
+ input_report_abs(input_dev, ABS_X, ts->x);
+ input_report_abs(input_dev, ABS_Y, ts->y);
+ input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
+ input_sync(input_dev);
+ }
+
+ ts->x = x;
+ ts->y = y;
+ ts->Rt = Rt;
- input_report_abs(input_dev, ABS_X, x);
- input_report_abs(input_dev, ABS_Y, y);
- input_report_abs(input_dev, ABS_PRESSURE, Rt);
- input_sync(input_dev);
return 0;
}
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index ccde58602563..f7fa9ef4cd65 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -365,7 +365,7 @@ static int bu21013_init_chip(struct bu21013_ts_data *data)
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
- BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+ BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
return retval;
@@ -514,7 +514,7 @@ err_free_irq:
err_cs_disable:
pdata->cs_dis(pdata->cs_pin);
err_free_mem:
- input_free_device(bu21013_data->in_dev);
+ input_free_device(in_dev);
kfree(bu21013_data);
return error;
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index d0c3a7229adf..a93c5c26ab3f 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -280,8 +280,9 @@ err_free_mem:
}
#ifdef CONFIG_PM
-static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+static int cy8ctmg110_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
@@ -293,8 +294,9 @@ static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int cy8ctmg110_resume(struct i2c_client *client)
+static int cy8ctmg110_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
@@ -305,6 +307,8 @@ static int cy8ctmg110_resume(struct i2c_client *client)
}
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
#endif
static int __devexit cy8ctmg110_remove(struct i2c_client *client)
@@ -335,14 +339,13 @@ static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.owner = THIS_MODULE,
.name = CY8CTMG110_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &cy8ctmg110_pm,
+#endif
},
.id_table = cy8ctmg110_idtable,
.probe = cy8ctmg110_probe,
.remove = __devexit_p(cy8ctmg110_remove),
-#ifdef CONFIG_PM
- .suspend = cy8ctmg110_suspend,
- .resume = cy8ctmg110_resume,
-#endif
};
static int __init cy8ctmg110_init(void)
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 7a3a916f84a8..7f8f538a9806 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -261,8 +261,9 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int eeti_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
@@ -279,8 +280,9 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int eeti_ts_resume(struct i2c_client *client)
+static int eeti_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
@@ -296,9 +298,8 @@ static int eeti_ts_resume(struct i2c_client *client)
return 0;
}
-#else
-#define eeti_ts_suspend NULL
-#define eeti_ts_resume NULL
+
+static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
#endif
static const struct i2c_device_id eeti_ts_id[] = {
@@ -310,11 +311,12 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
+#ifdef CONFIG_PM
+ .pm = &eeti_ts_pm,
+#endif
},
.probe = eeti_ts_probe,
.remove = __devexit_p(eeti_ts_remove),
- .suspend = eeti_ts_suspend,
- .resume = eeti_ts_resume,
.id_table = eeti_ts_id,
};
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 6ee9940aaf5b..2d84c80ceb66 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -261,25 +261,27 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int mcs5000_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
/* Touch sleep mode */
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
return 0;
}
-static int mcs5000_ts_resume(struct i2c_client *client)
+static int mcs5000_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
mcs5000_ts_phys_init(data);
return 0;
}
-#else
-#define mcs5000_ts_suspend NULL
-#define mcs5000_ts_resume NULL
+
+static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = {
@@ -291,10 +293,11 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.remove = __devexit_p(mcs5000_ts_remove),
- .suspend = mcs5000_ts_suspend,
- .resume = mcs5000_ts_resume,
.driver = {
.name = "mcs5000_ts",
+#ifdef CONFIG_PM
+ .pm = &mcs5000_ts_pm,
+#endif
},
.id_table = mcs5000_ts_id,
};
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index defe5dd3627c..5803bd0c1cca 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/pm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/i2c.h>
@@ -226,8 +227,9 @@ static int migor_ts_remove(struct i2c_client *client)
return 0;
}
-static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+static int migor_ts_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
@@ -236,8 +238,9 @@ static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int migor_ts_resume(struct i2c_client *client)
+static int migor_ts_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
@@ -246,6 +249,8 @@ static int migor_ts_resume(struct i2c_client *client)
return 0;
}
+static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
+
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
{ }
@@ -255,11 +260,10 @@ MODULE_DEVICE_TABLE(i2c, migor_ts);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
+ .pm = &migor_ts_pm,
},
.probe = migor_ts_probe,
.remove = migor_ts_remove,
- .suspend = migor_ts_suspend,
- .resume = migor_ts_resume,
.id_table = migor_ts_id,
};
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
index 66b26ad3032a..4dcb0e872f6a 100644
--- a/drivers/input/touchscreen/qt602240_ts.c
+++ b/drivers/input/touchscreen/qt602240_ts.c
@@ -969,7 +969,7 @@ static int qt602240_initialize(struct qt602240_data *data)
return error;
data->object_table = kcalloc(info->object_num,
- sizeof(struct qt602240_data),
+ sizeof(struct qt602240_object),
GFP_KERNEL);
if (!data->object_table) {
dev_err(&client->dev, "Failed to allocate memory\n");
@@ -1324,8 +1324,9 @@ static int __devexit qt602240_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
+static int qt602240_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct qt602240_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
@@ -1339,8 +1340,9 @@ static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int qt602240_resume(struct i2c_client *client)
+static int qt602240_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct qt602240_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
@@ -1359,9 +1361,11 @@ static int qt602240_resume(struct i2c_client *client)
return 0;
}
-#else
-#define qt602240_suspend NULL
-#define qt602240_resume NULL
+
+static const struct dev_pm_ops qt602240_pm_ops = {
+ .suspend = qt602240_suspend,
+ .resume = qt602240_resume,
+};
#endif
static const struct i2c_device_id qt602240_id[] = {
@@ -1374,11 +1378,12 @@ static struct i2c_driver qt602240_driver = {
.driver = {
.name = "qt602240_ts",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &qt602240_pm_ops,
+#endif
},
.probe = qt602240_probe,
.remove = __devexit_p(qt602240_remove),
- .suspend = qt602240_suspend,
- .resume = qt602240_resume,
.id_table = qt602240_id,
};
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
new file mode 100644
index 000000000000..4ab371358b33
--- /dev/null
+++ b/drivers/input/touchscreen/st1232.c
@@ -0,0 +1,274 @@
+/*
+ * ST1232 Touchscreen Controller Driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Tony SIM <chinyeow.sim.xt@renesas.com>
+ *
+ * Using code from:
+ * - android.git.kernel.org: projects/kernel/common.git: synaptics_i2c_rmi.c
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define ST1232_TS_NAME "st1232-ts"
+
+#define MIN_X 0x00
+#define MIN_Y 0x00
+#define MAX_X 0x31f /* (800 - 1) */
+#define MAX_Y 0x1df /* (480 - 1) */
+#define MAX_AREA 0xff
+#define MAX_FINGERS 2
+
+struct st1232_ts_finger {
+ u16 x;
+ u16 y;
+ u8 t;
+ bool is_valid;
+};
+
+struct st1232_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct st1232_ts_finger finger[MAX_FINGERS];
+};
+
+static int st1232_ts_read_data(struct st1232_ts_data *ts)
+{
+ struct st1232_ts_finger *finger = ts->finger;
+ struct i2c_client *client = ts->client;
+ struct i2c_msg msg[2];
+ int error;
+ u8 start_reg;
+ u8 buf[10];
+
+ /* read touchscreen data from ST1232 */
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &start_reg;
+ start_reg = 0x10;
+
+ msg[1].addr = ts->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(buf);
+ msg[1].buf = buf;
+
+ error = i2c_transfer(client->adapter, msg, 2);
+ if (error < 0)
+ return error;
+
+ /* get "valid" bits */
+ finger[0].is_valid = buf[2] >> 7;
+ finger[1].is_valid = buf[5] >> 7;
+
+ /* get xy coordinate */
+ if (finger[0].is_valid) {
+ finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3];
+ finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4];
+ finger[0].t = buf[8];
+ }
+
+ if (finger[1].is_valid) {
+ finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6];
+ finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7];
+ finger[1].t = buf[9];
+ }
+
+ return 0;
+}
+
+static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
+{
+ struct st1232_ts_data *ts = dev_id;
+ struct st1232_ts_finger *finger = ts->finger;
+ struct input_dev *input_dev = ts->input_dev;
+ int count = 0;
+ int i, ret;
+
+ ret = st1232_ts_read_data(ts);
+ if (ret < 0)
+ goto end;
+
+ /* multi touch protocol */
+ for (i = 0; i < MAX_FINGERS; i++) {
+ if (!finger[i].is_valid)
+ continue;
+
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
+ input_mt_sync(input_dev);
+ count++;
+ }
+
+ /* SYN_MT_REPORT only if no contact */
+ if (!count)
+ input_mt_sync(input_dev);
+
+ /* SYN_REPORT */
+ input_sync(input_dev);
+
+end:
+ return IRQ_HANDLED;
+}
+
+static int __devinit st1232_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct st1232_ts_data *ts;
+ struct input_dev *input_dev;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "need I2C_FUNC_I2C\n");
+ return -EIO;
+ }
+
+ if (!client->irq) {
+ dev_err(&client->dev, "no IRQ?\n");
+ return -EINVAL;
+ }
+
+
+ ts = kzalloc(sizeof(struct st1232_ts_data), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts->client = client;
+ ts->input_dev = input_dev;
+
+ input_dev->name = "st1232-touchscreen";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_SYN, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
+
+ error = request_threaded_irq(client->irq, NULL, st1232_ts_irq_handler,
+ IRQF_ONESHOT, client->name, ts);
+ if (error) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(ts->input_dev);
+ if (error) {
+ dev_err(&client->dev, "Unable to register %s input device\n",
+ input_dev->name);
+ goto err_free_irq;
+ }
+
+ i2c_set_clientdata(client, ts);
+ device_init_wakeup(&client->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, ts);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts);
+ return error;
+}
+
+static int __devexit st1232_ts_remove(struct i2c_client *client)
+{
+ struct st1232_ts_data *ts = i2c_get_clientdata(client);
+
+ device_init_wakeup(&client->dev, 0);
+ free_irq(client->irq, ts);
+ input_unregister_device(ts->input_dev);
+ kfree(ts);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int st1232_ts_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+ else
+ disable_irq(client->irq);
+
+ return 0;
+}
+
+static int st1232_ts_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+ else
+ enable_irq(client->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops st1232_ts_pm_ops = {
+ .suspend = st1232_ts_suspend,
+ .resume = st1232_ts_resume,
+};
+#endif
+
+static const struct i2c_device_id st1232_ts_id[] = {
+ { ST1232_TS_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
+
+static struct i2c_driver st1232_ts_driver = {
+ .probe = st1232_ts_probe,
+ .remove = __devexit_p(st1232_ts_remove),
+ .id_table = st1232_ts_id,
+ .driver = {
+ .name = ST1232_TS_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &st1232_ts_pm_ops,
+#endif
+ },
+};
+
+static int __init st1232_ts_init(void)
+{
+ return i2c_add_driver(&st1232_ts_driver);
+}
+module_init(st1232_ts_init);
+
+static void __exit st1232_ts_exit(void)
+{
+ i2c_del_driver(&st1232_ts_driver);
+}
+module_exit(st1232_ts_exit);
+
+MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
+MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index f45f80f6d336..73fd6642b681 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -178,6 +178,7 @@ static const struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_ITM
{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
+ {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 9ae4c7b16ba7..5cb8449c909d 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2008 Jaya Kumar
* Copyright (c) 2010 Red Hat, Inc.
+ * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.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
@@ -15,10 +16,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#define DRIVER_DESC "Wacom W8001 serial touchscreen driver"
@@ -37,6 +39,7 @@ MODULE_LICENSE("GPL");
#define W8001_QUERY_PACKET 0x20
+#define W8001_CMD_STOP '0'
#define W8001_CMD_START '1'
#define W8001_CMD_QUERY '*'
#define W8001_CMD_TOUCHQUERY '%'
@@ -48,8 +51,6 @@ MODULE_LICENSE("GPL");
#define W8001_PKTLEN_TPCCTL 11 /* control packet */
#define W8001_PKTLEN_TOUCH2FG 13
-#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
-
struct w8001_coord {
u8 rdy;
u8 tsw;
@@ -64,11 +65,11 @@ struct w8001_coord {
/* touch query reply packet */
struct w8001_touch_query {
+ u16 x;
+ u16 y;
u8 panel_res;
u8 capacity_res;
u8 sensor_id;
- u16 x;
- u16 y;
};
/*
@@ -87,10 +88,14 @@ struct w8001 {
char phys[32];
int type;
unsigned int pktlen;
- int trkid[2];
+ u16 max_touch_x;
+ u16 max_touch_y;
+ u16 max_pen_x;
+ u16 max_pen_y;
+ char name[64];
};
-static void parse_data(u8 *data, struct w8001_coord *coord)
+static void parse_pen_data(u8 *data, struct w8001_coord *coord)
{
memset(coord, 0, sizeof(*coord));
@@ -114,30 +119,58 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
coord->tilt_y = data[8] & 0x7F;
}
-static void parse_touch(struct w8001 *w8001)
+static void parse_single_touch(u8 *data, struct w8001_coord *coord)
+{
+ coord->x = (data[1] << 7) | data[2];
+ coord->y = (data[3] << 7) | data[4];
+ coord->tsw = data[0] & 0x01;
+}
+
+static void scale_touch_coordinates(struct w8001 *w8001,
+ unsigned int *x, unsigned int *y)
+{
+ if (w8001->max_pen_x && w8001->max_touch_x)
+ *x = *x * w8001->max_pen_x / w8001->max_touch_x;
+
+ if (w8001->max_pen_y && w8001->max_touch_y)
+ *y = *y * w8001->max_pen_y / w8001->max_touch_y;
+}
+
+static void parse_multi_touch(struct w8001 *w8001)
{
- static int trkid;
struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data;
+ unsigned int x, y;
int i;
+ int count = 0;
for (i = 0; i < 2; i++) {
- input_mt_slot(dev, i);
+ bool touch = data[0] & (1 << i);
- if (data[0] & (1 << i)) {
- int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
- int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
+ if (touch) {
+ x = (data[6 * i + 1] << 7) | data[6 * i + 2];
+ y = (data[6 * i + 3] << 7) | data[6 * i + 4];
/* data[5,6] and [11,12] is finger capacity */
+ /* scale to pen maximum */
+ scale_touch_coordinates(w8001, &x, &y);
+
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
- input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- if (w8001->trkid[i] < 0)
- w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
- } else {
- w8001->trkid[i] = -1;
+ count++;
}
- input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
+ }
+
+ /* emulate single touch events when stylus is out of proximity.
+ * This is to make single touch backward support consistent
+ * across all Wacom single touch devices.
+ */
+ if (w8001->type != BTN_TOOL_PEN &&
+ w8001->type != BTN_TOOL_RUBBER) {
+ w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED;
+ input_mt_report_pointer_emulation(dev, true);
}
input_sync(dev);
@@ -158,6 +191,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
query->y = data[5] << 9;
query->y |= data[6] << 2;
query->y |= (data[2] >> 3) & 0x3;
+
+ /* Early days' single-finger touch models need the following defaults */
+ if (!query->x && !query->y) {
+ query->x = 1024;
+ query->y = 1024;
+ if (query->panel_res)
+ query->x = query->y = (1 << query->panel_res);
+ query->panel_res = 10;
+ }
}
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
@@ -167,16 +209,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
/*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side,
* side2/eraser. If rdy && f2 are set, this can be either pen + side2,
- * or eraser. assume
+ * or eraser. Assume:
* - if dev is already in proximity and f2 is toggled → pen + side2
* - if dev comes into proximity with f2 set → eraser
* If f2 disappears after assuming eraser, fake proximity out for
* eraser and in for pen.
*/
- if (!w8001->type) {
- w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- } else if (w8001->type == BTN_TOOL_RUBBER) {
+ switch (w8001->type) {
+ case BTN_TOOL_RUBBER:
if (!coord->f2) {
input_report_abs(dev, ABS_PRESSURE, 0);
input_report_key(dev, BTN_TOUCH, 0);
@@ -186,8 +227,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
w8001->type = BTN_TOOL_PEN;
}
- } else {
+ break;
+
+ case BTN_TOOL_FINGER:
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_TOOL_FINGER, 0);
+ input_sync(dev);
+ /* fall through */
+
+ case KEY_RESERVED:
+ w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ break;
+
+ default:
input_report_key(dev, BTN_STYLUS2, coord->f2);
+ break;
}
input_report_abs(dev, ABS_X, coord->x);
@@ -199,7 +253,26 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
if (!coord->rdy)
- w8001->type = 0;
+ w8001->type = KEY_RESERVED;
+}
+
+static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
+{
+ struct input_dev *dev = w8001->dev;
+ unsigned int x = coord->x;
+ unsigned int y = coord->y;
+
+ /* scale to pen maximum */
+ scale_touch_coordinates(w8001, &x, &y);
+
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_report_key(dev, BTN_TOUCH, coord->tsw);
+ input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
+
+ input_sync(dev);
+
+ w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED;
}
static irqreturn_t w8001_interrupt(struct serio *serio,
@@ -220,9 +293,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
case W8001_PKTLEN_TOUCH93 - 1:
case W8001_PKTLEN_TOUCH9A - 1:
- /* ignore one-finger touch packet. */
- if (w8001->pktlen == w8001->idx)
+ tmp = w8001->data[0] & W8001_TOUCH_BYTE;
+ if (tmp != W8001_TOUCH_BYTE)
+ break;
+
+ if (w8001->pktlen == w8001->idx) {
w8001->idx = 0;
+ if (w8001->type != BTN_TOOL_PEN &&
+ w8001->type != BTN_TOOL_RUBBER) {
+ parse_single_touch(w8001->data, &coord);
+ report_single_touch(w8001, &coord);
+ }
+ }
break;
/* Pen coordinates packet */
@@ -231,18 +313,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
if (unlikely(tmp == W8001_TAB_BYTE))
break;
- tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
+ tmp = w8001->data[0] & W8001_TOUCH_BYTE;
if (tmp == W8001_TOUCH_BYTE)
break;
w8001->idx = 0;
- parse_data(w8001->data, &coord);
+ parse_pen_data(w8001->data, &coord);
report_pen_events(w8001, &coord);
break;
/* control packet */
case W8001_PKTLEN_TPCCTL - 1:
- tmp = (w8001->data[0] & W8001_TOUCH_MASK);
+ tmp = w8001->data[0] & W8001_TOUCH_MASK;
if (tmp == W8001_TOUCH_BYTE)
break;
@@ -255,7 +337,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
/* 2 finger touch packet */
case W8001_PKTLEN_TOUCH2FG - 1:
w8001->idx = 0;
- parse_touch(w8001);
+ parse_multi_touch(w8001);
break;
}
@@ -285,52 +367,104 @@ static int w8001_setup(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
+ struct w8001_touch_query touch;
int error;
- error = w8001_command(w8001, W8001_CMD_QUERY, true);
+ error = w8001_command(w8001, W8001_CMD_STOP, false);
if (error)
return error;
- parse_data(w8001->response, &coord);
+ msleep(250); /* wait 250ms before querying the device */
- input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
- input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
- input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
- input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
- input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+ dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
- error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+ /* penabled? */
+ error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
- struct w8001_touch_query touch;
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_PEN, dev->keybit);
+ __set_bit(BTN_TOOL_RUBBER, dev->keybit);
+ __set_bit(BTN_STYLUS, dev->keybit);
+ __set_bit(BTN_STYLUS2, dev->keybit);
+
+ parse_pen_data(w8001->response, &coord);
+ w8001->max_pen_x = coord.x;
+ w8001->max_pen_y = coord.y;
+
+ input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+ input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
+ if (coord.tilt_x && coord.tilt_y) {
+ input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
+ input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+ }
+ w8001->id = 0x90;
+ strlcat(w8001->name, " Penabled", sizeof(w8001->name));
+ }
+
+ /* Touch enabled? */
+ error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+
+ /*
+ * Some non-touch devices may reply to the touch query. But their
+ * second byte is empty, which indicates touch is not supported.
+ */
+ if (!error && w8001->response[1]) {
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, dev->keybit);
parse_touchquery(w8001->response, &touch);
+ w8001->max_touch_x = touch.x;
+ w8001->max_touch_y = touch.y;
+
+ /* scale to pen maximum */
+ if (w8001->max_pen_x && w8001->max_pen_y) {
+ touch.x = w8001->max_pen_x;
+ touch.y = w8001->max_pen_y;
+ }
+
+ input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
switch (touch.sensor_id) {
case 0:
case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93;
+ w8001->id = 0x93;
+ strlcat(w8001->name, " 1FG", sizeof(w8001->name));
break;
+
case 1:
case 3:
case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+ strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+ w8001->id = 0x9a;
break;
+
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
- input_mt_create_slots(dev, 2);
- input_set_abs_params(dev, ABS_MT_TRACKING_ID,
- 0, MAX_TRACKING_ID, 0, 0);
+ input_mt_init_slots(dev, 2);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
- 0, 0, 0, 0);
+ 0, MT_TOOL_MAX, 0, 0);
+
+ strlcat(w8001->name, " 2FG", sizeof(w8001->name));
+ if (w8001->max_pen_x && w8001->max_pen_y)
+ w8001->id = 0xE3;
+ else
+ w8001->id = 0xE2;
break;
}
}
+ strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+
return w8001_command(w8001, W8001_CMD_START, false);
}
@@ -370,27 +504,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
w8001->serio = serio;
- w8001->id = serio->id.id;
w8001->dev = input_dev;
- w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
- input_dev->name = "Wacom W8001 Penabled Serial TouchScreen";
- input_dev->phys = w8001->phys;
- input_dev->id.bustype = BUS_RS232;
- input_dev->id.vendor = SERIO_W8001;
- input_dev->id.product = w8001->id;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &serio->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN);
- input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER);
- input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS);
- input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2);
-
serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv);
if (err)
@@ -400,6 +517,14 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err)
goto fail3;
+ input_dev->name = w8001->name;
+ input_dev->phys = w8001->phys;
+ input_dev->id.product = w8001->id;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = 0x056a;
+ input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
+
err = input_register_device(w8001->dev);
if (err)
goto fail3;
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index e0c024db2ca5..7f85a862ad11 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -17,6 +17,8 @@
* Switch to grant tables together with xen-fbfront.c.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -84,9 +86,8 @@ static irqreturn_t input_handler(int rq, void *dev_id)
input_report_key(dev, event->key.keycode,
event->key.pressed);
else
- printk(KERN_WARNING
- "xenkbd: unhandled keycode 0x%x\n",
- event->key.keycode);
+ pr_warning("unhandled keycode 0x%x\n",
+ event->key.keycode);
break;
case XENKBD_TYPE_POS:
input_report_abs(dev, ABS_X, event->pos.abs_x);
@@ -292,8 +293,7 @@ InitWait:
ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
"request-abs-pointer", "1");
if (ret)
- printk(KERN_WARNING
- "xenkbd: can't request abs-pointer");
+ pr_warning("can't request abs-pointer\n");
}
xenbus_switch_state(dev, XenbusStateConnected);
break;
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index e54e79d4e2c1..92607ed25e2e 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -2297,6 +2297,7 @@ static int __init capidrv_init(void)
errcode = capi20_get_profile(0, &profile);
if (errcode != CAPI_NOERROR) {
+ unregister_capictr_notifier(&capictr_nb);
capi20_release(&global.ap);
return -EIO;
}
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 3acf94cc5acd..2b33b2627fce 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -38,6 +38,7 @@
#include <linux/rcupdate.h>
static int showcapimsgs = 0;
+static struct workqueue_struct *kcapi_wq;
MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
MODULE_AUTHOR("Carsten Paeth");
@@ -291,7 +292,7 @@ static int notify_push(unsigned int event_type, u32 controller)
event->type = event_type;
event->controller = controller;
- schedule_work(&event->work);
+ queue_work(kcapi_wq, &event->work);
return 0;
}
@@ -408,7 +409,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
goto error;
}
skb_queue_tail(&ap->recv_queue, skb);
- schedule_work(&ap->recv_work);
+ queue_work(kcapi_wq, &ap->recv_work);
rcu_read_unlock();
return;
@@ -743,7 +744,7 @@ u16 capi20_release(struct capi20_appl *ap)
mutex_unlock(&capi_controller_lock);
- flush_scheduled_work();
+ flush_workqueue(kcapi_wq);
skb_queue_purge(&ap->recv_queue);
if (showcapimsgs & 1) {
@@ -1285,21 +1286,30 @@ static int __init kcapi_init(void)
{
int err;
+ kcapi_wq = alloc_workqueue("kcapi", 0, 0);
+ if (!kcapi_wq)
+ return -ENOMEM;
+
register_capictr_notifier(&capictr_nb);
err = cdebug_init();
- if (!err)
- kcapi_proc_init();
- return err;
+ if (err) {
+ unregister_capictr_notifier(&capictr_nb);
+ destroy_workqueue(kcapi_wq);
+ return err;
+ }
+
+ kcapi_proc_init();
+ return 0;
}
static void __exit kcapi_exit(void)
{
kcapi_proc_exit();
- /* make sure all notifiers are finished */
- flush_scheduled_work();
+ unregister_capictr_notifier(&capictr_nb);
cdebug_exit();
+ destroy_workqueue(kcapi_wq);
}
module_init(kcapi_init);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 178942a2ee61..8a3c5cfc4fea 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -2318,7 +2318,7 @@ static int gigaset_probe(struct usb_interface *interface,
__func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
GIGASET_MODULENAME);
if (!cs)
@@ -2576,7 +2576,7 @@ static int __init bas_gigaset_init(void)
{
int result;
- /* allocate memory for our driver state and intialize it */
+ /* allocate memory for our driver state and initialize it */
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
&gigops, THIS_MODULE);
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index bcc174e4f3b1..658e75f18d05 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -1900,6 +1900,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
if (b3skb == NULL) {
dev_err(cs->dev, "%s: out of memory\n", __func__);
send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ kfree(b3cmsg);
return;
}
capi_cmsg2message(b3cmsg,
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index d151dcbf770d..0ef09d0eb96b 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -513,7 +513,7 @@ gigaset_tty_open(struct tty_struct *tty)
return -ENODEV;
}
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
if (!cs)
goto error;
@@ -771,7 +771,7 @@ static int __init ser_gigaset_init(void)
return rc;
}
- /* allocate memory for our driver state and intialize it */
+ /* allocate memory for our driver state and initialize it */
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 4a66338f4e7d..5e3300d8a2a5 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -695,7 +695,7 @@ static int gigaset_probe(struct usb_interface *interface,
dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
if (!cs)
return -ENODEV;
@@ -894,7 +894,7 @@ static int __init usb_gigaset_init(void)
{
int result;
- /* allocate memory for our driver state and intialize it */
+ /* allocate memory for our driver state and initialize it */
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h
index 74a6ccf9065c..8121e046b739 100644
--- a/drivers/isdn/hardware/mISDN/ipac.h
+++ b/drivers/isdn/hardware/mISDN/ipac.h
@@ -29,7 +29,7 @@ struct isac_hw {
u32 type;
u32 off; /* offset to isac regs */
char *name;
- spinlock_t *hwlock; /* lock HW acccess */
+ spinlock_t *hwlock; /* lock HW access */
read_reg_func *read_reg;
write_reg_func *write_reg;
fifo_func *read_fifo;
@@ -70,7 +70,7 @@ struct ipac_hw {
struct hscx_hw hscx[2];
char *name;
void *hw;
- spinlock_t *hwlock; /* lock HW acccess */
+ spinlock_t *hwlock; /* lock HW access */
struct module *owner;
u32 type;
read_reg_func *read_reg;
diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h
index 4a134acd44d0..9962bdf699c7 100644
--- a/drivers/isdn/hardware/mISDN/isar.h
+++ b/drivers/isdn/hardware/mISDN/isar.h
@@ -44,7 +44,7 @@ struct isar_ch {
struct isar_hw {
struct isar_ch ch[2];
void *hw;
- spinlock_t *hwlock; /* lock HW acccess */
+ spinlock_t *hwlock; /* lock HW access */
char *name;
struct module *owner;
read_reg_func *read_reg;
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
index e90db8870b6c..bc0529ac88a1 100644
--- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -420,7 +420,7 @@ enable_hwirq(struct inf_hw *hw)
break;
case INF_NICCY:
val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- val |= NICCY_IRQ_ENABLE;;
+ val |= NICCY_IRQ_ENABLE;
outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
break;
case INF_SCT_1:
@@ -924,7 +924,7 @@ setup_instance(struct inf_hw *card)
mISDNipac_init(&card->ipac, card);
if (card->ipac.isac.dch.dev.Bprotocols == 0)
- goto error_setup;;
+ goto error_setup;
err = mISDN_register_device(&card->ipac.isac.dch.dev,
&card->pdev->dev, card->name);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 38eb31439a73..d13fa5b119f5 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -264,7 +264,7 @@ load_firmware(struct isar_hw *isar, const u8 *buf, int size)
while (noc) {
val = le16_to_cpu(*sp++);
*mp++ = val >> 8;
- *mp++ = val & 0xFF;;
+ *mp++ = val & 0xFF;
noc--;
}
spin_lock_irqsave(isar->hwlock, flags);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index fcf4ed1cb4b9..0e66af1decd4 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -314,7 +314,7 @@ hdlc_fill_fifo(struct BCState *bcs)
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
}
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
+ debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len);
p = bcs->tx_skb->data;
ptr = (u_int *)p;
skb_pull(bcs->tx_skb, count);
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index f150330b5a23..37e685eafd24 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -65,7 +65,7 @@ hisax_findcard(int driverid)
return (struct IsdnCardState *) 0;
}
-static void
+static __attribute__((format(printf, 3, 4))) void
link_debug(struct Channel *chanp, int direction, char *fmt, ...)
{
va_list args;
@@ -1068,7 +1068,7 @@ init_d_st(struct Channel *chanp)
return 0;
}
-static void
+static __attribute__((format(printf, 2, 3))) void
callc_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index b133378d4dc9..c110f8679bab 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1917,7 +1917,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
#ifdef CONFIG_PCI
#include <linux/pci.h>
-static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
+static struct pci_device_id hisax_pci_tbl[] __devinitdata __used = {
#ifdef CONFIG_HISAX_FRITZPCI
{PCI_VDEVICE(AVM, PCI_DEVICE_ID_AVM_A1) },
#endif
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 7250f56a5246..a16459a1332c 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -292,7 +292,7 @@ hfc_fill_fifo(struct BCState *bcs)
}
count = GetFreeFifoBytes_B(bcs);
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx",
+ debugl1(cs, "hfc_fill_fifo %d count(%u/%d),%lx",
bcs->channel, bcs->tx_skb->len,
count, current->state);
if (count < bcs->tx_skb->len) {
@@ -719,7 +719,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
}
count = GetFreeFifoBytes_D(cs);
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)",
+ debugl1(cs, "hfc_fill_Dfifo count(%u/%d)",
cs->tx_skb->len, count);
if (count < cs->tx_skb->len) {
if (cs->debug & L1_DEB_ISAC)
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index b1f6481e1193..626f85df302b 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -282,7 +282,7 @@ hfc_fill_fifo(struct BCState *bcs)
count += cs->hw.hfc.fifosize;
} /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
+ debugl1(cs, "hfc_fill_fifo %d count(%u/%d)",
bcs->channel, bcs->tx_skb->len,
count);
if (count < bcs->tx_skb->len) {
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 917cc84065bd..3147020d188b 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -550,7 +550,7 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
count += D_FIFO_SIZE; /* count now contains available bytes */
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo count(%ld/%d)",
+ debugl1(cs, "hfcpci_fill_Dfifo count(%u/%d)",
cs->tx_skb->len, count);
if (count < cs->tx_skb->len) {
if (cs->debug & L1_DEB_ISAC)
@@ -681,7 +681,7 @@ hfcpci_fill_fifo(struct BCState *bcs)
count += B_FIFO_SIZE; /* count now contains available bytes */
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo %d count(%ld/%d),%lx",
+ debugl1(cs, "hfcpci_fill_fifo %d count(%u/%d),%lx",
bcs->channel, bcs->tx_skb->len,
count, current->state);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 5aa138eb0b3c..1235b7131ae1 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -179,7 +179,7 @@ write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans
count += fifo_size; /* count now contains available bytes */
if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
+ debugl1(cs, "hfcsx_write_fifo %d count(%u/%d)",
fifo, skb->len, count);
if (count < skb->len) {
if (cs->debug & L1_DEB_ISAC_FIFO)
@@ -265,7 +265,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
count++;
if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_read_fifo %d count %ld)",
+ debugl1(cs, "hfcsx_read_fifo %d count %u)",
fifo, count);
if ((count > fifo_size) || (count < 4)) {
@@ -986,7 +986,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
default:
spin_unlock_irqrestore(&cs->lock, flags);
if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_l1hw loop invalid %4lx", arg);
+ debugl1(cs, "hfcsx_l1hw loop invalid %4lx", (unsigned long)arg);
return;
}
cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 32ab3924aa73..de1c669c7b13 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1286,7 +1286,9 @@ int jiftime(char *s, long mark);
int HiSax_command(isdn_ctrl * ic);
int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
+__attribute__((format(printf, 3, 4)))
void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
+__attribute__((format(printf, 3, 0)))
void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
void HiSax_reportcard(int cardnr, int sel);
int QuickHex(char *txt, u_char * p, int cnt);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 751b25f2ff58..332104103e18 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -717,7 +717,7 @@ bch_mode(struct BCState *bcs, int mode, int bc)
bc = bc ? 1 : 0; // in case bc is greater than 1
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
+ debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 40b914bded8c..d4cce337add2 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -189,7 +189,7 @@ ISARVersion(struct IsdnCardState *cs, char *s)
static int
isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
{
- int ret, size, cnt, debug;
+ int cfu_ret, ret, size, cnt, debug;
u_char len, nom, noc;
u_short sadr, left, *sp;
u_char __user *p = buf;
@@ -212,9 +212,10 @@ isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
#endif
- if ((ret = copy_from_user(&size, p, sizeof(int)))) {
- printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
- return ret;
+ cfu_ret = copy_from_user(&size, p, sizeof(int));
+ if (cfu_ret) {
+ printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", cfu_ret);
+ return -EFAULT;
}
p += sizeof(int);
printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
@@ -953,7 +954,7 @@ isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
break;
case PSEV_GSTN_CLR:
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev GSTN CLEAR", devt);
+ debugl1(cs, "pump stev GSTN CLEAR");
break;
default:
if (cs->debug & L1_DEB_HSCX)
@@ -1268,7 +1269,7 @@ isar_int_main(struct IsdnCardState *cs)
static void
ftimer_handler(struct BCState *bcs) {
if (bcs->cs->debug)
- debugl1(bcs->cs, "ftimer flags %04x",
+ debugl1(bcs->cs, "ftimer flags %04lx",
bcs->Flag);
test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
@@ -1427,8 +1428,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
&bcs->hw.isar.reg->Flags))
bcs->hw.isar.dpath = 1;
else {
- printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
- debugl1(cs, "isar modeisar analog funktions only with DP1");
+ printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
+ debugl1(cs, "isar modeisar analog functions only with DP1");
return(1);
}
break;
@@ -1748,7 +1749,7 @@ isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
struct BCState *bcs;
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
+ debugl1(cs, "isar_auxcmd cmd/ch %x/%ld", ic->command, ic->arg);
switch (ic->command) {
case (ISDN_CMD_FAXCMD):
bcs = cs->channel[ic->arg].bcs;
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
index 172ad4c8c961..425d86116f2b 100644
--- a/drivers/isdn/hisax/isdnl1.h
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -21,6 +21,7 @@
#define B_XMTBUFREADY 1
#define B_ACKPENDING 2
+__attribute__((format(printf, 2, 3)))
void debugl1(struct IsdnCardState *cs, char *fmt, ...);
void DChannel_proc_xmt(struct IsdnCardState *cs);
void DChannel_proc_rcv(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index fd0b643ab740..ad291f21b201 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -66,7 +66,7 @@ static char *strL3Event[] =
"EV_TIMEOUT",
};
-static void
+static __attribute__((format(printf, 2, 3))) void
l3m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 5d7f0f2ff9b9..644891efc26f 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -254,7 +254,7 @@ static int make_raw_data(struct BCState *bcs) {
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d",
+ debugl1(bcs->cs,"tiger make_raw: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8>bitcnt++) {
@@ -361,7 +361,7 @@ static int make_raw_data_56k(struct BCState *bcs) {
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d",
+ debugl1(bcs->cs,"tiger make_raw_56k: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8>bitcnt++) {
@@ -612,7 +612,7 @@ void netjet_fill_dma(struct BCState *bcs)
if (!bcs->tx_skb)
return;
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma1: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
return;
@@ -625,7 +625,7 @@ void netjet_fill_dma(struct BCState *bcs)
return;
};
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma2: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
@@ -667,7 +667,7 @@ void netjet_fill_dma(struct BCState *bcs)
write_raw(bcs, p, cnt);
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma3: c%d %4lx", bcs->channel,
bcs->Flag);
}
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index b7876b19fe73..44082637a09f 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -167,7 +167,8 @@ static struct FsmNode L1FnList[] __initdata =
{ST_L1_F8, EV_IND_RSY, l1_ignore},
};
-static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
+static __attribute__((format(printf, 2, 3)))
+void l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
@@ -269,7 +270,8 @@ static char *strDoutEvent[] =
"EV_DOUT_UNDERRUN",
};
-static void dout_debug(struct FsmInst *fi, char *fmt, ...)
+static __attribute__((format(printf, 2, 3)))
+void dout_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index 46048e55f241..d568689669f8 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -61,7 +61,7 @@ static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *
static int isdn_concap_dl_connect_req(struct concap_proto *concap)
{
struct net_device *ndev = concap -> net_dev;
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
+ isdn_net_local *lp = netdev_priv(ndev);
int ret;
IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 26d44c3ca1d8..afeede7ee295 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -827,7 +827,7 @@ isdn_net_dial(void)
void
isdn_net_hangup(struct net_device *d)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(d);
+ isdn_net_local *lp = netdev_priv(d);
isdn_ctrl cmd;
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp->netdev->cprot;
@@ -1052,7 +1052,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
{
isdn_net_dev *nd;
isdn_net_local *slp;
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
+ isdn_net_local *lp = netdev_priv(ndev);
int retv = NETDEV_TX_OK;
if (((isdn_net_local *) netdev_priv(ndev))->master) {
@@ -1116,7 +1116,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
static void
isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
if (!skb)
return;
if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
@@ -1131,7 +1131,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
static void isdn_net_tx_timeout(struct net_device * ndev)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
+ isdn_net_local *lp = netdev_priv(ndev);
printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
if (!lp->dialstate){
@@ -1165,7 +1165,7 @@ static void isdn_net_tx_timeout(struct net_device * ndev)
static netdev_tx_t
isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
+ isdn_net_local *lp = netdev_priv(ndev);
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot;
/* At this point hard_start_xmit() passes control to the encapsulation
@@ -1347,7 +1347,7 @@ isdn_net_close(struct net_device *dev)
static struct net_device_stats *
isdn_net_get_stats(struct net_device *dev)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
return &lp->stats;
}
@@ -1426,7 +1426,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
unsigned long len = 0;
unsigned long expires = 0;
int tmp = 0;
@@ -1493,7 +1493,7 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static int isdn_net_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
switch (lp->p_encap) {
#ifdef CONFIG_ISDN_PPP
@@ -1786,7 +1786,7 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
static void
isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
{
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
+ isdn_net_local *lp = netdev_priv(ndev);
isdn_net_local *olp = lp; /* original 'lp' */
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
@@ -1800,7 +1800,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
* handle master's statistics and hangup-timeout
*/
ndev = lp->master;
- lp = (isdn_net_local *) netdev_priv(ndev);
+ lp = netdev_priv(ndev);
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index fe824e0cbb25..9e8162c80bb0 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1147,15 +1147,14 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
if (is->pass_filter
- && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0) {
+ && sk_run_filter(skb, is->pass_filter) == 0) {
if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
kfree_skb(skb);
return;
}
if (!(is->active_filter
- && sk_run_filter(skb, is->active_filter,
- is->active_len) == 0)) {
+ && sk_run_filter(skb, is->active_filter) == 0)) {
if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
lp->huptimer = 0;
@@ -1221,7 +1220,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
struct ippp_struct *ipt,*ipts;
int slot, retval = NETDEV_TX_OK;
- mlp = (isdn_net_local *) netdev_priv(netdev);
+ mlp = netdev_priv(netdev);
nd = mlp->netdev; /* get master lp */
slot = mlp->ppp_slot;
@@ -1294,15 +1293,14 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
}
if (ipt->pass_filter
- && sk_run_filter(skb, ipt->pass_filter, ipt->pass_len) == 0) {
+ && sk_run_filter(skb, ipt->pass_filter) == 0) {
if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
kfree_skb(skb);
goto unlock;
}
if (!(ipt->active_filter
- && sk_run_filter(skb, ipt->active_filter,
- ipt->active_len) == 0)) {
+ && sk_run_filter(skb, ipt->active_filter) == 0)) {
if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
lp->huptimer = 0;
@@ -1492,9 +1490,9 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
}
drop |= is->pass_filter
- && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0;
+ && sk_run_filter(skb, is->pass_filter) == 0;
drop |= is->active_filter
- && sk_run_filter(skb, is->active_filter, is->active_len) == 0;
+ && sk_run_filter(skb, is->active_filter) == 0;
skb_push(skb, IPPP_MAX_HEADER - 4);
return drop;
@@ -1985,7 +1983,7 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
{
struct ppp_stats __user *res = ifr->ifr_data;
struct ppp_stats t;
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
return -EFAULT;
@@ -2024,7 +2022,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
int error=0;
int len;
- isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+ isdn_net_local *lp = netdev_priv(dev);
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
@@ -2091,7 +2089,7 @@ isdn_ppp_dial_slave(char *name)
sdev = lp->slave;
while (sdev) {
- isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev);
+ isdn_net_local *mlp = netdev_priv(sdev);
if (!(mlp->flags & ISDN_NET_CONNECTED))
break;
sdev = mlp->slave;
@@ -2099,7 +2097,7 @@ isdn_ppp_dial_slave(char *name)
if (!sdev)
return 2;
- isdn_net_dial_req((isdn_net_local *) netdev_priv(sdev));
+ isdn_net_dial_req(netdev_priv(sdev));
return 0;
#else
return -1;
@@ -2122,7 +2120,7 @@ isdn_ppp_hangup_slave(char *name)
sdev = lp->slave;
while (sdev) {
- isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev);
+ isdn_net_local *mlp = netdev_priv(sdev);
if (mlp->slave) { /* find last connected link in chain */
isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 2e847a90bad0..f2b5bab5e6a1 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1627,7 +1627,7 @@ __setup("icn=", icn_setup);
static int __init icn_init(void)
{
char *p;
- char rev[10];
+ char rev[20];
memset(&dev, 0, sizeof(icn_dev));
dev.memaddr = (membase & 0x0ffc000);
@@ -1637,9 +1637,10 @@ static int __init icn_init(void)
spin_lock_init(&dev.devlock);
if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 1);
+ strncpy(rev, p + 1, 20);
p = strchr(rev, '$');
- *p = 0;
+ if (p)
+ *p = 0;
} else
strcpy(rev, " ??? ");
printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 76d9e673b4e1..309bacf1fadc 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -112,7 +112,7 @@
* Disable rx-data:
* If cmx is realized in hardware, rx data will be disabled if requested by
* the upper layer. If dtmf decoding is done by software and enabled, rx data
- * will not be diabled but blocked to the upper layer.
+ * will not be disabled but blocked to the upper layer.
*
* HFC conference engine:
* If it is possible to realize all features using hardware, hardware will be
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 307bd6e8988b..199f374cf9da 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -110,7 +110,7 @@ mISDN_freedchannel(struct dchannel *ch)
}
skb_queue_purge(&ch->squeue);
skb_queue_purge(&ch->rqueue);
- flush_scheduled_work();
+ flush_work_sync(&ch->workq);
return 0;
}
EXPORT_SYMBOL(mISDN_freedchannel);
@@ -143,7 +143,7 @@ mISDN_freebchannel(struct bchannel *ch)
mISDN_clear_bchannel(ch);
skb_queue_purge(&ch->rqueue);
ch->rcount = 0;
- flush_scheduled_work();
+ flush_work_sync(&ch->workq);
return 0;
}
EXPORT_SYMBOL(mISDN_freebchannel);
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 5b59796ed250..bd526f664a39 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -1269,6 +1269,8 @@ release_card(struct l1oip *hc)
if (timer_pending(&hc->timeout_tl))
del_timer(&hc->timeout_tl);
+ cancel_work_sync(&hc->workq);
+
if (hc->socket_thread)
l1oip_socket_close(hc);
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index ac4aa18c632b..5cc7c001c523 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -99,12 +99,16 @@ static void
l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
struct layer1 *l1 = fi->userdata;
+ struct va_format vaf;
va_list va;
va_start(va, fmt);
- printk(KERN_DEBUG "%s: ", dev_name(&l1->dch->dev.dev));
- vprintk(fmt, va);
- printk("\n");
+
+ vaf.fmt = fmt;
+ vaf.va = &va;
+
+ printk(KERN_DEBUG "%s: %pV\n", dev_name(&l1->dch->dev.dev), &vaf);
+
va_end(va);
}
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index c97371788764..4ae75053c9d2 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -95,14 +95,20 @@ static void
l2m_debug(struct FsmInst *fi, char *fmt, ...)
{
struct layer2 *l2 = fi->userdata;
+ struct va_format vaf;
va_list va;
if (!(*debug & DEBUG_L2_FSM))
return;
+
va_start(va, fmt);
- printk(KERN_DEBUG "l2 (sapi %d tei %d): ", l2->sapi, l2->tei);
- vprintk(fmt, va);
- printk("\n");
+
+ vaf.fmt = fmt;
+ vaf.va = &va;
+
+ printk(KERN_DEBUG "l2 (sapi %d tei %d): %pV\n",
+ l2->sapi, l2->tei, &vaf);
+
va_end(va);
}
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 3232206406b1..7446d8b4282d 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -392,6 +392,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (dev) {
struct mISDN_devinfo di;
+ memset(&di, 0, sizeof(di));
di.id = dev->id;
di.Dprotocols = dev->Dprotocols;
di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
@@ -672,6 +673,7 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (dev) {
struct mISDN_devinfo di;
+ memset(&di, 0, sizeof(di));
di.id = dev->id;
di.Dprotocols = dev->Dprotocols;
di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 1b85d9d27496..687c9b6264ab 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -79,14 +79,19 @@ static void
da_debug(struct FsmInst *fi, char *fmt, ...)
{
struct manager *mgr = fi->userdata;
+ struct va_format vaf;
va_list va;
if (!(*debug & DEBUG_L2_TEIFSM))
return;
+
va_start(va, fmt);
- printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id);
- vprintk(fmt, va);
- printk("\n");
+
+ vaf.fmt = fmt;
+ vaf.va = &va;
+
+ printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf);
+
va_end(va);
}
@@ -223,14 +228,20 @@ static void
tei_debug(struct FsmInst *fi, char *fmt, ...)
{
struct teimgr *tm = fi->userdata;
+ struct va_format vaf;
va_list va;
if (!(*debug & DEBUG_L2_TEIFSM))
return;
+
va_start(va, fmt);
- printk(KERN_DEBUG "sapi(%d) tei(%d): ", tm->l2->sapi, tm->l2->tei);
- vprintk(fmt, va);
- printk("\n");
+
+ vaf.fmt = fmt;
+ vaf.va = &va;
+
+ printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n",
+ tm->l2->sapi, tm->l2->tei, &vaf);
+
va_end(va);
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index cc2a88d5192f..6f190f4cdbc0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -7,20 +7,20 @@ menuconfig 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"
+ bool "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.
-if LEDS_CLASS
+if NEW_LEDS
comment "LED drivers"
config LEDS_88PM860X
tristate "LED Support for Marvell 88PM860x PMIC"
+ depends on LEDS_CLASS
depends on MFD_88PM860X
help
This option enables support for on-chip LED drivers found on Marvell
@@ -28,6 +28,7 @@ config LEDS_88PM860X
config LEDS_ATMEL_PWM
tristate "LED Support using Atmel PWM outputs"
+ depends on LEDS_CLASS
depends on ATMEL_PWM
help
This option enables support for LEDs driven using outputs
@@ -35,6 +36,7 @@ config LEDS_ATMEL_PWM
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
+ depends on LEDS_CLASS
depends on SHARP_LOCOMO
help
This option enables support for the LEDs on Sharp Locomo.
@@ -42,6 +44,7 @@ config LEDS_LOCOMO
config LEDS_MIKROTIK_RB532
tristate "LED Support for Mikrotik Routerboard 532"
+ depends on LEDS_CLASS
depends on MIKROTIK_RB532
help
This option enables support for the so called "User LED" of
@@ -49,6 +52,7 @@ config LEDS_MIKROTIK_RB532
config LEDS_S3C24XX
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
+ depends on LEDS_CLASS
depends on ARCH_S3C2410
help
This option enables support for LEDs connected to GPIO lines
@@ -56,12 +60,14 @@ config LEDS_S3C24XX
config LEDS_AMS_DELTA
tristate "LED Support for the Amstrad Delta (E3)"
+ depends on LEDS_CLASS
depends on MACH_AMS_DELTA
help
This option enables support for the LEDs on Amstrad Delta (E3).
config LEDS_NET48XX
tristate "LED Support for Soekris net48xx series Error LED"
+ depends on LEDS_CLASS
depends on SCx200_GPIO
help
This option enables support for the Soekris net4801 and net4826 error
@@ -79,18 +85,21 @@ config LEDS_NET5501
config LEDS_FSG
tristate "LED Support for the Freecom FSG-3"
+ depends on LEDS_CLASS
depends on MACH_FSG
help
This option enables support for the LEDs on the Freecom FSG-3.
config LEDS_WRAP
tristate "LED Support for the WRAP series LEDs"
+ depends on LEDS_CLASS
depends on SCx200_GPIO
help
This option enables support for the PCEngines WRAP programmable LEDs.
config LEDS_ALIX2
tristate "LED Support for ALIX.2 and ALIX.3 series"
+ depends on LEDS_CLASS
depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
help
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
@@ -98,12 +107,14 @@ config LEDS_ALIX2
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
+ depends on LEDS_CLASS
depends on ARCH_H1940
help
This option enables support for the LEDs on the h1940.
config LEDS_COBALT_QUBE
tristate "LED Support for the Cobalt Qube series front LED"
+ depends on LEDS_CLASS
depends on MIPS_COBALT
help
This option enables support for the front LED on Cobalt Qube series
@@ -117,6 +128,7 @@ config LEDS_COBALT_RAQ
config LEDS_SUNFIRE
tristate "LED support for SunFire servers."
+ depends on LEDS_CLASS
depends on SPARC64
select LEDS_TRIGGERS
help
@@ -125,6 +137,7 @@ config LEDS_SUNFIRE
config LEDS_HP6XX
tristate "LED Support for the HP Jornada 6xx"
+ depends on LEDS_CLASS
depends on SH_HP6XX
help
This option enables LED support for the handheld
@@ -132,6 +145,7 @@ config LEDS_HP6XX
config LEDS_PCA9532
tristate "LED driver for PCA9532 dimmer"
+ depends on LEDS_CLASS
depends on I2C && INPUT && EXPERIMENTAL
help
This option enables support for NXP pca9532
@@ -140,6 +154,7 @@ config LEDS_PCA9532
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
+ depends on LEDS_CLASS
depends on GENERIC_GPIO
help
This option enables support for the LEDs connected to GPIO
@@ -167,6 +182,7 @@ config LEDS_GPIO_OF
config LEDS_LP3944
tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for LEDs connected to the National
@@ -176,8 +192,27 @@ config LEDS_LP3944
To compile this driver as a module, choose M here: the
module will be called leds-lp3944.
+config LEDS_LP5521
+ tristate "LED Support for N.S. LP5521 LED driver chip"
+ depends on LEDS_CLASS && I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LP5521 LED driver. It is 3 channel chip with programmable engines.
+ Driver provides direct control via LED class and interface for
+ programming the engines.
+
+config LEDS_LP5523
+ tristate "LED Support for N.S. LP5523 LED driver chip"
+ depends on LEDS_CLASS && I2C
+ help
+ If you say yes here you get support for the National Semiconductor
+ LP5523 LED driver. It is 9 channel chip with programmable engines.
+ Driver provides direct control via LED class and interface for
+ programming the engines.
+
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
+ depends on LEDS_CLASS
depends on X86 && SERIO_I8042 && DMI
help
This driver makes the mail LED accessible from userspace
@@ -208,6 +243,7 @@ config LEDS_CLEVO_MAIL
config LEDS_PCA955X
tristate "LED Support for PCA955x I2C chips"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for LEDs connected to PCA955x
@@ -216,6 +252,7 @@ config LEDS_PCA955X
config LEDS_WM831X_STATUS
tristate "LED support for status LEDs on WM831x PMICs"
+ depends on LEDS_CLASS
depends on MFD_WM831X
help
This option enables support for the status LEDs of the WM831x
@@ -223,6 +260,7 @@ config LEDS_WM831X_STATUS
config LEDS_WM8350
tristate "LED Support for WM8350 AudioPlus PMIC"
+ depends on LEDS_CLASS
depends on MFD_WM8350
help
This option enables support for LEDs driven by the Wolfson
@@ -230,6 +268,7 @@ config LEDS_WM8350
config LEDS_DA903X
tristate "LED Support for DA9030/DA9034 PMIC"
+ depends on LEDS_CLASS
depends on PMIC_DA903X
help
This option enables support for on-chip LED drivers found
@@ -237,6 +276,7 @@ config LEDS_DA903X
config LEDS_DAC124S085
tristate "LED Support for DAC124S085 SPI DAC"
+ depends on LEDS_CLASS
depends on SPI
help
This option enables support for DAC124S085 SPI DAC from NatSemi,
@@ -244,18 +284,21 @@ config LEDS_DAC124S085
config LEDS_PWM
tristate "PWM driven LED Support"
+ depends on LEDS_CLASS
depends on HAVE_PWM
help
This option enables support for pwm driven LEDs
config LEDS_REGULATOR
tristate "REGULATOR driven LED support"
+ depends on LEDS_CLASS
depends on REGULATOR
help
This option enables support for regulator driven LEDs.
config LEDS_BD2802
tristate "LED driver for BD2802 RGB LED"
+ depends on LEDS_CLASS
depends on I2C
help
This option enables support for BD2802GU RGB LED driver chips
@@ -263,6 +306,7 @@ config LEDS_BD2802
config LEDS_INTEL_SS4200
tristate "LED driver for Intel NAS SS4200 series"
+ depends on LEDS_CLASS
depends on PCI && DMI
help
This option enables support for the Intel SS4200 series of
@@ -272,6 +316,7 @@ config LEDS_INTEL_SS4200
config LEDS_LT3593
tristate "LED driver for LT3593 controllers"
+ depends on LEDS_CLASS
depends on GENERIC_GPIO
help
This option enables support for LEDs driven by a Linear Technology
@@ -280,6 +325,7 @@ config LEDS_LT3593
config LEDS_ADP5520
tristate "LED Support for ADP5520/ADP5501 PMIC"
+ depends on LEDS_CLASS
depends on PMIC_ADP5520
help
This option enables support for on-chip LED drivers found
@@ -290,6 +336,7 @@ config LEDS_ADP5520
config LEDS_DELL_NETBOOKS
tristate "External LED on Dell Business Netbooks"
+ depends on LEDS_CLASS
depends on X86 && ACPI_WMI
help
This adds support for the Latitude 2100 and similar
@@ -297,6 +344,7 @@ config LEDS_DELL_NETBOOKS
config LEDS_MC13783
tristate "LED Support for MC13783 PMIC"
+ depends on LEDS_CLASS
depends on MFD_MC13783
help
This option enable support for on-chip LED drivers found
@@ -304,6 +352,7 @@ config LEDS_MC13783
config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs"
+ depends on LEDS_CLASS
depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2
default y
help
@@ -322,17 +371,17 @@ config LEDS_NETXBIG
config LEDS_TRIGGERS
bool "LED Trigger support"
+ depends on LEDS_CLASS
help
This option enables trigger support for the leds class.
These triggers allow kernel events to drive the LEDs and can
be configured via sysfs. If unsure, say Y.
-if LEDS_TRIGGERS
-
comment "LED Triggers"
config LEDS_TRIGGER_TIMER
tristate "LED Timer Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a programmable timer
via sysfs. Some LED hardware can be programmed to start
@@ -344,12 +393,14 @@ config LEDS_TRIGGER_TIMER
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
depends on IDE_GD_ATA
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
config LEDS_TRIGGER_HEARTBEAT
tristate "LED Heartbeat Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a CPU load average.
The flash frequency is a hyperbolic function of the 1-minute
@@ -358,6 +409,7 @@ config LEDS_TRIGGER_HEARTBEAT
config LEDS_TRIGGER_BACKLIGHT
tristate "LED backlight Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled as a backlight device: they
turn off and on when the display is blanked and unblanked.
@@ -366,6 +418,7 @@ config LEDS_TRIGGER_BACKLIGHT
config LEDS_TRIGGER_GPIO
tristate "LED GPIO Trigger"
+ depends on LEDS_TRIGGERS
depends on GPIOLIB
help
This allows LEDs to be controlled by gpio events. It's good
@@ -378,6 +431,7 @@ config LEDS_TRIGGER_GPIO
config LEDS_TRIGGER_DEFAULT_ON
tristate "LED Default ON Trigger"
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be initialised in the ON state.
If unsure, say Y.
@@ -385,8 +439,4 @@ config LEDS_TRIGGER_DEFAULT_ON
comment "iptables trigger is under Netfilter config (LED target)"
depends on LEDS_TRIGGERS
-endif # LEDS_TRIGGERS
-
-endif # LEDS_CLASS
-
endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 9c96db40ef6d..aae6989ff6b6 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
+obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
+obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 260660076507..d5a4ade88991 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -81,6 +81,79 @@ static struct device_attribute led_class_attrs[] = {
__ATTR_NULL,
};
+static void led_timer_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (void *)data;
+ unsigned long brightness;
+ unsigned long delay;
+
+ if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
+ led_set_brightness(led_cdev, LED_OFF);
+ return;
+ }
+
+ brightness = led_get_brightness(led_cdev);
+ if (!brightness) {
+ /* Time to switch the LED on. */
+ brightness = led_cdev->blink_brightness;
+ delay = led_cdev->blink_delay_on;
+ } else {
+ /* Store the current brightness value to be able
+ * to restore it when the delay_off period is over.
+ */
+ led_cdev->blink_brightness = brightness;
+ brightness = LED_OFF;
+ delay = led_cdev->blink_delay_off;
+ }
+
+ led_set_brightness(led_cdev, brightness);
+
+ mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static void led_stop_software_blink(struct led_classdev *led_cdev)
+{
+ /* deactivate previous settings */
+ del_timer_sync(&led_cdev->blink_timer);
+ led_cdev->blink_delay_on = 0;
+ led_cdev->blink_delay_off = 0;
+}
+
+static void led_set_software_blink(struct led_classdev *led_cdev,
+ unsigned long delay_on,
+ unsigned long delay_off)
+{
+ int current_brightness;
+
+ current_brightness = led_get_brightness(led_cdev);
+ if (current_brightness)
+ led_cdev->blink_brightness = current_brightness;
+ if (!led_cdev->blink_brightness)
+ led_cdev->blink_brightness = led_cdev->max_brightness;
+
+ if (delay_on == led_cdev->blink_delay_on &&
+ delay_off == led_cdev->blink_delay_off)
+ return;
+
+ led_stop_software_blink(led_cdev);
+
+ led_cdev->blink_delay_on = delay_on;
+ led_cdev->blink_delay_off = delay_off;
+
+ /* never on - don't blink */
+ if (!delay_on)
+ return;
+
+ /* never off - just set to brightness */
+ if (!delay_off) {
+ led_set_brightness(led_cdev, led_cdev->blink_brightness);
+ return;
+ }
+
+ mod_timer(&led_cdev->blink_timer, jiffies + 1);
+}
+
+
/**
* led_classdev_suspend - suspend an led_classdev.
* @led_cdev: the led_classdev to suspend.
@@ -148,6 +221,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
led_update_brightness(led_cdev);
+ init_timer(&led_cdev->blink_timer);
+ led_cdev->blink_timer.function = led_timer_function;
+ led_cdev->blink_timer.data = (unsigned long)led_cdev;
+
#ifdef CONFIG_LEDS_TRIGGERS
led_trigger_set_default(led_cdev);
#endif
@@ -157,7 +234,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
return 0;
}
-
EXPORT_SYMBOL_GPL(led_classdev_register);
/**
@@ -175,6 +251,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
+ /* Stop blinking */
+ led_brightness_set(led_cdev, LED_OFF);
+
device_unregister(led_cdev->dev);
down_write(&leds_list_lock);
@@ -183,6 +262,30 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_classdev_unregister);
+void led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ if (led_cdev->blink_set &&
+ !led_cdev->blink_set(led_cdev, delay_on, delay_off))
+ return;
+
+ /* blink with 1 Hz as default if nothing specified */
+ if (!*delay_on && !*delay_off)
+ *delay_on = *delay_off = 500;
+
+ led_set_software_blink(led_cdev, *delay_on, *delay_off);
+}
+EXPORT_SYMBOL(led_blink_set);
+
+void led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ led_stop_software_blink(led_cdev);
+ led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL(led_brightness_set);
+
static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE, "leds");
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index f1c00db88b5e..c41eb6180c9c 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
led_cdev->trigger = NULL;
- led_set_brightness(led_cdev, LED_OFF);
+ led_brightness_set(led_cdev, LED_OFF);
}
if (trigger) {
write_lock_irqsave(&trigger->leddev_list_lock, flags);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index ea57e05d08f3..4d9fa38d9ff6 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -316,7 +316,7 @@ static struct of_platform_driver of_gpio_leds_driver = {
static int __init gpio_led_init(void)
{
- int ret;
+ int ret = 0;
#ifdef CONFIG_LEDS_GPIO_PLATFORM
ret = platform_driver_register(&gpio_led_driver);
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
new file mode 100644
index 000000000000..80a3ae3c00b9
--- /dev/null
+++ b/drivers/leds/leds-lp5521.c
@@ -0,0 +1,804 @@
+/*
+ * LP5521 LED chip driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5521.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5521_PROGRAM_LENGTH 32 /* in bytes */
+
+#define LP5521_MAX_LEDS 3 /* Maximum number of LEDs */
+#define LP5521_MAX_ENGINES 3 /* Maximum number of engines */
+
+#define LP5521_ENG_MASK_BASE 0x30 /* 00110000 */
+#define LP5521_ENG_STATUS_MASK 0x07 /* 00000111 */
+
+#define LP5521_CMD_LOAD 0x15 /* 00010101 */
+#define LP5521_CMD_RUN 0x2a /* 00101010 */
+#define LP5521_CMD_DIRECT 0x3f /* 00111111 */
+#define LP5521_CMD_DISABLED 0x00 /* 00000000 */
+
+/* Registers */
+#define LP5521_REG_ENABLE 0x00
+#define LP5521_REG_OP_MODE 0x01
+#define LP5521_REG_R_PWM 0x02
+#define LP5521_REG_G_PWM 0x03
+#define LP5521_REG_B_PWM 0x04
+#define LP5521_REG_R_CURRENT 0x05
+#define LP5521_REG_G_CURRENT 0x06
+#define LP5521_REG_B_CURRENT 0x07
+#define LP5521_REG_CONFIG 0x08
+#define LP5521_REG_R_CHANNEL_PC 0x09
+#define LP5521_REG_G_CHANNEL_PC 0x0A
+#define LP5521_REG_B_CHANNEL_PC 0x0B
+#define LP5521_REG_STATUS 0x0C
+#define LP5521_REG_RESET 0x0D
+#define LP5521_REG_GPO 0x0E
+#define LP5521_REG_R_PROG_MEM 0x10
+#define LP5521_REG_G_PROG_MEM 0x30
+#define LP5521_REG_B_PROG_MEM 0x50
+
+#define LP5521_PROG_MEM_BASE LP5521_REG_R_PROG_MEM
+#define LP5521_PROG_MEM_SIZE 0x20
+
+/* Base register to set LED current */
+#define LP5521_REG_LED_CURRENT_BASE LP5521_REG_R_CURRENT
+
+/* Base register to set the brightness */
+#define LP5521_REG_LED_PWM_BASE LP5521_REG_R_PWM
+
+/* Bits in ENABLE register */
+#define LP5521_MASTER_ENABLE 0x40 /* Chip master enable */
+#define LP5521_LOGARITHMIC_PWM 0x80 /* Logarithmic PWM adjustment */
+#define LP5521_EXEC_RUN 0x2A
+
+/* Bits in CONFIG register */
+#define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */
+#define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */
+#define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */
+#define LP5521_CP_MODE_BYPASS 8 /* CP forced to bypass mode */
+#define LP5521_CP_MODE_1X5 0x10 /* CP forced to 1.5x mode */
+#define LP5521_CP_MODE_AUTO 0x18 /* Automatic mode selection */
+#define LP5521_R_TO_BATT 4 /* R out: 0 = CP, 1 = Vbat */
+#define LP5521_CLK_SRC_EXT 0 /* Ext-clk source (CLK_32K) */
+#define LP5521_CLK_INT 1 /* Internal clock */
+#define LP5521_CLK_AUTO 2 /* Automatic clock selection */
+
+/* Status */
+#define LP5521_EXT_CLK_USED 0x08
+
+struct lp5521_engine {
+ int id;
+ u8 mode;
+ u8 prog_page;
+ u8 engine_mask;
+};
+
+struct lp5521_led {
+ int id;
+ u8 chan_nr;
+ u8 led_current;
+ u8 max_current;
+ struct led_classdev cdev;
+ struct work_struct brightness_work;
+ u8 brightness;
+};
+
+struct lp5521_chip {
+ struct lp5521_platform_data *pdata;
+ struct mutex lock; /* Serialize control */
+ struct i2c_client *client;
+ struct lp5521_engine engines[LP5521_MAX_ENGINES];
+ struct lp5521_led leds[LP5521_MAX_LEDS];
+ u8 num_channels;
+ u8 num_leds;
+};
+
+static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct lp5521_led, cdev);
+}
+
+static inline struct lp5521_chip *engine_to_lp5521(struct lp5521_engine *engine)
+{
+ return container_of(engine, struct lp5521_chip,
+ engines[engine->id - 1]);
+}
+
+static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led)
+{
+ return container_of(led, struct lp5521_chip,
+ leds[led->id]);
+}
+
+static void lp5521_led_brightness_work(struct work_struct *work);
+
+static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ return -EIO;
+
+ *buf = ret;
+ return 0;
+}
+
+static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode)
+{
+ struct lp5521_chip *chip = engine_to_lp5521(engine);
+ struct i2c_client *client = chip->client;
+ int ret;
+ u8 engine_state;
+
+ /* Only transition between RUN and DIRECT mode are handled here */
+ if (mode == LP5521_CMD_LOAD)
+ return 0;
+
+ if (mode == LP5521_CMD_DISABLED)
+ mode = LP5521_CMD_DIRECT;
+
+ ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state);
+
+ /* set mode only for this engine */
+ engine_state &= ~(engine->engine_mask);
+ mode &= engine->engine_mask;
+ engine_state |= mode;
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
+
+ return ret;
+}
+
+static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
+{
+ struct lp5521_chip *chip = engine_to_lp5521(eng);
+ struct i2c_client *client = chip->client;
+ int ret;
+ int addr;
+ u8 mode;
+
+ /* move current engine to direct mode and remember the state */
+ ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
+ ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode);
+
+ /* For loading, all the engines to load mode */
+ lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
+ lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+ /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
+ usleep_range(1000, 2000);
+
+ addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE;
+ i2c_smbus_write_i2c_block_data(client,
+ addr,
+ LP5521_PROG_MEM_SIZE,
+ pattern);
+
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode);
+ return ret;
+}
+
+static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
+{
+ return lp5521_write(chip->client,
+ LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+ curr);
+}
+
+static void lp5521_init_engine(struct lp5521_chip *chip)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+ chip->engines[i].id = i + 1;
+ chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2);
+ chip->engines[i].prog_page = i;
+ }
+}
+
+static int lp5521_configure(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ int ret;
+
+ lp5521_init_engine(chip);
+
+ /* Set all PWMs to direct control mode */
+ ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+
+ /* Enable auto-powersave, set charge pump to auto, red to battery */
+ ret |= lp5521_write(client, LP5521_REG_CONFIG,
+ LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+
+ /* Initialize all channels PWM to zero -> leds off */
+ ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+ /* Set engines are set to run state when OP_MODE enables engines */
+ ret |= lp5521_write(client, LP5521_REG_ENABLE,
+ LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
+ LP5521_EXEC_RUN);
+ /* enable takes 500us. 1 - 2 ms leaves some margin */
+ usleep_range(1000, 2000);
+
+ return ret;
+}
+
+static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf)
+{
+ int ret;
+ u8 status;
+
+ ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ /* Check that ext clock is really in use if requested */
+ if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT)
+ if ((status & LP5521_EXT_CLK_USED) == 0)
+ return -EIO;
+ return 0;
+}
+
+static void lp5521_set_brightness(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lp5521_led *led = cdev_to_led(cdev);
+ led->brightness = (u8)brightness;
+ schedule_work(&led->brightness_work);
+}
+
+static void lp5521_led_brightness_work(struct work_struct *work)
+{
+ struct lp5521_led *led = container_of(work,
+ struct lp5521_led,
+ brightness_work);
+ struct lp5521_chip *chip = led_to_lp5521(led);
+ struct i2c_client *client = chip->client;
+
+ mutex_lock(&chip->lock);
+ lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+ led->brightness);
+ mutex_unlock(&chip->lock);
+}
+
+/* Detect the chip by setting its ENABLE register and reading it back. */
+static int lp5521_detect(struct i2c_client *client)
+{
+ int ret;
+ u8 buf;
+
+ ret = lp5521_write(client, LP5521_REG_ENABLE,
+ LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+ if (ret)
+ return ret;
+ /* enable takes 500us. 1 - 2 ms leaves some margin */
+ usleep_range(1000, 2000);
+ ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
+ if (ret)
+ return ret;
+ if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+ return -ENODEV;
+
+ return 0;
+}
+
+/* Set engine mode and create appropriate sysfs attributes, if required. */
+static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode)
+{
+ int ret = 0;
+
+ /* if in that mode already do nothing, except for run */
+ if (mode == engine->mode && mode != LP5521_CMD_RUN)
+ return 0;
+
+ if (mode == LP5521_CMD_RUN) {
+ ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN);
+ } else if (mode == LP5521_CMD_LOAD) {
+ lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+ lp5521_set_engine_mode(engine, LP5521_CMD_LOAD);
+ } else if (mode == LP5521_CMD_DISABLED) {
+ lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+ }
+
+ engine->mode = mode;
+
+ return ret;
+}
+
+static int lp5521_do_store_load(struct lp5521_engine *engine,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = engine_to_lp5521(engine);
+ struct i2c_client *client = chip->client;
+ int ret, nrchars, offset = 0, i = 0;
+ char c[3];
+ unsigned cmd;
+ u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+
+ while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+ /* separate sscanfs because length is working only for %s */
+ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+ if (ret != 2)
+ goto fail;
+ ret = sscanf(c, "%2x", &cmd);
+ if (ret != 1)
+ goto fail;
+ pattern[i] = (u8)cmd;
+
+ offset += nrchars;
+ i++;
+ }
+
+ /* Each instruction is 16bit long. Check that length is even */
+ if (i % 2)
+ goto fail;
+
+ mutex_lock(&chip->lock);
+ if (engine->mode == LP5521_CMD_LOAD)
+ ret = lp5521_load_program(engine, pattern);
+ else
+ ret = -EINVAL;
+ mutex_unlock(&chip->lock);
+
+ if (ret) {
+ dev_err(&client->dev, "failed loading pattern\n");
+ return ret;
+ }
+
+ return len;
+fail:
+ dev_err(&client->dev, "wrong pattern format\n");
+ return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ return lp5521_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr) \
+static ssize_t store_engine##nr##_load(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_engine_load(dev, attr, buf, len, nr); \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ switch (chip->engines[nr - 1].mode) {
+ case LP5521_CMD_RUN:
+ return sprintf(buf, "run\n");
+ case LP5521_CMD_LOAD:
+ return sprintf(buf, "load\n");
+ case LP5521_CMD_DISABLED:
+ return sprintf(buf, "disabled\n");
+ default:
+ return sprintf(buf, "disabled\n");
+ }
+}
+
+#define show_mode(nr) \
+static ssize_t show_engine##nr##_mode(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_engine_mode(dev, attr, buf, nr); \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ struct lp5521_engine *engine = &chip->engines[nr - 1];
+ mutex_lock(&chip->lock);
+
+ if (!strncmp(buf, "run", 3))
+ lp5521_set_mode(engine, LP5521_CMD_RUN);
+ else if (!strncmp(buf, "load", 4))
+ lp5521_set_mode(engine, LP5521_CMD_LOAD);
+ else if (!strncmp(buf, "disabled", 8))
+ lp5521_set_mode(engine, LP5521_CMD_DISABLED);
+
+ mutex_unlock(&chip->lock);
+ return len;
+}
+
+#define store_mode(nr) \
+static ssize_t store_engine##nr##_mode(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_engine_mode(dev, attr, buf, len, nr); \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5521_led *led = cdev_to_led(led_cdev);
+
+ return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5521_led *led = cdev_to_led(led_cdev);
+
+ return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5521_led *led = cdev_to_led(led_cdev);
+ struct lp5521_chip *chip = led_to_lp5521(led);
+ ssize_t ret;
+ unsigned long curr;
+
+ if (strict_strtoul(buf, 0, &curr))
+ return -EINVAL;
+
+ if (curr > led->max_current)
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+ ret = lp5521_set_led_current(chip, led->id, curr);
+ mutex_unlock(&chip->lock);
+
+ if (ret < 0)
+ return ret;
+
+ led->led_current = (u8)curr;
+
+ return len;
+}
+
+static ssize_t lp5521_selftest(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&chip->lock);
+ ret = lp5521_run_selftest(chip, buf);
+ mutex_unlock(&chip->lock);
+ return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5521_led_attributes[] = {
+ &dev_attr_led_current.attr,
+ &dev_attr_max_current.attr,
+ NULL,
+};
+
+static struct attribute_group lp5521_led_attribute_group = {
+ .attrs = lp5521_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+ show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+ show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+ show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+
+static struct attribute *lp5521_attributes[] = {
+ &dev_attr_engine1_mode.attr,
+ &dev_attr_engine2_mode.attr,
+ &dev_attr_engine3_mode.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_engine1_load.attr,
+ &dev_attr_engine2_load.attr,
+ &dev_attr_engine3_load.attr,
+ NULL
+};
+
+static const struct attribute_group lp5521_group = {
+ .attrs = lp5521_attributes,
+};
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ return sysfs_create_group(&dev->kobj, &lp5521_group);
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+ int i;
+
+ sysfs_remove_group(&dev->kobj, &lp5521_group);
+
+ for (i = 0; i < chip->num_leds; i++)
+ sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+ &lp5521_led_attribute_group);
+}
+
+static int __init lp5521_init_led(struct lp5521_led *led,
+ struct i2c_client *client,
+ int chan, struct lp5521_platform_data *pdata)
+{
+ struct device *dev = &client->dev;
+ char name[32];
+ int res;
+
+ if (chan >= LP5521_MAX_LEDS)
+ return -EINVAL;
+
+ if (pdata->led_config[chan].led_current == 0)
+ return 0;
+
+ led->led_current = pdata->led_config[chan].led_current;
+ led->max_current = pdata->led_config[chan].max_current;
+ led->chan_nr = pdata->led_config[chan].chan_nr;
+
+ if (led->chan_nr >= LP5521_MAX_LEDS) {
+ dev_err(dev, "Use channel numbers between 0 and %d\n",
+ LP5521_MAX_LEDS - 1);
+ return -EINVAL;
+ }
+
+ snprintf(name, sizeof(name), "%s:channel%d",
+ pdata->label ?: client->name, chan);
+ led->cdev.brightness_set = lp5521_set_brightness;
+ led->cdev.name = name;
+ res = led_classdev_register(dev, &led->cdev);
+ if (res < 0) {
+ dev_err(dev, "couldn't register led on channel %d\n", chan);
+ return res;
+ }
+
+ res = sysfs_create_group(&led->cdev.dev->kobj,
+ &lp5521_led_attribute_group);
+ if (res < 0) {
+ dev_err(dev, "couldn't register current attribute\n");
+ led_classdev_unregister(&led->cdev);
+ return res;
+ }
+ return 0;
+}
+
+static int lp5521_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lp5521_chip *chip;
+ struct lp5521_platform_data *pdata;
+ int ret, i, led;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ pdata = client->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data\n");
+ ret = -EINVAL;
+ goto fail1;
+ }
+
+ mutex_init(&chip->lock);
+
+ chip->pdata = pdata;
+
+ if (pdata->setup_resources) {
+ ret = pdata->setup_resources();
+ if (ret < 0)
+ goto fail1;
+ }
+
+ if (pdata->enable) {
+ pdata->enable(0);
+ usleep_range(1000, 2000); /* Keep enable down at least 1ms */
+ pdata->enable(1);
+ usleep_range(1000, 2000); /* 500us abs min. */
+ }
+
+ lp5521_write(client, LP5521_REG_RESET, 0xff);
+ usleep_range(10000, 20000); /*
+ * Exact value is not available. 10 - 20ms
+ * appears to be enough for reset.
+ */
+ ret = lp5521_detect(client);
+
+ if (ret) {
+ dev_err(&client->dev, "Chip not found\n");
+ goto fail2;
+ }
+
+ dev_info(&client->dev, "%s programmable led chip found\n", id->name);
+
+ ret = lp5521_configure(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "error configuring chip\n");
+ goto fail2;
+ }
+
+ /* Initialize leds */
+ chip->num_channels = pdata->num_channels;
+ chip->num_leds = 0;
+ led = 0;
+ for (i = 0; i < pdata->num_channels; i++) {
+ /* Do not initialize channels that are not connected */
+ if (pdata->led_config[i].led_current == 0)
+ continue;
+
+ ret = lp5521_init_led(&chip->leds[led], client, i, pdata);
+ if (ret) {
+ dev_err(&client->dev, "error initializing leds\n");
+ goto fail3;
+ }
+ chip->num_leds++;
+
+ chip->leds[led].id = led;
+ /* Set initial LED current */
+ lp5521_set_led_current(chip, led,
+ chip->leds[led].led_current);
+
+ INIT_WORK(&(chip->leds[led].brightness_work),
+ lp5521_led_brightness_work);
+
+ led++;
+ }
+
+ ret = lp5521_register_sysfs(client);
+ if (ret) {
+ dev_err(&client->dev, "registering sysfs failed\n");
+ goto fail3;
+ }
+ return ret;
+fail3:
+ for (i = 0; i < chip->num_leds; i++) {
+ led_classdev_unregister(&chip->leds[i].cdev);
+ cancel_work_sync(&chip->leds[i].brightness_work);
+ }
+fail2:
+ if (pdata->enable)
+ pdata->enable(0);
+ if (pdata->release_resources)
+ pdata->release_resources();
+fail1:
+ kfree(chip);
+ return ret;
+}
+
+static int lp5521_remove(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ int i;
+
+ lp5521_unregister_sysfs(client);
+
+ for (i = 0; i < chip->num_leds; i++) {
+ led_classdev_unregister(&chip->leds[i].cdev);
+ cancel_work_sync(&chip->leds[i].brightness_work);
+ }
+
+ if (chip->pdata->enable)
+ chip->pdata->enable(0);
+ if (chip->pdata->release_resources)
+ chip->pdata->release_resources();
+ kfree(chip);
+ return 0;
+}
+
+static const struct i2c_device_id lp5521_id[] = {
+ { "lp5521", 0 }, /* Three channel chip */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+ .driver = {
+ .name = "lp5521",
+ },
+ .probe = lp5521_probe,
+ .remove = lp5521_remove,
+ .id_table = lp5521_id,
+};
+
+static int __init lp5521_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&lp5521_driver);
+
+ if (ret < 0)
+ printk(KERN_ALERT "Adding lp5521 driver failed\n");
+
+ return ret;
+}
+
+static void __exit lp5521_exit(void)
+{
+ i2c_del_driver(&lp5521_driver);
+}
+
+module_init(lp5521_init);
+module_exit(lp5521_exit);
+
+MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
+MODULE_DESCRIPTION("LP5521 LED engine");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
new file mode 100644
index 000000000000..d0c4068ecddd
--- /dev/null
+++ b/drivers/leds/leds-lp5523.c
@@ -0,0 +1,1046 @@
+/*
+ * lp5523.c - LP5523 LED Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5523.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5523_REG_ENABLE 0x00
+#define LP5523_REG_OP_MODE 0x01
+#define LP5523_REG_RATIOMETRIC_MSB 0x02
+#define LP5523_REG_RATIOMETRIC_LSB 0x03
+#define LP5523_REG_ENABLE_LEDS_MSB 0x04
+#define LP5523_REG_ENABLE_LEDS_LSB 0x05
+#define LP5523_REG_LED_CNTRL_BASE 0x06
+#define LP5523_REG_LED_PWM_BASE 0x16
+#define LP5523_REG_LED_CURRENT_BASE 0x26
+#define LP5523_REG_CONFIG 0x36
+#define LP5523_REG_CHANNEL1_PC 0x37
+#define LP5523_REG_CHANNEL2_PC 0x38
+#define LP5523_REG_CHANNEL3_PC 0x39
+#define LP5523_REG_STATUS 0x3a
+#define LP5523_REG_GPO 0x3b
+#define LP5523_REG_VARIABLE 0x3c
+#define LP5523_REG_RESET 0x3d
+#define LP5523_REG_TEMP_CTRL 0x3e
+#define LP5523_REG_TEMP_READ 0x3f
+#define LP5523_REG_TEMP_WRITE 0x40
+#define LP5523_REG_LED_TEST_CTRL 0x41
+#define LP5523_REG_LED_TEST_ADC 0x42
+#define LP5523_REG_ENG1_VARIABLE 0x45
+#define LP5523_REG_ENG2_VARIABLE 0x46
+#define LP5523_REG_ENG3_VARIABLE 0x47
+#define LP5523_REG_MASTER_FADER1 0x48
+#define LP5523_REG_MASTER_FADER2 0x49
+#define LP5523_REG_MASTER_FADER3 0x4a
+#define LP5523_REG_CH1_PROG_START 0x4c
+#define LP5523_REG_CH2_PROG_START 0x4d
+#define LP5523_REG_CH3_PROG_START 0x4e
+#define LP5523_REG_PROG_PAGE_SEL 0x4f
+#define LP5523_REG_PROG_MEM 0x50
+
+#define LP5523_CMD_LOAD 0x15 /* 00010101 */
+#define LP5523_CMD_RUN 0x2a /* 00101010 */
+#define LP5523_CMD_DISABLED 0x00 /* 00000000 */
+
+#define LP5523_ENABLE 0x40
+#define LP5523_AUTO_INC 0x40
+#define LP5523_PWR_SAVE 0x20
+#define LP5523_PWM_PWR_SAVE 0x04
+#define LP5523_CP_1 0x08
+#define LP5523_CP_1_5 0x10
+#define LP5523_CP_AUTO 0x18
+#define LP5523_INT_CLK 0x01
+#define LP5523_AUTO_CLK 0x02
+#define LP5523_EN_LEDTEST 0x80
+#define LP5523_LEDTEST_DONE 0x80
+
+#define LP5523_DEFAULT_CURRENT 50 /* microAmps */
+#define LP5523_PROGRAM_LENGTH 32 /* in bytes */
+#define LP5523_PROGRAM_PAGES 6
+#define LP5523_ADC_SHORTCIRC_LIM 80
+
+#define LP5523_LEDS 9
+#define LP5523_ENGINES 3
+
+#define LP5523_ENG_MASK_BASE 0x30 /* 00110000 */
+
+#define LP5523_ENG_STATUS_MASK 0x07 /* 00000111 */
+
+#define LP5523_IRQ_FLAGS IRQF_TRIGGER_FALLING
+
+#define LP5523_EXT_CLK_USED 0x08
+
+#define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led)))
+#define SHIFT_MASK(id) (((id) - 1) * 2)
+
+struct lp5523_engine {
+ int id;
+ u8 mode;
+ u8 prog_page;
+ u8 mux_page;
+ u16 led_mux;
+ u8 engine_mask;
+};
+
+struct lp5523_led {
+ int id;
+ u8 chan_nr;
+ u8 led_current;
+ u8 max_current;
+ struct led_classdev cdev;
+ struct work_struct brightness_work;
+ u8 brightness;
+};
+
+struct lp5523_chip {
+ struct mutex lock; /* Serialize control */
+ struct i2c_client *client;
+ struct lp5523_engine engines[LP5523_ENGINES];
+ struct lp5523_led leds[LP5523_LEDS];
+ struct lp5523_platform_data *pdata;
+ u8 num_channels;
+ u8 num_leds;
+};
+
+static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct lp5523_led, cdev);
+}
+
+static inline struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
+{
+ return container_of(engine, struct lp5523_chip,
+ engines[engine->id - 1]);
+}
+
+static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
+{
+ return container_of(led, struct lp5523_chip,
+ leds[led->id]);
+}
+
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern);
+
+static void lp5523_led_brightness_work(struct work_struct *work);
+
+static int lp5523_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+ s32 ret = i2c_smbus_read_byte_data(client, reg);
+
+ if (ret < 0)
+ return -EIO;
+
+ *buf = ret;
+ return 0;
+}
+
+static int lp5523_detect(struct i2c_client *client)
+{
+ int ret;
+ u8 buf;
+
+ ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40);
+ if (ret)
+ return ret;
+ ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
+ if (ret)
+ return ret;
+ if (buf == 0x40)
+ return 0;
+ else
+ return -ENODEV;
+}
+
+static int lp5523_configure(struct i2c_client *client)
+{
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ int ret = 0;
+ u8 status;
+
+ /* one pattern per engine setting led mux start and stop addresses */
+ u8 pattern[][LP5523_PROGRAM_LENGTH] = {
+ { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
+ { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
+ { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
+ };
+
+ ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
+ /* Chip startup time is 500 us, 1 - 2 ms gives some margin */
+ usleep_range(1000, 2000);
+
+ ret |= lp5523_write(client, LP5523_REG_CONFIG,
+ LP5523_AUTO_INC | LP5523_PWR_SAVE |
+ LP5523_CP_AUTO | LP5523_AUTO_CLK |
+ LP5523_PWM_PWR_SAVE);
+
+ /* turn on all leds */
+ ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
+ ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
+
+ /* hardcode 32 bytes of memory for each engine from program memory */
+ ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00);
+ ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10);
+ ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20);
+
+ /* write led mux address space for each channel */
+ ret |= lp5523_load_program(&chip->engines[0], pattern[0]);
+ ret |= lp5523_load_program(&chip->engines[1], pattern[1]);
+ ret |= lp5523_load_program(&chip->engines[2], pattern[2]);
+
+ if (ret) {
+ dev_err(&client->dev, "could not load mux programs\n");
+ return -1;
+ }
+
+ /* set all engines exec state and mode to run 00101010 */
+ ret |= lp5523_write(client, LP5523_REG_ENABLE,
+ (LP5523_CMD_RUN | LP5523_ENABLE));
+
+ ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN);
+
+ if (ret) {
+ dev_err(&client->dev, "could not start mux programs\n");
+ return -1;
+ }
+
+ /* Let the programs run for couple of ms and check the engine status */
+ usleep_range(3000, 6000);
+ lp5523_read(client, LP5523_REG_STATUS, &status);
+ status &= LP5523_ENG_STATUS_MASK;
+
+ if (status == LP5523_ENG_STATUS_MASK) {
+ dev_dbg(&client->dev, "all engines configured\n");
+ } else {
+ dev_info(&client->dev, "status == %x\n", status);
+ dev_err(&client->dev, "cound not configure LED engine\n");
+ return -1;
+ }
+
+ dev_info(&client->dev, "disabling engines\n");
+
+ ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+
+ return ret;
+}
+
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode)
+{
+ struct lp5523_chip *chip = engine_to_lp5523(engine);
+ struct i2c_client *client = chip->client;
+ int ret;
+ u8 engine_state;
+
+ ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state);
+ if (ret)
+ goto fail;
+
+ engine_state &= ~(engine->engine_mask);
+
+ /* set mode only for this engine */
+ mode &= engine->engine_mask;
+
+ engine_state |= mode;
+
+ ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state);
+fail:
+ return ret;
+}
+
+static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux)
+{
+ struct lp5523_chip *chip = engine_to_lp5523(engine);
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+ ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page);
+ ret |= lp5523_write(client, LP5523_REG_PROG_MEM,
+ (u8)(mux >> 8));
+ ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux));
+ engine->led_mux = mux;
+
+ return ret;
+}
+
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern)
+{
+ struct lp5523_chip *chip = engine_to_lp5523(engine);
+ struct i2c_client *client = chip->client;
+
+ int ret = 0;
+
+ ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+ ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL,
+ engine->prog_page);
+ ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM,
+ LP5523_PROGRAM_LENGTH, pattern);
+
+ return ret;
+}
+
+static int lp5523_run_program(struct lp5523_engine *engine)
+{
+ struct lp5523_chip *chip = engine_to_lp5523(engine);
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = lp5523_write(client, LP5523_REG_ENABLE,
+ LP5523_CMD_RUN | LP5523_ENABLE);
+ if (ret)
+ goto fail;
+
+ ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN);
+fail:
+ return ret;
+}
+
+static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
+{
+ int i;
+ u16 tmp_mux = 0;
+ len = len < LP5523_LEDS ? len : LP5523_LEDS;
+ for (i = 0; i < len; i++) {
+ switch (buf[i]) {
+ case '1':
+ tmp_mux |= (1 << i);
+ break;
+ case '0':
+ break;
+ case '\n':
+ i = len;
+ break;
+ default:
+ return -1;
+ }
+ }
+ *mux = tmp_mux;
+
+ return 0;
+}
+
+static void lp5523_mux_to_array(u16 led_mux, char *array)
+{
+ int i, pos = 0;
+ for (i = 0; i < LP5523_LEDS; i++)
+ pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
+
+ array[pos] = '\0';
+}
+
+/*--------------------------------------------------------------*/
+/* Sysfs interface */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_engine_leds(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ char mux[LP5523_LEDS + 1];
+
+ lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
+
+ return sprintf(buf, "%s\n", mux);
+}
+
+#define show_leds(nr) \
+static ssize_t show_engine##nr##_leds(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_engine_leds(dev, attr, buf, nr); \
+}
+show_leds(1)
+show_leds(2)
+show_leds(3)
+
+static ssize_t store_engine_leds(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ u16 mux = 0;
+ ssize_t ret;
+
+ if (lp5523_mux_parse(buf, &mux, len))
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+ ret = -EINVAL;
+ if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD)
+ goto leave;
+
+ if (lp5523_load_mux(&chip->engines[nr - 1], mux))
+ goto leave;
+
+ ret = len;
+leave:
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+#define store_leds(nr) \
+static ssize_t store_engine##nr##_leds(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_engine_leds(dev, attr, buf, len, nr); \
+}
+store_leds(1)
+store_leds(2)
+store_leds(3)
+
+static ssize_t lp5523_selftest(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ int i, ret, pos = 0;
+ int led = 0;
+ u8 status, adc, vdd;
+
+ mutex_lock(&chip->lock);
+
+ ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ if (ret < 0)
+ goto fail;
+
+ /* Check that ext clock is really in use if requested */
+ if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT))
+ if ((status & LP5523_EXT_CLK_USED) == 0)
+ goto fail;
+
+ /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
+ lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL,
+ LP5523_EN_LEDTEST | 16);
+ usleep_range(3000, 6000); /* ADC conversion time is typically 2.7 ms */
+ ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ if (!(status & LP5523_LEDTEST_DONE))
+ usleep_range(3000, 6000); /* Was not ready. Wait little bit */
+
+ ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd);
+ vdd--; /* There may be some fluctuation in measurement */
+
+ for (i = 0; i < LP5523_LEDS; i++) {
+ /* Skip non-existing channels */
+ if (chip->pdata->led_config[i].led_current == 0)
+ continue;
+
+ /* Set default current */
+ lp5523_write(chip->client,
+ LP5523_REG_LED_CURRENT_BASE + i,
+ chip->pdata->led_config[i].led_current);
+
+ lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff);
+ /* let current stabilize 2 - 4ms before measurements start */
+ usleep_range(2000, 4000);
+ lp5523_write(chip->client,
+ LP5523_REG_LED_TEST_CTRL,
+ LP5523_EN_LEDTEST | i);
+ /* ADC conversion time is 2.7 ms typically */
+ usleep_range(3000, 6000);
+ ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ if (!(status & LP5523_LEDTEST_DONE))
+ usleep_range(3000, 6000);/* Was not ready. Wait. */
+ ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc);
+
+ if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
+ pos += sprintf(buf + pos, "LED %d FAIL\n", i);
+
+ lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00);
+
+ /* Restore current */
+ lp5523_write(chip->client,
+ LP5523_REG_LED_CURRENT_BASE + i,
+ chip->leds[led].led_current);
+ led++;
+ }
+ if (pos == 0)
+ pos = sprintf(buf, "OK\n");
+ goto release_lock;
+fail:
+ pos = sprintf(buf, "FAIL\n");
+
+release_lock:
+ mutex_unlock(&chip->lock);
+
+ return pos;
+}
+
+static void lp5523_set_brightness(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lp5523_led *led = cdev_to_led(cdev);
+
+ led->brightness = (u8)brightness;
+
+ schedule_work(&led->brightness_work);
+}
+
+static void lp5523_led_brightness_work(struct work_struct *work)
+{
+ struct lp5523_led *led = container_of(work,
+ struct lp5523_led,
+ brightness_work);
+ struct lp5523_chip *chip = led_to_lp5523(led);
+ struct i2c_client *client = chip->client;
+
+ mutex_lock(&chip->lock);
+
+ lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+ led->brightness);
+
+ mutex_unlock(&chip->lock);
+}
+
+static int lp5523_do_store_load(struct lp5523_engine *engine,
+ const char *buf, size_t len)
+{
+ struct lp5523_chip *chip = engine_to_lp5523(engine);
+ struct i2c_client *client = chip->client;
+ int ret, nrchars, offset = 0, i = 0;
+ char c[3];
+ unsigned cmd;
+ u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
+
+ while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
+ /* separate sscanfs because length is working only for %s */
+ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+ ret = sscanf(c, "%2x", &cmd);
+ if (ret != 1)
+ goto fail;
+ pattern[i] = (u8)cmd;
+
+ offset += nrchars;
+ i++;
+ }
+
+ /* Each instruction is 16bit long. Check that length is even */
+ if (i % 2)
+ goto fail;
+
+ mutex_lock(&chip->lock);
+
+ if (engine->mode == LP5523_CMD_LOAD)
+ ret = lp5523_load_program(engine, pattern);
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&chip->lock);
+
+ if (ret) {
+ dev_err(&client->dev, "failed loading pattern\n");
+ return ret;
+ }
+
+ return len;
+fail:
+ dev_err(&client->dev, "wrong pattern format\n");
+ return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ return lp5523_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr) \
+static ssize_t store_engine##nr##_load(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_engine_load(dev, attr, buf, len, nr); \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ switch (chip->engines[nr - 1].mode) {
+ case LP5523_CMD_RUN:
+ return sprintf(buf, "run\n");
+ case LP5523_CMD_LOAD:
+ return sprintf(buf, "load\n");
+ case LP5523_CMD_DISABLED:
+ return sprintf(buf, "disabled\n");
+ default:
+ return sprintf(buf, "disabled\n");
+ }
+}
+
+#define show_mode(nr) \
+static ssize_t show_engine##nr##_mode(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_engine_mode(dev, attr, buf, nr); \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ struct lp5523_engine *engine = &chip->engines[nr - 1];
+ mutex_lock(&chip->lock);
+
+ if (!strncmp(buf, "run", 3))
+ lp5523_set_mode(engine, LP5523_CMD_RUN);
+ else if (!strncmp(buf, "load", 4))
+ lp5523_set_mode(engine, LP5523_CMD_LOAD);
+ else if (!strncmp(buf, "disabled", 8))
+ lp5523_set_mode(engine, LP5523_CMD_DISABLED);
+
+ mutex_unlock(&chip->lock);
+ return len;
+}
+
+#define store_mode(nr) \
+static ssize_t store_engine##nr##_mode(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return store_engine_mode(dev, attr, buf, len, nr); \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5523_led *led = cdev_to_led(led_cdev);
+
+ return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5523_led *led = cdev_to_led(led_cdev);
+
+ return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lp5523_led *led = cdev_to_led(led_cdev);
+ struct lp5523_chip *chip = led_to_lp5523(led);
+ ssize_t ret;
+ unsigned long curr;
+
+ if (strict_strtoul(buf, 0, &curr))
+ return -EINVAL;
+
+ if (curr > led->max_current)
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+ ret = lp5523_write(chip->client,
+ LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
+ (u8)curr);
+ mutex_unlock(&chip->lock);
+
+ if (ret < 0)
+ return ret;
+
+ led->led_current = (u8)curr;
+
+ return len;
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5523_led_attributes[] = {
+ &dev_attr_led_current.attr,
+ &dev_attr_max_current.attr,
+ NULL,
+};
+
+static struct attribute_group lp5523_led_attribute_group = {
+ .attrs = lp5523_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+ show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+ show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+ show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO,
+ show_engine1_leds, store_engine1_leds);
+static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO,
+ show_engine2_leds, store_engine2_leds);
+static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO,
+ show_engine3_leds, store_engine3_leds);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
+
+static struct attribute *lp5523_attributes[] = {
+ &dev_attr_engine1_mode.attr,
+ &dev_attr_engine2_mode.attr,
+ &dev_attr_engine3_mode.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_engine1_load.attr,
+ &dev_attr_engine1_leds.attr,
+ &dev_attr_engine2_load.attr,
+ &dev_attr_engine2_leds.attr,
+ &dev_attr_engine3_load.attr,
+ &dev_attr_engine3_leds.attr,
+};
+
+static const struct attribute_group lp5523_group = {
+ .attrs = lp5523_attributes,
+};
+
+static int lp5523_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int ret;
+
+ ret = sysfs_create_group(&dev->kobj, &lp5523_group);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void lp5523_unregister_sysfs(struct i2c_client *client)
+{
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+ int i;
+
+ sysfs_remove_group(&dev->kobj, &lp5523_group);
+
+ for (i = 0; i < chip->num_leds; i++)
+ sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+ &lp5523_led_attribute_group);
+}
+
+/*--------------------------------------------------------------*/
+/* Set chip operating mode */
+/*--------------------------------------------------------------*/
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
+{
+ int ret = 0;
+
+ /* if in that mode already do nothing, except for run */
+ if (mode == engine->mode && mode != LP5523_CMD_RUN)
+ return 0;
+
+ if (mode == LP5523_CMD_RUN) {
+ ret = lp5523_run_program(engine);
+ } else if (mode == LP5523_CMD_LOAD) {
+ lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+ lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+ } else if (mode == LP5523_CMD_DISABLED) {
+ lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+ }
+
+ engine->mode = mode;
+
+ return ret;
+}
+
+/*--------------------------------------------------------------*/
+/* Probe, Attach, Remove */
+/*--------------------------------------------------------------*/
+static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
+{
+ if (id < 1 || id > LP5523_ENGINES)
+ return -1;
+ engine->id = id;
+ engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
+ engine->prog_page = id - 1;
+ engine->mux_page = id + 2;
+
+ return 0;
+}
+
+static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev,
+ int chan, struct lp5523_platform_data *pdata)
+{
+ char name[32];
+ int res;
+
+ if (chan >= LP5523_LEDS)
+ return -EINVAL;
+
+ if (pdata->led_config[chan].led_current) {
+ led->led_current = pdata->led_config[chan].led_current;
+ led->max_current = pdata->led_config[chan].max_current;
+ led->chan_nr = pdata->led_config[chan].chan_nr;
+
+ if (led->chan_nr >= LP5523_LEDS) {
+ dev_err(dev, "Use channel numbers between 0 and %d\n",
+ LP5523_LEDS - 1);
+ return -EINVAL;
+ }
+
+ snprintf(name, sizeof(name), "%s:channel%d",
+ pdata->label ?: "lp5523", chan);
+
+ led->cdev.name = name;
+ led->cdev.brightness_set = lp5523_set_brightness;
+ res = led_classdev_register(dev, &led->cdev);
+ if (res < 0) {
+ dev_err(dev, "couldn't register led on channel %d\n",
+ chan);
+ return res;
+ }
+ res = sysfs_create_group(&led->cdev.dev->kobj,
+ &lp5523_led_attribute_group);
+ if (res < 0) {
+ dev_err(dev, "couldn't register current attribute\n");
+ led_classdev_unregister(&led->cdev);
+ return res;
+ }
+ } else {
+ led->led_current = 0;
+ }
+ return 0;
+}
+
+static struct i2c_driver lp5523_driver;
+
+static int lp5523_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lp5523_chip *chip;
+ struct lp5523_platform_data *pdata;
+ int ret, i, led;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ pdata = client->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data\n");
+ ret = -EINVAL;
+ goto fail1;
+ }
+
+ mutex_init(&chip->lock);
+
+ chip->pdata = pdata;
+
+ if (pdata->setup_resources) {
+ ret = pdata->setup_resources();
+ if (ret < 0)
+ goto fail1;
+ }
+
+ if (pdata->enable) {
+ pdata->enable(0);
+ usleep_range(1000, 2000); /* Keep enable down at least 1ms */
+ pdata->enable(1);
+ usleep_range(1000, 2000); /* 500us abs min. */
+ }
+
+ lp5523_write(client, LP5523_REG_RESET, 0xff);
+ usleep_range(10000, 20000); /*
+ * Exact value is not available. 10 - 20ms
+ * appears to be enough for reset.
+ */
+ ret = lp5523_detect(client);
+ if (ret)
+ goto fail2;
+
+ dev_info(&client->dev, "LP5523 Programmable led chip found\n");
+
+ /* Initialize engines */
+ for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+ ret = lp5523_init_engine(&chip->engines[i], i + 1);
+ if (ret) {
+ dev_err(&client->dev, "error initializing engine\n");
+ goto fail2;
+ }
+ }
+ ret = lp5523_configure(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "error configuring chip\n");
+ goto fail2;
+ }
+
+ /* Initialize leds */
+ chip->num_channels = pdata->num_channels;
+ chip->num_leds = 0;
+ led = 0;
+ for (i = 0; i < pdata->num_channels; i++) {
+ /* Do not initialize channels that are not connected */
+ if (pdata->led_config[i].led_current == 0)
+ continue;
+
+ ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
+ if (ret) {
+ dev_err(&client->dev, "error initializing leds\n");
+ goto fail3;
+ }
+ chip->num_leds++;
+
+ chip->leds[led].id = led;
+ /* Set LED current */
+ lp5523_write(client,
+ LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+ chip->leds[led].led_current);
+
+ INIT_WORK(&(chip->leds[led].brightness_work),
+ lp5523_led_brightness_work);
+
+ led++;
+ }
+
+ ret = lp5523_register_sysfs(client);
+ if (ret) {
+ dev_err(&client->dev, "registering sysfs failed\n");
+ goto fail3;
+ }
+ return ret;
+fail3:
+ for (i = 0; i < chip->num_leds; i++) {
+ led_classdev_unregister(&chip->leds[i].cdev);
+ cancel_work_sync(&chip->leds[i].brightness_work);
+ }
+fail2:
+ if (pdata->enable)
+ pdata->enable(0);
+ if (pdata->release_resources)
+ pdata->release_resources();
+fail1:
+ kfree(chip);
+ return ret;
+}
+
+static int lp5523_remove(struct i2c_client *client)
+{
+ struct lp5523_chip *chip = i2c_get_clientdata(client);
+ int i;
+
+ lp5523_unregister_sysfs(client);
+
+ for (i = 0; i < chip->num_leds; i++) {
+ led_classdev_unregister(&chip->leds[i].cdev);
+ cancel_work_sync(&chip->leds[i].brightness_work);
+ }
+
+ if (chip->pdata->enable)
+ chip->pdata->enable(0);
+ if (chip->pdata->release_resources)
+ chip->pdata->release_resources();
+ kfree(chip);
+ return 0;
+}
+
+static const struct i2c_device_id lp5523_id[] = {
+ { "lp5523", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, lp5523_id);
+
+static struct i2c_driver lp5523_driver = {
+ .driver = {
+ .name = "lp5523",
+ },
+ .probe = lp5523_probe,
+ .remove = lp5523_remove,
+ .id_table = lp5523_id,
+};
+
+static int __init lp5523_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&lp5523_driver);
+
+ if (ret < 0)
+ printk(KERN_ALERT "Adding lp5523 driver failed\n");
+
+ return ret;
+}
+
+static void __exit lp5523_exit(void)
+{
+ i2c_del_driver(&lp5523_driver);
+}
+
+module_init(lp5523_init);
+module_exit(lp5523_exit);
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_DESCRIPTION("LP5523 LED engine");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-net5501.c b/drivers/leds/leds-net5501.c
index 3063f591f0dc..1739557a9038 100644
--- a/drivers/leds/leds-net5501.c
+++ b/drivers/leds/leds-net5501.c
@@ -92,3 +92,5 @@ unmap:
}
arch_initcall(soekris_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 43d08756d823..afac338d5025 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -200,6 +200,32 @@ static void pca9532_led_work(struct work_struct *work)
pca9532_setled(led);
}
+static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
+{
+ int i = n_devs;
+
+ if (!data)
+ return;
+
+ while (--i >= 0) {
+ switch (data->leds[i].type) {
+ case PCA9532_TYPE_NONE:
+ break;
+ case PCA9532_TYPE_LED:
+ led_classdev_unregister(&data->leds[i].ldev);
+ cancel_work_sync(&data->leds[i].work);
+ break;
+ case PCA9532_TYPE_N2100_BEEP:
+ if (data->idev != NULL) {
+ input_unregister_device(data->idev);
+ cancel_work_sync(&data->work);
+ data->idev = NULL;
+ }
+ break;
+ }
+ }
+}
+
static int pca9532_configure(struct i2c_client *client,
struct pca9532_data *data, struct pca9532_platform_data *pdata)
{
@@ -274,25 +300,7 @@ static int pca9532_configure(struct i2c_client *client,
return 0;
exit:
- if (i > 0)
- for (i = i - 1; i >= 0; i--)
- switch (data->leds[i].type) {
- case PCA9532_TYPE_NONE:
- break;
- case PCA9532_TYPE_LED:
- led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
- break;
- case PCA9532_TYPE_N2100_BEEP:
- if (data->idev != NULL) {
- input_unregister_device(data->idev);
- input_free_device(data->idev);
- cancel_work_sync(&data->work);
- data->idev = NULL;
- }
- break;
- }
-
+ pca9532_destroy_devices(data, i);
return err;
}
@@ -329,25 +337,7 @@ static int pca9532_probe(struct i2c_client *client,
static int pca9532_remove(struct i2c_client *client)
{
struct pca9532_data *data = i2c_get_clientdata(client);
- int i;
- for (i = 0; i < 16; i++)
- switch (data->leds[i].type) {
- case PCA9532_TYPE_NONE:
- break;
- case PCA9532_TYPE_LED:
- led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
- break;
- case PCA9532_TYPE_N2100_BEEP:
- if (data->idev != NULL) {
- input_unregister_device(data->idev);
- input_free_device(data->idev);
- cancel_work_sync(&data->work);
- data->idev = NULL;
- }
- break;
- }
-
+ pca9532_destroy_devices(data, 16);
kfree(data);
return 0;
}
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
index a688293abd0b..614ebebaaa28 100644
--- a/drivers/leds/leds-ss4200.c
+++ b/drivers/leds/leds-ss4200.c
@@ -102,6 +102,7 @@ static struct dmi_system_id __initdata nas_led_whitelist[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
}
},
+ {}
};
/*
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 5aab32ce4f4d..a04523273282 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -276,7 +276,7 @@ static int wm8350_led_remove(struct platform_device *pdev)
struct wm8350_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
- flush_scheduled_work();
+ flush_work_sync(&led->work);
wm8350_led_disable(led);
regulator_put(led->dcdc);
regulator_put(led->isink);
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
index f948e57bd9b8..2b513a2ad7de 100644
--- a/drivers/leds/ledtrig-backlight.c
+++ b/drivers/leds/ledtrig-backlight.c
@@ -26,6 +26,7 @@ struct bl_trig_notifier {
int brightness;
int old_status;
struct notifier_block notifier;
+ unsigned invert;
};
static int fb_notifier_callback(struct notifier_block *p,
@@ -36,23 +37,64 @@ static int fb_notifier_callback(struct notifier_block *p,
struct led_classdev *led = n->led;
struct fb_event *fb_event = data;
int *blank = fb_event->data;
+ int new_status = *blank ? BLANK : UNBLANK;
switch (event) {
case FB_EVENT_BLANK :
- if (*blank && n->old_status == UNBLANK) {
+ if (new_status == n->old_status)
+ break;
+
+ if ((n->old_status == UNBLANK) ^ n->invert) {
n->brightness = led->brightness;
led_set_brightness(led, LED_OFF);
- n->old_status = BLANK;
- } else if (!*blank && n->old_status == BLANK) {
+ } else {
led_set_brightness(led, n->brightness);
- n->old_status = UNBLANK;
}
+
+ n->old_status = new_status;
+
break;
}
return 0;
}
+static ssize_t bl_trig_invert_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led = dev_get_drvdata(dev);
+ struct bl_trig_notifier *n = led->trigger_data;
+
+ return sprintf(buf, "%u\n", n->invert);
+}
+
+static ssize_t bl_trig_invert_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t num)
+{
+ struct led_classdev *led = dev_get_drvdata(dev);
+ struct bl_trig_notifier *n = led->trigger_data;
+ unsigned long invert;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &invert);
+ if (ret < 0)
+ return ret;
+
+ if (invert > 1)
+ return -EINVAL;
+
+ n->invert = invert;
+
+ /* After inverting, we need to update the LED. */
+ if ((n->old_status == BLANK) ^ n->invert)
+ led_set_brightness(led, LED_OFF);
+ else
+ led_set_brightness(led, n->brightness);
+
+ return num;
+}
+static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store);
+
static void bl_trig_activate(struct led_classdev *led)
{
int ret;
@@ -66,6 +108,10 @@ static void bl_trig_activate(struct led_classdev *led)
return;
}
+ ret = device_create_file(led->dev, &dev_attr_inverted);
+ if (ret)
+ goto err_invert;
+
n->led = led;
n->brightness = led->brightness;
n->old_status = UNBLANK;
@@ -74,6 +120,12 @@ static void bl_trig_activate(struct led_classdev *led)
ret = fb_register_client(&n->notifier);
if (ret)
dev_err(led->dev, "unable to register backlight trigger\n");
+
+ return;
+
+err_invert:
+ led->trigger_data = NULL;
+ kfree(n);
}
static void bl_trig_deactivate(struct led_classdev *led)
@@ -82,6 +134,7 @@ static void bl_trig_deactivate(struct led_classdev *led)
(struct bl_trig_notifier *) led->trigger_data;
if (n) {
+ device_remove_file(led->dev, &dev_attr_inverted);
fb_unregister_client(&n->notifier);
kfree(n);
}
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 82b77bd482ff..b09bcbeade9c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -12,73 +12,25 @@
*/
#include <linux/module.h>
-#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
#include <linux/device.h>
-#include <linux/sysdev.h>
-#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/leds.h>
-#include <linux/slab.h>
#include "leds.h"
-struct timer_trig_data {
- int brightness_on; /* LED brightness during "on" period.
- * (LED_OFF < brightness_on <= LED_FULL)
- */
- unsigned long delay_on; /* milliseconds on */
- unsigned long delay_off; /* milliseconds off */
- struct timer_list timer;
-};
-
-static void led_timer_function(unsigned long data)
-{
- struct led_classdev *led_cdev = (struct led_classdev *) data;
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
- unsigned long brightness;
- unsigned long delay;
-
- if (!timer_data->delay_on || !timer_data->delay_off) {
- led_set_brightness(led_cdev, LED_OFF);
- return;
- }
-
- brightness = led_get_brightness(led_cdev);
- if (!brightness) {
- /* Time to switch the LED on. */
- brightness = timer_data->brightness_on;
- delay = timer_data->delay_on;
- } else {
- /* Store the current brightness value to be able
- * to restore it when the delay_off period is over.
- */
- timer_data->brightness_on = brightness;
- brightness = LED_OFF;
- delay = timer_data->delay_off;
- }
-
- led_set_brightness(led_cdev, brightness);
-
- mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
-}
-
static ssize_t led_delay_on_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
- return sprintf(buf, "%lu\n", timer_data->delay_on);
+ return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
}
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 = dev_get_drvdata(dev);
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
@@ -88,21 +40,7 @@ static ssize_t led_delay_on_store(struct device *dev,
count++;
if (count == size) {
- if (timer_data->delay_on != state) {
- /* the new value differs from the previous */
- timer_data->delay_on = state;
-
- /* deactivate previous settings */
- del_timer_sync(&timer_data->timer);
-
- /* try to activate hardware acceleration, if any */
- if (!led_cdev->blink_set ||
- led_cdev->blink_set(led_cdev,
- &timer_data->delay_on, &timer_data->delay_off)) {
- /* no hardware acceleration, blink via timer */
- mod_timer(&timer_data->timer, jiffies + 1);
- }
- }
+ led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
ret = count;
}
@@ -113,16 +51,14 @@ static ssize_t led_delay_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
- return sprintf(buf, "%lu\n", timer_data->delay_off);
+ return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
}
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 = dev_get_drvdata(dev);
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
@@ -132,21 +68,7 @@ static ssize_t led_delay_off_store(struct device *dev,
count++;
if (count == size) {
- if (timer_data->delay_off != state) {
- /* the new value differs from the previous */
- timer_data->delay_off = state;
-
- /* deactivate previous settings */
- del_timer_sync(&timer_data->timer);
-
- /* try to activate hardware acceleration, if any */
- if (!led_cdev->blink_set ||
- led_cdev->blink_set(led_cdev,
- &timer_data->delay_on, &timer_data->delay_off)) {
- /* no hardware acceleration, blink via timer */
- mod_timer(&timer_data->timer, jiffies + 1);
- }
- }
+ led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
ret = count;
}
@@ -158,60 +80,34 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
static void timer_trig_activate(struct led_classdev *led_cdev)
{
- struct timer_trig_data *timer_data;
int rc;
- timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
- if (!timer_data)
- return;
-
- timer_data->brightness_on = led_get_brightness(led_cdev);
- if (timer_data->brightness_on == LED_OFF)
- timer_data->brightness_on = led_cdev->max_brightness;
- led_cdev->trigger_data = timer_data;
-
- init_timer(&timer_data->timer);
- timer_data->timer.function = led_timer_function;
- timer_data->timer.data = (unsigned long) led_cdev;
+ led_cdev->trigger_data = NULL;
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
if (rc)
- goto err_out;
+ return;
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
if (rc)
goto err_out_delayon;
- /* If there is hardware support for blinking, start one
- * user friendly blink rate chosen by the driver.
- */
- if (led_cdev->blink_set)
- led_cdev->blink_set(led_cdev,
- &timer_data->delay_on, &timer_data->delay_off);
+ led_cdev->trigger_data = (void *)1;
return;
err_out_delayon:
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
-err_out:
- led_cdev->trigger_data = NULL;
- kfree(timer_data);
}
static void timer_trig_deactivate(struct led_classdev *led_cdev)
{
- struct timer_trig_data *timer_data = led_cdev->trigger_data;
- unsigned long on = 0, off = 0;
-
- if (timer_data) {
+ if (led_cdev->trigger_data) {
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);
}
- /* If there is hardware support for blinking, stop it */
- if (led_cdev->blink_set)
- led_cdev->blink_set(led_cdev, &on, &off);
+ /* Stop blinking */
+ led_brightness_set(led_cdev, LED_OFF);
}
static struct led_trigger timer_led_trigger = {
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 3d7355ff7308..fa51af11c6f1 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -102,6 +102,7 @@ config ADB_PMU_LED
config ADB_PMU_LED_IDE
bool "Use front LED as IDE LED by default"
depends on ADB_PMU_LED
+ depends on LEDS_CLASS
select LEDS_TRIGGERS
select LEDS_TRIGGER_IDE_DISK
help
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index 444696625171..f5f4da3d0b67 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -80,7 +80,7 @@ static void adb_iop_end_req(struct adb_request *req, int state)
static void adb_iop_complete(struct iop_msg *msg)
{
struct adb_request *req;
- uint flags;
+ unsigned long flags;
local_irq_save(flags);
@@ -103,7 +103,7 @@ static void adb_iop_listen(struct iop_msg *msg)
{
struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
struct adb_request *req;
- uint flags;
+ unsigned long flags;
#ifdef DEBUG_ADB_IOP
int i;
#endif
diff --git a/drivers/macintosh/ams/ams-core.c b/drivers/macintosh/ams/ams-core.c
index 2ad62c339cd2..399beb1638d1 100644
--- a/drivers/macintosh/ams/ams-core.c
+++ b/drivers/macintosh/ams/ams-core.c
@@ -226,7 +226,7 @@ void ams_sensor_detach(void)
* We do this after ams_info.exit(), because an interrupt might
* have arrived before disabling them.
*/
- flush_scheduled_work();
+ flush_work_sync(&ams_info.worker);
/* Remove device */
of_device_unregister(ams_info.of_dev);
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 067f9962f499..6a82388505f0 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -23,6 +23,8 @@ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
static struct input_dev *mac_hid_emumouse_dev;
+static DEFINE_MUTEX(mac_hid_emumouse_mutex);
+
static int mac_hid_create_emumouse(void)
{
static struct lock_class_key mac_hid_emumouse_dev_event_class;
@@ -187,6 +189,10 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
int old_val = *valp;
int rc;
+ rc = mutex_lock_killable(&mac_hid_emumouse_mutex);
+ if (rc)
+ return rc;
+
rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (rc == 0 && write && *valp != old_val) {
@@ -202,6 +208,8 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
if (rc)
*valp = old_val;
+ mutex_unlock(&mac_hid_emumouse_mutex);
+
return rc;
}
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index b6e7ddc09d76..4daf9e5a7736 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -387,11 +387,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
/* Set the DMA ops to the ones from the PCI device, this could be
* fishy if we didn't know that on PowerMac it's always direct ops
* or iommu ops that will work fine
+ *
+ * To get all the fields, copy all archdata
*/
- dev->ofdev.dev.archdata.dma_ops =
- chip->lbus.pdev->dev.archdata.dma_ops;
- dev->ofdev.dev.archdata.dma_data =
- chip->lbus.pdev->dev.archdata.dma_data;
+ dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata;
#endif /* CONFIG_PCI */
#ifdef DEBUG
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 53cce3a5da23..39f660b2a60d 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -285,8 +285,8 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
{
- cancel_rearming_delayed_work(&rm->cpu[0].sniffer);
- cancel_rearming_delayed_work(&rm->cpu[1].sniffer);
+ cancel_delayed_work_sync(&rm->cpu[0].sniffer);
+ cancel_delayed_work_sync(&rm->cpu[1].sniffer);
}
static int __devinit rackmeter_setup(struct rackmeter *rm)
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 44549272333c..2e041fd0a00c 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -2213,6 +2213,9 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
static int fcu_of_probe(struct platform_device* dev, const struct of_device_id *match)
{
state = state_detached;
+ of_dev = dev;
+
+ dev_info(&dev->dev, "PowerMac G5 Thermal control driver %s\n", VERSION);
/* Lookup the fans in the device tree */
fcu_lookup_fans(dev->dev.of_node);
@@ -2235,6 +2238,7 @@ static const struct of_device_id fcu_match[] =
},
{},
};
+MODULE_DEVICE_TABLE(of, fcu_match);
static struct of_platform_driver fcu_of_platform_driver =
{
@@ -2252,8 +2256,6 @@ static struct of_platform_driver fcu_of_platform_driver =
*/
static int __init therm_pm72_init(void)
{
- struct device_node *np;
-
rackmac = of_machine_is_compatible("RackMac3,1");
if (!of_machine_is_compatible("PowerMac7,2") &&
@@ -2261,34 +2263,12 @@ static int __init therm_pm72_init(void)
!rackmac)
return -ENODEV;
- printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION);
-
- np = of_find_node_by_type(NULL, "fcu");
- if (np == NULL) {
- /* Some machines have strangely broken device-tree */
- np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e");
- if (np == NULL) {
- printk(KERN_ERR "Can't find FCU in device-tree !\n");
- return -ENODEV;
- }
- }
- of_dev = of_platform_device_create(np, "temperature", NULL);
- if (of_dev == NULL) {
- printk(KERN_ERR "Can't register FCU platform device !\n");
- return -ENODEV;
- }
-
- of_register_platform_driver(&fcu_of_platform_driver);
-
- return 0;
+ return of_register_platform_driver(&fcu_of_platform_driver);
}
static void __exit therm_pm72_exit(void)
{
of_unregister_platform_driver(&fcu_of_platform_driver);
-
- if (of_dev)
- of_device_unregister(of_dev);
}
module_init(therm_pm72_init);
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 1cec02f6c431..ade1e656bfb2 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -15,7 +15,7 @@
#define MAX_PMU_LEVEL 0xFF
-static struct backlight_ops pmu_backlight_data;
+static const struct backlight_ops pmu_backlight_data;
static DEFINE_SPINLOCK(pmu_backlight_lock);
static int sleeping, uses_pmu_bl;
static u8 bl_curve[FB_BACKLIGHT_LEVELS];
@@ -115,7 +115,7 @@ static int pmu_backlight_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops pmu_backlight_data = {
+static const struct backlight_ops pmu_backlight_data = {
.get_brightness = pmu_backlight_get_brightness,
.update_status = pmu_backlight_update_status,
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index cd29c8248386..8b021eb0d48c 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -2257,7 +2257,7 @@ static int pmu_sleep_valid(suspend_state_t state)
&& (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0);
}
-static struct platform_suspend_ops pmu_pm_ops = {
+static const struct platform_suspend_ops pmu_pm_ops = {
.enter = powerbook_sleep,
.valid = pmu_sleep_valid,
};
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index bf1a95e31559..98d9ec85e0eb 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -240,6 +240,30 @@ config DM_MIRROR
Allow volume managers to mirror logical volumes, also
needed for live data migration tools such as 'pvmove'.
+config DM_RAID
+ tristate "RAID 4/5/6 target (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ select MD_RAID456
+ select BLK_DEV_MD
+ ---help---
+ A dm target that supports RAID4, RAID5 and RAID6 mappings
+
+ A RAID-5 set of N drives with a capacity of C MB per drive provides
+ the capacity of C * (N - 1) MB, and protects against a failure
+ of a single drive. For a given sector (row) number, (N - 1) drives
+ contain data sectors, and one drive contains the parity protection.
+ For a RAID-4 set, the parity blocks are present on a single drive,
+ while a RAID-5 set distributes the parity across the drives in one
+ of the available parity distribution methods.
+
+ A RAID-6 set of N drives with a capacity of C MB per drive
+ provides the capacity of C * (N - 2) MB, and protects
+ against a failure of any two drives. For a given sector
+ (row) number, (N - 2) drives contain data sectors, and two
+ drives contains two independent redundancy syndromes. Like
+ RAID-5, RAID-6 distributes the syndromes across the drives
+ in one of the available parity distribution methods.
+
config DM_LOG_USERSPACE
tristate "Mirror userspace logging (EXPERIMENTAL)"
depends on DM_MIRROR && EXPERIMENTAL && NET
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 5e3aac41919d..d0138606c2e8 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
+obj-$(CONFIG_DM_RAID) += dm-raid.o
ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 5a1ffe3527aa..9a35320fb59f 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -210,11 +210,11 @@ static struct page *read_sb_page(mddev_t *mddev, loff_t offset,
|| test_bit(Faulty, &rdev->flags))
continue;
- target = rdev->sb_start + offset + index * (PAGE_SIZE/512);
+ target = offset + index * (PAGE_SIZE/512);
if (sync_page_io(rdev, target,
roundup(size, bdev_logical_block_size(rdev->bdev)),
- page, READ)) {
+ page, READ, true)) {
page->index = index;
attach_page_buffers(page, NULL); /* so that free_buffer will
* quietly no-op */
@@ -264,14 +264,18 @@ static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
{
mdk_rdev_t *rdev = NULL;
+ struct block_device *bdev;
mddev_t *mddev = bitmap->mddev;
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
int size = PAGE_SIZE;
loff_t offset = mddev->bitmap_info.offset;
+
+ bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
+
if (page->index == bitmap->file_pages-1)
size = roundup(bitmap->last_page_size,
- bdev_logical_block_size(rdev->bdev));
+ bdev_logical_block_size(bdev));
/* Just make sure we aren't corrupting data or
* metadata
*/
@@ -1542,7 +1546,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
wait_event(bitmap->mddev->recovery_wait,
atomic_read(&bitmap->mddev->recovery_active) == 0);
- bitmap->mddev->curr_resync_completed = bitmap->mddev->curr_resync;
+ bitmap->mddev->curr_resync_completed = sector;
set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
s = 0;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index d5b0e4c0e702..4e054bd91664 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -18,10 +18,14 @@
#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <linux/backing-dev.h>
+#include <linux/percpu.h>
#include <asm/atomic.h>
#include <linux/scatterlist.h>
#include <asm/page.h>
#include <asm/unaligned.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/algapi.h>
#include <linux/device-mapper.h>
@@ -63,6 +67,7 @@ struct dm_crypt_request {
struct convert_context *ctx;
struct scatterlist sg_in;
struct scatterlist sg_out;
+ sector_t iv_sector;
};
struct crypt_config;
@@ -73,11 +78,13 @@ struct crypt_iv_operations {
void (*dtr)(struct crypt_config *cc);
int (*init)(struct crypt_config *cc);
int (*wipe)(struct crypt_config *cc);
- int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+ int (*generator)(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq);
+ int (*post)(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq);
};
struct iv_essiv_private {
- struct crypto_cipher *tfm;
struct crypto_hash *hash_tfm;
u8 *salt;
};
@@ -86,11 +93,32 @@ struct iv_benbi_private {
int shift;
};
+#define LMK_SEED_SIZE 64 /* hash + 0 */
+struct iv_lmk_private {
+ struct crypto_shash *hash_tfm;
+ u8 *seed;
+};
+
/*
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
*/
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
+
+/*
+ * Duplicated per-CPU state for cipher.
+ */
+struct crypt_cpu {
+ struct ablkcipher_request *req;
+ /* ESSIV: struct crypto_cipher *essiv_tfm */
+ void *iv_private;
+ struct crypto_ablkcipher *tfms[0];
+};
+
+/*
+ * The fields in here must be read only after initialization,
+ * changing state should be in crypt_cpu.
+ */
struct crypt_config {
struct dm_dev *dev;
sector_t start;
@@ -108,17 +136,25 @@ struct crypt_config {
struct workqueue_struct *crypt_queue;
char *cipher;
- char *cipher_mode;
+ char *cipher_string;
struct crypt_iv_operations *iv_gen_ops;
union {
struct iv_essiv_private essiv;
struct iv_benbi_private benbi;
+ struct iv_lmk_private lmk;
} iv_gen_private;
sector_t iv_offset;
unsigned int iv_size;
/*
+ * Duplicated per cpu state. Access through
+ * per_cpu_ptr() only.
+ */
+ struct crypt_cpu __percpu *cpu;
+ unsigned tfms_count;
+
+ /*
* Layout of each crypto request:
*
* struct ablkcipher_request
@@ -132,11 +168,10 @@ struct crypt_config {
* correctly aligned.
*/
unsigned int dmreq_start;
- struct ablkcipher_request *req;
- struct crypto_ablkcipher *tfm;
unsigned long flags;
unsigned int key_size;
+ unsigned int key_parts;
u8 key[0];
};
@@ -148,6 +183,20 @@ static struct kmem_cache *_crypt_io_pool;
static void clone_init(struct dm_crypt_io *, struct bio *);
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
+static u8 *iv_of_dmreq(struct crypt_config *cc, struct dm_crypt_request *dmreq);
+
+static struct crypt_cpu *this_crypt_config(struct crypt_config *cc)
+{
+ return this_cpu_ptr(cc->cpu);
+}
+
+/*
+ * Use this to access cipher attributes that are the same for each CPU.
+ */
+static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
+{
+ return __this_cpu_ptr(cc->cpu)->tfms[0];
+}
/*
* Different IV generation algorithms:
@@ -168,23 +217,38 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io);
* null: the initial vector is always zero. Provides compatibility with
* obsolete loop_fish2 devices. Do not use for new devices.
*
+ * lmk: Compatible implementation of the block chaining mode used
+ * by the Loop-AES block device encryption system
+ * designed by Jari Ruusu. See http://loop-aes.sourceforge.net/
+ * It operates on full 512 byte sectors and uses CBC
+ * with an IV derived from the sector number, the data and
+ * optionally extra IV seed.
+ * This means that after decryption the first block
+ * of sector must be tweaked according to decrypted data.
+ * Loop-AES can use three encryption schemes:
+ * version 1: is plain aes-cbc mode
+ * version 2: uses 64 multikey scheme with lmk IV generator
+ * version 3: the same as version 2 with additional IV seed
+ * (it uses 65 keys, last key is used as IV seed)
+ *
* plumb: unimplemented, see:
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
*/
-static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
{
memset(iv, 0, cc->iv_size);
- *(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
+ *(u32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff);
return 0;
}
static int crypt_iv_plain64_gen(struct crypt_config *cc, u8 *iv,
- sector_t sector)
+ struct dm_crypt_request *dmreq)
{
memset(iv, 0, cc->iv_size);
- *(u64 *)iv = cpu_to_le64(sector);
+ *(u64 *)iv = cpu_to_le64(dmreq->iv_sector);
return 0;
}
@@ -195,7 +259,8 @@ static int crypt_iv_essiv_init(struct crypt_config *cc)
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
struct hash_desc desc;
struct scatterlist sg;
- int err;
+ struct crypto_cipher *essiv_tfm;
+ int err, cpu;
sg_init_one(&sg, cc->key, cc->key_size);
desc.tfm = essiv->hash_tfm;
@@ -205,8 +270,16 @@ static int crypt_iv_essiv_init(struct crypt_config *cc)
if (err)
return err;
- return crypto_cipher_setkey(essiv->tfm, essiv->salt,
+ for_each_possible_cpu(cpu) {
+ essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private,
+
+ err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
crypto_hash_digestsize(essiv->hash_tfm));
+ if (err)
+ return err;
+ }
+
+ return 0;
}
/* Wipe salt and reset key derived from volume key */
@@ -214,24 +287,76 @@ static int crypt_iv_essiv_wipe(struct crypt_config *cc)
{
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm);
+ struct crypto_cipher *essiv_tfm;
+ int cpu, r, err = 0;
memset(essiv->salt, 0, salt_size);
- return crypto_cipher_setkey(essiv->tfm, essiv->salt, salt_size);
+ for_each_possible_cpu(cpu) {
+ essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private;
+ r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
+ if (r)
+ err = r;
+ }
+
+ return err;
+}
+
+/* Set up per cpu cipher state */
+static struct crypto_cipher *setup_essiv_cpu(struct crypt_config *cc,
+ struct dm_target *ti,
+ u8 *salt, unsigned saltsize)
+{
+ struct crypto_cipher *essiv_tfm;
+ int err;
+
+ /* Setup the essiv_tfm with the given salt */
+ essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(essiv_tfm)) {
+ ti->error = "Error allocating crypto tfm for ESSIV";
+ return essiv_tfm;
+ }
+
+ if (crypto_cipher_blocksize(essiv_tfm) !=
+ crypto_ablkcipher_ivsize(any_tfm(cc))) {
+ ti->error = "Block size of ESSIV cipher does "
+ "not match IV size of block cipher";
+ crypto_free_cipher(essiv_tfm);
+ return ERR_PTR(-EINVAL);
+ }
+
+ err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
+ if (err) {
+ ti->error = "Failed to set key for ESSIV cipher";
+ crypto_free_cipher(essiv_tfm);
+ return ERR_PTR(err);
+ }
+
+ return essiv_tfm;
}
static void crypt_iv_essiv_dtr(struct crypt_config *cc)
{
+ int cpu;
+ struct crypt_cpu *cpu_cc;
+ struct crypto_cipher *essiv_tfm;
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
- crypto_free_cipher(essiv->tfm);
- essiv->tfm = NULL;
-
crypto_free_hash(essiv->hash_tfm);
essiv->hash_tfm = NULL;
kzfree(essiv->salt);
essiv->salt = NULL;
+
+ for_each_possible_cpu(cpu) {
+ cpu_cc = per_cpu_ptr(cc->cpu, cpu);
+ essiv_tfm = cpu_cc->iv_private;
+
+ if (essiv_tfm)
+ crypto_free_cipher(essiv_tfm);
+
+ cpu_cc->iv_private = NULL;
+ }
}
static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
@@ -240,7 +365,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
struct crypto_cipher *essiv_tfm = NULL;
struct crypto_hash *hash_tfm = NULL;
u8 *salt = NULL;
- int err;
+ int err, cpu;
if (!opts) {
ti->error = "Digest algorithm missing for ESSIV mode";
@@ -262,48 +387,44 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
goto bad;
}
- /* Allocate essiv_tfm */
- essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(essiv_tfm)) {
- ti->error = "Error allocating crypto tfm for ESSIV";
- err = PTR_ERR(essiv_tfm);
- goto bad;
- }
- if (crypto_cipher_blocksize(essiv_tfm) !=
- crypto_ablkcipher_ivsize(cc->tfm)) {
- ti->error = "Block size of ESSIV cipher does "
- "not match IV size of block cipher";
- err = -EINVAL;
- goto bad;
- }
-
cc->iv_gen_private.essiv.salt = salt;
- cc->iv_gen_private.essiv.tfm = essiv_tfm;
cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
+ for_each_possible_cpu(cpu) {
+ essiv_tfm = setup_essiv_cpu(cc, ti, salt,
+ crypto_hash_digestsize(hash_tfm));
+ if (IS_ERR(essiv_tfm)) {
+ crypt_iv_essiv_dtr(cc);
+ return PTR_ERR(essiv_tfm);
+ }
+ per_cpu_ptr(cc->cpu, cpu)->iv_private = essiv_tfm;
+ }
+
return 0;
bad:
- if (essiv_tfm && !IS_ERR(essiv_tfm))
- crypto_free_cipher(essiv_tfm);
if (hash_tfm && !IS_ERR(hash_tfm))
crypto_free_hash(hash_tfm);
kfree(salt);
return err;
}
-static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
{
+ struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private;
+
memset(iv, 0, cc->iv_size);
- *(u64 *)iv = cpu_to_le64(sector);
- crypto_cipher_encrypt_one(cc->iv_gen_private.essiv.tfm, iv, iv);
+ *(u64 *)iv = cpu_to_le64(dmreq->iv_sector);
+ crypto_cipher_encrypt_one(essiv_tfm, iv, iv);
+
return 0;
}
static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
- unsigned bs = crypto_ablkcipher_blocksize(cc->tfm);
+ unsigned bs = crypto_ablkcipher_blocksize(any_tfm(cc));
int log = ilog2(bs);
/* we need to calculate how far we must shift the sector count
@@ -328,25 +449,177 @@ static void crypt_iv_benbi_dtr(struct crypt_config *cc)
{
}
-static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
{
__be64 val;
memset(iv, 0, cc->iv_size - sizeof(u64)); /* rest is cleared below */
- val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi.shift) + 1);
+ val = cpu_to_be64(((u64)dmreq->iv_sector << cc->iv_gen_private.benbi.shift) + 1);
put_unaligned(val, (__be64 *)(iv + cc->iv_size - sizeof(u64)));
return 0;
}
-static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
{
memset(iv, 0, cc->iv_size);
return 0;
}
+static void crypt_iv_lmk_dtr(struct crypt_config *cc)
+{
+ struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
+
+ if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm))
+ crypto_free_shash(lmk->hash_tfm);
+ lmk->hash_tfm = NULL;
+
+ kzfree(lmk->seed);
+ lmk->seed = NULL;
+}
+
+static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts)
+{
+ struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
+
+ lmk->hash_tfm = crypto_alloc_shash("md5", 0, 0);
+ if (IS_ERR(lmk->hash_tfm)) {
+ ti->error = "Error initializing LMK hash";
+ return PTR_ERR(lmk->hash_tfm);
+ }
+
+ /* No seed in LMK version 2 */
+ if (cc->key_parts == cc->tfms_count) {
+ lmk->seed = NULL;
+ return 0;
+ }
+
+ lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL);
+ if (!lmk->seed) {
+ crypt_iv_lmk_dtr(cc);
+ ti->error = "Error kmallocing seed storage in LMK";
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int crypt_iv_lmk_init(struct crypt_config *cc)
+{
+ struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
+ int subkey_size = cc->key_size / cc->key_parts;
+
+ /* LMK seed is on the position of LMK_KEYS + 1 key */
+ if (lmk->seed)
+ memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size),
+ crypto_shash_digestsize(lmk->hash_tfm));
+
+ return 0;
+}
+
+static int crypt_iv_lmk_wipe(struct crypt_config *cc)
+{
+ struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
+
+ if (lmk->seed)
+ memset(lmk->seed, 0, LMK_SEED_SIZE);
+
+ return 0;
+}
+
+static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq,
+ u8 *data)
+{
+ struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
+ struct {
+ struct shash_desc desc;
+ char ctx[crypto_shash_descsize(lmk->hash_tfm)];
+ } sdesc;
+ struct md5_state md5state;
+ u32 buf[4];
+ int i, r;
+
+ sdesc.desc.tfm = lmk->hash_tfm;
+ sdesc.desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ r = crypto_shash_init(&sdesc.desc);
+ if (r)
+ return r;
+
+ if (lmk->seed) {
+ r = crypto_shash_update(&sdesc.desc, lmk->seed, LMK_SEED_SIZE);
+ if (r)
+ return r;
+ }
+
+ /* Sector is always 512B, block size 16, add data of blocks 1-31 */
+ r = crypto_shash_update(&sdesc.desc, data + 16, 16 * 31);
+ if (r)
+ return r;
+
+ /* Sector is cropped to 56 bits here */
+ buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF);
+ buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000);
+ buf[2] = cpu_to_le32(4024);
+ buf[3] = 0;
+ r = crypto_shash_update(&sdesc.desc, (u8 *)buf, sizeof(buf));
+ if (r)
+ return r;
+
+ /* No MD5 padding here */
+ r = crypto_shash_export(&sdesc.desc, &md5state);
+ if (r)
+ return r;
+
+ for (i = 0; i < MD5_HASH_WORDS; i++)
+ __cpu_to_le32s(&md5state.hash[i]);
+ memcpy(iv, &md5state.hash, cc->iv_size);
+
+ return 0;
+}
+
+static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
+{
+ u8 *src;
+ int r = 0;
+
+ if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
+ src = kmap_atomic(sg_page(&dmreq->sg_in), KM_USER0);
+ r = crypt_iv_lmk_one(cc, iv, dmreq, src + dmreq->sg_in.offset);
+ kunmap_atomic(src, KM_USER0);
+ } else
+ memset(iv, 0, cc->iv_size);
+
+ return r;
+}
+
+static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
+{
+ u8 *dst;
+ int r;
+
+ if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
+ return 0;
+
+ dst = kmap_atomic(sg_page(&dmreq->sg_out), KM_USER0);
+ r = crypt_iv_lmk_one(cc, iv, dmreq, dst + dmreq->sg_out.offset);
+
+ /* Tweak the first block of plaintext sector */
+ if (!r)
+ crypto_xor(dst + dmreq->sg_out.offset, iv, cc->iv_size);
+
+ kunmap_atomic(dst, KM_USER0);
+ return r;
+}
+
static struct crypt_iv_operations crypt_iv_plain_ops = {
.generator = crypt_iv_plain_gen
};
@@ -373,6 +646,15 @@ static struct crypt_iv_operations crypt_iv_null_ops = {
.generator = crypt_iv_null_gen
};
+static struct crypt_iv_operations crypt_iv_lmk_ops = {
+ .ctr = crypt_iv_lmk_ctr,
+ .dtr = crypt_iv_lmk_dtr,
+ .init = crypt_iv_lmk_init,
+ .wipe = crypt_iv_lmk_wipe,
+ .generator = crypt_iv_lmk_gen,
+ .post = crypt_iv_lmk_post
+};
+
static void crypt_convert_init(struct crypt_config *cc,
struct convert_context *ctx,
struct bio *bio_out, struct bio *bio_in,
@@ -400,6 +682,13 @@ static struct ablkcipher_request *req_of_dmreq(struct crypt_config *cc,
return (struct ablkcipher_request *)((char *)dmreq - cc->dmreq_start);
}
+static u8 *iv_of_dmreq(struct crypt_config *cc,
+ struct dm_crypt_request *dmreq)
+{
+ return (u8 *)ALIGN((unsigned long)(dmreq + 1),
+ crypto_ablkcipher_alignmask(any_tfm(cc)) + 1);
+}
+
static int crypt_convert_block(struct crypt_config *cc,
struct convert_context *ctx,
struct ablkcipher_request *req)
@@ -411,9 +700,9 @@ static int crypt_convert_block(struct crypt_config *cc,
int r = 0;
dmreq = dmreq_of_req(cc, req);
- iv = (u8 *)ALIGN((unsigned long)(dmreq + 1),
- crypto_ablkcipher_alignmask(cc->tfm) + 1);
+ iv = iv_of_dmreq(cc, dmreq);
+ dmreq->iv_sector = ctx->sector;
dmreq->ctx = ctx;
sg_init_table(&dmreq->sg_in, 1);
sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT,
@@ -436,7 +725,7 @@ static int crypt_convert_block(struct crypt_config *cc,
}
if (cc->iv_gen_ops) {
- r = cc->iv_gen_ops->generator(cc, iv, ctx->sector);
+ r = cc->iv_gen_ops->generator(cc, iv, dmreq);
if (r < 0)
return r;
}
@@ -449,21 +738,28 @@ static int crypt_convert_block(struct crypt_config *cc,
else
r = crypto_ablkcipher_decrypt(req);
+ if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
+ r = cc->iv_gen_ops->post(cc, iv, dmreq);
+
return r;
}
static void kcryptd_async_done(struct crypto_async_request *async_req,
int error);
+
static void crypt_alloc_req(struct crypt_config *cc,
struct convert_context *ctx)
{
- if (!cc->req)
- cc->req = mempool_alloc(cc->req_pool, GFP_NOIO);
- ablkcipher_request_set_tfm(cc->req, cc->tfm);
- ablkcipher_request_set_callback(cc->req, CRYPTO_TFM_REQ_MAY_BACKLOG |
- CRYPTO_TFM_REQ_MAY_SLEEP,
- kcryptd_async_done,
- dmreq_of_req(cc, cc->req));
+ struct crypt_cpu *this_cc = this_crypt_config(cc);
+ unsigned key_index = ctx->sector & (cc->tfms_count - 1);
+
+ if (!this_cc->req)
+ this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO);
+
+ ablkcipher_request_set_tfm(this_cc->req, this_cc->tfms[key_index]);
+ ablkcipher_request_set_callback(this_cc->req,
+ CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+ kcryptd_async_done, dmreq_of_req(cc, this_cc->req));
}
/*
@@ -472,6 +768,7 @@ static void crypt_alloc_req(struct crypt_config *cc,
static int crypt_convert(struct crypt_config *cc,
struct convert_context *ctx)
{
+ struct crypt_cpu *this_cc = this_crypt_config(cc);
int r;
atomic_set(&ctx->pending, 1);
@@ -483,7 +780,7 @@ static int crypt_convert(struct crypt_config *cc,
atomic_inc(&ctx->pending);
- r = crypt_convert_block(cc, ctx, cc->req);
+ r = crypt_convert_block(cc, ctx, this_cc->req);
switch (r) {
/* async */
@@ -492,7 +789,7 @@ static int crypt_convert(struct crypt_config *cc,
INIT_COMPLETION(ctx->restart);
/* fall through*/
case -EINPROGRESS:
- cc->req = NULL;
+ this_cc->req = NULL;
ctx->sector++;
continue;
@@ -651,6 +948,9 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
* They must be separated as otherwise the final stages could be
* starved by new requests which can block in the first stages due
* to memory allocation.
+ *
+ * The work is done per CPU global for all dm-crypt instances.
+ * They should not depend on each other and do not block.
*/
static void crypt_endio(struct bio *clone, int error)
{
@@ -691,26 +991,30 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
clone->bi_destructor = dm_crypt_bio_destructor;
}
-static void kcryptd_io_read(struct dm_crypt_io *io)
+static void kcryptd_unplug(struct crypt_config *cc)
+{
+ blk_unplug(bdev_get_queue(cc->dev->bdev));
+}
+
+static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
{
struct crypt_config *cc = io->target->private;
struct bio *base_bio = io->base_bio;
struct bio *clone;
- crypt_inc_pending(io);
-
/*
* The block layer might modify the bvec array, so always
* copy the required bvecs because we need the original
* one in order to decrypt the whole bio data *afterwards*.
*/
- clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs);
- if (unlikely(!clone)) {
- io->error = -ENOMEM;
- crypt_dec_pending(io);
- return;
+ clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs);
+ if (!clone) {
+ kcryptd_unplug(cc);
+ return 1;
}
+ crypt_inc_pending(io);
+
clone_init(io, clone);
clone->bi_idx = 0;
clone->bi_vcnt = bio_segments(base_bio);
@@ -720,6 +1024,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io)
sizeof(struct bio_vec) * clone->bi_vcnt);
generic_make_request(clone);
+ return 0;
}
static void kcryptd_io_write(struct dm_crypt_io *io)
@@ -732,9 +1037,12 @@ static void kcryptd_io(struct work_struct *work)
{
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
- if (bio_data_dir(io->base_bio) == READ)
- kcryptd_io_read(io);
- else
+ if (bio_data_dir(io->base_bio) == READ) {
+ crypt_inc_pending(io);
+ if (kcryptd_io_read(io, GFP_NOIO))
+ io->error = -ENOMEM;
+ crypt_dec_pending(io);
+ } else
kcryptd_io_write(io);
}
@@ -901,6 +1209,9 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
return;
}
+ if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
+ error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
+
mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
if (!atomic_dec_and_test(&ctx->pending))
@@ -971,34 +1282,84 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
}
}
-static int crypt_set_key(struct crypt_config *cc, char *key)
+static void crypt_free_tfms(struct crypt_config *cc, int cpu)
{
- unsigned key_size = strlen(key) >> 1;
+ struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
+ unsigned i;
- if (cc->key_size && cc->key_size != key_size)
+ for (i = 0; i < cc->tfms_count; i++)
+ if (cpu_cc->tfms[i] && !IS_ERR(cpu_cc->tfms[i])) {
+ crypto_free_ablkcipher(cpu_cc->tfms[i]);
+ cpu_cc->tfms[i] = NULL;
+ }
+}
+
+static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode)
+{
+ struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
+ unsigned i;
+ int err;
+
+ for (i = 0; i < cc->tfms_count; i++) {
+ cpu_cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
+ if (IS_ERR(cpu_cc->tfms[i])) {
+ err = PTR_ERR(cpu_cc->tfms[i]);
+ crypt_free_tfms(cc, cpu);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int crypt_setkey_allcpus(struct crypt_config *cc)
+{
+ unsigned subkey_size = cc->key_size >> ilog2(cc->tfms_count);
+ int cpu, err = 0, i, r;
+
+ for_each_possible_cpu(cpu) {
+ for (i = 0; i < cc->tfms_count; i++) {
+ r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfms[i],
+ cc->key + (i * subkey_size), subkey_size);
+ if (r)
+ err = r;
+ }
+ }
+
+ return err;
+}
+
+static int crypt_set_key(struct crypt_config *cc, char *key)
+{
+ /* The key size may not be changed. */
+ if (cc->key_size != (strlen(key) >> 1))
return -EINVAL;
- cc->key_size = key_size; /* initial settings */
+ /* Hyphen (which gives a key_size of zero) means there is no key. */
+ if (!cc->key_size && strcmp(key, "-"))
+ return -EINVAL;
- if ((!key_size && strcmp(key, "-")) ||
- (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
+ if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0)
return -EINVAL;
set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
- return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size);
+ return crypt_setkey_allcpus(cc);
}
static int crypt_wipe_key(struct crypt_config *cc)
{
clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
memset(&cc->key, 0, cc->key_size * sizeof(u8));
- return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size);
+
+ return crypt_setkey_allcpus(cc);
}
static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = ti->private;
+ struct crypt_cpu *cpu_cc;
+ int cpu;
ti->private = NULL;
@@ -1010,6 +1371,14 @@ static void crypt_dtr(struct dm_target *ti)
if (cc->crypt_queue)
destroy_workqueue(cc->crypt_queue);
+ if (cc->cpu)
+ for_each_possible_cpu(cpu) {
+ cpu_cc = per_cpu_ptr(cc->cpu, cpu);
+ if (cpu_cc->req)
+ mempool_free(cpu_cc->req, cc->req_pool);
+ crypt_free_tfms(cc, cpu);
+ }
+
if (cc->bs)
bioset_free(cc->bs);
@@ -1023,14 +1392,14 @@ static void crypt_dtr(struct dm_target *ti)
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
- if (cc->tfm && !IS_ERR(cc->tfm))
- crypto_free_ablkcipher(cc->tfm);
-
if (cc->dev)
dm_put_device(ti, cc->dev);
+ if (cc->cpu)
+ free_percpu(cc->cpu);
+
kzfree(cc->cipher);
- kzfree(cc->cipher_mode);
+ kzfree(cc->cipher_string);
/* Must zero key material before freeing */
kzfree(cc);
@@ -1040,9 +1409,9 @@ static int crypt_ctr_cipher(struct dm_target *ti,
char *cipher_in, char *key)
{
struct crypt_config *cc = ti->private;
- char *tmp, *cipher, *chainmode, *ivmode, *ivopts;
+ char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
char *cipher_api = NULL;
- int ret = -EINVAL;
+ int cpu, ret = -EINVAL;
/* Convert to crypto api definition? */
if (strchr(cipher_in, '(')) {
@@ -1050,23 +1419,31 @@ static int crypt_ctr_cipher(struct dm_target *ti,
return -EINVAL;
}
+ cc->cipher_string = kstrdup(cipher_in, GFP_KERNEL);
+ if (!cc->cipher_string)
+ goto bad_mem;
+
/*
* Legacy dm-crypt cipher specification
- * cipher-mode-iv:ivopts
+ * cipher[:keycount]-mode-iv:ivopts
*/
tmp = cipher_in;
- cipher = strsep(&tmp, "-");
+ keycount = strsep(&tmp, "-");
+ cipher = strsep(&keycount, ":");
+
+ if (!keycount)
+ cc->tfms_count = 1;
+ else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 ||
+ !is_power_of_2(cc->tfms_count)) {
+ ti->error = "Bad cipher key count specification";
+ return -EINVAL;
+ }
+ cc->key_parts = cc->tfms_count;
cc->cipher = kstrdup(cipher, GFP_KERNEL);
if (!cc->cipher)
goto bad_mem;
- if (tmp) {
- cc->cipher_mode = kstrdup(tmp, GFP_KERNEL);
- if (!cc->cipher_mode)
- goto bad_mem;
- }
-
chainmode = strsep(&tmp, "-");
ivopts = strsep(&tmp, "-");
ivmode = strsep(&ivopts, ":");
@@ -1074,10 +1451,19 @@ static int crypt_ctr_cipher(struct dm_target *ti,
if (tmp)
DMWARN("Ignoring unexpected additional cipher options");
- /* Compatibility mode for old dm-crypt mappings */
+ cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)) +
+ cc->tfms_count * sizeof(*(cc->cpu->tfms)),
+ __alignof__(struct crypt_cpu));
+ if (!cc->cpu) {
+ ti->error = "Cannot allocate per cpu state";
+ goto bad_mem;
+ }
+
+ /*
+ * For compatibility with the original dm-crypt mapping format, if
+ * only the cipher name is supplied, use cbc-plain.
+ */
if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) {
- kfree(cc->cipher_mode);
- cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL);
chainmode = "cbc";
ivmode = "plain";
}
@@ -1099,11 +1485,12 @@ static int crypt_ctr_cipher(struct dm_target *ti,
}
/* Allocate cipher */
- cc->tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0);
- if (IS_ERR(cc->tfm)) {
- ret = PTR_ERR(cc->tfm);
- ti->error = "Error allocating crypto tfm";
- goto bad;
+ for_each_possible_cpu(cpu) {
+ ret = crypt_alloc_tfms(cc, cpu, cipher_api);
+ if (ret < 0) {
+ ti->error = "Error allocating crypto tfm";
+ goto bad;
+ }
}
/* Initialize and set key */
@@ -1114,7 +1501,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
}
/* Initialize IV */
- cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
+ cc->iv_size = crypto_ablkcipher_ivsize(any_tfm(cc));
if (cc->iv_size)
/* at least a 64 bit sector number should fit in our buffer */
cc->iv_size = max(cc->iv_size,
@@ -1137,7 +1524,15 @@ static int crypt_ctr_cipher(struct dm_target *ti,
cc->iv_gen_ops = &crypt_iv_benbi_ops;
else if (strcmp(ivmode, "null") == 0)
cc->iv_gen_ops = &crypt_iv_null_ops;
- else {
+ else if (strcmp(ivmode, "lmk") == 0) {
+ cc->iv_gen_ops = &crypt_iv_lmk_ops;
+ /* Version 2 and 3 is recognised according
+ * to length of provided multi-key string.
+ * If present (version 3), last key is used as IV seed.
+ */
+ if (cc->key_size % cc->key_parts)
+ cc->key_parts++;
+ } else {
ret = -EINVAL;
ti->error = "Invalid IV mode";
goto bad;
@@ -1194,6 +1589,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->error = "Cannot allocate encryption context";
return -ENOMEM;
}
+ cc->key_size = key_size;
ti->private = cc;
ret = crypt_ctr_cipher(ti, argv[0], argv[1]);
@@ -1208,9 +1604,9 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
cc->dmreq_start = sizeof(struct ablkcipher_request);
- cc->dmreq_start += crypto_ablkcipher_reqsize(cc->tfm);
+ cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment());
- cc->dmreq_start += crypto_ablkcipher_alignmask(cc->tfm) &
+ cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) &
~(crypto_tfm_ctx_alignment() - 1);
cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
@@ -1219,7 +1615,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->error = "Cannot allocate crypt request mempool";
goto bad;
}
- cc->req = NULL;
cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!cc->page_pool) {
@@ -1252,13 +1647,20 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->start = tmpll;
ret = -ENOMEM;
- cc->io_queue = create_singlethread_workqueue("kcryptd_io");
+ cc->io_queue = alloc_workqueue("kcryptd_io",
+ WQ_NON_REENTRANT|
+ WQ_MEM_RECLAIM,
+ 1);
if (!cc->io_queue) {
ti->error = "Couldn't create kcryptd io queue";
goto bad;
}
- cc->crypt_queue = create_singlethread_workqueue("kcryptd");
+ cc->crypt_queue = alloc_workqueue("kcryptd",
+ WQ_NON_REENTRANT|
+ WQ_CPU_INTENSIVE|
+ WQ_MEM_RECLAIM,
+ 1);
if (!cc->crypt_queue) {
ti->error = "Couldn't create kcryptd queue";
goto bad;
@@ -1286,9 +1688,10 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
io = crypt_io_alloc(ti, bio, dm_target_offset(ti, bio->bi_sector));
- if (bio_data_dir(io->base_bio) == READ)
- kcryptd_queue_io(io);
- else
+ if (bio_data_dir(io->base_bio) == READ) {
+ if (kcryptd_io_read(io, GFP_NOWAIT))
+ kcryptd_queue_io(io);
+ } else
kcryptd_queue_crypt(io);
return DM_MAPIO_SUBMITTED;
@@ -1306,10 +1709,7 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
break;
case STATUSTYPE_TABLE:
- if (cc->cipher_mode)
- DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode);
- else
- DMEMIT("%s ", cc->cipher);
+ DMEMIT("%s ", cc->cipher_string);
if (cc->key_size > 0) {
if ((maxlen - sz) < ((cc->key_size << 1) + 1))
@@ -1421,7 +1821,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
static struct target_type crypt_target = {
.name = "crypt",
- .version = {1, 7, 0},
+ .version = {1, 10, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index baa11912cc94..f18375dcedd9 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -352,7 +352,7 @@ static int __init dm_delay_init(void)
{
int r = -ENOMEM;
- kdelayd_wq = create_workqueue("kdelayd");
+ kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
if (!kdelayd_wq) {
DMERR("Couldn't start kdelayd");
goto bad_queue;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 4b54618b4159..6d12775a1061 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -295,19 +295,55 @@ retry:
DMWARN("remove_all left %d open device(s)", dev_skipped);
}
+/*
+ * Set the uuid of a hash_cell that isn't already set.
+ */
+static void __set_cell_uuid(struct hash_cell *hc, char *new_uuid)
+{
+ mutex_lock(&dm_hash_cells_mutex);
+ hc->uuid = new_uuid;
+ mutex_unlock(&dm_hash_cells_mutex);
+
+ list_add(&hc->uuid_list, _uuid_buckets + hash_str(new_uuid));
+}
+
+/*
+ * Changes the name of a hash_cell and returns the old name for
+ * the caller to free.
+ */
+static char *__change_cell_name(struct hash_cell *hc, char *new_name)
+{
+ char *old_name;
+
+ /*
+ * Rename and move the name cell.
+ */
+ list_del(&hc->name_list);
+ old_name = hc->name;
+
+ mutex_lock(&dm_hash_cells_mutex);
+ hc->name = new_name;
+ mutex_unlock(&dm_hash_cells_mutex);
+
+ list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+
+ return old_name;
+}
+
static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
const char *new)
{
- char *new_name, *old_name;
+ char *new_data, *old_name = NULL;
struct hash_cell *hc;
struct dm_table *table;
struct mapped_device *md;
+ unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
/*
* duplicate new.
*/
- new_name = kstrdup(new, GFP_KERNEL);
- if (!new_name)
+ new_data = kstrdup(new, GFP_KERNEL);
+ if (!new_data)
return ERR_PTR(-ENOMEM);
down_write(&_hash_lock);
@@ -315,13 +351,19 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
/*
* Is new free ?
*/
- hc = __get_name_cell(new);
+ if (change_uuid)
+ hc = __get_uuid_cell(new);
+ else
+ hc = __get_name_cell(new);
+
if (hc) {
- DMWARN("asked to rename to an already-existing name %s -> %s",
+ DMWARN("Unable to change %s on mapped device %s to one that "
+ "already exists: %s",
+ change_uuid ? "uuid" : "name",
param->name, new);
dm_put(hc->md);
up_write(&_hash_lock);
- kfree(new_name);
+ kfree(new_data);
return ERR_PTR(-EBUSY);
}
@@ -330,22 +372,30 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
*/
hc = __get_name_cell(param->name);
if (!hc) {
- DMWARN("asked to rename a non-existent device %s -> %s",
- param->name, new);
+ DMWARN("Unable to rename non-existent device, %s to %s%s",
+ param->name, change_uuid ? "uuid " : "", new);
up_write(&_hash_lock);
- kfree(new_name);
+ kfree(new_data);
return ERR_PTR(-ENXIO);
}
/*
- * rename and move the name cell.
+ * Does this device already have a uuid?
*/
- list_del(&hc->name_list);
- old_name = hc->name;
- mutex_lock(&dm_hash_cells_mutex);
- hc->name = new_name;
- mutex_unlock(&dm_hash_cells_mutex);
- list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+ if (change_uuid && hc->uuid) {
+ DMWARN("Unable to change uuid of mapped device %s to %s "
+ "because uuid is already set to %s",
+ param->name, new, hc->uuid);
+ dm_put(hc->md);
+ up_write(&_hash_lock);
+ kfree(new_data);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (change_uuid)
+ __set_cell_uuid(hc, new_data);
+ else
+ old_name = __change_cell_name(hc, new_data);
/*
* Wake up any dm event waiters.
@@ -729,7 +779,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
hc = __find_device_hash_cell(param);
if (!hc) {
- DMWARN("device doesn't appear to be in the dev hash table.");
+ DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
return -ENXIO;
}
@@ -741,7 +791,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
*/
r = dm_lock_for_deletion(md);
if (r) {
- DMWARN("unable to remove open device %s", hc->name);
+ DMDEBUG_LIMIT("unable to remove open device %s", hc->name);
up_write(&_hash_lock);
dm_put(md);
return r;
@@ -774,21 +824,24 @@ static int invalid_str(char *str, void *end)
static int dev_rename(struct dm_ioctl *param, size_t param_size)
{
int r;
- char *new_name = (char *) param + param->data_start;
+ char *new_data = (char *) param + param->data_start;
struct mapped_device *md;
+ unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
- if (new_name < param->data ||
- invalid_str(new_name, (void *) param + param_size) ||
- strlen(new_name) > DM_NAME_LEN - 1) {
- DMWARN("Invalid new logical volume name supplied.");
+ if (new_data < param->data ||
+ invalid_str(new_data, (void *) param + param_size) ||
+ strlen(new_data) > (change_uuid ? DM_UUID_LEN - 1 : DM_NAME_LEN - 1)) {
+ DMWARN("Invalid new mapped device name or uuid string supplied.");
return -EINVAL;
}
- r = check_name(new_name);
- if (r)
- return r;
+ if (!change_uuid) {
+ r = check_name(new_data);
+ if (r)
+ return r;
+ }
- md = dm_hash_rename(param, new_name);
+ md = dm_hash_rename(param, new_data);
if (IS_ERR(md))
return PTR_ERR(md);
@@ -885,7 +938,7 @@ static int do_resume(struct dm_ioctl *param)
hc = __find_device_hash_cell(param);
if (!hc) {
- DMWARN("device doesn't appear to be in the dev hash table.");
+ DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
return -ENXIO;
}
@@ -1212,7 +1265,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
hc = __find_device_hash_cell(param);
if (!hc) {
- DMWARN("device doesn't appear to be in the dev hash table.");
+ DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
return -ENXIO;
}
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index d8587bac5682..924f5f0084c2 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -37,6 +37,13 @@ struct dm_kcopyd_client {
unsigned int nr_pages;
unsigned int nr_free_pages;
+ /*
+ * Block devices to unplug.
+ * Non-NULL pointer means that a block device has some pending requests
+ * and needs to be unplugged.
+ */
+ struct block_device *unplug[2];
+
struct dm_io_client *io_client;
wait_queue_head_t destroyq;
@@ -308,6 +315,31 @@ static int run_complete_job(struct kcopyd_job *job)
return 0;
}
+/*
+ * Unplug the block device at the specified index.
+ */
+static void unplug(struct dm_kcopyd_client *kc, int rw)
+{
+ if (kc->unplug[rw] != NULL) {
+ blk_unplug(bdev_get_queue(kc->unplug[rw]));
+ kc->unplug[rw] = NULL;
+ }
+}
+
+/*
+ * Prepare block device unplug. If there's another device
+ * to be unplugged at the same array index, we unplug that
+ * device first.
+ */
+static void prepare_unplug(struct dm_kcopyd_client *kc, int rw,
+ struct block_device *bdev)
+{
+ if (likely(kc->unplug[rw] == bdev))
+ return;
+ unplug(kc, rw);
+ kc->unplug[rw] = bdev;
+}
+
static void complete_io(unsigned long error, void *context)
{
struct kcopyd_job *job = (struct kcopyd_job *) context;
@@ -345,7 +377,7 @@ static int run_io_job(struct kcopyd_job *job)
{
int r;
struct dm_io_request io_req = {
- .bi_rw = job->rw | REQ_SYNC | REQ_UNPLUG,
+ .bi_rw = job->rw,
.mem.type = DM_IO_PAGE_LIST,
.mem.ptr.pl = job->pages,
.mem.offset = job->offset,
@@ -354,10 +386,16 @@ static int run_io_job(struct kcopyd_job *job)
.client = job->kc->io_client,
};
- if (job->rw == READ)
+ if (job->rw == READ) {
r = dm_io(&io_req, 1, &job->source, NULL);
- else
+ prepare_unplug(job->kc, READ, job->source.bdev);
+ } else {
+ if (job->num_dests > 1)
+ io_req.bi_rw |= REQ_UNPLUG;
r = dm_io(&io_req, job->num_dests, job->dests, NULL);
+ if (!(io_req.bi_rw & REQ_UNPLUG))
+ prepare_unplug(job->kc, WRITE, job->dests[0].bdev);
+ }
return r;
}
@@ -435,10 +473,18 @@ static void do_work(struct work_struct *work)
* Pages jobs when successful will jump onto the io jobs
* list. io jobs call wake when they complete and it all
* starts again.
+ *
+ * Note that io_jobs add block devices to the unplug array,
+ * this array is cleared with "unplug" calls. It is thus
+ * forbidden to run complete_jobs after io_jobs and before
+ * unplug because the block device could be destroyed in
+ * job completion callback.
*/
process_jobs(&kc->complete_jobs, kc, run_complete_job);
process_jobs(&kc->pages_jobs, kc, run_pages_job);
process_jobs(&kc->io_jobs, kc, run_io_job);
+ unplug(kc, READ);
+ unplug(kc, WRITE);
}
/*
@@ -619,12 +665,15 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
INIT_LIST_HEAD(&kc->io_jobs);
INIT_LIST_HEAD(&kc->pages_jobs);
+ memset(kc->unplug, 0, sizeof(kc->unplug));
+
kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
if (!kc->job_pool)
goto bad_slab;
INIT_WORK(&kc->kcopyd_work, do_work);
- kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
+ kc->kcopyd_wq = alloc_workqueue("kcopyd",
+ WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
if (!kc->kcopyd_wq)
goto bad_workqueue;
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
index 1ed0094f064b..aa2e0c374ab3 100644
--- a/drivers/md/dm-log-userspace-base.c
+++ b/drivers/md/dm-log-userspace-base.c
@@ -12,12 +12,22 @@
#include "dm-log-userspace-transfer.h"
+#define DM_LOG_USERSPACE_VSN "1.1.0"
+
struct flush_entry {
int type;
region_t region;
struct list_head list;
};
+/*
+ * This limit on the number of mark and clear request is, to a degree,
+ * arbitrary. However, there is some basis for the choice in the limits
+ * imposed on the size of data payload by dm-log-userspace-transfer.c:
+ * dm_consult_userspace().
+ */
+#define MAX_FLUSH_GROUP_COUNT 32
+
struct log_c {
struct dm_target *ti;
uint32_t region_size;
@@ -37,8 +47,15 @@ struct log_c {
*/
uint64_t in_sync_hint;
+ /*
+ * Mark and clear requests are held until a flush is issued
+ * so that we can group, and thereby limit, the amount of
+ * network traffic between kernel and userspace. The 'flush_lock'
+ * is used to protect these lists.
+ */
spinlock_t flush_lock;
- struct list_head flush_list; /* only for clear and mark requests */
+ struct list_head mark_list;
+ struct list_head clear_list;
};
static mempool_t *flush_entry_pool;
@@ -169,7 +186,8 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
strncpy(lc->uuid, argv[0], DM_UUID_LEN);
spin_lock_init(&lc->flush_lock);
- INIT_LIST_HEAD(&lc->flush_list);
+ INIT_LIST_HEAD(&lc->mark_list);
+ INIT_LIST_HEAD(&lc->clear_list);
str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str);
if (str_size < 0) {
@@ -181,8 +199,11 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR,
ctr_str, str_size, NULL, NULL);
- if (r == -ESRCH) {
- DMERR("Userspace log server not found");
+ if (r < 0) {
+ if (r == -ESRCH)
+ DMERR("Userspace log server not found");
+ else
+ DMERR("Userspace log server failed to create log");
goto out;
}
@@ -214,10 +235,9 @@ out:
static void userspace_dtr(struct dm_dirty_log *log)
{
- int r;
struct log_c *lc = log->context;
- r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR,
+ (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR,
NULL, 0,
NULL, NULL);
@@ -338,6 +358,71 @@ static int userspace_in_sync(struct dm_dirty_log *log, region_t region,
return (r) ? 0 : (int)in_sync;
}
+static int flush_one_by_one(struct log_c *lc, struct list_head *flush_list)
+{
+ int r = 0;
+ struct flush_entry *fe;
+
+ list_for_each_entry(fe, flush_list, list) {
+ r = userspace_do_request(lc, lc->uuid, fe->type,
+ (char *)&fe->region,
+ sizeof(fe->region),
+ NULL, NULL);
+ if (r)
+ break;
+ }
+
+ return r;
+}
+
+static int flush_by_group(struct log_c *lc, struct list_head *flush_list)
+{
+ int r = 0;
+ int count;
+ uint32_t type = 0;
+ struct flush_entry *fe, *tmp_fe;
+ LIST_HEAD(tmp_list);
+ uint64_t group[MAX_FLUSH_GROUP_COUNT];
+
+ /*
+ * Group process the requests
+ */
+ while (!list_empty(flush_list)) {
+ count = 0;
+
+ list_for_each_entry_safe(fe, tmp_fe, flush_list, list) {
+ group[count] = fe->region;
+ count++;
+
+ list_del(&fe->list);
+ list_add(&fe->list, &tmp_list);
+
+ type = fe->type;
+ if (count >= MAX_FLUSH_GROUP_COUNT)
+ break;
+ }
+
+ r = userspace_do_request(lc, lc->uuid, type,
+ (char *)(group),
+ count * sizeof(uint64_t),
+ NULL, NULL);
+ if (r) {
+ /* Group send failed. Attempt one-by-one. */
+ list_splice_init(&tmp_list, flush_list);
+ r = flush_one_by_one(lc, flush_list);
+ break;
+ }
+ }
+
+ /*
+ * Must collect flush_entrys that were successfully processed
+ * as a group so that they will be free'd by the caller.
+ */
+ list_splice_init(&tmp_list, flush_list);
+
+ return r;
+}
+
/*
* userspace_flush
*
@@ -360,31 +445,25 @@ static int userspace_flush(struct dm_dirty_log *log)
int r = 0;
unsigned long flags;
struct log_c *lc = log->context;
- LIST_HEAD(flush_list);
+ LIST_HEAD(mark_list);
+ LIST_HEAD(clear_list);
struct flush_entry *fe, *tmp_fe;
spin_lock_irqsave(&lc->flush_lock, flags);
- list_splice_init(&lc->flush_list, &flush_list);
+ list_splice_init(&lc->mark_list, &mark_list);
+ list_splice_init(&lc->clear_list, &clear_list);
spin_unlock_irqrestore(&lc->flush_lock, flags);
- if (list_empty(&flush_list))
+ if (list_empty(&mark_list) && list_empty(&clear_list))
return 0;
- /*
- * FIXME: Count up requests, group request types,
- * allocate memory to stick all requests in and
- * send to server in one go. Failing the allocation,
- * do it one by one.
- */
+ r = flush_by_group(lc, &mark_list);
+ if (r)
+ goto fail;
- list_for_each_entry(fe, &flush_list, list) {
- r = userspace_do_request(lc, lc->uuid, fe->type,
- (char *)&fe->region,
- sizeof(fe->region),
- NULL, NULL);
- if (r)
- goto fail;
- }
+ r = flush_by_group(lc, &clear_list);
+ if (r)
+ goto fail;
r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH,
NULL, 0, NULL, NULL);
@@ -395,7 +474,11 @@ fail:
* Calling code will receive an error and will know that
* the log facility has failed.
*/
- list_for_each_entry_safe(fe, tmp_fe, &flush_list, list) {
+ list_for_each_entry_safe(fe, tmp_fe, &mark_list, list) {
+ list_del(&fe->list);
+ mempool_free(fe, flush_entry_pool);
+ }
+ list_for_each_entry_safe(fe, tmp_fe, &clear_list, list) {
list_del(&fe->list);
mempool_free(fe, flush_entry_pool);
}
@@ -425,7 +508,7 @@ static void userspace_mark_region(struct dm_dirty_log *log, region_t region)
spin_lock_irqsave(&lc->flush_lock, flags);
fe->type = DM_ULOG_MARK_REGION;
fe->region = region;
- list_add(&fe->list, &lc->flush_list);
+ list_add(&fe->list, &lc->mark_list);
spin_unlock_irqrestore(&lc->flush_lock, flags);
return;
@@ -462,7 +545,7 @@ static void userspace_clear_region(struct dm_dirty_log *log, region_t region)
spin_lock_irqsave(&lc->flush_lock, flags);
fe->type = DM_ULOG_CLEAR_REGION;
fe->region = region;
- list_add(&fe->list, &lc->flush_list);
+ list_add(&fe->list, &lc->clear_list);
spin_unlock_irqrestore(&lc->flush_lock, flags);
return;
@@ -684,7 +767,7 @@ static int __init userspace_dirty_log_init(void)
return r;
}
- DMINFO("version 1.0.0 loaded");
+ DMINFO("version " DM_LOG_USERSPACE_VSN " loaded");
return 0;
}
@@ -694,7 +777,7 @@ static void __exit userspace_dirty_log_exit(void)
dm_ulog_tfr_exit();
mempool_destroy(flush_entry_pool);
- DMINFO("version 1.0.0 unloaded");
+ DMINFO("version " DM_LOG_USERSPACE_VSN " unloaded");
return;
}
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index 075cbcf8a9f5..049eaf12aaab 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -198,6 +198,7 @@ resend:
memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - sizeof(struct cn_msg));
memcpy(tfr->uuid, uuid, DM_UUID_LEN);
+ tfr->version = DM_ULOG_REQUEST_VERSION;
tfr->luid = luid;
tfr->seq = dm_ulog_seq++;
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 33420e68d153..6951536ea29c 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -455,7 +455,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
r = PTR_ERR(lc->io_req.client);
DMWARN("couldn't allocate disk io client");
kfree(lc);
- return -ENOMEM;
+ return r;
}
lc->disk_header = vmalloc(buf_size);
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 487ecda90ad4..b82d28819e2a 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -23,6 +23,8 @@
#define DM_MSG_PREFIX "multipath"
#define MESG_STR(x) x, sizeof(x)
+#define DM_PG_INIT_DELAY_MSECS 2000
+#define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1)
/* Path properties */
struct pgpath {
@@ -33,8 +35,7 @@ struct pgpath {
unsigned fail_count; /* Cumulative failure count */
struct dm_path path;
- struct work_struct deactivate_path;
- struct work_struct activate_path;
+ struct delayed_work activate_path;
};
#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -65,11 +66,15 @@ struct multipath {
const char *hw_handler_name;
char *hw_handler_params;
+
unsigned nr_priority_groups;
struct list_head priority_groups;
+
+ wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */
+
unsigned pg_init_required; /* pg_init needs calling? */
unsigned pg_init_in_progress; /* Only one pg_init allowed at once */
- wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */
+ unsigned pg_init_delay_retry; /* Delay pg_init retry? */
unsigned nr_valid_paths; /* Total number of usable paths */
struct pgpath *current_pgpath;
@@ -82,6 +87,7 @@ struct multipath {
unsigned saved_queue_if_no_path;/* Saved state during suspension */
unsigned pg_init_retries; /* Number of times to retry pg_init */
unsigned pg_init_count; /* Number of times pg_init called */
+ unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */
struct work_struct process_queued_ios;
struct list_head queued_ios;
@@ -116,7 +122,6 @@ static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
static void process_queued_ios(struct work_struct *work);
static void trigger_event(struct work_struct *work);
static void activate_path(struct work_struct *work);
-static void deactivate_path(struct work_struct *work);
/*-----------------------------------------------
@@ -129,8 +134,7 @@ static struct pgpath *alloc_pgpath(void)
if (pgpath) {
pgpath->is_active = 1;
- INIT_WORK(&pgpath->deactivate_path, deactivate_path);
- INIT_WORK(&pgpath->activate_path, activate_path);
+ INIT_DELAYED_WORK(&pgpath->activate_path, activate_path);
}
return pgpath;
@@ -141,14 +145,6 @@ static void free_pgpath(struct pgpath *pgpath)
kfree(pgpath);
}
-static void deactivate_path(struct work_struct *work)
-{
- struct pgpath *pgpath =
- container_of(work, struct pgpath, deactivate_path);
-
- blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue);
-}
-
static struct priority_group *alloc_priority_group(void)
{
struct priority_group *pg;
@@ -199,6 +195,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
INIT_LIST_HEAD(&m->queued_ios);
spin_lock_init(&m->lock);
m->queue_io = 1;
+ m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
INIT_WORK(&m->process_queued_ios, process_queued_ios);
INIT_WORK(&m->trigger_event, trigger_event);
init_waitqueue_head(&m->pg_init_wait);
@@ -238,14 +235,19 @@ static void free_multipath(struct multipath *m)
static void __pg_init_all_paths(struct multipath *m)
{
struct pgpath *pgpath;
+ unsigned long pg_init_delay = 0;
m->pg_init_count++;
m->pg_init_required = 0;
+ if (m->pg_init_delay_retry)
+ pg_init_delay = msecs_to_jiffies(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT ?
+ m->pg_init_delay_msecs : DM_PG_INIT_DELAY_MSECS);
list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) {
/* Skip failed paths */
if (!pgpath->is_active)
continue;
- if (queue_work(kmpath_handlerd, &pgpath->activate_path))
+ if (queue_delayed_work(kmpath_handlerd, &pgpath->activate_path,
+ pg_init_delay))
m->pg_init_in_progress++;
}
}
@@ -793,8 +795,9 @@ static int parse_features(struct arg_set *as, struct multipath *m)
const char *param_name;
static struct param _params[] = {
- {0, 3, "invalid number of feature args"},
+ {0, 5, "invalid number of feature args"},
{1, 50, "pg_init_retries must be between 1 and 50"},
+ {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"},
};
r = read_param(_params, shift(as), &argc, &ti->error);
@@ -821,6 +824,14 @@ static int parse_features(struct arg_set *as, struct multipath *m)
continue;
}
+ if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) &&
+ (argc >= 1)) {
+ r = read_param(_params + 2, shift(as),
+ &m->pg_init_delay_msecs, &ti->error);
+ argc--;
+ continue;
+ }
+
ti->error = "Unrecognised multipath feature request";
r = -EINVAL;
} while (argc && !r);
@@ -931,7 +942,7 @@ static void flush_multipath_work(struct multipath *m)
flush_workqueue(kmpath_handlerd);
multipath_wait_for_pg_init_completion(m);
flush_workqueue(kmultipathd);
- flush_scheduled_work();
+ flush_work_sync(&m->trigger_event);
}
static void multipath_dtr(struct dm_target *ti)
@@ -995,7 +1006,6 @@ static int fail_path(struct pgpath *pgpath)
pgpath->path.dev->name, m->nr_valid_paths);
schedule_work(&m->trigger_event);
- queue_work(kmultipathd, &pgpath->deactivate_path);
out:
spin_unlock_irqrestore(&m->lock, flags);
@@ -1034,7 +1044,7 @@ static int reinstate_path(struct pgpath *pgpath)
m->current_pgpath = NULL;
queue_work(kmultipathd, &m->process_queued_ios);
} else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) {
- if (queue_work(kmpath_handlerd, &pgpath->activate_path))
+ if (queue_work(kmpath_handlerd, &pgpath->activate_path.work))
m->pg_init_in_progress++;
}
@@ -1169,6 +1179,7 @@ static void pg_init_done(void *data, int errors)
struct priority_group *pg = pgpath->pg;
struct multipath *m = pg->m;
unsigned long flags;
+ unsigned delay_retry = 0;
/* device or driver problems */
switch (errors) {
@@ -1193,8 +1204,9 @@ static void pg_init_done(void *data, int errors)
*/
bypass_pg(m, pg, 1);
break;
- /* TODO: For SCSI_DH_RETRY we should wait a couple seconds */
case SCSI_DH_RETRY:
+ /* Wait before retrying. */
+ delay_retry = 1;
case SCSI_DH_IMM_RETRY:
case SCSI_DH_RES_TEMP_UNAVAIL:
if (pg_init_limit_reached(m, pgpath))
@@ -1227,6 +1239,7 @@ static void pg_init_done(void *data, int errors)
if (!m->pg_init_required)
m->queue_io = 0;
+ m->pg_init_delay_retry = delay_retry;
queue_work(kmultipathd, &m->process_queued_ios);
/*
@@ -1241,7 +1254,7 @@ out:
static void activate_path(struct work_struct *work)
{
struct pgpath *pgpath =
- container_of(work, struct pgpath, activate_path);
+ container_of(work, struct pgpath, activate_path.work);
scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
pg_init_done, pgpath);
@@ -1382,11 +1395,14 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count);
else {
DMEMIT("%u ", m->queue_if_no_path +
- (m->pg_init_retries > 0) * 2);
+ (m->pg_init_retries > 0) * 2 +
+ (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2);
if (m->queue_if_no_path)
DMEMIT("queue_if_no_path ");
if (m->pg_init_retries)
DMEMIT("pg_init_retries %u ", m->pg_init_retries);
+ if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT)
+ DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs);
}
if (!m->hw_handler_name || type == STATUSTYPE_INFO)
@@ -1655,7 +1671,7 @@ out:
*---------------------------------------------------------------*/
static struct target_type multipath_target = {
.name = "multipath",
- .version = {1, 1, 1},
+ .version = {1, 2, 0},
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
@@ -1687,7 +1703,7 @@ static int __init dm_multipath_init(void)
return -EINVAL;
}
- kmultipathd = create_workqueue("kmpathd");
+ kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
if (!kmultipathd) {
DMERR("failed to create workqueue kmpathd");
dm_unregister_target(&multipath_target);
@@ -1701,7 +1717,8 @@ static int __init dm_multipath_init(void)
* old workqueue would also create a bottleneck in the
* path of the storage hardware device activation.
*/
- kmpath_handlerd = create_singlethread_workqueue("kmpath_handlerd");
+ kmpath_handlerd = alloc_ordered_workqueue("kmpath_handlerd",
+ WQ_MEM_RECLAIM);
if (!kmpath_handlerd) {
DMERR("failed to create workqueue kmpath_handlerd");
destroy_workqueue(kmultipathd);
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
new file mode 100644
index 000000000000..b9e1e15ef11c
--- /dev/null
+++ b/drivers/md/dm-raid.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2010-2011 Neil Brown
+ * Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/slab.h>
+
+#include "md.h"
+#include "raid5.h"
+#include "dm.h"
+#include "bitmap.h"
+
+#define DM_MSG_PREFIX "raid"
+
+/*
+ * If the MD doesn't support MD_SYNC_STATE_FORCED yet, then
+ * make it so the flag doesn't set anything.
+ */
+#ifndef MD_SYNC_STATE_FORCED
+#define MD_SYNC_STATE_FORCED 0
+#endif
+
+struct raid_dev {
+ /*
+ * Two DM devices, one to hold metadata and one to hold the
+ * actual data/parity. The reason for this is to not confuse
+ * ti->len and give more flexibility in altering size and
+ * characteristics.
+ *
+ * While it is possible for this device to be associated
+ * with a different physical device than the data_dev, it
+ * is intended for it to be the same.
+ * |--------- Physical Device ---------|
+ * |- meta_dev -|------ data_dev ------|
+ */
+ struct dm_dev *meta_dev;
+ struct dm_dev *data_dev;
+ struct mdk_rdev_s rdev;
+};
+
+/*
+ * Flags for rs->print_flags field.
+ */
+#define DMPF_DAEMON_SLEEP 0x1
+#define DMPF_MAX_WRITE_BEHIND 0x2
+#define DMPF_SYNC 0x4
+#define DMPF_NOSYNC 0x8
+#define DMPF_STRIPE_CACHE 0x10
+#define DMPF_MIN_RECOVERY_RATE 0x20
+#define DMPF_MAX_RECOVERY_RATE 0x40
+
+struct raid_set {
+ struct dm_target *ti;
+
+ uint64_t print_flags;
+
+ struct mddev_s md;
+ struct raid_type *raid_type;
+ struct dm_target_callbacks callbacks;
+
+ struct raid_dev dev[0];
+};
+
+/* Supported raid types and properties. */
+static struct raid_type {
+ const char *name; /* RAID algorithm. */
+ const char *descr; /* Descriptor text for logging. */
+ const unsigned parity_devs; /* # of parity devices. */
+ const unsigned minimal_devs; /* minimal # of devices in set. */
+ const unsigned level; /* RAID level. */
+ const unsigned algorithm; /* RAID algorithm. */
+} raid_types[] = {
+ {"raid4", "RAID4 (dedicated parity disk)", 1, 2, 5, ALGORITHM_PARITY_0},
+ {"raid5_la", "RAID5 (left asymmetric)", 1, 2, 5, ALGORITHM_LEFT_ASYMMETRIC},
+ {"raid5_ra", "RAID5 (right asymmetric)", 1, 2, 5, ALGORITHM_RIGHT_ASYMMETRIC},
+ {"raid5_ls", "RAID5 (left symmetric)", 1, 2, 5, ALGORITHM_LEFT_SYMMETRIC},
+ {"raid5_rs", "RAID5 (right symmetric)", 1, 2, 5, ALGORITHM_RIGHT_SYMMETRIC},
+ {"raid6_zr", "RAID6 (zero restart)", 2, 4, 6, ALGORITHM_ROTATING_ZERO_RESTART},
+ {"raid6_nr", "RAID6 (N restart)", 2, 4, 6, ALGORITHM_ROTATING_N_RESTART},
+ {"raid6_nc", "RAID6 (N continue)", 2, 4, 6, ALGORITHM_ROTATING_N_CONTINUE}
+};
+
+static struct raid_type *get_raid_type(char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(raid_types); i++)
+ if (!strcmp(raid_types[i].name, name))
+ return &raid_types[i];
+
+ return NULL;
+}
+
+static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *raid_type, unsigned raid_devs)
+{
+ unsigned i;
+ struct raid_set *rs;
+ sector_t sectors_per_dev;
+
+ if (raid_devs <= raid_type->parity_devs) {
+ ti->error = "Insufficient number of devices";
+ return ERR_PTR(-EINVAL);
+ }
+
+ sectors_per_dev = ti->len;
+ if (sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) {
+ ti->error = "Target length not divisible by number of data devices";
+ return ERR_PTR(-EINVAL);
+ }
+
+ rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL);
+ if (!rs) {
+ ti->error = "Cannot allocate raid context";
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mddev_init(&rs->md);
+
+ rs->ti = ti;
+ rs->raid_type = raid_type;
+ rs->md.raid_disks = raid_devs;
+ rs->md.level = raid_type->level;
+ rs->md.new_level = rs->md.level;
+ rs->md.dev_sectors = sectors_per_dev;
+ rs->md.layout = raid_type->algorithm;
+ rs->md.new_layout = rs->md.layout;
+ rs->md.delta_disks = 0;
+ rs->md.recovery_cp = 0;
+
+ for (i = 0; i < raid_devs; i++)
+ md_rdev_init(&rs->dev[i].rdev);
+
+ /*
+ * Remaining items to be initialized by further RAID params:
+ * rs->md.persistent
+ * rs->md.external
+ * rs->md.chunk_sectors
+ * rs->md.new_chunk_sectors
+ */
+
+ return rs;
+}
+
+static void context_free(struct raid_set *rs)
+{
+ int i;
+
+ for (i = 0; i < rs->md.raid_disks; i++)
+ if (rs->dev[i].data_dev)
+ dm_put_device(rs->ti, rs->dev[i].data_dev);
+
+ kfree(rs);
+}
+
+/*
+ * For every device we have two words
+ * <meta_dev>: meta device name or '-' if missing
+ * <data_dev>: data device name or '-' if missing
+ *
+ * This code parses those words.
+ */
+static int dev_parms(struct raid_set *rs, char **argv)
+{
+ int i;
+ int rebuild = 0;
+ int metadata_available = 0;
+ int ret = 0;
+
+ for (i = 0; i < rs->md.raid_disks; i++, argv += 2) {
+ rs->dev[i].rdev.raid_disk = i;
+
+ rs->dev[i].meta_dev = NULL;
+ rs->dev[i].data_dev = NULL;
+
+ /*
+ * There are no offsets, since there is a separate device
+ * for data and metadata.
+ */
+ rs->dev[i].rdev.data_offset = 0;
+ rs->dev[i].rdev.mddev = &rs->md;
+
+ if (strcmp(argv[0], "-")) {
+ rs->ti->error = "Metadata devices not supported";
+ return -EINVAL;
+ }
+
+ if (!strcmp(argv[1], "-")) {
+ if (!test_bit(In_sync, &rs->dev[i].rdev.flags) &&
+ (!rs->dev[i].rdev.recovery_offset)) {
+ rs->ti->error = "Drive designated for rebuild not specified";
+ return -EINVAL;
+ }
+
+ continue;
+ }
+
+ ret = dm_get_device(rs->ti, argv[1],
+ dm_table_get_mode(rs->ti->table),
+ &rs->dev[i].data_dev);
+ if (ret) {
+ rs->ti->error = "RAID device lookup failure";
+ return ret;
+ }
+
+ rs->dev[i].rdev.bdev = rs->dev[i].data_dev->bdev;
+ list_add(&rs->dev[i].rdev.same_set, &rs->md.disks);
+ if (!test_bit(In_sync, &rs->dev[i].rdev.flags))
+ rebuild++;
+ }
+
+ if (metadata_available) {
+ rs->md.external = 0;
+ rs->md.persistent = 1;
+ rs->md.major_version = 2;
+ } else if (rebuild && !rs->md.recovery_cp) {
+ /*
+ * Without metadata, we will not be able to tell if the array
+ * is in-sync or not - we must assume it is not. Therefore,
+ * it is impossible to rebuild a drive.
+ *
+ * Even if there is metadata, the on-disk information may
+ * indicate that the array is not in-sync and it will then
+ * fail at that time.
+ *
+ * User could specify 'nosync' option if desperate.
+ */
+ DMERR("Unable to rebuild drive while array is not in-sync");
+ rs->ti->error = "RAID device lookup failure";
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Possible arguments are...
+ * RAID456:
+ * <chunk_size> [optional_args]
+ *
+ * Optional args:
+ * [[no]sync] Force or prevent recovery of the entire array
+ * [rebuild <idx>] Rebuild the drive indicated by the index
+ * [daemon_sleep <ms>] Time between bitmap daemon work to clear bits
+ * [min_recovery_rate <kB/sec/disk>] Throttle RAID initialization
+ * [max_recovery_rate <kB/sec/disk>] Throttle RAID initialization
+ * [max_write_behind <sectors>] See '-write-behind=' (man mdadm)
+ * [stripe_cache <sectors>] Stripe cache size for higher RAIDs
+ */
+static int parse_raid_params(struct raid_set *rs, char **argv,
+ unsigned num_raid_params)
+{
+ unsigned i, rebuild_cnt = 0;
+ unsigned long value;
+ char *key;
+
+ /*
+ * First, parse the in-order required arguments
+ */
+ if ((strict_strtoul(argv[0], 10, &value) < 0) ||
+ !is_power_of_2(value) || (value < 8)) {
+ rs->ti->error = "Bad chunk size";
+ return -EINVAL;
+ }
+
+ rs->md.new_chunk_sectors = rs->md.chunk_sectors = value;
+ argv++;
+ num_raid_params--;
+
+ /*
+ * Second, parse the unordered optional arguments
+ */
+ for (i = 0; i < rs->md.raid_disks; i++)
+ set_bit(In_sync, &rs->dev[i].rdev.flags);
+
+ for (i = 0; i < num_raid_params; i++) {
+ if (!strcmp(argv[i], "nosync")) {
+ rs->md.recovery_cp = MaxSector;
+ rs->print_flags |= DMPF_NOSYNC;
+ rs->md.flags |= MD_SYNC_STATE_FORCED;
+ continue;
+ }
+ if (!strcmp(argv[i], "sync")) {
+ rs->md.recovery_cp = 0;
+ rs->print_flags |= DMPF_SYNC;
+ rs->md.flags |= MD_SYNC_STATE_FORCED;
+ continue;
+ }
+
+ /* The rest of the optional arguments come in key/value pairs */
+ if ((i + 1) >= num_raid_params) {
+ rs->ti->error = "Wrong number of raid parameters given";
+ return -EINVAL;
+ }
+
+ key = argv[i++];
+ if (strict_strtoul(argv[i], 10, &value) < 0) {
+ rs->ti->error = "Bad numerical argument given in raid params";
+ return -EINVAL;
+ }
+
+ if (!strcmp(key, "rebuild")) {
+ if (++rebuild_cnt > rs->raid_type->parity_devs) {
+ rs->ti->error = "Too many rebuild drives given";
+ return -EINVAL;
+ }
+ if (value > rs->md.raid_disks) {
+ rs->ti->error = "Invalid rebuild index given";
+ return -EINVAL;
+ }
+ clear_bit(In_sync, &rs->dev[value].rdev.flags);
+ rs->dev[value].rdev.recovery_offset = 0;
+ } else if (!strcmp(key, "max_write_behind")) {
+ rs->print_flags |= DMPF_MAX_WRITE_BEHIND;
+
+ /*
+ * In device-mapper, we specify things in sectors, but
+ * MD records this value in kB
+ */
+ value /= 2;
+ if (value > COUNTER_MAX) {
+ rs->ti->error = "Max write-behind limit out of range";
+ return -EINVAL;
+ }
+ rs->md.bitmap_info.max_write_behind = value;
+ } else if (!strcmp(key, "daemon_sleep")) {
+ rs->print_flags |= DMPF_DAEMON_SLEEP;
+ if (!value || (value > MAX_SCHEDULE_TIMEOUT)) {
+ rs->ti->error = "daemon sleep period out of range";
+ return -EINVAL;
+ }
+ rs->md.bitmap_info.daemon_sleep = value;
+ } else if (!strcmp(key, "stripe_cache")) {
+ rs->print_flags |= DMPF_STRIPE_CACHE;
+
+ /*
+ * In device-mapper, we specify things in sectors, but
+ * MD records this value in kB
+ */
+ value /= 2;
+
+ if (rs->raid_type->level < 5) {
+ rs->ti->error = "Inappropriate argument: stripe_cache";
+ return -EINVAL;
+ }
+ if (raid5_set_cache_size(&rs->md, (int)value)) {
+ rs->ti->error = "Bad stripe_cache size";
+ return -EINVAL;
+ }
+ } else if (!strcmp(key, "min_recovery_rate")) {
+ rs->print_flags |= DMPF_MIN_RECOVERY_RATE;
+ if (value > INT_MAX) {
+ rs->ti->error = "min_recovery_rate out of range";
+ return -EINVAL;
+ }
+ rs->md.sync_speed_min = (int)value;
+ } else if (!strcmp(key, "max_recovery_rate")) {
+ rs->print_flags |= DMPF_MAX_RECOVERY_RATE;
+ if (value > INT_MAX) {
+ rs->ti->error = "max_recovery_rate out of range";
+ return -EINVAL;
+ }
+ rs->md.sync_speed_max = (int)value;
+ } else {
+ DMERR("Unable to parse RAID parameter: %s", key);
+ rs->ti->error = "Unable to parse RAID parameters";
+ return -EINVAL;
+ }
+ }
+
+ /* Assume there are no metadata devices until the drives are parsed */
+ rs->md.persistent = 0;
+ rs->md.external = 1;
+
+ return 0;
+}
+
+static void do_table_event(struct work_struct *ws)
+{
+ struct raid_set *rs = container_of(ws, struct raid_set, md.event_work);
+
+ dm_table_event(rs->ti->table);
+}
+
+static int raid_is_congested(struct dm_target_callbacks *cb, int bits)
+{
+ struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
+
+ return md_raid5_congested(&rs->md, bits);
+}
+
+static void raid_unplug(struct dm_target_callbacks *cb)
+{
+ struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
+
+ md_raid5_unplug_device(rs->md.private);
+}
+
+/*
+ * Construct a RAID4/5/6 mapping:
+ * Args:
+ * <raid_type> <#raid_params> <raid_params> \
+ * <#raid_devs> { <meta_dev1> <dev1> .. <meta_devN> <devN> }
+ *
+ * ** metadata devices are not supported yet, use '-' instead **
+ *
+ * <raid_params> varies by <raid_type>. See 'parse_raid_params' for
+ * details on possible <raid_params>.
+ */
+static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+ int ret;
+ struct raid_type *rt;
+ unsigned long num_raid_params, num_raid_devs;
+ struct raid_set *rs = NULL;
+
+ /* Must have at least <raid_type> <#raid_params> */
+ if (argc < 2) {
+ ti->error = "Too few arguments";
+ return -EINVAL;
+ }
+
+ /* raid type */
+ rt = get_raid_type(argv[0]);
+ if (!rt) {
+ ti->error = "Unrecognised raid_type";
+ return -EINVAL;
+ }
+ argc--;
+ argv++;
+
+ /* number of RAID parameters */
+ if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) {
+ ti->error = "Cannot understand number of RAID parameters";
+ return -EINVAL;
+ }
+ argc--;
+ argv++;
+
+ /* Skip over RAID params for now and find out # of devices */
+ if (num_raid_params + 1 > argc) {
+ ti->error = "Arguments do not agree with counts given";
+ return -EINVAL;
+ }
+
+ if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
+ (num_raid_devs >= INT_MAX)) {
+ ti->error = "Cannot understand number of raid devices";
+ return -EINVAL;
+ }
+
+ rs = context_alloc(ti, rt, (unsigned)num_raid_devs);
+ if (IS_ERR(rs))
+ return PTR_ERR(rs);
+
+ ret = parse_raid_params(rs, argv, (unsigned)num_raid_params);
+ if (ret)
+ goto bad;
+
+ ret = -EINVAL;
+
+ argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */
+ argv += num_raid_params + 1;
+
+ if (argc != (num_raid_devs * 2)) {
+ ti->error = "Supplied RAID devices does not match the count given";
+ goto bad;
+ }
+
+ ret = dev_parms(rs, argv);
+ if (ret)
+ goto bad;
+
+ INIT_WORK(&rs->md.event_work, do_table_event);
+ ti->split_io = rs->md.chunk_sectors;
+ ti->private = rs;
+
+ mutex_lock(&rs->md.reconfig_mutex);
+ ret = md_run(&rs->md);
+ rs->md.in_sync = 0; /* Assume already marked dirty */
+ mutex_unlock(&rs->md.reconfig_mutex);
+
+ if (ret) {
+ ti->error = "Fail to run raid array";
+ goto bad;
+ }
+
+ rs->callbacks.congested_fn = raid_is_congested;
+ rs->callbacks.unplug_fn = raid_unplug;
+ dm_table_add_target_callbacks(ti->table, &rs->callbacks);
+
+ return 0;
+
+bad:
+ context_free(rs);
+
+ return ret;
+}
+
+static void raid_dtr(struct dm_target *ti)
+{
+ struct raid_set *rs = ti->private;
+
+ list_del_init(&rs->callbacks.list);
+ md_stop(&rs->md);
+ context_free(rs);
+}
+
+static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
+{
+ struct raid_set *rs = ti->private;
+ mddev_t *mddev = &rs->md;
+
+ mddev->pers->make_request(mddev, bio);
+
+ return DM_MAPIO_SUBMITTED;
+}
+
+static int raid_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ struct raid_set *rs = ti->private;
+ unsigned raid_param_cnt = 1; /* at least 1 for chunksize */
+ unsigned sz = 0;
+ int i;
+ sector_t sync;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ DMEMIT("%s %d ", rs->raid_type->name, rs->md.raid_disks);
+
+ for (i = 0; i < rs->md.raid_disks; i++) {
+ if (test_bit(Faulty, &rs->dev[i].rdev.flags))
+ DMEMIT("D");
+ else if (test_bit(In_sync, &rs->dev[i].rdev.flags))
+ DMEMIT("A");
+ else
+ DMEMIT("a");
+ }
+
+ if (test_bit(MD_RECOVERY_RUNNING, &rs->md.recovery))
+ sync = rs->md.curr_resync_completed;
+ else
+ sync = rs->md.recovery_cp;
+
+ if (sync > rs->md.resync_max_sectors)
+ sync = rs->md.resync_max_sectors;
+
+ DMEMIT(" %llu/%llu",
+ (unsigned long long) sync,
+ (unsigned long long) rs->md.resync_max_sectors);
+
+ break;
+ case STATUSTYPE_TABLE:
+ /* The string you would use to construct this array */
+ for (i = 0; i < rs->md.raid_disks; i++)
+ if (rs->dev[i].data_dev &&
+ !test_bit(In_sync, &rs->dev[i].rdev.flags))
+ raid_param_cnt++; /* for rebuilds */
+
+ raid_param_cnt += (hweight64(rs->print_flags) * 2);
+ if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC))
+ raid_param_cnt--;
+
+ DMEMIT("%s %u %u", rs->raid_type->name,
+ raid_param_cnt, rs->md.chunk_sectors);
+
+ if ((rs->print_flags & DMPF_SYNC) &&
+ (rs->md.recovery_cp == MaxSector))
+ DMEMIT(" sync");
+ if (rs->print_flags & DMPF_NOSYNC)
+ DMEMIT(" nosync");
+
+ for (i = 0; i < rs->md.raid_disks; i++)
+ if (rs->dev[i].data_dev &&
+ !test_bit(In_sync, &rs->dev[i].rdev.flags))
+ DMEMIT(" rebuild %u", i);
+
+ if (rs->print_flags & DMPF_DAEMON_SLEEP)
+ DMEMIT(" daemon_sleep %lu",
+ rs->md.bitmap_info.daemon_sleep);
+
+ if (rs->print_flags & DMPF_MIN_RECOVERY_RATE)
+ DMEMIT(" min_recovery_rate %d", rs->md.sync_speed_min);
+
+ if (rs->print_flags & DMPF_MAX_RECOVERY_RATE)
+ DMEMIT(" max_recovery_rate %d", rs->md.sync_speed_max);
+
+ if (rs->print_flags & DMPF_MAX_WRITE_BEHIND)
+ DMEMIT(" max_write_behind %lu",
+ rs->md.bitmap_info.max_write_behind);
+
+ if (rs->print_flags & DMPF_STRIPE_CACHE) {
+ raid5_conf_t *conf = rs->md.private;
+
+ /* convert from kiB to sectors */
+ DMEMIT(" stripe_cache %d",
+ conf ? conf->max_nr_stripes * 2 : 0);
+ }
+
+ DMEMIT(" %d", rs->md.raid_disks);
+ for (i = 0; i < rs->md.raid_disks; i++) {
+ DMEMIT(" -"); /* metadata device */
+
+ if (rs->dev[i].data_dev)
+ DMEMIT(" %s", rs->dev[i].data_dev->name);
+ else
+ DMEMIT(" -");
+ }
+ }
+
+ return 0;
+}
+
+static int raid_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
+{
+ struct raid_set *rs = ti->private;
+ unsigned i;
+ int ret = 0;
+
+ for (i = 0; !ret && i < rs->md.raid_disks; i++)
+ if (rs->dev[i].data_dev)
+ ret = fn(ti,
+ rs->dev[i].data_dev,
+ 0, /* No offset on data devs */
+ rs->md.dev_sectors,
+ data);
+
+ return ret;
+}
+
+static void raid_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+ struct raid_set *rs = ti->private;
+ unsigned chunk_size = rs->md.chunk_sectors << 9;
+ raid5_conf_t *conf = rs->md.private;
+
+ blk_limits_io_min(limits, chunk_size);
+ blk_limits_io_opt(limits, chunk_size * (conf->raid_disks - conf->max_degraded));
+}
+
+static void raid_presuspend(struct dm_target *ti)
+{
+ struct raid_set *rs = ti->private;
+
+ md_stop_writes(&rs->md);
+}
+
+static void raid_postsuspend(struct dm_target *ti)
+{
+ struct raid_set *rs = ti->private;
+
+ mddev_suspend(&rs->md);
+}
+
+static void raid_resume(struct dm_target *ti)
+{
+ struct raid_set *rs = ti->private;
+
+ mddev_resume(&rs->md);
+}
+
+static struct target_type raid_target = {
+ .name = "raid",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = raid_ctr,
+ .dtr = raid_dtr,
+ .map = raid_map,
+ .status = raid_status,
+ .iterate_devices = raid_iterate_devices,
+ .io_hints = raid_io_hints,
+ .presuspend = raid_presuspend,
+ .postsuspend = raid_postsuspend,
+ .resume = raid_resume,
+};
+
+static int __init dm_raid_init(void)
+{
+ return dm_register_target(&raid_target);
+}
+
+static void __exit dm_raid_exit(void)
+{
+ dm_unregister_target(&raid_target);
+}
+
+module_init(dm_raid_init);
+module_exit(dm_raid_exit);
+
+MODULE_DESCRIPTION(DM_NAME " raid4/5/6 target");
+MODULE_ALIAS("dm-raid4");
+MODULE_ALIAS("dm-raid5");
+MODULE_ALIAS("dm-raid6");
+MODULE_AUTHOR("Neil Brown <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 19a59b041c27..dee326775c60 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -261,7 +261,7 @@ static int mirror_flush(struct dm_target *ti)
struct dm_io_request io_req = {
.bi_rw = WRITE_FLUSH,
.mem.type = DM_IO_KMEM,
- .mem.ptr.bvec = NULL,
+ .mem.ptr.addr = NULL,
.client = ms->io_client,
};
@@ -637,6 +637,12 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
.client = ms->io_client,
};
+ if (bio->bi_rw & REQ_DISCARD) {
+ io_req.bi_rw |= REQ_DISCARD;
+ io_req.mem.type = DM_IO_KMEM;
+ io_req.mem.ptr.addr = NULL;
+ }
+
for (i = 0, m = ms->mirror; i < ms->nr_mirrors; i++, m++)
map_region(dest++, m, bio);
@@ -670,7 +676,8 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
bio_list_init(&requeue);
while ((bio = bio_list_pop(writes))) {
- if (bio->bi_rw & REQ_FLUSH) {
+ if ((bio->bi_rw & REQ_FLUSH) ||
+ (bio->bi_rw & REQ_DISCARD)) {
bio_list_add(&sync, bio);
continue;
}
@@ -1076,8 +1083,10 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = ms;
ti->split_io = dm_rh_get_region_size(ms->rh);
ti->num_flush_requests = 1;
+ ti->num_discard_requests = 1;
- ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
+ ms->kmirrord_wq = alloc_workqueue("kmirrord",
+ WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
if (!ms->kmirrord_wq) {
DMERR("couldn't start kmirrord");
r = -ENOMEM;
@@ -1130,7 +1139,7 @@ static void mirror_dtr(struct dm_target *ti)
del_timer_sync(&ms->timer);
flush_workqueue(ms->kmirrord_wq);
- flush_scheduled_work();
+ flush_work_sync(&ms->trigger_event);
dm_kcopyd_client_destroy(ms->kcopyd_client);
destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
@@ -1406,7 +1415,7 @@ static int mirror_iterate_devices(struct dm_target *ti,
static struct target_type mirror_target = {
.name = "mirror",
- .version = {1, 12, 0},
+ .version = {1, 12, 1},
.module = THIS_MODULE,
.ctr = mirror_ctr,
.dtr = mirror_dtr,
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 2129cdb115dc..95891dfcbca0 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -256,7 +256,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
*/
INIT_WORK_ONSTACK(&req.work, do_metadata);
queue_work(ps->metadata_wq, &req.work);
- flush_workqueue(ps->metadata_wq);
+ flush_work(&req.work);
return req.result;
}
@@ -818,7 +818,7 @@ static int persistent_ctr(struct dm_exception_store *store,
atomic_set(&ps->pending_count, 0);
ps->callbacks = NULL;
- ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
+ ps->metadata_wq = alloc_workqueue("ksnaphd", WQ_MEM_RECLAIM, 0);
if (!ps->metadata_wq) {
kfree(ps);
DMERR("couldn't start header metadata update thread");
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 53cf79d8bcbc..fdde53cd12b7 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -19,7 +19,6 @@
#include <linux/vmalloc.h>
#include <linux/log2.h>
#include <linux/dm-kcopyd.h>
-#include <linux/workqueue.h>
#include "dm-exception-store.h"
@@ -80,9 +79,6 @@ struct dm_snapshot {
/* Origin writes don't trigger exceptions until this is set */
int active;
- /* Whether or not owning mapped_device is suspended */
- int suspended;
-
atomic_t pending_exceptions_count;
mempool_t *pending_pool;
@@ -106,10 +102,6 @@ struct dm_snapshot {
struct dm_kcopyd_client *kcopyd_client;
- /* Queue of snapshot writes for ksnapd to flush */
- struct bio_list queued_bios;
- struct work_struct queued_bios_work;
-
/* Wait for events based on state_bits */
unsigned long state_bits;
@@ -160,9 +152,6 @@ struct dm_dev *dm_snap_cow(struct dm_snapshot *s)
}
EXPORT_SYMBOL(dm_snap_cow);
-static struct workqueue_struct *ksnapd;
-static void flush_queued_bios(struct work_struct *work);
-
static sector_t chunk_to_sector(struct dm_exception_store *store,
chunk_t chunk)
{
@@ -1110,7 +1099,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
s->ti = ti;
s->valid = 1;
s->active = 0;
- s->suspended = 0;
atomic_set(&s->pending_exceptions_count, 0);
init_rwsem(&s->lock);
INIT_LIST_HEAD(&s->list);
@@ -1153,9 +1141,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
spin_lock_init(&s->tracked_chunk_lock);
- bio_list_init(&s->queued_bios);
- INIT_WORK(&s->queued_bios_work, flush_queued_bios);
-
ti->private = s;
ti->num_flush_requests = num_flush_requests;
@@ -1279,8 +1264,6 @@ static void snapshot_dtr(struct dm_target *ti)
struct dm_snapshot *s = ti->private;
struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
- flush_workqueue(ksnapd);
-
down_read(&_origins_lock);
/* Check whether exception handover must be cancelled */
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
@@ -1342,20 +1325,6 @@ static void flush_bios(struct bio *bio)
}
}
-static void flush_queued_bios(struct work_struct *work)
-{
- struct dm_snapshot *s =
- container_of(work, struct dm_snapshot, queued_bios_work);
- struct bio *queued_bios;
- unsigned long flags;
-
- spin_lock_irqsave(&s->pe_lock, flags);
- queued_bios = bio_list_get(&s->queued_bios);
- spin_unlock_irqrestore(&s->pe_lock, flags);
-
- flush_bios(queued_bios);
-}
-
static int do_origin(struct dm_dev *origin, struct bio *bio);
/*
@@ -1760,15 +1729,6 @@ static void snapshot_merge_presuspend(struct dm_target *ti)
stop_merge(s);
}
-static void snapshot_postsuspend(struct dm_target *ti)
-{
- struct dm_snapshot *s = ti->private;
-
- down_write(&s->lock);
- s->suspended = 1;
- up_write(&s->lock);
-}
-
static int snapshot_preresume(struct dm_target *ti)
{
int r = 0;
@@ -1783,7 +1743,7 @@ static int snapshot_preresume(struct dm_target *ti)
DMERR("Unable to resume snapshot source until "
"handover completes.");
r = -EINVAL;
- } else if (!snap_src->suspended) {
+ } else if (!dm_suspended(snap_src->ti)) {
DMERR("Unable to perform snapshot handover until "
"source is suspended.");
r = -EINVAL;
@@ -1816,7 +1776,6 @@ static void snapshot_resume(struct dm_target *ti)
down_write(&s->lock);
s->active = 1;
- s->suspended = 0;
up_write(&s->lock);
}
@@ -2194,7 +2153,7 @@ static int origin_iterate_devices(struct dm_target *ti,
static struct target_type origin_target = {
.name = "snapshot-origin",
- .version = {1, 7, 0},
+ .version = {1, 7, 1},
.module = THIS_MODULE,
.ctr = origin_ctr,
.dtr = origin_dtr,
@@ -2207,13 +2166,12 @@ static struct target_type origin_target = {
static struct target_type snapshot_target = {
.name = "snapshot",
- .version = {1, 9, 0},
+ .version = {1, 10, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
.map = snapshot_map,
.end_io = snapshot_end_io,
- .postsuspend = snapshot_postsuspend,
.preresume = snapshot_preresume,
.resume = snapshot_resume,
.status = snapshot_status,
@@ -2222,14 +2180,13 @@ static struct target_type snapshot_target = {
static struct target_type merge_target = {
.name = dm_snapshot_merge_target_name,
- .version = {1, 0, 0},
+ .version = {1, 1, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
.map = snapshot_merge_map,
.end_io = snapshot_end_io,
.presuspend = snapshot_merge_presuspend,
- .postsuspend = snapshot_postsuspend,
.preresume = snapshot_preresume,
.resume = snapshot_merge_resume,
.status = snapshot_status,
@@ -2291,17 +2248,8 @@ static int __init dm_snapshot_init(void)
goto bad_tracked_chunk_cache;
}
- ksnapd = create_singlethread_workqueue("ksnapd");
- if (!ksnapd) {
- DMERR("Failed to create ksnapd workqueue.");
- r = -ENOMEM;
- goto bad_pending_pool;
- }
-
return 0;
-bad_pending_pool:
- kmem_cache_destroy(tracked_chunk_cache);
bad_tracked_chunk_cache:
kmem_cache_destroy(pending_cache);
bad_pending_cache:
@@ -2322,8 +2270,6 @@ bad_register_snapshot_target:
static void __exit dm_snapshot_exit(void)
{
- destroy_workqueue(ksnapd);
-
dm_unregister_target(&snapshot_target);
dm_unregister_target(&origin_target);
dm_unregister_target(&merge_target);
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index f0371b4c4fbf..dddfa14f2982 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -39,23 +39,20 @@ struct stripe_c {
struct dm_target *ti;
/* Work struct used for triggering events*/
- struct work_struct kstriped_ws;
+ struct work_struct trigger_event;
struct stripe stripe[0];
};
-static struct workqueue_struct *kstriped;
-
/*
* An event is triggered whenever a drive
* drops out of a stripe volume.
*/
static void trigger_event(struct work_struct *work)
{
- struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws);
-
+ struct stripe_c *sc = container_of(work, struct stripe_c,
+ trigger_event);
dm_table_event(sc->ti->table);
-
}
static inline struct stripe_c *alloc_context(unsigned int stripes)
@@ -160,7 +157,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -ENOMEM;
}
- INIT_WORK(&sc->kstriped_ws, trigger_event);
+ INIT_WORK(&sc->trigger_event, trigger_event);
/* Set pointer to dm target; used in trigger_event */
sc->ti = ti;
@@ -211,7 +208,7 @@ static void stripe_dtr(struct dm_target *ti)
for (i = 0; i < sc->stripes; i++)
dm_put_device(ti, sc->stripe[i].dev);
- flush_workqueue(kstriped);
+ flush_work_sync(&sc->trigger_event);
kfree(sc);
}
@@ -367,7 +364,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio,
atomic_inc(&(sc->stripe[i].error_count));
if (atomic_read(&(sc->stripe[i].error_count)) <
DM_IO_ERROR_THRESHOLD)
- queue_work(kstriped, &sc->kstriped_ws);
+ schedule_work(&sc->trigger_event);
}
return error;
@@ -401,7 +398,7 @@ static void stripe_io_hints(struct dm_target *ti,
static struct target_type stripe_target = {
.name = "striped",
- .version = {1, 3, 0},
+ .version = {1, 3, 1},
.module = THIS_MODULE,
.ctr = stripe_ctr,
.dtr = stripe_dtr,
@@ -422,20 +419,10 @@ int __init dm_stripe_init(void)
return r;
}
- kstriped = create_singlethread_workqueue("kstriped");
- if (!kstriped) {
- DMERR("failed to create workqueue kstriped");
- dm_unregister_target(&stripe_target);
- return -ENOMEM;
- }
-
return r;
}
void dm_stripe_exit(void)
{
dm_unregister_target(&stripe_target);
- destroy_workqueue(kstriped);
-
- return;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 90267f8d64ee..38e4eb1bb965 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -71,6 +71,8 @@ struct dm_table {
void *event_context;
struct dm_md_mempools *mempools;
+
+ struct list_head target_callbacks;
};
/*
@@ -204,6 +206,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
return -ENOMEM;
INIT_LIST_HEAD(&t->devices);
+ INIT_LIST_HEAD(&t->target_callbacks);
atomic_set(&t->holders, 0);
t->discards_supported = 1;
@@ -325,15 +328,18 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev,
BUG_ON(d->dm_dev.bdev);
- bdev = open_by_devnum(dev, d->dm_dev.mode);
+ bdev = blkdev_get_by_dev(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
- r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
- if (r)
- blkdev_put(bdev, d->dm_dev.mode);
- else
- d->dm_dev.bdev = bdev;
- return r;
+
+ r = bd_link_disk_holder(bdev, dm_disk(md));
+ if (r) {
+ blkdev_put(bdev, d->dm_dev.mode | FMODE_EXCL);
+ return r;
+ }
+
+ d->dm_dev.bdev = bdev;
+ return 0;
}
/*
@@ -344,8 +350,8 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
if (!d->dm_dev.bdev)
return;
- bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
- blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
+ bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
+ blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
d->dm_dev.bdev = NULL;
}
@@ -517,9 +523,8 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
*/
if (q->merge_bvec_fn && !ti->type->merge)
- limits->max_sectors =
- min_not_zero(limits->max_sectors,
- (unsigned int) (PAGE_SIZE >> 9));
+ blk_limits_max_hw_sectors(limits,
+ (unsigned int) (PAGE_SIZE >> 9));
return 0;
}
EXPORT_SYMBOL_GPL(dm_set_device_limits);
@@ -1131,11 +1136,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
*/
q->limits = *limits;
- if (limits->no_cluster)
- queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
- else
- queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
-
if (!dm_table_supports_discards(t))
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
else
@@ -1229,10 +1229,17 @@ int dm_table_resume_targets(struct dm_table *t)
return 0;
}
+void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb)
+{
+ list_add(&cb->list, &t->target_callbacks);
+}
+EXPORT_SYMBOL_GPL(dm_table_add_target_callbacks);
+
int dm_table_any_congested(struct dm_table *t, int bdi_bits)
{
struct dm_dev_internal *dd;
struct list_head *devices = dm_table_get_devices(t);
+ struct dm_target_callbacks *cb;
int r = 0;
list_for_each_entry(dd, devices, list) {
@@ -1247,6 +1254,10 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
bdevname(dd->dm_dev.bdev, b));
}
+ list_for_each_entry(cb, &t->target_callbacks, list)
+ if (cb->congested_fn)
+ r |= cb->congested_fn(cb, bdi_bits);
+
return r;
}
@@ -1268,6 +1279,7 @@ void dm_table_unplug_all(struct dm_table *t)
{
struct dm_dev_internal *dd;
struct list_head *devices = dm_table_get_devices(t);
+ struct dm_target_callbacks *cb;
list_for_each_entry(dd, devices, list) {
struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
@@ -1280,6 +1292,10 @@ void dm_table_unplug_all(struct dm_table *t)
dm_device_name(t->md),
bdevname(dd->dm_dev.bdev, b));
}
+
+ list_for_each_entry(cb, &t->target_callbacks, list)
+ if (cb->unplug_fn)
+ cb->unplug_fn(cb);
}
struct mapped_device *dm_table_get_md(struct dm_table *t)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7cb1352f7e7a..eaa3af0e0632 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -32,7 +32,6 @@
#define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE"
#define DM_COOKIE_LENGTH 24
-static DEFINE_MUTEX(dm_mutex);
static const char *_name = DM_NAME;
static unsigned int major = 0;
@@ -328,7 +327,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mapped_device *md;
- mutex_lock(&dm_mutex);
spin_lock(&_minor_lock);
md = bdev->bd_disk->private_data;
@@ -346,7 +344,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
out:
spin_unlock(&_minor_lock);
- mutex_unlock(&dm_mutex);
return md ? 0 : -ENXIO;
}
@@ -355,10 +352,12 @@ static int dm_blk_close(struct gendisk *disk, fmode_t mode)
{
struct mapped_device *md = disk->private_data;
- mutex_lock(&dm_mutex);
+ spin_lock(&_minor_lock);
+
atomic_dec(&md->open_count);
dm_put(md);
- mutex_unlock(&dm_mutex);
+
+ spin_unlock(&_minor_lock);
return 0;
}
@@ -630,7 +629,7 @@ static void dec_pending(struct dm_io *io, int error)
queue_io(md, bio);
} else {
/* done with normal IO or empty flush */
- trace_block_bio_complete(md->queue, bio);
+ trace_block_bio_complete(md->queue, bio, io_error);
bio_endio(bio, io_error);
}
}
@@ -990,8 +989,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
if (r == DM_MAPIO_REMAPPED) {
/* the bio has been remapped so dispatch it */
- trace_block_remap(bdev_get_queue(clone->bi_bdev), clone,
- tio->io->bio->bi_bdev->bd_dev, sector);
+ trace_block_bio_remap(bdev_get_queue(clone->bi_bdev), clone,
+ tio->io->bio->bi_bdev->bd_dev, sector);
generic_make_request(clone);
} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
@@ -1638,13 +1637,15 @@ static void dm_request_fn(struct request_queue *q)
if (map_request(ti, clone, md))
goto requeued;
- spin_lock_irq(q->queue_lock);
+ BUG_ON(!irqs_disabled());
+ spin_lock(q->queue_lock);
}
goto out;
requeued:
- spin_lock_irq(q->queue_lock);
+ BUG_ON(!irqs_disabled());
+ spin_lock(q->queue_lock);
plug_and_out:
if (!elv_queue_empty(q))
@@ -1884,7 +1885,8 @@ static struct mapped_device *alloc_dev(int minor)
add_disk(md->disk);
format_dev_t(md->name, MKDEV(_major, minor));
- md->wq = create_singlethread_workqueue("kdmflush");
+ md->wq = alloc_workqueue("kdmflush",
+ WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
if (!md->wq)
goto bad_thread;
@@ -1992,13 +1994,14 @@ static void event_callback(void *context)
wake_up(&md->eventq);
}
+/*
+ * Protected by md->suspend_lock obtained by dm_swap_table().
+ */
static void __set_size(struct mapped_device *md, sector_t size)
{
set_capacity(md->disk, size);
- mutex_lock(&md->bdev->bd_inode->i_mutex);
i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
- mutex_unlock(&md->bdev->bd_inode->i_mutex);
}
/*
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4e957f3140a8..b76cfc89e1b5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -288,10 +288,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
int rv;
int cpu;
- if (mddev == NULL || mddev->pers == NULL) {
+ if (mddev == NULL || mddev->pers == NULL
+ || !mddev->ready) {
bio_io_error(bio);
return 0;
}
+ smp_rmb(); /* Ensure implications of 'active' are visible */
rcu_read_lock();
if (mddev->suspended) {
DEFINE_WAIT(__wait);
@@ -371,10 +373,15 @@ static void md_end_flush(struct bio *bio, int err)
bio_put(bio);
}
-static void submit_flushes(mddev_t *mddev)
+static void md_submit_flush_data(struct work_struct *ws);
+
+static void submit_flushes(struct work_struct *ws)
{
+ mddev_t *mddev = container_of(ws, mddev_t, flush_work);
mdk_rdev_t *rdev;
+ INIT_WORK(&mddev->flush_work, md_submit_flush_data);
+ atomic_set(&mddev->flush_pending, 1);
rcu_read_lock();
list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
@@ -397,6 +404,8 @@ static void submit_flushes(mddev_t *mddev)
rdev_dec_pending(rdev, mddev);
}
rcu_read_unlock();
+ if (atomic_dec_and_test(&mddev->flush_pending))
+ queue_work(md_wq, &mddev->flush_work);
}
static void md_submit_flush_data(struct work_struct *ws)
@@ -404,8 +413,6 @@ static void md_submit_flush_data(struct work_struct *ws)
mddev_t *mddev = container_of(ws, mddev_t, flush_work);
struct bio *bio = mddev->flush_bio;
- atomic_set(&mddev->flush_pending, 1);
-
if (bio->bi_size == 0)
/* an empty barrier - all done */
bio_endio(bio, 0);
@@ -414,10 +421,9 @@ static void md_submit_flush_data(struct work_struct *ws)
if (mddev->pers->make_request(mddev, bio))
generic_make_request(bio);
}
- if (atomic_dec_and_test(&mddev->flush_pending)) {
- mddev->flush_bio = NULL;
- wake_up(&mddev->sb_wait);
- }
+
+ mddev->flush_bio = NULL;
+ wake_up(&mddev->sb_wait);
}
void md_flush_request(mddev_t *mddev, struct bio *bio)
@@ -429,13 +435,8 @@ void md_flush_request(mddev_t *mddev, struct bio *bio)
mddev->flush_bio = bio;
spin_unlock_irq(&mddev->write_lock);
- atomic_set(&mddev->flush_pending, 1);
- INIT_WORK(&mddev->flush_work, md_submit_flush_data);
-
- submit_flushes(mddev);
-
- if (atomic_dec_and_test(&mddev->flush_pending))
- queue_work(md_wq, &mddev->flush_work);
+ INIT_WORK(&mddev->flush_work, submit_flushes);
+ queue_work(md_wq, &mddev->flush_work);
}
EXPORT_SYMBOL(md_flush_request);
@@ -704,9 +705,9 @@ static struct mdk_personality *find_pers(int level, char *clevel)
}
/* return the offset of the super block in 512byte sectors */
-static inline sector_t calc_dev_sboffset(struct block_device *bdev)
+static inline sector_t calc_dev_sboffset(mdk_rdev_t *rdev)
{
- sector_t num_sectors = bdev->bd_inode->i_size / 512;
+ sector_t num_sectors = i_size_read(rdev->bdev->bd_inode) / 512;
return MD_NEW_SIZE_SECTORS(num_sectors);
}
@@ -764,7 +765,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
*/
struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev);
- bio->bi_bdev = rdev->bdev;
+ bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
bio->bi_private = rdev;
@@ -794,7 +795,7 @@ static void bi_complete(struct bio *bio, int error)
}
int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size,
- struct page *page, int rw)
+ struct page *page, int rw, bool metadata_op)
{
struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev);
struct completion event;
@@ -802,8 +803,12 @@ int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size,
rw |= REQ_SYNC | REQ_UNPLUG;
- bio->bi_bdev = rdev->bdev;
- bio->bi_sector = sector;
+ bio->bi_bdev = (metadata_op && rdev->meta_bdev) ?
+ rdev->meta_bdev : rdev->bdev;
+ if (metadata_op)
+ bio->bi_sector = sector + rdev->sb_start;
+ else
+ bio->bi_sector = sector + rdev->data_offset;
bio_add_page(bio, page, size, 0);
init_completion(&event);
bio->bi_private = &event;
@@ -828,7 +833,7 @@ static int read_disk_sb(mdk_rdev_t * rdev, int size)
return 0;
- if (!sync_page_io(rdev, rdev->sb_start, size, rdev->sb_page, READ))
+ if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, true))
goto fail;
rdev->sb_loaded = 1;
return 0;
@@ -990,7 +995,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
*
* It also happens to be a multiple of 4Kb.
*/
- rdev->sb_start = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_start = calc_dev_sboffset(rdev);
ret = read_disk_sb(rdev, MD_SB_BYTES);
if (ret) return ret;
@@ -1331,13 +1336,13 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
return 0; /* component must fit device */
if (rdev->mddev->bitmap_info.offset)
return 0; /* can't move bitmap */
- rdev->sb_start = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_start = calc_dev_sboffset(rdev);
if (!num_sectors || num_sectors > rdev->sb_start)
num_sectors = rdev->sb_start;
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
- return num_sectors / 2; /* kB for sysfs */
+ return num_sectors;
}
@@ -1386,7 +1391,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
*/
switch(minor_version) {
case 0:
- sb_start = rdev->bdev->bd_inode->i_size >> 9;
+ sb_start = i_size_read(rdev->bdev->bd_inode) >> 9;
sb_start -= 8*2;
sb_start &= ~(sector_t)(4*2-1);
break;
@@ -1472,7 +1477,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
ret = 0;
}
if (minor_version)
- rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+ rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
le64_to_cpu(sb->data_offset);
else
rdev->sectors = rdev->sb_start;
@@ -1680,7 +1685,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
return 0; /* component must fit device */
if (rdev->sb_start < rdev->data_offset) {
/* minor versions 1 and 2; superblock before data */
- max_sectors = rdev->bdev->bd_inode->i_size >> 9;
+ max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
max_sectors -= rdev->data_offset;
if (!num_sectors || num_sectors > max_sectors)
num_sectors = max_sectors;
@@ -1690,7 +1695,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
} else {
/* minor version 0; superblock after data */
sector_t sb_start;
- sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
+ sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
sb_start &= ~(sector_t)(4*2 - 1);
max_sectors = rdev->sectors + sb_start - rdev->sb_start;
if (!num_sectors || num_sectors > max_sectors)
@@ -1704,7 +1709,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
- return num_sectors / 2; /* kB for sysfs */
+ return num_sectors;
}
static struct super_type super_types[] = {
@@ -1880,7 +1885,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
list_add_rcu(&rdev->same_set, &mddev->disks);
- bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
+ bd_link_disk_holder(rdev->bdev, mddev->gendisk);
/* May as well allow recovery to be retried once */
mddev->recovery_disabled = 0;
@@ -1907,7 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
MD_BUG();
return;
}
- bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk);
+ bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
@@ -1935,19 +1940,13 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
- bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
+ shared ? (mdk_rdev_t *)lock_rdev : rdev);
if (IS_ERR(bdev)) {
printk(KERN_ERR "md: could not open %s.\n",
__bdevname(dev, b));
return PTR_ERR(bdev);
}
- err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
- if (err) {
- printk(KERN_ERR "md: could not bd_claim %s.\n",
- bdevname(bdev, b));
- blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
- return err;
- }
if (!shared)
set_bit(AllReserved, &rdev->flags);
rdev->bdev = bdev;
@@ -1960,8 +1959,7 @@ static void unlock_rdev(mdk_rdev_t *rdev)
rdev->bdev = NULL;
if (!bdev)
MD_BUG();
- bd_release(bdev);
- blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
void md_autodetect_dev(dev_t dev);
@@ -2474,6 +2472,10 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
if (rdev2->raid_disk == slot)
return -EEXIST;
+ if (slot >= rdev->mddev->raid_disks &&
+ slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks)
+ return -ENOSPC;
+
rdev->raid_disk = slot;
if (test_bit(In_sync, &rdev->flags))
rdev->saved_raid_disk = slot;
@@ -2491,7 +2493,8 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
/* failure here is OK */;
/* don't wakeup anyone, leave that to userspace. */
} else {
- if (slot >= rdev->mddev->raid_disks)
+ if (slot >= rdev->mddev->raid_disks &&
+ slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks)
return -ENOSPC;
rdev->raid_disk = slot;
/* assume it is working */
@@ -2584,7 +2587,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
if (!sectors)
return -EBUSY;
} else if (!sectors)
- sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+ sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
rdev->data_offset;
}
if (sectors < my_mddev->dev_sectors)
@@ -2797,7 +2800,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
kobject_init(&rdev->kobj, &rdev_ktype);
- size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+ size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
if (!size) {
printk(KERN_WARNING
"md: %s has zero or unknown size, marking faulty!\n",
@@ -3116,7 +3119,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
char nm[20];
if (rdev->raid_disk < 0)
continue;
- if (rdev->new_raid_disk > mddev->raid_disks)
+ if (rdev->new_raid_disk >= mddev->raid_disks)
rdev->new_raid_disk = -1;
if (rdev->new_raid_disk == rdev->raid_disk)
continue;
@@ -3745,6 +3748,8 @@ action_show(mddev_t *mddev, char *page)
return sprintf(page, "%s\n", type);
}
+static void reap_sync_thread(mddev_t *mddev);
+
static ssize_t
action_store(mddev_t *mddev, const char *page, size_t len)
{
@@ -3759,9 +3764,7 @@ action_store(mddev_t *mddev, const char *page, size_t len)
if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(mddev->sync_thread);
- mddev->sync_thread = NULL;
- mddev->recovery = 0;
+ reap_sync_thread(mddev);
}
} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
@@ -3913,7 +3916,7 @@ static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed);
static ssize_t
sync_completed_show(mddev_t *mddev, char *page)
{
- unsigned long max_sectors, resync;
+ unsigned long long max_sectors, resync;
if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return sprintf(page, "none\n");
@@ -3924,7 +3927,7 @@ sync_completed_show(mddev_t *mddev, char *page)
max_sectors = mddev->dev_sectors;
resync = mddev->curr_resync_completed;
- return sprintf(page, "%lu / %lu\n", resync, max_sectors);
+ return sprintf(page, "%llu / %llu\n", resync, max_sectors);
}
static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
@@ -4011,19 +4014,24 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
+ unsigned long long old = mddev->suspend_lo;
if (mddev->pers == NULL ||
mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
- if (new >= mddev->suspend_hi ||
- (new > mddev->suspend_lo && new < mddev->suspend_hi)) {
- mddev->suspend_lo = new;
+
+ mddev->suspend_lo = new;
+ if (new >= old)
+ /* Shrinking suspended region */
mddev->pers->quiesce(mddev, 2);
- return len;
- } else
- return -EINVAL;
+ else {
+ /* Expanding suspended region - need to wait */
+ mddev->pers->quiesce(mddev, 1);
+ mddev->pers->quiesce(mddev, 0);
+ }
+ return len;
}
static struct md_sysfs_entry md_suspend_lo =
__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
@@ -4040,20 +4048,24 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
+ unsigned long long old = mddev->suspend_hi;
if (mddev->pers == NULL ||
mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
- if ((new <= mddev->suspend_lo && mddev->suspend_lo >= mddev->suspend_hi) ||
- (new > mddev->suspend_lo && new > mddev->suspend_hi)) {
- mddev->suspend_hi = new;
+
+ mddev->suspend_hi = new;
+ if (new <= old)
+ /* Shrinking suspended region */
+ mddev->pers->quiesce(mddev, 2);
+ else {
+ /* Expanding suspended region - need to wait */
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
- return len;
- } else
- return -EINVAL;
+ }
+ return len;
}
static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
@@ -4296,9 +4308,6 @@ static int md_alloc(dev_t dev, char *name)
goto abort;
mddev->queue->queuedata = mddev;
- /* Can be unlocked because the queue is new: no concurrency */
- queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue);
-
blk_queue_make_request(mddev->queue, md_make_request);
disk = alloc_disk(1 << shift);
@@ -4338,6 +4347,8 @@ static int md_alloc(dev_t dev, char *name)
if (mddev->kobj.sd &&
sysfs_create_group(&mddev->kobj, &md_bitmap_group))
printk(KERN_DEBUG "pointless warning\n");
+
+ blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
abort:
mutex_unlock(&disks_mutex);
if (!error && mddev->kobj.sd) {
@@ -4432,7 +4443,9 @@ int md_run(mddev_t *mddev)
* We don't want the data to overlap the metadata,
* Internal Bitmap issues have been handled elsewhere.
*/
- if (rdev->data_offset < rdev->sb_start) {
+ if (rdev->meta_bdev) {
+ /* Nothing to check */;
+ } else if (rdev->data_offset < rdev->sb_start) {
if (mddev->dev_sectors &&
rdev->data_offset + mddev->dev_sectors
> rdev->sb_start) {
@@ -4566,7 +4579,8 @@ int md_run(mddev_t *mddev)
mddev->safemode_timer.data = (unsigned long) mddev;
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
-
+ smp_wmb();
+ mddev->ready = 1;
list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0) {
char nm[20];
@@ -4703,13 +4717,12 @@ static void md_clean(mddev_t *mddev)
mddev->plug = NULL;
}
-void md_stop_writes(mddev_t *mddev)
+static void __md_stop_writes(mddev_t *mddev)
{
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(mddev->sync_thread);
- mddev->sync_thread = NULL;
+ reap_sync_thread(mddev);
}
del_timer_sync(&mddev->safemode_timer);
@@ -4723,10 +4736,18 @@ void md_stop_writes(mddev_t *mddev)
md_update_sb(mddev, 1);
}
}
+
+void md_stop_writes(mddev_t *mddev)
+{
+ mddev_lock(mddev);
+ __md_stop_writes(mddev);
+ mddev_unlock(mddev);
+}
EXPORT_SYMBOL_GPL(md_stop_writes);
void md_stop(mddev_t *mddev)
{
+ mddev->ready = 0;
mddev->pers->stop(mddev);
if (mddev->pers->sync_request && mddev->to_remove == NULL)
mddev->to_remove = &md_redundancy_group;
@@ -4746,7 +4767,7 @@ static int md_set_readonly(mddev_t *mddev, int is_open)
goto out;
}
if (mddev->pers) {
- md_stop_writes(mddev);
+ __md_stop_writes(mddev);
err = -ENXIO;
if (mddev->ro==1)
@@ -4783,7 +4804,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
if (mddev->ro)
set_disk_ro(disk, 0);
- md_stop_writes(mddev);
+ __md_stop_writes(mddev);
md_stop(mddev);
mddev->queue->merge_bvec_fn = NULL;
mddev->queue->unplug_fn = NULL;
@@ -5158,17 +5179,21 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
PTR_ERR(rdev));
return PTR_ERR(rdev);
}
- /* set save_raid_disk if appropriate */
+ /* set saved_raid_disk if appropriate */
if (!mddev->persistent) {
if (info->state & (1<<MD_DISK_SYNC) &&
- info->raid_disk < mddev->raid_disks)
+ info->raid_disk < mddev->raid_disks) {
rdev->raid_disk = info->raid_disk;
- else
+ set_bit(In_sync, &rdev->flags);
+ } else
rdev->raid_disk = -1;
} else
super_types[mddev->major_version].
validate_super(mddev, rdev);
- rdev->saved_raid_disk = rdev->raid_disk;
+ if (test_bit(In_sync, &rdev->flags))
+ rdev->saved_raid_disk = rdev->raid_disk;
+ else
+ rdev->saved_raid_disk = -1;
clear_bit(In_sync, &rdev->flags); /* just to be sure */
if (info->state & (1<<MD_DISK_WRITEMOSTLY))
@@ -5235,9 +5260,9 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
if (!mddev->persistent) {
printk(KERN_INFO "md: nonpersistent superblock ...\n");
- rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
- } else
- rdev->sb_start = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
+ } else
+ rdev->sb_start = calc_dev_sboffset(rdev);
rdev->sectors = rdev->sb_start;
err = bind_rdev_to_array(rdev, mddev);
@@ -5304,9 +5329,9 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
}
if (mddev->persistent)
- rdev->sb_start = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_start = calc_dev_sboffset(rdev);
else
- rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
+ rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
rdev->sectors = rdev->sb_start;
@@ -5517,7 +5542,6 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
* sb_start or, if that is <data_offset, it must fit before the size
* of each device. If num_sectors is zero, we find the largest size
* that fits.
-
*/
if (mddev->sync_thread)
return -EBUSY;
@@ -6041,8 +6065,8 @@ static int md_thread(void * arg)
thread->timeout);
clear_bit(THREAD_WAKEUP, &thread->flags);
-
- thread->run(thread->mddev);
+ if (!kthread_should_stop())
+ thread->run(thread->mddev);
}
return 0;
@@ -6807,7 +6831,7 @@ void md_do_sync(mddev_t *mddev)
desc, mdname(mddev));
mddev->curr_resync = j;
}
- mddev->curr_resync_completed = mddev->curr_resync;
+ mddev->curr_resync_completed = j;
while (j < max_sectors) {
sector_t sectors;
@@ -6825,8 +6849,7 @@ void md_do_sync(mddev_t *mddev)
md_unplug(mddev);
wait_event(mddev->recovery_wait,
atomic_read(&mddev->recovery_active) == 0);
- mddev->curr_resync_completed =
- mddev->curr_resync;
+ mddev->curr_resync_completed = j;
set_bit(MD_CHANGE_CLEAN, &mddev->flags);
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
}
@@ -7031,6 +7054,45 @@ static int remove_and_add_spares(mddev_t *mddev)
}
return spares;
}
+
+static void reap_sync_thread(mddev_t *mddev)
+{
+ mdk_rdev_t *rdev;
+
+ /* resync has finished, collect result */
+ md_unregister_thread(mddev->sync_thread);
+ mddev->sync_thread = NULL;
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+ /* success...*/
+ /* activate any spares */
+ if (mddev->pers->spare_active(mddev))
+ sysfs_notify(&mddev->kobj, NULL,
+ "degraded");
+ }
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ mddev->pers->finish_reshape)
+ mddev->pers->finish_reshape(mddev);
+ md_update_sb(mddev, 1);
+
+ /* if array is no-longer degraded, then any saved_raid_disk
+ * information must be scrapped
+ */
+ if (!mddev->degraded)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ rdev->saved_raid_disk = -1;
+
+ clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ /* flag recovery needed just to double check */
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ sysfs_notify_dirent_safe(mddev->sysfs_action);
+ md_new_event(mddev);
+}
+
/*
* This routine is regularly called by all per-raid-array threads to
* deal with generic issues like resync and super-block update.
@@ -7055,9 +7117,6 @@ static int remove_and_add_spares(mddev_t *mddev)
*/
void md_check_recovery(mddev_t *mddev)
{
- mdk_rdev_t *rdev;
-
-
if (mddev->bitmap)
bitmap_daemon_work(mddev);
@@ -7125,34 +7184,7 @@ void md_check_recovery(mddev_t *mddev)
goto unlock;
}
if (mddev->sync_thread) {
- /* resync has finished, collect result */
- md_unregister_thread(mddev->sync_thread);
- mddev->sync_thread = NULL;
- if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
- /* success...*/
- /* activate any spares */
- if (mddev->pers->spare_active(mddev))
- sysfs_notify(&mddev->kobj, NULL,
- "degraded");
- }
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- mddev->pers->finish_reshape)
- mddev->pers->finish_reshape(mddev);
- md_update_sb(mddev, 1);
-
- /* if array is no-longer degraded, then any saved_raid_disk
- * information must be scrapped
- */
- if (!mddev->degraded)
- list_for_each_entry(rdev, &mddev->disks, same_set)
- rdev->saved_raid_disk = -1;
-
- mddev->recovery = 0;
- /* flag recovery needed just to double check */
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- sysfs_notify_dirent_safe(mddev->sysfs_action);
- md_new_event(mddev);
+ reap_sync_thread(mddev);
goto unlock;
}
/* Set RUNNING before clearing NEEDED to avoid
@@ -7210,7 +7242,11 @@ void md_check_recovery(mddev_t *mddev)
" thread...\n",
mdname(mddev));
/* leave the spares where they are, it shouldn't hurt */
- mddev->recovery = 0;
+ clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
} else
md_wakeup_thread(mddev->sync_thread);
sysfs_notify_dirent_safe(mddev->sysfs_action);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d05bab55df4e..eec517ced31a 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -60,6 +60,12 @@ struct mdk_rdev_s
mddev_t *mddev; /* RAID array if running */
int last_events; /* IO event timestamp */
+ /*
+ * If meta_bdev is non-NULL, it means that a separate device is
+ * being used to store the metadata (superblock/bitmap) which
+ * would otherwise be contained on the same device as the data (bdev).
+ */
+ struct block_device *meta_bdev;
struct block_device *bdev; /* block device handle */
struct page *sb_page;
@@ -148,7 +154,8 @@ struct mddev_s
* are happening, so run/
* takeover/stop are not safe
*/
-
+ int ready; /* See when safe to pass
+ * IO requests down */
struct gendisk *gendisk;
struct kobject kobj;
@@ -497,8 +504,8 @@ extern void md_flush_request(mddev_t *mddev, struct bio *bio);
extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
sector_t sector, int size, struct page *page);
extern void md_super_wait(mddev_t *mddev);
-extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size,
- struct page *page, int rw);
+extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size,
+ struct page *page, int rw, bool metadata_op);
extern void md_do_sync(mddev_t *mddev);
extern void md_new_event(mddev_t *mddev);
extern int md_allow_write(mddev_t *mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 45f8324196ec..a23ffa397ba9 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1027,8 +1027,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
} else
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- printk(KERN_ALERT "md/raid1:%s: Disk failure on %s, disabling device.\n"
- KERN_ALERT "md/raid1:%s: Operation continuing on %d devices.\n",
+ printk(KERN_ALERT
+ "md/raid1:%s: Disk failure on %s, disabling device.\n"
+ "md/raid1:%s: Operation continuing on %d devices.\n",
mdname(mddev), bdevname(rdev->bdev, b),
mdname(mddev), conf->raid_disks - mddev->degraded);
}
@@ -1161,6 +1162,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
* is not possible.
*/
if (!test_bit(Faulty, &rdev->flags) &&
+ !mddev->recovery_disabled &&
mddev->degraded < conf->raid_disks) {
err = -EBUSY;
goto abort;
@@ -1363,10 +1365,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
*/
rdev = conf->mirrors[d].rdev;
if (sync_page_io(rdev,
- sect + rdev->data_offset,
+ sect,
s<<9,
bio->bi_io_vec[idx].bv_page,
- READ)) {
+ READ, false)) {
success = 1;
break;
}
@@ -1389,10 +1391,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
rdev = conf->mirrors[d].rdev;
atomic_add(s, &rdev->corrected_errors);
if (sync_page_io(rdev,
- sect + rdev->data_offset,
+ sect,
s<<9,
bio->bi_io_vec[idx].bv_page,
- WRITE) == 0)
+ WRITE, false) == 0)
md_error(mddev, rdev);
}
d = start;
@@ -1404,10 +1406,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
continue;
rdev = conf->mirrors[d].rdev;
if (sync_page_io(rdev,
- sect + rdev->data_offset,
+ sect,
s<<9,
bio->bi_io_vec[idx].bv_page,
- READ) == 0)
+ READ, false) == 0)
md_error(mddev, rdev);
}
} else {
@@ -1487,10 +1489,8 @@ static void fix_read_error(conf_t *conf, int read_disk,
rdev = conf->mirrors[d].rdev;
if (rdev &&
test_bit(In_sync, &rdev->flags) &&
- sync_page_io(rdev,
- sect + rdev->data_offset,
- s<<9,
- conf->tmppage, READ))
+ sync_page_io(rdev, sect, s<<9,
+ conf->tmppage, READ, false))
success = 1;
else {
d++;
@@ -1513,9 +1513,8 @@ static void fix_read_error(conf_t *conf, int read_disk,
rdev = conf->mirrors[d].rdev;
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
- if (sync_page_io(rdev,
- sect + rdev->data_offset,
- s<<9, conf->tmppage, WRITE)
+ if (sync_page_io(rdev, sect, s<<9,
+ conf->tmppage, WRITE, false)
== 0)
/* Well, this device is dead */
md_error(mddev, rdev);
@@ -1530,9 +1529,8 @@ static void fix_read_error(conf_t *conf, int read_disk,
rdev = conf->mirrors[d].rdev;
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
- if (sync_page_io(rdev,
- sect + rdev->data_offset,
- s<<9, conf->tmppage, READ)
+ if (sync_page_io(rdev, sect, s<<9,
+ conf->tmppage, READ, false)
== 0)
/* Well, this device is dead */
md_error(mddev, rdev);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index c67aa54694ae..69b659544390 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1051,8 +1051,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
}
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- printk(KERN_ALERT "md/raid10:%s: Disk failure on %s, disabling device.\n"
- KERN_ALERT "md/raid10:%s: Operation continuing on %d devices.\n",
+ printk(KERN_ALERT
+ "md/raid10:%s: Disk failure on %s, disabling device.\n"
+ "md/raid10:%s: Operation continuing on %d devices.\n",
mdname(mddev), bdevname(rdev->bdev, b),
mdname(mddev), conf->raid_disks - mddev->degraded);
}
@@ -1559,9 +1560,9 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
rcu_read_unlock();
success = sync_page_io(rdev,
r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
+ sect,
s<<9,
- conf->tmppage, READ);
+ conf->tmppage, READ, false);
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
if (success)
@@ -1598,8 +1599,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
atomic_add(s, &rdev->corrected_errors);
if (sync_page_io(rdev,
r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
- s<<9, conf->tmppage, WRITE)
+ sect,
+ s<<9, conf->tmppage, WRITE, false)
== 0) {
/* Well, this device is dead */
printk(KERN_NOTICE
@@ -1635,9 +1636,9 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
rcu_read_unlock();
if (sync_page_io(rdev,
r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
+ sect,
s<<9, conf->tmppage,
- READ) == 0) {
+ READ, false) == 0) {
/* Well, this device is dead */
printk(KERN_NOTICE
"md/raid10:%s: unable to read back "
@@ -2397,13 +2398,13 @@ static int run(mddev_t *mddev)
return 0;
out_free_conf:
+ md_unregister_thread(mddev->thread);
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
safe_put_page(conf->tmppage);
kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
- md_unregister_thread(mddev->thread);
out:
return -EIO;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index dc574f303f8b..5044babfcda0 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1721,7 +1721,6 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
set_bit(Faulty, &rdev->flags);
printk(KERN_ALERT
"md/raid:%s: Disk failure on %s, disabling device.\n"
- KERN_ALERT
"md/raid:%s: Operation continuing on %d devices.\n",
mdname(mddev),
bdevname(rdev->bdev, b),
@@ -4237,7 +4236,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
wait_event(conf->wait_for_overlap,
atomic_read(&conf->reshape_stripes)==0);
mddev->reshape_position = conf->reshape_progress;
- mddev->curr_resync_completed = mddev->curr_resync;
+ mddev->curr_resync_completed = sector_nr;
conf->reshape_checkpoint = jiffies;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
md_wakeup_thread(mddev->thread);
@@ -4338,7 +4337,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
wait_event(conf->wait_for_overlap,
atomic_read(&conf->reshape_stripes) == 0);
mddev->reshape_position = conf->reshape_progress;
- mddev->curr_resync_completed = mddev->curr_resync + reshape_sectors;
+ mddev->curr_resync_completed = sector_nr;
conf->reshape_checkpoint = jiffies;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
md_wakeup_thread(mddev->thread);
@@ -5339,7 +5338,7 @@ static int raid5_spare_active(mddev_t *mddev)
&& !test_bit(Faulty, &tmp->rdev->flags)
&& !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
count++;
- sysfs_notify_dirent(tmp->rdev->sysfs_state);
+ sysfs_notify_dirent_safe(tmp->rdev->sysfs_state);
}
}
spin_lock_irqsave(&conf->device_lock, flags);
@@ -5528,8 +5527,8 @@ static int raid5_start_reshape(mddev_t *mddev)
return -ENOSPC;
list_for_each_entry(rdev, &mddev->disks, same_set)
- if (rdev->raid_disk < 0 &&
- !test_bit(Faulty, &rdev->flags))
+ if ((rdev->raid_disk < 0 || rdev->raid_disk >= conf->raid_disks)
+ && !test_bit(Faulty, &rdev->flags))
spares++;
if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
@@ -5589,6 +5588,11 @@ static int raid5_start_reshape(mddev_t *mddev)
/* Failure here is OK */;
} else
break;
+ } else if (rdev->raid_disk >= conf->previous_raid_disks
+ && !test_bit(Faulty, &rdev->flags)) {
+ /* This is a spare that was manually added */
+ set_bit(In_sync, &rdev->flags);
+ added_devices++;
}
/* When a reshape changes the number of devices, ->degraded
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
deleted file mode 100644
index db591e421887..000000000000
--- a/drivers/media/IR/ir-functions.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-#include <media/ir-common.h>
-#include "ir-core-priv.h"
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (KEY_RESERVED == ir->keycode) {
- printk(KERN_INFO "%s: unknown key: key=0x%02x down=%d\n",
- dev->name, ir->ir_key, ir->keypressed);
- return;
- }
- IR_dprintk(1,"%s: key event code=%d down=%d\n",
- dev->name,ir->keycode,ir->keypressed);
- input_report_key(dev,ir->keycode,ir->keypressed);
- input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- const u64 ir_type)
-{
- ir->ir_type = ir_type;
-
- if (repeat)
- set_bit(EV_REP, dev->evbit);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_input_init);
-
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (ir->keypressed) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
-}
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
- u32 ir_key)
-{
- u32 keycode = ir_g_keycode_from_table(dev, ir_key);
-
- if (ir->keypressed && ir->keycode != keycode) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
- if (!ir->keypressed) {
- ir->ir_key = ir_key;
- ir->keycode = keycode;
- ir->keypressed = 1;
- ir_input_key_event(dev,ir);
- }
-}
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-/* -------------------------------------------------------------------------- */
-/* extract mask bits out of data and pack them into the result */
-u32 ir_extract_bits(u32 data, u32 mask)
-{
- u32 vbit = 1, value = 0;
-
- do {
- if (mask&1) {
- if (data&1)
- value |= vbit;
- vbit<<=1;
- }
- data>>=1;
- } while (mask>>=1);
-
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-
-static int inline getbit(u32 *samples, int bit)
-{
- return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
- int i, bit, start;
-
- printk(KERN_DEBUG "ir samples: ");
- start = 0;
- for (i = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- start = 1;
- if (0 == start)
- continue;
- printk("%s", bit ? "#" : "_");
- }
- printk("\n");
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len;
- u32 curBit;
- u32 value;
-
- /* find start burst */
- for (i = len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- len++;
- } else {
- if (len >= 29)
- break;
- len = 0;
- }
- }
-
- /* start burst to short */
- if (len < 29)
- return 0xffffffff;
-
- /* find start silence */
- for (len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- break;
- } else {
- len++;
- }
- }
-
- /* silence to short */
- if (len < 7)
- return 0xffffffff;
-
- /* go decoding */
- len = 0;
- last = 1;
- value = 0; curBit = 1;
- for (; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (last) {
- if(bit) {
- continue;
- } else {
- len = 1;
- }
- } else {
- if (bit) {
- if (len > (low + high) /2)
- value |= curBit;
- curBit <<= 1;
- if (curBit == 1)
- break;
- } else {
- len++;
- }
- }
- last = bit;
- }
-
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len,flips;
- u32 value;
-
- /* find start bit (1) */
- for (i = 0; i < 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- break;
- }
-
- /* go decoding */
- len = 0;
- flips = 0;
- value = 1;
- for (; i < count * 32; i++) {
- if (len > high)
- break;
- if (flips > 1)
- break;
- last = bit;
- bit = getbit(samples,i);
- if (last == bit) {
- len++;
- continue;
- }
- if (len < low) {
- len++;
- flips++;
- continue;
- }
- value <<= 1;
- value |= bit;
- flips = 0;
- len = 1;
- }
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-
-/* RC5 decoding stuff, moved from bttv-input.c to share it with
- * saa7134 */
-
-/* decode raw bit pattern to RC5 code */
-u32 ir_rc5_decode(unsigned int code)
-{
- unsigned int org_code = code;
- unsigned int pair;
- unsigned int rc5 = 0;
- int i;
-
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
- IR_dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
- return 0;
- }
- }
- IR_dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
- return rc5;
-}
-EXPORT_SYMBOL_GPL(ir_rc5_decode);
-
-void ir_rc5_timer_end(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
- struct timeval tv;
- unsigned long current_jiffies, timeout;
- u32 gap;
- u32 rc5 = 0;
-
- /* get time */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* signal we're ready to start a new code */
- ir->active = 0;
-
- /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
- if (gap < 28000) {
- IR_dprintk(1, "ir-common: spurious timer_end\n");
- return;
- }
-
- if (ir->last_bit < 20) {
- /* ignore spurious codes (caused by light/other remotes) */
- IR_dprintk(1, "ir-common: short code: %x\n", ir->code);
- } else {
- ir->code = (ir->code << ir->shift_by) | 1;
- rc5 = ir_rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != ir->start) {
- IR_dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == ir->addr) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code, decide if repeat/repress */
- if (toggle != RC5_TOGGLE(ir->last_rc5) ||
- instr != RC5_INSTR(ir->last_rc5)) {
- IR_dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
- toggle);
- ir_input_nokey(ir->dev, &ir->ir);
- ir_input_keydown(ir->dev, &ir->ir, instr);
- }
-
- /* Set/reset key-up timer */
- timeout = current_jiffies +
- msecs_to_jiffies(ir->rc5_key_timeout);
- mod_timer(&ir->timer_keyup, timeout);
-
- /* Save code for repeat test */
- ir->last_rc5 = rc5;
- }
- }
-}
-EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
-
-void ir_rc5_timer_keyup(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
-
- IR_dprintk(1, "ir-common: key released\n");
- ir_input_nokey(ir->dev, &ir->ir);
-}
-EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
deleted file mode 100644
index 9186b45132ed..000000000000
--- a/drivers/media/IR/ir-keytable.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/* ir-keytable.c - handle IR scancode->keycode tables
- *
- * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-
-#include <linux/input.h>
-#include <linux/slab.h>
-#include "ir-core-priv.h"
-
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE 256
-#define IR_TAB_MAX_SIZE 8192
-
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
-
-/**
- * ir_create_table() - initializes a scancode table
- * @rc_tab: the ir_scancode_table to initialize
- * @name: name to assign to the table
- * @ir_type: ir type to assign to the new table
- * @size: initial size of the table
- * @return: zero on success or a negative error code
- *
- * This routine will initialize the ir_scancode_table and will allocate
- * memory to hold at least the specified number elements.
- */
-static int ir_create_table(struct ir_scancode_table *rc_tab,
- const char *name, u64 ir_type, size_t size)
-{
- rc_tab->name = name;
- rc_tab->ir_type = ir_type;
- rc_tab->alloc = roundup_pow_of_two(size * sizeof(struct ir_scancode));
- rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
- rc_tab->scan = kmalloc(rc_tab->alloc, GFP_KERNEL);
- if (!rc_tab->scan)
- return -ENOMEM;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_tab->size, rc_tab->alloc);
- return 0;
-}
-
-/**
- * ir_free_table() - frees memory allocated by a scancode table
- * @rc_tab: the table whose mappings need to be freed
- *
- * This routine will free memory alloctaed for key mappings used by given
- * scancode table.
- */
-static void ir_free_table(struct ir_scancode_table *rc_tab)
-{
- rc_tab->size = 0;
- kfree(rc_tab->scan);
- rc_tab->scan = NULL;
-}
-
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_tab: the ir_scancode_table to resize
- * @gfp_flags: gfp flags to use when allocating memory
- * @return: zero on success or a negative error code
- *
- * This routine will shrink the ir_scancode_table if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct ir_scancode_table *rc_tab, gfp_t gfp_flags)
-{
- unsigned int oldalloc = rc_tab->alloc;
- unsigned int newalloc = oldalloc;
- struct ir_scancode *oldscan = rc_tab->scan;
- struct ir_scancode *newscan;
-
- if (rc_tab->size == rc_tab->len) {
- /* All entries in use -> grow keytable */
- if (rc_tab->alloc >= IR_TAB_MAX_SIZE)
- return -ENOMEM;
-
- newalloc *= 2;
- IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
- }
-
- if ((rc_tab->len * 3 < rc_tab->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
- /* Less than 1/3 of entries in use -> shrink keytable */
- newalloc /= 2;
- IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
- }
-
- if (newalloc == oldalloc)
- return 0;
-
- newscan = kmalloc(newalloc, gfp_flags);
- if (!newscan) {
- IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
- return -ENOMEM;
- }
-
- memcpy(newscan, rc_tab->scan, rc_tab->len * sizeof(struct ir_scancode));
- rc_tab->scan = newscan;
- rc_tab->alloc = newalloc;
- rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
- kfree(oldscan);
- return 0;
-}
-
-/**
- * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @rc_tab: scancode table to be adjusted
- * @index: index of the mapping that needs to be updated
- * @keycode: the desired keycode
- * @return: previous keycode assigned to the mapping
- *
- * This routine is used to update scancode->keycopde mapping at given
- * position.
- */
-static unsigned int ir_update_mapping(struct input_dev *dev,
- struct ir_scancode_table *rc_tab,
- unsigned int index,
- unsigned int new_keycode)
-{
- int old_keycode = rc_tab->scan[index].keycode;
- int i;
-
- /* Did the user wish to remove the mapping? */
- if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- index, rc_tab->scan[index].scancode);
- rc_tab->len--;
- memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1],
- (rc_tab->len - index) * sizeof(struct ir_scancode));
- } else {
- IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
- index,
- old_keycode == KEY_RESERVED ? "New" : "Replacing",
- rc_tab->scan[index].scancode, new_keycode);
- rc_tab->scan[index].keycode = new_keycode;
- __set_bit(new_keycode, dev->keybit);
- }
-
- if (old_keycode != KEY_RESERVED) {
- /* A previous mapping was updated... */
- __clear_bit(old_keycode, dev->keybit);
- /* ... but another scancode might use the same keycode */
- for (i = 0; i < rc_tab->len; i++) {
- if (rc_tab->scan[i].keycode == old_keycode) {
- __set_bit(old_keycode, dev->keybit);
- break;
- }
- }
-
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_tab, GFP_ATOMIC);
- }
-
- return old_keycode;
-}
-
-/**
- * ir_locate_scancode() - set a keycode in the scancode->keycode table
- * @ir_dev: the struct ir_input_dev device descriptor
- * @rc_tab: scancode table to be searched
- * @scancode: the desired scancode
- * @resize: controls whether we allowed to resize the table to
- * accomodate not yet present scancodes
- * @return: index of the mapping containing scancode in question
- * or -1U in case of failure.
- *
- * This routine is used to locate given scancode in ir_scancode_table.
- * If scancode is not yet present the routine will allocate a new slot
- * for it.
- */
-static unsigned int ir_establish_scancode(struct ir_input_dev *ir_dev,
- struct ir_scancode_table *rc_tab,
- unsigned int scancode,
- bool resize)
-{
- unsigned int i;
-
- /*
- * Unfortunately, some hardware-based IR decoders don't provide
- * all bits for the complete IR code. In general, they provide only
- * the command part of the IR code. Yet, as it is possible to replace
- * the provided IR with another one, it is needed to allow loading
- * IR tables from other remotes. So,
- */
- if (ir_dev->props && ir_dev->props->scanmask)
- scancode &= ir_dev->props->scanmask;
-
- /* First check if we already have a mapping for this ir command */
- for (i = 0; i < rc_tab->len; i++) {
- if (rc_tab->scan[i].scancode == scancode)
- return i;
-
- /* Keytable is sorted from lowest to highest scancode */
- if (rc_tab->scan[i].scancode >= scancode)
- break;
- }
-
- /* No previous mapping found, we might need to grow the table */
- if (rc_tab->size == rc_tab->len) {
- if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC))
- return -1U;
- }
-
- /* i is the proper index to insert our new keycode */
- if (i < rc_tab->len)
- memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
- (rc_tab->len - i) * sizeof(struct ir_scancode));
- rc_tab->scan[i].scancode = scancode;
- rc_tab->scan[i].keycode = KEY_RESERVED;
- rc_tab->len++;
-
- return i;
-}
-
-/**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: result
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
- *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
- */
-static int ir_setkeycode(struct input_dev *dev,
- const struct input_keymap_entry *ke,
- unsigned int *old_keycode)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned int index;
- unsigned int scancode;
- int retval;
- unsigned long flags;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
-
- if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
- index = ke->index;
- if (index >= rc_tab->len) {
- retval = -EINVAL;
- goto out;
- }
- } else {
- retval = input_scancode_to_scalar(ke, &scancode);
- if (retval)
- goto out;
-
- index = ir_establish_scancode(ir_dev, rc_tab, scancode, true);
- if (index >= rc_tab->len) {
- retval = -ENOMEM;
- goto out;
- }
- }
-
- *old_keycode = ir_update_mapping(dev, rc_tab, index, ke->keycode);
-
-out:
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- return retval;
-}
-
-/**
- * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @to: the struct ir_scancode_table to copy entries to
- * @from: the struct ir_scancode_table to copy entries from
- * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-static int ir_setkeytable(struct ir_input_dev *ir_dev,
- const struct ir_scancode_table *from)
-{
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned int i, index;
- int rc;
-
- rc = ir_create_table(&ir_dev->rc_tab,
- from->name, from->ir_type, from->size);
- if (rc)
- return rc;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_tab->size, rc_tab->alloc);
-
- for (i = 0; i < from->size; i++) {
- index = ir_establish_scancode(ir_dev, rc_tab,
- from->scan[i].scancode, false);
- if (index >= rc_tab->len) {
- rc = -ENOMEM;
- break;
- }
-
- ir_update_mapping(ir_dev->input_dev, rc_tab, index,
- from->scan[i].keycode);
- }
-
- if (rc)
- ir_free_table(rc_tab);
-
- return rc;
-}
-
-/**
- * ir_lookup_by_scancode() - locate mapping by scancode
- * @rc_tab: the &struct ir_scancode_table to search
- * @scancode: scancode to look for in the table
- * @return: index in the table, -1U if not found
- *
- * This routine performs binary search in RC keykeymap table for
- * given scancode.
- */
-static unsigned int ir_lookup_by_scancode(const struct ir_scancode_table *rc_tab,
- unsigned int scancode)
-{
- unsigned int start = 0;
- unsigned int end = rc_tab->len - 1;
- unsigned int mid;
-
- while (start <= end) {
- mid = (start + end) / 2;
- if (rc_tab->scan[mid].scancode < scancode)
- start = mid + 1;
- else if (rc_tab->scan[mid].scancode > scancode)
- end = mid - 1;
- else
- return mid;
- }
-
- return -1U;
-}
-
-/**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: used to return the keycode, if found, or KEY_RESERVED
- * @return: always returns zero.
- *
- * This routine is used to handle evdev EVIOCGKEY ioctl.
- */
-static int ir_getkeycode(struct input_dev *dev,
- struct input_keymap_entry *ke)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- struct ir_scancode *entry;
- unsigned long flags;
- unsigned int index;
- unsigned int scancode;
- int retval;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
-
- if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
- index = ke->index;
- } else {
- retval = input_scancode_to_scalar(ke, &scancode);
- if (retval)
- goto out;
-
- index = ir_lookup_by_scancode(rc_tab, scancode);
- }
-
- if (index >= rc_tab->len) {
- if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
- IR_dprintk(1, "unknown key for scancode 0x%04x\n",
- scancode);
- retval = -EINVAL;
- goto out;
- }
-
- entry = &rc_tab->scan[index];
-
- ke->index = index;
- ke->keycode = entry->keycode;
- ke->len = sizeof(entry->scancode);
- memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
-
-out:
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- return retval;
-}
-
-/**
- * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @input_dev: the struct input_dev descriptor of the device
- * @scancode: the scancode that we're seeking
- *
- * This routine is used by the input routines when a key is pressed at the
- * IR. The scancode is received and needs to be converted into a keycode.
- * If the key is not found, it returns KEY_RESERVED. Otherwise, returns the
- * corresponding keycode from the table.
- */
-u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned int keycode;
- unsigned int index;
- unsigned long flags;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
-
- index = ir_lookup_by_scancode(rc_tab, scancode);
- keycode = index < rc_tab->len ?
- rc_tab->scan[index].keycode : KEY_RESERVED;
-
- spin_unlock_irqrestore(&rc_tab->lock, flags);
-
- if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
- dev->name, scancode, keycode);
-
- return keycode;
-}
-EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
-
-/**
- * ir_keyup() - generates input event to cleanup a key press
- * @ir: the struct ir_input_dev descriptor of the device
- *
- * This routine is used to signal that a key has been released on the
- * remote control. It reports a keyup input event via input_report_key().
- */
-void ir_keyup(struct ir_input_dev *ir)
-{
- if (!ir->keypressed)
- return;
-
- IR_dprintk(1, "keyup key 0x%04x\n", ir->last_keycode);
- input_report_key(ir->input_dev, ir->last_keycode, 0);
- input_sync(ir->input_dev);
- ir->keypressed = false;
-}
-EXPORT_SYMBOL_GPL(ir_keyup);
-
-/**
- * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie: a pointer to struct ir_input_dev passed to setup_timer()
- *
- * This routine will generate a keyup event some time after a keydown event
- * is generated when no further activity has been detected.
- */
-static void ir_timer_keyup(unsigned long cookie)
-{
- struct ir_input_dev *ir = (struct ir_input_dev *)cookie;
- unsigned long flags;
-
- /*
- * ir->keyup_jiffies is used to prevent a race condition if a
- * hardware interrupt occurs at this point and the keyup timer
- * event is moved further into the future as a result.
- *
- * The timer will then be reactivated and this function called
- * again in the future. We need to exit gracefully in that case
- * to allow the input subsystem to do its auto-repeat magic or
- * a keyup event might follow immediately after the keydown.
- */
- spin_lock_irqsave(&ir->keylock, flags);
- if (time_is_before_eq_jiffies(ir->keyup_jiffies))
- ir_keyup(ir);
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-
-/**
- * ir_repeat() - notifies the IR core that a key is still pressed
- * @dev: the struct input_dev descriptor of the device
- *
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
- */
-void ir_repeat(struct input_dev *dev)
-{
- unsigned long flags;
- struct ir_input_dev *ir = input_get_drvdata(dev);
-
- spin_lock_irqsave(&ir->keylock, flags);
-
- input_event(dev, EV_MSC, MSC_SCAN, ir->last_scancode);
-
- if (!ir->keypressed)
- goto out;
-
- ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
-
-out:
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(ir_repeat);
-
-/**
- * ir_keydown() - generates input event for a key press
- * @dev: the struct input_dev descriptor of the device
- * @scancode: the scancode that we're seeking
- * @toggle: the toggle value (protocol dependent, if the protocol doesn't
- * support toggle values, this should be set to zero)
- *
- * This routine is used by the input routines when a key is pressed at the
- * IR. It gets the keycode for a scancode and reports an input event via
- * input_report_key().
- */
-void ir_keydown(struct input_dev *dev, int scancode, u8 toggle)
-{
- unsigned long flags;
- struct ir_input_dev *ir = input_get_drvdata(dev);
-
- u32 keycode = ir_g_keycode_from_table(dev, scancode);
-
- spin_lock_irqsave(&ir->keylock, flags);
-
- input_event(dev, EV_MSC, MSC_SCAN, scancode);
-
- /* Repeat event? */
- if (ir->keypressed &&
- ir->last_scancode == scancode &&
- ir->last_toggle == toggle)
- goto set_timer;
-
- /* Release old keypress */
- ir_keyup(ir);
-
- ir->last_scancode = scancode;
- ir->last_toggle = toggle;
- ir->last_keycode = keycode;
-
-
- if (keycode == KEY_RESERVED)
- goto out;
-
-
- /* Register a keypress */
- ir->keypressed = true;
- IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
- dev->name, keycode, scancode);
- input_report_key(dev, ir->last_keycode, 1);
- input_sync(dev);
-
-set_timer:
- ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
-out:
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(ir_keydown);
-
-static int ir_open(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- return ir_dev->props->open(ir_dev->props->priv);
-}
-
-static void ir_close(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- ir_dev->props->close(ir_dev->props->priv);
-}
-
-/**
- * __ir_input_register() - sets the IR keycode table and add the handlers
- * for keymap table get/set
- * @input_dev: the struct input_dev descriptor of the device
- * @rc_tab: the struct ir_scancode_table table of scancode/keymap
- *
- * This routine is used to initialize the input infrastructure
- * to work with an IR.
- * It will register the input/evdev interface for the device and
- * register the syfs code for IR class
- */
-int __ir_input_register(struct input_dev *input_dev,
- const struct ir_scancode_table *rc_tab,
- struct ir_dev_props *props,
- const char *driver_name)
-{
- struct ir_input_dev *ir_dev;
- int rc;
-
- if (rc_tab->scan == NULL || !rc_tab->size)
- return -EINVAL;
-
- ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL);
- if (!ir_dev)
- return -ENOMEM;
-
- ir_dev->driver_name = kasprintf(GFP_KERNEL, "%s", driver_name);
- if (!ir_dev->driver_name) {
- rc = -ENOMEM;
- goto out_dev;
- }
-
- input_dev->getkeycode_new = ir_getkeycode;
- input_dev->setkeycode_new = ir_setkeycode;
- input_set_drvdata(input_dev, ir_dev);
- ir_dev->input_dev = input_dev;
-
- spin_lock_init(&ir_dev->rc_tab.lock);
- spin_lock_init(&ir_dev->keylock);
- setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
-
- if (props) {
- ir_dev->props = props;
- if (props->open)
- input_dev->open = ir_open;
- if (props->close)
- input_dev->close = ir_close;
- }
-
- set_bit(EV_KEY, input_dev->evbit);
- set_bit(EV_REP, input_dev->evbit);
- set_bit(EV_MSC, input_dev->evbit);
- set_bit(MSC_SCAN, input_dev->mscbit);
-
- rc = ir_setkeytable(ir_dev, rc_tab);
- if (rc)
- goto out_name;
-
- rc = ir_register_class(input_dev);
- if (rc < 0)
- goto out_table;
-
- if (ir_dev->props)
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
- rc = ir_raw_event_register(input_dev);
- if (rc < 0)
- goto out_event;
- }
-
- rc = ir_register_input(input_dev);
- if (rc < 0)
- goto out_event;
-
- IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
- driver_name, rc_tab->name,
- (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
- " in raw mode" : "");
-
- /*
- * Default delay of 250ms is too short for some protocols, expecially
- * since the timeout is currently set to 250ms. Increase it to 500ms,
- * to avoid wrong repetition of the keycodes.
- */
- input_dev->rep[REP_DELAY] = 500;
-
- return 0;
-
-out_event:
- ir_unregister_class(input_dev);
-out_table:
- ir_free_table(&ir_dev->rc_tab);
-out_name:
- kfree(ir_dev->driver_name);
-out_dev:
- kfree(ir_dev);
- return rc;
-}
-EXPORT_SYMBOL_GPL(__ir_input_register);
-
-/**
- * ir_input_unregister() - unregisters IR and frees resources
- * @input_dev: the struct input_dev descriptor of the device
-
- * This routine is used to free memory and de-register interfaces.
- */
-void ir_input_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- if (!ir_dev)
- return;
-
- IR_dprintk(1, "Freed keycode table\n");
-
- del_timer_sync(&ir_dev->timer_keyup);
- if (ir_dev->props)
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
- ir_raw_event_unregister(input_dev);
-
- ir_free_table(&ir_dev->rc_tab);
-
- ir_unregister_class(input_dev);
-
- kfree(ir_dev->driver_name);
- kfree(ir_dev);
-}
-EXPORT_SYMBOL_GPL(ir_input_unregister);
-
-int ir_core_debug; /* ir_debug level (0,1,2) */
-EXPORT_SYMBOL_GPL(ir_core_debug);
-module_param_named(debug, ir_core_debug, int, 0644);
-
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
deleted file mode 100644
index 38423a8da871..000000000000
--- a/drivers/media/IR/ir-sysfs.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/* ir-sysfs.c - sysfs interface for RC devices (/sys/class/rc)
- *
- * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/device.h>
-#include "ir-core-priv.h"
-
-#define IRRCV_NUM_DEVICES 256
-
-/* bit array to represent IR sysfs device number */
-static unsigned long ir_core_dev_number;
-
-/* class for /sys/class/rc */
-static char *ir_devnode(struct device *dev, mode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
-}
-
-static struct class ir_input_class = {
- .name = "rc",
- .devnode = ir_devnode,
-};
-
-static struct {
- u64 type;
- char *name;
-} proto_names[] = {
- { IR_TYPE_UNKNOWN, "unknown" },
- { IR_TYPE_RC5, "rc-5" },
- { IR_TYPE_NEC, "nec" },
- { IR_TYPE_RC6, "rc-6" },
- { IR_TYPE_JVC, "jvc" },
- { IR_TYPE_SONY, "sony" },
- { IR_TYPE_RC5_SZ, "rc-5-sz" },
- { IR_TYPE_LIRC, "lirc" },
-};
-
-#define PROTO_NONE "none"
-
-/**
- * show_protocols() - shows the current IR protocol(s)
- * @d: the device descriptor
- * @mattr: the device attribute struct (unused)
- * @buf: a pointer to the output buffer
- *
- * This routine is a callback routine for input read the IR protocol type(s).
- * it is trigged by reading /sys/class/rc/rc?/protocols.
- * It returns the protocol names of supported protocols.
- * Enabled protocols are printed in brackets.
- */
-static ssize_t show_protocols(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- u64 allowed, enabled;
- char *tmp = buf;
- int i;
-
- /* Device is being removed */
- if (!ir_dev)
- return -EINVAL;
-
- if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
- enabled = ir_dev->rc_tab.ir_type;
- allowed = ir_dev->props->allowed_protos;
- } else if (ir_dev->raw) {
- enabled = ir_dev->raw->enabled_protocols;
- allowed = ir_raw_get_allowed_protocols();
- } else
- return sprintf(tmp, "[builtin]\n");
-
- IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
- (long long)allowed,
- (long long)enabled);
-
- for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
- if (allowed & enabled & proto_names[i].type)
- tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
- else if (allowed & proto_names[i].type)
- tmp += sprintf(tmp, "%s ", proto_names[i].name);
- }
-
- if (tmp != buf)
- tmp--;
- *tmp = '\n';
- return tmp + 1 - buf;
-}
-
-/**
- * store_protocols() - changes the current IR protocol(s)
- * @d: the device descriptor
- * @mattr: the device attribute struct (unused)
- * @buf: a pointer to the input buffer
- * @len: length of the input buffer
- *
- * This routine is a callback routine for changing the IR protocol type.
- * It is trigged by writing to /sys/class/rc/rc?/protocols.
- * Writing "+proto" will add a protocol to the list of enabled protocols.
- * Writing "-proto" will remove a protocol from the list of enabled protocols.
- * Writing "proto" will enable only "proto".
- * Writing "none" will disable all protocols.
- * Returns -EINVAL if an invalid protocol combination or unknown protocol name
- * is used, otherwise @len.
- */
-static ssize_t store_protocols(struct device *d,
- struct device_attribute *mattr,
- const char *data,
- size_t len)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- bool enable, disable;
- const char *tmp;
- u64 type;
- u64 mask;
- int rc, i, count = 0;
- unsigned long flags;
-
- /* Device is being removed */
- if (!ir_dev)
- return -EINVAL;
-
- if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
- type = ir_dev->rc_tab.ir_type;
- else if (ir_dev->raw)
- type = ir_dev->raw->enabled_protocols;
- else {
- IR_dprintk(1, "Protocol switching not supported\n");
- return -EINVAL;
- }
-
- while ((tmp = strsep((char **) &data, " \n")) != NULL) {
- if (!*tmp)
- break;
-
- if (*tmp == '+') {
- enable = true;
- disable = false;
- tmp++;
- } else if (*tmp == '-') {
- enable = false;
- disable = true;
- tmp++;
- } else {
- enable = false;
- disable = false;
- }
-
- if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
- tmp += sizeof(PROTO_NONE);
- mask = 0;
- count++;
- } else {
- for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
- if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
- tmp += strlen(proto_names[i].name);
- mask = proto_names[i].type;
- break;
- }
- }
- if (i == ARRAY_SIZE(proto_names)) {
- IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
- return -EINVAL;
- }
- count++;
- }
-
- if (enable)
- type |= mask;
- else if (disable)
- type &= ~mask;
- else
- type = mask;
- }
-
- if (!count) {
- IR_dprintk(1, "Protocol not specified\n");
- return -EINVAL;
- }
-
- if (ir_dev->props && ir_dev->props->change_protocol) {
- rc = ir_dev->props->change_protocol(ir_dev->props->priv,
- type);
- if (rc < 0) {
- IR_dprintk(1, "Error setting protocols to 0x%llx\n",
- (long long)type);
- return -EINVAL;
- }
- }
-
- if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
- ir_dev->rc_tab.ir_type = type;
- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
- } else {
- ir_dev->raw->enabled_protocols = type;
- }
-
- IR_dprintk(1, "Current protocol(s): 0x%llx\n",
- (long long)type);
-
- return len;
-}
-
-#define ADD_HOTPLUG_VAR(fmt, val...) \
- do { \
- int err = add_uevent_var(env, fmt, val); \
- if (err) \
- return err; \
- } while (0)
-
-static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(device);
-
- if (ir_dev->rc_tab.name)
- ADD_HOTPLUG_VAR("NAME=%s", ir_dev->rc_tab.name);
- if (ir_dev->driver_name)
- ADD_HOTPLUG_VAR("DRV_NAME=%s", ir_dev->driver_name);
-
- return 0;
-}
-
-/*
- * Static device attribute struct with the sysfs attributes for IR's
- */
-static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
- show_protocols, store_protocols);
-
-static struct attribute *rc_dev_attrs[] = {
- &dev_attr_protocols.attr,
- NULL,
-};
-
-static struct attribute_group rc_dev_attr_grp = {
- .attrs = rc_dev_attrs,
-};
-
-static const struct attribute_group *rc_dev_attr_groups[] = {
- &rc_dev_attr_grp,
- NULL
-};
-
-static struct device_type rc_dev_type = {
- .groups = rc_dev_attr_groups,
- .uevent = rc_dev_uevent,
-};
-
-/**
- * ir_register_class() - creates the sysfs for /sys/class/rc/rc?
- * @input_dev: the struct input_dev descriptor of the device
- *
- * This routine is used to register the syfs code for IR class
- */
-int ir_register_class(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- int devno = find_first_zero_bit(&ir_core_dev_number,
- IRRCV_NUM_DEVICES);
-
- if (unlikely(devno < 0))
- return devno;
-
- ir_dev->dev.type = &rc_dev_type;
- ir_dev->devno = devno;
-
- ir_dev->dev.class = &ir_input_class;
- ir_dev->dev.parent = input_dev->dev.parent;
- input_dev->dev.parent = &ir_dev->dev;
- dev_set_name(&ir_dev->dev, "rc%d", devno);
- dev_set_drvdata(&ir_dev->dev, ir_dev);
- return device_register(&ir_dev->dev);
-};
-
-/**
- * ir_register_input - registers ir input device with input subsystem
- * @input_dev: the struct input_dev descriptor of the device
- */
-
-int ir_register_input(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- int rc;
- const char *path;
-
-
- rc = input_register_device(input_dev);
- if (rc < 0) {
- device_del(&ir_dev->dev);
- return rc;
- }
-
- __module_get(THIS_MODULE);
-
- path = kobject_get_path(&ir_dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "%s: %s as %s\n",
- dev_name(&ir_dev->dev),
- input_dev->name ? input_dev->name : "Unspecified device",
- path ? path : "N/A");
- kfree(path);
-
- set_bit(ir_dev->devno, &ir_core_dev_number);
- return 0;
-}
-
-/**
- * ir_unregister_class() - removes the sysfs for sysfs for
- * /sys/class/rc/rc?
- * @input_dev: the struct input_dev descriptor of the device
- *
- * This routine is used to unregister the syfs code for IR class
- */
-void ir_unregister_class(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- input_set_drvdata(input_dev, NULL);
- clear_bit(ir_dev->devno, &ir_core_dev_number);
- input_unregister_device(input_dev);
- device_del(&ir_dev->dev);
-
- module_put(THIS_MODULE);
-}
-
-/*
- * Init/exit code for the module. Basically, creates/removes /sys/class/rc
- */
-
-static int __init ir_core_init(void)
-{
- int rc = class_register(&ir_input_class);
- if (rc) {
- printk(KERN_ERR "ir_core: unable to register rc class\n");
- return rc;
- }
-
- /* Initialize/load the decoders/keymap code that will be used */
- ir_raw_init();
- ir_rcmap_init();
-
- return 0;
-}
-
-static void __exit ir_core_exit(void)
-{
- class_unregister(&ir_input_class);
- ir_rcmap_cleanup();
-}
-
-module_init(ir_core_init);
-module_exit(ir_core_exit);
diff --git a/drivers/media/IR/keymaps/rc-tbs-nec.c b/drivers/media/IR/keymaps/rc-tbs-nec.c
deleted file mode 100644
index 3309631e6f80..000000000000
--- a/drivers/media/IR/keymaps/rc-tbs-nec.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* tbs-nec.h - Keytable for tbs_nec Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-static struct ir_scancode tbs_nec[] = {
- { 0x04, KEY_POWER2}, /*power*/
- { 0x14, KEY_MUTE}, /*mute*/
- { 0x07, KEY_1},
- { 0x06, KEY_2},
- { 0x05, KEY_3},
- { 0x0b, KEY_4},
- { 0x0a, KEY_5},
- { 0x09, KEY_6},
- { 0x0f, KEY_7},
- { 0x0e, KEY_8},
- { 0x0d, KEY_9},
- { 0x12, KEY_0},
- { 0x16, KEY_CHANNELUP}, /*ch+*/
- { 0x11, KEY_CHANNELDOWN},/*ch-*/
- { 0x13, KEY_VOLUMEUP}, /*vol+*/
- { 0x0c, KEY_VOLUMEDOWN},/*vol-*/
- { 0x03, KEY_RECORD}, /*rec*/
- { 0x18, KEY_PAUSE}, /*pause*/
- { 0x19, KEY_OK}, /*ok*/
- { 0x1a, KEY_CAMERA}, /* snapshot */
- { 0x01, KEY_UP},
- { 0x10, KEY_LEFT},
- { 0x02, KEY_RIGHT},
- { 0x08, KEY_DOWN},
- { 0x15, KEY_FAVORITES},
- { 0x17, KEY_SUBTITLE},
- { 0x1d, KEY_ZOOM},
- { 0x1f, KEY_EXIT},
- { 0x1e, KEY_MENU},
- { 0x1c, KEY_EPG},
- { 0x00, KEY_PREVIOUS},
- { 0x1b, KEY_MODE},
-};
-
-static struct rc_keymap tbs_nec_map = {
- .map = {
- .scan = tbs_nec,
- .size = ARRAY_SIZE(tbs_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_TBS_NEC,
- }
-};
-
-static int __init init_rc_map_tbs_nec(void)
-{
- return ir_register_map(&tbs_nec_map);
-}
-
-static void __exit exit_rc_map_tbs_nec(void)
-{
- ir_unregister_map(&tbs_nec_map);
-}
-
-module_init(init_rc_map_tbs_nec)
-module_exit(exit_rc_map_tbs_nec)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tt-1500.c b/drivers/media/IR/keymaps/rc-tt-1500.c
deleted file mode 100644
index bc88de011d5d..000000000000
--- a/drivers/media/IR/keymaps/rc-tt-1500.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* tt-1500.h - Keytable for tt_1500 Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/* for the Technotrend 1500 bundled remotes (grey and black): */
-
-static struct ir_scancode tt_1500[] = {
- { 0x01, KEY_POWER },
- { 0x02, KEY_SHUFFLE }, /* ? double-arrow key */
- { 0x03, KEY_1 },
- { 0x04, KEY_2 },
- { 0x05, KEY_3 },
- { 0x06, KEY_4 },
- { 0x07, KEY_5 },
- { 0x08, KEY_6 },
- { 0x09, KEY_7 },
- { 0x0a, KEY_8 },
- { 0x0b, KEY_9 },
- { 0x0c, KEY_0 },
- { 0x0d, KEY_UP },
- { 0x0e, KEY_LEFT },
- { 0x0f, KEY_OK },
- { 0x10, KEY_RIGHT },
- { 0x11, KEY_DOWN },
- { 0x12, KEY_INFO },
- { 0x13, KEY_EXIT },
- { 0x14, KEY_RED },
- { 0x15, KEY_GREEN },
- { 0x16, KEY_YELLOW },
- { 0x17, KEY_BLUE },
- { 0x18, KEY_MUTE },
- { 0x19, KEY_TEXT },
- { 0x1a, KEY_MODE }, /* ? TV/Radio */
- { 0x21, KEY_OPTION },
- { 0x22, KEY_EPG },
- { 0x23, KEY_CHANNELUP },
- { 0x24, KEY_CHANNELDOWN },
- { 0x25, KEY_VOLUMEUP },
- { 0x26, KEY_VOLUMEDOWN },
- { 0x27, KEY_SETUP },
- { 0x3a, KEY_RECORD }, /* these keys are only in the black remote */
- { 0x3b, KEY_PLAY },
- { 0x3c, KEY_STOP },
- { 0x3d, KEY_REWIND },
- { 0x3e, KEY_PAUSE },
- { 0x3f, KEY_FORWARD },
-};
-
-static struct rc_keymap tt_1500_map = {
- .map = {
- .scan = tt_1500,
- .size = ARRAY_SIZE(tt_1500),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_TT_1500,
- }
-};
-
-static int __init init_rc_map_tt_1500(void)
-{
- return ir_register_map(&tt_1500_map);
-}
-
-static void __exit exit_rc_map_tt_1500(void)
-{
- ir_unregister_map(&tt_1500_map);
-}
-
-module_init(init_rc_map_tt_1500)
-module_exit(exit_rc_map_tt_1500)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/rc-map.c b/drivers/media/IR/rc-map.c
deleted file mode 100644
index 689143f2fff0..000000000000
--- a/drivers/media/IR/rc-map.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ir-raw-event.c - handle IR Pulse/Space event
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <media/ir-core.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-
-/* Used to handle IR raw handler extensions */
-static LIST_HEAD(rc_map_list);
-static DEFINE_SPINLOCK(rc_map_lock);
-
-static struct rc_keymap *seek_rc_map(const char *name)
-{
- struct rc_keymap *map = NULL;
-
- spin_lock(&rc_map_lock);
- list_for_each_entry(map, &rc_map_list, list) {
- if (!strcmp(name, map->map.name)) {
- spin_unlock(&rc_map_lock);
- return map;
- }
- }
- spin_unlock(&rc_map_lock);
-
- return NULL;
-}
-
-struct ir_scancode_table *get_rc_map(const char *name)
-{
-
- struct rc_keymap *map;
-
- map = seek_rc_map(name);
-#ifdef MODULE
- if (!map) {
- int rc = request_module(name);
- if (rc < 0) {
- printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
- return NULL;
- }
- msleep(20); /* Give some time for IR to register */
-
- map = seek_rc_map(name);
- }
-#endif
- if (!map) {
- printk(KERN_ERR "IR keymap %s not found\n", name);
- return NULL;
- }
-
- printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
-
- return &map->map;
-}
-EXPORT_SYMBOL_GPL(get_rc_map);
-
-int ir_register_map(struct rc_keymap *map)
-{
- spin_lock(&rc_map_lock);
- list_add_tail(&map->list, &rc_map_list);
- spin_unlock(&rc_map_lock);
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_register_map);
-
-void ir_unregister_map(struct rc_keymap *map)
-{
- spin_lock(&rc_map_lock);
- list_del(&map->list);
- spin_unlock(&rc_map_lock);
-}
-EXPORT_SYMBOL_GPL(ir_unregister_map);
-
-
-static struct ir_scancode empty[] = {
- { 0x2a, KEY_COFFEE },
-};
-
-static struct rc_keymap empty_map = {
- .map = {
- .scan = empty,
- .size = ARRAY_SIZE(empty),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_EMPTY,
- }
-};
-
-int ir_rcmap_init(void)
-{
- return ir_register_map(&empty_map);
-}
-
-void ir_rcmap_cleanup(void)
-{
- ir_unregister_map(&empty_map);
-}
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index bad2cedb8d96..81b3ba83cc65 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -19,7 +19,6 @@ comment "Multimedia core support"
config VIDEO_DEV
tristate "Video For Linux"
- depends on BKL # used in many drivers for ioctl handling, need to kill
---help---
V4L core support for video capture and overlay devices, webcams and
AM/FM radio cards.
@@ -41,35 +40,6 @@ config VIDEO_V4L2_COMMON
depends on (I2C || I2C=n) && VIDEO_DEV
default (I2C || I2C=n) && VIDEO_DEV
-config VIDEO_ALLOW_V4L1
- bool "Enable Video For Linux API 1 (DEPRECATED)"
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON
- default VIDEO_DEV && VIDEO_V4L2_COMMON
- ---help---
- Enables drivers based on the legacy V4L1 API.
-
- This api were developed to be used at Kernel 2.2 and 2.4, but
- lacks support for several video standards. There are several
- drivers at kernel that still depends on it.
-
- If you are unsure as to whether this is required, answer Y.
-
-config VIDEO_V4L1_COMPAT
- bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1
- depends on VIDEO_DEV
- default y
- ---help---
- Enables a compatibility API used by most V4L2 devices to allow
- its usage with legacy applications that supports only V4L1 api.
-
- Documentation for the original API is included in the file
- <Documentation/video4linux/API.html>.
-
- User tools for this are available from
- <ftp://ftp.uk.linux.org/pub/linux/video4linux/>.
-
- If you are unsure as to whether this is required, answer Y.
-
#
# DVB Core
#
@@ -100,7 +70,7 @@ config VIDEO_MEDIA
comment "Multimedia drivers"
source "drivers/media/common/Kconfig"
-source "drivers/media/IR/Kconfig"
+source "drivers/media/rc/Kconfig"
#
# Tuner drivers for DVB and V4L
@@ -122,26 +92,4 @@ source "drivers/media/radio/Kconfig"
source "drivers/media/dvb/Kconfig"
-config DAB
- boolean "DAB adapters"
- ---help---
- Allow selecting support for Digital Audio Broadcasting (DAB)
- Receiver adapters.
-
-if DAB
-config USB_DABUSB
- tristate "DABUSB driver"
- depends on USB
- ---help---
- A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
- brought to you by the DAB-Team
- <http://wwwbode.cs.tum.edu/Par/arch/dab/>. This driver can be taken
- as an example for URB-based bulk, control, and isochronous
- transactions. URB's are explained in
- <Documentation/usb/URB.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called dabusb.
-endif # DAB
-
endif # MEDIA_SUPPORT
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 499b0810d019..b603ea645ede 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y += common/ IR/ video/
+obj-y += common/ rc/ video/
obj-$(CONFIG_VIDEO_DEV) += radio/
obj-$(CONFIG_DVB_CORE) += dvb/
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 05bde9ccb770..1d1d8d200755 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -558,7 +558,7 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
{
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline;
@@ -702,7 +702,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_video_dma vdma1;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -827,7 +827,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
struct saa7146_video_dma vdma2;
struct saa7146_video_dma vdma3;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -994,7 +994,7 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
struct saa7146_vv *vv = dev->vv_data;
u32 vdma1_prot_addr;
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 3d88542612ea..74ee172b5bc9 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -391,7 +391,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
/*****************************************************************************/
/* i2c-adapter helper functions */
-#include <linux/i2c-id.h>
/* exported algorithm data */
static struct i2c_algorithm saa7146_algo = {
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 741c5732b430..0ac5c619aecf 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -84,7 +84,7 @@ static struct saa7146_format formats[] = {
static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
-struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
{
int i, j = NUM_FORMATS;
@@ -266,7 +266,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
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);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -408,7 +408,7 @@ static int video_begin(struct saa7146_fh *fh)
}
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -460,7 +460,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
return -EBUSY;
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -536,7 +536,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
return -EPERM;
/* check args */
- fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
@@ -760,7 +760,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
- fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
@@ -1129,35 +1129,6 @@ static int vidioc_g_chip_ident(struct file *file, void *__fh,
core, g_chip_ident, chip);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
-{
- struct saa7146_fh *fh = __fh;
- struct videobuf_queue *q = &fh->video_q;
- int err, i;
-
- /* fixme: number of capture buffers and sizes for v4l apps */
- int gbuffers = 2;
- int gbufsize = 768 * 576 * 4;
-
- DEB_D(("VIDIOCGMBUF \n"));
-
- q = &fh->video_q;
- err = videobuf_mmap_setup(q, gbuffers, gbufsize,
- V4L2_MEMORY_MMAP);
- if (err < 0)
- return err;
-
- gbuffers = err;
- memset(mbuf, 0, sizeof(*mbuf));
- mbuf->frames = gbuffers;
- mbuf->size = gbuffers * gbufsize;
- for (i = 0; i < gbuffers; i++)
- mbuf->offsets[i] = i * gbufsize;
- return 0;
-}
-#endif
-
const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
@@ -1186,9 +1157,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
/*********************************************************************************/
@@ -1264,7 +1232,7 @@ static int buffer_prepare(struct videobuf_queue *q,
buf->fmt = &fh->video_fmt;
buf->vb.field = fh->video_fmt.field;
- sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
release_all_pagetables(dev, buf);
if( 0 != IS_PLANAR(sfmt->trans)) {
@@ -1378,7 +1346,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
fh->video_fmt.bytesperline = 0;
fh->video_fmt.field = V4L2_FIELD_ANY;
- sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ sfmt = saa7146_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_sg_init(&fh->video_q, &video_qops,
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 2385e6cca635..78b089526e02 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -31,7 +31,7 @@ config MEDIA_TUNER
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-menuconfig MEDIA_TUNER_CUSTOMISE
+config MEDIA_TUNER_CUSTOMISE
bool "Customize analog and hybrid tuner modules to build"
depends on MEDIA_TUNER
default y if EMBEDDED
@@ -44,7 +44,8 @@ menuconfig MEDIA_TUNER_CUSTOMISE
If unsure say N.
-if MEDIA_TUNER_CUSTOMISE
+menu "Customize TV tuners"
+ visible if MEDIA_TUNER_CUSTOMISE
config MEDIA_TUNER_SIMPLE
tristate "Simple tuner support"
@@ -185,5 +186,4 @@ config MEDIA_TUNER_TDA18218
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
-
-endif # MEDIA_TUNER_CUSTOMISE
+endmenu
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
index 937e4b00d7ee..9883617b7862 100644
--- a/drivers/media/common/tuners/max2165.c
+++ b/drivers/media/common/tuners/max2165.c
@@ -52,13 +52,12 @@ static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
msg.addr = priv->config->i2c_address;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg, 1);
if (ret != 1)
- dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
__func__, reg, data, ret);
return (ret != 1) ? -EIO : 0;
@@ -78,14 +77,13 @@ static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret != 2) {
- dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
return -EIO;
}
*p_data = b1[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
+ dprintk("%s: reg=0x%02X, data=0x%02X\n",
__func__, reg, b1[0]);
return 0;
}
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
index 8da1fdeddaa7..aacfe2387e28 100644
--- a/drivers/media/common/tuners/tda18218.c
+++ b/drivers/media/common/tuners/tda18218.c
@@ -28,7 +28,7 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
/* write multiple registers */
static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
{
- int ret;
+ int ret = 0;
u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
struct i2c_msg msg[1] = {
{
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
index a6ceb08f1183..f3de0a4d63f2 100644
--- a/drivers/media/dvb/dm1105/Kconfig
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -1,7 +1,6 @@
config DVB_DM1105
tristate "SDMC DM1105 based PCI cards"
depends on DVB_CORE && PCI && I2C
- depends on INPUT
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
@@ -9,7 +8,7 @@ config DVB_DM1105
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE
- depends on VIDEO_IR
+ depends on RC_CORE
help
Support for cards based on the SDMC DM1105 PCI chip like
DvbWorld 2002
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index 5d404f1bf036..2d8b4044be36 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -26,9 +26,8 @@
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
-#include <linux/input.h>
#include <linux/slab.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "demux.h"
#include "dmxdev.h"
@@ -266,7 +265,7 @@ static void dm1105_card_list(struct pci_dev *pci)
/* infrared remote control */
struct infrared {
- struct input_dev *input_dev;
+ struct rc_dev *dev;
char input_phys[32];
struct work_struct work;
u32 ir_command;
@@ -532,7 +531,7 @@ static void dm1105_emit_key(struct work_struct *work)
data = (ircom >> 8) & 0x7f;
- ir_keydown(ir->input_dev, data, 0);
+ rc_keydown(ir->dev, data, 0);
}
/* work handler */
@@ -593,46 +592,47 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id)
int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
{
- struct input_dev *input_dev;
- char *ir_codes = RC_MAP_DM1105_NEC;
+ struct rc_dev *dev;
int err = -ENOMEM;
- input_dev = input_allocate_device();
- if (!input_dev)
+ dev = rc_allocate_device();
+ if (!dev)
return -ENOMEM;
- dm1105->ir.input_dev = input_dev;
snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
"pci-%s/ir0", pci_name(dm1105->pdev));
- input_dev->name = "DVB on-card IR receiver";
- input_dev->phys = dm1105->ir.input_phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->map_name = RC_MAP_DM1105_NEC;
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ dev->input_name = "DVB on-card IR receiver";
+ dev->input_phys = dm1105->ir.input_phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
if (dm1105->pdev->subsystem_vendor) {
- input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
- input_dev->id.product = dm1105->pdev->subsystem_device;
+ dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
+ dev->input_id.product = dm1105->pdev->subsystem_device;
} else {
- input_dev->id.vendor = dm1105->pdev->vendor;
- input_dev->id.product = dm1105->pdev->device;
+ dev->input_id.vendor = dm1105->pdev->vendor;
+ dev->input_id.product = dm1105->pdev->device;
}
-
- input_dev->dev.parent = &dm1105->pdev->dev;
+ dev->dev.parent = &dm1105->pdev->dev;
INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
- err = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(dev);
if (err < 0) {
- input_free_device(input_dev);
+ rc_free_device(dev);
return err;
}
+ dm1105->ir.dev = dev;
return 0;
}
void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
{
- ir_input_unregister(dm1105->ir.input_dev);
+ rc_unregister_device(dm1105->ir.dev);
}
static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index ad1f61d301e1..e4b5c03ae516 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -572,13 +572,13 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
dmx_output_t otype;
int ret;
int ts_type;
- enum dmx_ts_pes ts_pes;
+ dmx_pes_type_t ts_pes;
struct dmx_ts_feed *tsfeed;
feed->ts = NULL;
otype = para->output;
- ts_pes = (enum dmx_ts_pes)para->pes_type;
+ ts_pes = para->pes_type;
if (ts_pes < DMX_PES_OTHER)
ts_type = TS_DECODER;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 4d0646da6087..7ea517b7e186 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 1589d5a5cb46..cad6634610ea 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -36,7 +36,6 @@
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <asm/processor.h>
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4df42aaae7f7..51752a9ef7a4 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
return -EBUSY;
dvb_net_stop(net);
- flush_scheduled_work();
+ flush_work_sync(&priv->set_multicast_list_wq);
+ flush_work_sync(&priv->restart_net_feed_wq);
printk("dvb_net: removed network interface %s\n", net->name);
unregister_netdev(net);
dvbnet->state[num]=0;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 2525d3b3c88d..3d48ba019342 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB && I2C && IR_CORE
+ depends on DVB_CORE && USB && I2C && RC_CORE
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index a5c363727133..53b93a4b6f8a 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -37,7 +37,7 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
return 0;
}
-static struct ir_scancode ir_codes_a800_table[] = {
+static struct rc_map_table rc_map_a800_table[] = {
{ 0x0201, KEY_PROG1 }, /* SOURCE */
{ 0x0200, KEY_POWER }, /* POWER */
{ 0x0205, KEY_1 }, /* 1 */
@@ -148,8 +148,8 @@ static struct dvb_usb_device_properties a800_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_a800_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_a800_table),
+ .rc_map_table = rc_map_a800_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_a800_table),
.rc_query = a800_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index 696207fe37ec..c3bc64ed405c 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug,
#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
-struct ir_scancode ir_codes_af9005_table[] = {
+struct rc_map_table rc_map_af9005_table[] = {
{0x01b7, KEY_POWER},
{0x01a7, KEY_VOLUMEUP},
@@ -74,7 +74,7 @@ struct ir_scancode ir_codes_af9005_table[] = {
{0x00d5, KEY_GOTO}, /* marked jump on the remote */
};
-int ir_codes_af9005_table_size = ARRAY_SIZE(ir_codes_af9005_table);
+int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
static int repeatable_keys[] = {
KEY_VOLUMEUP,
@@ -130,10 +130,10 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
deb_decode("code != inverted code\n");
return 0;
}
- for (i = 0; i < ir_codes_af9005_table_size; i++) {
- if (rc5_custom(&ir_codes_af9005_table[i]) == cust
- && rc5_data(&ir_codes_af9005_table[i]) == dat) {
- *event = ir_codes_af9005_table[i].keycode;
+ for (i = 0; i < rc_map_af9005_table_size; i++) {
+ if (rc5_custom(&rc_map_af9005_table[i]) == cust
+ && rc5_data(&rc_map_af9005_table[i]) == dat) {
+ *event = rc_map_af9005_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
deb_decode
("key pressed, event %x\n", *event);
@@ -146,8 +146,8 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
return 0;
}
-EXPORT_SYMBOL(ir_codes_af9005_table);
-EXPORT_SYMBOL(ir_codes_af9005_table_size);
+EXPORT_SYMBOL(rc_map_af9005_table);
+EXPORT_SYMBOL(rc_map_af9005_table_size);
EXPORT_SYMBOL(af9005_rc_decode);
MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index 8ecba8848bcf..51f6439dcfd5 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -1027,8 +1027,8 @@ static struct dvb_usb_device_properties af9005_properties = {
.rc.legacy = {
.rc_interval = 200,
- .rc_key_map = NULL,
- .rc_key_map_size = 0,
+ .rc_map_table = NULL,
+ .rc_map_size = 0,
.rc_query = af9005_rc_query,
},
@@ -1070,14 +1070,14 @@ static int __init af9005_usb_module_init(void)
return result;
}
rc_decode = symbol_request(af9005_rc_decode);
- rc_keys = symbol_request(ir_codes_af9005_table);
- rc_keys_size = symbol_request(ir_codes_af9005_table_size);
+ rc_keys = symbol_request(rc_map_af9005_table);
+ rc_keys_size = symbol_request(rc_map_af9005_table_size);
if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
err("af9005_rc_decode function not found, disabling remote");
af9005_properties.rc.legacy.rc_query = NULL;
} else {
- af9005_properties.rc.legacy.rc_key_map = rc_keys;
- af9005_properties.rc.legacy.rc_key_map_size = *rc_keys_size;
+ af9005_properties.rc.legacy.rc_map_table = rc_keys;
+ af9005_properties.rc.legacy.rc_map_size = *rc_keys_size;
}
return 0;
@@ -1089,9 +1089,9 @@ static void __exit af9005_usb_module_exit(void)
if (rc_decode != NULL)
symbol_put(af9005_rc_decode);
if (rc_keys != NULL)
- symbol_put(ir_codes_af9005_table);
+ symbol_put(rc_map_af9005_table);
if (rc_keys_size != NULL)
- symbol_put(ir_codes_af9005_table_size);
+ symbol_put(rc_map_af9005_table_size);
/* deregister this driver from the USB subsystem */
usb_deregister(&af9005_usb_driver);
}
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index 3c1fbd1c5d60..c71c77bd7f4b 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -3490,7 +3490,7 @@ 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 ir_scancode ir_codes_af9005_table[];
-extern int ir_codes_af9005_table_size;
+extern struct rc_map_table rc_map_af9005_table[];
+extern int rc_map_af9005_table_size;
#endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 31c0a0ed39f5..8671ca362c81 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1041,13 +1041,13 @@ static int af9015_rc_query(struct dvb_usb_device *d)
priv->rc_keycode = buf[12] << 16 |
buf[13] << 8 | buf[14];
}
- ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+ rc_keydown(d->rc_dev, priv->rc_keycode, 0);
} else {
priv->rc_keycode = 0; /* clear just for sure */
}
} else if (priv->rc_repeat != buf[6] || buf[0]) {
deb_rc("%s: key repeated\n", __func__);
- ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+ rc_keydown(d->rc_dev, priv->rc_keycode, 0);
} else {
deb_rc("%s: no key press\n", __func__);
}
@@ -1344,13 +1344,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = IR_TYPE_NEC,
+ .protocol = RC_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .rc_props = {
- .allowed_protos = IR_TYPE_NEC,
- },
+ .allowed_protos = RC_TYPE_NEC,
},
.i2c_algo = &af9015_i2c_algo,
@@ -1474,13 +1472,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = IR_TYPE_NEC,
+ .protocol = RC_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .rc_props = {
- .allowed_protos = IR_TYPE_NEC,
- },
+ .allowed_protos = RC_TYPE_NEC,
},
.i2c_algo = &af9015_i2c_algo,
@@ -1588,13 +1584,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = IR_TYPE_NEC,
+ .protocol = RC_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .rc_props = {
- .allowed_protos = IR_TYPE_NEC,
- },
+ .allowed_protos = RC_TYPE_NEC,
},
.i2c_algo = &af9015_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 1759d26bca42..6b402e943539 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -394,7 +394,7 @@ static int anysee_rc_query(struct dvb_usb_device *d)
if (ircode[0]) {
deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
- ir_keydown(d->rc_input_dev, 0x08 << 8 | ircode[1], 0);
+ rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
}
return 0;
@@ -476,7 +476,7 @@ static struct dvb_usb_device_properties anysee_properties = {
.rc.core = {
.rc_codes = RC_MAP_ANYSEE,
- .protocol = IR_TYPE_OTHER,
+ .protocol = RC_TYPE_OTHER,
.module_name = "anysee",
.rc_query = anysee_rc_query,
.rc_interval = 250, /* windows driver uses 500ms */
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
index 62c58288469f..57e2444d51ab 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -386,7 +386,7 @@ static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct ir_scancode ir_codes_az6027_table[] = {
+static struct rc_map_table rc_map_az6027_table[] = {
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
};
@@ -1089,6 +1089,7 @@ static struct usb_device_id az6027_usb_table[] = {
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
+ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
{ },
};
@@ -1126,15 +1127,15 @@ static struct dvb_usb_device_properties az6027_properties = {
.read_mac_address = az6027_read_mac_addr,
*/
.rc.legacy = {
- .rc_key_map = ir_codes_az6027_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_az6027_table),
+ .rc_map_table = rc_map_az6027_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_az6027_table),
.rc_interval = 400,
.rc_query = az6027_rc_query,
},
.i2c_algo = &az6027_i2c_algo,
- .num_device_descs = 5,
+ .num_device_descs = 6,
.devices = {
{
.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
@@ -1156,6 +1157,10 @@ static struct dvb_usb_device_properties az6027_properties = {
.name = "Technisat SkyStar USB 2 HD CI",
.cold_ids = { &az6027_usb_table[4], NULL },
.warm_ids = { NULL },
+ }, {
+ .name = "Elgato EyeTV Sat",
+ .cold_ids = { &az6027_usb_table[5], NULL },
+ .warm_ids = { NULL },
},
{ NULL },
}
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
index 4f5aa83fc1fc..16f2ce2bc15a 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -84,7 +84,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct ir_scancode ir_codes_cinergyt2_table[] = {
+static struct rc_map_table rc_map_cinergyt2_table[] = {
{ 0x0401, KEY_POWER },
{ 0x0402, KEY_1 },
{ 0x0403, KEY_2 },
@@ -219,8 +219,8 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
.rc.legacy = {
.rc_interval = 50,
- .rc_key_map = ir_codes_cinergyt2_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_cinergyt2_table),
+ .rc_map_table = rc_map_cinergyt2_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table),
.rc_query = cinergyt2_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index cd9f362c37b2..acb5fb2d2e73 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -385,7 +385,7 @@ static int cxusb_d680_dmb_streaming_ctrl(
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[4];
int i;
@@ -394,7 +394,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[2] &&
rc5_data(&keymap[i]) == ircode[3]) {
*event = keymap[i].keycode;
@@ -410,7 +410,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[4];
int i;
struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
@@ -422,7 +422,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
return 0;
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[1] &&
rc5_data(&keymap[i]) == ircode[2]) {
*event = keymap[i].keycode;
@@ -438,7 +438,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[2];
int i;
@@ -448,7 +448,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
return 0;
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[0] &&
rc5_data(&keymap[i]) == ircode[1]) {
*event = keymap[i].keycode;
@@ -461,7 +461,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
return 0;
}
-static struct ir_scancode ir_codes_dvico_mce_table[] = {
+static struct rc_map_table rc_map_dvico_mce_table[] = {
{ 0xfe02, KEY_TV },
{ 0xfe0e, KEY_MP3 },
{ 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@ static struct ir_scancode ir_codes_dvico_mce_table[] = {
{ 0xfe4e, KEY_POWER },
};
-static struct ir_scancode ir_codes_dvico_portable_table[] = {
+static struct rc_map_table rc_map_dvico_portable_table[] = {
{ 0xfc02, KEY_SETUP }, /* Profile */
{ 0xfc43, KEY_POWER2 },
{ 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@ static struct ir_scancode ir_codes_dvico_portable_table[] = {
{ 0xfc00, KEY_UNKNOWN }, /* HD */
};
-static struct ir_scancode ir_codes_d680_dmb_table[] = {
+static struct rc_map_table rc_map_d680_dmb_table[] = {
{ 0x0038, KEY_UNKNOWN }, /* TV/AV */
{ 0x080c, KEY_ZOOM },
{ 0x0800, KEY_0 },
@@ -923,7 +923,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
return -EIO;
/* try to determine if there is no IR decoder on the I2C bus */
- for (i = 0; adap->dev->props.rc.legacy.rc_key_map != NULL && i < 5; i++) {
+ for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) {
msleep(20);
if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
goto no_IR;
@@ -931,7 +931,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
continue;
if (ircode[2] + ircode[3] != 0xff) {
no_IR:
- adap->dev->props.rc.legacy.rc_key_map = NULL;
+ adap->dev->props.rc.legacy.rc_map_table = NULL;
info("No IR receiver detected on this device.");
break;
}
@@ -1453,8 +1453,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
.rc_query = cxusb_rc_query,
},
@@ -1506,8 +1506,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.rc.legacy = {
.rc_interval = 150,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
.rc_query = cxusb_rc_query,
},
@@ -1567,8 +1567,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
.rc_query = cxusb_rc_query,
},
@@ -1619,8 +1619,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
.rc_query = cxusb_rc_query,
},
@@ -1670,8 +1670,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
.rc_query = cxusb_bluebird2_rc_query,
},
@@ -1720,8 +1720,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
.rc_query = cxusb_bluebird2_rc_query,
},
@@ -1772,8 +1772,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
.rc_query = cxusb_rc_query,
},
@@ -1865,8 +1865,8 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
.rc_query = cxusb_rc_query,
},
@@ -1915,8 +1915,8 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
+ .rc_map_table = rc_map_d680_dmb_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table),
.rc_query = cxusb_d680_dmb_rc_query,
},
@@ -1966,8 +1966,8 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
+ .rc_map_table = rc_map_d680_dmb_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table),
.rc_query = cxusb_d680_dmb_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index c2c9d236ec7e..3537d65c04bc 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -60,7 +60,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc, int *cold);
-extern int dib0700_change_protocol(void *priv, u64 ir_type);
+extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type);
extern int dib0700_device_count;
extern int dvb_usb_dib0700_ir_proto;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 48397f103d32..8ca48f76dfa9 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -471,19 +471,19 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
-int dib0700_change_protocol(void *priv, u64 ir_type)
+int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
{
- struct dvb_usb_device *d = priv;
+ struct dvb_usb_device *d = rc->priv;
struct dib0700_state *st = d->priv;
u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
int new_proto, ret;
/* Set the IR mode */
- if (ir_type == IR_TYPE_RC5)
+ if (rc_type == RC_TYPE_RC5)
new_proto = 1;
- else if (ir_type == IR_TYPE_NEC)
+ else if (rc_type == RC_TYPE_NEC)
new_proto = 0;
- else if (ir_type == IR_TYPE_RC6) {
+ else if (rc_type == RC_TYPE_RC6) {
if (st->fw_version < 0x10200)
return -EINVAL;
@@ -499,7 +499,7 @@ int dib0700_change_protocol(void *priv, u64 ir_type)
return ret;
}
- d->props.rc.core.protocol = ir_type;
+ d->props.rc.core.protocol = rc_type;
return ret;
}
@@ -535,7 +535,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
if (d == NULL)
return;
- if (d->rc_input_dev == NULL) {
+ if (d->rc_dev == NULL) {
/* This will occur if disable_rc_polling=1 */
usb_free_urb(purb);
return;
@@ -562,7 +562,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
purb->actual_length);
switch (d->props.rc.core.protocol) {
- case IR_TYPE_NEC:
+ case RC_TYPE_NEC:
toggle = 0;
/* NEC protocol sends repeat code as 0 0 0 FF */
@@ -600,7 +600,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
goto resubmit;
}
- ir_keydown(d->rc_input_dev, keycode, toggle);
+ rc_keydown(d->rc_dev, keycode, toggle);
resubmit:
/* Clean the buffer before we requeue */
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index e06acd1fecb6..defd83964ce2 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -510,7 +510,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
d->last_event = 0;
switch (d->props.rc.core.protocol) {
- case IR_TYPE_NEC:
+ case RC_TYPE_NEC:
/* NEC protocol sends repeat code as 0 0 0 FF */
if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
(key[3] == 0xff))
@@ -520,13 +520,13 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
d->last_event = keycode;
}
- ir_keydown(d->rc_input_dev, keycode, 0);
+ rc_keydown(d->rc_dev, keycode, 0);
break;
default:
/* RC-5 protocol changes toggle bit on new keypress */
keycode = key[3-2] << 8 | key[3-3];
toggle = key[3-1];
- ir_keydown(d->rc_input_dev, keycode, toggle);
+ rc_keydown(d->rc_dev, keycode, toggle);
break;
}
@@ -1924,12 +1924,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -1960,12 +1958,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2021,12 +2017,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2065,12 +2059,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2143,12 +2135,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2189,12 +2179,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2259,12 +2247,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2308,12 +2294,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_NEC_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -2379,12 +2363,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2417,12 +2399,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2487,12 +2467,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2533,12 +2511,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_NEC_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2584,12 +2560,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2623,12 +2597,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .rc_props = {
- .allowed_protos = IR_TYPE_RC5 |
- IR_TYPE_RC6 |
- IR_TYPE_NEC,
- .change_protocol = dib0700_change_protocol,
- },
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
},
},
};
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index ba991aa21aff..956f7ae2e510 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -327,7 +327,7 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
/*
* common remote control stuff
*/
-struct ir_scancode ir_codes_dibusb_table[] = {
+struct rc_map_table rc_map_dibusb_table[] = {
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
@@ -456,7 +456,7 @@ struct ir_scancode ir_codes_dibusb_table[] = {
{ 0x804e, KEY_ENTER },
{ 0x804f, KEY_VOLUMEDOWN },
};
-EXPORT_SYMBOL(ir_codes_dibusb_table);
+EXPORT_SYMBOL(rc_map_dibusb_table);
int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 8e3c0d2cce16..04d91bdd3562 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -213,8 +213,8 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
},
@@ -299,8 +299,8 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
},
@@ -365,8 +365,8 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
},
@@ -424,8 +424,8 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 1cbc41cb4e8f..c1d9094b61e5 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -83,8 +83,8 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
.rc.legacy = {
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* FIXME */
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* FIXME */
.rc_query = dibusb_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 61a6bf389472..e47c321b3ffc 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -124,7 +124,7 @@ extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
#define DEFAULT_RC_INTERVAL 150
//#define DEFAULT_RC_INTERVAL 100000
-extern struct ir_scancode ir_codes_dibusb_table[];
+extern struct rc_map_table rc_map_dibusb_table[];
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 13d006bb19db..f2dbce7edb3b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -161,7 +161,7 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct ir_scancode ir_codes_digitv_table[] = {
+static struct rc_map_table rc_map_digitv_table[] = {
{ 0x5f55, KEY_0 },
{ 0x6f55, KEY_1 },
{ 0x9f55, KEY_2 },
@@ -237,10 +237,10 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
/* if something is inside the buffer, simulate key press */
if (key[1] != 0)
{
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
- if (rc5_custom(&d->props.rc.legacy.rc_key_map[i]) == key[1] &&
- rc5_data(&d->props.rc.legacy.rc_key_map[i]) == key[2]) {
- *event = d->props.rc.legacy.rc_key_map[i].keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+ if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
+ rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
+ *event = d->props.rc.legacy.rc_map_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
@@ -312,8 +312,8 @@ static struct dvb_usb_device_properties digitv_properties = {
.rc.legacy = {
.rc_interval = 1000,
- .rc_key_map = ir_codes_digitv_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_digitv_table),
+ .rc_map_table = rc_map_digitv_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_digitv_table),
.rc_query = digitv_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index ca495e07f35c..ecd86eca2548 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -57,7 +57,7 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
/* remote control */
/* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct ir_scancode ir_codes_dtt200u_table[] = {
+static struct rc_map_table rc_map_dtt200u_table[] = {
{ 0x8001, KEY_MUTE },
{ 0x8002, KEY_CHANNELDOWN },
{ 0x8003, KEY_VOLUMEDOWN },
@@ -163,8 +163,8 @@ static struct dvb_usb_device_properties dtt200u_properties = {
.rc.legacy = {
.rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
.rc_query = dtt200u_rc_query,
},
@@ -210,8 +210,8 @@ static struct dvb_usb_device_properties wt220u_properties = {
.rc.legacy = {
.rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
.rc_query = dtt200u_rc_query,
},
@@ -257,8 +257,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
.rc.legacy = {
.rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
.rc_query = dtt200u_rc_query,
},
@@ -304,8 +304,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
.rc.legacy = {
.rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
.rc_query = dtt200u_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 192a40ce583d..1a6310b61923 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -301,6 +301,7 @@
#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011
#define USB_PID_ELGATO_EYETV_DTT 0x0021
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
+#define USB_PID_ELGATO_EYETV_SAT 0x002a
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
#define USB_PID_FRIIO_WHITE 0x0001
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index b579fed3ab3f..23005b3cf30b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -13,11 +13,11 @@ static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
int i;
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (keymap[i].scancode == scancode) {
*keycode = keymap[i].keycode;
return 0;
@@ -28,7 +28,7 @@ static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
* otherwise, input core won't let legacy_dvb_usb_setkeycode
* to work
*/
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (keymap[i].keycode == KEY_RESERVED ||
keymap[i].keycode == KEY_UNKNOWN) {
*keycode = KEY_RESERVED;
@@ -43,18 +43,18 @@ static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
int i;
/* Search if it is replacing an existing keycode */
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (keymap[i].scancode == scancode) {
keymap[i].keycode = keycode;
return 0;
}
/* Search if is there a clean entry. If so, use it */
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (keymap[i].keycode == KEY_RESERVED ||
keymap[i].keycode == KEY_UNKNOWN) {
keymap[i].scancode = scancode;
@@ -106,10 +106,10 @@ static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
d->last_event = event;
case REMOTE_KEY_REPEAT:
deb_rc("key repeated\n");
- input_event(d->rc_input_dev, EV_KEY, event, 1);
- input_sync(d->rc_input_dev);
- input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
- input_sync(d->rc_input_dev);
+ input_event(d->input_dev, EV_KEY, event, 1);
+ input_sync(d->input_dev);
+ input_event(d->input_dev, EV_KEY, d->last_event, 0);
+ input_sync(d->input_dev);
break;
default:
break;
@@ -154,20 +154,32 @@ schedule:
schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
}
-static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d,
- struct input_dev *input_dev)
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
{
int i, err, rc_interval;
+ struct input_dev *input_dev;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ 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->dev.parent = &d->udev->dev;
+ d->input_dev = input_dev;
+ d->rc_dev = NULL;
input_dev->getkeycode = legacy_dvb_usb_getkeycode;
input_dev->setkeycode = legacy_dvb_usb_setkeycode;
/* set the bits for the keys */
- deb_rc("key map size: %d\n", d->props.rc.legacy.rc_key_map_size);
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
deb_rc("setting bit for event %d item %d\n",
- d->props.rc.legacy.rc_key_map[i].keycode, i);
- set_bit(d->props.rc.legacy.rc_key_map[i].keycode, input_dev->keybit);
+ d->props.rc.legacy.rc_map_table[i].keycode, i);
+ set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
}
/* setting these two values to non-zero, we have to manage key repeats */
@@ -221,18 +233,34 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
msecs_to_jiffies(d->props.rc.core.rc_interval));
}
-static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d,
- struct input_dev *input_dev)
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
{
int err, rc_interval;
+ struct rc_dev *dev;
+
+ dev = rc_allocate_device();
+ if (!dev)
+ return -ENOMEM;
- d->props.rc.core.rc_props.priv = d;
- err = ir_input_register(input_dev,
- d->props.rc.core.rc_codes,
- &d->props.rc.core.rc_props,
- d->props.rc.core.module_name);
- if (err < 0)
+ dev->driver_name = d->props.rc.core.module_name;
+ dev->map_name = d->props.rc.core.rc_codes;
+ dev->change_protocol = d->props.rc.core.change_protocol;
+ dev->allowed_protos = d->props.rc.core.allowed_protos;
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ usb_to_input_id(d->udev, &dev->input_id);
+ dev->input_name = "IR-receiver inside an USB DVB receiver";
+ dev->input_phys = d->rc_phys;
+ dev->dev.parent = &d->udev->dev;
+ dev->priv = d;
+
+ err = rc_register_device(dev);
+ if (err < 0) {
+ rc_free_device(dev);
return err;
+ }
+
+ d->input_dev = NULL;
+ d->rc_dev = dev;
if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
return 0;
@@ -251,13 +279,12 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d,
int dvb_usb_remote_init(struct dvb_usb_device *d)
{
- struct input_dev *input_dev;
int err;
if (dvb_usb_disable_rc_polling)
return 0;
- if (d->props.rc.legacy.rc_key_map && d->props.rc.legacy.rc_query)
+ if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
d->props.rc.mode = DVB_RC_LEGACY;
else if (d->props.rc.core.rc_codes)
d->props.rc.mode = DVB_RC_CORE;
@@ -267,26 +294,14 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
- input_dev = input_allocate_device();
- if (!input_dev)
- return -ENOMEM;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- 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->dev.parent = &d->udev->dev;
-
/* Start the remote-control polling. */
if (d->props.rc.legacy.rc_interval < 40)
d->props.rc.legacy.rc_interval = 100; /* default */
- d->rc_input_dev = input_dev;
-
if (d->props.rc.mode == DVB_RC_LEGACY)
- err = legacy_dvb_usb_remote_init(d, input_dev);
+ err = legacy_dvb_usb_remote_init(d);
else
- err = rc_core_dvb_usb_remote_init(d, input_dev);
+ err = rc_core_dvb_usb_remote_init(d);
if (err)
return err;
@@ -298,12 +313,11 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
int dvb_usb_remote_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_REMOTE) {
- cancel_rearming_delayed_work(&d->rc_query_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&d->rc_query_work);
if (d->props.rc.mode == DVB_RC_LEGACY)
- input_unregister_device(d->rc_input_dev);
+ input_unregister_device(d->input_dev);
else
- ir_input_unregister(d->rc_input_dev);
+ rc_unregister_device(d->rc_dev);
}
d->state &= ~DVB_USB_STATE_REMOTE;
return 0;
@@ -316,7 +330,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
u8 keybuf[5], u32 *event, int *state)
{
int i;
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
switch (keybuf[0]) {
@@ -329,7 +343,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
break;
}
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (rc5_custom(&keymap[i]) == keybuf[1] &&
rc5_data(&keymap[i]) == keybuf[3]) {
*event = keymap[i].keycode;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 34f7b3ba8cc7..65fa9268e7f7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -14,7 +14,7 @@
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
@@ -75,17 +75,17 @@ struct dvb_usb_device_description {
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
};
-static inline u8 rc5_custom(struct ir_scancode *key)
+static inline u8 rc5_custom(struct rc_map_table *key)
{
return (key->scancode >> 8) & 0xff;
}
-static inline u8 rc5_data(struct ir_scancode *key)
+static inline u8 rc5_data(struct rc_map_table *key)
{
return key->scancode & 0xff;
}
-static inline u8 rc5_scan(struct ir_scancode *key)
+static inline u8 rc5_scan(struct rc_map_table *key)
{
return key->scancode & 0xffff;
}
@@ -159,9 +159,9 @@ struct dvb_usb_adapter_properties {
/**
* struct dvb_rc_legacy - old properties of remote controller
- * @rc_key_map: a hard-wired array of struct ir_scancode (NULL to disable
+ * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
* remote control handling).
- * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_map_size: number of items in @rc_map_table.
* @rc_query: called to query an event event.
* @rc_interval: time in ms between two queries.
*/
@@ -170,8 +170,8 @@ struct dvb_rc_legacy {
#define REMOTE_NO_KEY_PRESSED 0x00
#define REMOTE_KEY_PRESSED 0x01
#define REMOTE_KEY_REPEAT 0x02
- struct ir_scancode *rc_key_map;
- int rc_key_map_size;
+ struct rc_map_table *rc_map_table;
+ int rc_map_size;
int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
int rc_interval;
};
@@ -180,18 +180,20 @@ struct dvb_rc_legacy {
* struct dvb_rc properties of remote controller, using rc-core
* @rc_codes: name of rc codes table
* @protocol: type of protocol(s) currently used by the driver
+ * @allowed_protos: protocol(s) supported by the driver
+ * @change_protocol: callback to change protocol
* @rc_query: called to query an event event.
* @rc_interval: time in ms between two queries.
- * @rc_props: remote controller properties
* @bulk_mode: device supports bulk mode for RC (disable polling mode)
*/
struct dvb_rc {
char *rc_codes;
u64 protocol;
+ u64 allowed_protos;
+ int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
char *module_name;
int (*rc_query) (struct dvb_usb_device *d);
int rc_interval;
- struct ir_dev_props rc_props;
bool bulk_mode; /* uses bulk mode */
};
@@ -385,7 +387,8 @@ struct dvb_usb_adapter {
*
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
*
- * @rc_input_dev: input device for the remote control.
+ * @rc_dev: rc device for the remote control (rc-core mode)
+ * @input_dev: input device for the remote control (legacy mode)
* @rc_query_work: struct work_struct frequent rc queries
* @last_event: last triggered event
* @last_state: last state (no, pressed, repeat)
@@ -418,7 +421,8 @@ struct dvb_usb_device {
struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
/* remote control */
- struct input_dev *rc_input_dev;
+ struct rc_dev *rc_dev;
+ struct input_dev *input_dev;
char rc_phys[64];
struct delayed_work rc_query_work;
u32 last_event;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 774df88dc6e3..2c307ba0d28b 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -73,8 +73,8 @@
"Please see linux/Documentation/dvb/ for more details " \
"on firmware-problems."
-struct ir_codes_dvb_usb_table_table {
- struct ir_scancode *rc_keys;
+struct rc_map_dvb_usb_table_table {
+ struct rc_map_table *rc_keys;
int rc_keys_size;
};
@@ -948,7 +948,7 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct ir_scancode ir_codes_dw210x_table[] = {
+static struct rc_map_table rc_map_dw210x_table[] = {
{ 0xf80a, KEY_Q }, /*power*/
{ 0xf80c, KEY_M }, /*mute*/
{ 0xf811, KEY_1 },
@@ -982,7 +982,7 @@ static struct ir_scancode ir_codes_dw210x_table[] = {
{ 0xf81b, KEY_B }, /*recall*/
};
-static struct ir_scancode ir_codes_tevii_table[] = {
+static struct rc_map_table rc_map_tevii_table[] = {
{ 0xf80a, KEY_POWER },
{ 0xf80c, KEY_MUTE },
{ 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@ static struct ir_scancode ir_codes_tevii_table[] = {
{ 0xf858, KEY_SWITCHVIDEOMODE },
};
-static struct ir_scancode ir_codes_tbs_table[] = {
+static struct rc_map_table rc_map_tbs_table[] = {
{ 0xf884, KEY_POWER },
{ 0xf894, KEY_MUTE },
{ 0xf887, KEY_1 },
@@ -1067,16 +1067,16 @@ static struct ir_scancode ir_codes_tbs_table[] = {
{ 0xf89b, KEY_MODE }
};
-static struct ir_codes_dvb_usb_table_table keys_tables[] = {
- { ir_codes_dw210x_table, ARRAY_SIZE(ir_codes_dw210x_table) },
- { ir_codes_tevii_table, ARRAY_SIZE(ir_codes_tevii_table) },
- { ir_codes_tbs_table, ARRAY_SIZE(ir_codes_tbs_table) },
+static struct rc_map_dvb_usb_table_table keys_tables[] = {
+ { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
+ { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
+ { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
};
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
- int keymap_size = d->props.rc.legacy.rc_key_map_size;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+ int keymap_size = d->props.rc.legacy.rc_map_size;
u8 key[2];
struct i2c_msg msg = {
.addr = DW2102_RC_QUERY,
@@ -1185,14 +1185,14 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* init registers */
switch (dev->descriptor.idProduct) {
case USB_PID_PROF_1100:
- s6x0_properties.rc.legacy.rc_key_map = ir_codes_tbs_table;
- s6x0_properties.rc.legacy.rc_key_map_size =
- ARRAY_SIZE(ir_codes_tbs_table);
+ s6x0_properties.rc.legacy.rc_map_table = rc_map_tbs_table;
+ s6x0_properties.rc.legacy.rc_map_size =
+ ARRAY_SIZE(rc_map_tbs_table);
break;
case USB_PID_TEVII_S650:
- dw2104_properties.rc.legacy.rc_key_map = ir_codes_tevii_table;
- dw2104_properties.rc.legacy.rc_key_map_size =
- ARRAY_SIZE(ir_codes_tevii_table);
+ dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
+ dw2104_properties.rc.legacy.rc_map_size =
+ ARRAY_SIZE(rc_map_tevii_table);
case USB_PID_DW2104:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
@@ -1257,8 +1257,8 @@ static struct dvb_usb_device_properties dw2102_properties = {
.i2c_algo = &dw2102_serit_i2c_algo,
.rc.legacy = {
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
.rc_interval = 150,
.rc_query = dw2102_rc_query,
},
@@ -1310,8 +1310,8 @@ static struct dvb_usb_device_properties dw2104_properties = {
.i2c_algo = &dw2104_i2c_algo,
.rc.legacy = {
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
.rc_interval = 150,
.rc_query = dw2102_rc_query,
},
@@ -1359,8 +1359,8 @@ static struct dvb_usb_device_properties dw3101_properties = {
.i2c_algo = &dw3101_i2c_algo,
.rc.legacy = {
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
.rc_interval = 150,
.rc_query = dw2102_rc_query,
},
@@ -1404,8 +1404,8 @@ static struct dvb_usb_device_properties s6x0_properties = {
.i2c_algo = &s6x0_i2c_algo,
.rc.legacy = {
- .rc_key_map = ir_codes_tevii_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
+ .rc_map_table = rc_map_tevii_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
.rc_interval = 150,
.rc_query = dw2102_rc_query,
},
@@ -1468,8 +1468,8 @@ static int dw2102_probe(struct usb_interface *intf,
/* fill only different fields */
p7500->firmware = "dvb-usb-p7500.fw";
p7500->devices[0] = d7500;
- p7500->rc.legacy.rc_key_map = ir_codes_tbs_table;
- p7500->rc.legacy.rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
+ p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
+ p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p7500->adapter->frontend_attach = prof_7500_frontend_attach;
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index c821293dbc22..1cb3d9a66e02 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -24,6 +24,33 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
+{
+ return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
+}
+
+static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
+{
+ return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
+}
+
+static void gp8psk_info(struct dvb_usb_device *d)
+{
+ u8 fpga_vers, fw_vers[6];
+
+ if (!gp8psk_get_fw_version(d, fw_vers))
+ info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i",
+ fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
+ 2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
+ else
+ info("failed to get FW version");
+
+ if (!gp8psk_get_fpga_version(d, &fpga_vers))
+ info("FPGA Version = %i", fpga_vers);
+ else
+ info("failed to get FPGA version");
+}
+
int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
{
int ret = 0,try = 0;
@@ -146,6 +173,7 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
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;
+ gp8psk_info(d);
}
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index e83a57506cfa..831749a518cb 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -25,7 +25,6 @@ extern int dvb_usb_gp8psk_debug;
#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
-/* gp8psk commands */
/* Twinhan Vendor requests */
#define TH_COMMAND_IN 0xC0
@@ -49,8 +48,10 @@ extern int dvb_usb_gp8psk_debug;
#define SET_DVB_MODE 0x8E
#define SET_DN_SWITCH 0x8F
#define GET_SIGNAL_LOCK 0x90 /* in */
+#define GET_FW_VERS 0x92
#define GET_SERIAL_NUMBER 0x93 /* in */
#define USE_EXTRA_VOLT 0x94
+#define GET_FPGA_VERS 0x95
#define CW3K_INIT 0x9d
/* PSK_configuration bits */
@@ -88,6 +89,11 @@ extern int dvb_usb_gp8psk_debug;
#define PRODUCT_STRING_READ 0x0D
#define FW_BCD_VERSION_READ 0x14
+/* firmware revision id's */
+#define GP8PSK_FW_REV1 0x020604
+#define GP8PSK_FW_REV2 0x020704
+#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
+
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,
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index d939fbbf9fe6..9eea4188303b 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -61,7 +61,7 @@
#define DVB_USB_LOG_PREFIX "LME2510(C)"
#include <linux/usb.h>
#include <linux/usb/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "dvb-usb.h"
#include "lmedm04.h"
@@ -112,7 +112,6 @@ struct lme2510_state {
u8 i2c_tuner_gate_r;
u8 i2c_tuner_addr;
u8 stream_on;
- u8 one_tune;
void *buffer;
struct urb *lme_urb;
void *usb_buffer;
@@ -125,7 +124,7 @@ static int lme2510_bulk_write(struct usb_device *dev,
int ret, actual_l;
ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
- snd, len , &actual_l, 500);
+ snd, len , &actual_l, 100);
return ret;
}
@@ -135,7 +134,7 @@ static int lme2510_bulk_read(struct usb_device *dev,
int ret, actual_l;
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
- rev, len , &actual_l, 500);
+ rev, len , &actual_l, 200);
return ret;
}
@@ -167,7 +166,7 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
- msleep(12);
+ msleep(10);
ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
@@ -182,15 +181,13 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
return (ret < 0) ? -ENODEV : 0;
}
-static int lme2510_usb_talk_restart(struct dvb_usb_device *d,
- u8 *wbuf, int wlen, u8 *rbuf, int rlen) {
+static int lme2510_stream_restart(struct dvb_usb_device *d)
+{
static u8 stream_on[] = LME_ST_ON_W;
int ret;
u8 rbuff[10];
- /*Send Normal Command*/
- ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
/*Restart Stream Command*/
- ret |= lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+ ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
rbuff, sizeof(rbuff));
return ret;
}
@@ -201,7 +198,7 @@ static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
deb_info(1, "INT Key Keypress =%04x", keypress);
if (keypress > 0)
- ir_keydown(d->rc_input_dev, keypress, 0);
+ rc_keydown(d->rc_dev, keypress, 0);
return 0;
}
@@ -254,11 +251,16 @@ static void lme2510_int_response(struct urb *lme_urb)
case TUNER_S7395:
/* Tweak for earlier firmware*/
if (ibuf[1] == 0x03) {
+ if (ibuf[2] > 1)
+ st->signal_lock = ibuf[2];
st->signal_level = ibuf[3];
st->signal_sn = ibuf[4];
} else {
st->signal_level = ibuf[4];
st->signal_sn = ibuf[5];
+ st->signal_lock =
+ (st->signal_lock & 0xf7) +
+ ((ibuf[2] & 0x01) << 0x03);
}
break;
default:
@@ -341,11 +343,10 @@ static int lme2510_msg(struct dvb_usb_device *d,
st->signal_lock = rbuf[1];
if ((st->stream_on & 1) &&
(st->signal_lock & 0x10)) {
- lme2510_usb_talk_restart(d,
- wbuf, wlen, rbuf, rlen);
+ lme2510_stream_restart(d);
st->i2c_talk_onoff = 0;
}
- msleep(80);
+ msleep(80);
}
}
break;
@@ -355,15 +356,12 @@ static int lme2510_msg(struct dvb_usb_device *d,
st->signal_lock = rbuf[1];
if ((st->stream_on & 1) &&
(st->signal_lock & 0x8)) {
- lme2510_usb_talk_restart(d,
- wbuf, wlen, rbuf, rlen);
+ lme2510_stream_restart(d);
st->i2c_talk_onoff = 0;
}
}
if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
msleep(5);
-
-
}
break;
default:
@@ -385,18 +383,16 @@ static int lme2510_msg(struct dvb_usb_device *d,
rbuf[0] = 0x55;
rbuf[1] = st->signal_sn;
break;
- /*DiSEqC functions as per TDA10086*/
- case 0x36:
- case 0x48:
- case 0x49:
- case 0x4a:
- case 0x4b:
- case 0x4c:
- case 0x4d:
- if (wbuf[2] == 0x1c)
- lme2510_usb_talk_restart(d,
- wbuf, wlen, rbuf, rlen);
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
break;
}
break;
@@ -413,39 +409,22 @@ static int lme2510_msg(struct dvb_usb_device *d,
break;
case 0x24:
rbuf[0] = 0x55;
- rbuf[1] = (st->signal_level & 0x80)
- ? 0 : st->signal_lock;
- break;
- case 0x6:
- if (wbuf[2] == 0xd0)
- lme2510_usb_talk(d,
- wbuf, wlen, rbuf, rlen);
- break;
- case 0x1:
- if (st->one_tune > 0)
- break;
- st->one_tune++;
- st->i2c_talk_onoff = 1;
- /*DiSEqC functions as per STV0288*/
- case 0x5:
- case 0x7:
- case 0x8:
- case 0x9:
- case 0xa:
- case 0xb:
- if (wbuf[2] == 0xd0)
- lme2510_usb_talk_restart(d,
- wbuf, wlen, rbuf, rlen);
+ rbuf[1] = st->signal_lock;
break;
- default:
+ case 0x2e:
+ case 0x26:
+ case 0x27:
rbuf[0] = 0x55;
rbuf[1] = 0x00;
break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
}
break;
default:
break;
-
}
deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)",
@@ -548,35 +527,26 @@ static int lme2510_identify_state(struct usb_device *udev,
static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct lme2510_state *st = adap->dev->priv;
- static u8 stream_on[] = LME_ST_ON_W;
static u8 clear_reg_3[] = LME_CLEAR_PID;
static u8 rbuf[1];
- static u8 timeout;
- int ret = 0, len = 2, rlen = sizeof(rbuf);
+ int ret = 0, rlen = sizeof(rbuf);
deb_info(1, "STM (%02x)", onoff);
- if (onoff == 1) {
- st->i2c_talk_onoff = 0;
- timeout = 0;
- /* wait for i2C to be free */
- while (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) {
- timeout++;
- if (timeout > 5)
- return -ENODEV;
- }
- msleep(100);
- ret |= lme2510_usb_talk(adap->dev,
- stream_on, len, rbuf, rlen);
+ /* Streaming is started by FE_HAS_LOCK */
+ if (onoff == 1)
st->stream_on = 1;
- st->one_tune = 0;
- mutex_unlock(&adap->dev->i2c_mutex);
- } else {
+ else {
deb_info(1, "STM Steam Off");
+ /* mutex is here only to avoid collision with I2C */
+ ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+
ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
sizeof(clear_reg_3), rbuf, rlen);
st->stream_on = 0;
st->i2c_talk_onoff = 1;
+
+ mutex_unlock(&adap->dev->i2c_mutex);
}
return (ret < 0) ? -ENODEV : 0;
@@ -585,41 +555,40 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
static int lme2510_int_service(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap->dev;
- struct input_dev *input_dev;
- char *ir_codes = RC_MAP_LME2510;
- int ret = 0;
+ struct rc_dev *rc;
+ int ret;
info("STA Configuring Remote");
- usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
-
- strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
-
- input_dev = input_allocate_device();
- if (!input_dev)
+ rc = rc_allocate_device();
+ if (!rc)
return -ENOMEM;
- input_dev->name = "LME2510 Remote Control";
- input_dev->phys = d->rc_phys;
-
- usb_to_input_id(d->udev, &input_dev->id);
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
- ret |= ir_input_register(input_dev, ir_codes, NULL, "LME 2510");
+ rc->input_name = "LME2510 Remote Control";
+ rc->input_phys = d->rc_phys;
+ rc->map_name = RC_MAP_LME2510;
+ rc->driver_name = "LME 2510";
+ usb_to_input_id(d->udev, &rc->input_id);
+ ret = rc_register_device(rc);
if (ret) {
- input_free_device(input_dev);
+ rc_free_device(rc);
return ret;
}
+ d->rc_dev = rc;
- d->rc_input_dev = input_dev;
/* Start the Interupt */
ret = lme2510_int_read(adap);
-
if (ret < 0) {
- ir_input_unregister(input_dev);
- input_free_device(input_dev);
+ rc_unregister_device(rc);
+ info("INT Unable to start Interupt Service");
+ return -ENODEV;
}
- return (ret < 0) ? -ENODEV : 0;
+
+ return 0;
}
static u8 check_sum(u8 *p, u8 len)
@@ -668,6 +637,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
ret |= (data[0] == 0x88) ? 0 : -1;
}
}
+
usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
@@ -701,10 +671,11 @@ static void lme_coldreset(struct usb_device *dev)
info("FRM Firmware Cold Reset");
ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
ret |= lme2510_bulk_read(dev, data, len_in, 1);
+
return;
}
-static void lme_firmware_switch(struct usb_device *udev, int cold)
+static int lme_firmware_switch(struct usb_device *udev, int cold)
{
const struct firmware *fw = NULL;
char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
@@ -712,8 +683,10 @@ static void lme_firmware_switch(struct usb_device *udev, int cold)
char *firm_msg[] = {"Loading", "Switching to"};
int ret;
+ cold = (cold > 0) ? (cold & 1) : 0;
+
if (udev->descriptor.idProduct == 0x1122)
- return;
+ return 0;
switch (dvb_usb_lme2510_firmware) {
case 0:
@@ -740,22 +713,28 @@ static void lme_firmware_switch(struct usb_device *udev, int cold)
cold = 0;
break;
}
+
release_firmware(fw);
- if (cold)
+
+ if (cold) {
lme_coldreset(udev);
- return;
+ return -ENODEV;
+ }
+
+ return ret;
}
static int lme2510_kill_urb(struct usb_data_stream *stream)
{
int i;
+
for (i = 0; i < stream->urbs_submitted; i++) {
deb_info(3, "killing URB no. %d.", i);
-
/* stop the URB */
usb_kill_urb(stream->urb_list[i]);
}
stream->urbs_submitted = 0;
+
return 0;
}
@@ -783,18 +762,13 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct lme2510_state *st = adap->dev->priv;
static u8 voltage_low[] = LME_VOLTAGE_L;
static u8 voltage_high[] = LME_VOLTAGE_H;
- static u8 lnb_on[] = LNB_ON;
- static u8 lnb_off[] = LNB_OFF;
static u8 rbuf[1];
int ret = 0, len = 3, rlen = 1;
- if (st->stream_on == 1)
- return 0;
-
- ret |= lme2510_usb_talk(adap->dev, lnb_on, len, rbuf, rlen);
+ if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+ return -EAGAIN;
switch (voltage) {
case SEC_VOLTAGE_18:
@@ -803,94 +777,143 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
break;
case SEC_VOLTAGE_OFF:
- ret |= lme2510_usb_talk(adap->dev,
- lnb_off, len, rbuf, rlen);
case SEC_VOLTAGE_13:
default:
ret |= lme2510_usb_talk(adap->dev,
voltage_low, len, rbuf, rlen);
break;
+ }
+ mutex_unlock(&adap->dev->i2c_mutex);
- };
- st->i2c_talk_onoff = 1;
return (ret < 0) ? -ENODEV : 0;
}
+static int lme_name(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ const char *desc = adap->dev->desc->name;
+ char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395"};
+ char *name = adap->fe->ops.info.name;
+
+ strlcpy(name, desc, 128);
+ strlcat(name, fe_name[st->tuner_config], 128);
+
+ return 0;
+}
+
static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
{
- int ret = 0;
struct lme2510_state *st = adap->dev->priv;
- /* Interupt Start */
- ret = lme2510_int_service(adap);
- if (ret < 0) {
- info("INT Unable to start Interupt Service");
- return -ENODEV;
- }
+ int ret = 0;
st->i2c_talk_onoff = 1;
- st->i2c_gate = 4;
+ st->i2c_gate = 4;
adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
&adap->dev->i2c_adap);
if (adap->fe) {
info("TUN Found Frontend TDA10086");
- memcpy(&adap->fe->ops.info.name,
- &"DM04_LG_TDQY-P001F DVB-S", 24);
- adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 4;
st->i2c_tuner_addr = 0xc0;
- if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
- &adap->dev->i2c_adap, 1)) {
- info("TUN TDA8263 Found");
- st->tuner_config = TUNER_LG;
- if (dvb_usb_lme2510_firmware != 1) {
- dvb_usb_lme2510_firmware = 1;
- lme_firmware_switch(adap->dev->udev, 1);
- }
- return 0;
- }
- kfree(adap->fe);
- adap->fe = NULL;
+ st->tuner_config = TUNER_LG;
+ if (dvb_usb_lme2510_firmware != 1) {
+ dvb_usb_lme2510_firmware = 1;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ } else /*stops LG/Sharp multi tuner problems*/
+ dvb_usb_lme2510_firmware = 0;
+ goto end;
}
+
st->i2c_gate = 5;
adap->fe = dvb_attach(stv0288_attach, &lme_config,
&adap->dev->i2c_adap);
if (adap->fe) {
info("FE Found Stv0288");
- memcpy(&adap->fe->ops.info.name,
- &"DM04_SHARP:BS2F7HZ7395", 22);
- adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 5;
st->i2c_tuner_addr = 0xc0;
- if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
- &adap->dev->i2c_adap)) {
- st->tuner_config = TUNER_S7395;
- info("TUN Sharp IX2505V silicon tuner");
- if (dvb_usb_lme2510_firmware != 0) {
- dvb_usb_lme2510_firmware = 0;
- lme_firmware_switch(adap->dev->udev, 1);
- }
- return 0;
+ st->tuner_config = TUNER_S7395;
+ if (dvb_usb_lme2510_firmware != 0) {
+ dvb_usb_lme2510_firmware = 0;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
}
+ } else {
+ info("DM04 Not Supported");
+ return -ENODEV;
+ }
+
+end: if (ret) {
kfree(adap->fe);
adap->fe = NULL;
+ return -ENODEV;
}
- info("DM04 Not Supported");
- return -ENODEV;
+ adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+ ret = lme_name(adap);
+
+ return ret;
+}
+
+static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ char *tun_msg[] = {"", "TDA8263", "IX2505V"};
+ int ret = 0;
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
+ &adap->dev->i2c_adap, 1))
+ ret = st->tuner_config;
+ break;
+ case TUNER_S7395:
+ if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
+ &adap->dev->i2c_adap))
+ ret = st->tuner_config;
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ info("TUN Found %s tuner", tun_msg[ret]);
+ else {
+ info("TUN No tuner found --- reseting device");
+ lme_coldreset(adap->dev->udev);
+ return -ENODEV;
+ }
+
+ /* Start the Interupt & Remote*/
+ ret = lme2510_int_service(adap);
+
+ return ret;
}
static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
{
struct lme2510_state *st = d->priv;
+ static u8 lnb_on[] = LNB_ON;
+ static u8 lnb_off[] = LNB_OFF;
+ static u8 rbuf[1];
+ int ret, len = 3, rlen = 1;
+
+ ret = mutex_lock_interruptible(&d->i2c_mutex);
+
+ if (onoff)
+ ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+ else
+ ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+
st->i2c_talk_onoff = 1;
- return 0;
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
}
/* DVB USB Driver stuff */
@@ -951,6 +974,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
{
.streaming_ctrl = lme2510_streaming_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
+ .tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
@@ -971,7 +995,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
.generic_bulk_ctrl_endpoint = 0,
.num_device_descs = 1,
.devices = {
- { "DM04 LME2510 DVB-S USB 2.0",
+ { "DM04_LME2510_DVB-S",
{ &lme2510_table[0], NULL },
},
@@ -989,6 +1013,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
{
.streaming_ctrl = lme2510_streaming_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
+ .tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
@@ -1009,7 +1034,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
.generic_bulk_ctrl_endpoint = 0,
.num_device_descs = 1,
.devices = {
- { "DM04 LME2510C USB2.0",
+ { "DM04_LME2510C_DVB-S",
{ &lme2510_table[1], NULL },
},
}
@@ -1036,7 +1061,7 @@ void *lme2510_exit_int(struct dvb_usb_device *d)
usb_free_coherent(d->udev, 5000, st->buffer,
st->lme_urb->transfer_dma);
info("Interupt Service Stopped");
- ir_input_unregister(d->rc_input_dev);
+ rc_unregister_device(d->rc_dev);
info("Remote Stopped");
}
return buffer;
@@ -1055,7 +1080,7 @@ void lme2510_exit(struct usb_interface *intf)
}
static struct usb_driver lme2510_driver = {
- .name = "LME2510C_DVBS",
+ .name = "LME2510C_DVB-S",
.probe = lme2510_probe,
.disconnect = lme2510_exit,
.id_table = lme2510_table,
@@ -1083,6 +1108,6 @@ module_init(lme2510_module_init);
module_exit(lme2510_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.60");
+MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
+MODULE_VERSION("1.74");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index bdef1a18b664..da9dc91ce910 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -142,9 +142,9 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
goto unlock;
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
- if (rc5_data(&d->props.rc.legacy.rc_key_map[i]) == rc_state[1]) {
- *event = d->props.rc.legacy.rc_key_map[i].keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
+ *event = d->props.rc.legacy.rc_map_table[i].keycode;
switch(rc_state[0]) {
case 0x80:
@@ -589,7 +589,7 @@ static struct m920x_inits pinnacle310e_init[] = {
};
/* ir keymaps */
-static struct ir_scancode ir_codes_megasky_table[] = {
+static struct rc_map_table rc_map_megasky_table[] = {
{ 0x0012, KEY_POWER },
{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
{ 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@ static struct ir_scancode ir_codes_megasky_table[] = {
{ 0x000e, KEY_COFFEE }, /* "MTS" */
};
-static struct ir_scancode ir_codes_tvwalkertwin_table[] = {
+static struct rc_map_table rc_map_tvwalkertwin_table[] = {
{ 0x0001, KEY_ZOOM }, /* Full Screen */
{ 0x0002, KEY_CAMERA }, /* snapshot */
{ 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@ static struct ir_scancode ir_codes_tvwalkertwin_table[] = {
{ 0x001e, KEY_VOLUMEUP },
};
-static struct ir_scancode ir_codes_pinnacle310e_table[] = {
+static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x16, KEY_POWER },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
@@ -786,8 +786,8 @@ static struct dvb_usb_device_properties megasky_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_megasky_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_megasky_table),
+ .rc_map_table = rc_map_megasky_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_megasky_table),
.rc_query = m920x_rc_query,
},
@@ -889,8 +889,8 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_tvwalkertwin_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
+ .rc_map_table = rc_map_tvwalkertwin_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table),
.rc_query = m920x_rc_query,
},
@@ -998,8 +998,8 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_pinnacle310e_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_pinnacle310e_table),
+ .rc_map_table = rc_map_pinnacle310e_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table),
.rc_query = m920x_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 181f36a12e2a..9d3cd2de46fc 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -21,7 +21,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define deb_ee(args...) dprintk(debug,0x02,args)
/* Hauppauge NOVA-T USB2 keys */
-static struct ir_scancode ir_codes_haupp_table[] = {
+static struct rc_map_table rc_map_haupp_table[] = {
{ 0x1e00, KEY_0 },
{ 0x1e01, KEY_1 },
{ 0x1e02, KEY_2 },
@@ -91,14 +91,14 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
- for (i = 0; i < ARRAY_SIZE(ir_codes_haupp_table); i++) {
- if (rc5_data(&ir_codes_haupp_table[i]) == data &&
- rc5_custom(&ir_codes_haupp_table[i]) == custom) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) {
+ if (rc5_data(&rc_map_haupp_table[i]) == data &&
+ rc5_custom(&rc_map_haupp_table[i]) == custom) {
- deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
- rc5_custom(&ir_codes_haupp_table[i]));
+ deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]),
+ rc5_custom(&rc_map_haupp_table[i]));
- *event = ir_codes_haupp_table[i].keycode;
+ *event = rc_map_haupp_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
if (st->old_toggle == toggle) {
if (st->last_repeat_count++ < 2)
@@ -197,8 +197,8 @@ static struct dvb_usb_device_properties nova_t_properties = {
.rc.legacy = {
.rc_interval = 100,
- .rc_key_map = ir_codes_haupp_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_haupp_table),
+ .rc_map_table = rc_map_haupp_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_haupp_table),
.rc_query = nova_t_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index f896337b4535..1f1b7d6980a5 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -35,7 +35,7 @@
struct opera1_state {
u32 last_key_pressed;
};
-struct ir_codes_opera_table {
+struct rc_map_opera_table {
u32 keycode;
u32 event;
};
@@ -331,7 +331,7 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
return 0;
}
-static struct ir_scancode ir_codes_opera1_table[] = {
+static struct rc_map_table rc_map_opera1_table[] = {
{0x5fa0, KEY_1},
{0x51af, KEY_2},
{0x5da2, KEY_3},
@@ -404,12 +404,12 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
send_key = (send_key & 0xffff) | 0x0100;
- for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
- if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
+ if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_opera1_table[i].keycode;
+ *event = rc_map_opera1_table[i].keycode;
opst->last_key_pressed =
- ir_codes_opera1_table[i].keycode;
+ rc_map_opera1_table[i].keycode;
break;
}
opst->last_key_pressed = 0;
@@ -497,8 +497,8 @@ static struct dvb_usb_device_properties opera1_properties = {
.i2c_algo = &opera1_i2c_algo,
.rc.legacy = {
- .rc_key_map = ir_codes_opera1_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
+ .rc_map_table = rc_map_opera1_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
.rc_interval = 200,
.rc_query = opera1_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index a6de489a6a39..0d4709ff9cbb 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -43,6 +43,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct ttusb2_state {
u8 id;
+ u16 last_rc_key;
};
static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
@@ -128,6 +129,33 @@ static struct i2c_algorithm ttusb2_i2c_algo = {
.functionality = ttusb2_i2c_func,
};
+/* command to poll IR receiver (copied from pctv452e.c) */
+#define CMD_GET_IR_CODE 0x1b
+
+/* IR */
+static int tt3650_rc_query(struct dvb_usb_device *d)
+{
+ int ret;
+ u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
+ struct ttusb2_state *st = d->priv;
+ ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
+ if (ret != 0)
+ return ret;
+
+ if (rx[8] & 0x01) {
+ /* got a "press" event */
+ st->last_rc_key = (rx[3] << 8) | rx[2];
+ deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
+ rc_keydown(d->rc_dev, st->last_rc_key, 0);
+ } else if (st->last_rc_key) {
+ rc_keyup(d->rc_dev);
+ st->last_rc_key = 0;
+ }
+
+ return 0;
+}
+
+
/* Callbacks for DVB USB */
static int ttusb2_identify_state (struct usb_device *udev, struct
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
@@ -345,6 +373,13 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
.size_of_priv = sizeof(struct ttusb2_state),
+ .rc.core = {
+ .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */
+ .rc_codes = RC_MAP_TT_1500,
+ .rc_query = tt3650_rc_query,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ },
+
.num_adapters = 1,
.adapter = {
{
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 5c9f3275aaa0..7890e75600df 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -174,7 +174,7 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct ir_scancode ir_codes_vp702x_table[] = {
+static struct rc_map_table rc_map_vp702x_table[] = {
{ 0x0001, KEY_1 },
{ 0x0002, KEY_2 },
};
@@ -197,10 +197,10 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
- if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
+ if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp702x_table[i].keycode;
+ *event = rc_map_vp702x_table[i].keycode;
break;
}
return 0;
@@ -284,8 +284,8 @@ static struct dvb_usb_device_properties vp702x_properties = {
.read_mac_address = vp702x_read_mac_addr,
.rc.legacy = {
- .rc_key_map = ir_codes_vp702x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp702x_table),
+ .rc_map_table = rc_map_vp702x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table),
.rc_interval = 400,
.rc_query = vp702x_rc_query,
},
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index f13791ca5994..ab0ab3c35e80 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -99,7 +99,7 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded. */
-static struct ir_scancode ir_codes_vp7045_table[] = {
+static struct rc_map_table rc_map_vp7045_table[] = {
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
{ 0x0003, KEY_1 },
@@ -165,10 +165,10 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
- if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++)
+ if (rc5_data(&rc_map_vp7045_table[i]) == key) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp7045_table[i].keycode;
+ *event = rc_map_vp7045_table[i].keycode;
break;
}
return 0;
@@ -261,8 +261,8 @@ static struct dvb_usb_device_properties vp7045_properties = {
.rc.legacy = {
.rc_interval = 400,
- .rc_key_map = ir_codes_vp7045_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp7045_table),
+ .rc_map_table = rc_map_vp7045_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table),
.rc_query = vp7045_rc_query,
},
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index e9062b08a485..ef3e43a03199 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -12,9 +12,8 @@ config DVB_FE_CUSTOMISE
If unsure say N.
-if DVB_FE_CUSTOMISE
-
menu "Customise DVB Frontends"
+ visible if DVB_FE_CUSTOMISE
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
@@ -498,7 +497,7 @@ comment "ISDB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_S921
- tristate "Sharp S921 tuner"
+ tristate "Sharp S921 frontend"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -513,6 +512,14 @@ config DVB_DIB8000
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
Say Y when you want to support this frontend.
+config DVB_MB86A20S
+ tristate "Fujitsu mb86a20s"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
+ Say Y when you want to support this frontend.
+
comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE
@@ -619,5 +626,3 @@ config DVB_DUMMY_FE
tristate "Dummy frontend driver"
default n
endmenu
-
-endif
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 9a31985c0dfb..b1d9525aa7e3 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -5,7 +5,6 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
-s921-objs := s921_module.o s921_core.o
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
au8522-objs = au8522_dig.o au8522_decoder.o
@@ -82,4 +81,5 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index e2a95c07bab4..ce222055526d 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -964,7 +964,7 @@ error:
static int af9013_update_signal_strength(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
+ int ret = 0;
u8 rf_gain, if_gain;
int signal_strength;
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 43aac2f85c2e..1539ea1f81ac 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -50,8 +50,7 @@ static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
msg2.addr = dev_addr;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg1, 1);
if (ret != 1)
@@ -77,8 +76,7 @@ static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, &msg1, 1);
if (ret != 1) {
- dprintk(KERN_DEBUG "%s: error reg=0x%04x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
return -EIO;
}
@@ -88,7 +86,7 @@ static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
*p_data = buf2[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
+ dprintk("%s: reg=0x%04X, data=0x%02X\n",
__func__, reg, buf2[0]);
return 0;
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 6d9c5943eb3d..b537891a4cc9 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -278,10 +278,18 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
- AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
- AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+ if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+ input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
+ } else {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+ }
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
@@ -347,9 +355,11 @@ static void au8522_setup_cvbs_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+ /* PGA in automatic mode */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
- au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+ /* Enable clamping control */
+ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
@@ -366,14 +376,14 @@ static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
- /* It's not clear why they turn off the PGA before enabling the clamp
- control, but the Windows trace does it so we will too... */
+ /* It's not clear why we have to have the PGA in automatic mode while
+ enabling clamp control, but it's what Windows does */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
/* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
- /* Turn on the PGA */
+ /* Disable automatic PGA (since the CVBS is coming from the tuner) */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
@@ -396,7 +406,10 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
- /* Disable clamping control (required for S-video) */
+ /* PGA in automatic mode */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+ /* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
setup_decoder_defaults(state,
@@ -410,29 +423,15 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
static void disable_audio_input(struct au8522_state *state)
{
- /* This can probably be optimized */
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
-
- au8522_writereg(state, AU8522_ENA_USB_REG101H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
- au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
- au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x40);
-
- au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x11);
- msleep(5);
- au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x00);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
- au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
}
/* 0=disable, 1=SIF */
@@ -622,7 +621,7 @@ static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
return v4l2_ctrl_query_fill(qc, 0, 255, 1,
AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
case V4L2_CID_SATURATION:
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
case V4L2_CID_HUE:
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index 609cf04bc312..751e17d692a9 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -397,7 +397,9 @@ void au8522_release_state(struct au8522_state *state);
#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a
#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15
#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index 0f09fd31cb29..c7f5ccf54aa5 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -805,7 +805,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
value = 0;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
- case /* 4K MODE */ 255: value |= (2 << 7); break;
+ case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
@@ -866,7 +866,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
/* P_dvsy_sync_wait */
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
- case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_4K: value = 128; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
@@ -1020,7 +1020,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (6 << 8) | 0x80;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
- case /* 4K MODE */ 255: value |= (8 << 12); break;
+ case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
default:
case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
}
@@ -1030,7 +1030,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
- case /* 4K MODE */ 255: value |= 0x7; break;
+ case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
@@ -1040,7 +1040,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
- case /* 4K MODE */ 255: value |= 0x7; break;
+ case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 3aed0d433921..6aa02cb80733 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -717,7 +717,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value = 0;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
- case /* 4K MODE */ 255: value |= (2 << 7); break;
+ case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
@@ -770,7 +770,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
/* P_dvsy_sync_wait */
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
- case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_4K: value = 128; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
@@ -994,7 +994,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (6 << 8) | 0x80;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
- case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+ case TRANSMISSION_MODE_4K: tmp |= (8 << 12); break;
default:
case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
}
@@ -1004,7 +1004,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
- case /* 4K MODE */ 255: tmp |= 0x7; break;
+ case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
@@ -1014,7 +1014,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
- case /* 4K MODE */ 255: tmp |= 0x7; break;
+ case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index a4991026254d..2311c0a3406c 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -130,6 +130,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct dibx000_i2c_master *mst)
{
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
+ i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
if (i2c_add_adapter(i2c_adap) < 0)
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
index 55f2eba7bc96..6360c681ded9 100644
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -72,7 +72,7 @@ static int ix2505v_read_status_reg(struct ix2505v_state *state)
ret = i2c_transfer(state->i2c, msg, 1);
deb_i2c("Read %s ", __func__);
- return (ret = 1) ? (int) b2[0] : -1;
+ return (ret == 1) ? (int) b2[0] : -1;
}
static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index 0fcddc4569d2..1172b54689f8 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -60,13 +60,12 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
msg.addr += 0x02;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg, 1);
if (ret != 1)
- dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
__func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
@@ -91,15 +90,13 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret != 2) {
- dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
return -1;
}
*p_data = b1[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, b1[0]);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
return 0;
}
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c
new file mode 100644
index 000000000000..d3ad3e75a35a
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a20s.c
@@ -0,0 +1,615 @@
+/*
+ * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * FIXME: Need to port to DVB v5.2 API
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "mb86a20s.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...) do { \
+ printk(KERN_ERR "mb86a20s: " args); \
+} while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct mb86a20s_state {
+ struct i2c_adapter *i2c;
+ const struct mb86a20s_config *config;
+
+ struct dvb_frontend frontend;
+};
+
+struct regdata {
+ u8 reg;
+ u8 data;
+};
+
+/*
+ * Initialization sequence: Use whatevere default values that PV SBTVD
+ * does on its initialisation, obtained via USB snoop
+ */
+static struct regdata mb86a20s_init[] = {
+ { 0x70, 0x0f },
+ { 0x70, 0xff },
+ { 0x08, 0x01 },
+ { 0x09, 0x3e },
+ { 0x50, 0xd1 },
+ { 0x51, 0x22 },
+ { 0x39, 0x01 },
+ { 0x71, 0x00 },
+ { 0x28, 0x2a },
+ { 0x29, 0x00 },
+ { 0x2a, 0xff },
+ { 0x2b, 0x80 },
+ { 0x28, 0x20 },
+ { 0x29, 0x33 },
+ { 0x2a, 0xdf },
+ { 0x2b, 0xa9 },
+ { 0x3b, 0x21 },
+ { 0x3c, 0x3a },
+ { 0x01, 0x0d },
+ { 0x04, 0x08 },
+ { 0x05, 0x05 },
+ { 0x04, 0x0e },
+ { 0x05, 0x00 },
+ { 0x04, 0x0f },
+ { 0x05, 0x14 },
+ { 0x04, 0x0b },
+ { 0x05, 0x8c },
+ { 0x04, 0x00 },
+ { 0x05, 0x00 },
+ { 0x04, 0x01 },
+ { 0x05, 0x07 },
+ { 0x04, 0x02 },
+ { 0x05, 0x0f },
+ { 0x04, 0x03 },
+ { 0x05, 0xa0 },
+ { 0x04, 0x09 },
+ { 0x05, 0x00 },
+ { 0x04, 0x0a },
+ { 0x05, 0xff },
+ { 0x04, 0x27 },
+ { 0x05, 0x64 },
+ { 0x04, 0x28 },
+ { 0x05, 0x00 },
+ { 0x04, 0x1e },
+ { 0x05, 0xff },
+ { 0x04, 0x29 },
+ { 0x05, 0x0a },
+ { 0x04, 0x32 },
+ { 0x05, 0x0a },
+ { 0x04, 0x14 },
+ { 0x05, 0x02 },
+ { 0x04, 0x04 },
+ { 0x05, 0x00 },
+ { 0x04, 0x05 },
+ { 0x05, 0x22 },
+ { 0x04, 0x06 },
+ { 0x05, 0x0e },
+ { 0x04, 0x07 },
+ { 0x05, 0xd8 },
+ { 0x04, 0x12 },
+ { 0x05, 0x00 },
+ { 0x04, 0x13 },
+ { 0x05, 0xff },
+ { 0x52, 0x01 },
+ { 0x50, 0xa7 },
+ { 0x51, 0x00 },
+ { 0x50, 0xa8 },
+ { 0x51, 0xff },
+ { 0x50, 0xa9 },
+ { 0x51, 0xff },
+ { 0x50, 0xaa },
+ { 0x51, 0x00 },
+ { 0x50, 0xab },
+ { 0x51, 0xff },
+ { 0x50, 0xac },
+ { 0x51, 0xff },
+ { 0x50, 0xad },
+ { 0x51, 0x00 },
+ { 0x50, 0xae },
+ { 0x51, 0xff },
+ { 0x50, 0xaf },
+ { 0x51, 0xff },
+ { 0x5e, 0x07 },
+ { 0x50, 0xdc },
+ { 0x51, 0x01 },
+ { 0x50, 0xdd },
+ { 0x51, 0xf4 },
+ { 0x50, 0xde },
+ { 0x51, 0x01 },
+ { 0x50, 0xdf },
+ { 0x51, 0xf4 },
+ { 0x50, 0xe0 },
+ { 0x51, 0x01 },
+ { 0x50, 0xe1 },
+ { 0x51, 0xf4 },
+ { 0x50, 0xb0 },
+ { 0x51, 0x07 },
+ { 0x50, 0xb2 },
+ { 0x51, 0xff },
+ { 0x50, 0xb3 },
+ { 0x51, 0xff },
+ { 0x50, 0xb4 },
+ { 0x51, 0xff },
+ { 0x50, 0xb5 },
+ { 0x51, 0xff },
+ { 0x50, 0xb6 },
+ { 0x51, 0xff },
+ { 0x50, 0xb7 },
+ { 0x51, 0xff },
+ { 0x50, 0x50 },
+ { 0x51, 0x02 },
+ { 0x50, 0x51 },
+ { 0x51, 0x04 },
+ { 0x45, 0x04 },
+ { 0x48, 0x04 },
+ { 0x50, 0xd5 },
+ { 0x51, 0x01 }, /* Serial */
+ { 0x50, 0xd6 },
+ { 0x51, 0x1f },
+ { 0x50, 0xd2 },
+ { 0x51, 0x03 },
+ { 0x50, 0xd7 },
+ { 0x51, 0x3f },
+ { 0x1c, 0x01 },
+ { 0x28, 0x06 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x03 },
+ { 0x28, 0x07 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0d },
+ { 0x28, 0x08 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x02 },
+ { 0x28, 0x09 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x01 },
+ { 0x28, 0x0a },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x21 },
+ { 0x28, 0x0b },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x29 },
+ { 0x28, 0x0c },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x16 },
+ { 0x28, 0x0d },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x31 },
+ { 0x28, 0x0e },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0e },
+ { 0x28, 0x0f },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x4e },
+ { 0x28, 0x10 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x46 },
+ { 0x28, 0x11 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0f },
+ { 0x28, 0x12 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x56 },
+ { 0x28, 0x13 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x35 },
+ { 0x28, 0x14 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0xbe },
+ { 0x28, 0x15 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0x84 },
+ { 0x28, 0x16 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x03 },
+ { 0x2b, 0xee },
+ { 0x28, 0x17 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x98 },
+ { 0x28, 0x18 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x9f },
+ { 0x28, 0x19 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x07 },
+ { 0x2b, 0xb2 },
+ { 0x28, 0x1a },
+ { 0x29, 0x00 },
+ { 0x2a, 0x06 },
+ { 0x2b, 0xc2 },
+ { 0x28, 0x1b },
+ { 0x29, 0x00 },
+ { 0x2a, 0x07 },
+ { 0x2b, 0x4a },
+ { 0x28, 0x1c },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0xbc },
+ { 0x28, 0x1d },
+ { 0x29, 0x00 },
+ { 0x2a, 0x04 },
+ { 0x2b, 0xba },
+ { 0x28, 0x1e },
+ { 0x29, 0x00 },
+ { 0x2a, 0x06 },
+ { 0x2b, 0x14 },
+ { 0x50, 0x1e },
+ { 0x51, 0x5d },
+ { 0x50, 0x22 },
+ { 0x51, 0x00 },
+ { 0x50, 0x23 },
+ { 0x51, 0xc8 },
+ { 0x50, 0x24 },
+ { 0x51, 0x00 },
+ { 0x50, 0x25 },
+ { 0x51, 0xf0 },
+ { 0x50, 0x26 },
+ { 0x51, 0x00 },
+ { 0x50, 0x27 },
+ { 0x51, 0xc3 },
+ { 0x50, 0x39 },
+ { 0x51, 0x02 },
+ { 0x50, 0xd5 },
+ { 0x51, 0x01 },
+ { 0xd0, 0x00 },
+};
+
+static struct regdata mb86a20s_reset_reception[] = {
+ { 0x70, 0xf0 },
+ { 0x70, 0xff },
+ { 0x08, 0x01 },
+ { 0x08, 0x00 },
+};
+
+static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
+ u8 i2c_addr, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+ };
+ int rc;
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+ if (rc != 1) {
+ printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, rc, reg, data);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state,
+ u8 i2c_addr, struct regdata *rd, int size)
+{
+ int i, rc;
+
+ for (i = 0; i < size; i++) {
+ rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg,
+ rd[i].data);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
+ u8 i2c_addr, u8 reg)
+{
+ u8 val;
+ int rc;
+ struct i2c_msg msg[] = {
+ { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ };
+
+ rc = i2c_transfer(state->i2c, msg, 2);
+
+ if (rc != 2) {
+ rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+ return rc;
+ }
+
+ return val;
+}
+
+#define mb86a20s_readreg(state, reg) \
+ mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
+#define mb86a20s_writereg(state, reg, val) \
+ mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
+#define mb86a20s_writeregdata(state, regdata) \
+ mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
+ regdata, ARRAY_SIZE(regdata))
+
+static int mb86a20s_initfe(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+ u8 regD5 = 1;
+
+ dprintk("\n");
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Initialize the frontend */
+ rc = mb86a20s_writeregdata(state, mb86a20s_init);
+ if (rc < 0)
+ return rc;
+
+ if (!state->config->is_serial) {
+ regD5 &= ~1;
+
+ rc = mb86a20s_writereg(state, 0x50, 0xd5);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, regD5);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+
+static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ unsigned rf_max, rf_min, rf;
+ u8 val;
+
+ dprintk("\n");
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Does a binary search to get RF strength */
+ rf_max = 0xfff;
+ rf_min = 0;
+ do {
+ rf = (rf_max + rf_min) / 2;
+ mb86a20s_writereg(state, 0x04, 0x1f);
+ mb86a20s_writereg(state, 0x05, rf >> 8);
+ mb86a20s_writereg(state, 0x04, 0x20);
+ mb86a20s_writereg(state, 0x04, rf);
+
+ val = mb86a20s_readreg(state, 0x02);
+ if (val & 0x08)
+ rf_min = (rf_max + rf_min) / 2;
+ else
+ rf_max = (rf_max + rf_min) / 2;
+ if (rf_max - rf_min < 4) {
+ *strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
+ break;
+ }
+ } while (1);
+
+ dprintk("signal strength = %d\n", *strength);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+
+static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u8 val;
+
+ dprintk("\n");
+ *status = 0;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ val = mb86a20s_readreg(state, 0x0a) & 0xf;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (val >= 2)
+ *status |= FE_HAS_SIGNAL;
+
+ if (val >= 4)
+ *status |= FE_HAS_CARRIER;
+
+ if (val >= 5)
+ *status |= FE_HAS_VITERBI;
+
+ if (val >= 7)
+ *status |= FE_HAS_SYNC;
+
+ if (val >= 8) /* Maybe 9? */
+ *status |= FE_HAS_LOCK;
+
+ dprintk("val = %d, status = 0x%02x\n", val, *status);
+
+ return 0;
+}
+
+static int mb86a20s_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ 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);
+ rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+
+ /* FIXME: For now, it does nothing */
+
+ fe->dtv_property_cache.bandwidth_hz = 6000000;
+ fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+ fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+ fe->dtv_property_cache.isdbt_partial_reception = 0;
+
+ return 0;
+}
+
+static int mb86a20s_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status)
+{
+ int rc = 0;
+
+ dprintk("\n");
+
+ if (params != NULL)
+ rc = mb86a20s_set_frontend(fe, params);
+
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ mb86a20s_read_status(fe, status);
+
+ return rc;
+}
+
+static void mb86a20s_release(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+
+ dprintk("\n");
+
+ kfree(state);
+}
+
+static struct dvb_frontend_ops mb86a20s_ops;
+
+struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+ struct i2c_adapter *i2c)
+{
+ u8 rev;
+
+ /* allocate memory for the internal state */
+ struct mb86a20s_state *state =
+ kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
+
+ dprintk("\n");
+ if (state == NULL) {
+ rc("Unable to kzalloc\n");
+ goto error;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &mb86a20s_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* Check if it is a mb86a20s frontend */
+ rev = mb86a20s_readreg(state, 0);
+
+ if (rev == 0x13) {
+ printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
+ } else {
+ printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
+ rev);
+ goto error;
+ }
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(mb86a20s_attach);
+
+static struct dvb_frontend_ops mb86a20s_ops = {
+ /* Use dib8000 values per default */
+ .info = {
+ .name = "Fujitsu mb86A20s",
+ .type = FE_OFDM,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
+ 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_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+ /* Actually, those values depend on the used tuner */
+ .frequency_min = 45000000,
+ .frequency_max = 864000000,
+ .frequency_stepsize = 62500,
+ },
+
+ .release = mb86a20s_release,
+
+ .init = mb86a20s_initfe,
+ .set_frontend = mb86a20s_set_frontend,
+ .get_frontend = mb86a20s_get_frontend,
+ .read_status = mb86a20s_read_status,
+ .read_signal_strength = mb86a20s_read_signal_strength,
+ .tune = mb86a20s_tune,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mb86a20s.h b/drivers/media/dvb/frontends/mb86a20s.h
new file mode 100644
index 000000000000..bf22e77888b9
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a20s.h
@@ -0,0 +1,52 @@
+/*
+ * Fujitsu mb86a20s driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 MB86A20S_H
+#define MB86A20S_H
+
+#include <linux/dvb/frontend.h>
+
+/**
+ * struct mb86a20s_config - Define the per-device attributes of the frontend
+ *
+ * @demod_address: the demodulator's i2c address
+ */
+
+struct mb86a20s_config {
+ u8 demod_address;
+ bool is_serial;
+};
+
+#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *mb86a20s_attach(
+ const struct mb86a20s_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static struct i2c_adapter *
+ mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* MB86A20S */
diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c
new file mode 100644
index 000000000000..ca0103d5f148
--- /dev/null
+++ b/drivers/media/dvb/frontends/s921.c
@@ -0,0 +1,548 @@
+/*
+ * Sharp VA3A5JZ921 One Seg Broadcast Module driver
+ * This device is labeled as just S. 921 at the top of the frontend can
+ *
+ * Copyright (C) 2009-2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * Developed for Leadership SBTVD 1seg device sold in Brazil
+ *
+ * Frontend module based on cx24123 driver, getting some info from
+ * the old s921 driver.
+ *
+ * FIXME: Need to port to DVB v5.2 API
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "s921.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...) do { \
+ printk(KERN_ERR "s921: " args); \
+} while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "s921: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct s921_state {
+ struct i2c_adapter *i2c;
+ const struct s921_config *config;
+
+ struct dvb_frontend frontend;
+
+ /* The Demod can't easily provide these, we cache them */
+ u32 currentfreq;
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct s921_bandselect_val {
+ u32 freq_low;
+ u8 band_reg;
+} s921_bandselect[] = {
+ { 0, 0x7b },
+ { 485140000, 0x5b },
+ { 515140000, 0x3b },
+ { 545140000, 0x1b },
+ { 599140000, 0xfb },
+ { 623140000, 0xdb },
+ { 659140000, 0xbb },
+ { 713140000, 0x9b },
+};
+
+struct regdata {
+ u8 reg;
+ u8 data;
+};
+
+static struct regdata s921_init[] = {
+ { 0x01, 0x80 }, /* Probably, a reset sequence */
+ { 0x01, 0x40 },
+ { 0x01, 0x80 },
+ { 0x01, 0x40 },
+
+ { 0x02, 0x00 },
+ { 0x03, 0x40 },
+ { 0x04, 0x01 },
+ { 0x05, 0x00 },
+ { 0x06, 0x00 },
+ { 0x07, 0x00 },
+ { 0x08, 0x00 },
+ { 0x09, 0x00 },
+ { 0x0a, 0x00 },
+ { 0x0b, 0x5a },
+ { 0x0c, 0x00 },
+ { 0x0d, 0x00 },
+ { 0x0f, 0x00 },
+ { 0x13, 0x1b },
+ { 0x14, 0x80 },
+ { 0x15, 0x40 },
+ { 0x17, 0x70 },
+ { 0x18, 0x01 },
+ { 0x19, 0x12 },
+ { 0x1a, 0x01 },
+ { 0x1b, 0x12 },
+ { 0x1c, 0xa0 },
+ { 0x1d, 0x00 },
+ { 0x1e, 0x0a },
+ { 0x1f, 0x08 },
+ { 0x20, 0x40 },
+ { 0x21, 0xff },
+ { 0x22, 0x4c },
+ { 0x23, 0x4e },
+ { 0x24, 0x4c },
+ { 0x25, 0x00 },
+ { 0x26, 0x00 },
+ { 0x27, 0xf4 },
+ { 0x28, 0x60 },
+ { 0x29, 0x88 },
+ { 0x2a, 0x40 },
+ { 0x2b, 0x40 },
+ { 0x2c, 0xff },
+ { 0x2d, 0x00 },
+ { 0x2e, 0xff },
+ { 0x2f, 0x00 },
+ { 0x30, 0x20 },
+ { 0x31, 0x06 },
+ { 0x32, 0x0c },
+ { 0x34, 0x0f },
+ { 0x37, 0xfe },
+ { 0x38, 0x00 },
+ { 0x39, 0x63 },
+ { 0x3a, 0x10 },
+ { 0x3b, 0x10 },
+ { 0x47, 0x00 },
+ { 0x49, 0xe5 },
+ { 0x4b, 0x00 },
+ { 0x50, 0xc0 },
+ { 0x52, 0x20 },
+ { 0x54, 0x5a },
+ { 0x55, 0x5b },
+ { 0x56, 0x40 },
+ { 0x57, 0x70 },
+ { 0x5c, 0x50 },
+ { 0x5d, 0x00 },
+ { 0x62, 0x17 },
+ { 0x63, 0x2f },
+ { 0x64, 0x6f },
+ { 0x68, 0x00 },
+ { 0x69, 0x89 },
+ { 0x6a, 0x00 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x00 },
+ { 0x6d, 0x00 },
+ { 0x6e, 0x00 },
+ { 0x70, 0x10 },
+ { 0x71, 0x00 },
+ { 0x75, 0x00 },
+ { 0x76, 0x30 },
+ { 0x77, 0x01 },
+ { 0xaf, 0x00 },
+ { 0xb0, 0xa0 },
+ { 0xb2, 0x3d },
+ { 0xb3, 0x25 },
+ { 0xb4, 0x8b },
+ { 0xb5, 0x4b },
+ { 0xb6, 0x3f },
+ { 0xb7, 0xff },
+ { 0xb8, 0xff },
+ { 0xb9, 0xfc },
+ { 0xba, 0x00 },
+ { 0xbb, 0x00 },
+ { 0xbc, 0x00 },
+ { 0xd0, 0x30 },
+ { 0xe4, 0x84 },
+ { 0xf0, 0x48 },
+ { 0xf1, 0x19 },
+ { 0xf2, 0x5a },
+ { 0xf3, 0x8e },
+ { 0xf4, 0x2d },
+ { 0xf5, 0x07 },
+ { 0xf6, 0x5a },
+ { 0xf7, 0xba },
+ { 0xf8, 0xd7 },
+};
+
+static struct regdata s921_prefreq[] = {
+ { 0x47, 0x60 },
+ { 0x68, 0x00 },
+ { 0x69, 0x89 },
+ { 0xf0, 0x48 },
+ { 0xf1, 0x19 },
+};
+
+static struct regdata s921_postfreq[] = {
+ { 0xf5, 0xae },
+ { 0xf6, 0xb7 },
+ { 0xf7, 0xba },
+ { 0xf8, 0xd7 },
+ { 0x68, 0x0a },
+ { 0x69, 0x09 },
+};
+
+static int s921_i2c_writereg(struct s921_state *state,
+ u8 i2c_addr, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+ };
+ int rc;
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+ if (rc != 1) {
+ printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, rc, reg, data);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
+ struct regdata *rd, int size)
+{
+ int i, rc;
+
+ for (i = 0; i < size; i++) {
+ rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
+{
+ u8 val;
+ int rc;
+ struct i2c_msg msg[] = {
+ { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ };
+
+ rc = i2c_transfer(state->i2c, msg, 2);
+
+ if (rc != 2) {
+ rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+ return rc;
+ }
+
+ return val;
+}
+
+#define s921_readreg(state, reg) \
+ s921_i2c_readreg(state, state->config->demod_address, reg)
+#define s921_writereg(state, reg, val) \
+ s921_i2c_writereg(state, state->config->demod_address, reg, val)
+#define s921_writeregdata(state, regdata) \
+ s921_i2c_writeregdata(state, state->config->demod_address, \
+ regdata, ARRAY_SIZE(regdata))
+
+static int s921_pll_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int band, rc, i;
+ unsigned long f_offset;
+ u8 f_switch;
+ u64 offset;
+
+ dprintk("frequency=%i\n", p->frequency);
+
+ for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
+ if (p->frequency < s921_bandselect[band].freq_low)
+ break;
+ band--;
+
+ if (band < 0) {
+ rc("%s: frequency out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ f_switch = s921_bandselect[band].band_reg;
+
+ offset = ((u64)p->frequency) * 258;
+ do_div(offset, 6000000);
+ f_offset = ((unsigned long)offset) + 2321;
+
+ rc = s921_writeregdata(state, s921_prefreq);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf3, f_offset & 0xff);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf4, f_switch);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writeregdata(state, s921_postfreq);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0 ; i < 6; i++) {
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+ }
+ rc = s921_writereg(state, 0x01, 0x40);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_readreg(state, 0x01);
+ dprintk("status 0x01: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x32);
+ dprintk("status 0x32: %02x\n", rc);
+
+ dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
+
+ return 0;
+}
+
+static int s921_initfe(struct dvb_frontend *fe)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ rc = s921_writeregdata(state, s921_init);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int regstatus, rc;
+
+ *status = 0;
+
+ rc = s921_readreg(state, 0x81);
+ if (rc < 0)
+ return rc;
+
+ regstatus = rc << 8;
+
+ rc = s921_readreg(state, 0x82);
+ if (rc < 0)
+ return rc;
+
+ regstatus |= rc;
+
+ dprintk("status = %04x\n", regstatus);
+
+ /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
+ if ((regstatus & 0xff) == 0x40) {
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ } else if (regstatus & 0x40) {
+ /* This is close to Full Sync, but not enough to get useful info */
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC;
+ }
+
+ return 0;
+}
+
+static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ fe_status_t status;
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ /* FIXME: Use the proper register for it... 0x80? */
+ rc = s921_read_status(fe, &status);
+ if (rc < 0)
+ return rc;
+
+ *strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
+
+ dprintk("strength = 0x%04x\n", *strength);
+
+ rc = s921_readreg(state, 0x01);
+ dprintk("status 0x01: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x32);
+ dprintk("status 0x32: %02x\n", rc);
+
+ return 0;
+}
+
+static int s921_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ /* FIXME: We don't know how to use non-auto mode */
+
+ rc = s921_pll_tune(fe, p);
+ if (rc < 0)
+ return rc;
+
+ state->currentfreq = p->frequency;
+
+ return 0;
+}
+
+static int s921_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+
+ /* FIXME: Probably it is possible to get it from regs f1 and f2 */
+ p->frequency = state->currentfreq;
+
+ return 0;
+}
+
+static int s921_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status)
+{
+ int rc = 0;
+
+ dprintk("\n");
+
+ if (params != NULL)
+ rc = s921_set_frontend(fe, params);
+
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ s921_read_status(fe, status);
+
+ return rc;
+}
+
+static int s921_get_algo(struct dvb_frontend *fe)
+{
+ return 1; /* FE_ALGO_HW */
+}
+
+static void s921_release(struct dvb_frontend *fe)
+{
+ struct s921_state *state = fe->demodulator_priv;
+
+ dprintk("\n");
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s921_ops;
+
+struct dvb_frontend *s921_attach(const struct s921_config *config,
+ struct i2c_adapter *i2c)
+{
+ /* allocate memory for the internal state */
+ struct s921_state *state =
+ kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+
+ dprintk("\n");
+ if (state == NULL) {
+ rc("Unable to kzalloc\n");
+ goto rcor;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s921_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+
+rcor:
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(s921_attach);
+
+static struct dvb_frontend_ops s921_ops = {
+ /* Use dib8000 values per default */
+ .info = {
+ .name = "Sharp S921",
+ .type = FE_OFDM,
+ .frequency_min = 470000000,
+ /*
+ * Max should be 770MHz instead, according with Sharp docs,
+ * but Leadership doc says it works up to 806 MHz. This is
+ * required to get channel 69, used in Brazil
+ */
+ .frequency_max = 806000000,
+ .frequency_tolerance = 0,
+ .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 = s921_release,
+
+ .init = s921_initfe,
+ .set_frontend = s921_set_frontend,
+ .get_frontend = s921_get_frontend,
+ .read_status = s921_read_status,
+ .read_signal_strength = s921_read_signal_strength,
+ .tune = s921_tune,
+ .get_frontend_algo = s921_get_algo,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921.h b/drivers/media/dvb/frontends/s921.h
new file mode 100644
index 000000000000..f220d8299c81
--- /dev/null
+++ b/drivers/media/dvb/frontends/s921.h
@@ -0,0 +1,47 @@
+/*
+ * Sharp s921 driver
+ *
+ * Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 S921_H
+#define S921_H
+
+#include <linux/dvb/frontend.h>
+
+struct s921_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *s921_attach(const struct s921_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *s921_attach(
+ const struct s921_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static struct i2c_adapter *
+ s921_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* S921_H */
diff --git a/drivers/media/dvb/frontends/s921_core.c b/drivers/media/dvb/frontends/s921_core.c
deleted file mode 100644
index 974b52be9aea..000000000000
--- a/drivers/media/dvb/frontends/s921_core.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Driver for Sharp s921 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "s921_core.h"
-
-static int s921_isdb_init(struct s921_isdb_t *dev);
-static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
-static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
-static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
-
-static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
- 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
- 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
- 0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
- 0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
- 0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
- 0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
- 0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
- 0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
- 0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
- 0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
- 0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
- 0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
- 0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
- 0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
- 0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
- 0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
- 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
- 0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
- 0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
- 0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
- 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
- 0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
- 0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
- 0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
- 0xf8, 0xd7 };
-
-static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
- 0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
- 0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
- 0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
- 0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
- 0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
- 0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
- 0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
- 0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
- 0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
- 0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
- 0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
- 0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
- 0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
- 0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
- 0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
- 0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
-
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
- switch(cmd) {
- case ISDB_T_CMD_INIT:
- s921_isdb_init(dev);
- break;
- case ISDB_T_CMD_SET_PARAM:
- s921_isdb_set_parameters(dev, data);
- break;
- case ISDB_T_CMD_TUNE:
- s921_isdb_tune(dev, data);
- break;
- case ISDB_T_CMD_GET_STATUS:
- s921_isdb_get_status(dev, data);
- break;
- default:
- printk("unhandled command\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int s921_isdb_init(struct s921_isdb_t *dev) {
- unsigned int i;
- unsigned int ret;
- printk("isdb_init\n");
- for (i = 0; i < sizeof(init_table); i+=2) {
- ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
- if (ret != 0) {
- printk("i2c write failed\n");
- return ret;
- }
- }
- return 0;
-}
-
-static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
-
- int ret;
- /* auto is sufficient for now, lateron this should be reflected in an extra interface */
-
-
-
- ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
- ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
-
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
- if (ret < 0)
- return -EINVAL;
-
- return E_OK;
-}
-
-static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
-
- int ret;
- int index;
-
- index = (params->frequency - 473143000)/6000000;
-
- if (index > 48) {
- return -EINVAL;
- }
-
- dev->i2c_write(dev->priv_dev, 0x47, 0x60);
-
- ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
- if (ret < 0)
- return -EINVAL;
-
- dev->i2c_write(dev->priv_dev, 0x01, 0x40);
- return 0;
-}
-
-static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
- unsigned int *ret = (unsigned int*)data;
- u8 ifagc_dt;
- u8 rfagc_dt;
-
- mdelay(10);
- ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
- rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
- if (rfagc_dt == 0x40) {
- *ret = 1;
- }
- return 0;
-}
diff --git a/drivers/media/dvb/frontends/s921_core.h b/drivers/media/dvb/frontends/s921_core.h
deleted file mode 100644
index de2f10a44e72..000000000000
--- a/drivers/media/dvb/frontends/s921_core.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _S921_CORE_H
-#define _S921_CORE_H
-//#define u8 unsigned int
-//#define u32 unsigned int
-
-
-
-//#define EINVAL -1
-#define E_OK 0
-
-struct s921_isdb_t {
- void *priv_dev;
- int (*i2c_write)(void *dev, u8 reg, u8 val);
- int (*i2c_read)(void *dev, u8 reg);
-};
-
-#define ISDB_T_CMD_INIT 0
-#define ISDB_T_CMD_SET_PARAM 1
-#define ISDB_T_CMD_TUNE 2
-#define ISDB_T_CMD_GET_STATUS 3
-
-struct s921_isdb_t_tune_params {
- u32 frequency;
-};
-
-struct s921_isdb_t_status {
-};
-
-struct s921_isdb_t_transmission_mode_params {
- u8 mode;
- u8 layer_a_mode;
-#define ISDB_T_LA_MODE_1 0
-#define ISDB_T_LA_MODE_2 1
-#define ISDB_T_LA_MODE_3 2
- u8 layer_a_carrier_modulation;
-#define ISDB_T_LA_CM_DQPSK 0
-#define ISDB_T_LA_CM_QPSK 1
-#define ISDB_T_LA_CM_16QAM 2
-#define ISDB_T_LA_CM_64QAM 3
-#define ISDB_T_LA_CM_NOLAYER 4
- u8 layer_a_code_rate;
-#define ISDB_T_LA_CR_1_2 0
-#define ISDB_T_LA_CR_2_3 1
-#define ISDB_T_LA_CR_3_4 2
-#define ISDB_T_LA_CR_5_6 4
-#define ISDB_T_LA_CR_7_8 8
-#define ISDB_T_LA_CR_NOLAYER 16
- u8 layer_a_time_interleave;
-#define ISDB_T_LA_TI_0 0
-#define ISDB_T_LA_TI_1 1
-#define ISDB_T_LA_TI_2 2
-#define ISDB_T_LA_TI_4 4
-#define ISDB_T_LA_TI_8 8
-#define ISDB_T_LA_TI_16 16
-#define ISDB_T_LA_TI_32 32
- u8 layer_a_nseg;
-
- u8 layer_b_mode;
-#define ISDB_T_LB_MODE_1 0
-#define ISDB_T_LB_MODE_2 1
-#define ISDB_T_LB_MODE_3 2
- u8 layer_b_carrier_modulation;
-#define ISDB_T_LB_CM_DQPSK 0
-#define ISDB_T_LB_CM_QPSK 1
-#define ISDB_T_LB_CM_16QAM 2
-#define ISDB_T_LB_CM_64QAM 3
-#define ISDB_T_LB_CM_NOLAYER 4
- u8 layer_b_code_rate;
-#define ISDB_T_LB_CR_1_2 0
-#define ISDB_T_LB_CR_2_3 1
-#define ISDB_T_LB_CR_3_4 2
-#define ISDB_T_LB_CR_5_6 4
-#define ISDB_T_LB_CR_7_8 8
-#define ISDB_T_LB_CR_NOLAYER 16
- u8 layer_b_time_interleave;
-#define ISDB_T_LB_TI_0 0
-#define ISDB_T_LB_TI_1 1
-#define ISDB_T_LB_TI_2 2
-#define ISDB_T_LB_TI_4 4
-#define ISDB_T_LB_TI_8 8
-#define ISDB_T_LB_TI_16 16
-#define ISDB_T_LB_TI_32 32
- u8 layer_b_nseg;
-
- u8 layer_c_mode;
-#define ISDB_T_LC_MODE_1 0
-#define ISDB_T_LC_MODE_2 1
-#define ISDB_T_LC_MODE_3 2
- u8 layer_c_carrier_modulation;
-#define ISDB_T_LC_CM_DQPSK 0
-#define ISDB_T_LC_CM_QPSK 1
-#define ISDB_T_LC_CM_16QAM 2
-#define ISDB_T_LC_CM_64QAM 3
-#define ISDB_T_LC_CM_NOLAYER 4
- u8 layer_c_code_rate;
-#define ISDB_T_LC_CR_1_2 0
-#define ISDB_T_LC_CR_2_3 1
-#define ISDB_T_LC_CR_3_4 2
-#define ISDB_T_LC_CR_5_6 4
-#define ISDB_T_LC_CR_7_8 8
-#define ISDB_T_LC_CR_NOLAYER 16
- u8 layer_c_time_interleave;
-#define ISDB_T_LC_TI_0 0
-#define ISDB_T_LC_TI_1 1
-#define ISDB_T_LC_TI_2 2
-#define ISDB_T_LC_TI_4 4
-#define ISDB_T_LC_TI_8 8
-#define ISDB_T_LC_TI_16 16
-#define ISDB_T_LC_TI_32 32
- u8 layer_c_nseg;
-};
-
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
-#endif
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
deleted file mode 100644
index 0eefff61cc50..000000000000
--- a/drivers/media/dvb/frontends/s921_module.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Driver for Sharp s921 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- * All rights reserved.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "s921_module.h"
-#include "s921_core.h"
-
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"s921 debugging (default off)");
-
-#define dprintk(fmt, args...) if (debug) do {\
- printk("s921 debug: " fmt, ##args); } while (0)
-
-struct s921_state
-{
- struct dvb_frontend frontend;
- fe_modulation_t current_modulation;
- __u32 snr;
- __u32 current_frequency;
- __u8 addr;
- struct s921_isdb_t dev;
- struct i2c_adapter *i2c;
-};
-
-static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- struct s921_isdb_t_transmission_mode_params params;
- struct s921_isdb_t_tune_params tune_params;
-
- tune_params.frequency = param->frequency;
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
- mdelay(100);
- return 0;
-}
-
-static int s921_init(struct dvb_frontend *fe) {
- printk("s921 init\n");
- return 0;
-}
-
-static int s921_sleep(struct dvb_frontend *fe) {
- printk("s921 sleep\n");
- return 0;
-}
-
-static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- unsigned int ret;
- mdelay(5);
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
- *status = 0;
-
- printk("status: %02x\n", ret);
- if (ret == 1) {
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- }
-
- return 0;
-}
-
-static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
-{
- dprintk("read ber\n");
- return 0;
-}
-
-static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
-{
- dprintk("read snr\n");
- return 0;
-}
-
-static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
-{
- dprintk("read ucblocks\n");
- return 0;
-}
-
-static void s921_release(struct dvb_frontend *fe)
-{
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops demod_s921={
- .info = {
- .name = "SHARP S921",
- .type = FE_OFDM,
- .frequency_min = 473143000,
- .frequency_max = 767143000,
- .frequency_stepsize = 6000000,
- .frequency_tolerance = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_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_HIERARCHY_AUTO | FE_CAN_RECOVER |
- FE_CAN_MUTE_TS
- },
- .init = s921_init,
- .sleep = s921_sleep,
- .set_frontend = s921_set_parameters,
- .read_snr = s921_read_snr,
- .read_ber = s921_read_ber,
- .read_status = s921_read_status,
- .read_ucblocks = s921_read_ucblocks,
- .release = s921_release,
-};
-
-static int s921_write(void *dev, u8 reg, u8 val) {
- struct s921_state *state = dev;
- char buf[2]={reg,val};
- int err;
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 2,
- .buf = buf
- };
-
- if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __func__, err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int s921_read(void *dev, u8 reg) {
- struct s921_state *state = dev;
- u8 b1;
- int ret;
- struct i2c_msg msg[2] = { { .addr = state->addr,
- .flags = 0,
- .buf = &reg, .len = 1 },
- { .addr = state->addr,
- .flags = I2C_M_RD,
- .buf = &b1, .len = 1 } };
-
- ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- return ret;
- return b1;
-}
-
-struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c)
-{
-
- struct s921_state *state;
- state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
-
- state->addr = config->i2c_address;
- state->i2c = i2c;
- state->dev.i2c_write = &s921_write;
- state->dev.i2c_read = &s921_read;
- state->dev.priv_dev = state;
-
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
-
- memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-}
-
-EXPORT_SYMBOL_GPL(s921_attach);
-MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
-MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921_module.h b/drivers/media/dvb/frontends/s921_module.h
deleted file mode 100644
index 78660424ba95..000000000000
--- a/drivers/media/dvb/frontends/s921_module.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Driver for DVB-T s921 demodulator
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.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 S921_MODULE_H
-#define S921_MODULE_H
-
-#include <linux/dvb/frontend.h>
-#include "s921_core.h"
-
-int s921_isdb_init(struct s921_isdb_t *dev);
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
-
-struct s921_config
-{
- /* demodulator's I2C address */
- u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_S921 */
-
-#endif /* S921_H */
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index 8e38fcee564e..37a222d9ddb3 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -714,7 +714,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma
reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-
+ msleep(100);
return 0;
}
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index 80a9e4cba631..64673b8b64a2 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -51,7 +51,7 @@ module_param(verbose, int, 0644);
if (x > y) \
printk(format, ##arg); \
} \
-} while(0)
+} while (0)
struct stb6100_lkup {
u32 val_low;
@@ -117,7 +117,10 @@ static const struct stb6100_regmask stb6100_template[] = {
[STB6100_TEST3] = { 0x00, 0xde },
};
-static void stb6100_normalise_regs(u8 regs[])
+/*
+ * Currently unused. Some boards might need it in the future
+ */
+static inline void stb6100_normalise_regs(u8 regs[])
{
int i;
@@ -157,13 +160,25 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
u8 regs[STB6100_NUMREGS];
int rc;
+ struct i2c_msg msg = {
+ .addr = state->config->tuner_address + reg,
+ .flags = I2C_M_RD,
+ .buf = regs,
+ .len = 1
+ };
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
return -EINVAL;
}
- if ((rc = stb6100_read_regs(state, regs)) < 0)
- return rc;
- return (unsigned int)regs[reg];
+ if (unlikely(verbose > FE_DEBUG)) {
+ dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address);
+ dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]);
+ }
+
+ return (unsigned int)regs[0];
}
static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
@@ -211,20 +226,17 @@ static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
return stb6100_write_reg_range(state, &data, reg, 1);
}
-static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
-{
- stb6100_normalise_regs(regs);
- return stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 1);
-}
static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
{
int rc;
struct stb6100_state *state = fe->tuner_priv;
- if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0)
+ rc = stb6100_read_reg(state, STB6100_LD);
+ if (rc < 0) {
+ dprintk(verbose, FE_ERROR, 1, "%s failed", __func__);
return rc;
-
+ }
return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
}
@@ -234,7 +246,8 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
u8 f;
struct stb6100_state *state = fe->tuner_priv;
- if ((rc = stb6100_read_reg(state, STB6100_F)) < 0)
+ rc = stb6100_read_reg(state, STB6100_F);
+ if (rc < 0)
return rc;
f = rc & STB6100_F_F;
@@ -265,14 +278,21 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
/* Turn on LPF bandwidth setting clock control,
* set bandwidth, wait 10ms, turn off.
*/
- if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0)
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK);
+ if (rc < 0)
return rc;
- if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0)
+ rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp);
+ if (rc < 0)
return rc;
- msleep(1);
- if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0)
+
+ msleep(5); /* This is dangerous as another (related) thread may start */
+
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+ if (rc < 0)
return rc;
+ msleep(10); /* This is dangerous as another (related) thread may start */
+
return 0;
}
@@ -284,7 +304,8 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
struct stb6100_state *state = fe->tuner_priv;
u8 regs[STB6100_NUMREGS];
- if ((rc = stb6100_read_regs(state, regs)) < 0)
+ rc = stb6100_read_regs(state, regs);
+ if (rc < 0)
return rc;
odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
@@ -312,8 +333,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
u8 regs[STB6100_NUMREGS];
u8 g, psd2, odiv;
- if ((rc = stb6100_read_regs(state, regs)) < 0)
- return rc;
+ dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51");
if (fe->ops.get_frontend) {
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
@@ -321,96 +341,140 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
}
srate = p.u.qpsk.symbol_rate;
- regs[STB6100_DLB] = 0xdc;
- /* Disable LPEN */
- regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */
+ /* Set up tuner cleanly, LPF calibration on */
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
+ if (rc < 0)
+ return rc; /* allow LPF calibration */
- if ((rc = stb6100_write_regs(state, regs)) < 0)
+ /* PLL Loop disabled, bias on, VCO on, synth on */
+ regs[STB6100_LPEN] = 0xeb;
+ rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+ if (rc < 0)
return rc;
- /* Baseband gain. */
- if (srate >= 15000000)
- g = 9; // +4 dB
- else if (srate >= 5000000)
- g = 11; // +8 dB
- else
- g = 14; // +14 dB
-
- regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g;
- regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
- regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+ /* Program the registers with their data values */
/* VCO divide ratio (LO divide ratio, VCO prescaler enable). */
if (frequency <= 1075000)
odiv = 1;
else
odiv = 0;
- regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT);
- if ((frequency > 1075000) && (frequency <= 1325000))
- psd2 = 0;
- else
- psd2 = 1;
- regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+ /* VCO enabled, seach clock off as per LL3.7, 3.4.1 */
+ regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT);
/* OSM */
for (ptr = lkup;
(ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
ptr++);
+
if (ptr->val_high == 0) {
printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
return -EINVAL;
}
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
+ return rc;
+ if ((frequency > 1075000) && (frequency <= 1325000))
+ psd2 = 0;
+ else
+ psd2 = 1;
/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */
fvco = frequency << (1 + odiv);
/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */
nint = fvco / (state->reference << psd2);
/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */
nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
- << (9 - psd2),
- state->reference);
+ << (9 - psd2), state->reference);
+
+ /* NI */
+ regs[STB6100_NI] = nint;
+ rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]);
+ if (rc < 0)
+ return rc;
+
+ /* NF */
+ regs[STB6100_NF_LSB] = nfrac;
+ rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]);
+ if (rc < 0)
+ return rc;
+
+ /* K */
+ regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+ regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
+ rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]);
+ if (rc < 0)
+ return rc;
+
+ /* G Baseband gain. */
+ if (srate >= 15000000)
+ g = 9; /* +4 dB */
+ else if (srate >= 5000000)
+ g = 11; /* +8 dB */
+ else
+ g = 14; /* +14 dB */
+
+ regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g;
+ regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
+ regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+ rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]);
+ if (rc < 0)
+ return rc;
+
+ /* F we don't write as it is set up in BW set */
+
+ /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */
+ regs[STB6100_DLB] = 0xcc;
+ rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]);
+ if (rc < 0)
+ return rc;
+
dprintk(verbose, FE_DEBUG, 1,
"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
frequency, srate, (unsigned int)g, (unsigned int)odiv,
(unsigned int)psd2, state->reference,
ptr->reg, fvco, nint, nfrac);
- regs[STB6100_NI] = nint;
- regs[STB6100_NF_LSB] = nfrac;
- regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
- regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */
- regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */
- regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */
- regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */
- /* Power up. */
- regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN;
- msleep(2);
- if ((rc = stb6100_write_regs(state, regs)) < 0)
+ /* Set up the test registers */
+ regs[STB6100_TEST1] = 0x8f;
+ rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]);
+ if (rc < 0)
+ return rc;
+ regs[STB6100_TEST3] = 0xde;
+ rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]);
+ if (rc < 0)
return rc;
- msleep(2);
- regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */
- if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0)
+ /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */
+ regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */
+ rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+ if (rc < 0)
return rc;
+ msleep(2);
+
+ /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */
regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */
- if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
return rc;
- msleep(10); /* wait for LO to lock */
+ msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */
+
regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */
- if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
- return rc;
- regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */
- stb6100_normalise_regs(regs);
- if ((rc = stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 3)) < 0)
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
return rc;
- msleep(100);
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+ if (rc < 0)
+ return rc; /* Stop LPF calibration */
+ msleep(10); /* This is dangerous as another (related) thread may start */
+ /* wait for stabilisation, (should not be necessary) */
return 0;
}
@@ -433,8 +497,8 @@ static int stb6100_init(struct dvb_frontend *fe)
state->bandwidth = status->bandwidth * 1000; /* Hz */
state->reference = status->refclock / 1000; /* kHz */
- /* Set default bandwidth. */
- return stb6100_set_bandwidth(fe, state->bandwidth);
+ /* Set default bandwidth. Modified, PN 13-May-10 */
+ return 0;
}
static int stb6100_get_state(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 425e7a43ae19..4e0fc2c8a41c 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -1483,8 +1483,8 @@ static int stv090x_start_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
goto err;
- if ((state->search_mode == STV090x_DVBS1) ||
- (state->search_mode == STV090x_DSS) ||
+ if ((state->search_mode == STV090x_SEARCH_DVBS1) ||
+ (state->search_mode == STV090x_SEARCH_DSS) ||
(state->search_mode == STV090x_SEARCH_AUTO)) {
if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
@@ -2940,7 +2940,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
break;
- case STV090x_UNKNOWN:
+ case STV090x_ERROR:
default:
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
index fd0830ed10d8..a13a50503134 100644
--- a/drivers/media/dvb/mantis/Kconfig
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -1,6 +1,6 @@
config MANTIS_CORE
tristate "Mantis/Hopper PCI bridge based devices"
- depends on PCI && I2C && INPUT && IR_CORE
+ depends on PCI && I2C && INPUT && RC_CORE
help
Support for PCI cards based on the Mantis and Hopper PCi bridge.
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
index 09e9fc785189..70e73afefb3d 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -251,6 +251,8 @@ static struct pci_device_id hopper_pci_table[] = {
{ }
};
+MODULE_DEVICE_TABLE(pci, hopper_pci_table);
+
static struct pci_driver hopper_pci_driver = {
.name = DRIVER_NAME,
.id_table = hopper_pci_table,
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
index 96674c78e86b..68a29f8bdf73 100644
--- a/drivers/media/dvb/mantis/hopper_vp3028.c
+++ b/drivers/media/dvb/mantis/hopper_vp3028.c
@@ -47,17 +47,17 @@ static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
struct mantis_hwconfig *config = mantis->hwconfig;
int err = 0;
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
err = mantis_frontend_power(mantis, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
err = mantis_frontend_power(mantis, POWER_ON);
if (err == 0) {
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
- fe = zl10353_attach(&hopper_vp3028_config, adapter);
+ fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter);
if (!fe)
return -1;
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
index cf4b39ffdaad..40da225098cc 100644
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -281,6 +281,8 @@ static struct pci_device_id mantis_pci_table[] = {
{ }
};
+MODULE_DEVICE_TABLE(pci, mantis_pci_table);
+
static struct pci_driver mantis_pci_driver = {
.name = DRIVER_NAME,
.id_table = mantis_pci_table,
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
index d0b645a483c9..bd400d21b81f 100644
--- a/drivers/media/dvb/mantis/mantis_common.h
+++ b/drivers/media/dvb/mantis/mantis_common.h
@@ -171,7 +171,9 @@ struct mantis_pci {
struct work_struct uart_work;
spinlock_t uart_lock;
- struct input_dev *rc;
+ struct rc_dev *rc;
+ char input_name[80];
+ char input_phys[80];
};
#define MANTIS_HIF_STATUS (mantis->gpio_status)
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
index 99d82eec3b03..e5180e45d310 100644
--- a/drivers/media/dvb/mantis/mantis_dvb.c
+++ b/drivers/media/dvb/mantis/mantis_dvb.c
@@ -47,15 +47,15 @@ int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
switch (power) {
case POWER_ON:
dprintk(MANTIS_DEBUG, 1, "Power ON");
- gpio_set_bits(mantis, config->power, POWER_ON);
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->power, POWER_ON);
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
msleep(100);
break;
case POWER_OFF:
dprintk(MANTIS_DEBUG, 1, "Power OFF");
- gpio_set_bits(mantis, config->power, POWER_OFF);
+ mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
msleep(100);
break;
@@ -73,13 +73,13 @@ void mantis_frontend_soft_reset(struct mantis_pci *mantis)
struct mantis_hwconfig *config = mantis->hwconfig;
dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
msleep(100);
return;
@@ -117,6 +117,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (mantis->feeds == 1) {
dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
mantis_dma_start(mantis);
+ tasklet_enable(&mantis->tasklet);
}
return mantis->feeds;
@@ -136,6 +137,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
mantis->feeds--;
if (mantis->feeds == 0) {
dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ tasklet_disable(&mantis->tasklet);
mantis_dma_stop(mantis);
}
@@ -216,6 +218,7 @@ int __devinit mantis_dvb_init(struct mantis_pci *mantis)
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ tasklet_disable(&mantis->tasklet);
if (mantis->hwconfig) {
result = config->frontend_init(mantis, mantis->fe);
if (result < 0) {
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
index a7b369a439d6..9f73c2cfc9ea 100644
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -111,7 +111,7 @@ void mantis_evmgr_exit(struct mantis_ca *ca)
struct mantis_pci *mantis = ca->ca_priv;
dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
- flush_scheduled_work();
+ flush_work_sync(&ca->hif_evm_work);
mantis_hif_exit(ca);
mantis_pcmcia_exit(ca);
}
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index a99489b8418b..db6d54d3fec0 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -18,8 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <linux/pci.h>
#include "dmxdev.h"
@@ -33,8 +32,9 @@
#include "mantis_uart.h"
#define MODULE_NAME "mantis_core"
+#define RC_MAP_MANTIS "rc-mantis"
-static struct ir_scancode mantis_ir_table[] = {
+static struct rc_map_table mantis_ir_table[] = {
{ 0x29, KEY_POWER },
{ 0x28, KEY_FAVORITES },
{ 0x30, KEY_TEXT },
@@ -95,53 +95,65 @@ static struct ir_scancode mantis_ir_table[] = {
{ 0x00, KEY_BLUE },
};
-struct ir_scancode_table ir_mantis = {
- .scan = mantis_ir_table,
- .size = ARRAY_SIZE(mantis_ir_table),
+static struct rc_map_list ir_mantis_map = {
+ .map = {
+ .scan = mantis_ir_table,
+ .size = ARRAY_SIZE(mantis_ir_table),
+ .rc_type = RC_TYPE_UNKNOWN,
+ .name = RC_MAP_MANTIS,
+ }
};
-EXPORT_SYMBOL_GPL(ir_mantis);
int mantis_input_init(struct mantis_pci *mantis)
{
- struct input_dev *rc;
- char name[80], dev[80];
+ struct rc_dev *dev;
int err;
- rc = input_allocate_device();
- if (!rc) {
- dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
- return -ENOMEM;
- }
+ err = rc_map_register(&ir_mantis_map);
+ if (err)
+ goto out;
- sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
- sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+ dev = rc_allocate_device();
+ if (!dev) {
+ dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
+ err = -ENOMEM;
+ goto out_map;
+ }
- rc->name = name;
- rc->phys = dev;
+ sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+ sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev));
- rc->id.bustype = BUS_PCI;
- rc->id.vendor = mantis->vendor_id;
- rc->id.product = mantis->device_id;
- rc->id.version = 1;
- rc->dev = mantis->pdev->dev;
+ dev->input_name = mantis->input_name;
+ dev->input_phys = mantis->input_phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.vendor = mantis->vendor_id;
+ dev->input_id.product = mantis->device_id;
+ dev->input_id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->map_name = RC_MAP_MANTIS;
+ dev->dev.parent = &mantis->pdev->dev;
- err = __ir_input_register(rc, &ir_mantis, NULL, MODULE_NAME);
+ err = rc_register_device(dev);
if (err) {
dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
- input_free_device(rc);
- return -ENODEV;
+ goto out_dev;
}
- mantis->rc = rc;
-
+ mantis->rc = dev;
return 0;
+
+out_dev:
+ rc_free_device(dev);
+out_map:
+ rc_map_unregister(&ir_mantis_map);
+out:
+ return err;
}
int mantis_exit(struct mantis_pci *mantis)
{
- struct input_dev *rc = mantis->rc;
-
- ir_input_unregister(rc);
-
+ rc_unregister_device(mantis->rc);
+ rc_map_unregister(&ir_mantis_map);
return 0;
}
+
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
index fe31cfb0b158..479086dbb9a8 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.c
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -75,7 +75,7 @@ int mantis_get_mac(struct mantis_pci *mantis)
EXPORT_SYMBOL_GPL(mantis_get_mac);
/* Turn the given bit on or off. */
-void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
{
u32 cur;
@@ -90,7 +90,7 @@ void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
mmwrite(0x00, MANTIS_GPIF_DOUT);
}
-EXPORT_SYMBOL_GPL(gpio_set_bits);
+EXPORT_SYMBOL_GPL(mantis_gpio_set_bits);
int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
{
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
index 188fe5a81614..d56e002b2955 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.h
+++ b/drivers/media/dvb/mantis/mantis_ioc.h
@@ -44,7 +44,7 @@ enum mantis_stream_control {
};
extern int mantis_get_mac(struct mantis_pci *mantis);
-extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
index 7d2f2398fa8b..97b889e8a341 100644
--- a/drivers/media/dvb/mantis/mantis_uart.c
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -182,5 +182,6 @@ void mantis_uart_exit(struct mantis_pci *mantis)
{
/* disable interrupt */
mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+ flush_work_sync(&mantis->uart_work);
}
EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
index 4a723bda0031..deec927c7f7a 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -173,7 +173,7 @@ static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
- fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+ fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter);
if (fe) {
fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
index 8e6ae558ee57..26bc0cbe84d4 100644
--- a/drivers/media/dvb/mantis/mantis_vp1034.c
+++ b/drivers/media/dvb/mantis/mantis_vp1034.c
@@ -50,13 +50,13 @@ int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
switch (voltage) {
case SEC_VOLTAGE_13:
dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
- gpio_set_bits(mantis, 13, 1);
- gpio_set_bits(mantis, 14, 0);
+ mantis_gpio_set_bits(mantis, 13, 1);
+ mantis_gpio_set_bits(mantis, 14, 0);
break;
case SEC_VOLTAGE_18:
dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
- gpio_set_bits(mantis, 13, 1);
- gpio_set_bits(mantis, 14, 1);
+ mantis_gpio_set_bits(mantis, 13, 1);
+ mantis_gpio_set_bits(mantis, 14, 1);
break;
case SEC_VOLTAGE_OFF:
dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
@@ -82,7 +82,7 @@ static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
- fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+ fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter);
if (fe) {
dprintk(MANTIS_ERROR, 1,
"found MB86A16 DVB-S/DSS frontend @0x%02x",
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
index d1aa2bc0c155..38a436ca2fdf 100644
--- a/drivers/media/dvb/mantis/mantis_vp1041.c
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -316,14 +316,14 @@ static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
if (err == 0) {
mantis_frontend_soft_reset(mantis);
msleep(250);
- mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+ mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter);
if (mantis->fe) {
dprintk(MANTIS_ERROR, 1,
"found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
vp1041_stb0899_config.demod_address);
- if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
- if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+ if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) {
+ if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0))
dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
}
} else {
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
index 10ce81790a8c..06da0ddf05a7 100644
--- a/drivers/media/dvb/mantis/mantis_vp2033.c
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -132,7 +132,7 @@ static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
- fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+ fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config,
adapter,
read_pwm(mantis));
@@ -141,7 +141,7 @@ static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
vp2033_tda1002x_cu1216_config.demod_address);
} else {
- fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+ fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config,
adapter,
read_pwm(mantis));
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
index a7ca233e800b..f72b137b7652 100644
--- a/drivers/media/dvb/mantis/mantis_vp2040.c
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -132,7 +132,7 @@ static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
- fe = tda10021_attach(&vp2040_tda1002x_cu1216_config,
+ fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config,
adapter,
read_pwm(mantis));
@@ -141,7 +141,7 @@ static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
vp2040_tda1002x_cu1216_config.demod_address);
} else {
- fe = tda10023_attach(&vp2040_tda10023_cu1216_config,
+ fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config,
adapter,
read_pwm(mantis));
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
index 1f4334214953..c09308cd3ac6 100644
--- a/drivers/media/dvb/mantis/mantis_vp3030.c
+++ b/drivers/media/dvb/mantis/mantis_vp3030.c
@@ -59,21 +59,21 @@ static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
struct mantis_hwconfig *config = mantis->hwconfig;
int err = 0;
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
err = mantis_frontend_power(mantis, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
if (err == 0) {
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
- fe = zl10353_attach(&mantis_vp3030_config, adapter);
+ fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter);
if (!fe)
return -1;
- tda665x_attach(fe, &env57h12d5_config, adapter);
+ dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter);
} else {
dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
adapter->name,
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index 4caeb163a666..dc073bdc623a 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -34,7 +34,6 @@
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
@@ -1305,7 +1304,6 @@ static void ngene_stop(struct ngene *dev)
static int ngene_start(struct ngene *dev)
{
int stat;
- unsigned long flags;
int i;
pci_set_master(dev->pci_dev);
@@ -1338,6 +1336,8 @@ static int ngene_start(struct ngene *dev)
#ifdef CONFIG_PCI_MSI
/* enable MSI if kernel and card support it */
if (pci_msi_enabled() && dev->card_info->msi_supported) {
+ unsigned long flags;
+
ngwritel(0, NGENE_INT_ENABLE);
free_irq(dev->pci_dev->irq, dev);
stat = pci_enable_msi(dev->pci_dev);
@@ -1516,7 +1516,7 @@ static int init_channels(struct ngene *dev)
void __devexit ngene_remove(struct pci_dev *pdev)
{
- struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+ struct ngene *dev = pci_get_drvdata(pdev);
int i;
tasklet_kill(&dev->event_tasklet);
@@ -1537,12 +1537,11 @@ int __devinit ngene_probe(struct pci_dev *pci_dev,
if (pci_enable_device(pci_dev) < 0)
return -ENODEV;
- dev = vmalloc(sizeof(struct ngene));
+ dev = vzalloc(sizeof(struct ngene));
if (dev == NULL) {
stat = -ENOMEM;
goto fail0;
}
- memset(dev, 0, sizeof(struct ngene));
dev->pci_dev = pci_dev;
dev->card_info = (struct ngene_info *)id->driver_data;
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c
index 48f980b21d66..3832e5983c19 100644
--- a/drivers/media/dvb/ngene/ngene-dvb.c
+++ b/drivers/media/dvb/ngene/ngene-dvb.c
@@ -35,7 +35,6 @@
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
index c3ae956714e7..d28554f8ce99 100644
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ b/drivers/media/dvb/ngene/ngene-i2c.c
@@ -37,7 +37,6 @@
#include <asm/div64.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
index e520bceee0af..bc6456eb2c4f 100644
--- a/drivers/media/dvb/siano/Kconfig
+++ b/drivers/media/dvb/siano/Kconfig
@@ -4,7 +4,7 @@
config SMS_SIANO_MDTV
tristate "Siano SMS1xxx based MDTV receiver"
- depends on DVB_CORE && IR_CORE && HAS_DMA
+ depends on DVB_CORE && RC_CORE && HAS_DMA
---help---
Choose Y or M here if you have MDTV receiver with a Siano chipset.
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index 135e45bd00c7..78765ed28063 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -438,7 +438,7 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
int rc;
void *buffer;
- coredev->ir.input_dev = NULL;
+ coredev->ir.dev = NULL;
ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
if (ir_io) {/* only if IR port exist we use IR sub-module */
sms_info("IR loading");
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index a27c44a8af5a..37bc5c4b8ad8 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -45,25 +45,24 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
ev.pulse = (samples[i] > 0) ? false : true;
- ir_raw_event_store(coredev->ir.input_dev, &ev);
+ ir_raw_event_store(coredev->ir.dev, &ev);
}
- ir_raw_event_handle(coredev->ir.input_dev);
+ ir_raw_event_handle(coredev->ir.dev);
}
int sms_ir_init(struct smscore_device_t *coredev)
{
- struct input_dev *input_dev;
+ int err;
int board_id = smscore_get_board_id(coredev);
+ struct rc_dev *dev;
- sms_log("Allocating input device");
- input_dev = input_allocate_device();
- if (!input_dev) {
+ sms_log("Allocating rc device");
+ dev = rc_allocate_device();
+ if (!dev) {
sms_err("Not enough memory");
return -ENOMEM;
}
- coredev->ir.input_dev = input_dev;
-
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
sms_log("IR port %d, timeout %d ms",
@@ -75,38 +74,41 @@ int sms_ir_init(struct smscore_device_t *coredev)
strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
- input_dev->name = coredev->ir.name;
- input_dev->phys = coredev->ir.phys;
- input_dev->dev.parent = coredev->device;
+ dev->input_name = coredev->ir.name;
+ dev->input_phys = coredev->ir.phys;
+ dev->dev.parent = coredev->device;
#if 0
/* TODO: properly initialize the parameters bellow */
- input_dev->id.bustype = BUS_USB;
- input_dev->id.version = 1;
- input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ dev->input_id.bustype = BUS_USB;
+ dev->input_id.version = 1;
+ dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
#endif
- coredev->ir.props.priv = coredev;
- coredev->ir.props.driver_type = RC_DRIVER_IR_RAW;
- coredev->ir.props.allowed_protos = IR_TYPE_ALL;
+ dev->priv = coredev;
+ dev->driver_type = RC_DRIVER_IR_RAW;
+ dev->allowed_protos = RC_TYPE_ALL;
+ dev->map_name = sms_get_board(board_id)->rc_codes;
+ dev->driver_name = MODULE_NAME;
- sms_log("Input device (IR) %s is set for key events", input_dev->name);
+ sms_log("Input device (IR) %s is set for key events", dev->input_name);
- if (ir_input_register(input_dev, sms_get_board(board_id)->rc_codes,
- &coredev->ir.props, MODULE_NAME)) {
+ err = rc_register_device(dev);
+ if (err < 0) {
sms_err("Failed to register device");
- input_free_device(input_dev);
- return -EACCES;
+ rc_free_device(dev);
+ return err;
}
+ coredev->ir.dev = dev;
return 0;
}
void sms_ir_exit(struct smscore_device_t *coredev)
{
- if (coredev->ir.input_dev)
- ir_input_unregister(coredev->ir.input_dev);
+ if (coredev->ir.dev)
+ rc_unregister_device(coredev->ir.dev);
sms_log("");
}
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index 926e247523bd..ae92b3a8587e 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -28,20 +28,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define __SMS_IR_H__
#include <linux/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#define IR_DEFAULT_TIMEOUT 100
struct smscore_device_t;
struct ir_t {
- struct input_dev *input_dev;
+ struct rc_dev *dev;
char name[40];
char phys[32];
char *rc_codes;
u64 protocol;
- struct ir_dev_props props;
u32 timeout;
u32 controller;
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index 50d4338610e0..0b8da57cf4c3 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -288,8 +288,7 @@ static int smsusb1_setmode(void *context, int mode)
static void smsusb_term_device(struct usb_interface *intf)
{
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *) usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
if (dev) {
smsusb_stop_streaming(dev);
@@ -445,8 +444,7 @@ static void smsusb_disconnect(struct usb_interface *intf)
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
smsusb_stop_streaming(dev);
return 0;
@@ -455,8 +453,7 @@ static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
static int smsusb_resume(struct usb_interface *intf)
{
int rc, i;
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
struct usb_device *udev = interface_to_usbdev(intf);
printk(KERN_INFO "%s: Entering.\n", __func__);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index debea8d1d31c..44afab2fdc2d 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -89,7 +89,6 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_BUDGET_CORE && I2C
- depends on INPUT # due to IR
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -98,7 +97,7 @@ config DVB_BUDGET_CI
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
- depends on VIDEO_IR
+ depends on RC_CORE
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index ac20c5bbfa43..cdd31cae46c4 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -100,6 +100,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0, /* ignored */
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 1,
.name = "Television",
@@ -108,6 +109,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 2,
.name = "Video",
@@ -116,6 +118,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 3,
.name = "Y/C",
@@ -124,6 +127,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}
};
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 97afc01f60d0..e957d7690bcc 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1406,8 +1406,10 @@ static int budget_av_detach(struct saa7146_dev *dev)
#define KNC1_INPUTS 2
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
- {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
- {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+ { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,
+ V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,
+ V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index a9c2c326df4b..b82756db5bd1 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -33,9 +33,8 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/spinlock.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "budget.h"
@@ -96,7 +95,7 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct budget_ci_ir {
- struct input_dev *dev;
+ struct rc_dev *dev;
struct tasklet_struct msp430_irq_tasklet;
char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
char phys[32];
@@ -118,7 +117,7 @@ struct budget_ci {
static void msp430_ir_interrupt(unsigned long data)
{
struct budget_ci *budget_ci = (struct budget_ci *) data;
- struct input_dev *dev = budget_ci->ir.dev;
+ struct rc_dev *dev = budget_ci->ir.dev;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
/*
@@ -160,19 +159,17 @@ static void msp430_ir_interrupt(unsigned long data)
budget_ci->ir.rc5_device != (command & 0x1f))
return;
- ir_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+ rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
}
static int msp430_ir_init(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *input_dev = budget_ci->ir.dev;
+ struct rc_dev *dev;
int error;
- char *ir_codes = NULL;
-
- budget_ci->ir.dev = input_dev = input_allocate_device();
- if (!input_dev) {
+ dev = rc_allocate_device();
+ if (!dev) {
printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
return -ENOMEM;
}
@@ -182,19 +179,20 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
"pci-%s/ir0", pci_name(saa->pci));
- input_dev->name = budget_ci->ir.name;
-
- input_dev->phys = budget_ci->ir.phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->input_name = budget_ci->ir.name;
+ dev->input_phys = budget_ci->ir.phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
+ dev->scanmask = 0xff;
if (saa->pci->subsystem_vendor) {
- input_dev->id.vendor = saa->pci->subsystem_vendor;
- input_dev->id.product = saa->pci->subsystem_device;
+ dev->input_id.vendor = saa->pci->subsystem_vendor;
+ dev->input_id.product = saa->pci->subsystem_device;
} else {
- input_dev->id.vendor = saa->pci->vendor;
- input_dev->id.product = saa->pci->device;
+ dev->input_id.vendor = saa->pci->vendor;
+ dev->input_id.product = saa->pci->device;
}
- input_dev->dev.parent = &saa->pci->dev;
+ dev->dev.parent = &saa->pci->dev;
if (rc5_device < 0)
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
@@ -208,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x1011:
case 0x1012:
/* The hauppauge keymap is a superset of these remotes */
- ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ dev->map_name = RC_MAP_HAUPPAUGE_NEW;
if (rc5_device < 0)
budget_ci->ir.rc5_device = 0x1f;
@@ -218,23 +216,22 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x1019:
case 0x101a:
/* for the Technotrend 1500 bundled remote */
- ir_codes = RC_MAP_TT_1500;
+ dev->map_name = RC_MAP_TT_1500;
break;
default:
/* unknown remote */
- ir_codes = RC_MAP_BUDGET_CI_OLD;
+ dev->map_name = RC_MAP_BUDGET_CI_OLD;
break;
}
- error = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
+ error = rc_register_device(dev);
if (error) {
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
+ rc_free_device(dev);
return error;
}
- /* note: these must be after input_register_device */
- input_dev->rep[REP_DELAY] = 400;
- input_dev->rep[REP_PERIOD] = 250;
+ budget_ci->ir.dev = dev;
tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
(unsigned long) budget_ci);
@@ -248,13 +245,12 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
static void msp430_ir_deinit(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *dev = budget_ci->ir.dev;
SAA7146_IER_DISABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
- ir_input_unregister(dev);
+ rc_unregister_device(budget_ci->ir.dev);
}
static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 83567b898d09..3c5a4739ed70 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -452,4 +452,20 @@ config RADIO_TIMBERDALE
found behind the Timberdale FPGA on the Russellville board.
Enabling this driver will automatically select the DSP and tuner.
+config RADIO_WL1273
+ tristate "Texas Instruments WL1273 I2C FM Radio"
+ depends on I2C && VIDEO_V4L2
+ select MFD_WL1273_CORE
+ select FW_LOADER
+ ---help---
+ Choose Y here if you have this FM radio chip.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l2" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-wl1273.
+
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index f615583b4837..d2970748a69f 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
+obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5bf4985daede..6cc5d130fbc8 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -31,7 +31,6 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
-#include <linux/delay.h> /* udelay */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#include <linux/io.h> /* outb, outb_p */
@@ -71,27 +70,17 @@ static struct rtrack rtrack_card;
/* local things */
-static void sleep_delay(long n)
-{
- /* Sleep nicely for 'n' uS */
- int d = n / msecs_to_jiffies(1000);
- if (!d)
- udelay(n);
- else
- msleep(jiffies_to_msecs(d));
-}
-
static void rt_decvol(struct rtrack *rt)
{
outb(0x58, rt->io); /* volume down + sigstr + on */
- sleep_delay(100000);
+ msleep(100);
outb(0xd8, rt->io); /* volume steady + sigstr + on */
}
static void rt_incvol(struct rtrack *rt)
{
outb(0x98, rt->io); /* volume up + sigstr + on */
- sleep_delay(100000);
+ msleep(100);
outb(0xd8, rt->io); /* volume steady + sigstr + on */
}
@@ -120,7 +109,7 @@ static int rt_setvol(struct rtrack *rt, int vol)
if (vol == 0) { /* volume = 0 means mute the card */
outb(0x48, rt->io); /* volume down but still "on" */
- sleep_delay(2000000); /* make sure it's totally down */
+ msleep(2000); /* make sure it's totally down */
outb(0xd0, rt->io); /* volume steady, off */
rt->curvol = 0; /* track the volume state! */
mutex_unlock(&rt->lock);
@@ -155,7 +144,7 @@ static void send_0_byte(struct rtrack *rt)
outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */
outb_p(128+64+16+8+2+1, rt->io); /* clock */
}
- sleep_delay(1000);
+ msleep(1);
}
static void send_1_byte(struct rtrack *rt)
@@ -169,7 +158,7 @@ static void send_1_byte(struct rtrack *rt)
outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
}
- sleep_delay(1000);
+ msleep(1);
}
static int rt_setfreq(struct rtrack *rt, unsigned long freq)
@@ -361,7 +350,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
@@ -412,13 +401,6 @@ static int __init rtrack_init(void)
rt->vdev.release = video_device_release_empty;
video_set_drvdata(&rt->vdev, rt);
- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&rt->v4l2_dev);
- release_region(rt->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
/* Set up the I/O locking */
mutex_init(&rt->lock);
@@ -427,9 +409,16 @@ static int __init rtrack_init(void)
/* this ensures that the volume is all the way down */
outb(0x48, rt->io); /* volume down but still "on" */
- sleep_delay(2000000); /* make sure it's totally down */
+ msleep(2000); /* make sure it's totally down */
outb(0xc0, rt->io); /* steady volume, mute card */
+ if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(&rt->v4l2_dev);
+ release_region(rt->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
+
return 0;
}
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index c22311393624..dd8a6ab0d437 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
@@ -375,6 +375,8 @@ static int __init aztech_init(void)
az->vdev.ioctl_ops = &aztech_ioctl_ops;
az->vdev.release = video_device_release_empty;
video_set_drvdata(&az->vdev, az);
+ /* mute card - prevents noisy bootups */
+ outb(0, az->io);
if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
@@ -383,8 +385,6 @@ static int __init aztech_init(void)
}
v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
- /* mute card - prevents noisy bootups */
- outb(0, az->io);
return 0;
}
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index b701ea6e7c73..bc9ad0897c55 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
unsigned char readbuf[RDS_BUFFER];
int i = 0;
+ mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
- mutex_lock(&dev->lock);
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
- mutex_unlock(&dev->lock);
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev;
@@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
add_timer(&dev->readtimer);
}
if (dev->rdsin == dev->rdsout) {
+ mutex_unlock(&dev->lock);
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue);
+ mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
+ mutex_unlock(&dev->lock);
if (copy_to_user(data, readbuf, i))
return -EFAULT;
@@ -525,9 +527,11 @@ static int cadet_open(struct file *file)
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users++;
if (1 == dev->users)
init_waitqueue_head(&dev->read_queue);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -535,11 +539,13 @@ static int cadet_release(struct file *file)
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users--;
if (0 == dev->users) {
del_timer_sync(&dev->readtimer);
dev->rdsstat = 0;
}
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = {
.open = cadet_open,
.release = cadet_release,
.read = cadet_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = cadet_poll,
};
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 79039674a0e0..28fa85ba2087 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
@@ -422,11 +422,11 @@ static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_dev
card->vdev.release = video_device_release_empty;
video_set_drvdata(&card->vdev, card);
+ gemtek_pci_mute(card);
+
if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
goto err_video;
- gemtek_pci_mute(card);
-
v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
pdev->revision, card->iobase, card->iobase + card->length - 1);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 73985f641f07..259936422e49 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt)
static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -577,12 +577,6 @@ static int __init gemtek_init(void)
gt->vdev.release = video_device_release_empty;
video_set_drvdata(&gt->vdev, gt);
- if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(gt->io, 1);
- return -EBUSY;
- }
-
/* Set defaults */
gt->lastfreq = GEMTEK_LOWFREQ;
gt->bu2614data = 0;
@@ -590,6 +584,12 @@ static int __init gemtek_init(void)
if (initmute)
gemtek_mute(gt);
+ if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(gt->io, 1);
+ return -EBUSY;
+ }
+
return 0;
}
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 08f1051979ca..6af61bfeb178 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
@@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ if (!radio_power_on(dev)) {
+ retval = -EIO;
+ goto errfr1;
+ }
+
retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1;
}
- if (!radio_power_on(dev)) {
- retval = -EIO;
- goto errunr;
- }
-
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0;
-errunr:
- video_unregister_device(&dev->vdev);
errfr1:
v4l2_device_unregister(v4l2_dev);
errfr:
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 255d40df4b46..6459a220b0dd 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 4ff885445fd4..3fb76e3834c9 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -33,6 +33,7 @@ struct pcm20 {
unsigned long freq;
int muted;
struct snd_miro_aci *aci;
+ struct mutex lock;
};
static struct pcm20 pcm20_card = {
@@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -229,7 +230,7 @@ static int __init pcm20_init(void)
return -ENODEV;
}
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
-
+ mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
if (res < 0) {
@@ -242,6 +243,7 @@ static int __init pcm20_init(void)
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
+ dev->vdev.lock = &dev->lock;
video_set_drvdata(&dev->vdev, dev);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index b540e8072e92..e6b2d085a449 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -58,7 +58,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index a79296aac9a9..8d6ea591bd18 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
@@ -315,6 +315,10 @@ static int __init rtrack2_init(void)
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ /* mute card - prevents noisy bootups */
+ outb(1, dev->io);
+ dev->muted = 1;
+
mutex_init(&dev->lock);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
@@ -324,10 +328,6 @@ static int __init rtrack2_init(void)
v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
- outb(1, dev->io);
- dev->muted = 1;
-
return 0;
}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 985359d18aa5..b5a5f89e238a 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
@@ -382,6 +382,9 @@ static int __init fmi_init(void)
mutex_init(&fmi->lock);
+ /* mute card - prevents noisy bootups */
+ fmi_mute(fmi);
+
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2);
@@ -391,8 +394,6 @@ static int __init fmi_init(void)
}
v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
- /* mute card - prevents noisy bootups */
- fmi_mute(fmi);
return 0;
}
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 52c7bbb32b8b..dc3f04c52d5e 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
@@ -424,6 +424,10 @@ static int __init fmr2_init(void)
fmr2->vdev.release = video_device_release_empty;
video_set_drvdata(&fmr2->vdev, fmr2);
+ /* mute card - prevents noisy bootups */
+ fmr2_mute(fmr2->io);
+ fmr2_product_info(fmr2);
+
if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmr2->io, 2);
@@ -431,11 +435,6 @@ static int __init fmr2_init(void)
}
v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
- /* mute card - prevents noisy bootups */
- mutex_lock(&fmr2->lock);
- fmr2_mute(fmr2->io);
- fmr2_product_info(fmr2);
- mutex_unlock(&fmr2->lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
return 0;
}
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 6a435786b63d..726d367ad8d0 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -53,7 +53,8 @@ struct radio_si4713_device {
/* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ /* Note: locking is done at the subdev level in the i2c driver. */
+ .unlocked_ioctl = video_ioctl2,
};
/* Video4Linux Interface */
@@ -291,7 +292,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto unregister_v4l2_dev;
}
- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 789d2ec66e19..0e71d816c725 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -142,7 +142,6 @@ struct tea5764_device {
struct video_device *videodev;
struct tea5764_regs regs;
struct mutex mutex;
- int users;
};
/* I2C code related */
@@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
-static int tea5764_open(struct file *file)
-{
- /* Currently we support only one device */
- struct tea5764_device *radio = video_drvdata(file);
-
- mutex_lock(&radio->mutex);
- /* Only exclusive access */
- if (radio->users) {
- mutex_unlock(&radio->mutex);
- return -EBUSY;
- }
- radio->users++;
- mutex_unlock(&radio->mutex);
- file->private_data = radio;
- return 0;
-}
-
-static int tea5764_close(struct file *file)
-{
- struct tea5764_device *radio = video_drvdata(file);
-
- if (!radio)
- return -ENODEV;
- mutex_lock(&radio->mutex);
- radio->users--;
- mutex_unlock(&radio->mutex);
- return 0;
-}
-
/* File system interface */
static const struct v4l2_file_operations tea5764_fops = {
.owner = THIS_MODULE,
- .open = tea5764_open,
- .release = tea5764_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
@@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
int ret;
PDEBUG("probe");
- radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
+ radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
if (!radio)
return -ENOMEM;
@@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, radio);
video_set_drvdata(radio->videodev, radio);
-
- ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
- if (ret < 0) {
- PWARN("Could not register video device!");
- goto errrel;
- }
+ radio->videodev->lock = &radio->mutex;
/* initialize and power off the chip */
tea5764_i2c_read(radio);
@@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
tea5764_mute(radio, 1);
tea5764_power_down(radio);
+ ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (ret < 0) {
+ PWARN("Could not register video device!");
+ goto errrel;
+ }
+
PINFO("registered.");
return 0;
errrel:
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index fc1c860fd438..a32663917059 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
@@ -389,6 +389,9 @@ static int __init terratec_init(void)
mutex_init(&tt->lock);
+ /* mute card - prevents noisy bootups */
+ tt_write_vol(tt, 0);
+
if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&tt->v4l2_dev);
release_region(tt->io, 2);
@@ -396,9 +399,6 @@ static int __init terratec_init(void)
}
v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
-
- /* mute card - prevents noisy bootups */
- tt_write_vol(tt, 0);
return 0;
}
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index b8bb3ef47df5..a185610b376b 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -34,6 +34,7 @@ struct timbradio {
struct v4l2_subdev *sd_dsp;
struct video_device video_dev;
struct v4l2_device v4l2_dev;
+ struct mutex lock;
};
@@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int __devinit timbradio_probe(struct platform_device *pdev)
@@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
}
tr->pdata = *pdata;
+ mutex_init(&tr->lock);
strlcpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name));
@@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
+ tr->video_dev.lock = &tr->lock;
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 9d6dcf8af5b0..22fa9cc28abe 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops trust_ioctl_ops = {
@@ -396,14 +396,6 @@ static int __init trust_init(void)
tr->vdev.release = video_device_release_empty;
video_set_drvdata(&tr->vdev, tr);
- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(tr->io, 2);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
-
write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
@@ -418,6 +410,14 @@ static int __init trust_init(void)
/* mute card - prevents noisy bootups */
tr_setmute(tr, 1);
+ if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(tr->io, 2);
+ return -EINVAL;
+ }
+
+ v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+
return 0;
}
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index b1f630527dc1..8dbbf08f2207 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv)
static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
@@ -344,18 +344,18 @@ static int __init typhoon_init(void)
strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
dev->io = io;
- dev->curfreq = dev->mutefreq = mutefreq;
if (dev->io == -1) {
v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
return -EINVAL;
}
- if (dev->mutefreq < 87000 || dev->mutefreq > 108500) {
+ if (mutefreq < 87000 || mutefreq > 108500) {
v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
return -EINVAL;
}
+ dev->curfreq = dev->mutefreq = mutefreq << 4;
mutex_init(&dev->lock);
if (!request_region(dev->io, 8, "typhoon")) {
@@ -378,17 +378,17 @@ static int __init typhoon_init(void)
dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+
+ /* mute card - prevents noisy bootups */
+ typhoon_mute(dev);
+
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&dev->v4l2_dev);
release_region(dev->io, 8);
return -EINVAL;
}
v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
- dev->mutefreq <<= 4;
-
- /* mute card - prevents noisy bootups */
- typhoon_mute(dev);
+ v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
return 0;
}
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
new file mode 100644
index 000000000000..dd6bd364efa0
--- /dev/null
+++ b/drivers/media/radio/radio-wl1273.c
@@ -0,0 +1,2330 @@
+/*
+ * Driver for the Texas Instruments WL1273 FM radio.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Author: Matti J. Aaltonen <matti.j.aaltonen@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define DRIVER_DESC "Wl1273 FM Radio"
+
+#define WL1273_POWER_SET_OFF 0
+#define WL1273_POWER_SET_FM BIT(0)
+#define WL1273_POWER_SET_RDS BIT(1)
+#define WL1273_POWER_SET_RETENTION BIT(4)
+
+#define WL1273_PUPD_SET_OFF 0x00
+#define WL1273_PUPD_SET_ON 0x01
+#define WL1273_PUPD_SET_RETENTION 0x10
+
+#define WL1273_FREQ(x) (x * 10000 / 625)
+#define WL1273_INV_FREQ(x) (x * 625 / 10000)
+
+/*
+ * static int radio_nr - The number of the radio device
+ *
+ * The default is 0.
+ */
+static int radio_nr;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0");
+
+struct wl1273_device {
+ char *bus_type;
+
+ u8 forbidden;
+ unsigned int preemphasis;
+ unsigned int spacing;
+ unsigned int tx_power;
+ unsigned int rx_frequency;
+ unsigned int tx_frequency;
+ unsigned int rangelow;
+ unsigned int rangehigh;
+ unsigned int band;
+ bool stereo;
+
+ /* RDS */
+ unsigned int rds_on;
+ struct delayed_work work;
+
+ wait_queue_head_t read_queue;
+ struct mutex lock; /* for serializing fm radio operations */
+ struct completion busy;
+
+ unsigned char *buffer;
+ unsigned int buf_size;
+ unsigned int rd_index;
+ unsigned int wr_index;
+
+ /* Selected interrupts */
+ u16 irq_flags;
+ u16 irq_received;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_device v4l2dev;
+ struct video_device videodev;
+ struct device *dev;
+ struct wl1273_core *core;
+ struct file *owner;
+ char *write_buf;
+ unsigned int rds_users;
+};
+
+#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \
+ WL1273_POW_ENB_EVENT)
+
+/*
+ * static unsigned int rds_buf - the number of RDS buffer blocks used.
+ *
+ * The default number is 100.
+ */
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0);
+MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100");
+
+static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
+{
+ struct i2c_client *client = core->client;
+ u8 b[2];
+ int r;
+
+ r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
+ if (r != 2) {
+ dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
+ return -EREMOTEIO;
+ }
+
+ *value = (u16)b[0] << 8 | b[1];
+
+ return 0;
+}
+
+static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
+{
+ struct i2c_client *client = core->client;
+ u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
+ int r;
+
+ r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
+ if (r) {
+ dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
+ return r;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
+{
+ struct i2c_client *client = core->client;
+ struct i2c_msg msg;
+ int r;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.buf = data;
+ msg.len = len;
+
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ dev_err(&client->dev, "%s: write error.\n", __func__);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_write_fw(struct wl1273_core *core,
+ __u8 *fw, int len)
+{
+ struct i2c_client *client = core->client;
+ struct i2c_msg msg;
+ int i, r = 0;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+
+ for (i = 0; i <= len; i++) {
+ msg.len = fw[0];
+ msg.buf = fw + 1;
+
+ fw += msg.len + 1;
+ dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len);
+
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r < 0 && i < len + 1)
+ break;
+ }
+
+ dev_dbg(&client->dev, "%s: i: %d\n", __func__, i);
+ dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1);
+
+ /* Last transfer always fails. */
+ if (i == len || r == 1)
+ r = 0;
+
+ return r;
+}
+
+/**
+ * wl1273_fm_set_audio() - Set audio mode.
+ * @core: A pointer to the device struct.
+ * @new_mode: The new audio mode.
+ *
+ * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
+ */
+static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
+{
+ int r = 0;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
+ r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
+ WL1273_PCM_DEF_MODE);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+ core->i2s_mode);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_I2S);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_RX &&
+ new_mode == WL1273_AUDIO_ANALOG) {
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_ANALOG);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_TX &&
+ new_mode == WL1273_AUDIO_DIGITAL) {
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+ core->i2s_mode);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+ WL1273_AUDIO_IO_SET_I2S);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_TX &&
+ new_mode == WL1273_AUDIO_ANALOG) {
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+ WL1273_AUDIO_IO_SET_ANALOG);
+ if (r)
+ goto out;
+ }
+
+ core->audio_mode = new_mode;
+out:
+ return r;
+}
+
+/**
+ * wl1273_fm_set_volume() - Set volume.
+ * @core: A pointer to the device struct.
+ * @volume: The new volume value.
+ */
+static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
+{
+ u16 val;
+ int r;
+
+ if (volume > WL1273_MAX_VOLUME)
+ return -EINVAL;
+
+ if (core->volume == volume)
+ return 0;
+
+ val = volume;
+ r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
+ if (r)
+ return r;
+
+ core->volume = volume;
+ return 0;
+}
+
+#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status)
+#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3)
+#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4)
+
+static int wl1273_fm_rds(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ struct i2c_client *client = core->client;
+ u16 val;
+ u8 b0 = WL1273_RDS_DATA_GET, status;
+ struct v4l2_rds_data rds = { 0, 0, 0 };
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = &b0,
+ .len = 1,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = (u8 *) &rds,
+ .len = sizeof(rds),
+ }
+ };
+ int r;
+
+ if (core->mode != WL1273_MODE_RX)
+ return 0;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ return r;
+
+ if ((val & 0x01) == 0) {
+ /* RDS decoder not synchronized */
+ return -EAGAIN;
+ }
+
+ /* copy all four RDS blocks to internal buffer */
+ do {
+ r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (r != ARRAY_SIZE(msg)) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": %s: read_rds error r == %i)\n",
+ __func__, r);
+ }
+
+ status = rds.block;
+
+ if (!WL1273_FIFO_HAS_DATA(status))
+ break;
+
+ /* copy bits 0-2 (the block ID) to bits 3-5 */
+ rds.block = V4L2_RDS_BLOCK_MSK & status;
+ rds.block |= rds.block << 3;
+
+ /* copy the error bits to standard positions */
+ if (WL1273_RDS_UNCORRECTABLE_ERROR & status) {
+ rds.block |= V4L2_RDS_BLOCK_ERROR;
+ rds.block &= ~V4L2_RDS_BLOCK_CORRECTED;
+ } else if (WL1273_RDS_CORRECTABLE_ERROR & status) {
+ rds.block &= ~V4L2_RDS_BLOCK_ERROR;
+ rds.block |= V4L2_RDS_BLOCK_CORRECTED;
+ }
+
+ /* copy RDS block to internal buffer */
+ memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE);
+ radio->wr_index += 3;
+
+ /* wrap write pointer */
+ if (radio->wr_index >= radio->buf_size)
+ radio->wr_index = 0;
+
+ /* check for overflow & start over */
+ if (radio->wr_index == radio->rd_index) {
+ dev_dbg(radio->dev, "RDS OVERFLOW");
+
+ radio->rd_index = 0;
+ radio->wr_index = 0;
+ break;
+ }
+ } while (WL1273_FIFO_HAS_DATA(status));
+
+ /* wake up read queue */
+ if (radio->wr_index != radio->rd_index)
+ wake_up_interruptible(&radio->read_queue);
+
+ return 0;
+}
+
+static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
+{
+ struct wl1273_device *radio = dev_id;
+ struct wl1273_core *core = radio->core;
+ u16 flags;
+ int r;
+
+ r = wl1273_fm_read_reg(core, WL1273_FLAG_GET, &flags);
+ if (r)
+ goto out;
+
+ if (flags & WL1273_BL_EVENT) {
+ radio->irq_received = flags;
+ dev_dbg(radio->dev, "IRQ: BL\n");
+ }
+
+ if (flags & WL1273_RDS_EVENT) {
+ msleep(200);
+
+ wl1273_fm_rds(radio);
+ }
+
+ if (flags & WL1273_BBLK_EVENT)
+ dev_dbg(radio->dev, "IRQ: BBLK\n");
+
+ if (flags & WL1273_LSYNC_EVENT)
+ dev_dbg(radio->dev, "IRQ: LSYNC\n");
+
+ if (flags & WL1273_LEV_EVENT) {
+ u16 level;
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &level);
+ if (r)
+ goto out;
+
+ if (level > 14)
+ dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level);
+ }
+
+ if (flags & WL1273_IFFR_EVENT)
+ dev_dbg(radio->dev, "IRQ: IFFR\n");
+
+ if (flags & WL1273_PI_EVENT)
+ dev_dbg(radio->dev, "IRQ: PI\n");
+
+ if (flags & WL1273_PD_EVENT)
+ dev_dbg(radio->dev, "IRQ: PD\n");
+
+ if (flags & WL1273_STIC_EVENT)
+ dev_dbg(radio->dev, "IRQ: STIC\n");
+
+ if (flags & WL1273_MAL_EVENT)
+ dev_dbg(radio->dev, "IRQ: MAL\n");
+
+ if (flags & WL1273_POW_ENB_EVENT) {
+ complete(&radio->busy);
+ dev_dbg(radio->dev, "NOT BUSY\n");
+ dev_dbg(radio->dev, "IRQ: POW_ENB\n");
+ }
+
+ if (flags & WL1273_SCAN_OVER_EVENT)
+ dev_dbg(radio->dev, "IRQ: SCAN_OVER\n");
+
+ if (flags & WL1273_ERROR_EVENT)
+ dev_dbg(radio->dev, "IRQ: ERROR\n");
+
+ if (flags & WL1273_FR_EVENT) {
+ u16 freq;
+
+ dev_dbg(radio->dev, "IRQ: FR:\n");
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_STOP_SEARCH);
+ if (r) {
+ dev_err(radio->dev,
+ "%s: TUNER_MODE_SET fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &freq);
+ if (r)
+ goto out;
+
+ if (radio->band == WL1273_BAND_JAPAN)
+ radio->rx_frequency = WL1273_BAND_JAPAN_LOW +
+ freq * 50;
+ else
+ radio->rx_frequency = WL1273_BAND_OTHER_LOW +
+ freq * 50;
+ /*
+ * The driver works better with this msleep,
+ * the documentation doesn't mention it.
+ */
+ usleep_range(10000, 15000);
+
+ dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency);
+
+ } else {
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &freq);
+ if (r)
+ goto out;
+
+ dev_dbg(radio->dev, "%dkHz\n", freq);
+ }
+ dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__);
+ }
+
+out:
+ wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ complete(&radio->busy);
+
+ return IRQ_HANDLED;
+}
+
+static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ if (freq < WL1273_BAND_TX_LOW) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d < %d\n", freq,
+ WL1273_BAND_TX_LOW);
+ return -ERANGE;
+ }
+
+ if (freq > WL1273_BAND_TX_HIGH) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d > %d\n", freq,
+ WL1273_BAND_TX_HIGH);
+ return -ERANGE;
+ }
+
+ /*
+ * The driver works better with this sleep,
+ * the documentation doesn't mention it.
+ */
+ usleep_range(5000, 10000);
+
+ dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq);
+
+ /* Set the current tx channel */
+ r = wl1273_fm_write_cmd(core, WL1273_CHANL_SET, freq / 10);
+ if (r)
+ return r;
+
+ INIT_COMPLETION(radio->busy);
+
+ /* wait for the FR IRQ */
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!r)
+ return -ETIMEDOUT;
+
+ dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r);
+
+ /* Enable the output power */
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_ENB_SET, 1);
+ if (r)
+ return r;
+
+ INIT_COMPLETION(radio->busy);
+
+ /* wait for the POWER_ENB IRQ */
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ if (!r)
+ return -ETIMEDOUT;
+
+ radio->tx_frequency = freq;
+ dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r);
+
+ return 0;
+}
+
+static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq)
+{
+ struct wl1273_core *core = radio->core;
+ int r, f;
+
+ if (freq < radio->rangelow) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d < %d\n", freq,
+ radio->rangelow);
+ r = -ERANGE;
+ goto err;
+ }
+
+ if (freq > radio->rangehigh) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d > %d\n", freq,
+ radio->rangehigh);
+ r = -ERANGE;
+ goto err;
+ }
+
+ dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq);
+
+ wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+
+ if (radio->band == WL1273_BAND_JAPAN)
+ f = (freq - WL1273_BAND_JAPAN_LOW) / 50;
+ else
+ f = (freq - WL1273_BAND_OTHER_LOW) / 50;
+
+ r = wl1273_fm_write_cmd(core, WL1273_FREQ_SET, f);
+ if (r) {
+ dev_err(radio->dev, "FREQ_SET fails\n");
+ goto err;
+ }
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET);
+ if (r) {
+ dev_err(radio->dev, "TUNER_MODE_SET fails\n");
+ goto err;
+ }
+
+ INIT_COMPLETION(radio->busy);
+
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!r) {
+ dev_err(radio->dev, "%s: TIMEOUT\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ radio->rd_index = 0;
+ radio->wr_index = 0;
+ radio->rx_frequency = freq;
+ return 0;
+err:
+ return r;
+}
+
+static int wl1273_fm_get_freq(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ unsigned int freq;
+ u16 f;
+ int r;
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &f);
+ if (r)
+ return r;
+
+ dev_dbg(radio->dev, "Freq get: 0x%04x\n", f);
+ if (radio->band == WL1273_BAND_JAPAN)
+ freq = WL1273_BAND_JAPAN_LOW + 50 * f;
+ else
+ freq = WL1273_BAND_OTHER_LOW + 50 * f;
+ } else {
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &f);
+ if (r)
+ return r;
+
+ freq = f * 10;
+ }
+
+ return freq;
+}
+
+/**
+ * wl1273_fm_upload_firmware_patch() - Upload the firmware.
+ * @radio: A pointer to the device struct.
+ *
+ * The firmware file consists of arrays of bytes where the first byte
+ * gives the array length. The first byte in the file gives the
+ * number of these arrays.
+ */
+static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ unsigned int packet_num;
+ const struct firmware *fw_p;
+ const char *fw_name = "radio-wl1273-fw.bin";
+ struct device *dev = radio->dev;
+ __u8 *ptr;
+ int r;
+
+ dev_dbg(dev, "%s:\n", __func__);
+
+ /*
+ * Uploading the firmware patch is not always necessary,
+ * so we only print an info message.
+ */
+ if (request_firmware(&fw_p, fw_name, dev)) {
+ dev_info(dev, "%s - %s not found\n", __func__, fw_name);
+
+ return 0;
+ }
+
+ ptr = (__u8 *) fw_p->data;
+ packet_num = ptr[0];
+ dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num);
+
+ r = wl1273_fm_write_fw(core, ptr + 1, packet_num);
+ if (r) {
+ dev_err(dev, "FW upload error: %d\n", r);
+ goto out;
+ }
+
+ /* ignore possible error here */
+ wl1273_fm_write_cmd(core, WL1273_RESET, 0);
+
+ dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r);
+out:
+ release_firmware(fw_p);
+ return r;
+}
+
+static int wl1273_fm_stop(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+
+ if (core->mode == WL1273_MODE_RX) {
+ int r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_OFF);
+ if (r)
+ dev_err(radio->dev, "%s: POWER_SET fails: %d\n",
+ __func__, r);
+ } else if (core->mode == WL1273_MODE_TX) {
+ int r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_OFF);
+ if (r)
+ dev_err(radio->dev,
+ "%s: PUPD_SET fails: %d\n", __func__, r);
+ }
+
+ if (core->pdata->disable) {
+ core->pdata->disable();
+ dev_dbg(radio->dev, "Back to reset\n");
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
+{
+ struct wl1273_core *core = radio->core;
+ struct wl1273_fm_platform_data *pdata = core->pdata;
+ struct device *dev = radio->dev;
+ int r = -EINVAL;
+
+ if (pdata->enable && core->mode == WL1273_MODE_OFF) {
+ dev_dbg(radio->dev, "Out of reset\n");
+
+ pdata->enable();
+ msleep(250);
+ }
+
+ if (new_mode == WL1273_MODE_RX) {
+ u16 val = WL1273_POWER_SET_FM;
+
+ if (radio->rds_on)
+ val |= WL1273_POWER_SET_RDS;
+
+ /* If this fails try again */
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ msleep(100);
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ dev_err(dev, "%s: POWER_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+
+ /* rds buffer configuration */
+ radio->wr_index = 0;
+ radio->rd_index = 0;
+
+ } else if (new_mode == WL1273_MODE_TX) {
+ /* If this fails try again once */
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ msleep(100);
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ dev_err(dev, "%s: PUPD_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+
+ if (radio->rds_on)
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+ else
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+ } else {
+ dev_warn(dev, "%s: Illegal mode.\n", __func__);
+ }
+
+ if (core->mode == WL1273_MODE_OFF) {
+ r = wl1273_fm_upload_firmware_patch(radio);
+ if (r)
+ dev_warn(dev, "Firmware upload failed.\n");
+
+ /*
+ * Sometimes the chip is in a wrong power state at this point.
+ * So we set the power once again.
+ */
+ if (new_mode == WL1273_MODE_RX) {
+ u16 val = WL1273_POWER_SET_FM;
+
+ if (radio->rds_on)
+ val |= WL1273_POWER_SET_RDS;
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ dev_err(dev, "%s: POWER_SET fails\n", __func__);
+ goto fail;
+ }
+ } else if (new_mode == WL1273_MODE_TX) {
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ dev_err(dev, "%s: PUPD_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+ }
+
+ return 0;
+fail:
+ if (pdata->disable)
+ pdata->disable();
+
+ dev_dbg(dev, "%s: return: %d\n", __func__, r);
+ return r;
+}
+
+static int wl1273_fm_suspend(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ /* Cannot go from OFF to SUSPENDED */
+ if (core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_RETENTION);
+ else if (core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_RETENTION);
+ else
+ r = -EINVAL;
+
+ if (r) {
+ dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r);
+ goto out;
+ }
+
+out:
+ return r;
+}
+
+static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode)
+{
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ int old_mode;
+ int r;
+
+ dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden);
+
+ old_mode = core->mode;
+ if (mode & radio->forbidden) {
+ r = -EPERM;
+ goto out;
+ }
+
+ switch (mode) {
+ case WL1273_MODE_RX:
+ case WL1273_MODE_TX:
+ r = wl1273_fm_start(radio, mode);
+ if (r) {
+ dev_err(dev, "%s: Cannot start.\n", __func__);
+ wl1273_fm_stop(radio);
+ goto out;
+ }
+
+ core->mode = mode;
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ dev_err(dev, "INT_MASK_SET fails.\n");
+ goto out;
+ }
+
+ /* remember previous settings */
+ if (mode == WL1273_MODE_RX) {
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r) {
+ dev_err(dev, "set freq fails: %d.\n", r);
+ goto out;
+ }
+
+ r = core->set_volume(core, core->volume);
+ if (r) {
+ dev_err(dev, "set volume fails: %d.\n", r);
+ goto out;
+ }
+
+ dev_dbg(dev, "%s: Set vol: %d.\n", __func__,
+ core->volume);
+ } else {
+ r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency);
+ if (r) {
+ dev_err(dev, "set freq fails: %d.\n", r);
+ goto out;
+ }
+ }
+
+ dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__);
+
+ r = core->set_audio(core, core->audio_mode);
+ if (r)
+ dev_err(dev, "Cannot set audio mode.\n");
+ break;
+
+ case WL1273_MODE_OFF:
+ r = wl1273_fm_stop(radio);
+ if (r)
+ dev_err(dev, "%s: Off fails: %d\n", __func__, r);
+ else
+ core->mode = WL1273_MODE_OFF;
+
+ break;
+
+ case WL1273_MODE_SUSPENDED:
+ r = wl1273_fm_suspend(radio);
+ if (r)
+ dev_err(dev, "%s: Suspend fails: %d\n", __func__, r);
+ else
+ core->mode = WL1273_MODE_SUSPENDED;
+
+ break;
+
+ default:
+ dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode);
+ r = -EINVAL;
+ break;
+ }
+out:
+ if (r)
+ core->mode = old_mode;
+
+ return r;
+}
+
+static int wl1273_fm_set_seek(struct wl1273_device *radio,
+ unsigned int wrap_around,
+ unsigned int seek_upward,
+ int level)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+ unsigned int dir = (seek_upward == 0) ? 0 : 1;
+ unsigned int f;
+
+ f = radio->rx_frequency;
+ dev_dbg(radio->dev, "rx_frequency: %d\n", f);
+
+ if (dir && f + radio->spacing <= radio->rangehigh)
+ r = wl1273_fm_set_rx_freq(radio, f + radio->spacing);
+ else if (dir && wrap_around)
+ r = wl1273_fm_set_rx_freq(radio, radio->rangelow);
+ else if (f - radio->spacing >= radio->rangelow)
+ r = wl1273_fm_set_rx_freq(radio, f - radio->spacing);
+ else if (wrap_around)
+ r = wl1273_fm_set_rx_freq(radio, radio->rangehigh);
+
+ if (r)
+ goto out;
+
+ if (level < SCHAR_MIN || level > SCHAR_MAX)
+ return -EINVAL;
+
+ INIT_COMPLETION(radio->busy);
+ dev_dbg(radio->dev, "%s: BUSY\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+ if (r)
+ goto out;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_SEARCH_LVL_SET, level);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_SEARCH_DIR_SET, dir);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_AUTO_SEEK);
+ if (r)
+ goto out;
+
+ wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ if (!(radio->irq_received & WL1273_BL_EVENT))
+ goto out;
+
+ radio->irq_received &= ~WL1273_BL_EVENT;
+
+ if (!wrap_around)
+ goto out;
+
+ /* Wrap around */
+ dev_dbg(radio->dev, "Wrap around in HW seek.\n");
+
+ if (seek_upward)
+ f = radio->rangelow;
+ else
+ f = radio->rangehigh;
+
+ r = wl1273_fm_set_rx_freq(radio, f);
+ if (r)
+ goto out;
+
+ INIT_COMPLETION(radio->busy);
+ dev_dbg(radio->dev, "%s: BUSY\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_AUTO_SEEK);
+ if (r)
+ goto out;
+
+ wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+out:
+ dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r);
+ return r;
+}
+
+/**
+ * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value.
+ * @radio: A pointer to the device struct.
+ */
+static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ u16 val;
+ int r;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ r = wl1273_fm_read_reg(core, WL1273_READ_FMANT_TUNE_VALUE, &val);
+ if (r) {
+ dev_err(dev, "%s: read error: %d\n", __func__, r);
+ goto out;
+ }
+
+out:
+ return val;
+}
+
+/**
+ * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value.
+ * @radio: A pointer to the device struct.
+ * @preemphasis: The new pre-amphasis value.
+ *
+ * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED,
+ * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS.
+ */
+static int wl1273_fm_set_preemphasis(struct wl1273_device *radio,
+ unsigned int preemphasis)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+ u16 em;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ mutex_lock(&core->lock);
+
+ switch (preemphasis) {
+ case V4L2_PREEMPHASIS_DISABLED:
+ em = 1;
+ break;
+ case V4L2_PREEMPHASIS_50_uS:
+ em = 0;
+ break;
+ case V4L2_PREEMPHASIS_75_uS:
+ em = 2;
+ break;
+ default:
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = wl1273_fm_write_cmd(core, WL1273_PREMPH_SET, em);
+ if (r)
+ goto out;
+
+ radio->preemphasis = preemphasis;
+
+out:
+ mutex_unlock(&core->lock);
+ return r;
+}
+
+static int wl1273_fm_rds_on(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ if (radio->rds_on)
+ return 0;
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r)
+ dev_err(radio->dev, "set freq fails: %d.\n", r);
+out:
+ return r;
+}
+
+static int wl1273_fm_rds_off(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ if (!radio->rds_on)
+ return 0;
+
+ radio->irq_flags &= ~WL1273_RDS_EVENT;
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+ if (r)
+ goto out;
+
+ /* stop rds reception */
+ cancel_delayed_work(&radio->work);
+
+ /* Service pending read */
+ wake_up_interruptible(&radio->read_queue);
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, WL1273_POWER_SET_FM);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r)
+ dev_err(radio->dev, "set freq fails: %d.\n", r);
+out:
+ dev_dbg(radio->dev, "%s: exiting...\n", __func__);
+
+ return r;
+}
+
+static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode)
+{
+ int r = 0;
+ struct wl1273_core *core = radio->core;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ if (new_mode == WL1273_RDS_RESET) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_CNTRL_SET, 1);
+ return r;
+ }
+
+ if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+ } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+ } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) {
+ r = wl1273_fm_rds_off(radio);
+ } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) {
+ r = wl1273_fm_rds_on(radio);
+ } else {
+ dev_err(radio->dev, "%s: Unknown mode: %d\n",
+ __func__, new_mode);
+ r = -EINVAL;
+ }
+
+ if (!r)
+ radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false;
+
+ return r;
+}
+
+static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->core->mode != WL1273_MODE_TX)
+ return count;
+
+ if (radio->rds_users == 0) {
+ dev_warn(radio->dev, "%s: RDS not on.\n", __func__);
+ return 0;
+ }
+
+ if (mutex_lock_interruptible(&radio->core->lock))
+ return -EINTR;
+ /*
+ * Multiple processes can open the device, but only
+ * one gets to write to it.
+ */
+ if (radio->owner && radio->owner != file) {
+ r = -EBUSY;
+ goto out;
+ }
+ radio->owner = file;
+
+ /* Manual Mode */
+ if (count > 255)
+ val = 255;
+ else
+ val = count;
+
+ wl1273_fm_write_cmd(radio->core, WL1273_RDS_CONFIG_DATA_SET, val);
+
+ if (copy_from_user(radio->write_buf + 1, buf, val)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ dev_dbg(radio->dev, "Count: %d\n", val);
+ dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf);
+
+ radio->write_buf[0] = WL1273_RDS_DATA_SET;
+ wl1273_fm_write_data(radio->core, radio->write_buf, val + 1);
+
+ r = val;
+out:
+ mutex_unlock(&radio->core->lock);
+
+ return r;
+}
+
+static unsigned int wl1273_fm_fops_poll(struct file *file,
+ struct poll_table_struct *pts)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+
+ if (radio->owner && radio->owner != file)
+ return -EBUSY;
+
+ radio->owner = file;
+
+ if (core->mode == WL1273_MODE_RX) {
+ poll_wait(file, &radio->read_queue, pts);
+
+ if (radio->rd_index != radio->wr_index)
+ return POLLIN | POLLRDNORM;
+
+ } else if (core->mode == WL1273_MODE_TX) {
+ return POLLOUT | POLLWRNORM;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_fops_open(struct file *file)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (core->mode == WL1273_MODE_RX && radio->rds_on &&
+ !radio->rds_users) {
+ dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ radio->irq_flags |= WL1273_RDS_EVENT;
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ mutex_unlock(&core->lock);
+ goto out;
+ }
+
+ radio->rds_users++;
+
+ mutex_unlock(&core->lock);
+ }
+out:
+ return r;
+}
+
+static int wl1273_fm_fops_release(struct file *file)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->rds_users > 0) {
+ radio->rds_users--;
+ if (radio->rds_users == 0) {
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ radio->irq_flags &= ~WL1273_RDS_EVENT;
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_write_cmd(core,
+ WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ mutex_unlock(&core->lock);
+ goto out;
+ }
+ }
+ mutex_unlock(&core->lock);
+ }
+ }
+
+ if (file == radio->owner)
+ radio->owner = NULL;
+out:
+ return r;
+}
+
+static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int r = 0;
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ unsigned int block_count = 0;
+ u16 val;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->core->mode != WL1273_MODE_RX)
+ return 0;
+
+ if (radio->rds_users == 0) {
+ dev_warn(radio->dev, "%s: RDS not on.\n", __func__);
+ return 0;
+ }
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ /*
+ * Multiple processes can open the device, but only
+ * one at a time gets read access.
+ */
+ if (radio->owner && radio->owner != file) {
+ r = -EBUSY;
+ goto out;
+ }
+ radio->owner = file;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r) {
+ dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__);
+ goto out;
+ } else if (val == 0) {
+ dev_info(radio->dev, "RDS_SYNC: Not synchronized\n");
+ r = -ENODATA;
+ goto out;
+ }
+
+ /* block if no new data available */
+ while (radio->wr_index == radio->rd_index) {
+ if (file->f_flags & O_NONBLOCK) {
+ r = -EWOULDBLOCK;
+ goto out;
+ }
+
+ dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__);
+ if (wait_event_interruptible(radio->read_queue,
+ radio->wr_index !=
+ radio->rd_index) < 0) {
+ r = -EINTR;
+ goto out;
+ }
+ }
+
+ /* calculate block count from byte count */
+ count /= RDS_BLOCK_SIZE;
+
+ /* copy RDS blocks from the internal buffer and to user buffer */
+ while (block_count < count) {
+ if (radio->rd_index == radio->wr_index)
+ break;
+
+ /* always transfer complete RDS blocks */
+ if (copy_to_user(buf, &radio->buffer[radio->rd_index],
+ RDS_BLOCK_SIZE))
+ break;
+
+ /* increment and wrap the read pointer */
+ radio->rd_index += RDS_BLOCK_SIZE;
+ if (radio->rd_index >= radio->buf_size)
+ radio->rd_index = 0;
+
+ /* increment counters */
+ block_count++;
+ buf += RDS_BLOCK_SIZE;
+ r += RDS_BLOCK_SIZE;
+ }
+
+out:
+ dev_dbg(radio->dev, "%s: exit\n", __func__);
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static const struct v4l2_file_operations wl1273_fops = {
+ .owner = THIS_MODULE,
+ .read = wl1273_fm_fops_read,
+ .write = wl1273_fm_fops_write,
+ .poll = wl1273_fm_fops_poll,
+ .ioctl = video_ioctl2,
+ .open = wl1273_fm_fops_open,
+ .release = wl1273_fm_fops_release,
+};
+
+static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ strlcpy(capability->driver, WL1273_FM_DRIVER_NAME,
+ sizeof(capability->driver));
+ strlcpy(capability->card, "Texas Instruments Wl1273 FM Radio",
+ sizeof(capability->card));
+ strlcpy(capability->bus_info, radio->bus_type,
+ sizeof(capability->bus_info));
+
+ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+ V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO |
+ V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR |
+ V4L2_CAP_RDS_OUTPUT;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ *i = 0;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_input(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * wl1273_fm_set_tx_power() - Set the transmission power value.
+ * @core: A pointer to the device struct.
+ * @power: The new power value.
+ */
+static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power)
+{
+ int r;
+
+ if (radio->core->mode == WL1273_MODE_OFF ||
+ radio->core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ mutex_lock(&radio->core->lock);
+
+ /* Convert the dBuV value to chip presentation */
+ r = wl1273_fm_write_cmd(radio->core, WL1273_POWER_LEV_SET, 122 - power);
+ if (r)
+ goto out;
+
+ radio->tx_power = power;
+
+out:
+ mutex_unlock(&radio->core->lock);
+ return r;
+}
+
+#define WL1273_SPACING_50kHz 1
+#define WL1273_SPACING_100kHz 2
+#define WL1273_SPACING_200kHz 4
+
+static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio,
+ unsigned int spacing)
+{
+ int r;
+
+ if (spacing == 0) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_100kHz);
+ radio->spacing = 100;
+ } else if (spacing - 50000 < 25000) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_50kHz);
+ radio->spacing = 50;
+ } else if (spacing - 100000 < 50000) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_100kHz);
+ radio->spacing = 100;
+ } else {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_200kHz);
+ radio->spacing = 200;
+ }
+
+ return r;
+}
+
+static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct wl1273_device *radio = ctrl->priv;
+ struct wl1273_core *core = radio->core;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ switch (ctrl->id) {
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ ctrl->val = wl1273_fm_get_tx_ctune(radio);
+ break;
+
+ default:
+ dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+#define WL1273_MUTE_SOFT_ENABLE (1 << 0)
+#define WL1273_MUTE_AC (1 << 1)
+#define WL1273_MUTE_HARD_LEFT (1 << 2)
+#define WL1273_MUTE_HARD_RIGHT (1 << 3)
+#define WL1273_MUTE_SOFT_FORCE (1 << 4)
+
+static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct wl1273_device, ctrl_handler);
+}
+
+static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct wl1273_device *radio = to_radio(ctrl);
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ if (core->mode == WL1273_MODE_RX && ctrl->val)
+ r = wl1273_fm_write_cmd(core,
+ WL1273_MUTE_STATUS_SET,
+ WL1273_MUTE_HARD_LEFT |
+ WL1273_MUTE_HARD_RIGHT);
+ else if (core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core,
+ WL1273_MUTE_STATUS_SET, 0x0);
+ else if (core->mode == WL1273_MODE_TX && ctrl->val)
+ r = wl1273_fm_write_cmd(core, WL1273_MUTE, 1);
+ else if (core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MUTE, 0);
+
+ mutex_unlock(&core->lock);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ if (ctrl->val == 0)
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF);
+ else
+ r = core->set_volume(core, core->volume);
+ break;
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ r = wl1273_fm_set_preemphasis(radio, ctrl->val);
+ break;
+
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ r = wl1273_fm_set_tx_power(radio, ctrl->val);
+ break;
+
+ default:
+ dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (audio->index > 1)
+ return -EINVAL;
+
+ strlcpy(audio->name, "Radio", sizeof(audio->name));
+ audio->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (audio->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+#define WL1273_RDS_NOT_SYNCHRONIZED 0
+#define WL1273_RDS_SYNCHRONIZED 1
+
+static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (tuner->index > 0)
+ return -EINVAL;
+
+ strlcpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name));
+ tuner->type = V4L2_TUNER_RADIO;
+
+ tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
+ tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
+
+ tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+
+ if (radio->stereo)
+ tuner->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+ if (core->mode != WL1273_MODE_RX)
+ return 0;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+ if (r)
+ goto out;
+
+ if (val == 1)
+ tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ else
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+ if (r)
+ goto out;
+
+ tuner->signal = (s16) val;
+ dev_dbg(radio->dev, "Signal: %d\n", tuner->signal);
+
+ tuner->afc = 0;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ goto out;
+
+ if (val == WL1273_RDS_SYNCHRONIZED)
+ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index);
+ dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name);
+ dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability);
+ dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans);
+ dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow);
+ dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh);
+
+ if (tuner->index > 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_RX);
+ if (r)
+ goto out;
+
+ if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS)
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_ON);
+ else
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF);
+
+ if (r)
+ dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r);
+
+ if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_MONO);
+ if (r < 0) {
+ dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+ radio->stereo = false;
+ } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) {
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_STEREO);
+ if (r < 0) {
+ dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+ radio->stereo = true;
+ } else {
+ dev_err(radio->dev, "%s: tuner->audmode: %d\n",
+ __func__, tuner->audmode);
+ r = -EINVAL;
+ goto out;
+ }
+
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ freq->type = V4L2_TUNER_RADIO;
+ freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio));
+
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency);
+
+ if (freq->type != V4L2_TUNER_RADIO) {
+ dev_dbg(radio->dev,
+ "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type);
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ if (core->mode == WL1273_MODE_RX) {
+ dev_dbg(radio->dev, "freq: %d\n", freq->frequency);
+
+ r = wl1273_fm_set_rx_freq(radio,
+ WL1273_INV_FREQ(freq->frequency));
+ if (r)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ ": set frequency failed with %d\n", r);
+ } else {
+ r = wl1273_fm_set_tx_freq(radio,
+ WL1273_INV_FREQ(freq->frequency));
+ if (r)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ ": set frequency failed with %d\n", r);
+ }
+
+ mutex_unlock(&core->lock);
+
+ dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n");
+ return r;
+}
+
+#define WL1273_DEFAULT_SEEK_LEVEL 7
+
+static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+ struct v4l2_hw_freq_seek *seek)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_RX);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_tx_set_spacing(radio, seek->spacing);
+ if (r)
+ dev_warn(radio->dev, "HW seek failed: %d\n", r);
+
+ r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward,
+ WL1273_DEFAULT_SEEK_LEVEL);
+ if (r)
+ dev_warn(radio->dev, "HW seek failed: %d\n", r);
+
+out:
+ mutex_unlock(&core->lock);
+ return r;
+}
+
+static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *modulator)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (modulator->index > 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_TX);
+ if (r)
+ goto out;
+
+ if (modulator->txsubchans & V4L2_TUNER_SUB_RDS)
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_ON);
+ else
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF);
+
+ if (modulator->txsubchans & V4L2_TUNER_SUB_MONO)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, WL1273_TX_MONO);
+ else
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_RX_STEREO);
+ if (r < 0)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ "MONO_SET fails: %d\n", r);
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *modulator)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ strlcpy(modulator->name, WL1273_FM_DRIVER_NAME,
+ sizeof(modulator->name));
+
+ modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
+ modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
+
+ modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+
+ if (core->mode != WL1273_MODE_TX)
+ return 0;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_read_reg(core, WL1273_MONO_SET, &val);
+ if (r)
+ goto out;
+
+ if (val == WL1273_TX_STEREO)
+ modulator->txsubchans = V4L2_TUNER_SUB_STEREO;
+ else
+ modulator->txsubchans = V4L2_TUNER_SUB_MONO;
+
+ if (radio->rds_on)
+ modulator->txsubchans |= V4L2_TUNER_SUB_RDS;
+out:
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ u16 val;
+ int r;
+
+ dev_info(dev, DRIVER_DESC);
+
+ if (core->mode == WL1273_MODE_OFF) {
+ dev_info(dev, "Mode: Off\n");
+ return 0;
+ }
+
+ if (core->mode == WL1273_MODE_SUSPENDED) {
+ dev_info(dev, "Mode: Suspended\n");
+ return 0;
+ }
+
+ r = wl1273_fm_read_reg(core, WL1273_ASIC_ID_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__);
+ else
+ dev_info(dev, "ASIC_ID: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_ASIC_VER_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__);
+ else
+ dev_info(dev, "ASIC Version: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_FIRM_VER_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__);
+ else
+ dev_info(dev, "FW version: %d(0x%04x)\n", val, val);
+
+ r = wl1273_fm_read_reg(core, WL1273_BAND_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get BAND fails.\n", __func__);
+ else
+ dev_info(dev, "BAND: %d\n", val);
+
+ if (core->mode == WL1273_MODE_TX) {
+ r = wl1273_fm_read_reg(core, WL1273_PUPD_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get PUPD fails.\n", __func__);
+ else
+ dev_info(dev, "PUPD: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get CHANL fails.\n", __func__);
+ else
+ dev_info(dev, "Tx frequency: %dkHz\n", val*10);
+ } else if (core->mode == WL1273_MODE_RX) {
+ int bf = radio->rangelow;
+
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get FREQ fails.\n", __func__);
+ else
+ dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50);
+
+ r = wl1273_fm_read_reg(core, WL1273_MOST_MODE_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get MOST_MODE fails.\n",
+ __func__);
+ else if (val == 0)
+ dev_info(dev, "MOST_MODE: Stereo according to blend\n");
+ else if (val == 1)
+ dev_info(dev, "MOST_MODE: Force mono output\n");
+ else
+ dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_MOST_BLEND_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__);
+ else if (val == 0)
+ dev_info(dev,
+ "MOST_BLEND: Switched blend & hysteresis.\n");
+ else if (val == 1)
+ dev_info(dev, "MOST_BLEND: Soft blend.\n");
+ else
+ dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get STEREO fails.\n", __func__);
+ else if (val == 0)
+ dev_info(dev, "STEREO: Not detected\n");
+ else if (val == 1)
+ dev_info(dev, "STEREO: Detected\n");
+ else
+ dev_info(dev, "STEREO: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__);
+ else
+ dev_info(dev, "RX signal strength: %d\n", (s16) val);
+
+ r = wl1273_fm_read_reg(core, WL1273_POWER_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get POWER fails.\n", __func__);
+ else
+ dev_info(dev, "POWER: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_INT_MASK_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get INT_MASK fails.\n", __func__);
+ else
+ dev_info(dev, "INT_MASK: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get RDS_SYNC fails.\n",
+ __func__);
+ else if (val == 0)
+ dev_info(dev, "RDS_SYNC: Not synchronized\n");
+
+ else if (val == 1)
+ dev_info(dev, "RDS_SYNC: Synchronized\n");
+ else
+ dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_I2S_MODE_CONFIG_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n",
+ __func__);
+ else
+ dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get VOLUME fails.\n", __func__);
+ else
+ dev_info(dev, "VOLUME: 0x%04x\n", val);
+ }
+
+ return 0;
+}
+
+static void wl1273_vdev_release(struct video_device *dev)
+{
+}
+
+static const struct v4l2_ctrl_ops wl1273_ctrl_ops = {
+ .s_ctrl = wl1273_fm_vidioc_s_ctrl,
+ .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl,
+};
+
+static const struct v4l2_ioctl_ops wl1273_ioctl_ops = {
+ .vidioc_querycap = wl1273_fm_vidioc_querycap,
+ .vidioc_g_input = wl1273_fm_vidioc_g_input,
+ .vidioc_s_input = wl1273_fm_vidioc_s_input,
+ .vidioc_g_audio = wl1273_fm_vidioc_g_audio,
+ .vidioc_s_audio = wl1273_fm_vidioc_s_audio,
+ .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner,
+ .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner,
+ .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency,
+ .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency,
+ .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek,
+ .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator,
+ .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator,
+ .vidioc_log_status = wl1273_fm_vidioc_log_status,
+};
+
+static struct video_device wl1273_viddev_template = {
+ .fops = &wl1273_fops,
+ .ioctl_ops = &wl1273_ioctl_ops,
+ .name = WL1273_FM_DRIVER_NAME,
+ .release = wl1273_vdev_release,
+};
+
+static int wl1273_fm_radio_remove(struct platform_device *pdev)
+{
+ struct wl1273_device *radio = platform_get_drvdata(pdev);
+ struct wl1273_core *core = radio->core;
+
+ dev_info(&pdev->dev, "%s.\n", __func__);
+
+ free_irq(core->client->irq, radio);
+ core->pdata->free_resources();
+
+ v4l2_ctrl_handler_free(&radio->ctrl_handler);
+ video_unregister_device(&radio->videodev);
+ v4l2_device_unregister(&radio->v4l2dev);
+ kfree(radio->buffer);
+ kfree(radio->write_buf);
+ kfree(radio);
+
+ return 0;
+}
+
+static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
+{
+ struct wl1273_core **core = pdev->dev.platform_data;
+ struct wl1273_device *radio;
+ struct v4l2_ctrl *ctrl;
+ int r = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (!core) {
+ dev_err(&pdev->dev, "No platform data.\n");
+ r = -EINVAL;
+ goto pdata_err;
+ }
+
+ radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+ if (!radio) {
+ r = -ENOMEM;
+ goto pdata_err;
+ }
+
+ /* RDS buffer allocation */
+ radio->buf_size = rds_buf * RDS_BLOCK_SIZE;
+ radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+ if (!radio->buffer) {
+ pr_err("Cannot allocate memory for RDS buffer.\n");
+ r = -ENOMEM;
+ goto err_kmalloc;
+ }
+
+ radio->core = *core;
+ radio->irq_flags = WL1273_IRQ_MASK;
+ radio->dev = &radio->core->client->dev;
+ radio->rds_on = false;
+ radio->core->mode = WL1273_MODE_OFF;
+ radio->tx_power = 118;
+ radio->core->audio_mode = WL1273_AUDIO_ANALOG;
+ radio->band = WL1273_BAND_OTHER;
+ radio->core->i2s_mode = WL1273_I2S_DEF_MODE;
+ radio->core->channel_number = 2;
+ radio->core->volume = WL1273_DEFAULT_VOLUME;
+ radio->rx_frequency = WL1273_BAND_OTHER_LOW;
+ radio->tx_frequency = WL1273_BAND_OTHER_HIGH;
+ radio->rangelow = WL1273_BAND_OTHER_LOW;
+ radio->rangehigh = WL1273_BAND_OTHER_HIGH;
+ radio->stereo = true;
+ radio->bus_type = "I2C";
+
+ radio->core->write = wl1273_fm_write_cmd;
+ radio->core->set_audio = wl1273_fm_set_audio;
+ radio->core->set_volume = wl1273_fm_set_volume;
+
+ if (radio->core->pdata->request_resources) {
+ r = radio->core->pdata->request_resources(radio->core->client);
+ if (r) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": Cannot get platform data\n");
+ goto err_resources;
+ }
+
+ dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq);
+
+ r = request_threaded_irq(radio->core->client->irq, NULL,
+ wl1273_fm_irq_thread_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ "wl1273-fm", radio);
+ if (r < 0) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": Unable to register IRQ handler: %d\n", r);
+ goto err_request_irq;
+ }
+ } else {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ"
+ " not configured");
+ r = -EINVAL;
+ goto err_resources;
+ }
+
+ init_completion(&radio->busy);
+ init_waitqueue_head(&radio->read_queue);
+
+ radio->write_buf = kmalloc(256, GFP_KERNEL);
+ if (!radio->write_buf) {
+ r = -ENOMEM;
+ goto write_buf_err;
+ }
+
+ radio->dev = &pdev->dev;
+ radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
+ radio->rds_users = 0;
+
+ r = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
+ if (r) {
+ dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
+ goto device_register_err;
+ }
+
+ /* V4L2 configuration */
+ memcpy(&radio->videodev, &wl1273_viddev_template,
+ sizeof(wl1273_viddev_template));
+
+ radio->videodev.v4l2_dev = &radio->v4l2dev;
+
+ v4l2_ctrl_handler_init(&radio->ctrl_handler, 6);
+
+ /* add in ascending ID order */
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1,
+ WL1273_DEFAULT_VOLUME);
+
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+
+ v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_PREEMPHASIS,
+ V4L2_PREEMPHASIS_75_uS, 0x03,
+ V4L2_PREEMPHASIS_50_uS);
+
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118);
+
+ ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_ANTENNA_CAPACITOR,
+ 0, 255, 1, 255);
+ if (ctrl)
+ ctrl->is_volatile = 1;
+
+ if (radio->ctrl_handler.error) {
+ r = radio->ctrl_handler.error;
+ dev_err(&pdev->dev, "Ctrl handler error: %d\n", r);
+ goto handler_init_err;
+ }
+
+ video_set_drvdata(&radio->videodev, radio);
+ platform_set_drvdata(pdev, radio);
+
+ /* register video device */
+ r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (r) {
+ dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME
+ ": Could not register video device\n");
+ goto handler_init_err;
+ }
+
+ return 0;
+
+handler_init_err:
+ v4l2_ctrl_handler_free(&radio->ctrl_handler);
+ v4l2_device_unregister(&radio->v4l2dev);
+device_register_err:
+ kfree(radio->write_buf);
+write_buf_err:
+ free_irq(radio->core->client->irq, radio);
+err_request_irq:
+ radio->core->pdata->free_resources();
+err_resources:
+ kfree(radio->buffer);
+err_kmalloc:
+ kfree(radio);
+pdata_err:
+ return r;
+}
+
+MODULE_ALIAS("platform:wl1273_fm_radio");
+
+static struct platform_driver wl1273_fm_radio_driver = {
+ .probe = wl1273_fm_radio_probe,
+ .remove = __devexit_p(wl1273_fm_radio_remove),
+ .driver = {
+ .name = "wl1273_fm_radio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wl1273_fm_module_init(void)
+{
+ pr_info("%s\n", __func__);
+ return platform_driver_register(&wl1273_fm_radio_driver);
+}
+module_init(wl1273_fm_module_init);
+
+static void __exit wl1273_fm_module_exit(void)
+{
+ flush_scheduled_work();
+ platform_driver_unregister(&wl1273_fm_radio_driver);
+ pr_info(DRIVER_DESC ", Exiting.\n");
+}
+module_exit(wl1273_fm_module_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index f31eab99c943..af99c5bd88c1 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
@@ -424,20 +424,6 @@ static int __init zoltrix_init(void)
return res;
}
- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
- zol->vdev.v4l2_dev = v4l2_dev;
- zol->vdev.fops = &zoltrix_fops;
- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
- zol->vdev.release = video_device_release_empty;
- video_set_drvdata(&zol->vdev, zol);
-
- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(zol->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
mutex_init(&zol->lock);
/* mute card - prevents noisy bootups */
@@ -452,6 +438,20 @@ static int __init zoltrix_init(void)
zol->curvol = 0;
zol->stereo = 1;
+ strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
+ zol->vdev.v4l2_dev = v4l2_dev;
+ zol->vdev.fops = &zoltrix_fops;
+ zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
+ zol->vdev.release = video_device_release_empty;
+ video_set_drvdata(&zol->vdev, zol);
+
+ if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(zol->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
+
return 0;
}
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index ea12782359a0..4a4e908db04c 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -31,14 +31,12 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/rds.h>
#include <asm/unaligned.h>
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index a6e6f1987a3a..0fab6f8f7e24 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -27,6 +27,8 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
@@ -43,6 +45,11 @@ MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter");
MODULE_VERSION("0.0.1");
+static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
+ "vio",
+ "vdd",
+};
+
#define DEFAULT_RDS_PI 0x00
#define DEFAULT_RDS_PTY 0x00
#define DEFAULT_RDS_PS_NAME ""
@@ -369,7 +376,17 @@ static int si4713_powerup(struct si4713_device *sdev)
if (sdev->power_state)
return 0;
- sdev->platform_data->set_power(1);
+ err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err) {
+ v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err);
+ return err;
+ }
+ if (gpio_is_valid(sdev->gpio_reset)) {
+ udelay(50);
+ gpio_set_value(sdev->gpio_reset, 1);
+ }
+
err = si4713_send_command(sdev, SI4713_CMD_POWER_UP,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
@@ -384,7 +401,13 @@ static int si4713_powerup(struct si4713_device *sdev)
err = si4713_write_property(sdev, SI4713_GPO_IEN,
SI4713_STC_INT | SI4713_CTS);
} else {
- sdev->platform_data->set_power(0);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_set_value(sdev->gpio_reset, 0);
+ err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
}
return err;
@@ -411,7 +434,13 @@ static int si4713_powerdown(struct si4713_device *sdev)
v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
resp[0]);
v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
- sdev->platform_data->set_power(0);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_set_value(sdev->gpio_reset, 0);
+ err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
sdev->power_state = POWER_OFF;
}
@@ -1967,7 +1996,8 @@ static int si4713_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct si4713_device *sdev;
- int rval;
+ struct si4713_platform_data *pdata = client->dev.platform_data;
+ int rval, i;
sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
if (!sdev) {
@@ -1976,11 +2006,26 @@ static int si4713_probe(struct i2c_client *client,
goto exit;
}
- sdev->platform_data = client->dev.platform_data;
- if (!sdev->platform_data) {
- v4l2_err(&sdev->sd, "No platform data registered.\n");
- rval = -ENODEV;
- goto free_sdev;
+ sdev->gpio_reset = -1;
+ if (pdata && gpio_is_valid(pdata->gpio_reset)) {
+ rval = gpio_request(pdata->gpio_reset, "si4713 reset");
+ if (rval) {
+ dev_err(&client->dev,
+ "Failed to request gpio: %d\n", rval);
+ goto free_sdev;
+ }
+ sdev->gpio_reset = pdata->gpio_reset;
+ gpio_direction_output(sdev->gpio_reset, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++)
+ sdev->supplies[i].supply = si4713_supply_names[i];
+
+ rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (rval) {
+ dev_err(&client->dev, "Cannot get regulators: %d\n", rval);
+ goto free_gpio;
}
v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops);
@@ -1994,7 +2039,7 @@ static int si4713_probe(struct i2c_client *client,
client->name, sdev);
if (rval < 0) {
v4l2_err(&sdev->sd, "Could not request IRQ\n");
- goto free_sdev;
+ goto put_reg;
}
v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n");
} else {
@@ -2012,6 +2057,11 @@ static int si4713_probe(struct i2c_client *client,
free_irq:
if (client->irq)
free_irq(client->irq, sdev);
+put_reg:
+ regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+free_gpio:
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_free(sdev->gpio_reset);
free_sdev:
kfree(sdev);
exit:
@@ -2031,7 +2081,9 @@ static int si4713_remove(struct i2c_client *client)
free_irq(client->irq, sdev);
v4l2_device_unregister_subdev(sd);
-
+ regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_free(sdev->gpio_reset);
kfree(sdev);
return 0;
diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h
index faf8cff124f1..c6dfa7fb101c 100644
--- a/drivers/media/radio/si4713-i2c.h
+++ b/drivers/media/radio/si4713-i2c.h
@@ -211,6 +211,8 @@ struct acomp_info {
u32 enabled;
};
+#define SI4713_NUM_SUPPLIES 2
+
/*
* si4713_device - private data
*/
@@ -220,11 +222,12 @@ struct si4713_device {
/* private data structures */
struct mutex mutex;
struct completion work;
- struct si4713_platform_data *platform_data;
struct rds_info rds_info;
struct limiter_info limiter_info;
struct pilot_info pilot_info;
struct acomp_info acomp_info;
+ struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES];
+ int gpio_reset;
u32 frequency;
u32 preemphasis;
u32 mute;
diff --git a/drivers/media/IR/Kconfig b/drivers/media/rc/Kconfig
index aa4163eb7a83..3785162f928e 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -1,21 +1,17 @@
-menuconfig IR_CORE
- tristate "Infrared remote controller adapters"
+menuconfig RC_CORE
+ tristate "Remote Controller adapters"
depends on INPUT
default INPUT
---help---
Enable support for Remote Controllers on Linux. This is
needed in order to support several video capture adapters.
+ Currently, all supported devices use InfraRed.
Enable this option if you have a video capture board even
if you don't need IR, as otherwise, you may not be able to
compile the driver for your adapter.
-config VIDEO_IR
- tristate
- depends on IR_CORE
- default IR_CORE
-
-if IR_CORE
+if RC_CORE
config LIRC
tristate
@@ -28,11 +24,11 @@ config LIRC
LIRC daemon handles protocol decoding for IR reception and
encoding for IR transmitting (aka "blasting").
-source "drivers/media/IR/keymaps/Kconfig"
+source "drivers/media/rc/keymaps/Kconfig"
config IR_NEC_DECODER
tristate "Enable IR raw decoder for the NEC protocol"
- depends on IR_CORE
+ depends on RC_CORE
select BITREVERSE
default y
@@ -42,7 +38,7 @@ config IR_NEC_DECODER
config IR_RC5_DECODER
tristate "Enable IR raw decoder for the RC-5 protocol"
- depends on IR_CORE
+ depends on RC_CORE
select BITREVERSE
default y
@@ -52,7 +48,7 @@ config IR_RC5_DECODER
config IR_RC6_DECODER
tristate "Enable IR raw decoder for the RC6 protocol"
- depends on IR_CORE
+ depends on RC_CORE
select BITREVERSE
default y
@@ -62,7 +58,7 @@ config IR_RC6_DECODER
config IR_JVC_DECODER
tristate "Enable IR raw decoder for the JVC protocol"
- depends on IR_CORE
+ depends on RC_CORE
select BITREVERSE
default y
@@ -72,7 +68,7 @@ config IR_JVC_DECODER
config IR_SONY_DECODER
tristate "Enable IR raw decoder for the Sony protocol"
- depends on IR_CORE
+ depends on RC_CORE
default y
---help---
@@ -81,7 +77,7 @@ config IR_SONY_DECODER
config IR_RC5_SZ_DECODER
tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
- depends on IR_CORE
+ depends on RC_CORE
select BITREVERSE
default y
@@ -93,7 +89,7 @@ config IR_RC5_SZ_DECODER
config IR_LIRC_CODEC
tristate "Enable IR to LIRC bridge"
- depends on IR_CORE
+ depends on RC_CORE
depends on LIRC
default y
@@ -104,7 +100,7 @@ config IR_LIRC_CODEC
config IR_ENE
tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
depends on PNP
- depends on IR_CORE
+ depends on RC_CORE
---help---
Say Y here to enable support for integrated infrared receiver
/transceiver made by ENE.
@@ -118,7 +114,7 @@ config IR_ENE
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
depends on USB_ARCH_HAS_HCD
- depends on IR_CORE
+ depends on RC_CORE
select USB
---help---
Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
@@ -130,7 +126,7 @@ config IR_IMON
config IR_MCEUSB
tristate "Windows Media Center Ed. eHome Infrared Transceiver"
depends on USB_ARCH_HAS_HCD
- depends on IR_CORE
+ depends on RC_CORE
select USB
---help---
Say Y here if you want to use a Windows Media Center Edition
@@ -142,7 +138,7 @@ config IR_MCEUSB
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
- depends on IR_CORE
+ depends on RC_CORE
---help---
Say Y here to enable support for integrated infrared receiver
/transciever made by Nuvoton (formerly Winbond). This chip is
@@ -155,7 +151,7 @@ config IR_NUVOTON
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"
depends on USB_ARCH_HAS_HCD
- depends on IR_CORE
+ depends on RC_CORE
select USB
---help---
Say Y here if you want to use a Streamzap PC Remote
@@ -164,4 +160,34 @@ config IR_STREAMZAP
To compile this driver as a module, choose M here: the
module will be called streamzap.
-endif #IR_CORE
+config IR_WINBOND_CIR
+ tristate "Winbond IR remote control"
+ depends on X86 && PNP
+ depends on RC_CORE
+ select NEW_LEDS
+ select LEDS_CLASS
+ select LEDS_TRIGGERS
+ select BITREVERSE
+ ---help---
+ Say Y here if you want to use the IR remote functionality found
+ in some Winbond SuperI/O chips. Currently only the WPCD376I
+ chip is supported (included in some Intel Media series
+ motherboards).
+
+ To compile this driver as a module, choose M here: the module will
+ be called winbond_cir.
+
+config RC_LOOPBACK
+ tristate "Remote Control Loopback Driver"
+ depends on RC_CORE
+ ---help---
+ Say Y here if you want support for the remote control loopback
+ driver which allows TX data to be sent back as RX data.
+ This is mostly useful for debugging purposes.
+
+ If you're not sure, select N here.
+
+ To compile this driver as a module, choose M here: the module will
+ be called rc_loopback.
+
+endif #RC_CORE
diff --git a/drivers/media/IR/Makefile b/drivers/media/rc/Makefile
index f9574adab82a..67b4f7fe2577 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,10 +1,8 @@
-ir-common-objs := ir-functions.o
-ir-core-objs := ir-keytable.o ir-sysfs.o ir-raw-event.o rc-map.o
+rc-core-objs := rc-main.o ir-raw.o
obj-y += keymaps/
-obj-$(CONFIG_IR_CORE) += ir-core.o
-obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_RC_CORE) += rc-core.o
obj-$(CONFIG_LIRC) += lirc_dev.o
obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
@@ -20,3 +18,5 @@ obj-$(CONFIG_IR_MCEUSB) += mceusb.o
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
+obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
+obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
diff --git a/drivers/media/IR/ene_ir.c b/drivers/media/rc/ene_ir.c
index 7637babcd262..80b3c319f698 100644
--- a/drivers/media/IR/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -37,9 +37,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/input.h>
-#include <media/ir-core.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include "ene_ir.h"
static int sample_period;
@@ -357,7 +355,7 @@ void ene_rx_sense_carrier(struct ene_device *dev)
ev.carrier_report = true;
ev.carrier = carrier;
ev.duty_cycle = duty_cycle;
- ir_raw_event_store(dev->idev, &ev);
+ ir_raw_event_store(dev->rdev, &ev);
}
}
@@ -448,32 +446,32 @@ static void ene_rx_setup(struct ene_device *dev)
select_timeout:
if (dev->rx_fan_input_inuse) {
- dev->props->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
+ dev->rdev->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
/* Fan input doesn't support timeouts, it just ends the
input with a maximum sample */
- dev->props->min_timeout = dev->props->max_timeout =
+ dev->rdev->min_timeout = dev->rdev->max_timeout =
MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
ENE_FW_SAMPLE_PERIOD_FAN);
} else {
- dev->props->rx_resolution = MS_TO_NS(sample_period);
+ dev->rdev->rx_resolution = MS_TO_NS(sample_period);
/* Theoreticly timeout is unlimited, but we cap it
* because it was seen that on one device, it
* would stop sending spaces after around 250 msec.
* Besides, this is close to 2^32 anyway and timeout is u32.
*/
- dev->props->min_timeout = MS_TO_NS(127 * sample_period);
- dev->props->max_timeout = MS_TO_NS(200000);
+ dev->rdev->min_timeout = MS_TO_NS(127 * sample_period);
+ dev->rdev->max_timeout = MS_TO_NS(200000);
}
if (dev->hw_learning_and_tx_capable)
- dev->props->tx_resolution = MS_TO_NS(sample_period);
+ dev->rdev->tx_resolution = MS_TO_NS(sample_period);
- if (dev->props->timeout > dev->props->max_timeout)
- dev->props->timeout = dev->props->max_timeout;
- if (dev->props->timeout < dev->props->min_timeout)
- dev->props->timeout = dev->props->min_timeout;
+ if (dev->rdev->timeout > dev->rdev->max_timeout)
+ dev->rdev->timeout = dev->rdev->max_timeout;
+ if (dev->rdev->timeout < dev->rdev->min_timeout)
+ dev->rdev->timeout = dev->rdev->min_timeout;
}
/* Enable the device for receive */
@@ -504,7 +502,7 @@ static void ene_rx_enable(struct ene_device *dev)
ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
/* enter idle mode */
- ir_raw_event_set_idle(dev->idev, true);
+ ir_raw_event_set_idle(dev->rdev, true);
dev->rx_enabled = true;
}
@@ -518,7 +516,7 @@ static void ene_rx_disable(struct ene_device *dev)
/* disable hardware IRQ and firmware flag */
ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
- ir_raw_event_set_idle(dev->idev, true);
+ ir_raw_event_set_idle(dev->rdev, true);
dev->rx_enabled = false;
}
@@ -805,10 +803,10 @@ static irqreturn_t ene_isr(int irq, void *data)
ev.duration = MS_TO_NS(hw_sample);
ev.pulse = pulse;
- ir_raw_event_store_with_filter(dev->idev, &ev);
+ ir_raw_event_store_with_filter(dev->rdev, &ev);
}
- ir_raw_event_handle(dev->idev);
+ ir_raw_event_handle(dev->rdev);
unlock:
spin_unlock_irqrestore(&dev->hw_lock, flags);
return retval;
@@ -823,7 +821,7 @@ static void ene_setup_default_settings(struct ene_device *dev)
dev->learning_mode_enabled = learning_mode_force;
/* Set reasonable default timeout */
- dev->props->timeout = MS_TO_NS(150000);
+ dev->rdev->timeout = MS_TO_NS(150000);
}
/* Upload all hardware settings at once. Used at load and resume time */
@@ -838,9 +836,9 @@ static void ene_setup_hw_settings(struct ene_device *dev)
}
/* outside interface: called on first open*/
-static int ene_open(void *data)
+static int ene_open(struct rc_dev *rdev)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
unsigned long flags;
spin_lock_irqsave(&dev->hw_lock, flags);
@@ -850,9 +848,9 @@ static int ene_open(void *data)
}
/* outside interface: called on device close*/
-static void ene_close(void *data)
+static void ene_close(struct rc_dev *rdev)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
unsigned long flags;
spin_lock_irqsave(&dev->hw_lock, flags);
@@ -861,9 +859,9 @@ static void ene_close(void *data)
}
/* outside interface: set transmitter mask */
-static int ene_set_tx_mask(void *data, u32 tx_mask)
+static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
dbg("TX: attempt to set transmitter mask %02x", tx_mask);
/* invalid txmask */
@@ -879,9 +877,9 @@ static int ene_set_tx_mask(void *data, u32 tx_mask)
}
/* outside interface : set tx carrier */
-static int ene_set_tx_carrier(void *data, u32 carrier)
+static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
u32 period = 2000000 / carrier;
dbg("TX: attempt to set tx carrier to %d kHz", carrier);
@@ -900,9 +898,9 @@ static int ene_set_tx_carrier(void *data, u32 carrier)
}
/*outside interface : set tx duty cycle */
-static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle)
+static int ene_set_tx_duty_cycle(struct rc_dev *rdev, u32 duty_cycle)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
dbg("TX: setting duty cycle to %d%%", duty_cycle);
dev->tx_duty_cycle = duty_cycle;
ene_tx_set_carrier(dev);
@@ -910,9 +908,9 @@ static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle)
}
/* outside interface: enable learning mode */
-static int ene_set_learning_mode(void *data, int enable)
+static int ene_set_learning_mode(struct rc_dev *rdev, int enable)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
unsigned long flags;
if (enable == dev->learning_mode_enabled)
return 0;
@@ -926,9 +924,9 @@ static int ene_set_learning_mode(void *data, int enable)
return 0;
}
-static int ene_set_carrier_report(void *data, int enable)
+static int ene_set_carrier_report(struct rc_dev *rdev, int enable)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
unsigned long flags;
if (enable == dev->carrier_detect_enabled)
@@ -944,18 +942,20 @@ static int ene_set_carrier_report(void *data, int enable)
}
/* outside interface: enable or disable idle mode */
-static void ene_set_idle(void *data, bool idle)
+static void ene_set_idle(struct rc_dev *rdev, bool idle)
{
+ struct ene_device *dev = rdev->priv;
+
if (idle) {
- ene_rx_reset((struct ene_device *)data);
+ ene_rx_reset(dev);
dbg("RX: end of data");
}
}
/* outside interface: transmit */
-static int ene_transmit(void *data, int *buf, u32 n)
+static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n)
{
- struct ene_device *dev = (struct ene_device *)data;
+ struct ene_device *dev = rdev->priv;
unsigned long flags;
dev->tx_buffer = buf;
@@ -992,16 +992,13 @@ static int ene_transmit(void *data, int *buf, u32 n)
static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
{
int error = -ENOMEM;
- struct ir_dev_props *ir_props;
- struct input_dev *input_dev;
+ struct rc_dev *rdev;
struct ene_device *dev;
/* allocate memory */
- input_dev = input_allocate_device();
- ir_props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
-
- if (!input_dev || !ir_props || !dev)
+ rdev = rc_allocate_device();
+ if (!dev || !rdev)
goto error1;
/* validate resources */
@@ -1054,24 +1051,25 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
if (!dev->hw_learning_and_tx_capable)
learning_mode_force = false;
- ir_props->driver_type = RC_DRIVER_IR_RAW;
- ir_props->allowed_protos = IR_TYPE_ALL;
- ir_props->priv = dev;
- ir_props->open = ene_open;
- ir_props->close = ene_close;
- ir_props->s_idle = ene_set_idle;
-
- dev->props = ir_props;
- dev->idev = input_dev;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->priv = dev;
+ rdev->open = ene_open;
+ rdev->close = ene_close;
+ rdev->s_idle = ene_set_idle;
+ rdev->driver_name = ENE_DRIVER_NAME;
+ rdev->map_name = RC_MAP_RC6_MCE;
+ rdev->input_name = "ENE eHome Infrared Remote Receiver";
if (dev->hw_learning_and_tx_capable) {
- ir_props->s_learning_mode = ene_set_learning_mode;
+ rdev->s_learning_mode = ene_set_learning_mode;
init_completion(&dev->tx_complete);
- ir_props->tx_ir = ene_transmit;
- ir_props->s_tx_mask = ene_set_tx_mask;
- ir_props->s_tx_carrier = ene_set_tx_carrier;
- ir_props->s_tx_duty_cycle = ene_set_tx_duty_cycle;
- ir_props->s_carrier_report = ene_set_carrier_report;
+ rdev->tx_ir = ene_transmit;
+ rdev->s_tx_mask = ene_set_tx_mask;
+ rdev->s_tx_carrier = ene_set_tx_carrier;
+ rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle;
+ rdev->s_carrier_report = ene_set_carrier_report;
+ rdev->input_name = "ENE eHome Infrared Remote Transceiver";
}
ene_rx_setup_hw_buffer(dev);
@@ -1081,16 +1079,11 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
device_set_wakeup_capable(&pnp_dev->dev, true);
device_set_wakeup_enable(&pnp_dev->dev, true);
- if (dev->hw_learning_and_tx_capable)
- input_dev->name = "ENE eHome Infrared Remote Transceiver";
- else
- input_dev->name = "ENE eHome Infrared Remote Receiver";
-
- error = -ENODEV;
- if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props,
- ENE_DRIVER_NAME))
+ error = rc_register_device(rdev);
+ if (error < 0)
goto error;
+ dev->rdev = rdev;
ene_notice("driver has been succesfully loaded");
return 0;
error:
@@ -1099,8 +1092,7 @@ error:
if (dev && dev->hw_io >= 0)
release_region(dev->hw_io, ENE_IO_SIZE);
error1:
- input_free_device(input_dev);
- kfree(ir_props);
+ rc_free_device(rdev);
kfree(dev);
return error;
}
@@ -1118,8 +1110,7 @@ static void ene_remove(struct pnp_dev *pnp_dev)
free_irq(dev->irq, dev);
release_region(dev->hw_io, ENE_IO_SIZE);
- ir_input_unregister(dev->idev);
- kfree(dev->props);
+ rc_unregister_device(dev->rdev);
kfree(dev);
}
diff --git a/drivers/media/IR/ene_ir.h b/drivers/media/rc/ene_ir.h
index f5870667a433..c179baf34cb4 100644
--- a/drivers/media/IR/ene_ir.h
+++ b/drivers/media/rc/ene_ir.h
@@ -205,8 +205,7 @@
struct ene_device {
struct pnp_dev *pnp_dev;
- struct input_dev *idev;
- struct ir_dev_props *props;
+ struct rc_dev *rdev;
/* hw IO settings */
long hw_io;
diff --git a/drivers/media/IR/imon.c b/drivers/media/rc/imon.c
index bc118066bc38..6811512b4e83 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/rc/imon.c
@@ -38,7 +38,7 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <linux/time.h>
#include <linux/timer.h>
@@ -88,7 +88,6 @@ static ssize_t lcd_write(struct file *file, const char *buf,
struct imon_context {
struct device *dev;
- struct ir_dev_props *props;
/* Newer devices have two interfaces */
struct usb_device *usbdev_intf0;
struct usb_device *usbdev_intf1;
@@ -123,7 +122,7 @@ struct imon_context {
u16 vendor; /* usb vendor ID */
u16 product; /* usb product ID */
- struct input_dev *rdev; /* input device for remote */
+ struct rc_dev *rdev; /* rc-core device for remote */
struct input_dev *idev; /* input device for panel & IR mouse */
struct input_dev *touch; /* input device for touchscreen */
@@ -132,7 +131,7 @@ struct imon_context {
u32 last_keycode; /* last reported input keycode */
u32 rc_scancode; /* the computed remote scancode */
u8 rc_toggle; /* the computed remote toggle bit */
- u64 ir_type; /* iMON or MCE (RC6) IR protocol? */
+ u64 rc_type; /* iMON or MCE (RC6) IR protocol? */
bool release_code; /* some keys send a release code */
u8 display_type; /* store the display type */
@@ -984,27 +983,27 @@ static void imon_touch_display_timeout(unsigned long data)
* really just RC-6), but only one or the other at a time, as the signals
* are decoded onboard the receiver.
*/
-int imon_ir_change_protocol(void *priv, u64 ir_type)
+static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
{
int retval;
- struct imon_context *ictx = priv;
+ struct imon_context *ictx = rc->priv;
struct device *dev = ictx->dev;
bool pad_mouse;
unsigned char ir_proto_packet[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
- if (ir_type && !(ir_type & ictx->props->allowed_protos))
+ if (rc_type && !(rc_type & rc->allowed_protos))
dev_warn(dev, "Looks like you're trying to use an IR protocol "
"this device does not support\n");
- switch (ir_type) {
- case IR_TYPE_RC6:
+ switch (rc_type) {
+ case RC_TYPE_RC6:
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
pad_mouse = false;
break;
- case IR_TYPE_UNKNOWN:
- case IR_TYPE_OTHER:
+ case RC_TYPE_UNKNOWN:
+ case RC_TYPE_OTHER:
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
if (pad_stabilize && !nomouse)
pad_mouse = true;
@@ -1013,7 +1012,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
pad_mouse = false;
}
/* ir_proto_packet[0] = 0x00; // already the default */
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
break;
default:
dev_warn(dev, "Unsupported IR protocol specified, overriding "
@@ -1025,7 +1024,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
pad_mouse = false;
}
/* ir_proto_packet[0] = 0x00; // already the default */
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
break;
}
@@ -1035,7 +1034,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
if (retval)
goto out;
- ictx->ir_type = ir_type;
+ ictx->rc_type = rc_type;
ictx->pad_mouse = pad_mouse;
out:
@@ -1147,14 +1146,14 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
bool is_release_code = false;
/* Look for the initial press of a button */
- keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+ keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
ictx->rc_toggle = 0x0;
ictx->rc_scancode = scancode;
/* Look for the release of a button */
if (keycode == KEY_RESERVED) {
release = scancode & ~0x4000;
- keycode = ir_g_keycode_from_table(ictx->rdev, release);
+ keycode = rc_g_keycode_from_table(ictx->rdev, release);
if (keycode != KEY_RESERVED)
is_release_code = true;
}
@@ -1183,7 +1182,7 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
ictx->rc_scancode = scancode;
- keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+ keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
/* not used in mce mode, but make sure we know its false */
ictx->release_code = false;
@@ -1307,7 +1306,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
rel_x = buf[2];
rel_y = buf[3];
- if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
@@ -1374,7 +1373,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
buf[0] = 0x01;
buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
- if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
@@ -1479,17 +1478,12 @@ static void imon_incoming_packet(struct imon_context *ictx,
bool norelease = false;
int i;
u64 scancode;
- struct input_dev *rdev = NULL;
- struct ir_input_dev *irdev = NULL;
int press_type = 0;
int msec;
struct timeval t;
static struct timeval prev_time = { 0, 0 };
u8 ktype;
- rdev = ictx->rdev;
- irdev = input_get_drvdata(rdev);
-
/* filter out junk data on the older 0xffdc imon devices */
if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
return;
@@ -1501,7 +1495,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
kc = imon_panel_key_lookup(scancode);
} else {
scancode = be32_to_cpu(*((u32 *)buf));
- if (ictx->ir_type == IR_TYPE_RC6) {
+ if (ictx->rc_type == RC_TYPE_RC6) {
ktype = IMON_KEY_IMON;
if (buf[0] == 0x80)
ktype = IMON_KEY_MCE;
@@ -1570,9 +1564,9 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (ktype != IMON_KEY_PANEL) {
if (press_type == 0)
- ir_keyup(irdev);
+ rc_keyup(ictx->rdev);
else {
- ir_keydown(rdev, ictx->rc_scancode, ictx->rc_toggle);
+ rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
@@ -1715,7 +1709,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
{
u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
- u64 allowed_protos = IR_TYPE_OTHER;
+ u64 allowed_protos = RC_TYPE_OTHER;
switch (ffdc_cfg_byte) {
/* iMON Knob, no display, iMON IR + vol knob */
@@ -1744,13 +1738,13 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
case 0x9e:
dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD;
- allowed_protos = IR_TYPE_RC6;
+ allowed_protos = RC_TYPE_RC6;
break;
/* iMON LCD, MCE IR */
case 0x9f:
dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_LCD;
- allowed_protos = IR_TYPE_RC6;
+ allowed_protos = RC_TYPE_RC6;
break;
default:
dev_info(ictx->dev, "Unknown 0xffdc device, "
@@ -1762,8 +1756,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
ictx->display_type = detected_display_type;
- ictx->props->allowed_protos = allowed_protos;
- ictx->ir_type = allowed_protos;
+ ictx->rdev->allowed_protos = allowed_protos;
+ ictx->rc_type = allowed_protos;
}
static void imon_set_display_type(struct imon_context *ictx)
@@ -1816,18 +1810,15 @@ static void imon_set_display_type(struct imon_context *ictx)
ictx->display_type = configured_display_type;
}
-static struct input_dev *imon_init_rdev(struct imon_context *ictx)
+static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
{
- struct input_dev *rdev;
- struct ir_dev_props *props;
+ struct rc_dev *rdev;
int ret;
- char *ir_codes = NULL;
const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x88 };
- rdev = input_allocate_device();
- props = kzalloc(sizeof(*props), GFP_KERNEL);
- if (!rdev || !props) {
+ rdev = rc_allocate_device();
+ if (!rdev) {
dev_err(ictx->dev, "remote control dev allocation failed\n");
goto out;
}
@@ -1838,18 +1829,20 @@ static struct input_dev *imon_init_rdev(struct imon_context *ictx)
sizeof(ictx->phys_rdev));
strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
- rdev->name = ictx->name_rdev;
- rdev->phys = ictx->phys_rdev;
- usb_to_input_id(ictx->usbdev_intf0, &rdev->id);
+ rdev->input_name = ictx->name_rdev;
+ rdev->input_phys = ictx->phys_rdev;
+ usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id);
rdev->dev.parent = ictx->dev;
- rdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- input_set_drvdata(rdev, ictx);
- props->priv = ictx;
- props->driver_type = RC_DRIVER_SCANCODE;
- props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; /* iMON PAD or MCE */
- props->change_protocol = imon_ir_change_protocol;
- ictx->props = props;
+ rdev->priv = ictx;
+ rdev->driver_type = RC_DRIVER_SCANCODE;
+ rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
+ rdev->change_protocol = imon_ir_change_protocol;
+ rdev->driver_name = MOD_NAME;
+ if (ictx->rc_type == RC_TYPE_RC6)
+ rdev->map_name = RC_MAP_IMON_MCE;
+ else
+ rdev->map_name = RC_MAP_IMON_PAD;
/* Enable front-panel buttons and/or knobs */
memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
@@ -1863,12 +1856,7 @@ static struct input_dev *imon_init_rdev(struct imon_context *ictx)
imon_set_display_type(ictx);
- if (ictx->ir_type == IR_TYPE_RC6)
- ir_codes = RC_MAP_IMON_MCE;
- else
- ir_codes = RC_MAP_IMON_PAD;
-
- ret = ir_input_register(rdev, ir_codes, props, MOD_NAME);
+ ret = rc_register_device(rdev);
if (ret < 0) {
dev_err(ictx->dev, "remote input dev register failed\n");
goto out;
@@ -1877,8 +1865,7 @@ static struct input_dev *imon_init_rdev(struct imon_context *ictx)
return rdev;
out:
- kfree(props);
- input_free_device(rdev);
+ rc_free_device(rdev);
return NULL;
}
@@ -2149,7 +2136,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
return ictx;
urb_submit_failed:
- ir_input_unregister(ictx->rdev);
+ rc_unregister_device(ictx->rdev);
rdev_setup_failed:
input_unregister_device(ictx->idev);
idev_setup_failed:
@@ -2287,7 +2274,7 @@ static int __devinit imon_probe(struct usb_interface *interface,
mutex_lock(&driver_lock);
first_if = usb_ifnum_to_if(usbdev, 0);
- first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if);
+ first_if_ctx = usb_get_intfdata(first_if);
if (ifnum == 0) {
ictx = imon_init_intf0(interface);
@@ -2376,7 +2363,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
ictx->dev_present_intf0 = false;
usb_kill_urb(ictx->rx_urb_intf0);
input_unregister_device(ictx->idev);
- ir_input_unregister(ictx->rdev);
+ rc_unregister_device(ictx->rdev);
if (ictx->display_supported) {
if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
usb_deregister_dev(interface, &imon_lcd_class);
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 63dca6e5458b..624449afaa61 100644
--- a/drivers/media/IR/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -13,7 +13,7 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define JVC_NBITS 16 /* dev(8) + func(8) */
#define JVC_UNIT 525000 /* ns */
@@ -37,17 +37,16 @@ enum jvc_state {
/**
* ir_jvc_decode() - Decode one JVC pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @duration: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct jvc_dec *data = &ir_dev->raw->jvc;
+ struct jvc_dec *data = &dev->raw->jvc;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))
return 0;
if (!is_timing_event(ev)) {
@@ -140,12 +139,12 @@ again:
scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
(bitrev8((data->bits >> 0) & 0xff) << 0);
IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
- ir_keydown(input_dev, scancode, data->toggle);
+ rc_keydown(dev, scancode, data->toggle);
data->first = false;
data->old_bits = data->bits;
} else if (data->bits == data->old_bits) {
IR_dprintk(1, "JVC repeat\n");
- ir_repeat(input_dev);
+ rc_repeat(dev);
} else {
IR_dprintk(1, "JVC invalid repeat msg\n");
break;
@@ -174,7 +173,7 @@ out:
}
static struct ir_raw_handler jvc_handler = {
- .protocols = IR_TYPE_JVC,
+ .protocols = RC_TYPE_JVC,
.decode = ir_jvc_decode,
};
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 9fc0db9d344d..f011c5d9dea1 100644
--- a/drivers/media/IR/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -16,29 +16,28 @@
#include <linux/wait.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
-#include <media/ir-core.h>
-#include "ir-core-priv.h"
+#include <media/rc-core.h>
+#include "rc-core-priv.h"
#define LIRCBUF_SIZE 256
/**
* ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
* lircd userspace daemon for decoding.
- * @input_dev: the struct input_dev descriptor of the device
+ * @input_dev: the struct rc_dev descriptor of the device
* @duration: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the lirc interfaces aren't wired up.
*/
-static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct lirc_codec *lirc = &ir_dev->raw->lirc;
+ struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC))
return 0;
- if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
+ if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
return -EINVAL;
/* Packet start */
@@ -79,7 +78,7 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
(u64)LIRC_VALUE_MASK);
gap_sample = LIRC_SPACE(lirc->gap_duration);
- lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+ lirc_buffer_write(dev->raw->lirc.drv->rbuf,
(unsigned char *) &gap_sample);
lirc->gap = false;
}
@@ -88,9 +87,9 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
LIRC_SPACE(ev.duration / 1000);
}
- lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+ lirc_buffer_write(dev->raw->lirc.drv->rbuf,
(unsigned char *) &sample);
- wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
+ wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
return 0;
}
@@ -99,9 +98,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
size_t n, loff_t *ppos)
{
struct lirc_codec *lirc;
- struct ir_input_dev *ir_dev;
+ struct rc_dev *dev;
int *txbuf; /* buffer with values to transmit */
- int ret = 0, count;
+ int ret = 0;
+ size_t count;
lirc = lirc_get_pdata(file);
if (!lirc)
@@ -111,21 +111,21 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
return -EINVAL;
count = n / sizeof(int);
- if (count > LIRCBUF_SIZE || count % 2 == 0)
+ if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0)
return -EINVAL;
txbuf = memdup_user(buf, n);
if (IS_ERR(txbuf))
return PTR_ERR(txbuf);
- ir_dev = lirc->ir_dev;
- if (!ir_dev) {
+ dev = lirc->dev;
+ if (!dev) {
ret = -EFAULT;
goto out;
}
- if (ir_dev->props && ir_dev->props->tx_ir)
- ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n);
+ if (dev->tx_ir)
+ ret = dev->tx_ir(dev, txbuf, (u32)n);
out:
kfree(txbuf);
@@ -136,21 +136,18 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
unsigned long __user arg)
{
struct lirc_codec *lirc;
- struct ir_input_dev *ir_dev;
+ struct rc_dev *dev;
int ret = 0;
- void *drv_data;
__u32 val = 0, tmp;
lirc = lirc_get_pdata(filep);
if (!lirc)
return -EFAULT;
- ir_dev = lirc->ir_dev;
- if (!ir_dev || !ir_dev->props || !ir_dev->props->priv)
+ dev = lirc->dev;
+ if (!dev)
return -EFAULT;
- drv_data = ir_dev->props->priv;
-
if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = get_user(val, (__u32 *)arg);
if (ret)
@@ -171,84 +168,85 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
/* TX settings */
case LIRC_SET_TRANSMITTER_MASK:
- if (!ir_dev->props->s_tx_mask)
+ if (!dev->s_tx_mask)
return -EINVAL;
- return ir_dev->props->s_tx_mask(drv_data, val);
+ return dev->s_tx_mask(dev, val);
case LIRC_SET_SEND_CARRIER:
- if (!ir_dev->props->s_tx_carrier)
+ if (!dev->s_tx_carrier)
return -EINVAL;
- return ir_dev->props->s_tx_carrier(drv_data, val);
+ return dev->s_tx_carrier(dev, val);
case LIRC_SET_SEND_DUTY_CYCLE:
- if (!ir_dev->props->s_tx_duty_cycle)
+ if (!dev->s_tx_duty_cycle)
return -ENOSYS;
if (val <= 0 || val >= 100)
return -EINVAL;
- return ir_dev->props->s_tx_duty_cycle(drv_data, val);
+ return dev->s_tx_duty_cycle(dev, val);
/* RX settings */
case LIRC_SET_REC_CARRIER:
- if (!ir_dev->props->s_rx_carrier_range)
+ if (!dev->s_rx_carrier_range)
return -ENOSYS;
if (val <= 0)
return -EINVAL;
- return ir_dev->props->s_rx_carrier_range(drv_data,
- ir_dev->raw->lirc.carrier_low, val);
+ return dev->s_rx_carrier_range(dev,
+ dev->raw->lirc.carrier_low,
+ val);
case LIRC_SET_REC_CARRIER_RANGE:
if (val <= 0)
return -EINVAL;
- ir_dev->raw->lirc.carrier_low = val;
+ dev->raw->lirc.carrier_low = val;
return 0;
case LIRC_GET_REC_RESOLUTION:
- val = ir_dev->props->rx_resolution;
+ val = dev->rx_resolution;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
- if (!ir_dev->props->s_learning_mode)
+ if (!dev->s_learning_mode)
return -ENOSYS;
- return ir_dev->props->s_learning_mode(drv_data, !!val);
+ return dev->s_learning_mode(dev, !!val);
case LIRC_SET_MEASURE_CARRIER_MODE:
- if (!ir_dev->props->s_carrier_report)
+ if (!dev->s_carrier_report)
return -ENOSYS;
- return ir_dev->props->s_carrier_report(drv_data, !!val);
+ return dev->s_carrier_report(dev, !!val);
/* Generic timeout support */
case LIRC_GET_MIN_TIMEOUT:
- if (!ir_dev->props->max_timeout)
+ if (!dev->max_timeout)
return -ENOSYS;
- val = ir_dev->props->min_timeout / 1000;
+ val = dev->min_timeout / 1000;
break;
case LIRC_GET_MAX_TIMEOUT:
- if (!ir_dev->props->max_timeout)
+ if (!dev->max_timeout)
return -ENOSYS;
- val = ir_dev->props->max_timeout / 1000;
+ val = dev->max_timeout / 1000;
break;
case LIRC_SET_REC_TIMEOUT:
- if (!ir_dev->props->max_timeout)
+ if (!dev->max_timeout)
return -ENOSYS;
tmp = val * 1000;
- if (tmp < ir_dev->props->min_timeout ||
- tmp > ir_dev->props->max_timeout)
+ if (tmp < dev->min_timeout ||
+ tmp > dev->max_timeout)
return -EINVAL;
- ir_dev->props->timeout = tmp;
+ dev->timeout = tmp;
break;
case LIRC_SET_REC_TIMEOUT_REPORTS:
@@ -289,9 +287,8 @@ static struct file_operations lirc_fops = {
.llseek = no_llseek,
};
-static int ir_lirc_register(struct input_dev *input_dev)
+static int ir_lirc_register(struct rc_dev *dev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
struct lirc_driver *drv;
struct lirc_buffer *rbuf;
int rc = -ENOMEM;
@@ -310,44 +307,40 @@ static int ir_lirc_register(struct input_dev *input_dev)
goto rbuf_init_failed;
features = LIRC_CAN_REC_MODE2;
- if (ir_dev->props->tx_ir) {
-
+ if (dev->tx_ir) {
features |= LIRC_CAN_SEND_PULSE;
- if (ir_dev->props->s_tx_mask)
+ if (dev->s_tx_mask)
features |= LIRC_CAN_SET_TRANSMITTER_MASK;
- if (ir_dev->props->s_tx_carrier)
+ if (dev->s_tx_carrier)
features |= LIRC_CAN_SET_SEND_CARRIER;
-
- if (ir_dev->props->s_tx_duty_cycle)
+ if (dev->s_tx_duty_cycle)
features |= LIRC_CAN_SET_SEND_DUTY_CYCLE;
}
- if (ir_dev->props->s_rx_carrier_range)
+ if (dev->s_rx_carrier_range)
features |= LIRC_CAN_SET_REC_CARRIER |
LIRC_CAN_SET_REC_CARRIER_RANGE;
- if (ir_dev->props->s_learning_mode)
+ if (dev->s_learning_mode)
features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
- if (ir_dev->props->s_carrier_report)
+ if (dev->s_carrier_report)
features |= LIRC_CAN_MEASURE_CARRIER;
-
- if (ir_dev->props->max_timeout)
+ if (dev->max_timeout)
features |= LIRC_CAN_SET_REC_TIMEOUT;
-
snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
- ir_dev->driver_name);
+ dev->driver_name);
drv->minor = -1;
drv->features = features;
- drv->data = &ir_dev->raw->lirc;
+ drv->data = &dev->raw->lirc;
drv->rbuf = rbuf;
drv->set_use_inc = &ir_lirc_open;
drv->set_use_dec = &ir_lirc_close;
drv->code_length = sizeof(struct ir_raw_event) * 8;
drv->fops = &lirc_fops;
- drv->dev = &ir_dev->dev;
+ drv->dev = &dev->dev;
drv->owner = THIS_MODULE;
drv->minor = lirc_register_driver(drv);
@@ -356,8 +349,8 @@ static int ir_lirc_register(struct input_dev *input_dev)
goto lirc_register_failed;
}
- ir_dev->raw->lirc.drv = drv;
- ir_dev->raw->lirc.ir_dev = ir_dev;
+ dev->raw->lirc.drv = drv;
+ dev->raw->lirc.dev = dev;
return 0;
lirc_register_failed:
@@ -369,10 +362,9 @@ rbuf_alloc_failed:
return rc;
}
-static int ir_lirc_unregister(struct input_dev *input_dev)
+static int ir_lirc_unregister(struct rc_dev *dev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct lirc_codec *lirc = &ir_dev->raw->lirc;
+ struct lirc_codec *lirc = &dev->raw->lirc;
lirc_unregister_driver(lirc->drv->minor);
lirc_buffer_free(lirc->drv->rbuf);
@@ -382,7 +374,7 @@ static int ir_lirc_unregister(struct input_dev *input_dev)
}
static struct ir_raw_handler lirc_handler = {
- .protocols = IR_TYPE_LIRC,
+ .protocols = RC_TYPE_LIRC,
.decode = ir_lirc_decode,
.raw_register = ir_lirc_register,
.raw_unregister = ir_lirc_unregister,
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 70993f79c8a2..7b58b4a1729b 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -13,7 +13,7 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define NEC_NBITS 32
#define NEC_UNIT 562500 /* ns */
@@ -39,19 +39,18 @@ enum nec_state {
/**
* ir_nec_decode() - Decode one NEC pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @duration: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct nec_dec *data = &ir_dev->raw->nec;
+ struct nec_dec *data = &dev->raw->nec;
u32 scancode;
u8 address, not_address, command, not_command;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
return 0;
if (!is_timing_event(ev)) {
@@ -89,9 +88,13 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
data->state = STATE_BIT_PULSE;
return 0;
} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
- ir_repeat(input_dev);
- IR_dprintk(1, "Repeat last key\n");
- data->state = STATE_TRAILER_PULSE;
+ if (!dev->keypressed) {
+ IR_dprintk(1, "Discarding last key repeat: event after key up\n");
+ } else {
+ rc_repeat(dev);
+ IR_dprintk(1, "Repeat last key\n");
+ data->state = STATE_TRAILER_PULSE;
+ }
return 0;
}
@@ -115,7 +118,7 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
geq_margin(ev.duration,
NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
IR_dprintk(1, "Repeat last key\n");
- ir_repeat(input_dev);
+ rc_repeat(dev);
data->state = STATE_INACTIVE;
return 0;
@@ -179,7 +182,7 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (data->is_nec_x)
data->necx_repeat = true;
- ir_keydown(input_dev, scancode, 0);
+ rc_keydown(dev, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
@@ -191,7 +194,7 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
}
static struct ir_raw_handler nec_handler = {
- .protocols = IR_TYPE_NEC,
+ .protocols = RC_TYPE_NEC,
.decode = ir_nec_decode,
};
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/rc/ir-raw.c
index a06a07e4e0b1..185baddcbf14 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/rc/ir-raw.c
@@ -1,4 +1,4 @@
-/* ir-raw-event.c - handle IR Pulse/Space event
+/* ir-raw.c - handle IR pulse/space events
*
* Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
*
@@ -16,7 +16,7 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/freezer.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
/* Define the max number of pulse/space transitions to buffer */
#define MAX_IR_EVENT_SIZE 512
@@ -64,7 +64,7 @@ static int ir_raw_event_thread(void *data)
mutex_lock(&ir_raw_handler_lock);
list_for_each_entry(handler, &ir_raw_handler_list, list)
- handler->decode(raw->input_dev, ev);
+ handler->decode(raw->dev, ev);
raw->prev_ev = ev;
mutex_unlock(&ir_raw_handler_lock);
}
@@ -74,7 +74,7 @@ static int ir_raw_event_thread(void *data)
/**
* ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
- * @input_dev: the struct input_dev device descriptor
+ * @dev: the struct rc_dev device descriptor
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This routine (which may be called from an interrupt context) stores a
@@ -82,17 +82,15 @@ static int ir_raw_event_thread(void *data)
* signalled as positive values and spaces as negative values. A zero value
* will reset the decoding state machines.
*/
-int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
+int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
- if (!ir->raw)
+ if (!dev->raw)
return -EINVAL;
IR_dprintk(2, "sample: (%05dus %s)\n",
- TO_US(ev->duration), TO_STR(ev->pulse));
+ TO_US(ev->duration), TO_STR(ev->pulse));
- if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+ if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
return -ENOMEM;
return 0;
@@ -101,7 +99,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store);
/**
* ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
- * @input_dev: the struct input_dev device descriptor
+ * @dev: the struct rc_dev device descriptor
* @type: the type of the event that has occurred
*
* This routine (which may be called from an interrupt context) is used to
@@ -110,50 +108,49 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store);
* hardware which does not provide durations directly but only interrupts
* (or similar events) on state change.
*/
-int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type)
+int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
ktime_t now;
s64 delta; /* ns */
struct ir_raw_event ev;
int rc = 0;
- if (!ir->raw)
+ if (!dev->raw)
return -EINVAL;
now = ktime_get();
- delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
+ delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
/* Check for a long duration since last event or if we're
* being called for the first time, note that delta can't
* possibly be negative.
*/
ev.duration = 0;
- if (delta > IR_MAX_DURATION || !ir->raw->last_type)
+ if (delta > IR_MAX_DURATION || !dev->raw->last_type)
type |= IR_START_EVENT;
else
ev.duration = delta;
if (type & IR_START_EVENT)
- ir_raw_event_reset(input_dev);
- else if (ir->raw->last_type & IR_SPACE) {
+ ir_raw_event_reset(dev);
+ else if (dev->raw->last_type & IR_SPACE) {
ev.pulse = false;
- rc = ir_raw_event_store(input_dev, &ev);
- } else if (ir->raw->last_type & IR_PULSE) {
+ rc = ir_raw_event_store(dev, &ev);
+ } else if (dev->raw->last_type & IR_PULSE) {
ev.pulse = true;
- rc = ir_raw_event_store(input_dev, &ev);
+ rc = ir_raw_event_store(dev, &ev);
} else
return 0;
- ir->raw->last_event = now;
- ir->raw->last_type = type;
+ dev->raw->last_event = now;
+ dev->raw->last_type = type;
return rc;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
/**
* ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
- * @input_dev: the struct input_dev device descriptor
+ * @dev: the struct rc_dev device descriptor
* @type: the type of the event that has occurred
*
* This routine (which may be called from an interrupt context) works
@@ -161,84 +158,76 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
* This routine is intended for devices with limited internal buffer
* It automerges samples of same type, and handles timeouts
*/
-int ir_raw_event_store_with_filter(struct input_dev *input_dev,
- struct ir_raw_event *ev)
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
- struct ir_raw_event_ctrl *raw = ir->raw;
-
- if (!raw || !ir->props)
+ if (!dev->raw)
return -EINVAL;
/* Ignore spaces in idle mode */
- if (ir->idle && !ev->pulse)
+ if (dev->idle && !ev->pulse)
return 0;
- else if (ir->idle)
- ir_raw_event_set_idle(input_dev, false);
-
- if (!raw->this_ev.duration) {
- raw->this_ev = *ev;
- } else if (ev->pulse == raw->this_ev.pulse) {
- raw->this_ev.duration += ev->duration;
- } else {
- ir_raw_event_store(input_dev, &raw->this_ev);
- raw->this_ev = *ev;
+ else if (dev->idle)
+ ir_raw_event_set_idle(dev, false);
+
+ if (!dev->raw->this_ev.duration)
+ dev->raw->this_ev = *ev;
+ else if (ev->pulse == dev->raw->this_ev.pulse)
+ dev->raw->this_ev.duration += ev->duration;
+ else {
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ dev->raw->this_ev = *ev;
}
/* Enter idle mode if nessesary */
- if (!ev->pulse && ir->props->timeout &&
- raw->this_ev.duration >= ir->props->timeout) {
- ir_raw_event_set_idle(input_dev, true);
- }
+ if (!ev->pulse && dev->timeout &&
+ dev->raw->this_ev.duration >= dev->timeout)
+ ir_raw_event_set_idle(dev, true);
+
return 0;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
/**
- * ir_raw_event_set_idle() - hint the ir core if device is receiving
- * IR data or not
- * @input_dev: the struct input_dev device descriptor
- * @idle: the hint value
+ * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
+ * @dev: the struct rc_dev device descriptor
+ * @idle: whether the device is idle or not
*/
-void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
+void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
- struct ir_raw_event_ctrl *raw = ir->raw;
-
- if (!ir->props || !ir->raw)
+ if (!dev->raw)
return;
IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
if (idle) {
- raw->this_ev.timeout = true;
- ir_raw_event_store(input_dev, &raw->this_ev);
- init_ir_raw_event(&raw->this_ev);
+ dev->raw->this_ev.timeout = true;
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ init_ir_raw_event(&dev->raw->this_ev);
}
- if (ir->props->s_idle)
- ir->props->s_idle(ir->props->priv, idle);
- ir->idle = idle;
+ if (dev->s_idle)
+ dev->s_idle(dev, idle);
+
+ dev->idle = idle;
}
EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
/**
* ir_raw_event_handle() - schedules the decoding of stored ir data
- * @input_dev: the struct input_dev device descriptor
+ * @dev: the struct rc_dev device descriptor
*
- * This routine will signal the workqueue to start decoding stored ir data.
+ * This routine will tell rc-core to start decoding stored ir data.
*/
-void ir_raw_event_handle(struct input_dev *input_dev)
+void ir_raw_event_handle(struct rc_dev *dev)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
unsigned long flags;
- if (!ir->raw)
+ if (!dev->raw)
return;
- spin_lock_irqsave(&ir->raw->lock, flags);
- wake_up_process(ir->raw->thread);
- spin_unlock_irqrestore(&ir->raw->lock, flags);
+ spin_lock_irqsave(&dev->raw->lock, flags);
+ wake_up_process(dev->raw->thread);
+ spin_unlock_irqrestore(&dev->raw->lock, flags);
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
@@ -256,69 +245,69 @@ ir_raw_get_allowed_protocols()
/*
* Used to (un)register raw event clients
*/
-int ir_raw_event_register(struct input_dev *input_dev)
+int ir_raw_event_register(struct rc_dev *dev)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
int rc;
struct ir_raw_handler *handler;
- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
- if (!ir->raw)
- return -ENOMEM;
+ if (!dev)
+ return -EINVAL;
- ir->raw->input_dev = input_dev;
+ dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
+ if (!dev->raw)
+ return -ENOMEM;
- ir->raw->enabled_protocols = ~0;
- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+ dev->raw->dev = dev;
+ dev->raw->enabled_protocols = ~0;
+ rc = kfifo_alloc(&dev->raw->kfifo,
+ sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL);
- if (rc < 0) {
- kfree(ir->raw);
- ir->raw = NULL;
- return rc;
- }
+ if (rc < 0)
+ goto out;
- spin_lock_init(&ir->raw->lock);
- ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
- "rc%u", (unsigned int)ir->devno);
+ spin_lock_init(&dev->raw->lock);
+ dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+ "rc%ld", dev->devno);
- if (IS_ERR(ir->raw->thread)) {
- int ret = PTR_ERR(ir->raw->thread);
-
- kfree(ir->raw);
- ir->raw = NULL;
- return ret;
+ if (IS_ERR(dev->raw->thread)) {
+ rc = PTR_ERR(dev->raw->thread);
+ goto out;
}
mutex_lock(&ir_raw_handler_lock);
- list_add_tail(&ir->raw->list, &ir_raw_client_list);
+ list_add_tail(&dev->raw->list, &ir_raw_client_list);
list_for_each_entry(handler, &ir_raw_handler_list, list)
if (handler->raw_register)
- handler->raw_register(ir->raw->input_dev);
+ handler->raw_register(dev);
mutex_unlock(&ir_raw_handler_lock);
return 0;
+
+out:
+ kfree(dev->raw);
+ dev->raw = NULL;
+ return rc;
}
-void ir_raw_event_unregister(struct input_dev *input_dev)
+void ir_raw_event_unregister(struct rc_dev *dev)
{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
struct ir_raw_handler *handler;
- if (!ir->raw)
+ if (!dev || !dev->raw)
return;
- kthread_stop(ir->raw->thread);
+ kthread_stop(dev->raw->thread);
mutex_lock(&ir_raw_handler_lock);
- list_del(&ir->raw->list);
+ list_del(&dev->raw->list);
list_for_each_entry(handler, &ir_raw_handler_list, list)
if (handler->raw_unregister)
- handler->raw_unregister(ir->raw->input_dev);
+ handler->raw_unregister(dev);
mutex_unlock(&ir_raw_handler_lock);
- kfifo_free(&ir->raw->kfifo);
- kfree(ir->raw);
- ir->raw = NULL;
+ kfifo_free(&dev->raw->kfifo);
+ kfree(dev->raw);
+ dev->raw = NULL;
}
/*
@@ -333,7 +322,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
if (ir_raw_handler->raw_register)
list_for_each_entry(raw, &ir_raw_client_list, list)
- ir_raw_handler->raw_register(raw->input_dev);
+ ir_raw_handler->raw_register(raw->dev);
available_protocols |= ir_raw_handler->protocols;
mutex_unlock(&ir_raw_handler_lock);
@@ -349,7 +338,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
list_del(&ir_raw_handler->list);
if (ir_raw_handler->raw_unregister)
list_for_each_entry(raw, &ir_raw_client_list, list)
- ir_raw_handler->raw_unregister(raw->input_dev);
+ ir_raw_handler->raw_unregister(raw->dev);
available_protocols &= ~ir_raw_handler->protocols;
mutex_unlock(&ir_raw_handler_lock);
}
@@ -368,7 +357,7 @@ static void init_decoders(struct work_struct *work)
load_lirc_codec();
/* If needed, we may later add some init code. In this case,
- it is needed to change the CONFIG_MODULE test at ir-core.h
+ it is needed to change the CONFIG_MODULE test at rc-core.h
*/
}
#endif
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 572ed4ca8c68..ebdba5539916 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -20,7 +20,7 @@
* the first two bits are start bits, and a third one is a filing bit
*/
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define RC5_NBITS 14
#define RC5X_NBITS 20
@@ -40,19 +40,18 @@ enum rc5_state {
/**
* ir_rc5_decode() - Decode one RC-5 pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct rc5_dec *data = &ir_dev->raw->rc5;
+ struct rc5_dec *data = &dev->raw->rc5;
u8 toggle;
u32 scancode;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC5))
return 0;
if (!is_timing_event(ev)) {
@@ -96,7 +95,7 @@ again:
return 0;
case STATE_BIT_END:
- if (!is_transition(&ev, &ir_dev->raw->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -151,7 +150,7 @@ again:
scancode, toggle);
}
- ir_keydown(input_dev, scancode, toggle);
+ rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
@@ -164,7 +163,7 @@ out:
}
static struct ir_raw_handler rc5_handler = {
- .protocols = IR_TYPE_RC5,
+ .protocols = RC_TYPE_RC5,
.decode = ir_rc5_decode,
};
diff --git a/drivers/media/IR/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index 7c413501a3f7..90aa8868629a 100644
--- a/drivers/media/IR/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -20,7 +20,7 @@
* the first two bits are start bits, and a third one is a filing bit
*/
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define RC5_SZ_NBITS 15
#define RC5_UNIT 888888 /* ns */
@@ -36,19 +36,18 @@ enum rc5_sz_state {
/**
* ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
+ struct rc5_sz_dec *data = &dev->raw->rc5_sz;
u8 toggle, command, system;
u32 scancode;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ))
return 0;
if (!is_timing_event(ev)) {
@@ -91,7 +90,7 @@ again:
return 0;
case STATE_BIT_END:
- if (!is_transition(&ev, &ir_dev->raw->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -115,7 +114,7 @@ again:
IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
- ir_keydown(input_dev, scancode, toggle);
+ rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
@@ -128,7 +127,7 @@ out:
}
static struct ir_raw_handler rc5_sz_handler = {
- .protocols = IR_TYPE_RC5_SZ,
+ .protocols = RC_TYPE_RC5_SZ,
.decode = ir_rc5_sz_decode,
};
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index d25da91f44ff..755dafa3871b 100644
--- a/drivers/media/IR/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
/*
* This decoder currently supports:
@@ -70,19 +70,18 @@ static enum rc6_mode rc6_mode(struct rc6_dec *data)
/**
* ir_rc6_decode() - Decode one RC6 pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct rc6_dec *data = &ir_dev->raw->rc6;
+ struct rc6_dec *data = &dev->raw->rc6;
u32 scancode;
u8 toggle;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
return 0;
if (!is_timing_event(ev)) {
@@ -139,7 +138,7 @@ again:
return 0;
case STATE_HEADER_BIT_END:
- if (!is_transition(&ev, &ir_dev->raw->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == RC6_HEADER_NBITS)
@@ -159,7 +158,7 @@ again:
return 0;
case STATE_TOGGLE_END:
- if (!is_transition(&ev, &ir_dev->raw->prev_ev) ||
+ if (!is_transition(&ev, &dev->raw->prev_ev) ||
!geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
break;
@@ -204,7 +203,7 @@ again:
return 0;
case STATE_BODY_BIT_END:
- if (!is_transition(&ev, &ir_dev->raw->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -243,7 +242,7 @@ again:
goto out;
}
- ir_keydown(input_dev, scancode, toggle);
+ rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
@@ -256,7 +255,7 @@ out:
}
static struct ir_raw_handler rc6_handler = {
- .protocols = IR_TYPE_RC6,
+ .protocols = RC_TYPE_RC6,
.decode = ir_rc6_decode,
};
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 2d15730822bc..a92de80c48db 100644
--- a/drivers/media/IR/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -13,7 +13,7 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define SONY_UNIT 600000 /* ns */
#define SONY_HEADER_PULSE (4 * SONY_UNIT)
@@ -33,19 +33,18 @@ enum sony_state {
/**
* ir_sony_decode() - Decode one Sony pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct sony_dec *data = &ir_dev->raw->sony;
+ struct sony_dec *data = &dev->raw->sony;
u32 scancode;
u8 device, subdevice, function;
- if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
+ if (!(dev->raw->enabled_protocols & RC_TYPE_SONY))
return 0;
if (!is_timing_event(ev)) {
@@ -144,7 +143,7 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
scancode = device << 16 | subdevice << 8 | function;
IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
- ir_keydown(input_dev, scancode, 0);
+ rc_keydown(dev, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
@@ -157,7 +156,7 @@ out:
}
static struct ir_raw_handler sony_handler = {
- .protocols = IR_TYPE_SONY,
+ .protocols = RC_TYPE_SONY,
.decode = ir_sony_decode,
};
diff --git a/drivers/media/IR/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig
index 14b22f58f823..8e615fd55852 100644
--- a/drivers/media/IR/keymaps/Kconfig
+++ b/drivers/media/rc/keymaps/Kconfig
@@ -1,6 +1,6 @@
config RC_MAP
tristate "Compile Remote Controller keymap modules"
- depends on IR_CORE
+ depends on RC_CORE
default y
---help---
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 3194d391bbd4..0659e9f50144 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-pinnacle-pctv-hd.o \
rc-pixelview.o \
rc-pixelview-mk12.o \
+ rc-pixelview-002t.o \
rc-pixelview-new.o \
rc-powercolor-real-angel.o \
rc-proteus-2309.o \
@@ -80,6 +81,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-trekstor.o \
rc-tt-1500.o \
rc-twinhan1027.o \
+ rc-videomate-m1f.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
rc-winfast.o \
diff --git a/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
index b17283176ecd..136d3952dedc 100644
--- a/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c
+++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
@@ -14,7 +14,7 @@
/* ADS Tech Instant TV DVB-T PCI Remote */
-static struct ir_scancode adstech_dvb_t_pci[] = {
+static struct rc_map_table adstech_dvb_t_pci[] = {
/* Keys 0 to 9 */
{ 0x4d, KEY_0 },
{ 0x57, KEY_1 },
@@ -63,23 +63,23 @@ static struct ir_scancode adstech_dvb_t_pci[] = {
{ 0x1c, KEY_VOLUMEDOWN },
};
-static struct rc_keymap adstech_dvb_t_pci_map = {
+static struct rc_map_list adstech_dvb_t_pci_map = {
.map = {
.scan = adstech_dvb_t_pci,
.size = ARRAY_SIZE(adstech_dvb_t_pci),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ADSTECH_DVB_T_PCI,
}
};
static int __init init_rc_map_adstech_dvb_t_pci(void)
{
- return ir_register_map(&adstech_dvb_t_pci_map);
+ return rc_map_register(&adstech_dvb_t_pci_map);
}
static void __exit exit_rc_map_adstech_dvb_t_pci(void)
{
- ir_unregister_map(&adstech_dvb_t_pci_map);
+ rc_map_unregister(&adstech_dvb_t_pci_map);
}
module_init(init_rc_map_adstech_dvb_t_pci)
diff --git a/drivers/media/IR/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
index ddfee7f8093d..fe652e928dc0 100644
--- a/drivers/media/IR/keymaps/rc-alink-dtu-m.c
+++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
@@ -21,7 +21,7 @@
#include <media/rc-map.h>
/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
-static struct ir_scancode alink_dtu_m[] = {
+static struct rc_map_table alink_dtu_m[] = {
{ 0x0800, KEY_VOLUMEUP },
{ 0x0801, KEY_1 },
{ 0x0802, KEY_3 },
@@ -42,23 +42,23 @@ static struct ir_scancode alink_dtu_m[] = {
{ 0x081d, KEY_CHANNELDOWN },
};
-static struct rc_keymap alink_dtu_m_map = {
+static struct rc_map_list alink_dtu_m_map = {
.map = {
.scan = alink_dtu_m,
.size = ARRAY_SIZE(alink_dtu_m),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_ALINK_DTU_M,
}
};
static int __init init_rc_map_alink_dtu_m(void)
{
- return ir_register_map(&alink_dtu_m_map);
+ return rc_map_register(&alink_dtu_m_map);
}
static void __exit exit_rc_map_alink_dtu_m(void)
{
- ir_unregister_map(&alink_dtu_m_map);
+ rc_map_unregister(&alink_dtu_m_map);
}
module_init(init_rc_map_alink_dtu_m)
diff --git a/drivers/media/IR/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c
index 30d70498cfed..884f1b51a8ee 100644
--- a/drivers/media/IR/keymaps/rc-anysee.c
+++ b/drivers/media/rc/keymaps/rc-anysee.c
@@ -20,7 +20,7 @@
#include <media/rc-map.h>
-static struct ir_scancode anysee[] = {
+static struct rc_map_table anysee[] = {
{ 0x0800, KEY_0 },
{ 0x0801, KEY_1 },
{ 0x0802, KEY_2 },
@@ -67,23 +67,23 @@ static struct ir_scancode anysee[] = {
{ 0x0851, KEY_PAUSE },
};
-static struct rc_keymap anysee_map = {
+static struct rc_map_list anysee_map = {
.map = {
.scan = anysee,
.size = ARRAY_SIZE(anysee),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_ANYSEE,
}
};
static int __init init_rc_map_anysee(void)
{
- return ir_register_map(&anysee_map);
+ return rc_map_register(&anysee_map);
}
static void __exit exit_rc_map_anysee(void)
{
- ir_unregister_map(&anysee_map);
+ rc_map_unregister(&anysee_map);
}
module_init(init_rc_map_anysee)
diff --git a/drivers/media/IR/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
index 0ef2b562baf0..7af188209ff9 100644
--- a/drivers/media/IR/keymaps/rc-apac-viewcomp.c
+++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
@@ -14,7 +14,7 @@
/* Attila Kondoros <attila.kondoros@chello.hu> */
-static struct ir_scancode apac_viewcomp[] = {
+static struct rc_map_table apac_viewcomp[] = {
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -54,23 +54,23 @@ static struct ir_scancode apac_viewcomp[] = {
{ 0x18, KEY_KPMINUS }, /* fine tune <<<< */
};
-static struct rc_keymap apac_viewcomp_map = {
+static struct rc_map_list apac_viewcomp_map = {
.map = {
.scan = apac_viewcomp,
.size = ARRAY_SIZE(apac_viewcomp),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_APAC_VIEWCOMP,
}
};
static int __init init_rc_map_apac_viewcomp(void)
{
- return ir_register_map(&apac_viewcomp_map);
+ return rc_map_register(&apac_viewcomp_map);
}
static void __exit exit_rc_map_apac_viewcomp(void)
{
- ir_unregister_map(&apac_viewcomp_map);
+ rc_map_unregister(&apac_viewcomp_map);
}
module_init(init_rc_map_apac_viewcomp)
diff --git a/drivers/media/IR/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c
index 2996e0a3b8d5..b2481154491b 100644
--- a/drivers/media/IR/keymaps/rc-asus-pc39.c
+++ b/drivers/media/rc/keymaps/rc-asus-pc39.c
@@ -18,7 +18,7 @@
* which has a label saying is "Model PC-39"
*/
-static struct ir_scancode asus_pc39[] = {
+static struct rc_map_table asus_pc39[] = {
/* Keys 0 to 9 */
{ 0x082a, KEY_0 },
{ 0x0816, KEY_1 },
@@ -65,23 +65,23 @@ static struct ir_scancode asus_pc39[] = {
{ 0x083e, KEY_DVD }, /* dvd */
};
-static struct rc_keymap asus_pc39_map = {
+static struct rc_map_list asus_pc39_map = {
.map = {
.scan = asus_pc39,
.size = ARRAY_SIZE(asus_pc39),
- .ir_type = IR_TYPE_RC5,
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_ASUS_PC39,
}
};
static int __init init_rc_map_asus_pc39(void)
{
- return ir_register_map(&asus_pc39_map);
+ return rc_map_register(&asus_pc39_map);
}
static void __exit exit_rc_map_asus_pc39(void)
{
- ir_unregister_map(&asus_pc39_map);
+ rc_map_unregister(&asus_pc39_map);
}
module_init(init_rc_map_asus_pc39)
diff --git a/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
index 8edfd293d010..f766b24b0158 100644
--- a/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c
+++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
@@ -16,7 +16,7 @@
Devin Heitmueller <devin.heitmueller@gmail.com>
*/
-static struct ir_scancode ati_tv_wonder_hd_600[] = {
+static struct rc_map_table ati_tv_wonder_hd_600[] = {
{ 0x00, KEY_RECORD}, /* Row 1 */
{ 0x01, KEY_PLAYPAUSE},
{ 0x02, KEY_STOP},
@@ -43,23 +43,23 @@ static struct ir_scancode ati_tv_wonder_hd_600[] = {
{ 0x17, KEY_VOLUMEDOWN},
};
-static struct rc_keymap ati_tv_wonder_hd_600_map = {
+static struct rc_map_list ati_tv_wonder_hd_600_map = {
.map = {
.scan = ati_tv_wonder_hd_600,
.size = ARRAY_SIZE(ati_tv_wonder_hd_600),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ATI_TV_WONDER_HD_600,
}
};
static int __init init_rc_map_ati_tv_wonder_hd_600(void)
{
- return ir_register_map(&ati_tv_wonder_hd_600_map);
+ return rc_map_register(&ati_tv_wonder_hd_600_map);
}
static void __exit exit_rc_map_ati_tv_wonder_hd_600(void)
{
- ir_unregister_map(&ati_tv_wonder_hd_600_map);
+ rc_map_unregister(&ati_tv_wonder_hd_600_map);
}
module_init(init_rc_map_ati_tv_wonder_hd_600)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
index 12f043587f2e..ec9beeebd410 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-a16d.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode avermedia_a16d[] = {
+static struct rc_map_table avermedia_a16d[] = {
{ 0x20, KEY_LIST},
{ 0x00, KEY_POWER},
{ 0x28, KEY_1},
@@ -49,23 +49,23 @@ static struct ir_scancode avermedia_a16d[] = {
{ 0x2a, KEY_MENU},
};
-static struct rc_keymap avermedia_a16d_map = {
+static struct rc_map_list avermedia_a16d_map = {
.map = {
.scan = avermedia_a16d,
.size = ARRAY_SIZE(avermedia_a16d),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_A16D,
}
};
static int __init init_rc_map_avermedia_a16d(void)
{
- return ir_register_map(&avermedia_a16d_map);
+ return rc_map_register(&avermedia_a16d_map);
}
static void __exit exit_rc_map_avermedia_a16d(void)
{
- ir_unregister_map(&avermedia_a16d_map);
+ rc_map_unregister(&avermedia_a16d_map);
}
module_init(init_rc_map_avermedia_a16d)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
index 2a945b02e8ca..bdf97b74cf90 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-cardbus.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -14,7 +14,7 @@
/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
-static struct ir_scancode avermedia_cardbus[] = {
+static struct rc_map_table avermedia_cardbus[] = {
{ 0x00, KEY_POWER },
{ 0x01, KEY_TUNER }, /* TV/FM */
{ 0x03, KEY_TEXT }, /* Teletext */
@@ -71,23 +71,23 @@ static struct ir_scancode avermedia_cardbus[] = {
{ 0x43, KEY_CHANNELUP }, /* Channel up */
};
-static struct rc_keymap avermedia_cardbus_map = {
+static struct rc_map_list avermedia_cardbus_map = {
.map = {
.scan = avermedia_cardbus,
.size = ARRAY_SIZE(avermedia_cardbus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_CARDBUS,
}
};
static int __init init_rc_map_avermedia_cardbus(void)
{
- return ir_register_map(&avermedia_cardbus_map);
+ return rc_map_register(&avermedia_cardbus_map);
}
static void __exit exit_rc_map_avermedia_cardbus(void)
{
- ir_unregister_map(&avermedia_cardbus_map);
+ rc_map_unregister(&avermedia_cardbus_map);
}
module_init(init_rc_map_avermedia_cardbus)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
index 39dde6222875..3ddb41bc075e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-dvbt.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
@@ -14,7 +14,7 @@
/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static struct ir_scancode avermedia_dvbt[] = {
+static struct rc_map_table avermedia_dvbt[] = {
{ 0x28, KEY_0 }, /* '0' / 'enter' */
{ 0x22, KEY_1 }, /* '1' */
{ 0x12, KEY_2 }, /* '2' / 'up arrow' */
@@ -52,23 +52,23 @@ static struct ir_scancode avermedia_dvbt[] = {
{ 0x3e, KEY_VOLUMEUP }, /* 'volume +' */
};
-static struct rc_keymap avermedia_dvbt_map = {
+static struct rc_map_list avermedia_dvbt_map = {
.map = {
.scan = avermedia_dvbt,
.size = ARRAY_SIZE(avermedia_dvbt),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_DVBT,
}
};
static int __init init_rc_map_avermedia_dvbt(void)
{
- return ir_register_map(&avermedia_dvbt_map);
+ return rc_map_register(&avermedia_dvbt_map);
}
static void __exit exit_rc_map_avermedia_dvbt(void)
{
- ir_unregister_map(&avermedia_dvbt_map);
+ rc_map_unregister(&avermedia_dvbt_map);
}
module_init(init_rc_map_avermedia_dvbt)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
index e4471fb2ad1e..357fea58a46e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-m135a.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
@@ -22,7 +22,7 @@
* codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
*/
-static struct ir_scancode avermedia_m135a[] = {
+static struct rc_map_table avermedia_m135a[] = {
/* RM-JX */
{ 0x0200, KEY_POWER2 },
{ 0x022e, KEY_DOT }, /* '.' */
@@ -121,23 +121,23 @@ static struct ir_scancode avermedia_m135a[] = {
{ 0x041e, KEY_NEXT },
};
-static struct rc_keymap avermedia_m135a_map = {
+static struct rc_map_list avermedia_m135a_map = {
.map = {
.scan = avermedia_m135a,
.size = ARRAY_SIZE(avermedia_m135a),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_AVERMEDIA_M135A,
}
};
static int __init init_rc_map_avermedia_m135a(void)
{
- return ir_register_map(&avermedia_m135a_map);
+ return rc_map_register(&avermedia_m135a_map);
}
static void __exit exit_rc_map_avermedia_m135a(void)
{
- ir_unregister_map(&avermedia_m135a_map);
+ rc_map_unregister(&avermedia_m135a_map);
}
module_init(init_rc_map_avermedia_m135a)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
index cf8d45717cb3..e694e6eac37e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -16,7 +16,7 @@
* Herton Ronaldo Krzesinski <herton@mandriva.com.br>
*/
-static struct ir_scancode avermedia_m733a_rm_k6[] = {
+static struct rc_map_table avermedia_m733a_rm_k6[] = {
{ 0x0401, KEY_POWER2 },
{ 0x0406, KEY_MUTE },
{ 0x0408, KEY_MODE }, /* TV/FM */
@@ -69,23 +69,23 @@ static struct ir_scancode avermedia_m733a_rm_k6[] = {
{ 0x041e, KEY_NEXT },
};
-static struct rc_keymap avermedia_m733a_rm_k6_map = {
+static struct rc_map_list avermedia_m733a_rm_k6_map = {
.map = {
.scan = avermedia_m733a_rm_k6,
.size = ARRAY_SIZE(avermedia_m733a_rm_k6),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_AVERMEDIA_M733A_RM_K6,
}
};
static int __init init_rc_map_avermedia_m733a_rm_k6(void)
{
- return ir_register_map(&avermedia_m733a_rm_k6_map);
+ return rc_map_register(&avermedia_m733a_rm_k6_map);
}
static void __exit exit_rc_map_avermedia_m733a_rm_k6(void)
{
- ir_unregister_map(&avermedia_m733a_rm_k6_map);
+ rc_map_unregister(&avermedia_m733a_rm_k6_map);
}
module_init(init_rc_map_avermedia_m733a_rm_k6)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
index 9ee60906c861..f4ca1fff455d 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
@@ -23,7 +23,7 @@
/* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net>
and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
/* FIXME: mappings are not 100% correct? */
-static struct ir_scancode avermedia_rm_ks[] = {
+static struct rc_map_table avermedia_rm_ks[] = {
{ 0x0501, KEY_POWER2 },
{ 0x0502, KEY_CHANNELUP },
{ 0x0503, KEY_CHANNELDOWN },
@@ -53,23 +53,23 @@ static struct ir_scancode avermedia_rm_ks[] = {
{ 0x0556, KEY_ZOOM },
};
-static struct rc_keymap avermedia_rm_ks_map = {
+static struct rc_map_list avermedia_rm_ks_map = {
.map = {
.scan = avermedia_rm_ks,
.size = ARRAY_SIZE(avermedia_rm_ks),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_AVERMEDIA_RM_KS,
}
};
static int __init init_rc_map_avermedia_rm_ks(void)
{
- return ir_register_map(&avermedia_rm_ks_map);
+ return rc_map_register(&avermedia_rm_ks_map);
}
static void __exit exit_rc_map_avermedia_rm_ks(void)
{
- ir_unregister_map(&avermedia_rm_ks_map);
+ rc_map_unregister(&avermedia_rm_ks_map);
}
module_init(init_rc_map_avermedia_rm_ks)
diff --git a/drivers/media/IR/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c
index 21effd5bfb0d..edfa71506d3e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia.c
+++ b/drivers/media/rc/keymaps/rc-avermedia.c
@@ -14,7 +14,7 @@
/* Alex Hermann <gaaf@gmx.net> */
-static struct ir_scancode avermedia[] = {
+static struct rc_map_table avermedia[] = {
{ 0x28, KEY_1 },
{ 0x18, KEY_2 },
{ 0x38, KEY_3 },
@@ -60,23 +60,23 @@ static struct ir_scancode avermedia[] = {
{ 0x31, KEY_CHANNELUP } /* CHANNEL/PAGE+ */
};
-static struct rc_keymap avermedia_map = {
+static struct rc_map_list avermedia_map = {
.map = {
.scan = avermedia,
.size = ARRAY_SIZE(avermedia),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA,
}
};
static int __init init_rc_map_avermedia(void)
{
- return ir_register_map(&avermedia_map);
+ return rc_map_register(&avermedia_map);
}
static void __exit exit_rc_map_avermedia(void)
{
- ir_unregister_map(&avermedia_map);
+ rc_map_unregister(&avermedia_map);
}
module_init(init_rc_map_avermedia)
diff --git a/drivers/media/IR/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c
index 971c59d6f9d6..32e94988dc94 100644
--- a/drivers/media/IR/keymaps/rc-avertv-303.c
+++ b/drivers/media/rc/keymaps/rc-avertv-303.c
@@ -14,7 +14,7 @@
/* AVERTV STUDIO 303 Remote */
-static struct ir_scancode avertv_303[] = {
+static struct rc_map_table avertv_303[] = {
{ 0x2a, KEY_1 },
{ 0x32, KEY_2 },
{ 0x3a, KEY_3 },
@@ -59,23 +59,23 @@ static struct ir_scancode avertv_303[] = {
{ 0x1b, KEY_UP },
};
-static struct rc_keymap avertv_303_map = {
+static struct rc_map_list avertv_303_map = {
.map = {
.scan = avertv_303,
.size = ARRAY_SIZE(avertv_303),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERTV_303,
}
};
static int __init init_rc_map_avertv_303(void)
{
- return ir_register_map(&avertv_303_map);
+ return rc_map_register(&avertv_303_map);
}
static void __exit exit_rc_map_avertv_303(void)
{
- ir_unregister_map(&avertv_303_map);
+ rc_map_unregister(&avertv_303_map);
}
module_init(init_rc_map_avertv_303)
diff --git a/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
index e0876147d471..c3f6d62ac892 100644
--- a/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c
+++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
@@ -20,7 +20,7 @@
#include <media/rc-map.h>
-static struct ir_scancode azurewave_ad_tu700[] = {
+static struct rc_map_table azurewave_ad_tu700[] = {
{ 0x0000, KEY_TAB }, /* Tab */
{ 0x0001, KEY_2 },
{ 0x0002, KEY_CHANNELDOWN },
@@ -76,23 +76,23 @@ static struct ir_scancode azurewave_ad_tu700[] = {
{ 0x005f, KEY_BLUE },
};
-static struct rc_keymap azurewave_ad_tu700_map = {
+static struct rc_map_list azurewave_ad_tu700_map = {
.map = {
.scan = azurewave_ad_tu700,
.size = ARRAY_SIZE(azurewave_ad_tu700),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_AZUREWAVE_AD_TU700,
}
};
static int __init init_rc_map_azurewave_ad_tu700(void)
{
- return ir_register_map(&azurewave_ad_tu700_map);
+ return rc_map_register(&azurewave_ad_tu700_map);
}
static void __exit exit_rc_map_azurewave_ad_tu700(void)
{
- ir_unregister_map(&azurewave_ad_tu700_map);
+ rc_map_unregister(&azurewave_ad_tu700_map);
}
module_init(init_rc_map_azurewave_ad_tu700)
diff --git a/drivers/media/IR/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c
index 9f56c98fef5b..4b787fa94f08 100644
--- a/drivers/media/IR/keymaps/rc-behold-columbus.c
+++ b/drivers/media/rc/keymaps/rc-behold-columbus.c
@@ -21,7 +21,7 @@
* helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode behold_columbus[] = {
+static struct rc_map_table behold_columbus[] = {
/* 0x13 0x11 0x1C 0x12 *
* Mute Source TV/FM Power *
@@ -82,23 +82,23 @@ static struct ir_scancode behold_columbus[] = {
};
-static struct rc_keymap behold_columbus_map = {
+static struct rc_map_list behold_columbus_map = {
.map = {
.scan = behold_columbus,
.size = ARRAY_SIZE(behold_columbus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_BEHOLD_COLUMBUS,
}
};
static int __init init_rc_map_behold_columbus(void)
{
- return ir_register_map(&behold_columbus_map);
+ return rc_map_register(&behold_columbus_map);
}
static void __exit exit_rc_map_behold_columbus(void)
{
- ir_unregister_map(&behold_columbus_map);
+ rc_map_unregister(&behold_columbus_map);
}
module_init(init_rc_map_behold_columbus)
diff --git a/drivers/media/IR/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index abc140b2098b..0ee1f149364c 100644
--- a/drivers/media/IR/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -24,13 +24,13 @@
* helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode behold[] = {
+static struct rc_map_table behold[] = {
/* 0x1c 0x12 *
* TV/FM POWER *
* */
- { 0x1c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
- { 0x12, KEY_POWER },
+ { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
+ { 0x6b8612, KEY_POWER },
/* 0x01 0x02 0x03 *
* 1 2 3 *
@@ -41,28 +41,28 @@ static struct ir_scancode behold[] = {
* 0x07 0x08 0x09 *
* 7 8 9 *
* */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x6b8601, KEY_1 },
+ { 0x6b8602, KEY_2 },
+ { 0x6b8603, KEY_3 },
+ { 0x6b8604, KEY_4 },
+ { 0x6b8605, KEY_5 },
+ { 0x6b8606, KEY_6 },
+ { 0x6b8607, KEY_7 },
+ { 0x6b8608, KEY_8 },
+ { 0x6b8609, KEY_9 },
/* 0x0a 0x00 0x17 *
* RECALL 0 MODE *
* */
- { 0x0a, KEY_AGAIN },
- { 0x00, KEY_0 },
- { 0x17, KEY_MODE },
+ { 0x6b860a, KEY_AGAIN },
+ { 0x6b8600, KEY_0 },
+ { 0x6b8617, KEY_MODE },
/* 0x14 0x10 *
* ASPECT FULLSCREEN *
* */
- { 0x14, KEY_SCREEN },
- { 0x10, KEY_ZOOM },
+ { 0x6b8614, KEY_SCREEN },
+ { 0x6b8610, KEY_ZOOM },
/* 0x0b *
* Up *
@@ -73,17 +73,17 @@ static struct ir_scancode behold[] = {
* 0x015 *
* Down *
* */
- { 0x0b, KEY_CHANNELUP },
- { 0x18, KEY_VOLUMEDOWN },
- { 0x16, KEY_OK }, /* XXX KEY_ENTER */
- { 0x0c, KEY_VOLUMEUP },
- { 0x15, KEY_CHANNELDOWN },
+ { 0x6b860b, KEY_CHANNELUP },
+ { 0x6b8618, KEY_VOLUMEDOWN },
+ { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */
+ { 0x6b860c, KEY_VOLUMEUP },
+ { 0x6b8615, KEY_CHANNELDOWN },
/* 0x11 0x0d *
* MUTE INFO *
* */
- { 0x11, KEY_MUTE },
- { 0x0d, KEY_INFO },
+ { 0x6b8611, KEY_MUTE },
+ { 0x6b860d, KEY_INFO },
/* 0x0f 0x1b 0x1a *
* RECORD PLAY/PAUSE STOP *
@@ -92,46 +92,46 @@ static struct ir_scancode behold[] = {
*TELETEXT AUDIO SOURCE *
* RED YELLOW *
* */
- { 0x0f, KEY_RECORD },
- { 0x1b, KEY_PLAYPAUSE },
- { 0x1a, KEY_STOP },
- { 0x0e, KEY_TEXT },
- { 0x1f, KEY_RED }, /*XXX KEY_AUDIO */
- { 0x1e, KEY_YELLOW }, /*XXX KEY_SOURCE */
+ { 0x6b860f, KEY_RECORD },
+ { 0x6b861b, KEY_PLAYPAUSE },
+ { 0x6b861a, KEY_STOP },
+ { 0x6b860e, KEY_TEXT },
+ { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */
+ { 0x6b861e, KEY_YELLOW }, /*XXX KEY_SOURCE */
/* 0x1d 0x13 0x19 *
* SLEEP PREVIEW DVB *
* GREEN BLUE *
* */
- { 0x1d, KEY_SLEEP },
- { 0x13, KEY_GREEN },
- { 0x19, KEY_BLUE }, /* XXX KEY_SAT */
+ { 0x6b861d, KEY_SLEEP },
+ { 0x6b8613, KEY_GREEN },
+ { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */
/* 0x58 0x5c *
* FREEZE SNAPSHOT *
* */
- { 0x58, KEY_SLOW },
- { 0x5c, KEY_CAMERA },
+ { 0x6b8658, KEY_SLOW },
+ { 0x6b865c, KEY_CAMERA },
};
-static struct rc_keymap behold_map = {
+static struct rc_map_list behold_map = {
.map = {
.scan = behold,
.size = ARRAY_SIZE(behold),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_BEHOLD,
}
};
static int __init init_rc_map_behold(void)
{
- return ir_register_map(&behold_map);
+ return rc_map_register(&behold_map);
}
static void __exit exit_rc_map_behold(void)
{
- ir_unregister_map(&behold_map);
+ rc_map_unregister(&behold_map);
}
module_init(init_rc_map_behold)
diff --git a/drivers/media/IR/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c
index 64c2ac913338..97fc3862f608 100644
--- a/drivers/media/IR/keymaps/rc-budget-ci-old.c
+++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c
@@ -18,7 +18,7 @@
* This is a "middle of the road" approach, differences are noted
*/
-static struct ir_scancode budget_ci_old[] = {
+static struct rc_map_table budget_ci_old[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -66,23 +66,23 @@ static struct ir_scancode budget_ci_old[] = {
{ 0x3e, KEY_TUNER },
};
-static struct rc_keymap budget_ci_old_map = {
+static struct rc_map_list budget_ci_old_map = {
.map = {
.scan = budget_ci_old,
.size = ARRAY_SIZE(budget_ci_old),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_BUDGET_CI_OLD,
}
};
static int __init init_rc_map_budget_ci_old(void)
{
- return ir_register_map(&budget_ci_old_map);
+ return rc_map_register(&budget_ci_old_map);
}
static void __exit exit_rc_map_budget_ci_old(void)
{
- ir_unregister_map(&budget_ci_old_map);
+ rc_map_unregister(&budget_ci_old_map);
}
module_init(init_rc_map_budget_ci_old)
diff --git a/drivers/media/IR/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c
index 074f2c2c2c61..284534b67e7d 100644
--- a/drivers/media/IR/keymaps/rc-cinergy-1400.c
+++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c
@@ -14,7 +14,7 @@
/* Cinergy 1400 DVB-T */
-static struct ir_scancode cinergy_1400[] = {
+static struct rc_map_table cinergy_1400[] = {
{ 0x01, KEY_POWER },
{ 0x02, KEY_1 },
{ 0x03, KEY_2 },
@@ -58,23 +58,23 @@ static struct ir_scancode cinergy_1400[] = {
{ 0x5c, KEY_NEXT },
};
-static struct rc_keymap cinergy_1400_map = {
+static struct rc_map_list cinergy_1400_map = {
.map = {
.scan = cinergy_1400,
.size = ARRAY_SIZE(cinergy_1400),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_CINERGY_1400,
}
};
static int __init init_rc_map_cinergy_1400(void)
{
- return ir_register_map(&cinergy_1400_map);
+ return rc_map_register(&cinergy_1400_map);
}
static void __exit exit_rc_map_cinergy_1400(void)
{
- ir_unregister_map(&cinergy_1400_map);
+ rc_map_unregister(&cinergy_1400_map);
}
module_init(init_rc_map_cinergy_1400)
diff --git a/drivers/media/IR/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c
index cf84c3dba742..99520ff65b61 100644
--- a/drivers/media/IR/keymaps/rc-cinergy.c
+++ b/drivers/media/rc/keymaps/rc-cinergy.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode cinergy[] = {
+static struct rc_map_table cinergy[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -52,23 +52,23 @@ static struct ir_scancode cinergy[] = {
{ 0x23, KEY_STOP },
};
-static struct rc_keymap cinergy_map = {
+static struct rc_map_list cinergy_map = {
.map = {
.scan = cinergy,
.size = ARRAY_SIZE(cinergy),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_CINERGY,
}
};
static int __init init_rc_map_cinergy(void)
{
- return ir_register_map(&cinergy_map);
+ return rc_map_register(&cinergy_map);
}
static void __exit exit_rc_map_cinergy(void)
{
- ir_unregister_map(&cinergy_map);
+ rc_map_unregister(&cinergy_map);
}
module_init(init_rc_map_cinergy)
diff --git a/drivers/media/IR/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
index ae1832038fbe..c59851b203da 100644
--- a/drivers/media/IR/keymaps/rc-dib0700-nec.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -17,7 +17,7 @@
#include <media/rc-map.h>
-static struct ir_scancode dib0700_nec_table[] = {
+static struct rc_map_table dib0700_nec_table[] = {
/* Key codes for the Pixelview SBTVD remote */
{ 0x8613, KEY_MUTE },
{ 0x8612, KEY_POWER },
@@ -98,23 +98,23 @@ static struct ir_scancode dib0700_nec_table[] = {
{ 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
};
-static struct rc_keymap dib0700_nec_map = {
+static struct rc_map_list dib0700_nec_map = {
.map = {
.scan = dib0700_nec_table,
.size = ARRAY_SIZE(dib0700_nec_table),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_DIB0700_NEC_TABLE,
}
};
static int __init init_rc_map(void)
{
- return ir_register_map(&dib0700_nec_map);
+ return rc_map_register(&dib0700_nec_map);
}
static void __exit exit_rc_map(void)
{
- ir_unregister_map(&dib0700_nec_map);
+ rc_map_unregister(&dib0700_nec_map);
}
module_init(init_rc_map)
diff --git a/drivers/media/IR/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
index 4a4797cfd77d..4af12e45dfba 100644
--- a/drivers/media/IR/keymaps/rc-dib0700-rc5.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
@@ -17,7 +17,7 @@
#include <media/rc-map.h>
-static struct ir_scancode dib0700_rc5_table[] = {
+static struct rc_map_table dib0700_rc5_table[] = {
/* Key codes for the tiny Pinnacle remote*/
{ 0x0700, KEY_MUTE },
{ 0x0701, KEY_MENU }, /* Pinnacle logo */
@@ -209,23 +209,23 @@ static struct ir_scancode dib0700_rc5_table[] = {
{ 0x1d3d, KEY_POWER },
};
-static struct rc_keymap dib0700_rc5_map = {
+static struct rc_map_list dib0700_rc5_map = {
.map = {
.scan = dib0700_rc5_table,
.size = ARRAY_SIZE(dib0700_rc5_table),
- .ir_type = IR_TYPE_RC5,
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_DIB0700_RC5_TABLE,
}
};
static int __init init_rc_map(void)
{
- return ir_register_map(&dib0700_rc5_map);
+ return rc_map_register(&dib0700_rc5_map);
}
static void __exit exit_rc_map(void)
{
- ir_unregister_map(&dib0700_rc5_map);
+ rc_map_unregister(&dib0700_rc5_map);
}
module_init(init_rc_map)
diff --git a/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
index 63e469e2dd21..f68b450f5593 100644
--- a/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c
+++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
@@ -20,7 +20,7 @@
#include <media/rc-map.h>
-static struct ir_scancode digitalnow_tinytwin[] = {
+static struct rc_map_table digitalnow_tinytwin[] = {
{ 0x0000, KEY_MUTE }, /* [symbol speaker] */
{ 0x0001, KEY_VOLUMEUP },
{ 0x0002, KEY_POWER2 }, /* TV [power button] */
@@ -72,23 +72,23 @@ static struct ir_scancode digitalnow_tinytwin[] = {
{ 0x005a, KEY_PREVIOUS }, /* REPLAY */
};
-static struct rc_keymap digitalnow_tinytwin_map = {
+static struct rc_map_list digitalnow_tinytwin_map = {
.map = {
.scan = digitalnow_tinytwin,
.size = ARRAY_SIZE(digitalnow_tinytwin),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_DIGITALNOW_TINYTWIN,
}
};
static int __init init_rc_map_digitalnow_tinytwin(void)
{
- return ir_register_map(&digitalnow_tinytwin_map);
+ return rc_map_register(&digitalnow_tinytwin_map);
}
static void __exit exit_rc_map_digitalnow_tinytwin(void)
{
- ir_unregister_map(&digitalnow_tinytwin_map);
+ rc_map_unregister(&digitalnow_tinytwin_map);
}
module_init(init_rc_map_digitalnow_tinytwin)
diff --git a/drivers/media/IR/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c
index 5dece78e19c5..21d49871f2a3 100644
--- a/drivers/media/IR/keymaps/rc-digittrade.c
+++ b/drivers/media/rc/keymaps/rc-digittrade.c
@@ -25,7 +25,7 @@
Initial keytable was from Alain Kalker <miki@dds.nl> */
/* Digittrade DVB-T USB Stick */
-static struct ir_scancode digittrade[] = {
+static struct rc_map_table digittrade[] = {
{ 0x0000, KEY_9 },
{ 0x0001, KEY_EPG }, /* EPG */
{ 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
@@ -56,23 +56,23 @@ static struct ir_scancode digittrade[] = {
{ 0x0054, KEY_0 },
};
-static struct rc_keymap digittrade_map = {
+static struct rc_map_list digittrade_map = {
.map = {
.scan = digittrade,
.size = ARRAY_SIZE(digittrade),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_DIGITTRADE,
}
};
static int __init init_rc_map_digittrade(void)
{
- return ir_register_map(&digittrade_map);
+ return rc_map_register(&digittrade_map);
}
static void __exit exit_rc_map_digittrade(void)
{
- ir_unregister_map(&digittrade_map);
+ rc_map_unregister(&digittrade_map);
}
module_init(init_rc_map_digittrade)
diff --git a/drivers/media/IR/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c
index 90684d0efea3..d024fbf88bc4 100644
--- a/drivers/media/IR/keymaps/rc-dm1105-nec.c
+++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c
@@ -16,7 +16,7 @@
Igor M. Liplianin <liplianin@me.by>
*/
-static struct ir_scancode dm1105_nec[] = {
+static struct rc_map_table dm1105_nec[] = {
{ 0x0a, KEY_POWER2}, /* power */
{ 0x0c, KEY_MUTE}, /* mute */
{ 0x11, KEY_1},
@@ -50,23 +50,23 @@ static struct ir_scancode dm1105_nec[] = {
{ 0x1b, KEY_B}, /* recall */
};
-static struct rc_keymap dm1105_nec_map = {
+static struct rc_map_list dm1105_nec_map = {
.map = {
.scan = dm1105_nec,
.size = ARRAY_SIZE(dm1105_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DM1105_NEC,
}
};
static int __init init_rc_map_dm1105_nec(void)
{
- return ir_register_map(&dm1105_nec_map);
+ return rc_map_register(&dm1105_nec_map);
}
static void __exit exit_rc_map_dm1105_nec(void)
{
- ir_unregister_map(&dm1105_nec_map);
+ rc_map_unregister(&dm1105_nec_map);
}
module_init(init_rc_map_dm1105_nec)
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
index 8a4027af964a..43912bd02a9e 100644
--- a/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
@@ -14,7 +14,7 @@
/* DigitalNow DNTV Live DVB-T Remote */
-static struct ir_scancode dntv_live_dvb_t[] = {
+static struct rc_map_table dntv_live_dvb_t[] = {
{ 0x00, KEY_ESC }, /* 'go up a level?' */
/* Keys 0 to 9 */
{ 0x0a, KEY_0 },
@@ -52,23 +52,23 @@ static struct ir_scancode dntv_live_dvb_t[] = {
{ 0x1f, KEY_VOLUMEDOWN },
};
-static struct rc_keymap dntv_live_dvb_t_map = {
+static struct rc_map_list dntv_live_dvb_t_map = {
.map = {
.scan = dntv_live_dvb_t,
.size = ARRAY_SIZE(dntv_live_dvb_t),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DNTV_LIVE_DVB_T,
}
};
static int __init init_rc_map_dntv_live_dvb_t(void)
{
- return ir_register_map(&dntv_live_dvb_t_map);
+ return rc_map_register(&dntv_live_dvb_t_map);
}
static void __exit exit_rc_map_dntv_live_dvb_t(void)
{
- ir_unregister_map(&dntv_live_dvb_t_map);
+ rc_map_unregister(&dntv_live_dvb_t_map);
}
module_init(init_rc_map_dntv_live_dvb_t)
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
index 6f4d60764d59..015e99de06de 100644
--- a/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
@@ -14,7 +14,7 @@
/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static struct ir_scancode dntv_live_dvbt_pro[] = {
+static struct rc_map_table dntv_live_dvbt_pro[] = {
{ 0x16, KEY_POWER },
{ 0x5b, KEY_HOME },
@@ -71,23 +71,23 @@ static struct ir_scancode dntv_live_dvbt_pro[] = {
{ 0x5d, KEY_BLUE },
};
-static struct rc_keymap dntv_live_dvbt_pro_map = {
+static struct rc_map_list dntv_live_dvbt_pro_map = {
.map = {
.scan = dntv_live_dvbt_pro,
.size = ARRAY_SIZE(dntv_live_dvbt_pro),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DNTV_LIVE_DVBT_PRO,
}
};
static int __init init_rc_map_dntv_live_dvbt_pro(void)
{
- return ir_register_map(&dntv_live_dvbt_pro_map);
+ return rc_map_register(&dntv_live_dvbt_pro_map);
}
static void __exit exit_rc_map_dntv_live_dvbt_pro(void)
{
- ir_unregister_map(&dntv_live_dvbt_pro_map);
+ rc_map_unregister(&dntv_live_dvbt_pro_map);
}
module_init(init_rc_map_dntv_live_dvbt_pro)
diff --git a/drivers/media/IR/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c
index 3130c9c29e6b..269d4299da34 100644
--- a/drivers/media/IR/keymaps/rc-em-terratec.c
+++ b/drivers/media/rc/keymaps/rc-em-terratec.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode em_terratec[] = {
+static struct rc_map_table em_terratec[] = {
{ 0x01, KEY_CHANNEL },
{ 0x02, KEY_SELECT },
{ 0x03, KEY_MUTE },
@@ -43,23 +43,23 @@ static struct ir_scancode em_terratec[] = {
{ 0x40, KEY_ZOOM },
};
-static struct rc_keymap em_terratec_map = {
+static struct rc_map_list em_terratec_map = {
.map = {
.scan = em_terratec,
.size = ARRAY_SIZE(em_terratec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EM_TERRATEC,
}
};
static int __init init_rc_map_em_terratec(void)
{
- return ir_register_map(&em_terratec_map);
+ return rc_map_register(&em_terratec_map);
}
static void __exit exit_rc_map_em_terratec(void)
{
- ir_unregister_map(&em_terratec_map);
+ rc_map_unregister(&em_terratec_map);
}
module_init(init_rc_map_em_terratec)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
index 4b816967877e..e388698a0697 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode encore_enltv_fm53[] = {
+static struct rc_map_table encore_enltv_fm53[] = {
{ 0x10, KEY_POWER2},
{ 0x06, KEY_MUTE},
@@ -55,23 +55,23 @@ static struct ir_scancode encore_enltv_fm53[] = {
{ 0x47, KEY_SLEEP}, /* shutdown */
};
-static struct rc_keymap encore_enltv_fm53_map = {
+static struct rc_map_list encore_enltv_fm53_map = {
.map = {
.scan = encore_enltv_fm53,
.size = ARRAY_SIZE(encore_enltv_fm53),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV_FM53,
}
};
static int __init init_rc_map_encore_enltv_fm53(void)
{
- return ir_register_map(&encore_enltv_fm53_map);
+ return rc_map_register(&encore_enltv_fm53_map);
}
static void __exit exit_rc_map_encore_enltv_fm53(void)
{
- ir_unregister_map(&encore_enltv_fm53_map);
+ rc_map_unregister(&encore_enltv_fm53_map);
}
module_init(init_rc_map_encore_enltv_fm53)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c
index 9fabffd28cc9..afa4e92284ef 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv.c
@@ -15,7 +15,7 @@
/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
Juan Pablo Sormani <sorman@gmail.com> */
-static struct ir_scancode encore_enltv[] = {
+static struct rc_map_table encore_enltv[] = {
/* Power button does nothing, neither in Windows app,
although it sends data (used for BIOS wakeup?) */
@@ -86,23 +86,23 @@ static struct ir_scancode encore_enltv[] = {
{ 0x57, KEY_BLUE }, /* AP4 */
};
-static struct rc_keymap encore_enltv_map = {
+static struct rc_map_list encore_enltv_map = {
.map = {
.scan = encore_enltv,
.size = ARRAY_SIZE(encore_enltv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV,
}
};
static int __init init_rc_map_encore_enltv(void)
{
- return ir_register_map(&encore_enltv_map);
+ return rc_map_register(&encore_enltv_map);
}
static void __exit exit_rc_map_encore_enltv(void)
{
- ir_unregister_map(&encore_enltv_map);
+ rc_map_unregister(&encore_enltv_map);
}
module_init(init_rc_map_encore_enltv)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c
index efefd5166618..7d5b00ed4ff2 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv2.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c
@@ -15,7 +15,7 @@
/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton
Mauro Carvalho Chehab <mchehab@infradead.org> */
-static struct ir_scancode encore_enltv2[] = {
+static struct rc_map_table encore_enltv2[] = {
{ 0x4c, KEY_POWER2 },
{ 0x4a, KEY_TUNER },
{ 0x40, KEY_1 },
@@ -64,23 +64,23 @@ static struct ir_scancode encore_enltv2[] = {
{ 0x79, KEY_STOP },
};
-static struct rc_keymap encore_enltv2_map = {
+static struct rc_map_list encore_enltv2_map = {
.map = {
.scan = encore_enltv2,
.size = ARRAY_SIZE(encore_enltv2),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV2,
}
};
static int __init init_rc_map_encore_enltv2(void)
{
- return ir_register_map(&encore_enltv2_map);
+ return rc_map_register(&encore_enltv2_map);
}
static void __exit exit_rc_map_encore_enltv2(void)
{
- ir_unregister_map(&encore_enltv2_map);
+ rc_map_unregister(&encore_enltv2_map);
}
module_init(init_rc_map_encore_enltv2)
diff --git a/drivers/media/IR/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c
index 3f3fb13813b3..a2bf24f6dfbb 100644
--- a/drivers/media/IR/keymaps/rc-evga-indtube.c
+++ b/drivers/media/rc/keymaps/rc-evga-indtube.c
@@ -16,7 +16,7 @@
Devin Heitmueller <devin.heitmueller@gmail.com>
*/
-static struct ir_scancode evga_indtube[] = {
+static struct rc_map_table evga_indtube[] = {
{ 0x12, KEY_POWER},
{ 0x02, KEY_MODE}, /* TV */
{ 0x14, KEY_MUTE},
@@ -35,23 +35,23 @@ static struct ir_scancode evga_indtube[] = {
{ 0x13, KEY_CAMERA},
};
-static struct rc_keymap evga_indtube_map = {
+static struct rc_map_list evga_indtube_map = {
.map = {
.scan = evga_indtube,
.size = ARRAY_SIZE(evga_indtube),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EVGA_INDTUBE,
}
};
static int __init init_rc_map_evga_indtube(void)
{
- return ir_register_map(&evga_indtube_map);
+ return rc_map_register(&evga_indtube_map);
}
static void __exit exit_rc_map_evga_indtube(void)
{
- ir_unregister_map(&evga_indtube_map);
+ rc_map_unregister(&evga_indtube_map);
}
module_init(init_rc_map_evga_indtube)
diff --git a/drivers/media/IR/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c
index 660907a78db9..1e8e5b2d6e36 100644
--- a/drivers/media/IR/keymaps/rc-eztv.c
+++ b/drivers/media/rc/keymaps/rc-eztv.c
@@ -15,7 +15,7 @@
/* Alfons Geser <a.geser@cox.net>
* updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static struct ir_scancode eztv[] = {
+static struct rc_map_table eztv[] = {
{ 0x12, KEY_POWER },
{ 0x01, KEY_TV }, /* DVR */
{ 0x15, KEY_DVD }, /* DVD */
@@ -70,23 +70,23 @@ static struct ir_scancode eztv[] = {
{ 0x21, KEY_DOT }, /* . (decimal dot) */
};
-static struct rc_keymap eztv_map = {
+static struct rc_map_list eztv_map = {
.map = {
.scan = eztv,
.size = ARRAY_SIZE(eztv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EZTV,
}
};
static int __init init_rc_map_eztv(void)
{
- return ir_register_map(&eztv_map);
+ return rc_map_register(&eztv_map);
}
static void __exit exit_rc_map_eztv(void)
{
- ir_unregister_map(&eztv_map);
+ rc_map_unregister(&eztv_map);
}
module_init(init_rc_map_eztv)
diff --git a/drivers/media/IR/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c
index a173c81035f4..aea2f4acf7d8 100644
--- a/drivers/media/IR/keymaps/rc-flydvb.c
+++ b/drivers/media/rc/keymaps/rc-flydvb.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode flydvb[] = {
+static struct rc_map_table flydvb[] = {
{ 0x01, KEY_ZOOM }, /* Full Screen */
{ 0x00, KEY_POWER }, /* Power */
@@ -51,23 +51,23 @@ static struct ir_scancode flydvb[] = {
{ 0x0e, KEY_NEXT }, /* End >>| */
};
-static struct rc_keymap flydvb_map = {
+static struct rc_map_list flydvb_map = {
.map = {
.scan = flydvb,
.size = ARRAY_SIZE(flydvb),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FLYDVB,
}
};
static int __init init_rc_map_flydvb(void)
{
- return ir_register_map(&flydvb_map);
+ return rc_map_register(&flydvb_map);
}
static void __exit exit_rc_map_flydvb(void)
{
- ir_unregister_map(&flydvb_map);
+ rc_map_unregister(&flydvb_map);
}
module_init(init_rc_map_flydvb)
diff --git a/drivers/media/IR/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c
index 9c73043cbdba..5bbe68371756 100644
--- a/drivers/media/IR/keymaps/rc-flyvideo.c
+++ b/drivers/media/rc/keymaps/rc-flyvideo.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode flyvideo[] = {
+static struct rc_map_table flyvideo[] = {
{ 0x0f, KEY_0 },
{ 0x03, KEY_1 },
{ 0x04, KEY_2 },
@@ -44,23 +44,23 @@ static struct ir_scancode flyvideo[] = {
{ 0x0a, KEY_ANGLE }, /* no label, may be used as the PAUSE button */
};
-static struct rc_keymap flyvideo_map = {
+static struct rc_map_list flyvideo_map = {
.map = {
.scan = flyvideo,
.size = ARRAY_SIZE(flyvideo),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FLYVIDEO,
}
};
static int __init init_rc_map_flyvideo(void)
{
- return ir_register_map(&flyvideo_map);
+ return rc_map_register(&flyvideo_map);
}
static void __exit exit_rc_map_flyvideo(void)
{
- ir_unregister_map(&flyvideo_map);
+ rc_map_unregister(&flyvideo_map);
}
module_init(init_rc_map_flyvideo)
diff --git a/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
index cdb10389b10e..c80b25c65b57 100644
--- a/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c
+++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
@@ -14,7 +14,7 @@
/* DViCO FUSION HDTV MCE remote */
-static struct ir_scancode fusionhdtv_mce[] = {
+static struct rc_map_table fusionhdtv_mce[] = {
{ 0x0b, KEY_1 },
{ 0x17, KEY_2 },
@@ -72,23 +72,23 @@ static struct ir_scancode fusionhdtv_mce[] = {
{ 0x4e, KEY_POWER },
};
-static struct rc_keymap fusionhdtv_mce_map = {
+static struct rc_map_list fusionhdtv_mce_map = {
.map = {
.scan = fusionhdtv_mce,
.size = ARRAY_SIZE(fusionhdtv_mce),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FUSIONHDTV_MCE,
}
};
static int __init init_rc_map_fusionhdtv_mce(void)
{
- return ir_register_map(&fusionhdtv_mce_map);
+ return rc_map_register(&fusionhdtv_mce_map);
}
static void __exit exit_rc_map_fusionhdtv_mce(void)
{
- ir_unregister_map(&fusionhdtv_mce_map);
+ rc_map_unregister(&fusionhdtv_mce_map);
}
module_init(init_rc_map_fusionhdtv_mce)
diff --git a/drivers/media/IR/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
index c16c0d1263ac..068c9ead98dd 100644
--- a/drivers/media/IR/keymaps/rc-gadmei-rm008z.c
+++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
@@ -16,7 +16,7 @@
Shine Liu <shinel@foxmail.com>
*/
-static struct ir_scancode gadmei_rm008z[] = {
+static struct rc_map_table gadmei_rm008z[] = {
{ 0x14, KEY_POWER2}, /* POWER OFF */
{ 0x0c, KEY_MUTE}, /* MUTE */
@@ -55,23 +55,23 @@ static struct ir_scancode gadmei_rm008z[] = {
{ 0x15, KEY_ENTER}, /* OK */
};
-static struct rc_keymap gadmei_rm008z_map = {
+static struct rc_map_list gadmei_rm008z_map = {
.map = {
.scan = gadmei_rm008z,
.size = ARRAY_SIZE(gadmei_rm008z),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GADMEI_RM008Z,
}
};
static int __init init_rc_map_gadmei_rm008z(void)
{
- return ir_register_map(&gadmei_rm008z_map);
+ return rc_map_register(&gadmei_rm008z_map);
}
static void __exit exit_rc_map_gadmei_rm008z(void)
{
- ir_unregister_map(&gadmei_rm008z_map);
+ rc_map_unregister(&gadmei_rm008z_map);
}
module_init(init_rc_map_gadmei_rm008z)
diff --git a/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
index 89f8e384e52a..cdbbed467926 100644
--- a/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c
+++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
@@ -17,7 +17,7 @@
* Adrian Pardini <pardo.bsso@gmail.com>
*/
-static struct ir_scancode genius_tvgo_a11mce[] = {
+static struct rc_map_table genius_tvgo_a11mce[] = {
/* Keys 0 to 9 */
{ 0x48, KEY_0 },
{ 0x09, KEY_1 },
@@ -58,23 +58,23 @@ static struct ir_scancode genius_tvgo_a11mce[] = {
{ 0x50, KEY_BLUE },
};
-static struct rc_keymap genius_tvgo_a11mce_map = {
+static struct rc_map_list genius_tvgo_a11mce_map = {
.map = {
.scan = genius_tvgo_a11mce,
.size = ARRAY_SIZE(genius_tvgo_a11mce),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GENIUS_TVGO_A11MCE,
}
};
static int __init init_rc_map_genius_tvgo_a11mce(void)
{
- return ir_register_map(&genius_tvgo_a11mce_map);
+ return rc_map_register(&genius_tvgo_a11mce_map);
}
static void __exit exit_rc_map_genius_tvgo_a11mce(void)
{
- ir_unregister_map(&genius_tvgo_a11mce_map);
+ rc_map_unregister(&genius_tvgo_a11mce_map);
}
module_init(init_rc_map_genius_tvgo_a11mce)
diff --git a/drivers/media/IR/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c
index 52f025bb35f6..a38bdde8c140 100644
--- a/drivers/media/IR/keymaps/rc-gotview7135.c
+++ b/drivers/media/rc/keymaps/rc-gotview7135.c
@@ -14,7 +14,7 @@
/* Mike Baikov <mike@baikov.com> */
-static struct ir_scancode gotview7135[] = {
+static struct rc_map_table gotview7135[] = {
{ 0x11, KEY_POWER },
{ 0x35, KEY_TV },
@@ -53,23 +53,23 @@ static struct ir_scancode gotview7135[] = {
{ 0x38, KEY_F24 }, /* NORMAL TIMESHIFT */
};
-static struct rc_keymap gotview7135_map = {
+static struct rc_map_list gotview7135_map = {
.map = {
.scan = gotview7135,
.size = ARRAY_SIZE(gotview7135),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GOTVIEW7135,
}
};
static int __init init_rc_map_gotview7135(void)
{
- return ir_register_map(&gotview7135_map);
+ return rc_map_register(&gotview7135_map);
}
static void __exit exit_rc_map_gotview7135(void)
{
- ir_unregister_map(&gotview7135_map);
+ rc_map_unregister(&gotview7135_map);
}
module_init(init_rc_map_gotview7135)
diff --git a/drivers/media/IR/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c
index c6f8cd7c5186..bd11da46e56a 100644
--- a/drivers/media/IR/keymaps/rc-hauppauge-new.c
+++ b/drivers/media/rc/keymaps/rc-hauppauge-new.c
@@ -16,7 +16,7 @@
* slightly different versions), shipped with cx88+ivtv cards.
* almost rc5 coding, but some non-standard keys */
-static struct ir_scancode hauppauge_new[] = {
+static struct rc_map_table hauppauge_new[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -74,23 +74,23 @@ static struct ir_scancode hauppauge_new[] = {
{ 0x3d, KEY_POWER }, /* system power (green button) */
};
-static struct rc_keymap hauppauge_new_map = {
+static struct rc_map_list hauppauge_new_map = {
.map = {
.scan = hauppauge_new,
.size = ARRAY_SIZE(hauppauge_new),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_HAUPPAUGE_NEW,
}
};
static int __init init_rc_map_hauppauge_new(void)
{
- return ir_register_map(&hauppauge_new_map);
+ return rc_map_register(&hauppauge_new_map);
}
static void __exit exit_rc_map_hauppauge_new(void)
{
- ir_unregister_map(&hauppauge_new_map);
+ rc_map_unregister(&hauppauge_new_map);
}
module_init(init_rc_map_hauppauge_new)
diff --git a/drivers/media/IR/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c
index e49f350e3a0d..cb67184e015c 100644
--- a/drivers/media/IR/keymaps/rc-imon-mce.c
+++ b/drivers/media/rc/keymaps/rc-imon-mce.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
/* mce-mode imon mce remote key table */
-static struct ir_scancode imon_mce[] = {
+static struct rc_map_table imon_mce[] = {
/* keys sorted mostly by frequency of use to optimize lookups */
{ 0x800ff415, KEY_REWIND },
{ 0x800ff414, KEY_FASTFORWARD },
@@ -115,24 +115,24 @@ static struct ir_scancode imon_mce[] = {
};
-static struct rc_keymap imon_mce_map = {
+static struct rc_map_list imon_mce_map = {
.map = {
.scan = imon_mce,
.size = ARRAY_SIZE(imon_mce),
/* its RC6, but w/a hardware decoder */
- .ir_type = IR_TYPE_RC6,
+ .rc_type = RC_TYPE_RC6,
.name = RC_MAP_IMON_MCE,
}
};
static int __init init_rc_map_imon_mce(void)
{
- return ir_register_map(&imon_mce_map);
+ return rc_map_register(&imon_mce_map);
}
static void __exit exit_rc_map_imon_mce(void)
{
- ir_unregister_map(&imon_mce_map);
+ rc_map_unregister(&imon_mce_map);
}
module_init(init_rc_map_imon_mce)
diff --git a/drivers/media/IR/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
index bc4db72f02e6..eef46b73ca7b 100644
--- a/drivers/media/IR/keymaps/rc-imon-pad.c
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -17,7 +17,7 @@
* same remote to different hex codes, and the silkscreened names
* vary a bit between the SoundGraph and Antec remotes... ugh.
*/
-static struct ir_scancode imon_pad[] = {
+static struct rc_map_table imon_pad[] = {
/* keys sorted mostly by frequency of use to optimize lookups */
{ 0x2a8195b7, KEY_REWIND },
{ 0x298315b7, KEY_REWIND },
@@ -129,24 +129,24 @@ static struct ir_scancode imon_pad[] = {
{ 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
};
-static struct rc_keymap imon_pad_map = {
+static struct rc_map_list imon_pad_map = {
.map = {
.scan = imon_pad,
.size = ARRAY_SIZE(imon_pad),
/* actual protocol details unknown, hardware decoder */
- .ir_type = IR_TYPE_OTHER,
+ .rc_type = RC_TYPE_OTHER,
.name = RC_MAP_IMON_PAD,
}
};
static int __init init_rc_map_imon_pad(void)
{
- return ir_register_map(&imon_pad_map);
+ return rc_map_register(&imon_pad_map);
}
static void __exit exit_rc_map_imon_pad(void)
{
- ir_unregister_map(&imon_pad_map);
+ rc_map_unregister(&imon_pad_map);
}
module_init(init_rc_map_imon_pad)
diff --git a/drivers/media/IR/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
index ef6600259fc0..1f59e163f75d 100644
--- a/drivers/media/IR/keymaps/rc-iodata-bctv7e.c
+++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
@@ -14,7 +14,7 @@
/* IO-DATA BCTV7E Remote */
-static struct ir_scancode iodata_bctv7e[] = {
+static struct rc_map_table iodata_bctv7e[] = {
{ 0x40, KEY_TV },
{ 0x20, KEY_RADIO }, /* FM */
{ 0x60, KEY_EPG },
@@ -62,23 +62,23 @@ static struct ir_scancode iodata_bctv7e[] = {
{ 0x01, KEY_NEXT }, /* skip >| */
};
-static struct rc_keymap iodata_bctv7e_map = {
+static struct rc_map_list iodata_bctv7e_map = {
.map = {
.scan = iodata_bctv7e,
.size = ARRAY_SIZE(iodata_bctv7e),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_IODATA_BCTV7E,
}
};
static int __init init_rc_map_iodata_bctv7e(void)
{
- return ir_register_map(&iodata_bctv7e_map);
+ return rc_map_register(&iodata_bctv7e_map);
}
static void __exit exit_rc_map_iodata_bctv7e(void)
{
- ir_unregister_map(&iodata_bctv7e_map);
+ rc_map_unregister(&iodata_bctv7e_map);
}
module_init(init_rc_map_iodata_bctv7e)
diff --git a/drivers/media/IR/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c
index 4c7883ba0f15..f31dc5c1ad9c 100644
--- a/drivers/media/IR/keymaps/rc-kaiomy.c
+++ b/drivers/media/rc/keymaps/rc-kaiomy.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode kaiomy[] = {
+static struct rc_map_table kaiomy[] = {
{ 0x43, KEY_POWER2},
{ 0x01, KEY_LIST},
{ 0x0b, KEY_ZOOM},
@@ -61,23 +61,23 @@ static struct ir_scancode kaiomy[] = {
{ 0x1f, KEY_BLUE},
};
-static struct rc_keymap kaiomy_map = {
+static struct rc_map_list kaiomy_map = {
.map = {
.scan = kaiomy,
.size = ARRAY_SIZE(kaiomy),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_KAIOMY,
}
};
static int __init init_rc_map_kaiomy(void)
{
- return ir_register_map(&kaiomy_map);
+ return rc_map_register(&kaiomy_map);
}
static void __exit exit_rc_map_kaiomy(void)
{
- ir_unregister_map(&kaiomy_map);
+ rc_map_unregister(&kaiomy_map);
}
module_init(init_rc_map_kaiomy)
diff --git a/drivers/media/IR/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c
index 618c817374e6..3ce6ef79fc34 100644
--- a/drivers/media/IR/keymaps/rc-kworld-315u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-315u.c
@@ -15,7 +15,7 @@
/* Kworld 315U
*/
-static struct ir_scancode kworld_315u[] = {
+static struct rc_map_table kworld_315u[] = {
{ 0x6143, KEY_POWER },
{ 0x6101, KEY_TUNER }, /* source */
{ 0x610b, KEY_ZOOM },
@@ -57,23 +57,23 @@ static struct ir_scancode kworld_315u[] = {
{ 0x611f, KEY_BLUE },
};
-static struct rc_keymap kworld_315u_map = {
+static struct rc_map_list kworld_315u_map = {
.map = {
.scan = kworld_315u,
.size = ARRAY_SIZE(kworld_315u),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_KWORLD_315U,
}
};
static int __init init_rc_map_kworld_315u(void)
{
- return ir_register_map(&kworld_315u_map);
+ return rc_map_register(&kworld_315u_map);
}
static void __exit exit_rc_map_kworld_315u(void)
{
- ir_unregister_map(&kworld_315u_map);
+ rc_map_unregister(&kworld_315u_map);
}
module_init(init_rc_map_kworld_315u)
diff --git a/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
index 366732f1f7b7..e45f0b8759d0 100644
--- a/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode kworld_plus_tv_analog[] = {
+static struct rc_map_table kworld_plus_tv_analog[] = {
{ 0x0c, KEY_PROG1 }, /* Kworld key */
{ 0x16, KEY_CLOSECD }, /* -> ) */
{ 0x1d, KEY_POWER2 },
@@ -73,23 +73,23 @@ static struct ir_scancode kworld_plus_tv_analog[] = {
{ 0x23, KEY_GREEN}, /* C */
};
-static struct rc_keymap kworld_plus_tv_analog_map = {
+static struct rc_map_list kworld_plus_tv_analog_map = {
.map = {
.scan = kworld_plus_tv_analog,
.size = ARRAY_SIZE(kworld_plus_tv_analog),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_KWORLD_PLUS_TV_ANALOG,
}
};
static int __init init_rc_map_kworld_plus_tv_analog(void)
{
- return ir_register_map(&kworld_plus_tv_analog_map);
+ return rc_map_register(&kworld_plus_tv_analog_map);
}
static void __exit exit_rc_map_kworld_plus_tv_analog(void)
{
- ir_unregister_map(&kworld_plus_tv_analog_map);
+ rc_map_unregister(&kworld_plus_tv_analog_map);
}
module_init(init_rc_map_kworld_plus_tv_analog)
diff --git a/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
index 7521315fd876..8faa54ff16e6 100644
--- a/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c
+++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
@@ -20,7 +20,7 @@
#include <media/rc-map.h>
-static struct ir_scancode leadtek_y04g0051[] = {
+static struct rc_map_table leadtek_y04g0051[] = {
{ 0x0300, KEY_POWER2 },
{ 0x0303, KEY_SCREEN },
{ 0x0304, KEY_RIGHT },
@@ -73,23 +73,23 @@ static struct ir_scancode leadtek_y04g0051[] = {
{ 0x035f, KEY_CHANNELDOWN },
};
-static struct rc_keymap leadtek_y04g0051_map = {
+static struct rc_map_list leadtek_y04g0051_map = {
.map = {
.scan = leadtek_y04g0051,
.size = ARRAY_SIZE(leadtek_y04g0051),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_LEADTEK_Y04G0051,
}
};
static int __init init_rc_map_leadtek_y04g0051(void)
{
- return ir_register_map(&leadtek_y04g0051_map);
+ return rc_map_register(&leadtek_y04g0051_map);
}
static void __exit exit_rc_map_leadtek_y04g0051(void)
{
- ir_unregister_map(&leadtek_y04g0051_map);
+ rc_map_unregister(&leadtek_y04g0051_map);
}
module_init(init_rc_map_leadtek_y04g0051)
diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c
index 43fcf9035082..e8e23e233c39 100644
--- a/drivers/media/IR/keymaps/rc-lirc.c
+++ b/drivers/media/rc/keymaps/rc-lirc.c
@@ -9,29 +9,29 @@
* (at your option) any later version.
*/
-#include <media/ir-core.h>
+#include <media/rc-core.h>
-static struct ir_scancode lirc[] = {
+static struct rc_map_table lirc[] = {
{ },
};
-static struct rc_keymap lirc_map = {
+static struct rc_map_list lirc_map = {
.map = {
.scan = lirc,
.size = ARRAY_SIZE(lirc),
- .ir_type = IR_TYPE_LIRC,
+ .rc_type = RC_TYPE_LIRC,
.name = RC_MAP_LIRC,
}
};
static int __init init_rc_map_lirc(void)
{
- return ir_register_map(&lirc_map);
+ return rc_map_register(&lirc_map);
}
static void __exit exit_rc_map_lirc(void)
{
- ir_unregister_map(&lirc_map);
+ rc_map_unregister(&lirc_map);
}
module_init(init_rc_map_lirc)
diff --git a/drivers/media/IR/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
index 40dcf0b4e21a..875cd81477c7 100644
--- a/drivers/media/IR/keymaps/rc-lme2510.c
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode lme2510_rc[] = {
+static struct rc_map_table lme2510_rc[] = {
{ 0xba45, KEY_0 },
{ 0xa05f, KEY_1 },
{ 0xaf50, KEY_2 },
@@ -42,23 +42,23 @@ static struct ir_scancode lme2510_rc[] = {
};
-static struct rc_keymap lme2510_map = {
+static struct rc_map_list lme2510_map = {
.map = {
.scan = lme2510_rc,
.size = ARRAY_SIZE(lme2510_rc),
- .ir_type = IR_TYPE_UNKNOWN,
+ .rc_type = RC_TYPE_UNKNOWN,
.name = RC_MAP_LME2510,
}
};
static int __init init_rc_lme2510_map(void)
{
- return ir_register_map(&lme2510_map);
+ return rc_map_register(&lme2510_map);
}
static void __exit exit_rc_lme2510_map(void)
{
- ir_unregister_map(&lme2510_map);
+ rc_map_unregister(&lme2510_map);
}
module_init(init_rc_lme2510_map)
diff --git a/drivers/media/IR/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c
index 0f590b3d01c0..23b2d04e7a9f 100644
--- a/drivers/media/IR/keymaps/rc-manli.c
+++ b/drivers/media/rc/keymaps/rc-manli.c
@@ -21,7 +21,7 @@
helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode manli[] = {
+static struct rc_map_table manli[] = {
/* 0x1c 0x12 *
* FUNCTION POWER *
@@ -108,23 +108,23 @@ static struct ir_scancode manli[] = {
/* 0x1d unused ? */
};
-static struct rc_keymap manli_map = {
+static struct rc_map_list manli_map = {
.map = {
.scan = manli,
.size = ARRAY_SIZE(manli),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MANLI,
}
};
static int __init init_rc_map_manli(void)
{
- return ir_register_map(&manli_map);
+ return rc_map_register(&manli_map);
}
static void __exit exit_rc_map_manli(void)
{
- ir_unregister_map(&manli_map);
+ rc_map_unregister(&manli_map);
}
module_init(init_rc_map_manli)
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
index 67237fbf9e4b..7b9a01b6e4cf 100644
--- a/drivers/media/IR/keymaps/rc-msi-digivox-ii.c
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
@@ -20,7 +20,7 @@
#include <media/rc-map.h>
-static struct ir_scancode msi_digivox_ii[] = {
+static struct rc_map_table msi_digivox_ii[] = {
{ 0x0002, KEY_2 },
{ 0x0003, KEY_UP }, /* up */
{ 0x0004, KEY_3 },
@@ -41,23 +41,23 @@ static struct ir_scancode msi_digivox_ii[] = {
{ 0x001f, KEY_VOLUMEDOWN },
};
-static struct rc_keymap msi_digivox_ii_map = {
+static struct rc_map_list msi_digivox_ii_map = {
.map = {
.scan = msi_digivox_ii,
.size = ARRAY_SIZE(msi_digivox_ii),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_MSI_DIGIVOX_II,
}
};
static int __init init_rc_map_msi_digivox_ii(void)
{
- return ir_register_map(&msi_digivox_ii_map);
+ return rc_map_register(&msi_digivox_ii_map);
}
static void __exit exit_rc_map_msi_digivox_ii(void)
{
- ir_unregister_map(&msi_digivox_ii_map);
+ rc_map_unregister(&msi_digivox_ii_map);
}
module_init(init_rc_map_msi_digivox_ii)
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
index 882056e52ef9..ae9d06b39157 100644
--- a/drivers/media/IR/keymaps/rc-msi-digivox-iii.c
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
@@ -24,7 +24,7 @@
/* Uses NEC extended 0x61d6. */
/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
since rc-kworld-315u.c lacks NEC extended address byte. */
-static struct ir_scancode msi_digivox_iii[] = {
+static struct rc_map_table msi_digivox_iii[] = {
{ 0x61d601, KEY_VIDEO }, /* Source */
{ 0x61d602, KEY_3 },
{ 0x61d603, KEY_POWER }, /* ShutDown */
@@ -59,23 +59,23 @@ static struct ir_scancode msi_digivox_iii[] = {
{ 0x61d643, KEY_POWER2 }, /* [red power button] */
};
-static struct rc_keymap msi_digivox_iii_map = {
+static struct rc_map_list msi_digivox_iii_map = {
.map = {
.scan = msi_digivox_iii,
.size = ARRAY_SIZE(msi_digivox_iii),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_MSI_DIGIVOX_III,
}
};
static int __init init_rc_map_msi_digivox_iii(void)
{
- return ir_register_map(&msi_digivox_iii_map);
+ return rc_map_register(&msi_digivox_iii_map);
}
static void __exit exit_rc_map_msi_digivox_iii(void)
{
- ir_unregister_map(&msi_digivox_iii_map);
+ rc_map_unregister(&msi_digivox_iii_map);
}
module_init(init_rc_map_msi_digivox_iii)
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
index eb8e42c18ff9..fa8fd0ab94c7 100644
--- a/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
@@ -26,7 +26,7 @@
Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
*/
-static struct ir_scancode msi_tvanywhere_plus[] = {
+static struct rc_map_table msi_tvanywhere_plus[] = {
/* ---- Remote Button Layout ----
@@ -97,23 +97,23 @@ static struct ir_scancode msi_tvanywhere_plus[] = {
{ 0x1d, KEY_RESTART }, /* Reset */
};
-static struct rc_keymap msi_tvanywhere_plus_map = {
+static struct rc_map_list msi_tvanywhere_plus_map = {
.map = {
.scan = msi_tvanywhere_plus,
.size = ARRAY_SIZE(msi_tvanywhere_plus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MSI_TVANYWHERE_PLUS,
}
};
static int __init init_rc_map_msi_tvanywhere_plus(void)
{
- return ir_register_map(&msi_tvanywhere_plus_map);
+ return rc_map_register(&msi_tvanywhere_plus_map);
}
static void __exit exit_rc_map_msi_tvanywhere_plus(void)
{
- ir_unregister_map(&msi_tvanywhere_plus_map);
+ rc_map_unregister(&msi_tvanywhere_plus_map);
}
module_init(init_rc_map_msi_tvanywhere_plus)
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
index ef411854f067..18b37facb0dd 100644
--- a/drivers/media/IR/keymaps/rc-msi-tvanywhere.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
@@ -14,7 +14,7 @@
/* MSI TV@nywhere MASTER remote */
-static struct ir_scancode msi_tvanywhere[] = {
+static struct rc_map_table msi_tvanywhere[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -43,23 +43,23 @@ static struct ir_scancode msi_tvanywhere[] = {
{ 0x1f, KEY_VOLUMEDOWN },
};
-static struct rc_keymap msi_tvanywhere_map = {
+static struct rc_map_list msi_tvanywhere_map = {
.map = {
.scan = msi_tvanywhere,
.size = ARRAY_SIZE(msi_tvanywhere),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MSI_TVANYWHERE,
}
};
static int __init init_rc_map_msi_tvanywhere(void)
{
- return ir_register_map(&msi_tvanywhere_map);
+ return rc_map_register(&msi_tvanywhere_map);
}
static void __exit exit_rc_map_msi_tvanywhere(void)
{
- ir_unregister_map(&msi_tvanywhere_map);
+ rc_map_unregister(&msi_tvanywhere_map);
}
module_init(init_rc_map_msi_tvanywhere)
diff --git a/drivers/media/IR/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index ccc50eb402ec..3e6f077eb700 100644
--- a/drivers/media/IR/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode nebula[] = {
+static struct rc_map_table nebula[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -70,23 +70,23 @@ static struct ir_scancode nebula[] = {
{ 0x36, KEY_PC },
};
-static struct rc_keymap nebula_map = {
+static struct rc_map_list nebula_map = {
.map = {
.scan = nebula,
.size = ARRAY_SIZE(nebula),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NEBULA,
}
};
static int __init init_rc_map_nebula(void)
{
- return ir_register_map(&nebula_map);
+ return rc_map_register(&nebula_map);
}
static void __exit exit_rc_map_nebula(void)
{
- ir_unregister_map(&nebula_map);
+ rc_map_unregister(&nebula_map);
}
module_init(init_rc_map_nebula)
diff --git a/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index e1b54d20db60..26f114c5c0de 100644
--- a/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@redhat.com>
*/
-static struct ir_scancode nec_terratec_cinergy_xs[] = {
+static struct rc_map_table nec_terratec_cinergy_xs[] = {
{ 0x1441, KEY_HOME},
{ 0x1401, KEY_POWER2},
@@ -79,23 +79,23 @@ static struct ir_scancode nec_terratec_cinergy_xs[] = {
{ 0x145c, KEY_NEXT},
};
-static struct rc_keymap nec_terratec_cinergy_xs_map = {
+static struct rc_map_list nec_terratec_cinergy_xs_map = {
.map = {
.scan = nec_terratec_cinergy_xs,
.size = ARRAY_SIZE(nec_terratec_cinergy_xs),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_NEC_TERRATEC_CINERGY_XS,
}
};
static int __init init_rc_map_nec_terratec_cinergy_xs(void)
{
- return ir_register_map(&nec_terratec_cinergy_xs_map);
+ return rc_map_register(&nec_terratec_cinergy_xs_map);
}
static void __exit exit_rc_map_nec_terratec_cinergy_xs(void)
{
- ir_unregister_map(&nec_terratec_cinergy_xs_map);
+ rc_map_unregister(&nec_terratec_cinergy_xs_map);
}
module_init(init_rc_map_nec_terratec_cinergy_xs)
diff --git a/drivers/media/IR/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c
index e5849a6b3f05..629ee9d84537 100644
--- a/drivers/media/IR/keymaps/rc-norwood.c
+++ b/drivers/media/rc/keymaps/rc-norwood.c
@@ -16,7 +16,7 @@
By Peter Naulls <peter@chocky.org>
Key comments are the functions given in the manual */
-static struct ir_scancode norwood[] = {
+static struct rc_map_table norwood[] = {
/* Keys 0 to 9 */
{ 0x20, KEY_0 },
{ 0x21, KEY_1 },
@@ -59,23 +59,23 @@ static struct ir_scancode norwood[] = {
{ 0x65, KEY_POWER }, /* Computer power */
};
-static struct rc_keymap norwood_map = {
+static struct rc_map_list norwood_map = {
.map = {
.scan = norwood,
.size = ARRAY_SIZE(norwood),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NORWOOD,
}
};
static int __init init_rc_map_norwood(void)
{
- return ir_register_map(&norwood_map);
+ return rc_map_register(&norwood_map);
}
static void __exit exit_rc_map_norwood(void)
{
- ir_unregister_map(&norwood_map);
+ rc_map_unregister(&norwood_map);
}
module_init(init_rc_map_norwood)
diff --git a/drivers/media/IR/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c
index b9ece1e90296..4aa588bf6d69 100644
--- a/drivers/media/IR/keymaps/rc-npgtech.c
+++ b/drivers/media/rc/keymaps/rc-npgtech.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode npgtech[] = {
+static struct rc_map_table npgtech[] = {
{ 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x2a, KEY_FRONT },
@@ -54,23 +54,23 @@ static struct ir_scancode npgtech[] = {
};
-static struct rc_keymap npgtech_map = {
+static struct rc_map_list npgtech_map = {
.map = {
.scan = npgtech,
.size = ARRAY_SIZE(npgtech),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NPGTECH,
}
};
static int __init init_rc_map_npgtech(void)
{
- return ir_register_map(&npgtech_map);
+ return rc_map_register(&npgtech_map);
}
static void __exit exit_rc_map_npgtech(void)
{
- ir_unregister_map(&npgtech_map);
+ rc_map_unregister(&npgtech_map);
}
module_init(init_rc_map_npgtech)
diff --git a/drivers/media/IR/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c
index 4129bb44a25b..fa5ae5981eb8 100644
--- a/drivers/media/IR/keymaps/rc-pctv-sedna.c
+++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c
@@ -17,7 +17,7 @@
Pavel Mihaylov <bin@bash.info>
Also for the remote bundled with Kozumi KTV-01C card */
-static struct ir_scancode pctv_sedna[] = {
+static struct rc_map_table pctv_sedna[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -54,23 +54,23 @@ static struct ir_scancode pctv_sedna[] = {
{ 0x1f, KEY_PLAY }, /* Play */
};
-static struct rc_keymap pctv_sedna_map = {
+static struct rc_map_list pctv_sedna_map = {
.map = {
.scan = pctv_sedna,
.size = ARRAY_SIZE(pctv_sedna),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PCTV_SEDNA,
}
};
static int __init init_rc_map_pctv_sedna(void)
{
- return ir_register_map(&pctv_sedna_map);
+ return rc_map_register(&pctv_sedna_map);
}
static void __exit exit_rc_map_pctv_sedna(void)
{
- ir_unregister_map(&pctv_sedna_map);
+ rc_map_unregister(&pctv_sedna_map);
}
module_init(init_rc_map_pctv_sedna)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c
index 326e023ce126..23b8c505c6aa 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-color.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pinnacle_color[] = {
+static struct rc_map_table pinnacle_color[] = {
{ 0x59, KEY_MUTE },
{ 0x4a, KEY_POWER },
@@ -68,23 +68,23 @@ static struct ir_scancode pinnacle_color[] = {
{ 0x0a, KEY_BACKSPACE },
};
-static struct rc_keymap pinnacle_color_map = {
+static struct rc_map_list pinnacle_color_map = {
.map = {
.scan = pinnacle_color,
.size = ARRAY_SIZE(pinnacle_color),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_COLOR,
}
};
static int __init init_rc_map_pinnacle_color(void)
{
- return ir_register_map(&pinnacle_color_map);
+ return rc_map_register(&pinnacle_color_map);
}
static void __exit exit_rc_map_pinnacle_color(void)
{
- ir_unregister_map(&pinnacle_color_map);
+ rc_map_unregister(&pinnacle_color_map);
}
module_init(init_rc_map_pinnacle_color)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
index 14cb772515c6..6ba8c368d10a 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-grey.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pinnacle_grey[] = {
+static struct rc_map_table pinnacle_grey[] = {
{ 0x3a, KEY_0 },
{ 0x31, KEY_1 },
{ 0x32, KEY_2 },
@@ -63,23 +63,23 @@ static struct ir_scancode pinnacle_grey[] = {
{ 0x18, KEY_EPG },
};
-static struct rc_keymap pinnacle_grey_map = {
+static struct rc_map_list pinnacle_grey_map = {
.map = {
.scan = pinnacle_grey,
.size = ARRAY_SIZE(pinnacle_grey),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_GREY,
}
};
static int __init init_rc_map_pinnacle_grey(void)
{
- return ir_register_map(&pinnacle_grey_map);
+ return rc_map_register(&pinnacle_grey_map);
}
static void __exit exit_rc_map_pinnacle_grey(void)
{
- ir_unregister_map(&pinnacle_grey_map);
+ rc_map_unregister(&pinnacle_grey_map);
}
module_init(init_rc_map_pinnacle_grey)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
index 835bf4ef8de7..bb10ffe086b4 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -14,7 +14,7 @@
/* Pinnacle PCTV HD 800i mini remote */
-static struct ir_scancode pinnacle_pctv_hd[] = {
+static struct rc_map_table pinnacle_pctv_hd[] = {
{ 0x0f, KEY_1 },
{ 0x15, KEY_2 },
@@ -47,23 +47,23 @@ static struct ir_scancode pinnacle_pctv_hd[] = {
{ 0x3f, KEY_EPG }, /* Labeled "?" */
};
-static struct rc_keymap pinnacle_pctv_hd_map = {
+static struct rc_map_list pinnacle_pctv_hd_map = {
.map = {
.scan = pinnacle_pctv_hd,
.size = ARRAY_SIZE(pinnacle_pctv_hd),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_PCTV_HD,
}
};
static int __init init_rc_map_pinnacle_pctv_hd(void)
{
- return ir_register_map(&pinnacle_pctv_hd_map);
+ return rc_map_register(&pinnacle_pctv_hd_map);
}
static void __exit exit_rc_map_pinnacle_pctv_hd(void)
{
- ir_unregister_map(&pinnacle_pctv_hd_map);
+ rc_map_unregister(&pinnacle_pctv_hd_map);
}
module_init(init_rc_map_pinnacle_pctv_hd)
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
new file mode 100644
index 000000000000..e5ab071f635a
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -0,0 +1,77 @@
+/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Keytable for 002-T IR remote provided together with Pixelview
+ * SBTVD Hybrid Remote Controller. Uses NEC extended format.
+ */
+static struct rc_map_table pixelview_002t[] = {
+ { 0x866b13, KEY_MUTE },
+ { 0x866b12, KEY_POWER2 }, /* power */
+
+ { 0x866b01, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
+ { 0x866b00, KEY_0 },
+
+ { 0x866b0d, KEY_CHANNELUP },
+ { 0x866b19, KEY_CHANNELDOWN },
+ { 0x866b10, KEY_VOLUMEUP }, /* vol + */
+ { 0x866b0c, KEY_VOLUMEDOWN }, /* vol - */
+
+ { 0x866b0a, KEY_CAMERA }, /* snapshot */
+ { 0x866b0b, KEY_ZOOM }, /* zoom */
+
+ { 0x866b1b, KEY_BACKSPACE },
+ { 0x866b15, KEY_ENTER },
+
+ { 0x866b1d, KEY_UP },
+ { 0x866b1e, KEY_DOWN },
+ { 0x866b0e, KEY_LEFT },
+ { 0x866b0f, KEY_RIGHT },
+
+ { 0x866b18, KEY_RECORD },
+ { 0x866b1a, KEY_STOP },
+};
+
+static struct rc_map_list pixelview_map = {
+ .map = {
+ .scan = pixelview_002t,
+ .size = ARRAY_SIZE(pixelview_002t),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_PIXELVIEW_002T,
+ }
+};
+
+static int __init init_rc_map_pixelview(void)
+{
+ return rc_map_register(&pixelview_map);
+}
+
+static void __exit exit_rc_map_pixelview(void)
+{
+ rc_map_unregister(&pixelview_map);
+}
+
+module_init(init_rc_map_pixelview)
+module_exit(exit_rc_map_pixelview)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
index 5a735d569a8b..8d9f664e0a2d 100644
--- a/drivers/media/IR/keymaps/rc-pixelview-mk12.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -16,7 +16,7 @@
* Keytable for MK-F12 IR remote provided together with Pixelview
* Ultra Pro Remote Controller. Uses NEC extended format.
*/
-static struct ir_scancode pixelview_mk12[] = {
+static struct rc_map_table pixelview_mk12[] = {
{ 0x866b03, KEY_TUNER }, /* Timeshift */
{ 0x866b1e, KEY_POWER2 }, /* power */
@@ -57,23 +57,23 @@ static struct ir_scancode pixelview_mk12[] = {
{ 0x866b07, KEY_RADIO }, /* FM */
};
-static struct rc_keymap pixelview_map = {
+static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview_mk12,
.size = ARRAY_SIZE(pixelview_mk12),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_PIXELVIEW_MK12,
}
};
static int __init init_rc_map_pixelview(void)
{
- return ir_register_map(&pixelview_map);
+ return rc_map_register(&pixelview_map);
}
static void __exit exit_rc_map_pixelview(void)
{
- ir_unregister_map(&pixelview_map);
+ rc_map_unregister(&pixelview_map);
}
module_init(init_rc_map_pixelview)
diff --git a/drivers/media/IR/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c
index 7bbbbf5735e6..777a70076be2 100644
--- a/drivers/media/IR/keymaps/rc-pixelview-new.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-new.c
@@ -17,7 +17,7 @@
present on PV MPEG 8000GT
*/
-static struct ir_scancode pixelview_new[] = {
+static struct rc_map_table pixelview_new[] = {
{ 0x3c, KEY_TIME }, /* Timeshift */
{ 0x12, KEY_POWER },
@@ -57,23 +57,23 @@ static struct ir_scancode pixelview_new[] = {
{ 0x34, KEY_RADIO },
};
-static struct rc_keymap pixelview_new_map = {
+static struct rc_map_list pixelview_new_map = {
.map = {
.scan = pixelview_new,
.size = ARRAY_SIZE(pixelview_new),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PIXELVIEW_NEW,
}
};
static int __init init_rc_map_pixelview_new(void)
{
- return ir_register_map(&pixelview_new_map);
+ return rc_map_register(&pixelview_new_map);
}
static void __exit exit_rc_map_pixelview_new(void)
{
- ir_unregister_map(&pixelview_new_map);
+ rc_map_unregister(&pixelview_new_map);
}
module_init(init_rc_map_pixelview_new)
diff --git a/drivers/media/IR/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c
index 82ff12e182a0..0ec5988916b9 100644
--- a/drivers/media/IR/keymaps/rc-pixelview.c
+++ b/drivers/media/rc/keymaps/rc-pixelview.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pixelview[] = {
+static struct rc_map_table pixelview[] = {
{ 0x1e, KEY_POWER }, /* power */
{ 0x07, KEY_MEDIA }, /* source */
@@ -56,23 +56,23 @@ static struct ir_scancode pixelview[] = {
{ 0x18, KEY_MUTE }, /* mute/unmute */
};
-static struct rc_keymap pixelview_map = {
+static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview,
.size = ARRAY_SIZE(pixelview),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PIXELVIEW,
}
};
static int __init init_rc_map_pixelview(void)
{
- return ir_register_map(&pixelview_map);
+ return rc_map_register(&pixelview_map);
}
static void __exit exit_rc_map_pixelview(void)
{
- ir_unregister_map(&pixelview_map);
+ rc_map_unregister(&pixelview_map);
}
module_init(init_rc_map_pixelview)
diff --git a/drivers/media/IR/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
index 7cef8190a224..5f9d546a86c4 100644
--- a/drivers/media/IR/keymaps/rc-powercolor-real-angel.c
+++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
@@ -17,7 +17,7 @@
* Daniel Fraga <fragabr@gmail.com>
*/
-static struct ir_scancode powercolor_real_angel[] = {
+static struct rc_map_table powercolor_real_angel[] = {
{ 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */
{ 0x00, KEY_0 },
@@ -55,23 +55,23 @@ static struct ir_scancode powercolor_real_angel[] = {
{ 0x25, KEY_POWER }, /* power */
};
-static struct rc_keymap powercolor_real_angel_map = {
+static struct rc_map_list powercolor_real_angel_map = {
.map = {
.scan = powercolor_real_angel,
.size = ARRAY_SIZE(powercolor_real_angel),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_POWERCOLOR_REAL_ANGEL,
}
};
static int __init init_rc_map_powercolor_real_angel(void)
{
- return ir_register_map(&powercolor_real_angel_map);
+ return rc_map_register(&powercolor_real_angel_map);
}
static void __exit exit_rc_map_powercolor_real_angel(void)
{
- ir_unregister_map(&powercolor_real_angel_map);
+ rc_map_unregister(&powercolor_real_angel_map);
}
module_init(init_rc_map_powercolor_real_angel)
diff --git a/drivers/media/IR/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c
index 22e92d39dee5..8a3a643879d4 100644
--- a/drivers/media/IR/keymaps/rc-proteus-2309.c
+++ b/drivers/media/rc/keymaps/rc-proteus-2309.c
@@ -14,7 +14,7 @@
/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-static struct ir_scancode proteus_2309[] = {
+static struct rc_map_table proteus_2309[] = {
/* numeric */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -43,23 +43,23 @@ static struct ir_scancode proteus_2309[] = {
{ 0x14, KEY_F1 },
};
-static struct rc_keymap proteus_2309_map = {
+static struct rc_map_list proteus_2309_map = {
.map = {
.scan = proteus_2309,
.size = ARRAY_SIZE(proteus_2309),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PROTEUS_2309,
}
};
static int __init init_rc_map_proteus_2309(void)
{
- return ir_register_map(&proteus_2309_map);
+ return rc_map_register(&proteus_2309_map);
}
static void __exit exit_rc_map_proteus_2309(void)
{
- ir_unregister_map(&proteus_2309_map);
+ rc_map_unregister(&proteus_2309_map);
}
module_init(init_rc_map_proteus_2309)
diff --git a/drivers/media/IR/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c
index 4e20fc2269f7..ef90296bfd68 100644
--- a/drivers/media/IR/keymaps/rc-purpletv.c
+++ b/drivers/media/rc/keymaps/rc-purpletv.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode purpletv[] = {
+static struct rc_map_table purpletv[] = {
{ 0x03, KEY_POWER },
{ 0x6f, KEY_MUTE },
{ 0x10, KEY_BACKSPACE }, /* Recall */
@@ -55,23 +55,23 @@ static struct ir_scancode purpletv[] = {
};
-static struct rc_keymap purpletv_map = {
+static struct rc_map_list purpletv_map = {
.map = {
.scan = purpletv,
.size = ARRAY_SIZE(purpletv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PURPLETV,
}
};
static int __init init_rc_map_purpletv(void)
{
- return ir_register_map(&purpletv_map);
+ return rc_map_register(&purpletv_map);
}
static void __exit exit_rc_map_purpletv(void)
{
- ir_unregister_map(&purpletv_map);
+ rc_map_unregister(&purpletv_map);
}
module_init(init_rc_map_purpletv)
diff --git a/drivers/media/IR/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c
index 36679e706cf3..83a418de12c6 100644
--- a/drivers/media/IR/keymaps/rc-pv951.c
+++ b/drivers/media/rc/keymaps/rc-pv951.c
@@ -14,7 +14,7 @@
/* Mark Phalan <phalanm@o2.ie> */
-static struct ir_scancode pv951[] = {
+static struct rc_map_table pv951[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -52,23 +52,23 @@ static struct ir_scancode pv951[] = {
{ 0x1c, KEY_MEDIA }, /* PC/TV */
};
-static struct rc_keymap pv951_map = {
+static struct rc_map_list pv951_map = {
.map = {
.scan = pv951,
.size = ARRAY_SIZE(pv951),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PV951,
}
};
static int __init init_rc_map_pv951(void)
{
- return ir_register_map(&pv951_map);
+ return rc_map_register(&pv951_map);
}
static void __exit exit_rc_map_pv951(void)
{
- ir_unregister_map(&pv951_map);
+ rc_map_unregister(&pv951_map);
}
module_init(init_rc_map_pv951)
diff --git a/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
index cc6b8f548747..dfc9b15f43a9 100644
--- a/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c
+++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
@@ -19,7 +19,7 @@
* This table contains the complete RC5 code, instead of just the data part
*/
-static struct ir_scancode rc5_hauppauge_new[] = {
+static struct rc_map_table rc5_hauppauge_new[] = {
/* Keys 0 to 9 */
{ 0x1e00, KEY_0 },
{ 0x1e01, KEY_1 },
@@ -75,25 +75,63 @@ static struct ir_scancode rc5_hauppauge_new[] = {
{ 0x1e3b, KEY_SELECT }, /* top right button */
{ 0x1e3c, KEY_ZOOM }, /* full */
{ 0x1e3d, KEY_POWER }, /* system power (green button) */
+
+ /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */
+ { 0x1d00, KEY_0 },
+ { 0x1d01, KEY_1 },
+ { 0x1d02, KEY_2 },
+ { 0x1d03, KEY_3 },
+ { 0x1d04, KEY_4 },
+ { 0x1d05, KEY_5 },
+ { 0x1d06, KEY_6 },
+ { 0x1d07, KEY_7 },
+ { 0x1d08, KEY_8 },
+ { 0x1d09, KEY_9 },
+ { 0x1d0a, KEY_TEXT },
+ { 0x1d0d, KEY_MENU },
+ { 0x1d0f, KEY_MUTE },
+ { 0x1d10, KEY_VOLUMEUP },
+ { 0x1d11, KEY_VOLUMEDOWN },
+ { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */
+ { 0x1d14, KEY_UP },
+ { 0x1d15, KEY_DOWN },
+ { 0x1d16, KEY_LEFT },
+ { 0x1d17, KEY_RIGHT },
+ { 0x1d1c, KEY_TV },
+ { 0x1d1e, KEY_NEXT }, /* >| */
+ { 0x1d1f, KEY_EXIT },
+ { 0x1d20, KEY_CHANNELUP },
+ { 0x1d21, KEY_CHANNELDOWN },
+ { 0x1d24, KEY_LAST }, /* <| */
+ { 0x1d25, KEY_OK },
+ { 0x1d30, KEY_PAUSE },
+ { 0x1d32, KEY_REWIND },
+ { 0x1d34, KEY_FASTFORWARD },
+ { 0x1d35, KEY_PLAY },
+ { 0x1d36, KEY_STOP },
+ { 0x1d37, KEY_RECORD },
+ { 0x1d3b, KEY_GOTO },
+ { 0x1d3d, KEY_POWER },
+ { 0x1d3f, KEY_HOME },
};
-static struct rc_keymap rc5_hauppauge_new_map = {
+static struct rc_map_list rc5_hauppauge_new_map = {
.map = {
.scan = rc5_hauppauge_new,
.size = ARRAY_SIZE(rc5_hauppauge_new),
- .ir_type = IR_TYPE_RC5,
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_RC5_HAUPPAUGE_NEW,
}
};
static int __init init_rc_map_rc5_hauppauge_new(void)
{
- return ir_register_map(&rc5_hauppauge_new_map);
+ return rc_map_register(&rc5_hauppauge_new_map);
}
static void __exit exit_rc_map_rc5_hauppauge_new(void)
{
- ir_unregister_map(&rc5_hauppauge_new_map);
+ rc_map_unregister(&rc5_hauppauge_new_map);
}
module_init(init_rc_map_rc5_hauppauge_new)
diff --git a/drivers/media/IR/keymaps/rc-rc5-tv.c b/drivers/media/rc/keymaps/rc-rc5-tv.c
index 73cce2f8ddfb..4fcef9f1f721 100644
--- a/drivers/media/IR/keymaps/rc-rc5-tv.c
+++ b/drivers/media/rc/keymaps/rc-rc5-tv.c
@@ -16,7 +16,7 @@
/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
/* used by old (black) Hauppauge remotes */
-static struct ir_scancode rc5_tv[] = {
+static struct rc_map_table rc5_tv[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -55,23 +55,23 @@ static struct ir_scancode rc5_tv[] = {
};
-static struct rc_keymap rc5_tv_map = {
+static struct rc_map_list rc5_tv_map = {
.map = {
.scan = rc5_tv,
.size = ARRAY_SIZE(rc5_tv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_RC5_TV,
}
};
static int __init init_rc_map_rc5_tv(void)
{
- return ir_register_map(&rc5_tv_map);
+ return rc_map_register(&rc5_tv_map);
}
static void __exit exit_rc_map_rc5_tv(void)
{
- ir_unregister_map(&rc5_tv_map);
+ rc_map_unregister(&rc5_tv_map);
}
module_init(init_rc_map_rc5_tv)
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c
index 1b7adabbcee9..3bf3337875d1 100644
--- a/drivers/media/IR/keymaps/rc-rc6-mce.c
+++ b/drivers/media/rc/keymaps/rc-rc6-mce.c
@@ -11,7 +11,7 @@
#include <media/rc-map.h>
-static struct ir_scancode rc6_mce[] = {
+static struct rc_map_table rc6_mce[] = {
{ 0x800f0400, KEY_NUMERIC_0 },
{ 0x800f0401, KEY_NUMERIC_1 },
@@ -26,8 +26,8 @@ static struct ir_scancode rc6_mce[] = {
{ 0x800f040a, KEY_DELETE },
{ 0x800f040b, KEY_ENTER },
- { 0x800f040c, KEY_POWER },
- { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+ { 0x800f040c, KEY_POWER }, /* PC Power */
+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
{ 0x800f040e, KEY_MUTE },
{ 0x800f040f, KEY_INFO },
@@ -56,53 +56,54 @@ static struct ir_scancode rc6_mce[] = {
{ 0x800f0422, KEY_OK },
{ 0x800f0423, KEY_EXIT },
{ 0x800f0424, KEY_DVD },
- { 0x800f0425, KEY_TUNER }, /* LiveTV */
- { 0x800f0426, KEY_EPG }, /* Guide */
- { 0x800f0427, KEY_ZOOM }, /* Aspect */
+ { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f0426, KEY_EPG }, /* Guide */
+ { 0x800f0427, KEY_ZOOM }, /* Aspect */
{ 0x800f043a, KEY_BRIGHTNESSUP },
{ 0x800f0446, KEY_TV },
- { 0x800f0447, KEY_AUDIO }, /* My Music */
- { 0x800f0448, KEY_PVR }, /* RecordedTV */
+ { 0x800f0447, KEY_AUDIO }, /* My Music */
+ { 0x800f0448, KEY_PVR }, /* RecordedTV */
{ 0x800f0449, KEY_CAMERA },
{ 0x800f044a, KEY_VIDEO },
{ 0x800f044c, KEY_LANGUAGE },
{ 0x800f044d, KEY_TITLE },
- { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
+ { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
{ 0x800f0450, KEY_RADIO },
- { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
{ 0x800f045b, KEY_RED },
{ 0x800f045c, KEY_GREEN },
{ 0x800f045d, KEY_YELLOW },
{ 0x800f045e, KEY_BLUE },
+ { 0x800f0465, KEY_POWER2 }, /* TV Power */
{ 0x800f046e, KEY_PLAYPAUSE },
- { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
+ { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
{ 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0481, KEY_PLAYPAUSE },
};
-static struct rc_keymap rc6_mce_map = {
+static struct rc_map_list rc6_mce_map = {
.map = {
.scan = rc6_mce,
.size = ARRAY_SIZE(rc6_mce),
- .ir_type = IR_TYPE_RC6,
+ .rc_type = RC_TYPE_RC6,
.name = RC_MAP_RC6_MCE,
}
};
static int __init init_rc_map_rc6_mce(void)
{
- return ir_register_map(&rc6_mce_map);
+ return rc_map_register(&rc6_mce_map);
}
static void __exit exit_rc_map_rc6_mce(void)
{
- ir_unregister_map(&rc6_mce_map);
+ rc_map_unregister(&rc6_mce_map);
}
module_init(init_rc_map_rc6_mce)
diff --git a/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
index ab1a6d2baf72..2d14598592d8 100644
--- a/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c
+++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
@@ -14,7 +14,7 @@
/* Zogis Real Audio 220 - 32 keys IR */
-static struct ir_scancode real_audio_220_32_keys[] = {
+static struct rc_map_table real_audio_220_32_keys[] = {
{ 0x1c, KEY_RADIO},
{ 0x12, KEY_POWER2},
@@ -52,23 +52,23 @@ static struct ir_scancode real_audio_220_32_keys[] = {
};
-static struct rc_keymap real_audio_220_32_keys_map = {
+static struct rc_map_list real_audio_220_32_keys_map = {
.map = {
.scan = real_audio_220_32_keys,
.size = ARRAY_SIZE(real_audio_220_32_keys),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_REAL_AUDIO_220_32_KEYS,
}
};
static int __init init_rc_map_real_audio_220_32_keys(void)
{
- return ir_register_map(&real_audio_220_32_keys_map);
+ return rc_map_register(&real_audio_220_32_keys_map);
}
static void __exit exit_rc_map_real_audio_220_32_keys(void)
{
- ir_unregister_map(&real_audio_220_32_keys_map);
+ rc_map_unregister(&real_audio_220_32_keys_map);
}
module_init(init_rc_map_real_audio_220_32_keys)
diff --git a/drivers/media/IR/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
index df32013a321c..92cc10d2f9cd 100644
--- a/drivers/media/IR/keymaps/rc-streamzap.c
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -11,7 +11,7 @@
#include <media/rc-map.h>
-static struct ir_scancode streamzap[] = {
+static struct rc_map_table streamzap[] = {
/*
* The Streamzap remote is almost, but not quite, RC-5, as it has an extra
* bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
@@ -56,23 +56,23 @@ static struct ir_scancode streamzap[] = {
};
-static struct rc_keymap streamzap_map = {
+static struct rc_map_list streamzap_map = {
.map = {
.scan = streamzap,
.size = ARRAY_SIZE(streamzap),
- .ir_type = IR_TYPE_RC5_SZ,
+ .rc_type = RC_TYPE_RC5_SZ,
.name = RC_MAP_STREAMZAP,
}
};
static int __init init_rc_map_streamzap(void)
{
- return ir_register_map(&streamzap_map);
+ return rc_map_register(&streamzap_map);
}
static void __exit exit_rc_map_streamzap(void)
{
- ir_unregister_map(&streamzap_map);
+ rc_map_unregister(&streamzap_map);
}
module_init(init_rc_map_streamzap)
diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c
new file mode 100644
index 000000000000..7242ee66f6e0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tbs-nec.c
@@ -0,0 +1,75 @@
+/* tbs-nec.h - Keytable for tbs_nec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table tbs_nec[] = {
+ { 0x84, KEY_POWER2}, /* power */
+ { 0x94, KEY_MUTE}, /* mute */
+ { 0x87, KEY_1},
+ { 0x86, KEY_2},
+ { 0x85, KEY_3},
+ { 0x8b, KEY_4},
+ { 0x8a, KEY_5},
+ { 0x89, KEY_6},
+ { 0x8f, KEY_7},
+ { 0x8e, KEY_8},
+ { 0x8d, KEY_9},
+ { 0x92, KEY_0},
+ { 0xc0, KEY_10CHANNELSUP}, /* 10+ */
+ { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */
+ { 0x96, KEY_CHANNELUP}, /* ch+ */
+ { 0x91, KEY_CHANNELDOWN}, /* ch- */
+ { 0x93, KEY_VOLUMEUP}, /* vol+ */
+ { 0x8c, KEY_VOLUMEDOWN}, /* vol- */
+ { 0x83, KEY_RECORD}, /* rec */
+ { 0x98, KEY_PAUSE}, /* pause, yellow */
+ { 0x99, KEY_OK}, /* ok */
+ { 0x9a, KEY_CAMERA}, /* snapshot */
+ { 0x81, KEY_UP},
+ { 0x90, KEY_LEFT},
+ { 0x82, KEY_RIGHT},
+ { 0x88, KEY_DOWN},
+ { 0x95, KEY_FAVORITES}, /* blue */
+ { 0x97, KEY_SUBTITLE}, /* green */
+ { 0x9d, KEY_ZOOM},
+ { 0x9f, KEY_EXIT},
+ { 0x9e, KEY_MENU},
+ { 0x9c, KEY_EPG},
+ { 0x80, KEY_PREVIOUS}, /* red */
+ { 0x9b, KEY_MODE},
+};
+
+static struct rc_map_list tbs_nec_map = {
+ .map = {
+ .scan = tbs_nec,
+ .size = ARRAY_SIZE(tbs_nec),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TBS_NEC,
+ }
+};
+
+static int __init init_rc_map_tbs_nec(void)
+{
+ return rc_map_register(&tbs_nec_map);
+}
+
+static void __exit exit_rc_map_tbs_nec(void)
+{
+ rc_map_unregister(&tbs_nec_map);
+}
+
+module_init(init_rc_map_tbs_nec)
+module_exit(exit_rc_map_tbs_nec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
index 5326a0b444c1..bc38e34b9fda 100644
--- a/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
@@ -16,7 +16,7 @@
Devin Heitmueller <dheitmueller@linuxtv.org>
*/
-static struct ir_scancode terratec_cinergy_xs[] = {
+static struct rc_map_table terratec_cinergy_xs[] = {
{ 0x41, KEY_HOME},
{ 0x01, KEY_POWER},
{ 0x42, KEY_MENU},
@@ -66,23 +66,23 @@ static struct ir_scancode terratec_cinergy_xs[] = {
{ 0x5c, KEY_NEXT},
};
-static struct rc_keymap terratec_cinergy_xs_map = {
+static struct rc_map_list terratec_cinergy_xs_map = {
.map = {
.scan = terratec_cinergy_xs,
.size = ARRAY_SIZE(terratec_cinergy_xs),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TERRATEC_CINERGY_XS,
}
};
static int __init init_rc_map_terratec_cinergy_xs(void)
{
- return ir_register_map(&terratec_cinergy_xs_map);
+ return rc_map_register(&terratec_cinergy_xs_map);
}
static void __exit exit_rc_map_terratec_cinergy_xs(void)
{
- ir_unregister_map(&terratec_cinergy_xs_map);
+ rc_map_unregister(&terratec_cinergy_xs_map);
}
module_init(init_rc_map_terratec_cinergy_xs)
diff --git a/drivers/media/IR/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c
index 10dee4c1deff..1abafa5fd303 100644
--- a/drivers/media/IR/keymaps/rc-terratec-slim.c
+++ b/drivers/media/rc/keymaps/rc-terratec-slim.c
@@ -22,7 +22,7 @@
/* TerraTec slim remote, 7 rows, 4 columns. */
/* Uses NEC extended 0x02bd. */
-static struct ir_scancode terratec_slim[] = {
+static struct rc_map_table terratec_slim[] = {
{ 0x02bd00, KEY_1 },
{ 0x02bd01, KEY_2 },
{ 0x02bd02, KEY_3 },
@@ -53,23 +53,23 @@ static struct ir_scancode terratec_slim[] = {
{ 0x02bd45, KEY_POWER2 }, /* [red power button] */
};
-static struct rc_keymap terratec_slim_map = {
+static struct rc_map_list terratec_slim_map = {
.map = {
.scan = terratec_slim,
.size = ARRAY_SIZE(terratec_slim),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_TERRATEC_SLIM,
}
};
static int __init init_rc_map_terratec_slim(void)
{
- return ir_register_map(&terratec_slim_map);
+ return rc_map_register(&terratec_slim_map);
}
static void __exit exit_rc_map_terratec_slim(void)
{
- ir_unregister_map(&terratec_slim_map);
+ rc_map_unregister(&terratec_slim_map);
}
module_init(init_rc_map_terratec_slim)
diff --git a/drivers/media/IR/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c
index e30d411c07bb..ef5ba3f32735 100644
--- a/drivers/media/IR/keymaps/rc-tevii-nec.c
+++ b/drivers/media/rc/keymaps/rc-tevii-nec.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode tevii_nec[] = {
+static struct rc_map_table tevii_nec[] = {
{ 0x0a, KEY_POWER2},
{ 0x0c, KEY_MUTE},
{ 0x11, KEY_1},
@@ -62,23 +62,23 @@ static struct ir_scancode tevii_nec[] = {
{ 0x58, KEY_SWITCHVIDEOMODE},
};
-static struct rc_keymap tevii_nec_map = {
+static struct rc_map_list tevii_nec_map = {
.map = {
.scan = tevii_nec,
.size = ARRAY_SIZE(tevii_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TEVII_NEC,
}
};
static int __init init_rc_map_tevii_nec(void)
{
- return ir_register_map(&tevii_nec_map);
+ return rc_map_register(&tevii_nec_map);
}
static void __exit exit_rc_map_tevii_nec(void)
{
- ir_unregister_map(&tevii_nec_map);
+ rc_map_unregister(&tevii_nec_map);
}
module_init(init_rc_map_tevii_nec)
diff --git a/drivers/media/IR/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
index fd1985763781..20ac4e19fb3f 100644
--- a/drivers/media/IR/keymaps/rc-total-media-in-hand.c
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
@@ -21,7 +21,7 @@
#include <media/rc-map.h>
/* Uses NEC extended 0x02bd */
-static struct ir_scancode total_media_in_hand[] = {
+static struct rc_map_table total_media_in_hand[] = {
{ 0x02bd00, KEY_1 },
{ 0x02bd01, KEY_2 },
{ 0x02bd02, KEY_3 },
@@ -59,23 +59,23 @@ static struct ir_scancode total_media_in_hand[] = {
{ 0x02bd45, KEY_INFO }, /* [red (I)] */
};
-static struct rc_keymap total_media_in_hand_map = {
+static struct rc_map_list total_media_in_hand_map = {
.map = {
.scan = total_media_in_hand,
.size = ARRAY_SIZE(total_media_in_hand),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_TOTAL_MEDIA_IN_HAND,
}
};
static int __init init_rc_map_total_media_in_hand(void)
{
- return ir_register_map(&total_media_in_hand_map);
+ return rc_map_register(&total_media_in_hand_map);
}
static void __exit exit_rc_map_total_media_in_hand(void)
{
- ir_unregister_map(&total_media_in_hand_map);
+ rc_map_unregister(&total_media_in_hand_map);
}
module_init(init_rc_map_total_media_in_hand)
diff --git a/drivers/media/IR/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c
index 91092caca452..f8190ead2e32 100644
--- a/drivers/media/IR/keymaps/rc-trekstor.c
+++ b/drivers/media/rc/keymaps/rc-trekstor.c
@@ -23,7 +23,7 @@
/* TrekStor DVB-T USB Stick remote controller. */
/* Imported from af9015.h.
Initial keytable was from Marc Schneider <macke@macke.org> */
-static struct ir_scancode trekstor[] = {
+static struct rc_map_table trekstor[] = {
{ 0x0084, KEY_0 },
{ 0x0085, KEY_MUTE }, /* Mute */
{ 0x0086, KEY_HOMEPAGE }, /* Home */
@@ -54,23 +54,23 @@ static struct ir_scancode trekstor[] = {
{ 0x009f, KEY_LEFT }, /* Left */
};
-static struct rc_keymap trekstor_map = {
+static struct rc_map_list trekstor_map = {
.map = {
.scan = trekstor,
.size = ARRAY_SIZE(trekstor),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_TREKSTOR,
}
};
static int __init init_rc_map_trekstor(void)
{
- return ir_register_map(&trekstor_map);
+ return rc_map_register(&trekstor_map);
}
static void __exit exit_rc_map_trekstor(void)
{
- ir_unregister_map(&trekstor_map);
+ rc_map_unregister(&trekstor_map);
}
module_init(init_rc_map_trekstor)
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
new file mode 100644
index 000000000000..295f3738e301
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -0,0 +1,82 @@
+/* tt-1500.h - Keytable for tt_1500 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* for the Technotrend 1500 bundled remotes (grey and black): */
+
+static struct rc_map_table tt_1500[] = {
+ { 0x1501, KEY_POWER },
+ { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */
+ { 0x1503, KEY_1 },
+ { 0x1504, KEY_2 },
+ { 0x1505, KEY_3 },
+ { 0x1506, KEY_4 },
+ { 0x1507, KEY_5 },
+ { 0x1508, KEY_6 },
+ { 0x1509, KEY_7 },
+ { 0x150a, KEY_8 },
+ { 0x150b, KEY_9 },
+ { 0x150c, KEY_0 },
+ { 0x150d, KEY_UP },
+ { 0x150e, KEY_LEFT },
+ { 0x150f, KEY_OK },
+ { 0x1510, KEY_RIGHT },
+ { 0x1511, KEY_DOWN },
+ { 0x1512, KEY_INFO },
+ { 0x1513, KEY_EXIT },
+ { 0x1514, KEY_RED },
+ { 0x1515, KEY_GREEN },
+ { 0x1516, KEY_YELLOW },
+ { 0x1517, KEY_BLUE },
+ { 0x1518, KEY_MUTE },
+ { 0x1519, KEY_TEXT },
+ { 0x151a, KEY_MODE }, /* ? TV/Radio */
+ { 0x1521, KEY_OPTION },
+ { 0x1522, KEY_EPG },
+ { 0x1523, KEY_CHANNELUP },
+ { 0x1524, KEY_CHANNELDOWN },
+ { 0x1525, KEY_VOLUMEUP },
+ { 0x1526, KEY_VOLUMEDOWN },
+ { 0x1527, KEY_SETUP },
+ { 0x153a, KEY_RECORD }, /* these keys are only in the black remote */
+ { 0x153b, KEY_PLAY },
+ { 0x153c, KEY_STOP },
+ { 0x153d, KEY_REWIND },
+ { 0x153e, KEY_PAUSE },
+ { 0x153f, KEY_FORWARD },
+};
+
+static struct rc_map_list tt_1500_map = {
+ .map = {
+ .scan = tt_1500,
+ .size = ARRAY_SIZE(tt_1500),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TT_1500,
+ }
+};
+
+static int __init init_rc_map_tt_1500(void)
+{
+ return rc_map_register(&tt_1500_map);
+}
+
+static void __exit exit_rc_map_tt_1500(void)
+{
+ rc_map_unregister(&tt_1500_map);
+}
+
+module_init(init_rc_map_tt_1500)
+module_exit(exit_rc_map_tt_1500)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c
index 0b5d356c2d84..8bf8df64b081 100644
--- a/drivers/media/IR/keymaps/rc-twinhan1027.c
+++ b/drivers/media/rc/keymaps/rc-twinhan1027.c
@@ -1,6 +1,6 @@
#include <media/rc-map.h>
-static struct ir_scancode twinhan_vp1027[] = {
+static struct rc_map_table twinhan_vp1027[] = {
{ 0x16, KEY_POWER2 },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
@@ -61,23 +61,23 @@ static struct ir_scancode twinhan_vp1027[] = {
{ 0x5f, KEY_BLUE },
};
-static struct rc_keymap twinhan_vp1027_map = {
+static struct rc_map_list twinhan_vp1027_map = {
.map = {
.scan = twinhan_vp1027,
.size = ARRAY_SIZE(twinhan_vp1027),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TWINHAN_VP1027_DVBS,
}
};
static int __init init_rc_map_twinhan_vp1027(void)
{
- return ir_register_map(&twinhan_vp1027_map);
+ return rc_map_register(&twinhan_vp1027_map);
}
static void __exit exit_rc_map_twinhan_vp1027(void)
{
- ir_unregister_map(&twinhan_vp1027_map);
+ rc_map_unregister(&twinhan_vp1027_map);
}
module_init(init_rc_map_twinhan_vp1027)
diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c
new file mode 100644
index 000000000000..4994d405c0a1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c
@@ -0,0 +1,92 @@
+/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Pavel Osnova <pvosnova@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table videomate_m1f[] = {
+ { 0x01, KEY_POWER },
+ { 0x31, KEY_TUNER },
+ { 0x33, KEY_VIDEO },
+ { 0x2f, KEY_RADIO },
+ { 0x30, KEY_CAMERA },
+ { 0x2d, KEY_NEW }, /* TV record button */
+ { 0x17, KEY_CYCLEWINDOWS },
+ { 0x2c, KEY_ANGLE },
+ { 0x2b, KEY_LANGUAGE },
+ { 0x32, KEY_SEARCH }, /* '...' button */
+ { 0x11, KEY_UP },
+ { 0x13, KEY_LEFT },
+ { 0x15, KEY_OK },
+ { 0x14, KEY_RIGHT },
+ { 0x12, KEY_DOWN },
+ { 0x16, KEY_BACKSPACE },
+ { 0x02, KEY_ZOOM }, /* WIN key */
+ { 0x04, KEY_INFO },
+ { 0x05, KEY_VOLUMEUP },
+ { 0x03, KEY_MUTE },
+ { 0x07, KEY_CHANNELUP },
+ { 0x06, KEY_VOLUMEDOWN },
+ { 0x08, KEY_CHANNELDOWN },
+ { 0x0c, KEY_RECORD },
+ { 0x0e, KEY_STOP },
+ { 0x0a, KEY_BACK },
+ { 0x0b, KEY_PLAY },
+ { 0x09, KEY_FORWARD },
+ { 0x10, KEY_PREVIOUS },
+ { 0x0d, KEY_PAUSE },
+ { 0x0f, KEY_NEXT },
+ { 0x1e, KEY_1 },
+ { 0x1f, KEY_2 },
+ { 0x20, KEY_3 },
+ { 0x21, KEY_4 },
+ { 0x22, KEY_5 },
+ { 0x23, KEY_6 },
+ { 0x24, KEY_7 },
+ { 0x25, KEY_8 },
+ { 0x26, KEY_9 },
+ { 0x2a, KEY_NUMERIC_STAR }, /* * key */
+ { 0x1d, KEY_0 },
+ { 0x29, KEY_SUBTITLE }, /* # key */
+ { 0x27, KEY_CLEAR },
+ { 0x34, KEY_SCREEN },
+ { 0x28, KEY_ENTER },
+ { 0x19, KEY_RED },
+ { 0x1a, KEY_GREEN },
+ { 0x1b, KEY_YELLOW },
+ { 0x1c, KEY_BLUE },
+ { 0x18, KEY_TEXT },
+};
+
+static struct rc_map_list videomate_m1f_map = {
+ .map = {
+ .scan = videomate_m1f,
+ .size = ARRAY_SIZE(videomate_m1f),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_VIDEOMATE_M1F,
+ }
+};
+
+static int __init init_rc_map_videomate_m1f(void)
+{
+ return rc_map_register(&videomate_m1f_map);
+}
+
+static void __exit exit_rc_map_videomate_m1f(void)
+{
+ rc_map_unregister(&videomate_m1f_map);
+}
+
+module_init(init_rc_map_videomate_m1f)
+module_exit(exit_rc_map_videomate_m1f)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>");
diff --git a/drivers/media/IR/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c
index 4df7fcd1d2fc..9e474a6024e5 100644
--- a/drivers/media/IR/keymaps/rc-videomate-s350.c
+++ b/drivers/media/rc/keymaps/rc-videomate-s350.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode videomate_s350[] = {
+static struct rc_map_table videomate_s350[] = {
{ 0x00, KEY_TV},
{ 0x01, KEY_DVD},
{ 0x04, KEY_RECORD},
@@ -59,23 +59,23 @@ static struct ir_scancode videomate_s350[] = {
{ 0x20, KEY_TEXT},
};
-static struct rc_keymap videomate_s350_map = {
+static struct rc_map_list videomate_s350_map = {
.map = {
.scan = videomate_s350,
.size = ARRAY_SIZE(videomate_s350),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_VIDEOMATE_S350,
}
};
static int __init init_rc_map_videomate_s350(void)
{
- return ir_register_map(&videomate_s350_map);
+ return rc_map_register(&videomate_s350_map);
}
static void __exit exit_rc_map_videomate_s350(void)
{
- ir_unregister_map(&videomate_s350_map);
+ rc_map_unregister(&videomate_s350_map);
}
module_init(init_rc_map_videomate_s350)
diff --git a/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
index 776b0a638d87..5f2a46e1f8f6 100644
--- a/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c
+++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode videomate_tv_pvr[] = {
+static struct rc_map_table videomate_tv_pvr[] = {
{ 0x14, KEY_MUTE },
{ 0x24, KEY_ZOOM },
@@ -61,23 +61,23 @@ static struct ir_scancode videomate_tv_pvr[] = {
{ 0x21, KEY_SLEEP },
};
-static struct rc_keymap videomate_tv_pvr_map = {
+static struct rc_map_list videomate_tv_pvr_map = {
.map = {
.scan = videomate_tv_pvr,
.size = ARRAY_SIZE(videomate_tv_pvr),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_VIDEOMATE_TV_PVR,
}
};
static int __init init_rc_map_videomate_tv_pvr(void)
{
- return ir_register_map(&videomate_tv_pvr_map);
+ return rc_map_register(&videomate_tv_pvr_map);
}
static void __exit exit_rc_map_videomate_tv_pvr(void)
{
- ir_unregister_map(&videomate_tv_pvr_map);
+ rc_map_unregister(&videomate_tv_pvr_map);
}
module_init(init_rc_map_videomate_tv_pvr)
diff --git a/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
index 9d2d550aaa90..bd8d021f40aa 100644
--- a/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c
+++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
@@ -16,7 +16,7 @@
Magnus Alm <magnus.alm@gmail.com>
*/
-static struct ir_scancode winfast_usbii_deluxe[] = {
+static struct rc_map_table winfast_usbii_deluxe[] = {
{ 0x62, KEY_0},
{ 0x75, KEY_1},
{ 0x76, KEY_2},
@@ -56,23 +56,23 @@ static struct ir_scancode winfast_usbii_deluxe[] = {
};
-static struct rc_keymap winfast_usbii_deluxe_map = {
+static struct rc_map_list winfast_usbii_deluxe_map = {
.map = {
.scan = winfast_usbii_deluxe,
.size = ARRAY_SIZE(winfast_usbii_deluxe),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_WINFAST_USBII_DELUXE,
}
};
static int __init init_rc_map_winfast_usbii_deluxe(void)
{
- return ir_register_map(&winfast_usbii_deluxe_map);
+ return rc_map_register(&winfast_usbii_deluxe_map);
}
static void __exit exit_rc_map_winfast_usbii_deluxe(void)
{
- ir_unregister_map(&winfast_usbii_deluxe_map);
+ rc_map_unregister(&winfast_usbii_deluxe_map);
}
module_init(init_rc_map_winfast_usbii_deluxe)
diff --git a/drivers/media/IR/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
index 0e90a3bd9499..2747db43b70c 100644
--- a/drivers/media/IR/keymaps/rc-winfast.c
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -14,7 +14,7 @@
/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-static struct ir_scancode winfast[] = {
+static struct rc_map_table winfast[] = {
/* Keys 0 to 9 */
{ 0x12, KEY_0 },
{ 0x05, KEY_1 },
@@ -76,23 +76,23 @@ static struct ir_scancode winfast[] = {
{ 0x3f, KEY_F24 } /* MCE -CH, on Y04G0033 */
};
-static struct rc_keymap winfast_map = {
+static struct rc_map_list winfast_map = {
.map = {
.scan = winfast,
.size = ARRAY_SIZE(winfast),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_WINFAST,
}
};
static int __init init_rc_map_winfast(void)
{
- return ir_register_map(&winfast_map);
+ return rc_map_register(&winfast_map);
}
static void __exit exit_rc_map_winfast(void)
{
- ir_unregister_map(&winfast_map);
+ rc_map_unregister(&winfast_map);
}
module_init(init_rc_map_winfast)
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 8418b14ee4d2..fd237ab120bb 100644
--- a/drivers/media/IR/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -178,7 +178,9 @@ static int lirc_cdev_add(struct irctl *ir)
cdev_init(cdev, &lirc_dev_fops);
cdev->owner = THIS_MODULE;
}
- kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
+ retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
+ if (retval)
+ return retval;
retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
if (retval)
@@ -522,10 +524,8 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
- if (!ir->attached) {
- mutex_unlock(&ir->irctl_lock);
+ if (!ir->attached)
return POLLERR;
- }
poll_wait(file, &ir->buf->wait_poll, wait);
@@ -629,7 +629,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(lirc_dev_fop_ioctl);
ssize_t lirc_dev_fop_read(struct file *file,
- char *buffer,
+ char __user *buffer,
size_t length,
loff_t *ppos)
{
@@ -649,18 +649,18 @@ ssize_t lirc_dev_fop_read(struct file *file,
if (!buf)
return -ENOMEM;
- if (mutex_lock_interruptible(&ir->irctl_lock))
- return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&ir->irctl_lock)) {
+ ret = -ERESTARTSYS;
+ goto out_unlocked;
+ }
if (!ir->attached) {
- mutex_unlock(&ir->irctl_lock);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_locked;
}
if (length % ir->chunk_size) {
- dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n",
- ir->d.name, ir->d.minor);
- mutex_unlock(&ir->irctl_lock);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_locked;
}
/*
@@ -711,18 +711,23 @@ ssize_t lirc_dev_fop_read(struct file *file,
lirc_buffer_read(ir->buf, buf);
ret = copy_to_user((void *)buffer+written, buf,
ir->buf->chunk_size);
- written += ir->buf->chunk_size;
+ if (!ret)
+ written += ir->buf->chunk_size;
+ else
+ ret = -EFAULT;
}
}
remove_wait_queue(&ir->buf->wait_poll, &wait);
set_current_state(TASK_RUNNING);
+
+out_locked:
mutex_unlock(&ir->irctl_lock);
out_unlocked:
kfree(buf);
dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
- ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
+ ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret);
return ret ? ret : written;
}
@@ -744,7 +749,7 @@ void *lirc_get_pdata(struct file *file)
EXPORT_SYMBOL(lirc_get_pdata);
-ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
+ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
size_t length, loff_t *ppos)
{
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/rc/mceusb.c
index 9dce684fd231..0fef6efad537 100644
--- a/drivers/media/IR/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -36,9 +36,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
-#include <linux/input.h>
-#include <media/ir-core.h>
-#include <media/ir-common.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
#define DRIVER_VERSION "1.91"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
@@ -49,6 +48,7 @@
#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
+#define MS_TO_NS(msec) ((msec) * 1000)
/* MCE constants */
#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
@@ -74,6 +74,7 @@
#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_SIG_END 0x01 /* End of signal */
#define MCE_CMD_PING 0x03 /* Ping device */
#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
@@ -91,6 +92,7 @@
#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
+#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */
#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
@@ -146,14 +148,16 @@ enum mceusb_model_type {
MCE_GEN3,
MCE_GEN2_TX_INV,
POLARIS_EVK,
+ CX_HYBRID_TV,
};
struct mceusb_model {
u32 mce_gen1:1;
u32 mce_gen2:1;
u32 mce_gen3:1;
- u32 tx_mask_inverted:1;
+ u32 tx_mask_normal:1;
u32 is_polaris:1;
+ u32 no_tx:1;
const char *rc_map; /* Allow specify a per-board map */
const char *name; /* per-board name */
@@ -162,18 +166,18 @@ struct mceusb_model {
static const struct mceusb_model mceusb_model[] = {
[MCE_GEN1] = {
.mce_gen1 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[MCE_GEN2] = {
.mce_gen2 = 1,
},
[MCE_GEN2_TX_INV] = {
.mce_gen2 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[MCE_GEN3] = {
.mce_gen3 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[POLARIS_EVK] = {
.is_polaris = 1,
@@ -183,7 +187,12 @@ static const struct mceusb_model mceusb_model[] = {
* to allow testing it
*/
.rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
- .name = "cx231xx MCE IR",
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
+ },
+ [CX_HYBRID_TV] = {
+ .is_polaris = 1,
+ .no_tx = 1, /* tx isn't wired up at all */
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
},
};
@@ -273,6 +282,8 @@ static struct usb_device_id mceusb_dev_table[] = {
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
/* Formosa Industrial Computing */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+ /* Fintek eHome Infrared Transceiver (HP branded) */
+ { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
/* Fintek eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_FINTEK, 0x0602) },
/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
@@ -292,9 +303,12 @@ static struct usb_device_id mceusb_dev_table[] = {
{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
/* TiVo PC IR Receiver */
{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
- /* Conexant SDK */
+ /* Conexant Hybrid TV "Shelby" Polaris SDK */
{ USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
.driver_info = POLARIS_EVK },
+ /* Conexant Hybrid TV RDU253S Polaris */
+ { USB_DEVICE(VENDOR_CONEXANT, 0x58a5),
+ .driver_info = CX_HYBRID_TV },
/* Terminating entry */
{ }
};
@@ -302,12 +316,14 @@ static struct usb_device_id mceusb_dev_table[] = {
/* data structure for each usb transceiver */
struct mceusb_dev {
/* ir-core bits */
- struct ir_dev_props *props;
- struct ir_raw_event rawir;
+ struct rc_dev *rc;
+
+ /* optional features we can enable */
+ bool carrier_report_enabled;
+ bool learning_enabled;
/* core device bits */
struct device *dev;
- struct input_dev *idev;
/* usb */
struct usb_device *usbdev;
@@ -318,6 +334,8 @@ struct mceusb_dev {
/* buffers and dma */
unsigned char *buf_in;
unsigned int len_in;
+ dma_addr_t dma_in;
+ dma_addr_t dma_out;
enum {
CMD_HEADER = 0,
@@ -325,15 +343,14 @@ struct mceusb_dev {
CMD_DATA,
PARSE_IRDATA,
} parser_state;
- u8 cmd, rem; /* Remaining IR data bytes in packet */
- dma_addr_t dma_in;
- dma_addr_t dma_out;
+ u8 cmd, rem; /* Remaining IR data bytes in packet */
struct {
u32 connected:1;
- u32 tx_mask_inverted:1;
+ u32 tx_mask_normal:1;
u32 microsoft_gen1:1;
+ u32 no_tx:1;
} flags;
/* transmit support */
@@ -408,9 +425,10 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
case MCE_CMD_UNKNOWN:
case MCE_CMD_S_CARRIER:
case MCE_CMD_S_TIMEOUT:
- case MCE_CMD_G_RXSENSOR:
+ case MCE_RSP_PULSE_COUNT:
datasize = 2;
break;
+ case MCE_CMD_SIG_END:
case MCE_CMD_S_TXMASK:
case MCE_CMD_S_RXSENSOR:
datasize = 1;
@@ -433,7 +451,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
return;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
- if (ir->flags.microsoft_gen1 && !out)
+ if (ir->flags.microsoft_gen1 && !out && !offset)
skip = 2;
if (len <= skip)
@@ -491,6 +509,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
break;
case MCE_COMMAND_HEADER:
switch (subcmd) {
+ case MCE_CMD_SIG_END:
+ dev_info(dev, "End of signal\n");
+ break;
case MCE_CMD_PING:
dev_info(dev, "Ping\n");
break;
@@ -525,10 +546,11 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
inout, data1 == 0x02 ? "short" : "long");
break;
case MCE_CMD_G_RXSENSOR:
- if (len == 2)
+ /* aka MCE_RSP_PULSE_COUNT */
+ if (out)
dev_info(dev, "Get receive sensor\n");
- else
- dev_info(dev, "Received pulse count is %d\n",
+ else if (ir->learning_enabled)
+ dev_info(dev, "RX pulse count: %d\n",
((data1 << 8) | data2));
break;
case MCE_RSP_CMD_INVALID:
@@ -639,9 +661,9 @@ static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
}
/* Send data out the IR blaster port(s) */
-static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
+static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
{
- struct mceusb_dev *ir = priv;
+ struct mceusb_dev *ir = dev->priv;
int i, ret = 0;
int count, cmdcount = 0;
unsigned char *cmdbuf; /* MCE command buffer */
@@ -724,24 +746,24 @@ out:
return ret ? ret : n;
}
-/* Sets active IR outputs -- mce devices typically (all?) have two */
-static int mceusb_set_tx_mask(void *priv, u32 mask)
+/* Sets active IR outputs -- mce devices typically have two */
+static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask)
{
- struct mceusb_dev *ir = priv;
+ struct mceusb_dev *ir = dev->priv;
- if (ir->flags.tx_mask_inverted)
+ if (ir->flags.tx_mask_normal)
+ ir->tx_mask = mask;
+ else
ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
- else
- ir->tx_mask = mask;
return 0;
}
/* Sets the send carrier frequency and mode */
-static int mceusb_set_tx_carrier(void *priv, u32 carrier)
+static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
{
- struct mceusb_dev *ir = priv;
+ struct mceusb_dev *ir = dev->priv;
int clk = 10000000;
int prescaler = 0, divisor = 0;
unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
@@ -752,7 +774,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
if (carrier == 0) {
ir->carrier = carrier;
- cmdbuf[2] = 0x01;
+ cmdbuf[2] = MCE_CMD_SIG_END;
cmdbuf[3] = MCE_IRDATA_TRAILER;
dev_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__);
@@ -782,6 +804,34 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
return carrier;
}
+/*
+ * We don't do anything but print debug spew for many of the command bits
+ * we receive from the hardware, but some of them are useful information
+ * we want to store so that we can use them.
+ */
+static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+{
+ u8 hi = ir->buf_in[index + 1] & 0xff;
+ u8 lo = ir->buf_in[index + 2] & 0xff;
+
+ switch (ir->buf_in[index]) {
+ /* 2-byte return value commands */
+ case MCE_CMD_S_TIMEOUT:
+ ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2);
+ break;
+
+ /* 1-byte return value commands */
+ case MCE_CMD_S_TXMASK:
+ ir->tx_mask = hi;
+ break;
+ case MCE_CMD_S_RXSENSOR:
+ ir->learning_enabled = (hi == 0x02);
+ break;
+ default:
+ break;
+ }
+}
+
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
DEFINE_IR_RAW_EVENT(rawir);
@@ -791,39 +841,30 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
if (ir->flags.microsoft_gen1)
i = 2;
+ /* if there's no data, just return now */
+ if (buf_len <= i)
+ return;
+
for (; i < buf_len; i++) {
switch (ir->parser_state) {
case SUBCMD:
ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
mceusb_dev_printdata(ir, ir->buf_in, i - 1,
ir->rem + 2, false);
+ mceusb_handle_command(ir, i);
ir->parser_state = CMD_DATA;
break;
case PARSE_IRDATA:
ir->rem--;
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
- * MCE_TIME_UNIT * 1000;
-
- if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
- if (ir->rawir.pulse == rawir.pulse) {
- ir->rawir.duration += rawir.duration;
- } else {
- ir->rawir.duration = rawir.duration;
- ir->rawir.pulse = rawir.pulse;
- }
- if (ir->rem)
- break;
- }
- rawir.duration += ir->rawir.duration;
- ir->rawir.duration = 0;
- ir->rawir.pulse = rawir.pulse;
+ * MS_TO_NS(MCE_TIME_UNIT);
dev_dbg(ir->dev, "Storing %s with duration %d\n",
rawir.pulse ? "pulse" : "space",
rawir.duration);
- ir_raw_event_store(ir->idev, &rawir);
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
break;
case CMD_DATA:
ir->rem--;
@@ -839,17 +880,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
continue;
}
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
- mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
- if (ir->rem) {
+ mceusb_dev_printdata(ir, ir->buf_in,
+ i, ir->rem + 1, false);
+ if (ir->rem)
ir->parser_state = PARSE_IRDATA;
- break;
- }
- /*
- * a package with len=0 (e. g. 0x80) means end of
- * data. We could use it to do the call to
- * ir_raw_event_handle(). For now, we don't need to
- * use it.
- */
break;
}
@@ -857,7 +891,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->parser_state = CMD_HEADER;
}
dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
- ir_raw_event_handle(ir->idev);
+ ir_raw_event_handle(ir->rc);
}
static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
@@ -984,9 +1018,11 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
mce_sync_in(ir, NULL, maxp);
- /* get the transmitter bitmask */
- mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
- mce_sync_in(ir, NULL, maxp);
+ if (!ir->flags.no_tx) {
+ /* get the transmitter bitmask */
+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+ mce_sync_in(ir, NULL, maxp);
+ }
/* get receiver timeout value */
mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
@@ -997,66 +1033,54 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
mce_sync_in(ir, NULL, maxp);
}
-static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
{
- struct input_dev *idev;
- struct ir_dev_props *props;
struct device *dev = ir->dev;
- const char *rc_map = RC_MAP_RC6_MCE;
- const char *name = "Media Center Ed. eHome Infrared Remote Transceiver";
- int ret = -ENODEV;
-
- idev = input_allocate_device();
- if (!idev) {
- dev_err(dev, "remote input dev allocation failed\n");
- goto idev_alloc_failed;
- }
+ struct rc_dev *rc;
+ int ret;
- ret = -ENOMEM;
- props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
- if (!props) {
- dev_err(dev, "remote ir dev props allocation failed\n");
- goto props_alloc_failed;
+ rc = rc_allocate_device();
+ if (!rc) {
+ dev_err(dev, "remote dev allocation failed\n");
+ goto out;
}
- if (mceusb_model[ir->model].name)
- name = mceusb_model[ir->model].name;
-
snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
- name,
+ mceusb_model[ir->model].name ?
+ mceusb_model[ir->model].name :
+ "Media Center Ed. eHome Infrared Remote Transceiver",
le16_to_cpu(ir->usbdev->descriptor.idVendor),
le16_to_cpu(ir->usbdev->descriptor.idProduct));
- idev->name = ir->name;
usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
- strlcat(ir->phys, "/input0", sizeof(ir->phys));
- idev->phys = ir->phys;
-
- props->priv = ir;
- props->driver_type = RC_DRIVER_IR_RAW;
- props->allowed_protos = IR_TYPE_ALL;
- props->s_tx_mask = mceusb_set_tx_mask;
- props->s_tx_carrier = mceusb_set_tx_carrier;
- props->tx_ir = mceusb_tx_ir;
- ir->props = props;
-
- if (mceusb_model[ir->model].rc_map)
- rc_map = mceusb_model[ir->model].rc_map;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ usb_to_input_id(ir->usbdev, &rc->input_id);
+ rc->dev.parent = dev;
+ rc->priv = ir;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->timeout = MS_TO_NS(1000);
+ if (!ir->flags.no_tx) {
+ rc->s_tx_mask = mceusb_set_tx_mask;
+ rc->s_tx_carrier = mceusb_set_tx_carrier;
+ rc->tx_ir = mceusb_tx_ir;
+ }
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = mceusb_model[ir->model].rc_map ?
+ mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
- ret = ir_input_register(idev, rc_map, props, DRIVER_NAME);
+ ret = rc_register_device(rc);
if (ret < 0) {
- dev_err(dev, "remote input device register failed\n");
- goto irdev_failed;
+ dev_err(dev, "remote dev registration failed\n");
+ goto out;
}
- return idev;
+ return rc;
-irdev_failed:
- kfree(props);
-props_alloc_failed:
- input_free_device(idev);
-idev_alloc_failed:
+out:
+ rc_free_device(rc);
return NULL;
}
@@ -1074,16 +1098,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
enum mceusb_model_type model = id->driver_info;
bool is_gen3;
bool is_microsoft_gen1;
- bool tx_mask_inverted;
+ bool tx_mask_normal;
bool is_polaris;
- dev_dbg(&intf->dev, ": %s called\n", __func__);
+ dev_dbg(&intf->dev, "%s called\n", __func__);
idesc = intf->cur_altsetting;
is_gen3 = mceusb_model[model].mce_gen3;
is_microsoft_gen1 = mceusb_model[model].mce_gen1;
- tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
+ tx_mask_normal = mceusb_model[model].tx_mask_normal;
is_polaris = mceusb_model[model].is_polaris;
if (is_polaris) {
@@ -1107,7 +1131,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_in = ep;
ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_in->bInterval = 1;
- dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+ dev_dbg(&intf->dev, "acceptable inbound endpoint "
"found\n");
}
@@ -1122,12 +1146,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_out = ep;
ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_out->bInterval = 1;
- dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+ dev_dbg(&intf->dev, "acceptable outbound endpoint "
"found\n");
}
}
if (ep_in == NULL) {
- dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+ dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
return -ENODEV;
}
@@ -1150,11 +1174,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ir->dev = &intf->dev;
ir->len_in = maxp;
ir->flags.microsoft_gen1 = is_microsoft_gen1;
- ir->flags.tx_mask_inverted = tx_mask_inverted;
+ ir->flags.tx_mask_normal = tx_mask_normal;
+ ir->flags.no_tx = mceusb_model[model].no_tx;
ir->model = model;
- init_ir_raw_event(&ir->rawir);
-
/* Saving usb interface data for use by the transmitter routine */
ir->usb_ep_in = ep_in;
ir->usb_ep_out = ep_out;
@@ -1169,9 +1192,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
- ir->idev = mceusb_init_input_dev(ir);
- if (!ir->idev)
- goto input_dev_fail;
+ ir->rc = mceusb_init_rc_dev(ir);
+ if (!ir->rc)
+ goto rc_dev_fail;
/* flush buffers on the device */
mce_sync_in(ir, NULL, maxp);
@@ -1191,7 +1214,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
mceusb_get_parameters(ir);
- mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+ if (!ir->flags.no_tx)
+ mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
usb_set_intfdata(intf, ir);
@@ -1201,7 +1225,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
return 0;
/* Error-handling path */
-input_dev_fail:
+rc_dev_fail:
usb_free_urb(ir->urb_in);
urb_in_alloc_fail:
usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
@@ -1225,7 +1249,7 @@ static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
return;
ir->usbdev = NULL;
- ir_input_unregister(ir->idev);
+ rc_unregister_device(ir->rc);
usb_kill_urb(ir->urb_in);
usb_free_urb(ir->urb_in);
usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 301be53aee85..dd4caf8ef80b 100644
--- a/drivers/media/IR/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -32,8 +32,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <linux/pci_ids.h>
#include "nuvoton-cir.h"
@@ -249,9 +248,12 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
- if (chip_major != CHIP_ID_HIGH &&
- (chip_minor != CHIP_ID_LOW || chip_minor != CHIP_ID_LOW2))
+ if (chip_major != CHIP_ID_HIGH ||
+ (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) {
+ nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x",
+ chip_id, chip_major, chip_minor);
ret = -ENODEV;
+ }
nvt_efm_disable(nvt);
@@ -476,9 +478,9 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
* always set CP as 0x81
* set CC by SPEC, CC = 3MHz/carrier - 1
*/
-static int nvt_set_tx_carrier(void *data, u32 carrier)
+static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
{
- struct nvt_dev *nvt = data;
+ struct nvt_dev *nvt = dev->priv;
u16 val;
nvt_cir_reg_write(nvt, 1, CIR_CP);
@@ -509,9 +511,9 @@ static int nvt_set_tx_carrier(void *data, u32 carrier)
* number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
* set TXFCONT as 0xff, until buf_count less than 0xff.
*/
-static int nvt_tx_ir(void *priv, int *txbuf, u32 n)
+static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
{
- struct nvt_dev *nvt = priv;
+ struct nvt_dev *nvt = dev->priv;
unsigned long flags;
size_t cur_count;
unsigned int i;
@@ -603,6 +605,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
count = nvt->pkts;
nvt_dbg_verbose("Processing buffer of len %d", count);
+ init_ir_raw_event(&rawir);
+
for (i = 0; i < count; i++) {
nvt->pkts--;
sample = nvt->buf[i];
@@ -643,11 +647,15 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
* indicates end of IR signal, but new data incoming. In both
* cases, it means we're ready to call ir_raw_event_handle
*/
- if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) &&
- (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE))
+ if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
ir_raw_event_handle(nvt->rdev);
+ }
}
+ nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
+ ir_raw_event_handle(nvt->rdev);
+
if (nvt->pkts) {
nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
nvt->pkts = 0;
@@ -942,9 +950,9 @@ static void nvt_disable_cir(struct nvt_dev *nvt)
nvt_efm_disable(nvt);
}
-static int nvt_open(void *data)
+static int nvt_open(struct rc_dev *dev)
{
- struct nvt_dev *nvt = (struct nvt_dev *)data;
+ struct nvt_dev *nvt = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags);
@@ -955,9 +963,9 @@ static int nvt_open(void *data)
return 0;
}
-static void nvt_close(void *data)
+static void nvt_close(struct rc_dev *dev)
{
- struct nvt_dev *nvt = (struct nvt_dev *)data;
+ struct nvt_dev *nvt = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags);
@@ -969,21 +977,16 @@ static void nvt_close(void *data)
/* Allocate memory, probe hardware, and initialize everything */
static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
{
- struct nvt_dev *nvt = NULL;
- struct input_dev *rdev = NULL;
- struct ir_dev_props *props = NULL;
+ struct nvt_dev *nvt;
+ struct rc_dev *rdev;
int ret = -ENOMEM;
nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
if (!nvt)
return ret;
- props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
- if (!props)
- goto failure;
-
/* input device for IR remote (and tx) */
- rdev = input_allocate_device();
+ rdev = rc_allocate_device();
if (!rdev)
goto failure;
@@ -1057,41 +1060,38 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
nvt_cir_regs_init(nvt);
nvt_cir_wake_regs_init(nvt);
- /* Set up ir-core props */
- props->priv = nvt;
- props->driver_type = RC_DRIVER_IR_RAW;
- props->allowed_protos = IR_TYPE_ALL;
- props->open = nvt_open;
- props->close = nvt_close;
+ /* Set up the rc device */
+ rdev->priv = nvt;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->open = nvt_open;
+ rdev->close = nvt_close;
+ rdev->tx_ir = nvt_tx_ir;
+ rdev->s_tx_carrier = nvt_set_tx_carrier;
+ rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+ rdev->input_id.bustype = BUS_HOST;
+ rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2;
+ rdev->input_id.product = nvt->chip_major;
+ rdev->input_id.version = nvt->chip_minor;
+ rdev->driver_name = NVT_DRIVER_NAME;
+ rdev->map_name = RC_MAP_RC6_MCE;
#if 0
- props->min_timeout = XYZ;
- props->max_timeout = XYZ;
- props->timeout = XYZ;
+ rdev->min_timeout = XYZ;
+ rdev->max_timeout = XYZ;
+ rdev->timeout = XYZ;
/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
- props->rx_resolution = XYZ;
-
+ rdev->rx_resolution = XYZ;
/* tx bits */
- props->tx_resolution = XYZ;
+ rdev->tx_resolution = XYZ;
#endif
- props->tx_ir = nvt_tx_ir;
- props->s_tx_carrier = nvt_set_tx_carrier;
-
- rdev->name = "Nuvoton w836x7hg Infrared Remote Transceiver";
- rdev->id.bustype = BUS_HOST;
- rdev->id.vendor = PCI_VENDOR_ID_WINBOND2;
- rdev->id.product = nvt->chip_major;
- rdev->id.version = nvt->chip_minor;
- nvt->props = props;
- nvt->rdev = rdev;
-
- device_set_wakeup_capable(&pdev->dev, 1);
- device_set_wakeup_enable(&pdev->dev, 1);
-
- ret = ir_input_register(rdev, RC_MAP_RC6_MCE, props, NVT_DRIVER_NAME);
+ ret = rc_register_device(rdev);
if (ret)
goto failure;
+ device_set_wakeup_capable(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, 1);
+ nvt->rdev = rdev;
nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
if (debug) {
cir_dump_regs(nvt);
@@ -1111,8 +1111,7 @@ failure:
if (nvt->cir_wake_addr)
release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
- input_free_device(rdev);
- kfree(props);
+ rc_free_device(rdev);
kfree(nvt);
return ret;
@@ -1137,9 +1136,8 @@ static void __devexit nvt_remove(struct pnp_dev *pdev)
release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
- ir_input_unregister(nvt->rdev);
+ rc_unregister_device(nvt->rdev);
- kfree(nvt->props);
kfree(nvt);
}
diff --git a/drivers/media/IR/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 62dc53017c8e..1df82351cb03 100644
--- a/drivers/media/IR/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -66,8 +66,7 @@ static int debug;
struct nvt_dev {
struct pnp_dev *pdev;
- struct input_dev *rdev;
- struct ir_dev_props *props;
+ struct rc_dev *rdev;
struct ir_raw_event rawir;
spinlock_t nvt_lock;
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 81c936bd793f..873b38789751 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -13,22 +13,22 @@
* GNU General Public License for more details.
*/
-#ifndef _IR_RAW_EVENT
-#define _IR_RAW_EVENT
+#ifndef _RC_CORE_PRIV
+#define _RC_CORE_PRIV
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
struct ir_raw_handler {
struct list_head list;
u64 protocols; /* which are handled by this handler */
- int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+ int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
/* These two should only be used by the lirc decoder */
- int (*raw_register)(struct input_dev *input_dev);
- int (*raw_unregister)(struct input_dev *input_dev);
+ int (*raw_register)(struct rc_dev *dev);
+ int (*raw_unregister)(struct rc_dev *dev);
};
struct ir_raw_event_ctrl {
@@ -38,7 +38,7 @@ struct ir_raw_event_ctrl {
struct kfifo kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
- struct input_dev *input_dev; /* pointer to the parent input_dev */
+ struct rc_dev *dev; /* pointer to the parent rc_dev */
u64 enabled_protocols; /* enabled raw protocol decoders */
/* raw decoder state follows */
@@ -85,7 +85,7 @@ struct ir_raw_event_ctrl {
unsigned wanted_bits;
} rc5_sz;
struct lirc_codec {
- struct ir_input_dev *ir_dev;
+ struct rc_dev *dev;
struct lirc_driver *drv;
int carrier_low;
@@ -129,27 +129,17 @@ static inline bool is_timing_event(struct ir_raw_event ev)
#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
-/*
- * Routines from ir-sysfs.c - Meant to be called only internally inside
- * ir-core
- */
-int ir_register_input(struct input_dev *input_dev);
-
-int ir_register_class(struct input_dev *input_dev);
-void ir_unregister_class(struct input_dev *input_dev);
/*
- * Routines from ir-raw-event.c to be used internally and by decoders
+ * Routines from rc-raw.c to be used internally and by decoders
*/
u64 ir_raw_get_allowed_protocols(void);
-int ir_raw_event_register(struct input_dev *input_dev);
-void ir_raw_event_unregister(struct input_dev *input_dev);
+int ir_raw_event_register(struct rc_dev *dev);
+void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
void ir_raw_init(void);
-int ir_rcmap_init(void);
-void ir_rcmap_cleanup(void);
/*
* Decoder initialization code
*
@@ -200,4 +190,4 @@ void ir_rcmap_cleanup(void);
#endif
-#endif /* _IR_RAW_EVENT */
+#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
new file mode 100644
index 000000000000..49cee61d79c6
--- /dev/null
+++ b/drivers/media/rc/rc-loopback.c
@@ -0,0 +1,260 @@
+/*
+ * Loopback driver for rc-core,
+ *
+ * Copyright (c) 2010 David Härdeman <david@hardeman.nu>
+ *
+ * This driver receives TX data and passes it back as RX data,
+ * which is useful for (scripted) debugging of rc-core without
+ * having to use actual hardware.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <media/rc-core.h>
+
+#define DRIVER_NAME "rc-loopback"
+#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
+#define RXMASK_REGULAR 0x1
+#define RXMASK_LEARNING 0x2
+
+static bool debug;
+
+struct loopback_dev {
+ struct rc_dev *dev;
+ u32 txmask;
+ u32 txcarrier;
+ u32 txduty;
+ bool idle;
+ bool learning;
+ bool carrierreport;
+ u32 rxcarriermin;
+ u32 rxcarriermax;
+};
+
+static struct loopback_dev loopdev;
+
+static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
+ dprintk("invalid tx mask: %u\n", mask);
+ return -EINVAL;
+ }
+
+ dprintk("setting tx mask: %u\n", mask);
+ lodev->txmask = mask;
+ return 0;
+}
+
+static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ dprintk("setting tx carrier: %u\n", carrier);
+ lodev->txcarrier = carrier;
+ return 0;
+}
+
+static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (duty_cycle < 1 || duty_cycle > 99) {
+ dprintk("invalid duty cycle: %u\n", duty_cycle);
+ return -EINVAL;
+ }
+
+ dprintk("setting duty cycle: %u\n", duty_cycle);
+ lodev->txduty = duty_cycle;
+ return 0;
+}
+
+static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (min < 1 || min > max) {
+ dprintk("invalid rx carrier range %u to %u\n", min, max);
+ return -EINVAL;
+ }
+
+ dprintk("setting rx carrier range %u to %u\n", min, max);
+ lodev->rxcarriermin = min;
+ lodev->rxcarriermax = max;
+ return 0;
+}
+
+static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+{
+ struct loopback_dev *lodev = dev->priv;
+ u32 rxmask;
+ unsigned count;
+ unsigned total_duration = 0;
+ unsigned i;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ if (n == 0 || n % sizeof(int)) {
+ dprintk("invalid tx buffer size\n");
+ return -EINVAL;
+ }
+
+ count = n / sizeof(int);
+ for (i = 0; i < count; i++)
+ total_duration += abs(txbuf[i]);
+
+ if (total_duration == 0) {
+ dprintk("invalid tx data, total duration zero\n");
+ return -EINVAL;
+ }
+
+ if (lodev->txcarrier < lodev->rxcarriermin ||
+ lodev->txcarrier > lodev->rxcarriermax) {
+ dprintk("ignoring tx, carrier out of range\n");
+ goto out;
+ }
+
+ if (lodev->learning)
+ rxmask = RXMASK_LEARNING;
+ else
+ rxmask = RXMASK_REGULAR;
+
+ if (!(rxmask & lodev->txmask)) {
+ dprintk("ignoring tx, rx mask mismatch\n");
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ rawir.pulse = i % 2 ? false : true;
+ rawir.duration = abs(txbuf[i]) * 1000;
+ if (rawir.duration)
+ ir_raw_event_store_with_filter(dev, &rawir);
+ }
+ ir_raw_event_handle(dev);
+
+out:
+ /* Lirc expects this function to take as long as the total duration */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(total_duration));
+ return n;
+}
+
+static void loop_set_idle(struct rc_dev *dev, bool enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->idle != enable) {
+ dprintk("%sing idle mode\n", enable ? "enter" : "exit");
+ lodev->idle = enable;
+ }
+}
+
+static int loop_set_learning_mode(struct rc_dev *dev, int enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->learning != enable) {
+ dprintk("%sing learning mode\n", enable ? "enter" : "exit");
+ lodev->learning = !!enable;
+ }
+
+ return 0;
+}
+
+static int loop_set_carrier_report(struct rc_dev *dev, int enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->carrierreport != enable) {
+ dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
+ lodev->carrierreport = !!enable;
+ }
+
+ return 0;
+}
+
+static int __init loop_init(void)
+{
+ struct rc_dev *rc;
+ int ret;
+
+ rc = rc_allocate_device();
+ if (!rc) {
+ printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
+ return -ENOMEM;
+ }
+
+ rc->input_name = "rc-core loopback device";
+ rc->input_phys = "rc-core/virtual";
+ rc->input_id.bustype = BUS_VIRTUAL;
+ rc->input_id.version = 1;
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = RC_MAP_EMPTY;
+ rc->priv = &loopdev;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->timeout = 100 * 1000 * 1000; /* 100 ms */
+ rc->min_timeout = 1;
+ rc->max_timeout = UINT_MAX;
+ rc->rx_resolution = 1000;
+ rc->tx_resolution = 1000;
+ rc->s_tx_mask = loop_set_tx_mask;
+ rc->s_tx_carrier = loop_set_tx_carrier;
+ rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
+ rc->s_rx_carrier_range = loop_set_rx_carrier_range;
+ rc->tx_ir = loop_tx_ir;
+ rc->s_idle = loop_set_idle;
+ rc->s_learning_mode = loop_set_learning_mode;
+ rc->s_carrier_report = loop_set_carrier_report;
+ rc->priv = &loopdev;
+
+ loopdev.txmask = RXMASK_REGULAR;
+ loopdev.txcarrier = 36000;
+ loopdev.txduty = 50;
+ loopdev.rxcarriermin = 1;
+ loopdev.rxcarriermax = ~0;
+ loopdev.idle = true;
+ loopdev.learning = false;
+ loopdev.carrierreport = false;
+
+ ret = rc_register_device(rc);
+ if (ret < 0) {
+ printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
+ rc_free_device(rc);
+ return ret;
+ }
+
+ loopdev.dev = rc;
+ return 0;
+}
+
+static void __exit loop_exit(void)
+{
+ rc_unregister_device(loopdev.dev);
+}
+
+module_init(loop_init);
+module_exit(loop_exit);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debug messages");
+
+MODULE_DESCRIPTION("Loopback device for rc-core debugging");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
new file mode 100644
index 000000000000..72be8a02118c
--- /dev/null
+++ b/drivers/media/rc/rc-main.c
@@ -0,0 +1,1135 @@
+/* rc-main.c - Remote Controller core module
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <media/rc-core.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include "rc-core-priv.h"
+
+/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
+#define IR_TAB_MIN_SIZE 256
+#define IR_TAB_MAX_SIZE 8192
+
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
+#define IR_KEYPRESS_TIMEOUT 250
+
+/* Used to keep track of known keymaps */
+static LIST_HEAD(rc_map_list);
+static DEFINE_SPINLOCK(rc_map_lock);
+
+static struct rc_map_list *seek_rc_map(const char *name)
+{
+ struct rc_map_list *map = NULL;
+
+ spin_lock(&rc_map_lock);
+ list_for_each_entry(map, &rc_map_list, list) {
+ if (!strcmp(name, map->map.name)) {
+ spin_unlock(&rc_map_lock);
+ return map;
+ }
+ }
+ spin_unlock(&rc_map_lock);
+
+ return NULL;
+}
+
+struct rc_map *rc_map_get(const char *name)
+{
+
+ struct rc_map_list *map;
+
+ map = seek_rc_map(name);
+#ifdef MODULE
+ if (!map) {
+ int rc = request_module(name);
+ if (rc < 0) {
+ printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
+ return NULL;
+ }
+ msleep(20); /* Give some time for IR to register */
+
+ map = seek_rc_map(name);
+ }
+#endif
+ if (!map) {
+ printk(KERN_ERR "IR keymap %s not found\n", name);
+ return NULL;
+ }
+
+ printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
+
+ return &map->map;
+}
+EXPORT_SYMBOL_GPL(rc_map_get);
+
+int rc_map_register(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_add_tail(&map->list, &rc_map_list);
+ spin_unlock(&rc_map_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rc_map_register);
+
+void rc_map_unregister(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_del(&map->list);
+ spin_unlock(&rc_map_lock);
+}
+EXPORT_SYMBOL_GPL(rc_map_unregister);
+
+
+static struct rc_map_table empty[] = {
+ { 0x2a, KEY_COFFEE },
+};
+
+static struct rc_map_list empty_map = {
+ .map = {
+ .scan = empty,
+ .size = ARRAY_SIZE(empty),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_EMPTY,
+ }
+};
+
+/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_map: the rc_map to initialize
+ * @name: name to assign to the table
+ * @rc_type: ir type to assign to the new table
+ * @size: initial size of the table
+ * @return: zero on success or a negative error code
+ *
+ * This routine will initialize the rc_map and will allocate
+ * memory to hold at least the specified number of elements.
+ */
+static int ir_create_table(struct rc_map *rc_map,
+ const char *name, u64 rc_type, size_t size)
+{
+ rc_map->name = name;
+ rc_map->rc_type = rc_type;
+ rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
+ if (!rc_map->scan)
+ return -ENOMEM;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+ return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_map: the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct rc_map *rc_map)
+{
+ rc_map->size = 0;
+ kfree(rc_map->scan);
+ rc_map->scan = NULL;
+}
+
+/**
+ * ir_resize_table() - resizes a scancode table if necessary
+ * @rc_map: the rc_map to resize
+ * @gfp_flags: gfp flags to use when allocating memory
+ * @return: zero on success or a negative error code
+ *
+ * This routine will shrink the rc_map if it has lots of
+ * unused entries and grow it if it is full.
+ */
+static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+{
+ unsigned int oldalloc = rc_map->alloc;
+ unsigned int newalloc = oldalloc;
+ struct rc_map_table *oldscan = rc_map->scan;
+ struct rc_map_table *newscan;
+
+ if (rc_map->size == rc_map->len) {
+ /* All entries in use -> grow keytable */
+ if (rc_map->alloc >= IR_TAB_MAX_SIZE)
+ return -ENOMEM;
+
+ newalloc *= 2;
+ IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+ }
+
+ if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
+ /* Less than 1/3 of entries in use -> shrink keytable */
+ newalloc /= 2;
+ IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+ }
+
+ if (newalloc == oldalloc)
+ return 0;
+
+ newscan = kmalloc(newalloc, gfp_flags);
+ if (!newscan) {
+ IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+ return -ENOMEM;
+ }
+
+ memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
+ rc_map->scan = newscan;
+ rc_map->alloc = newalloc;
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ kfree(oldscan);
+ return 0;
+}
+
+/**
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @rc_map: scancode table to be adjusted
+ * @index: index of the mapping that needs to be updated
+ * @keycode: the desired keycode
+ * @return: previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycode mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct rc_dev *dev,
+ struct rc_map *rc_map,
+ unsigned int index,
+ unsigned int new_keycode)
+{
+ int old_keycode = rc_map->scan[index].keycode;
+ int i;
+
+ /* Did the user wish to remove the mapping? */
+ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+ IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+ index, rc_map->scan[index].scancode);
+ rc_map->len--;
+ memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
+ (rc_map->len - index) * sizeof(struct rc_map_table));
+ } else {
+ IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_map->scan[index].scancode, new_keycode);
+ rc_map->scan[index].keycode = new_keycode;
+ __set_bit(new_keycode, dev->input_dev->keybit);
+ }
+
+ if (old_keycode != KEY_RESERVED) {
+ /* A previous mapping was updated... */
+ __clear_bit(old_keycode, dev->input_dev->keybit);
+ /* ... but another scancode might use the same keycode */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].keycode == old_keycode) {
+ __set_bit(old_keycode, dev->input_dev->keybit);
+ break;
+ }
+ }
+
+ /* Possibly shrink the keytable, failure is not a problem */
+ ir_resize_table(rc_map, GFP_ATOMIC);
+ }
+
+ return old_keycode;
+}
+
+/**
+ * ir_establish_scancode() - set a keycode in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @rc_map: scancode table to be searched
+ * @scancode: the desired scancode
+ * @resize: controls whether we allowed to resize the table to
+ * accomodate not yet present scancodes
+ * @return: index of the mapping containing scancode in question
+ * or -1U in case of failure.
+ *
+ * This routine is used to locate given scancode in rc_map.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
+ */
+static unsigned int ir_establish_scancode(struct rc_dev *dev,
+ struct rc_map *rc_map,
+ unsigned int scancode,
+ bool resize)
+{
+ unsigned int i;
+
+ /*
+ * Unfortunately, some hardware-based IR decoders don't provide
+ * all bits for the complete IR code. In general, they provide only
+ * the command part of the IR code. Yet, as it is possible to replace
+ * the provided IR with another one, it is needed to allow loading
+ * IR tables from other remotes. So, we support specifying a mask to
+ * indicate the valid bits of the scancodes.
+ */
+ if (dev->scanmask)
+ scancode &= dev->scanmask;
+
+ /* First check if we already have a mapping for this ir command */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].scancode == scancode)
+ return i;
+
+ /* Keytable is sorted from lowest to highest scancode */
+ if (rc_map->scan[i].scancode >= scancode)
+ break;
+ }
+
+ /* No previous mapping found, we might need to grow the table */
+ if (rc_map->size == rc_map->len) {
+ if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+ return -1U;
+ }
+
+ /* i is the proper index to insert our new keycode */
+ if (i < rc_map->len)
+ memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
+ (rc_map->len - i) * sizeof(struct rc_map_table));
+ rc_map->scan[i].scancode = scancode;
+ rc_map->scan[i].keycode = KEY_RESERVED;
+ rc_map->len++;
+
+ return i;
+}
+
+/**
+ * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: result
+ * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ */
+static int ir_setkeycode(struct input_dev *idev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+ struct rc_map *rc_map = &rdev->rc_map;
+ unsigned int index;
+ unsigned int scancode;
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= rc_map->len) {
+ retval = -EINVAL;
+ goto out;
+ }
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_establish_scancode(rdev, rc_map, scancode, true);
+ if (index >= rc_map->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * ir_setkeytable() - sets several entries in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @to: the struct rc_map to copy entries to
+ * @from: the struct rc_map to copy entries from
+ * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle table initialization.
+ */
+static int ir_setkeytable(struct rc_dev *dev,
+ const struct rc_map *from)
+{
+ struct rc_map *rc_map = &dev->rc_map;
+ unsigned int i, index;
+ int rc;
+
+ rc = ir_create_table(rc_map, from->name,
+ from->rc_type, from->size);
+ if (rc)
+ return rc;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+
+ for (i = 0; i < from->size; i++) {
+ index = ir_establish_scancode(dev, rc_map,
+ from->scan[i].scancode, false);
+ if (index >= rc_map->len) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ ir_update_mapping(dev, rc_map, index,
+ from->scan[i].keycode);
+ }
+
+ if (rc)
+ ir_free_table(rc_map);
+
+ return rc;
+}
+
+/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_map: the struct rc_map to search
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
+ unsigned int scancode)
+{
+ int start = 0;
+ int end = rc_map->len - 1;
+ int mid;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ if (rc_map->scan[mid].scancode < scancode)
+ start = mid + 1;
+ else if (rc_map->scan[mid].scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
+ * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: used to return the keycode, if found, or KEY_RESERVED
+ * @return: always returns zero.
+ *
+ * This routine is used to handle evdev EVIOCGKEY ioctl.
+ */
+static int ir_getkeycode(struct input_dev *idev,
+ struct input_keymap_entry *ke)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+ struct rc_map *rc_map = &rdev->rc_map;
+ struct rc_map_table *entry;
+ unsigned long flags;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_lookup_by_scancode(rc_map, scancode);
+ }
+
+ if (index >= rc_map->len) {
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+ scancode);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ entry = &rc_map->scan[index];
+
+ ke->index = index;
+ ke->keycode = entry->keycode;
+ ke->len = sizeof(entry->scancode);
+ memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+ retval = 0;
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode to look for
+ * @return: the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. Normally it should not be used since drivers should have no
+ * interest in keycodes.
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
+{
+ struct rc_map *rc_map = &dev->rc_map;
+ unsigned int keycode;
+ unsigned int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ index = ir_lookup_by_scancode(rc_map, scancode);
+ keycode = index < rc_map->len ?
+ rc_map->scan[index].keycode : KEY_RESERVED;
+
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+
+ if (keycode != KEY_RESERVED)
+ IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
+ dev->input_name, scancode, keycode);
+
+ return keycode;
+}
+EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
+
+/**
+ * ir_do_keyup() - internal function to signal the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This function is used internally to release a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keyup(struct rc_dev *dev)
+{
+ if (!dev->keypressed)
+ return;
+
+ IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+ input_report_key(dev->input_dev, dev->last_keycode, 0);
+ input_sync(dev->input_dev);
+ dev->keypressed = false;
+}
+
+/**
+ * rc_keyup() - signals the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used to signal that a key has been released on the
+ * remote control.
+ */
+void rc_keyup(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keyup(dev);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keyup);
+
+/**
+ * ir_timer_keyup() - generates a keyup event after a timeout
+ * @cookie: a pointer to the struct rc_dev for the device
+ *
+ * This routine will generate a keyup event some time after a keydown event
+ * is generated when no further activity has been detected.
+ */
+static void ir_timer_keyup(unsigned long cookie)
+{
+ struct rc_dev *dev = (struct rc_dev *)cookie;
+ unsigned long flags;
+
+ /*
+ * ir->keyup_jiffies is used to prevent a race condition if a
+ * hardware interrupt occurs at this point and the keyup timer
+ * event is moved further into the future as a result.
+ *
+ * The timer will then be reactivated and this function called
+ * again in the future. We need to exit gracefully in that case
+ * to allow the input subsystem to do its auto-repeat magic or
+ * a keyup event might follow immediately after the keydown.
+ */
+ spin_lock_irqsave(&dev->keylock, flags);
+ if (time_is_before_eq_jiffies(dev->keyup_jiffies))
+ ir_do_keyup(dev);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+
+/**
+ * rc_repeat() - signals that a key is still pressed
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used by IR decoders when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
+ */
+void rc_repeat(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->keylock, flags);
+
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
+
+ if (!dev->keypressed)
+ goto out;
+
+ dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+
+out:
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_repeat);
+
+/**
+ * ir_do_keydown() - internal function to process a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode of the keypress
+ * @keycode: the keycode of the keypress
+ * @toggle: the toggle value of the keypress
+ *
+ * This function is used internally to register a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keydown(struct rc_dev *dev, int scancode,
+ u32 keycode, u8 toggle)
+{
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+
+ /* Repeat event? */
+ if (dev->keypressed &&
+ dev->last_scancode == scancode &&
+ dev->last_toggle == toggle)
+ return;
+
+ /* Release old keypress */
+ ir_do_keyup(dev);
+
+ dev->last_scancode = scancode;
+ dev->last_toggle = toggle;
+ dev->last_keycode = keycode;
+
+ if (keycode == KEY_RESERVED)
+ return;
+
+ /* Register a keypress */
+ dev->keypressed = true;
+ IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
+ dev->input_name, keycode, scancode);
+ input_report_key(dev->input_dev, dev->last_keycode, 1);
+ input_sync(dev->input_dev);
+}
+
+/**
+ * rc_keydown() - generates input event for a key press
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode that we're seeking
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control.
+ */
+void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
+{
+ unsigned long flags;
+ u32 keycode = rc_g_keycode_from_table(dev, scancode);
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keydown(dev, scancode, keycode, toggle);
+
+ if (dev->keypressed) {
+ dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+ }
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown);
+
+/**
+ * rc_keydown_notimeout() - generates input event for a key press without
+ * an automatic keyup event at a later time
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode that we're seeking
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control. The driver must manually call rc_keyup() at a later stage.
+ */
+void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
+{
+ unsigned long flags;
+ u32 keycode = rc_g_keycode_from_table(dev, scancode);
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keydown(dev, scancode, keycode, toggle);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
+
+static int ir_open(struct input_dev *idev)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+
+ return rdev->open(rdev);
+}
+
+static void ir_close(struct input_dev *idev)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+
+ rdev->close(rdev);
+}
+
+/* class for /sys/class/rc */
+static char *ir_devnode(struct device *dev, mode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
+}
+
+static struct class ir_input_class = {
+ .name = "rc",
+ .devnode = ir_devnode,
+};
+
+static struct {
+ u64 type;
+ char *name;
+} proto_names[] = {
+ { RC_TYPE_UNKNOWN, "unknown" },
+ { RC_TYPE_RC5, "rc-5" },
+ { RC_TYPE_NEC, "nec" },
+ { RC_TYPE_RC6, "rc-6" },
+ { RC_TYPE_JVC, "jvc" },
+ { RC_TYPE_SONY, "sony" },
+ { RC_TYPE_RC5_SZ, "rc-5-sz" },
+ { RC_TYPE_LIRC, "lirc" },
+};
+
+#define PROTO_NONE "none"
+
+/**
+ * show_protocols() - shows the current IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * It returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
+ */
+static ssize_t show_protocols(struct device *device,
+ struct device_attribute *mattr, char *buf)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ u64 allowed, enabled;
+ char *tmp = buf;
+ int i;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE) {
+ enabled = dev->rc_map.rc_type;
+ allowed = dev->allowed_protos;
+ } else {
+ enabled = dev->raw->enabled_protocols;
+ allowed = ir_raw_get_allowed_protocols();
+ }
+
+ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+ (long long)allowed,
+ (long long)enabled);
+
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (allowed & enabled & proto_names[i].type)
+ tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
+ else if (allowed & proto_names[i].type)
+ tmp += sprintf(tmp, "%s ", proto_names[i].name);
+ }
+
+ if (tmp != buf)
+ tmp--;
+ *tmp = '\n';
+ return tmp + 1 - buf;
+}
+
+/**
+ * store_protocols() - changes the current IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * Writing "+proto" will add a protocol to the list of enabled protocols.
+ * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "proto" will enable only "proto".
+ * Writing "none" will disable all protocols.
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
+ */
+static ssize_t store_protocols(struct device *device,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ bool enable, disable;
+ const char *tmp;
+ u64 type;
+ u64 mask;
+ int rc, i, count = 0;
+ unsigned long flags;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
+ type = dev->rc_map.rc_type;
+ else if (dev->raw)
+ type = dev->raw->enabled_protocols;
+ else {
+ IR_dprintk(1, "Protocol switching not supported\n");
+ return -EINVAL;
+ }
+
+ while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+ if (!*tmp)
+ break;
+
+ if (*tmp == '+') {
+ enable = true;
+ disable = false;
+ tmp++;
+ } else if (*tmp == '-') {
+ enable = false;
+ disable = true;
+ tmp++;
+ } else {
+ enable = false;
+ disable = false;
+ }
+
+ if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
+ tmp += sizeof(PROTO_NONE);
+ mask = 0;
+ count++;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+ tmp += strlen(proto_names[i].name);
+ mask = proto_names[i].type;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(proto_names)) {
+ IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+ return -EINVAL;
+ }
+ count++;
+ }
+
+ if (enable)
+ type |= mask;
+ else if (disable)
+ type &= ~mask;
+ else
+ type = mask;
+ }
+
+ if (!count) {
+ IR_dprintk(1, "Protocol not specified\n");
+ return -EINVAL;
+ }
+
+ if (dev->change_protocol) {
+ rc = dev->change_protocol(dev, type);
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+ (long long)type);
+ return -EINVAL;
+ }
+ }
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE) {
+ spin_lock_irqsave(&dev->rc_map.lock, flags);
+ dev->rc_map.rc_type = type;
+ spin_unlock_irqrestore(&dev->rc_map.lock, flags);
+ } else {
+ dev->raw->enabled_protocols = type;
+ }
+
+ IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+ (long long)type);
+
+ return len;
+}
+
+static void rc_dev_release(struct device *device)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+
+ kfree(dev);
+ module_put(THIS_MODULE);
+}
+
+#define ADD_HOTPLUG_VAR(fmt, val...) \
+ do { \
+ int err = add_uevent_var(env, fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+
+ if (dev->rc_map.name)
+ ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
+ if (dev->driver_name)
+ ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
+
+ return 0;
+}
+
+/*
+ * Static device attribute struct with the sysfs attributes for IR's
+ */
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols);
+
+static struct attribute *rc_dev_attrs[] = {
+ &dev_attr_protocols.attr,
+ NULL,
+};
+
+static struct attribute_group rc_dev_attr_grp = {
+ .attrs = rc_dev_attrs,
+};
+
+static const struct attribute_group *rc_dev_attr_groups[] = {
+ &rc_dev_attr_grp,
+ NULL
+};
+
+static struct device_type rc_dev_type = {
+ .groups = rc_dev_attr_groups,
+ .release = rc_dev_release,
+ .uevent = rc_dev_uevent,
+};
+
+struct rc_dev *rc_allocate_device(void)
+{
+ struct rc_dev *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->input_dev = input_allocate_device();
+ if (!dev->input_dev) {
+ kfree(dev);
+ return NULL;
+ }
+
+ dev->input_dev->getkeycode_new = ir_getkeycode;
+ dev->input_dev->setkeycode_new = ir_setkeycode;
+ input_set_drvdata(dev->input_dev, dev);
+
+ spin_lock_init(&dev->rc_map.lock);
+ spin_lock_init(&dev->keylock);
+ setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
+
+ dev->dev.type = &rc_dev_type;
+ dev->dev.class = &ir_input_class;
+ device_initialize(&dev->dev);
+
+ __module_get(THIS_MODULE);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(rc_allocate_device);
+
+void rc_free_device(struct rc_dev *dev)
+{
+ if (dev) {
+ input_free_device(dev->input_dev);
+ put_device(&dev->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(rc_free_device);
+
+int rc_register_device(struct rc_dev *dev)
+{
+ static atomic_t devno = ATOMIC_INIT(0);
+ struct rc_map *rc_map;
+ const char *path;
+ int rc;
+
+ if (!dev || !dev->map_name)
+ return -EINVAL;
+
+ rc_map = rc_map_get(dev->map_name);
+ if (!rc_map)
+ rc_map = rc_map_get(RC_MAP_EMPTY);
+ if (!rc_map || !rc_map->scan || rc_map->size == 0)
+ return -EINVAL;
+
+ set_bit(EV_KEY, dev->input_dev->evbit);
+ set_bit(EV_REP, dev->input_dev->evbit);
+ set_bit(EV_MSC, dev->input_dev->evbit);
+ set_bit(MSC_SCAN, dev->input_dev->mscbit);
+ if (dev->open)
+ dev->input_dev->open = ir_open;
+ if (dev->close)
+ dev->input_dev->close = ir_close;
+
+ dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
+ dev_set_name(&dev->dev, "rc%ld", dev->devno);
+ dev_set_drvdata(&dev->dev, dev);
+ rc = device_add(&dev->dev);
+ if (rc)
+ return rc;
+
+ rc = ir_setkeytable(dev, rc_map);
+ if (rc)
+ goto out_dev;
+
+ dev->input_dev->dev.parent = &dev->dev;
+ memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
+ dev->input_dev->phys = dev->input_phys;
+ dev->input_dev->name = dev->input_name;
+ rc = input_register_device(dev->input_dev);
+ if (rc)
+ goto out_table;
+
+ /*
+ * Default delay of 250ms is too short for some protocols, expecially
+ * since the timeout is currently set to 250ms. Increase it to 500ms,
+ * to avoid wrong repetition of the keycodes. Note that this must be
+ * set after the call to input_register_device().
+ */
+ dev->input_dev->rep[REP_DELAY] = 500;
+
+ path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
+ printk(KERN_INFO "%s: %s as %s\n",
+ dev_name(&dev->dev),
+ dev->input_name ? dev->input_name : "Unspecified device",
+ path ? path : "N/A");
+ kfree(path);
+
+ if (dev->driver_type == RC_DRIVER_IR_RAW) {
+ rc = ir_raw_event_register(dev);
+ if (rc < 0)
+ goto out_input;
+ }
+
+ if (dev->change_protocol) {
+ rc = dev->change_protocol(dev, rc_map->rc_type);
+ if (rc < 0)
+ goto out_raw;
+ }
+
+ IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
+ dev->devno,
+ dev->driver_name ? dev->driver_name : "unknown",
+ rc_map->name ? rc_map->name : "unknown",
+ dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
+
+ return 0;
+
+out_raw:
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_event_unregister(dev);
+out_input:
+ input_unregister_device(dev->input_dev);
+ dev->input_dev = NULL;
+out_table:
+ ir_free_table(&dev->rc_map);
+out_dev:
+ device_del(&dev->dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rc_register_device);
+
+void rc_unregister_device(struct rc_dev *dev)
+{
+ if (!dev)
+ return;
+
+ del_timer_sync(&dev->timer_keyup);
+
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_event_unregister(dev);
+
+ input_unregister_device(dev->input_dev);
+ dev->input_dev = NULL;
+
+ ir_free_table(&dev->rc_map);
+ IR_dprintk(1, "Freed keycode table\n");
+
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(rc_unregister_device);
+
+/*
+ * Init/exit code for the module. Basically, creates/removes /sys/class/rc
+ */
+
+static int __init rc_core_init(void)
+{
+ int rc = class_register(&ir_input_class);
+ if (rc) {
+ printk(KERN_ERR "rc_core: unable to register rc class\n");
+ return rc;
+ }
+
+ /* Initialize/load the decoders/keymap code that will be used */
+ ir_raw_init();
+ rc_map_register(&empty_map);
+
+ return 0;
+}
+
+static void __exit rc_core_exit(void)
+{
+ class_unregister(&ir_input_class);
+ rc_map_unregister(&empty_map);
+}
+
+module_init(rc_core_init);
+module_exit(rc_core_exit);
+
+int rc_core_debug; /* ir_debug level (0,1,2) */
+EXPORT_SYMBOL_GPL(rc_core_debug);
+module_param_named(debug, rc_core_debug, int, 0644);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/IR/streamzap.c b/drivers/media/rc/streamzap.c
index 548381c35bfd..6e2911c2abfb 100644
--- a/drivers/media/IR/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -35,8 +35,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
-#include <linux/input.h>
-#include <media/ir-core.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
#define DRIVER_VERSION "1.61"
#define DRIVER_NAME "streamzap"
@@ -73,7 +73,7 @@ MODULE_DEVICE_TABLE(usb, streamzap_table);
#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
#else
-#define load_rc5_sz_decode() 0
+#define load_rc5_sz_decode() {}
#endif
enum StreamzapDecoderState {
@@ -85,13 +85,11 @@ enum StreamzapDecoderState {
/* structure to hold our device specific stuff */
struct streamzap_ir {
-
/* ir-core */
- struct ir_dev_props *props;
+ struct rc_dev *rdev;
/* core device info */
struct device *dev;
- struct input_dev *idev;
/* usb */
struct usb_device *usbdev;
@@ -140,7 +138,9 @@ static struct usb_driver streamzap_driver = {
static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
{
- ir_raw_event_store(sz->idev, &rawir);
+ dev_dbg(sz->dev, "Storing %s with duration %u us\n",
+ (rawir.pulse ? "pulse" : "space"), rawir.duration);
+ ir_raw_event_store_with_filter(sz->rdev, &rawir);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
@@ -167,7 +167,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
}
- dev_dbg(sz->dev, "ls %u\n", rawir.duration);
sz_push(sz, rawir);
sz->idle = false;
@@ -180,7 +179,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
sz->sum += rawir.duration;
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
- dev_dbg(sz->dev, "p %u\n", rawir.duration);
sz_push(sz, rawir);
}
@@ -200,7 +198,6 @@ static void sz_push_full_space(struct streamzap_ir *sz,
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
rawir.duration *= 1000;
- dev_dbg(sz->dev, "s %u\n", rawir.duration);
sz_push(sz, rawir);
}
@@ -221,8 +218,6 @@ static void streamzap_callback(struct urb *urb)
struct streamzap_ir *sz;
unsigned int i;
int len;
- static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
- IR_MAX_DURATION) | 0x03000000);
if (!urb)
return;
@@ -246,7 +241,7 @@ static void streamzap_callback(struct urb *urb)
dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
for (i = 0; i < len; i++) {
- dev_dbg(sz->dev, "sz idx %d: %x\n",
+ dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n",
i, (unsigned char)sz->buf_in[i]);
switch (sz->decoder_state) {
case PulseSpace:
@@ -273,11 +268,11 @@ static void streamzap_callback(struct urb *urb)
DEFINE_IR_RAW_EVENT(rawir);
rawir.pulse = false;
- rawir.duration = timeout;
+ rawir.duration = sz->rdev->timeout;
sz->idle = true;
if (sz->timeout_enabled)
sz_push(sz, rawir);
- ir_raw_event_handle(sz->idev);
+ ir_raw_event_handle(sz->rdev);
} else {
sz_push_full_space(sz, sz->buf_in[i]);
}
@@ -300,54 +295,45 @@ static void streamzap_callback(struct urb *urb)
return;
}
-static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
+static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
{
- struct input_dev *idev;
- struct ir_dev_props *props;
+ struct rc_dev *rdev;
struct device *dev = sz->dev;
int ret;
- idev = input_allocate_device();
- if (!idev) {
- dev_err(dev, "remote input dev allocation failed\n");
- goto idev_alloc_failed;
- }
-
- props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
- if (!props) {
- dev_err(dev, "remote ir dev props allocation failed\n");
- goto props_alloc_failed;
+ rdev = rc_allocate_device();
+ if (!rdev) {
+ dev_err(dev, "remote dev allocation failed\n");
+ goto out;
}
snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared "
"Receiver (%04x:%04x)",
le16_to_cpu(sz->usbdev->descriptor.idVendor),
le16_to_cpu(sz->usbdev->descriptor.idProduct));
-
- idev->name = sz->name;
usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
strlcat(sz->phys, "/input0", sizeof(sz->phys));
- idev->phys = sz->phys;
-
- props->priv = sz;
- props->driver_type = RC_DRIVER_IR_RAW;
- props->allowed_protos = IR_TYPE_ALL;
- sz->props = props;
-
- ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
+ rdev->input_name = sz->name;
+ rdev->input_phys = sz->phys;
+ usb_to_input_id(sz->usbdev, &rdev->input_id);
+ rdev->dev.parent = dev;
+ rdev->priv = sz;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->driver_name = DRIVER_NAME;
+ rdev->map_name = RC_MAP_STREAMZAP;
+
+ ret = rc_register_device(rdev);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
- goto irdev_failed;
+ goto out;
}
- return idev;
+ return rdev;
-irdev_failed:
- kfree(props);
-props_alloc_failed:
- input_free_device(idev);
-idev_alloc_failed:
+out:
+ rc_free_device(rdev);
return NULL;
}
@@ -436,14 +422,16 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
- sz->idev = streamzap_init_input_dev(sz);
- if (!sz->idev)
- goto input_dev_fail;
+ sz->rdev = streamzap_init_rc_dev(sz);
+ if (!sz->rdev)
+ goto rc_dev_fail;
sz->idle = true;
sz->decoder_state = PulseSpace;
/* FIXME: don't yet have a way to set this */
sz->timeout_enabled = true;
+ sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
+ IR_MAX_DURATION) | 0x03000000);
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
@@ -473,7 +461,7 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
return 0;
-input_dev_fail:
+rc_dev_fail:
usb_free_urb(sz->urb_in);
free_buf_in:
usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
@@ -504,7 +492,7 @@ static void streamzap_disconnect(struct usb_interface *interface)
return;
sz->usbdev = NULL;
- ir_input_unregister(sz->idev);
+ rc_unregister_device(sz->rdev);
usb_kill_urb(sz->urb_in);
usb_free_urb(sz->urb_in);
usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
diff --git a/drivers/input/misc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 64f1de7960c6..186de5522001 100644
--- a/drivers/input/misc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -7,10 +7,10 @@
* with minor modifications.
*
* Original Author: David Härdeman <david@hardeman.nu>
- * Copyright (C) 2009 David Härdeman <david@hardeman.nu>
+ * Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu>
*
- * Dedicated to Matilda, my newborn daughter, without whose loving attention
- * this driver would have been finished in half the time and with a fraction
+ * Dedicated to my daughter Matilda, without whose loving attention this
+ * driver would have been finished in half the time and with a fraction
* of the bugs.
*
* Written using:
@@ -19,15 +19,11 @@
* o DSDT dumps
*
* Supported features:
- * o RC6
* o Wake-On-CIR functionality
*
* To do:
- * o Test NEC and RC5
- *
- * Left as an exercise for the reader:
- * o Learning (I have neither the hardware, nor the need)
- * o IR Transmit (ibid)
+ * o Learning
+ * o IR Transmit
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,15 +44,13 @@
#include <linux/pnp.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#include <linux/input.h>
#include <linux/leds.h>
-#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/pci_ids.h>
#include <linux/io.h>
#include <linux/bitrev.h>
-#include <linux/bitops.h>
#include <linux/slab.h>
+#include <media/rc-core.h>
#define DRVNAME "winbond-cir"
@@ -108,7 +102,7 @@
#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */
/* Bank 6 */
#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */
-#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */
+#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */
/* Bank 7 */
#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */
#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */
@@ -153,7 +147,7 @@ enum wbcir_bank {
WBCIR_BANK_7 = 0xF4,
};
-/* Supported IR Protocols */
+/* Supported power-on IR Protocols */
enum wbcir_protocol {
IR_PROTOCOL_RC5 = 0x0,
IR_PROTOCOL_NEC = 0x1,
@@ -164,113 +158,35 @@ enum wbcir_protocol {
#define WBCIR_NAME "Winbond CIR"
#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */
#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */
-#define IR_KEYPRESS_TIMEOUT 250 /* FIXME: should be per-protocol? */
#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */
#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */
#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */
#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */
-#define WBCIR_MAX_IDLE_BYTES 10
-
-static DEFINE_SPINLOCK(wbcir_lock);
-static DEFINE_RWLOCK(keytable_lock);
-struct wbcir_key {
- u32 scancode;
- unsigned int keycode;
-};
-
-struct wbcir_keyentry {
- struct wbcir_key key;
- struct list_head list;
-};
-
-static struct wbcir_key rc6_def_keymap[] = {
- { 0x800F0400, KEY_NUMERIC_0 },
- { 0x800F0401, KEY_NUMERIC_1 },
- { 0x800F0402, KEY_NUMERIC_2 },
- { 0x800F0403, KEY_NUMERIC_3 },
- { 0x800F0404, KEY_NUMERIC_4 },
- { 0x800F0405, KEY_NUMERIC_5 },
- { 0x800F0406, KEY_NUMERIC_6 },
- { 0x800F0407, KEY_NUMERIC_7 },
- { 0x800F0408, KEY_NUMERIC_8 },
- { 0x800F0409, KEY_NUMERIC_9 },
- { 0x800F041D, KEY_NUMERIC_STAR },
- { 0x800F041C, KEY_NUMERIC_POUND },
- { 0x800F0410, KEY_VOLUMEUP },
- { 0x800F0411, KEY_VOLUMEDOWN },
- { 0x800F0412, KEY_CHANNELUP },
- { 0x800F0413, KEY_CHANNELDOWN },
- { 0x800F040E, KEY_MUTE },
- { 0x800F040D, KEY_VENDOR }, /* Vista Logo Key */
- { 0x800F041E, KEY_UP },
- { 0x800F041F, KEY_DOWN },
- { 0x800F0420, KEY_LEFT },
- { 0x800F0421, KEY_RIGHT },
- { 0x800F0422, KEY_OK },
- { 0x800F0423, KEY_ESC },
- { 0x800F040F, KEY_INFO },
- { 0x800F040A, KEY_CLEAR },
- { 0x800F040B, KEY_ENTER },
- { 0x800F045B, KEY_RED },
- { 0x800F045C, KEY_GREEN },
- { 0x800F045D, KEY_YELLOW },
- { 0x800F045E, KEY_BLUE },
- { 0x800F045A, KEY_TEXT },
- { 0x800F0427, KEY_SWITCHVIDEOMODE },
- { 0x800F040C, KEY_POWER },
- { 0x800F0450, KEY_RADIO },
- { 0x800F0448, KEY_PVR },
- { 0x800F0447, KEY_AUDIO },
- { 0x800F0426, KEY_EPG },
- { 0x800F0449, KEY_CAMERA },
- { 0x800F0425, KEY_TV },
- { 0x800F044A, KEY_VIDEO },
- { 0x800F0424, KEY_DVD },
- { 0x800F0416, KEY_PLAY },
- { 0x800F0418, KEY_PAUSE },
- { 0x800F0419, KEY_STOP },
- { 0x800F0414, KEY_FASTFORWARD },
- { 0x800F041A, KEY_NEXT },
- { 0x800F041B, KEY_PREVIOUS },
- { 0x800F0415, KEY_REWIND },
- { 0x800F0417, KEY_RECORD },
-};
-
-/* Registers and other state is protected by wbcir_lock */
+/* Per-device data */
struct wbcir_data {
+ spinlock_t spinlock;
+
unsigned long wbase; /* Wake-Up Baseaddr */
unsigned long ebase; /* Enhanced Func. Baseaddr */
unsigned long sbase; /* Serial Port Baseaddr */
unsigned int irq; /* Serial Port IRQ */
- struct input_dev *input_dev;
- struct timer_list timer_keyup;
+ struct rc_dev *dev;
+
struct led_trigger *rxtrigger;
struct led_trigger *txtrigger;
struct led_classdev led;
- u32 last_scancode;
- unsigned int last_keycode;
- u8 last_toggle;
- u8 keypressed;
- unsigned long keyup_jiffies;
- unsigned int idle_count;
-
- /* RX irdata and parsing state */
- unsigned long irdata[30];
- unsigned int irdata_count;
- unsigned int irdata_idle;
- unsigned int irdata_off;
- unsigned int irdata_error;
-
- /* Protected by keytable_lock */
- struct list_head keytable;
+ /* RX irdata state */
+ bool irdata_active;
+ bool irdata_error;
+ struct ir_raw_event ev;
};
static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
module_param(protocol, uint, 0444);
-MODULE_PARM_DESC(protocol, "IR protocol to use "
+MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command "
"(0 = RC5, 1 = NEC, 2 = RC6A, default)");
static int invert; /* default = 0 */
@@ -327,7 +243,7 @@ wbcir_led_brightness_get(struct led_classdev *led_cdev)
static void
wbcir_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+ enum led_brightness brightness)
{
struct wbcir_data *data = container_of(led_cdev,
struct wbcir_data,
@@ -338,7 +254,7 @@ wbcir_led_brightness_set(struct led_classdev *led_cdev,
WBCIR_LED_ENABLE);
}
-/* Manchester encodes bits to RC6 message cells (see wbcir_parse_rc6) */
+/* Manchester encodes bits to RC6 message cells (see wbcir_shutdown) */
static u8
wbcir_to_rc6cells(u8 val)
{
@@ -357,579 +273,6 @@ wbcir_to_rc6cells(u8 val)
return coded;
}
-
-
-/*****************************************************************************
- *
- * INPUT FUNCTIONS
- *
- *****************************************************************************/
-
-static unsigned int
-wbcir_do_getkeycode(struct wbcir_data *data, u32 scancode)
-{
- struct wbcir_keyentry *keyentry;
- unsigned int keycode = KEY_RESERVED;
- unsigned long flags;
-
- read_lock_irqsave(&keytable_lock, flags);
-
- list_for_each_entry(keyentry, &data->keytable, list) {
- if (keyentry->key.scancode == scancode) {
- keycode = keyentry->key.keycode;
- break;
- }
- }
-
- read_unlock_irqrestore(&keytable_lock, flags);
- return keycode;
-}
-
-static int
-wbcir_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct wbcir_data *data = input_get_drvdata(dev);
-
- *keycode = wbcir_do_getkeycode(data, scancode);
- return 0;
-}
-
-static int
-wbcir_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct wbcir_data *data = input_get_drvdata(dev);
- struct wbcir_keyentry *keyentry;
- struct wbcir_keyentry *new_keyentry;
- unsigned long flags;
- unsigned int old_keycode = KEY_RESERVED;
-
- new_keyentry = kmalloc(sizeof(*new_keyentry), GFP_KERNEL);
- if (!new_keyentry)
- return -ENOMEM;
-
- write_lock_irqsave(&keytable_lock, flags);
-
- list_for_each_entry(keyentry, &data->keytable, list) {
- if (keyentry->key.scancode != scancode)
- continue;
-
- old_keycode = keyentry->key.keycode;
- keyentry->key.keycode = keycode;
-
- if (keyentry->key.keycode == KEY_RESERVED) {
- list_del(&keyentry->list);
- kfree(keyentry);
- }
-
- break;
- }
-
- set_bit(keycode, dev->keybit);
-
- if (old_keycode == KEY_RESERVED) {
- new_keyentry->key.scancode = scancode;
- new_keyentry->key.keycode = keycode;
- list_add(&new_keyentry->list, &data->keytable);
- } else {
- kfree(new_keyentry);
- clear_bit(old_keycode, dev->keybit);
- list_for_each_entry(keyentry, &data->keytable, list) {
- if (keyentry->key.keycode == old_keycode) {
- set_bit(old_keycode, dev->keybit);
- break;
- }
- }
- }
-
- write_unlock_irqrestore(&keytable_lock, flags);
- return 0;
-}
-
-/*
- * Timer function to report keyup event some time after keydown is
- * reported by the ISR.
- */
-static void
-wbcir_keyup(unsigned long cookie)
-{
- struct wbcir_data *data = (struct wbcir_data *)cookie;
- unsigned long flags;
-
- /*
- * data->keyup_jiffies is used to prevent a race condition if a
- * hardware interrupt occurs at this point and the keyup timer
- * event is moved further into the future as a result.
- *
- * The timer will then be reactivated and this function called
- * again in the future. We need to exit gracefully in that case
- * to allow the input subsystem to do its auto-repeat magic or
- * a keyup event might follow immediately after the keydown.
- */
-
- spin_lock_irqsave(&wbcir_lock, flags);
-
- if (time_is_after_eq_jiffies(data->keyup_jiffies) && data->keypressed) {
- data->keypressed = 0;
- led_trigger_event(data->rxtrigger, LED_OFF);
- input_report_key(data->input_dev, data->last_keycode, 0);
- input_sync(data->input_dev);
- }
-
- spin_unlock_irqrestore(&wbcir_lock, flags);
-}
-
-static void
-wbcir_keydown(struct wbcir_data *data, u32 scancode, u8 toggle)
-{
- unsigned int keycode;
-
- /* Repeat? */
- if (data->last_scancode == scancode &&
- data->last_toggle == toggle &&
- data->keypressed)
- goto set_timer;
- data->last_scancode = scancode;
-
- /* Do we need to release an old keypress? */
- if (data->keypressed) {
- input_report_key(data->input_dev, data->last_keycode, 0);
- input_sync(data->input_dev);
- data->keypressed = 0;
- }
-
- /* Report scancode */
- input_event(data->input_dev, EV_MSC, MSC_SCAN, (int)scancode);
-
- /* Do we know this scancode? */
- keycode = wbcir_do_getkeycode(data, scancode);
- if (keycode == KEY_RESERVED)
- goto set_timer;
-
- /* Register a keypress */
- input_report_key(data->input_dev, keycode, 1);
- data->keypressed = 1;
- data->last_keycode = keycode;
- data->last_toggle = toggle;
-
-set_timer:
- input_sync(data->input_dev);
- led_trigger_event(data->rxtrigger,
- data->keypressed ? LED_FULL : LED_OFF);
- data->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&data->timer_keyup, data->keyup_jiffies);
-}
-
-
-
-/*****************************************************************************
- *
- * IR PARSING FUNCTIONS
- *
- *****************************************************************************/
-
-/* Resets all irdata */
-static void
-wbcir_reset_irdata(struct wbcir_data *data)
-{
- memset(data->irdata, 0, sizeof(data->irdata));
- data->irdata_count = 0;
- data->irdata_off = 0;
- data->irdata_error = 0;
- data->idle_count = 0;
-}
-
-/* Adds one bit of irdata */
-static void
-add_irdata_bit(struct wbcir_data *data, int set)
-{
- if (data->irdata_count >= sizeof(data->irdata) * 8) {
- data->irdata_error = 1;
- return;
- }
-
- if (set)
- __set_bit(data->irdata_count, data->irdata);
- data->irdata_count++;
-}
-
-/* Gets count bits of irdata */
-static u16
-get_bits(struct wbcir_data *data, int count)
-{
- u16 val = 0x0;
-
- if (data->irdata_count - data->irdata_off < count) {
- data->irdata_error = 1;
- return 0x0;
- }
-
- while (count > 0) {
- val <<= 1;
- if (test_bit(data->irdata_off, data->irdata))
- val |= 0x1;
- count--;
- data->irdata_off++;
- }
-
- return val;
-}
-
-/* Reads 16 cells and converts them to a byte */
-static u8
-wbcir_rc6cells_to_byte(struct wbcir_data *data)
-{
- u16 raw = get_bits(data, 16);
- u8 val = 0x00;
- int bit;
-
- for (bit = 0; bit < 8; bit++) {
- switch (raw & 0x03) {
- case 0x01:
- break;
- case 0x02:
- val |= (0x01 << bit);
- break;
- default:
- data->irdata_error = 1;
- break;
- }
- raw >>= 2;
- }
-
- return val;
-}
-
-/* Decodes a number of bits from raw RC5 data */
-static u8
-wbcir_get_rc5bits(struct wbcir_data *data, unsigned int count)
-{
- u16 raw = get_bits(data, count * 2);
- u8 val = 0x00;
- int bit;
-
- for (bit = 0; bit < count; bit++) {
- switch (raw & 0x03) {
- case 0x01:
- val |= (0x01 << bit);
- break;
- case 0x02:
- break;
- default:
- data->irdata_error = 1;
- break;
- }
- raw >>= 2;
- }
-
- return val;
-}
-
-static void
-wbcir_parse_rc6(struct device *dev, struct wbcir_data *data)
-{
- /*
- * Normal bits are manchester coded as follows:
- * cell0 + cell1 = logic "0"
- * cell1 + cell0 = logic "1"
- *
- * The IR pulse has the following components:
- *
- * Leader - 6 * cell1 - discarded
- * Gap - 2 * cell0 - discarded
- * Start bit - Normal Coding - always "1"
- * Mode Bit 2 - 0 - Normal Coding
- * Toggle bit - Normal Coding with double bit time,
- * e.g. cell0 + cell0 + cell1 + cell1
- * means logic "0".
- *
- * The rest depends on the mode, the following modes are known:
- *
- * MODE 0:
- * Address Bit 7 - 0 - Normal Coding
- * Command Bit 7 - 0 - Normal Coding
- *
- * MODE 6:
- * The above Toggle Bit is used as a submode bit, 0 = A, 1 = B.
- * Submode B is for pointing devices, only remotes using submode A
- * are supported.
- *
- * Customer range bit - 0 => Customer = 7 bits, 0...127
- * 1 => Customer = 15 bits, 32768...65535
- * Customer Bits - Normal Coding
- *
- * Customer codes are allocated by Philips. The rest of the bits
- * are customer dependent. The following is commonly used (and the
- * only supported config):
- *
- * Toggle Bit - Normal Coding
- * Address Bit 6 - 0 - Normal Coding
- * Command Bit 7 - 0 - Normal Coding
- *
- * All modes are followed by at least 6 * cell0.
- *
- * MODE 0 msglen:
- * 1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (toggle) +
- * 8 * 2 (address) + 8 * 2 (command) =
- * 44 cells
- *
- * MODE 6A msglen:
- * 1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (submode) +
- * 1 * 2 (customer range bit) + 7/15 * 2 (customer bits) +
- * 1 * 2 (toggle bit) + 7 * 2 (address) + 8 * 2 (command) =
- * 60 - 76 cells
- */
- u8 mode;
- u8 toggle;
- u16 customer = 0x0;
- u8 address;
- u8 command;
- u32 scancode;
-
- /* Leader mark */
- while (get_bits(data, 1) && !data->irdata_error)
- /* Do nothing */;
-
- /* Leader space */
- if (get_bits(data, 1)) {
- dev_dbg(dev, "RC6 - Invalid leader space\n");
- return;
- }
-
- /* Start bit */
- if (get_bits(data, 2) != 0x02) {
- dev_dbg(dev, "RC6 - Invalid start bit\n");
- return;
- }
-
- /* Mode */
- mode = get_bits(data, 6);
- switch (mode) {
- case 0x15: /* 010101 = b000 */
- mode = 0;
- break;
- case 0x29: /* 101001 = b110 */
- mode = 6;
- break;
- default:
- dev_dbg(dev, "RC6 - Invalid mode\n");
- return;
- }
-
- /* Toggle bit / Submode bit */
- toggle = get_bits(data, 4);
- switch (toggle) {
- case 0x03:
- toggle = 0;
- break;
- case 0x0C:
- toggle = 1;
- break;
- default:
- dev_dbg(dev, "RC6 - Toggle bit error\n");
- break;
- }
-
- /* Customer */
- if (mode == 6) {
- if (toggle != 0) {
- dev_dbg(dev, "RC6B - Not Supported\n");
- return;
- }
-
- customer = wbcir_rc6cells_to_byte(data);
-
- if (customer & 0x80) {
- /* 15 bit customer value */
- customer <<= 8;
- customer |= wbcir_rc6cells_to_byte(data);
- }
- }
-
- /* Address */
- address = wbcir_rc6cells_to_byte(data);
- if (mode == 6) {
- toggle = address >> 7;
- address &= 0x7F;
- }
-
- /* Command */
- command = wbcir_rc6cells_to_byte(data);
-
- /* Create scancode */
- scancode = command;
- scancode |= address << 8;
- scancode |= customer << 16;
-
- /* Last sanity check */
- if (data->irdata_error) {
- dev_dbg(dev, "RC6 - Cell error(s)\n");
- return;
- }
-
- dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X "
- "toggle %u mode %u scan 0x%08X\n",
- address,
- command,
- customer,
- (unsigned int)toggle,
- (unsigned int)mode,
- scancode);
-
- wbcir_keydown(data, scancode, toggle);
-}
-
-static void
-wbcir_parse_rc5(struct device *dev, struct wbcir_data *data)
-{
- /*
- * Bits are manchester coded as follows:
- * cell1 + cell0 = logic "0"
- * cell0 + cell1 = logic "1"
- * (i.e. the reverse of RC6)
- *
- * Start bit 1 - "1" - discarded
- * Start bit 2 - Must be inverted to get command bit 6
- * Toggle bit
- * Address Bit 4 - 0
- * Command Bit 5 - 0
- */
- u8 toggle;
- u8 address;
- u8 command;
- u32 scancode;
-
- /* Start bit 1 */
- if (!get_bits(data, 1)) {
- dev_dbg(dev, "RC5 - Invalid start bit\n");
- return;
- }
-
- /* Start bit 2 */
- if (!wbcir_get_rc5bits(data, 1))
- command = 0x40;
- else
- command = 0x00;
-
- toggle = wbcir_get_rc5bits(data, 1);
- address = wbcir_get_rc5bits(data, 5);
- command |= wbcir_get_rc5bits(data, 6);
- scancode = address << 7 | command;
-
- /* Last sanity check */
- if (data->irdata_error) {
- dev_dbg(dev, "RC5 - Invalid message\n");
- return;
- }
-
- dev_dbg(dev, "IR-RC5 ad %u cm %u t %u s %u\n",
- (unsigned int)address,
- (unsigned int)command,
- (unsigned int)toggle,
- (unsigned int)scancode);
-
- wbcir_keydown(data, scancode, toggle);
-}
-
-static void
-wbcir_parse_nec(struct device *dev, struct wbcir_data *data)
-{
- /*
- * Each bit represents 560 us.
- *
- * Leader - 9 ms burst
- * Gap - 4.5 ms silence
- * Address1 bit 0 - 7 - Address 1
- * Address2 bit 0 - 7 - Address 2
- * Command1 bit 0 - 7 - Command 1
- * Command2 bit 0 - 7 - Command 2
- *
- * Note the bit order!
- *
- * With the old NEC protocol, Address2 was the inverse of Address1
- * and Command2 was the inverse of Command1 and were used as
- * an error check.
- *
- * With NEC extended, Address1 is the LSB of the Address and
- * Address2 is the MSB, Command parsing remains unchanged.
- *
- * A repeat message is coded as:
- * Leader - 9 ms burst
- * Gap - 2.25 ms silence
- * Repeat - 560 us active
- */
- u8 address1;
- u8 address2;
- u8 command1;
- u8 command2;
- u16 address;
- u32 scancode;
-
- /* Leader mark */
- while (get_bits(data, 1) && !data->irdata_error)
- /* Do nothing */;
-
- /* Leader space */
- if (get_bits(data, 4)) {
- dev_dbg(dev, "NEC - Invalid leader space\n");
- return;
- }
-
- /* Repeat? */
- if (get_bits(data, 1)) {
- if (!data->keypressed) {
- dev_dbg(dev, "NEC - Stray repeat message\n");
- return;
- }
-
- dev_dbg(dev, "IR-NEC repeat s %u\n",
- (unsigned int)data->last_scancode);
-
- wbcir_keydown(data, data->last_scancode, data->last_toggle);
- return;
- }
-
- /* Remaining leader space */
- if (get_bits(data, 3)) {
- dev_dbg(dev, "NEC - Invalid leader space\n");
- return;
- }
-
- address1 = bitrev8(get_bits(data, 8));
- address2 = bitrev8(get_bits(data, 8));
- command1 = bitrev8(get_bits(data, 8));
- command2 = bitrev8(get_bits(data, 8));
-
- /* Sanity check */
- if (data->irdata_error) {
- dev_dbg(dev, "NEC - Invalid message\n");
- return;
- }
-
- /* Check command validity */
- if (command1 != ~command2) {
- dev_dbg(dev, "NEC - Command bytes mismatch\n");
- return;
- }
-
- /* Check for extended NEC protocol */
- address = address1;
- if (address1 != ~address2)
- address |= address2 << 8;
-
- scancode = address << 8 | command1;
-
- dev_dbg(dev, "IR-NEC ad %u cm %u s %u\n",
- (unsigned int)address,
- (unsigned int)command1,
- (unsigned int)scancode);
-
- wbcir_keydown(data, scancode, !data->last_toggle);
-}
-
-
-
/*****************************************************************************
*
* INTERRUPT FUNCTIONS
@@ -941,75 +284,88 @@ wbcir_irq_handler(int irqno, void *cookie)
{
struct pnp_dev *device = cookie;
struct wbcir_data *data = pnp_get_drvdata(device);
- struct device *dev = &device->dev;
- u8 status;
unsigned long flags;
u8 irdata[8];
+ u8 disable = true;
+ u8 status;
int i;
- unsigned int hw;
- spin_lock_irqsave(&wbcir_lock, flags);
+ spin_lock_irqsave(&data->spinlock, flags);
wbcir_select_bank(data, WBCIR_BANK_0);
status = inb(data->sbase + WBCIR_REG_SP3_EIR);
if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) {
- spin_unlock_irqrestore(&wbcir_lock, flags);
+ spin_unlock_irqrestore(&data->spinlock, flags);
return IRQ_NONE;
}
- if (status & WBCIR_IRQ_ERR)
- data->irdata_error = 1;
+ /* Check for e.g. buffer overflow */
+ if (status & WBCIR_IRQ_ERR) {
+ data->irdata_error = true;
+ ir_raw_event_reset(data->dev);
+ }
if (!(status & WBCIR_IRQ_RX))
goto out;
+ if (!data->irdata_active) {
+ data->irdata_active = true;
+ led_trigger_event(data->rxtrigger, LED_FULL);
+ }
+
/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8);
- for (i = 0; i < sizeof(irdata); i++) {
- hw = hweight8(irdata[i]);
- if (hw > 4)
- add_irdata_bit(data, 0);
- else
- add_irdata_bit(data, 1);
+ for (i = 0; i < 8; i++) {
+ u8 pulse;
+ u32 duration;
- if (hw == 8)
- data->idle_count++;
- else
- data->idle_count = 0;
+ if (irdata[i] != 0xFF && irdata[i] != 0x00)
+ disable = false;
+
+ if (data->irdata_error)
+ continue;
+
+ pulse = irdata[i] & 0x80 ? false : true;
+ duration = (irdata[i] & 0x7F) * 10000; /* ns */
+
+ if (data->ev.pulse != pulse) {
+ if (data->ev.duration != 0) {
+ ir_raw_event_store(data->dev, &data->ev);
+ data->ev.duration = 0;
+ }
+
+ data->ev.pulse = pulse;
+ }
+
+ data->ev.duration += duration;
}
- if (data->idle_count > WBCIR_MAX_IDLE_BYTES) {
- /* Set RXINACTIVE... */
+ if (disable) {
+ if (data->ev.duration != 0 && !data->irdata_error) {
+ ir_raw_event_store(data->dev, &data->ev);
+ data->ev.duration = 0;
+ }
+
+ /* Set RXINACTIVE */
outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
- /* ...and drain the FIFO */
+ /* Drain the FIFO */
while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL)
inb(data->sbase + WBCIR_REG_SP3_RXDATA);
- dev_dbg(dev, "IRDATA:\n");
- for (i = 0; i < data->irdata_count; i += BITS_PER_LONG)
- dev_dbg(dev, "0x%08lX\n", data->irdata[i/BITS_PER_LONG]);
-
- switch (protocol) {
- case IR_PROTOCOL_RC5:
- wbcir_parse_rc5(dev, data);
- break;
- case IR_PROTOCOL_RC6:
- wbcir_parse_rc6(dev, data);
- break;
- case IR_PROTOCOL_NEC:
- wbcir_parse_nec(dev, data);
- break;
- }
-
- wbcir_reset_irdata(data);
+ ir_raw_event_reset(data->dev);
+ data->irdata_error = false;
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
}
+ ir_raw_event_handle(data->dev);
+
out:
- spin_unlock_irqrestore(&wbcir_lock, flags);
+ spin_unlock_irqrestore(&data->spinlock, flags);
return IRQ_HANDLED;
}
@@ -1199,6 +555,10 @@ finish:
wbcir_select_bank(data, WBCIR_BANK_0);
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+ /* Disable LED */
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
+
/*
* ACPI will set the HW disable bit for SP3 which means that the
* output signals are left in an undefined state which may cause
@@ -1323,8 +683,15 @@ wbcir_init_hw(struct wbcir_data *data)
/* Clear AUX status bits */
outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
+ /* Clear IR decoding state */
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
+ data->irdata_error = false;
+ data->ev.duration = 0;
+ ir_raw_event_reset(data->dev);
+ ir_raw_event_handle(data->dev);
+
/* Enable interrupts */
- wbcir_reset_irdata(data);
outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
}
@@ -1361,6 +728,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
pnp_set_drvdata(device, data);
+ spin_lock_init(&data->spinlock);
data->ebase = pnp_port_start(device, 0);
data->wbase = pnp_port_start(device, 1);
data->sbase = pnp_port_start(device, 2);
@@ -1426,43 +794,25 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
if (err)
goto exit_unregister_rxtrigger;
- data->input_dev = input_allocate_device();
- if (!data->input_dev) {
+ data->dev = rc_allocate_device();
+ if (!data->dev) {
err = -ENOMEM;
goto exit_unregister_led;
}
- data->input_dev->evbit[0] = BIT(EV_KEY);
- data->input_dev->name = WBCIR_NAME;
- data->input_dev->phys = "wbcir/cir0";
- data->input_dev->id.bustype = BUS_HOST;
- data->input_dev->id.vendor = PCI_VENDOR_ID_WINBOND;
- data->input_dev->id.product = WBCIR_ID_FAMILY;
- data->input_dev->id.version = WBCIR_ID_CHIP;
- data->input_dev->getkeycode = wbcir_getkeycode;
- data->input_dev->setkeycode = wbcir_setkeycode;
- input_set_capability(data->input_dev, EV_MSC, MSC_SCAN);
- input_set_drvdata(data->input_dev, data);
-
- err = input_register_device(data->input_dev);
+ data->dev->driver_name = WBCIR_NAME;
+ data->dev->input_name = WBCIR_NAME;
+ data->dev->input_phys = "wbcir/cir0";
+ data->dev->input_id.bustype = BUS_HOST;
+ data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND;
+ data->dev->input_id.product = WBCIR_ID_FAMILY;
+ data->dev->input_id.version = WBCIR_ID_CHIP;
+ data->dev->priv = data;
+ data->dev->dev.parent = &device->dev;
+
+ err = rc_register_device(data->dev);
if (err)
- goto exit_free_input;
-
- data->last_scancode = INVALID_SCANCODE;
- INIT_LIST_HEAD(&data->keytable);
- setup_timer(&data->timer_keyup, wbcir_keyup, (unsigned long)data);
-
- /* Load default keymaps */
- if (protocol == IR_PROTOCOL_RC6) {
- int i;
- for (i = 0; i < ARRAY_SIZE(rc6_def_keymap); i++) {
- err = wbcir_setkeycode(data->input_dev,
- (int)rc6_def_keymap[i].scancode,
- (int)rc6_def_keymap[i].keycode);
- if (err)
- goto exit_unregister_keys;
- }
- }
+ goto exit_free_rc;
device_init_wakeup(&device->dev, 1);
@@ -1470,21 +820,8 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
return 0;
-exit_unregister_keys:
- if (!list_empty(&data->keytable)) {
- struct wbcir_keyentry *key;
- struct wbcir_keyentry *keytmp;
-
- list_for_each_entry_safe(key, keytmp, &data->keytable, list) {
- list_del(&key->list);
- kfree(key);
- }
- }
- input_unregister_device(data->input_dev);
- /* Can't call input_free_device on an unregistered device */
- data->input_dev = NULL;
-exit_free_input:
- input_free_device(data->input_dev);
+exit_free_rc:
+ rc_free_device(data->dev);
exit_unregister_led:
led_classdev_unregister(&data->led);
exit_unregister_rxtrigger:
@@ -1510,15 +847,11 @@ static void __devexit
wbcir_remove(struct pnp_dev *device)
{
struct wbcir_data *data = pnp_get_drvdata(device);
- struct wbcir_keyentry *key;
- struct wbcir_keyentry *keytmp;
/* Disable interrupts */
wbcir_select_bank(data, WBCIR_BANK_0);
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
- del_timer_sync(&data->timer_keyup);
-
free_irq(data->irq, device);
/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
@@ -1530,8 +863,7 @@ wbcir_remove(struct pnp_dev *device)
/* Clear BUFF_EN, END_EN, MATCH_EN */
wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
- /* This will generate a keyup event if necessary */
- input_unregister_device(data->input_dev);
+ rc_unregister_device(data->dev);
led_trigger_unregister_simple(data->rxtrigger);
led_trigger_unregister_simple(data->txtrigger);
@@ -1544,11 +876,6 @@ wbcir_remove(struct pnp_dev *device)
release_region(data->ebase, EHFUNC_IOMEM_LEN);
release_region(data->sbase, SP_IOMEM_LEN);
- list_for_each_entry_safe(key, keytmp, &data->keytable, list) {
- list_del(&key->list);
- kfree(key);
- }
-
kfree(data);
pnp_set_drvdata(device, NULL);
@@ -1581,8 +908,7 @@ wbcir_init(void)
case IR_PROTOCOL_RC6:
break;
default:
- printk(KERN_ERR DRVNAME ": Invalid protocol argument\n");
- return -EINVAL;
+ printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n");
}
ret = pnp_register_driver(&wbcir_driver);
@@ -1598,11 +924,9 @@ wbcir_exit(void)
pnp_unregister_driver(&wbcir_driver);
}
-MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
-MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver");
-MODULE_LICENSE("GPL");
-
module_init(wbcir_init);
module_exit(wbcir_exit);
-
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ac16e815e275..eb875af05e79 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,11 +7,6 @@ config VIDEO_V4L2
depends on VIDEO_DEV && VIDEO_V4L2_COMMON
default VIDEO_DEV && VIDEO_V4L2_COMMON
-config VIDEO_V4L1
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
- default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
-
config VIDEOBUF_GEN
tristate
@@ -96,7 +91,7 @@ config VIDEO_HELPER_CHIPS_AUTO
config VIDEO_IR_I2C
tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
- depends on I2C && VIDEO_IR
+ depends on I2C && RC_CORE
default y
---help---
Most boards have an IR chip directly connected via GPIO. However,
@@ -112,7 +107,7 @@ config VIDEO_IR_I2C
#
menu "Encoders/decoders and other helper chips"
- depends on !VIDEO_HELPER_CHIPS_AUTO
+ visible if !VIDEO_HELPER_CHIPS_AUTO
comment "Audio decoders"
@@ -666,6 +661,16 @@ config VIDEO_HEXIUM_GEMINI
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
+config VIDEO_TIMBERDALE
+ tristate "Support for timberdale Video In/LogiWIN"
+ depends on VIDEO_V4L2 && I2C
+ select DMA_ENGINE
+ select TIMB_DMA
+ select VIDEO_ADV7180
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ Add support for the Video In peripherial of the timberdale FPGA.
+
source "drivers/media/video/cx88/Kconfig"
source "drivers/media/video/cx23885/Kconfig"
@@ -789,6 +794,12 @@ config SOC_CAMERA_PLATFORM
help
This is a generic SoC camera platform driver, useful for testing
+config SOC_CAMERA_OV2640
+ tristate "ov2640 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov2640 camera driver
+
config SOC_CAMERA_OV6650
tristate "ov6650 sensor support"
depends on SOC_CAMERA && I2C
@@ -905,21 +916,8 @@ source "drivers/media/video/cx231xx/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
-source "drivers/media/video/usbvideo/Kconfig"
-
source "drivers/media/video/et61x251/Kconfig"
-config USB_SE401
- tristate "USB SE401 Camera support"
- depends on VIDEO_V4L1
- ---help---
- Say Y here if you want to connect this type of camera to your
- computer's USB port. See <file:Documentation/video4linux/se401.txt>
- for more information and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called se401.
-
source "drivers/media/video/sn9c102/Kconfig"
source "drivers/media/video/pwc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index af79d476a4c8..81e38cb0b846 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -22,10 +22,6 @@ endif
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
-ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
- obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
-endif
-
# All i2c modules must come first:
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -79,6 +75,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o
obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
@@ -106,6 +103,7 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -124,8 +122,6 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
-obj-$(CONFIG_USB_DABUSB) += dabusb.o
-obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
@@ -136,10 +132,6 @@ obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
-obj-$(CONFIG_USB_IBMCAM) += usbvideo/
-obj-$(CONFIG_USB_KONICAWC) += usbvideo/
-obj-$(CONFIG_USB_VICAM) += usbvideo/
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_USB_S2255) += s2255drv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 31e7a123d19a..f989f2820d88 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar)
static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
.read = ar_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops ar_ioctl_ops = {
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 0453816d4ec3..01be89fa5c78 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "au8522", 0x8e >> 1, NULL);
+ "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->board.tuner_addr, NULL);
+ "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 162fd5f9d448..e41e4ad5cc40 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -122,6 +122,7 @@ static void au0828_irq_callback(struct urb *urb)
{
struct au0828_dmaqueue *dma_q = urb->context;
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+ unsigned long flags = 0;
int rc, i;
switch (urb->status) {
@@ -139,9 +140,9 @@ static void au0828_irq_callback(struct urb *urb)
}
/* Copy data from URB */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
rc = dev->isoc_ctl.isoc_copy(dev, urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
@@ -576,7 +577,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
p += 4;
au0828_isocdbg("Video frame %s\n",
(fbyte & 0x40) ? "odd" : "even");
- if (!(fbyte & 0x40)) {
+ if (fbyte & 0x40) {
/* VBI */
if (vbi_buf != NULL)
vbi_buffer_filled(dev,
@@ -597,6 +598,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
outp = NULL;
else
outp = videobuf_to_vmalloc(&buf->vb);
+
+ /* As long as isoc traffic is arriving, keep
+ resetting the timer */
+ if (dev->vid_timeout_running)
+ mod_timer(&dev->vid_timeout,
+ jiffies + (HZ / 10));
+ if (dev->vbi_timeout_running)
+ mod_timer(&dev->vbi_timeout,
+ jiffies + (HZ / 10));
}
if (buf != NULL) {
@@ -907,6 +917,57 @@ static int get_ressource(struct au0828_fh *fh)
}
}
+/* This function ensures that video frames continue to be delivered even if
+ the ITU-656 input isn't receiving any data (thereby preventing applications
+ such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vidq;
+ struct au0828_buffer *buf;
+ unsigned char *vid_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL) {
+ vid_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+ buffer_filled(dev, dma_q, buf);
+ }
+ get_next_buf(dma_q, &buf);
+
+ if (dev->vid_timeout_running == 1)
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vbiq;
+ struct au0828_buffer *buf;
+ unsigned char *vbi_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.vbi_buf;
+ if (buf != NULL) {
+ vbi_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vbi_data, 0x00, buf->vb.size);
+ vbi_buffer_filled(dev, dma_q, buf);
+ }
+ vbi_get_next_buf(dma_q, &buf);
+
+ if (dev->vbi_timeout_running == 1)
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
static int au0828_v4l2_open(struct file *filp)
{
int ret = 0;
@@ -976,7 +1037,6 @@ static int au0828_v4l2_open(struct file *filp)
V4L2_FIELD_SEQ_TB,
sizeof(struct au0828_buffer), fh, NULL);
-
return ret;
}
@@ -987,11 +1047,19 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_dev *dev = fh->dev;
if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
videobuf_stop(&fh->vb_vidq);
res_free(fh, AU0828_RESOURCE_VIDEO);
}
if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
videobuf_stop(&fh->vb_vbiq);
res_free(fh, AU0828_RESOURCE_VBI);
}
@@ -1048,6 +1116,13 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
if (!res_get(fh, AU0828_RESOURCE_VBI))
return -EBUSY;
+ if (dev->vbi_timeout_running == 0) {
+ /* Handle case where caller tries to read without
+ calling streamon first */
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
+
return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}
@@ -1577,10 +1652,15 @@ static int vidioc_streamon(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
}
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
rc = videobuf_streamon(&fh->vb_vidq);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ dev->vid_timeout_running = 1;
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
rc = videobuf_streamon(&fh->vb_vbiq);
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
return rc;
}
@@ -1607,6 +1687,9 @@ static int vidioc_streamoff(struct file *file, void *priv,
fh, type, fh->resources, dev->resources);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
rc = au0828_stream_interrupt(dev);
if (rc != 0)
@@ -1621,6 +1704,9 @@ static int vidioc_streamoff(struct file *file, void *priv,
videobuf_streamoff(&fh->vb_vidq);
res_free(fh, AU0828_RESOURCE_VIDEO);
} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
videobuf_streamoff(&fh->vb_vbiq);
res_free(fh, AU0828_RESOURCE_VBI);
}
@@ -1723,15 +1809,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct au0828_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
static struct v4l2_file_operations au0828_v4l_fops = {
.owner = THIS_MODULE,
.open = au0828_v4l2_open,
@@ -1775,9 +1852,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static const struct video_device au0828_video_template = {
@@ -1840,6 +1914,14 @@ int au0828_analog_register(struct au0828_dev *dev,
INIT_LIST_HEAD(&dev->vbiq.active);
INIT_LIST_HEAD(&dev->vbiq.queued);
+ dev->vid_timeout.function = au0828_vid_buffer_timeout;
+ dev->vid_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vid_timeout);
+
+ dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+ dev->vbi_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vbi_timeout);
+
dev->width = NTSC_STD_W;
dev->height = NTSC_STD_H;
dev->field_size = dev->width * dev->height;
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 9905bc4f5f59..9cde35321824 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -53,7 +53,7 @@
/* Defination for AU0828 USB transfer */
#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
-#define AU0828_ISO_PACKETS_PER_URB 10
+#define AU0828_ISO_PACKETS_PER_URB 128
#define AU0828_MIN_BUF 4
#define AU0828_DEF_BUF 8
@@ -204,6 +204,10 @@ struct au0828_dev {
unsigned int resources; /* resources in use */
struct video_device *vdev;
struct video_device *vbi_dev;
+ struct timer_list vid_timeout;
+ int vid_timeout_running;
+ struct timer_list vbi_timeout;
+ int vbi_timeout_running;
int width;
int height;
int vbi_width;
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 1a4a89fdf767..7da5c2e1fc12 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,10 +1,10 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 87d8b006ef77..49efcf660ba6 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3529,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "saa6588", 0, addrs);
+ &btv->c.i2c_adap, "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}
@@ -3554,7 +3554,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400", 0, addrs);
+ &btv->c.i2c_adap, "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
@@ -3568,7 +3568,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
goto no_audio;
}
@@ -3576,7 +3576,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
@@ -3596,11 +3596,11 @@ void __devinit bttv_init_card2(struct bttv *btv)
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}
@@ -3616,13 +3616,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
@@ -3646,13 +3646,13 @@ void __devinit bttv_init_tuner(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, NULL, "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 3da6e80e1041..91399c94cd18 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -42,7 +42,6 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include "bttvp.h"
@@ -56,7 +55,7 @@
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
unsigned int bttv_num; /* number of Bt848s in use */
@@ -190,8 +189,14 @@ static void request_modules(struct bttv *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct bttv *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -855,7 +860,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
/* is it free? */
- mutex_lock(&btv->lock);
if (btv->resources & xbits) {
/* no, someone else uses it */
goto fail;
@@ -885,11 +889,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->lock);
return 1;
fail:
- mutex_unlock(&btv->lock);
return 0;
}
@@ -941,7 +943,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
- mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
@@ -952,8 +953,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
if (0 == (bits & VBI_RESOURCES))
disclaim_vbi_lines(btv);
-
- mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
@@ -1714,28 +1713,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
/* Make sure tvnorm and vbi_end remain consistent
until we're done. */
- mutex_lock(&btv->lock);
norm = btv->tvnorm;
/* In this mode capturing always starts at defrect.top
(default VDELAY), ignoring cropping parameters. */
if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
- mutex_unlock(&btv->lock);
return -EINVAL;
}
- mutex_unlock(&btv->lock);
-
c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- mutex_lock(&btv->lock);
-
norm = btv->tvnorm;
c = btv->crop[!!fh->do_crop];
- mutex_unlock(&btv->lock);
-
if (width < c.min_scaled_width ||
width > c.max_scaled_width ||
height < c.min_scaled_height)
@@ -1859,7 +1850,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
unsigned int i;
int err;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (err)
goto err;
@@ -1875,7 +1865,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
set_tvnorm(btv, i);
err:
- mutex_unlock(&btv->lock);
return err;
}
@@ -1899,7 +1888,6 @@ static int bttv_enum_input(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int rc = 0;
- mutex_lock(&btv->lock);
if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
rc = -EINVAL;
goto err;
@@ -1929,7 +1917,6 @@ static int bttv_enum_input(struct file *file, void *priv,
i->std = BTTV_NORMS;
err:
- mutex_unlock(&btv->lock);
return rc;
}
@@ -1939,9 +1926,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
*i = btv->input;
- mutex_unlock(&btv->lock);
return 0;
}
@@ -1953,7 +1938,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
int err;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (unlikely(err))
goto err;
@@ -1966,7 +1950,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
set_input(btv, i, btv->tvnorm);
err:
- mutex_unlock(&btv->lock);
return 0;
}
@@ -1980,7 +1963,6 @@ static int bttv_s_tuner(struct file *file, void *priv,
if (unlikely(0 != t->index))
return -EINVAL;
- mutex_lock(&btv->lock);
if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
err = -EINVAL;
goto err;
@@ -1996,7 +1978,6 @@ static int bttv_s_tuner(struct file *file, void *priv,
btv->audio_mode_gpio(btv, t, 1);
err:
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2007,10 +1988,8 @@ static int bttv_g_frequency(struct file *file, void *priv,
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = btv->freq;
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2025,7 +2004,6 @@ static int bttv_s_frequency(struct file *file, void *priv,
if (unlikely(f->tuner != 0))
return -EINVAL;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (unlikely(err))
goto err;
@@ -2040,7 +2018,6 @@ static int bttv_s_frequency(struct file *file, void *priv,
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv, btv->freq);
err:
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2173,7 +2150,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,
/* Make sure tvnorm, vbi_end and the current cropping parameters
remain consistent until we're done. */
- mutex_lock(&btv->lock);
b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
@@ -2251,7 +2227,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,
rc = 0; /* success */
fail:
- mutex_unlock(&btv->lock);
return rc;
}
@@ -2283,9 +2258,7 @@ verify_window_lock (struct bttv_fh * fh,
if (V4L2_FIELD_ANY == field) {
__s32 height2;
- mutex_lock(&fh->btv->lock);
height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
- mutex_unlock(&fh->btv->lock);
field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
@@ -2361,7 +2334,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
}
}
- mutex_lock(&fh->cap.vb_lock);
/* clip against screen */
if (NULL != btv->fbuf.base)
n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2392,13 +2364,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
- /*
- * FIXME: btv is protected by btv->lock mutex, while btv->init
- * is protected by fh->cap.vb_lock. This seems to open the
- * possibility for some race situations. Maybe the better would
- * be to unify those locks or to use another way to store the
- * init values that will be consumed by videobuf callbacks
- */
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
@@ -2413,7 +2378,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2527,9 +2491,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
if (V4L2_FIELD_ANY == field) {
__s32 height2;
- mutex_lock(&btv->lock);
height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
- mutex_unlock(&btv->lock);
field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
@@ -2615,7 +2577,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
- mutex_lock(&fh->cap.vb_lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
@@ -2624,7 +2585,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
- mutex_unlock(&fh->cap.vb_lock);
return 0;
}
@@ -2643,34 +2603,6 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
return setup_window_lock(fh, btv, &f->fmt.win, 1);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- int retval;
- unsigned int i;
- struct bttv_fh *fh = priv;
-
- mutex_lock(&fh->cap.vb_lock);
- retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
- V4L2_MEMORY_MMAP);
- if (retval < 0) {
- mutex_unlock(&fh->cap.vb_lock);
- return retval;
- }
-
- gbuffers = retval;
- memset(mbuf, 0, sizeof(*mbuf));
- mbuf->frames = gbuffers;
- mbuf->size = gbuffers * gbufsize;
-
- for (i = 0; i < gbuffers; i++)
- mbuf->offsets[i] = i * gbufsize;
-
- mutex_unlock(&fh->cap.vb_lock);
- return 0;
-}
-#endif
-
static int bttv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -2776,10 +2708,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
int retval = 0;
if (on) {
- mutex_lock(&fh->cap.vb_lock);
/* verify args */
if (unlikely(!btv->fbuf.base)) {
- mutex_unlock(&fh->cap.vb_lock);
return -EINVAL;
}
if (unlikely(!fh->ov.setup_ok)) {
@@ -2788,13 +2718,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
}
if (retval)
return retval;
- mutex_unlock(&fh->cap.vb_lock);
}
if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
return -EBUSY;
- mutex_lock(&fh->cap.vb_lock);
if (on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_sg_alloc(sizeof(*new));
@@ -2806,7 +2734,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
/* switch over */
retval = bttv_switch_overlay(btv, fh, new);
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2845,7 +2772,6 @@ static int bttv_s_fbuf(struct file *file, void *f,
}
/* ok, accept it */
- mutex_lock(&fh->cap.vb_lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2877,7 +2803,6 @@ static int bttv_s_fbuf(struct file *file, void *f,
retval = bttv_switch_overlay(btv, fh, new);
}
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2956,7 +2881,6 @@ static int bttv_queryctrl(struct file *file, void *priv,
c->id >= V4L2_CID_PRIVATE_LASTP1))
return -EINVAL;
- mutex_lock(&btv->lock);
if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
*c = no_ctl;
else {
@@ -2964,7 +2888,6 @@ static int bttv_queryctrl(struct file *file, void *priv,
*c = (NULL != ctrl) ? *ctrl : no_ctl;
}
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2975,10 +2898,8 @@ static int bttv_g_parm(struct file *file, void *f,
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
&parm->parm.capture.timeperframe);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2994,7 +2915,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
t->rxsubchans = V4L2_TUNER_SUB_MONO;
bttv_call_all(btv, tuner, g_tuner, t);
strcpy(t->name, "Television");
@@ -3006,7 +2926,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3015,9 +2934,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
*p = v4l2_prio_max(&btv->prio);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3029,9 +2946,7 @@ static int bttv_s_priority(struct file *file, void *f,
struct bttv *btv = fh->btv;
int rc;
- mutex_lock(&btv->lock);
rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
- mutex_unlock(&btv->lock);
return rc;
}
@@ -3046,9 +2961,7 @@ static int bttv_cropcap(struct file *file, void *priv,
cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
- mutex_lock(&btv->lock);
*cap = bttv_tvnorms[btv->tvnorm].cropcap;
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3066,9 +2979,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
inconsistent with fh->width or fh->height and apps
do not expect a change here. */
- mutex_lock(&btv->lock);
crop->c = btv->crop[!!fh->do_crop].rect;
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3092,17 +3003,14 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
/* Make sure tvnorm, vbi_end and the current cropping
parameters remain consistent until we're done. Note
read() may change vbi_end in check_alloc_btres_lock(). */
- mutex_lock(&btv->lock);
retval = v4l2_prio_check(&btv->prio, fh->prio);
if (0 != retval) {
- mutex_unlock(&btv->lock);
return retval;
}
retval = -EBUSY;
if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
- mutex_unlock(&btv->lock);
return retval;
}
@@ -3114,7 +3022,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
b_top = max(b->top, btv->vbi_end);
if (b_top + 32 >= b_bottom) {
- mutex_unlock(&btv->lock);
return retval;
}
@@ -3137,12 +3044,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
btv->crop[1] = c;
- mutex_unlock(&btv->lock);
-
fh->do_crop = 1;
- mutex_lock(&fh->cap.vb_lock);
-
if (fh->width < c.min_scaled_width) {
fh->width = c.min_scaled_width;
btv->init.width = c.min_scaled_width;
@@ -3159,8 +3062,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
btv->init.height = c.max_scaled_height;
}
- mutex_unlock(&fh->cap.vb_lock);
-
return 0;
}
@@ -3228,7 +3129,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
return videobuf_poll_stream(file, &fh->vbi, wait);
}
- mutex_lock(&fh->cap.vb_lock);
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
@@ -3263,7 +3163,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
else
rc = 0;
err:
- mutex_unlock(&fh->cap.vb_lock);
return rc;
}
@@ -3294,23 +3193,11 @@ static int bttv_open(struct file *file)
return -ENOMEM;
file->private_data = fh;
- /*
- * btv is protected by btv->lock mutex, while btv->init and other
- * streaming vars are protected by fh->cap.vb_lock. We need to take
- * care of both locks to avoid troubles. However, vb_lock is used also
- * inside videobuf, without calling buf->lock. So, it is a very bad
- * idea to hold both locks at the same time.
- * Let's first copy btv->init at fh, holding cap.vb_lock, and then work
- * with the rest of init, holding btv->lock.
- */
- mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
- mutex_unlock(&fh->cap.vb_lock);
fh->type = type;
fh->ov.setup_ok = 0;
- mutex_lock(&btv->lock);
v4l2_prio_open(&btv->prio, &fh->prio);
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3318,13 +3205,13 @@ static int bttv_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
- fh, NULL);
+ fh, &btv->lock);
videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer),
- fh, NULL);
+ fh, &btv->lock);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
@@ -3347,7 +3234,6 @@ static int bttv_open(struct file *file)
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3356,7 +3242,6 @@ static int bttv_release(struct file *file)
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
/* turn off overlay */
if (check_btres(fh, RESOURCE_OVERLAY))
bttv_switch_overlay(btv,fh,NULL);
@@ -3382,14 +3267,8 @@ static int bttv_release(struct file *file)
/* free stuff */
- /*
- * videobuf uses cap.vb_lock - we should avoid holding btv->lock,
- * otherwise we may have dead lock conditions
- */
- mutex_unlock(&btv->lock);
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
- mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
@@ -3399,7 +3278,6 @@ static int bttv_release(struct file *file)
if (!btv->users)
audio_mute(btv, 1);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3457,9 +3335,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_streamoff = bttv_streamoff,
.vidioc_g_tuner = bttv_g_tuner,
.vidioc_s_tuner = bttv_s_tuner,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_crop = bttv_g_crop,
.vidioc_s_crop = bttv_s_crop,
.vidioc_g_fbuf = bttv_g_fbuf,
@@ -3503,11 +3378,8 @@ static int radio_open(struct file *file)
if (unlikely(!fh))
return -ENOMEM;
file->private_data = fh;
- mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
- mutex_unlock(&fh->cap.vb_lock);
- mutex_lock(&btv->lock);
v4l2_prio_open(&btv->prio, &fh->prio);
btv->radio_user++;
@@ -3515,7 +3387,6 @@ static int radio_open(struct file *file)
bttv_call_all(btv, tuner, s_radio);
audio_input(btv,TVAUDIO_INPUT_RADIO);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -3523,17 +3394,15 @@ static int radio_release(struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
- mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
btv->radio_user--;
- bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
- mutex_unlock(&btv->lock);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
return 0;
}
@@ -3562,7 +3431,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
@@ -3571,8 +3439,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
-
return 0;
}
@@ -3663,13 +3529,13 @@ static ssize_t radio_read(struct file *file, char __user *data,
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.block_count = count/3;
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;
- bttv_call_all(btv, core, ioctl, RDS_CMD_READ, &cmd);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
return cmd.result;
}
@@ -3678,11 +3544,11 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.instance = file;
cmd.event_list = wait;
cmd.result = -ENODEV;
- bttv_call_all(btv, core, ioctl, RDS_CMD_POLL, &cmd);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
return cmd.result;
}
@@ -3693,7 +3559,7 @@ static const struct v4l2_file_operations radio_fops =
.open = radio_open,
.read = radio_read,
.release = radio_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = radio_poll,
};
@@ -4153,9 +4019,6 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btv=(struct bttv *)dev_id;
- if (btv->custom_irq)
- handled = btv->custom_irq(btv);
-
count=0;
while (1) {
/* get/clear interrupt status bits */
@@ -4191,7 +4054,6 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btv->field_count++;
if ((astat & BT848_INT_GPINT) && btv->remote) {
- wake_up(&btv->gpioq);
bttv_input_irq(btv);
}
@@ -4396,7 +4258,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
mutex_init(&btv->lock);
spin_lock_init(&btv->s_lock);
spin_lock_init(&btv->gpio_lock);
- init_waitqueue_head(&btv->gpioq);
init_waitqueue_head(&btv->i2c_queue);
INIT_LIST_HEAD(&btv->c.subs);
INIT_LIST_HEAD(&btv->capture);
@@ -4574,6 +4435,9 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->c.nr);
+ if (bttv_tvcards[btv->c.type].has_dvb)
+ flush_request_modules(btv);
+
/* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
@@ -4584,7 +4448,6 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
/* tell gpio modules we are leaving ... */
btv->shutdown=1;
- wake_up(&btv->gpioq);
bttv_input_fini(btv);
bttv_sub_del_devices(&btv->c);
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 6bf05a7dc5f9..e8b64bca9db2 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -31,15 +31,9 @@
static int ir_debug;
module_param(ir_debug, int, 0644);
-static int repeat_delay = 500;
-module_param(repeat_delay, int, 0644);
-static int repeat_period = 33;
-module_param(repeat_period, int, 0644);
static int ir_rc5_remote_gap = 885;
module_param(ir_rc5_remote_gap, int, 0644);
-static int ir_rc5_key_timeout = 200;
-module_param(ir_rc5_key_timeout, int, 0644);
#undef dprintk
#define dprintk(arg...) do { \
@@ -55,7 +49,7 @@ module_param(ir_rc5_key_timeout, int, 0644);
static void ir_handle_key(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
u32 gpio,data;
/* read gpio value */
@@ -74,23 +68,22 @@ static void ir_handle_key(struct bttv *btv)
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
- (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
+ if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
+ (ir->mask_keyup && !(gpio & ir->mask_keyup))) {
+ rc_keydown_notimeout(ir->dev, data, 0);
} else {
/* HACK: Probably, ir->mask_keydown is missing
for this board */
if (btv->c.type == BTTV_BOARD_WINFAST2000)
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
- ir_input_nokey(ir->dev,&ir->ir);
+ rc_keyup(ir->dev);
}
-
}
static void ir_enltv_handle_key(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
u32 gpio, data, keyup;
/* read gpio value */
@@ -107,9 +100,9 @@ static void ir_enltv_handle_key(struct bttv *btv)
gpio, data,
(gpio & ir->mask_keyup) ? " up" : "up/down");
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
if (keyup)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
} else {
if ((ir->last_gpio & 1 << 31) == keyup)
return;
@@ -119,26 +112,30 @@ static void ir_enltv_handle_key(struct bttv *btv)
(gpio & ir->mask_keyup) ? " up" : "down");
if (keyup)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
else
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
}
ir->last_gpio = data | keyup;
}
+static int bttv_rc5_irq(struct bttv *btv);
+
void bttv_input_irq(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
- if (!ir->polling)
+ if (ir->rc5_gpio)
+ bttv_rc5_irq(btv);
+ else if (!ir->polling)
ir_handle_key(btv);
}
static void bttv_input_timer(unsigned long data)
{
struct bttv *btv = (struct bttv*)data;
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
ir_enltv_handle_key(btv);
@@ -147,11 +144,109 @@ static void bttv_input_timer(unsigned long data)
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-/* ---------------------------------------------------------------*/
+/*
+ * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying
+ * on the rc-core way. As we need to be sure that both IRQ transitions are
+ * properly triggered, Better to touch it only with this hardware for
+ * testing.
+ */
+
+#define RC5_START(x) (((x) >> 12) & 3)
+#define RC5_TOGGLE(x) (((x) >> 11) & 1)
+#define RC5_ADDR(x) (((x) >> 6) & 31)
+#define RC5_INSTR(x) ((x) & 63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 bttv_rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n",
+ org_code);
+ return 0;
+ }
+ }
+ dprintk(KERN_INFO DEVNAME ":"
+ "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+static void bttv_rc5_timer_end(unsigned long data)
+{
+ struct bttv_ir *ir = (struct bttv_ir *)data;
+ struct timeval tv;
+ unsigned long current_jiffies;
+ u32 gap;
+ u32 rc5 = 0;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* signal we're ready to start a new code */
+ ir->active = false;
+
+ /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk(KERN_INFO DEVNAME ": spurious timer_end\n");
+ return;
+ }
+
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code);
+ } else {
+ ir->code = (ir->code << ir->shift_by) | 1;
+ rc5 = bttv_rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != ir->start) {
+ printk(KERN_INFO DEVNAME ":"
+ " rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == ir->addr) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code */
+ rc_keydown(ir->dev, instr, toggle);
+ dprintk(KERN_INFO DEVNAME ":"
+ " instruction %x, toggle %x\n",
+ instr, toggle);
+ }
+ }
+}
static int bttv_rc5_irq(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
struct timeval tv;
u32 gpio;
u32 gap;
@@ -160,10 +255,6 @@ static int bttv_rc5_irq(struct bttv *btv)
/* read gpio port */
gpio = bttv_gpio_read(&btv->c);
- /* remote IRQ? */
- if (!(gpio & 0x20))
- return 0;
-
/* get time of bit */
current_jiffies = jiffies;
do_gettimeofday(&tv);
@@ -176,6 +267,13 @@ static int bttv_rc5_irq(struct bttv *btv)
tv.tv_usec - ir->base_time.tv_usec;
}
+ dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n",
+ gap, (gpio & 0x20) ? "mark" : "space");
+
+ /* remote IRQ? */
+ if (!(gpio & 0x20))
+ return 0;
+
/* active code => add bit */
if (ir->active) {
/* only if in the code (otherwise spurious IRQ or timer
@@ -187,13 +285,12 @@ static int bttv_rc5_irq(struct bttv *btv)
}
/* starting new code */
} else {
- ir->active = 1;
+ ir->active = true;
ir->code = 0;
ir->base_time = tv;
ir->last_bit = 0;
- mod_timer(&ir->timer_end,
- current_jiffies + msecs_to_jiffies(30));
+ mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30));
}
/* toggle GPIO pin 4 to reset the irq */
@@ -204,7 +301,7 @@ static int bttv_rc5_irq(struct bttv *btv)
/* ---------------------------------------------------------------------- */
-static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
@@ -212,33 +309,23 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_rc5_timer_end;
- ir->timer_end.data = (unsigned long)ir;
-
- init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = ir_rc5_timer_keyup;
- ir->timer_keyup.data = (unsigned long)ir;
+ setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
ir->shift_by = 1;
ir->start = 3;
ir->addr = 0x0;
- ir->rc5_key_timeout = ir_rc5_key_timeout;
ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
static void bttv_ir_stop(struct bttv *btv)
{
- if (btv->remote->polling) {
+ if (btv->remote->polling)
del_timer_sync(&btv->remote->timer);
- flush_scheduled_work();
- }
if (btv->remote->rc5_gpio) {
u32 gpio;
- del_timer_sync(&btv->remote->timer_end);
- flush_scheduled_work();
+ del_timer_sync(&btv->remote->timer);
gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
@@ -264,6 +351,18 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 0;
dprintk(KERN_INFO DEVNAME ": key %02x\n", b);
+ /*
+ * NOTE:
+ * lirc_i2c maps the pv951 code as:
+ * addr = 0x61D6
+ * cmd = bit_reverse (b)
+ * So, it seems that this device uses NEC extended
+ * I decided to not fix the table, due to two reasons:
+ * 1) Without the actual device, this is only a guess;
+ * 2) As the addr is not reported via I2C, nor can be changed,
+ * the device is bound to the vendor-provided RC.
+ */
+
*ir_key = b;
*ir_raw = b;
return 1;
@@ -290,16 +389,15 @@ void __devinit init_bttv_i2c_ir(struct bttv *btv)
btv->init_data.name = "PV951";
btv->init_data.get_key = get_key_pv951;
btv->init_data.ir_codes = RC_MAP_PV951;
- btv->init_data.type = IR_TYPE_OTHER;
info.addr = 0x4b;
break;
default:
/*
* The external IR receiver is at i2c address 0x34 (0x35 for
- * reads). Future Hauppauge cards will have an internal
- * receiver at 0x30 (0x31 for reads). In theory, both can be
- * fitted, and Hauppauge suggest an external overrides an
- * internal.
+ * reads). Future Hauppauge cards will have an internal
+ * receiver at 0x30 (0x31 for reads). In theory, both can be
+ * fitted, and Hauppauge suggest an external overrides an
+ * internal.
* That's why we probe 0x1a (~0x34) first. CB
*/
@@ -324,18 +422,17 @@ int __devexit fini_bttv_i2c(struct bttv *btv)
int bttv_input_init(struct bttv *btv)
{
- struct card_ir *ir;
+ struct bttv_ir *ir;
char *ir_codes = NULL;
- struct input_dev *input_dev;
- u64 ir_type = IR_TYPE_OTHER;
+ struct rc_dev *rc;
int err = -ENOMEM;
if (!btv->has_remote)
return -ENODEV;
ir = kzalloc(sizeof(*ir),GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ rc = rc_allocate_device();
+ if (!ir || !rc)
goto err_out_free;
/* detect & configure */
@@ -398,8 +495,7 @@ int bttv_input_init(struct bttv *btv)
break;
case BTTV_BOARD_NEBULA_DIGITV:
ir_codes = RC_MAP_NEBULA;
- btv->custom_irq = bttv_rc5_irq;
- ir->rc5_gpio = 1;
+ ir->rc5_gpio = true;
break;
case BTTV_BOARD_MACHTV_MAGICTV:
ir_codes = RC_MAP_APAC_VIEWCOMP;
@@ -441,48 +537,43 @@ int bttv_input_init(struct bttv *btv)
}
/* init input device */
- ir->dev = input_dev;
+ ir->dev = rc;
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
btv->c.type);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(btv->c.pci));
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (btv->c.pci->subsystem_vendor) {
- input_dev->id.vendor = btv->c.pci->subsystem_vendor;
- input_dev->id.product = btv->c.pci->subsystem_device;
+ rc->input_id.vendor = btv->c.pci->subsystem_vendor;
+ rc->input_id.product = btv->c.pci->subsystem_device;
} else {
- input_dev->id.vendor = btv->c.pci->vendor;
- input_dev->id.product = btv->c.pci->device;
+ rc->input_id.vendor = btv->c.pci->vendor;
+ rc->input_id.product = btv->c.pci->device;
}
- input_dev->dev.parent = &btv->c.pci->dev;
+ rc->dev.parent = &btv->c.pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
btv->remote = ir;
bttv_ir_start(btv, ir);
/* all done */
- err = ir_input_register(btv->remote->dev, ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_stop;
- /* the remote isn't as bouncy as a keyboard */
- ir->dev->rep[REP_DELAY] = repeat_delay;
- ir->dev->rep[REP_PERIOD] = repeat_period;
-
return 0;
err_out_stop:
bttv_ir_stop(btv);
btv->remote = NULL;
err_out_free:
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -493,7 +584,7 @@ void bttv_input_fini(struct bttv *btv)
return;
bttv_ir_stop(btv);
- ir_input_unregister(btv->remote->dev);
+ rc_unregister_device(btv->remote->dev);
kfree(btv->remote);
btv->remote = NULL;
}
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 6fd2a8ebda1e..fd62bf15d779 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -17,7 +17,6 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/ir-common.h>
#include <media/i2c-addr.h>
#include <media/tuner.h>
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index d1e26a448ed2..9b776faf0741 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -41,7 +41,7 @@
#include <linux/device.h>
#include <media/videobuf-dma-sg.h>
#include <media/tveeprom.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include "bt848.h"
@@ -120,6 +120,33 @@ struct bttv_format {
int hshift,vshift; /* for planar modes */
};
+struct bttv_ir {
+ struct rc_dev *dev;
+ struct timer_list timer;
+
+ char name[32];
+ char phys[32];
+
+ /* Usual gpio signalling */
+ u32 mask_keycode;
+ u32 mask_keydown;
+ u32 mask_keyup;
+ u32 polling;
+ u32 last_gpio;
+ int shift_by;
+ int start; // What should RC5_START() be
+ int addr; // What RC5_ADDR() should be.
+ int rc5_remote_gap;
+
+ /* RC5 gpio */
+ bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */
+ u32 last_bit; /* last raw bit seen */
+ u32 code; /* raw code under construction */
+ struct timeval base_time; /* time of last seen code */
+ bool active; /* building raw code */
+};
+
+
/* ---------------------------------------------------------- */
struct bttv_geometry {
@@ -305,7 +332,6 @@ struct bttv_pll_info {
/* for gpio-connected remote control */
struct bttv_input {
struct input_dev *dev;
- struct ir_input_state ir;
char name[32];
char phys[32];
u32 mask_keycode;
@@ -338,12 +364,10 @@ struct bttv {
struct bttv_pll_info pll;
int triton1;
int gpioirq;
- int (*custom_irq)(struct bttv *btv);
int use_i2c_hw;
/* old gpio interface */
- wait_queue_head_t gpioq;
int shutdown;
void (*volume_gpio)(struct bttv *btv, __u16 volume);
@@ -368,7 +392,7 @@ struct bttv {
/* infrared remote */
int has_remote;
- struct card_ir *remote;
+ struct bttv_ir *remote;
/* I2C remote data */
struct IR_i2c_init_data init_data;
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 935e0c9a9674..c1193506131c 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 6e4b19698c13..24fc00965a12 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 2934770dacc3..49f1b8f1418e 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -859,8 +859,6 @@ static int cafe_cam_configure(struct cafe_camera *cam)
struct v4l2_mbus_framefmt mbus_fmt;
int ret;
- if (cam->state != S_IDLE)
- return -EINVAL;
v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
ret = sensor_call(cam, core, init, 0);
if (ret == 0)
@@ -1775,7 +1773,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = {
.read = cafe_v4l_read,
.poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
@@ -2065,8 +2063,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
sensor_cfg.clock_speed = 45;
cam->sensor_addr = 0x42;
- cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
- NULL, "ov7670", cam->sensor_addr, NULL);
+ cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
+ "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
@@ -2186,9 +2184,7 @@ static int cafe_pci_resume(struct pci_dev *pdev)
struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = 0;
- ret = pci_restore_state(pdev);
- if (ret)
- return ret;
+ pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
@@ -2196,12 +2192,13 @@ static int cafe_pci_resume(struct pci_dev *pdev)
return ret;
}
cafe_ctlr_init(cam);
- cafe_ctlr_power_down(cam);
mutex_lock(&cam->s_mutex);
if (cam->users > 0) {
cafe_ctlr_power_up(cam);
__cafe_cam_reset(cam);
+ } else {
+ cafe_ctlr_power_down(cam);
}
mutex_unlock(&cam->s_mutex);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 46b433bbf2c1..7edf80b0d01a 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -419,28 +419,6 @@ static int sync(struct camera_data *cam, int frame_nr)
/******************************************************************************
*
- * ioctl_get_mbuf
- *
- *****************************************************************************/
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
-{
- struct video_mbuf *vm;
- int i;
- vm = arg;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = cam->frame_size*cam->num_frames;
- vm->frames = cam->num_frames;
- for (i = 0; i < cam->num_frames; i++)
- vm->offsets[i] = cam->frame_size * i;
-
- return 0;
-}
-#endif
-
-/******************************************************************************
- *
* ioctl_set_gpio
*
*****************************************************************************/
@@ -1380,17 +1358,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
break;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGMBUF:
- {
- struct cpia2_fh *fh = file->private_data;
- if(fh->prio != V4L2_PRIORITY_RECORD) {
- mutex_unlock(&cam->busy_lock);
- return -EBUSY;
- }
- break;
- }
-#endif
default:
break;
}
@@ -1400,11 +1367,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case CPIA2_IOC_SET_GPIO:
retval = ioctl_set_gpio(arg, cam);
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGMBUF: /* mmap interface */
- retval = ioctl_get_mbuf(arg, cam);
- break;
-#endif
case VIDIOC_QUERYCAP:
retval = ioctl_querycap(arg,cam);
break;
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index 76c054d1eef9..d9d2f6ad6ffb 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -1,9 +1,8 @@
config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
- depends on INPUT # due to VIDEO_IR
select I2C_ALGOBIT
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
index 8f55692db36d..82d195be9197 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ int ret;
+
+ snd_cx18_lock(cxsc);
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ snd_cx18_unlock(cxsc);
+ return ret;
}
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index fe1090940b01..87177733cf92 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -39,7 +39,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
-/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */
@@ -251,6 +251,66 @@ static const struct cx18_card cx18_card_mpc718 = {
/* ------------------------------------------------------------------------- */
+/* GoTView PCI */
+
+static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_gotview_dvd3 = {
+ .type = CX18_CARD_GOTVIEW_PCI_DVD3,
+ .name = "GoTView PCI DVD3 Hybrid",
+ .comment = "Experimenters needed for device to work well.\n"
+ "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_418_AV,
+ .hw_muxer = CX18_HW_GPIO_MUX,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+ CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 },
+ },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ /* FIXME - the FM radio is just a guess and driver doesn't use SIF */
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+ .ddr = {
+ /* Hynix HY5DU283222B DDR RAM */
+ .chip_config = 0x303,
+ .refresh = 0x3bd,
+ .timing1 = 0x36320966,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .gpio_init.initial_value = 0x1,
+ .gpio_init.direction = 0x3,
+
+ .gpio_audio_input = { .mask = 0x3,
+ .tuner = 0x1,
+ .linein = 0x2,
+ .radio = 0x1 },
+ .xceive_pin = 0,
+ .pci_list = cx18_pci_gotview_dvd3,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
@@ -463,6 +523,7 @@ static const struct cx18_card *cx18_card_list[] = {
&cx18_card_toshiba_qosmio_dvbt,
&cx18_card_leadtek_pvr2100,
&cx18_card_leadtek_dvr3100h,
+ &cx18_card_gotview_dvd3
};
const struct cx18_card *cx18_get_card(u16 index)
@@ -485,7 +546,6 @@ int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
"Component 1"
};
- memset(input, 0, sizeof(*input));
if (index >= cx->nof_inputs)
return -EINVAL;
input->index = index;
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 67043c7b452b..97d7b7e100a3 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -108,7 +108,7 @@ static int cx18_try_ctrl(struct file *file, void *fh,
struct v4l2_ext_control *vctrl)
{
struct v4l2_queryctrl qctrl;
- const char **menu_items = NULL;
+ const char * const *menu_items = NULL;
int err;
qctrl.id = vctrl->id;
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index df60f27337cf..133ec2bac180 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -156,6 +156,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
"\t\t\t 7 = Leadtek WinFast PVR2100\n"
"\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
+ "\t\t\t 9 = GoTView PCI DVD3 Hybrid\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");
@@ -266,8 +267,14 @@ static void request_modules(struct cx18 *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx18 *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/* Generic utility functions */
@@ -333,6 +340,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
tveeprom_hauppauge_analog(&c, tv, eedata);
break;
case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
tv->model = 0x718;
cx18_eeprom_dump(cx, eedata, sizeof(eedata));
CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
@@ -923,8 +931,13 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
CX18_MEM_SIZE);
if (!cx->enc_mem) {
- CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ CX18_ERR("ioremap failed. Can't get a window into CX23418 "
+ "memory and register space\n");
+ CX18_ERR("Each capture card with a CX23418 needs 64 MB of "
+ "vmalloc address space for the window\n");
+ CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ CX18_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1226,6 +1239,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
CX18_DEBUG_INFO("Removing Card\n");
+ flush_request_modules(cx);
+
/* Stop all captures */
CX18_DEBUG_INFO("Stopping all streams\n");
if (atomic_read(&cx->tot_capturing) > 0)
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 77be58c1096b..f6f3e50d4bdf 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -84,7 +84,8 @@
#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */
#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */
-#define CX18_CARD_LAST 7
+#define CX18_CARD_GOTVIEW_PCI_DVD3 8 /* GoTView PCI DVD3 Hybrid */
+#define CX18_CARD_LAST 8
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
@@ -106,6 +107,7 @@
#define CX18_PCI_ID_CONEXANT 0x14f1
#define CX18_PCI_ID_TOSHIBA 0x1179
#define CX18_PCI_ID_LEADTEK 0x107D
+#define CX18_PCI_ID_GOTVIEW 0x5854
/* ======================================================================== */
/* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -323,7 +325,10 @@ struct cx18_queue {
spinlock_t lock;
};
+struct cx18_stream; /* forward reference */
+
struct cx18_dvb {
+ struct cx18_stream *stream;
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
struct dmxdev dmxdev;
@@ -363,9 +368,10 @@ struct cx18_in_work_order {
#define CX18_INVALID_TASK_HANDLE 0xffffffff
struct cx18_stream {
- /* These first four fields are always set, even if the stream
+ /* These first five fields are always set, even if the stream
is not actually created. */
struct video_device *video_dev; /* NULL when stream not created */
+ struct cx18_dvb *dvb; /* DVB / Digital Transport */
struct cx18 *cx; /* for ease of use */
const char *name; /* name of the stream */
int type; /* stream type */
@@ -395,9 +401,6 @@ struct cx18_stream {
struct cx18_queue q_idle; /* idle - not in rotation */
struct work_struct out_work_order;
-
- /* DVB / Digital Transport */
- struct cx18_dvb dvb;
};
struct cx18_open_id {
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 6d19f040d70f..f0381d62518d 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -137,7 +137,7 @@ static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
{
struct cx18_dvb *dvb = container_of(fe->dvb,
struct cx18_dvb, dvb_adapter);
- struct cx18_stream *stream = container_of(dvb, struct cx18_stream, dvb);
+ struct cx18_stream *stream = dvb->stream;
const struct firmware *fw = NULL;
int ret;
int i;
@@ -203,6 +203,14 @@ static struct zl10353_config yuan_mpc718_zl10353_demod = {
.disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
};
+static struct zl10353_config gotview_dvd3_zl10353_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
+};
+
static int dvb_register(struct cx18_stream *stream);
/* Kernel DVB framework calls this when the feed needs to start.
@@ -247,6 +255,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
case CX18_CARD_LEADTEK_DVR3100H:
case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
default:
/* Assumption - Parallel transport - Signalling
* undefined or default.
@@ -257,22 +266,22 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (!demux->dmx.frontend)
return -EINVAL;
- mutex_lock(&stream->dvb.feedlock);
- if (stream->dvb.feeding++ == 0) {
+ mutex_lock(&stream->dvb->feedlock);
+ if (stream->dvb->feeding++ == 0) {
CX18_DEBUG_INFO("Starting Transport DMA\n");
mutex_lock(&cx->serialize_lock);
set_bit(CX18_F_S_STREAMING, &stream->s_flags);
ret = cx18_start_v4l2_encode_stream(stream);
if (ret < 0) {
CX18_DEBUG_INFO("Failed to start Transport DMA\n");
- stream->dvb.feeding--;
- if (stream->dvb.feeding == 0)
+ stream->dvb->feeding--;
+ if (stream->dvb->feeding == 0)
clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
}
mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
- mutex_unlock(&stream->dvb.feedlock);
+ mutex_unlock(&stream->dvb->feedlock);
return ret;
}
@@ -290,15 +299,15 @@ static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
feed->pid, feed->index);
- mutex_lock(&stream->dvb.feedlock);
- if (--stream->dvb.feeding == 0) {
+ mutex_lock(&stream->dvb->feedlock);
+ if (--stream->dvb->feeding == 0) {
CX18_DEBUG_INFO("Stopping Transport DMA\n");
mutex_lock(&cx->serialize_lock);
ret = cx18_stop_v4l2_encode_stream(stream, 0);
mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
- mutex_unlock(&stream->dvb.feedlock);
+ mutex_unlock(&stream->dvb->feedlock);
}
return ret;
@@ -307,7 +316,7 @@ static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
int cx18_dvb_register(struct cx18_stream *stream)
{
struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct dvb_adapter *dvb_adapter;
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
@@ -316,6 +325,9 @@ int cx18_dvb_register(struct cx18_stream *stream)
if (!dvb)
return -EINVAL;
+ dvb->enabled = 0;
+ dvb->stream = stream;
+
ret = dvb_register_adapter(&dvb->dvb_adapter,
CX18_DRIVER_NAME,
THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
@@ -369,7 +381,7 @@ int cx18_dvb_register(struct cx18_stream *stream)
CX18_INFO("DVB Frontend registered\n");
CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
- stream->dvb.dvb_adapter.num, stream->name,
+ stream->dvb->dvb_adapter.num, stream->name,
stream->buffers, stream->buf_size/1024,
(stream->buf_size * 100 / 1024) % 100);
@@ -396,13 +408,16 @@ err_out:
void cx18_dvb_unregister(struct cx18_stream *stream)
{
struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct dvb_adapter *dvb_adapter;
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
CX18_INFO("unregister DVB\n");
+ if (dvb == NULL || !dvb->enabled)
+ return;
+
dvb_adapter = &dvb->dvb_adapter;
dvbdemux = &dvb->demux;
dmx = &dvbdemux->dmx;
@@ -423,7 +438,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream)
*/
static int dvb_register(struct cx18_stream *stream)
{
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct cx18 *cx = stream->cx;
int ret = 0;
@@ -495,6 +510,29 @@ static int dvb_register(struct cx18_stream *stream)
fe->ops.tuner_ops.set_config(fe, &ctrl);
}
break;
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
+ dvb->fe = dvb_attach(zl10353_attach,
+ &gotview_dvd3_zl10353_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
default:
/* No Digital Tv Support */
break;
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index a09caf883170..c330fb917b50 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -98,7 +98,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
case CX18_HW_Z8F0811_IR_RX_HAUP:
init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
init_data->name = cx->card_name;
info.platform_data = init_data;
break;
@@ -122,15 +122,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->radio);
+ adap, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->demod);
+ adap, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, NULL, type, 0, cx->card_i2c->tv);
+ adap, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
@@ -144,7 +144,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;
/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx],
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
NULL);
if (sd != NULL)
sd->grp_id = hw;
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 956aa190ecca..c545f3beef78 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -136,7 +136,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
{
struct cx18_buffer *buf;
- if (!s->dvb.enabled || mdl->bytesused == 0)
+ if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0)
return;
/* We ignore mdl and buf readpos accounting here - it doesn't matter */
@@ -146,7 +146,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
list);
if (buf->bytesused)
- dvb_dmx_swfilter(&s->dvb.demux,
+ dvb_dmx_swfilter(&s->dvb->demux,
buf->buf, buf->bytesused);
return;
}
@@ -154,7 +154,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
list_for_each_entry(buf, &mdl->buf_list, list) {
if (buf->bytesused == 0)
break;
- dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused);
+ dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused);
}
}
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 9045f1ece0eb..94f5d7967c5c 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */
- .ioctl = cx18_v4l2_ioctl,
+ .unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
@@ -107,6 +107,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->video_dev = video_dev;
/* initialize cx18_stream fields */
+ s->dvb = NULL;
s->cx = cx;
s->type = type;
s->name = cx18_stream_info[type].name;
@@ -140,10 +141,15 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
int num_offset = cx18_stream_info[type].num_offset;
int num = cx->instance + cx18_first_minor + num_offset;
- /* These four fields are always initialized. If video_dev == NULL, then
- this stream is not in use. In that case no other fields but these
- four can be used. */
+ /*
+ * These five fields are always initialized.
+ * For analog capture related streams, if video_dev == NULL then the
+ * stream is not in use.
+ * For the TS stream, if dvb == NULL then the stream is not in use.
+ * In those cases no other fields but these four can be used.
+ */
s->video_dev = NULL;
+ s->dvb = NULL;
s->cx = cx;
s->type = type;
s->name = cx18_stream_info[type].name;
@@ -167,6 +173,21 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
cx18_stream_init(cx, type);
+ /* Allocate the cx18_dvb struct only for the TS on cards with DTV */
+ if (type == CX18_ENC_STREAM_TYPE_TS) {
+ if (cx->card->hw_all & CX18_HW_DVB) {
+ s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL);
+ if (s->dvb == NULL) {
+ CX18_ERR("Couldn't allocate cx18_dvb structure"
+ " for %s\n", s->name);
+ return -ENOMEM;
+ }
+ } else {
+ /* Don't need buffers for the TS, if there is no DVB */
+ s->buffers = 0;
+ }
+ }
+
if (num_offset == -1)
return 0;
@@ -222,13 +243,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
const char *name;
int num, ret;
- /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
- * We need a VFL_TYPE_TS defined.
- */
- if (strcmp("TS", s->name) == 0) {
- /* just return if no DVB is supported */
- if ((cx->card->hw_all & CX18_HW_DVB) == 0)
- return 0;
+ if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) {
ret = cx18_dvb_register(s);
if (ret < 0) {
CX18_ERR("DVB failed to register\n");
@@ -320,11 +335,13 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
/* Teardown all streams */
for (type = 0; type < CX18_MAX_STREAMS; type++) {
- /* No struct video_device, but can have buffers allocated */
+ /* The TS has a cx18_dvb structure, not a video_device */
if (type == CX18_ENC_STREAM_TYPE_TS) {
- if (cx->streams[type].dvb.enabled) {
- cx18_dvb_unregister(&cx->streams[type]);
- cx->streams[type].dvb.enabled = false;
+ if (cx->streams[type].dvb != NULL) {
+ if (unregister)
+ cx18_dvb_unregister(&cx->streams[type]);
+ kfree(cx->streams[type].dvb);
+ cx->streams[type].dvb = NULL;
cx18_stream_free(&cx->streams[type]);
}
continue;
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 77412bee5963..51765eb12d39 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -33,7 +33,8 @@ void cx18_stream_rotate_idx_mdls(struct cx18 *cx);
static inline bool cx18_stream_enabled(struct cx18_stream *s)
{
- return s->video_dev || s->dvb.enabled ||
+ return s->video_dev ||
+ (s->dvb && s->dvb->enabled) ||
(s->type == CX18_ENC_STREAM_TYPE_IDX &&
s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0);
}
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 2c00980acfcb..7e40035028d2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -177,7 +177,7 @@
IN[0] - Task handle.
IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
3 = 2D H/V separable, 4 = 2D symmetric non-separable
- IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
+ IN[2] - chroma type: 0 - disable, 1 = 1D horizontal
ReturnCode - One of the ERR_CAPTURE_... */
#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
index bb04914983fd..ae85a7a7bd73 100644
--- a/drivers/media/video/cx231xx/Kconfig
+++ b/drivers/media/video/cx231xx/Kconfig
@@ -1,9 +1,9 @@
config VIDEO_CX231XX
tristate "Conexant cx231xx USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT
+ depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select VIDEO_CX25840
select VIDEO_CX2341X
@@ -14,6 +14,19 @@ config VIDEO_CX231XX
To compile this driver as a module, choose M here: the
module will be called cx231xx
+config VIDEO_CX231XX_RC
+ bool "Conexant cx231xx Remote Controller additional support"
+ depends on RC_CORE
+ depends on VIDEO_CX231XX
+ default y
+ ---help---
+ cx231xx hardware has a builtin RX/TX support. However, a few
+ designs opted to not use it, but, instead, some other hardware.
+ This module enables the usage of those other hardware, like the
+ ones used with ISDB-T boards.
+
+ On most cases, all you need for IR is mceusb module.
+
config VIDEO_CX231XX_ALSA
tristate "Conexant Cx231xx ALSA audio module"
depends on VIDEO_CX231XX && SND
@@ -30,6 +43,8 @@ config VIDEO_CX231XX_DVB
depends on VIDEO_CX231XX && DVB_CORE
select VIDEOBUF_DVB
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE
+ select DVB_MB86A20S if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
index a6bc4cc54677..2c2484355449 100644
--- a/drivers/media/video/cx231xx/Makefile
+++ b/drivers/media/video/cx231xx/Makefile
@@ -1,5 +1,6 @@
-cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
- cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o
+cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o
cx231xx-alsa-objs := cx231xx-audio.o
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
index aab21f3ce472..fc9526a5b746 100644
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -941,14 +940,14 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
u16 _buffer_size = 4096;
u8 *p_buffer;
- p_current_fw = (u32 *)vmalloc(1884180*4);
+ p_current_fw = vmalloc(1884180 * 4);
p_fw = p_current_fw;
if (p_current_fw == 0) {
dprintk(2, "FAIL!!!\n");
return -1;
}
- p_buffer = (u8 *)vmalloc(4096);
+ p_buffer = vmalloc(4096);
if (p_buffer == 0) {
dprintk(2, "FAIL!!!\n");
return -1;
@@ -1927,10 +1926,9 @@ static int mpeg_open(struct file *file)
dev = h;
}
- if (dev == NULL) {
- unlock_kernel();
+ if (dev == NULL)
return -ENODEV;
- }
+
mutex_lock(&dev->lock);
/* allocate + initialize per filehandle data */
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index cf50fafa8abb..c53e97295a0d 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -274,7 +274,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
if (ch1_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH1, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch1_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH1, value);
@@ -282,7 +282,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
if (ch2_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH2, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch2_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH2, value);
@@ -292,7 +292,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
7 less than the input number */
if (ch3_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch3_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH3, value);
@@ -354,6 +354,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
FLD_PWRDN_ENABLE_PLL)) {
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 56c2d8195ac6..588f3e8f028b 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -34,6 +34,7 @@
#include <media/cx25840.h>
#include "dvb-usb-ids.h"
#include "xc5000.h"
+#include "tda18271.h"
#include "cx231xx.h"
@@ -395,6 +396,45 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = 0,
} },
},
+ [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
+ .name = "Pixelview PlayTV USB Hybrid",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */
+ .tuner_sif_gpio = -1,
+ .tuner_scl_gpio = -1,
+ .tuner_sda_gpio = -1,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 2,
+ .demod_i2c_master = 1,
+ .ir_i2c_master = 2,
+ .rc_map_name = RC_MAP_PIXELVIEW_002T,
+ .has_dvb = 1,
+ .demod_addr = 0x10,
+ .norm = V4L2_STD_PAL_M,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -402,8 +442,6 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
struct usb_device_id cx231xx_id_table[] = {
{USB_DEVICE(0x0572, 0x5A3C),
.driver_info = CX231XX_BOARD_UNKNOWN},
- {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000,0x4fff),
- .driver_info = CX231XX_BOARD_UNKNOWN},
{USB_DEVICE(0x0572, 0x58A2),
.driver_info = CX231XX_BOARD_CNXT_CARRAERA},
{USB_DEVICE(0x0572, 0x58A1),
@@ -424,6 +462,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
{USB_DEVICE(0x2040, 0xc200),
.driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
+ {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001),
+ .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
{},
};
@@ -453,6 +493,16 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
1);
msleep(10);
}
+ } else if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ switch (command) {
+ case TDA18271_CALLBACK_CMD_AGC_ENABLE:
+ if (dev->model == CX231XX_BOARD_PV_PLAYTV_USB_HYBRID)
+ rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
}
return rc;
}
@@ -560,7 +610,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[0].i2c_adap,
- NULL, "cx25840", 0x88 >> 1, NULL);
+ "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
cx231xx_info("cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
@@ -571,7 +621,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
- NULL, "tuner",
+ "tuner",
dev->tuner_addr, NULL);
if (dev->sd_tuner == NULL)
cx231xx_info("tuner subdev registration failure\n");
@@ -615,8 +665,11 @@ void cx231xx_release_resources(struct cx231xx *dev)
cx231xx_remove_from_devlist(dev);
+ /* Release I2C buses */
cx231xx_dev_uninit(dev);
+ cx231xx_ir_exit(dev);
+
usb_put_dev(dev->udev);
/* Mark device as unused */
@@ -731,16 +784,14 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
retval = cx231xx_register_analog_devices(dev);
if (retval < 0) {
cx231xx_release_resources(dev);
- goto fail_reg_devices;
+ return retval;
}
+ cx231xx_ir_init(dev);
+
cx231xx_init_extension(dev);
return 0;
-
-fail_reg_devices:
- mutex_unlock(&dev->lock);
- return retval;
}
#if defined(CONFIG_MODULES) && defined(MODULE)
@@ -762,8 +813,14 @@ static void request_modules(struct cx231xx *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx231xx *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/*
@@ -1096,6 +1153,8 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
if (!dev->udev)
return;
+ flush_request_modules(dev);
+
/* delete v4l2 device */
v4l2_device_unregister(&dev->v4l2_dev);
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index 4af46fca9b0a..7d62d58617f5 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -740,6 +740,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
break;
default:
@@ -1288,7 +1289,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
/* Internal Master 3 Bus */
dev->i2c_bus[2].nr = 2;
dev->i2c_bus[2].dev = dev;
- dev->i2c_bus[2].i2c_period = I2C_SPEED_400K; /* 400kHz */
+ dev->i2c_bus[2].i2c_period = I2C_SPEED_100K; /* 100kHz */
dev->i2c_bus[2].i2c_nostop = 0;
dev->i2c_bus[2].i2c_reserve = 0;
@@ -1381,6 +1382,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
break;
default:
@@ -1513,7 +1515,7 @@ int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
@@ -1564,7 +1566,7 @@ int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
@@ -1598,7 +1600,7 @@ int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
@@ -1639,7 +1641,7 @@ int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index 5feb3ee640d9..fe59a1c3f064 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -33,6 +33,7 @@
#include "tda18271.h"
#include "s5h1411.h"
#include "lgdt3305.h"
+#include "mb86a20s.h"
MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
@@ -88,6 +89,11 @@ static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
.if_lvl = 1, .rfagc_top = 0x37, },
};
+static struct tda18271_std_map mb86a20s_tda18271_config = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
static struct tda18271_config cnxt_rde253s_tunerconfig = {
.std_map = &cnxt_rde253s_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
@@ -135,6 +141,17 @@ static struct tda18271_config hcw_tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
};
+static const struct mb86a20s_config pv_mb86a20s_config = {
+ .demod_address = 0x10,
+ .is_serial = true,
+};
+
+static struct tda18271_config pv_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_config,
+ .gate = TDA18271_GATE_DIGITAL,
+ .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
+};
+
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
{
char *errmsg = "Unknown";
@@ -687,6 +704,29 @@ static int dvb_init(struct cx231xx *dev)
&hcw_tda18271_config);
break;
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+
+ printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+ dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+ &pv_mb86a20s_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach mb86a20s demod\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &pv_tda18271_config);
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
new file mode 100644
index 000000000000..45e14cac4622
--- /dev/null
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -0,0 +1,112 @@
+/*
+ * cx231xx IR glue driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Polaris (cx231xx) has its support for IR's with a design close to MCE.
+ * however, a few designs are using an external I2C chip for IR, instead
+ * of using the one provided by the chip.
+ * This driver provides support for those extra devices
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 "cx231xx.h"
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "cx231xx-input"
+
+static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw)
+{
+ u8 cmd, scancode;
+
+ dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(ir->c, &cmd, 1))
+ return -EIO;
+
+ /* it seems that 0xFE indicates that a button is still hold
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+ if (cmd == 0xff)
+ return 0;
+
+ scancode =
+ ((cmd & 0x01) ? 0x80 : 0) |
+ ((cmd & 0x02) ? 0x40 : 0) |
+ ((cmd & 0x04) ? 0x20 : 0) |
+ ((cmd & 0x08) ? 0x10 : 0) |
+ ((cmd & 0x10) ? 0x08 : 0) |
+ ((cmd & 0x20) ? 0x04 : 0) |
+ ((cmd & 0x40) ? 0x02 : 0) |
+ ((cmd & 0x80) ? 0x01 : 0);
+
+ dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
+ cmd, scancode);
+
+ *ir_key = scancode;
+ *ir_raw = scancode;
+ return 1;
+}
+
+int cx231xx_ir_init(struct cx231xx *dev)
+{
+ struct i2c_board_info info;
+ u8 ir_i2c_bus;
+
+ dev_dbg(&dev->udev->dev, "%s\n", __func__);
+
+ /* Only initialize if a rc keycode map is defined */
+ if (!cx231xx_boards[dev->model].rc_map_name)
+ return -ENODEV;
+
+ request_module("ir-kbd-i2c");
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ dev->init_data.rc_dev = rc_allocate_device();
+ if (!dev->init_data.rc_dev)
+ return -ENOMEM;
+
+ dev->init_data.name = cx231xx_boards[dev->model].name;
+
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ info.platform_data = &dev->init_data;
+
+ /*
+ * Board-dependent values
+ *
+ * For now, there's just one type of hardware design using
+ * an i2c device.
+ */
+ dev->init_data.get_key = get_key_isdbt;
+ dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name;
+ /* The i2c micro-controller only outputs the cmd part of NEC protocol */
+ dev->init_data.rc_dev->scanmask = 0xff;
+ dev->init_data.rc_dev->driver_name = "cx231xx";
+ dev->init_data.type = RC_TYPE_NEC;
+ info.addr = 0x30;
+
+ /* Load and bind ir-kbd-i2c */
+ ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
+ dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
+ ir_i2c_bus, info.addr);
+ i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+
+ return 0;
+}
+
+void cx231xx_ir_exit(struct cx231xx *dev)
+{
+}
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index b13b69fb2af6..7e3e8c4f19b7 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -2044,15 +2044,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct cx231xx_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -2507,9 +2498,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device cx231xx_vbi_template;
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index d067df9b81e7..72bbea2bcd56 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -34,7 +34,8 @@
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dvb.h>
#include "cx231xx-reg.h"
@@ -62,6 +63,7 @@
#define CX231XX_BOARD_CNXT_RDU_250 7
#define CX231XX_BOARD_HAUPPAUGE_EXETER 8
#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
+#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -344,6 +346,10 @@ struct cx231xx_board {
/* i2c masters */
u8 tuner_i2c_master;
u8 demod_i2c_master;
+ u8 ir_i2c_master;
+
+ /* for devices with I2C chips for IR */
+ char *rc_map_name;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
@@ -356,7 +362,7 @@ struct cx231xx_board {
struct cx231xx_input input[MAX_CX231XX_INPUT];
struct cx231xx_input radio;
- struct ir_scancode_table *ir_codes;
+ struct rc_map *ir_codes;
};
/* device states */
@@ -605,6 +611,9 @@ struct cx231xx {
struct cx231xx_board board;
+ /* For I2C IR support */
+ struct IR_i2c_init_data init_data;
+
unsigned int stream_on:1; /* Locks streams */
unsigned int vbi_stream_on:1; /* Locks streams for VBI */
unsigned int has_audio_class:1;
@@ -616,8 +625,6 @@ struct cx231xx {
struct v4l2_subdev *sd_cx25840;
struct v4l2_subdev *sd_tuner;
- struct cx231xx_IR *ir;
-
struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
atomic_t stream_started; /* stream should be running if true */
@@ -954,6 +961,17 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
extern int cx231xx_417_register(struct cx231xx *dev);
extern void cx231xx_417_unregister(struct cx231xx *dev);
+/* cx23885-input.c */
+
+#if defined(CONFIG_VIDEO_CX231XX_RC)
+int cx231xx_ir_init(struct cx231xx *dev);
+void cx231xx_ir_exit(struct cx231xx *dev);
+#else
+#define cx231xx_ir_init(dev) (0)
+#define cx231xx_ir_exit(dev) (0)
+#endif
+
+
/* printk macros */
#define cx231xx_err(fmt, arg...) do {\
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index e5c3c8da4be3..103ef6bad2e2 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -853,9 +853,9 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
}
EXPORT_SYMBOL(cx2341x_ctrl_query);
-const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
{
- static const char *mpeg_stream_type_without_ts[] = {
+ static const char * const mpeg_stream_type_without_ts[] = {
"MPEG-2 Program Stream",
"",
"MPEG-1 System Stream",
@@ -952,7 +952,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
for (i = 0; i < ctrls->count; i++) {
struct v4l2_ext_control *ctrl = ctrls->controls + i;
struct v4l2_queryctrl qctrl;
- const char **menu_items = NULL;
+ const char * const *menu_items = NULL;
qctrl.id = ctrl->id;
err = cx2341x_ctrl_query(params, &qctrl);
@@ -1135,7 +1135,7 @@ EXPORT_SYMBOL(cx2341x_update);
static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
{
- const char **menu = cx2341x_ctrl_get_menu(p, id);
+ const char * const *menu = cx2341x_ctrl_get_menu(p, id);
struct v4l2_ext_control ctrl;
if (menu == NULL)
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index e1367b35647a..6b4a516addfe 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -5,7 +5,7 @@ config VIDEO_CX23885
select VIDEO_BTCX
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on IR_CORE
+ depends on RC_CORE
select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
select VIDEO_CX25840
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index c95e7bc14745..209b971bd267 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -368,7 +368,7 @@ static void netup_read_ci_status(struct work_struct *work)
DVB_CA_EN50221_POLL_CAM_READY;
else
state->status = 0;
- };
+ }
}
/* CI irq handler */
@@ -377,16 +377,24 @@ int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
struct cx23885_tsport *port = NULL;
struct netup_ci_state *state = NULL;
- if (pci_status & PCI_MSK_GPIO0)
- port = &dev->ts1;
- else if (pci_status & PCI_MSK_GPIO1)
- port = &dev->ts2;
- else /* who calls ? */
+ ci_dbg_print("%s:\n", __func__);
+
+ if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1)))
return 0;
- state = port->port_priv;
+ if (pci_status & PCI_MSK_GPIO0) {
+ port = &dev->ts1;
+ state = port->port_priv;
+ schedule_work(&state->work);
+ ci_dbg_print("%s: Wakeup CI0\n", __func__);
+ }
- schedule_work(&state->work);
+ if (pci_status & PCI_MSK_GPIO1) {
+ port = &dev->ts2;
+ state = port->port_priv;
+ schedule_work(&state->work);
+ ci_dbg_print("%s: Wakeup CI1\n", __func__);
+ }
return 1;
}
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index a6cc12f8736c..9a98dc55f657 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -1576,12 +1575,8 @@ static int mpeg_open(struct file *file)
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ if (!fh)
return -ENOMEM;
- }
-
- lock_kernel();
file->private_data = fh;
fh->dev = dev;
@@ -1592,8 +1587,6 @@ static int mpeg_open(struct file *file)
V4L2_FIELD_INTERLACED,
sizeof(struct cx23885_buffer),
fh, NULL);
- unlock_kernel();
-
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index db054004e462..b298b730943c 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -309,6 +309,26 @@ struct cx23885_board cx23885_boards[] = {
CX25840_COMPONENT_ON,
} },
},
+ [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = {
+ .name = "GoTView X5 3D Hybrid",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x64,
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2,
+ .gpio0 = 0x02,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX23885_VMUX_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ } },
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -496,6 +516,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x107d,
.subdevice = 0x6f22,
.card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
+ }, {
+ .subvendor = 0x5654,
+ .subdevice = 0x2390,
+ .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -712,6 +736,10 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
else if (port->nr == 2)
bitmask = 0x04;
break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ /* Tuner Reset Command */
+ bitmask = 0x02;
+ break;
}
if (bitmask) {
@@ -967,6 +995,9 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* CX24228 GPIO */
/* Connected to IF / Mux */
break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
}
}
@@ -1218,6 +1249,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -1245,9 +1277,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
- NULL, "cx25840", 0x88 >> 1, NULL);
+ "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840) {
dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index bb61870b8d6e..199b9964bbe5 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -35,9 +35,8 @@
* 02110-1301, USA.
*/
-#include <linux/input.h>
#include <linux/slab.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <media/v4l2-subdev.h>
#include "cx23885.h"
@@ -62,16 +61,16 @@ static void cx23885_input_process_measurements(struct cx23885_dev *dev,
count = num / sizeof(struct ir_raw_event);
for (i = 0; i < count; i++) {
- ir_raw_event_store(kernel_ir->inp_dev,
+ ir_raw_event_store(kernel_ir->rc,
&ir_core_event[i]);
handle = true;
}
} while (num != 0);
if (overrun)
- ir_raw_event_reset(kernel_ir->inp_dev);
+ ir_raw_event_reset(kernel_ir->rc);
else if (handle)
- ir_raw_event_handle(kernel_ir->inp_dev);
+ ir_raw_event_handle(kernel_ir->rc);
}
void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
@@ -197,9 +196,9 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
return 0;
}
-static int cx23885_input_ir_open(void *priv)
+static int cx23885_input_ir_open(struct rc_dev *rc)
{
- struct cx23885_kernel_ir *kernel_ir = priv;
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
if (kernel_ir->cx == NULL)
return -ENODEV;
@@ -230,13 +229,11 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
}
-
- flush_scheduled_work();
}
-static void cx23885_input_ir_close(void *priv)
+static void cx23885_input_ir_close(struct rc_dev *rc)
{
- struct cx23885_kernel_ir *kernel_ir = priv;
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
if (kernel_ir->cx != NULL)
cx23885_input_ir_stop(kernel_ir->cx);
@@ -245,9 +242,7 @@ static void cx23885_input_ir_close(void *priv)
int cx23885_input_init(struct cx23885_dev *dev)
{
struct cx23885_kernel_ir *kernel_ir;
- struct input_dev *inp_dev;
- struct ir_dev_props *props;
-
+ struct rc_dev *rc;
char *rc_map;
enum rc_driver_type driver_type;
unsigned long allowed_protos;
@@ -267,14 +262,14 @@ int cx23885_input_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1250:
/* Integrated CX2388[58] IR controller */
driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = IR_TYPE_ALL;
+ allowed_protos = RC_TYPE_ALL;
/* The grey Hauppauge RC-5 remote */
rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
break;
case CX23885_BOARD_TEVII_S470:
/* Integrated CX23885 IR controller */
driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = IR_TYPE_ALL;
+ allowed_protos = RC_TYPE_ALL;
/* A guess at the remote */
rc_map = RC_MAP_TEVII_NEC;
break;
@@ -294,37 +289,36 @@ int cx23885_input_init(struct cx23885_dev *dev)
pci_name(dev->pci));
/* input device */
- inp_dev = input_allocate_device();
- if (inp_dev == NULL) {
+ rc = rc_allocate_device();
+ if (!rc) {
ret = -ENOMEM;
goto err_out_free;
}
- kernel_ir->inp_dev = inp_dev;
- inp_dev->name = kernel_ir->name;
- inp_dev->phys = kernel_ir->phys;
- inp_dev->id.bustype = BUS_PCI;
- inp_dev->id.version = 1;
+ kernel_ir->rc = rc;
+ rc->input_name = kernel_ir->name;
+ rc->input_phys = kernel_ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (dev->pci->subsystem_vendor) {
- inp_dev->id.vendor = dev->pci->subsystem_vendor;
- inp_dev->id.product = dev->pci->subsystem_device;
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
} else {
- inp_dev->id.vendor = dev->pci->vendor;
- inp_dev->id.product = dev->pci->device;
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
}
- inp_dev->dev.parent = &dev->pci->dev;
-
- /* kernel ir device properties */
- props = &kernel_ir->props;
- props->driver_type = driver_type;
- props->allowed_protos = allowed_protos;
- props->priv = kernel_ir;
- props->open = cx23885_input_ir_open;
- props->close = cx23885_input_ir_close;
+ rc->dev.parent = &dev->pci->dev;
+ rc->driver_type = driver_type;
+ rc->allowed_protos = allowed_protos;
+ rc->priv = kernel_ir;
+ rc->open = cx23885_input_ir_open;
+ rc->close = cx23885_input_ir_close;
+ rc->map_name = rc_map;
+ rc->driver_name = MODULE_NAME;
/* Go */
dev->kernel_ir = kernel_ir;
- ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME);
+ ret = rc_register_device(rc);
if (ret)
goto err_out_stop;
@@ -333,7 +327,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
err_out_stop:
cx23885_input_ir_stop(dev);
dev->kernel_ir = NULL;
- /* TODO: double check clean-up of kernel_ir->inp_dev */
+ rc_free_device(rc);
err_out_free:
kfree(kernel_ir->phys);
kfree(kernel_ir->name);
@@ -348,7 +342,7 @@ void cx23885_input_fini(struct cx23885_dev *dev)
if (dev->kernel_ir == NULL)
return;
- ir_input_unregister(dev->kernel_ir->inp_dev);
+ rc_unregister_device(dev->kernel_ir->rc);
kfree(dev->kernel_ir->phys);
kfree(dev->kernel_ir->name);
kfree(dev->kernel_ir);
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 93af9c65b484..644fcb808c0b 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -26,7 +26,6 @@
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kthread.h>
@@ -743,8 +742,6 @@ static int video_open(struct file *file)
if (NULL == fh)
return -ENOMEM;
- lock_kernel();
-
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -762,8 +759,6 @@ static int video_open(struct file *file)
dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
return 0;
}
@@ -1029,35 +1024,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
- struct video_mbuf *mbuf)
-{
- struct cx23885_fh *fh = priv;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int err;
-
- q = get_queue(fh);
- memset(&req, 0, sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q, &req);
- if (err < 0)
- return err;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
-}
-#endif
-
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -1160,7 +1126,6 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
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]);
@@ -1432,9 +1397,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.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,
@@ -1512,10 +1474,10 @@ int cx23885_video_register(struct cx23885_dev *dev)
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
else
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[1].i2c_adap, NULL,
+ &dev->i2c_bus[1].i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index ed94b17dd8a5..62e41ab65810 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -30,7 +30,7 @@
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "btcx-risc.h"
#include "cx23885-reg.h"
@@ -84,6 +84,7 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1290 26
#define CX23885_BOARD_MYGICA_X8558PRO 27
#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
+#define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -310,8 +311,7 @@ struct cx23885_kernel_ir {
char *name;
char *phys;
- struct input_dev *inp_dev;
- struct ir_dev_props props;
+ struct rc_dev *rc;
};
struct cx23885_dev {
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index e78e3e4c8112..e37be6fcf67d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -26,7 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "cx23885.h"
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index dfb198d0415b..f16461844c5c 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1989,8 +1989,23 @@ static int cx25840_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_HUE, -128, 127, 1, 0);
if (!is_cx2583x(state)) {
- default_volume = 228 - cx25840_read(client, 0x8d4);
- default_volume = ((default_volume / 2) + 23) << 9;
+ default_volume = cx25840_read(client, 0x8d4);
+ /*
+ * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
+ * scale mapping limits to avoid -ERANGE errors when
+ * initializing the volume control
+ */
+ if (default_volume > 228) {
+ /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+ default_volume = 228;
+ cx25840_write(client, 0x8d4, 228);
+ }
+ else if (default_volume < 20) {
+ /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+ default_volume = 20;
+ cx25840_write(client, 0x8d4, 20);
+ }
+ default_volume = (((228 - default_volume) >> 1) + 23) << 9;
state->volume = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
index 97a4e9b25fe4..7eb79af28aa3 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <media/cx25840.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "cx25840-core.h"
@@ -261,7 +261,7 @@ static u16 ns_to_pulse_width_count(u32 ns, u16 divider)
u32 rem;
/*
- * The 2 lsb's of the pulse width timer count are not accessable, hence
+ * The 2 lsb's of the pulse width timer count are not accessible, hence
* the (1 << 2)
*/
n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0fa85cbefbb1..5c42abdf422f 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,12 +1,11 @@
config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && INPUT
+ depends on VIDEO_DEV && PCI && I2C && RC_CORE
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on VIDEO_IR
select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Conexant 2388x based
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 4aaa47c0eabf..54b7fcd469a8 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -40,7 +40,6 @@
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <media/wm8775.h>
#include "cx88.h"
#include "cx88-reg.h"
@@ -587,47 +586,26 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
int left, right, v, b;
int changed = 0;
u32 old;
- struct v4l2_control client_ctl;
-
- /* Pass volume & balance onto any WM8775 */
- if (value->value.integer.value[0] >= value->value.integer.value[1]) {
- v = value->value.integer.value[0] << 10;
- b = value->value.integer.value[0] ?
- (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
- 0x8000;
- } else {
- v = value->value.integer.value[1] << 10;
- b = value->value.integer.value[1] ?
- 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
- 0x8000;
- }
- client_ctl.value = v;
- client_ctl.id = V4L2_CID_AUDIO_VOLUME;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
- client_ctl.value = b;
- client_ctl.id = V4L2_CID_AUDIO_BALANCE;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
left = value->value.integer.value[0] & 0x3f;
right = value->value.integer.value[1] & 0x3f;
b = right - left;
if (b < 0) {
- v = 0x3f - left;
- b = (-b) | 0x40;
+ v = 0x3f - left;
+ b = (-b) | 0x40;
} else {
- v = 0x3f - right;
+ v = 0x3f - right;
}
/* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);
old = cx_read(AUD_VOL_CTL);
if (v != (old & 0x3f)) {
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
- changed = 1;
+ cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
+ changed = 1;
}
- if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
- cx_write(AUD_BAL_CTL, b);
- changed = 1;
+ if (cx_read(AUD_BAL_CTL) != b) {
+ cx_write(AUD_BAL_CTL, b);
+ changed = 1;
}
spin_unlock_irq(&chip->reg_lock);
@@ -640,7 +618,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .name = "Analog-TV Volume",
+ .name = "Playback Volume",
.info = snd_cx88_volume_info,
.get = snd_cx88_volume_get,
.put = snd_cx88_volume_put,
@@ -671,14 +649,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
vol = cx_read(AUD_VOL_CTL);
if (value->value.integer.value[0] != !(vol & bit)) {
vol ^= bit;
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
- /* Pass mute onto any WM8775 */
- if ((1<<6) == bit) {
- struct v4l2_control client_ctl;
- client_ctl.value = 0 != (vol & bit);
- client_ctl.id = V4L2_CID_AUDIO_MUTE;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
- }
+ cx_write(AUD_VOL_CTL, vol);
ret = 1;
}
spin_unlock_irq(&chip->reg_lock);
@@ -687,7 +658,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new snd_cx88_dac_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Audio-Out Switch",
+ .name = "Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = snd_cx88_switch_get,
.put = snd_cx88_switch_put,
@@ -696,49 +667,13 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
static const struct snd_kcontrol_new snd_cx88_source_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog-TV Switch",
+ .name = "Capture Switch",
.info = snd_ctl_boolean_mono_info,
.get = snd_cx88_switch_get,
.put = snd_cx88_switch_put,
.private_value = (1<<6),
};
-static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- struct v4l2_control client_ctl;
-
- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
- call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
- value->value.integer.value[0] = client_ctl.value ? 1 : 0;
-
- return 0;
-}
-
-static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- struct v4l2_control client_ctl;
-
- client_ctl.value = 0 != value->value.integer.value[0];
- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
- return 0;
-}
-
-static struct snd_kcontrol_new snd_cx88_alc_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In ALC Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = snd_cx88_alc_get,
- .put = snd_cx88_alc_put,
-};
-
/****************************************************************************
Basic Flow for Sound Devices
****************************************************************************/
@@ -860,7 +795,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
{
struct snd_card *card;
snd_cx88_card_t *chip;
- struct v4l2_subdev *sd;
int err;
if (devno >= SNDRV_CARDS)
@@ -896,15 +830,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
if (err < 0)
goto error;
- /* If there's a wm8775 then add a Line-In ALC switch */
- list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
- if (WM8775_GID == sd->grp_id) {
- snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
- chip));
- break;
- }
- }
-
strcpy (card->driver, "CX88x");
sprintf(card->shortname, "Conexant CX%x", pci->device);
sprintf(card->longname, "%s at %#llx",
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 417d1d5c73c4..bca307eb1e24 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/cx2341x.h>
@@ -1065,7 +1064,7 @@ static int mpeg_open(struct file *file)
err = drv->request_acquire(drv);
if(err != 0) {
dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
- mutex_unlock(&dev->core->lock);;
+ mutex_unlock(&dev->core->lock);
return err;
}
}
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index b26fcba8600c..4e6ee5584cb3 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -47,7 +47,7 @@ MODULE_PARM_DESC(latency,"pci latency timer");
static int disable_ir;
module_param(disable_ir, int, 0444);
-MODULE_PARM_DESC(latency, "Disable IR support");
+MODULE_PARM_DESC(disable_ir, "Disable IR support");
#define info_printk(core, fmt, arg...) \
printk(KERN_INFO "%s: " fmt, core->name , ## arg)
@@ -1007,15 +1007,22 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .audio_chip = V4L2_IDENT_WM8775,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
+ /* 2: Line-In */
+ .audioroute = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
@@ -3515,19 +3522,18 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
later code configures a tea5767.
*/
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
if (has_demod)
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, NULL, "tuner",
+ &core->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (core->board.tuner_addr == ADDR_UNSET) {
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, NULL, "tuner",
+ &core->i2c_adap, "tuner",
0, has_demod ? tv_addrs + 4 : tv_addrs);
} else {
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "tuner", core->board.tuner_addr, NULL);
+ "tuner", core->board.tuner_addr, NULL);
}
}
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 367a653f4c95..90717ee944ec 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -67,6 +67,10 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+static unsigned int dvb_buf_tscnt = 32;
+module_param(dvb_buf_tscnt, int, 0644);
+MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define dprintk(level,fmt, arg...) if (debug >= level) \
@@ -80,10 +84,10 @@ static int dvb_buf_setup(struct videobuf_queue *q,
struct cx8802_dev *dev = q->priv_data;
dev->ts_packet_size = 188 * 4;
- dev->ts_packet_count = 32;
+ dev->ts_packet_count = dvb_buf_tscnt;
*size = dev->ts_packet_size * dev->ts_packet_count;
- *count = 32;
+ *count = dvb_buf_tscnt;
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index f53836bb6a5a..a1fe0abb6e43 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -146,7 +146,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
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_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index fc777bc6e716..06f7d1d00944 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -24,14 +24,12 @@
#include <linux/init.h>
#include <linux/hrtimer.h>
-#include <linux/input.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
#include "cx88.h"
-#include <media/ir-core.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#define MODULE_NAME "cx88xx"
@@ -39,9 +37,7 @@
struct cx88_IR {
struct cx88_core *core;
- struct input_dev *input;
- struct ir_dev_props props;
- u64 ir_type;
+ struct rc_dev *dev;
int users;
@@ -50,8 +46,6 @@ struct cx88_IR {
/* sample from gpio pin 16 */
u32 sampling;
- u32 samples[16];
- int scount;
/* poll external decoder */
int polling;
@@ -63,6 +57,10 @@ struct cx88_IR {
u32 mask_keyup;
};
+static unsigned ir_samplerate = 4;
+module_param(ir_samplerate, uint, 0444);
+MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");
+
static int ir_debug;
module_param(ir_debug, int, 0644); /* debug level [IR] */
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
@@ -70,6 +68,9 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define ir_dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
+#define dprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "cx88 IR: " fmt , ##arg)
+
/* ---------------------------------------------------------------------- */
static void cx88_ir_handle_key(struct cx88_IR *ir)
@@ -125,21 +126,26 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
- ir_keydown(ir->input, data, 0);
+ rc_keydown(ir->dev, data, 0);
} else if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown)
- ir_keydown(ir->input, data, 0);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ else
+ rc_keyup(ir->dev);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (0 == (gpio & ir->mask_keyup))
- ir_keydown(ir->input, data, 0);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ else
+ rc_keyup(ir->dev);
} else {
/* can't distinguish keydown/up :-/ */
- ir_keydown(ir->input, data, 0);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keyup(ir->dev);
}
}
@@ -176,8 +182,8 @@ static int __cx88_ir_start(void *priv)
}
if (ir->sampling) {
core->pci_irqmask |= PCI_INT_IR_SMPINT;
- cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
- cx_write(MO_DDSCFG_IO, 0x5); /* enable */
+ cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
+ cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
return 0;
}
@@ -214,17 +220,17 @@ void cx88_ir_stop(struct cx88_core *core)
__cx88_ir_stop(core);
}
-static int cx88_ir_open(void *priv)
+static int cx88_ir_open(struct rc_dev *rc)
{
- struct cx88_core *core = priv;
+ struct cx88_core *core = rc->priv;
core->ir->users++;
return __cx88_ir_start(core);
}
-static void cx88_ir_close(void *priv)
+static void cx88_ir_close(struct rc_dev *rc)
{
- struct cx88_core *core = priv;
+ struct cx88_core *core = rc->priv;
core->ir->users--;
if (!core->ir->users)
@@ -236,20 +242,20 @@ static void cx88_ir_close(void *priv)
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
struct cx88_IR *ir;
- struct input_dev *input_dev;
+ struct rc_dev *dev;
char *ir_codes = NULL;
- u64 ir_type = IR_TYPE_OTHER;
+ u64 rc_type = RC_TYPE_OTHER;
int err = -ENOMEM;
u32 hardware_mask = 0; /* For devices with a hardware mask, when
* used with a full-code IR table
*/
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ dev = rc_allocate_device();
+ if (!ir || !dev)
goto err_out_free;
- ir->input = input_dev;
+ ir->dev = dev;
/* detect & configure */
switch (core->boardnr) {
@@ -264,7 +270,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
ir_codes = RC_MAP_CINERGY_1400;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xeb04; /* address */
break;
case CX88_BOARD_HAUPPAUGE:
@@ -279,7 +284,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_PCHDTV_HD5500:
case CX88_BOARD_HAUPPAUGE_IRONLY:
ir_codes = RC_MAP_HAUPPAUGE_NEW;
- ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -367,18 +371,15 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_PROF_7301:
case CX88_BOARD_PROF_6200:
ir_codes = RC_MAP_TBS_NEC;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_TEVII_S460:
case CX88_BOARD_TEVII_S420:
ir_codes = RC_MAP_TEVII_NEC;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
ir_codes = RC_MAP_DNTV_LIVE_DVBT_PRO;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_NORWOOD_MICRO:
@@ -396,7 +397,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
ir_codes = RC_MAP_PINNACLE_PCTV_HD;
- ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
@@ -407,12 +407,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_TWINHAN_VP1027_DVBS:
ir_codes = RC_MAP_TWINHAN_VP1027_DVBS;
- ir_type = IR_TYPE_NEC;
+ rc_type = RC_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
}
- if (NULL == ir_codes) {
+ if (!ir_codes) {
err = -ENODEV;
goto err_out_free;
}
@@ -436,37 +436,45 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
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->ir_type = ir_type;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->input_name = ir->name;
+ dev->input_phys = ir->phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
if (pci->subsystem_vendor) {
- input_dev->id.vendor = pci->subsystem_vendor;
- input_dev->id.product = pci->subsystem_device;
+ dev->input_id.vendor = pci->subsystem_vendor;
+ dev->input_id.product = pci->subsystem_device;
} else {
- input_dev->id.vendor = pci->vendor;
- input_dev->id.product = pci->device;
+ dev->input_id.vendor = pci->vendor;
+ dev->input_id.product = pci->device;
}
- input_dev->dev.parent = &pci->dev;
- /* record handles to ourself */
+ dev->dev.parent = &pci->dev;
+ dev->map_name = ir_codes;
+ dev->driver_name = MODULE_NAME;
+ dev->priv = core;
+ dev->open = cx88_ir_open;
+ dev->close = cx88_ir_close;
+ dev->scanmask = hardware_mask;
+
+ if (ir->sampling) {
+ dev->driver_type = RC_DRIVER_IR_RAW;
+ dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+ } else {
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ dev->allowed_protos = rc_type;
+ }
+
ir->core = core;
core->ir = ir;
- ir->props.priv = core;
- ir->props.open = cx88_ir_open;
- ir->props.close = cx88_ir_close;
- ir->props.scanmask = hardware_mask;
-
/* all done */
- err = ir_input_register(ir->input, ir_codes, &ir->props, MODULE_NAME);
+ err = rc_register_device(dev);
if (err)
goto err_out_free;
return 0;
- err_out_free:
+err_out_free:
+ rc_free_device(dev);
core->ir = NULL;
kfree(ir);
return err;
@@ -481,7 +489,7 @@ int cx88_ir_fini(struct cx88_core *core)
return 0;
cx88_ir_stop(core);
- ir_input_unregister(ir->input);
+ rc_unregister_device(ir->dev);
kfree(ir);
/* done */
@@ -494,135 +502,75 @@ int cx88_ir_fini(struct cx88_core *core)
void cx88_ir_irq(struct cx88_core *core)
{
struct cx88_IR *ir = core->ir;
- u32 samples, ircode;
- int i, start, range, toggle, dev, code;
+ u32 samples;
+ unsigned todo, bits;
+ struct ir_raw_event ev;
- if (NULL == ir)
- return;
- if (!ir->sampling)
+ if (!ir || !ir->sampling)
return;
+ /*
+ * Samples are stored in a 32 bit register, oldest sample in
+ * the msb. A set bit represents space and an unset bit
+ * represents a pulse.
+ */
samples = cx_read(MO_SAMPLE_IO);
- if (0 != samples && 0xffffffff != samples) {
- /* record sample data */
- if (ir->scount < ARRAY_SIZE(ir->samples))
- ir->samples[ir->scount++] = samples;
- return;
- }
- if (!ir->scount) {
- /* nothing to sample */
- return;
- }
-
- /* have a complete sample */
- if (ir->scount < ARRAY_SIZE(ir->samples))
- ir->samples[ir->scount++] = samples;
- for (i = 0; i < ir->scount; i++)
- ir->samples[i] = ~ir->samples[i];
- if (ir_debug)
- ir_dump_samples(ir->samples, ir->scount);
- /* decode it */
- switch (core->boardnr) {
- case CX88_BOARD_TEVII_S460:
- case CX88_BOARD_TEVII_S420:
- case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
- case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
- case CX88_BOARD_OMICOM_SS4_PCI:
- case CX88_BOARD_SATTRADE_ST4200:
- case CX88_BOARD_TBS_8920:
- case CX88_BOARD_TBS_8910:
- case CX88_BOARD_PROF_7300:
- case CX88_BOARD_PROF_7301:
- case CX88_BOARD_PROF_6200:
- case CX88_BOARD_TWINHAN_VP1027_DVBS:
- ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
-
- if (ircode == 0xffffffff) { /* decoding error */
- ir_dprintk("pulse distance decoding error\n");
- break;
- }
-
- ir_dprintk("pulse distance decoded: %x\n", ircode);
+ if (samples == 0xff && ir->dev->idle)
+ return;
- if (ircode == 0) { /* key still pressed */
- ir_dprintk("pulse distance decoded repeat code\n");
- ir_repeat(ir->input);
- break;
- }
+ init_ir_raw_event(&ev);
+ for (todo = 32; todo > 0; todo -= bits) {
+ ev.pulse = samples & 0x80000000 ? false : true;
+ bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
+ ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate);
+ ir_raw_event_store_with_filter(ir->dev, &ev);
+ samples <<= bits;
+ }
+ ir_raw_event_handle(ir->dev);
+}
- if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
- ir_dprintk("pulse distance decoded wrong address\n");
- break;
- }
+static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ int flags, code;
- if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
- ir_dprintk("pulse distance decoded wrong check sum\n");
- break;
- }
+ /* poll IR chip */
+ flags = i2c_smbus_read_byte_data(ir->c, 0x10);
+ if (flags < 0) {
+ dprintk("read error\n");
+ return 0;
+ }
+ /* key pressed ? */
+ if (0 == (flags & 0x80))
+ return 0;
- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff);
- ir_keydown(ir->input, (ircode >> 16) & 0xff, 0);
- break;
- case CX88_BOARD_HAUPPAUGE:
- case CX88_BOARD_HAUPPAUGE_DVB_T1:
- case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
- case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
- case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR3000:
- case CX88_BOARD_HAUPPAUGE_HVR4000:
- case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
- case CX88_BOARD_PCHDTV_HD3000:
- case CX88_BOARD_PCHDTV_HD5500:
- case CX88_BOARD_HAUPPAUGE_IRONLY:
- ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
- ir_dprintk("biphase decoded: %x\n", ircode);
- /*
- * RC5 has an extension bit which adds a new range
- * of available codes, this is detected here. Also
- * hauppauge remotes (black/silver) always use
- * specific device ids. If we do not filter the
- * device ids then messages destined for devices
- * such as TVs (id=0) will get through to the
- * device causing mis-fired events.
- */
- /* split rc5 data block ... */
- start = (ircode & 0x2000) >> 13;
- range = (ircode & 0x1000) >> 12;
- toggle= (ircode & 0x0800) >> 11;
- dev = (ircode & 0x07c0) >> 6;
- code = (ircode & 0x003f) | ((range << 6) ^ 0x0040);
- if( start != 1)
- /* no key pressed */
- break;
- if ( dev != 0x1e && dev != 0x1f )
- /* not a hauppauge remote */
- break;
- ir_keydown(ir->input, code, toggle);
- break;
- case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
- ir_dprintk("biphase decoded: %x\n", ircode);
- if ((ircode & 0xfffff000) != 0x3000)
- break;
- /* Note: bit 0x800 being the toggle is assumed, not checked
- with real hardware */
- ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0);
- break;
+ /* read actual key code */
+ code = i2c_smbus_read_byte_data(ir->c, 0x00);
+ if (code < 0) {
+ dprintk("read error\n");
+ return 0;
}
- ir->scount = 0;
- return;
-}
+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
+ code & 0xff, flags & 0xff);
+ *ir_key = code & 0xff;
+ *ir_raw = code;
+ return 1;
+}
void cx88_i2c_init_ir(struct cx88_core *core)
{
struct i2c_board_info info;
- const unsigned short addr_list[] = {
+ const unsigned short default_addr_list[] = {
0x18, 0x6b, 0x71,
I2C_CLIENT_END
};
+ const unsigned short pvr2000_addr_list[] = {
+ 0x18, 0x1a,
+ I2C_CLIENT_END
+ };
+ const unsigned short *addr_list = default_addr_list;
const unsigned short *addrp;
/* Instantiate the IR receiver device, if present */
if (0 != core->i2c_rc)
@@ -631,6 +579,16 @@ void cx88_i2c_init_ir(struct cx88_core *core)
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ switch (core->boardnr) {
+ case CX88_BOARD_LEADTEK_PVR2000:
+ addr_list = pvr2000_addr_list;
+ core->init_data.name = "cx88 Leadtek PVR 2000 remote";
+ core->init_data.type = RC_TYPE_UNKNOWN;
+ core->init_data.get_key = get_key_pvr2000;
+ core->init_data.ir_codes = RC_MAP_EMPTY;
+ break;
+ }
+
/*
* We can't call i2c_new_probed_device() because it uses
* quick writes for probing and at least some RC receiver
@@ -646,7 +604,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
/* Hauppauge XVR */
core->init_data.name = "cx88 Hauppauge XVR remote";
core->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
- core->init_data.type = IR_TYPE_RC5;
+ core->init_data.type = RC_TYPE_RC5;
core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
info.platform_data = &core->init_data;
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index f7d71acbb078..addf9545e9bf 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -66,8 +66,14 @@ static void request_modules(struct cx8802_dev *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx8802_dev *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -819,6 +825,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
dprintk( 1, "%s\n", __func__);
+ flush_request_modules(dev);
+
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
int err;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index d2f159daa8b5..508dabbed986 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -31,7 +31,6 @@
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
@@ -41,7 +40,6 @@
#include "cx88.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/wm8775.h>
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -978,7 +976,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
const struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
- struct v4l2_control client_ctl;
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == ctl->id) {
@@ -992,27 +989,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
ctl->value = c->v.minimum;
if (ctl->value > c->v.maximum)
ctl->value = c->v.maximum;
-
- /* Pass changes onto any WM8775 */
- client_ctl.id = ctl->id;
- switch (ctl->id) {
- case V4L2_CID_AUDIO_MUTE:
- client_ctl.value = ctl->value;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- client_ctl.value = (ctl->value) ?
- (0x90 + ctl->value) << 8 : 0;
- break;
- case V4L2_CID_AUDIO_BALANCE:
- client_ctl.value = ctl->value << 9;
- break;
- default:
- client_ctl.id = 0;
- break;
- }
- if (client_ctl.id)
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
mask=c->mask;
switch (ctl->id) {
case V4L2_CID_AUDIO_BALANCE:
@@ -1180,15 +1156,6 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct cx8800_fh *fh = priv;
-
- return videobuf_cgmbuf (get_queue(fh), mbuf, 8);
-}
-#endif
-
static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
struct cx8800_fh *fh = priv;
@@ -1559,9 +1526,7 @@ static int radio_queryctrl (struct file *file, void *priv,
if (c->id < V4L2_CID_BASE ||
c->id >= V4L2_CID_LASTP1)
return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE ||
- c->id == V4L2_CID_AUDIO_VOLUME ||
- c->id == V4L2_CID_AUDIO_BALANCE) {
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == c->id)
break;
@@ -1732,9 +1697,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.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,
@@ -1896,14 +1858,13 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
if (core->board.audio_chip == V4L2_IDENT_WM8775)
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- NULL, "wm8775", 0x36 >> 1, NULL);
+ "wm8775", 0x36 >> 1, NULL);
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
- v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap,
- NULL, "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+ "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
}
switch (core->boardnr) {
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index ec5476d8b10b..d77f8ecab9d7 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -125,7 +125,6 @@ int vp3054_i2c_probe(struct cx8802_dev *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;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e8c732e7ae4f..c9981e77416a 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -398,19 +398,17 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
}
-#define call_hw(core, grpid, o, f, args...) \
+#define call_all(core, o, f, args...) \
do { \
if (!core->i2c_rc) { \
if (core->gate_ctrl) \
core->gate_ctrl(core, 1); \
- v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
+ v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
if (core->gate_ctrl) \
core->gate_ctrl(core, 0); \
} \
} while (0)
-#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
-
struct cx8800_dev;
struct cx8802_dev;
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index d8e38cc4ec40..353eadaa823e 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1276,7 +1276,7 @@ static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
vb->field = field;
- ret = videobuf_iolock(vq, vb, NULL);;
+ ret = videobuf_iolock(vq, vb, NULL);
if (ret < 0)
return ret;
@@ -1986,7 +1986,6 @@ static __init int vpfe_probe(struct platform_device *pdev)
vpfe_dev->sd[i] =
v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
i2c_adap,
- NULL,
&sdinfo->board_info,
NULL);
if (vpfe_dev->sd[i]) {
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
index 188841b476e0..ebd5c4338ebb 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/video/davinci/vpif.h
@@ -33,7 +33,7 @@ extern spinlock_t vpif_lock;
#define regr(reg) readl((reg) + vpif_base)
#define regw(value, reg) writel(value, (reg + vpif_base))
-/* Register Addresss Offsets */
+/* Register Address Offsets */
#define VPIF_PID (0x0000)
#define VPIF_CH0_CTRL (0x0004)
#define VPIF_CH1_CTRL (0x0008)
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 6ac6acd16352..193abab6b355 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2013,7 +2013,6 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i] =
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
i2c_adap,
- NULL,
&subdevdata->board_info,
NULL);
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 685f6a6ee603..412c65d54fe1 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -1553,7 +1553,7 @@ static __init int vpif_probe(struct platform_device *pdev)
for (i = 0; i < subdev_count; i++) {
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap, NULL,
+ i2c_adap,
&subdevdata[i].board_info,
NULL);
if (!vpif_obj.sd[i]) {
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
index 7918680917d0..3e5cf27ec2b2 100644
--- a/drivers/media/video/davinci/vpss.c
+++ b/drivers/media/video/davinci/vpss.c
@@ -85,7 +85,7 @@ enum vpss_platform_type {
/*
* vpss operations. Depends on platform. Not all functions are available
* on all platforms. The api, first check if a functio is available before
- * invoking it. In the probe, the function ptrs are intialized based on
+ * invoking it. In the probe, the function ptrs are initialized based on
* vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
*/
struct vpss_hw_ops {
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 66aefd6eef55..985100ea17a4 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,9 +1,9 @@
config VIDEO_EM28XX
tristate "Empia EM28xx USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT
+ depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
@@ -37,6 +37,7 @@ config VIDEO_EM28XX_DVB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ select DVB_S921 if !DVB_FE_CUSTOMISE
select VIDEOBUF_DVB
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 54859233f311..099d5df8c572 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -268,6 +268,20 @@ static struct em28xx_reg_seq dikom_dk300_digital[] = {
};
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq leadership_digital[] = {
+ {EM2874_R80_GPIO, 0x70, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq leadership_reset[] = {
+ {EM2874_R80_GPIO, 0xf0, 0xff, 10},
+ {EM2874_R80_GPIO, 0xb0, 0xff, 10},
+ {EM2874_R80_GPIO, 0xf0, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+
/*
* Board definitions
*/
@@ -1224,6 +1238,19 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE0,
} },
},
+
+ [EM2874_LEADERSHIP_ISDBT] = {
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .xclk = EM28XX_XCLK_FREQUENCY_10MHZ,
+ .name = "EM2874 Leadership ISDBT",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = leadership_reset,
+ .dvb_gpio = leadership_digital,
+ .has_dvb = 1,
+ },
+
[EM2880_BOARD_MSI_DIGIVOX_AD] = {
.name = "MSI DigiVox A/D",
.valid = EM28XX_BOARD_NOT_VALIDATED,
@@ -1469,7 +1496,7 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
- .name = "Terratec Hybrid XS (em2882)",
+ .name = "Terratec Cinnergy Hybrid T USB XS (em2882)",
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
@@ -1633,11 +1660,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = EM28XX_AMUX_VIDEO2,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = EM28XX_AMUX_VIDEO2,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2860_BOARD_TERRATEC_AV350] = {
@@ -1754,6 +1781,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2868),
.driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2875),
+ .driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0xe300),
.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
{ USB_DEVICE(0xeb1a, 0xe303),
@@ -1791,7 +1820,7 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x0ccd, 0x005e),
.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0042),
- .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
+ .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0043),
.driver_info = EM2870_BOARD_TERRATEC_XS },
{ USB_DEVICE(0x0ccd, 0x0047),
@@ -1873,6 +1902,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
+ {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT},
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2408,7 +2438,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
dev->init_data.get_key = em28xx_get_key_em_haup;
dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
- dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;;
+ dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
break;
@@ -2430,8 +2460,36 @@ void em28xx_card_setup(struct em28xx *dev)
dev->board.is_webcam = 0;
else
dev->progressive = 1;
- } else
- em28xx_set_model(dev);
+ }
+
+ if (!dev->board.is_webcam) {
+ switch (dev->model) {
+ case EM2820_BOARD_UNKNOWN:
+ case EM2800_BOARD_UNKNOWN:
+ /*
+ * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+ *
+ * This occurs because they share identical USB vendor and
+ * product IDs.
+ *
+ * What we do here is look up the EEPROM hash of the K-WORLD
+ * and if it is found then we decide that we do not have
+ * a DIGIVOX and reset the device to the K-WORLD instead.
+ *
+ * This solution is only valid if they do not share eeprom
+ * hash identities which has not been determined as yet.
+ */
+ if (em28xx_hint_board(dev) < 0)
+ em28xx_errdev("Board not discovered\n");
+ else {
+ em28xx_set_model(dev);
+ em28xx_pre_card_setup(dev);
+ }
+ break;
+ default:
+ em28xx_set_model(dev);
+ }
+ }
em28xx_info("Identified as %s (card=%d)\n",
dev->board.name, dev->model);
@@ -2554,39 +2612,39 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */
if (dev->board.has_msp34xx)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "msp3400", 0, msp3400_addrs);
+ "msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "saa7115_auto", 0, saa711x_addrs);
+ "saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvp5150", 0, tvp5150_addrs);
+ "tvp5150", 0, tvp5150_addrs);
if (dev->em28xx_sensor == EM28XX_MT9V011) {
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "mt9v011", 0, mt9v011_addrs);
+ &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs);
v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
}
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvaudio", dev->board.tvaudio_addr, NULL);
+ "tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->board.radio_addr, NULL);
+ "tuner", dev->board.radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
@@ -2594,14 +2652,14 @@ void em28xx_card_setup(struct em28xx *dev)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
}
}
@@ -2632,8 +2690,14 @@ static void request_modules(struct em28xx *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct em28xx *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/*
@@ -2749,8 +2813,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
em28xx_pre_card_setup(dev);
if (!dev->board.is_em2800) {
- /* Sets I2C speed to 100 KHz */
- retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+ /* Resets I2C speed */
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
if (retval < 0) {
em28xx_errdev("%s: em28xx_write_regs_req failed!"
" retval [%d]\n",
@@ -3060,6 +3124,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_info("disconnecting %s\n", dev->vdev->name);
+ flush_request_modules(dev);
+
/* wait until all current v4l2 io is finished then deallocate
resources */
mutex_lock(&dev->lock);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 3ac8d3025fea..c7c04bf712aa 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -37,6 +37,7 @@
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
#include "tda18271.h"
+#include "s921.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -245,6 +246,10 @@ static struct lgdt3305_config em2870_lgdt3304_dev = {
.qam_if_khz = 4000,
};
+static struct s921_config sharp_isdbt = {
+ .demod_address = 0x30 >> 1
+};
+
static struct zl10353_config em28xx_zl10353_with_xc3028 = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -481,6 +486,7 @@ static int dvb_init(struct em28xx *dev)
if (!dev->board.has_dvb) {
/* This device does not support the extension */
+ printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
return 0;
}
@@ -496,6 +502,16 @@ static int dvb_init(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
+ case EM2874_LEADERSHIP_ISDBT:
+ dvb->frontend = dvb_attach(s921_attach,
+ &sharp_isdbt, &dev->i2c_adap);
+
+ if (!dvb->frontend) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ break;
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 6759cd5570dd..ba1ba8648c81 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/usb.h>
#include <linux/slab.h>
@@ -64,7 +63,7 @@ struct em28xx_ir_poll_result {
struct em28xx_IR {
struct em28xx *dev;
- struct input_dev *input;
+ struct rc_dev *rc;
char name[32];
char phys[32];
@@ -75,10 +74,6 @@ struct em28xx_IR {
unsigned int last_readcount;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
-
- /* IR device properties */
-
- struct ir_dev_props props;
};
/**********************************************************
@@ -302,12 +297,12 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
poll_result.toggle_bit, poll_result.read_count,
poll_result.rc_address, poll_result.rc_data[0]);
if (ir->full_code)
- ir_keydown(ir->input,
+ rc_keydown(ir->rc,
poll_result.rc_address << 8 |
poll_result.rc_data[0],
poll_result.toggle_bit);
else
- ir_keydown(ir->input,
+ rc_keydown(ir->rc,
poll_result.rc_data[0],
poll_result.toggle_bit);
@@ -331,9 +326,9 @@ static void em28xx_ir_work(struct work_struct *work)
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
-static int em28xx_ir_start(void *priv)
+static int em28xx_ir_start(struct rc_dev *rc)
{
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc->priv;
INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
schedule_delayed_work(&ir->work, 0);
@@ -341,30 +336,30 @@ static int em28xx_ir_start(void *priv)
return 0;
}
-static void em28xx_ir_stop(void *priv)
+static void em28xx_ir_stop(struct rc_dev *rc)
{
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc->priv;
cancel_delayed_work_sync(&ir->work);
}
-int em28xx_ir_change_protocol(void *priv, u64 ir_type)
+int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
{
int rc = 0;
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc_dev->priv;
struct em28xx *dev = ir->dev;
u8 ir_config = EM2874_IR_RC5;
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (ir_type == IR_TYPE_RC5) {
+ if (rc_type == RC_TYPE_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
- } else if (ir_type == IR_TYPE_NEC) {
+ } else if (rc_type == RC_TYPE_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
ir->full_code = 1;
- } else if (ir_type != IR_TYPE_UNKNOWN)
+ } else if (rc_type != RC_TYPE_UNKNOWN)
rc = -EINVAL;
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
@@ -391,7 +386,7 @@ int em28xx_ir_change_protocol(void *priv, u64 ir_type)
int em28xx_ir_init(struct em28xx *dev)
{
struct em28xx_IR *ir;
- struct input_dev *input_dev;
+ struct rc_dev *rc;
int err = -ENOMEM;
if (dev->board.ir_codes == NULL) {
@@ -400,28 +395,27 @@ int em28xx_ir_init(struct em28xx *dev)
}
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ rc = rc_allocate_device();
+ if (!ir || !rc)
goto err_out_free;
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;
-
- ir->input = input_dev;
+ ir->rc = rc;
/*
* em2874 supports more protocols. For now, let's just announce
* the two protocols that were already tested
*/
- ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
- ir->props.priv = ir;
- ir->props.change_protocol = em28xx_ir_change_protocol;
- ir->props.open = em28xx_ir_start;
- ir->props.close = em28xx_ir_stop;
+ rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ rc->priv = ir;
+ rc->change_protocol = em28xx_ir_change_protocol;
+ rc->open = em28xx_ir_start;
+ rc->close = em28xx_ir_stop;
/* By default, keep protocol field untouched */
- err = em28xx_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+ err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
if (err)
goto err_out_free;
@@ -435,27 +429,27 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_USB;
- input_dev->id.version = 1;
- input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-
- input_dev->dev.parent = &dev->udev->dev;
-
-
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_USB;
+ rc->input_id.version = 1;
+ rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ rc->dev.parent = &dev->udev->dev;
+ rc->map_name = dev->board.ir_codes;
+ rc->driver_name = MODULE_NAME;
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes,
- &ir->props, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_stop;
return 0;
+
err_out_stop:
dev->ir = NULL;
err_out_free:
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -468,8 +462,8 @@ int em28xx_ir_fini(struct em28xx *dev)
if (!ir)
return 0;
- em28xx_ir_stop(ir);
- ir_input_unregister(ir->input);
+ em28xx_ir_stop(ir->rc);
+ rc_unregister_device(ir->rc);
kfree(ir);
/* done */
@@ -557,7 +551,7 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
{
if (dev->sbutton_input_dev != NULL) {
em28xx_info("Deregistering snapshot button\n");
- cancel_rearming_delayed_work(&dev->sbutton_query_work);
+ cancel_delayed_work_sync(&dev->sbutton_query_work);
input_unregister_device(dev->sbutton_input_dev);
dev->sbutton_input_dev = NULL;
}
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/video/em28xx/em28xx-vbi.c
index 7f1c4a2173b6..2b4c9cba2d67 100644
--- a/drivers/media/video/em28xx/em28xx-vbi.c
+++ b/drivers/media/video/em28xx/em28xx-vbi.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/hardirq.h>
#include <linux/init.h>
#include "em28xx.h"
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 908e3bc88303..f34d524ccb09 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1434,7 +1434,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
if (rc == 1) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+ rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
/*
* In the case of non-AC97 volume controls, we still need
@@ -1708,11 +1708,15 @@ static int vidioc_streamoff(struct file *file, void *priv,
fh, type, fh->resources, dev->resources);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
}
return 0;
@@ -1934,19 +1938,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct em28xx_fh *fh = priv;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
- else
- return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
-}
-#endif
-
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -2359,9 +2350,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
.vidioc_g_chip_ident = vidioc_g_chip_ident,
#endif
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static const struct video_device em28xx_video_template = {
@@ -2377,7 +2365,7 @@ static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 6a75e6a4fc21..6f2795a3d4b7 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -33,7 +33,7 @@
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
#include <media/ir-kbd-i2c.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
#include <media/videobuf-dvb.h>
#endif
@@ -117,6 +117,8 @@
#define EM2800_BOARD_VC211A 74
#define EM2882_BOARD_DIKOM_DK300 75
#define EM2870_BOARD_KWORLD_A340 76
+#define EM2874_LEADERSHIP_ISDBT 77
+
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a5cfc76b40b7..a982750dcef1 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1610,6 +1610,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
memset(&i, 0, sizeof(i));
strcpy(i.name, "Camera");
i.type = V4L2_INPUT_TYPE_CAMERA;
+ i.capabilities = V4L2_IN_CAP_STD;
if (copy_to_user(arg, &i, sizeof(i)))
return -EFAULT;
@@ -2530,7 +2531,7 @@ static const struct v4l2_file_operations et61x251_fops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
- .ioctl = et61x251_ioctl,
+ .unlocked_ioctl = et61x251_ioctl,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 9a075d83dd1f..e4bba88254c7 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -194,6 +194,8 @@ struct viu_dev {
/* decoder */
struct v4l2_subdev *decoder;
+
+ v4l2_std_id std;
};
struct viu_fh {
@@ -915,6 +917,8 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
if (fh->type != i)
return -EINVAL;
+ viu_start_dma(fh->dev);
+
return videobuf_streamon(&fh->vb_vidq);
}
@@ -927,20 +931,39 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
if (fh->type != i)
return -EINVAL;
+ viu_stop_dma(fh->dev);
+
return videobuf_streamoff(&fh->vb_vidq);
}
#define decoder_call(viu, o, f, args...) \
v4l2_subdev_call(viu->decoder, o, f, ##args)
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ decoder_call(fh->dev, video, querystd, std_id);
+ return 0;
+}
+
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct viu_fh *fh = priv;
+ fh->dev->std = *id;
decoder_call(fh->dev, core, s_std, *id);
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ *std_id = fh->dev->std;
+ return 0;
+}
+
/* only one input in this driver */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
@@ -1331,6 +1354,7 @@ static int viu_release(struct file *file)
viu_stop_dma(dev);
videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
kfree(fh);
@@ -1397,7 +1421,9 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = {
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_querystd = vidioc_querystd,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1486,7 +1512,7 @@ static int __devinit viu_of_probe(struct platform_device *op,
ad = i2c_get_adapter(0);
viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
- NULL, "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+ "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
viu_dev->vidq.timeout.function = viu_vid_timeout;
viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 9b121681d135..c1ae05f4661f 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -37,7 +37,7 @@ MODULE_LICENSE("GPL");
/* constant value's */
#define MAGIC_0 0x19
#define MAGIC_1 0x68
-#define DATA_IN 0xC0
+#define DATA_IN 0xc0
#define DATA_OUT 0x40
#define VIDEOSIZE_QCIF 0 /* 176x144 */
#define VIDEOSIZE_CIF 1 /* 352x288 */
@@ -660,9 +660,9 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command,
if (sd->params.qx3.button) {
/* button pressed - unlock the latch */
do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
- 3, 0xDF, 0xDF, 0);
+ 3, 0xdf, 0xdf, 0);
do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
- 3, 0xFF, 0xFF, 0);
+ 3, 0xff, 0xff, 0);
}
/* test whether microscope is cradled */
@@ -829,7 +829,7 @@ static int goto_low_power(struct gspca_dev *gspca_dev)
if (ret)
return ret;
- do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
if (ret)
return ret;
@@ -1110,12 +1110,12 @@ static int command_setlights(struct gspca_dev *gspca_dev)
p2 = (sd->params.qx3.toplight == 0) << 3;
ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,
- 0x90, 0x8F, 0x50, 0);
+ 0x90, 0x8f, 0x50, 0);
if (ret)
return ret;
return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
- p1 | p2 | 0xE0, 0);
+ p1 | p2 | 0xe0, 0);
}
static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 8fe8fb486d62..442970073e8a 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 10, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 11, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -224,12 +224,12 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
buffer, buffer_len,
int_irq, (void *)gspca_dev, interval);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- gspca_dev->int_urb = urb;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
goto error_submit;
}
+ gspca_dev->int_urb = urb;
return ret;
error_submit:
@@ -318,14 +318,9 @@ static void fill_frame(struct gspca_dev *gspca_dev,
}
pkt_scan = gspca_dev->sd_desc->pkt_scan;
for (i = 0; i < urb->number_of_packets; i++) {
+ len = urb->iso_frame_desc[i].actual_length;
/* check the packet status and length */
- len = urb->iso_frame_desc[i].actual_length;
- if (len == 0) {
- if (gspca_dev->empty_packet == 0)
- gspca_dev->empty_packet = 1;
- continue;
- }
st = urb->iso_frame_desc[i].status;
if (st) {
err("ISOC data error: [%d] len=%d, status=%d",
@@ -333,6 +328,11 @@ static void fill_frame(struct gspca_dev *gspca_dev,
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
+ if (len == 0) {
+ if (gspca_dev->empty_packet == 0)
+ gspca_dev->empty_packet = 1;
+ continue;
+ }
/* let the packet be analyzed by the subdriver */
PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
@@ -652,16 +652,12 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
: USB_ENDPOINT_XFER_ISOC;
i = gspca_dev->alt; /* previous alt setting */
if (gspca_dev->cam.reverse_alts) {
- if (gspca_dev->audio && i < gspca_dev->nbalt - 2)
- i++;
while (++i < gspca_dev->nbalt) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
break;
}
} else {
- if (gspca_dev->audio && i > 1)
- i--;
while (--i >= 0) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
@@ -676,13 +672,11 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
i, ep->desc.bEndpointAddress);
gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
- gspca_input_destroy_urb(gspca_dev);
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
err("set alt %d err %d", i, ret);
ep = NULL;
}
- gspca_input_create_urb(gspca_dev);
}
return ep;
}
@@ -759,7 +753,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
}
} else { /* bulk */
urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,
- ep->desc.bEndpointAddress),
+ ep->desc.bEndpointAddress);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->complete = bulk_irq;
}
@@ -781,7 +775,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (!gspca_dev->present) {
ret = -ENODEV;
- goto out;
+ goto unlock;
}
/* reset the streaming variables */
@@ -802,8 +796,10 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (gspca_dev->sd_desc->isoc_init) {
ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
- goto out;
+ goto unlock;
}
+
+ gspca_input_destroy_urb(gspca_dev);
ep = get_ep(gspca_dev);
if (ep == NULL) {
ret = -EIO;
@@ -873,6 +869,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
}
}
out:
+ gspca_input_create_urb(gspca_dev);
+unlock:
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1299,17 +1297,19 @@ static int vidioc_querycap(struct file *file, void *priv,
ret = -ENODEV;
goto out;
}
- strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+ strncpy((char *) cap->driver, gspca_dev->sd_desc->name,
+ sizeof cap->driver);
if (gspca_dev->dev->product != NULL) {
- strncpy(cap->card, gspca_dev->dev->product,
+ strncpy((char *) cap->card, gspca_dev->dev->product,
sizeof cap->card);
} else {
- snprintf(cap->card, sizeof cap->card,
+ snprintf((char *) cap->card, sizeof cap->card,
"USB Camera (%04x:%04x)",
le16_to_cpu(gspca_dev->dev->descriptor.idVendor),
le16_to_cpu(gspca_dev->dev->descriptor.idProduct));
}
- usb_make_path(gspca_dev->dev, cap->bus_info, sizeof(cap->bus_info));
+ usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
+ sizeof(cap->bus_info));
cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
@@ -1710,12 +1710,13 @@ static int vidioc_g_parm(struct file *filp, void *priv,
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
- gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->get_streamparm(gspca_dev,
- parm);
- else
+ if (gspca_dev->present) {
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+ ret = gspca_dev->usb_err;
+ } else {
ret = -ENODEV;
+ }
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1740,12 +1741,13 @@ static int vidioc_s_parm(struct file *filp, void *priv,
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
- gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->set_streamparm(gspca_dev,
- parm);
- else
+ if (gspca_dev->present) {
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+ ret = gspca_dev->usb_err;
+ } else {
ret = -ENODEV;
+ }
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index d4d210b56b49..97b77a26a2eb 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -62,7 +62,7 @@ struct gspca_ctrl {
/* device information - set at probe time */
struct cam {
const struct v4l2_pix_format *cam_mode; /* size nmodes */
- const struct framerates *mode_framerates; /* must have size nmode,
+ const struct framerates *mode_framerates; /* must have size nmodes,
* just like cam_mode */
struct gspca_ctrl *ctrls; /* control table - size nctrls */
/* may be NULL */
@@ -93,7 +93,7 @@ typedef int (*cam_reg_op) (struct gspca_dev *,
struct v4l2_dbg_register *);
typedef int (*cam_ident_op) (struct gspca_dev *,
struct v4l2_dbg_chip_ident *);
-typedef int (*cam_streamparm_op) (struct gspca_dev *,
+typedef void (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
typedef int (*cam_qmnu_op) (struct gspca_dev *,
struct v4l2_querymenu *);
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
index 8ded8b100576..703d48670a24 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -624,7 +624,7 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) |
- (i2c_data & 0x3F);
+ (i2c_data & 0x3f);
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
return err;
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 6cf6855aa506..e1c3b9328ace 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -75,14 +75,14 @@ struct sd {
struct gspca_ctrl ctrls[NCTRL];
- __u8 packet_nr;
+ u8 packet_nr;
char bridge;
#define BRIDGE_OV511 0
#define BRIDGE_OV511PLUS 1
#define BRIDGE_OV518 2
#define BRIDGE_OV518PLUS 3
-#define BRIDGE_OV519 4
+#define BRIDGE_OV519 4 /* = ov530 */
#define BRIDGE_OVFX2 5
#define BRIDGE_W9968CF 6
#define BRIDGE_MASK 7
@@ -94,42 +94,44 @@ struct sd {
char snapshot_needs_reset;
/* Determined by sensor type */
- __u8 sif;
+ u8 sif;
- __u8 quality;
+ u8 quality;
#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50
- __u8 stopped; /* Streaming is temporarily paused */
- __u8 first_frame;
-
- __u8 frame_rate; /* current Framerate */
- __u8 clockdiv; /* clockdiv override */
-
- char sensor; /* Type of image sensor chip (SEN_*) */
-#define SEN_UNKNOWN 0
-#define SEN_OV2610 1
-#define SEN_OV3610 2
-#define SEN_OV6620 3
-#define SEN_OV6630 4
-#define SEN_OV66308AF 5
-#define SEN_OV7610 6
-#define SEN_OV7620 7
-#define SEN_OV7620AE 8
-#define SEN_OV7640 9
-#define SEN_OV7648 10
-#define SEN_OV7670 11
-#define SEN_OV76BE 12
-#define SEN_OV8610 13
+ u8 stopped; /* Streaming is temporarily paused */
+ u8 first_frame;
+
+ u8 frame_rate; /* current Framerate */
+ u8 clockdiv; /* clockdiv override */
+
+ s8 sensor; /* Type of image sensor chip (SEN_*) */
u8 sensor_addr;
- int sensor_width;
- int sensor_height;
- int sensor_reg_cache[256];
+ u16 sensor_width;
+ u16 sensor_height;
+ s16 sensor_reg_cache[256];
u8 jpeg_hdr[JPEG_HDR_SZ];
};
+enum sensors {
+ SEN_OV2610,
+ SEN_OV3610,
+ SEN_OV6620,
+ SEN_OV6630,
+ SEN_OV66308AF,
+ SEN_OV7610,
+ SEN_OV7620,
+ SEN_OV7620AE,
+ SEN_OV7640,
+ SEN_OV7648,
+ SEN_OV7660,
+ SEN_OV7670,
+ SEN_OV76BE,
+ SEN_OV8610,
+};
/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
the ov sensors which is already present here. When we have the time we
@@ -182,7 +184,7 @@ static const struct ctrl sd_ctrls[] = {
},
.set_control = setcolors,
},
-/* The flip controls work with ov7670 only */
+/* The flip controls work for sensors ov7660 and ov7670 only */
[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
@@ -225,7 +227,7 @@ static const struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .maximum = 2, /* 0: no flicker, 1: 50Hz, 2:60Hz, 3: auto */
.step = 1,
.default_value = 0,
},
@@ -233,6 +235,53 @@ static const struct ctrl sd_ctrls[] = {
},
};
+/* table of the disabled controls */
+static const unsigned ctrl_dis[] = {
+[SEN_OV2610] = (1 << NCTRL) - 1, /* no control */
+
+[SEN_OV3610] = (1 << NCTRL) - 1, /* no control */
+
+[SEN_OV6620] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV6630] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV66308AF] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7610] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7620] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7620AE] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7640] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << AUTOBRIGHT) |
+ (1 << CONTRAST),
+
+[SEN_OV7648] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << AUTOBRIGHT) |
+ (1 << CONTRAST),
+
+[SEN_OV7660] = (1 << AUTOBRIGHT),
+
+[SEN_OV7670] = (1 << COLORS) |
+ (1 << AUTOBRIGHT),
+
+[SEN_OV76BE] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV8610] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+};
+
static const struct v4l2_pix_format ov519_vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
@@ -412,7 +461,6 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
.priv = 0},
};
-
/* Registers common to OV511 / OV518 */
#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
#define R51x_SYS_RESET 0x50
@@ -420,7 +468,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV511_RESET_OMNICE 0x08
#define R51x_SYS_INIT 0x53
#define R51x_SYS_SNAP 0x52
-#define R51x_SYS_CUST_ID 0x5F
+#define R51x_SYS_CUST_ID 0x5f
#define R51x_COMP_LUT_BEGIN 0x80
/* OV511 Camera interface register numbers */
@@ -435,13 +483,13 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define R511_CAM_OPTS 0x18
#define R511_SNAP_FRAME 0x19
-#define R511_SNAP_PXCNT 0x1A
-#define R511_SNAP_LNCNT 0x1B
-#define R511_SNAP_PXDIV 0x1C
-#define R511_SNAP_LNDIV 0x1D
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_OPTS 0x1F
+#define R511_SNAP_PXCNT 0x1a
+#define R511_SNAP_LNCNT 0x1b
+#define R511_SNAP_PXDIV 0x1c
+#define R511_SNAP_LNDIV 0x1d
+#define R511_SNAP_UV_EN 0x1e
+#define R511_SNAP_UV_EN 0x1e
+#define R511_SNAP_OPTS 0x1f
#define R511_DRAM_FLOW_CTL 0x20
#define R511_FIFO_OPTS 0x31
@@ -466,13 +514,14 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV519_R25_FORMAT 0x25
/* OV519 System Controller register numbers */
-#define OV519_SYS_RESET1 0x51
-#define OV519_SYS_EN_CLK1 0x54
+#define OV519_R51_RESET1 0x51
+#define OV519_R54_EN_CLK1 0x54
+#define OV519_R57_SNAPSHOT 0x57
#define OV519_GPIO_DATA_OUT0 0x71
#define OV519_GPIO_IO_CTRL0 0x72
-#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
+/*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */
/*
* The FX2 chip does not give us a zero length read at end of frame.
@@ -526,80 +575,81 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
#define OV7610_REG_COM_I 0x29 /* misc settings */
-/* OV7670 registers */
-#define OV7670_REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
-#define OV7670_REG_BLUE 0x01 /* blue gain */
-#define OV7670_REG_RED 0x02 /* red gain */
-#define OV7670_REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
-#define OV7670_REG_COM1 0x04 /* Control 1 */
-#define OV7670_REG_AECHH 0x07 /* AEC MS 5 bits */
-#define OV7670_REG_COM3 0x0c /* Control 3 */
-#define OV7670_REG_COM4 0x0d /* Control 4 */
-#define OV7670_REG_COM5 0x0e /* All "reserved" */
-#define OV7670_REG_COM6 0x0f /* Control 6 */
-#define OV7670_REG_AECH 0x10 /* More bits of AEC value */
-#define OV7670_REG_CLKRC 0x11 /* Clock control */
-#define OV7670_REG_COM7 0x12 /* Control 7 */
-#define OV7670_COM7_FMT_VGA 0x00
-#define OV7670_COM7_YUV 0x00 /* YUV */
-#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
-#define OV7670_COM7_FMT_MASK 0x38
-#define OV7670_COM7_RESET 0x80 /* Register reset */
-#define OV7670_REG_COM8 0x13 /* Control 8 */
-#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
-#define OV7670_COM8_AWB 0x02 /* White balance enable */
-#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
-#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
-#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
-#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
-#define OV7670_REG_COM9 0x14 /* Control 9 - gain ceiling */
-#define OV7670_REG_COM10 0x15 /* Control 10 */
-#define OV7670_REG_HSTART 0x17 /* Horiz start high bits */
-#define OV7670_REG_HSTOP 0x18 /* Horiz stop high bits */
-#define OV7670_REG_VSTART 0x19 /* Vert start high bits */
-#define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */
-#define OV7670_REG_MVFP 0x1e /* Mirror / vflip */
-#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */
-#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
-#define OV7670_REG_AEW 0x24 /* AGC upper limit */
-#define OV7670_REG_AEB 0x25 /* AGC lower limit */
-#define OV7670_REG_VPT 0x26 /* AGC/AEC fast mode op region */
-#define OV7670_REG_HREF 0x32 /* HREF pieces */
-#define OV7670_REG_TSLB 0x3a /* lots of stuff */
-#define OV7670_REG_COM11 0x3b /* Control 11 */
-#define OV7670_COM11_EXP 0x02
-#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
-#define OV7670_REG_COM12 0x3c /* Control 12 */
-#define OV7670_REG_COM13 0x3d /* Control 13 */
-#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
-#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
-#define OV7670_REG_COM14 0x3e /* Control 14 */
-#define OV7670_REG_EDGE 0x3f /* Edge enhancement factor */
-#define OV7670_REG_COM15 0x40 /* Control 15 */
-#define OV7670_COM15_R00FF 0xc0 /* 00 to FF */
-#define OV7670_REG_COM16 0x41 /* Control 16 */
-#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
-#define OV7670_REG_BRIGHT 0x55 /* Brightness */
-#define OV7670_REG_CONTRAS 0x56 /* Contrast control */
-#define OV7670_REG_GFIX 0x69 /* Fix gain control */
-#define OV7670_REG_RGB444 0x8c /* RGB 444 control */
-#define OV7670_REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
-#define OV7670_REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
-#define OV7670_REG_BD50MAX 0xa5 /* 50hz banding step limit */
-#define OV7670_REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
-#define OV7670_REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
-#define OV7670_REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
-#define OV7670_REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
-#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
-#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */
+/* OV7660 and OV7670 registers */
+#define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
+#define OV7670_R01_BLUE 0x01 /* blue gain */
+#define OV7670_R02_RED 0x02 /* red gain */
+#define OV7670_R03_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_R04_COM1 0x04 /* Control 1 */
+/*#define OV7670_R07_AECHH 0x07 * AEC MS 5 bits */
+#define OV7670_R0C_COM3 0x0c /* Control 3 */
+#define OV7670_R0D_COM4 0x0d /* Control 4 */
+#define OV7670_R0E_COM5 0x0e /* All "reserved" */
+#define OV7670_R0F_COM6 0x0f /* Control 6 */
+#define OV7670_R10_AECH 0x10 /* More bits of AEC value */
+#define OV7670_R11_CLKRC 0x11 /* Clock control */
+#define OV7670_R12_COM7 0x12 /* Control 7 */
+#define OV7670_COM7_FMT_VGA 0x00
+/*#define OV7670_COM7_YUV 0x00 * YUV */
+#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
+#define OV7670_COM7_FMT_MASK 0x38
+#define OV7670_COM7_RESET 0x80 /* Register reset */
+#define OV7670_R13_COM8 0x13 /* Control 8 */
+#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
+#define OV7670_COM8_AWB 0x02 /* White balance enable */
+#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
+#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
+#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define OV7670_R14_COM9 0x14 /* Control 9 - gain ceiling */
+#define OV7670_R15_COM10 0x15 /* Control 10 */
+#define OV7670_R17_HSTART 0x17 /* Horiz start high bits */
+#define OV7670_R18_HSTOP 0x18 /* Horiz stop high bits */
+#define OV7670_R19_VSTART 0x19 /* Vert start high bits */
+#define OV7670_R1A_VSTOP 0x1a /* Vert stop high bits */
+#define OV7670_R1E_MVFP 0x1e /* Mirror / vflip */
+#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */
+#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
+#define OV7670_R24_AEW 0x24 /* AGC upper limit */
+#define OV7670_R25_AEB 0x25 /* AGC lower limit */
+#define OV7670_R26_VPT 0x26 /* AGC/AEC fast mode op region */
+#define OV7670_R32_HREF 0x32 /* HREF pieces */
+#define OV7670_R3A_TSLB 0x3a /* lots of stuff */
+#define OV7670_R3B_COM11 0x3b /* Control 11 */
+#define OV7670_COM11_EXP 0x02
+#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
+#define OV7670_R3C_COM12 0x3c /* Control 12 */
+#define OV7670_R3D_COM13 0x3d /* Control 13 */
+#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
+#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define OV7670_R3E_COM14 0x3e /* Control 14 */
+#define OV7670_R3F_EDGE 0x3f /* Edge enhancement factor */
+#define OV7670_R40_COM15 0x40 /* Control 15 */
+/*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */
+#define OV7670_R41_COM16 0x41 /* Control 16 */
+#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
+/* end of ov7660 common registers */
+#define OV7670_R55_BRIGHT 0x55 /* Brightness */
+#define OV7670_R56_CONTRAS 0x56 /* Contrast control */
+#define OV7670_R69_GFIX 0x69 /* Fix gain control */
+/*#define OV7670_R8C_RGB444 0x8c * RGB 444 control */
+#define OV7670_R9F_HAECC1 0x9f /* Hist AEC/AGC control 1 */
+#define OV7670_RA0_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
+#define OV7670_RA5_BD50MAX 0xa5 /* 50hz banding step limit */
+#define OV7670_RA6_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
+#define OV7670_RA7_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
+#define OV7670_RA8_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
+#define OV7670_RA9_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
+#define OV7670_RAA_HAECC7 0xaa /* Hist AEC/AGC control 7 */
+#define OV7670_RAB_BD60MAX 0xab /* 60hz banding step limit */
struct ov_regvals {
- __u8 reg;
- __u8 val;
+ u8 reg;
+ u8 val;
};
struct ov_i2c_regvals {
- __u8 reg;
- __u8 val;
+ u8 reg;
+ u8 val;
};
/* Settings for OV2610 camera chip */
@@ -617,7 +667,6 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* "wait 4096 external clock ... to make sure the sensor is
* stable and ready to access registers" i.e. 160us at 24MHz
*/
-
{ 0x12, 0x80 }, /* COMH reset */
{ 0x12, 0x00 }, /* QXGA, master */
@@ -650,7 +699,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* COMI[0] "Exposure control"
* = 0 (0x00) .......0 "Manual"
*/
- { 0x13, 0xC0 },
+ { 0x13, 0xc0 },
/*
* 09 COMC "Common Control C"
@@ -706,7 +755,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* COME[0] "Auto zero circuit select"
* = 1 (0x01) .......1 "On"
*/
- { 0x0d, 0xA1 },
+ { 0x0d, 0xa1 },
/*
* 0E COMF "Common Control F"
@@ -770,7 +819,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* COMJ[0] "Reserved"
* = 0 (0x00) .......0
*/
- { 0x14, 0xC6 },
+ { 0x14, 0xc6 },
/*
* 15 COMK "Common Control K"
@@ -876,7 +925,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* FVOPT[7:0] "Range"
* = 31 (0x1F) 00011111
*/
- { 0x3c, 0x1F },
+ { 0x3c, 0x1f },
/*
* 44 Undocumented = 0 (0x00) 00000000
@@ -925,7 +974,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* 48[7:0] "It's a secret"
* = 192 (0xC0) 11000000
*/
- { 0x48, 0xC0 },
+ { 0x48, 0xc0 },
/*
* 49 Undocumented = 25 (0x19) 00011001
@@ -939,18 +988,18 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* 4B[7:0] "It's a secret"
* = 128 (0x80) 10000000
*/
- { 0x4B, 0x80 },
+ { 0x4b, 0x80 },
/*
* 4D Undocumented = 196 (0xC4) 11000100
* 4D[7:0] "It's a secret"
* = 196 (0xC4) 11000100
*/
- { 0x4D, 0xC4 },
+ { 0x4d, 0xc4 },
/*
* 35 VREF "Reference Voltage Control"
- * = 76 (0x4C) 01001100
+ * = 76 (0x4c) 01001100
* VREF[7:5] "Column high reference control"
* = 2 (0x02) 010..... "higher voltage"
* VREF[4:2] "Column low reference control"
@@ -958,21 +1007,21 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* VREF[1:0] "Reserved"
* = 0 (0x00) ......00
*/
- { 0x35, 0x4C },
+ { 0x35, 0x4c },
/*
* 3D Undocumented = 0 (0x00) 00000000
* 3D[7:0] "It's a secret"
* = 0 (0x00) 00000000
*/
- { 0x3D, 0x00 },
+ { 0x3d, 0x00 },
/*
* 3E Undocumented = 0 (0x00) 00000000
* 3E[7:0] "It's a secret"
* = 0 (0x00) 00000000
*/
- { 0x3E, 0x00 },
+ { 0x3e, 0x00 },
/*
* 3B FREFB "Internal Reference Adjustment"
@@ -1012,7 +1061,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* VBLM[3:0] "Sensor current control"
* = 10 (0x0A) ....1010
*/
- { 0x34, 0x5A },
+ { 0x34, 0x5a },
/*
* 3B FREFB "Internal Reference Adjustment"
@@ -1078,7 +1127,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* HREFST[7:0] "Horizontal window start, 8 MSBs"
* = 31 (0x1F) 00011111
*/
- { 0x17, 0x1F },
+ { 0x17, 0x1f },
/*
* 18 HREFEND "Horizontal window end"
@@ -1086,7 +1135,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* HREFEND[7:0] "Horizontal Window End, 8 MSBs"
* = 95 (0x5F) 01011111
*/
- { 0x18, 0x5F },
+ { 0x18, 0x5f },
/*
* 19 VSTRT "Vertical window start"
@@ -1126,7 +1175,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* COMA[1:0] "Vertical window start line control 2 LSBs"
* = 2 (0x02) ......10
*/
- { 0x03, 0x4A },
+ { 0x03, 0x4a },
/*
* 11 CLKRC "Clock Rate Control"
@@ -1183,7 +1232,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* HREFST[7:0] "Horizontal window start, 8 MSBs"
* = 31 (0x1F) 00011111
*/
- { 0x17, 0x1F },
+ { 0x17, 0x1f },
/*
* 18 HREFEND "Horizontal window end"
@@ -1191,7 +1240,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* HREFEND[7:0] "Horizontal Window End, 8 MSBs"
* = 95 (0x5F) 01011111
*/
- { 0x18, 0x5F },
+ { 0x18, 0x5f },
/*
* 19 VSTRT "Vertical window start"
@@ -1231,7 +1280,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* COMA[1:0] "Vertical window start line control 2 LSBs"
* = 2 (0x02) ......10
*/
- { 0x03, 0x4A },
+ { 0x03, 0x4a },
/*
* 02 RED "Red Gain Control"
@@ -1241,7 +1290,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* RED[6:0] "Value"
* = 47 (0x2F) .0101111
*/
- { 0x02, 0xAF },
+ { 0x02, 0xaf },
/*
* 2D ADDVSL "VSYNC Pulse Width"
@@ -1249,7 +1298,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* ADDVSL[7:0] "VSYNC pulse width, LSB"
* = 210 (0xD2) 11010010
*/
- { 0x2d, 0xD2 },
+ { 0x2d, 0xd2 },
/*
* 00 GAIN = 24 (0x18) 00011000
@@ -1272,7 +1321,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* BLUE[6:0] "Value"
* = 112 (0x70) .1110000
*/
- { 0x01, 0xF0 },
+ { 0x01, 0xf0 },
/*
* 10 AEC "Automatic Exposure Control"
@@ -1280,14 +1329,14 @@ static const struct ov_i2c_regvals norm_3620b[] = {
* AEC[7:0] "Automatic Exposure Control, 8 MSBs"
* = 10 (0x0A) 00001010
*/
- { 0x10, 0x0A },
-
- { 0xE1, 0x67 },
- { 0xE3, 0x03 },
- { 0xE4, 0x26 },
- { 0xE5, 0x3E },
- { 0xF8, 0x01 },
- { 0xFF, 0x01 },
+ { 0x10, 0x0a },
+
+ { 0xe1, 0x67 },
+ { 0xe3, 0x03 },
+ { 0xe4, 0x26 },
+ { 0xe5, 0x3e },
+ { 0xf8, 0x01 },
+ { 0xff, 0x01 },
};
static const struct ov_i2c_regvals norm_6x20[] = {
@@ -1296,7 +1345,7 @@ static const struct ov_i2c_regvals norm_6x20[] = {
{ 0x03, 0x60 },
{ 0x05, 0x7f }, /* For when autoadjust is off */
{ 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
+ /* The ratio of 0x0c and 0x0d controls the white point */
{ 0x0c, 0x24 },
{ 0x0d, 0x24 },
{ 0x0f, 0x15 }, /* COMS */
@@ -1464,7 +1513,7 @@ static const struct ov_i2c_regvals norm_7620[] = {
{ 0x00, 0x00 }, /* gain */
{ 0x01, 0x80 }, /* blue gain */
{ 0x02, 0x80 }, /* red gain */
- { 0x03, 0xc0 }, /* OV7670_REG_VREF */
+ { 0x03, 0xc0 }, /* OV7670_R03_VREF */
{ 0x06, 0x60 },
{ 0x07, 0x00 },
{ 0x0c, 0x24 },
@@ -1532,33 +1581,177 @@ static const struct ov_i2c_regvals norm_7640[] = {
{ 0x12, 0x14 },
};
+static const struct ov_regvals init_519_ov7660[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x20, 0x0c }, /* 0x0d does U <-> V swap */
+ { 0x21, 0x38 },
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+};
+static const struct ov_i2c_regvals norm_7660[] = {
+ {OV7670_R12_COM7, OV7670_COM7_RESET},
+ {OV7670_R11_CLKRC, 0x81},
+ {0x92, 0x00}, /* DM_LNL */
+ {0x93, 0x00}, /* DM_LNH */
+ {0x9d, 0x4c}, /* BD50ST */
+ {0x9e, 0x3f}, /* BD60ST */
+ {OV7670_R3B_COM11, 0x02},
+ {OV7670_R13_COM8, 0xf5},
+ {OV7670_R10_AECH, 0x00},
+ {OV7670_R00_GAIN, 0x00},
+ {OV7670_R01_BLUE, 0x7c},
+ {OV7670_R02_RED, 0x9d},
+ {OV7670_R12_COM7, 0x00},
+ {OV7670_R04_COM1, 00},
+ {OV7670_R18_HSTOP, 0x01},
+ {OV7670_R17_HSTART, 0x13},
+ {OV7670_R32_HREF, 0x92},
+ {OV7670_R19_VSTART, 0x02},
+ {OV7670_R1A_VSTOP, 0x7a},
+ {OV7670_R03_VREF, 0x00},
+ {OV7670_R0E_COM5, 0x04},
+ {OV7670_R0F_COM6, 0x62},
+ {OV7670_R15_COM10, 0x00},
+ {0x16, 0x02}, /* RSVD */
+ {0x1b, 0x00}, /* PSHFT */
+ {OV7670_R1E_MVFP, 0x01},
+ {0x29, 0x3c}, /* RSVD */
+ {0x33, 0x00}, /* CHLF */
+ {0x34, 0x07}, /* ARBLM */
+ {0x35, 0x84}, /* RSVD */
+ {0x36, 0x00}, /* RSVD */
+ {0x37, 0x04}, /* ADC */
+ {0x39, 0x43}, /* OFON */
+ {OV7670_R3A_TSLB, 0x00},
+ {OV7670_R3C_COM12, 0x6c},
+ {OV7670_R3D_COM13, 0x98},
+ {OV7670_R3F_EDGE, 0x23},
+ {OV7670_R40_COM15, 0xc1},
+ {OV7670_R41_COM16, 0x22},
+ {0x6b, 0x0a}, /* DBLV */
+ {0xa1, 0x08}, /* RSVD */
+ {0x69, 0x80}, /* HV */
+ {0x43, 0xf0}, /* RSVD.. */
+ {0x44, 0x10},
+ {0x45, 0x78},
+ {0x46, 0xa8},
+ {0x47, 0x60},
+ {0x48, 0x80},
+ {0x59, 0xba},
+ {0x5a, 0x9a},
+ {0x5b, 0x22},
+ {0x5c, 0xb9},
+ {0x5d, 0x9b},
+ {0x5e, 0x10},
+ {0x5f, 0xe0},
+ {0x60, 0x85},
+ {0x61, 0x60},
+ {0x9f, 0x9d}, /* RSVD */
+ {0xa0, 0xa0}, /* DSPC2 */
+ {0x4f, 0x60}, /* matrix */
+ {0x50, 0x64},
+ {0x51, 0x04},
+ {0x52, 0x18},
+ {0x53, 0x3c},
+ {0x54, 0x54},
+ {0x55, 0x40},
+ {0x56, 0x40},
+ {0x57, 0x40},
+ {0x58, 0x0d}, /* matrix sign */
+ {0x8b, 0xcc}, /* RSVD */
+ {0x8c, 0xcc},
+ {0x8d, 0xcf},
+ {0x6c, 0x40}, /* gamma curve */
+ {0x6d, 0xe0},
+ {0x6e, 0xa0},
+ {0x6f, 0x80},
+ {0x70, 0x70},
+ {0x71, 0x80},
+ {0x72, 0x60},
+ {0x73, 0x60},
+ {0x74, 0x50},
+ {0x75, 0x40},
+ {0x76, 0x38},
+ {0x77, 0x3c},
+ {0x78, 0x32},
+ {0x79, 0x1a},
+ {0x7a, 0x28},
+ {0x7b, 0x24},
+ {0x7c, 0x04}, /* gamma curve */
+ {0x7d, 0x12},
+ {0x7e, 0x26},
+ {0x7f, 0x46},
+ {0x80, 0x54},
+ {0x81, 0x64},
+ {0x82, 0x70},
+ {0x83, 0x7c},
+ {0x84, 0x86},
+ {0x85, 0x8e},
+ {0x86, 0x9c},
+ {0x87, 0xab},
+ {0x88, 0xc4},
+ {0x89, 0xd1},
+ {0x8a, 0xe5},
+ {OV7670_R14_COM9, 0x1e},
+ {OV7670_R24_AEW, 0x80},
+ {OV7670_R25_AEB, 0x72},
+ {OV7670_R26_VPT, 0xb3},
+ {0x62, 0x80}, /* LCC1 */
+ {0x63, 0x80}, /* LCC2 */
+ {0x64, 0x06}, /* LCC3 */
+ {0x65, 0x00}, /* LCC4 */
+ {0x66, 0x01}, /* LCC5 */
+ {0x94, 0x0e}, /* RSVD.. */
+ {0x95, 0x14},
+ {OV7670_R13_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | 0x10
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AWB
+ | OV7670_COM8_AEC},
+ {0xa1, 0xc8}
+};
+
/* 7670. Defaults taken from OmniVision provided data,
* as provided by Jonathan Corbet of OLPC */
static const struct ov_i2c_regvals norm_7670[] = {
- { OV7670_REG_COM7, OV7670_COM7_RESET },
- { OV7670_REG_TSLB, 0x04 }, /* OV */
- { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
- { OV7670_REG_CLKRC, 0x01 },
+ { OV7670_R12_COM7, OV7670_COM7_RESET },
+ { OV7670_R3A_TSLB, 0x04 }, /* OV */
+ { OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+ { OV7670_R11_CLKRC, 0x01 },
/*
* Set the hardware window. These values from OV don't entirely
* make sense - hstop is less than hstart. But they work...
*/
- { OV7670_REG_HSTART, 0x13 },
- { OV7670_REG_HSTOP, 0x01 },
- { OV7670_REG_HREF, 0xb6 },
- { OV7670_REG_VSTART, 0x02 },
- { OV7670_REG_VSTOP, 0x7a },
- { OV7670_REG_VREF, 0x0a },
-
- { OV7670_REG_COM3, 0x00 },
- { OV7670_REG_COM14, 0x00 },
+ { OV7670_R17_HSTART, 0x13 },
+ { OV7670_R18_HSTOP, 0x01 },
+ { OV7670_R32_HREF, 0xb6 },
+ { OV7670_R19_VSTART, 0x02 },
+ { OV7670_R1A_VSTOP, 0x7a },
+ { OV7670_R03_VREF, 0x0a },
+
+ { OV7670_R0C_COM3, 0x00 },
+ { OV7670_R3E_COM14, 0x00 },
/* Mystery scaling numbers */
{ 0x70, 0x3a },
{ 0x71, 0x35 },
{ 0x72, 0x11 },
{ 0x73, 0xf0 },
{ 0xa2, 0x02 },
-/* { OV7670_REG_COM10, 0x0 }, */
+/* { OV7670_R15_COM10, 0x0 }, */
/* Gamma curve values */
{ 0x7a, 0x20 },
@@ -1580,37 +1773,37 @@ static const struct ov_i2c_regvals norm_7670[] = {
/* AGC and AEC parameters. Note we start by disabling those features,
then turn them only after tweaking the values. */
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT },
- { OV7670_REG_GAIN, 0x00 },
- { OV7670_REG_AECH, 0x00 },
- { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
- { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
- { OV7670_REG_BD50MAX, 0x05 },
- { OV7670_REG_BD60MAX, 0x07 },
- { OV7670_REG_AEW, 0x95 },
- { OV7670_REG_AEB, 0x33 },
- { OV7670_REG_VPT, 0xe3 },
- { OV7670_REG_HAECC1, 0x78 },
- { OV7670_REG_HAECC2, 0x68 },
+ { OV7670_R00_GAIN, 0x00 },
+ { OV7670_R10_AECH, 0x00 },
+ { OV7670_R0D_COM4, 0x40 }, /* magic reserved bit */
+ { OV7670_R14_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { OV7670_RA5_BD50MAX, 0x05 },
+ { OV7670_RAB_BD60MAX, 0x07 },
+ { OV7670_R24_AEW, 0x95 },
+ { OV7670_R25_AEB, 0x33 },
+ { OV7670_R26_VPT, 0xe3 },
+ { OV7670_R9F_HAECC1, 0x78 },
+ { OV7670_RA0_HAECC2, 0x68 },
{ 0xa1, 0x03 }, /* magic */
- { OV7670_REG_HAECC3, 0xd8 },
- { OV7670_REG_HAECC4, 0xd8 },
- { OV7670_REG_HAECC5, 0xf0 },
- { OV7670_REG_HAECC6, 0x90 },
- { OV7670_REG_HAECC7, 0x94 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_RA6_HAECC3, 0xd8 },
+ { OV7670_RA7_HAECC4, 0xd8 },
+ { OV7670_RA8_HAECC5, 0xf0 },
+ { OV7670_RA9_HAECC6, 0x90 },
+ { OV7670_RAA_HAECC7, 0x94 },
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT
| OV7670_COM8_AGC
| OV7670_COM8_AEC },
/* Almost all of these are magic "reserved" values. */
- { OV7670_REG_COM5, 0x61 },
- { OV7670_REG_COM6, 0x4b },
+ { OV7670_R0E_COM5, 0x61 },
+ { OV7670_R0F_COM6, 0x4b },
{ 0x16, 0x02 },
- { OV7670_REG_MVFP, 0x07 },
+ { OV7670_R1E_MVFP, 0x07 },
{ 0x21, 0x02 },
{ 0x22, 0x91 },
{ 0x29, 0x07 },
@@ -1619,10 +1812,10 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x37, 0x1d },
{ 0x38, 0x71 },
{ 0x39, 0x2a },
- { OV7670_REG_COM12, 0x78 },
+ { OV7670_R3C_COM12, 0x78 },
{ 0x4d, 0x40 },
{ 0x4e, 0x20 },
- { OV7670_REG_GFIX, 0x00 },
+ { OV7670_R69_GFIX, 0x00 },
{ 0x6b, 0x4a },
{ 0x74, 0x10 },
{ 0x8d, 0x4f },
@@ -1657,9 +1850,9 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x6f, 0x9f },
/* "9e for advance AWB" */
{ 0x6a, 0x40 },
- { OV7670_REG_BLUE, 0x40 },
- { OV7670_REG_RED, 0x60 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_R01_BLUE, 0x40 },
+ { OV7670_R02_RED, 0x60 },
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT
| OV7670_COM8_AGC
@@ -1675,22 +1868,22 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x54, 0x80 },
{ 0x58, 0x9e },
- { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
- { OV7670_REG_EDGE, 0x00 },
+ { OV7670_R41_COM16, OV7670_COM16_AWBGAIN },
+ { OV7670_R3F_EDGE, 0x00 },
{ 0x75, 0x05 },
{ 0x76, 0xe1 },
{ 0x4c, 0x00 },
{ 0x77, 0x01 },
- { OV7670_REG_COM13, OV7670_COM13_GAMMA
+ { OV7670_R3D_COM13, OV7670_COM13_GAMMA
| OV7670_COM13_UVSAT
| 2}, /* was 3 */
{ 0x4b, 0x09 },
{ 0xc9, 0x60 },
- { OV7670_REG_COM16, 0x38 },
+ { OV7670_R41_COM16, 0x38 },
{ 0x56, 0x40 },
{ 0x34, 0x11 },
- { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+ { OV7670_R3B_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
{ 0xa4, 0x88 },
{ 0x96, 0x00 },
{ 0x97, 0x30 },
@@ -1825,10 +2018,13 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
}
/* Write a OV519 register */
-static int reg_w(struct sd *sd, __u16 index, __u16 value)
+static void reg_w(struct sd *sd, u16 index, u16 value)
{
int ret, req = 0;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
@@ -1838,6 +2034,8 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
req = 0x0a;
/* fall through */
case BRIDGE_W9968CF:
+ PDEBUG(D_USBO, "SET %02x %04x %04x",
+ req, value, index);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
req,
@@ -1848,6 +2046,8 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
req = 1;
}
+ PDEBUG(D_USBO, "SET %02x 0000 %04x %02x",
+ req, index, value);
sd->gspca_dev.usb_buf[0] = value;
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
@@ -1857,22 +2057,22 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
sd->gspca_dev.usb_buf, 1, 500);
leave:
if (ret < 0) {
- err("Write reg 0x%04x -> [0x%02x] failed",
- value, index);
- return ret;
+ err("reg_w %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ return;
}
-
- PDEBUG(D_USBO, "Write reg 0x%04x -> [0x%02x]", value, index);
- return 0;
}
/* Read from a OV519 register, note not valid for the w9968cf!! */
/* returns: negative is error, pos or zero is data */
-static int reg_r(struct sd *sd, __u16 index)
+static int reg_r(struct sd *sd, u16 index)
{
int ret;
int req;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
@@ -1893,29 +2093,37 @@ static int reg_r(struct sd *sd, __u16 index)
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- PDEBUG(D_USBI, "Read reg [0x%02X] -> 0x%04X", index, ret);
- } else
- err("Read reg [0x%02x] failed", index);
+ PDEBUG(D_USBI, "GET %02x 0000 %04x %02x",
+ req, index, ret);
+ } else {
+ err("reg_r %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
/* Read 8 values from a OV519 register */
static int reg_r8(struct sd *sd,
- __u16 index)
+ u16 index)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
1, /* REQ_IO */
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, sd->gspca_dev.usb_buf, 8, 500);
- if (ret >= 0)
+ if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- else
- err("Read reg 8 [0x%02x] failed", index);
+ } else {
+ err("reg_r8 %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
@@ -1926,34 +2134,37 @@ static int reg_r8(struct sd *sd,
* that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int reg_w_mask(struct sd *sd,
- __u16 index,
- __u8 value,
- __u8 mask)
+static void reg_w_mask(struct sd *sd,
+ u16 index,
+ u8 value,
+ u8 mask)
{
int ret;
- __u8 oldval;
+ u8 oldval;
if (mask != 0xff) {
value &= mask; /* Enforce mask on value */
ret = reg_r(sd, index);
if (ret < 0)
- return ret;
+ return;
oldval = ret & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
}
- return reg_w(sd, index, value);
+ reg_w(sd, index, value);
}
/*
* Writes multiple (n) byte value to a single register. Only valid with certain
* registers (0x30 and 0xc4 - 0xce).
*/
-static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
+static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
*((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -1963,69 +2174,55 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
0, index,
sd->gspca_dev.usb_buf, n, 500);
if (ret < 0) {
- err("Write reg32 [%02x] %08x failed", index, value);
- return ret;
+ err("reg_w32 %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
-static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
{
int rc, retries;
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+ PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value);
/* Three byte write cycle */
for (retries = 6; ; ) {
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_3, reg);
/* Write "value" to I2C data port of OV511 */
- rc = reg_w(sd, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_DATA, value);
/* Initiate 3-byte write cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x01);
do {
rc = reg_r(sd, R511_I2C_CTL);
} while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
if (rc < 0)
- return rc;
+ return;
if ((rc & 2) == 0) /* Ack? */
break;
if (--retries < 0) {
PDEBUG(D_USBO, "i2c write retries exhausted");
- return -1;
+ return;
}
}
-
- return 0;
}
-static int ov511_i2c_r(struct sd *sd, __u8 reg)
+static int ov511_i2c_r(struct sd *sd, u8 reg)
{
int rc, value, retries;
/* Two byte write cycle */
for (retries = 6; ; ) {
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_2, reg);
/* Initiate 2-byte write cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x03);
do {
rc = reg_r(sd, R511_I2C_CTL);
@@ -2049,9 +2246,7 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
/* Two byte read cycle */
for (retries = 6; ; ) {
/* Initiate 2-byte read cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x05);
do {
rc = reg_r(sd, R511_I2C_CTL);
@@ -2064,9 +2259,7 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
break;
/* I2C abort */
- rc = reg_w(sd, R511_I2C_CTL, 0x10);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x10);
if (--retries < 0) {
PDEBUG(D_USBI, "i2c read retries exhausted");
@@ -2076,12 +2269,10 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
value = reg_r(sd, R51x_I2C_DATA);
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ PDEBUG(D_USBI, "ov511_i2c_r %02x %02x", reg, value);
/* This is needed to make i2c_w() work */
- rc = reg_w(sd, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x05);
return value;
}
@@ -2091,32 +2282,24 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
* This is normally only called from i2c_w(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int ov518_i2c_w(struct sd *sd,
- __u8 reg,
- __u8 value)
+static void ov518_i2c_w(struct sd *sd,
+ u8 reg,
+ u8 value)
{
- int rc;
-
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+ PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value);
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_3, reg);
/* Write "value" to I2C data port of OV511 */
- rc = reg_w(sd, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_DATA, value);
/* Initiate 3-byte write cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x01);
/* wait for write complete */
msleep(4);
- return reg_r8(sd, R518_I2C_CTL);
+ reg_r8(sd, R518_I2C_CTL);
}
/*
@@ -2126,105 +2309,102 @@ static int ov518_i2c_w(struct sd *sd,
* This is normally only called from i2c_r(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int ov518_i2c_r(struct sd *sd, __u8 reg)
+static int ov518_i2c_r(struct sd *sd, u8 reg)
{
- int rc, value;
+ int value;
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_2, reg);
/* Initiate 2-byte write cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x03);
/* Initiate 2-byte read cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x05);
value = reg_r(sd, R51x_I2C_DATA);
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value);
return value;
}
-static int ovfx2_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
0x02,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (__u16)value, (__u16)reg, NULL, 0, 500);
+ (u16) value, (u16) reg, NULL, 0, 500);
if (ret < 0) {
- err("i2c 0x%02x -> [0x%02x] failed", value, reg);
- return ret;
+ err("ovfx2_i2c_w %02x failed %d", reg, ret);
+ sd->gspca_dev.usb_err = ret;
}
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
- return 0;
+ PDEBUG(D_USBO, "ovfx2_i2c_w %02x %02x", reg, value);
}
-static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
+static int ovfx2_i2c_r(struct sd *sd, u8 reg)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
0x03,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, sd->gspca_dev.usb_buf, 1, 500);
+ 0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500);
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, ret);
- } else
- err("i2c read [0x%02x] failed", reg);
+ PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret);
+ } else {
+ err("ovfx2_i2c_r %02x failed %d", reg, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
-static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void i2c_w(struct sd *sd, u8 reg, u8 value)
{
- int ret = -1;
-
if (sd->sensor_reg_cache[reg] == value)
- return 0;
+ return;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_i2c_w(sd, reg, value);
+ ov511_i2c_w(sd, reg, value);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
case BRIDGE_OV519:
- ret = ov518_i2c_w(sd, reg, value);
+ ov518_i2c_w(sd, reg, value);
break;
case BRIDGE_OVFX2:
- ret = ovfx2_i2c_w(sd, reg, value);
+ ovfx2_i2c_w(sd, reg, value);
break;
case BRIDGE_W9968CF:
- ret = w9968cf_i2c_w(sd, reg, value);
+ w9968cf_i2c_w(sd, reg, value);
break;
}
- if (ret >= 0) {
+ if (sd->gspca_dev.usb_err >= 0) {
/* Up on sensor reset empty the register cache */
if (reg == 0x12 && (value & 0x80))
memset(sd->sensor_reg_cache, -1,
- sizeof(sd->sensor_reg_cache));
+ sizeof(sd->sensor_reg_cache));
else
sd->sensor_reg_cache[reg] = value;
}
-
- return ret;
}
-static int i2c_r(struct sd *sd, __u8 reg)
+static int i2c_r(struct sd *sd, u8 reg)
{
int ret = -1;
@@ -2260,95 +2440,99 @@ static int i2c_r(struct sd *sd, __u8 reg)
* that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int i2c_w_mask(struct sd *sd,
- __u8 reg,
- __u8 value,
- __u8 mask)
+static void i2c_w_mask(struct sd *sd,
+ u8 reg,
+ u8 value,
+ u8 mask)
{
int rc;
- __u8 oldval;
+ u8 oldval;
value &= mask; /* Enforce mask on value */
rc = i2c_r(sd, reg);
if (rc < 0)
- return rc;
+ return;
oldval = rc & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
- return i2c_w(sd, reg, value);
+ i2c_w(sd, reg, value);
}
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */
-static inline int ov51x_stop(struct sd *sd)
+static inline void ov51x_stop(struct sd *sd)
{
PDEBUG(D_STREAM, "stopping");
sd->stopped = 1;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return reg_w(sd, R51x_SYS_RESET, 0x3d);
+ reg_w(sd, R51x_SYS_RESET, 0x3d);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+ reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+ break;
case BRIDGE_OV519:
- return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x00);
+ reg_w(sd, 0x22, 0x00); /* FRAR */
+ break;
case BRIDGE_OVFX2:
- return reg_w_mask(sd, 0x0f, 0x00, 0x02);
+ reg_w_mask(sd, 0x0f, 0x00, 0x02);
+ break;
case BRIDGE_W9968CF:
- return reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
+ reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
+ break;
}
-
- return 0;
}
/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
* actually stopped (for performance). */
-static inline int ov51x_restart(struct sd *sd)
+static inline void ov51x_restart(struct sd *sd)
{
- int rc;
-
PDEBUG(D_STREAM, "restarting");
if (!sd->stopped)
- return 0;
+ return;
sd->stopped = 0;
/* Reinitialize the stream */
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return reg_w(sd, R51x_SYS_RESET, 0x00);
+ reg_w(sd, R51x_SYS_RESET, 0x00);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- rc = reg_w(sd, 0x2f, 0x80);
- if (rc < 0)
- return rc;
- return reg_w(sd, R51x_SYS_RESET, 0x00);
+ reg_w(sd, 0x2f, 0x80);
+ reg_w(sd, R51x_SYS_RESET, 0x00);
+ break;
case BRIDGE_OV519:
- return reg_w(sd, OV519_SYS_RESET1, 0x00);
+ reg_w(sd, OV519_R51_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x00);
+ reg_w(sd, 0x22, 0x1d); /* FRAR */
+ break;
case BRIDGE_OVFX2:
- return reg_w_mask(sd, 0x0f, 0x02, 0x02);
+ reg_w_mask(sd, 0x0f, 0x02, 0x02);
+ break;
case BRIDGE_W9968CF:
- return reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
+ reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
+ break;
}
-
- return 0;
}
-static int ov51x_set_slave_ids(struct sd *sd, __u8 slave);
+static void ov51x_set_slave_ids(struct sd *sd, u8 slave);
/* This does an initial reset of an OmniVision sensor and ensures that I2C
* is synchronized. Returns <0 on failure.
*/
-static int init_ov_sensor(struct sd *sd, __u8 slave)
+static int init_ov_sensor(struct sd *sd, u8 slave)
{
int i;
- if (ov51x_set_slave_ids(sd, slave) < 0)
- return -EIO;
+ ov51x_set_slave_ids(sd, slave);
/* Reset the sensor */
- if (i2c_w(sd, 0x12, 0x80) < 0)
- return -EIO;
+ i2c_w(sd, 0x12, 0x80);
/* Wait for it to initialize */
msleep(150);
@@ -2361,15 +2545,16 @@ static int init_ov_sensor(struct sd *sd, __u8 slave)
}
/* Reset the sensor */
- if (i2c_w(sd, 0x12, 0x80) < 0)
- return -EIO;
+ i2c_w(sd, 0x12, 0x80);
+
/* Wait for it to initialize */
msleep(150);
+
/* Dummy read to sync I2C */
if (i2c_r(sd, 0x00) < 0)
- return -EIO;
+ return -1;
}
- return -EIO;
+ return -1;
}
/* Set the read and write slave IDs. The "slave" argument is the write slave,
@@ -2377,53 +2562,40 @@ static int init_ov_sensor(struct sd *sd, __u8 slave)
* This should not be called from outside the i2c I/O functions.
* Sets I2C read and write slave IDs. Returns <0 for error
*/
-static int ov51x_set_slave_ids(struct sd *sd,
- __u8 slave)
+static void ov51x_set_slave_ids(struct sd *sd,
+ u8 slave)
{
- int rc;
-
switch (sd->bridge) {
case BRIDGE_OVFX2:
- return reg_w(sd, OVFX2_I2C_ADDR, slave);
+ reg_w(sd, OVFX2_I2C_ADDR, slave);
+ return;
case BRIDGE_W9968CF:
sd->sensor_addr = slave;
- return 0;
+ return;
}
- rc = reg_w(sd, R51x_I2C_W_SID, slave);
- if (rc < 0)
- return rc;
- return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+ reg_w(sd, R51x_I2C_W_SID, slave);
+ reg_w(sd, R51x_I2C_R_SID, slave + 1);
}
-static int write_regvals(struct sd *sd,
+static void write_regvals(struct sd *sd,
const struct ov_regvals *regvals,
int n)
{
- int rc;
-
while (--n >= 0) {
- rc = reg_w(sd, regvals->reg, regvals->val);
- if (rc < 0)
- return rc;
+ reg_w(sd, regvals->reg, regvals->val);
regvals++;
}
- return 0;
}
-static int write_i2c_regvals(struct sd *sd,
- const struct ov_i2c_regvals *regvals,
- int n)
+static void write_i2c_regvals(struct sd *sd,
+ const struct ov_i2c_regvals *regvals,
+ int n)
{
- int rc;
-
while (--n >= 0) {
- rc = i2c_w(sd, regvals->reg, regvals->val);
- if (rc < 0)
- return rc;
+ i2c_w(sd, regvals->reg, regvals->val);
regvals++;
}
- return 0;
}
/****************************************************************************
@@ -2433,13 +2605,13 @@ static int write_i2c_regvals(struct sd *sd,
***************************************************************************/
/* This initializes the OV2x10 / OV3610 / OV3620 */
-static int ov_hires_configure(struct sd *sd)
+static void ov_hires_configure(struct sd *sd)
{
int high, low;
if (sd->bridge != BRIDGE_OVFX2) {
err("error hires sensors only supported with ovfx2");
- return -1;
+ return;
}
PDEBUG(D_PROBE, "starting ov hires configuration");
@@ -2455,20 +2627,15 @@ static int ov_hires_configure(struct sd *sd)
PDEBUG(D_PROBE, "Sensor is an OV3610");
sd->sensor = SEN_OV3610;
} else {
- err("Error unknown sensor type: 0x%02x%02x",
- high, low);
- return -1;
+ err("Error unknown sensor type: %02x%02x",
+ high, low);
}
-
- /* Set sensor-specific vars */
- return 0;
}
-
/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
* the same register settings as the OV8610, since they are very similar.
*/
-static int ov8xx0_configure(struct sd *sd)
+static void ov8xx0_configure(struct sd *sd)
{
int rc;
@@ -2478,27 +2645,21 @@ static int ov8xx0_configure(struct sd *sd)
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
- if ((rc & 3) == 1) {
+ if ((rc & 3) == 1)
sd->sensor = SEN_OV8610;
- } else {
+ else
err("Unknown image sensor version: %d", rc & 3);
- return -1;
- }
-
- /* Set sensor-specific vars */
- return 0;
}
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
* the same register settings as the OV7610, since they are very similar.
*/
-static int ov7xx0_configure(struct sd *sd)
+static void ov7xx0_configure(struct sd *sd)
{
int rc, high, low;
-
PDEBUG(D_PROBE, "starting OV7xx0 configuration");
/* Detect sensor (sub)type */
@@ -2508,15 +2669,15 @@ static int ov7xx0_configure(struct sd *sd)
* it appears to be wrongly detected as a 7610 by default */
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
if ((rc & 3) == 3) {
/* quick hack to make OV7670s work */
high = i2c_r(sd, 0x0a);
low = i2c_r(sd, 0x0b);
/* info("%x, %x", high, low); */
- if (high == 0x76 && low == 0x73) {
- PDEBUG(D_PROBE, "Sensor is an OV7670");
+ if (high == 0x76 && (low & 0xf0) == 0x70) {
+ PDEBUG(D_PROBE, "Sensor is an OV76%02x", low);
sd->sensor = SEN_OV7670;
} else {
PDEBUG(D_PROBE, "Sensor is an OV7610");
@@ -2536,19 +2697,19 @@ static int ov7xx0_configure(struct sd *sd)
high = i2c_r(sd, 0x0a);
if (high < 0) {
PDEBUG(D_ERR, "Error detecting camera chip PID");
- return high;
+ return;
}
low = i2c_r(sd, 0x0b);
if (low < 0) {
PDEBUG(D_ERR, "Error detecting camera chip VER");
- return low;
+ return;
}
if (high == 0x76) {
switch (low) {
case 0x30:
err("Sensor is an OV7630/OV7635");
err("7630 is not supported by this driver");
- return -1;
+ return;
case 0x40:
PDEBUG(D_PROBE, "Sensor is an OV7645");
sd->sensor = SEN_OV7640; /* FIXME */
@@ -2561,9 +2722,14 @@ static int ov7xx0_configure(struct sd *sd)
PDEBUG(D_PROBE, "Sensor is an OV7648");
sd->sensor = SEN_OV7648;
break;
+ case 0x60:
+ PDEBUG(D_PROBE, "Sensor is a OV7660");
+ sd->sensor = SEN_OV7660;
+ sd->invert_led = 0;
+ break;
default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
- return -1;
+ return;
}
} else {
PDEBUG(D_PROBE, "Sensor is an OV7620");
@@ -2571,15 +2737,11 @@ static int ov7xx0_configure(struct sd *sd)
}
} else {
err("Unknown image sensor version: %d", rc & 3);
- return -1;
}
-
- /* Set sensor-specific vars */
- return 0;
}
/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int ov6xx0_configure(struct sd *sd)
+static void ov6xx0_configure(struct sd *sd)
{
int rc;
PDEBUG(D_PROBE, "starting OV6xx0 configuration");
@@ -2588,7 +2750,7 @@ static int ov6xx0_configure(struct sd *sd)
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
/* Ugh. The first two bits are the version bits, but
@@ -2619,13 +2781,11 @@ static int ov6xx0_configure(struct sd *sd)
break;
default:
err("FATAL: Unknown sensor version: 0x%02x", rc);
- return -1;
+ return;
}
/* Set sensor-specific vars */
sd->sif = 1;
-
- return 0;
}
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
@@ -2637,14 +2797,14 @@ static void ov51x_led_control(struct sd *sd, int on)
switch (sd->bridge) {
/* OV511 has no LED control */
case BRIDGE_OV511PLUS:
- reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+ reg_w(sd, R511_SYS_LED_CTL, on);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+ reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02);
break;
case BRIDGE_OV519:
- reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1);
break;
}
}
@@ -2679,7 +2839,7 @@ static void sd_reset_snapshot(struct gspca_dev *gspca_dev)
}
}
-static int ov51x_upload_quan_tables(struct sd *sd)
+static void ov51x_upload_quan_tables(struct sd *sd)
{
const unsigned char yQuanTable511[] = {
0, 1, 1, 2, 2, 3, 3, 4,
@@ -2710,7 +2870,6 @@ static int ov51x_upload_quan_tables(struct sd *sd)
6, 6, 6, 6, 7, 7, 7, 8,
7, 7, 6, 7, 7, 7, 8, 8
};
-
const unsigned char uvQuanTable518[] = {
6, 6, 6, 7, 7, 7, 7, 7,
6, 6, 6, 7, 7, 7, 7, 7,
@@ -2720,18 +2879,18 @@ static int ov51x_upload_quan_tables(struct sd *sd)
const unsigned char *pYTable, *pUVTable;
unsigned char val0, val1;
- int i, size, rc, reg = R51x_COMP_LUT_BEGIN;
+ int i, size, reg = R51x_COMP_LUT_BEGIN;
PDEBUG(D_PROBE, "Uploading quantization tables");
if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) {
pYTable = yQuanTable511;
pUVTable = uvQuanTable511;
- size = 32;
+ size = 32;
} else {
pYTable = yQuanTable518;
pUVTable = uvQuanTable518;
- size = 16;
+ size = 16;
}
for (i = 0; i < size; i++) {
@@ -2740,30 +2899,23 @@ static int ov51x_upload_quan_tables(struct sd *sd)
val0 &= 0x0f;
val1 &= 0x0f;
val0 |= val1 << 4;
- rc = reg_w(sd, reg, val0);
- if (rc < 0)
- return rc;
+ reg_w(sd, reg, val0);
val0 = *pUVTable++;
val1 = *pUVTable++;
val0 &= 0x0f;
val1 &= 0x0f;
val0 |= val1 << 4;
- rc = reg_w(sd, reg + size, val0);
- if (rc < 0)
- return rc;
+ reg_w(sd, reg + size, val0);
reg++;
}
-
- return 0;
}
/* This initializes the OV511/OV511+ and the sensor */
-static int ov511_configure(struct gspca_dev *gspca_dev)
+static void ov511_configure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int rc;
/* For 511 and 511+ */
const struct ov_regvals init_511[] = {
@@ -2809,42 +2961,27 @@ static int ov511_configure(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID));
- rc = write_regvals(sd, init_511, ARRAY_SIZE(init_511));
- if (rc < 0)
- return rc;
+ write_regvals(sd, init_511, ARRAY_SIZE(init_511));
switch (sd->bridge) {
case BRIDGE_OV511:
- rc = write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
break;
case BRIDGE_OV511PLUS:
- rc = write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
break;
}
/* Init compression */
- rc = write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
- if (rc < 0)
- return rc;
-
- rc = ov51x_upload_quan_tables(sd);
- if (rc < 0) {
- PDEBUG(D_ERR, "Error uploading quantization tables");
- return rc;
- }
+ write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
- return 0;
+ ov51x_upload_quan_tables(sd);
}
/* This initializes the OV518/OV518+ and the sensor */
-static int ov518_configure(struct gspca_dev *gspca_dev)
+static void ov518_configure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int rc;
/* For 518 and 518+ */
const struct ov_regvals init_518[] = {
@@ -2892,65 +3029,49 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
/* First 5 bits of custom ID reg are a revision ID on OV518 */
PDEBUG(D_PROBE, "Device revision %d",
- 0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+ 0x1f & reg_r(sd, R51x_SYS_CUST_ID));
- rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
- if (rc < 0)
- return rc;
+ write_regvals(sd, init_518, ARRAY_SIZE(init_518));
/* Set LED GPIO pin to output mode */
- rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
- if (rc < 0)
- return rc;
+ reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
switch (sd->bridge) {
case BRIDGE_OV518:
- rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
break;
case BRIDGE_OV518PLUS:
- rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
break;
}
- rc = ov51x_upload_quan_tables(sd);
- if (rc < 0) {
- PDEBUG(D_ERR, "Error uploading quantization tables");
- return rc;
- }
+ ov51x_upload_quan_tables(sd);
- rc = reg_w(sd, 0x2f, 0x80);
- if (rc < 0)
- return rc;
-
- return 0;
+ reg_w(sd, 0x2f, 0x80);
}
-static int ov519_configure(struct sd *sd)
+static void ov519_configure(struct sd *sd)
{
static const struct ov_regvals init_519[] = {
- { 0x5a, 0x6d }, /* EnableSystem */
- { 0x53, 0x9b },
- { 0x54, 0xff }, /* set bit2 to enable jpeg */
- { 0x5d, 0x03 },
- { 0x49, 0x01 },
- { 0x48, 0x00 },
+ { 0x5a, 0x6d }, /* EnableSystem */
+ { 0x53, 0x9b },
+ { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */
+ { 0x5d, 0x03 },
+ { 0x49, 0x01 },
+ { 0x48, 0x00 },
/* Set LED pin to output mode. Bit 4 must be cleared or sensor
* detection will fail. This deserves further investigation. */
{ OV519_GPIO_IO_CTRL0, 0xee },
- { 0x51, 0x0f }, /* SetUsbInit */
- { 0x51, 0x00 },
- { 0x22, 0x00 },
+ { OV519_R51_RESET1, 0x0f },
+ { OV519_R51_RESET1, 0x00 },
+ { 0x22, 0x00 },
/* windows reads 0x55 at this point*/
};
- return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+ write_regvals(sd, init_519, ARRAY_SIZE(init_519));
}
-static int ovfx2_configure(struct sd *sd)
+static void ovfx2_configure(struct sd *sd)
{
static const struct ov_regvals init_fx2[] = {
{ 0x00, 0x60 },
@@ -2964,7 +3085,92 @@ static int ovfx2_configure(struct sd *sd)
sd->stopped = 1;
- return write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+ write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+}
+
+/* set the mode */
+/* This function works for ov7660 only */
+static void ov519_set_mode(struct sd *sd)
+{
+ static const struct ov_regvals bridge_ov7660[2][10] = {
+ {{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
+ {0x25, 0x01}, {0x26, 0x00}},
+ {{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
+ {0x25, 0x03}, {0x26, 0x00}}
+ };
+ static const struct ov_i2c_regvals sensor_ov7660[2][3] = {
+ {{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}},
+ {{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}}
+ };
+ static const struct ov_i2c_regvals sensor_ov7660_2[] = {
+ {OV7670_R17_HSTART, 0x13},
+ {OV7670_R18_HSTOP, 0x01},
+ {OV7670_R32_HREF, 0x92},
+ {OV7670_R19_VSTART, 0x02},
+ {OV7670_R1A_VSTOP, 0x7a},
+ {OV7670_R03_VREF, 0x00},
+/* {0x33, 0x00}, */
+/* {0x34, 0x07}, */
+/* {0x36, 0x00}, */
+/* {0x6b, 0x0a}, */
+ };
+
+ write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode],
+ ARRAY_SIZE(bridge_ov7660[0]));
+ write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode],
+ ARRAY_SIZE(sensor_ov7660[0]));
+ write_i2c_regvals(sd, sensor_ov7660_2,
+ ARRAY_SIZE(sensor_ov7660_2));
+}
+
+/* set the frame rate */
+/* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */
+static void ov519_set_fr(struct sd *sd)
+{
+ int fr;
+ u8 clock;
+ /* frame rate table with indices:
+ * - mode = 0: 320x240, 1: 640x480
+ * - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5
+ * - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock)
+ */
+ static const u8 fr_tb[2][6][3] = {
+ {{0x04, 0xff, 0x00},
+ {0x04, 0x1f, 0x00},
+ {0x04, 0x1b, 0x00},
+ {0x04, 0x15, 0x00},
+ {0x04, 0x09, 0x00},
+ {0x04, 0x01, 0x00}},
+ {{0x0c, 0xff, 0x00},
+ {0x0c, 0x1f, 0x00},
+ {0x0c, 0x1b, 0x00},
+ {0x04, 0xff, 0x01},
+ {0x04, 0x1f, 0x01},
+ {0x04, 0x1b, 0x01}},
+ };
+
+ if (frame_rate > 0)
+ sd->frame_rate = frame_rate;
+ if (sd->frame_rate >= 30)
+ fr = 0;
+ else if (sd->frame_rate >= 25)
+ fr = 1;
+ else if (sd->frame_rate >= 20)
+ fr = 2;
+ else if (sd->frame_rate >= 15)
+ fr = 3;
+ else if (sd->frame_rate >= 10)
+ fr = 4;
+ else
+ fr = 5;
+ reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]);
+ reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]);
+ clock = fr_tb[sd->gspca_dev.curr_mode][fr][2];
+ if (sd->sensor == SEN_OV7660)
+ clock |= 0x80; /* enable double clock */
+ ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
}
/* this function is called at probe time */
@@ -2973,99 +3179,119 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
- int ret = 0;
sd->bridge = id->driver_info & BRIDGE_MASK;
- sd->invert_led = id->driver_info & BRIDGE_INVERT_LED;
+ sd->invert_led = (id->driver_info & BRIDGE_INVERT_LED) != 0;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_configure(gspca_dev);
+ cam->cam_mode = ov511_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- ret = ov518_configure(gspca_dev);
+ cam->cam_mode = ov518_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
break;
case BRIDGE_OV519:
- ret = ov519_configure(sd);
+ cam->cam_mode = ov519_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+ sd->invert_led = !sd->invert_led;
break;
case BRIDGE_OVFX2:
- ret = ovfx2_configure(sd);
+ cam->cam_mode = ov519_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
cam->bulk_size = OVFX2_BULK_SIZE;
cam->bulk_nurbs = MAX_NURBS;
cam->bulk = 1;
break;
case BRIDGE_W9968CF:
- ret = w9968cf_configure(sd);
+ cam->cam_mode = w9968cf_vga_mode;
+ cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
cam->reverse_alts = 1;
break;
}
- if (ret)
- goto error;
+ gspca_dev->cam.ctrls = sd->ctrls;
+ sd->quality = QUALITY_DEF;
- ov51x_led_control(sd, 0); /* turn LED off */
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ ov511_configure(gspca_dev);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ ov518_configure(gspca_dev);
+ break;
+ case BRIDGE_OV519:
+ ov519_configure(sd);
+ break;
+ case BRIDGE_OVFX2:
+ ovfx2_configure(sd);
+ break;
+ case BRIDGE_W9968CF:
+ w9968cf_configure(sd);
+ break;
+ }
/* The OV519 must be more aggressive about sensor detection since
* I2C write will never fail if the sensor is not present. We have
* to try to initialize the sensor to detect its presence */
+ sd->sensor = -1;
/* Test for 76xx */
if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
- if (ov7xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV7xx0");
- goto error;
- }
+ ov7xx0_configure(sd);
+
/* Test for 6xx0 */
} else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
- if (ov6xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV6xx0");
- goto error;
- }
+ ov6xx0_configure(sd);
+
/* Test for 8xx0 */
} else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
- if (ov8xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV8xx0");
- goto error;
- }
+ ov8xx0_configure(sd);
+
/* Test for 3xxx / 2xxx */
} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
- if (ov_hires_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure high res OV");
- goto error;
- }
+ ov_hires_configure(sd);
} else {
err("Can't determine sensor slave IDs");
goto error;
}
+ if (sd->sensor < 0)
+ goto error;
+
+ ov51x_led_control(sd, 0); /* turn LED off */
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- if (!sd->sif) {
- cam->cam_mode = ov511_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov511_sif_mode;
cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
}
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- if (!sd->sif) {
- cam->cam_mode = ov518_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov518_sif_mode;
cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
}
break;
case BRIDGE_OV519:
- if (!sd->sif) {
- cam->cam_mode = ov519_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov519_sif_mode;
cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
}
@@ -3077,118 +3303,107 @@ static int sd_config(struct gspca_dev *gspca_dev,
} else if (sd->sensor == SEN_OV3610) {
cam->cam_mode = ovfx2_ov3610_mode;
cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
- } else if (!sd->sif) {
- cam->cam_mode = ov519_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- } else {
+ } else if (sd->sif) {
cam->cam_mode = ov519_sif_mode;
cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
}
break;
case BRIDGE_W9968CF:
- cam->cam_mode = w9968cf_vga_mode;
- cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
if (sd->sif)
- cam->nmodes--;
+ cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1;
/* w9968cf needs initialisation once the sensor is known */
- if (w9968cf_init(sd) < 0)
- goto error;
+ w9968cf_init(sd);
break;
}
- gspca_dev->cam.ctrls = sd->ctrls;
- if (sd->sensor == SEN_OV7670)
- gspca_dev->ctrl_dis = 1 << COLORS;
- else
- gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
- sd->quality = QUALITY_DEF;
- if (sd->sensor == SEN_OV7640 ||
- sd->sensor == SEN_OV7648)
- gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT) | (1 << CONTRAST);
- if (sd->sensor == SEN_OV7670)
- gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT;
- /* OV8610 Frequency filter control should work but needs testing */
- if (sd->sensor == SEN_OV8610)
- gspca_dev->ctrl_dis |= 1 << FREQ;
- /* No controls for the OV2610/OV3610 */
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- gspca_dev->ctrl_dis |= (1 << NCTRL) - 1;
- return 0;
-error:
- PDEBUG(D_ERR, "OV519 Config failed");
- return -EBUSY;
-}
-
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
+ gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
/* initialize the sensor */
switch (sd->sensor) {
case SEN_OV2610:
- if (write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610)))
- return -EIO;
+ write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610));
+
/* Enable autogain, autoexpo, awb, bandfilter */
- if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
- return -EIO;
+ i2c_w_mask(sd, 0x13, 0x27, 0x27);
break;
case SEN_OV3610:
- if (write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)))
- return -EIO;
+ write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b));
+
/* Enable autogain, autoexpo, awb, bandfilter */
- if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
- return -EIO;
+ i2c_w_mask(sd, 0x13, 0x27, 0x27);
break;
case SEN_OV6620:
- if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
- return -EIO;
+ write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20));
break;
case SEN_OV6630:
case SEN_OV66308AF:
sd->ctrls[CONTRAST].def = 200;
/* The default is too low for the ov6630 */
- if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
- return -EIO;
+ write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30));
break;
default:
/* case SEN_OV7610: */
/* case SEN_OV76BE: */
- if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
- return -EIO;
- if (i2c_w_mask(sd, 0x0e, 0x00, 0x40))
- return -EIO;
+ write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610));
+ i2c_w_mask(sd, 0x0e, 0x00, 0x40);
break;
case SEN_OV7620:
case SEN_OV7620AE:
- if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
- return -EIO;
+ write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620));
break;
case SEN_OV7640:
case SEN_OV7648:
- if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
- return -EIO;
+ write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640));
+ break;
+ case SEN_OV7660:
+ i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET);
+ msleep(14);
+ reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
+ write_regvals(sd, init_519_ov7660,
+ ARRAY_SIZE(init_519_ov7660));
+ write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
+ sd->gspca_dev.curr_mode = 1; /* 640x480 */
+ sd->frame_rate = 15;
+ ov519_set_mode(sd);
+ ov519_set_fr(sd);
+ sd->ctrls[COLORS].max = 4; /* 0..4 */
+ sd->ctrls[COLORS].val =
+ sd->ctrls[COLORS].def = 2;
+ setcolors(gspca_dev);
+ sd->ctrls[CONTRAST].max = 6; /* 0..6 */
+ sd->ctrls[CONTRAST].val =
+ sd->ctrls[CONTRAST].def = 3;
+ setcontrast(gspca_dev);
+ sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */
+ sd->ctrls[BRIGHTNESS].val =
+ sd->ctrls[BRIGHTNESS].def = 3;
+ setbrightness(gspca_dev);
+ sd_reset_snapshot(gspca_dev);
+ ov51x_restart(sd);
+ ov51x_stop(sd); /* not in win traces */
+ ov51x_led_control(sd, 0);
break;
case SEN_OV7670:
sd->ctrls[FREQ].max = 3; /* auto */
sd->ctrls[FREQ].def = 3;
- if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
- return -EIO;
+ write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670));
break;
case SEN_OV8610:
- if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
- return -EIO;
+ write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
break;
}
- return 0;
+ return gspca_dev->usb_err;
+error:
+ PDEBUG(D_ERR, "OV519 Config failed");
+ return -EINVAL;
}
/* Set up the OV511/OV511+ with the given image parameters.
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov511_mode_init_regs(struct sd *sd)
+static void ov511_mode_init_regs(struct sd *sd)
{
int hsegs, vsegs, packet_size, fps, needed;
int interlaced = 0;
@@ -3199,7 +3414,8 @@ static int ov511_mode_init_regs(struct sd *sd)
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
err("Couldn't get altsetting");
- return -EIO;
+ sd->gspca_dev.usb_err = -EIO;
+ return;
}
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
@@ -3302,8 +3518,6 @@ static int ov511_mode_init_regs(struct sd *sd)
reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE);
reg_w(sd, R51x_SYS_RESET, 0);
-
- return 0;
}
/* Sets up the OV518/OV518+ with the given image parameters
@@ -3313,7 +3527,7 @@ static int ov511_mode_init_regs(struct sd *sd)
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov518_mode_init_regs(struct sd *sd)
+static void ov518_mode_init_regs(struct sd *sd)
{
int hsegs, vsegs, packet_size;
struct usb_host_interface *alt;
@@ -3323,14 +3537,14 @@ static int ov518_mode_init_regs(struct sd *sd)
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
err("Couldn't get altsetting");
- return -EIO;
+ sd->gspca_dev.usb_err = -EIO;
+ return;
}
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
/******** Set the mode ********/
-
reg_w(sd, 0x2b, 0);
reg_w(sd, 0x2c, 0);
reg_w(sd, 0x2d, 0);
@@ -3364,7 +3578,7 @@ static int ov518_mode_init_regs(struct sd *sd)
/* Windows driver does this here; who knows why */
reg_w(sd, 0x2f, 0x80);
- /******** Set the framerate ********/
+ /******** Set the framerate ********/
sd->clockdiv = 1;
/* Mode independent, but framerate dependent, regs */
@@ -3427,11 +3641,8 @@ static int ov518_mode_init_regs(struct sd *sd)
}
reg_w(sd, 0x2f, 0x80);
-
- return 0;
}
-
/* Sets up the OV519 with the given image parameters
*
* OV519 needs a completely different approach, until we can figure out what
@@ -3439,12 +3650,12 @@ static int ov518_mode_init_regs(struct sd *sd)
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov519_mode_init_regs(struct sd *sd)
+static void ov519_mode_init_regs(struct sd *sd)
{
static const struct ov_regvals mode_init_519_ov7670[] = {
{ 0x5d, 0x03 }, /* Turn off suspend mode */
{ 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
- { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
{ 0xa2, 0x20 }, /* a2-a5 are undocumented */
{ 0xa3, 0x18 },
{ 0xa4, 0x04 },
@@ -3467,7 +3678,7 @@ static int ov519_mode_init_regs(struct sd *sd)
static const struct ov_regvals mode_init_519[] = {
{ 0x5d, 0x03 }, /* Turn off suspend mode */
{ 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
- { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
{ 0xa2, 0x20 }, /* a2-a5 are undocumented */
{ 0xa3, 0x18 },
{ 0xa4, 0x04 },
@@ -3486,19 +3697,21 @@ static int ov519_mode_init_regs(struct sd *sd)
};
/******** Set the mode ********/
- if (sd->sensor != SEN_OV7670) {
- if (write_regvals(sd, mode_init_519,
- ARRAY_SIZE(mode_init_519)))
- return -EIO;
+ switch (sd->sensor) {
+ default:
+ write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519));
if (sd->sensor == SEN_OV7640 ||
sd->sensor == SEN_OV7648) {
/* Select 8-bit input mode */
reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
}
- } else {
- if (write_regvals(sd, mode_init_519_ov7670,
- ARRAY_SIZE(mode_init_519_ov7670)))
- return -EIO;
+ break;
+ case SEN_OV7660:
+ return; /* done by ov519_set_mode/fr() */
+ case SEN_OV7670:
+ write_regvals(sd, mode_init_519_ov7670,
+ ARRAY_SIZE(mode_init_519_ov7670));
+ break;
}
reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4);
@@ -3594,17 +3807,16 @@ static int ov519_mode_init_regs(struct sd *sd)
}
break;
}
- return 0;
}
-static int mode_init_ov_sensor_regs(struct sd *sd)
+static void mode_init_ov_sensor_regs(struct sd *sd)
{
struct gspca_dev *gspca_dev;
int qvga, xstart, xend, ystart, yend;
- __u8 v;
+ u8 v;
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
+ qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
/******** Mode (VGA/QVGA) and sensor specific regs ********/
switch (sd->sensor) {
@@ -3616,7 +3828,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
- return 0;
+ return;
case SEN_OV3610:
if (qvga) {
xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
@@ -3640,7 +3852,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w(sd, 0x18, xend >> 4);
i2c_w(sd, 0x19, ystart >> 3);
i2c_w(sd, 0x1a, yend >> 3);
- return 0;
+ return;
case SEN_OV8610:
/* For OV8610 qvga means qsvga */
i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
@@ -3687,11 +3899,11 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
/* set COM7_FMT_VGA or COM7_FMT_QVGA
* do we need to set anything else?
* HSTART etc are set in set_ov_sensor_window itself */
- i2c_w_mask(sd, OV7670_REG_COM7,
+ i2c_w_mask(sd, OV7670_R12_COM7,
qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
OV7670_COM7_FMT_MASK);
i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB,
OV7670_COM8_AWB);
if (qvga) { /* QVGA from ov7670.c by
* Jonathan Corbet */
@@ -3707,21 +3919,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
}
/* OV7670 hardware window registers are split across
* multiple locations */
- i2c_w(sd, OV7670_REG_HSTART, xstart >> 3);
- i2c_w(sd, OV7670_REG_HSTOP, xend >> 3);
- v = i2c_r(sd, OV7670_REG_HREF);
+ i2c_w(sd, OV7670_R17_HSTART, xstart >> 3);
+ i2c_w(sd, OV7670_R18_HSTOP, xend >> 3);
+ v = i2c_r(sd, OV7670_R32_HREF);
v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
msleep(10); /* need to sleep between read and write to
* same reg! */
- i2c_w(sd, OV7670_REG_HREF, v);
+ i2c_w(sd, OV7670_R32_HREF, v);
- i2c_w(sd, OV7670_REG_VSTART, ystart >> 2);
- i2c_w(sd, OV7670_REG_VSTOP, yend >> 2);
- v = i2c_r(sd, OV7670_REG_VREF);
+ i2c_w(sd, OV7670_R19_VSTART, ystart >> 2);
+ i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2);
+ v = i2c_r(sd, OV7670_R03_VREF);
v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
msleep(10); /* need to sleep between read and write to
* same reg! */
- i2c_w(sd, OV7670_REG_VREF, v);
+ i2c_w(sd, OV7670_R03_VREF, v);
break;
case SEN_OV6620:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
@@ -3734,46 +3946,50 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
break;
default:
- return -EINVAL;
+ return;
}
/******** Clock programming ********/
i2c_w(sd, 0x11, sd->clockdiv);
-
- return 0;
}
+/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (sd->sensor != SEN_OV7670)
- return;
if (sd->gspca_dev.streaming)
- ov51x_stop(sd);
- i2c_w_mask(sd, OV7670_REG_MVFP,
+ reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */
+ i2c_w_mask(sd, OV7670_R1E_MVFP,
OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val
| OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val,
OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
if (sd->gspca_dev.streaming)
- ov51x_restart(sd);
+ reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */
}
-static int set_ov_sensor_window(struct sd *sd)
+static void set_ov_sensor_window(struct sd *sd)
{
struct gspca_dev *gspca_dev;
int qvga, crop;
int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
- int ret;
/* mode setup is fully handled in mode_init_ov_sensor_regs for these */
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610 ||
- sd->sensor == SEN_OV7670)
- return mode_init_ov_sensor_regs(sd);
+ switch (sd->sensor) {
+ case SEN_OV2610:
+ case SEN_OV3610:
+ case SEN_OV7670:
+ mode_init_ov_sensor_regs(sd);
+ return;
+ case SEN_OV7660:
+ ov519_set_mode(sd);
+ ov519_set_fr(sd);
+ return;
+ }
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
- crop = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 2;
+ qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
+ crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2;
/* The different sensor ICs handle setting up of window differently.
* IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
@@ -3820,7 +4036,7 @@ static int set_ov_sensor_window(struct sd *sd)
vwsbase = vwebase = 0x03;
break;
default:
- return -EINVAL;
+ return;
}
switch (sd->sensor) {
@@ -3855,23 +4071,18 @@ static int set_ov_sensor_window(struct sd *sd)
}
}
- ret = mode_init_ov_sensor_regs(sd);
- if (ret < 0)
- return ret;
+ mode_init_ov_sensor_regs(sd);
i2c_w(sd, 0x17, hwsbase);
i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale));
i2c_w(sd, 0x19, vwsbase);
i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale));
-
- return 0;
}
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
/* Default for most bridges, allow bridge_mode_init_regs to override */
sd->sensor_width = sd->gspca_dev.width;
@@ -3880,50 +4091,46 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_mode_init_regs(sd);
+ ov511_mode_init_regs(sd);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- ret = ov518_mode_init_regs(sd);
+ ov518_mode_init_regs(sd);
break;
case BRIDGE_OV519:
- ret = ov519_mode_init_regs(sd);
+ ov519_mode_init_regs(sd);
break;
/* case BRIDGE_OVFX2: nothing to do */
case BRIDGE_W9968CF:
- ret = w9968cf_mode_init_regs(sd);
+ w9968cf_mode_init_regs(sd);
break;
}
- if (ret < 0)
- goto out;
-
- ret = set_ov_sensor_window(sd);
- if (ret < 0)
- goto out;
-
- setcontrast(gspca_dev);
- setbrightness(gspca_dev);
- setcolors(gspca_dev);
- sethvflip(gspca_dev);
- setautobright(gspca_dev);
- setfreq_i(sd);
+
+ set_ov_sensor_window(sd);
+
+ if (!(sd->gspca_dev.ctrl_dis & (1 << CONTRAST)))
+ setcontrast(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS)))
+ setbrightness(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS)))
+ setcolors(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP))))
+ sethvflip(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT)))
+ setautobright(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ)))
+ setfreq_i(sd);
/* Force clear snapshot state in case the snapshot button was
pressed while we weren't streaming */
sd->snapshot_needs_reset = 1;
sd_reset_snapshot(gspca_dev);
- sd->snapshot_pressed = 0;
sd->first_frame = 3;
- ret = ov51x_restart(sd);
- if (ret < 0)
- goto out;
+ ov51x_restart(sd);
ov51x_led_control(sd, 1);
- return 0;
-out:
- PDEBUG(D_ERR, "camera start error:%d", ret);
- return ret;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -3938,8 +4145,21 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (!sd->gspca_dev.present)
+ return;
if (sd->bridge == BRIDGE_W9968CF)
w9968cf_stop0(sd);
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->snapshot_pressed) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->snapshot_pressed = 0;
+ }
+#endif
+ if (sd->bridge == BRIDGE_OV519)
+ reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
}
static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
@@ -4160,6 +4380,22 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals brit_7660[][7] = {
+ {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90},
+ {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}},
+ {{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1},
+ {0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}},
+ {{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2},
+ {0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}},
+ {{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3},
+ {0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}},
+ {{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3},
+ {0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}},
+ {{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3},
+ {0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}},
+ {{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4},
+ {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}}
+ };
val = sd->ctrls[BRIGHTNESS].val;
switch (sd->sensor) {
@@ -4179,10 +4415,14 @@ static void setbrightness(struct gspca_dev *gspca_dev)
if (!sd->ctrls[AUTOBRIGHT].val)
i2c_w(sd, OV7610_REG_BRT, val);
break;
+ case SEN_OV7660:
+ write_i2c_regvals(sd, brit_7660[val],
+ ARRAY_SIZE(brit_7660[0]));
+ break;
case SEN_OV7670:
/*win trace
- * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
- i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+ * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */
+ i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val));
break;
}
}
@@ -4191,6 +4431,64 @@ static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals contrast_7660[][31] = {
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0},
+ {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30},
+ {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24},
+ {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65},
+ {0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83},
+ {0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f},
+ {0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94},
+ {0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30},
+ {0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24},
+ {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62},
+ {0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81},
+ {0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1},
+ {0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84},
+ {0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40},
+ {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24},
+ {0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d},
+ {0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81},
+ {0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e},
+ {0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70},
+ {0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48},
+ {0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34},
+ {0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58},
+ {0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80},
+ {0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9},
+ {0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}},
+ {{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80},
+ {0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60},
+ {0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38},
+ {0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e},
+ {0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46},
+ {0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c},
+ {0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4},
+ {0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}},
+ {{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80},
+ {0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30},
+ {0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50},
+ {0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08},
+ {0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a},
+ {0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b},
+ {0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3},
+ {0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}},
+ {{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60},
+ {0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8},
+ {0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c},
+ {0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04},
+ {0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22},
+ {0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b},
+ {0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde},
+ {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}},
+ };
val = sd->ctrls[CONTRAST].val;
switch (sd->sensor) {
@@ -4203,7 +4501,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
break;
case SEN_OV8610: {
- static const __u8 ctab[] = {
+ static const u8 ctab[] = {
0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
};
@@ -4213,7 +4511,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
}
case SEN_OV7620:
case SEN_OV7620AE: {
- static const __u8 ctab[] = {
+ static const u8 ctab[] = {
0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
};
@@ -4222,9 +4520,13 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, 0x64, ctab[val >> 4]);
break;
}
+ case SEN_OV7660:
+ write_i2c_regvals(sd, contrast_7660[val],
+ ARRAY_SIZE(contrast_7660[0]));
+ break;
case SEN_OV7670:
/* check that this isn't just the same as ov7610 */
- i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
+ i2c_w(sd, OV7670_R56_CONTRAS, val >> 1);
break;
}
}
@@ -4233,6 +4535,18 @@ static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals colors_7660[][6] = {
+ {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a},
+ {0x53, 0x19}, {0x54, 0x23}},
+ {{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11},
+ {0x53, 0x2c}, {0x54, 0x3e}},
+ {{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19},
+ {0x53, 0x40}, {0x54, 0x59}},
+ {{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20},
+ {0x53, 0x53}, {0x54, 0x73}},
+ {{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28},
+ {0x53, 0x66}, {0x54, 0x8e}},
+ };
val = sd->ctrls[COLORS].val;
switch (sd->sensor) {
@@ -4256,6 +4570,10 @@ static void setcolors(struct gspca_dev *gspca_dev)
case SEN_OV7648:
i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
break;
+ case SEN_OV7660:
+ write_i2c_regvals(sd, colors_7660[val],
+ ARRAY_SIZE(colors_7660[0]));
+ break;
case SEN_OV7670:
/* supported later once I work out how to do it
* transparently fail now! */
@@ -4268,38 +4586,31 @@ static void setautobright(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 ||
- sd->sensor == SEN_OV7670 ||
- sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- return;
-
i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10);
}
static void setfreq_i(struct sd *sd)
{
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- return;
-
- if (sd->sensor == SEN_OV7670) {
+ if (sd->sensor == SEN_OV7660
+ || sd->sensor == SEN_OV7670) {
switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */
- i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
+ i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT);
break;
case 1: /* 50 hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18);
+ i2c_w_mask(sd, OV7670_R3B_COM11, 0x08, 0x18);
break;
case 2: /* 60 hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18);
+ i2c_w_mask(sd, OV7670_R3B_COM11, 0x00, 0x18);
break;
- case 3: /* Auto hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ case 3: /* Auto hz - ov7670 only */
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO,
+ i2c_w_mask(sd, OV7670_R3B_COM11, OV7670_COM11_HZAUTO,
0x18);
break;
}
@@ -4443,14 +4754,14 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4064),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4068),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0155),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
{USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
@@ -4464,7 +4775,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF },
- {USB_DEVICE(0x8020, 0xEF04), .driver_info = BRIDGE_OVFX2 },
+ {USB_DEVICE(0x8020, 0xef04), .driver_info = BRIDGE_OVFX2 },
{}
};
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 88ef03f6235b..0edf93973b1c 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -1243,34 +1243,26 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
}
/* get stream parameters (framerate) */
-static int sd_get_streamparm(struct gspca_dev *gspca_dev,
+static void sd_get_streamparm(struct gspca_dev *gspca_dev,
struct v4l2_streamparm *parm)
{
struct v4l2_captureparm *cp = &parm->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe;
struct sd *sd = (struct sd *) gspca_dev;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
cp->capability |= V4L2_CAP_TIMEPERFRAME;
tpf->numerator = 1;
tpf->denominator = sd->frame_rate;
-
- return 0;
}
/* set stream parameters (framerate) */
-static int sd_set_streamparm(struct gspca_dev *gspca_dev,
+static void sd_set_streamparm(struct gspca_dev *gspca_dev,
struct v4l2_streamparm *parm)
{
struct v4l2_captureparm *cp = &parm->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe;
struct sd *sd = (struct sd *) gspca_dev;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
/* Set requested framerate */
sd->frame_rate = tpf->denominator / tpf->numerator;
if (gspca_dev->streaming)
@@ -1279,8 +1271,6 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
/* Return the actual framerate */
tpf->numerator = 1;
tpf->denominator = sd->frame_rate;
-
- return 0;
}
/* sub-driver description */
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index e831f0d280ea..c5244b4b4777 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -945,7 +945,6 @@ static void setautogain(struct gspca_dev *gspca_dev)
u8 val;
/*fixme: should adjust agc/awb/aec by different controls */
- val = sd->autogain;
val = sccb_read(gspca_dev, 0x13); /* com8 */
sccb_write(gspca_dev, 0xff, 0x00);
if (sd->autogain)
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 15e97fa4c337..96f9986305b4 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -162,7 +162,7 @@ static const __u8 pac207_sensor_init[][8] = {
{0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
{0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
{0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
- {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
+ {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
};
static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
@@ -228,7 +228,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
- idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
+ idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4);
idreg[1] = idreg[1] & 0x0f;
PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
idreg[0], idreg[1]);
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 55fbea7381b0..2700975abce5 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -393,7 +393,7 @@ static const __u8 page3_7302[] = {
static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
- const char *buffer, int len)
+ const u8 *buffer, int len)
{
int ret;
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 7657b43b3203..6820f5d58b19 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -261,7 +261,7 @@ static const __u8 page4_7311[] = {
static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
- const char *buffer, int len)
+ const u8 *buffer, int len)
{
int ret;
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 6b155ae3a746..cb08d00d0a31 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -33,6 +33,14 @@ MODULE_LICENSE("GPL");
#define MODULE_NAME "sn9c20x"
+/*
+ * Pixel format private data
+ */
+#define SCALE_MASK 0x0f
+#define SCALE_160x120 0
+#define SCALE_320x240 1
+#define SCALE_640x480 2
+#define SCALE_1280x1024 3
#define MODE_RAW 0x10
#define MODE_JPEG 0x20
#define MODE_SXGA 0x80
@@ -348,47 +356,47 @@ static const struct v4l2_pix_format vga_mode[] = {
.bytesperline = 160,
.sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0 | MODE_JPEG},
+ .priv = SCALE_160x120 | MODE_JPEG},
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0 | MODE_RAW},
+ .priv = SCALE_160x120 | MODE_RAW},
{160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 240 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
+ .priv = SCALE_160x120},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1 | MODE_JPEG},
+ .priv = SCALE_320x240 | MODE_JPEG},
{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1 | MODE_RAW},
+ .priv = SCALE_320x240 | MODE_RAW},
{320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 480 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
+ .priv = SCALE_320x240},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2 | MODE_JPEG},
+ .priv = SCALE_640x480 | MODE_JPEG},
{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2 | MODE_RAW},
+ .priv = SCALE_640x480 | MODE_RAW},
{640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 960 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
+ .priv = SCALE_640x480},
};
static const struct v4l2_pix_format sxga_mode[] = {
@@ -396,52 +404,75 @@ static const struct v4l2_pix_format sxga_mode[] = {
.bytesperline = 160,
.sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0 | MODE_JPEG},
+ .priv = SCALE_160x120 | MODE_JPEG},
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0 | MODE_RAW},
+ .priv = SCALE_160x120 | MODE_RAW},
{160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 240 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
+ .priv = SCALE_160x120},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1 | MODE_JPEG},
+ .priv = SCALE_320x240 | MODE_JPEG},
{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1 | MODE_RAW},
+ .priv = SCALE_320x240 | MODE_RAW},
{320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 480 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
+ .priv = SCALE_320x240},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2 | MODE_JPEG},
+ .priv = SCALE_640x480 | MODE_JPEG},
{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2 | MODE_RAW},
+ .priv = SCALE_640x480 | MODE_RAW},
{640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 960 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
+ .priv = SCALE_640x480},
{1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 1280,
.sizeimage = 1280 * 1024,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 3 | MODE_RAW | MODE_SXGA},
+ .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
+};
+
+static const struct v4l2_pix_format mono_mode[] = {
+ {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_160x120 | MODE_RAW},
+ {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_320x240 | MODE_RAW},
+ {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_640x480 | MODE_RAW},
+ {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
};
static const s16 hsv_red_x[] = {
@@ -1029,16 +1060,19 @@ static struct i2c_reg_u16 mt9v011_init[] = {
};
static struct i2c_reg_u16 mt9m001_init[] = {
- {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
- {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
- {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
- {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
- {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
- {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
- {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
- {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
- {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
- {0x2e, 0x0029}, {0x07, 0x0002},
+ {0x0d, 0x0001},
+ {0x0d, 0x0000},
+ {0x04, 0x0500}, /* hres = 1280 */
+ {0x03, 0x0400}, /* vres = 1024 */
+ {0x20, 0x1100},
+ {0x06, 0x0010},
+ {0x2b, 0x0024},
+ {0x2e, 0x0024},
+ {0x35, 0x0024},
+ {0x2d, 0x0020},
+ {0x2c, 0x0020},
+ {0x09, 0x0ad4},
+ {0x35, 0x0057},
};
static struct i2c_reg_u16 mt9m111_init[] = {
@@ -1224,8 +1258,17 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
{
int i;
+ u16 id;
struct sd *sd = (struct sd *) gspca_dev;
+ if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
+ return -EINVAL;
+
+ if (id != 0x7fa2) {
+ err("sensor id for ov9650 doesn't match (0x%04x)", id);
+ return -ENODEV;
+ }
+
for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
if (i2c_w1(gspca_dev, ov9650_init[i].reg,
ov9650_init[i].val) < 0) {
@@ -1425,6 +1468,25 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
+ u16 id;
+
+ if (i2c_r2(gspca_dev, 0x00, &id) < 0)
+ return -EINVAL;
+
+ /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+ switch (id) {
+ case 0x8411:
+ case 0x8421:
+ info("MT9M001 color sensor detected");
+ break;
+ case 0x8431:
+ info("MT9M001 mono sensor detected");
+ break;
+ default:
+ err("No MT9M001 chip detected, ID = %x\n", id);
+ return -ENODEV;
+ }
+
for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
mt9m001_init[i].val) < 0) {
@@ -1434,8 +1496,8 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
}
/* disable hflip and vflip */
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
- sd->hstart = 2;
- sd->vstart = 2;
+ sd->hstart = 1;
+ sd->vstart = 1;
return 0;
}
@@ -1977,6 +2039,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = sxga_mode;
cam->nmodes = ARRAY_SIZE(sxga_mode);
break;
+ case SENSOR_MT9M001:
+ cam->cam_mode = mono_mode;
+ cam->nmodes = ARRAY_SIZE(mono_mode);
+ break;
default:
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -2075,7 +2141,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
case SENSOR_MT9M001:
if (mt9m001_init_sensor(gspca_dev) < 0)
return -ENODEV;
- info("MT9M001 sensor detected");
break;
case SENSOR_HV7131R:
if (hv7131r_init_sensor(gspca_dev) < 0)
@@ -2173,22 +2238,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
else if (mode & MODE_JPEG)
fmt = 0x2c;
else
- fmt = 0x2f;
+ fmt = 0x2f; /* YUV 420 */
- switch (mode & 0x0f) {
- case 3:
+ switch (mode & SCALE_MASK) {
+ case SCALE_1280x1024:
scale = 0xc0;
info("Set 1280x1024");
break;
- case 2:
+ case SCALE_640x480:
scale = 0x80;
info("Set 640x480");
break;
- case 1:
+ case SCALE_320x240:
scale = 0x90;
info("Set 320x240");
break;
- case 0:
+ case SCALE_160x120:
scale = 0xa0;
info("Set 160x120");
break;
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 706f96f92654..73504a3f87b7 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -56,6 +56,8 @@ struct sd {
int prev_avg_lum;
int exp_too_low_cnt;
int exp_too_high_cnt;
+ int header_read;
+ u8 header[12]; /* Header without sof marker */
unsigned short exposure;
unsigned char gain;
@@ -71,14 +73,15 @@ struct sd {
#define BRIDGE_103 1
__u8 sensor; /* Type of image sensor chip */
-#define SENSOR_HV7131R 0
-#define SENSOR_OV6650 1
-#define SENSOR_OV7630 2
-#define SENSOR_PAS106 3
-#define SENSOR_PAS202 4
-#define SENSOR_TAS5110C 5
-#define SENSOR_TAS5110D 6
-#define SENSOR_TAS5130CXX 7
+#define SENSOR_HV7131D 0
+#define SENSOR_HV7131R 1
+#define SENSOR_OV6650 2
+#define SENSOR_OV7630 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110C 6
+#define SENSOR_TAS5110D 7
+#define SENSOR_TAS5130CXX 8
__u8 reg11;
};
@@ -303,14 +306,29 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
-static const __u8 initHv7131[] = {
+static const __u8 initHv7131d[] = {
+ 0x04, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
+ 0x28, 0x1e, 0x60, 0x8e, 0x42,
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131d_sensor_init[][8] = {
+ {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x30, 0x30, 0x00, 0x00, 0x00, 0x17}, /* reset level */
+ {0xa0, 0x11, 0x34, 0x02, 0x00, 0x00, 0x00, 0x17}, /* pixel bias volt */
+};
+
+static const __u8 initHv7131r[] = {
0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
0x28, 0x1e, 0x60, 0x8a, 0x20,
0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
};
-static const __u8 hv7131_sensor_init[][8] = {
+static const __u8 hv7131r_sensor_init[][8] = {
{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
{0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
{0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
@@ -340,7 +358,7 @@ static const __u8 ov6650_sensor_init[][8] = {
* but blue wont be there. Avoid this data ... */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
- {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+ {0xa0, 0x60, 0x30, 0x3d, 0x0a, 0xd8, 0xa4, 0x10},
/* Enable rgb brightness control */
{0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
/* HDG: Note windows uses the line below, which sets both register 0x60
@@ -505,7 +523,7 @@ static const __u8 pas202_sensor_init[][8] = {
{0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
- {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x01, 0x32, 0x10},
+ {0xd0, 0x40, 0x0c, 0x00, 0x0c, 0x01, 0x32, 0x10},
{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
@@ -551,7 +569,8 @@ static const __u8 tas5130_sensor_init[][8] = {
};
static struct sensor_data sensor_data[] = {
-SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
+SENS(initHv7131d, NULL, hv7131d_sensor_init, NULL, NULL, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initHv7131r, NULL, hv7131r_sensor_init, NULL, NULL, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
F_GAIN, 0, 0x21),
@@ -701,7 +720,18 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
unsigned char gain = sd->gain;
switch (sd->sensor) {
+ case SENSOR_HV7131D: {
+ __u8 i2c[] =
+ {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17};
+ i2c[3] = 0x3f - (sd->gain / 4);
+ i2c[4] = 0x3f - (sd->gain / 4);
+ i2c[5] = 0x3f - (sd->gain / 4);
+
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
case SENSOR_TAS5110C:
case SENSOR_TAS5110D: {
__u8 i2c[] =
@@ -788,6 +818,23 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
switch (sd->sensor) {
+ case SENSOR_HV7131D: {
+ /* Note the datasheet wrongly says line mode exposure uses reg
+ 0x26 and 0x27, testing has shown 0x25 + 0x26 */
+ __u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17};
+ /* The HV7131D's exposure goes from 0 - 65535, we scale our
+ exposure of 0-1023 to 0-6138. There are 2 reasons for this:
+ 1) This puts our exposure knee of 200 at approx the point
+ where the framerate starts dropping
+ 2) At 6138 the framerate has already dropped to 2 fps,
+ going any lower makes little sense */
+ __u16 reg = sd->exposure * 6;
+ i2c[3] = reg >> 8;
+ i2c[4] = reg & 0xff;
+ if (i2c_w(gspca_dev, i2c) != 0)
+ goto err;
+ break;
+ }
case SENSOR_TAS5110C:
case SENSOR_TAS5110D: {
/* register 19's high nibble contains the sn9c10x clock divider
@@ -1177,13 +1224,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
sd_init(gspca_dev);
}
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
- u8 *data, /* isoc packet */
- int len) /* iso packet length */
+static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam = &gspca_dev->cam;
+ int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12;
/* frames start with:
* ff ff 00 c4 c4 96 synchro
@@ -1194,58 +1238,84 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
* ll mm brightness sum outside auto exposure
* (xx xx xx xx xx) audio values for snc103
*/
- if (len > 6 && len < 24) {
- for (i = 0; i < len - 6; i++) {
- if (data[0 + i] == 0xff
- && data[1 + i] == 0xff
- && data[2 + i] == 0x00
- && data[3 + i] == 0xc4
- && data[4 + i] == 0xc4
- && data[5 + i] == 0x96) { /* start of frame */
- int lum = -1;
- int pkt_type = LAST_PACKET;
- int fr_h_sz = (sd->bridge == BRIDGE_103) ?
- 18 : 12;
-
- if (len - i < fr_h_sz) {
- PDEBUG(D_STREAM, "packet too short to"
- " get avg brightness");
- } else if (sd->bridge == BRIDGE_103) {
- lum = data[i + 9] +
- (data[i + 10] << 8);
- } else {
- lum = data[i + 8] + (data[i + 9] << 8);
- }
- /* When exposure changes midway a frame we
- get a lum of 0 in this case drop 2 frames
- as the frames directly after an exposure
- change have an unstable image. Sometimes lum
- *really* is 0 (cam used in low light with
- low exposure setting), so do not drop frames
- if the previous lum was 0 too. */
- if (lum == 0 && sd->prev_avg_lum != 0) {
- lum = -1;
- sd->frames_to_drop = 2;
- sd->prev_avg_lum = 0;
- } else
- sd->prev_avg_lum = lum;
- atomic_set(&sd->avg_lum, lum);
-
- if (sd->frames_to_drop) {
- sd->frames_to_drop--;
- pkt_type = DISCARD_PACKET;
- }
-
- gspca_frame_add(gspca_dev, pkt_type,
- NULL, 0);
- data += i + fr_h_sz;
- len -= i + fr_h_sz;
- gspca_frame_add(gspca_dev, FIRST_PACKET,
- data, len);
- return;
+ for (i = 0; i < len; i++) {
+ switch (sd->header_read) {
+ case 0:
+ if (data[i] == 0xff)
+ sd->header_read++;
+ break;
+ case 1:
+ if (data[i] == 0xff)
+ sd->header_read++;
+ else
+ sd->header_read = 0;
+ break;
+ case 2:
+ if (data[i] == 0x00)
+ sd->header_read++;
+ else if (data[i] != 0xff)
+ sd->header_read = 0;
+ break;
+ case 3:
+ if (data[i] == 0xc4)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ case 4:
+ if (data[i] == 0xc4)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ case 5:
+ if (data[i] == 0x96)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ default:
+ sd->header[sd->header_read - 6] = data[i];
+ sd->header_read++;
+ if (sd->header_read == header_size) {
+ sd->header_read = 0;
+ return data + i + 1;
}
}
}
+ return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0;
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+ u8 *sof;
+
+ sof = find_sof(gspca_dev, data, len);
+ if (sof) {
+ if (sd->bridge == BRIDGE_103) {
+ fr_h_sz = 18;
+ lum_offset = 3;
+ } else {
+ fr_h_sz = 12;
+ lum_offset = 2;
+ }
+
+ len_after_sof = len - (sof - data);
+ len = (sof - data) - fr_h_sz;
+ if (len < 0)
+ len = 0;
+ }
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
/* In raw mode we sometimes get some garbage after the frame
@@ -1259,6 +1329,33 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
+ if (sof) {
+ int lum = sd->header[lum_offset] +
+ (sd->header[lum_offset + 1] << 8);
+
+ /* When exposure changes midway a frame we
+ get a lum of 0 in this case drop 2 frames
+ as the frames directly after an exposure
+ change have an unstable image. Sometimes lum
+ *really* is 0 (cam used in low light with
+ low exposure setting), so do not drop frames
+ if the previous lum was 0 too. */
+ if (lum == 0 && sd->prev_avg_lum != 0) {
+ lum = -1;
+ sd->frames_to_drop = 2;
+ sd->prev_avg_lum = 0;
+ } else
+ sd->prev_avg_lum = lum;
+ atomic_set(&sd->avg_lum, lum);
+
+ if (sd->frames_to_drop)
+ sd->frames_to_drop--;
+ else
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+ gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof);
+ }
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -1431,9 +1528,7 @@ static const struct sd_desc sd_desc = {
static const struct usb_device_id device_table[] __devinitconst = {
{USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
{USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
-#endif
{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
@@ -1444,9 +1539,12 @@ static const struct usb_device_id device_table[] __devinitconst = {
#endif
{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
+ {USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)},
+ /* {USB_DEVICE(0x0c45, 0x602b), SB(MI0343, 102)}, */
{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
+ /* {USB_DEVICE(0x0c45, 0x602b), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 330dadc00106..2d0bb17a30a2 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -63,7 +63,10 @@ struct sd {
#define QUALITY_DEF 80
u8 jpegqual; /* webcam quality */
+ u8 reg01;
+ u8 reg17;
u8 reg18;
+ u8 flags;
s8 ag_cnt;
#define AG_CNT_START 13
@@ -96,6 +99,22 @@ enum sensors {
SENSOR_SP80708,
};
+/* device flags */
+#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */
+
+/* sn9c1xx definitions */
+/* register 0x01 */
+#define S_PWR_DN 0x01 /* sensor power down */
+#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */
+#define V_TX_EN 0x04 /* video transfer enable */
+#define LED 0x08 /* output to pin LED */
+#define SCL_SEL_OD 0x20 /* open-drain mode */
+#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */
+/* register 0x17 */
+#define MCK_SIZE_MASK 0x1f /* sensor master clock */
+#define SEN_CLK_EN 0x20 /* enable sensor clock */
+#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */
+
/* V4L2 controls supported by the driver */
static void setbrightness(struct gspca_dev *gspca_dev);
static void setcontrast(struct gspca_dev *gspca_dev);
@@ -1579,22 +1598,22 @@ static void i2c_w_seq(struct gspca_dev *gspca_dev,
}
}
+/* check the ID of the hv7131 sensor */
+/* this sequence is needed because it activates the sensor */
static void hv7131r_probe(struct gspca_dev *gspca_dev)
{
- i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
+ i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
msleep(10);
- reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
+ reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
msleep(10);
- i2c_r(gspca_dev, 0, 5); /* read sensor id */
- if (gspca_dev->usb_buf[0] == 0x02
+ i2c_r(gspca_dev, 0, 5); /* read sensor id */
+ if (gspca_dev->usb_buf[0] == 0x02 /* chip ID (02 is R) */
&& gspca_dev->usb_buf[1] == 0x09
- && gspca_dev->usb_buf[2] == 0x01
- && gspca_dev->usb_buf[3] == 0x00
- && gspca_dev->usb_buf[4] == 0x00) {
- PDEBUG(D_PROBE, "Sensor sn9c102P HV7131R found");
+ && gspca_dev->usb_buf[2] == 0x01) {
+ PDEBUG(D_PROBE, "Sensor HV7131R found");
return;
}
- PDEBUG(D_PROBE, "Sensor 0x%02x 0x%02x 0x%02x - sn9c102P not found",
+ warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x",
gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
gspca_dev->usb_buf[2]);
}
@@ -1755,141 +1774,6 @@ static void po2030n_probe(struct gspca_dev *gspca_dev)
}
}
-static void bridge_init(struct gspca_dev *gspca_dev,
- const u8 *sn9c1xx)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 reg0102[2];
- const u8 *reg9a;
- static const u8 reg9a_def[] =
- {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
- static const u8 reg9a_spec[] =
- {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
- static const u8 regd4[] = {0x60, 0x00, 0x00};
-
- /* sensor clock already enabled in sd_init */
- /* reg_w1(gspca_dev, 0xf1, 0x00); */
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
-
- /* configure gpio */
- reg0102[0] = sn9c1xx[1];
- reg0102[1] = sn9c1xx[2];
- if (gspca_dev->audio)
- reg0102[1] |= 0x04; /* keep the audio connection */
- reg_w(gspca_dev, 0x01, reg0102, 2);
- reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
- reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
- switch (sd->sensor) {
- case SENSOR_GC0307:
- case SENSOR_OV7660:
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- case SENSOR_SOI768:
- case SENSOR_SP80708:
- reg9a = reg9a_spec;
- break;
- default:
- reg9a = reg9a_def;
- break;
- }
- reg_w(gspca_dev, 0x9a, reg9a, 6);
-
- reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
-
- reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
-
- switch (sd->sensor) {
- case SENSOR_ADCM1700:
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_GC0307:
- msleep(50);
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x22);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- msleep(50);
- break;
- case SENSOR_MI0360B:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x60);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_MT9V111:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OM6802:
- msleep(10);
- reg_w1(gspca_dev, 0x02, 0x73);
- reg_w1(gspca_dev, 0x17, 0x60);
- reg_w1(gspca_dev, 0x01, 0x22);
- msleep(100);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(10);
- reg_w1(gspca_dev, 0x01, 0x42);
- i2c_w8(gspca_dev, om6802_init0[0]);
- i2c_w8(gspca_dev, om6802_init0[1]);
- msleep(15);
- reg_w1(gspca_dev, 0x02, 0x71);
- msleep(150);
- break;
- case SENSOR_OV7630:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0xe2);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OV7648:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_PO1030:
- case SENSOR_SOI768:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_PO2030N:
- case SENSOR_OV7660:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_SP80708:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(100);
- reg_w1(gspca_dev, 0x02, 0x62);
- break;
- default:
-/* case SENSOR_HV7131R: */
-/* case SENSOR_MI0360: */
-/* case SENSOR_MO4000: */
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x42);
- if (sd->sensor == SENSOR_HV7131R)
- hv7131r_probe(gspca_dev);
- break;
- }
-}
-
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -1898,7 +1782,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam;
sd->bridge = id->driver_info >> 16;
- sd->sensor = id->driver_info;
+ sd->sensor = id->driver_info >> 8;
+ sd->flags = id->driver_info;
cam = &gspca_dev->cam;
if (sd->sensor == SENSOR_ADCM1700) {
@@ -1929,7 +1814,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* setup a selector by bridge */
reg_w1(gspca_dev, 0xf1, 0x01);
reg_r(gspca_dev, 0x00, 1);
- reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
+ reg_w1(gspca_dev, 0xf1, 0x00);
reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */
regF1 = gspca_dev->usb_buf[0];
if (gspca_dev->usb_err < 0)
@@ -2423,10 +2308,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg17;
+ u8 reg01, reg17;
+ u8 reg0102[2];
const u8 *sn9c1xx;
const u8 (*init)[8];
+ const u8 *reg9a;
int mode;
+ static const u8 reg9a_def[] =
+ {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+ static const u8 reg9a_spec[] =
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+ static const u8 regd4[] = {0x60, 0x00, 0x00};
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const u8 CA_adcm1700[] =
@@ -2448,7 +2340,85 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* initialize the bridge */
sn9c1xx = sn_tb[sd->sensor];
- bridge_init(gspca_dev, sn9c1xx);
+
+ /* sensor clock already enabled in sd_init */
+ /* reg_w1(gspca_dev, 0xf1, 0x00); */
+ reg01 = sn9c1xx[1];
+ if (sd->flags & PDN_INV)
+ reg01 ^= S_PDN_INV; /* power down inverted */
+ reg_w1(gspca_dev, 0x01, reg01);
+
+ /* configure gpio */
+ reg0102[0] = reg01;
+ reg0102[1] = sn9c1xx[2];
+ if (gspca_dev->audio)
+ reg0102[1] |= 0x04; /* keep the audio connection */
+ reg_w(gspca_dev, 0x01, reg0102, 2);
+ reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
+ reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
+ switch (sd->sensor) {
+ case SENSOR_GC0307:
+ case SENSOR_OV7660:
+ case SENSOR_PO1030:
+ case SENSOR_PO2030N:
+ case SENSOR_SOI768:
+ case SENSOR_SP80708:
+ reg9a = reg9a_spec;
+ break;
+ default:
+ reg9a = reg9a_def;
+ break;
+ }
+ reg_w(gspca_dev, 0x9a, reg9a, 6);
+
+ reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
+
+ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ reg17 = sn9c1xx[0x17];
+ switch (sd->sensor) {
+ case SENSOR_GC0307:
+ msleep(50); /*fixme: is it useful? */
+ break;
+ case SENSOR_OM6802:
+ msleep(10);
+ reg_w1(gspca_dev, 0x02, 0x73);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg_w1(gspca_dev, 0x01, 0x22);
+ msleep(100);
+ reg01 = SCL_SEL_OD | S_PDN_INV;
+ reg17 &= MCK_SIZE_MASK;
+ reg17 |= 0x04; /* clock / 4 */
+ break;
+ }
+ reg01 |= SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~S_PWR_DN; /* sensor power on */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ hv7131r_probe(gspca_dev); /*fixme: is it useful? */
+ break;
+ case SENSOR_OM6802:
+ msleep(10);
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, om6802_init0[0]);
+ i2c_w8(gspca_dev, om6802_init0[1]);
+ msleep(15);
+ reg_w1(gspca_dev, 0x02, 0x71);
+ msleep(150);
+ break;
+ case SENSOR_SP80708:
+ msleep(100);
+ reg_w1(gspca_dev, 0x02, 0x62);
+ break;
+ }
/* initialize the sensor */
i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
@@ -2476,30 +2446,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
switch (sd->sensor) {
- case SENSOR_GC0307:
- reg17 = 0xa2;
- break;
- case SENSOR_MT9V111:
- case SENSOR_MI0360B:
- reg17 = 0xe0;
- break;
- case SENSOR_ADCM1700:
- case SENSOR_OV7630:
- reg17 = 0xe2;
- break;
- case SENSOR_OV7648:
- reg17 = 0x20;
- break;
- case SENSOR_OV7660:
- case SENSOR_SOI768:
- reg17 = 0xa0;
- break;
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- reg17 = 0xa0;
+ case SENSOR_OM6802:
+/* case SENSOR_OV7648: * fixme: sometimes */
break;
default:
- reg17 = 0x60;
+ reg17 |= DEF_EN;
break;
}
reg_w1(gspca_dev, 0x17, reg17);
@@ -2546,95 +2497,67 @@ static int sd_start(struct gspca_dev *gspca_dev)
init = NULL;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- if (mode)
- reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */
- else
- reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */
- reg17 = 0x61; /* 0x:20: enable sensor clock */
+ reg01 |= SYS_SEL_48M | V_TX_EN;
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x02; /* clock / 2 */
switch (sd->sensor) {
case SENSOR_ADCM1700:
init = adcm1700_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xe2;
break;
case SENSOR_GC0307:
init = gc0307_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
+ break;
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ if (mode)
+ reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */
+ else
+ reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
break;
case SENSOR_MI0360B:
init = mi0360b_sensor_param1;
- reg1 &= ~0x02; /* don't inverse pin S_PWR_DN */
- reg17 = 0xe2;
break;
case SENSOR_MO4000:
- if (mode) {
-/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
- reg1 = 0x06; /* clk 24Mz */
- } else {
- reg17 = 0x22; /* 640 MCKSIZE */
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
+ if (mode) { /* if 320x240 */
+ reg01 &= ~SYS_SEL_48M; /* clk 24Mz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
}
break;
case SENSOR_MT9V111:
init = mt9v111_sensor_param1;
- if (mode) {
- reg1 = 0x04; /* 320 clk 48Mhz */
- } else {
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
- reg17 = 0xc2;
- }
break;
case SENSOR_OM6802:
init = om6802_sensor_param1;
- reg17 = 0x64; /* 640 MCKSIZE */
+ if (!mode) { /* if 640x480 */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x04; /* clock / 4 */
+ }
break;
case SENSOR_OV7630:
init = ov7630_sensor_param1;
- reg17 = 0xe2;
- reg1 = 0x44;
break;
case SENSOR_OV7648:
init = ov7648_sensor_param1;
- reg17 = 0x21;
-/* reg1 = 0x42; * 42 - 46? */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
break;
case SENSOR_OV7660:
init = ov7660_sensor_param1;
- if (sd->bridge == BRIDGE_SN9C120) {
- if (mode) { /* 320x240 - 160x120 */
- reg17 = 0xa2;
- reg1 = 0x44; /* 48 Mhz, video trf eneble */
- }
- } else {
- reg17 = 0x22;
- reg1 = 0x06; /* 24 Mhz, video trf eneble
- * inverse power down */
- }
break;
case SENSOR_PO1030:
init = po1030_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
break;
case SENSOR_PO2030N:
init = po2030n_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xa2;
break;
case SENSOR_SOI768:
init = soi768_sensor_param1;
- reg1 = 0x44;
- reg17 = 0xa2;
break;
case SENSOR_SP80708:
init = sp80708_sensor_param1;
- if (mode) {
-/*?? reg1 = 0x04; * 320 clk 48Mhz */
- } else {
- reg1 = 0x46; /* 640 clk 48Mz */
- reg17 = 0xa2;
- }
break;
}
@@ -2684,7 +2607,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
- reg_w1(gspca_dev, 0x01, reg1);
+ reg_w1(gspca_dev, 0x01, reg01);
+ sd->reg01 = reg01;
+ sd->reg17 = reg17;
sethvflip(gspca_dev);
setbrightness(gspca_dev);
@@ -2706,41 +2631,64 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
{ 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
static const u8 stopsoi768[] =
{ 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 };
- u8 data;
- const u8 *sn9c1xx;
+ u8 reg01;
+ u8 reg17;
- data = 0x0b;
+ reg01 = sd->reg01;
+ reg17 = sd->reg17 & ~SEN_CLK_EN;
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_GC0307:
- data = 0x29;
+ case SENSOR_PO2030N:
+ case SENSOR_SP80708:
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~(LED | V_TX_EN);
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */
break;
case SENSOR_HV7131R:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
i2c_w8(gspca_dev, stophv7131);
- data = 0x2b;
break;
case SENSOR_MI0360:
case SENSOR_MI0360B:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */
i2c_w8(gspca_dev, stopmi0360);
- data = 0x29;
break;
- case SENSOR_OV7648:
- i2c_w8(gspca_dev, stopov7648);
- /* fall thru */
case SENSOR_MT9V111:
- case SENSOR_OV7630:
+ case SENSOR_OM6802:
case SENSOR_PO1030:
- data = 0x29;
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ break;
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, stopov7648);
+ break;
+ case SENSOR_OV7660:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
break;
case SENSOR_SOI768:
i2c_w8(gspca_dev, stopsoi768);
- data = 0x29;
break;
}
- sn9c1xx = sn_tb[sd->sensor];
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x01, data);
+
+ reg01 |= SCL_SEL_OD;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= S_PWR_DN; /* sensor power down */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~SYS_SEL_48M; /* clock 24MHz */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
/* Don't disable sensor clock as that disables the button on the cam */
/* reg_w1(gspca_dev, 0xf1, 0x01); */
}
@@ -2954,14 +2902,18 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
#define BS(bridge, sensor) \
.driver_info = (BRIDGE_ ## bridge << 16) \
- | SENSOR_ ## sensor
+ | (SENSOR_ ## sensor << 8)
+#define BSF(bridge, sensor, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 16) \
+ | (SENSOR_ ## sensor << 8) \
+ | (flags)
static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
#endif
- {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)},
- {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)},
+ {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)},
+ {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)},
{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index ad73f4812c05..3a162c6d5466 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -597,7 +597,7 @@ static void setgain(struct gspca_dev *gspca_dev)
else if (sd->gain < 128)
gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
else
- gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+ gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0;
gspca_dev->usb_buf[1] = 0;
reg_w_buf(gspca_dev, 0x8335, 2);
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index c2e88b5303cb..8ba199543856 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -301,6 +301,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x905c)},
{USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x9051)},
{USB_DEVICE(0x2770, 0x9052)},
{USB_DEVICE(0x2770, 0x913d)},
{}
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
index 3e4b0b94c700..a4a98811b9e3 100644
--- a/drivers/media/video/gspca/sq930x.c
+++ b/drivers/media/video/gspca/sq930x.c
@@ -687,10 +687,19 @@ static void cmos_probe(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_buf[0] != 0)
break;
}
- if (i >= ARRAY_SIZE(probe_order))
+ if (i >= ARRAY_SIZE(probe_order)) {
err("Unknown sensor");
- else
- sd->sensor = probe_order[i];
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+ sd->sensor = probe_order[i];
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV9630:
+ err("Sensor %s not yet treated", sensor_tb[sd->sensor].name);
+ gspca_dev->usb_err = -EINVAL;
+ break;
+ }
}
static void mt9v111_init(struct gspca_dev *gspca_dev)
@@ -867,6 +876,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
*/
reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+ if (gspca_dev->usb_err < 0)
+ return gspca_dev->usb_err;
+
/* it returns:
* 03 00 12 93 0b f6 c9 00 live! ultra
* 03 00 07 93 0b f6 ca 00 live! ultra for notebook
@@ -900,15 +912,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_MI0360) {
/* no sensor probe for icam tracer */
- if (gspca_dev->usb_buf[5] == 0xf6) /* if CMOS */
+ if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */
sd->sensor = SENSOR_ICX098BQ;
else
cmos_probe(gspca_dev);
}
-
- PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
-
- global_init(sd, 1);
+ if (gspca_dev->usb_err >= 0) {
+ PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+ global_init(sd, 1);
+ }
return gspca_dev->usb_err;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 086de44a6e57..28ea4175b80e 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -263,7 +263,21 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
static int stv06xx_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int err;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+ int err, packet_size;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ PDEBUG(D_ERR, "Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
+ if (err < 0)
+ return err;
/* Prepare the sensor for start */
err = sd->sensor->start(sd);
@@ -282,6 +296,43 @@ out:
return (err < 0) ? err : 0;
}
+static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt->endpoint[0].desc.wMaxPacketSize =
+ cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
+
+ return 0;
+}
+
+static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
+{
+ int ret, packet_size, min_packet_size;
+ struct usb_host_interface *alt;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
+ if (packet_size <= min_packet_size)
+ return -EIO;
+
+ packet_size -= 100;
+ if (packet_size < min_packet_size)
+ packet_size = min_packet_size;
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret);
+
+ return ret;
+}
+
static void stv06xx_stopN(struct gspca_dev *gspca_dev)
{
int err;
@@ -349,7 +400,7 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
}
/* First byte seem to be 02=data 2nd byte is unknown??? */
- if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200)
+ if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200)
goto frame_data;
switch (id) {
@@ -462,6 +513,8 @@ static const struct sd_desc sd_desc = {
.start = stv06xx_start,
.stopN = stv06xx_stopN,
.pkt_scan = stv06xx_pkt_scan,
+ .isoc_init = stv06xx_isoc_init,
+ .isoc_nego = stv06xx_isoc_nego,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index cf3d0ccc1121..b538dce96f78 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -146,6 +146,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
.i2c_addr = (0x55 << 1),
.i2c_len = 1,
+ /* FIXME (see if we can lower min_packet_size, needs testing, and also
+ adjusting framerate when the bandwidth gets lower) */
+ .min_packet_size = { 847 },
+ .max_packet_size = { 847 },
+
.init = hdcs_init,
.probe = hdcs_probe_1x00,
.start = hdcs_start,
@@ -160,6 +165,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
.i2c_addr = (0x55 << 1),
.i2c_len = 1,
+ /* FIXME (see if we can lower min_packet_size, needs testing, and also
+ adjusting framerate when the bandwidthm gets lower) */
+ .min_packet_size = { 847 },
+ .max_packet_size = { 847 },
+
.init = hdcs_init,
.probe = hdcs_probe_1020,
.start = hdcs_start,
@@ -177,7 +187,6 @@ static const u16 stv_bridge_init[][2] = {
{STV_REG04, 0x07},
{STV_SCAN_RATE, 0x20},
- {STV_ISO_SIZE_L, 847},
{STV_Y_CTRL, 0x01},
{STV_X_CTRL, 0x0a}
};
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index 285221e6b390..ac47b4c94388 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -208,11 +208,24 @@ static int pb0100_probe(struct sd *sd)
static int pb0100_start(struct sd *sd)
{
- int err;
+ int err, packet_size, max_packet_size;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
struct cam *cam = &sd->gspca_dev.cam;
s32 *sensor_settings = sd->sensor_priv;
u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+
+ /* If we don't have enough bandwidth use a lower framerate */
+ max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode];
+ if (packet_size < max_packet_size)
+ stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
+ else
+ stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1));
+
/* Setup sensor window */
if (mode & PB0100_CROP_TO_VGA) {
stv06xx_write_sensor(sd, PB_RSTART, 30);
@@ -328,9 +341,6 @@ static int pb0100_init(struct sd *sd)
stv06xx_write_bridge(sd, STV_REG03, 0x45);
stv06xx_write_bridge(sd, STV_REG04, 0x07);
- /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
- stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
-
/* Scan/timing for the sensor */
stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
stv06xx_write_sensor(sd, PB_CFILLIN, 14);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
index 4de4fa5ebc57..757de246dc75 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -138,6 +138,9 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
.i2c_addr = 0xba,
.i2c_len = 2,
+ .min_packet_size = { 635, 847 },
+ .max_packet_size = { 847, 923 },
+
.init = pb0100_init,
.probe = pb0100_probe,
.start = pb0100_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index 934b9cebc1ab..fb229d8ded58 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -53,6 +53,10 @@ struct stv06xx_sensor {
/* length of an i2c word */
u8 i2c_len;
+ /* Isoc packet size (per mode) */
+ int min_packet_size[4];
+ int max_packet_size[4];
+
/* Probes if the sensor is connected */
int (*probe)(struct sd *sd);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index 3af53264a364..8a456de4970a 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -28,6 +28,20 @@
#include "stv06xx_st6422.h"
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ GAIN,
+ EXPOSURE,
+ NCTRLS /* number of controls */
+};
+
+/* sensor settings */
+struct st6422_settings {
+ struct gspca_ctrl ctrls[NCTRLS];
+};
+
static struct v4l2_pix_format st6422_mode[] = {
/* Note we actually get 124 lines of data, of which we skip the 4st
4 as they are garbage */
@@ -57,9 +71,14 @@ static struct v4l2_pix_format st6422_mode[] = {
},
};
-static const struct ctrl st6422_ctrl[] = {
-#define BRIGHTNESS_IDX 0
- {
+/* V4L2 controls supported by the driver */
+static void st6422_set_brightness(struct gspca_dev *gspca_dev);
+static void st6422_set_contrast(struct gspca_dev *gspca_dev);
+static void st6422_set_gain(struct gspca_dev *gspca_dev);
+static void st6422_set_exposure(struct gspca_dev *gspca_dev);
+
+static const struct ctrl st6422_ctrl[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -69,11 +88,9 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 3
},
- .set = st6422_set_brightness,
- .get = st6422_get_brightness
+ .set_control = st6422_set_brightness
},
-#define CONTRAST_IDX 1
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -83,11 +100,9 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 11
},
- .set = st6422_set_contrast,
- .get = st6422_get_contrast
+ .set_control = st6422_set_contrast
},
-#define GAIN_IDX 2
- {
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -97,49 +112,43 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 64
},
- .set = st6422_set_gain,
- .get = st6422_get_gain
+ .set_control = st6422_set_gain
},
-#define EXPOSURE_IDX 3
- {
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 0,
- .maximum = 1023,
+#define EXPOSURE_MAX 1023
+ .maximum = EXPOSURE_MAX,
.step = 1,
.default_value = 256
},
- .set = st6422_set_exposure,
- .get = st6422_get_exposure
+ .set_control = st6422_set_exposure
},
};
static int st6422_probe(struct sd *sd)
{
- int i;
- s32 *sensor_settings;
+ struct st6422_settings *sensor_settings;
if (sd->bridge != BRIDGE_ST6422)
return -ENODEV;
info("st6422 sensor detected");
- sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32),
- GFP_KERNEL);
+ sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = st6422_mode;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
+ sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;
sd->desc.ctrls = st6422_ctrl;
sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
sd->sensor_priv = sensor_settings;
- for (i = 0; i < sd->desc.nctrls; i++)
- sensor_settings[i] = st6422_ctrl[i].qctrl.default_value;
-
return 0;
}
@@ -151,11 +160,11 @@ static int st6422_init(struct sd *sd)
{ STV_ISO_ENABLE, 0x00 }, /* disable capture */
{ 0x1436, 0x00 },
{ 0x1432, 0x03 }, /* 0x00-0x1F brightness */
- { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */
+ { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */
{ 0x0509, 0x38 }, /* R */
{ 0x050a, 0x38 }, /* G */
{ 0x050b, 0x38 }, /* B */
- { 0x050c, 0x2A },
+ { 0x050c, 0x2a },
{ 0x050d, 0x01 },
@@ -213,7 +222,6 @@ static int st6422_init(struct sd *sd)
{ 0x150e, 0x8e },
{ 0x150f, 0x37 },
{ 0x15c0, 0x00 },
- { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */
{ 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */
@@ -235,91 +243,92 @@ static void st6422_disconnect(struct sd *sd)
kfree(sd->sensor_priv);
}
-static int st6422_start(struct sd *sd)
+static int setbrightness(struct sd *sd)
{
- int err, packet_size;
- struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
- struct usb_host_interface *alt;
- struct usb_interface *intf;
-
- intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
- alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
- if (!alt) {
- err("Couldn't get altsetting");
- return -EIO;
- }
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
- packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
- err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
- if (err < 0)
- return err;
+ /* val goes from 0 -> 31 */
+ return stv06xx_write_bridge(sd, 0x1432,
+ sensor_settings->ctrls[BRIGHTNESS].val);
+}
- if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
- err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
- else
- err = stv06xx_write_bridge(sd, 0x1505, 0x02);
- if (err < 0)
- return err;
+static int setcontrast(struct sd *sd)
+{
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+
+ /* Val goes from 0 -> 15 */
+ return stv06xx_write_bridge(sd, 0x143a,
+ sensor_settings->ctrls[CONTRAST].val | 0xf0);
+}
+
+static int setgain(struct sd *sd)
+{
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+ u8 gain;
+ int err;
+
+ gain = sensor_settings->ctrls[GAIN].val;
- err = st6422_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
+ /* Set red, green, blue, gain */
+ err = stv06xx_write_bridge(sd, 0x0509, gain);
if (err < 0)
return err;
- err = st6422_set_contrast(&sd->gspca_dev,
- sensor_settings[CONTRAST_IDX]);
+ err = stv06xx_write_bridge(sd, 0x050a, gain);
if (err < 0)
return err;
- err = st6422_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
+ err = stv06xx_write_bridge(sd, 0x050b, gain);
if (err < 0)
return err;
- err = st6422_set_gain(&sd->gspca_dev,
- sensor_settings[GAIN_IDX]);
+ /* 2 mystery writes */
+ err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
if (err < 0)
return err;
- PDEBUG(D_STREAM, "Starting stream");
-
- return 0;
+ return stv06xx_write_bridge(sd, 0x050d, 0x01);
}
-static int st6422_stop(struct sd *sd)
+static int setexposure(struct sd *sd)
{
- PDEBUG(D_STREAM, "Halting stream");
-
- return 0;
-}
-
-static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BRIGHTNESS_IDX];
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+ u16 expo;
+ int err;
- PDEBUG(D_V4L2, "Read brightness %d", *val);
+ expo = sensor_settings->ctrls[EXPOSURE].val;
+ err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);
+ if (err < 0)
+ return err;
- return 0;
+ return stv06xx_write_bridge(sd, 0x143e, expo >> 8);
}
-static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int st6422_start(struct sd *sd)
{
int err;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct cam *cam = &sd->gspca_dev.cam;
- sensor_settings[BRIGHTNESS_IDX] = val;
+ if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
+ err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
+ else
+ err = stv06xx_write_bridge(sd, 0x1505, 0x02);
+ if (err < 0)
+ return err;
- if (!gspca_dev->streaming)
- return 0;
+ err = setbrightness(sd);
+ if (err < 0)
+ return err;
- /* val goes from 0 -> 31 */
- PDEBUG(D_V4L2, "Set brightness to %d", val);
- err = stv06xx_write_bridge(sd, 0x1432, val);
+ err = setcontrast(sd);
+ if (err < 0)
+ return err;
+
+ err = setexposure(sd);
+ if (err < 0)
+ return err;
+
+ err = setgain(sd);
if (err < 0)
return err;
@@ -328,125 +337,65 @@ static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
return (err < 0) ? err : 0;
}
-static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val)
+static int st6422_stop(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[CONTRAST_IDX];
-
- PDEBUG(D_V4L2, "Read contrast %d", *val);
+ PDEBUG(D_STREAM, "Halting stream");
return 0;
}
-static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_brightness(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[CONTRAST_IDX] = val;
- if (!gspca_dev->streaming)
- return 0;
-
- /* Val goes from 0 -> 15 */
- PDEBUG(D_V4L2, "Set contrast to %d\n", val);
- err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val);
- if (err < 0)
- return err;
+ err = setbrightness(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
-}
-
-static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
-
- PDEBUG(D_V4L2, "Read gain %d", *val);
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return 0;
+ gspca_dev->usb_err = err;
}
-static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_contrast(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[GAIN_IDX] = val;
-
- if (!gspca_dev->streaming)
- return 0;
-
- PDEBUG(D_V4L2, "Set gain to %d", val);
- /* Set red, green, blue, gain */
- err = stv06xx_write_bridge(sd, 0x0509, val);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050a, val);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050b, val);
- if (err < 0)
- return err;
-
- /* 2 mystery writes */
- err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050d, 0x01);
- if (err < 0)
- return err;
+ err = setcontrast(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+
+ gspca_dev->usb_err = err;
}
-static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static void st6422_set_gain(struct gspca_dev *gspca_dev)
{
+ int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- *val = sensor_settings[EXPOSURE_IDX];
+ err = setgain(sd);
- PDEBUG(D_V4L2, "Read exposure %d", *val);
+ /* commit settings */
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return 0;
+ gspca_dev->usb_err = err;
}
-static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_exposure(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[EXPOSURE_IDX] = val;
- if (!gspca_dev->streaming)
- return 0;
-
- PDEBUG(D_V4L2, "Set exposure to %d\n", val);
- err = stv06xx_write_bridge(sd, 0x143d, val & 0xff);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x143e, val >> 8);
- if (err < 0)
- return err;
+ err = setexposure(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+
+ gspca_dev->usb_err = err;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
index b2d45fe50522..d7498e06432b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -37,18 +37,11 @@ static int st6422_init(struct sd *sd);
static int st6422_stop(struct sd *sd);
static void st6422_disconnect(struct sd *sd);
-/* V4L2 controls supported by the driver */
-static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-
const struct stv06xx_sensor stv06xx_sensor_st6422 = {
.name = "ST6422",
+ /* No known way to lower framerate in case of less bandwidth */
+ .min_packet_size = { 300, 847 },
+ .max_packet_size = { 300, 847 },
.init = st6422_init,
.probe = st6422_probe,
.start = st6422_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index b3b5508473bc..7fe3587f5f71 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -197,6 +197,10 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
.i2c_flush = 5,
.i2c_addr = 0x20,
.i2c_len = 1,
+ /* FIXME (see if we can lower packet_size-s, needs testing, and also
+ adjusting framerate when the bandwidth gets lower) */
+ .min_packet_size = { 1023 },
+ .max_packet_size = { 1023 },
.init = vv6410_init,
.probe = vv6410_probe,
.start = vv6410_start,
@@ -220,10 +224,6 @@ static const u8 x1536[] = { /* 0x1536 - 0x153b */
0x02, 0x00, 0x60, 0x01, 0x20, 0x01
};
-static const u8 x15c1[] = { /* 0x15c1 - 0x15c2 */
- 0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */
-};
-
static const struct stv_init stv_bridge_init[] = {
/* This reg is written twice. Some kind of reset? */
{NULL, 0x1620, 0x80},
@@ -232,7 +232,6 @@ static const struct stv_init stv_bridge_init[] = {
{NULL, 0x1423, 0x04},
{x1500, 0x1500, ARRAY_SIZE(x1500)},
{x1536, 0x1536, ARRAY_SIZE(x1536)},
- {x15c1, 0x15c1, ARRAY_SIZE(x15c1)}
};
static const u8 vv6410_sensor_init[][2] = {
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index b45f4d0f3997..8f0c33116e0d 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -487,7 +487,7 @@ static const u8 gamma_table[GAMMA_MAX][17] = {
{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
0xff},
- {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
+ {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
0xff},
{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index d9e3c6050781..38c22f0a4263 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -132,7 +132,7 @@ static const struct v4l2_pix_format sif_mode[] = {
#define R36_PID 0x36
#define R37_PIDH 0x37
#define R39_Test1 0x39 /* GPIO */
-#define R3B_Test3 0x3B /* GPIO */
+#define R3B_Test3 0x3b /* GPIO */
#define R83_AD_IDH 0x83
#define R91_AD_SLOPEREG 0x91
#define R94_AD_BITCONTROL 0x94
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 38a6efe1a5f9..9b2ae1b6cc75 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -47,24 +47,29 @@ struct sd {
u8 image_offset;
u8 bridge;
-#define BRIDGE_VC0321 0
-#define BRIDGE_VC0323 1
u8 sensor;
-#define SENSOR_HV7131R 0
-#define SENSOR_MI0360 1
-#define SENSOR_MI1310_SOC 2
-#define SENSOR_MI1320 3
-#define SENSOR_MI1320_SOC 4
-#define SENSOR_OV7660 5
-#define SENSOR_OV7670 6
-#define SENSOR_PO1200 7
-#define SENSOR_PO3130NC 8
-#define SENSOR_POxxxx 9
u8 flags;
#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
#define FL_HFLIP 0x02 /* mirrored by default */
#define FL_VFLIP 0x04 /* vertical flipped by default */
};
+enum bridges {
+ BRIDGE_VC0321,
+ BRIDGE_VC0323,
+};
+enum sensors {
+ SENSOR_HV7131R,
+ SENSOR_MI0360,
+ SENSOR_MI1310_SOC,
+ SENSOR_MI1320,
+ SENSOR_MI1320_SOC,
+ SENSOR_OV7660,
+ SENSOR_OV7670,
+ SENSOR_PO1200,
+ SENSOR_PO3130NC,
+ SENSOR_POxxxx,
+ NSENSORS
+};
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -260,56 +265,56 @@ static const struct ctrl sd_ctrls[] = {
};
/* table of the disabled controls */
-static u32 ctrl_dis[] = {
-/* SENSOR_HV7131R 0 */
+static u32 ctrl_dis[NSENSORS] = {
+ [SENSOR_HV7131R] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
| (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_MI0360 1 */
+ [SENSOR_MI0360] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
| (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_MI1310_SOC 2 */
+ [SENSOR_MI1310_SOC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_MI1320 3 */
+ [SENSOR_MI1320] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_MI1320_SOC 4 */
+ [SENSOR_MI1320_SOC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_OV7660 5 */
+ [SENSOR_OV7660] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_OV7670 6 */
+ [SENSOR_OV7670] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_PO1200 7 */
+ [SENSOR_PO1200] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << LIGHTFREQ_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_PO3130NC 8 */
+ [SENSOR_PO3130NC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
| (1 << SHARPNESS_IDX)
| (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
| (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
-/* SENSOR_POxxxx 9 */
+ [SENSOR_POxxxx] =
(1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX),
};
@@ -3420,17 +3425,18 @@ static int sd_init(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
int sensor;
- static u8 npkt[] = { /* number of packets per ISOC message */
- 64, /* HV7131R 0 */
- 32, /* MI0360 1 */
- 32, /* MI1310_SOC 2 */
- 64, /* MI1320 3 */
- 128, /* MI1320_SOC 4 */
- 32, /* OV7660 5 */
- 64, /* OV7670 6 */
- 128, /* PO1200 7 */
- 128, /* PO3130NC 8 */
- 128, /* POxxxx 9 */
+ /* number of packets per ISOC message */
+ static u8 npkt[NSENSORS] = {
+ [SENSOR_HV7131R] = 64,
+ [SENSOR_MI0360] = 32,
+ [SENSOR_MI1310_SOC] = 32,
+ [SENSOR_MI1320] = 64,
+ [SENSOR_MI1320_SOC] = 128,
+ [SENSOR_OV7660] = 32,
+ [SENSOR_OV7670] = 64,
+ [SENSOR_PO1200] = 128,
+ [SENSOR_PO3130NC] = 128,
+ [SENSOR_POxxxx] = 128,
};
if (sd->sensor != SENSOR_POxxxx)
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c
index 4066ac8c45a0..4a9e622e5e1b 100644
--- a/drivers/media/video/gspca/w996Xcf.c
+++ b/drivers/media/video/gspca/w996Xcf.c
@@ -59,18 +59,21 @@ static const struct v4l2_pix_format w9968cf_vga_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG},
};
-static int reg_w(struct sd *sd, __u16 index, __u16 value);
+static void reg_w(struct sd *sd, u16 index, u16 value);
/*--------------------------------------------------------------------------
Write 64-bit data to the fast serial bus registers.
Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct sd *sd, u16* data)
+static void w9968cf_write_fsb(struct sd *sd, u16* data)
{
struct usb_device *udev = sd->gspca_dev.dev;
u16 value;
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
value = *data++;
memcpy(sd->gspca_dev.usb_buf, data, 6);
@@ -79,20 +82,21 @@ static int w9968cf_write_fsb(struct sd *sd, u16* data)
value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
if (ret < 0) {
err("Write FSB registers failed (%d)", ret);
- return ret;
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
/*--------------------------------------------------------------------------
Write data to the serial bus control register.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct sd *sd, u16 value)
+static void w9968cf_write_sb(struct sd *sd, u16 value)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
/* We don't use reg_w here, as that would cause all writes when
bitbanging i2c to be logged, making the logs impossible to read */
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -105,10 +109,8 @@ static int w9968cf_write_sb(struct sd *sd, u16 value)
if (ret < 0) {
err("Write SB reg [01] %04x failed", value);
- return ret;
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
/*--------------------------------------------------------------------------
@@ -119,6 +121,9 @@ static int w9968cf_read_sb(struct sd *sd)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
/* We don't use reg_r here, as the w9968cf is special and has 16
bit registers instead of 8 bit */
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -126,11 +131,13 @@ static int w9968cf_read_sb(struct sd *sd)
1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0x01, sd->gspca_dev.usb_buf, 2, 500);
- if (ret >= 0)
+ if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0] |
(sd->gspca_dev.usb_buf[1] << 8);
- else
+ } else {
err("Read SB reg [01] failed");
+ sd->gspca_dev.usb_err = ret;
+ }
udelay(W9968CF_I2C_BUS_DELAY);
@@ -142,22 +149,20 @@ static int w9968cf_read_sb(struct sd *sd)
This function is called by w9968cf_start_transfer().
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct sd *sd)
+static void w9968cf_upload_quantizationtables(struct sd *sd)
{
u16 a, b;
- int ret = 0, i, j;
+ int i, j;
- ret += reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
+ reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
for (i = 0, j = 0; i < 32; i++, j += 2) {
- a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
- b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
- ret += reg_w(sd, 0x40+i, a);
- ret += reg_w(sd, 0x60+i, b);
+ a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8);
+ b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j + 1]) << 8);
+ reg_w(sd, 0x40 + i, a);
+ reg_w(sd, 0x60 + i, b);
}
- ret += reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
-
- return ret;
+ reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
}
/****************************************************************************
@@ -168,50 +173,39 @@ static int w9968cf_upload_quantizationtables(struct sd *sd)
* i2c_adap_read_byte() *
****************************************************************************/
-static int w9968cf_smbus_start(struct sd *sd)
+static void w9968cf_smbus_start(struct sd *sd)
{
- int ret = 0;
-
- ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+ w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
}
-static int w9968cf_smbus_stop(struct sd *sd)
+static void w9968cf_smbus_stop(struct sd *sd)
{
- int ret = 0;
-
- ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+ w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
}
-static int w9968cf_smbus_write_byte(struct sd *sd, u8 v)
+static void w9968cf_smbus_write_byte(struct sd *sd, u8 v)
{
u8 bit;
- int ret = 0, sda;
+ int sda;
for (bit = 0 ; bit < 8 ; bit++) {
sda = (v & 0x80) ? 2 : 0;
v <<= 1;
/* SDE=1, SDA=sda, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x10 | sda);
+ w9968cf_write_sb(sd, 0x10 | sda);
/* SDE=1, SDA=sda, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x11 | sda);
+ w9968cf_write_sb(sd, 0x11 | sda);
/* SDE=1, SDA=sda, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x10 | sda);
+ w9968cf_write_sb(sd, 0x10 | sda);
}
-
- return ret;
}
-static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
+static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v)
{
u8 bit;
- int ret = 0;
/* No need to ensure SDA is high as we are always called after
read_ack which ends with SDA high */
@@ -219,51 +213,40 @@ static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
for (bit = 0 ; bit < 8 ; bit++) {
*v <<= 1;
/* SDE=1, SDA=1, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0013);
+ w9968cf_write_sb(sd, 0x0013);
*v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0;
/* SDE=1, SDA=1, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0012);
+ w9968cf_write_sb(sd, 0x0012);
}
-
- return ret;
}
-static int w9968cf_smbus_write_nack(struct sd *sd)
+static void w9968cf_smbus_write_nack(struct sd *sd)
{
- int ret = 0;
-
/* No need to ensure SDA is high as we are always called after
read_byte which ends with SDA high */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
}
-static int w9968cf_smbus_read_ack(struct sd *sd)
+static void w9968cf_smbus_read_ack(struct sd *sd)
{
- int ret = 0, sda;
+ int sda;
/* Ensure SDA is high before raising clock to avoid a spurious stop */
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
sda = w9968cf_read_sb(sd);
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- if (sda < 0)
- ret += sda;
- else if (sda & 0x08) {
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+ if (sda >= 0 && (sda & 0x08)) {
PDEBUG(D_USBI, "Did not receive i2c ACK");
- ret += -1;
+ sd->gspca_dev.usb_err = -EIO;
}
-
- return ret;
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
+static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
{
u16* data = (u16 *)sd->gspca_dev.usb_buf;
- int ret = 0;
data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0;
@@ -276,7 +259,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0);
data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0);
data[0] |= (reg & 0x40) ? 0x0540 : 0x0;
@@ -290,7 +273,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (reg & 0x01) ? 0x5400 : 0x0;
data[3] = 0x001d;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
data[0] |= (value & 0x40) ? 0x0540 : 0x0;
@@ -304,14 +287,9 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (value & 0x01) ? 0x5400 : 0x0;
data[3] = 0xfe1d;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
- if (!ret)
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
- else
- PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
-
- return ret;
+ PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
@@ -321,28 +299,28 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
u8 value;
/* Fast serial bus data control disable */
- ret += w9968cf_write_sb(sd, 0x0013); /* don't change ! */
-
- ret += w9968cf_smbus_start(sd);
- ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_write_byte(sd, reg);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_stop(sd);
- ret += w9968cf_smbus_start(sd);
- ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_read_byte(sd, &value);
+ w9968cf_write_sb(sd, 0x0013); /* don't change ! */
+
+ w9968cf_smbus_start(sd);
+ w9968cf_smbus_write_byte(sd, sd->sensor_addr);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_write_byte(sd, reg);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_stop(sd);
+ w9968cf_smbus_start(sd);
+ w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_read_byte(sd, &value);
/* signal we don't want to read anymore, the v4l1 driver used to
send an ack here which is very wrong! (and then fixed
the issues this gave by retrying reads) */
- ret += w9968cf_smbus_write_nack(sd);
- ret += w9968cf_smbus_stop(sd);
+ w9968cf_smbus_write_nack(sd);
+ w9968cf_smbus_stop(sd);
/* Fast serial bus data control re-enable */
- ret += w9968cf_write_sb(sd, 0x0030);
+ w9968cf_write_sb(sd, 0x0030);
- if (!ret) {
+ if (sd->gspca_dev.usb_err >= 0) {
ret = value;
PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
} else
@@ -351,79 +329,68 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
return ret;
}
-
/*--------------------------------------------------------------------------
Turn on the LED on some webcams. A beep should be heard too.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_configure(struct sd *sd)
+static void w9968cf_configure(struct sd *sd)
{
- int ret = 0;
-
- ret += reg_w(sd, 0x00, 0xff00); /* power-down */
- ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
- ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
- ret += reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
- ret += reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
- ret += reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
- ret += reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
-
- if (ret)
- PDEBUG(D_ERR, "Couldn't turn on the LED");
+ reg_w(sd, 0x00, 0xff00); /* power-down */
+ reg_w(sd, 0x00, 0xbf17); /* reset everything */
+ reg_w(sd, 0x00, 0xbf10); /* normal operation */
+ reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
+ reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
+ reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
+ reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
sd->stopped = 1;
-
- return ret;
}
-static int w9968cf_init(struct sd *sd)
+static void w9968cf_init(struct sd *sd)
{
- int ret = 0;
unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2),
y0 = 0x0000,
- u0 = y0 + hw_bufsize/2,
- v0 = u0 + hw_bufsize/4,
- y1 = v0 + hw_bufsize/4,
- u1 = y1 + hw_bufsize/2,
- v1 = u1 + hw_bufsize/4;
-
- ret += reg_w(sd, 0x00, 0xff00); /* power off */
- ret += reg_w(sd, 0x00, 0xbf10); /* power on */
-
- ret += reg_w(sd, 0x03, 0x405d); /* DRAM timings */
- ret += reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
-
- ret += reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
- ret += reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
- ret += reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
- ret += reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
- ret += reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
- ret += reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
-
- ret += reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
- ret += reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
- ret += reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
- ret += reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
- ret += reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
- ret += reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
-
- ret += reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
- ret += reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
-
- ret += reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
- ret += reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
-
- ret += reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
- ret += reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
- ret += reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
- ret += reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
-
- return ret;
+ u0 = y0 + hw_bufsize / 2,
+ v0 = u0 + hw_bufsize / 4,
+ y1 = v0 + hw_bufsize / 4,
+ u1 = y1 + hw_bufsize / 2,
+ v1 = u1 + hw_bufsize / 4;
+
+ reg_w(sd, 0x00, 0xff00); /* power off */
+ reg_w(sd, 0x00, 0xbf10); /* power on */
+
+ reg_w(sd, 0x03, 0x405d); /* DRAM timings */
+ reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
+
+ reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
+ reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
+ reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
+ reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
+ reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
+ reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
+
+ reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
+ reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
+ reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
+ reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
+ reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
+ reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
+
+ reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
+ reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
+
+ reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
+ reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
+
+ reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
+ reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
+ reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
+ reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
}
-static int w9968cf_set_crop_window(struct sd *sd)
+static void w9968cf_set_crop_window(struct sd *sd)
{
- int ret = 0, start_cropx, start_cropy, x, y, fw, fh, cw, ch,
+ int start_cropx, start_cropy, x, y, fw, fh, cw, ch,
max_width, max_height;
if (sd->sif) {
@@ -456,8 +423,8 @@ static int w9968cf_set_crop_window(struct sd *sd)
fw = SC(sd->gspca_dev.width) / max_width;
fh = SC(sd->gspca_dev.height) / max_height;
- cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width)/fh;
- ch = (fw >= fh) ? SC(sd->gspca_dev.height)/fw : max_height;
+ cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh;
+ ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height;
sd->sensor_width = max_width;
sd->sensor_height = max_height;
@@ -465,42 +432,40 @@ static int w9968cf_set_crop_window(struct sd *sd)
x = (max_width - cw) / 2;
y = (max_height - ch) / 2;
- ret += reg_w(sd, 0x10, start_cropx + x);
- ret += reg_w(sd, 0x11, start_cropy + y);
- ret += reg_w(sd, 0x12, start_cropx + x + cw);
- ret += reg_w(sd, 0x13, start_cropy + y + ch);
-
- return ret;
+ reg_w(sd, 0x10, start_cropx + x);
+ reg_w(sd, 0x11, start_cropy + y);
+ reg_w(sd, 0x12, start_cropx + x + cw);
+ reg_w(sd, 0x13, start_cropy + y + ch);
}
-static int w9968cf_mode_init_regs(struct sd *sd)
+static void w9968cf_mode_init_regs(struct sd *sd)
{
- int ret = 0, val, vs_polarity, hs_polarity;
+ int val, vs_polarity, hs_polarity;
- ret += w9968cf_set_crop_window(sd);
+ w9968cf_set_crop_window(sd);
- ret += reg_w(sd, 0x14, sd->gspca_dev.width);
- ret += reg_w(sd, 0x15, sd->gspca_dev.height);
+ reg_w(sd, 0x14, sd->gspca_dev.width);
+ reg_w(sd, 0x15, sd->gspca_dev.height);
/* JPEG width & height */
- ret += reg_w(sd, 0x30, sd->gspca_dev.width);
- ret += reg_w(sd, 0x31, sd->gspca_dev.height);
+ reg_w(sd, 0x30, sd->gspca_dev.width);
+ reg_w(sd, 0x31, sd->gspca_dev.height);
/* Y & UV frame buffer strides (in WORD) */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
- ret += reg_w(sd, 0x2c, sd->gspca_dev.width/2);
- ret += reg_w(sd, 0x2d, sd->gspca_dev.width/4);
+ reg_w(sd, 0x2c, sd->gspca_dev.width / 2);
+ reg_w(sd, 0x2d, sd->gspca_dev.width / 4);
} else
- ret += reg_w(sd, 0x2c, sd->gspca_dev.width);
+ reg_w(sd, 0x2c, sd->gspca_dev.width);
- ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
- ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
+ reg_w(sd, 0x00, 0xbf17); /* reset everything */
+ reg_w(sd, 0x00, 0xbf10); /* normal operation */
/* Transfer size in WORDS (for UYVY format only) */
val = sd->gspca_dev.width * sd->gspca_dev.height;
- ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */
- ret += reg_w(sd, 0x3e, val >> 16); /* high bits */
+ reg_w(sd, 0x3d, val & 0xffff); /* low bits */
+ reg_w(sd, 0x3e, val >> 16); /* high bits */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
@@ -508,7 +473,7 @@ static int w9968cf_mode_init_regs(struct sd *sd)
jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
sd->gspca_dev.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
- ret += w9968cf_upload_quantizationtables(sd);
+ w9968cf_upload_quantizationtables(sd);
}
/* Video Capture Control Register */
@@ -540,19 +505,15 @@ static int w9968cf_mode_init_regs(struct sd *sd)
val |= 0x8000; /* capt. enable */
- ret += reg_w(sd, 0x16, val);
+ reg_w(sd, 0x16, val);
sd->gspca_dev.empty_packet = 0;
-
- return ret;
}
static void w9968cf_stop0(struct sd *sd)
{
- if (sd->gspca_dev.present) {
- reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
- reg_w(sd, 0x16, 0x0000); /* stop video capture */
- }
+ reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
+ reg_w(sd, 0x16, 0x0000); /* stop video capture */
}
/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
index 8715577bc2d8..5b5039a02031 100644
--- a/drivers/media/video/gspca/xirlink_cit.c
+++ b/drivers/media/video/gspca/xirlink_cit.c
@@ -29,6 +29,7 @@
#define MODULE_NAME "xirlink-cit"
+#include <linux/input.h>
#include "gspca.h"
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
@@ -58,6 +59,7 @@ struct sd {
#define CIT_MODEL4 4
#define CIT_IBM_NETCAM_PRO 5
u8 input_index;
+ u8 button_state;
u8 stop_on_control_change;
u8 sof_read;
u8 sof_len;
@@ -185,60 +187,60 @@ static const struct ctrl sd_ctrls[] = {
static const struct v4l2_pix_format cif_yuv_mode[] = {
{176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 176,
- .sizeimage = 176 * 144 * 3 / 2,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{352, 288, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 352,
- .sizeimage = 352 * 288 * 3 / 2,
+ .sizeimage = 352 * 288 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
};
static const struct v4l2_pix_format vga_yuv_mode[] = {
{160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 2,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 320,
- .sizeimage = 320 * 240 * 3 / 2,
+ .sizeimage = 320 * 240 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 640,
- .sizeimage = 640 * 480 * 3 / 2,
+ .sizeimage = 640 * 480 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
};
static const struct v4l2_pix_format model0_mode[] = {
{160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 2,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 176,
- .sizeimage = 176 * 144 * 3 / 2,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 320,
- .sizeimage = 320 * 240 * 3 / 2,
+ .sizeimage = 320 * 240 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
};
static const struct v4l2_pix_format model2_mode[] = {
{160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 2,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
.bytesperline = 176,
- .sizeimage = 176 * 144 * 3 / 2,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
.bytesperline = 320,
- .sizeimage = 320 * 240,
+ .sizeimage = 320 * 240 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
{352, 288, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
.bytesperline = 352,
- .sizeimage = 352 * 288,
+ .sizeimage = 352 * 288 + 4,
.colorspace = V4L2_COLORSPACE_SRGB},
};
@@ -804,7 +806,7 @@ static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index)
return 0;
}
-static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index)
+static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose)
{
struct usb_device *udev = gspca_dev->dev;
__u8 *buf = gspca_dev->usb_buf;
@@ -819,10 +821,8 @@ static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index)
return res;
}
- PDEBUG(D_PROBE,
- "Register %04x value: %02x %02x %02x %02x %02x %02x %02x %02x",
- index,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ if (verbose)
+ PDEBUG(D_PROBE, "Register %04x value: %02x", index, buf[0]);
return 0;
}
@@ -907,7 +907,7 @@ static void cit_Packet_Format1(struct gspca_dev *gspca_dev, u16 fkey, u16 val)
cit_send_x_00_05(gspca_dev, 0x0089);
cit_send_x_00(gspca_dev, fkey);
cit_send_00_04_06(gspca_dev);
- cit_read_reg(gspca_dev, 0x0126);
+ cit_read_reg(gspca_dev, 0x0126, 0);
cit_send_FF_04_02(gspca_dev);
}
@@ -1074,12 +1074,12 @@ static int cit_init_model0(struct gspca_dev *gspca_dev)
static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev)
{
- cit_read_reg(gspca_dev, 0x128);
+ cit_read_reg(gspca_dev, 0x128, 1);
cit_write_reg(gspca_dev, 0x0003, 0x0133);
cit_write_reg(gspca_dev, 0x0000, 0x0117);
cit_write_reg(gspca_dev, 0x0008, 0x0123);
cit_write_reg(gspca_dev, 0x0000, 0x0100);
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x0060, 0x0116);
cit_write_reg(gspca_dev, 0x0002, 0x0112);
cit_write_reg(gspca_dev, 0x0000, 0x0133);
@@ -1098,7 +1098,7 @@ static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x00ff, 0x0130);
cit_write_reg(gspca_dev, 0xcd41, 0x0124);
cit_write_reg(gspca_dev, 0xfffa, 0x0124);
- cit_read_reg(gspca_dev, 0x0126);
+ cit_read_reg(gspca_dev, 0x0126, 1);
cit_model3_Packet1(gspca_dev, 0x0000, 0x0000);
cit_model3_Packet1(gspca_dev, 0x0000, 0x0001);
@@ -1557,18 +1557,20 @@ static int cit_restart_stream(struct gspca_dev *gspca_dev)
switch (sd->model) {
case CIT_MODEL0:
case CIT_MODEL1:
- case CIT_MODEL3:
- case CIT_IBM_NETCAM_PRO:
cit_write_reg(gspca_dev, 0x0001, 0x0114);
/* Fall through */
case CIT_MODEL2:
case CIT_MODEL4:
cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
- /* This happens repeatedly while streaming with the ibm netcam
- pro and the ibmcam driver did it for model3 after changing
- settings, but it does not seem to have any effect. */
- /* cit_write_reg(gspca_dev, 0x0001, 0x0113); */
+ break;
+ case CIT_MODEL3:
+ case CIT_IBM_NETCAM_PRO:
+ cit_write_reg(gspca_dev, 0x0001, 0x0114);
+ cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
+ usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+ /* Clear button events from while we were not streaming */
+ cit_write_reg(gspca_dev, 0x0001, 0x0113);
break;
}
@@ -1680,23 +1682,23 @@ static int cit_start_model1(struct gspca_dev *gspca_dev)
if (clock_div < 0)
return clock_div;
- cit_read_reg(gspca_dev, 0x0128);
- cit_read_reg(gspca_dev, 0x0100);
+ cit_read_reg(gspca_dev, 0x0128, 1);
+ cit_read_reg(gspca_dev, 0x0100, 0);
cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
- cit_read_reg(gspca_dev, 0x0100);
+ cit_read_reg(gspca_dev, 0x0100, 0);
cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
- cit_read_reg(gspca_dev, 0x0100);
+ cit_read_reg(gspca_dev, 0x0100, 0);
cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
cit_write_reg(gspca_dev, 0x01, 0x0108);
cit_write_reg(gspca_dev, 0x03, 0x0112);
- cit_read_reg(gspca_dev, 0x0115);
+ cit_read_reg(gspca_dev, 0x0115, 0);
cit_write_reg(gspca_dev, 0x06, 0x0115);
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x44, 0x0116);
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x40, 0x0116);
- cit_read_reg(gspca_dev, 0x0115);
+ cit_read_reg(gspca_dev, 0x0115, 0);
cit_write_reg(gspca_dev, 0x0e, 0x0115);
cit_write_reg(gspca_dev, 0x19, 0x012c);
@@ -1878,7 +1880,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
int clock_div = 0;
cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x0060, 0x0116);
cit_write_reg(gspca_dev, 0x0002, 0x0112);
cit_write_reg(gspca_dev, 0x00bc, 0x012c);
@@ -2070,10 +2072,10 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
/* HDG not in ibmcam driver, added to see if it helps with
auto-detecting between model3 and ibm netcamera pro */
- cit_read_reg(gspca_dev, 0x128);
+ cit_read_reg(gspca_dev, 0x128, 1);
cit_write_reg(gspca_dev, 0x0000, 0x0100);
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x0060, 0x0116);
cit_write_reg(gspca_dev, 0x0002, 0x0112);
cit_write_reg(gspca_dev, 0x0000, 0x0123);
@@ -2083,7 +2085,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x0060, 0x0116);
cit_write_reg(gspca_dev, 0x0002, 0x0115);
cit_write_reg(gspca_dev, 0x0003, 0x0115);
- cit_read_reg(gspca_dev, 0x0115);
+ cit_read_reg(gspca_dev, 0x0115, 0);
cit_write_reg(gspca_dev, 0x000b, 0x0115);
/* TESTME HDG not in ibmcam driver, added to see if it helps with
@@ -2096,7 +2098,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x00ff, 0x0130);
cit_write_reg(gspca_dev, 0xcd41, 0x0124);
cit_write_reg(gspca_dev, 0xfffa, 0x0124);
- cit_read_reg(gspca_dev, 0x0126);
+ cit_read_reg(gspca_dev, 0x0126, 1);
}
cit_model3_Packet1(gspca_dev, 0x000a, 0x0040);
@@ -2293,7 +2295,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
if (rca_input) {
for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
if (rca_initdata[i][0])
- cit_read_reg(gspca_dev, rca_initdata[i][2]);
+ cit_read_reg(gspca_dev, rca_initdata[i][2], 0);
else
cit_write_reg(gspca_dev, rca_initdata[i][1],
rca_initdata[i][2]);
@@ -2712,7 +2714,7 @@ static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
if (rca_input) {
for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
if (rca_initdata[i][0])
- cit_read_reg(gspca_dev, rca_initdata[i][2]);
+ cit_read_reg(gspca_dev, rca_initdata[i][2], 0);
else
cit_write_reg(gspca_dev, rca_initdata[i][1],
rca_initdata[i][2]);
@@ -2769,16 +2771,55 @@ static int sd_start(struct gspca_dev *gspca_dev)
return 0;
}
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ int max_packet_size;
+
+ switch (gspca_dev->width) {
+ case 160:
+ max_packet_size = 450;
+ break;
+ case 176:
+ max_packet_size = 600;
+ break;
+ default:
+ max_packet_size = 1022;
+ break;
+ }
+
+ /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
+
+ return 0;
+}
+
static int sd_isoc_nego(struct gspca_dev *gspca_dev)
{
- int ret, packet_size;
+ int ret, packet_size, min_packet_size;
struct usb_host_interface *alt;
+ switch (gspca_dev->width) {
+ case 160:
+ min_packet_size = 200;
+ break;
+ case 176:
+ min_packet_size = 266;
+ break;
+ default:
+ min_packet_size = 400;
+ break;
+ }
+
alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
- packet_size -= 100;
- if (packet_size < 300)
+ if (packet_size <= min_packet_size)
return -EIO;
+
+ packet_size -= 100;
+ if (packet_size < min_packet_size)
+ packet_size = min_packet_size;
alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
@@ -2796,15 +2837,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_host_interface *alt;
/* We cannot use gspca_dev->present here as that is not set when
sd_init gets called and we get called from sd_init */
if (!gspca_dev->dev)
return;
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
-
switch (sd->model) {
case CIT_MODEL0:
/* HDG windows does this, but it causes the cams autogain to
@@ -2815,7 +2853,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
break;
case CIT_MODEL1:
cit_send_FF_04_02(gspca_dev);
- cit_read_reg(gspca_dev, 0x0100);
+ cit_read_reg(gspca_dev, 0x0100, 0);
cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
break;
case CIT_MODEL2:
@@ -2834,9 +2872,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
case CIT_MODEL3:
cit_write_reg(gspca_dev, 0x0006, 0x012c);
cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
- cit_read_reg(gspca_dev, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
cit_write_reg(gspca_dev, 0x0064, 0x0116);
- cit_read_reg(gspca_dev, 0x0115);
+ cit_read_reg(gspca_dev, 0x0115, 0);
cit_write_reg(gspca_dev, 0x0003, 0x0115);
cit_write_reg(gspca_dev, 0x0008, 0x0123);
cit_write_reg(gspca_dev, 0x0000, 0x0117);
@@ -2859,12 +2897,17 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
restarting the stream after this */
/* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
cit_write_reg(gspca_dev, 0x00c0, 0x0100);
-
- /* Start isoc bandwidth "negotiation" at max isoc bandwith
- next stream start */
- alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(1022);
break;
}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->button_state) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->button_state = 0;
+ }
+#endif
}
static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
@@ -3158,6 +3201,38 @@ static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static void cit_check_button(struct gspca_dev *gspca_dev)
+{
+ int new_button_state;
+ struct sd *sd = (struct sd *)gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL3:
+ case CIT_IBM_NETCAM_PRO:
+ break;
+ default: /* TEST ME unknown if this works on other models too */
+ return;
+ }
+
+ /* Read the button state */
+ cit_read_reg(gspca_dev, 0x0113, 0);
+ new_button_state = !gspca_dev->usb_buf[0];
+
+ /* Tell the cam we've seen the button press, notice that this
+ is a nop (iow the cam keeps reporting pressed) until the
+ button is actually released. */
+ if (new_button_state)
+ cit_write_reg(gspca_dev, 0x01, 0x0113);
+
+ if (sd->button_state != new_button_state) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA,
+ new_button_state);
+ input_sync(gspca_dev->input_dev);
+ sd->button_state = new_button_state;
+ }
+}
+#endif
/* sub-driver description */
static const struct sd_desc sd_desc = {
@@ -3170,6 +3245,10 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .dq_callback = cit_check_button,
+ .other_input = 1,
+#endif
};
static const struct sd_desc sd_desc_isoc_nego = {
@@ -3179,10 +3258,15 @@ static const struct sd_desc sd_desc_isoc_nego = {
.config = sd_config,
.init = sd_init,
.start = sd_start,
+ .isoc_init = sd_isoc_init,
.isoc_nego = sd_isoc_nego,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .dq_callback = cit_check_button,
+ .other_input = 1,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index c7e1970ca284..14b85d483163 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -35,16 +35,23 @@ static int force_sensor = -1;
#define QUANT_VAL 1 /* quantization table */
#include "zc3xx-reg.h"
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ GAMMA,
+ AUTOGAIN,
+ LIGHTFREQ,
+ SHARPNESS,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 brightness;
- u8 contrast;
- u8 gamma;
- u8 autogain;
- u8 lightfreq;
- u8 sharpness;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 quality; /* image quality */
#define QUALITY_MIN 50
#define QUALITY_MAX 80
@@ -64,6 +71,7 @@ enum sensors {
SENSOR_ADCM2700,
SENSOR_CS2102,
SENSOR_CS2102K,
+ SENSOR_GC0303,
SENSOR_GC0305,
SENSOR_HDCS2020b,
SENSOR_HV7131B,
@@ -79,26 +87,17 @@ enum sensors {
SENSOR_PB0330,
SENSOR_PO2030,
SENSOR_TAS5130C,
- SENSOR_TAS5130C_VF0250,
SENSOR_MAX
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
- {
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -106,13 +105,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define BRIGHTNESS_DEF 128
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 128,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setcontrast
},
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -120,13 +117,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define CONTRAST_DEF 128
- .default_value = CONTRAST_DEF,
+ .default_value = 128,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setcontrast
},
- {
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -136,10 +131,9 @@ static const struct ctrl sd_ctrls[] = {
.step = 1,
.default_value = 4,
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = setcontrast
},
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -147,14 +141,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
+ .default_value = 1,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set_control = setautogain
},
-#define LIGHTFREQ_IDX 4
- {
+[LIGHTFREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
@@ -162,13 +153,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
-#define FREQ_DEF 0
- .default_value = FREQ_DEF,
+ .default_value = 0,
},
- .set = sd_setfreq,
- .get = sd_getfreq,
+ .set_control = setlightfreq
},
- {
+[SHARPNESS] = {
{
.id = V4L2_CID_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -176,11 +165,9 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define SHARPNESS_DEF 2
- .default_value = SHARPNESS_DEF,
+ .default_value = 2,
},
- .set = sd_setsharpness,
- .get = sd_getsharpness,
+ .set_control = setsharpness
},
};
@@ -4499,7 +4486,7 @@ static const struct usb_action mt9v111_3_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
- {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
@@ -5406,7 +5393,7 @@ static const struct usb_action tas5130c_NoFlikerScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5473,7 +5460,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_Initial[] = {
+static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5538,7 +5525,7 @@ static const struct usb_action tas5130c_vf0250_Initial[] = {
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
{}
};
-static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+static const struct usb_action gc0303_50HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
@@ -5562,7 +5549,7 @@ static const struct usb_action tas5130c_vf0250_50HZScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_50HZ[] = {
+static const struct usb_action gc0303_50HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
{0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
@@ -5586,7 +5573,7 @@ static const struct usb_action tas5130c_vf0250_50HZ[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+static const struct usb_action gc0303_60HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
@@ -5610,7 +5597,7 @@ static const struct usb_action tas5130c_vf0250_60HZScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_60HZ[] = {
+static const struct usb_action gc0303_60HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
{0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
@@ -5634,7 +5621,7 @@ static const struct usb_action tas5130c_vf0250_60HZ[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+static const struct usb_action gc0303_NoFlikerScale[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5656,7 +5643,7 @@ static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+static const struct usb_action gc0303_NoFliker[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5833,12 +5820,13 @@ static void setmatrix(struct gspca_dev *gspca_dev)
{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
static const u8 tas5130c_matrix[9] =
{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
- static const u8 vf0250_matrix[9] =
+ static const u8 gc0303_matrix[9] =
{0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
static const u8 *matrix_tb[SENSOR_MAX] = {
[SENSOR_ADCM2700] = adcm2700_matrix,
[SENSOR_CS2102] = ov7620_matrix,
[SENSOR_CS2102K] = NULL,
+ [SENSOR_GC0303] = gc0303_matrix,
[SENSOR_GC0305] = gc0305_matrix,
[SENSOR_HDCS2020b] = NULL,
[SENSOR_HV7131B] = NULL,
@@ -5854,7 +5842,6 @@ static void setmatrix(struct gspca_dev *gspca_dev)
[SENSOR_PB0330] = gc0305_matrix,
[SENSOR_PO2030] = po2030_matrix,
[SENSOR_TAS5130C] = tas5130c_matrix,
- [SENSOR_TAS5130C_VF0250] = vf0250_matrix,
};
matrix = matrix_tb[sd->sensor];
@@ -5875,7 +5862,7 @@ static void setsharpness(struct gspca_dev *gspca_dev)
{0x10, 0x1e}
};
- sharpness = sd->sharpness;
+ sharpness = sd->ctrls[SHARPNESS].val;
reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6);
reg_r(gspca_dev, 0x01c8);
reg_r(gspca_dev, 0x01c9);
@@ -5910,10 +5897,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
};
- Tgamma = gamma_tb[sd->gamma - 1];
+ Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1];
- contrast = ((int) sd->contrast - 128); /* -128 / 127 */
- brightness = ((int) sd->brightness - 128); /* -128 / 92 */
+ contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */
+ brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */
adj = 0;
gp1 = gp2 = 0;
for (i = 0; i < 16; i++) {
@@ -5994,6 +5981,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
{cs2102_NoFliker, cs2102_NoFlikerScale,
NULL, NULL, /* currently disabled */
NULL, NULL},
+ [SENSOR_GC0303] =
+ {gc0303_NoFliker, gc0303_NoFlikerScale,
+ gc0303_50HZ, gc0303_50HZScale,
+ gc0303_60HZ, gc0303_60HZScale},
[SENSOR_GC0305] =
{gc0305_NoFliker, gc0305_NoFliker,
gc0305_50HZ, gc0305_50HZ,
@@ -6054,14 +6045,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
{tas5130c_NoFliker, tas5130c_NoFlikerScale,
tas5130c_50HZ, tas5130c_50HZScale,
tas5130c_60HZ, tas5130c_60HZScale},
- [SENSOR_TAS5130C_VF0250] =
- {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
- tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
- tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
};
- i = sd->lightfreq * 2;
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ i = sd->ctrls[LIGHTFREQ].val * 2;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
if (mode)
i++; /* 320x240 */
zc3_freq = freq_tb[sd->sensor][i];
@@ -6070,14 +6057,14 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, zc3_freq);
switch (sd->sensor) {
case SENSOR_GC0305:
- if (mode /* if 320x240 */
- && sd->lightfreq == 1) /* and 50Hz */
+ if (mode /* if 320x240 */
+ && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */
reg_w(gspca_dev, 0x85, 0x018d);
/* win: 0x80, 0x018d */
break;
case SENSOR_OV7620:
- if (!mode) { /* if 640x480 */
- if (sd->lightfreq != 0) /* and 50 or 60 Hz */
+ if (!mode) { /* if 640x480 */
+ if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */
reg_w(gspca_dev, 0x40, 0x0002);
else
reg_w(gspca_dev, 0x44, 0x0002);
@@ -6094,7 +6081,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
u8 autoval;
- if (sd->autogain)
+ if (sd->ctrls[AUTOGAIN].val)
autoval = 0x42;
else
autoval = 0x02;
@@ -6330,8 +6317,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
retword = i2c_read(gspca_dev, 0x00);
if (retword != 0) {
PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword);
- if (retword == 0x0011) /* VF0250 */
- return 0x0250;
+ if (retword == 0x0011) /* gc0303 */
+ return 0x0303;
if (retword == 0x0029) /* gc0305 */
send_unknown(gspca_dev, SENSOR_GC0305);
return retword;
@@ -6392,7 +6379,7 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_MC501CB:
return -1; /* don't probe */
- case SENSOR_TAS5130C_VF0250:
+ case SENSOR_GC0303:
/* may probe but with no write in reg 0x0010 */
return -1; /* don't probe */
case SENSOR_PAS106:
@@ -6421,11 +6408,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* define some sensors from the vendor/product */
sd->sensor = id->driver_info;
- sd->sharpness = SHARPNESS_DEF;
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->autogain = AUTOGAIN_DEF;
- sd->lightfreq = FREQ_DEF;
+ gspca_dev->cam.ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
return 0;
@@ -6441,6 +6424,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_ADCM2700] = 4,
[SENSOR_CS2102] = 4,
[SENSOR_CS2102K] = 5,
+ [SENSOR_GC0303] = 3,
[SENSOR_GC0305] = 4,
[SENSOR_HDCS2020b] = 4,
[SENSOR_HV7131B] = 4,
@@ -6456,12 +6440,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PB0330] = 4,
[SENSOR_PO2030] = 4,
[SENSOR_TAS5130C] = 3,
- [SENSOR_TAS5130C_VF0250] = 3,
};
static const u8 mode_tb[SENSOR_MAX] = {
[SENSOR_ADCM2700] = 2,
[SENSOR_CS2102] = 1,
[SENSOR_CS2102K] = 1,
+ [SENSOR_GC0303] = 1,
[SENSOR_GC0305] = 1,
[SENSOR_HDCS2020b] = 1,
[SENSOR_HV7131B] = 1,
@@ -6477,7 +6461,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PB0330] = 1,
[SENSOR_PO2030] = 1,
[SENSOR_TAS5130C] = 1,
- [SENSOR_TAS5130C_VF0250] = 1,
};
sensor = zcxx_probeSensor(gspca_dev);
@@ -6493,8 +6476,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
case SENSOR_MC501CB:
PDEBUG(D_PROBE, "Sensor MC501CB");
break;
- case SENSOR_TAS5130C_VF0250:
- PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
+ case SENSOR_GC0303:
+ PDEBUG(D_PROBE, "Sensor GC0303");
break;
default:
warn("Unknown sensor - set to TAS5130C");
@@ -6581,14 +6564,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "Find Sensor GC0305");
sd->sensor = SENSOR_GC0305;
break;
- case 0x0250:
- PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
- sd->sensor = SENSOR_TAS5130C_VF0250;
+ case 0x0303:
+ PDEBUG(D_PROBE, "Sensor GC0303");
+ sd->sensor = SENSOR_GC0303;
break;
case 0x2030:
PDEBUG(D_PROBE, "Find Sensor PO2030");
sd->sensor = SENSOR_PO2030;
- sd->sharpness = 0; /* from win traces */
+ sd->ctrls[SHARPNESS].def = 0; /* from win traces */
break;
case 0x7620:
PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -6629,11 +6612,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
cam->nmodes = ARRAY_SIZE(broken_vga_mode);
break;
}
- sd->gamma = gamma[sd->sensor];
+
+ sd->ctrls[GAMMA].def = gamma[sd->sensor];
switch (sd->sensor) {
case SENSOR_OV7630C:
- gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+ gspca_dev->ctrl_dis = (1 << LIGHTFREQ);
break;
}
@@ -6653,6 +6637,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
{cs2102_Initial, cs2102_InitialScale},
[SENSOR_CS2102K] =
{cs2102K_Initial, cs2102K_InitialScale},
+ [SENSOR_GC0303] =
+ {gc0303_Initial, gc0303_InitialScale},
[SENSOR_GC0305] =
{gc0305_Initial, gc0305_InitialScale},
[SENSOR_HDCS2020b] =
@@ -6683,8 +6669,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
{po2030_Initial, po2030_InitialScale},
[SENSOR_TAS5130C] =
{tas5130c_Initial, tas5130c_InitialScale},
- [SENSOR_TAS5130C_VF0250] =
- {tas5130c_vf0250_Initial, tas5130c_vf0250_InitialScale},
};
/* create the JPEG header */
@@ -6709,7 +6693,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7620:
case SENSOR_PO2030:
case SENSOR_TAS5130C:
- case SENSOR_TAS5130C_VF0250:
+ case SENSOR_GC0303:
/* msleep(100); * ?? */
reg_r(gspca_dev, 0x0002); /* --> 0x40 */
reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
@@ -6843,114 +6827,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gamma;
- return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->lightfreq = val;
- if (gspca_dev->streaming)
- setlightfreq(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->lightfreq;
- return 0;
-}
-
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->sharpness = val;
- if (gspca_dev->streaming)
- setsharpness(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->sharpness;
- return 0;
-}
-
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
@@ -7045,8 +6921,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x041e, 0x4036)},
{USB_DEVICE(0x041e, 0x403a)},
- {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
- {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
+ {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_GC0303},
+ {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_GC0303},
{USB_DEVICE(0x0458, 0x7007)},
{USB_DEVICE(0x0458, 0x700c)},
{USB_DEVICE(0x0458, 0x700f)},
@@ -7066,8 +6942,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08af)},
{USB_DEVICE(0x046d, 0x08b9)},
{USB_DEVICE(0x046d, 0x08d7)},
- {USB_DEVICE(0x046d, 0x08d9)},
{USB_DEVICE(0x046d, 0x08d8)},
+ {USB_DEVICE(0x046d, 0x08d9)},
{USB_DEVICE(0x046d, 0x08da)},
{USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
{USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106},
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index b70d6afc9fec..f7d1ee55185a 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -385,6 +385,11 @@ static int hdpvr_probe(struct usb_interface *interface,
v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
goto error;
}
+
+ /* until i2c is working properly */
+ retval = 0; /* hdpvr_register_i2c_ir(dev); */
+ if (retval < 0)
+ v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
#endif /* CONFIG_I2C */
/* let the user know what node this device is now attached to */
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index 409de11096d4..24966aa02a70 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -4,6 +4,9 @@
*
* Copyright (C) 2008 Janne Grunau (j@jannau.net)
*
+ * IR device registration code is
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.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, version 2.
@@ -22,6 +25,56 @@
#define REQTYPE_I2C_WRITE 0xb0
#define REQTYPE_I2C_WRITE_STATT 0xd0
+#define Z8F0811_IR_TX_I2C_ADDR 0x70
+#define Z8F0811_IR_RX_I2C_ADDR 0x71
+
+static const u8 ir_i2c_addrs[] = {
+ Z8F0811_IR_TX_I2C_ADDR,
+ Z8F0811_IR_RX_I2C_ADDR,
+};
+
+static const char * const ir_devicenames[] = {
+ "ir_tx_z8f0811_hdpvr",
+ "ir_rx_z8f0811_hdpvr",
+};
+
+static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,
+ const char *type, u8 addr)
+{
+ struct i2c_board_info info;
+ struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
+ unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, type, I2C_NAME_SIZE);
+
+ /* Our default information for ir-kbd-i2c.c to use */
+ switch (addr) {
+ case Z8F0811_IR_RX_I2C_ADDR:
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = "HD PVR";
+ info.platform_data = init_data;
+ break;
+ }
+
+ return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+ -1 : 0;
+}
+
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++)
+ ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter,
+ ir_devicenames[i], ir_i2c_addrs[i]);
+
+ return ret;
+}
+
static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
char *data, int len)
{
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index 5efc963f9164..37f1e4c7675d 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -16,6 +16,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/ir-kbd-i2c.h>
#define HDPVR_MAJOR_VERSION 0
#define HDPVR_MINOR_VERSION 2
@@ -109,6 +110,9 @@ struct hdpvr_device {
/* I2C lock */
struct mutex i2c_mutex;
+ /* For passing data to ir-kbd-i2c */
+ struct IR_i2c_init_data ir_i2c_init_data;
+
/* usb control transfer buffer and lock */
struct mutex usbc_mutex;
u8 *usbc_buf;
@@ -306,6 +310,8 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev);
/* i2c adapter registration */
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev);
+
/*========================================================================*/
/* buffer management */
int hdpvr_free_buffers(struct hdpvr_device *dev);
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index 7ae96367b3ab..cdf8b191f710 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -37,15 +37,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index b72d0f0b8310..6ad7e1c8b922 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -38,15 +38,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
index 380e459f899d..1a1169115716 100644
--- a/drivers/media/video/imx074.c
+++ b/drivers/media/video/imx074.c
@@ -451,7 +451,6 @@ static int imx074_probe(struct i2c_client *client,
ret = imx074_video_probe(icd, client);
if (ret < 0) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return ret;
}
@@ -468,8 +467,6 @@ static int imx074_remove(struct i2c_client *client)
icd->ops = NULL;
if (icl->free_bus)
icl->free_bus(icl);
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(priv);
return 0;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 5a000c65ae98..c87b6bc45555 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -44,10 +44,9 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/workqueue.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
/* ----------------------------------------------------------------------- */
@@ -253,7 +252,7 @@ static void ir_key_poll(struct IR_i2c *ir)
}
if (rc)
- ir_keydown(ir->input, ir_key, 0);
+ rc_keydown(ir->rc, ir_key, 0);
}
static void ir_work(struct work_struct *work)
@@ -270,22 +269,18 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
char *ir_codes = NULL;
const char *name = NULL;
- u64 ir_type = 0;
+ u64 rc_type = RC_TYPE_UNKNOWN;
struct IR_i2c *ir;
- struct input_dev *input_dev;
+ struct rc_dev *rc = NULL;
struct i2c_adapter *adap = client->adapter;
unsigned short addr = client->addr;
int err;
- ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- err = -ENOMEM;
- goto err_out_free;
- }
+ ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
ir->c = client;
- ir->input = input_dev;
ir->polling_interval = DEFAULT_POLLING_INTERVAL;
i2c_set_clientdata(client, ir);
@@ -293,7 +288,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x64:
name = "Pixelview";
ir->get_key = get_key_pixelview;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x18:
@@ -301,7 +296,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x1a:
name = "Hauppauge";
ir->get_key = get_key_haup;
- ir_type = IR_TYPE_RC5;
+ rc_type = RC_TYPE_RC5;
if (hauppauge == 1) {
ir_codes = RC_MAP_HAUPPAUGE_NEW;
} else {
@@ -311,19 +306,19 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x30:
name = "KNC One";
ir->get_key = get_key_knc1;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
- ir_type = IR_TYPE_RC5;
+ rc_type = RC_TYPE_RC5;
ir_codes = RC_MAP_FUSIONHDTV_MCE;
break;
case 0x40:
name = "AVerMedia Cardbus remote";
ir->get_key = get_key_avermedia_cardbus;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
}
@@ -334,9 +329,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
client->dev.platform_data;
ir_codes = init_data->ir_codes;
+ rc = init_data->rc_dev;
+
name = init_data->name;
if (init_data->type)
- ir_type = init_data->type;
+ rc_type = init_data->type;
if (init_data->polling_interval)
ir->polling_interval = init_data->polling_interval;
@@ -367,8 +364,21 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
+ if (!rc) {
+ /*
+ * If platform_data doesn't specify rc_dev, initilize it
+ * internally
+ */
+ rc = rc_allocate_device();
+ if (!rc) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+ }
+ ir->rc = rc;
+
/* Make sure we are all setup before going on */
- if (!name || !ir->get_key || !ir_type || !ir_codes) {
+ if (!name || !ir->get_key || !rc_type || !ir_codes) {
dprintk(1, ": Unsupported device at address 0x%02x\n",
addr);
err = -ENODEV;
@@ -383,18 +393,28 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_name(&adap->dev),
dev_name(&client->dev));
- /* init + register input device */
- ir->ir_type = ir_type;
- input_dev->id.bustype = BUS_I2C;
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
+ /*
+ * Initialize input_dev fields
+ * It doesn't make sense to allow overriding them via platform_data
+ */
+ rc->input_id.bustype = BUS_I2C;
+ rc->input_phys = ir->phys;
+ rc->input_name = ir->name;
+
+ /*
+ * Initialize the other fields of rc_dev
+ */
+ rc->map_name = ir->ir_codes;
+ rc->allowed_protos = rc_type;
+ if (!rc->driver_name)
+ rc->driver_name = MODULE_NAME;
- err = ir_input_register(ir->input, ir->ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_free;
printk(MODULE_NAME ": %s detected at %s [%s]\n",
- ir->input->name, ir->input->phys, adap->name);
+ ir->name, ir->phys, adap->name);
/* start polling via eventd */
INIT_DELAYED_WORK(&ir->work, ir_work);
@@ -403,6 +423,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0;
err_out_free:
+ /* Only frees rc if it were allocated internally */
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -415,7 +437,7 @@ static int ir_remove(struct i2c_client *client)
cancel_delayed_work_sync(&ir->work);
/* unregister device */
- ir_input_unregister(ir->input);
+ rc_unregister_device(ir->rc);
/* free memory */
kfree(ir);
@@ -427,6 +449,7 @@ static const struct i2c_device_id ir_kbd_id[] = {
{ "ir_video", 0 },
/* IR device specific entries should be added here */
{ "ir_rx_z8f0811_haup", 0 },
+ { "ir_rx_z8f0811_hdpvr", 0 },
{ }
};
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index be4af1fa557e..89f65914cc8e 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,9 +1,8 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L2 && PCI && I2C
- depends on INPUT # due to VIDEO_IR
select I2C_ALGOBIT
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 87afbbee2063..145e4749a69d 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -405,7 +405,8 @@ static const struct ivtv_card ivtv_card_avc2410 = {
.hw_audio_ctrl = IVTV_HW_MSP34XX,
.hw_muxer = IVTV_HW_CS53L32A,
.hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A |
- IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+ IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+ IVTV_HW_I2C_IR_RX_ADAPTEC,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 },
{ IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 },
@@ -1313,7 +1314,6 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
"Composite 3"
};
- memset(input, 0, sizeof(*input));
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
@@ -1331,7 +1331,6 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
{
const struct ivtv_card_output *card_output = itv->card->video_outputs + index;
- memset(output, 0, sizeof(*output));
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 78eca992e1fd..e6f5c02981f1 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -111,6 +111,7 @@
#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18)
#define IVTV_HW_Z8F0811_IR_TX_HAUP (1 << 19)
#define IVTV_HW_Z8F0811_IR_RX_HAUP (1 << 20)
+#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 21)
#define IVTV_HW_Z8F0811_IR_HAUP (IVTV_HW_Z8F0811_IR_RX_HAUP | \
IVTV_HW_Z8F0811_IR_TX_HAUP)
@@ -120,7 +121,8 @@
#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \
IVTV_HW_I2C_IR_RX_HAUP_EXT | \
IVTV_HW_I2C_IR_RX_HAUP_INT | \
- IVTV_HW_Z8F0811_IR_RX_HAUP)
+ IVTV_HW_Z8F0811_IR_RX_HAUP | \
+ IVTV_HW_I2C_IR_RX_ADAPTEC)
#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP)
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index e421d15b0f5c..39946420b301 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1029,8 +1029,13 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET,
IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+ "encoder memory\n");
+ IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of "
+ "vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1041,8 +1046,14 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET,
IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into "
+ "CX23415 decoder memory\n");
+ IVTV_ERR("Each capture card with a CX23415 needs 8 MB "
+ "of vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc "
+ "/proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option "
+ "to set VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1057,8 +1068,13 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->reg_mem =
ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (!itv->reg_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+ "register space\n");
+ IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of "
+ "vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_io;
}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index d727485da886..c57a58523ca8 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -570,8 +570,8 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
int elems = count / sizeof(struct v4l2_sliced_vbi_data);
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);
- return elems * sizeof(struct v4l2_sliced_vbi_data);
+ return ivtv_write_vbi_from_user(itv,
+ (const struct v4l2_sliced_vbi_data __user *)user_buf, elems);
}
mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 9e8039ac909e..e103b8fc7452 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -94,6 +94,7 @@
#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18
#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70
#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71
+#define IVTV_ADAPTEC_IR_ADDR 0x6b
/* This array should match the IVTV_HW_ defines */
static const u8 hw_addrs[] = {
@@ -118,6 +119,7 @@ static const u8 hw_addrs[] = {
IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */
IVTV_Z8F0811_IR_TX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_TX_HAUP */
IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_RX_HAUP */
+ IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */
};
/* This array should match the IVTV_HW_ defines */
@@ -143,8 +145,34 @@ static const char * const hw_devicenames[] = {
"ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */
"ir_tx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_TX_HAUP */
"ir_rx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_RX_HAUP */
+ "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */
};
+static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char keybuf[4];
+
+ keybuf[0] = 0x00;
+ i2c_master_send(ir->c, keybuf, 1);
+ /* poll IR chip */
+ if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+ return 0;
+ }
+
+ /* key pressed ? */
+ if (keybuf[2] == 0xff)
+ return 0;
+
+ /* remove repeat bit */
+ keybuf[2] &= 0x7f;
+ keybuf[3] |= 0x80;
+
+ *ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
+ *ir_raw = *ir_key;
+
+ return 1;
+}
+
static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
{
struct i2c_board_info info;
@@ -172,7 +200,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
init_data->internal_get_key_func =
IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
- init_data->type = IR_TYPE_OTHER;
+ init_data->type = RC_TYPE_OTHER;
init_data->name = "AVerMedia AVerTV card";
break;
case IVTV_HW_I2C_IR_RX_HAUP_EXT:
@@ -180,15 +208,22 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
/* Default to old black remote */
init_data->ir_codes = RC_MAP_RC5_TV;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
init_data->name = itv->card_name;
break;
case IVTV_HW_Z8F0811_IR_RX_HAUP:
/* Default to grey remote */
init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = itv->card_name;
+ break;
+ case IVTV_HW_I2C_IR_RX_ADAPTEC:
+ init_data->get_key = get_key_adaptec;
init_data->name = itv->card_name;
+ /* FIXME: The protocol and RC_MAP needs to be corrected */
+ init_data->ir_codes = RC_MAP_EMPTY;
+ init_data->type = RC_TYPE_UNKNOWN;
break;
}
@@ -218,8 +253,6 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv)
const unsigned short addr_list[] = {
0x1a, /* Hauppauge IR external - collides with WM8739 */
0x18, /* Hauppauge IR internal */
- 0x71, /* Hauppauge IR (PVR150) */
- 0x6b, /* Adaptec IR */
I2C_CLIENT_END
};
@@ -239,19 +272,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->radio);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->radio);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->demod);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->demod);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type,
- 0, itv->card_i2c->tv);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->tv);
if (sd)
sd->grp_id = 1 << idx;
return sd ? 0 : -1;
@@ -267,17 +297,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
/* It's an I2C device other than an analog tuner or IR chip */
if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
} else if (hw == IVTV_HW_CX25840) {
struct cx25840_platform_data pdata;
pdata.pvr150_workaround = itv->pvr150_workaround;
sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
- adap, NULL, type, 0, &pdata, hw_addrs[idx],
- NULL);
+ adap, type, 0, &pdata, hw_addrs[idx], NULL);
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, NULL, type, hw_addrs[idx], NULL);
+ adap, type, hw_addrs[idx], NULL);
}
if (sd)
sd->grp_id = 1 << idx;
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index e1c347e5ebd8..2dfa957b0fd5 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -92,54 +92,97 @@ static int odd_parity(u8 c)
return c & 1;
}
-void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
+static void ivtv_write_vbi_line(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data *d,
+ struct vbi_cc *cc, int *found_cc)
{
struct vbi_info *vi = &itv->vbi;
- struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
- int found_cc = 0;
- size_t i;
-
- for (i = 0; i < cnt; i++) {
- const struct v4l2_sliced_vbi_data *d = sliced + i;
- if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
- if (d->field) {
- cc.even[0] = d->data[0];
- cc.even[1] = d->data[1];
- } else {
- cc.odd[0] = d->data[0];
- cc.odd[1] = d->data[1];
- }
- found_cc = 1;
+ if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
+ if (d->field) {
+ cc->even[0] = d->data[0];
+ cc->even[1] = d->data[1];
+ } else {
+ cc->odd[0] = d->data[0];
+ cc->odd[1] = d->data[1];
}
- else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
- 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);
- }
+ *found_cc = 1;
+ } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
+ 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) {
- int wss = d->data[0] | d->data[1] << 8;
+ } else if (d->id == V4L2_SLICED_WSS_625 &&
+ d->line == 23 && d->field == 0) {
+ int wss = d->data[0] | d->data[1] << 8;
- if (vi->wss_payload != wss) {
- vi->wss_payload = wss;
- set_bit(IVTV_F_I_UPDATE_WSS, &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 && vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
- vi->cc_payload[vi->cc_payload_idx++] = cc;
+}
+
+static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc)
+{
+ struct vbi_info *vi = &itv->vbi;
+
+ if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
+ memcpy(&vi->cc_payload[vi->cc_payload_idx], cc,
+ sizeof(struct vbi_cc));
+ vi->cc_payload_idx++;
set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
}
}
+static void ivtv_write_vbi(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data *sliced,
+ size_t cnt)
+{
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+ int found_cc = 0;
+ size_t i;
+
+ for (i = 0; i < cnt; i++)
+ ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+
+ if (found_cc)
+ ivtv_write_vbi_cc_lines(itv, &cc);
+}
+
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data __user *sliced,
+ size_t cnt)
+{
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+ int found_cc = 0;
+ size_t i;
+ struct v4l2_sliced_vbi_data d;
+ ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data);
+
+ for (i = 0; i < cnt; i++) {
+ if (copy_from_user(&d, sliced + i,
+ sizeof(struct v4l2_sliced_vbi_data))) {
+ ret = -EFAULT;
+ break;
+ }
+ ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+ }
+
+ if (found_cc)
+ ivtv_write_vbi_cc_lines(itv, &cc);
+
+ return ret;
+}
+
static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
{
int line = 0;
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index 970567b9194d..166dd0b75d0f 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -20,7 +20,10 @@
#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);
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data __user *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);
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 3b19f5b25a72..c179041d91f8 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -524,7 +524,6 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
{
struct m2mtest_q_data *q_data;
struct videobuf_queue *vq;
- int ret = 0;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
if (!vq)
@@ -534,12 +533,9 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
if (!q_data)
return -EINVAL;
- mutex_lock(&vq->vb_lock);
-
if (videobuf_queue_is_busy(vq)) {
v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
q_data->fmt = find_format(f);
@@ -553,9 +549,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
-out:
- mutex_unlock(&vq->vb_lock);
- return ret;
+ return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
@@ -845,10 +839,12 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
enum v4l2_buf_type type)
{
struct m2mtest_ctx *ctx = priv;
+ struct m2mtest_dev *dev = ctx->dev;
- videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
- &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
- sizeof(struct m2mtest_buffer), priv, NULL);
+ videobuf_queue_vmalloc_init(vq, &m2mtest_qops, dev->v4l2_dev.dev,
+ &dev->irqlock, type, V4L2_FIELD_NONE,
+ sizeof(struct m2mtest_buffer), priv,
+ &dev->dev_mutex);
}
@@ -920,7 +916,7 @@ static const struct v4l2_file_operations m2mtest_fops = {
.open = m2mtest_open,
.release = m2mtest_release,
.poll = m2mtest_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = m2mtest_mmap,
};
@@ -965,6 +961,7 @@ static int m2mtest_probe(struct platform_device *pdev)
}
*vfd = m2mtest_videodev;
+ vfd->lock = &dev->dev_mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 2be23bccd3c8..48d2c2419c13 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = {
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = meye_poll,
};
@@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
msleep(1);
mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
- if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
- video_nr) < 0) {
- v4l2_err(v4l2_dev, "video_register_device failed\n");
- goto outvideoreg;
- }
-
mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list);
meye.brightness = 32 << 10;
@@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
+ if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
+ video_nr) < 0) {
+ v4l2_err(v4l2_dev, "video_register_device failed\n");
+ goto outvideoreg;
+ }
+
v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index fcb4cd941853..f7fc88d240e6 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -798,7 +798,6 @@ static int mt9m001_remove(struct i2c_client *client)
icd->ops = NULL;
mt9m001_video_remove(icd);
- client->driver = NULL;
kfree(mt9m001);
return 0;
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 525a16e73285..53fa2a7bf156 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -1092,7 +1092,6 @@ static int mt9m111_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- client->driver = NULL;
kfree(mt9m111);
return 0;
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 9bd44a816ea1..7ce279c3751d 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -896,7 +896,6 @@ static int mt9t031_remove(struct i2c_client *client)
if (icd)
icd->ops = NULL;
- client->driver = NULL;
kfree(mt9t031);
return 0;
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index b96171cc79f9..6a784c87e5ff 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -930,7 +930,6 @@ static int mt9v022_remove(struct i2c_client *client)
icd->ops = NULL;
mt9v022_video_remove(icd);
- client->driver = NULL;
kfree(mt9v022);
return 0;
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 5e486a88ad7c..bc0c23a1009c 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -382,10 +382,9 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
struct mx1_camera_dev *pcdev = ici->priv;
videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
- &pcdev->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct mx1_buffer), icd, NULL);
+ &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct mx1_buffer), icd, &icd->video_lock);
}
static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 4a27862da30d..4eab1c620318 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -31,6 +31,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
#include <media/videobuf-dma-contig.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
@@ -682,7 +683,8 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE, sizeof(struct mx2_buffer), icd, NULL);
+ V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
+ icd, &icd->video_lock);
}
#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \
@@ -806,8 +808,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
if (common_flags & SOCAM_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
- if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
- csicr1 |= CSICR1_INV_PCLK;
if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
@@ -903,8 +903,6 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
static int mx2_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct mx2_camera_dev *pcdev = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -943,8 +941,6 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
static int mx2_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- struct mx2_camera_dev *pcdev = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -1024,13 +1020,13 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
return 0;
}
-static int mx2_camera_reqbufs(struct soc_camera_file *icf,
+static int mx2_camera_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
for (i = 0; i < p->count; i++) {
- struct mx2_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+ struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
struct mx2_buffer, vb);
INIT_LIST_HEAD(&buf->vb.queue);
}
@@ -1151,9 +1147,9 @@ err_out:
static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
- return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+ return videobuf_poll_stream(file, &icd->vb_vidq, pt);
}
static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 29c5fc348133..b9cb4a436959 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -27,6 +27,7 @@
#include <mach/ipu.h>
#include <mach/mx3_camera.h>
+#include <mach/dma.h>
#define MX3_CAM_DRV_NAME "mx3-camera"
@@ -442,7 +443,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
sizeof(struct mx3_camera_buffer), icd,
- NULL);
+ &icd->video_lock);
}
/* First part of ipu_csi_init_interface() */
@@ -638,6 +639,9 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
struct dma_chan_request *rq = arg;
struct mx3_camera_pdata *pdata;
+ if (!imx_dma_is_ipu(chan))
+ return false;
+
if (!rq)
return false;
@@ -1182,13 +1186,12 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
goto egetres;
}
- mx3_cam = vmalloc(sizeof(*mx3_cam));
+ mx3_cam = vzalloc(sizeof(*mx3_cam));
if (!mx3_cam) {
dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
err = -ENOMEM;
goto ealloc;
}
- memset(mx3_cam, 0, sizeof(*mx3_cam));
mx3_cam->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(mx3_cam->clk)) {
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 94ba698d0ad4..e8846a09b026 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -59,10 +59,10 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
/* this array holds the information, which port of the saa7146 each
@@ -185,17 +185,17 @@ static int mxb_probe(struct saa7146_dev *dev)
}
mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "saa7111", I2C_SAA7111A, NULL);
+ "saa7111", I2C_SAA7111A, NULL);
mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6420", I2C_TEA6420_1, NULL);
+ "tea6420", I2C_TEA6420_1, NULL);
mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6420", I2C_TEA6420_2, NULL);
+ "tea6420", I2C_TEA6420_2, NULL);
mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tea6415c", I2C_TEA6415C, NULL);
+ "tea6415c", I2C_TEA6415C, NULL);
mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tda9840", I2C_TDA9840, NULL);
+ "tda9840", I2C_TDA9840, NULL);
mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- NULL, "tuner", I2C_TUNER, NULL);
+ "tuner", I2C_TUNER, NULL);
/* check if all devices are present */
if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 15f8793e325b..029a4babfd61 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -1286,7 +1286,7 @@ static int omap_vout_release(struct file *file)
videobuf_mmap_free(q);
/* Even if apply changes fails we should continue
- freeing allocated memeory */
+ freeing allocated memory */
if (vout->streaming) {
u32 mask = 0;
@@ -2230,7 +2230,6 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
- /* need to register for a VID_HARDWARE_* ID in videodev.h */
vfd->fops = &omap_vout_fops;
vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
mutex_init(&vout->lock);
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index 7c30e62b50db..0a2fb2bfdbfb 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -235,7 +235,7 @@ static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
BUG_ON(in_interrupt());
- videobuf_waiton(vb, 0, 0);
+ videobuf_waiton(vq, vb, 0, 0);
if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
videobuf_dma_contig_free(vq, vb);
@@ -504,7 +504,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
* empty. Since the transfer of the DMA programming register set
* content to the DMA working register set is done automatically
* by the DMA hardware, this can pretty well happen while we
- * are keeping the lock here. Levae fetching it from the queue
+ * are keeping the lock here. Leave fetching it from the queue
* to be done when a next DMA interrupt occures instead.
*/
return;
@@ -1365,12 +1365,12 @@ static void omap1_cam_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
icd->dev.parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd);
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
else
videobuf_queue_sg_init(q, &omap1_videobuf_ops,
icd->dev.parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd);
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
/* use videobuf mode (auto)selected with the module parameter */
pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
@@ -1386,7 +1386,7 @@ static void omap1_cam_init_videobuf(struct videobuf_queue *q,
}
}
-static int omap1_cam_reqbufs(struct soc_camera_file *icf,
+static int omap1_cam_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
@@ -1398,7 +1398,7 @@ static int omap1_cam_reqbufs(struct soc_camera_file *icf,
* it hadn't triggered
*/
for (i = 0; i < p->count; i++) {
- struct omap1_cam_buf *buf = container_of(icf->vb_vidq.bufs[i],
+ struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
struct omap1_cam_buf, vb);
buf->inwork = 0;
INIT_LIST_HEAD(&buf->vb.queue);
@@ -1485,10 +1485,10 @@ static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
struct omap1_cam_buf *buf;
- buf = list_entry(icf->vb_vidq.stream.next, struct omap1_cam_buf,
+ buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
vb.stream);
poll_wait(file, &buf->vb.done, pt);
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index 378b094aff16..017552762902 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1198,7 +1198,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
atomic_inc(&cam->reset_disable);
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
rval = videobuf_streamoff(q);
if (!rval) {
@@ -1512,7 +1512,7 @@ static int omap24xxcam_release(struct file *file)
atomic_inc(&cam->reset_disable);
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
/* stop streaming capture */
videobuf_streamoff(&fh->vbq);
@@ -1536,7 +1536,7 @@ static int omap24xxcam_release(struct file *file)
* not be scheduled anymore since streaming is already
* disabled.)
*/
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
mutex_lock(&cam->mutex);
if (atomic_dec_return(&cam->users) == 0) {
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c
new file mode 100644
index 000000000000..0cea0cf36679
--- /dev/null
+++ b/drivers/media/video/ov2640.c
@@ -0,0 +1,1205 @@
+/*
+ * ov2640 Camera Driver
+ *
+ * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * Based on ov772x, ov9640 drivers and previous non merged implementations.
+ *
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2006, OmniVision
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#define VAL_SET(x, mask, rshift, lshift) \
+ ((((x) >> rshift) & mask) << lshift)
+/*
+ * DSP registers
+ * register offset for BANK_SEL == BANK_SEL_DSP
+ */
+#define R_BYPASS 0x05 /* Bypass DSP */
+#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */
+#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */
+#define QS 0x44 /* Quantization Scale Factor */
+#define CTRLI 0x50
+#define CTRLI_LP_DP 0x80
+#define CTRLI_ROUND 0x40
+#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)
+#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */
+#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */
+#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define XOFFL 0x53 /* OFFSET_X[7:0] */
+#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define YOFFL 0x54 /* OFFSET_Y[7:0] */
+#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define VHYX 0x55 /* Offset and size completion */
+#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7)
+#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3)
+#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4)
+#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0)
+#define DPRP 0x56
+#define TEST 0x57 /* Horizontal size completion */
+#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7)
+#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */
+#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */
+#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMHH 0x5C /* Zoom: Speed and H&W completion */
+#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)
+#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2)
+#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0)
+#define BPADDR 0x7C /* SDE Indirect Register Access: Address */
+#define BPDATA 0x7D /* SDE Indirect Register Access: Data */
+#define CTRL2 0x86 /* DSP Module enable 2 */
+#define CTRL2_DCW_EN 0x20
+#define CTRL2_SDE_EN 0x10
+#define CTRL2_UV_ADJ_EN 0x08
+#define CTRL2_UV_AVG_EN 0x04
+#define CTRL2_CMX_EN 0x01
+#define CTRL3 0x87 /* DSP Module enable 3 */
+#define CTRL3_BPC_EN 0x80
+#define CTRL3_WPC_EN 0x40
+#define SIZEL 0x8C /* Image Size Completion */
+#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)
+#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3)
+#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0)
+#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */
+#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */
+#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define CTRL0 0xC2 /* DSP Module enable 0 */
+#define CTRL0_AEC_EN 0x80
+#define CTRL0_AEC_SEL 0x40
+#define CTRL0_STAT_SEL 0x20
+#define CTRL0_VFIRST 0x10
+#define CTRL0_YUV422 0x08
+#define CTRL0_YUV_EN 0x04
+#define CTRL0_RGB_EN 0x02
+#define CTRL0_RAW_EN 0x01
+#define CTRL1 0xC3 /* DSP Module enable 1 */
+#define CTRL1_CIP 0x80
+#define CTRL1_DMY 0x40
+#define CTRL1_RAW_GMA 0x20
+#define CTRL1_DG 0x10
+#define CTRL1_AWB 0x08
+#define CTRL1_AWB_GAIN 0x04
+#define CTRL1_LENC 0x02
+#define CTRL1_PRE 0x01
+#define R_DVP_SP 0xD3 /* DVP output speed control */
+#define R_DVP_SP_AUTO_MODE 0x80
+#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);
+ * = sysclk (48)/(2*[6:0]) (RAW);*/
+#define IMAGE_MODE 0xDA /* Image Output Format Select */
+#define IMAGE_MODE_Y8_DVP_EN 0x40
+#define IMAGE_MODE_JPEG_EN 0x10
+#define IMAGE_MODE_YUV422 0x00
+#define IMAGE_MODE_RAW10 0x04 /* (DVP) */
+#define IMAGE_MODE_RGB565 0x08
+#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output
+ * mode (0 for HREF is same as sensor) */
+#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP
+ * 1: Low byte first UYVY (C2[4] =0)
+ * VYUY (C2[4] =1)
+ * 0: High byte first YUYV (C2[4]=0)
+ * YVYU (C2[4] = 1) */
+#define RESET 0xE0 /* Reset */
+#define RESET_MICROC 0x40
+#define RESET_SCCB 0x20
+#define RESET_JPEG 0x10
+#define RESET_DVP 0x04
+#define RESET_IPU 0x02
+#define RESET_CIF 0x01
+#define REGED 0xED /* Register ED */
+#define REGED_CLK_OUT_DIS 0x10
+#define MS_SP 0xF0 /* SCCB Master Speed */
+#define SS_ID 0xF7 /* SCCB Slave ID */
+#define SS_CTRL 0xF8 /* SCCB Slave Control */
+#define SS_CTRL_ADD_AUTO_INC 0x20
+#define SS_CTRL_EN 0x08
+#define SS_CTRL_DELAY_CLK 0x04
+#define SS_CTRL_ACC_EN 0x02
+#define SS_CTRL_SEN_PASS_THR 0x01
+#define MC_BIST 0xF9 /* Microcontroller misc register */
+#define MC_BIST_RESET 0x80 /* Microcontroller Reset */
+#define MC_BIST_BOOT_ROM_SEL 0x40
+#define MC_BIST_12KB_SEL 0x20
+#define MC_BIST_12KB_MASK 0x30
+#define MC_BIST_512KB_SEL 0x08
+#define MC_BIST_512KB_MASK 0x0C
+#define MC_BIST_BUSY_BIT_R 0x02
+#define MC_BIST_MC_RES_ONE_SH_W 0x02
+#define MC_BIST_LAUNCH 0x01
+#define BANK_SEL 0xFF /* Register Bank Select */
+#define BANK_SEL_DSP 0x00
+#define BANK_SEL_SENS 0x01
+
+/*
+ * Sensor registers
+ * register offset for BANK_SEL == BANK_SEL_SENS
+ */
+#define GAIN 0x00 /* AGC - Gain control gain setting */
+#define COM1 0x03 /* Common control 1 */
+#define COM1_1_DUMMY_FR 0x40
+#define COM1_3_DUMMY_FR 0x80
+#define COM1_7_DUMMY_FR 0xC0
+#define COM1_VWIN_LSB_UXGA 0x0F
+#define COM1_VWIN_LSB_SVGA 0x0A
+#define COM1_VWIN_LSB_CIF 0x06
+#define REG04 0x04 /* Register 04 */
+#define REG04_DEF 0x20 /* Always set */
+#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */
+#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */
+#define REG04_VREF_EN 0x10
+#define REG04_HREF_EN 0x08
+#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */
+#define COM2 0x09 /* Common control 2 */
+#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
+ /* Output drive capability */
+#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */
+#define PID 0x0A /* Product ID Number MSB */
+#define VER 0x0B /* Product ID Number LSB */
+#define COM3 0x0C /* Common control 3 */
+#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */
+#define COM3_BAND_AUTO 0x02 /* Auto Banding */
+#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the
+ * snapshot sequence*/
+#define AEC 0x10 /* AEC[9:2] Exposure Value */
+#define CLKRC 0x11 /* Internal clock */
+#define CLKRC_EN 0x80
+#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */
+#define COM7 0x12 /* Common control 7 */
+#define COM7_SRST 0x80 /* Initiates system reset. All registers are
+ * set to factory default values after which
+ * the chip resumes normal operation */
+#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */
+#define COM7_RES_SVGA 0x40 /* SVGA */
+#define COM7_RES_CIF 0x20 /* CIF */
+#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */
+#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */
+#define COM8 0x13 /* Common control 8 */
+#define COM8_DEF 0xC0 /* Banding filter ON/OFF */
+#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */
+#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
+#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
+#define COM9 0x14 /* Common control 9
+ * Automatic gain ceiling - maximum AGC value [7:5]*/
+#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */
+#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */
+#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */
+#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */
+#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */
+#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */
+#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */
+#define COM10 0x15 /* Common control 10 */
+#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */
+#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of
+ * PCLK (user can latch data at the next
+ * falling edge of PCLK).
+ * 0 otherwise. */
+#define COM10_HREF_INV 0x08 /* Invert HREF polarity:
+ * HREF negative for valid data*/
+#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */
+#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */
+#define HEND 0x18 /* Horizontal Window end MSB 8 bit */
+#define VSTART 0x19 /* Vertical Window start MSB 8 bit */
+#define VEND 0x1A /* Vertical Window end MSB 8 bit */
+#define MIDH 0x1C /* Manufacturer ID byte - high */
+#define MIDL 0x1D /* Manufacturer ID byte - low */
+#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VV 0x26 /* AGC/AEC Fast mode operating region */
+#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4)
+#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0)
+#define REG2A 0x2A /* Dummy pixel insert MSB */
+#define FRARL 0x2B /* Dummy pixel insert LSB */
+#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */
+#define YAVG 0x2F /* Y/G Channel Average value */
+#define REG32 0x32 /* Common Control 32 */
+#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */
+#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */
+#define ARCOM2 0x34 /* Zoom: Horizontal start point */
+#define REG45 0x45 /* Register 45 */
+#define FLL 0x46 /* Frame Length Adjustment LSBs */
+#define FLH 0x47 /* Frame Length Adjustment MSBs */
+#define COM19 0x48 /* Zoom: Vertical start point */
+#define ZOOMS 0x49 /* Zoom: Vertical start point */
+#define COM22 0x4B /* Flash light control */
+#define COM25 0x4E /* For Banding operations */
+#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */
+#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */
+#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */
+#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */
+#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */
+#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */
+#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */
+#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */
+
+/*
+ * ID
+ */
+#define MANUFACTURER_ID 0x7FA2
+#define PID_OV2640 0x2642
+#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
+
+/*
+ * Struct
+ */
+struct regval_list {
+ u8 reg_num;
+ u8 value;
+};
+
+/* Supported resolutions */
+enum ov2640_width {
+ W_QCIF = 176,
+ W_QVGA = 320,
+ W_CIF = 352,
+ W_VGA = 640,
+ W_SVGA = 800,
+ W_XGA = 1024,
+ W_SXGA = 1280,
+ W_UXGA = 1600,
+};
+
+enum ov2640_height {
+ H_QCIF = 144,
+ H_QVGA = 240,
+ H_CIF = 288,
+ H_VGA = 480,
+ H_SVGA = 600,
+ H_XGA = 768,
+ H_SXGA = 1024,
+ H_UXGA = 1200,
+};
+
+struct ov2640_win_size {
+ char *name;
+ enum ov2640_width width;
+ enum ov2640_height height;
+ const struct regval_list *regs;
+};
+
+
+struct ov2640_priv {
+ struct v4l2_subdev subdev;
+ struct ov2640_camera_info *info;
+ enum v4l2_mbus_pixelcode cfmt_code;
+ const struct ov2640_win_size *win;
+ int model;
+ u16 flag_vflip:1;
+ u16 flag_hflip:1;
+};
+
+/*
+ * Registers settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list ov2640_init_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0x2c, 0xff },
+ { 0x2e, 0xdf },
+ { BANK_SEL, BANK_SEL_SENS },
+ { 0x3c, 0x32 },
+ { CLKRC, CLKRC_DIV_SET(1) },
+ { COM2, COM2_OCAP_Nx_SET(3) },
+ { REG04, REG04_DEF | REG04_HREF_EN },
+ { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN },
+ { COM9, COM9_AGC_GAIN_8x | 0x08},
+ { 0x2c, 0x0c },
+ { 0x33, 0x78 },
+ { 0x3a, 0x33 },
+ { 0x3b, 0xfb },
+ { 0x3e, 0x00 },
+ { 0x43, 0x11 },
+ { 0x16, 0x10 },
+ { 0x39, 0x02 },
+ { 0x35, 0x88 },
+ { 0x22, 0x0a },
+ { 0x37, 0x40 },
+ { 0x23, 0x00 },
+ { ARCOM2, 0xa0 },
+ { 0x06, 0x02 },
+ { 0x06, 0x88 },
+ { 0x07, 0xc0 },
+ { 0x0d, 0xb7 },
+ { 0x0e, 0x01 },
+ { 0x4c, 0x00 },
+ { 0x4a, 0x81 },
+ { 0x21, 0x99 },
+ { AEW, 0x40 },
+ { AEB, 0x38 },
+ { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) },
+ { 0x5c, 0x00 },
+ { 0x63, 0x00 },
+ { FLL, 0x22 },
+ { COM3, 0x38 | COM3_BAND_AUTO },
+ { REG5D, 0x55 },
+ { REG5E, 0x7d },
+ { REG5F, 0x7d },
+ { REG60, 0x55 },
+ { HISTO_LOW, 0x70 },
+ { HISTO_HIGH, 0x80 },
+ { 0x7c, 0x05 },
+ { 0x20, 0x80 },
+ { 0x28, 0x30 },
+ { 0x6c, 0x00 },
+ { 0x6d, 0x80 },
+ { 0x6e, 0x00 },
+ { 0x70, 0x02 },
+ { 0x71, 0x94 },
+ { 0x73, 0xc1 },
+ { 0x3d, 0x34 },
+ { COM7, COM7_RES_UXGA | COM7_ZOOM_EN },
+ { 0x5a, 0x57 },
+ { BD50, 0xbb },
+ { BD60, 0x9c },
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0xe5, 0x7f },
+ { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
+ { 0x41, 0x24 },
+ { RESET, RESET_JPEG | RESET_DVP },
+ { 0x76, 0xff },
+ { 0x33, 0xa0 },
+ { 0x42, 0x20 },
+ { 0x43, 0x18 },
+ { 0x4c, 0x00 },
+ { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
+ { 0x88, 0x3f },
+ { 0xd7, 0x03 },
+ { 0xd9, 0x10 },
+ { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 },
+ { 0xc8, 0x08 },
+ { 0xc9, 0x80 },
+ { BPADDR, 0x00 },
+ { BPDATA, 0x00 },
+ { BPADDR, 0x03 },
+ { BPDATA, 0x48 },
+ { BPDATA, 0x48 },
+ { BPADDR, 0x08 },
+ { BPDATA, 0x20 },
+ { BPDATA, 0x10 },
+ { BPDATA, 0x0e },
+ { 0x90, 0x00 },
+ { 0x91, 0x0e },
+ { 0x91, 0x1a },
+ { 0x91, 0x31 },
+ { 0x91, 0x5a },
+ { 0x91, 0x69 },
+ { 0x91, 0x75 },
+ { 0x91, 0x7e },
+ { 0x91, 0x88 },
+ { 0x91, 0x8f },
+ { 0x91, 0x96 },
+ { 0x91, 0xa3 },
+ { 0x91, 0xaf },
+ { 0x91, 0xc4 },
+ { 0x91, 0xd7 },
+ { 0x91, 0xe8 },
+ { 0x91, 0x20 },
+ { 0x92, 0x00 },
+ { 0x93, 0x06 },
+ { 0x93, 0xe3 },
+ { 0x93, 0x03 },
+ { 0x93, 0x03 },
+ { 0x93, 0x00 },
+ { 0x93, 0x02 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x96, 0x00 },
+ { 0x97, 0x08 },
+ { 0x97, 0x19 },
+ { 0x97, 0x02 },
+ { 0x97, 0x0c },
+ { 0x97, 0x24 },
+ { 0x97, 0x30 },
+ { 0x97, 0x28 },
+ { 0x97, 0x26 },
+ { 0x97, 0x02 },
+ { 0x97, 0x98 },
+ { 0x97, 0x80 },
+ { 0x97, 0x00 },
+ { 0x97, 0x00 },
+ { 0xa4, 0x00 },
+ { 0xa8, 0x00 },
+ { 0xc5, 0x11 },
+ { 0xc6, 0x51 },
+ { 0xbf, 0x80 },
+ { 0xc7, 0x10 },
+ { 0xb6, 0x66 },
+ { 0xb8, 0xA5 },
+ { 0xb7, 0x64 },
+ { 0xb9, 0x7C },
+ { 0xb3, 0xaf },
+ { 0xb4, 0x97 },
+ { 0xb5, 0xFF },
+ { 0xb0, 0xC5 },
+ { 0xb1, 0x94 },
+ { 0xb2, 0x0f },
+ { 0xc4, 0x5c },
+ { 0xa6, 0x00 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x1b },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0x7f, 0x00 },
+ { 0xe5, 0x1f },
+ { 0xe1, 0x77 },
+ { 0xdd, 0x7f },
+ { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
+ ENDMARKER,
+};
+
+/*
+ * Register settings for window size
+ * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.
+ * Then the different zooming configurations will setup the output image size.
+ */
+static const struct regval_list ov2640_size_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { RESET, RESET_DVP },
+ { HSIZE8, HSIZE8_SET(W_UXGA) },
+ { VSIZE8, VSIZE8_SET(H_UXGA) },
+ { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
+ CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
+ { HSIZE, HSIZE_SET(W_UXGA) },
+ { VSIZE, VSIZE_SET(H_UXGA) },
+ { XOFFL, XOFFL_SET(0) },
+ { YOFFL, YOFFL_SET(0) },
+ { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+ VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
+ { TEST, TEST_HSIZE_SET(W_UXGA) },
+ ENDMARKER,
+};
+
+#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \
+ { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \
+ CTRLI_H_DIV_SET(h_div)}, \
+ { ZMOW, ZMOW_OUTW_SET(x) }, \
+ { ZMOH, ZMOH_OUTH_SET(y) }, \
+ { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \
+ { R_DVP_SP, pclk_div }, \
+ { RESET, 0x00}
+
+static const struct regval_list ov2640_qcif_regs[] = {
+ PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_qvga_regs[] = {
+ PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_cif_regs[] = {
+ PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_vga_regs[] = {
+ PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_svga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_xga_regs[] = {
+ PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_sxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_uxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+#define OV2640_SIZE(n, w, h, r) \
+ {.name = n, .width = w , .height = h, .regs = r }
+
+static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
+ OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
+ OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
+ OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
+ OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
+ OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
+ OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
+ OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
+ OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+};
+
+/*
+ * Register settings for pixel formats
+ */
+static const struct regval_list ov2640_format_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_yuv422_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },
+ { 0xD7, 0x01 },
+ { 0x33, 0xa0 },
+ { 0xe1, 0x67 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_rgb565_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },
+ { 0xd7, 0x03 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static enum v4l2_mbus_pixelcode ov2640_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/*
+ * Supported controls
+ */
+static const struct v4l2_queryctrl ov2640_controls[] = {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+/*
+ * General functions
+ */
+static struct ov2640_priv *to_ov2640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov2640_priv,
+ subdev);
+}
+
+static int ov2640_write_array(struct i2c_client *client,
+ const struct regval_list *vals)
+{
+ int ret;
+
+ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {
+ ret = i2c_smbus_write_byte_data(client,
+ vals->reg_num, vals->value);
+ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",
+ vals->reg_num, vals->value);
+
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ return 0;
+}
+
+static int ov2640_mask_set(struct i2c_client *client,
+ u8 reg, u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, reg);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ov2640_reset(struct i2c_client *client)
+{
+ int ret;
+ const struct regval_list reset_seq[] = {
+ {BANK_SEL, BANK_SEL_SENS},
+ {COM7, COM7_SRST},
+ ENDMARKER,
+ };
+
+ ret = ov2640_write_array(client, reset_seq);
+ if (ret)
+ goto err;
+
+ msleep(5);
+err:
+ dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);
+ return ret;
+}
+
+/*
+ * soc_camera_ops functions
+ */
+static int ov2640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+static int ov2640_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
+
+ /* Only one width bit may be set */
+ if (!is_power_of_2(width_flag))
+ return -EINVAL;
+
+ if (icl->set_bus_param)
+ return icl->set_bus_param(icl, width_flag);
+
+ /*
+ * Without board specific bus width settings we support only the
+ * sensors native bus width witch are tested working
+ */
+ if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8))
+ return 0;
+
+ return 0;
+}
+
+static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH;
+
+ if (icl->query_bus_param)
+ flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
+ else
+ flags |= SOCAM_DATAWIDTH_10;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ ctrl->value = priv->flag_vflip;
+ break;
+ case V4L2_CID_HFLIP:
+ ctrl->value = priv->flag_hflip;
+ break;
+ }
+ return 0;
+}
+
+static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+ int ret = 0;
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->value ? REG04_VFLIP_IMG : 0x00;
+ priv->flag_vflip = ctrl->value ? 1 : 0;
+ ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val);
+ break;
+ case V4L2_CID_HFLIP:
+ val = ctrl->value ? REG04_HFLIP_IMG : 0x00;
+ priv->flag_hflip = ctrl->value ? 1 : 0;
+ ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
+ break;
+ }
+
+ return ret;
+}
+
+static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ id->ident = priv->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov2640_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 1;
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+
+ return 0;
+}
+
+static int ov2640_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+/* Select the nearest higher resolution for capture */
+static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
+{
+ int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
+
+ for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
+ if (ov2640_supported_win_sizes[i].width >= *width &&
+ ov2640_supported_win_sizes[i].height >= *height) {
+ *width = ov2640_supported_win_sizes[i].width;
+ *height = ov2640_supported_win_sizes[i].height;
+ return &ov2640_supported_win_sizes[i];
+ }
+ }
+
+ *width = ov2640_supported_win_sizes[default_size].width;
+ *height = ov2640_supported_win_sizes[default_size].height;
+ return &ov2640_supported_win_sizes[default_size];
+}
+
+static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
+ enum v4l2_mbus_pixelcode code)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ const struct regval_list *selected_cfmt_regs;
+ int ret;
+
+ /* select win */
+ priv->win = ov2640_select_win(width, height);
+
+ /* select format */
+ priv->cfmt_code = 0;
+ switch (code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__);
+ selected_cfmt_regs = ov2640_rgb565_regs;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__);
+ selected_cfmt_regs = ov2640_yuv422_regs;
+ }
+
+ /* reset hardware */
+ ov2640_reset(client);
+
+ /* initialize the sensor with default data */
+ dev_dbg(&client->dev, "%s: Init default", __func__);
+ ret = ov2640_write_array(client, ov2640_init_regs);
+ if (ret < 0)
+ goto err;
+
+ /* select preamble */
+ dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
+ ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set size win */
+ ret = ov2640_write_array(client, priv->win->regs);
+ if (ret < 0)
+ goto err;
+
+ /* cfmt preamble */
+ dev_dbg(&client->dev, "%s: Set cfmt", __func__);
+ ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set cfmt */
+ ret = ov2640_write_array(client, selected_cfmt_regs);
+ if (ret < 0)
+ goto err;
+
+ priv->cfmt_code = code;
+ *width = priv->win->width;
+ *height = priv->win->height;
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "%s: Error %d", __func__, ret);
+ ov2640_reset(client);
+ priv->win = NULL;
+
+ return ret;
+}
+
+static int ov2640_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ if (!priv->win) {
+ u32 width = W_SVGA, height = H_SVGA;
+ int ret = ov2640_set_params(client, &width, &height,
+ V4L2_MBUS_FMT_UYVY8_2X8);
+ if (ret < 0)
+ return ret;
+ }
+
+ mf->width = priv->win->width;
+ mf->height = priv->win->height;
+ mf->code = priv->cfmt_code;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov2640_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code);
+
+ return ret;
+}
+
+static int ov2640_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct ov2640_win_size *win;
+
+ /*
+ * select suitable win
+ */
+ win = ov2640_select_win(&mf->width, &mf->height);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ return 0;
+}
+
+static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov2640_codes))
+ return -EINVAL;
+
+ *code = ov2640_codes[index];
+ return 0;
+}
+
+static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = W_UXGA;
+ a->c.height = H_UXGA;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = W_UXGA;
+ a->bounds.height = H_UXGA;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov2640_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ u8 pid, ver, midh, midl;
+ const char *devname;
+ int ret;
+
+ /*
+ * we must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant.
+ */
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
+ dev_err(&client->dev, "Parent missing or invalid!\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
+ pid = i2c_smbus_read_byte_data(client, PID);
+ ver = i2c_smbus_read_byte_data(client, VER);
+ midh = i2c_smbus_read_byte_data(client, MIDH);
+ midl = i2c_smbus_read_byte_data(client, MIDL);
+
+ switch (VERSION(pid, ver)) {
+ case PID_OV2640:
+ devname = "ov2640";
+ priv->model = V4L2_IDENT_OV2640;
+ break;
+ default:
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_info(&client->dev,
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname, pid, ver, midh, midl);
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static struct soc_camera_ops ov2640_ops = {
+ .set_bus_param = ov2640_set_bus_param,
+ .query_bus_param = ov2640_query_bus_param,
+ .controls = ov2640_controls,
+ .num_controls = ARRAY_SIZE(ov2640_controls),
+};
+
+static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
+ .g_ctrl = ov2640_g_ctrl,
+ .s_ctrl = ov2640_s_ctrl,
+ .g_chip_ident = ov2640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov2640_g_register,
+ .s_register = ov2640_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
+ .s_stream = ov2640_s_stream,
+ .g_mbus_fmt = ov2640_g_fmt,
+ .s_mbus_fmt = ov2640_s_fmt,
+ .try_mbus_fmt = ov2640_try_fmt,
+ .cropcap = ov2640_cropcap,
+ .g_crop = ov2640_g_crop,
+ .enum_mbus_fmt = ov2640_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov2640_subdev_ops = {
+ .core = &ov2640_subdev_core_ops,
+ .video = &ov2640_subdev_video_ops,
+};
+
+/*
+ * i2c_driver functions
+ */
+static int ov2640_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov2640_priv *priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
+ if (!icl) {
+ dev_err(&adapter->dev,
+ "OV2640: Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&adapter->dev,
+ "OV2640: I2C-Adapter doesn't support SMBUS\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&adapter->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ priv->info = icl->priv;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
+
+ icd->ops = &ov2640_ops;
+
+ ret = ov2640_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ kfree(priv);
+ } else {
+ dev_info(&adapter->dev, "OV2640 Probed\n");
+ }
+
+ return ret;
+}
+
+static int ov2640_remove(struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ icd->ops = NULL;
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov2640_id[] = {
+ { "ov2640", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov2640_id);
+
+static struct i2c_driver ov2640_i2c_driver = {
+ .driver = {
+ .name = "ov2640",
+ },
+ .probe = ov2640_probe,
+ .remove = ov2640_remove,
+ .id_table = ov2640_id,
+};
+
+/*
+ * Module functions
+ */
+static int __init ov2640_module_init(void)
+{
+ return i2c_add_driver(&ov2640_i2c_driver);
+}
+
+static void __exit ov2640_module_exit(void)
+{
+ i2c_del_driver(&ov2640_i2c_driver);
+}
+
+module_init(ov2640_module_init);
+module_exit(ov2640_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
+MODULE_AUTHOR("Alberto Panizzo");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
index b7cfeab0948c..cf93de988068 100644
--- a/drivers/media/video/ov6650.c
+++ b/drivers/media/video/ov6650.c
@@ -754,7 +754,7 @@ static int ov6650_g_fmt(struct v4l2_subdev *sd,
static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
{
- return (width > rect->width >> 1 || height > rect->height >> 1);
+ return width > rect->width >> 1 || height > rect->height >> 1;
}
static u8 to_clkrc(struct v4l2_fract *timeperframe,
@@ -840,8 +840,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
coma_set |= COMA_RAW_RGB | COMA_RGB;
break;
- case 0:
- break;
default:
dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
return -EINVAL;
@@ -1176,7 +1174,6 @@ static int ov6650_probe(struct i2c_client *client,
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1187,7 +1184,6 @@ static int ov6650_remove(struct i2c_client *client)
{
struct ov6650 *priv = to_ov6650(client);
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index a84b770352f9..48895ef863ff 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -600,7 +600,7 @@ static int ov772x_reset(struct i2c_client *client)
static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
if (!enable) {
ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
@@ -645,8 +645,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -665,7 +664,7 @@ static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
int ret = 0;
u8 val;
@@ -715,8 +714,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
id->ident = priv->model;
id->revision = 0;
@@ -955,7 +953,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
if (!priv->win || !priv->cfmt) {
u32 width = VGA_WIDTH, height = VGA_HEIGHT;
@@ -978,7 +976,7 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
int ret = ov772x_set_params(client, &mf->width, &mf->height,
mf->code);
@@ -991,8 +989,7 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd,
static int ov772x_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
const struct ov772x_win_size *win;
int i;
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 99e9e1d3c83b..53d88a2ab920 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -31,6 +31,8 @@
#include "ov9640.h"
+#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev)
+
/* default register setup */
static const struct ov9640_reg ov9640_regs_dflt[] = {
{ OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
@@ -308,9 +310,7 @@ static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd)
/* Get status of additional camera capabilities */
static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -327,8 +327,7 @@ static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
int ret = 0;
@@ -360,9 +359,7 @@ static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
id->ident = priv->model;
id->revision = priv->revision;
@@ -654,7 +651,8 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int ov9640_video_probe(struct soc_camera_device *icd,
struct i2c_client *client)
{
- struct ov9640_priv *priv = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
u8 pid, ver, midh, midl;
const char *devname;
int ret = 0;
@@ -791,7 +789,8 @@ static int ov9640_probe(struct i2c_client *client,
static int ov9640_remove(struct i2c_client *client)
{
- struct ov9640_priv *priv = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
kfree(priv);
return 0;
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 7129b50757db..7551907f8c28 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = pms_read,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 55ea914c7fcd..7d5a7139a45a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -203,7 +203,7 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
*blen = 0;
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_enum) {
- const char **names;
+ const char * const *names;
names = cptr->info->def.type_enum.value_names;
if (pvr2_ctrl_range_check(cptr,val) == 0) {
if (names[val]) {
@@ -367,7 +367,7 @@ static const char *boolNames[] = {
static int parse_token(const char *ptr,unsigned int len,
int *valptr,
- const char **names,unsigned int namecnt)
+ const char * const *names, unsigned int namecnt)
{
char buf[33];
unsigned int slen;
@@ -559,7 +559,7 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
ret = 0;
} else if (cptr->info->type == pvr2_ctl_enum) {
- const char **names;
+ const char * const *names;
names = cptr->info->def.type_enum.value_names;
if ((val >= 0) &&
(val < cptr->info->def.type_enum.count)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index cb4057bb07a0..ac94a8bf883e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -115,7 +115,7 @@ struct pvr2_ctl_info {
} type_int;
struct { /* enumerated control */
unsigned int count; /* enum value count */
- const char **value_names; /* symbol names */
+ const char * const *value_names; /* symbol names */
} type_enum;
struct { /* bitmask control */
unsigned int valid_bits; /* bits in use */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index bef202752cc8..66ad516bdfd9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2088,16 +2088,14 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
" Setting up with specified i2c address 0x%x",
mid, i2caddr[0]);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- NULL, fname,
- i2caddr[0], NULL);
+ fname, i2caddr[0], NULL);
} else {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with address probe list",
mid);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- NULL, fname,
- 0, i2caddr);
+ fname, 0, i2caddr);
}
if (!sd) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 3d7e5aab547f..281806b2df62 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -647,7 +647,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"device_register failed");
- kfree(class_dev);
+ put_device(class_dev);
return;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index aaafa0398fd5..58617fc656c2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -852,8 +852,8 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
#endif
default :
- ret = v4l_compat_translate_ioctl(file, cmd,
- arg, pvr2_v4l2_do_ioctl);
+ ret = -EINVAL;
+ break;
}
pvr2_hdw_commit_ctl(hdw);
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 6b8fbddc0747..1593f8deb810 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1386,11 +1386,16 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
ARG_DEF(int, qual)
+ if (pdev->iso_init) {
+ ret = -EBUSY;
+ break;
+ }
+
ARG_IN(qual)
if (ARGR(qual) < 0 || ARGR(qual) > 3)
ret = -EINVAL;
else
- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
+ ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
if (ret >= 0)
pdev->vcompression = ARGR(qual);
break;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index e62beb4efdb4..bd1519a4ecb4 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -62,7 +62,6 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
#include <linux/usb/input.h>
#endif
@@ -288,14 +287,13 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
/* create frame buffers, and make circular ring */
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data == NULL) {
- kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+ kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
if (kbuf == NULL) {
PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
return -ENOMEM;
}
PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
pdev->fbuf[i].data = kbuf;
- memset(kbuf, 0, PWC_FRAME_SIZE);
}
}
@@ -900,10 +898,13 @@ int pwc_isoc_init(struct pwc_device *pdev)
/* link */
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
- if (ret)
+ if (ret) {
PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
- else
- PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+ pdev->iso_init = 1;
+ pwc_isoc_cleanup(pdev);
+ return ret;
+ }
+ PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
/* All is done... */
@@ -959,7 +960,7 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
/* Stop camera, but only if we are sure the camera is still there (unplug
is signalled by EPIPE)
*/
- if (pdev->error_status && pdev->error_status != EPIPE) {
+ if (pdev->error_status != EPIPE) {
PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
}
@@ -968,36 +969,6 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
-{
- int ret, start;
-
- /* Stop isoc stuff */
- pwc_isoc_cleanup(pdev);
- /* Reset parameters */
- pwc_reset_buffers(pdev);
- /* Try to set video mode... */
- start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
- if (ret) {
- PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
- /* That failed... restore old mode (we know that worked) */
- start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (start) {
- PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
- }
- }
- if (start == 0)
- {
- if (pwc_isoc_init(pdev) < 0)
- {
- PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
- ret = -EAGAIN; /* let's try again, who knows if it works a second time */
- }
- }
- pdev->drop_frames++; /* try to avoid garbage during switch */
- return ret; /* Return original error code */
-}
-
/*********
* sysfs
*********/
@@ -1177,7 +1148,7 @@ static int pwc_video_open(struct file *file)
/* Set some defaults */
pdev->vsnapshot = 0;
- /* Start iso pipe for video; first try the last used video size
+ /* Set video size, first try the last used video size
(or the default one); if that fails try QCIF/10 or QSIF/10;
it that fails too, give up.
*/
@@ -1204,15 +1175,6 @@ static int pwc_video_open(struct file *file)
return i;
}
- i = pwc_isoc_init(pdev);
- if (i) {
- PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
- pwc_isoc_cleanup(pdev);
- pwc_free_buffers(pdev);
- mutex_unlock(&pdev->modlock);
- return i;
- }
-
/* Initialize the webcam to sane value */
pwc_set_brightness(pdev, 0x7fff);
pwc_set_agc(pdev, 1, 0);
@@ -1327,6 +1289,11 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
goto err_out;
}
+ /* Start the stream (if not already started) */
+ rv = pwc_isoc_init(pdev);
+ if (rv)
+ 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) {
/* Do wait queueing according to the (doc)book */
@@ -1396,6 +1363,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
+ int ret;
if (vdev == NULL)
return -EFAULT;
@@ -1403,6 +1371,13 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
if (pdev == NULL)
return -EFAULT;
+ /* Start the stream (if not already started) */
+ mutex_lock(&pdev->modlock);
+ ret = pwc_isoc_init(pdev);
+ mutex_unlock(&pdev->modlock);
+ if (ret)
+ return ret;
+
poll_wait(file, &pdev->frameq, wait);
if (pdev->error_status)
return POLLERR;
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 7061a03f5cf1..8ca4d22b4384 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -309,7 +309,10 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
pixelformat != V4L2_PIX_FMT_PWC2)
return -EINVAL;
- PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+ if (pdev->iso_init)
+ return -EBUSY;
+
+ PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
"compression=%d snapshot=%d format=%c%c%c%c\n",
f->fmt.pix.width, f->fmt.pix.height, fps,
compression, snapshot,
@@ -318,14 +321,14 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
(pixelformat>>16)&255,
(pixelformat>>24)&255);
- ret = pwc_try_video_mode(pdev,
+ ret = pwc_set_video_mode(pdev,
f->fmt.pix.width,
f->fmt.pix.height,
fps,
compression,
snapshot);
- PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+ PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
if (ret)
return ret;
@@ -359,23 +362,6 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* mmap() functions */
- case VIDIOCGMBUF:
- {
- /* Tell the user program how much memory is needed for a mmap() */
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = pwc_mbufs * pdev->len_per_image;
- vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
- for (i = 0; i < pwc_mbufs; i++)
- vm->offsets[i] = i * pdev->len_per_image;
- break;
- }
-#endif
-
/* V4L2 Layer */
case VIDIOC_QUERYCAP:
{
@@ -882,9 +868,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_STREAMON:
{
- /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
- pwc_isoc_init(pdev);
- return 0;
+ return pwc_isoc_init(pdev);
}
case VIDIOC_STREAMOFF:
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 36a9c83b5f5d..16bbc6df9b07 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -275,7 +275,6 @@ extern int pwc_trace;
extern int pwc_mbufs;
/** functions in pwc-if.c */
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
int pwc_handle_frame(struct pwc_device *pdev);
void pwc_next_image(struct pwc_device *pdev);
int pwc_isoc_init(struct pwc_device *pdev);
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index c143ed0a5270..02686771740d 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -852,7 +852,7 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
*/
videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct pxa_buffer), icd, NULL);
+ sizeof(struct pxa_buffer), icd, &icd->video_lock);
}
static u32 mclk_get_divisor(struct platform_device *pdev,
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index d2fa2d43ff19..57e11b6f19fb 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1460,7 +1460,6 @@ static int rj54n1_remove(struct i2c_client *client)
icd->ops = NULL;
if (icl->free_bus)
icl->free_bus(icl);
- client->driver = NULL;
kfree(rj54n1);
return 0;
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index f5a46c458717..b63f8cafa671 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -49,7 +49,6 @@
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@@ -269,7 +268,7 @@ struct s2255_dev {
struct v4l2_device v4l2_dev;
atomic_t num_channels;
int frames;
- struct mutex lock;
+ struct mutex lock; /* channels[].vdev.lock */
struct mutex open_lock;
struct usb_device *udev;
struct usb_interface *interface;
@@ -781,20 +780,14 @@ static struct videobuf_queue_ops s2255_video_qops = {
static int res_get(struct s2255_fh *fh)
{
- struct s2255_dev *dev = fh->dev;
- /* is it free? */
struct s2255_channel *channel = fh->channel;
- mutex_lock(&dev->lock);
- if (channel->resources) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
+ /* is it free? */
+ if (channel->resources)
+ return 0; /* no, someone else uses it */
/* it's free, grab it */
channel->resources = 1;
fh->resources = 1;
dprintk(1, "s2255: res: get\n");
- mutex_unlock(&dev->lock);
return 1;
}
@@ -812,11 +805,8 @@ static int res_check(struct s2255_fh *fh)
static void res_free(struct s2255_fh *fh)
{
struct s2255_channel *channel = fh->channel;
- struct s2255_dev *dev = fh->dev;
- mutex_lock(&dev->lock);
channel->resources = 0;
fh->resources = 0;
- mutex_unlock(&dev->lock);
dprintk(1, "res: put\n");
}
@@ -1107,15 +1097,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
return rc;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct s2255_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
/* write to the configuration pipe, synchronously */
static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
int size)
@@ -1219,7 +1200,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
__le32 *buffer;
unsigned long chn_rev;
struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- mutex_lock(&dev->lock);
chn_rev = G_chnmap[channel->idx];
dprintk(3, "%s channel: %d\n", __func__, channel->idx);
/* if JPEG, set the quality */
@@ -1236,7 +1216,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
/* set the mode */
@@ -1261,7 +1240,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
}
/* clear the restart flag */
channel->mode.restart = 0;
- mutex_unlock(&dev->lock);
dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
return res;
}
@@ -1272,13 +1250,11 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
__le32 *buffer;
u32 chn_rev;
struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- mutex_lock(&dev->lock);
chn_rev = G_chnmap[channel->idx];
dprintk(4, "%s chan %d\n", __func__, channel->idx);
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
/* form the get vid status command */
@@ -1298,7 +1274,6 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
}
*pstatus = channel->vidstatus;
dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
- mutex_unlock(&dev->lock);
return res;
}
@@ -1817,7 +1792,8 @@ static int s2255_open(struct file *file)
NULL, &dev->slock,
fh->type,
V4L2_FIELD_INTERLACED,
- sizeof(struct s2255_buffer), fh, NULL);
+ sizeof(struct s2255_buffer),
+ fh, vdev->lock);
return 0;
}
@@ -1900,7 +1876,7 @@ static const struct v4l2_file_operations s2255_fops_v4l = {
.open = s2255_open,
.release = s2255_release,
.poll = s2255_poll,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = s2255_mmap_v4l,
};
@@ -1924,9 +1900,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidioc_cgmbuf,
-#endif
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
.vidioc_s_parm = vidioc_s_parm,
@@ -1970,6 +1943,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
channel->vidq.dev = dev;
/* register 4 video devices */
channel->vdev = template;
+ channel->vdev.lock = &dev->lock;
channel->vdev.v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(&channel->vdev, channel);
if (video_nr == -1)
@@ -2676,7 +2650,9 @@ static void s2255_disconnect(struct usb_interface *interface)
struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
int i;
int channels = atomic_read(&dev->num_channels);
+ mutex_lock(&dev->lock);
v4l2_device_disconnect(&dev->v4l2_dev);
+ mutex_unlock(&dev->lock);
/*see comments in the uvc_driver.c usb disconnect function */
atomic_inc(&dev->num_channels);
/* unregister each video device. */
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index e8f13d3e2df1..2f500809f53d 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -44,7 +44,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
return ERR_PTR(-ENOMEM);
sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
- MODULE_NAME, isp_info->board_info, NULL);
+ isp_info->board_info, NULL);
if (!sd) {
v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
return NULL;
@@ -522,6 +522,7 @@ static int fimc_cap_streamon(struct file *file, void *priv,
INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
fimc->vid_cap.active_buf_cnt = 0;
fimc->vid_cap.frame_count = 0;
+ fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc);
set_bit(ST_CAPT_PEND, &fimc->state);
ret = videobuf_streamon(&fimc->vid_cap.vbq);
@@ -652,6 +653,50 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv,
return ret;
}
+static int fimc_cap_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = f->o_width;
+ cr->bounds.height = f->o_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->c.left = f->offs_h;
+ cr->c.top = f->offs_v;
+ cr->c.width = f->width;
+ cr->c.height = f->height;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
static int fimc_cap_s_crop(struct file *file, void *fh,
struct v4l2_crop *cr)
{
@@ -716,9 +761,9 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_cap_s_ctrl,
- .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_g_crop = fimc_cap_g_crop,
.vidioc_s_crop = fimc_cap_s_crop,
- .vidioc_cropcap = fimc_vidioc_cropcap,
+ .vidioc_cropcap = fimc_cap_cropcap,
.vidioc_enum_input = fimc_cap_enum_input,
.vidioc_s_input = fimc_cap_s_input,
@@ -785,7 +830,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
vid_cap->v4l2_dev.dev, &fimc->irqlock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct fimc_vid_buffer), (void *)ctx);
+ sizeof(struct fimc_vid_buffer), (void *)ctx, NULL);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret) {
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 2e7c547894b6..817aa66627f6 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -50,8 +50,8 @@ static struct fimc_fmt fimc_formats[] = {
.planes_cnt = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "XRGB-8-8-8-8, 24 bpp",
- .fourcc = V4L2_PIX_FMT_RGB24,
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.color = S5P_FIMC_RGB888,
.buff_cnt = 1,
@@ -543,7 +543,7 @@ static void fimc_dma_run(void *priv)
unsigned long flags;
u32 ret;
- if (WARN(!ctx, "null hardware context"))
+ if (WARN(!ctx, "null hardware context\n"))
return;
fimc = ctx->fimc_dev;
@@ -983,6 +983,7 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv,
{
struct fimc_ctx *ctx = priv;
struct v4l2_queryctrl *c;
+ int ret = -EINVAL;
c = get_ctrl(qc->id);
if (c) {
@@ -990,10 +991,14 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv,
return 0;
}
- if (ctx->state & FIMC_CTX_CAP)
- return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ if (ctx->state & FIMC_CTX_CAP) {
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+ ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
core, queryctrl, qc);
- return -EINVAL;
+ mutex_unlock(&ctx->fimc_dev->lock);
+ }
+ return ret;
}
int fimc_vidioc_g_ctrl(struct file *file, void *priv,
@@ -1115,7 +1120,7 @@ static int fimc_m2m_s_ctrl(struct file *file, void *priv,
return 0;
}
-int fimc_vidioc_cropcap(struct file *file, void *fh,
+static int fimc_m2m_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *cr)
{
struct fimc_frame *frame;
@@ -1139,7 +1144,7 @@ int fimc_vidioc_cropcap(struct file *file, void *fh,
return 0;
}
-int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
@@ -1167,22 +1172,22 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
struct fimc_frame *f;
u32 min_size, halign;
- f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
- &ctx->s_frame : &ctx->d_frame;
-
if (cr->c.top < 0 || cr->c.left < 0) {
v4l2_err(&fimc->m2m.v4l2_dev,
"doesn't support negative values for top & left\n");
return -EINVAL;
}
- f = ctx_get_frame(ctx, cr->type);
- if (IS_ERR(f))
- return PTR_ERR(f);
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame;
+ else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ ctx->state & FIMC_CTX_M2M)
+ f = &ctx->s_frame;
+ else
+ return -EINVAL;
- min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- ? fimc->variant->min_inp_pixsize
- : fimc->variant->min_out_pixsize;
+ min_size = (f == &ctx->s_frame) ?
+ fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
if (ctx->state & FIMC_CTX_M2M) {
if (fimc->id == 1 && fimc->variant->pix_hoff)
@@ -1233,6 +1238,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
&ctx->s_frame : &ctx->d_frame;
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
spin_lock_irqsave(&ctx->slock, flags);
if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
/* Check to see if scaling ratio is within supported range */
@@ -1241,9 +1249,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
else
ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
if (ret) {
- spin_unlock_irqrestore(&ctx->slock, flags);
v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
- return -EINVAL;
+ ret = -EINVAL;
+ goto scr_unlock;
}
}
ctx->state |= FIMC_PARAMS;
@@ -1253,7 +1261,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
f->width = cr->c.width;
f->height = cr->c.height;
+scr_unlock:
spin_unlock_irqrestore(&ctx->slock, flags);
+ mutex_unlock(&fimc->lock);
return 0;
}
@@ -1285,9 +1295,9 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_m2m_s_ctrl,
- .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_g_crop = fimc_m2m_g_crop,
.vidioc_s_crop = fimc_m2m_s_crop,
- .vidioc_cropcap = fimc_vidioc_cropcap
+ .vidioc_cropcap = fimc_m2m_cropcap
};
@@ -1396,7 +1406,7 @@ static const struct v4l2_file_operations fimc_m2m_fops = {
.open = fimc_m2m_open,
.release = fimc_m2m_release,
.poll = fimc_m2m_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = fimc_m2m_mmap,
};
@@ -1736,6 +1746,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
+ .has_cistatus2 = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 1,
@@ -1745,6 +1756,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
.pix_hoff = 1,
+ .has_cistatus2 = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 1,
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 3e1078516560..4f047d35f8ad 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -13,13 +13,15 @@
/*#define DEBUG*/
+#include <linux/sched.h>
#include <linux/types.h>
+#include <linux/videodev2.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-mediabus.h>
#include <media/s3c_fimc.h>
-#include <linux/videodev2.h>
+
#include "regs-fimc.h"
#define err(fmt, args...) \
@@ -369,6 +371,7 @@ struct fimc_pix_limit {
* @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
* @has_inp_rot: set if has input rotator
* @has_out_rot: set if has output rotator
+ * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
* @pix_limit: pixel size constraints for the scaler
* @min_inp_pixsize: minimum input pixel size
* @min_out_pixsize: minimum output pixel size
@@ -379,6 +382,7 @@ struct samsung_fimc_variant {
unsigned int pix_hoff:1;
unsigned int has_inp_rot:1;
unsigned int has_out_rot:1;
+ unsigned int has_cistatus2:1;
struct fimc_pix_limit *pix_limit;
u16 min_inp_pixsize;
u16 min_out_pixsize;
@@ -554,11 +558,19 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
+/* Return an index to the buffer actually being written. */
static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
{
- u32 reg = readl(dev->regs + S5P_CISTATUS);
- return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
- S5P_CISTATUS_FRAMECNT_SHIFT;
+ u32 reg;
+
+ if (dev->variant->has_cistatus2) {
+ reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F;
+ return reg > 0 ? --reg : reg;
+ } else {
+ reg = readl(dev->regs + S5P_CISTATUS);
+ return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+ S5P_CISTATUS_FRAMECNT_SHIFT;
+ }
}
/* -----------------------------------------------------*/
@@ -594,10 +606,6 @@ int fimc_vidioc_g_fmt(struct file *file, void *priv,
struct v4l2_format *f);
int fimc_vidioc_try_fmt(struct file *file, void *priv,
struct v4l2_format *f);
-int fimc_vidioc_g_crop(struct file *file, void *fh,
- struct v4l2_crop *cr);
-int fimc_vidioc_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr);
int fimc_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc);
int fimc_vidioc_g_ctrl(struct file *file, void *priv,
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
index a57daedb5b5c..57e33f84fcfa 100644
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ b/drivers/media/video/s5p-fimc/regs-fimc.h
@@ -165,6 +165,9 @@
#define S5P_CISTATUS_VVALID_A (1 << 15)
#define S5P_CISTATUS_VVALID_B (1 << 14)
+/* Indexes to the last and the currently processed buffer. */
+#define S5P_CISTATUS2 0x68
+
/* Image capture control */
#define S5P_CIIMGCPT 0xc0
#define S5P_CIIMGCPT_IMGCPTEN (1 << 31)
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 984c0feb2a4e..99a2ac16f9e5 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,7 +31,7 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
@@ -181,7 +181,7 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
return 1;
}
-static void read_from_buf(struct saa6588 *s, struct rds_command *a)
+static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
{
unsigned long flags;
@@ -392,25 +392,25 @@ static void saa6588_configure(struct saa6588 *s)
static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct saa6588 *s = to_saa6588(sd);
- struct rds_command *a = arg;
+ struct saa6588_command *a = arg;
switch (cmd) {
/* --- open() for /dev/radio --- */
- case RDS_CMD_OPEN:
+ case SAA6588_CMD_OPEN:
a->result = 0; /* return error if chip doesn't work ??? */
break;
/* --- close() for /dev/radio --- */
- case RDS_CMD_CLOSE:
+ case SAA6588_CMD_CLOSE:
s->data_available_for_read = 1;
wake_up_interruptible(&s->read_queue);
a->result = 0;
break;
/* --- read() for /dev/radio --- */
- case RDS_CMD_READ:
+ case SAA6588_CMD_READ:
read_from_buf(s, a);
break;
/* --- poll() for /dev/radio --- */
- case RDS_CMD_POLL:
+ case SAA6588_CMD_POLL:
a->result = 0;
if (s->data_available_for_read) {
a->result |= POLLIN | POLLRDNORM;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 301c62b88cad..f35459d1f42f 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1348,8 +1348,17 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
int reg1e;
*std = V4L2_STD_ALL;
- if (state->ident != V4L2_IDENT_SAA7115)
+ if (state->ident != V4L2_IDENT_SAA7115) {
+ int reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+
+ if (reg1f & 0x20)
+ *std = V4L2_STD_525_60;
+ else
+ *std = V4L2_STD_625_50;
+
return 0;
+ }
+
reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
switch (reg1e & 0x03) {
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 3fe71be41a1f..380f1b28cfcc 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -26,7 +26,7 @@ config VIDEO_SAA7134_ALSA
config VIDEO_SAA7134_RC
bool "Philips SAA7134 Remote Controller support"
- depends on VIDEO_IR
+ depends on RC_CORE
depends on VIDEO_SAA7134
default y
---help---
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 10a6cbf6a790..e7aa588c6c5a 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5176,6 +5176,58 @@ struct saa7134_board saa7134_boards[] = {
.amux = 2,
},
},
+ [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
+ .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
+ .audio_clock = 0x00187de7,
+#if 0
+ /*
+ * FIXME: Analog mode doesn't work, if digital is enabled. The proper
+ * fix is to use tda8290 driver, but Kworld seems to use an
+ * unsupported version of tda8295.
+ */
+ .tuner_type = TUNER_NXP_TDA18271, /* TUNER_PHILIPS_TDA8290 */
+ .tuner_addr = 0x60,
+#else
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+#endif
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x8e054000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+#if 0 /* FIXME */
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+#endif
+ } },
+#if 0
+ .radio = {
+ .name = name_radio,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+#endif
+ .mute = {
+ .name = name_mute,
+ .vmux = 0,
+ .amux = TV,
+ },
+ },
[SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = {
.name = "Avermedia AVerTV GO 007 FM Plus",
.audio_clock = 0x00187de7,
@@ -5486,6 +5538,37 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
} },
},
+ [SAA7134_BOARD_VIDEOMATE_M1F] = {
+ /* Pavel Osnova <pvosnova@gmail.com> */
+ .name = "Compro VideoMate Vista M1F",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ },
+ },
};
@@ -6615,6 +6698,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0xb136,
+ .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0xf31d,
.driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
@@ -6661,6 +6750,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2804,
.driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7190,
+ .driver_data = SAA7134_BOARD_BEHOLD_H7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7090,
+ .driver_data = SAA7134_BOARD_BEHOLD_A7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7135,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_M1F,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -6698,18 +6805,6 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
- .subdevice = 0x7190,
- .driver_data = SAA7134_BOARD_BEHOLD_H7,
- }, {
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
- .subdevice = 0x7090,
- .driver_data = SAA7134_BOARD_BEHOLD_A7,
},{
/* --- end of list --- */
}
@@ -6831,6 +6926,23 @@ static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
return 0;
}
+static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 27 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 27, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 27, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
int command, int arg)
{
@@ -6843,6 +6955,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
+ break;
default:
break;
}
@@ -6863,6 +6978,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
case SAA7134_BOARD_AVERMEDIA_M733A:
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
break;
@@ -6967,6 +7083,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_VIDEOMATE_M1F:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -7541,6 +7658,37 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name);
break;
}
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ {
+ struct i2c_msg msg = { .addr = 0x4b, .flags = 0 };
+ int i;
+ static u8 buffer[][2] = {
+ {0x30, 0x31},
+ {0xff, 0x00},
+ {0x41, 0x03},
+ {0x41, 0x1a},
+ {0xff, 0x02},
+ {0x34, 0x00},
+ {0x45, 0x97},
+ {0x45, 0xc1},
+ };
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+
+ /*
+ * FIXME: identify what device is at addr 0x4b and what means
+ * this initialization
+ */
+ for (i = 0; i < ARRAY_SIZE(buffer); i++) {
+ msg.buf = &buffer[i][0];
+ msg.len = ARRAY_SIZE(buffer[0]);
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ printk(KERN_WARNING
+ "%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
+ }
+ break;
+ }
} /* switch() */
/* initialize tuner */
@@ -7551,22 +7699,22 @@ int saa7134_board_init2(struct saa7134_dev *dev)
so we do not need to probe for a radio tuner device. */
if (dev->radio_type != UNSET)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
dev->radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == ADDR_UNSET) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "tuner",
+ &dev->i2c_adap, "tuner",
dev->tuner_addr, NULL);
}
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 764d7d219fed..6abeecff6da7 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -166,8 +166,14 @@ static void request_submodules(struct saa7134_dev *dev)
schedule_work(&dev->request_module_wk);
}
+static void flush_request_submodules(struct saa7134_dev *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
+
#else
#define request_submodules(dev)
+#define flush_request_submodules(dev)
#endif /* CONFIG_MODULES */
/* ------------------------------------------------------------------ */
@@ -991,7 +997,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "saa6752hs",
+ "saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);
if (sd)
@@ -1002,7 +1008,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, NULL, "saa6588",
+ &dev->i2c_adap, "saa6588",
0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
@@ -1010,8 +1016,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
}
}
- request_submodules(dev);
-
v4l2_prio_init(&dev->prio);
mutex_lock(&saa7134_devlist_lock);
@@ -1066,6 +1070,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (saa7134_dmasound_init && !dev->dmasound.priv_data)
saa7134_dmasound_init(dev);
+ request_submodules(dev);
return 0;
fail4:
@@ -1091,6 +1096,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
struct saa7134_mpeg_ops *mops;
+ flush_request_submodules(dev);
+
/* Release DMA sound modules if present */
if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
saa7134_dmasound_exit(dev);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index beb95e21d109..3315a48a848b 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -52,6 +52,7 @@
#include "tda18271.h"
#include "lgdt3305.h"
#include "tda8290.h"
+#include "mb86a20s.h"
#include "zl10353.h"
@@ -228,6 +229,20 @@ static struct mt352_config avermedia_xc3028_mt352_dev = {
.demod_init = mt352_avermedia_xc3028_init,
};
+static struct tda18271_std_map mb86a20s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
+static const struct mb86a20s_config kworld_mb86a20s_config = {
+ .demod_address = 0x10,
+};
+
/* ==================================================================
* tda1004x based DVB-T cards, helper functions
*/
@@ -608,6 +623,37 @@ static struct tda827x_config tda827x_cfg_2_sw42 = {
/* ------------------------------------------------------------------ */
+static int __kworld_sbtvd_i2c_gate_ctrl(struct saa7134_dev *dev, int enable)
+{
+ unsigned char initmsg[] = {0x45, 0x97};
+ unsigned char msg_enable[] = {0x45, 0xc1};
+ unsigned char msg_disable[] = {0x45, 0x81};
+ struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ if (enable)
+ msg.buf = msg_enable;
+ else
+ msg.buf = msg_disable;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+static int kworld_sbtvd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ return __kworld_sbtvd_i2c_gate_ctrl(dev, enable);
+}
+
+/* ------------------------------------------------------------------ */
+
static struct tda1004x_config tda827x_lifeview_config = {
.demod_address = 0x08,
.invert = 1,
@@ -1613,6 +1659,29 @@ static int dvb_init(struct saa7134_dev *dev)
&dtv1000s_tda18271_config);
}
break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ __kworld_sbtvd_i2c_gate_ctrl(dev, 0);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+ msleep(20);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+ msleep(20);
+ fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
+ &kworld_mb86a20s_config,
+ &dev->i2c_adap);
+ __kworld_sbtvd_i2c_gate_ctrl(dev, 1);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_tda18271_config);
+ /*
+ * Only after success, it can initialize the gate, otherwise
+ * an OOPS will hit, due to kfree(fe0->dvb.frontend)
+ */
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_i2c_gate_ctrl;
+ }
+ 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 1467a30a434f..6b8459c7728e 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -21,7 +21,6 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include "saa7134-reg.h"
@@ -554,7 +553,7 @@ static int empress_fini(struct saa7134_dev *dev)
if (NULL == dev->empress_dev)
return 0;
- flush_scheduled_work();
+ flush_work_sync(&dev->empress_workqueue);
video_unregister_device(dev->empress_dev);
dev->empress_dev = NULL;
return 0;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 46d31dfca7a3..dc646e65edb7 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/slab.h>
#include "saa7134-reg.h"
@@ -42,41 +41,19 @@ static int pinnacle_remote;
module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
-static int ir_rc5_remote_gap = 885;
-module_param(ir_rc5_remote_gap, int, 0644);
-static int ir_rc5_key_timeout = 115;
-module_param(ir_rc5_key_timeout, int, 0644);
-
-static int repeat_delay = 500;
-module_param(repeat_delay, int, 0644);
-MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
-static int repeat_period = 33;
-module_param(repeat_period, int, 0644);
-MODULE_PARM_DESC(repeat_period, "repeat period between "
- "keypresses when key is down");
-
-static unsigned int disable_other_ir;
-module_param(disable_other_ir, int, 0644);
-MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
- "alternative remotes from other manufacturers");
-
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
-/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
-static int saa7134_rc5_irq(struct saa7134_dev *dev);
-static int saa7134_nec_irq(struct saa7134_dev *dev);
+/* Helper function for raw decoding at GPIO16 or GPIO18 */
static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
-static void nec_task(unsigned long data);
-static void saa7134_nec_timer(unsigned long data);
/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
- struct card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
u32 gpio, data;
/* here comes the additional handshake steps for some cards */
@@ -104,25 +81,25 @@ static int build_key(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
if (data == ir->mask_keycode)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
else
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
return 0;
}
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
} else {
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
}
}
else { /* IRQ driven mode - handle key press and release in one go */
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keyup(ir->dev);
}
}
@@ -300,22 +277,12 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
i2cdprintk("read error\n");
return -EIO;
}
- /* IR of this card normally decode signals NEC-standard from
- * - Sven IHOO MT 5.1R remote. xxyye718
- * - Sven DVD HD-10xx remote. xxyyf708
- * - BBK ...
- * - mayby others
- * So, skip not our, if disable full codes mode.
- */
- if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
- return 0;
- /* Wrong data decode fix */
if (data[9] != (unsigned char)(~data[8]))
return 0;
- *ir_key = data[9];
- *ir_raw = data[9];
+ *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
+ *ir_key = *ir_raw;
return 1;
}
@@ -400,7 +367,7 @@ static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
if (!dev || !dev->remote)
return;
@@ -409,12 +376,8 @@ void saa7134_input_irq(struct saa7134_dev *dev)
if (!ir->running)
return;
- if (ir->nec_gpio) {
- saa7134_nec_irq(dev);
- } else if (!ir->polling && !ir->rc5_gpio && !ir->raw_decode) {
+ if (!ir->polling && !ir->raw_decode) {
build_key(dev);
- } else if (ir->rc5_gpio) {
- saa7134_rc5_irq(dev);
} else if (ir->raw_decode) {
saa7134_raw_decode_irq(dev);
}
@@ -423,7 +386,7 @@ 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 card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
build_key(dev);
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
@@ -432,57 +395,37 @@ static void saa7134_input_timer(unsigned long data)
static void ir_raw_decode_timer_end(unsigned long data)
{
struct saa7134_dev *dev = (struct saa7134_dev *)data;
- struct card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
ir_raw_event_handle(dev->remote->dev);
- ir->active = 0;
+ ir->active = false;
}
static int __saa7134_ir_start(void *priv)
{
struct saa7134_dev *dev = priv;
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
- if (!dev)
+ if (!dev || !dev->remote)
return -EINVAL;
ir = dev->remote;
- if (!ir)
- return -EINVAL;
-
if (ir->running)
return 0;
- ir->running = 1;
+ ir->running = true;
+ ir->active = false;
+
if (ir->polling) {
setup_timer(&ir->timer, saa7134_input_timer,
(unsigned long)dev);
- ir->timer.expires = jiffies + HZ;
+ ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
- } else if (ir->rc5_gpio) {
- /* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_rc5_timer_end;
- ir->timer_end.data = (unsigned long)ir;
- init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = ir_rc5_timer_keyup;
- ir->timer_keyup.data = (unsigned long)ir;
- ir->shift_by = 2;
- ir->start = 0x2;
- ir->addr = 0x17;
- ir->rc5_key_timeout = ir_rc5_key_timeout;
- ir->rc5_remote_gap = ir_rc5_remote_gap;
- } else if (ir->nec_gpio) {
- setup_timer(&ir->timer_keyup, saa7134_nec_timer,
- (unsigned long)dev);
- tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
} else if (ir->raw_decode) {
/* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_raw_decode_timer_end;
- ir->timer_end.data = (unsigned long)dev;
- ir->active = 0;
+ setup_timer(&ir->timer, ir_raw_decode_timer_end,
+ (unsigned long)dev);
}
return 0;
@@ -491,29 +434,20 @@ static int __saa7134_ir_start(void *priv)
static void __saa7134_ir_stop(void *priv)
{
struct saa7134_dev *dev = priv;
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
- if (!dev)
+ if (!dev || !dev->remote)
return;
ir = dev->remote;
- if (!ir)
- return;
-
if (!ir->running)
return;
- if (dev->remote->polling)
- del_timer_sync(&dev->remote->timer);
- else if (ir->rc5_gpio)
- del_timer_sync(&ir->timer_end);
- else if (ir->nec_gpio)
- tasklet_kill(&ir->tlet);
- else if (ir->raw_decode) {
- del_timer_sync(&ir->timer_end);
- ir->active = 0;
- }
- ir->running = 0;
+ if (ir->polling || ir->raw_decode)
+ del_timer_sync(&ir->timer);
+
+ ir->active = false;
+ ir->running = false;
return;
}
@@ -532,71 +466,33 @@ void saa7134_ir_stop(struct saa7134_dev *dev)
__saa7134_ir_stop(dev);
}
-static int saa7134_ir_open(void *priv)
+static int saa7134_ir_open(struct rc_dev *rc)
{
- struct saa7134_dev *dev = priv;
+ struct saa7134_dev *dev = rc->priv;
dev->remote->users++;
return __saa7134_ir_start(dev);
}
-static void saa7134_ir_close(void *priv)
+static void saa7134_ir_close(struct rc_dev *rc)
{
- struct saa7134_dev *dev = priv;
+ struct saa7134_dev *dev = rc->priv;
dev->remote->users--;
if (!dev->remote->users)
__saa7134_ir_stop(dev);
}
-
-static int saa7134_ir_change_protocol(void *priv, u64 ir_type)
-{
- struct saa7134_dev *dev = priv;
- struct card_ir *ir = dev->remote;
- u32 nec_gpio, rc5_gpio;
-
- if (ir_type == IR_TYPE_RC5) {
- dprintk("Changing protocol to RC5\n");
- nec_gpio = 0;
- rc5_gpio = 1;
- } else if (ir_type == IR_TYPE_NEC) {
- dprintk("Changing protocol to NEC\n");
- nec_gpio = 1;
- rc5_gpio = 0;
- } else {
- dprintk("IR protocol type %ud is not supported\n",
- (unsigned)ir_type);
- return -EINVAL;
- }
-
- if (ir->running) {
- saa7134_ir_stop(dev);
- ir->nec_gpio = nec_gpio;
- ir->rc5_gpio = rc5_gpio;
- saa7134_ir_start(dev);
- } else {
- ir->nec_gpio = nec_gpio;
- ir->rc5_gpio = rc5_gpio;
- }
-
- return 0;
-}
-
int saa7134_input_init1(struct saa7134_dev *dev)
{
- struct card_ir *ir;
- struct input_dev *input_dev;
+ struct saa7134_card_ir *ir;
+ struct rc_dev *rc;
char *ir_codes = NULL;
u32 mask_keycode = 0;
u32 mask_keydown = 0;
u32 mask_keyup = 0;
- int polling = 0;
- int rc5_gpio = 0;
- int nec_gpio = 0;
- int raw_decode = 0;
- int allow_protocol_change = 0;
- u64 ir_type = IR_TYPE_OTHER;
+ unsigned polling = 0;
+ bool raw_decode = false;
int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO)
@@ -661,14 +557,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
mask_keyup = 0x0040000;
mask_keycode = 0xffff;
- raw_decode = 1;
+ raw_decode = true;
break;
case SAA7134_BOARD_AVERMEDIA_M733A:
ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
mask_keydown = 0x0040000;
mask_keyup = 0x0040000;
mask_keycode = 0xffff;
- raw_decode = 1;
+ raw_decode = true;
break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -775,7 +671,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
mask_keyup = 0x0040000;
mask_keycode = 0xffff;
- raw_decode = 1;
+ raw_decode = true;
break;
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
@@ -786,9 +682,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ENCORE_ENLTV_FM53:
ir_codes = RC_MAP_ENCORE_ENLTV_FM53;
- mask_keydown = 0x0040000;
- mask_keycode = 0x00007f;
- nec_gpio = 1;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
break;
case SAA7134_BOARD_10MOONSTVMASTER3:
ir_codes = RC_MAP_ENCORE_ENLTV;
@@ -824,6 +721,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x020000;
polling = 50; /* ms */
break;
+ case SAA7134_BOARD_VIDEOMATE_M1F:
+ ir_codes = RC_MAP_VIDEOMATE_M1F;
+ mask_keycode = 0x0ff00;
+ mask_keyup = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -832,24 +734,20 @@ int saa7134_input_init1(struct saa7134_dev *dev)
}
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
+ rc = rc_allocate_device();
+ if (!ir || !rc) {
err = -ENOMEM;
goto err_out_free;
}
- ir->dev = input_dev;
+ ir->dev = rc;
dev->remote = ir;
- ir->running = 0;
-
/* init hardware-specific stuff */
ir->mask_keycode = mask_keycode;
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
ir->polling = polling;
- ir->rc5_gpio = rc5_gpio;
- ir->nec_gpio = nec_gpio;
ir->raw_decode = raw_decode;
/* init input device */
@@ -858,47 +756,35 @@ int saa7134_input_init1(struct saa7134_dev *dev)
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(dev->pci));
-
- ir->props.priv = dev;
- ir->props.open = saa7134_ir_open;
- ir->props.close = saa7134_ir_close;
-
+ rc->priv = dev;
+ rc->open = saa7134_ir_open;
+ rc->close = saa7134_ir_close;
if (raw_decode)
- ir->props.driver_type = RC_DRIVER_IR_RAW;
-
- if (!raw_decode && allow_protocol_change) {
- ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
- ir->props.change_protocol = saa7134_ir_change_protocol;
- }
-
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
+ rc->driver_type = RC_DRIVER_IR_RAW;
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (dev->pci->subsystem_vendor) {
- input_dev->id.vendor = dev->pci->subsystem_vendor;
- input_dev->id.product = dev->pci->subsystem_device;
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
} else {
- input_dev->id.vendor = dev->pci->vendor;
- input_dev->id.product = dev->pci->device;
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
}
- input_dev->dev.parent = &dev->pci->dev;
+ rc->dev.parent = &dev->pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
- err = ir_input_register(ir->dev, ir_codes, &ir->props, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_free;
- /* the remote isn't as bouncy as a keyboard */
- ir->dev->rep[REP_DELAY] = repeat_delay;
- ir->dev->rep[REP_PERIOD] = repeat_period;
-
return 0;
err_out_free:
+ rc_free_device(rc);
dev->remote = NULL;
kfree(ir);
return err;
@@ -910,7 +796,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
return;
saa7134_ir_stop(dev);
- ir_input_unregister(dev->remote->dev);
+ rc_unregister_device(dev->remote->dev);
kfree(dev->remote);
dev->remote = NULL;
}
@@ -918,14 +804,12 @@ void saa7134_input_fini(struct saa7134_dev *dev)
void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
{
struct i2c_board_info info;
-
struct i2c_msg msg_msi = {
.addr = 0x50,
.flags = I2C_M_RD,
.len = 0,
.buf = NULL,
};
-
int rc;
if (disable_ir) {
@@ -972,7 +856,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
an existing device. Weird...
REVISIT: might no longer be needed */
rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
- dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+ dprintk("probe 0x%02x @ %s: %s\n",
msg_msi.addr, dev->i2c_adap.name,
(1 == rc) ? "yes" : "no");
break;
@@ -1000,7 +884,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
dev->init_data.name = "BeholdTV";
dev->init_data.get_key = get_key_beholdm6xx;
dev->init_data.ir_codes = RC_MAP_BEHOLD;
- dev->init_data.type = IR_TYPE_NEC;
+ dev->init_data.type = RC_TYPE_NEC;
info.addr = 0x2d;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
@@ -1025,8 +909,8 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
{
- struct card_ir *ir = dev->remote;
- unsigned long timeout;
+ struct saa7134_card_ir *ir = dev->remote;
+ unsigned long timeout;
int space;
/* Generate initial event */
@@ -1035,7 +919,6 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
-
/*
* Wait 15 ms from the start of the first IR event before processing
* the event. This time is enough for NEC protocol. May need adjustments
@@ -1043,173 +926,9 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
*/
if (!ir->active) {
timeout = jiffies + jiffies_to_msecs(15);
- mod_timer(&ir->timer_end, timeout);
- ir->active = 1;
+ mod_timer(&ir->timer, timeout);
+ ir->active = true;
}
return 1;
}
-
-static int saa7134_rc5_irq(struct saa7134_dev *dev)
-{
- struct card_ir *ir = dev->remote;
- struct timeval tv;
- u32 gap;
- unsigned long current_jiffies, timeout;
-
- /* get time of bit */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* active code => add bit */
- if (ir->active) {
- /* only if in the code (otherwise spurious IRQ or timer
- late) */
- if (ir->last_bit < 28) {
- ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
- ir_rc5_remote_gap;
- ir->code |= 1 << ir->last_bit;
- }
- /* starting new code */
- } else {
- ir->active = 1;
- ir->code = 0;
- ir->base_time = tv;
- ir->last_bit = 0;
-
- timeout = current_jiffies + (500 + 30 * HZ) / 1000;
- mod_timer(&ir->timer_end, timeout);
- }
-
- return 1;
-}
-
-/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
- The first pulse (start) has 9 + 4.5 ms
- */
-
-static void saa7134_nec_timer(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *) data;
- struct card_ir *ir = dev->remote;
-
- dprintk("Cancel key repeat\n");
-
- ir_input_nokey(ir->dev, &ir->ir);
-}
-
-static void nec_task(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *) data;
- struct card_ir *ir;
- struct timeval tv;
- int count, pulse, oldpulse, gap;
- u32 ircode = 0, not_code = 0;
- int ngap = 0;
-
- if (!data) {
- printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n");
- /* GPIO will be kept disabled */
- return;
- }
-
- ir = dev->remote;
-
- /* rising SAA7134_GPIO_GPRESCAN reads the status */
- saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-
- oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
- pulse = oldpulse;
-
- do_gettimeofday(&tv);
- ir->base_time = tv;
-
- /* Decode NEC pulsecode. This code can take up to 76.5 ms to run.
- Unfortunately, using IRQ to decode pulse didn't work, since it uses
- a pulse train of 38KHz. This means one pulse on each 52 us
- */
- do {
- /* Wait until the end of pulse/space or 5 ms */
- for (count = 0; count < 500; count++) {
- udelay(10);
- /* rising SAA7134_GPIO_GPRESCAN reads the status */
- saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
- & ir->mask_keydown;
- if (pulse != oldpulse)
- break;
- }
-
- do_gettimeofday(&tv);
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
-
- if (!pulse) {
- /* Bit 0 has 560 us, while bit 1 has 1120 us.
- Do something only if bit == 1
- */
- if (ngap && (gap > 560 + 280)) {
- unsigned int shift = ngap - 1;
-
- /* Address first, then command */
- if (shift < 8) {
- shift += 8;
- ircode |= 1 << shift;
- } else if (shift < 16) {
- not_code |= 1 << shift;
- } else if (shift < 24) {
- shift -= 16;
- ircode |= 1 << shift;
- } else {
- shift -= 24;
- not_code |= 1 << shift;
- }
- }
- ngap++;
- }
-
-
- ir->base_time = tv;
-
- /* TIMEOUT - Long pulse */
- if (gap >= 5000)
- break;
- oldpulse = pulse;
- } while (ngap < 32);
-
- if (ngap == 32) {
- /* FIXME: should check if not_code == ~ircode */
- ir->code = ir_extract_bits(ircode, ir->mask_keycode);
-
- dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
- ir->code, ircode, not_code);
-
- ir_input_keydown(ir->dev, &ir->ir, ir->code);
- } else
- dprintk("Repeat last key\n");
-
- /* Keep repeating the last key */
- mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
-
- saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
-}
-
-static int saa7134_nec_irq(struct saa7134_dev *dev)
-{
- struct card_ir *ir = dev->remote;
-
- saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
- tasklet_schedule(&ir->tlet);
-
- return 1;
-}
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 3e7d2fd1688f..57e646bb48b3 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -550,16 +550,16 @@ static int tvaudio_thread(void *data)
} else if (0 != dev->last_carrier) {
/* no carrier -- try last detected one as fallback */
carrier = dev->last_carrier;
- dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
- "using %d.%03d MHz [last detected]\n",
- dev->name, carrier/1000, carrier%1000);
+ dprintk("audio carrier scan failed, "
+ "using %d.%03d MHz [last detected]\n",
+ carrier/1000, carrier%1000);
} else {
/* no carrier + no fallback -- use default */
carrier = default_carrier;
- dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
- "using %d.%03d MHz [default]\n",
- dev->name, carrier/1000, carrier%1000);
+ dprintk("audio carrier scan failed, "
+ "using %d.%03d MHz [default]\n",
+ carrier/1000, carrier%1000);
}
tvaudio_setcarrier(dev,carrier,carrier);
dev->automute = 0;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index f0b1573137f4..776ba2dd7f9f 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -30,7 +30,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
#include <media/v4l2-common.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
/* ------------------------------------------------------------------ */
@@ -1459,7 +1459,7 @@ static int video_release(struct file *file)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
unsigned long flags;
/* turn off overlay */
@@ -1494,7 +1494,7 @@ static int video_release(struct file *file)
saa_call_all(dev, core, s_power, 0);
if (fh->radio)
- saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
/* free stuff */
videobuf_mmap_free(&fh->cap);
@@ -1520,14 +1520,14 @@ static ssize_t radio_read(struct file *file, char __user *data,
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.block_count = count/3;
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;
- saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
return cmd.result;
}
@@ -1536,12 +1536,12 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.instance = file;
cmd.event_list = wait;
cmd.result = -ENODEV;
- saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
return cmd.result;
}
@@ -1748,7 +1748,6 @@ static int saa7134_enum_input(struct file *file, void *priv,
return -EINVAL;
if (NULL == card_in(dev, i->index).name)
return -EINVAL;
- memset(i, 0, sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, card_in(dev, n).name);
@@ -2211,14 +2210,6 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on)
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct saa7134_fh *fh = file->private_data;
- return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
-}
-#endif
-
static int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -2456,9 +2447,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_streamoff = saa7134_streamoff,
.vidioc_g_tuner = saa7134_g_tuner,
.vidioc_s_tuner = saa7134_s_tuner,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_crop = saa7134_g_crop,
.vidioc_s_crop = saa7134_s_crop,
.vidioc_g_fbuf = saa7134_g_fbuf,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index d3b6a196e5dc..5b0a347b0b8f 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,7 +37,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/tuner.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dma-sg.h>
#include <sound/core.h>
@@ -119,6 +119,26 @@ struct saa7134_format {
unsigned int uvswap:1;
};
+struct saa7134_card_ir {
+ struct rc_dev *dev;
+
+ char name[32];
+ char phys[32];
+ unsigned users;
+
+ u32 polling;
+ u32 last_gpio;
+ u32 mask_keycode, mask_keydown, mask_keyup;
+
+ bool running;
+ bool active;
+
+ struct timer_list timer;
+
+ /* IR core raw decoding */
+ u32 raw_decode;
+};
+
/* ----------------------------------------------------------- */
/* card configuration */
@@ -305,6 +325,8 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_A7 179
#define SAA7134_BOARD_AVERMEDIA_M733A 180
#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
+#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
+#define SAA7134_BOARD_VIDEOMATE_M1F 183
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -529,7 +551,7 @@ struct saa7134_dev {
/* infrared remote */
int has_remote;
- struct card_ir *remote;
+ struct saa7134_card_ir *remote;
/* pci i/o */
char name[32];
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c
index ad3bc4154176..bd86d970f4c2 100644
--- a/drivers/media/video/saa7164/saa7164-api.c
+++ b/drivers/media/video/saa7164/saa7164-api.c
@@ -40,9 +40,8 @@ int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
ret = saa7164_cmd_send(dev, 0, GET_CUR,
GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
- if (ret != SAA_OK) {
+ if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- }
printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
@@ -63,14 +62,15 @@ int saa7164_api_collect_debug(struct saa7164_dev *dev)
ret = saa7164_cmd_send(dev, 0, GET_CUR,
GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
- if (ret != SAA_OK) {
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- }
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n",
+ __func__, ret);
if (d.dwResult != SAA_OK)
break;
- printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr, d.ucDebugData);
+ printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr,
+ d.ucDebugData);
}
return 0;
@@ -86,9 +86,9 @@ int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
/* Retrieve current state */
ret = saa7164_cmd_send(dev, 0, GET_CUR,
SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
- if (ret != SAA_OK) {
+ if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- }
+
dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
lvl.dwDebugLevel = level;
@@ -96,9 +96,8 @@ int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
/* set new state */
ret = saa7164_cmd_send(dev, 0, SET_CUR,
SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
- if (ret != SAA_OK) {
+ if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- }
return ret;
}
@@ -152,8 +151,10 @@ int saa7164_api_set_vbi_format(struct saa7164_port *port)
dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
- dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n", rsp.bFormatIndex);
- dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n", rsp.bFrameIndex);
+ dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n",
+ rsp.bFormatIndex);
+ dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n",
+ rsp.bFrameIndex);
} else
printk(KERN_ERR "%s() compare failed\n", __func__);
}
@@ -210,14 +211,17 @@ int saa7164_api_set_encoder(struct saa7164_port *port)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
/* Establish video bitrates */
- if (port->encoder_params.bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ if (port->encoder_params.bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
else
vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
vb.dwVideoBitRate = port->encoder_params.bitrate;
vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_VIDEO_BIT_RATE_CONTROL, sizeof(struct tmComResEncVideoBitRate), &vb);
+ EU_VIDEO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncVideoBitRate),
+ &vb);
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
@@ -226,9 +230,12 @@ int saa7164_api_set_encoder(struct saa7164_port *port)
ab.dwAudioBitRate = 384000;
ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
- EU_AUDIO_BIT_RATE_CONTROL, sizeof(struct tmComResEncAudioBitRate), &ab);
+ EU_AUDIO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncAudioBitRate),
+ &ab);
if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
saa7164_api_set_aspect_ratio(port);
saa7164_api_set_gop_size(port);
@@ -244,7 +251,8 @@ int saa7164_api_get_encoder(struct saa7164_port *port)
struct tmComResEncVideoInputAspectRatio ar;
int ret;
- dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, port->hwcfg.sourceid);
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+ port->hwcfg.sourceid);
port->encoder_profile = 0;
port->video_format = 0;
@@ -257,7 +265,8 @@ int saa7164_api_get_encoder(struct saa7164_port *port)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
- EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8), &port->video_resolution);
+ EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8),
+ &port->video_resolution);
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
@@ -294,13 +303,20 @@ int saa7164_api_get_encoder(struct saa7164_port *port)
dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format);
dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format);
dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
- dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n", v.ucVideoBitRateMode);
- dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n", v.dwVideoBitRate);
- dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n", v.dwVideoBitRatePeak);
- dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n", a.ucAudioBitRateMode);
- dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n", a.dwAudioBitRate);
- dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n", a.dwAudioBitRatePeak);
- dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n", ar.width, ar.height);
+ dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n",
+ v.ucVideoBitRateMode);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n",
+ v.dwVideoBitRate);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n",
+ v.dwVideoBitRatePeak);
+ dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n",
+ a.ucAudioBitRateMode);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n",
+ a.dwAudioBitRate);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n",
+ a.dwAudioBitRatePeak);
+ dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n",
+ ar.width, ar.height);
return ret;
}
@@ -439,7 +455,8 @@ int saa7164_api_set_videomux(struct saa7164_port *port)
/* Audio Mux */
ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
- SU_INPUT_SELECT_CONTROL, sizeof(u8), &inputs[port->mux_input - 1]);
+ SU_INPUT_SELECT_CONTROL, sizeof(u8),
+ &inputs[port->mux_input - 1]);
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
@@ -492,7 +509,8 @@ int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v);
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
v = level;
if (v < min)
@@ -517,7 +535,8 @@ int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
- dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, level, min, max, v);
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
return ret;
}
@@ -539,7 +558,8 @@ int saa7164_api_set_audio_std(struct saa7164_port *port)
lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
- AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults), &lvl);
+ AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults),
+ &lvl);
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
@@ -555,7 +575,8 @@ int saa7164_api_set_audio_std(struct saa7164_port *port)
ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
if (ret != SAA_OK)
- printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n", __func__, ret);
+ printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
return ret;
}
@@ -575,7 +596,9 @@ int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
if (ret != SAA_OK)
- printk(KERN_ERR "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n", __func__, ret);
+ printk(KERN_ERR
+ "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
return ret;
}
@@ -646,9 +669,9 @@ int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
EXU_REGISTER_ACCESS_CONTROL, len, &buf);
if (ret != SAA_OK)
printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
-
- //saa7164_dumphex16(dev, buf, 16);
-
+#if 0
+ saa7164_dumphex16(dev, buf, 16);
+#endif
return ret == SAA_OK ? 0 : -EIO;
}
@@ -696,7 +719,8 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
} else {
/* Unknown standard, assume DTV */
dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
- saa7164_api_set_dif(port, 0x00, 0x80); /* Undefined Video Standard */
+ /* Undefinded Video Standard */
+ saa7164_api_set_dif(port, 0x00, 0x80);
agc_disable = 1;
}
@@ -933,7 +957,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
if (hdr->type != CS_INTERFACE)
return SAA_ERR_NOT_SUPPORTED;
- dprintk(DBGLVL_API, "@ 0x%x = \n", idx);
+ dprintk(DBGLVL_API, "@ 0x%x =\n", idx);
switch (hdr->subtype) {
case GENERAL_REQUEST:
dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
@@ -1085,7 +1109,8 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
vbiport = &dev->ports[SAA7164_PORT_VBI2];
memcpy(&vbiport->hwcfg, vcoutputtermhdr,
sizeof(*vcoutputtermhdr));
- memcpy(&vbiport->vbi_fmt_ntsc, vbifmt, sizeof(*vbifmt));
+ memcpy(&vbiport->vbi_fmt_ntsc, vbifmt,
+ sizeof(*vbifmt));
saa7164_api_configure_port_vbi(dev,
vbiport);
break;
@@ -1134,7 +1159,9 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
encport = &dev->ports[SAA7164_PORT_ENC2];
memcpy(&encport->tunerunit, tunerunithdr,
sizeof(struct tmComResTunerDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d] tuner)\n", encport->nr);
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d] tuner)\n",
+ encport->nr);
}
break;
case VC_SELECTOR_UNIT:
@@ -1163,7 +1190,8 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
encport = &dev->ports[SAA7164_PORT_ENC2];
memcpy(&encport->vidproc, pdh,
sizeof(struct tmComResProcDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr);
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
}
break;
case FEATURE_UNIT:
@@ -1181,15 +1209,18 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
encport = &dev->ports[SAA7164_PORT_ENC2];
memcpy(&encport->audfeat, afd,
sizeof(struct tmComResAFeatureDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr);
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
break;
case ENCODER_UNIT:
edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " ENCODER_UNIT\n");
dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype);
dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid);
- dprintk(DBGLVL_API, " vsourceid = 0x%x\n", edh->vsourceid);
- dprintk(DBGLVL_API, " asourceid = 0x%x\n", edh->asourceid);
+ dprintk(DBGLVL_API, " vsourceid = 0x%x\n",
+ edh->vsourceid);
+ dprintk(DBGLVL_API, " asourceid = 0x%x\n",
+ edh->asourceid);
dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit);
if (edh->iunit == edh->unitid) {
if (currpath == 1)
@@ -1198,7 +1229,9 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
encport = &dev->ports[SAA7164_PORT_ENC2];
memcpy(&encport->encunit, edh,
sizeof(struct tmComResEncoderDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr);
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
}
break;
case EXTENSION_UNIT:
@@ -1262,7 +1295,9 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
encport = &dev->ports[SAA7164_PORT_ENC2];
memcpy(&encport->ifunit, exthdr,
sizeof(struct tmComResExtDevDescrHeader));
- dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", encport->nr);
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
}
break;
case PVC_INFRARED_UNIT:
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c
index 7230912acc7d..ddd25211c9e8 100644
--- a/drivers/media/video/saa7164/saa7164-buffer.c
+++ b/drivers/media/video/saa7164/saa7164-buffer.c
@@ -24,46 +24,46 @@
#include "saa7164.h"
/* The PCI address space for buffer handling looks like this:
-
- +-u32 wide-------------+
- | +
- +-u64 wide------------------------------------+
- + +
- +----------------------+
- | CurrentBufferPtr + Pointer to current PCI buffer >-+
- +----------------------+ |
- | Unused + |
- +----------------------+ |
- | Pitch + = 188 (bytes) |
- +----------------------+ |
- | PCI buffer size + = pitch * number of lines (312) |
- +----------------------+ |
- |0| Buf0 Write Offset + |
- +----------------------+ v
- |1| Buf1 Write Offset + |
- +----------------------+ |
- |2| Buf2 Write Offset + |
- +----------------------+ |
- |3| Buf3 Write Offset + |
- +----------------------+ |
- ... More write offsets |
- +---------------------------------------------+ |
- +0| set of ptrs to PCI pagetables + |
- +---------------------------------------------+ |
- +1| set of ptrs to PCI pagetables + <--------+
- +---------------------------------------------+
- +2| set of ptrs to PCI pagetables +
- +---------------------------------------------+
- +3| set of ptrs to PCI pagetables + >--+
- +---------------------------------------------+ |
- ... More buffer pointers | +----------------+
- +->| pt[0] TS data |
- | +----------------+
- |
- | +----------------+
- +->| pt[1] TS data |
- | +----------------+
- | etc
+ *
+ * +-u32 wide-------------+
+ * | +
+ * +-u64 wide------------------------------------+
+ * + +
+ * +----------------------+
+ * | CurrentBufferPtr + Pointer to current PCI buffer >-+
+ * +----------------------+ |
+ * | Unused + |
+ * +----------------------+ |
+ * | Pitch + = 188 (bytes) |
+ * +----------------------+ |
+ * | PCI buffer size + = pitch * number of lines (312) |
+ * +----------------------+ |
+ * |0| Buf0 Write Offset + |
+ * +----------------------+ v
+ * |1| Buf1 Write Offset + |
+ * +----------------------+ |
+ * |2| Buf2 Write Offset + |
+ * +----------------------+ |
+ * |3| Buf3 Write Offset + |
+ * +----------------------+ |
+ * ... More write offsets |
+ * +---------------------------------------------+ |
+ * +0| set of ptrs to PCI pagetables + |
+ * +---------------------------------------------+ |
+ * +1| set of ptrs to PCI pagetables + <--------+
+ * +---------------------------------------------+
+ * +2| set of ptrs to PCI pagetables +
+ * +---------------------------------------------+
+ * +3| set of ptrs to PCI pagetables + >--+
+ * +---------------------------------------------+ |
+ * ... More buffer pointers | +----------------+
+ * +->| pt[0] TS data |
+ * | +----------------+
+ * |
+ * | +----------------+
+ * +->| pt[1] TS data |
+ * | +----------------+
+ * | etc
*/
void saa7164_buffer_display(struct saa7164_buffer *buf)
@@ -283,7 +283,8 @@ int saa7164_buffer_cfg_port(struct saa7164_port *port)
return 0;
}
-struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, u32 len)
+struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev,
+ u32 len)
{
struct saa7164_user_buffer *buf;
@@ -313,12 +314,9 @@ void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
if (!buf)
return;
- if (buf->data) {
- kfree(buf->data);
- buf->data = 0;
- }
+ kfree(buf->data);
+ buf->data = 0;
- if (buf)
- kfree(buf);
+ kfree(buf);
}
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c
index 30d5283da41e..b2b0d97101d0 100644
--- a/drivers/media/video/saa7164/saa7164-bus.c
+++ b/drivers/media/video/saa7164/saa7164-bus.c
@@ -43,7 +43,8 @@ int saa7164_bus_setup(struct saa7164_dev *dev)
b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
- b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64));
+ b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) +
+ (2 * sizeof(u64));
b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32));
b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32));
@@ -105,7 +106,8 @@ void saa7164_bus_verify(struct saa7164_dev *dev)
}
}
-void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, void *buf)
+void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m,
+ void *buf)
{
dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
dprintk(DBGLVL_BUS, " .id = %d\n", m->id);
@@ -129,7 +131,8 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, void *
* SAA_OK The function executed successfully.
* < 0 One or more members are not initialized.
*/
-int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf)
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf)
{
struct tmComResBusInfo *bus = &dev->bus;
u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
@@ -294,14 +297,15 @@ out:
/*
* Receive a command or a response from the bus. The implementation does not
* know if it is a command or a response it simply dequeues the data,
- * depending on the bus information given in the struct tmComResBusInfo structure.
+ * depending on the bus information given in the struct tmComResBusInfo
+ * structure.
*
* Return Value:
* 0 The function executed successfully.
* < 0 One or more members are not initialized.
*/
-int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf,
- int peekonly)
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf, int peekonly)
{
struct tmComResBusInfo *bus = &dev->bus;
u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c
index 4cb634e952a6..69822a4e7275 100644
--- a/drivers/media/video/saa7164/saa7164-cards.c
+++ b/drivers/media/video/saa7164/saa7164-cards.c
@@ -482,7 +482,7 @@ void saa7164_gpio_setup(struct saa7164_dev *dev)
saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
- msleep(10);
+ msleep(20);
saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c
index 301a9e302f45..a97ae17b36c2 100644
--- a/drivers/media/video/saa7164/saa7164-cmd.c
+++ b/drivers/media/video/saa7164/saa7164-cmd.c
@@ -122,8 +122,8 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev)
return ret;
}
- /* It's unlikely to have more than 4 or 5 pending messages, ensure we exit
- * at some point regardles.
+ /* It's unlikely to have more than 4 or 5 pending messages,
+ * ensure we exit at some point regardless.
*/
} while (i++ < 32);
@@ -186,7 +186,8 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
return SAA_OK;
}
-int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf)
+int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg,
+ void *buf)
{
struct tmComResBusInfo *bus = &dev->bus;
u8 cmd_sent;
@@ -292,7 +293,8 @@ int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
* We typically are signalled in < 50ms but it can
* take MUCH longer.
*/
- wait_event_timeout(*q, dev->cmds[seqno].signalled, (HZ * waitsecs));
+ wait_event_timeout(*q, dev->cmds[seqno].signalled,
+ (HZ * waitsecs));
r = time_before(jiffies, stamp + (HZ * waitsecs));
if (r)
ret = SAA_OK;
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index e1bac5051460..58af67f2278b 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -40,12 +40,12 @@ MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>");
MODULE_LICENSE("GPL");
/*
- 1 Basic
- 2
- 4 i2c
- 8 api
- 16 cmd
- 32 bus
+ * 1 Basic
+ * 2
+ * 4 i2c
+ * 8 api
+ * 16 cmd
+ * 32 bus
*/
unsigned int saa_debug;
@@ -82,7 +82,8 @@ MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
unsigned int guard_checking = 1;
module_param(guard_checking, int, 0644);
-MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns");
+MODULE_PARM_DESC(guard_checking,
+ "enable dma sanity checking for buffer overruns");
static unsigned int saa7164_devcount;
@@ -123,7 +124,9 @@ static void saa7164_pack_verifier(struct saa7164_buffer *buf)
if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
(*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
printk(KERN_ERR "No pack at 0x%x\n", i);
-// saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
+#if 0
+ saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
+#endif
}
}
}
@@ -199,19 +202,16 @@ static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
strcpy(hg->name, name);
/* First 30ms x 1ms */
- for (i = 0; i < 30; i++) {
+ for (i = 0; i < 30; i++)
hg->counter1[0 + i].val = i;
- }
/* 30 - 200ms x 10ms */
- for (i = 0; i < 18; i++) {
+ for (i = 0; i < 18; i++)
hg->counter1[30 + i].val = 30 + (i * 10);
- }
/* 200 - 2000ms x 100ms */
- for (i = 0; i < 15; i++) {
+ for (i = 0; i < 15; i++)
hg->counter1[48 + i].val = 200 + (i * 200);
- }
/* Catch all massive value (2secs) */
hg->counter1[55].val = 2000;
@@ -315,7 +315,9 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
(*(p + buf->actual_size + 0x13) != 0xff)) {
printk(KERN_ERR "%s() buf %p guard buffer breach\n",
__func__, buf);
-// saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
+#if 0
+ saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
+#endif
}
}
@@ -653,8 +655,8 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
goto out;
}
- /* Check that the hardware is accessable. If the status bytes are
- * 0xFF then the device is not accessable, the the IRQ belongs
+ /* Check that the hardware is accessible. If the status bytes are
+ * 0xFF then the device is not accessible, the the IRQ belongs
* to another driver.
* 4 x u32 interrupt registers.
*/
@@ -961,9 +963,7 @@ static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
/* We need a deferred interrupt handler for cmd handling */
INIT_WORK(&port->workenc, saa7164_work_enchandler);
- }
- else
- if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
+ } else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
port->type = SAA7164_MPEG_VBI;
/* We need a deferred interrupt handler for cmd handling */
@@ -1001,7 +1001,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
atomic_inc(&dev->refcount);
dev->nr = saa7164_devcount++;
- sprintf(dev->name, "saa7164[%d]", dev->nr);
+ snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
mutex_lock(&devlist);
list_add_tail(&dev->devlist, &saa7164_devlist);
@@ -1169,7 +1169,7 @@ static int saa7164_proc_open(struct inode *inode, struct file *filp)
return single_open(filp, saa7164_proc_show, NULL);
}
-static struct file_operations saa7164_proc_fops = {
+static const struct file_operations saa7164_proc_fops = {
.open = saa7164_proc_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index cbb53d0ee979..1838408cd5cb 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -125,16 +125,22 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
dprintk(DBGLVL_ENC, "%s()\n", __func__);
- if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
- dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n", __func__);
+ if (port->encoder_params.stream_type ==
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+ dprintk(DBGLVL_ENC,
+ "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n",
+ __func__);
params->samplesperline = 128;
params->numberoflines = 256;
params->pitch = 128;
params->numpagetables = 2 +
((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
} else
- if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
- dprintk(DBGLVL_ENC, "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n", __func__);
+ if (port->encoder_params.stream_type ==
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
+ dprintk(DBGLVL_ENC,
+ "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n",
+ __func__);
params->samplesperline = 188;
params->numberoflines = 312;
params->pitch = 188;
@@ -826,7 +832,8 @@ static int fill_queryctrl(struct saa7164_encoder_params *params,
return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
return v4l2_ctrl_query_fill(c,
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
return v4l2_ctrl_query_fill(c,
@@ -1113,7 +1120,9 @@ struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
if (crc_checking) {
crc = crc32(0, ubuf->data, ubuf->actual_size);
if (crc != ubuf->crc) {
- printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
+ printk(KERN_ERR
+ "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+ __func__,
ubuf, ubuf->crc, crc);
}
}
@@ -1201,9 +1210,8 @@ static ssize_t fops_read(struct file *file, char __user *buffer,
buffer += cnt;
ret += cnt;
- if (ubuf->pos > ubuf->actual_size) {
+ if (ubuf->pos > ubuf->actual_size)
printk(KERN_ERR "read() pos > actual, huh?\n");
- }
if (ubuf->pos == ubuf->actual_size) {
@@ -1227,16 +1235,16 @@ static ssize_t fops_read(struct file *file, char __user *buffer,
}
}
err:
- if (!ret && !ubuf) {
+ if (!ret && !ubuf)
ret = -EAGAIN;
- }
return ret;
}
static unsigned int fops_poll(struct file *file, poll_table *wait)
{
- struct saa7164_encoder_fh *fh = (struct saa7164_encoder_fh *)file->private_data;
+ struct saa7164_encoder_fh *fh =
+ (struct saa7164_encoder_fh *)file->private_data;
struct saa7164_port *port = fh->port;
struct saa7164_user_buffer *ubuf;
unsigned int mask = 0;
@@ -1249,9 +1257,8 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
saa7164_histogram_update(&port->poll_interval,
port->last_poll_msecs_diff);
- if (!video_is_registered(port->v4l_device)) {
+ if (!video_is_registered(port->v4l_device))
return -EIO;
- }
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
if (atomic_inc_return(&port->v4l_reader_count) == 1) {
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c
index 484533c32bb1..ebed6f786a23 100644
--- a/drivers/media/video/saa7164/saa7164-fw.c
+++ b/drivers/media/video/saa7164/saa7164-fw.c
@@ -178,7 +178,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
goto out;
}
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (timeout++ > 60)
break;
}
@@ -235,7 +235,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
dprintk(DBGLVL_FW, "%s() err_flags = %x\n",
__func__, err_flags);
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
printk(KERN_ERR "%s() firmware corrupt\n",
@@ -294,7 +294,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n",
__func__, err_flags);
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
printk(KERN_ERR
@@ -365,7 +365,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
first_timeout = SAA_DEVICE_TIMEOUT;
while (first_timeout) {
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
version =
saa7164_getcurrentfirmwareversion(dev);
@@ -608,8 +608,6 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
ret = 0;
out:
- if (fw)
- release_firmware(fw);
-
+ release_firmware(fw);
return ret;
}
diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/video/saa7164/saa7164-i2c.c
index b5167d33650a..26148f76cba2 100644
--- a/drivers/media/video/saa7164/saa7164-i2c.c
+++ b/drivers/media/video/saa7164/saa7164-i2c.c
@@ -23,7 +23,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "saa7164.h"
@@ -65,7 +65,7 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
}
return num;
- err:
+err:
return retval;
}
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index 323c7cdca37b..8abbe6d661e4 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -51,11 +51,15 @@ static void saa7164_vbi_configure(struct saa7164_port *port)
/* Set up the DIF (enable it) for analog mode by default */
saa7164_api_initialize_dif(port);
-// /* Configure the correct video standard */
-// saa7164_api_configure_dif(port, port->encodernorm.id);
+ /* Configure the correct video standard */
+#if 0
+ saa7164_api_configure_dif(port, port->encodernorm.id);
+#endif
-// /* Ensure the audio decoder is correct configured */
-// saa7164_api_set_audio_std(port);
+#if 0
+ /* Ensure the audio decoder is correct configured */
+ saa7164_api_set_audio_std(port);
+#endif
dprintk(DBGLVL_VBI, "%s() ends\n", __func__);
}
@@ -919,8 +923,10 @@ static int saa7164_vbi_start_streaming(struct saa7164_port *port)
saa7164_vbi_buffers_alloc(port);
/* Configure the encoder with any cache values */
-// saa7164_api_set_encoder(port);
-// saa7164_api_get_encoder(port);
+#if 0
+ saa7164_api_set_encoder(port);
+ saa7164_api_get_encoder(port);
+#endif
/* Place the empty buffers on the hardware */
saa7164_buffer_cfg_port(port);
@@ -1060,7 +1066,8 @@ struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
if (crc_checking) {
crc = crc32(0, ubuf->data, ubuf->actual_size);
if (crc != ubuf->crc) {
- printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", __func__,
+ printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+ __func__,
ubuf, ubuf->crc, crc);
}
}
@@ -1148,9 +1155,8 @@ static ssize_t fops_read(struct file *file, char __user *buffer,
buffer += cnt;
ret += cnt;
- if (ubuf->pos > ubuf->actual_size) {
+ if (ubuf->pos > ubuf->actual_size)
printk(KERN_ERR "read() pos > actual, huh?\n");
- }
if (ubuf->pos == ubuf->actual_size) {
@@ -1197,9 +1203,8 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
saa7164_histogram_update(&port->poll_interval,
port->last_poll_msecs_diff);
- if (!video_is_registered(port->v4l_device)) {
+ if (!video_is_registered(port->v4l_device))
return -EIO;
- }
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
if (atomic_inc_return(&port->v4l_reader_count) == 1) {
@@ -1257,10 +1262,14 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_log_status = vidioc_log_status,
.vidioc_queryctrl = vidioc_queryctrl,
-// .vidioc_g_chip_ident = saa7164_g_chip_ident,
+#if 0
+ .vidioc_g_chip_ident = saa7164_g_chip_ident,
+#endif
#ifdef CONFIG_VIDEO_ADV_DEBUG
-// .vidioc_g_register = saa7164_g_register,
-// .vidioc_s_register = saa7164_s_register,
+#if 0
+ .vidioc_g_register = saa7164_g_register,
+ .vidioc_s_register = saa7164_s_register,
+#endif
#endif
.vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt,
.vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt,
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index 1d9c5cbbbc52..16745d2fb349 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -58,7 +58,6 @@
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
-#include <linux/smp_lock.h>
#include <dvb_demux.h>
#include <dvb_frontend.h>
#include <dvb_net.h>
@@ -114,7 +113,8 @@
#define DBGLVL_THR 4096
#define DBGLVL_CPU 8192
-#define SAA7164_NORMS (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443)
+#define SAA7164_NORMS \
+ (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443)
enum port_t {
SAA7164_MPEG_UNDEFINED = 0,
@@ -183,15 +183,11 @@ struct saa7164_subid {
struct saa7164_encoder_fh {
struct saa7164_port *port;
-// u32 freq;
-// u32 tuner_type;
atomic_t v4l_reading;
};
struct saa7164_vbi_fh {
struct saa7164_port *port;
-// u32 freq;
-// u32 tuner_type;
atomic_t v4l_reading;
};
@@ -266,8 +262,6 @@ struct saa7164_ctrl {
struct saa7164_tvnorm {
char *name;
v4l2_std_id id;
-// u32 cxiformat;
-// u32 cxoformat;
};
struct saa7164_encoder_params {
@@ -448,7 +442,7 @@ struct saa7164_dev {
int nr;
int hwrevision;
u32 board;
- char name[32];
+ char name[16];
/* firmware status */
struct saa7164_fw_status fw_status;
@@ -511,7 +505,8 @@ extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
/* saa7164-bus.c */
int saa7164_bus_setup(struct saa7164_dev *dev);
void saa7164_bus_dump(struct saa7164_dev *dev);
-int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, void *buf);
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf);
int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
void *buf, int peekonly);
@@ -553,7 +548,8 @@ int saa7164_api_get_videomux(struct saa7164_port *port);
int saa7164_api_set_vbi_format(struct saa7164_port *port);
int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
int saa7164_api_collect_debug(struct saa7164_dev *dev);
-int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i);
+int saa7164_api_get_load_info(struct saa7164_dev *dev,
+ struct tmFwInfoStruct *i);
/* ----------------------------------------------------------- */
/* saa7164-cards.c */
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 5c209afb0ac8..954222bc3458 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -1786,7 +1786,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
pcdev->field,
sizeof(struct sh_mobile_ceu_buffer),
- icd, NULL);
+ icd, &icd->video_lock);
}
static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
@@ -1980,7 +1980,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
* we complete the completion.
*/
- if (!csi2->driver || !csi2->driver->owner) {
+ if (!csi2->driver) {
complete(&wait.completion);
/* Either too late, or probing failed */
bus_unregister_notifier(&platform_bus_type, &wait.notifier);
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index 0f4906136b8f..07cf0c6c7c1f 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -75,6 +75,7 @@ struct sh_vou_device {
int pix_idx;
struct videobuf_buffer *active;
enum sh_vou_status status;
+ struct mutex fop_lock;
};
struct sh_vou_file {
@@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
vb->state = VIDEOBUF_NEEDS_INIT;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
@@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb,
enum v4l2_field field)
@@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */
+/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
static void sh_vou_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
@@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
sizeof(struct videobuf_buffer), vdev,
- NULL);
+ &vou_dev->fop_lock);
return 0;
}
@@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = {
.owner = THIS_MODULE,
.open = sh_vou_open,
.release = sh_vou_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = sh_vou_mmap,
.poll = sh_vou_poll,
};
@@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&vou_dev->queue);
spin_lock_init(&vou_dev->lock);
+ mutex_init(&vou_dev->fop_lock);
atomic_set(&vou_dev->use_count, 0);
vou_dev->pdata = vou_pdata;
vou_dev->status = SH_VOU_IDLE;
@@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release;
+ vdev->lock = &vou_dev->fop_lock;
vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
@@ -1406,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
goto ereset;
subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- NULL, vou_pdata->board_info, NULL);
+ vou_pdata->board_info, NULL);
if (!subdev) {
ret = -ENOMEM;
goto ei2cnd;
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 28e19daadec9..84984f64b234 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2189,6 +2189,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
memset(&i, 0, sizeof(i));
strcpy(i.name, "Camera");
i.type = V4L2_INPUT_TYPE_CAMERA;
+ i.capabilities = V4L2_IN_CAP_STD;
if (copy_to_user(arg, &i, sizeof(i)))
return -EFAULT;
@@ -3238,7 +3239,7 @@ static const struct v4l2_file_operations sn9c102_fops = {
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
- .ioctl = sn9c102_ioctl,
+ .unlocked_ioctl = sn9c102_ioctl,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index ccfa59c54552..41064c7b5ef8 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -43,9 +43,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
@@ -56,8 +54,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 494957b10bac..7f38549715b6 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -147,7 +147,7 @@ enum sn9c102_i2c_interface {
struct sn9c102_sensor {
char name[32], /* sensor name */
- maintainer[64]; /* name of the mantainer <email> */
+ maintainer[64]; /* name of the maintainer <email> */
enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 43848a751d11..a66811b43710 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/vmalloc.h>
@@ -43,6 +44,51 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
+static int soc_camera_power_set(struct soc_camera_device *icd,
+ struct soc_camera_link *icl,
+ int power_on)
+{
+ int ret;
+
+ if (power_on) {
+ ret = regulator_bulk_enable(icl->num_regulators,
+ icl->regulators);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Cannot enable regulators\n");
+ return ret;
+ }
+
+ if (icl->power)
+ ret = icl->power(icd->pdev, power_on);
+ if (ret < 0) {
+ dev_err(&icd->dev,
+ "Platform failed to power-on the camera.\n");
+
+ regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ return ret;
+ }
+ } else {
+ ret = 0;
+ if (icl->power)
+ ret = icl->power(icd->pdev, 0);
+ if (ret < 0) {
+ dev_err(&icd->dev,
+ "Platform failed to power-off the camera.\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Cannot disable regulators\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
@@ -352,12 +398,6 @@ static int soc_camera_open(struct file *file)
return -EINVAL;
}
- /*
- * Protect against icd->ops->remove() until we module_get() both
- * drivers.
- */
- mutex_lock(&icd->video_lock);
-
icd->use_count++;
/* Now we really have to activate the camera */
@@ -375,11 +415,9 @@ static int soc_camera_open(struct file *file)
},
};
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0)
- goto epower;
- }
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -405,15 +443,13 @@ static int soc_camera_open(struct file *file)
ret = soc_camera_set_fmt(icd, &f);
if (ret < 0)
goto esfmt;
+
+ ici->ops->init_videobuf(&icd->vb_vidq, icd);
}
file->private_data = icd;
dev_dbg(&icd->dev, "camera device open\n");
- ici->ops->init_videobuf(&icd->vb_vidq, icd);
-
- mutex_unlock(&icd->video_lock);
-
return 0;
/*
@@ -425,11 +461,9 @@ esfmt:
eresume:
ici->ops->remove(icd);
eiciadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
icd->use_count--;
- mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
return ret;
@@ -440,7 +474,6 @@ static int soc_camera_close(struct file *file)
struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- mutex_lock(&icd->video_lock);
icd->use_count--;
if (!icd->use_count) {
struct soc_camera_link *icl = to_soc_camera_link(icd);
@@ -450,15 +483,12 @@ static int soc_camera_close(struct file *file)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
}
if (icd->streamer == file)
icd->streamer = NULL;
- mutex_unlock(&icd->video_lock);
-
module_put(ici->ops->owner);
dev_dbg(&icd->dev, "camera device close\n");
@@ -517,7 +547,7 @@ static struct v4l2_file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
.release = soc_camera_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = soc_camera_read,
.mmap = soc_camera_mmap,
.poll = soc_camera_poll,
@@ -534,12 +564,9 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
if (icd->streamer && icd->streamer != file)
return -EBUSY;
- mutex_lock(&icd->vb_vidq.vb_lock);
-
if (icd->vb_vidq.bufs[0]) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
- ret = -EBUSY;
- goto unlock;
+ return -EBUSY;
}
ret = soc_camera_set_fmt(icd, f);
@@ -547,9 +574,6 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
if (!ret && !icd->streamer)
icd->streamer = file;
-unlock:
- mutex_unlock(&icd->vb_vidq.vb_lock);
-
return ret;
}
@@ -622,15 +646,11 @@ static int soc_camera_streamon(struct file *file, void *priv,
if (icd->streamer != file)
return -EBUSY;
- mutex_lock(&icd->video_lock);
-
v4l2_subdev_call(sd, video, s_stream, 1);
/* This calls buf_queue from host driver's videobuf_queue_ops */
ret = videobuf_streamon(&icd->vb_vidq);
- mutex_unlock(&icd->video_lock);
-
return ret;
}
@@ -648,8 +668,6 @@ static int soc_camera_streamoff(struct file *file, void *priv,
if (icd->streamer != file)
return -EBUSY;
- mutex_lock(&icd->video_lock);
-
/*
* This calls buf_release from host driver's videobuf_queue_ops for all
* remaining buffers. When the last buffer is freed, stop capture
@@ -658,8 +676,6 @@ static int soc_camera_streamoff(struct file *file, void *priv,
v4l2_subdev_call(sd, video, s_stream, 0);
- mutex_unlock(&icd->video_lock);
-
return 0;
}
@@ -748,9 +764,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret;
- mutex_lock(&icd->vb_vidq.vb_lock);
ret = ici->ops->get_crop(icd, a);
- mutex_unlock(&icd->vb_vidq.vb_lock);
return ret;
}
@@ -775,9 +789,6 @@ static int soc_camera_s_crop(struct file *file, void *fh,
dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
rect->width, rect->height, rect->left, rect->top);
- /* Cropping is allowed during a running capture, guard consistency */
- mutex_lock(&icd->vb_vidq.vb_lock);
-
/* If get_crop fails, we'll let host and / or client drivers decide */
ret = ici->ops->get_crop(icd, &current_crop);
@@ -795,8 +806,6 @@ static int soc_camera_s_crop(struct file *file, void *fh,
ret = ici->ops->set_crop(icd, a);
}
- mutex_unlock(&icd->vb_vidq.vb_lock);
-
return ret;
}
@@ -896,7 +905,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
icl->board_info->platform_data = icd;
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- NULL, icl->board_info, NULL);
+ icl->board_info, NULL);
if (!subdev)
goto ei2cnd;
@@ -941,14 +950,14 @@ static int soc_camera_probe(struct device *dev)
dev_info(dev, "Probing %s\n", dev_name(dev));
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0) {
- dev_err(dev,
- "Platform failed to power-on the camera.\n");
- goto epower;
- }
- }
+ ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
+ icl->regulators);
+ if (ret < 0)
+ goto ereg;
+
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -998,7 +1007,13 @@ static int soc_camera_probe(struct device *dev)
icd->field = V4L2_FIELD_ANY;
- /* ..._video_start() will create a device node, so we have to protect */
+ icd->vdev->lock = &icd->video_lock;
+
+ /*
+ * ..._video_start() will create a device node, video_register_device()
+ * itself is protected against concurrent open() calls, but we also have
+ * to protect our data.
+ */
mutex_lock(&icd->video_lock);
ret = soc_camera_video_start(icd);
@@ -1021,8 +1036,7 @@ static int soc_camera_probe(struct device *dev)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
mutex_unlock(&icd->video_lock);
@@ -1044,9 +1058,10 @@ eadddev:
evdc:
ici->ops->remove(icd);
eadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+ereg:
return ret;
}
@@ -1063,10 +1078,8 @@ static int soc_camera_remove(struct device *dev)
BUG_ON(!dev->parent);
if (vdev) {
- mutex_lock(&icd->video_lock);
video_unregister_device(vdev);
icd->vdev = NULL;
- mutex_unlock(&icd->video_lock);
}
if (icl->board_info) {
@@ -1081,6 +1094,8 @@ static int soc_camera_remove(struct device *dev)
}
soc_camera_free_user_formats(icd);
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+
return 0;
}
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
index c9dc67aba980..864696b7a006 100644
--- a/drivers/media/video/sr030pc30.c
+++ b/drivers/media/video/sr030pc30.c
@@ -735,7 +735,7 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
const struct sr030pc30_platform_data *pdata = info->pdata;
int ret;
- if (WARN(pdata == NULL, "No platform data!"))
+ if (WARN(pdata == NULL, "No platform data!\n"))
return -ENOMEM;
/*
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index f07a0f6b71c4..d1a2cefbf55b 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mm.h>
@@ -231,120 +230,6 @@ static int stk_initialise(struct stk_camera *dev)
return -1;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-
-/* sysfs functions */
-/*FIXME cleanup this */
-
-static ssize_t show_brightness(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%X\n", dev->vsettings.brightness);
-}
-
-static ssize_t store_brightness(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- char *endp;
- unsigned long value;
- int ret;
-
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- value = simple_strtoul(buf, &endp, 16);
-
- dev->vsettings.brightness = (int) value;
-
- ret = stk_sensor_set_brightness(dev, value >> 8);
- if (ret)
- return ret;
- else
- return count;
-}
-
-static ssize_t show_hflip(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%d\n", dev->vsettings.hflip);
-}
-
-static ssize_t store_hflip(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- if (strncmp(buf, "1", 1) == 0)
- dev->vsettings.hflip = 1;
- else if (strncmp(buf, "0", 1) == 0)
- dev->vsettings.hflip = 0;
- else
- return -EINVAL;
-
- return strlen(buf);
-}
-
-static ssize_t show_vflip(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%d\n", dev->vsettings.vflip);
-}
-
-static ssize_t store_vflip(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- if (strncmp(buf, "1", 1) == 0)
- dev->vsettings.vflip = 1;
- else if (strncmp(buf, "0", 1) == 0)
- dev->vsettings.vflip = 0;
- else
- return -EINVAL;
-
- return strlen(buf);
-}
-
-static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
- show_brightness, store_brightness);
-static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
-static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
-
-static int stk_create_sysfs_files(struct video_device *vdev)
-{
- int ret;
-
- ret = device_create_file(&vdev->dev, &dev_attr_brightness);
- ret += device_create_file(&vdev->dev, &dev_attr_hflip);
- ret += device_create_file(&vdev->dev, &dev_attr_vflip);
- if (ret)
- STK_WARNING("Could not create sysfs files\n");
- return ret;
-}
-
-static void stk_remove_sysfs_files(struct video_device *vdev)
-{
- device_remove_file(&vdev->dev, &dev_attr_brightness);
- device_remove_file(&vdev->dev, &dev_attr_hflip);
- device_remove_file(&vdev->dev, &dev_attr_vflip);
-}
-
-#else
-#define stk_create_sysfs_files(a)
-#define stk_remove_sysfs_files(a)
-#endif
-
/* *********************************************** */
/*
* This function is called as an URB transfert is complete (Isochronous pipe).
@@ -673,14 +558,11 @@ static int v4l_stk_open(struct file *fp)
vdev = video_devdata(fp);
dev = vdev_to_camera(vdev);
- lock_kernel();
if (dev == NULL || !is_present(dev)) {
- unlock_kernel();
return -ENXIO;
}
fp->private_data = dev;
usb_autopm_get_interface(dev->interface);
- unlock_kernel();
return 0;
}
@@ -882,7 +764,24 @@ static struct v4l2_queryctrl stk_controls[] = {
.step = 0x0100,
.default_value = 0x6000,
},
- /*TODO: get more controls to work */
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
};
static int stk_vidioc_queryctrl(struct file *filp,
@@ -910,6 +809,12 @@ static int stk_vidioc_g_ctrl(struct file *filp,
case V4L2_CID_BRIGHTNESS:
c->value = dev->vsettings.brightness;
break;
+ case V4L2_CID_HFLIP:
+ c->value = dev->vsettings.hflip;
+ break;
+ case V4L2_CID_VFLIP:
+ c->value = dev->vsettings.vflip;
+ break;
default:
return -EINVAL;
}
@@ -924,6 +829,12 @@ static int stk_vidioc_s_ctrl(struct file *filp,
case V4L2_CID_BRIGHTNESS:
dev->vsettings.brightness = c->value;
return stk_sensor_set_brightness(dev, c->value >> 8);
+ case V4L2_CID_HFLIP:
+ dev->vsettings.hflip = c->value;
+ return 0;
+ case V4L2_CID_VFLIP:
+ dev->vsettings.vflip = c->value;
+ return 0;
default:
return -EINVAL;
}
@@ -1398,8 +1309,6 @@ static int stk_camera_probe(struct usb_interface *interface,
goto error;
}
- stk_create_sysfs_files(&dev->vdev);
-
return 0;
error:
@@ -1415,7 +1324,6 @@ static void stk_camera_disconnect(struct usb_interface *interface)
unset_present(dev);
wake_up_interruptible(&dev->wait_frame);
- stk_remove_sysfs_files(&dev->vdev);
STK_INFO("Syntek USB2.0 Camera release resources device %s\n",
video_device_node_name(&dev->vdev));
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 3e99cea8e4dc..19621ed523ec 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -148,7 +148,7 @@ static int tea6415c_probe(struct i2c_client *client,
/* let's see whether this adapter can support what we need */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
- return 0;
+ return -EIO;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
new file mode 100644
index 000000000000..fc611ebeb82c
--- /dev/null
+++ b/drivers/media/video/timblogiw.c
@@ -0,0 +1,893 @@
+/*
+ * timblogiw.c timberdale FPGA LogiWin Video In driver
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Timberdale FPGA LogiWin Video In
+ */
+
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/timb_video.h>
+
+#define DRIVER_NAME "timb-video"
+
+#define TIMBLOGIWIN_NAME "Timberdale Video-In"
+#define TIMBLOGIW_VERSION_CODE 0x04
+
+#define TIMBLOGIW_LINES_PER_DESC 44
+#define TIMBLOGIW_MAX_VIDEO_MEM 16
+
+#define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name)
+
+
+struct timblogiw {
+ struct video_device video_dev;
+ struct v4l2_device v4l2_dev; /* mutual exclusion */
+ struct mutex lock;
+ struct device *dev;
+ struct timb_video_platform_data pdata;
+ struct v4l2_subdev *sd_enc; /* encoder */
+ bool opened;
+};
+
+struct timblogiw_tvnorm {
+ v4l2_std_id std;
+ u16 width;
+ u16 height;
+ u8 fps;
+};
+
+struct timblogiw_fh {
+ struct videobuf_queue vb_vidq;
+ struct timblogiw_tvnorm const *cur_norm;
+ struct list_head capture;
+ struct dma_chan *chan;
+ spinlock_t queue_lock; /* mutual exclusion */
+ unsigned int frame_count;
+};
+
+struct timblogiw_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ struct scatterlist sg[16];
+ dma_cookie_t cookie;
+ struct timblogiw_fh *fh;
+};
+
+const struct timblogiw_tvnorm timblogiw_tvnorms[] = {
+ {
+ .std = V4L2_STD_PAL,
+ .width = 720,
+ .height = 576,
+ .fps = 25
+ },
+ {
+ .std = V4L2_STD_NTSC,
+ .width = 720,
+ .height = 480,
+ .fps = 30
+ }
+};
+
+static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm)
+{
+ return norm->width * 2;
+}
+
+
+static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm)
+{
+ return norm->height * timblogiw_bytes_per_line(norm);
+}
+
+static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+ if (timblogiw_tvnorms[i].std & std)
+ return timblogiw_tvnorms + i;
+
+ /* default to first element */
+ return timblogiw_tvnorms;
+}
+
+static void timblogiw_dma_cb(void *data)
+{
+ struct timblogiw_buffer *buf = data;
+ struct timblogiw_fh *fh = buf->fh;
+ struct videobuf_buffer *vb = &buf->vb;
+
+ spin_lock(&fh->queue_lock);
+
+ /* mark the transfer done */
+ buf->cookie = -1;
+
+ fh->frame_count++;
+
+ if (vb->state != VIDEOBUF_ERROR) {
+ list_del(&vb->queue);
+ do_gettimeofday(&vb->ts);
+ vb->field_count = fh->frame_count * 2;
+ vb->state = VIDEOBUF_DONE;
+
+ wake_up(&vb->done);
+ }
+
+ if (!list_empty(&fh->capture)) {
+ vb = list_entry(fh->capture.next, struct videobuf_buffer,
+ queue);
+ vb->state = VIDEOBUF_ACTIVE;
+ }
+
+ spin_unlock(&fh->queue_lock);
+}
+
+static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+ return chan->chan_id == (uintptr_t)filter_param;
+}
+
+/* IOCTL functions */
+
+static int timblogiw_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&lw->lock);
+
+ format->fmt.pix.width = fh->cur_norm->width;
+ format->fmt.pix.height = fh->cur_norm->height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm);
+ format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm);
+ format->fmt.pix.field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&lw->lock);
+
+ return 0;
+}
+
+static int timblogiw_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_pix_format *pix = &format->fmt.pix;
+
+ dev_dbg(&vdev->dev,
+ "%s - width=%d, height=%d, pixelformat=%d, field=%d\n"
+ "bytes per line %d, size image: %d, colorspace: %d\n",
+ __func__,
+ pix->width, pix->height, pix->pixelformat, pix->field,
+ pix->bytesperline, pix->sizeimage, pix->colorspace);
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int timblogiw_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+ struct v4l2_pix_format *pix = &format->fmt.pix;
+ int err;
+
+ mutex_lock(&lw->lock);
+
+ err = timblogiw_try_fmt(file, priv, format);
+ if (err)
+ goto out;
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ dev_err(&vdev->dev, "%s queue busy\n", __func__);
+ err = -EBUSY;
+ goto out;
+ }
+
+ pix->width = fh->cur_norm->width;
+ pix->height = fh->cur_norm->height;
+
+out:
+ mutex_unlock(&lw->lock);
+ return err;
+}
+
+static int timblogiw_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+ memset(cap, 0, sizeof(*cap));
+ strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
+ strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
+ strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
+ cap->version = TIMBLOGIW_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+
+ return 0;
+}
+
+static int timblogiw_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index);
+
+ if (fmt->index != 0)
+ return -EINVAL;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = 0;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strncpy(fmt->description, "4:2:2, packed, YUYV",
+ sizeof(fmt->description)-1);
+ fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ return 0;
+}
+
+static int timblogiw_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct timblogiw_fh *fh = priv;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = fh->cur_norm->fps;
+
+ return 0;
+}
+
+static int timblogiw_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int timblogiw_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ *std = fh->cur_norm->std;
+ return 0;
+}
+
+static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+ int err = 0;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ mutex_lock(&lw->lock);
+
+ if (TIMBLOGIW_HAS_DECODER(lw))
+ err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std);
+
+ if (!err)
+ fh->cur_norm = timblogiw_get_norm(*std);
+
+ mutex_unlock(&lw->lock);
+
+ return err;
+}
+
+static int timblogiw_enuminput(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+ int i;
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->index = 0;
+
+ strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1);
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ inp->std = 0;
+ for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+ inp->std |= timblogiw_tvnorms[i].std;
+
+ return 0;
+}
+
+static int timblogiw_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ *input = 0;
+
+ return 0;
+}
+
+static int timblogiw_s_input(struct file *file, void *priv, unsigned int input)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ if (input != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int timblogiw_streamon(struct file *file, void *priv, unsigned int type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_dbg(&vdev->dev, "%s - No capture device\n", __func__);
+ return -EINVAL;
+ }
+
+ fh->frame_count = 0;
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int timblogiw_streamoff(struct file *file, void *priv,
+ unsigned int type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamoff(&fh->vb_vidq);
+}
+
+static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (TIMBLOGIW_HAS_DECODER(lw))
+ return v4l2_subdev_call(lw->sd_enc, video, querystd, std);
+ else {
+ *std = fh->cur_norm->std;
+ return 0;
+ }
+}
+
+static int timblogiw_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__,
+ fsize->index, fsize->pixel_format);
+
+ if ((fsize->index != 0) ||
+ (fsize->pixel_format != V4L2_PIX_FMT_UYVY))
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fh->cur_norm->width;
+ fsize->discrete.height = fh->cur_norm->height;
+
+ return 0;
+}
+
+/* Video buffer functions */
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+
+ *size = timblogiw_frame_size(fh->cur_norm);
+
+ if (!*count)
+ *count = 32;
+
+ while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+ unsigned int data_size = timblogiw_frame_size(fh->cur_norm);
+ int err = 0;
+
+ if (vb->baddr && vb->bsize < data_size)
+ /* User provided buffer, but it is too small */
+ return -ENOMEM;
+
+ vb->size = data_size;
+ vb->width = fh->cur_norm->width;
+ vb->height = fh->cur_norm->height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int i;
+ unsigned int size;
+ unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+ timblogiw_bytes_per_line(fh->cur_norm);
+ dma_addr_t addr;
+
+ sg_init_table(buf->sg, ARRAY_SIZE(buf->sg));
+
+ err = videobuf_iolock(vq, vb, NULL);
+ if (err)
+ goto err;
+
+ addr = videobuf_to_dma_contig(vb);
+ for (i = 0, size = 0; size < data_size; i++) {
+ sg_dma_address(buf->sg + i) = addr + size;
+ size += bytes_per_desc;
+ sg_dma_len(buf->sg + i) = (size > data_size) ?
+ (bytes_per_desc - (size - data_size)) :
+ bytes_per_desc;
+ }
+
+ vb->state = VIDEOBUF_PREPARED;
+ buf->cookie = -1;
+ buf->fh = fh;
+ }
+
+ return 0;
+
+err:
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ return err;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+ struct dma_async_tx_descriptor *desc;
+ int sg_elems;
+ int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+ timblogiw_bytes_per_line(fh->cur_norm);
+
+ sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc;
+ sg_elems +=
+ (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0;
+
+ if (list_empty(&fh->capture))
+ vb->state = VIDEOBUF_ACTIVE;
+ else
+ vb->state = VIDEOBUF_QUEUED;
+
+ list_add_tail(&vb->queue, &fh->capture);
+
+ spin_unlock_irq(&fh->queue_lock);
+
+ desc = fh->chan->device->device_prep_slave_sg(fh->chan,
+ buf->sg, sg_elems, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+ if (!desc) {
+ spin_lock_irq(&fh->queue_lock);
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_PREPARED;
+ return;
+ }
+
+ desc->callback_param = buf;
+ desc->callback = timblogiw_dma_cb;
+
+ buf->cookie = desc->tx_submit(desc);
+
+ spin_lock_irq(&fh->queue_lock);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+
+ videobuf_waiton(vq, vb, 0, 0);
+ if (buf->cookie >= 0)
+ dma_sync_wait(fh->chan, buf->cookie);
+
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops timblogiw_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* Device Operations functions */
+
+static int timblogiw_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh;
+ v4l2_std_id std;
+ dma_cap_mask_t mask;
+ int err = 0;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ mutex_lock(&lw->lock);
+ if (lw->opened) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) {
+ struct i2c_adapter *adapt;
+
+ /* find the video decoder */
+ adapt = i2c_get_adapter(lw->pdata.i2c_adapter);
+ if (!adapt) {
+ dev_err(&vdev->dev, "No I2C bus #%d\n",
+ lw->pdata.i2c_adapter);
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* now find the encoder */
+ lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt,
+ lw->pdata.encoder.info, NULL);
+
+ i2c_put_adapter(adapt);
+
+ if (!lw->sd_enc) {
+ dev_err(&vdev->dev, "Failed to get encoder: %s\n",
+ lw->pdata.encoder.module_name);
+ err = -ENODEV;
+ goto out;
+ }
+ }
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ fh->cur_norm = timblogiw_tvnorms;
+ timblogiw_querystd(file, fh, &std);
+ fh->cur_norm = timblogiw_get_norm(std);
+
+ INIT_LIST_HEAD(&fh->capture);
+ spin_lock_init(&fh->queue_lock);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ /* find the DMA channel */
+ fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn,
+ (void *)(uintptr_t)lw->pdata.dma_channel);
+ if (!fh->chan) {
+ dev_err(&vdev->dev, "Failed to get DMA channel\n");
+ kfree(fh);
+ err = -ENODEV;
+ goto out;
+ }
+
+ file->private_data = fh;
+ videobuf_queue_dma_contig_init(&fh->vb_vidq,
+ &timblogiw_video_qops, lw->dev, &fh->queue_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct timblogiw_buffer), fh, NULL);
+
+ lw->opened = true;
+out:
+ mutex_unlock(&lw->lock);
+
+ return err;
+}
+
+static int timblogiw_close(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ dma_release_channel(fh->chan);
+
+ kfree(fh);
+
+ mutex_lock(&lw->lock);
+ lw->opened = false;
+ mutex_unlock(&lw->lock);
+ return 0;
+}
+
+static ssize_t timblogiw_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int timblogiw_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+}
+
+static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->vb_vidq, vma);
+}
+
+/* Platform device functions */
+
+static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
+ .vidioc_querycap = timblogiw_querycap,
+ .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt,
+ .vidioc_g_fmt_vid_cap = timblogiw_g_fmt,
+ .vidioc_try_fmt_vid_cap = timblogiw_try_fmt,
+ .vidioc_s_fmt_vid_cap = timblogiw_s_fmt,
+ .vidioc_g_parm = timblogiw_g_parm,
+ .vidioc_reqbufs = timblogiw_reqbufs,
+ .vidioc_querybuf = timblogiw_querybuf,
+ .vidioc_qbuf = timblogiw_qbuf,
+ .vidioc_dqbuf = timblogiw_dqbuf,
+ .vidioc_g_std = timblogiw_g_std,
+ .vidioc_s_std = timblogiw_s_std,
+ .vidioc_enum_input = timblogiw_enuminput,
+ .vidioc_g_input = timblogiw_g_input,
+ .vidioc_s_input = timblogiw_s_input,
+ .vidioc_streamon = timblogiw_streamon,
+ .vidioc_streamoff = timblogiw_streamoff,
+ .vidioc_querystd = timblogiw_querystd,
+ .vidioc_enum_framesizes = timblogiw_enum_framesizes,
+};
+
+static __devinitconst struct v4l2_file_operations timblogiw_fops = {
+ .owner = THIS_MODULE,
+ .open = timblogiw_open,
+ .release = timblogiw_close,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = timblogiw_mmap,
+ .read = timblogiw_read,
+ .poll = timblogiw_poll,
+};
+
+static __devinitconst struct video_device timblogiw_template = {
+ .name = TIMBLOGIWIN_NAME,
+ .fops = &timblogiw_fops,
+ .ioctl_ops = &timblogiw_ioctl_ops,
+ .release = video_device_release_empty,
+ .minor = -1,
+ .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC
+};
+
+static int __devinit timblogiw_probe(struct platform_device *pdev)
+{
+ int err;
+ struct timblogiw *lw = NULL;
+ struct timb_video_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (!pdata->encoder.module_name)
+ dev_info(&pdev->dev, "Running without decoder\n");
+
+ lw = kzalloc(sizeof(*lw), GFP_KERNEL);
+ if (!lw) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ if (pdev->dev.parent)
+ lw->dev = pdev->dev.parent;
+ else
+ lw->dev = &pdev->dev;
+
+ memcpy(&lw->pdata, pdata, sizeof(lw->pdata));
+
+ mutex_init(&lw->lock);
+
+ lw->video_dev = timblogiw_template;
+
+ strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name));
+ err = v4l2_device_register(NULL, &lw->v4l2_dev);
+ if (err)
+ goto err_register;
+
+ lw->video_dev.v4l2_dev = &lw->v4l2_dev;
+
+ platform_set_drvdata(pdev, lw);
+ video_set_drvdata(&lw->video_dev, lw);
+
+ err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0);
+ if (err) {
+ dev_err(&pdev->dev, "Error reg video: %d\n", err);
+ goto err_request;
+ }
+
+
+ return 0;
+
+err_request:
+ platform_set_drvdata(pdev, NULL);
+ v4l2_device_unregister(&lw->v4l2_dev);
+err_register:
+ kfree(lw);
+err:
+ dev_err(&pdev->dev, "Failed to register: %d\n", err);
+
+ return err;
+}
+
+static int __devexit timblogiw_remove(struct platform_device *pdev)
+{
+ struct timblogiw *lw = platform_get_drvdata(pdev);
+
+ video_unregister_device(&lw->video_dev);
+
+ v4l2_device_unregister(&lw->v4l2_dev);
+
+ kfree(lw);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver timblogiw_platform_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = timblogiw_probe,
+ .remove = __devexit_p(timblogiw_remove),
+};
+
+/* Module functions */
+
+static int __init timblogiw_init(void)
+{
+ return platform_driver_register(&timblogiw_platform_driver);
+}
+
+static void __exit timblogiw_exit(void)
+{
+ platform_driver_unregister(&timblogiw_platform_driver);
+}
+
+module_init(timblogiw_init);
+module_exit(timblogiw_exit);
+
+MODULE_DESCRIPTION(TIMBLOGIWIN_NAME);
+MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/drivers/media/video/tlg2300/Kconfig b/drivers/media/video/tlg2300/Kconfig
index 1686ebfa6951..645d915267e6 100644
--- a/drivers/media/video/tlg2300/Kconfig
+++ b/drivers/media/video/tlg2300/Kconfig
@@ -1,9 +1,9 @@
config VIDEO_TLG2300
tristate "Telegent TLG2300 USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT && SND && DVB_CORE
+ depends on VIDEO_DEV && I2C && SND && DVB_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select SND_PCM
select VIDEOBUF_DVB
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 4555f4a5f4c8..99c81a9a4f46 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -36,7 +36,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include "vendorcmds.h"
#include "pd-common.h"
@@ -453,7 +452,8 @@ static int poseidon_probe(struct usb_interface *interface,
device_init_wakeup(&udev->dev, 1);
#ifdef CONFIG_PM
- pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
+ pm_runtime_set_autosuspend_delay(&pd->udev->dev,
+ 1000 * PM_SUSPEND_DELAY);
usb_enable_autosuspend(pd->udev);
if (in_hibernation(pd)) {
@@ -485,15 +485,11 @@ static void poseidon_disconnect(struct usb_interface *interface)
/*unregister v4l2 device */
v4l2_device_unregister(&pd->v4l2_dev);
- lock_kernel();
- {
- pd_dvb_usb_device_exit(pd);
- poseidon_fm_exit(pd);
+ pd_dvb_usb_device_exit(pd);
+ poseidon_fm_exit(pd);
- poseidon_audio_free(pd);
- pd_video_exit(pd);
- }
- unlock_kernel();
+ poseidon_audio_free(pd);
+ pd_video_exit(pd);
usb_set_intfdata(interface, NULL);
kref_put(&pd->kref, poseidon_delete);
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index e63b40f5a706..c799e4eb6fcd 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -789,7 +789,7 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
* Get the value of a TVP7002 decoder device register.
* Returns zero when successful, -EINVAL if register read fails or
* access to I2C client fails, -EPERM if the call is not allowed
- * by diabled CAP_SYS_ADMIN.
+ * by disabled CAP_SYS_ADMIN.
*/
static int tvp7002_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
deleted file mode 100644
index dfa7fc68a657..000000000000
--- a/drivers/media/video/usbvideo/Kconfig
+++ /dev/null
@@ -1,45 +0,0 @@
-config VIDEO_USBVIDEO
- tristate
-
-config USB_VICAM
- tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
- depends on VIDEO_V4L1 && EXPERIMENTAL
- select VIDEO_USBVIDEO
- ---help---
- Say Y here if you have 3com homeconnect camera (vicam).
-
- To compile this driver as a module, choose M here: the
- module will be called vicam.
-
-config USB_IBMCAM
- tristate "USB IBM (Xirlink) C-it Camera support (DEPRECATED)"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- This driver is DEPRECATED please use the gspca xirlink_cit module
- instead.
-
- Say Y here if you want to connect a IBM "C-It" camera, also known as
- "Xirlink PC Camera" to your computer's USB port.
-
- To compile this driver as a module, choose M here: the
- module will be called ibmcam.
-
- This camera has several configuration options which
- can be specified when you load the module. Read
- <file:Documentation/video4linux/ibmcam.txt> to learn more.
-
-config USB_KONICAWC
- tristate "USB Konica Webcam support (DEPRECATED)"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- This driver is DEPRECATED (and known to crash) please use the
- gspca konica module instead.
-
- Say Y here if you want support for webcams based on a Konica
- chipset. This is known to work with the Intel YC76 webcam.
-
- To compile this driver as a module, choose M here: the
- module will be called konicawc.
-
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
deleted file mode 100644
index bb52eb8dc2f9..000000000000
--- a/drivers/media/video/usbvideo/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
-obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
-obj-$(CONFIG_USB_KONICAWC) += konicawc.o
-obj-$(CONFIG_USB_VICAM) += vicam.o
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
deleted file mode 100644
index b08549661781..000000000000
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ /dev/null
@@ -1,3977 +0,0 @@
-/*
- * USB IBM C-It Video Camera driver
- *
- * Supports Xirlink C-It Video Camera, IBM PC Camera,
- * IBM NetCamera and Veo Stingray.
- *
- * This driver is based on earlier work of:
- *
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- *
- * 5/24/00 Removed optional (and unnecessary) locking of the driver while
- * the device remains plugged in. Corrected race conditions in ibmcam_open
- * and ibmcam_probe() routines using this as a guideline:
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define IBMCAM_VENDOR_ID 0x0545
-#define IBMCAM_PRODUCT_ID 0x8080
-#define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */
-#define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */
-#define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */
-
-#define MAX_IBMCAM 4 /* How many devices we allow to connect */
-#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */
-
-/* Header signatures */
-
-/* Model 1 header: 00 FF 00 xx */
-#define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */
-#define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */
-#define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */
-
-#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */
-#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */
-#define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */
-#define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */
-
-/* Video sizes supported */
-#define VIDEOSIZE_128x96 VIDEOSIZE(128, 96)
-#define VIDEOSIZE_176x144 VIDEOSIZE(176,144)
-#define VIDEOSIZE_352x288 VIDEOSIZE(352,288)
-#define VIDEOSIZE_320x240 VIDEOSIZE(320,240)
-#define VIDEOSIZE_352x240 VIDEOSIZE(352,240)
-#define VIDEOSIZE_640x480 VIDEOSIZE(640,480)
-#define VIDEOSIZE_160x120 VIDEOSIZE(160,120)
-
-/* Video sizes supported */
-enum {
- SIZE_128x96 = 0,
- SIZE_160x120,
- SIZE_176x144,
- SIZE_320x240,
- SIZE_352x240,
- SIZE_352x288,
- SIZE_640x480,
- /* Add/remove/rearrange items before this line */
- SIZE_LastItem
-};
-
-/*
- * This structure lives in uvd->user field.
- */
-typedef struct {
- int initialized; /* Had we already sent init sequence? */
- int camera_model; /* What type of IBM camera we got? */
- int has_hdr;
-} ibmcam_t;
-#define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams;
-
-static int debug;
-
-static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth = 8;
-static const int min_canvasHeight = 4;
-
-static int lighting = 1; /* Medium */
-
-#define SHARPNESS_MIN 0
-#define SHARPNESS_MAX 6
-static int sharpness = 4; /* Low noise, good details */
-
-#define FRAMERATE_MIN 0
-#define FRAMERATE_MAX 6
-static int framerate = -1;
-
-static int size = SIZE_352x288;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-/* Settings for camera model 2 */
-static int init_model2_rg2 = -1;
-static int init_model2_sat = -1;
-static int init_model2_yb = -1;
-
-/* 01.01.08 - Added for RCA video in support -LO */
-/* Settings for camera model 3 */
-static int init_model3_input;
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-module_param(lighting, int, 0);
-MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)");
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-module_param(init_model2_rg2, int, 0);
-MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
-module_param(init_model2_sat, int, 0);
-MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
-module_param(init_model2_yb, int, 0);
-MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
-
-/* 01.01.08 - Added for RCA video in support -LO */
-module_param(init_model3_input, int, 0);
-MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
-
-MODULE_AUTHOR ("Dmitri");
-MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
-MODULE_LICENSE("GPL");
-
-/* Still mysterious i2c commands */
-static const unsigned short unknown_88 = 0x0088;
-static const unsigned short unknown_89 = 0x0089;
-static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
-static const unsigned short contrast_14 = 0x0014;
-static const unsigned short light_27 = 0x0027;
-static const unsigned short sharp_13 = 0x0013;
-
-/* i2c commands for Model 2 cameras */
-static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */
-static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */
-static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */
-static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */
-static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */
-static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */
-static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */
-
-struct struct_initData {
- unsigned char req;
- unsigned short value;
- unsigned short index;
-};
-
-/*
- * ibmcam_size_to_videosize()
- *
- * This procedure converts module option 'size' into the actual
- * videosize_t that defines the image size in pixels. We need
- * simplified 'size' because user wants a simple enumerated list
- * of choices, not an infinite set of possibilities.
- */
-static videosize_t ibmcam_size_to_videosize(int size)
-{
- videosize_t vs = VIDEOSIZE_352x288;
- RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
- switch (size) {
- case SIZE_128x96:
- vs = VIDEOSIZE_128x96;
- break;
- case SIZE_160x120:
- vs = VIDEOSIZE_160x120;
- break;
- case SIZE_176x144:
- vs = VIDEOSIZE_176x144;
- break;
- case SIZE_320x240:
- vs = VIDEOSIZE_320x240;
- break;
- case SIZE_352x240:
- vs = VIDEOSIZE_352x240;
- break;
- case SIZE_352x288:
- vs = VIDEOSIZE_352x288;
- break;
- case SIZE_640x480:
- vs = VIDEOSIZE_640x480;
- break;
- default:
- err("size=%d. is not valid", size);
- break;
- }
- return vs;
-}
-
-/*
- * ibmcam_find_header()
- *
- * Locate one of supported header markers in the queue.
- * Once found, remove all preceding bytes AND the marker (4 bytes)
- * from the data pump queue. Whatever follows must be video lines.
- *
- * History:
- * 1/21/00 Created.
- */
-static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
-{
- struct usbvideo_frame *frame;
- ibmcam_t *icam;
-
- if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
- err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
- return scan_EndParse;
- }
- icam = IBMCAM_T(uvd);
- assert(icam != NULL);
- frame = &uvd->frame[uvd->curframe];
- icam->has_hdr = 0;
- switch (icam->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int marker_len = 4;
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
- {
-#if 0 /* This code helps to detect new frame markers */
- dev_info(&uvd->dev->dev,
- "Header sig: 00 FF 00 %02X\n",
- RING_QUEUE_PEEK(&uvd->dp, 3));
-#endif
- frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
- if ((frame->header == HDRSIG_MODEL1_128x96) ||
- (frame->header == HDRSIG_MODEL1_176x144) ||
- (frame->header == HDRSIG_MODEL1_352x288))
- {
-#if 0
- dev_info(&uvd->dev->dev,
- "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- break;
- }
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
- {
- int marker_len = 0;
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- marker_len = 10;
- break;
- default:
- marker_len = 2;
- break;
- }
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
- {
-#if 0
- dev_info(&uvd->dev->dev, "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- frame->header = HDRSIG_MODEL1_176x144;
- break;
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- case IBMCAM_MODEL_3:
- { /*
- * Headers: (one precedes every frame). nc=no compression,
- * bq=best quality bf=best frame rate.
- *
- * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
- * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
- * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
- *
- * Bytes '00 FF' seem to indicate header. Other two bytes
- * encode the frame type. This is a set of bit fields that
- * encode image size, compression type etc. These fields
- * do NOT contain frame number because all frames carry
- * the same header.
- */
- const int marker_len = 4;
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
- {
- /*
- * Combine 2 bytes of frame type into one
- * easy to use value
- */
- unsigned long byte3, byte4;
-
- byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
- byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
- frame->header = (byte3 << 8) | byte4;
-#if 0
- dev_info(&uvd->dev->dev, "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- break;
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- default:
- break;
- }
- if (!icam->has_hdr) {
- if (uvd->debug > 2)
- dev_info(&uvd->dev->dev,
- "Skipping frame, no header\n");
- return scan_EndParse;
- }
-
- /* Header found */
- icam->has_hdr = 1;
- uvd->stats.header_count++;
- frame->scanstate = ScanState_Lines;
- frame->curline = 0;
-
- if (flags & FLAGS_FORCE_TESTPATTERN) {
- usbvideo_TestPattern(uvd, 1, 1);
- return scan_NextFrame;
- }
- return scan_Continue;
-}
-
-/*
- * ibmcam_parse_lines()
- *
- * Parse one line (interlaced) from the buffer, put
- * decoded RGB value into the current frame buffer
- * and add the written number of bytes (RGB) to
- * the *pcopylen.
- *
- * History:
- * 21-Jan-2000 Created.
- * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
- */
-static enum ParseState ibmcam_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *f;
- ibmcam_t *icam;
- unsigned int len, scanLength, scanHeight, order_uv, order_yc;
- int v4l_linesize; /* V4L line offset */
- const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */
- const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */
- const int ccm = 128; /* Color correction median - see below */
- int y, u, v, i, frame_done=0, color_corr;
- static unsigned char lineBuffer[640*3];
- unsigned const char *chromaLine, *lumaLine;
-
- assert(uvd != NULL);
- assert(frame != NULL);
- icam = IBMCAM_T(uvd);
- assert(icam != NULL);
- color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
- RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
- /* Model 4 frame markers do not carry image size identification */
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- case VIDEOSIZE_160x120:
- case VIDEOSIZE_176x144:
- scanLength = VIDEOSIZE_X(uvd->videosize);
- scanHeight = VIDEOSIZE_Y(uvd->videosize);
- break;
- default:
- err("ibmcam_parse_lines: Wrong mode.");
- return scan_Out;
- }
- order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */
- order_uv = 1; /* Always true in this algorithm */
- } else {
- switch (frame->header) {
- case HDRSIG_MODEL1_128x96:
- scanLength = 128;
- scanHeight = 96;
- order_uv = 1; /* U Y V Y ... */
- break;
- case HDRSIG_MODEL1_176x144:
- scanLength = 176;
- scanHeight = 144;
- order_uv = 1; /* U Y V Y ... */
- break;
- case HDRSIG_MODEL1_352x288:
- scanLength = 352;
- scanHeight = 288;
- order_uv = 0; /* Y V Y V ... */
- break;
- default:
- err("Unknown header signature 00 FF 00 %02lX", frame->header);
- return scan_NextFrame;
- }
- /* order_yc: true=Yc false=cY ('c'=either U or V) */
- order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
- }
-
- len = scanLength * 3;
- assert(len <= sizeof(lineBuffer));
-
- /*
- * Lines are organized this way:
- *
- * I420:
- * ~~~~
- * <scanLength->
- * ___________________________________
- * |-----Y-----|---UVUVUV...UVUV-----| \
- * |-----------+---------------------| \
- * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced)
- * |... ... | ... | /
- * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced)
- * |___________|_____________________| /
- * \ \
- * lumaLine chromaLine
- */
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Mind that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
- return scan_NextFrame;
-
- /*
- * Now we are sure that entire line (representing all 'scanLength'
- * pixels from the camera) is available in the buffer. We
- * start copying the line left-aligned to the V4L buffer.
- * If the camera line is shorter then we should pad the V4L
- * buffer with something (black) to complete the line.
- */
- assert(frame->data != NULL);
- f = frame->data + (v4l_linesize * frame->curline);
-
- /*
- * To obtain chrominance data from the 'chromaLine' use this:
- * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
- * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
- *
- * Indices must be calculated this way:
- * v_index = (i >> 1) << 2;
- * u_index = (i >> 1) << 2 + 2;
- *
- * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
- */
- lumaLine = lineBuffer;
- chromaLine = lineBuffer + scanLength;
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
- {
- unsigned char rv, gv, bv; /* RGB components */
-
- /* Check for various visual debugging hints (colorized pixels) */
- if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
- /*
- * This is bad and should not happen. This means that
- * we somehow overshoot the line and encountered new
- * frame! Obviously our camera/V4L frame size is out
- * of whack. This cyan dot will help you to figure
- * out where exactly the new frame arrived.
- */
- if (icam->has_hdr == 1) {
- bv = 0; /* Yellow marker */
- gv = 0xFF;
- rv = 0xFF;
- } else {
- bv = 0xFF; /* Cyan marker */
- gv = 0xFF;
- rv = 0;
- }
- icam->has_hdr = 0;
- goto make_pixel;
- }
-
- /*
- * Check if we are still in range. We may be out of range if our
- * V4L canvas is wider or taller than the camera "native" image.
- * Then we quickly fill the remainder of the line with zeros to
- * make black color and quit the horizontal scanning loop.
- */
- if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
- /* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
- memset(f, 0, v4l_linesize - j);
- break;
- }
-
- y = lumaLine[i];
- if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
- rv = gv = bv = y;
- else {
- int off_0, off_2;
-
- off_0 = (i >> 1) << 2;
- off_2 = off_0 + 2;
-
- if (order_yc) {
- off_0++;
- off_2++;
- }
- if (!order_uv) {
- off_0 += 2;
- off_2 -= 2;
- }
- u = chromaLine[off_0] + hue_corr;
- v = chromaLine[off_2] + hue2_corr;
-
- /* Apply color correction */
- if (color_corr != 0) {
- /* Magnify up to 2 times, reduce down to zero saturation */
- u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
- v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
- }
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- }
-
- make_pixel:
- /*
- * The purpose of creating the pixel here, in one,
- * dedicated place is that we may need to make the
- * pixel wider and taller than it actually is. This
- * may be used if camera generates small frames for
- * sake of frame rate (or any other reason.)
- *
- * The output data consists of B, G, R bytes
- * (in this order).
- */
-#if USES_IBMCAM_PUTPIXEL
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-#else
- *f++ = bv;
- *f++ = gv;
- *f++ = rv;
-#endif
- /*
- * Typically we do not decide within a legitimate frame
- * that we want to end the frame. However debugging code
- * may detect marker of new frame within the data. Then
- * this condition activates. The 'data' pointer is already
- * pointing at the new marker, so we'd better leave it as is.
- */
- if (frame_done)
- break; /* End scanning of lines */
- }
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- if (pcopylen != NULL)
- *pcopylen += 2 * v4l_linesize;
- frame->deinterlace = Deinterlace_FillOddLines;
-
- if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
- return scan_NextFrame;
- else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model2_320x240_parse_lines()
- *
- * This procedure deals with a weird RGB format that is produced by IBM
- * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
- * depending on horizontal size of the picture:
- *
- * <--- 160 or 176 pairs of RA,RB bytes ----->
- * *-----------------------------------------* \
- * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines,
- * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total
- * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield
- * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing.
- *
- * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
- * defines ONE pixel. Therefore this format yields 176x144 "decoded"
- * resolution at best. I do not know why camera sends such format - the
- * previous model (1) just used interlaced I420 and everyone was happy.
- *
- * I do not know what is the difference between RAi and RBi bytes. Both
- * seemingly represent R component, but slightly vary in value (so that
- * the picture looks a bit colored if one or another is used). I use
- * them both as R component in attempt to at least partially recover the
- * lost resolution.
- */
-static enum ParseState ibmcam_model2_320x240_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *f, *la, *lb;
- unsigned int len;
- int v4l_linesize; /* V4L line offset */
- int i, j, frame_done=0, color_corr;
- int scanLength, scanHeight;
- static unsigned char lineBuffer[352*2];
-
- switch (uvd->videosize) {
- case VIDEOSIZE_320x240:
- case VIDEOSIZE_352x240:
- case VIDEOSIZE_352x288:
- scanLength = VIDEOSIZE_X(uvd->videosize);
- scanHeight = VIDEOSIZE_Y(uvd->videosize);
- break;
- default:
- err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
- return scan_Out;
- }
-
- color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- len = scanLength * 2; /* See explanation above */
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Mind that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
- return scan_NextFrame;
-
- la = lineBuffer;
- lb = lineBuffer + scanLength;
-
- /*
- * Now we are sure that entire line (representing all
- * VIDEOSIZE_X(frame->request)
- * pixels from the camera) is available in the scratch buffer. We
- * start copying the line left-aligned to the V4L buffer (which
- * might be larger - not smaller, hopefully). If the camera
- * line is shorter then we should pad the V4L buffer with something
- * (black in this case) to complete the line.
- */
- f = frame->data + (v4l_linesize * frame->curline);
-
- /* Fill the 2-line strip */
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y, rv, gv, bv; /* RGB components */
-
- j = i & (~1);
-
- /* Check for various visual debugging hints (colorized pixels) */
- if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
- if (IBMCAM_T(uvd)->has_hdr == 1) {
- bv = 0; /* Yellow marker */
- gv = 0xFF;
- rv = 0xFF;
- } else {
- bv = 0xFF; /* Cyan marker */
- gv = 0xFF;
- rv = 0;
- }
- IBMCAM_T(uvd)->has_hdr = 0;
- goto make_pixel;
- }
-
- /*
- * Check if we are still in range. We may be out of range if our
- * V4L canvas is wider or taller than the camera "native" image.
- * Then we quickly fill the remainder of the line with zeros to
- * make black color and quit the horizontal scanning loop.
- */
- if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int offset = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
- /* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + offset;
-#endif
- memset(f, 0, v4l_linesize - offset);
- break;
- }
-
- /*
- * Here I use RA and RB components, one per physical pixel.
- * This causes fine vertical grid on the picture but may improve
- * horizontal resolution. If you prefer replicating, use this:
- * rv = la[j + 0]; ... or ... rv = la[j + 1];
- * then the pixel will be replicated.
- */
- rv = la[i];
- gv = lb[j + 1];
- bv = lb[j + 0];
-
- y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
-
- if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
- rv = gv = bv = y;
- else if (color_corr != 128) {
-
- /* Calculate difference between color and brightness */
- rv -= y;
- gv -= y;
- bv -= y;
-
- /* Scale differences */
- rv = (rv * color_corr) / 128;
- gv = (gv * color_corr) / 128;
- bv = (bv * color_corr) / 128;
-
- /* Reapply brightness */
- rv += y;
- gv += y;
- bv += y;
-
- /* Watch for overflows */
- RESTRICT_TO_RANGE(rv, 0, 255);
- RESTRICT_TO_RANGE(gv, 0, 255);
- RESTRICT_TO_RANGE(bv, 0, 255);
- }
-
- make_pixel:
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
- }
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- *pcopylen += v4l_linesize * 2;
- frame->deinterlace = Deinterlace_FillOddLines;
-
- if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
- return scan_NextFrame;
- else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model3_parse_lines()
- *
- * | Even lines | Odd Lines |
- * -----------------------------------|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |............|.....................|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |------------+---------------------|
- *
- * There is one (U, V) chroma pair for every four luma (Y) values. This
- * function reads a pair of lines at a time and obtains missing chroma values
- * from adjacent pixels.
- */
-static enum ParseState ibmcam_model3_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *data;
- const unsigned char *color;
- unsigned int len;
- int v4l_linesize; /* V4L line offset */
- const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */
- const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */
- const int ccm = 128; /* Color correction median - see below */
- int i, u, v, rw, data_w=0, data_h=0, color_corr;
- static unsigned char lineBuffer[640*3];
- int line;
-
- color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
- RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- /* The header tells us what sort of data is in this frame */
- switch (frame->header) {
- /*
- * Uncompressed modes (that are easy to decode).
- */
- case 0x0308:
- data_w = 640;
- data_h = 480;
- break;
- case 0x0208:
- data_w = 320;
- data_h = 240;
- break;
- case 0x020A:
- data_w = 160;
- data_h = 120;
- break;
- /*
- * Compressed modes (ViCE - that I don't know how to decode).
- */
- case 0x0328: /* 640x480, best quality compression */
- case 0x0368: /* 640x480, best frame rate compression */
- case 0x0228: /* 320x240, best quality compression */
- case 0x0268: /* 320x240, best frame rate compression */
- case 0x02CA: /* 160x120, best quality compression */
- case 0x02EA: /* 160x120, best frame rate compression */
- /* Do nothing with this - not supported */
- err("Unsupported mode $%04lx", frame->header);
- return scan_NextFrame;
- default:
- /* Catch unknown headers, may help in learning new headers */
- err("Strange frame->header=$%08lx", frame->header);
- return scan_NextFrame;
- }
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Note that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 1) >= data_h) {
- if (uvd->debug >= 3)
- dev_info(&uvd->dev->dev,
- "Reached line %d. (frame is done)\n",
- frame->curline);
- return scan_NextFrame;
- }
-
- /* Make sure that lineBuffer can store two lines of data */
- len = 3 * data_w; /* <y-data> <uyvy-data> */
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for two lines */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck two lines of data out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- data = lineBuffer;
- color = data + data_w; /* Point to where color planes begin */
-
- /* Bottom-to-top scanning */
- rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
- RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
-
- /* Iterate over two lines. */
- for (line = 0; line < 2; line++) {
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y;
- int rv, gv, bv; /* RGB components */
-
- if (i >= data_w) {
- RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0);
- continue;
- }
-
- /* first line is YYY...Y; second is UYVY...UYVY */
- y = data[(line == 0) ? i : (i*2 + 1)];
-
- /* Apply static color correction */
- u = color[(i/2)*4] + hue_corr;
- v = color[(i/2)*4 + 2] + hue2_corr;
-
- /* Apply color correction */
- if (color_corr != 0) {
- /* Magnify up to 2 times, reduce down to zero saturation */
- u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
- v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
- }
-
-
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* No deinterlacing */
- }
-
- /* Check for the end of requested data */
- if (rw == 0)
- break;
-
- /* Prepare for the second line */
- rw--;
- data = lineBuffer + data_w;
- }
- frame->deinterlace = Deinterlace_None;
-
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- *pcopylen += 2 * v4l_linesize;
-
- if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
- if (uvd->debug >= 3) {
- dev_info(&uvd->dev->dev,
- "All requested lines (%ld.) done.\n",
- VIDEOSIZE_Y(frame->request));
- }
- return scan_NextFrame;
- } else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model4_128x96_parse_lines()
- *
- * This decoder is for one strange data format that is produced by Model 4
- * camera only in 128x96 mode. This is RGB format and here is its description.
- * First of all, this is non-interlaced stream, meaning that all scan lines
- * are present in the datastream. There are 96 consecutive blocks of data
- * that describe all 96 lines of the image. Each block is 5*128 bytes long
- * and carries R, G, B components. The format of the block is shown in the
- * code below. First 128*2 bytes are interleaved R and G components. Then
- * we have a gap (junk data) 64 bytes long. Then follow B and something
- * else, also interleaved (this makes another 128*2 bytes). After that
- * probably another 64 bytes of junk follow.
- *
- * History:
- * 10-Feb-2001 Created.
- */
-static enum ParseState ibmcam_model4_128x96_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- const unsigned char *data_rv, *data_gv, *data_bv;
- unsigned int len;
- int i, v4l_linesize; /* V4L line offset */
- const int data_w=128, data_h=96;
- static unsigned char lineBuffer[128*5];
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Note that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 1) >= data_h) {
- if (uvd->debug >= 3)
- dev_info(&uvd->dev->dev,
- "Reached line %d. (frame is done)\n",
- frame->curline);
- return scan_NextFrame;
- }
-
- /*
- * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
- * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
- */
-
- /* Make sure there's enough data for the entire line */
- len = 5 * data_w;
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- data_rv = lineBuffer;
- data_gv = lineBuffer + 1;
- data_bv = lineBuffer + data_w*2 + data_w/2;
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int rv, gv, bv; /* RGB components */
- if (i < data_w) {
- const int j = i * 2;
- gv = data_rv[j];
- rv = data_gv[j];
- bv = data_bv[j];
- if (flags & FLAGS_MONOCHROME) {
- unsigned long y;
- y = rv + gv + bv;
- y /= 3;
- if (y > 0xFF)
- y = 0xFF;
- rv = gv = bv = (unsigned char) y;
- }
- } else {
- rv = gv = bv = 0;
- }
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
- }
- frame->deinterlace = Deinterlace_None;
- frame->curline++;
- *pcopylen += v4l_linesize;
-
- if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
- if (uvd->debug >= 3) {
- dev_info(&uvd->dev->dev,
- "All requested lines (%ld.) done.\n",
- VIDEOSIZE_Y(frame->request));
- }
- return scan_NextFrame;
- } else
- return scan_Continue;
-}
-
-/*
- * ibmcam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ibmcam_find_header() or ibmcam_parse_lines() to do most
- * of work.
- *
- * History:
- * 1/21/00 Created.
- */
-static void ibmcam_ProcessIsocData(struct uvd *uvd,
- struct usbvideo_frame *frame)
-{
- enum ParseState newstate;
- long copylen = 0;
- int mod = IBMCAM_T(uvd)->camera_model;
-
- while (1) {
- newstate = scan_Out;
- if (RingQueue_GetLength(&uvd->dp) > 0) {
- if (frame->scanstate == ScanState_Scanning) {
- newstate = ibmcam_find_header(uvd);
- } else if (frame->scanstate == ScanState_Lines) {
- if ((mod == IBMCAM_MODEL_2) &&
- ((uvd->videosize == VIDEOSIZE_352x288) ||
- (uvd->videosize == VIDEOSIZE_320x240) ||
- (uvd->videosize == VIDEOSIZE_352x240)))
- {
- newstate = ibmcam_model2_320x240_parse_lines(
- uvd, frame, &copylen);
- } else if (mod == IBMCAM_MODEL_4) {
- /*
- * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
- * for 320x240 and above; 160x120 and 176x144 uses Model 1
- * decoder (YUV), and 128x96 mode uses ???
- */
- if ((uvd->videosize == VIDEOSIZE_352x288) ||
- (uvd->videosize == VIDEOSIZE_320x240) ||
- (uvd->videosize == VIDEOSIZE_352x240))
- {
- newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
- } else if (uvd->videosize == VIDEOSIZE_128x96) {
- newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
- } else {
- newstate = ibmcam_parse_lines(uvd, frame, &copylen);
- }
- } else if (mod == IBMCAM_MODEL_3) {
- newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
- } else {
- newstate = ibmcam_parse_lines(uvd, frame, &copylen);
- }
- }
- }
- if (newstate == scan_Continue)
- continue;
- else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
- break;
- else
- return; /* scan_EndParse */
- }
-
- if (newstate == scan_NextFrame) {
- frame->frameState = FrameState_Done;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
- /* Need software contrast adjustment for those cameras */
- frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
- }
- }
-
- /* Update the frame's uncompressed length. */
- frame->seqRead_Length += copylen;
-
-#if 0
- {
- static unsigned char j=0;
- memset(frame->data, j++, uvd->max_frame_size);
- frame->frameState = FrameState_Ready;
- }
-#endif
-}
-
-/*
- * ibmcam_veio()
- *
- * History:
- * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ibmcam_veio(
- struct uvd *uvd,
- unsigned char req,
- unsigned short value,
- unsigned short index)
-{
- static const char proc[] = "ibmcam_veio";
- unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
- int i;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return 0;
-
- if (req == 1) {
- i = usb_control_msg(
- uvd->dev,
- usb_rcvctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
- value,
- index,
- cp,
- sizeof(cp),
- 1000);
-#if 0
- dev_info(&uvd->dev->dev,
- "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
- "(req=$%02x val=$%04x ind=$%04x)\n",
- cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
- req, value, index);
-#endif
- } else {
- i = usb_control_msg(
- uvd->dev,
- usb_sndctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
- value,
- index,
- NULL,
- 0,
- 1000);
- }
- if (i < 0) {
- err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
- proc, i);
- uvd->last_error = i;
- }
- return i;
-}
-
-/*
- * ibmcam_calculate_fps()
- *
- * This procedure roughly calculates the real frame rate based
- * on FPS code (framerate=NNN option). Actual FPS differs
- * slightly depending on lighting conditions, so that actual frame
- * rate is determined by the camera. Since I don't know how to ask
- * the camera what FPS is now I have to use the FPS code instead.
- *
- * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
- * Corresponding real FPS should be in range [3..30] frames per second.
- * The conversion formula is obvious:
- *
- * real_fps = 3 + (fps_code * 4.5)
- *
- * History:
- * 1/18/00 Created.
- */
-static int ibmcam_calculate_fps(struct uvd *uvd)
-{
- return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ibmcam_send_FF_04_02()
- *
- * This procedure sends magic 3-command prefix to the camera.
- * The purpose of this prefix is not known.
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_send_FF_04_02(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
- ibmcam_veio(uvd, 0, 0x0004, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_00_04_06(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x0004, 0x0124);
- ibmcam_veio(uvd, 0, 0x0006, 0x0124);
-}
-
-static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-}
-
-static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
-{
- ibmcam_send_x_00(uvd, x);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
- ibmcam_send_x_01_00_05(uvd, unknown_88);
- ibmcam_send_x_00_05(uvd, fkey);
- ibmcam_send_x_00_05_02_08_01(uvd, val);
- ibmcam_send_x_00_05(uvd, unknown_88);
- ibmcam_send_x_00_05_02_01(uvd, fkey);
- ibmcam_send_x_00_05(uvd, unknown_89);
- ibmcam_send_x_00(uvd, fkey);
- ibmcam_send_00_04_06(uvd);
- ibmcam_veio(uvd, 1, 0x0000, 0x0126);
- ibmcam_send_FF_04_02(uvd);
-}
-
-static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
- ibmcam_send_x_01_00_05 (uvd, unknown_88);
- ibmcam_send_x_00_05 (uvd, fkey);
- ibmcam_send_x_00_05_02 (uvd, val);
-}
-
-static void ibmcam_model2_Packet2(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
- ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
-}
-
-static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
- ibmcam_veio(uvd, 0, v1, 0x012f);
- ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
- ibmcam_veio(uvd, 0, 0xc719, 0x0124);
- ibmcam_veio(uvd, 0, v2, 0x0127);
-
- ibmcam_model2_Packet2(uvd);
-}
-
-/*
- * ibmcam_model3_Packet1()
- *
- * 00_0078_012d
- * 00_0097_012f
- * 00_d141_0124
- * 00_0096_0127
- * 00_fea8_0124
-*/
-static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
- ibmcam_veio(uvd, 0, 0x0078, 0x012d);
- ibmcam_veio(uvd, 0, v1, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, v2, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-}
-
-static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
-{
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0026, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, i, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-}
-
-/*
- * ibmcam_adjust_contrast()
- *
- * The contrast value changes from 0 (high contrast) to 15 (low contrast).
- * This is in reverse to usual order of things (such as TV controls), so
- * we reverse it again here.
- *
- * TODO: we probably don't need to send the setup 5 times...
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_adjust_contrast(struct uvd *uvd)
-{
- unsigned char a_contrast = uvd->vpic.contrast >> 12;
- unsigned char new_contrast;
-
- if (a_contrast >= 16)
- a_contrast = 15;
- new_contrast = 15 - a_contrast;
- if (new_contrast == uvd->vpic_old.contrast)
- return;
- uvd->vpic_old.contrast = new_contrast;
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int ntries = 5;
- int i;
- for (i=0; i < ntries; i++) {
- ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
- ibmcam_send_FF_04_02(uvd);
- }
- break;
- }
- case IBMCAM_MODEL_2:
- case IBMCAM_MODEL_4:
- /* Models 2, 4 do not have this control; implemented in software. */
- break;
- case IBMCAM_MODEL_3:
- { /* Preset hardware values */
- static const struct {
- unsigned short cv1;
- unsigned short cv2;
- unsigned short cv3;
- } cv[7] = {
- { 0x05, 0x05, 0x0f }, /* Minimum */
- { 0x04, 0x04, 0x16 },
- { 0x02, 0x03, 0x16 },
- { 0x02, 0x08, 0x16 },
- { 0x01, 0x0c, 0x16 },
- { 0x01, 0x0e, 0x16 },
- { 0x01, 0x10, 0x16 } /* Maximum */
- };
- int i = a_contrast / 2;
- RESTRICT_TO_RANGE(i, 0, 6);
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
- ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
- ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_change_lighting_conditions()
- *
- * Camera model 1:
- * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
- *
- * Camera model 2:
- * We have 16 levels of lighting, 0 for bright light and up to 15 for
- * low light. But values above 5 or so are useless because camera is
- * not really capable to produce anything worth viewing at such light.
- * This setting may be altered only in certain camera state.
- *
- * Low lighting forces slower FPS. Lighting is set as a module parameter.
- *
- * History:
- * 1/5/00 Created.
- * 2/20/00 Added support for Model 2 cameras.
- */
-static void ibmcam_change_lighting_conditions(struct uvd *uvd)
-{
- if (debug > 0)
- dev_info(&uvd->dev->dev,
- "%s: Set lighting to %hu.\n", __func__, lighting);
-
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int ntries = 5;
- int i;
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
- break;
- }
- case IBMCAM_MODEL_2:
-#if 0
- /*
- * This command apparently requires camera to be stopped. My
- * experiments showed that it -is- possible to alter the lighting
- * conditions setting "on the fly", but why bother? This setting does
- * not work reliably in all cases, so I decided simply to leave the
- * setting where Xirlink put it - in the camera setup phase. This code
- * is commented out because it does not work at -any- moment, so its
- * presence makes no sense. You may use it for experiments.
- */
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */
- ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */
-#endif
- break;
- case IBMCAM_MODEL_3:
- case IBMCAM_MODEL_4:
- default:
- break;
- }
-}
-
-/*
- * ibmcam_set_sharpness()
- *
- * Cameras model 1 have internal smoothing feature. It is controlled by value in
- * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
- * Recommended value is 4. Cameras model 2 do not have this feature at all.
- */
-static void ibmcam_set_sharpness(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
- unsigned short i, sv;
-
- RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
- if (debug > 0)
- dev_info(&uvd->dev->dev, "%s: Set sharpness to %hu.\n",
- __func__, sharpness);
-
- sv = sa[sharpness - SHARPNESS_MIN];
- for (i=0; i < 2; i++) {
- ibmcam_send_x_01_00_05 (uvd, unknown_88);
- ibmcam_send_x_00_05 (uvd, sharp_13);
- ibmcam_send_x_00_05_02 (uvd, sv);
- }
- break;
- }
- case IBMCAM_MODEL_2:
- case IBMCAM_MODEL_4:
- /* Models 2, 4 do not have this control */
- break;
- case IBMCAM_MODEL_3:
- { /*
- * "Use a table of magic numbers.
- * This setting doesn't really change much.
- * But that's how Windows does it."
- */
- static const struct {
- unsigned short sv1;
- unsigned short sv2;
- unsigned short sv3;
- unsigned short sv4;
- } sv[7] = {
- { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */
- { 0x01, 0x04, 0x05, 0x14 },
- { 0x02, 0x04, 0x05, 0x14 },
- { 0x03, 0x04, 0x05, 0x14 },
- { 0x03, 0x05, 0x05, 0x14 },
- { 0x03, 0x06, 0x05, 0x14 },
- { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */
- };
- RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
- RESTRICT_TO_RANGE(sharpness, 0, 6);
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
- ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
- ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
- ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ibmcam_set_brightness(struct uvd *uvd)
-{
- static const unsigned short n = 1;
-
- if (debug > 0)
- dev_info(&uvd->dev->dev, "%s: Set brightness to %hu.\n",
- __func__, uvd->vpic.brightness);
-
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- unsigned short i, j, bv[3];
- bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
- if (bv[0] == (uvd->vpic_old.brightness >> 10))
- return;
- uvd->vpic_old.brightness = bv[0];
- for (j=0; j < 3; j++)
- for (i=0; i < n; i++)
- ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
- break;
- }
- case IBMCAM_MODEL_2:
- {
- unsigned short i, j;
- i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
- j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */
- if (uvd->vpic_old.brightness == j)
- break;
- uvd->vpic_old.brightness = j;
- ibmcam_model2_Packet1(uvd, mod2_brightness, j);
- break;
- }
- case IBMCAM_MODEL_3:
- {
- /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
- unsigned short i =
- 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
- RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
- if (uvd->vpic_old.brightness == i)
- break;
- uvd->vpic_old.brightness = i;
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0036, i);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
- break;
- }
- case IBMCAM_MODEL_4:
- {
- /* Model 4: Brightness range 'i' in [0x04..0xb4] */
- unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
- RESTRICT_TO_RANGE(i, 0x04, 0xb4);
- if (uvd->vpic_old.brightness == i)
- break;
- uvd->vpic_old.brightness = i;
- ibmcam_model4_BrightnessPacket(uvd, i);
- break;
- }
- default:
- break;
- }
-}
-
-static void ibmcam_set_hue(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_2:
- {
- unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
- if (uvd->vpic_old.hue == hue)
- return;
- uvd->vpic_old.hue = hue;
- ibmcam_model2_Packet1(uvd, mod2_hue, hue);
- /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
- break;
- }
- case IBMCAM_MODEL_3:
- {
-#if 0 /* This seems not to work. No problem, will fix programmatically */
- unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
- RESTRICT_TO_RANGE(hue, 0x05, 0x37);
- if (uvd->vpic_old.hue == hue)
- return;
- uvd->vpic_old.hue = hue;
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x007e, hue);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-#endif
- break;
- }
- case IBMCAM_MODEL_4:
- {
- unsigned short r_gain, g_gain, b_gain, hue;
-
- /*
- * I am not sure r/g/b_gain variables exactly control gain
- * of those channels. Most likely they subtly change some
- * very internal image processing settings in the camera.
- * In any case, here is what they do, and feel free to tweak:
- *
- * r_gain: seriously affects red gain
- * g_gain: seriously affects green gain
- * b_gain: seriously affects blue gain
- * hue: changes average color from violet (0) to red (0xFF)
- *
- * These settings are preset for a decent white balance in
- * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
- * and therefore may need different values here.
- */
- hue = 20 + (uvd->vpic.hue >> 9);
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- r_gain = 90;
- g_gain = 166;
- b_gain = 175;
- break;
- case VIDEOSIZE_160x120:
- r_gain = 70;
- g_gain = 166;
- b_gain = 185;
- break;
- case VIDEOSIZE_176x144:
- r_gain = 160;
- g_gain = 175;
- b_gain = 185;
- break;
- default:
- r_gain = 120;
- g_gain = 166;
- b_gain = 175;
- break;
- }
- RESTRICT_TO_RANGE(hue, 1, 0x7f);
-
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */
- ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */
- ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */
- ibmcam_veio(uvd, 0, 0xf545, 0x0124);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ibmcam_adjust_picture(struct uvd *uvd)
-{
- ibmcam_adjust_contrast(uvd);
- ibmcam_set_brightness(uvd);
- ibmcam_set_hue(uvd);
-}
-
-static int ibmcam_model1_setup(struct uvd *uvd)
-{
- const int ntries = 5;
- int i;
-
- ibmcam_veio(uvd, 1, 0x00, 0x0128);
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 0, 0x01, 0x0108);
-
- ibmcam_veio(uvd, 0, 0x03, 0x0112);
- ibmcam_veio(uvd, 1, 0x00, 0x0115);
- ibmcam_veio(uvd, 0, 0x06, 0x0115);
- ibmcam_veio(uvd, 1, 0x00, 0x0116);
- ibmcam_veio(uvd, 0, 0x44, 0x0116);
- ibmcam_veio(uvd, 1, 0x00, 0x0116);
- ibmcam_veio(uvd, 0, 0x40, 0x0116);
- ibmcam_veio(uvd, 1, 0x00, 0x0115);
- ibmcam_veio(uvd, 0, 0x0e, 0x0115);
- ibmcam_veio(uvd, 0, 0x19, 0x012c);
-
- ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
- ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
- ibmcam_Packet_Format1(uvd, 0x39, 0x09);
- ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
- ibmcam_Packet_Format1(uvd, 0x28, 0x22);
- ibmcam_Packet_Format1(uvd, light_27, 0);
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
- ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x30, 0x14);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
- ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
- ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
- ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
- ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
- ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
- ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
- ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
- ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
- ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
- ibmcam_PacketFormat2(uvd, 0x11, 0xba);
- ibmcam_PacketFormat2(uvd, 0x12, 0x53);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x16, 0x00);
- ibmcam_PacketFormat2(uvd, 0x17, 0x28);
- ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
- ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x00, 0x18);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x13, 0x18);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x14, 0x06);
-
- /* This is default brightness */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x31, 0x37);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x32, 0x46);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x33, 0x55);
-
- ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x29, 0x80);
- ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
- ibmcam_Packet_Format1(uvd, 0x30, 0x17);
- ibmcam_Packet_Format1(uvd, 0x39, 0x08);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x34, 0x00);
-
- ibmcam_veio(uvd, 0, 0x00, 0x0101);
- ibmcam_veio(uvd, 0, 0x00, 0x010a);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_veio(uvd, 0, 0x80, 0x0103);
- ibmcam_veio(uvd, 0, 0x60, 0x0105);
- ibmcam_veio(uvd, 0, 0x0c, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x0b, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x00, 0x0129);
- break;
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0xb0, 0x0103);
- ibmcam_veio(uvd, 0, 0x8f, 0x0105);
- ibmcam_veio(uvd, 0, 0x06, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x0d, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x03, 0x0129);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0xb0, 0x0103);
- ibmcam_veio(uvd, 0, 0x90, 0x0105);
- ibmcam_veio(uvd, 0, 0x02, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x05, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x00, 0x0129);
- break;
- }
-
- ibmcam_veio(uvd, 0, 0xff, 0x012b);
-
- /* This is another brightness - don't know why */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
-
- /* Default contrast */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
-
- /* Default sharpness */
- for (i=0; i < 2; i++)
- ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */
-
- /* Default lighting conditions */
- ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
-
- /* Assorted init */
-
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x36, 0x0102);
- ibmcam_veio(uvd, 0, 0x1a, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2b, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
-#if 0
- ibmcam_veio(uvd, 0, 0x00, 0x0106);
- ibmcam_veio(uvd, 0, 0x38, 0x0107);
-#else
- ibmcam_veio(uvd, 0, 0x02, 0x0106);
- ibmcam_veio(uvd, 0, 0x2a, 0x0107);
-#endif
- break;
- case VIDEOSIZE_176x144:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x04, 0x0102);
- ibmcam_veio(uvd, 0, 0x02, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2b, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x01, 0x0106);
- ibmcam_veio(uvd, 0, 0xca, 0x0107);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x08, 0x0102);
- ibmcam_veio(uvd, 0, 0x01, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2f, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x03, 0x0106);
- ibmcam_veio(uvd, 0, 0xf6, 0x0107);
- break;
- }
- return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-static int ibmcam_model2_setup(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0112);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0008, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_352x240:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/
- break;
- }
- return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-/*
- * ibmcam_model1_setup_after_video_if()
- *
- * This code adds finishing touches to the video data interface.
- * Here we configure the frame rate and turn on the LED.
- */
-static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
-{
- unsigned short internal_frame_rate;
-
- RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
- internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
- ibmcam_veio(uvd, 0, 0x01, 0x0114);
- ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-}
-
-static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
-{
- unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
-
- ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */
-
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x0050, 0x0111);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- break;
- case VIDEOSIZE_320x240:
- case VIDEOSIZE_352x240:
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x0040, 0x0111);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- break;
- }
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-
- /*
- * Hardware settings, may affect CMOS sensor; not user controls!
- * -------------------------------------------------------------
- * 0x0004: no effect
- * 0x0006: hardware effect
- * 0x0008: no effect
- * 0x000a: stops video stream, probably important h/w setting
- * 0x000c: changes color in hardware manner (not user setting)
- * 0x0012: changes number of colors (does not affect speed)
- * 0x002a: no effect
- * 0x002c: hardware setting (related to scan lines)
- * 0x002e: stops video stream, probably important h/w setting
- */
- ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
- ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
- ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
- ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
- ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
-
- /*
- * Function 0x0030 pops up all over the place. Apparently
- * it is a hardware control register, with every bit assigned to
- * do something.
- */
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
-
- /*
- * Magic control of CMOS sensor. Only lower values like
- * 0-3 work, and picture shifts left or right. Don't change.
- */
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
- break;
- case VIDEOSIZE_320x240:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
- break;
- case VIDEOSIZE_352x240:
- /* This mode doesn't work as Windows programs it; changed to work */
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
- break;
- case VIDEOSIZE_352x288:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
- break;
- }
-
- ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
-
- /*
- * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
- * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
- * slowest setting. However for all practical reasons high settings make no
- * sense because USB is not fast enough to support high FPS. Be aware that
- * the picture datastream will be severely disrupted if you ask for
- * frame rate faster than allowed for the video size - see below:
- *
- * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
- * -----------------------------------------------------------------
- * 176x144: [6..31]
- * 320x240: [8..31]
- * 352x240: [10..31]
- * 352x288: [16..31] I have to raise lower threshold for stability...
- *
- * As usual, slower FPS provides better sensitivity.
- */
- {
- short hw_fps=31, i_framerate;
-
- RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
- i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- hw_fps = 6 + i_framerate*4;
- break;
- case VIDEOSIZE_320x240:
- hw_fps = 8 + i_framerate*3;
- break;
- case VIDEOSIZE_352x240:
- hw_fps = 10 + i_framerate*2;
- break;
- case VIDEOSIZE_352x288:
- hw_fps = 28 + i_framerate/2;
- break;
- }
- if (uvd->debug > 0)
- dev_info(&uvd->dev->dev, "Framerate (hardware): %hd.\n",
- hw_fps);
- RESTRICT_TO_RANGE(hw_fps, 0, 31);
- ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
- }
-
- /*
- * This setting does not visibly affect pictures; left it here
- * because it was present in Windows USB data stream. This function
- * does not allow arbitrary values and apparently is a bit mask, to
- * be activated only at appropriate time. Don't change it randomly!
- */
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
- break;
- case VIDEOSIZE_352x240:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
- break;
- }
-
- ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-
- if (init_model2_rg2 >= 0) {
- RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
- setup_model2_rg2 = init_model2_rg2;
- } else
- setup_model2_rg2 = 0x002f;
-
- if (init_model2_sat >= 0) {
- RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
- setup_model2_sat = init_model2_sat;
- } else
- setup_model2_sat = 0x0034;
-
- if (init_model2_yb >= 0) {
- RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
- setup_model2_yb = init_model2_yb;
- } else
- setup_model2_yb = 0x00a0;
-
- ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
- ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
- ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
- ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
-
- /* Hardware control command */
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
-{
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x005e, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000a, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0031, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x012d);
- ibmcam_veio(uvd, 0, 0x0078, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
- ibmcam_veio(uvd, 0, 0x0002, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000b, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0025, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0048, 0x0127);
- ibmcam_veio(uvd, 0, 0x0035, 0x012e);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0048, 0x012d);
- ibmcam_veio(uvd, 0, 0x0090, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x0018, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x002c, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x0024, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0007, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0001, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005e, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0049, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0028, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x002a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x012d);
- ibmcam_veio(uvd, 0, 0x006d, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x005e, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000a, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0031, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x012d);
- ibmcam_veio(uvd, 0, 0x0078, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x008c, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x002c, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x0024, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0006, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0002, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005e, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0049, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0025, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x012d);
- ibmcam_veio(uvd, 0, 0x0048, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- }
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
-{
- int i;
- /*
- * 01.01.08 - Added for RCA video in support -LO
- * This struct is used to init the Model3 cam to use the RCA video in port
- * instead of the CCD sensor.
- */
- static const struct struct_initData initData[] = {
- {0, 0x0000, 0x010c},
- {0, 0x0006, 0x012c},
- {0, 0x0078, 0x012d},
- {0, 0x0046, 0x012f},
- {0, 0xd141, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfea8, 0x0124},
- {1, 0x0000, 0x0116},
- {0, 0x0064, 0x0116},
- {1, 0x0000, 0x0115},
- {0, 0x0003, 0x0115},
- {0, 0x0008, 0x0123},
- {0, 0x0000, 0x0117},
- {0, 0x0000, 0x0112},
- {0, 0x0080, 0x0100},
- {0, 0x0000, 0x0100},
- {1, 0x0000, 0x0116},
- {0, 0x0060, 0x0116},
- {0, 0x0002, 0x0112},
- {0, 0x0000, 0x0123},
- {0, 0x0001, 0x0117},
- {0, 0x0040, 0x0108},
- {0, 0x0019, 0x012c},
- {0, 0x0040, 0x0116},
- {0, 0x000a, 0x0115},
- {0, 0x000b, 0x0115},
- {0, 0x0078, 0x012d},
- {0, 0x0046, 0x012f},
- {0, 0xd141, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfea8, 0x0124},
- {0, 0x0064, 0x0116},
- {0, 0x0000, 0x0115},
- {0, 0x0001, 0x0115},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00aa, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f2, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x000f, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f8, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00fc, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f9, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x003c, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0027, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0019, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0021, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0006, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0045, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002a, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x000e, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002b, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f4, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002c, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0004, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002d, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0014, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002e, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0003, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002f, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0003, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0014, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0053, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0x0000, 0x0101},
- {0, 0x00a0, 0x0103},
- {0, 0x0078, 0x0105},
- {0, 0x0000, 0x010a},
- {0, 0x0024, 0x010b},
- {0, 0x0028, 0x0119},
- {0, 0x0088, 0x011b},
- {0, 0x0002, 0x011d},
- {0, 0x0003, 0x011e},
- {0, 0x0000, 0x0129},
- {0, 0x00fc, 0x012b},
- {0, 0x0008, 0x0102},
- {0, 0x0000, 0x0104},
- {0, 0x0008, 0x011a},
- {0, 0x0028, 0x011c},
- {0, 0x0021, 0x012a},
- {0, 0x0000, 0x0118},
- {0, 0x0000, 0x0132},
- {0, 0x0000, 0x0109},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0031, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00dc, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0032, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0020, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0030, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0008, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0x0003, 0x0106},
- {0, 0x0062, 0x0107},
- {0, 0x0003, 0x0111},
- };
-#define NUM_INIT_DATA
-
- unsigned short compression = 0; /* 0=none, 7=best frame rate */
- int f_rate; /* 0=Fastest 7=slowest */
-
- if (IBMCAM_T(uvd)->initialized)
- return;
-
- /* Internal frame rate is controlled by f_rate value */
- f_rate = 7 - framerate;
- RESTRICT_TO_RANGE(f_rate, 0, 7);
-
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0112);
- ibmcam_veio(uvd, 0, 0x0000, 0x0123);
- ibmcam_veio(uvd, 0, 0x0001, 0x0117);
- ibmcam_veio(uvd, 0, 0x0040, 0x0108);
- ibmcam_veio(uvd, 0, 0x0019, 0x012c);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0115);
- ibmcam_veio(uvd, 0, 0x0003, 0x0115);
- ibmcam_veio(uvd, 1, 0x0000, 0x0115);
- ibmcam_veio(uvd, 0, 0x000b, 0x0115);
- ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
- ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
- ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
- ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
- ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
- ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
- ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
- ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
- ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
- ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
- ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
- ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
- ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
- ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
- ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
- ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
- ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
- ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
- ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
- ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
- ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
- ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
- ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
- ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
- ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
- ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
- ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
- ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
- ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
- ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
- ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
- ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
- ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
- ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
- ibmcam_veio(uvd, 0, 0x0016, 0x011b);
- ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- ibmcam_veio(uvd, 0, 0x0018, 0x0102);
- ibmcam_veio(uvd, 0, 0x0004, 0x0104);
- ibmcam_veio(uvd, 0, 0x0004, 0x011a);
- ibmcam_veio(uvd, 0, 0x0028, 0x011c);
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_veio(uvd, 0, 0x0000, 0x0118);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132);
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
- ibmcam_veio(uvd, 0, 0x0000, 0x011e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- /* 4 commands from 160x120 skipped */
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
- ibmcam_veio(uvd, 0, 0x0006, 0x011b);
- ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0010, 0x0104);
- ibmcam_veio(uvd, 0, 0x0004, 0x011a);
- ibmcam_veio(uvd, 0, 0x003f, 0x011c);
- ibmcam_veio(uvd, 0, 0x001c, 0x0118);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132);
- break;
- case VIDEOSIZE_640x480:
- ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
- ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
- ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- ibmcam_veio(uvd, 0, 0x0040, 0x0101);
- ibmcam_veio(uvd, 0, 0x0040, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
- break;
- }
- ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */
- ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */
- ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */
- ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */
- ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */
- ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
- ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
- ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
- ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
- ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
- ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
- ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
- ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
- ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
- ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
- ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
- ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
- ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
- ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */
- ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */
- ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0002, 0x0106);
- ibmcam_veio(uvd, 0, 0x0008, 0x0107);
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
- ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x0062, 0x0107);
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
- ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
- break;
- case VIDEOSIZE_640x480:
- ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */
- ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
- break;
- }
-
- /* 01.01.08 - Added for RCA video in support -LO */
- if(init_model3_input) {
- if (debug > 0)
- dev_info(&uvd->dev->dev, "Setting input to RCA.\n");
- for (i=0; i < ARRAY_SIZE(initData); i++) {
- ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
- }
- }
-
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-/*
- * ibmcam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ibmcam_video_stop(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_veio(uvd, 0, 0x01, 0x0114);
- ibmcam_veio(uvd, 0, 0xc0, 0x010c);
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_send_FF_04_02(uvd);
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */
- break;
- case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */
-
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
- ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */
- ibmcam_veio(uvd, 0, 0x0020, 0x0111);
- ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
-
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
-
- ibmcam_veio(uvd, 0, 0x0020, 0x0111);
- ibmcam_veio(uvd, 0, 0x0000, 0x0112);
- break;
- case IBMCAM_MODEL_3:
-#if 1
- ibmcam_veio(uvd, 0, 0x0000, 0x010c);
-
- /* Here we are supposed to select video interface alt. setting 0 */
- ibmcam_veio(uvd, 0, 0x0006, 0x012c);
-
- ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
-
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0064, 0x0116);
- ibmcam_veio(uvd, 1, 0x0000, 0x0115);
- ibmcam_veio(uvd, 0, 0x0003, 0x0115);
- ibmcam_veio(uvd, 0, 0x0008, 0x0123);
- ibmcam_veio(uvd, 0, 0x0000, 0x0117);
- ibmcam_veio(uvd, 0, 0x0000, 0x0112);
- ibmcam_veio(uvd, 0, 0x0080, 0x0100);
- IBMCAM_T(uvd)->initialized = 0;
-#endif
- break;
- } /* switch */
-}
-
-/*
- * ibmcam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- if (do_stop)
- ibmcam_video_stop(uvd);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_model1_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_2:
- ibmcam_model2_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_3:
- ibmcam_video_stop(uvd);
- ibmcam_model3_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_4:
- ibmcam_model4_setup_after_video_if(uvd);
- break;
- }
-}
-
-static void ibmcam_video_start(struct uvd *uvd)
-{
- ibmcam_change_lighting_conditions(uvd);
- ibmcam_set_sharpness(uvd);
- ibmcam_reinit_iso(uvd, 0);
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ibmcam_setup_on_open(struct uvd *uvd)
-{
- int setup_ok = 0; /* Success by default */
- /* Send init sequence only once, it's large! */
- if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- setup_ok = ibmcam_model1_setup(uvd);
- break;
- case IBMCAM_MODEL_2:
- setup_ok = ibmcam_model2_setup(uvd);
- break;
- case IBMCAM_MODEL_3:
- case IBMCAM_MODEL_4:
- /* We do all setup when Isoc stream is requested */
- break;
- }
- IBMCAM_T(uvd)->initialized = (setup_ok != 0);
- }
- return setup_ok;
-}
-
-static void ibmcam_configure_video(struct uvd *uvd)
-{
- if (uvd == NULL)
- return;
-
- RESTRICT_TO_RANGE(init_brightness, 0, 255);
- RESTRICT_TO_RANGE(init_contrast, 0, 255);
- RESTRICT_TO_RANGE(init_color, 0, 255);
- RESTRICT_TO_RANGE(init_hue, 0, 255);
- RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = init_color << 8;
- uvd->vpic.hue = init_hue << 8;
- uvd->vpic.brightness = init_brightness << 8;
- uvd->vpic.contrast = init_contrast << 8;
- uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "IBM USB Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
- uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
- uvd->vcap.minwidth = min_canvasWidth;
- uvd->vcap.minheight = min_canvasHeight;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ibmcam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like IBM C-it camera.
- *
- * History:
- * 22-Jan-2000 Moved camera init code to ibmcam_open()
- * 27=Jan-2000 Changed to use static structures, added locking.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 03-Jul-2000 Fixed endianness bug.
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas, model=0, canvasX=0, canvasY=0;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
- unsigned char video_ep = 0;
-
- if (debug >= 1)
- dev_info(&dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum);
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- /* Check the version/revision */
- switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
- case 0x0002:
- if (ifnum != 2)
- return -ENODEV;
- model = IBMCAM_MODEL_1;
- break;
- case 0x030A:
- if (ifnum != 0)
- return -ENODEV;
- if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
- (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
- model = IBMCAM_MODEL_4;
- else
- model = IBMCAM_MODEL_2;
- break;
- case 0x0301:
- if (ifnum != 0)
- return -ENODEV;
- model = IBMCAM_MODEL_3;
- break;
- default:
- err("IBM camera with revision 0x%04x is not supported.",
- le16_to_cpu(dev->descriptor.bcdDevice));
- return -ENODEV;
- }
-
- /* Print detailed info on what we found so far */
- do {
- char *brand = NULL;
- switch (le16_to_cpu(dev->descriptor.idProduct)) {
- case NETCAM_PRODUCT_ID:
- brand = "IBM NetCamera";
- break;
- case VEO_800C_PRODUCT_ID:
- brand = "Veo Stingray [800C]";
- break;
- case VEO_800D_PRODUCT_ID:
- brand = "Veo Stingray [800D]";
- break;
- case IBMCAM_PRODUCT_ID:
- default:
- brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
- break;
- }
- dev_info(&dev->dev,
- "%s USB camera found (model %d, rev. 0x%04x)\n",
- brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
- } while (0);
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (debug > 0)
- dev_info(&dev->dev, "Number of alternate settings=%d.\n",
- nas);
- if (nas < 2) {
- err("Too few alternate settings for this camera!");
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 1) {
- err("Interface %d. has %u. endpoints!",
- ifnum, (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[0].desc;
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!", ifnum);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!", ifnum);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (actInterface < 0) {
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0)
- dev_info(&dev->dev,
- "Active setting=%d. "
- "maxPS=%d.\n", i, maxPS);
- } else
- err("More than one active alt. setting! Ignoring #%d.", i);
- }
- }
- if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
- err("Failed to recognize the camera!");
- return -ENODEV;
- }
-
- /* Validate options */
- switch (model) {
- case IBMCAM_MODEL_1:
- RESTRICT_TO_RANGE(lighting, 0, 2);
- RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
- if (framerate < 0)
- framerate = 2;
- canvasX = 352;
- canvasY = 288;
- break;
- case IBMCAM_MODEL_2:
- RESTRICT_TO_RANGE(lighting, 0, 15);
- RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
- if (framerate < 0)
- framerate = 2;
- canvasX = 352;
- canvasY = 240;
- break;
- case IBMCAM_MODEL_3:
- RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
- switch (size) {
- case SIZE_160x120:
- canvasX = 160;
- canvasY = 120;
- if (framerate < 0)
- framerate = 2;
- RESTRICT_TO_RANGE(framerate, 0, 5);
- break;
- default:
- dev_info(&dev->dev, "IBM camera: using 320x240\n");
- size = SIZE_320x240;
- /* No break here */
- case SIZE_320x240:
- canvasX = 320;
- canvasY = 240;
- if (framerate < 0)
- framerate = 3;
- RESTRICT_TO_RANGE(framerate, 0, 5);
- break;
- case SIZE_640x480:
- canvasX = 640;
- canvasY = 480;
- framerate = 0; /* Slowest, and maybe even that is too fast */
- break;
- }
- break;
- case IBMCAM_MODEL_4:
- RESTRICT_TO_RANGE(lighting, 0, 2);
- switch (size) {
- case SIZE_128x96:
- canvasX = 128;
- canvasY = 96;
- break;
- case SIZE_160x120:
- canvasX = 160;
- canvasY = 120;
- break;
- default:
- dev_info(&dev->dev, "IBM NetCamera: using 176x144\n");
- size = SIZE_176x144;
- /* No break here */
- case SIZE_176x144:
- canvasX = 176;
- canvasY = 144;
- break;
- case SIZE_320x240:
- canvasX = 320;
- canvasY = 240;
- break;
- case SIZE_352x288:
- canvasX = 352;
- canvasY = 288;
- break;
- }
- break;
- default:
- err("IBM camera: Model %d. not supported!", model);
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- /* Here uvd is a fully allocated uvd object */
- uvd->flags = flags;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = ifnum;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(canvasX, canvasY);
- uvd->videosize = ibmcam_size_to_videosize(size);
-
- /* Initialize ibmcam-specific data */
- assert(IBMCAM_T(uvd) != NULL);
- IBMCAM_T(uvd)->camera_model = model;
- IBMCAM_T(uvd)->initialized = 0;
-
- ibmcam_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
- }
- usb_set_intfdata (intf, uvd);
- return 0;
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
- { } /* Terminating entry */
-};
-
-/*
- * ibmcam_init()
- *
- * This code is run to initialize the driver.
- *
- * History:
- * 1/27/00 Reworked to use statically allocated ibmcam structures.
- * 21/10/00 Completely redesigned to use usbvideo services.
- */
-static int __init ibmcam_init(void)
-{
- struct usbvideo_cb cbTbl;
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = ibmcam_probe;
- cbTbl.setupOnOpen = ibmcam_setup_on_open;
- cbTbl.videoStart = ibmcam_video_start;
- cbTbl.videoStop = ibmcam_video_stop;
- cbTbl.processData = ibmcam_ProcessIsocData;
- cbTbl.postProcess = usbvideo_DeinterlaceFrame;
- cbTbl.adjustPicture = ibmcam_adjust_picture;
- cbTbl.getFPS = ibmcam_calculate_fps;
- return usbvideo_register(
- &cams,
- MAX_IBMCAM,
- sizeof(ibmcam_t),
- "ibmcam",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-static void __exit ibmcam_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-module_init(ibmcam_init);
-module_exit(ibmcam_cleanup);
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
deleted file mode 100644
index 562e1d170be0..000000000000
--- a/drivers/media/video/usbvideo/konicawc.c
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * konicawc.c - konica webcam driver
- *
- * Author: Simon Evans <spse@secret.org.uk>
- *
- * Copyright (C) 2002 Simon Evans
- *
- * Licence: GPL
- *
- * Driver for USB webcams based on Konica chipset. This
- * chipset is used in Intel YC76 camera.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/gfp.h>
-
-#include "usbvideo.h"
-
-#define MAX_BRIGHTNESS 108
-#define MAX_CONTRAST 108
-#define MAX_SATURATION 108
-#define MAX_SHARPNESS 108
-#define MAX_WHITEBAL 372
-#define MAX_SPEED 6
-
-
-#define MAX_CAMERAS 1
-
-#define DRIVER_VERSION "v1.4"
-#define DRIVER_DESC "Konica Webcam driver"
-
-enum ctrl_req {
- SetWhitebal = 0x01,
- SetBrightness = 0x02,
- SetSharpness = 0x03,
- SetContrast = 0x04,
- SetSaturation = 0x05,
-};
-
-
-enum frame_sizes {
- SIZE_160X120 = 0,
- SIZE_160X136 = 1,
- SIZE_176X144 = 2,
- SIZE_320X240 = 3,
-
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-static struct usbvideo *cams;
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
- if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
- }
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-
-/* Some default values for initial camera settings,
- can be set by modprobe */
-
-static int size;
-static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */
-static int brightness = MAX_BRIGHTNESS/2;
-static int contrast = MAX_CONTRAST/2;
-static int saturation = MAX_SATURATION/2;
-static int sharpness = MAX_SHARPNESS/2;
-static int whitebal = 3*(MAX_WHITEBAL/4);
-
-static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
-
-/* These FPS speeds are from the windows config box. They are
- * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
- * real fps.
- */
-
-static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
- { 24, 40, 48, 60, 72, 80, 100 },
- { 18, 30, 36, 45, 54, 60, 75 },
- { 6, 10, 12, 15, 18, 21, 25 } };
-
-struct cam_size {
- u16 width;
- u16 height;
- u8 cmd;
-};
-
-static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
- { 160, 136, 0xa },
- { 176, 144, 0x4 },
- { 320, 240, 0x5 } };
-
-struct konicawc {
- u8 brightness; /* camera uses 0 - 9, x11 for real value */
- u8 contrast; /* as above */
- u8 saturation; /* as above */
- u8 sharpness; /* as above */
- u8 white_bal; /* 0 - 33, x11 for real value */
- u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */
- u8 size; /* Frame Size */
- int height;
- int width;
- struct urb *sts_urb[USBVIDEO_NUMSBUF];
- u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
- struct urb *last_data_urb;
- int lastframe;
- int cur_frame_size; /* number of bytes in current frame size */
- int maxline; /* number of lines per frame */
- int yplanesz; /* Number of bytes in the Y plane */
- unsigned int buttonsts:1;
-#ifdef CONFIG_INPUT
- struct input_dev *input;
- char input_physname[64];
-#endif
-};
-
-
-#define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
-#define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
-#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
-
-
-static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
-{
- int retval = usb_control_msg(uvd->dev,
- dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
- request, 0x40 | dir, value, index, buf, len, 1000);
- return retval < 0 ? retval : 0;
-}
-
-
-static inline void konicawc_camera_on(struct uvd *uvd)
-{
- DEBUG(0, "camera on");
- konicawc_set_misc(uvd, 0x2, 1, 0x0b);
-}
-
-
-static inline void konicawc_camera_off(struct uvd *uvd)
-{
- DEBUG(0, "camera off");
- konicawc_set_misc(uvd, 0x2, 0, 0x0b);
-}
-
-
-static void konicawc_set_camera_size(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
- cam->width = camera_sizes[cam->size].width;
- cam->height = camera_sizes[cam->size].height;
- cam->yplanesz = cam->height * cam->width;
- cam->cur_frame_size = (cam->yplanesz * 3) / 2;
- cam->maxline = cam->yplanesz / 256;
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-}
-
-
-static int konicawc_setup_on_open(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
- cam->brightness * 11);
- konicawc_set_value(uvd, cam->brightness, SetBrightness);
- DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
- cam->white_bal * 11);
- konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
- DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
- cam->contrast * 11);
- konicawc_set_value(uvd, cam->contrast, SetContrast);
- DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
- cam->saturation * 11);
- konicawc_set_value(uvd, cam->saturation, SetSaturation);
- DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
- cam->sharpness * 11);
- konicawc_set_value(uvd, cam->sharpness, SetSharpness);
- konicawc_set_camera_size(uvd);
- cam->lastframe = -2;
- cam->buttonsts = 0;
- return 0;
-}
-
-
-static void konicawc_adjust_picture(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_camera_off(uvd);
- DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
- uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
- if(cam->brightness != uvd->vpic.brightness / 11) {
- cam->brightness = uvd->vpic.brightness / 11;
- DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
- cam->brightness * 11);
- konicawc_set_value(uvd, cam->brightness, SetBrightness);
- }
-
- DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
- uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
- if(cam->contrast != uvd->vpic.contrast / 11) {
- cam->contrast = uvd->vpic.contrast / 11;
- DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
- cam->contrast * 11);
- konicawc_set_value(uvd, cam->contrast, SetContrast);
- }
- konicawc_camera_on(uvd);
-}
-
-#ifdef CONFIG_INPUT
-
-static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
-{
- struct input_dev *input_dev;
- int error;
-
- usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
- strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
- cam->input = input_dev = input_allocate_device();
- if (!input_dev) {
- dev_warn(&dev->dev,
- "Not enough memory for camera's input device\n");
- return;
- }
-
- input_dev->name = "Konicawc snapshot button";
- input_dev->phys = cam->input_physname;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->dev.parent = &dev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
- error = input_register_device(cam->input);
- if (error) {
- dev_warn(&dev->dev,
- "Failed to register camera's input device, err: %d\n",
- error);
- input_free_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void konicawc_unregister_input(struct konicawc *cam)
-{
- if (cam->input) {
- input_unregister_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void konicawc_report_buttonstat(struct konicawc *cam)
-{
- if (cam->input) {
- input_report_key(cam->input, KEY_CAMERA, cam->buttonsts);
- input_sync(cam->input);
- }
-}
-
-#else
-
-static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
-static inline void konicawc_unregister_input(struct konicawc *cam) { }
-static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
-
-#endif /* CONFIG_INPUT */
-
-static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
-{
- char *cdata;
- int i, totlen = 0;
- unsigned char *status = stsurb->transfer_buffer;
- int keep = 0, discard = 0, bad = 0;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- for (i = 0; i < dataurb->number_of_packets; i++) {
- int button = cam->buttonsts;
- unsigned char sts;
- int n = dataurb->iso_frame_desc[i].actual_length;
- int st = dataurb->iso_frame_desc[i].status;
- cdata = dataurb->transfer_buffer +
- dataurb->iso_frame_desc[i].offset;
-
- /* Detect and ignore errored packets */
- if (st < 0) {
- DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
- i, n, st);
- uvd->stats.iso_err_count++;
- continue;
- }
-
- /* Detect and ignore empty packets */
- if (n <= 0) {
- uvd->stats.iso_skip_count++;
- continue;
- }
-
- /* See what the status data said about the packet */
- sts = *(status+stsurb->iso_frame_desc[i].offset);
-
- /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
- * otherwise:
- * bit 0 0: keep packet
- * 1: drop packet (padding data)
- *
- * bit 4 0 button not clicked
- * 1 button clicked
- * button is used to `take a picture' (in software)
- */
-
- if(sts < 0x80) {
- button = !!(sts & 0x40);
- sts &= ~0x40;
- }
-
- /* work out the button status, but don't do
- anything with it for now */
-
- if(button != cam->buttonsts) {
- DEBUG(2, "button: %sclicked", button ? "" : "un");
- cam->buttonsts = button;
- konicawc_report_buttonstat(cam);
- }
-
- if(sts == 0x01) { /* drop frame */
- discard++;
- continue;
- }
-
- if((sts > 0x01) && (sts < 0x80)) {
- dev_info(&uvd->dev->dev, "unknown status %2.2x\n",
- sts);
- bad++;
- continue;
- }
- if(!sts && cam->lastframe == -2) {
- DEBUG(2, "dropping frame looking for image start");
- continue;
- }
-
- keep++;
- if(sts & 0x80) { /* frame start */
- unsigned char marker[] = { 0, 0xff, 0, 0x00 };
-
- if(cam->lastframe == -2) {
- DEBUG(2, "found initial image");
- cam->lastframe = -1;
- }
-
- marker[3] = sts & 0x7F;
- RingQueue_Enqueue(&uvd->dp, marker, 4);
- totlen += 4;
- }
-
- totlen += n; /* Little local accounting */
- RingQueue_Enqueue(&uvd->dp, cdata, n);
- }
- DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
- keep, discard, bad, totlen);
- return totlen;
-}
-
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
- int i, ret;
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- urb->iso_frame_desc[i].status = 0;
- }
- urb->dev = uvd->dev;
- urb->status = 0;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
- if(ret)
- err("usb_submit_urb error (%d)", ret);
-
-}
-
-
-static void konicawc_isoc_irq(struct urb *urb)
-{
- struct uvd *uvd = urb->context;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- /* We don't want to do anything if we are about to be removed! */
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming) {
- DEBUG(1, "Not streaming, but interrupt!");
- return;
- }
-
- DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
-
- uvd->stats.urb_count++;
-
- if (urb->transfer_buffer_length > 32) {
- cam->last_data_urb = urb;
- return;
- }
- /* Copy the data received into ring queue */
- if(cam->last_data_urb) {
- int len = 0;
- if(urb->start_frame != cam->last_data_urb->start_frame)
- err("Lost sync on frames");
- else if (!urb->status && !cam->last_data_urb->status)
- len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
-
- resubmit_urb(uvd, cam->last_data_urb);
- resubmit_urb(uvd, urb);
- cam->last_data_urb = NULL;
- uvd->stats.urb_length = len;
- uvd->stats.data_count += len;
- if(len)
- RingQueue_WakeUpInterruptible(&uvd->dp);
- return;
- }
- return;
-}
-
-
-static int konicawc_start_data(struct uvd *uvd)
-{
- struct usb_device *dev = uvd->dev;
- int i, errFlag;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int pktsz;
- struct usb_interface *intf;
- struct usb_host_interface *interface = NULL;
-
- intf = usb_ifnum_to_if(dev, uvd->iface);
- if (intf)
- interface = usb_altnum_to_altsetting(intf,
- spd_to_iface[cam->speed]);
- if (!interface)
- return -ENXIO;
- pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
- DEBUG(1, "pktsz = %d", pktsz);
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("Camera is not operational");
- return -EFAULT;
- }
- uvd->curframe = -1;
- konicawc_camera_on(uvd);
- /* Alternate interface 1 is is the biggest frame size */
- i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
- if (i < 0) {
- err("usb_set_interface error");
- uvd->last_error = i;
- return -EBUSY;
- }
-
- /* We double buffer the Iso lists */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- int j, k;
- struct urb *urb = uvd->sbuf[i].urb;
- urb->dev = dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = uvd->sbuf[i].data;
- urb->complete = konicawc_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
- for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length = pktsz;
- }
-
- urb = cam->sts_urb[i];
- urb->dev = dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = cam->sts_buf[i];
- urb->complete = konicawc_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAMES_PER_DESC;
- for (j=0; j < FRAMES_PER_DESC; j++) {
- urb->iso_frame_desc[j].offset = j;
- urb->iso_frame_desc[j].length = 1;
- }
- }
-
- cam->last_data_urb = NULL;
-
- /* Submit all URBs */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
- if (errFlag)
- err("usb_submit_isoc(%d) ret %d", i, errFlag);
-
- errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
- if (errFlag)
- err ("usb_submit_isoc(%d) ret %d", i, errFlag);
- }
-
- uvd->streaming = 1;
- DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
- return 0;
-}
-
-
-static void konicawc_stop_data(struct uvd *uvd)
-{
- int i, j;
- struct konicawc *cam;
-
- if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
- return;
-
- konicawc_camera_off(uvd);
- uvd->streaming = 0;
- cam = (struct konicawc *)uvd->user_data;
- cam->last_data_urb = NULL;
-
- /* Unschedule all of the iso td's */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- usb_kill_urb(uvd->sbuf[i].urb);
- usb_kill_urb(cam->sts_urb[i]);
- }
-
- if (!uvd->remove_pending) {
- /* Set packet size to 0 */
- j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
- if (j < 0) {
- err("usb_set_interface() error %d.", j);
- uvd->last_error = j;
- }
- }
-}
-
-
-static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int maxline = cam->maxline;
- int yplanesz = cam->yplanesz;
-
- assert(frame != NULL);
-
- DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
- DEBUG(3, "Frame state = %d", frame->scanstate);
-
- if(frame->scanstate == ScanState_Scanning) {
- int drop = 0;
- int curframe;
- int fdrops = 0;
- DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
- while(RingQueue_GetLength(&uvd->dp) >= 4) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
- curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
- if(cam->lastframe >= 0) {
- fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
- fdrops--;
- if(fdrops) {
- dev_info(&uvd->dev->dev,
- "Dropped %d frames "
- "(%d -> %d)\n",
- fdrops,
- cam->lastframe,
- curframe);
- }
- }
- cam->lastframe = curframe;
- frame->curline = 0;
- frame->scanstate = ScanState_Lines;
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
- break;
- }
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- drop++;
- }
- if(drop)
- DEBUG(2, "dropped %d bytes looking for new frame", drop);
- }
-
- if(frame->scanstate == ScanState_Scanning)
- return;
-
- /* Try to move data from queue into frame buffer
- * We get data in blocks of 384 bytes made up of:
- * 256 Y, 64 U, 64 V.
- * This needs to be written out as a Y plane, a U plane and a V plane.
- */
-
- while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
- /* Y */
- RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
- /* U */
- RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
- /* V */
- RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
- frame->seqRead_Length += 384;
- frame->curline++;
- }
- /* See if we filled the frame */
- if (frame->curline == maxline) {
- DEBUG(5, "got whole frame");
-
- frame->frameState = FrameState_Done_Hold;
- frame->curline = 0;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-
-static int konicawc_find_fps(int size, int fps)
-{
- int i;
-
- fps *= 3;
- DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
- if(fps <= spd_to_fps[size][0])
- return 0;
-
- if(fps >= spd_to_fps[size][MAX_SPEED])
- return MAX_SPEED;
-
- for(i = 0; i < MAX_SPEED; i++) {
- if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
- DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
- if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
- return i;
- else
- return i+1;
- }
- }
- return MAX_SPEED+1;
-}
-
-
-static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int newspeed = cam->speed;
- int newsize;
- int x = vw->width;
- int y = vw->height;
- int fps = vw->flags;
-
- if(x > 0 && y > 0) {
- DEBUG(2, "trying to find size %d,%d", x, y);
- for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
- if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
- break;
- }
- } else {
- newsize = cam->size;
- }
-
- if(newsize > MAX_FRAME_SIZE) {
- DEBUG(1, "couldn't find size %d,%d", x, y);
- return -EINVAL;
- }
-
- if(fps > 0) {
- DEBUG(1, "trying to set fps to %d", fps);
- newspeed = konicawc_find_fps(newsize, fps);
- DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
- }
-
- if(newspeed > MAX_SPEED)
- return -EINVAL;
-
- DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
- if((newsize == cam->size) && (newspeed == cam->speed)) {
- DEBUG(1, "Nothing to do");
- return 0;
- }
- DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width,
- camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
-
- konicawc_stop_data(uvd);
- uvd->ifaceAltActive = spd_to_iface[newspeed];
- DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
- cam->speed = newspeed;
-
- if(cam->size != newsize) {
- cam->size = newsize;
- konicawc_set_camera_size(uvd);
- }
-
- /* Flush the input queue and clear any current frame in progress */
-
- RingQueue_Flush(&uvd->dp);
- cam->lastframe = -2;
- if(uvd->curframe != -1) {
- uvd->frame[uvd->curframe].curline = 0;
- uvd->frame[uvd->curframe].seqRead_Length = 0;
- uvd->frame[uvd->curframe].seqRead_Index = 0;
- }
-
- konicawc_start_data(uvd);
- return 0;
-}
-
-
-static int konicawc_calculate_fps(struct uvd *uvd)
-{
- struct konicawc *cam = uvd->user_data;
- return spd_to_fps[cam->size][cam->speed]/3;
-}
-
-
-static void konicawc_configure_video(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- u8 buf[2];
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
- RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
- RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
- RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
- RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
-
- cam->brightness = brightness / 11;
- cam->contrast = contrast / 11;
- cam->saturation = saturation / 11;
- cam->sharpness = sharpness / 11;
- cam->white_bal = whitebal / 11;
-
- uvd->vpic.colour = 108;
- uvd->vpic.hue = 108;
- uvd->vpic.brightness = brightness;
- uvd->vpic.contrast = contrast;
- uvd->vpic.whiteness = whitebal;
- uvd->vpic.depth = 6;
- uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "Konica Webcam");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
- uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
- uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
- uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0 ;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-
- /* Talk to device */
- DEBUG(1, "device init");
- if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
- DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
- if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
- DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
- if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
- DEBUG(2, "2,0,d failed");
- DEBUG(1, "setting initial values");
-}
-
-static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- unsigned char video_ep = 0;
-
- DEBUG(1, "konicawc_probe(%p)", intf);
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n",
- le16_to_cpu(dev->descriptor.bcdDevice));
- RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (nas != 8) {
- err("Incorrect number of alternate settings (%d) for this camera!", nas);
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 2) {
- err("Interface %d. has %u. endpoints!",
- interface->desc.bInterfaceNumber,
- (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[1].desc;
- DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
- endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (i == spd_to_iface[speed]) {
- /* This one is the requested one */
- actInterface = i;
- }
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- }
- if(actInterface == -1) {
- err("Cant find required endpoint");
- return -ENODEV;
- }
-
- DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- struct konicawc *cam = (struct konicawc *)(uvd->user_data);
- /* Here uvd is a fully allocated uvd object */
- for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
- cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if(cam->sts_urb[i] == NULL) {
- while(i--) {
- usb_free_urb(cam->sts_urb[i]);
- }
- err("can't allocate urbs");
- return -ENOMEM;
- }
- }
- cam->speed = speed;
- RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
- cam->width = camera_sizes[size].width;
- cam->height = camera_sizes[size].height;
- cam->size = size;
-
- uvd->flags = 0;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
- uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
- uvd->canvas = VIDEOSIZE(320, 240);
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
- /* Initialize konicawc specific data */
- konicawc_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- uvd->max_frame_size = (320 * 240 * 3)/2;
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
-
- konicawc_register_input(cam, dev);
- }
-
- if (uvd) {
- usb_set_intfdata (intf, uvd);
- return 0;
- }
- return -EIO;
-}
-
-
-static void konicawc_free_uvd(struct uvd *uvd)
-{
- int i;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_unregister_input(cam);
-
- for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
- usb_free_urb(cam->sts_urb[i]);
- cam->sts_urb[i] = NULL;
- }
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
- { } /* Terminating entry */
-};
-
-
-static int __init konicawc_init(void)
-{
- struct usbvideo_cb cbTbl;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = konicawc_probe;
- cbTbl.setupOnOpen = konicawc_setup_on_open;
- cbTbl.processData = konicawc_process_isoc;
- cbTbl.getFPS = konicawc_calculate_fps;
- cbTbl.setVideoMode = konicawc_set_video_mode;
- cbTbl.startDataPump = konicawc_start_data;
- cbTbl.stopDataPump = konicawc_stop_data;
- cbTbl.adjustPicture = konicawc_adjust_picture;
- cbTbl.userFree = konicawc_free_uvd;
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(struct konicawc),
- "konicawc",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-
-static void __exit konicawc_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-module_param(speed, int, 0);
-MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
-module_param(saturation, int, 0);
-MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
-module_param(whitebal, int, 0);
-MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(konicawc_init);
-module_exit(konicawc_cleanup);
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
deleted file mode 100644
index fbd1b6392290..000000000000
--- a/drivers/media/video/usbvideo/ultracam.c
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * USB NB Camera driver
- *
- * HISTORY:
- * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define ULTRACAM_VENDOR_ID 0x0461
-#define ULTRACAM_PRODUCT_ID 0x0813
-
-#define MAX_CAMERAS 4 /* How many devices we allow to connect */
-
-/*
- * This structure lives in uvd_t->user field.
- */
-typedef struct {
- int initialized; /* Had we already sent init sequence? */
- int camera_model; /* What type of IBM camera we got? */
- int has_hdr;
-} ultracam_t;
-#define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams = NULL;
-
-static int debug;
-
-static int flags; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth = 8;
-static const int min_canvasHeight = 4;
-
-#define FRAMERATE_MIN 0
-#define FRAMERATE_MAX 6
-static int framerate = -1;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags,
- "Bitfield: 0=VIDIOCSYNC, "
- "1=B/W, "
- "2=show hints, "
- "3=show stats, "
- "4=test pattern, "
- "5=separate frames, "
- "6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-/*
- * ultracam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ultracam_find_header() or ultracam_parse_lines() to do most
- * of work.
- *
- * 02-Nov-2000 First (mostly dummy) version.
- * 06-Nov-2000 Rewrote to dump all data into frame.
- */
-static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- int n;
-
- assert(uvd != NULL);
- assert(frame != NULL);
-
- /* Try to move data from queue into frame buffer */
- n = RingQueue_GetLength(&uvd->dp);
- if (n > 0) {
- int m;
- /* See how much spare we have left */
- m = uvd->max_frame_size - frame->seqRead_Length;
- if (n > m)
- n = m;
- /* Now move that much data into frame buffer */
- RingQueue_Dequeue(
- &uvd->dp,
- frame->data + frame->seqRead_Length,
- m);
- frame->seqRead_Length += m;
- }
- /* See if we filled the frame */
- if (frame->seqRead_Length >= uvd->max_frame_size) {
- frame->frameState = FrameState_Done;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-/*
- * ultracam_veio()
- *
- * History:
- * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ultracam_veio(
- struct uvd *uvd,
- unsigned char req,
- unsigned short value,
- unsigned short index,
- int is_out)
-{
- static const char proc[] = "ultracam_veio";
- unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
- int i;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return 0;
-
- if (!is_out) {
- i = usb_control_msg(
- uvd->dev,
- usb_rcvctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- cp,
- sizeof(cp),
- 1000);
-#if 1
- dev_info(&uvd->dev->dev,
- "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
- "(req=$%02x val=$%04x ind=$%04x)\n",
- cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
- req, value, index);
-#endif
- } else {
- i = usb_control_msg(
- uvd->dev,
- usb_sndctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- NULL,
- 0,
- 1000);
- }
- if (i < 0) {
- err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
- proc, i);
- uvd->last_error = i;
- }
- return i;
-}
-
-/*
- * ultracam_calculate_fps()
- */
-static int ultracam_calculate_fps(struct uvd *uvd)
-{
- return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ultracam_adjust_contrast()
- */
-static void ultracam_adjust_contrast(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ultracam_set_brightness(struct uvd *uvd)
-{
-}
-
-static void ultracam_set_hue(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ultracam_adjust_picture(struct uvd *uvd)
-{
- ultracam_adjust_contrast(uvd);
- ultracam_set_brightness(uvd);
- ultracam_set_hue(uvd);
-}
-
-/*
- * ultracam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ultracam_video_stop(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- */
-static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-}
-
-static void ultracam_video_start(struct uvd *uvd)
-{
- ultracam_reinit_iso(uvd, 0);
-}
-
-static int ultracam_resetPipe(struct uvd *uvd)
-{
- usb_clear_halt(uvd->dev, uvd->video_endp);
- return 0;
-}
-
-static int ultracam_alternateSetting(struct uvd *uvd, int setting)
-{
- static const char proc[] = "ultracam_alternateSetting";
- int i;
- i = usb_set_interface(uvd->dev, uvd->iface, setting);
- if (i < 0) {
- err("%s: usb_set_interface error", proc);
- uvd->last_error = i;
- return -EBUSY;
- }
- return 0;
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ultracam_setup_on_open(struct uvd *uvd)
-{
- int setup_ok = 0; /* Success by default */
- /* Send init sequence only once, it's large! */
- if (!ULTRACAM_T(uvd)->initialized) {
- ultracam_alternateSetting(uvd, 0x04);
- ultracam_alternateSetting(uvd, 0x00);
- ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
- ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
- ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
- ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
- ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
- ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
- ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
- ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
- ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
- ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
- ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
- ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
- ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
- ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
- ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
- ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
- ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
- ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
- ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
- ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
- ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
- ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
- ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
- ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
- ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
- ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
- ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
- ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
- ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
- ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
- ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
- ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
- ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
- ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
- ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
- ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
- ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
- ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
- ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
- ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
- ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
- ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
- ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
- ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
- ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
- ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
- ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
- ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
- ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
- ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
- ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
- ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
- ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_alternateSetting(uvd, 0x04);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
- ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
- ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
- ultracam_resetPipe(uvd);
- ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
- }
- return setup_ok;
-}
-
-static void ultracam_configure_video(struct uvd *uvd)
-{
- if (uvd == NULL)
- return;
-
- RESTRICT_TO_RANGE(init_brightness, 0, 255);
- RESTRICT_TO_RANGE(init_contrast, 0, 255);
- RESTRICT_TO_RANGE(init_color, 0, 255);
- RESTRICT_TO_RANGE(init_hue, 0, 255);
- RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = init_color << 8;
- uvd->vpic.hue = init_hue << 8;
- uvd->vpic.brightness = init_brightness << 8;
- uvd->vpic.contrast = init_contrast << 8;
- uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "IBM Ultra Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
- uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
- uvd->vcap.minwidth = min_canvasWidth;
- uvd->vcap.minheight = min_canvasHeight;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ultracam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like our camera.
- *
- * History:
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- unsigned char video_ep = 0;
-
- if (debug >= 1)
- dev_info(&intf->dev, "ultracam_probe\n");
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n",
- le16_to_cpu(dev->descriptor.bcdDevice));
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (debug > 0)
- dev_info(&intf->dev, "Number of alternate settings=%d.\n",
- nas);
- if (nas < 8) {
- err("Too few alternate settings for this camera!");
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 1) {
- err("Interface %d. has %u. endpoints!",
- interface->desc.bInterfaceNumber,
- (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[0].desc;
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (actInterface < 0) {
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0)
- dev_info(&intf->dev,
- "Active setting=%d. "
- "maxPS=%d.\n", i, maxPS);
- } else {
- /* Got another active alt. setting */
- if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
- /* This one is better! */
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0) {
- dev_info(&intf->dev,
- "Even better ctive "
- "setting=%d. "
- "maxPS=%d.\n",
- i, maxPS);
- }
- }
- }
- }
- }
- if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
- err("Failed to recognize the camera!");
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- /* Here uvd is a fully allocated uvd object */
- uvd->flags = flags;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */
- uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
-
- /* Initialize ibmcam-specific data */
- assert(ULTRACAM_T(uvd) != NULL);
- ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
- ULTRACAM_T(uvd)->initialized = 0;
-
- ultracam_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
- }
-
- if (uvd) {
- usb_set_intfdata (intf, uvd);
- return 0;
- }
- return -EIO;
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
-/*
- * ultracam_init()
- *
- * This code is run to initialize the driver.
- */
-static int __init ultracam_init(void)
-{
- struct usbvideo_cb cbTbl;
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = ultracam_probe;
- cbTbl.setupOnOpen = ultracam_setup_on_open;
- cbTbl.videoStart = ultracam_video_start;
- cbTbl.videoStop = ultracam_video_stop;
- cbTbl.processData = ultracam_ProcessIsocData;
- cbTbl.postProcess = usbvideo_DeinterlaceFrame;
- cbTbl.adjustPicture = ultracam_adjust_picture;
- cbTbl.getFPS = ultracam_calculate_fps;
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(ultracam_t),
- "ultracam",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-static void __exit ultracam_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-MODULE_LICENSE("GPL");
-
-module_init(ultracam_init);
-module_exit(ultracam_cleanup);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 503b13beb922..68b998bd203f 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -32,1072 +32,1072 @@
/* Supported Devices: A table for usbvision.c*/
struct usbvision_device_data_st usbvision_device_data[] = {
[XANBOO] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 4,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Xanboo",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 4,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Xanboo",
},
[BELKIN_VIDEOBUS_II] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Belkin USB VideoBus II Adapter",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Belkin USB VideoBus II Adapter",
},
[BELKIN_VIDEOBUS] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Belkin Components USB VideoBus",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Belkin Components USB VideoBus",
},
[BELKIN_USB_VIDEOBUS_II] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Belkin USB VideoBus II",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Belkin USB VideoBus II",
},
[ECHOFX_INTERVIEW_LITE] = {
- .Interface = 0,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "echoFX InterView Lite",
+ .interface = 0,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "echoFX InterView Lite",
},
[USBGEAR_USBG_V1] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "USBGear USBG-V1 resp. HAMA USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "USBGear USBG-V1 resp. HAMA USB",
},
[D_LINK_V100] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 4,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "D-Link V100",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 4,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "D-Link V100",
},
[X10_USB_CAMERA] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "X10 USB Camera",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "X10 USB Camera",
},
[HPG_WINTV_LIVE_PAL_BG] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Live (PAL B/G)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Live (PAL B/G)",
},
[HPG_WINTV_LIVE_PRO_NTSC_MN] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Live Pro (NTSC M/N)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Live Pro (NTSC M/N)",
},
[ZORAN_PMD_NOGATECH] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 2,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 2,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan",
},
[NOGATECH_USB_TV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "Nogatech USB-TV (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "Nogatech USB-TV (NTSC) FM",
},
[PNY_USB_TV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "PNY USB-TV (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "PNY USB-TV (NTSC) FM",
},
[PV_PLAYTV_USB_PRO_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "PixelView PlayTv-USB PRO (PAL) FM",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "PixelView PlayTv-USB PRO (PAL) FM",
},
[ZT_721] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "ZTV ZT-721 2.4GHz USB A/V Receiver",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "ZTV ZT-721 2.4GHz USB A/V Receiver",
},
[HPG_WINTV_NTSC_MN] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "Hauppauge WinTV USB (NTSC M/N)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "Hauppauge WinTV USB (NTSC M/N)",
},
[HPG_WINTV_PAL_BG] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL B/G)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL B/G)",
},
[HPG_WINTV_PAL_I] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL I)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL I)",
},
[HPG_WINTV_PAL_SECAM_L] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0x80,
- .Y_Offset = 0x16,
- .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0x80,
+ .y_offset = 0x16,
+ .model_string = "Hauppauge WinTV USB (PAL/SECAM L)",
},
[HPG_WINTV_PAL_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL D/K)",
},
[HPG_WINTV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (NTSC FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (NTSC FM)",
},
[HPG_WINTV_PAL_BG_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL B/G FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL B/G FM)",
},
[HPG_WINTV_PAL_I_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL I FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL I FM)",
},
[HPG_WINTV_PAL_D_K_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL D/K FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL D/K FM)",
},
[HPG_WINTV_PRO_NTSC_MN] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N)",
},
[HPG_WINTV_PRO_NTSC_MN_V2] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V2",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V2",
},
[HPG_WINTV_PRO_PAL] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)",
},
[HPG_WINTV_PRO_NTSC_MN_V3] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V3",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V3",
},
[HPG_WINTV_PRO_PAL_BG] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G)",
},
[HPG_WINTV_PRO_PAL_I] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I)",
},
[HPG_WINTV_PRO_PAL_SECAM_L] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM L)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM L)",
},
[HPG_WINTV_PRO_PAL_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL D/K)",
},
[HPG_WINTV_PRO_PAL_SECAM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)",
},
[HPG_WINTV_PRO_PAL_SECAM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2",
},
[HPG_WINTV_PRO_PAL_BG_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_ALPS_TSBE1_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G) V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_ALPS_TSBE1_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G) V2",
},
[HPG_WINTV_PRO_PAL_BG_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_ALPS_TSBE1_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G,D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_ALPS_TSBE1_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G,D/K)",
},
[HPG_WINTV_PRO_PAL_I_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_LG_PAL_NEW_TAPC,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I,D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I,D/K)",
},
[HPG_WINTV_PRO_NTSC_MN_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM)",
},
[HPG_WINTV_PRO_PAL_BG_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G FM)",
},
[HPG_WINTV_PRO_PAL_I_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I FM)",
},
[HPG_WINTV_PRO_PAL_D_K_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL D/K FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL D/K FM)",
},
[HPG_WINTV_PRO_TEMIC_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)",
},
[HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)",
},
[HPG_WINTV_PRO_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)",
},
[HPG_WINTV_PRO_NTSC_MN_FM_V2] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2",
},
[CAMTEL_TVB330] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 5,
- .Y_Offset = 5,
- .ModelString = "Camtel Technology USB TV Genie Pro FM Model TVB330",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 5,
+ .y_offset = 5,
+ .model_string = "Camtel Technology USB TV Genie Pro FM Model TVB330",
},
[DIGITAL_VIDEO_CREATOR_I] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Digital Video Creator I",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Digital Video Creator I",
},
[GLOBAL_VILLAGE_GV_007_NTSC] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 82,
- .Y_Offset = 20,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Global Village GV-007 (NTSC)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 82,
+ .y_offset = 20,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Global Village GV-007 (NTSC)",
},
[DAZZLE_DVC_50_REV_1_NTSC] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)",
},
[DAZZLE_DVC_80_REV_1_PAL] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)",
},
[DAZZLE_DVC_90_REV_1_SECAM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)",
},
[ESKAPE_LABS_MYTV2GO] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Eskape Labs MyTV2Go",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Eskape Labs MyTV2Go",
},
[PINNA_PCTV_USB_PAL] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 0,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4066FY5_PAL_I,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (PAL)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4066FY5_PAL_I,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (PAL)",
},
[PINNA_PCTV_USB_SECAM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (SECAM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (SECAM)",
},
[PINNA_PCTV_USB_PAL_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 128,
- .Y_Offset = 23,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 128,
+ .y_offset = 23,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM",
},
[MIRO_PCTV_USB] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Miro PCTV USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Miro PCTV USB",
},
[PINNA_PCTV_USB_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM",
},
[PINNA_PCTV_USB_NTSC_FM_V3] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V3",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V3",
},
[PINNA_PCTV_USB_PAL_FM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM V2",
},
[PINNA_PCTV_USB_NTSC_FM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4039FR5_NTSC,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V2",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V2",
},
[PINNA_PCTV_USB_PAL_FM_V3] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V3",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM V3",
},
[PINNA_LINX_VD_IN_CAB_NTSC] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio Linx Video input cable (NTSC)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio Linx Video input cable (NTSC)",
},
[PINNA_LINX_VD_IN_CAB_PAL] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio Linx Video input cable (PAL)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio Linx Video input cable (PAL)",
},
[PINNA_PCTV_BUNGEE_PAL_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle PCTV Bungee USB (PAL) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle PCTV Bungee USB (PAL) FM",
},
[HPG_WINTV] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTv-USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTv-USB",
},
};
-const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data);
+const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
/* Supported Devices */
-struct usb_device_id usbvision_table [] = {
- { USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO },
- { USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II },
- { USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS },
- { USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II },
- { USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE },
- { USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 },
- { USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 },
- { USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA },
- { USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG },
- { USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN },
- { USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH },
- { USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM },
- { USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 },
- { USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN },
- { USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG },
- { USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I },
- { USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L },
- { USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K },
- { USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM },
- { USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM },
- { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
- { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
- { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
+struct usb_device_id usbvision_table[] = {
+ { USB_DEVICE(0x0a6f, 0x0400), .driver_info = XANBOO },
+ { USB_DEVICE(0x050d, 0x0106), .driver_info = BELKIN_VIDEOBUS_II },
+ { USB_DEVICE(0x050d, 0x0207), .driver_info = BELKIN_VIDEOBUS },
+ { USB_DEVICE(0x050d, 0x0208), .driver_info = BELKIN_USB_VIDEOBUS_II },
+ { USB_DEVICE(0x0571, 0x0002), .driver_info = ECHOFX_INTERVIEW_LITE },
+ { USB_DEVICE(0x0573, 0x0003), .driver_info = USBGEAR_USBG_V1 },
+ { USB_DEVICE(0x0573, 0x0400), .driver_info = D_LINK_V100 },
+ { USB_DEVICE(0x0573, 0x2000), .driver_info = X10_USB_CAMERA },
+ { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
+ { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
+ { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4550), .driver_info = ZT_721 },
+ { USB_DEVICE(0x0573, 0x4d00), .driver_info = HPG_WINTV_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x4d01), .driver_info = HPG_WINTV_PAL_BG },
+ { USB_DEVICE(0x0573, 0x4d02), .driver_info = HPG_WINTV_PAL_I },
+ { USB_DEVICE(0x0573, 0x4d03), .driver_info = HPG_WINTV_PAL_SECAM_L },
+ { USB_DEVICE(0x0573, 0x4d04), .driver_info = HPG_WINTV_PAL_D_K },
+ { USB_DEVICE(0x0573, 0x4d10), .driver_info = HPG_WINTV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4d11), .driver_info = HPG_WINTV_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d12), .driver_info = HPG_WINTV_PAL_I_FM },
+ { USB_DEVICE(0x0573, 0x4d14), .driver_info = HPG_WINTV_PAL_D_K_FM },
+ { USB_DEVICE(0x0573, 0x4d2a), .driver_info = HPG_WINTV_PRO_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x4d2b), .driver_info = HPG_WINTV_PRO_NTSC_MN_V2 },
+ { USB_DEVICE(0x0573, 0x4d2c), .driver_info = HPG_WINTV_PRO_PAL },
{ USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
- { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
- { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
- { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
- { USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K },
- { USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM },
- { USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 },
- { USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 },
- { USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K },
- { USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K },
- { USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM },
- { USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM },
- { USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM },
- { USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM },
- { USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM },
- { USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 },
- { USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 },
- { USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I },
- { USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC },
- { USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC },
- { USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL },
- { USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM },
- { USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO },
- { USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL },
- { USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM },
- { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
- { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
- { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4d21), .driver_info = HPG_WINTV_PRO_PAL_BG },
+ { USB_DEVICE(0x0573, 0x4d22), .driver_info = HPG_WINTV_PRO_PAL_I },
+ { USB_DEVICE(0x0573, 0x4d23), .driver_info = HPG_WINTV_PRO_PAL_SECAM_L },
+ { USB_DEVICE(0x0573, 0x4d24), .driver_info = HPG_WINTV_PRO_PAL_D_K },
+ { USB_DEVICE(0x0573, 0x4d25), .driver_info = HPG_WINTV_PRO_PAL_SECAM },
+ { USB_DEVICE(0x0573, 0x4d26), .driver_info = HPG_WINTV_PRO_PAL_SECAM_V2 },
+ { USB_DEVICE(0x0573, 0x4d27), .driver_info = HPG_WINTV_PRO_PAL_BG_V2 },
+ { USB_DEVICE(0x0573, 0x4d28), .driver_info = HPG_WINTV_PRO_PAL_BG_D_K },
+ { USB_DEVICE(0x0573, 0x4d29), .driver_info = HPG_WINTV_PRO_PAL_I_D_K },
+ { USB_DEVICE(0x0573, 0x4d30), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM },
+ { USB_DEVICE(0x0573, 0x4d31), .driver_info = HPG_WINTV_PRO_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d32), .driver_info = HPG_WINTV_PRO_PAL_I_FM },
+ { USB_DEVICE(0x0573, 0x4d34), .driver_info = HPG_WINTV_PRO_PAL_D_K_FM },
+ { USB_DEVICE(0x0573, 0x4d35), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4d36), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d37), .driver_info = HPG_WINTV_PRO_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4d38), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM_V2 },
+ { USB_DEVICE(0x0768, 0x0006), .driver_info = CAMTEL_TVB330 },
+ { USB_DEVICE(0x07d0, 0x0001), .driver_info = DIGITAL_VIDEO_CREATOR_I },
+ { USB_DEVICE(0x07d0, 0x0002), .driver_info = GLOBAL_VILLAGE_GV_007_NTSC },
+ { USB_DEVICE(0x07d0, 0x0003), .driver_info = DAZZLE_DVC_50_REV_1_NTSC },
+ { USB_DEVICE(0x07d0, 0x0004), .driver_info = DAZZLE_DVC_80_REV_1_PAL },
+ { USB_DEVICE(0x07d0, 0x0005), .driver_info = DAZZLE_DVC_90_REV_1_SECAM },
+ { USB_DEVICE(0x07f8, 0x9104), .driver_info = ESKAPE_LABS_MYTV2GO },
+ { USB_DEVICE(0x2304, 0x010d), .driver_info = PINNA_PCTV_USB_PAL },
+ { USB_DEVICE(0x2304, 0x0109), .driver_info = PINNA_PCTV_USB_SECAM },
+ { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
+ { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
+ { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
{ USB_DEVICE(0x2304, 0x0113),
.driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
- { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
- { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
- { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
- { USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC },
- { 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 },
+ { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
+ { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
+ { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
+ { USB_DEVICE(0x2304, 0x0300), .driver_info = PINNA_LINX_VD_IN_CAB_NTSC },
+ { 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);
+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 b9dd74fde212..c8feb0d6fccf 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -33,7 +33,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
@@ -46,30 +46,30 @@
#include "usbvision.h"
static unsigned int core_debug;
-module_param(core_debug,int,0644);
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
static unsigned int force_testpattern;
-module_param(force_testpattern,int,0644);
-MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");
+module_param(force_testpattern, int, 0644);
+MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]");
-static int adjustCompression = 1; /* Set the compression to be adaptive */
-module_param(adjustCompression, int, 0444);
-MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)");
+static int adjust_compression = 1; /* Set the compression to be adaptive */
+module_param(adjust_compression, int, 0444);
+MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)");
/* To help people with Black and White output with using s-video input.
* Some cables and input device are wired differently. */
-static int SwitchSVideoInput;
-module_param(SwitchSVideoInput, int, 0444);
-MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");
+static int switch_svideo_input;
+module_param(switch_svideo_input, int, 0444);
+MODULE_PARM_DESC(switch_svideo_input, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");
-static unsigned int adjust_X_Offset = -1;
-module_param(adjust_X_Offset, int, 0644);
-MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
+static unsigned int adjust_x_offset = -1;
+module_param(adjust_x_offset, int, 0644);
+MODULE_PARM_DESC(adjust_x_offset, "adjust X offset display [core]");
-static unsigned int adjust_Y_Offset = -1;
-module_param(adjust_Y_Offset, int, 0644);
-MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
+static unsigned int adjust_y_offset = -1;
+module_param(adjust_y_offset, int, 0644);
+MODULE_PARM_DESC(adjust_y_offset, "adjust Y offset display [core]");
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
@@ -82,15 +82,15 @@ MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
__func__, __LINE__ , ## args); \
}
#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
+ #define PDEBUG(level, fmt, args...) do {} while (0)
#endif
-#define DBG_HEADER 1<<0
-#define DBG_IRQ 1<<1
-#define DBG_ISOC 1<<2
-#define DBG_PARSE 1<<3
-#define DBG_SCRATCH 1<<4
-#define DBG_FUNC 1<<5
+#define DBG_HEADER (1 << 0)
+#define DBG_IRQ (1 << 1)
+#define DBG_ISOC (1 << 2)
+#define DBG_PARSE (1 << 3)
+#define DBG_SCRATCH (1 << 4)
+#define DBG_FUNC (1 << 5)
static const int max_imgwidth = MAX_FRAME_WIDTH;
static const int max_imgheight = MAX_FRAME_HEIGHT;
@@ -103,14 +103,14 @@ static const int min_imgheight = MIN_FRAME_HEIGHT;
* to work with. This setting can be adjusted, but the default value
* should be OK for most desktop users.
*/
-#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch buffer
+#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) /* 128kB memory scratch buffer */
static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;
-// Function prototypes
-static int usbvision_request_intra (struct usb_usbvision *usbvision);
-static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);
-static int usbvision_adjust_compression (struct usb_usbvision *usbvision);
-static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);
+/* Function prototypes */
+static int usbvision_request_intra(struct usb_usbvision *usbvision);
+static int usbvision_unrequest_intra(struct usb_usbvision *usbvision);
+static int usbvision_adjust_compression(struct usb_usbvision *usbvision);
+static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision);
/*******************************/
/* Memory management functions */
@@ -176,19 +176,19 @@ static void usbvision_hexdump(const unsigned char *data, int len)
k += sprintf(&tmp[k], "%02x ", data[i]);
}
if (k > 0)
- printk("%s\n", tmp);
+ printk(KERN_CONT "%s\n", tmp);
}
#endif
/********************************
* scratch ring buffer handling
********************************/
-static int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */
+static int scratch_len(struct usb_usbvision *usbvision) /* This returns the amount of data actually in the buffer */
{
int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr;
- if (len < 0) {
+
+ if (len < 0)
len += scratch_buf_size;
- }
PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len);
return len;
@@ -199,9 +199,8 @@ static int scratch_len(struct usb_usbvision *usbvision) /*This returns the am
static int scratch_free(struct usb_usbvision *usbvision)
{
int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr;
- if (free <= 0) {
+ if (free <= 0)
free += scratch_buf_size;
- }
if (free) {
free -= 1; /* at least one byte in the buffer must */
/* left blank, otherwise there is no chance to differ between full and empty */
@@ -221,14 +220,12 @@ static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data,
if (usbvision->scratch_write_ptr + len < scratch_buf_size) {
memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len);
usbvision->scratch_write_ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - usbvision->scratch_write_ptr;
memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part);
if (len == len_part) {
usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */
- }
- else {
+ } else {
memcpy(usbvision->scratch, data + len_part, len - len_part);
usbvision->scratch_write_ptr = len - len_part;
}
@@ -255,17 +252,16 @@ static int scratch_get_extra(struct usb_usbvision *usbvision,
unsigned char *data, int *ptr, int len)
{
int len_part;
+
if (*ptr + len < scratch_buf_size) {
memcpy(data, usbvision->scratch + *ptr, len);
*ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - *ptr;
memcpy(data, usbvision->scratch + *ptr, len_part);
if (len == len_part) {
*ptr = 0; /* just set the y_ptr to zero */
- }
- else {
+ } else {
memcpy(data + len_part, usbvision->scratch, len - len_part);
*ptr = len - len_part;
}
@@ -281,13 +277,13 @@ static int scratch_get_extra(struct usb_usbvision *usbvision,
static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr,
int len)
{
- *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size;
+ *ptr = (usbvision->scratch_read_ptr + len) % scratch_buf_size;
PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
}
-/*This increments the scratch extra read pointer */
+/* This increments the scratch extra read pointer */
static void scratch_inc_extra_ptr(int *ptr, int len)
{
*ptr = (*ptr + len) % scratch_buf_size;
@@ -301,17 +297,16 @@ static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,
int len)
{
int len_part;
+
if (usbvision->scratch_read_ptr + len < scratch_buf_size) {
memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len);
usbvision->scratch_read_ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - usbvision->scratch_read_ptr;
memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part);
if (len == len_part) {
usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */
- }
- else {
+ } else {
memcpy(data + len_part, usbvision->scratch, len - len_part);
usbvision->scratch_read_ptr = len - len_part;
}
@@ -327,7 +322,7 @@ static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,
static int scratch_get_header(struct usb_usbvision *usbvision,
struct usbvision_frame_header *header)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr);
@@ -340,29 +335,28 @@ static int scratch_get_header(struct usb_usbvision *usbvision,
scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH);
if ((header->magic_1 == USBVISION_MAGIC_1)
&& (header->magic_2 == USBVISION_MAGIC_2)
- && (header->headerLength == USBVISION_HEADER_LENGTH)) {
- errCode = USBVISION_HEADER_LENGTH;
- header->frameWidth = header->frameWidthLo + (header->frameWidthHi << 8);
- header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8);
+ && (header->header_length == USBVISION_HEADER_LENGTH)) {
+ err_code = USBVISION_HEADER_LENGTH;
+ header->frame_width = header->frame_width_lo + (header->frame_width_hi << 8);
+ header->frame_height = header->frame_height_lo + (header->frame_height_hi << 8);
break;
}
}
- return errCode;
+ return err_code;
}
-/*This removes len bytes of old data from the buffer */
+/* This removes len bytes of old data from the buffer */
static void scratch_rm_old(struct usb_usbvision *usbvision, int len)
{
-
usbvision->scratch_read_ptr += len;
usbvision->scratch_read_ptr %= scratch_buf_size;
PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);
}
-/*This resets the buffer - kills all data in it too */
+/* This resets the buffer - kills all data in it too */
static void scratch_reset(struct usb_usbvision *usbvision)
{
PDEBUG(DBG_SCRATCH, "\n");
@@ -371,14 +365,14 @@ static void scratch_reset(struct usb_usbvision *usbvision)
usbvision->scratch_write_ptr = 0;
usbvision->scratch_headermarker_read_ptr = 0;
usbvision->scratch_headermarker_write_ptr = 0;
- usbvision->isocstate = IsocState_NoFrame;
+ usbvision->isocstate = isoc_state_no_frame;
}
int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
{
usbvision->scratch = vmalloc_32(scratch_buf_size);
scratch_reset(usbvision);
- if(usbvision->scratch == NULL) {
+ if (usbvision->scratch == NULL) {
dev_err(&usbvision->dev->dev,
"%s: unable to allocate %d bytes for scratch\n",
__func__, scratch_buf_size);
@@ -391,7 +385,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision)
{
vfree(usbvision->scratch);
usbvision->scratch = NULL;
-
}
/*
@@ -420,13 +413,13 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
printk(KERN_ERR "%s: usbvision == NULL\n", proc);
return;
}
- if (usbvision->curFrame == NULL) {
- printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);
+ if (usbvision->cur_frame == NULL) {
+ printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc);
return;
}
/* Grab the current frame */
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
/* Optionally start at the beginning */
if (fullframe) {
@@ -473,10 +466,9 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
}
}
- frame->grabstate = FrameState_Done;
+ frame->grabstate = frame_state_done;
frame->scanlength += scan_length;
++num_pass;
-
}
/*
@@ -487,8 +479,9 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
{
int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
- usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
- if (usbvision->IntraFrameBuffer == NULL) {
+
+ usbvision->intra_frame_buffer = vmalloc_32(IFB_size);
+ if (usbvision->intra_frame_buffer == NULL) {
dev_err(&usbvision->dev->dev,
"%s: unable to allocate %d for compr. frame buffer\n",
__func__, IFB_size);
@@ -504,8 +497,8 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
*/
void usbvision_decompress_free(struct usb_usbvision *usbvision)
{
- vfree(usbvision->IntraFrameBuffer);
- usbvision->IntraFrameBuffer = NULL;
+ vfree(usbvision->intra_frame_buffer);
+ usbvision->intra_frame_buffer = NULL;
}
@@ -517,117 +510,111 @@ void usbvision_decompress_free(struct usb_usbvision *usbvision)
*
* Locate one of supported header markers in the scratch buffer.
*/
-static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
+static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision)
{
struct usbvision_frame *frame;
- int foundHeader = 0;
+ int found_header = 0;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
- while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {
- // found header in scratch
+ while (scratch_get_header(usbvision, &frame->isoc_header) == USBVISION_HEADER_LENGTH) {
+ /* found header in scratch */
PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u",
- frame->isocHeader.magic_2,
- frame->isocHeader.magic_1,
- frame->isocHeader.headerLength,
- frame->isocHeader.frameNum,
- frame->isocHeader.framePhase,
- frame->isocHeader.frameLatency,
- frame->isocHeader.dataFormat,
- frame->isocHeader.formatParam,
- frame->isocHeader.frameWidth,
- frame->isocHeader.frameHeight);
-
- if (usbvision->requestIntra) {
- if (frame->isocHeader.formatParam & 0x80) {
- foundHeader = 1;
- usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time
+ frame->isoc_header.magic_2,
+ frame->isoc_header.magic_1,
+ frame->isoc_header.header_length,
+ frame->isoc_header.frame_num,
+ frame->isoc_header.frame_phase,
+ frame->isoc_header.frame_latency,
+ frame->isoc_header.data_format,
+ frame->isoc_header.format_param,
+ frame->isoc_header.frame_width,
+ frame->isoc_header.frame_height);
+
+ if (usbvision->request_intra) {
+ if (frame->isoc_header.format_param & 0x80) {
+ found_header = 1;
+ usbvision->last_isoc_frame_num = -1; /* do not check for lost frames this time */
usbvision_unrequest_intra(usbvision);
break;
}
- }
- else {
- foundHeader = 1;
+ } else {
+ found_header = 1;
break;
}
}
- if (foundHeader) {
- frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;
- frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;
- frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;
- }
- else { // no header found
+ if (found_header) {
+ frame->frmwidth = frame->isoc_header.frame_width * usbvision->stretch_width;
+ frame->frmheight = frame->isoc_header.frame_height * usbvision->stretch_height;
+ frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth) >> 3;
+ } else { /* no header found */
PDEBUG(DBG_HEADER, "skipping scratch data, no header");
scratch_reset(usbvision);
- return ParseState_EndParse;
+ return parse_state_end_parse;
}
- // found header
- if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) {
- //check isocHeader.frameNum for lost frames
- if (usbvision->lastIsocFrameNum >= 0) {
- if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) {
- // unexpected frame drop: need to request new intra frame
- PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum);
+ /* found header */
+ if (frame->isoc_header.data_format == ISOC_MODE_COMPRESS) {
+ /* check isoc_header.frame_num for lost frames */
+ if (usbvision->last_isoc_frame_num >= 0) {
+ if (((usbvision->last_isoc_frame_num + 1) % 32) != frame->isoc_header.frame_num) {
+ /* unexpected frame drop: need to request new intra frame */
+ PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isoc_header.frame_num);
usbvision_request_intra(usbvision);
- return ParseState_NextFrame;
+ return parse_state_next_frame;
}
}
- usbvision->lastIsocFrameNum = frame->isocHeader.frameNum;
+ usbvision->last_isoc_frame_num = frame->isoc_header.frame_num;
}
usbvision->header_count++;
- frame->scanstate = ScanState_Lines;
+ frame->scanstate = scan_state_lines;
frame->curline = 0;
if (force_testpattern) {
usbvision_testpattern(usbvision, 1, 1);
- return ParseState_NextFrame;
+ return parse_state_next_frame;
}
- return ParseState_Continue;
+ return parse_state_continue;
}
-static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_lines_422(struct usb_usbvision *usbvision,
long *pcopylen)
{
volatile struct usbvision_frame *frame;
unsigned char *f;
int len;
int i;
- unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components
- unsigned char rv, gv, bv; // RGB components
+ unsigned char yuyv[4] = { 180, 128, 10, 128 }; /* YUV components */
+ unsigned char rv, gv, bv; /* RGB components */
int clipmask_index, bytes_per_pixel;
int stretch_bytes, clipmask_add;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
f = frame->data + (frame->v4l2_linesize * frame->curline);
/* Make sure there's enough data for the entire line */
- len = (frame->isocHeader.frameWidth * 2)+5;
+ len = (frame->isoc_header.frame_width * 2) + 5;
if (scratch_len(usbvision) < len) {
PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len);
- return ParseState_Out;
+ return parse_state_out;
}
- if ((frame->curline + 1) >= frame->frmheight) {
- return ParseState_NextFrame;
- }
+ if ((frame->curline + 1) >= frame->frmheight)
+ return parse_state_next_frame;
bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
clipmask_index = frame->curline * MAX_FRAME_WIDTH;
clipmask_add = usbvision->stretch_width;
- for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) {
-
+ for (i = 0; i < frame->frmwidth; i += (2 * usbvision->stretch_width)) {
scratch_get(usbvision, &yuyv[0], 4);
if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = yuyv[0]; // Y
- *f++ = yuyv[3]; // U
- }
- else {
-
+ *f++ = yuyv[0]; /* Y */
+ *f++ = yuyv[3]; /* U */
+ } else {
YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
switch (frame->v4l2_format.format) {
case V4L2_PIX_FMT_RGB565:
@@ -659,11 +646,9 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
f += stretch_bytes;
if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = yuyv[2]; // Y
- *f++ = yuyv[1]; // V
- }
- else {
-
+ *f++ = yuyv[2]; /* Y */
+ *f++ = yuyv[1]; /* V */
+ } else {
YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
switch (frame->v4l2_format.format) {
case V4L2_PIX_FMT_RGB565:
@@ -698,100 +683,94 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
frame->curline += usbvision->stretch_height;
*pcopylen += frame->v4l2_linesize * usbvision->stretch_height;
- if (frame->curline >= frame->frmheight) {
- return ParseState_NextFrame;
- }
- else {
- return ParseState_Continue;
- }
+ if (frame->curline >= frame->frmheight)
+ return parse_state_next_frame;
+ return parse_state_continue;
}
/* The decompression routine */
-static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed,
- unsigned char *Decompressed, int *StartPos,
- int *BlockTypeStartPos, int Len)
+static int usbvision_decompress(struct usb_usbvision *usbvision, unsigned char *compressed,
+ unsigned char *decompressed, int *start_pos,
+ int *block_typestart_pos, int len)
{
- int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen;
- unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator;
-
- Integrator = 0;
- Pos = *StartPos;
- BlockTypePos = *BlockTypeStartPos;
- MaxPos = 396; //Pos + Len;
- ExtraPos = Pos;
- BlockLen = 0;
- BlockByte = 0;
- BlockCode = 0;
- BlockType = 0;
- BlockTypeByte = 0;
- BlockTypeLen = 0;
- RestPixel = Len;
-
- for (Idx = 0; Idx < Len; Idx++) {
-
- if (BlockLen == 0) {
- if (BlockTypeLen==0) {
- BlockTypeByte = Compressed[BlockTypePos];
- BlockTypePos++;
- BlockTypeLen = 4;
+ int rest_pixel, idx, max_pos, pos, extra_pos, block_len, block_type_pos, block_type_len;
+ unsigned char block_byte, block_code, block_type, block_type_byte, integrator;
+
+ integrator = 0;
+ pos = *start_pos;
+ block_type_pos = *block_typestart_pos;
+ max_pos = 396; /* pos + len; */
+ extra_pos = pos;
+ block_len = 0;
+ block_byte = 0;
+ block_code = 0;
+ block_type = 0;
+ block_type_byte = 0;
+ block_type_len = 0;
+ rest_pixel = len;
+
+ for (idx = 0; idx < len; idx++) {
+ if (block_len == 0) {
+ if (block_type_len == 0) {
+ block_type_byte = compressed[block_type_pos];
+ block_type_pos++;
+ block_type_len = 4;
}
- BlockType = (BlockTypeByte & 0xC0) >> 6;
+ block_type = (block_type_byte & 0xC0) >> 6;
- //statistic:
- usbvision->ComprBlockTypes[BlockType]++;
+ /* statistic: */
+ usbvision->compr_block_types[block_type]++;
- Pos = ExtraPos;
- if (BlockType == 0) {
- if(RestPixel >= 24) {
- Idx += 23;
- RestPixel -= 24;
- Integrator = Decompressed[Idx];
+ pos = extra_pos;
+ if (block_type == 0) {
+ if (rest_pixel >= 24) {
+ idx += 23;
+ rest_pixel -= 24;
+ integrator = decompressed[idx];
} else {
- Idx += RestPixel - 1;
- RestPixel = 0;
+ idx += rest_pixel - 1;
+ rest_pixel = 0;
}
} else {
- BlockCode = Compressed[Pos];
- Pos++;
- if (RestPixel >= 24) {
- BlockLen = 24;
- } else {
- BlockLen = RestPixel;
- }
- RestPixel -= BlockLen;
- ExtraPos = Pos + (BlockLen / 4);
+ block_code = compressed[pos];
+ pos++;
+ if (rest_pixel >= 24)
+ block_len = 24;
+ else
+ block_len = rest_pixel;
+ rest_pixel -= block_len;
+ extra_pos = pos + (block_len / 4);
}
- BlockTypeByte <<= 2;
- BlockTypeLen -= 1;
+ block_type_byte <<= 2;
+ block_type_len -= 1;
}
- if (BlockLen > 0) {
- if ((BlockLen%4) == 0) {
- BlockByte = Compressed[Pos];
- Pos++;
+ if (block_len > 0) {
+ if ((block_len % 4) == 0) {
+ block_byte = compressed[pos];
+ pos++;
}
- if (BlockType == 1) { //inter Block
- Integrator = Decompressed[Idx];
- }
- switch (BlockByte & 0xC0) {
- case 0x03<<6:
- Integrator += Compressed[ExtraPos];
- ExtraPos++;
- break;
- case 0x02<<6:
- Integrator += BlockCode;
- break;
- case 0x00:
- Integrator -= BlockCode;
- break;
+ if (block_type == 1) /* inter Block */
+ integrator = decompressed[idx];
+ switch (block_byte & 0xC0) {
+ case 0x03 << 6:
+ integrator += compressed[extra_pos];
+ extra_pos++;
+ break;
+ case 0x02 << 6:
+ integrator += block_code;
+ break;
+ case 0x00:
+ integrator -= block_code;
+ break;
}
- Decompressed[Idx] = Integrator;
- BlockByte <<= 2;
- BlockLen -= 1;
+ decompressed[idx] = integrator;
+ block_byte <<= 2;
+ block_len -= 1;
}
}
- *StartPos = ExtraPos;
- *BlockTypeStartPos = BlockTypePos;
- return Idx;
+ *start_pos = extra_pos;
+ *block_typestart_pos = block_type_pos;
+ return idx;
}
@@ -803,7 +782,7 @@ static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *C
* number of bytes (RGB) to the *pcopylen.
*
*/
-static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision,
long *pcopylen)
{
#define USBVISION_STRIP_MAGIC 0x5A
@@ -811,191 +790,165 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
#define USBVISION_STRIP_HEADER_LEN 3
struct usbvision_frame *frame;
- unsigned char *f,*u = NULL ,*v = NULL;
- unsigned char StripData[USBVISION_STRIP_LEN_MAX];
- unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN];
- int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos;
+ unsigned char *f, *u = NULL, *v = NULL;
+ unsigned char strip_data[USBVISION_STRIP_LEN_MAX];
+ unsigned char strip_header[USBVISION_STRIP_HEADER_LEN];
+ int idx, idx_end, strip_len, strip_ptr, startblock_pos, block_pos, block_type_pos;
int clipmask_index, bytes_per_pixel, rc;
- int imageSize;
+ int image_size;
unsigned char rv, gv, bv;
static unsigned char *Y, *U, *V;
- frame = usbvision->curFrame;
- imageSize = frame->frmwidth * frame->frmheight;
- if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
- (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) { // this is a planar format
- //... v4l2_linesize not used here.
+ frame = usbvision->cur_frame;
+ image_size = frame->frmwidth * frame->frmheight;
+ if ((frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
+ (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420)) { /* this is a planar format */
+ /* ... v4l2_linesize not used here. */
f = frame->data + (frame->width * frame->curline);
} else
f = frame->data + (frame->v4l2_linesize * frame->curline);
- if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers
- // get base of u and b planes add halfoffset
-
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { /* initialise u and v pointers */
+ /* get base of u and b planes add halfoffset */
u = frame->data
- + imageSize
- + (frame->frmwidth >>1) * frame->curline ;
- v = u + (imageSize >>1 );
-
- } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){
-
- v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ;
- u = v + (imageSize >>2) ;
+ + image_size
+ + (frame->frmwidth >> 1) * frame->curline;
+ v = u + (image_size >> 1);
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+ v = frame->data + image_size + ((frame->curline * (frame->width)) >> 2);
+ u = v + (image_size >> 2);
}
- if (frame->curline == 0) {
+ if (frame->curline == 0)
usbvision_adjust_compression(usbvision);
- }
- if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) {
- return ParseState_Out;
- }
+ if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN)
+ return parse_state_out;
- //get strip header without changing the scratch_read_ptr
- scratch_set_extra_ptr(usbvision, &StripPtr, 0);
- scratch_get_extra(usbvision, &StripHeader[0], &StripPtr,
+ /* get strip header without changing the scratch_read_ptr */
+ scratch_set_extra_ptr(usbvision, &strip_ptr, 0);
+ scratch_get_extra(usbvision, &strip_header[0], &strip_ptr,
USBVISION_STRIP_HEADER_LEN);
- if (StripHeader[0] != USBVISION_STRIP_MAGIC) {
- // wrong strip magic
- usbvision->stripMagicErrors++;
- return ParseState_NextFrame;
+ if (strip_header[0] != USBVISION_STRIP_MAGIC) {
+ /* wrong strip magic */
+ usbvision->strip_magic_errors++;
+ return parse_state_next_frame;
}
- if (frame->curline != (int)StripHeader[2]) {
- //line number missmatch error
- usbvision->stripLineNumberErrors++;
+ if (frame->curline != (int)strip_header[2]) {
+ /* line number mismatch error */
+ usbvision->strip_line_number_errors++;
}
- StripLen = 2 * (unsigned int)StripHeader[1];
- if (StripLen > USBVISION_STRIP_LEN_MAX) {
- // strip overrun
- // I think this never happens
+ strip_len = 2 * (unsigned int)strip_header[1];
+ if (strip_len > USBVISION_STRIP_LEN_MAX) {
+ /* strip overrun */
+ /* I think this never happens */
usbvision_request_intra(usbvision);
}
- if (scratch_len(usbvision) < StripLen) {
- //there is not enough data for the strip
- return ParseState_Out;
+ if (scratch_len(usbvision) < strip_len) {
+ /* there is not enough data for the strip */
+ return parse_state_out;
}
- if (usbvision->IntraFrameBuffer) {
- Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline;
- U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2);
- V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
- }
- else {
- return ParseState_NextFrame;
+ if (usbvision->intra_frame_buffer) {
+ Y = usbvision->intra_frame_buffer + frame->frmwidth * frame->curline;
+ U = usbvision->intra_frame_buffer + image_size + (frame->frmwidth / 2) * (frame->curline / 2);
+ V = usbvision->intra_frame_buffer + image_size / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
+ } else {
+ return parse_state_next_frame;
}
bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
clipmask_index = frame->curline * MAX_FRAME_WIDTH;
- scratch_get(usbvision, StripData, StripLen);
+ scratch_get(usbvision, strip_data, strip_len);
- IdxEnd = frame->frmwidth;
- BlockTypePos = USBVISION_STRIP_HEADER_LEN;
- StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2;
- BlockPos = StartBlockPos;
+ idx_end = frame->frmwidth;
+ block_type_pos = USBVISION_STRIP_HEADER_LEN;
+ startblock_pos = block_type_pos + (idx_end - 1) / 96 + (idx_end / 2 - 1) / 96 + 2;
+ block_pos = startblock_pos;
- usbvision->BlockPos = BlockPos;
+ usbvision->block_pos = block_pos;
- if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) {
- //return ParseState_Continue;
- }
- if (StripLen > usbvision->maxStripLen) {
- usbvision->maxStripLen = StripLen;
- }
+ rc = usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
+ if (strip_len > usbvision->max_strip_len)
+ usbvision->max_strip_len = strip_len;
- if (frame->curline%2) {
- if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
- //return ParseState_Continue;
- }
- }
- else {
- if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
- //return ParseState_Continue;
- }
- }
+ if (frame->curline % 2)
+ rc = usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
+ else
+ rc = usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
- if (BlockPos > usbvision->comprBlockPos) {
- usbvision->comprBlockPos = BlockPos;
- }
- if (BlockPos > StripLen) {
- usbvision->stripLenErrors++;
- }
+ if (block_pos > usbvision->comprblock_pos)
+ usbvision->comprblock_pos = block_pos;
+ if (block_pos > strip_len)
+ usbvision->strip_len_errors++;
- for (Idx = 0; Idx < IdxEnd; Idx++) {
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = Y[Idx];
- *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2];
- }
- else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
- *f++ = Y[Idx];
- if ( Idx & 0x01)
- *u++ = U[Idx>>1] ;
+ for (idx = 0; idx < idx_end; idx++) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f++ = Y[idx];
+ *f++ = idx & 0x01 ? U[idx / 2] : V[idx / 2];
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
+ *f++ = Y[idx];
+ if (idx & 0x01)
+ *u++ = U[idx >> 1];
else
- *v++ = V[Idx>>1];
- }
- else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
- *f++ = Y [Idx];
- if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){
-
-/* only need do this for 1 in 4 pixels */
-/* intraframe buffer is YUV420 format */
-
- *u++ = U[Idx >>1];
- *v++ = V[Idx >>1];
+ *v++ = V[idx >> 1];
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+ *f++ = Y[idx];
+ if (!((idx & 0x01) | (frame->curline & 0x01))) {
+ /* only need do this for 1 in 4 pixels */
+ /* intraframe buffer is YUV420 format */
+ *u++ = U[idx >> 1];
+ *v++ = V[idx >> 1];
}
-
- }
- else {
- YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv);
+ } else {
+ YUV_TO_RGB_BY_THE_BOOK(Y[idx], U[idx / 2], V[idx / 2], rv, gv, bv);
switch (frame->v4l2_format.format) {
- case V4L2_PIX_FMT_GREY:
- *f++ = Y[Idx];
- break;
- case V4L2_PIX_FMT_RGB555:
- *f++ = (0x1F & rv) |
- (0xE0 & (gv << 5));
- *f++ = (0x03 & (gv >> 3)) |
- (0x7C & (bv << 2));
- break;
- case V4L2_PIX_FMT_RGB565:
- *f++ = (0x1F & rv) |
- (0xE0 & (gv << 5));
- *f++ = (0x07 & (gv >> 3)) |
- (0xF8 & bv);
- break;
- case V4L2_PIX_FMT_RGB24:
- *f++ = rv;
- *f++ = gv;
- *f++ = bv;
- break;
- case V4L2_PIX_FMT_RGB32:
- *f++ = rv;
- *f++ = gv;
- *f++ = bv;
- f++;
- break;
+ case V4L2_PIX_FMT_GREY:
+ *f++ = Y[idx];
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ *f++ = (0x1F & rv) |
+ (0xE0 & (gv << 5));
+ *f++ = (0x03 & (gv >> 3)) |
+ (0x7C & (bv << 2));
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ *f++ = (0x1F & rv) |
+ (0xE0 & (gv << 5));
+ *f++ = (0x07 & (gv >> 3)) |
+ (0xF8 & bv);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f++ = rv;
+ *f++ = gv;
+ *f++ = bv;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f++ = rv;
+ *f++ = gv;
+ *f++ = bv;
+ f++;
+ break;
}
}
clipmask_index++;
}
/* Deal with non-integer no. of bytes for YUV420P */
- if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 )
+ if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420)
*pcopylen += frame->v4l2_linesize;
else
*pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1;
frame->curline += 1;
- if (frame->curline >= frame->frmheight) {
- return ParseState_NextFrame;
- }
- else {
- return ParseState_Continue;
- }
+ if (frame->curline >= frame->frmheight)
+ return parse_state_next_frame;
+ return parse_state_continue;
}
@@ -1008,7 +961,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
* number of bytes (RGB) to the *pcopylen.
*
*/
-static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_lines_420(struct usb_usbvision *usbvision,
long *pcopylen)
{
struct usbvision_frame *frame;
@@ -1016,11 +969,11 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
unsigned int pixel_per_line, block;
int pixel, block_split;
int y_ptr, u_ptr, v_ptr, y_odd_offset;
- const int y_block_size = 128;
- const int uv_block_size = 64;
+ const int y_block_size = 128;
+ const int uv_block_size = 64;
const int sub_block_size = 32;
- const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4;
- const int uv_step[]= { 0, 0, 0, 4 }, uv_step_size = 4;
+ const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4;
+ const int uv_step[] = { 0, 0, 0, 4 }, uv_step_size = 4;
unsigned char y[2], u, v; /* YUV components */
int y_, u_, v_, vb, uvg, ur;
int r_, g_, b_; /* RGB components */
@@ -1028,7 +981,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
int clipmask_even_index, clipmask_odd_index, bytes_per_pixel;
int clipmask_add, stretch_bytes;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
f_even = frame->data + (frame->v4l2_linesize * frame->curline);
f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height;
@@ -1040,18 +993,17 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_even_index = frame->curline * MAX_FRAME_WIDTH;
clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH;
clipmask_add = usbvision->stretch_width;
- pixel_per_line = frame->isocHeader.frameWidth;
+ pixel_per_line = frame->isoc_header.frame_width;
if (scratch_len(usbvision) < (int)pixel_per_line * 3) {
- //printk(KERN_DEBUG "out of data, need %d\n", len);
- return ParseState_Out;
+ /* printk(KERN_DEBUG "out of data, need %d\n", len); */
+ return parse_state_out;
}
- if ((frame->curline + 1) >= frame->frmheight) {
- return ParseState_NextFrame;
- }
+ if ((frame->curline + 1) >= frame->frmheight)
+ return parse_state_next_frame;
- block_split = (pixel_per_line%y_block_size) ? 1 : 0; //are some blocks splitted into different lines?
+ block_split = (pixel_per_line%y_block_size) ? 1 : 0; /* are some blocks splitted into different lines? */
y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size)
+ block_split * uv_block_size;
@@ -1061,31 +1013,27 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset
+ (4 - block_split) * sub_block_size);
- for (block = 0; block < (pixel_per_line / sub_block_size);
- block++) {
-
-
- for (pixel = 0; pixel < sub_block_size; pixel +=2) {
+ for (block = 0; block < (pixel_per_line / sub_block_size); block++) {
+ for (pixel = 0; pixel < sub_block_size; pixel += 2) {
scratch_get(usbvision, &y[0], 2);
scratch_get_extra(usbvision, &u, &u_ptr, 1);
scratch_get_extra(usbvision, &v, &v_ptr, 1);
- //I don't use the YUV_TO_RGB macro for better performance
+ /* I don't use the YUV_TO_RGB macro for better performance */
v_ = v - 128;
u_ = u - 128;
- vb = 132252 * v_;
- uvg= -53281 * u_ - 25625 * v_;
+ vb = 132252 * v_;
+ uvg = -53281 * u_ - 25625 * v_;
ur = 104595 * u_;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_even++ = y[0];
*f_even++ = v;
- }
- else {
+ } else {
y_ = 76284 * (y[0] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1121,15 +1069,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_even_index += clipmask_add;
f_even += stretch_bytes;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_even++ = y[1];
*f_even++ = u;
- }
- else {
+ } else {
y_ = 76284 * (y[1] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1167,15 +1114,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
scratch_get_extra(usbvision, &y[0], &y_ptr, 2);
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_odd++ = y[0];
*f_odd++ = v;
- }
- else {
+ } else {
y_ = 76284 * (y[0] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1211,15 +1157,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_odd_index += clipmask_add;
f_odd += stretch_bytes;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_odd++ = y[1];
*f_odd++ = u;
- }
- else {
+ } else {
y_ = 76284 * (y[1] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1256,7 +1201,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
f_odd += stretch_bytes;
}
- scratch_rm_old(usbvision,y_step[block % y_step_size] * sub_block_size);
+ scratch_rm_old(usbvision, y_step[block % y_step_size] * sub_block_size);
scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size]
* sub_block_size);
scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size]
@@ -1272,9 +1217,8 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
*pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height;
if (frame->curline >= frame->frmheight)
- return ParseState_NextFrame;
- else
- return ParseState_Continue;
+ return parse_state_next_frame;
+ return parse_state_continue;
}
/*
@@ -1288,53 +1232,43 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
static void usbvision_parse_data(struct usb_usbvision *usbvision)
{
struct usbvision_frame *frame;
- enum ParseState newstate;
+ enum parse_state newstate;
long copylen = 0;
unsigned long lock_flags;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision));
while (1) {
-
- newstate = ParseState_Out;
+ newstate = parse_state_out;
if (scratch_len(usbvision)) {
- if (frame->scanstate == ScanState_Scanning) {
+ if (frame->scanstate == scan_state_scanning) {
newstate = usbvision_find_header(usbvision);
- }
- else if (frame->scanstate == ScanState_Lines) {
- if (usbvision->isocMode == ISOC_MODE_YUV420) {
+ } else if (frame->scanstate == scan_state_lines) {
+ if (usbvision->isoc_mode == ISOC_MODE_YUV420)
newstate = usbvision_parse_lines_420(usbvision, &copylen);
- }
- else if (usbvision->isocMode == ISOC_MODE_YUV422) {
+ else if (usbvision->isoc_mode == ISOC_MODE_YUV422)
newstate = usbvision_parse_lines_422(usbvision, &copylen);
- }
- else if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ else if (usbvision->isoc_mode == ISOC_MODE_COMPRESS)
newstate = usbvision_parse_compress(usbvision, &copylen);
- }
-
}
}
- if (newstate == ParseState_Continue) {
+ if (newstate == parse_state_continue)
continue;
- }
- else if ((newstate == ParseState_NextFrame) || (newstate == ParseState_Out)) {
+ if ((newstate == parse_state_next_frame) || (newstate == parse_state_out))
break;
- }
- else {
- return; /* ParseState_EndParse */
- }
+ return; /* parse_state_end_parse */
}
- if (newstate == ParseState_NextFrame) {
- frame->grabstate = FrameState_Done;
+ if (newstate == parse_state_next_frame) {
+ frame->grabstate = frame_state_done;
do_gettimeofday(&(frame->timestamp));
frame->sequence = usbvision->frame_num;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
list_move_tail(&(frame->frame), &usbvision->outqueue);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
usbvision->frame_num++;
@@ -1344,10 +1278,9 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
PDEBUG(DBG_PARSE, "Wake up !");
wake_up_interruptible(&usbvision->wait_frame);
}
+ } else {
+ frame->grabstate = frame_state_grabbing;
}
- else
- frame->grabstate = FrameState_Grabbing;
-
/* Update the frame's uncompressed length. */
frame->scanlength += copylen;
@@ -1370,34 +1303,32 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
/* Detect and ignore errored packets */
- if (packet_stat) { // packet_stat != 0 ?????????????
+ if (packet_stat) { /* packet_stat != 0 ????????????? */
PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat);
- usbvision->isocErrCount++;
+ usbvision->isoc_err_count++;
continue;
}
/* Detect and ignore empty packets */
if (packet_len < 0) {
PDEBUG(DBG_ISOC, "error packet [%d]", i);
- usbvision->isocSkipCount++;
+ usbvision->isoc_skip_count++;
continue;
- }
- else if (packet_len == 0) { /* Frame end ????? */
+ } else if (packet_len == 0) { /* Frame end ????? */
PDEBUG(DBG_ISOC, "null packet [%d]", i);
- usbvision->isocstate=IsocState_NoFrame;
- usbvision->isocSkipCount++;
+ usbvision->isocstate = isoc_state_no_frame;
+ usbvision->isoc_skip_count++;
continue;
- }
- else if (packet_len > usbvision->isocPacketSize) {
- PDEBUG(DBG_ISOC, "packet[%d] > isocPacketSize", i);
- usbvision->isocSkipCount++;
+ } else if (packet_len > usbvision->isoc_packet_size) {
+ PDEBUG(DBG_ISOC, "packet[%d] > isoc_packet_size", i);
+ usbvision->isoc_skip_count++;
continue;
}
PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len);
- if (usbvision->isocstate==IsocState_NoFrame) { //new frame begins
- usbvision->isocstate=IsocState_InFrame;
+ if (usbvision->isocstate == isoc_state_no_frame) { /* new frame begins */
+ usbvision->isocstate = isoc_state_in_frame;
scratch_mark_header(usbvision);
usbvision_measure_bandwidth(usbvision);
PDEBUG(DBG_ISOC, "packet with header");
@@ -1412,7 +1343,6 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
* your favorite evil here.
*/
if (scratch_free(usbvision) < packet_len) {
-
usbvision->scratch_ovf_count++;
PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d",
scratch_len(usbvision), packet_len);
@@ -1422,12 +1352,13 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
/* Now we know that there is enough room in scratch buffer */
scratch_put(usbvision, packet_data, packet_len);
totlen += packet_len;
- usbvision->isocDataCount += packet_len;
- usbvision->isocPacketCount++;
+ usbvision->isoc_data_count += packet_len;
+ usbvision->isoc_packet_count++;
}
#if ENABLE_HEXDUMP
if (totlen > 0) {
static int foo;
+
if (foo < 1) {
printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
@@ -1435,16 +1366,16 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
}
}
#endif
- return totlen;
+ return totlen;
}
-static void usbvision_isocIrq(struct urb *urb)
+static void usbvision_isoc_irq(struct urb *urb)
{
- int errCode = 0;
+ int err_code = 0;
int len;
struct usb_usbvision *usbvision = urb->context;
int i;
- unsigned long startTime = jiffies;
+ unsigned long start_time = jiffies;
struct usbvision_frame **f;
/* We don't want to do anything if we are about to be removed! */
@@ -1452,18 +1383,17 @@ static void usbvision_isocIrq(struct urb *urb)
return;
/* any urb with wrong status is ignored without acknowledgement */
- if (urb->status == -ENOENT) {
+ if (urb->status == -ENOENT)
return;
- }
- f = &usbvision->curFrame;
+ f = &usbvision->cur_frame;
/* Manage streaming interruption */
- if (usbvision->streaming == Stream_Interrupt) {
- usbvision->streaming = Stream_Idle;
+ if (usbvision->streaming == stream_interrupt) {
+ usbvision->streaming = stream_idle;
if ((*f)) {
- (*f)->grabstate = FrameState_Ready;
- (*f)->scanstate = ScanState_Scanning;
+ (*f)->grabstate = frame_state_ready;
+ (*f)->scanstate = scan_state_scanning;
}
PDEBUG(DBG_IRQ, "stream interrupted");
wake_up_interruptible(&usbvision->wait_stream);
@@ -1472,35 +1402,32 @@ static void usbvision_isocIrq(struct urb *urb)
/* Copy the data received into our scratch buffer */
len = usbvision_compress_isochronous(usbvision, urb);
- usbvision->isocUrbCount++;
+ usbvision->isoc_urb_count++;
usbvision->urb_length = len;
- if (usbvision->streaming == Stream_On) {
-
+ if (usbvision->streaming == stream_on) {
/* If we collected enough data let's parse! */
- if ((scratch_len(usbvision) > USBVISION_HEADER_LENGTH) &&
- (!list_empty(&(usbvision->inqueue))) ) {
+ if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH &&
+ !list_empty(&(usbvision->inqueue))) {
if (!(*f)) {
(*f) = list_entry(usbvision->inqueue.next,
struct usbvision_frame,
frame);
}
usbvision_parse_data(usbvision);
- }
- else {
- /*If we don't have a frame
+ } else {
+ /* If we don't have a frame
we're current working on, complain */
PDEBUG(DBG_IRQ,
"received data, but no one needs it");
scratch_reset(usbvision);
}
- }
- else {
+ } else {
PDEBUG(DBG_IRQ, "received data, but no one needs it");
scratch_reset(usbvision);
}
- usbvision->timeInIrq += jiffies - startTime;
+ usbvision->time_in_irq += jiffies - start_time;
for (i = 0; i < USBVISION_URB_FRAMES; i++) {
urb->iso_frame_desc[i].status = 0;
@@ -1509,12 +1436,12 @@ static void usbvision_isocIrq(struct urb *urb)
urb->status = 0;
urb->dev = usbvision->dev;
- errCode = usb_submit_urb (urb, GFP_ATOMIC);
+ err_code = usb_submit_urb(urb, GFP_ATOMIC);
- if(errCode) {
+ if (err_code) {
dev_err(&usbvision->dev->dev,
"%s: usb_submit_urb failed: error %d\n",
- __func__, errCode);
+ __func__, err_code);
}
return;
@@ -1533,21 +1460,21 @@ static void usbvision_isocIrq(struct urb *urb)
int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
if (!USBVISION_IS_OPERATIONAL(usbvision))
return -1;
- errCode = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
0, (__u16) reg, buffer, 1, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s: failed: error %d\n", __func__, errCode);
- return errCode;
+ "%s: failed: error %d\n", __func__, err_code);
+ return err_code;
}
return buffer[0];
}
@@ -1563,179 +1490,176 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
unsigned char value)
{
- int errCode = 0;
+ int err_code = 0;
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s: failed: error %d\n", __func__, errCode);
+ "%s: failed: error %d\n", __func__, err_code);
}
- return errCode;
+ return err_code;
}
-static void usbvision_ctrlUrb_complete(struct urb *urb)
+static void usbvision_ctrl_urb_complete(struct urb *urb)
{
struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context;
PDEBUG(DBG_IRQ, "");
- usbvision->ctrlUrbBusy = 0;
- if (waitqueue_active(&usbvision->ctrlUrb_wq)) {
- wake_up_interruptible(&usbvision->ctrlUrb_wq);
- }
+ usbvision->ctrl_urb_busy = 0;
+ if (waitqueue_active(&usbvision->ctrl_urb_wq))
+ wake_up_interruptible(&usbvision->ctrl_urb_wq);
}
-static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
- unsigned char *data, int len)
+static int usbvision_write_reg_irq(struct usb_usbvision *usbvision, int address,
+ unsigned char *data, int len)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IRQ, "");
- if (len > 8) {
+ if (len > 8)
return -EFAULT;
- }
- if (usbvision->ctrlUrbBusy) {
+ if (usbvision->ctrl_urb_busy)
return -EBUSY;
- }
- usbvision->ctrlUrbBusy = 1;
-
- usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
- usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE;
- usbvision->ctrlUrbSetup.wValue = 0;
- usbvision->ctrlUrbSetup.wIndex = cpu_to_le16(address);
- usbvision->ctrlUrbSetup.wLength = cpu_to_le16(len);
- usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev,
+ usbvision->ctrl_urb_busy = 1;
+
+ usbvision->ctrl_urb_setup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ usbvision->ctrl_urb_setup.bRequest = USBVISION_OP_CODE;
+ usbvision->ctrl_urb_setup.wValue = 0;
+ usbvision->ctrl_urb_setup.wIndex = cpu_to_le16(address);
+ usbvision->ctrl_urb_setup.wLength = cpu_to_le16(len);
+ usb_fill_control_urb(usbvision->ctrl_urb, usbvision->dev,
usb_sndctrlpipe(usbvision->dev, 1),
- (unsigned char *)&usbvision->ctrlUrbSetup,
- (void *)usbvision->ctrlUrbBuffer, len,
- usbvision_ctrlUrb_complete,
+ (unsigned char *)&usbvision->ctrl_urb_setup,
+ (void *)usbvision->ctrl_urb_buffer, len,
+ usbvision_ctrl_urb_complete,
(void *)usbvision);
- memcpy(usbvision->ctrlUrbBuffer, data, len);
+ memcpy(usbvision->ctrl_urb_buffer, data, len);
- errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC);
- if (errCode < 0) {
- // error in usb_submit_urb()
- usbvision->ctrlUrbBusy = 0;
+ err_code = usb_submit_urb(usbvision->ctrl_urb, GFP_ATOMIC);
+ if (err_code < 0) {
+ /* error in usb_submit_urb() */
+ usbvision->ctrl_urb_busy = 0;
}
- PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, errCode);
- return errCode;
+ PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, err_code);
+ return err_code;
}
static int usbvision_init_compression(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- usbvision->lastIsocFrameNum = -1;
- usbvision->isocDataCount = 0;
- usbvision->isocPacketCount = 0;
- usbvision->isocSkipCount = 0;
- usbvision->comprLevel = 50;
- usbvision->lastComprLevel = -1;
- usbvision->isocUrbCount = 0;
- usbvision->requestIntra = 1;
- usbvision->isocMeasureBandwidthCount = 0;
-
- return errCode;
+ int err_code = 0;
+
+ usbvision->last_isoc_frame_num = -1;
+ usbvision->isoc_data_count = 0;
+ usbvision->isoc_packet_count = 0;
+ usbvision->isoc_skip_count = 0;
+ usbvision->compr_level = 50;
+ usbvision->last_compr_level = -1;
+ usbvision->isoc_urb_count = 0;
+ usbvision->request_intra = 1;
+ usbvision->isoc_measure_bandwidth_count = 0;
+
+ return err_code;
}
/* this function measures the used bandwidth since last call
* return: 0 : no error
- * sets usedBandwidth to 1-100 : 1-100% of full bandwidth resp. to isocPacketSize
+ * sets used_bandwidth to 1-100 : 1-100% of full bandwidth resp. to isoc_packet_size
*/
-static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision)
+static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- if (usbvision->isocMeasureBandwidthCount < 2) { // this gives an average bandwidth of 3 frames
- usbvision->isocMeasureBandwidthCount++;
- return errCode;
- }
- if ((usbvision->isocPacketSize > 0) && (usbvision->isocPacketCount > 0)) {
- usbvision->usedBandwidth = usbvision->isocDataCount /
- (usbvision->isocPacketCount + usbvision->isocSkipCount) *
- 100 / usbvision->isocPacketSize;
- }
- usbvision->isocMeasureBandwidthCount = 0;
- usbvision->isocDataCount = 0;
- usbvision->isocPacketCount = 0;
- usbvision->isocSkipCount = 0;
- return errCode;
+ int err_code = 0;
+
+ if (usbvision->isoc_measure_bandwidth_count < 2) { /* this gives an average bandwidth of 3 frames */
+ usbvision->isoc_measure_bandwidth_count++;
+ return err_code;
+ }
+ if ((usbvision->isoc_packet_size > 0) && (usbvision->isoc_packet_count > 0)) {
+ usbvision->used_bandwidth = usbvision->isoc_data_count /
+ (usbvision->isoc_packet_count + usbvision->isoc_skip_count) *
+ 100 / usbvision->isoc_packet_size;
+ }
+ usbvision->isoc_measure_bandwidth_count = 0;
+ usbvision->isoc_data_count = 0;
+ usbvision->isoc_packet_count = 0;
+ usbvision->isoc_skip_count = 0;
+ return err_code;
}
-static int usbvision_adjust_compression (struct usb_usbvision *usbvision)
+static int usbvision_adjust_compression(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[6];
PDEBUG(DBG_IRQ, "");
- if ((adjustCompression) && (usbvision->usedBandwidth > 0)) {
- usbvision->comprLevel += (usbvision->usedBandwidth - 90) / 2;
- RESTRICT_TO_RANGE(usbvision->comprLevel, 0, 100);
- if (usbvision->comprLevel != usbvision->lastComprLevel) {
- int distorsion;
- if (usbvision->bridgeType == BRIDGE_NT1004 || usbvision->bridgeType == BRIDGE_NT1005) {
- buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM Threshold 1
- buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM Threshold 2
- distorsion = 7 + 248 * usbvision->comprLevel / 100;
- buffer[2] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (inter)
- buffer[3] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (intra)
- distorsion = 1 + 42 * usbvision->comprLevel / 100;
- buffer[4] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (inter)
- buffer[5] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (intra)
- }
- else { //BRIDGE_NT1003
- buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM threshold 1
- buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM threshold 2
- distorsion = 2 + 253 * usbvision->comprLevel / 100;
- buffer[2] = (unsigned char)(distorsion & 0xFF); // distorsion threshold bit0-7
- buffer[3] = 0; //(unsigned char)((distorsion >> 8) & 0x0F); // distorsion threshold bit 8-11
- distorsion = 0 + 43 * usbvision->comprLevel / 100;
- buffer[4] = (unsigned char)(distorsion & 0xFF); // maximum distorsion bit0-7
- buffer[5] = 0; //(unsigned char)((distorsion >> 8) & 0x01); // maximum distorsion bit 8
+ if ((adjust_compression) && (usbvision->used_bandwidth > 0)) {
+ usbvision->compr_level += (usbvision->used_bandwidth - 90) / 2;
+ RESTRICT_TO_RANGE(usbvision->compr_level, 0, 100);
+ if (usbvision->compr_level != usbvision->last_compr_level) {
+ int distortion;
+
+ if (usbvision->bridge_type == BRIDGE_NT1004 || usbvision->bridge_type == BRIDGE_NT1005) {
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM Threshold 1 */
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM Threshold 2 */
+ distortion = 7 + 248 * usbvision->compr_level / 100;
+ buffer[2] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (inter) */
+ buffer[3] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (intra) */
+ distortion = 1 + 42 * usbvision->compr_level / 100;
+ buffer[4] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (inter) */
+ buffer[5] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (intra) */
+ } else { /* BRIDGE_NT1003 */
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM threshold 1 */
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM threshold 2 */
+ distortion = 2 + 253 * usbvision->compr_level / 100;
+ buffer[2] = (unsigned char)(distortion & 0xFF); /* distortion threshold bit0-7 */
+ buffer[3] = 0; /* (unsigned char)((distortion >> 8) & 0x0F); distortion threshold bit 8-11 */
+ distortion = 0 + 43 * usbvision->compr_level / 100;
+ buffer[4] = (unsigned char)(distortion & 0xFF); /* maximum distortion bit0-7 */
+ buffer[5] = 0; /* (unsigned char)((distortion >> 8) & 0x01); maximum distortion bit 8 */
}
- errCode = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
- if (errCode == 0){
+ err_code = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
+ if (err_code == 0) {
PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0],
buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
- usbvision->lastComprLevel = usbvision->comprLevel;
+ usbvision->last_compr_level = usbvision->compr_level;
}
}
}
- return errCode;
+ return err_code;
}
-static int usbvision_request_intra (struct usb_usbvision *usbvision)
+static int usbvision_request_intra(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
PDEBUG(DBG_IRQ, "");
- usbvision->requestIntra = 1;
+ usbvision->request_intra = 1;
buffer[0] = 1;
usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
- return errCode;
+ return err_code;
}
-static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
+static int usbvision_unrequest_intra(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
PDEBUG(DBG_IRQ, "");
- usbvision->requestIntra = 0;
+ usbvision->request_intra = 0;
buffer[0] = 0;
usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
- return errCode;
+ return err_code;
}
/*******************************
@@ -1744,16 +1668,15 @@ static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
int usbvision_power_off(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_FUNC, "");
- errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
- if (errCode == 1) {
+ err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+ if (err_code == 1)
usbvision->power = 0;
- }
- PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode!=1)?"ERROR":"power is off", errCode);
- return errCode;
+ PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code != 1) ? "ERROR" : "power is off", err_code);
+ return err_code;
}
/*
@@ -1769,7 +1692,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- PDEBUG(DBG_FUNC, "isocMode %#02x", format);
+ PDEBUG(DBG_FUNC, "isoc_mode %#02x", format);
if ((format != ISOC_MODE_YUV422)
&& (format != ISOC_MODE_YUV420)
@@ -1778,8 +1701,8 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
format);
format = ISOC_MODE_YUV420;
}
- value[0] = 0x0A; //TODO: See the effect of the filter
- value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
+ value[0] = 0x0A; /* TODO: See the effect of the filter */
+ 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 |
@@ -1790,7 +1713,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - "
"reconnect or reload driver.\n", proc, rc);
}
- usbvision->isocMode = format;
+ usbvision->isoc_mode = format;
return rc;
}
@@ -1802,96 +1725,88 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
int usbvision_set_output(struct usb_usbvision *usbvision, int width,
int height)
{
- int errCode = 0;
- int UsbWidth, UsbHeight;
- unsigned int frameRate=0, frameDrop=0;
+ int err_code = 0;
+ int usb_width, usb_height;
+ unsigned int frame_rate = 0, frame_drop = 0;
unsigned char value[4];
- if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- }
if (width > MAX_USB_WIDTH) {
- UsbWidth = width / 2;
+ usb_width = width / 2;
usbvision->stretch_width = 2;
- }
- else {
- UsbWidth = width;
+ } else {
+ usb_width = width;
usbvision->stretch_width = 1;
}
if (height > MAX_USB_HEIGHT) {
- UsbHeight = height / 2;
+ usb_height = height / 2;
usbvision->stretch_height = 2;
- }
- else {
- UsbHeight = height;
+ } else {
+ usb_height = height;
usbvision->stretch_height = 1;
}
- RESTRICT_TO_RANGE(UsbWidth, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
- UsbWidth &= ~(MIN_FRAME_WIDTH-1);
- RESTRICT_TO_RANGE(UsbHeight, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
- UsbHeight &= ~(1);
+ RESTRICT_TO_RANGE(usb_width, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
+ usb_width &= ~(MIN_FRAME_WIDTH-1);
+ RESTRICT_TO_RANGE(usb_height, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
+ usb_height &= ~(1);
PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d",
- UsbWidth, UsbHeight, width, height,
+ usb_width, usb_height, width, height,
usbvision->stretch_width, usbvision->stretch_height);
/* I'll not rewrite the same values */
- if ((UsbWidth != usbvision->curwidth) || (UsbHeight != usbvision->curheight)) {
- value[0] = UsbWidth & 0xff; //LSB
- value[1] = (UsbWidth >> 8) & 0x03; //MSB
- value[2] = UsbHeight & 0xff; //LSB
- value[3] = (UsbHeight >> 8) & 0x03; //MSB
+ if ((usb_width != usbvision->curwidth) || (usb_height != usbvision->curheight)) {
+ value[0] = usb_width & 0xff; /* LSB */
+ value[1] = (usb_width >> 8) & 0x03; /* MSB */
+ value[2] = usb_height & 0xff; /* LSB */
+ value[3] = (usb_height >> 8) & 0x03; /* MSB */
- errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s failed: error %d\n", __func__, errCode);
- return errCode;
+ "%s failed: error %d\n", __func__, err_code);
+ return err_code;
}
- usbvision->curwidth = usbvision->stretch_width * UsbWidth;
- usbvision->curheight = usbvision->stretch_height * UsbHeight;
+ usbvision->curwidth = usbvision->stretch_width * usb_width;
+ usbvision->curheight = usbvision->stretch_height * usb_height;
}
- if (usbvision->isocMode == ISOC_MODE_YUV422) {
- frameRate = (usbvision->isocPacketSize * 1000) / (UsbWidth * UsbHeight * 2);
- }
- else if (usbvision->isocMode == ISOC_MODE_YUV420) {
- frameRate = (usbvision->isocPacketSize * 1000) / ((UsbWidth * UsbHeight * 12) / 8);
- }
- else {
- frameRate = FRAMERATE_MAX;
- }
+ if (usbvision->isoc_mode == ISOC_MODE_YUV422)
+ frame_rate = (usbvision->isoc_packet_size * 1000) / (usb_width * usb_height * 2);
+ else if (usbvision->isoc_mode == ISOC_MODE_YUV420)
+ frame_rate = (usbvision->isoc_packet_size * 1000) / ((usb_width * usb_height * 12) / 8);
+ else
+ frame_rate = FRAMERATE_MAX;
- if (usbvision->tvnormId & V4L2_STD_625_50) {
- frameDrop = frameRate * 32 / 25 - 1;
- }
- else if (usbvision->tvnormId & V4L2_STD_525_60) {
- frameDrop = frameRate * 32 / 30 - 1;
- }
+ if (usbvision->tvnorm_id & V4L2_STD_625_50)
+ frame_drop = frame_rate * 32 / 25 - 1;
+ else if (usbvision->tvnorm_id & V4L2_STD_525_60)
+ frame_drop = frame_rate * 32 / 30 - 1;
- RESTRICT_TO_RANGE(frameDrop, FRAMERATE_MIN, FRAMERATE_MAX);
+ RESTRICT_TO_RANGE(frame_drop, FRAMERATE_MIN, FRAMERATE_MAX);
- PDEBUG(DBG_FUNC, "frameRate %d fps, frameDrop %d", frameRate, frameDrop);
+ PDEBUG(DBG_FUNC, "frame_rate %d fps, frame_drop %d", frame_rate, frame_drop);
- frameDrop = FRAMERATE_MAX; // We can allow the maximum here, because dropping is controlled
+ frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
- /* frameDrop = 7; => framePhase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
- => frameSkip = 4;
- => frameRate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
+ /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
+ => frame_skip = 4;
+ => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
- frameDrop = 9; => framePhase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
- => frameSkip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
- => frameRate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
+ frame_drop = 9; => frame_phase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
+ => frame_skip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
+ => frame_rate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
*/
- errCode = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frameDrop);
- return errCode;
+ err_code = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frame_drop);
+ return err_code;
}
@@ -1903,8 +1818,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
{
int i;
- /*needs to be page aligned cause the buffers can be mapped individually! */
- usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
+ /* needs to be page aligned cause the buffers can be mapped individually! */
+ usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
usbvision->curheight *
usbvision->palette.bytes_per_pixel);
@@ -1912,9 +1827,9 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
usbvision->num_frames = number_of_frames;
while (usbvision->num_frames > 0) {
usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
- if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+ usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+ if (usbvision->fbuf)
break;
- }
usbvision->num_frames--;
}
@@ -1925,7 +1840,7 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
/* Allocate all buffers */
for (i = 0; i < usbvision->num_frames; i++) {
usbvision->frame[i].index = i;
- usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].grabstate = frame_state_unused;
usbvision->frame[i].data = usbvision->fbuf +
i * usbvision->max_frame_size;
/*
@@ -1937,7 +1852,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
usbvision->frame[i].height = usbvision->curheight;
usbvision->frame[i].bytes_read = 0;
}
- PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+ PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",
+ usbvision->num_frames, usbvision->max_frame_size);
return usbvision->num_frames;
}
@@ -1948,7 +1864,7 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
void usbvision_frames_free(struct usb_usbvision *usbvision)
{
/* Have to free all that memory */
- PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+ PDEBUG(DBG_FUNC, "free %d frames", usbvision->num_frames);
if (usbvision->fbuf != NULL) {
usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
@@ -1969,7 +1885,7 @@ void usbvision_empty_framequeues(struct usb_usbvision *usbvision)
INIT_LIST_HEAD(&(usbvision->outqueue));
for (i = 0; i < USBVISION_NUMFRAMES; i++) {
- usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].grabstate = frame_state_unused;
usbvision->frame[i].bytes_read = 0;
}
}
@@ -1984,9 +1900,9 @@ int usbvision_stream_interrupt(struct usb_usbvision *usbvision)
/* stop reading from the device */
- usbvision->streaming = Stream_Interrupt;
+ usbvision->streaming = stream_interrupt;
ret = wait_event_timeout(usbvision->wait_stream,
- (usbvision->streaming == Stream_Idle),
+ (usbvision->streaming == stream_idle),
msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES));
return ret;
}
@@ -2002,19 +1918,19 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
int rc;
unsigned char value[6];
- value[0] = 0x0F; // Intra-Compression cycle
- value[1] = 0x01; // Reg.45 one line per strip
- value[2] = 0x00; // Reg.46 Force intra mode on all new frames
- value[3] = 0x00; // Reg.47 FORCE_UP <- 0 normal operation (not force)
- value[4] = 0xA2; // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode.
- value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression
-
- //catched values for NT1004
- // value[0] = 0xFF; // Never apply intra mode automatically
- // value[1] = 0xF1; // Use full frame height for virtual strip width; One line per strip
- // value[2] = 0x01; // Force intra mode on all new frames
- // value[3] = 0x00; // Strip size 400 Bytes; do not force up
- // value[4] = 0xA2; //
+ value[0] = 0x0F; /* Intra-Compression cycle */
+ value[1] = 0x01; /* Reg.45 one line per strip */
+ value[2] = 0x00; /* Reg.46 Force intra mode on all new frames */
+ value[3] = 0x00; /* Reg.47 FORCE_UP <- 0 normal operation (not force) */
+ value[4] = 0xA2; /* Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. */
+ value[5] = 0x00; /* Reg.49 DVI_YUV This has nothing to do with compression */
+
+ /* catched values for NT1004 */
+ /* value[0] = 0xFF; Never apply intra mode automatically */
+ /* value[1] = 0xF1; Use full frame height for virtual strip width; One line per strip */
+ /* value[2] = 0x01; Force intra mode on all new frames */
+ /* value[3] = 0x00; Strip size 400 Bytes; do not force up */
+ /* value[4] = 0xA2; */
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
@@ -2030,21 +1946,20 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
return rc;
}
- if (usbvision->bridgeType == BRIDGE_NT1004) {
- value[0] = 20; // PCM Threshold 1
- value[1] = 12; // PCM Threshold 2
- value[2] = 255; // Distorsion Threshold inter
- value[3] = 255; // Distorsion Threshold intra
- value[4] = 43; // Max Distorsion inter
- value[5] = 43; // Max Distorsion intra
- }
- else {
- value[0] = 20; // PCM Threshold 1
- value[1] = 12; // PCM Threshold 2
- value[2] = 255; // Distorsion Threshold d7-d0
- value[3] = 0; // Distorsion Threshold d11-d8
- value[4] = 43; // Max Distorsion d7-d0
- value[5] = 0; // Max Distorsion d8
+ if (usbvision->bridge_type == BRIDGE_NT1004) {
+ value[0] = 20; /* PCM Threshold 1 */
+ value[1] = 12; /* PCM Threshold 2 */
+ value[2] = 255; /* Distortion Threshold inter */
+ value[3] = 255; /* Distortion Threshold intra */
+ value[4] = 43; /* Max Distortion inter */
+ value[5] = 43; /* Max Distortion intra */
+ } else {
+ value[0] = 20; /* PCM Threshold 1 */
+ value[1] = 12; /* PCM Threshold 2 */
+ value[2] = 255; /* Distortion Threshold d7-d0 */
+ value[3] = 0; /* Distortion Threshold d11-d8 */
+ value[4] = 43; /* Max Distortion d7-d0 */
+ value[5] = 0; /* Max Distortion d8 */
}
if (!USBVISION_IS_OPERATIONAL(usbvision))
@@ -2059,10 +1974,7 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
if (rc < 0) {
printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
"reconnect or reload driver.\n", proc, rc);
- return rc;
}
-
-
return rc;
}
@@ -2085,9 +1997,9 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
return 0;
/* Set input format expected from decoder*/
- if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) {
- value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1;
- } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+ if (usbvision_device_data[usbvision->dev_model].vin_reg1_override) {
+ value[0] = usbvision_device_data[usbvision->dev_model].vin_reg1;
+ } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) {
/* SAA7113 uses 8 bit output */
value[0] = USBVISION_8_422_SYNC;
} else {
@@ -2105,53 +2017,53 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
}
- if (usbvision->tvnormId & V4L2_STD_PAL) {
+ if (usbvision->tvnorm_id & V4L2_STD_PAL) {
value[0] = 0xC0;
- value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */
value[2] = 0x20;
- value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */
value[4] = 0x60;
- value[5] = 0x00; //0x0060 -> 96 Input video h offset
+ value[5] = 0x00; /* 0x0060 -> 96 Input video h offset */
value[6] = 0x16;
- value[7] = 0x00; //0x0016 -> 22 Input video v offset
- } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
+ value[7] = 0x00; /* 0x0016 -> 22 Input video v offset */
+ } else if (usbvision->tvnorm_id & V4L2_STD_SECAM) {
value[0] = 0xC0;
- value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */
value[2] = 0x20;
- value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */
value[4] = 0x01;
- value[5] = 0x00; //0x0001 -> 01 Input video h offset
+ value[5] = 0x00; /* 0x0001 -> 01 Input video h offset */
value[6] = 0x01;
- value[7] = 0x00; //0x0001 -> 01 Input video v offset
+ value[7] = 0x00; /* 0x0001 -> 01 Input video v offset */
} else { /* V4L2_STD_NTSC */
value[0] = 0xD0;
- value[1] = 0x02; //0x02D0 -> 720 Input video line length
+ value[1] = 0x02; /* 0x02D0 -> 720 Input video line length */
value[2] = 0xF0;
- value[3] = 0x00; //0x00F0 -> 240 Input video number of lines
+ value[3] = 0x00; /* 0x00F0 -> 240 Input video number of lines */
value[4] = 0x50;
- value[5] = 0x00; //0x0050 -> 80 Input video h offset
+ value[5] = 0x00; /* 0x0050 -> 80 Input video h offset */
value[6] = 0x10;
- value[7] = 0x00; //0x0010 -> 16 Input video v offset
+ value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
}
- if (usbvision_device_data[usbvision->DevModel].X_Offset >= 0) {
- value[4]=usbvision_device_data[usbvision->DevModel].X_Offset & 0xff;
- value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
+ if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
+ value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
+ value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
}
- if (adjust_X_Offset != -1) {
- value[4] = adjust_X_Offset & 0xff;
- value[5] = (adjust_X_Offset & 0x0300) >> 8;
+ if (adjust_x_offset != -1) {
+ value[4] = adjust_x_offset & 0xff;
+ value[5] = (adjust_x_offset & 0x0300) >> 8;
}
- if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
- value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
- value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
+ if (usbvision_device_data[usbvision->dev_model].y_offset >= 0) {
+ value[6] = usbvision_device_data[usbvision->dev_model].y_offset & 0xff;
+ value[7] = (usbvision_device_data[usbvision->dev_model].y_offset & 0x0300) >> 8;
}
- if (adjust_Y_Offset != -1) {
- value[6] = adjust_Y_Offset & 0xff;
- value[7] = (adjust_Y_Offset & 0x0300) >> 8;
+ if (adjust_y_offset != -1) {
+ value[6] = adjust_y_offset & 0xff;
+ value[7] = (adjust_y_offset & 0x0300) >> 8;
}
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
@@ -2167,15 +2079,14 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */
- if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){
- dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv;
- }
- else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
- /* This changes as the fine sync control changes. Further investigation necessary */
+ if (usbvision_device_data[usbvision->dev_model].dvi_yuv_override) {
+ dvi_yuv_value = usbvision_device_data[usbvision->dev_model].dvi_yuv;
+ } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) {
+ /* This changes as the fine sync control changes. Further investigation necessary */
dvi_yuv_value = 0x06;
}
- return (usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value));
+ return usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value);
}
@@ -2192,7 +2103,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
int rc;
unsigned char value[8];
- if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ if (usbvision->isoc_mode == ISOC_MODE_COMPRESS) {
value[0] = 0x42;
value[1] = 0x71;
value[2] = 0xff;
@@ -2201,11 +2112,10 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
value[5] = 0xe0;
value[6] = 0x71;
value[7] = 0xff;
- // UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte)
- // FDL: 0x00000-0x0E099 = 57498 Words
- // VDW: 0x0E3FF-0x3FFFF
- }
- else {
+ /* UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte) */
+ /* FDL: 0x00000-0x0E099 = 57498 Words */
+ /* VDW: 0x0E3FF-0x3FFFF */
+ } else {
value[0] = 0x42;
value[1] = 0x00;
value[2] = 0xff;
@@ -2218,14 +2128,14 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
/* These are the values of the address of the video buffer,
* they have to be loaded into the USBVISION_DRM_PRM1-8
*
- * Start address of video output buffer for read: drm_prm1-2 -> 0x00000
- * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff
- * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000
+ * Start address of video output buffer for read: drm_prm1-2 -> 0x00000
+ * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff
+ * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000
* Only used in compressed mode
- * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff
+ * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff
* Only used in compressed mode
- * Start address of video output buffer for write: drm_prm1-7 -> 0x00000
- * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff
+ * Start address of video output buffer for write: drm_prm1-7 -> 0x00000
+ * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff
*/
if (!USBVISION_IS_OPERATIONAL(usbvision))
@@ -2243,8 +2153,9 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
}
/* Restart the video buffer logic */
- if ((rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
- USBVISION_RES_FDL | USBVISION_RES_VDW)) < 0)
+ rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
+ USBVISION_RES_FDL | USBVISION_RES_VDW);
+ if (rc < 0)
return rc;
rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00);
@@ -2261,23 +2172,22 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
int usbvision_power_on(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_FUNC, "");
usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_RES2);
+ USBVISION_SSPND_EN | USBVISION_RES2);
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID);
- errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
- if (errCode == 1) {
+ USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
+ if (err_code == 1)
usbvision->power = 1;
- }
- PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode<0)?"ERROR":"power is on", errCode);
- return errCode;
+ PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code < 0) ? "ERROR" : "power is on", err_code);
+ return err_code;
}
@@ -2285,53 +2195,50 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
* usbvision timer stuff
*/
-// to call usbvision_power_off from task queue
+/* to call usbvision_power_off from task queue */
static void call_usbvision_power_off(struct work_struct *work)
{
- struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
+ struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, power_off_work);
PDEBUG(DBG_FUNC, "");
- if(mutex_lock_interruptible(&usbvision->lock)) {
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
return;
- }
-
- if(usbvision->user == 0) {
+ if (usbvision->user == 0) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
+ mutex_unlock(&usbvision->v4l2_lock);
}
-static void usbvision_powerOffTimer(unsigned long data)
+static void usbvision_power_off_timer(unsigned long data)
{
- struct usb_usbvision *usbvision = (void *) data;
+ struct usb_usbvision *usbvision = (void *)data;
PDEBUG(DBG_FUNC, "");
- del_timer(&usbvision->powerOffTimer);
- INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
- (void) schedule_work(&usbvision->powerOffWork);
+ del_timer(&usbvision->power_off_timer);
+ INIT_WORK(&usbvision->power_off_work, call_usbvision_power_off);
+ (void) schedule_work(&usbvision->power_off_work);
}
-void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_init_power_off_timer(struct usb_usbvision *usbvision)
{
- init_timer(&usbvision->powerOffTimer);
- usbvision->powerOffTimer.data = (long) usbvision;
- usbvision->powerOffTimer.function = usbvision_powerOffTimer;
+ init_timer(&usbvision->power_off_timer);
+ usbvision->power_off_timer.data = (long)usbvision;
+ usbvision->power_off_timer.function = usbvision_power_off_timer;
}
-void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_set_power_off_timer(struct usb_usbvision *usbvision)
{
- mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME);
+ mod_timer(&usbvision->power_off_timer, jiffies + USBVISION_POWEROFF_TIME);
}
-void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision)
{
- if (timer_pending(&usbvision->powerOffTimer)) {
- del_timer(&usbvision->powerOffTimer);
- }
+ if (timer_pending(&usbvision->power_off_timer))
+ del_timer(&usbvision->power_off_timer);
}
/*
@@ -2341,14 +2248,10 @@ void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
*/
int usbvision_begin_streaming(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ if (usbvision->isoc_mode == ISOC_MODE_COMPRESS)
usbvision_init_compression(usbvision);
- }
- errCode = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, USBVISION_NOHVALID |
- usbvision->Vin_Reg2_Preset);
- return errCode;
+ return usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ USBVISION_NOHVALID | usbvision->vin_reg2_preset);
}
/*
@@ -2360,25 +2263,24 @@ int usbvision_restart_isoc(struct usb_usbvision *usbvision)
{
int ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID)) < 0)
+ ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ if (ret < 0)
return ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID |
- USBVISION_RES2)) < 0)
+ USBVISION_RES2);
+ if (ret < 0)
return ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ ret = usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
USBVISION_KEEP_BLANK | USBVISION_NOHVALID |
- usbvision->Vin_Reg2_Preset)) < 0) return ret;
+ usbvision->vin_reg2_preset);
+ if (ret < 0)
+ return ret;
/* TODO: schedule timeout */
- while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1);
+ while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1)
+ ;
return 0;
}
@@ -2386,27 +2288,27 @@ int usbvision_restart_isoc(struct usb_usbvision *usbvision)
int usbvision_audio_off(struct usb_usbvision *usbvision)
{
if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) {
- printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n");
+ printk(KERN_ERR "usbvision_audio_off: can't write reg\n");
return -1;
}
- usbvision->AudioMute = 0;
- usbvision->AudioChannel = USBVISION_AUDIO_MUTE;
+ usbvision->audio_mute = 0;
+ usbvision->audio_channel = USBVISION_AUDIO_MUTE;
return 0;
}
-int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel)
+int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
{
- if (!usbvision->AudioMute) {
- if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) {
+ if (!usbvision->audio_mute) {
+ if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, audio_channel) < 0) {
printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n");
return -1;
}
}
- usbvision->AudioChannel = AudioChannel;
+ usbvision->audio_channel = audio_channel;
return 0;
}
-int usbvision_setup(struct usb_usbvision *usbvision,int format)
+int usbvision_setup(struct usb_usbvision *usbvision, int format)
{
usbvision_set_video_format(usbvision, format);
usbvision_set_dram_settings(usbvision);
@@ -2421,27 +2323,28 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format)
int usbvision_set_alternate(struct usb_usbvision *dev)
{
- int errCode, prev_alt = dev->ifaceAlt;
+ int err_code, prev_alt = dev->iface_alt;
int i;
- dev->ifaceAlt=0;
- for(i=0;i< dev->num_alt; i++)
- if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->ifaceAlt])
- dev->ifaceAlt=i;
-
- if (dev->ifaceAlt != prev_alt) {
- dev->isocPacketSize = dev->alt_max_pkt_size[dev->ifaceAlt];
- PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
- errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
- if (errCode < 0) {
+ dev->iface_alt = 0;
+ for (i = 0; i < dev->num_alt; i++)
+ if (dev->alt_max_pkt_size[i] > dev->alt_max_pkt_size[dev->iface_alt])
+ dev->iface_alt = i;
+
+ if (dev->iface_alt != prev_alt) {
+ dev->isoc_packet_size = dev->alt_max_pkt_size[dev->iface_alt];
+ PDEBUG(DBG_FUNC, "setting alternate %d with max_packet_size=%u",
+ dev->iface_alt, dev->isoc_packet_size);
+ err_code = usb_set_interface(dev->dev, dev->iface, dev->iface_alt);
+ if (err_code < 0) {
dev_err(&dev->dev->dev,
"cannot change alternate number to %d (error=%i)\n",
- dev->ifaceAlt, errCode);
- return errCode;
+ dev->iface_alt, err_code);
+ return err_code;
}
}
- PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isocPacketSize);
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isoc_packet_size);
return 0;
}
@@ -2453,27 +2356,27 @@ int usbvision_set_alternate(struct usb_usbvision *dev)
int usbvision_init_isoc(struct usb_usbvision *usbvision)
{
struct usb_device *dev = usbvision->dev;
- int bufIdx, errCode, regValue;
+ int buf_idx, err_code, reg_value;
int sb_size;
if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT;
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
scratch_reset(usbvision);
/* Alternate interface 1 is is the biggest frame size */
- errCode = usbvision_set_alternate(usbvision);
- if (errCode < 0) {
- usbvision->last_error = errCode;
+ err_code = usbvision_set_alternate(usbvision);
+ if (err_code < 0) {
+ usbvision->last_error = err_code;
return -EBUSY;
}
- sb_size = USBVISION_URB_FRAMES * usbvision->isocPacketSize;
+ sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size;
- regValue = (16 - usbvision_read_reg(usbvision,
+ reg_value = (16 - usbvision_read_reg(usbvision,
USBVISION_ALTER_REG)) & 0x0F;
- usbvision->usb_bandwidth = regValue >> 1;
+ usbvision->usb_bandwidth = reg_value >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec",
usbvision->usb_bandwidth);
@@ -2481,7 +2384,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
/* We double buffer the Iso lists */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
int j, k;
struct urb *urb;
@@ -2491,8 +2394,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
"%s: usb_alloc_urb() failed\n", __func__);
return -ENOMEM;
}
- usbvision->sbuf[bufIdx].urb = urb;
- usbvision->sbuf[bufIdx].data =
+ usbvision->sbuf[buf_idx].urb = urb;
+ usbvision->sbuf[buf_idx].data =
usb_alloc_coherent(usbvision->dev,
sb_size,
GFP_KERNEL,
@@ -2502,31 +2405,31 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = 1;
- urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
- urb->complete = usbvision_isocIrq;
+ urb->transfer_buffer = usbvision->sbuf[buf_idx].data;
+ urb->complete = usbvision_isoc_irq;
urb->number_of_packets = USBVISION_URB_FRAMES;
urb->transfer_buffer_length =
- usbvision->isocPacketSize * USBVISION_URB_FRAMES;
+ usbvision->isoc_packet_size * USBVISION_URB_FRAMES;
for (j = k = 0; j < USBVISION_URB_FRAMES; j++,
- k += usbvision->isocPacketSize) {
+ k += usbvision->isoc_packet_size) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length =
- usbvision->isocPacketSize;
+ usbvision->isoc_packet_size;
}
}
/* Submit all URBs */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
+ err_code = usb_submit_urb(usbvision->sbuf[buf_idx].urb,
GFP_KERNEL);
- if (errCode) {
+ if (err_code) {
dev_err(&usbvision->dev->dev,
"%s: usb_submit_urb(%d) failed: error %d\n",
- __func__, bufIdx, errCode);
+ __func__, buf_idx, err_code);
}
}
- usbvision->streaming = Stream_Idle;
+ usbvision->streaming = stream_idle;
PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x",
__func__,
usbvision->video_endp);
@@ -2542,47 +2445,46 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
*/
void usbvision_stop_isoc(struct usb_usbvision *usbvision)
{
- int bufIdx, errCode, regValue;
- int sb_size = USBVISION_URB_FRAMES * usbvision->isocPacketSize;
+ int buf_idx, err_code, reg_value;
+ int sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size;
- if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL))
+ if ((usbvision->streaming == stream_off) || (usbvision->dev == NULL))
return;
/* Unschedule all of the iso td's */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- usb_kill_urb(usbvision->sbuf[bufIdx].urb);
- if (usbvision->sbuf[bufIdx].data){
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
+ usb_kill_urb(usbvision->sbuf[buf_idx].urb);
+ if (usbvision->sbuf[buf_idx].data) {
usb_free_coherent(usbvision->dev,
sb_size,
- usbvision->sbuf[bufIdx].data,
- usbvision->sbuf[bufIdx].urb->transfer_dma);
+ usbvision->sbuf[buf_idx].data,
+ usbvision->sbuf[buf_idx].urb->transfer_dma);
}
- usb_free_urb(usbvision->sbuf[bufIdx].urb);
- usbvision->sbuf[bufIdx].urb = NULL;
+ usb_free_urb(usbvision->sbuf[buf_idx].urb);
+ usbvision->sbuf[buf_idx].urb = NULL;
}
- PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
- usbvision->streaming = Stream_Off;
+ PDEBUG(DBG_ISOC, "%s: streaming=stream_off\n", __func__);
+ usbvision->streaming = stream_off;
if (!usbvision->remove_pending) {
-
/* Set packet size to 0 */
- usbvision->ifaceAlt=0;
- errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAlt);
- if (errCode < 0) {
+ usbvision->iface_alt = 0;
+ err_code = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->iface_alt);
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
"%s: usb_set_interface() failed: error %d\n",
- __func__, errCode);
- usbvision->last_error = errCode;
+ __func__, err_code);
+ usbvision->last_error = err_code;
}
- regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
- usbvision->isocPacketSize =
- (regValue == 0) ? 0 : (regValue * 64) - 1;
+ reg_value = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+ usbvision->isoc_packet_size =
+ (reg_value == 0) ? 0 : (reg_value * 64) - 1;
PDEBUG(DBG_ISOC, "ISO Packet Length:%d",
- usbvision->isocPacketSize);
+ usbvision->isoc_packet_size);
- usbvision->usb_bandwidth = regValue >> 1;
+ usbvision->usb_bandwidth = reg_value >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec",
usbvision->usb_bandwidth);
}
@@ -2592,39 +2494,38 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
{
/* 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};
- //channel 0 is TV with audiochannel 1 (tuner mono)
- //channel 1 is Composite with audio channel 0 (line in)
- //channel 2 is S-Video with audio channel 0 (line in)
- //channel 3 is additional video inputs to the device with audio channel 0 (line in)
+ int mode[4] = { SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3 };
+ int audio[] = { 1, 0, 0, 0 };
+ /* channel 0 is TV with audiochannel 1 (tuner mono) */
+ /* channel 1 is Composite with audio channel 0 (line in) */
+ /* channel 2 is S-Video with audio channel 0 (line in) */
+ /* channel 3 is additional video inputs to the device with audio channel 0 (line in) */
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
- // set the new channel
- // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
- // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red
-
- switch (usbvision_device_data[usbvision->DevModel].Codec) {
- case CODEC_SAA7113:
- 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] = SAA7115_SVIDEO1;
- }
- break;
- case CODEC_SAA7111:
- default:
- /* modes for saa7111 */
- mode[1] = SAA7115_COMPOSITE1;
+ /* set the new channel */
+ /* Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video */
+ /* Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red */
+
+ switch (usbvision_device_data[usbvision->dev_model].codec) {
+ case CODEC_SAA7113:
+ mode[1] = SAA7115_COMPOSITE2;
+ if (switch_svideo_input) {
+ /* To handle problems with S-Video Input for
+ * some devices. Use switch_svideo_input
+ * parameter when loading the module.*/
+ mode[2] = SAA7115_COMPOSITE1;
+ } else {
mode[2] = SAA7115_SVIDEO1;
- break;
+ }
+ break;
+ case CODEC_SAA7111:
+ default:
+ /* modes for saa7111 */
+ mode[1] = SAA7115_COMPOSITE1;
+ mode[2] = SAA7115_SVIDEO1;
+ break;
}
call_all(usbvision, video, s_routing, mode[channel], 0, 0);
usbvision_set_audio(usbvision, audio[channel]);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index e3bbae26e3ce..05b1344181cd 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -28,18 +28,18 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include "usbvision.h"
-#define DBG_I2C 1<<0
+#define DBG_I2C (1 << 0)
static int i2c_debug;
-module_param (i2c_debug, int, 0644); // debug_i2c_usb mode of the device driver
+module_param(i2c_debug, int, 0644); /* debug_i2c_usb mode of the device driver */
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
#define PDEBUG(level, fmt, args...) { \
@@ -72,8 +72,8 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap,
udelay(10);
}
if (i) {
- PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
- PDEBUG(DBG_I2C,"Maybe there's no device at this address");
+ PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_I2C, "Maybe there's no device at this address");
}
return ret;
}
@@ -96,8 +96,8 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap,
udelay(10);
}
if (i) {
- PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
- PDEBUG(DBG_I2C,"Maybe there's no device at this address");
+ PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_I2C, "Maybe there's no device at this address");
}
return ret;
}
@@ -143,9 +143,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
else
ret = try_write_address(i2c_adap, addr, retries);
- if (ret != 1) {
+ if (ret != 1)
return -EREMOTEIO;
- }
}
return 0;
}
@@ -164,22 +163,20 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
pmsg = &msgs[i];
ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr);
if (ret != 0) {
- PDEBUG(DBG_I2C,"got NAK from device, message #%d", i);
+ PDEBUG(DBG_I2C, "got NAK from device, message #%d", i);
return (ret < 0) ? ret : -EREMOTEIO;
}
if (pmsg->flags & I2C_M_RD) {
/* read bytes into buffer */
ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len));
- if (ret < pmsg->len) {
+ if (ret < pmsg->len)
return (ret < 0) ? ret : -EREMOTEIO;
- }
} else {
/* write bytes from buffer */
ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len));
- if (ret < pmsg->len) {
+ if (ret < pmsg->len)
return (ret < 0) ? ret : -EREMOTEIO;
- }
}
}
return num;
@@ -219,7 +216,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name,
usbvision->dev->bus->busnum, usbvision->dev->devpath);
- PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+ PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name);
usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
@@ -244,31 +241,31 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
/* Request the load of the i2c modules we need */
- switch (usbvision_device_data[usbvision->DevModel].Codec) {
+ switch (usbvision_device_data[usbvision->dev_model].codec) {
case CODEC_SAA7113:
case CODEC_SAA7111:
/* Without this delay the detection of the saa711x is
hit-and-miss. */
mdelay(10);
v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"saa7115_auto", 0, saa711x_addrs);
break;
}
- if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
+ if (usbvision_device_data[usbvision->dev_model].tuner == 1) {
struct v4l2_subdev *sd;
enum v4l2_i2c_tuner_type type;
struct tuner_setup tun_setup;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
/* depending on whether we found a demod or not, select
the tuner type. */
type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, NULL,
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(type));
if (sd == NULL)
@@ -293,7 +290,7 @@ int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
i2c_del_adapter(&(usbvision->i2c_adap));
usbvision->registered_i2c = 0;
- PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name);
+ PDEBUG(DBG_I2C, "i2c bus for %s unregistered", usbvision->i2c_adap.name);
return 0;
}
@@ -355,9 +352,9 @@ usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
if (i2c_debug & DBG_I2C) {
int idx;
- for (idx = 0; idx < len; idx++) {
- PDEBUG(DBG_I2C,"read %x from address %x", (unsigned char)buf[idx], addr);
- }
+
+ for (idx = 0; idx < len; idx++)
+ PDEBUG(DBG_I2C, "read %x from address %x", (unsigned char)buf[idx], addr);
}
return len;
}
@@ -416,9 +413,9 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
if (i2c_debug & DBG_I2C) {
int idx;
- for (idx = 0; idx < len; idx++) {
- PDEBUG(DBG_I2C,"wrote %x at address %x", (unsigned char)buf[idx], addr);
- }
+
+ for (idx = 0; idx < len; idx++)
+ PDEBUG(DBG_I2C, "wrote %x at address %x", (unsigned char)buf[idx], addr);
}
return len;
}
@@ -426,18 +423,18 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
short len)
{
- char *bufPtr = buf;
+ char *buf_ptr = buf;
int retval;
int wrcount = 0;
int count;
- int maxLen = 4;
+ int max_len = 4;
while (len > 0) {
- count = (len > maxLen) ? maxLen : len;
- retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count);
+ count = (len > max_len) ? max_len : len;
+ retval = usbvision_i2c_write_max4(usbvision, addr, buf_ptr, count);
if (retval > 0) {
len -= count;
- bufPtr += count;
+ buf_ptr += count;
wrcount += count;
} else
return (retval < 0) ? retval : -EFAULT;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index db6b828594f5..6083137f0bf8 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -50,14 +50,13 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
@@ -71,8 +70,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"
@@ -83,9 +82,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_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 */
@@ -97,16 +96,16 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
__func__, __LINE__ , ## args); \
}
#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
+ #define PDEBUG(level, fmt, args...) do {} while (0)
#endif
-#define DBG_IO 1<<1
-#define DBG_PROBE 1<<2
-#define DBG_MMAP 1<<3
+#define DBG_IO (1 << 1)
+#define DBG_PROBE (1 << 2)
+#define DBG_MMAP (1 << 3)
-//String operations
-#define rmspace(str) while(*str==' ') str++;
-#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
+/* String operations */
+#define rmspace(str) while (*str == ' ') str++;
+#define goto2next(str) while (*str != ' ') str++; while (*str == ' ') str++;
/* sequential number of usbvision device */
@@ -119,7 +118,7 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" },
{ 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" },
{ 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" },
- { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 !
+ { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
};
@@ -128,11 +127,11 @@ static void usbvision_release(struct usb_usbvision *usbvision);
/* Default initialization of device driver parameters */
/* Set the default format for ISOC endpoint */
-static int isocMode = ISOC_MODE_COMPRESS;
+static int isoc_mode = ISOC_MODE_COMPRESS;
/* Set the default Debug Mode of the device driver */
static int video_debug;
/* Set the default device to power on at startup */
-static int PowerOnAtOpen = 1;
+static int power_on_at_open = 1;
/* Sequential Number of Video Device */
static int video_nr = -1;
/* Sequential Number of Radio Device */
@@ -141,20 +140,20 @@ static int radio_nr = -1;
/* Grab parameters for the device driver */
/* Showing parameters under SYSFS */
-module_param(isocMode, int, 0444);
+module_param(isoc_mode, int, 0444);
module_param(video_debug, int, 0444);
-module_param(PowerOnAtOpen, int, 0444);
+module_param(power_on_at_open, int, 0444);
module_param(video_nr, int, 0444);
module_param(radio_nr, int, 0444);
-MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
+MODULE_PARM_DESC(isoc_mode, " 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)");
-MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)");
+MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)");
MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
-// Misc stuff
+/* Misc stuff */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
@@ -193,7 +192,7 @@ static ssize_t show_model(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- usbvision_device_data[usbvision->DevModel].ModelString);
+ usbvision_device_data[usbvision->dev_model].model_string);
}
static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
@@ -206,7 +205,7 @@ static ssize_t show_hue(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -221,7 +220,7 @@ static ssize_t show_contrast(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -236,7 +235,7 @@ static ssize_t show_brightness(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -251,7 +250,7 @@ static ssize_t show_saturation(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -264,7 +263,7 @@ static ssize_t show_streaming(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- YES_NO(usbvision->streaming==Stream_On?1:0));
+ YES_NO(usbvision->streaming == stream_on ? 1 : 0));
}
static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
@@ -275,7 +274,7 @@ static ssize_t show_compression(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+ YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS));
}
static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
@@ -285,42 +284,43 @@ static ssize_t show_device_bridge(struct device *cd,
struct video_device *vdev =
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%d\n", usbvision->bridgeType);
+ return sprintf(buf, "%d\n", usbvision->bridge_type);
}
static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
static void usbvision_create_sysfs(struct video_device *vdev)
{
int res;
+
if (!vdev)
return;
do {
res = device_create_file(&vdev->dev, &dev_attr_version);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_model);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_hue);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_contrast);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_brightness);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_saturation);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_streaming);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_compression);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_bridge);
- if (res>=0)
+ if (res >= 0)
return;
} while (0);
@@ -353,24 +353,23 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
static int usbvision_v4l2_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "open");
- mutex_lock(&usbvision->lock);
- usbvision_reset_powerOffTimer(usbvision);
+ usbvision_reset_power_off_timer(usbvision);
if (usbvision->user)
- errCode = -EBUSY;
+ err_code = -EBUSY;
else {
/* Allocate memory for the scratch ring buffer */
- errCode = usbvision_scratch_alloc(usbvision);
- if (isocMode==ISOC_MODE_COMPRESS) {
+ err_code = usbvision_scratch_alloc(usbvision);
+ if (isoc_mode == ISOC_MODE_COMPRESS) {
/* Allocate intermediate decompression buffers
only if needed */
- errCode = usbvision_decompress_alloc(usbvision);
+ err_code = usbvision_decompress_alloc(usbvision);
}
- if (errCode) {
+ if (err_code) {
/* Deallocate all buffers if trouble */
usbvision_scratch_free(usbvision);
usbvision_decompress_free(usbvision);
@@ -378,7 +377,7 @@ static int usbvision_v4l2_open(struct file *file)
}
/* If so far no errors then we shall start the camera */
- if (!errCode) {
+ if (!err_code) {
if (usbvision->power == 0) {
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -387,21 +386,21 @@ static int usbvision_v4l2_open(struct file *file)
/* Send init sequence only once, it's large! */
if (!usbvision->initialized) {
int setup_ok = 0;
- setup_ok = usbvision_setup(usbvision,isocMode);
+ setup_ok = usbvision_setup(usbvision, isoc_mode);
if (setup_ok)
usbvision->initialized = 1;
else
- errCode = -EBUSY;
+ err_code = -EBUSY;
}
- if (!errCode) {
+ if (!err_code) {
usbvision_begin_streaming(usbvision);
- errCode = usbvision_init_isoc(usbvision);
+ err_code = usbvision_init_isoc(usbvision);
/* device must be initialized before isoc transfer */
- usbvision_muxsel(usbvision,0);
+ usbvision_muxsel(usbvision, 0);
usbvision->user++;
} else {
- if (PowerOnAtOpen) {
+ if (power_on_at_open) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
@@ -413,8 +412,7 @@ static int usbvision_v4l2_open(struct file *file)
usbvision_empty_framequeues(usbvision);
PDEBUG(DBG_IO, "success");
- mutex_unlock(&usbvision->lock);
- return errCode;
+ return err_code;
}
/*
@@ -430,7 +428,6 @@ static int usbvision_v4l2_close(struct file *file)
struct usb_usbvision *usbvision = video_drvdata(file);
PDEBUG(DBG_IO, "close");
- mutex_lock(&usbvision->lock);
usbvision_audio_off(usbvision);
usbvision_restart_isoc(usbvision);
@@ -443,15 +440,13 @@ static int usbvision_v4l2_close(struct file *file)
usbvision->user--;
- if (PowerOnAtOpen) {
+ if (power_on_at_open) {
/* power off in a little while
to avoid off/on every close/open short sequences */
- usbvision_set_powerOffTimer(usbvision);
+ usbvision_set_power_off_timer(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
-
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
@@ -469,55 +464,55 @@ static int usbvision_v4l2_close(struct file *file)
*
*/
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register (struct file *file, void *priv,
+static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode;
+ int err_code;
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* NT100x has a 8-bit register space */
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- if (errCode < 0) {
+ err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (err_code < 0) {
dev_err(&usbvision->vdev->dev,
"%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
- __func__, errCode);
- return errCode;
+ __func__, err_code);
+ return err_code;
}
- reg->val = errCode;
+ reg->val = err_code;
reg->size = 1;
return 0;
}
-static int vidioc_s_register (struct file *file, void *priv,
+static int vidioc_s_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode;
+ int err_code;
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* NT100x has a 8-bit register space */
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
- if (errCode < 0) {
+ err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
+ if (err_code < 0) {
dev_err(&usbvision->vdev->dev,
"%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
- __func__, errCode);
- return errCode;
+ __func__, err_code);
+ return err_code;
}
return 0;
}
#endif
-static int vidioc_querycap (struct file *file, void *priv,
+static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *vc)
{
struct usb_usbvision *usbvision = video_drvdata(file);
strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
strlcpy(vc->card,
- usbvision_device_data[usbvision->DevModel].ModelString,
+ usbvision_device_data[usbvision->dev_model].model_string,
sizeof(vc->card));
usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
vc->version = USBVISION_DRIVER_VERSION;
@@ -529,7 +524,7 @@ static int vidioc_querycap (struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *vi)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -537,16 +532,16 @@ static int vidioc_enum_input (struct file *file, void *priv,
if (vi->index >= usbvision->video_inputs)
return -EINVAL;
- if (usbvision->have_tuner) {
+ if (usbvision->have_tuner)
chan = vi->index;
- } else {
- chan = vi->index + 1; /*skip Television string*/
- }
+ else
+ chan = vi->index + 1; /* skip Television string*/
+
/* Determine the requested input characteristics
specific for each usbvision card model */
- switch(chan) {
+ switch (chan) {
case 0:
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4) {
strcpy(vi->name, "White Video Input");
} else {
strcpy(vi->name, "Television");
@@ -558,20 +553,18 @@ static int vidioc_enum_input (struct file *file, void *priv,
break;
case 1:
vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
strcpy(vi->name, "Green Video Input");
- } else {
+ 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) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
strcpy(vi->name, "Yellow Video Input");
- } else {
+ else
strcpy(vi->name, "S-Video Input");
- }
vi->std = V4L2_STD_PAL;
break;
case 3:
@@ -583,7 +576,7 @@ static int vidioc_enum_input (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -591,46 +584,42 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
return 0;
}
-static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
{
struct usb_usbvision *usbvision = video_drvdata(file);
if (input >= usbvision->video_inputs)
return -EINVAL;
- mutex_lock(&usbvision->lock);
usbvision_muxsel(usbvision, input);
usbvision_set_input(usbvision);
usbvision_set_output(usbvision,
usbvision->curwidth,
usbvision->curheight);
- mutex_unlock(&usbvision->lock);
return 0;
}
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- usbvision->tvnormId=*id;
+ usbvision->tvnorm_id = *id;
- mutex_lock(&usbvision->lock);
- call_all(usbvision, core, s_std, usbvision->tvnormId);
- mutex_unlock(&usbvision->lock);
+ call_all(usbvision, core, s_std, usbvision->tvnorm_id);
/* propagate the change to the decoder */
usbvision_muxsel(usbvision, usbvision->ctl_input);
return 0;
}
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */
return -EINVAL;
- if(usbvision->radio) {
+ if (usbvision->radio) {
strcpy(vt->name, "Radio");
vt->type = V4L2_TUNER_RADIO;
} else {
@@ -642,12 +631,12 @@ static int vidioc_g_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- // Only no or one tuner for now
+ /* Only no or one tuner for now */
if (!usbvision->have_tuner || vt->index)
return -EINVAL;
/* let clients handle this */
@@ -656,28 +645,27 @@ static int vidioc_s_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- freq->tuner = 0; // Only one tuner
- if(usbvision->radio) {
+ freq->tuner = 0; /* Only one tuner */
+ if (usbvision->radio)
freq->type = V4L2_TUNER_RADIO;
- } else {
+ else
freq->type = V4L2_TUNER_ANALOG_TV;
- }
freq->frequency = usbvision->freq;
return 0;
}
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- // Only no or one tuner for now
+ /* Only no or one tuner for now */
if (!usbvision->have_tuner || freq->tuner)
return -EINVAL;
@@ -687,30 +675,27 @@ static int vidioc_s_frequency (struct file *file, void *priv,
return 0;
}
-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)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- if(usbvision->radio) {
- strcpy(a->name,"Radio");
- } else {
+ if (usbvision->radio)
+ strcpy(a->name, "Radio");
+ else
strcpy(a->name, "TV");
- }
return 0;
}
-static int vidioc_s_audio (struct file *file, void *fh,
+static int vidioc_s_audio(struct file *file, void *fh,
struct v4l2_audio *a)
{
- if(a->index) {
+ if (a->index)
return -EINVAL;
- }
-
return 0;
}
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -723,52 +708,53 @@ static int vidioc_queryctrl (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_ctrl (struct file *file, void *priv,
+static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_all(usbvision, core, g_ctrl, ctrl);
+ call_all(usbvision, core, g_ctrl, ctrl);
return 0;
}
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_all(usbvision, core, s_ctrl, ctrl);
+ call_all(usbvision, core, s_ctrl, ctrl);
return 0;
}
-static int vidioc_reqbufs (struct file *file,
+static int vidioc_reqbufs(struct file *file,
void *priv, struct v4l2_requestbuffers *vr)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
- RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+ RESTRICT_TO_RANGE(vr->count, 1, USBVISION_NUMFRAMES);
/* Check input validity:
the user must do a VIDEO CAPTURE and MMAP method. */
if (vr->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
return ret;
}
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision,vr->count);
+ vr->count = usbvision_frames_alloc(usbvision, vr->count);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
return 0;
}
-static int vidioc_querybuf (struct file *file,
+static int vidioc_querybuf(struct file *file,
void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -776,52 +762,49 @@ static int vidioc_querybuf (struct file *file,
/* FIXME : must control
that buffers are mapped (VIDIOC_REQBUFS has been called) */
- if(vb->index>=usbvision->num_frames) {
+ 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)
+ if (frame->grabstate >= frame_state_ready)
vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if(frame->grabstate >= FrameState_Done)
+ if (frame->grabstate >= frame_state_done)
vb->flags |= V4L2_BUF_FLAG_DONE;
- if(frame->grabstate == FrameState_Unused)
+ if (frame->grabstate == frame_state_unused)
vb->flags |= V4L2_BUF_FLAG_MAPPED;
vb->memory = V4L2_MEMORY_MMAP;
- vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+ vb->m.offset = vb->index * PAGE_ALIGN(usbvision->max_frame_size);
vb->memory = V4L2_MEMORY_MMAP;
vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth*
- usbvision->curheight*
+ 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)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
struct usbvision_frame *frame;
unsigned long lock_flags;
/* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
- if(vb->index>=usbvision->num_frames) {
+ if (vb->index >= usbvision->num_frames)
return -EINVAL;
- }
frame = &usbvision->frame[vb->index];
- if (frame->grabstate != FrameState_Unused) {
+ if (frame->grabstate != frame_state_unused)
return -EAGAIN;
- }
/* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
vb->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -836,7 +819,7 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
return 0;
}
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
@@ -844,7 +827,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
unsigned long lock_flags;
if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == Stream_Idle)
+ if (usbvision->streaming == stream_idle)
return -EINVAL;
ret = wait_event_interruptible
(usbvision->wait_frame,
@@ -859,7 +842,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
list_del(usbvision->outqueue.next);
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
- f->grabstate = FrameState_Unused;
+ f->grabstate = frame_state_unused;
vb->memory = V4L2_MEMORY_MMAP;
vb->flags = V4L2_BUF_FLAG_MAPPED |
@@ -878,7 +861,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- usbvision->streaming = Stream_On;
+ usbvision->streaming = stream_on;
call_all(usbvision, video, s_stream, 1);
return 0;
@@ -892,7 +875,7 @@ static int vidioc_streamoff(struct file *file,
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if(usbvision->streaming == Stream_On) {
+ if (usbvision->streaming == stream_on) {
usbvision_stream_interrupt(usbvision);
/* Stop all video streamings */
call_all(usbvision, video, s_stream, 0);
@@ -902,18 +885,17 @@ static int vidioc_streamoff(struct file *file,
return 0;
}
-static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *vfd)
{
- if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1)
return -EINVAL;
- }
- strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc);
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
return 0;
}
-static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *vf)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -921,32 +903,31 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
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;
+ 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_vid_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *vf)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int formatIdx;
+ int format_idx;
/* 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];
+ for (format_idx = 0; format_idx < USBVISION_SUPPORTED_PALETTES; format_idx++) {
+ if (vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[format_idx].format) {
+ usbvision->palette = usbvision_v4l2_format[format_idx];
break;
}
}
/* robustness */
- if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ if (format_idx == 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);
@@ -963,24 +944,23 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
- if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
+ ret = vidioc_try_fmt_vid_cap(file, priv, vf);
+ if (ret)
return ret;
- }
/* stop io in case it is already in progress */
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
return ret;
}
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
/* by now we are committed to the new data... */
- mutex_lock(&usbvision->lock);
usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
- mutex_unlock(&usbvision->lock);
return 0;
}
@@ -991,8 +971,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
struct usb_usbvision *usbvision = video_drvdata(file);
int noblock = file->f_flags & O_NONBLOCK;
unsigned long lock_flags;
-
- int ret,i;
+ int ret, i;
struct usbvision_frame *frame;
PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
@@ -1004,28 +983,28 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
/* 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) {
+ if (!usbvision->num_frames) {
/* First, allocate some frames to work with
if this has not been done with VIDIOC_REQBUF */
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+ usbvision_frames_alloc(usbvision, USBVISION_NUMFRAMES);
}
- if(usbvision->streaming != Stream_On) {
+ if (usbvision->streaming != stream_on) {
/* no stream is running, make it running ! */
- usbvision->streaming = Stream_On;
+ usbvision->streaming = stream_on;
call_all(usbvision, video, s_stream, 1);
}
/* Then, enqueue as many frames as possible
(like a user of VIDIOC_QBUF would do) */
- for(i=0;i<usbvision->num_frames;i++) {
+ for (i = 0; i < usbvision->num_frames; i++) {
frame = &usbvision->frame[i];
- if(frame->grabstate == FrameState_Unused) {
+ if (frame->grabstate == frame_state_unused) {
/* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
/* Accumulated in usbvision_parse_data() */
frame->scanlength = 0;
@@ -1041,7 +1020,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
/* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
if (list_empty(&(usbvision->outqueue))) {
- if(noblock)
+ if (noblock)
return -EAGAIN;
ret = wait_event_interruptible
@@ -1058,7 +1037,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
/* An error returns an empty frame */
- if (frame->grabstate == FrameState_Error) {
+ if (frame->grabstate == frame_state_error) {
frame->bytes_read = 0;
return 0;
}
@@ -1071,9 +1050,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
count = frame->scanlength - frame->bytes_read;
- if (copy_to_user(buf, frame->data + frame->bytes_read, count)) {
+ if (copy_to_user(buf, frame->data + frame->bytes_read, count))
return -EFAULT;
- }
frame->bytes_read += count;
PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
@@ -1081,12 +1059,12 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
(unsigned long)count, frame->bytes_read);
/* 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 */
+/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */
frame->bytes_read = 0;
/* Mark it as available to be used again. */
- frame->grabstate = FrameState_Unused;
-/* } */
+ frame->grabstate = frame_state_unused;
+/* } */
return count;
}
@@ -1101,16 +1079,11 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
PDEBUG(DBG_MMAP, "mmap");
- mutex_lock(&usbvision->lock);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision)) {
- mutex_unlock(&usbvision->lock);
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT;
- }
if (!(vma->vm_flags & VM_WRITE) ||
size != PAGE_ALIGN(usbvision->max_frame_size)) {
- mutex_unlock(&usbvision->lock);
return -EINVAL;
}
@@ -1122,7 +1095,6 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
if (i == usbvision->num_frames) {
PDEBUG(DBG_MMAP,
"mmap: user supplied mapping address is out of range");
- mutex_unlock(&usbvision->lock);
return -EINVAL;
}
@@ -1132,10 +1104,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
pos = usbvision->frame[i].data;
while (size > 0) {
-
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
- mutex_unlock(&usbvision->lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -1143,7 +1113,6 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
size -= PAGE_SIZE;
}
- mutex_unlock(&usbvision->lock);
return 0;
}
@@ -1155,21 +1124,18 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
static int usbvision_radio_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "%s:", __func__);
- mutex_lock(&usbvision->lock);
-
if (usbvision->user) {
dev_err(&usbvision->rdev->dev,
"%s: Someone tried to open an already opened USBVision Radio!\n",
__func__);
- errCode = -EBUSY;
- }
- else {
- if(PowerOnAtOpen) {
- usbvision_reset_powerOffTimer(usbvision);
+ err_code = -EBUSY;
+ } else {
+ if (power_on_at_open) {
+ usbvision_reset_power_off_timer(usbvision);
if (usbvision->power == 0) {
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -1177,80 +1143,73 @@ static int usbvision_radio_open(struct file *file)
}
/* Alternate interface 1 is is the biggest frame size */
- errCode = usbvision_set_alternate(usbvision);
- if (errCode < 0) {
- usbvision->last_error = errCode;
- errCode = -EBUSY;
+ err_code = usbvision_set_alternate(usbvision);
+ if (err_code < 0) {
+ usbvision->last_error = err_code;
+ err_code = -EBUSY;
goto out;
}
- // If so far no errors then we shall start the radio
+ /* If so far no errors then we shall start the radio */
usbvision->radio = 1;
call_all(usbvision, tuner, s_radio);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
- if (errCode) {
- if (PowerOnAtOpen) {
+ if (err_code) {
+ if (power_on_at_open) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
}
}
out:
- mutex_unlock(&usbvision->lock);
- return errCode;
+ return err_code;
}
static int usbvision_radio_close(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "");
- mutex_lock(&usbvision->lock);
-
/* Set packet size to 0 */
- usbvision->ifaceAlt=0;
- errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAlt);
+ usbvision->iface_alt = 0;
+ err_code = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->iface_alt);
usbvision_audio_off(usbvision);
- usbvision->radio=0;
+ usbvision->radio = 0;
usbvision->user--;
- if (PowerOnAtOpen) {
- usbvision_set_powerOffTimer(usbvision);
+ if (power_on_at_open) {
+ usbvision_set_power_off_timer(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
-
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
}
PDEBUG(DBG_IO, "success");
- return errCode;
+ return err_code;
}
-//
-// Video registration stuff
-//
+/* Video registration stuff */
-// Video template
+/* Video template */
static const struct v4l2_file_operations usbvision_fops = {
.owner = THIS_MODULE,
.open = usbvision_v4l2_open,
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
.mmap = usbvision_v4l2_mmap,
- .ioctl = video_ioctl2,
-/* .poll = video_poll, */
+ .unlocked_ioctl = video_ioctl2,
+/* .poll = video_poll, */
};
static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
@@ -1274,9 +1233,6 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
.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,
@@ -1289,20 +1245,20 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
static struct video_device usbvision_video_template = {
.fops = &usbvision_fops,
- .ioctl_ops = &usbvision_ioctl_ops,
+ .ioctl_ops = &usbvision_ioctl_ops,
.name = "usbvision-video",
.release = video_device_release,
- .tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
-// Radio template
+/* Radio template */
static const struct v4l2_file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
@@ -1323,9 +1279,9 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
static struct video_device usbvision_radio_template = {
.fops = &usbvision_radio_fops,
- .name = "usbvision-radio",
+ .name = "usbvision-radio",
.release = video_device_release,
- .ioctl_ops = &usbvision_radio_ioctl_ops,
+ .ioctl_ops = &usbvision_radio_ioctl_ops,
.tvnorms = USBVISION_NORMS,
.current_norm = V4L2_STD_PAL
@@ -1346,80 +1302,70 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
}
vdev = video_device_alloc();
- if (NULL == vdev) {
+ if (NULL == vdev)
return NULL;
- }
*vdev = *vdev_template;
+ vdev->lock = &usbvision->v4l2_lock;
vdev->v4l2_dev = &usbvision->v4l2_dev;
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
video_set_drvdata(vdev, usbvision);
return vdev;
}
-// unregister video4linux devices
+/* unregister video4linux devices */
static void usbvision_unregister_video(struct usb_usbvision *usbvision)
{
- // Radio Device:
+ /* Radio Device: */
if (usbvision->rdev) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
video_device_node_name(usbvision->rdev));
- if (video_is_registered(usbvision->rdev)) {
+ if (video_is_registered(usbvision->rdev))
video_unregister_device(usbvision->rdev);
- } else {
+ else
video_device_release(usbvision->rdev);
- }
usbvision->rdev = NULL;
}
- // Video Device:
+ /* Video Device: */
if (usbvision->vdev) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
video_device_node_name(usbvision->vdev));
- if (video_is_registered(usbvision->vdev)) {
+ if (video_is_registered(usbvision->vdev))
video_unregister_device(usbvision->vdev);
- } else {
+ else
video_device_release(usbvision->vdev);
- }
usbvision->vdev = NULL;
}
}
-// register video4linux devices
+/* register video4linux devices */
static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
{
- // Video Device:
+ /* Video Device: */
usbvision->vdev = usbvision_vdev_init(usbvision,
&usbvision_video_template,
"USBVision Video");
- if (usbvision->vdev == NULL) {
+ 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 %s [v4l2]\n",
usbvision->nr, video_device_node_name(usbvision->vdev));
- // Radio Device:
- if (usbvision_device_data[usbvision->DevModel].Radio) {
- // usbvision has radio
+ /* Radio Device: */
+ if (usbvision_device_data[usbvision->dev_model].radio) {
+ /* usbvision has radio */
usbvision->rdev = usbvision_vdev_init(usbvision,
&usbvision_radio_template,
"USBVision Radio");
- if (usbvision->rdev == NULL) {
+ 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 %s [v4l2]\n",
usbvision->nr, video_device_node_name(usbvision->rdev));
}
- // all done
+ /* all done */
return 0;
err_exit:
@@ -1452,15 +1398,15 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev,
if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev))
goto err_free;
- mutex_init(&usbvision->lock); /* available */
+ mutex_init(&usbvision->v4l2_lock);
- // prepare control urb for control messages during interrupts
- usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
- if (usbvision->ctrlUrb == NULL)
+ /* prepare control urb for control messages during interrupts */
+ usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (usbvision->ctrl_urb == NULL)
goto err_unreg;
- init_waitqueue_head(&usbvision->ctrlUrb_wq);
+ init_waitqueue_head(&usbvision->ctrl_urb_wq);
- usbvision_init_powerOffTimer(usbvision);
+ usbvision_init_power_off_timer(usbvision);
return usbvision;
@@ -1482,20 +1428,14 @@ static void usbvision_release(struct usb_usbvision *usbvision)
{
PDEBUG(DBG_PROBE, "");
- mutex_lock(&usbvision->lock);
-
- usbvision_reset_powerOffTimer(usbvision);
+ usbvision_reset_power_off_timer(usbvision);
usbvision->initialized = 0;
- mutex_unlock(&usbvision->lock);
-
usbvision_remove_sysfs(usbvision->vdev);
usbvision_unregister_video(usbvision);
- if (usbvision->ctrlUrb) {
- usb_free_urb(usbvision->ctrlUrb);
- }
+ usb_free_urb(usbvision->ctrl_urb);
v4l2_device_unregister(&usbvision->v4l2_dev);
kfree(usbvision);
@@ -1513,25 +1453,25 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
if (usbvision == NULL)
return;
- model = usbvision->DevModel;
- usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
+ model = usbvision->dev_model;
+ 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;
+ if (usbvision_device_data[usbvision->dev_model].vin_reg2_override) {
+ usbvision->vin_reg2_preset =
+ usbvision_device_data[usbvision->dev_model].vin_reg2;
} else {
- usbvision->Vin_Reg2_Preset = 0;
+ usbvision->vin_reg2_preset = 0;
}
- usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
+ usbvision->tvnorm_id = usbvision_device_data[model].video_norm;
- usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
+ usbvision->video_inputs = usbvision_device_data[model].video_channels;
usbvision->ctl_input = 0;
/* This should be here to make i2c clients to be able to register */
/* first switch off audio */
usbvision_audio_off(usbvision);
- if (!PowerOnAtOpen) {
+ if (!power_on_at_open) {
/* and then power up the noisy tuner */
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -1554,25 +1494,24 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
- int model,i;
+ int model, i;
PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor,
dev->descriptor.idProduct, ifnum);
model = devid->driver_info;
- if ( (model<0) || (model>=usbvision_device_data_size) ) {
- PDEBUG(DBG_PROBE, "model out of bounds %d",model);
+ if (model < 0 || model >= usbvision_device_data_size) {
+ PDEBUG(DBG_PROBE, "model out of bounds %d", model);
return -ENODEV;
}
printk(KERN_INFO "%s: %s found\n", __func__,
- usbvision_device_data[model].ModelString);
+ usbvision_device_data[model].model_string);
- if (usbvision_device_data[model].Interface >= 0) {
- interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
- } else {
+ if (usbvision_device_data[model].interface >= 0)
+ interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
+ else
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
- }
endpoint = &interface->endpoint[1].desc;
if (!usb_endpoint_xfer_isoc(endpoint)) {
dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
@@ -1593,59 +1532,52 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
return -ENOMEM;
}
- if (dev->descriptor.bNumConfigurations > 1) {
- usbvision->bridgeType = BRIDGE_NT1004;
- } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
- usbvision->bridgeType = BRIDGE_NT1005;
- } else {
- usbvision->bridgeType = BRIDGE_NT1003;
- }
- PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
-
- mutex_lock(&usbvision->lock);
+ if (dev->descriptor.bNumConfigurations > 1)
+ usbvision->bridge_type = BRIDGE_NT1004;
+ else if (model == DAZZLE_DVC_90_REV_1_SECAM)
+ usbvision->bridge_type = BRIDGE_NT1005;
+ else
+ usbvision->bridge_type = BRIDGE_NT1003;
+ PDEBUG(DBG_PROBE, "bridge_type %d", usbvision->bridge_type);
/* compute alternate max packet sizes */
uif = dev->actconfig->interface[0];
- usbvision->num_alt=uif->num_altsetting;
- PDEBUG(DBG_PROBE, "Alternate settings: %i",usbvision->num_alt);
- usbvision->alt_max_pkt_size = kmalloc(32*
- usbvision->num_alt,GFP_KERNEL);
+ usbvision->num_alt = uif->num_altsetting;
+ PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt);
+ usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
if (usbvision->alt_max_pkt_size == NULL) {
dev_err(&intf->dev, "usbvision: out of memory!\n");
- mutex_unlock(&usbvision->lock);
return -ENOMEM;
}
- for (i = 0; i < usbvision->num_alt ; i++) {
+ for (i = 0; i < usbvision->num_alt; i++) {
u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
wMaxPacketSize);
usbvision->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i",i,
+ PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i", i,
usbvision->alt_max_pkt_size[i]);
}
usbvision->nr = usbvision_nr++;
- usbvision->have_tuner = usbvision_device_data[model].Tuner;
- if (usbvision->have_tuner) {
- usbvision->tuner_type = usbvision_device_data[model].TunerType;
- }
+ usbvision->have_tuner = usbvision_device_data[model].tuner;
+ if (usbvision->have_tuner)
+ usbvision->tuner_type = usbvision_device_data[model].tuner_type;
- usbvision->DevModel = model;
+ usbvision->dev_model = model;
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
- usbvision->ifaceAlt = 0;
+ usbvision->iface_alt = 0;
usbvision->video_endp = endpoint->bEndpointAddress;
- usbvision->isocPacketSize = 0;
+ usbvision->isoc_packet_size = 0;
usbvision->usb_bandwidth = 0;
usbvision->user = 0;
- usbvision->streaming = Stream_Off;
+ usbvision->streaming = stream_off;
usbvision_configure_video(usbvision);
usbvision_register_video(usbvision);
- mutex_unlock(&usbvision->lock);
usbvision_create_sysfs(usbvision->vdev);
@@ -1673,9 +1605,9 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
return;
}
- mutex_lock(&usbvision->lock);
+ mutex_lock(&usbvision->v4l2_lock);
- // At this time we ask to cancel outstanding URBs
+ /* At this time we ask to cancel outstanding URBs */
usbvision_stop_isoc(usbvision);
v4l2_device_disconnect(&usbvision->v4l2_dev);
@@ -1684,12 +1616,12 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
}
- usbvision->remove_pending = 1; // Now all ISO data will be ignored
+ usbvision->remove_pending = 1; /* Now all ISO data will be ignored */
usb_put_dev(usbvision->dev);
- usbvision->dev = NULL; // USB device is no more
+ usbvision->dev = NULL; /* USB device is no more */
- mutex_unlock(&usbvision->lock);
+ mutex_unlock(&usbvision->v4l2_lock);
if (usbvision->user) {
printk(KERN_INFO "%s: In use, disconnect pending\n",
@@ -1718,7 +1650,7 @@ static struct usb_driver usbvision_driver = {
*/
static int __init usbvision_init(void)
{
- int errCode;
+ int err_code;
PDEBUG(DBG_PROBE, "");
@@ -1727,27 +1659,27 @@ static int __init usbvision_init(void)
PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
/* disable planar mode support unless compression enabled */
- if (isocMode != ISOC_MODE_COMPRESS ) {
- // FIXME : not the right way to set supported flag
- usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420
- usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P
+ if (isoc_mode != ISOC_MODE_COMPRESS) {
+ /* FIXME : not the right way to set supported flag */
+ usbvision_v4l2_format[6].supported = 0; /* V4L2_PIX_FMT_YVU420 */
+ usbvision_v4l2_format[7].supported = 0; /* V4L2_PIX_FMT_YUV422P */
}
- errCode = usb_register(&usbvision_driver);
+ err_code = usb_register(&usbvision_driver);
- if (errCode == 0) {
+ if (err_code == 0) {
printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
PDEBUG(DBG_PROBE, "success");
}
- return errCode;
+ return err_code;
}
static void __exit usbvision_exit(void)
{
- PDEBUG(DBG_PROBE, "");
+ PDEBUG(DBG_PROBE, "");
- usb_deregister(&usbvision_driver);
- PDEBUG(DBG_PROBE, "success");
+ usb_deregister(&usbvision_driver);
+ PDEBUG(DBG_PROBE, "success");
}
module_init(usbvision_init);
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index cc4e96c8cd6c..8074787fd1ac 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -132,15 +132,15 @@
#define MAX_BYTES_PER_PIXEL 4
#define MIN_FRAME_WIDTH 64
-#define MAX_USB_WIDTH 320 //384
-#define MAX_FRAME_WIDTH 320 //384 /*streching sometimes causes crashes*/
+#define MAX_USB_WIDTH 320 /* 384 */
+#define MAX_FRAME_WIDTH 320 /* 384 */ /* streching sometimes causes crashes*/
#define MIN_FRAME_HEIGHT 48
-#define MAX_USB_HEIGHT 240 //288
-#define MAX_FRAME_HEIGHT 240 //288 /*Streching sometimes causes crashes*/
+#define MAX_USB_HEIGHT 240 /* 288 */
+#define MAX_FRAME_HEIGHT 240 /* 288 */ /* Streching sometimes causes crashes*/
-#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
-#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) //bytesize of clipmask
+#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
+#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) /* bytesize of clipmask */
#define USBVISION_URB_FRAMES 32
@@ -148,7 +148,7 @@
#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */
#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */
-#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds
+#define USBVISION_POWEROFF_TIME (3 * HZ) /* 3 seconds */
#define FRAMERATE_MIN 0
@@ -161,7 +161,8 @@ enum {
};
/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+#define RESTRICT_TO_RANGE(v, mi, ma) \
+ { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
/*
* We use macros to do YUV -> RGB conversion because this is
@@ -183,18 +184,18 @@ enum {
* Make sure the output values are within [0..255] range.
*/
#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
- int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
- mm_y = (my) - 16; \
- mm_u = (mu) - 128; \
- mm_v = (mv) - 128; \
- mm_yc= mm_y * 76284; \
- mm_b = (mm_yc + 132252*mm_v ) >> 16; \
- mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \
- mm_r = (mm_yc + 104595*mm_u ) >> 16; \
- mb = LIMIT_RGB(mm_b); \
- mg = LIMIT_RGB(mm_g); \
- mr = LIMIT_RGB(mm_r); \
+#define YUV_TO_RGB_BY_THE_BOOK(my, mu, mv, mr, mg, mb) { \
+ int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+ mm_y = (my) - 16; \
+ mm_u = (mu) - 128; \
+ mm_v = (mv) - 128; \
+ mm_yc = mm_y * 76284; \
+ mm_b = (mm_yc + 132252 * mm_v) >> 16; \
+ mm_g = (mm_yc - 53281 * mm_u - 25625 * mm_v) >> 16; \
+ mm_r = (mm_yc + 104595 * mm_u) >> 16; \
+ mb = LIMIT_RGB(mm_b); \
+ mg = LIMIT_RGB(mm_g); \
+ mr = LIMIT_RGB(mm_r); \
}
/* Debugging aid */
@@ -202,7 +203,7 @@ enum {
wait_queue_head_t wq; \
init_waitqueue_head(&wq); \
printk(KERN_INFO "Say: %s\n", what); \
- interruptible_sleep_on_timeout (&wq, HZ*3); \
+ interruptible_sleep_on_timeout(&wq, HZ * 3); \
}
/*
@@ -223,39 +224,39 @@ enum {
/* ----------------------------------------------------------------- */
/* usbvision video structures */
/* ----------------------------------------------------------------- */
-enum ScanState {
- ScanState_Scanning, /* Scanning for header */
- ScanState_Lines /* Parsing lines */
+enum scan_state {
+ scan_state_scanning, /* Scanning for header */
+ scan_state_lines /* Parsing lines */
};
/* Completion states of the data parser */
-enum ParseState {
- ParseState_Continue, /* Just parse next item */
- ParseState_NextFrame, /* Frame done, send it to V4L */
- ParseState_Out, /* Not enough data for frame */
- ParseState_EndParse /* End parsing */
+enum parse_state {
+ parse_state_continue, /* Just parse next item */
+ parse_state_next_frame, /* Frame done, send it to V4L */
+ parse_state_out, /* Not enough data for frame */
+ parse_state_end_parse /* End parsing */
};
-enum FrameState {
- FrameState_Unused, /* Unused (no MCAPTURE) */
- FrameState_Ready, /* Ready to start grabbing */
- FrameState_Grabbing, /* In the process of being grabbed into */
- FrameState_Done, /* Finished grabbing, but not been synced yet */
- FrameState_DoneHold, /* Are syncing or reading */
- FrameState_Error, /* Something bad happened while processing */
+enum frame_state {
+ frame_state_unused, /* Unused (no MCAPTURE) */
+ frame_state_ready, /* Ready to start grabbing */
+ frame_state_grabbing, /* In the process of being grabbed into */
+ frame_state_done, /* Finished grabbing, but not been synced yet */
+ frame_state_done_hold, /* Are syncing or reading */
+ frame_state_error, /* Something bad happened while processing */
};
/* stream states */
-enum StreamState {
- Stream_Off, /* Driver streaming is completely OFF */
- Stream_Idle, /* Driver streaming is ready to be put ON by the application */
- Stream_Interrupt, /* Driver streaming must be interrupted */
- Stream_On, /* Driver streaming is put ON by the application */
+enum stream_state {
+ stream_off, /* Driver streaming is completely OFF */
+ stream_idle, /* Driver streaming is ready to be put ON by the application */
+ stream_interrupt, /* Driver streaming must be interrupted */
+ stream_on, /* Driver streaming is put ON by the application */
};
-enum IsocState {
- IsocState_InFrame, /* Isoc packet is member of frame */
- IsocState_NoFrame, /* Isoc packet is not member of any frame */
+enum isoc_state {
+ isoc_state_in_frame, /* Isoc packet is member of frame */
+ isoc_state_no_frame, /* Isoc packet is not member of any frame */
};
struct usb_device;
@@ -265,8 +266,8 @@ struct usbvision_sbuf {
struct urb *urb;
};
-#define USBVISION_MAGIC_1 0x55
-#define USBVISION_MAGIC_2 0xAA
+#define USBVISION_MAGIC_1 0x55
+#define USBVISION_MAGIC_2 0xAA
#define USBVISION_HEADER_LENGTH 0x0c
#define USBVISION_SAA7111_ADDR 0x48
#define USBVISION_SAA7113_ADDR 0x4a
@@ -286,23 +287,23 @@ struct usbvision_v4l2_format_st {
struct usbvision_frame_header {
unsigned char magic_1; /* 0 magic */
unsigned char magic_2; /* 1 magic */
- unsigned char headerLength; /* 2 */
- unsigned char frameNum; /* 3 */
- unsigned char framePhase; /* 4 */
- unsigned char frameLatency; /* 5 */
- unsigned char dataFormat; /* 6 */
- unsigned char formatParam; /* 7 */
- unsigned char frameWidthLo; /* 8 */
- unsigned char frameWidthHi; /* 9 */
- unsigned char frameHeightLo; /* 10 */
- unsigned char frameHeightHi; /* 11 */
- __u16 frameWidth; /* 8 - 9 after endian correction*/
- __u16 frameHeight; /* 10 - 11 after endian correction*/
+ unsigned char header_length; /* 2 */
+ unsigned char frame_num; /* 3 */
+ unsigned char frame_phase; /* 4 */
+ unsigned char frame_latency; /* 5 */
+ unsigned char data_format; /* 6 */
+ unsigned char format_param; /* 7 */
+ unsigned char frame_width_lo; /* 8 */
+ unsigned char frame_width_hi; /* 9 */
+ unsigned char frame_height_lo; /* 10 */
+ unsigned char frame_height_hi; /* 11 */
+ __u16 frame_width; /* 8 - 9 after endian correction*/
+ __u16 frame_height; /* 10 - 11 after endian correction*/
};
struct usbvision_frame {
char *data; /* Frame buffer */
- struct usbvision_frame_header isocHeader; /* Header from stream */
+ struct usbvision_frame_header isoc_header; /* Header from stream */
int width; /* Width application is expecting */
int height; /* Height */
@@ -322,7 +323,7 @@ struct usbvision_frame {
struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/
int v4l2_linesize; /* bytes for one videoline*/
struct timeval timestamp;
- int sequence; // How many video frames we send to user
+ int sequence; /* How many video frames we send to user */
};
#define CODEC_SAA7113 7113
@@ -332,24 +333,24 @@ struct usbvision_frame {
#define BRIDGE_NT1005 1005
struct usbvision_device_data_st {
- __u64 VideoNorm;
- const char *ModelString;
- int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
- __u16 Codec;
- unsigned VideoChannels:3;
- unsigned AudioChannels:2;
- unsigned Radio:1;
+ __u64 video_norm;
+ const char *model_string;
+ int interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
+ __u16 codec;
+ unsigned video_channels:3;
+ unsigned audio_channels:2;
+ unsigned radio:1;
unsigned vbi:1;
- unsigned Tuner:1;
- unsigned Vin_Reg1_override:1; /* Override default value with */
- unsigned Vin_Reg2_override:1; /* Vin_Reg1, Vin_Reg2, etc. */
- unsigned Dvi_yuv_override:1;
- __u8 Vin_Reg1;
- __u8 Vin_Reg2;
- __u8 Dvi_yuv;
- __u8 TunerType;
- __s16 X_Offset;
- __s16 Y_Offset;
+ unsigned tuner:1;
+ unsigned vin_reg1_override:1; /* Override default value with */
+ unsigned vin_reg2_override:1; /* vin_reg1, vin_reg2, etc. */
+ unsigned dvi_yuv_override:1;
+ __u8 vin_reg1;
+ __u8 vin_reg2;
+ __u8 dvi_yuv;
+ __u8 tuner_type;
+ __s16 x_offset;
+ __s16 y_offset;
};
/* Declared on usbvision-cards.c */
@@ -358,50 +359,50 @@ extern struct usb_device_id usbvision_table[];
struct usb_usbvision {
struct v4l2_device v4l2_dev;
- struct video_device *vdev; /* Video Device */
- struct video_device *rdev; /* Radio Device */
+ struct video_device *vdev; /* Video Device */
+ struct video_device *rdev; /* Radio Device */
/* i2c Declaration Section*/
struct i2c_adapter i2c_adap;
int registered_i2c;
- struct urb *ctrlUrb;
- unsigned char ctrlUrbBuffer[8];
- int ctrlUrbBusy;
- struct usb_ctrlrequest ctrlUrbSetup;
- wait_queue_head_t ctrlUrb_wq; // Processes waiting
+ struct urb *ctrl_urb;
+ unsigned char ctrl_urb_buffer[8];
+ int ctrl_urb_busy;
+ struct usb_ctrlrequest ctrl_urb_setup;
+ wait_queue_head_t ctrl_urb_wq; /* Processes waiting */
/* configuration part */
int have_tuner;
int tuner_type;
- int bridgeType; // NT1003, NT1004, NT1005
+ int bridge_type; /* NT1003, NT1004, NT1005 */
int radio;
- int video_inputs; // # of inputs
+ int video_inputs; /* # of inputs */
unsigned long freq;
- int AudioMute;
- int AudioChannel;
- int isocMode; // format of video data for the usb isoc-transfer
- unsigned int nr; // Number of the device
+ int audio_mute;
+ int audio_channel;
+ int isoc_mode; /* format of video data for the usb isoc-transfer */
+ unsigned int nr; /* Number of the device */
/* Device structure */
struct usb_device *dev;
/* usb transfer */
int num_alt; /* Number of alternative settings */
- unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ unsigned int *alt_max_pkt_size; /* array of max_packet_size */
unsigned char iface; /* Video interface number */
- unsigned char ifaceAlt; /* Alt settings */
- unsigned char Vin_Reg2_Preset;
- struct mutex lock;
- struct timer_list powerOffTimer;
- struct work_struct powerOffWork;
+ unsigned char iface_alt; /* Alt settings */
+ unsigned char vin_reg2_preset;
+ struct mutex v4l2_lock;
+ struct timer_list power_off_timer;
+ struct work_struct power_off_work;
int power; /* is the device powered on? */
int user; /* user count for exclusive use */
int initialized; /* Had we already sent init sequence? */
- int DevModel; /* What type of USBVISION device we got? */
- enum StreamState streaming; /* Are we streaming Isochronous? */
+ int dev_model; /* What type of USBVISION device we got? */
+ enum stream_state streaming; /* Are we streaming Isochronous? */
int last_error; /* What calamity struck us? */
int curwidth; /* width of the frame the device is currently set to*/
- int curheight; /* height of the frame the device is currently set to*/
+ int curheight; /* height of the frame the device is currently set to*/
int stretch_width; /* stretch-factor for frame width (from usb to screen)*/
int stretch_height; /* stretch-factor for frame height (from usb to screen)*/
char *fbuf; /* Videodev buffer area for mmap*/
@@ -411,10 +412,10 @@ struct usb_usbvision {
struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */
wait_queue_head_t wait_frame; /* Processes waiting */
wait_queue_head_t wait_stream; /* Processes waiting */
- struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header
- struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
- int num_frames; // number of frames allocated
- struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering
+ struct usbvision_frame *cur_frame; /* pointer to current frame, set by usbvision_find_header */
+ struct usbvision_frame frame[USBVISION_NUMFRAMES]; /* frame buffer */
+ int num_frames; /* number of frames allocated */
+ struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; /* S buffering */
volatile int remove_pending; /* If set then about to exit */
/* Scratch space from the Isochronous Pipe.*/
@@ -424,43 +425,43 @@ struct usb_usbvision {
int scratch_headermarker[USBVISION_NUM_HEADERMARKER];
int scratch_headermarker_read_ptr;
int scratch_headermarker_write_ptr;
- enum IsocState isocstate;
+ enum isoc_state isocstate;
struct usbvision_v4l2_format_st palette;
struct v4l2_capability vcap; /* Video capabilities */
unsigned int ctl_input; /* selected input */
- v4l2_std_id tvnormId; /* selected tv norm */
+ v4l2_std_id tvnorm_id; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
- // Decompression stuff:
- unsigned char *IntraFrameBuffer; /* Buffer for reference frame */
- int BlockPos; //for test only
- int requestIntra; // 0 = normal; 1 = intra frame is requested;
- int lastIsocFrameNum; // check for lost isoc frames
- int isocPacketSize; // need to calculate usedBandwidth
- int usedBandwidth; // used bandwidth 0-100%, need to set comprLevel
- int comprLevel; // How strong (100) or weak (0) is compression
- int lastComprLevel; // How strong (100) or weak (0) was compression
+ /* Decompression stuff: */
+ unsigned char *intra_frame_buffer; /* Buffer for reference frame */
+ int block_pos; /* for test only */
+ int request_intra; /* 0 = normal; 1 = intra frame is requested; */
+ int last_isoc_frame_num; /* check for lost isoc frames */
+ int isoc_packet_size; /* need to calculate used_bandwidth */
+ int used_bandwidth; /* used bandwidth 0-100%, need to set compr_level */
+ int compr_level; /* How strong (100) or weak (0) is compression */
+ int last_compr_level; /* How strong (100) or weak (0) was compression */
int usb_bandwidth; /* Mbit/s */
/* Statistics that can be overlayed on the screen */
- unsigned long isocUrbCount; // How many URBs we received so far
+ unsigned long isoc_urb_count; /* How many URBs we received so far */
unsigned long urb_length; /* Length of last URB */
- unsigned long isocDataCount; /* How many bytes we received */
+ unsigned long isoc_data_count; /* How many bytes we received */
unsigned long header_count; /* How many frame headers we found */
unsigned long scratch_ovf_count; /* How many times we overflowed scratch */
- unsigned long isocSkipCount; /* How many empty ISO packets received */
- unsigned long isocErrCount; /* How many bad ISO packets received */
- unsigned long isocPacketCount; // How many packets we totally got
- unsigned long timeInIrq; // How long do we need for interrupt
- int isocMeasureBandwidthCount;
- int frame_num; // How many video frames we send to user
- int maxStripLen; // How big is the biggest strip
- int comprBlockPos;
- int stripLenErrors; // How many times was BlockPos greater than StripLen
- int stripMagicErrors;
- int stripLineNumberErrors;
- int ComprBlockTypes[4];
+ unsigned long isoc_skip_count; /* How many empty ISO packets received */
+ unsigned long isoc_err_count; /* How many bad ISO packets received */
+ unsigned long isoc_packet_count; /* How many packets we totally got */
+ unsigned long time_in_irq; /* How long do we need for interrupt */
+ int isoc_measure_bandwidth_count;
+ int frame_num; /* How many video frames we send to user */
+ int max_strip_len; /* How big is the biggest strip */
+ int comprblock_pos;
+ int strip_len_errors; /* How many times was block_pos greater than strip_len */
+ int strip_magic_errors;
+ int strip_line_number_errors;
+ int compr_block_types[4];
};
static inline struct usb_usbvision *to_usbvision(struct v4l2_device *v4l2_dev)
@@ -494,13 +495,13 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision);
int usbvision_decompress_alloc(struct usb_usbvision *usbvision);
void usbvision_decompress_free(struct usb_usbvision *usbvision);
-int usbvision_setup(struct usb_usbvision *usbvision,int format);
+int usbvision_setup(struct usb_usbvision *usbvision, int format);
int usbvision_init_isoc(struct usb_usbvision *usbvision);
int usbvision_restart_isoc(struct usb_usbvision *usbvision);
void usbvision_stop_isoc(struct usb_usbvision *usbvision);
int usbvision_set_alternate(struct usb_usbvision *dev);
-int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
+int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel);
int usbvision_audio_off(struct usb_usbvision *usbvision);
int usbvision_begin_streaming(struct usb_usbvision *usbvision);
@@ -511,9 +512,9 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel);
int usbvision_set_input(struct usb_usbvision *usbvision);
int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height);
-void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision);
-void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision);
-void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_init_power_off_timer(struct usb_usbvision *usbvision);
+void usbvision_set_power_off_timer(struct usb_usbvision *usbvision);
+void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision);
int usbvision_power_off(struct usb_usbvision *usbvision);
int usbvision_power_on(struct usb_usbvision *usbvision);
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index f169f7736677..59f8a9ad3796 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
}
}
-struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
+static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping)
{
struct uvc_control *ctrl = NULL;
@@ -944,6 +944,52 @@ done:
return ret;
}
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls that can be mapped directly, and handle the others
+ * manually.
+ */
+int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu)
+{
+ struct uvc_menu_info *menu_info;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ u32 index = query_menu->index;
+ u32 id = query_menu->id;
+ int ret;
+
+ memset(query_menu, 0, sizeof(*query_menu));
+ query_menu->id = id;
+ query_menu->index = index;
+
+ ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ ctrl = uvc_find_control(chain, query_menu->id, &mapping);
+ if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (query_menu->index >= mapping->menu_count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ menu_info = &mapping->menu_info[query_menu->index];
+ strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
+
+done:
+ mutex_unlock(&chain->ctrl_mutex);
+ return ret;
+}
+
/* --------------------------------------------------------------------------
* Control transactions
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index ed6d5449741c..f14581bd707f 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -90,6 +90,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
}
/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int __uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ unsigned int i;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffer[i].vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ if (queue->count) {
+ vfree(queue->mem);
+ queue->count = 0;
+ }
+
+ return 0;
+}
+
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = __uvc_free_buffers(queue);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
+/*
* Allocate the video buffers.
*
* Pages are reserved to make sure they will not be swapped, as they will be
@@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
mutex_lock(&queue->mutex);
- if ((ret = uvc_free_buffers(queue)) < 0)
+ if ((ret = __uvc_free_buffers(queue)) < 0)
goto done;
/* Bail out if no buffers should be allocated. */
@@ -152,28 +185,6 @@ done:
}
/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
- */
-int uvc_free_buffers(struct uvc_video_queue *queue)
-{
- unsigned int i;
-
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
-
- if (queue->count) {
- vfree(queue->mem);
- queue->count = 0;
- }
-
- return 0;
-}
-
-/*
* Check if buffers have been allocated.
*/
int uvc_queue_allocated(struct uvc_video_queue *queue)
@@ -369,6 +380,82 @@ done:
}
/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count--;
+}
+
+static const struct vm_operations_struct uvc_vm_ops = {
+ .open = uvc_vm_open,
+ .close = uvc_vm_close,
+};
+
+/*
+ * Memory-map a video buffer.
+ *
+ * This function implements video buffers memory mapping and is intended to be
+ * used by the device mmap handler.
+ */
+int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+{
+ struct uvc_buffer *uninitialized_var(buffer);
+ struct page *page;
+ unsigned long addr, start, size;
+ unsigned int i;
+ int ret = 0;
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+
+ mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == queue->count || size != queue->buf_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * VM_IO marks the area as being an mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+ while (size > 0) {
+ page = vmalloc_to_page((void *)addr);
+ if ((ret = vm_insert_page(vma, start, page)) < 0)
+ goto done;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &uvc_vm_ops;
+ vma->vm_private_data = buffer;
+ uvc_vm_open(vma);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
* Poll the video queue.
*
* This function implements video queue polling and is intended to be used by
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 6d15de9b5204..9005a8d9d5f8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -101,40 +101,6 @@ done:
*/
/*
- * Mapping V4L2 controls to UVC controls can be straighforward if done well.
- * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
- * must be grouped (for instance the Red Balance, Blue Balance and Do White
- * Balance V4L2 controls use the White Balance Component UVC control) or
- * otherwise translated. The approach we take here is to use a translation
- * table for the controls that can be mapped directly, and handle the others
- * manually.
- */
-static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu)
-{
- struct uvc_menu_info *menu_info;
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- u32 index = query_menu->index;
- u32 id = query_menu->id;
-
- ctrl = uvc_find_control(chain, query_menu->id, &mapping);
- if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
- return -EINVAL;
-
- if (query_menu->index >= mapping->menu_count)
- return -EINVAL;
-
- memset(query_menu, 0, sizeof(*query_menu));
- query_menu->id = id;
- query_menu->index = index;
-
- menu_info = &mapping->menu_info[query_menu->index];
- strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
- return 0;
-}
-
-/*
* Find the frame interval closest to the requested frame interval for the
* given frame format and size. This should be done by the device as part of
* the Video Probe and Commit negotiation, but some hardware don't implement
@@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
+ mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
goto done;
@@ -289,14 +257,21 @@ done:
static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
- struct uvc_format *format = stream->cur_format;
- struct uvc_frame *frame = stream->cur_frame;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ int ret = 0;
if (fmt->type != stream->type)
return -EINVAL;
- if (format == NULL || frame == NULL)
- return -EINVAL;
+ mutex_lock(&stream->mutex);
+ format = stream->cur_format;
+ frame = stream->cur_frame;
+
+ if (format == NULL || frame == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth;
@@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream,
fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_set_format(struct uvc_streaming *stream,
@@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
if (fmt->type != stream->type)
return -EINVAL;
- if (uvc_queue_allocated(&stream->queue))
- return -EBUSY;
-
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0)
return ret;
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_allocated(&stream->queue)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
memcpy(&stream->ctrl, &probe, sizeof probe);
stream->cur_format = format;
stream->cur_frame = frame;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
@@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
+ mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval;
+ mutex_unlock(&stream->mutex);
+
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
@@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
- struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
uint32_t interval;
@@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
- if (uvc_queue_streaming(&stream->queue))
- return -EBUSY;
-
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
timeperframe = parm->parm.capture.timeperframe;
else
timeperframe = parm->parm.output.timeperframe;
- memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator);
-
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
timeperframe.numerator, timeperframe.denominator, interval);
- probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_streaming(&stream->queue)) {
+ mutex_unlock(&stream->mutex);
+ return -EBUSY;
+ }
+
+ memcpy(&probe, &stream->ctrl, sizeof probe);
+ probe.dwFrameInterval =
+ uvc_try_frame_interval(stream->cur_frame, interval);
/* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe);
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&stream->mutex);
return ret;
+ }
memcpy(&stream->ctrl, &probe, sizeof probe);
+ mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
@@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file)
if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0);
- mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n");
- mutex_unlock(&stream->queue.mutex);
}
/* Release the file handle. */
@@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
case VIDIOC_QUERYMENU:
- return uvc_v4l2_query_menu(chain, arg);
+ return uvc_query_v4l2_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS:
{
@@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
- struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != stream->type)
return -EINVAL;
ccap->bounds.left = 0;
ccap->bounds.top = 0;
- ccap->bounds.width = frame->wWidth;
- ccap->bounds.height = frame->wHeight;
+
+ mutex_lock(&stream->mutex);
+ ccap->bounds.width = stream->cur_frame->wWidth;
+ ccap->bounds.height = stream->cur_frame->wHeight;
+ mutex_unlock(&stream->mutex);
ccap->defrect = ccap->bounds;
@@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *rb = arg;
- unsigned int bufsize =
- stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP)
@@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
+ mutex_lock(&stream->mutex);
+ ret = uvc_alloc_buffers(&stream->queue, rb->count,
+ stream->ctrl.dwMaxVideoFrameSize);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
@@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!uvc_has_privileges(handle))
return -EBUSY;
+ mutex_lock(&stream->mutex);
ret = uvc_video_enable(stream, 1);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
break;
@@ -1039,11 +1035,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_xu_ctrl_query(chain, arg, 1);
default:
- if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
- uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
- uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
- cmd);
- return ret;
+ uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
+ return -EINVAL;
}
return ret;
@@ -1068,79 +1061,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
return -EINVAL;
}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
-}
-
-static void uvc_vm_close(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
-}
-
-static const struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
-
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
-
- mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || size != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ return uvc_queue_mmap(&stream->queue, vma);
}
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
@@ -1157,7 +1085,7 @@ const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
- .ioctl = uvc_v4l2_ioctl,
+ .unlocked_ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 5555f0102838..5673d673504b 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
unsigned int i;
int ret;
- mutex_lock(&stream->mutex);
-
/* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video
@@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
}
done:
- mutex_unlock(&stream->mutex);
return ret;
}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d97cf6d6a4f9..45f01e7e13d2 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -436,7 +436,9 @@ struct uvc_streaming {
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
-
+ /* Protect access to ctrl, cur_format, cur_frame and hardware video
+ * probe control.
+ */
struct mutex mutex;
unsigned int frozen : 1;
@@ -574,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf);
+extern int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
@@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
-extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
- __u32 v4l2_id, struct uvc_control_mapping **mapping);
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl);
+extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu);
extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
const struct uvc_control_mapping *mapping);
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
deleted file mode 100644
index d4ac751036a2..000000000000
--- a/drivers/media/video/v4l1-compat.c
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- *
- * Video for Linux Two
- * Backward Compatibility Layer
- *
- * Support subroutines for providing V4L2 drivers with backward
- * compatibility with applications using the old API.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Author: Bill Dirks <bill@thedirks.org>
- * et al.
- *
- */
-
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-MODULE_AUTHOR("Bill Dirks");
-MODULE_DESCRIPTION("v4l(1) compatibility layer for v4l2 drivers.");
-MODULE_LICENSE("GPL");
-
-#define dprintk(fmt, arg...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg);\
- } while (0)
-
-/*
- * I O C T L T R A N S L A T I O N
- *
- * From here on down is the code for translating the numerous
- * ioctl commands from the old API to the new API.
- */
-
-static int
-get_v4l_control(struct file *file,
- int cid,
- v4l2_kioctl drv)
-{
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
-
- qctrl2.id = cid;
- err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
- if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n", err);
- if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl2.id = qctrl2.id;
- err = drv(file, VIDIOC_G_CTRL, &ctrl2);
- if (err < 0) {
- dprintk("VIDIOC_G_CTRL: %d\n", err);
- return 0;
- }
- return DIV_ROUND_CLOSEST((ctrl2.value-qctrl2.minimum) * 65535,
- qctrl2.maximum - qctrl2.minimum);
- }
- return 0;
-}
-
-static int
-set_v4l_control(struct file *file,
- int cid,
- int value,
- v4l2_kioctl drv)
-{
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
-
- qctrl2.id = cid;
- err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
- if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n", err);
- if (err == 0 &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) {
- if (value < 0)
- value = 0;
- if (value > 65535)
- value = 65535;
- if (value && qctrl2.type == V4L2_CTRL_TYPE_BOOLEAN)
- value = 65535;
- ctrl2.id = qctrl2.id;
- ctrl2.value =
- (value * (qctrl2.maximum - qctrl2.minimum)
- + 32767)
- / 65535;
- ctrl2.value += qctrl2.minimum;
- err = drv(file, VIDIOC_S_CTRL, &ctrl2);
- if (err < 0)
- dprintk("VIDIOC_S_CTRL: %d\n", err);
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------- */
-
-static const unsigned int palette2pixelformat[] = {
- [VIDEO_PALETTE_GREY] = V4L2_PIX_FMT_GREY,
- [VIDEO_PALETTE_RGB555] = V4L2_PIX_FMT_RGB555,
- [VIDEO_PALETTE_RGB565] = V4L2_PIX_FMT_RGB565,
- [VIDEO_PALETTE_RGB24] = V4L2_PIX_FMT_BGR24,
- [VIDEO_PALETTE_RGB32] = V4L2_PIX_FMT_BGR32,
- /* yuv packed pixel */
- [VIDEO_PALETTE_YUYV] = V4L2_PIX_FMT_YUYV,
- [VIDEO_PALETTE_YUV422] = V4L2_PIX_FMT_YUYV,
- [VIDEO_PALETTE_UYVY] = V4L2_PIX_FMT_UYVY,
- /* yuv planar */
- [VIDEO_PALETTE_YUV410P] = V4L2_PIX_FMT_YUV410,
- [VIDEO_PALETTE_YUV420] = V4L2_PIX_FMT_YUV420,
- [VIDEO_PALETTE_YUV420P] = V4L2_PIX_FMT_YUV420,
- [VIDEO_PALETTE_YUV411P] = V4L2_PIX_FMT_YUV411P,
- [VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P,
-};
-
-static unsigned int __pure
-palette_to_pixelformat(unsigned int palette)
-{
- if (palette < ARRAY_SIZE(palette2pixelformat))
- return palette2pixelformat[palette];
- else
- return 0;
-}
-
-static unsigned int __attribute_const__
-pixelformat_to_palette(unsigned int pixelformat)
-{
- int palette = 0;
- switch (pixelformat) {
- case V4L2_PIX_FMT_GREY:
- palette = VIDEO_PALETTE_GREY;
- break;
- case V4L2_PIX_FMT_RGB555:
- palette = VIDEO_PALETTE_RGB555;
- break;
- case V4L2_PIX_FMT_RGB565:
- palette = VIDEO_PALETTE_RGB565;
- break;
- case V4L2_PIX_FMT_BGR24:
- palette = VIDEO_PALETTE_RGB24;
- break;
- case V4L2_PIX_FMT_BGR32:
- palette = VIDEO_PALETTE_RGB32;
- break;
- /* yuv packed pixel */
- case V4L2_PIX_FMT_YUYV:
- palette = VIDEO_PALETTE_YUYV;
- break;
- case V4L2_PIX_FMT_UYVY:
- palette = VIDEO_PALETTE_UYVY;
- break;
- /* yuv planar */
- case V4L2_PIX_FMT_YUV410:
- palette = VIDEO_PALETTE_YUV420;
- break;
- case V4L2_PIX_FMT_YUV420:
- palette = VIDEO_PALETTE_YUV420;
- break;
- case V4L2_PIX_FMT_YUV411P:
- palette = VIDEO_PALETTE_YUV411P;
- break;
- case V4L2_PIX_FMT_YUV422P:
- palette = VIDEO_PALETTE_YUV422P;
- break;
- }
- return palette;
-}
-
-/* ----------------------------------------------------------------- */
-
-static int poll_one(struct file *file, struct poll_wqueues *pwq)
-{
- int retval = 1;
- poll_table *table;
-
- poll_initwait(pwq);
- table = &pwq->pt;
- for (;;) {
- int mask;
- mask = file->f_op->poll(file, table);
- if (mask & POLLIN)
- break;
- table = NULL;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- poll_schedule(pwq, TASK_INTERRUPTIBLE);
- }
- poll_freewait(pwq);
- return retval;
-}
-
-static int count_inputs(
- struct file *file,
- v4l2_kioctl drv)
-{
- struct v4l2_input input2;
- int i;
-
- for (i = 0;; i++) {
- memset(&input2, 0, sizeof(input2));
- input2.index = i;
- if (0 != drv(file, VIDIOC_ENUMINPUT, &input2))
- break;
- }
- return i;
-}
-
-static int check_size(
- struct file *file,
- v4l2_kioctl drv,
- int *maxw,
- int *maxh)
-{
- struct v4l2_fmtdesc desc2;
- struct v4l2_format fmt2;
-
- memset(&desc2, 0, sizeof(desc2));
- memset(&fmt2, 0, sizeof(fmt2));
-
- desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (0 != drv(file, VIDIOC_ENUM_FMT, &desc2))
- goto done;
-
- fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt2.fmt.pix.width = 10000;
- fmt2.fmt.pix.height = 10000;
- fmt2.fmt.pix.pixelformat = desc2.pixelformat;
- if (0 != drv(file, VIDIOC_TRY_FMT, &fmt2))
- goto done;
-
- *maxw = fmt2.fmt.pix.width;
- *maxh = fmt2.fmt.pix.height;
-
-done:
- return 0;
-}
-
-/* ----------------------------------------------------------------- */
-
-static noinline long v4l1_compat_get_capabilities(
- struct video_capability *cap,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
- struct v4l2_capability *cap2;
-
- cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL);
- if (!cap2) {
- err = -ENOMEM;
- return err;
- }
- memset(cap, 0, sizeof(*cap));
- memset(&fbuf, 0, sizeof(fbuf));
-
- err = drv(file, VIDIOC_QUERYCAP, cap2);
- if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %ld\n", err);
- goto done;
- }
- if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
- err = drv(file, VIDIOC_G_FBUF, &fbuf);
- if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %ld\n", err);
- memset(&fbuf, 0, sizeof(fbuf));
- }
- err = 0;
- }
-
- memcpy(cap->name, cap2->card,
- min(sizeof(cap->name), sizeof(cap2->card)));
- cap->name[sizeof(cap->name) - 1] = 0;
- if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE)
- cap->type |= VID_TYPE_CAPTURE;
- if (cap2->capabilities & V4L2_CAP_TUNER)
- cap->type |= VID_TYPE_TUNER;
- if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE)
- cap->type |= VID_TYPE_TELETEXT;
- if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY)
- cap->type |= VID_TYPE_OVERLAY;
- if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
- cap->type |= VID_TYPE_CLIPPING;
-
- cap->channels = count_inputs(file, drv);
- check_size(file, drv,
- &cap->maxwidth, &cap->maxheight);
- cap->audios = 0; /* FIXME */
- cap->minwidth = 48; /* FIXME */
- cap->minheight = 32; /* FIXME */
-
-done:
- kfree(cap2);
- return err;
-}
-
-static noinline long v4l1_compat_get_frame_buffer(
- struct video_buffer *buffer,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
-
- memset(buffer, 0, sizeof(*buffer));
- memset(&fbuf, 0, sizeof(fbuf));
-
- err = drv(file, VIDIOC_G_FBUF, &fbuf);
- if (err < 0) {
- dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %ld\n", err);
- goto done;
- }
- buffer->base = fbuf.base;
- buffer->height = fbuf.fmt.height;
- buffer->width = fbuf.fmt.width;
-
- switch (fbuf.fmt.pixelformat) {
- case V4L2_PIX_FMT_RGB332:
- buffer->depth = 8;
- break;
- case V4L2_PIX_FMT_RGB555:
- buffer->depth = 15;
- break;
- case V4L2_PIX_FMT_RGB565:
- buffer->depth = 16;
- break;
- case V4L2_PIX_FMT_BGR24:
- buffer->depth = 24;
- break;
- case V4L2_PIX_FMT_BGR32:
- buffer->depth = 32;
- break;
- default:
- buffer->depth = 0;
- }
- if (fbuf.fmt.bytesperline) {
- buffer->bytesperline = fbuf.fmt.bytesperline;
- if (!buffer->depth && buffer->width)
- buffer->depth = ((fbuf.fmt.bytesperline<<3)
- + (buffer->width-1))
- / buffer->width;
- } else {
- buffer->bytesperline =
- (buffer->width * buffer->depth + 7) & 7;
- buffer->bytesperline >>= 3;
- }
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_frame_buffer(
- struct video_buffer *buffer,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
-
- memset(&fbuf, 0, sizeof(fbuf));
- fbuf.base = buffer->base;
- fbuf.fmt.height = buffer->height;
- fbuf.fmt.width = buffer->width;
- switch (buffer->depth) {
- case 8:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
- break;
- case 15:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
- break;
- case 16:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 24:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- break;
- case 32:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
- break;
- }
- fbuf.fmt.bytesperline = buffer->bytesperline;
- err = drv(file, VIDIOC_S_FBUF, &fbuf);
- if (err < 0)
- dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_win_cap_dimensions(
- struct video_window *win,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(win, 0, sizeof(*win));
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0)
- dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %ld\n", err);
- if (err == 0) {
- win->x = fmt->fmt.win.w.left;
- win->y = fmt->fmt.win.w.top;
- win->width = fmt->fmt.win.w.width;
- win->height = fmt->fmt.win.w.height;
- win->chromakey = fmt->fmt.win.chromakey;
- win->clips = NULL;
- win->clipcount = 0;
- goto done;
- }
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- win->x = 0;
- win->y = 0;
- win->width = fmt->fmt.pix.width;
- win->height = fmt->fmt.pix.height;
- win->chromakey = 0;
- win->clips = NULL;
- win->clipcount = 0;
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_set_win_cap_dimensions(
- struct video_window *win,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err, err1, err2;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- drv(file, VIDIOC_STREAMOFF, &fmt->type);
- err1 = drv(file, VIDIOC_G_FMT, fmt);
- if (err1 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %ld\n", err1);
- if (err1 == 0) {
- fmt->fmt.pix.width = win->width;
- fmt->fmt.pix.height = win->height;
- fmt->fmt.pix.field = V4L2_FIELD_ANY;
- fmt->fmt.pix.bytesperline = 0;
- err = drv(file, VIDIOC_S_FMT, fmt);
- if (err < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %ld\n",
- err);
- win->width = fmt->fmt.pix.width;
- win->height = fmt->fmt.pix.height;
- }
-
- memset(fmt, 0, sizeof(*fmt));
- fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- fmt->fmt.win.w.left = win->x;
- fmt->fmt.win.w.top = win->y;
- fmt->fmt.win.w.width = win->width;
- fmt->fmt.win.w.height = win->height;
- fmt->fmt.win.chromakey = win->chromakey;
- fmt->fmt.win.clips = (void __user *)win->clips;
- fmt->fmt.win.clipcount = win->clipcount;
- err2 = drv(file, VIDIOC_S_FMT, fmt);
- if (err2 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %ld\n", err2);
-
- if (err1 != 0 && err2 != 0)
- err = err1;
- else
- err = 0;
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_turn_preview_on_off(
- int *on,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (0 == *on) {
- /* dirty hack time. But v4l1 has no STREAMOFF
- * equivalent in the API, and this one at
- * least comes close ... */
- drv(file, VIDIOC_STREAMOFF, &captype);
- }
- err = drv(file, VIDIOC_OVERLAY, on);
- if (err < 0)
- dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_input_info(
- struct video_channel *chan,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_input input2;
- v4l2_std_id sid;
-
- memset(&input2, 0, sizeof(input2));
- input2.index = chan->channel;
- err = drv(file, VIDIOC_ENUMINPUT, &input2);
- if (err < 0) {
- dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
- "channel=%d err=%ld\n", chan->channel, err);
- goto done;
- }
- chan->channel = input2.index;
- memcpy(chan->name, input2.name,
- min(sizeof(chan->name), sizeof(input2.name)));
- chan->name[sizeof(chan->name) - 1] = 0;
- chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0;
- chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0;
- switch (input2.type) {
- case V4L2_INPUT_TYPE_TUNER:
- chan->type = VIDEO_TYPE_TV;
- break;
- default:
- case V4L2_INPUT_TYPE_CAMERA:
- chan->type = VIDEO_TYPE_CAMERA;
- break;
- }
- chan->norm = 0;
- /* Note: G_STD might not be present for radio receivers,
- * so we should ignore any errors. */
- if (drv(file, VIDIOC_G_STD, &sid) == 0) {
- if (sid & V4L2_STD_PAL)
- chan->norm = VIDEO_MODE_PAL;
- if (sid & V4L2_STD_NTSC)
- chan->norm = VIDEO_MODE_NTSC;
- if (sid & V4L2_STD_SECAM)
- chan->norm = VIDEO_MODE_SECAM;
- if (sid == V4L2_STD_ALL)
- chan->norm = VIDEO_MODE_AUTO;
- }
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_input(
- struct video_channel *chan,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- v4l2_std_id sid = 0;
-
- err = drv(file, VIDIOC_S_INPUT, &chan->channel);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %ld\n", err);
- switch (chan->norm) {
- case VIDEO_MODE_PAL:
- sid = V4L2_STD_PAL;
- break;
- case VIDEO_MODE_NTSC:
- sid = V4L2_STD_NTSC;
- break;
- case VIDEO_MODE_SECAM:
- sid = V4L2_STD_SECAM;
- break;
- case VIDEO_MODE_AUTO:
- sid = V4L2_STD_ALL;
- break;
- }
- if (0 != sid) {
- err = drv(file, VIDIOC_S_STD, &sid);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %ld\n", err);
- }
- return err;
-}
-
-static noinline long v4l1_compat_get_picture(
- struct video_picture *pict,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
-
- pict->brightness = get_v4l_control(file,
- V4L2_CID_BRIGHTNESS, drv);
- pict->hue = get_v4l_control(file,
- V4L2_CID_HUE, drv);
- pict->contrast = get_v4l_control(file,
- V4L2_CID_CONTRAST, drv);
- pict->colour = get_v4l_control(file,
- V4L2_CID_SATURATION, drv);
- pict->whiteness = get_v4l_control(file,
- V4L2_CID_WHITENESS, drv);
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
-
- if (fmt->fmt.pix.width)
- {
- pict->depth = ((fmt->fmt.pix.bytesperline << 3)
- + (fmt->fmt.pix.width - 1))
- / fmt->fmt.pix.width;
- } else {
- err = -EINVAL;
- goto done;
- }
-
- pict->palette = pixelformat_to_palette(
- fmt->fmt.pix.pixelformat);
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_set_picture(
- struct video_picture *pict,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
- int mem_err = 0, ovl_err = 0;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(&fbuf, 0, sizeof(fbuf));
-
- set_v4l_control(file,
- V4L2_CID_BRIGHTNESS, pict->brightness, drv);
- set_v4l_control(file,
- V4L2_CID_HUE, pict->hue, drv);
- set_v4l_control(file,
- V4L2_CID_CONTRAST, pict->contrast, drv);
- set_v4l_control(file,
- V4L2_CID_SATURATION, pict->colour, drv);
- set_v4l_control(file,
- V4L2_CID_WHITENESS, pict->whiteness, drv);
- /*
- * V4L1 uses this ioctl to set both memory capture and overlay
- * pixel format, while V4L2 has two different ioctls for this.
- * Some cards may not support one or the other, and may support
- * different pixel formats for memory vs overlay.
- */
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- /* If VIDIOC_G_FMT failed, then the driver likely doesn't
- support memory capture. Trying to set the memory capture
- parameters would be pointless. */
- if (err < 0) {
- dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %ld\n", err);
- mem_err = -1000; /* didn't even try */
- } else if (fmt->fmt.pix.pixelformat !=
- palette_to_pixelformat(pict->palette)) {
- fmt->fmt.pix.pixelformat = palette_to_pixelformat(
- pict->palette);
- mem_err = drv(file, VIDIOC_S_FMT, fmt);
- if (mem_err < 0)
- dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
- mem_err);
- }
-
- err = drv(file, VIDIOC_G_FBUF, &fbuf);
- /* If VIDIOC_G_FBUF failed, then the driver likely doesn't
- support overlay. Trying to set the overlay parameters
- would be quite pointless. */
- if (err < 0) {
- dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %ld\n", err);
- ovl_err = -1000; /* didn't even try */
- } else if (fbuf.fmt.pixelformat !=
- palette_to_pixelformat(pict->palette)) {
- fbuf.fmt.pixelformat = palette_to_pixelformat(
- pict->palette);
- ovl_err = drv(file, VIDIOC_S_FBUF, &fbuf);
- if (ovl_err < 0)
- dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n",
- ovl_err);
- }
- if (ovl_err < 0 && mem_err < 0) {
- /* ioctl failed, couldn't set either parameter */
- if (mem_err != -1000)
- err = mem_err;
- else if (ovl_err == -EPERM)
- err = 0;
- else
- err = ovl_err;
- } else
- err = 0;
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_get_tuner(
- struct video_tuner *tun,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- int i;
- struct v4l2_tuner tun2;
- struct v4l2_standard std2;
- v4l2_std_id sid;
-
- memset(&tun2, 0, sizeof(tun2));
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %ld\n", err);
- goto done;
- }
- memcpy(tun->name, tun2.name,
- min(sizeof(tun->name), sizeof(tun2.name)));
- tun->name[sizeof(tun->name) - 1] = 0;
- tun->rangelow = tun2.rangelow;
- tun->rangehigh = tun2.rangehigh;
- tun->flags = 0;
- tun->mode = VIDEO_MODE_AUTO;
-
- for (i = 0; i < 64; i++) {
- memset(&std2, 0, sizeof(std2));
- std2.index = i;
- if (0 != drv(file, VIDIOC_ENUMSTD, &std2))
- break;
- if (std2.id & V4L2_STD_PAL)
- tun->flags |= VIDEO_TUNER_PAL;
- if (std2.id & V4L2_STD_NTSC)
- tun->flags |= VIDEO_TUNER_NTSC;
- if (std2.id & V4L2_STD_SECAM)
- tun->flags |= VIDEO_TUNER_SECAM;
- }
-
- /* Note: G_STD might not be present for radio receivers,
- * so we should ignore any errors. */
- if (drv(file, VIDIOC_G_STD, &sid) == 0) {
- if (sid & V4L2_STD_PAL)
- tun->mode = VIDEO_MODE_PAL;
- if (sid & V4L2_STD_NTSC)
- tun->mode = VIDEO_MODE_NTSC;
- if (sid & V4L2_STD_SECAM)
- tun->mode = VIDEO_MODE_SECAM;
- }
-
- if (tun2.capability & V4L2_TUNER_CAP_LOW)
- tun->flags |= VIDEO_TUNER_LOW;
- if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
- tun->flags |= VIDEO_TUNER_STEREO_ON;
- tun->signal = tun2.signal;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_select_tuner(
- struct video_tuner *tun,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_tuner t;/*84 bytes on x86_64*/
- memset(&t, 0, sizeof(t));
-
- t.index = tun->tuner;
-
- err = drv(file, VIDIOC_S_TUNER, &t);
- if (err < 0)
- dprintk("VIDIOCSTUNER / VIDIOC_S_TUNER: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_frequency(
- unsigned long *freq,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_frequency freq2;
- memset(&freq2, 0, sizeof(freq2));
-
- freq2.tuner = 0;
- err = drv(file, VIDIOC_G_FREQUENCY, &freq2);
- if (err < 0)
- dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %ld\n", err);
- if (0 == err)
- *freq = freq2.frequency;
- return err;
-}
-
-static noinline long v4l1_compat_set_frequency(
- unsigned long *freq,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_frequency freq2;
- memset(&freq2, 0, sizeof(freq2));
-
- drv(file, VIDIOC_G_FREQUENCY, &freq2);
- freq2.frequency = *freq;
- err = drv(file, VIDIOC_S_FREQUENCY, &freq2);
- if (err < 0)
- dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_audio(
- struct video_audio *aud,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- int i;
- struct v4l2_queryctrl qctrl2;
- struct v4l2_audio aud2;
- struct v4l2_tuner tun2;
- memset(&aud2, 0, sizeof(aud2));
-
- err = drv(file, VIDIOC_G_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %ld\n", err);
- goto done;
- }
- memcpy(aud->name, aud2.name,
- min(sizeof(aud->name), sizeof(aud2.name)));
- aud->name[sizeof(aud->name) - 1] = 0;
- aud->audio = aud2.index;
- aud->flags = 0;
- i = get_v4l_control(file, V4L2_CID_AUDIO_VOLUME, drv);
- if (i >= 0) {
- aud->volume = i;
- aud->flags |= VIDEO_AUDIO_VOLUME;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_BASS, drv);
- if (i >= 0) {
- aud->bass = i;
- aud->flags |= VIDEO_AUDIO_BASS;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_TREBLE, drv);
- if (i >= 0) {
- aud->treble = i;
- aud->flags |= VIDEO_AUDIO_TREBLE;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_BALANCE, drv);
- if (i >= 0) {
- aud->balance = i;
- aud->flags |= VIDEO_AUDIO_BALANCE;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_MUTE, drv);
- if (i >= 0) {
- if (i)
- aud->flags |= VIDEO_AUDIO_MUTE;
- aud->flags |= VIDEO_AUDIO_MUTABLE;
- }
- aud->step = 1;
- qctrl2.id = V4L2_CID_AUDIO_VOLUME;
- if (drv(file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
- aud->step = qctrl2.step;
- aud->mode = 0;
-
- memset(&tun2, 0, sizeof(tun2));
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %ld\n", err);
- err = 0;
- goto done;
- }
-
- if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
- aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
- aud->mode = VIDEO_SOUND_STEREO;
- else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO)
- aud->mode = VIDEO_SOUND_MONO;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_audio(
- struct video_audio *aud,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_audio aud2;
- struct v4l2_tuner tun2;
-
- memset(&aud2, 0, sizeof(aud2));
- memset(&tun2, 0, sizeof(tun2));
-
- aud2.index = aud->audio;
- err = drv(file, VIDIOC_S_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %ld\n", err);
- goto done;
- }
-
- set_v4l_control(file, V4L2_CID_AUDIO_VOLUME,
- aud->volume, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_BASS,
- aud->bass, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_TREBLE,
- aud->treble, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_BALANCE,
- aud->balance, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_MUTE,
- !!(aud->flags & VIDEO_AUDIO_MUTE), drv);
-
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %ld\n", err);
- if (err == 0) {
- switch (aud->mode) {
- default:
- case VIDEO_SOUND_MONO:
- case VIDEO_SOUND_LANG1:
- tun2.audmode = V4L2_TUNER_MODE_MONO;
- break;
- case VIDEO_SOUND_STEREO:
- tun2.audmode = V4L2_TUNER_MODE_STEREO;
- break;
- case VIDEO_SOUND_LANG2:
- tun2.audmode = V4L2_TUNER_MODE_LANG2;
- break;
- }
- err = drv(file, VIDIOC_S_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %ld\n", err);
- }
- err = 0;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_capture_frame(
- struct video_mmap *mm,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- struct v4l2_buffer buf;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(&buf, 0, sizeof(buf));
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- if (mm->width != fmt->fmt.pix.width ||
- mm->height != fmt->fmt.pix.height ||
- palette_to_pixelformat(mm->format) !=
- fmt->fmt.pix.pixelformat) {
- /* New capture format... */
- fmt->fmt.pix.width = mm->width;
- fmt->fmt.pix.height = mm->height;
- fmt->fmt.pix.pixelformat =
- palette_to_pixelformat(mm->format);
- fmt->fmt.pix.field = V4L2_FIELD_ANY;
- fmt->fmt.pix.bytesperline = 0;
- err = drv(file, VIDIOC_S_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %ld\n", err);
- goto done;
- }
- }
- buf.index = mm->frame;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %ld\n", err);
- goto done;
- }
- err = drv(file, VIDIOC_QBUF, &buf);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %ld\n", err);
- goto done;
- }
- err = drv(file, VIDIOC_STREAMON, &captype);
- if (err < 0)
- dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %ld\n", err);
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_sync(
- int *i,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- struct v4l2_buffer buf;
- struct poll_wqueues *pwq;
-
- memset(&buf, 0, sizeof(buf));
- buf.index = *i;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0) {
- /* No such buffer */
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
- goto done;
- }
- if (!(buf.flags & V4L2_BUF_FLAG_MAPPED)) {
- /* Buffer is not mapped */
- err = -EINVAL;
- goto done;
- }
-
- /* make sure capture actually runs so we don't block forever */
- err = drv(file, VIDIOC_STREAMON, &captype);
- if (err < 0) {
- dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %ld\n", err);
- goto done;
- }
-
- pwq = kmalloc(sizeof(*pwq), GFP_KERNEL);
- /* Loop as long as the buffer is queued, but not done */
- while ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
- == V4L2_BUF_FLAG_QUEUED) {
- err = poll_one(file, pwq);
- if (err < 0 || /* error or sleep was interrupted */
- err == 0) /* timeout? Shouldn't occur. */
- break;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
- }
- kfree(pwq);
- if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
- goto done;
- do {
- err = drv(file, VIDIOC_DQBUF, &buf);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %ld\n", err);
- } while (err == 0 && buf.index != *i);
-done:
- return err;
-}
-
-static noinline long v4l1_compat_get_vbi_format(
- struct vbi_format *fmt,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt2;
-
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- return err;
- }
- fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-
- err = drv(file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
- err = -EINVAL;
- goto done;
- }
- memset(fmt, 0, sizeof(*fmt));
- fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
- fmt->sampling_rate = fmt2->fmt.vbi.sampling_rate;
- fmt->sample_format = VIDEO_PALETTE_RAW;
- fmt->start[0] = fmt2->fmt.vbi.start[0];
- fmt->count[0] = fmt2->fmt.vbi.count[0];
- fmt->start[1] = fmt2->fmt.vbi.start[1];
- fmt->count[1] = fmt2->fmt.vbi.count[1];
- fmt->flags = fmt2->fmt.vbi.flags & 0x03;
-done:
- kfree(fmt2);
- return err;
-}
-
-static noinline long v4l1_compat_set_vbi_format(
- struct vbi_format *fmt,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt2 = NULL;
-
- if (VIDEO_PALETTE_RAW != fmt->sample_format) {
- err = -EINVAL;
- return err;
- }
-
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- return err;
- }
- fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line;
- fmt2->fmt.vbi.sampling_rate = fmt->sampling_rate;
- fmt2->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- fmt2->fmt.vbi.start[0] = fmt->start[0];
- fmt2->fmt.vbi.count[0] = fmt->count[0];
- fmt2->fmt.vbi.start[1] = fmt->start[1];
- fmt2->fmt.vbi.count[1] = fmt->count[1];
- fmt2->fmt.vbi.flags = fmt->flags;
- err = drv(file, VIDIOC_TRY_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %ld\n", err);
- goto done;
- }
-
- if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
- fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate ||
- fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY ||
- fmt2->fmt.vbi.start[0] != fmt->start[0] ||
- fmt2->fmt.vbi.count[0] != fmt->count[0] ||
- fmt2->fmt.vbi.start[1] != fmt->start[1] ||
- fmt2->fmt.vbi.count[1] != fmt->count[1] ||
- fmt2->fmt.vbi.flags != fmt->flags) {
- err = -EINVAL;
- goto done;
- }
- err = drv(file, VIDIOC_S_FMT, fmt2);
- if (err < 0)
- dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %ld\n", err);
-done:
- kfree(fmt2);
- return err;
-}
-
-/*
- * This function is exported.
- */
-long
-v4l_compat_translate_ioctl(struct file *file,
- int cmd,
- void *arg,
- v4l2_kioctl drv)
-{
- long err;
-
- switch (cmd) {
- case VIDIOCGCAP: /* capability */
- err = v4l1_compat_get_capabilities(arg, file, drv);
- break;
- case VIDIOCGFBUF: /* get frame buffer */
- err = v4l1_compat_get_frame_buffer(arg, file, drv);
- break;
- case VIDIOCSFBUF: /* set frame buffer */
- err = v4l1_compat_set_frame_buffer(arg, file, drv);
- break;
- case VIDIOCGWIN: /* get window or capture dimensions */
- err = v4l1_compat_get_win_cap_dimensions(arg, file, drv);
- break;
- case VIDIOCSWIN: /* set window and/or capture dimensions */
- err = v4l1_compat_set_win_cap_dimensions(arg, file, drv);
- break;
- case VIDIOCCAPTURE: /* turn on/off preview */
- err = v4l1_compat_turn_preview_on_off(arg, file, drv);
- break;
- case VIDIOCGCHAN: /* get input information */
- err = v4l1_compat_get_input_info(arg, file, drv);
- break;
- case VIDIOCSCHAN: /* set input */
- err = v4l1_compat_set_input(arg, file, drv);
- break;
- case VIDIOCGPICT: /* get tone controls & partial capture format */
- err = v4l1_compat_get_picture(arg, file, drv);
- break;
- case VIDIOCSPICT: /* set tone controls & partial capture format */
- err = v4l1_compat_set_picture(arg, file, drv);
- break;
- case VIDIOCGTUNER: /* get tuner information */
- err = v4l1_compat_get_tuner(arg, file, drv);
- break;
- case VIDIOCSTUNER: /* select a tuner input */
- err = v4l1_compat_select_tuner(arg, file, drv);
- break;
- case VIDIOCGFREQ: /* get frequency */
- err = v4l1_compat_get_frequency(arg, file, drv);
- break;
- case VIDIOCSFREQ: /* set frequency */
- err = v4l1_compat_set_frequency(arg, file, drv);
- break;
- case VIDIOCGAUDIO: /* get audio properties/controls */
- err = v4l1_compat_get_audio(arg, file, drv);
- break;
- case VIDIOCSAUDIO: /* set audio controls */
- err = v4l1_compat_set_audio(arg, file, drv);
- break;
- case VIDIOCMCAPTURE: /* capture a frame */
- err = v4l1_compat_capture_frame(arg, file, drv);
- break;
- case VIDIOCSYNC: /* wait for a frame */
- err = v4l1_compat_sync(arg, file, drv);
- break;
- case VIDIOCGVBIFMT: /* query VBI data capture format */
- err = v4l1_compat_get_vbi_format(arg, file, drv);
- break;
- case VIDIOCSVBIFMT:
- err = v4l1_compat_set_vbi_format(arg, file, drv);
- break;
- default:
- err = -ENOIOCTLCMD;
- break;
- }
-
- return err;
-}
-EXPORT_SYMBOL(v4l_compat_translate_ioctl);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 9294282b5add..3f0871b550ad 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -150,7 +150,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
struct v4l2_queryctrl and the available menu items. Note that
menu_items may be NULL, in that case it is ignored. */
int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
- const char **menu_items)
+ const char * const *menu_items)
{
if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
return -EINVAL;
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
If menu_items is NULL, then the menu items are retrieved using
v4l2_ctrl_get_menu. */
int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
- const char **menu_items)
+ const char * const *menu_items)
{
int i;
@@ -222,7 +222,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
Use this if there are 'holes' in the list of valid menu items. */
int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
{
- const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+ const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
qmenu->reserved = 0;
if (menu_items == NULL || ids == NULL)
@@ -368,18 +368,15 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs)
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+ const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
BUG_ON(!v4l2_dev);
- if (module_name)
- request_module(module_name);
- else
- request_module(I2C_MODULE_PREFIX "%s", info->type);
+ request_module(I2C_MODULE_PREFIX "%s", info->type);
/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
@@ -432,8 +429,7 @@ error:
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
+ struct i2c_adapter *adapter, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
@@ -447,8 +443,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
info.irq = irq;
info.platform_data = platform_data;
- return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
- &info, probe_addrs);
+ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 86294ed35c9b..dc82eb83c1d4 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -15,220 +15,12 @@
#include <linux/compat.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
-#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-ioctl.h>
#ifdef CONFIG_COMPAT
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-struct video_tuner32 {
- compat_int_t tuner;
- char name[32];
- compat_ulong_t rangelow, rangehigh;
- u32 flags; /* It is really u32 in videodev.h */
- u16 mode, signal;
-};
-
-static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
- get_user(kp->tuner, &up->tuner) ||
- copy_from_user(kp->name, up->name, 32) ||
- get_user(kp->rangelow, &up->rangelow) ||
- get_user(kp->rangehigh, &up->rangehigh) ||
- get_user(kp->flags, &up->flags) ||
- get_user(kp->mode, &up->mode) ||
- get_user(kp->signal, &up->signal))
- return -EFAULT;
- return 0;
-}
-
-static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
- put_user(kp->tuner, &up->tuner) ||
- copy_to_user(up->name, kp->name, 32) ||
- put_user(kp->rangelow, &up->rangelow) ||
- put_user(kp->rangehigh, &up->rangehigh) ||
- put_user(kp->flags, &up->flags) ||
- put_user(kp->mode, &up->mode) ||
- put_user(kp->signal, &up->signal))
- return -EFAULT;
- return 0;
-}
-
-struct video_buffer32 {
- compat_caddr_t base;
- compat_int_t height, width, depth, bytesperline;
-};
-
-static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
- get_user(tmp, &up->base) ||
- get_user(kp->height, &up->height) ||
- get_user(kp->width, &up->width) ||
- get_user(kp->depth, &up->depth) ||
- get_user(kp->bytesperline, &up->bytesperline))
- return -EFAULT;
-
- /* This is actually a physical address stored
- * as a void pointer.
- */
- kp->base = (void *)(unsigned long) tmp;
-
- return 0;
-}
-
-static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp = (u32)((unsigned long)kp->base);
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
- put_user(tmp, &up->base) ||
- put_user(kp->height, &up->height) ||
- put_user(kp->width, &up->width) ||
- put_user(kp->depth, &up->depth) ||
- put_user(kp->bytesperline, &up->bytesperline))
- return -EFAULT;
- return 0;
-}
-
-struct video_clip32 {
- s32 x, y, width, height; /* It's really s32 in videodev.h */
- compat_caddr_t next;
-};
-
-struct video_window32 {
- u32 x, y, width, height, chromakey, flags;
- compat_caddr_t clips;
- compat_int_t clipcount;
-};
-
-static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- struct video_clip __user *uclips;
- struct video_clip __user *kclips;
- compat_caddr_t p;
- int nclips;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
- return -EFAULT;
-
- if (get_user(nclips, &up->clipcount))
- return -EFAULT;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
- get_user(kp->x, &up->x) ||
- get_user(kp->y, &up->y) ||
- get_user(kp->width, &up->width) ||
- get_user(kp->height, &up->height) ||
- get_user(kp->chromakey, &up->chromakey) ||
- get_user(kp->flags, &up->flags) ||
- get_user(kp->clipcount, &up->clipcount))
- return -EFAULT;
-
- nclips = kp->clipcount;
- kp->clips = NULL;
-
- if (nclips == 0)
- return 0;
- if (get_user(p, &up->clips))
- return -EFAULT;
- uclips = compat_ptr(p);
-
- /* If nclips < 0, then it is a clipping bitmap of size
- VIDEO_CLIPMAP_SIZE */
- if (nclips < 0) {
- if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
- return -EFAULT;
- kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
- if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
- return -EFAULT;
- return 0;
- }
-
- /* Otherwise it is an array of video_clip structs. */
- if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
- return -EFAULT;
-
- kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
- kclips = kp->clips;
- while (nclips--) {
- int err;
-
- err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
- err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
- err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
- err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
- kclips->next = NULL;
- if (err)
- return -EFAULT;
- kclips++;
- uclips++;
- }
- return 0;
-}
-
-/* You get back everything except the clips... */
-static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
- put_user(kp->x, &up->x) ||
- put_user(kp->y, &up->y) ||
- put_user(kp->width, &up->width) ||
- put_user(kp->height, &up->height) ||
- put_user(kp->chromakey, &up->chromakey) ||
- put_user(kp->flags, &up->flags) ||
- put_user(kp->clipcount, &up->clipcount))
- return -EFAULT;
- return 0;
-}
-
-struct video_code32 {
- char loadwhat[16]; /* name or tag of file being passed */
- compat_int_t datasize;
- compat_uptr_t data;
-};
-
-static struct video_code __user *get_microcode32(struct video_code32 *kp)
-{
- struct video_code __user *up;
-
- up = compat_alloc_user_space(sizeof(*up));
-
- /*
- * NOTE! We don't actually care if these fail. If the
- * user address is invalid, the native ioctl will do
- * the error handling for us
- */
- (void) copy_to_user(up->loadwhat, kp->loadwhat, sizeof(up->loadwhat));
- (void) put_user(kp->datasize, &up->datasize);
- (void) put_user(compat_ptr(kp->data), &up->data);
- return up;
-}
-
-#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
-#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
-#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
-#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
-#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
-#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
-#define VIDIOCGFREQ32 _IOR('v', 14, u32)
-#define VIDIOCSFREQ32 _IOW('v', 15, u32)
-#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
-
-#define VIDIOCCAPTURE32 _IOW('v', 8, s32)
-#define VIDIOCSYNC32 _IOW('v', 18, s32)
-#define VIDIOCSWRITEMODE32 _IOW('v', 25, s32)
-
-#endif
-
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOIOCTLCMD;
@@ -373,8 +165,6 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
return -EFAULT;
return 0;
- case 0:
- return -EINVAL;
default:
printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
@@ -404,8 +194,6 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
return -EFAULT;
return 0;
- case 0:
- return -EINVAL;
default:
printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
@@ -742,13 +530,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- struct video_tuner vt;
- struct video_buffer vb;
- struct video_window vw;
- struct video_code32 vc;
- struct video_audio va;
-#endif
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
@@ -764,17 +545,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
/* First, convert the command. */
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
- case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
- case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
- case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
- case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
- case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
- case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
- case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
- case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
-#endif
case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
@@ -801,46 +571,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
}
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSTUNER:
- case VIDIOCGTUNER:
- err = get_video_tuner32(&karg.vt, up);
- compatible_arg = 0;
- break;
-
- case VIDIOCSFBUF:
- err = get_video_buffer32(&karg.vb, up);
- compatible_arg = 0;
- break;
-
- case VIDIOCSWIN:
- err = get_video_window32(&karg.vw, up);
- compatible_arg = 0;
- break;
-
- case VIDIOCGWIN:
- case VIDIOCGFBUF:
- case VIDIOCGFREQ:
- compatible_arg = 0;
- break;
-
- case VIDIOCSMICROCODE:
- /* Copy the 32-bit "video_code32" to kernel space */
- if (copy_from_user(&karg.vc, up, sizeof(karg.vc)))
- return -EFAULT;
- /* Convert the 32-bit version to a 64-bit version in user space */
- up = get_microcode32(&karg.vc);
- break;
-
- case VIDIOCSFREQ:
- err = get_user(karg.vx, (u32 __user *)up);
- compatible_arg = 0;
- break;
-
- case VIDIOCCAPTURE:
- case VIDIOCSYNC:
- case VIDIOCSWRITEMODE:
-#endif
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
@@ -923,23 +653,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
return err;
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER:
- err = put_video_tuner32(&karg.vt, up);
- break;
-
- case VIDIOCGWIN:
- err = put_video_window32(&karg.vw, up);
- break;
-
- case VIDIOCGFBUF:
- err = put_video_buffer32(&karg.vb, up);
- break;
-
- case VIDIOCGFREQ:
- err = put_user(((u32)karg.vx), (u32 __user *)up);
- break;
-#endif
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_G_INPUT:
@@ -982,37 +695,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGCAP:
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
- case VIDIOCGTUNER32:
- case VIDIOCSTUNER32:
- case VIDIOCGPICT:
- case VIDIOCSPICT:
- case VIDIOCCAPTURE32:
- case VIDIOCGWIN32:
- case VIDIOCSWIN32:
- case VIDIOCGFBUF32:
- case VIDIOCSFBUF32:
- case VIDIOCKEY:
- case VIDIOCGFREQ32:
- case VIDIOCSFREQ32:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- case VIDIOCSYNC32:
- case VIDIOCMCAPTURE:
- case VIDIOCGMBUF:
- case VIDIOCGUNIT:
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
- case VIDIOCSPLAYMODE:
- case VIDIOCSWRITEMODE32:
- case VIDIOCGPLAYINFO:
- case VIDIOCSMICROCODE32:
- case VIDIOCGVBIFMT:
- case VIDIOCSVBIFMT:
-#endif
#ifdef __OLD_VIDIOC_
case VIDIOC_OVERLAY32_OLD:
case VIDIOC_S_PARM_OLD:
@@ -1097,19 +779,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
ret = do_video_ioctl(file, cmd, arg);
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* BTTV specific... */
- case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
- case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
- case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
- case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
- case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
- ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
- break;
-#endif
default:
printk(KERN_WARNING "compat_ioctl32: "
"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9d2502cd03ff..8f81efcfcf56 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -38,15 +38,15 @@ struct ctrl_helper {
the given control ID. The pointer array ends with a NULL pointer.
An empty string signifies a menu entry that is invalid. This allows
drivers to disable certain options if it is not supported. */
-const char **v4l2_ctrl_get_menu(u32 id)
+const char * const *v4l2_ctrl_get_menu(u32 id)
{
- static const char *mpeg_audio_sampling_freq[] = {
+ static const char * const mpeg_audio_sampling_freq[] = {
"44.1 kHz",
"48 kHz",
"32 kHz",
NULL
};
- static const char *mpeg_audio_encoding[] = {
+ static const char * const mpeg_audio_encoding[] = {
"MPEG-1/2 Layer I",
"MPEG-1/2 Layer II",
"MPEG-1/2 Layer III",
@@ -54,7 +54,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
"AC-3",
NULL
};
- static const char *mpeg_audio_l1_bitrate[] = {
+ static const char * const mpeg_audio_l1_bitrate[] = {
"32 kbps",
"64 kbps",
"96 kbps",
@@ -71,7 +71,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
"448 kbps",
NULL
};
- static const char *mpeg_audio_l2_bitrate[] = {
+ static const char * const mpeg_audio_l2_bitrate[] = {
"32 kbps",
"48 kbps",
"56 kbps",
@@ -88,7 +88,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
"384 kbps",
NULL
};
- static const char *mpeg_audio_l3_bitrate[] = {
+ static const char * const mpeg_audio_l3_bitrate[] = {
"32 kbps",
"40 kbps",
"48 kbps",
@@ -105,7 +105,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
"320 kbps",
NULL
};
- static const char *mpeg_audio_ac3_bitrate[] = {
+ static const char * const mpeg_audio_ac3_bitrate[] = {
"32 kbps",
"40 kbps",
"48 kbps",
@@ -127,50 +127,50 @@ const char **v4l2_ctrl_get_menu(u32 id)
"640 kbps",
NULL
};
- static const char *mpeg_audio_mode[] = {
+ static const char * const mpeg_audio_mode[] = {
"Stereo",
"Joint Stereo",
"Dual",
"Mono",
NULL
};
- static const char *mpeg_audio_mode_extension[] = {
+ static const char * const mpeg_audio_mode_extension[] = {
"Bound 4",
"Bound 8",
"Bound 12",
"Bound 16",
NULL
};
- static const char *mpeg_audio_emphasis[] = {
+ static const char * const mpeg_audio_emphasis[] = {
"No Emphasis",
"50/15 us",
"CCITT J17",
NULL
};
- static const char *mpeg_audio_crc[] = {
+ static const char * const mpeg_audio_crc[] = {
"No CRC",
"16-bit CRC",
NULL
};
- static const char *mpeg_video_encoding[] = {
+ static const char * const mpeg_video_encoding[] = {
"MPEG-1",
"MPEG-2",
"MPEG-4 AVC",
NULL
};
- static const char *mpeg_video_aspect[] = {
+ static const char * const mpeg_video_aspect[] = {
"1x1",
"4x3",
"16x9",
"2.21x1",
NULL
};
- static const char *mpeg_video_bitrate_mode[] = {
+ static const char * const mpeg_video_bitrate_mode[] = {
"Variable Bitrate",
"Constant Bitrate",
NULL
};
- static const char *mpeg_stream_type[] = {
+ static const char * const mpeg_stream_type[] = {
"MPEG-2 Program Stream",
"MPEG-2 Transport Stream",
"MPEG-1 System Stream",
@@ -179,25 +179,25 @@ const char **v4l2_ctrl_get_menu(u32 id)
"MPEG-2 SVCD-compatible Stream",
NULL
};
- static const char *mpeg_stream_vbi_fmt[] = {
+ static const char * const mpeg_stream_vbi_fmt[] = {
"No VBI",
"Private packet, IVTV format",
NULL
};
- static const char *camera_power_line_frequency[] = {
+ static const char * const camera_power_line_frequency[] = {
"Disabled",
"50 Hz",
"60 Hz",
NULL
};
- static const char *camera_exposure_auto[] = {
+ static const char * const camera_exposure_auto[] = {
"Auto Mode",
"Manual Mode",
"Shutter Priority Mode",
"Aperture Priority Mode",
NULL
};
- static const char *colorfx[] = {
+ static const char * const colorfx[] = {
"None",
"Black & White",
"Sepia",
@@ -210,7 +210,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
"Vivid",
NULL
};
- static const char *tune_preemphasis[] = {
+ static const char * const tune_preemphasis[] = {
"No preemphasis",
"50 useconds",
"75 useconds",
@@ -952,7 +952,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, const char *name, enum v4l2_ctrl_type type,
s32 min, s32 max, u32 step, s32 def,
- u32 flags, const char **qmenu, void *priv)
+ u32 flags, const char * const *qmenu, void *priv)
{
struct v4l2_ctrl *ctrl;
unsigned sz_extra = 0;
@@ -962,13 +962,20 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
/* Sanity checks */
if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
- def < min || def > max || max < min ||
+ max < min ||
(type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
(type == V4L2_CTRL_TYPE_STRING && max == 0)) {
handler_set_err(hdl, -ERANGE);
return NULL;
}
+ if ((type == V4L2_CTRL_TYPE_INTEGER ||
+ type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_BOOLEAN) &&
+ (def < min || def > max)) {
+ handler_set_err(hdl, -ERANGE);
+ return NULL;
+ }
if (type == V4L2_CTRL_TYPE_BUTTON)
flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -1019,7 +1026,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
bool is_menu;
struct v4l2_ctrl *ctrl;
const char *name = cfg->name;
- const char **qmenu = cfg->qmenu;
+ const char * const *qmenu = cfg->qmenu;
enum v4l2_ctrl_type type = cfg->type;
u32 flags = cfg->flags;
s32 min = cfg->min;
@@ -1075,7 +1082,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, s32 max, s32 mask, s32 def)
{
- const char **qmenu = v4l2_ctrl_get_menu(id);
+ const char * const *qmenu = v4l2_ctrl_get_menu(id);
const char *name;
enum v4l2_ctrl_type type;
s32 min;
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7978654b5..359e23290a7e 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -187,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
- int ret = -EIO;
+ int ret = -ENODEV;
if (!vdev->fops->read)
return -EINVAL;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
if (vdev->lock)
@@ -204,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
- int ret = -EIO;
+ int ret = -ENODEV;
if (!vdev->fops->write)
return -EINVAL;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
if (vdev->lock)
@@ -220,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
{
struct video_device *vdev = video_devdata(filp);
- int ret = DEFAULT_POLLMASK;
+ int ret = POLLERR | POLLHUP;
if (!vdev->fops->poll)
- return ret;
+ return DEFAULT_POLLMASK;
if (vdev->lock)
mutex_lock(vdev->lock);
if (video_is_registered(vdev))
@@ -239,18 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (vdev->lock)
mutex_unlock(vdev->lock);
} else if (vdev->fops->ioctl) {
- /* TODO: convert all drivers to unlocked_ioctl */
- lock_kernel();
+ /* This code path is a replacement for the BKL. It is a major
+ * hack but it will have to do for those drivers that are not
+ * yet converted to use unlocked_ioctl.
+ *
+ * There are two options: if the driver implements struct
+ * v4l2_device, then the lock defined there is used to
+ * serialize the ioctls. Otherwise the v4l2 core lock defined
+ * below is used. This lock is really bad since it serializes
+ * completely independent devices.
+ *
+ * Both variants suffer from the same problem: if the driver
+ * sleeps, then it blocks all ioctls since the lock is still
+ * held. This is very common for VIDIOC_DQBUF since that
+ * normally waits for a frame to arrive. As a result any other
+ * ioctl calls will proceed very, very slowly since each call
+ * will have to wait for the VIDIOC_QBUF to finish. Things that
+ * should take 0.01s may now take 10-20 seconds.
+ *
+ * The workaround is to *not* take the lock for VIDIOC_DQBUF.
+ * This actually works OK for videobuf-based drivers, since
+ * videobuf will take its own internal lock.
+ */
+ static DEFINE_MUTEX(v4l2_ioctl_mutex);
+ struct mutex *m = vdev->v4l2_dev ?
+ &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
+
+ if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->ioctl(filp, cmd, arg);
- unlock_kernel();
+ if (cmd != VIDIOC_DQBUF)
+ mutex_unlock(m);
} else
ret = -ENOTTY;
@@ -264,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
if (!vdev->fops->mmap)
return ret;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
if (vdev->lock)
@@ -283,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&videodev_lock);
vdev = video_devdata(filp);
/* return ENODEV if the video device has already been removed. */
- if (vdev == NULL) {
+ if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
}
@@ -291,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp)
video_get(vdev);
mutex_unlock(&videodev_lock);
if (vdev->fops->open) {
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+ ret = -ERESTARTSYS;
+ goto err;
+ }
if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
else
@@ -301,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
mutex_unlock(vdev->lock);
}
+err:
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
@@ -595,7 +624,12 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev))
return;
+ mutex_lock(&videodev_lock);
+ /* This must be in a critical section to prevent a race with v4l2_open.
+ * Once this bit has been cleared video_get may never be called again.
+ */
clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL(video_unregister_device);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 0b08f96b74a5..7fe6f92af480 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
+ mutex_init(&v4l2_dev->ioctl_lock);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index dd9283fcb564..7e47f15f350d 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -18,12 +18,8 @@
#include <linux/kernel.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls */
-#include <linux/videodev.h>
#include <linux/videodev2.h>
-#ifdef CONFIG_VIDEO_V4L1
-#include <linux/videodev.h>
-#endif
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
@@ -183,42 +179,6 @@ static const char *v4l2_memory_names[] = {
/* ------------------------------------------------------------------ */
/* debug help functions */
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static const char *v4l1_ioctls[] = {
- [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
- [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
- [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
- [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
- [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
- [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
- [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
- [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
- [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
- [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
- [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
- [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
- [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
- [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
- [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
- [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
- [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
- [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
- [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
- [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
- [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
- [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
- [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
- [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
- [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
- [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
- [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
- [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
- [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
-};
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-#endif
-
static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
[_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
@@ -310,15 +270,6 @@ void v4l_printk_ioctl(unsigned int cmd)
case 'd':
type = "v4l2_int";
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case 'v':
- if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
- type = "v4l1";
- break;
- }
- printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
- return;
-#endif
case 'V':
if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
type = "v4l2";
@@ -622,20 +573,6 @@ static long __video_do_ioctl(struct file *file,
return -EINVAL;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /********************************************************
- All other V4L1 calls are handled by v4l1_compat module.
- Those calls will be translated into V4L2 calls, and
- __video_do_ioctl will be called again, with one or more
- V4L2 ioctls.
- ********************************************************/
- if (_IOC_TYPE(cmd) == 'v' && cmd != VIDIOCGMBUF &&
- _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) {
- return v4l_compat_translate_ioctl(file, cmd, arg,
- __video_do_ioctl);
- }
-#endif
-
if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
v4l_print_ioctl(vfd->name, cmd);
@@ -644,29 +581,6 @@ static long __video_do_ioctl(struct file *file,
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /***********************************************************
- Handles calls to the obsoleted V4L1 API
- Due to the nature of VIDIOCGMBUF, each driver that supports
- V4L1 should implement its own handler for this ioctl.
- ***********************************************************/
-
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *p = arg;
-
- if (!ops->vidiocgmbuf)
- break;
- ret = ops->vidiocgmbuf(file, fh, p);
- if (!ret)
- dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
- p->size, p->frames,
- (unsigned long)p->offsets);
- break;
- }
-#endif
-
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP:
{
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 02a21bccae18..2f973cd56408 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -13,14 +13,12 @@
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
#include <media/videobuf-dma-sg.h>
-#include <linux/device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/pm_qos_params.h>
@@ -1161,16 +1159,6 @@ out:
return ret;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int viacam_vidiocgmbuf(struct file *filp, void *priv,
- struct video_mbuf *mbuf)
-{
- struct via_camera *cam = priv;
-
- return videobuf_cgmbuf(&cam->vb_queue, mbuf, 6);
-}
-#endif
-
/* G/S_PARM */
static int viacam_g_parm(struct file *filp, void *priv,
@@ -1251,9 +1239,6 @@ static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
.vidioc_s_parm = viacam_s_parm,
.vidioc_enum_framesizes = viacam_enum_framesizes,
.vidioc_enum_frameintervals = viacam_enum_frameintervals,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = viacam_vidiocgmbuf,
-#endif
};
/*----------------------------------------------------------------------------*/
@@ -1360,7 +1345,7 @@ static __devinit int viacam_probe(struct platform_device *pdev)
*/
sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
- "ov7670", "ov7670", 0x42 >> 1, NULL);
+ "ov7670", 0x42 >> 1, NULL);
if (cam->sensor == NULL) {
dev_err(&pdev->dev, "Unable to find the sensor!\n");
ret = -ENODEV;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 8979f91fa8e5..de4fa4eb8844 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -1202,33 +1202,3 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
return rc;
}
EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-#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;
-
- 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 += PAGE_ALIGN(q->bufs[i]->bsize);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
-#endif
-
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 20f227ee2b3e..ddb8f4b46c03 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -69,10 +69,9 @@ static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
struct page *pg;
int i;
- sglist = vmalloc(nr_pages * sizeof(*sglist));
+ sglist = vzalloc(nr_pages * sizeof(*sglist));
if (NULL == sglist)
return NULL;
- memset(sglist, 0, nr_pages * sizeof(*sglist));
sg_init_table(sglist, nr_pages);
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
pg = vmalloc_to_page(virt);
@@ -544,14 +543,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
retval = -EINVAL;
- /* This function maintains backwards compatibility with V4L1 and will
- * map more than one buffer if the vma length is equal to the combined
- * size of multiple buffers than it will map them together. See
- * VIDIOCGMBUF in the v4l spec
- *
- * TODO: Allow drivers to specify if they support this mode
- */
-
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
@@ -571,29 +562,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
last = first;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- if (size != (vma->vm_end - vma->vm_start)) {
- /* look for last buffer to map */
- for (last = first + 1; 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 += PAGE_ALIGN(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;
- }
- }
-#endif
/* create mapping + update buffer list */
retval = -ENOMEM;
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index e5e005dc1554..d63e9d978493 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2954,9 +2954,6 @@ static int vino_enum_input(struct file *file, void *__fh,
if (input == VINO_INPUT_NONE)
return -EINVAL;
- memset(i, 0, sizeof(struct v4l2_input));
-
- i->index = index;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->std = vino_inputs[input].std;
strcpy(i->name, vino_inputs[input].name);
@@ -4334,10 +4331,10 @@ static int __init vino_module_init(void)
vino_drvdata->decoder =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- NULL, "saa7191", 0, I2C_ADDRS(0x45));
+ "saa7191", 0, I2C_ADDRS(0x45));
vino_drvdata->camera =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- NULL, "indycam", 0, I2C_ADDRS(0x2b));
+ "indycam", 0, I2C_ADDRS(0x2b));
dprintk("init complete!\n");
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 9797e5a69265..c49c39386bd0 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -870,15 +870,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
-}
-#endif
-
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_dev *dev = video_drvdata(file);
@@ -1105,9 +1096,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device vivi_template = {
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 635420d8d84a..019ee206cbee 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -815,7 +815,7 @@ out:
static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read,
};
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 135525649086..fe8ef6419f83 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -35,7 +35,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
-#include <media/wm8775.h>
MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -51,16 +50,10 @@ enum {
TOT_REGS
};
-#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
-#define ALC_EN 0x100 /* R17: ALC enable */
-
struct wm8775_state {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *mute;
- struct v4l2_ctrl *vol;
- struct v4l2_ctrl *bal;
- struct v4l2_ctrl *loud;
u8 input; /* Last selected input (0-0xf) */
};
@@ -92,30 +85,6 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
return -1;
}
-static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
-{
- struct wm8775_state *state = to_state(sd);
- u8 vol_l, vol_r;
- int muted = 0 != state->mute->val;
- u16 volume = (u16)state->vol->val;
- u16 balance = (u16)state->bal->val;
-
- /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
- vol_l = (min(65536 - balance, 32768) * volume) >> 23;
- vol_r = (min(balance, (u16)32768) * volume) >> 23;
-
- /* Mute */
- if (muted || quietly)
- wm8775_write(sd, R21, 0x0c0 | state->input);
-
- wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
- wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
-
- /* Un-mute */
- if (!muted)
- wm8775_write(sd, R21, state->input);
-}
-
static int wm8775_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -133,26 +102,25 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
state->input = input;
if (!v4l2_ctrl_g_ctrl(state->mute))
return 0;
- if (!v4l2_ctrl_g_ctrl(state->vol))
- return 0;
- if (!v4l2_ctrl_g_ctrl(state->bal))
- return 0;
- wm8775_set_audio(sd, 1);
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
+ struct wm8775_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- wm8775_set_audio(sd, 0);
- return 0;
- case V4L2_CID_AUDIO_LOUDNESS:
- wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ if (!ctrl->val)
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
return -EINVAL;
@@ -176,7 +144,16 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
{
- wm8775_set_audio(sd, 0);
+ struct wm8775_state *state = to_state(sd);
+
+ /* If I remove this, then it can happen that I have no
+ sound the first time I tune from static to a valid channel.
+ It's difficult to reproduce and is almost certainly related
+ to the zero cross detect circuit. */
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
@@ -226,7 +203,6 @@ static int wm8775_probe(struct i2c_client *client,
{
struct wm8775_state *state;
struct v4l2_subdev *sd;
- int err;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -240,21 +216,15 @@ static int wm8775_probe(struct i2c_client *client,
return -ENOMEM;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
- sd->grp_id = WM8775_GID; /* subdev group id */
state->input = 2;
- v4l2_ctrl_handler_init(&state->hdl, 4);
+ v4l2_ctrl_handler_init(&state->hdl, 1);
state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
- state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
- state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
- state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
sd->ctrl_handler = &state->hdl;
- err = state->hdl.error;
- if (err) {
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
v4l2_ctrl_handler_free(&state->hdl);
kfree(state);
return err;
@@ -266,25 +236,29 @@ static int wm8775_probe(struct i2c_client *client,
wm8775_write(sd, R23, 0x000);
/* Disable zero cross detect timeout */
wm8775_write(sd, R7, 0x000);
- /* HPF enable, I2S mode, 24-bit */
- wm8775_write(sd, R11, 0x022);
+ /* Left justified, 24-bit mode */
+ wm8775_write(sd, R11, 0x021);
/* Master mode, clock ratio 256fs */
wm8775_write(sd, R12, 0x102);
/* Powered up */
wm8775_write(sd, R13, 0x000);
- /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
- wm8775_write(sd, R16, 0x1bb);
- /* Set ALC mode and hold time */
- wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
+ /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(sd, R14, 0x1d4);
+ /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(sd, R15, 0x1d4);
+ /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+ wm8775_write(sd, R16, 0x1bf);
+ /* Enable gain control, use zero cross detection,
+ ALC hold time 42.6 ms */
+ wm8775_write(sd, R17, 0x185);
/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
wm8775_write(sd, R18, 0x0a2);
/* Enable noise gate, threshold -72dBfs */
wm8775_write(sd, R19, 0x005);
- /* Transient window 4ms, ALC min gain -5dB */
- wm8775_write(sd, R20, 0x0fb);
-
- wm8775_set_audio(sd, 1); /* set volume/mute/mux */
-
+ /* Transient window 4ms, lower PGA gain limit -1dB */
+ wm8775_write(sd, R20, 0x07a);
+ /* LRBOTH = 1, use input 2. */
+ wm8775_write(sd, R21, 0x102);
return 0;
}
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index 37fe16181e3c..4bb368e6fd47 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -33,15 +33,6 @@
#include <media/v4l2-device.h>
-#define ZORAN_VIDMODE_PAL 0
-#define ZORAN_VIDMODE_NTSC 1
-#define ZORAN_VIDMODE_SECAM 2
-
-struct zoran_requestbuffers {
- unsigned long count; /* Number of buffers for MJPEG grabbing */
- unsigned long size; /* Size PER BUFFER in bytes */
-};
-
struct zoran_sync {
unsigned long frame; /* number of buffer that has been free'd */
unsigned long length; /* number of code bytes in buffer (capture only) */
@@ -49,102 +40,6 @@ struct zoran_sync {
struct timeval timestamp; /* timestamp */
};
-struct zoran_status {
- int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */
- int signal; /* Returned: 1 if valid video signal detected */
- int norm; /* Returned: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
- int color; /* Returned: 1 if color signal detected */
-};
-
-struct zoran_params {
-
- /* The following parameters can only be queried */
-
- int major_version; /* Major version number of driver */
- int minor_version; /* Minor version number of driver */
-
- /* Main control parameters */
-
- int input; /* Input channel: 0 = Composite, 1 = S-VHS */
- int norm; /* Norm: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
- int decimation; /* decimation of captured video,
- * enlargement of video played back.
- * Valid values are 1, 2, 4 or 0.
- * 0 is a special value where the user
- * has full control over video scaling */
-
- /* The following parameters only have to be set if decimation==0,
- * for other values of decimation they provide the data how the image is captured */
-
- int HorDcm; /* Horizontal decimation: 1, 2 or 4 */
- int VerDcm; /* Vertical decimation: 1 or 2 */
- int TmpDcm; /* Temporal decimation: 1 or 2,
- * if TmpDcm==2 in capture every second frame is dropped,
- * in playback every frame is played twice */
- int field_per_buff; /* Number of fields per buffer: 1 or 2 */
- int img_x; /* start of image in x direction */
- int img_y; /* start of image in y direction */
- int img_width; /* image width BEFORE decimation,
- * must be a multiple of HorDcm*16 */
- int img_height; /* image height BEFORE decimation,
- * must be a multiple of VerDcm*8 */
-
- /* --- End of parameters for decimation==0 only --- */
-
- /* JPEG control parameters */
-
- int quality; /* Measure for quality of compressed images.
- * Scales linearly with the size of the compressed images.
- * Must be beetween 0 and 100, 100 is a compression
- * ratio of 1:4 */
-
- int odd_even; /* Which field should come first ??? */
-
- int APPn; /* Number of APP segment to be written, must be 0..15 */
- int APP_len; /* Length of data in JPEG APPn segment */
- char APP_data[60]; /* Data in the JPEG APPn segment. */
-
- int COM_len; /* Length of data in JPEG COM segment */
- char COM_data[60]; /* Data in JPEG COM segment */
-
- unsigned long jpeg_markers; /* Which markers should go into the JPEG output.
- * Unless you exactly know what you do, leave them untouched.
- * Inluding less markers will make the resulting code
- * smaller, but there will be fewer applications
- * which can read it.
- * The presence of the APP and COM marker is
- * influenced by APP0_len and COM_len ONLY! */
-#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
-#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
-#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
-#define JPEG_MARKER_COM (1<<6) /* Comment segment */
-#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */
-
- int VFIFO_FB; /* Flag for enabling Video Fifo Feedback.
- * If this flag is turned on and JPEG decompressing
- * is going to the screen, the decompress process
- * is stopped every time the Video Fifo is full.
- * This enables a smooth decompress to the screen
- * but the video output signal will get scrambled */
-
- /* Misc */
-
- char reserved[312]; /* Makes 512 bytes for this structure */
-};
-
-/*
-Private IOCTL to set up for displaying MJPEG
-*/
-#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOC_PRIVATE+0, struct zoran_params)
-#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOC_PRIVATE+1, struct zoran_params)
-#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOC_PRIVATE+2, struct zoran_requestbuffers)
-#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOC_PRIVATE+3, int)
-#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOC_PRIVATE+4, int)
-#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOC_PRIVATE+5, struct zoran_sync)
-#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOC_PRIVATE+6, struct zoran_status)
-
-
-#ifdef __KERNEL__
#define MAJOR_VERSION 0 /* driver major version */
#define MINOR_VERSION 10 /* driver minor version */
@@ -388,6 +283,7 @@ struct zoran {
struct videocodec *vfe; /* video front end */
struct mutex resource_lock; /* prevent evil stuff */
+ struct mutex other_lock; /* please merge with above */
u8 initialized; /* flag if zoran has been correctly initialized */
int user; /* number of current users */
@@ -506,6 +402,4 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-#endif /* __kernel__ */
-
#endif
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 0aac376c3f7a..9cdc3bb15b15 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -943,7 +943,7 @@ zoran_open_init_params (struct zoran *zr)
memset(zr->jpg_settings.jpg_comp.COM_data, 0,
sizeof(zr->jpg_settings.jpg_comp.COM_data));
zr->jpg_settings.jpg_comp.jpeg_markers =
- JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+ V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT;
i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
if (i)
dprintk(1, KERN_ERR "%s: %s internal error\n",
@@ -1227,6 +1227,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
spin_lock_init(&zr->spinlock);
mutex_init(&zr->resource_lock);
+ mutex_init(&zr->other_lock);
if (pci_enable_device(pdev))
goto zr_unreg;
pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
@@ -1342,13 +1343,12 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
}
zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter, NULL, zr->card.i2c_decoder,
+ &zr->i2c_adapter, zr->card.i2c_decoder,
0, zr->card.addrs_decoder);
if (zr->card.i2c_encoder)
zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter,
- NULL, zr->card.i2c_encoder,
+ &zr->i2c_adapter, zr->card.i2c_encoder,
0, zr->card.addrs_encoder);
dprintk(2,
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index b02007e42150..e8a27844bf39 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -1523,7 +1523,7 @@ zoran_irq (int irq,
zr->JPEG_missed > 25 ||
zr->JPEG_error == 1 ||
((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
- (zr->frame_num & (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
+ (zr->frame_num && (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
error_handler(zr, astat, stat);
}
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 401082b853f0..7c3921de9589 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -49,7 +49,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
@@ -913,7 +912,7 @@ static int zoran_open(struct file *file)
dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
- lock_kernel();
+ mutex_lock(&zr->other_lock);
if (zr->user >= 2048) {
dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
@@ -963,14 +962,14 @@ static int zoran_open(struct file *file)
file->private_data = fh;
fh->zr = zr;
zoran_open_init_session(fh);
- unlock_kernel();
+ mutex_unlock(&zr->other_lock);
return 0;
fail_fh:
kfree(fh);
fail_unlock:
- unlock_kernel();
+ mutex_unlock(&zr->other_lock);
dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n",
ZR_DEVNAME(zr), res, zr->user);
@@ -989,7 +988,7 @@ zoran_close(struct file *file)
/* kernel locks (fs/device.c), so don't do that ourselves
* (prevents deadlocks) */
- /*mutex_lock(&zr->resource_lock);*/
+ mutex_lock(&zr->other_lock);
zoran_close_end_session(fh);
@@ -1023,6 +1022,7 @@ zoran_close(struct file *file)
encoder_call(zr, video, s_routing, 2, 0, 0);
}
}
+ mutex_unlock(&zr->other_lock);
file->private_data = NULL;
kfree(fh->overlay_mask);
@@ -1528,323 +1528,6 @@ zoran_set_input (struct zoran *zr,
* ioctl routine
*/
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static long zoran_default(struct file *file, void *__fh, int cmd, void *arg)
-{
- struct zoran_fh *fh = __fh;
- struct zoran *zr = fh->zr;
- struct zoran_jpg_settings settings;
-
- switch (cmd) {
- case BUZIOC_G_PARAMS:
- {
- struct zoran_params *bparams = arg;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
-
- memset(bparams, 0, sizeof(struct zoran_params));
- bparams->major_version = MAJOR_VERSION;
- bparams->minor_version = MINOR_VERSION;
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->norm & V4L2_STD_NTSC)
- bparams->norm = ZORAN_VIDMODE_NTSC;
- else if (zr->norm & V4L2_STD_SECAM)
- bparams->norm = ZORAN_VIDMODE_SECAM;
- else
- bparams->norm = ZORAN_VIDMODE_PAL;
-
- bparams->input = zr->input;
-
- bparams->decimation = fh->jpg_settings.decimation;
- bparams->HorDcm = fh->jpg_settings.HorDcm;
- bparams->VerDcm = fh->jpg_settings.VerDcm;
- bparams->TmpDcm = fh->jpg_settings.TmpDcm;
- bparams->field_per_buff = fh->jpg_settings.field_per_buff;
- bparams->img_x = fh->jpg_settings.img_x;
- bparams->img_y = fh->jpg_settings.img_y;
- bparams->img_width = fh->jpg_settings.img_width;
- bparams->img_height = fh->jpg_settings.img_height;
- bparams->odd_even = fh->jpg_settings.odd_even;
-
- bparams->quality = fh->jpg_settings.jpg_comp.quality;
- bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
- bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
- memcpy(bparams->APP_data,
- fh->jpg_settings.jpg_comp.APP_data,
- sizeof(bparams->APP_data));
- bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
- memcpy(bparams->COM_data,
- fh->jpg_settings.jpg_comp.COM_data,
- sizeof(bparams->COM_data));
- bparams->jpeg_markers =
- fh->jpg_settings.jpg_comp.jpeg_markers;
-
- mutex_unlock(&zr->resource_lock);
-
- bparams->VFIFO_FB = 0;
-
- return 0;
- }
-
- case BUZIOC_S_PARAMS:
- {
- struct zoran_params *bparams = arg;
- int res = 0;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));
-
- settings.decimation = bparams->decimation;
- settings.HorDcm = bparams->HorDcm;
- settings.VerDcm = bparams->VerDcm;
- settings.TmpDcm = bparams->TmpDcm;
- settings.field_per_buff = bparams->field_per_buff;
- settings.img_x = bparams->img_x;
- settings.img_y = bparams->img_y;
- settings.img_width = bparams->img_width;
- settings.img_height = bparams->img_height;
- settings.odd_even = bparams->odd_even;
-
- settings.jpg_comp.quality = bparams->quality;
- settings.jpg_comp.APPn = bparams->APPn;
- settings.jpg_comp.APP_len = bparams->APP_len;
- memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
- sizeof(bparams->APP_data));
- settings.jpg_comp.COM_len = bparams->COM_len;
- memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
- sizeof(bparams->COM_data));
- settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto sparams_unlock_and_return;
- }
-
- /* Check the params first before overwriting our
- * nternal values */
- if (zoran_check_jpg_settings(zr, &settings, 0)) {
- res = -EINVAL;
- goto sparams_unlock_and_return;
- }
-
- fh->jpg_settings = settings;
-sparams_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_REQBUFS:
- {
- struct zoran_requestbuffers *breq = arg;
- int res = 0;
-
- dprintk(3,
- KERN_DEBUG
- "%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
- ZR_DEVNAME(zr), breq->count, breq->size);
-
- /* Enforce reasonable lower and upper limits */
- if (breq->count < 4)
- breq->count = 4; /* Could be choosen smaller */
- if (breq->count > jpg_nbufs)
- breq->count = jpg_nbufs;
- breq->size = PAGE_ALIGN(breq->size);
- if (breq->size < 8192)
- breq->size = 8192; /* Arbitrary */
- /* breq->size is limited by 1 page for the stat_com
- * tables to a Maximum of 2 MB */
- if (breq->size > jpg_bufsize)
- breq->size = jpg_bufsize;
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->buffers.allocated) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_REQBUFS - buffers already allocated\n",
- ZR_DEVNAME(zr));
- res = -EBUSY;
- goto jpgreqbuf_unlock_and_return;
- }
-
- /* The next mmap will map the MJPEG buffers - could
- * also be *_PLAY, but it doesn't matter here */
- map_mode_jpg(fh, 0);
- fh->buffers.num_buffers = breq->count;
- fh->buffers.buffer_size = breq->size;
-
- if (jpg_fbuffer_alloc(fh)) {
- res = -ENOMEM;
- goto jpgreqbuf_unlock_and_return;
- }
-
-jpgreqbuf_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_QBUF_CAPT:
- {
- int *frame = arg, res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
- ZR_DEVNAME(zr), *frame);
-
- mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_COMPRESS);
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_QBUF_PLAY:
- {
- int *frame = arg, res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
- ZR_DEVNAME(zr), *frame);
-
- mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_DECOMPRESS);
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_SYNC:
- {
- struct zoran_sync *bsync = arg;
- int res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
- dprintk(2, KERN_WARNING
- "%s: %s - not in jpg capture mode\n",
- ZR_DEVNAME(zr), __func__);
- res = -EINVAL;
- } else {
- res = jpg_sync(fh, bsync);
- }
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_G_STATUS:
- {
- struct zoran_status *bstat = arg;
- int status = 0, res = 0;
- v4l2_std_id norm;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- return -EINVAL;
- }
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto gstat_unlock_and_return;
- }
-
- decoder_call(zr, video, s_routing,
- zr->card.input[bstat->input].muxsel, 0, 0);
-
- /* sleep 1 second */
- ssleep(1);
-
- /* Get status of video decoder */
- decoder_call(zr, video, querystd, &norm);
- decoder_call(zr, video, g_input_status, &status);
-
- /* restore previous input and norm */
- decoder_call(zr, video, s_routing,
- zr->card.input[zr->input].muxsel, 0, 0);
-gstat_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- if (!res) {
- bstat->signal =
- (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1;
- if (norm & V4L2_STD_NTSC)
- bstat->norm = ZORAN_VIDMODE_NTSC;
- else if (norm & V4L2_STD_SECAM)
- bstat->norm = ZORAN_VIDMODE_SECAM;
- else
- bstat->norm = ZORAN_VIDMODE_PAL;
-
- bstat->color =
- (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1;
- }
-
- return res;
- }
-
- default:
- return -EINVAL;
- }
-}
-
-static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf)
-{
- struct zoran_fh *fh = __fh;
- struct zoran *zr = fh->zr;
- int i, res = 0;
-
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->buffers.allocated) {
- dprintk(1,
- KERN_ERR
- "%s: VIDIOCGMBUF - buffers already allocated\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto v4l1reqbuf_unlock_and_return;
- }
-
- /* The next mmap will map the V4L buffers */
- map_mode_raw(fh);
-
- if (v4l_fbuffer_alloc(fh)) {
- res = -ENOMEM;
- goto v4l1reqbuf_unlock_and_return;
- }
-
- vmbuf->size = fh->buffers.num_buffers * fh->buffers.buffer_size;
- vmbuf->frames = fh->buffers.num_buffers;
- for (i = 0; i < vmbuf->frames; i++)
- vmbuf->offsets[i] = i * fh->buffers.buffer_size;
-
-v4l1reqbuf_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
-}
-#endif
-
static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
{
struct zoran_fh *fh = __fh;
@@ -2533,6 +2216,7 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
+ bs.frame = 0; /* suppress compiler warning */
res = jpg_sync(fh, &bs);
if (res)
goto dqbuf_unlock_and_return;
@@ -2766,11 +2450,6 @@ static int zoran_enum_input(struct file *file, void *__fh,
if (inp->index >= zr->card.inputs)
return -EINVAL;
- else {
- int id = inp->index;
- memset(inp, 0, sizeof(*inp));
- inp->index = id;
- }
strncpy(inp->name, zr->card.input[inp->index].name,
sizeof(inp->name) - 1);
@@ -2820,7 +2499,6 @@ static int zoran_enum_output(struct file *file, void *__fh,
if (outp->index != 0)
return -EINVAL;
- memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
@@ -3364,17 +3042,28 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
.vidioc_queryctrl = zoran_queryctrl,
.vidioc_s_ctrl = zoran_s_ctrl,
.vidioc_g_ctrl = zoran_g_ctrl,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidioc_default = zoran_default,
- .vidiocgmbuf = zoran_vidiocgmbuf,
-#endif
};
+/* please use zr->resource_lock consistently and kill this wrapper */
+static long zoran_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ int ret;
+
+ mutex_lock(&zr->other_lock);
+ ret = video_ioctl2(file, cmd, arg);
+ mutex_unlock(&zr->other_lock);
+
+ return ret;
+}
+
static const struct v4l2_file_operations zoran_fops = {
.owner = THIS_MODULE,
.open = zoran_open,
.release = zoran_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = zoran_ioctl,
.read = zoran_read,
.write = zoran_write,
.mmap = zoran_mmap,
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index c00fe8253c51..e9a3eab7b0cf 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
if (!host->card) {
host->card = card;
if (device_register(&card->dev)) {
+ put_device(&card->dev);
kfree(host->card);
host->card = NULL;
}
@@ -510,14 +511,18 @@ int memstick_add_host(struct memstick_host *host)
{
int rc;
- if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL))
- return -ENOMEM;
+ while (1) {
+ if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL))
+ return -ENOMEM;
- spin_lock(&memstick_host_lock);
- rc = idr_get_new(&memstick_host_idr, host, &host->id);
- spin_unlock(&memstick_host_lock);
- if (rc)
- return rc;
+ spin_lock(&memstick_host_lock);
+ rc = idr_get_new(&memstick_host_idr, host, &host->id);
+ spin_unlock(&memstick_host_lock);
+ if (!rc)
+ break;
+ else if (rc != -EAGAIN)
+ return rc;
+ }
dev_set_name(&host->dev, "memstick%u", host->id);
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 02362eccc588..57b42bfc7d23 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -23,7 +23,6 @@
#define DRIVER_NAME "mspro_block"
-static DEFINE_MUTEX(mspro_block_mutex);
static int major;
module_param(major, int, 0644);
@@ -160,6 +159,13 @@ struct mspro_block_data {
int (*mrq_handler)(struct memstick_dev *card,
struct memstick_request **mrq);
+
+ /* Default request setup function for data access method preferred by
+ * this host instance.
+ */
+ void (*setup_transfer)(struct memstick_dev *card,
+ u64 offset, size_t length);
+
struct attribute_group attr_group;
struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS];
@@ -181,7 +187,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
struct mspro_block_data *msb = disk->private_data;
int rc = -ENXIO;
- mutex_lock(&mspro_block_mutex);
mutex_lock(&mspro_block_disk_lock);
if (msb && msb->card) {
@@ -193,7 +198,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
}
mutex_unlock(&mspro_block_disk_lock);
- mutex_unlock(&mspro_block_mutex);
return rc;
}
@@ -225,11 +229,7 @@ static int mspro_block_disk_release(struct gendisk *disk)
static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode)
{
- int ret;
- mutex_lock(&mspro_block_mutex);
- ret = mspro_block_disk_release(disk);
- mutex_unlock(&mspro_block_mutex);
- return ret;
+ return mspro_block_disk_release(disk);
}
static int mspro_block_bd_getgeo(struct block_device *bdev,
@@ -663,14 +663,43 @@ has_int_reg:
}
}
+/*** Transfer setup functions for different access methods. ***/
+
+/** Setup data transfer request for SET_CMD TPC with arguments in card
+ * registers.
+ *
+ * @card Current media instance
+ * @offset Target data offset in bytes
+ * @length Required transfer length in bytes.
+ */
+static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset,
+ size_t length)
+{
+ struct mspro_block_data *msb = memstick_get_drvdata(card);
+ struct mspro_param_register param = {
+ .system = msb->system,
+ .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)),
+ /* ISO C90 warning precludes direct initialization for now. */
+ .data_address = 0,
+ .tpc_param = 0
+ };
+
+ do_div(offset, msb->page_size);
+ param.data_address = cpu_to_be32((uint32_t)offset);
+
+ card->next_request = h_mspro_block_req_init;
+ msb->mrq_handler = h_mspro_block_transfer_data;
+ memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
+ &param, sizeof(param));
+}
+
/*** Data transfer ***/
static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- sector_t t_sec;
+ u64 t_off;
unsigned int count;
- struct mspro_param_register param;
try_again:
while (chunk) {
@@ -685,30 +714,17 @@ try_again:
continue;
}
- t_sec = blk_rq_pos(msb->block_req) << 9;
- sector_div(t_sec, msb->page_size);
-
+ t_off = blk_rq_pos(msb->block_req);
+ t_off <<= 9;
count = blk_rq_bytes(msb->block_req);
- count /= msb->page_size;
- param.system = msb->system;
- param.data_count = cpu_to_be16(count);
- param.data_address = cpu_to_be32((uint32_t)t_sec);
- param.tpc_param = 0;
+ msb->setup_transfer(card, t_off, count);
msb->data_dir = rq_data_dir(msb->block_req);
msb->transfer_cmd = msb->data_dir == READ
? MSPRO_CMD_READ_DATA
: MSPRO_CMD_WRITE_DATA;
- dev_dbg(&card->dev, "data transfer: cmd %x, "
- "lba %x, count %x\n", msb->transfer_cmd,
- be32_to_cpu(param.data_address), count);
-
- card->next_request = h_mspro_block_req_init;
- msb->mrq_handler = h_mspro_block_transfer_data;
- memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
- &param, sizeof(param));
memstick_new_req(card->host);
return 0;
}
@@ -963,18 +979,16 @@ try_again:
static int mspro_block_read_attributes(struct memstick_dev *card)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- struct mspro_param_register param = {
- .system = msb->system,
- .data_count = cpu_to_be16(1),
- .data_address = 0,
- .tpc_param = 0
- };
struct mspro_attribute *attr = NULL;
struct mspro_sys_attr *s_attr = NULL;
unsigned char *buffer = NULL;
int cnt, rc, attr_count;
- unsigned int addr;
- unsigned short page_count;
+ /* While normally physical device offsets, represented here by
+ * attr_offset and attr_len will be of large numeric types, we can be
+ * sure, that attributes are close enough to the beginning of the
+ * device, to save ourselves some trouble.
+ */
+ unsigned int addr, attr_offset = 0, attr_len = msb->page_size;
attr = kmalloc(msb->page_size, GFP_KERNEL);
if (!attr)
@@ -987,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
msb->data_dir = READ;
msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
- card->next_request = h_mspro_block_req_init;
- msb->mrq_handler = h_mspro_block_transfer_data;
- memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, &param,
- sizeof(param));
+ msb->setup_transfer(card, attr_offset, attr_len);
+
memstick_new_req(card->host);
wait_for_completion(&card->mrq_complete);
if (card->current_mrq.error) {
@@ -1021,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
}
msb->attr_group.name = "media_attributes";
- buffer = kmalloc(msb->page_size, GFP_KERNEL);
+ buffer = kmalloc(attr_len, GFP_KERNEL);
if (!buffer) {
rc = -ENOMEM;
goto out_free_attr;
}
- memcpy(buffer, (char *)attr, msb->page_size);
- page_count = 1;
+ memcpy(buffer, (char *)attr, attr_len);
for (cnt = 0; cnt < attr_count; ++cnt) {
s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL);
@@ -1038,9 +1049,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;
addr = be32_to_cpu(attr->entries[cnt].address);
- rc = be32_to_cpu(attr->entries[cnt].size);
+ s_attr->size = be32_to_cpu(attr->entries[cnt].size);
dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, "
- "size %x\n", cnt, attr->entries[cnt].id, addr, rc);
+ "size %zx\n", cnt, attr->entries[cnt].id, addr,
+ s_attr->size);
s_attr->id = attr->entries[cnt].id;
if (mspro_block_attr_name(s_attr->id))
snprintf(s_attr->name, sizeof(s_attr->name), "%s",
@@ -1054,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
s_attr->dev_attr.attr.mode = S_IRUGO;
s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
- if (!rc)
+ if (!s_attr->size)
continue;
- s_attr->size = rc;
- s_attr->data = kmalloc(rc, GFP_KERNEL);
+ s_attr->data = kmalloc(s_attr->size, GFP_KERNEL);
if (!s_attr->data) {
rc = -ENOMEM;
goto out_free_buffer;
}
- if (((addr / msb->page_size)
- == be32_to_cpu(param.data_address))
- && (((addr + rc - 1) / msb->page_size)
- == be32_to_cpu(param.data_address))) {
+ if (((addr / msb->page_size) == (attr_offset / msb->page_size))
+ && (((addr + s_attr->size - 1) / msb->page_size)
+ == (attr_offset / msb->page_size))) {
memcpy(s_attr->data, buffer + addr % msb->page_size,
- rc);
+ s_attr->size);
continue;
}
- if (page_count <= (rc / msb->page_size)) {
+ attr_offset = (addr / msb->page_size) * msb->page_size;
+
+ if ((attr_offset + attr_len) < (addr + s_attr->size)) {
kfree(buffer);
- page_count = (rc / msb->page_size) + 1;
- buffer = kmalloc(page_count * msb->page_size,
- GFP_KERNEL);
+ attr_len = (((addr + s_attr->size) / msb->page_size)
+ + 1 ) * msb->page_size - attr_offset;
+ buffer = kmalloc(attr_len, GFP_KERNEL);
if (!buffer) {
rc = -ENOMEM;
goto out_free_attr;
}
}
- param.system = msb->system;
- param.data_count = cpu_to_be16((rc / msb->page_size) + 1);
- param.data_address = cpu_to_be32(addr / msb->page_size);
- param.tpc_param = 0;
-
- sg_init_one(&msb->req_sg[0], buffer,
- be16_to_cpu(param.data_count) * msb->page_size);
+ sg_init_one(&msb->req_sg[0], buffer, attr_len);
msb->seg_count = 1;
msb->current_seg = 0;
msb->current_page = 0;
msb->data_dir = READ;
msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
- dev_dbg(&card->dev, "reading attribute pages %x, %x\n",
- be32_to_cpu(param.data_address),
- be16_to_cpu(param.data_count));
+ dev_dbg(&card->dev, "reading attribute range %x, %x\n",
+ attr_offset, attr_len);
- card->next_request = h_mspro_block_req_init;
- msb->mrq_handler = h_mspro_block_transfer_data;
- memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
- (char *)&param, sizeof(param));
+ msb->setup_transfer(card, attr_offset, attr_len);
memstick_new_req(card->host);
wait_for_completion(&card->mrq_complete);
if (card->current_mrq.error) {
@@ -1112,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
goto out_free_buffer;
}
- memcpy(s_attr->data, buffer + addr % msb->page_size, rc);
+ memcpy(s_attr->data, buffer + addr % msb->page_size,
+ s_attr->size);
}
rc = 0;
@@ -1130,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card)
int rc = 0;
msb->system = MEMSTICK_SYS_SERIAL;
+ msb->setup_transfer = h_mspro_block_setup_cmd;
+
card->reg_addr.r_offset = offsetof(struct mspro_register, status);
card->reg_addr.r_length = sizeof(struct ms_status_register);
card->reg_addr.w_offset = offsetof(struct mspro_register, param);
@@ -1206,10 +1211,12 @@ static int mspro_block_init_disk(struct memstick_dev *card)
msb->page_size = be16_to_cpu(sys_info->unit_size);
- if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL))
+ mutex_lock(&mspro_block_disk_lock);
+ if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) {
+ mutex_unlock(&mspro_block_disk_lock);
return -ENOMEM;
+ }
- mutex_lock(&mspro_block_disk_lock);
rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id);
mutex_unlock(&mspro_block_disk_lock);
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index f2b894cd8b02..d89d925caecf 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -61,6 +61,7 @@ struct jmb38x_ms_host {
struct memstick_request *req;
unsigned char cmd_flags;
unsigned char io_pos;
+ unsigned char ifmode;
unsigned int io_word[2];
};
@@ -136,15 +137,14 @@ struct jmb38x_ms {
#define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000
#define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000
+#define CLOCK_CONTROL_BY_MMIO 0x00000008
#define CLOCK_CONTROL_40MHZ 0x00000001
-#define CLOCK_CONTROL_50MHZ 0x0000000a
-#define CLOCK_CONTROL_60MHZ 0x00000008
-#define CLOCK_CONTROL_62_5MHZ 0x0000000c
+#define CLOCK_CONTROL_50MHZ 0x00000002
+#define CLOCK_CONTROL_60MHZ 0x00000010
+#define CLOCK_CONTROL_62_5MHZ 0x00000004
#define CLOCK_CONTROL_OFF 0x00000000
#define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0
-#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00
-#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000
enum {
CMD_READY = 0x01,
@@ -390,8 +390,13 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
if (host->req->data_dir == READ)
cmd |= TPC_DIR;
- if (host->req->need_card_int)
- cmd |= TPC_WAIT_INT;
+
+ if (host->req->need_card_int) {
+ if (host->ifmode == MEMSTICK_SERIAL)
+ cmd |= TPC_GET_INT;
+ else
+ cmd |= TPC_WAIT_INT;
+ }
data = host->req->data;
@@ -529,7 +534,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
if (irq_status & INT_STATUS_ANY_ERR) {
if (irq_status & INT_STATUS_CRC_ERR)
host->req->error = -EILSEQ;
- else
+ else if (irq_status & INT_STATUS_TPC_ERR) {
+ dev_dbg(&host->chip->pdev->dev, "TPC_ERR\n");
+ jmb38x_ms_complete_cmd(msh, 0);
+ } else
host->req->error = -ETIME;
} else {
if (host->cmd_flags & DMA_DATA) {
@@ -644,7 +652,6 @@ static int jmb38x_ms_reset(struct jmb38x_ms_host *host)
ndelay(20);
}
dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n");
- /* return -EIO; */
reset_next:
writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN
@@ -675,7 +682,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
{
struct jmb38x_ms_host *host = memstick_priv(msh);
unsigned int host_ctl = readl(host->addr + HOST_CONTROL);
- unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0;
+ unsigned int clock_ctl = CLOCK_CONTROL_BY_MMIO, clock_delay = 0;
int rc = 0;
switch (param) {
@@ -687,9 +694,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
host_ctl = 7;
host_ctl |= HOST_CONTROL_POWER_EN
- | HOST_CONTROL_CLOCK_EN
- | HOST_CONTROL_HW_OC_P
- | HOST_CONTROL_TDELAY_EN;
+ | HOST_CONTROL_CLOCK_EN;
writel(host_ctl, host->addr + HOST_CONTROL);
writel(host->id ? PAD_PU_PD_ON_MS_SOCK1
@@ -712,46 +717,88 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
return -EINVAL;
break;
case MEMSTICK_INTERFACE:
+ dev_dbg(&host->chip->pdev->dev,
+ "Set Host Interface Mode to %d\n", value);
+ host_ctl &= ~(HOST_CONTROL_FAST_CLK | HOST_CONTROL_REI |
+ HOST_CONTROL_REO);
+ host_ctl |= HOST_CONTROL_TDELAY_EN | HOST_CONTROL_HW_OC_P;
host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT);
- pci_read_config_dword(host->chip->pdev,
- PCI_CTL_CLOCK_DLY_ADDR,
- &clock_delay);
- clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B
- : ~PCI_CTL_CLOCK_DLY_MASK_A;
if (value == MEMSTICK_SERIAL) {
- host_ctl &= ~HOST_CONTROL_FAST_CLK;
- host_ctl &= ~HOST_CONTROL_REO;
host_ctl |= HOST_CONTROL_IF_SERIAL
<< HOST_CONTROL_IF_SHIFT;
host_ctl |= HOST_CONTROL_REI;
- clock_ctl = CLOCK_CONTROL_40MHZ;
+ clock_ctl |= CLOCK_CONTROL_40MHZ;
+ clock_delay = 0;
} else if (value == MEMSTICK_PAR4) {
- host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO;
+ host_ctl |= HOST_CONTROL_FAST_CLK;
host_ctl |= HOST_CONTROL_IF_PAR4
<< HOST_CONTROL_IF_SHIFT;
- host_ctl &= ~HOST_CONTROL_REI;
- clock_ctl = CLOCK_CONTROL_40MHZ;
- clock_delay |= host->id ? (4 << 12) : (4 << 8);
+ host_ctl |= HOST_CONTROL_REO;
+ clock_ctl |= CLOCK_CONTROL_40MHZ;
+ clock_delay = 4;
} else if (value == MEMSTICK_PAR8) {
host_ctl |= HOST_CONTROL_FAST_CLK;
host_ctl |= HOST_CONTROL_IF_PAR8
<< HOST_CONTROL_IF_SHIFT;
- host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO);
- clock_ctl = CLOCK_CONTROL_50MHZ;
+ clock_ctl |= CLOCK_CONTROL_50MHZ;
+ clock_delay = 0;
} else
return -EINVAL;
writel(host_ctl, host->addr + HOST_CONTROL);
+ writel(CLOCK_CONTROL_OFF, host->addr + CLOCK_CONTROL);
writel(clock_ctl, host->addr + CLOCK_CONTROL);
- pci_write_config_dword(host->chip->pdev,
- PCI_CTL_CLOCK_DLY_ADDR,
- clock_delay);
+ pci_write_config_byte(host->chip->pdev,
+ PCI_CTL_CLOCK_DLY_ADDR + 1,
+ clock_delay);
+ host->ifmode = value;
break;
};
return 0;
}
+#define PCI_PMOS0_CONTROL 0xae
+#define PMOS0_ENABLE 0x01
+#define PMOS0_OVERCURRENT_LEVEL_2_4V 0x06
+#define PMOS0_EN_OVERCURRENT_DEBOUNCE 0x40
+#define PMOS0_SW_LED_POLARITY_ENABLE 0x80
+#define PMOS0_ACTIVE_BITS (PMOS0_ENABLE | PMOS0_EN_OVERCURRENT_DEBOUNCE | \
+ PMOS0_OVERCURRENT_LEVEL_2_4V)
+#define PCI_PMOS1_CONTROL 0xbd
+#define PMOS1_ACTIVE_BITS 0x4a
+#define PCI_CLOCK_CTL 0xb9
+
+static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag)
+{
+ unsigned char val;
+
+ pci_read_config_byte(pdev, PCI_PMOS0_CONTROL, &val);
+ if (flag)
+ val |= PMOS0_ACTIVE_BITS;
+ else
+ val &= ~PMOS0_ACTIVE_BITS;
+ pci_write_config_byte(pdev, PCI_PMOS0_CONTROL, val);
+ dev_dbg(&pdev->dev, "JMB38x: set PMOS0 val 0x%x\n", val);
+
+ if (pci_resource_flags(pdev, 1)) {
+ pci_read_config_byte(pdev, PCI_PMOS1_CONTROL, &val);
+ if (flag)
+ val |= PMOS1_ACTIVE_BITS;
+ else
+ val &= ~PMOS1_ACTIVE_BITS;
+ pci_write_config_byte(pdev, PCI_PMOS1_CONTROL, val);
+ dev_dbg(&pdev->dev, "JMB38x: set PMOS1 val 0x%x\n", val);
+ }
+
+ pci_read_config_byte(pdev, PCI_CLOCK_CTL, &val);
+ pci_write_config_byte(pdev, PCI_CLOCK_CTL, val & ~0x0f);
+ pci_write_config_byte(pdev, PCI_CLOCK_CTL, val | 0x01);
+ dev_dbg(&pdev->dev, "Clock Control by PCI config is disabled!\n");
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
@@ -784,8 +831,7 @@ static int jmb38x_ms_resume(struct pci_dev *dev)
return rc;
pci_set_master(dev);
- pci_read_config_dword(dev, 0xac, &rc);
- pci_write_config_dword(dev, 0xac, rc | 0x00470000);
+ jmb38x_ms_pmos(dev, 1);
for (rc = 0; rc < jm->host_cnt; ++rc) {
if (!jm->hosts[rc])
@@ -894,8 +940,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev,
goto err_out;
}
- pci_read_config_dword(pdev, 0xac, &rc);
- pci_write_config_dword(pdev, 0xac, rc | 0x00470000);
+ jmb38x_ms_pmos(pdev, 1);
cnt = jmb38x_ms_count_slots(pdev);
if (!cnt) {
@@ -976,6 +1021,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
jmb38x_ms_free_host(jm->hosts[cnt]);
}
+ jmb38x_ms_pmos(dev, 0);
+
pci_set_drvdata(dev, NULL);
pci_release_regions(dev);
pci_disable_device(dev);
@@ -983,8 +1030,9 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
}
static struct pci_device_id jmb38x_ms_id_tbl [] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB385_MS) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB390_MS) },
{ }
};
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index 691620dbedd2..8b04810df469 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -268,7 +268,7 @@
/* Compatibility Error : IR Disabled */
#define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030)
-/* Compatibility Error : Inquiry Comand failed */
+/* Compatibility Error : Inquiry Command failed */
#define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031)
/* Compatibility Error : Device not direct access device */
#define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 3e57b61ca446..3358c0af3466 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -7977,7 +7977,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
NULL, /* 2Eh */
NULL, /* 2Fh */
"Compatibility Error: IR Disabled", /* 30h */
- "Compatibility Error: Inquiry Comand Failed", /* 31h */
+ "Compatibility Error: Inquiry Command Failed", /* 31h */
"Compatibility Error: Device not Direct Access "
"Device ", /* 32h */
"Compatibility Error: Removable Device Found", /* 33h */
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index e15220ff52fc..d784c36707c0 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -97,8 +97,7 @@ static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
static int mptfc_target_alloc(struct scsi_target *starget);
static int mptfc_slave_alloc(struct scsi_device *sdev);
-static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *));
+static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);
static void mptfc_target_destroy(struct scsi_target *starget);
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
static void __devexit mptfc_remove(struct pci_dev *pdev);
@@ -650,7 +649,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
}
static int
-mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptfc_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
struct mptfc_rport_info *ri;
struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
@@ -681,6 +680,8 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptfc_qcmd)
+
/*
* mptfc_display_port_link_speed - displaying link speed
* @ioc: Pointer to MPT_ADAPTER structure
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 83a5115f0251..8aefb1829fcd 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1146,7 +1146,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
*
* This function will delete scheduled target reset from the list and
* try to send next target reset. This will be called from completion
- * context of any Task managment command.
+ * context of any Task management command.
*/
void
@@ -1889,7 +1889,7 @@ mptsas_slave_alloc(struct scsi_device *sdev)
}
static int
-mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptsas_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
MPT_SCSI_HOST *hd;
MPT_ADAPTER *ioc;
@@ -1913,6 +1913,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptsas_qcmd)
+
/**
* mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
* if the device under question is currently in the
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 0e2803155ae2..6d9568d2ec59 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -780,7 +780,7 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
}
static int
-mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptspi_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
VirtDevice *vdevice = SCpnt->device->hostdata;
@@ -805,6 +805,8 @@ mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return mptscsih_qcmd(SCpnt,done);
}
+static DEF_SCSI_QCMD(mptspi_qcmd)
+
static void mptspi_slave_destroy(struct scsi_device *sdev)
{
struct scsi_target *starget = scsi_target(sdev);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index f87a9d405a5e..ae7cad185898 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -309,7 +309,7 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq)
* @ireq: I2O block request
* @mptr: message body pointer
*
- * Builds the SG list and map it to be accessable by the controller.
+ * Builds the SG list and map it to be accessible by the controller.
*
* Returns 0 on failure or 1 on success.
*/
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index ea6b2197da8a..97bdf82ec905 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -506,7 +506,7 @@ static struct i2o_driver i2o_scsi_driver = {
* Locks: takes the controller lock on error path only
*/
-static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
+static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct i2o_controller *c;
@@ -688,7 +688,9 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
exit:
return rc;
-};
+}
+
+static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
/**
* i2o_scsi_abort - abort a running command
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 20895e7a99c9..793300c554b4 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = {
},
};
-static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
- int irq)
-{
- return &pm860x_irqs[irq - chip->irq_base];
-}
-
static irqreturn_t pm860x_irq(int irq, void *data)
{
struct pm860x_chip *chip = data;
@@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void pm860x_irq_lock(unsigned int irq)
+static void pm860x_irq_lock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void pm860x_irq_sync_unlock(unsigned int irq)
+static void pm860x_irq_sync_unlock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
struct pm860x_irq_data *irq_data;
struct i2c_client *i2c;
static unsigned char cached[3] = {0x0, 0x0, 0x0};
@@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void pm860x_irq_enable(unsigned int irq)
+static void pm860x_irq_enable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable
- = pm860x_irqs[irq - chip->irq_base].offs;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable
+ = pm860x_irqs[data->irq - chip->irq_base].offs;
}
-static void pm860x_irq_disable(unsigned int irq)
+static void pm860x_irq_disable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable = 0;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip pm860x_irq_chip = {
.name = "88pm860x",
- .bus_lock = pm860x_irq_lock,
- .bus_sync_unlock = pm860x_irq_sync_unlock,
- .enable = pm860x_irq_enable,
- .disable = pm860x_irq_disable,
+ .irq_bus_lock = pm860x_irq_lock,
+ .irq_bus_sync_unlock = pm860x_irq_sync_unlock,
+ .irq_enable = pm860x_irq_enable,
+ .irq_disable = pm860x_irq_disable,
};
static int __devinit device_gpadc_init(struct pm860x_chip *chip,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3a1493b8b5e5..fd018366d670 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -218,12 +218,12 @@ config MFD_STMPE
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
-config MFD_TC35892
- bool "Support Toshiba TC35892"
+config MFD_TC3589X
+ bool "Support Toshiba TC35892 and variants"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
help
- Support for the Toshiba TC35892 I/O Expander.
+ Support for the Toshiba TC35892 and variants I/O Expander.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
@@ -496,13 +496,13 @@ config EZX_PCAP
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
- depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
+ depends on GENERIC_HARDIRQS && ABX500_CORE
select MFD_CORE
help
Select this option to enable access to AB8500 power management
- chip. This connects to U8500 either on the SSP/SPI bus
- or the I2C bus via PRCMU. It also adds the irq_chip
- parts for handling the Mixed Signal chip events.
+ chip. This connects to U8500 either on the SSP/SPI bus (deprecated
+ since hardware version v1.0) or the I2C bus via PRCMU. It also adds
+ the irq_chip parts for handling the Mixed Signal chip events.
This chip embeds various other multimedia funtionalities as well.
config AB8500_I2C_CORE
@@ -537,6 +537,14 @@ config AB3550_CORE
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
+config MFD_CS5535
+ tristate "Support for CS5535 and CS5536 southbridge core functions"
+ select MFD_CORE
+ depends on PCI
+ ---help---
+ This is the core driver for CS5535/CS5536 MFD functions. This is
+ necessary for using the board's GPIO and MFGPT functionality.
+
config MFD_TIMBERDALE
tristate "Support for the Timberdale FPGA"
select MFD_CORE
@@ -606,6 +614,16 @@ config MFD_VX855
VIA VX855/VX875 south bridge. You will need to enable the vx855_spi
and/or vx855_gpio drivers for this to do anything useful.
+config MFD_WL1273_CORE
+ tristate
+ depends on I2C
+ select MFD_CORE
+ default n
+ help
+ This is the core driver for the TI WL1273 FM radio. This MFD
+ driver connects the radio-wl1273 V4L2 module and the wl1273
+ audio codec.
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f54b3659abbb..a54e2c7c6a1c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
-obj-$(CONFIG_MFD_TC35892) += tc35892.o
+obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
@@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_CORE) += ab8500-core.o
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
@@ -81,3 +81,5 @@ obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o
obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
+obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
+obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index 8a98739e6d9c..5fbca346b998 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work)
}
}
-static void ab3550_mask(unsigned int irq)
+static void ab3550_mask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] |= BIT(irq % 8);
@@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void ab3550_unmask(unsigned int irq)
+static void ab3550_unmask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] &= ~BIT(irq % 8);
@@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void noop(unsigned int irq)
+static void noop(struct irq_data *data)
{
}
static struct irq_chip ab3550_irq_chip = {
.name = "ab3550-core", /* Keep the same name as the request */
- .startup = NULL, /* defaults to enable */
- .shutdown = NULL, /* defaults to disable */
- .enable = NULL, /* defaults to unmask */
- .disable = ab3550_mask, /* No default to mask in chip.c */
- .ack = noop,
- .mask = ab3550_mask,
- .unmask = ab3550_unmask,
- .end = NULL,
+ .irq_disable = ab3550_mask, /* No default to mask in chip.c */
+ .irq_ack = noop,
+ .irq_mask = ab3550_mask,
+ .irq_unmask = ab3550_unmask,
};
struct ab_family_id {
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index dbe1c93c1af3..b6887014d687 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -52,6 +52,7 @@
#define AB8500_IT_LATCH8_REG 0x27
#define AB8500_IT_LATCH9_REG 0x28
#define AB8500_IT_LATCH10_REG 0x29
+#define AB8500_IT_LATCH12_REG 0x2B
#define AB8500_IT_LATCH19_REG 0x32
#define AB8500_IT_LATCH20_REG 0x33
#define AB8500_IT_LATCH21_REG 0x34
@@ -98,13 +99,17 @@
* offset 0.
*/
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
- 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
static int ab8500_get_chip_id(struct device *dev)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
- return (int)ab8500->chip_id;
+ struct ab8500 *ab8500;
+
+ if (!dev)
+ return -EINVAL;
+ ab8500 = dev_get_drvdata(dev->parent);
+ return ab8500 ? (int)ab8500->chip_id : -EINVAL;
}
static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
@@ -228,16 +233,16 @@ static struct abx500_ops ab8500_ops = {
.startup_irq_enabled = NULL,
};
-static void ab8500_irq_lock(unsigned int irq)
+static void ab8500_irq_lock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
mutex_lock(&ab8500->irq_lock);
}
-static void ab8500_irq_sync_unlock(unsigned int irq)
+static void ab8500_irq_sync_unlock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
@@ -248,6 +253,10 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
if (new == old)
continue;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
+
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
@@ -257,20 +266,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
mutex_unlock(&ab8500->irq_lock);
}
-static void ab8500_irq_mask(unsigned int irq)
+static void ab8500_irq_mask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
ab8500->mask[index] |= mask;
}
-static void ab8500_irq_unmask(unsigned int irq)
+static void ab8500_irq_unmask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
@@ -279,10 +288,10 @@ static void ab8500_irq_unmask(unsigned int irq)
static struct irq_chip ab8500_irq_chip = {
.name = "ab8500",
- .bus_lock = ab8500_irq_lock,
- .bus_sync_unlock = ab8500_irq_sync_unlock,
- .mask = ab8500_irq_mask,
- .unmask = ab8500_irq_unmask,
+ .irq_bus_lock = ab8500_irq_lock,
+ .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
+ .irq_mask = ab8500_irq_mask,
+ .irq_unmask = ab8500_irq_unmask,
};
static irqreturn_t ab8500_irq(int irq, void *dev)
@@ -297,13 +306,17 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int status;
u8 value;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (regoffset == 11 && ab8500->chip_id < 0x20)
+ continue;
+
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + regoffset, &value);
if (status < 0 || value == 0)
continue;
do {
- int bit = __ffs(status);
+ int bit = __ffs(value);
int line = i * 8 + bit;
handle_nested_irq(ab8500->irq_base + line);
@@ -393,13 +406,195 @@ static struct resource ab8500_poweronkey_db_resources[] = {
},
};
+static struct resource ab8500_bm_resources[] = {
+ {
+ .name = "MAIN_EXT_CH_NOT_OK",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BATT_OVV",
+ .start = AB8500_INT_BATT_OVV,
+ .end = AB8500_INT_BATT_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_UNPLUG_DET",
+ .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CHARGE_PLUG_DET",
+ .start = AB8500_INT_MAIN_CH_PLUG_DET,
+ .end = AB8500_INT_MAIN_CH_PLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BAT_CTRL_INDB",
+ .start = AB8500_INT_BAT_CTRL_INDB,
+ .end = AB8500_INT_BAT_CTRL_INDB,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CH_WD_EXP",
+ .start = AB8500_INT_CH_WD_EXP,
+ .end = AB8500_INT_CH_WD_EXP,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_OVV",
+ .start = AB8500_INT_VBUS_OVV,
+ .end = AB8500_INT_VBUS_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "NCONV_ACCU",
+ .start = AB8500_INT_CCN_CONV_ACC,
+ .end = AB8500_INT_CCN_CONV_ACC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_F",
+ .start = AB8500_INT_LOW_BAT_F,
+ .end = AB8500_INT_LOW_BAT_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_R",
+ .start = AB8500_INT_LOW_BAT_R,
+ .end = AB8500_INT_LOW_BAT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_LOW",
+ .start = AB8500_INT_BTEMP_LOW,
+ .end = AB8500_INT_BTEMP_LOW,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_HIGH",
+ .start = AB8500_INT_BTEMP_HIGH,
+ .end = AB8500_INT_BTEMP_HIGH,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKR",
+ .start = AB8500_INT_USB_CHARGER_NOT_OK,
+ .end = AB8500_INT_USB_CHARGER_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGE_DET_DONE",
+ .start = AB8500_INT_USB_CHG_DET_DONE,
+ .end = AB8500_INT_USB_CHG_DET_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CH_TH_PROT_R",
+ .start = AB8500_INT_USB_CH_TH_PROT_R,
+ .end = AB8500_INT_USB_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_TH_PROT_R",
+ .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKF",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_debug_resources[] = {
+ {
+ .name = "IRQ_FIRST",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "IRQ_LAST",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_usb_resources[] = {
+ {
+ .name = "ID_WAKEUP_R",
+ .start = AB8500_INT_ID_WAKEUP_R,
+ .end = AB8500_INT_ID_WAKEUP_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP_F",
+ .start = AB8500_INT_ID_WAKEUP_F,
+ .end = AB8500_INT_ID_WAKEUP_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_LINK_STATUS",
+ .start = AB8500_INT_USB_LINK_STATUS,
+ .end = AB8500_INT_USB_LINK_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_temp_resources[] = {
+ {
+ .name = "AB8500_TEMP_WARM",
+ .start = AB8500_INT_TEMP_WARM,
+ .end = AB8500_INT_TEMP_WARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
},
#endif
{
+ .name = "ab8500-sysctrl",
+ },
+ {
+ .name = "ab8500-regulator",
+ },
+ {
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
@@ -410,6 +605,22 @@ static struct mfd_cell ab8500_devs[] = {
.resources = ab8500_rtc_resources,
},
{
+ .name = "ab8500-bm",
+ .num_resources = ARRAY_SIZE(ab8500_bm_resources),
+ .resources = ab8500_bm_resources,
+ },
+ { .name = "ab8500-codec", },
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
.name = "ab8500-pwm",
.id = 1,
},
@@ -421,17 +632,37 @@ static struct mfd_cell ab8500_devs[] = {
.name = "ab8500-pwm",
.id = 3,
},
- { .name = "ab8500-charger", },
- { .name = "ab8500-audio", },
- { .name = "ab8500-usb", },
- { .name = "ab8500-regulator", },
+ { .name = "ab8500-leds", },
{
- .name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
+ .name = "ab8500-denc",
+ },
+ {
+ .name = "ab8500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
},
};
+static ssize_t show_chip_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ab8500 *ab8500;
+
+ ab8500 = dev_get_drvdata(dev);
+ return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+
+static struct attribute *ab8500_sysfs_entries[] = {
+ &dev_attr_chip_id.attr,
+ NULL,
+};
+
+static struct attribute_group ab8500_attr_group = {
+ .attrs = ab8500_sysfs_entries,
+};
+
int __devinit ab8500_init(struct ab8500 *ab8500)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
@@ -454,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
* 0x0 - Early Drop
* 0x10 - Cut 1.0
* 0x11 - Cut 1.1
+ * 0x20 - Cut 2.0
*/
- if (value == 0x0 || value == 0x10 || value == 0x11) {
+ if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
ab8500->revision = value;
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
} else {
@@ -468,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
plat->init(ab8500);
/* Clear and mask all interrupts */
- for (i = 0; i < 10; i++) {
- get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
- set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
- }
+ for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
- for (i = 18; i < 24; i++) {
get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
+ AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+ &value);
set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
+ AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
}
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
@@ -495,7 +725,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
return ret;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
- IRQF_ONESHOT, "ab8500", ab8500);
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "ab8500", ab8500);
if (ret)
goto out_removeirq;
}
@@ -506,6 +737,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
if (ret)
goto out_freeirq;
+ ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if (ret)
+ dev_err(ab8500->dev, "error creating sysfs entries\n");
+
return ret;
out_freeirq:
@@ -519,6 +754,7 @@ out_removeirq:
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
+ sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 8d1e05a39815..3c1541ae7223 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -24,9 +24,9 @@ static u32 debug_address;
* @perm: access permissions for the range
*/
struct ab8500_reg_range {
- u8 first;
- u8 last;
- u8 perm;
+ u8 first;
+ u8 last;
+ u8 perm;
};
/**
@@ -36,9 +36,9 @@ struct ab8500_reg_range {
* @range: the list of register ranges
*/
struct ab8500_i2c_ranges {
- u8 num_ranges;
- u8 bankid;
- const struct ab8500_reg_range *range;
+ u8 num_ranges;
+ u8 bankid;
+ const struct ab8500_reg_range *range;
};
#define AB8500_NAME_STRING "ab8500"
@@ -47,521 +47,521 @@ struct ab8500_i2c_ranges {
#define AB8500_REV_REG 0x80
static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
- [0x0] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_SYS_CTRL1_BLOCK] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x02,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_SYS_CTRL2_BLOCK] = {
- .num_ranges = 4,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0D,
- },
- {
- .first = 0x0F,
- .last = 0x17,
- },
- {
- .first = 0x30,
- .last = 0x30,
- },
- {
- .first = 0x32,
- .last = 0x33,
- },
- },
- },
- [AB8500_REGU_CTRL1] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x03,
- .last = 0x10,
- },
- {
- .first = 0x80,
- .last = 0x84,
- },
- },
- },
- [AB8500_REGU_CTRL2] = {
- .num_ranges = 5,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x15,
- },
- {
- .first = 0x17,
- .last = 0x19,
- },
- {
- .first = 0x1B,
- .last = 0x1D,
- },
- {
- .first = 0x1F,
- .last = 0x22,
- },
- {
- .first = 0x40,
- .last = 0x44,
- },
- /* 0x80-0x8B is SIM registers and should
- * not be accessed from here */
- },
- },
- [AB8500_USB] = {
- .num_ranges = 2,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x83,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- },
- },
- },
- [AB8500_TVOUT] = {
- .num_ranges = 9,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x12,
- },
- {
- .first = 0x15,
- .last = 0x17,
- },
- {
- .first = 0x19,
- .last = 0x21,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- },
- {
- .first = 0x41,
- .last = 0x41,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- },
- {
- .first = 0x69,
- .last = 0x69,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_DBI] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_ECI_AV_ACC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x82,
- },
- },
- },
- [0x9] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_GPADC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- },
- },
- },
- [AB8500_CHARGER] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x03,
- },
- {
- .first = 0x05,
- .last = 0x05,
- },
- {
- .first = 0x40,
- .last = 0x40,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x44,
- .last = 0x44,
- },
- {
- .first = 0x50,
- .last = 0x55,
- },
- {
- .first = 0x80,
- .last = 0x82,
- },
- {
- .first = 0xC0,
- .last = 0xC2,
- },
- },
- },
- [AB8500_GAS_GAUGE] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x07,
- .last = 0x0A,
- },
- {
- .first = 0x10,
- .last = 0x14,
- },
- },
- },
- [AB8500_AUDIO] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x6F,
- },
- },
- },
- [AB8500_INTERRUPT] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_RTC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0F,
- },
- },
- },
- [AB8500_MISC] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x05,
- },
- {
- .first = 0x10,
- .last = 0x15,
- },
- {
- .first = 0x20,
- .last = 0x25,
- },
- {
- .first = 0x30,
- .last = 0x35,
- },
- {
- .first = 0x40,
- .last = 0x45,
- },
- {
- .first = 0x50,
- .last = 0x50,
- },
- {
- .first = 0x60,
- .last = 0x67,
- },
- {
- .first = 0x80,
- .last = 0x80,
- },
- },
- },
- [0x11] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x12] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x13] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x14] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_OTP_EMUL] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x0F,
- },
- },
- },
+ [0x0] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x02,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x17,
+ },
+ {
+ .first = 0x30,
+ .last = 0x30,
+ },
+ {
+ .first = 0x32,
+ .last = 0x33,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x03,
+ .last = 0x10,
+ },
+ {
+ .first = 0x80,
+ .last = 0x84,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x22,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ /* 0x80-0x8B is SIM registers and should
+ * not be accessed from here */
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x12,
+ },
+ {
+ .first = 0x15,
+ .last = 0x17,
+ },
+ {
+ .first = 0x19,
+ .last = 0x21,
+ },
+ {
+ .first = 0x27,
+ .last = 0x2C,
+ },
+ {
+ .first = 0x41,
+ .last = 0x41,
+ },
+ {
+ .first = 0x45,
+ .last = 0x5B,
+ },
+ {
+ .first = 0x5D,
+ .last = 0x5D,
+ },
+ {
+ .first = 0x69,
+ .last = 0x69,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [0x9] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x08,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x40,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x44,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x55,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC2,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x6F,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0F,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x05,
+ },
+ {
+ .first = 0x10,
+ .last = 0x15,
+ },
+ {
+ .first = 0x20,
+ .last = 0x25,
+ },
+ {
+ .first = 0x30,
+ .last = 0x35,
+ },
+ {
+ .first = 0x40,
+ .last = 0x45,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x67,
+ },
+ {
+ .first = 0x80,
+ .last = 0x80,
+ },
+ },
+ },
+ [0x11] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x12] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x13] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x14] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x0F,
+ },
+ },
+ },
};
static int ab8500_registers_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- unsigned int i;
- u32 bank = debug_bank;
-
- seq_printf(s, AB8500_NAME_STRING " register values:\n");
-
- seq_printf(s, " bank %u:\n", bank);
- for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
- u32 reg;
-
- for (reg = debug_ranges[bank].range[i].first;
- reg <= debug_ranges[bank].range[i].last;
- reg++) {
- u8 value;
- int err;
-
- err = abx500_get_register_interruptible(dev,
- (u8)bank, (u8)reg, &value);
- if (err < 0) {
- dev_err(dev, "ab->read fail %d\n", err);
- return err;
- }
-
- err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
- reg, value);
- if (err < 0) {
- dev_err(dev, "seq_printf overflow\n");
- /* Error is not returned here since
- * the output is wanted in any case */
- return 0;
- }
- }
- }
- return 0;
+ struct device *dev = s->private;
+ unsigned int i;
+ u32 bank = debug_bank;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u:\n", bank);
+ for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+ u32 reg;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+ int err;
+
+ err = abx500_get_register_interruptible(dev,
+ (u8)bank, (u8)reg, &value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+
+ err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
+ reg, value);
+ if (err < 0) {
+ dev_err(dev, "seq_printf overflow\n");
+ /* Error is not returned here since
+ * the output is wanted in any case */
+ return 0;
+ }
+ }
+ }
+ return 0;
}
static int ab8500_registers_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_registers_print, inode->i_private);
+ return single_open(file, ab8500_registers_print, inode->i_private);
}
static const struct file_operations ab8500_registers_fops = {
- .open = ab8500_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static int ab8500_bank_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "%d\n", debug_bank);
+ return seq_printf(s, "%d\n", debug_bank);
}
static int ab8500_bank_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_bank_print, inode->i_private);
+ return single_open(file, ab8500_bank_print, inode->i_private);
}
static ssize_t ab8500_bank_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_bank;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_bank);
- if (err)
- return -EINVAL;
-
- if (user_bank >= AB8500_NUM_BANKS) {
- dev_err(dev, "debugfs error input > number of banks\n");
- return -EINVAL;
- }
-
- debug_bank = user_bank;
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_bank;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_bank);
+ if (err)
+ return -EINVAL;
+
+ if (user_bank >= AB8500_NUM_BANKS) {
+ dev_err(dev, "debugfs error input > number of banks\n");
+ return -EINVAL;
+ }
+
+ debug_bank = user_bank;
+
+ return buf_size;
}
static int ab8500_address_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "0x%02X\n", debug_address);
+ return seq_printf(s, "0x%02X\n", debug_address);
}
static int ab8500_address_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_address_print, inode->i_private);
+ return single_open(file, ab8500_address_print, inode->i_private);
}
static ssize_t ab8500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_address;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_address);
- if (err)
- return -EINVAL;
- if (user_address > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- debug_address = user_address;
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_address;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_address);
+ if (err)
+ return -EINVAL;
+ if (user_address > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ debug_address = user_address;
+ return buf_size;
}
static int ab8500_val_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- int ret;
- u8 regvalue;
-
- ret = abx500_get_register_interruptible(dev,
- (u8)debug_bank, (u8)debug_address, &regvalue);
- if (ret < 0) {
- dev_err(dev, "abx500_get_reg fail %d, %d\n",
- ret, __LINE__);
- return -EINVAL;
- }
- seq_printf(s, "0x%02X\n", regvalue);
-
- return 0;
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)debug_bank, (u8)debug_address, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+ seq_printf(s, "0x%02X\n", regvalue);
+
+ return 0;
}
static int ab8500_val_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_val_print, inode->i_private);
+ return single_open(file, ab8500_val_print, inode->i_private);
}
static ssize_t ab8500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_val;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
- if (err)
- return -EINVAL;
- if (user_val > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- err = abx500_set_register_interruptible(dev,
- (u8)debug_bank, debug_address, (u8)user_val);
- if (err < 0) {
- printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
- return -EINVAL;
- }
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ err = abx500_set_register_interruptible(dev,
+ (u8)debug_bank, debug_address, (u8)user_val);
+ if (err < 0) {
+ printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+ return -EINVAL;
+ }
+
+ return buf_size;
}
static const struct file_operations ab8500_bank_fops = {
- .open = ab8500_bank_open,
- .write = ab8500_bank_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_bank_open,
+ .write = ab8500_bank_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_address_fops = {
- .open = ab8500_address_open,
- .write = ab8500_address_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_address_open,
+ .write = ab8500_address_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_val_fops = {
- .open = ab8500_val_open,
- .write = ab8500_val_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_val_open,
+ .write = ab8500_val_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static struct dentry *ab8500_dir;
@@ -572,77 +572,77 @@ static struct dentry *ab8500_val_file;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
- debug_bank = AB8500_MISC;
- debug_address = AB8500_REV_REG & 0x00FF;
+ debug_bank = AB8500_MISC;
+ debug_address = AB8500_REV_REG & 0x00FF;
- ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
- if (!ab8500_dir)
- goto exit_no_debugfs;
+ ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+ if (!ab8500_dir)
+ goto exit_no_debugfs;
- ab8500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
- if (!ab8500_reg_file)
- goto exit_destroy_dir;
+ ab8500_reg_file = debugfs_create_file("all-bank-registers",
+ S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!ab8500_reg_file)
+ goto exit_destroy_dir;
- ab8500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
- if (!ab8500_bank_file)
- goto exit_destroy_reg;
+ ab8500_bank_file = debugfs_create_file("register-bank",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!ab8500_bank_file)
+ goto exit_destroy_reg;
- ab8500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
- &ab8500_address_fops);
- if (!ab8500_address_file)
- goto exit_destroy_bank;
+ ab8500_address_file = debugfs_create_file("register-address",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_address_fops);
+ if (!ab8500_address_file)
+ goto exit_destroy_bank;
- ab8500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
- if (!ab8500_val_file)
- goto exit_destroy_address;
+ ab8500_val_file = debugfs_create_file("register-value",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!ab8500_val_file)
+ goto exit_destroy_address;
- return 0;
+ return 0;
exit_destroy_address:
- debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_address_file);
exit_destroy_bank:
- debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_bank_file);
exit_destroy_reg:
- debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_reg_file);
exit_destroy_dir:
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_dir);
exit_no_debugfs:
- dev_err(&plf->dev, "failed to create debugfs entries.\n");
- return -ENOMEM;
+ dev_err(&plf->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
}
static int __devexit ab8500_debug_remove(struct platform_device *plf)
{
- debugfs_remove(ab8500_val_file);
- debugfs_remove(ab8500_address_file);
- debugfs_remove(ab8500_bank_file);
- debugfs_remove(ab8500_reg_file);
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_val_file);
+ debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_dir);
- return 0;
+ return 0;
}
static struct platform_driver ab8500_debug_driver = {
- .driver = {
- .name = "ab8500-debug",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_debug_probe,
- .remove = __devexit_p(ab8500_debug_remove)
+ .driver = {
+ .name = "ab8500-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_debug_probe,
+ .remove = __devexit_p(ab8500_debug_remove)
};
static int __init ab8500_debug_init(void)
{
- return platform_driver_register(&ab8500_debug_driver);
+ return platform_driver_register(&ab8500_debug_driver);
}
static void __exit ab8500_debug_exit(void)
{
- platform_driver_unregister(&ab8500_debug_driver);
+ platform_driver_unregister(&ab8500_debug_driver);
}
subsys_initcall(ab8500_debug_init);
module_exit(ab8500_debug_exit);
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
deleted file mode 100644
index b1653421edb5..000000000000
--- a/drivers/mfd/ab8500-spi.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
-
-/*
- * This funtion writes to any AB8500 registers using
- * SPI protocol & before it writes it packs the data
- * in the below 24 bit frame format
- *
- * *|------------------------------------|
- * *| 23|22...18|17.......10|9|8|7......0|
- * *| r/w bank adr data |
- * * ------------------------------------
- *
- * This function shouldn't be called from interrupt
- * context
- */
-static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = addr << 10 | data;
- struct spi_transfer xfer;
- struct spi_message msg;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = NULL;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(spi, &msg);
-}
-
-static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = 1 << 23 | addr << 10;
- struct spi_transfer xfer;
- struct spi_message msg;
- int ret;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = ab8500->rx_buf;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- ret = spi_sync(spi, &msg);
- if (!ret)
- /*
- * Only the 8 lowermost bytes are
- * defined with value, the rest may
- * vary depending on chip/board noise.
- */
- ret = ab8500->rx_buf[0] & 0xFFU;
-
- return ret;
-}
-
-static int __devinit ab8500_spi_probe(struct spi_device *spi)
-{
- struct ab8500 *ab8500;
- int ret;
-
- spi->bits_per_word = 24;
- ret = spi_setup(spi);
- if (ret < 0)
- return ret;
-
- ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
- if (!ab8500)
- return -ENOMEM;
-
- ab8500->dev = &spi->dev;
- ab8500->irq = spi->irq;
-
- ab8500->read = ab8500_spi_read;
- ab8500->write = ab8500_spi_write;
-
- spi_set_drvdata(spi, ab8500);
-
- ret = ab8500_init(ab8500);
- if (ret)
- kfree(ab8500);
-
- return ret;
-}
-
-static int __devexit ab8500_spi_remove(struct spi_device *spi)
-{
- struct ab8500 *ab8500 = spi_get_drvdata(spi);
-
- ab8500_exit(ab8500);
- kfree(ab8500);
-
- return 0;
-}
-
-static struct spi_driver ab8500_spi_driver = {
- .driver = {
- .name = "ab8500-spi",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_spi_probe,
- .remove = __devexit_p(ab8500_spi_remove)
-};
-
-static int __init ab8500_spi_init(void)
-{
- return spi_register_driver(&ab8500_spi_driver);
-}
-subsys_initcall(ab8500_spi_init);
-
-static void __exit ab8500_spi_exit(void)
-{
- spi_unregister_driver(&ab8500_spi_driver);
-}
-module_exit(ab8500_spi_exit);
-
-MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
-MODULE_DESCRIPTION("AB8500 SPI");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 7de708d15d72..6a1f94042612 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -57,7 +57,7 @@ struct asic3_clk {
.rate = _rate, \
}
-struct asic3_clk asic3_clk_init[] __initdata = {
+static struct asic3_clk asic3_clk_init[] __initdata = {
INIT_CDEX(SPI, 0),
INIT_CDEX(OWM, 5000000),
INIT_CDEX(PWM0, 0),
@@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic,
(reg >> asic->bus_shift));
}
-void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
+static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
{
unsigned long flags;
u32 val;
@@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
return (irq - asic->irq_base) & 0xf;
}
-static void asic3_mask_gpio_irq(unsigned int irq)
+static void asic3_mask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_mask_irq(unsigned int irq)
+static void asic3_mask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval &= ~(ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_gpio_irq(unsigned int irq)
+static void asic3_unmask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_irq(unsigned int irq)
+static void asic3_unmask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval |= (ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 bank, index;
u16 trigger, level, edge, bit;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
bit = 1<<index;
spin_lock_irqsave(&asic->lock, flags);
@@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
bank + ASIC3_GPIO_EDGE_TRIGGER);
trigger = asic3_read_register(asic,
bank + ASIC3_GPIO_TRIGGER_TYPE);
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
if (type == IRQ_TYPE_EDGE_RISING) {
trigger |= bit;
@@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
edge &= ~bit;
} else if (type == IRQ_TYPE_EDGE_BOTH) {
trigger |= bit;
- if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
+ if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
edge &= ~bit;
else
edge |= bit;
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
} else if (type == IRQ_TYPE_LEVEL_LOW) {
trigger &= ~bit;
level &= ~bit;
@@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
static struct irq_chip asic3_gpio_irq_chip = {
.name = "ASIC3-GPIO",
- .ack = asic3_mask_gpio_irq,
- .mask = asic3_mask_gpio_irq,
- .unmask = asic3_unmask_gpio_irq,
- .set_type = asic3_gpio_irq_type,
+ .irq_ack = asic3_mask_gpio_irq,
+ .irq_mask = asic3_mask_gpio_irq,
+ .irq_unmask = asic3_unmask_gpio_irq,
+ .irq_set_type = asic3_gpio_irq_type,
};
static struct irq_chip asic3_irq_chip = {
.name = "ASIC3",
- .ack = asic3_mask_irq,
- .mask = asic3_mask_irq,
- .unmask = asic3_unmask_irq,
+ .irq_ack = asic3_mask_irq,
+ .irq_mask = asic3_mask_irq,
+ .irq_unmask = asic3_unmask_irq,
};
static int __init asic3_irq_probe(struct platform_device *pdev)
@@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = {
},
{
.start = ASIC3_IRQ_OWM,
- .start = ASIC3_IRQ_OWM,
+ .end = ASIC3_IRQ_OWM,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
};
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
new file mode 100644
index 000000000000..59ca6f151e78
--- /dev/null
+++ b/drivers/mfd/cs5535-mfd.c
@@ -0,0 +1,151 @@
+/*
+ * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
+ *
+ * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
+ * used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has
+ * an IO range that's specified in a single BAR. The BAR order is
+ * hardcoded in the CS553x specifications.
+ *
+ * Copyright (c) 2010 Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#define DRV_NAME "cs5535-mfd"
+
+enum cs5535_mfd_bars {
+ SMB_BAR = 0,
+ GPIO_BAR = 1,
+ MFGPT_BAR = 2,
+ PMS_BAR = 4,
+ ACPI_BAR = 5,
+ NR_BARS,
+};
+
+static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
+
+static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
+ {
+ .id = SMB_BAR,
+ .name = "cs5535-smb",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[SMB_BAR],
+ },
+ {
+ .id = GPIO_BAR,
+ .name = "cs5535-gpio",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[GPIO_BAR],
+ },
+ {
+ .id = MFGPT_BAR,
+ .name = "cs5535-mfgpt",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[MFGPT_BAR],
+ },
+ {
+ .id = PMS_BAR,
+ .name = "cs5535-pms",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[PMS_BAR],
+ },
+ {
+ .id = ACPI_BAR,
+ .name = "cs5535-acpi",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[ACPI_BAR],
+ },
+};
+
+static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err, i;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ /* fill in IO range for each cell; subdrivers handle the region */
+ for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) {
+ int bar = cs5535_mfd_cells[i].id;
+ struct resource *r = &cs5535_mfd_resources[bar];
+
+ r->flags = IORESOURCE_IO;
+ r->start = pci_resource_start(pdev, bar);
+ r->end = pci_resource_end(pdev, bar);
+
+ /* id is used for temporarily storing BAR; unset it now */
+ cs5535_mfd_cells[i].id = 0;
+ }
+
+ err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
+ ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
+ if (err) {
+ dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
+ goto err_disable;
+ }
+
+ dev_info(&pdev->dev, "%zu devices registered.\n",
+ ARRAY_SIZE(cs5535_mfd_cells));
+
+ return 0;
+
+err_disable:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
+{
+ mfd_remove_devices(&pdev->dev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
+
+static struct pci_driver cs5535_mfd_drv = {
+ .name = DRV_NAME,
+ .id_table = cs5535_mfd_pci_tbl,
+ .probe = cs5535_mfd_probe,
+ .remove = __devexit_p(cs5535_mfd_remove),
+};
+
+static int __init cs5535_mfd_init(void)
+{
+ return pci_register_driver(&cs5535_mfd_drv);
+}
+
+static void __exit cs5535_mfd_exit(void)
+{
+ pci_unregister_driver(&cs5535_mfd_drv);
+}
+
+module_init(cs5535_mfd_init);
+module_exit(cs5535_mfd_exit);
+
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
+MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index c2b698d69a93..9e2d8dd5f9e5 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq)
}
EXPORT_SYMBOL_GPL(pcap_to_irq);
-static void pcap_mask_irq(unsigned int irq)
+static void pcap_mask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr |= 1 << irq_to_pcap(pcap, irq);
+ pcap->msr |= 1 << irq_to_pcap(pcap, d->irq);
queue_work(pcap->workqueue, &pcap->msr_work);
}
-static void pcap_unmask_irq(unsigned int irq)
+static void pcap_unmask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
+ pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq));
queue_work(pcap->workqueue, &pcap->msr_work);
}
static struct irq_chip pcap_irq_chip = {
- .name = "pcap",
- .mask = pcap_mask_irq,
- .unmask = pcap_unmask_irq,
+ .name = "pcap",
+ .irq_mask = pcap_mask_irq,
+ .irq_unmask = pcap_unmask_irq,
};
static void pcap_msr_work(struct work_struct *work)
@@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work)
if (service & 1) {
struct irq_desc *desc = irq_to_desc(irq);
- if (WARN(!desc, KERN_WARNING
- "Invalid PCAP IRQ %d\n", irq))
+ if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq))
break;
if (desc->status & IRQ_DISABLED)
@@ -218,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct pcap_chip *pcap = get_irq_data(irq);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
queue_work(pcap->workqueue, &pcap->isr_work);
return;
}
@@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
mutex_lock(&pcap->adc_mutex);
req = pcap->adc_queue[pcap->adc_head];
- if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+ if (WARN(!req, "adc irq without pending request\n")) {
mutex_unlock(&pcap->adc_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index d3e74f8585e0..d00b6d1a69e5 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei)
ei->ack_write, ei->ack_register << ei->bus_shift);
}
-static void egpio_ack(unsigned int irq)
+static void egpio_ack(struct irq_data *data)
{
}
/* There does not appear to be a way to proactively mask interrupts
* on the egpio chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void egpio_mask(unsigned int irq)
+static void egpio_mask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
- pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
+ pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
}
-static void egpio_unmask(unsigned int irq)
+
+static void egpio_unmask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled |= 1 << (irq - ei->irq_start);
- pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
+ pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
}
static struct irq_chip egpio_muxed_chip = {
- .name = "htc-egpio",
- .ack = egpio_ack,
- .mask = egpio_mask,
- .unmask = egpio_unmask,
+ .name = "htc-egpio",
+ .irq_ack = egpio_ack,
+ .irq_mask = egpio_mask,
+ .irq_unmask = egpio_unmask,
};
static void egpio_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 594c9a8e25e1..296ad1562f69 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -82,25 +82,25 @@ struct htcpld_data {
/* There does not appear to be a way to proactively mask interrupts
* on the htcpld chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void htcpld_mask(unsigned int irq)
+static void htcpld_mask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
- pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start));
+ pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static void htcpld_unmask(unsigned int irq)
+static void htcpld_unmask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled |= 1 << (irq - chip->irq_start);
- pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled |= 1 << (data->irq - chip->irq_start);
+ pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static int htcpld_set_type(unsigned int irq, unsigned int flags)
+static int htcpld_set_type(struct irq_data *data, unsigned int flags)
{
- struct irq_desc *d = irq_to_desc(irq);
+ struct irq_desc *d = irq_to_desc(data->irq);
if (!d) {
- pr_err("HTCPLD invalid IRQ: %d\n", irq);
+ pr_err("HTCPLD invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags)
}
static struct irq_chip htcpld_muxed_chip = {
- .name = "htcpld",
- .mask = htcpld_mask,
- .unmask = htcpld_unmask,
- .set_type = htcpld_set_type,
+ .name = "htcpld",
+ .irq_mask = htcpld_mask,
+ .irq_unmask = htcpld_unmask,
+ .irq_set_type = htcpld_set_type,
};
/* To properly dispatch IRQ events, we need to read from the
@@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
* and that work is scheduled in the set routine. The kernel can then run
* the I2C functions, which will sleep, in process context.
*/
-void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
+static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct i2c_client *client;
struct htcpld_chip *chip_data;
@@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
schedule_work(&(chip_data->set_val_work));
}
-void htcpld_chip_set_ni(struct work_struct *work)
+static void htcpld_chip_set_ni(struct work_struct *work)
{
struct htcpld_chip *chip_data;
struct i2c_client *client;
@@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work)
i2c_smbus_read_byte_data(client, chip_data->cache_out);
}
-int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
int val = 0;
@@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
return (offset < chip->ngpio) ? 0 : -EINVAL;
}
-int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
@@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
-void htcpld_chip_reset(struct i2c_client *client)
+static void htcpld_chip_reset(struct i2c_client *client)
{
struct htcpld_chip *chip_data = i2c_get_clientdata(client);
if (!chip_data)
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 9dd1b33f2275..0cc59795f600 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
spin_unlock_irqrestore(&adc->lock, flags);
}
-static void jz4740_adc_irq_mask(unsigned int irq)
+static void jz4740_adc_irq_mask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, true);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, true);
}
-static void jz4740_adc_irq_unmask(unsigned int irq)
+static void jz4740_adc_irq_unmask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, false);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, false);
}
-static void jz4740_adc_irq_ack(unsigned int irq)
+static void jz4740_adc_irq_ack(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
-
- irq -= adc->irq_base;
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq - adc->irq_base;
writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
}
static struct irq_chip jz4740_adc_irq_chip = {
.name = "jz4740-adc",
- .mask = jz4740_adc_irq_mask,
- .unmask = jz4740_adc_irq_unmask,
- .ack = jz4740_adc_irq_ack,
+ .irq_mask = jz4740_adc_irq_mask,
+ .irq_unmask = jz4740_adc_irq_unmask,
+ .irq_ack = jz4740_adc_irq_ack,
};
static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 44695f5a1800..0e998dc4e7d8 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void max8925_irq_lock(unsigned int irq)
+static void max8925_irq_lock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void max8925_irq_sync_unlock(unsigned int irq)
+static void max8925_irq_sync_unlock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
struct max8925_irq_data *irq_data;
static unsigned char cache_chg[2] = {0xff, 0xff};
static unsigned char cache_on[2] = {0xff, 0xff};
@@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void max8925_irq_enable(unsigned int irq)
+static void max8925_irq_enable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable
- = max8925_irqs[irq - chip->irq_base].offs;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable
+ = max8925_irqs[data->irq - chip->irq_base].offs;
}
-static void max8925_irq_disable(unsigned int irq)
+static void max8925_irq_disable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable = 0;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip max8925_irq_chip = {
.name = "max8925",
- .bus_lock = max8925_irq_lock,
- .bus_sync_unlock = max8925_irq_sync_unlock,
- .enable = max8925_irq_enable,
- .disable = max8925_irq_disable,
+ .irq_bus_lock = max8925_irq_lock,
+ .irq_bus_sync_unlock = max8925_irq_sync_unlock,
+ .irq_enable = max8925_irq_enable,
+ .irq_disable = max8925_irq_disable,
};
static int max8925_irq_init(struct max8925_chip *chip, int irq,
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c
index 45bfe77b639b..3903e1fbb334 100644
--- a/drivers/mfd/max8998-irq.c
+++ b/drivers/mfd/max8998-irq.c
@@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
return &max8998_irqs[irq - max8998->irq_base];
}
-static void max8998_irq_lock(unsigned int irq)
+static void max8998_irq_lock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
mutex_lock(&max8998->irqlock);
}
-static void max8998_irq_sync_unlock(unsigned int irq)
+static void max8998_irq_sync_unlock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
@@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq)
mutex_unlock(&max8998->irqlock);
}
-static void max8998_irq_unmask(unsigned int irq)
+static void max8998_irq_unmask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void max8998_irq_mask(unsigned int irq)
+static void max8998_irq_mask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip max8998_irq_chip = {
.name = "max8998",
- .bus_lock = max8998_irq_lock,
- .bus_sync_unlock = max8998_irq_sync_unlock,
- .mask = max8998_irq_mask,
- .unmask = max8998_irq_unmask,
+ .irq_bus_lock = max8998_irq_lock,
+ .irq_bus_sync_unlock = max8998_irq_sync_unlock,
+ .irq_mask = max8998_irq_mask,
+ .irq_unmask = max8998_irq_unmask,
};
static irqreturn_t max8998_irq_thread(int irq, void *data)
@@ -181,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
return IRQ_HANDLED;
}
+int max8998_irq_resume(struct max8998_dev *max8998)
+{
+ if (max8998->irq && max8998->irq_base)
+ max8998_irq_thread(max8998->irq_base, max8998);
+ return 0;
+}
+
int max8998_irq_init(struct max8998_dev *max8998)
{
int i;
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index bb9977bebe78..bbfe86732602 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -25,6 +25,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max8998.h>
@@ -40,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
},
};
+static struct mfd_cell lp3974_devs[] = {
+ {
+ .name = "lp3974-pmic",
+ }, {
+ .name = "lp3974-rtc",
+ },
+};
+
int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
{
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
@@ -135,6 +145,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (pdata) {
max8998->ono = pdata->ono;
max8998->irq_base = pdata->irq_base;
+ max8998->wakeup = pdata->wakeup;
}
mutex_init(&max8998->iolock);
@@ -143,9 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
max8998_irq_init(max8998);
- ret = mfd_add_devices(max8998->dev, -1,
- max8998_devs, ARRAY_SIZE(max8998_devs),
- NULL, 0);
+ pm_runtime_set_active(max8998->dev);
+
+ switch (id->driver_data) {
+ case TYPE_LP3974:
+ ret = mfd_add_devices(max8998->dev, -1,
+ lp3974_devs, ARRAY_SIZE(lp3974_devs),
+ NULL, 0);
+ break;
+ case TYPE_MAX8998:
+ ret = mfd_add_devices(max8998->dev, -1,
+ max8998_devs, ARRAY_SIZE(max8998_devs),
+ NULL, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
if (ret < 0)
goto err;
@@ -178,10 +203,113 @@ static const struct i2c_device_id max8998_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
+static int max8998_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 1);
+ return 0;
+}
+
+static int max8998_resume(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 0);
+ /*
+ * In LP3974, if IRQ registers are not "read & clear"
+ * when it's set during sleep, the interrupt becomes
+ * disabled.
+ */
+ return max8998_irq_resume(i2c_get_clientdata(i2c));
+}
+
+struct max8998_reg_dump {
+ u8 addr;
+ u8 val;
+};
+#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, }
+struct max8998_reg_dump max8998_dump[] = {
+ SAVE_ITEM(MAX8998_REG_IRQM1),
+ SAVE_ITEM(MAX8998_REG_IRQM2),
+ SAVE_ITEM(MAX8998_REG_IRQM3),
+ SAVE_ITEM(MAX8998_REG_IRQM4),
+ SAVE_ITEM(MAX8998_REG_STATUSM1),
+ SAVE_ITEM(MAX8998_REG_STATUSM2),
+ SAVE_ITEM(MAX8998_REG_CHGR1),
+ SAVE_ITEM(MAX8998_REG_CHGR2),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3),
+ SAVE_ITEM(MAX8998_REG_ONOFF1),
+ SAVE_ITEM(MAX8998_REG_ONOFF2),
+ SAVE_ITEM(MAX8998_REG_ONOFF3),
+ SAVE_ITEM(MAX8998_REG_ONOFF4),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_LDO2_LDO3),
+ SAVE_ITEM(MAX8998_REG_LDO4),
+ SAVE_ITEM(MAX8998_REG_LDO5),
+ SAVE_ITEM(MAX8998_REG_LDO6),
+ SAVE_ITEM(MAX8998_REG_LDO7),
+ SAVE_ITEM(MAX8998_REG_LDO8_LDO9),
+ SAVE_ITEM(MAX8998_REG_LDO10_LDO11),
+ SAVE_ITEM(MAX8998_REG_LDO12),
+ SAVE_ITEM(MAX8998_REG_LDO13),
+ SAVE_ITEM(MAX8998_REG_LDO14),
+ SAVE_ITEM(MAX8998_REG_LDO15),
+ SAVE_ITEM(MAX8998_REG_LDO16),
+ SAVE_ITEM(MAX8998_REG_LDO17),
+ SAVE_ITEM(MAX8998_REG_BKCHR),
+ SAVE_ITEM(MAX8998_REG_LBCNFG1),
+ SAVE_ITEM(MAX8998_REG_LBCNFG2),
+};
+/* Save registers before hibernation */
+static int max8998_freeze(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_read_reg(i2c, max8998_dump[i].addr,
+ &max8998_dump[i].val);
+
+ return 0;
+}
+
+/* Restore registers after hibernation */
+static int max8998_restore(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_write_reg(i2c, max8998_dump[i].addr,
+ max8998_dump[i].val);
+
+ return 0;
+}
+
+const struct dev_pm_ops max8998_pm = {
+ .suspend = max8998_suspend,
+ .resume = max8998_resume,
+ .freeze = max8998_freeze,
+ .restore = max8998_restore,
+};
+
static struct i2c_driver max8998_i2c_driver = {
.driver = {
.name = "max8998",
.owner = THIS_MODULE,
+ .pm = &max8998_pm,
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index a2ac2ed6d64c..b9fcaf0004da 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi)
if (ret) {
err_mask:
err_revision:
- mutex_unlock(&mc13xxx->lock);
+ mc13xxx_unlock(mc13xxx);
dev_set_drvdata(&spi->dev, NULL);
kfree(mc13xxx);
return ret;
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index 4ba85bbdb4c1..9cee8e7f0bcb 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1259,7 +1259,7 @@ static int menelaus_probe(struct i2c_client *client,
return 0;
fail2:
free_irq(client->irq, menelaus);
- flush_scheduled_work();
+ flush_work_sync(&menelaus->work);
fail1:
kfree(menelaus);
return err;
@@ -1270,6 +1270,7 @@ static int __exit menelaus_remove(struct i2c_client *client)
struct menelaus_chip *menelaus = i2c_get_clientdata(client);
free_irq(client->irq, menelaus);
+ flush_work_sync(&menelaus->work);
kfree(menelaus);
the_menelaus = NULL;
return 0;
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index ec99f681e773..d83ad0f141af 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
static int mfd_add_device(struct device *parent, int id,
@@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id,
if (ret)
goto fail_res;
+ if (cell->pm_runtime_no_callbacks)
+ pm_runtime_no_callbacks(&pdev->dev);
+
kfree(res);
return 0;
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
index f1714f93af9d..0a7df44a93c0 100644
--- a/drivers/mfd/sh_mobile_sdhi.c
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -131,11 +131,17 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
*/
mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
+ /*
+ * All SDHI blocks support SDIO IRQ signalling.
+ */
+ mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
+
if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
priv->param_tx.slave_id = p->dma_slave_tx;
priv->param_rx.slave_id = p->dma_slave_rx;
priv->dma_priv.chan_priv_tx = &priv->param_tx;
priv->dma_priv.chan_priv_rx = &priv->param_rx;
+ priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
mmc_data->dma = &priv->dma_priv;
}
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index bc9275c12133..5de3a760ea1e 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -26,7 +26,7 @@
#include <linux/sm501-regs.h>
#include <linux/serial_8250.h>
-#include <asm/io.h>
+#include <linux/io.h>
struct sm501_device {
struct list_head list;
@@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm,
int ret;
for (ptr = 0; ptr < pdev->num_resources; ptr++) {
- printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
- pdev->name, ptr,
- pdev->resource[ptr].flags,
- (unsigned long long)pdev->resource[ptr].start,
- (unsigned long long)pdev->resource[ptr].end);
+ printk(KERN_DEBUG "%s[%d] %pR\n",
+ pdev->name, ptr, &pdev->resource[ptr]);
}
ret = platform_device_register(pdev);
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index b11487f1e1cb..3e5732b58c49 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void stmpe_irq_lock(unsigned int irq)
+static void stmpe_irq_lock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
mutex_lock(&stmpe->irq_lock);
}
-static void stmpe_irq_sync_unlock(unsigned int irq)
+static void stmpe_irq_sync_unlock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
struct stmpe_variant_info *variant = stmpe->variant;
int num = DIV_ROUND_UP(variant->num_irqs, 8);
int i;
@@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq)
mutex_unlock(&stmpe->irq_lock);
}
-static void stmpe_irq_mask(unsigned int irq)
+static void stmpe_irq_mask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe->ier[regoffset] &= ~mask;
}
-static void stmpe_irq_unmask(unsigned int irq)
+static void stmpe_irq_unmask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq)
static struct irq_chip stmpe_irq_chip = {
.name = "stmpe",
- .bus_lock = stmpe_irq_lock,
- .bus_sync_unlock = stmpe_irq_sync_unlock,
- .mask = stmpe_irq_mask,
- .unmask = stmpe_irq_unmask,
+ .irq_bus_lock = stmpe_irq_lock,
+ .irq_bus_sync_unlock = stmpe_irq_sync_unlock,
+ .irq_mask = stmpe_irq_mask,
+ .irq_unmask = stmpe_irq_unmask,
};
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 006c121f3f0d..9caeb4ac6ea6 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(irq_base + i);
}
-static void t7l66xb_irq_mask(unsigned int irq)
+static void t7l66xb_irq_mask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr |= 1 << (irq - t7l66xb->irq_base);
+ imr |= 1 << (data->irq - t7l66xb->irq_base);
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
-static void t7l66xb_irq_unmask(unsigned int irq)
+static void t7l66xb_irq_unmask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - t7l66xb->irq_base));
+ imr &= ~(1 << (data->irq - t7l66xb->irq_base));
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
static struct irq_chip t7l66xb_chip = {
- .name = "t7l66xb",
- .ack = t7l66xb_irq_mask,
- .mask = t7l66xb_irq_mask,
- .unmask = t7l66xb_irq_unmask,
+ .name = "t7l66xb",
+ .irq_ack = t7l66xb_irq_mask,
+ .irq_mask = t7l66xb_irq_mask,
+ .irq_unmask = t7l66xb_irq_unmask,
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c
deleted file mode 100644
index e619e2a55997..000000000000
--- a/drivers/mfd/tc35892.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License, version 2
- * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tc35892.h>
-
-/**
- * tc35892_reg_read() - read a single TC35892 register
- * @tc35892: Device to read from
- * @reg: Register to read
- */
-int tc35892_reg_read(struct tc35892 *tc35892, u8 reg)
-{
- int ret;
-
- ret = i2c_smbus_read_byte_data(tc35892->i2c, reg);
- if (ret < 0)
- dev_err(tc35892->dev, "failed to read reg %#x: %d\n",
- reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tc35892_reg_read);
-
-/**
- * tc35892_reg_read() - write a single TC35892 register
- * @tc35892: Device to write to
- * @reg: Register to read
- * @data: Value to write
- */
-int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data)
-{
- int ret;
-
- ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data);
- if (ret < 0)
- dev_err(tc35892->dev, "failed to write reg %#x: %d\n",
- reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tc35892_reg_write);
-
-/**
- * tc35892_block_read() - read multiple TC35892 registers
- * @tc35892: Device to read from
- * @reg: First register
- * @length: Number of registers
- * @values: Buffer to write to
- */
-int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values)
-{
- int ret;
-
- ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values);
- if (ret < 0)
- dev_err(tc35892->dev, "failed to read regs %#x: %d\n",
- reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tc35892_block_read);
-
-/**
- * tc35892_block_write() - write multiple TC35892 registers
- * @tc35892: Device to write to
- * @reg: First register
- * @length: Number of registers
- * @values: Values to write
- */
-int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length,
- const u8 *values)
-{
- int ret;
-
- ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length,
- values);
- if (ret < 0)
- dev_err(tc35892->dev, "failed to write regs %#x: %d\n",
- reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tc35892_block_write);
-
-/**
- * tc35892_set_bits() - set the value of a bitfield in a TC35892 register
- * @tc35892: Device to write to
- * @reg: Register to write
- * @mask: Mask of bits to set
- * @values: Value to set
- */
-int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val)
-{
- int ret;
-
- mutex_lock(&tc35892->lock);
-
- ret = tc35892_reg_read(tc35892, reg);
- if (ret < 0)
- goto out;
-
- ret &= ~mask;
- ret |= val;
-
- ret = tc35892_reg_write(tc35892, reg, ret);
-
-out:
- mutex_unlock(&tc35892->lock);
- return ret;
-}
-EXPORT_SYMBOL_GPL(tc35892_set_bits);
-
-static struct resource gpio_resources[] = {
- {
- .start = TC35892_INT_GPIIRQ,
- .end = TC35892_INT_GPIIRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mfd_cell tc35892_devs[] = {
- {
- .name = "tc35892-gpio",
- .num_resources = ARRAY_SIZE(gpio_resources),
- .resources = &gpio_resources[0],
- },
-};
-
-static irqreturn_t tc35892_irq(int irq, void *data)
-{
- struct tc35892 *tc35892 = data;
- int status;
-
- status = tc35892_reg_read(tc35892, TC35892_IRQST);
- if (status < 0)
- return IRQ_NONE;
-
- while (status) {
- int bit = __ffs(status);
-
- handle_nested_irq(tc35892->irq_base + bit);
- status &= ~(1 << bit);
- }
-
- /*
- * A dummy read or write (to any register) appears to be necessary to
- * have the last interrupt clear (for example, GPIO IC write) take
- * effect.
- */
- tc35892_reg_read(tc35892, TC35892_IRQST);
-
- return IRQ_HANDLED;
-}
-
-static void tc35892_irq_dummy(unsigned int irq)
-{
- /* No mask/unmask at this level */
-}
-
-static struct irq_chip tc35892_irq_chip = {
- .name = "tc35892",
- .mask = tc35892_irq_dummy,
- .unmask = tc35892_irq_dummy,
-};
-
-static int tc35892_irq_init(struct tc35892 *tc35892)
-{
- int base = tc35892->irq_base;
- int irq;
-
- for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
- set_irq_chip_data(irq, tc35892);
- set_irq_chip_and_handler(irq, &tc35892_irq_chip,
- handle_edge_irq);
- set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- set_irq_noprobe(irq);
-#endif
- }
-
- return 0;
-}
-
-static void tc35892_irq_remove(struct tc35892 *tc35892)
-{
- int base = tc35892->irq_base;
- int irq;
-
- for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- set_irq_chip_and_handler(irq, NULL, NULL);
- set_irq_chip_data(irq, NULL);
- }
-}
-
-static int tc35892_chip_init(struct tc35892 *tc35892)
-{
- int manf, ver, ret;
-
- manf = tc35892_reg_read(tc35892, TC35892_MANFCODE);
- if (manf < 0)
- return manf;
-
- ver = tc35892_reg_read(tc35892, TC35892_VERSION);
- if (ver < 0)
- return ver;
-
- if (manf != TC35892_MANFCODE_MAGIC) {
- dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf);
- return -EINVAL;
- }
-
- dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
-
- /* Put everything except the IRQ module into reset */
- ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL,
- TC35892_RSTCTRL_TIMRST
- | TC35892_RSTCTRL_ROTRST
- | TC35892_RSTCTRL_KBDRST
- | TC35892_RSTCTRL_GPIRST);
- if (ret < 0)
- return ret;
-
- /* Clear the reset interrupt. */
- return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1);
-}
-
-static int __devinit tc35892_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct tc35892_platform_data *pdata = i2c->dev.platform_data;
- struct tc35892 *tc35892;
- int ret;
-
- if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_I2C_BLOCK))
- return -EIO;
-
- tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL);
- if (!tc35892)
- return -ENOMEM;
-
- mutex_init(&tc35892->lock);
-
- tc35892->dev = &i2c->dev;
- tc35892->i2c = i2c;
- tc35892->pdata = pdata;
- tc35892->irq_base = pdata->irq_base;
- tc35892->num_gpio = id->driver_data;
-
- i2c_set_clientdata(i2c, tc35892);
-
- ret = tc35892_chip_init(tc35892);
- if (ret)
- goto out_free;
-
- ret = tc35892_irq_init(tc35892);
- if (ret)
- goto out_free;
-
- ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "tc35892", tc35892);
- if (ret) {
- dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret);
- goto out_removeirq;
- }
-
- ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs,
- ARRAY_SIZE(tc35892_devs), NULL,
- tc35892->irq_base);
- if (ret) {
- dev_err(tc35892->dev, "failed to add children\n");
- goto out_freeirq;
- }
-
- return 0;
-
-out_freeirq:
- free_irq(tc35892->i2c->irq, tc35892);
-out_removeirq:
- tc35892_irq_remove(tc35892);
-out_free:
- kfree(tc35892);
- return ret;
-}
-
-static int __devexit tc35892_remove(struct i2c_client *client)
-{
- struct tc35892 *tc35892 = i2c_get_clientdata(client);
-
- mfd_remove_devices(tc35892->dev);
-
- free_irq(tc35892->i2c->irq, tc35892);
- tc35892_irq_remove(tc35892);
-
- kfree(tc35892);
-
- return 0;
-}
-
-static const struct i2c_device_id tc35892_id[] = {
- { "tc35892", 24 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tc35892_id);
-
-static struct i2c_driver tc35892_driver = {
- .driver.name = "tc35892",
- .driver.owner = THIS_MODULE,
- .probe = tc35892_probe,
- .remove = __devexit_p(tc35892_remove),
- .id_table = tc35892_id,
-};
-
-static int __init tc35892_init(void)
-{
- return i2c_add_driver(&tc35892_driver);
-}
-subsys_initcall(tc35892_init);
-
-static void __exit tc35892_exit(void)
-{
- i2c_del_driver(&tc35892_driver);
-}
-module_exit(tc35892_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("TC35892 MFD core driver");
-MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
new file mode 100644
index 000000000000..729dbeed2ce0
--- /dev/null
+++ b/drivers/mfd/tc3589x.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tc3589x.h>
+
+#define TC3589x_CLKMODE_MODCTL_SLEEP 0x0
+#define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0)
+
+/**
+ * tc3589x_reg_read() - read a single TC3589x register
+ * @tc3589x: Device to read from
+ * @reg: Register to read
+ */
+int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
+ if (ret < 0)
+ dev_err(tc3589x->dev, "failed to read reg %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tc3589x_reg_read);
+
+/**
+ * tc3589x_reg_read() - write a single TC3589x register
+ * @tc3589x: Device to write to
+ * @reg: Register to read
+ * @data: Value to write
+ */
+int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
+ if (ret < 0)
+ dev_err(tc3589x->dev, "failed to write reg %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tc3589x_reg_write);
+
+/**
+ * tc3589x_block_read() - read multiple TC3589x registers
+ * @tc3589x: Device to read from
+ * @reg: First register
+ * @length: Number of registers
+ * @values: Buffer to write to
+ */
+int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
+{
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
+ if (ret < 0)
+ dev_err(tc3589x->dev, "failed to read regs %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tc3589x_block_read);
+
+/**
+ * tc3589x_block_write() - write multiple TC3589x registers
+ * @tc3589x: Device to write to
+ * @reg: First register
+ * @length: Number of registers
+ * @values: Values to write
+ */
+int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
+ const u8 *values)
+{
+ int ret;
+
+ ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
+ values);
+ if (ret < 0)
+ dev_err(tc3589x->dev, "failed to write regs %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tc3589x_block_write);
+
+/**
+ * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register
+ * @tc3589x: Device to write to
+ * @reg: Register to write
+ * @mask: Mask of bits to set
+ * @values: Value to set
+ */
+int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
+{
+ int ret;
+
+ mutex_lock(&tc3589x->lock);
+
+ ret = tc3589x_reg_read(tc3589x, reg);
+ if (ret < 0)
+ goto out;
+
+ ret &= ~mask;
+ ret |= val;
+
+ ret = tc3589x_reg_write(tc3589x, reg, ret);
+
+out:
+ mutex_unlock(&tc3589x->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tc3589x_set_bits);
+
+static struct resource gpio_resources[] = {
+ {
+ .start = TC3589x_INT_GPIIRQ,
+ .end = TC3589x_INT_GPIIRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource keypad_resources[] = {
+ {
+ .start = TC3589x_INT_KBDIRQ,
+ .end = TC3589x_INT_KBDIRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell tc3589x_dev_gpio[] = {
+ {
+ .name = "tc3589x-gpio",
+ .num_resources = ARRAY_SIZE(gpio_resources),
+ .resources = &gpio_resources[0],
+ },
+};
+
+static struct mfd_cell tc3589x_dev_keypad[] = {
+ {
+ .name = "tc3589x-keypad",
+ .num_resources = ARRAY_SIZE(keypad_resources),
+ .resources = &keypad_resources[0],
+ },
+};
+
+static irqreturn_t tc3589x_irq(int irq, void *data)
+{
+ struct tc3589x *tc3589x = data;
+ int status;
+
+again:
+ status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
+ if (status < 0)
+ return IRQ_NONE;
+
+ while (status) {
+ int bit = __ffs(status);
+
+ handle_nested_irq(tc3589x->irq_base + bit);
+ status &= ~(1 << bit);
+ }
+
+ /*
+ * A dummy read or write (to any register) appears to be necessary to
+ * have the last interrupt clear (for example, GPIO IC write) take
+ * effect. In such a case, recheck for any interrupt which is still
+ * pending.
+ */
+ status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
+ if (status)
+ goto again;
+
+ return IRQ_HANDLED;
+}
+
+static int tc3589x_irq_init(struct tc3589x *tc3589x)
+{
+ int base = tc3589x->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
+ set_irq_chip_data(irq, tc3589x);
+ set_irq_chip_and_handler(irq, &dummy_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ return 0;
+}
+
+static void tc3589x_irq_remove(struct tc3589x *tc3589x)
+{
+ int base = tc3589x->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ set_irq_chip_and_handler(irq, NULL, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
+}
+
+static int tc3589x_chip_init(struct tc3589x *tc3589x)
+{
+ int manf, ver, ret;
+
+ manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
+ if (manf < 0)
+ return manf;
+
+ ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
+ if (ver < 0)
+ return ver;
+
+ if (manf != TC3589x_MANFCODE_MAGIC) {
+ dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
+ return -EINVAL;
+ }
+
+ dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
+
+ /*
+ * Put everything except the IRQ module into reset;
+ * also spare the GPIO module for any pin initialization
+ * done during pre-kernel boot
+ */
+ ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
+ TC3589x_RSTCTRL_TIMRST
+ | TC3589x_RSTCTRL_ROTRST
+ | TC3589x_RSTCTRL_KBDRST);
+ if (ret < 0)
+ return ret;
+
+ /* Clear the reset interrupt. */
+ return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
+}
+
+static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
+{
+ int ret = 0;
+ unsigned int blocks = tc3589x->pdata->block;
+
+ if (blocks & TC3589x_BLOCK_GPIO) {
+ ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
+ ARRAY_SIZE(tc3589x_dev_gpio), NULL,
+ tc3589x->irq_base);
+ if (ret) {
+ dev_err(tc3589x->dev, "failed to add gpio child\n");
+ return ret;
+ }
+ dev_info(tc3589x->dev, "added gpio block\n");
+ }
+
+ if (blocks & TC3589x_BLOCK_KEYPAD) {
+ ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
+ ARRAY_SIZE(tc3589x_dev_keypad), NULL,
+ tc3589x->irq_base);
+ if (ret) {
+ dev_err(tc3589x->dev, "failed to keypad child\n");
+ return ret;
+ }
+ dev_info(tc3589x->dev, "added keypad block\n");
+ }
+
+ return ret;
+}
+
+static int __devinit tc3589x_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
+ struct tc3589x *tc3589x;
+ int ret;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -EIO;
+
+ tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL);
+ if (!tc3589x)
+ return -ENOMEM;
+
+ mutex_init(&tc3589x->lock);
+
+ tc3589x->dev = &i2c->dev;
+ tc3589x->i2c = i2c;
+ tc3589x->pdata = pdata;
+ tc3589x->irq_base = pdata->irq_base;
+ tc3589x->num_gpio = id->driver_data;
+
+ i2c_set_clientdata(i2c, tc3589x);
+
+ ret = tc3589x_chip_init(tc3589x);
+ if (ret)
+ goto out_free;
+
+ ret = tc3589x_irq_init(tc3589x);
+ if (ret)
+ goto out_free;
+
+ ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "tc3589x", tc3589x);
+ if (ret) {
+ dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
+ goto out_removeirq;
+ }
+
+ ret = tc3589x_device_init(tc3589x);
+ if (ret) {
+ dev_err(tc3589x->dev, "failed to add child devices\n");
+ goto out_freeirq;
+ }
+
+ return 0;
+
+out_freeirq:
+ free_irq(tc3589x->i2c->irq, tc3589x);
+out_removeirq:
+ tc3589x_irq_remove(tc3589x);
+out_free:
+ kfree(tc3589x);
+ return ret;
+}
+
+static int __devexit tc3589x_remove(struct i2c_client *client)
+{
+ struct tc3589x *tc3589x = i2c_get_clientdata(client);
+
+ mfd_remove_devices(tc3589x->dev);
+
+ free_irq(tc3589x->i2c->irq, tc3589x);
+ tc3589x_irq_remove(tc3589x);
+
+ kfree(tc3589x);
+
+ return 0;
+}
+
+static int tc3589x_suspend(struct device *dev)
+{
+ struct tc3589x *tc3589x = dev_get_drvdata(dev);
+ struct i2c_client *client = tc3589x->i2c;
+ int ret = 0;
+
+ /* put the system to sleep mode */
+ if (!device_may_wakeup(&client->dev))
+ ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
+ TC3589x_CLKMODE_MODCTL_SLEEP);
+
+ return ret;
+}
+
+static int tc3589x_resume(struct device *dev)
+{
+ struct tc3589x *tc3589x = dev_get_drvdata(dev);
+ struct i2c_client *client = tc3589x->i2c;
+ int ret = 0;
+
+ /* enable the system into operation */
+ if (!device_may_wakeup(&client->dev))
+ ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
+ TC3589x_CLKMODE_MODCTL_OPERATION);
+
+ return ret;
+}
+
+static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend,
+ tc3589x_resume);
+
+static const struct i2c_device_id tc3589x_id[] = {
+ { "tc3589x", 24 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tc3589x_id);
+
+static struct i2c_driver tc3589x_driver = {
+ .driver.name = "tc3589x",
+ .driver.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .driver.pm = &tc3589x_dev_pm_ops,
+#endif
+ .probe = tc3589x_probe,
+ .remove = __devexit_p(tc3589x_remove),
+ .id_table = tc3589x_id,
+};
+
+static int __init tc3589x_init(void)
+{
+ return i2c_add_driver(&tc3589x_driver);
+}
+subsys_initcall(tc3589x_init);
+
+static void __exit tc3589x_exit(void)
+{
+ i2c_del_driver(&tc3589x_driver);
+}
+module_exit(tc3589x_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TC3589x MFD core driver");
+MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1ea80d8ad915..9a238633a54d 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
}
}
-static void tc6393xb_irq_ack(unsigned int irq)
+static void tc6393xb_irq_ack(struct irq_data *data)
{
}
-static void tc6393xb_irq_mask(unsigned int irq)
+static void tc6393xb_irq_mask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr |= 1 << (irq - tc6393xb->irq_base);
+ imr |= 1 << (data->irq - tc6393xb->irq_base);
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
-static void tc6393xb_irq_unmask(unsigned int irq)
+static void tc6393xb_irq_unmask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - tc6393xb->irq_base));
+ imr &= ~(1 << (data->irq - tc6393xb->irq_base));
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static struct irq_chip tc6393xb_chip = {
- .name = "tc6393xb",
- .ack = tc6393xb_irq_ack,
- .mask = tc6393xb_irq_mask,
- .unmask = tc6393xb_irq_unmask,
+ .name = "tc6393xb",
+ .irq_ack = tc6393xb_irq_ack,
+ .irq_mask = tc6393xb_irq_mask,
+ .irq_unmask = tc6393xb_irq_unmask,
};
static void tc6393xb_attach_irq(struct platform_device *dev)
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index 727f62c15a60..6ad8a7f8d390 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -40,6 +40,7 @@
#include <linux/spi/mc33880.h>
#include <media/timb_radio.h>
+#include <media/timb_video.h>
#include <linux/timb_dma.h>
@@ -246,7 +247,23 @@ static const __devinitconst struct resource timberdale_uartlite_resources[] = {
},
};
-static const __devinitconst struct resource timberdale_radio_resources[] = {
+static __devinitdata struct i2c_board_info timberdale_adv7180_i2c_board_info = {
+ /* Requires jumper JP9 to be off */
+ I2C_BOARD_INFO("adv7180", 0x42 >> 1),
+ .irq = IRQ_TIMBERDALE_ADV7180
+};
+
+static __devinitdata struct timb_video_platform_data
+ timberdale_video_platform_data = {
+ .dma_channel = DMA_VIDEO_RX,
+ .i2c_adapter = 0,
+ .encoder = {
+ .info = &timberdale_adv7180_i2c_board_info
+ }
+};
+
+static const __devinitconst struct resource
+timberdale_radio_resources[] = {
{
.start = RDSOFFSET,
.end = RDSEND,
@@ -271,15 +288,25 @@ static __devinitdata struct timb_radio_platform_data
timberdale_radio_platform_data = {
.i2c_adapter = 0,
.tuner = {
- .module_name = "tef6862",
.info = &timberdale_tef6868_i2c_board_info
},
.dsp = {
- .module_name = "saa7706h",
.info = &timberdale_saa7706_i2c_board_info
}
};
+static const __devinitconst struct resource timberdale_video_resources[] = {
+ {
+ .start = LOGIWOFFSET,
+ .end = LOGIWEND,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ note that the "frame buffer" is located in DMA area
+ starting at 0x1200000
+ */
+};
+
static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = {
.nr_channels = 10,
.channels = {
@@ -380,6 +407,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
.data_size = sizeof(timberdale_gpio_platform_data),
},
{
+ .name = "timb-video",
+ .num_resources = ARRAY_SIZE(timberdale_video_resources),
+ .resources = timberdale_video_resources,
+ .platform_data = &timberdale_video_platform_data,
+ .data_size = sizeof(timberdale_video_platform_data),
+ },
+ {
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
@@ -440,6 +474,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.resources = timberdale_mlogicore_resources,
},
{
+ .name = "timb-video",
+ .num_resources = ARRAY_SIZE(timberdale_video_resources),
+ .resources = timberdale_video_resources,
+ .platform_data = &timberdale_video_platform_data,
+ .data_size = sizeof(timberdale_video_platform_data),
+ },
+ {
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
@@ -490,6 +531,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
.data_size = sizeof(timberdale_gpio_platform_data),
},
{
+ .name = "timb-video",
+ .num_resources = ARRAY_SIZE(timberdale_video_resources),
+ .resources = timberdale_video_resources,
+ .platform_data = &timberdale_video_platform_data,
+ .data_size = sizeof(timberdale_video_platform_data),
+ },
+ {
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
@@ -533,6 +581,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
.data_size = sizeof(timberdale_gpio_platform_data),
},
{
+ .name = "timb-video",
+ .num_resources = ARRAY_SIZE(timberdale_video_resources),
+ .resources = timberdale_video_resources,
+ .platform_data = &timberdale_video_platform_data,
+ .data_size = sizeof(timberdale_video_platform_data),
+ },
+ {
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h
index c11bf6ebfe00..4412acd826fa 100644
--- a/drivers/mfd/timberdale.h
+++ b/drivers/mfd/timberdale.h
@@ -23,7 +23,7 @@
#ifndef MFD_TIMBERDALE_H
#define MFD_TIMBERDALE_H
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
/* This driver only support versions >= 3.8 and < 4.0 */
#define TIMB_SUPPORTED_MAJOR 3
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index d0016b67d125..93d5fdf020c7 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -34,7 +34,7 @@
#include <linux/i2c/tps65010.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
/*-------------------------------------------------------------------------*/
@@ -242,7 +242,7 @@ static int dbg_show(struct seq_file *s, void *_)
seq_printf(s, "mask2 %s\n", buf);
/* ignore ackint2 */
- (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+ schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
/* VMAIN voltage, enable lowpower, etc */
@@ -400,7 +400,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
&& (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)))
poll = 1;
if (poll)
- (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+ schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
/* also potentially gpio-in rise or fall */
}
@@ -410,7 +410,7 @@ static void tps65010_work(struct work_struct *work)
{
struct tps65010 *tps;
- tps = container_of(work, struct tps65010, work.work);
+ tps = container_of(to_delayed_work(work), struct tps65010, work);
mutex_lock(&tps->lock);
tps65010_interrupt(tps);
@@ -448,7 +448,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
disable_irq_nosync(irq);
set_bit(FLAG_IRQ_ENABLE, &tps->flags);
- (void) schedule_work(&tps->work.work);
+ schedule_delayed_work(&tps->work, 0);
return IRQ_HANDLED;
}
@@ -527,8 +527,7 @@ static int __exit tps65010_remove(struct i2c_client *client)
}
if (client->irq > 0)
free_irq(client->irq, tps);
- cancel_delayed_work(&tps->work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&tps->work);
debugfs_remove(tps->file);
kfree(tps);
the_tps = NULL;
@@ -720,7 +719,7 @@ int tps65010_set_vbus_draw(unsigned mA)
&& test_and_set_bit(
FLAG_VBUS_CHANGED, &the_tps->flags)) {
/* gadget drivers call this in_irq() */
- (void) schedule_work(&the_tps->work.work);
+ schedule_delayed_work(&the_tps->work, 0);
}
local_irq_restore(flags);
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index b4931ab34929..627cf577b16d 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -46,8 +46,6 @@
/* device id */
#define TPS6586X_VERSIONCRC 0xcd
-#define TPS658621A_VERSIONCRC 0x15
-#define TPS658621C_VERSIONCRC 0x2c
struct tps6586x_irq_data {
u8 mask_reg;
@@ -325,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
}
-static void tps6586x_irq_lock(unsigned int irq)
+static void tps6586x_irq_lock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
mutex_lock(&tps6586x->irq_lock);
}
-static void tps6586x_irq_enable(unsigned int irq)
+static void tps6586x_irq_enable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
- unsigned int __irq = irq - tps6586x->irq_base;
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
tps6586x->irq_en |= (1 << __irq);
}
-static void tps6586x_irq_disable(unsigned int irq)
+static void tps6586x_irq_disable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
- unsigned int __irq = irq - tps6586x->irq_base;
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
tps6586x->irq_en &= ~(1 << __irq);
}
-static void tps6586x_irq_sync_unlock(unsigned int irq)
+static void tps6586x_irq_sync_unlock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
@@ -421,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
tps6586x->irq_base = irq_base;
tps6586x->irq_chip.name = "tps6586x";
- tps6586x->irq_chip.enable = tps6586x_irq_enable;
- tps6586x->irq_chip.disable = tps6586x_irq_disable;
- tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
- tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
+ tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
+ tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
+ tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
+ tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;
for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
int __irq = i + tps6586x->irq_base;
@@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
return -EIO;
}
- if ((ret != TPS658621A_VERSIONCRC) &&
- (ret != TPS658621C_VERSIONCRC)) {
- dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
- return -ENODEV;
- }
+ dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
if (tps6586x == NULL)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 35275ba7096f..a35fa7dcbf53 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -95,7 +95,8 @@
#define twl_has_rtc() false
#endif
-#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
+ defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
#define twl_has_usb() true
#else
#define twl_has_usb() false
@@ -682,6 +683,43 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
usb3v1.dev = child;
}
}
+ if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
+
+ static struct regulator_consumer_supply usb3v3 = {
+ .supply = "vusb",
+ };
+
+ if (twl_has_regulator()) {
+ /* this is a template that gets copied */
+ struct regulator_init_data usb_fixed = {
+ .constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ };
+
+ child = add_regulator_linked(TWL6030_REG_VUSB,
+ &usb_fixed, &usb3v3, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ child = add_child(0, "twl6030_usb",
+ pdata->usb, sizeof(*pdata->usb),
+ true,
+ /* irq1 = VBUS_PRES, irq0 = USB ID */
+ pdata->irq_base + USBOTG_INTR_OFFSET,
+ pdata->irq_base + USB_PRES_INTR_OFFSET);
+
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ /* we need to connect regulators to this transceiver */
+ if (twl_has_regulator() && child)
+ usb3v3.dev = child;
+
+ }
if (twl_has_watchdog()) {
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
@@ -815,10 +853,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VUSB, pdata->vusb);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -969,7 +1003,7 @@ static int twl_remove(struct i2c_client *client)
}
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
-static int __init
+static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int status;
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 5d3a1478004b..63a30e88908f 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work)
* completion, potentially including some re-ordering, of these requests.
*/
-static void twl4030_sih_mask(unsigned irq)
+static void twl4030_sih_mask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr |= BIT(irq - sih->irq_base);
+ sih->imr |= BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static void twl4030_sih_unmask(unsigned irq)
+static void twl4030_sih_unmask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr &= ~BIT(irq - sih->irq_base);
+ sih->imr &= ~BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
+static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
- struct irq_desc *desc = irq_to_desc(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
+ struct irq_desc *desc = irq_to_desc(data->irq);
unsigned long flags;
if (!desc) {
- pr_err("twl4030: Invalid IRQ: %d\n", irq);
+ pr_err("twl4030: Invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
desc->status &= ~IRQ_TYPE_SENSE_MASK;
desc->status |= trigger;
- sih->edge_change |= BIT(irq - sih->irq_base);
+ sih->edge_change |= BIT(data->irq - sih->irq_base);
queue_work(wq, &sih->edge_work);
}
spin_unlock_irqrestore(&sih_agent_lock, flags);
@@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
static struct irq_chip twl4030_sih_irq_chip = {
.name = "twl4030",
- .mask = twl4030_sih_mask,
- .unmask = twl4030_sih_unmask,
- .set_type = twl4030_sih_set_type,
+ .irq_mask = twl4030_sih_mask,
+ .irq_unmask = twl4030_sih_unmask,
+ .irq_set_type = twl4030_sih_set_type,
};
/*----------------------------------------------------------------------*/
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index aaedb11d9d2c..4082ed73613f 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -74,7 +74,7 @@ static int twl6030_interrupt_mapping[24] = {
USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */
USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */
USBOTG_INTR_OFFSET, /* Bit 18 ID */
- USBOTG_INTR_OFFSET, /* Bit 19 VBUS */
+ USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
@@ -128,6 +128,13 @@ static int twl6030_irq_thread(void *data)
sts.bytes[3] = 0; /* Only 24 bits are valid*/
+ /*
+ * Since VBUS status bit is not reliable for VBUS disconnect
+ * use CHARGER VBUS detection status bit instead.
+ */
+ if (sts.bytes[2] & 0x10)
+ sts.bytes[2] |= 0x08;
+
for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
local_irq_disable();
if (sts.int_sts & 0x1) {
@@ -325,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
*/
twl6030_irq_chip = dummy_irq_chip;
twl6030_irq_chip.name = "twl6030";
- twl6030_irq_chip.set_type = NULL;
+ twl6030_irq_chip.irq_set_type = NULL;
for (i = irq_base; i < irq_end; i++) {
set_irq_chip_and_handler(i, &twl6030_irq_chip,
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c
index ebb059765edd..348052aa5dbf 100644
--- a/drivers/mfd/vx855.c
+++ b/drivers/mfd/vx855.c
@@ -112,7 +112,7 @@ out:
return ret;
}
-static void vx855_remove(struct pci_dev *pdev)
+static void __devexit vx855_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
pci_disable_device(pdev);
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c
new file mode 100644
index 000000000000..d2ecc2435736
--- /dev/null
+++ b/drivers/mfd/wl1273-core.c
@@ -0,0 +1,148 @@
+/*
+ * MFD driver for wl1273 FM radio and audio codec submodules.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@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/mfd/wl1273-core.h>
+#include <linux/slab.h>
+
+#define DRIVER_DESC "WL1273 FM Radio Core"
+
+static struct i2c_device_id wl1273_driver_id_table[] = {
+ { WL1273_FM_DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
+
+static int wl1273_core_remove(struct i2c_client *client)
+{
+ struct wl1273_core *core = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ mfd_remove_devices(&client->dev);
+ i2c_set_clientdata(client, NULL);
+ kfree(core);
+
+ return 0;
+}
+
+static int __devinit wl1273_core_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wl1273_fm_platform_data *pdata = client->dev.platform_data;
+ struct wl1273_core *core;
+ struct mfd_cell *cell;
+ int children = 0;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ if (!pdata) {
+ dev_err(&client->dev, "No platform data.\n");
+ return -EINVAL;
+ }
+
+ if (!(pdata->children & WL1273_RADIO_CHILD)) {
+ dev_err(&client->dev, "Cannot function without radio child.\n");
+ return -EINVAL;
+ }
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+
+ core->pdata = pdata;
+ core->client = client;
+ mutex_init(&core->lock);
+
+ i2c_set_clientdata(client, core);
+
+ dev_dbg(&client->dev, "%s: Have V4L2.\n", __func__);
+
+ cell = &core->cells[children];
+ cell->name = "wl1273_fm_radio";
+ cell->platform_data = &core;
+ cell->data_size = sizeof(core);
+ children++;
+
+ if (pdata->children & WL1273_CODEC_CHILD) {
+ cell = &core->cells[children];
+
+ dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
+ cell->name = "wl1273-codec";
+ cell->platform_data = &core;
+ cell->data_size = sizeof(core);
+ children++;
+ }
+
+ dev_dbg(&client->dev, "%s: number of children: %d.\n",
+ __func__, children);
+
+ r = mfd_add_devices(&client->dev, -1, core->cells,
+ children, NULL, 0);
+ if (r)
+ goto err;
+
+ return 0;
+
+err:
+ i2c_set_clientdata(client, NULL);
+ pdata->free_resources();
+ kfree(core);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ return r;
+}
+
+static struct i2c_driver wl1273_core_driver = {
+ .driver = {
+ .name = WL1273_FM_DRIVER_NAME,
+ },
+ .probe = wl1273_core_probe,
+ .id_table = wl1273_driver_id_table,
+ .remove = __devexit_p(wl1273_core_remove),
+};
+
+static int __init wl1273_core_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wl1273_core_driver);
+ if (r) {
+ pr_err(WL1273_FM_DRIVER_NAME
+ ": driver registration failed\n");
+ return r;
+ }
+
+ return r;
+}
+
+static void __exit wl1273_core_exit(void)
+{
+ i2c_del_driver(&wl1273_core_driver);
+}
+late_initcall(wl1273_core_init);
+module_exit(wl1273_core_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 7d2563fc15c6..3fe9a58fe6c7 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1455,7 +1455,11 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
goto err;
}
- if (ret != 0x6204) {
+ switch (ret) {
+ case 0x6204:
+ case 0x6246:
+ break;
+ default:
dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
ret = -EINVAL;
goto err;
@@ -1537,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
break;
+ case WM8326:
+ parent = WM8326;
+ wm831x->num_gpio = 12;
+ dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
+ break;
+
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
@@ -1606,21 +1616,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
break;
case WM8320:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8321:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8325:
+ case WM8326:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
+ NULL, wm831x->irq_base);
break;
default:
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index 156b19859e81..3853fa8e7cc2 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
return 0;
}
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int wm831x_i2c_suspend(struct device *dev)
{
- struct wm831x *wm831x = i2c_get_clientdata(i2c);
+ struct wm831x *wm831x = dev_get_drvdata(dev);
return wm831x_device_suspend(wm831x);
}
@@ -108,19 +108,23 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8320", WM8320 },
{ "wm8321", WM8321 },
{ "wm8325", WM8325 },
+ { "wm8326", WM8326 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
+static const struct dev_pm_ops wm831x_pm_ops = {
+ .suspend = wm831x_i2c_suspend,
+};
static struct i2c_driver wm831x_i2c_driver = {
.driver = {
- .name = "wm831x",
- .owner = THIS_MODULE,
+ .name = "wm831x",
+ .owner = THIS_MODULE,
+ .pm = &wm831x_pm_ops,
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
- .suspend = wm831x_i2c_suspend,
.id_table = wm831x_i2c_id,
};
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 294183b6260b..f7192d438aab 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
return &wm831x_irqs[irq - wm831x->irq_base];
}
-static void wm831x_irq_lock(unsigned int irq)
+static void wm831x_irq_lock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
mutex_lock(&wm831x->irq_lock);
}
-static void wm831x_irq_sync_unlock(unsigned int irq)
+static void wm831x_irq_sync_unlock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
@@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm831x->irq_lock);
}
-static void wm831x_irq_unmask(unsigned int irq)
+static void wm831x_irq_unmask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm831x_irq_mask(unsigned int irq)
+static void wm831x_irq_mask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
-static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
+static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- int val;
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ int val, irq;
- irq = irq - wm831x->irq_base;
+ irq = data->irq - wm831x->irq_base;
if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
/* Ignore internal-only IRQs */
@@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
}
static struct irq_chip wm831x_irq_chip = {
- .name = "wm831x",
- .bus_lock = wm831x_irq_lock,
- .bus_sync_unlock = wm831x_irq_sync_unlock,
- .mask = wm831x_irq_mask,
- .unmask = wm831x_irq_unmask,
- .set_type = wm831x_irq_set_type,
+ .name = "wm831x",
+ .irq_bus_lock = wm831x_irq_lock,
+ .irq_bus_sync_unlock = wm831x_irq_sync_unlock,
+ .irq_mask = wm831x_irq_mask,
+ .irq_unmask = wm831x_irq_unmask,
+ .irq_set_type = wm831x_irq_set_type,
};
/* The processing of the primary interrupt occurs in a thread so that
@@ -515,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
return 0;
}
+ /* Try to flag /IRQ as a wake source; there are a number of
+ * unconditional wake sources in the PMIC so this isn't
+ * conditional but we don't actually care *too* much if it
+ * fails.
+ */
+ ret = enable_irq_wake(irq);
+ if (ret != 0) {
+ dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
+ ret);
+ }
+
wm831x->irq = irq;
wm831x->irq_base = pdata->irq_base;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 2789b151b0f9..0a8f772be88c 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
type = WM8321;
else if (strcmp(spi->modalias, "wm8325") == 0)
type = WM8325;
+ else if (strcmp(spi->modalias, "wm8326") == 0)
+ type = WM8326;
else {
dev_err(&spi->dev, "Unknown device type\n");
return -EINVAL;
@@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = {
.suspend = wm831x_spi_suspend,
};
+static struct spi_driver wm8326_spi_driver = {
+ .driver = {
+ .name = "wm8326",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm831x_spi_probe,
+ .remove = __devexit_p(wm831x_spi_remove),
+ .suspend = wm831x_spi_suspend,
+};
+
static int __init wm831x_spi_init(void)
{
int ret;
@@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void)
if (ret != 0)
pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
+ ret = spi_register_driver(&wm8326_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
+
return 0;
}
subsys_initcall(wm831x_spi_init);
static void __exit wm831x_spi_exit(void)
{
+ spi_unregister_driver(&wm8326_spi_driver);
spi_unregister_driver(&wm8325_spi_driver);
spi_unregister_driver(&wm8321_spi_driver);
spi_unregister_driver(&wm8320_spi_driver);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index f56c9adf9493..5839966ebd85 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
return IRQ_HANDLED;
}
-static void wm8350_irq_lock(unsigned int irq)
+static void wm8350_irq_lock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8350->irq_lock);
}
-static void wm8350_irq_sync_unlock(unsigned int irq)
+static void wm8350_irq_sync_unlock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
@@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8350->irq_lock);
}
-static void wm8350_irq_enable(unsigned int irq)
+static void wm8350_irq_enable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
}
-static void wm8350_irq_disable(unsigned int irq)
+static void wm8350_irq_disable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
}
static struct irq_chip wm8350_irq_chip = {
- .name = "wm8350",
- .bus_lock = wm8350_irq_lock,
- .bus_sync_unlock = wm8350_irq_sync_unlock,
- .disable = wm8350_irq_disable,
- .enable = wm8350_irq_enable,
+ .name = "wm8350",
+ .irq_bus_lock = wm8350_irq_lock,
+ .irq_bus_sync_unlock = wm8350_irq_sync_unlock,
+ .irq_disable = wm8350_irq_disable,
+ .irq_enable = wm8350_irq_enable,
};
int wm8350_irq_init(struct wm8350 *wm8350, int irq,
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index b3b2aaf89dbe..41233c7fa581 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
@@ -169,8 +170,16 @@ out:
EXPORT_SYMBOL_GPL(wm8994_set_bits);
static struct mfd_cell wm8994_regulator_devs[] = {
- { .name = "wm8994-ldo", .id = 1 },
- { .name = "wm8994-ldo", .id = 2 },
+ {
+ .name = "wm8994-ldo",
+ .id = 1,
+ .pm_runtime_no_callbacks = true,
+ },
+ {
+ .name = "wm8994-ldo",
+ .id = 2,
+ .pm_runtime_no_callbacks = true,
+ },
};
static struct resource wm8994_codec_resources[] = {
@@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = {
.name = "wm8994-gpio",
.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
.resources = wm8994_gpio_resources,
+ .pm_runtime_no_callbacks = true,
},
};
@@ -218,8 +228,20 @@ static const char *wm8994_main_supplies[] = {
"SPKVDD2",
};
+static const char *wm8958_main_supplies[] = {
+ "DBVDD1",
+ "DBVDD2",
+ "DBVDD3",
+ "DCVDD",
+ "AVDD1",
+ "AVDD2",
+ "CPVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
#ifdef CONFIG_PM
-static int wm8994_device_suspend(struct device *dev)
+static int wm8994_suspend(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
@@ -239,7 +261,7 @@ static int wm8994_device_suspend(struct device *dev)
if (ret < 0)
dev_err(dev, "Failed to save LDO registers: %d\n", ret);
- ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ ret = regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(dev, "Failed to disable supplies: %d\n", ret);
@@ -249,12 +271,12 @@ static int wm8994_device_suspend(struct device *dev)
return 0;
}
-static int wm8994_device_resume(struct device *dev)
+static int wm8994_resume(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+ ret = regulator_bulk_enable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(dev, "Failed to enable supplies: %d\n", ret);
@@ -305,9 +327,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
/*
* Instantiate the generic non-control parts of the device.
*/
-static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
+static int wm8994_device_init(struct wm8994 *wm8994, int irq)
{
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ const char *devname;
int ret, i;
mutex_init(&wm8994->io_lock);
@@ -323,25 +346,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
goto err;
}
+ switch (wm8994->type) {
+ case WM8994:
+ wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
+ break;
+ case WM8958:
+ wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies);
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
- ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->num_supplies,
GFP_KERNEL);
if (!wm8994->supplies) {
ret = -ENOMEM;
goto err;
}
- for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
- wm8994->supplies[i].supply = wm8994_main_supplies[i];
-
- ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies),
+ switch (wm8994->type) {
+ case WM8994:
+ for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
+ wm8994->supplies[i].supply = wm8994_main_supplies[i];
+ break;
+ case WM8958:
+ for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
+ wm8994->supplies[i].supply = wm8958_main_supplies[i];
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
goto err_supplies;
}
- ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+ ret = regulator_bulk_enable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
@@ -353,7 +399,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
dev_err(wm8994->dev, "Failed to read ID register\n");
goto err_enable;
}
- if (ret != 0x8994) {
+ switch (ret) {
+ case 0x8994:
+ devname = "WM8994";
+ if (wm8994->type != WM8994)
+ dev_warn(wm8994->dev, "Device registered as type %d\n",
+ wm8994->type);
+ wm8994->type = WM8994;
+ break;
+ case 0x8958:
+ devname = "WM8958";
+ if (wm8994->type != WM8958)
+ dev_warn(wm8994->dev, "Device registered as type %d\n",
+ wm8994->type);
+ wm8994->type = WM8958;
+ break;
+ default:
dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
ret);
ret = -EINVAL;
@@ -370,14 +431,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
switch (ret) {
case 0:
case 1:
- dev_warn(wm8994->dev, "revision %c not fully supported\n",
- 'A' + ret);
+ if (wm8994->type == WM8994)
+ dev_warn(wm8994->dev,
+ "revision %c not fully supported\n",
+ 'A' + ret);
break;
default:
- dev_info(wm8994->dev, "revision %c\n", 'A' + ret);
break;
}
+ dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
if (pdata) {
wm8994->irq_base = pdata->irq_base;
@@ -418,15 +481,18 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
goto err_irq;
}
+ pm_runtime_enable(wm8994->dev);
+ pm_runtime_resume(wm8994->dev);
+
return 0;
err_irq:
wm8994_irq_exit(wm8994);
err_enable:
- regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
err_get:
- regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+ regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
err_supplies:
kfree(wm8994->supplies);
err:
@@ -437,11 +503,12 @@ err:
static void wm8994_device_exit(struct wm8994 *wm8994)
{
+ pm_runtime_disable(wm8994->dev);
mfd_remove_devices(wm8994->dev);
wm8994_irq_exit(wm8994);
- regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
- regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+ regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
kfree(wm8994->supplies);
kfree(wm8994);
}
@@ -506,8 +573,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
wm8994->read_dev = wm8994_i2c_read_device;
wm8994->write_dev = wm8994_i2c_write_device;
wm8994->irq = i2c->irq;
+ wm8994->type = id->driver_data;
- return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
+ return wm8994_device_init(wm8994, i2c->irq);
}
static int wm8994_i2c_remove(struct i2c_client *i2c)
@@ -519,36 +587,23 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
-{
- return wm8994_device_suspend(&i2c->dev);
-}
-
-static int wm8994_i2c_resume(struct i2c_client *i2c)
-{
- return wm8994_device_resume(&i2c->dev);
-}
-#else
-#define wm8994_i2c_suspend NULL
-#define wm8994_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8994_i2c_id[] = {
- { "wm8994", 0 },
+ { "wm8994", WM8994 },
+ { "wm8958", WM8958 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
+UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
+
static struct i2c_driver wm8994_i2c_driver = {
.driver = {
- .name = "wm8994",
- .owner = THIS_MODULE,
+ .name = "wm8994",
+ .owner = THIS_MODULE,
+ .pm = &wm8994_pm_ops,
},
.probe = wm8994_i2c_probe,
.remove = wm8994_i2c_remove,
- .suspend = wm8994_i2c_suspend,
- .resume = wm8994_i2c_resume,
.id_table = wm8994_i2c_id,
};
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index 8400eb1ee5db..29e8faf9c01c 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
return &wm8994_irqs[irq - wm8994->irq_base];
}
-static void wm8994_irq_lock(unsigned int irq)
+static void wm8994_irq_lock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8994->irq_lock);
}
-static void wm8994_irq_sync_unlock(unsigned int irq)
+static void wm8994_irq_sync_unlock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
@@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8994->irq_lock);
}
-static void wm8994_irq_unmask(unsigned int irq)
+static void wm8994_irq_unmask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm8994_irq_mask(unsigned int irq)
+static void wm8994_irq_mask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip wm8994_irq_chip = {
- .name = "wm8994",
- .bus_lock = wm8994_irq_lock,
- .bus_sync_unlock = wm8994_irq_sync_unlock,
- .mask = wm8994_irq_mask,
- .unmask = wm8994_irq_unmask,
+ .name = "wm8994",
+ .irq_bus_lock = wm8994_irq_lock,
+ .irq_bus_sync_unlock = wm8994_irq_sync_unlock,
+ .irq_mask = wm8994_irq_mask,
+ .irq_unmask = wm8994_irq_unmask,
};
/* The processing of the primary interrupt occurs in a thread so that
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4d073f1e4502..cc8e49db45fe 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -64,7 +64,7 @@ config ATMEL_PWM
config AB8500_PWM
bool "AB8500 PWM support"
- depends on AB8500_CORE
+ depends on AB8500_CORE && ARCH_U8500
select HAVE_PWM
help
This driver exports functions to enable/disble/config/free Pulse
@@ -402,7 +402,7 @@ config TI_DAC7512
DAC7512 16-bit digital-to-analog converter.
This driver can also be built as a module. If so, the module
- will be calles ti_dac7512.
+ will be called ti_dac7512.
config VMWARE_BALLOON
tristate "VMware Balloon Driver"
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index f9b91ba8900c..644d4cd071cc 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -123,7 +123,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct als_data *data = i2c_get_clientdata(client);
- unsigned int ret_val;
+ int ret_val;
unsigned long val;
if (strict_strtoul(buf, 10, &val))
@@ -251,7 +251,6 @@ static int apds9802als_probe(struct i2c_client *client,
return res;
als_error1:
- i2c_set_clientdata(client, NULL);
kfree(data);
return res;
}
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
index 9e3879ef58f2..fe8616a8d287 100644
--- a/drivers/misc/arm-charlcd.c
+++ b/drivers/misc/arm-charlcd.c
@@ -313,7 +313,7 @@ static int __init charlcd_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work);
schedule_delayed_work(&lcd->init_work, 0);
- dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n",
+ dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n",
lcd->phybase);
return 0;
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index cee632e645e1..d79a972f2c79 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -649,7 +649,7 @@ static ssize_t bh1770_power_state_store(struct device *dev,
{
struct bh1770_chip *chip = dev_get_drvdata(dev);
unsigned long value;
- size_t ret;
+ ssize_t ret;
if (strict_strtoul(buf, 0, &value))
return -EINVAL;
@@ -659,8 +659,12 @@ static ssize_t bh1770_power_state_store(struct device *dev,
pm_runtime_get_sync(dev);
ret = bh1770_lux_rate(chip, chip->lux_rate_index);
- ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+ if (ret < 0) {
+ pm_runtime_put(dev);
+ goto leave;
+ }
+ ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
if (ret < 0) {
pm_runtime_put(dev);
goto leave;
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 6f6218061b0d..d02d302ee6d5 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -16,12 +16,11 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/cs5535.h>
#include <linux/slab.h>
#define DRV_NAME "cs5535-mfgpt"
-#define MFGPT_BAR 2
static int mfgpt_reset_timers;
module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
@@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip {
DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
int initialized;
} cs5535_mfgpt_chip;
@@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)
return timers;
}
-static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev)
{
- int err, t;
+ struct resource *res;
+ int err = -EIO, t;
/* There are two ways to get the MFGPT base address; one is by
* fetching it from MSR_LBAR_MFGPT, the other is by reading the
@@ -302,29 +301,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR);
+ cs5535_mfgpt_chip.base = res->start;
cs5535_mfgpt_chip.pdev = pdev;
spin_lock_init(&cs5535_mfgpt_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR,
- (unsigned long long) cs5535_mfgpt_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* detect the available timers */
t = scan_timers(&cs5535_mfgpt_chip);
- dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t);
+ dev_info(&pdev->dev, "%d MFGPT timers available\n", t);
cs5535_mfgpt_chip.initialized = 1;
return 0;
@@ -332,47 +329,18 @@ done:
return err;
}
-static struct pci_device_id cs5535_mfgpt_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
+static struct platform_driver cs5535_mfgpt_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_mfgpt_probe,
};
-MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl);
-/*
- * Just like with the cs5535-gpio driver, we can't use the standard PCI driver
- * registration stuff. It only allows only one driver to bind to each PCI
- * device, and we want the GPIO and MFGPT drivers to be able to share a PCI
- * device. Instead, we manually scan for the PCI device, request a single
- * region, and keep track of the devices that we're using.
- */
-
-static int __init cs5535_mfgpt_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor,
- cs5535_mfgpt_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_mfgpt_probe(pdev,
- &cs5535_mfgpt_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
-}
static int __init cs5535_mfgpt_init(void)
{
- return cs5535_mfgpt_scan_pci();
+ return platform_driver_register(&cs5535_mfgpt_drv);
}
module_init(cs5535_mfgpt_init);
@@ -380,3 +348,4 @@ module_init(cs5535_mfgpt_init);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 559b0b3c16c3..ab1ad41786d1 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -20,6 +20,7 @@
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
@@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{
+ const __be32 *val;
+ struct device_node *node = client->dev.of_node;
+
+ if (node) {
+ if (of_get_property(node, "read-only", NULL))
+ chip->flags |= AT24_FLAG_READONLY;
+ val = of_get_property(node, "pagesize", NULL);
+ if (val)
+ chip->page_size = be32_to_cpup(val);
+ }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct at24_platform_data chip;
@@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
chip.page_size = 1;
+ /* update chipdata if OF is present */
+ at24_get_ofdata(client, &chip);
+
chip.setup = NULL;
chip.context = NULL;
}
@@ -492,6 +517,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (!is_power_of_2(chip.byte_len))
dev_warn(&client->dev,
"byte_len looks suspicious (no power of 2)!\n");
+ if (!chip.page_size) {
+ dev_err(&client->dev, "page_size must not be 0!\n");
+ err = -EINVAL;
+ goto err_out;
+ }
if (!is_power_of_2(chip.page_size))
dev_warn(&client->dev,
"page_size looks suspicious (no power of 2)!\n");
@@ -597,19 +627,15 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, at24);
- dev_info(&client->dev, "%zu byte %s EEPROM %s\n",
+ dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
at24->bin.size, client->name,
- writable ? "(writable)" : "(read-only)");
+ writable ? "writable" : "read-only", at24->write_max);
if (use_smbus == I2C_SMBUS_WORD_DATA ||
use_smbus == I2C_SMBUS_BYTE_DATA) {
dev_notice(&client->dev, "Falling back to %s reads, "
"performance will suffer\n", use_smbus ==
I2C_SMBUS_WORD_DATA ? "word" : "byte");
}
- dev_dbg(&client->dev,
- "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n",
- chip.page_size, num_addresses,
- at24->write_max, use_smbus);
/* export data to kernel code */
if (chip.setup)
@@ -660,6 +686,11 @@ static struct i2c_driver at24_driver = {
static int __init at24_init(void)
{
+ if (!io_limit) {
+ pr_err("at24: io_limit must not be 0!\n");
+ return -EINVAL;
+ }
+
io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&at24_driver);
}
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 193206602d88..668d41e594a9 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -273,13 +273,11 @@ ioc4_variant(struct ioc4_driver_data *idd)
static void __devinit
ioc4_load_modules(struct work_struct *work)
{
- /* arg just has to be freed */
-
request_module("sgiioc4");
-
- kfree(work);
}
+static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules);
+
/* Adds a new instance of an IOC4 card */
static int __devinit
ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
@@ -396,21 +394,12 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
* PCI device.
*/
if (idd->idd_variant != IOC4_VARIANT_PCI_RT) {
- struct work_struct *work;
- work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
- if (!work) {
- printk(KERN_WARNING
- "%s: IOC4 unable to allocate memory for "
- "load of sub-modules.\n", __func__);
- } else {
- /* Request the module from a work procedure as the
- * modprobe goes out to a userland helper and that
- * will hang if done directly from ioc4_probe().
- */
- printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
- INIT_WORK(work, ioc4_load_modules);
- schedule_work(work);
- }
+ /* Request the module from a work procedure as the modprobe
+ * goes out to a userland helper and that will hang if done
+ * directly from ioc4_probe().
+ */
+ printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
+ schedule_work(&ioc4_load_modules_work);
}
return 0;
@@ -498,7 +487,7 @@ static void __exit
ioc4_exit(void)
{
/* Ensure ioc4_load_modules() has completed before exiting */
- flush_scheduled_work();
+ flush_work_sync(&ioc4_load_modules_work);
pci_unregister_driver(&ioc4_driver);
}
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index 34fe835921c4..307aada5fffe 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -87,7 +87,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
- unsigned int ret_val;
+ int ret_val;
unsigned long val;
if (strict_strtoul(buf, 10, &val))
@@ -106,6 +106,8 @@ static ssize_t als_sensing_range_store(struct device *dev,
val = 4;
ret_val = i2c_smbus_read_byte_data(client, 0x00);
+ if (ret_val < 0)
+ return ret_val;
ret_val &= 0xFC; /*reset the bit before setting them */
ret_val |= val - 1;
@@ -181,9 +183,7 @@ static int isl29020_probe(struct i2c_client *client,
static int isl29020_remove(struct i2c_client *client)
{
- struct als_data *data = i2c_get_clientdata(client);
sysfs_remove_group(&client->dev.kobj, &m_als_gr);
- kfree(data);
return 0;
}
@@ -243,6 +243,6 @@ static void __exit sensor_isl29020_exit(void)
module_init(sensor_isl29020_init);
module_exit(sensor_isl29020_exit);
-MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>");
MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index d551f09ccb79..6956f7e7d439 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -439,18 +439,23 @@ xpc_discovery(void)
* nodes that can comprise an access protection grouping. The access
* protection is in regards to memory, IOI and IPI.
*/
- max_regions = 64;
region_size = xp_region_size;
- switch (region_size) {
- case 128:
- max_regions *= 2;
- case 64:
- max_regions *= 2;
- case 32:
- max_regions *= 2;
- region_size = 16;
- DBUG_ON(!is_shub2());
+ if (is_uv())
+ max_regions = 256;
+ else {
+ max_regions = 64;
+
+ switch (region_size) {
+ case 128:
+ max_regions *= 2;
+ case 64:
+ max_regions *= 2;
+ case 32:
+ max_regions *= 2;
+ region_size = 16;
+ DBUG_ON(!is_shub2());
+ }
}
for (region = 0; region < max_regions; region++) {
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index 2a1e804a71aa..4d2ea8e80140 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -45,7 +45,7 @@
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
-MODULE_VERSION("1.2.1.1-k");
+MODULE_VERSION("1.2.1.2-k");
MODULE_ALIAS("dmi:*:svnVMware*:*");
MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL");
@@ -315,7 +315,8 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target)
* fear that guest will need it. Host may reject some pages, we need to
* check the return value and maybe submit a different page.
*/
-static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn)
+static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
+ unsigned int *hv_status)
{
unsigned long status, dummy;
u32 pfn32;
@@ -326,7 +327,7 @@ static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn)
STATS_INC(b->stats.lock);
- status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy);
+ *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy);
if (vmballoon_check_status(b, status))
return true;
@@ -410,6 +411,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
{
struct page *page;
gfp_t flags;
+ unsigned int hv_status;
bool locked = false;
do {
@@ -429,11 +431,12 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
}
/* inform monitor */
- locked = vmballoon_send_lock_page(b, page_to_pfn(page));
+ locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status);
if (!locked) {
STATS_INC(b->stats.refused_alloc);
- if (b->reset_required) {
+ if (hv_status == VMW_BALLOON_ERROR_RESET ||
+ hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) {
__free_page(page);
return -EIO;
}
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 57e4416b9ef0..2a876c4099cd 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -16,6 +16,7 @@ config MMC_BLOCK
config MMC_BLOCK_MINORS
int "Number of minors per block device"
+ depends on MMC_BLOCK
range 4 256
default 8
help
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 217f82037fc1..bfc8a8ae55df 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -257,7 +257,7 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err)
- printk(KERN_ERR "%s: error %d sending status comand",
+ printk(KERN_ERR "%s: error %d sending status command",
req->rq_disk->disk_name, err);
return cmd.resp[0];
}
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index bb22ffd76ef8..ef103871517f 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -16,3 +16,14 @@ config MMC_UNSAFE_RESUME
This option sets a default which can be overridden by the
module parameter "removable=0" or "removable=1".
+
+config MMC_CLKGATE
+ bool "MMC host clock gating (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ This will attempt to aggressively gate the clock to the MMC card.
+ This is done to save power due to gating off the logic and bus
+ noise when the MMC card is not in use. Your host driver has to
+ support handling this in order for it to be of any use.
+
+ If unsure, say N.
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index af8dc6a2a317..63667a8f140c 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -303,14 +303,14 @@ int mmc_add_card(struct mmc_card *card)
type, card->rca);
}
- ret = device_add(&card->dev);
- if (ret)
- return ret;
-
#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif
+ ret = device_add(&card->dev);
+ if (ret)
+ return ret;
+
mmc_card_set_present(card);
return 0;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8f86d702e46e..6625c057be05 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -22,6 +22,7 @@
#include <linux/scatterlist.h>
#include <linux/log2.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -130,6 +131,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
if (mrq->done)
mrq->done(mrq);
+
+ mmc_host_clk_gate(host);
}
}
@@ -190,6 +193,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
+ mmc_host_clk_ungate(host);
host->ops->request(host, mrq);
}
@@ -295,8 +299,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
unsigned int timeout_us, limit_us;
timeout_us = data->timeout_ns / 1000;
- timeout_us += data->timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
+ if (mmc_host_clk_rate(card->host))
+ timeout_us += data->timeout_clks * 1000 /
+ (mmc_host_clk_rate(card->host) / 1000);
if (data->flags & MMC_DATA_WRITE)
/*
@@ -614,6 +619,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width, ios->timing);
+ if (ios->clock > 0)
+ mmc_set_ungated(host);
host->ops->set_ios(host, ios);
}
@@ -641,6 +648,61 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
mmc_set_ios(host);
}
+#ifdef CONFIG_MMC_CLKGATE
+/*
+ * This gates the clock by setting it to 0 Hz.
+ */
+void mmc_gate_clock(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_old = host->ios.clock;
+ host->ios.clock = 0;
+ host->clk_gated = true;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_set_ios(host);
+}
+
+/*
+ * This restores the clock from gating by using the cached
+ * clock value.
+ */
+void mmc_ungate_clock(struct mmc_host *host)
+{
+ /*
+ * We should previously have gated the clock, so the clock shall
+ * be 0 here! The clock may however be 0 during initialization,
+ * when some request operations are performed before setting
+ * the frequency. When ungate is requested in that situation
+ * we just ignore the call.
+ */
+ if (host->clk_old) {
+ BUG_ON(host->ios.clock);
+ /* This call will also set host->clk_gated to false */
+ mmc_set_clock(host, host->clk_old);
+ }
+}
+
+void mmc_set_ungated(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ /*
+ * We've been given a new frequency while the clock is gated,
+ * so make sure we regard this as ungating it.
+ */
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_gated = false;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+#else
+void mmc_set_ungated(struct mmc_host *host)
+{
+}
+#endif
+
/*
* Change the bus mode (open drain/push-pull) of a host.
*/
@@ -1424,35 +1486,57 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
+static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
+{
+ host->f_init = freq;
+
+#ifdef CONFIG_MMC_DEBUG
+ pr_info("%s: %s: trying to init card at %u Hz\n",
+ mmc_hostname(host), __func__, host->f_init);
+#endif
+ mmc_power_up(host);
+ sdio_reset(host);
+ mmc_go_idle(host);
+
+ mmc_send_if_cond(host, host->ocr_avail);
+
+ /* Order's important: probe SDIO, then SD, then MMC */
+ if (!mmc_attach_sdio(host))
+ return 0;
+ if (!mmc_attach_sd(host))
+ return 0;
+ if (!mmc_attach_mmc(host))
+ return 0;
+
+ mmc_power_off(host);
+ return -EIO;
+}
+
void mmc_rescan(struct work_struct *work)
{
+ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
- u32 ocr;
- int err;
- unsigned long flags;
int i;
- const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->rescan_disable) {
- spin_unlock_irqrestore(&host->lock, flags);
+ if (host->rescan_disable)
return;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-
mmc_bus_get(host);
- /* if there is a card registered, check whether it is still present */
- if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
+ /*
+ * if there is a _removable_ card registered, check whether it is
+ * still present
+ */
+ if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+ && mmc_card_is_removable(host))
host->bus_ops->detect(host);
+ /*
+ * Let mmc_bus_put() free the bus/bus_ops if we've found that
+ * the card is no longer present.
+ */
mmc_bus_put(host);
-
-
mmc_bus_get(host);
/* if there still is a card present, stop here */
@@ -1461,8 +1545,6 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
- /* detect a newly inserted card */
-
/*
* Only we can add a new handler, so it's safe to
* release the lock here.
@@ -1472,72 +1554,16 @@ void mmc_rescan(struct work_struct *work)
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
+ mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
- mmc_claim_host(host);
-
- if (freqs[i] >= host->f_min)
- host->f_init = freqs[i];
- else if (!i || freqs[i-1] > host->f_min)
- host->f_init = host->f_min;
- else {
- mmc_release_host(host);
- goto out;
- }
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: trying to init card at %u Hz\n",
- mmc_hostname(host), __func__, host->f_init);
-#endif
- mmc_power_up(host);
- sdio_reset(host);
- mmc_go_idle(host);
-
- 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_claim_host(host);
- /*
- * Try SDMEM (but not MMC) even if SDIO
- * is broken.
- */
- if (mmc_send_app_op_cond(host, 0, &ocr))
- goto out_fail;
-
- if (mmc_attach_sd(host, ocr))
- mmc_power_off(host);
- }
- goto out;
- }
-
- /*
- * ...then normal SD...
- */
- err = mmc_send_app_op_cond(host, 0, &ocr);
- if (!err) {
- if (mmc_attach_sd(host, ocr))
- mmc_power_off(host);
- goto out;
- }
-
- /*
- * ...and finally MMC.
- */
- err = mmc_send_op_cond(host, 0, &ocr);
- if (!err) {
- if (mmc_attach_mmc(host, ocr))
- mmc_power_off(host);
- goto out;
- }
-
-out_fail:
- mmc_release_host(host);
- mmc_power_off(host);
+ if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
+ break;
+ if (freqs[i] < host->f_min)
+ break;
}
-out:
+ mmc_release_host(host);
+
+ out:
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
}
@@ -1559,7 +1585,7 @@ void mmc_stop_host(struct mmc_host *host)
if (host->caps & MMC_CAP_DISABLE)
cancel_delayed_work(&host->disable);
- cancel_delayed_work(&host->detect);
+ cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
@@ -1721,6 +1747,18 @@ int mmc_resume_host(struct mmc_host *host)
if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
+ /*
+ * Tell runtime PM core we just powered up the card,
+ * since it still believes the card is powered off.
+ * Note that currently runtime PM is only enabled
+ * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
+ */
+ if (mmc_card_sdio(host->card) &&
+ (host->caps & MMC_CAP_POWER_OFF_CARD)) {
+ pm_runtime_disable(&host->card->dev);
+ pm_runtime_set_active(&host->card->dev);
+ pm_runtime_enable(&host->card->dev);
+ }
}
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
@@ -1773,6 +1811,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
case PM_POST_SUSPEND:
case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
@@ -1789,7 +1828,7 @@ static int __init mmc_init(void)
{
int ret;
- workqueue = create_singlethread_workqueue("kmmcd");
+ workqueue = alloc_ordered_workqueue("kmmcd", 0);
if (!workqueue)
return -ENOMEM;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 77240cd11bcf..ca1fdde29df6 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -33,6 +33,9 @@ void mmc_init_erase(struct mmc_card *card);
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_gate_clock(struct mmc_host *host);
+void mmc_ungate_clock(struct mmc_host *host);
+void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
@@ -54,9 +57,9 @@ void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
-int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
-int mmc_attach_sd(struct mmc_host *host, u32 ocr);
-int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
+int mmc_attach_mmc(struct mmc_host *host);
+int mmc_attach_sd(struct mmc_host *host);
+int mmc_attach_sdio(struct mmc_host *host);
/* Module parameters */
extern int use_spi_crc;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index eed1405fd742..998797ed67a6 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -183,6 +183,11 @@ void mmc_add_host_debugfs(struct mmc_host *host)
&mmc_clock_fops))
goto err_node;
+#ifdef CONFIG_MMC_CLKGATE
+ if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
+ root, &host->clk_delay))
+ goto err_node;
+#endif
return;
err_node:
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 10b8af27e03a..b3ac6c5bc5c6 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007-2008 Pierre Ossman
+ * Copyright (C) 2010 Linus Walleij
*
* 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
@@ -20,6 +21,7 @@
#include <linux/suspend.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
#include "core.h"
#include "host.h"
@@ -50,6 +52,205 @@ void mmc_unregister_host_class(void)
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
+#ifdef CONFIG_MMC_CLKGATE
+
+/*
+ * Enabling clock gating will make the core call out to the host
+ * once up and once down when it performs a request or card operation
+ * intermingled in any fashion. The driver will see this through
+ * set_ios() operations with ios.clock field set to 0 to gate (disable)
+ * the block clock, and to the old frequency to enable it again.
+ */
+static void mmc_host_clk_gate_delayed(struct mmc_host *host)
+{
+ unsigned long tick_ns;
+ unsigned long freq = host->ios.clock;
+ unsigned long flags;
+
+ if (!freq) {
+ pr_debug("%s: frequency set to 0 in disable function, "
+ "this means the clock is already disabled.\n",
+ mmc_hostname(host));
+ return;
+ }
+ /*
+ * New requests may have appeared while we were scheduling,
+ * then there is no reason to delay the check before
+ * clk_disable().
+ */
+ spin_lock_irqsave(&host->clk_lock, flags);
+
+ /*
+ * Delay n bus cycles (at least 8 from MMC spec) before attempting
+ * to disable the MCI block clock. The reference count may have
+ * gone up again after this delay due to rescheduling!
+ */
+ if (!host->clk_requests) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ tick_ns = DIV_ROUND_UP(1000000000, freq);
+ ndelay(host->clk_delay * tick_ns);
+ } else {
+ /* New users appeared while waiting for this work */
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return;
+ }
+ mutex_lock(&host->clk_gate_mutex);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (!host->clk_requests) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ /* This will set host->ios.clock to 0 */
+ mmc_gate_clock(host);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
+ }
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mutex_unlock(&host->clk_gate_mutex);
+}
+
+/*
+ * Internal work. Work to disable the clock at some later point.
+ */
+static void mmc_host_clk_gate_work(struct work_struct *work)
+{
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_gate_work);
+
+ mmc_host_clk_gate_delayed(host);
+}
+
+/**
+ * mmc_host_clk_ungate - ungate hardware MCI clocks
+ * @host: host to ungate.
+ *
+ * Makes sure the host ios.clock is restored to a non-zero value
+ * past this call. Increase clock reference count and ungate clock
+ * if we're the first user.
+ */
+void mmc_host_clk_ungate(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ mutex_lock(&host->clk_gate_mutex);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (host->clk_gated) {
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_ungate_clock(host);
+ spin_lock_irqsave(&host->clk_lock, flags);
+ pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
+ }
+ host->clk_requests++;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mutex_unlock(&host->clk_gate_mutex);
+}
+
+/**
+ * mmc_host_may_gate_card - check if this card may be gated
+ * @card: card to check.
+ */
+static bool mmc_host_may_gate_card(struct mmc_card *card)
+{
+ /* If there is no card we may gate it */
+ if (!card)
+ return true;
+ /*
+ * Don't gate SDIO cards! These need to be clocked at all times
+ * since they may be independent systems generating interrupts
+ * and other events. The clock requests counter from the core will
+ * go down to zero since the core does not need it, but we will not
+ * gate the clock, because there is somebody out there that may still
+ * be using it.
+ */
+ if (mmc_card_sdio(card))
+ return false;
+
+ return true;
+}
+
+/**
+ * mmc_host_clk_gate - gate off hardware MCI clocks
+ * @host: host to gate.
+ *
+ * Calls the host driver with ios.clock set to zero as often as possible
+ * in order to gate off hardware MCI clocks. Decrease clock reference
+ * count and schedule disabling of clock.
+ */
+void mmc_host_clk_gate(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_requests--;
+ if (mmc_host_may_gate_card(host->card) &&
+ !host->clk_requests)
+ schedule_work(&host->clk_gate_work);
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
+/**
+ * mmc_host_clk_rate - get current clock frequency setting
+ * @host: host to get the clock frequency for.
+ *
+ * Returns current clock frequency regardless of gating.
+ */
+unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+ unsigned long freq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (host->clk_gated)
+ freq = host->clk_old;
+ else
+ freq = host->ios.clock;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ return freq;
+}
+
+/**
+ * mmc_host_clk_init - set up clock gating code
+ * @host: host with potential clock to control
+ */
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+ host->clk_requests = 0;
+ /* Hold MCI clock for 8 cycles by default */
+ host->clk_delay = 8;
+ host->clk_gated = false;
+ INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+ spin_lock_init(&host->clk_lock);
+ mutex_init(&host->clk_gate_mutex);
+}
+
+/**
+ * mmc_host_clk_exit - shut down clock gating code
+ * @host: host with potential clock to control
+ */
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+ /*
+ * Wait for any outstanding gate and then make sure we're
+ * ungated before exiting.
+ */
+ if (cancel_work_sync(&host->clk_gate_work))
+ mmc_host_clk_gate_delayed(host);
+ if (host->clk_gated)
+ mmc_host_clk_ungate(host);
+ /* There should be only one user now */
+ WARN_ON(host->clk_requests > 1);
+}
+
+#else
+
+static inline void mmc_host_clk_init(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_exit(struct mmc_host *host)
+{
+}
+
+#endif
+
/**
* mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure
@@ -82,6 +283,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
+ mmc_host_clk_init(host);
+
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -163,6 +366,8 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
+
+ mmc_host_clk_exit(host);
}
EXPORT_SYMBOL(mmc_remove_host);
@@ -183,4 +388,3 @@ void mmc_free_host(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_free_host);
-
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 8c87e1109a34..de199f911928 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -10,10 +10,31 @@
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
+#include <linux/mmc/host.h>
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
+#ifdef CONFIG_MMC_CLKGATE
+void mmc_host_clk_ungate(struct mmc_host *host);
+void mmc_host_clk_gate(struct mmc_host *host);
+unsigned int mmc_host_clk_rate(struct mmc_host *host);
+
+#else
+static inline void mmc_host_clk_ungate(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_gate(struct mmc_host *host)
+{
+}
+
+static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+ return host->ios.clock;
+}
+#endif
+
void mmc_host_deeper_disable(struct work_struct *work);
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 995261f7fd70..16006ef153fe 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -375,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
struct mmc_card *card;
- int err, ddr = MMC_SDR_MODE;
+ int err, ddr = 0;
u32 cid[4];
unsigned int max_dtr;
@@ -534,34 +534,56 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
- unsigned ext_csd_bit, bus_width;
-
- if (host->caps & MMC_CAP_8_BIT_DATA) {
- if (ddr)
- ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
- else
- ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
- bus_width = MMC_BUS_WIDTH_8;
- } else {
- if (ddr)
- ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
- else
- ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
- bus_width = MMC_BUS_WIDTH_4;
+ static unsigned ext_csd_bits[][2] = {
+ { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
+ { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
+ { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
+ };
+ static unsigned bus_widths[] = {
+ MMC_BUS_WIDTH_8,
+ MMC_BUS_WIDTH_4,
+ MMC_BUS_WIDTH_1
+ };
+ unsigned idx, bus_width = 0;
+
+ if (host->caps & MMC_CAP_8_BIT_DATA)
+ idx = 0;
+ else
+ idx = 1;
+ for (; idx < ARRAY_SIZE(bus_widths); idx++) {
+ bus_width = bus_widths[idx];
+ if (bus_width == MMC_BUS_WIDTH_1)
+ ddr = 0; /* no DDR for 1-bit width */
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx][0]);
+ if (!err) {
+ mmc_set_bus_width_ddr(card->host,
+ bus_width, MMC_SDR_MODE);
+ /*
+ * If controller can't handle bus width test,
+ * use the highest bus width to maintain
+ * compatibility with previous MMC behavior.
+ */
+ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+ break;
+ err = mmc_bus_test(card, bus_width);
+ if (!err)
+ break;
+ }
}
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH, ext_csd_bit);
-
- if (err && err != -EBADMSG)
- goto free_card;
-
+ if (!err && ddr) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx][1]);
+ }
if (err) {
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
- "failed\n", mmc_hostname(card->host),
- 1 << bus_width, ddr);
- err = 0;
- } else {
+ "failed\n", mmc_hostname(card->host),
+ 1 << bus_width, ddr);
+ goto free_card;
+ } else if (ddr) {
mmc_card_set_ddr_mode(card);
mmc_set_bus_width_ddr(card->host, bus_width, ddr);
}
@@ -733,14 +755,21 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
/*
* Starting point for MMC card init.
*/
-int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
+int mmc_attach_mmc(struct mmc_host *host)
{
int err;
+ u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err)
+ return err;
+
mmc_attach_bus_ops(host);
+ if (host->ocr_avail_mmc)
+ host->ocr_avail = host->ocr_avail_mmc;
/*
* We need to get OCR a different way for SPI.
@@ -780,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
goto err;
mmc_release_host(host);
-
err = mmc_add_card(host->card);
+ mmc_claim_host(host);
if (err)
goto remove_card;
return 0;
remove_card:
+ mmc_release_host(host);
mmc_remove_card(host->card);
- host->card = NULL;
mmc_claim_host(host);
+ host->card = NULL;
err:
mmc_detach_bus(host);
- mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
mmc_hostname(host), err);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 326447c9ede8..60842f878ded 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -462,3 +462,104 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
return 0;
}
+static int
+mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
+ u8 len)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+ u8 *data_buf;
+ u8 *test_buf;
+ int i, err;
+ static u8 testdata_8bit[8] = { 0x55, 0xaa, 0, 0, 0, 0, 0, 0 };
+ static u8 testdata_4bit[4] = { 0x5a, 0, 0, 0 };
+
+ /* 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)
+ return -ENOMEM;
+
+ if (len == 8)
+ test_buf = testdata_8bit;
+ else if (len == 4)
+ test_buf = testdata_4bit;
+ else {
+ printk(KERN_ERR "%s: Invalid bus_width %d\n",
+ mmc_hostname(host), len);
+ kfree(data_buf);
+ return -EINVAL;
+ }
+
+ if (opcode == MMC_BUS_TEST_W)
+ memcpy(data_buf, test_buf, len);
+
+ 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 = opcode;
+ cmd.arg = 0;
+
+ /* 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;
+ if (opcode == MMC_BUS_TEST_R)
+ data.flags = MMC_DATA_READ;
+ else
+ data.flags = MMC_DATA_WRITE;
+
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, data_buf, len);
+ mmc_wait_for_req(host, &mrq);
+ err = 0;
+ if (opcode == MMC_BUS_TEST_R) {
+ for (i = 0; i < len / 4; i++)
+ if ((test_buf[i] ^ data_buf[i]) != 0xff) {
+ err = -EIO;
+ break;
+ }
+ }
+ kfree(data_buf);
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return err;
+}
+
+int mmc_bus_test(struct mmc_card *card, u8 bus_width)
+{
+ int err, width;
+
+ if (bus_width == MMC_BUS_WIDTH_8)
+ width = 8;
+ else if (bus_width == MMC_BUS_WIDTH_4)
+ width = 4;
+ else if (bus_width == MMC_BUS_WIDTH_1)
+ return 0; /* no need for test */
+ else
+ return -EINVAL;
+
+ /*
+ * Ignore errors from BUS_TEST_W. BUS_TEST_R will fail if there
+ * is a problem. This improves chances that the test will work.
+ */
+ mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width);
+ err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
+ return err;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e84178..e6d44b8a18db 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@ 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);
int mmc_card_sleepawake(struct mmc_host *host, int sleep);
+int mmc_bus_test(struct mmc_card *card, u8 bus_width);
#endif
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 49da4dffd28e..d18c32bca99b 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -764,14 +764,21 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
/*
* Starting point for SD card init.
*/
-int mmc_attach_sd(struct mmc_host *host, u32 ocr)
+int mmc_attach_sd(struct mmc_host *host)
{
int err;
+ u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+ if (err)
+ return err;
+
mmc_sd_attach_bus_ops(host);
+ if (host->ocr_avail_sd)
+ host->ocr_avail = host->ocr_avail_sd;
/*
* We need to get OCR a different way for SPI.
@@ -795,7 +802,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
ocr &= ~0x7F;
}
- if (ocr & MMC_VDD_165_195) {
+ if ((ocr & MMC_VDD_165_195) &&
+ !(host->ocr_avail_sd & MMC_VDD_165_195)) {
printk(KERN_WARNING "%s: SD card claims to support the "
"incompletely defined 'low voltage range'. This "
"will be ignored.\n", mmc_hostname(host));
@@ -820,20 +828,20 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
goto err;
mmc_release_host(host);
-
err = mmc_add_card(host->card);
+ mmc_claim_host(host);
if (err)
goto remove_card;
return 0;
remove_card:
+ mmc_release_host(host);
mmc_remove_card(host->card);
host->card = NULL;
mmc_claim_host(host);
err:
mmc_detach_bus(host);
- mmc_release_host(host);
printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index c3ad1058cd31..5c4a54d9b6a4 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -547,9 +547,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
BUG_ON(!host->card);
/* Make sure card is powered before detecting it */
- err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0)
- goto out;
+ if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+ err = pm_runtime_get_sync(&host->card->dev);
+ if (err < 0)
+ goto out;
+ }
mmc_claim_host(host);
@@ -560,6 +562,20 @@ static void mmc_sdio_detect(struct mmc_host *host)
mmc_release_host(host);
+ /*
+ * Tell PM core it's OK to power off the card now.
+ *
+ * The _sync variant is used in order to ensure that the card
+ * is left powered off in case an error occurred, and the card
+ * is going to be removed.
+ *
+ * Since there is no specific reason to believe a new user
+ * is about to show up at this point, the _sync variant is
+ * desirable anyway.
+ */
+ if (host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_sync(&host->card->dev);
+
out:
if (err) {
mmc_sdio_remove(host);
@@ -568,9 +584,6 @@ out:
mmc_detach_bus(host);
mmc_release_host(host);
}
-
- /* Tell PM core that we're done */
- pm_runtime_put(&host->card->dev);
}
/*
@@ -614,15 +627,27 @@ static int mmc_sdio_suspend(struct mmc_host *host)
static int mmc_sdio_resume(struct mmc_host *host)
{
- int i, err;
+ int i, err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
/* Basic card reinitialization. */
mmc_claim_host(host);
- err = mmc_sdio_init_card(host, host->ocr, host->card,
+
+ /* No need to reinitialize powered-resumed nonremovable cards */
+ if (mmc_card_is_removable(host) || !mmc_card_is_powered_resumed(host))
+ err = mmc_sdio_init_card(host, host->ocr, host->card,
(host->pm_flags & MMC_PM_KEEP_POWER));
+ else if (mmc_card_is_powered_resumed(host)) {
+ /* We may have switched to 1-bit mode during suspend */
+ err = sdio_enable_4bit_bus(host->card);
+ if (err > 0) {
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ err = 0;
+ }
+ }
+
if (!err && host->sdio_irqs)
mmc_signal_sdio_irq(host);
mmc_release_host(host);
@@ -677,16 +702,22 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
/*
* Starting point for SDIO card init.
*/
-int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
+int mmc_attach_sdio(struct mmc_host *host)
{
- int err;
- int i, funcs;
+ int err, i, funcs;
+ u32 ocr;
struct mmc_card *card;
BUG_ON(!host);
WARN_ON(!host->claimed);
+ err = mmc_send_io_op_cond(host, 0, &ocr);
+ if (err)
+ return err;
+
mmc_attach_bus(host, &mmc_sdio_ops);
+ if (host->ocr_avail_sdio)
+ host->ocr_avail = host->ocr_avail_sdio;
/*
* Sanity check the voltages that the card claims to
@@ -718,16 +749,21 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
card = host->card;
/*
- * Let runtime PM core know our card is active
+ * Enable runtime PM only if supported by host+card+board
*/
- err = pm_runtime_set_active(&card->dev);
- if (err)
- goto remove;
+ if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+ /*
+ * Let runtime PM core know our card is active
+ */
+ err = pm_runtime_set_active(&card->dev);
+ if (err)
+ goto remove;
- /*
- * Enable runtime PM for this card
- */
- pm_runtime_enable(&card->dev);
+ /*
+ * Enable runtime PM for this card
+ */
+ pm_runtime_enable(&card->dev);
+ }
/*
* The number of functions on the card is encoded inside
@@ -745,17 +781,18 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
goto remove;
/*
- * Enable Runtime PM for this func
+ * Enable Runtime PM for this func (if supported)
*/
- pm_runtime_enable(&card->sdio_func[i]->dev);
+ if (host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_enable(&card->sdio_func[i]->dev);
}
- mmc_release_host(host);
-
/*
* First add the card to the driver model...
*/
+ mmc_release_host(host);
err = mmc_add_card(host->card);
+ mmc_claim_host(host);
if (err)
goto remove_added;
@@ -773,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
remove_added:
/* Remove without lock if the device has been added. */
+ mmc_release_host(host);
mmc_sdio_remove(host);
mmc_claim_host(host);
remove:
/* And with lock if it hasn't been added. */
+ mmc_release_host(host);
if (host->card)
mmc_sdio_remove(host);
+ mmc_claim_host(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);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 2716c7ab6bbf..d29b9c36919a 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include "sdio_cis.h"
@@ -132,9 +133,11 @@ static int sdio_bus_probe(struct device *dev)
* it should call pm_runtime_put_noidle() in its probe routine and
* pm_runtime_get_noresume() in its remove routine.
*/
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto out;
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto out;
+ }
/* Set the default block size so the driver is sure it's something
* sensible. */
@@ -151,7 +154,8 @@ static int sdio_bus_probe(struct device *dev)
return 0;
disable_runtimepm:
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
out:
return ret;
}
@@ -160,12 +164,14 @@ 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);
- int ret;
+ int ret = 0;
/* Make sure card is powered before invoking ->remove() */
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto out;
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto out;
+ }
drv->remove(func);
@@ -178,10 +184,12 @@ static int sdio_bus_remove(struct device *dev)
}
/* First, undo the increment made directly above */
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
/* Then undo the runtime PM settings in sdio_bus_probe() */
- pm_runtime_put_noidle(dev);
+ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
+ pm_runtime_put_noidle(dev);
out:
return ret;
@@ -189,41 +197,12 @@ out:
#ifdef CONFIG_PM_RUNTIME
-static int sdio_bus_pm_prepare(struct device *dev)
-{
- /*
- * Resume an SDIO device which was suspended at run time at this
- * point, in order to allow standard SDIO suspend/resume paths
- * to keep working as usual.
- *
- * Ultimately, the SDIO driver itself will decide (in its
- * suspend handler, or lack thereof) whether the card should be
- * removed or kept, and if kept, at what power state.
- *
- * At this point, PM core have increased our use count, so it's
- * safe to directly resume the device. After system is resumed
- * again, PM core will drop back its runtime PM use count, and if
- * needed device will be suspended again.
- *
- * The end result is guaranteed to be a power state that is
- * coherent with the device's runtime PM use count.
- *
- * The return value of pm_runtime_resume is deliberately unchecked
- * since there is little point in failing system suspend if a
- * device can't be resumed.
- */
- pm_runtime_resume(dev);
-
- return 0;
-}
-
static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
pm_generic_runtime_idle
)
- .prepare = sdio_bus_pm_prepare,
};
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index d618e8673996..afe8c6fa166a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -83,7 +83,7 @@ config MMC_RICOH_MMC
config MMC_SDHCI_OF
tristate "SDHCI support on OpenFirmware platforms"
- depends on MMC_SDHCI && PPC_OF
+ depends on MMC_SDHCI && OF
help
This selects the OF support for Secure Digital Host Controller
Interfaces.
@@ -93,6 +93,7 @@ config MMC_SDHCI_OF
config MMC_SDHCI_OF_ESDHC
bool "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_OF
+ depends on PPC_OF
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help
This selects the Freescale eSDHC controller support.
@@ -102,6 +103,7 @@ config MMC_SDHCI_OF_ESDHC
config MMC_SDHCI_OF_HLWD
bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
depends on MMC_SDHCI_OF
+ depends on PPC_OF
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help
This selects the Secure Digital Host Controller Interface (SDHCI)
@@ -140,6 +142,27 @@ config MMC_SDHCI_ESDHC_IMX
If unsure, say N.
+config MMC_SDHCI_DOVE
+ bool "SDHCI support on Marvell's Dove SoC"
+ depends on ARCH_DOVE
+ depends on MMC_SDHCI_PLTFM
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This selects the Secure Digital Host Controller Interface in
+ Marvell's Dove SoC.
+
+ If unsure, say N.
+
+config MMC_SDHCI_TEGRA
+ tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+ depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This selects the Tegra SD/MMC controller. If you have a Tegra
+ platform with SD or MMC devices, say Y or M here.
+
+ If unsure, say N.
+
config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC"
depends on MMC_SDHCI && PLAT_SAMSUNG
@@ -458,11 +481,27 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
help
If you say yes here SD-Cards may work on the EZkit.
+config MMC_DW
+ tristate "Synopsys DesignWare Memory Card Interface"
+ depends on ARM
+ help
+ This selects support for the Synopsys DesignWare Mobile Storage IP
+ block, this provides host support for SD and MMC interfaces, in both
+ PIO and external DMA modes.
+
+config MMC_DW_IDMAC
+ bool "Internal DMAC interface"
+ depends on MMC_DW
+ help
+ This selects support for the internal DMAC block within the Synopsys
+ Designware Mobile Storage IP block. This disables the external DMA
+ interface.
+
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
help
- This selects the MMC Host Interface controler (MMCIF).
+ This selects the MMC Host Interface controller (MMCIF).
This driver supports MMCIF in sh7724/sh7757/sh7372.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7b645ff43b30..e834fb223e9a 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
+obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_USHC) += ushc.o
@@ -39,6 +40,8 @@ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
sdhci-platform-y := sdhci-pltfm.o
sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 591ab540b407..d3e6a962f423 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -69,6 +69,7 @@
#include <linux/highmem.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sdio.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -493,10 +494,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
else if (data->flags & MMC_DATA_WRITE)
cmdr |= AT91_MCI_TRCMD_START;
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->blocks > 1)
- cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ if (cmd->opcode == SD_IO_RW_EXTENDED) {
+ cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
+ } else {
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= AT91_MCI_TRTYP_STREAM;
+ if (data->blocks > 1)
+ cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ }
}
else {
block_length = 0;
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 301351a5d838..ad2a7a032cdf 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -26,6 +26,7 @@
#include <linux/stat.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sdio.h>
#include <mach/atmel-mci.h>
#include <linux/atmel-mci.h>
@@ -532,12 +533,17 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
data = cmd->data;
if (data) {
cmdr |= MCI_CMDR_START_XFER;
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= MCI_CMDR_STREAM;
- else if (data->blocks > 1)
- cmdr |= MCI_CMDR_MULTI_BLOCK;
- else
- cmdr |= MCI_CMDR_BLOCK;
+
+ if (cmd->opcode == SD_IO_RW_EXTENDED) {
+ cmdr |= MCI_CMDR_SDIO_BLOCK;
+ } else {
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= MCI_CMDR_STREAM;
+ else if (data->blocks > 1)
+ cmdr |= MCI_CMDR_MULTI_BLOCK;
+ else
+ cmdr |= MCI_CMDR_BLOCK;
+ }
if (data->flags & MMC_DATA_READ)
cmdr |= MCI_CMDR_TRDIR_READ;
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 41e5a60493ad..ef72e874ca36 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -192,7 +192,7 @@ static inline void SEND_STOP(struct au1xmmc_host *host)
au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
au_sync();
- /* Send the stop commmand */
+ /* Send the stop command */
au_writel(STOP_CMD, HOST_CMD(host));
}
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index e15547cf701f..0076c7448fe6 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -66,8 +66,8 @@
#define DAVINCI_MMCBLNC 0x60
#define DAVINCI_SDIOCTL 0x64
#define DAVINCI_SDIOST0 0x68
-#define DAVINCI_SDIOEN 0x6C
-#define DAVINCI_SDIOST 0x70
+#define DAVINCI_SDIOIEN 0x6C
+#define DAVINCI_SDIOIST 0x70
#define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */
/* DAVINCI_MMCCTL definitions */
@@ -131,6 +131,14 @@
#define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */
#define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */
+/* DAVINCI_SDIOST0 definitions */
+#define SDIOST0_DAT1_HI BIT(0)
+
+/* DAVINCI_SDIOIEN definitions */
+#define SDIOIEN_IOINTEN BIT(0)
+
+/* DAVINCI_SDIOIST definitions */
+#define SDIOIST_IOINT BIT(0)
/* MMCSD Init clock in Hz in opendrain mode */
#define MMCSD_INIT_CLOCK 200000
@@ -164,7 +172,7 @@ struct mmc_davinci_host {
unsigned int mmc_input_clk;
void __iomem *base;
struct resource *mem_res;
- int irq;
+ int mmc_irq, sdio_irq;
unsigned char bus_mode;
#define DAVINCI_MMC_DATADIR_NONE 0
@@ -184,6 +192,7 @@ struct mmc_davinci_host {
u32 rxdma, txdma;
bool use_dma;
bool do_dma;
+ bool sdio_int;
/* Scatterlist DMA uses one or more parameter RAM entries:
* the main one (associated with rxdma or txdma) plus zero or
@@ -480,7 +489,7 @@ static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
struct scatterlist *sg;
unsigned sg_len;
unsigned bytes_left = host->bytes_left;
- const unsigned shift = ffs(rw_threshold) - 1;;
+ const unsigned shift = ffs(rw_threshold) - 1;
if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
template = &host->tx_template;
@@ -866,6 +875,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
{
host->data = NULL;
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
+ /*
+ * SDIO Interrupt Detection work-around as suggested by
+ * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata
+ * 2.1.6): Signal SDIO interrupt only if it is enabled by core
+ */
+ if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) &
+ SDIOST0_DAT1_HI)) {
+ writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
+ mmc_signal_sdio_irq(host->mmc);
+ }
+ }
+
if (host->do_dma) {
davinci_abort_dma(host);
@@ -932,6 +954,21 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
mmc_davinci_reset_ctrl(host, 0);
}
+static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id)
+{
+ struct mmc_davinci_host *host = dev_id;
+ unsigned int status;
+
+ status = readl(host->base + DAVINCI_SDIOIST);
+ if (status & SDIOIST_IOINT) {
+ dev_dbg(mmc_dev(host->mmc),
+ "SDIO interrupt status %x\n", status);
+ writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
+ mmc_signal_sdio_irq(host->mmc);
+ }
+ return IRQ_HANDLED;
+}
+
static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
{
struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id;
@@ -1076,11 +1113,32 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc)
return config->get_ro(pdev->id);
}
+static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct mmc_davinci_host *host = mmc_priv(mmc);
+
+ if (enable) {
+ if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) {
+ writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
+ mmc_signal_sdio_irq(host->mmc);
+ } else {
+ host->sdio_int = true;
+ writel(readl(host->base + DAVINCI_SDIOIEN) |
+ SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
+ }
+ } else {
+ host->sdio_int = false;
+ writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
+ host->base + DAVINCI_SDIOIEN);
+ }
+}
+
static struct mmc_host_ops mmc_davinci_ops = {
.request = mmc_davinci_request,
.set_ios = mmc_davinci_set_ios,
.get_cd = mmc_davinci_get_cd,
.get_ro = mmc_davinci_get_ro,
+ .enable_sdio_irq = mmc_davinci_enable_sdio_irq,
};
/*----------------------------------------------------------------------*/
@@ -1209,7 +1267,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
host->nr_sg = MAX_NR_SG;
host->use_dma = use_dma;
- host->irq = irq;
+ host->mmc_irq = irq;
+ host->sdio_irq = platform_get_irq(pdev, 1);
if (host->use_dma && davinci_acquire_dma_channels(host) != 0)
host->use_dma = 0;
@@ -1270,6 +1329,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
if (ret)
goto out;
+ if (host->sdio_irq >= 0) {
+ ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0,
+ mmc_hostname(mmc), host);
+ if (!ret)
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ }
+
rename_region(mem, mmc_hostname(mmc));
dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n",
@@ -1313,7 +1379,9 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
mmc_davinci_cpufreq_deregister(host);
mmc_remove_host(host->mmc);
- free_irq(host->irq, host);
+ free_irq(host->mmc_irq, host);
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ free_irq(host->sdio_irq, host);
davinci_release_dma_channels(host);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
new file mode 100644
index 000000000000..2fcc82577c1b
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc.c
@@ -0,0 +1,1796 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ * (Based on NXP driver for lpc 31xx)
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies 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/blkdev.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/bitops.h>
+
+#include "dw_mmc.h"
+
+/* Common flag combinations */
+#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
+ SDMMC_INT_HTO | SDMMC_INT_SBE | \
+ SDMMC_INT_EBE)
+#define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
+ SDMMC_INT_RESP_ERR)
+#define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \
+ DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
+#define DW_MCI_SEND_STATUS 1
+#define DW_MCI_RECV_STATUS 2
+#define DW_MCI_DMA_THRESHOLD 16
+
+#ifdef CONFIG_MMC_DW_IDMAC
+struct idmac_desc {
+ u32 des0; /* Control Descriptor */
+#define IDMAC_DES0_DIC BIT(1)
+#define IDMAC_DES0_LD BIT(2)
+#define IDMAC_DES0_FD BIT(3)
+#define IDMAC_DES0_CH BIT(4)
+#define IDMAC_DES0_ER BIT(5)
+#define IDMAC_DES0_CES BIT(30)
+#define IDMAC_DES0_OWN BIT(31)
+
+ u32 des1; /* Buffer sizes */
+#define IDMAC_SET_BUFFER1_SIZE(d, s) \
+ ((d)->des1 = ((d)->des1 & 0x03ffc000) | ((s) & 0x3fff))
+
+ u32 des2; /* buffer 1 physical address */
+
+ u32 des3; /* buffer 2 physical address */
+};
+#endif /* CONFIG_MMC_DW_IDMAC */
+
+/**
+ * struct dw_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @ctype: Card type for this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ * processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ * &struct dw_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @id: Number of this slot.
+ * @last_detect_state: Most recently observed card detect state.
+ */
+struct dw_mci_slot {
+ struct mmc_host *mmc;
+ struct dw_mci *host;
+
+ u32 ctype;
+
+ struct mmc_request *mrq;
+ struct list_head queue_node;
+
+ unsigned int clock;
+ unsigned long flags;
+#define DW_MMC_CARD_PRESENT 0
+#define DW_MMC_CARD_NEED_INIT 1
+ int id;
+ int last_detect_state;
+};
+
+#if defined(CONFIG_DEBUG_FS)
+static int dw_mci_req_show(struct seq_file *s, void *v)
+{
+ struct dw_mci_slot *slot = s->private;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_command *stop;
+ struct mmc_data *data;
+
+ /* Make sure we get a consistent snapshot */
+ spin_lock_bh(&slot->host->lock);
+ mrq = slot->mrq;
+
+ if (mrq) {
+ cmd = mrq->cmd;
+ data = mrq->data;
+ stop = mrq->stop;
+
+ if (cmd)
+ seq_printf(s,
+ "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+ cmd->opcode, cmd->arg, cmd->flags,
+ cmd->resp[0], cmd->resp[1], cmd->resp[2],
+ cmd->resp[2], cmd->error);
+ if (data)
+ seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
+ data->bytes_xfered, data->blocks,
+ data->blksz, data->flags, data->error);
+ if (stop)
+ seq_printf(s,
+ "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+ stop->opcode, stop->arg, stop->flags,
+ stop->resp[0], stop->resp[1], stop->resp[2],
+ stop->resp[2], stop->error);
+ }
+
+ spin_unlock_bh(&slot->host->lock);
+
+ return 0;
+}
+
+static int dw_mci_req_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dw_mci_req_show, inode->i_private);
+}
+
+static const struct file_operations dw_mci_req_fops = {
+ .owner = THIS_MODULE,
+ .open = dw_mci_req_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dw_mci_regs_show(struct seq_file *s, void *v)
+{
+ seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
+ seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
+ seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
+ seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
+ seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
+ seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
+
+ return 0;
+}
+
+static int dw_mci_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dw_mci_regs_show, inode->i_private);
+}
+
+static const struct file_operations dw_mci_regs_fops = {
+ .owner = THIS_MODULE,
+ .open = dw_mci_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
+{
+ struct mmc_host *mmc = slot->mmc;
+ struct dw_mci *host = slot->host;
+ struct dentry *root;
+ struct dentry *node;
+
+ root = mmc->debugfs_root;
+ if (!root)
+ return;
+
+ node = debugfs_create_file("regs", S_IRUSR, root, host,
+ &dw_mci_regs_fops);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_file("req", S_IRUSR, root, slot,
+ &dw_mci_req_fops);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
+ if (!node)
+ goto err;
+
+ return;
+
+err:
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+}
+#endif /* defined(CONFIG_DEBUG_FS) */
+
+static void dw_mci_set_timeout(struct dw_mci *host)
+{
+ /* timeout (maximum) */
+ mci_writel(host, TMOUT, 0xffffffff);
+}
+
+static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
+{
+ struct mmc_data *data;
+ u32 cmdr;
+ cmd->error = -EINPROGRESS;
+
+ cmdr = cmd->opcode;
+
+ if (cmdr == MMC_STOP_TRANSMISSION)
+ cmdr |= SDMMC_CMD_STOP;
+ else
+ cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ /* We expect a response, so set this bit */
+ cmdr |= SDMMC_CMD_RESP_EXP;
+ if (cmd->flags & MMC_RSP_136)
+ cmdr |= SDMMC_CMD_RESP_LONG;
+ }
+
+ if (cmd->flags & MMC_RSP_CRC)
+ cmdr |= SDMMC_CMD_RESP_CRC;
+
+ data = cmd->data;
+ if (data) {
+ cmdr |= SDMMC_CMD_DAT_EXP;
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= SDMMC_CMD_STRM_MODE;
+ if (data->flags & MMC_DATA_WRITE)
+ cmdr |= SDMMC_CMD_DAT_WR;
+ }
+
+ return cmdr;
+}
+
+static void dw_mci_start_command(struct dw_mci *host,
+ struct mmc_command *cmd, u32 cmd_flags)
+{
+ host->cmd = cmd;
+ dev_vdbg(&host->pdev->dev,
+ "start command: ARGR=0x%08x CMDR=0x%08x\n",
+ cmd->arg, cmd_flags);
+
+ mci_writel(host, CMDARG, cmd->arg);
+ wmb();
+
+ mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
+}
+
+static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
+{
+ dw_mci_start_command(host, data->stop, host->stop_cmdr);
+}
+
+/* DMA interface functions */
+static void dw_mci_stop_dma(struct dw_mci *host)
+{
+ if (host->use_dma) {
+ host->dma_ops->stop(host);
+ host->dma_ops->cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
+ set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
+ }
+}
+
+#ifdef CONFIG_MMC_DW_IDMAC
+static void dw_mci_dma_cleanup(struct dw_mci *host)
+{
+ struct mmc_data *data = host->data;
+
+ if (data)
+ dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_WRITE)
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+}
+
+static void dw_mci_idmac_stop_dma(struct dw_mci *host)
+{
+ u32 temp;
+
+ /* Disable and reset the IDMAC interface */
+ temp = mci_readl(host, CTRL);
+ temp &= ~SDMMC_CTRL_USE_IDMAC;
+ temp |= SDMMC_CTRL_DMA_RESET;
+ mci_writel(host, CTRL, temp);
+
+ /* Stop the IDMAC running */
+ temp = mci_readl(host, BMOD);
+ temp &= ~SDMMC_IDMAC_ENABLE;
+ mci_writel(host, BMOD, temp);
+}
+
+static void dw_mci_idmac_complete_dma(struct dw_mci *host)
+{
+ struct mmc_data *data = host->data;
+
+ dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+ host->dma_ops->cleanup(host);
+
+ /*
+ * If the card was removed, data will be NULL. No point in trying to
+ * send the stop command or waiting for NBUSY in this case.
+ */
+ if (data) {
+ set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+}
+
+static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
+ unsigned int sg_len)
+{
+ int i;
+ struct idmac_desc *desc = host->sg_cpu;
+
+ for (i = 0; i < sg_len; i++, desc++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ u32 mem_addr = sg_dma_address(&data->sg[i]);
+
+ /* Set the OWN bit and disable interrupts for this descriptor */
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
+
+ /* Buffer length */
+ IDMAC_SET_BUFFER1_SIZE(desc, length);
+
+ /* Physical address to DMA to/from */
+ desc->des2 = mem_addr;
+ }
+
+ /* Set first descriptor */
+ desc = host->sg_cpu;
+ desc->des0 |= IDMAC_DES0_FD;
+
+ /* Set last descriptor */
+ desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
+ desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+ desc->des0 |= IDMAC_DES0_LD;
+
+ wmb();
+}
+
+static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
+{
+ u32 temp;
+
+ dw_mci_translate_sglist(host, host->data, sg_len);
+
+ /* Select IDMAC interface */
+ temp = mci_readl(host, CTRL);
+ temp |= SDMMC_CTRL_USE_IDMAC;
+ mci_writel(host, CTRL, temp);
+
+ wmb();
+
+ /* Enable the IDMAC */
+ temp = mci_readl(host, BMOD);
+ temp |= SDMMC_IDMAC_ENABLE;
+ mci_writel(host, BMOD, temp);
+
+ /* Start it running */
+ mci_writel(host, PLDMND, 1);
+}
+
+static int dw_mci_idmac_init(struct dw_mci *host)
+{
+ struct idmac_desc *p;
+ int i;
+
+ /* Number of descriptors in the ring buffer */
+ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
+
+ /* Forward link the descriptor list */
+ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
+ p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
+
+ /* Set the last descriptor as the end-of-ring descriptor */
+ p->des3 = host->sg_dma;
+ p->des0 = IDMAC_DES0_ER;
+
+ /* Mask out interrupts - get Tx & Rx complete only */
+ mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
+ SDMMC_IDMAC_INT_TI);
+
+ /* Set the descriptor base address */
+ mci_writel(host, DBADDR, host->sg_dma);
+ return 0;
+}
+
+static struct dw_mci_dma_ops dw_mci_idmac_ops = {
+ .init = dw_mci_idmac_init,
+ .start = dw_mci_idmac_start_dma,
+ .stop = dw_mci_idmac_stop_dma,
+ .complete = dw_mci_idmac_complete_dma,
+ .cleanup = dw_mci_dma_cleanup,
+};
+#endif /* CONFIG_MMC_DW_IDMAC */
+
+static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+{
+ struct scatterlist *sg;
+ unsigned int i, direction, sg_len;
+ u32 temp;
+
+ /* If we don't have a channel, we can't do DMA */
+ if (!host->use_dma)
+ return -ENODEV;
+
+ /*
+ * We don't do DMA on "complex" transfers, i.e. with
+ * non-word-aligned buffers or lengths. Also, we don't bother
+ * with all the DMA setup overhead for short transfers.
+ */
+ if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
+ return -EINVAL;
+ if (data->blksz & 3)
+ return -EINVAL;
+
+ for_each_sg(data->sg, sg, data->sg_len, i) {
+ if (sg->offset & 3 || sg->length & 3)
+ return -EINVAL;
+ }
+
+ if (data->flags & MMC_DATA_READ)
+ direction = DMA_FROM_DEVICE;
+ else
+ direction = DMA_TO_DEVICE;
+
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
+ direction);
+
+ dev_vdbg(&host->pdev->dev,
+ "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
+ (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
+ sg_len);
+
+ /* Enable the DMA interface */
+ temp = mci_readl(host, CTRL);
+ temp |= SDMMC_CTRL_DMA_ENABLE;
+ mci_writel(host, CTRL, temp);
+
+ /* Disable RX/TX IRQs, let DMA handle it */
+ temp = mci_readl(host, INTMASK);
+ temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
+ mci_writel(host, INTMASK, temp);
+
+ host->dma_ops->start(host, sg_len);
+
+ return 0;
+}
+
+static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
+{
+ u32 temp;
+
+ data->error = -EINPROGRESS;
+
+ WARN_ON(host->data);
+ host->sg = NULL;
+ host->data = data;
+
+ if (dw_mci_submit_data_dma(host, data)) {
+ host->sg = data->sg;
+ host->pio_offset = 0;
+ if (data->flags & MMC_DATA_READ)
+ host->dir_status = DW_MCI_RECV_STATUS;
+ else
+ host->dir_status = DW_MCI_SEND_STATUS;
+
+ temp = mci_readl(host, INTMASK);
+ temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
+ mci_writel(host, INTMASK, temp);
+
+ temp = mci_readl(host, CTRL);
+ temp &= ~SDMMC_CTRL_DMA_ENABLE;
+ mci_writel(host, CTRL, temp);
+ }
+}
+
+static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
+{
+ struct dw_mci *host = slot->host;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ unsigned int cmd_status = 0;
+
+ mci_writel(host, CMDARG, arg);
+ wmb();
+ mci_writel(host, CMD, SDMMC_CMD_START | cmd);
+
+ while (time_before(jiffies, timeout)) {
+ cmd_status = mci_readl(host, CMD);
+ if (!(cmd_status & SDMMC_CMD_START))
+ return;
+ }
+ dev_err(&slot->mmc->class_dev,
+ "Timeout sending command (cmd %#x arg %#x status %#x)\n",
+ cmd, arg, cmd_status);
+}
+
+static void dw_mci_setup_bus(struct dw_mci_slot *slot)
+{
+ struct dw_mci *host = slot->host;
+ u32 div;
+
+ if (slot->clock != host->current_speed) {
+ if (host->bus_hz % slot->clock)
+ /*
+ * move the + 1 after the divide to prevent
+ * over-clocking the card.
+ */
+ div = ((host->bus_hz / slot->clock) >> 1) + 1;
+ else
+ div = (host->bus_hz / slot->clock) >> 1;
+
+ dev_info(&slot->mmc->class_dev,
+ "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ"
+ " div = %d)\n", slot->id, host->bus_hz, slot->clock,
+ div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div);
+
+ /* disable clock */
+ mci_writel(host, CLKENA, 0);
+ mci_writel(host, CLKSRC, 0);
+
+ /* inform CIU */
+ mci_send_cmd(slot,
+ SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+
+ /* set clock to desired speed */
+ mci_writel(host, CLKDIV, div);
+
+ /* inform CIU */
+ mci_send_cmd(slot,
+ SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+
+ /* enable clock */
+ mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE);
+
+ /* inform CIU */
+ mci_send_cmd(slot,
+ SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+
+ host->current_speed = slot->clock;
+ }
+
+ /* Set the current slot bus width */
+ mci_writel(host, CTYPE, slot->ctype);
+}
+
+static void dw_mci_start_request(struct dw_mci *host,
+ struct dw_mci_slot *slot)
+{
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 cmdflags;
+
+ mrq = slot->mrq;
+ if (host->pdata->select_slot)
+ host->pdata->select_slot(slot->id);
+
+ /* Slot specific timing and width adjustment */
+ dw_mci_setup_bus(slot);
+
+ host->cur_slot = slot;
+ host->mrq = mrq;
+
+ host->pending_events = 0;
+ host->completed_events = 0;
+ host->data_status = 0;
+
+ data = mrq->data;
+ if (data) {
+ dw_mci_set_timeout(host);
+ mci_writel(host, BYTCNT, data->blksz*data->blocks);
+ mci_writel(host, BLKSIZ, data->blksz);
+ }
+
+ cmd = mrq->cmd;
+ cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
+
+ /* this is the first command, send the initialization clock */
+ if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
+ cmdflags |= SDMMC_CMD_INIT;
+
+ if (data) {
+ dw_mci_submit_data(host, data);
+ wmb();
+ }
+
+ dw_mci_start_command(host, cmd, cmdflags);
+
+ if (mrq->stop)
+ host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
+}
+
+static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
+ struct mmc_request *mrq)
+{
+ dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+ host->state);
+
+ spin_lock_bh(&host->lock);
+ slot->mrq = mrq;
+
+ if (host->state == STATE_IDLE) {
+ host->state = STATE_SENDING_CMD;
+ dw_mci_start_request(host, slot);
+ } else {
+ list_add_tail(&slot->queue_node, &host->queue);
+ }
+
+ spin_unlock_bh(&host->lock);
+}
+
+static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+
+ WARN_ON(slot->mrq);
+
+ if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ /* We don't support multiple blocks of weird lengths. */
+ dw_mci_queue_request(host, slot, mrq);
+}
+
+static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+
+ /* set default 1 bit mode */
+ slot->ctype = SDMMC_CTYPE_1BIT;
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ slot->ctype = SDMMC_CTYPE_1BIT;
+ break;
+ case MMC_BUS_WIDTH_4:
+ slot->ctype = SDMMC_CTYPE_4BIT;
+ break;
+ }
+
+ if (ios->clock) {
+ /*
+ * Use mirror of ios->clock to prevent race with mmc
+ * core ios update when finding the minimum.
+ */
+ slot->clock = ios->clock;
+ }
+
+ switch (ios->power_mode) {
+ case MMC_POWER_UP:
+ set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
+ break;
+ default:
+ break;
+ }
+}
+
+static int dw_mci_get_ro(struct mmc_host *mmc)
+{
+ int read_only;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci_board *brd = slot->host->pdata;
+
+ /* Use platform get_ro function, else try on board write protect */
+ if (brd->get_ro)
+ read_only = brd->get_ro(slot->id);
+ else
+ read_only =
+ mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
+
+ dev_dbg(&mmc->class_dev, "card is %s\n",
+ read_only ? "read-only" : "read-write");
+
+ return read_only;
+}
+
+static int dw_mci_get_cd(struct mmc_host *mmc)
+{
+ int present;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci_board *brd = slot->host->pdata;
+
+ /* Use platform get_cd function, else try onboard card detect */
+ if (brd->get_cd)
+ present = !brd->get_cd(slot->id);
+ else
+ present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
+ == 0 ? 1 : 0;
+
+ if (present)
+ dev_dbg(&mmc->class_dev, "card is present\n");
+ else
+ dev_dbg(&mmc->class_dev, "card is not present\n");
+
+ return present;
+}
+
+static const struct mmc_host_ops dw_mci_ops = {
+ .request = dw_mci_request,
+ .set_ios = dw_mci_set_ios,
+ .get_ro = dw_mci_get_ro,
+ .get_cd = dw_mci_get_cd,
+};
+
+static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
+ __releases(&host->lock)
+ __acquires(&host->lock)
+{
+ struct dw_mci_slot *slot;
+ struct mmc_host *prev_mmc = host->cur_slot->mmc;
+
+ WARN_ON(host->cmd || host->data);
+
+ host->cur_slot->mrq = NULL;
+ host->mrq = NULL;
+ if (!list_empty(&host->queue)) {
+ slot = list_entry(host->queue.next,
+ struct dw_mci_slot, queue_node);
+ list_del(&slot->queue_node);
+ dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+ mmc_hostname(slot->mmc));
+ host->state = STATE_SENDING_CMD;
+ dw_mci_start_request(host, slot);
+ } else {
+ dev_vdbg(&host->pdev->dev, "list empty\n");
+ host->state = STATE_IDLE;
+ }
+
+ spin_unlock(&host->lock);
+ mmc_request_done(prev_mmc, mrq);
+ spin_lock(&host->lock);
+}
+
+static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
+{
+ u32 status = host->cmd_status;
+
+ host->cmd_status = 0;
+
+ /* Read the response from the card (up to 16 bytes) */
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136) {
+ cmd->resp[3] = mci_readl(host, RESP0);
+ cmd->resp[2] = mci_readl(host, RESP1);
+ cmd->resp[1] = mci_readl(host, RESP2);
+ cmd->resp[0] = mci_readl(host, RESP3);
+ } else {
+ cmd->resp[0] = mci_readl(host, RESP0);
+ cmd->resp[1] = 0;
+ cmd->resp[2] = 0;
+ cmd->resp[3] = 0;
+ }
+ }
+
+ if (status & SDMMC_INT_RTO)
+ cmd->error = -ETIMEDOUT;
+ else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
+ cmd->error = -EILSEQ;
+ else if (status & SDMMC_INT_RESP_ERR)
+ cmd->error = -EIO;
+ else
+ cmd->error = 0;
+
+ if (cmd->error) {
+ /* newer ip versions need a delay between retries */
+ if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
+ mdelay(20);
+
+ if (cmd->data) {
+ host->data = NULL;
+ dw_mci_stop_dma(host);
+ }
+ }
+}
+
+static void dw_mci_tasklet_func(unsigned long priv)
+{
+ struct dw_mci *host = (struct dw_mci *)priv;
+ struct mmc_data *data;
+ struct mmc_command *cmd;
+ enum dw_mci_state state;
+ enum dw_mci_state prev_state;
+ u32 status;
+
+ spin_lock(&host->lock);
+
+ state = host->state;
+ data = host->data;
+
+ do {
+ prev_state = state;
+
+ switch (state) {
+ case STATE_IDLE:
+ break;
+
+ case STATE_SENDING_CMD:
+ if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
+ &host->pending_events))
+ break;
+
+ cmd = host->cmd;
+ host->cmd = NULL;
+ set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
+ dw_mci_command_complete(host, host->mrq->cmd);
+ if (!host->mrq->data || cmd->error) {
+ dw_mci_request_end(host, host->mrq);
+ goto unlock;
+ }
+
+ prev_state = state = STATE_SENDING_DATA;
+ /* fall through */
+
+ case STATE_SENDING_DATA:
+ if (test_and_clear_bit(EVENT_DATA_ERROR,
+ &host->pending_events)) {
+ dw_mci_stop_dma(host);
+ if (data->stop)
+ send_stop_cmd(host, data);
+ state = STATE_DATA_ERROR;
+ break;
+ }
+
+ if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
+ &host->pending_events))
+ break;
+
+ set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
+ prev_state = state = STATE_DATA_BUSY;
+ /* fall through */
+
+ case STATE_DATA_BUSY:
+ if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
+ &host->pending_events))
+ break;
+
+ host->data = NULL;
+ set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
+ status = host->data_status;
+
+ if (status & DW_MCI_DATA_ERROR_FLAGS) {
+ if (status & SDMMC_INT_DTO) {
+ dev_err(&host->pdev->dev,
+ "data timeout error\n");
+ data->error = -ETIMEDOUT;
+ } else if (status & SDMMC_INT_DCRC) {
+ dev_err(&host->pdev->dev,
+ "data CRC error\n");
+ data->error = -EILSEQ;
+ } else {
+ dev_err(&host->pdev->dev,
+ "data FIFO error "
+ "(status=%08x)\n",
+ status);
+ data->error = -EIO;
+ }
+ } else {
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ }
+
+ if (!data->stop) {
+ dw_mci_request_end(host, host->mrq);
+ goto unlock;
+ }
+
+ prev_state = state = STATE_SENDING_STOP;
+ if (!data->error)
+ send_stop_cmd(host, data);
+ /* fall through */
+
+ case STATE_SENDING_STOP:
+ if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
+ &host->pending_events))
+ break;
+
+ host->cmd = NULL;
+ dw_mci_command_complete(host, host->mrq->stop);
+ dw_mci_request_end(host, host->mrq);
+ goto unlock;
+
+ case STATE_DATA_ERROR:
+ if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
+ &host->pending_events))
+ break;
+
+ state = STATE_DATA_BUSY;
+ break;
+ }
+ } while (state != prev_state);
+
+ host->state = state;
+unlock:
+ spin_unlock(&host->lock);
+
+}
+
+static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
+{
+ u16 *pdata = (u16 *)buf;
+
+ WARN_ON(cnt % 2 != 0);
+
+ cnt = cnt >> 1;
+ while (cnt > 0) {
+ mci_writew(host, DATA, *pdata++);
+ cnt--;
+ }
+}
+
+static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
+{
+ u16 *pdata = (u16 *)buf;
+
+ WARN_ON(cnt % 2 != 0);
+
+ cnt = cnt >> 1;
+ while (cnt > 0) {
+ *pdata++ = mci_readw(host, DATA);
+ cnt--;
+ }
+}
+
+static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
+{
+ u32 *pdata = (u32 *)buf;
+
+ WARN_ON(cnt % 4 != 0);
+ WARN_ON((unsigned long)pdata & 0x3);
+
+ cnt = cnt >> 2;
+ while (cnt > 0) {
+ mci_writel(host, DATA, *pdata++);
+ cnt--;
+ }
+}
+
+static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
+{
+ u32 *pdata = (u32 *)buf;
+
+ WARN_ON(cnt % 4 != 0);
+ WARN_ON((unsigned long)pdata & 0x3);
+
+ cnt = cnt >> 2;
+ while (cnt > 0) {
+ *pdata++ = mci_readl(host, DATA);
+ cnt--;
+ }
+}
+
+static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
+{
+ u64 *pdata = (u64 *)buf;
+
+ WARN_ON(cnt % 8 != 0);
+
+ cnt = cnt >> 3;
+ while (cnt > 0) {
+ mci_writeq(host, DATA, *pdata++);
+ cnt--;
+ }
+}
+
+static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
+{
+ u64 *pdata = (u64 *)buf;
+
+ WARN_ON(cnt % 8 != 0);
+
+ cnt = cnt >> 3;
+ while (cnt > 0) {
+ *pdata++ = mci_readq(host, DATA);
+ cnt--;
+ }
+}
+
+static void dw_mci_read_data_pio(struct dw_mci *host)
+{
+ struct scatterlist *sg = host->sg;
+ void *buf = sg_virt(sg);
+ unsigned int offset = host->pio_offset;
+ struct mmc_data *data = host->data;
+ int shift = host->data_shift;
+ u32 status;
+ unsigned int nbytes = 0, len, old_len, count = 0;
+
+ do {
+ len = SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift;
+ if (count == 0)
+ old_len = len;
+
+ if (offset + len <= sg->length) {
+ host->pull_data(host, (void *)(buf + offset), len);
+
+ offset += len;
+ nbytes += len;
+
+ if (offset == sg->length) {
+ flush_dcache_page(sg_page(sg));
+ host->sg = sg = sg_next(sg);
+ if (!sg)
+ goto done;
+
+ offset = 0;
+ buf = sg_virt(sg);
+ }
+ } else {
+ unsigned int remaining = sg->length - offset;
+ host->pull_data(host, (void *)(buf + offset),
+ remaining);
+ nbytes += remaining;
+
+ flush_dcache_page(sg_page(sg));
+ host->sg = sg = sg_next(sg);
+ if (!sg)
+ goto done;
+
+ offset = len - remaining;
+ buf = sg_virt(sg);
+ host->pull_data(host, buf, offset);
+ nbytes += offset;
+ }
+
+ status = mci_readl(host, MINTSTS);
+ mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
+ if (status & DW_MCI_DATA_ERROR_FLAGS) {
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+ smp_wmb();
+
+ set_bit(EVENT_DATA_ERROR, &host->pending_events);
+
+ tasklet_schedule(&host->tasklet);
+ return;
+ }
+ count++;
+ } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
+ len = SDMMC_GET_FCNT(mci_readl(host, STATUS));
+ host->pio_offset = offset;
+ data->bytes_xfered += nbytes;
+ return;
+
+done:
+ data->bytes_xfered += nbytes;
+ smp_wmb();
+ set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
+}
+
+static void dw_mci_write_data_pio(struct dw_mci *host)
+{
+ struct scatterlist *sg = host->sg;
+ void *buf = sg_virt(sg);
+ unsigned int offset = host->pio_offset;
+ struct mmc_data *data = host->data;
+ int shift = host->data_shift;
+ u32 status;
+ unsigned int nbytes = 0, len;
+
+ do {
+ len = SDMMC_FIFO_SZ -
+ (SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift);
+ if (offset + len <= sg->length) {
+ host->push_data(host, (void *)(buf + offset), len);
+
+ offset += len;
+ nbytes += len;
+ if (offset == sg->length) {
+ host->sg = sg = sg_next(sg);
+ if (!sg)
+ goto done;
+
+ offset = 0;
+ buf = sg_virt(sg);
+ }
+ } else {
+ unsigned int remaining = sg->length - offset;
+
+ host->push_data(host, (void *)(buf + offset),
+ remaining);
+ nbytes += remaining;
+
+ host->sg = sg = sg_next(sg);
+ if (!sg)
+ goto done;
+
+ offset = len - remaining;
+ buf = sg_virt(sg);
+ host->push_data(host, (void *)buf, offset);
+ nbytes += offset;
+ }
+
+ status = mci_readl(host, MINTSTS);
+ mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
+ if (status & DW_MCI_DATA_ERROR_FLAGS) {
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+
+ smp_wmb();
+
+ set_bit(EVENT_DATA_ERROR, &host->pending_events);
+
+ tasklet_schedule(&host->tasklet);
+ return;
+ }
+ } while (status & SDMMC_INT_TXDR); /* if TXDR write again */
+
+ host->pio_offset = offset;
+ data->bytes_xfered += nbytes;
+
+ return;
+
+done:
+ data->bytes_xfered += nbytes;
+ smp_wmb();
+ set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
+}
+
+static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
+{
+ if (!host->cmd_status)
+ host->cmd_status = status;
+
+ smp_wmb();
+
+ set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
+{
+ struct dw_mci *host = dev_id;
+ u32 status, pending;
+ unsigned int pass_count = 0;
+
+ do {
+ status = mci_readl(host, RINTSTS);
+ pending = mci_readl(host, MINTSTS); /* read-only mask reg */
+
+ /*
+ * DTO fix - version 2.10a and below, and only if internal DMA
+ * is configured.
+ */
+ if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
+ if (!pending &&
+ ((mci_readl(host, STATUS) >> 17) & 0x1fff))
+ pending |= SDMMC_INT_DATA_OVER;
+ }
+
+ if (!pending)
+ break;
+
+ if (pending & DW_MCI_CMD_ERROR_FLAGS) {
+ mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
+ host->cmd_status = status;
+ smp_wmb();
+ set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & DW_MCI_DATA_ERROR_FLAGS) {
+ /* if there is an error report DATA_ERROR */
+ mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
+ host->data_status = status;
+ smp_wmb();
+ set_bit(EVENT_DATA_ERROR, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & SDMMC_INT_DATA_OVER) {
+ mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
+ if (!host->data_status)
+ host->data_status = status;
+ smp_wmb();
+ if (host->dir_status == DW_MCI_RECV_STATUS) {
+ if (host->sg != NULL)
+ dw_mci_read_data_pio(host);
+ }
+ set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & SDMMC_INT_RXDR) {
+ mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
+ if (host->sg)
+ dw_mci_read_data_pio(host);
+ }
+
+ if (pending & SDMMC_INT_TXDR) {
+ mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
+ if (host->sg)
+ dw_mci_write_data_pio(host);
+ }
+
+ if (pending & SDMMC_INT_CMD_DONE) {
+ mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
+ dw_mci_cmd_interrupt(host, status);
+ }
+
+ if (pending & SDMMC_INT_CD) {
+ mci_writel(host, RINTSTS, SDMMC_INT_CD);
+ tasklet_schedule(&host->card_tasklet);
+ }
+
+ } while (pass_count++ < 5);
+
+#ifdef CONFIG_MMC_DW_IDMAC
+ /* Handle DMA interrupts */
+ pending = mci_readl(host, IDSTS);
+ if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
+ set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+ host->dma_ops->complete(host);
+ }
+#endif
+
+ return IRQ_HANDLED;
+}
+
+static void dw_mci_tasklet_card(unsigned long data)
+{
+ struct dw_mci *host = (struct dw_mci *)data;
+ int i;
+
+ for (i = 0; i < host->num_slots; i++) {
+ struct dw_mci_slot *slot = host->slot[i];
+ struct mmc_host *mmc = slot->mmc;
+ struct mmc_request *mrq;
+ int present;
+ u32 ctrl;
+
+ present = dw_mci_get_cd(mmc);
+ while (present != slot->last_detect_state) {
+ spin_lock(&host->lock);
+
+ dev_dbg(&slot->mmc->class_dev, "card %s\n",
+ present ? "inserted" : "removed");
+
+ /* Card change detected */
+ slot->last_detect_state = present;
+
+ /* Power up slot */
+ if (present != 0) {
+ if (host->pdata->setpower)
+ host->pdata->setpower(slot->id,
+ mmc->ocr_avail);
+
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+ }
+
+ /* Clean up queue if present */
+ mrq = slot->mrq;
+ if (mrq) {
+ if (mrq == host->mrq) {
+ host->data = NULL;
+ host->cmd = NULL;
+
+ switch (host->state) {
+ case STATE_IDLE:
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+ if (!mrq->data)
+ break;
+ /* fall through */
+ case STATE_SENDING_DATA:
+ mrq->data->error = -ENOMEDIUM;
+ dw_mci_stop_dma(host);
+ break;
+ case STATE_DATA_BUSY:
+ case STATE_DATA_ERROR:
+ if (mrq->data->error == -EINPROGRESS)
+ mrq->data->error = -ENOMEDIUM;
+ if (!mrq->stop)
+ break;
+ /* fall through */
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
+ }
+
+ dw_mci_request_end(host, mrq);
+ } else {
+ list_del(&slot->queue_node);
+ mrq->cmd->error = -ENOMEDIUM;
+ if (mrq->data)
+ mrq->data->error = -ENOMEDIUM;
+ if (mrq->stop)
+ mrq->stop->error = -ENOMEDIUM;
+
+ spin_unlock(&host->lock);
+ mmc_request_done(slot->mmc, mrq);
+ spin_lock(&host->lock);
+ }
+ }
+
+ /* Power down slot */
+ if (present == 0) {
+ if (host->pdata->setpower)
+ host->pdata->setpower(slot->id, 0);
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+
+ /*
+ * Clear down the FIFO - doing so generates a
+ * block interrupt, hence setting the
+ * scatter-gather pointer to NULL.
+ */
+ host->sg = NULL;
+
+ ctrl = mci_readl(host, CTRL);
+ ctrl |= SDMMC_CTRL_FIFO_RESET;
+ mci_writel(host, CTRL, ctrl);
+
+#ifdef CONFIG_MMC_DW_IDMAC
+ ctrl = mci_readl(host, BMOD);
+ ctrl |= 0x01; /* Software reset of DMA */
+ mci_writel(host, BMOD, ctrl);
+#endif
+
+ }
+
+ spin_unlock(&host->lock);
+ present = dw_mci_get_cd(mmc);
+ }
+
+ mmc_detect_change(slot->mmc,
+ msecs_to_jiffies(host->pdata->detect_delay_ms));
+ }
+}
+
+static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
+{
+ struct mmc_host *mmc;
+ struct dw_mci_slot *slot;
+
+ mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ slot = mmc_priv(mmc);
+ slot->id = id;
+ slot->mmc = mmc;
+ slot->host = host;
+
+ mmc->ops = &dw_mci_ops;
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
+ mmc->f_max = host->bus_hz;
+
+ if (host->pdata->get_ocr)
+ mmc->ocr_avail = host->pdata->get_ocr(id);
+ else
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ /*
+ * Start with slot power disabled, it will be enabled when a card
+ * is detected.
+ */
+ if (host->pdata->setpower)
+ host->pdata->setpower(id, 0);
+
+ mmc->caps = 0;
+ if (host->pdata->get_bus_wd)
+ if (host->pdata->get_bus_wd(slot->id) >= 4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+
+#ifdef CONFIG_MMC_DW_IDMAC
+ mmc->max_segs = host->ring_size;
+ mmc->max_blk_size = 65536;
+ mmc->max_blk_count = host->ring_size;
+ mmc->max_seg_size = 0x1000;
+ mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+#else
+ if (host->pdata->blk_settings) {
+ mmc->max_segs = host->pdata->blk_settings->max_segs;
+ mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
+ mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
+ mmc->max_req_size = host->pdata->blk_settings->max_req_size;
+ mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
+ } else {
+ /* Useful defaults if platform data is unset. */
+ mmc->max_segs = 64;
+ mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
+ mmc->max_blk_count = 512;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+ }
+#endif /* CONFIG_MMC_DW_IDMAC */
+
+ if (dw_mci_get_cd(mmc))
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+ else
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+
+ host->slot[id] = slot;
+ mmc_add_host(mmc);
+
+#if defined(CONFIG_DEBUG_FS)
+ dw_mci_init_debugfs(slot);
+#endif
+
+ /* Card initially undetected */
+ slot->last_detect_state = 0;
+
+ return 0;
+}
+
+static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
+{
+ /* Shutdown detect IRQ */
+ if (slot->host->pdata->exit)
+ slot->host->pdata->exit(id);
+
+ /* Debugfs stuff is cleaned up by mmc core */
+ mmc_remove_host(slot->mmc);
+ slot->host->slot[id] = NULL;
+ mmc_free_host(slot->mmc);
+}
+
+static void dw_mci_init_dma(struct dw_mci *host)
+{
+ /* Alloc memory for sg translation */
+ host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE,
+ &host->sg_dma, GFP_KERNEL);
+ if (!host->sg_cpu) {
+ dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n",
+ __func__);
+ goto no_dma;
+ }
+
+ /* Determine which DMA interface to use */
+#ifdef CONFIG_MMC_DW_IDMAC
+ host->dma_ops = &dw_mci_idmac_ops;
+ dev_info(&host->pdev->dev, "Using internal DMA controller.\n");
+#endif
+
+ if (!host->dma_ops)
+ goto no_dma;
+
+ if (host->dma_ops->init) {
+ if (host->dma_ops->init(host)) {
+ dev_err(&host->pdev->dev, "%s: Unable to initialize "
+ "DMA Controller.\n", __func__);
+ goto no_dma;
+ }
+ } else {
+ dev_err(&host->pdev->dev, "DMA initialization not found.\n");
+ goto no_dma;
+ }
+
+ host->use_dma = 1;
+ return;
+
+no_dma:
+ dev_info(&host->pdev->dev, "Using PIO mode.\n");
+ host->use_dma = 0;
+ return;
+}
+
+static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ unsigned int ctrl;
+
+ mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
+ SDMMC_CTRL_DMA_RESET));
+
+ /* wait till resets clear */
+ do {
+ ctrl = mci_readl(host, CTRL);
+ if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
+ SDMMC_CTRL_DMA_RESET)))
+ return true;
+ } while (time_before(jiffies, timeout));
+
+ dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
+
+ return false;
+}
+
+static int dw_mci_probe(struct platform_device *pdev)
+{
+ struct dw_mci *host;
+ struct resource *regs;
+ struct dw_mci_board *pdata;
+ int irq, ret, i, width;
+ u32 fifo_size;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ host->pdev = pdev;
+ host->pdata = pdata = pdev->dev.platform_data;
+ if (!pdata || !pdata->init) {
+ dev_err(&pdev->dev,
+ "Platform data must supply init function\n");
+ ret = -ENODEV;
+ goto err_freehost;
+ }
+
+ if (!pdata->select_slot && pdata->num_slots > 1) {
+ dev_err(&pdev->dev,
+ "Platform data must supply select_slot function\n");
+ ret = -ENODEV;
+ goto err_freehost;
+ }
+
+ if (!pdata->bus_hz) {
+ dev_err(&pdev->dev,
+ "Platform data must supply bus speed\n");
+ ret = -ENODEV;
+ goto err_freehost;
+ }
+
+ host->bus_hz = pdata->bus_hz;
+ host->quirks = pdata->quirks;
+
+ spin_lock_init(&host->lock);
+ INIT_LIST_HEAD(&host->queue);
+
+ ret = -ENOMEM;
+ host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!host->regs)
+ goto err_freehost;
+
+ host->dma_ops = pdata->dma_ops;
+ dw_mci_init_dma(host);
+
+ /*
+ * Get the host data width - this assumes that HCON has been set with
+ * the correct values.
+ */
+ i = (mci_readl(host, HCON) >> 7) & 0x7;
+ if (!i) {
+ host->push_data = dw_mci_push_data16;
+ host->pull_data = dw_mci_pull_data16;
+ width = 16;
+ host->data_shift = 1;
+ } else if (i == 2) {
+ host->push_data = dw_mci_push_data64;
+ host->pull_data = dw_mci_pull_data64;
+ width = 64;
+ host->data_shift = 3;
+ } else {
+ /* Check for a reserved value, and warn if it is */
+ WARN((i != 1),
+ "HCON reports a reserved host data width!\n"
+ "Defaulting to 32-bit access.\n");
+ host->push_data = dw_mci_push_data32;
+ host->pull_data = dw_mci_pull_data32;
+ width = 32;
+ host->data_shift = 2;
+ }
+
+ /* Reset all blocks */
+ if (!mci_wait_reset(&pdev->dev, host)) {
+ ret = -ENODEV;
+ goto err_dmaunmap;
+ }
+
+ /* Clear the interrupts for the host controller */
+ mci_writel(host, RINTSTS, 0xFFFFFFFF);
+ mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
+
+ /* Put in max timeout */
+ mci_writel(host, TMOUT, 0xFFFFFFFF);
+
+ /*
+ * FIFO threshold settings RxMark = fifo_size / 2 - 1,
+ * Tx Mark = fifo_size / 2 DMA Size = 8
+ */
+ fifo_size = mci_readl(host, FIFOTH);
+ fifo_size = (fifo_size >> 16) & 0x7ff;
+ mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+ ((fifo_size/2) << 0)));
+
+ /* disable clock to CIU */
+ mci_writel(host, CLKENA, 0);
+ mci_writel(host, CLKSRC, 0);
+
+ tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
+ tasklet_init(&host->card_tasklet,
+ dw_mci_tasklet_card, (unsigned long)host);
+
+ ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+ if (ret)
+ goto err_dmaunmap;
+
+ platform_set_drvdata(pdev, host);
+
+ if (host->pdata->num_slots)
+ host->num_slots = host->pdata->num_slots;
+ else
+ host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
+
+ /* We need at least one slot to succeed */
+ for (i = 0; i < host->num_slots; i++) {
+ ret = dw_mci_init_slot(host, i);
+ if (ret) {
+ ret = -ENODEV;
+ goto err_init_slot;
+ }
+ }
+
+ /*
+ * Enable interrupts for command done, data over, data empty, card det,
+ * receive ready and error such as transmit, receive timeout, crc error
+ */
+ mci_writel(host, RINTSTS, 0xFFFFFFFF);
+ mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
+ SDMMC_INT_TXDR | SDMMC_INT_RXDR |
+ DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+ mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
+
+ dev_info(&pdev->dev, "DW MMC controller at irq %d, "
+ "%d bit host data width\n", irq, width);
+ if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
+ dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n");
+
+ return 0;
+
+err_init_slot:
+ /* De-init any initialized slots */
+ while (i > 0) {
+ if (host->slot[i])
+ dw_mci_cleanup_slot(host->slot[i], i);
+ i--;
+ }
+ free_irq(irq, host);
+
+err_dmaunmap:
+ if (host->use_dma && host->dma_ops->exit)
+ host->dma_ops->exit(host);
+ dma_free_coherent(&host->pdev->dev, PAGE_SIZE,
+ host->sg_cpu, host->sg_dma);
+ iounmap(host->regs);
+
+err_freehost:
+ kfree(host);
+ return ret;
+}
+
+static int __exit dw_mci_remove(struct platform_device *pdev)
+{
+ struct dw_mci *host = platform_get_drvdata(pdev);
+ int i;
+
+ mci_writel(host, RINTSTS, 0xFFFFFFFF);
+ mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
+
+ platform_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < host->num_slots; i++) {
+ dev_dbg(&pdev->dev, "remove slot %d\n", i);
+ if (host->slot[i])
+ dw_mci_cleanup_slot(host->slot[i], i);
+ }
+
+ /* disable clock to CIU */
+ mci_writel(host, CLKENA, 0);
+ mci_writel(host, CLKSRC, 0);
+
+ free_irq(platform_get_irq(pdev, 0), host);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+
+ if (host->use_dma && host->dma_ops->exit)
+ host->dma_ops->exit(host);
+
+ iounmap(host->regs);
+
+ kfree(host);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * TODO: we should probably disable the clock to the card in the suspend path.
+ */
+static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int i, ret;
+ struct dw_mci *host = platform_get_drvdata(pdev);
+
+ for (i = 0; i < host->num_slots; i++) {
+ struct dw_mci_slot *slot = host->slot[i];
+ if (!slot)
+ continue;
+ ret = mmc_suspend_host(slot->mmc);
+ if (ret < 0) {
+ while (--i >= 0) {
+ slot = host->slot[i];
+ if (slot)
+ mmc_resume_host(host->slot[i]->mmc);
+ }
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int dw_mci_resume(struct platform_device *pdev)
+{
+ int i, ret;
+ struct dw_mci *host = platform_get_drvdata(pdev);
+
+ for (i = 0; i < host->num_slots; i++) {
+ struct dw_mci_slot *slot = host->slot[i];
+ if (!slot)
+ continue;
+ ret = mmc_resume_host(host->slot[i]->mmc);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+#else
+#define dw_mci_suspend NULL
+#define dw_mci_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dw_mci_driver = {
+ .remove = __exit_p(dw_mci_remove),
+ .suspend = dw_mci_suspend,
+ .resume = dw_mci_resume,
+ .driver = {
+ .name = "dw_mmc",
+ },
+};
+
+static int __init dw_mci_init(void)
+{
+ return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+}
+
+static void __exit dw_mci_exit(void)
+{
+ platform_driver_unregister(&dw_mci_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
+MODULE_AUTHOR("NXP Semiconductor VietNam");
+MODULE_AUTHOR("Imagination Technologies Ltd");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
new file mode 100644
index 000000000000..5dd55a75233d
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc.h
@@ -0,0 +1,168 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ * (Based on NXP driver for lpc 31xx)
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies 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.
+ */
+
+#ifndef _DW_MMC_H_
+#define _DW_MMC_H_
+
+#define SDMMC_CTRL 0x000
+#define SDMMC_PWREN 0x004
+#define SDMMC_CLKDIV 0x008
+#define SDMMC_CLKSRC 0x00c
+#define SDMMC_CLKENA 0x010
+#define SDMMC_TMOUT 0x014
+#define SDMMC_CTYPE 0x018
+#define SDMMC_BLKSIZ 0x01c
+#define SDMMC_BYTCNT 0x020
+#define SDMMC_INTMASK 0x024
+#define SDMMC_CMDARG 0x028
+#define SDMMC_CMD 0x02c
+#define SDMMC_RESP0 0x030
+#define SDMMC_RESP1 0x034
+#define SDMMC_RESP2 0x038
+#define SDMMC_RESP3 0x03c
+#define SDMMC_MINTSTS 0x040
+#define SDMMC_RINTSTS 0x044
+#define SDMMC_STATUS 0x048
+#define SDMMC_FIFOTH 0x04c
+#define SDMMC_CDETECT 0x050
+#define SDMMC_WRTPRT 0x054
+#define SDMMC_GPIO 0x058
+#define SDMMC_TCBCNT 0x05c
+#define SDMMC_TBBCNT 0x060
+#define SDMMC_DEBNCE 0x064
+#define SDMMC_USRID 0x068
+#define SDMMC_VERID 0x06c
+#define SDMMC_HCON 0x070
+#define SDMMC_BMOD 0x080
+#define SDMMC_PLDMND 0x084
+#define SDMMC_DBADDR 0x088
+#define SDMMC_IDSTS 0x08c
+#define SDMMC_IDINTEN 0x090
+#define SDMMC_DSCADDR 0x094
+#define SDMMC_BUFADDR 0x098
+#define SDMMC_DATA 0x100
+#define SDMMC_DATA_ADR 0x100
+
+/* shift bit field */
+#define _SBF(f, v) ((v) << (f))
+
+/* Control register defines */
+#define SDMMC_CTRL_USE_IDMAC BIT(25)
+#define SDMMC_CTRL_CEATA_INT_EN BIT(11)
+#define SDMMC_CTRL_SEND_AS_CCSD BIT(10)
+#define SDMMC_CTRL_SEND_CCSD BIT(9)
+#define SDMMC_CTRL_ABRT_READ_DATA BIT(8)
+#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7)
+#define SDMMC_CTRL_READ_WAIT BIT(6)
+#define SDMMC_CTRL_DMA_ENABLE BIT(5)
+#define SDMMC_CTRL_INT_ENABLE BIT(4)
+#define SDMMC_CTRL_DMA_RESET BIT(2)
+#define SDMMC_CTRL_FIFO_RESET BIT(1)
+#define SDMMC_CTRL_RESET BIT(0)
+/* Clock Enable register defines */
+#define SDMMC_CLKEN_LOW_PWR BIT(16)
+#define SDMMC_CLKEN_ENABLE BIT(0)
+/* time-out register defines */
+#define SDMMC_TMOUT_DATA(n) _SBF(8, (n))
+#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00
+#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF)
+#define SDMMC_TMOUT_RESP_MSK 0xFF
+/* card-type register defines */
+#define SDMMC_CTYPE_8BIT BIT(16)
+#define SDMMC_CTYPE_4BIT BIT(0)
+#define SDMMC_CTYPE_1BIT 0
+/* Interrupt status & mask register defines */
+#define SDMMC_INT_SDIO BIT(16)
+#define SDMMC_INT_EBE BIT(15)
+#define SDMMC_INT_ACD BIT(14)
+#define SDMMC_INT_SBE BIT(13)
+#define SDMMC_INT_HLE BIT(12)
+#define SDMMC_INT_FRUN BIT(11)
+#define SDMMC_INT_HTO BIT(10)
+#define SDMMC_INT_DTO BIT(9)
+#define SDMMC_INT_RTO BIT(8)
+#define SDMMC_INT_DCRC BIT(7)
+#define SDMMC_INT_RCRC BIT(6)
+#define SDMMC_INT_RXDR BIT(5)
+#define SDMMC_INT_TXDR BIT(4)
+#define SDMMC_INT_DATA_OVER BIT(3)
+#define SDMMC_INT_CMD_DONE BIT(2)
+#define SDMMC_INT_RESP_ERR BIT(1)
+#define SDMMC_INT_CD BIT(0)
+#define SDMMC_INT_ERROR 0xbfc2
+/* Command register defines */
+#define SDMMC_CMD_START BIT(31)
+#define SDMMC_CMD_CCS_EXP BIT(23)
+#define SDMMC_CMD_CEATA_RD BIT(22)
+#define SDMMC_CMD_UPD_CLK BIT(21)
+#define SDMMC_CMD_INIT BIT(15)
+#define SDMMC_CMD_STOP BIT(14)
+#define SDMMC_CMD_PRV_DAT_WAIT BIT(13)
+#define SDMMC_CMD_SEND_STOP BIT(12)
+#define SDMMC_CMD_STRM_MODE BIT(11)
+#define SDMMC_CMD_DAT_WR BIT(10)
+#define SDMMC_CMD_DAT_EXP BIT(9)
+#define SDMMC_CMD_RESP_CRC BIT(8)
+#define SDMMC_CMD_RESP_LONG BIT(7)
+#define SDMMC_CMD_RESP_EXP BIT(6)
+#define SDMMC_CMD_INDX(n) ((n) & 0x1F)
+/* Status register defines */
+#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF)
+#define SDMMC_FIFO_SZ 32
+/* Internal DMAC interrupt defines */
+#define SDMMC_IDMAC_INT_AI BIT(9)
+#define SDMMC_IDMAC_INT_NI BIT(8)
+#define SDMMC_IDMAC_INT_CES BIT(5)
+#define SDMMC_IDMAC_INT_DU BIT(4)
+#define SDMMC_IDMAC_INT_FBE BIT(2)
+#define SDMMC_IDMAC_INT_RI BIT(1)
+#define SDMMC_IDMAC_INT_TI BIT(0)
+/* Internal DMAC bus mode bits */
+#define SDMMC_IDMAC_ENABLE BIT(7)
+#define SDMMC_IDMAC_FB BIT(1)
+#define SDMMC_IDMAC_SWRESET BIT(0)
+
+/* Register access macros */
+#define mci_readl(dev, reg) \
+ __raw_readl(dev->regs + SDMMC_##reg)
+#define mci_writel(dev, reg, value) \
+ __raw_writel((value), dev->regs + SDMMC_##reg)
+
+/* 16-bit FIFO access macros */
+#define mci_readw(dev, reg) \
+ __raw_readw(dev->regs + SDMMC_##reg)
+#define mci_writew(dev, reg, value) \
+ __raw_writew((value), dev->regs + SDMMC_##reg)
+
+/* 64-bit FIFO access macros */
+#ifdef readq
+#define mci_readq(dev, reg) \
+ __raw_readq(dev->regs + SDMMC_##reg)
+#define mci_writeq(dev, reg, value) \
+ __raw_writeq((value), dev->regs + SDMMC_##reg)
+#else
+/*
+ * Dummy readq implementation for architectures that don't define it.
+ *
+ * We would assume that none of these architectures would configure
+ * the IP block with a 64bit FIFO width, so this code will never be
+ * executed on those machines. Defining these macros here keeps the
+ * rest of the code free from ifdefs.
+ */
+#define mci_readq(dev, reg) \
+ (*(volatile u64 __force *)(dev->regs + SDMMC_##reg))
+#define mci_writeq(dev, reg, value) \
+ (*(volatile u64 __force *)(dev->regs + SDMMC_##reg) = value)
+#endif
+
+#endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 87b4fc6c98c2..563022825667 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -19,6 +19,7 @@
#include <linux/highmem.h>
#include <linux/log2.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
@@ -45,6 +46,12 @@ static unsigned int fmax = 515633;
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
+ * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
+ * and will not work at all.
+ * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
+ * using DMA.
+ * @sdio: variant supports SDIO
+ * @st_clkdiv: true if using a ST-specific clock divider algorithm
*/
struct variant_data {
unsigned int clkreg;
@@ -52,6 +59,10 @@ struct variant_data {
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
+ bool broken_blockend;
+ bool broken_blockend_dma;
+ bool sdio;
+ bool st_clkdiv;
};
static struct variant_data variant_arm = {
@@ -65,6 +76,8 @@ static struct variant_data variant_u300 = {
.fifohalfsize = 8 * 4,
.clkreg_enable = 1 << 13, /* HWFCEN */
.datalength_bits = 16,
+ .broken_blockend_dma = true,
+ .sdio = true,
};
static struct variant_data variant_ux500 = {
@@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = {
.clkreg = MCI_CLK_ENABLE,
.clkreg_enable = 1 << 14, /* HWFCEN */
.datalength_bits = 24,
+ .broken_blockend = true,
+ .sdio = true,
+ .st_clkdiv = true,
};
+
/*
* This must be called with host->lock held
*/
@@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if (desired >= host->mclk) {
clk = MCI_CLK_BYPASS;
host->cclk = host->mclk;
+ } else if (variant->st_clkdiv) {
+ /*
+ * DB8500 TRM says f = mclk / (clkdiv + 2)
+ * => clkdiv = (mclk / f) - 2
+ * Round the divider up so we don't exceed the max
+ * frequency
+ */
+ clk = DIV_ROUND_UP(host->mclk, desired) - 2;
+ if (clk >= 256)
+ clk = 255;
+ host->cclk = host->mclk / (clk + 2);
} else {
+ /*
+ * PL180 TRM says f = mclk / (2 * (clkdiv + 1))
+ * => clkdiv = mclk / (2 * f) - 1
+ */
clk = host->mclk / (2 * desired) - 1;
if (clk >= 256)
clk = 255;
@@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
spin_lock(&host->lock);
}
+static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
+{
+ void __iomem *base = host->base;
+
+ if (host->singleirq) {
+ unsigned int mask0 = readl(base + MMCIMASK0);
+
+ mask0 &= ~MCI_IRQ1MASK;
+ mask0 |= mask;
+
+ writel(mask0, base + MMCIMASK0);
+ }
+
+ writel(mask, base + MMCIMASK1);
+}
+
static void mmci_stop_data(struct mmci_host *host)
{
writel(0, host->base + MMCIDATACTRL);
- writel(0, host->base + MMCIMASK1);
+ mmci_set_mask1(host, 0);
host->data = NULL;
}
@@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
host->data = data;
host->size = data->blksz * data->blocks;
host->data_xfered = 0;
+ host->blockend = false;
+ host->dataend = false;
mmci_init_sg(host, data);
@@ -196,9 +246,14 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
irqmask = MCI_TXFIFOHALFEMPTYMASK;
}
+ /* The ST Micro variants has a special bit to enable SDIO */
+ if (variant->sdio && host->mmc->card)
+ if (mmc_card_sdio(host->mmc->card))
+ datactrl |= MCI_ST_DPSM_SDIOEN;
+
writel(datactrl, base + MMCIDATACTRL);
writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
- writel(irqmask, base + MMCIMASK1);
+ mmci_set_mask1(host, irqmask);
}
static void
@@ -233,20 +288,9 @@ static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
- if (status & MCI_DATABLOCKEND) {
- host->data_xfered += data->blksz;
-#ifdef CONFIG_ARCH_U300
- /*
- * On the U300 some signal or other is
- * badly routed so that a data write does
- * not properly terminate with a MCI_DATAEND
- * status flag. This quirk will make writes
- * work again.
- */
- if (data->flags & MMC_DATA_WRITE)
- status |= MCI_DATAEND;
-#endif
- }
+ struct variant_data *variant = host->variant;
+
+ /* First check for errors */
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
if (status & MCI_DATACRCFAIL)
@@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
data->error = -ETIMEDOUT;
else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
data->error = -EIO;
- status |= MCI_DATAEND;
+
+ /* Force-complete the transaction */
+ host->blockend = true;
+ host->dataend = true;
/*
* We hit an error condition. Ensure that any data
@@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
local_irq_restore(flags);
}
}
- if (status & MCI_DATAEND) {
+
+ /*
+ * On ARM variants in PIO mode, MCI_DATABLOCKEND
+ * is always sent first, and we increase the
+ * transfered number of bytes for that IRQ. Then
+ * MCI_DATAEND follows and we conclude the transaction.
+ *
+ * On the Ux500 single-IRQ variant MCI_DATABLOCKEND
+ * doesn't seem to immediately clear from the status,
+ * so we can't use it keep count when only one irq is
+ * used because the irq will hit for other reasons, and
+ * then the flag is still up. So we use the MCI_DATAEND
+ * IRQ at the end of the entire transfer because
+ * MCI_DATABLOCKEND is broken.
+ *
+ * In the U300, the IRQs can arrive out-of-order,
+ * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
+ * so for this case we use the flags "blockend" and
+ * "dataend" to make sure both IRQs have arrived before
+ * concluding the transaction. (This does not apply
+ * to the Ux500 which doesn't fire MCI_DATABLOCKEND
+ * at all.) In DMA mode it suffers from the same problem
+ * as the Ux500.
+ */
+ if (status & MCI_DATABLOCKEND) {
+ /*
+ * Just being a little over-cautious, we do not
+ * use this progressive update if the hardware blockend
+ * flag is unreliable: since it can stay high between
+ * IRQs it will corrupt the transfer counter.
+ */
+ if (!variant->broken_blockend)
+ host->data_xfered += data->blksz;
+ host->blockend = true;
+ }
+
+ if (status & MCI_DATAEND)
+ host->dataend = true;
+
+ /*
+ * On variants with broken blockend we shall only wait for dataend,
+ * on others we must sync with the blockend signal since they can
+ * appear out-of-order.
+ */
+ if (host->dataend && (host->blockend || variant->broken_blockend)) {
mmci_stop_data(host);
+ /* Reset these flags */
+ host->blockend = false;
+ host->dataend = false;
+
+ /*
+ * Variants with broken blockend flags need to handle the
+ * end of the entire transfer here.
+ */
+ if (variant->broken_blockend && !data->error)
+ host->data_xfered += data->blksz * data->blocks;
+
if (!data->stop) {
mmci_request_end(host, data->mrq);
} else {
@@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
variant->fifosize : variant->fifohalfsize;
count = min(remain, maxcnt);
- writesl(base + MMCIFIFO, ptr, count >> 2);
+ /*
+ * The ST Micro variant for SDIO transfer sizes
+ * less then 8 bytes should have clock H/W flow
+ * control disabled.
+ */
+ if (variant->sdio &&
+ mmc_card_sdio(host->mmc->card)) {
+ if (count < 8)
+ writel(readl(host->base + MMCICLOCK) &
+ ~variant->clkreg_enable,
+ host->base + MMCICLOCK);
+ else
+ writel(readl(host->base + MMCICLOCK) |
+ variant->clkreg_enable,
+ host->base + MMCICLOCK);
+ }
+
+ /*
+ * SDIO especially may want to send something that is
+ * not divisible by 4 (as opposed to card sectors
+ * etc), and the FIFO only accept full 32-bit writes.
+ * So compensate by adding +3 on the count, a single
+ * byte become a 32bit write, 7 bytes will be two
+ * 32bit writes etc.
+ */
+ writesl(base + MMCIFIFO, ptr, (count + 3) >> 2);
ptr += count;
remain -= count;
@@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* "any data available" mode.
*/
if (status & MCI_RXACTIVE && host->size < variant->fifosize)
- writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+ mmci_set_mask1(host, MCI_RXDATAAVLBLMASK);
/*
* If we run out of data, disable the data IRQs; this
@@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* stops us racing with our data end IRQ.
*/
if (host->size == 0) {
- writel(0, base + MMCIMASK1);
+ mmci_set_mask1(host, 0);
writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
}
@@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
struct mmc_data *data;
status = readl(host->base + MMCISTATUS);
+
+ if (host->singleirq) {
+ if (status & readl(host->base + MMCIMASK1))
+ mmci_pio_irq(irq, dev_id);
+
+ status &= ~MCI_IRQ1MASK;
+ }
+
status &= readl(host->base + MMCIMASK0);
writel(status, host->base + MMCICLEAR);
@@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
struct variant_data *variant = id->data;
struct mmci_host *host;
struct mmc_host *mmc;
+ unsigned int mask;
int ret;
/* must have platform data */
@@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if (ret)
goto unmap;
- ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
- if (ret)
- goto irq0_free;
+ if (dev->irq[1] == NO_IRQ)
+ host->singleirq = true;
+ else {
+ ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
+ DRIVER_NAME " (pio)", host);
+ if (ret)
+ goto irq0_free;
+ }
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ mask = MCI_IRQENABLE;
+ /* Don't use the datablockend flag if it's broken */
+ if (variant->broken_blockend)
+ mask &= ~MCI_DATABLOCKEND;
- amba_set_drvdata(dev, mmc);
+ writel(mask, host->base + MMCIMASK0);
- mmc_add_host(mmc);
+ amba_set_drvdata(dev, mmc);
- dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
- mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
+ dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n",
+ mmc_hostname(mmc), amba_part(dev), amba_rev(dev),
(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
+ mmc_add_host(mmc);
+
return 0;
irq0_free:
@@ -864,7 +1010,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
writel(0, host->base + MMCIDATACTRL);
free_irq(dev->irq[0], host);
- free_irq(dev->irq[1], host);
+ if (!host->singleirq)
+ free_irq(dev->irq[1], host);
if (host->gpio_wp != -ENOSYS)
gpio_free(host->gpio_wp);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 4ae887fc0189..df06f01aac89 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -139,6 +139,11 @@
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+/* These interrupts are directed to IRQ1 when two IRQ lines are available */
+#define MCI_IRQ1MASK \
+ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
+ MCI_TXFIFOHALFEMPTYMASK)
+
#define NR_SG 16
struct clk;
@@ -154,6 +159,7 @@ struct mmci_host {
int gpio_cd;
int gpio_wp;
int gpio_cd_irq;
+ bool singleirq;
unsigned int data_xfered;
@@ -171,6 +177,9 @@ struct mmci_host {
struct timer_list timer;
unsigned int oldstat;
+ bool blockend;
+ bool dataend;
+
/* pio stuff */
struct sg_mapping_iter sg_miter;
unsigned int size;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 1290d14c5839..5decfd0bd61d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -44,6 +44,7 @@
#include <mach/mmc.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
+#include <mach/clk.h>
#include "msm_sdcc.h"
@@ -126,6 +127,40 @@ static void
msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
u32 c);
+static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
+{
+ u32 mci_clk = 0;
+ u32 mci_mask0 = 0;
+ int ret = 0;
+
+ /* Save the controller state */
+ mci_clk = readl(host->base + MMCICLOCK);
+ mci_mask0 = readl(host->base + MMCIMASK0);
+
+ /* Reset the controller */
+ ret = clk_reset(host->clk, CLK_RESET_ASSERT);
+ if (ret)
+ pr_err("%s: Clock assert failed at %u Hz with err %d\n",
+ mmc_hostname(host->mmc), host->clk_rate, ret);
+
+ ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
+ if (ret)
+ pr_err("%s: Clock deassert failed at %u Hz with err %d\n",
+ mmc_hostname(host->mmc), host->clk_rate, ret);
+
+ pr_info("%s: Controller has been re-initialiazed\n",
+ mmc_hostname(host->mmc));
+
+ /* Restore the contoller state */
+ writel(host->pwr, host->base + MMCIPOWER);
+ writel(mci_clk, host->base + MMCICLOCK);
+ writel(mci_mask0, host->base + MMCIMASK0);
+ ret = clk_set_rate(host->clk, host->clk_rate);
+ if (ret)
+ pr_err("%s: Failed to set clk rate %u Hz (%d)\n",
+ mmc_hostname(host->mmc), host->clk_rate, ret);
+}
+
static void
msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
{
@@ -155,7 +190,7 @@ static void
msmsdcc_stop_data(struct msmsdcc_host *host)
{
host->curr.data = NULL;
- host->curr.got_dataend = host->curr.got_datablkend = 0;
+ host->curr.got_dataend = 0;
}
uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
@@ -189,42 +224,42 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
}
static void
-msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
- unsigned int result,
- struct msm_dmov_errdata *err)
+msmsdcc_dma_complete_tlet(unsigned long data)
{
- struct msmsdcc_dma_data *dma_data =
- container_of(cmd, struct msmsdcc_dma_data, hdr);
- struct msmsdcc_host *host = dma_data->host;
+ struct msmsdcc_host *host = (struct msmsdcc_host *)data;
unsigned long flags;
struct mmc_request *mrq;
+ struct msm_dmov_errdata err;
spin_lock_irqsave(&host->lock, flags);
host->dma.active = 0;
+ err = host->dma.err;
mrq = host->curr.mrq;
BUG_ON(!mrq);
WARN_ON(!mrq->data);
- if (!(result & DMOV_RSLT_VALID)) {
+ if (!(host->dma.result & DMOV_RSLT_VALID)) {
pr_err("msmsdcc: Invalid DataMover result\n");
goto out;
}
- if (result & DMOV_RSLT_DONE) {
+ if (host->dma.result & DMOV_RSLT_DONE) {
host->curr.data_xfered = host->curr.xfer_size;
} else {
/* Error or flush */
- if (result & DMOV_RSLT_ERROR)
+ if (host->dma.result & DMOV_RSLT_ERROR)
pr_err("%s: DMA error (0x%.8x)\n",
- mmc_hostname(host->mmc), result);
- if (result & DMOV_RSLT_FLUSH)
+ mmc_hostname(host->mmc), host->dma.result);
+ if (host->dma.result & DMOV_RSLT_FLUSH)
pr_err("%s: DMA channel flushed (0x%.8x)\n",
- mmc_hostname(host->mmc), result);
- if (err)
- pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
- err->flush[0], err->flush[1], err->flush[2],
- err->flush[3], err->flush[4], err->flush[5]);
+ mmc_hostname(host->mmc), host->dma.result);
+
+ pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ err.flush[0], err.flush[1], err.flush[2],
+ err.flush[3], err.flush[4], err.flush[5]);
+
+ msmsdcc_reset_and_restore(host);
if (!mrq->data->error)
mrq->data->error = -EIO;
}
@@ -242,8 +277,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
host->dma.sg = NULL;
host->dma.busy = 0;
- if ((host->curr.got_dataend && host->curr.got_datablkend)
- || mrq->data->error) {
+ if (host->curr.got_dataend || mrq->data->error) {
/*
* If we've already gotten our DATAEND / DATABLKEND
@@ -273,6 +307,22 @@ out:
return;
}
+static void
+msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
+ unsigned int result,
+ struct msm_dmov_errdata *err)
+{
+ struct msmsdcc_dma_data *dma_data =
+ container_of(cmd, struct msmsdcc_dma_data, hdr);
+ struct msmsdcc_host *host = dma_data->host;
+
+ dma_data->result = result;
+ if (err)
+ memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
+
+ tasklet_schedule(&host->dma_tlet);
+}
+
static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
{
if (host->dma.channel == -1)
@@ -424,6 +474,11 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host,
(cmd->opcode == 53))
*c |= MCI_CSPM_DATCMD;
+ if (host->prog_scan && (cmd->opcode == 12)) {
+ *c |= MCI_CPSM_PROGENA;
+ host->prog_enable = true;
+ }
+
if (cmd == cmd->mrq->stop)
*c |= MCI_CSPM_MCIABORT;
@@ -450,7 +505,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
host->curr.xfer_remain = host->curr.xfer_size;
host->curr.data_xfered = 0;
host->curr.got_dataend = 0;
- host->curr.got_datablkend = 0;
memset(&host->pio, 0, sizeof(host->pio));
@@ -494,6 +548,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
host->cmd_c = c;
}
msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
+ if (data->flags & MMC_DATA_WRITE)
+ host->prog_scan = true;
} else {
msmsdcc_writel(host, timeout, MMCIDATATIMER);
@@ -555,6 +611,9 @@ msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
uint32_t *ptr = (uint32_t *) buffer;
int count = 0;
+ if (remain % 4)
+ remain = ((remain >> 2) + 1) << 2;
+
while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
*ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
ptr++;
@@ -575,13 +634,14 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
char *ptr = buffer;
do {
- unsigned int count, maxcnt;
+ unsigned int count, maxcnt, sz;
maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
MCI_FIFOHALFSIZE;
count = min(remain, maxcnt);
- writesl(base + MMCIFIFO, ptr, count >> 2);
+ sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
+ writesl(base + MMCIFIFO, ptr, sz);
ptr += count;
remain -= count;
@@ -702,10 +762,26 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
msm_dmov_stop_cmd(host->dma.channel,
&host->dma.hdr, 0);
else if (host->curr.data) { /* Non DMA */
+ msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
msmsdcc_request_end(host, cmd->mrq);
- } else /* host->data == NULL */
- msmsdcc_request_end(host, cmd->mrq);
+ } else { /* host->data == NULL */
+ if (!cmd->error && host->prog_enable) {
+ if (status & MCI_PROGDONE) {
+ host->prog_scan = false;
+ host->prog_enable = false;
+ msmsdcc_request_end(host, cmd->mrq);
+ } else {
+ host->curr.cmd = cmd;
+ }
+ } else {
+ if (host->prog_enable) {
+ host->prog_scan = false;
+ host->prog_enable = false;
+ }
+ msmsdcc_request_end(host, cmd->mrq);
+ }
+ }
} else if (cmd->data)
if (!(cmd->data->flags & MMC_DATA_READ))
msmsdcc_start_data(host, cmd->data,
@@ -719,7 +795,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
struct mmc_data *data = host->curr.data;
if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
- MCI_CMDTIMEOUT) && host->curr.cmd) {
+ MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) {
msmsdcc_do_cmdirq(host, status);
}
@@ -735,6 +811,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
msm_dmov_stop_cmd(host->dma.channel,
&host->dma.hdr, 0);
else {
+ msmsdcc_reset_and_restore(host);
if (host->curr.data)
msmsdcc_stop_data(host);
if (!data->stop)
@@ -748,14 +825,10 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
if (!host->curr.got_dataend && (status & MCI_DATAEND))
host->curr.got_dataend = 1;
- if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND))
- host->curr.got_datablkend = 1;
-
/*
* If DMA is still in progress, we complete via the completion handler
*/
- if (host->curr.got_dataend && host->curr.got_datablkend &&
- !host->dma.busy) {
+ if (host->curr.got_dataend && !host->dma.busy) {
/*
* There appears to be an issue in the controller where
* if you request a small block transfer (< fifo size),
@@ -792,8 +865,7 @@ msmsdcc_irq(int irq, void *dev_id)
do {
status = msmsdcc_readl(host, MMCISTATUS);
- status &= (msmsdcc_readl(host, MMCIMASK0) |
- MCI_DATABLOCKENDMASK);
+ status &= msmsdcc_readl(host, MMCIMASK0);
msmsdcc_writel(host, status, MMCICLEAR);
if (status & MCI_SDIOINTR)
@@ -1118,6 +1190,9 @@ msmsdcc_probe(struct platform_device *pdev)
host->dmares = dmares;
spin_lock_init(&host->lock);
+ tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
+ (unsigned long)host);
+
/*
* Setup DMA
*/
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ff2b0f74f6f4..939557af266d 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -138,7 +138,7 @@
#define MCI_IRQENABLE \
(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK)
+ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK)
/*
* The size of the FIFO in bytes.
@@ -172,6 +172,8 @@ struct msmsdcc_dma_data {
struct msmsdcc_host *host;
int busy; /* Set if DM is busy */
int active;
+ unsigned int result;
+ struct msm_dmov_errdata err;
};
struct msmsdcc_pio_data {
@@ -188,7 +190,6 @@ struct msmsdcc_curr_req {
unsigned int xfer_remain; /* Bytes remaining to send */
unsigned int data_xfered; /* Bytes acked by BLKEND irq */
int got_dataend;
- int got_datablkend;
int user_pages;
};
@@ -235,6 +236,7 @@ struct msmsdcc_host {
int cmdpoll;
struct msmsdcc_stats stats;
+ struct tasklet_struct dma_tlet;
/* Command parameters */
unsigned int cmd_timeout;
unsigned int cmd_pio_irqmask;
@@ -242,6 +244,8 @@ struct msmsdcc_host {
struct mmc_command *cmd_cmd;
u32 cmd_c;
+ bool prog_scan;
+ bool prog_enable;
};
#endif
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index bdd2cbb87cba..4428594261c5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -141,10 +142,49 @@ struct mxcmci_host {
struct work_struct datawork;
spinlock_t lock;
+
+ struct regulator *vcc;
};
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
+static inline void mxcmci_init_ocr(struct mxcmci_host *host)
+{
+ host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+
+ if (IS_ERR(host->vcc)) {
+ host->vcc = NULL;
+ } else {
+ host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
+ if (host->pdata && host->pdata->ocr_avail)
+ dev_warn(mmc_dev(host->mmc),
+ "pdata->ocr_avail will not be used\n");
+ }
+
+ if (host->vcc == NULL) {
+ /* fall-back to platform data */
+ if (host->pdata && host->pdata->ocr_avail)
+ host->mmc->ocr_avail = host->pdata->ocr_avail;
+ else
+ host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ }
+}
+
+static inline void mxcmci_set_power(struct mxcmci_host *host,
+ unsigned char power_mode,
+ unsigned int vdd)
+{
+ if (host->vcc) {
+ if (power_mode == MMC_POWER_UP)
+ mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+ else if (power_mode == MMC_POWER_OFF)
+ mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+ }
+
+ if (host->pdata && host->pdata->setpower)
+ host->pdata->setpower(mmc_dev(host->mmc), vdd);
+}
+
static inline int mxcmci_use_dma(struct mxcmci_host *host)
{
return host->do_dma;
@@ -680,9 +720,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
if (host->power_mode != ios->power_mode) {
- if (host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc_dev(mmc), ios->vdd);
+ mxcmci_set_power(host, ios->power_mode, ios->vdd);
host->power_mode = ios->power_mode;
+
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMD_DAT_CONT_INIT;
}
@@ -807,10 +847,7 @@ static int mxcmci_probe(struct platform_device *pdev)
host->pdata = pdev->dev.platform_data;
spin_lock_init(&host->lock);
- if (host->pdata && host->pdata->ocr_avail)
- mmc->ocr_avail = host->pdata->ocr_avail;
- else
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mxcmci_init_ocr(host);
if (host->pdata && host->pdata->dat3_card_detect)
host->default_irq_mask =
@@ -915,6 +952,9 @@ static int mxcmci_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
+ if (host->vcc)
+ regulator_put(host->vcc);
+
if (host->pdata && host->pdata->exit)
host->pdata->exit(&pdev->dev, mmc);
@@ -927,7 +967,6 @@ static int mxcmci_remove(struct platform_device *pdev)
clk_put(host->clk);
release_mem_region(host->res->start, resource_size(host->res));
- release_resource(host->res);
mmc_free_host(mmc);
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 0c7e37f496ef..379d2ffe4c87 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -173,6 +173,8 @@ struct mmc_omap_host {
struct omap_mmc_platform_data *pdata;
};
+static struct workqueue_struct *mmc_omap_wq;
+
static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
{
unsigned long tick_ns;
@@ -289,7 +291,7 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
host->next_slot = new_slot;
host->mmc = new_slot->mmc;
spin_unlock_irqrestore(&host->slot_lock, flags);
- schedule_work(&host->slot_release_work);
+ queue_work(mmc_omap_wq, &host->slot_release_work);
return;
}
@@ -457,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
}
host->stop_data = data;
- schedule_work(&host->send_stop_work);
+ queue_work(mmc_omap_wq, &host->send_stop_work);
}
static void
@@ -637,7 +639,7 @@ mmc_omap_cmd_timer(unsigned long data)
OMAP_MMC_WRITE(host, IE, 0);
disable_irq(host->irq);
host->abort = 1;
- schedule_work(&host->cmd_abort_work);
+ queue_work(mmc_omap_wq, &host->cmd_abort_work);
}
spin_unlock_irqrestore(&host->slot_lock, flags);
}
@@ -826,7 +828,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
host->abort = 1;
OMAP_MMC_WRITE(host, IE, 0);
disable_irq_nosync(host->irq);
- schedule_work(&host->cmd_abort_work);
+ queue_work(mmc_omap_wq, &host->cmd_abort_work);
return IRQ_HANDLED;
}
@@ -1387,7 +1389,7 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)
tasklet_kill(&slot->cover_tasklet);
del_timer_sync(&slot->cover_timer);
- flush_scheduled_work();
+ flush_workqueue(mmc_omap_wq);
mmc_remove_host(mmc);
mmc_free_host(mmc);
@@ -1608,12 +1610,22 @@ static struct platform_driver mmc_omap_driver = {
static int __init mmc_omap_init(void)
{
- return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
+ int ret;
+
+ mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0);
+ if (!mmc_omap_wq)
+ return -ENOMEM;
+
+ ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
+ if (ret)
+ destroy_workqueue(mmc_omap_wq);
+ return ret;
}
static void __exit mmc_omap_exit(void)
{
platform_driver_unregister(&mmc_omap_driver);
+ destroy_workqueue(mmc_omap_wq);
}
module_init(mmc_omap_init);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 82a1079bbdc7..078fdf11af03 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1002,7 +1002,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
* Monitor a 0->1 transition first
*/
if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
- while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit))
+ while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
cpu_relax();
}
@@ -2290,7 +2290,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
free_irq(host->irq, host);
if (mmc_slot(host).card_detect_irq)
free_irq(mmc_slot(host).card_detect_irq, host);
- flush_scheduled_work();
+ flush_work_sync(&host->mmc_carddetect_work);
mmc_host_disable(host->mmc);
clk_disable(host->iclk);
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
new file mode 100644
index 000000000000..2aeef4ffed8c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -0,0 +1,70 @@
+/*
+ * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC
+ *
+ * Author: Saeed Bishara <saeed@marvell.com>
+ * Mike Rapoport <mike@compulab.co.il>
+ * Based on sdhci-cns3xxx.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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/io.h>
+#include <linux/mmc/host.h>
+
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+
+static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
+{
+ u16 ret;
+
+ switch (reg) {
+ case SDHCI_HOST_VERSION:
+ case SDHCI_SLOT_INT_STATUS:
+ /* those registers don't exist */
+ return 0;
+ default:
+ ret = readw(host->ioaddr + reg);
+ }
+ return ret;
+}
+
+static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
+{
+ u32 ret;
+
+ switch (reg) {
+ case SDHCI_CAPABILITIES:
+ ret = readl(host->ioaddr + reg);
+ /* Mask the support for 3.0V */
+ ret &= ~SDHCI_CAN_VDD_300;
+ break;
+ default:
+ ret = readl(host->ioaddr + reg);
+ }
+ return ret;
+}
+
+static struct sdhci_ops sdhci_dove_ops = {
+ .read_w = sdhci_dove_readw,
+ .read_l = sdhci_dove_readl,
+};
+
+struct sdhci_pltfm_data sdhci_dove_pdata = {
+ .ops = &sdhci_dove_ops,
+ .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+ SDHCI_QUIRK_NO_BUSY_IRQ |
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_FORCE_DMA,
+};
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 2e9cca19c90b..9b82910b9dbb 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h>
+#include <mach/hardware.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -112,6 +113,13 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
clk_enable(clk);
pltfm_host->clk = clk;
+ if (cpu_is_mx35() || cpu_is_mx51())
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+ /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */
+ if (cpu_is_mx25() || cpu_is_mx35())
+ host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+
return 0;
}
@@ -133,10 +141,8 @@ static struct sdhci_ops sdhci_esdhc_ops = {
};
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
- | SDHCI_QUIRK_BROKEN_ADMA,
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA,
/* ADMA has issues. Might be fixable */
- /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,
.exit = esdhc_pltfm_exit,
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
index c51b71174c1d..dd84124f4209 100644
--- a/drivers/mmc/host/sdhci-of-core.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -13,6 +13,7 @@
* your option) any later version.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -20,8 +21,12 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/mmc/host.h>
+#ifdef CONFIG_PPC
#include <asm/machdep.h>
+#endif
#include "sdhci-of.h"
#include "sdhci.h"
@@ -112,7 +117,11 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
return true;
/* Old device trees don't have the wp-inverted property. */
+#ifdef CONFIG_PPC
return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
+#else
+ return false;
+#endif
}
static int __devinit sdhci_of_probe(struct platform_device *ofdev,
@@ -122,7 +131,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev,
struct sdhci_of_data *sdhci_of_data = match->data;
struct sdhci_host *host;
struct sdhci_of_host *of_host;
- const u32 *clk;
+ const __be32 *clk;
int size;
int ret;
@@ -166,7 +175,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev,
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
- of_host->clock = *clk;
+ of_host->clock = be32_to_cpup(clk);
ret = sdhci_add_host(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 55746bac2f44..0dc905b20eee 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -149,11 +149,11 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
* ADMA operation is disabled for Moorestown platform due to
* hardware bugs.
*/
-static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
+static int mrst_hc_probe(struct sdhci_pci_chip *chip)
{
/*
- * slots number is fixed here for MRST as SDIO3 is never used and has
- * hardware bugs.
+ * slots number is fixed here for MRST as SDIO3/5 are never used and
+ * have hardware bugs.
*/
chip->num_slots = 1;
return 0;
@@ -163,9 +163,9 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
};
-static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
- .probe = mrst_hc1_probe,
+ .probe = mrst_hc_probe,
};
static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
@@ -176,6 +176,74 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
};
+/* O2Micro extra registers */
+#define O2_SD_LOCK_WP 0xD3
+#define O2_SD_MULTI_VCC3V 0xEE
+#define O2_SD_CLKREQ 0xEC
+#define O2_SD_CAPS 0xE0
+#define O2_SD_ADMA1 0xE2
+#define O2_SD_ADMA2 0xE7
+#define O2_SD_INF_MOD 0xF1
+
+static int o2_probe(struct sdhci_pci_chip *chip)
+{
+ int ret;
+ u8 scratch;
+
+ switch (chip->pdev->device) {
+ case PCI_DEVICE_ID_O2_8220:
+ case PCI_DEVICE_ID_O2_8221:
+ case PCI_DEVICE_ID_O2_8320:
+ case PCI_DEVICE_ID_O2_8321:
+ /* This extra setup is required due to broken ADMA. */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+ if (ret)
+ return ret;
+ scratch &= 0x7f;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+
+ /* Set Multi 3 to VCC3V# */
+ pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
+
+ /* Disable CLK_REQ# support after media DET */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch);
+ if (ret)
+ return ret;
+ scratch |= 0x20;
+ pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
+
+ /* Choose capabilities, enable SDMA. We have to write 0x01
+ * to the capabilities register first to unlock it.
+ */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
+ if (ret)
+ return ret;
+ scratch |= 0x01;
+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
+
+ /* Disable ADMA1/2 */
+ pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
+ pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
+
+ /* Disable the infinite transfer mode */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch);
+ if (ret)
+ return ret;
+ scratch |= 0x08;
+ pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
+
+ /* Lock WP */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+ if (ret)
+ return ret;
+ scratch |= 0x80;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+ }
+
+ return 0;
+}
+
static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
{
u8 scratch;
@@ -204,6 +272,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
static int jmicron_probe(struct sdhci_pci_chip *chip)
{
int ret;
+ u16 mmcdev = 0;
if (chip->pdev->revision == 0) {
chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
@@ -225,12 +294,17 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
* 2. The MMC interface has a lower subfunction number
* than the SD interface.
*/
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) {
+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD)
+ mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC;
+ else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD)
+ mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD;
+
+ if (mmcdev) {
struct pci_dev *sd_dev;
sd_dev = NULL;
while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
- PCI_DEVICE_ID_JMICRON_JMB38X_MMC, sd_dev)) != NULL) {
+ mmcdev, sd_dev)) != NULL) {
if ((PCI_SLOT(chip->pdev->devfn) ==
PCI_SLOT(sd_dev->devfn)) &&
(chip->pdev->bus == sd_dev->bus))
@@ -290,13 +364,25 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
}
+ /* JM388 MMC doesn't support 1.8V while SD supports it */
+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
+ slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 |
+ MMC_VDD_29_30 | MMC_VDD_30_31 |
+ MMC_VDD_165_195; /* allow 1.8V */
+ slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 |
+ MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */
+ }
+
/*
* The secondary interface requires a bit set to get the
* interrupts.
*/
- if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
jmicron_enable_mmc(slot->host, 1);
+ slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST;
+
return 0;
}
@@ -305,7 +391,8 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead)
if (dead)
return;
- if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
+ if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+ slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
jmicron_enable_mmc(slot->host, 0);
}
@@ -313,7 +400,8 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
{
int i;
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 0);
}
@@ -325,7 +413,8 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
{
int ret, i;
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 1);
}
@@ -339,6 +428,10 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
return 0;
}
+static const struct sdhci_pci_fixes sdhci_o2 = {
+ .probe = o2_probe,
+};
+
static const struct sdhci_pci_fixes sdhci_jmicron = {
.probe = jmicron_probe,
@@ -510,6 +603,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
},
{
+ .vendor = PCI_VENDOR_ID_JMICRON,
+ .device = PCI_DEVICE_ID_JMICRON_JMB388_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_jmicron,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_JMICRON,
+ .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_jmicron,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_SYSKONNECT,
.device = 0x8000,
.subvendor = PCI_ANY_ID,
@@ -538,7 +647,15 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_INTEL_MRST_SD1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_MRST_SD2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
},
{
@@ -581,6 +698,46 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
},
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_8120,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_8220,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_8221,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_8320,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_O2,
+ .device = PCI_DEVICE_ID_O2_8321,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -637,6 +794,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ mmc_pm_flag_t slot_pm_flags;
mmc_pm_flag_t pm_flags = 0;
int i, ret;
@@ -657,7 +815,11 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
return ret;
}
- pm_flags |= slot->host->mmc->pm_flags;
+ slot_pm_flags = slot->host->mmc->pm_flags;
+ if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ sdhci_enable_irq_wakeups(slot->host);
+
+ pm_flags |= slot_pm_flags;
}
if (chip->fixes && chip->fixes->suspend) {
@@ -671,8 +833,10 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
pci_save_state(pdev);
if (pm_flags & MMC_PM_KEEP_POWER) {
- if (pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
+ pci_pme_active(pdev, true);
pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
pci_set_power_state(pdev, PCI_D3hot);
} else {
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 0502f89f662b..dbab0407f4b6 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -170,6 +170,12 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
#endif
+#ifdef CONFIG_MMC_SDHCI_DOVE
+ { "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata },
+#endif
+#ifdef CONFIG_MMC_SDHCI_TEGRA
+ { "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata },
+#endif
{ },
};
MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index c1bfe48af56a..ea2e44d9be5e 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -22,5 +22,7 @@ struct sdhci_pltfm_host {
extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
+extern struct sdhci_pltfm_data sdhci_dove_pdata;
+extern struct sdhci_pltfm_data sdhci_tegra_pdata;
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c
index fc406ac5d193..5a61208cbc66 100644
--- a/drivers/mmc/host/sdhci-pxa.c
+++ b/drivers/mmc/host/sdhci-pxa.c
@@ -141,6 +141,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
if (pdata->quirks)
host->quirks |= pdata->quirks;
+ /* If slot design supports 8 bit data, indicate this to MMC. */
+ if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index aacb862ecc8a..17203586305c 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
if (!clksrc)
return UINT_MAX;
+ /*
+ * Clock divider's step is different as 1 from that of host controller
+ * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
+ */
+ if (ourhost->pdata->clk_type) {
+ rate = clk_round_rate(clksrc, wanted);
+ return wanted - rate;
+ }
+
rate = clk_get_rate(clksrc);
for (div = 1; div < 256; div *= 2) {
@@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
return min;
}
+/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/
+static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
+}
+
+/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
+static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /*
+ * initial clock can be in the frequency range of
+ * 100KHz-400KHz, so we set it as max value.
+ */
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
+}
+
+/* sdhci_cmu_set_clock - callback on clock change.*/
+static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /* don't bother if the clock is going off */
+ if (clock == 0)
+ return;
+
+ sdhci_s3c_set_clock(host, clock);
+
+ clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+
+ host->clock = clock;
+}
+
static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock,
@@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clks++;
sc->clk_bus[ptr] = clk;
+
+ /*
+ * save current clock index to know which clock bus
+ * is used later in overriding functions.
+ */
+ sc->cur_clk = ptr;
+
clk_enable(clk);
dev_info(dev, "clock source %d: %s (%ld Hz)\n",
@@ -427,6 +479,20 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
+ /*
+ * If controller does not have internal clock divider,
+ * we can use overriding functions instead of default.
+ */
+ if (pdata->clk_type) {
+ sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
+ sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
+ sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
+ }
+
+ /* It supports additional host capabilities if needed */
+ if (pdata->host_caps)
+ host->mmc->caps |= pdata->host_caps;
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(dev, "sdhci_add_host() failed\n");
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
new file mode 100644
index 000000000000..4823ee94a63f
--- /dev/null
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <mach/gpio.h>
+#include <mach/sdhci.h>
+
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+
+static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
+{
+ u32 val;
+
+ if (unlikely(reg == SDHCI_PRESENT_STATE)) {
+ /* Use wp_gpio here instead? */
+ val = readl(host->ioaddr + reg);
+ return val | SDHCI_WRITE_PROTECT;
+ }
+
+ return readl(host->ioaddr + reg);
+}
+
+static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
+{
+ if (unlikely(reg == SDHCI_HOST_VERSION)) {
+ /* Erratum: Version register is invalid in HW. */
+ return SDHCI_SPEC_200;
+ }
+
+ return readw(host->ioaddr + reg);
+}
+
+static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ /* Seems like we're getting spurious timeout and crc errors, so
+ * disable signalling of them. In case of real errors software
+ * timers should take care of eventually detecting them.
+ */
+ if (unlikely(reg == SDHCI_SIGNAL_ENABLE))
+ val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC);
+
+ writel(val, host->ioaddr + reg);
+
+ if (unlikely(reg == SDHCI_INT_ENABLE)) {
+ /* Erratum: Must enable block gap interrupt detection */
+ u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
+ if (val & SDHCI_INT_CARD_INT)
+ gap_ctrl |= 0x8;
+ else
+ gap_ctrl &= ~0x8;
+ writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
+ }
+}
+
+static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
+{
+ struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc));
+ struct tegra_sdhci_platform_data *plat;
+
+ plat = pdev->dev.platform_data;
+
+ if (!gpio_is_valid(plat->wp_gpio))
+ return -1;
+
+ return gpio_get_value(plat->wp_gpio);
+}
+
+static irqreturn_t carddetect_irq(int irq, void *data)
+{
+ struct sdhci_host *sdhost = (struct sdhci_host *)data;
+
+ tasklet_schedule(&sdhost->card_tasklet);
+ return IRQ_HANDLED;
+};
+
+static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
+{
+ struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
+ struct tegra_sdhci_platform_data *plat;
+ u32 ctrl;
+
+ plat = pdev->dev.platform_data;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) {
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl |= SDHCI_CTRL_8BITBUS;
+ } else {
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (bus_width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ }
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ return 0;
+}
+
+
+static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
+ struct sdhci_pltfm_data *pdata)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
+ struct tegra_sdhci_platform_data *plat;
+ struct clk *clk;
+ int rc;
+
+ plat = pdev->dev.platform_data;
+ if (plat == NULL) {
+ dev_err(mmc_dev(host->mmc), "missing platform data\n");
+ return -ENXIO;
+ }
+
+ if (gpio_is_valid(plat->power_gpio)) {
+ rc = gpio_request(plat->power_gpio, "sdhci_power");
+ if (rc) {
+ dev_err(mmc_dev(host->mmc),
+ "failed to allocate power gpio\n");
+ goto out;
+ }
+ tegra_gpio_enable(plat->power_gpio);
+ gpio_direction_output(plat->power_gpio, 1);
+ }
+
+ if (gpio_is_valid(plat->cd_gpio)) {
+ rc = gpio_request(plat->cd_gpio, "sdhci_cd");
+ if (rc) {
+ dev_err(mmc_dev(host->mmc),
+ "failed to allocate cd gpio\n");
+ goto out_power;
+ }
+ tegra_gpio_enable(plat->cd_gpio);
+ gpio_direction_input(plat->cd_gpio);
+
+ rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ mmc_hostname(host->mmc), host);
+
+ if (rc) {
+ dev_err(mmc_dev(host->mmc), "request irq error\n");
+ goto out_cd;
+ }
+
+ }
+
+ if (gpio_is_valid(plat->wp_gpio)) {
+ rc = gpio_request(plat->wp_gpio, "sdhci_wp");
+ if (rc) {
+ dev_err(mmc_dev(host->mmc),
+ "failed to allocate wp gpio\n");
+ goto out_cd;
+ }
+ tegra_gpio_enable(plat->wp_gpio);
+ gpio_direction_input(plat->wp_gpio);
+ }
+
+ clk = clk_get(mmc_dev(host->mmc), NULL);
+ if (IS_ERR(clk)) {
+ dev_err(mmc_dev(host->mmc), "clk err\n");
+ rc = PTR_ERR(clk);
+ goto out_wp;
+ }
+ clk_enable(clk);
+ pltfm_host->clk = clk;
+
+ if (plat->is_8bit)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
+ return 0;
+
+out_wp:
+ if (gpio_is_valid(plat->wp_gpio)) {
+ tegra_gpio_disable(plat->wp_gpio);
+ gpio_free(plat->wp_gpio);
+ }
+
+out_cd:
+ if (gpio_is_valid(plat->cd_gpio)) {
+ tegra_gpio_disable(plat->cd_gpio);
+ gpio_free(plat->cd_gpio);
+ }
+
+out_power:
+ if (gpio_is_valid(plat->power_gpio)) {
+ tegra_gpio_disable(plat->power_gpio);
+ gpio_free(plat->power_gpio);
+ }
+
+out:
+ return rc;
+}
+
+static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
+ struct tegra_sdhci_platform_data *plat;
+
+ plat = pdev->dev.platform_data;
+
+ if (gpio_is_valid(plat->wp_gpio)) {
+ tegra_gpio_disable(plat->wp_gpio);
+ gpio_free(plat->wp_gpio);
+ }
+
+ if (gpio_is_valid(plat->cd_gpio)) {
+ tegra_gpio_disable(plat->cd_gpio);
+ gpio_free(plat->cd_gpio);
+ }
+
+ if (gpio_is_valid(plat->power_gpio)) {
+ tegra_gpio_disable(plat->power_gpio);
+ gpio_free(plat->power_gpio);
+ }
+
+ clk_disable(pltfm_host->clk);
+ clk_put(pltfm_host->clk);
+}
+
+static struct sdhci_ops tegra_sdhci_ops = {
+ .get_ro = tegra_sdhci_get_ro,
+ .read_l = tegra_sdhci_readl,
+ .read_w = tegra_sdhci_readw,
+ .write_l = tegra_sdhci_writel,
+ .platform_8bit_width = tegra_sdhci_8bit,
+};
+
+struct sdhci_pltfm_data sdhci_tegra_pdata = {
+ .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_NO_HISPD_BIT |
+ SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+ .ops = &tegra_sdhci_ops,
+ .init = tegra_sdhci_pltfm_init,
+ .exit = tegra_sdhci_pltfm_exit,
+};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 782c0ee3c925..9e15f41f87be 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -23,6 +23,7 @@
#include <linux/leds.h>
+#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include "sdhci.h"
@@ -77,8 +78,11 @@ static void sdhci_dumpregs(struct sdhci_host *host)
printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
sdhci_readw(host, SDHCI_ACMD12_ERR),
sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
- printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n",
+ printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
sdhci_readl(host, SDHCI_CAPABILITIES),
+ sdhci_readl(host, SDHCI_CAPABILITIES_1));
+ printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
+ sdhci_readw(host, SDHCI_COMMAND),
sdhci_readl(host, SDHCI_MAX_CURRENT));
if (host->flags & SDHCI_USE_ADMA)
@@ -1185,17 +1189,31 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- ctrl |= SDHCI_CTRL_8BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_8BITBUS;
+ /*
+ * If your platform has 8-bit width support but is not a v3 controller,
+ * or if it requires special setup code, you should implement that in
+ * platform_8bit_width().
+ */
+ if (host->ops->platform_8bit_width)
+ host->ops->platform_8bit_width(host, ios->bus_width);
+ else {
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ if (host->version >= SDHCI_SPEC_300)
+ ctrl |= SDHCI_CTRL_8BITBUS;
+ } else {
+ if (host->version >= SDHCI_SPEC_300)
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ }
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ }
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if ((ios->timing == MMC_TIMING_SD_HS ||
ios->timing == MMC_TIMING_MMC_HS)
@@ -1504,7 +1522,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & SDHCI_INT_DATA_TIMEOUT)
host->data->error = -ETIMEDOUT;
- else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+ else if (intmask & SDHCI_INT_DATA_END_BIT)
+ host->data->error = -EILSEQ;
+ else if ((intmask & SDHCI_INT_DATA_CRC) &&
+ SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
+ != MMC_BUS_TEST_R)
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc));
@@ -1681,6 +1703,16 @@ int sdhci_resume_host(struct sdhci_host *host)
EXPORT_SYMBOL_GPL(sdhci_resume_host);
+void sdhci_enable_irq_wakeups(struct sdhci_host *host)
+{
+ u8 val;
+ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+ val |= SDHCI_WAKE_ON_INT;
+ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+}
+
+EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
+
#endif /* CONFIG_PM */
/*****************************************************************************\
@@ -1712,7 +1744,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
int sdhci_add_host(struct sdhci_host *host)
{
struct mmc_host *mmc;
- unsigned int caps;
+ unsigned int caps, ocr_avail;
int ret;
WARN_ON(host == NULL);
@@ -1845,11 +1877,19 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
else
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
+
mmc->f_max = host->max_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ;
+ /*
+ * A controller may support 8-bit width, but the board itself
+ * might not have the pins brought out. Boards that support
+ * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
+ * their platform code before calling sdhci_add_host(), and we
+ * won't assume 8-bit width for hosts without that CAP.
+ */
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1858,13 +1898,26 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_card_is_removable(mmc))
mmc->caps |= MMC_CAP_NEEDS_POLL;
- mmc->ocr_avail = 0;
+ ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
- mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
+ ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
if (caps & SDHCI_CAN_VDD_300)
- mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
+ ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180)
- mmc->ocr_avail |= MMC_VDD_165_195;
+ ocr_avail |= MMC_VDD_165_195;
+
+ mmc->ocr_avail = ocr_avail;
+ mmc->ocr_avail_sdio = ocr_avail;
+ if (host->ocr_avail_sdio)
+ mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
+ mmc->ocr_avail_sd = ocr_avail;
+ if (host->ocr_avail_sd)
+ mmc->ocr_avail_sd &= host->ocr_avail_sd;
+ else /* normal SD controllers don't support 1.8V */
+ mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
+ mmc->ocr_avail_mmc = ocr_avail;
+ if (host->ocr_avail_mmc)
+ mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any "
@@ -1896,10 +1949,14 @@ int sdhci_add_host(struct sdhci_host *host)
* of bytes. When doing hardware scatter/gather, each entry cannot
* be larger than 64 KiB though.
*/
- if (host->flags & SDHCI_USE_ADMA)
- mmc->max_seg_size = 65536;
- else
+ if (host->flags & SDHCI_USE_ADMA) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
+ mmc->max_seg_size = 65535;
+ else
+ mmc->max_seg_size = 65536;
+ } else {
mmc->max_seg_size = mmc->max_req_size;
+ }
/*
* Maximum block size. This varies from controller to controller and
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b7b8a3b28b01..6e0969e40650 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -52,6 +52,7 @@
#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f)
#define SDHCI_RESPONSE 0x10
@@ -76,7 +77,7 @@
#define SDHCI_CTRL_ADMA1 0x08
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
-#define SDHCI_CTRL_8BITBUS 0x20
+#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01
@@ -87,6 +88,9 @@
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
#define SDHCI_WAKE_UP_CONTROL 0x2B
+#define SDHCI_WAKE_ON_INT 0x01
+#define SDHCI_WAKE_ON_INSERT 0x02
+#define SDHCI_WAKE_ON_REMOVE 0x04
#define SDHCI_CLOCK_CONTROL 0x2C
#define SDHCI_DIVIDER_SHIFT 8
@@ -152,6 +156,7 @@
#define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16
+#define SDHCI_CAN_DO_8BIT 0x00040000
#define SDHCI_CAN_DO_ADMA2 0x00080000
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000
@@ -161,7 +166,7 @@
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT 0x10000000
-/* 44-47 reserved for more caps */
+#define SDHCI_CAPABILITIES_1 0x44
#define SDHCI_MAX_CURRENT 0x48
@@ -212,6 +217,8 @@ struct sdhci_ops {
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
+ int (*platform_8bit_width)(struct sdhci_host *host,
+ int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
@@ -317,6 +324,7 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
#ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
extern int sdhci_resume_host(struct sdhci_host *host);
+extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
#endif
#endif /* __SDHCI_HW_H */
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index f472c2714eb8..bbc298fd2a15 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -446,7 +446,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev,
mmc->max_seg_size = 1024 * 512;
mmc->max_blk_size = 512;
- /* reset the controler */
+ /* reset the controller */
if (sdricoh_reset(host)) {
dev_dbg(dev, "could not reset\n");
result = -EIO;
@@ -478,7 +478,7 @@ static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev)
dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device"
" %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]);
- /* search pci cardbus bridge that contains the mmc controler */
+ /* search pci cardbus bridge that contains the mmc controller */
/* the io region is already claimed by yenta_socket... */
while ((pci_dev =
pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476,
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index ddd09840520b..12884c270171 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -16,16 +16,19 @@
*
*/
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
+#include <linux/dmaengine.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
#include <linux/mmc/sh_mmcif.h>
+#include <linux/pagemap.h>
+#include <linux/platform_device.h>
#define DRIVER_NAME "sh_mmcif"
#define DRIVER_VERSION "2010-04-28"
@@ -62,25 +65,6 @@
/* CE_BLOCK_SET */
#define BLOCK_SIZE_MASK 0x0000ffff
-/* CE_CLK_CTRL */
-#define CLK_ENABLE (1 << 24) /* 1: output mmc clock */
-#define CLK_CLEAR ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define CLK_SUP_PCLK ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define SRSPTO_256 ((1 << 13) | (0 << 12)) /* resp timeout */
-#define SRBSYTO_29 ((1 << 11) | (1 << 10) | \
- (1 << 9) | (1 << 8)) /* resp busy timeout */
-#define SRWDTO_29 ((1 << 7) | (1 << 6) | \
- (1 << 5) | (1 << 4)) /* read/write timeout */
-#define SCCSTO_29 ((1 << 3) | (1 << 2) | \
- (1 << 1) | (1 << 0)) /* ccs timeout */
-
-/* CE_BUF_ACC */
-#define BUF_ACC_DMAWEN (1 << 25)
-#define BUF_ACC_DMAREN (1 << 24)
-#define BUF_ACC_BUSW_32 (0 << 17)
-#define BUF_ACC_BUSW_16 (1 << 17)
-#define BUF_ACC_ATYP (1 << 16)
-
/* CE_INT */
#define INT_CCSDE (1 << 29)
#define INT_CMD12DRE (1 << 26)
@@ -165,10 +149,6 @@
STS2_AC12BSYTO | STS2_RSPBSYTO | \
STS2_AC12RSPTO | STS2_RSPTO)
-/* CE_VERSION */
-#define SOFT_RST_ON (1 << 31)
-#define SOFT_RST_OFF (0 << 31)
-
#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */
#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
#define CLKDEV_INIT 400000 /* 400 KHz */
@@ -176,18 +156,21 @@
struct sh_mmcif_host {
struct mmc_host *mmc;
struct mmc_data *data;
- struct mmc_command *cmd;
struct platform_device *pd;
struct clk *hclk;
unsigned int clk;
int bus_width;
- u16 wait_int;
- u16 sd_error;
+ bool sd_error;
long timeout;
void __iomem *addr;
- wait_queue_head_t intr_wait;
-};
+ struct completion intr_wait;
+ /* DMA support */
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct completion dma_complete;
+ unsigned int dma_sglen;
+};
static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
unsigned int reg, u32 val)
@@ -201,6 +184,188 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
writel(~val & readl(host->addr + reg), host->addr + reg);
}
+static void mmcif_dma_complete(void *arg)
+{
+ struct sh_mmcif_host *host = arg;
+ dev_dbg(&host->pd->dev, "Command completed\n");
+
+ if (WARN(!host->data, "%s: NULL data in DMA completion!\n",
+ dev_name(&host->pd->dev)))
+ return;
+
+ if (host->data->flags & MMC_DATA_READ)
+ dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+ DMA_TO_DEVICE);
+
+ complete(&host->dma_complete);
+}
+
+static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
+{
+ struct scatterlist *sg = host->data->sg;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_rx;
+ dma_cookie_t cookie = -EINVAL;
+ int ret;
+
+ ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_FROM_DEVICE);
+ if (ret > 0) {
+ host->dma_sglen = ret;
+ desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ }
+
+ if (desc) {
+ desc->callback = mmcif_dma_complete;
+ desc->callback_param = host;
+ cookie = desc->tx_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ } else {
+ sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
+ chan->device->device_issue_pending(chan);
+ }
+ }
+ dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
+ __func__, host->data->sg_len, ret, cookie);
+
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_rx = NULL;
+ host->dma_sglen = 0;
+ dma_release_channel(chan);
+ /* Free the Tx channel too */
+ chan = host->chan_tx;
+ if (chan) {
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pd->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+ }
+
+ dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
+ desc, cookie, host->data->sg_len);
+}
+
+static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
+{
+ struct scatterlist *sg = host->data->sg;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_tx;
+ dma_cookie_t cookie = -EINVAL;
+ int ret;
+
+ ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_TO_DEVICE);
+ if (ret > 0) {
+ host->dma_sglen = ret;
+ desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ }
+
+ if (desc) {
+ desc->callback = mmcif_dma_complete;
+ desc->callback_param = host;
+ cookie = desc->tx_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ } else {
+ sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN);
+ chan->device->device_issue_pending(chan);
+ }
+ }
+ dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
+ __func__, host->data->sg_len, ret, cookie);
+
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_tx = NULL;
+ host->dma_sglen = 0;
+ dma_release_channel(chan);
+ /* Free the Rx channel too */
+ chan = host->chan_rx;
+ if (chan) {
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pd->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+ }
+
+ dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d\n", __func__,
+ desc, cookie);
+}
+
+static bool sh_mmcif_filter(struct dma_chan *chan, void *arg)
+{
+ dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
+ chan->private = arg;
+ return true;
+}
+
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
+ struct sh_mmcif_plat_data *pdata)
+{
+ host->dma_sglen = 0;
+
+ /* We can only either use DMA for both Tx and Rx or not use it at all */
+ if (pdata->dma) {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->chan_tx = dma_request_channel(mask, sh_mmcif_filter,
+ &pdata->dma->chan_priv_tx);
+ dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
+ host->chan_tx);
+
+ if (!host->chan_tx)
+ return;
+
+ host->chan_rx = dma_request_channel(mask, sh_mmcif_filter,
+ &pdata->dma->chan_priv_rx);
+ dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
+ host->chan_rx);
+
+ if (!host->chan_rx) {
+ dma_release_channel(host->chan_tx);
+ host->chan_tx = NULL;
+ return;
+ }
+
+ init_completion(&host->dma_complete);
+ }
+}
+
+static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
+{
+ sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+ /* Descriptors are freed automatically */
+ if (host->chan_tx) {
+ struct dma_chan *chan = host->chan_tx;
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ if (host->chan_rx) {
+ struct dma_chan *chan = host->chan_rx;
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+
+ host->dma_sglen = 0;
+}
static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
{
@@ -239,13 +404,12 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
u32 state1, state2;
int ret, timeout = 10000000;
- host->sd_error = 0;
- host->wait_int = 0;
+ host->sd_error = false;
state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
- pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1);
- pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2);
+ dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1);
+ dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2);
if (state1 & STS1_CMDSEQ) {
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
@@ -253,8 +417,8 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
while (1) {
timeout--;
if (timeout < 0) {
- pr_err(DRIVER_NAME": Forceed end of " \
- "command sequence timeout err\n");
+ dev_err(&host->pd->dev,
+ "Forceed end of command sequence timeout err\n");
return -EIO;
}
if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
@@ -263,18 +427,18 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
mdelay(1);
}
sh_mmcif_sync_reset(host);
- pr_debug(DRIVER_NAME": Forced end of command sequence\n");
+ dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
return -EIO;
}
if (state2 & STS2_CRC_ERR) {
- pr_debug(DRIVER_NAME": Happened CRC error\n");
+ dev_dbg(&host->pd->dev, ": Happened CRC error\n");
ret = -EIO;
} else if (state2 & STS2_TIMEOUT_ERR) {
- pr_debug(DRIVER_NAME": Happened Timeout error\n");
+ dev_dbg(&host->pd->dev, ": Happened Timeout error\n");
ret = -ETIMEDOUT;
} else {
- pr_debug(DRIVER_NAME": Happened End/Index error\n");
+ dev_dbg(&host->pd->dev, ": Happened End/Index error\n");
ret = -EIO;
}
return ret;
@@ -287,17 +451,13 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
long time;
u32 blocksize, i, *p = sg_virt(data->sg);
- host->wait_int = 0;
-
/* buf read enable */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
blocksize = (BLOCK_SIZE_MASK &
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
for (i = 0; i < blocksize / 4; i++)
@@ -305,13 +465,11 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
/* buffer read end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
return 0;
}
@@ -326,19 +484,15 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
MMCIF_CE_BLOCK_SET);
for (j = 0; j < data->sg_len; j++) {
p = sg_virt(data->sg);
- host->wait_int = 0;
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
/* buf read enable */
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
- if (host->wait_int != 1 &&
- (time == 0 || host->sd_error != 0))
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
for (i = 0; i < blocksize / 4; i++)
*p++ = sh_mmcif_readl(host->addr,
MMCIF_CE_DATA);
@@ -356,17 +510,14 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
long time;
u32 blocksize, i, *p = sg_virt(data->sg);
- host->wait_int = 0;
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
/* buf write enable */
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
blocksize = (BLOCK_SIZE_MASK &
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
for (i = 0; i < blocksize / 4; i++)
@@ -375,13 +526,11 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
/* buffer write end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
return 0;
}
@@ -397,19 +546,15 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
for (j = 0; j < data->sg_len; j++) {
p = sg_virt(data->sg);
- host->wait_int = 0;
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
/* buf write enable*/
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
- if (host->wait_int != 1 &&
- (time == 0 || host->sd_error != 0))
+ if (time <= 0 || host->sd_error)
return sh_mmcif_error_manage(host);
- host->wait_int = 0;
for (i = 0; i < blocksize / 4; i++)
sh_mmcif_writel(host->addr,
MMCIF_CE_DATA, *p++);
@@ -457,7 +602,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
tmp |= CMD_SET_RTYP_17B;
break;
default:
- pr_err(DRIVER_NAME": Not support type response.\n");
+ dev_err(&host->pd->dev, "Unsupported response type.\n");
break;
}
switch (opc) {
@@ -485,7 +630,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
tmp |= CMD_SET_DATW_8;
break;
default:
- pr_err(DRIVER_NAME": Not support bus width.\n");
+ dev_err(&host->pd->dev, "Unsupported bus width.\n");
break;
}
}
@@ -513,10 +658,10 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
return opc = ((opc << 24) | tmp);
}
-static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
+static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
struct mmc_request *mrq, u32 opc)
{
- u32 ret;
+ int ret;
switch (opc) {
case MMC_READ_MULTIPLE_BLOCK:
@@ -533,7 +678,7 @@ static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
ret = sh_mmcif_single_read(host, mrq);
break;
default:
- pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
+ dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
ret = -EINVAL;
break;
}
@@ -547,8 +692,6 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
int ret = 0, mask = 0;
u32 opc = cmd->opcode;
- host->cmd = cmd;
-
switch (opc) {
/* respons busy check */
case MMC_SWITCH:
@@ -579,13 +722,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
/* set arg */
sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
- host->wait_int = 0;
/* set cmd */
sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 || host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && time == 0) {
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0) {
cmd->error = sh_mmcif_error_manage(host);
return;
}
@@ -597,26 +739,34 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
cmd->error = -ETIMEDOUT;
break;
default:
- pr_debug("%s: Cmd(d'%d) err\n",
- DRIVER_NAME, cmd->opcode);
+ dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n",
+ cmd->opcode);
cmd->error = sh_mmcif_error_manage(host);
break;
}
- host->sd_error = 0;
- host->wait_int = 0;
+ host->sd_error = false;
return;
}
if (!(cmd->flags & MMC_RSP_PRESENT)) {
- cmd->error = ret;
- host->wait_int = 0;
+ cmd->error = 0;
return;
}
- if (host->wait_int == 1) {
- sh_mmcif_get_response(host, cmd);
- host->wait_int = 0;
- }
+ sh_mmcif_get_response(host, cmd);
if (host->data) {
- ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+ if (!host->dma_sglen) {
+ ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+ } else {
+ long time =
+ wait_for_completion_interruptible_timeout(&host->dma_complete,
+ host->timeout);
+ if (!time)
+ ret = -ETIMEDOUT;
+ else if (time < 0)
+ ret = time;
+ sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
+ BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+ host->dma_sglen = 0;
+ }
if (ret < 0)
mrq->data->bytes_xfered = 0;
else
@@ -636,20 +786,18 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
else {
- pr_err(DRIVER_NAME": not support stop cmd\n");
+ dev_err(&host->pd->dev, "unsupported stop cmd\n");
cmd->error = sh_mmcif_error_manage(host);
return;
}
- time = wait_event_interruptible_timeout(host->intr_wait,
- host->wait_int == 1 ||
- host->sd_error == 1, host->timeout);
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
+ host->timeout);
+ if (time <= 0 || host->sd_error) {
cmd->error = sh_mmcif_error_manage(host);
return;
}
sh_mmcif_get_cmd12response(host, cmd);
- host->wait_int = 0;
cmd->error = 0;
}
@@ -676,6 +824,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
break;
}
host->data = mrq->data;
+ if (mrq->data) {
+ if (mrq->data->flags & MMC_DATA_READ) {
+ if (host->chan_rx)
+ sh_mmcif_start_dma_rx(host);
+ } else {
+ if (host->chan_tx)
+ sh_mmcif_start_dma_tx(host);
+ }
+ }
sh_mmcif_start_cmd(host, mrq, mrq->cmd);
host->data = NULL;
@@ -735,7 +892,7 @@ static void sh_mmcif_detect(struct mmc_host *mmc)
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
- u32 state = 0;
+ u32 state;
int err = 0;
state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
@@ -774,17 +931,19 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
} else {
- pr_debug("%s: Not support int\n", DRIVER_NAME);
+ dev_dbg(&host->pd->dev, "Not support int\n");
sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
}
if (err) {
- host->sd_error = 1;
- pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
+ host->sd_error = true;
+ dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
}
- host->wait_int = 1;
- wake_up(&host->intr_wait);
+ if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
+ complete(&host->intr_wait);
+ else
+ dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
return IRQ_HANDLED;
}
@@ -793,8 +952,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
{
int ret = 0, irq[2];
struct mmc_host *mmc;
- struct sh_mmcif_host *host = NULL;
- struct sh_mmcif_plat_data *pd = NULL;
+ struct sh_mmcif_host *host;
+ struct sh_mmcif_plat_data *pd;
struct resource *res;
void __iomem *reg;
char clk_name[8];
@@ -802,7 +961,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
if (irq[0] < 0 || irq[1] < 0) {
- pr_err(DRIVER_NAME": Get irq error\n");
+ dev_err(&pdev->dev, "Get irq error\n");
return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -815,7 +974,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "ioremap error.\n");
return -ENOMEM;
}
- pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data);
+ pd = pdev->dev.platform_data;
if (!pd) {
dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
ret = -ENXIO;
@@ -842,7 +1001,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
host->clk = clk_get_rate(host->hclk);
host->pd = pdev;
- init_waitqueue_head(&host->intr_wait);
+ init_completion(&host->intr_wait);
mmc->ops = &sh_mmcif_ops;
mmc->f_max = host->clk;
@@ -858,33 +1017,37 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_MMC_HIGHSPEED;
if (pd->caps)
mmc->caps |= pd->caps;
- mmc->max_segs = 128;
+ mmc->max_segs = 32;
mmc->max_blk_size = 512;
- mmc->max_blk_count = 65535;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs;
+ mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
mmc->max_seg_size = mmc->max_req_size;
sh_mmcif_sync_reset(host);
platform_set_drvdata(pdev, host);
+
+ /* See if we also get DMA */
+ sh_mmcif_request_dma(host, pd);
+
mmc_add_host(mmc);
ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
if (ret) {
- pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n");
+ dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
goto clean_up2;
}
ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
if (ret) {
free_irq(irq[0], host);
- pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n");
+ dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
goto clean_up2;
}
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
sh_mmcif_detect(host->mmc);
- pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
- pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME,
+ dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
+ dev_dbg(&pdev->dev, "chip ver H'%04x\n",
sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
return ret;
@@ -903,20 +1066,22 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
int irq[2];
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
- irq[0] = platform_get_irq(pdev, 0);
- irq[1] = platform_get_irq(pdev, 1);
+ mmc_remove_host(host->mmc);
+ sh_mmcif_release_dma(host);
if (host->addr)
iounmap(host->addr);
- platform_set_drvdata(pdev, NULL);
- mmc_remove_host(host->mmc);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+
+ irq[0] = platform_get_irq(pdev, 0);
+ irq[1] = platform_get_irq(pdev, 1);
free_irq(irq[0], host);
free_irq(irq[1], host);
+ platform_set_drvdata(pdev, NULL);
+
clk_disable(host->hclk);
mmc_free_host(host->mmc);
@@ -947,5 +1112,5 @@ module_exit(sh_mmcif_exit);
MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index e7765a89593e..e3c6ef208391 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -25,16 +25,261 @@
* double buffer support
*
*/
-#include <linux/module.h>
-#include <linux/irq.h>
-#include <linux/device.h>
+
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/dmaengine.h>
-#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+#define CTL_SD_CMD 0x00
+#define CTL_ARG_REG 0x04
+#define CTL_STOP_INTERNAL_ACTION 0x08
+#define CTL_XFER_BLK_COUNT 0xa
+#define CTL_RESPONSE 0x0c
+#define CTL_STATUS 0x1c
+#define CTL_IRQ_MASK 0x20
+#define CTL_SD_CARD_CLK_CTL 0x24
+#define CTL_SD_XFER_LEN 0x26
+#define CTL_SD_MEM_CARD_OPT 0x28
+#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
+#define CTL_SD_DATA_PORT 0x30
+#define CTL_TRANSACTION_CTL 0x34
+#define CTL_SDIO_STATUS 0x36
+#define CTL_SDIO_IRQ_MASK 0x38
+#define CTL_RESET_SD 0xe0
+#define CTL_SDIO_REGS 0x100
+#define CTL_CLK_AND_WAIT_CTL 0x138
+#define CTL_RESET_SDIO 0x1e0
+
+/* Definitions for values the CTRL_STATUS register can take. */
+#define TMIO_STAT_CMDRESPEND 0x00000001
+#define TMIO_STAT_DATAEND 0x00000004
+#define TMIO_STAT_CARD_REMOVE 0x00000008
+#define TMIO_STAT_CARD_INSERT 0x00000010
+#define TMIO_STAT_SIGSTATE 0x00000020
+#define TMIO_STAT_WRPROTECT 0x00000080
+#define TMIO_STAT_CARD_REMOVE_A 0x00000100
+#define TMIO_STAT_CARD_INSERT_A 0x00000200
+#define TMIO_STAT_SIGSTATE_A 0x00000400
+#define TMIO_STAT_CMD_IDX_ERR 0x00010000
+#define TMIO_STAT_CRCFAIL 0x00020000
+#define TMIO_STAT_STOPBIT_ERR 0x00040000
+#define TMIO_STAT_DATATIMEOUT 0x00080000
+#define TMIO_STAT_RXOVERFLOW 0x00100000
+#define TMIO_STAT_TXUNDERRUN 0x00200000
+#define TMIO_STAT_CMDTIMEOUT 0x00400000
+#define TMIO_STAT_RXRDY 0x01000000
+#define TMIO_STAT_TXRQ 0x02000000
+#define TMIO_STAT_ILL_FUNC 0x20000000
+#define TMIO_STAT_CMD_BUSY 0x40000000
+#define TMIO_STAT_ILL_ACCESS 0x80000000
+
+/* Definitions for values the CTRL_SDIO_STATUS register can take. */
+#define TMIO_SDIO_STAT_IOIRQ 0x0001
+#define TMIO_SDIO_STAT_EXPUB52 0x4000
+#define TMIO_SDIO_STAT_EXWT 0x8000
+#define TMIO_SDIO_MASK_ALL 0xc007
+
+/* Define some IRQ masks */
+/* This is the mask used at reset by the chip */
+#define TMIO_MASK_ALL 0x837f031d
+#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
+#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
+#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
+ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
+#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
+
+#define enable_mmc_irqs(host, i) \
+ do { \
+ u32 mask;\
+ mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
+ mask &= ~((i) & TMIO_MASK_IRQ); \
+ sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
+ } while (0)
+
+#define disable_mmc_irqs(host, i) \
+ do { \
+ u32 mask;\
+ mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
+ mask |= ((i) & TMIO_MASK_IRQ); \
+ sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
+ } while (0)
+
+#define ack_mmc_irqs(host, i) \
+ do { \
+ sd_ctrl_write32((host), CTL_STATUS, ~(i)); \
+ } while (0)
+
+/* This is arbitrary, just noone needed any higher alignment yet */
+#define MAX_ALIGN 4
+
+struct tmio_mmc_host {
+ void __iomem *ctl;
+ unsigned long bus_shift;
+ struct mmc_command *cmd;
+ struct mmc_request *mrq;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ int irq;
+ unsigned int sdio_irq_enabled;
+
+ /* Callbacks for clock / power control */
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_clk_div)(struct platform_device *host, int state);
+
+ /* pio related stuff */
+ struct scatterlist *sg_ptr;
+ struct scatterlist *sg_orig;
+ unsigned int sg_len;
+ unsigned int sg_off;
+
+ struct platform_device *pdev;
+
+ /* DMA support */
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct tasklet_struct dma_complete;
+ struct tasklet_struct dma_issue;
+#ifdef CONFIG_TMIO_MMC_DMA
+ unsigned int dma_sglen;
+ u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN)));
+ struct scatterlist bounce_sg;
+#endif
+
+ /* Track lost interrupts */
+ struct delayed_work delayed_reset_work;
+ spinlock_t lock;
+ unsigned long last_req_ts;
+};
+
+static void tmio_check_bounce_buffer(struct tmio_mmc_host *host);
+
+static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
+{
+ return readw(host->ctl + (addr << host->bus_shift));
+}
+
+static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
+ u16 *buf, int count)
+{
+ readsw(host->ctl + (addr << host->bus_shift), buf, count);
+}
-#include "tmio_mmc.h"
+static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
+{
+ return readw(host->ctl + (addr << host->bus_shift)) |
+ readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
+}
+
+static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
+{
+ writew(val, host->ctl + (addr << host->bus_shift));
+}
+
+static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
+ u16 *buf, int count)
+{
+ writesw(host->ctl + (addr << host->bus_shift), buf, count);
+}
+
+static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
+{
+ writew(val, host->ctl + (addr << host->bus_shift));
+ writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
+}
+
+static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
+{
+ host->sg_len = data->sg_len;
+ host->sg_ptr = data->sg;
+ host->sg_orig = data->sg;
+ host->sg_off = 0;
+}
+
+static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
+{
+ host->sg_ptr = sg_next(host->sg_ptr);
+ host->sg_off = 0;
+ return --host->sg_len;
+}
+
+static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
+{
+ local_irq_save(*flags);
+ return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+}
+
+static void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags)
+{
+ kunmap_atomic(virt, KM_BIO_SRC_IRQ);
+ local_irq_restore(*flags);
+}
+
+#ifdef CONFIG_MMC_DEBUG
+
+#define STATUS_TO_TEXT(a) \
+ do { \
+ if (status & TMIO_STAT_##a) \
+ printk(#a); \
+ } while (0)
+
+void pr_debug_status(u32 status)
+{
+ printk(KERN_DEBUG "status: %08x = ", status);
+ STATUS_TO_TEXT(CARD_REMOVE);
+ STATUS_TO_TEXT(CARD_INSERT);
+ STATUS_TO_TEXT(SIGSTATE);
+ STATUS_TO_TEXT(WRPROTECT);
+ STATUS_TO_TEXT(CARD_REMOVE_A);
+ STATUS_TO_TEXT(CARD_INSERT_A);
+ STATUS_TO_TEXT(SIGSTATE_A);
+ STATUS_TO_TEXT(CMD_IDX_ERR);
+ STATUS_TO_TEXT(STOPBIT_ERR);
+ STATUS_TO_TEXT(ILL_FUNC);
+ STATUS_TO_TEXT(CMD_BUSY);
+ STATUS_TO_TEXT(CMDRESPEND);
+ STATUS_TO_TEXT(DATAEND);
+ STATUS_TO_TEXT(CRCFAIL);
+ STATUS_TO_TEXT(DATATIMEOUT);
+ STATUS_TO_TEXT(CMDTIMEOUT);
+ STATUS_TO_TEXT(RXOVERFLOW);
+ STATUS_TO_TEXT(TXUNDERRUN);
+ STATUS_TO_TEXT(RXRDY);
+ STATUS_TO_TEXT(TXRQ);
+ STATUS_TO_TEXT(ILL_ACCESS);
+ printk("\n");
+}
+
+#else
+#define pr_debug_status(s) do { } while (0)
+#endif
+
+static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ if (enable) {
+ host->sdio_irq_enabled = 1;
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK,
+ (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ));
+ } else {
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL);
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+ host->sdio_irq_enabled = 0;
+ }
+}
static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
{
@@ -55,8 +300,23 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
{
+ struct mfd_cell *cell = host->pdev->dev.platform_data;
+ struct tmio_mmc_data *pdata = cell->driver_data;
+
+ /*
+ * Testing on sh-mobile showed that SDIO IRQs are unmasked when
+ * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the
+ * device IRQ here and restore the SDIO IRQ mask before
+ * re-enabling the device IRQ.
+ */
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ disable_irq(host->irq);
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
msleep(10);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
+ enable_irq(host->irq);
+ }
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(10);
@@ -64,11 +324,21 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
{
+ struct mfd_cell *cell = host->pdev->dev.platform_data;
+ struct tmio_mmc_data *pdata = cell->driver_data;
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(10);
+ /* see comment in tmio_mmc_clk_stop above */
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ disable_irq(host->irq);
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
msleep(10);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
+ enable_irq(host->irq);
+ }
}
static void reset(struct tmio_mmc_host *host)
@@ -82,15 +352,60 @@ static void reset(struct tmio_mmc_host *host)
msleep(10);
}
+static void tmio_mmc_reset_work(struct work_struct *work)
+{
+ struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
+ delayed_reset_work.work);
+ struct mmc_request *mrq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ mrq = host->mrq;
+
+ /* request already finished */
+ if (!mrq
+ || time_is_after_jiffies(host->last_req_ts +
+ msecs_to_jiffies(2000))) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ dev_warn(&host->pdev->dev,
+ "timeout waiting for hardware interrupt (CMD%u)\n",
+ mrq->cmd->opcode);
+
+ if (host->data)
+ host->data->error = -ETIMEDOUT;
+ else if (host->cmd)
+ host->cmd->error = -ETIMEDOUT;
+ else
+ mrq->cmd->error = -ETIMEDOUT;
+
+ host->cmd = NULL;
+ host->data = NULL;
+ host->mrq = NULL;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ reset(host);
+
+ mmc_request_done(host->mmc, mrq);
+}
+
static void
tmio_mmc_finish_request(struct tmio_mmc_host *host)
{
struct mmc_request *mrq = host->mrq;
+ if (!mrq)
+ return;
+
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
+ cancel_delayed_work(&host->delayed_reset_work);
+
mmc_request_done(host->mmc, mrq);
}
@@ -200,6 +515,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
return;
}
+/* needs to be called with host->lock held */
static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
{
struct mmc_data *data = host->data;
@@ -233,6 +549,8 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
if (data->flags & MMC_DATA_READ) {
if (!host->chan_rx)
disable_mmc_irqs(host, TMIO_MASK_READOP);
+ else
+ tmio_check_bounce_buffer(host);
dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
host->mrq);
} else {
@@ -254,10 +572,12 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
{
- struct mmc_data *data = host->data;
+ struct mmc_data *data;
+ spin_lock(&host->lock);
+ data = host->data;
if (!data)
- return;
+ goto out;
if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) {
/*
@@ -278,6 +598,8 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
} else {
tmio_mmc_do_data_irq(host);
}
+out:
+ spin_unlock(&host->lock);
}
static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
@@ -286,9 +608,11 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
struct mmc_command *cmd = host->cmd;
int i, addr;
+ spin_lock(&host->lock);
+
if (!host->cmd) {
pr_debug("Spurious CMD irq\n");
- return;
+ goto out;
}
host->cmd = NULL;
@@ -324,8 +648,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
if (!host->chan_rx)
enable_mmc_irqs(host, TMIO_MASK_READOP);
} else {
- struct dma_chan *chan = host->chan_tx;
- if (!chan)
+ if (!host->chan_tx)
enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
else
tasklet_schedule(&host->dma_issue);
@@ -334,13 +657,19 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
tmio_mmc_finish_request(host);
}
+out:
+ spin_unlock(&host->lock);
+
return;
}
static irqreturn_t tmio_mmc_irq(int irq, void *devid)
{
struct tmio_mmc_host *host = devid;
+ struct mfd_cell *cell = host->pdev->dev.platform_data;
+ struct tmio_mmc_data *pdata = cell->driver_data;
unsigned int ireg, irq_mask, status;
+ unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
pr_debug("MMC IRQ begin\n");
@@ -348,6 +677,29 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
ireg = status & TMIO_MASK_IRQ & ~irq_mask;
+ sdio_ireg = 0;
+ if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
+ sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
+ sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask;
+
+ sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
+
+ if (sdio_ireg && !host->sdio_irq_enabled) {
+ pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
+ sdio_status, sdio_irq_mask, sdio_ireg);
+ tmio_mmc_enable_sdio_irq(host->mmc, 0);
+ goto out;
+ }
+
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ &&
+ sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (sdio_ireg)
+ goto out;
+ }
+
pr_debug_status(status);
pr_debug_status(ireg);
@@ -375,8 +727,10 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
*/
/* Command completion */
- if (ireg & TMIO_MASK_CMD) {
- ack_mmc_irqs(host, TMIO_MASK_CMD);
+ if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
+ ack_mmc_irqs(host,
+ TMIO_STAT_CMDRESPEND |
+ TMIO_STAT_CMDTIMEOUT);
tmio_mmc_cmd_irq(host, status);
}
@@ -407,6 +761,16 @@ out:
}
#ifdef CONFIG_TMIO_MMC_DMA
+static void tmio_check_bounce_buffer(struct tmio_mmc_host *host)
+{
+ if (host->sg_ptr == &host->bounce_sg) {
+ unsigned long flags;
+ void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
+ memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
+ tmio_mmc_kunmap_atomic(sg_vaddr, &flags);
+ }
+}
+
static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
{
#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
@@ -427,12 +791,39 @@ static void tmio_dma_complete(void *arg)
enable_mmc_irqs(host, TMIO_STAT_DATAEND);
}
-static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
+static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
{
- struct scatterlist *sg = host->sg_ptr;
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_rx;
- int ret;
+ struct mfd_cell *cell = host->pdev->dev.platform_data;
+ struct tmio_mmc_data *pdata = cell->driver_data;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ align >= MAX_ALIGN)) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE);
if (ret > 0) {
@@ -442,21 +833,21 @@ static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
}
if (desc) {
- host->desc = desc;
desc->callback = tmio_dma_complete;
desc->callback_param = host;
- host->cookie = desc->tx_submit(desc);
- if (host->cookie < 0) {
- host->desc = NULL;
- ret = host->cookie;
+ cookie = desc->tx_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
} else {
chan->device->device_issue_pending(chan);
}
}
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, host->cookie, host->mrq);
+ __func__, host->sg_len, ret, cookie, host->mrq);
- if (!host->desc) {
+pio:
+ if (!desc) {
/* DMA failed, fall back to PIO */
if (ret >= 0)
ret = -EIO;
@@ -471,24 +862,49 @@ static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret);
tmio_mmc_enable_dma(host, false);
- reset(host);
- /* Fail this request, let above layers recover */
- host->mrq->cmd->error = ret;
- tmio_mmc_finish_request(host);
}
dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
- desc, host->cookie, host->sg_len);
-
- return ret > 0 ? 0 : ret;
+ desc, cookie, host->sg_len);
}
-static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
+static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
{
- struct scatterlist *sg = host->sg_ptr;
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_tx;
- int ret;
+ struct mfd_cell *cell = host->pdev->dev.platform_data;
+ struct tmio_mmc_data *pdata = cell->driver_data;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ align >= MAX_ALIGN)) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ unsigned long flags;
+ void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
+ tmio_mmc_kunmap_atomic(sg_vaddr, &flags);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0) {
@@ -498,19 +914,19 @@ static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
}
if (desc) {
- host->desc = desc;
desc->callback = tmio_dma_complete;
desc->callback_param = host;
- host->cookie = desc->tx_submit(desc);
- if (host->cookie < 0) {
- host->desc = NULL;
- ret = host->cookie;
+ cookie = desc->tx_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
}
}
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, host->cookie, host->mrq);
+ __func__, host->sg_len, ret, cookie, host->mrq);
- if (!host->desc) {
+pio:
+ if (!desc) {
/* DMA failed, fall back to PIO */
if (ret >= 0)
ret = -EIO;
@@ -525,30 +941,22 @@ static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret);
tmio_mmc_enable_dma(host, false);
- reset(host);
- /* Fail this request, let above layers recover */
- host->mrq->cmd->error = ret;
- tmio_mmc_finish_request(host);
}
dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
- desc, host->cookie);
-
- return ret > 0 ? 0 : ret;
+ desc, cookie);
}
-static int tmio_mmc_start_dma(struct tmio_mmc_host *host,
+static void tmio_mmc_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
if (data->flags & MMC_DATA_READ) {
if (host->chan_rx)
- return tmio_mmc_start_dma_rx(host);
+ tmio_mmc_start_dma_rx(host);
} else {
if (host->chan_tx)
- return tmio_mmc_start_dma_tx(host);
+ tmio_mmc_start_dma_tx(host);
}
-
- return 0;
}
static void tmio_issue_tasklet_fn(unsigned long priv)
@@ -562,6 +970,12 @@ static void tmio_issue_tasklet_fn(unsigned long priv)
static void tmio_tasklet_fn(unsigned long arg)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (!host->data)
+ goto out;
if (host->data->flags & MMC_DATA_READ)
dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen,
@@ -571,6 +985,8 @@ static void tmio_tasklet_fn(unsigned long arg)
DMA_TO_DEVICE);
tmio_mmc_do_data_irq(host);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
}
/* It might be necessary to make filter MFD specific */
@@ -584,9 +1000,6 @@ static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata)
{
- host->cookie = -EINVAL;
- host->desc = NULL;
-
/* We can only either use DMA for both Tx and Rx or not use it at all */
if (pdata->dma) {
dma_cap_mask_t mask;
@@ -632,15 +1045,15 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
host->chan_rx = NULL;
dma_release_channel(chan);
}
-
- host->cookie = -EINVAL;
- host->desc = NULL;
}
#else
-static int tmio_mmc_start_dma(struct tmio_mmc_host *host,
+static void tmio_check_bounce_buffer(struct tmio_mmc_host *host)
+{
+}
+
+static void tmio_mmc_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
- return 0;
}
static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
@@ -682,7 +1095,9 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
- return tmio_mmc_start_dma(host, data);
+ tmio_mmc_start_dma(host, data);
+
+ return 0;
}
/* Process requests from the MMC layer */
@@ -694,6 +1109,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (host->mrq)
pr_debug("request not null\n");
+ host->last_req_ts = jiffies;
+ wmb();
host->mrq = mrq;
if (mrq->data) {
@@ -703,10 +1120,14 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
ret = tmio_mmc_start_command(host, mrq->cmd);
- if (!ret)
+ if (!ret) {
+ schedule_delayed_work(&host->delayed_reset_work,
+ msecs_to_jiffies(2000));
return;
+ }
fail:
+ host->mrq = NULL;
mrq->cmd->error = ret;
mmc_request_done(mmc, mrq);
}
@@ -780,6 +1201,7 @@ static const struct mmc_host_ops tmio_mmc_ops = {
.set_ios = tmio_mmc_set_ios,
.get_ro = tmio_mmc_get_ro,
.get_cd = tmio_mmc_get_cd,
+ .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
};
#ifdef CONFIG_PM
@@ -864,10 +1286,15 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
goto host_free;
mmc->ops = &tmio_mmc_ops;
- mmc->caps = MMC_CAP_4_BIT_DATA;
- mmc->caps |= pdata->capabilities;
+ mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->f_max = pdata->hclk;
mmc->f_min = mmc->f_max / 512;
+ mmc->max_segs = 32;
+ mmc->max_blk_size = 512;
+ mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
+ mmc->max_segs;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
if (pdata->ocr_mask)
mmc->ocr_avail = pdata->ocr_mask;
else
@@ -890,12 +1317,19 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
goto cell_disable;
disable_mmc_irqs(host, TMIO_MASK_ALL);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ tmio_mmc_enable_sdio_irq(mmc, 0);
ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host);
if (ret)
goto cell_disable;
+ spin_lock_init(&host->lock);
+
+ /* Init delayed work for request timeouts */
+ INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work);
+
/* See if we also get DMA */
tmio_mmc_request_dma(host, pdata);
@@ -934,6 +1368,7 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
if (mmc) {
struct tmio_mmc_host *host = mmc_priv(mmc);
mmc_remove_host(mmc);
+ cancel_delayed_work_sync(&host->delayed_reset_work);
tmio_mmc_release_dma(host);
free_irq(host->irq, host);
if (cell->disable)
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
deleted file mode 100644
index 0fedc78e3ea5..000000000000
--- a/drivers/mmc/host/tmio_mmc.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/* Definitons for use with the tmio_mmc.c
- *
- * (c) 2004 Ian Molton <spyro@f2s.com>
- * (c) 2007 Ian Molton <spyro@f2s.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/dmaengine.h>
-
-#define CTL_SD_CMD 0x00
-#define CTL_ARG_REG 0x04
-#define CTL_STOP_INTERNAL_ACTION 0x08
-#define CTL_XFER_BLK_COUNT 0xa
-#define CTL_RESPONSE 0x0c
-#define CTL_STATUS 0x1c
-#define CTL_IRQ_MASK 0x20
-#define CTL_SD_CARD_CLK_CTL 0x24
-#define CTL_SD_XFER_LEN 0x26
-#define CTL_SD_MEM_CARD_OPT 0x28
-#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
-#define CTL_SD_DATA_PORT 0x30
-#define CTL_TRANSACTION_CTL 0x34
-#define CTL_RESET_SD 0xe0
-#define CTL_SDIO_REGS 0x100
-#define CTL_CLK_AND_WAIT_CTL 0x138
-#define CTL_RESET_SDIO 0x1e0
-
-/* Definitions for values the CTRL_STATUS register can take. */
-#define TMIO_STAT_CMDRESPEND 0x00000001
-#define TMIO_STAT_DATAEND 0x00000004
-#define TMIO_STAT_CARD_REMOVE 0x00000008
-#define TMIO_STAT_CARD_INSERT 0x00000010
-#define TMIO_STAT_SIGSTATE 0x00000020
-#define TMIO_STAT_WRPROTECT 0x00000080
-#define TMIO_STAT_CARD_REMOVE_A 0x00000100
-#define TMIO_STAT_CARD_INSERT_A 0x00000200
-#define TMIO_STAT_SIGSTATE_A 0x00000400
-#define TMIO_STAT_CMD_IDX_ERR 0x00010000
-#define TMIO_STAT_CRCFAIL 0x00020000
-#define TMIO_STAT_STOPBIT_ERR 0x00040000
-#define TMIO_STAT_DATATIMEOUT 0x00080000
-#define TMIO_STAT_RXOVERFLOW 0x00100000
-#define TMIO_STAT_TXUNDERRUN 0x00200000
-#define TMIO_STAT_CMDTIMEOUT 0x00400000
-#define TMIO_STAT_RXRDY 0x01000000
-#define TMIO_STAT_TXRQ 0x02000000
-#define TMIO_STAT_ILL_FUNC 0x20000000
-#define TMIO_STAT_CMD_BUSY 0x40000000
-#define TMIO_STAT_ILL_ACCESS 0x80000000
-
-/* Define some IRQ masks */
-/* This is the mask used at reset by the chip */
-#define TMIO_MASK_ALL 0x837f031d
-#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
-#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
-#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
- TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
-#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
-
-
-#define enable_mmc_irqs(host, i) \
- do { \
- u32 mask;\
- mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
- mask &= ~((i) & TMIO_MASK_IRQ); \
- sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
- } while (0)
-
-#define disable_mmc_irqs(host, i) \
- do { \
- u32 mask;\
- mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
- mask |= ((i) & TMIO_MASK_IRQ); \
- sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
- } while (0)
-
-#define ack_mmc_irqs(host, i) \
- do { \
- sd_ctrl_write32((host), CTL_STATUS, ~(i)); \
- } while (0)
-
-
-struct tmio_mmc_host {
- void __iomem *ctl;
- unsigned long bus_shift;
- struct mmc_command *cmd;
- struct mmc_request *mrq;
- struct mmc_data *data;
- struct mmc_host *mmc;
- int irq;
-
- /* Callbacks for clock / power control */
- void (*set_pwr)(struct platform_device *host, int state);
- void (*set_clk_div)(struct platform_device *host, int state);
-
- /* pio related stuff */
- struct scatterlist *sg_ptr;
- unsigned int sg_len;
- unsigned int sg_off;
-
- struct platform_device *pdev;
-
- /* DMA support */
- struct dma_chan *chan_rx;
- struct dma_chan *chan_tx;
- struct tasklet_struct dma_complete;
- struct tasklet_struct dma_issue;
-#ifdef CONFIG_TMIO_MMC_DMA
- struct dma_async_tx_descriptor *desc;
- unsigned int dma_sglen;
- dma_cookie_t cookie;
-#endif
-};
-
-#include <linux/io.h>
-
-static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift));
-}
-
-static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- readsw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift)) |
- readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
-}
-
-static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr,
- u16 val)
-{
- writew(val, host->ctl + (addr << host->bus_shift));
-}
-
-static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- writesw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
- u32 val)
-{
- writew(val, host->ctl + (addr << host->bus_shift));
- writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
-}
-
-#include <linux/scatterlist.h>
-#include <linux/blkdev.h>
-
-static inline void tmio_mmc_init_sg(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- host->sg_len = data->sg_len;
- host->sg_ptr = data->sg;
- host->sg_off = 0;
-}
-
-static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host)
-{
- host->sg_ptr = sg_next(host->sg_ptr);
- host->sg_off = 0;
- return --host->sg_len;
-}
-
-static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
- unsigned long *flags)
-{
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void tmio_mmc_kunmap_atomic(void *virt,
- unsigned long *flags)
-{
- kunmap_atomic(virt, KM_BIO_SRC_IRQ);
- local_irq_restore(*flags);
-}
-
-#ifdef CONFIG_MMC_DEBUG
-
-#define STATUS_TO_TEXT(a) \
- do { \
- if (status & TMIO_STAT_##a) \
- printk(#a); \
- } while (0)
-
-void pr_debug_status(u32 status)
-{
- printk(KERN_DEBUG "status: %08x = ", status);
- STATUS_TO_TEXT(CARD_REMOVE);
- STATUS_TO_TEXT(CARD_INSERT);
- STATUS_TO_TEXT(SIGSTATE);
- STATUS_TO_TEXT(WRPROTECT);
- STATUS_TO_TEXT(CARD_REMOVE_A);
- STATUS_TO_TEXT(CARD_INSERT_A);
- STATUS_TO_TEXT(SIGSTATE_A);
- STATUS_TO_TEXT(CMD_IDX_ERR);
- STATUS_TO_TEXT(STOPBIT_ERR);
- STATUS_TO_TEXT(ILL_FUNC);
- STATUS_TO_TEXT(CMD_BUSY);
- STATUS_TO_TEXT(CMDRESPEND);
- STATUS_TO_TEXT(DATAEND);
- STATUS_TO_TEXT(CRCFAIL);
- STATUS_TO_TEXT(DATATIMEOUT);
- STATUS_TO_TEXT(CMDTIMEOUT);
- STATUS_TO_TEXT(RXOVERFLOW);
- STATUS_TO_TEXT(TXUNDERRUN);
- STATUS_TO_TEXT(RXRDY);
- STATUS_TO_TEXT(TXRQ);
- STATUS_TO_TEXT(ILL_ACCESS);
- printk("\n");
-}
-
-#else
-#define pr_debug_status(s) do { } while (0)
-#endif
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
index b4ead4a13c98..f8f65df9b017 100644
--- a/drivers/mmc/host/ushc.c
+++ b/drivers/mmc/host/ushc.c
@@ -425,7 +425,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct mmc_host *mmc;
struct ushc_data *ushc;
- int ret = -ENOMEM;
+ int ret;
mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
if (mmc == NULL)
@@ -462,11 +462,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
mmc->max_blk_count = 511;
ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->int_urb == NULL)
+ if (ushc->int_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
- if (ushc->int_data == NULL)
+ if (ushc->int_data == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
usb_rcvintpipe(usb_dev,
intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
@@ -475,11 +479,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
intf->cur_altsetting->endpoint[0].desc.bInterval);
ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->cbw_urb == NULL)
+ if (ushc->cbw_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->cbw == NULL)
+ if (ushc->cbw == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->cbw->signature = USHC_CBW_SIGNATURE;
usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
@@ -487,15 +495,21 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
cbw_callback, ushc);
ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->data_urb == NULL)
+ if (ushc->data_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->csw_urb == NULL)
+ if (ushc->csw_urb == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->csw == NULL)
+ if (ushc->csw == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
ushc->csw, sizeof(struct ushc_csw),
csw_callback, ushc);
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 2cf0cc6a4189..f29a6f9df6e7 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -224,7 +224,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
if (dev->blkdev) {
invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
0, -1);
- close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
+ blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
kfree(dev);
@@ -234,6 +234,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
/* FIXME: ensure that mtd->size % erase_size == 0 */
static struct block2mtd_dev *add_device(char *devname, int erase_size)
{
+ const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev;
struct block2mtd_dev *dev;
char *name;
@@ -246,7 +247,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
return NULL;
/* Get a handle on the device */
- bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
+ bdev = blkdev_get_by_path(devname, mode, dev);
#ifndef MODULE
if (IS_ERR(bdev)) {
@@ -254,9 +255,8 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
to resolve the device name by other means. */
dev_t devt = name_to_dev_t(devname);
- if (devt) {
- bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
- }
+ if (devt)
+ bdev = blkdev_get_by_dev(devt, mode, dev);
}
#endif
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index a0dd7bba9481..5d37d315fa98 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -72,7 +72,7 @@ config MTD_PHYSMAP_BANKWIDTH
config MTD_PHYSMAP_OF
tristate "Flash device in physical memory map based on OF description"
- depends on (MICROBLAZE || PPC_OF) && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
+ depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
help
This provides a 'mapping' driver which allows the NOR Flash and
ROM driver code to communicate with chips which are mapped
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index dd90880048cf..d8ae634d347e 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -51,7 +51,7 @@ struct pxa2xx_flash_info {
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-static int __init pxa2xx_flash_probe(struct platform_device *pdev)
+static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
{
struct flash_platform_data *flash = pdev->dev.platform_data;
struct pxa2xx_flash_info *info;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 16de17b5b829..145b3d0dc0db 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1134,7 +1134,7 @@ static const struct file_operations mtd_fops = {
static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
- return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC);
+ return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC);
}
static struct file_system_type mtd_inodefs_type = {
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 8b102736b34a..e3e40f440323 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -307,6 +307,11 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
unsigned long l1_cpy, l2_cpy;
char *dst;
+ if (reason != KMSG_DUMP_OOPS &&
+ reason != KMSG_DUMP_PANIC &&
+ reason != KMSG_DUMP_KEXEC)
+ return;
+
/* Only dump oopses if dump_oops is set */
if (reason == KMSG_DUMP_OOPS && !dump_oops)
return;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 4915067379b8..a9c6ce745767 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -821,7 +821,7 @@ retry:
*
* Wait for command done. This is a helper function for nand_wait used when
* we are in interrupt context. May happen when in panic and trying to write
- * an oops trough mtdoops.
+ * an oops through mtdoops.
*/
static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
unsigned long timeo)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index cd41c58b5bbd..15682ec8530e 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -7,7 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#define CONFIG_MTD_NAND_OMAP_HWECC
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 1a07bfcc70d4..ac31f461cc1c 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -767,6 +767,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
case 3:
c->freq = 83;
break;
+ case 4:
+ c->freq = 104;
+ break;
}
#ifdef CONFIG_MTD_PARTITIONS
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index c2960ac9f39c..811775aa8ee8 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -482,10 +482,17 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
uint32_t data = 0;
struct ubi_vid_hdr vid_hdr;
- addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
+ /*
+ * It is important to first invalidate the EC header, and then the VID
+ * header. Otherwise a power cut may lead to valid EC header and
+ * invalid VID header, in which case UBI will treat this PEB as
+ * corrupted and will try to preserve it, and print scary warnings (see
+ * the header comment in scan.c for more information).
+ */
+ addr = (loff_t)pnum * ubi->peb_size;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
if (!err) {
- addr -= ubi->vid_hdr_aloffset;
+ addr += ubi->vid_hdr_aloffset;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
(void *)&data);
if (!err)
@@ -494,18 +501,24 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
/*
* We failed to write to the media. This was observed with Spansion
- * S29GL512N NOR flash. Most probably the eraseblock erasure was
- * interrupted at a very inappropriate moment, so it became unwritable.
- * In this case we probably anyway have garbage in this PEB.
+ * S29GL512N NOR flash. Most probably the previously eraseblock erasure
+ * was interrupted at a very inappropriate moment, so it became
+ * unwritable. In this case we probably anyway have garbage in this
+ * PEB.
*/
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
- if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
- /*
- * The VID header is corrupted, so we can safely erase this
- * PEB and not afraid that it will be treated as a valid PEB in
- * case of an unclean reboot.
- */
- return 0;
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
+ struct ubi_ec_hdr ec_hdr;
+
+ err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
+ /*
+ * Both VID and EC headers are corrupted, so we can
+ * safely erase this PEB and not afraid that it will be
+ * treated as a valid PEB in case of an unclean reboot.
+ */
+ return 0;
+ }
/*
* The PEB contains a valid VID header, but we cannot invalidate it.
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 3c631863bf40..79ca304fc4db 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -787,16 +787,15 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
* erased, so it became unstable and corrupted, and should be
* erased.
*/
- return 0;
+ err = 0;
+ goto out_unlock;
}
if (err)
- return err;
+ goto out_unlock;
- if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size)) {
- mutex_unlock(&ubi->buf_mutex);
- return 0;
- }
+ if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
+ goto out_unlock;
ubi_err("PEB %d contains corrupted VID header, and the data does not "
"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
@@ -806,8 +805,11 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
pnum, ubi->leb_start, ubi->leb_size);
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->peb_buf1, ubi->leb_size, 1);
+ err = 1;
+
+out_unlock:
mutex_unlock(&ubi->buf_mutex);
- return 1;
+ return err;
}
/**
@@ -951,6 +953,10 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* impossible to distinguish it from a PEB which just
* contains garbage because of a power cut during erase
* operation. So we just schedule this PEB for erasure.
+ *
+ * Besides, in case of NOR flash, we deliberatly
+ * corrupt both headers because NOR flash erasure is
+ * slow and can start from the end.
*/
err = 0;
else
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 1776ab61b05f..9e1c03eb97ae 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -158,8 +158,8 @@ static int mem_start;
struct net_device * __init el1_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static unsigned ports[] = { 0x280, 0x300, 0};
- unsigned *port;
+ static const unsigned ports[] = { 0x280, 0x300, 0};
+ const unsigned *port;
int err = 0;
if (!dev)
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 4777a1cbcd8d..d84f6e8903a5 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -392,8 +392,8 @@ el2_open(struct net_device *dev)
int retval;
if (dev->irq < 2) {
- int irqlist[] = {5, 9, 3, 4, 0};
- int *irqp = irqlist;
+ static const int irqlist[] = {5, 9, 3, 4, 0};
+ const int *irqp = irqlist;
outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */
do {
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index ea9b7a098c9b..1e945551c144 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -201,7 +201,7 @@ struct net_local {
#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
#define RX_BUF_END (dev->mem_end - dev->mem_start)
-#define TX_TIMEOUT 5
+#define TX_TIMEOUT (HZ/20)
/*
That's it: only 86 bytes to set up the beast, including every extra
@@ -311,8 +311,8 @@ static int mem_start;
struct net_device * __init el16_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
- unsigned *port;
+ static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
+ const unsigned *port;
int err = -ENODEV;
if (!dev)
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index cdf7226a7c43..d2bb4b254c57 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -98,7 +98,7 @@ static int rx_nocopy, rx_copy, queued_packet;
#define WAIT_TX_AVAIL 200
/* Operational parameter that usually are not changed. */
-#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT ((4*HZ)/10) /* Time in jiffies before concluding Tx hung */
/* The size here is somewhat misleading: the Corkscrew also uses the ISA
aliased registers at <base>+0x400.
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 013b7c396663..8c094bae8bf3 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -317,13 +317,13 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
u8 POS;
u32 base;
struct mc32_local *lp = netdev_priv(dev);
- static u16 mca_io_bases[]={
+ static const u16 mca_io_bases[] = {
0x7280,0x7290,
0x7680,0x7690,
0x7A80,0x7A90,
0x7E80,0x7E90
};
- static u32 mca_mem_bases[]={
+ static const u32 mca_mem_bases[] = {
0x00C0000,
0x00C4000,
0x00C8000,
@@ -333,7 +333,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
0x00D8000,
0x00DC000
};
- static char *failures[]={
+ static const char * const failures[] = {
"Processor instruction",
"Processor data bus",
"Processor data bus",
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index e1da258bbfb7..0a92436f0538 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -699,7 +699,8 @@ DEFINE_WINDOW_IO(32)
#define DEVICE_PCI(dev) NULL
#endif
-#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)
+#define VORTEX_PCI(vp) \
+ ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
#ifdef CONFIG_EISA
#define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
@@ -707,7 +708,8 @@ DEFINE_WINDOW_IO(32)
#define DEVICE_EISA(dev) NULL
#endif
-#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)
+#define VORTEX_EISA(vp) \
+ ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
/* The action to take with a media selection timer tick.
Note that we deviate from the 3Com order by checking 10base2 before AUI.
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index ac422cd332ea..dd16e83933a2 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -490,13 +490,11 @@ static inline unsigned int cp_rx_csum_ok (u32 status)
{
unsigned int protocol = (status >> 16) & 0x3;
- if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
+ if (((protocol == RxProtoTCP) && !(status & TCPFail)) ||
+ ((protocol == RxProtoUDP) && !(status & UDPFail)))
return 1;
- else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
- return 1;
- else if ((protocol == RxProtoIP) && (!(status & IPFail)))
- return 1;
- return 0;
+ else
+ return 0;
}
static int cp_rx_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index f5166dccd8df..98517a373473 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1092,10 +1092,11 @@ err_out:
static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
+ struct rtl8139_private *tp = netdev_priv(dev);
assert (dev != NULL);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&tp->thread);
unregister_netdev (dev);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index e2c9c5b949f9..be1f1970c842 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -191,7 +191,7 @@ enum commands {
#define RX_SUSPEND 0x0030
#define RX_ABORT 0x0040
-#define TX_TIMEOUT 5
+#define TX_TIMEOUT (HZ/20)
struct i596_reg {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f6668cdaac85..16fe4f9b719b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1533,7 +1533,7 @@ config E100
<http://support.intel.com/support/network/adapter/pro100/21397.htm>
- to identify the adapter.
+ to identify the adapter.
For the latest Intel PRO/100 network driver for Linux, see:
@@ -1786,17 +1786,17 @@ config KS8842
tristate "Micrel KSZ8841/42 with generic bus interface"
depends on HAS_IOMEM && DMA_ENGINE
help
- This platform driver is for KSZ8841(1-port) / KS8842(2-port)
- ethernet switch chip (managed, VLAN, QoS) from Micrel or
- Timberdale(FPGA).
+ This platform driver is for KSZ8841(1-port) / KS8842(2-port)
+ ethernet switch chip (managed, VLAN, QoS) from Micrel or
+ Timberdale(FPGA).
config KS8851
- tristate "Micrel KS8851 SPI"
- depends on SPI
- select MII
+ tristate "Micrel KS8851 SPI"
+ depends on SPI
+ select MII
select CRC32
- help
- SPI driver for Micrel KS8851 SPI attached network chip.
+ help
+ SPI driver for Micrel KS8851 SPI attached network chip.
config KS8851_MLL
tristate "Micrel KS8851 MLL"
@@ -1944,19 +1944,12 @@ config 68360_ENET
config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
- MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5
+ MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5 || SOC_IMX28
select PHYLIB
help
Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors.
-config FEC2
- bool "Second FEC ethernet controller (on some ColdFire CPUs)"
- depends on FEC
- help
- Say Y here if you want to use the second built-in 10/100 Fast
- ethernet controller on some Motorola ColdFire processors.
-
config FEC_MPC52xx
tristate "MPC52xx FEC driver"
depends on PPC_MPC52xx && PPC_BESTCOMM
@@ -2133,25 +2126,25 @@ config IP1000
will be called ipg. This is recommended.
config IGB
- tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
- depends on PCI
- ---help---
- This driver supports Intel(R) 82575/82576 gigabit ethernet family of
- adapters. For more information on how to identify your adapter, go
- to the Adapter & Driver ID Guide at:
+ tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 82575/82576 gigabit ethernet 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>
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
- For general information and support, go to the Intel support
- website at:
+ For general information and support, go to the Intel support
+ website at:
- <http://support.intel.com>
+ <http://support.intel.com>
- More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.txt>.
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000.txt>.
- To compile this driver as a module, choose M here. The module
- will be called igb.
+ To compile this driver as a module, choose M here. The module
+ will be called igb.
config IGB_DCA
bool "Direct Cache Access (DCA) Support"
@@ -2163,25 +2156,25 @@ config IGB_DCA
is used, with the intent of lessening the impact of cache misses.
config IGBVF
- tristate "Intel(R) 82576 Virtual Function Ethernet support"
- depends on PCI
- ---help---
- This driver supports Intel(R) 82576 virtual functions. For more
- information on how to identify your adapter, go to the Adapter &
- Driver ID Guide at:
+ tristate "Intel(R) 82576 Virtual Function Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 82576 virtual functions. For more
+ information on how to identify your adapter, go to the Adapter &
+ Driver ID Guide at:
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
- For general information and support, go to the Intel support
- website at:
+ For general information and support, go to the Intel support
+ website at:
- <http://support.intel.com>
+ <http://support.intel.com>
- More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.txt>.
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000.txt>.
- To compile this driver as a module, choose M here. The module
- will be called igbvf.
+ To compile this driver as a module, choose M here. The module
+ will be called igbvf.
source "drivers/net/ixp2000/Kconfig"
@@ -2233,6 +2226,7 @@ config YELLOWFIN
config R8169
tristate "Realtek 8169 gigabit ethernet support"
depends on PCI
+ select FW_LOADER
select CRC32
select MII
---help---
@@ -2300,14 +2294,14 @@ config SKGE
will be called skge. This is recommended.
config SKGE_DEBUG
- bool "Debugging interface"
- depends on SKGE && DEBUG_FS
- help
- This option adds the ability to dump driver state for debugging.
- The file /sys/kernel/debug/skge/ethX displays the state of the internal
- transmit and receive rings.
+ bool "Debugging interface"
+ depends on SKGE && DEBUG_FS
+ help
+ This option adds the ability to dump driver state for debugging.
+ The file /sys/kernel/debug/skge/ethX displays the state of the internal
+ transmit and receive rings.
- If unsure, say N.
+ If unsure, say N.
config SKY2
tristate "SysKonnect Yukon2 support"
@@ -2326,14 +2320,14 @@ config SKY2
will be called sky2. This is recommended.
config SKY2_DEBUG
- bool "Debugging interface"
- depends on SKY2 && DEBUG_FS
- help
- This option adds the ability to dump driver state for debugging.
- The file /sys/kernel/debug/sky2/ethX displays the state of the internal
- transmit and receive rings.
+ bool "Debugging interface"
+ depends on SKY2 && DEBUG_FS
+ help
+ This option adds the ability to dump driver state for debugging.
+ The file /sys/kernel/debug/sky2/ethX displays the state of the internal
+ transmit and receive rings.
- If unsure, say N.
+ If unsure, say N.
config VIA_VELOCITY
tristate "VIA Velocity support"
@@ -2389,12 +2383,12 @@ config SPIDER_NET
Cell Processor-Based Blades from IBM.
config TSI108_ETH
- tristate "Tundra TSI108 gigabit Ethernet support"
- depends on TSI108_BRIDGE
- help
- This driver supports Tundra TSI108 gigabit Ethernet ports.
- To compile this driver as a module, choose M here: the module
- will be called tsi108_eth.
+ tristate "Tundra TSI108 gigabit Ethernet support"
+ depends on TSI108_BRIDGE
+ help
+ This driver supports Tundra TSI108 gigabit Ethernet ports.
+ To compile this driver as a module, choose M here: the module
+ will be called tsi108_eth.
config GELIC_NET
tristate "PS3 Gigabit Ethernet driver"
@@ -2543,10 +2537,10 @@ config PCH_GBE
depends on PCI
select MII
---help---
- This is a gigabit ethernet driver for Topcliff PCH.
- Topcliff PCH is the platform controller hub that is used in Intel's
+ This is a gigabit ethernet driver for EG20T PCH.
+ EG20T PCH is the platform controller hub that is used in Intel's
general embedded platform.
- Topcliff PCH has Gigabit Ethernet interface.
+ EG20T PCH has Gigabit Ethernet interface.
Using this interface, it is able to access system devices connected
to Gigabit Ethernet.
This driver enables Gigabit Ethernet function.
@@ -2573,32 +2567,32 @@ config MDIO
tristate
config CHELSIO_T1
- tristate "Chelsio 10Gb Ethernet support"
- depends on PCI
+ tristate "Chelsio 10Gb Ethernet support"
+ depends on PCI
select CRC32
select MDIO
- help
- This driver supports Chelsio gigabit and 10-gigabit
- Ethernet cards. More information about adapter features and
+ help
+ This driver supports Chelsio gigabit and 10-gigabit
+ Ethernet cards. More information about adapter features and
performance tuning is in <file:Documentation/networking/cxgb.txt>.
- For general information about Chelsio and our products, visit
- our website at <http://www.chelsio.com>.
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
- For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.html>.
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.html>.
- Please send feedback to <linux-bugs@chelsio.com>.
+ Please send feedback to <linux-bugs@chelsio.com>.
- To compile this driver as a module, choose M here: the module
- will be called cxgb.
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb.
config CHELSIO_T1_1G
- bool "Chelsio gigabit Ethernet support"
- depends on CHELSIO_T1
- help
- Enables support for Chelsio's gigabit Ethernet PCI cards. If you
- are using only 10G cards say 'N' here.
+ bool "Chelsio gigabit Ethernet support"
+ depends on CHELSIO_T1
+ help
+ Enables support for Chelsio's gigabit Ethernet PCI cards. If you
+ are using only 10G cards say 'N' here.
config CHELSIO_T3_DEPENDS
tristate
@@ -2728,26 +2722,26 @@ config IXGBE_DCB
If unsure, say N.
config IXGBEVF
- tristate "Intel(R) 82599 Virtual Function Ethernet support"
- depends on PCI_MSI
- ---help---
- This driver supports Intel(R) 82599 virtual functions. For more
- information on how to identify your adapter, go to the Adapter &
- Driver ID Guide at:
+ tristate "Intel(R) 82599 Virtual Function Ethernet support"
+ depends on PCI_MSI
+ ---help---
+ This driver supports Intel(R) 82599 virtual functions. For more
+ information on how to identify your adapter, go to the Adapter &
+ Driver ID Guide at:
- <http://support.intel.com/support/network/sb/CS-008441.htm>
+ <http://support.intel.com/support/network/sb/CS-008441.htm>
- For general information and support, go to the Intel support
- website at:
+ For general information and support, go to the Intel support
+ website at:
- <http://support.intel.com>
+ <http://support.intel.com>
- More specific information on configuring the driver is in
- <file:Documentation/networking/ixgbevf.txt>.
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbevf.txt>.
- To compile this driver as a module, choose M here. The module
- will be called ixgbevf. MSI-X interrupt support is required
- for this driver to work correctly.
+ To compile this driver as a module, choose M here. The module
+ will be called ixgbevf. MSI-X interrupt support is required
+ for this driver to work correctly.
config IXGB
tristate "Intel(R) PRO/10GbE support"
@@ -2772,29 +2766,38 @@ config IXGB
will be called ixgb.
config S2IO
- tristate "S2IO 10Gbe XFrame NIC"
+ tristate "Exar Xframe 10Gb Ethernet Adapter"
depends on PCI
---help---
- This driver supports the 10Gbe XFrame NIC of S2IO.
+ This driver supports Exar Corp's Xframe Series 10Gb Ethernet Adapters.
+
More specific information on configuring the driver is in
<file:Documentation/networking/s2io.txt>.
+ To compile this driver as a module, choose M here. The module
+ will be called s2io.
+
config VXGE
- tristate "Neterion X3100 Series 10GbE PCIe Server Adapter"
+ tristate "Exar X3100 Series 10GbE PCIe Server Adapter"
depends on PCI && INET
---help---
- This driver supports Neterion Inc's X3100 Series 10 GbE PCIe
+ This driver supports Exar Corp's X3100 Series 10 GbE PCIe
I/O Virtualized Server Adapter.
+
More specific information on configuring the driver is in
<file:Documentation/networking/vxge.txt>.
+ To compile this driver as a module, choose M here. The module
+ will be called vxge.
+
config VXGE_DEBUG_TRACE_ALL
bool "Enabling All Debug trace statments in driver"
default n
depends on VXGE
---help---
Say Y here if you want to enabling all the debug trace statements in
- driver. By default only few debug trace statements are enabled.
+ the vxge driver. By default only few debug trace statements are
+ enabled.
config MYRI10GE
tristate "Myricom Myri-10G Ethernet support"
@@ -2906,18 +2909,18 @@ config QLGE
will be called qlge.
config BNA
- tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
- depends on PCI
- ---help---
- This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
- cards.
- To compile this driver as a module, choose M here: the module
- will be called bna.
+ tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
+ depends on PCI
+ ---help---
+ This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
+ cards.
+ To compile this driver as a module, choose M here: the module
+ will be called bna.
- For general information and support, go to the Brocade support
- website at:
+ For general information and support, go to the Brocade support
+ website at:
- <http://support.brocade.com>
+ <http://support.brocade.com>
source "drivers/net/sfc/Kconfig"
@@ -2945,9 +2948,22 @@ source "drivers/s390/net/Kconfig"
source "drivers/net/caif/Kconfig"
+config TILE_NET
+ tristate "Tilera GBE/XGBE network driver support"
+ depends on TILE
+ default y
+ select CRC32
+ help
+ This is a standard Linux network device driver for the
+ on-chip Tilera Gigabit Ethernet and XAUI interfaces.
+
+ To compile this driver as a module, choose M here: the module
+ will be called tile_net.
+
config XEN_NETDEV_FRONTEND
tristate "Xen network device frontend driver"
depends on XEN
+ select XEN_XENBUS_FRONTEND
default y
help
The network device frontend driver allows the kernel to
@@ -3227,18 +3243,18 @@ config PPP_BSDCOMP
modules once you have said "make modules". If unsure, say N.
config PPP_MPPE
- tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
- select CRYPTO
- select CRYPTO_SHA1
- select CRYPTO_ARC4
- select CRYPTO_ECB
- ---help---
- Support for the MPPE Encryption protocol, as employed by the
- Microsoft Point-to-Point Tunneling Protocol.
-
- See http://pptpclient.sourceforge.net/ for information on
- configuring PPTP clients and servers to utilize this method.
+ tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+ depends on PPP && EXPERIMENTAL
+ select CRYPTO
+ select CRYPTO_SHA1
+ select CRYPTO_ARC4
+ select CRYPTO_ECB
+ ---help---
+ Support for the MPPE Encryption protocol, as employed by the
+ Microsoft Point-to-Point Tunneling Protocol.
+
+ See http://pptpclient.sourceforge.net/ for information on
+ configuring PPTP clients and servers to utilize this method.
config PPPOE
tristate "PPP over Ethernet (EXPERIMENTAL)"
@@ -3373,8 +3389,7 @@ config NETCONSOLE
config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
- depends on NETCONSOLE && SYSFS
- select CONFIGFS_FS
+ depends on NETCONSOLE && SYSFS && CONFIGFS_FS
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)
@@ -3397,14 +3412,14 @@ config VIRTIO_NET
depends on EXPERIMENTAL && VIRTIO
---help---
This is the virtual network driver for virtio. It can be used with
- lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
+ lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
config VMXNET3
- tristate "VMware VMXNET3 ethernet driver"
- depends on PCI && INET
- help
- This driver supports VMware's vmxnet3 virtual ethernet NIC.
- To compile this driver as a module, choose M here: the
- module will be called vmxnet3.
+ tristate "VMware VMXNET3 ethernet driver"
+ depends on PCI && INET
+ help
+ This driver supports VMware's vmxnet3 virtual ethernet NIC.
+ To compile this driver as a module, choose M here: the
+ module will be called vmxnet3.
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 652fc6b98039..b90738d13994 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -301,3 +301,4 @@ obj-$(CONFIG_CAIF) += caif/
obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
obj-$(CONFIG_PCH_GBE) += pch_gbe/
+obj-$(CONFIG_TILE_NET) += tile/
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 9bb405bd664e..068c3563e00f 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -55,8 +55,6 @@ extern struct net_device *eth16i_probe(int unit);
extern struct net_device *i82596_probe(int unit);
extern struct net_device *ewrk3_probe(int unit);
extern struct net_device *el1_probe(int unit);
-extern struct net_device *wavelan_probe(int unit);
-extern struct net_device *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit);
extern struct net_device *elmc_probe(int unit);
extern struct net_device *elplus_probe(int unit);
@@ -68,7 +66,6 @@ extern struct net_device *ni5010_probe(int unit);
extern struct net_device *ni52_probe(int unit);
extern struct net_device *ni65_probe(int unit);
extern struct net_device *sonic_probe(int unit);
-extern struct net_device *SK_init(int unit);
extern struct net_device *seeq8005_probe(int unit);
extern struct net_device *smc_init(int unit);
extern struct net_device *atarilance_probe(int unit);
@@ -76,8 +73,6 @@ extern struct net_device *sun3lance_probe(int unit);
extern struct net_device *sun3_82586_probe(int unit);
extern struct net_device *apne_probe(int unit);
extern struct net_device *cs89x0_probe(int unit);
-extern struct net_device *hplance_probe(int unit);
-extern struct net_device *bagetlance_probe(int unit);
extern struct net_device *mvme147lance_probe(int unit);
extern struct net_device *tc515_probe(int unit);
extern struct net_device *lance_probe(int unit);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 62f21106efec..0c9217f48b72 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -340,14 +340,6 @@ am79c961_close(struct net_device *dev)
return 0;
}
-/*
- * Get the current statistics.
- */
-static struct net_device_stats *am79c961_getstats (struct net_device *dev)
-{
- return &dev->stats;
-}
-
static void am79c961_mc_hash(char *addr, unsigned short *hash)
{
if (addr[0] & 0x01) {
@@ -665,7 +657,6 @@ static const struct net_device_ops am79c961_netdev_ops = {
.ndo_open = am79c961_open,
.ndo_stop = am79c961_close,
.ndo_start_xmit = am79c961_sendpacket,
- .ndo_get_stats = am79c961_getstats,
.ndo_set_multicast_list = am79c961_setmulticastlist,
.ndo_tx_timeout = am79c961_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 6028226a7270..9eb9b98a7ae3 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -1229,8 +1229,10 @@ static int __devinit eth_init_one(struct platform_device *pdev)
snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy);
port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
- if ((err = IS_ERR(port->phydev)))
+ if (IS_ERR(port->phydev)) {
+ err = PTR_ERR(port->phydev);
goto err_free_mem;
+ }
port->phydev->irq = PHY_POLL;
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index 54c6d849cf25..62d6f88cbab5 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -854,12 +854,12 @@ ks8695_set_msglevel(struct net_device *ndev, u32 value)
}
/**
- * ks8695_get_settings - Get device-specific settings.
+ * ks8695_wan_get_settings - Get device-specific settings.
* @ndev: The network device to read settings from
* @cmd: The ethtool structure to read into
*/
static int
-ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
@@ -870,69 +870,50 @@ ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
SUPPORTED_TP | SUPPORTED_MII);
cmd->transceiver = XCVR_INTERNAL;
- /* Port specific extras */
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- cmd->phy_address = 0;
- /* not supported for HPNA */
- cmd->autoneg = AUTONEG_DISABLE;
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+ cmd->port = PORT_MII;
+ cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
+ cmd->phy_address = 0;
- /* BUG: Erm, dtype hpna implies no phy regs */
- /*
- ctrl = readl(KS8695_MISC_VA + KS8695_HMC);
- cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF;
- */
- return -EOPNOTSUPP;
- case KS8695_DTYPE_WAN:
- cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
- cmd->port = PORT_MII;
- cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
- cmd->phy_address = 0;
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+ if ((ctrl & WMC_WAND) == 0) {
+ /* auto-negotiation is enabled */
+ cmd->advertising |= ADVERTISED_Autoneg;
+ if (ctrl & WMC_WANA100F)
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+ if (ctrl & WMC_WANA100H)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+ if (ctrl & WMC_WANA10F)
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+ if (ctrl & WMC_WANA10H)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+ if (ctrl & WMC_WANAP)
+ cmd->advertising |= ADVERTISED_Pause;
+ cmd->autoneg = AUTONEG_ENABLE;
+
+ cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
+ cmd->duplex = (ctrl & WMC_WDS) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ /* auto-negotiation is disabled */
+ cmd->autoneg = AUTONEG_DISABLE;
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- if ((ctrl & WMC_WAND) == 0) {
- /* auto-negotiation is enabled */
- cmd->advertising |= ADVERTISED_Autoneg;
- if (ctrl & WMC_WANA100F)
- cmd->advertising |= ADVERTISED_100baseT_Full;
- if (ctrl & WMC_WANA100H)
- cmd->advertising |= ADVERTISED_100baseT_Half;
- if (ctrl & WMC_WANA10F)
- cmd->advertising |= ADVERTISED_10baseT_Full;
- if (ctrl & WMC_WANA10H)
- cmd->advertising |= ADVERTISED_10baseT_Half;
- if (ctrl & WMC_WANAP)
- cmd->advertising |= ADVERTISED_Pause;
- cmd->autoneg = AUTONEG_ENABLE;
-
- cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & WMC_WDS) ?
- DUPLEX_FULL : DUPLEX_HALF;
- } else {
- /* auto-negotiation is disabled */
- cmd->autoneg = AUTONEG_DISABLE;
-
- cmd->speed = (ctrl & WMC_WANF100) ?
- SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & WMC_WANFF) ?
- DUPLEX_FULL : DUPLEX_HALF;
- }
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
+ cmd->speed = (ctrl & WMC_WANF100) ?
+ SPEED_100 : SPEED_10;
+ cmd->duplex = (ctrl & WMC_WANFF) ?
+ DUPLEX_FULL : DUPLEX_HALF;
}
return 0;
}
/**
- * ks8695_set_settings - Set device-specific settings.
+ * ks8695_wan_set_settings - Set device-specific settings.
* @ndev: The network device to configure
* @cmd: The settings to configure
*/
static int
-ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
@@ -956,171 +937,85 @@ ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
ADVERTISED_100baseT_Full)) == 0)
return -EINVAL;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* HPNA does not support auto-negotiation. */
- return -EINVAL;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
- WMC_WANA10F | WMC_WANA10H);
- if (cmd->advertising & ADVERTISED_100baseT_Full)
- ctrl |= WMC_WANA100F;
- if (cmd->advertising & ADVERTISED_100baseT_Half)
- ctrl |= WMC_WANA100H;
- if (cmd->advertising & ADVERTISED_10baseT_Full)
- ctrl |= WMC_WANA10F;
- if (cmd->advertising & ADVERTISED_10baseT_Half)
- ctrl |= WMC_WANA10H;
-
- /* force a re-negotiation */
- ctrl |= WMC_WANR;
- writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+ ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
+ WMC_WANA10F | WMC_WANA10H);
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ ctrl |= WMC_WANA100F;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ ctrl |= WMC_WANA100H;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ ctrl |= WMC_WANA10F;
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ ctrl |= WMC_WANA10H;
+
+ /* force a re-negotiation */
+ ctrl |= WMC_WANR;
+ writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
} else {
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* BUG: dtype_hpna implies no phy registers */
- /*
- ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC);
-
- ctrl &= ~(HMC_HSS | HMC_HDS);
- if (cmd->speed == SPEED_100)
- ctrl |= HMC_HSS;
- if (cmd->duplex == DUPLEX_FULL)
- ctrl |= HMC_HDS;
-
- __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC);
- */
- return -EOPNOTSUPP;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- /* disable auto-negotiation */
- ctrl |= WMC_WAND;
- ctrl &= ~(WMC_WANF100 | WMC_WANFF);
-
- if (cmd->speed == SPEED_100)
- ctrl |= WMC_WANF100;
- if (cmd->duplex == DUPLEX_FULL)
- ctrl |= WMC_WANFF;
-
- writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+ /* disable auto-negotiation */
+ ctrl |= WMC_WAND;
+ ctrl &= ~(WMC_WANF100 | WMC_WANFF);
+
+ if (cmd->speed == SPEED_100)
+ ctrl |= WMC_WANF100;
+ if (cmd->duplex == DUPLEX_FULL)
+ ctrl |= WMC_WANFF;
+
+ writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
}
return 0;
}
/**
- * ks8695_nwayreset - Restart the autonegotiation on the port.
+ * ks8695_wan_nwayreset - Restart the autonegotiation on the port.
* @ndev: The network device to restart autoneotiation on
*/
static int
-ks8695_nwayreset(struct net_device *ndev)
+ks8695_wan_nwayreset(struct net_device *ndev)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* No phy means no autonegotiation on hpna */
- return -EINVAL;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- if ((ctrl & WMC_WAND) == 0)
- writel(ctrl | WMC_WANR,
- ksp->phyiface_regs + KS8695_WMC);
- else
- /* auto-negotiation not enabled */
- return -EINVAL;
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-/**
- * ks8695_get_link - Retrieve link status of network interface
- * @ndev: The network interface to retrive the link status of.
- */
-static u32
-ks8695_get_link(struct net_device *ndev)
-{
- struct ks8695_priv *ksp = netdev_priv(ndev);
- u32 ctrl;
+ if ((ctrl & WMC_WAND) == 0)
+ writel(ctrl | WMC_WANR,
+ ksp->phyiface_regs + KS8695_WMC);
+ else
+ /* auto-negotiation not enabled */
+ return -EINVAL;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* HPNA always has link */
- return 1;
- case KS8695_DTYPE_WAN:
- /* WAN we can read the PHY for */
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- return ctrl & WMC_WLS;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
return 0;
}
/**
- * ks8695_get_pause - Retrieve network pause/flow-control advertising
+ * ks8695_wan_get_pause - Retrieve network pause/flow-control advertising
* @ndev: The device to retrieve settings from
* @param: The structure to fill out with the information
*/
static void
-ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
+ks8695_wan_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* No phy link on hpna to configure */
- return;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- /* advertise Pause */
- param->autoneg = (ctrl & WMC_WANAP);
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- /* current Rx Flow-control */
- ctrl = ks8695_readreg(ksp, KS8695_DRXC);
- param->rx_pause = (ctrl & DRXC_RFCE);
+ /* advertise Pause */
+ param->autoneg = (ctrl & WMC_WANAP);
- /* current Tx Flow-control */
- ctrl = ks8695_readreg(ksp, KS8695_DTXC);
- param->tx_pause = (ctrl & DTXC_TFCE);
- break;
- case KS8695_DTYPE_LAN:
- /* The LAN's "phy" is a direct-attached switch */
- return;
- }
-}
+ /* current Rx Flow-control */
+ ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+ param->rx_pause = (ctrl & DRXC_RFCE);
-/**
- * ks8695_set_pause - Configure pause/flow-control
- * @ndev: The device to configure
- * @param: The pause parameters to set
- *
- * TODO: Implement this
- */
-static int
-ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
-{
- return -EOPNOTSUPP;
+ /* current Tx Flow-control */
+ ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+ param->tx_pause = (ctrl & DTXC_TFCE);
}
/**
@@ -1140,12 +1035,17 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
static const struct ethtool_ops ks8695_ethtool_ops = {
.get_msglevel = ks8695_get_msglevel,
.set_msglevel = ks8695_set_msglevel,
- .get_settings = ks8695_get_settings,
- .set_settings = ks8695_set_settings,
- .nway_reset = ks8695_nwayreset,
- .get_link = ks8695_get_link,
- .get_pauseparam = ks8695_get_pause,
- .set_pauseparam = ks8695_set_pause,
+ .get_drvinfo = ks8695_get_drvinfo,
+};
+
+static const struct ethtool_ops ks8695_wan_ethtool_ops = {
+ .get_msglevel = ks8695_get_msglevel,
+ .set_msglevel = ks8695_set_msglevel,
+ .get_settings = ks8695_wan_get_settings,
+ .set_settings = ks8695_wan_set_settings,
+ .nway_reset = ks8695_wan_nwayreset,
+ .get_link = ethtool_op_get_link,
+ .get_pauseparam = ks8695_wan_get_pause,
.get_drvinfo = ks8695_get_drvinfo,
};
@@ -1541,7 +1441,6 @@ ks8695_probe(struct platform_device *pdev)
/* driver system setup */
ndev->netdev_ops = &ks8695_netdev_ops;
- SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
@@ -1608,12 +1507,15 @@ ks8695_probe(struct platform_device *pdev)
if (ksp->phyiface_regs && ksp->link_irq == -1) {
ks8695_init_switch(ksp);
ksp->dtype = KS8695_DTYPE_LAN;
+ SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
} else if (ksp->phyiface_regs && ksp->link_irq != -1) {
ks8695_init_wan_phy(ksp);
ksp->dtype = KS8695_DTYPE_WAN;
+ SET_ETHTOOL_OPS(ndev, &ks8695_wan_ethtool_ops);
} else {
/* No initialisation since HPNA does not have a PHY */
ksp->dtype = KS8695_DTYPE_HPNA;
+ SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
}
/* And bring up the net_device with the net core */
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 4545d5a06c24..bfea499a3513 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -117,7 +117,7 @@
#define TX_DESC_SIZE 10
#define MAX_RBUFF_SZ 0x600
#define MAX_TBUFF_SZ 0x600
-#define TX_TIMEOUT 50
+#define TX_TIMEOUT (HZ/2)
#define DELAY 1000
#define CAM0 0x0
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 89876897a6fe..f4744fc89768 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -150,7 +150,7 @@ struct net_local {
#define PORT_OFFSET(o) (o)
-#define TX_TIMEOUT 10
+#define TX_TIMEOUT (HZ/10)
/* Index to functions, as function prototypes. */
@@ -270,9 +270,9 @@ static const struct net_device_ops at1700_netdev_ops = {
static int __init at1700_probe1(struct net_device *dev, int ioaddr)
{
- char fmv_irqmap[4] = {3, 7, 10, 15};
- char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
- char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
+ static const char fmv_irqmap[4] = {3, 7, 10, 15};
+ static const char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
+ static const char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
int slot, ret = -ENODEV;
struct net_local *lp = netdev_priv(dev);
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 8cb27cb7bca1..ce0091eb06f5 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -116,7 +116,7 @@ MODULE_LICENSE("GPL");
#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5)
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
-#define TX_TIMEOUT 20
+#define TX_TIMEOUT (HZ/5)
/* The LANCE Rx and Tx ring descriptors. */
struct lance_rx_head {
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index 919080b2c3a5..1bf672009948 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -82,7 +82,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
addr[0] = addr[1] = 0;
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
if (atl1c_check_eeprom_exist(hw)) {
- if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
/* Enable OTP CLK */
if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
otp_ctrl_data |= OTP_CTRL_CLK_EN;
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 09b099bfab2b..a699bbf20eb5 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -702,6 +702,7 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
adapter->wol = 0;
+ device_set_wakeup_enable(&pdev->dev, false);
adapter->link_speed = SPEED_0;
adapter->link_duplex = FULL_DUPLEX;
adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE;
@@ -2078,7 +2079,7 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
check_sum:
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
u8 css, cso;
- cso = skb_transport_offset(skb);
+ cso = skb_checksum_start_offset(skb);
if (unlikely(cso & 0x1)) {
if (netif_msg_tx_err(adapter))
@@ -2444,8 +2445,9 @@ static int atl1c_close(struct net_device *netdev)
return 0;
}
-static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+static int atl1c_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw *hw = &adapter->hw;
@@ -2454,7 +2456,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
u32 wol_ctrl_data = 0;
u16 mii_intr_status_data = 0;
u32 wufc = adapter->wol;
- int retval = 0;
atl1c_disable_l0s_l1(hw);
if (netif_running(netdev)) {
@@ -2462,9 +2463,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
atl1c_down(adapter);
}
netif_device_detach(netdev);
- retval = pci_save_state(pdev);
- if (retval)
- return retval;
if (wufc)
if (atl1c_phy_power_saving(hw) != 0)
@@ -2525,12 +2523,8 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
- /* pcie patch */
- device_set_wakeup_enable(&pdev->dev, 1);
-
AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
GPHY_CTRL_EXT_RESET);
- pci_prepare_to_sleep(pdev);
} else {
AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
@@ -2540,25 +2534,17 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
hw->phy_configured = false; /* re-init PHY when resume */
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
}
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
return 0;
}
-static int atl1c_resume(struct pci_dev *pdev)
+static int atl1c_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
-
AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
ATL1C_PCIE_PHY_RESET);
@@ -2582,7 +2568,12 @@ static int atl1c_resume(struct pci_dev *pdev)
static void atl1c_shutdown(struct pci_dev *pdev)
{
- atl1c_suspend(pdev, PMSG_SUSPEND);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+ atl1c_suspend(&pdev->dev);
+ pci_wake_from_d3(pdev, adapter->wol);
+ pci_set_power_state(pdev, PCI_D3hot);
}
static const struct net_device_ops atl1c_netdev_ops = {
@@ -2886,16 +2877,16 @@ static struct pci_error_handlers atl1c_err_handler = {
.resume = atl1c_io_resume,
};
+static SIMPLE_DEV_PM_OPS(atl1c_pm_ops, atl1c_suspend, atl1c_resume);
+
static struct pci_driver atl1c_driver = {
.name = atl1c_driver_name,
.id_table = atl1c_pci_tbl,
.probe = atl1c_probe,
.remove = __devexit_p(atl1c_remove),
- /* Power Managment Hooks */
- .suspend = atl1c_suspend,
- .resume = atl1c_resume,
.shutdown = atl1c_shutdown,
- .err_handler = &atl1c_err_handler
+ .err_handler = &atl1c_err_handler,
+ .driver.pm = &atl1c_pm_ops,
};
/*
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index ef6349bf3b33..e28f8baf394e 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -1649,7 +1649,7 @@ check_sum:
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
u8 css, cso;
- cso = skb_transport_offset(skb);
+ cso = skb_checksum_start_offset(skb);
if (unlikely(cso & 0x1)) {
netdev_err(adapter->netdev,
"payload offset should not ant event number\n");
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 43579b3b24ac..3b527687c28f 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -2174,7 +2174,7 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
u8 css, cso;
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
- css = (u8) (skb->csum_start - skb_headroom(skb));
+ css = skb_checksum_start_offset(skb);
cso = css + (u8) skb->csum_offset;
if (unlikely(css & 0x1)) {
/* L1 hardware requires an even number here */
@@ -3043,7 +3043,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
atl1_pcie_patch(adapter);
/* assume we have no link for now */
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
setup_timer(&adapter->phy_config_timer, atl1_phy_config,
(unsigned long)adapter);
@@ -3505,6 +3504,8 @@ static int atl1_set_ringparam(struct net_device *netdev,
struct atl1_rfd_ring rfd_old, rfd_new;
struct atl1_rrd_ring rrd_old, rrd_new;
struct atl1_ring_header rhdr_old, rhdr_new;
+ struct atl1_smb smb;
+ struct atl1_cmb cmb;
int err;
tpd_old = adapter->tpd_ring;
@@ -3545,11 +3546,19 @@ static int atl1_set_ringparam(struct net_device *netdev,
adapter->rrd_ring = rrd_old;
adapter->tpd_ring = tpd_old;
adapter->ring_header = rhdr_old;
+ /*
+ * Save SMB and CMB, since atl1_free_ring_resources
+ * will clear them.
+ */
+ smb = adapter->smb;
+ cmb = adapter->cmb;
atl1_free_ring_resources(adapter);
adapter->rfd_ring = rfd_new;
adapter->rrd_ring = rrd_new;
adapter->tpd_ring = tpd_new;
adapter->ring_header = rhdr_new;
+ adapter->smb = smb;
+ adapter->cmb = cmb;
err = atl1_up(adapter);
if (err)
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 35b14bec1207..4e6f4e95a5a0 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -1504,8 +1504,8 @@ static void __devexit atl2_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_config_timer);
-
- flush_scheduled_work();
+ cancel_work_sync(&adapter->reset_task);
+ cancel_work_sync(&adapter->link_chg_task);
unregister_netdev(netdev);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 43489f89c142..b9debcfb61a0 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -106,8 +106,6 @@ MODULE_VERSION(DRV_VERSION);
* complete immediately.
*/
-struct au1000_private *au_macs[NUM_ETH_INTERFACES];
-
/*
* board-specific configurations
*
@@ -155,10 +153,10 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
spin_lock_irqsave(&aup->lock, flags);
if (force_reset || (!aup->mac_enabled)) {
- writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+ writel(MAC_EN_CLOCK_ENABLE, aup->enable);
au_sync_delay(2);
writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
- | MAC_EN_CLOCK_ENABLE), &aup->enable);
+ | MAC_EN_CLOCK_ENABLE), aup->enable);
au_sync_delay(2);
aup->mac_enabled = 1;
@@ -503,9 +501,9 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
au1000_hard_stop(dev);
- writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+ writel(MAC_EN_CLOCK_ENABLE, aup->enable);
au_sync_delay(2);
- writel(0, &aup->enable);
+ writel(0, aup->enable);
au_sync_delay(2);
aup->tx_full = 0;
@@ -1119,7 +1117,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
/* set a random MAC now in case platform_data doesn't provide one */
random_ether_addr(dev->dev_addr);
- writel(0, &aup->enable);
+ writel(0, aup->enable);
aup->mac_enabled = 0;
pd = pdev->dev.platform_data;
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index b6da4cf3694b..4bebff3faeab 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -325,7 +325,7 @@ static void ax_block_output(struct net_device *dev, int count,
static void
ax_mii_ei_outbits(struct net_device *dev, unsigned int bits, int len)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
void __iomem *memr_addr = (void __iomem *)dev->base_addr + AX_MEMR;
unsigned int memr;
@@ -364,7 +364,7 @@ ax_mii_ei_outbits(struct net_device *dev, unsigned int bits, int len)
static unsigned int
ax_phy_ei_inbits(struct net_device *dev, int no)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
void __iomem *memr_addr = (void __iomem *)dev->base_addr + AX_MEMR;
unsigned int memr;
unsigned int result = 0;
@@ -412,7 +412,7 @@ ax_phy_issueaddr(struct net_device *dev, int phy_addr, int reg, int opc)
static int
ax_phy_read(struct net_device *dev, int phy_addr, int reg)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned long flags;
unsigned int result;
@@ -435,7 +435,7 @@ ax_phy_read(struct net_device *dev, int phy_addr, int reg)
static void
ax_phy_write(struct net_device *dev, int phy_addr, int reg, int value)
{
- struct ei_device *ei = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei = netdev_priv(dev);
struct ax_device *ax = to_ax_dev(dev);
unsigned long flags;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index c6e86315b3f8..2e2b76258ab4 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -381,11 +381,11 @@ 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);
+#ifdef CONFIG_BCM47XX
+#include <asm/mach-bcm47xx/nvram.h>
static void b44_wap54g10_workaround(struct b44 *bp)
{
- const char *str;
+ char buf[20];
u32 val;
int err;
@@ -394,10 +394,9 @@ static void b44_wap54g10_workaround(struct b44 *bp)
* see https://dev.openwrt.org/ticket/146
* check and reset bit "isolate"
*/
- str = nvram_get("boardnum");
- if (!str)
+ if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
return;
- if (simple_strtoul(str, NULL, 0) == 2) {
+ if (simple_strtoul(buf, NULL, 0) == 2) {
err = __b44_readphy(bp, 0, MII_BMCR, &val);
if (err)
goto error;
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index ecfef240a303..e94a966af418 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -1097,7 +1097,7 @@ static int bcm_enet_stop(struct net_device *dev)
enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
/* make sure no mib update is scheduled */
- flush_scheduled_work();
+ cancel_work_sync(&priv->mib_update_task);
/* disable dma & mac */
bcm_enet_disable_dma(priv, priv->tx_chan);
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 4594a28b1f66..add0b93350dd 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -38,14 +38,17 @@
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
-#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)"
+#define OC_NAME_BE OC_NAME "(be3)"
+#define OC_NAME_LANCER OC_NAME "(Lancer)"
#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver"
#define BE_VENDOR_ID 0x19a2
+#define EMULEX_VENDOR_ID 0x10df
#define BE_DEVICE_ID1 0x211
#define BE_DEVICE_ID2 0x221
-#define OC_DEVICE_ID1 0x700
-#define OC_DEVICE_ID2 0x710
+#define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */
+#define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */
+#define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */
static inline char *nic_name(struct pci_dev *pdev)
{
@@ -53,7 +56,9 @@ static inline char *nic_name(struct pci_dev *pdev)
case OC_DEVICE_ID1:
return OC_NAME;
case OC_DEVICE_ID2:
- return OC_NAME1;
+ return OC_NAME_BE;
+ case OC_DEVICE_ID3:
+ return OC_NAME_LANCER;
case BE_DEVICE_ID2:
return BE3_NAME;
default:
@@ -149,6 +154,7 @@ struct be_eq_obj {
u16 min_eqd; /* in usecs */
u16 max_eqd; /* in usecs */
u16 cur_eqd; /* in usecs */
+ u8 msix_vec_idx;
struct napi_struct napi;
};
@@ -214,7 +220,9 @@ struct be_rx_obj {
struct be_rx_stats stats;
u8 rss_id;
bool rx_post_starved; /* Zero rx frags have been posted to BE */
- u32 cache_line_barrier[16];
+ u16 last_frag_index;
+ u16 rsvd;
+ u32 cache_line_barrier[15];
};
struct be_vf_cfg {
@@ -234,7 +242,7 @@ struct be_adapter {
u8 __iomem *db; /* Door Bell */
u8 __iomem *pcicfg; /* PCI config space */
- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
struct be_dma_mem mbox_mem;
/* Mbox mem is adjusted to align to 16 bytes. The allocated addr
* is stored for freeing purpose */
@@ -260,6 +268,8 @@ struct be_adapter {
u32 num_rx_qs;
u32 big_page_size; /* Compounded page size shared by rx wrbs */
+ u8 msix_vec_next_idx;
+
struct vlan_group *vlan_grp;
u16 vlans_added;
u16 max_vlans; /* Number of vlans supported */
@@ -299,8 +309,8 @@ struct be_adapter {
bool sriov_enabled;
struct be_vf_cfg vf_cfg[BE_MAX_VF];
- u8 base_eq_id;
u8 is_virtfn;
+ u32 sli_family;
};
#define be_physfn(adapter) (!adapter->is_virtfn)
@@ -309,6 +319,8 @@ struct be_adapter {
#define BE_GEN2 2
#define BE_GEN3 3
+#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3)
+
extern const struct ethtool_ops be_ethtool_ops;
#define tx_stats(adapter) (&adapter->tx_stats)
@@ -416,10 +428,17 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
{
u8 data;
-
- pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
- pci_read_config_byte(adapter->pdev, 0xFE, &data);
- adapter->is_virtfn = (data != 0xAA);
+ u32 sli_intf;
+
+ if (lancer_chip(adapter)) {
+ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET,
+ &sli_intf);
+ adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
+ } else {
+ pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
+ pci_read_config_byte(adapter->pdev, 0xFE, &data);
+ adapter->is_virtfn = (data != 0xAA);
+ }
}
static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 36eca1ce75d4..0c7811faf72c 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -323,7 +323,12 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage)
{
- u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET);
+ u32 sem;
+
+ if (lancer_chip(adapter))
+ sem = ioread32(adapter->db + MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET);
+ else
+ sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET);
*stage = sem & EP_SEMAPHORE_POST_STAGE_MASK;
if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK)
@@ -462,7 +467,8 @@ int be_cmd_fw_init(struct be_adapter *adapter)
u8 *wrb;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = (u8 *)wrb_from_mbox(adapter);
*wrb++ = 0xFF;
@@ -476,7 +482,7 @@ int be_cmd_fw_init(struct be_adapter *adapter)
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -491,7 +497,8 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = (u8 *)wrb_from_mbox(adapter);
*wrb++ = 0xFF;
@@ -505,7 +512,7 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
int be_cmd_eq_create(struct be_adapter *adapter,
@@ -516,7 +523,8 @@ int be_cmd_eq_create(struct be_adapter *adapter,
struct be_dma_mem *q_mem = &eq->dma_mem;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -546,7 +554,7 @@ int be_cmd_eq_create(struct be_adapter *adapter,
eq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -558,7 +566,8 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
struct be_cmd_req_mac_query *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -583,7 +592,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -667,7 +676,8 @@ int be_cmd_cq_create(struct be_adapter *adapter,
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -680,16 +690,36 @@ int be_cmd_cq_create(struct be_adapter *adapter,
OPCODE_COMMON_CQ_CREATE, sizeof(*req));
req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+ if (lancer_chip(adapter)) {
+ req->hdr.version = 1;
+ req->page_size = 1; /* 1 for 4K */
+ AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt,
+ coalesce_wm);
+ AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt,
+ no_delay);
+ AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt,
+ __ilog2_u32(cq->len/256));
+ AMAP_SET_BITS(struct amap_cq_context_lancer, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context_lancer, eventable,
+ ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context_lancer, eqid,
+ ctxt, eq->id);
+ AMAP_SET_BITS(struct amap_cq_context_lancer, armed, ctxt, 1);
+ } else {
+ AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt,
+ coalesce_wm);
+ AMAP_SET_BITS(struct amap_cq_context_be, nodelay,
+ ctxt, no_delay);
+ AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt,
+ __ilog2_u32(cq->len/256));
+ AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context_be, solevent,
+ ctxt, sol_evts);
+ AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id);
+ AMAP_SET_BITS(struct amap_cq_context_be, armed, ctxt, 1);
+ }
- AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
- AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
- AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
- __ilog2_u32(cq->len/256));
- AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
- AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
- AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
- AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
- AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -701,7 +731,7 @@ int be_cmd_cq_create(struct be_adapter *adapter,
cq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -724,7 +754,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -737,13 +768,27 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+ if (lancer_chip(adapter)) {
+ req->hdr.version = 1;
+ req->cq_id = cpu_to_le16(cq->id);
+
+ AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt,
+ be_encoded_q_len(mccq->len));
+ AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id,
+ ctxt, cq->id);
+ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid,
+ ctxt, 1);
+
+ } else {
+ AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
+ be_encoded_q_len(mccq->len));
+ AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
+ }
- AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
- AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
- be_encoded_q_len(mccq->len));
- AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id);
/* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
- req->async_event_bitmap[0] |= 0x00000022;
+ req->async_event_bitmap[0] = cpu_to_le32(0x00000022);
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -754,7 +799,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
mccq->id = le16_to_cpu(resp->id);
mccq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -769,7 +814,8 @@ int be_cmd_txq_create(struct be_adapter *adapter,
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -801,7 +847,7 @@ int be_cmd_txq_create(struct be_adapter *adapter,
txq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -816,7 +862,8 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_dma_mem *q_mem = &rxq->dma_mem;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -843,7 +890,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
*rss_id = resp->rss_id;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -862,7 +909,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -899,7 +947,7 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -915,7 +963,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
struct be_cmd_req_if_create *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -941,7 +990,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
*pmac_id = le32_to_cpu(resp->pmac_id);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -955,7 +1004,8 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -970,7 +1020,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -1060,7 +1110,8 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
struct be_cmd_req_get_fw_version *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -1077,7 +1128,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -1235,7 +1286,7 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
i = 0;
netdev_for_each_mc_addr(ha, netdev)
- memcpy(req->mac[i].byte, ha->addr, ETH_ALEN);
+ memcpy(req->mac[i++].byte, ha->addr, ETH_ALEN);
} else {
req->promiscuous = 1;
}
@@ -1322,7 +1373,8 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
struct be_cmd_req_query_fw_cfg *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -1341,7 +1393,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
*caps = le32_to_cpu(resp->function_caps);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -1352,7 +1404,8 @@ int be_cmd_reset_function(struct be_adapter *adapter)
struct be_cmd_req_hdr *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -1365,7 +1418,7 @@ int be_cmd_reset_function(struct be_adapter *adapter)
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -1376,7 +1429,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
u32 myhash[10];
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
@@ -1396,7 +1450,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 8469ff061f30..83d15c8a9fa3 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -309,7 +309,7 @@ struct be_cmd_req_pmac_del {
/******************** Create CQ ***************************/
/* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field */
-struct amap_cq_context {
+struct amap_cq_context_be {
u8 cidx[11]; /* dword 0*/
u8 rsvd0; /* dword 0*/
u8 coalescwm[2]; /* dword 0*/
@@ -332,14 +332,32 @@ struct amap_cq_context {
u8 rsvd5[32]; /* dword 3*/
} __packed;
+struct amap_cq_context_lancer {
+ u8 rsvd0[12]; /* dword 0*/
+ u8 coalescwm[2]; /* dword 0*/
+ u8 nodelay; /* dword 0*/
+ u8 rsvd1[12]; /* dword 0*/
+ u8 count[2]; /* dword 0*/
+ u8 valid; /* dword 0*/
+ u8 rsvd2; /* dword 0*/
+ u8 eventable; /* dword 0*/
+ u8 eqid[16]; /* dword 1*/
+ u8 rsvd3[15]; /* dword 1*/
+ u8 armed; /* dword 1*/
+ u8 rsvd4[32]; /* dword 2*/
+ u8 rsvd5[32]; /* dword 3*/
+} __packed;
+
struct be_cmd_req_cq_create {
struct be_cmd_req_hdr hdr;
u16 num_pages;
- u16 rsvd0;
- u8 context[sizeof(struct amap_cq_context) / 8];
+ u8 page_size;
+ u8 rsvd0;
+ u8 context[sizeof(struct amap_cq_context_be) / 8];
struct phys_addr pages[8];
} __packed;
+
struct be_cmd_resp_cq_create {
struct be_cmd_resp_hdr hdr;
u16 cq_id;
@@ -349,7 +367,7 @@ struct be_cmd_resp_cq_create {
/******************** Create MCCQ ***************************/
/* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field */
-struct amap_mcc_context {
+struct amap_mcc_context_be {
u8 con_index[14];
u8 rsvd0[2];
u8 ring_size[4];
@@ -364,12 +382,23 @@ struct amap_mcc_context {
u8 rsvd2[32];
} __packed;
+struct amap_mcc_context_lancer {
+ u8 async_cq_id[16];
+ u8 ring_size[4];
+ u8 rsvd0[12];
+ u8 rsvd1[31];
+ u8 valid;
+ u8 async_cq_valid[1];
+ u8 rsvd2[31];
+ u8 rsvd3[32];
+} __packed;
+
struct be_cmd_req_mcc_create {
struct be_cmd_req_hdr hdr;
u16 num_pages;
- u16 rsvd0;
+ u16 cq_id;
u32 async_event_bitmap[1];
- u8 context[sizeof(struct amap_mcc_context) / 8];
+ u8 context[sizeof(struct amap_mcc_context_be) / 8];
struct phys_addr pages[8];
} __packed;
@@ -605,6 +634,7 @@ struct be_hw_stats {
struct be_rxf_stats rxf;
u32 rsvd[48];
struct be_erx_stats erx;
+ u32 rsvd1[6];
};
struct be_cmd_req_get_stats {
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 0f46366ecc48..b4be0271efe0 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -549,7 +549,9 @@ be_test_ddr_dma(struct be_adapter *adapter)
{
int ret, i;
struct be_dma_mem ddrdma_cmd;
- u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL};
+ static const u64 pattern[2] = {
+ 0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL
+ };
ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size,
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index a2ec5df0d733..4096d9778234 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -32,10 +32,12 @@
#define MPU_EP_CONTROL 0
/********** MPU semphore ******************/
-#define MPU_EP_SEMAPHORE_OFFSET 0xac
-#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
-#define EP_SEMAPHORE_POST_ERR_MASK 0x1
-#define EP_SEMAPHORE_POST_ERR_SHIFT 31
+#define MPU_EP_SEMAPHORE_OFFSET 0xac
+#define MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET 0x400
+#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
+#define EP_SEMAPHORE_POST_ERR_MASK 0x1
+#define EP_SEMAPHORE_POST_ERR_SHIFT 31
+
/* MPU semphore POST stage values */
#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
@@ -66,6 +68,28 @@
#define PCICFG_UE_STATUS_LOW_MASK 0xA8
#define PCICFG_UE_STATUS_HI_MASK 0xAC
+/******** SLI_INTF ***********************/
+#define SLI_INTF_REG_OFFSET 0x58
+#define SLI_INTF_VALID_MASK 0xE0000000
+#define SLI_INTF_VALID 0xC0000000
+#define SLI_INTF_HINT2_MASK 0x1F000000
+#define SLI_INTF_HINT2_SHIFT 24
+#define SLI_INTF_HINT1_MASK 0x00FF0000
+#define SLI_INTF_HINT1_SHIFT 16
+#define SLI_INTF_FAMILY_MASK 0x00000F00
+#define SLI_INTF_FAMILY_SHIFT 8
+#define SLI_INTF_IF_TYPE_MASK 0x0000F000
+#define SLI_INTF_IF_TYPE_SHIFT 12
+#define SLI_INTF_REV_MASK 0x000000F0
+#define SLI_INTF_REV_SHIFT 4
+#define SLI_INTF_FT_MASK 0x00000001
+
+
+/* SLI family */
+#define BE_SLI_FAMILY 0x0
+#define LANCER_A0_SLI_FAMILY 0xA
+
+
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
#define CEV_ISR_SIZE 4
@@ -73,6 +97,9 @@
/********* Event Q door bell *************/
#define DB_EQ_OFFSET DB_CQ_OFFSET
#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
+#define DB_EQ_RING_ID_EXT_MASK 0x3e00 /* bits 9-13 */
+#define DB_EQ_RING_ID_EXT_MASK_SHIFT (2) /* qid bits 9-13 placing at 11-15 */
+
/* Clear the interrupt for this eq */
#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
/* Must be 1 */
@@ -85,6 +112,10 @@
/********* Compl Q door bell *************/
#define DB_CQ_OFFSET 0x120
#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_CQ_RING_ID_EXT_MASK 0x7C00 /* bits 10-14 */
+#define DB_CQ_RING_ID_EXT_MASK_SHIFT (1) /* qid bits 10-14
+ placing at 11-15 */
+
/* Number of event entries processed */
#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index c36cd2ffbadc..de40d3b7152f 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -41,6 +41,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
+ { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -188,6 +189,8 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,
{
u32 val = 0;
val |= qid & DB_EQ_RING_ID_MASK;
+ val |= ((qid & DB_EQ_RING_ID_EXT_MASK) <<
+ DB_EQ_RING_ID_EXT_MASK_SHIFT);
if (adapter->eeh_err)
return;
@@ -205,6 +208,8 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
{
u32 val = 0;
val |= qid & DB_CQ_RING_ID_MASK;
+ val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<
+ DB_CQ_RING_ID_EXT_MASK_SHIFT);
if (adapter->eeh_err)
return;
@@ -404,7 +409,8 @@ static void be_tx_stats_update(struct be_adapter *adapter,
}
/* Determine number of WRB entries needed to xmit data in an skb */
-static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
+static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb,
+ bool *dummy)
{
int cnt = (skb->len > skb->data_len);
@@ -412,12 +418,13 @@ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
/* to account for hdr wrb */
cnt++;
- if (cnt & 1) {
+ if (lancer_chip(adapter) || !(cnt & 1)) {
+ *dummy = false;
+ } else {
/* add a dummy to make it an even num */
cnt++;
*dummy = true;
- } else
- *dummy = false;
+ }
BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
return cnt;
}
@@ -443,8 +450,18 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
hdr, skb_shinfo(skb)->gso_size);
- if (skb_is_gso_v6(skb))
+ if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
+ if (lancer_chip(adapter) && adapter->sli_family ==
+ LANCER_A0_SLI_FAMILY) {
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
+ if (is_tcp_pkt(skb))
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb,
+ tcpcs, hdr, 1);
+ else if (is_udp_pkt(skb))
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb,
+ udpcs, hdr, 1);
+ }
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (is_tcp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
@@ -566,7 +583,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
u32 start = txq->head;
bool dummy_wrb, stopped = false;
- wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb);
+ wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb);
if (copied) {
@@ -894,11 +911,17 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
- for (i = 0; i < num_rcvd; i++) {
- page_info = get_rx_page_info(adapter, rxo, rxq_idx);
- put_page(page_info->page);
- memset(page_info, 0, sizeof(*page_info));
- index_inc(&rxq_idx, rxq->len);
+ /* Skip out-of-buffer compl(lancer) or flush compl(BE) */
+ if (likely(rxq_idx != rxo->last_frag_index && num_rcvd != 0)) {
+
+ rxo->last_frag_index = rxq_idx;
+
+ for (i = 0; i < num_rcvd; i++) {
+ page_info = get_rx_page_info(adapter, rxo, rxq_idx);
+ put_page(page_info->page);
+ memset(page_info, 0, sizeof(*page_info));
+ index_inc(&rxq_idx, rxq->len);
+ }
}
}
@@ -999,9 +1022,6 @@ static void be_rx_compl_process(struct be_adapter *adapter,
u8 vtm;
num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
- /* Is it a flush compl that has no data */
- if (unlikely(num_rcvd == 0))
- return;
skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
if (unlikely(!skb)) {
@@ -1035,7 +1055,8 @@ static void be_rx_compl_process(struct be_adapter *adapter,
return;
}
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
- vid = swab16(vid);
+ if (!lancer_chip(adapter))
+ vid = swab16(vid);
vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
} else {
netif_receive_skb(skb);
@@ -1057,10 +1078,6 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
u8 pkt_type;
num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
- /* Is it a flush compl that has no data */
- if (unlikely(num_rcvd == 0))
- return;
-
pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -1113,7 +1130,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
napi_gro_frags(&eq_obj->napi);
} else {
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
- vid = swab16(vid);
+ if (!lancer_chip(adapter))
+ vid = swab16(vid);
if (!adapter->vlan_grp || adapter->vlans_added == 0)
return;
@@ -1330,7 +1348,7 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
be_rx_compl_discard(adapter, rxo, rxcp);
be_rx_compl_reset(rxcp);
- be_cq_notify(adapter, rx_cq->id, true, 1);
+ be_cq_notify(adapter, rx_cq->id, false, 1);
}
/* Then free posted rx buffer that were not used */
@@ -1381,7 +1399,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
sent_skb = sent_skbs[txq->tail];
end_idx = txq->tail;
index_adv(&end_idx,
- wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len);
+ wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
+ txq->len);
be_tx_compl_process(adapter, end_idx);
}
}
@@ -1476,7 +1495,9 @@ static int be_tx_queues_create(struct be_adapter *adapter)
/* Ask BE to create Tx Event queue */
if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
goto tx_eq_free;
- adapter->base_eq_id = adapter->tx_eq.q.id;
+
+ adapter->tx_eq.msix_vec_idx = adapter->msix_vec_next_idx++;
+
/* Alloc TX eth compl queue */
cq = &adapter->tx_obj.cq;
@@ -1554,6 +1575,9 @@ static int be_rx_queues_create(struct be_adapter *adapter)
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
for_all_rx_queues(adapter, rxo, i) {
rxo->adapter = adapter;
+ /* Init last_frag_index so that the frag index in the first
+ * completion will never match */
+ rxo->last_frag_index = 0xffff;
rxo->rx_eq.max_eqd = BE_MAX_EQD;
rxo->rx_eq.enable_aic = true;
@@ -1568,6 +1592,8 @@ static int be_rx_queues_create(struct be_adapter *adapter)
if (rc)
goto err;
+ rxo->rx_eq.msix_vec_idx = adapter->msix_vec_next_idx++;
+
/* CQ */
cq = &rxo->cq;
rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
@@ -1578,7 +1604,6 @@ static int be_rx_queues_create(struct be_adapter *adapter)
rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
if (rc)
goto err;
-
/* Rx Q */
q = &rxo->q;
rc = be_queue_alloc(adapter, q, RX_Q_LEN,
@@ -1611,29 +1636,45 @@ err:
return -1;
}
-/* There are 8 evt ids per func. Retruns the evt id's bit number */
-static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
+static bool event_peek(struct be_eq_obj *eq_obj)
{
- return eq_id - adapter->base_eq_id;
+ struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q);
+ if (!eqe->evt)
+ return false;
+ else
+ return true;
}
static irqreturn_t be_intx(int irq, void *dev)
{
struct be_adapter *adapter = dev;
struct be_rx_obj *rxo;
- int isr, i;
+ int isr, i, tx = 0 , rx = 0;
- isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
- (adapter->tx_eq.q.id/ 8) * CEV_ISR_SIZE);
- if (!isr)
- return IRQ_NONE;
+ if (lancer_chip(adapter)) {
+ if (event_peek(&adapter->tx_eq))
+ tx = event_handle(adapter, &adapter->tx_eq);
+ for_all_rx_queues(adapter, rxo, i) {
+ if (event_peek(&rxo->rx_eq))
+ rx |= event_handle(adapter, &rxo->rx_eq);
+ }
- if ((1 << be_evt_bit_get(adapter, adapter->tx_eq.q.id) & isr))
- event_handle(adapter, &adapter->tx_eq);
+ if (!(tx || rx))
+ return IRQ_NONE;
- for_all_rx_queues(adapter, rxo, i) {
- if ((1 << be_evt_bit_get(adapter, rxo->rx_eq.q.id) & isr))
- event_handle(adapter, &rxo->rx_eq);
+ } else {
+ isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
+ (adapter->tx_eq.q.id / 8) * CEV_ISR_SIZE);
+ if (!isr)
+ return IRQ_NONE;
+
+ if ((1 << adapter->tx_eq.msix_vec_idx & isr))
+ event_handle(adapter, &adapter->tx_eq);
+
+ for_all_rx_queues(adapter, rxo, i) {
+ if ((1 << rxo->rx_eq.msix_vec_idx & isr))
+ event_handle(adapter, &rxo->rx_eq);
+ }
}
return IRQ_HANDLED;
@@ -1658,10 +1699,9 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
return IRQ_HANDLED;
}
-static inline bool do_gro(struct be_adapter *adapter, struct be_rx_obj *rxo,
- struct be_eth_rx_compl *rxcp)
+static inline bool do_gro(struct be_rx_obj *rxo,
+ struct be_eth_rx_compl *rxcp, u8 err)
{
- int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
if (err)
@@ -1678,6 +1718,8 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
struct be_queue_info *rx_cq = &rxo->cq;
struct be_eth_rx_compl *rxcp;
u32 work_done;
+ u16 frag_index, num_rcvd;
+ u8 err;
rxo->stats.rx_polls++;
for (work_done = 0; work_done < budget; work_done++) {
@@ -1685,10 +1727,22 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
if (!rxcp)
break;
- if (do_gro(adapter, rxo, rxcp))
- be_rx_compl_process_gro(adapter, rxo, rxcp);
- else
- be_rx_compl_process(adapter, rxo, rxcp);
+ err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
+ frag_index = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx,
+ rxcp);
+ num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags,
+ rxcp);
+
+ /* Skip out-of-buffer compl(lancer) or flush compl(BE) */
+ if (likely(frag_index != rxo->last_frag_index &&
+ num_rcvd != 0)) {
+ rxo->last_frag_index = frag_index;
+
+ if (do_gro(rxo, rxcp, err))
+ be_rx_compl_process_gro(adapter, rxo, rxcp);
+ else
+ be_rx_compl_process(adapter, rxo, rxcp);
+ }
be_rx_compl_reset(rxcp);
}
@@ -1830,8 +1884,7 @@ static void be_worker(struct work_struct *work)
be_post_rx_frags(rxo);
}
}
-
- if (!adapter->ue_detected)
+ if (!adapter->ue_detected && !lancer_chip(adapter))
be_detect_dump_ue(adapter);
reschedule:
@@ -1910,10 +1963,10 @@ static void be_sriov_disable(struct be_adapter *adapter)
#endif
}
-static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
+static inline int be_msix_vec_get(struct be_adapter *adapter,
+ struct be_eq_obj *eq_obj)
{
- return adapter->msix_entries[
- be_evt_bit_get(adapter, eq_id)].vector;
+ return adapter->msix_entries[eq_obj->msix_vec_idx].vector;
}
static int be_request_irq(struct be_adapter *adapter,
@@ -1924,14 +1977,14 @@ static int be_request_irq(struct be_adapter *adapter,
int vec;
sprintf(eq_obj->desc, "%s-%s", netdev->name, desc);
- vec = be_msix_vec_get(adapter, eq_obj->q.id);
+ vec = be_msix_vec_get(adapter, eq_obj);
return request_irq(vec, handler, 0, eq_obj->desc, context);
}
static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj,
void *context)
{
- int vec = be_msix_vec_get(adapter, eq_obj->q.id);
+ int vec = be_msix_vec_get(adapter, eq_obj);
free_irq(vec, context);
}
@@ -2036,14 +2089,15 @@ static int be_close(struct net_device *netdev)
netif_carrier_off(netdev);
adapter->link_up = false;
- be_intr_set(adapter, false);
+ if (!lancer_chip(adapter))
+ be_intr_set(adapter, false);
if (adapter->msix_enabled) {
- vec = be_msix_vec_get(adapter, tx_eq->q.id);
+ vec = be_msix_vec_get(adapter, tx_eq);
synchronize_irq(vec);
for_all_rx_queues(adapter, rxo, i) {
- vec = be_msix_vec_get(adapter, rxo->rx_eq.q.id);
+ vec = be_msix_vec_get(adapter, &rxo->rx_eq);
synchronize_irq(vec);
}
} else {
@@ -2082,7 +2136,8 @@ static int be_open(struct net_device *netdev)
be_irq_register(adapter);
- be_intr_set(adapter, true);
+ if (!lancer_chip(adapter))
+ be_intr_set(adapter, true);
/* The evt queues are created in unarmed state; arm them */
for_all_rx_queues(adapter, rxo, i) {
@@ -2343,10 +2398,10 @@ static int be_flash_data(struct be_adapter *adapter,
int num_bytes;
const u8 *p = fw->data;
struct be_cmd_write_flashrom *req = flash_cmd->va;
- struct flash_comp *pflashcomp;
+ const struct flash_comp *pflashcomp;
int num_comp;
- struct flash_comp gen3_flash_types[9] = {
+ static const struct flash_comp gen3_flash_types[9] = {
{ FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
FLASH_IMAGE_MAX_SIZE_g3},
{ FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
@@ -2366,7 +2421,7 @@ static int be_flash_data(struct be_adapter *adapter,
{ FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW,
FLASH_NCSI_IMAGE_MAX_SIZE_g3}
};
- struct flash_comp gen2_flash_types[8] = {
+ static const struct flash_comp gen2_flash_types[8] = {
{ FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
FLASH_IMAGE_MAX_SIZE_g2},
{ FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT,
@@ -2388,11 +2443,11 @@ static int be_flash_data(struct be_adapter *adapter,
if (adapter->generation == BE_GEN3) {
pflashcomp = gen3_flash_types;
filehdr_size = sizeof(struct flash_file_hdr_g3);
- num_comp = 9;
+ num_comp = ARRAY_SIZE(gen3_flash_types);
} else {
pflashcomp = gen2_flash_types;
filehdr_size = sizeof(struct flash_file_hdr_g2);
- num_comp = 8;
+ num_comp = ARRAY_SIZE(gen2_flash_types);
}
for (i = 0; i < num_comp; i++) {
if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) &&
@@ -2458,6 +2513,12 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
int status, i = 0, num_imgs = 0;
const u8 *p;
+ if (!netif_running(adapter->netdev)) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware load not allowed (interface is down)\n");
+ return -EPERM;
+ }
+
strcpy(fw_file, func);
status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
@@ -2537,10 +2598,15 @@ static void be_netdev_init(struct net_device *netdev)
int i;
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_GRO | NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+ if (lancer_chip(adapter))
+ netdev->vlan_features |= NETIF_F_TSO6;
netdev->flags |= IFF_MULTICAST;
@@ -2581,6 +2647,15 @@ static int be_map_pci_bars(struct be_adapter *adapter)
u8 __iomem *addr;
int pcicfg_reg, db_reg;
+ if (lancer_chip(adapter)) {
+ addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0),
+ pci_resource_len(adapter->pdev, 0));
+ if (addr == NULL)
+ return -ENOMEM;
+ adapter->db = addr;
+ return 0;
+ }
+
if (be_physfn(adapter)) {
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
pci_resource_len(adapter->pdev, 2));
@@ -2671,7 +2746,7 @@ static int be_ctrl_init(struct be_adapter *adapter)
}
memset(mc_cmd_mem->va, 0, mc_cmd_mem->size);
- spin_lock_init(&adapter->mbox_lock);
+ mutex_init(&adapter->mbox_lock);
spin_lock_init(&adapter->mcc_lock);
spin_lock_init(&adapter->mcc_cq_lock);
@@ -2777,6 +2852,44 @@ static int be_get_config(struct be_adapter *adapter)
return 0;
}
+static int be_dev_family_check(struct be_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ u32 sli_intf = 0, if_type;
+
+ switch (pdev->device) {
+ case BE_DEVICE_ID1:
+ case OC_DEVICE_ID1:
+ adapter->generation = BE_GEN2;
+ break;
+ case BE_DEVICE_ID2:
+ case OC_DEVICE_ID2:
+ adapter->generation = BE_GEN3;
+ break;
+ case OC_DEVICE_ID3:
+ pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
+ if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
+ SLI_INTF_IF_TYPE_SHIFT;
+
+ if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) ||
+ if_type != 0x02) {
+ dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
+ return -EINVAL;
+ }
+ if (num_vfs > 0) {
+ dev_err(&pdev->dev, "VFs not supported\n");
+ return -EINVAL;
+ }
+ adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
+ SLI_INTF_FAMILY_SHIFT);
+ adapter->generation = BE_GEN3;
+ break;
+ default:
+ adapter->generation = 0;
+ }
+ return 0;
+}
+
static int __devinit be_probe(struct pci_dev *pdev,
const struct pci_device_id *pdev_id)
{
@@ -2799,22 +2912,13 @@ static int __devinit be_probe(struct pci_dev *pdev,
goto rel_reg;
}
adapter = netdev_priv(netdev);
-
- switch (pdev->device) {
- case BE_DEVICE_ID1:
- case OC_DEVICE_ID1:
- adapter->generation = BE_GEN2;
- break;
- case BE_DEVICE_ID2:
- case OC_DEVICE_ID2:
- adapter->generation = BE_GEN3;
- break;
- default:
- adapter->generation = 0;
- }
-
adapter->pdev = pdev;
pci_set_drvdata(pdev, adapter);
+
+ status = be_dev_family_check(adapter);
+ if (status)
+ goto free_netdev;
+
adapter->netdev = netdev;
SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -2889,7 +2993,7 @@ ctrl_clean:
be_ctrl_cleanup(adapter);
free_netdev:
be_sriov_disable(adapter);
- free_netdev(adapter->netdev);
+ free_netdev(netdev);
pci_set_drvdata(pdev, NULL);
rel_reg:
pci_release_regions(pdev);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index ce1e5e9d06f6..22abfb39d813 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -8,6 +8,11 @@
* Licensed under the GPL-2 or later.
*/
+#define DRV_VERSION "1.1"
+#define DRV_DESC "Blackfin on-chip Ethernet MAC driver"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -41,12 +46,7 @@
#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 on-chip Ethernet MAC driver"
-
-MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_AUTHOR("Bryan Wu, Luke Yang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_DESC);
MODULE_ALIAS("platform:bfin_mac");
@@ -189,8 +189,7 @@ static int desc_list_init(void)
/* allocate a new skb for next time receive */
new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN);
if (!new_skb) {
- printk(KERN_NOTICE DRV_NAME
- ": init: low on mem - packet dropped\n");
+ pr_notice("init: low on mem - packet dropped\n");
goto init_error;
}
skb_reserve(new_skb, NET_IP_ALIGN);
@@ -240,7 +239,7 @@ static int desc_list_init(void)
init_error:
desc_list_free();
- printk(KERN_ERR DRV_NAME ": kmalloc failed\n");
+ pr_err("kmalloc failed\n");
return -ENOMEM;
}
@@ -259,8 +258,7 @@ static int bfin_mdio_poll(void)
while ((bfin_read_EMAC_STAADD()) & STABUSY) {
udelay(1);
if (timeout_cnt-- < 0) {
- printk(KERN_ERR DRV_NAME
- ": wait MDC/MDIO transaction to complete timeout\n");
+ pr_err("wait MDC/MDIO transaction to complete timeout\n");
return -ETIMEDOUT;
}
}
@@ -350,9 +348,9 @@ static void bfin_mac_adjust_link(struct net_device *dev)
opmode &= ~RMII_10;
break;
default:
- printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100!\n",
- DRV_NAME, phydev->speed);
+ netdev_warn(dev,
+ "Ack! Speed (%d) is not 10/100!\n",
+ phydev->speed);
break;
}
bfin_write_EMAC_OPMODE(opmode);
@@ -417,14 +415,13 @@ static int mii_probe(struct net_device *dev, int phy_mode)
/* 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);
+ netdev_err(dev, "no phy device found\n");
return -ENODEV;
}
if (phy_mode != PHY_INTERFACE_MODE_RMII &&
phy_mode != PHY_INTERFACE_MODE_MII) {
- printk(KERN_INFO "%s: Invalid phy interface mode\n", dev->name);
+ netdev_err(dev, "invalid phy interface mode\n");
return -EINVAL;
}
@@ -432,7 +429,7 @@ static int mii_probe(struct net_device *dev, int phy_mode)
0, phy_mode);
if (IS_ERR(phydev)) {
- printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ netdev_err(dev, "could not attach PHY\n");
return PTR_ERR(phydev);
}
@@ -453,11 +450,10 @@ static int mii_probe(struct net_device *dev, int phy_mode)
lp->old_duplex = -1;
lp->phydev = phydev;
- printk(KERN_INFO "%s: attached PHY driver [%s] "
- "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)"
- "@sclk=%dMHz)\n",
- DRV_NAME, phydev->drv->name, dev_name(&phydev->dev), phydev->irq,
- MDC_CLK, mdc_div, sclk/1000000);
+ pr_info("attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)@sclk=%dMHz)\n",
+ phydev->drv->name, dev_name(&phydev->dev), phydev->irq,
+ MDC_CLK, mdc_div, sclk/1000000);
return 0;
}
@@ -502,7 +498,7 @@ bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_NAME);
+ strcpy(info->driver, KBUILD_MODNAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->fw_version, "N/A");
strcpy(info->bus_info, dev_name(&dev->dev));
@@ -562,7 +558,7 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
};
/**************************************************************************/
-void setup_system_regs(struct net_device *dev)
+static void setup_system_regs(struct net_device *dev)
{
struct bfin_mac_local *lp = netdev_priv(dev);
int i;
@@ -592,6 +588,10 @@ void setup_system_regs(struct net_device *dev)
bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+ /* Set vlan regs to let 1522 bytes long packets pass through */
+ bfin_write_EMAC_VLAN1(lp->vlan1_mask);
+ bfin_write_EMAC_VLAN2(lp->vlan2_mask);
+
/* Initialize the TX DMA channel registers */
bfin_write_DMA2_X_COUNT(0);
bfin_write_DMA2_X_MODIFY(4);
@@ -827,8 +827,7 @@ static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
while ((!(bfin_read_EMAC_PTP_ISTAT() & TXTL)) && (--timeout_cnt))
udelay(1);
if (timeout_cnt == 0)
- printk(KERN_ERR DRV_NAME
- ": fails to timestamp the TX packet\n");
+ netdev_err(netdev, "timestamp the TX packet failed\n");
else {
struct skb_shared_hwtstamps shhwtstamps;
u64 ns;
@@ -1083,8 +1082,7 @@ static void bfin_mac_rx(struct net_device *dev)
* we which case we simply drop the packet
*/
if (current_rx_ptr->status.status_word & RX_ERROR_MASK) {
- printk(KERN_NOTICE DRV_NAME
- ": rx: receive error - packet dropped\n");
+ netdev_notice(dev, "rx: receive error - packet dropped\n");
dev->stats.rx_dropped++;
goto out;
}
@@ -1094,8 +1092,7 @@ static void bfin_mac_rx(struct net_device *dev)
new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN);
if (!new_skb) {
- printk(KERN_NOTICE DRV_NAME
- ": rx: low on mem - packet dropped\n");
+ netdev_notice(dev, "rx: low on mem - packet dropped\n");
dev->stats.rx_dropped++;
goto out;
}
@@ -1213,7 +1210,7 @@ static int bfin_mac_enable(struct phy_device *phydev)
int ret;
u32 opmode;
- pr_debug("%s: %s\n", DRV_NAME, __func__);
+ pr_debug("%s\n", __func__);
/* Set RX DMA */
bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
@@ -1287,19 +1284,12 @@ static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct netdev_hw_addr *ha;
- char *addrs;
u32 crc;
emac_hashhi = emac_hashlo = 0;
netdev_for_each_mc_addr(ha, dev) {
- addrs = ha->addr;
-
- /* skip non-multicast addresses */
- if (!(*addrs & 1))
- continue;
-
- crc = ether_crc(ETH_ALEN, addrs);
+ crc = ether_crc(ETH_ALEN, ha->addr);
crc >>= 26;
if (crc & 0x20)
@@ -1323,7 +1313,7 @@ static void bfin_mac_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);
+ netdev_info(dev, "set promisc mode\n");
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= PR;
bfin_write_EMAC_OPMODE(sysctl);
@@ -1393,7 +1383,7 @@ static int bfin_mac_open(struct net_device *dev)
* 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");
+ netdev_warn(dev, "no valid ethernet hw addr\n");
return -EINVAL;
}
@@ -1527,6 +1517,9 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
goto out_err_mii_probe;
}
+ lp->vlan1_mask = ETH_P_8021Q | mii_bus_data->vlan1_mask;
+ lp->vlan2_mask = ETH_P_8021Q | mii_bus_data->vlan2_mask;
+
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(ndev);
@@ -1558,7 +1551,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
bfin_mac_hwtstamp_init(ndev);
/* now, print out the card info, in a short format.. */
- dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
+ netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
return 0;
@@ -1650,7 +1643,7 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
* so set the GPIO pins to Ethernet mode
*/
pin_req = mii_bus_pd->mac_peripherals;
- rc = peripheral_request_list(pin_req, DRV_NAME);
+ rc = peripheral_request_list(pin_req, KBUILD_MODNAME);
if (rc) {
dev_err(&pdev->dev, "Requesting peripherals failed!\n");
return rc;
@@ -1739,7 +1732,7 @@ static struct platform_driver bfin_mac_driver = {
.resume = bfin_mac_resume,
.suspend = bfin_mac_suspend,
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
};
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index aed68bed2365..f8559ac9a403 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -17,7 +17,14 @@
#include <linux/etherdevice.h>
#include <linux/bfin_mac.h>
+/*
+ * Disable hardware checksum for bug #5600 if writeback cache is
+ * enabled. Otherwize, corrupted RX packet will be sent up stack
+ * without error mark.
+ */
+#ifndef CONFIG_BFIN_EXTMEM_WRITEBACK
#define BFIN_MAC_CSUM_OFFLOAD
+#endif
#define TX_RECLAIM_JIFFIES (HZ / 5)
@@ -68,7 +75,6 @@ struct bfin_mac_local {
*/
struct net_device_stats stats;
- unsigned char Mac[6]; /* MAC address of the board */
spinlock_t lock;
int wol; /* Wake On Lan */
@@ -76,6 +82,9 @@ struct bfin_mac_local {
struct timer_list tx_reclaim_timer;
struct net_device *ndev;
+ /* Data for EMAC_VLAN1 regs */
+ u16 vlan1_mask, vlan2_mask;
+
/* MII and PHY stuffs */
int old_link; /* used by bf537_adjust_link */
int old_speed;
diff --git a/drivers/net/bna/bfa_defs.h b/drivers/net/bna/bfa_defs.h
index 29c1b8de2c2d..2ea0dfe1cedc 100644
--- a/drivers/net/bna/bfa_defs.h
+++ b/drivers/net/bna/bfa_defs.h
@@ -112,16 +112,18 @@ struct bfa_ioc_pci_attr {
* IOC states
*/
enum bfa_ioc_state {
- BFA_IOC_RESET = 1, /*!< IOC is in reset state */
- BFA_IOC_SEMWAIT = 2, /*!< Waiting for IOC h/w semaphore */
- BFA_IOC_HWINIT = 3, /*!< IOC h/w is being initialized */
- BFA_IOC_GETATTR = 4, /*!< IOC is being configured */
- BFA_IOC_OPERATIONAL = 5, /*!< IOC is operational */
- BFA_IOC_INITFAIL = 6, /*!< IOC hardware failure */
- BFA_IOC_HBFAIL = 7, /*!< IOC heart-beat failure */
- BFA_IOC_DISABLING = 8, /*!< IOC is being disabled */
- BFA_IOC_DISABLED = 9, /*!< IOC is disabled */
- BFA_IOC_FWMISMATCH = 10, /*!< IOC f/w different from drivers */
+ BFA_IOC_UNINIT = 1, /*!< IOC is in uninit state */
+ BFA_IOC_RESET = 2, /*!< IOC is in reset state */
+ BFA_IOC_SEMWAIT = 3, /*!< Waiting for IOC h/w semaphore */
+ BFA_IOC_HWINIT = 4, /*!< IOC h/w is being initialized */
+ BFA_IOC_GETATTR = 5, /*!< IOC is being configured */
+ BFA_IOC_OPERATIONAL = 6, /*!< IOC is operational */
+ BFA_IOC_INITFAIL = 7, /*!< IOC hardware failure */
+ BFA_IOC_FAIL = 8, /*!< IOC heart-beat failure */
+ BFA_IOC_DISABLING = 9, /*!< IOC is being disabled */
+ BFA_IOC_DISABLED = 10, /*!< IOC is disabled */
+ BFA_IOC_FWMISMATCH = 11, /*!< IOC f/w different from drivers */
+ BFA_IOC_ENABLING = 12, /*!< IOC is being enabled */
};
/**
diff --git a/drivers/net/bna/bfa_defs_mfg_comm.h b/drivers/net/bna/bfa_defs_mfg_comm.h
index 987978fcb3fe..fdd677618361 100644
--- a/drivers/net/bna/bfa_defs_mfg_comm.h
+++ b/drivers/net/bna/bfa_defs_mfg_comm.h
@@ -95,28 +95,6 @@ enum {
(type) == BFA_MFG_TYPE_CNA10P1 || \
bfa_mfg_is_mezz(type)))
-/**
- * Check if the card having old wwn/mac handling
- */
-#define bfa_mfg_is_old_wwn_mac_model(type) (( \
- (type) == BFA_MFG_TYPE_FC8P2 || \
- (type) == BFA_MFG_TYPE_FC8P1 || \
- (type) == BFA_MFG_TYPE_FC4P2 || \
- (type) == BFA_MFG_TYPE_FC4P1 || \
- (type) == BFA_MFG_TYPE_CNA10P2 || \
- (type) == BFA_MFG_TYPE_CNA10P1 || \
- (type) == BFA_MFG_TYPE_JAYHAWK || \
- (type) == BFA_MFG_TYPE_WANCHESE))
-
-#define bfa_mfg_increment_wwn_mac(m, i) \
-do { \
- u32 t = ((m)[0] << 16) | ((m)[1] << 8) | (m)[2]; \
- t += (i); \
- (m)[0] = (t >> 16) & 0xFF; \
- (m)[1] = (t >> 8) & 0xFF; \
- (m)[2] = t & 0xFF; \
-} while (0)
-
#define bfa_mfg_adapter_prop_init_flash(card_type, prop) \
do { \
switch ((card_type)) { \
diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c
index e94e5aa97515..34933cb9569f 100644
--- a/drivers/net/bna/bfa_ioc.c
+++ b/drivers/net/bna/bfa_ioc.c
@@ -26,25 +26,6 @@
* IOC local definitions
*/
-#define bfa_ioc_timer_start(__ioc) \
- mod_timer(&(__ioc)->ioc_timer, jiffies + \
- msecs_to_jiffies(BFA_IOC_TOV))
-#define bfa_ioc_timer_stop(__ioc) del_timer(&(__ioc)->ioc_timer)
-
-#define bfa_ioc_recovery_timer_start(__ioc) \
- mod_timer(&(__ioc)->ioc_timer, jiffies + \
- msecs_to_jiffies(BFA_IOC_TOV_RECOVER))
-
-#define bfa_sem_timer_start(__ioc) \
- mod_timer(&(__ioc)->sem_timer, jiffies + \
- msecs_to_jiffies(BFA_IOC_HWSEM_TOV))
-#define bfa_sem_timer_stop(__ioc) del_timer(&(__ioc)->sem_timer)
-
-#define bfa_hb_timer_start(__ioc) \
- mod_timer(&(__ioc)->hb_timer, jiffies + \
- msecs_to_jiffies(BFA_IOC_HB_TOV))
-#define bfa_hb_timer_stop(__ioc) del_timer(&(__ioc)->hb_timer)
-
/**
* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
*/
@@ -55,11 +36,16 @@
((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
-#define bfa_ioc_notify_hbfail(__ioc) \
- ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
-
-#define bfa_ioc_is_optrom(__ioc) \
- (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
+#define bfa_ioc_notify_fail(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
+#define bfa_ioc_sync_join(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
+#define bfa_ioc_sync_leave(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))
+#define bfa_ioc_sync_ack(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
+#define bfa_ioc_sync_complete(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
#define bfa_ioc_mbox_cmd_pending(__ioc) \
(!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
@@ -85,6 +71,12 @@ static void bfa_ioc_recover(struct bfa_ioc *ioc);
static void bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc);
static void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_fail_notify(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_enabled(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_initfailed(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
u32 boot_param);
static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
@@ -101,72 +93,173 @@ static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc,
char *manufacturer);
static void bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model);
static u64 bfa_ioc_get_pwwn(struct bfa_ioc *ioc);
-static mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc);
/**
- * IOC state machine events
+ * IOC state machine definitions/declarations
*/
enum ioc_event {
- IOC_E_ENABLE = 1, /*!< IOC enable request */
- IOC_E_DISABLE = 2, /*!< IOC disable request */
- IOC_E_TIMEOUT = 3, /*!< f/w response timeout */
- IOC_E_FWREADY = 4, /*!< f/w initialization done */
- IOC_E_FWRSP_GETATTR = 5, /*!< IOC get attribute response */
- IOC_E_FWRSP_ENABLE = 6, /*!< enable f/w response */
- IOC_E_FWRSP_DISABLE = 7, /*!< disable f/w response */
- IOC_E_HBFAIL = 8, /*!< heartbeat failure */
- IOC_E_HWERROR = 9, /*!< hardware error interrupt */
- IOC_E_SEMLOCKED = 10, /*!< h/w semaphore is locked */
- IOC_E_DETACH = 11, /*!< driver detach cleanup */
+ IOC_E_RESET = 1, /*!< IOC reset request */
+ IOC_E_ENABLE = 2, /*!< IOC enable request */
+ IOC_E_DISABLE = 3, /*!< IOC disable request */
+ IOC_E_DETACH = 4, /*!< driver detach cleanup */
+ IOC_E_ENABLED = 5, /*!< f/w enabled */
+ IOC_E_FWRSP_GETATTR = 6, /*!< IOC get attribute response */
+ IOC_E_DISABLED = 7, /*!< f/w disabled */
+ IOC_E_INITFAILED = 8, /*!< failure notice by iocpf sm */
+ IOC_E_PFAILED = 9, /*!< failure notice by iocpf sm */
+ IOC_E_HBFAIL = 10, /*!< heartbeat failure */
+ IOC_E_HWERROR = 11, /*!< hardware error interrupt */
+ IOC_E_TIMEOUT = 12, /*!< timeout */
};
+bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
static struct bfa_sm_table ioc_sm_table[] = {
+ {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
{BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
- {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
- {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
- {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
- {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
- {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},
{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
- {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
- {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+ {BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
};
/**
+ * IOCPF state machine definitions/declarations
+ */
+
+/*
+ * Forward declareations for iocpf state machine
+ */
+static void bfa_iocpf_enable(struct bfa_ioc *ioc);
+static void bfa_iocpf_disable(struct bfa_ioc *ioc);
+static void bfa_iocpf_fail(struct bfa_ioc *ioc);
+static void bfa_iocpf_initfail(struct bfa_ioc *ioc);
+static void bfa_iocpf_getattrfail(struct bfa_ioc *ioc);
+static void bfa_iocpf_stop(struct bfa_ioc *ioc);
+
+/**
+ * IOCPF state machine events
+ */
+enum iocpf_event {
+ IOCPF_E_ENABLE = 1, /*!< IOCPF enable request */
+ IOCPF_E_DISABLE = 2, /*!< IOCPF disable request */
+ IOCPF_E_STOP = 3, /*!< stop on driver detach */
+ IOCPF_E_FWREADY = 4, /*!< f/w initialization done */
+ IOCPF_E_FWRSP_ENABLE = 5, /*!< enable f/w response */
+ IOCPF_E_FWRSP_DISABLE = 6, /*!< disable f/w response */
+ IOCPF_E_FAIL = 7, /*!< failure notice by ioc sm */
+ IOCPF_E_INITFAIL = 8, /*!< init fail notice by ioc sm */
+ IOCPF_E_GETATTRFAIL = 9, /*!< init fail notice by ioc sm */
+ IOCPF_E_SEMLOCKED = 10, /*!< h/w semaphore is locked */
+ IOCPF_E_TIMEOUT = 11, /*!< f/w response timeout */
+};
+
+/**
+ * IOCPF states
+ */
+enum bfa_iocpf_state {
+ BFA_IOCPF_RESET = 1, /*!< IOC is in reset state */
+ BFA_IOCPF_SEMWAIT = 2, /*!< Waiting for IOC h/w semaphore */
+ BFA_IOCPF_HWINIT = 3, /*!< IOC h/w is being initialized */
+ BFA_IOCPF_READY = 4, /*!< IOCPF is initialized */
+ BFA_IOCPF_INITFAIL = 5, /*!< IOCPF failed */
+ BFA_IOCPF_FAIL = 6, /*!< IOCPF failed */
+ BFA_IOCPF_DISABLING = 7, /*!< IOCPF is being disabled */
+ BFA_IOCPF_DISABLED = 8, /*!< IOCPF is disabled */
+ BFA_IOCPF_FWMISMATCH = 9, /*!< IOC f/w different from drivers */
+};
+
+bfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf,
+ enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf,
+ enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf, enum iocpf_event);
+
+static struct bfa_sm_table iocpf_sm_table[] = {
+ {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET},
+ {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH},
+ {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH},
+ {BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT},
+ {BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},
+ {BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},
+ {BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},
+ {BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},
+ {BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},
+ {BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},
+ {BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},
+ {BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},
+ {BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},
+ {BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
+};
+
+/**
+ * IOC State Machine
+ */
+
+/**
+ * Beginning state. IOC uninit state.
+ */
+static void
+bfa_ioc_sm_uninit_entry(struct bfa_ioc *ioc)
+{
+}
+
+/**
+ * IOC is in uninit state.
+ */
+static void
+bfa_ioc_sm_uninit(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_RESET:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
* Reset entry actions -- initialize state machine
*/
static void
bfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
{
- ioc->retry_count = 0;
- ioc->auto_recover = bfa_nw_auto_recover;
+ bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);
}
/**
- * Beginning state. IOC is in reset state.
+ * IOC is in reset state.
*/
static void
bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
case IOC_E_ENABLE:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
break;
case IOC_E_DISABLE:
@@ -174,6 +267,7 @@ bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
break;
case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
break;
default:
@@ -181,42 +275,43 @@ bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
}
}
-/**
- * Semaphore should be acquired for version check.
- */
static void
-bfa_ioc_sm_fwcheck_entry(struct bfa_ioc *ioc)
+bfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
{
- bfa_ioc_hw_sem_get(ioc);
+ bfa_iocpf_enable(ioc);
}
/**
- * Awaiting h/w semaphore to continue with version check.
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
*/
static void
-bfa_ioc_sm_fwcheck(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
- case IOC_E_SEMLOCKED:
- if (bfa_ioc_firmware_lock(ioc)) {
- ioc->retry_count = 0;
- bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
- } else {
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
- }
+ case IOC_E_ENABLED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+ break;
+
+ case IOC_E_PFAILED:
+ /* !!! fall through !!! */
+ case IOC_E_HWERROR:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFAILED)
+ bfa_iocpf_initfail(ioc);
break;
case IOC_E_DISABLE:
- bfa_ioc_disable_comp(ioc);
- /* fall through */
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
case IOC_E_DETACH:
- bfa_ioc_hw_sem_get_cancel(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_iocpf_stop(ioc);
break;
- case IOC_E_FWREADY:
+ case IOC_E_ENABLE:
break;
default:
@@ -225,41 +320,85 @@ bfa_ioc_sm_fwcheck(struct bfa_ioc *ioc, enum ioc_event event)
}
/**
- * Notify enable completion callback and generate mismatch AEN.
+ * Semaphore should be acquired for version check.
*/
static void
-bfa_ioc_sm_mismatch_entry(struct bfa_ioc *ioc)
+bfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
{
- /**
- * Provide enable completion callback and AEN notification only once.
- */
- if (ioc->retry_count == 0)
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- ioc->retry_count++;
- bfa_ioc_timer_start(ioc);
+ mod_timer(&ioc->ioc_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV));
+ bfa_ioc_send_getattr(ioc);
}
/**
- * Awaiting firmware version match.
+ * IOC configuration in progress. Timer is active.
*/
static void
-bfa_ioc_sm_mismatch(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
+ case IOC_E_FWRSP_GETATTR:
+ del_timer(&ioc->ioc_timer);
+ bfa_ioc_check_attr_wwns(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+ break;
+
+ case IOC_E_PFAILED:
+ case IOC_E_HWERROR:
+ del_timer(&ioc->ioc_timer);
+ /* fall through */
case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFAILED)
+ bfa_iocpf_getattrfail(ioc);
break;
case IOC_E_DISABLE:
- bfa_ioc_disable_comp(ioc);
- /* fall through */
+ del_timer(&ioc->ioc_timer);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
- case IOC_E_DETACH:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ case IOC_E_ENABLE:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
+ bfa_ioc_hb_monitor(ioc);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_ENABLE:
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hb_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
- case IOC_E_FWREADY:
+ case IOC_E_PFAILED:
+ case IOC_E_HWERROR:
+ bfa_ioc_hb_stop(ioc);
+ /* !!! fall through !!! */
+ case IOC_E_HBFAIL:
+ bfa_ioc_fail_notify(ioc);
+ if (ioc->iocpf.auto_recover)
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ else
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+
+ if (event != IOC_E_PFAILED)
+ bfa_iocpf_fail(ioc);
break;
default:
@@ -267,30 +406,61 @@ bfa_ioc_sm_mismatch(struct bfa_ioc *ioc, enum ioc_event event)
}
}
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
+{
+ bfa_iocpf_disable(ioc);
+}
+
/**
- * Request for semaphore.
+ * IOC is being desabled
*/
static void
-bfa_ioc_sm_semwait_entry(struct bfa_ioc *ioc)
+bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
{
- bfa_ioc_hw_sem_get(ioc);
+ switch (event) {
+ case IOC_E_DISABLED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_HWERROR:
+ /*
+ * No state change. Will move to disabled state
+ * after iocpf sm completes failure processing and
+ * moves to disabled state.
+ */
+ bfa_iocpf_fail(ioc);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
}
/**
- * Awaiting semaphore for h/w initialzation.
+ * IOC desable completion entry.
*/
static void
-bfa_ioc_sm_semwait(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
- case IOC_E_SEMLOCKED:
- ioc->retry_count = 0;
- bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
break;
case IOC_E_DISABLE:
- bfa_ioc_hw_sem_get_cancel(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_iocpf_stop(ioc);
break;
default:
@@ -299,46 +469,45 @@ bfa_ioc_sm_semwait(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_hwinit_entry(struct bfa_ioc *ioc)
+bfa_ioc_sm_fail_retry_entry(struct bfa_ioc *ioc)
{
- bfa_ioc_timer_start(ioc);
- bfa_ioc_reset(ioc, false);
}
/**
- * @brief
- * Hardware is being initialized. Interrupts are enabled.
- * Holding hardware semaphore lock.
+ * Hardware initialization retry.
*/
static void
-bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_ioc_sm_fail_retry(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
- case IOC_E_FWREADY:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+ case IOC_E_ENABLED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
break;
+ case IOC_E_PFAILED:
case IOC_E_HWERROR:
- bfa_ioc_timer_stop(ioc);
- /* fall through */
+ /**
+ * Initialization retry failed.
+ */
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ if (event != IOC_E_PFAILED)
+ bfa_iocpf_initfail(ioc);
+ break;
- case IOC_E_TIMEOUT:
- ioc->retry_count++;
- if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
- bfa_ioc_timer_start(ioc);
- bfa_ioc_reset(ioc, true);
- break;
- }
+ case IOC_E_INITFAILED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+ break;
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ case IOC_E_ENABLE:
break;
case IOC_E_DISABLE:
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_iocpf_stop(ioc);
break;
default:
@@ -347,51 +516,248 @@ bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
+bfa_ioc_sm_fail_entry(struct bfa_ioc *ioc)
{
- bfa_ioc_timer_start(ioc);
- bfa_ioc_send_enable(ioc);
}
/**
- * Host IOC function is being enabled, awaiting response from firmware.
- * Semaphore is acquired.
+ * IOC failure.
*/
static void
-bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_ioc_sm_fail(struct bfa_ioc *ioc, enum ioc_event event)
{
switch (event) {
- case IOC_E_FWRSP_ENABLE:
- bfa_ioc_timer_stop(ioc);
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+ case IOC_E_ENABLE:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_iocpf_stop(ioc);
break;
case IOC_E_HWERROR:
- bfa_ioc_timer_stop(ioc);
- /* fall through */
+ /* HB failure notification, ignore. */
+ break;
- case IOC_E_TIMEOUT:
- ioc->retry_count++;
- if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
- writel(BFI_IOC_UNINIT,
- ioc->ioc_regs.ioc_fwstate);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
- break;
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * IOCPF State Machine
+ */
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_iocpf_sm_reset_entry(struct bfa_iocpf *iocpf)
+{
+ iocpf->retry_count = 0;
+ iocpf->auto_recover = bfa_nw_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_iocpf_sm_reset(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ switch (event) {
+ case IOCPF_E_ENABLE:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
+ break;
+
+ case IOCPF_E_STOP:
+ break;
+
+ default:
+ bfa_sm_fault(iocpf->ioc, event);
+ }
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ if (bfa_ioc_firmware_lock(ioc)) {
+ if (bfa_ioc_sync_complete(ioc)) {
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ mod_timer(&ioc->sem_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
+ }
+ } else {
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);
}
+ break;
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ case IOCPF_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ bfa_ioc_pf_disabled(ioc);
break;
- case IOC_E_DISABLE:
- bfa_ioc_timer_stop(ioc);
+ case IOCPF_E_STOP:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Notify enable completion callback
+ */
+static void
+bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf *iocpf)
+{
+ /* Call only the first time sm enters fwmismatch state. */
+ if (iocpf->retry_count == 0)
+ bfa_ioc_pf_fwmismatch(iocpf->ioc);
+
+ iocpf->retry_count++;
+ mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV));
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_iocpf_sm_mismatch(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
+ switch (event) {
+ case IOCPF_E_TIMEOUT:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
+ break;
+
+ case IOCPF_E_DISABLE:
+ del_timer(&ioc->iocpf_timer);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ bfa_ioc_pf_disabled(ioc);
+ break;
+
+ case IOCPF_E_STOP:
+ del_timer(&ioc->iocpf_timer);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_iocpf_sm_semwait_entry(struct bfa_iocpf *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_iocpf_sm_semwait(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ if (bfa_ioc_sync_complete(ioc)) {
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ bfa_nw_ioc_hw_sem_release(ioc);
+ mod_timer(&ioc->sem_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
+ }
+ break;
+
+ case IOCPF_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf *iocpf)
+{
+ mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV));
+ bfa_ioc_reset(iocpf->ioc, 0);
+}
+
+/**
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_iocpf_sm_hwinit(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
+ switch (event) {
+ case IOCPF_E_FWREADY:
+ del_timer(&ioc->iocpf_timer);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling);
+ break;
+
+ case IOCPF_E_INITFAIL:
+ del_timer(&ioc->iocpf_timer);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOCPF_E_TIMEOUT:
bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ if (event == IOCPF_E_TIMEOUT)
+ bfa_ioc_pf_failed(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
- case IOC_E_FWREADY:
- bfa_ioc_send_enable(ioc);
+ case IOCPF_E_DISABLE:
+ del_timer(&ioc->iocpf_timer);
+ bfa_ioc_sync_leave(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
default:
@@ -400,37 +766,49 @@ bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_enabling_entry(struct bfa_iocpf *iocpf)
{
- bfa_ioc_timer_start(ioc);
- bfa_ioc_send_getattr(ioc);
+ mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV));
+ bfa_ioc_send_enable(iocpf->ioc);
}
/**
- * @brief
- * IOC configuration in progress. Timer is active.
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
*/
static void
-bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_enabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
switch (event) {
- case IOC_E_FWRSP_GETATTR:
- bfa_ioc_timer_stop(ioc);
- bfa_ioc_check_attr_wwns(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+ case IOCPF_E_FWRSP_ENABLE:
+ del_timer(&ioc->iocpf_timer);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);
break;
- case IOC_E_HWERROR:
- bfa_ioc_timer_stop(ioc);
- /* fall through */
+ case IOCPF_E_INITFAIL:
+ del_timer(&ioc->iocpf_timer);
+ /*
+ * !!! fall through !!!
+ */
+ case IOCPF_E_TIMEOUT:
+ bfa_nw_ioc_hw_sem_release(ioc);
+ if (event == IOCPF_E_TIMEOUT)
+ bfa_ioc_pf_failed(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
+ break;
- case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ case IOCPF_E_DISABLE:
+ del_timer(&ioc->iocpf_timer);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
break;
- case IOC_E_DISABLE:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ case IOCPF_E_FWREADY:
+ bfa_ioc_send_enable(ioc);
break;
default:
@@ -438,36 +816,42 @@ bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
}
}
+static bool
+bfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
+{
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
static void
-bfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_ready_entry(struct bfa_iocpf *iocpf)
{
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
- bfa_ioc_hb_monitor(ioc);
+ bfa_ioc_pf_enabled(iocpf->ioc);
}
static void
-bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_ready(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
switch (event) {
- case IOC_E_ENABLE:
+ case IOCPF_E_DISABLE:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
break;
- case IOC_E_DISABLE:
- bfa_ioc_hb_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ case IOCPF_E_GETATTRFAIL:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
- case IOC_E_HWERROR:
- case IOC_E_FWREADY:
- /**
- * Hard error or IOC recovery by other function.
- * Treat it same as heartbeat failure.
- */
- bfa_ioc_hb_stop(ioc);
- /* !!! fall through !!! */
+ case IOCPF_E_FAIL:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
+ break;
- case IOC_E_HBFAIL:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+ case IOCPF_E_FWREADY:
+ bfa_ioc_pf_failed(ioc);
+ if (bfa_nw_ioc_is_operational(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
+ else
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
default:
@@ -476,33 +860,40 @@ bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_disabling_entry(struct bfa_iocpf *iocpf)
{
- bfa_ioc_timer_start(ioc);
- bfa_ioc_send_disable(ioc);
+ mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV));
+ bfa_ioc_send_disable(iocpf->ioc);
}
/**
* IOC is being disabled
*/
static void
-bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
switch (event) {
- case IOC_E_FWRSP_DISABLE:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ case IOCPF_E_FWRSP_DISABLE:
+ case IOCPF_E_FWREADY:
+ del_timer(&ioc->iocpf_timer);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
- case IOC_E_HWERROR:
- bfa_ioc_timer_stop(ioc);
+ case IOCPF_E_FAIL:
+ del_timer(&ioc->iocpf_timer);
/*
* !!! fall through !!!
*/
- case IOC_E_TIMEOUT:
+ case IOCPF_E_TIMEOUT:
writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ case IOCPF_E_FWRSP_ENABLE:
break;
default:
@@ -510,33 +901,58 @@ bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
}
}
-/**
- * IOC disable completion entry.
- */
static void
-bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf *iocpf)
{
- bfa_ioc_disable_comp(ioc);
+ bfa_ioc_hw_sem_get(iocpf->ioc);
}
+/**
+ * IOC hb ack request is being removed.
+ */
static void
-bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_disabling_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
switch (event) {
- case IOC_E_ENABLE:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_sync_leave(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
- case IOC_E_DISABLE:
- ioc->cbfn->disable_cbfn(ioc->bfa);
+ case IOCPF_E_FAIL:
break;
- case IOC_E_FWREADY:
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_iocpf_sm_disabled_entry(struct bfa_iocpf *iocpf)
+{
+ bfa_ioc_pf_disabled(iocpf->ioc);
+}
+
+static void
+bfa_iocpf_sm_disabled(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
+ switch (event) {
+ case IOCPF_E_ENABLE:
+ iocpf->retry_count = 0;
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
break;
- case IOC_E_DETACH:
+ case IOCPF_E_STOP:
bfa_ioc_firmware_unlock(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
default:
@@ -545,33 +961,50 @@ bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_initfail_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf *iocpf)
{
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- bfa_ioc_timer_start(ioc);
+ bfa_ioc_hw_sem_get(iocpf->ioc);
}
/**
- * @brief
* Hardware initialization failed.
*/
static void
-bfa_ioc_sm_initfail(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
+ struct bfa_ioc *ioc = iocpf->ioc;
+
switch (event) {
- case IOC_E_DISABLE:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_notify_fail(ioc);
+ bfa_ioc_sync_ack(ioc);
+ iocpf->retry_count++;
+ if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_sync_leave(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
break;
- case IOC_E_DETACH:
- bfa_ioc_timer_stop(ioc);
+ case IOCPF_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ case IOCPF_E_STOP:
+ bfa_ioc_hw_sem_get_cancel(ioc);
bfa_ioc_firmware_unlock(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
- case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ case IOCPF_E_FAIL:
break;
default:
@@ -580,80 +1013,108 @@ bfa_ioc_sm_initfail(struct bfa_ioc *ioc, enum ioc_event event)
}
static void
-bfa_ioc_sm_hbfail_entry(struct bfa_ioc *ioc)
+bfa_iocpf_sm_initfail_entry(struct bfa_iocpf *iocpf)
{
- struct list_head *qe;
- struct bfa_ioc_hbfail_notify *notify;
+ bfa_ioc_pf_initfailed(iocpf->ioc);
+}
- /**
- * Mark IOC as failed in hardware and stop firmware.
- */
- bfa_ioc_lpu_stop(ioc);
- writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+/**
+ * Hardware initialization failed.
+ */
+static void
+bfa_iocpf_sm_initfail(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc *ioc = iocpf->ioc;
- /**
- * Notify other functions on HB failure.
- */
- bfa_ioc_notify_hbfail(ioc);
+ switch (event) {
+ case IOCPF_E_DISABLE:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ break;
- /**
- * Notify driver and common modules registered for notification.
- */
- ioc->cbfn->hbfail_cbfn(ioc->bfa);
- list_for_each(qe, &ioc->hb_notify_q) {
- notify = (struct bfa_ioc_hbfail_notify *) qe;
- notify->cbfn(notify->cbarg);
+ case IOCPF_E_STOP:
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
}
+}
+static void
+bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf *iocpf)
+{
/**
- * Flush any queued up mailbox requests.
+ * Mark IOC as failed in hardware and stop firmware.
*/
- bfa_ioc_mbox_hbfail(ioc);
+ bfa_ioc_lpu_stop(iocpf->ioc);
/**
- * Trigger auto-recovery after a delay.
+ * Flush any queued up mailbox requests.
*/
- if (ioc->auto_recover)
- mod_timer(&ioc->ioc_timer, jiffies +
- msecs_to_jiffies(BFA_IOC_TOV_RECOVER));
+ bfa_ioc_mbox_hbfail(iocpf->ioc);
+ bfa_ioc_hw_sem_get(iocpf->ioc);
}
/**
- * @brief
- * IOC heartbeat failure.
+ * IOC is in failed state.
*/
static void
-bfa_ioc_sm_hbfail(struct bfa_ioc *ioc, enum ioc_event event)
+bfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
- switch (event) {
+ struct bfa_ioc *ioc = iocpf->ioc;
- case IOC_E_ENABLE:
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_ack(ioc);
+ bfa_ioc_notify_fail(ioc);
+ if (!iocpf->auto_recover) {
+ bfa_ioc_sync_leave(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
break;
- case IOC_E_DISABLE:
- if (ioc->auto_recover)
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ case IOCPF_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
- case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ case IOCPF_E_FAIL:
break;
- case IOC_E_FWREADY:
- /**
- * Recovery is already initiated by other function.
- */
- break;
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
- case IOC_E_HWERROR:
- /*
- * HB failure notification, ignore.
- */
+static void
+bfa_iocpf_sm_fail_entry(struct bfa_iocpf *iocpf)
+{
+}
+
+/**
+ * @brief
+ * IOC is in failed state.
+ */
+static void
+bfa_iocpf_sm_fail(struct bfa_iocpf *iocpf, enum iocpf_event event)
+{
+ switch (event) {
+ case IOCPF_E_DISABLE:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
+
default:
- bfa_sm_fault(ioc, event);
+ bfa_sm_fault(iocpf->ioc, event);
}
}
@@ -678,14 +1139,6 @@ bfa_ioc_disable_comp(struct bfa_ioc *ioc)
}
}
-void
-bfa_nw_ioc_sem_timeout(void *ioc_arg)
-{
- struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
-
- bfa_ioc_hw_sem_get(ioc);
-}
-
bool
bfa_nw_ioc_sem_get(void __iomem *sem_reg)
{
@@ -725,7 +1178,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
*/
r32 = readl(ioc->ioc_regs.ioc_sem_reg);
if (r32 == 0) {
- bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
return;
}
@@ -865,12 +1318,6 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
{
struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
- /**
- * If bios/efi boot (flash based) -- return true
- */
- if (bfa_ioc_is_optrom(ioc))
- return true;
-
bfa_nw_ioc_fwver_get(ioc, &fwhdr);
drv_fwhdr = (struct bfi_ioc_image_hdr *)
bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
@@ -934,20 +1381,15 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
/**
* If IOC function is disabled and firmware version is same,
* just re-enable IOC.
- *
- * If option rom, IOC must not be in operational state. With
- * convergence, IOC will be in operational state when 2nd driver
- * is loaded.
*/
- if (ioc_fwstate == BFI_IOC_DISABLED ||
- (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
+ if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
/**
* When using MSI-X any pending firmware ready event should
* be flushed. Otherwise MSI-X interrupts are not delivered.
*/
bfa_ioc_msgflush(ioc);
ioc->cbfn->reset_cbfn(ioc->bfa);
- bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
return;
}
@@ -1033,7 +1475,6 @@ bfa_nw_ioc_hb_check(void *cbarg)
hb_count = readl(ioc->ioc_regs.heartbeat);
if (ioc->hb_count == hb_count) {
- pr_crit("Firmware heartbeat failure at %d", hb_count);
bfa_ioc_recover(ioc);
return;
} else {
@@ -1078,11 +1519,6 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
*/
bfa_ioc_lmem_init(ioc);
- /**
- * Flash based firmware boot
- */
- if (bfa_ioc_is_optrom(ioc))
- boot_type = BFI_BOOT_TYPE_FLASH;
fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
pgnum = bfa_ioc_smem_pgnum(ioc, loff);
@@ -1209,6 +1645,55 @@ bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc)
bfa_q_deq(&mod->cmd_q, &cmd);
}
+static void
+bfa_ioc_fail_notify(struct bfa_ioc *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify *notify;
+
+ /**
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify *) qe;
+ notify->cbfn(notify->cbarg);
+ }
+}
+
+static void
+bfa_ioc_pf_enabled(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_ENABLED);
+}
+
+static void
+bfa_ioc_pf_disabled(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_DISABLED);
+}
+
+static void
+bfa_ioc_pf_initfailed(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_INITFAILED);
+}
+
+static void
+bfa_ioc_pf_failed(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_PFAILED);
+}
+
+static void
+bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc)
+{
+ /**
+ * Provide enable completion callback and AEN notification.
+ */
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+}
+
/**
* IOC public
*/
@@ -1304,6 +1789,7 @@ static void
bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
{
union bfi_ioc_i2h_msg_u *msg;
+ struct bfa_iocpf *iocpf = &ioc->iocpf;
msg = (union bfi_ioc_i2h_msg_u *) m;
@@ -1314,15 +1800,15 @@ bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
break;
case BFI_IOC_I2H_READY_EVENT:
- bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ bfa_fsm_send_event(iocpf, IOCPF_E_FWREADY);
break;
case BFI_IOC_I2H_ENABLE_REPLY:
- bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+ bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);
break;
case BFI_IOC_I2H_DISABLE_REPLY:
- bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+ bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE);
break;
case BFI_IOC_I2H_GETATTR_REPLY:
@@ -1348,11 +1834,13 @@ bfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn)
ioc->fcmode = false;
ioc->pllinit = false;
ioc->dbg_fwsave_once = true;
+ ioc->iocpf.ioc = ioc;
bfa_ioc_mbox_attach(ioc);
INIT_LIST_HEAD(&ioc->hb_notify_q);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_fsm_send_event(ioc, IOC_E_RESET);
}
/**
@@ -1657,7 +2145,40 @@ bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
static enum bfa_ioc_state
bfa_ioc_get_state(struct bfa_ioc *ioc)
{
- return bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+ enum bfa_iocpf_state iocpf_st;
+ enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+
+ if (ioc_st == BFA_IOC_ENABLING ||
+ ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) {
+
+ iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
+
+ switch (iocpf_st) {
+ case BFA_IOCPF_SEMWAIT:
+ ioc_st = BFA_IOC_SEMWAIT;
+ break;
+
+ case BFA_IOCPF_HWINIT:
+ ioc_st = BFA_IOC_HWINIT;
+ break;
+
+ case BFA_IOCPF_FWMISMATCH:
+ ioc_st = BFA_IOC_FWMISMATCH;
+ break;
+
+ case BFA_IOCPF_FAIL:
+ ioc_st = BFA_IOC_FAIL;
+ break;
+
+ case BFA_IOCPF_INITFAIL:
+ ioc_st = BFA_IOC_INITFAIL;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return ioc_st;
}
void
@@ -1689,28 +2210,7 @@ bfa_ioc_get_pwwn(struct bfa_ioc *ioc)
mac_t
bfa_nw_ioc_get_mac(struct bfa_ioc *ioc)
{
- /*
- * Currently mfg mac is used as FCoE enode mac (not configured by PBC)
- */
- if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)
- return bfa_ioc_get_mfg_mac(ioc);
- else
- return ioc->attr->mac;
-}
-
-static mac_t
-bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc)
-{
- mac_t m;
-
- m = ioc->attr->mfg_mac;
- if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type))
- m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
- else
- bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]),
- bfa_ioc_pcifn(ioc));
-
- return m;
+ return ioc->attr->mac;
}
/**
@@ -1719,8 +2219,13 @@ bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc)
static void
bfa_ioc_recover(struct bfa_ioc *ioc)
{
- bfa_ioc_stats(ioc, ioc_hbfails);
- bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+ u16 bdf;
+
+ bdf = (ioc->pcidev.pci_slot << 8 | ioc->pcidev.pci_func << 3 |
+ ioc->pcidev.device_id);
+
+ pr_crit("Firmware heartbeat failure at %d", bdf);
+ BUG_ON(1);
}
static void
@@ -1728,5 +2233,61 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc)
{
if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
return;
+}
+
+/**
+ * @dg hal_iocpf_pvt BFA IOC PF private functions
+ * @{
+ */
+
+static void
+bfa_iocpf_enable(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
+}
+
+static void
+bfa_iocpf_disable(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
+}
+
+static void
+bfa_iocpf_fail(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
+}
+
+static void
+bfa_iocpf_initfail(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
+}
+
+static void
+bfa_iocpf_getattrfail(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
+}
+
+static void
+bfa_iocpf_stop(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
+}
+void
+bfa_nw_iocpf_timeout(void *ioc_arg)
+{
+ struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
+}
+
+void
+bfa_nw_iocpf_sem_timeout(void *ioc_arg)
+{
+ struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+ bfa_ioc_hw_sem_get(ioc);
}
diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h
index a73d84ec808c..e4974bc24ef6 100644
--- a/drivers/net/bna/bfa_ioc.h
+++ b/drivers/net/bna/bfa_ioc.h
@@ -26,16 +26,7 @@
#define BFA_IOC_TOV 3000 /* msecs */
#define BFA_IOC_HWSEM_TOV 500 /* msecs */
#define BFA_IOC_HB_TOV 500 /* msecs */
-#define BFA_IOC_HWINIT_MAX 2
-#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV
-
-/**
- * Generic Scatter Gather Element used by driver
- */
-struct bfa_sge {
- u32 sg_len;
- void *sg_addr;
-};
+#define BFA_IOC_HWINIT_MAX 5
/**
* PCI device information required by IOC
@@ -65,19 +56,6 @@ struct bfa_dma {
#define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */
/**
- * @brief BFA dma address assignment macro
- */
-#define bfa_dma_addr_set(dma_addr, pa) \
- __bfa_dma_addr_set(&dma_addr, (u64)pa)
-
-static inline void
-__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
-{
- dma_addr->a32.addr_lo = (u32) pa;
- dma_addr->a32.addr_hi = (u32) (upper_32_bits(pa));
-}
-
-/**
* @brief BFA dma address assignment macro. (big endian format)
*/
#define bfa_dma_be_addr_set(dma_addr, pa) \
@@ -105,8 +83,11 @@ struct bfa_ioc_regs {
void __iomem *host_page_num_fn;
void __iomem *heartbeat;
void __iomem *ioc_fwstate;
+ void __iomem *alt_ioc_fwstate;
void __iomem *ll_halt;
+ void __iomem *alt_ll_halt;
void __iomem *err_set;
+ void __iomem *ioc_fail_sync;
void __iomem *shirq_isr_next;
void __iomem *shirq_msk_next;
void __iomem *smem_page_start;
@@ -165,16 +146,22 @@ struct bfa_ioc_hbfail_notify {
(__notify)->cbarg = (__cbarg); \
} while (0)
+struct bfa_iocpf {
+ bfa_fsm_t fsm;
+ struct bfa_ioc *ioc;
+ u32 retry_count;
+ bool auto_recover;
+};
+
struct bfa_ioc {
bfa_fsm_t fsm;
struct bfa *bfa;
struct bfa_pcidev pcidev;
- struct bfa_timer_mod *timer_mod;
struct timer_list ioc_timer;
+ struct timer_list iocpf_timer;
struct timer_list sem_timer;
struct timer_list hb_timer;
u32 hb_count;
- u32 retry_count;
struct list_head hb_notify_q;
void *dbg_fwsave;
int dbg_fwsave_len;
@@ -182,7 +169,6 @@ struct bfa_ioc {
enum bfi_mclass ioc_mc;
struct bfa_ioc_regs ioc_regs;
struct bfa_ioc_drv_stats stats;
- bool auto_recover;
bool fcmode;
bool ctdev;
bool cna;
@@ -195,6 +181,7 @@ struct bfa_ioc {
struct bfa_ioc_cbfn *cbfn;
struct bfa_ioc_mbox_mod mbox_mod;
struct bfa_ioc_hwif *ioc_hwif;
+ struct bfa_iocpf iocpf;
};
struct bfa_ioc_hwif {
@@ -205,8 +192,12 @@ struct bfa_ioc_hwif {
void (*ioc_map_port) (struct bfa_ioc *ioc);
void (*ioc_isr_mode_set) (struct bfa_ioc *ioc,
bool msix);
- void (*ioc_notify_hbfail) (struct bfa_ioc *ioc);
+ void (*ioc_notify_fail) (struct bfa_ioc *ioc);
void (*ioc_ownership_reset) (struct bfa_ioc *ioc);
+ void (*ioc_sync_join) (struct bfa_ioc *ioc);
+ void (*ioc_sync_leave) (struct bfa_ioc *ioc);
+ void (*ioc_sync_ack) (struct bfa_ioc *ioc);
+ bool (*ioc_sync_complete) (struct bfa_ioc *ioc);
};
#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
@@ -271,7 +262,6 @@ void bfa_nw_ioc_enable(struct bfa_ioc *ioc);
void bfa_nw_ioc_disable(struct bfa_ioc *ioc);
void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc);
-
void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr);
void bfa_nw_ioc_hbfail_register(struct bfa_ioc *ioc,
struct bfa_ioc_hbfail_notify *notify);
@@ -289,7 +279,8 @@ mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc);
*/
void bfa_nw_ioc_timeout(void *ioc);
void bfa_nw_ioc_hb_check(void *ioc);
-void bfa_nw_ioc_sem_timeout(void *ioc);
+void bfa_nw_iocpf_timeout(void *ioc);
+void bfa_nw_iocpf_sem_timeout(void *ioc);
/*
* F/W Image Size & Chunk
diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c
index 121cfd6d48b1..469997c4ffd1 100644
--- a/drivers/net/bna/bfa_ioc_ct.c
+++ b/drivers/net/bna/bfa_ioc_ct.c
@@ -22,6 +22,15 @@
#include "bfi_ctreg.h"
#include "bfa_defs.h"
+#define bfa_ioc_ct_sync_pos(__ioc) \
+ ((u32) (1 << bfa_ioc_pcifn(__ioc)))
+#define BFA_IOC_SYNC_REQD_SH 16
+#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
+#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
+#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
+#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
+ (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
+
/*
* forward declarations
*/
@@ -30,8 +39,12 @@ static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
-static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc);
static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc);
+static bool bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc);
static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode);
static struct bfa_ioc_hwif nw_hwif_ct;
@@ -48,8 +61,12 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
nw_hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
nw_hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
- nw_hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+ nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+ nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
+ nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
+ nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
+ nw_hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete;
ioc->ioc_hwif = &nw_hwif_ct;
}
@@ -86,6 +103,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
if (usecnt == 0) {
writel(1, ioc->ioc_regs.ioc_usage_reg);
bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_fail_sync);
return true;
}
@@ -149,12 +167,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
* Notify other functions on HB failure.
*/
static void
-bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc)
+bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc)
{
if (ioc->cna) {
writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
/* Wait for halt to take effect */
readl(ioc->ioc_regs.ll_halt);
+ readl(ioc->ioc_regs.alt_ll_halt);
} else {
writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
readl(ioc->ioc_regs.err_set);
@@ -206,15 +226,19 @@ bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
}
/*
@@ -232,6 +256,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+ ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC);
/**
* sram memory access
@@ -317,6 +342,77 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
bfa_nw_ioc_hw_sem_release(ioc);
}
+/**
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_ct_sync_join(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
+
+ writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
+ bfa_ioc_ct_sync_pos(ioc);
+
+ writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+
+ writel((r32 | bfa_ioc_ct_sync_pos(ioc)), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static bool
+bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+ u32 sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
+ u32 tmp_ackd;
+
+ if (sync_ackd == 0)
+ return true;
+
+ /**
+ * The check below is to see whether any other PCI fn
+ * has reinitialized the ASIC (reset sync_ackd bits)
+ * and failed again while this IOC was waiting for hw
+ * semaphore (in bfa_iocpf_sm_semwait()).
+ */
+ tmp_ackd = sync_ackd;
+ if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) &&
+ !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
+ sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
+
+ if (sync_reqd == sync_ackd) {
+ writel(bfa_ioc_ct_clear_sync_ackd(r32),
+ ioc->ioc_regs.ioc_fail_sync);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
+ return true;
+ }
+
+ /**
+ * If another PCI fn reinitialized and failed again while
+ * this IOC was waiting for hw sem, the sync_ackd bit for
+ * this IOC need to be set again to allow reinitialization.
+ */
+ if (tmp_ackd != sync_ackd)
+ writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
+
+ return false;
+}
+
static enum bfa_status
bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode)
{
diff --git a/drivers/net/bna/bfi_ctreg.h b/drivers/net/bna/bfi_ctreg.h
index 404ea351d4a1..5130d7918660 100644
--- a/drivers/net/bna/bfi_ctreg.h
+++ b/drivers/net/bna/bfi_ctreg.h
@@ -535,6 +535,7 @@ enum {
#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
#define CPE_DEPTH_Q(__n) \
(CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
@@ -552,22 +553,30 @@ enum {
(RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
#define RME_CI_PTR_Q(__n) \
(RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
-#define HQM_QSET_RXQ_DRBL_P0(__n) (HQM_QSET0_RXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
-#define HQM_QSET_TXQ_DRBL_P0(__n) (HQM_QSET0_TXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
-#define HQM_QSET_IB_DRBL_1_P0(__n) (HQM_QSET0_IB_DRBL_1_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
-#define HQM_QSET_IB_DRBL_2_P0(__n) (HQM_QSET0_IB_DRBL_2_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
-#define HQM_QSET_RXQ_DRBL_P1(__n) (HQM_QSET0_RXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
-#define HQM_QSET_TXQ_DRBL_P1(__n) (HQM_QSET0_TXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
-#define HQM_QSET_IB_DRBL_1_P1(__n) (HQM_QSET0_IB_DRBL_1_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
-#define HQM_QSET_IB_DRBL_2_P1(__n) (HQM_QSET0_IB_DRBL_2_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+ (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+ (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+ (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+ (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+ (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+ (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+ (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+ (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
diff --git a/drivers/net/bna/bna.h b/drivers/net/bna/bna.h
index df6676bbc84e..a287f89b0289 100644
--- a/drivers/net/bna/bna.h
+++ b/drivers/net/bna/bna.h
@@ -32,8 +32,6 @@ extern const u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
/* Log string size */
#define BNA_MESSAGE_SIZE 256
-#define bna_device_timer(_dev) bfa_timer_beat(&((_dev)->timer_mod))
-
/* MBOX API for PORT, TX, RX */
#define bna_mbox_qe_fill(_qe, _cmd, _cmd_len, _cbfn, _cbarg) \
do { \
@@ -390,8 +388,8 @@ void bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe);
/* API for RX */
int bna_port_mtu_get(struct bna_port *port);
-void bna_llport_admin_up(struct bna_llport *llport);
-void bna_llport_admin_down(struct bna_llport *llport);
+void bna_llport_rx_started(struct bna_llport *llport);
+void bna_llport_rx_stopped(struct bna_llport *llport);
/* API for BNAD */
void bna_port_enable(struct bna_port *port);
diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c
index 07b26598546e..e1527472b961 100644
--- a/drivers/net/bna/bna_ctrl.c
+++ b/drivers/net/bna/bna_ctrl.c
@@ -59,14 +59,70 @@ bna_port_cb_link_down(struct bna_port *port, int status)
port->link_cbfn(port->bna->bnad, BNA_LINK_DOWN);
}
+static inline int
+llport_can_be_up(struct bna_llport *llport)
+{
+ int ready = 0;
+ if (llport->type == BNA_PORT_T_REGULAR)
+ ready = ((llport->flags & BNA_LLPORT_F_ADMIN_UP) &&
+ (llport->flags & BNA_LLPORT_F_RX_STARTED) &&
+ (llport->flags & BNA_LLPORT_F_PORT_ENABLED));
+ else
+ ready = ((llport->flags & BNA_LLPORT_F_ADMIN_UP) &&
+ (llport->flags & BNA_LLPORT_F_RX_STARTED) &&
+ !(llport->flags & BNA_LLPORT_F_PORT_ENABLED));
+ return ready;
+}
+
+#define llport_is_up llport_can_be_up
+
+enum bna_llport_event {
+ LLPORT_E_START = 1,
+ LLPORT_E_STOP = 2,
+ LLPORT_E_FAIL = 3,
+ LLPORT_E_UP = 4,
+ LLPORT_E_DOWN = 5,
+ LLPORT_E_FWRESP_UP_OK = 6,
+ LLPORT_E_FWRESP_UP_FAIL = 7,
+ LLPORT_E_FWRESP_DOWN = 8
+};
+
+static void
+bna_llport_cb_port_enabled(struct bna_llport *llport)
+{
+ llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
+
+ if (llport_can_be_up(llport))
+ bfa_fsm_send_event(llport, LLPORT_E_UP);
+}
+
+static void
+bna_llport_cb_port_disabled(struct bna_llport *llport)
+{
+ int llport_up = llport_is_up(llport);
+
+ llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
+
+ if (llport_up)
+ bfa_fsm_send_event(llport, LLPORT_E_DOWN);
+}
+
/**
* MBOX
*/
static int
bna_is_aen(u8 msg_id)
{
- return msg_id == BFI_LL_I2H_LINK_DOWN_AEN ||
- msg_id == BFI_LL_I2H_LINK_UP_AEN;
+ switch (msg_id) {
+ case BFI_LL_I2H_LINK_DOWN_AEN:
+ case BFI_LL_I2H_LINK_UP_AEN:
+ case BFI_LL_I2H_PORT_ENABLE_AEN:
+ case BFI_LL_I2H_PORT_DISABLE_AEN:
+ return 1;
+
+ default:
+ return 0;
+ }
}
static void
@@ -81,6 +137,12 @@ bna_mbox_aen_callback(struct bna *bna, struct bfi_mbmsg *msg)
case BFI_LL_I2H_LINK_DOWN_AEN:
bna_port_cb_link_down(&bna->port, aen->reason);
break;
+ case BFI_LL_I2H_PORT_ENABLE_AEN:
+ bna_llport_cb_port_enabled(&bna->port.llport);
+ break;
+ case BFI_LL_I2H_PORT_DISABLE_AEN:
+ bna_llport_cb_port_disabled(&bna->port.llport);
+ break;
default:
break;
}
@@ -251,16 +313,6 @@ static void bna_llport_start(struct bna_llport *llport);
static void bna_llport_stop(struct bna_llport *llport);
static void bna_llport_fail(struct bna_llport *llport);
-enum bna_llport_event {
- LLPORT_E_START = 1,
- LLPORT_E_STOP = 2,
- LLPORT_E_FAIL = 3,
- LLPORT_E_UP = 4,
- LLPORT_E_DOWN = 5,
- LLPORT_E_FWRESP_UP = 6,
- LLPORT_E_FWRESP_DOWN = 7
-};
-
enum bna_llport_state {
BNA_LLPORT_STOPPED = 1,
BNA_LLPORT_DOWN = 2,
@@ -320,7 +372,7 @@ bna_llport_sm_stopped(struct bna_llport *llport,
/* No-op */
break;
- case LLPORT_E_FWRESP_UP:
+ case LLPORT_E_FWRESP_UP_OK:
case LLPORT_E_FWRESP_DOWN:
/**
* These events are received due to flushing of mbox when
@@ -366,6 +418,7 @@ bna_llport_sm_down(struct bna_llport *llport,
static void
bna_llport_sm_up_resp_wait_entry(struct bna_llport *llport)
{
+ BUG_ON(!llport_can_be_up(llport));
/**
* NOTE: Do not call bna_fw_llport_up() here. That will over step
* mbox due to down_resp_wait -> up_resp_wait transition on event
@@ -390,10 +443,14 @@ bna_llport_sm_up_resp_wait(struct bna_llport *llport,
bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
break;
- case LLPORT_E_FWRESP_UP:
+ case LLPORT_E_FWRESP_UP_OK:
bfa_fsm_set_state(llport, bna_llport_sm_up);
break;
+ case LLPORT_E_FWRESP_UP_FAIL:
+ bfa_fsm_set_state(llport, bna_llport_sm_down);
+ break;
+
case LLPORT_E_FWRESP_DOWN:
/* down_resp_wait -> up_resp_wait transition on LLPORT_E_UP */
bna_fw_llport_up(llport);
@@ -431,11 +488,12 @@ bna_llport_sm_down_resp_wait(struct bna_llport *llport,
bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
break;
- case LLPORT_E_FWRESP_UP:
+ case LLPORT_E_FWRESP_UP_OK:
/* up_resp_wait->down_resp_wait transition on LLPORT_E_DOWN */
bna_fw_llport_down(llport);
break;
+ case LLPORT_E_FWRESP_UP_FAIL:
case LLPORT_E_FWRESP_DOWN:
bfa_fsm_set_state(llport, bna_llport_sm_down);
break;
@@ -496,11 +554,12 @@ bna_llport_sm_last_resp_wait(struct bna_llport *llport,
/* No-op */
break;
- case LLPORT_E_FWRESP_UP:
+ case LLPORT_E_FWRESP_UP_OK:
/* up_resp_wait->last_resp_wait transition on LLPORT_T_STOP */
bna_fw_llport_down(llport);
break;
+ case LLPORT_E_FWRESP_UP_FAIL:
case LLPORT_E_FWRESP_DOWN:
bfa_fsm_set_state(llport, bna_llport_sm_stopped);
break;
@@ -541,7 +600,14 @@ bna_fw_cb_llport_up(void *arg, int status)
struct bna_llport *llport = (struct bna_llport *)arg;
bfa_q_qe_init(&llport->mbox_qe.qe);
- bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP);
+ if (status == BFI_LL_CMD_FAIL) {
+ if (llport->type == BNA_PORT_T_REGULAR)
+ llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
+ else
+ llport->flags &= ~BNA_LLPORT_F_ADMIN_UP;
+ bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP_FAIL);
+ } else
+ bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP_OK);
}
static void
@@ -588,13 +654,14 @@ bna_port_cb_llport_stopped(struct bna_port *port,
static void
bna_llport_init(struct bna_llport *llport, struct bna *bna)
{
- llport->flags |= BNA_LLPORT_F_ENABLED;
+ llport->flags |= BNA_LLPORT_F_ADMIN_UP;
+ llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
llport->type = BNA_PORT_T_REGULAR;
llport->bna = bna;
llport->link_status = BNA_LINK_DOWN;
- llport->admin_up_count = 0;
+ llport->rx_started_count = 0;
llport->stop_cbfn = NULL;
@@ -606,7 +673,8 @@ bna_llport_init(struct bna_llport *llport, struct bna *bna)
static void
bna_llport_uninit(struct bna_llport *llport)
{
- llport->flags &= ~BNA_LLPORT_F_ENABLED;
+ llport->flags &= ~BNA_LLPORT_F_ADMIN_UP;
+ llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
llport->bna = NULL;
}
@@ -628,6 +696,8 @@ bna_llport_stop(struct bna_llport *llport)
static void
bna_llport_fail(struct bna_llport *llport)
{
+ /* Reset the physical port status to enabled */
+ llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
bfa_fsm_send_event(llport, LLPORT_E_FAIL);
}
@@ -638,25 +708,31 @@ bna_llport_state_get(struct bna_llport *llport)
}
void
-bna_llport_admin_up(struct bna_llport *llport)
+bna_llport_rx_started(struct bna_llport *llport)
{
- llport->admin_up_count++;
+ llport->rx_started_count++;
- if (llport->admin_up_count == 1) {
- llport->flags |= BNA_LLPORT_F_RX_ENABLED;
- if (llport->flags & BNA_LLPORT_F_ENABLED)
+ if (llport->rx_started_count == 1) {
+
+ llport->flags |= BNA_LLPORT_F_RX_STARTED;
+
+ if (llport_can_be_up(llport))
bfa_fsm_send_event(llport, LLPORT_E_UP);
}
}
void
-bna_llport_admin_down(struct bna_llport *llport)
+bna_llport_rx_stopped(struct bna_llport *llport)
{
- llport->admin_up_count--;
+ int llport_up = llport_is_up(llport);
+
+ llport->rx_started_count--;
- if (llport->admin_up_count == 0) {
- llport->flags &= ~BNA_LLPORT_F_RX_ENABLED;
- if (llport->flags & BNA_LLPORT_F_ENABLED)
+ if (llport->rx_started_count == 0) {
+
+ llport->flags &= ~BNA_LLPORT_F_RX_STARTED;
+
+ if (llport_up)
bfa_fsm_send_event(llport, LLPORT_E_DOWN);
}
}
@@ -2056,37 +2132,6 @@ rxf_fltr_mbox_cmd(struct bna_rxf *rxf, u8 cmd, enum bna_status status)
bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
}
-static void
-__rxf_default_function_config(struct bna_rxf *rxf, enum bna_status status)
-{
- struct bna_rx_fndb_ram *rx_fndb_ram;
- u32 ctrl_flags;
- int i;
-
- rx_fndb_ram = (struct bna_rx_fndb_ram *)
- BNA_GET_MEM_BASE_ADDR(rxf->rx->bna->pcidev.pci_bar_kva,
- RX_FNDB_RAM_BASE_OFFSET);
-
- for (i = 0; i < BFI_MAX_RXF; i++) {
- if (status == BNA_STATUS_T_ENABLED) {
- if (i == rxf->rxf_id)
- continue;
-
- ctrl_flags =
- readl(&rx_fndb_ram[i].control_flags);
- ctrl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
- writel(ctrl_flags,
- &rx_fndb_ram[i].control_flags);
- } else {
- ctrl_flags =
- readl(&rx_fndb_ram[i].control_flags);
- ctrl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
- writel(ctrl_flags,
- &rx_fndb_ram[i].control_flags);
- }
- }
-}
-
int
rxf_process_packet_filter_ucast(struct bna_rxf *rxf)
{
@@ -2153,46 +2198,6 @@ rxf_process_packet_filter_promisc(struct bna_rxf *rxf)
}
int
-rxf_process_packet_filter_default(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* Enable/disable default mode */
- if (is_default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move default configuration from pending -> active */
- default_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active |= BNA_RXMODE_DEFAULT;
-
- /* Disable VLAN filter to allow all VLANs */
- __rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
- /* Redirect all other RxF vlan filtering to this one */
- __rxf_default_function_config(rxf, BNA_STATUS_T_ENABLED);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
- BNA_STATUS_T_ENABLED);
- return 1;
- } else if (is_default_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move default configuration from pending -> active */
- default_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
- bna->rxf_default_id = BFI_MAX_RXF;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- /* Stop RxF vlan filter table redirection */
- __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-int
rxf_process_packet_filter_allmulti(struct bna_rxf *rxf)
{
/* Enable/disable allmulti mode */
@@ -2289,48 +2294,6 @@ rxf_clear_packet_filter_promisc(struct bna_rxf *rxf)
}
int
-rxf_clear_packet_filter_default(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* 8. Execute pending default mode disable command */
- if (is_default_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move default configuration from pending -> active */
- default_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
- bna->rxf_default_id = BFI_MAX_RXF;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- /* Stop RxF vlan filter table redirection */
- __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- /* 9. Clear active default mode; move it to pending enable */
- if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
- /* move default configuration from active -> pending */
- default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- /* Stop RxF vlan filter table redirection */
- __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-int
rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf)
{
/* 10. Execute pending allmulti mode disable command */
@@ -2405,28 +2368,6 @@ rxf_reset_packet_filter_promisc(struct bna_rxf *rxf)
}
void
-rxf_reset_packet_filter_default(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* 8. Clear pending default mode disable */
- if (is_default_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- default_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
- bna->rxf_default_id = BFI_MAX_RXF;
- }
-
- /* 9. Move default mode config from active -> pending */
- if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
- default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
- }
-}
-
-void
rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf)
{
/* 10. Clear pending allmulti mode disable */
@@ -2523,76 +2464,6 @@ rxf_promisc_disable(struct bna_rxf *rxf)
* 1 = need h/w change
*/
static int
-rxf_default_enable(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- int ret = 0;
-
- /* There can not be any pending disable command */
-
- /* Do nothing if pending enable or already enabled */
- if (is_default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask) ||
- (rxf->rxmode_active & BNA_RXMODE_DEFAULT)) {
- /* Schedule enable */
- } else {
- /* Default mode should not be active in the system */
- default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- bna->rxf_default_id = rxf->rxf_id;
- ret = 1;
- }
-
- return ret;
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
-rxf_default_disable(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- int ret = 0;
-
- /* There can not be any pending disable */
-
- /* Turn off pending enable command , if any */
- if (is_default_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* Promisc mode should not be active */
- /* system default state should be pending */
- default_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- /* Remove the default state from the system */
- bna->rxf_default_id = BFI_MAX_RXF;
-
- /* Schedule disable */
- } else if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
- /* Default mode should be active in the system */
- default_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- ret = 1;
-
- /* Do nothing if already disabled */
- } else {
- }
-
- return ret;
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
rxf_allmulti_enable(struct bna_rxf *rxf)
{
int ret = 0;
@@ -2654,38 +2525,13 @@ bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
struct bna_rxf *rxf = &rx->rxf;
int need_hw_config = 0;
- /* Error checks */
+ /* Process the commands */
if (is_promisc_enable(new_mode, bitmask)) {
/* If promisc mode is already enabled elsewhere in the system */
if ((rx->bna->rxf_promisc_id != BFI_MAX_RXF) &&
(rx->bna->rxf_promisc_id != rxf->rxf_id))
goto err_return;
-
- /* If default mode is already enabled in the system */
- if (rx->bna->rxf_default_id != BFI_MAX_RXF)
- goto err_return;
-
- /* Trying to enable promiscuous and default mode together */
- if (is_default_enable(new_mode, bitmask))
- goto err_return;
- }
-
- if (is_default_enable(new_mode, bitmask)) {
- /* If default mode is already enabled elsewhere in the system */
- if ((rx->bna->rxf_default_id != BFI_MAX_RXF) &&
- (rx->bna->rxf_default_id != rxf->rxf_id)) {
- goto err_return;
- }
-
- /* If promiscuous mode is already enabled in the system */
- if (rx->bna->rxf_promisc_id != BFI_MAX_RXF)
- goto err_return;
- }
-
- /* Process the commands */
-
- if (is_promisc_enable(new_mode, bitmask)) {
if (rxf_promisc_enable(rxf))
need_hw_config = 1;
} else if (is_promisc_disable(new_mode, bitmask)) {
@@ -2693,14 +2539,6 @@ bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
need_hw_config = 1;
}
- if (is_default_enable(new_mode, bitmask)) {
- if (rxf_default_enable(rxf))
- need_hw_config = 1;
- } else if (is_default_disable(new_mode, bitmask)) {
- if (rxf_default_disable(rxf))
- need_hw_config = 1;
- }
-
if (is_allmulti_enable(new_mode, bitmask)) {
if (rxf_allmulti_enable(rxf))
need_hw_config = 1;
@@ -3126,7 +2964,6 @@ bna_init(struct bna *bna, struct bnad *bnad, struct bfa_pcidev *pcidev,
bna_mcam_mod_init(&bna->mcam_mod, bna, res_info);
- bna->rxf_default_id = BFI_MAX_RXF;
bna->rxf_promisc_id = BFI_MAX_RXF;
/* Mbox q element for posting stat request to f/w */
diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c
index ad93fdb0f427..58c7664040dc 100644
--- a/drivers/net/bna/bna_txrx.c
+++ b/drivers/net/bna/bna_txrx.c
@@ -1226,8 +1226,7 @@ rxf_process_packet_filter_vlan(struct bna_rxf *rxf)
/* Apply the VLAN filter */
if (rxf->rxf_flags & BNA_RXF_FL_VLAN_CONFIG_PENDING) {
rxf->rxf_flags &= ~BNA_RXF_FL_VLAN_CONFIG_PENDING;
- if (!(rxf->rxmode_active & BNA_RXMODE_PROMISC) &&
- !(rxf->rxmode_active & BNA_RXMODE_DEFAULT))
+ if (!(rxf->rxmode_active & BNA_RXMODE_PROMISC))
__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
}
@@ -1276,9 +1275,6 @@ rxf_process_packet_filter(struct bna_rxf *rxf)
if (rxf_process_packet_filter_promisc(rxf))
return 1;
- if (rxf_process_packet_filter_default(rxf))
- return 1;
-
if (rxf_process_packet_filter_allmulti(rxf))
return 1;
@@ -1340,9 +1336,6 @@ rxf_clear_packet_filter(struct bna_rxf *rxf)
if (rxf_clear_packet_filter_promisc(rxf))
return 1;
- if (rxf_clear_packet_filter_default(rxf))
- return 1;
-
if (rxf_clear_packet_filter_allmulti(rxf))
return 1;
@@ -1389,8 +1382,6 @@ rxf_reset_packet_filter(struct bna_rxf *rxf)
rxf_reset_packet_filter_promisc(rxf);
- rxf_reset_packet_filter_default(rxf);
-
rxf_reset_packet_filter_allmulti(rxf);
}
@@ -1441,12 +1432,16 @@ bna_rxf_init(struct bna_rxf *rxf,
memset(rxf->vlan_filter_table, 0,
(sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32)));
+ /* Set up VLAN 0 for pure priority tagged packets */
+ rxf->vlan_filter_table[0] |= 1;
+
bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
}
static void
bna_rxf_uninit(struct bna_rxf *rxf)
{
+ struct bna *bna = rxf->rx->bna;
struct bna_mac *mac;
bna_rit_mod_seg_put(&rxf->rx->bna->rit_mod, rxf->rit_segment);
@@ -1473,6 +1468,27 @@ bna_rxf_uninit(struct bna_rxf *rxf)
bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
}
+ /* Turn off pending promisc mode */
+ if (is_promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* system promisc state should be pending */
+ BUG_ON(!(bna->rxf_promisc_id == rxf->rxf_id));
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ bna->rxf_promisc_id = BFI_MAX_RXF;
+ }
+ /* Promisc mode should not be active */
+ BUG_ON(rxf->rxmode_active & BNA_RXMODE_PROMISC);
+
+ /* Turn off pending all-multi mode */
+ if (is_allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ }
+ /* Allmulti mode should not be active */
+ BUG_ON(rxf->rxmode_active & BNA_RXMODE_ALLMULTI);
+
rxf->rx = NULL;
}
@@ -1947,7 +1963,7 @@ bna_rx_sm_started_entry(struct bna_rx *rx)
bna_ib_ack(&rxp->cq.ib->door_bell, 0);
}
- bna_llport_admin_up(&rx->bna->port.llport);
+ bna_llport_rx_started(&rx->bna->port.llport);
}
void
@@ -1955,13 +1971,13 @@ bna_rx_sm_started(struct bna_rx *rx, enum bna_rx_event event)
{
switch (event) {
case RX_E_FAIL:
- bna_llport_admin_down(&rx->bna->port.llport);
+ bna_llport_rx_stopped(&rx->bna->port.llport);
bfa_fsm_set_state(rx, bna_rx_sm_stopped);
rx_ib_fail(rx);
bna_rxf_fail(&rx->rxf);
break;
case RX_E_STOP:
- bna_llport_admin_down(&rx->bna->port.llport);
+ bna_llport_rx_stopped(&rx->bna->port.llport);
bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
break;
default:
@@ -3373,7 +3389,7 @@ __bna_txq_start(struct bna_tx *tx, struct bna_txq *txq)
txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
txq_cfg.nxt_qid_n_fid_n_pri = (((tx->txf.txf_id & 0x3f) << 3) |
- (txq->priority & 0x3));
+ (txq->priority & 0x7));
txq_cfg.wvc_n_cquota_n_rquota =
((((u32)BFI_TX_MAX_WRR_QUOTA & 0xfff) << 12) |
(BFI_TX_MAX_WRR_QUOTA & 0xfff));
diff --git a/drivers/net/bna/bna_types.h b/drivers/net/bna/bna_types.h
index 6877310f6ef4..b9c134f7ad31 100644
--- a/drivers/net/bna/bna_types.h
+++ b/drivers/net/bna/bna_types.h
@@ -165,8 +165,7 @@ enum bna_rxp_type {
enum bna_rxmode {
BNA_RXMODE_PROMISC = 1,
- BNA_RXMODE_DEFAULT = 2,
- BNA_RXMODE_ALLMULTI = 4
+ BNA_RXMODE_ALLMULTI = 2
};
enum bna_rx_event {
@@ -249,8 +248,9 @@ enum bna_link_status {
};
enum bna_llport_flags {
- BNA_LLPORT_F_ENABLED = 1,
- BNA_LLPORT_F_RX_ENABLED = 2
+ BNA_LLPORT_F_ADMIN_UP = 1,
+ BNA_LLPORT_F_PORT_ENABLED = 2,
+ BNA_LLPORT_F_RX_STARTED = 4
};
enum bna_port_flags {
@@ -405,7 +405,7 @@ struct bna_llport {
enum bna_link_status link_status;
- int admin_up_count;
+ int rx_started_count;
void (*stop_cbfn)(struct bna_port *, enum bna_cb_status);
@@ -1117,7 +1117,6 @@ struct bna {
struct bna_rit_mod rit_mod;
- int rxf_default_id;
int rxf_promisc_id;
struct bna_mbox_qe mbox_qe;
diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c
index 7e839b9cec22..fad912656fe4 100644
--- a/drivers/net/bna/bnad.c
+++ b/drivers/net/bna/bnad.c
@@ -70,6 +70,8 @@ do { \
(sizeof(struct bnad_skb_unmap) * ((_depth) - 1)); \
} while (0)
+#define BNAD_TXRX_SYNC_MDELAY 250 /* 250 msecs */
+
/*
* Reinitialize completions in CQ, once Rx is taken down
*/
@@ -107,7 +109,7 @@ static void
bnad_free_all_txbufs(struct bnad *bnad,
struct bna_tcb *tcb)
{
- u16 unmap_cons;
+ u32 unmap_cons;
struct bnad_unmap_q *unmap_q = tcb->unmap_q;
struct bnad_skb_unmap *unmap_array;
struct sk_buff *skb = NULL;
@@ -130,7 +132,9 @@ bnad_free_all_txbufs(struct bnad *bnad,
PCI_DMA_TODEVICE);
pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
- unmap_cons++;
+ if (++unmap_cons >= unmap_q->q_depth)
+ break;
+
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
pci_unmap_page(bnad->pcidev,
pci_unmap_addr(&unmap_array[unmap_cons],
@@ -139,7 +143,8 @@ bnad_free_all_txbufs(struct bnad *bnad,
PCI_DMA_TODEVICE);
pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
0);
- unmap_cons++;
+ if (++unmap_cons >= unmap_q->q_depth)
+ break;
}
dev_kfree_skb_any(skb);
}
@@ -167,11 +172,11 @@ bnad_free_txbufs(struct bnad *bnad,
/*
* Just return if TX is stopped. This check is useful
* when bnad_free_txbufs() runs out of a tasklet scheduled
- * before bnad_cb_tx_cleanup() cleared BNAD_RF_TX_STARTED bit
+ * before bnad_cb_tx_cleanup() cleared BNAD_TXQ_TX_STARTED bit
* but this routine runs actually after the cleanup has been
* executed.
*/
- if (!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+ if (!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
return 0;
updated_hw_cons = *(tcb->hw_consumer_index);
@@ -239,7 +244,7 @@ bnad_tx_free_tasklet(unsigned long bnad_ptr)
{
struct bnad *bnad = (struct bnad *)bnad_ptr;
struct bna_tcb *tcb;
- u32 acked;
+ u32 acked = 0;
int i, j;
for (i = 0; i < bnad->num_tx; i++) {
@@ -252,10 +257,26 @@ bnad_tx_free_tasklet(unsigned long bnad_ptr)
(!test_and_set_bit(BNAD_TXQ_FREE_SENT,
&tcb->flags))) {
acked = bnad_free_txbufs(bnad, tcb);
- bna_ib_ack(tcb->i_dbell, acked);
+ if (likely(test_bit(BNAD_TXQ_TX_STARTED,
+ &tcb->flags)))
+ bna_ib_ack(tcb->i_dbell, acked);
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
}
+ if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED,
+ &tcb->flags)))
+ continue;
+ if (netif_queue_stopped(bnad->netdev)) {
+ if (acked && netif_carrier_ok(bnad->netdev) &&
+ BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
+ BNAD_NETIF_WAKE_THRESHOLD) {
+ netif_wake_queue(bnad->netdev);
+ /* TODO */
+ /* Counters for individual TxQs? */
+ BNAD_UPDATE_CTR(bnad,
+ netif_queue_wakeup);
+ }
+ }
}
}
}
@@ -264,7 +285,7 @@ static u32
bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
{
struct net_device *netdev = bnad->netdev;
- u32 sent;
+ u32 sent = 0;
if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
return 0;
@@ -275,12 +296,15 @@ bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
netif_carrier_ok(netdev) &&
BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
BNAD_NETIF_WAKE_THRESHOLD) {
- netif_wake_queue(netdev);
- BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) {
+ netif_wake_queue(netdev);
+ BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ }
}
+ }
+
+ if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
bna_ib_ack(tcb->i_dbell, sent);
- } else
- bna_ib_ack(tcb->i_dbell, 0);
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
@@ -313,25 +337,24 @@ bnad_reset_rcb(struct bnad *bnad, struct bna_rcb *rcb)
}
static void
-bnad_free_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+bnad_free_all_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
{
struct bnad_unmap_q *unmap_q;
struct sk_buff *skb;
+ int unmap_cons;
unmap_q = rcb->unmap_q;
- while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
- skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
- BUG_ON(!(skb));
- unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+ for (unmap_cons = 0; unmap_cons < unmap_q->q_depth; unmap_cons++) {
+ skb = unmap_q->unmap_array[unmap_cons].skb;
+ if (!skb)
+ continue;
+ unmap_q->unmap_array[unmap_cons].skb = NULL;
pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q->
- unmap_array[unmap_q->consumer_index],
- dma_addr), rcb->rxq->buffer_size +
- NET_IP_ALIGN, PCI_DMA_FROMDEVICE);
+ unmap_array[unmap_cons],
+ dma_addr), rcb->rxq->buffer_size,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
- BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
- BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
}
-
bnad_reset_rcb(bnad, rcb);
}
@@ -385,43 +408,11 @@ finishing:
unmap_q->producer_index = unmap_prod;
rcb->producer_index = unmap_prod;
smp_mb();
- bna_rxq_prod_indx_doorbell(rcb);
+ if (likely(test_bit(BNAD_RXQ_STARTED, &rcb->flags)))
+ bna_rxq_prod_indx_doorbell(rcb);
}
}
-/*
- * Locking is required in the enable path
- * because it is called from a napi poll
- * context, where the bna_lock is not held
- * unlike the IRQ context.
- */
-static void
-bnad_enable_txrx_irqs(struct bnad *bnad)
-{
- struct bna_tcb *tcb;
- struct bna_ccb *ccb;
- int i, j;
- unsigned long flags;
-
- spin_lock_irqsave(&bnad->bna_lock, flags);
- for (i = 0; i < bnad->num_tx; i++) {
- for (j = 0; j < bnad->num_txq_per_tx; j++) {
- tcb = bnad->tx_info[i].tcb[j];
- bna_ib_coalescing_timer_set(tcb->i_dbell,
- tcb->txq->ib->ib_config.coalescing_timeo);
- bna_ib_ack(tcb->i_dbell, 0);
- }
- }
-
- for (i = 0; i < bnad->num_rx; i++) {
- for (j = 0; j < bnad->num_rxp_per_rx; j++) {
- ccb = bnad->rx_info[i].rx_ctrl[j].ccb;
- bnad_enable_rx_irq_unsafe(ccb);
- }
- }
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
-}
-
static inline void
bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
{
@@ -448,6 +439,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
+ if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))
+ return 0;
+
prefetch(bnad->netdev);
BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
wi_range);
@@ -544,12 +538,15 @@ next:
BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
if (likely(ccb)) {
- bna_ib_ack(ccb->i_dbell, packets);
+ if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
+ bna_ib_ack(ccb->i_dbell, packets);
bnad_refill_rxq(bnad, ccb->rcb[0]);
if (ccb->rcb[1])
bnad_refill_rxq(bnad, ccb->rcb[1]);
- } else
- bna_ib_ack(ccb->i_dbell, 0);
+ } else {
+ if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
+ bna_ib_ack(ccb->i_dbell, 0);
+ }
return packets;
}
@@ -557,6 +554,9 @@ next:
static void
bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
{
+ if (unlikely(!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
+ return;
+
bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
bna_ib_ack(ccb->i_dbell, 0);
}
@@ -566,7 +566,8 @@ bnad_enable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
{
unsigned long flags;
- spin_lock_irqsave(&bnad->bna_lock, flags); /* Because of polling context */
+ /* Because of polling context */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
bnad_enable_rx_irq_unsafe(ccb);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -575,9 +576,11 @@ static void
bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
{
struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
- if (likely(napi_schedule_prep((&rx_ctrl->napi)))) {
+ struct napi_struct *napi = &rx_ctrl->napi;
+
+ if (likely(napi_schedule_prep(napi))) {
bnad_disable_rx_irq(bnad, ccb);
- __napi_schedule((&rx_ctrl->napi));
+ __napi_schedule(napi);
}
BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
}
@@ -602,12 +605,11 @@ bnad_msix_mbox_handler(int irq, void *data)
{
u32 intr_status;
unsigned long flags;
- struct net_device *netdev = data;
- struct bnad *bnad;
+ struct bnad *bnad = (struct bnad *)data;
- bnad = netdev_priv(netdev);
+ if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags)))
+ return IRQ_HANDLED;
- /* BNA_ISR_GET(bnad); Inc Ref count */
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_intr_status_get(&bnad->bna, intr_status);
@@ -617,7 +619,6 @@ bnad_msix_mbox_handler(int irq, void *data)
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- /* BNAD_ISR_PUT(bnad); Dec Ref count */
return IRQ_HANDLED;
}
@@ -627,8 +628,7 @@ bnad_isr(int irq, void *data)
int i, j;
u32 intr_status;
unsigned long flags;
- struct net_device *netdev = data;
- struct bnad *bnad = netdev_priv(netdev);
+ struct bnad *bnad = (struct bnad *)data;
struct bnad_rx_info *rx_info;
struct bnad_rx_ctrl *rx_ctrl;
@@ -642,16 +642,21 @@ bnad_isr(int irq, void *data)
spin_lock_irqsave(&bnad->bna_lock, flags);
- if (BNA_IS_MBOX_ERR_INTR(intr_status)) {
+ if (BNA_IS_MBOX_ERR_INTR(intr_status))
bna_mbox_handler(&bnad->bna, intr_status);
- if (!BNA_IS_INTX_DATA_INTR(intr_status)) {
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
- goto done;
- }
- }
+
spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (!BNA_IS_INTX_DATA_INTR(intr_status))
+ return IRQ_HANDLED;
+
/* Process data interrupts */
+ /* Tx processing */
+ for (i = 0; i < bnad->num_tx; i++) {
+ for (j = 0; j < bnad->num_txq_per_tx; j++)
+ bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
+ }
+ /* Rx processing */
for (i = 0; i < bnad->num_rx; i++) {
rx_info = &bnad->rx_info[i];
if (!rx_info->rx)
@@ -663,7 +668,6 @@ bnad_isr(int irq, void *data)
rx_ctrl->ccb);
}
}
-done:
return IRQ_HANDLED;
}
@@ -674,11 +678,7 @@ done:
static void
bnad_enable_mbox_irq(struct bnad *bnad)
{
- int irq = BNAD_GET_MBOX_IRQ(bnad);
-
- if (test_and_clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
- if (bnad->cfg_flags & BNAD_CF_MSIX)
- enable_irq(irq);
+ clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);
BNAD_UPDATE_CTR(bnad, mbox_intr_enabled);
}
@@ -690,14 +690,19 @@ bnad_enable_mbox_irq(struct bnad *bnad)
static void
bnad_disable_mbox_irq(struct bnad *bnad)
{
- int irq = BNAD_GET_MBOX_IRQ(bnad);
+ set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);
+ BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+}
- if (!test_and_set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
- if (bnad->cfg_flags & BNAD_CF_MSIX)
- disable_irq_nosync(irq);
+static void
+bnad_set_netdev_perm_addr(struct bnad *bnad)
+{
+ struct net_device *netdev = bnad->netdev;
- BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+ memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
+ if (is_zero_ether_addr(netdev->dev_addr))
+ memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
}
/* Control Path Handlers */
@@ -755,11 +760,14 @@ bnad_cb_port_link_status(struct bnad *bnad,
if (link_up) {
if (!netif_carrier_ok(bnad->netdev)) {
+ struct bna_tcb *tcb = bnad->tx_info[0].tcb[0];
+ if (!tcb)
+ return;
pr_warn("bna: %s link up\n",
bnad->netdev->name);
netif_carrier_on(bnad->netdev);
BNAD_UPDATE_CTR(bnad, link_toggle);
- if (test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags)) {
+ if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) {
/* Force an immediate Transmit Schedule */
pr_info("bna: %s TX_STARTED\n",
bnad->netdev->name);
@@ -807,6 +815,18 @@ bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
{
struct bnad_tx_info *tx_info =
(struct bnad_tx_info *)tcb->txq->tx->priv;
+ struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+ while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+ cpu_relax();
+
+ bnad_free_all_txbufs(bnad, tcb);
+
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
tx_info->tcb[tcb->id] = NULL;
}
@@ -822,6 +842,12 @@ bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
}
static void
+bnad_cb_rcb_destroy(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ bnad_free_all_rxbufs(bnad, rcb);
+}
+
+static void
bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
{
struct bnad_rx_info *rx_info =
@@ -849,7 +875,7 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
if (tx_info != &bnad->tx_info[0])
return;
- clear_bit(BNAD_RF_TX_STARTED, &bnad->run_flags);
+ clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
netif_stop_queue(bnad->netdev);
pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name);
}
@@ -857,30 +883,15 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
static void
bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
{
- if (test_and_set_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
- return;
-
- if (netif_carrier_ok(bnad->netdev)) {
- pr_info("bna: %s TX_STARTED\n", bnad->netdev->name);
- netif_wake_queue(bnad->netdev);
- BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
- }
-}
-
-static void
-bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
-{
- struct bnad_unmap_q *unmap_q;
+ struct bnad_unmap_q *unmap_q = tcb->unmap_q;
- if (!tcb || (!tcb->unmap_q))
+ if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
return;
- unmap_q = tcb->unmap_q;
- if (!unmap_q->unmap_array)
- return;
+ clear_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags);
- if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
- return;
+ while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+ cpu_relax();
bnad_free_all_txbufs(bnad, tcb);
@@ -889,21 +900,45 @@ bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+
+ /*
+ * Workaround for first device enable failure & we
+ * get a 0 MAC address. We try to get the MAC address
+ * again here.
+ */
+ if (is_zero_ether_addr(&bnad->perm_addr.mac[0])) {
+ bna_port_mac_get(&bnad->bna.port, &bnad->perm_addr);
+ bnad_set_netdev_perm_addr(bnad);
+ }
+
+ set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
+
+ if (netif_carrier_ok(bnad->netdev)) {
+ pr_info("bna: %s TX_STARTED\n", bnad->netdev->name);
+ netif_wake_queue(bnad->netdev);
+ BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ }
+}
+
+static void
+bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ /* Delay only once for the whole Tx Path Shutdown */
+ if (!test_and_set_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags))
+ mdelay(BNAD_TXRX_SYNC_MDELAY);
}
static void
bnad_cb_rx_cleanup(struct bnad *bnad,
struct bna_ccb *ccb)
{
- bnad_cq_cmpl_init(bnad, ccb);
-
- bnad_free_rxbufs(bnad, ccb->rcb[0]);
clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
- if (ccb->rcb[1]) {
- bnad_free_rxbufs(bnad, ccb->rcb[1]);
+ if (ccb->rcb[1])
clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
- }
+
+ if (!test_and_set_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags))
+ mdelay(BNAD_TXRX_SYNC_MDELAY);
}
static void
@@ -911,6 +946,13 @@ bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
{
struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+ clear_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags);
+
+ if (rcb == rcb->cq->ccb->rcb[0])
+ bnad_cq_cmpl_init(bnad, rcb->cq->ccb);
+
+ bnad_free_all_rxbufs(bnad, rcb);
+
set_bit(BNAD_RXQ_STARTED, &rcb->flags);
/* Now allocate & post buffers for this RCB */
@@ -1047,7 +1089,7 @@ bnad_mbox_irq_free(struct bnad *bnad,
spin_unlock_irqrestore(&bnad->bna_lock, flags);
irq = BNAD_GET_MBOX_IRQ(bnad);
- free_irq(irq, bnad->netdev);
+ free_irq(irq, bnad);
kfree(intr_info->idl);
}
@@ -1061,7 +1103,7 @@ static int
bnad_mbox_irq_alloc(struct bnad *bnad,
struct bna_intr_info *intr_info)
{
- int err;
+ int err = 0;
unsigned long flags;
u32 irq;
irq_handler_t irq_handler;
@@ -1096,22 +1138,17 @@ bnad_mbox_irq_alloc(struct bnad *bnad,
*/
set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);
+ BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+
err = request_irq(irq, irq_handler, flags,
- bnad->mbox_irq_name, bnad->netdev);
+ bnad->mbox_irq_name, bnad);
if (err) {
kfree(intr_info->idl);
intr_info->idl = NULL;
- return err;
}
- spin_lock_irqsave(&bnad->bna_lock, flags);
-
- if (bnad->cfg_flags & BNAD_CF_MSIX)
- disable_irq_nosync(irq);
-
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
- return 0;
+ return err;
}
static void
@@ -1388,13 +1425,24 @@ bnad_ioc_hb_check(unsigned long data)
}
static void
-bnad_ioc_sem_timeout(unsigned long data)
+bnad_iocpf_timeout(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bfa_nw_iocpf_timeout((void *) &bnad->bna.device.ioc);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_iocpf_sem_timeout(unsigned long data)
{
struct bnad *bnad = (struct bnad *)data;
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_sem_timeout((void *) &bnad->bna.device.ioc);
+ bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.device.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1555,62 +1603,19 @@ poll_exit:
return rcvd;
}
-static int
-bnad_napi_poll_txrx(struct napi_struct *napi, int budget)
-{
- struct bnad_rx_ctrl *rx_ctrl =
- container_of(napi, struct bnad_rx_ctrl, napi);
- struct bna_ccb *ccb;
- struct bnad *bnad;
- int rcvd = 0;
- int i, j;
-
- ccb = rx_ctrl->ccb;
-
- bnad = ccb->bnad;
-
- if (!netif_carrier_ok(bnad->netdev))
- goto poll_exit;
-
- /* Handle Tx Completions, if any */
- for (i = 0; i < bnad->num_tx; i++) {
- for (j = 0; j < bnad->num_txq_per_tx; j++)
- bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
- }
-
- /* Handle Rx Completions */
- rcvd = bnad_poll_cq(bnad, ccb, budget);
- if (rcvd == budget)
- return rcvd;
-poll_exit:
- napi_complete((napi));
-
- BNAD_UPDATE_CTR(bnad, netif_rx_complete);
-
- bnad_enable_txrx_irqs(bnad);
- return rcvd;
-}
-
static void
bnad_napi_enable(struct bnad *bnad, u32 rx_id)
{
- int (*napi_poll) (struct napi_struct *, int);
struct bnad_rx_ctrl *rx_ctrl;
int i;
- unsigned long flags;
-
- spin_lock_irqsave(&bnad->bna_lock, flags);
- if (bnad->cfg_flags & BNAD_CF_MSIX)
- napi_poll = bnad_napi_poll_rx;
- else
- napi_poll = bnad_napi_poll_txrx;
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Initialize & enable NAPI */
for (i = 0; i < bnad->num_rxp_per_rx; i++) {
rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];
+
netif_napi_add(bnad->netdev, &rx_ctrl->napi,
- napi_poll, 64);
+ bnad_napi_poll_rx, 64);
+
napi_enable(&rx_ctrl->napi);
}
}
@@ -1825,6 +1830,7 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
/* Initialize the Rx event handlers */
rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
+ rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy;
rx_cbfn.rcb_destroy_cbfn = NULL;
rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
@@ -1968,6 +1974,27 @@ bnad_enable_default_bcast(struct bnad *bnad)
return 0;
}
+/* Called with bnad_conf_lock() held */
+static void
+bnad_restore_vlans(struct bnad *bnad, u32 rx_id)
+{
+ u16 vlan_id;
+ unsigned long flags;
+
+ if (!bnad->vlan_grp)
+ return;
+
+ BUG_ON(!(VLAN_N_VID == (BFI_MAX_VLAN + 1)));
+
+ for (vlan_id = 0; vlan_id < VLAN_N_VID; vlan_id++) {
+ if (!vlan_group_get_device(bnad->vlan_grp, vlan_id))
+ continue;
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_rx_vlan_add(bnad->rx_info[rx_id].rx, vlan_id);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ }
+}
+
/* Statistics utilities */
void
bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
@@ -2152,16 +2179,6 @@ bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
bnad->num_rxp_per_rx = 1;
}
-static void
-bnad_set_netdev_perm_addr(struct bnad *bnad)
-{
- struct net_device *netdev = bnad->netdev;
-
- memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
- if (is_zero_ether_addr(netdev->dev_addr))
- memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
-}
-
/* Enable / disable device */
static void
bnad_device_disable(struct bnad *bnad)
@@ -2353,6 +2370,9 @@ bnad_open(struct net_device *netdev)
/* Enable broadcast */
bnad_enable_default_bcast(bnad);
+ /* Restore VLANs, if any */
+ bnad_restore_vlans(bnad, 0);
+
/* Set the UCAST address */
spin_lock_irqsave(&bnad->bna_lock, flags);
bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
@@ -2433,21 +2453,21 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
+ tx_id = 0;
+
+ tx_info = &bnad->tx_info[tx_id];
+ tcb = tx_info->tcb[tx_id];
+ unmap_q = tcb->unmap_q;
+
/*
* Takes care of the Tx that is scheduled between clearing the flag
* and the netif_stop_queue() call.
*/
- if (unlikely(!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))) {
+ if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
- tx_id = 0;
-
- tx_info = &bnad->tx_info[tx_id];
- tcb = tx_info->tcb[tx_id];
- unmap_q = tcb->unmap_q;
-
vectors = 1 + skb_shinfo(skb)->nr_frags;
if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
dev_kfree_skb(skb);
@@ -2462,7 +2482,8 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
tcb->consumer_index &&
!test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
acked = bnad_free_txbufs(bnad, tcb);
- bna_ib_ack(tcb->i_dbell, acked);
+ if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
+ bna_ib_ack(tcb->i_dbell, acked);
smp_mb__before_clear_bit();
clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
} else {
@@ -2624,6 +2645,10 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
tcb->producer_index = txq_prod;
smp_mb();
+
+ if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
+ return NETDEV_TX_OK;
+
bna_txq_prod_indx_doorbell(tcb);
if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
@@ -3032,7 +3057,7 @@ static int __devinit
bnad_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pcidev_id)
{
- bool using_dac;
+ bool using_dac = false;
int err;
struct bnad *bnad;
struct bna *bna;
@@ -3066,7 +3091,7 @@ bnad_pci_probe(struct pci_dev *pdev,
/*
* PCI initialization
* Output : using_dac = 1 for 64 bit DMA
- * = 0 for 32 bit DMA
+ * = 0 for 32 bit DMA
*/
err = bnad_pci_init(bnad, pdev, &using_dac);
if (err)
@@ -3084,6 +3109,9 @@ bnad_pci_probe(struct pci_dev *pdev,
/* Initialize netdev structure, set up ethtool ops */
bnad_netdev_init(bnad, using_dac);
+ /* Set link to down state */
+ netif_carrier_off(netdev);
+
bnad_enable_msix(bnad);
/* Get resource requirement form bna */
@@ -3115,11 +3143,13 @@ bnad_pci_probe(struct pci_dev *pdev,
((unsigned long)bnad));
setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check,
((unsigned long)bnad));
- setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_ioc_sem_timeout,
+ setup_timer(&bnad->bna.device.ioc.iocpf_timer, bnad_iocpf_timeout,
+ ((unsigned long)bnad));
+ setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_iocpf_sem_timeout,
((unsigned long)bnad));
/* Now start the timer before calling IOC */
- mod_timer(&bnad->bna.device.ioc.ioc_timer,
+ mod_timer(&bnad->bna.device.ioc.iocpf_timer,
jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ));
/*
@@ -3137,11 +3167,6 @@ bnad_pci_probe(struct pci_dev *pdev,
mutex_unlock(&bnad->conf_mutex);
- /*
- * Make sure the link appears down to the stack
- */
- netif_carrier_off(netdev);
-
/* Finally, reguister with net_device layer */
err = register_netdev(netdev);
if (err) {
diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h
index ebc3a9078642..8b1d51557def 100644
--- a/drivers/net/bna/bnad.h
+++ b/drivers/net/bna/bnad.h
@@ -51,6 +51,7 @@
*/
struct bnad_rx_ctrl {
struct bna_ccb *ccb;
+ unsigned long flags;
struct napi_struct napi;
};
@@ -64,7 +65,7 @@ struct bnad_rx_ctrl {
#define BNAD_NAME "bna"
#define BNAD_NAME_LEN 64
-#define BNAD_VERSION "2.3.2.0"
+#define BNAD_VERSION "2.3.2.3"
#define BNAD_MAILBOX_MSIX_VECTORS 1
@@ -82,6 +83,7 @@ struct bnad_rx_ctrl {
/* Bit positions for tcb->flags */
#define BNAD_TXQ_FREE_SENT 0
+#define BNAD_TXQ_TX_STARTED 1
/* Bit positions for rcb->flags */
#define BNAD_RXQ_REFILL 0
@@ -124,6 +126,7 @@ struct bnad_completion {
struct bnad_drv_stats {
u64 netif_queue_stop;
u64 netif_queue_wakeup;
+ u64 netif_queue_stopped;
u64 tso4;
u64 tso6;
u64 tso_err;
@@ -199,12 +202,12 @@ struct bnad_unmap_q {
/* Set, tested & cleared using xxx_bit() functions */
/* Values indicated bit positions */
#define BNAD_RF_CEE_RUNNING 1
-#define BNAD_RF_HW_ERROR 2
-#define BNAD_RF_MBOX_IRQ_DISABLED 3
-#define BNAD_RF_TX_STARTED 4
-#define BNAD_RF_RX_STARTED 5
-#define BNAD_RF_DIM_TIMER_RUNNING 6
-#define BNAD_RF_STATS_TIMER_RUNNING 7
+#define BNAD_RF_MBOX_IRQ_DISABLED 2
+#define BNAD_RF_RX_STARTED 3
+#define BNAD_RF_DIM_TIMER_RUNNING 4
+#define BNAD_RF_STATS_TIMER_RUNNING 5
+#define BNAD_RF_TX_SHUTDOWN_DELAYED 6
+#define BNAD_RF_RX_SHUTDOWN_DELAYED 7
struct bnad {
struct net_device *netdev;
@@ -306,8 +309,10 @@ extern void bnad_cleanup_rx(struct bnad *bnad, uint rx_id);
extern void bnad_dim_timer_start(struct bnad *bnad);
/* Statistics */
-extern void bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
-extern void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
+extern void bnad_netdev_qstats_fill(struct bnad *bnad,
+ struct rtnl_link_stats64 *stats);
+extern void bnad_netdev_hwstats_fill(struct bnad *bnad,
+ struct rtnl_link_stats64 *stats);
/**
* MACROS
@@ -320,9 +325,11 @@ extern void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64
#define bnad_enable_rx_irq_unsafe(_ccb) \
{ \
- bna_ib_coalescing_timer_set((_ccb)->i_dbell, \
- (_ccb)->rx_coalescing_timeo); \
- bna_ib_ack((_ccb)->i_dbell, 0); \
+ if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))) {\
+ bna_ib_coalescing_timer_set((_ccb)->i_dbell, \
+ (_ccb)->rx_coalescing_timeo); \
+ bna_ib_ack((_ccb)->i_dbell, 0); \
+ } \
}
#define bnad_dim_timer_running(_bnad) \
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index 11fa2ea842c1..142d6047da27 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -68,6 +68,7 @@ static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
"netif_queue_stop",
"netif_queue_wakeup",
+ "netif_queue_stopped",
"tso4",
"tso6",
"tso_err",
@@ -274,7 +275,6 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
if (ioc_attr) {
- memset(ioc_attr, 0, sizeof(*ioc_attr));
spin_lock_irqsave(&bnad->bna_lock, flags);
bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -330,10 +330,6 @@ do { \
BNAD_GET_REG(PCIE_MISC_REG);
- BNAD_GET_REG(HOST_SEM0_REG);
- BNAD_GET_REG(HOST_SEM1_REG);
- BNAD_GET_REG(HOST_SEM2_REG);
- BNAD_GET_REG(HOST_SEM3_REG);
BNAD_GET_REG(HOST_SEM0_INFO_REG);
BNAD_GET_REG(HOST_SEM1_INFO_REG);
BNAD_GET_REG(HOST_SEM2_INFO_REG);
@@ -1184,6 +1180,9 @@ bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
bi = sizeof(*net_stats64) / sizeof(u64);
+ /* Get netif_queue_stopped from stack */
+ bnad->stats.drv_stats.netif_queue_stopped = netif_queue_stopped(netdev);
+
/* Fill driver stats into ethtool buffers */
stats64 = (u64 *)&bnad->stats.drv_stats;
for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 062600be073b..df99edf3464a 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -56,11 +56,11 @@
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
-#define DRV_MODULE_VERSION "2.0.18"
-#define DRV_MODULE_RELDATE "Oct 7, 2010"
-#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.0.15.fw"
+#define DRV_MODULE_VERSION "2.0.21"
+#define DRV_MODULE_RELDATE "Dec 23, 2010"
+#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.1.fw"
#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
-#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.0.17.fw"
+#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1.fw"
#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
@@ -766,13 +766,10 @@ bnx2_alloc_rx_mem(struct bnx2 *bp)
int j;
rxr->rx_buf_ring =
- vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
+ vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
if (rxr->rx_buf_ring == NULL)
return -ENOMEM;
- memset(rxr->rx_buf_ring, 0,
- SW_RXBD_RING_SIZE * bp->rx_max_ring);
-
for (j = 0; j < bp->rx_max_ring; j++) {
rxr->rx_desc_ring[j] =
dma_alloc_coherent(&bp->pdev->dev,
@@ -785,13 +782,11 @@ bnx2_alloc_rx_mem(struct bnx2 *bp)
}
if (bp->rx_pg_ring_size) {
- rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
+ rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
bp->rx_max_pg_ring);
if (rxr->rx_pg_ring == NULL)
return -ENOMEM;
- memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
- bp->rx_max_pg_ring);
}
for (j = 0; j < bp->rx_max_pg_ring; j++) {
@@ -4645,13 +4640,28 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
/* Wait for the current PCI transaction to complete before
* issuing a reset. */
- REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
- BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
- BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
- BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
- BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
- val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
- udelay(5);
+ if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
+ (CHIP_NUM(bp) == CHIP_NUM_5708)) {
+ REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
+ BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
+ BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
+ BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
+ BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
+ val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
+ udelay(5);
+ } else { /* 5709 */
+ val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
+ val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
+ REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
+ val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
+
+ for (i = 0; i < 100; i++) {
+ msleep(1);
+ val = REG_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
+ if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
+ break;
+ }
+ }
/* Wait for the firmware to tell us it is ok to issue a reset. */
bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
@@ -4673,7 +4683,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
- pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
+ REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
} else {
val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
@@ -6086,7 +6096,7 @@ bnx2_request_irq(struct bnx2 *bp)
}
static void
-bnx2_free_irq(struct bnx2 *bp)
+__bnx2_free_irq(struct bnx2 *bp)
{
struct bnx2_irq *irq;
int i;
@@ -6097,6 +6107,13 @@ bnx2_free_irq(struct bnx2 *bp)
free_irq(irq->vector, &bp->bnx2_napi[i]);
irq->requested = 0;
}
+}
+
+static void
+bnx2_free_irq(struct bnx2 *bp)
+{
+
+ __bnx2_free_irq(bp);
if (bp->flags & BNX2_FLAG_USING_MSI)
pci_disable_msi(bp->pdev);
else if (bp->flags & BNX2_FLAG_USING_MSIX)
@@ -6801,28 +6818,30 @@ bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
u32 *p = _p, i, offset;
u8 *orig_p = _p;
struct bnx2 *bp = netdev_priv(dev);
- u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
- 0x0800, 0x0880, 0x0c00, 0x0c10,
- 0x0c30, 0x0d08, 0x1000, 0x101c,
- 0x1040, 0x1048, 0x1080, 0x10a4,
- 0x1400, 0x1490, 0x1498, 0x14f0,
- 0x1500, 0x155c, 0x1580, 0x15dc,
- 0x1600, 0x1658, 0x1680, 0x16d8,
- 0x1800, 0x1820, 0x1840, 0x1854,
- 0x1880, 0x1894, 0x1900, 0x1984,
- 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
- 0x1c80, 0x1c94, 0x1d00, 0x1d84,
- 0x2000, 0x2030, 0x23c0, 0x2400,
- 0x2800, 0x2820, 0x2830, 0x2850,
- 0x2b40, 0x2c10, 0x2fc0, 0x3058,
- 0x3c00, 0x3c94, 0x4000, 0x4010,
- 0x4080, 0x4090, 0x43c0, 0x4458,
- 0x4c00, 0x4c18, 0x4c40, 0x4c54,
- 0x4fc0, 0x5010, 0x53c0, 0x5444,
- 0x5c00, 0x5c18, 0x5c80, 0x5c90,
- 0x5fc0, 0x6000, 0x6400, 0x6428,
- 0x6800, 0x6848, 0x684c, 0x6860,
- 0x6888, 0x6910, 0x8000 };
+ static const u32 reg_boundaries[] = {
+ 0x0000, 0x0098, 0x0400, 0x045c,
+ 0x0800, 0x0880, 0x0c00, 0x0c10,
+ 0x0c30, 0x0d08, 0x1000, 0x101c,
+ 0x1040, 0x1048, 0x1080, 0x10a4,
+ 0x1400, 0x1490, 0x1498, 0x14f0,
+ 0x1500, 0x155c, 0x1580, 0x15dc,
+ 0x1600, 0x1658, 0x1680, 0x16d8,
+ 0x1800, 0x1820, 0x1840, 0x1854,
+ 0x1880, 0x1894, 0x1900, 0x1984,
+ 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
+ 0x1c80, 0x1c94, 0x1d00, 0x1d84,
+ 0x2000, 0x2030, 0x23c0, 0x2400,
+ 0x2800, 0x2820, 0x2830, 0x2850,
+ 0x2b40, 0x2c10, 0x2fc0, 0x3058,
+ 0x3c00, 0x3c94, 0x4000, 0x4010,
+ 0x4080, 0x4090, 0x43c0, 0x4458,
+ 0x4c00, 0x4c18, 0x4c40, 0x4c54,
+ 0x4fc0, 0x5010, 0x53c0, 0x5444,
+ 0x5c00, 0x5c18, 0x5c80, 0x5c90,
+ 0x5fc0, 0x6000, 0x6400, 0x6428,
+ 0x6800, 0x6848, 0x684c, 0x6860,
+ 0x6888, 0x6910, 0x8000
+ };
regs->version = 0;
@@ -7080,6 +7099,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
bnx2_netif_stop(bp, true);
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+ __bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
}
@@ -7092,6 +7112,9 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
rc = bnx2_alloc_mem(bp);
if (!rc)
+ rc = bnx2_request_irq(bp);
+
+ if (!rc)
rc = bnx2_init_nic(bp, 0);
if (rc) {
@@ -7914,15 +7937,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
goto err_out_release;
}
+ bnx2_set_power_state(bp, PCI_D0);
+
/* Configure byte swap and enable write to the reg_window registers.
* Rely on CPU to do target byte swapping on big endian systems
* The chip's target access swapping will not swap all accesses
*/
- pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
- BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
- BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
-
- bnx2_set_power_state(bp, PCI_D0);
+ REG_WR(bp, BNX2_PCICFG_MISC_CONFIG,
+ BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
+ BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
@@ -8383,8 +8406,6 @@ bnx2_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2 *bp = netdev_priv(dev);
- flush_scheduled_work();
-
unregister_netdev(dev);
if (bp->mips_firmware)
@@ -8421,7 +8442,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
- flush_scheduled_work();
+ cancel_work_sync(&bp->reset_task);
bnx2_netif_stop(bp, true);
netif_device_detach(dev);
del_timer_sync(&bp->timer);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index bf4c3421067d..5488a2e82fe9 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -461,6 +461,8 @@ struct l2_fhdr {
#define BNX2_PCICFG_MAILBOX_QUEUE_ADDR 0x00000090
#define BNX2_PCICFG_MAILBOX_QUEUE_DATA 0x00000094
+#define BNX2_PCICFG_DEVICE_CONTROL 0x000000b4
+#define BNX2_PCICFG_DEVICE_STATUS_NO_PEND ((1L<<5)<<16)
/*
* pci_reg definition
diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/bnx2x/Makefile
index 084afce89ae9..bb83a2961273 100644
--- a/drivers/net/bnx2x/Makefile
+++ b/drivers/net/bnx2x/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_BNX2X) += bnx2x.o
-bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o
+bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index 9eea225decaf..a6cd335c9436 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -13,6 +13,8 @@
#ifndef BNX2X_H
#define BNX2X_H
+#include <linux/netdevice.h>
+#include <linux/types.h>
/* compilation time flags */
@@ -20,15 +22,17 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.60.00-3"
-#define DRV_MODULE_RELDATE "2010/10/19"
+#define DRV_MODULE_VERSION "1.62.00-3"
+#define DRV_MODULE_RELDATE "2010/12/21"
#define BNX2X_BC_VER 0x040200
#define BNX2X_MULTI_QUEUE
#define BNX2X_NEW_NAPI
-
+#if defined(CONFIG_DCB)
+#define BCM_DCB
+#endif
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
#include "../cnic_if.h"
@@ -48,6 +52,7 @@
#include "bnx2x_fw_defs.h"
#include "bnx2x_hsi.h"
#include "bnx2x_link.h"
+#include "bnx2x_dcb.h"
#include "bnx2x_stats.h"
/* error/debug prints */
@@ -199,10 +204,25 @@ void bnx2x_panic_dump(struct bnx2x *bp);
/* EQ completions */
#define HC_SP_INDEX_EQ_CONS 7
+/* FCoE L2 connection completions */
+#define HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS 6
+#define HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS 4
/* iSCSI L2 */
#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5
#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1
+/* Special clients parameters */
+
+/* SB indices */
+/* FCoE L2 */
+#define BNX2X_FCOE_L2_RX_INDEX \
+ (&bp->def_status_blk->sp_sb.\
+ index_values[HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS])
+
+#define BNX2X_FCOE_L2_TX_INDEX \
+ (&bp->def_status_blk->sp_sb.\
+ index_values[HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS])
+
/**
* CIDs and CLIDs:
* CLIDs below is a CLID for func 0, then the CLID for other
@@ -215,12 +235,19 @@ void bnx2x_panic_dump(struct bnx2x *bp);
#define BNX2X_ISCSI_ETH_CL_ID 17
#define BNX2X_ISCSI_ETH_CID 17
+/* FCoE L2 */
+#define BNX2X_FCOE_ETH_CL_ID 18
+#define BNX2X_FCOE_ETH_CID 18
+
/** Additional rings budgeting */
#ifdef BCM_CNIC
#define CNIC_CONTEXT_USE 1
+#define FCOE_CONTEXT_USE 1
#else
#define CNIC_CONTEXT_USE 0
+#define FCOE_CONTEXT_USE 0
#endif /* BCM_CNIC */
+#define NONE_ETH_CONTEXT_USE (FCOE_CONTEXT_USE)
#define AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR \
AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR
@@ -401,6 +428,17 @@ struct bnx2x_fastpath {
};
#define bnx2x_fp(bp, nr, var) (bp->fp[nr].var)
+#ifdef BCM_CNIC
+/* FCoE L2 `fastpath' is right after the eth entries */
+#define FCOE_IDX BNX2X_NUM_ETH_QUEUES(bp)
+#define bnx2x_fcoe_fp(bp) (&bp->fp[FCOE_IDX])
+#define bnx2x_fcoe(bp, var) (bnx2x_fcoe_fp(bp)->var)
+#define IS_FCOE_FP(fp) (fp->index == FCOE_IDX)
+#define IS_FCOE_IDX(idx) ((idx) == FCOE_IDX)
+#else
+#define IS_FCOE_FP(fp) false
+#define IS_FCOE_IDX(idx) false
+#endif
/* MC hsi */
@@ -598,6 +636,7 @@ struct bnx2x_common {
#define CHIP_METAL(bp) (bp->common.chip_id & 0x00000ff0)
#define CHIP_BOND_ID(bp) (bp->common.chip_id & 0x0000000f)
+#define CHIP_PARITY_ENABLED(bp) (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
int flash_size;
#define NVRAM_1MB_SIZE 0x20000 /* 1M bit in bytes */
@@ -669,8 +708,14 @@ struct bnx2x_port {
enum {
CAM_ETH_LINE = 0,
CAM_ISCSI_ETH_LINE,
- CAM_MAX_PF_LINE = CAM_ISCSI_ETH_LINE
+ CAM_FIP_ETH_LINE,
+ CAM_FIP_MCAST_LINE,
+ CAM_MAX_PF_LINE = CAM_FIP_MCAST_LINE
};
+/* number of MACs per function in NIG memory - used for SI mode */
+#define NIG_LLH_FUNC_MEM_SIZE 16
+/* number of entries in NIG_REG_LLHX_FUNC_MEM */
+#define NIG_LLH_FUNC_MEM_MAX_OFFSET 8
#define BNX2X_VF_ID_INVALID 0xFF
@@ -710,6 +755,14 @@ enum {
*/
#define L2_FP_COUNT(cid_cnt) ((cid_cnt) - CNIC_CONTEXT_USE)
+/*
+ * The number of FP-SB allocated by the driver == max number of regular L2
+ * queues + 1 for the CNIC which also consumes an FP-SB
+ */
+#define FP_SB_COUNT(cid_cnt) ((cid_cnt) - FCOE_CONTEXT_USE)
+#define NUM_IGU_SB_REQUIRED(cid_cnt) \
+ (FP_SB_COUNT(cid_cnt) - NONE_ETH_CONTEXT_USE)
+
union cdu_context {
struct eth_context eth;
char pad[1024];
@@ -722,7 +775,8 @@ union cdu_context {
#ifdef BCM_CNIC
#define CNIC_ISCSI_CID_MAX 256
-#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX)
+#define CNIC_FCOE_CID_MAX 2048
+#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX + CNIC_FCOE_CID_MAX)
#define CNIC_ILT_LINES DIV_ROUND_UP(CNIC_CID_MAX, ILT_PAGE_CIDS)
#endif
@@ -770,6 +824,8 @@ struct bnx2x_slowpath {
u32 wb_comp;
u32 wb_data[4];
+ /* pfc configuration for DCBX ramrod */
+ struct flow_control_configuration pfc_config;
};
#define bnx2x_sp(bp, var) (&bp->slowpath->var)
@@ -918,6 +974,10 @@ struct bnx2x {
#define DISABLE_MSI_FLAG 0x200
#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG)
#define MF_FUNC_DIS 0x1000
+#define FCOE_MACS_SET 0x2000
+#define NO_FCOE_FLAG 0x4000
+
+#define NO_FCOE(bp) ((bp)->flags & NO_FCOE_FLAG)
int pf_num; /* absolute PF number */
int pfid; /* per-path PF number */
@@ -967,6 +1027,8 @@ struct bnx2x {
u16 mf_ov;
u8 mf_mode;
#define IS_MF(bp) (bp->mf_mode != 0)
+#define IS_MF_SI(bp) (bp->mf_mode == MULTI_FUNCTION_SI)
+#define IS_MF_SD(bp) (bp->mf_mode == MULTI_FUNCTION_SD)
u8 wol;
@@ -1010,6 +1072,7 @@ struct bnx2x {
#define BNX2X_ACCEPT_ALL_UNICAST 0x0004
#define BNX2X_ACCEPT_ALL_MULTICAST 0x0008
#define BNX2X_ACCEPT_BROADCAST 0x0010
+#define BNX2X_ACCEPT_UNMATCHED_UCAST 0x0020
#define BNX2X_PROMISCUOUS_MODE 0x10000
u32 rx_mode;
@@ -1062,7 +1125,8 @@ struct bnx2x {
u16 cnic_kwq_pending;
u16 cnic_spq_pending;
struct mutex cnic_mutex;
- u8 iscsi_mac[6];
+ u8 iscsi_mac[ETH_ALEN];
+ u8 fip_mac[ETH_ALEN];
#endif
int dmae_ready;
@@ -1122,6 +1186,31 @@ struct bnx2x {
char fw_ver[32];
const struct firmware *firmware;
+ /* LLDP params */
+ struct bnx2x_config_lldp_params lldp_config_params;
+
+ /* DCB support on/off */
+ u16 dcb_state;
+#define BNX2X_DCB_STATE_OFF 0
+#define BNX2X_DCB_STATE_ON 1
+
+ /* DCBX engine mode */
+ int dcbx_enabled;
+#define BNX2X_DCBX_ENABLED_OFF 0
+#define BNX2X_DCBX_ENABLED_ON_NEG_OFF 1
+#define BNX2X_DCBX_ENABLED_ON_NEG_ON 2
+#define BNX2X_DCBX_ENABLED_INVALID (-1)
+
+ bool dcbx_mode_uset;
+
+ struct bnx2x_config_dcbx_params dcbx_config_params;
+
+ struct bnx2x_dcbx_port_params dcbx_port_params;
+ int dcb_version;
+
+ /* DCBX Negotation results */
+ struct dcbx_features dcbx_local_feat;
+ u32 dcbx_error;
};
/**
@@ -1152,10 +1241,17 @@ struct bnx2x {
#define RSS_IPV6_TCP_CAP 0x0008
#define BNX2X_NUM_QUEUES(bp) (bp->num_queues)
+#define BNX2X_NUM_ETH_QUEUES(bp) (BNX2X_NUM_QUEUES(bp) - NONE_ETH_CONTEXT_USE)
+
+/* ethtool statistics are displayed for all regular ethernet queues and the
+ * fcoe L2 queue if not disabled
+ */
+#define BNX2X_NUM_STAT_QUEUES(bp) (NO_FCOE(bp) ? BNX2X_NUM_ETH_QUEUES(bp) : \
+ (BNX2X_NUM_ETH_QUEUES(bp) + FCOE_CONTEXT_USE))
+
#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1)
#define BNX2X_MAX_QUEUES(bp) (bp->igu_sb_cnt - CNIC_CONTEXT_USE)
-#define is_eth_multi(bp) (BNX2X_NUM_ETH_QUEUES(bp) > 1)
#define RSS_IPV4_CAP_MASK \
TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY
@@ -1248,6 +1344,7 @@ struct bnx2x_client_ramrod_params {
u16 cl_id;
u32 cid;
u8 poll;
+#define CLIENT_IS_FCOE 0x01
#define CLIENT_IS_LEADING_RSS 0x02
u8 flags;
};
@@ -1280,11 +1377,54 @@ struct bnx2x_func_init_params {
u16 spq_prod; /* valid iff FUNC_FLG_SPQ */
};
+#define for_each_eth_queue(bp, var) \
+ for (var = 0; var < BNX2X_NUM_ETH_QUEUES(bp); var++)
+
+#define for_each_nondefault_eth_queue(bp, var) \
+ for (var = 1; var < BNX2X_NUM_ETH_QUEUES(bp); var++)
+
+#define for_each_napi_queue(bp, var) \
+ for (var = 0; \
+ var < BNX2X_NUM_ETH_QUEUES(bp) + FCOE_CONTEXT_USE; var++) \
+ if (skip_queue(bp, var)) \
+ continue; \
+ else
+
#define for_each_queue(bp, var) \
- for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++)
+ for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \
+ if (skip_queue(bp, var)) \
+ continue; \
+ else
+
+#define for_each_rx_queue(bp, var) \
+ for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \
+ if (skip_rx_queue(bp, var)) \
+ continue; \
+ else
+
+#define for_each_tx_queue(bp, var) \
+ for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \
+ if (skip_tx_queue(bp, var)) \
+ continue; \
+ else
+
#define for_each_nondefault_queue(bp, var) \
- for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++)
+ for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++) \
+ if (skip_queue(bp, var)) \
+ continue; \
+ else
+
+/* skip rx queue
+ * if FCOE l2 support is disabled and this is the fcoe L2 queue
+ */
+#define skip_rx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx))
+/* skip tx queue
+ * if FCOE l2 support is disabled and this is the fcoe L2 queue
+ */
+#define skip_tx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx))
+
+#define skip_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx))
#define WAIT_RAMROD_POLL 0x01
#define WAIT_RAMROD_COMMON 0x02
@@ -1329,7 +1469,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_ILT_ZALLOC(x, y, size) \
do { \
- x = pci_alloc_consistent(bp->pdev, size, y); \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
if (x) \
memset(x, 0, size); \
} while (0)
@@ -1337,7 +1477,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_ILT_FREE(x, y, size) \
do { \
if (x) { \
- pci_free_consistent(bp->pdev, size, x, y); \
+ dma_free_coherent(&bp->pdev->dev, size, x, y); \
x = NULL; \
y = 0; \
} \
@@ -1608,10 +1748,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \
(T_ETH_MAC_COMMAND_INVALIDATE))
-#define CAM_INVALIDATE(x) \
- (x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE)
-
-
/* Number of u32 elements in MC hash array */
#define MC_HASH_SIZE 8
#define MC_HASH_OFFSET(bp, i) (BAR_TSTRORM_INTMEM + \
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index 459614d2d7bc..710ce5d04c53 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -698,6 +698,29 @@ void bnx2x_release_phy_lock(struct bnx2x *bp)
mutex_unlock(&bp->port.phy_mutex);
}
+/* calculates MF speed according to current linespeed and MF configuration */
+u16 bnx2x_get_mf_speed(struct bnx2x *bp)
+{
+ u16 line_speed = bp->link_vars.line_speed;
+ if (IS_MF(bp)) {
+ u16 maxCfg = (bp->mf_config[BP_VN(bp)] &
+ FUNC_MF_CFG_MAX_BW_MASK) >>
+ FUNC_MF_CFG_MAX_BW_SHIFT;
+ /* Calculate the current MAX line speed limit for the DCC
+ * capable devices
+ */
+ if (IS_MF_SD(bp)) {
+ u16 vn_max_rate = maxCfg * 100;
+
+ if (vn_max_rate < line_speed)
+ line_speed = vn_max_rate;
+ } else /* IS_MF_SI(bp)) */
+ line_speed = (line_speed * maxCfg) / 100;
+ }
+
+ return line_speed;
+}
+
void bnx2x_link_report(struct bnx2x *bp)
{
if (bp->flags & MF_FUNC_DIS) {
@@ -713,17 +736,8 @@ void bnx2x_link_report(struct bnx2x *bp)
netif_carrier_on(bp->dev);
netdev_info(bp->dev, "NIC Link is Up, ");
- line_speed = bp->link_vars.line_speed;
- if (IS_MF(bp)) {
- u16 vn_max_rate;
+ line_speed = bnx2x_get_mf_speed(bp);
- vn_max_rate =
- ((bp->mf_config[BP_VN(bp)] &
- FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
- if (vn_max_rate < line_speed)
- line_speed = vn_max_rate;
- }
pr_cont("%d Mbps ", line_speed);
if (bp->link_vars.duplex == DUPLEX_FULL)
@@ -813,7 +827,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
DP(NETIF_MSG_IFUP,
"mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
- for_each_queue(bp, j) {
+ for_each_rx_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
if (!fp->disable_tpa) {
@@ -866,7 +880,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
}
}
- for_each_queue(bp, j) {
+ for_each_rx_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
fp->rx_bd_cons = 0;
@@ -897,7 +911,7 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
{
int i;
- for_each_queue(bp, i) {
+ for_each_tx_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
u16 bd_cons = fp->tx_bd_cons;
@@ -915,7 +929,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
{
int i, j;
- for_each_queue(bp, j) {
+ for_each_rx_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
for (i = 0; i < NUM_RX_BD; i++) {
@@ -956,7 +970,7 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
#ifdef BCM_CNIC
offset++;
#endif
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
"state %x\n", i, bp->msix_table[i + offset].vector,
bnx2x_fp(bp, i, state));
@@ -990,14 +1004,14 @@ int bnx2x_enable_msix(struct bnx2x *bp)
bp->msix_table[msix_vec].entry, bp->msix_table[msix_vec].entry);
msix_vec++;
#endif
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
bp->msix_table[msix_vec].entry = msix_vec;
DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
"(fastpath #%u)\n", msix_vec, msix_vec, i);
msix_vec++;
}
- req_cnt = BNX2X_NUM_QUEUES(bp) + CNIC_CONTEXT_USE + 1;
+ req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_CONTEXT_USE + 1;
rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt);
@@ -1053,7 +1067,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
#ifdef BCM_CNIC
offset++;
#endif
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
bp->dev->name, i);
@@ -1070,7 +1084,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
fp->state = BNX2X_FP_STATE_IRQ;
}
- i = BNX2X_NUM_QUEUES(bp);
+ i = BNX2X_NUM_ETH_QUEUES(bp);
offset = 1 + CNIC_CONTEXT_USE;
netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d"
" ... fp[%d] %d\n",
@@ -1117,7 +1131,7 @@ static void bnx2x_napi_enable(struct bnx2x *bp)
{
int i;
- for_each_queue(bp, i)
+ for_each_napi_queue(bp, i)
napi_enable(&bnx2x_fp(bp, i, napi));
}
@@ -1125,7 +1139,7 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
{
int i;
- for_each_queue(bp, i)
+ for_each_napi_queue(bp, i)
napi_disable(&bnx2x_fp(bp, i, napi));
}
@@ -1153,6 +1167,35 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
netif_tx_disable(bp->dev);
}
+u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+#ifdef BCM_CNIC
+ struct bnx2x *bp = netdev_priv(dev);
+ if (NO_FCOE(bp))
+ return skb_tx_hash(dev, skb);
+ else {
+ struct ethhdr *hdr = (struct ethhdr *)skb->data;
+ u16 ether_type = ntohs(hdr->h_proto);
+
+ /* Skip VLAN tag if present */
+ if (ether_type == ETH_P_8021Q) {
+ struct vlan_ethhdr *vhdr =
+ (struct vlan_ethhdr *)skb->data;
+
+ ether_type = ntohs(vhdr->h_vlan_encapsulated_proto);
+ }
+
+ /* If ethertype is FCoE or FIP - use FCoE ring */
+ if ((ether_type == ETH_P_FCOE) || (ether_type == ETH_P_FIP))
+ return bnx2x_fcoe(bp, index);
+ }
+#endif
+ /* Select a none-FCoE queue: if FCoE is enabled, exclude FCoE L2 ring
+ */
+ return __skb_tx_hash(dev, skb,
+ dev->real_num_tx_queues - FCOE_CONTEXT_USE);
+}
+
void bnx2x_set_num_queues(struct bnx2x *bp)
{
switch (bp->multi_mode) {
@@ -1167,8 +1210,23 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
bp->num_queues = 1;
break;
}
+
+ /* Add special queues */
+ bp->num_queues += NONE_ETH_CONTEXT_USE;
}
+#ifdef BCM_CNIC
+static inline void bnx2x_set_fcoe_eth_macs(struct bnx2x *bp)
+{
+ if (!NO_FCOE(bp)) {
+ if (!IS_MF_SD(bp))
+ bnx2x_set_fip_eth_mac_addr(bp, 1);
+ bnx2x_set_all_enode_macs(bp, 1);
+ bp->flags |= FCOE_MACS_SET;
+ }
+}
+#endif
+
static void bnx2x_release_firmware(struct bnx2x *bp)
{
kfree(bp->init_ops_offsets);
@@ -1177,6 +1235,20 @@ static void bnx2x_release_firmware(struct bnx2x *bp)
release_firmware(bp->firmware);
}
+static inline int bnx2x_set_real_num_queues(struct bnx2x *bp)
+{
+ int rc, num = bp->num_queues;
+
+#ifdef BCM_CNIC
+ if (NO_FCOE(bp))
+ num -= FCOE_CONTEXT_USE;
+
+#endif
+ netif_set_real_num_tx_queues(bp->dev, num);
+ rc = netif_set_real_num_rx_queues(bp->dev, num);
+ return rc;
+}
+
/* must be called with rtnl_lock */
int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
{
@@ -1203,10 +1275,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (bnx2x_alloc_mem(bp))
return -ENOMEM;
- netif_set_real_num_tx_queues(bp->dev, bp->num_queues);
- rc = netif_set_real_num_rx_queues(bp->dev, bp->num_queues);
+ rc = bnx2x_set_real_num_queues(bp);
if (rc) {
- BNX2X_ERR("Unable to update real_num_rx_queues\n");
+ BNX2X_ERR("Unable to set real_num_queues\n");
goto load_error0;
}
@@ -1214,6 +1285,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bnx2x_fp(bp, i, disable_tpa) =
((bp->flags & TPA_ENABLE_FLAG) == 0);
+#ifdef BCM_CNIC
+ /* We don't want TPA on FCoE L2 ring */
+ bnx2x_fcoe(bp, disable_tpa) = 1;
+#endif
bnx2x_napi_enable(bp);
/* Send LOAD_REQUEST command to MCP
@@ -1296,6 +1371,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
}
+ bnx2x_dcbx_init(bp);
+
bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
rc = bnx2x_func_start(bp);
@@ -1344,6 +1421,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Now when Clients are configured we are ready to work */
bp->state = BNX2X_STATE_OPEN;
+#ifdef BCM_CNIC
+ bnx2x_set_fcoe_eth_macs(bp);
+#endif
+
bnx2x_set_eth_mac(bp, 1);
if (bp->port.pmf)
@@ -1402,7 +1483,7 @@ load_error3:
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
- for_each_queue(bp, i)
+ for_each_rx_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
/* Release IRQs */
@@ -1473,7 +1554,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
- for_each_queue(bp, i)
+ for_each_rx_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
bnx2x_free_mem(bp);
@@ -1577,6 +1658,17 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
/* Fall out from the NAPI loop if needed */
if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+#ifdef BCM_CNIC
+ /* No need to update SB for FCoE L2 ring as long as
+ * it's connected to the default SB and the SB
+ * has been updated when NAPI was scheduled.
+ */
+ if (IS_FCOE_FP(fp)) {
+ napi_complete(napi);
+ break;
+ }
+#endif
+
bnx2x_update_fpsb_idx(fp);
/* bnx2x_has_rx_work() reads the status block,
* thus we need to ensure that status block indices
@@ -1680,7 +1772,7 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
rc = XMIT_PLAIN;
else {
- if (skb->protocol == htons(ETH_P_IPV6)) {
+ if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) {
rc = XMIT_CSUM_V6;
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
rc |= XMIT_CSUM_TCP;
@@ -1692,11 +1784,10 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
}
}
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
- rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
-
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
+ if (skb_is_gso_v6(skb))
+ rc |= XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6;
+ else if (skb_is_gso(skb))
+ rc |= XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP;
return rc;
}
@@ -1782,15 +1873,15 @@ exit_lbl:
}
#endif
-static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb,
- struct eth_tx_parse_bd_e2 *pbd,
- u32 xmit_type)
+static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
+ u32 xmit_type)
{
- pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) <<
- ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT;
+ *parsing_data |= (skb_shinfo(skb)->gso_size <<
+ ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+ ETH_TX_PARSE_BD_E2_LSO_MSS;
if ((xmit_type & XMIT_GSO_V6) &&
(ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
- pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+ *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
}
/**
@@ -1835,15 +1926,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
* @return header len
*/
static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
- struct eth_tx_parse_bd_e2 *pbd,
- u32 xmit_type)
+ u32 *parsing_data, u32 xmit_type)
{
- pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT;
+ *parsing_data |= ((tcp_hdrlen(skb)/4) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
- pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) -
- skb->data) / 2) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT;
+ *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
}
@@ -1912,6 +2003,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
+ u32 pbd_e2_parsing_data = 0;
u16 pkt_prod, bd_prod;
int nbd, fp_index;
dma_addr_t mapping;
@@ -2033,8 +2125,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
/* Set PBD in checksum offload case */
if (xmit_type & XMIT_CSUM)
- hlen = bnx2x_set_pbd_csum_e2(bp,
- skb, pbd_e2, xmit_type);
+ hlen = bnx2x_set_pbd_csum_e2(bp, skb,
+ &pbd_e2_parsing_data,
+ xmit_type);
} else {
pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
@@ -2076,10 +2169,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
hlen, bd_prod, ++nbd);
if (CHIP_IS_E2(bp))
- bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type);
+ bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
+ xmit_type);
else
bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
}
+
+ /* Set the PBD's parsing_data field if not zero
+ * (for the chips newer than 57711).
+ */
+ if (pbd_e2_parsing_data)
+ pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);
+
tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
/* Handle fragmented skb */
@@ -2232,7 +2333,7 @@ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp)
bp->fp = fp;
/* msix table */
- tbl = kzalloc((bp->l2_cid_count + 1) * sizeof(*tbl),
+ tbl = kzalloc((FP_SB_COUNT(bp->l2_cid_count) + 1) * sizeof(*tbl),
GFP_KERNEL);
if (!tbl)
goto alloc_err;
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h
index 6b28739c5302..03eb4d68e6bb 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/bnx2x/bnx2x_cmn.h
@@ -73,6 +73,16 @@ void bnx2x__link_status_update(struct bnx2x *bp);
void bnx2x_link_report(struct bnx2x *bp);
/**
+ * calculates MF speed according to current linespeed and MF
+ * configuration
+ *
+ * @param bp
+ *
+ * @return u16
+ */
+u16 bnx2x_get_mf_speed(struct bnx2x *bp);
+
+/**
* MSI-X slowpath interrupt handler
*
* @param irq
@@ -232,6 +242,30 @@ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource);
*/
void bnx2x_set_eth_mac(struct bnx2x *bp, int set);
+#ifdef BCM_CNIC
+/**
+ * Set/Clear FIP MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). This function will wait until the ramdord completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set);
+
+/**
+ * Set/Clear ALL_ENODE mcast MAC.
+ *
+ * @param bp
+ * @param set
+ *
+ * @return int
+ */
+int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set);
+#endif
+
/**
* Set MAC filtering configurations.
*
@@ -290,6 +324,13 @@ int bnx2x_func_start(struct bnx2x *bp);
void bnx2x_ilt_set_info(struct bnx2x *bp);
/**
+ * Inintialize dcbx protocol
+ *
+ * @param bp
+ */
+void bnx2x_dcbx_init(struct bnx2x *bp);
+
+/**
* Set power state to the requested value. Currently only D0 and
* D3hot are supported.
*
@@ -309,6 +350,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
/* hard_xmit callback */
netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
+/* select_queue callback */
+u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
+
int bnx2x_change_mac_addr(struct net_device *dev, void *p);
/* NAPI poll Rx part */
@@ -685,7 +729,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
int i;
/* Add NAPI objects */
- for_each_queue(bp, i)
+ for_each_napi_queue(bp, i)
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
bnx2x_poll, BNX2X_NAPI_WEIGHT);
}
@@ -694,7 +738,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
{
int i;
- for_each_queue(bp, i)
+ for_each_napi_queue(bp, i)
netif_napi_del(&bnx2x_fp(bp, i, napi));
}
@@ -860,7 +904,7 @@ static inline void bnx2x_init_tx_rings(struct bnx2x *bp)
{
int i, j;
- for_each_queue(bp, j) {
+ for_each_tx_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
for (i = 1; i <= NUM_TX_RINGS; i++) {
@@ -939,7 +983,30 @@ static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp)
}
}
+#ifdef BCM_CNIC
+static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
+{
+ bnx2x_fcoe(bp, cl_id) = BNX2X_FCOE_ETH_CL_ID +
+ BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE;
+ bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID;
+ bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID;
+ bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id;
+ bnx2x_fcoe(bp, bp) = bp;
+ bnx2x_fcoe(bp, state) = BNX2X_FP_STATE_CLOSED;
+ bnx2x_fcoe(bp, index) = FCOE_IDX;
+ bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX;
+ bnx2x_fcoe(bp, tx_cons_sb) = BNX2X_FCOE_L2_TX_INDEX;
+ /* qZone id equals to FW (per path) client id */
+ bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fcoe(bp, cl_id) +
+ BP_PORT(bp)*(CHIP_IS_E2(bp) ? ETH_MAX_RX_CLIENTS_E2 :
+ ETH_MAX_RX_CLIENTS_E1H);
+ /* init shortcut */
+ bnx2x_fcoe(bp, ustorm_rx_prods_offset) = CHIP_IS_E2(bp) ?
+ USTORM_RX_PRODS_E2_OFFSET(bnx2x_fcoe(bp, cl_qzone_id)) :
+ USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), bnx2x_fcoe_fp(bp)->cl_id);
+}
+#endif
static inline void __storm_memset_struct(struct bnx2x *bp,
u32 addr, size_t size, u32 *data)
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c
new file mode 100644
index 000000000000..fb60021f81fb
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_dcb.c
@@ -0,0 +1,2118 @@
+/* bnx2x_dcb.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2010 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Dmitry Kravkov
+ *
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include "bnx2x_dcb.h"
+
+
+/* forward declarations of dcbx related functions */
+static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
+static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
+static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
+static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
+static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
+ u32 *set_configuration_ets_pg,
+ u32 *pri_pg_tbl);
+static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
+ u32 *pg_pri_orginal_spread,
+ struct pg_help_data *help_data);
+static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
+ struct pg_help_data *help_data,
+ struct dcbx_ets_feature *ets,
+ u32 *pg_pri_orginal_spread);
+static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
+ struct cos_help_data *cos_data,
+ u32 *pg_pri_orginal_spread,
+ struct dcbx_ets_feature *ets);
+static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp);
+
+
+static void bnx2x_pfc_set(struct bnx2x *bp)
+{
+ struct bnx2x_nig_brb_pfc_port_params pfc_params = {0};
+ u32 pri_bit, val = 0;
+ u8 pri;
+
+ /* Tx COS configuration */
+ if (bp->dcbx_port_params.ets.cos_params[0].pauseable)
+ pfc_params.rx_cos0_priority_mask =
+ bp->dcbx_port_params.ets.cos_params[0].pri_bitmask;
+ if (bp->dcbx_port_params.ets.cos_params[1].pauseable)
+ pfc_params.rx_cos1_priority_mask =
+ bp->dcbx_port_params.ets.cos_params[1].pri_bitmask;
+
+
+ /**
+ * Rx COS configuration
+ * Changing PFC RX configuration .
+ * In RX COS0 will always be configured to lossy and COS1 to lossless
+ */
+ for (pri = 0 ; pri < MAX_PFC_PRIORITIES ; pri++) {
+ pri_bit = 1 << pri;
+
+ if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp))
+ val |= 1 << (pri * 4);
+ }
+
+ pfc_params.pkt_priority_to_cos = val;
+
+ /* RX COS0 */
+ pfc_params.llfc_low_priority_classes = 0;
+ /* RX COS1 */
+ pfc_params.llfc_high_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp);
+
+ /* BRB configuration */
+ pfc_params.cos0_pauseable = false;
+ pfc_params.cos1_pauseable = true;
+
+ bnx2x_acquire_phy_lock(bp);
+ bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED;
+ bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params);
+ bnx2x_release_phy_lock(bp);
+}
+
+static void bnx2x_pfc_clear(struct bnx2x *bp)
+{
+ struct bnx2x_nig_brb_pfc_port_params nig_params = {0};
+ nig_params.pause_enable = 1;
+#ifdef BNX2X_SAFC
+ if (bp->flags & SAFC_TX_FLAG) {
+ u32 high = 0, low = 0;
+ int i;
+
+ for (i = 0; i < BNX2X_MAX_PRIORITY; i++) {
+ if (bp->pri_map[i] == 1)
+ high |= (1 << i);
+ if (bp->pri_map[i] == 0)
+ low |= (1 << i);
+ }
+
+ nig_params.llfc_low_priority_classes = high;
+ nig_params.llfc_low_priority_classes = low;
+
+ nig_params.pause_enable = 0;
+ nig_params.llfc_enable = 1;
+ nig_params.llfc_out_en = 1;
+ }
+#endif /* BNX2X_SAFC */
+ bnx2x_acquire_phy_lock(bp);
+ bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED;
+ bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params);
+ bnx2x_release_phy_lock(bp);
+}
+
+static void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp,
+ struct dcbx_features *features,
+ u32 error)
+{
+ u8 i = 0;
+ DP(NETIF_MSG_LINK, "local_mib.error %x\n", error);
+
+ /* PG */
+ DP(NETIF_MSG_LINK,
+ "local_mib.features.ets.enabled %x\n", features->ets.enabled);
+ for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++)
+ DP(NETIF_MSG_LINK,
+ "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i,
+ DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i));
+ for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++)
+ DP(NETIF_MSG_LINK,
+ "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i,
+ DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i));
+
+ /* pfc */
+ DP(NETIF_MSG_LINK, "dcbx_features.pfc.pri_en_bitmap %x\n",
+ features->pfc.pri_en_bitmap);
+ DP(NETIF_MSG_LINK, "dcbx_features.pfc.pfc_caps %x\n",
+ features->pfc.pfc_caps);
+ DP(NETIF_MSG_LINK, "dcbx_features.pfc.enabled %x\n",
+ features->pfc.enabled);
+
+ DP(NETIF_MSG_LINK, "dcbx_features.app.default_pri %x\n",
+ features->app.default_pri);
+ DP(NETIF_MSG_LINK, "dcbx_features.app.tc_supported %x\n",
+ features->app.tc_supported);
+ DP(NETIF_MSG_LINK, "dcbx_features.app.enabled %x\n",
+ features->app.enabled);
+ for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
+ DP(NETIF_MSG_LINK,
+ "dcbx_features.app.app_pri_tbl[%x].app_id %x\n",
+ i, features->app.app_pri_tbl[i].app_id);
+ DP(NETIF_MSG_LINK,
+ "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n",
+ i, features->app.app_pri_tbl[i].pri_bitmap);
+ DP(NETIF_MSG_LINK,
+ "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n",
+ i, features->app.app_pri_tbl[i].appBitfield);
+ }
+}
+
+static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp,
+ u8 pri_bitmap,
+ u8 llfc_traf_type)
+{
+ u32 pri = MAX_PFC_PRIORITIES;
+ u32 index = MAX_PFC_PRIORITIES - 1;
+ u32 pri_mask;
+ u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+
+ /* Choose the highest priority */
+ while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) {
+ pri_mask = 1 << index;
+ if (GET_FLAGS(pri_bitmap, pri_mask))
+ pri = index ;
+ index--;
+ }
+
+ if (pri < MAX_PFC_PRIORITIES)
+ ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri);
+}
+
+static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
+ struct dcbx_app_priority_feature *app,
+ u32 error) {
+ u8 index;
+ u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+
+ if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_ERROR\n");
+
+ if (app->enabled && !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) {
+
+ bp->dcbx_port_params.app.enabled = true;
+
+ for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
+ ttp[index] = 0;
+
+ if (app->default_pri < MAX_PFC_PRIORITIES)
+ ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri;
+
+ for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) {
+ struct dcbx_app_priority_entry *entry =
+ app->app_pri_tbl;
+
+ if (GET_FLAGS(entry[index].appBitfield,
+ DCBX_APP_SF_ETH_TYPE) &&
+ ETH_TYPE_FCOE == entry[index].app_id)
+ bnx2x_dcbx_get_ap_priority(bp,
+ entry[index].pri_bitmap,
+ LLFC_TRAFFIC_TYPE_FCOE);
+
+ if (GET_FLAGS(entry[index].appBitfield,
+ DCBX_APP_SF_PORT) &&
+ TCP_PORT_ISCSI == entry[index].app_id)
+ bnx2x_dcbx_get_ap_priority(bp,
+ entry[index].pri_bitmap,
+ LLFC_TRAFFIC_TYPE_ISCSI);
+ }
+ } else {
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_DISABLED\n");
+ bp->dcbx_port_params.app.enabled = false;
+ for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
+ ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY;
+ }
+}
+
+static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
+ struct dcbx_ets_feature *ets,
+ u32 error) {
+ int i = 0;
+ u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0};
+ struct pg_help_data pg_help_data;
+ struct bnx2x_dcbx_cos_params *cos_params =
+ bp->dcbx_port_params.ets.cos_params;
+
+ memset(&pg_help_data, 0, sizeof(struct pg_help_data));
+
+
+ if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR))
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ERROR\n");
+
+
+ /* Clean up old settings of ets on COS */
+ for (i = 0; i < E2_NUM_OF_COS ; i++) {
+
+ cos_params[i].pauseable = false;
+ cos_params[i].strict = BNX2X_DCBX_COS_NOT_STRICT;
+ cos_params[i].bw_tbl = DCBX_INVALID_COS_BW;
+ cos_params[i].pri_bitmask = DCBX_PFC_PRI_GET_NON_PAUSE(bp, 0);
+ }
+
+ if (bp->dcbx_port_params.app.enabled &&
+ !GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR) &&
+ ets->enabled) {
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ENABLE\n");
+ bp->dcbx_port_params.ets.enabled = true;
+
+ bnx2x_dcbx_get_ets_pri_pg_tbl(bp,
+ pg_pri_orginal_spread,
+ ets->pri_pg_tbl);
+
+ bnx2x_dcbx_get_num_pg_traf_type(bp,
+ pg_pri_orginal_spread,
+ &pg_help_data);
+
+ bnx2x_dcbx_fill_cos_params(bp, &pg_help_data,
+ ets, pg_pri_orginal_spread);
+
+ } else {
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_DISABLED\n");
+ bp->dcbx_port_params.ets.enabled = false;
+ ets->pri_pg_tbl[0] = 0;
+
+ for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++)
+ DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1);
+ }
+}
+
+static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,
+ struct dcbx_pfc_feature *pfc, u32 error)
+{
+
+ if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR))
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_ERROR\n");
+
+ if (bp->dcbx_port_params.app.enabled &&
+ !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR) &&
+ pfc->enabled) {
+ bp->dcbx_port_params.pfc.enabled = true;
+ bp->dcbx_port_params.pfc.priority_non_pauseable_mask =
+ ~(pfc->pri_en_bitmap);
+ } else {
+ DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_DISABLED\n");
+ bp->dcbx_port_params.pfc.enabled = false;
+ bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0;
+ }
+}
+
+static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp,
+ struct dcbx_features *features,
+ u32 error)
+{
+ bnx2x_dcbx_get_ap_feature(bp, &features->app, error);
+
+ bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error);
+
+ bnx2x_dcbx_get_ets_feature(bp, &features->ets, error);
+}
+
+#define DCBX_LOCAL_MIB_MAX_TRY_READ (100)
+static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
+ u32 *base_mib_addr,
+ u32 offset,
+ int read_mib_type)
+{
+ int max_try_read = 0, i;
+ u32 *buff, mib_size, prefix_seq_num, suffix_seq_num;
+ struct lldp_remote_mib *remote_mib ;
+ struct lldp_local_mib *local_mib;
+
+
+ switch (read_mib_type) {
+ case DCBX_READ_LOCAL_MIB:
+ mib_size = sizeof(struct lldp_local_mib);
+ break;
+ case DCBX_READ_REMOTE_MIB:
+ mib_size = sizeof(struct lldp_remote_mib);
+ break;
+ default:
+ return 1; /*error*/
+ }
+
+ offset += BP_PORT(bp) * mib_size;
+
+ do {
+ buff = base_mib_addr;
+ for (i = 0; i < mib_size; i += 4, buff++)
+ *buff = REG_RD(bp, offset + i);
+
+ max_try_read++;
+
+ switch (read_mib_type) {
+ case DCBX_READ_LOCAL_MIB:
+ local_mib = (struct lldp_local_mib *) base_mib_addr;
+ prefix_seq_num = local_mib->prefix_seq_num;
+ suffix_seq_num = local_mib->suffix_seq_num;
+ break;
+ case DCBX_READ_REMOTE_MIB:
+ remote_mib = (struct lldp_remote_mib *) base_mib_addr;
+ prefix_seq_num = remote_mib->prefix_seq_num;
+ suffix_seq_num = remote_mib->suffix_seq_num;
+ break;
+ default:
+ return 1; /*error*/
+ }
+ } while ((prefix_seq_num != suffix_seq_num) &&
+ (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ));
+
+ if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) {
+ BNX2X_ERR("MIB could not be read\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
+{
+ if (CHIP_IS_E2(bp)) {
+ if (BP_PORT(bp)) {
+ BNX2X_ERR("4 port mode is not supported");
+ return;
+ }
+
+ if (bp->dcbx_port_params.pfc.enabled)
+
+ /* 1. Fills up common PFC structures if required.*/
+ /* 2. Configure NIG, MAC and BRB via the elink:
+ * elink must first check if BMAC is not in reset
+ * and only then configures the BMAC
+ * Or, configure EMAC.
+ */
+ bnx2x_pfc_set(bp);
+
+ else
+ bnx2x_pfc_clear(bp);
+ }
+}
+
+static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
+{
+ DP(NETIF_MSG_LINK, "sending STOP TRAFFIC\n");
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC,
+ 0 /* connectionless */,
+ 0 /* dataHi is zero */,
+ 0 /* dataLo is zero */,
+ 1 /* common */);
+}
+
+static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
+{
+ bnx2x_pfc_fw_struct_e2(bp);
+ DP(NETIF_MSG_LINK, "sending START TRAFFIC\n");
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC,
+ 0, /* connectionless */
+ U64_HI(bnx2x_sp_mapping(bp, pfc_config)),
+ U64_LO(bnx2x_sp_mapping(bp, pfc_config)),
+ 1 /* commmon */);
+}
+
+static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
+{
+ struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
+ u8 status = 0;
+
+ bnx2x_ets_disabled(&bp->link_params);
+
+ if (!ets->enabled)
+ return;
+
+ if ((ets->num_of_cos == 0) || (ets->num_of_cos > E2_NUM_OF_COS)) {
+ BNX2X_ERR("illegal num of cos= %x", ets->num_of_cos);
+ return;
+ }
+
+ /* valid COS entries */
+ if (ets->num_of_cos == 1) /* no ETS */
+ return;
+
+ /* sanity */
+ if (((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[0].strict) &&
+ (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) ||
+ ((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[1].strict) &&
+ (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) {
+ BNX2X_ERR("all COS should have at least bw_limit or strict"
+ "ets->cos_params[0].strict= %x"
+ "ets->cos_params[0].bw_tbl= %x"
+ "ets->cos_params[1].strict= %x"
+ "ets->cos_params[1].bw_tbl= %x",
+ ets->cos_params[0].strict,
+ ets->cos_params[0].bw_tbl,
+ ets->cos_params[1].strict,
+ ets->cos_params[1].bw_tbl);
+ return;
+ }
+ /* If we join a group and there is bw_tbl and strict then bw rules */
+ if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) &&
+ (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) {
+ u32 bw_tbl_0 = ets->cos_params[0].bw_tbl;
+ u32 bw_tbl_1 = ets->cos_params[1].bw_tbl;
+ /* Do not allow 0-100 configuration
+ * since PBF does not support it
+ * force 1-99 instead
+ */
+ if (bw_tbl_0 == 0) {
+ bw_tbl_0 = 1;
+ bw_tbl_1 = 99;
+ } else if (bw_tbl_1 == 0) {
+ bw_tbl_1 = 1;
+ bw_tbl_0 = 99;
+ }
+
+ bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1);
+ } else {
+ if (ets->cos_params[0].strict == BNX2X_DCBX_COS_HIGH_STRICT)
+ status = bnx2x_ets_strict(&bp->link_params, 0);
+ else if (ets->cos_params[1].strict
+ == BNX2X_DCBX_COS_HIGH_STRICT)
+ status = bnx2x_ets_strict(&bp->link_params, 1);
+
+ if (status)
+ BNX2X_ERR("update_ets_params failed\n");
+ }
+}
+
+static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
+{
+ struct lldp_local_mib local_mib = {0};
+ u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset);
+ int rc;
+
+ DP(NETIF_MSG_LINK, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset);
+
+ if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) {
+ BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n");
+ return -EINVAL;
+ }
+ rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset,
+ DCBX_READ_LOCAL_MIB);
+
+ if (rc) {
+ BNX2X_ERR("Faild to read local mib from FW\n");
+ return rc;
+ }
+
+ /* save features and error */
+ bp->dcbx_local_feat = local_mib.features;
+ bp->dcbx_error = local_mib.error;
+ return 0;
+}
+
+void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
+{
+ switch (state) {
+ case BNX2X_DCBX_STATE_NEG_RECEIVED:
+ {
+ DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n");
+
+ /* Read neg results if dcbx is in the FW */
+ if (bnx2x_dcbx_read_shmem_neg_results(bp))
+ return;
+
+ bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,
+ bp->dcbx_error);
+
+ bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
+ bp->dcbx_error);
+
+ if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) {
+ bnx2x_dcbx_stop_hw_tx(bp);
+ return;
+ }
+ /* fall through */
+ }
+ case BNX2X_DCBX_STATE_TX_PAUSED:
+ DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_PAUSED\n");
+ bnx2x_pfc_set_pfc(bp);
+
+ bnx2x_dcbx_update_ets_params(bp);
+ if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) {
+ bnx2x_dcbx_resume_hw_tx(bp);
+ return;
+ }
+ /* fall through */
+ case BNX2X_DCBX_STATE_TX_RELEASED:
+ DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n");
+ if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD)
+ bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0);
+
+ return;
+ default:
+ BNX2X_ERR("Unknown DCBX_STATE\n");
+ }
+}
+
+
+#define LLDP_STATS_OFFSET(bp) (BP_PORT(bp)*\
+ sizeof(struct lldp_dcbx_stat))
+
+/* calculate struct offset in array according to chip information */
+#define LLDP_PARAMS_OFFSET(bp) (BP_PORT(bp)*sizeof(struct lldp_params))
+
+#define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \
+ BP_PORT(bp)*sizeof(struct lldp_admin_mib))
+
+static void bnx2x_dcbx_lldp_updated_params(struct bnx2x *bp,
+ u32 dcbx_lldp_params_offset)
+{
+ struct lldp_params lldp_params = {0};
+ u32 i = 0, *buff = NULL;
+ u32 offset = dcbx_lldp_params_offset + LLDP_PARAMS_OFFSET(bp);
+
+ DP(NETIF_MSG_LINK, "lldp_offset 0x%x\n", offset);
+
+ if ((bp->lldp_config_params.overwrite_settings ==
+ BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE)) {
+ /* Read the data first */
+ buff = (u32 *)&lldp_params;
+ for (i = 0; i < sizeof(struct lldp_params); i += 4, buff++)
+ *buff = REG_RD(bp, (offset + i));
+
+ lldp_params.msg_tx_hold =
+ (u8)bp->lldp_config_params.msg_tx_hold;
+ lldp_params.msg_fast_tx_interval =
+ (u8)bp->lldp_config_params.msg_fast_tx;
+ lldp_params.tx_crd_max =
+ (u8)bp->lldp_config_params.tx_credit_max;
+ lldp_params.msg_tx_interval =
+ (u8)bp->lldp_config_params.msg_tx_interval;
+ lldp_params.tx_fast =
+ (u8)bp->lldp_config_params.tx_fast;
+
+ /* Write the data.*/
+ buff = (u32 *)&lldp_params;
+ for (i = 0; i < sizeof(struct lldp_params); i += 4, buff++)
+ REG_WR(bp, (offset + i) , *buff);
+
+
+ } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
+ bp->lldp_config_params.overwrite_settings)
+ bp->lldp_config_params.overwrite_settings =
+ BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID;
+}
+
+static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
+ u32 dcbx_lldp_params_offset)
+{
+ struct lldp_admin_mib admin_mib;
+ u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0;
+ u32 *buff;
+ u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp);
+
+ /*shortcuts*/
+ struct dcbx_features *af = &admin_mib.features;
+ struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params;
+
+ memset(&admin_mib, 0, sizeof(struct lldp_admin_mib));
+ buff = (u32 *)&admin_mib;
+ /* Read the data first */
+ for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++)
+ *buff = REG_RD(bp, (offset + i));
+
+ if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON)
+ SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
+
+ if ((BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
+ dp->overwrite_settings)) {
+ RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK);
+ admin_mib.ver_cfg_flags |=
+ (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) &
+ DCBX_CEE_VERSION_MASK;
+
+ af->ets.enabled = (u8)dp->admin_ets_enable;
+
+ af->pfc.enabled = (u8)dp->admin_pfc_enable;
+
+ /* FOR IEEE dp->admin_tc_supported_tx_enable */
+ if (dp->admin_ets_configuration_tx_enable)
+ SET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_ETS_CONFIG_TX_ENABLED);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_ETS_CONFIG_TX_ENABLED);
+ /* For IEEE admin_ets_recommendation_tx_enable */
+ if (dp->admin_pfc_tx_enable)
+ SET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_PFC_CONFIG_TX_ENABLED);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_PFC_CONFIG_TX_ENABLED);
+
+ if (dp->admin_application_priority_tx_enable)
+ SET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_APP_CONFIG_TX_ENABLED);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags,
+ DCBX_APP_CONFIG_TX_ENABLED);
+
+ if (dp->admin_ets_willing)
+ SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);
+ /* For IEEE admin_ets_reco_valid */
+ if (dp->admin_pfc_willing)
+ SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);
+
+ if (dp->admin_app_priority_willing)
+ SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);
+ else
+ RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);
+
+ for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) {
+ DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i,
+ (u8)dp->admin_configuration_bw_precentage[i]);
+
+ DP(NETIF_MSG_LINK, "pg_bw_tbl[%d] = %02x\n",
+ i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i));
+ }
+
+ for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
+ DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i,
+ (u8)dp->admin_configuration_ets_pg[i]);
+
+ DP(NETIF_MSG_LINK, "pri_pg_tbl[%d] = %02x\n",
+ i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i));
+ }
+
+ /*For IEEE admin_recommendation_bw_precentage
+ *For IEEE admin_recommendation_ets_pg */
+ af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
+ for (i = 0; i < 4; i++) {
+ if (dp->admin_priority_app_table[i].valid) {
+ struct bnx2x_admin_priority_app_table *table =
+ dp->admin_priority_app_table;
+ if ((ETH_TYPE_FCOE == table[i].app_id) &&
+ (TRAFFIC_TYPE_ETH == table[i].traffic_type))
+ traf_type = FCOE_APP_IDX;
+ else if ((TCP_PORT_ISCSI == table[i].app_id) &&
+ (TRAFFIC_TYPE_PORT == table[i].traffic_type))
+ traf_type = ISCSI_APP_IDX;
+ else
+ traf_type = other_traf_type++;
+
+ af->app.app_pri_tbl[traf_type].app_id =
+ table[i].app_id;
+
+ af->app.app_pri_tbl[traf_type].pri_bitmap =
+ (u8)(1 << table[i].priority);
+
+ af->app.app_pri_tbl[traf_type].appBitfield =
+ (DCBX_APP_ENTRY_VALID);
+
+ af->app.app_pri_tbl[traf_type].appBitfield |=
+ (TRAFFIC_TYPE_ETH == table[i].traffic_type) ?
+ DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT;
+ }
+ }
+
+ af->app.default_pri = (u8)dp->admin_default_priority;
+
+ } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
+ dp->overwrite_settings)
+ dp->overwrite_settings = BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID;
+
+ /* Write the data. */
+ buff = (u32 *)&admin_mib;
+ for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++)
+ REG_WR(bp, (offset + i), *buff);
+}
+
+void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
+{
+ if (CHIP_IS_E2(bp) && !CHIP_MODE_IS_4_PORT(bp)) {
+ bp->dcb_state = dcb_on;
+ bp->dcbx_enabled = dcbx_enabled;
+ } else {
+ bp->dcb_state = false;
+ bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID;
+ }
+ DP(NETIF_MSG_LINK, "DCB state [%s:%s]\n",
+ dcb_on ? "ON" : "OFF",
+ dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" :
+ dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" :
+ dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ?
+ "on-chip with negotiation" : "invalid");
+}
+
+void bnx2x_dcbx_init_params(struct bnx2x *bp)
+{
+ bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */
+ bp->dcbx_config_params.admin_ets_willing = 1;
+ bp->dcbx_config_params.admin_pfc_willing = 1;
+ bp->dcbx_config_params.overwrite_settings = 1;
+ bp->dcbx_config_params.admin_ets_enable = 1;
+ bp->dcbx_config_params.admin_pfc_enable = 1;
+ bp->dcbx_config_params.admin_tc_supported_tx_enable = 1;
+ bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
+ bp->dcbx_config_params.admin_pfc_tx_enable = 1;
+ bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
+ bp->dcbx_config_params.admin_ets_reco_valid = 1;
+ bp->dcbx_config_params.admin_app_priority_willing = 1;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 00;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 50;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 50;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0;
+ bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[0] = 1;
+ bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[3] = 2;
+ bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0;
+ bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 0;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 1;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 2;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 7;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 5;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 6;
+ bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 7;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6;
+ bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7;
+ bp->dcbx_config_params.admin_pfc_bitmap = 0x8; /* FCoE(3) enable */
+ bp->dcbx_config_params.admin_priority_app_table[0].valid = 1;
+ bp->dcbx_config_params.admin_priority_app_table[1].valid = 1;
+ bp->dcbx_config_params.admin_priority_app_table[2].valid = 0;
+ bp->dcbx_config_params.admin_priority_app_table[3].valid = 0;
+ bp->dcbx_config_params.admin_priority_app_table[0].priority = 3;
+ bp->dcbx_config_params.admin_priority_app_table[1].priority = 0;
+ bp->dcbx_config_params.admin_priority_app_table[2].priority = 0;
+ bp->dcbx_config_params.admin_priority_app_table[3].priority = 0;
+ bp->dcbx_config_params.admin_priority_app_table[0].traffic_type = 0;
+ bp->dcbx_config_params.admin_priority_app_table[1].traffic_type = 1;
+ bp->dcbx_config_params.admin_priority_app_table[2].traffic_type = 0;
+ bp->dcbx_config_params.admin_priority_app_table[3].traffic_type = 0;
+ bp->dcbx_config_params.admin_priority_app_table[0].app_id = 0x8906;
+ bp->dcbx_config_params.admin_priority_app_table[1].app_id = 3260;
+ bp->dcbx_config_params.admin_priority_app_table[2].app_id = 0;
+ bp->dcbx_config_params.admin_priority_app_table[3].app_id = 0;
+ bp->dcbx_config_params.admin_default_priority =
+ bp->dcbx_config_params.admin_priority_app_table[1].priority;
+}
+
+void bnx2x_dcbx_init(struct bnx2x *bp)
+{
+ u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE;
+
+ if (bp->dcbx_enabled <= 0)
+ return;
+
+ /* validate:
+ * chip of good for dcbx version,
+ * dcb is wanted
+ * the function is pmf
+ * shmem2 contains DCBX support fields
+ */
+ DP(NETIF_MSG_LINK, "dcb_state %d bp->port.pmf %d\n",
+ bp->dcb_state, bp->port.pmf);
+
+ if (bp->dcb_state == BNX2X_DCB_STATE_ON && bp->port.pmf &&
+ SHMEM2_HAS(bp, dcbx_lldp_params_offset)) {
+ dcbx_lldp_params_offset =
+ SHMEM2_RD(bp, dcbx_lldp_params_offset);
+
+ DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n",
+ dcbx_lldp_params_offset);
+
+ if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
+ bnx2x_dcbx_lldp_updated_params(bp,
+ dcbx_lldp_params_offset);
+
+ bnx2x_dcbx_admin_mib_updated_params(bp,
+ dcbx_lldp_params_offset);
+
+ /* set default configuration BC has */
+ bnx2x_dcbx_set_params(bp,
+ BNX2X_DCBX_STATE_NEG_RECEIVED);
+
+ bnx2x_fw_command(bp,
+ DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0);
+ }
+ }
+}
+
+void bnx2x_dcb_init_intmem_pfc(struct bnx2x *bp)
+{
+ struct priority_cos pricos[MAX_PFC_TRAFFIC_TYPES];
+ u32 i = 0, addr;
+ memset(pricos, 0, sizeof(pricos));
+ /* Default initialization */
+ for (i = 0; i < MAX_PFC_TRAFFIC_TYPES; i++)
+ pricos[i].priority = LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED;
+
+ /* Store per port struct to internal memory */
+ addr = BAR_XSTRORM_INTMEM +
+ XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) +
+ offsetof(struct cmng_struct_per_port,
+ traffic_type_to_priority_cos);
+ __storm_memset_struct(bp, addr, sizeof(pricos), (u32 *)pricos);
+
+
+ /* LLFC disabled.*/
+ REG_WR8(bp , BAR_XSTRORM_INTMEM +
+ XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) +
+ offsetof(struct cmng_struct_per_port, llfc_mode),
+ LLFC_MODE_NONE);
+
+ /* DCBX disabled.*/
+ REG_WR8(bp , BAR_XSTRORM_INTMEM +
+ XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) +
+ offsetof(struct cmng_struct_per_port, dcb_enabled),
+ DCB_DISABLED);
+}
+
+static void
+bnx2x_dcbx_print_cos_params(struct bnx2x *bp,
+ struct flow_control_configuration *pfc_fw_cfg)
+{
+ u8 pri = 0;
+ u8 cos = 0;
+
+ DP(NETIF_MSG_LINK,
+ "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version);
+ DP(NETIF_MSG_LINK,
+ "pdev->params.dcbx_port_params.pfc."
+ "priority_non_pauseable_mask %x\n",
+ bp->dcbx_port_params.pfc.priority_non_pauseable_mask);
+
+ for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) {
+ DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
+ "cos_params[%d].pri_bitmask %x\n", cos,
+ bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask);
+
+ DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
+ "cos_params[%d].bw_tbl %x\n", cos,
+ bp->dcbx_port_params.ets.cos_params[cos].bw_tbl);
+
+ DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
+ "cos_params[%d].strict %x\n", cos,
+ bp->dcbx_port_params.ets.cos_params[cos].strict);
+
+ DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
+ "cos_params[%d].pauseable %x\n", cos,
+ bp->dcbx_port_params.ets.cos_params[cos].pauseable);
+ }
+
+ for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
+ DP(NETIF_MSG_LINK,
+ "pfc_fw_cfg->traffic_type_to_priority_cos[%d]."
+ "priority %x\n", pri,
+ pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority);
+
+ DP(NETIF_MSG_LINK,
+ "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n",
+ pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos);
+ }
+}
+
+/* fills help_data according to pg_info */
+static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
+ u32 *pg_pri_orginal_spread,
+ struct pg_help_data *help_data)
+{
+ bool pg_found = false;
+ u32 i, traf_type, add_traf_type, add_pg;
+ u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+ struct pg_entry_help_data *data = help_data->data; /*shotcut*/
+
+ /* Set to invalid */
+ for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
+ data[i].pg = DCBX_ILLEGAL_PG;
+
+ for (add_traf_type = 0;
+ add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) {
+ pg_found = false;
+ if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) {
+ add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]];
+ for (traf_type = 0;
+ traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX;
+ traf_type++) {
+ if (data[traf_type].pg == add_pg) {
+ if (!(data[traf_type].pg_priority &
+ (1 << ttp[add_traf_type])))
+ data[traf_type].
+ num_of_dif_pri++;
+ data[traf_type].pg_priority |=
+ (1 << ttp[add_traf_type]);
+ pg_found = true;
+ break;
+ }
+ }
+ if (false == pg_found) {
+ data[help_data->num_of_pg].pg = add_pg;
+ data[help_data->num_of_pg].pg_priority =
+ (1 << ttp[add_traf_type]);
+ data[help_data->num_of_pg].num_of_dif_pri = 1;
+ help_data->num_of_pg++;
+ }
+ }
+ DP(NETIF_MSG_LINK,
+ "add_traf_type %d pg_found %s num_of_pg %d\n",
+ add_traf_type, (false == pg_found) ? "NO" : "YES",
+ help_data->num_of_pg);
+ }
+}
+
+
+/*******************************************************************************
+ * Description: single priority group
+ *
+ * Return:
+ ******************************************************************************/
+static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,
+ struct cos_help_data *cos_data,
+ u32 pri_join_mask)
+{
+ /* Only one priority than only one COS */
+ cos_data->data[0].pausable =
+ IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
+ cos_data->data[0].pri_join_mask = pri_join_mask;
+ cos_data->data[0].cos_bw = 100;
+ cos_data->num_of_cos = 1;
+}
+
+/*******************************************************************************
+ * Description: updating the cos bw
+ *
+ * Return:
+ ******************************************************************************/
+static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,
+ struct cos_entry_help_data *data,
+ u8 pg_bw)
+{
+ if (data->cos_bw == DCBX_INVALID_COS_BW)
+ data->cos_bw = pg_bw;
+ else
+ data->cos_bw += pg_bw;
+}
+
+/*******************************************************************************
+ * Description: single priority group
+ *
+ * Return:
+ ******************************************************************************/
+static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
+ struct cos_help_data *cos_data,
+ u32 *pg_pri_orginal_spread,
+ struct dcbx_ets_feature *ets)
+{
+ u32 pri_tested = 0;
+ u8 i = 0;
+ u8 entry = 0;
+ u8 pg_entry = 0;
+ u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
+
+ cos_data->data[0].pausable = true;
+ cos_data->data[1].pausable = false;
+ cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
+
+ for (i = 0 ; i < num_of_pri ; i++) {
+ pri_tested = 1 << bp->dcbx_port_params.
+ app.traffic_type_priority[i];
+
+ if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) {
+ cos_data->data[1].pri_join_mask |= pri_tested;
+ entry = 1;
+ } else {
+ cos_data->data[0].pri_join_mask |= pri_tested;
+ entry = 0;
+ }
+ pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params.
+ app.traffic_type_priority[i]];
+ /* There can be only one strict pg */
+ if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES)
+ bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry],
+ DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry));
+ else
+ /* If we join a group and one is strict
+ * than the bw rulls */
+ cos_data->data[entry].strict =
+ BNX2X_DCBX_COS_HIGH_STRICT;
+ }
+ if ((0 == cos_data->data[0].pri_join_mask) &&
+ (0 == cos_data->data[1].pri_join_mask))
+ BNX2X_ERR("dcbx error: Both groups must have priorities\n");
+}
+
+
+#ifndef POWER_OF_2
+#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))
+#endif
+
+static void bxn2x_dcbx_single_pg_to_cos_params(struct bnx2x *bp,
+ struct pg_help_data *pg_help_data,
+ struct cos_help_data *cos_data,
+ u32 pri_join_mask,
+ u8 num_of_dif_pri)
+{
+ u8 i = 0;
+ u32 pri_tested = 0;
+ u32 pri_mask_without_pri = 0;
+ u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+ /*debug*/
+ if (num_of_dif_pri == 1) {
+ bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask);
+ return;
+ }
+ /* single priority group */
+ if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
+ /* If there are both pauseable and non-pauseable priorities,
+ * the pauseable priorities go to the first queue and
+ * the non-pauseable priorities go to the second queue.
+ */
+ if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
+ /* Pauseable */
+ cos_data->data[0].pausable = true;
+ /* Non pauseable.*/
+ cos_data->data[1].pausable = false;
+
+ if (2 == num_of_dif_pri) {
+ cos_data->data[0].cos_bw = 50;
+ cos_data->data[1].cos_bw = 50;
+ }
+
+ if (3 == num_of_dif_pri) {
+ if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp,
+ pri_join_mask))) {
+ cos_data->data[0].cos_bw = 33;
+ cos_data->data[1].cos_bw = 67;
+ } else {
+ cos_data->data[0].cos_bw = 67;
+ cos_data->data[1].cos_bw = 33;
+ }
+ }
+
+ } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) {
+ /* If there are only pauseable priorities,
+ * then one/two priorities go to the first queue
+ * and one priority goes to the second queue.
+ */
+ if (2 == num_of_dif_pri) {
+ cos_data->data[0].cos_bw = 50;
+ cos_data->data[1].cos_bw = 50;
+ } else {
+ cos_data->data[0].cos_bw = 67;
+ cos_data->data[1].cos_bw = 33;
+ }
+ cos_data->data[1].pausable = true;
+ cos_data->data[0].pausable = true;
+ /* All priorities except FCOE */
+ cos_data->data[0].pri_join_mask = (pri_join_mask &
+ ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE])));
+ /* Only FCOE priority.*/
+ cos_data->data[1].pri_join_mask =
+ (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]);
+ } else
+ /* If there are only non-pauseable priorities,
+ * they will all go to the same queue.
+ */
+ bnx2x_dcbx_ets_disabled_entry_data(bp,
+ cos_data, pri_join_mask);
+ } else {
+ /* priority group which is not BW limited (PG#15):*/
+ if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
+ /* If there are both pauseable and non-pauseable
+ * priorities, the pauseable priorities go to the first
+ * queue and the non-pauseable priorities
+ * go to the second queue.
+ */
+ if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) >
+ DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) {
+ cos_data->data[0].strict =
+ BNX2X_DCBX_COS_HIGH_STRICT;
+ cos_data->data[1].strict =
+ BNX2X_DCBX_COS_LOW_STRICT;
+ } else {
+ cos_data->data[0].strict =
+ BNX2X_DCBX_COS_LOW_STRICT;
+ cos_data->data[1].strict =
+ BNX2X_DCBX_COS_HIGH_STRICT;
+ }
+ /* Pauseable */
+ cos_data->data[0].pausable = true;
+ /* Non pause-able.*/
+ cos_data->data[1].pausable = false;
+ } else {
+ /* If there are only pauseable priorities or
+ * only non-pauseable,* the lower priorities go
+ * to the first queue and the higherpriorities go
+ * to the second queue.
+ */
+ cos_data->data[0].pausable =
+ cos_data->data[1].pausable =
+ IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
+
+ for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) {
+ pri_tested = 1 << bp->dcbx_port_params.
+ app.traffic_type_priority[i];
+ /* Remove priority tested */
+ pri_mask_without_pri =
+ (pri_join_mask & ((u8)(~pri_tested)));
+ if (pri_mask_without_pri < pri_tested)
+ break;
+ }
+
+ if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX)
+ BNX2X_ERR("Invalid value for pri_join_mask -"
+ " could not find a priority\n");
+
+ cos_data->data[0].pri_join_mask = pri_mask_without_pri;
+ cos_data->data[1].pri_join_mask = pri_tested;
+ /* Both queues are strict priority,
+ * and that with the highest priority
+ * gets the highest strict priority in the arbiter.
+ */
+ cos_data->data[0].strict = BNX2X_DCBX_COS_LOW_STRICT;
+ cos_data->data[1].strict = BNX2X_DCBX_COS_HIGH_STRICT;
+ }
+ }
+}
+
+static void bnx2x_dcbx_two_pg_to_cos_params(
+ struct bnx2x *bp,
+ struct pg_help_data *pg_help_data,
+ struct dcbx_ets_feature *ets,
+ struct cos_help_data *cos_data,
+ u32 *pg_pri_orginal_spread,
+ u32 pri_join_mask,
+ u8 num_of_dif_pri)
+{
+ u8 i = 0;
+ u8 pg[E2_NUM_OF_COS] = {0};
+
+ /* If there are both pauseable and non-pauseable priorities,
+ * the pauseable priorities go to the first queue and
+ * the non-pauseable priorities go to the second queue.
+ */
+ if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
+ if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp,
+ pg_help_data->data[0].pg_priority) ||
+ IS_DCBX_PFC_PRI_MIX_PAUSE(bp,
+ pg_help_data->data[1].pg_priority)) {
+ /* If one PG contains both pauseable and
+ * non-pauseable priorities then ETS is disabled.
+ */
+ bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data,
+ pg_pri_orginal_spread, ets);
+ bp->dcbx_port_params.ets.enabled = false;
+ return;
+ }
+
+ /* Pauseable */
+ cos_data->data[0].pausable = true;
+ /* Non pauseable. */
+ cos_data->data[1].pausable = false;
+ if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp,
+ pg_help_data->data[0].pg_priority)) {
+ /* 0 is pauseable */
+ cos_data->data[0].pri_join_mask =
+ pg_help_data->data[0].pg_priority;
+ pg[0] = pg_help_data->data[0].pg;
+ cos_data->data[1].pri_join_mask =
+ pg_help_data->data[1].pg_priority;
+ pg[1] = pg_help_data->data[1].pg;
+ } else {/* 1 is pauseable */
+ cos_data->data[0].pri_join_mask =
+ pg_help_data->data[1].pg_priority;
+ pg[0] = pg_help_data->data[1].pg;
+ cos_data->data[1].pri_join_mask =
+ pg_help_data->data[0].pg_priority;
+ pg[1] = pg_help_data->data[0].pg;
+ }
+ } else {
+ /* If there are only pauseable priorities or
+ * only non-pauseable, each PG goes to a queue.
+ */
+ cos_data->data[0].pausable = cos_data->data[1].pausable =
+ IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
+ cos_data->data[0].pri_join_mask =
+ pg_help_data->data[0].pg_priority;
+ pg[0] = pg_help_data->data[0].pg;
+ cos_data->data[1].pri_join_mask =
+ pg_help_data->data[1].pg_priority;
+ pg[1] = pg_help_data->data[1].pg;
+ }
+
+ /* There can be only one strict pg */
+ for (i = 0 ; i < E2_NUM_OF_COS; i++) {
+ if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES)
+ cos_data->data[i].cos_bw =
+ DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]);
+ else
+ cos_data->data[i].strict = BNX2X_DCBX_COS_HIGH_STRICT;
+ }
+}
+
+/*******************************************************************************
+ * Description: Still
+ *
+ * Return:
+ ******************************************************************************/
+static void bnx2x_dcbx_three_pg_to_cos_params(
+ struct bnx2x *bp,
+ struct pg_help_data *pg_help_data,
+ struct dcbx_ets_feature *ets,
+ struct cos_help_data *cos_data,
+ u32 *pg_pri_orginal_spread,
+ u32 pri_join_mask,
+ u8 num_of_dif_pri)
+{
+ u8 i = 0;
+ u32 pri_tested = 0;
+ u8 entry = 0;
+ u8 pg_entry = 0;
+ bool b_found_strict = false;
+ u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
+
+ cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
+ /* If there are both pauseable and non-pauseable priorities,
+ * the pauseable priorities go to the first queue and the
+ * non-pauseable priorities go to the second queue.
+ */
+ if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask))
+ bnx2x_dcbx_separate_pauseable_from_non(bp,
+ cos_data, pg_pri_orginal_spread, ets);
+ else {
+ /* If two BW-limited PG-s were combined to one queue,
+ * the BW is their sum.
+ *
+ * If there are only pauseable priorities or only non-pauseable,
+ * and there are both BW-limited and non-BW-limited PG-s,
+ * the BW-limited PG/s go to one queue and the non-BW-limited
+ * PG/s go to the second queue.
+ *
+ * If there are only pauseable priorities or only non-pauseable
+ * and all are BW limited, then two priorities go to the first
+ * queue and one priority goes to the second queue.
+ *
+ * We will join this two cases:
+ * if one is BW limited it will go to the secoend queue
+ * otherwise the last priority will get it
+ */
+
+ cos_data->data[0].pausable = cos_data->data[1].pausable =
+ IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
+
+ for (i = 0 ; i < num_of_pri; i++) {
+ pri_tested = 1 << bp->dcbx_port_params.
+ app.traffic_type_priority[i];
+ pg_entry = (u8)pg_pri_orginal_spread[bp->
+ dcbx_port_params.app.traffic_type_priority[i]];
+
+ if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) {
+ entry = 0;
+
+ if (i == (num_of_pri-1) &&
+ false == b_found_strict)
+ /* last entry will be handled separately
+ * If no priority is strict than last
+ * enty goes to last queue.*/
+ entry = 1;
+ cos_data->data[entry].pri_join_mask |=
+ pri_tested;
+ bnx2x_dcbx_add_to_cos_bw(bp,
+ &cos_data->data[entry],
+ DCBX_PG_BW_GET(ets->pg_bw_tbl,
+ pg_entry));
+ } else {
+ b_found_strict = true;
+ cos_data->data[1].pri_join_mask |= pri_tested;
+ /* If we join a group and one is strict
+ * than the bw rulls */
+ cos_data->data[1].strict =
+ BNX2X_DCBX_COS_HIGH_STRICT;
+ }
+ }
+ }
+}
+
+
+static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
+ struct pg_help_data *help_data,
+ struct dcbx_ets_feature *ets,
+ u32 *pg_pri_orginal_spread)
+{
+ struct cos_help_data cos_data ;
+ u8 i = 0;
+ u32 pri_join_mask = 0;
+ u8 num_of_dif_pri = 0;
+
+ memset(&cos_data, 0, sizeof(cos_data));
+ /* Validate the pg value */
+ for (i = 0; i < help_data->num_of_pg ; i++) {
+ if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&
+ DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)
+ BNX2X_ERR("Invalid pg[%d] data %x\n", i,
+ help_data->data[i].pg);
+ pri_join_mask |= help_data->data[i].pg_priority;
+ num_of_dif_pri += help_data->data[i].num_of_dif_pri;
+ }
+
+ /* default settings */
+ cos_data.num_of_cos = 2;
+ for (i = 0; i < E2_NUM_OF_COS ; i++) {
+ cos_data.data[i].pri_join_mask = pri_join_mask;
+ cos_data.data[i].pausable = false;
+ cos_data.data[i].strict = BNX2X_DCBX_COS_NOT_STRICT;
+ cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;
+ }
+
+ switch (help_data->num_of_pg) {
+ case 1:
+
+ bxn2x_dcbx_single_pg_to_cos_params(
+ bp,
+ help_data,
+ &cos_data,
+ pri_join_mask,
+ num_of_dif_pri);
+ break;
+ case 2:
+ bnx2x_dcbx_two_pg_to_cos_params(
+ bp,
+ help_data,
+ ets,
+ &cos_data,
+ pg_pri_orginal_spread,
+ pri_join_mask,
+ num_of_dif_pri);
+ break;
+
+ case 3:
+ bnx2x_dcbx_three_pg_to_cos_params(
+ bp,
+ help_data,
+ ets,
+ &cos_data,
+ pg_pri_orginal_spread,
+ pri_join_mask,
+ num_of_dif_pri);
+
+ break;
+ default:
+ BNX2X_ERR("Wrong pg_help_data.num_of_pg\n");
+ bnx2x_dcbx_ets_disabled_entry_data(bp,
+ &cos_data, pri_join_mask);
+ }
+
+ for (i = 0; i < cos_data.num_of_cos ; i++) {
+ struct bnx2x_dcbx_cos_params *params =
+ &bp->dcbx_port_params.ets.cos_params[i];
+
+ params->pauseable = cos_data.data[i].pausable;
+ params->strict = cos_data.data[i].strict;
+ params->bw_tbl = cos_data.data[i].cos_bw;
+ if (params->pauseable) {
+ params->pri_bitmask =
+ DCBX_PFC_PRI_GET_PAUSE(bp,
+ cos_data.data[i].pri_join_mask);
+ DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n",
+ i, cos_data.data[i].pri_join_mask);
+ } else {
+ params->pri_bitmask =
+ DCBX_PFC_PRI_GET_NON_PAUSE(bp,
+ cos_data.data[i].pri_join_mask);
+ DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask "
+ "0x%x\n",
+ i, cos_data.data[i].pri_join_mask);
+ }
+ }
+
+ bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ;
+}
+
+static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
+ u32 *set_configuration_ets_pg,
+ u32 *pri_pg_tbl)
+{
+ int i;
+
+ for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
+ set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i);
+
+ DP(NETIF_MSG_LINK, "set_configuration_ets_pg[%d] = 0x%x\n",
+ i, set_configuration_ets_pg[i]);
+ }
+}
+
+/*******************************************************************************
+ * Description: Fill pfc_config struct that will be sent in DCBX start ramrod
+ *
+ * Return:
+ ******************************************************************************/
+static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp)
+{
+ struct flow_control_configuration *pfc_fw_cfg = NULL;
+ u16 pri_bit = 0;
+ u8 cos = 0, pri = 0;
+ struct priority_cos *tt2cos;
+ u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+
+ pfc_fw_cfg = (struct flow_control_configuration *)
+ bnx2x_sp(bp, pfc_config);
+ memset(pfc_fw_cfg, 0, sizeof(struct flow_control_configuration));
+
+ /*shortcut*/
+ tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos;
+
+ /* Fw version should be incremented each update */
+ pfc_fw_cfg->dcb_version = ++bp->dcb_version;
+ pfc_fw_cfg->dcb_enabled = DCB_ENABLED;
+
+ /* Default initialization */
+ for (pri = 0; pri < MAX_PFC_TRAFFIC_TYPES ; pri++) {
+ tt2cos[pri].priority = LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED;
+ tt2cos[pri].cos = 0;
+ }
+
+ /* Fill priority parameters */
+ for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
+ tt2cos[pri].priority = ttp[pri];
+ pri_bit = 1 << tt2cos[pri].priority;
+
+ /* Fill COS parameters based on COS calculated to
+ * make it more generally for future use */
+ for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++)
+ if (bp->dcbx_port_params.ets.cos_params[cos].
+ pri_bitmask & pri_bit)
+ tt2cos[pri].cos = cos;
+ }
+ bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg);
+}
+/* DCB netlink */
+#ifdef BCM_DCB
+#include <linux/dcbnl.h>
+
+#define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \
+ DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC)
+
+static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp)
+{
+ /* validate dcbnl call that may change HW state:
+ * DCB is on and DCBX mode was SUCCESSFULLY set by the user.
+ */
+ return bp->dcb_state && bp->dcbx_mode_uset;
+}
+
+static u8 bnx2x_dcbnl_get_state(struct net_device *netdev)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "state = %d\n", bp->dcb_state);
+ return bp->dcb_state;
+}
+
+static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off");
+
+ bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
+ return 0;
+}
+
+static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev,
+ u8 *perm_addr)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "GET-PERM-ADDR\n");
+
+ /* first the HW mac address */
+ memcpy(perm_addr, netdev->dev_addr, netdev->addr_len);
+
+#ifdef BCM_CNIC
+ /* second SAN address */
+ memcpy(perm_addr+netdev->addr_len, bp->fip_mac, netdev->addr_len);
+#endif
+}
+
+static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio,
+ u8 prio_type, u8 pgid, u8 bw_pct,
+ u8 up_map)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+
+ DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, pgid);
+ if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
+ return;
+
+ /**
+ * bw_pct ingnored - band-width percentage devision between user
+ * priorities within the same group is not
+ * standard and hence not supported
+ *
+ * prio_type igonred - priority levels within the same group are not
+ * standard and hence are not supported. According
+ * to the standard pgid 15 is dedicated to strict
+ * prioirty traffic (on the port level).
+ *
+ * up_map ignored
+ */
+
+ bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid;
+ bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
+}
+
+static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev,
+ int pgid, u8 bw_pct)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "pgid[%d] = %d\n", pgid, bw_pct);
+
+ if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
+ return;
+
+ bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct;
+ bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
+}
+
+static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio,
+ u8 prio_type, u8 pgid, u8 bw_pct,
+ u8 up_map)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n");
+}
+
+static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev,
+ int pgid, u8 bw_pct)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n");
+}
+
+static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio,
+ u8 *prio_type, u8 *pgid, u8 *bw_pct,
+ u8 *up_map)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "prio = %d\n", prio);
+
+ /**
+ * bw_pct ingnored - band-width percentage devision between user
+ * priorities within the same group is not
+ * standard and hence not supported
+ *
+ * prio_type igonred - priority levels within the same group are not
+ * standard and hence are not supported. According
+ * to the standard pgid 15 is dedicated to strict
+ * prioirty traffic (on the port level).
+ *
+ * up_map ignored
+ */
+ *up_map = *bw_pct = *prio_type = *pgid = 0;
+
+ if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
+ return;
+
+ *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio);
+}
+
+static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev,
+ int pgid, u8 *bw_pct)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "pgid = %d\n", pgid);
+
+ *bw_pct = 0;
+
+ if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
+ return;
+
+ *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid);
+}
+
+static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio,
+ u8 *prio_type, u8 *pgid, u8 *bw_pct,
+ u8 *up_map)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n");
+
+ *prio_type = *pgid = *bw_pct = *up_map = 0;
+}
+
+static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev,
+ int pgid, u8 *bw_pct)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n");
+
+ *bw_pct = 0;
+}
+
+static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
+ u8 setting)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, setting);
+
+ if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
+ return;
+
+ bp->dcbx_config_params.admin_pfc_bitmap |= ((setting ? 1 : 0) << prio);
+
+ if (setting)
+ bp->dcbx_config_params.admin_pfc_tx_enable = 1;
+}
+
+static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
+ u8 *setting)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "prio = %d\n", prio);
+
+ *setting = 0;
+
+ if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES)
+ return;
+
+ *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1;
+}
+
+static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ int rc = 0;
+
+ DP(NETIF_MSG_LINK, "SET-ALL\n");
+
+ if (!bnx2x_dcbnl_set_valid(bp))
+ return 1;
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ netdev_err(bp->dev, "Handling parity error recovery. "
+ "Try again later\n");
+ return 1;
+ }
+ if (netif_running(bp->dev)) {
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+ }
+ DP(NETIF_MSG_LINK, "set_dcbx_params done (%d)\n", rc);
+ if (rc)
+ return 1;
+
+ return 0;
+}
+
+static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u8 rval = 0;
+
+ if (bp->dcb_state) {
+ switch (capid) {
+ case DCB_CAP_ATTR_PG:
+ *cap = true;
+ break;
+ case DCB_CAP_ATTR_PFC:
+ *cap = true;
+ break;
+ case DCB_CAP_ATTR_UP2TC:
+ *cap = false;
+ break;
+ case DCB_CAP_ATTR_PG_TCS:
+ *cap = 0x80; /* 8 priorities for PGs */
+ break;
+ case DCB_CAP_ATTR_PFC_TCS:
+ *cap = 0x80; /* 8 priorities for PFC */
+ break;
+ case DCB_CAP_ATTR_GSP:
+ *cap = true;
+ break;
+ case DCB_CAP_ATTR_BCN:
+ *cap = false;
+ break;
+ case DCB_CAP_ATTR_DCBX:
+ *cap = BNX2X_DCBX_CAPS;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ } else
+ rval = -EINVAL;
+
+ DP(NETIF_MSG_LINK, "capid %d:%x\n", capid, *cap);
+ return rval;
+}
+
+static u8 bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u8 rval = 0;
+
+ DP(NETIF_MSG_LINK, "tcid %d\n", tcid);
+
+ if (bp->dcb_state) {
+ switch (tcid) {
+ case DCB_NUMTCS_ATTR_PG:
+ *num = E2_NUM_OF_COS;
+ break;
+ case DCB_NUMTCS_ATTR_PFC:
+ *num = E2_NUM_OF_COS;
+ break;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ } else
+ rval = -EINVAL;
+
+ return rval;
+}
+
+static u8 bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "num tcs = %d; Not supported\n", num);
+ return -EINVAL;
+}
+
+static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "state = %d\n", bp->dcbx_local_feat.pfc.enabled);
+
+ if (!bp->dcb_state)
+ return 0;
+
+ return bp->dcbx_local_feat.pfc.enabled;
+}
+
+static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off");
+
+ if (!bnx2x_dcbnl_set_valid(bp))
+ return;
+
+ bp->dcbx_config_params.admin_pfc_tx_enable =
+ bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0);
+}
+
+static bool bnx2x_app_is_equal(struct dcbx_app_priority_entry *app_ent,
+ u8 idtype, u16 idval)
+{
+ if (!(app_ent->appBitfield & DCBX_APP_ENTRY_VALID))
+ return false;
+
+ switch (idtype) {
+ case DCB_APP_IDTYPE_ETHTYPE:
+ if ((app_ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) !=
+ DCBX_APP_SF_ETH_TYPE)
+ return false;
+ break;
+ case DCB_APP_IDTYPE_PORTNUM:
+ if ((app_ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) !=
+ DCBX_APP_SF_PORT)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ if (app_ent->app_id != idval)
+ return false;
+
+ return true;
+}
+
+static void bnx2x_admin_app_set_ent(
+ struct bnx2x_admin_priority_app_table *app_ent,
+ u8 idtype, u16 idval, u8 up)
+{
+ app_ent->valid = 1;
+
+ switch (idtype) {
+ case DCB_APP_IDTYPE_ETHTYPE:
+ app_ent->traffic_type = TRAFFIC_TYPE_ETH;
+ break;
+ case DCB_APP_IDTYPE_PORTNUM:
+ app_ent->traffic_type = TRAFFIC_TYPE_PORT;
+ break;
+ default:
+ break; /* never gets here */
+ }
+ app_ent->app_id = idval;
+ app_ent->priority = up;
+}
+
+static bool bnx2x_admin_app_is_equal(
+ struct bnx2x_admin_priority_app_table *app_ent,
+ u8 idtype, u16 idval)
+{
+ if (!app_ent->valid)
+ return false;
+
+ switch (idtype) {
+ case DCB_APP_IDTYPE_ETHTYPE:
+ if (app_ent->traffic_type != TRAFFIC_TYPE_ETH)
+ return false;
+ break;
+ case DCB_APP_IDTYPE_PORTNUM:
+ if (app_ent->traffic_type != TRAFFIC_TYPE_PORT)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ if (app_ent->app_id != idval)
+ return false;
+
+ return true;
+}
+
+static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
+{
+ int i, ff;
+
+ /* iterate over the app entries looking for idtype and idval */
+ for (i = 0, ff = -1; i < 4; i++) {
+ struct bnx2x_admin_priority_app_table *app_ent =
+ &bp->dcbx_config_params.admin_priority_app_table[i];
+ if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))
+ break;
+
+ if (ff < 0 && !app_ent->valid)
+ ff = i;
+ }
+ if (i < 4)
+ /* if found overwrite up */
+ bp->dcbx_config_params.
+ admin_priority_app_table[i].priority = up;
+ else if (ff >= 0)
+ /* not found use first-free */
+ bnx2x_admin_app_set_ent(
+ &bp->dcbx_config_params.admin_priority_app_table[ff],
+ idtype, idval, up);
+ else
+ /* app table is full */
+ return -EBUSY;
+
+ /* up configured, if not 0 make sure feature is enabled */
+ if (up)
+ bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
+
+ return 0;
+}
+
+static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,
+ u16 idval, u8 up)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+
+ DP(NETIF_MSG_LINK, "app_type %d, app_id %x, prio bitmap %d\n",
+ idtype, idval, up);
+
+ if (!bnx2x_dcbnl_set_valid(bp))
+ return -EINVAL;
+
+ /* verify idtype */
+ switch (idtype) {
+ case DCB_APP_IDTYPE_ETHTYPE:
+ case DCB_APP_IDTYPE_PORTNUM:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return bnx2x_set_admin_app_up(bp, idtype, idval, up);
+}
+
+static u8 bnx2x_dcbnl_get_app_up(struct net_device *netdev, u8 idtype,
+ u16 idval)
+{
+ int i;
+ u8 up = 0;
+
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "app_type %d, app_id 0x%x\n", idtype, idval);
+
+ /* iterate over the app entries looking for idtype and idval */
+ for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++)
+ if (bnx2x_app_is_equal(&bp->dcbx_local_feat.app.app_pri_tbl[i],
+ idtype, idval))
+ break;
+
+ if (i < DCBX_MAX_APP_PROTOCOL)
+ /* if found return up */
+ up = bp->dcbx_local_feat.app.app_pri_tbl[i].pri_bitmap;
+ else
+ DP(NETIF_MSG_LINK, "app not found\n");
+
+ return up;
+}
+
+static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u8 state;
+
+ state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE;
+
+ if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF)
+ state |= DCB_CAP_DCBX_STATIC;
+
+ return state;
+}
+
+static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ DP(NETIF_MSG_LINK, "state = %02x\n", state);
+
+ /* set dcbx mode */
+
+ if ((state & BNX2X_DCBX_CAPS) != state) {
+ BNX2X_ERR("Requested DCBX mode %x is beyond advertised "
+ "capabilities\n", state);
+ return 1;
+ }
+
+ if (bp->dcb_state != BNX2X_DCB_STATE_ON) {
+ BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n");
+ return 1;
+ }
+
+ if (state & DCB_CAP_DCBX_STATIC)
+ bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF;
+ else
+ bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON;
+
+ bp->dcbx_mode_uset = true;
+ return 0;
+}
+
+
+static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
+ u8 *flags)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u8 rval = 0;
+
+ DP(NETIF_MSG_LINK, "featid %d\n", featid);
+
+ if (bp->dcb_state) {
+ *flags = 0;
+ switch (featid) {
+ case DCB_FEATCFG_ATTR_PG:
+ if (bp->dcbx_local_feat.ets.enabled)
+ *flags |= DCB_FEATCFG_ENABLE;
+ if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR)
+ *flags |= DCB_FEATCFG_ERROR;
+ break;
+ case DCB_FEATCFG_ATTR_PFC:
+ if (bp->dcbx_local_feat.pfc.enabled)
+ *flags |= DCB_FEATCFG_ENABLE;
+ if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |
+ DCBX_LOCAL_PFC_MISMATCH))
+ *flags |= DCB_FEATCFG_ERROR;
+ break;
+ case DCB_FEATCFG_ATTR_APP:
+ if (bp->dcbx_local_feat.app.enabled)
+ *flags |= DCB_FEATCFG_ENABLE;
+ if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |
+ DCBX_LOCAL_APP_MISMATCH))
+ *flags |= DCB_FEATCFG_ERROR;
+ break;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ } else
+ rval = -EINVAL;
+
+ return rval;
+}
+
+static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
+ u8 flags)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ u8 rval = 0;
+
+ DP(NETIF_MSG_LINK, "featid = %d flags = %02x\n", featid, flags);
+
+ /* ignore the 'advertise' flag */
+ if (bnx2x_dcbnl_set_valid(bp)) {
+ switch (featid) {
+ case DCB_FEATCFG_ATTR_PG:
+ bp->dcbx_config_params.admin_ets_enable =
+ flags & DCB_FEATCFG_ENABLE ? 1 : 0;
+ bp->dcbx_config_params.admin_ets_willing =
+ flags & DCB_FEATCFG_WILLING ? 1 : 0;
+ break;
+ case DCB_FEATCFG_ATTR_PFC:
+ bp->dcbx_config_params.admin_pfc_enable =
+ flags & DCB_FEATCFG_ENABLE ? 1 : 0;
+ bp->dcbx_config_params.admin_pfc_willing =
+ flags & DCB_FEATCFG_WILLING ? 1 : 0;
+ break;
+ case DCB_FEATCFG_ATTR_APP:
+ /* ignore enable, always enabled */
+ bp->dcbx_config_params.admin_app_priority_willing =
+ flags & DCB_FEATCFG_WILLING ? 1 : 0;
+ break;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ } else
+ rval = -EINVAL;
+
+ return rval;
+}
+
+const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = {
+ .getstate = bnx2x_dcbnl_get_state,
+ .setstate = bnx2x_dcbnl_set_state,
+ .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr,
+ .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx,
+ .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx,
+ .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx,
+ .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx,
+ .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx,
+ .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx,
+ .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx,
+ .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx,
+ .setpfccfg = bnx2x_dcbnl_set_pfc_cfg,
+ .getpfccfg = bnx2x_dcbnl_get_pfc_cfg,
+ .setall = bnx2x_dcbnl_set_all,
+ .getcap = bnx2x_dcbnl_get_cap,
+ .getnumtcs = bnx2x_dcbnl_get_numtcs,
+ .setnumtcs = bnx2x_dcbnl_set_numtcs,
+ .getpfcstate = bnx2x_dcbnl_get_pfc_state,
+ .setpfcstate = bnx2x_dcbnl_set_pfc_state,
+ .getapp = bnx2x_dcbnl_get_app_up,
+ .setapp = bnx2x_dcbnl_set_app_up,
+ .getdcbx = bnx2x_dcbnl_get_dcbx,
+ .setdcbx = bnx2x_dcbnl_set_dcbx,
+ .getfeatcfg = bnx2x_dcbnl_get_featcfg,
+ .setfeatcfg = bnx2x_dcbnl_set_featcfg,
+};
+
+#endif /* BCM_DCB */
diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h
new file mode 100644
index 000000000000..f650f98e4092
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_dcb.h
@@ -0,0 +1,196 @@
+/* bnx2x_dcb.h: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2010 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Dmitry Kravkov
+ *
+ */
+#ifndef BNX2X_DCB_H
+#define BNX2X_DCB_H
+
+#include "bnx2x_hsi.h"
+
+#define LLFC_DRIVER_TRAFFIC_TYPE_MAX 3 /* NW, iSCSI, FCoE */
+struct bnx2x_dcbx_app_params {
+ u32 enabled;
+ u32 traffic_type_priority[LLFC_DRIVER_TRAFFIC_TYPE_MAX];
+};
+
+#define E2_NUM_OF_COS 2
+#define BNX2X_DCBX_COS_NOT_STRICT 0
+#define BNX2X_DCBX_COS_LOW_STRICT 1
+#define BNX2X_DCBX_COS_HIGH_STRICT 2
+
+struct bnx2x_dcbx_cos_params {
+ u32 bw_tbl;
+ u32 pri_bitmask;
+ u8 strict;
+ u8 pauseable;
+};
+
+struct bnx2x_dcbx_pg_params {
+ u32 enabled;
+ u8 num_of_cos; /* valid COS entries */
+ struct bnx2x_dcbx_cos_params cos_params[E2_NUM_OF_COS];
+};
+
+struct bnx2x_dcbx_pfc_params {
+ u32 enabled;
+ u32 priority_non_pauseable_mask;
+};
+
+struct bnx2x_dcbx_port_params {
+ struct bnx2x_dcbx_pfc_params pfc;
+ struct bnx2x_dcbx_pg_params ets;
+ struct bnx2x_dcbx_app_params app;
+};
+
+#define BNX2X_DCBX_CONFIG_INV_VALUE (0xFFFFFFFF)
+#define BNX2X_DCBX_OVERWRITE_SETTINGS_DISABLE 0
+#define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1
+#define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE)
+
+/*******************************************************************************
+ * LLDP protocol configuration parameters.
+ ******************************************************************************/
+struct bnx2x_config_lldp_params {
+ u32 overwrite_settings;
+ u32 msg_tx_hold;
+ u32 msg_fast_tx;
+ u32 tx_credit_max;
+ u32 msg_tx_interval;
+ u32 tx_fast;
+};
+
+struct bnx2x_admin_priority_app_table {
+ u32 valid;
+ u32 priority;
+#define INVALID_TRAFFIC_TYPE_PRIORITY (0xFFFFFFFF)
+ u32 traffic_type;
+#define TRAFFIC_TYPE_ETH 0
+#define TRAFFIC_TYPE_PORT 1
+ u32 app_id;
+};
+
+/*******************************************************************************
+ * DCBX protocol configuration parameters.
+ ******************************************************************************/
+struct bnx2x_config_dcbx_params {
+ u32 overwrite_settings;
+ u32 admin_dcbx_version;
+ u32 admin_ets_enable;
+ u32 admin_pfc_enable;
+ u32 admin_tc_supported_tx_enable;
+ u32 admin_ets_configuration_tx_enable;
+ u32 admin_ets_recommendation_tx_enable;
+ u32 admin_pfc_tx_enable;
+ u32 admin_application_priority_tx_enable;
+ u32 admin_ets_willing;
+ u32 admin_ets_reco_valid;
+ u32 admin_pfc_willing;
+ u32 admin_app_priority_willing;
+ u32 admin_configuration_bw_precentage[8];
+ u32 admin_configuration_ets_pg[8];
+ u32 admin_recommendation_bw_precentage[8];
+ u32 admin_recommendation_ets_pg[8];
+ u32 admin_pfc_bitmap;
+ struct bnx2x_admin_priority_app_table admin_priority_app_table[4];
+ u32 admin_default_priority;
+};
+
+#define GET_FLAGS(flags, bits) ((flags) & (bits))
+#define SET_FLAGS(flags, bits) ((flags) |= (bits))
+#define RESET_FLAGS(flags, bits) ((flags) &= ~(bits))
+
+enum {
+ DCBX_READ_LOCAL_MIB,
+ DCBX_READ_REMOTE_MIB
+};
+
+#define ETH_TYPE_FCOE (0x8906)
+#define TCP_PORT_ISCSI (0xCBC)
+
+#define PFC_VALUE_FRAME_SIZE (512)
+#define PFC_QUANTA_IN_NANOSEC_FROM_SPEED_MEGA(mega_speed) \
+ ((1000 * PFC_VALUE_FRAME_SIZE)/(mega_speed))
+
+#define PFC_BRB1_REG_HIGH_LLFC_LOW_THRESHOLD 130
+#define PFC_BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD 170
+
+
+
+struct cos_entry_help_data {
+ u32 pri_join_mask;
+ u32 cos_bw;
+ u8 strict;
+ bool pausable;
+};
+
+struct cos_help_data {
+ struct cos_entry_help_data data[E2_NUM_OF_COS];
+ u8 num_of_cos;
+};
+
+#define DCBX_ILLEGAL_PG (0xFF)
+#define DCBX_PFC_PRI_MASK (0xFF)
+#define DCBX_STRICT_PRIORITY (15)
+#define DCBX_INVALID_COS_BW (0xFFFFFFFF)
+#define DCBX_PFC_PRI_NON_PAUSE_MASK(bp) \
+ ((bp)->dcbx_port_params.pfc.priority_non_pauseable_mask)
+#define DCBX_PFC_PRI_PAUSE_MASK(bp) \
+ ((u8)~DCBX_PFC_PRI_NON_PAUSE_MASK(bp))
+#define DCBX_PFC_PRI_GET_PAUSE(bp, pg_pri) \
+ ((pg_pri) & (DCBX_PFC_PRI_PAUSE_MASK(bp)))
+#define DCBX_PFC_PRI_GET_NON_PAUSE(bp, pg_pri) \
+ (DCBX_PFC_PRI_NON_PAUSE_MASK(bp) & (pg_pri))
+#define IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pg_pri) \
+ (pg_pri == DCBX_PFC_PRI_GET_PAUSE((bp), (pg_pri)))
+#define IS_DCBX_PFC_PRI_ONLY_NON_PAUSE(bp, pg_pri)\
+ ((pg_pri) == DCBX_PFC_PRI_GET_NON_PAUSE((bp), (pg_pri)))
+#define IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pg_pri) \
+ (!(IS_DCBX_PFC_PRI_ONLY_NON_PAUSE((bp), (pg_pri)) || \
+ IS_DCBX_PFC_PRI_ONLY_PAUSE((bp), (pg_pri))))
+
+
+struct pg_entry_help_data {
+ u8 num_of_dif_pri;
+ u8 pg;
+ u32 pg_priority;
+};
+
+struct pg_help_data {
+ struct pg_entry_help_data data[LLFC_DRIVER_TRAFFIC_TYPE_MAX];
+ u8 num_of_pg;
+};
+
+/* forward DCB/PFC related declarations */
+struct bnx2x;
+void bnx2x_dcb_init_intmem_pfc(struct bnx2x *bp);
+void bnx2x_dcbx_update(struct work_struct *work);
+void bnx2x_dcbx_init_params(struct bnx2x *bp);
+void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled);
+
+enum {
+ BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1,
+ BNX2X_DCBX_STATE_TX_PAUSED = 0x2,
+ BNX2X_DCBX_STATE_TX_RELEASED = 0x4
+};
+void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state);
+
+/* DCB netlink */
+#ifdef BCM_DCB
+extern const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops;
+#endif /* BCM_DCB */
+
+#endif /* BNX2X_DCB_H */
diff --git a/drivers/net/bnx2x/bnx2x_dump.h b/drivers/net/bnx2x/bnx2x_dump.h
index dc18c25ca9e5..fb3ff7c4d7ca 100644
--- a/drivers/net/bnx2x/bnx2x_dump.h
+++ b/drivers/net/bnx2x/bnx2x_dump.h
@@ -1,10 +1,16 @@
/* bnx2x_dump.h: Broadcom Everest network driver.
*
- * Copyright (c) 2009 Broadcom Corporation
+ * Copyright (c) 2011 Broadcom Corporation
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
*/
@@ -17,53 +23,53 @@
#define BNX2X_DUMP_H
-struct dump_sign {
- u32 time_stamp;
- u32 diag_ver;
- u32 grc_dump_ver;
-};
-#define TSTORM_WAITP_ADDR 0x1b8a80
-#define CSTORM_WAITP_ADDR 0x238a80
-#define XSTORM_WAITP_ADDR 0x2b8a80
-#define USTORM_WAITP_ADDR 0x338a80
-#define TSTORM_CAM_MODE 0x1b1440
+/*definitions */
+#define XSTORM_WAITP_ADDR 0x2b8a80
+#define TSTORM_WAITP_ADDR 0x1b8a80
+#define USTORM_WAITP_ADDR 0x338a80
+#define CSTORM_WAITP_ADDR 0x238a80
+#define TSTORM_CAM_MODE 0x1B1440
-#define RI_E1 0x1
-#define RI_E1H 0x2
+#define MAX_TIMER_PENDING 200
+#define TIMER_SCAN_DONT_CARE 0xFF
+#define RI_E1 0x1
+#define RI_E1H 0x2
#define RI_E2 0x4
-#define RI_ONLINE 0x100
+#define RI_ONLINE 0x100
#define RI_PATH0_DUMP 0x200
#define RI_PATH1_DUMP 0x400
-#define RI_E1_OFFLINE (RI_E1)
-#define RI_E1_ONLINE (RI_E1 | RI_ONLINE)
-#define RI_E1H_OFFLINE (RI_E1H)
-#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE)
-#define RI_E2_OFFLINE (RI_E2)
-#define RI_E2_ONLINE (RI_E2 | RI_ONLINE)
-#define RI_E1E1H_OFFLINE (RI_E1 | RI_E1H)
-#define RI_E1E1H_ONLINE (RI_E1 | RI_E1H | RI_ONLINE)
-#define RI_E1HE2_OFFLINE (RI_E2 | RI_E1H)
-#define RI_E1HE2_ONLINE (RI_E2 | RI_E1H | RI_ONLINE)
-#define RI_E1E2_OFFLINE (RI_E2 | RI_E1)
-#define RI_E1E2_ONLINE (RI_E2 | RI_E1 | RI_ONLINE)
-#define RI_ALL_OFFLINE (RI_E1 | RI_E1H | RI_E2)
-#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
-
-#define MAX_TIMER_PENDING 200
-#define TIMER_SCAN_DONT_CARE 0xFF
+#define RI_E1_OFFLINE (RI_E1)
+#define RI_E1_ONLINE (RI_E1 | RI_ONLINE)
+#define RI_E1H_OFFLINE (RI_E1H)
+#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE)
+#define RI_E2_OFFLINE (RI_E2)
+#define RI_E2_ONLINE (RI_E2 | RI_ONLINE)
+#define RI_E1E1H_OFFLINE (RI_E1 | RI_E1H)
+#define RI_E1E1H_ONLINE (RI_E1 | RI_E1H | RI_ONLINE)
+#define RI_E1HE2_OFFLINE (RI_E2 | RI_E1H)
+#define RI_E1HE2_ONLINE (RI_E2 | RI_E1H | RI_ONLINE)
+#define RI_E1E2_OFFLINE (RI_E2 | RI_E1)
+#define RI_E1E2_ONLINE (RI_E2 | RI_E1 | RI_ONLINE)
+#define RI_ALL_OFFLINE (RI_E1 | RI_E1H | RI_E2)
+#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
+struct dump_sign {
+ u32 time_stamp;
+ u32 diag_ver;
+ u32 grc_dump_ver;
+};
struct dump_hdr {
- u32 hdr_size; /* in dwords, excluding this field */
- struct dump_sign dump_sign;
- u32 xstorm_waitp;
- u32 tstorm_waitp;
- u32 ustorm_waitp;
- u32 cstorm_waitp;
- u16 info;
- u8 idle_chk;
- u8 reserved;
+ u32 hdr_size; /* in dwords, excluding this field */
+ struct dump_sign dump_sign;
+ u32 xstorm_waitp;
+ u32 tstorm_waitp;
+ u32 ustorm_waitp;
+ u32 cstorm_waitp;
+ u16 info;
+ u8 idle_chk;
+ u8 reserved;
};
struct reg_addr {
@@ -80,202 +86,185 @@ struct wreg_addr {
u16 info;
};
-
-#define REGS_COUNT 558
+#define REGS_COUNT 834
static const struct reg_addr reg_addrs[REGS_COUNT] = {
{ 0x2000, 341, RI_ALL_ONLINE }, { 0x2800, 103, RI_ALL_ONLINE },
{ 0x3000, 287, RI_ALL_ONLINE }, { 0x3800, 331, RI_ALL_ONLINE },
- { 0x8800, 6, RI_E1_ONLINE }, { 0xa000, 223, RI_ALL_ONLINE },
- { 0xa388, 1, RI_ALL_ONLINE }, { 0xa398, 1, RI_ALL_ONLINE },
- { 0xa39c, 7, RI_E1H_ONLINE }, { 0xa3c0, 3, RI_E1H_ONLINE },
- { 0xa3d0, 1, RI_E1H_ONLINE }, { 0xa3d8, 1, RI_E1H_ONLINE },
- { 0xa3e0, 1, RI_E1H_ONLINE }, { 0xa3e8, 1, RI_E1H_ONLINE },
- { 0xa3f0, 1, RI_E1H_ONLINE }, { 0xa3f8, 1, RI_E1H_ONLINE },
- { 0xa400, 69, RI_ALL_ONLINE }, { 0xa518, 1, RI_ALL_ONLINE },
- { 0xa520, 1, RI_ALL_ONLINE }, { 0xa528, 1, RI_ALL_ONLINE },
- { 0xa530, 1, RI_ALL_ONLINE }, { 0xa538, 1, RI_ALL_ONLINE },
- { 0xa540, 1, RI_ALL_ONLINE }, { 0xa548, 1, RI_ALL_ONLINE },
- { 0xa550, 1, RI_ALL_ONLINE }, { 0xa558, 1, RI_ALL_ONLINE },
- { 0xa560, 1, RI_ALL_ONLINE }, { 0xa568, 1, RI_ALL_ONLINE },
- { 0xa570, 1, RI_ALL_ONLINE }, { 0xa580, 1, RI_ALL_ONLINE },
- { 0xa590, 1, RI_ALL_ONLINE }, { 0xa5a0, 1, RI_ALL_ONLINE },
- { 0xa5c0, 1, RI_ALL_ONLINE }, { 0xa5e0, 1, RI_E1H_ONLINE },
- { 0xa5e8, 1, RI_E1H_ONLINE }, { 0xa5f0, 1, RI_E1H_ONLINE },
- { 0xa5f8, 10, RI_E1H_ONLINE }, { 0x10000, 236, RI_ALL_ONLINE },
- { 0x103bc, 1, RI_ALL_ONLINE }, { 0x103cc, 1, RI_ALL_ONLINE },
- { 0x103dc, 1, RI_ALL_ONLINE }, { 0x10400, 57, RI_ALL_ONLINE },
- { 0x104e8, 2, RI_ALL_ONLINE }, { 0x104f4, 2, RI_ALL_ONLINE },
- { 0x10500, 146, RI_ALL_ONLINE }, { 0x10750, 2, RI_ALL_ONLINE },
- { 0x10760, 2, RI_ALL_ONLINE }, { 0x10770, 2, RI_ALL_ONLINE },
- { 0x10780, 2, RI_ALL_ONLINE }, { 0x10790, 2, RI_ALL_ONLINE },
- { 0x107a0, 2, RI_ALL_ONLINE }, { 0x107b0, 2, RI_ALL_ONLINE },
- { 0x107c0, 2, RI_ALL_ONLINE }, { 0x107d0, 2, RI_ALL_ONLINE },
- { 0x107e0, 2, RI_ALL_ONLINE }, { 0x10880, 2, RI_ALL_ONLINE },
- { 0x10900, 2, RI_ALL_ONLINE }, { 0x12000, 1, RI_ALL_ONLINE },
- { 0x14000, 1, RI_ALL_ONLINE }, { 0x16000, 26, RI_E1H_ONLINE },
- { 0x16070, 18, RI_E1H_ONLINE }, { 0x160c0, 27, RI_E1H_ONLINE },
- { 0x16140, 1, RI_E1H_ONLINE }, { 0x16160, 1, RI_E1H_ONLINE },
- { 0x16180, 2, RI_E1H_ONLINE }, { 0x161c0, 2, RI_E1H_ONLINE },
- { 0x16204, 5, RI_E1H_ONLINE }, { 0x18000, 1, RI_E1H_ONLINE },
- { 0x18008, 1, RI_E1H_ONLINE }, { 0x20000, 24, RI_ALL_ONLINE },
- { 0x20060, 8, RI_ALL_ONLINE }, { 0x20080, 138, RI_ALL_ONLINE },
- { 0x202b4, 1, RI_ALL_ONLINE }, { 0x202c4, 1, RI_ALL_ONLINE },
- { 0x20400, 2, RI_ALL_ONLINE }, { 0x2040c, 8, RI_ALL_ONLINE },
- { 0x2042c, 18, RI_E1H_ONLINE }, { 0x20480, 1, RI_ALL_ONLINE },
- { 0x20500, 1, RI_ALL_ONLINE }, { 0x20600, 1, RI_ALL_ONLINE },
- { 0x28000, 1, RI_ALL_ONLINE }, { 0x28004, 8191, RI_ALL_OFFLINE },
- { 0x30000, 1, RI_ALL_ONLINE }, { 0x30004, 16383, RI_ALL_OFFLINE },
- { 0x40000, 98, RI_ALL_ONLINE }, { 0x40194, 1, RI_ALL_ONLINE },
- { 0x401a4, 1, RI_ALL_ONLINE }, { 0x401a8, 11, RI_E1H_ONLINE },
- { 0x40200, 4, RI_ALL_ONLINE }, { 0x40400, 43, RI_ALL_ONLINE },
- { 0x404b8, 1, RI_ALL_ONLINE }, { 0x404c8, 1, RI_ALL_ONLINE },
- { 0x404cc, 3, RI_E1H_ONLINE }, { 0x40500, 2, RI_ALL_ONLINE },
+ { 0x8800, 6, RI_ALL_ONLINE }, { 0x8818, 1, RI_E1HE2_ONLINE },
+ { 0x9000, 164, RI_E2_ONLINE }, { 0x9400, 33, RI_E2_ONLINE },
+ { 0xa000, 27, RI_ALL_ONLINE }, { 0xa06c, 1, RI_E1E1H_ONLINE },
+ { 0xa070, 71, RI_ALL_ONLINE }, { 0xa18c, 4, RI_E1E1H_ONLINE },
+ { 0xa19c, 62, RI_ALL_ONLINE }, { 0xa294, 2, RI_E1E1H_ONLINE },
+ { 0xa29c, 56, RI_ALL_ONLINE }, { 0xa39c, 7, RI_E1HE2_ONLINE },
+ { 0xa3c0, 3, RI_E1HE2_ONLINE }, { 0xa3d0, 1, RI_E1HE2_ONLINE },
+ { 0xa3d8, 1, RI_E1HE2_ONLINE }, { 0xa3e0, 1, RI_E1HE2_ONLINE },
+ { 0xa3e8, 1, RI_E1HE2_ONLINE }, { 0xa3f0, 1, RI_E1HE2_ONLINE },
+ { 0xa3f8, 1, RI_E1HE2_ONLINE }, { 0xa400, 43, RI_ALL_ONLINE },
+ { 0xa4ac, 2, RI_E1E1H_ONLINE }, { 0xa4b4, 1, RI_ALL_ONLINE },
+ { 0xa4b8, 2, RI_E1E1H_ONLINE }, { 0xa4c0, 3, RI_ALL_ONLINE },
+ { 0xa4cc, 5, RI_E1E1H_ONLINE }, { 0xa4e0, 9, RI_ALL_ONLINE },
+ { 0xa504, 1, RI_E1E1H_ONLINE }, { 0xa508, 3, RI_ALL_ONLINE },
+ { 0xa518, 1, RI_ALL_ONLINE }, { 0xa520, 1, RI_ALL_ONLINE },
+ { 0xa528, 1, RI_ALL_ONLINE }, { 0xa530, 1, RI_ALL_ONLINE },
+ { 0xa538, 1, RI_ALL_ONLINE }, { 0xa540, 1, RI_ALL_ONLINE },
+ { 0xa548, 1, RI_E1E1H_ONLINE }, { 0xa550, 1, RI_E1E1H_ONLINE },
+ { 0xa558, 1, RI_E1E1H_ONLINE }, { 0xa560, 1, RI_E1E1H_ONLINE },
+ { 0xa568, 1, RI_E1E1H_ONLINE }, { 0xa570, 1, RI_ALL_ONLINE },
+ { 0xa580, 1, RI_ALL_ONLINE }, { 0xa590, 1, RI_ALL_ONLINE },
+ { 0xa5a0, 1, RI_ALL_ONLINE }, { 0xa5c0, 1, RI_ALL_ONLINE },
+ { 0xa5e0, 1, RI_E1HE2_ONLINE }, { 0xa5e8, 1, RI_E1HE2_ONLINE },
+ { 0xa5f0, 1, RI_E1HE2_ONLINE }, { 0xa5f8, 10, RI_E1HE2_ONLINE },
+ { 0xa620, 111, RI_E2_ONLINE }, { 0xa800, 51, RI_E2_ONLINE },
+ { 0xa8d4, 4, RI_E2_ONLINE }, { 0xa8e8, 1, RI_E2_ONLINE },
+ { 0xa8f0, 1, RI_E2_ONLINE }, { 0x10000, 236, RI_ALL_ONLINE },
+ { 0x10400, 57, RI_ALL_ONLINE }, { 0x104e8, 2, RI_ALL_ONLINE },
+ { 0x104f4, 2, RI_ALL_ONLINE }, { 0x10500, 146, RI_ALL_ONLINE },
+ { 0x10750, 2, RI_ALL_ONLINE }, { 0x10760, 2, RI_ALL_ONLINE },
+ { 0x10770, 2, RI_ALL_ONLINE }, { 0x10780, 2, RI_ALL_ONLINE },
+ { 0x10790, 2, RI_ALL_ONLINE }, { 0x107a0, 2, RI_ALL_ONLINE },
+ { 0x107b0, 2, RI_ALL_ONLINE }, { 0x107c0, 2, RI_ALL_ONLINE },
+ { 0x107d0, 2, RI_ALL_ONLINE }, { 0x107e0, 2, RI_ALL_ONLINE },
+ { 0x10880, 2, RI_ALL_ONLINE }, { 0x10900, 2, RI_ALL_ONLINE },
+ { 0x16000, 26, RI_E1HE2_ONLINE }, { 0x16070, 18, RI_E1HE2_ONLINE },
+ { 0x160c0, 27, RI_E1HE2_ONLINE }, { 0x16140, 1, RI_E1HE2_ONLINE },
+ { 0x16160, 1, RI_E1HE2_ONLINE }, { 0x16180, 2, RI_E1HE2_ONLINE },
+ { 0x161c0, 2, RI_E1HE2_ONLINE }, { 0x16204, 5, RI_E1HE2_ONLINE },
+ { 0x18000, 1, RI_E1HE2_ONLINE }, { 0x18008, 1, RI_E1HE2_ONLINE },
+ { 0x18010, 35, RI_E2_ONLINE }, { 0x180a4, 2, RI_E2_ONLINE },
+ { 0x180c0, 191, RI_E2_ONLINE }, { 0x18440, 1, RI_E2_ONLINE },
+ { 0x18460, 1, RI_E2_ONLINE }, { 0x18480, 2, RI_E2_ONLINE },
+ { 0x184c0, 2, RI_E2_ONLINE }, { 0x18500, 15, RI_E2_ONLINE },
+ { 0x20000, 24, RI_ALL_ONLINE }, { 0x20060, 8, RI_ALL_ONLINE },
+ { 0x20080, 94, RI_ALL_ONLINE }, { 0x201f8, 1, RI_E1E1H_ONLINE },
+ { 0x201fc, 1, RI_ALL_ONLINE }, { 0x20200, 1, RI_E1E1H_ONLINE },
+ { 0x20204, 1, RI_ALL_ONLINE }, { 0x20208, 1, RI_E1E1H_ONLINE },
+ { 0x2020c, 39, RI_ALL_ONLINE }, { 0x202c8, 1, RI_E2_ONLINE },
+ { 0x202d8, 4, RI_E2_ONLINE }, { 0x20400, 2, RI_ALL_ONLINE },
+ { 0x2040c, 8, RI_ALL_ONLINE }, { 0x2042c, 18, RI_E1HE2_ONLINE },
+ { 0x20480, 1, RI_ALL_ONLINE }, { 0x20500, 1, RI_ALL_ONLINE },
+ { 0x20600, 1, RI_ALL_ONLINE }, { 0x28000, 1, RI_ALL_ONLINE },
+ { 0x28004, 8191, RI_ALL_OFFLINE }, { 0x30000, 1, RI_ALL_ONLINE },
+ { 0x30004, 16383, RI_ALL_OFFLINE }, { 0x40000, 98, RI_ALL_ONLINE },
+ { 0x401a8, 8, RI_E1HE2_ONLINE }, { 0x401c8, 1, RI_E1H_ONLINE },
+ { 0x401cc, 2, RI_E1HE2_ONLINE }, { 0x401d4, 2, RI_E2_ONLINE },
+ { 0x40200, 4, RI_ALL_ONLINE }, { 0x40220, 18, RI_E2_ONLINE },
+ { 0x40400, 43, RI_ALL_ONLINE }, { 0x404cc, 3, RI_E1HE2_ONLINE },
+ { 0x404e0, 1, RI_E2_ONLINE }, { 0x40500, 2, RI_ALL_ONLINE },
{ 0x40510, 2, RI_ALL_ONLINE }, { 0x40520, 2, RI_ALL_ONLINE },
{ 0x40530, 2, RI_ALL_ONLINE }, { 0x40540, 2, RI_ALL_ONLINE },
- { 0x42000, 164, RI_ALL_ONLINE }, { 0x4229c, 1, RI_ALL_ONLINE },
- { 0x422ac, 1, RI_ALL_ONLINE }, { 0x422bc, 1, RI_ALL_ONLINE },
- { 0x422d4, 5, RI_E1H_ONLINE }, { 0x42400, 49, RI_ALL_ONLINE },
- { 0x424c8, 38, RI_ALL_ONLINE }, { 0x42568, 2, RI_ALL_ONLINE },
- { 0x42800, 1, RI_ALL_ONLINE }, { 0x50000, 20, RI_ALL_ONLINE },
- { 0x50050, 8, RI_ALL_ONLINE }, { 0x50070, 88, RI_ALL_ONLINE },
- { 0x501dc, 1, RI_ALL_ONLINE }, { 0x501ec, 1, RI_ALL_ONLINE },
- { 0x501f0, 4, RI_E1H_ONLINE }, { 0x50200, 2, RI_ALL_ONLINE },
- { 0x5020c, 7, RI_ALL_ONLINE }, { 0x50228, 6, RI_E1H_ONLINE },
- { 0x50240, 1, RI_ALL_ONLINE }, { 0x50280, 1, RI_ALL_ONLINE },
+ { 0x40550, 10, RI_E2_ONLINE }, { 0x40610, 2, RI_E2_ONLINE },
+ { 0x42000, 164, RI_ALL_ONLINE }, { 0x422c0, 4, RI_E2_ONLINE },
+ { 0x422d4, 5, RI_E1HE2_ONLINE }, { 0x422e8, 1, RI_E2_ONLINE },
+ { 0x42400, 49, RI_ALL_ONLINE }, { 0x424c8, 38, RI_ALL_ONLINE },
+ { 0x42568, 2, RI_ALL_ONLINE }, { 0x42640, 5, RI_E2_ONLINE },
+ { 0x42800, 1, RI_ALL_ONLINE }, { 0x50000, 1, RI_ALL_ONLINE },
+ { 0x50004, 19, RI_ALL_ONLINE }, { 0x50050, 8, RI_ALL_ONLINE },
+ { 0x50070, 88, RI_ALL_ONLINE }, { 0x501f0, 4, RI_E1HE2_ONLINE },
+ { 0x50200, 2, RI_ALL_ONLINE }, { 0x5020c, 7, RI_ALL_ONLINE },
+ { 0x50228, 6, RI_E1HE2_ONLINE }, { 0x50240, 1, RI_ALL_ONLINE },
+ { 0x50280, 1, RI_ALL_ONLINE }, { 0x50300, 1, RI_E2_ONLINE },
+ { 0x5030c, 1, RI_E2_ONLINE }, { 0x50318, 1, RI_E2_ONLINE },
+ { 0x5031c, 1, RI_E2_ONLINE }, { 0x50320, 2, RI_E2_ONLINE },
{ 0x52000, 1, RI_ALL_ONLINE }, { 0x54000, 1, RI_ALL_ONLINE },
{ 0x54004, 3327, RI_ALL_OFFLINE }, { 0x58000, 1, RI_ALL_ONLINE },
- { 0x58004, 8191, RI_ALL_OFFLINE }, { 0x60000, 71, RI_ALL_ONLINE },
- { 0x60128, 1, RI_ALL_ONLINE }, { 0x60138, 1, RI_ALL_ONLINE },
- { 0x6013c, 24, RI_E1H_ONLINE }, { 0x60200, 1, RI_ALL_ONLINE },
+ { 0x58004, 8191, RI_E1E1H_OFFLINE }, { 0x60000, 26, RI_ALL_ONLINE },
+ { 0x60068, 8, RI_E1E1H_ONLINE }, { 0x60088, 12, RI_ALL_ONLINE },
+ { 0x600b8, 9, RI_E1E1H_ONLINE }, { 0x600dc, 1, RI_ALL_ONLINE },
+ { 0x600e0, 5, RI_E1E1H_ONLINE }, { 0x600f4, 1, RI_ALL_ONLINE },
+ { 0x600f8, 1, RI_E1E1H_ONLINE }, { 0x600fc, 8, RI_ALL_ONLINE },
+ { 0x6013c, 24, RI_E1H_ONLINE }, { 0x6019c, 2, RI_E2_ONLINE },
+ { 0x601ac, 18, RI_E2_ONLINE }, { 0x60200, 1, RI_ALL_ONLINE },
+ { 0x60204, 2, RI_ALL_OFFLINE }, { 0x60210, 13, RI_E2_ONLINE },
{ 0x61000, 1, RI_ALL_ONLINE }, { 0x61004, 511, RI_ALL_OFFLINE },
- { 0x70000, 8, RI_ALL_ONLINE }, { 0x70020, 21496, RI_ALL_OFFLINE },
- { 0x85000, 3, RI_ALL_ONLINE }, { 0x8500c, 4, RI_ALL_OFFLINE },
- { 0x8501c, 7, RI_ALL_ONLINE }, { 0x85038, 4, RI_ALL_OFFLINE },
- { 0x85048, 1, RI_ALL_ONLINE }, { 0x8504c, 109, RI_ALL_OFFLINE },
- { 0x85200, 32, RI_ALL_ONLINE }, { 0x85280, 11104, RI_ALL_OFFLINE },
- { 0xa0000, 16384, RI_ALL_ONLINE }, { 0xb0000, 16384, RI_E1H_ONLINE },
- { 0xc1000, 7, RI_ALL_ONLINE }, { 0xc1028, 1, RI_ALL_ONLINE },
- { 0xc1038, 1, RI_ALL_ONLINE }, { 0xc1800, 2, RI_ALL_ONLINE },
- { 0xc2000, 164, RI_ALL_ONLINE }, { 0xc229c, 1, RI_ALL_ONLINE },
- { 0xc22ac, 1, RI_ALL_ONLINE }, { 0xc22bc, 1, RI_ALL_ONLINE },
+ { 0x70000, 8, RI_ALL_ONLINE }, { 0x70020, 8184, RI_ALL_OFFLINE },
+ { 0x85000, 3, RI_ALL_ONLINE }, { 0x8501c, 7, RI_ALL_ONLINE },
+ { 0x85048, 1, RI_ALL_ONLINE }, { 0x85200, 32, RI_ALL_ONLINE },
+ { 0xc1000, 7, RI_ALL_ONLINE }, { 0xc103c, 2, RI_E2_ONLINE },
+ { 0xc1800, 2, RI_ALL_ONLINE }, { 0xc2000, 164, RI_ALL_ONLINE },
+ { 0xc22c0, 5, RI_E2_ONLINE }, { 0xc22d8, 4, RI_E2_ONLINE },
{ 0xc2400, 49, RI_ALL_ONLINE }, { 0xc24c8, 38, RI_ALL_ONLINE },
{ 0xc2568, 2, RI_ALL_ONLINE }, { 0xc2600, 1, RI_ALL_ONLINE },
- { 0xc4000, 165, RI_ALL_ONLINE }, { 0xc42a0, 1, RI_ALL_ONLINE },
- { 0xc42b0, 1, RI_ALL_ONLINE }, { 0xc42c0, 1, RI_ALL_ONLINE },
- { 0xc42e0, 7, RI_E1H_ONLINE }, { 0xc4400, 51, RI_ALL_ONLINE },
- { 0xc44d0, 38, RI_ALL_ONLINE }, { 0xc4570, 2, RI_ALL_ONLINE },
+ { 0xc4000, 165, RI_ALL_ONLINE }, { 0xc42d8, 2, RI_E2_ONLINE },
+ { 0xc42e0, 7, RI_E1HE2_ONLINE }, { 0xc42fc, 1, RI_E2_ONLINE },
+ { 0xc4400, 51, RI_ALL_ONLINE }, { 0xc44d0, 38, RI_ALL_ONLINE },
+ { 0xc4570, 2, RI_ALL_ONLINE }, { 0xc4578, 5, RI_E2_ONLINE },
{ 0xc4600, 1, RI_ALL_ONLINE }, { 0xd0000, 19, RI_ALL_ONLINE },
{ 0xd004c, 8, RI_ALL_ONLINE }, { 0xd006c, 91, RI_ALL_ONLINE },
- { 0xd01e4, 1, RI_ALL_ONLINE }, { 0xd01f4, 1, RI_ALL_ONLINE },
- { 0xd0200, 2, RI_ALL_ONLINE }, { 0xd020c, 7, RI_ALL_ONLINE },
- { 0xd0228, 18, RI_E1H_ONLINE }, { 0xd0280, 1, RI_ALL_ONLINE },
- { 0xd0300, 1, RI_ALL_ONLINE }, { 0xd0400, 1, RI_ALL_ONLINE },
- { 0xd4000, 1, RI_ALL_ONLINE }, { 0xd4004, 2559, RI_ALL_OFFLINE },
- { 0xd8000, 1, RI_ALL_ONLINE }, { 0xd8004, 8191, RI_ALL_OFFLINE },
- { 0xe0000, 21, RI_ALL_ONLINE }, { 0xe0054, 8, RI_ALL_ONLINE },
- { 0xe0074, 85, RI_ALL_ONLINE }, { 0xe01d4, 1, RI_ALL_ONLINE },
- { 0xe01e4, 1, RI_ALL_ONLINE }, { 0xe0200, 2, RI_ALL_ONLINE },
- { 0xe020c, 8, RI_ALL_ONLINE }, { 0xe022c, 18, RI_E1H_ONLINE },
+ { 0xd01fc, 1, RI_E2_ONLINE }, { 0xd0200, 2, RI_ALL_ONLINE },
+ { 0xd020c, 7, RI_ALL_ONLINE }, { 0xd0228, 18, RI_E1HE2_ONLINE },
+ { 0xd0280, 1, RI_ALL_ONLINE }, { 0xd0300, 1, RI_ALL_ONLINE },
+ { 0xd0400, 1, RI_ALL_ONLINE }, { 0xd4000, 1, RI_ALL_ONLINE },
+ { 0xd4004, 2559, RI_ALL_OFFLINE }, { 0xd8000, 1, RI_ALL_ONLINE },
+ { 0xd8004, 8191, RI_ALL_OFFLINE }, { 0xe0000, 21, RI_ALL_ONLINE },
+ { 0xe0054, 8, RI_ALL_ONLINE }, { 0xe0074, 49, RI_ALL_ONLINE },
+ { 0xe0138, 1, RI_E1E1H_ONLINE }, { 0xe013c, 35, RI_ALL_ONLINE },
+ { 0xe01f4, 2, RI_E2_ONLINE }, { 0xe0200, 2, RI_ALL_ONLINE },
+ { 0xe020c, 8, RI_ALL_ONLINE }, { 0xe022c, 18, RI_E1HE2_ONLINE },
{ 0xe0280, 1, RI_ALL_ONLINE }, { 0xe0300, 1, RI_ALL_ONLINE },
{ 0xe1000, 1, RI_ALL_ONLINE }, { 0xe2000, 1, RI_ALL_ONLINE },
{ 0xe2004, 2047, RI_ALL_OFFLINE }, { 0xf0000, 1, RI_ALL_ONLINE },
{ 0xf0004, 16383, RI_ALL_OFFLINE }, { 0x101000, 12, RI_ALL_ONLINE },
- { 0x10103c, 1, RI_ALL_ONLINE }, { 0x10104c, 1, RI_ALL_ONLINE },
- { 0x101050, 1, RI_E1H_ONLINE }, { 0x101100, 1, RI_ALL_ONLINE },
- { 0x101800, 8, RI_ALL_ONLINE }, { 0x102000, 18, RI_ALL_ONLINE },
- { 0x102054, 1, RI_ALL_ONLINE }, { 0x102064, 1, RI_ALL_ONLINE },
+ { 0x101050, 1, RI_E1HE2_ONLINE }, { 0x101054, 3, RI_E2_ONLINE },
+ { 0x101100, 1, RI_ALL_ONLINE }, { 0x101800, 8, RI_ALL_ONLINE },
+ { 0x102000, 18, RI_ALL_ONLINE }, { 0x102068, 6, RI_E2_ONLINE },
{ 0x102080, 17, RI_ALL_ONLINE }, { 0x1020c8, 8, RI_E1H_ONLINE },
- { 0x102400, 1, RI_ALL_ONLINE }, { 0x103000, 26, RI_ALL_ONLINE },
- { 0x103074, 1, RI_ALL_ONLINE }, { 0x103084, 1, RI_ALL_ONLINE },
- { 0x103094, 1, RI_ALL_ONLINE }, { 0x103098, 5, RI_E1H_ONLINE },
+ { 0x1020e8, 9, RI_E2_ONLINE }, { 0x102400, 1, RI_ALL_ONLINE },
+ { 0x103000, 26, RI_ALL_ONLINE }, { 0x103098, 5, RI_E1HE2_ONLINE },
+ { 0x1030ac, 10, RI_E2_ONLINE }, { 0x1030d8, 8, RI_E2_ONLINE },
+ { 0x103400, 1, RI_E2_ONLINE }, { 0x103404, 135, RI_E2_OFFLINE },
{ 0x103800, 8, RI_ALL_ONLINE }, { 0x104000, 63, RI_ALL_ONLINE },
- { 0x104108, 1, RI_ALL_ONLINE }, { 0x104118, 1, RI_ALL_ONLINE },
- { 0x104200, 17, RI_ALL_ONLINE }, { 0x104400, 64, RI_ALL_ONLINE },
- { 0x104500, 192, RI_ALL_OFFLINE }, { 0x104800, 64, RI_ALL_ONLINE },
- { 0x104900, 192, RI_ALL_OFFLINE }, { 0x105000, 7, RI_ALL_ONLINE },
- { 0x10501c, 1, RI_ALL_OFFLINE }, { 0x105020, 3, RI_ALL_ONLINE },
- { 0x10502c, 1, RI_ALL_OFFLINE }, { 0x105030, 3, RI_ALL_ONLINE },
- { 0x10503c, 1, RI_ALL_OFFLINE }, { 0x105040, 3, RI_ALL_ONLINE },
- { 0x10504c, 1, RI_ALL_OFFLINE }, { 0x105050, 3, RI_ALL_ONLINE },
- { 0x10505c, 1, RI_ALL_OFFLINE }, { 0x105060, 3, RI_ALL_ONLINE },
- { 0x10506c, 1, RI_ALL_OFFLINE }, { 0x105070, 3, RI_ALL_ONLINE },
- { 0x10507c, 1, RI_ALL_OFFLINE }, { 0x105080, 3, RI_ALL_ONLINE },
- { 0x10508c, 1, RI_ALL_OFFLINE }, { 0x105090, 3, RI_ALL_ONLINE },
- { 0x10509c, 1, RI_ALL_OFFLINE }, { 0x1050a0, 3, RI_ALL_ONLINE },
- { 0x1050ac, 1, RI_ALL_OFFLINE }, { 0x1050b0, 3, RI_ALL_ONLINE },
- { 0x1050bc, 1, RI_ALL_OFFLINE }, { 0x1050c0, 3, RI_ALL_ONLINE },
- { 0x1050cc, 1, RI_ALL_OFFLINE }, { 0x1050d0, 3, RI_ALL_ONLINE },
- { 0x1050dc, 1, RI_ALL_OFFLINE }, { 0x1050e0, 3, RI_ALL_ONLINE },
- { 0x1050ec, 1, RI_ALL_OFFLINE }, { 0x1050f0, 3, RI_ALL_ONLINE },
- { 0x1050fc, 1, RI_ALL_OFFLINE }, { 0x105100, 3, RI_ALL_ONLINE },
- { 0x10510c, 1, RI_ALL_OFFLINE }, { 0x105110, 3, RI_ALL_ONLINE },
- { 0x10511c, 1, RI_ALL_OFFLINE }, { 0x105120, 3, RI_ALL_ONLINE },
- { 0x10512c, 1, RI_ALL_OFFLINE }, { 0x105130, 3, RI_ALL_ONLINE },
- { 0x10513c, 1, RI_ALL_OFFLINE }, { 0x105140, 3, RI_ALL_ONLINE },
- { 0x10514c, 1, RI_ALL_OFFLINE }, { 0x105150, 3, RI_ALL_ONLINE },
- { 0x10515c, 1, RI_ALL_OFFLINE }, { 0x105160, 3, RI_ALL_ONLINE },
- { 0x10516c, 1, RI_ALL_OFFLINE }, { 0x105170, 3, RI_ALL_ONLINE },
- { 0x10517c, 1, RI_ALL_OFFLINE }, { 0x105180, 3, RI_ALL_ONLINE },
- { 0x10518c, 1, RI_ALL_OFFLINE }, { 0x105190, 3, RI_ALL_ONLINE },
- { 0x10519c, 1, RI_ALL_OFFLINE }, { 0x1051a0, 3, RI_ALL_ONLINE },
- { 0x1051ac, 1, RI_ALL_OFFLINE }, { 0x1051b0, 3, RI_ALL_ONLINE },
- { 0x1051bc, 1, RI_ALL_OFFLINE }, { 0x1051c0, 3, RI_ALL_ONLINE },
- { 0x1051cc, 1, RI_ALL_OFFLINE }, { 0x1051d0, 3, RI_ALL_ONLINE },
- { 0x1051dc, 1, RI_ALL_OFFLINE }, { 0x1051e0, 3, RI_ALL_ONLINE },
- { 0x1051ec, 1, RI_ALL_OFFLINE }, { 0x1051f0, 3, RI_ALL_ONLINE },
- { 0x1051fc, 1, RI_ALL_OFFLINE }, { 0x105200, 3, RI_ALL_ONLINE },
- { 0x10520c, 1, RI_ALL_OFFLINE }, { 0x105210, 3, RI_ALL_ONLINE },
- { 0x10521c, 1, RI_ALL_OFFLINE }, { 0x105220, 3, RI_ALL_ONLINE },
- { 0x10522c, 1, RI_ALL_OFFLINE }, { 0x105230, 3, RI_ALL_ONLINE },
- { 0x10523c, 1, RI_ALL_OFFLINE }, { 0x105240, 3, RI_ALL_ONLINE },
- { 0x10524c, 1, RI_ALL_OFFLINE }, { 0x105250, 3, RI_ALL_ONLINE },
- { 0x10525c, 1, RI_ALL_OFFLINE }, { 0x105260, 3, RI_ALL_ONLINE },
- { 0x10526c, 1, RI_ALL_OFFLINE }, { 0x105270, 3, RI_ALL_ONLINE },
- { 0x10527c, 1, RI_ALL_OFFLINE }, { 0x105280, 3, RI_ALL_ONLINE },
- { 0x10528c, 1, RI_ALL_OFFLINE }, { 0x105290, 3, RI_ALL_ONLINE },
- { 0x10529c, 1, RI_ALL_OFFLINE }, { 0x1052a0, 3, RI_ALL_ONLINE },
- { 0x1052ac, 1, RI_ALL_OFFLINE }, { 0x1052b0, 3, RI_ALL_ONLINE },
- { 0x1052bc, 1, RI_ALL_OFFLINE }, { 0x1052c0, 3, RI_ALL_ONLINE },
- { 0x1052cc, 1, RI_ALL_OFFLINE }, { 0x1052d0, 3, RI_ALL_ONLINE },
- { 0x1052dc, 1, RI_ALL_OFFLINE }, { 0x1052e0, 3, RI_ALL_ONLINE },
- { 0x1052ec, 1, RI_ALL_OFFLINE }, { 0x1052f0, 3, RI_ALL_ONLINE },
- { 0x1052fc, 1, RI_ALL_OFFLINE }, { 0x105300, 3, RI_ALL_ONLINE },
- { 0x10530c, 1, RI_ALL_OFFLINE }, { 0x105310, 3, RI_ALL_ONLINE },
- { 0x10531c, 1, RI_ALL_OFFLINE }, { 0x105320, 3, RI_ALL_ONLINE },
- { 0x10532c, 1, RI_ALL_OFFLINE }, { 0x105330, 3, RI_ALL_ONLINE },
- { 0x10533c, 1, RI_ALL_OFFLINE }, { 0x105340, 3, RI_ALL_ONLINE },
- { 0x10534c, 1, RI_ALL_OFFLINE }, { 0x105350, 3, RI_ALL_ONLINE },
- { 0x10535c, 1, RI_ALL_OFFLINE }, { 0x105360, 3, RI_ALL_ONLINE },
- { 0x10536c, 1, RI_ALL_OFFLINE }, { 0x105370, 3, RI_ALL_ONLINE },
- { 0x10537c, 1, RI_ALL_OFFLINE }, { 0x105380, 3, RI_ALL_ONLINE },
- { 0x10538c, 1, RI_ALL_OFFLINE }, { 0x105390, 3, RI_ALL_ONLINE },
- { 0x10539c, 1, RI_ALL_OFFLINE }, { 0x1053a0, 3, RI_ALL_ONLINE },
- { 0x1053ac, 1, RI_ALL_OFFLINE }, { 0x1053b0, 3, RI_ALL_ONLINE },
- { 0x1053bc, 1, RI_ALL_OFFLINE }, { 0x1053c0, 3, RI_ALL_ONLINE },
- { 0x1053cc, 1, RI_ALL_OFFLINE }, { 0x1053d0, 3, RI_ALL_ONLINE },
- { 0x1053dc, 1, RI_ALL_OFFLINE }, { 0x1053e0, 3, RI_ALL_ONLINE },
- { 0x1053ec, 1, RI_ALL_OFFLINE }, { 0x1053f0, 3, RI_ALL_ONLINE },
- { 0x1053fc, 769, RI_ALL_OFFLINE }, { 0x108000, 33, RI_ALL_ONLINE },
- { 0x108090, 1, RI_ALL_ONLINE }, { 0x1080a0, 1, RI_ALL_ONLINE },
- { 0x1080ac, 5, RI_E1H_ONLINE }, { 0x108100, 5, RI_ALL_ONLINE },
- { 0x108120, 5, RI_ALL_ONLINE }, { 0x108200, 74, RI_ALL_ONLINE },
- { 0x108400, 74, RI_ALL_ONLINE }, { 0x108800, 152, RI_ALL_ONLINE },
- { 0x109000, 1, RI_ALL_ONLINE }, { 0x120000, 347, RI_ALL_ONLINE },
- { 0x120578, 1, RI_ALL_ONLINE }, { 0x120588, 1, RI_ALL_ONLINE },
- { 0x120598, 1, RI_ALL_ONLINE }, { 0x12059c, 23, RI_E1H_ONLINE },
- { 0x120614, 1, RI_E1H_ONLINE }, { 0x12061c, 30, RI_E1H_ONLINE },
- { 0x12080c, 65, RI_ALL_ONLINE }, { 0x120a00, 2, RI_ALL_ONLINE },
- { 0x122000, 2, RI_ALL_ONLINE }, { 0x128000, 2, RI_E1H_ONLINE },
- { 0x140000, 114, RI_ALL_ONLINE }, { 0x1401d4, 1, RI_ALL_ONLINE },
- { 0x1401e4, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE },
- { 0x144000, 4, RI_ALL_ONLINE }, { 0x148000, 4, RI_ALL_ONLINE },
- { 0x14c000, 4, RI_ALL_ONLINE }, { 0x150000, 4, RI_ALL_ONLINE },
- { 0x154000, 4, RI_ALL_ONLINE }, { 0x158000, 4, RI_ALL_ONLINE },
- { 0x15c000, 7, RI_E1H_ONLINE }, { 0x161000, 7, RI_ALL_ONLINE },
- { 0x161028, 1, RI_ALL_ONLINE }, { 0x161038, 1, RI_ALL_ONLINE },
- { 0x161800, 2, RI_ALL_ONLINE }, { 0x164000, 60, RI_ALL_ONLINE },
- { 0x1640fc, 1, RI_ALL_ONLINE }, { 0x16410c, 1, RI_ALL_ONLINE },
- { 0x164110, 2, RI_E1H_ONLINE }, { 0x164200, 1, RI_ALL_ONLINE },
+ { 0x10411c, 16, RI_E2_ONLINE }, { 0x104200, 17, RI_ALL_ONLINE },
+ { 0x104400, 64, RI_ALL_ONLINE }, { 0x104500, 192, RI_ALL_OFFLINE },
+ { 0x104800, 64, RI_ALL_ONLINE }, { 0x104900, 192, RI_ALL_OFFLINE },
+ { 0x105000, 256, RI_ALL_ONLINE }, { 0x105400, 768, RI_ALL_OFFLINE },
+ { 0x107000, 7, RI_E2_ONLINE }, { 0x108000, 33, RI_E1E1H_ONLINE },
+ { 0x1080ac, 5, RI_E1H_ONLINE }, { 0x108100, 5, RI_E1E1H_ONLINE },
+ { 0x108120, 5, RI_E1E1H_ONLINE }, { 0x108200, 74, RI_E1E1H_ONLINE },
+ { 0x108400, 74, RI_E1E1H_ONLINE }, { 0x108800, 152, RI_E1E1H_ONLINE },
+ { 0x110000, 111, RI_E2_ONLINE }, { 0x110200, 4, RI_E2_ONLINE },
+ { 0x120000, 2, RI_ALL_ONLINE }, { 0x120008, 4, RI_ALL_ONLINE },
+ { 0x120018, 3, RI_ALL_ONLINE }, { 0x120024, 4, RI_ALL_ONLINE },
+ { 0x120034, 3, RI_ALL_ONLINE }, { 0x120040, 4, RI_ALL_ONLINE },
+ { 0x120050, 3, RI_ALL_ONLINE }, { 0x12005c, 4, RI_ALL_ONLINE },
+ { 0x12006c, 3, RI_ALL_ONLINE }, { 0x120078, 4, RI_ALL_ONLINE },
+ { 0x120088, 3, RI_ALL_ONLINE }, { 0x120094, 4, RI_ALL_ONLINE },
+ { 0x1200a4, 3, RI_ALL_ONLINE }, { 0x1200b0, 4, RI_ALL_ONLINE },
+ { 0x1200c0, 3, RI_ALL_ONLINE }, { 0x1200cc, 4, RI_ALL_ONLINE },
+ { 0x1200dc, 3, RI_ALL_ONLINE }, { 0x1200e8, 4, RI_ALL_ONLINE },
+ { 0x1200f8, 3, RI_ALL_ONLINE }, { 0x120104, 4, RI_ALL_ONLINE },
+ { 0x120114, 1, RI_ALL_ONLINE }, { 0x120118, 22, RI_ALL_ONLINE },
+ { 0x120170, 2, RI_E1E1H_ONLINE }, { 0x120178, 243, RI_ALL_ONLINE },
+ { 0x120544, 4, RI_E1E1H_ONLINE }, { 0x120554, 7, RI_ALL_ONLINE },
+ { 0x12059c, 6, RI_E1HE2_ONLINE }, { 0x1205b4, 1, RI_E1HE2_ONLINE },
+ { 0x1205b8, 16, RI_E1HE2_ONLINE }, { 0x1205f8, 4, RI_E2_ONLINE },
+ { 0x120618, 1, RI_E2_ONLINE }, { 0x12061c, 20, RI_E1HE2_ONLINE },
+ { 0x12066c, 11, RI_E1HE2_ONLINE }, { 0x120698, 5, RI_E2_ONLINE },
+ { 0x1206b0, 76, RI_E2_ONLINE }, { 0x1207fc, 1, RI_E2_ONLINE },
+ { 0x120808, 66, RI_ALL_ONLINE }, { 0x120910, 7, RI_E2_ONLINE },
+ { 0x120930, 9, RI_E2_ONLINE }, { 0x120a00, 2, RI_ALL_ONLINE },
+ { 0x122000, 2, RI_ALL_ONLINE }, { 0x122008, 2046, RI_E1_OFFLINE },
+ { 0x128000, 2, RI_E1HE2_ONLINE }, { 0x128008, 6142, RI_E1HE2_OFFLINE },
+ { 0x130000, 35, RI_E2_ONLINE }, { 0x130100, 29, RI_E2_ONLINE },
+ { 0x130180, 1, RI_E2_ONLINE }, { 0x130200, 1, RI_E2_ONLINE },
+ { 0x130280, 1, RI_E2_ONLINE }, { 0x130300, 5, RI_E2_ONLINE },
+ { 0x130380, 1, RI_E2_ONLINE }, { 0x130400, 1, RI_E2_ONLINE },
+ { 0x130480, 5, RI_E2_ONLINE }, { 0x130800, 72, RI_E2_ONLINE },
+ { 0x131000, 136, RI_E2_ONLINE }, { 0x132000, 148, RI_E2_ONLINE },
+ { 0x134000, 544, RI_E2_ONLINE }, { 0x140000, 64, RI_ALL_ONLINE },
+ { 0x140100, 5, RI_E1E1H_ONLINE }, { 0x140114, 45, RI_ALL_ONLINE },
+ { 0x140200, 6, RI_ALL_ONLINE }, { 0x140220, 4, RI_E2_ONLINE },
+ { 0x140240, 4, RI_E2_ONLINE }, { 0x140260, 4, RI_E2_ONLINE },
+ { 0x140280, 4, RI_E2_ONLINE }, { 0x1402a0, 4, RI_E2_ONLINE },
+ { 0x1402c0, 4, RI_E2_ONLINE }, { 0x1402e0, 13, RI_E2_ONLINE },
+ { 0x144000, 4, RI_E1E1H_ONLINE }, { 0x148000, 4, RI_E1E1H_ONLINE },
+ { 0x14c000, 4, RI_E1E1H_ONLINE }, { 0x150000, 4, RI_E1E1H_ONLINE },
+ { 0x154000, 4, RI_E1E1H_ONLINE }, { 0x158000, 4, RI_E1E1H_ONLINE },
+ { 0x15c000, 2, RI_E1HE2_ONLINE }, { 0x15c008, 5, RI_E1H_ONLINE },
+ { 0x15c020, 27, RI_E2_ONLINE }, { 0x15c090, 13, RI_E2_ONLINE },
+ { 0x15c0c8, 34, RI_E2_ONLINE }, { 0x161000, 7, RI_ALL_ONLINE },
+ { 0x16103c, 2, RI_E2_ONLINE }, { 0x161800, 2, RI_ALL_ONLINE },
+ { 0x164000, 60, RI_ALL_ONLINE }, { 0x164110, 2, RI_E1HE2_ONLINE },
+ { 0x164118, 15, RI_E2_ONLINE }, { 0x164200, 1, RI_ALL_ONLINE },
{ 0x164208, 1, RI_ALL_ONLINE }, { 0x164210, 1, RI_ALL_ONLINE },
{ 0x164218, 1, RI_ALL_ONLINE }, { 0x164220, 1, RI_ALL_ONLINE },
{ 0x164228, 1, RI_ALL_ONLINE }, { 0x164230, 1, RI_ALL_ONLINE },
@@ -284,169 +273,298 @@ static const struct reg_addr reg_addrs[REGS_COUNT] = {
{ 0x164258, 1, RI_ALL_ONLINE }, { 0x164260, 1, RI_ALL_ONLINE },
{ 0x164270, 2, RI_ALL_ONLINE }, { 0x164280, 2, RI_ALL_ONLINE },
{ 0x164800, 2, RI_ALL_ONLINE }, { 0x165000, 2, RI_ALL_ONLINE },
- { 0x166000, 164, RI_ALL_ONLINE }, { 0x16629c, 1, RI_ALL_ONLINE },
- { 0x1662ac, 1, RI_ALL_ONLINE }, { 0x1662bc, 1, RI_ALL_ONLINE },
+ { 0x166000, 164, RI_ALL_ONLINE }, { 0x1662cc, 7, RI_E2_ONLINE },
{ 0x166400, 49, RI_ALL_ONLINE }, { 0x1664c8, 38, RI_ALL_ONLINE },
- { 0x166568, 2, RI_ALL_ONLINE }, { 0x166800, 1, RI_ALL_ONLINE },
- { 0x168000, 270, RI_ALL_ONLINE }, { 0x168444, 1, RI_ALL_ONLINE },
- { 0x168454, 1, RI_ALL_ONLINE }, { 0x168800, 19, RI_ALL_ONLINE },
- { 0x168900, 1, RI_ALL_ONLINE }, { 0x168a00, 128, RI_ALL_ONLINE },
- { 0x16a000, 1, RI_ALL_ONLINE }, { 0x16a004, 1535, RI_ALL_OFFLINE },
- { 0x16c000, 1, RI_ALL_ONLINE }, { 0x16c004, 1535, RI_ALL_OFFLINE },
- { 0x16e000, 16, RI_E1H_ONLINE }, { 0x16e100, 1, RI_E1H_ONLINE },
- { 0x16e200, 2, RI_E1H_ONLINE }, { 0x16e400, 183, RI_E1H_ONLINE },
- { 0x170000, 93, RI_ALL_ONLINE }, { 0x170180, 1, RI_ALL_ONLINE },
- { 0x170190, 1, RI_ALL_ONLINE }, { 0x170200, 4, RI_ALL_ONLINE },
- { 0x170214, 1, RI_ALL_ONLINE }, { 0x178000, 1, RI_ALL_ONLINE },
- { 0x180000, 61, RI_ALL_ONLINE }, { 0x180100, 1, RI_ALL_ONLINE },
- { 0x180110, 1, RI_ALL_ONLINE }, { 0x180120, 1, RI_ALL_ONLINE },
- { 0x180130, 1, RI_ALL_ONLINE }, { 0x18013c, 2, RI_E1H_ONLINE },
- { 0x180200, 58, RI_ALL_ONLINE }, { 0x180340, 4, RI_ALL_ONLINE },
- { 0x180400, 1, RI_ALL_ONLINE }, { 0x180404, 255, RI_ALL_OFFLINE },
+ { 0x166568, 2, RI_ALL_ONLINE }, { 0x166570, 5, RI_E2_ONLINE },
+ { 0x166800, 1, RI_ALL_ONLINE }, { 0x168000, 137, RI_ALL_ONLINE },
+ { 0x168224, 2, RI_E1E1H_ONLINE }, { 0x16822c, 29, RI_ALL_ONLINE },
+ { 0x1682a0, 12, RI_E1E1H_ONLINE }, { 0x1682d0, 12, RI_ALL_ONLINE },
+ { 0x168300, 2, RI_E1E1H_ONLINE }, { 0x168308, 68, RI_ALL_ONLINE },
+ { 0x168418, 2, RI_E1E1H_ONLINE }, { 0x168420, 6, RI_ALL_ONLINE },
+ { 0x168800, 19, RI_ALL_ONLINE }, { 0x168900, 1, RI_ALL_ONLINE },
+ { 0x168a00, 128, RI_ALL_ONLINE }, { 0x16a000, 1, RI_ALL_ONLINE },
+ { 0x16a004, 1535, RI_ALL_OFFLINE }, { 0x16c000, 1, RI_ALL_ONLINE },
+ { 0x16c004, 1535, RI_ALL_OFFLINE }, { 0x16e000, 16, RI_E1H_ONLINE },
+ { 0x16e040, 8, RI_E2_ONLINE }, { 0x16e100, 1, RI_E1H_ONLINE },
+ { 0x16e200, 2, RI_E1H_ONLINE }, { 0x16e400, 161, RI_E1H_ONLINE },
+ { 0x16e684, 2, RI_E1HE2_ONLINE }, { 0x16e68c, 12, RI_E1H_ONLINE },
+ { 0x16e6bc, 4, RI_E1HE2_ONLINE }, { 0x16e6cc, 4, RI_E1H_ONLINE },
+ { 0x16e6e0, 12, RI_E2_ONLINE }, { 0x16e768, 17, RI_E2_ONLINE },
+ { 0x170000, 24, RI_ALL_ONLINE }, { 0x170060, 4, RI_E1E1H_ONLINE },
+ { 0x170070, 65, RI_ALL_ONLINE }, { 0x170194, 11, RI_E2_ONLINE },
+ { 0x1701c4, 1, RI_E2_ONLINE }, { 0x1701cc, 7, RI_E2_ONLINE },
+ { 0x1701ec, 1, RI_E2_ONLINE }, { 0x1701f4, 1, RI_E2_ONLINE },
+ { 0x170200, 4, RI_ALL_ONLINE }, { 0x170214, 1, RI_ALL_ONLINE },
+ { 0x170218, 77, RI_E2_ONLINE }, { 0x170400, 64, RI_E2_ONLINE },
+ { 0x178000, 1, RI_ALL_ONLINE }, { 0x180000, 61, RI_ALL_ONLINE },
+ { 0x18013c, 2, RI_E1HE2_ONLINE }, { 0x180200, 58, RI_ALL_ONLINE },
+ { 0x180340, 4, RI_ALL_ONLINE }, { 0x180380, 1, RI_E2_ONLINE },
+ { 0x180388, 1, RI_E2_ONLINE }, { 0x180390, 1, RI_E2_ONLINE },
+ { 0x180398, 1, RI_E2_ONLINE }, { 0x1803a0, 5, RI_E2_ONLINE },
+ { 0x180400, 1, RI_ALL_ONLINE }, { 0x180404, 255, RI_E1E1H_OFFLINE },
{ 0x181000, 4, RI_ALL_ONLINE }, { 0x181010, 1020, RI_ALL_OFFLINE },
- { 0x1a0000, 1, RI_ALL_ONLINE }, { 0x1a0004, 1023, RI_ALL_OFFLINE },
- { 0x1a1000, 1, RI_ALL_ONLINE }, { 0x1a1004, 4607, RI_ALL_OFFLINE },
- { 0x1a5800, 2560, RI_E1H_OFFLINE }, { 0x1a8000, 64, RI_ALL_OFFLINE },
- { 0x1a8100, 1984, RI_E1H_OFFLINE }, { 0x1aa000, 1, RI_E1H_ONLINE },
- { 0x1aa004, 6655, RI_E1H_OFFLINE }, { 0x1b1800, 128, RI_ALL_OFFLINE },
- { 0x1b1c00, 128, RI_ALL_OFFLINE }, { 0x1b2000, 1, RI_ALL_OFFLINE },
- { 0x1b2400, 64, RI_E1H_OFFLINE }, { 0x1b8200, 1, RI_ALL_ONLINE },
+ { 0x1a0000, 1, RI_ALL_ONLINE }, { 0x1a0004, 5631, RI_ALL_OFFLINE },
+ { 0x1a5800, 2560, RI_E1HE2_OFFLINE }, { 0x1a8000, 1, RI_ALL_ONLINE },
+ { 0x1a8004, 8191, RI_E1HE2_OFFLINE }, { 0x1b0000, 1, RI_ALL_ONLINE },
+ { 0x1b0004, 15, RI_E1H_OFFLINE }, { 0x1b0040, 1, RI_E1HE2_ONLINE },
+ { 0x1b0044, 239, RI_E1H_OFFLINE }, { 0x1b0400, 1, RI_ALL_ONLINE },
+ { 0x1b0404, 255, RI_E1H_OFFLINE }, { 0x1b0800, 1, RI_ALL_ONLINE },
+ { 0x1b0840, 1, RI_E1HE2_ONLINE }, { 0x1b0c00, 1, RI_ALL_ONLINE },
+ { 0x1b1000, 1, RI_ALL_ONLINE }, { 0x1b1040, 1, RI_E1HE2_ONLINE },
+ { 0x1b1400, 1, RI_ALL_ONLINE }, { 0x1b1440, 1, RI_E1HE2_ONLINE },
+ { 0x1b1480, 1, RI_E1HE2_ONLINE }, { 0x1b14c0, 1, RI_E1HE2_ONLINE },
+ { 0x1b1800, 128, RI_ALL_OFFLINE }, { 0x1b1c00, 128, RI_ALL_OFFLINE },
+ { 0x1b2000, 1, RI_ALL_ONLINE }, { 0x1b2400, 1, RI_E1HE2_ONLINE },
+ { 0x1b2404, 5631, RI_E2_OFFLINE }, { 0x1b8000, 1, RI_ALL_ONLINE },
+ { 0x1b8040, 1, RI_ALL_ONLINE }, { 0x1b8080, 1, RI_ALL_ONLINE },
+ { 0x1b80c0, 1, RI_ALL_ONLINE }, { 0x1b8100, 1, RI_ALL_ONLINE },
+ { 0x1b8140, 1, RI_ALL_ONLINE }, { 0x1b8180, 1, RI_ALL_ONLINE },
+ { 0x1b81c0, 1, RI_ALL_ONLINE }, { 0x1b8200, 1, RI_ALL_ONLINE },
{ 0x1b8240, 1, RI_ALL_ONLINE }, { 0x1b8280, 1, RI_ALL_ONLINE },
- { 0x1b82c0, 1, RI_ALL_ONLINE }, { 0x1b8a00, 1, RI_ALL_ONLINE },
- { 0x1b8a80, 1, RI_ALL_ONLINE }, { 0x1c0000, 2, RI_ALL_ONLINE },
- { 0x200000, 65, RI_ALL_ONLINE }, { 0x200110, 1, RI_ALL_ONLINE },
- { 0x200120, 1, RI_ALL_ONLINE }, { 0x200130, 1, RI_ALL_ONLINE },
- { 0x200140, 1, RI_ALL_ONLINE }, { 0x20014c, 2, RI_E1H_ONLINE },
- { 0x200200, 58, RI_ALL_ONLINE }, { 0x200340, 4, RI_ALL_ONLINE },
- { 0x200400, 1, RI_ALL_ONLINE }, { 0x200404, 255, RI_ALL_OFFLINE },
- { 0x202000, 4, RI_ALL_ONLINE }, { 0x202010, 2044, RI_ALL_OFFLINE },
- { 0x220000, 1, RI_ALL_ONLINE }, { 0x220004, 1023, RI_ALL_OFFLINE },
- { 0x221000, 1, RI_ALL_ONLINE }, { 0x221004, 4607, RI_ALL_OFFLINE },
- { 0x225800, 1536, RI_E1H_OFFLINE }, { 0x227000, 1, RI_E1H_ONLINE },
- { 0x227004, 1023, RI_E1H_OFFLINE }, { 0x228000, 64, RI_ALL_OFFLINE },
- { 0x228100, 8640, RI_E1H_OFFLINE }, { 0x231800, 128, RI_ALL_OFFLINE },
- { 0x231c00, 128, RI_ALL_OFFLINE }, { 0x232000, 1, RI_ALL_OFFLINE },
- { 0x232400, 64, RI_E1H_OFFLINE }, { 0x238200, 1, RI_ALL_ONLINE },
- { 0x238240, 1, RI_ALL_ONLINE }, { 0x238280, 1, RI_ALL_ONLINE },
- { 0x2382c0, 1, RI_ALL_ONLINE }, { 0x238a00, 1, RI_ALL_ONLINE },
- { 0x238a80, 1, RI_ALL_ONLINE }, { 0x240000, 2, RI_ALL_ONLINE },
- { 0x280000, 65, RI_ALL_ONLINE }, { 0x280110, 1, RI_ALL_ONLINE },
- { 0x280120, 1, RI_ALL_ONLINE }, { 0x280130, 1, RI_ALL_ONLINE },
- { 0x280140, 1, RI_ALL_ONLINE }, { 0x28014c, 2, RI_E1H_ONLINE },
- { 0x280200, 58, RI_ALL_ONLINE }, { 0x280340, 4, RI_ALL_ONLINE },
- { 0x280400, 1, RI_ALL_ONLINE }, { 0x280404, 255, RI_ALL_OFFLINE },
- { 0x282000, 4, RI_ALL_ONLINE }, { 0x282010, 2044, RI_ALL_OFFLINE },
- { 0x2a0000, 1, RI_ALL_ONLINE }, { 0x2a0004, 1023, RI_ALL_OFFLINE },
- { 0x2a1000, 1, RI_ALL_ONLINE }, { 0x2a1004, 4607, RI_ALL_OFFLINE },
- { 0x2a5800, 2560, RI_E1H_OFFLINE }, { 0x2a8000, 64, RI_ALL_OFFLINE },
- { 0x2a8100, 960, RI_E1H_OFFLINE }, { 0x2a9000, 1, RI_E1H_ONLINE },
- { 0x2a9004, 7679, RI_E1H_OFFLINE }, { 0x2b1800, 128, RI_ALL_OFFLINE },
- { 0x2b1c00, 128, RI_ALL_OFFLINE }, { 0x2b2000, 1, RI_ALL_OFFLINE },
- { 0x2b2400, 64, RI_E1H_OFFLINE }, { 0x2b8200, 1, RI_ALL_ONLINE },
- { 0x2b8240, 1, RI_ALL_ONLINE }, { 0x2b8280, 1, RI_ALL_ONLINE },
- { 0x2b82c0, 1, RI_ALL_ONLINE }, { 0x2b8a00, 1, RI_ALL_ONLINE },
- { 0x2b8a80, 1, RI_ALL_ONLINE }, { 0x2c0000, 2, RI_ALL_ONLINE },
- { 0x300000, 65, RI_ALL_ONLINE }, { 0x300110, 1, RI_ALL_ONLINE },
- { 0x300120, 1, RI_ALL_ONLINE }, { 0x300130, 1, RI_ALL_ONLINE },
- { 0x300140, 1, RI_ALL_ONLINE }, { 0x30014c, 2, RI_E1H_ONLINE },
+ { 0x1b82c0, 1, RI_ALL_ONLINE }, { 0x1b8300, 1, RI_ALL_ONLINE },
+ { 0x1b8340, 1, RI_ALL_ONLINE }, { 0x1b8380, 1, RI_ALL_ONLINE },
+ { 0x1b83c0, 1, RI_ALL_ONLINE }, { 0x1b8400, 1, RI_ALL_ONLINE },
+ { 0x1b8440, 1, RI_ALL_ONLINE }, { 0x1b8480, 1, RI_ALL_ONLINE },
+ { 0x1b84c0, 1, RI_ALL_ONLINE }, { 0x1b8500, 1, RI_ALL_ONLINE },
+ { 0x1b8540, 1, RI_ALL_ONLINE }, { 0x1b8580, 1, RI_ALL_ONLINE },
+ { 0x1b85c0, 19, RI_E2_ONLINE }, { 0x1b8800, 1, RI_ALL_ONLINE },
+ { 0x1b8840, 1, RI_ALL_ONLINE }, { 0x1b8880, 1, RI_ALL_ONLINE },
+ { 0x1b88c0, 1, RI_ALL_ONLINE }, { 0x1b8900, 1, RI_ALL_ONLINE },
+ { 0x1b8940, 1, RI_ALL_ONLINE }, { 0x1b8980, 1, RI_ALL_ONLINE },
+ { 0x1b89c0, 1, RI_ALL_ONLINE }, { 0x1b8a00, 1, RI_ALL_ONLINE },
+ { 0x1b8a40, 1, RI_ALL_ONLINE }, { 0x1b8a80, 1, RI_ALL_ONLINE },
+ { 0x1b8ac0, 1, RI_ALL_ONLINE }, { 0x1b8b00, 1, RI_ALL_ONLINE },
+ { 0x1b8b40, 1, RI_ALL_ONLINE }, { 0x1b8b80, 1, RI_ALL_ONLINE },
+ { 0x1b8bc0, 1, RI_ALL_ONLINE }, { 0x1b8c00, 1, RI_ALL_ONLINE },
+ { 0x1b8c40, 1, RI_ALL_ONLINE }, { 0x1b8c80, 1, RI_ALL_ONLINE },
+ { 0x1b8cc0, 1, RI_ALL_ONLINE }, { 0x1b8cc4, 1, RI_E2_ONLINE },
+ { 0x1b8d00, 1, RI_ALL_ONLINE }, { 0x1b8d40, 1, RI_ALL_ONLINE },
+ { 0x1b8d80, 1, RI_ALL_ONLINE }, { 0x1b8dc0, 1, RI_ALL_ONLINE },
+ { 0x1b8e00, 1, RI_ALL_ONLINE }, { 0x1b8e40, 1, RI_ALL_ONLINE },
+ { 0x1b8e80, 1, RI_ALL_ONLINE }, { 0x1b8e84, 1, RI_E2_ONLINE },
+ { 0x1b8ec0, 1, RI_E1HE2_ONLINE }, { 0x1b8f00, 1, RI_E1HE2_ONLINE },
+ { 0x1b8f40, 1, RI_E1HE2_ONLINE }, { 0x1b8f80, 1, RI_E1HE2_ONLINE },
+ { 0x1b8fc0, 1, RI_E1HE2_ONLINE }, { 0x1b8fc4, 2, RI_E2_ONLINE },
+ { 0x1b8fd0, 6, RI_E2_ONLINE }, { 0x1b9000, 1, RI_E2_ONLINE },
+ { 0x1b9040, 3, RI_E2_ONLINE }, { 0x1b9400, 14, RI_E2_ONLINE },
+ { 0x1b943c, 19, RI_E2_ONLINE }, { 0x1b9490, 10, RI_E2_ONLINE },
+ { 0x1c0000, 2, RI_ALL_ONLINE }, { 0x200000, 65, RI_ALL_ONLINE },
+ { 0x20014c, 2, RI_E1HE2_ONLINE }, { 0x200200, 58, RI_ALL_ONLINE },
+ { 0x200340, 4, RI_ALL_ONLINE }, { 0x200380, 1, RI_E2_ONLINE },
+ { 0x200388, 1, RI_E2_ONLINE }, { 0x200390, 1, RI_E2_ONLINE },
+ { 0x200398, 1, RI_E2_ONLINE }, { 0x2003a0, 1, RI_E2_ONLINE },
+ { 0x2003a8, 2, RI_E2_ONLINE }, { 0x200400, 1, RI_ALL_ONLINE },
+ { 0x200404, 255, RI_E1E1H_OFFLINE }, { 0x202000, 4, RI_ALL_ONLINE },
+ { 0x202010, 2044, RI_ALL_OFFLINE }, { 0x220000, 1, RI_ALL_ONLINE },
+ { 0x220004, 5631, RI_ALL_OFFLINE }, { 0x225800, 2560, RI_E1HE2_OFFLINE},
+ { 0x228000, 1, RI_ALL_ONLINE }, { 0x228004, 8191, RI_E1HE2_OFFLINE },
+ { 0x230000, 1, RI_ALL_ONLINE }, { 0x230004, 15, RI_E1H_OFFLINE },
+ { 0x230040, 1, RI_E1HE2_ONLINE }, { 0x230044, 239, RI_E1H_OFFLINE },
+ { 0x230400, 1, RI_ALL_ONLINE }, { 0x230404, 255, RI_E1H_OFFLINE },
+ { 0x230800, 1, RI_ALL_ONLINE }, { 0x230840, 1, RI_E1HE2_ONLINE },
+ { 0x230c00, 1, RI_ALL_ONLINE }, { 0x231000, 1, RI_ALL_ONLINE },
+ { 0x231040, 1, RI_E1HE2_ONLINE }, { 0x231400, 1, RI_ALL_ONLINE },
+ { 0x231440, 1, RI_E1HE2_ONLINE }, { 0x231480, 1, RI_E1HE2_ONLINE },
+ { 0x2314c0, 1, RI_E1HE2_ONLINE }, { 0x231800, 128, RI_ALL_OFFLINE },
+ { 0x231c00, 128, RI_ALL_OFFLINE }, { 0x232000, 1, RI_ALL_ONLINE },
+ { 0x232400, 1, RI_E1HE2_ONLINE }, { 0x232404, 5631, RI_E2_OFFLINE },
+ { 0x238000, 1, RI_ALL_ONLINE }, { 0x238040, 1, RI_ALL_ONLINE },
+ { 0x238080, 1, RI_ALL_ONLINE }, { 0x2380c0, 1, RI_ALL_ONLINE },
+ { 0x238100, 1, RI_ALL_ONLINE }, { 0x238140, 1, RI_ALL_ONLINE },
+ { 0x238180, 1, RI_ALL_ONLINE }, { 0x2381c0, 1, RI_ALL_ONLINE },
+ { 0x238200, 1, RI_ALL_ONLINE }, { 0x238240, 1, RI_ALL_ONLINE },
+ { 0x238280, 1, RI_ALL_ONLINE }, { 0x2382c0, 1, RI_ALL_ONLINE },
+ { 0x238300, 1, RI_ALL_ONLINE }, { 0x238340, 1, RI_ALL_ONLINE },
+ { 0x238380, 1, RI_ALL_ONLINE }, { 0x2383c0, 1, RI_ALL_ONLINE },
+ { 0x238400, 1, RI_ALL_ONLINE }, { 0x238440, 1, RI_ALL_ONLINE },
+ { 0x238480, 1, RI_ALL_ONLINE }, { 0x2384c0, 1, RI_ALL_ONLINE },
+ { 0x238500, 1, RI_ALL_ONLINE }, { 0x238540, 1, RI_ALL_ONLINE },
+ { 0x238580, 1, RI_ALL_ONLINE }, { 0x2385c0, 19, RI_E2_ONLINE },
+ { 0x238800, 1, RI_ALL_ONLINE }, { 0x238840, 1, RI_ALL_ONLINE },
+ { 0x238880, 1, RI_ALL_ONLINE }, { 0x2388c0, 1, RI_ALL_ONLINE },
+ { 0x238900, 1, RI_ALL_ONLINE }, { 0x238940, 1, RI_ALL_ONLINE },
+ { 0x238980, 1, RI_ALL_ONLINE }, { 0x2389c0, 1, RI_ALL_ONLINE },
+ { 0x238a00, 1, RI_ALL_ONLINE }, { 0x238a40, 1, RI_ALL_ONLINE },
+ { 0x238a80, 1, RI_ALL_ONLINE }, { 0x238ac0, 1, RI_ALL_ONLINE },
+ { 0x238b00, 1, RI_ALL_ONLINE }, { 0x238b40, 1, RI_ALL_ONLINE },
+ { 0x238b80, 1, RI_ALL_ONLINE }, { 0x238bc0, 1, RI_ALL_ONLINE },
+ { 0x238c00, 1, RI_ALL_ONLINE }, { 0x238c40, 1, RI_ALL_ONLINE },
+ { 0x238c80, 1, RI_ALL_ONLINE }, { 0x238cc0, 1, RI_ALL_ONLINE },
+ { 0x238cc4, 1, RI_E2_ONLINE }, { 0x238d00, 1, RI_ALL_ONLINE },
+ { 0x238d40, 1, RI_ALL_ONLINE }, { 0x238d80, 1, RI_ALL_ONLINE },
+ { 0x238dc0, 1, RI_ALL_ONLINE }, { 0x238e00, 1, RI_ALL_ONLINE },
+ { 0x238e40, 1, RI_ALL_ONLINE }, { 0x238e80, 1, RI_ALL_ONLINE },
+ { 0x238e84, 1, RI_E2_ONLINE }, { 0x238ec0, 1, RI_E1HE2_ONLINE },
+ { 0x238f00, 1, RI_E1HE2_ONLINE }, { 0x238f40, 1, RI_E1HE2_ONLINE },
+ { 0x238f80, 1, RI_E1HE2_ONLINE }, { 0x238fc0, 1, RI_E1HE2_ONLINE },
+ { 0x238fc4, 2, RI_E2_ONLINE }, { 0x238fd0, 6, RI_E2_ONLINE },
+ { 0x239000, 1, RI_E2_ONLINE }, { 0x239040, 3, RI_E2_ONLINE },
+ { 0x240000, 2, RI_ALL_ONLINE }, { 0x280000, 65, RI_ALL_ONLINE },
+ { 0x28014c, 2, RI_E1HE2_ONLINE }, { 0x280200, 58, RI_ALL_ONLINE },
+ { 0x280340, 4, RI_ALL_ONLINE }, { 0x280380, 1, RI_E2_ONLINE },
+ { 0x280388, 1, RI_E2_ONLINE }, { 0x280390, 1, RI_E2_ONLINE },
+ { 0x280398, 1, RI_E2_ONLINE }, { 0x2803a0, 1, RI_E2_ONLINE },
+ { 0x2803a8, 2, RI_E2_ONLINE }, { 0x280400, 1, RI_ALL_ONLINE },
+ { 0x280404, 255, RI_E1E1H_OFFLINE }, { 0x282000, 4, RI_ALL_ONLINE },
+ { 0x282010, 2044, RI_ALL_OFFLINE }, { 0x2a0000, 1, RI_ALL_ONLINE },
+ { 0x2a0004, 5631, RI_ALL_OFFLINE }, { 0x2a5800, 2560, RI_E1HE2_OFFLINE},
+ { 0x2a8000, 1, RI_ALL_ONLINE }, { 0x2a8004, 8191, RI_E1HE2_OFFLINE },
+ { 0x2b0000, 1, RI_ALL_ONLINE }, { 0x2b0004, 15, RI_E1H_OFFLINE },
+ { 0x2b0040, 1, RI_E1HE2_ONLINE }, { 0x2b0044, 239, RI_E1H_OFFLINE },
+ { 0x2b0400, 1, RI_ALL_ONLINE }, { 0x2b0404, 255, RI_E1H_OFFLINE },
+ { 0x2b0800, 1, RI_ALL_ONLINE }, { 0x2b0840, 1, RI_E1HE2_ONLINE },
+ { 0x2b0c00, 1, RI_ALL_ONLINE }, { 0x2b1000, 1, RI_ALL_ONLINE },
+ { 0x2b1040, 1, RI_E1HE2_ONLINE }, { 0x2b1400, 1, RI_ALL_ONLINE },
+ { 0x2b1440, 1, RI_E1HE2_ONLINE }, { 0x2b1480, 1, RI_E1HE2_ONLINE },
+ { 0x2b14c0, 1, RI_E1HE2_ONLINE }, { 0x2b1800, 128, RI_ALL_OFFLINE },
+ { 0x2b1c00, 128, RI_ALL_OFFLINE }, { 0x2b2000, 1, RI_ALL_ONLINE },
+ { 0x2b2400, 1, RI_E1HE2_ONLINE }, { 0x2b2404, 5631, RI_E2_OFFLINE },
+ { 0x2b8000, 1, RI_ALL_ONLINE }, { 0x2b8040, 1, RI_ALL_ONLINE },
+ { 0x2b8080, 1, RI_ALL_ONLINE }, { 0x2b80c0, 1, RI_ALL_ONLINE },
+ { 0x2b8100, 1, RI_ALL_ONLINE }, { 0x2b8140, 1, RI_ALL_ONLINE },
+ { 0x2b8180, 1, RI_ALL_ONLINE }, { 0x2b81c0, 1, RI_ALL_ONLINE },
+ { 0x2b8200, 1, RI_ALL_ONLINE }, { 0x2b8240, 1, RI_ALL_ONLINE },
+ { 0x2b8280, 1, RI_ALL_ONLINE }, { 0x2b82c0, 1, RI_ALL_ONLINE },
+ { 0x2b8300, 1, RI_ALL_ONLINE }, { 0x2b8340, 1, RI_ALL_ONLINE },
+ { 0x2b8380, 1, RI_ALL_ONLINE }, { 0x2b83c0, 1, RI_ALL_ONLINE },
+ { 0x2b8400, 1, RI_ALL_ONLINE }, { 0x2b8440, 1, RI_ALL_ONLINE },
+ { 0x2b8480, 1, RI_ALL_ONLINE }, { 0x2b84c0, 1, RI_ALL_ONLINE },
+ { 0x2b8500, 1, RI_ALL_ONLINE }, { 0x2b8540, 1, RI_ALL_ONLINE },
+ { 0x2b8580, 1, RI_ALL_ONLINE }, { 0x2b85c0, 19, RI_E2_ONLINE },
+ { 0x2b8800, 1, RI_ALL_ONLINE }, { 0x2b8840, 1, RI_ALL_ONLINE },
+ { 0x2b8880, 1, RI_ALL_ONLINE }, { 0x2b88c0, 1, RI_ALL_ONLINE },
+ { 0x2b8900, 1, RI_ALL_ONLINE }, { 0x2b8940, 1, RI_ALL_ONLINE },
+ { 0x2b8980, 1, RI_ALL_ONLINE }, { 0x2b89c0, 1, RI_ALL_ONLINE },
+ { 0x2b8a00, 1, RI_ALL_ONLINE }, { 0x2b8a40, 1, RI_ALL_ONLINE },
+ { 0x2b8a80, 1, RI_ALL_ONLINE }, { 0x2b8ac0, 1, RI_ALL_ONLINE },
+ { 0x2b8b00, 1, RI_ALL_ONLINE }, { 0x2b8b40, 1, RI_ALL_ONLINE },
+ { 0x2b8b80, 1, RI_ALL_ONLINE }, { 0x2b8bc0, 1, RI_ALL_ONLINE },
+ { 0x2b8c00, 1, RI_ALL_ONLINE }, { 0x2b8c40, 1, RI_ALL_ONLINE },
+ { 0x2b8c80, 1, RI_ALL_ONLINE }, { 0x2b8cc0, 1, RI_ALL_ONLINE },
+ { 0x2b8cc4, 1, RI_E2_ONLINE }, { 0x2b8d00, 1, RI_ALL_ONLINE },
+ { 0x2b8d40, 1, RI_ALL_ONLINE }, { 0x2b8d80, 1, RI_ALL_ONLINE },
+ { 0x2b8dc0, 1, RI_ALL_ONLINE }, { 0x2b8e00, 1, RI_ALL_ONLINE },
+ { 0x2b8e40, 1, RI_ALL_ONLINE }, { 0x2b8e80, 1, RI_ALL_ONLINE },
+ { 0x2b8e84, 1, RI_E2_ONLINE }, { 0x2b8ec0, 1, RI_E1HE2_ONLINE },
+ { 0x2b8f00, 1, RI_E1HE2_ONLINE }, { 0x2b8f40, 1, RI_E1HE2_ONLINE },
+ { 0x2b8f80, 1, RI_E1HE2_ONLINE }, { 0x2b8fc0, 1, RI_E1HE2_ONLINE },
+ { 0x2b8fc4, 2, RI_E2_ONLINE }, { 0x2b8fd0, 6, RI_E2_ONLINE },
+ { 0x2b9000, 1, RI_E2_ONLINE }, { 0x2b9040, 3, RI_E2_ONLINE },
+ { 0x2b9400, 14, RI_E2_ONLINE }, { 0x2b943c, 19, RI_E2_ONLINE },
+ { 0x2b9490, 10, RI_E2_ONLINE }, { 0x2c0000, 2, RI_ALL_ONLINE },
+ { 0x300000, 65, RI_ALL_ONLINE }, { 0x30014c, 2, RI_E1HE2_ONLINE },
{ 0x300200, 58, RI_ALL_ONLINE }, { 0x300340, 4, RI_ALL_ONLINE },
- { 0x300400, 1, RI_ALL_ONLINE }, { 0x300404, 255, RI_ALL_OFFLINE },
+ { 0x300380, 1, RI_E2_ONLINE }, { 0x300388, 1, RI_E2_ONLINE },
+ { 0x300390, 1, RI_E2_ONLINE }, { 0x300398, 1, RI_E2_ONLINE },
+ { 0x3003a0, 1, RI_E2_ONLINE }, { 0x3003a8, 2, RI_E2_ONLINE },
+ { 0x300400, 1, RI_ALL_ONLINE }, { 0x300404, 255, RI_E1E1H_OFFLINE },
{ 0x302000, 4, RI_ALL_ONLINE }, { 0x302010, 2044, RI_ALL_OFFLINE },
- { 0x320000, 1, RI_ALL_ONLINE }, { 0x320004, 1023, RI_ALL_OFFLINE },
- { 0x321000, 1, RI_ALL_ONLINE }, { 0x321004, 4607, RI_ALL_OFFLINE },
- { 0x325800, 2560, RI_E1H_OFFLINE }, { 0x328000, 64, RI_ALL_OFFLINE },
- { 0x328100, 536, RI_E1H_OFFLINE }, { 0x328960, 1, RI_E1H_ONLINE },
- { 0x328964, 8103, RI_E1H_OFFLINE }, { 0x331800, 128, RI_ALL_OFFLINE },
- { 0x331c00, 128, RI_ALL_OFFLINE }, { 0x332000, 1, RI_ALL_OFFLINE },
- { 0x332400, 64, RI_E1H_OFFLINE }, { 0x338200, 1, RI_ALL_ONLINE },
+ { 0x320000, 1, RI_ALL_ONLINE }, { 0x320004, 5631, RI_ALL_OFFLINE },
+ { 0x325800, 2560, RI_E1HE2_OFFLINE }, { 0x328000, 1, RI_ALL_ONLINE },
+ { 0x328004, 8191, RI_E1HE2_OFFLINE }, { 0x330000, 1, RI_ALL_ONLINE },
+ { 0x330004, 15, RI_E1H_OFFLINE }, { 0x330040, 1, RI_E1HE2_ONLINE },
+ { 0x330044, 239, RI_E1H_OFFLINE }, { 0x330400, 1, RI_ALL_ONLINE },
+ { 0x330404, 255, RI_E1H_OFFLINE }, { 0x330800, 1, RI_ALL_ONLINE },
+ { 0x330840, 1, RI_E1HE2_ONLINE }, { 0x330c00, 1, RI_ALL_ONLINE },
+ { 0x331000, 1, RI_ALL_ONLINE }, { 0x331040, 1, RI_E1HE2_ONLINE },
+ { 0x331400, 1, RI_ALL_ONLINE }, { 0x331440, 1, RI_E1HE2_ONLINE },
+ { 0x331480, 1, RI_E1HE2_ONLINE }, { 0x3314c0, 1, RI_E1HE2_ONLINE },
+ { 0x331800, 128, RI_ALL_OFFLINE }, { 0x331c00, 128, RI_ALL_OFFLINE },
+ { 0x332000, 1, RI_ALL_ONLINE }, { 0x332400, 1, RI_E1HE2_ONLINE },
+ { 0x332404, 5631, RI_E2_OFFLINE }, { 0x338000, 1, RI_ALL_ONLINE },
+ { 0x338040, 1, RI_ALL_ONLINE }, { 0x338080, 1, RI_ALL_ONLINE },
+ { 0x3380c0, 1, RI_ALL_ONLINE }, { 0x338100, 1, RI_ALL_ONLINE },
+ { 0x338140, 1, RI_ALL_ONLINE }, { 0x338180, 1, RI_ALL_ONLINE },
+ { 0x3381c0, 1, RI_ALL_ONLINE }, { 0x338200, 1, RI_ALL_ONLINE },
{ 0x338240, 1, RI_ALL_ONLINE }, { 0x338280, 1, RI_ALL_ONLINE },
- { 0x3382c0, 1, RI_ALL_ONLINE }, { 0x338a00, 1, RI_ALL_ONLINE },
- { 0x338a80, 1, RI_ALL_ONLINE }, { 0x340000, 2, RI_ALL_ONLINE }
+ { 0x3382c0, 1, RI_ALL_ONLINE }, { 0x338300, 1, RI_ALL_ONLINE },
+ { 0x338340, 1, RI_ALL_ONLINE }, { 0x338380, 1, RI_ALL_ONLINE },
+ { 0x3383c0, 1, RI_ALL_ONLINE }, { 0x338400, 1, RI_ALL_ONLINE },
+ { 0x338440, 1, RI_ALL_ONLINE }, { 0x338480, 1, RI_ALL_ONLINE },
+ { 0x3384c0, 1, RI_ALL_ONLINE }, { 0x338500, 1, RI_ALL_ONLINE },
+ { 0x338540, 1, RI_ALL_ONLINE }, { 0x338580, 1, RI_ALL_ONLINE },
+ { 0x3385c0, 19, RI_E2_ONLINE }, { 0x338800, 1, RI_ALL_ONLINE },
+ { 0x338840, 1, RI_ALL_ONLINE }, { 0x338880, 1, RI_ALL_ONLINE },
+ { 0x3388c0, 1, RI_ALL_ONLINE }, { 0x338900, 1, RI_ALL_ONLINE },
+ { 0x338940, 1, RI_ALL_ONLINE }, { 0x338980, 1, RI_ALL_ONLINE },
+ { 0x3389c0, 1, RI_ALL_ONLINE }, { 0x338a00, 1, RI_ALL_ONLINE },
+ { 0x338a40, 1, RI_ALL_ONLINE }, { 0x338a80, 1, RI_ALL_ONLINE },
+ { 0x338ac0, 1, RI_ALL_ONLINE }, { 0x338b00, 1, RI_ALL_ONLINE },
+ { 0x338b40, 1, RI_ALL_ONLINE }, { 0x338b80, 1, RI_ALL_ONLINE },
+ { 0x338bc0, 1, RI_ALL_ONLINE }, { 0x338c00, 1, RI_ALL_ONLINE },
+ { 0x338c40, 1, RI_ALL_ONLINE }, { 0x338c80, 1, RI_ALL_ONLINE },
+ { 0x338cc0, 1, RI_ALL_ONLINE }, { 0x338cc4, 1, RI_E2_ONLINE },
+ { 0x338d00, 1, RI_ALL_ONLINE }, { 0x338d40, 1, RI_ALL_ONLINE },
+ { 0x338d80, 1, RI_ALL_ONLINE }, { 0x338dc0, 1, RI_ALL_ONLINE },
+ { 0x338e00, 1, RI_ALL_ONLINE }, { 0x338e40, 1, RI_ALL_ONLINE },
+ { 0x338e80, 1, RI_ALL_ONLINE }, { 0x338e84, 1, RI_E2_ONLINE },
+ { 0x338ec0, 1, RI_E1HE2_ONLINE }, { 0x338f00, 1, RI_E1HE2_ONLINE },
+ { 0x338f40, 1, RI_E1HE2_ONLINE }, { 0x338f80, 1, RI_E1HE2_ONLINE },
+ { 0x338fc0, 1, RI_E1HE2_ONLINE }, { 0x338fc4, 2, RI_E2_ONLINE },
+ { 0x338fd0, 6, RI_E2_ONLINE }, { 0x339000, 1, RI_E2_ONLINE },
+ { 0x339040, 3, RI_E2_ONLINE }, { 0x340000, 2, RI_ALL_ONLINE },
};
-
-#define IDLE_REGS_COUNT 277
+#define IDLE_REGS_COUNT 237
static const struct reg_addr idle_addrs[IDLE_REGS_COUNT] = {
- { 0x2114, 1, RI_ALL_ONLINE }, { 0x2120, 1, RI_ALL_ONLINE },
- { 0x212c, 4, RI_ALL_ONLINE }, { 0x2814, 1, RI_ALL_ONLINE },
- { 0x281c, 2, RI_ALL_ONLINE }, { 0xa38c, 1, RI_ALL_ONLINE },
+ { 0x2104, 1, RI_ALL_ONLINE }, { 0x2110, 2, RI_ALL_ONLINE },
+ { 0x211c, 8, RI_ALL_ONLINE }, { 0x2814, 1, RI_ALL_ONLINE },
+ { 0x281c, 2, RI_ALL_ONLINE }, { 0x2854, 1, RI_ALL_ONLINE },
+ { 0x285c, 1, RI_ALL_ONLINE }, { 0x9010, 7, RI_E2_ONLINE },
+ { 0x9030, 1, RI_E2_ONLINE }, { 0x9068, 16, RI_E2_ONLINE },
+ { 0x9230, 2, RI_E2_ONLINE }, { 0x9244, 1, RI_E2_ONLINE },
+ { 0x9298, 1, RI_E2_ONLINE }, { 0x92a8, 1, RI_E2_ONLINE },
+ { 0xa38c, 1, RI_ALL_ONLINE }, { 0xa3c4, 1, RI_E1HE2_ONLINE },
{ 0xa408, 1, RI_ALL_ONLINE }, { 0xa42c, 12, RI_ALL_ONLINE },
- { 0xa600, 5, RI_E1H_ONLINE }, { 0xa618, 1, RI_E1H_ONLINE },
- { 0xc09c, 1, RI_ALL_ONLINE }, { 0x103b0, 1, RI_ALL_ONLINE },
- { 0x103c0, 1, RI_ALL_ONLINE }, { 0x103d0, 1, RI_E1H_ONLINE },
- { 0x2021c, 11, RI_ALL_ONLINE }, { 0x202a8, 1, RI_ALL_ONLINE },
- { 0x202b8, 1, RI_ALL_ONLINE }, { 0x20404, 1, RI_ALL_ONLINE },
- { 0x2040c, 2, RI_ALL_ONLINE }, { 0x2041c, 2, RI_ALL_ONLINE },
- { 0x40154, 14, RI_ALL_ONLINE }, { 0x40198, 1, RI_ALL_ONLINE },
- { 0x404ac, 1, RI_ALL_ONLINE }, { 0x404bc, 1, RI_ALL_ONLINE },
- { 0x42290, 1, RI_ALL_ONLINE }, { 0x422a0, 1, RI_ALL_ONLINE },
- { 0x422b0, 1, RI_ALL_ONLINE }, { 0x42548, 1, RI_ALL_ONLINE },
- { 0x42550, 1, RI_ALL_ONLINE }, { 0x42558, 1, RI_ALL_ONLINE },
- { 0x50160, 8, RI_ALL_ONLINE }, { 0x501d0, 1, RI_ALL_ONLINE },
- { 0x501e0, 1, RI_ALL_ONLINE }, { 0x50204, 1, RI_ALL_ONLINE },
- { 0x5020c, 2, RI_ALL_ONLINE }, { 0x5021c, 1, RI_ALL_ONLINE },
- { 0x60090, 1, RI_ALL_ONLINE }, { 0x6011c, 1, RI_ALL_ONLINE },
- { 0x6012c, 1, RI_ALL_ONLINE }, { 0xc101c, 1, RI_ALL_ONLINE },
- { 0xc102c, 1, RI_ALL_ONLINE }, { 0xc2290, 1, RI_ALL_ONLINE },
- { 0xc22a0, 1, RI_ALL_ONLINE }, { 0xc22b0, 1, RI_ALL_ONLINE },
- { 0xc2548, 1, RI_ALL_ONLINE }, { 0xc2550, 1, RI_ALL_ONLINE },
- { 0xc2558, 1, RI_ALL_ONLINE }, { 0xc4294, 1, RI_ALL_ONLINE },
- { 0xc42a4, 1, RI_ALL_ONLINE }, { 0xc42b4, 1, RI_ALL_ONLINE },
- { 0xc4550, 1, RI_ALL_ONLINE }, { 0xc4558, 1, RI_ALL_ONLINE },
- { 0xc4560, 1, RI_ALL_ONLINE }, { 0xd016c, 8, RI_ALL_ONLINE },
- { 0xd01d8, 1, RI_ALL_ONLINE }, { 0xd01e8, 1, RI_ALL_ONLINE },
- { 0xd0204, 1, RI_ALL_ONLINE }, { 0xd020c, 3, RI_ALL_ONLINE },
- { 0xe0154, 8, RI_ALL_ONLINE }, { 0xe01c8, 1, RI_ALL_ONLINE },
- { 0xe01d8, 1, RI_ALL_ONLINE }, { 0xe0204, 1, RI_ALL_ONLINE },
- { 0xe020c, 2, RI_ALL_ONLINE }, { 0xe021c, 2, RI_ALL_ONLINE },
- { 0x101014, 1, RI_ALL_ONLINE }, { 0x101030, 1, RI_ALL_ONLINE },
- { 0x101040, 1, RI_ALL_ONLINE }, { 0x102058, 1, RI_ALL_ONLINE },
- { 0x102080, 16, RI_ALL_ONLINE }, { 0x103004, 2, RI_ALL_ONLINE },
- { 0x103068, 1, RI_ALL_ONLINE }, { 0x103078, 1, RI_ALL_ONLINE },
- { 0x103088, 1, RI_ALL_ONLINE }, { 0x10309c, 2, RI_E1H_ONLINE },
+ { 0xa600, 5, RI_E1HE2_ONLINE }, { 0xa618, 1, RI_E1HE2_ONLINE },
+ { 0xa714, 1, RI_E2_ONLINE }, { 0xa720, 1, RI_E2_ONLINE },
+ { 0xa750, 1, RI_E2_ONLINE }, { 0xc09c, 1, RI_E1E1H_ONLINE },
+ { 0x103b0, 1, RI_ALL_ONLINE }, { 0x103c0, 1, RI_ALL_ONLINE },
+ { 0x103d0, 1, RI_E1H_ONLINE }, { 0x183bc, 1, RI_E2_ONLINE },
+ { 0x183cc, 1, RI_E2_ONLINE }, { 0x2021c, 11, RI_ALL_ONLINE },
+ { 0x202a8, 1, RI_ALL_ONLINE }, { 0x202b8, 1, RI_ALL_ONLINE },
+ { 0x20404, 1, RI_ALL_ONLINE }, { 0x2040c, 2, RI_ALL_ONLINE },
+ { 0x2041c, 2, RI_ALL_ONLINE }, { 0x40154, 14, RI_ALL_ONLINE },
+ { 0x40198, 1, RI_ALL_ONLINE }, { 0x404ac, 1, RI_ALL_ONLINE },
+ { 0x404bc, 1, RI_ALL_ONLINE }, { 0x42290, 1, RI_ALL_ONLINE },
+ { 0x422a0, 1, RI_ALL_ONLINE }, { 0x422b0, 1, RI_ALL_ONLINE },
+ { 0x42548, 1, RI_ALL_ONLINE }, { 0x42550, 1, RI_ALL_ONLINE },
+ { 0x42558, 1, RI_ALL_ONLINE }, { 0x50160, 8, RI_ALL_ONLINE },
+ { 0x501d0, 1, RI_ALL_ONLINE }, { 0x501e0, 1, RI_ALL_ONLINE },
+ { 0x50204, 1, RI_ALL_ONLINE }, { 0x5020c, 2, RI_ALL_ONLINE },
+ { 0x5021c, 1, RI_ALL_ONLINE }, { 0x60090, 1, RI_ALL_ONLINE },
+ { 0x6011c, 1, RI_ALL_ONLINE }, { 0x6012c, 1, RI_ALL_ONLINE },
+ { 0xc101c, 1, RI_ALL_ONLINE }, { 0xc102c, 1, RI_ALL_ONLINE },
+ { 0xc2290, 1, RI_ALL_ONLINE }, { 0xc22a0, 1, RI_ALL_ONLINE },
+ { 0xc22b0, 1, RI_ALL_ONLINE }, { 0xc2548, 1, RI_ALL_ONLINE },
+ { 0xc2550, 1, RI_ALL_ONLINE }, { 0xc2558, 1, RI_ALL_ONLINE },
+ { 0xc4294, 1, RI_ALL_ONLINE }, { 0xc42a4, 1, RI_ALL_ONLINE },
+ { 0xc42b4, 1, RI_ALL_ONLINE }, { 0xc4550, 1, RI_ALL_ONLINE },
+ { 0xc4558, 1, RI_ALL_ONLINE }, { 0xc4560, 1, RI_ALL_ONLINE },
+ { 0xd016c, 8, RI_ALL_ONLINE }, { 0xd01d8, 1, RI_ALL_ONLINE },
+ { 0xd01e8, 1, RI_ALL_ONLINE }, { 0xd0204, 1, RI_ALL_ONLINE },
+ { 0xd020c, 3, RI_ALL_ONLINE }, { 0xe0154, 8, RI_ALL_ONLINE },
+ { 0xe01c8, 1, RI_ALL_ONLINE }, { 0xe01d8, 1, RI_ALL_ONLINE },
+ { 0xe0204, 1, RI_ALL_ONLINE }, { 0xe020c, 2, RI_ALL_ONLINE },
+ { 0xe021c, 2, RI_ALL_ONLINE }, { 0x101014, 1, RI_ALL_ONLINE },
+ { 0x101030, 1, RI_ALL_ONLINE }, { 0x101040, 1, RI_ALL_ONLINE },
+ { 0x102058, 1, RI_ALL_ONLINE }, { 0x102080, 16, RI_ALL_ONLINE },
+ { 0x103004, 2, RI_ALL_ONLINE }, { 0x103068, 1, RI_ALL_ONLINE },
+ { 0x103078, 1, RI_ALL_ONLINE }, { 0x103088, 1, RI_ALL_ONLINE },
+ { 0x10309c, 2, RI_E1HE2_ONLINE }, { 0x1030b8, 2, RI_E2_ONLINE },
+ { 0x1030cc, 1, RI_E2_ONLINE }, { 0x1030e0, 1, RI_E2_ONLINE },
{ 0x104004, 1, RI_ALL_ONLINE }, { 0x104018, 1, RI_ALL_ONLINE },
{ 0x104020, 1, RI_ALL_ONLINE }, { 0x10403c, 1, RI_ALL_ONLINE },
{ 0x1040fc, 1, RI_ALL_ONLINE }, { 0x10410c, 1, RI_ALL_ONLINE },
{ 0x104400, 64, RI_ALL_ONLINE }, { 0x104800, 64, RI_ALL_ONLINE },
- { 0x105000, 3, RI_ALL_ONLINE }, { 0x105010, 3, RI_ALL_ONLINE },
- { 0x105020, 3, RI_ALL_ONLINE }, { 0x105030, 3, RI_ALL_ONLINE },
- { 0x105040, 3, RI_ALL_ONLINE }, { 0x105050, 3, RI_ALL_ONLINE },
- { 0x105060, 3, RI_ALL_ONLINE }, { 0x105070, 3, RI_ALL_ONLINE },
- { 0x105080, 3, RI_ALL_ONLINE }, { 0x105090, 3, RI_ALL_ONLINE },
- { 0x1050a0, 3, RI_ALL_ONLINE }, { 0x1050b0, 3, RI_ALL_ONLINE },
- { 0x1050c0, 3, RI_ALL_ONLINE }, { 0x1050d0, 3, RI_ALL_ONLINE },
- { 0x1050e0, 3, RI_ALL_ONLINE }, { 0x1050f0, 3, RI_ALL_ONLINE },
- { 0x105100, 3, RI_ALL_ONLINE }, { 0x105110, 3, RI_ALL_ONLINE },
- { 0x105120, 3, RI_ALL_ONLINE }, { 0x105130, 3, RI_ALL_ONLINE },
- { 0x105140, 3, RI_ALL_ONLINE }, { 0x105150, 3, RI_ALL_ONLINE },
- { 0x105160, 3, RI_ALL_ONLINE }, { 0x105170, 3, RI_ALL_ONLINE },
- { 0x105180, 3, RI_ALL_ONLINE }, { 0x105190, 3, RI_ALL_ONLINE },
- { 0x1051a0, 3, RI_ALL_ONLINE }, { 0x1051b0, 3, RI_ALL_ONLINE },
- { 0x1051c0, 3, RI_ALL_ONLINE }, { 0x1051d0, 3, RI_ALL_ONLINE },
- { 0x1051e0, 3, RI_ALL_ONLINE }, { 0x1051f0, 3, RI_ALL_ONLINE },
- { 0x105200, 3, RI_ALL_ONLINE }, { 0x105210, 3, RI_ALL_ONLINE },
- { 0x105220, 3, RI_ALL_ONLINE }, { 0x105230, 3, RI_ALL_ONLINE },
- { 0x105240, 3, RI_ALL_ONLINE }, { 0x105250, 3, RI_ALL_ONLINE },
- { 0x105260, 3, RI_ALL_ONLINE }, { 0x105270, 3, RI_ALL_ONLINE },
- { 0x105280, 3, RI_ALL_ONLINE }, { 0x105290, 3, RI_ALL_ONLINE },
- { 0x1052a0, 3, RI_ALL_ONLINE }, { 0x1052b0, 3, RI_ALL_ONLINE },
- { 0x1052c0, 3, RI_ALL_ONLINE }, { 0x1052d0, 3, RI_ALL_ONLINE },
- { 0x1052e0, 3, RI_ALL_ONLINE }, { 0x1052f0, 3, RI_ALL_ONLINE },
- { 0x105300, 3, RI_ALL_ONLINE }, { 0x105310, 3, RI_ALL_ONLINE },
- { 0x105320, 3, RI_ALL_ONLINE }, { 0x105330, 3, RI_ALL_ONLINE },
- { 0x105340, 3, RI_ALL_ONLINE }, { 0x105350, 3, RI_ALL_ONLINE },
- { 0x105360, 3, RI_ALL_ONLINE }, { 0x105370, 3, RI_ALL_ONLINE },
- { 0x105380, 3, RI_ALL_ONLINE }, { 0x105390, 3, RI_ALL_ONLINE },
- { 0x1053a0, 3, RI_ALL_ONLINE }, { 0x1053b0, 3, RI_ALL_ONLINE },
- { 0x1053c0, 3, RI_ALL_ONLINE }, { 0x1053d0, 3, RI_ALL_ONLINE },
- { 0x1053e0, 3, RI_ALL_ONLINE }, { 0x1053f0, 3, RI_ALL_ONLINE },
- { 0x108094, 1, RI_ALL_ONLINE }, { 0x1201b0, 2, RI_ALL_ONLINE },
- { 0x12032c, 1, RI_ALL_ONLINE }, { 0x12036c, 3, RI_ALL_ONLINE },
- { 0x120408, 2, RI_ALL_ONLINE }, { 0x120414, 15, RI_ALL_ONLINE },
- { 0x120478, 2, RI_ALL_ONLINE }, { 0x12052c, 1, RI_ALL_ONLINE },
- { 0x120564, 3, RI_ALL_ONLINE }, { 0x12057c, 1, RI_ALL_ONLINE },
- { 0x12058c, 1, RI_ALL_ONLINE }, { 0x120608, 1, RI_E1H_ONLINE },
- { 0x120808, 1, RI_E1_ONLINE }, { 0x12080c, 2, RI_ALL_ONLINE },
+ { 0x105000, 256, RI_ALL_ONLINE }, { 0x108094, 1, RI_E1E1H_ONLINE },
+ { 0x1201b0, 2, RI_ALL_ONLINE }, { 0x12032c, 1, RI_ALL_ONLINE },
+ { 0x12036c, 3, RI_ALL_ONLINE }, { 0x120408, 2, RI_ALL_ONLINE },
+ { 0x120414, 15, RI_ALL_ONLINE }, { 0x120478, 2, RI_ALL_ONLINE },
+ { 0x12052c, 1, RI_ALL_ONLINE }, { 0x120564, 3, RI_ALL_ONLINE },
+ { 0x12057c, 1, RI_ALL_ONLINE }, { 0x12058c, 1, RI_ALL_ONLINE },
+ { 0x120608, 1, RI_E1HE2_ONLINE }, { 0x120738, 1, RI_E2_ONLINE },
+ { 0x120778, 2, RI_E2_ONLINE }, { 0x120808, 3, RI_ALL_ONLINE },
{ 0x120818, 1, RI_ALL_ONLINE }, { 0x120820, 1, RI_ALL_ONLINE },
{ 0x120828, 1, RI_ALL_ONLINE }, { 0x120830, 1, RI_ALL_ONLINE },
{ 0x120838, 1, RI_ALL_ONLINE }, { 0x120840, 1, RI_ALL_ONLINE },
@@ -462,48 +580,50 @@ static const struct reg_addr idle_addrs[IDLE_REGS_COUNT] = {
{ 0x1208d8, 1, RI_ALL_ONLINE }, { 0x1208e0, 1, RI_ALL_ONLINE },
{ 0x1208e8, 1, RI_ALL_ONLINE }, { 0x1208f0, 1, RI_ALL_ONLINE },
{ 0x1208f8, 1, RI_ALL_ONLINE }, { 0x120900, 1, RI_ALL_ONLINE },
- { 0x120908, 1, RI_ALL_ONLINE }, { 0x14005c, 2, RI_ALL_ONLINE },
- { 0x1400d0, 2, RI_ALL_ONLINE }, { 0x1400e0, 1, RI_ALL_ONLINE },
- { 0x1401c8, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE },
- { 0x16101c, 1, RI_ALL_ONLINE }, { 0x16102c, 1, RI_ALL_ONLINE },
- { 0x164014, 2, RI_ALL_ONLINE }, { 0x1640f0, 1, RI_ALL_ONLINE },
- { 0x166290, 1, RI_ALL_ONLINE }, { 0x1662a0, 1, RI_ALL_ONLINE },
- { 0x1662b0, 1, RI_ALL_ONLINE }, { 0x166548, 1, RI_ALL_ONLINE },
- { 0x166550, 1, RI_ALL_ONLINE }, { 0x166558, 1, RI_ALL_ONLINE },
- { 0x168000, 1, RI_ALL_ONLINE }, { 0x168008, 1, RI_ALL_ONLINE },
- { 0x168010, 1, RI_ALL_ONLINE }, { 0x168018, 1, RI_ALL_ONLINE },
- { 0x168028, 2, RI_ALL_ONLINE }, { 0x168058, 4, RI_ALL_ONLINE },
- { 0x168070, 1, RI_ALL_ONLINE }, { 0x168238, 1, RI_ALL_ONLINE },
- { 0x1682d0, 2, RI_ALL_ONLINE }, { 0x1682e0, 1, RI_ALL_ONLINE },
- { 0x168300, 67, RI_ALL_ONLINE }, { 0x168410, 2, RI_ALL_ONLINE },
+ { 0x120908, 1, RI_ALL_ONLINE }, { 0x120940, 5, RI_E2_ONLINE },
+ { 0x130030, 1, RI_E2_ONLINE }, { 0x13004c, 3, RI_E2_ONLINE },
+ { 0x130064, 2, RI_E2_ONLINE }, { 0x13009c, 1, RI_E2_ONLINE },
+ { 0x130130, 1, RI_E2_ONLINE }, { 0x13016c, 1, RI_E2_ONLINE },
+ { 0x130300, 1, RI_E2_ONLINE }, { 0x130480, 1, RI_E2_ONLINE },
+ { 0x14005c, 2, RI_ALL_ONLINE }, { 0x1400d0, 2, RI_ALL_ONLINE },
+ { 0x1400e0, 1, RI_ALL_ONLINE }, { 0x1401c8, 1, RI_ALL_ONLINE },
+ { 0x140200, 6, RI_ALL_ONLINE }, { 0x16101c, 1, RI_ALL_ONLINE },
+ { 0x16102c, 1, RI_ALL_ONLINE }, { 0x164014, 2, RI_ALL_ONLINE },
+ { 0x1640f0, 1, RI_ALL_ONLINE }, { 0x166290, 1, RI_ALL_ONLINE },
+ { 0x1662a0, 1, RI_ALL_ONLINE }, { 0x1662b0, 1, RI_ALL_ONLINE },
+ { 0x166548, 1, RI_ALL_ONLINE }, { 0x166550, 1, RI_ALL_ONLINE },
+ { 0x166558, 1, RI_ALL_ONLINE }, { 0x168000, 1, RI_ALL_ONLINE },
+ { 0x168008, 1, RI_ALL_ONLINE }, { 0x168010, 1, RI_ALL_ONLINE },
+ { 0x168018, 1, RI_ALL_ONLINE }, { 0x168028, 2, RI_ALL_ONLINE },
+ { 0x168058, 4, RI_ALL_ONLINE }, { 0x168070, 1, RI_ALL_ONLINE },
+ { 0x168238, 1, RI_ALL_ONLINE }, { 0x1682d0, 2, RI_ALL_ONLINE },
+ { 0x1682e0, 1, RI_ALL_ONLINE }, { 0x168300, 2, RI_E1E1H_ONLINE },
+ { 0x168308, 65, RI_ALL_ONLINE }, { 0x168410, 2, RI_ALL_ONLINE },
{ 0x168438, 1, RI_ALL_ONLINE }, { 0x168448, 1, RI_ALL_ONLINE },
{ 0x168a00, 128, RI_ALL_ONLINE }, { 0x16e200, 128, RI_E1H_ONLINE },
- { 0x16e404, 2, RI_E1H_ONLINE }, { 0x16e584, 70, RI_E1H_ONLINE },
- { 0x1700a4, 1, RI_ALL_ONLINE }, { 0x1700ac, 2, RI_ALL_ONLINE },
- { 0x1700c0, 1, RI_ALL_ONLINE }, { 0x170174, 1, RI_ALL_ONLINE },
- { 0x170184, 1, RI_ALL_ONLINE }, { 0x1800f4, 1, RI_ALL_ONLINE },
- { 0x180104, 1, RI_ALL_ONLINE }, { 0x180114, 1, RI_ALL_ONLINE },
- { 0x180124, 1, RI_ALL_ONLINE }, { 0x18026c, 1, RI_ALL_ONLINE },
- { 0x1802a0, 1, RI_ALL_ONLINE }, { 0x1a1000, 1, RI_ALL_ONLINE },
- { 0x1aa000, 1, RI_E1H_ONLINE }, { 0x1b8000, 1, RI_ALL_ONLINE },
- { 0x1b8040, 1, RI_ALL_ONLINE }, { 0x1b8080, 1, RI_ALL_ONLINE },
- { 0x1b80c0, 1, RI_ALL_ONLINE }, { 0x200104, 1, RI_ALL_ONLINE },
- { 0x200114, 1, RI_ALL_ONLINE }, { 0x200124, 1, RI_ALL_ONLINE },
- { 0x200134, 1, RI_ALL_ONLINE }, { 0x20026c, 1, RI_ALL_ONLINE },
- { 0x2002a0, 1, RI_ALL_ONLINE }, { 0x221000, 1, RI_ALL_ONLINE },
- { 0x227000, 1, RI_E1H_ONLINE }, { 0x238000, 1, RI_ALL_ONLINE },
- { 0x238040, 1, RI_ALL_ONLINE }, { 0x238080, 1, RI_ALL_ONLINE },
- { 0x2380c0, 1, RI_ALL_ONLINE }, { 0x280104, 1, RI_ALL_ONLINE },
- { 0x280114, 1, RI_ALL_ONLINE }, { 0x280124, 1, RI_ALL_ONLINE },
- { 0x280134, 1, RI_ALL_ONLINE }, { 0x28026c, 1, RI_ALL_ONLINE },
- { 0x2802a0, 1, RI_ALL_ONLINE }, { 0x2a1000, 1, RI_ALL_ONLINE },
- { 0x2a9000, 1, RI_E1H_ONLINE }, { 0x2b8000, 1, RI_ALL_ONLINE },
- { 0x2b8040, 1, RI_ALL_ONLINE }, { 0x2b8080, 1, RI_ALL_ONLINE },
- { 0x2b80c0, 1, RI_ALL_ONLINE }, { 0x300104, 1, RI_ALL_ONLINE },
+ { 0x16e404, 2, RI_E1H_ONLINE }, { 0x16e584, 64, RI_E1H_ONLINE },
+ { 0x16e684, 2, RI_E1HE2_ONLINE }, { 0x16e68c, 4, RI_E1H_ONLINE },
+ { 0x16e6fc, 4, RI_E2_ONLINE }, { 0x1700a4, 1, RI_ALL_ONLINE },
+ { 0x1700ac, 2, RI_ALL_ONLINE }, { 0x1700c0, 1, RI_ALL_ONLINE },
+ { 0x170174, 1, RI_ALL_ONLINE }, { 0x170184, 1, RI_ALL_ONLINE },
+ { 0x1800f4, 1, RI_ALL_ONLINE }, { 0x180104, 1, RI_ALL_ONLINE },
+ { 0x180114, 1, RI_ALL_ONLINE }, { 0x180124, 1, RI_ALL_ONLINE },
+ { 0x18026c, 1, RI_ALL_ONLINE }, { 0x1802a0, 1, RI_ALL_ONLINE },
+ { 0x1b8000, 1, RI_ALL_ONLINE }, { 0x1b8040, 1, RI_ALL_ONLINE },
+ { 0x1b8080, 1, RI_ALL_ONLINE }, { 0x1b80c0, 1, RI_ALL_ONLINE },
+ { 0x200104, 1, RI_ALL_ONLINE }, { 0x200114, 1, RI_ALL_ONLINE },
+ { 0x200124, 1, RI_ALL_ONLINE }, { 0x200134, 1, RI_ALL_ONLINE },
+ { 0x20026c, 1, RI_ALL_ONLINE }, { 0x2002a0, 1, RI_ALL_ONLINE },
+ { 0x238000, 1, RI_ALL_ONLINE }, { 0x238040, 1, RI_ALL_ONLINE },
+ { 0x238080, 1, RI_ALL_ONLINE }, { 0x2380c0, 1, RI_ALL_ONLINE },
+ { 0x280104, 1, RI_ALL_ONLINE }, { 0x280114, 1, RI_ALL_ONLINE },
+ { 0x280124, 1, RI_ALL_ONLINE }, { 0x280134, 1, RI_ALL_ONLINE },
+ { 0x28026c, 1, RI_ALL_ONLINE }, { 0x2802a0, 1, RI_ALL_ONLINE },
+ { 0x2b8000, 1, RI_ALL_ONLINE }, { 0x2b8040, 1, RI_ALL_ONLINE },
+ { 0x2b8080, 1, RI_ALL_ONLINE }, { 0x300104, 1, RI_ALL_ONLINE },
{ 0x300114, 1, RI_ALL_ONLINE }, { 0x300124, 1, RI_ALL_ONLINE },
{ 0x300134, 1, RI_ALL_ONLINE }, { 0x30026c, 1, RI_ALL_ONLINE },
- { 0x3002a0, 1, RI_ALL_ONLINE }, { 0x321000, 1, RI_ALL_ONLINE },
- { 0x328960, 1, RI_E1H_ONLINE }, { 0x338000, 1, RI_ALL_ONLINE },
+ { 0x3002a0, 1, RI_ALL_ONLINE }, { 0x338000, 1, RI_ALL_ONLINE },
{ 0x338040, 1, RI_ALL_ONLINE }, { 0x338080, 1, RI_ALL_ONLINE },
{ 0x3380c0, 1, RI_ALL_ONLINE }
};
@@ -515,7 +635,6 @@ static const struct wreg_addr wreg_addrs_e1[WREGS_COUNT_E1] = {
{ 0x1b0c00, 192, 1, read_reg_e1_0, RI_E1_OFFLINE }
};
-
#define WREGS_COUNT_E1H 1
static const u32 read_reg_e1h_0[] = { 0x1b1040, 0x1b1000 };
@@ -530,22 +649,53 @@ static const struct wreg_addr wreg_addrs_e2[WREGS_COUNT_E2] = {
{ 0x1b0c00, 128, 2, read_reg_e2_0, RI_E2_OFFLINE }
};
-static const struct dump_sign dump_sign_all = { 0x49aa93ee, 0x40835, 0x22 };
-
+static const struct dump_sign dump_sign_all = { 0x4d18b0a4, 0x60010, 0x3a };
#define TIMER_REGS_COUNT_E1 2
-static const u32 timer_status_regs_e1[TIMER_REGS_COUNT_E1] =
- { 0x164014, 0x164018 };
-static const u32 timer_scan_regs_e1[TIMER_REGS_COUNT_E1] =
- { 0x1640d0, 0x1640d4 };
+static const u32 timer_status_regs_e1[TIMER_REGS_COUNT_E1] = {
+ 0x164014, 0x164018 };
+static const u32 timer_scan_regs_e1[TIMER_REGS_COUNT_E1] = {
+ 0x1640d0, 0x1640d4 };
#define TIMER_REGS_COUNT_E1H 2
-static const u32 timer_status_regs_e1h[TIMER_REGS_COUNT_E1H] =
- { 0x164014, 0x164018 };
-static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] =
- { 0x1640d0, 0x1640d4 };
+static const u32 timer_status_regs_e1h[TIMER_REGS_COUNT_E1H] = {
+ 0x164014, 0x164018 };
+static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] = {
+ 0x1640d0, 0x1640d4 };
+
+#define TIMER_REGS_COUNT_E2 2
+
+static const u32 timer_status_regs_e2[TIMER_REGS_COUNT_E2] = {
+ 0x164014, 0x164018 };
+static const u32 timer_scan_regs_e2[TIMER_REGS_COUNT_E2] = {
+ 0x1640d0, 0x1640d4 };
+
+#define PAGE_MODE_VALUES_E1 0
+
+#define PAGE_READ_REGS_E1 0
+
+#define PAGE_WRITE_REGS_E1 0
+
+static const u32 page_vals_e1[] = { 0 };
+
+static const u32 page_write_regs_e1[] = { 0 };
+
+static const struct reg_addr page_read_regs_e1[] = { { 0x0, 0, RI_E1_ONLINE } };
+
+#define PAGE_MODE_VALUES_E1H 0
+
+#define PAGE_READ_REGS_E1H 0
+
+#define PAGE_WRITE_REGS_E1H 0
+
+static const u32 page_vals_e1h[] = { 0 };
+
+static const u32 page_write_regs_e1h[] = { 0 };
+
+static const struct reg_addr page_read_regs_e1h[] = {
+ { 0x0, 0, RI_E1H_ONLINE } };
#define PAGE_MODE_VALUES_E2 2
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index d02ffbdc9f0e..5b44a8b48509 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -24,6 +24,144 @@
#include "bnx2x.h"
#include "bnx2x_cmn.h"
#include "bnx2x_dump.h"
+#include "bnx2x_init.h"
+
+/* Note: in the format strings below %s is replaced by the queue-name which is
+ * either its index or 'fcoe' for the fcoe queue. Make sure the format string
+ * length does not exceed ETH_GSTRING_LEN - MAX_QUEUE_NAME_LEN + 2
+ */
+#define MAX_QUEUE_NAME_LEN 4
+static const struct {
+ long offset;
+ int size;
+ char string[ETH_GSTRING_LEN];
+} bnx2x_q_stats_arr[] = {
+/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" },
+ { Q_STATS_OFFSET32(error_bytes_received_hi),
+ 8, "[%s]: rx_error_bytes" },
+ { Q_STATS_OFFSET32(total_unicast_packets_received_hi),
+ 8, "[%s]: rx_ucast_packets" },
+ { Q_STATS_OFFSET32(total_multicast_packets_received_hi),
+ 8, "[%s]: rx_mcast_packets" },
+ { Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
+ 8, "[%s]: rx_bcast_packets" },
+ { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" },
+ { Q_STATS_OFFSET32(rx_err_discard_pkt),
+ 4, "[%s]: rx_phy_ip_err_discards"},
+ { Q_STATS_OFFSET32(rx_skb_alloc_failed),
+ 4, "[%s]: rx_skb_alloc_discard" },
+ { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" },
+
+/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" },
+ { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+ 8, "[%s]: tx_ucast_packets" },
+ { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+ 8, "[%s]: tx_mcast_packets" },
+ { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+ 8, "[%s]: tx_bcast_packets" }
+};
+
+#define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr)
+
+static const struct {
+ long offset;
+ int size;
+ u32 flags;
+#define STATS_FLAGS_PORT 1
+#define STATS_FLAGS_FUNC 2
+#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
+ char string[ETH_GSTRING_LEN];
+} bnx2x_stats_arr[] = {
+/* 1 */ { STATS_OFFSET32(total_bytes_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_bytes" },
+ { STATS_OFFSET32(error_bytes_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_error_bytes" },
+ { STATS_OFFSET32(total_unicast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
+ { STATS_OFFSET32(total_multicast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
+ { STATS_OFFSET32(total_broadcast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
+ { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
+ 8, STATS_FLAGS_PORT, "rx_crc_errors" },
+ { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
+ 8, STATS_FLAGS_PORT, "rx_align_errors" },
+ { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
+ 8, STATS_FLAGS_PORT, "rx_undersize_packets" },
+ { STATS_OFFSET32(etherstatsoverrsizepkts_hi),
+ 8, STATS_FLAGS_PORT, "rx_oversize_packets" },
+/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
+ 8, STATS_FLAGS_PORT, "rx_fragments" },
+ { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
+ 8, STATS_FLAGS_PORT, "rx_jabbers" },
+ { STATS_OFFSET32(no_buff_discard_hi),
+ 8, STATS_FLAGS_BOTH, "rx_discards" },
+ { STATS_OFFSET32(mac_filter_discard),
+ 4, STATS_FLAGS_PORT, "rx_filtered_packets" },
+ { STATS_OFFSET32(xxoverflow_discard),
+ 4, STATS_FLAGS_PORT, "rx_fw_discards" },
+ { STATS_OFFSET32(brb_drop_hi),
+ 8, STATS_FLAGS_PORT, "rx_brb_discard" },
+ { STATS_OFFSET32(brb_truncate_hi),
+ 8, STATS_FLAGS_PORT, "rx_brb_truncate" },
+ { STATS_OFFSET32(pause_frames_received_hi),
+ 8, STATS_FLAGS_PORT, "rx_pause_frames" },
+ { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
+ 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
+ { STATS_OFFSET32(nig_timer_max),
+ 4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
+/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
+ 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
+ { STATS_OFFSET32(rx_skb_alloc_failed),
+ 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
+ { STATS_OFFSET32(hw_csum_err),
+ 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
+
+ { STATS_OFFSET32(total_bytes_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_bytes" },
+ { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
+ 8, STATS_FLAGS_PORT, "tx_error_bytes" },
+ { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
+ { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
+ { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
+ { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
+ 8, STATS_FLAGS_PORT, "tx_mac_errors" },
+ { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
+ 8, STATS_FLAGS_PORT, "tx_carrier_errors" },
+/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
+ 8, STATS_FLAGS_PORT, "tx_single_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
+ 8, STATS_FLAGS_PORT, "tx_multi_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
+ 8, STATS_FLAGS_PORT, "tx_deferred" },
+ { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_excess_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_late_collisions" },
+ { STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_total_collisions" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
+/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
+ { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
+ { STATS_OFFSET32(etherstatspktsover1522octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
+ { STATS_OFFSET32(pause_frames_sent_hi),
+ 8, STATS_FLAGS_PORT, "tx_pause_frames" }
+};
+
+#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr)
static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -45,14 +183,9 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->speed = bp->link_params.req_line_speed[cfg_idx];
cmd->duplex = bp->link_params.req_duplex[cfg_idx];
}
- if (IS_MF(bp)) {
- u16 vn_max_rate = ((bp->mf_config[BP_VN(bp)] &
- FUNC_MF_CFG_MAX_BW_MASK) >> FUNC_MF_CFG_MAX_BW_SHIFT) *
- 100;
- if (vn_max_rate < cmd->speed)
- cmd->speed = vn_max_rate;
- }
+ if (IS_MF(bp))
+ cmd->speed = bnx2x_get_mf_speed(bp);
if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
cmd->port = PORT_TP;
@@ -87,18 +220,57 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2x *bp = netdev_priv(dev);
u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config;
+ u32 speed;
- if (IS_MF(bp))
+ if (IS_MF_SD(bp))
return 0;
DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
- DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n"
- DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
- DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
+ " supported 0x%x advertising 0x%x speed %d speed_hi %d\n"
+ " duplex %d port %d phy_address %d transceiver %d\n"
+ " autoneg %d maxtxpkt %d maxrxpkt %d\n",
cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+ cmd->speed_hi,
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+ speed = cmd->speed;
+ speed |= (cmd->speed_hi << 16);
+
+ if (IS_MF_SI(bp)) {
+ u32 param = 0;
+ u32 line_speed = bp->link_vars.line_speed;
+
+ /* use 10G if no link detected */
+ if (!line_speed)
+ line_speed = 10000;
+
+ if (bp->common.bc_ver < REQ_BC_VER_4_SET_MF_BW) {
+ BNX2X_DEV_INFO("To set speed BC %X or higher "
+ "is required, please upgrade BC\n",
+ REQ_BC_VER_4_SET_MF_BW);
+ return -EINVAL;
+ }
+ if (line_speed < speed) {
+ BNX2X_DEV_INFO("New speed should be less or equal "
+ "to actual line speed\n");
+ return -EINVAL;
+ }
+ /* load old values */
+ param = bp->mf_config[BP_VN(bp)];
+
+ /* leave only MIN value */
+ param &= FUNC_MF_CFG_MIN_BW_MASK;
+
+ /* set new MAX value */
+ param |= (((speed * 100) / line_speed)
+ << FUNC_MF_CFG_MAX_BW_SHIFT)
+ & FUNC_MF_CFG_MAX_BW_MASK;
+
+ bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, param);
+ return 0;
+ }
+
cfg_idx = bnx2x_get_link_cfg_idx(bp);
old_multi_phy_config = bp->link_params.multi_phy_config;
switch (cmd->port) {
@@ -168,8 +340,6 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
} else { /* forced speed */
/* advertise the requested speed and duplex if supported */
- u32 speed = cmd->speed;
- speed |= (cmd->speed_hi << 16);
switch (speed) {
case SPEED_10:
if (cmd->duplex == DUPLEX_FULL) {
@@ -303,7 +473,7 @@ static int bnx2x_get_regs_len(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
int regdump_len = 0;
- int i;
+ int i, j, k;
if (CHIP_IS_E1(bp)) {
for (i = 0; i < REGS_COUNT; i++)
@@ -333,6 +503,15 @@ static int bnx2x_get_regs_len(struct net_device *dev)
if (IS_E2_ONLINE(wreg_addrs_e2[i].info))
regdump_len += wreg_addrs_e2[i].size *
(1 + wreg_addrs_e2[i].read_regs_count);
+
+ for (i = 0; i < PAGE_MODE_VALUES_E2; i++)
+ for (j = 0; j < PAGE_WRITE_REGS_E2; j++) {
+ for (k = 0; k < PAGE_READ_REGS_E2; k++)
+ if (IS_E2_ONLINE(page_read_regs_e2[k].
+ info))
+ regdump_len +=
+ page_read_regs_e2[k].size;
+ }
}
regdump_len *= 4;
regdump_len += sizeof(struct dump_hdr);
@@ -370,6 +549,12 @@ static void bnx2x_get_regs(struct net_device *dev,
if (!netif_running(bp->dev))
return;
+ /* Disable parity attentions as long as following dump may
+ * cause false alarms by reading never written registers. We
+ * will re-enable parity attentions right after the dump.
+ */
+ bnx2x_disable_blocks_parity(bp);
+
dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
dump_hdr.dump_sign = dump_sign_all;
dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
@@ -411,6 +596,10 @@ static void bnx2x_get_regs(struct net_device *dev,
bnx2x_read_pages_regs_e2(bp, p);
}
+ /* Re-enable parity attentions */
+ bnx2x_clear_blocks_parity(bp);
+ if (CHIP_PARITY_ENABLED(bp))
+ bnx2x_enable_blocks_parity(bp);
}
#define PHY_FW_VER_LEN 20
@@ -1286,7 +1475,7 @@ static int bnx2x_test_registers(struct bnx2x *bp)
save_val = REG_RD(bp, offset);
- REG_WR(bp, offset, (wr_val & mask));
+ REG_WR(bp, offset, wr_val & mask);
val = REG_RD(bp, offset);
@@ -1499,8 +1688,15 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
* updates that have been performed while interrupts were
* disabled.
*/
- if (bp->common.int_block == INT_BLOCK_IGU)
+ if (bp->common.int_block == INT_BLOCK_IGU) {
+ /* Disable local BHes to prevent a dead-lock situation between
+ * sch_direct_xmit() and bnx2x_run_loopback() (calling
+ * bnx2x_tx_int()), as both are taking netif_tx_lock().
+ */
+ local_bh_disable();
bnx2x_tx_int(fp_tx);
+ local_bh_enable();
+ }
rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
if (rx_idx != rx_start_idx + num_pkts)
@@ -1650,7 +1846,7 @@ static int bnx2x_test_intr(struct bnx2x *bp)
config->hdr.client_id = bp->fp->cl_id;
config->hdr.reserved1 = 0;
- bp->set_mac_pending++;
+ bp->set_mac_pending = 1;
smp_wmb();
rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
@@ -1748,134 +1944,6 @@ static void bnx2x_self_test(struct net_device *dev,
#endif
}
-static const struct {
- long offset;
- int size;
- u8 string[ETH_GSTRING_LEN];
-} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = {
-/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
- { Q_STATS_OFFSET32(error_bytes_received_hi),
- 8, "[%d]: rx_error_bytes" },
- { Q_STATS_OFFSET32(total_unicast_packets_received_hi),
- 8, "[%d]: rx_ucast_packets" },
- { Q_STATS_OFFSET32(total_multicast_packets_received_hi),
- 8, "[%d]: rx_mcast_packets" },
- { Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
- 8, "[%d]: rx_bcast_packets" },
- { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" },
- { Q_STATS_OFFSET32(rx_err_discard_pkt),
- 4, "[%d]: rx_phy_ip_err_discards"},
- { Q_STATS_OFFSET32(rx_skb_alloc_failed),
- 4, "[%d]: rx_skb_alloc_discard" },
- { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
-
-/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" },
- { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
- 8, "[%d]: tx_ucast_packets" },
- { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
- 8, "[%d]: tx_mcast_packets" },
- { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
- 8, "[%d]: tx_bcast_packets" }
-};
-
-static const struct {
- long offset;
- int size;
- u32 flags;
-#define STATS_FLAGS_PORT 1
-#define STATS_FLAGS_FUNC 2
-#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
- u8 string[ETH_GSTRING_LEN];
-} bnx2x_stats_arr[BNX2X_NUM_STATS] = {
-/* 1 */ { STATS_OFFSET32(total_bytes_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_bytes" },
- { STATS_OFFSET32(error_bytes_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_error_bytes" },
- { STATS_OFFSET32(total_unicast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
- { STATS_OFFSET32(total_multicast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
- { STATS_OFFSET32(total_broadcast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
- { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
- 8, STATS_FLAGS_PORT, "rx_crc_errors" },
- { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
- 8, STATS_FLAGS_PORT, "rx_align_errors" },
- { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
- 8, STATS_FLAGS_PORT, "rx_undersize_packets" },
- { STATS_OFFSET32(etherstatsoverrsizepkts_hi),
- 8, STATS_FLAGS_PORT, "rx_oversize_packets" },
-/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
- 8, STATS_FLAGS_PORT, "rx_fragments" },
- { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
- 8, STATS_FLAGS_PORT, "rx_jabbers" },
- { STATS_OFFSET32(no_buff_discard_hi),
- 8, STATS_FLAGS_BOTH, "rx_discards" },
- { STATS_OFFSET32(mac_filter_discard),
- 4, STATS_FLAGS_PORT, "rx_filtered_packets" },
- { STATS_OFFSET32(xxoverflow_discard),
- 4, STATS_FLAGS_PORT, "rx_fw_discards" },
- { STATS_OFFSET32(brb_drop_hi),
- 8, STATS_FLAGS_PORT, "rx_brb_discard" },
- { STATS_OFFSET32(brb_truncate_hi),
- 8, STATS_FLAGS_PORT, "rx_brb_truncate" },
- { STATS_OFFSET32(pause_frames_received_hi),
- 8, STATS_FLAGS_PORT, "rx_pause_frames" },
- { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
- 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
- { STATS_OFFSET32(nig_timer_max),
- 4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
-/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
- 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
- { STATS_OFFSET32(rx_skb_alloc_failed),
- 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
- { STATS_OFFSET32(hw_csum_err),
- 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
-
- { STATS_OFFSET32(total_bytes_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_bytes" },
- { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
- 8, STATS_FLAGS_PORT, "tx_error_bytes" },
- { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
- { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
- { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
- { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
- 8, STATS_FLAGS_PORT, "tx_mac_errors" },
- { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
- 8, STATS_FLAGS_PORT, "tx_carrier_errors" },
-/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
- 8, STATS_FLAGS_PORT, "tx_single_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
- 8, STATS_FLAGS_PORT, "tx_multi_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
- 8, STATS_FLAGS_PORT, "tx_deferred" },
- { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_excess_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_late_collisions" },
- { STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_total_collisions" },
- { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
- 8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
- 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
- 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
- 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
-/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
- 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
- { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
- 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
- { STATS_OFFSET32(etherstatspktsover1522octets_hi),
- 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
- { STATS_OFFSET32(pause_frames_sent_hi),
- 8, STATS_FLAGS_PORT, "tx_pause_frames" }
-};
-
#define IS_PORT_STAT(i) \
((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
@@ -1890,7 +1958,8 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
switch (stringset) {
case ETH_SS_STATS:
if (is_multi(bp)) {
- num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
+ num_stats = BNX2X_NUM_STAT_QUEUES(bp) *
+ BNX2X_NUM_Q_STATS;
if (!IS_MF_MODE_STAT(bp))
num_stats += BNX2X_NUM_STATS;
} else {
@@ -1916,15 +1985,25 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnx2x *bp = netdev_priv(dev);
int i, j, k;
+ char queue_name[MAX_QUEUE_NAME_LEN+1];
switch (stringset) {
case ETH_SS_STATS:
if (is_multi(bp)) {
k = 0;
- for_each_queue(bp, i) {
+ for_each_napi_queue(bp, i) {
+ memset(queue_name, 0, sizeof(queue_name));
+
+ if (IS_FCOE_IDX(i))
+ sprintf(queue_name, "fcoe");
+ else
+ sprintf(queue_name, "%d", i);
+
for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
- sprintf(buf + (k + j)*ETH_GSTRING_LEN,
- bnx2x_q_stats_arr[j].string, i);
+ snprintf(buf + (k + j)*ETH_GSTRING_LEN,
+ ETH_GSTRING_LEN,
+ bnx2x_q_stats_arr[j].string,
+ queue_name);
k += BNX2X_NUM_Q_STATS;
}
if (IS_MF_MODE_STAT(bp))
@@ -1958,7 +2037,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
if (is_multi(bp)) {
k = 0;
- for_each_queue(bp, i) {
+ for_each_napi_queue(bp, i) {
hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
if (bnx2x_q_stats_arr[j].size == 0) {
diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
index 18c8e23a0e82..6238d4f63989 100644
--- a/drivers/net/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/bnx2x/bnx2x_hsi.h
@@ -244,7 +244,14 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
u16 xgxs_config_tx[4]; /* 0x1A0 */
- u32 Reserved1[57]; /* 0x1A8 */
+ u32 Reserved1[56]; /* 0x1A8 */
+ u32 default_cfg; /* 0x288 */
+ /* Enable BAM on KR */
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK 0x00100000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT 20
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED 0x00000000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED 0x00100000
+
u32 speed_capability_mask2; /* 0x28C */
#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK 0x0000FFFF
#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT 0
@@ -427,7 +434,12 @@ struct shared_feat_cfg { /* NVRAM Offset */
#define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_DISABLED 0x00000000
#define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED 0x00000002
-#define SHARED_FEATURE_MF_MODE_DISABLED 0x00000100
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_MASK 0x00000700
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_SHIFT 8
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED 0x00000000
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_FORCED_SF 0x00000100
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200
+#define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300
};
@@ -672,7 +684,7 @@ struct shm_dev_info { /* size */
#define E1VN_MAX 1
#define E1HVN_MAX 4
-
+#define E2_VF_MAX 64
/* This value (in milliseconds) determines the frequency of the driver
* issuing the PULSE message code. The firmware monitors this periodic
* pulse to determine when to switch to an OS-absent mode. */
@@ -808,6 +820,11 @@ struct drv_func_mb {
#define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL 0xa1000000
#define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL 0x00050234
+#define DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG 0xb0000000
+#define DRV_MSG_CODE_DCBX_PMF_DRV_OK 0xb2000000
+#define DRV_MSG_CODE_SET_MF_BW 0xe0000000
+#define REQ_BC_VER_4_SET_MF_BW 0x00060202
+#define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000
#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000
#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000
#define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000
@@ -881,6 +898,7 @@ struct drv_func_mb {
u32 drv_status;
#define DRV_STATUS_PMF 0x00000001
+#define DRV_STATUS_SET_MF_BW 0x00000004
#define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00
#define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100
@@ -889,6 +907,8 @@ struct drv_func_mb {
#define DRV_STATUS_DCC_RESERVED1 0x00000800
#define DRV_STATUS_DCC_SET_PROTOCOL 0x00001000
#define DRV_STATUS_DCC_SET_PRIORITY 0x00002000
+#define DRV_STATUS_DCBX_EVENT_MASK 0x000f0000
+#define DRV_STATUS_DCBX_NEGOTIATION_RESULTS 0x00010000
u32 virt_mac_upper;
#define VIRT_MAC_SIGN_MASK 0xffff0000
@@ -981,12 +1001,43 @@ struct func_mf_cfg {
};
+/* This structure is not applicable and should not be accessed on 57711 */
+struct func_ext_cfg {
+ u32 func_cfg;
+#define MACP_FUNC_CFG_FLAGS_MASK 0x000000FF
+#define MACP_FUNC_CFG_FLAGS_SHIFT 0
+#define MACP_FUNC_CFG_FLAGS_ENABLED 0x00000001
+#define MACP_FUNC_CFG_FLAGS_ETHERNET 0x00000002
+#define MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD 0x00000004
+#define MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD 0x00000008
+
+ u32 iscsi_mac_addr_upper;
+ u32 iscsi_mac_addr_lower;
+
+ u32 fcoe_mac_addr_upper;
+ u32 fcoe_mac_addr_lower;
+
+ u32 fcoe_wwn_port_name_upper;
+ u32 fcoe_wwn_port_name_lower;
+
+ u32 fcoe_wwn_node_name_upper;
+ u32 fcoe_wwn_node_name_lower;
+
+ u32 preserve_data;
+#define MF_FUNC_CFG_PRESERVE_L2_MAC (1<<0)
+#define MF_FUNC_CFG_PRESERVE_ISCSI_MAC (1<<1)
+#define MF_FUNC_CFG_PRESERVE_FCOE_MAC (1<<2)
+#define MF_FUNC_CFG_PRESERVE_FCOE_WWN_P (1<<3)
+#define MF_FUNC_CFG_PRESERVE_FCOE_WWN_N (1<<4)
+};
+
struct mf_cfg {
struct shared_mf_cfg shared_mf_config;
struct port_mf_cfg port_mf_config[PORT_MAX];
struct func_mf_cfg func_mf_config[E1H_FUNC_MAX];
+ struct func_ext_cfg func_ext_config[E1H_FUNC_MAX];
};
@@ -1042,6 +1093,251 @@ struct fw_flr_mb {
struct fw_flr_ack ack;
};
+/**** SUPPORT FOR SHMEM ARRRAYS ***
+ * The SHMEM HSI is aligned on 32 bit boundaries which makes it difficult to
+ * define arrays with storage types smaller then unsigned dwords.
+ * The macros below add generic support for SHMEM arrays with numeric elements
+ * that can span 2,4,8 or 16 bits. The array underlying type is a 32 bit dword
+ * array with individual bit-filed elements accessed using shifts and masks.
+ *
+ */
+
+/* eb is the bitwidth of a single element */
+#define SHMEM_ARRAY_MASK(eb) ((1<<(eb))-1)
+#define SHMEM_ARRAY_ENTRY(i, eb) ((i)/(32/(eb)))
+
+/* the bit-position macro allows the used to flip the order of the arrays
+ * elements on a per byte or word boundary.
+ *
+ * example: an array with 8 entries each 4 bit wide. This array will fit into
+ * a single dword. The diagrmas below show the array order of the nibbles.
+ *
+ * SHMEM_ARRAY_BITPOS(i, 4, 4) defines the stadard ordering:
+ *
+ * | | | |
+ * 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ * | | | |
+ *
+ * SHMEM_ARRAY_BITPOS(i, 4, 8) defines a flip ordering per byte:
+ *
+ * | | | |
+ * 1 | 0 | 3 | 2 | 5 | 4 | 7 | 6 |
+ * | | | |
+ *
+ * SHMEM_ARRAY_BITPOS(i, 4, 16) defines a flip ordering per word:
+ *
+ * | | | |
+ * 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 |
+ * | | | |
+ */
+#define SHMEM_ARRAY_BITPOS(i, eb, fb) \
+ ((((32/(fb)) - 1 - ((i)/((fb)/(eb))) % (32/(fb))) * (fb)) + \
+ (((i)%((fb)/(eb))) * (eb)))
+
+#define SHMEM_ARRAY_GET(a, i, eb, fb) \
+ ((a[SHMEM_ARRAY_ENTRY(i, eb)] >> SHMEM_ARRAY_BITPOS(i, eb, fb)) & \
+ SHMEM_ARRAY_MASK(eb))
+
+#define SHMEM_ARRAY_SET(a, i, eb, fb, val) \
+do { \
+ a[SHMEM_ARRAY_ENTRY(i, eb)] &= ~(SHMEM_ARRAY_MASK(eb) << \
+ SHMEM_ARRAY_BITPOS(i, eb, fb)); \
+ a[SHMEM_ARRAY_ENTRY(i, eb)] |= (((val) & SHMEM_ARRAY_MASK(eb)) << \
+ SHMEM_ARRAY_BITPOS(i, eb, fb)); \
+} while (0)
+
+
+/****START OF DCBX STRUCTURES DECLARATIONS****/
+#define DCBX_MAX_NUM_PRI_PG_ENTRIES 8
+#define DCBX_PRI_PG_BITWIDTH 4
+#define DCBX_PRI_PG_FBITS 8
+#define DCBX_PRI_PG_GET(a, i) \
+ SHMEM_ARRAY_GET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS)
+#define DCBX_PRI_PG_SET(a, i, val) \
+ SHMEM_ARRAY_SET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS, val)
+#define DCBX_MAX_NUM_PG_BW_ENTRIES 8
+#define DCBX_BW_PG_BITWIDTH 8
+#define DCBX_PG_BW_GET(a, i) \
+ SHMEM_ARRAY_GET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH)
+#define DCBX_PG_BW_SET(a, i, val) \
+ SHMEM_ARRAY_SET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH, val)
+#define DCBX_STRICT_PRI_PG 15
+#define DCBX_MAX_APP_PROTOCOL 16
+#define FCOE_APP_IDX 0
+#define ISCSI_APP_IDX 1
+#define PREDEFINED_APP_IDX_MAX 2
+
+struct dcbx_ets_feature {
+ u32 enabled;
+ u32 pg_bw_tbl[2];
+ u32 pri_pg_tbl[1];
+};
+
+struct dcbx_pfc_feature {
+#ifdef __BIG_ENDIAN
+ u8 pri_en_bitmap;
+#define DCBX_PFC_PRI_0 0x01
+#define DCBX_PFC_PRI_1 0x02
+#define DCBX_PFC_PRI_2 0x04
+#define DCBX_PFC_PRI_3 0x08
+#define DCBX_PFC_PRI_4 0x10
+#define DCBX_PFC_PRI_5 0x20
+#define DCBX_PFC_PRI_6 0x40
+#define DCBX_PFC_PRI_7 0x80
+ u8 pfc_caps;
+ u8 reserved;
+ u8 enabled;
+#elif defined(__LITTLE_ENDIAN)
+ u8 enabled;
+ u8 reserved;
+ u8 pfc_caps;
+ u8 pri_en_bitmap;
+#define DCBX_PFC_PRI_0 0x01
+#define DCBX_PFC_PRI_1 0x02
+#define DCBX_PFC_PRI_2 0x04
+#define DCBX_PFC_PRI_3 0x08
+#define DCBX_PFC_PRI_4 0x10
+#define DCBX_PFC_PRI_5 0x20
+#define DCBX_PFC_PRI_6 0x40
+#define DCBX_PFC_PRI_7 0x80
+#endif
+};
+
+struct dcbx_app_priority_entry {
+#ifdef __BIG_ENDIAN
+ u16 app_id;
+ u8 pri_bitmap;
+ u8 appBitfield;
+#define DCBX_APP_ENTRY_VALID 0x01
+#define DCBX_APP_ENTRY_SF_MASK 0x30
+#define DCBX_APP_ENTRY_SF_SHIFT 4
+#define DCBX_APP_SF_ETH_TYPE 0x10
+#define DCBX_APP_SF_PORT 0x20
+#elif defined(__LITTLE_ENDIAN)
+ u8 appBitfield;
+#define DCBX_APP_ENTRY_VALID 0x01
+#define DCBX_APP_ENTRY_SF_MASK 0x30
+#define DCBX_APP_ENTRY_SF_SHIFT 4
+#define DCBX_APP_SF_ETH_TYPE 0x10
+#define DCBX_APP_SF_PORT 0x20
+ u8 pri_bitmap;
+ u16 app_id;
+#endif
+};
+
+struct dcbx_app_priority_feature {
+#ifdef __BIG_ENDIAN
+ u8 reserved;
+ u8 default_pri;
+ u8 tc_supported;
+ u8 enabled;
+#elif defined(__LITTLE_ENDIAN)
+ u8 enabled;
+ u8 tc_supported;
+ u8 default_pri;
+ u8 reserved;
+#endif
+ struct dcbx_app_priority_entry app_pri_tbl[DCBX_MAX_APP_PROTOCOL];
+};
+
+struct dcbx_features {
+ struct dcbx_ets_feature ets;
+ struct dcbx_pfc_feature pfc;
+ struct dcbx_app_priority_feature app;
+};
+
+struct lldp_params {
+#ifdef __BIG_ENDIAN
+ u8 msg_fast_tx_interval;
+ u8 msg_tx_hold;
+ u8 msg_tx_interval;
+ u8 admin_status;
+#define LLDP_TX_ONLY 0x01
+#define LLDP_RX_ONLY 0x02
+#define LLDP_TX_RX 0x03
+#define LLDP_DISABLED 0x04
+ u8 reserved1;
+ u8 tx_fast;
+ u8 tx_crd_max;
+ u8 tx_crd;
+#elif defined(__LITTLE_ENDIAN)
+ u8 admin_status;
+#define LLDP_TX_ONLY 0x01
+#define LLDP_RX_ONLY 0x02
+#define LLDP_TX_RX 0x03
+#define LLDP_DISABLED 0x04
+ u8 msg_tx_interval;
+ u8 msg_tx_hold;
+ u8 msg_fast_tx_interval;
+ u8 tx_crd;
+ u8 tx_crd_max;
+ u8 tx_fast;
+ u8 reserved1;
+#endif
+#define REM_CHASSIS_ID_STAT_LEN 4
+#define REM_PORT_ID_STAT_LEN 4
+ u32 peer_chassis_id[REM_CHASSIS_ID_STAT_LEN];
+ u32 peer_port_id[REM_PORT_ID_STAT_LEN];
+};
+
+struct lldp_dcbx_stat {
+#define LOCAL_CHASSIS_ID_STAT_LEN 2
+#define LOCAL_PORT_ID_STAT_LEN 2
+ u32 local_chassis_id[LOCAL_CHASSIS_ID_STAT_LEN];
+ u32 local_port_id[LOCAL_PORT_ID_STAT_LEN];
+ u32 num_tx_dcbx_pkts;
+ u32 num_rx_dcbx_pkts;
+};
+
+struct lldp_admin_mib {
+ u32 ver_cfg_flags;
+#define DCBX_ETS_CONFIG_TX_ENABLED 0x00000001
+#define DCBX_PFC_CONFIG_TX_ENABLED 0x00000002
+#define DCBX_APP_CONFIG_TX_ENABLED 0x00000004
+#define DCBX_ETS_RECO_TX_ENABLED 0x00000008
+#define DCBX_ETS_RECO_VALID 0x00000010
+#define DCBX_ETS_WILLING 0x00000020
+#define DCBX_PFC_WILLING 0x00000040
+#define DCBX_APP_WILLING 0x00000080
+#define DCBX_VERSION_CEE 0x00000100
+#define DCBX_VERSION_IEEE 0x00000200
+#define DCBX_DCBX_ENABLED 0x00000400
+#define DCBX_CEE_VERSION_MASK 0x0000f000
+#define DCBX_CEE_VERSION_SHIFT 12
+#define DCBX_CEE_MAX_VERSION_MASK 0x000f0000
+#define DCBX_CEE_MAX_VERSION_SHIFT 16
+ struct dcbx_features features;
+};
+
+struct lldp_remote_mib {
+ u32 prefix_seq_num;
+ u32 flags;
+#define DCBX_ETS_TLV_RX 0x00000001
+#define DCBX_PFC_TLV_RX 0x00000002
+#define DCBX_APP_TLV_RX 0x00000004
+#define DCBX_ETS_RX_ERROR 0x00000010
+#define DCBX_PFC_RX_ERROR 0x00000020
+#define DCBX_APP_RX_ERROR 0x00000040
+#define DCBX_ETS_REM_WILLING 0x00000100
+#define DCBX_PFC_REM_WILLING 0x00000200
+#define DCBX_APP_REM_WILLING 0x00000400
+#define DCBX_REMOTE_ETS_RECO_VALID 0x00001000
+ struct dcbx_features features;
+ u32 suffix_seq_num;
+};
+
+struct lldp_local_mib {
+ u32 prefix_seq_num;
+ u32 error;
+#define DCBX_LOCAL_ETS_ERROR 0x00000001
+#define DCBX_LOCAL_PFC_ERROR 0x00000002
+#define DCBX_LOCAL_APP_ERROR 0x00000004
+#define DCBX_LOCAL_PFC_MISMATCH 0x00000010
+#define DCBX_LOCAL_APP_MISMATCH 0x00000020
+ struct dcbx_features features;
+ u32 suffix_seq_num;
+};
+/***END OF DCBX STRUCTURES DECLARATIONS***/
struct shmem2_region {
@@ -1065,7 +1361,12 @@ struct shmem2_region {
#define SHMEM_MF_CFG_ADDR_NONE 0x00000000
struct fw_flr_mb flr_mb;
- u32 reserved[3];
+ u32 dcbx_lldp_params_offset;
+#define SHMEM_LLDP_DCBX_PARAMS_NONE 0x00000000
+ u32 dcbx_neg_res_offset;
+#define SHMEM_DCBX_NEG_RES_NONE 0x00000000
+ u32 dcbx_remote_mib_offset;
+#define SHMEM_DCBX_REMOTE_MIB_NONE 0x00000000
/*
* The other shmemX_base_addr holds the other path's shmem address
* required for example in case of common phy init, or for path1 to know
@@ -1074,6 +1375,10 @@ struct shmem2_region {
*/
u32 other_shmem_base_addr;
u32 other_shmem2_base_addr;
+ u32 reserved1[E2_VF_MAX / 32];
+ u32 reserved2[E2_FUNC_MAX][E2_VF_MAX / 32];
+ u32 dcbx_lldp_dcbx_stat_offset;
+#define SHMEM_LLDP_DCBX_STAT_NONE 0x00000000
};
@@ -1527,8 +1832,8 @@ struct host_func_stats {
#define BCM_5710_FW_MAJOR_VERSION 6
-#define BCM_5710_FW_MINOR_VERSION 0
-#define BCM_5710_FW_REVISION_VERSION 34
+#define BCM_5710_FW_MINOR_VERSION 2
+#define BCM_5710_FW_REVISION_VERSION 5
#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
@@ -2976,6 +3281,25 @@ struct fairness_vars_per_vn {
/*
+ * The data for flow control configuration
+ */
+struct flow_control_configuration {
+ struct priority_cos
+ traffic_type_to_priority_cos[MAX_PFC_TRAFFIC_TYPES];
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 dcb_version;
+ u8 dcb_enabled;
+#elif defined(__LITTLE_ENDIAN)
+ u8 dcb_enabled;
+ u8 dcb_version;
+ u16 reserved1;
+#endif
+ u32 reserved2;
+};
+
+
+/*
* FW version stored in the Xstorm RAM
*/
struct fw_version {
diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h
index a9d54874a559..5a268e9a0895 100644
--- a/drivers/net/bnx2x/bnx2x_init.h
+++ b/drivers/net/bnx2x/bnx2x_init.h
@@ -192,5 +192,225 @@ struct src_ent {
u64 next;
};
+/****************************************************************************
+* Parity configuration
+****************************************************************************/
+#define BLOCK_PRTY_INFO(block, en_mask, m1, m1h, m2) \
+{ \
+ block##_REG_##block##_PRTY_MASK, \
+ block##_REG_##block##_PRTY_STS_CLR, \
+ en_mask, {m1, m1h, m2}, #block \
+}
+
+#define BLOCK_PRTY_INFO_0(block, en_mask, m1, m1h, m2) \
+{ \
+ block##_REG_##block##_PRTY_MASK_0, \
+ block##_REG_##block##_PRTY_STS_CLR_0, \
+ en_mask, {m1, m1h, m2}, #block"_0" \
+}
+
+#define BLOCK_PRTY_INFO_1(block, en_mask, m1, m1h, m2) \
+{ \
+ block##_REG_##block##_PRTY_MASK_1, \
+ block##_REG_##block##_PRTY_STS_CLR_1, \
+ en_mask, {m1, m1h, m2}, #block"_1" \
+}
+
+static const struct {
+ u32 mask_addr;
+ u32 sts_clr_addr;
+ u32 en_mask; /* Mask to enable parity attentions */
+ struct {
+ u32 e1; /* 57710 */
+ u32 e1h; /* 57711 */
+ u32 e2; /* 57712 */
+ } reg_mask; /* Register mask (all valid bits) */
+ char name[7]; /* Block's longest name is 6 characters long
+ * (name + suffix)
+ */
+} bnx2x_blocks_parity_data[] = {
+ /* bit 19 masked */
+ /* REG_WR(bp, PXP_REG_PXP_PRTY_MASK, 0x80000); */
+ /* bit 5,18,20-31 */
+ /* REG_WR(bp, PXP2_REG_PXP2_PRTY_MASK_0, 0xfff40020); */
+ /* bit 5 */
+ /* REG_WR(bp, PXP2_REG_PXP2_PRTY_MASK_1, 0x20); */
+ /* REG_WR(bp, HC_REG_HC_PRTY_MASK, 0x0); */
+ /* REG_WR(bp, MISC_REG_MISC_PRTY_MASK, 0x0); */
+
+ /* Block IGU, MISC, PXP and PXP2 parity errors as long as we don't
+ * want to handle "system kill" flow at the moment.
+ */
+ BLOCK_PRTY_INFO(PXP, 0x3ffffff, 0x3ffffff, 0x3ffffff, 0x3ffffff),
+ BLOCK_PRTY_INFO_0(PXP2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff),
+ BLOCK_PRTY_INFO_1(PXP2, 0x7ff, 0x7f, 0x7f, 0x7ff),
+ BLOCK_PRTY_INFO(HC, 0x7, 0x7, 0x7, 0),
+ BLOCK_PRTY_INFO(IGU, 0x7ff, 0, 0, 0x7ff),
+ BLOCK_PRTY_INFO(MISC, 0x1, 0x1, 0x1, 0x1),
+ BLOCK_PRTY_INFO(QM, 0, 0x1ff, 0xfff, 0xfff),
+ BLOCK_PRTY_INFO(DORQ, 0, 0x3, 0x3, 0x3),
+ {GRCBASE_UPB + PB_REG_PB_PRTY_MASK,
+ GRCBASE_UPB + PB_REG_PB_PRTY_STS_CLR, 0,
+ {0xf, 0xf, 0xf}, "UPB"},
+ {GRCBASE_XPB + PB_REG_PB_PRTY_MASK,
+ GRCBASE_XPB + PB_REG_PB_PRTY_STS_CLR, 0,
+ {0xf, 0xf, 0xf}, "XPB"},
+ BLOCK_PRTY_INFO(SRC, 0x4, 0x7, 0x7, 0x7),
+ BLOCK_PRTY_INFO(CDU, 0, 0x1f, 0x1f, 0x1f),
+ BLOCK_PRTY_INFO(CFC, 0, 0xf, 0xf, 0xf),
+ BLOCK_PRTY_INFO(DBG, 0, 0x1, 0x1, 0x1),
+ BLOCK_PRTY_INFO(DMAE, 0, 0xf, 0xf, 0xf),
+ BLOCK_PRTY_INFO(BRB1, 0, 0xf, 0xf, 0xf),
+ BLOCK_PRTY_INFO(PRS, (1<<6), 0xff, 0xff, 0xff),
+ BLOCK_PRTY_INFO(TSDM, 0x18, 0x7ff, 0x7ff, 0x7ff),
+ BLOCK_PRTY_INFO(CSDM, 0x8, 0x7ff, 0x7ff, 0x7ff),
+ BLOCK_PRTY_INFO(USDM, 0x38, 0x7ff, 0x7ff, 0x7ff),
+ BLOCK_PRTY_INFO(XSDM, 0x8, 0x7ff, 0x7ff, 0x7ff),
+ BLOCK_PRTY_INFO_0(TSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff),
+ BLOCK_PRTY_INFO_1(TSEM, 0, 0x3, 0x1f, 0x3f),
+ BLOCK_PRTY_INFO_0(USEM, 0, 0xffffffff, 0xffffffff, 0xffffffff),
+ BLOCK_PRTY_INFO_1(USEM, 0, 0x3, 0x1f, 0x1f),
+ BLOCK_PRTY_INFO_0(CSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff),
+ BLOCK_PRTY_INFO_1(CSEM, 0, 0x3, 0x1f, 0x1f),
+ BLOCK_PRTY_INFO_0(XSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff),
+ BLOCK_PRTY_INFO_1(XSEM, 0, 0x3, 0x1f, 0x3f),
+};
+
+
+/* [28] MCP Latched rom_parity
+ * [29] MCP Latched ump_rx_parity
+ * [30] MCP Latched ump_tx_parity
+ * [31] MCP Latched scpad_parity
+ */
+#define MISC_AEU_ENABLE_MCP_PRTY_BITS \
+ (AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | \
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | \
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY | \
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY)
+
+/* Below registers control the MCP parity attention output. When
+ * MISC_AEU_ENABLE_MCP_PRTY_BITS are set - attentions are
+ * enabled, when cleared - disabled.
+ */
+static const u32 mcp_attn_ctl_regs[] = {
+ MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0,
+ MISC_REG_AEU_ENABLE4_NIG_0,
+ MISC_REG_AEU_ENABLE4_PXP_0,
+ MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0,
+ MISC_REG_AEU_ENABLE4_NIG_1,
+ MISC_REG_AEU_ENABLE4_PXP_1
+};
+
+static inline void bnx2x_set_mcp_parity(struct bnx2x *bp, u8 enable)
+{
+ int i;
+ u32 reg_val;
+
+ for (i = 0; i < ARRAY_SIZE(mcp_attn_ctl_regs); i++) {
+ reg_val = REG_RD(bp, mcp_attn_ctl_regs[i]);
+
+ if (enable)
+ reg_val |= MISC_AEU_ENABLE_MCP_PRTY_BITS;
+ else
+ reg_val &= ~MISC_AEU_ENABLE_MCP_PRTY_BITS;
+
+ REG_WR(bp, mcp_attn_ctl_regs[i], reg_val);
+ }
+}
+
+static inline u32 bnx2x_parity_reg_mask(struct bnx2x *bp, int idx)
+{
+ if (CHIP_IS_E1(bp))
+ return bnx2x_blocks_parity_data[idx].reg_mask.e1;
+ else if (CHIP_IS_E1H(bp))
+ return bnx2x_blocks_parity_data[idx].reg_mask.e1h;
+ else
+ return bnx2x_blocks_parity_data[idx].reg_mask.e2;
+}
+
+static inline void bnx2x_disable_blocks_parity(struct bnx2x *bp)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) {
+ u32 dis_mask = bnx2x_parity_reg_mask(bp, i);
+
+ if (dis_mask) {
+ REG_WR(bp, bnx2x_blocks_parity_data[i].mask_addr,
+ dis_mask);
+ DP(NETIF_MSG_HW, "Setting parity mask "
+ "for %s to\t\t0x%x\n",
+ bnx2x_blocks_parity_data[i].name, dis_mask);
+ }
+ }
+
+ /* Disable MCP parity attentions */
+ bnx2x_set_mcp_parity(bp, false);
+}
+
+/**
+ * Clear the parity error status registers.
+ */
+static inline void bnx2x_clear_blocks_parity(struct bnx2x *bp)
+{
+ int i;
+ u32 reg_val, mcp_aeu_bits =
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY |
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY |
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY |
+ AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY;
+
+ /* Clear SEM_FAST parities */
+ REG_WR(bp, XSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1);
+ REG_WR(bp, TSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1);
+ REG_WR(bp, USEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1);
+ REG_WR(bp, CSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1);
+
+ for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) {
+ u32 reg_mask = bnx2x_parity_reg_mask(bp, i);
+
+ if (reg_mask) {
+ reg_val = REG_RD(bp, bnx2x_blocks_parity_data[i].
+ sts_clr_addr);
+ if (reg_val & reg_mask)
+ DP(NETIF_MSG_HW,
+ "Parity errors in %s: 0x%x\n",
+ bnx2x_blocks_parity_data[i].name,
+ reg_val & reg_mask);
+ }
+ }
+
+ /* Check if there were parity attentions in MCP */
+ reg_val = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_MCP);
+ if (reg_val & mcp_aeu_bits)
+ DP(NETIF_MSG_HW, "Parity error in MCP: 0x%x\n",
+ reg_val & mcp_aeu_bits);
+
+ /* Clear parity attentions in MCP:
+ * [7] clears Latched rom_parity
+ * [8] clears Latched ump_rx_parity
+ * [9] clears Latched ump_tx_parity
+ * [10] clears Latched scpad_parity (both ports)
+ */
+ REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x780);
+}
+
+static inline void bnx2x_enable_blocks_parity(struct bnx2x *bp)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) {
+ u32 reg_mask = bnx2x_parity_reg_mask(bp, i);
+
+ if (reg_mask)
+ REG_WR(bp, bnx2x_blocks_parity_data[i].mask_addr,
+ bnx2x_blocks_parity_data[i].en_mask & reg_mask);
+ }
+
+ /* Enable MCP parity attentions */
+ bnx2x_set_mcp_parity(bp, true);
+}
+
+
#endif /* BNX2X_INIT_H */
diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
index a306b0e46b61..66df29fcf751 100644
--- a/drivers/net/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x/bnx2x_init_ops.h
@@ -838,7 +838,7 @@ static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count,
/****************************************************************************
* SRC initializations
****************************************************************************/
-
+#ifdef BCM_CNIC
/* called during init func stage */
static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
dma_addr_t t2_mapping, int src_cid_count)
@@ -862,5 +862,5 @@ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
U64_HI((u64)t2_mapping +
(src_cid_count-1) * sizeof(struct src_ent)));
}
-
+#endif
#endif /* BNX2X_INIT_OPS_H */
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index 2326774df843..43b0de24f391 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -164,7 +164,8 @@
#define EDC_MODE_PASSIVE_DAC 0x0055
-
+#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
+#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
/**********************************************************/
/* INTERFACE */
/**********************************************************/
@@ -205,6 +206,270 @@ static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
return val;
}
+/******************************************************************/
+/* ETS section */
+/******************************************************************/
+void bnx2x_ets_disabled(struct link_params *params)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x *bp = params->bp;
+
+ DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
+
+ /**
+ * mapping between entry priority to client number (0,1,2 -debug and
+ * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
+ * 3bits client num.
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
+ */
+
+ REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
+ /**
+ * Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries, 3 -
+ * COS0 entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
+ /* defines which entries (clients) are subjected to WFQ arbitration */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
+ /**
+ * For strict priority entries defines the number of consecutive
+ * slots for the highest priority.
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+ /**
+ * mapping between the CREDIT_WEIGHT registers and actual client
+ * numbers
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
+
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
+ REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
+ /* ETS mode disable */
+ REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
+ /**
+ * If ETS mode is enabled (there is no strict priority) defines a WFQ
+ * weight for COS0/COS1.
+ */
+ REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
+ REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
+ /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
+ REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
+ REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
+}
+
+void bnx2x_ets_bw_limit_common(const struct link_params *params)
+{
+ /* ETS disabled configuration */
+ struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
+ /**
+ * defines which entries (clients) are subjected to WFQ arbitration
+ * COS0 0x8
+ * COS1 0x10
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
+ /**
+ * mapping between the ARB_CREDIT_WEIGHT registers and actual
+ * client numbers (WEIGHT_0 does not actually have to represent
+ * client 0)
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
+
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
+ ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
+ ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+
+ /* ETS mode enabled*/
+ REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
+
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
+ /**
+ * Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
+ * entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
+
+ /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
+ REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
+ ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+ REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
+ ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
+}
+
+void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
+ const u32 cos1_bw)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x *bp = params->bp;
+ const u32 total_bw = cos0_bw + cos1_bw;
+ u32 cos0_credit_weight = 0;
+ u32 cos1_credit_weight = 0;
+
+ DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
+
+ if ((0 == total_bw) ||
+ (0 == cos0_bw) ||
+ (0 == cos1_bw)) {
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_bw_limit: Total BW can't be zero\n");
+ return;
+ }
+
+ cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
+ total_bw;
+ cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
+ total_bw;
+
+ bnx2x_ets_bw_limit_common(params);
+
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
+
+ REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
+ REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
+}
+
+u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
+{
+ /* ETS disabled configuration*/
+ struct bnx2x *bp = params->bp;
+ u32 val = 0;
+
+ DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
+ /**
+ * Bitmap of 5bits length. Each bit specifies whether the entry behaves
+ * as strict. Bits 0,1,2 - debug and management entries,
+ * 3 - COS0 entry, 4 - COS1 entry.
+ * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
+ * bit4 bit3 bit2 bit1 bit0
+ * MCP and debug are strict
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
+ /**
+ * For strict priority entries defines the number of consecutive slots
+ * for the highest priority.
+ */
+ REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
+ /* ETS mode disable */
+ REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
+
+ /* Defines the number of consecutive slots for the strict priority */
+ REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
+
+ /**
+ * mapping between entry priority to client number (0,1,2 -debug and
+ * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
+ * 3bits client num.
+ * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
+ * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
+ * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
+ */
+ val = (0 == strict_cos) ? 0x2318 : 0x22E0;
+ REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
+
+ return 0;
+}
+/******************************************************************/
+/* ETS section */
+/******************************************************************/
+
+static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
+ u32 pfc_frames_sent[2],
+ u32 pfc_frames_received[2])
+{
+ /* Read pfc statistic */
+ struct bnx2x *bp = params->bp;
+ u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+
+ DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
+
+ REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
+ pfc_frames_sent, 2);
+
+ REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
+ pfc_frames_received, 2);
+
+}
+static void bnx2x_emac_get_pfc_stat(struct link_params *params,
+ u32 pfc_frames_sent[2],
+ u32 pfc_frames_received[2])
+{
+ /* Read pfc statistic */
+ struct bnx2x *bp = params->bp;
+ u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ u32 val_xon = 0;
+ u32 val_xoff = 0;
+
+ DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
+
+ /* PFC received frames */
+ val_xoff = REG_RD(bp, emac_base +
+ EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
+ val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
+ val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
+ val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
+
+ pfc_frames_received[0] = val_xon + val_xoff;
+
+ /* PFC received sent */
+ val_xoff = REG_RD(bp, emac_base +
+ EMAC_REG_RX_PFC_STATS_XOFF_SENT);
+ val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
+ val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
+ val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
+
+ pfc_frames_sent[0] = val_xon + val_xoff;
+}
+
+void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
+ u32 pfc_frames_sent[2],
+ u32 pfc_frames_received[2])
+{
+ /* Read pfc statistic */
+ struct bnx2x *bp = params->bp;
+ u32 val = 0;
+ DP(NETIF_MSG_LINK, "pfc statistic\n");
+
+ if (!vars->link_up)
+ return;
+
+ val = REG_RD(bp, MISC_REG_RESET_REG_2);
+ if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
+ == 0) {
+ DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
+ bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
+ pfc_frames_received);
+ } else {
+ DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
+ bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
+ pfc_frames_received);
+ }
+}
+/******************************************************************/
+/* MAC/PBF section */
+/******************************************************************/
static void bnx2x_emac_init(struct link_params *params,
struct link_vars *vars)
{
@@ -315,24 +580,55 @@ static u8 bnx2x_emac_enable(struct link_params *params,
/* pause enable/disable */
bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
EMAC_RX_MODE_FLOW_EN);
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
- bnx2x_bits_en(bp, emac_base +
- EMAC_REG_EMAC_RX_MODE,
- EMAC_RX_MODE_FLOW_EN);
bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
- (EMAC_TX_MODE_EXT_PAUSE_EN |
- EMAC_TX_MODE_FLOW_EN));
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
- bnx2x_bits_en(bp, emac_base +
- EMAC_REG_EMAC_TX_MODE,
- (EMAC_TX_MODE_EXT_PAUSE_EN |
- EMAC_TX_MODE_FLOW_EN));
+ (EMAC_TX_MODE_EXT_PAUSE_EN |
+ EMAC_TX_MODE_FLOW_EN));
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED)) {
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ bnx2x_bits_en(bp, emac_base +
+ EMAC_REG_EMAC_RX_MODE,
+ EMAC_RX_MODE_FLOW_EN);
+
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ bnx2x_bits_en(bp, emac_base +
+ EMAC_REG_EMAC_TX_MODE,
+ (EMAC_TX_MODE_EXT_PAUSE_EN |
+ EMAC_TX_MODE_FLOW_EN));
+ } else
+ bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
+ EMAC_TX_MODE_FLOW_EN);
}
/* KEEP_VLAN_TAG, promiscuous */
val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
+
+ /**
+ * Setting this bit causes MAC control frames (except for pause
+ * frames) to be passed on for processing. This setting has no
+ * affect on the operation of the pause frames. This bit effects
+ * all packets regardless of RX Parser packet sorting logic.
+ * Turn the PFC off to make sure we are in Xon state before
+ * enabling it.
+ */
+ EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
+ DP(NETIF_MSG_LINK, "PFC is enabled\n");
+ /* Enable PFC again */
+ EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
+ EMAC_REG_RX_PFC_MODE_RX_EN |
+ EMAC_REG_RX_PFC_MODE_TX_EN |
+ EMAC_REG_RX_PFC_MODE_PRIORITIES);
+
+ EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
+ ((0x0101 <<
+ EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
+ (0x00ff <<
+ EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
+ val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
+ }
EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
/* Set Loopback */
@@ -362,7 +658,9 @@ static u8 bnx2x_emac_enable(struct link_params *params,
/* enable the NIG in/out to the emac */
REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
val = 0;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED) ||
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
val = 1;
REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
@@ -383,9 +681,38 @@ static u8 bnx2x_emac_enable(struct link_params *params,
return 0;
}
-static void bnx2x_update_bmac2(struct link_params *params,
- struct link_vars *vars,
- u8 is_lb)
+static void bnx2x_update_pfc_bmac1(struct link_params *params,
+ struct link_vars *vars)
+{
+ u32 wb_data[2];
+ struct bnx2x *bp = params->bp;
+ u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+
+ u32 val = 0x14;
+ if ((!(params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED)) &&
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
+ /* Enable BigMAC to react on received Pause packets */
+ val |= (1<<5);
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
+
+ /* tx control */
+ val = 0xc0;
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED) &&
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
+ val |= 0x800000;
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
+}
+
+static void bnx2x_update_pfc_bmac2(struct link_params *params,
+ struct link_vars *vars,
+ u8 is_lb)
{
/*
* Set rx control: Strip CRC and enable BigMAC to relay
@@ -397,7 +724,9 @@ static void bnx2x_update_bmac2(struct link_params *params,
NIG_REG_INGRESS_BMAC0_MEM;
u32 val = 0x14;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ if ((!(params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED)) &&
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
/* Enable BigMAC to react on received Pause packets */
val |= (1<<5);
wb_data[0] = val;
@@ -408,14 +737,47 @@ static void bnx2x_update_bmac2(struct link_params *params,
/* Tx control */
val = 0xc0;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED) &&
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
val |= 0x800000;
wb_data[0] = val;
wb_data[1] = 0;
- REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL,
- wb_data, 2);
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
+
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
+ DP(NETIF_MSG_LINK, "PFC is enabled\n");
+ /* Enable PFC RX & TX & STATS and set 8 COS */
+ wb_data[0] = 0x0;
+ wb_data[0] |= (1<<0); /* RX */
+ wb_data[0] |= (1<<1); /* TX */
+ wb_data[0] |= (1<<2); /* Force initial Xon */
+ wb_data[0] |= (1<<3); /* 8 cos */
+ wb_data[0] |= (1<<5); /* STATS */
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
+ wb_data, 2);
+ /* Clear the force Xon */
+ wb_data[0] &= ~(1<<2);
+ } else {
+ DP(NETIF_MSG_LINK, "PFC is disabled\n");
+ /* disable PFC RX & TX & STATS and set 8 COS */
+ wb_data[0] = 0x8;
+ wb_data[1] = 0;
+ }
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
+
+ /**
+ * Set Time (based unit is 512 bit time) between automatic
+ * re-sending of PP packets amd enable automatic re-send of
+ * Per-Priroity Packet as long as pp_gen is asserted and
+ * pp_disable is low.
+ */
val = 0x8000;
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+ val |= (1<<16); /* enable automatic re-send */
+
wb_data[0] = val;
wb_data[1] = 0;
REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
@@ -427,6 +789,9 @@ static void bnx2x_update_bmac2(struct link_params *params,
val |= 0x4; /* Local loopback */
DP(NETIF_MSG_LINK, "enable bmac loopback\n");
}
+ /* When PFC enabled, Pass pause frames towards the NIG. */
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+ val |= ((1<<6)|(1<<5));
wb_data[0] = val;
wb_data[1] = 0;
@@ -434,6 +799,239 @@ static void bnx2x_update_bmac2(struct link_params *params,
wb_data, 2);
}
+static void bnx2x_update_pfc_brb(struct link_params *params,
+ struct link_vars *vars,
+ struct bnx2x_nig_brb_pfc_port_params *pfc_params)
+{
+ struct bnx2x *bp = params->bp;
+ int set_pfc = params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED;
+
+ /* default - pause configuration */
+ u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
+ u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
+ u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
+ u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
+
+ if (set_pfc && pfc_params)
+ /* First COS */
+ if (!pfc_params->cos0_pauseable) {
+ pause_xoff_th =
+ PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
+ pause_xon_th =
+ PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
+ full_xoff_th =
+ PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
+ full_xon_th =
+ PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
+ }
+ /* The number of free blocks below which the pause signal to class 0
+ of MAC #n is asserted. n=0,1 */
+ REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
+ /* The number of free blocks above which the pause signal to class 0
+ of MAC #n is de-asserted. n=0,1 */
+ REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
+ /* The number of free blocks below which the full signal to class 0
+ of MAC #n is asserted. n=0,1 */
+ REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
+ /* The number of free blocks above which the full signal to class 0
+ of MAC #n is de-asserted. n=0,1 */
+ REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
+
+ if (set_pfc && pfc_params) {
+ /* Second COS */
+ if (pfc_params->cos1_pauseable) {
+ pause_xoff_th =
+ PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
+ pause_xon_th =
+ PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
+ full_xoff_th =
+ PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
+ full_xon_th =
+ PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
+ } else {
+ pause_xoff_th =
+ PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
+ pause_xon_th =
+ PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
+ full_xoff_th =
+ PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
+ full_xon_th =
+ PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
+ }
+ /**
+ * The number of free blocks below which the pause signal to
+ * class 1 of MAC #n is asserted. n=0,1
+ **/
+ REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
+ /**
+ * The number of free blocks above which the pause signal to
+ * class 1 of MAC #n is de-asserted. n=0,1
+ **/
+ REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
+ /**
+ * The number of free blocks below which the full signal to
+ * class 1 of MAC #n is asserted. n=0,1
+ **/
+ REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
+ /**
+ * The number of free blocks above which the full signal to
+ * class 1 of MAC #n is de-asserted. n=0,1
+ **/
+ REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
+ }
+}
+
+static void bnx2x_update_pfc_nig(struct link_params *params,
+ struct link_vars *vars,
+ struct bnx2x_nig_brb_pfc_port_params *nig_params)
+{
+ u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
+ u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
+ u32 pkt_priority_to_cos = 0;
+ u32 val;
+ struct bnx2x *bp = params->bp;
+ int port = params->port;
+ int set_pfc = params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED;
+ DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
+
+ /**
+ * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
+ * MAC control frames (that are not pause packets)
+ * will be forwarded to the XCM.
+ */
+ xcm_mask = REG_RD(bp,
+ port ? NIG_REG_LLH1_XCM_MASK :
+ NIG_REG_LLH0_XCM_MASK);
+ /**
+ * nig params will override non PFC params, since it's possible to
+ * do transition from PFC to SAFC
+ */
+ if (set_pfc) {
+ pause_enable = 0;
+ llfc_out_en = 0;
+ llfc_enable = 0;
+ ppp_enable = 1;
+ xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
+ NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
+ xcm0_out_en = 0;
+ p0_hwpfc_enable = 1;
+ } else {
+ if (nig_params) {
+ llfc_out_en = nig_params->llfc_out_en;
+ llfc_enable = nig_params->llfc_enable;
+ pause_enable = nig_params->pause_enable;
+ } else /*defaul non PFC mode - PAUSE */
+ pause_enable = 1;
+
+ xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
+ NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
+ xcm0_out_en = 1;
+ }
+
+ REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
+ NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
+ REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
+ NIG_REG_LLFC_ENABLE_0, llfc_enable);
+ REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
+ NIG_REG_PAUSE_ENABLE_0, pause_enable);
+
+ REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
+ NIG_REG_PPP_ENABLE_0, ppp_enable);
+
+ REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
+ NIG_REG_LLH0_XCM_MASK, xcm_mask);
+
+ REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
+
+ /* output enable for RX_XCM # IF */
+ REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
+
+ /* HW PFC TX enable */
+ REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
+
+ /* 0x2 = BMAC, 0x1= EMAC */
+ switch (vars->mac_type) {
+ case MAC_TYPE_EMAC:
+ val = 1;
+ break;
+ case MAC_TYPE_BMAC:
+ val = 0;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
+
+ if (nig_params) {
+ pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
+
+ REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK :
+ NIG_REG_P0_RX_COS0_PRIORITY_MASK,
+ nig_params->rx_cos0_priority_mask);
+
+ REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK :
+ NIG_REG_P0_RX_COS1_PRIORITY_MASK,
+ nig_params->rx_cos1_priority_mask);
+
+ REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
+ NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
+ nig_params->llfc_high_priority_classes);
+
+ REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
+ NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
+ nig_params->llfc_low_priority_classes);
+ }
+ REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
+ NIG_REG_P0_PKT_PRIORITY_TO_COS,
+ pkt_priority_to_cos);
+}
+
+
+void bnx2x_update_pfc(struct link_params *params,
+ struct link_vars *vars,
+ struct bnx2x_nig_brb_pfc_port_params *pfc_params)
+{
+ /**
+ * The PFC and pause are orthogonal to one another, meaning when
+ * PFC is enabled, the pause are disabled, and when PFC is
+ * disabled, pause are set according to the pause result.
+ */
+ u32 val;
+ struct bnx2x *bp = params->bp;
+
+ /* update NIG params */
+ bnx2x_update_pfc_nig(params, vars, pfc_params);
+
+ /* update BRB params */
+ bnx2x_update_pfc_brb(params, vars, pfc_params);
+
+ if (!vars->link_up)
+ return;
+
+ val = REG_RD(bp, MISC_REG_RESET_REG_2);
+ if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
+ == 0) {
+ DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
+ bnx2x_emac_enable(params, vars, 0);
+ return;
+ }
+
+ DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
+ if (CHIP_IS_E2(bp))
+ bnx2x_update_pfc_bmac2(params, vars, 0);
+ else
+ bnx2x_update_pfc_bmac1(params, vars);
+
+ val = 0;
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED) ||
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
+ val = 1;
+ REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
+}
static u8 bnx2x_bmac1_enable(struct link_params *params,
struct link_vars *vars,
@@ -465,15 +1063,6 @@ static u8 bnx2x_bmac1_enable(struct link_params *params,
REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
wb_data, 2);
- /* tx control */
- val = 0xc0;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
- val |= 0x800000;
- wb_data[0] = val;
- wb_data[1] = 0;
- REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
- wb_data, 2);
-
/* mac control */
val = 0x3;
if (is_lb) {
@@ -491,14 +1080,7 @@ static u8 bnx2x_bmac1_enable(struct link_params *params,
REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
wb_data, 2);
- /* rx control set to don't strip crc */
- val = 0x14;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
- val |= 0x20;
- wb_data[0] = val;
- wb_data[1] = 0;
- REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
- wb_data, 2);
+ bnx2x_update_pfc_bmac1(params, vars);
/* set tx mtu */
wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
@@ -595,7 +1177,7 @@ static u8 bnx2x_bmac2_enable(struct link_params *params,
REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE,
wb_data, 2);
udelay(30);
- bnx2x_update_bmac2(params, vars, is_lb);
+ bnx2x_update_pfc_bmac2(params, vars, is_lb);
return 0;
}
@@ -610,7 +1192,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
/* reset and unreset the BigMac */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
- udelay(10);
+ msleep(1);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -627,7 +1209,9 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
val = 0;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_PFC_ENABLED) ||
+ (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
val = 1;
REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
@@ -3525,13 +4109,19 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
/* Enable CL37 BAM */
- bnx2x_cl45_read(bp, phy,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8073_BAM, &val);
- bnx2x_cl45_write(bp, phy,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8073_BAM, val | 1);
+ if (REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_hw_config[params->port].default_cfg)) &
+ PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8073_BAM, &val);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8073_BAM, val | 1);
+ DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
+ }
if (params->loopback_mode == LOOPBACK_EXT) {
bnx2x_807x_force_10G(bp, phy);
DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
@@ -3898,7 +4488,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
- return 0;;
+ return 0;
msleep(1);
}
return -EINVAL;
@@ -3982,7 +4572,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
- return 0;;
+ return 0;
msleep(1);
}
@@ -5302,7 +5892,7 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
{
struct bnx2x *bp = params->bp;
u16 autoneg_val, an_1000_val, an_10_100_val;
- bnx2x_wait_reset_complete(bp, phy);
+
bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
1 << NIG_LATCH_BC_ENABLE_MI_INT);
@@ -5431,6 +6021,7 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
+ bnx2x_wait_reset_complete(bp, phy);
bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
return bnx2x_848xx_cmn_config_init(phy, params, vars);
@@ -5441,7 +6032,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
- u8 port = params->port, initialize = 1;
+ u8 port, initialize = 1;
u16 val;
u16 temp;
u32 actual_phy_selection;
@@ -5450,11 +6041,16 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
/* This is just for MDIO_CTL_REG_84823_MEDIA register. */
msleep(1);
+ if (CHIP_IS_E2(bp))
+ port = BP_PATH(bp);
+ else
+ port = params->port;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
port);
- msleep(200); /* 100 is not enough */
-
+ bnx2x_wait_reset_complete(bp, phy);
+ /* Wait for GPHY to come out of reset */
+ msleep(50);
/* BCM84823 requires that XGXS links up first @ 10G for normal
behavior */
temp = vars->line_speed;
@@ -5625,7 +6221,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 port = params->port;
+ u8 port;
+ if (CHIP_IS_E2(bp))
+ port = BP_PATH(bp);
+ else
+ port = params->port;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port);
@@ -6928,7 +7528,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u8 reset_ext_phy)
{
struct bnx2x *bp = params->bp;
- u8 phy_index, port = params->port;
+ u8 phy_index, port = params->port, clear_latch_ind = 0;
DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
/* disable attentions */
vars->link_status = 0;
@@ -6966,9 +7566,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
params->phy[phy_index].link_reset(
&params->phy[phy_index],
params);
+ if (params->phy[phy_index].flags &
+ FLAGS_REARM_LATCH_SIGNAL)
+ clear_latch_ind = 1;
}
}
+ if (clear_latch_ind) {
+ /* Clear latching indication */
+ bnx2x_rearm_latch_signal(bp, port, 0);
+ bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
+ 1 << NIG_LATCH_BC_ENABLE_MI_INT);
+ }
if (params->phy[INT_PHY].link_reset)
params->phy[INT_PHY].link_reset(
&params->phy[INT_PHY], params);
@@ -6999,6 +7608,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
s8 port;
s8 port_of_path = 0;
+ bnx2x_ext_phy_hw_reset(bp, 0);
/* PART1 - Reset both phys */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
u32 shmem_base, shmem2_base;
@@ -7021,7 +7631,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
return -EINVAL;
}
/* disable attentions */
- bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+ port_of_path*4,
(NIG_MASK_XGXS0_LINK_STATUS |
NIG_MASK_XGXS0_LINK10G |
NIG_MASK_SERDES0_LINK_STATUS |
@@ -7132,7 +7743,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
(1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
- bnx2x_ext_phy_hw_reset(bp, 1);
+ bnx2x_ext_phy_hw_reset(bp, 0);
msleep(5);
for (port = 0; port < PORT_MAX; port++) {
u32 shmem_base, shmem2_base;
diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h
index 171abf8097ee..bedab1a942c4 100644
--- a/drivers/net/bnx2x/bnx2x_link.h
+++ b/drivers/net/bnx2x/bnx2x_link.h
@@ -65,6 +65,22 @@
#define FW_PARAM_MDIO_CTRL_OFFSET 16
#define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \
(phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET)
+
+#define PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE 170
+#define PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE 0
+
+#define PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE 250
+#define PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE 0
+
+#define PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE 10
+#define PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE 90
+
+#define PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE 50
+#define PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE 250
+
+#define PFC_BRB_FULL_LB_XOFF_THRESHOLD 170
+#define PFC_BRB_FULL_LB_XON_THRESHOLD 250
+
/***********************************************************/
/* Structs */
/***********************************************************/
@@ -216,6 +232,7 @@ struct link_params {
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
+#define FEATURE_CONFIG_PFC_ENABLED (1<<1)
#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
#define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY (1<<3)
/* Will be populated during common init */
@@ -332,4 +349,43 @@ u8 bnx2x_phy_probe(struct link_params *params);
u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base,
u32 shmem2_base, u8 port);
+/* PFC port configuration params */
+struct bnx2x_nig_brb_pfc_port_params {
+ /* NIG */
+ u32 pause_enable;
+ u32 llfc_out_en;
+ u32 llfc_enable;
+ u32 pkt_priority_to_cos;
+ u32 rx_cos0_priority_mask;
+ u32 rx_cos1_priority_mask;
+ u32 llfc_high_priority_classes;
+ u32 llfc_low_priority_classes;
+ /* BRB */
+ u32 cos0_pauseable;
+ u32 cos1_pauseable;
+};
+
+/**
+ * Used to update the PFC attributes in EMAC, BMAC, NIG and BRB
+ * when link is already up
+ */
+void bnx2x_update_pfc(struct link_params *params,
+ struct link_vars *vars,
+ struct bnx2x_nig_brb_pfc_port_params *pfc_params);
+
+
+/* Used to configure the ETS to disable */
+void bnx2x_ets_disabled(struct link_params *params);
+
+/* Used to configure the ETS to BW limited */
+void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
+ const u32 cos1_bw);
+
+/* Used to configure the ETS to strict */
+u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos);
+
+/* Read pfc statistic*/
+void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
+ u32 pfc_frames_sent[2],
+ u32 pfc_frames_received[2]);
#endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index e9ad16f00b56..8cdcf5b39d1e 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -55,6 +55,7 @@
#include "bnx2x_init.h"
#include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h"
+#include "bnx2x_dcb.h"
#include <linux/firmware.h>
#include "bnx2x_fw_file_hdr.h"
@@ -121,6 +122,10 @@ MODULE_PARM_DESC(debug, " Default debug msglevel");
static struct workqueue_struct *bnx2x_wq;
+#ifdef BCM_CNIC
+static u8 ALL_ENODE_MACS[] = {0x01, 0x10, 0x18, 0x01, 0x00, 0x01};
+#endif
+
enum bnx2x_board_type {
BCM57710 = 0,
BCM57711 = 1,
@@ -921,7 +926,7 @@ void bnx2x_panic_dump(struct bnx2x *bp)
sp_sb_data.p_func.vf_valid);
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
int loop;
struct hc_status_block_data_e2 sb_data_e2;
@@ -961,6 +966,10 @@ void bnx2x_panic_dump(struct bnx2x *bp)
/* host sb data */
+#ifdef BCM_CNIC
+ if (IS_FCOE_FP(fp))
+ continue;
+#endif
BNX2X_ERR(" run indexes (");
for (j = 0; j < HC_SB_MAX_SM; j++)
pr_cont("0x%x%s",
@@ -1029,7 +1038,7 @@ void bnx2x_panic_dump(struct bnx2x *bp)
#ifdef BNX2X_STOP_ON_ERROR
/* Rings */
/* Rx */
- for_each_queue(bp, i) {
+ for_each_rx_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
@@ -1063,7 +1072,7 @@ void bnx2x_panic_dump(struct bnx2x *bp)
}
/* Tx */
- for_each_queue(bp, i) {
+ for_each_tx_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
@@ -1298,7 +1307,7 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
#ifdef BCM_CNIC
offset++;
#endif
- for_each_queue(bp, i)
+ for_each_eth_queue(bp, i)
synchronize_irq(bp->msix_table[i + offset].vector);
} else
synchronize_irq(bp->pdev->irq);
@@ -1420,7 +1429,7 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
return IRQ_HANDLED;
#endif
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
mask = 0x2 << (fp->index + CNIC_CONTEXT_USE);
@@ -2026,13 +2035,28 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
static void bnx2x_read_mf_cfg(struct bnx2x *bp)
{
- int vn;
+ int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1);
if (BP_NOMCP(bp))
return; /* what should be the default bvalue in this case */
+ /* For 2 port configuration the absolute function number formula
+ * is:
+ * abs_func = 2 * vn + BP_PORT + BP_PATH
+ *
+ * and there are 4 functions per port
+ *
+ * For 4 port configuration it is
+ * abs_func = 4 * vn + 2 * BP_PORT + BP_PATH
+ *
+ * and there are 2 functions per port
+ */
for (vn = VN_0; vn < E1HVN_MAX; vn++) {
- int /*abs*/func = 2*vn + BP_PORT(bp);
+ int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp);
+
+ if (func >= E1H_FUNC_MAX)
+ break;
+
bp->mf_config[vn] =
MF_CFG_RD(bp, func_mf_config[func].config);
}
@@ -2238,6 +2262,15 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
return rc;
}
+static u8 stat_counter_valid(struct bnx2x *bp, struct bnx2x_fastpath *fp)
+{
+#ifdef BCM_CNIC
+ if (IS_FCOE_FP(fp) && IS_MF(bp))
+ return false;
+#endif
+ return true;
+}
+
/* must be called under rtnl_lock */
static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
{
@@ -2248,10 +2281,21 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0;
u8 unmatched_unicast = 0;
+ if (filters & BNX2X_ACCEPT_UNMATCHED_UCAST)
+ unmatched_unicast = 1;
+
if (filters & BNX2X_PROMISCUOUS_MODE) {
/* promiscious - accept all, drop none */
drop_all_ucast = drop_all_bcast = drop_all_mcast = 0;
accp_all_ucast = accp_all_bcast = accp_all_mcast = 1;
+ if (IS_MF_SI(bp)) {
+ /*
+ * SI mode defines to accept in promiscuos mode
+ * only unmatched packets
+ */
+ unmatched_unicast = 1;
+ accp_all_ucast = 0;
+ }
}
if (filters & BNX2X_ACCEPT_UNICAST) {
/* accept matched ucast */
@@ -2260,6 +2304,11 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
if (filters & BNX2X_ACCEPT_MULTICAST) {
/* accept matched mcast */
drop_all_mcast = 0;
+ if (IS_MF_SI(bp))
+ /* since mcast addresses won't arrive with ovlan,
+ * fw needs to accept all of them in
+ * switch-independent mode */
+ accp_all_mcast = 1;
}
if (filters & BNX2X_ACCEPT_ALL_UNICAST) {
/* accept all mcast */
@@ -2372,7 +2421,7 @@ static inline u16 bnx2x_get_cl_flags(struct bnx2x *bp,
/* calculate queue flags */
flags |= QUEUE_FLG_CACHE_ALIGN;
flags |= QUEUE_FLG_HC;
- flags |= IS_MF(bp) ? QUEUE_FLG_OV : 0;
+ flags |= IS_MF_SD(bp) ? QUEUE_FLG_OV : 0;
flags |= QUEUE_FLG_VLAN;
DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
@@ -2380,7 +2429,8 @@ static inline u16 bnx2x_get_cl_flags(struct bnx2x *bp,
if (!fp->disable_tpa)
flags |= QUEUE_FLG_TPA;
- flags |= QUEUE_FLG_STATS;
+ flags = stat_counter_valid(bp, fp) ?
+ (flags | QUEUE_FLG_STATS) : (flags & ~QUEUE_FLG_STATS);
return flags;
}
@@ -2440,7 +2490,10 @@ static void bnx2x_pf_rx_cl_prep(struct bnx2x *bp,
rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
rxq_init->fw_sb_id = fp->fw_sb_id;
- rxq_init->sb_cq_index = U_SB_ETH_RX_CQ_INDEX;
+ if (IS_FCOE_FP(fp))
+ rxq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS;
+ else
+ rxq_init->sb_cq_index = U_SB_ETH_RX_CQ_INDEX;
rxq_init->cid = HW_CID(bp, fp->cid);
@@ -2460,6 +2513,12 @@ static void bnx2x_pf_tx_cl_prep(struct bnx2x *bp,
txq_init->sb_cq_index = C_SB_ETH_TX_CQ_INDEX;
txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW;
txq_init->fw_sb_id = fp->fw_sb_id;
+
+ if (IS_FCOE_FP(fp)) {
+ txq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS;
+ txq_init->traffic_type = LLFC_TRAFFIC_TYPE_FCOE;
+ }
+
txq_init->hc_rate = bp->tx_ticks ? (1000000 / bp->tx_ticks) : 0;
}
@@ -2573,6 +2632,26 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
*/
}
+/* called due to MCP event (on pmf):
+ * reread new bandwidth configuration
+ * configure FW
+ * notify others function about the change
+ */
+static inline void bnx2x_config_mf_bw(struct bnx2x *bp)
+{
+ if (bp->link_vars.link_up) {
+ bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
+ bnx2x_link_sync_notify(bp);
+ }
+ storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+}
+
+static inline void bnx2x_set_mf_bw(struct bnx2x *bp)
+{
+ bnx2x_config_mf_bw(bp);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0);
+}
+
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
{
DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
@@ -2598,10 +2677,7 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
}
if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
-
- bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
- bnx2x_link_sync_notify(bp);
- storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+ bnx2x_config_mf_bw(bp);
dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
}
@@ -3022,10 +3098,20 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
if (val & DRV_STATUS_DCC_EVENT_MASK)
bnx2x_dcc_event(bp,
(val & DRV_STATUS_DCC_EVENT_MASK));
+
+ if (val & DRV_STATUS_SET_MF_BW)
+ bnx2x_set_mf_bw(bp);
+
bnx2x__link_status_update(bp);
if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
bnx2x_pmf_update(bp);
+ if (bp->port.pmf &&
+ (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) &&
+ bp->dcbx_enabled > 0)
+ /* start dcbx state machine */
+ bnx2x_dcbx_set_params(bp,
+ BNX2X_DCBX_STATE_NEG_RECEIVED);
} else if (attn & BNX2X_MC_ASSERT_BITS) {
BNX2X_ERR("MC assert!\n");
@@ -3066,7 +3152,6 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
#define LOAD_COUNTER_MASK (((u32)0x1 << LOAD_COUNTER_BITS) - 1)
#define RESET_DONE_FLAG_MASK (~LOAD_COUNTER_MASK)
#define RESET_DONE_FLAG_SHIFT LOAD_COUNTER_BITS
-#define CHIP_PARITY_SUPPORTED(bp) (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
/*
* should be run under rtnl lock
@@ -3441,7 +3526,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
try to handle this event */
bnx2x_acquire_alr(bp);
- if (bnx2x_chk_parity_attn(bp)) {
+ if (CHIP_PARITY_ENABLED(bp) && bnx2x_chk_parity_attn(bp)) {
bp->recovery_state = BNX2X_RECOVERY_INIT;
bnx2x_set_reset_in_progress(bp);
schedule_delayed_work(&bp->reset_task, 0);
@@ -3637,11 +3722,23 @@ static void bnx2x_eq_int(struct bnx2x *bp)
#ifdef BCM_CNIC
if (!bnx2x_cnic_handle_cfc_del(bp, cid, elem))
goto next_spqe;
+ if (cid == BNX2X_FCOE_ETH_CID)
+ bnx2x_fcoe(bp, state) = BNX2X_FP_STATE_CLOSED;
+ else
#endif
- bnx2x_fp(bp, cid, state) =
+ bnx2x_fp(bp, cid, state) =
BNX2X_FP_STATE_CLOSED;
goto next_spqe;
+
+ case EVENT_RING_OPCODE_STOP_TRAFFIC:
+ DP(NETIF_MSG_IFUP, "got STOP TRAFFIC\n");
+ bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED);
+ goto next_spqe;
+ case EVENT_RING_OPCODE_START_TRAFFIC:
+ DP(NETIF_MSG_IFUP, "got START TRAFFIC\n");
+ bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED);
+ goto next_spqe;
}
switch (opcode | bp->state) {
@@ -3714,7 +3811,13 @@ static void bnx2x_sp_task(struct work_struct *work)
/* SP events: STAT_QUERY and others */
if (status & BNX2X_DEF_SB_IDX) {
+#ifdef BCM_CNIC
+ struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+ if ((!NO_FCOE(bp)) &&
+ (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp)))
+ napi_schedule(&bnx2x_fcoe(bp, napi));
+#endif
/* Handle EQ completions */
bnx2x_eq_int(bp);
@@ -4097,7 +4200,7 @@ void bnx2x_update_coalesce(struct bnx2x *bp)
{
int i;
- for_each_queue(bp, i)
+ for_each_eth_queue(bp, i)
bnx2x_update_coalesce_sb(bp, bp->fp[i].fw_sb_id,
bp->rx_ticks, bp->tx_ticks);
}
@@ -4145,13 +4248,16 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
REG_WR8(bp, BAR_TSTRORM_INTMEM +
TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
- bp->fp->cl_id + (i % bp->num_queues));
+ bp->fp->cl_id + (i % (bp->num_queues -
+ NONE_ETH_CONTEXT_USE)));
}
void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
{
int mode = bp->rx_mode;
+ int port = BP_PORT(bp);
u16 cl_id;
+ u32 def_q_filters = 0;
/* All but management unicast packets should pass to the host as well */
u32 llh_mask =
@@ -4162,30 +4268,42 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
switch (mode) {
case BNX2X_RX_MODE_NONE: /* no Rx */
- cl_id = BP_L_ID(bp);
- bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE);
+ def_q_filters = BNX2X_ACCEPT_NONE;
+#ifdef BCM_CNIC
+ if (!NO_FCOE(bp)) {
+ cl_id = bnx2x_fcoe(bp, cl_id);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE);
+ }
+#endif
break;
case BNX2X_RX_MODE_NORMAL:
- cl_id = BP_L_ID(bp);
- bnx2x_rxq_set_mac_filters(bp, cl_id,
- BNX2X_ACCEPT_UNICAST |
- BNX2X_ACCEPT_BROADCAST |
- BNX2X_ACCEPT_MULTICAST);
+ def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
+ BNX2X_ACCEPT_MULTICAST;
+#ifdef BCM_CNIC
+ cl_id = bnx2x_fcoe(bp, cl_id);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_MULTICAST);
+#endif
break;
case BNX2X_RX_MODE_ALLMULTI:
- cl_id = BP_L_ID(bp);
- bnx2x_rxq_set_mac_filters(bp, cl_id,
- BNX2X_ACCEPT_UNICAST |
- BNX2X_ACCEPT_BROADCAST |
- BNX2X_ACCEPT_ALL_MULTICAST);
+ def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
+ BNX2X_ACCEPT_ALL_MULTICAST;
+#ifdef BCM_CNIC
+ cl_id = bnx2x_fcoe(bp, cl_id);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_MULTICAST);
+#endif
break;
case BNX2X_RX_MODE_PROMISC:
- cl_id = BP_L_ID(bp);
- bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_PROMISCUOUS_MODE);
-
+ def_q_filters |= BNX2X_PROMISCUOUS_MODE;
+#ifdef BCM_CNIC
+ cl_id = bnx2x_fcoe(bp, cl_id);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_MULTICAST);
+#endif
/* pass management unicast packets as well */
llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
break;
@@ -4195,20 +4313,24 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
break;
}
+ cl_id = BP_L_ID(bp);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, def_q_filters);
+
REG_WR(bp,
- BP_PORT(bp) ? NIG_REG_LLH1_BRB1_DRV_MASK :
- NIG_REG_LLH0_BRB1_DRV_MASK,
- llh_mask);
+ (port ? NIG_REG_LLH1_BRB1_DRV_MASK :
+ NIG_REG_LLH0_BRB1_DRV_MASK), llh_mask);
DP(NETIF_MSG_IFUP, "rx mode %d\n"
"drop_ucast 0x%x\ndrop_mcast 0x%x\ndrop_bcast 0x%x\n"
- "accp_ucast 0x%x\naccp_mcast 0x%x\naccp_bcast 0x%x\n", mode,
+ "accp_ucast 0x%x\naccp_mcast 0x%x\naccp_bcast 0x%x\n"
+ "unmatched_ucast 0x%x\n", mode,
bp->mac_filters.ucast_drop_all,
bp->mac_filters.mcast_drop_all,
bp->mac_filters.bcast_drop_all,
bp->mac_filters.ucast_accept_all,
bp->mac_filters.mcast_accept_all,
- bp->mac_filters.bcast_accept_all
+ bp->mac_filters.bcast_accept_all,
+ bp->mac_filters.unmatched_unicast
);
storm_memset_mac_filters(bp, &bp->mac_filters, BP_FUNC(bp));
@@ -4232,6 +4354,15 @@ static void bnx2x_init_internal_common(struct bnx2x *bp)
bp->mf_mode);
}
+ if (IS_MF_SI(bp))
+ /*
+ * In switch independent mode, the TSTORM needs to accept
+ * packets that failed classification, since approximate match
+ * mac addresses aren't written to NIG LLH
+ */
+ REG_WR8(bp, BAR_TSTRORM_INTMEM +
+ TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2);
+
/* Zero this manually as its initialization is
currently missing in the initTool */
for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
@@ -4247,6 +4378,7 @@ static void bnx2x_init_internal_common(struct bnx2x *bp)
static void bnx2x_init_internal_port(struct bnx2x *bp)
{
/* port */
+ bnx2x_dcb_init_intmem_pfc(bp);
}
static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
@@ -4308,9 +4440,11 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
{
int i;
- for_each_queue(bp, i)
+ for_each_eth_queue(bp, i)
bnx2x_init_fp_sb(bp, i);
#ifdef BCM_CNIC
+ if (!NO_FCOE(bp))
+ bnx2x_init_fcoe_fp(bp);
bnx2x_init_sb(bp, bp->cnic_sb_mapping,
BNX2X_VF_ID_INVALID, false,
@@ -4619,7 +4753,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
return 0; /* OK */
}
-static void enable_blocks_attention(struct bnx2x *bp)
+static void bnx2x_enable_blocks_attention(struct bnx2x *bp)
{
REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
if (CHIP_IS_E2(bp))
@@ -4673,53 +4807,9 @@ static void enable_blocks_attention(struct bnx2x *bp)
REG_WR(bp, CDU_REG_CDU_INT_MASK, 0);
REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0);
/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */
- REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */
-}
-
-static const struct {
- u32 addr;
- u32 mask;
-} bnx2x_parity_mask[] = {
- {PXP_REG_PXP_PRTY_MASK, 0x3ffffff},
- {PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
- {PXP2_REG_PXP2_PRTY_MASK_1, 0x7f},
- {HC_REG_HC_PRTY_MASK, 0x7},
- {MISC_REG_MISC_PRTY_MASK, 0x1},
- {QM_REG_QM_PRTY_MASK, 0x0},
- {DORQ_REG_DORQ_PRTY_MASK, 0x0},
- {GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
- {GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
- {SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
- {CDU_REG_CDU_PRTY_MASK, 0x0},
- {CFC_REG_CFC_PRTY_MASK, 0x0},
- {DBG_REG_DBG_PRTY_MASK, 0x0},
- {DMAE_REG_DMAE_PRTY_MASK, 0x0},
- {BRB1_REG_BRB1_PRTY_MASK, 0x0},
- {PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
- {TSDM_REG_TSDM_PRTY_MASK, 0x18}, /* bit 3,4 */
- {CSDM_REG_CSDM_PRTY_MASK, 0x8}, /* bit 3 */
- {USDM_REG_USDM_PRTY_MASK, 0x38}, /* bit 3,4,5 */
- {XSDM_REG_XSDM_PRTY_MASK, 0x8}, /* bit 3 */
- {TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
- {TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
- {USEM_REG_USEM_PRTY_MASK_0, 0x0},
- {USEM_REG_USEM_PRTY_MASK_1, 0x0},
- {CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
- {CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
- {XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
- {XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
-};
-
-static void enable_blocks_parity(struct bnx2x *bp)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bnx2x_parity_mask); i++)
- REG_WR(bp, bnx2x_parity_mask[i].addr,
- bnx2x_parity_mask[i].mask);
+ REG_WR(bp, PBF_REG_PBF_INT_MASK, 0x18); /* bit 3,4 masked */
}
-
static void bnx2x_reset_common(struct bnx2x *bp)
{
/* reset_common */
@@ -4947,7 +5037,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
memset(&ilt_cli, 0, sizeof(struct ilt_client_info));
memset(&ilt, 0, sizeof(struct bnx2x_ilt));
- /* initalize dummy TM client */
+ /* initialize dummy TM client */
ilt_cli.start = 0;
ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1;
ilt_cli.client_num = ILT_CLIENT_TM;
@@ -5048,12 +5138,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
REG_WR(bp, PRS_REG_NIC_MODE, 1);
#endif
if (!CHIP_IS_E1(bp))
- REG_WR(bp, PRS_REG_E1HOV_MODE, IS_MF(bp));
+ REG_WR(bp, PRS_REG_E1HOV_MODE, IS_MF_SD(bp));
if (CHIP_IS_E2(bp)) {
/* Bit-map indicating which L2 hdrs may appear after the
basic Ethernet header */
- int has_ovlan = IS_MF(bp);
+ int has_ovlan = IS_MF_SD(bp);
REG_WR(bp, PRS_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6));
REG_WR(bp, PRS_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0));
}
@@ -5087,7 +5177,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
if (CHIP_IS_E2(bp)) {
- int has_ovlan = IS_MF(bp);
+ int has_ovlan = IS_MF_SD(bp);
REG_WR(bp, PBF_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6));
REG_WR(bp, PBF_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0));
}
@@ -5164,12 +5254,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE);
if (!CHIP_IS_E1(bp)) {
REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_MF(bp));
- REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF(bp));
+ REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF_SD(bp));
}
if (CHIP_IS_E2(bp)) {
/* Bit-map indicating which L2 hdrs may appear after the
basic Ethernet header */
- REG_WR(bp, NIG_REG_P0_HDRS_AFTER_BASIC, (IS_MF(bp) ? 7 : 6));
+ REG_WR(bp, NIG_REG_P0_HDRS_AFTER_BASIC, (IS_MF_SD(bp) ? 7 : 6));
}
if (CHIP_REV_IS_SLOW(bp))
@@ -5215,9 +5305,9 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
/* clear PXP2 attentions */
REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
- enable_blocks_attention(bp);
- if (CHIP_PARITY_SUPPORTED(bp))
- enable_blocks_parity(bp);
+ bnx2x_enable_blocks_attention(bp);
+ if (CHIP_PARITY_ENABLED(bp))
+ bnx2x_enable_blocks_parity(bp);
if (!BP_NOMCP(bp)) {
/* In E2 2-PORT mode, same ext phy is used for the two paths */
@@ -5370,8 +5460,10 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
* - SF mode: bits 3-7 are masked. only bits 0-2 are in use
* - MF mode: bit 3 is masked. bits 0-2 are in use as in SF
* bits 4-7 are used for "per vn group attention" */
- REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4,
- (IS_MF(bp) ? 0xF7 : 0x7));
+ val = IS_MF(bp) ? 0xF7 : 0x7;
+ /* Enable DCBX attention for all but E1 */
+ val |= CHIP_IS_E1(bp) ? 0 : 0x10;
+ REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, val);
bnx2x_init_block(bp, PXPCS_BLOCK, init_stage);
bnx2x_init_block(bp, EMAC0_BLOCK, init_stage);
@@ -5386,7 +5478,7 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
if (!CHIP_IS_E1(bp)) {
/* 0x2 disable mf_ov, 0x1 enable */
REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
- (IS_MF(bp) ? 0x1 : 0x2));
+ (IS_MF_SD(bp) ? 0x1 : 0x2));
if (CHIP_IS_E2(bp)) {
val = 0;
@@ -5816,6 +5908,15 @@ void bnx2x_free_mem(struct bnx2x *bp)
/* fastpath */
/* Common */
for_each_queue(bp, i) {
+#ifdef BCM_CNIC
+ /* FCoE client uses default status block */
+ if (IS_FCOE_IDX(i)) {
+ union host_hc_status_block *sb =
+ &bnx2x_fp(bp, i, status_blk);
+ memset(sb, 0, sizeof(union host_hc_status_block));
+ bnx2x_fp(bp, i, status_blk_mapping) = 0;
+ } else {
+#endif
/* status blocks */
if (CHIP_IS_E2(bp))
BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb),
@@ -5825,9 +5926,12 @@ void bnx2x_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb),
bnx2x_fp(bp, i, status_blk_mapping),
sizeof(struct host_hc_status_block_e1x));
+#ifdef BCM_CNIC
+ }
+#endif
}
/* Rx */
- for_each_queue(bp, i) {
+ for_each_rx_queue(bp, i) {
/* fastpath rx rings: rx_buf rx_desc rx_comp */
BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
@@ -5847,7 +5951,7 @@ void bnx2x_free_mem(struct bnx2x *bp)
BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
}
/* Tx */
- for_each_queue(bp, i) {
+ for_each_tx_queue(bp, i) {
/* fastpath tx rings: tx_buf tx_desc */
BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
@@ -5931,15 +6035,20 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk);
bnx2x_fp(bp, i, bp) = bp;
/* status blocks */
- if (CHIP_IS_E2(bp))
- BNX2X_PCI_ALLOC(sb->e2_sb,
- &bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e2));
- else
- BNX2X_PCI_ALLOC(sb->e1x_sb,
- &bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e1x));
-
+#ifdef BCM_CNIC
+ if (!IS_FCOE_IDX(i)) {
+#endif
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_ALLOC(sb->e2_sb,
+ &bnx2x_fp(bp, i, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_ALLOC(sb->e1x_sb,
+ &bnx2x_fp(bp, i, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
+#ifdef BCM_CNIC
+ }
+#endif
set_sb_shortcuts(bp, i);
}
/* Rx */
@@ -6055,7 +6164,7 @@ static int bnx2x_func_stop(struct bnx2x *bp)
* @param cam_offset offset in a CAM to use
* @param is_bcast is the set MAC a broadcast address (for E1 only)
*/
-static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, u8 *mac,
+static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac,
u32 cl_bit_vec, u8 cam_offset,
u8 is_bcast)
{
@@ -6170,6 +6279,70 @@ static u8 bnx2x_e1h_cam_offset(struct bnx2x *bp, u8 rel_offset)
return BP_VN(bp) * 32 + rel_offset;
}
+/**
+ * LLH CAM line allocations: currently only iSCSI and ETH macs are
+ * relevant. In addition, current implementation is tuned for a
+ * single ETH MAC.
+ *
+ * When multiple unicast ETH MACs PF configuration in switch
+ * independent mode is required (NetQ, multiple netdev MACs,
+ * etc.), consider better utilisation of 16 per function MAC
+ * entries in the LLH memory.
+ */
+enum {
+ LLH_CAM_ISCSI_ETH_LINE = 0,
+ LLH_CAM_ETH_LINE,
+ LLH_CAM_MAX_PF_LINE = NIG_REG_LLH1_FUNC_MEM_SIZE
+};
+
+static void bnx2x_set_mac_in_nig(struct bnx2x *bp,
+ int set,
+ unsigned char *dev_addr,
+ int index)
+{
+ u32 wb_data[2];
+ u32 mem_offset, ena_offset, mem_index;
+ /**
+ * indexes mapping:
+ * 0..7 - goes to MEM
+ * 8..15 - goes to MEM2
+ */
+
+ if (!IS_MF_SI(bp) || index > LLH_CAM_MAX_PF_LINE)
+ return;
+
+ /* calculate memory start offset according to the mapping
+ * and index in the memory */
+ if (index < NIG_LLH_FUNC_MEM_MAX_OFFSET) {
+ mem_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM :
+ NIG_REG_LLH0_FUNC_MEM;
+ ena_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM_ENABLE :
+ NIG_REG_LLH0_FUNC_MEM_ENABLE;
+ mem_index = index;
+ } else {
+ mem_offset = BP_PORT(bp) ? NIG_REG_P1_LLH_FUNC_MEM2 :
+ NIG_REG_P0_LLH_FUNC_MEM2;
+ ena_offset = BP_PORT(bp) ? NIG_REG_P1_LLH_FUNC_MEM2_ENABLE :
+ NIG_REG_P0_LLH_FUNC_MEM2_ENABLE;
+ mem_index = index - NIG_LLH_FUNC_MEM_MAX_OFFSET;
+ }
+
+ if (set) {
+ /* LLH_FUNC_MEM is a u64 WB register */
+ mem_offset += 8*mem_index;
+
+ wb_data[0] = ((dev_addr[2] << 24) | (dev_addr[3] << 16) |
+ (dev_addr[4] << 8) | dev_addr[5]);
+ wb_data[1] = ((dev_addr[0] << 8) | dev_addr[1]);
+
+ REG_WR_DMAE(bp, mem_offset, wb_data, 2);
+ }
+
+ /* enable/disable the entry */
+ REG_WR(bp, ena_offset + 4*mem_index, set);
+
+}
+
void bnx2x_set_eth_mac(struct bnx2x *bp, int set)
{
u8 cam_offset = (CHIP_IS_E1(bp) ? (BP_PORT(bp) ? 32 : 0) :
@@ -6179,9 +6352,13 @@ void bnx2x_set_eth_mac(struct bnx2x *bp, int set)
bnx2x_set_mac_addr_gen(bp, set, bp->dev->dev_addr,
(1 << bp->fp->cl_id), cam_offset , 0);
+ bnx2x_set_mac_in_nig(bp, set, bp->dev->dev_addr, LLH_CAM_ETH_LINE);
+
if (CHIP_IS_E1(bp)) {
/* broadcast MAC */
- u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ static const u8 bcast[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
bnx2x_set_mac_addr_gen(bp, set, bcast, 0, cam_offset + 1, 1);
}
}
@@ -6283,12 +6460,59 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
{
u8 cam_offset = (CHIP_IS_E1(bp) ? ((BP_PORT(bp) ? 32 : 0) + 2) :
bnx2x_e1h_cam_offset(bp, CAM_ISCSI_ETH_LINE));
- u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID;
+ u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID +
+ BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE;
u32 cl_bit_vec = (1 << iscsi_l2_cl_id);
/* Send a SET_MAC ramrod */
bnx2x_set_mac_addr_gen(bp, set, bp->iscsi_mac, cl_bit_vec,
cam_offset, 0);
+
+ bnx2x_set_mac_in_nig(bp, set, bp->iscsi_mac, LLH_CAM_ISCSI_ETH_LINE);
+
+ return 0;
+}
+
+/**
+ * Set FCoE L2 MAC(s) at the next enties in the CAM after the
+ * ETH MAC(s). This function will wait until the ramdord
+ * completion returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set)
+{
+ u32 cl_bit_vec = (1 << bnx2x_fcoe(bp, cl_id));
+ /**
+ * CAM allocation for E1H
+ * eth unicasts: by func number
+ * iscsi: by func number
+ * fip unicast: by func number
+ * fip multicast: by func number
+ */
+ bnx2x_set_mac_addr_gen(bp, set, bp->fip_mac,
+ cl_bit_vec, bnx2x_e1h_cam_offset(bp, CAM_FIP_ETH_LINE), 0);
+
+ return 0;
+}
+
+int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set)
+{
+ u32 cl_bit_vec = (1 << bnx2x_fcoe(bp, cl_id));
+
+ /**
+ * CAM allocation for E1H
+ * eth unicasts: by func number
+ * iscsi: by func number
+ * fip unicast: by func number
+ * fip multicast: by func number
+ */
+ bnx2x_set_mac_addr_gen(bp, set, ALL_ENODE_MACS, cl_bit_vec,
+ bnx2x_e1h_cam_offset(bp, CAM_FIP_MCAST_LINE), 0);
+
return 0;
}
#endif
@@ -6306,6 +6530,8 @@ static void bnx2x_fill_cl_init_data(struct bnx2x *bp,
data->general.statistics_counter_id = params->rxq_params.stat_id;
data->general.statistics_en_flg =
(params->rxq_params.flags & QUEUE_FLG_STATS) ? 1 : 0;
+ data->general.is_fcoe_flg =
+ (params->ramrod_params.flags & CLIENT_IS_FCOE) ? 1 : 0;
data->general.activate_flg = activate;
data->general.sp_client_id = params->rxq_params.spcl_id;
@@ -6374,7 +6600,9 @@ static void bnx2x_fill_cl_init_data(struct bnx2x *bp,
data->fc.safc_group_num = params->txq_params.cos;
data->fc.safc_group_en_flg =
(params->txq_params.flags & QUEUE_FLG_COS) ? 1 : 0;
- data->fc.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+ data->fc.traffic_type =
+ (params->ramrod_params.flags & CLIENT_IS_FCOE) ?
+ LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW;
}
static inline void bnx2x_set_ctx_validation(struct eth_context *cxt, u32 cid)
@@ -6473,7 +6701,7 @@ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp)
bnx2x_enable_msi(bp);
/* falling through... */
case INT_MODE_INTx:
- bp->num_queues = 1;
+ bp->num_queues = 1 + NONE_ETH_CONTEXT_USE;
DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
break;
default:
@@ -6496,8 +6724,8 @@ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp)
"enable MSI-X (%d), "
"set number of queues to %d\n",
bp->num_queues,
- 1);
- bp->num_queues = 1;
+ 1 + NONE_ETH_CONTEXT_USE);
+ bp->num_queues = 1 + NONE_ETH_CONTEXT_USE;
if (!(bp->flags & DISABLE_MSI_FLAG))
bnx2x_enable_msi(bp);
@@ -6618,7 +6846,9 @@ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp,
struct bnx2x_client_init_params params = { {0} };
int rc;
- bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0,
+ /* reset IGU state skip FCoE L2 queue */
+ if (!IS_FCOE_FP(fp))
+ bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0,
IGU_INT_ENABLE, 0);
params.ramrod_params.pstate = &fp->state;
@@ -6626,6 +6856,12 @@ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp,
params.ramrod_params.index = fp->index;
params.ramrod_params.cid = fp->cid;
+#ifdef BCM_CNIC
+ if (IS_FCOE_FP(fp))
+ params.ramrod_params.flags |= CLIENT_IS_FCOE;
+
+#endif
+
if (is_leading)
params.ramrod_params.flags |= CLIENT_IS_LEADING_RSS;
@@ -6710,7 +6946,7 @@ static void bnx2x_reset_func(struct bnx2x *bp)
REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(func), 0);
/* FP SBs */
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
REG_WR8(bp,
BAR_CSTRORM_INTMEM +
@@ -6830,6 +7066,20 @@ static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
}
}
+#ifdef BCM_CNIC
+static inline void bnx2x_del_fcoe_eth_macs(struct bnx2x *bp)
+{
+ if (bp->flags & FCOE_MACS_SET) {
+ if (!IS_MF_SD(bp))
+ bnx2x_set_fip_eth_mac_addr(bp, 0);
+
+ bnx2x_set_all_enode_macs(bp, 0);
+
+ bp->flags &= ~FCOE_MACS_SET;
+ }
+}
+#endif
+
void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
{
int port = BP_PORT(bp);
@@ -6837,7 +7087,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
int i, cnt, rc;
/* Wait until tx fastpath tasks complete */
- for_each_queue(bp, i) {
+ for_each_tx_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
cnt = 1000;
@@ -6877,13 +7127,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
}
#ifdef BCM_CNIC
- /* Clear iSCSI L2 MAC */
- mutex_lock(&bp->cnic_mutex);
- if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
- bnx2x_set_iscsi_eth_mac_addr(bp, 0);
- bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
- }
- mutex_unlock(&bp->cnic_mutex);
+ bnx2x_del_fcoe_eth_macs(bp);
#endif
if (unload_mode == UNLOAD_NORMAL)
@@ -7736,7 +7980,7 @@ static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp)
bp->igu_sb_cnt = 0;
if (CHIP_INT_MODE_IS_BC(bp)) {
bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x,
- bp->l2_cid_count);
+ NUM_IGU_SB_REQUIRED(bp->l2_cid_count));
bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) *
FP_SB_MAX_E1x;
@@ -7767,7 +8011,8 @@ static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp)
}
}
}
- bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt, bp->l2_cid_count);
+ bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt,
+ NUM_IGU_SB_REQUIRED(bp->l2_cid_count));
if (bp->igu_sb_cnt == 0)
BNX2X_ERR("CAM configuration error\n");
}
@@ -8076,9 +8321,8 @@ static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
{
int port = BP_PORT(bp);
- u32 val, val2;
u32 config;
- u32 ext_phy_type, ext_phy_config;;
+ u32 ext_phy_type, ext_phy_config;
bp->link_params.bp = bp;
bp->link_params.port = port;
@@ -8135,25 +8379,73 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
bp->mdio.prtad =
XGXS_EXT_PHY_ADDR(ext_phy_config);
+}
+
+static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
+{
+ u32 val, val2;
+ int func = BP_ABS_FUNC(bp);
+ int port = BP_PORT(bp);
+
+ if (BP_NOMCP(bp)) {
+ BNX2X_ERROR("warning: random MAC workaround active\n");
+ random_ether_addr(bp->dev->dev_addr);
+ } else if (IS_MF(bp)) {
+ val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper);
+ val = MF_CFG_RD(bp, func_mf_config[func].mac_lower);
+ if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) &&
+ (val != FUNC_MF_CFG_LOWERMAC_DEFAULT))
+ bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
+
+#ifdef BCM_CNIC
+ /* iSCSI NPAR MAC */
+ if (IS_MF_SI(bp)) {
+ u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg);
+ if (cfg & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD) {
+ val2 = MF_CFG_RD(bp, func_ext_config[func].
+ iscsi_mac_addr_upper);
+ val = MF_CFG_RD(bp, func_ext_config[func].
+ iscsi_mac_addr_lower);
+ bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+ }
+ }
+#endif
+ } else {
+ /* in SF read MACs from port configuration */
+ val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
+ val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
+ bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
+
+#ifdef BCM_CNIC
+ val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].
+ iscsi_mac_upper);
+ val = SHMEM_RD(bp, dev_info.port_hw_config[port].
+ iscsi_mac_lower);
+ bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+#endif
+ }
- val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
- val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
- bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
#ifdef BCM_CNIC
- val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
- val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
- bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+ /* Inform the upper layers about FCoE MAC */
+ if (!CHIP_IS_E1x(bp)) {
+ if (IS_MF_SD(bp))
+ memcpy(bp->fip_mac, bp->dev->dev_addr,
+ sizeof(bp->fip_mac));
+ else
+ memcpy(bp->fip_mac, bp->iscsi_mac,
+ sizeof(bp->fip_mac));
+ }
#endif
}
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
{
- int func = BP_ABS_FUNC(bp);
- int vn;
- u32 val, val2;
+ int /*abs*/func = BP_ABS_FUNC(bp);
+ int vn, port;
+ u32 val = 0;
int rc = 0;
bnx2x_get_common_hwinfo(bp);
@@ -8163,7 +8455,8 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->igu_dsb_id = DEF_SB_IGU_ID;
bp->igu_base_sb = 0;
- bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x, bp->l2_cid_count);
+ bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x,
+ NUM_IGU_SB_REQUIRED(bp->l2_cid_count));
} else {
bp->common.int_block = INT_BLOCK_IGU;
val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
@@ -8186,44 +8479,99 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->mf_ov = 0;
bp->mf_mode = 0;
vn = BP_E1HVN(bp);
+ port = BP_PORT(bp);
+
if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
+ DP(NETIF_MSG_PROBE,
+ "shmem2base 0x%x, size %d, mfcfg offset %d\n",
+ bp->common.shmem2_base, SHMEM2_RD(bp, size),
+ (u32)offsetof(struct shmem2_region, mf_cfg_addr));
if (SHMEM2_HAS(bp, mf_cfg_addr))
bp->common.mf_cfg_base = SHMEM2_RD(bp, mf_cfg_addr);
else
bp->common.mf_cfg_base = bp->common.shmem_base +
offsetof(struct shmem_region, func_mb) +
E1H_FUNC_MAX * sizeof(struct drv_func_mb);
- bp->mf_config[vn] =
- MF_CFG_RD(bp, func_mf_config[func].config);
+ /*
+ * get mf configuration:
+ * 1. existance of MF configuration
+ * 2. MAC address must be legal (check only upper bytes)
+ * for Switch-Independent mode;
+ * OVLAN must be legal for Switch-Dependent mode
+ * 3. SF_MODE configures specific MF mode
+ */
+ if (bp->common.mf_cfg_base != SHMEM_MF_CFG_ADDR_NONE) {
+ /* get mf configuration */
+ val = SHMEM_RD(bp,
+ dev_info.shared_feature_config.config);
+ val &= SHARED_FEAT_CFG_FORCE_SF_MODE_MASK;
+
+ switch (val) {
+ case SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT:
+ val = MF_CFG_RD(bp, func_mf_config[func].
+ mac_upper);
+ /* check for legal mac (upper bytes)*/
+ if (val != 0xffff) {
+ bp->mf_mode = MULTI_FUNCTION_SI;
+ bp->mf_config[vn] = MF_CFG_RD(bp,
+ func_mf_config[func].config);
+ } else
+ DP(NETIF_MSG_PROBE, "illegal MAC "
+ "address for SI\n");
+ break;
+ case SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED:
+ /* get OV configuration */
+ val = MF_CFG_RD(bp,
+ func_mf_config[FUNC_0].e1hov_tag);
+ val &= FUNC_MF_CFG_E1HOV_TAG_MASK;
+
+ if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
+ bp->mf_mode = MULTI_FUNCTION_SD;
+ bp->mf_config[vn] = MF_CFG_RD(bp,
+ func_mf_config[func].config);
+ } else
+ DP(NETIF_MSG_PROBE, "illegal OV for "
+ "SD\n");
+ break;
+ default:
+ /* Unknown configuration: reset mf_config */
+ bp->mf_config[vn] = 0;
+ DP(NETIF_MSG_PROBE, "Unkown MF mode 0x%x\n",
+ val);
+ }
+ }
- val = (MF_CFG_RD(bp, func_mf_config[FUNC_0].e1hov_tag) &
- FUNC_MF_CFG_E1HOV_TAG_MASK);
- if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT)
- bp->mf_mode = 1;
BNX2X_DEV_INFO("%s function mode\n",
IS_MF(bp) ? "multi" : "single");
- if (IS_MF(bp)) {
- val = (MF_CFG_RD(bp, func_mf_config[func].
- e1hov_tag) &
- FUNC_MF_CFG_E1HOV_TAG_MASK);
+ switch (bp->mf_mode) {
+ case MULTI_FUNCTION_SD:
+ val = MF_CFG_RD(bp, func_mf_config[func].e1hov_tag) &
+ FUNC_MF_CFG_E1HOV_TAG_MASK;
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
bp->mf_ov = val;
- BNX2X_DEV_INFO("MF OV for func %d is %d "
- "(0x%04x)\n",
- func, bp->mf_ov, bp->mf_ov);
+ BNX2X_DEV_INFO("MF OV for func %d is %d"
+ " (0x%04x)\n", func,
+ bp->mf_ov, bp->mf_ov);
} else {
- BNX2X_ERROR("No valid MF OV for func %d,"
- " aborting\n", func);
+ BNX2X_ERR("No valid MF OV for func %d,"
+ " aborting\n", func);
rc = -EPERM;
}
- } else {
- if (BP_VN(bp)) {
- BNX2X_ERROR("VN %d in single function mode,"
- " aborting\n", BP_E1HVN(bp));
+ break;
+ case MULTI_FUNCTION_SI:
+ BNX2X_DEV_INFO("func %d is in MF "
+ "switch-independent mode\n", func);
+ break;
+ default:
+ if (vn) {
+ BNX2X_ERR("VN %d in single function mode,"
+ " aborting\n", vn);
rc = -EPERM;
}
+ break;
}
+
}
/* adjust igu_sb_cnt to MF for E1x */
@@ -8248,32 +8596,8 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
}
- if (IS_MF(bp)) {
- val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper);
- val = MF_CFG_RD(bp, func_mf_config[func].mac_lower);
- if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) &&
- (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) {
- bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
- bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
- bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
- bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
- bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff);
- bp->dev->dev_addr[5] = (u8)(val & 0xff);
- memcpy(bp->link_params.mac_addr, bp->dev->dev_addr,
- ETH_ALEN);
- memcpy(bp->dev->perm_addr, bp->dev->dev_addr,
- ETH_ALEN);
- }
-
- return rc;
- }
-
- if (BP_NOMCP(bp)) {
- /* only supposed to happen on emulation/FPGA */
- BNX2X_ERROR("warning: random MAC workaround active\n");
- random_ether_addr(bp->dev->dev_addr);
- memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
- }
+ /* Get MAC addresses */
+ bnx2x_get_mac_hwinfo(bp);
return rc;
}
@@ -8382,13 +8706,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
dev_err(&bp->pdev->dev, "MCP disabled, "
"must load devices in order!\n");
- /* Set multi queue mode */
- if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
- ((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
- dev_err(&bp->pdev->dev, "Multi disabled since int_mode "
- "requested is not MSI-X\n");
- multi_mode = ETH_RSS_MODE_DISABLED;
- }
bp->multi_mode = multi_mode;
bp->int_mode = int_mode;
@@ -8427,6 +8744,9 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bp->timer.data = (unsigned long) bp;
bp->timer.function = bnx2x_timer;
+ bnx2x_dcbx_set_state(bp, true, BNX2X_DCBX_ENABLED_ON_NEG_ON);
+ bnx2x_dcbx_init_params(bp);
+
return rc;
}
@@ -8629,6 +8949,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_open = bnx2x_open,
.ndo_stop = bnx2x_close,
.ndo_start_xmit = bnx2x_start_xmit,
+ .ndo_select_queue = bnx2x_select_queue,
.ndo_set_multicast_list = bnx2x_set_rx_mode,
.ndo_set_mac_address = bnx2x_change_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -8761,7 +9082,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->netdev_ops = &bnx2x_netdev_ops;
bnx2x_set_ethtool_ops(dev);
dev->features |= NETIF_F_SG;
- dev->features |= NETIF_F_HW_CSUM;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
@@ -8769,12 +9090,16 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
dev->vlan_features |= NETIF_F_SG;
- dev->vlan_features |= NETIF_F_HW_CSUM;
+ dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
if (bp->flags & USING_DAC_FLAG)
dev->vlan_features |= NETIF_F_HIGHDMA;
dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
dev->vlan_features |= NETIF_F_TSO6;
+#ifdef BCM_DCB
+ dev->dcbnl_ops = &bnx2x_dcbnl_ops;
+#endif
+
/* get_port_hwinfo() will set prtad and mmds properly */
bp->mdio.prtad = MDIO_PRTAD_NONE;
bp->mdio.mmds = 0;
@@ -9064,10 +9389,10 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
default:
pr_err("Unknown board_type (%ld), aborting\n",
ent->driver_data);
- return ENODEV;
+ return -ENODEV;
}
- cid_count += CNIC_CONTEXT_USE;
+ cid_count += NONE_ETH_CONTEXT_USE + CNIC_CONTEXT_USE;
/* dev zeroed in init_etherdev */
dev = alloc_etherdev_mq(sizeof(*bp), cid_count);
@@ -9096,11 +9421,12 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
/* calc qm_cid_count */
bp->qm_cid_count = bnx2x_set_qm_cid_count(bp, cid_count);
- rc = register_netdev(dev);
- if (rc) {
- dev_err(&pdev->dev, "Cannot register net device\n");
- goto init_one_exit;
- }
+#ifdef BCM_CNIC
+ /* disable FCOE L2 queue for E1x*/
+ if (CHIP_IS_E1x(bp))
+ bp->flags |= NO_FCOE_FLAG;
+
+#endif
/* Configure interupt mode: try to enable MSI-X/MSI if
* needed, set bp->num_queues appropriately.
@@ -9110,6 +9436,21 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
/* Add all NAPI objects */
bnx2x_add_all_napi(bp);
+ rc = register_netdev(dev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register net device\n");
+ goto init_one_exit;
+ }
+
+#ifdef BCM_CNIC
+ if (!NO_FCOE(bp)) {
+ /* Add storage MAC address */
+ rtnl_lock();
+ dev_addr_add(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN);
+ rtnl_unlock();
+ }
+#endif
+
bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
@@ -9153,14 +9494,29 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
}
bp = netdev_priv(dev);
+#ifdef BCM_CNIC
+ /* Delete storage MAC address */
+ if (!NO_FCOE(bp)) {
+ rtnl_lock();
+ dev_addr_del(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN);
+ rtnl_unlock();
+ }
+#endif
+
unregister_netdev(dev);
/* Delete all NAPI objects */
bnx2x_del_all_napi(bp);
+ /* Power on: we can't let PCI layer write to us while we are in D3 */
+ bnx2x_set_power_state(bp, PCI_D0);
+
/* Disable MSI/MSI-X */
bnx2x_disable_msi(bp);
+ /* Power off */
+ bnx2x_set_power_state(bp, PCI_D3hot);
+
/* Make sure RESET task is not scheduled before continuing */
cancel_delayed_work_sync(&bp->reset_task);
@@ -9202,7 +9558,7 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
- for_each_queue(bp, i)
+ for_each_rx_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
bnx2x_free_mem(bp);
@@ -9429,7 +9785,8 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
break;
else
atomic_dec(&bp->spq_left);
- } else if (type == ISCSI_CONNECTION_TYPE) {
+ } else if ((type == ISCSI_CONNECTION_TYPE) ||
+ (type == FCOE_CONNECTION_TYPE)) {
if (bp->cnic_spq_pending >=
bp->cnic_eth_dev.max_kwqe_pending)
break;
@@ -9576,6 +9933,9 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
case DRV_CTL_START_L2_CMD: {
u32 cli = ctl->data.ring.client_id;
+ /* Clear FCoE FIP and ALL ENODE MACs addresses first */
+ bnx2x_del_fcoe_eth_macs(bp);
+
/* Set iSCSI MAC address */
bnx2x_set_iscsi_eth_mac_addr(bp, 1);
@@ -9697,10 +10057,6 @@ static int bnx2x_unregister_cnic(struct net_device *dev)
struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
mutex_lock(&bp->cnic_mutex);
- if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
- bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
- bnx2x_set_iscsi_eth_mac_addr(bp, 0);
- }
cp->drv_state = 0;
rcu_assign_pointer(bp->cnic_ops, NULL);
mutex_unlock(&bp->cnic_mutex);
@@ -9731,7 +10087,9 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
cp->drv_ctl = bnx2x_drv_ctl;
cp->drv_register_cnic = bnx2x_register_cnic;
cp->drv_unregister_cnic = bnx2x_unregister_cnic;
- cp->iscsi_l2_client_id = BNX2X_ISCSI_ETH_CL_ID;
+ cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID;
+ cp->iscsi_l2_client_id = BNX2X_ISCSI_ETH_CL_ID +
+ BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE;
cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID;
DP(BNX2X_MSG_SP, "page_size %d, tbl_offset %d, tbl_lines %d, "
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index 1cefe489a955..c939683e3d61 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -18,6 +18,8 @@
* WR - Write Clear (write 1 to clear the bit)
*
*/
+#ifndef BNX2X_REG_H
+#define BNX2X_REG_H
#define ATC_ATC_INT_STS_REG_ADDRESS_ERROR (0x1<<0)
#define ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS (0x1<<2)
@@ -39,6 +41,8 @@
#define BRB1_REG_BRB1_PRTY_MASK 0x60138
/* [R 4] Parity register #0 read */
#define BRB1_REG_BRB1_PRTY_STS 0x6012c
+/* [RC 4] Parity register #0 read clear */
+#define BRB1_REG_BRB1_PRTY_STS_CLR 0x60130
/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At
* address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address
* BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. Warning -
@@ -132,8 +136,12 @@
#define CCM_REG_CCM_INT_MASK 0xd01e4
/* [R 11] Interrupt register #0 read */
#define CCM_REG_CCM_INT_STS 0xd01d8
+/* [RW 27] Parity mask register #0 read/write */
+#define CCM_REG_CCM_PRTY_MASK 0xd01f4
/* [R 27] Parity register #0 read */
#define CCM_REG_CCM_PRTY_STS 0xd01e8
+/* [RC 27] Parity register #0 read clear */
+#define CCM_REG_CCM_PRTY_STS_CLR 0xd01ec
/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS
REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
Is used to determine the number of the AG context REG-pairs written back;
@@ -350,6 +358,8 @@
#define CDU_REG_CDU_PRTY_MASK 0x10104c
/* [R 5] Parity register #0 read */
#define CDU_REG_CDU_PRTY_STS 0x101040
+/* [RC 5] Parity register #0 read clear */
+#define CDU_REG_CDU_PRTY_STS_CLR 0x101044
/* [RC 32] logging of error data in case of a CDU load error:
{expected_cid[15:0]; xpected_type[2:0]; xpected_region[2:0]; ctive_error;
ype_error; ctual_active; ctual_compressed_context}; */
@@ -381,6 +391,8 @@
#define CFC_REG_CFC_PRTY_MASK 0x104118
/* [R 4] Parity register #0 read */
#define CFC_REG_CFC_PRTY_STS 0x10410c
+/* [RC 4] Parity register #0 read clear */
+#define CFC_REG_CFC_PRTY_STS_CLR 0x104110
/* [RW 21] CID cam access (21:1 - Data; alid - 0) */
#define CFC_REG_CID_CAM 0x104800
#define CFC_REG_CONTROL0 0x104028
@@ -466,6 +478,8 @@
#define CSDM_REG_CSDM_PRTY_MASK 0xc22bc
/* [R 11] Parity register #0 read */
#define CSDM_REG_CSDM_PRTY_STS 0xc22b0
+/* [RC 11] Parity register #0 read clear */
+#define CSDM_REG_CSDM_PRTY_STS_CLR 0xc22b4
#define CSDM_REG_ENABLE_IN1 0xc2238
#define CSDM_REG_ENABLE_IN2 0xc223c
#define CSDM_REG_ENABLE_OUT1 0xc2240
@@ -556,6 +570,9 @@
/* [R 32] Parity register #0 read */
#define CSEM_REG_CSEM_PRTY_STS_0 0x200124
#define CSEM_REG_CSEM_PRTY_STS_1 0x200134
+/* [RC 32] Parity register #0 read clear */
+#define CSEM_REG_CSEM_PRTY_STS_CLR_0 0x200128
+#define CSEM_REG_CSEM_PRTY_STS_CLR_1 0x200138
#define CSEM_REG_ENABLE_IN 0x2000a4
#define CSEM_REG_ENABLE_OUT 0x2000a8
/* [RW 32] This address space contains all registers and memories that are
@@ -648,6 +665,8 @@
#define DBG_REG_DBG_PRTY_MASK 0xc0a8
/* [R 1] Parity register #0 read */
#define DBG_REG_DBG_PRTY_STS 0xc09c
+/* [RC 1] Parity register #0 read clear */
+#define DBG_REG_DBG_PRTY_STS_CLR 0xc0a0
/* [RW 1] When set the DMAE will process the commands as in E1.5. 1.The
* function that is used is always SRC-PCI; 2.VF_Valid = 0; 3.VFID=0;
* 4.Completion function=0; 5.Error handling=0 */
@@ -668,6 +687,8 @@
#define DMAE_REG_DMAE_PRTY_MASK 0x102064
/* [R 4] Parity register #0 read */
#define DMAE_REG_DMAE_PRTY_STS 0x102058
+/* [RC 4] Parity register #0 read clear */
+#define DMAE_REG_DMAE_PRTY_STS_CLR 0x10205c
/* [RW 1] Command 0 go. */
#define DMAE_REG_GO_C0 0x102080
/* [RW 1] Command 1 go. */
@@ -734,6 +755,8 @@
#define DORQ_REG_DORQ_PRTY_MASK 0x170190
/* [R 2] Parity register #0 read */
#define DORQ_REG_DORQ_PRTY_STS 0x170184
+/* [RC 2] Parity register #0 read clear */
+#define DORQ_REG_DORQ_PRTY_STS_CLR 0x170188
/* [RW 8] The address to write the DPM CID to STORM. */
#define DORQ_REG_DPM_CID_ADDR 0x170044
/* [RW 5] The DPM mode CID extraction offset. */
@@ -842,8 +865,12 @@
/* [R 1] data availble for error memory. If this bit is clear do not red
* from error_handling_memory. */
#define IGU_REG_ERROR_HANDLING_DATA_VALID 0x130130
+/* [RW 11] Parity mask register #0 read/write */
+#define IGU_REG_IGU_PRTY_MASK 0x1300a8
/* [R 11] Parity register #0 read */
#define IGU_REG_IGU_PRTY_STS 0x13009c
+/* [RC 11] Parity register #0 read clear */
+#define IGU_REG_IGU_PRTY_STS_CLR 0x1300a0
/* [R 4] Debug: int_handle_fsm */
#define IGU_REG_INT_HANDLE_FSM 0x130050
#define IGU_REG_LEADING_EDGE_LATCH 0x130134
@@ -1501,6 +1528,8 @@
#define MISC_REG_MISC_PRTY_MASK 0xa398
/* [R 1] Parity register #0 read */
#define MISC_REG_MISC_PRTY_STS 0xa38c
+/* [RC 1] Parity register #0 read clear */
+#define MISC_REG_MISC_PRTY_STS_CLR 0xa390
#define MISC_REG_NIG_WOL_P0 0xa270
#define MISC_REG_NIG_WOL_P1 0xa274
/* [R 1] If set indicate that the pcie_rst_b was asserted without perst
@@ -1604,7 +1633,7 @@
(~misc_registers_sw_timer_cfg_4.sw_timer_cfg_4[1] ) is set */
#define MISC_REG_SW_TIMER_RELOAD_VAL_4 0xa2fc
/* [RW 32] the value of the counter for sw timers1-8. there are 8 addresses
- in this register. addres 0 - timer 1; address 1 - timer 2, ... address 7 -
+ in this register. address 0 - timer 1; address 1 - timer 2, ... address 7 -
timer 8 */
#define MISC_REG_SW_TIMER_VAL 0xa5c0
/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
@@ -1615,6 +1644,8 @@
#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4)
#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2)
#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3)
+#define NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN (0x1<<0)
+#define NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15)
@@ -1744,12 +1775,16 @@
~ppp_enable.ppp_enable = 0 and pause_enable.pause_enable =0 for the same
port */
#define NIG_REG_LLFC_ENABLE_0 0x16208
+#define NIG_REG_LLFC_ENABLE_1 0x1620c
/* [RW 16] classes are high-priority for port0 */
#define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0 0x16058
+#define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 0x1605c
/* [RW 16] classes are low-priority for port0 */
#define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0 0x16060
+#define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 0x16064
/* [RW 1] Output enable of message to LLFC BMAC IF for port0 */
#define NIG_REG_LLFC_OUT_EN_0 0x160c8
+#define NIG_REG_LLFC_OUT_EN_1 0x160cc
#define NIG_REG_LLH0_ACPI_PAT_0_CRC 0x1015c
#define NIG_REG_LLH0_ACPI_PAT_6_LEN 0x10154
#define NIG_REG_LLH0_BRB1_DRV_MASK 0x10244
@@ -1774,6 +1809,8 @@
/* [RW 8] event id for llh0 */
#define NIG_REG_LLH0_EVENT_ID 0x10084
#define NIG_REG_LLH0_FUNC_EN 0x160fc
+#define NIG_REG_LLH0_FUNC_MEM 0x16180
+#define NIG_REG_LLH0_FUNC_MEM_ENABLE 0x16140
#define NIG_REG_LLH0_FUNC_VLAN_ID 0x16100
/* [RW 1] Determine the IP version to look for in
~nig_registers_llh0_dest_ip_0.llh0_dest_ip_0. 0 - IPv6; 1-IPv4 */
@@ -1797,6 +1834,9 @@
#define NIG_REG_LLH1_ERROR_MASK 0x10090
/* [RW 8] event id for llh1 */
#define NIG_REG_LLH1_EVENT_ID 0x10088
+#define NIG_REG_LLH1_FUNC_MEM 0x161c0
+#define NIG_REG_LLH1_FUNC_MEM_ENABLE 0x16160
+#define NIG_REG_LLH1_FUNC_MEM_SIZE 16
/* [RW 8] init credit counter for port1 in LLH */
#define NIG_REG_LLH1_XCM_INIT_CREDIT 0x10564
#define NIG_REG_LLH1_XCM_MASK 0x10134
@@ -1907,11 +1947,17 @@
~safc_enable.safc_enable = 0 and ppp_enable.ppp_enable =0 for the same
port */
#define NIG_REG_PAUSE_ENABLE_0 0x160c0
+#define NIG_REG_PAUSE_ENABLE_1 0x160c4
/* [RW 1] Input enable for RX PBF LP IF */
#define NIG_REG_PBF_LB_IN_EN 0x100b4
/* [RW 1] Value of this register will be transmitted to port swap when
~nig_registers_strap_override.strap_override =1 */
#define NIG_REG_PORT_SWAP 0x10394
+/* [RW 1] PPP enable for port0. This register may get 1 only when
+ * ~safc_enable.safc_enable = 0 and pause_enable.pause_enable =0 for the
+ * same port */
+#define NIG_REG_PPP_ENABLE_0 0x160b0
+#define NIG_REG_PPP_ENABLE_1 0x160b4
/* [RW 1] output enable for RX parser descriptor IF */
#define NIG_REG_PRS_EOP_OUT_EN 0x10104
/* [RW 1] Input enable for RX parser request IF */
@@ -1978,6 +2024,14 @@
#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15)
#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18)
#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE 18
+/* [RW 31] The upper bound of the weight of COS0 in the ETS command arbiter. */
+#define PBF_REG_COS0_UPPER_BOUND 0x15c05c
+/* [RW 31] The weight of COS0 in the ETS command arbiter. */
+#define PBF_REG_COS0_WEIGHT 0x15c054
+/* [RW 31] The upper bound of the weight of COS1 in the ETS command arbiter. */
+#define PBF_REG_COS1_UPPER_BOUND 0x15c060
+/* [RW 31] The weight of COS1 in the ETS command arbiter. */
+#define PBF_REG_COS1_WEIGHT 0x15c058
/* [RW 1] Disable processing further tasks from port 0 (after ending the
current task in process). */
#define PBF_REG_DISABLE_NEW_TASK_PROC_P0 0x14005c
@@ -1988,9 +2042,16 @@
current task in process). */
#define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c
#define PBF_REG_DISABLE_PF 0x1402e8
+/* [RW 1] Indicates that ETS is performed between the COSes in the command
+ * arbiter. If reset strict priority w/ anti-starvation will be performed
+ * w/o WFQ. */
+#define PBF_REG_ETS_ENABLED 0x15c050
/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic
* Ethernet header. */
#define PBF_REG_HDRS_AFTER_BASIC 0x15c0a8
+/* [RW 1] Indicates which COS is conncted to the highest priority in the
+ * command arbiter. */
+#define PBF_REG_HIGH_PRIORITY_COS_NUM 0x15c04c
#define PBF_REG_IF_ENABLE_REG 0x140044
/* [RW 1] Init bit. When set the initial credits are copied to the credit
registers (except the port credits). Should be set and then reset after
@@ -2016,6 +2077,10 @@
#define PBF_REG_MAC_LB_ENABLE 0x140040
/* [RW 6] Bit-map indicating which headers must appear in the packet */
#define PBF_REG_MUST_HAVE_HDRS 0x15c0c4
+/* [RW 16] The number of strict priority arbitration slots between 2 RR
+ * arbitration slots. A value of 0 means no strict priority cycles; i.e. the
+ * strict-priority w/ anti-starvation arbiter is a RR arbiter. */
+#define PBF_REG_NUM_STRICT_ARB_SLOTS 0x15c064
/* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause
not suppoterd. */
#define PBF_REG_P0_ARB_THRSH 0x1400e4
@@ -2046,6 +2111,10 @@
#define PBF_REG_PBF_INT_MASK 0x1401d4
/* [R 5] Interrupt register #0 read */
#define PBF_REG_PBF_INT_STS 0x1401c8
+/* [RW 20] Parity mask register #0 read/write */
+#define PBF_REG_PBF_PRTY_MASK 0x1401e4
+/* [RC 20] Parity register #0 read clear */
+#define PBF_REG_PBF_PRTY_STS_CLR 0x1401dc
#define PB_REG_CONTROL 0
/* [RW 2] Interrupt mask register #0 read/write */
#define PB_REG_PB_INT_MASK 0x28
@@ -2055,6 +2124,8 @@
#define PB_REG_PB_PRTY_MASK 0x38
/* [R 4] Parity register #0 read */
#define PB_REG_PB_PRTY_STS 0x2c
+/* [RC 4] Parity register #0 read clear */
+#define PB_REG_PB_PRTY_STS_CLR 0x30
#define PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR (0x1<<0)
#define PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW (0x1<<8)
#define PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR (0x1<<1)
@@ -2410,6 +2481,8 @@
#define PRS_REG_PRS_PRTY_MASK 0x401a4
/* [R 8] Parity register #0 read */
#define PRS_REG_PRS_PRTY_STS 0x40198
+/* [RC 8] Parity register #0 read clear */
+#define PRS_REG_PRS_PRTY_STS_CLR 0x4019c
/* [RW 8] Context region for pure acknowledge packets. Used in CFC load
request message */
#define PRS_REG_PURE_REGIONS 0x40024
@@ -2563,6 +2636,9 @@
/* [R 32] Parity register #0 read */
#define PXP2_REG_PXP2_PRTY_STS_0 0x12057c
#define PXP2_REG_PXP2_PRTY_STS_1 0x12058c
+/* [RC 32] Parity register #0 read clear */
+#define PXP2_REG_PXP2_PRTY_STS_CLR_0 0x120580
+#define PXP2_REG_PXP2_PRTY_STS_CLR_1 0x120590
/* [R 1] Debug only: The 'almost full' indication from each fifo (gives
indication about backpressure) */
#define PXP2_REG_RD_ALMOST_FULL_0 0x120424
@@ -2965,6 +3041,8 @@
#define PXP_REG_PXP_PRTY_MASK 0x103094
/* [R 26] Parity register #0 read */
#define PXP_REG_PXP_PRTY_STS 0x103088
+/* [RC 27] Parity register #0 read clear */
+#define PXP_REG_PXP_PRTY_STS_CLR 0x10308c
/* [RW 4] The activity counter initial increment value sent in the load
request */
#define QM_REG_ACTCTRINITVAL_0 0x168040
@@ -3121,6 +3199,8 @@
#define QM_REG_QM_PRTY_MASK 0x168454
/* [R 12] Parity register #0 read */
#define QM_REG_QM_PRTY_STS 0x168448
+/* [RC 12] Parity register #0 read clear */
+#define QM_REG_QM_PRTY_STS_CLR 0x16844c
/* [R 32] Current queues in pipeline: Queues from 32 to 63 */
#define QM_REG_QSTATUS_HIGH 0x16802c
/* [R 32] Current queues in pipeline: Queues from 96 to 127 */
@@ -3406,6 +3486,8 @@
#define QM_REG_WRRWEIGHTS_9 0x168848
/* [R 6] Keep the fill level of the fifo from write client 1 */
#define QM_REG_XQM_WRC_FIFOLVL 0x168000
+/* [W 1] reset to parity interrupt */
+#define SEM_FAST_REG_PARITY_RST 0x18840
#define SRC_REG_COUNTFREE0 0x40500
/* [RW 1] If clr the searcher is compatible to E1 A0 - support only two
ports. If set the searcher support 8 functions. */
@@ -3434,6 +3516,8 @@
#define SRC_REG_SRC_PRTY_MASK 0x404c8
/* [R 3] Parity register #0 read */
#define SRC_REG_SRC_PRTY_STS 0x404bc
+/* [RC 3] Parity register #0 read clear */
+#define SRC_REG_SRC_PRTY_STS_CLR 0x404c0
/* [R 4] Used to read the value of the XX protection CAM occupancy counter. */
#define TCM_REG_CAM_OCCUP 0x5017c
/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
@@ -3560,8 +3644,12 @@
#define TCM_REG_TCM_INT_MASK 0x501dc
/* [R 11] Interrupt register #0 read */
#define TCM_REG_TCM_INT_STS 0x501d0
+/* [RW 27] Parity mask register #0 read/write */
+#define TCM_REG_TCM_PRTY_MASK 0x501ec
/* [R 27] Parity register #0 read */
#define TCM_REG_TCM_PRTY_STS 0x501e0
+/* [RC 27] Parity register #0 read clear */
+#define TCM_REG_TCM_PRTY_STS_CLR 0x501e4
/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS
REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
Is used to determine the number of the AG context REG-pairs written back;
@@ -3719,6 +3807,10 @@
#define TM_REG_TM_INT_MASK 0x1640fc
/* [R 1] Interrupt register #0 read */
#define TM_REG_TM_INT_STS 0x1640f0
+/* [RW 7] Parity mask register #0 read/write */
+#define TM_REG_TM_PRTY_MASK 0x16410c
+/* [RC 7] Parity register #0 read clear */
+#define TM_REG_TM_PRTY_STS_CLR 0x164104
/* [RW 8] The event id for aggregated interrupt 0 */
#define TSDM_REG_AGG_INT_EVENT_0 0x42038
#define TSDM_REG_AGG_INT_EVENT_1 0x4203c
@@ -3799,6 +3891,8 @@
#define TSDM_REG_TSDM_PRTY_MASK 0x422bc
/* [R 11] Parity register #0 read */
#define TSDM_REG_TSDM_PRTY_STS 0x422b0
+/* [RC 11] Parity register #0 read clear */
+#define TSDM_REG_TSDM_PRTY_STS_CLR 0x422b4
/* [RW 5] The number of time_slots in the arbitration cycle */
#define TSEM_REG_ARB_CYCLE_SIZE 0x180034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -3878,6 +3972,9 @@
#define TSEM_REG_SLOW_EXT_STORE_EMPTY 0x1802a0
/* [RW 8] List of free threads . There is a bit per thread. */
#define TSEM_REG_THREADS_LIST 0x1802e4
+/* [RC 32] Parity register #0 read clear */
+#define TSEM_REG_TSEM_PRTY_STS_CLR_0 0x180118
+#define TSEM_REG_TSEM_PRTY_STS_CLR_1 0x180128
/* [RW 3] The arbitration scheme of time_slot 0 */
#define TSEM_REG_TS_0_AS 0x180038
/* [RW 3] The arbitration scheme of time_slot 10 */
@@ -4080,6 +4177,8 @@
#define UCM_REG_UCM_INT_STS 0xe01c8
/* [R 27] Parity register #0 read */
#define UCM_REG_UCM_PRTY_STS 0xe01d8
+/* [RC 27] Parity register #0 read clear */
+#define UCM_REG_UCM_PRTY_STS_CLR 0xe01dc
/* [RW 2] The size of AG context region 0 in REG-pairs. Designates the MS
REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
Is used to determine the number of the AG context REG-pairs written back;
@@ -4256,6 +4355,8 @@
#define USDM_REG_USDM_PRTY_MASK 0xc42c0
/* [R 11] Parity register #0 read */
#define USDM_REG_USDM_PRTY_STS 0xc42b4
+/* [RC 11] Parity register #0 read clear */
+#define USDM_REG_USDM_PRTY_STS_CLR 0xc42b8
/* [RW 5] The number of time_slots in the arbitration cycle */
#define USEM_REG_ARB_CYCLE_SIZE 0x300034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -4385,6 +4486,9 @@
/* [R 32] Parity register #0 read */
#define USEM_REG_USEM_PRTY_STS_0 0x300124
#define USEM_REG_USEM_PRTY_STS_1 0x300134
+/* [RC 32] Parity register #0 read clear */
+#define USEM_REG_USEM_PRTY_STS_CLR_0 0x300128
+#define USEM_REG_USEM_PRTY_STS_CLR_1 0x300138
/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64
* VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */
#define USEM_REG_VFPF_ERR_NUM 0x300380
@@ -4761,6 +4865,8 @@
#define XSDM_REG_XSDM_PRTY_MASK 0x1662bc
/* [R 11] Parity register #0 read */
#define XSDM_REG_XSDM_PRTY_STS 0x1662b0
+/* [RC 11] Parity register #0 read clear */
+#define XSDM_REG_XSDM_PRTY_STS_CLR 0x1662b4
/* [RW 5] The number of time_slots in the arbitration cycle */
#define XSEM_REG_ARB_CYCLE_SIZE 0x280034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -4893,6 +4999,9 @@
/* [R 32] Parity register #0 read */
#define XSEM_REG_XSEM_PRTY_STS_0 0x280124
#define XSEM_REG_XSEM_PRTY_STS_1 0x280134
+/* [RC 32] Parity register #0 read clear */
+#define XSEM_REG_XSEM_PRTY_STS_CLR_0 0x280128
+#define XSEM_REG_XSEM_PRTY_STS_CLR_1 0x280138
#define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0)
#define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1)
#define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0)
@@ -4970,7 +5079,23 @@
#define EMAC_REG_EMAC_TX_MODE 0xbc
#define EMAC_REG_EMAC_TX_STAT_AC 0x280
#define EMAC_REG_EMAC_TX_STAT_AC_COUNT 22
+#define EMAC_REG_RX_PFC_MODE 0x320
+#define EMAC_REG_RX_PFC_MODE_PRIORITIES (1L<<2)
+#define EMAC_REG_RX_PFC_MODE_RX_EN (1L<<1)
+#define EMAC_REG_RX_PFC_MODE_TX_EN (1L<<0)
+#define EMAC_REG_RX_PFC_PARAM 0x324
+#define EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT 0
+#define EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT 16
+#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD 0x328
+#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT (0xffff<<0)
+#define EMAC_REG_RX_PFC_STATS_XOFF_SENT 0x330
+#define EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT (0xffff<<0)
+#define EMAC_REG_RX_PFC_STATS_XON_RCVD 0x32c
+#define EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT (0xffff<<0)
+#define EMAC_REG_RX_PFC_STATS_XON_SENT 0x334
+#define EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT (0xffff<<0)
#define EMAC_RX_MODE_FLOW_EN (1L<<2)
+#define EMAC_RX_MODE_KEEP_MAC_CONTROL (1L<<3)
#define EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10)
#define EMAC_RX_MODE_PROMISCUOUS (1L<<8)
#define EMAC_RX_MODE_RESET (1L<<0)
@@ -6264,3 +6389,4 @@ static inline u8 calc_crc8(u32 data, u8 crc)
}
+#endif /* BNX2X_REG_H */
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
index 4733c835dad9..bda60d590fa8 100644
--- a/drivers/net/bnx2x/bnx2x_stats.c
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -158,9 +158,14 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
spin_lock_bh(&bp->stats_lock);
+ if (bp->stats_pending) {
+ spin_unlock_bh(&bp->stats_lock);
+ return;
+ }
+
ramrod_data.drv_counter = bp->stats_counter++;
ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
- for_each_queue(bp, i)
+ for_each_eth_queue(bp, i)
ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
@@ -766,7 +771,7 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
estats->no_buff_discard_hi = 0;
estats->no_buff_discard_lo = 0;
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
int cl_id = fp->cl_id;
struct tstorm_per_client_stats *tclient =
@@ -996,7 +1001,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
tmp = estats->mac_discard;
- for_each_queue(bp, i)
+ for_each_rx_queue(bp, i)
tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
nstats->rx_dropped = tmp;
@@ -1087,7 +1092,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
bp->dev->name,
estats->brb_drop_lo, estats->brb_truncate_lo);
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
@@ -1101,7 +1106,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
fp->rx_calls, fp->rx_pkt);
}
- for_each_queue(bp, i) {
+ for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
struct netdev_queue *txq =
@@ -1381,7 +1386,8 @@ void bnx2x_stats_init(struct bnx2x *bp)
memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
}
- for_each_queue(bp, i) {
+ /* FW stats are currently collected for ETH clients only */
+ for_each_eth_queue(bp, i) {
/* Set initial stats counter in the stats ramrod data to -1 */
int cl_id = bp->fp[i].cl_id;
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h
index afd15efa429a..596798c47452 100644
--- a/drivers/net/bnx2x/bnx2x_stats.h
+++ b/drivers/net/bnx2x/bnx2x_stats.h
@@ -53,7 +53,6 @@ struct bnx2x_eth_q_stats {
u32 hw_csum_err;
};
-#define BNX2X_NUM_Q_STATS 13
#define Q_STATS_OFFSET32(stat_name) \
(offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
@@ -225,7 +224,6 @@ struct bnx2x_eth_stats {
u32 nig_timer_max;
};
-#define BNX2X_NUM_STATS 43
#define STATS_OFFSET32(stat_name) \
(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile
index 6f9c6faef24c..0e2737eac8b7 100644
--- a/drivers/net/bonding/Makefile
+++ b/drivers/net/bonding/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_BONDING) += bonding.o
-bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o
+bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o
ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o
bonding-objs += $(ipv6-y)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 881914bc4e9c..171782e2bb39 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -840,7 +840,7 @@ static int ad_lacpdu_send(struct port *port)
lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
- /* Note: source addres is set to be the member's PERMANENT address,
+ /* Note: source address is set to be the member's PERMANENT address,
because we use it to identify loopback lacpdus in receive. */
memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
@@ -881,7 +881,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
marker_header = (struct bond_marker_header *)skb_put(skb, length);
memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
- /* Note: source addres is set to be the member's PERMANENT address,
+ /* Note: source address is set to be the member's PERMANENT address,
because we use it to identify loopback MARKERs in receive. */
memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
@@ -1916,7 +1916,7 @@ int bond_3ad_bind_slave(struct slave *slave)
return -1;
}
- //check that the slave has not been intialized yet.
+ //check that the slave has not been initialized yet.
if (SLAVE_AD_INFO(slave).port.slave != slave) {
// port initialization
@@ -2474,8 +2474,7 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
goto out;
read_lock(&bond->lock);
- slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev),
- orig_dev);
+ slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev);
if (!slave)
goto out_unlock;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 26bb118c4533..f4e638c65129 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -44,42 +44,6 @@
#include "bond_alb.h"
-#define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */
-#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing.
- * Used for division - never set
- * to zero !!!
- */
-#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of
- * learning packets to the switch
- */
-
-#define BOND_TLB_REBALANCE_TICKS (BOND_TLB_REBALANCE_INTERVAL \
- * ALB_TIMER_TICKS_PER_SEC)
-
-#define BOND_ALB_LP_TICKS (BOND_ALB_LP_INTERVAL \
- * ALB_TIMER_TICKS_PER_SEC)
-
-#define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table.
- * Note that this value MUST NOT be smaller
- * because the key hash table is BYTE wide !
- */
-
-
-#define TLB_NULL_INDEX 0xffffffff
-#define MAX_LP_BURST 3
-
-/* rlb defs */
-#define RLB_HASH_TABLE_SIZE 256
-#define RLB_NULL_INDEX 0xffffffff
-#define RLB_UPDATE_DELAY 2*ALB_TIMER_TICKS_PER_SEC /* 2 seconds */
-#define RLB_ARP_BURST_SIZE 2
-#define RLB_UPDATE_RETRY 3 /* 3-ticks - must be smaller than the rlb
- * rebalance interval (5 min).
- */
-/* RLB_PROMISC_TIMEOUT = 10 sec equals the time that the current slave is
- * promiscuous after failover
- */
-#define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC
#ifndef __long_aligned
#define __long_aligned __attribute__((aligned((sizeof(long)))))
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 50968f8196cf..118c28aa471e 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -31,6 +31,44 @@ struct slave;
#define BOND_ALB_INFO(bond) ((bond)->alb_info)
#define SLAVE_TLB_INFO(slave) ((slave)->tlb_info)
+#define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */
+#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing.
+ * Used for division - never set
+ * to zero !!!
+ */
+#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of
+ * learning packets to the switch
+ */
+
+#define BOND_TLB_REBALANCE_TICKS (BOND_TLB_REBALANCE_INTERVAL \
+ * ALB_TIMER_TICKS_PER_SEC)
+
+#define BOND_ALB_LP_TICKS (BOND_ALB_LP_INTERVAL \
+ * ALB_TIMER_TICKS_PER_SEC)
+
+#define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table.
+ * Note that this value MUST NOT be smaller
+ * because the key hash table is BYTE wide !
+ */
+
+
+#define TLB_NULL_INDEX 0xffffffff
+#define MAX_LP_BURST 3
+
+/* rlb defs */
+#define RLB_HASH_TABLE_SIZE 256
+#define RLB_NULL_INDEX 0xffffffff
+#define RLB_UPDATE_DELAY (2*ALB_TIMER_TICKS_PER_SEC) /* 2 seconds */
+#define RLB_ARP_BURST_SIZE 2
+#define RLB_UPDATE_RETRY 3 /* 3-ticks - must be smaller than the rlb
+ * rebalance interval (5 min).
+ */
+/* RLB_PROMISC_TIMEOUT = 10 sec equals the time that the current slave is
+ * promiscuous after failover
+ */
+#define RLB_PROMISC_TIMEOUT (10*ALB_TIMER_TICKS_PER_SEC)
+
+
struct tlb_client_info {
struct slave *tx_slave; /* A pointer to slave used for transmiting
* packets to a Client that the Hash function
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
new file mode 100644
index 000000000000..3680aa251dea
--- /dev/null
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -0,0 +1,146 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+
+#include "bonding.h"
+#include "bond_alb.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static struct dentry *bonding_debug_root;
+
+/*
+ * Show RLB hash table
+ */
+static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
+{
+ struct bonding *bond = m->private;
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ struct rlb_client_info *client_info;
+ u32 hash_index;
+
+ if (bond->params.mode != BOND_MODE_ALB)
+ return 0;
+
+ seq_printf(m, "SourceIP DestinationIP "
+ "Destination MAC DEV\n");
+
+ spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+
+ hash_index = bond_info->rx_hashtbl_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ client_info = &(bond_info->rx_hashtbl[hash_index]);
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst,
+ client_info->slave->dev->name);
+ }
+
+ spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+
+ return 0;
+}
+
+static int bond_debug_rlb_hash_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, bond_debug_rlb_hash_show, inode->i_private);
+}
+
+static const struct file_operations bond_debug_rlb_hash_fops = {
+ .owner = THIS_MODULE,
+ .open = bond_debug_rlb_hash_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void bond_debug_register(struct bonding *bond)
+{
+ if (!bonding_debug_root)
+ return;
+
+ bond->debug_dir =
+ debugfs_create_dir(bond->dev->name, bonding_debug_root);
+
+ if (!bond->debug_dir) {
+ pr_warning("%s: Warning: failed to register to debugfs\n",
+ bond->dev->name);
+ return;
+ }
+
+ debugfs_create_file("rlb_hash_table", 0400, bond->debug_dir,
+ bond, &bond_debug_rlb_hash_fops);
+}
+
+void bond_debug_unregister(struct bonding *bond)
+{
+ if (!bonding_debug_root)
+ return;
+
+ debugfs_remove_recursive(bond->debug_dir);
+}
+
+void bond_debug_reregister(struct bonding *bond)
+{
+ struct dentry *d;
+
+ if (!bonding_debug_root)
+ return;
+
+ d = debugfs_rename(bonding_debug_root, bond->debug_dir,
+ bonding_debug_root, bond->dev->name);
+ if (d) {
+ bond->debug_dir = d;
+ } else {
+ pr_warning("%s: Warning: failed to reregister, "
+ "so just unregister old one\n",
+ bond->dev->name);
+ bond_debug_unregister(bond);
+ }
+}
+
+void bond_create_debugfs(void)
+{
+ bonding_debug_root = debugfs_create_dir("bonding", NULL);
+
+ if (!bonding_debug_root) {
+ pr_warning("Warning: Cannot create bonding directory"
+ " in debugfs\n");
+ }
+}
+
+void bond_destroy_debugfs(void)
+{
+ debugfs_remove_recursive(bonding_debug_root);
+ bonding_debug_root = NULL;
+}
+
+
+#else /* !CONFIG_DEBUG_FS */
+
+void bond_debug_register(struct bonding *bond)
+{
+}
+
+void bond_debug_unregister(struct bonding *bond)
+{
+}
+
+void bond_debug_reregister(struct bonding *bond)
+{
+}
+
+void bond_create_debugfs(void)
+{
+}
+
+void bond_destroy_debugfs(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c
index 121b073a6c3f..84fbd4ebd778 100644
--- a/drivers/net/bonding/bond_ipv6.c
+++ b/drivers/net/bonding/bond_ipv6.c
@@ -88,7 +88,12 @@ static void bond_na_send(struct net_device *slave_dev,
}
if (vlan_id) {
- skb = vlan_put_tag(skb, vlan_id);
+ /* The Ethernet header is not present yet, so it is
+ * too early to insert a VLAN tag. Force use of an
+ * out-of-line tag here and let dev_hard_start_xmit()
+ * insert it if the slave hardware can't.
+ */
+ skb = __vlan_hwaccel_put_tag(skb, vlan_id);
if (!skb) {
pr_err("failed to insert VLAN tag\n");
return;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index bdb68a600382..b1025b85acf1 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -171,7 +171,7 @@ MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link
/*----------------------------- Global variables ----------------------------*/
#ifdef CONFIG_NET_POLL_CONTROLLER
-cpumask_var_t netpoll_block_tx;
+atomic_t netpoll_block_tx = ATOMIC_INIT(0);
#endif
static const char * const version =
@@ -418,36 +418,11 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
* @bond: bond device that got this skb for tx.
* @skb: hw accel VLAN tagged skb to transmit
* @slave_dev: slave that is supposed to xmit this skbuff
- *
- * When the bond gets an skb to transmit that is
- * already hardware accelerated VLAN tagged, and it
- * needs to relay this skb to a slave that is not
- * hw accel capable, the skb needs to be "unaccelerated",
- * i.e. strip the hwaccel tag and re-insert it as part
- * of the payload.
*/
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
struct net_device *slave_dev)
{
- unsigned short uninitialized_var(vlan_id);
-
- /* Test vlan_list not vlgrp to catch and handle 802.1p tags */
- if (!list_empty(&bond->vlan_list) &&
- !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
- vlan_get_tag(skb, &vlan_id) == 0) {
- skb->dev = slave_dev;
- skb = vlan_put_tag(skb, vlan_id);
- if (!skb) {
- /* vlan_put_tag() frees the skb in case of error,
- * so return success here so the calling functions
- * won't attempt to free is again.
- */
- return 0;
- }
- } else {
- skb->dev = slave_dev;
- }
-
+ skb->dev = slave_dev;
skb->priority = 1;
#ifdef CONFIG_NET_POLL_CONTROLLER
if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
@@ -873,15 +848,11 @@ static void bond_mc_del(struct bonding *bond, void *addr)
static void __bond_resend_igmp_join_requests(struct net_device *dev)
{
struct in_device *in_dev;
- struct ip_mc_list *im;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
- if (in_dev) {
- for (im = in_dev->mc_list; im; im = im->next)
- ip_mc_rejoin_group(im);
- }
-
+ if (in_dev)
+ ip_mc_rejoin_groups(in_dev);
rcu_read_unlock();
}
@@ -1201,11 +1172,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
bond_do_fail_over_mac(bond, new_active,
old_active);
- bond->send_grat_arp = bond->params.num_grat_arp;
- bond_send_gratuitous_arp(bond);
+ if (netif_running(bond->dev)) {
+ bond->send_grat_arp = bond->params.num_grat_arp;
+ bond_send_gratuitous_arp(bond);
- bond->send_unsol_na = bond->params.num_unsol_na;
- bond_send_unsolicited_na(bond);
+ bond->send_unsol_na = bond->params.num_unsol_na;
+ bond_send_unsolicited_na(bond);
+ }
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
@@ -1219,8 +1192,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
/* resend IGMP joins since active slave has changed or
* all were sent on curr_active_slave */
- if ((USES_PRIMARY(bond->params.mode) && new_active) ||
- bond->params.mode == BOND_MODE_ROUNDROBIN) {
+ if (((USES_PRIMARY(bond->params.mode) && new_active) ||
+ bond->params.mode == BOND_MODE_ROUNDROBIN) &&
+ netif_running(bond->dev)) {
bond->igmp_retrans = bond->params.resend_igmp;
queue_delayed_work(bond->wq, &bond->mcast_work, 0);
}
@@ -1574,7 +1548,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* If this is the first slave, then we need to set the master's hardware
* address to be the same as the slave's. */
- if (bond->slave_cnt == 0)
+ if (is_zero_ether_addr(bond->dev->dev_addr))
memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
slave_dev->addr_len);
@@ -3209,7 +3183,7 @@ out:
#ifdef CONFIG_PROC_FS
static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(&dev_base_lock)
+ __acquires(RCU)
__acquires(&bond->lock)
{
struct bonding *bond = seq->private;
@@ -3218,7 +3192,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
int i;
/* make sure the bond won't be taken away */
- read_lock(&dev_base_lock);
+ rcu_read_lock();
read_lock(&bond->lock);
if (*pos == 0)
@@ -3248,12 +3222,12 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void bond_info_seq_stop(struct seq_file *seq, void *v)
__releases(&bond->lock)
- __releases(&dev_base_lock)
+ __releases(RCU)
{
struct bonding *bond = seq->private;
read_unlock(&bond->lock);
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
}
static void bond_info_show_master(struct seq_file *seq)
@@ -3507,6 +3481,8 @@ static int bond_event_changename(struct bonding *bond)
bond_remove_proc_entry(bond);
bond_create_proc_entry(bond);
+ bond_debug_reregister(bond);
+
return NOTIFY_DONE;
}
@@ -4789,6 +4765,8 @@ static void bond_uninit(struct net_device *bond_dev)
bond_remove_proc_entry(bond);
+ bond_debug_unregister(bond);
+
__hw_addr_flush(&bond->mc_list);
list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
@@ -5191,6 +5169,8 @@ static int bond_init(struct net_device *bond_dev)
bond_prepare_sysfs_group(bond);
+ bond_debug_register(bond);
+
__hw_addr_init(&bond->mc_list);
return 0;
}
@@ -5297,13 +5277,6 @@ static int __init bonding_init(void)
if (res)
goto out;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) {
- res = -ENOMEM;
- goto out;
- }
-#endif
-
res = register_pernet_subsys(&bond_net_ops);
if (res)
goto out;
@@ -5312,6 +5285,8 @@ static int __init bonding_init(void)
if (res)
goto err_link;
+ bond_create_debugfs();
+
for (i = 0; i < max_bonds; i++) {
res = bond_create(&init_net, NULL);
if (res)
@@ -5322,7 +5297,6 @@ static int __init bonding_init(void)
if (res)
goto err;
-
register_netdevice_notifier(&bond_netdev_notifier);
register_inetaddr_notifier(&bond_inetaddr_notifier);
bond_register_ipv6_notifier();
@@ -5332,9 +5306,6 @@ err:
rtnl_link_unregister(&bond_link_ops);
err_link:
unregister_pernet_subsys(&bond_net_ops);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- free_cpumask_var(netpoll_block_tx);
-#endif
goto out;
}
@@ -5346,12 +5317,16 @@ static void __exit bonding_exit(void)
bond_unregister_ipv6_notifier();
bond_destroy_sysfs();
+ bond_destroy_debugfs();
rtnl_link_unregister(&bond_link_ops);
unregister_pernet_subsys(&bond_net_ops);
#ifdef CONFIG_NET_POLL_CONTROLLER
- free_cpumask_var(netpoll_block_tx);
+ /*
+ * Make sure we don't have an imbalance on our netpoll blocking
+ */
+ WARN_ON(atomic_read(&netpoll_block_tx));
#endif
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4eedb12df6ca..31fe980e4e28 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -18,7 +18,6 @@
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
-#include <linux/kobject.h>
#include <linux/cpumask.h>
#include <linux/in6.h>
#include "bond_3ad.h"
@@ -119,26 +118,22 @@
#ifdef CONFIG_NET_POLL_CONTROLLER
-extern cpumask_var_t netpoll_block_tx;
+extern atomic_t netpoll_block_tx;
static inline void block_netpoll_tx(void)
{
- preempt_disable();
- BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(),
- netpoll_block_tx));
+ atomic_inc(&netpoll_block_tx);
}
static inline void unblock_netpoll_tx(void)
{
- BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(),
- netpoll_block_tx));
- preempt_enable();
+ atomic_dec(&netpoll_block_tx);
}
static inline int is_netpoll_tx_blocked(struct net_device *dev)
{
if (unlikely(dev->priv_flags & IFF_IN_NETPOLL))
- return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx);
+ return atomic_read(&netpoll_block_tx);
return 0;
}
#else
@@ -259,6 +254,10 @@ struct bonding {
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct in6_addr master_ipv6;
#endif
+#ifdef CONFIG_DEBUG_FS
+ /* debugging suport via debugfs */
+ struct dentry *debug_dir;
+#endif /* CONFIG_DEBUG_FS */
};
/**
@@ -273,11 +272,11 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n
bond_for_each_slave(bond, slave, i) {
if (slave->dev == slave_dev) {
- break;
+ return slave;
}
}
- return slave;
+ return 0;
}
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
@@ -286,7 +285,7 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
return NULL;
}
- return (struct bonding *)netdev_priv(slave->dev->master);
+ return netdev_priv(slave->dev->master);
}
static inline bool bond_is_lb(const struct bonding *bond)
@@ -380,6 +379,11 @@ void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_register_arp(struct bonding *);
void bond_unregister_arp(struct bonding *);
+void bond_create_debugfs(void);
+void bond_destroy_debugfs(void);
+void bond_debug_register(struct bonding *bond);
+void bond_debug_unregister(struct bonding *bond);
+void bond_debug_reregister(struct bonding *bond);
struct bond_net {
struct net * net; /* Associated network namespace */
diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c
index 1cd90da86f13..5f771ab712c4 100644
--- a/drivers/net/caif/caif_shm_u5500.c
+++ b/drivers/net/caif/caif_shm_u5500.c
@@ -5,13 +5,13 @@
* License terms: GNU General Public License (GPL) version 2
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <mach/mbox.h>
+#include <mach/mbox-db5500.h>
#include <net/caif/caif_shm.h>
MODULE_LICENSE("GPL");
diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c
index 19f9c0656667..80511167f35b 100644
--- a/drivers/net/caif/caif_shmcore.c
+++ b/drivers/net/caif/caif_shmcore.c
@@ -6,7 +6,7 @@
* License terms: GNU General Public License (GPL) version 2
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/spinlock.h>
#include <linux/sched.h>
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index 8427533fe313..20da1996d354 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
MODULE_DESCRIPTION("CAIF SPI driver");
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
+
static int spi_loop;
module_param(spi_loop, bool, S_IRUGO);
MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
@@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
module_param(spi_frm_align, int, S_IRUGO);
MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
-/* SPI padding options. */
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
module_param(spi_up_head_align, int, S_IRUGO);
MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
@@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
static const struct file_operations dbgfs_state_fops = {
.open = dbgfs_open,
.read = dbgfs_state,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
+ .owner = THIS_MODULE
};
static const struct file_operations dbgfs_frame_fops = {
.open = dbgfs_open,
.read = dbgfs_frame,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
+ .owner = THIS_MODULE
};
static inline void dev_debugfs_add(struct cfspi *cfspi)
@@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
u8 *dst = buf;
caif_assert(buf);
+ if (cfspi->slave && !cfspi->slave_talked)
+ cfspi->slave_talked = true;
+
do {
struct sk_buff *skb;
struct caif_payload_info *info;
@@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
* Compute head offset i.e. number of bytes to add to
* get the start of the payload aligned.
*/
- if (spi_up_head_align) {
- spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+ if (spi_up_head_align > 1) {
+ spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
*dst = (u8)(spad - 1);
dst += spad;
}
@@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
* Compute tail offset i.e. number of bytes to add to
* get the complete CAIF frame aligned.
*/
- epad = (skb->len + spad) & spi_up_tail_align;
+ epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
dst += epad;
dev_kfree_skb(skb);
@@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
* Compute head offset i.e. number of bytes to add to
* get the start of the payload aligned.
*/
- if (spi_up_head_align)
- spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+ if (spi_up_head_align > 1)
+ spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
/*
* Compute tail offset i.e. number of bytes to add to
* get the complete CAIF frame aligned.
*/
- epad = (skb->len + spad) & spi_up_tail_align;
+ epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
skb_queue_tail(&cfspi->chead, skb);
@@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
} else {
/* Put back packet. */
skb_queue_head(&cfspi->qhead, skb);
+ break;
}
} while (pkts <= CAIF_MAX_SPI_PKTS);
@@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
{
struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+ /*
+ * The slave device is the master on the link. Interrupts before the
+ * slave has transmitted are considered spurious.
+ */
+ if (cfspi->slave && !cfspi->slave_talked) {
+ printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
+ return;
+ }
+
if (!in_interrupt())
spin_lock(&cfspi->lock);
if (assert) {
@@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
spin_unlock(&cfspi->lock);
/* Wake up the xfer thread. */
- wake_up_interruptible(&cfspi->wait);
+ if (assert)
+ wake_up_interruptible(&cfspi->wait);
}
static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
@@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
* Compute head offset i.e. number of bytes added to
* get the start of the payload aligned.
*/
- if (spi_down_head_align) {
+ if (spi_down_head_align > 1) {
spad = 1 + *src;
src += spad;
}
@@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
* Compute tail offset i.e. number of bytes added to
* get the complete CAIF frame aligned.
*/
- epad = (pkt_len + spad) & spi_down_tail_align;
+ epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
src += epad;
} while ((src - buf) < len);
@@ -617,19 +635,28 @@ int cfspi_spi_probe(struct platform_device *pdev)
ndev = alloc_netdev(sizeof(struct cfspi),
"cfspi%d", cfspi_setup);
- if (!dev)
- return -ENODEV;
+ if (!ndev)
+ return -ENOMEM;
cfspi = netdev_priv(ndev);
netif_stop_queue(ndev);
cfspi->ndev = ndev;
cfspi->pdev = pdev;
- /* Set flow info */
+ /* Set flow info. */
cfspi->flow_off_sent = 0;
cfspi->qd_low_mark = LOW_WATER_MARK;
cfspi->qd_high_mark = HIGH_WATER_MARK;
+ /* Set slave info. */
+ if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
+ cfspi->slave = true;
+ cfspi->slave_talked = false;
+ } else {
+ cfspi->slave = false;
+ cfspi->slave_talked = false;
+ }
+
/* Assign the SPI device. */
cfspi->dev = dev;
/* Assign the device ifc to this SPI interface. */
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
index 2111dbfea6fe..1b9943a4edab 100644
--- a/drivers/net/caif/caif_spi_slave.c
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
#endif
int spi_frm_align = 2;
-int spi_up_head_align = 1;
-int spi_up_tail_align;
-int spi_down_head_align = 3;
-int spi_down_tail_align = 1;
+
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+int spi_up_head_align = 1 << 1;
+int spi_up_tail_align = 1 << 0;
+int spi_down_head_align = 1 << 2;
+int spi_down_tail_align = 1 << 1;
#ifdef CONFIG_DEBUG_FS
static inline void debugfs_store_prev(struct cfspi *cfspi)
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 080574b0fff0..d5a9db60ade9 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -12,6 +12,27 @@ config CAN_VCAN
This driver can also be built as a module. If so, the module
will be called vcan.
+config CAN_SLCAN
+ tristate "Serial / USB serial CAN Adaptors (slcan)"
+ depends on CAN
+ default N
+ ---help---
+ CAN driver for several 'low cost' CAN interfaces that are attached
+ via serial lines or via USB-to-serial adapters using the LAWICEL
+ ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
+
+ As only the sending and receiving of CAN frames is implemented, this
+ driver should work with the (serial/USB) CAN hardware from:
+ www.canusb.com / www.can232.com / www.mictronic.com / www.canhack.de
+
+ Userspace tools to attach the SLCAN line discipline (slcan_attach,
+ slcand) can be found in the can-utils at the SocketCAN SVN, see
+ http://developer.berlios.de/projects/socketcan for details.
+
+ The slcan driver supports up to 10 CAN netdevices by default which
+ can be changed by the 'maxdev=xx' module option. This driver can
+ also be built as a module. If so, the module will be called slcan.
+
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 90af15a4f106..07ca159ba3f9 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_CAN_VCAN) += vcan.o
+obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index cee98fa668bd..7ef83d06f7ed 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1,7 +1,7 @@
/*
* at91_can.c - CAN network driver for AT91 SoC CAN controller
*
- * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
* (C) 2008, 2009, 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
*
* This software may be distributed under the terms of the GNU General
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 6e533dcc36c0..b9a6d7a5a739 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1114,11 +1114,6 @@ static bool ican3_txok(struct ican3_dev *mod)
/*
* Recieve one CAN frame from the hardware
*
- * This works like the core of a NAPI function, but is intended to be called
- * from workqueue context instead. This driver already needs a workqueue to
- * process control messages, so we use the workqueue instead of using NAPI.
- * This was done to simplify locking.
- *
* CONTEXT: must be called from user context
*/
static int ican3_recv_skb(struct ican3_dev *mod)
@@ -1251,7 +1246,6 @@ static irqreturn_t ican3_irq(int irq, void *dev_id)
* Reset an ICAN module to its power-on state
*
* CONTEXT: no network device registered
- * LOCKING: work function disabled
*/
static int ican3_reset_module(struct ican3_dev *mod)
{
@@ -1262,9 +1256,6 @@ static int ican3_reset_module(struct ican3_dev *mod)
/* disable interrupts so no more work is scheduled */
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
- /* flush any pending work */
- flush_scheduled_work();
-
/* the first unallocated page in the DPM is #9 */
mod->free_page = DPM_FREE_START;
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 64c378cd0c34..74cd880c7e06 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -182,7 +182,7 @@ static int mscan_restart(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
- "bus-off state expected");
+ "bus-off state expected\n");
out_8(&regs->canmisc, MSCAN_BOHOLD);
/* Re-enable receive interrupts. */
out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index 55ec324caaf4..c42e97268248 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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
@@ -32,106 +32,115 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
-#define MAX_MSG_OBJ 32
-#define MSG_OBJ_RX 0 /* The receive message object flag. */
-#define MSG_OBJ_TX 1 /* The transmit message object flag. */
-
-#define ENABLE 1 /* The enable flag */
-#define DISABLE 0 /* The disable flag */
-#define CAN_CTRL_INIT 0x0001 /* The INIT bit of CANCONT register. */
-#define CAN_CTRL_IE 0x0002 /* The IE bit of CAN control register */
-#define CAN_CTRL_IE_SIE_EIE 0x000e
-#define CAN_CTRL_CCE 0x0040
-#define CAN_CTRL_OPT 0x0080 /* The OPT bit of CANCONT register. */
-#define CAN_OPT_SILENT 0x0008 /* The Silent bit of CANOPT reg. */
-#define CAN_OPT_LBACK 0x0010 /* The LoopBack bit of CANOPT reg. */
-#define CAN_CMASK_RX_TX_SET 0x00f3
-#define CAN_CMASK_RX_TX_GET 0x0073
-#define CAN_CMASK_ALL 0xff
-#define CAN_CMASK_RDWR 0x80
-#define CAN_CMASK_ARB 0x20
-#define CAN_CMASK_CTRL 0x10
-#define CAN_CMASK_MASK 0x40
-#define CAN_CMASK_NEWDAT 0x04
-#define CAN_CMASK_CLRINTPND 0x08
-
-#define CAN_IF_MCONT_NEWDAT 0x8000
-#define CAN_IF_MCONT_INTPND 0x2000
-#define CAN_IF_MCONT_UMASK 0x1000
-#define CAN_IF_MCONT_TXIE 0x0800
-#define CAN_IF_MCONT_RXIE 0x0400
-#define CAN_IF_MCONT_RMTEN 0x0200
-#define CAN_IF_MCONT_TXRQXT 0x0100
-#define CAN_IF_MCONT_EOB 0x0080
-#define CAN_IF_MCONT_DLC 0x000f
-#define CAN_IF_MCONT_MSGLOST 0x4000
-#define CAN_MASK2_MDIR_MXTD 0xc000
-#define CAN_ID2_DIR 0x2000
-#define CAN_ID_MSGVAL 0x8000
-
-#define CAN_STATUS_INT 0x8000
-#define CAN_IF_CREQ_BUSY 0x8000
-#define CAN_ID2_XTD 0x4000
-
-#define CAN_REC 0x00007f00
-#define CAN_TEC 0x000000ff
-
-#define PCH_RX_OK 0x00000010
-#define PCH_TX_OK 0x00000008
-#define PCH_BUS_OFF 0x00000080
-#define PCH_EWARN 0x00000040
-#define PCH_EPASSIV 0x00000020
-#define PCH_LEC0 0x00000001
-#define PCH_LEC1 0x00000002
-#define PCH_LEC2 0x00000004
-#define PCH_LEC_ALL (PCH_LEC0 | PCH_LEC1 | PCH_LEC2)
-#define PCH_STUF_ERR PCH_LEC0
-#define PCH_FORM_ERR PCH_LEC1
-#define PCH_ACK_ERR (PCH_LEC0 | PCH_LEC1)
-#define PCH_BIT1_ERR PCH_LEC2
-#define PCH_BIT0_ERR (PCH_LEC0 | PCH_LEC2)
-#define PCH_CRC_ERR (PCH_LEC1 | PCH_LEC2)
+#define PCH_CTRL_INIT BIT(0) /* The INIT bit of CANCONT register. */
+#define PCH_CTRL_IE BIT(1) /* The IE bit of CAN control register */
+#define PCH_CTRL_IE_SIE_EIE (BIT(3) | BIT(2) | BIT(1))
+#define PCH_CTRL_CCE BIT(6)
+#define PCH_CTRL_OPT BIT(7) /* The OPT bit of CANCONT register. */
+#define PCH_OPT_SILENT BIT(3) /* The Silent bit of CANOPT reg. */
+#define PCH_OPT_LBACK BIT(4) /* The LoopBack bit of CANOPT reg. */
+
+#define PCH_CMASK_RX_TX_SET 0x00f3
+#define PCH_CMASK_RX_TX_GET 0x0073
+#define PCH_CMASK_ALL 0xff
+#define PCH_CMASK_NEWDAT BIT(2)
+#define PCH_CMASK_CLRINTPND BIT(3)
+#define PCH_CMASK_CTRL BIT(4)
+#define PCH_CMASK_ARB BIT(5)
+#define PCH_CMASK_MASK BIT(6)
+#define PCH_CMASK_RDWR BIT(7)
+#define PCH_IF_MCONT_NEWDAT BIT(15)
+#define PCH_IF_MCONT_MSGLOST BIT(14)
+#define PCH_IF_MCONT_INTPND BIT(13)
+#define PCH_IF_MCONT_UMASK BIT(12)
+#define PCH_IF_MCONT_TXIE BIT(11)
+#define PCH_IF_MCONT_RXIE BIT(10)
+#define PCH_IF_MCONT_RMTEN BIT(9)
+#define PCH_IF_MCONT_TXRQXT BIT(8)
+#define PCH_IF_MCONT_EOB BIT(7)
+#define PCH_IF_MCONT_DLC (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define PCH_MASK2_MDIR_MXTD (BIT(14) | BIT(15))
+#define PCH_ID2_DIR BIT(13)
+#define PCH_ID2_XTD BIT(14)
+#define PCH_ID_MSGVAL BIT(15)
+#define PCH_IF_CREQ_BUSY BIT(15)
+
+#define PCH_STATUS_INT 0x8000
+#define PCH_REC 0x00007f00
+#define PCH_TEC 0x000000ff
+
+#define PCH_TX_OK BIT(3)
+#define PCH_RX_OK BIT(4)
+#define PCH_EPASSIV BIT(5)
+#define PCH_EWARN BIT(6)
+#define PCH_BUS_OFF BIT(7)
/* bit position of certain controller bits. */
-#define BIT_BITT_BRP 0
-#define BIT_BITT_SJW 6
-#define BIT_BITT_TSEG1 8
-#define BIT_BITT_TSEG2 12
-#define BIT_IF1_MCONT_RXIE 10
-#define BIT_IF2_MCONT_TXIE 11
-#define BIT_BRPE_BRPE 6
-#define BIT_ES_TXERRCNT 0
-#define BIT_ES_RXERRCNT 8
-#define MSK_BITT_BRP 0x3f
-#define MSK_BITT_SJW 0xc0
-#define MSK_BITT_TSEG1 0xf00
-#define MSK_BITT_TSEG2 0x7000
-#define MSK_BRPE_BRPE 0x3c0
-#define MSK_BRPE_GET 0x0f
-#define MSK_CTRL_IE_SIE_EIE 0x07
-#define MSK_MCONT_TXIE 0x08
-#define MSK_MCONT_RXIE 0x10
-#define PCH_CAN_NO_TX_BUFF 1
-#define COUNTER_LIMIT 10
+#define PCH_BIT_BRP_SHIFT 0
+#define PCH_BIT_SJW_SHIFT 6
+#define PCH_BIT_TSEG1_SHIFT 8
+#define PCH_BIT_TSEG2_SHIFT 12
+#define PCH_BIT_BRPE_BRPE_SHIFT 6
+
+#define PCH_MSK_BITT_BRP 0x3f
+#define PCH_MSK_BRPE_BRPE 0x3c0
+#define PCH_MSK_CTRL_IE_SIE_EIE 0x07
+#define PCH_COUNTER_LIMIT 10
#define PCH_CAN_CLK 50000000 /* 50MHz */
-/* Define the number of message object.
+/*
+ * Define the number of message object.
* PCH CAN communications are done via Message RAM.
- * The Message RAM consists of 32 message objects. */
-#define PCH_RX_OBJ_NUM 26 /* 1~ PCH_RX_OBJ_NUM is Rx*/
-#define PCH_TX_OBJ_NUM 6 /* PCH_RX_OBJ_NUM is RX ~ Tx*/
-#define PCH_OBJ_NUM (PCH_TX_OBJ_NUM + PCH_RX_OBJ_NUM)
+ * The Message RAM consists of 32 message objects.
+ */
+#define PCH_RX_OBJ_NUM 26
+#define PCH_TX_OBJ_NUM 6
+#define PCH_RX_OBJ_START 1
+#define PCH_RX_OBJ_END PCH_RX_OBJ_NUM
+#define PCH_TX_OBJ_START (PCH_RX_OBJ_END + 1)
+#define PCH_TX_OBJ_END (PCH_RX_OBJ_NUM + PCH_TX_OBJ_NUM)
#define PCH_FIFO_THRESH 16
+/* TxRqst2 show status of MsgObjNo.17~32 */
+#define PCH_TREQ2_TX_MASK (((1 << PCH_TX_OBJ_NUM) - 1) <<\
+ (PCH_RX_OBJ_END - 16))
+
+enum pch_ifreg {
+ PCH_RX_IFREG,
+ PCH_TX_IFREG,
+};
+
+enum pch_can_err {
+ PCH_STUF_ERR = 1,
+ PCH_FORM_ERR,
+ PCH_ACK_ERR,
+ PCH_BIT1_ERR,
+ PCH_BIT0_ERR,
+ PCH_CRC_ERR,
+ PCH_LEC_ALL,
+};
+
enum pch_can_mode {
PCH_CAN_ENABLE,
PCH_CAN_DISABLE,
PCH_CAN_ALL,
PCH_CAN_NONE,
PCH_CAN_STOP,
- PCH_CAN_RUN
+ PCH_CAN_RUN,
+};
+
+struct pch_can_if_regs {
+ u32 creq;
+ u32 cmask;
+ u32 mask1;
+ u32 mask2;
+ u32 id1;
+ u32 id2;
+ u32 mcont;
+ u32 data[4];
+ u32 rsv[13];
};
struct pch_can_regs {
@@ -142,57 +151,36 @@ struct pch_can_regs {
u32 intr;
u32 opt;
u32 brpe;
- u32 reserve1;
- u32 if1_creq;
- u32 if1_cmask;
- u32 if1_mask1;
- u32 if1_mask2;
- u32 if1_id1;
- u32 if1_id2;
- u32 if1_mcont;
- u32 if1_dataa1;
- u32 if1_dataa2;
- u32 if1_datab1;
- u32 if1_datab2;
- u32 reserve2;
- u32 reserve3[12];
- u32 if2_creq;
- u32 if2_cmask;
- u32 if2_mask1;
- u32 if2_mask2;
- u32 if2_id1;
- u32 if2_id2;
- u32 if2_mcont;
- u32 if2_dataa1;
- u32 if2_dataa2;
- u32 if2_datab1;
- u32 if2_datab2;
- u32 reserve4;
- u32 reserve5[20];
+ u32 reserve;
+ struct pch_can_if_regs ifregs[2]; /* [0]=if1 [1]=if2 */
+ u32 reserve1[8];
u32 treq1;
u32 treq2;
- u32 reserve6[2];
- u32 reserve7[56];
- u32 reserve8[3];
+ u32 reserve2[6];
+ u32 data1;
+ u32 data2;
+ u32 reserve3[6];
+ u32 canipend1;
+ u32 canipend2;
+ u32 reserve4[6];
+ u32 canmval1;
+ u32 canmval2;
+ u32 reserve5[37];
u32 srst;
};
struct pch_can_priv {
struct can_priv can;
- unsigned int can_num;
struct pci_dev *dev;
- unsigned int tx_enable[MAX_MSG_OBJ];
- unsigned int rx_enable[MAX_MSG_OBJ];
- unsigned int rx_link[MAX_MSG_OBJ];
- unsigned int int_enables;
- unsigned int int_stat;
+ u32 tx_enable[PCH_TX_OBJ_END];
+ u32 rx_enable[PCH_TX_OBJ_END];
+ u32 rx_link[PCH_TX_OBJ_END];
+ u32 int_enables;
struct net_device *ndev;
- spinlock_t msgif_reg_lock; /* Message Interface Registers Access Lock*/
- unsigned int msg_obj[MAX_MSG_OBJ];
struct pch_can_regs __iomem *regs;
struct napi_struct napi;
- unsigned int tx_obj; /* Point next Tx Obj index */
- unsigned int use_msi;
+ int tx_obj; /* Point next Tx Obj index */
+ int use_msi;
};
static struct can_bittiming_const pch_can_bittiming_const = {
@@ -213,12 +201,12 @@ static DEFINE_PCI_DEVICE_TABLE(pch_pci_tbl) = {
};
MODULE_DEVICE_TABLE(pci, pch_pci_tbl);
-static inline void pch_can_bit_set(u32 *addr, u32 mask)
+static inline void pch_can_bit_set(void __iomem *addr, u32 mask)
{
iowrite32(ioread32(addr) | mask, addr);
}
-static inline void pch_can_bit_clear(u32 *addr, u32 mask)
+static inline void pch_can_bit_clear(void __iomem *addr, u32 mask)
{
iowrite32(ioread32(addr) & ~mask, addr);
}
@@ -228,15 +216,15 @@ static void pch_can_set_run_mode(struct pch_can_priv *priv,
{
switch (mode) {
case PCH_CAN_RUN:
- pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_INIT);
+ pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_INIT);
break;
case PCH_CAN_STOP:
- pch_can_bit_set(&priv->regs->cont, CAN_CTRL_INIT);
+ pch_can_bit_set(&priv->regs->cont, PCH_CTRL_INIT);
break;
default:
- dev_err(&priv->ndev->dev, "%s -> Invalid Mode.\n", __func__);
+ netdev_err(priv->ndev, "%s -> Invalid Mode.\n", __func__);
break;
}
}
@@ -246,357 +234,184 @@ static void pch_can_set_optmode(struct pch_can_priv *priv)
u32 reg_val = ioread32(&priv->regs->opt);
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
- reg_val |= CAN_OPT_SILENT;
+ reg_val |= PCH_OPT_SILENT;
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
- reg_val |= CAN_OPT_LBACK;
+ reg_val |= PCH_OPT_LBACK;
- pch_can_bit_set(&priv->regs->cont, CAN_CTRL_OPT);
+ pch_can_bit_set(&priv->regs->cont, PCH_CTRL_OPT);
iowrite32(reg_val, &priv->regs->opt);
}
-static void pch_can_set_int_custom(struct pch_can_priv *priv)
+static void pch_can_rw_msg_obj(void __iomem *creq_addr, u32 num)
{
- /* Clearing the IE, SIE and EIE bits of Can control register. */
- pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
-
- /* Appropriately setting them. */
- pch_can_bit_set(&priv->regs->cont,
- ((priv->int_enables & MSK_CTRL_IE_SIE_EIE) << 1));
-}
+ int counter = PCH_COUNTER_LIMIT;
+ u32 ifx_creq;
-/* This function retrieves interrupt enabled for the CAN device. */
-static void pch_can_get_int_enables(struct pch_can_priv *priv, u32 *enables)
-{
- /* Obtaining the status of IE, SIE and EIE interrupt bits. */
- *enables = ((ioread32(&priv->regs->cont) & CAN_CTRL_IE_SIE_EIE) >> 1);
+ iowrite32(num, creq_addr);
+ while (counter) {
+ ifx_creq = ioread32(creq_addr) & PCH_IF_CREQ_BUSY;
+ if (!ifx_creq)
+ break;
+ counter--;
+ udelay(1);
+ }
+ if (!counter)
+ pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__);
}
static void pch_can_set_int_enables(struct pch_can_priv *priv,
enum pch_can_mode interrupt_no)
{
switch (interrupt_no) {
- case PCH_CAN_ENABLE:
- pch_can_bit_set(&priv->regs->cont, CAN_CTRL_IE);
- break;
-
case PCH_CAN_DISABLE:
- pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE);
+ pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE);
break;
case PCH_CAN_ALL:
- pch_can_bit_set(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
+ pch_can_bit_set(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
break;
case PCH_CAN_NONE:
- pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
+ pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
break;
default:
- dev_err(&priv->ndev->dev, "Invalid interrupt number.\n");
+ netdev_err(priv->ndev, "Invalid interrupt number.\n");
break;
}
}
-static void pch_can_check_if_busy(u32 __iomem *creq_addr, u32 num)
-{
- u32 counter = COUNTER_LIMIT;
- u32 ifx_creq;
-
- iowrite32(num, creq_addr);
- while (counter) {
- ifx_creq = ioread32(creq_addr) & CAN_IF_CREQ_BUSY;
- if (!ifx_creq)
- break;
- counter--;
- udelay(1);
- }
- if (!counter)
- pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__);
-}
-
-static void pch_can_set_rx_enable(struct pch_can_priv *priv, u32 buff_num,
- u32 set)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- /* Reading the receive buffer data from RAM to Interface1 registers */
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
-
- /* Setting the IF1MASK1 register to access MsgVal and RxIE bits */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if1_cmask);
-
- if (set == ENABLE) {
- /* Setting the MsgVal and RxIE bits */
- pch_can_bit_set(&priv->regs->if1_mcont, CAN_IF_MCONT_RXIE);
- pch_can_bit_set(&priv->regs->if1_id2, CAN_ID_MSGVAL);
-
- } else if (set == DISABLE) {
- /* Resetting the MsgVal and RxIE bits */
- pch_can_bit_clear(&priv->regs->if1_mcont, CAN_IF_MCONT_RXIE);
- pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID_MSGVAL);
- }
-
- pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
-}
-
-static void pch_can_rx_enable_all(struct pch_can_priv *priv)
+static void pch_can_set_rxtx(struct pch_can_priv *priv, u32 buff_num,
+ int set, enum pch_ifreg dir)
{
- int i;
+ u32 ie;
- /* Traversing to obtain the object configured as receivers. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_RX)
- pch_can_set_rx_enable(priv, i + 1, ENABLE);
- }
-}
+ if (dir)
+ ie = PCH_IF_MCONT_TXIE;
+ else
+ ie = PCH_IF_MCONT_RXIE;
-static void pch_can_rx_disable_all(struct pch_can_priv *priv)
-{
- int i;
+ /* Reading the Msg buffer from Message RAM to IF1/2 registers. */
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
- /* Traversing to obtain the object configured as receivers. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_RX)
- pch_can_set_rx_enable(priv, i + 1, DISABLE);
- }
-}
+ /* Setting the IF1/2MASK1 register to access MsgVal and RxIE bits */
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_ARB | PCH_CMASK_CTRL,
+ &priv->regs->ifregs[dir].cmask);
-static void pch_can_set_tx_enable(struct pch_can_priv *priv, u32 buff_num,
- u32 set)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- /* Reading the Msg buffer from Message RAM to Interface2 registers. */
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
-
- /* Setting the IF2CMASK register for accessing the
- MsgVal and TxIE bits */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if2_cmask);
-
- if (set == ENABLE) {
- /* Setting the MsgVal and TxIE bits */
- pch_can_bit_set(&priv->regs->if2_mcont, CAN_IF_MCONT_TXIE);
- pch_can_bit_set(&priv->regs->if2_id2, CAN_ID_MSGVAL);
- } else if (set == DISABLE) {
- /* Resetting the MsgVal and TxIE bits. */
- pch_can_bit_clear(&priv->regs->if2_mcont, CAN_IF_MCONT_TXIE);
- pch_can_bit_clear(&priv->regs->if2_id2, CAN_ID_MSGVAL);
+ if (set) {
+ /* Setting the MsgVal and RxIE/TxIE bits */
+ pch_can_bit_set(&priv->regs->ifregs[dir].mcont, ie);
+ pch_can_bit_set(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL);
+ } else {
+ /* Clearing the MsgVal and RxIE/TxIE bits */
+ pch_can_bit_clear(&priv->regs->ifregs[dir].mcont, ie);
+ pch_can_bit_clear(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL);
}
- pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
}
-static void pch_can_tx_enable_all(struct pch_can_priv *priv)
+static void pch_can_set_rx_all(struct pch_can_priv *priv, int set)
{
int i;
- /* Traversing to obtain the object configured as transmit object. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_TX)
- pch_can_set_tx_enable(priv, i + 1, ENABLE);
- }
+ /* Traversing to obtain the object configured as receivers. */
+ for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++)
+ pch_can_set_rxtx(priv, i, set, PCH_RX_IFREG);
}
-static void pch_can_tx_disable_all(struct pch_can_priv *priv)
+static void pch_can_set_tx_all(struct pch_can_priv *priv, int set)
{
int i;
/* Traversing to obtain the object configured as transmit object. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_TX)
- pch_can_set_tx_enable(priv, i + 1, DISABLE);
- }
-}
-
-static void pch_can_get_rx_enable(struct pch_can_priv *priv, u32 buff_num,
- u32 *enable)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
-
- if (((ioread32(&priv->regs->if1_id2)) & CAN_ID_MSGVAL) &&
- ((ioread32(&priv->regs->if1_mcont)) &
- CAN_IF_MCONT_RXIE))
- *enable = ENABLE;
- else
- *enable = DISABLE;
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
-}
-
-static void pch_can_get_tx_enable(struct pch_can_priv *priv, u32 buff_num,
- u32 *enable)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
-
- if (((ioread32(&priv->regs->if2_id2)) & CAN_ID_MSGVAL) &&
- ((ioread32(&priv->regs->if2_mcont)) &
- CAN_IF_MCONT_TXIE)) {
- *enable = ENABLE;
- } else {
- *enable = DISABLE;
- }
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
+ pch_can_set_rxtx(priv, i, set, PCH_TX_IFREG);
}
-static int pch_can_int_pending(struct pch_can_priv *priv)
+static u32 pch_can_int_pending(struct pch_can_priv *priv)
{
return ioread32(&priv->regs->intr) & 0xffff;
}
-static void pch_can_set_rx_buffer_link(struct pch_can_priv *priv,
- u32 buffer_num, u32 set)
+static void pch_can_clear_if_buffers(struct pch_can_priv *priv)
{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL, &priv->regs->if1_cmask);
- if (set == ENABLE)
- pch_can_bit_clear(&priv->regs->if1_mcont, CAN_IF_MCONT_EOB);
- else
- pch_can_bit_set(&priv->regs->if1_mcont, CAN_IF_MCONT_EOB);
-
- pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
-}
-
-static void pch_can_get_rx_buffer_link(struct pch_can_priv *priv,
- u32 buffer_num, u32 *link)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
-
- if (ioread32(&priv->regs->if1_mcont) & CAN_IF_MCONT_EOB)
- *link = DISABLE;
- else
- *link = ENABLE;
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
-}
-
-static void pch_can_clear_buffers(struct pch_can_priv *priv)
-{
- int i;
-
- for (i = 0; i < PCH_RX_OBJ_NUM; i++) {
- iowrite32(CAN_CMASK_RX_TX_SET, &priv->regs->if1_cmask);
- iowrite32(0xffff, &priv->regs->if1_mask1);
- iowrite32(0xffff, &priv->regs->if1_mask2);
- iowrite32(0x0, &priv->regs->if1_id1);
- iowrite32(0x0, &priv->regs->if1_id2);
- iowrite32(0x0, &priv->regs->if1_mcont);
- iowrite32(0x0, &priv->regs->if1_dataa1);
- iowrite32(0x0, &priv->regs->if1_dataa2);
- iowrite32(0x0, &priv->regs->if1_datab1);
- iowrite32(0x0, &priv->regs->if1_datab2);
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
- CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
- }
-
- for (i = i; i < PCH_OBJ_NUM; i++) {
- iowrite32(CAN_CMASK_RX_TX_SET, &priv->regs->if2_cmask);
- iowrite32(0xffff, &priv->regs->if2_mask1);
- iowrite32(0xffff, &priv->regs->if2_mask2);
- iowrite32(0x0, &priv->regs->if2_id1);
- iowrite32(0x0, &priv->regs->if2_id2);
- iowrite32(0x0, &priv->regs->if2_mcont);
- iowrite32(0x0, &priv->regs->if2_dataa1);
- iowrite32(0x0, &priv->regs->if2_dataa2);
- iowrite32(0x0, &priv->regs->if2_datab1);
- iowrite32(0x0, &priv->regs->if2_datab2);
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
- CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
+ int i; /* Msg Obj ID (1~32) */
+
+ for (i = PCH_RX_OBJ_START; i <= PCH_TX_OBJ_END; i++) {
+ iowrite32(PCH_CMASK_RX_TX_SET, &priv->regs->ifregs[0].cmask);
+ iowrite32(0xffff, &priv->regs->ifregs[0].mask1);
+ iowrite32(0xffff, &priv->regs->ifregs[0].mask2);
+ iowrite32(0x0, &priv->regs->ifregs[0].id1);
+ iowrite32(0x0, &priv->regs->ifregs[0].id2);
+ iowrite32(0x0, &priv->regs->ifregs[0].mcont);
+ iowrite32(0x0, &priv->regs->ifregs[0].data[0]);
+ iowrite32(0x0, &priv->regs->ifregs[0].data[1]);
+ iowrite32(0x0, &priv->regs->ifregs[0].data[2]);
+ iowrite32(0x0, &priv->regs->ifregs[0].data[3]);
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK |
+ PCH_CMASK_ARB | PCH_CMASK_CTRL,
+ &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
}
}
static void pch_can_config_rx_tx_buffers(struct pch_can_priv *priv)
{
int i;
- unsigned long flags;
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_RX) {
- iowrite32(CAN_CMASK_RX_TX_GET,
- &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
+ iowrite32(0x0, &priv->regs->ifregs[0].id1);
+ iowrite32(0x0, &priv->regs->ifregs[0].id2);
- iowrite32(0x0, &priv->regs->if1_id1);
- iowrite32(0x0, &priv->regs->if1_id2);
+ pch_can_bit_set(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_UMASK);
- pch_can_bit_set(&priv->regs->if1_mcont,
- CAN_IF_MCONT_UMASK);
+ /* In case FIFO mode, Last EoB of Rx Obj must be 1 */
+ if (i == PCH_RX_OBJ_END)
+ pch_can_bit_set(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_EOB);
+ else
+ pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_EOB);
- /* Set FIFO mode set to 0 except last Rx Obj*/
- pch_can_bit_clear(&priv->regs->if1_mcont,
- CAN_IF_MCONT_EOB);
- /* In case FIFO mode, Last EoB of Rx Obj must be 1 */
- if (i == (PCH_RX_OBJ_NUM - 1))
- pch_can_bit_set(&priv->regs->if1_mcont,
- CAN_IF_MCONT_EOB);
+ iowrite32(0, &priv->regs->ifregs[0].mask1);
+ pch_can_bit_clear(&priv->regs->ifregs[0].mask2,
+ 0x1fff | PCH_MASK2_MDIR_MXTD);
- iowrite32(0, &priv->regs->if1_mask1);
- pch_can_bit_clear(&priv->regs->if1_mask2,
- 0x1fff | CAN_MASK2_MDIR_MXTD);
+ /* Setting CMASK for writing */
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB |
+ PCH_CMASK_CTRL, &priv->regs->ifregs[0].cmask);
- /* Setting CMASK for writing */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
- CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if1_cmask);
-
- pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
- } else if (priv->msg_obj[i] == MSG_OBJ_TX) {
- iowrite32(CAN_CMASK_RX_TX_GET,
- &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
+ }
- /* Resetting DIR bit for reception */
- iowrite32(0x0, &priv->regs->if2_id1);
- iowrite32(0x0, &priv->regs->if2_id2);
- pch_can_bit_set(&priv->regs->if2_id2, CAN_ID2_DIR);
+ for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) {
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[1].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i);
- /* Setting EOB bit for transmitter */
- iowrite32(CAN_IF_MCONT_EOB, &priv->regs->if2_mcont);
+ /* Resetting DIR bit for reception */
+ iowrite32(0x0, &priv->regs->ifregs[1].id1);
+ iowrite32(PCH_ID2_DIR, &priv->regs->ifregs[1].id2);
- pch_can_bit_set(&priv->regs->if2_mcont,
- CAN_IF_MCONT_UMASK);
+ /* Setting EOB bit for transmitter */
+ iowrite32(PCH_IF_MCONT_EOB | PCH_IF_MCONT_UMASK,
+ &priv->regs->ifregs[1].mcont);
- iowrite32(0, &priv->regs->if2_mask1);
- pch_can_bit_clear(&priv->regs->if2_mask2, 0x1fff);
+ iowrite32(0, &priv->regs->ifregs[1].mask1);
+ pch_can_bit_clear(&priv->regs->ifregs[1].mask2, 0x1fff);
- /* Setting CMASK for writing */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
- CAN_CMASK_ARB | CAN_CMASK_CTRL,
- &priv->regs->if2_cmask);
+ /* Setting CMASK for writing */
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB |
+ PCH_CMASK_CTRL, &priv->regs->ifregs[1].cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
- }
+ pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i);
}
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
}
static void pch_can_init(struct pch_can_priv *priv)
@@ -605,7 +420,7 @@ static void pch_can_init(struct pch_can_priv *priv)
pch_can_set_run_mode(priv, PCH_CAN_STOP);
/* Clearing all the message object buffers. */
- pch_can_clear_buffers(priv);
+ pch_can_clear_if_buffers(priv);
/* Configuring the respective message object as either rx/tx object. */
pch_can_config_rx_tx_buffers(priv);
@@ -623,57 +438,47 @@ static void pch_can_release(struct pch_can_priv *priv)
pch_can_set_int_enables(priv, PCH_CAN_NONE);
/* Disabling all the receive object. */
- pch_can_rx_disable_all(priv);
+ pch_can_set_rx_all(priv, 0);
/* Disabling all the transmit object. */
- pch_can_tx_disable_all(priv);
+ pch_can_set_tx_all(priv, 0);
}
/* This function clears interrupt(s) from the CAN device. */
static void pch_can_int_clr(struct pch_can_priv *priv, u32 mask)
{
- if (mask == CAN_STATUS_INT) {
- ioread32(&priv->regs->stat);
- return;
- }
-
/* Clear interrupt for transmit object */
- if (priv->msg_obj[mask - 1] == MSG_OBJ_TX) {
- /* Setting CMASK for clearing interrupts for
- frame transmission. */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL | CAN_CMASK_ARB,
- &priv->regs->if2_cmask);
-
- /* Resetting the ID registers. */
- pch_can_bit_set(&priv->regs->if2_id2,
- CAN_ID2_DIR | (0x7ff << 2));
- iowrite32(0x0, &priv->regs->if2_id1);
-
- /* Claring NewDat, TxRqst & IntPnd */
- pch_can_bit_clear(&priv->regs->if2_mcont,
- CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND |
- CAN_IF_MCONT_TXRQXT);
- pch_can_check_if_busy(&priv->regs->if2_creq, mask);
- } else if (priv->msg_obj[mask - 1] == MSG_OBJ_RX) {
+ if ((mask >= PCH_RX_OBJ_START) && (mask <= PCH_RX_OBJ_END)) {
/* Setting CMASK for clearing the reception interrupts. */
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL | CAN_CMASK_ARB,
- &priv->regs->if1_cmask);
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB,
+ &priv->regs->ifregs[0].cmask);
/* Clearing the Dir bit. */
- pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID2_DIR);
+ pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR);
/* Clearing NewDat & IntPnd */
- pch_can_bit_clear(&priv->regs->if1_mcont,
- CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND);
+ pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND);
- pch_can_check_if_busy(&priv->regs->if1_creq, mask);
- }
-}
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, mask);
+ } else if ((mask >= PCH_TX_OBJ_START) && (mask <= PCH_TX_OBJ_END)) {
+ /*
+ * Setting CMASK for clearing interrupts for frame transmission.
+ */
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB,
+ &priv->regs->ifregs[1].cmask);
-static int pch_can_get_buffer_status(struct pch_can_priv *priv)
-{
- return (ioread32(&priv->regs->treq1) & 0xffff) |
- ((ioread32(&priv->regs->treq2) & 0xffff) << 16);
+ /* Resetting the ID registers. */
+ pch_can_bit_set(&priv->regs->ifregs[1].id2,
+ PCH_ID2_DIR | (0x7ff << 2));
+ iowrite32(0x0, &priv->regs->ifregs[1].id1);
+
+ /* Claring NewDat, TxRqst & IntPnd */
+ pch_can_bit_clear(&priv->regs->ifregs[1].mcont,
+ PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND |
+ PCH_IF_MCONT_TXRQXT);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, mask);
+ }
}
static void pch_can_reset(struct pch_can_priv *priv)
@@ -688,7 +493,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
struct sk_buff *skb;
struct pch_can_priv *priv = netdev_priv(ndev);
struct can_frame *cf;
- u32 errc;
+ u32 errc, lec;
struct net_device_stats *stats = &(priv->ndev->stats);
enum can_state state = priv->can.state;
@@ -697,26 +502,24 @@ static void pch_can_error(struct net_device *ndev, u32 status)
return;
if (status & PCH_BUS_OFF) {
- pch_can_tx_disable_all(priv);
- pch_can_rx_disable_all(priv);
+ pch_can_set_tx_all(priv, 0);
+ pch_can_set_rx_all(priv, 0);
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(ndev);
- pch_can_set_run_mode(priv, PCH_CAN_RUN);
- dev_err(&ndev->dev, "%s -> Bus Off occurres.\n", __func__);
}
+ errc = ioread32(&priv->regs->errc);
/* Warning interrupt. */
if (status & PCH_EWARN) {
state = CAN_STATE_ERROR_WARNING;
priv->can.can_stats.error_warning++;
cf->can_id |= CAN_ERR_CRTL;
- errc = ioread32(&priv->regs->errc);
- if (((errc & CAN_REC) >> 8) > 96)
+ if (((errc & PCH_REC) >> 8) > 96)
cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
- if ((errc & CAN_TEC) > 96)
+ if ((errc & PCH_TEC) > 96)
cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
- dev_warn(&ndev->dev,
+ netdev_dbg(ndev,
"%s -> Error Counter is more than 96.\n", __func__);
}
/* Error passive interrupt. */
@@ -724,46 +527,52 @@ static void pch_can_error(struct net_device *ndev, u32 status)
priv->can.can_stats.error_passive++;
state = CAN_STATE_ERROR_PASSIVE;
cf->can_id |= CAN_ERR_CRTL;
- errc = ioread32(&priv->regs->errc);
- if (((errc & CAN_REC) >> 8) > 127)
+ if (((errc & PCH_REC) >> 8) > 127)
cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
- if ((errc & CAN_TEC) > 127)
+ if ((errc & PCH_TEC) > 127)
cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
- dev_err(&ndev->dev,
+ netdev_dbg(ndev,
"%s -> CAN controller is ERROR PASSIVE .\n", __func__);
}
- if (status & PCH_LEC_ALL) {
+ lec = status & PCH_LEC_ALL;
+ switch (lec) {
+ case PCH_STUF_ERR:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
priv->can.can_stats.bus_error++;
stats->rx_errors++;
- switch (status & PCH_LEC_ALL) {
- case PCH_STUF_ERR:
- cf->data[2] |= CAN_ERR_PROT_STUFF;
- break;
- case PCH_FORM_ERR:
- cf->data[2] |= CAN_ERR_PROT_FORM;
- break;
- case PCH_ACK_ERR:
- cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
- CAN_ERR_PROT_LOC_ACK_DEL;
- break;
- case PCH_BIT1_ERR:
- case PCH_BIT0_ERR:
- cf->data[2] |= CAN_ERR_PROT_BIT;
- break;
- case PCH_CRC_ERR:
- cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL;
- break;
- default:
- iowrite32(status | PCH_LEC_ALL, &priv->regs->stat);
- break;
- }
-
+ break;
+ case PCH_FORM_ERR:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ break;
+ case PCH_ACK_ERR:
+ cf->can_id |= CAN_ERR_ACK;
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ break;
+ case PCH_BIT1_ERR:
+ case PCH_BIT0_ERR:
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ break;
+ case PCH_CRC_ERR:
+ cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ break;
+ case PCH_LEC_ALL: /* Written by CPU. No error status */
+ break;
}
+ cf->data[6] = errc & PCH_TEC;
+ cf->data[7] = (errc & PCH_REC) >> 8;
+
priv->can.state = state;
- netif_rx(skb);
+ netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
@@ -774,204 +583,202 @@ static irqreturn_t pch_can_interrupt(int irq, void *dev_id)
struct net_device *ndev = (struct net_device *)dev_id;
struct pch_can_priv *priv = netdev_priv(ndev);
- pch_can_set_int_enables(priv, PCH_CAN_NONE);
+ if (!pch_can_int_pending(priv))
+ return IRQ_NONE;
+ pch_can_set_int_enables(priv, PCH_CAN_NONE);
napi_schedule(&priv->napi);
-
return IRQ_HANDLED;
}
-static int pch_can_rx_normal(struct net_device *ndev, u32 int_stat)
+static void pch_fifo_thresh(struct pch_can_priv *priv, int obj_id)
+{
+ if (obj_id < PCH_FIFO_THRESH) {
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL |
+ PCH_CMASK_ARB, &priv->regs->ifregs[0].cmask);
+
+ /* Clearing the Dir bit. */
+ pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR);
+
+ /* Clearing NewDat & IntPnd */
+ pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_INTPND);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id);
+ } else if (obj_id > PCH_FIFO_THRESH) {
+ pch_can_int_clr(priv, obj_id);
+ } else if (obj_id == PCH_FIFO_THRESH) {
+ int cnt;
+ for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++)
+ pch_can_int_clr(priv, cnt + 1);
+ }
+}
+
+static void pch_can_rx_msg_lost(struct net_device *ndev, int obj_id)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &(priv->ndev->stats);
+ struct sk_buff *skb;
+ struct can_frame *cf;
+
+ netdev_dbg(priv->ndev, "Msg Obj is overwritten.\n");
+ pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_MSGLOST);
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL,
+ &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id);
+
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb)
+ return;
+
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
+ netif_receive_skb(skb);
+}
+
+static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
{
u32 reg;
canid_t id;
- u32 ide;
- u32 rtr;
- int i, j, k;
int rcv_pkts = 0;
struct sk_buff *skb;
struct can_frame *cf;
struct pch_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &(priv->ndev->stats);
+ int i;
+ u32 id2;
+ u16 data_reg;
+
+ do {
+ /* Reading the messsage object from the Message RAM */
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_num);
- /* Reading the messsage object from the Message RAM */
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, int_stat);
+ /* Reading the MCONT register. */
+ reg = ioread32(&priv->regs->ifregs[0].mcont);
- /* Reading the MCONT register. */
- reg = ioread32(&priv->regs->if1_mcont);
- reg &= 0xffff;
+ if (reg & PCH_IF_MCONT_EOB)
+ break;
- for (k = int_stat; !(reg & CAN_IF_MCONT_EOB); k++) {
/* If MsgLost bit set. */
- if (reg & CAN_IF_MCONT_MSGLOST) {
- dev_err(&priv->ndev->dev, "Msg Obj is overwritten.\n");
- pch_can_bit_clear(&priv->regs->if1_mcont,
- CAN_IF_MCONT_MSGLOST);
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL,
- &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, k);
-
- skb = alloc_can_err_skb(ndev, &cf);
- if (!skb)
- return -ENOMEM;
-
- priv->can.can_stats.error_passive++;
- priv->can.state = CAN_STATE_ERROR_PASSIVE;
- cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
- cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
-
- netif_receive_skb(skb);
+ if (reg & PCH_IF_MCONT_MSGLOST) {
+ pch_can_rx_msg_lost(ndev, obj_num);
rcv_pkts++;
- goto RX_NEXT;
+ quota--;
+ obj_num++;
+ continue;
+ } else if (!(reg & PCH_IF_MCONT_NEWDAT)) {
+ obj_num++;
+ continue;
}
- if (!(reg & CAN_IF_MCONT_NEWDAT))
- goto RX_NEXT;
skb = alloc_can_skb(priv->ndev, &cf);
- if (!skb)
- return -ENOMEM;
+ if (!skb) {
+ netdev_err(ndev, "alloc_can_skb Failed\n");
+ return rcv_pkts;
+ }
/* Get Received data */
- ide = ((ioread32(&priv->regs->if1_id2)) & CAN_ID2_XTD) >> 14;
- if (ide) {
- id = (ioread32(&priv->regs->if1_id1) & 0xffff);
- id |= (((ioread32(&priv->regs->if1_id2)) &
- 0x1fff) << 16);
- cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ id2 = ioread32(&priv->regs->ifregs[0].id2);
+ if (id2 & PCH_ID2_XTD) {
+ id = (ioread32(&priv->regs->ifregs[0].id1) & 0xffff);
+ id |= (((id2) & 0x1fff) << 16);
+ cf->can_id = id | CAN_EFF_FLAG;
} else {
- id = (((ioread32(&priv->regs->if1_id2)) &
- (CAN_SFF_MASK << 2)) >> 2);
- cf->can_id = (id & CAN_SFF_MASK);
+ id = (id2 >> 2) & CAN_SFF_MASK;
+ cf->can_id = id;
}
- rtr = (ioread32(&priv->regs->if1_id2) & CAN_ID2_DIR);
- if (rtr) {
- cf->can_dlc = 0;
+ if (id2 & PCH_ID2_DIR)
cf->can_id |= CAN_RTR_FLAG;
- } else {
- cf->can_dlc = ((ioread32(&priv->regs->if1_mcont)) &
- 0x0f);
- }
- for (i = 0, j = 0; i < cf->can_dlc; j++) {
- reg = ioread32(&priv->regs->if1_dataa1 + j*4);
- cf->data[i++] = cpu_to_le32(reg & 0xff);
- if (i == cf->can_dlc)
- break;
- cf->data[i++] = cpu_to_le32((reg >> 8) & 0xff);
+ cf->can_dlc = get_can_dlc((ioread32(&priv->regs->
+ ifregs[0].mcont)) & 0xF);
+
+ for (i = 0; i < cf->can_dlc; i += 2) {
+ data_reg = ioread16(&priv->regs->ifregs[0].data[i / 2]);
+ cf->data[i] = data_reg;
+ cf->data[i + 1] = data_reg >> 8;
}
netif_receive_skb(skb);
rcv_pkts++;
stats->rx_packets++;
+ quota--;
stats->rx_bytes += cf->can_dlc;
- if (k < PCH_FIFO_THRESH) {
- iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL |
- CAN_CMASK_ARB, &priv->regs->if1_cmask);
-
- /* Clearing the Dir bit. */
- pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID2_DIR);
-
- /* Clearing NewDat & IntPnd */
- pch_can_bit_clear(&priv->regs->if1_mcont,
- CAN_IF_MCONT_INTPND);
- pch_can_check_if_busy(&priv->regs->if1_creq, k);
- } else if (k > PCH_FIFO_THRESH) {
- pch_can_int_clr(priv, k);
- } else if (k == PCH_FIFO_THRESH) {
- int cnt;
- for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++)
- pch_can_int_clr(priv, cnt+1);
- }
-RX_NEXT:
- /* Reading the messsage object from the Message RAM */
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
- pch_can_check_if_busy(&priv->regs->if1_creq, k + 1);
- reg = ioread32(&priv->regs->if1_mcont);
- }
+ pch_fifo_thresh(priv, obj_num);
+ obj_num++;
+ } while (quota > 0);
return rcv_pkts;
}
-static int pch_can_rx_poll(struct napi_struct *napi, int quota)
+
+static void pch_can_tx_complete(struct net_device *ndev, u32 int_stat)
{
- struct net_device *ndev = napi->dev;
struct pch_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &(priv->ndev->stats);
u32 dlc;
+
+ can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1);
+ iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND,
+ &priv->regs->ifregs[1].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat);
+ dlc = get_can_dlc(ioread32(&priv->regs->ifregs[1].mcont) &
+ PCH_IF_MCONT_DLC);
+ stats->tx_bytes += dlc;
+ stats->tx_packets++;
+ if (int_stat == PCH_TX_OBJ_END)
+ netif_wake_queue(ndev);
+}
+
+static int pch_can_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct pch_can_priv *priv = netdev_priv(ndev);
u32 int_stat;
- int rcv_pkts = 0;
u32 reg_stat;
- unsigned long flags;
+ int quota_save = quota;
int_stat = pch_can_int_pending(priv);
if (!int_stat)
- return 0;
+ goto end;
-INT_STAT:
- if (int_stat == CAN_STATUS_INT) {
+ if (int_stat == PCH_STATUS_INT) {
reg_stat = ioread32(&priv->regs->stat);
- if (reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) {
- if ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)
- pch_can_error(ndev, reg_stat);
- }
- if (reg_stat & PCH_TX_OK) {
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq,
- ioread32(&priv->regs->intr));
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
- pch_can_bit_clear(&priv->regs->stat, PCH_TX_OK);
+ if ((reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) &&
+ ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)) {
+ pch_can_error(ndev, reg_stat);
+ quota--;
}
- if (reg_stat & PCH_RX_OK)
- pch_can_bit_clear(&priv->regs->stat, PCH_RX_OK);
+ if (reg_stat & (PCH_TX_OK | PCH_RX_OK))
+ pch_can_bit_clear(&priv->regs->stat,
+ reg_stat & (PCH_TX_OK | PCH_RX_OK));
int_stat = pch_can_int_pending(priv);
- if (int_stat == CAN_STATUS_INT)
- goto INT_STAT;
}
-MSG_OBJ:
- if ((int_stat >= 1) && (int_stat <= PCH_RX_OBJ_NUM)) {
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- rcv_pkts = pch_can_rx_normal(ndev, int_stat);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
- if (rcv_pkts < 0)
- return 0;
- } else if ((int_stat > PCH_RX_OBJ_NUM) && (int_stat <= PCH_OBJ_NUM)) {
- if (priv->msg_obj[int_stat - 1] == MSG_OBJ_TX) {
- /* Handle transmission interrupt */
- can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_NUM - 1);
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
- iowrite32(CAN_CMASK_RX_TX_GET | CAN_CMASK_CLRINTPND,
- &priv->regs->if2_cmask);
- dlc = ioread32(&priv->regs->if2_mcont) &
- CAN_IF_MCONT_DLC;
- pch_can_check_if_busy(&priv->regs->if2_creq, int_stat);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
- if (dlc > 8)
- dlc = 8;
- stats->tx_bytes += dlc;
- stats->tx_packets++;
- }
- }
+ if (quota == 0)
+ goto end;
- int_stat = pch_can_int_pending(priv);
- if (int_stat == CAN_STATUS_INT)
- goto INT_STAT;
- else if (int_stat >= 1 && int_stat <= 32)
- goto MSG_OBJ;
+ if ((int_stat >= PCH_RX_OBJ_START) && (int_stat <= PCH_RX_OBJ_END)) {
+ quota -= pch_can_rx_normal(ndev, int_stat, quota);
+ } else if ((int_stat >= PCH_TX_OBJ_START) &&
+ (int_stat <= PCH_TX_OBJ_END)) {
+ /* Handle transmission interrupt */
+ pch_can_tx_complete(ndev, int_stat);
+ }
+end:
napi_complete(napi);
pch_can_set_int_enables(priv, PCH_CAN_ALL);
- return rcv_pkts;
+ return quota_save - quota;
}
static int pch_set_bittiming(struct net_device *ndev)
@@ -980,20 +787,18 @@ static int pch_set_bittiming(struct net_device *ndev)
const struct can_bittiming *bt = &priv->can.bittiming;
u32 canbit;
u32 bepe;
- u32 brp;
/* Setting the CCE bit for accessing the Can Timing register. */
- pch_can_bit_set(&priv->regs->cont, CAN_CTRL_CCE);
-
- brp = (bt->tq) / (1000000000/PCH_CAN_CLK) - 1;
- canbit = brp & MSK_BITT_BRP;
- canbit |= (bt->sjw - 1) << BIT_BITT_SJW;
- canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << BIT_BITT_TSEG1;
- canbit |= (bt->phase_seg2 - 1) << BIT_BITT_TSEG2;
- bepe = (brp & MSK_BRPE_BRPE) >> BIT_BRPE_BRPE;
+ pch_can_bit_set(&priv->regs->cont, PCH_CTRL_CCE);
+
+ canbit = (bt->brp - 1) & PCH_MSK_BITT_BRP;
+ canbit |= (bt->sjw - 1) << PCH_BIT_SJW_SHIFT;
+ canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << PCH_BIT_TSEG1_SHIFT;
+ canbit |= (bt->phase_seg2 - 1) << PCH_BIT_TSEG2_SHIFT;
+ bepe = ((bt->brp - 1) & PCH_MSK_BRPE_BRPE) >> PCH_BIT_BRPE_BRPE_SHIFT;
iowrite32(canbit, &priv->regs->bitt);
iowrite32(bepe, &priv->regs->brpe);
- pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_CCE);
+ pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_CCE);
return 0;
}
@@ -1008,8 +813,8 @@ static void pch_can_start(struct net_device *ndev)
pch_set_bittiming(ndev);
pch_can_set_optmode(priv);
- pch_can_tx_enable_all(priv);
- pch_can_rx_enable_all(priv);
+ pch_can_set_tx_all(priv, 1);
+ pch_can_set_rx_all(priv, 1);
/* Setting the CAN to run mode. */
pch_can_set_run_mode(priv, PCH_CAN_RUN);
@@ -1041,27 +846,18 @@ static int pch_can_open(struct net_device *ndev)
struct pch_can_priv *priv = netdev_priv(ndev);
int retval;
- retval = pci_enable_msi(priv->dev);
- if (retval) {
- dev_info(&ndev->dev, "PCH CAN opened without MSI\n");
- priv->use_msi = 0;
- } else {
- dev_info(&ndev->dev, "PCH CAN opened with MSI\n");
- priv->use_msi = 1;
- }
-
- /* Regsitering the interrupt. */
+ /* Regstering the interrupt. */
retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED,
ndev->name, ndev);
if (retval) {
- dev_err(&ndev->dev, "request_irq failed.\n");
+ netdev_err(ndev, "request_irq failed.\n");
goto req_irq_err;
}
/* Open common can device */
retval = open_candev(ndev);
if (retval) {
- dev_err(ndev->dev.parent, "open_candev() failed %d\n", retval);
+ netdev_err(ndev, "open_candev() failed %d\n", retval);
goto err_open_candev;
}
@@ -1075,9 +871,6 @@ static int pch_can_open(struct net_device *ndev)
err_open_candev:
free_irq(priv->dev->irq, ndev);
req_irq_err:
- if (priv->use_msi)
- pci_disable_msi(priv->dev);
-
pch_can_release(priv);
return retval;
@@ -1091,102 +884,65 @@ static int pch_close(struct net_device *ndev)
napi_disable(&priv->napi);
pch_can_release(priv);
free_irq(priv->dev->irq, ndev);
- if (priv->use_msi)
- pci_disable_msi(priv->dev);
close_candev(ndev);
priv->can.state = CAN_STATE_STOPPED;
return 0;
}
-static int pch_get_msg_obj_sts(struct net_device *ndev, u32 obj_id)
-{
- u32 buffer_status = 0;
- struct pch_can_priv *priv = netdev_priv(ndev);
-
- /* Getting the message object status. */
- buffer_status = (u32) pch_can_get_buffer_status(priv);
-
- return buffer_status & obj_id;
-}
-
-
static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- int i, j;
- unsigned long flags;
struct pch_can_priv *priv = netdev_priv(ndev);
struct can_frame *cf = (struct can_frame *)skb->data;
- int tx_buffer_avail = 0;
+ int tx_obj_no;
+ int i;
+ u32 id2;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
- if (priv->tx_obj == (PCH_OBJ_NUM + 1)) { /* Point tail Obj */
- while (pch_get_msg_obj_sts(ndev, (((1 << PCH_TX_OBJ_NUM)-1) <<
- PCH_RX_OBJ_NUM)))
- udelay(500);
+ tx_obj_no = priv->tx_obj;
+ if (priv->tx_obj == PCH_TX_OBJ_END) {
+ if (ioread32(&priv->regs->treq2) & PCH_TREQ2_TX_MASK)
+ netif_stop_queue(ndev);
- priv->tx_obj = PCH_RX_OBJ_NUM + 1; /* Point head of Tx Obj ID */
- tx_buffer_avail = priv->tx_obj; /* Point Tail of Tx Obj */
+ priv->tx_obj = PCH_TX_OBJ_START;
} else {
- tx_buffer_avail = priv->tx_obj;
+ priv->tx_obj++;
}
- priv->tx_obj++;
-
- /* Attaining the lock. */
- spin_lock_irqsave(&priv->msgif_reg_lock, flags);
-
- /* Reading the Msg Obj from the Msg RAM to the Interface register. */
- iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
- pch_can_check_if_busy(&priv->regs->if2_creq, tx_buffer_avail);
/* Setting the CMASK register. */
- pch_can_bit_set(&priv->regs->if2_cmask, CAN_CMASK_ALL);
+ pch_can_bit_set(&priv->regs->ifregs[1].cmask, PCH_CMASK_ALL);
/* If ID extended is set. */
- pch_can_bit_clear(&priv->regs->if2_id1, 0xffff);
- pch_can_bit_clear(&priv->regs->if2_id2, 0x1fff | CAN_ID2_XTD);
if (cf->can_id & CAN_EFF_FLAG) {
- pch_can_bit_set(&priv->regs->if2_id1, cf->can_id & 0xffff);
- pch_can_bit_set(&priv->regs->if2_id2,
- ((cf->can_id >> 16) & 0x1fff) | CAN_ID2_XTD);
+ iowrite32(cf->can_id & 0xffff, &priv->regs->ifregs[1].id1);
+ id2 = ((cf->can_id >> 16) & 0x1fff) | PCH_ID2_XTD;
} else {
- pch_can_bit_set(&priv->regs->if2_id1, 0);
- pch_can_bit_set(&priv->regs->if2_id2,
- (cf->can_id & CAN_SFF_MASK) << 2);
+ iowrite32(0, &priv->regs->ifregs[1].id1);
+ id2 = (cf->can_id & CAN_SFF_MASK) << 2;
}
- /* If remote frame has to be transmitted.. */
- if (cf->can_id & CAN_RTR_FLAG)
- pch_can_bit_clear(&priv->regs->if2_id2, CAN_ID2_DIR);
+ id2 |= PCH_ID_MSGVAL;
- for (i = 0, j = 0; i < cf->can_dlc; j++) {
- iowrite32(le32_to_cpu(cf->data[i++]),
- (&priv->regs->if2_dataa1) + j*4);
- if (i == cf->can_dlc)
- break;
- iowrite32(le32_to_cpu(cf->data[i++] << 8),
- (&priv->regs->if2_dataa1) + j*4);
- }
-
- can_put_echo_skb(skb, ndev, tx_buffer_avail - PCH_RX_OBJ_NUM - 1);
+ /* If remote frame has to be transmitted.. */
+ if (!(cf->can_id & CAN_RTR_FLAG))
+ id2 |= PCH_ID2_DIR;
- /* Updating the size of the data. */
- pch_can_bit_clear(&priv->regs->if2_mcont, 0x0f);
- pch_can_bit_set(&priv->regs->if2_mcont, cf->can_dlc);
+ iowrite32(id2, &priv->regs->ifregs[1].id2);
- /* Clearing IntPend, NewDat & TxRqst */
- pch_can_bit_clear(&priv->regs->if2_mcont,
- CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND |
- CAN_IF_MCONT_TXRQXT);
+ /* Copy data to register */
+ for (i = 0; i < cf->can_dlc; i += 2) {
+ iowrite16(cf->data[i] | (cf->data[i + 1] << 8),
+ &priv->regs->ifregs[1].data[i / 2]);
+ }
- /* Setting NewDat, TxRqst bits */
- pch_can_bit_set(&priv->regs->if2_mcont,
- CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_TXRQXT);
+ can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1);
- pch_can_check_if_busy(&priv->regs->if2_creq, tx_buffer_avail);
+ /* Set the size of the data. Update if2_mcont */
+ iowrite32(cf->can_dlc | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT |
+ PCH_IF_MCONT_TXIE, &priv->regs->ifregs[1].mcont);
- spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, tx_obj_no);
return NETDEV_TX_OK;
}
@@ -1203,21 +959,98 @@ static void __devexit pch_can_remove(struct pci_dev *pdev)
struct pch_can_priv *priv = netdev_priv(ndev);
unregister_candev(priv->ndev);
- free_candev(priv->ndev);
pci_iounmap(pdev, priv->regs);
+ if (priv->use_msi)
+ pci_disable_msi(priv->dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
pch_can_reset(priv);
+ free_candev(priv->ndev);
}
#ifdef CONFIG_PM
+static void pch_can_set_int_custom(struct pch_can_priv *priv)
+{
+ /* Clearing the IE, SIE and EIE bits of Can control register. */
+ pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
+
+ /* Appropriately setting them. */
+ pch_can_bit_set(&priv->regs->cont,
+ ((priv->int_enables & PCH_MSK_CTRL_IE_SIE_EIE) << 1));
+}
+
+/* This function retrieves interrupt enabled for the CAN device. */
+static u32 pch_can_get_int_enables(struct pch_can_priv *priv)
+{
+ /* Obtaining the status of IE, SIE and EIE interrupt bits. */
+ return (ioread32(&priv->regs->cont) & PCH_CTRL_IE_SIE_EIE) >> 1;
+}
+
+static u32 pch_can_get_rxtx_ir(struct pch_can_priv *priv, u32 buff_num,
+ enum pch_ifreg dir)
+{
+ u32 ie, enable;
+
+ if (dir)
+ ie = PCH_IF_MCONT_RXIE;
+ else
+ ie = PCH_IF_MCONT_TXIE;
+
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
+
+ if (((ioread32(&priv->regs->ifregs[dir].id2)) & PCH_ID_MSGVAL) &&
+ ((ioread32(&priv->regs->ifregs[dir].mcont)) & ie))
+ enable = 1;
+ else
+ enable = 0;
+
+ return enable;
+}
+
+static void pch_can_set_rx_buffer_link(struct pch_can_priv *priv,
+ u32 buffer_num, int set)
+{
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
+ iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL,
+ &priv->regs->ifregs[0].cmask);
+ if (set)
+ pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
+ PCH_IF_MCONT_EOB);
+ else
+ pch_can_bit_set(&priv->regs->ifregs[0].mcont, PCH_IF_MCONT_EOB);
+
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
+}
+
+static u32 pch_can_get_rx_buffer_link(struct pch_can_priv *priv, u32 buffer_num)
+{
+ u32 link;
+
+ iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
+ pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
+
+ if (ioread32(&priv->regs->ifregs[0].mcont) & PCH_IF_MCONT_EOB)
+ link = 0;
+ else
+ link = 1;
+ return link;
+}
+
+static int pch_can_get_buffer_status(struct pch_can_priv *priv)
+{
+ return (ioread32(&priv->regs->treq1) & 0xffff) |
+ (ioread32(&priv->regs->treq2) << 16);
+}
+
static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
{
- int i; /* Counter variable. */
- int retval; /* Return value. */
+ int i;
+ int retval;
u32 buf_stat; /* Variable for reading the transmit buffer status. */
- u32 counter = 0xFFFFFF;
+ int counter = PCH_COUNTER_LIMIT;
struct net_device *dev = pci_get_drvdata(pdev);
struct pch_can_priv *priv = netdev_priv(dev);
@@ -1226,7 +1059,7 @@ static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
pch_can_set_run_mode(priv, PCH_CAN_STOP);
/* Indicate that we are aboutto/in suspend */
- priv->can.state = CAN_STATE_SLEEPING;
+ priv->can.state = CAN_STATE_STOPPED;
/* Waiting for all transmission to complete. */
while (counter) {
@@ -1240,31 +1073,26 @@ static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
dev_err(&pdev->dev, "%s -> Transmission time out.\n", __func__);
/* Save interrupt configuration and then disable them */
- pch_can_get_int_enables(priv, &(priv->int_enables));
+ priv->int_enables = pch_can_get_int_enables(priv);
pch_can_set_int_enables(priv, PCH_CAN_DISABLE);
/* Save Tx buffer enable state */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_TX)
- pch_can_get_tx_enable(priv, i + 1,
- &(priv->tx_enable[i]));
- }
+ for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
+ priv->tx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i,
+ PCH_TX_IFREG);
/* Disable all Transmit buffers */
- pch_can_tx_disable_all(priv);
+ pch_can_set_tx_all(priv, 0);
/* Save Rx buffer enable state */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_RX) {
- pch_can_get_rx_enable(priv, i + 1,
- &(priv->rx_enable[i]));
- pch_can_get_rx_buffer_link(priv, i + 1,
- &(priv->rx_link[i]));
- }
+ for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
+ priv->rx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i,
+ PCH_RX_IFREG);
+ priv->rx_link[i - 1] = pch_can_get_rx_buffer_link(priv, i);
}
/* Disable all Receive buffers */
- pch_can_rx_disable_all(priv);
+ pch_can_set_rx_all(priv, 0);
retval = pci_save_state(pdev);
if (retval) {
dev_err(&pdev->dev, "pci_save_state failed.\n");
@@ -1279,8 +1107,8 @@ static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
static int pch_can_resume(struct pci_dev *pdev)
{
- int i; /* Counter variable. */
- int retval; /* Return variable. */
+ int i;
+ int retval;
struct net_device *dev = pci_get_drvdata(pdev);
struct pch_can_priv *priv = netdev_priv(dev);
@@ -1312,23 +1140,16 @@ static int pch_can_resume(struct pci_dev *pdev)
pch_can_set_optmode(priv);
/* Enabling the transmit buffer. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_TX) {
- pch_can_set_tx_enable(priv, i + 1,
- priv->tx_enable[i]);
- }
- }
+ for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
+ pch_can_set_rxtx(priv, i, priv->tx_enable[i - 1], PCH_TX_IFREG);
/* Configuring the receive buffer and enabling them. */
- for (i = 0; i < PCH_OBJ_NUM; i++) {
- if (priv->msg_obj[i] == MSG_OBJ_RX) {
- /* Restore buffer link */
- pch_can_set_rx_buffer_link(priv, i + 1,
- priv->rx_link[i]);
-
- /* Restore buffer enables */
- pch_can_set_rx_enable(priv, i + 1, priv->rx_enable[i]);
- }
+ for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
+ /* Restore buffer link */
+ pch_can_set_rx_buffer_link(priv, i, priv->rx_link[i - 1]);
+
+ /* Restore buffer enables */
+ pch_can_set_rxtx(priv, i, priv->rx_enable[i - 1], PCH_RX_IFREG);
}
/* Enable CAN Interrupts */
@@ -1348,9 +1169,10 @@ static int pch_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct pch_can_priv *priv = netdev_priv(dev);
+ u32 errc = ioread32(&priv->regs->errc);
- bec->txerr = ioread32(&priv->regs->errc) & CAN_TEC;
- bec->rxerr = (ioread32(&priv->regs->errc) & CAN_REC) >> 8;
+ bec->txerr = errc & PCH_TEC;
+ bec->rxerr = (errc & PCH_REC) >> 8;
return 0;
}
@@ -1361,7 +1183,6 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
struct net_device *ndev;
struct pch_can_priv *priv;
int rc;
- int index;
void __iomem *addr;
rc = pci_enable_device(pdev);
@@ -1383,7 +1204,7 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
goto probe_exit_ipmap;
}
- ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_NUM);
+ ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_END);
if (!ndev) {
rc = -ENOMEM;
dev_err(&pdev->dev, "Failed alloc_candev\n");
@@ -1399,7 +1220,7 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
priv->can.do_get_berr_counter = pch_can_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_LOOPBACK;
- priv->tx_obj = PCH_RX_OBJ_NUM + 1; /* Point head of Tx Obj */
+ priv->tx_obj = PCH_TX_OBJ_START; /* Point head of Tx Obj */
ndev->irq = pdev->irq;
ndev->flags |= IFF_ECHO;
@@ -1407,15 +1228,18 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->netdev_ops = &pch_can_netdev_ops;
-
priv->can.clock.freq = PCH_CAN_CLK; /* Hz */
- for (index = 0; index < PCH_RX_OBJ_NUM;)
- priv->msg_obj[index++] = MSG_OBJ_RX;
- for (index = index; index < PCH_OBJ_NUM;)
- priv->msg_obj[index++] = MSG_OBJ_TX;
+ netif_napi_add(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END);
- netif_napi_add(ndev, &priv->napi, pch_can_rx_poll, PCH_RX_OBJ_NUM);
+ rc = pci_enable_msi(priv->dev);
+ if (rc) {
+ netdev_err(ndev, "PCH CAN opened without MSI\n");
+ priv->use_msi = 0;
+ } else {
+ netdev_err(ndev, "PCH CAN opened with MSI\n");
+ priv->use_msi = 1;
+ }
rc = register_candev(ndev);
if (rc) {
@@ -1426,6 +1250,8 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
return 0;
probe_exit_reg_candev:
+ if (priv->use_msi)
+ pci_disable_msi(priv->dev);
free_candev(ndev);
probe_exit_alloc_candev:
pci_iounmap(pdev, addr);
@@ -1437,7 +1263,7 @@ probe_exit_endev:
return rc;
}
-static struct pci_driver pch_can_pcidev = {
+static struct pci_driver pch_can_pci_driver = {
.name = "pch_can",
.id_table = pch_pci_tbl,
.probe = pch_can_probe,
@@ -1448,16 +1274,16 @@ static struct pci_driver pch_can_pcidev = {
static int __init pch_can_pci_init(void)
{
- return pci_register_driver(&pch_can_pcidev);
+ return pci_register_driver(&pch_can_pci_driver);
}
module_init(pch_can_pci_init);
static void __exit pch_can_pci_exit(void)
{
- pci_unregister_driver(&pch_can_pcidev);
+ pci_unregister_driver(&pch_can_pci_driver);
}
module_exit(pch_can_pci_exit);
-MODULE_DESCRIPTION("Controller Area Network Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH CAN(Controller Area Network) Driver");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.94");
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 437b5c716a24..231385b8e08f 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -383,7 +383,7 @@ static void plx_pci_reset_marathon(struct pci_dev *pdev)
{
void __iomem *reset_addr;
int i;
- int reset_bar[2] = {3, 5};
+ static const int reset_bar[2] = {3, 5};
plx_pci_reset_common(pdev);
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index 5bfccfdf3bbb..09c3e9db9316 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -107,17 +107,13 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev,
res_size = resource_size(&res);
if (!request_mem_region(res.start, res_size, DRV_NAME)) {
- dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n",
- (unsigned long long)res.start,
- (unsigned long long)res.end);
+ dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
return -EBUSY;
}
base = ioremap_nocache(res.start, res_size);
if (!base) {
- dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n",
- (unsigned long long)res.start,
- (unsigned long long)res.end);
+ dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
err = -ENOMEM;
goto exit_release_mem;
}
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
new file mode 100644
index 000000000000..b423965a78d1
--- /dev/null
+++ b/drivers/net/can/slcan.c
@@ -0,0 +1,756 @@
+/*
+ * slcan.c - serial line CAN interface driver (using tty line discipline)
+ *
+ * This file is derived from linux/drivers/net/slip.c
+ *
+ * slip.c Authors : Laurence Culhane <loz@holmes.demon.co.uk>
+ * Fred N. van Kempen <waltje@uwalt.nl.mugnet.org>
+ * slcan.c Author : Oliver Hartkopp <socketcan@hartkopp.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307. You can also get it
+ * at http://www.gnu.org/licenses/gpl.html
+ *
+ * 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.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/can.h>
+
+static __initdata const char banner[] =
+ KERN_INFO "slcan: serial line CAN interface driver\n";
+
+MODULE_ALIAS_LDISC(N_SLCAN);
+MODULE_DESCRIPTION("serial line CAN interface");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
+
+#define SLCAN_MAGIC 0x53CA
+
+static int maxdev = 10; /* MAX number of SLCAN channels;
+ This can be overridden with
+ insmod slcan.ko maxdev=nnn */
+module_param(maxdev, int, 0);
+MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
+
+/* maximum rx buffer len: extended CAN frame with timestamp */
+#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
+
+struct slcan {
+ int magic;
+
+ /* Various fields. */
+ struct tty_struct *tty; /* ptr to TTY structure */
+ struct net_device *dev; /* easy for intr handling */
+ spinlock_t lock;
+
+ /* These are pointers to the malloc()ed frame buffers. */
+ unsigned char rbuff[SLC_MTU]; /* receiver buffer */
+ int rcount; /* received chars counter */
+ unsigned char xbuff[SLC_MTU]; /* transmitter buffer */
+ unsigned char *xhead; /* pointer to next XMIT byte */
+ int xleft; /* bytes left in XMIT queue */
+
+ unsigned long flags; /* Flag values/ mode etc */
+#define SLF_INUSE 0 /* Channel in use */
+#define SLF_ERROR 1 /* Parity, etc. error */
+
+ unsigned char leased;
+ dev_t line;
+ pid_t pid;
+};
+
+static struct net_device **slcan_devs;
+
+ /************************************************************************
+ * SLCAN ENCAPSULATION FORMAT *
+ ************************************************************************/
+
+/*
+ * A CAN frame has a can_id (11 bit standard frame format OR 29 bit extended
+ * frame format) a data length code (can_dlc) which can be from 0 to 8
+ * and up to <can_dlc> data bytes as payload.
+ * Additionally a CAN frame may become a remote transmission frame if the
+ * RTR-bit is set. This causes another ECU to send a CAN frame with the
+ * given can_id.
+ *
+ * The SLCAN ASCII representation of these different frame types is:
+ * <type> <id> <dlc> <data>*
+ *
+ * Extended frames (29 bit) are defined by capital characters in the type.
+ * RTR frames are defined as 'r' types - normal frames have 't' type:
+ * t => 11 bit data frame
+ * r => 11 bit RTR frame
+ * T => 29 bit data frame
+ * R => 29 bit RTR frame
+ *
+ * The <id> is 3 (standard) or 8 (extended) bytes in ASCII Hex (base64).
+ * The <dlc> is a one byte ASCII number ('0' - '8')
+ * The <data> section has at much ASCII Hex bytes as defined by the <dlc>
+ *
+ * Examples:
+ *
+ * t1230 : can_id 0x123, can_dlc 0, no data
+ * t4563112233 : can_id 0x456, can_dlc 3, data 0x11 0x22 0x33
+ * T12ABCDEF2AA55 : extended can_id 0x12ABCDEF, can_dlc 2, data 0xAA 0x55
+ * r1230 : can_id 0x123, can_dlc 0, no data, remote transmission request
+ *
+ */
+
+ /************************************************************************
+ * STANDARD SLCAN DECAPSULATION *
+ ************************************************************************/
+
+static int asc2nibble(char c)
+{
+
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+
+ return 16; /* error */
+}
+
+/* Send one completely decapsulated can_frame to the network layer */
+static void slc_bump(struct slcan *sl)
+{
+ struct sk_buff *skb;
+ struct can_frame cf;
+ int i, dlc_pos, tmp;
+ unsigned long ultmp;
+ char cmd = sl->rbuff[0];
+
+ if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+ return;
+
+ if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
+ dlc_pos = 4; /* dlc position tiiid */
+ else
+ dlc_pos = 9; /* dlc position Tiiiiiiiid */
+
+ if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+ return;
+
+ cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+
+ sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
+
+ if (strict_strtoul(sl->rbuff+1, 16, &ultmp))
+ return;
+
+ cf.can_id = ultmp;
+
+ if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
+ cf.can_id |= CAN_EFF_FLAG;
+
+ if ((cmd | 0x20) == 'r') /* RTR frame */
+ cf.can_id |= CAN_RTR_FLAG;
+
+ *(u64 *) (&cf.data) = 0; /* clear payload */
+
+ for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
+
+ tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+ if (tmp > 0x0F)
+ return;
+ cf.data[i] = (tmp << 4);
+ tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+ if (tmp > 0x0F)
+ return;
+ cf.data[i] |= tmp;
+ }
+
+
+ skb = dev_alloc_skb(sizeof(struct can_frame));
+ if (!skb)
+ return;
+
+ skb->dev = sl->dev;
+ skb->protocol = htons(ETH_P_CAN);
+ skb->pkt_type = PACKET_BROADCAST;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ memcpy(skb_put(skb, sizeof(struct can_frame)),
+ &cf, sizeof(struct can_frame));
+ netif_rx(skb);
+
+ sl->dev->stats.rx_packets++;
+ sl->dev->stats.rx_bytes += cf.can_dlc;
+}
+
+/* parse tty input stream */
+static void slcan_unesc(struct slcan *sl, unsigned char s)
+{
+
+ if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
+ (sl->rcount > 4)) {
+ slc_bump(sl);
+ }
+ sl->rcount = 0;
+ } else {
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < SLC_MTU) {
+ sl->rbuff[sl->rcount++] = s;
+ return;
+ } else {
+ sl->dev->stats.rx_over_errors++;
+ set_bit(SLF_ERROR, &sl->flags);
+ }
+ }
+ }
+}
+
+ /************************************************************************
+ * STANDARD SLCAN ENCAPSULATION *
+ ************************************************************************/
+
+/* Encapsulate one can_frame and stuff into a TTY queue. */
+static void slc_encaps(struct slcan *sl, struct can_frame *cf)
+{
+ int actual, idx, i;
+ char cmd;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ cmd = 'R'; /* becomes 'r' in standard frame format */
+ else
+ cmd = 'T'; /* becomes 't' in standard frame format */
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ sprintf(sl->xbuff, "%c%08X%d", cmd,
+ cf->can_id & CAN_EFF_MASK, cf->can_dlc);
+ else
+ sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
+ cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+
+ idx = strlen(sl->xbuff);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+
+ strcat(sl->xbuff, "\r"); /* add terminating character */
+
+ /* Order of next two lines is *very* important.
+ * When we are sending a little amount of data,
+ * the transfer may be completed inside the ops->write()
+ * routine, because it's running with interrupts enabled.
+ * In this case we *never* got WRITE_WAKEUP event,
+ * if we did not request it before write operation.
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+ set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
+ sl->xleft = strlen(sl->xbuff) - actual;
+ sl->xhead = sl->xbuff + actual;
+ sl->dev->stats.tx_bytes += cf->can_dlc;
+}
+
+/*
+ * Called by the driver when there's room for more data. If we have
+ * more packets to send, we send them here.
+ */
+static void slcan_write_wakeup(struct tty_struct *tty)
+{
+ int actual;
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+ return;
+
+ if (sl->xleft <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet */
+ sl->dev->stats.tx_packets++;
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ netif_wake_queue(sl->dev);
+ return;
+ }
+
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
+ sl->xleft -= actual;
+ sl->xhead += actual;
+}
+
+/* Send a can_frame to a TTY queue. */
+static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ if (skb->len != sizeof(struct can_frame))
+ goto out;
+
+ spin_lock(&sl->lock);
+ if (!netif_running(dev)) {
+ spin_unlock(&sl->lock);
+ printk(KERN_WARNING "%s: xmit: iface is down\n", dev->name);
+ goto out;
+ }
+ if (sl->tty == NULL) {
+ spin_unlock(&sl->lock);
+ goto out;
+ }
+
+ netif_stop_queue(sl->dev);
+ slc_encaps(sl, (struct can_frame *) skb->data); /* encaps & send */
+ spin_unlock(&sl->lock);
+
+out:
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+
+/******************************************
+ * Routines looking at netdevice side.
+ ******************************************/
+
+/* Netdevice UP -> DOWN routine */
+static int slc_close(struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ spin_lock_bh(&sl->lock);
+ if (sl->tty) {
+ /* TTY discipline is running. */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+ }
+ netif_stop_queue(dev);
+ sl->rcount = 0;
+ sl->xleft = 0;
+ spin_unlock_bh(&sl->lock);
+
+ return 0;
+}
+
+/* Netdevice DOWN -> UP routine */
+static int slc_open(struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ if (sl->tty == NULL)
+ return -ENODEV;
+
+ sl->flags &= (1 << SLF_INUSE);
+ netif_start_queue(dev);
+ return 0;
+}
+
+/* Hook the destructor so we can free slcan devs at the right point in time */
+static void slc_free_netdev(struct net_device *dev)
+{
+ int i = dev->base_addr;
+ free_netdev(dev);
+ slcan_devs[i] = NULL;
+}
+
+static const struct net_device_ops slc_netdev_ops = {
+ .ndo_open = slc_open,
+ .ndo_stop = slc_close,
+ .ndo_start_xmit = slc_xmit,
+};
+
+static void slc_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &slc_netdev_ops;
+ dev->destructor = slc_free_netdev;
+
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 10;
+
+ dev->mtu = sizeof(struct can_frame);
+ dev->type = ARPHRD_CAN;
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP;
+ dev->features = NETIF_F_NO_CSUM;
+}
+
+/******************************************
+ Routines looking at TTY side.
+ ******************************************/
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of SLCAN data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
+ */
+
+static void slcan_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+ return;
+
+ /* Read the characters out of the buffer */
+ while (count--) {
+ if (fp && *fp++) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags))
+ sl->dev->stats.rx_errors++;
+ cp++;
+ continue;
+ }
+ slcan_unesc(sl, *cp++);
+ }
+}
+
+/************************************
+ * slcan_open helper routines.
+ ************************************/
+
+/* Collect hanged up channels */
+static void slc_sync(void)
+{
+ int i;
+ struct net_device *dev;
+ struct slcan *sl;
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (dev == NULL)
+ break;
+
+ sl = netdev_priv(dev);
+ if (sl->tty || sl->leased)
+ continue;
+ if (dev->flags & IFF_UP)
+ dev_close(dev);
+ }
+}
+
+/* Find a free SLCAN channel, and link in this `tty' line. */
+static struct slcan *slc_alloc(dev_t line)
+{
+ int i;
+ struct net_device *dev = NULL;
+ struct slcan *sl;
+
+ if (slcan_devs == NULL)
+ return NULL; /* Master array missing ! */
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (dev == NULL)
+ break;
+
+ }
+
+ /* Sorry, too many, all slots in use */
+ if (i >= maxdev)
+ return NULL;
+
+ if (dev) {
+ sl = netdev_priv(dev);
+ if (test_bit(SLF_INUSE, &sl->flags)) {
+ unregister_netdevice(dev);
+ dev = NULL;
+ slcan_devs[i] = NULL;
+ }
+ }
+
+ if (!dev) {
+ char name[IFNAMSIZ];
+ sprintf(name, "slcan%d", i);
+
+ dev = alloc_netdev(sizeof(*sl), name, slc_setup);
+ if (!dev)
+ return NULL;
+ dev->base_addr = i;
+ }
+
+ sl = netdev_priv(dev);
+
+ /* Initialize channel control data */
+ sl->magic = SLCAN_MAGIC;
+ sl->dev = dev;
+ spin_lock_init(&sl->lock);
+ slcan_devs[i] = dev;
+
+ return sl;
+}
+
+/*
+ * Open the high-level part of the SLCAN channel.
+ * This function is called by the TTY module when the
+ * SLCAN line discipline is called for. Because we are
+ * sure the tty line exists, we only have to link it to
+ * a free SLCAN channel...
+ *
+ * Called in process context serialized from other ldisc calls.
+ */
+
+static int slcan_open(struct tty_struct *tty)
+{
+ struct slcan *sl;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
+ /* RTnetlink lock is misused here to serialize concurrent
+ opens of slcan channels. There are better ways, but it is
+ the simplest one.
+ */
+ rtnl_lock();
+
+ /* Collect hanged up channels. */
+ slc_sync();
+
+ sl = tty->disc_data;
+
+ err = -EEXIST;
+ /* First make sure we're not already connected. */
+ if (sl && sl->magic == SLCAN_MAGIC)
+ goto err_exit;
+
+ /* OK. Find a free SLCAN channel to use. */
+ err = -ENFILE;
+ sl = slc_alloc(tty_devnum(tty));
+ if (sl == NULL)
+ goto err_exit;
+
+ sl->tty = tty;
+ tty->disc_data = sl;
+ sl->line = tty_devnum(tty);
+ sl->pid = current->pid;
+
+ if (!test_bit(SLF_INUSE, &sl->flags)) {
+ /* Perform the low-level SLCAN initialization. */
+ sl->rcount = 0;
+ sl->xleft = 0;
+
+ set_bit(SLF_INUSE, &sl->flags);
+
+ err = register_netdevice(sl->dev);
+ if (err)
+ goto err_free_chan;
+ }
+
+ /* Done. We have linked the TTY line to a channel. */
+ rtnl_unlock();
+ tty->receive_room = 65536; /* We don't flow control */
+ return sl->dev->base_addr;
+
+err_free_chan:
+ sl->tty = NULL;
+ tty->disc_data = NULL;
+ clear_bit(SLF_INUSE, &sl->flags);
+
+err_exit:
+ rtnl_unlock();
+
+ /* Count references from TTY module */
+ return err;
+}
+
+/*
+ * Close down a SLCAN channel.
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
+ *
+ * We also use this method for a hangup event.
+ */
+
+static void slcan_close(struct tty_struct *tty)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty)
+ return;
+
+ tty->disc_data = NULL;
+ sl->tty = NULL;
+ if (!sl->leased)
+ sl->line = 0;
+
+ /* Flush network side */
+ unregister_netdev(sl->dev);
+ /* This will complete via sl_free_netdev */
+}
+
+static int slcan_hangup(struct tty_struct *tty)
+{
+ slcan_close(tty);
+ return 0;
+}
+
+/* Perform I/O control on an active SLCAN channel. */
+static int slcan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+ unsigned int tmp;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC)
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCGIFNAME:
+ tmp = strlen(sl->dev->name) + 1;
+ if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
+ return -EFAULT;
+ return 0;
+
+ case SIOCSIFHWADDR:
+ return -EINVAL;
+
+ default:
+ return tty_mode_ioctl(tty, file, cmd, arg);
+ }
+}
+
+static struct tty_ldisc_ops slc_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "slcan",
+ .open = slcan_open,
+ .close = slcan_close,
+ .hangup = slcan_hangup,
+ .ioctl = slcan_ioctl,
+ .receive_buf = slcan_receive_buf,
+ .write_wakeup = slcan_write_wakeup,
+};
+
+static int __init slcan_init(void)
+{
+ int status;
+
+ if (maxdev < 4)
+ maxdev = 4; /* Sanity */
+
+ printk(banner);
+ printk(KERN_INFO "slcan: %d dynamic interface channels.\n", maxdev);
+
+ slcan_devs = kzalloc(sizeof(struct net_device *)*maxdev, GFP_KERNEL);
+ if (!slcan_devs) {
+ printk(KERN_ERR "slcan: can't allocate slcan device array!\n");
+ return -ENOMEM;
+ }
+
+ /* Fill in our line protocol discipline, and register it */
+ status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
+ if (status) {
+ printk(KERN_ERR "slcan: can't register line discipline\n");
+ kfree(slcan_devs);
+ }
+ return status;
+}
+
+static void __exit slcan_exit(void)
+{
+ int i;
+ struct net_device *dev;
+ struct slcan *sl;
+ unsigned long timeout = jiffies + HZ;
+ int busy = 0;
+
+ if (slcan_devs == NULL)
+ return;
+
+ /* First of all: check for active disciplines and hangup them.
+ */
+ do {
+ if (busy)
+ msleep_interruptible(100);
+
+ busy = 0;
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (!dev)
+ continue;
+ sl = netdev_priv(dev);
+ spin_lock_bh(&sl->lock);
+ if (sl->tty) {
+ busy++;
+ tty_hangup(sl->tty);
+ }
+ spin_unlock_bh(&sl->lock);
+ }
+ } while (busy && time_before(jiffies, timeout));
+
+ /* FIXME: hangup is async so we should wait when doing this second
+ phase */
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (!dev)
+ continue;
+ slcan_devs[i] = NULL;
+
+ sl = netdev_priv(dev);
+ if (sl->tty) {
+ printk(KERN_ERR "%s: tty discipline still running\n",
+ dev->name);
+ /* Intentionally leak the control block. */
+ dev->destructor = NULL;
+ }
+
+ unregister_netdev(dev);
+ }
+
+ kfree(slcan_devs);
+ slcan_devs = NULL;
+
+ i = tty_unregister_ldisc(N_SLCAN);
+ if (i)
+ printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
+}
+
+module_init(slcan_init);
+module_exit(slcan_exit);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index d6b6d6aa565a..3437613f0454 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2788,7 +2788,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
ctrl = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const u64 csum_start_off = skb_transport_offset(skb);
+ const u64 csum_start_off = skb_checksum_start_offset(skb);
const u64 csum_stuff_off = csum_start_off + skb->csum_offset;
ctrl = TX_DESC_CSUM_EN |
@@ -3203,6 +3203,10 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
int phy_type = CAS_PHY_MII_MDIO0; /* default phy type */
int mac_off = 0;
+#if defined(CONFIG_SPARC)
+ const unsigned char *addr;
+#endif
+
/* give us access to the PROM */
writel(BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_PAD,
cp->regs + REG_BIM_LOCAL_DEV_EN);
@@ -3350,6 +3354,14 @@ use_random_mac_addr:
if (found & VPD_FOUND_MAC)
goto done;
+#if defined(CONFIG_SPARC)
+ addr = of_get_property(cp->of_node, "local-mac-address", NULL);
+ if (addr != NULL) {
+ memcpy(dev_addr, addr, 6);
+ goto done;
+ }
+#endif
+
/* Sun MAC prefix then 3 random bytes. */
pr_info("MAC address not found in ROM VPD\n");
dev_addr[0] = 0x08;
@@ -3880,7 +3892,7 @@ static int cas_change_mtu(struct net_device *dev, int new_mtu)
schedule_work(&cp->reset_task);
#endif
- flush_scheduled_work();
+ flush_work_sync(&cp->reset_task);
return 0;
}
@@ -5019,6 +5031,10 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
cassini_debug;
+#if defined(CONFIG_SPARC)
+ cp->of_node = pci_device_to_OF_node(pdev);
+#endif
+
cp->link_transition = LINK_TRANSITION_UNKNOWN;
cp->link_transition_jiffies_valid = 0;
@@ -5177,7 +5193,7 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
vfree(cp->fw_data);
mutex_lock(&cp->pm_mutex);
- flush_scheduled_work();
+ cancel_work_sync(&cp->reset_task);
if (cp->hw_running)
cas_shutdown(cp);
mutex_unlock(&cp->pm_mutex);
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index dbc47878d83b..faf4746a0f3e 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -2868,6 +2868,9 @@ struct cas {
dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS];
struct pci_dev *pdev;
struct net_device *dev;
+#if defined(CONFIG_OF)
+ struct device_node *of_node;
+#endif
/* Firmware Info */
u16 fw_load_addr;
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 4c6028512d10..a683fd3bb624 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -22,7 +22,7 @@ static int my3126_interrupt_enable(struct cphy *cphy)
static int my3126_interrupt_disable(struct cphy *cphy)
{
- cancel_rearming_delayed_work(&cphy->phy_update);
+ cancel_delayed_work_sync(&cphy->phy_update);
return 0;
}
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 70221ca32683..f778b15ad3fd 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -273,6 +273,10 @@ struct sge {
struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp;
};
+static const u8 ch_mac_addr[ETH_ALEN] = {
+ 0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+};
+
/*
* stop tasklet and free all pending skb's
*/
@@ -2012,10 +2016,6 @@ static void espibug_workaround_t204(unsigned long data)
continue;
if (!skb->cb[0]) {
- u8 ch_mac_addr[ETH_ALEN] = {
- 0x0, 0x7, 0x43, 0x0, 0x0, 0x0
- };
-
skb_copy_to_linear_data_offset(skb,
sizeof(struct cpl_tx_pkt),
ch_mac_addr,
@@ -2048,8 +2048,6 @@ static void espibug_workaround(unsigned long data)
if ((seop & 0xfff0fff) == 0xfff && skb) {
if (!skb->cb[0]) {
- u8 ch_mac_addr[ETH_ALEN] =
- {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
skb_copy_to_linear_data_offset(skb,
sizeof(struct cpl_tx_pkt),
ch_mac_addr,
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 63ebf76d2390..8a43c7e19701 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -556,7 +556,7 @@ struct chelsio_vpd_t {
#define EEPROM_MAX_POLL 4
/*
- * Read SEEPROM. A zero is written to the flag register when the addres is
+ * Read SEEPROM. A zero is written to the flag register when the address is
* written to the Control register. The hardware device will set the flag to a
* one when 4B have been transferred to the Data register.
*/
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 92bac19ad60a..263a2944566f 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -59,6 +59,7 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(CNIC_MODULE_VERSION);
+/* cnic_dev_list modifications are protected by both rtnl and cnic_dev_lock */
static LIST_HEAD(cnic_dev_list);
static LIST_HEAD(cnic_udev_list);
static DEFINE_RWLOCK(cnic_dev_lock);
@@ -278,6 +279,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
u32 msg_type = ISCSI_KEVENT_IF_DOWN;
struct cnic_ulp_ops *ulp_ops;
struct cnic_uio_dev *udev = cp->udev;
+ int rc = 0, retry = 0;
if (!udev || udev->uio_dev == -1)
return -ENODEV;
@@ -302,14 +304,26 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
path_req.pmtu = csk->mtu;
}
- rcu_read_lock();
- ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
- if (ulp_ops)
- ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len);
- rcu_read_unlock();
+ while (retry < 3) {
+ rc = 0;
+ rcu_read_lock();
+ ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
+ if (ulp_ops)
+ rc = ulp_ops->iscsi_nl_send_msg(
+ cp->ulp_handle[CNIC_ULP_ISCSI],
+ msg_type, buf, len);
+ rcu_read_unlock();
+ if (rc == 0 || msg_type != ISCSI_KEVENT_PATH_REQ)
+ break;
+
+ msleep(100);
+ retry++;
+ }
return 0;
}
+static void cnic_cm_upcall(struct cnic_local *, struct cnic_sock *, u8);
+
static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
char *buf, u16 len)
{
@@ -339,7 +353,9 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
}
csk = &cp->csk_tbl[l5_cid];
csk_hold(csk);
- if (cnic_in_use(csk)) {
+ if (cnic_in_use(csk) &&
+ test_bit(SK_F_CONNECT_START, &csk->flags)) {
+
memcpy(csk->ha, path_resp->mac_addr, 6);
if (test_bit(SK_F_IPV6, &csk->flags))
memcpy(&csk->src_ip[0], &path_resp->src.v6_addr,
@@ -347,8 +363,16 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
else
memcpy(&csk->src_ip[0], &path_resp->src.v4_addr,
sizeof(struct in_addr));
- if (is_valid_ether_addr(csk->ha))
+
+ if (is_valid_ether_addr(csk->ha)) {
cnic_cm_set_pg(csk);
+ } else if (!test_bit(SK_F_OFFLD_SCHED, &csk->flags) &&
+ !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+
+ cnic_cm_upcall(cp, csk,
+ L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE);
+ clear_bit(SK_F_CONNECT_START, &csk->flags);
+ }
}
csk_put(csk);
rcu_read_unlock();
@@ -402,19 +426,6 @@ static int cnic_abort_prep(struct cnic_sock *csk)
return 0;
}
-static void cnic_uio_stop(void)
-{
- struct cnic_dev *dev;
-
- read_lock(&cnic_dev_lock);
- list_for_each_entry(dev, &cnic_dev_list, list) {
- struct cnic_local *cp = dev->cnic_priv;
-
- cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
- }
- read_unlock(&cnic_dev_lock);
-}
-
int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
{
struct cnic_dev *dev;
@@ -445,14 +456,12 @@ int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
/* Prevent race conditions with netdev_event */
rtnl_lock();
- read_lock(&cnic_dev_lock);
list_for_each_entry(dev, &cnic_dev_list, list) {
struct cnic_local *cp = dev->cnic_priv;
if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]))
ulp_ops->cnic_init(dev);
}
- read_unlock(&cnic_dev_lock);
rtnl_unlock();
return 0;
@@ -488,9 +497,6 @@ int cnic_unregister_driver(int ulp_type)
}
read_unlock(&cnic_dev_lock);
- if (ulp_type == CNIC_ULP_ISCSI)
- cnic_uio_stop();
-
rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
mutex_unlock(&cnic_lock);
@@ -574,6 +580,9 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
}
mutex_unlock(&cnic_lock);
+ if (ulp_type == CNIC_ULP_ISCSI)
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+
synchronize_rcu();
while (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]) &&
@@ -821,12 +830,14 @@ static void cnic_free_resc(struct cnic_dev *dev)
cnic_free_dma(dev, &cp->conn_buf_info);
cnic_free_dma(dev, &cp->kwq_info);
cnic_free_dma(dev, &cp->kwq_16_data_info);
+ cnic_free_dma(dev, &cp->kcq2.dma);
cnic_free_dma(dev, &cp->kcq1.dma);
kfree(cp->iscsi_tbl);
cp->iscsi_tbl = NULL;
kfree(cp->ctx_tbl);
cp->ctx_tbl = NULL;
+ cnic_free_id_tbl(&cp->fcoe_cid_tbl);
cnic_free_id_tbl(&cp->cid_tbl);
}
@@ -940,7 +951,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
&udev->l2_ring_map,
GFP_KERNEL | __GFP_COMP);
if (!udev->l2_ring)
- return -ENOMEM;
+ goto err_udev;
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
@@ -948,7 +959,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
&udev->l2_buf_map,
GFP_KERNEL | __GFP_COMP);
if (!udev->l2_buf)
- return -ENOMEM;
+ goto err_dma;
write_lock(&cnic_dev_lock);
list_add(&udev->list, &cnic_udev_list);
@@ -959,6 +970,12 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
cp->udev = udev;
return 0;
+ err_dma:
+ dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size,
+ udev->l2_ring, udev->l2_ring_map);
+ err_udev:
+ kfree(udev);
+ return -ENOMEM;
}
static int cnic_init_uio(struct cnic_dev *dev)
@@ -1114,12 +1131,22 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
cp->iro_arr = ethdev->iro_arr;
- cp->max_cid_space = MAX_ISCSI_TBL_SZ;
+ cp->max_cid_space = MAX_ISCSI_TBL_SZ + BNX2X_FCOE_NUM_CONNECTIONS;
cp->iscsi_start_cid = start_cid;
+ cp->fcoe_start_cid = start_cid + MAX_ISCSI_TBL_SZ;
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ cp->max_cid_space += BNX2X_FCOE_NUM_CONNECTIONS;
+ cp->fcoe_init_cid = ethdev->fcoe_init_cid;
+ if (!cp->fcoe_init_cid)
+ cp->fcoe_init_cid = 0x10;
+ }
+
if (start_cid < BNX2X_ISCSI_START_CID) {
u32 delta = BNX2X_ISCSI_START_CID - start_cid;
cp->iscsi_start_cid = BNX2X_ISCSI_START_CID;
+ cp->fcoe_start_cid += delta;
cp->max_cid_space += delta;
}
@@ -1138,6 +1165,9 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI;
}
+ for (i = MAX_ISCSI_TBL_SZ; i < cp->max_cid_space; i++)
+ cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_FCOE;
+
pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
PAGE_SIZE;
@@ -1161,6 +1191,12 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
if (ret)
goto error;
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ ret = cnic_alloc_kcq(dev, &cp->kcq2);
+ if (ret)
+ goto error;
+ }
+
pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
ret = cnic_alloc_dma(dev, &cp->conn_buf_info, pages, 1);
@@ -1254,12 +1290,18 @@ static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid,
struct cnic_local *cp = dev->cnic_priv;
struct l5cm_spe kwqe;
struct kwqe_16 *kwq[1];
+ u16 type_16;
int ret;
kwqe.hdr.conn_and_cmd_data =
cpu_to_le32(((cmd << SPE_HDR_CMD_ID_SHIFT) |
BNX2X_HW_CID(cp, cid)));
- kwqe.hdr.type = cpu_to_le16(type);
+
+ type_16 = (type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE;
+ type_16 |= (cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID;
+
+ kwqe.hdr.type = cpu_to_le16(type_16);
kwqe.hdr.reserved1 = 0;
kwqe.data.phy_address.lo = cpu_to_le32(l5_data->phy_address.lo);
kwqe.data.phy_address.hi = cpu_to_le32(l5_data->phy_address.hi);
@@ -1425,8 +1467,11 @@ static void cnic_free_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
cnic_free_dma(dev, &iscsi->hq_info);
cnic_free_dma(dev, &iscsi->r2tq_info);
cnic_free_dma(dev, &iscsi->task_array_info);
+ cnic_free_id(&cp->cid_tbl, ctx->cid);
+ } else {
+ cnic_free_id(&cp->fcoe_cid_tbl, ctx->cid);
}
- cnic_free_id(&cp->cid_tbl, ctx->cid);
+
ctx->cid = 0;
}
@@ -1438,6 +1483,16 @@ static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+ if (ctx->ulp_proto_id == CNIC_ULP_FCOE) {
+ cid = cnic_alloc_new_id(&cp->fcoe_cid_tbl);
+ if (cid == -1) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ ctx->cid = cid;
+ return 0;
+ }
+
cid = cnic_alloc_new_id(&cp->cid_tbl);
if (cid == -1) {
ret = -ENOMEM;
@@ -1695,7 +1750,7 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
*work = num;
return -EINVAL;
}
- *work = 2 + req2->num_additional_wqes;;
+ *work = 2 + req2->num_additional_wqes;
l5_cid = req1->iscsi_conn_id;
if (l5_cid >= MAX_ISCSI_TBL_SZ)
@@ -1770,19 +1825,15 @@ static int cnic_bnx2x_destroy_ramrod(struct cnic_dev *dev, u32 l5_cid)
struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
union l5cm_specific_data l5_data;
int ret;
- u32 hw_cid, type;
+ u32 hw_cid;
init_waitqueue_head(&ctx->waitq);
ctx->wait_cond = 0;
memset(&l5_data, 0, sizeof(l5_data));
hw_cid = BNX2X_HW_CID(cp, ctx->cid);
- type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
- & SPE_HDR_CONN_TYPE;
- type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
- SPE_HDR_FUNCTION_ID);
ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL,
- hw_cid, type, &l5_data);
+ hw_cid, NONE_CONNECTION_TYPE, &l5_data);
if (ret == 0)
wait_event(ctx->waitq, ctx->wait_cond);
@@ -2078,8 +2129,306 @@ static int cnic_bnx2x_update_pg(struct cnic_dev *dev, struct kwqe *kwqe)
return 0;
}
-static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
- u32 num_wqes)
+static int cnic_bnx2x_fcoe_stat(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct fcoe_kwqe_stat *req;
+ struct fcoe_stat_ramrod_params *fcoe_stat;
+ union l5cm_specific_data l5_data;
+ struct cnic_local *cp = dev->cnic_priv;
+ int ret;
+ u32 cid;
+
+ req = (struct fcoe_kwqe_stat *) kwqe;
+ cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
+
+ fcoe_stat = cnic_get_kwqe_16_data(cp, BNX2X_FCOE_L5_CID_BASE, &l5_data);
+ if (!fcoe_stat)
+ return -ENOMEM;
+
+ memset(fcoe_stat, 0, sizeof(*fcoe_stat));
+ memcpy(&fcoe_stat->stat_kwqe, req, sizeof(*req));
+
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_STAT, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_init1(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ int ret;
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 cid;
+ struct fcoe_init_ramrod_params *fcoe_init;
+ struct fcoe_kwqe_init1 *req1;
+ struct fcoe_kwqe_init2 *req2;
+ struct fcoe_kwqe_init3 *req3;
+ union l5cm_specific_data l5_data;
+
+ if (num < 3) {
+ *work = num;
+ return -EINVAL;
+ }
+ req1 = (struct fcoe_kwqe_init1 *) wqes[0];
+ req2 = (struct fcoe_kwqe_init2 *) wqes[1];
+ req3 = (struct fcoe_kwqe_init3 *) wqes[2];
+ if (req2->hdr.op_code != FCOE_KWQE_OPCODE_INIT2) {
+ *work = 1;
+ return -EINVAL;
+ }
+ if (req3->hdr.op_code != FCOE_KWQE_OPCODE_INIT3) {
+ *work = 2;
+ return -EINVAL;
+ }
+
+ if (sizeof(*fcoe_init) > CNIC_KWQ16_DATA_SIZE) {
+ netdev_err(dev->netdev, "fcoe_init size too big\n");
+ return -ENOMEM;
+ }
+ fcoe_init = cnic_get_kwqe_16_data(cp, BNX2X_FCOE_L5_CID_BASE, &l5_data);
+ if (!fcoe_init)
+ return -ENOMEM;
+
+ memset(fcoe_init, 0, sizeof(*fcoe_init));
+ memcpy(&fcoe_init->init_kwqe1, req1, sizeof(*req1));
+ memcpy(&fcoe_init->init_kwqe2, req2, sizeof(*req2));
+ memcpy(&fcoe_init->init_kwqe3, req3, sizeof(*req3));
+ fcoe_init->eq_addr.lo = cp->kcq2.dma.pg_map_arr[0] & 0xffffffff;
+ fcoe_init->eq_addr.hi = (u64) cp->kcq2.dma.pg_map_arr[0] >> 32;
+ fcoe_init->eq_next_page_addr.lo =
+ cp->kcq2.dma.pg_map_arr[1] & 0xffffffff;
+ fcoe_init->eq_next_page_addr.hi =
+ (u64) cp->kcq2.dma.pg_map_arr[1] >> 32;
+
+ fcoe_init->sb_num = cp->status_blk_num;
+ fcoe_init->eq_prod = MAX_KCQ_IDX;
+ fcoe_init->sb_id = HC_INDEX_FCOE_EQ_CONS;
+ cp->kcq2.sw_prod_idx = 0;
+
+ cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_INIT, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ *work = 3;
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ int ret = 0;
+ u32 cid = -1, l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct fcoe_kwqe_conn_offload1 *req1;
+ struct fcoe_kwqe_conn_offload2 *req2;
+ struct fcoe_kwqe_conn_offload3 *req3;
+ struct fcoe_kwqe_conn_offload4 *req4;
+ struct fcoe_conn_offload_ramrod_params *fcoe_offload;
+ struct cnic_context *ctx;
+ struct fcoe_context *fctx;
+ struct regpair ctx_addr;
+ union l5cm_specific_data l5_data;
+ struct fcoe_kcqe kcqe;
+ struct kcqe *cqes[1];
+
+ if (num < 4) {
+ *work = num;
+ return -EINVAL;
+ }
+ req1 = (struct fcoe_kwqe_conn_offload1 *) wqes[0];
+ req2 = (struct fcoe_kwqe_conn_offload2 *) wqes[1];
+ req3 = (struct fcoe_kwqe_conn_offload3 *) wqes[2];
+ req4 = (struct fcoe_kwqe_conn_offload4 *) wqes[3];
+
+ *work = 4;
+
+ l5_cid = req1->fcoe_conn_id;
+ if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ goto err_reply;
+
+ l5_cid += BNX2X_FCOE_L5_CID_BASE;
+
+ ctx = &cp->ctx_tbl[l5_cid];
+ if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
+ goto err_reply;
+
+ ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid);
+ if (ret) {
+ ret = 0;
+ goto err_reply;
+ }
+ cid = ctx->cid;
+
+ fctx = cnic_get_bnx2x_ctx(dev, cid, 1, &ctx_addr);
+ if (fctx) {
+ u32 hw_cid = BNX2X_HW_CID(cp, cid);
+ u32 val;
+
+ val = CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_XCM_AG,
+ FCOE_CONNECTION_TYPE);
+ fctx->xstorm_ag_context.cdu_reserved = val;
+ val = CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_UCM_AG,
+ FCOE_CONNECTION_TYPE);
+ fctx->ustorm_ag_context.cdu_usage = val;
+ }
+ if (sizeof(*fcoe_offload) > CNIC_KWQ16_DATA_SIZE) {
+ netdev_err(dev->netdev, "fcoe_offload size too big\n");
+ goto err_reply;
+ }
+ fcoe_offload = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!fcoe_offload)
+ goto err_reply;
+
+ memset(fcoe_offload, 0, sizeof(*fcoe_offload));
+ memcpy(&fcoe_offload->offload_kwqe1, req1, sizeof(*req1));
+ memcpy(&fcoe_offload->offload_kwqe2, req2, sizeof(*req2));
+ memcpy(&fcoe_offload->offload_kwqe3, req3, sizeof(*req3));
+ memcpy(&fcoe_offload->offload_kwqe4, req4, sizeof(*req4));
+
+ cid = BNX2X_HW_CID(cp, cid);
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_OFFLOAD_CONN, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ if (!ret)
+ set_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+
+ return ret;
+
+err_reply:
+ if (cid != -1)
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = FCOE_KCQE_OPCODE_OFFLOAD_CONN;
+ kcqe.fcoe_conn_id = req1->fcoe_conn_id;
+ kcqe.completion_status = FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE;
+
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_FCOE, cqes, 1);
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_enable(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct fcoe_kwqe_conn_enable_disable *req;
+ struct fcoe_conn_enable_disable_ramrod_params *fcoe_enable;
+ union l5cm_specific_data l5_data;
+ int ret;
+ u32 cid, l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ req = (struct fcoe_kwqe_conn_enable_disable *) kwqe;
+ cid = req->context_id;
+ l5_cid = req->conn_id + BNX2X_FCOE_L5_CID_BASE;
+
+ if (sizeof(*fcoe_enable) > CNIC_KWQ16_DATA_SIZE) {
+ netdev_err(dev->netdev, "fcoe_enable size too big\n");
+ return -ENOMEM;
+ }
+ fcoe_enable = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!fcoe_enable)
+ return -ENOMEM;
+
+ memset(fcoe_enable, 0, sizeof(*fcoe_enable));
+ memcpy(&fcoe_enable->enable_disable_kwqe, req, sizeof(*req));
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_ENABLE_CONN, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_disable(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct fcoe_kwqe_conn_enable_disable *req;
+ struct fcoe_conn_enable_disable_ramrod_params *fcoe_disable;
+ union l5cm_specific_data l5_data;
+ int ret;
+ u32 cid, l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ req = (struct fcoe_kwqe_conn_enable_disable *) kwqe;
+ cid = req->context_id;
+ l5_cid = req->conn_id;
+ if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ return -EINVAL;
+
+ l5_cid += BNX2X_FCOE_L5_CID_BASE;
+
+ if (sizeof(*fcoe_disable) > CNIC_KWQ16_DATA_SIZE) {
+ netdev_err(dev->netdev, "fcoe_disable size too big\n");
+ return -ENOMEM;
+ }
+ fcoe_disable = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!fcoe_disable)
+ return -ENOMEM;
+
+ memset(fcoe_disable, 0, sizeof(*fcoe_disable));
+ memcpy(&fcoe_disable->enable_disable_kwqe, req, sizeof(*req));
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_DISABLE_CONN, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct fcoe_kwqe_conn_destroy *req;
+ union l5cm_specific_data l5_data;
+ int ret;
+ u32 cid, l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx;
+ struct fcoe_kcqe kcqe;
+ struct kcqe *cqes[1];
+
+ req = (struct fcoe_kwqe_conn_destroy *) kwqe;
+ cid = req->context_id;
+ l5_cid = req->conn_id;
+ if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ return -EINVAL;
+
+ l5_cid += BNX2X_FCOE_L5_CID_BASE;
+
+ ctx = &cp->ctx_tbl[l5_cid];
+
+ init_waitqueue_head(&ctx->waitq);
+ ctx->wait_cond = 0;
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_TERMINATE_CONN, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ if (ret == 0) {
+ wait_event(ctx->waitq, ctx->wait_cond);
+ set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags);
+ queue_delayed_work(cnic_wq, &cp->delete_task,
+ msecs_to_jiffies(2000));
+ }
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_CONN;
+ kcqe.fcoe_conn_id = req->conn_id;
+ kcqe.fcoe_conn_context_id = cid;
+
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_FCOE, cqes, 1);
+ return ret;
+}
+
+static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct fcoe_kwqe_destroy *req;
+ union l5cm_specific_data l5_data;
+ struct cnic_local *cp = dev->cnic_priv;
+ int ret;
+ u32 cid;
+
+ req = (struct fcoe_kwqe_destroy *) kwqe;
+ cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_DESTROY, cid,
+ FCOE_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_submit_bnx2x_iscsi_kwqes(struct cnic_dev *dev,
+ struct kwqe *wqes[], u32 num_wqes)
{
int i, work, ret;
u32 opcode;
@@ -2143,6 +2492,98 @@ static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
return 0;
}
+static int cnic_submit_bnx2x_fcoe_kwqes(struct cnic_dev *dev,
+ struct kwqe *wqes[], u32 num_wqes)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i, work, ret;
+ u32 opcode;
+ struct kwqe *kwqe;
+
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EAGAIN; /* bnx2 is down */
+
+ if (BNX2X_CHIP_NUM(cp->chip_id) == BNX2X_CHIP_NUM_57710)
+ return -EINVAL;
+
+ for (i = 0; i < num_wqes; ) {
+ kwqe = wqes[i];
+ opcode = KWQE_OPCODE(kwqe->kwqe_op_flag);
+ work = 1;
+
+ switch (opcode) {
+ case FCOE_KWQE_OPCODE_INIT1:
+ ret = cnic_bnx2x_fcoe_init1(dev, &wqes[i],
+ num_wqes - i, &work);
+ break;
+ case FCOE_KWQE_OPCODE_OFFLOAD_CONN1:
+ ret = cnic_bnx2x_fcoe_ofld1(dev, &wqes[i],
+ num_wqes - i, &work);
+ break;
+ case FCOE_KWQE_OPCODE_ENABLE_CONN:
+ ret = cnic_bnx2x_fcoe_enable(dev, kwqe);
+ break;
+ case FCOE_KWQE_OPCODE_DISABLE_CONN:
+ ret = cnic_bnx2x_fcoe_disable(dev, kwqe);
+ break;
+ case FCOE_KWQE_OPCODE_DESTROY_CONN:
+ ret = cnic_bnx2x_fcoe_destroy(dev, kwqe);
+ break;
+ case FCOE_KWQE_OPCODE_DESTROY:
+ ret = cnic_bnx2x_fcoe_fw_destroy(dev, kwqe);
+ break;
+ case FCOE_KWQE_OPCODE_STAT:
+ ret = cnic_bnx2x_fcoe_stat(dev, kwqe);
+ break;
+ default:
+ ret = 0;
+ netdev_err(dev->netdev, "Unknown type of KWQE(0x%x)\n",
+ opcode);
+ break;
+ }
+ if (ret < 0)
+ netdev_err(dev->netdev, "KWQE(0x%x) failed\n",
+ opcode);
+ i += work;
+ }
+ return 0;
+}
+
+static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num_wqes)
+{
+ int ret = -EINVAL;
+ u32 layer_code;
+
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EAGAIN; /* bnx2x is down */
+
+ if (!num_wqes)
+ return 0;
+
+ layer_code = wqes[0]->kwqe_op_flag & KWQE_LAYER_MASK;
+ switch (layer_code) {
+ case KWQE_FLAGS_LAYER_MASK_L5_ISCSI:
+ case KWQE_FLAGS_LAYER_MASK_L4:
+ case KWQE_FLAGS_LAYER_MASK_L2:
+ ret = cnic_submit_bnx2x_iscsi_kwqes(dev, wqes, num_wqes);
+ break;
+
+ case KWQE_FLAGS_LAYER_MASK_L5_FCOE:
+ ret = cnic_submit_bnx2x_fcoe_kwqes(dev, wqes, num_wqes);
+ break;
+ }
+ return ret;
+}
+
+static inline u32 cnic_get_kcqe_layer_mask(u32 opflag)
+{
+ if (unlikely(KCQE_OPCODE(opflag) == FCOE_RAMROD_CMD_ID_TERMINATE_CONN))
+ return KCQE_FLAGS_LAYER_MASK_L4;
+
+ return opflag & KCQE_FLAGS_LAYER_MASK;
+}
+
static void service_kcqes(struct cnic_dev *dev, int num_cqes)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -2154,7 +2595,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
struct cnic_ulp_ops *ulp_ops;
int ulp_type;
u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag;
- u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK;
+ u32 kcqe_layer = cnic_get_kcqe_layer_mask(kcqe_op_flag);
if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION))
comp++;
@@ -2162,7 +2603,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
while (j < num_cqes) {
u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag;
- if ((next_op & KCQE_FLAGS_LAYER_MASK) != kcqe_layer)
+ if (cnic_get_kcqe_layer_mask(next_op) != kcqe_layer)
break;
if (unlikely(next_op & KCQE_RAMROD_COMPLETION))
@@ -2174,6 +2615,8 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
ulp_type = CNIC_ULP_RDMA;
else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_ISCSI)
ulp_type = CNIC_ULP_ISCSI;
+ else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_FCOE)
+ ulp_type = CNIC_ULP_FCOE;
else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L4)
ulp_type = CNIC_ULP_L4;
else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L2)
@@ -2342,11 +2785,12 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
static int cnic_service_bnx2(void *data, void *status_blk)
{
struct cnic_dev *dev = data;
- struct cnic_local *cp = dev->cnic_priv;
- u32 status_idx = *cp->kcq1.status_idx_ptr;
- if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
- return status_idx;
+ if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+ struct status_block *sblk = status_blk;
+
+ return sblk->status_idx;
+ }
return cnic_service_bnx2_queues(dev);
}
@@ -2365,9 +2809,10 @@ static void cnic_service_bnx2_msix(unsigned long data)
static void cnic_doirq(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- u16 prod = cp->kcq1.sw_prod_idx & MAX_KCQ_IDX;
if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+ u16 prod = cp->kcq1.sw_prod_idx & MAX_KCQ_IDX;
+
prefetch(cp->status_blk.gen);
prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
@@ -2469,12 +2914,19 @@ static void cnic_service_bnx2x_bh(unsigned long data)
status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
- if (BNX2X_CHIP_IS_E2(cp->chip_id))
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+
+ CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx +
+ MAX_KCQ_IDX);
+
cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
status_idx, IGU_INT_ENABLE, 1);
- else
+ } else {
cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
status_idx, IGU_INT_ENABLE, 1);
+ }
}
static int cnic_service_bnx2x(void *data, void *status_blk)
@@ -2883,7 +3335,7 @@ static void cnic_cm_cleanup(struct cnic_sock *csk)
struct cnic_dev *dev = csk->dev;
struct cnic_local *cp = dev->cnic_priv;
- cnic_free_id(&cp->csk_port_tbl, csk->src_port);
+ cnic_free_id(&cp->csk_port_tbl, be16_to_cpu(csk->src_port));
csk->src_port = 0;
}
}
@@ -3014,7 +3466,8 @@ static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
int is_v6, rc = 0;
struct dst_entry *dst = NULL;
struct net_device *realdev;
- u32 local_port;
+ __be16 local_port;
+ u32 port_id;
if (saddr->local.v6.sin6_family == AF_INET6 &&
saddr->remote.v6.sin6_family == AF_INET6)
@@ -3054,19 +3507,21 @@ static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
}
}
- if (local_port >= CNIC_LOCAL_PORT_MIN &&
- local_port < CNIC_LOCAL_PORT_MAX) {
- if (cnic_alloc_id(&cp->csk_port_tbl, local_port))
- local_port = 0;
+ port_id = be16_to_cpu(local_port);
+ if (port_id >= CNIC_LOCAL_PORT_MIN &&
+ port_id < CNIC_LOCAL_PORT_MAX) {
+ if (cnic_alloc_id(&cp->csk_port_tbl, port_id))
+ port_id = 0;
} else
- local_port = 0;
+ port_id = 0;
- if (!local_port) {
- local_port = cnic_alloc_new_id(&cp->csk_port_tbl);
- if (local_port == -1) {
+ if (!port_id) {
+ port_id = cnic_alloc_new_id(&cp->csk_port_tbl);
+ if (port_id == -1) {
rc = -ENOMEM;
goto err_out;
}
+ local_port = cpu_to_be16(port_id);
}
csk->src_port = local_port;
@@ -3208,6 +3663,18 @@ done:
csk_put(csk);
}
+static void cnic_process_fcoe_term_conn(struct cnic_dev *dev, struct kcqe *kcqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct fcoe_kcqe *fc_kcqe = (struct fcoe_kcqe *) kcqe;
+ u32 l5_cid = fc_kcqe->fcoe_conn_id + BNX2X_FCOE_L5_CID_BASE;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ ctx->timestamp = jiffies;
+ ctx->wait_cond = 1;
+ wake_up(&ctx->waitq);
+}
+
static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -3216,6 +3683,10 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
u32 l5_cid;
struct cnic_sock *csk;
+ if (opcode == FCOE_RAMROD_CMD_ID_TERMINATE_CONN) {
+ cnic_process_fcoe_term_conn(dev, kcqe);
+ return;
+ }
if (opcode == L4_KCQE_OPCODE_VALUE_OFFLOAD_PG ||
opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) {
cnic_cm_process_offld_pg(dev, l4kcqe);
@@ -3852,7 +4323,7 @@ static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *dev)
memset(&l2kwqe, 0, sizeof(l2kwqe));
wqes[0] = &l2kwqe;
- l2kwqe.kwqe_op_flag = (L2_LAYER_CODE << KWQE_FLAGS_LAYER_SHIFT) |
+ l2kwqe.kwqe_op_flag = (L2_LAYER_CODE << KWQE_LAYER_SHIFT) |
(L2_KWQE_OPCODE_VALUE_FLUSH <<
KWQE_OPCODE_SHIFT) | 2;
dev->submit_kwqes(dev, wqes, 1);
@@ -4106,7 +4577,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int port = CNIC_PORT(cp);
int i;
- int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 cli = cp->ethdev->iscsi_l2_client_id;
u32 val;
memset(txbd, 0, BCM_PAGE_SIZE);
@@ -4167,7 +4638,7 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int i;
int port = CNIC_PORT(cp);
- int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 cli = cp->ethdev->iscsi_l2_client_id;
int cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli);
u32 val;
dma_addr_t ring_map = udev->l2_ring_map;
@@ -4231,12 +4702,39 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
cp->rx_cons_ptr =
&sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS];
+ cp->rx_cons = *cp->rx_cons_ptr;
+}
+
+static int cnic_read_bnx2x_iscsi_mac(struct cnic_dev *dev, u32 upper_addr,
+ u32 lower_addr)
+{
+ u32 val;
+ u8 mac[6];
+
+ val = CNIC_RD(dev, upper_addr);
+
+ mac[0] = (u8) (val >> 8);
+ mac[1] = (u8) val;
+
+ val = CNIC_RD(dev, lower_addr);
+
+ mac[2] = (u8) (val >> 24);
+ mac[3] = (u8) (val >> 16);
+ mac[4] = (u8) (val >> 8);
+ mac[5] = (u8) val;
+
+ if (is_valid_ether_addr(mac)) {
+ memcpy(dev->mac_addr, mac, 6);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
}
static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- u32 base, base2, addr, val;
+ u32 base, base2, addr, addr1, val;
int port = CNIC_PORT(cp);
dev->max_iscsi_conn = 0;
@@ -4249,20 +4747,10 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
addr = BNX2X_SHMEM_ADDR(base,
dev_info.port_hw_config[port].iscsi_mac_upper);
- val = CNIC_RD(dev, addr);
-
- dev->mac_addr[0] = (u8) (val >> 8);
- dev->mac_addr[1] = (u8) val;
-
- addr = BNX2X_SHMEM_ADDR(base,
+ addr1 = BNX2X_SHMEM_ADDR(base,
dev_info.port_hw_config[port].iscsi_mac_lower);
- val = CNIC_RD(dev, addr);
-
- dev->mac_addr[2] = (u8) (val >> 24);
- dev->mac_addr[3] = (u8) (val >> 16);
- dev->mac_addr[4] = (u8) (val >> 8);
- dev->mac_addr[5] = (u8) val;
+ cnic_read_bnx2x_iscsi_mac(dev, addr, addr1);
addr = BNX2X_SHMEM_ADDR(base, validity_map[port]);
val = CNIC_RD(dev, addr);
@@ -4278,6 +4766,10 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
val16 ^= 0x1e1e;
dev->max_iscsi_conn = val16;
}
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id))
+ dev->max_fcoe_conn = BNX2X_FCOE_NUM_CONNECTIONS;
+
if (BNX2X_CHIP_IS_E1H(cp->chip_id) || BNX2X_CHIP_IS_E2(cp->chip_id)) {
int func = CNIC_FUNC(cp);
u32 mf_cfg_addr;
@@ -4288,21 +4780,90 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
else
mf_cfg_addr = base + BNX2X_SHMEM_MF_BLK_OFFSET;
- addr = mf_cfg_addr +
- offsetof(struct mf_cfg, func_mf_config[func].e1hov_tag);
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ /* Must determine if the MF is SD vs SI mode */
+ addr = BNX2X_SHMEM_ADDR(base,
+ dev_info.shared_feature_config.config);
+ val = CNIC_RD(dev, addr);
+ if ((val & SHARED_FEAT_CFG_FORCE_SF_MODE_MASK) ==
+ SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT) {
+ int rc;
+
+ /* MULTI_FUNCTION_SI mode */
+ addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr,
+ func_ext_config[func].func_cfg);
+ val = CNIC_RD(dev, addr);
+ if (!(val & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD))
+ dev->max_iscsi_conn = 0;
+
+ if (!(val & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD))
+ dev->max_fcoe_conn = 0;
+
+ addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr,
+ func_ext_config[func].
+ iscsi_mac_addr_upper);
+ addr1 = BNX2X_MF_CFG_ADDR(mf_cfg_addr,
+ func_ext_config[func].
+ iscsi_mac_addr_lower);
+ rc = cnic_read_bnx2x_iscsi_mac(dev, addr,
+ addr1);
+ if (rc && func > 1)
+ dev->max_iscsi_conn = 0;
+
+ return;
+ }
+ }
+
+ addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr,
+ func_mf_config[func].e1hov_tag);
val = CNIC_RD(dev, addr);
val &= FUNC_MF_CFG_E1HOV_TAG_MASK;
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
- addr = mf_cfg_addr +
- offsetof(struct mf_cfg,
- func_mf_config[func].config);
- val = CNIC_RD(dev, addr);
- val &= FUNC_MF_CFG_PROTOCOL_MASK;
- if (val != FUNC_MF_CFG_PROTOCOL_ISCSI)
- dev->max_iscsi_conn = 0;
+ dev->max_fcoe_conn = 0;
+ dev->max_iscsi_conn = 0;
}
}
+ if (!is_valid_ether_addr(dev->mac_addr))
+ dev->max_iscsi_conn = 0;
+}
+
+static void cnic_init_bnx2x_kcq(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 pfid = cp->pfid;
+
+ cp->kcq1.io_addr = BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_PROD_OFFSET(pfid, 0);
+ cp->kcq1.sw_prod_idx = 0;
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
+
+ cp->kcq1.hw_prod_idx_ptr =
+ &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
+ cp->kcq1.status_idx_ptr =
+ &sb->sb.running_index[SM_RX_ID];
+ } else {
+ struct host_hc_status_block_e1x *sb = cp->status_blk.gen;
+
+ cp->kcq1.hw_prod_idx_ptr =
+ &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
+ cp->kcq1.status_idx_ptr =
+ &sb->sb.running_index[SM_RX_ID];
+ }
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
+
+ cp->kcq2.io_addr = BAR_USTRORM_INTMEM +
+ USTORM_FCOE_EQ_PROD_OFFSET(pfid);
+ cp->kcq2.sw_prod_idx = 0;
+ cp->kcq2.hw_prod_idx_ptr =
+ &sb->sb.index_values[HC_INDEX_FCOE_EQ_CONS];
+ cp->kcq2.status_idx_ptr =
+ &sb->sb.running_index[SM_RX_ID];
+ }
}
static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
@@ -4335,28 +4896,19 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
if (ret)
return -ENOMEM;
- cp->bnx2x_igu_sb_id = ethdev->irq_arr[0].status_blk_num2;
-
- cp->kcq1.io_addr = BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_PROD_OFFSET(pfid, 0);
- cp->kcq1.sw_prod_idx = 0;
-
if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
- struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
-
- cp->kcq1.hw_prod_idx_ptr =
- &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
- cp->kcq1.status_idx_ptr =
- &sb->sb.running_index[SM_RX_ID];
- } else {
- struct host_hc_status_block_e1x *sb = cp->status_blk.gen;
+ ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl,
+ BNX2X_FCOE_NUM_CONNECTIONS,
+ cp->fcoe_start_cid);
- cp->kcq1.hw_prod_idx_ptr =
- &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
- cp->kcq1.status_idx_ptr =
- &sb->sb.running_index[SM_RX_ID];
+ if (ret)
+ return -ENOMEM;
}
+ cp->bnx2x_igu_sb_id = ethdev->irq_arr[0].status_blk_num2;
+
+ cnic_init_bnx2x_kcq(dev);
+
cnic_get_bnx2x_iscsi_info(dev);
/* Only 1 EQ */
@@ -4424,8 +4976,9 @@ static void cnic_init_rings(struct cnic_dev *dev)
cnic_init_bnx2_rx_ring(dev);
set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
- u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
- u32 cl_qzone_id, type;
+ u32 cli = cp->ethdev->iscsi_l2_client_id;
+ u32 cid = cp->ethdev->iscsi_l2_cid;
+ u32 cl_qzone_id;
struct client_init_ramrod_data *data;
union l5cm_specific_data l5_data;
struct ustorm_eth_rx_producers rx_prods = {0};
@@ -4457,15 +5010,10 @@ static void cnic_init_rings(struct cnic_dev *dev)
l5_data.phy_address.lo = udev->l2_buf_map & 0xffffffff;
l5_data.phy_address.hi = (u64) udev->l2_buf_map >> 32;
- type = (ETH_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
- & SPE_HDR_CONN_TYPE;
- type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
- SPE_HDR_FUNCTION_ID);
-
set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CLIENT_SETUP,
- BNX2X_ISCSI_L2_CID, type, &l5_data);
+ cid, ETH_CONNECTION_TYPE, &l5_data);
i = 0;
while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
@@ -4476,7 +5024,7 @@ static void cnic_init_rings(struct cnic_dev *dev)
netdev_err(dev->netdev,
"iSCSI CLIENT_SETUP did not complete\n");
cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
- cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
+ cnic_ring_ctl(dev, cid, cli, 1);
}
}
@@ -4491,19 +5039,19 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
cnic_shutdown_bnx2_rx_ring(dev);
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
struct cnic_local *cp = dev->cnic_priv;
- u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 cli = cp->ethdev->iscsi_l2_client_id;
+ u32 cid = cp->ethdev->iscsi_l2_cid;
union l5cm_specific_data l5_data;
int i;
- u32 type;
- cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
+ cnic_ring_ctl(dev, cid, cli, 0);
set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
l5_data.phy_address.lo = cli;
l5_data.phy_address.hi = 0;
cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_HALT,
- BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
+ cid, ETH_CONNECTION_TYPE, &l5_data);
i = 0;
while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
++i < 10)
@@ -4515,12 +5063,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
memset(&l5_data, 0, sizeof(l5_data));
- type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
- & SPE_HDR_CONN_TYPE;
- type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
- SPE_HDR_FUNCTION_ID);
cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL,
- BNX2X_ISCSI_L2_CID, type, &l5_data);
+ cid, NONE_CONNECTION_TYPE, &l5_data);
msleep(10);
}
clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 6a4a0ae5cfe3..b328f6c924c3 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -82,7 +82,7 @@ struct cnic_redirect_entry {
#define MAX_ISCSI_TBL_SZ 256
#define CNIC_LOCAL_PORT_MIN 60000
-#define CNIC_LOCAL_PORT_MAX 61000
+#define CNIC_LOCAL_PORT_MAX 61024
#define CNIC_LOCAL_PORT_RANGE (CNIC_LOCAL_PORT_MAX - CNIC_LOCAL_PORT_MIN)
#define KWQE_CNT (BCM_PAGE_SIZE / sizeof(struct kwqe))
@@ -258,6 +258,7 @@ struct cnic_local {
u16 kwq_con_idx;
struct kcq_info kcq1;
+ struct kcq_info kcq2;
union {
void *gen;
@@ -290,6 +291,10 @@ struct cnic_local {
atomic_t iscsi_conn;
u32 iscsi_start_cid;
+ u32 fcoe_init_cid;
+ u32 fcoe_start_cid;
+ struct cnic_id_tbl fcoe_cid_tbl;
+
u32 max_cid_space;
/* per connection parameters */
@@ -356,11 +361,6 @@ struct bnx2x_bd_chain_next {
#define BNX2X_CONTEXT_MEM_SIZE 1024
#define BNX2X_FCOE_CID 16
-/* iSCSI client IDs are 17, 19, 21, 23 */
-#define BNX2X_ISCSI_BASE_CL_ID 17
-#define BNX2X_ISCSI_CL_ID(vn) (BNX2X_ISCSI_BASE_CL_ID + ((vn) << 1))
-
-#define BNX2X_ISCSI_L2_CID 17
#define BNX2X_ISCSI_START_CID 18
#define BNX2X_ISCSI_NUM_CONNECTIONS 128
#define BNX2X_ISCSI_TASK_CONTEXT_SIZE 128
@@ -372,6 +372,10 @@ struct bnx2x_bd_chain_next {
#define BNX2X_ISCSI_PBL_NOT_CACHED 0xff
#define BNX2X_ISCSI_PDU_HEADER_NOT_CACHED 0xff
+#define BNX2X_FCOE_NUM_CONNECTIONS 128
+
+#define BNX2X_FCOE_L5_CID_BASE MAX_ISCSI_TBL_SZ
+
#define BNX2X_CHIP_NUM_57710 0x164e
#define BNX2X_CHIP_NUM_57711 0x164f
#define BNX2X_CHIP_NUM_57711E 0x1650
@@ -427,6 +431,13 @@ struct bnx2x_bd_chain_next {
(CNIC_RD(dev, BNX2X_SHMEM2_ADDR(base, size)) > \
offsetof(struct shmem2_region, field)))
+#define BNX2X_MF_CFG_ADDR(base, field) \
+ ((base) + offsetof(struct mf_cfg, field))
+
+#ifndef ETH_MAX_RX_CLIENTS_E2
+#define ETH_MAX_RX_CLIENTS_E2 ETH_MAX_RX_CLIENTS_E1H
+#endif
+
#define CNIC_PORT(cp) ((cp)->pfid & 1)
#define CNIC_FUNC(cp) ((cp)->func)
#define CNIC_PATH(cp) (!BNX2X_CHIP_IS_E2(cp->chip_id) ? 0 :\
@@ -439,7 +450,9 @@ struct bnx2x_bd_chain_next {
#define BNX2X_SW_CID(x) (x & 0x1ffff)
#define BNX2X_CL_QZONE_ID(cp, cli) \
- (cli + (CNIC_PORT(cp) * ETH_MAX_RX_CLIENTS_E1H))
+ (cli + (CNIC_PORT(cp) * (BNX2X_CHIP_IS_E2(cp->chip_id) ?\
+ ETH_MAX_RX_CLIENTS_E2 : \
+ ETH_MAX_RX_CLIENTS_E1H)))
#define TCP_TSTORM_OOO_DROP_AND_PROC_ACK (0<<4)
#endif
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
index 328e8b2765a3..fdbc00415603 100644
--- a/drivers/net/cnic_defs.h
+++ b/drivers/net/cnic_defs.h
@@ -35,6 +35,40 @@
#define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE (L5CM_RAMROD_CMD_ID_BASE + 14)
#define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD (L5CM_RAMROD_CMD_ID_BASE + 15)
+#define FCOE_KCQE_OPCODE_INIT_FUNC (0x10)
+#define FCOE_KCQE_OPCODE_DESTROY_FUNC (0x11)
+#define FCOE_KCQE_OPCODE_STAT_FUNC (0x12)
+#define FCOE_KCQE_OPCODE_OFFLOAD_CONN (0x15)
+#define FCOE_KCQE_OPCODE_ENABLE_CONN (0x16)
+#define FCOE_KCQE_OPCODE_DISABLE_CONN (0x17)
+#define FCOE_KCQE_OPCODE_DESTROY_CONN (0x18)
+#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20)
+#define FCOE_KCQE_OPCODE_FCOE_ERROR (0x21)
+
+#define FCOE_RAMROD_CMD_ID_INIT (FCOE_KCQE_OPCODE_INIT_FUNC)
+#define FCOE_RAMROD_CMD_ID_DESTROY (FCOE_KCQE_OPCODE_DESTROY_FUNC)
+#define FCOE_RAMROD_CMD_ID_OFFLOAD_CONN (FCOE_KCQE_OPCODE_OFFLOAD_CONN)
+#define FCOE_RAMROD_CMD_ID_ENABLE_CONN (FCOE_KCQE_OPCODE_ENABLE_CONN)
+#define FCOE_RAMROD_CMD_ID_DISABLE_CONN (FCOE_KCQE_OPCODE_DISABLE_CONN)
+#define FCOE_RAMROD_CMD_ID_DESTROY_CONN (FCOE_KCQE_OPCODE_DESTROY_CONN)
+#define FCOE_RAMROD_CMD_ID_STAT (FCOE_KCQE_OPCODE_STAT_FUNC)
+#define FCOE_RAMROD_CMD_ID_TERMINATE_CONN (0x81)
+
+#define FCOE_KWQE_OPCODE_INIT1 (0)
+#define FCOE_KWQE_OPCODE_INIT2 (1)
+#define FCOE_KWQE_OPCODE_INIT3 (2)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1 (3)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2 (4)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3 (5)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4 (6)
+#define FCOE_KWQE_OPCODE_ENABLE_CONN (7)
+#define FCOE_KWQE_OPCODE_DISABLE_CONN (8)
+#define FCOE_KWQE_OPCODE_DESTROY_CONN (9)
+#define FCOE_KWQE_OPCODE_DESTROY (10)
+#define FCOE_KWQE_OPCODE_STAT (11)
+
+#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3)
+
/* KCQ (kernel completion queue) response op codes */
#define L4_KCQE_OPCODE_VALUE_CLOSE_COMP (53)
#define L4_KCQE_OPCODE_VALUE_RESET_COMP (54)
@@ -683,6 +717,1496 @@ struct cstorm_iscsi_ag_context {
};
/*
+ * Parameters initialized during offloaded according to FLOGI/PLOGI/PRLI and used in FCoE context section
+ */
+struct ustorm_fcoe_params {
+#if defined(__BIG_ENDIAN)
+ u16 fcoe_conn_id;
+ u16 flags;
+#define USTORM_FCOE_PARAMS_B_MUL_N_PORT_IDS (0x1<<0)
+#define USTORM_FCOE_PARAMS_B_MUL_N_PORT_IDS_SHIFT 0
+#define USTORM_FCOE_PARAMS_B_E_D_TOV_RES (0x1<<1)
+#define USTORM_FCOE_PARAMS_B_E_D_TOV_RES_SHIFT 1
+#define USTORM_FCOE_PARAMS_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define USTORM_FCOE_PARAMS_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define USTORM_FCOE_PARAMS_B_CONF_REQ (0x1<<3)
+#define USTORM_FCOE_PARAMS_B_CONF_REQ_SHIFT 3
+#define USTORM_FCOE_PARAMS_B_REC_VALID (0x1<<4)
+#define USTORM_FCOE_PARAMS_B_REC_VALID_SHIFT 4
+#define USTORM_FCOE_PARAMS_B_CQ_TOGGLE_BIT (0x1<<5)
+#define USTORM_FCOE_PARAMS_B_CQ_TOGGLE_BIT_SHIFT 5
+#define USTORM_FCOE_PARAMS_B_XFRQ_TOGGLE_BIT (0x1<<6)
+#define USTORM_FCOE_PARAMS_B_XFRQ_TOGGLE_BIT_SHIFT 6
+#define USTORM_FCOE_PARAMS_B_C2_VALID (0x1<<7)
+#define USTORM_FCOE_PARAMS_B_C2_VALID_SHIFT 7
+#define USTORM_FCOE_PARAMS_B_ACK_0 (0x1<<8)
+#define USTORM_FCOE_PARAMS_B_ACK_0_SHIFT 8
+#define USTORM_FCOE_PARAMS_RSRV0 (0x7F<<9)
+#define USTORM_FCOE_PARAMS_RSRV0_SHIFT 9
+#elif defined(__LITTLE_ENDIAN)
+ u16 flags;
+#define USTORM_FCOE_PARAMS_B_MUL_N_PORT_IDS (0x1<<0)
+#define USTORM_FCOE_PARAMS_B_MUL_N_PORT_IDS_SHIFT 0
+#define USTORM_FCOE_PARAMS_B_E_D_TOV_RES (0x1<<1)
+#define USTORM_FCOE_PARAMS_B_E_D_TOV_RES_SHIFT 1
+#define USTORM_FCOE_PARAMS_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define USTORM_FCOE_PARAMS_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define USTORM_FCOE_PARAMS_B_CONF_REQ (0x1<<3)
+#define USTORM_FCOE_PARAMS_B_CONF_REQ_SHIFT 3
+#define USTORM_FCOE_PARAMS_B_REC_VALID (0x1<<4)
+#define USTORM_FCOE_PARAMS_B_REC_VALID_SHIFT 4
+#define USTORM_FCOE_PARAMS_B_CQ_TOGGLE_BIT (0x1<<5)
+#define USTORM_FCOE_PARAMS_B_CQ_TOGGLE_BIT_SHIFT 5
+#define USTORM_FCOE_PARAMS_B_XFRQ_TOGGLE_BIT (0x1<<6)
+#define USTORM_FCOE_PARAMS_B_XFRQ_TOGGLE_BIT_SHIFT 6
+#define USTORM_FCOE_PARAMS_B_C2_VALID (0x1<<7)
+#define USTORM_FCOE_PARAMS_B_C2_VALID_SHIFT 7
+#define USTORM_FCOE_PARAMS_B_ACK_0 (0x1<<8)
+#define USTORM_FCOE_PARAMS_B_ACK_0_SHIFT 8
+#define USTORM_FCOE_PARAMS_RSRV0 (0x7F<<9)
+#define USTORM_FCOE_PARAMS_RSRV0_SHIFT 9
+ u16 fcoe_conn_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 hc_csdm_byte_en;
+ u8 func_id;
+ u8 port_id;
+ u8 vnic_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 vnic_id;
+ u8 port_id;
+ u8 func_id;
+ u8 hc_csdm_byte_en;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 rx_total_conc_seqs;
+ u16 rx_max_fc_pay_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_max_fc_pay_len;
+ u16 rx_total_conc_seqs;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 ox_id;
+ u16 rx_max_conc_seqs;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_max_conc_seqs;
+ u16 ox_id;
+#endif
+};
+
+/*
+ * FCoE 16-bits index structure
+ */
+struct fcoe_idx16_fields {
+ u16 fields;
+#define FCOE_IDX16_FIELDS_IDX (0x7FFF<<0)
+#define FCOE_IDX16_FIELDS_IDX_SHIFT 0
+#define FCOE_IDX16_FIELDS_MSB (0x1<<15)
+#define FCOE_IDX16_FIELDS_MSB_SHIFT 15
+};
+
+/*
+ * FCoE 16-bits index union
+ */
+union fcoe_idx16_field_union {
+ struct fcoe_idx16_fields fields;
+ u16 val;
+};
+
+/*
+ * 4 regs size
+ */
+struct fcoe_bd_ctx {
+ u32 buf_addr_hi;
+ u32 buf_addr_lo;
+#if defined(__BIG_ENDIAN)
+ u16 rsrv0;
+ u16 buf_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 buf_len;
+ u16 rsrv0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 rsrv1;
+ u16 flags;
+#elif defined(__LITTLE_ENDIAN)
+ u16 flags;
+ u16 rsrv1;
+#endif
+};
+
+/*
+ * Parameters required for placement according to SGL
+ */
+struct ustorm_fcoe_data_place {
+#if defined(__BIG_ENDIAN)
+ u16 cached_sge_off;
+ u8 cached_num_sges;
+ u8 cached_sge_idx;
+#elif defined(__LITTLE_ENDIAN)
+ u8 cached_sge_idx;
+ u8 cached_num_sges;
+ u16 cached_sge_off;
+#endif
+ struct fcoe_bd_ctx cached_sge[3];
+};
+
+struct fcoe_task_ctx_entry_txwr_rxrd {
+#if defined(__BIG_ENDIAN)
+ u16 verify_tx_seq;
+ u8 init_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE (0x7<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE (0x1<<3)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT 3
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE (0x1<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE (0x1<<5)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT 5
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5 (0x3<<6)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5_SHIFT 6
+ u8 tx_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4 (0xF<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4_SHIFT 4
+#elif defined(__LITTLE_ENDIAN)
+ u8 tx_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4 (0xF<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4_SHIFT 4
+ u8 init_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE (0x7<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE (0x1<<3)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT 3
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE (0x1<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE (0x1<<5)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT 5
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5 (0x3<<6)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5_SHIFT 6
+ u16 verify_tx_seq;
+#endif
+};
+
+struct fcoe_fcp_cmd_payload {
+ u32 opaque[8];
+};
+
+struct fcoe_fc_hdr {
+#if defined(__BIG_ENDIAN)
+ u8 cs_ctl;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 cs_ctl;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 r_ctl;
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 r_ctl;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 seq_id;
+ u8 df_ctl;
+ u16 seq_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u16 seq_cnt;
+ u8 df_ctl;
+ u8 seq_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 type;
+ u8 f_ctl[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 f_ctl[3];
+ u8 type;
+#endif
+ u32 parameters;
+#if defined(__BIG_ENDIAN)
+ u16 ox_id;
+ u16 rx_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_id;
+ u16 ox_id;
+#endif
+};
+
+struct fcoe_fc_frame {
+ struct fcoe_fc_hdr fc_hdr;
+ u32 reserved0[2];
+};
+
+union fcoe_cmd_flow_info {
+ struct fcoe_fcp_cmd_payload fcp_cmd_payload;
+ struct fcoe_fc_frame mp_fc_frame;
+};
+
+struct fcoe_read_flow_info {
+ struct fcoe_fc_hdr fc_data_in_hdr;
+ u32 reserved[2];
+};
+
+struct fcoe_fcp_xfr_rdy_payload {
+ u32 burst_len;
+ u32 data_ro;
+};
+
+struct fcoe_write_flow_info {
+ struct fcoe_fc_hdr fc_data_out_hdr;
+ struct fcoe_fcp_xfr_rdy_payload fcp_xfr_payload;
+};
+
+struct fcoe_fcp_rsp_flags {
+ u8 flags;
+#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID (0x1<<0)
+#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID_SHIFT 0
+#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID (0x1<<1)
+#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID_SHIFT 1
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER (0x1<<2)
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER_SHIFT 2
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER (0x1<<3)
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER_SHIFT 3
+#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ (0x1<<4)
+#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ_SHIFT 4
+#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS (0x7<<5)
+#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS_SHIFT 5
+};
+
+struct fcoe_fcp_rsp_payload {
+ struct regpair reserved0;
+ u32 fcp_resid;
+#if defined(__BIG_ENDIAN)
+ u16 retry_delay_timer;
+ struct fcoe_fcp_rsp_flags fcp_flags;
+ u8 scsi_status_code;
+#elif defined(__LITTLE_ENDIAN)
+ u8 scsi_status_code;
+ struct fcoe_fcp_rsp_flags fcp_flags;
+ u16 retry_delay_timer;
+#endif
+ u32 fcp_rsp_len;
+ u32 fcp_sns_len;
+};
+
+/*
+ * Fixed size structure in order to plant it in Union structure
+ */
+struct fcoe_fcp_rsp_union {
+ struct fcoe_fcp_rsp_payload payload;
+ struct regpair reserved0;
+};
+
+/*
+ * Fixed size structure in order to plant it in Union structure
+ */
+struct fcoe_abts_rsp_union {
+ u32 r_ctl;
+ u32 abts_rsp_payload[7];
+};
+
+union fcoe_rsp_flow_info {
+ struct fcoe_fcp_rsp_union fcp_rsp;
+ struct fcoe_abts_rsp_union abts_rsp;
+};
+
+struct fcoe_cleanup_flow_info {
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u16 task_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 task_id;
+ u16 reserved1;
+#endif
+ u32 reserved2[7];
+};
+
+/*
+ * 32 bytes used for general purposes
+ */
+union fcoe_general_task_ctx {
+ union fcoe_cmd_flow_info cmd_info;
+ struct fcoe_read_flow_info read_info;
+ struct fcoe_write_flow_info write_info;
+ union fcoe_rsp_flow_info rsp_info;
+ struct fcoe_cleanup_flow_info cleanup_info;
+ u32 comp_info[8];
+};
+
+struct fcoe_s_stat_ctx {
+ u8 flags;
+#define FCOE_S_STAT_CTX_ACTIVE (0x1<<0)
+#define FCOE_S_STAT_CTX_ACTIVE_SHIFT 0
+#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND (0x1<<1)
+#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND_SHIFT 1
+#define FCOE_S_STAT_CTX_ABTS_PERFORMED (0x1<<2)
+#define FCOE_S_STAT_CTX_ABTS_PERFORMED_SHIFT 2
+#define FCOE_S_STAT_CTX_SEQ_TIMEOUT (0x1<<3)
+#define FCOE_S_STAT_CTX_SEQ_TIMEOUT_SHIFT 3
+#define FCOE_S_STAT_CTX_P_RJT (0x1<<4)
+#define FCOE_S_STAT_CTX_P_RJT_SHIFT 4
+#define FCOE_S_STAT_CTX_ACK_EOFT (0x1<<5)
+#define FCOE_S_STAT_CTX_ACK_EOFT_SHIFT 5
+#define FCOE_S_STAT_CTX_RSRV1 (0x3<<6)
+#define FCOE_S_STAT_CTX_RSRV1_SHIFT 6
+};
+
+/*
+ * Common section. Both TX and RX processing might write and read from it in different flows
+ */
+struct fcoe_task_ctx_entry_tx_rx_cmn {
+ u32 data_2_trns;
+ union fcoe_general_task_ctx general;
+#if defined(__BIG_ENDIAN)
+ u16 tx_low_seq_cnt;
+ struct fcoe_s_stat_ctx tx_s_stat;
+ u8 tx_seq_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 tx_seq_id;
+ struct fcoe_s_stat_ctx tx_s_stat;
+ u16 tx_low_seq_cnt;
+#endif
+ u32 common_flags;
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID (0xFFFFFF<<0)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID (0x1<<24)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT 24
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT (0x1<<25)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT_SHIFT 25
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_XFER (0x1<<26)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_XFER_SHIFT 26
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_CONF (0x1<<27)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_CONF_SHIFT 27
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME (0x1<<28)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT 28
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_RSRV (0x7<<29)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_RSRV_SHIFT 29
+};
+
+struct fcoe_task_ctx_entry_rxwr_txrd {
+#if defined(__BIG_ENDIAN)
+ u16 rx_id;
+ u16 rx_flags;
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE (0x7<<4)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ (0x1<<7)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ_SHIFT 7
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME (0x1<<8)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME_SHIFT 8
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0 (0x7F<<9)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0_SHIFT 9
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_flags;
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE (0x7<<4)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ (0x1<<7)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ_SHIFT 7
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME (0x1<<8)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME_SHIFT 8
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0 (0x7F<<9)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0_SHIFT 9
+ u16 rx_id;
+#endif
+};
+
+struct fcoe_seq_ctx {
+#if defined(__BIG_ENDIAN)
+ u16 low_seq_cnt;
+ struct fcoe_s_stat_ctx s_stat;
+ u8 seq_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 seq_id;
+ struct fcoe_s_stat_ctx s_stat;
+ u16 low_seq_cnt;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 err_seq_cnt;
+ u16 high_seq_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u16 high_seq_cnt;
+ u16 err_seq_cnt;
+#endif
+ u32 low_exp_ro;
+ u32 high_exp_ro;
+};
+
+struct fcoe_single_sge_ctx {
+ struct regpair cur_buf_addr;
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u16 cur_buf_rem;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cur_buf_rem;
+ u16 reserved0;
+#endif
+};
+
+struct fcoe_mul_sges_ctx {
+ struct regpair cur_sge_addr;
+#if defined(__BIG_ENDIAN)
+ u8 sgl_size;
+ u8 cur_sge_idx;
+ u16 cur_sge_off;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cur_sge_off;
+ u8 cur_sge_idx;
+ u8 sgl_size;
+#endif
+};
+
+union fcoe_sgl_ctx {
+ struct fcoe_single_sge_ctx single_sge;
+ struct fcoe_mul_sges_ctx mul_sges;
+};
+
+struct fcoe_task_ctx_entry_rx_only {
+ struct fcoe_seq_ctx seq_ctx;
+ struct fcoe_seq_ctx ooo_seq_ctx;
+ u32 rsrv3;
+ union fcoe_sgl_ctx sgl_ctx;
+};
+
+struct ustorm_fcoe_task_ctx_entry_rd {
+ struct fcoe_task_ctx_entry_txwr_rxrd tx_wr_rx_rd;
+ struct fcoe_task_ctx_entry_tx_rx_cmn cmn;
+ struct fcoe_task_ctx_entry_rxwr_txrd rx_wr_tx_rd;
+ struct fcoe_task_ctx_entry_rx_only rx_wr;
+ u32 reserved;
+};
+
+/*
+ * Ustorm FCoE Storm Context
+ */
+struct ustorm_fcoe_st_context {
+ struct ustorm_fcoe_params fcoe_params;
+ struct regpair task_addr;
+ struct regpair cq_base_addr;
+ struct regpair rq_pbl_base;
+ struct regpair rq_cur_page_addr;
+ struct regpair confq_pbl_base_addr;
+ struct regpair conn_db_base;
+ struct regpair xfrq_base_addr;
+ struct regpair lcq_base_addr;
+#if defined(__BIG_ENDIAN)
+ union fcoe_idx16_field_union rq_cons;
+ union fcoe_idx16_field_union rq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ union fcoe_idx16_field_union rq_prod;
+ union fcoe_idx16_field_union rq_cons;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 xfrq_prod;
+ u16 cq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cq_cons;
+ u16 xfrq_prod;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 lcq_cons;
+ u16 hc_cram_address;
+#elif defined(__LITTLE_ENDIAN)
+ u16 hc_cram_address;
+ u16 lcq_cons;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 sq_xfrq_lcq_confq_size;
+ u16 confq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 confq_prod;
+ u16 sq_xfrq_lcq_confq_size;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 hc_csdm_agg_int;
+ u8 flags;
+#define USTORM_FCOE_ST_CONTEXT_MID_SEQ_PROC_FLAG (0x1<<0)
+#define USTORM_FCOE_ST_CONTEXT_MID_SEQ_PROC_FLAG_SHIFT 0
+#define USTORM_FCOE_ST_CONTEXT_CACHED_CONN_FLAG (0x1<<1)
+#define USTORM_FCOE_ST_CONTEXT_CACHED_CONN_FLAG_SHIFT 1
+#define USTORM_FCOE_ST_CONTEXT_CACHED_TCE_FLAG (0x1<<2)
+#define USTORM_FCOE_ST_CONTEXT_CACHED_TCE_FLAG_SHIFT 2
+#define USTORM_FCOE_ST_CONTEXT_RSRV1 (0x1F<<3)
+#define USTORM_FCOE_ST_CONTEXT_RSRV1_SHIFT 3
+ u8 available_rqes;
+ u8 sp_q_flush_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u8 sp_q_flush_cnt;
+ u8 available_rqes;
+ u8 flags;
+#define USTORM_FCOE_ST_CONTEXT_MID_SEQ_PROC_FLAG (0x1<<0)
+#define USTORM_FCOE_ST_CONTEXT_MID_SEQ_PROC_FLAG_SHIFT 0
+#define USTORM_FCOE_ST_CONTEXT_CACHED_CONN_FLAG (0x1<<1)
+#define USTORM_FCOE_ST_CONTEXT_CACHED_CONN_FLAG_SHIFT 1
+#define USTORM_FCOE_ST_CONTEXT_CACHED_TCE_FLAG (0x1<<2)
+#define USTORM_FCOE_ST_CONTEXT_CACHED_TCE_FLAG_SHIFT 2
+#define USTORM_FCOE_ST_CONTEXT_RSRV1 (0x1F<<3)
+#define USTORM_FCOE_ST_CONTEXT_RSRV1_SHIFT 3
+ u8 hc_csdm_agg_int;
+#endif
+ struct ustorm_fcoe_data_place data_place;
+ struct ustorm_fcoe_task_ctx_entry_rd tce;
+};
+
+/*
+ * The FCoE non-aggregative context of Tstorm
+ */
+struct tstorm_fcoe_st_context {
+ struct regpair reserved0;
+ struct regpair reserved1;
+};
+
+/*
+ * The fcoe aggregative context section of Xstorm
+ */
+struct xstorm_fcoe_extra_ag_context_section {
+#if defined(__BIG_ENDIAN)
+ u8 tcp_agg_vars1;
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED51 (0x3<<0)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED51_SHIFT 0
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED (0x3<<2)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_SHIFT 2
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF (0x3<<4)
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_SHIFT 4
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_CLEAR_DA_TIMER_EN (0x1<<6)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_CLEAR_DA_TIMER_EN_SHIFT 6
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_DA_EXPIRATION_FLAG (0x1<<7)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_DA_EXPIRATION_FLAG_SHIFT 7
+ u8 __reserved_da_cnt;
+ u16 __mtu;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __mtu;
+ u8 __reserved_da_cnt;
+ u8 tcp_agg_vars1;
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED51 (0x3<<0)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED51_SHIFT 0
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED (0x3<<2)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_SHIFT 2
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF (0x3<<4)
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_SHIFT 4
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_CLEAR_DA_TIMER_EN (0x1<<6)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_CLEAR_DA_TIMER_EN_SHIFT 6
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_DA_EXPIRATION_FLAG (0x1<<7)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_DA_EXPIRATION_FLAG_SHIFT 7
+#endif
+ u32 __task_addr_lo;
+ u32 __task_addr_hi;
+ u32 __reserved55;
+ u32 __tx_prods;
+#if defined(__BIG_ENDIAN)
+ u8 __agg_val8_th;
+ u8 __agg_val8;
+ u16 tcp_agg_vars2;
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED57 (0x1<<0)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED57_SHIFT 0
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED58 (0x1<<1)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED58_SHIFT 1
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED59 (0x1<<2)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED59_SHIFT 2
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX3_FLAG (0x1<<3)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX3_FLAG_SHIFT 3
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX4_FLAG (0x1<<4)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX4_FLAG_SHIFT 4
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED60 (0x1<<5)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED60_SHIFT 5
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_ACK_TO_FE_UPDATED_EN (0x1<<6)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_ACK_TO_FE_UPDATED_EN_SHIFT 6
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_EN (0x1<<7)
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_EN_SHIFT 7
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_TX_FIN_FLAG_EN (0x1<<8)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_TX_FIN_FLAG_EN_SHIFT 8
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<9)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 9
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_SET_RTO_CF (0x3<<10)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_SET_RTO_CF_SHIFT 10
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF (0x3<<12)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF_SHIFT 12
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX8_CF (0x3<<14)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX8_CF_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+ u16 tcp_agg_vars2;
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED57 (0x1<<0)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED57_SHIFT 0
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED58 (0x1<<1)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED58_SHIFT 1
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED59 (0x1<<2)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED59_SHIFT 2
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX3_FLAG (0x1<<3)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX3_FLAG_SHIFT 3
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX4_FLAG (0x1<<4)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX4_FLAG_SHIFT 4
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED60 (0x1<<5)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED60_SHIFT 5
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_ACK_TO_FE_UPDATED_EN (0x1<<6)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_ACK_TO_FE_UPDATED_EN_SHIFT 6
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_EN (0x1<<7)
+#define XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_PBF_TX_SEQ_ACK_CF_EN_SHIFT 7
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_TX_FIN_FLAG_EN (0x1<<8)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED_TX_FIN_FLAG_EN_SHIFT 8
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<9)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 9
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_SET_RTO_CF (0x3<<10)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_SET_RTO_CF_SHIFT 10
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF (0x3<<12)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF_SHIFT 12
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX8_CF (0x3<<14)
+#define __XSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX8_CF_SHIFT 14
+ u8 __agg_val8;
+ u8 __agg_val8_th;
+#endif
+ u32 __sq_base_addr_lo;
+ u32 __sq_base_addr_hi;
+ u32 __xfrq_base_addr_lo;
+ u32 __xfrq_base_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 __xfrq_cons;
+ u16 __xfrq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __xfrq_prod;
+ u16 __xfrq_cons;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 __tcp_agg_vars5;
+ u8 __tcp_agg_vars4;
+ u8 __tcp_agg_vars3;
+ u8 __reserved_force_pure_ack_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __reserved_force_pure_ack_cnt;
+ u8 __tcp_agg_vars3;
+ u8 __tcp_agg_vars4;
+ u8 __tcp_agg_vars5;
+#endif
+ u32 __tcp_agg_vars6;
+#if defined(__BIG_ENDIAN)
+ u16 __agg_misc6;
+ u16 __tcp_agg_vars7;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __tcp_agg_vars7;
+ u16 __agg_misc6;
+#endif
+ u32 __agg_val10;
+ u32 __agg_val10_th;
+#if defined(__BIG_ENDIAN)
+ u16 __reserved3;
+ u8 __reserved2;
+ u8 __da_only_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __da_only_cnt;
+ u8 __reserved2;
+ u16 __reserved3;
+#endif
+};
+
+/*
+ * The fcoe aggregative context of Xstorm
+ */
+struct xstorm_fcoe_ag_context {
+#if defined(__BIG_ENDIAN)
+ u16 agg_val1;
+ u8 agg_vars1;
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED51 (0x1<<2)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED51_SHIFT 2
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED52 (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED52_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_MORE_TO_SEND_EN (0x1<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_MORE_TO_SEND_EN_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_NAGLE_EN (0x1<<5)
+#define XSTORM_FCOE_AG_CONTEXT_NAGLE_EN_SHIFT 5
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG (0x1<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_SHIFT 6
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED_UNA_GT_NXT_EN (0x1<<7)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED_UNA_GT_NXT_EN_SHIFT 7
+ u8 __state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __state;
+ u8 agg_vars1;
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define __XSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED51 (0x1<<2)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED51_SHIFT 2
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED52 (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED52_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_MORE_TO_SEND_EN (0x1<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_MORE_TO_SEND_EN_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_NAGLE_EN (0x1<<5)
+#define XSTORM_FCOE_AG_CONTEXT_NAGLE_EN_SHIFT 5
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG (0x1<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_SHIFT 6
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED_UNA_GT_NXT_EN (0x1<<7)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED_UNA_GT_NXT_EN_SHIFT 7
+ u16 agg_val1;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 cdu_reserved;
+ u8 __agg_vars4;
+ u8 agg_vars3;
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM2 (0x3F<<0)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM2_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_AUX19_CF (0x3<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX19_CF_SHIFT 6
+ u8 agg_vars2;
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF (0x3<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_EN (0x1<<2)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_EN_SHIFT 2
+#define __XSTORM_FCOE_AG_CONTEXT_AUX8_FLAG (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX8_FLAG_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_AUX9_FLAG (0x1<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX9_FLAG_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE1 (0x3<<5)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE1_SHIFT 5
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+#elif defined(__LITTLE_ENDIAN)
+ u8 agg_vars2;
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF (0x3<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_EN (0x1<<2)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_SPARE_FLAG_EN_SHIFT 2
+#define __XSTORM_FCOE_AG_CONTEXT_AUX8_FLAG (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX8_FLAG_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_AUX9_FLAG (0x1<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX9_FLAG_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE1 (0x3<<5)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE1_SHIFT 5
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __XSTORM_FCOE_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+ u8 agg_vars3;
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM2 (0x3F<<0)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM2_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_AUX19_CF (0x3<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX19_CF_SHIFT 6
+ u8 __agg_vars4;
+ u8 cdu_reserved;
+#endif
+ u32 more_to_send;
+#if defined(__BIG_ENDIAN)
+ u16 agg_vars5;
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE5 (0x3<<0)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE5_SHIFT 0
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM0 (0x3F<<2)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM0_SHIFT 2
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM1 (0x3F<<8)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM1_SHIFT 8
+#define __XSTORM_FCOE_AG_CONTEXT_CONFQ_DEC_RULE (0x3<<14)
+#define __XSTORM_FCOE_AG_CONTEXT_CONFQ_DEC_RULE_SHIFT 14
+ u16 sq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_cons;
+ u16 agg_vars5;
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE5 (0x3<<0)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE5_SHIFT 0
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM0 (0x3F<<2)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM0_SHIFT 2
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM1 (0x3F<<8)
+#define XSTORM_FCOE_AG_CONTEXT_PHYSICAL_QUEUE_NUM1_SHIFT 8
+#define __XSTORM_FCOE_AG_CONTEXT_CONFQ_DEC_RULE (0x3<<14)
+#define __XSTORM_FCOE_AG_CONTEXT_CONFQ_DEC_RULE_SHIFT 14
+#endif
+ struct xstorm_fcoe_extra_ag_context_section __extra_section;
+#if defined(__BIG_ENDIAN)
+ u16 agg_vars7;
+#define __XSTORM_FCOE_AG_CONTEXT_AGG_VAL11_DECISION_RULE (0x7<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_AGG_VAL11_DECISION_RULE_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_AUX13_FLAG (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX13_FLAG_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_QUEUE0_CF (0x3<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_QUEUE0_CF_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE3 (0x3<<6)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE3_SHIFT 6
+#define XSTORM_FCOE_AG_CONTEXT_AUX1_CF (0x3<<8)
+#define XSTORM_FCOE_AG_CONTEXT_AUX1_CF_SHIFT 8
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED62 (0x1<<10)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED62_SHIFT 10
+#define __XSTORM_FCOE_AG_CONTEXT_AUX1_CF_EN (0x1<<11)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX1_CF_EN_SHIFT 11
+#define __XSTORM_FCOE_AG_CONTEXT_AUX10_FLAG (0x1<<12)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX10_FLAG_SHIFT 12
+#define __XSTORM_FCOE_AG_CONTEXT_AUX11_FLAG (0x1<<13)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX11_FLAG_SHIFT 13
+#define __XSTORM_FCOE_AG_CONTEXT_AUX12_FLAG (0x1<<14)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX12_FLAG_SHIFT 14
+#define __XSTORM_FCOE_AG_CONTEXT_AUX2_FLAG (0x1<<15)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX2_FLAG_SHIFT 15
+ u8 agg_val3_th;
+ u8 agg_vars6;
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE6 (0x7<<0)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE6_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_XFRQ_DEC_RULE (0x7<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_XFRQ_DEC_RULE_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_SQ_DEC_RULE (0x3<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_SQ_DEC_RULE_SHIFT 6
+#elif defined(__LITTLE_ENDIAN)
+ u8 agg_vars6;
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE6 (0x7<<0)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE6_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_XFRQ_DEC_RULE (0x7<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_XFRQ_DEC_RULE_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_SQ_DEC_RULE (0x3<<6)
+#define __XSTORM_FCOE_AG_CONTEXT_SQ_DEC_RULE_SHIFT 6
+ u8 agg_val3_th;
+ u16 agg_vars7;
+#define __XSTORM_FCOE_AG_CONTEXT_AGG_VAL11_DECISION_RULE (0x7<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_AGG_VAL11_DECISION_RULE_SHIFT 0
+#define __XSTORM_FCOE_AG_CONTEXT_AUX13_FLAG (0x1<<3)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX13_FLAG_SHIFT 3
+#define __XSTORM_FCOE_AG_CONTEXT_QUEUE0_CF (0x3<<4)
+#define __XSTORM_FCOE_AG_CONTEXT_QUEUE0_CF_SHIFT 4
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE3 (0x3<<6)
+#define XSTORM_FCOE_AG_CONTEXT_DECISION_RULE3_SHIFT 6
+#define XSTORM_FCOE_AG_CONTEXT_AUX1_CF (0x3<<8)
+#define XSTORM_FCOE_AG_CONTEXT_AUX1_CF_SHIFT 8
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED62 (0x1<<10)
+#define __XSTORM_FCOE_AG_CONTEXT_RESERVED62_SHIFT 10
+#define __XSTORM_FCOE_AG_CONTEXT_AUX1_CF_EN (0x1<<11)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX1_CF_EN_SHIFT 11
+#define __XSTORM_FCOE_AG_CONTEXT_AUX10_FLAG (0x1<<12)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX10_FLAG_SHIFT 12
+#define __XSTORM_FCOE_AG_CONTEXT_AUX11_FLAG (0x1<<13)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX11_FLAG_SHIFT 13
+#define __XSTORM_FCOE_AG_CONTEXT_AUX12_FLAG (0x1<<14)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX12_FLAG_SHIFT 14
+#define __XSTORM_FCOE_AG_CONTEXT_AUX2_FLAG (0x1<<15)
+#define __XSTORM_FCOE_AG_CONTEXT_AUX2_FLAG_SHIFT 15
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __agg_val11_th;
+ u16 __agg_val11;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __agg_val11;
+ u16 __agg_val11_th;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 __reserved1;
+ u8 __agg_val6_th;
+ u16 __confq_tx_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __confq_tx_prod;
+ u8 __agg_val6_th;
+ u8 __reserved1;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 confq_cons;
+ u16 confq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 confq_prod;
+ u16 confq_cons;
+#endif
+ u32 agg_vars8;
+#define __XSTORM_FCOE_AG_CONTEXT_CACHE_WQE_IDX (0xFFFFFF<<0)
+#define __XSTORM_FCOE_AG_CONTEXT_CACHE_WQE_IDX_SHIFT 0
+#define XSTORM_FCOE_AG_CONTEXT_AGG_MISC3 (0xFF<<24)
+#define XSTORM_FCOE_AG_CONTEXT_AGG_MISC3_SHIFT 24
+#if defined(__BIG_ENDIAN)
+ u16 ox_id;
+ u16 sq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_prod;
+ u16 ox_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 agg_val3;
+ u8 agg_val6;
+ u8 agg_val5_th;
+ u8 agg_val5;
+#elif defined(__LITTLE_ENDIAN)
+ u8 agg_val5;
+ u8 agg_val5_th;
+ u8 agg_val6;
+ u8 agg_val3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __pbf_tx_seq_ack;
+ u16 agg_limit1;
+#elif defined(__LITTLE_ENDIAN)
+ u16 agg_limit1;
+ u16 __pbf_tx_seq_ack;
+#endif
+ u32 completion_seq;
+ u32 confq_pbl_base_lo;
+ u32 confq_pbl_base_hi;
+};
+
+/*
+ * The fcoe extra aggregative context section of Tstorm
+ */
+struct tstorm_fcoe_extra_ag_context_section {
+ u32 __agg_val1;
+#if defined(__BIG_ENDIAN)
+ u8 __tcp_agg_vars2;
+ u8 __agg_val3;
+ u16 __agg_val2;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __agg_val2;
+ u8 __agg_val3;
+ u8 __tcp_agg_vars2;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __agg_val5;
+ u8 __agg_val6;
+ u8 __tcp_agg_vars3;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __tcp_agg_vars3;
+ u8 __agg_val6;
+ u16 __agg_val5;
+#endif
+ u32 __lcq_prod;
+ u32 rtt_seq;
+ u32 rtt_time;
+ u32 __reserved66;
+ u32 wnd_right_edge;
+ u32 tcp_agg_vars1;
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_FIN_SENT_FLAG (0x1<<0)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_FIN_SENT_FLAG_SHIFT 0
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_LAST_PACKET_FIN_FLAG (0x1<<1)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_LAST_PACKET_FIN_FLAG_SHIFT 1
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_WND_UPD_CF (0x3<<2)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_WND_UPD_CF_SHIFT 2
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TIMEOUT_CF (0x3<<4)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TIMEOUT_CF_SHIFT 4
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_WND_UPD_CF_EN (0x1<<6)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_WND_UPD_CF_EN_SHIFT 6
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TIMEOUT_CF_EN (0x1<<7)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TIMEOUT_CF_EN_SHIFT 7
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_SEQ_EN (0x1<<8)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_SEQ_EN_SHIFT 8
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_LCQ_SND_EN (0x1<<9)
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_LCQ_SND_EN_SHIFT 9
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<10)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 10
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_FLAG (0x1<<11)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_FLAG_SHIFT 11
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_CF_EN (0x1<<12)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_CF_EN_SHIFT 12
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_CF_EN (0x1<<13)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_CF_EN_SHIFT 13
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_CF (0x3<<14)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX1_CF_SHIFT 14
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_CF (0x3<<16)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX2_CF_SHIFT 16
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TX_BLOCKED (0x1<<18)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_TX_BLOCKED_SHIFT 18
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX10_CF_EN (0x1<<19)
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX10_CF_EN_SHIFT 19
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX11_CF_EN (0x1<<20)
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX11_CF_EN_SHIFT 20
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX12_CF_EN (0x1<<21)
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_AUX12_CF_EN_SHIFT 21
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED1 (0x3<<22)
+#define __TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RESERVED1_SHIFT 22
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_PEND_SEQ (0xF<<24)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_PEND_SEQ_SHIFT 24
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_DONE_SEQ (0xF<<28)
+#define TSTORM_FCOE_EXTRA_AG_CONTEXT_SECTION_RETRANSMIT_DONE_SEQ_SHIFT 28
+ u32 snd_max;
+ u32 __lcq_cons;
+ u32 __reserved2;
+};
+
+/*
+ * The fcoe aggregative context of Tstorm
+ */
+struct tstorm_fcoe_ag_context {
+#if defined(__BIG_ENDIAN)
+ u16 ulp_credit;
+ u8 agg_vars1;
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF (0x3<<4)
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_SHIFT 4
+#define __TSTORM_FCOE_AG_CONTEXT_AUX3_FLAG (0x1<<6)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX3_FLAG_SHIFT 6
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_FLAG (0x1<<7)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_FLAG_SHIFT 7
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 agg_vars1;
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define TSTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF (0x3<<4)
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_SHIFT 4
+#define __TSTORM_FCOE_AG_CONTEXT_AUX3_FLAG (0x1<<6)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX3_FLAG_SHIFT 6
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_FLAG (0x1<<7)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_FLAG_SHIFT 7
+ u16 ulp_credit;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __agg_val4;
+ u16 agg_vars2;
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_FLAG (0x1<<0)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_FLAG_SHIFT 0
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_FLAG (0x1<<1)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_FLAG_SHIFT 1
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_CF (0x3<<2)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_CF_SHIFT 2
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_CF (0x3<<4)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_CF_SHIFT 4
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_CF (0x3<<6)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_CF_SHIFT 6
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_CF (0x3<<8)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_CF_SHIFT 8
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_FLAG (0x1<<10)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_FLAG_SHIFT 10
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_EN (0x1<<11)
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_EN_SHIFT 11
+#define TSTORM_FCOE_AG_CONTEXT_AUX4_CF_EN (0x1<<12)
+#define TSTORM_FCOE_AG_CONTEXT_AUX4_CF_EN_SHIFT 12
+#define TSTORM_FCOE_AG_CONTEXT_AUX5_CF_EN (0x1<<13)
+#define TSTORM_FCOE_AG_CONTEXT_AUX5_CF_EN_SHIFT 13
+#define TSTORM_FCOE_AG_CONTEXT_AUX6_CF_EN (0x1<<14)
+#define TSTORM_FCOE_AG_CONTEXT_AUX6_CF_EN_SHIFT 14
+#define TSTORM_FCOE_AG_CONTEXT_AUX7_CF_EN (0x1<<15)
+#define TSTORM_FCOE_AG_CONTEXT_AUX7_CF_EN_SHIFT 15
+#elif defined(__LITTLE_ENDIAN)
+ u16 agg_vars2;
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_FLAG (0x1<<0)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_FLAG_SHIFT 0
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_FLAG (0x1<<1)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_FLAG_SHIFT 1
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_CF (0x3<<2)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX4_CF_SHIFT 2
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_CF (0x3<<4)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX5_CF_SHIFT 4
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_CF (0x3<<6)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX6_CF_SHIFT 6
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_CF (0x3<<8)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_CF_SHIFT 8
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_FLAG (0x1<<10)
+#define __TSTORM_FCOE_AG_CONTEXT_AUX7_FLAG_SHIFT 10
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_EN (0x1<<11)
+#define __TSTORM_FCOE_AG_CONTEXT_QUEUE0_FLUSH_CF_EN_SHIFT 11
+#define TSTORM_FCOE_AG_CONTEXT_AUX4_CF_EN (0x1<<12)
+#define TSTORM_FCOE_AG_CONTEXT_AUX4_CF_EN_SHIFT 12
+#define TSTORM_FCOE_AG_CONTEXT_AUX5_CF_EN (0x1<<13)
+#define TSTORM_FCOE_AG_CONTEXT_AUX5_CF_EN_SHIFT 13
+#define TSTORM_FCOE_AG_CONTEXT_AUX6_CF_EN (0x1<<14)
+#define TSTORM_FCOE_AG_CONTEXT_AUX6_CF_EN_SHIFT 14
+#define TSTORM_FCOE_AG_CONTEXT_AUX7_CF_EN (0x1<<15)
+#define TSTORM_FCOE_AG_CONTEXT_AUX7_CF_EN_SHIFT 15
+ u16 __agg_val4;
+#endif
+ struct tstorm_fcoe_extra_ag_context_section __extra_section;
+};
+
+/*
+ * The fcoe aggregative context of Ustorm
+ */
+struct ustorm_fcoe_ag_context {
+#if defined(__BIG_ENDIAN)
+ u8 __aux_counter_flags;
+ u8 agg_vars2;
+#define USTORM_FCOE_AG_CONTEXT_TX_CF (0x3<<0)
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_SHIFT 0
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF (0x3<<2)
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_SHIFT 2
+#define USTORM_FCOE_AG_CONTEXT_AGG_MISC4_RULE (0x7<<4)
+#define USTORM_FCOE_AG_CONTEXT_AGG_MISC4_RULE_SHIFT 4
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL2_MASK (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL2_MASK_SHIFT 7
+ u8 agg_vars1;
+#define __USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define USTORM_FCOE_AG_CONTEXT_INV_CF (0x3<<4)
+#define USTORM_FCOE_AG_CONTEXT_INV_CF_SHIFT 4
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF (0x3<<6)
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_SHIFT 6
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 agg_vars1;
+#define __USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define USTORM_FCOE_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define USTORM_FCOE_AG_CONTEXT_INV_CF (0x3<<4)
+#define USTORM_FCOE_AG_CONTEXT_INV_CF_SHIFT 4
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF (0x3<<6)
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_SHIFT 6
+ u8 agg_vars2;
+#define USTORM_FCOE_AG_CONTEXT_TX_CF (0x3<<0)
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_SHIFT 0
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF (0x3<<2)
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_SHIFT 2
+#define USTORM_FCOE_AG_CONTEXT_AGG_MISC4_RULE (0x7<<4)
+#define USTORM_FCOE_AG_CONTEXT_AGG_MISC4_RULE_SHIFT 4
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL2_MASK (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL2_MASK_SHIFT 7
+ u8 __aux_counter_flags;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 cdu_usage;
+ u8 agg_misc2;
+ u16 pbf_tx_seq_ack;
+#elif defined(__LITTLE_ENDIAN)
+ u16 pbf_tx_seq_ack;
+ u8 agg_misc2;
+ u8 cdu_usage;
+#endif
+ u32 agg_misc4;
+#if defined(__BIG_ENDIAN)
+ u8 agg_val3_th;
+ u8 agg_val3;
+ u16 agg_misc3;
+#elif defined(__LITTLE_ENDIAN)
+ u16 agg_misc3;
+ u8 agg_val3;
+ u8 agg_val3_th;
+#endif
+ u32 expired_task_id;
+ u32 agg_misc4_th;
+#if defined(__BIG_ENDIAN)
+ u16 cq_prod;
+ u16 cq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cq_cons;
+ u16 cq_prod;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __reserved2;
+ u8 decision_rules;
+#define USTORM_FCOE_AG_CONTEXT_CQ_DEC_RULE (0x7<<0)
+#define USTORM_FCOE_AG_CONTEXT_CQ_DEC_RULE_SHIFT 0
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL3_RULE (0x7<<3)
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL3_RULE_SHIFT 3
+#define USTORM_FCOE_AG_CONTEXT_CQ_ARM_N_FLAG (0x1<<6)
+#define USTORM_FCOE_AG_CONTEXT_CQ_ARM_N_FLAG_SHIFT 6
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED1 (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED1_SHIFT 7
+ u8 decision_rule_enable_bits;
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED_INV_CF_EN (0x1<<0)
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED_INV_CF_EN_SHIFT 0
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_EN (0x1<<1)
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_EN_SHIFT 1
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_EN (0x1<<2)
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_EN_SHIFT 2
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_EN (0x1<<3)
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_EN_SHIFT 3
+#define __USTORM_FCOE_AG_CONTEXT_AUX1_CF_EN (0x1<<4)
+#define __USTORM_FCOE_AG_CONTEXT_AUX1_CF_EN_SHIFT 4
+#define __USTORM_FCOE_AG_CONTEXT_QUEUE0_CF_EN (0x1<<5)
+#define __USTORM_FCOE_AG_CONTEXT_QUEUE0_CF_EN_SHIFT 5
+#define __USTORM_FCOE_AG_CONTEXT_AUX3_CF_EN (0x1<<6)
+#define __USTORM_FCOE_AG_CONTEXT_AUX3_CF_EN_SHIFT 6
+#define __USTORM_FCOE_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+#elif defined(__LITTLE_ENDIAN)
+ u8 decision_rule_enable_bits;
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED_INV_CF_EN (0x1<<0)
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED_INV_CF_EN_SHIFT 0
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_EN (0x1<<1)
+#define USTORM_FCOE_AG_CONTEXT_COMPLETION_CF_EN_SHIFT 1
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_EN (0x1<<2)
+#define USTORM_FCOE_AG_CONTEXT_TX_CF_EN_SHIFT 2
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_EN (0x1<<3)
+#define __USTORM_FCOE_AG_CONTEXT_TIMER_CF_EN_SHIFT 3
+#define __USTORM_FCOE_AG_CONTEXT_AUX1_CF_EN (0x1<<4)
+#define __USTORM_FCOE_AG_CONTEXT_AUX1_CF_EN_SHIFT 4
+#define __USTORM_FCOE_AG_CONTEXT_QUEUE0_CF_EN (0x1<<5)
+#define __USTORM_FCOE_AG_CONTEXT_QUEUE0_CF_EN_SHIFT 5
+#define __USTORM_FCOE_AG_CONTEXT_AUX3_CF_EN (0x1<<6)
+#define __USTORM_FCOE_AG_CONTEXT_AUX3_CF_EN_SHIFT 6
+#define __USTORM_FCOE_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+ u8 decision_rules;
+#define USTORM_FCOE_AG_CONTEXT_CQ_DEC_RULE (0x7<<0)
+#define USTORM_FCOE_AG_CONTEXT_CQ_DEC_RULE_SHIFT 0
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL3_RULE (0x7<<3)
+#define __USTORM_FCOE_AG_CONTEXT_AGG_VAL3_RULE_SHIFT 3
+#define USTORM_FCOE_AG_CONTEXT_CQ_ARM_N_FLAG (0x1<<6)
+#define USTORM_FCOE_AG_CONTEXT_CQ_ARM_N_FLAG_SHIFT 6
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED1 (0x1<<7)
+#define __USTORM_FCOE_AG_CONTEXT_RESERVED1_SHIFT 7
+ u16 __reserved2;
+#endif
+};
+
+/*
+ * Ethernet context section
+ */
+struct xstorm_fcoe_eth_context_section {
+#if defined(__BIG_ENDIAN)
+ u8 remote_addr_4;
+ u8 remote_addr_5;
+ u8 local_addr_0;
+ u8 local_addr_1;
+#elif defined(__LITTLE_ENDIAN)
+ u8 local_addr_1;
+ u8 local_addr_0;
+ u8 remote_addr_5;
+ u8 remote_addr_4;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 remote_addr_0;
+ u8 remote_addr_1;
+ u8 remote_addr_2;
+ u8 remote_addr_3;
+#elif defined(__LITTLE_ENDIAN)
+ u8 remote_addr_3;
+ u8 remote_addr_2;
+ u8 remote_addr_1;
+ u8 remote_addr_0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 reserved_vlan_type;
+ u16 params;
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_VLAN_ID (0xFFF<<0)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_VLAN_ID_SHIFT 0
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_CFI (0x1<<12)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_CFI_SHIFT 12
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_PRIORITY (0x7<<13)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_PRIORITY_SHIFT 13
+#elif defined(__LITTLE_ENDIAN)
+ u16 params;
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_VLAN_ID (0xFFF<<0)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_VLAN_ID_SHIFT 0
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_CFI (0x1<<12)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_CFI_SHIFT 12
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_PRIORITY (0x7<<13)
+#define XSTORM_FCOE_ETH_CONTEXT_SECTION_PRIORITY_SHIFT 13
+ u16 reserved_vlan_type;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 local_addr_2;
+ u8 local_addr_3;
+ u8 local_addr_4;
+ u8 local_addr_5;
+#elif defined(__LITTLE_ENDIAN)
+ u8 local_addr_5;
+ u8 local_addr_4;
+ u8 local_addr_3;
+ u8 local_addr_2;
+#endif
+};
+
+/*
+ * Flags used in FCoE context section - 1 byte
+ */
+struct xstorm_fcoe_context_flags {
+ u8 flags;
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_PROC_Q (0x3<<0)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_PROC_Q_SHIFT 0
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_MID_SEQ (0x1<<2)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_MID_SEQ_SHIFT 2
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_EXCHANGE_CLEANUP_DEFFERED (0x1<<3)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_EXCHANGE_CLEANUP_DEFFERED_SHIFT 3
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_REC_SUPPORT (0x1<<4)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_REC_SUPPORT_SHIFT 4
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_SQ_TOGGLE (0x1<<5)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_SQ_TOGGLE_SHIFT 5
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_XFRQ_TOGGLE (0x1<<6)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_XFRQ_TOGGLE_SHIFT 6
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_ABTS_DEFFERED (0x1<<7)
+#define XSTORM_FCOE_CONTEXT_FLAGS_B_ABTS_DEFFERED_SHIFT 7
+};
+
+/*
+ * FCoE SQ element
+ */
+struct fcoe_sqe {
+ u16 wqe;
+#define FCOE_SQE_TASK_ID (0x7FFF<<0)
+#define FCOE_SQE_TASK_ID_SHIFT 0
+#define FCOE_SQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_SQE_TOGGLE_BIT_SHIFT 15
+};
+
+/*
+ * FCoE XFRQ element
+ */
+struct fcoe_xfrqe {
+ u16 wqe;
+#define FCOE_XFRQE_TASK_ID (0x7FFF<<0)
+#define FCOE_XFRQE_TASK_ID_SHIFT 0
+#define FCOE_XFRQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_XFRQE_TOGGLE_BIT_SHIFT 15
+};
+
+/*
+ * FCoE SQ\XFRQ element
+ */
+struct fcoe_cached_wqe {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_xfrqe xfrqe;
+ struct fcoe_sqe sqe;
+#elif defined(__LITTLE_ENDIAN)
+ struct fcoe_sqe sqe;
+ struct fcoe_xfrqe xfrqe;
+#endif
+};
+
+struct fcoe_task_ctx_entry_tx_only {
+ union fcoe_sgl_ctx sgl_ctx;
+};
+
+struct xstorm_fcoe_task_ctx_entry_rd {
+ struct fcoe_task_ctx_entry_tx_only tx_wr;
+ struct fcoe_task_ctx_entry_txwr_rxrd tx_wr_rx_rd;
+ struct fcoe_task_ctx_entry_tx_rx_cmn cmn;
+ struct fcoe_task_ctx_entry_rxwr_txrd rx_wr_tx_rd;
+};
+
+/*
+ * Cached SGEs
+ */
+struct common_fcoe_sgl {
+ struct fcoe_bd_ctx sge[2];
+};
+
+/*
+ * FCP_DATA parameters required for transmission
+ */
+struct xstorm_fcoe_fcp_data {
+ u32 io_rem;
+#if defined(__BIG_ENDIAN)
+ u16 cached_sge_off;
+ u8 cached_num_sges;
+ u8 cached_sge_idx;
+#elif defined(__LITTLE_ENDIAN)
+ u8 cached_sge_idx;
+ u8 cached_num_sges;
+ u16 cached_sge_off;
+#endif
+ struct common_fcoe_sgl cached_sgl;
+};
+
+/*
+ * FCoE context section
+ */
+struct xstorm_fcoe_context_section {
+#if defined(__BIG_ENDIAN)
+ u8 vlan_flag;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 vlan_flag;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 func_id;
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 func_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 sq_xfrq_lcq_confq_size;
+ u16 tx_max_fc_pay_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 tx_max_fc_pay_len;
+ u16 sq_xfrq_lcq_confq_size;
+#endif
+ u32 lcq_prod;
+#if defined(__BIG_ENDIAN)
+ u8 port_id;
+ u8 tx_max_conc_seqs_c3;
+ u8 seq_id;
+ struct xstorm_fcoe_context_flags tx_flags;
+#elif defined(__LITTLE_ENDIAN)
+ struct xstorm_fcoe_context_flags tx_flags;
+ u8 seq_id;
+ u8 tx_max_conc_seqs_c3;
+ u8 port_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 verify_tx_seq;
+ u8 func_mode;
+ u8 vnic_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 vnic_id;
+ u8 func_mode;
+ u16 verify_tx_seq;
+#endif
+ struct regpair confq_curr_page_addr;
+ struct fcoe_cached_wqe cached_wqe[8];
+ struct regpair lcq_base_addr;
+ struct xstorm_fcoe_task_ctx_entry_rd tce;
+ struct xstorm_fcoe_fcp_data fcp_data;
+#if defined(__BIG_ENDIAN)
+ u16 fcoe_tx_stat_params_ram_addr;
+ u16 cmng_port_ram_addr;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cmng_port_ram_addr;
+ u16 fcoe_tx_stat_params_ram_addr;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 fcp_cmd_pb_cmd_size;
+ u8 eth_hdr_size;
+ u16 pbf_addr;
+#elif defined(__LITTLE_ENDIAN)
+ u16 pbf_addr;
+ u8 eth_hdr_size;
+ u8 fcp_cmd_pb_cmd_size;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 reserved2[2];
+ u8 cos;
+ u8 dcb_version;
+#elif defined(__LITTLE_ENDIAN)
+ u8 dcb_version;
+ u8 cos;
+ u8 reserved2[2];
+#endif
+ u32 reserved3;
+ struct regpair reserved4[2];
+};
+
+/*
+ * Xstorm FCoE Storm Context
+ */
+struct xstorm_fcoe_st_context {
+ struct xstorm_fcoe_eth_context_section eth;
+ struct xstorm_fcoe_context_section fcoe;
+};
+
+/*
+ * Fcoe connection context
+ */
+struct fcoe_context {
+ struct ustorm_fcoe_st_context ustorm_st_context;
+ struct tstorm_fcoe_st_context tstorm_st_context;
+ struct xstorm_fcoe_ag_context xstorm_ag_context;
+ struct tstorm_fcoe_ag_context tstorm_ag_context;
+ struct ustorm_fcoe_ag_context ustorm_ag_context;
+ struct timers_block_context timers_context;
+ struct xstorm_fcoe_st_context xstorm_st_context;
+};
+
+/*
* iSCSI context region, used only in iSCSI
*/
struct ustorm_iscsi_rq_db {
@@ -2268,6 +3792,577 @@ struct iscsi_context {
};
/*
+ * FCoE KCQ CQE parameters
+ */
+union fcoe_kcqe_params {
+ u32 reserved0[4];
+};
+
+/*
+ * FCoE KCQ CQE
+ */
+struct fcoe_kcqe {
+ u32 fcoe_conn_id;
+ u32 completion_status;
+ u32 fcoe_conn_context_id;
+ union fcoe_kcqe_params params;
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KCQE_RESERVED0 (0x7<<0)
+#define FCOE_KCQE_RESERVED0_SHIFT 0
+#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3)
+#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3
+#define FCOE_KCQE_LAYER_CODE (0x7<<4)
+#define FCOE_KCQE_LAYER_CODE_SHIFT 4
+#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7)
+#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+ u16 qe_self_seq;
+ u8 op_code;
+ u8 flags;
+#define FCOE_KCQE_RESERVED0 (0x7<<0)
+#define FCOE_KCQE_RESERVED0_SHIFT 0
+#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3)
+#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3
+#define FCOE_KCQE_LAYER_CODE (0x7<<4)
+#define FCOE_KCQE_LAYER_CODE_SHIFT 4
+#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7)
+#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE KWQE header
+ */
+struct fcoe_kwqe_header {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0
+#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7
+ u8 op_code;
+#elif defined(__LITTLE_ENDIAN)
+ u8 op_code;
+ u8 flags;
+#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0
+#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE firmware init request 1
+ */
+struct fcoe_kwqe_init1 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 num_tasks;
+#elif defined(__LITTLE_ENDIAN)
+ u16 num_tasks;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 task_list_pbl_addr_lo;
+ u32 task_list_pbl_addr_hi;
+ u32 dummy_buffer_addr_lo;
+ u32 dummy_buffer_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 rq_num_wqes;
+ u16 sq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_num_wqes;
+ u16 rq_num_wqes;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 cq_num_wqes;
+ u16 rq_buffer_log_size;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rq_buffer_log_size;
+ u16 cq_num_wqes;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0)
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4)
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4
+#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7
+ u8 num_sessions_log;
+ u16 mtu;
+#elif defined(__LITTLE_ENDIAN)
+ u16 mtu;
+ u8 num_sessions_log;
+ u8 flags;
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0)
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4)
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4
+#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE firmware init request 2
+ */
+struct fcoe_kwqe_init2 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 hash_tbl_pbl_addr_lo;
+ u32 hash_tbl_pbl_addr_hi;
+ u32 t2_hash_tbl_addr_lo;
+ u32 t2_hash_tbl_addr_hi;
+ u32 t2_ptr_hash_tbl_addr_lo;
+ u32 t2_ptr_hash_tbl_addr_hi;
+ u32 free_list_count;
+};
+
+/*
+ * FCoE firmware init request 3
+ */
+struct fcoe_kwqe_init3 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 error_bit_map_lo;
+ u32 error_bit_map_hi;
+#if defined(__BIG_ENDIAN)
+ u8 reserved21[3];
+ u8 cached_session_enable;
+#elif defined(__LITTLE_ENDIAN)
+ u8 cached_session_enable;
+ u8 reserved21[3];
+#endif
+ u32 reserved2[4];
+};
+
+/*
+ * FCoE connection offload request 1
+ */
+struct fcoe_kwqe_conn_offload1 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 fcoe_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 fcoe_conn_id;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 sq_addr_lo;
+ u32 sq_addr_hi;
+ u32 rq_pbl_addr_lo;
+ u32 rq_pbl_addr_hi;
+ u32 rq_first_pbe_addr_lo;
+ u32 rq_first_pbe_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u16 rq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rq_prod;
+ u16 reserved0;
+#endif
+};
+
+/*
+ * FCoE connection offload request 2
+ */
+struct fcoe_kwqe_conn_offload2 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 tx_max_fc_pay_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 tx_max_fc_pay_len;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 cq_addr_lo;
+ u32 cq_addr_hi;
+ u32 xferq_addr_lo;
+ u32 xferq_addr_hi;
+ u32 conn_db_addr_lo;
+ u32 conn_db_addr_hi;
+ u32 reserved1;
+};
+
+/*
+ * FCoE connection offload request 3
+ */
+struct fcoe_kwqe_conn_offload3 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13
+#elif defined(__LITTLE_ENDIAN)
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13
+ struct fcoe_kwqe_header hdr;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 tx_max_conc_seqs_c3;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 tx_max_conc_seqs_c3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 flags;
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7
+#endif
+ u32 reserved;
+ u32 confq_first_pbe_addr_lo;
+ u32 confq_first_pbe_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 rx_max_fc_pay_len;
+ u16 tx_total_conc_seqs;
+#elif defined(__LITTLE_ENDIAN)
+ u16 tx_total_conc_seqs;
+ u16 rx_max_fc_pay_len;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 rx_open_seqs_exch_c3;
+ u8 rx_max_conc_seqs_c3;
+ u16 rx_total_conc_seqs;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_total_conc_seqs;
+ u8 rx_max_conc_seqs_c3;
+ u8 rx_open_seqs_exch_c3;
+#endif
+};
+
+/*
+ * FCoE connection offload request 4
+ */
+struct fcoe_kwqe_conn_offload4 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u8 reserved2;
+ u8 e_d_tov_timer_val;
+#elif defined(__LITTLE_ENDIAN)
+ u8 e_d_tov_timer_val;
+ u8 reserved2;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u8 src_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u8 dst_mac_addr_hi16[2];
+ u8 src_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 src_mac_addr_hi16[2];
+ u8 dst_mac_addr_hi16[2];
+#endif
+ u8 dst_mac_addr_lo32[4];
+ u32 lcq_addr_lo;
+ u32 lcq_addr_hi;
+ u32 confq_pbl_base_addr_lo;
+ u32 confq_pbl_base_addr_hi;
+};
+
+/*
+ * FCoE connection enable request
+ */
+struct fcoe_kwqe_conn_enable_disable {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u8 src_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13
+ u8 src_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 src_mac_addr_hi16[2];
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13
+#endif
+ u8 dst_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 dst_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 dst_mac_addr_hi16[2];
+ u16 reserved1;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 vlan_flag;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 vlan_flag;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 reserved3;
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 reserved3;
+#endif
+ u32 context_id;
+ u32 conn_id;
+ u32 reserved4;
+};
+
+/*
+ * FCoE connection destroy request
+ */
+struct fcoe_kwqe_conn_destroy {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 context_id;
+ u32 conn_id;
+ u32 reserved1[5];
+};
+
+/*
+ * FCoe destroy request
+ */
+struct fcoe_kwqe_destroy {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 reserved1[7];
+};
+
+/*
+ * FCoe statistics request
+ */
+struct fcoe_kwqe_stat {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 stat_params_addr_lo;
+ u32 stat_params_addr_hi;
+ u32 reserved1[5];
+};
+
+/*
+ * FCoE KWQ WQE
+ */
+union fcoe_kwqe {
+ struct fcoe_kwqe_init1 init1;
+ struct fcoe_kwqe_init2 init2;
+ struct fcoe_kwqe_init3 init3;
+ struct fcoe_kwqe_conn_offload1 conn_offload1;
+ struct fcoe_kwqe_conn_offload2 conn_offload2;
+ struct fcoe_kwqe_conn_offload3 conn_offload3;
+ struct fcoe_kwqe_conn_offload4 conn_offload4;
+ struct fcoe_kwqe_conn_enable_disable conn_enable_disable;
+ struct fcoe_kwqe_conn_destroy conn_destroy;
+ struct fcoe_kwqe_destroy destroy;
+ struct fcoe_kwqe_stat statistics;
+};
+
+struct fcoe_task_ctx_entry {
+ struct fcoe_task_ctx_entry_tx_only tx_wr_only;
+ struct fcoe_task_ctx_entry_txwr_rxrd tx_wr_rx_rd;
+ struct fcoe_task_ctx_entry_tx_rx_cmn cmn;
+ struct fcoe_task_ctx_entry_rxwr_txrd rx_wr_tx_rd;
+ struct fcoe_task_ctx_entry_rx_only rx_wr_only;
+ u32 reserved[4];
+};
+
+/*
+ * FCoE connection enable\disable params passed by driver to FW in FCoE enable ramrod
+ */
+struct fcoe_conn_enable_disable_ramrod_params {
+ struct fcoe_kwqe_conn_enable_disable enable_disable_kwqe;
+};
+
+
+/*
+ * FCoE connection offload params passed by driver to FW in FCoE offload ramrod
+ */
+struct fcoe_conn_offload_ramrod_params {
+ struct fcoe_kwqe_conn_offload1 offload_kwqe1;
+ struct fcoe_kwqe_conn_offload2 offload_kwqe2;
+ struct fcoe_kwqe_conn_offload3 offload_kwqe3;
+ struct fcoe_kwqe_conn_offload4 offload_kwqe4;
+};
+
+/*
+ * FCoE init params passed by driver to FW in FCoE init ramrod
+ */
+struct fcoe_init_ramrod_params {
+ struct fcoe_kwqe_init1 init_kwqe1;
+ struct fcoe_kwqe_init2 init_kwqe2;
+ struct fcoe_kwqe_init3 init_kwqe3;
+ struct regpair eq_addr;
+ struct regpair eq_next_page_addr;
+#if defined(__BIG_ENDIAN)
+ u16 sb_num;
+ u16 eq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 eq_prod;
+ u16 sb_num;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 reserved0;
+ u8 sb_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 sb_id;
+ u8 reserved0;
+ u16 reserved1;
+#endif
+};
+
+
+/*
+ * FCoE statistics params buffer passed by driver to FW in FCoE statistics ramrod
+ */
+struct fcoe_stat_ramrod_params {
+ struct fcoe_kwqe_stat stat_kwqe;
+};
+
+
+/*
+ * FCoE 16-bits vlan structure
+ */
+struct fcoe_vlan_fields {
+ u16 fields;
+#define FCOE_VLAN_FIELDS_VID (0xFFF<<0)
+#define FCOE_VLAN_FIELDS_VID_SHIFT 0
+#define FCOE_VLAN_FIELDS_CLI (0x1<<12)
+#define FCOE_VLAN_FIELDS_CLI_SHIFT 12
+#define FCOE_VLAN_FIELDS_PRI (0x7<<13)
+#define FCOE_VLAN_FIELDS_PRI_SHIFT 13
+};
+
+
+/*
+ * FCoE 16-bits vlan union
+ */
+union fcoe_vlan_field_union {
+ struct fcoe_vlan_fields fields;
+ u16 val;
+};
+
+/*
+ * Parameters used for Class 2 verifications
+ */
+struct ustorm_fcoe_c2_params {
+#if defined(__BIG_ENDIAN)
+ u16 e2e_credit;
+ u16 con_seq;
+#elif defined(__LITTLE_ENDIAN)
+ u16 con_seq;
+ u16 e2e_credit;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 ackq_prod;
+ u16 open_seq_per_exch;
+#elif defined(__LITTLE_ENDIAN)
+ u16 open_seq_per_exch;
+ u16 ackq_prod;
+#endif
+ struct regpair ackq_pbl_base;
+ struct regpair ackq_cur_seg;
+};
+
+/*
+ * Parameters used for Class 2 verifications
+ */
+struct xstorm_fcoe_c2_params {
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u8 ackq_x_prod;
+ u8 max_conc_seqs_c2;
+#elif defined(__LITTLE_ENDIAN)
+ u8 max_conc_seqs_c2;
+ u8 ackq_x_prod;
+ u16 reserved0;
+#endif
+ struct regpair ackq_pbl_base;
+ struct regpair ackq_cur_seg;
+};
+
+/*
* Buffer per connection, used in Tstorm
*/
struct iscsi_conn_buf {
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index 0dbeaec4f03a..9f44e0ffe003 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -1,6 +1,6 @@
/* cnic_if.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2010 Broadcom Corporation
+ * Copyright (c) 2006-2011 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,22 +12,31 @@
#ifndef CNIC_IF_H
#define CNIC_IF_H
-#define CNIC_MODULE_VERSION "2.2.6"
-#define CNIC_MODULE_RELDATE "Oct 12, 2010"
+#define CNIC_MODULE_VERSION "2.2.12"
+#define CNIC_MODULE_RELDATE "Jan 03, 2011"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
-#define CNIC_ULP_L4 2
-#define MAX_CNIC_ULP_TYPE_EXT 2
-#define MAX_CNIC_ULP_TYPE 3
+#define CNIC_ULP_FCOE 2
+#define CNIC_ULP_L4 3
+#define MAX_CNIC_ULP_TYPE_EXT 3
+#define MAX_CNIC_ULP_TYPE 4
struct kwqe {
u32 kwqe_op_flag;
+#define KWQE_QID_SHIFT 8
#define KWQE_OPCODE_MASK 0x00ff0000
#define KWQE_OPCODE_SHIFT 16
-#define KWQE_FLAGS_LAYER_SHIFT 28
#define KWQE_OPCODE(x) ((x & KWQE_OPCODE_MASK) >> KWQE_OPCODE_SHIFT)
+#define KWQE_LAYER_MASK 0x70000000
+#define KWQE_LAYER_SHIFT 28
+#define KWQE_FLAGS_LAYER_MASK_L2 (2<<28)
+#define KWQE_FLAGS_LAYER_MASK_L3 (3<<28)
+#define KWQE_FLAGS_LAYER_MASK_L4 (4<<28)
+#define KWQE_FLAGS_LAYER_MASK_L5_RDMA (5<<28)
+#define KWQE_FLAGS_LAYER_MASK_L5_ISCSI (6<<28)
+#define KWQE_FLAGS_LAYER_MASK_L5_FCOE (7<<28)
u32 kwqe_info0;
u32 kwqe_info1;
@@ -62,6 +71,7 @@ struct kcqe {
#define KCQE_FLAGS_LAYER_MASK_L4 (4<<28)
#define KCQE_FLAGS_LAYER_MASK_L5_RDMA (5<<28)
#define KCQE_FLAGS_LAYER_MASK_L5_ISCSI (6<<28)
+ #define KCQE_FLAGS_LAYER_MASK_L5_FCOE (7<<28)
#define KCQE_FLAGS_NEXT (1<<31)
#define KCQE_FLAGS_OPCODE_MASK (0xff<<16)
#define KCQE_FLAGS_OPCODE_SHIFT (16)
@@ -301,7 +311,7 @@ struct cnic_ulp_ops {
void (*cm_abort_complete)(struct cnic_sock *);
void (*cm_remote_close)(struct cnic_sock *);
void (*cm_remote_abort)(struct cnic_sock *);
- void (*iscsi_nl_send_msg)(struct cnic_dev *dev, u32 msg_type,
+ int (*iscsi_nl_send_msg)(void *ulp_ctx, u32 msg_type,
char *data, u16 data_size);
struct module *owner;
atomic_t ref_count;
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 81475cc80e1c..80c2feeefec5 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -59,7 +59,6 @@ static struct sockaddr default_mac = {
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
struct mii_if_info mii_if;
/* Tx control lock. This protects the transmit buffer ring
@@ -1059,7 +1058,7 @@ e100_tx_timeout(struct net_device *dev)
/* remember we got an error */
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* reset the TX DMA in case it has hung on something */
@@ -1157,7 +1156,7 @@ e100rxtx_interrupt(int irq, void *dev_id)
* allocate a new buffer to put a packet in.
*/
e100_rx(dev);
- np->stats.rx_packets++;
+ dev->stats.rx_packets++;
/* restart/continue on the channel, for safety */
*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
/* clear dma channel 1 eop/descr irq bits */
@@ -1173,8 +1172,8 @@ e100rxtx_interrupt(int irq, void *dev_id)
/* Report any packets that have been sent */
while (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST &&
(netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) {
- np->stats.tx_bytes += myFirstTxDesc->skb->len;
- np->stats.tx_packets++;
+ dev->stats.tx_bytes += myFirstTxDesc->skb->len;
+ dev->stats.tx_packets++;
/* dma is ready with the transmission of the data in tx_skb, so now
we can release the skb memory */
@@ -1197,7 +1196,6 @@ static irqreturn_t
e100nw_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct net_local *np = netdev_priv(dev);
unsigned long irqbits = *R_IRQ_MASK0_RD;
/* check for underrun irq */
@@ -1205,13 +1203,13 @@ e100nw_interrupt(int irq, void *dev_id)
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
D(printk("ethernet receiver underrun!\n"));
}
/* check for overrun irq */
if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
- update_rx_stats(&np->stats); /* this will ack the irq */
+ update_rx_stats(&dev->stats); /* this will ack the irq */
D(printk("ethernet receiver overrun!\n"));
}
/* check for excessive collision irq */
@@ -1219,7 +1217,7 @@ e100nw_interrupt(int irq, void *dev_id)
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
D(printk("ethernet excessive collisions!\n"));
}
return IRQ_HANDLED;
@@ -1250,7 +1248,7 @@ e100_rx(struct net_device *dev)
spin_unlock(&np->led_lock);
length = myNextRxDesc->descr.hw_len - 4;
- np->stats.rx_bytes += length;
+ dev->stats.rx_bytes += length;
#ifdef ETHDEBUG
printk("Got a packet of length %d:\n", length);
@@ -1268,7 +1266,7 @@ e100_rx(struct net_device *dev)
/* Small packet, copy data */
skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
if (!skb) {
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
goto update_nextrxdesc;
}
@@ -1294,7 +1292,7 @@ e100_rx(struct net_device *dev)
int align;
struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
if (!new_skb) {
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
goto update_nextrxdesc;
}
@@ -1333,8 +1331,6 @@ e100_rx(struct net_device *dev)
static int
e100_close(struct net_device *dev)
{
- struct net_local *np = netdev_priv(dev);
-
printk(KERN_INFO "Closing %s.\n", dev->name);
netif_stop_queue(dev);
@@ -1366,8 +1362,8 @@ e100_close(struct net_device *dev)
/* Update the statistics here. */
- update_rx_stats(&np->stats);
- update_tx_stats(&np->stats);
+ update_rx_stats(&dev->stats);
+ update_tx_stats(&dev->stats);
/* Stop speed/duplex timers */
del_timer(&speed_timer);
@@ -1545,11 +1541,11 @@ e100_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
- update_rx_stats(&lp->stats);
- update_tx_stats(&lp->stats);
+ update_rx_stats(&dev->stats);
+ update_tx_stats(&dev->stats);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
/*
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 35cd36729155..2028da95afa1 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -292,7 +292,7 @@ unknown:
*/
static int ael2005_setup_sr_edc(struct cphy *phy)
{
- static struct reg_val regs[] = {
+ static const struct reg_val regs[] = {
{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 },
{ MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a },
{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
@@ -324,11 +324,11 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
{
- static struct reg_val regs[] = {
+ static const struct reg_val regs[] = {
{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 },
{ 0, 0, 0, 0 }
};
- static struct reg_val preemphasis[] = {
+ static const struct reg_val preemphasis[] = {
{ MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 },
{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
{ 0, 0, 0, 0 }
@@ -393,7 +393,7 @@ static int ael2005_intr_clear(struct cphy *phy)
static int ael2005_reset(struct cphy *phy, int wait)
{
- static struct reg_val regs0[] = {
+ static const struct reg_val regs0[] = {
{ MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 },
{ MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 },
{ MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 },
@@ -403,7 +403,7 @@ static int ael2005_reset(struct cphy *phy, int wait)
{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 },
{ 0, 0, 0, 0 }
};
- static struct reg_val regs1[] = {
+ static const struct reg_val regs1[] = {
{ MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 },
{ MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 },
{ 0, 0, 0, 0 }
@@ -522,7 +522,7 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
*/
static int ael2020_setup_sr_edc(struct cphy *phy)
{
- static struct reg_val regs[] = {
+ static const struct reg_val regs[] = {
/* set CDR offset to 10 */
{ MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
@@ -551,20 +551,20 @@ static int ael2020_setup_sr_edc(struct cphy *phy)
static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
{
/* set uC to 40MHz */
- static struct reg_val uCclock40MHz[] = {
+ static const struct reg_val uCclock40MHz[] = {
{ MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
{ MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
{ 0, 0, 0, 0 }
};
/* activate uC clock */
- static struct reg_val uCclockActivate[] = {
+ static const struct reg_val uCclockActivate[] = {
{ MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
{ 0, 0, 0, 0 }
};
/* set PC to start of SRAM and activate uC */
- static struct reg_val uCactivate[] = {
+ static const struct reg_val uCactivate[] = {
{ MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
{ 0, 0, 0, 0 }
@@ -624,7 +624,7 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
*/
static int ael2020_intr_enable(struct cphy *phy)
{
- struct reg_val regs[] = {
+ static const struct reg_val regs[] = {
/* output Module's Loss Of Signal (LOS) to LED */
{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
0xffff, 0x4 },
@@ -664,7 +664,7 @@ static int ael2020_intr_enable(struct cphy *phy)
*/
static int ael2020_intr_disable(struct cphy *phy)
{
- struct reg_val regs[] = {
+ static const struct reg_val regs[] = {
/* reset "link status" LED to "off" */
{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
@@ -701,7 +701,7 @@ static int ael2020_intr_clear(struct cphy *phy)
return err ? err : t3_phy_lasi_intr_clear(phy);
}
-static struct reg_val ael2020_reset_regs[] = {
+static const struct reg_val ael2020_reset_regs[] = {
/* Erratum #2: CDRLOL asserted, causing PMA link down status */
{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 407d4e272075..4d538a4e9d55 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1359,6 +1359,7 @@ out:
static int offload_close(struct t3cdev *tdev)
{
struct adapter *adapter = tdev2adap(tdev);
+ struct t3c_data *td = T3C_DATA(tdev);
if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
return 0;
@@ -1369,7 +1370,7 @@ static int offload_close(struct t3cdev *tdev)
sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
/* Flush work scheduled while releasing TIDs */
- flush_scheduled_work();
+ flush_work_sync(&td->tid_release_task);
tdev->lldev = NULL;
cxgb3_set_dummy_ops(tdev);
@@ -3006,12 +3007,11 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
struct adapter *adapter = pci_get_drvdata(pdev);
- int ret;
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
- ret = t3_adapter_error(adapter, 0, 0);
+ t3_adapter_error(adapter, 0, 0);
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
@@ -3341,7 +3341,6 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->name = adapter->port[i]->name;
__set_bit(i, &adapter->registered_device_map);
- netif_tx_stop_all_queues(adapter->port[i]);
}
}
if (!adapter->registered_device_map) {
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index bcf07532953d..ef02aa68c926 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1164,12 +1164,10 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
*/
void *cxgb_alloc_mem(unsigned long size)
{
- void *p = kmalloc(size, GFP_KERNEL);
+ void *p = kzalloc(size, GFP_KERNEL);
if (!p)
- p = vmalloc(size);
- if (p)
- memset(p, 0, size);
+ p = vzalloc(size);
return p;
}
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index a8766fb2f9ab..e13b7fe9d082 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -318,7 +318,7 @@ static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
/*
* Initialization that requires the OS and protocol layers to already
- * be intialized goes here.
+ * be initialized goes here.
*/
int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
unsigned int nroutes)
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 3a6adf0b3e9d..d55db6b38e7b 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -607,7 +607,7 @@ struct t3_vpd {
*
* Read a 32-bit word from a location in VPD EEPROM using the card's PCI
* VPD ROM capability. A zero is written to the flag bit when the
- * addres is written to the control register. The hardware device will
+ * address is written to the control register. The hardware device will
* set the flag to 1 when 4 bytes have been read into the data register.
*/
int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
@@ -1562,7 +1562,7 @@ static void tp_intr_handler(struct adapter *adapter)
{0}
};
- static struct intr_info tp_intr_info_t3c[] = {
+ static const struct intr_info tp_intr_info_t3c[] = {
{0x1fffffff, "TP parity error", -1, 1},
{F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1},
{F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1},
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index 3d4253d311eb..01d49eaa44d2 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -482,11 +482,9 @@ struct adapter {
void __iomem *regs;
struct pci_dev *pdev;
struct device *pdev_dev;
- unsigned long registered_device_map;
unsigned int fn;
unsigned int flags;
- const char *name;
int msg_enable;
struct adapter_params params;
@@ -497,7 +495,7 @@ struct adapter {
struct {
unsigned short vec;
- char desc[14];
+ char desc[IFNAMSIZ + 10];
} msix_info[MAX_INGQ + 1];
struct sge sge;
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index f17703f410b3..059c1eec8c3f 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -522,39 +522,33 @@ static irqreturn_t t4_nondata_intr(int irq, void *cookie)
*/
static void name_msix_vecs(struct adapter *adap)
{
- int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc) - 1;
+ int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc);
/* non-data interrupts */
- snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
- adap->msix_info[0].desc[n] = 0;
+ snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name);
/* FW events */
- snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", adap->name);
- adap->msix_info[1].desc[n] = 0;
+ snprintf(adap->msix_info[1].desc, n, "%s-FWeventq",
+ adap->port[0]->name);
/* Ethernet queues */
for_each_port(adap, j) {
struct net_device *d = adap->port[j];
const struct port_info *pi = netdev_priv(d);
- for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+ for (i = 0; i < pi->nqsets; i++, msi_idx++)
snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d",
d->name, i);
- adap->msix_info[msi_idx].desc[n] = 0;
- }
}
/* offload queues */
- for_each_ofldrxq(&adap->sge, i) {
- snprintf(adap->msix_info[msi_idx].desc, n, "%s-ofld%d",
- adap->name, i);
- adap->msix_info[msi_idx++].desc[n] = 0;
- }
- for_each_rdmarxq(&adap->sge, i) {
- snprintf(adap->msix_info[msi_idx].desc, n, "%s-rdma%d",
- adap->name, i);
- adap->msix_info[msi_idx++].desc[n] = 0;
- }
+ for_each_ofldrxq(&adap->sge, i)
+ snprintf(adap->msix_info[msi_idx++].desc, n, "%s-ofld%d",
+ adap->port[0]->name, i);
+
+ for_each_rdmarxq(&adap->sge, i)
+ snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d",
+ adap->port[0]->name, i);
}
static int request_msix_queue_irqs(struct adapter *adap)
@@ -868,12 +862,10 @@ out: release_firmware(fw);
*/
void *t4_alloc_mem(size_t size)
{
- void *p = kmalloc(size, GFP_KERNEL);
+ void *p = kzalloc(size, GFP_KERNEL);
if (!p)
- p = vmalloc(size);
- if (p)
- memset(p, 0, size);
+ p = vzalloc(size);
return p;
}
@@ -1377,7 +1369,12 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
} else if (type == FW_PORT_TYPE_KR)
v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full;
else if (type == FW_PORT_TYPE_BP_AP)
- v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC;
+ v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+ SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full;
+ else if (type == FW_PORT_TYPE_BP4_AP)
+ v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+ SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full |
+ SUPPORTED_10000baseKX4_Full;
else if (type == FW_PORT_TYPE_FIBER_XFI ||
type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
v |= SUPPORTED_FIBRE;
@@ -2668,7 +2665,7 @@ static int cxgb_up(struct adapter *adap)
} else {
err = request_irq(adap->pdev->irq, t4_intr_handler(adap),
(adap->flags & USING_MSI) ? 0 : IRQF_SHARED,
- adap->name, adap);
+ adap->port[0]->name, adap);
if (err)
goto irq_err;
}
@@ -2719,10 +2716,6 @@ static int cxgb_open(struct net_device *dev)
return err;
}
- netif_set_real_num_tx_queues(dev, pi->nqsets);
- err = netif_set_real_num_rx_queues(dev, pi->nqsets);
- if (err)
- return err;
err = link_start(dev);
if (!err)
netif_tx_start_all_queues(dev);
@@ -3491,49 +3484,53 @@ static int __devinit init_rss(struct adapter *adap)
return 0;
}
-static void __devinit print_port_info(struct adapter *adap)
+static void __devinit print_port_info(const struct net_device *dev)
{
static const char *base[] = {
"R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
- "KX", "KR", "KR SFP+", "KR FEC"
+ "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4"
};
- int i;
char buf[80];
+ char *bufp = buf;
const char *spd = "";
+ const struct port_info *pi = netdev_priv(dev);
+ const struct adapter *adap = pi->adapter;
if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_2_5GB)
spd = " 2.5 GT/s";
else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB)
spd = " 5 GT/s";
- for_each_port(adap, i) {
- struct net_device *dev = adap->port[i];
- const struct port_info *pi = netdev_priv(dev);
- char *bufp = buf;
+ if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
+ bufp += sprintf(bufp, "100/");
+ if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
+ bufp += sprintf(bufp, "1000/");
+ if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
+ bufp += sprintf(bufp, "10G/");
+ if (bufp != buf)
+ --bufp;
+ sprintf(bufp, "BASE-%s", base[pi->port_type]);
- if (!test_bit(i, &adap->registered_device_map))
- continue;
+ netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
+ adap->params.vpd.id, adap->params.rev, buf,
+ is_offload(adap) ? "R" : "", adap->params.pci.width, spd,
+ (adap->flags & USING_MSIX) ? " MSI-X" :
+ (adap->flags & USING_MSI) ? " MSI" : "");
+ netdev_info(dev, "S/N: %s, E/C: %s\n",
+ adap->params.vpd.sn, adap->params.vpd.ec);
+}
- if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
- bufp += sprintf(bufp, "100/");
- if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
- bufp += sprintf(bufp, "1000/");
- if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
- bufp += sprintf(bufp, "10G/");
- if (bufp != buf)
- --bufp;
- sprintf(bufp, "BASE-%s", base[pi->port_type]);
+static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev)
+{
+ u16 v;
+ int pos;
- netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
- adap->params.vpd.id, adap->params.rev,
- buf, is_offload(adap) ? "R" : "",
- adap->params.pci.width, spd,
- (adap->flags & USING_MSIX) ? " MSI-X" :
- (adap->flags & USING_MSI) ? " MSI" : "");
- if (adap->name == dev->name)
- netdev_info(dev, "S/N: %s, E/C: %s\n",
- adap->params.vpd.sn, adap->params.vpd.ec);
+ pos = pci_pcie_cap(dev);
+ if (pos > 0) {
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &v);
+ v |= PCI_EXP_DEVCTL_RELAX_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, v);
}
}
@@ -3611,6 +3608,7 @@ static int __devinit init_one(struct pci_dev *pdev,
}
pci_enable_pcie_error_reporting(pdev);
+ enable_pcie_relaxed_ordering(pdev);
pci_set_master(pdev);
pci_save_state(pdev);
@@ -3630,7 +3628,6 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
adapter->fn = func;
- adapter->name = pci_name(pdev);
adapter->msg_enable = dflt_msg_enable;
memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@@ -3721,28 +3718,24 @@ static int __devinit init_one(struct pci_dev *pdev,
* register at least one net device.
*/
for_each_port(adapter, i) {
+ pi = adap2pinfo(adapter, i);
+ netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets);
+ netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets);
+
err = register_netdev(adapter->port[i]);
if (err)
- dev_warn(&pdev->dev,
- "cannot register net device %s, skipping\n",
- adapter->port[i]->name);
- else {
- /*
- * Change the name we use for messages to the name of
- * the first successfully registered interface.
- */
- if (!adapter->registered_device_map)
- adapter->name = adapter->port[i]->name;
-
- __set_bit(i, &adapter->registered_device_map);
- adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
- netif_tx_stop_all_queues(adapter->port[i]);
- }
+ break;
+ adapter->chan_map[pi->tx_chan] = i;
+ print_port_info(adapter->port[i]);
}
- if (!adapter->registered_device_map) {
+ if (i == 0) {
dev_err(&pdev->dev, "could not register any net devices\n");
goto out_free_dev;
}
+ if (err) {
+ dev_warn(&pdev->dev, "only %d net devices registered\n", i);
+ err = 0;
+ };
if (cxgb4_debugfs_root) {
adapter->debugfs_root = debugfs_create_dir(pci_name(pdev),
@@ -3753,8 +3746,6 @@ static int __devinit init_one(struct pci_dev *pdev,
if (is_offload(adapter))
attach_ulds(adapter);
- print_port_info(adapter);
-
sriov:
#ifdef CONFIG_PCI_IOV
if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0)
@@ -3793,7 +3784,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
detach_ulds(adapter);
for_each_port(adapter, i)
- if (test_bit(i, &adapter->registered_device_map))
+ if (adapter->port[i]->reg_state == NETREG_REGISTERED)
unregister_netdev(adapter->port[i]);
if (adapter->debugfs_root)
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index 17022258ed68..311471b439a8 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -579,6 +579,7 @@ static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
* @phys: the physical address of the allocated ring
* @metadata: address of the array holding the SW state for the ring
* @stat_size: extra space in HW ring for status information
+ * @node: preferred node for memory allocations
*
* Allocates resources for an SGE descriptor ring, such as Tx queues,
* free buffer lists, or response queues. Each SGE ring requires
@@ -590,7 +591,7 @@ static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
*/
static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size,
size_t sw_size, dma_addr_t *phys, void *metadata,
- size_t stat_size)
+ size_t stat_size, int node)
{
size_t len = nelem * elem_size + stat_size;
void *s = NULL;
@@ -599,7 +600,7 @@ static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size,
if (!p)
return NULL;
if (sw_size) {
- s = kcalloc(nelem, sw_size, GFP_KERNEL);
+ s = kzalloc_node(nelem * sw_size, GFP_KERNEL, node);
if (!s) {
dma_free_coherent(dev, len, p, *phys);
@@ -1982,7 +1983,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
iq->size = roundup(iq->size, 16);
iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0,
- &iq->phys_addr, NULL, 0);
+ &iq->phys_addr, NULL, 0, NUMA_NO_NODE);
if (!iq->desc)
return -ENOMEM;
@@ -2008,12 +2009,14 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
fl->size = roundup(fl->size, 8);
fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64),
sizeof(struct rx_sw_desc), &fl->addr,
- &fl->sdesc, STAT_LEN);
+ &fl->sdesc, STAT_LEN, NUMA_NO_NODE);
if (!fl->desc)
goto fl_nomem;
flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc);
c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN |
+ FW_IQ_CMD_FL0FETCHRO(1) |
+ FW_IQ_CMD_FL0DATARO(1) |
FW_IQ_CMD_FL0PADEN);
c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) |
FW_IQ_CMD_FL0FBMAX(3));
@@ -2093,7 +2096,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
- &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+ &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
+ netdev_queue_numa_node_read(netdevq));
if (!txq->q.desc)
return -ENOMEM;
@@ -2106,6 +2110,7 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) |
FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) |
+ FW_EQ_ETH_CMD_FETCHRO(1) |
FW_EQ_ETH_CMD_IQID(iqid));
c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN(2) |
FW_EQ_ETH_CMD_FBMAX(3) |
@@ -2144,7 +2149,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
txq->q.desc = alloc_ring(adap->pdev_dev, nentries,
sizeof(struct tx_desc), 0, &txq->q.phys_addr,
- NULL, 0);
+ NULL, 0, NUMA_NO_NODE);
if (!txq->q.desc)
return -ENOMEM;
@@ -2158,6 +2163,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
c.physeqid_pkd = htonl(0);
c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE(2) |
FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) |
+ FW_EQ_CTRL_CMD_FETCHRO |
FW_EQ_CTRL_CMD_IQID(iqid));
c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN(2) |
FW_EQ_CTRL_CMD_FBMAX(3) |
@@ -2194,7 +2200,8 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
- &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+ &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
+ NUMA_NO_NODE);
if (!txq->q.desc)
return -ENOMEM;
@@ -2207,6 +2214,7 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c));
c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) |
FW_EQ_OFLD_CMD_PCIECHN(pi->tx_chan) |
+ FW_EQ_OFLD_CMD_FETCHRO(1) |
FW_EQ_OFLD_CMD_IQID(iqid));
c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN(2) |
FW_EQ_OFLD_CMD_FBMAX(3) |
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index bb813d94aea8..b9fd8a6f2cc4 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -183,7 +183,7 @@ static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
void *rpl, bool sleep_ok)
{
- static int delay[] = {
+ static const int delay[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
};
@@ -330,18 +330,6 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
return 0;
}
-/*
- * Partial EEPROM Vital Product Data structure. Includes only the ID and
- * VPD-R header.
- */
-struct t4_vpd_hdr {
- u8 id_tag;
- u8 id_len[2];
- u8 id_data[ID_LEN];
- u8 vpdr_tag;
- u8 vpdr_len[2];
-};
-
#define EEPROM_STAT_ADDR 0x7bfc
#define VPD_BASE 0
#define VPD_LEN 512
@@ -370,25 +358,38 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
int i, ret;
- int ec, sn, v2;
+ int ec, sn;
u8 vpd[VPD_LEN], csum;
- unsigned int vpdr_len;
- const struct t4_vpd_hdr *v;
+ unsigned int vpdr_len, kw_offset, id_len;
ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
if (ret < 0)
return ret;
- v = (const struct t4_vpd_hdr *)vpd;
- vpdr_len = pci_vpd_lrdt_size(&v->vpdr_tag);
- if (vpdr_len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
+ if (vpd[0] != PCI_VPD_LRDT_ID_STRING) {
+ dev_err(adapter->pdev_dev, "missing VPD ID string\n");
+ return -EINVAL;
+ }
+
+ id_len = pci_vpd_lrdt_size(vpd);
+ if (id_len > ID_LEN)
+ id_len = ID_LEN;
+
+ i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA);
+ if (i < 0) {
+ dev_err(adapter->pdev_dev, "missing VPD-R section\n");
+ return -EINVAL;
+ }
+
+ vpdr_len = pci_vpd_lrdt_size(&vpd[i]);
+ kw_offset = i + PCI_VPD_LRDT_TAG_SIZE;
+ if (vpdr_len + kw_offset > VPD_LEN) {
dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
return -EINVAL;
}
#define FIND_VPD_KW(var, name) do { \
- var = pci_vpd_find_info_keyword(&v->id_tag, sizeof(struct t4_vpd_hdr), \
- vpdr_len, name); \
+ var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \
if (var < 0) { \
dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
return -EINVAL; \
@@ -408,11 +409,9 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
FIND_VPD_KW(ec, "EC");
FIND_VPD_KW(sn, "SN");
- FIND_VPD_KW(v2, "V2");
#undef FIND_VPD_KW
- p->cclk = simple_strtoul(vpd + v2, NULL, 10);
- memcpy(p->id, v->id_data, ID_LEN);
+ memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
strim(p->id);
memcpy(p->ec, vpd + ec, EC_LEN);
strim(p->ec);
@@ -919,7 +918,7 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
*/
static void pcie_intr_handler(struct adapter *adapter)
{
- static struct intr_info sysbus_intr_info[] = {
+ static const struct intr_info sysbus_intr_info[] = {
{ RNPP, "RXNP array parity error", -1, 1 },
{ RPCP, "RXPC array parity error", -1, 1 },
{ RCIP, "RXCIF array parity error", -1, 1 },
@@ -927,7 +926,7 @@ static void pcie_intr_handler(struct adapter *adapter)
{ RFTP, "RXFT array parity error", -1, 1 },
{ 0 }
};
- static struct intr_info pcie_port_intr_info[] = {
+ static const struct intr_info pcie_port_intr_info[] = {
{ TPCP, "TXPC array parity error", -1, 1 },
{ TNPP, "TXNP array parity error", -1, 1 },
{ TFTP, "TXFT array parity error", -1, 1 },
@@ -939,7 +938,7 @@ static void pcie_intr_handler(struct adapter *adapter)
{ TDUE, "Tx uncorrectable data error", -1, 1 },
{ 0 }
};
- static struct intr_info pcie_intr_info[] = {
+ static const struct intr_info pcie_intr_info[] = {
{ MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
{ MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
{ MSIDATAPERR, "MSI data parity error", -1, 1 },
@@ -991,7 +990,7 @@ static void pcie_intr_handler(struct adapter *adapter)
*/
static void tp_intr_handler(struct adapter *adapter)
{
- static struct intr_info tp_intr_info[] = {
+ static const struct intr_info tp_intr_info[] = {
{ 0x3fffffff, "TP parity error", -1, 1 },
{ FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
{ 0 }
@@ -1008,7 +1007,7 @@ static void sge_intr_handler(struct adapter *adapter)
{
u64 v;
- static struct intr_info sge_intr_info[] = {
+ static const struct intr_info sge_intr_info[] = {
{ ERR_CPL_EXCEED_IQE_SIZE,
"SGE received CPL exceeding IQE size", -1, 1 },
{ ERR_INVALID_CIDX_INC,
@@ -1053,7 +1052,7 @@ static void sge_intr_handler(struct adapter *adapter)
*/
static void cim_intr_handler(struct adapter *adapter)
{
- static struct intr_info cim_intr_info[] = {
+ static const struct intr_info cim_intr_info[] = {
{ PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
{ OBQPARERR, "CIM OBQ parity error", -1, 1 },
{ IBQPARERR, "CIM IBQ parity error", -1, 1 },
@@ -1063,7 +1062,7 @@ static void cim_intr_handler(struct adapter *adapter)
{ TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
{ 0 }
};
- static struct intr_info cim_upintr_info[] = {
+ static const struct intr_info cim_upintr_info[] = {
{ RSVDSPACEINT, "CIM reserved space access", -1, 1 },
{ ILLTRANSINT, "CIM illegal transaction", -1, 1 },
{ ILLWRINT, "CIM illegal write", -1, 1 },
@@ -1110,7 +1109,7 @@ static void cim_intr_handler(struct adapter *adapter)
*/
static void ulprx_intr_handler(struct adapter *adapter)
{
- static struct intr_info ulprx_intr_info[] = {
+ static const struct intr_info ulprx_intr_info[] = {
{ 0x1800000, "ULPRX context error", -1, 1 },
{ 0x7fffff, "ULPRX parity error", -1, 1 },
{ 0 }
@@ -1125,7 +1124,7 @@ static void ulprx_intr_handler(struct adapter *adapter)
*/
static void ulptx_intr_handler(struct adapter *adapter)
{
- static struct intr_info ulptx_intr_info[] = {
+ static const struct intr_info ulptx_intr_info[] = {
{ PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
0 },
{ PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
@@ -1147,7 +1146,7 @@ static void ulptx_intr_handler(struct adapter *adapter)
*/
static void pmtx_intr_handler(struct adapter *adapter)
{
- static struct intr_info pmtx_intr_info[] = {
+ static const struct intr_info pmtx_intr_info[] = {
{ PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
{ PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
{ PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
@@ -1169,7 +1168,7 @@ static void pmtx_intr_handler(struct adapter *adapter)
*/
static void pmrx_intr_handler(struct adapter *adapter)
{
- static struct intr_info pmrx_intr_info[] = {
+ static const struct intr_info pmrx_intr_info[] = {
{ ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
{ PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 },
{ OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
@@ -1188,7 +1187,7 @@ static void pmrx_intr_handler(struct adapter *adapter)
*/
static void cplsw_intr_handler(struct adapter *adapter)
{
- static struct intr_info cplsw_intr_info[] = {
+ static const struct intr_info cplsw_intr_info[] = {
{ CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
{ CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
{ TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
@@ -1207,7 +1206,7 @@ static void cplsw_intr_handler(struct adapter *adapter)
*/
static void le_intr_handler(struct adapter *adap)
{
- static struct intr_info le_intr_info[] = {
+ static const struct intr_info le_intr_info[] = {
{ LIPMISS, "LE LIP miss", -1, 0 },
{ LIP0, "LE 0 LIP error", -1, 0 },
{ PARITYERR, "LE parity error", -1, 1 },
@@ -1225,11 +1224,11 @@ static void le_intr_handler(struct adapter *adap)
*/
static void mps_intr_handler(struct adapter *adapter)
{
- static struct intr_info mps_rx_intr_info[] = {
+ static const struct intr_info mps_rx_intr_info[] = {
{ 0xffffff, "MPS Rx parity error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_tx_intr_info[] = {
+ static const struct intr_info mps_tx_intr_info[] = {
{ TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 },
{ NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
{ TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 },
@@ -1239,25 +1238,25 @@ static void mps_intr_handler(struct adapter *adapter)
{ FRMERR, "MPS Tx framing error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_trc_intr_info[] = {
+ static const struct intr_info mps_trc_intr_info[] = {
{ FILTMEM, "MPS TRC filter parity error", -1, 1 },
{ PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 },
{ MISCPERR, "MPS TRC misc parity error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_stat_sram_intr_info[] = {
+ static const struct intr_info mps_stat_sram_intr_info[] = {
{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_stat_tx_intr_info[] = {
+ static const struct intr_info mps_stat_tx_intr_info[] = {
{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_stat_rx_intr_info[] = {
+ static const struct intr_info mps_stat_rx_intr_info[] = {
{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
{ 0 }
};
- static struct intr_info mps_cls_intr_info[] = {
+ static const struct intr_info mps_cls_intr_info[] = {
{ MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
{ MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
{ HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
@@ -1356,7 +1355,7 @@ static void ma_intr_handler(struct adapter *adap)
*/
static void smb_intr_handler(struct adapter *adap)
{
- static struct intr_info smb_intr_info[] = {
+ static const struct intr_info smb_intr_info[] = {
{ MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
{ MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
{ SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
@@ -1372,7 +1371,7 @@ static void smb_intr_handler(struct adapter *adap)
*/
static void ncsi_intr_handler(struct adapter *adap)
{
- static struct intr_info ncsi_intr_info[] = {
+ static const struct intr_info ncsi_intr_info[] = {
{ CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
{ MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
{ TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
@@ -1410,7 +1409,7 @@ static void xgmac_intr_handler(struct adapter *adap, int port)
*/
static void pl_intr_handler(struct adapter *adap)
{
- static struct intr_info pl_intr_info[] = {
+ static const struct intr_info pl_intr_info[] = {
{ FATALPERR, "T4 fatal parity error", -1, 1 },
{ PERRVFID, "PL VFID_MAP parity error", -1, 1 },
{ 0 }
@@ -2408,7 +2407,7 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
if (index < NEXACT_MAC)
ret++;
else if (hash)
- *hash |= (1 << hash_mac_addr(addr[i]));
+ *hash |= (1ULL << hash_mac_addr(addr[i]));
}
return ret;
}
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h
index 940584a8a640..edcfd7ec7802 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/cxgb4/t4fw_api.h
@@ -1239,6 +1239,7 @@ enum fw_port_type {
FW_PORT_TYPE_KR,
FW_PORT_TYPE_SFP,
FW_PORT_TYPE_BP_AP,
+ FW_PORT_TYPE_BP4_AP,
FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
};
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h
index 8ea01962e045..4766b4116b41 100644
--- a/drivers/net/cxgb4vf/adapter.h
+++ b/drivers/net/cxgb4vf/adapter.h
@@ -60,7 +60,7 @@ enum {
* MSI-X interrupt index usage.
*/
MSIX_FW = 0, /* MSI-X index for firmware Q */
- MSIX_NIQFLINT = 1, /* MSI-X index base for Ingress Qs */
+ MSIX_IQFLINT = 1, /* MSI-X index base for Ingress Qs */
MSIX_EXTRAS = 1,
MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS,
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 555ecc5a2e93..56166ae2059f 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -280,9 +280,7 @@ static void name_msix_vecs(struct adapter *adapter)
const struct port_info *pi = netdev_priv(dev);
int qs, msi;
- for (qs = 0, msi = MSIX_NIQFLINT;
- qs < pi->nqsets;
- qs++, msi++) {
+ for (qs = 0, msi = MSIX_IQFLINT; qs < pi->nqsets; qs++, msi++) {
snprintf(adapter->msix_info[msi].desc, namelen,
"%s-%d", dev->name, qs);
adapter->msix_info[msi].desc[namelen] = 0;
@@ -309,7 +307,7 @@ static int request_msix_queue_irqs(struct adapter *adapter)
/*
* Ethernet queues.
*/
- msi = MSIX_NIQFLINT;
+ msi = MSIX_IQFLINT;
for_each_ethrxq(s, rxq) {
err = request_irq(adapter->msix_info[msi].vec,
t4vf_sge_intr_msix, 0,
@@ -337,7 +335,7 @@ static void free_msix_queue_irqs(struct adapter *adapter)
int rxq, msi;
free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
- msi = MSIX_NIQFLINT;
+ msi = MSIX_IQFLINT;
for_each_ethrxq(s, rxq)
free_irq(adapter->msix_info[msi++].vec,
&s->ethrxq[rxq].rspq);
@@ -527,7 +525,7 @@ static int setup_sge_queues(struct adapter *adapter)
* brought up at which point lots of things get nailed down
* permanently ...
*/
- msix = MSIX_NIQFLINT;
+ msix = MSIX_IQFLINT;
for_each_port(adapter, pidx) {
struct net_device *dev = adapter->port[pidx];
struct port_info *pi = netdev_priv(dev);
@@ -751,11 +749,19 @@ static int cxgb4vf_open(struct net_device *dev)
netif_set_real_num_tx_queues(dev, pi->nqsets);
err = netif_set_real_num_rx_queues(dev, pi->nqsets);
if (err)
- return err;
- set_bit(pi->port_id, &adapter->open_device_map);
- link_start(dev);
+ goto err_unwind;
+ err = link_start(dev);
+ if (err)
+ goto err_unwind;
+
netif_tx_start_all_queues(dev);
+ set_bit(pi->port_id, &adapter->open_device_map);
return 0;
+
+err_unwind:
+ if (adapter->open_device_map == 0)
+ adapter_down(adapter);
+ return err;
}
/*
@@ -764,13 +770,12 @@ static int cxgb4vf_open(struct net_device *dev)
*/
static int cxgb4vf_stop(struct net_device *dev)
{
- int ret;
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
netif_tx_stop_all_queues(dev);
netif_carrier_off(dev);
- ret = t4vf_enable_vi(adapter, pi->viid, false, false);
+ t4vf_enable_vi(adapter, pi->viid, false, false);
pi->link_cfg.link_ok = 0;
clear_bit(pi->port_id, &adapter->open_device_map);
@@ -814,40 +819,48 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
}
/*
- * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
*/
-static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
- const u8 **addr,
- unsigned int maxaddrs)
+static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int offset,
+ unsigned int maxaddrs)
{
+ unsigned int index = 0;
unsigned int naddr = 0;
const struct netdev_hw_addr *ha;
- for_each_dev_addr(dev, ha) {
- addr[naddr++] = ha->addr;
- if (naddr >= maxaddrs)
- break;
- }
+ for_each_dev_addr(dev, ha)
+ if (index++ >= offset) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
return naddr;
}
/*
- * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
*/
-static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
- const u8 **addr,
- unsigned int maxaddrs)
+static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int offset,
+ unsigned int maxaddrs)
{
+ unsigned int index = 0;
unsigned int naddr = 0;
const struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, dev) {
- addr[naddr++] = ha->addr;
- if (naddr >= maxaddrs)
- break;
- }
+ netdev_for_each_mc_addr(ha, dev)
+ if (index++ >= offset) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
return naddr;
}
@@ -860,16 +873,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
u64 mhash = 0;
u64 uhash = 0;
bool free = true;
- u16 filt_idx[7];
+ unsigned int offset, naddr;
const u8 *addr[7];
- int ret, naddr = 0;
+ int ret;
const struct port_info *pi = netdev_priv(dev);
/* first do the secondary unicast addresses */
- naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
- if (naddr > 0) {
+ for (offset = 0; ; offset += naddr) {
+ naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
+ ARRAY_SIZE(addr));
+ if (naddr == 0)
+ break;
+
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
- naddr, addr, filt_idx, &uhash, sleep);
+ naddr, addr, NULL, &uhash, sleep);
if (ret < 0)
return ret;
@@ -877,12 +894,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
}
/* next set up the multicast addresses */
- naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
- if (naddr > 0) {
+ for (offset = 0; ; offset += naddr) {
+ naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
+ ARRAY_SIZE(addr));
+ if (naddr == 0)
+ break;
+
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
- naddr, addr, filt_idx, &mhash, sleep);
+ naddr, addr, NULL, &mhash, sleep);
if (ret < 0)
return ret;
+ free = false;
}
return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
@@ -1103,18 +1125,6 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
return 0;
}
-/*
- * Return a TX Queue on which to send the specified skb.
- */
-static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
-{
- /*
- * XXX For now just use the default hash but we probably want to
- * XXX look at other possibilities ...
- */
- return skb_tx_hash(dev, skb);
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Poll all of our receive queues. This is called outside of normal interrupt
@@ -1358,6 +1368,8 @@ struct queue_port_stats {
u64 rx_csum;
u64 vlan_ex;
u64 vlan_ins;
+ u64 lro_pkts;
+ u64 lro_merged;
};
/*
@@ -1395,6 +1407,8 @@ static const char stats_strings[][ETH_GSTRING_LEN] = {
"RxCsumGood ",
"VLANextractions ",
"VLANinsertions ",
+ "GROPackets ",
+ "GROMerged ",
};
/*
@@ -1444,6 +1458,8 @@ static void collect_sge_port_stats(const struct adapter *adapter,
stats->rx_csum += rxq->stats.rx_cso;
stats->vlan_ex += rxq->stats.vlan_ex;
stats->vlan_ins += txq->vlan_ins;
+ stats->lro_pkts += rxq->stats.lro_pkts;
+ stats->lro_merged += rxq->stats.lro_merged;
}
}
@@ -1540,14 +1556,19 @@ static void cxgb4vf_get_wol(struct net_device *dev,
}
/*
+ * TCP Segmentation Offload flags which we support.
+ */
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
+/*
* Set TCP Segmentation Offloading feature capabilities.
*/
static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
{
if (tso)
- dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ dev->features |= TSO_FLAGS;
else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ dev->features &= ~TSO_FLAGS;
return 0;
}
@@ -2038,7 +2059,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
* Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave
* it to our caller to tear down the directory (debugfs_root).
*/
-static void __devexit cleanup_debugfs(struct adapter *adapter)
+static void cleanup_debugfs(struct adapter *adapter)
{
BUG_ON(adapter->debugfs_root == NULL);
@@ -2056,7 +2077,7 @@ static void __devexit cleanup_debugfs(struct adapter *adapter)
* adapter parameters we're going to be using and initialize basic adapter
* hardware support.
*/
-static int adap_init0(struct adapter *adapter)
+static int __devinit adap_init0(struct adapter *adapter)
{
struct vf_resources *vfres = &adapter->params.vfres;
struct sge_params *sge_params = &adapter->params.sge;
@@ -2075,6 +2096,22 @@ static int adap_init0(struct adapter *adapter)
}
/*
+ * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
+ * 2.6.31 and later we can't call pci_reset_function() in order to
+ * issue an FLR because of a self- deadlock on the device semaphore.
+ * Meanwhile, the OS infrastructure doesn't issue FLRs in all the
+ * cases where they're needed -- for instance, some versions of KVM
+ * fail to reset "Assigned Devices" when the VM reboots. Therefore we
+ * use the firmware based reset in order to reset any per function
+ * state.
+ */
+ err = t4vf_fw_reset(adapter);
+ if (err < 0) {
+ dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err);
+ return err;
+ }
+
+ /*
* Grab basic operational parameters. These will predominantly have
* been set up by the Physical Function Driver or will be hard coded
* into the adapter. We just have to live with them ... Note that
@@ -2246,6 +2283,7 @@ static void __devinit cfg_queues(struct adapter *adapter)
{
struct sge *s = &adapter->sge;
int q10g, n10g, qidx, pidx, qs;
+ size_t iqe_size;
/*
* We should not be called till we know how many Queue Sets we can
@@ -2290,6 +2328,13 @@ static void __devinit cfg_queues(struct adapter *adapter)
s->ethqsets = qidx;
/*
+ * The Ingress Queue Entry Size for our various Response Queues needs
+ * to be big enough to accommodate the largest message we can receive
+ * from the chip/firmware; which is 64 bytes ...
+ */
+ iqe_size = 64;
+
+ /*
* Set up default Queue Set parameters ... Start off with the
* shortest interrupt holdoff timer.
*/
@@ -2297,7 +2342,7 @@ static void __devinit cfg_queues(struct adapter *adapter)
struct sge_eth_rxq *rxq = &s->ethrxq[qs];
struct sge_eth_txq *txq = &s->ethtxq[qs];
- init_rspq(&rxq->rspq, 0, 0, 1024, L1_CACHE_BYTES);
+ init_rspq(&rxq->rspq, 0, 0, 1024, iqe_size);
rxq->fl.size = 72;
txq->q.size = 1024;
}
@@ -2306,8 +2351,7 @@ static void __devinit cfg_queues(struct adapter *adapter)
* The firmware event queue is used for link state changes and
* notifications of TX DMA completions.
*/
- init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512,
- L1_CACHE_BYTES);
+ init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, iqe_size);
/*
* The forwarded interrupt queue is used when we're in MSI interrupt
@@ -2323,7 +2367,7 @@ static void __devinit cfg_queues(struct adapter *adapter)
* any time ...
*/
init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1,
- L1_CACHE_BYTES);
+ iqe_size);
}
/*
@@ -2417,7 +2461,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops = {
.ndo_get_stats = cxgb4vf_get_stats,
.ndo_set_rx_mode = cxgb4vf_set_rxmode,
.ndo_set_mac_address = cxgb4vf_set_mac_addr,
- .ndo_select_queue = cxgb4vf_select_queue,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = cxgb4vf_do_ioctl,
.ndo_change_mtu = cxgb4vf_change_mtu,
@@ -2465,7 +2508,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
version_printed = 1;
}
-
/*
* Initialize generic PCI device state.
*/
@@ -2600,10 +2642,9 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
pi->xact_addr_filt = -1;
pi->rx_offload = RX_CSO;
netif_carrier_off(netdev);
- netif_tx_stop_all_queues(netdev);
netdev->irq = pdev->irq;
- netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ netdev->features = (NETIF_F_SG | TSO_FLAGS |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
NETIF_F_GRO);
@@ -2625,7 +2666,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
netdev->do_ioctl = cxgb4vf_do_ioctl;
netdev->change_mtu = cxgb4vf_change_mtu;
netdev->set_mac_address = cxgb4vf_set_mac_addr;
- netdev->select_queue = cxgb4vf_select_queue;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = cxgb4vf_poll_controller;
#endif
@@ -2844,6 +2884,14 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
CH_DEVICE(0x4800, 0), /* T440-dbg */
CH_DEVICE(0x4801, 0), /* T420-cr */
CH_DEVICE(0x4802, 0), /* T422-cr */
+ CH_DEVICE(0x4803, 0), /* T440-cr */
+ CH_DEVICE(0x4804, 0), /* T420-bch */
+ CH_DEVICE(0x4805, 0), /* T440-bch */
+ CH_DEVICE(0x4806, 0), /* T460-ch */
+ CH_DEVICE(0x4807, 0), /* T420-so */
+ CH_DEVICE(0x4808, 0), /* T420-cx */
+ CH_DEVICE(0x4809, 0), /* T420-bt */
+ CH_DEVICE(0x480a, 0), /* T404-bt */
{ 0, }
};
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index f10864ddafbe..e0b3d1bc2fdf 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -154,13 +154,14 @@ enum {
*/
RX_COPY_THRES = 256,
RX_PULL_LEN = 128,
-};
-/*
- * Can't define this in the above enum because PKTSHIFT isn't a constant in
- * the VF Driver ...
- */
-#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT)
+ /*
+ * Main body length for sk_buffs used for RX Ethernet packets with
+ * fragments. Should be >= RX_PULL_LEN but possibly bigger to give
+ * pskb_may_pull() some room.
+ */
+ RX_SKB_LEN = 512,
+};
/*
* Software state per TX descriptor.
@@ -1355,6 +1356,67 @@ out_free:
}
/**
+ * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list
+ * @gl: the gather list
+ * @skb_len: size of sk_buff main body if it carries fragments
+ * @pull_len: amount of data to move to the sk_buff's main body
+ *
+ * Builds an sk_buff from the given packet gather list. Returns the
+ * sk_buff or %NULL if sk_buff allocation failed.
+ */
+struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
+ unsigned int skb_len, unsigned int pull_len)
+{
+ struct sk_buff *skb;
+ struct skb_shared_info *ssi;
+
+ /*
+ * If the ingress packet is small enough, allocate an skb large enough
+ * for all of the data and copy it inline. Otherwise, allocate an skb
+ * with enough room to pull in the header and reference the rest of
+ * the data via the skb fragment list.
+ *
+ * Below we rely on RX_COPY_THRES being less than the smallest Rx
+ * buff! size, which is expected since buffers are at least
+ * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one
+ * fragment.
+ */
+ if (gl->tot_len <= RX_COPY_THRES) {
+ /* small packets have only one fragment */
+ skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ __skb_put(skb, gl->tot_len);
+ skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
+ } else {
+ skb = alloc_skb(skb_len, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ __skb_put(skb, pull_len);
+ skb_copy_to_linear_data(skb, gl->va, pull_len);
+
+ ssi = skb_shinfo(skb);
+ ssi->frags[0].page = gl->frags[0].page;
+ ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
+ ssi->frags[0].size = gl->frags[0].size - pull_len;
+ if (gl->nfrags > 1)
+ memcpy(&ssi->frags[1], &gl->frags[1],
+ (gl->nfrags-1) * sizeof(skb_frag_t));
+ ssi->nr_frags = gl->nfrags;
+
+ skb->len = gl->tot_len;
+ skb->data_len = skb->len - pull_len;
+ skb->truesize += skb->data_len;
+
+ /* Get a reference for the last page, we don't own it */
+ get_page(gl->frags[gl->nfrags - 1].page);
+ }
+
+out:
+ return skb;
+}
+
+/**
* t4vf_pktgl_free - free a packet gather list
* @gl: the gather list
*
@@ -1463,10 +1525,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
{
struct sk_buff *skb;
struct port_info *pi;
- struct skb_shared_info *ssi;
const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
bool csum_ok = pkt->csum_calc && !pkt->err_vec;
- unsigned int len = be16_to_cpu(pkt->len);
struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
/*
@@ -1481,42 +1541,14 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
}
/*
- * If the ingress packet is small enough, allocate an skb large enough
- * for all of the data and copy it inline. Otherwise, allocate an skb
- * with enough room to pull in the header and reference the rest of
- * the data via the skb fragment list.
+ * Convert the Packet Gather List into an skb.
*/
- if (len <= RX_COPY_THRES) {
- /* small packets have only one fragment */
- skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC);
- if (!skb)
- goto nomem;
- __skb_put(skb, gl->frags[0].size);
- skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size);
- } else {
- skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC);
- if (!skb)
- goto nomem;
- __skb_put(skb, RX_PKT_PULL_LEN);
- skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN);
-
- ssi = skb_shinfo(skb);
- ssi->frags[0].page = gl->frags[0].page;
- ssi->frags[0].page_offset = (gl->frags[0].page_offset +
- RX_PKT_PULL_LEN);
- ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN;
- if (gl->nfrags > 1)
- memcpy(&ssi->frags[1], &gl->frags[1],
- (gl->nfrags-1) * sizeof(skb_frag_t));
- ssi->nr_frags = gl->nfrags;
- skb->len = len + PKTSHIFT;
- skb->data_len = skb->len - RX_PKT_PULL_LEN;
- skb->truesize += skb->data_len;
-
- /* Get a reference for the last page, we don't own it */
- get_page(gl->frags[gl->nfrags - 1].page);
+ skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN);
+ if (unlikely(!skb)) {
+ t4vf_pktgl_free(gl);
+ rxq->stats.rx_drops++;
+ return 0;
}
-
__skb_pull(skb, PKTSHIFT);
skb->protocol = eth_type_trans(skb, rspq->netdev);
skb_record_rx_queue(skb, rspq->idx);
@@ -1536,6 +1568,9 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
} else
skb_checksum_none_assert(skb);
+ /*
+ * Deliver the packet to the stack.
+ */
if (unlikely(pkt->vlan_ex)) {
struct vlan_group *grp = pi->vlan_grp;
@@ -1549,11 +1584,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
netif_receive_skb(skb);
return 0;
-
-nomem:
- t4vf_pktgl_free(gl);
- rxq->stats.rx_drops++;
- return 0;
}
/**
@@ -1679,6 +1709,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
}
len = RSPD_LEN(len);
}
+ gl.tot_len = len;
/*
* Gather packet fragments.
@@ -2115,7 +2146,7 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
/*
* Calculate the size of the hardware free list ring plus
- * status page (which the SGE will place at the end of the
+ * Status Page (which the SGE will place after the end of the
* free list ring) in Egress Queue Units.
*/
flsz = (fl->size / FL_PER_EQ_UNIT +
@@ -2212,8 +2243,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
struct port_info *pi = netdev_priv(dev);
/*
- * Calculate the size of the hardware TX Queue (including the
- * status age on the end) in units of TX Descriptors.
+ * Calculate the size of the hardware TX Queue (including the Status
+ * Page on the end of the TX Queue) in units of TX Descriptors.
*/
nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
index 873cb7d86c57..a65c80aed1f2 100644
--- a/drivers/net/cxgb4vf/t4vf_common.h
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -235,6 +235,7 @@ static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
int __devinit t4vf_wait_dev_ready(struct adapter *);
int __devinit t4vf_port_init(struct adapter *, int);
+int t4vf_fw_reset(struct adapter *);
int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *);
int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
index ea1c123f0cb4..0f51c80475ce 100644
--- a/drivers/net/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/cxgb4vf/t4vf_hw.c
@@ -116,7 +116,7 @@ static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data)
int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
void *rpl, bool sleep_ok)
{
- static int delay[] = {
+ static const int delay[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100
};
@@ -147,9 +147,20 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
/*
* Write the command array into the Mailbox Data register array and
* transfer ownership of the mailbox to the firmware.
+ *
+ * For the VFs, the Mailbox Data "registers" are actually backed by
+ * T4's "MA" interface rather than PL Registers (as is the case for
+ * the PFs). Because these are in different coherency domains, the
+ * write to the VF's PL-register-backed Mailbox Control can race in
+ * front of the writes to the MA-backed VF Mailbox Data "registers".
+ * So we need to do a read-back on at least one byte of the VF Mailbox
+ * Data registers before doing the write to the VF Mailbox Control
+ * register.
*/
for (i = 0, p = cmd; i < size; i += 8)
t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
+ t4_read_reg(adapter, mbox_data); /* flush write */
+
t4_write_reg(adapter, mbox_ctl,
MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
t4_read_reg(adapter, mbox_ctl); /* flush write */
@@ -326,6 +337,25 @@ int __devinit t4vf_port_init(struct adapter *adapter, int pidx)
}
/**
+ * t4vf_fw_reset - issue a reset to FW
+ * @adapter: the adapter
+ *
+ * Issues a reset command to FW. For a Physical Function this would
+ * result in the Firmware reseting all of its state. For a Virtual
+ * Function this just resets the state associated with the VF.
+ */
+int t4vf_fw_reset(struct adapter *adapter)
+{
+ struct fw_reset_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) |
+ FW_CMD_WRITE);
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
* t4vf_query_params - query FW or device parameters
* @adapter: the adapter
* @nparams: the number of parameters
@@ -995,48 +1025,72 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
unsigned int naddr, const u8 **addr, u16 *idx,
u64 *hash, bool sleep_ok)
{
- int i, ret;
+ int offset, ret = 0;
+ unsigned nfilters = 0;
+ unsigned int rem = naddr;
struct fw_vi_mac_cmd cmd, rpl;
- struct fw_vi_mac_exact *p;
- size_t len16;
- if (naddr > ARRAY_SIZE(cmd.u.exact))
+ if (naddr > FW_CLS_TCAM_NUM_ENTRIES)
return -EINVAL;
- len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
- u.exact[naddr]), 16);
- memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- (free ? FW_CMD_EXEC : 0) |
- FW_VI_MAC_CMD_VIID(viid));
- cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
- FW_CMD_LEN16(len16));
+ for (offset = 0; offset < naddr; /**/) {
+ unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact)
+ ? rem
+ : ARRAY_SIZE(cmd.u.exact));
+ size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[fw_naddr]), 16);
+ struct fw_vi_mac_exact *p;
+ int i;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ (free ? FW_CMD_EXEC : 0) |
+ FW_VI_MAC_CMD_VIID(viid));
+ cmd.freemacs_to_len16 =
+ cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
+ FW_CMD_LEN16(len16));
+
+ for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
+ p->valid_to_idx = cpu_to_be16(
+ FW_VI_MAC_CMD_VALID |
+ FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
+ memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
+ }
- for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) {
- p->valid_to_idx =
- cpu_to_be16(FW_VI_MAC_CMD_VALID |
- FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
- memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
- }
- ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
- if (ret)
- return ret;
-
- for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) {
- u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
-
- if (idx)
- idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES
- ? 0xffff
- : index);
- if (index < FW_CLS_TCAM_NUM_ENTRIES)
- ret++;
- else if (hash)
- *hash |= (1 << hash_mac_addr(addr[i]));
+ ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl,
+ sleep_ok);
+ if (ret && ret != -ENOMEM)
+ break;
+
+ for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) {
+ u16 index = FW_VI_MAC_CMD_IDX_GET(
+ be16_to_cpu(p->valid_to_idx));
+
+ if (idx)
+ idx[offset+i] =
+ (index >= FW_CLS_TCAM_NUM_ENTRIES
+ ? 0xffff
+ : index);
+ if (index < FW_CLS_TCAM_NUM_ENTRIES)
+ nfilters++;
+ else if (hash)
+ *hash |= (1ULL << hash_mac_addr(addr[offset+i]));
+ }
+
+ free = false;
+ offset += fw_naddr;
+ rem -= fw_naddr;
}
+
+ /*
+ * If there were no errors or we merely ran out of room in our MAC
+ * address arena, return the number of filters actually written.
+ */
+ if (ret == 0 || ret == -ENOMEM)
+ ret = nfilters;
return ret;
}
@@ -1257,7 +1311,7 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
*/
int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
{
- struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl;
+ const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
switch (opcode) {
@@ -1265,7 +1319,8 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
/*
* Link/module state change message.
*/
- const struct fw_port_cmd *port_cmd = (void *)rpl;
+ const struct fw_port_cmd *port_cmd =
+ (const struct fw_port_cmd *)rpl;
u32 word;
int action, port_id, link_ok, speed, fc, pidx;
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 91b3846ffc8a..1b48b68ad4fd 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1513,7 +1513,7 @@ static enum depca_type __init depca_shmem_probe (ulong *mem_start)
return adapter;
}
-static int __init depca_isa_probe (struct platform_device *device)
+static int __devinit depca_isa_probe (struct platform_device *device)
{
struct net_device *dev;
struct depca_private *lp;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 9f6aeefa06bf..2d4c4fc1d900 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -1675,7 +1675,7 @@ dm9000_drv_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
- dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
+ dm9000_release_board(pdev, netdev_priv(ndev));
free_netdev(ndev); /* free device structure */
dev_dbg(&pdev->dev, "released and freed device\n");
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index c7e242b69a18..aed223b1b897 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -130,10 +130,15 @@ static s32 e1000_set_phy_type(struct e1000_hw *hw)
if (hw->mac_type == e1000_82541 ||
hw->mac_type == e1000_82541_rev_2 ||
hw->mac_type == e1000_82547 ||
- hw->mac_type == e1000_82547_rev_2) {
+ hw->mac_type == e1000_82547_rev_2)
hw->phy_type = e1000_phy_igp;
- break;
- }
+ break;
+ case RTL8211B_PHY_ID:
+ hw->phy_type = e1000_phy_8211;
+ break;
+ case RTL8201N_PHY_ID:
+ hw->phy_type = e1000_phy_8201;
+ break;
default:
/* Should never have loaded on this device */
hw->phy_type = e1000_phy_undefined;
@@ -318,6 +323,9 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82547GI:
hw->mac_type = e1000_82547_rev_2;
break;
+ case E1000_DEV_ID_INTEL_CE4100_GBE:
+ hw->mac_type = e1000_ce4100;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
@@ -372,6 +380,9 @@ void e1000_set_media_type(struct e1000_hw *hw)
case e1000_82542_rev2_1:
hw->media_type = e1000_media_type_fiber;
break;
+ case e1000_ce4100:
+ hw->media_type = e1000_media_type_copper;
+ break;
default:
status = er32(STATUS);
if (status & E1000_STATUS_TBIMODE) {
@@ -460,6 +471,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
/* Reset is performed on a shadow of the control register */
ew32(CTRL_DUP, (ctrl | E1000_CTRL_RST));
break;
+ case e1000_ce4100:
default:
ew32(CTRL, (ctrl | E1000_CTRL_RST));
break;
@@ -952,6 +964,67 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
}
/**
+ * e1000_copper_link_rtl_setup - Copper link setup for e1000_phy_rtl series.
+ * @hw: Struct containing variables accessed by shared code
+ *
+ * Commits changes to PHY configuration by calling e1000_phy_reset().
+ */
+static s32 e1000_copper_link_rtl_setup(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ /* SW reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if (ret_val) {
+ e_dbg("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+static s32 gbe_dhg_phy_setup(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u32 ctrl_aux;
+
+ switch (hw->phy_type) {
+ case e1000_phy_8211:
+ ret_val = e1000_copper_link_rtl_setup(hw);
+ if (ret_val) {
+ e_dbg("e1000_copper_link_rtl_setup failed!\n");
+ return ret_val;
+ }
+ break;
+ case e1000_phy_8201:
+ /* Set RMII mode */
+ ctrl_aux = er32(CTL_AUX);
+ ctrl_aux |= E1000_CTL_AUX_RMII;
+ ew32(CTL_AUX, ctrl_aux);
+ E1000_WRITE_FLUSH();
+
+ /* Disable the J/K bits required for receive */
+ ctrl_aux = er32(CTL_AUX);
+ ctrl_aux |= 0x4;
+ ctrl_aux &= ~0x2;
+ ew32(CTL_AUX, ctrl_aux);
+ E1000_WRITE_FLUSH();
+ ret_val = e1000_copper_link_rtl_setup(hw);
+
+ if (ret_val) {
+ e_dbg("e1000_copper_link_rtl_setup failed!\n");
+ return ret_val;
+ }
+ break;
+ default:
+ e_dbg("Error Resetting the PHY\n");
+ return E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
* e1000_copper_link_preconfig - early configuration for copper
* @hw: Struct containing variables accessed by shared code
*
@@ -1286,6 +1359,10 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
if (hw->autoneg_advertised == 0)
hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ /* IFE/RTL8201N PHY only supports 10/100 */
+ if (hw->phy_type == e1000_phy_8201)
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
e_dbg("Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw);
if (ret_val) {
@@ -1341,7 +1418,7 @@ static s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
s32 ret_val;
e_dbg("e1000_copper_link_postconfig");
- if (hw->mac_type >= e1000_82544) {
+ if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100)) {
e1000_config_collision_dist(hw);
} else {
ret_val = e1000_config_mac_to_phy(hw);
@@ -1395,6 +1472,12 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
ret_val = e1000_copper_link_mgp_setup(hw);
if (ret_val)
return ret_val;
+ } else {
+ ret_val = gbe_dhg_phy_setup(hw);
+ if (ret_val) {
+ e_dbg("gbe_dhg_phy_setup failed!\n");
+ return ret_val;
+ }
}
if (hw->autoneg) {
@@ -1461,10 +1544,11 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
return ret_val;
/* Read the MII 1000Base-T Control Register (Address 9). */
- ret_val =
- e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
if (ret_val)
return ret_val;
+ else if (hw->phy_type == e1000_phy_8201)
+ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
/* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
@@ -1577,9 +1661,14 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- if (ret_val)
- return ret_val;
+ if (hw->phy_type == e1000_phy_8201) {
+ mii_1000t_ctrl_reg = 0;
+ } else {
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
return E1000_SUCCESS;
}
@@ -1860,7 +1949,7 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
/* 82544 or newer MAC, Auto Speed Detection takes care of
* MAC speed/duplex configuration.*/
- if (hw->mac_type >= e1000_82544)
+ if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100))
return E1000_SUCCESS;
/* Read the Device Control Register and set the bits to Force Speed
@@ -1870,27 +1959,49 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
- /* Set up duplex in the Device Control and Transmit Control
- * registers depending on negotiated values.
- */
- ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
- if (ret_val)
- return ret_val;
+ switch (hw->phy_type) {
+ case e1000_phy_8201:
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
- if (phy_data & M88E1000_PSSR_DPLX)
- ctrl |= E1000_CTRL_FD;
- else
- ctrl &= ~E1000_CTRL_FD;
+ if (phy_data & RTL_PHY_CTRL_FD)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
- e1000_config_collision_dist(hw);
+ if (phy_data & RTL_PHY_CTRL_SPD_100)
+ ctrl |= E1000_CTRL_SPD_100;
+ else
+ ctrl |= E1000_CTRL_SPD_10;
- /* Set up speed in the Device Control register depending on
- * negotiated values.
- */
- if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
- ctrl |= E1000_CTRL_SPD_1000;
- else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
- ctrl |= E1000_CTRL_SPD_100;
+ e1000_config_collision_dist(hw);
+ break;
+ default:
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (phy_data & M88E1000_PSSR_DPLX)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
+
+ e1000_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if ((phy_data & M88E1000_PSSR_SPEED) ==
+ M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+ }
/* Write the configured values back to the Device Control Reg. */
ew32(CTRL, ctrl);
@@ -2401,7 +2512,8 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
* speed/duplex on the MAC to the current PHY speed/duplex
* settings.
*/
- if (hw->mac_type >= e1000_82544)
+ if ((hw->mac_type >= e1000_82544) &&
+ (hw->mac_type != e1000_ce4100))
e1000_config_collision_dist(hw);
else {
ret_val = e1000_config_mac_to_phy(hw);
@@ -2738,7 +2850,7 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
{
u32 i;
u32 mdic = 0;
- const u32 phy_addr = 1;
+ const u32 phy_addr = (hw->mac_type == e1000_ce4100) ? hw->phy_addr : 1;
e_dbg("e1000_read_phy_reg_ex");
@@ -2752,28 +2864,61 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
- mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
- (phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_READ));
+ if (hw->mac_type == e1000_ce4100) {
+ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (INTEL_CE_GBE_MDIC_OP_READ) |
+ (INTEL_CE_GBE_MDIC_GO));
- ew32(MDIC, mdic);
+ writel(mdic, E1000_MDIO_CMD);
- /* 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)) {
- e_dbg("MDI Read did not complete\n");
- return -E1000_ERR_PHY;
- }
- if (mdic & E1000_MDIC_ERROR) {
- e_dbg("MDI Error\n");
- return -E1000_ERR_PHY;
+ /* Poll the ready bit to see if the MDI read
+ * completed
+ */
+ for (i = 0; i < 64; i++) {
+ udelay(50);
+ mdic = readl(E1000_MDIO_CMD);
+ if (!(mdic & INTEL_CE_GBE_MDIC_GO))
+ break;
+ }
+
+ if (mdic & INTEL_CE_GBE_MDIC_GO) {
+ e_dbg("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+
+ mdic = readl(E1000_MDIO_STS);
+ if (mdic & INTEL_CE_GBE_MDIC_READ_ERROR) {
+ e_dbg("MDI Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (u16) mdic;
+ } else {
+ mdic = ((reg_addr << 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)) {
+ e_dbg("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ e_dbg("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (u16) mdic;
}
- *phy_data = (u16) mdic;
} else {
/* We must first send a preamble through the MDIO pin to signal the
* beginning of an MII instruction. This is done by sending 32
@@ -2840,7 +2985,7 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
{
u32 i;
u32 mdic = 0;
- const u32 phy_addr = 1;
+ const u32 phy_addr = (hw->mac_type == e1000_ce4100) ? hw->phy_addr : 1;
e_dbg("e1000_write_phy_reg_ex");
@@ -2850,27 +2995,54 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
}
if (hw->mac_type > e1000_82543) {
- /* Set up Op-code, Phy Address, register address, and data intended
- * for the PHY register in the MDI Control register. The MAC will take
- * care of interfacing with the PHY to send the desired data.
+ /* Set up Op-code, Phy Address, register address, and data
+ * intended for the PHY register in the MDI Control register.
+ * The MAC will take care of interfacing with the PHY to send
+ * the desired data.
*/
- mdic = (((u32) phy_data) |
- (reg_addr << E1000_MDIC_REG_SHIFT) |
- (phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_WRITE));
+ if (hw->mac_type == e1000_ce4100) {
+ mdic = (((u32) phy_data) |
+ (reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (INTEL_CE_GBE_MDIC_OP_WRITE) |
+ (INTEL_CE_GBE_MDIC_GO));
- ew32(MDIC, mdic);
+ writel(mdic, E1000_MDIO_CMD);
- /* Poll the ready bit to see if the MDI read completed */
- for (i = 0; i < 641; i++) {
- udelay(5);
- mdic = er32(MDIC);
- if (mdic & E1000_MDIC_READY)
- break;
- }
- if (!(mdic & E1000_MDIC_READY)) {
- e_dbg("MDI Write did not complete\n");
- return -E1000_ERR_PHY;
+ /* Poll the ready bit to see if the MDI read
+ * completed
+ */
+ for (i = 0; i < 640; i++) {
+ udelay(5);
+ mdic = readl(E1000_MDIO_CMD);
+ if (!(mdic & INTEL_CE_GBE_MDIC_GO))
+ break;
+ }
+ if (mdic & INTEL_CE_GBE_MDIC_GO) {
+ e_dbg("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ } else {
+ mdic = (((u32) phy_data) |
+ (reg_addr << 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 < 641; i++) {
+ udelay(5);
+ mdic = er32(MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ e_dbg("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
}
} else {
/* We'll need to use the SW defined pins to shift the write command
@@ -3048,6 +3220,11 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
if (hw->phy_id == M88E1011_I_PHY_ID)
match = true;
break;
+ case e1000_ce4100:
+ if ((hw->phy_id == RTL8211B_PHY_ID) ||
+ (hw->phy_id == RTL8201N_PHY_ID))
+ match = true;
+ break;
case e1000_82541:
case e1000_82541_rev_2:
case e1000_82547:
@@ -3291,6 +3468,9 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
if (hw->phy_type == e1000_phy_igp)
return e1000_phy_igp_get_info(hw, phy_info);
+ else if ((hw->phy_type == e1000_phy_8211) ||
+ (hw->phy_type == e1000_phy_8201))
+ return E1000_SUCCESS;
else
return e1000_phy_m88_get_info(hw, phy_info);
}
@@ -3742,6 +3922,12 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
e_dbg("e1000_read_eeprom");
+ if (hw->mac_type == e1000_ce4100) {
+ GBE_CONFIG_FLASH_READ(GBE_CONFIG_BASE_VIRT, offset, words,
+ data);
+ return E1000_SUCCESS;
+ }
+
/* If eeprom is not yet detected, do so now */
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
@@ -3904,6 +4090,12 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
e_dbg("e1000_write_eeprom");
+ if (hw->mac_type == e1000_ce4100) {
+ GBE_CONFIG_FLASH_WRITE(GBE_CONFIG_BASE_VIRT, offset, words,
+ data);
+ return E1000_SUCCESS;
+ }
+
/* If eeprom is not yet detected, do so now */
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
@@ -4892,11 +5084,11 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
} else if (hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
u16 cur_agc_value;
u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
- u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
- { IGP01E1000_PHY_AGC_A,
- IGP01E1000_PHY_AGC_B,
- IGP01E1000_PHY_AGC_C,
- IGP01E1000_PHY_AGC_D
+ static const u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
+ IGP01E1000_PHY_AGC_A,
+ IGP01E1000_PHY_AGC_B,
+ IGP01E1000_PHY_AGC_C,
+ IGP01E1000_PHY_AGC_D
};
/* Read the AGC registers for all channels */
for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
@@ -5071,11 +5263,11 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
{
s32 ret_val;
u16 phy_data, phy_saved_data, speed, duplex, i;
- u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
- { IGP01E1000_PHY_AGC_PARAM_A,
- IGP01E1000_PHY_AGC_PARAM_B,
- IGP01E1000_PHY_AGC_PARAM_C,
- IGP01E1000_PHY_AGC_PARAM_D
+ static const u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
+ IGP01E1000_PHY_AGC_PARAM_A,
+ IGP01E1000_PHY_AGC_PARAM_B,
+ IGP01E1000_PHY_AGC_PARAM_C,
+ IGP01E1000_PHY_AGC_PARAM_D
};
u16 min_length, max_length;
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index ecd9f6c6bcd5..196eeda2dd6c 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -41,7 +41,7 @@ struct e1000_hw;
struct e1000_hw_stats;
/* Enumerated types specific to the e1000 hardware */
-/* Media Access Controlers */
+/* Media Access Controllers */
typedef enum {
e1000_undefined = 0,
e1000_82542_rev2_0,
@@ -52,6 +52,7 @@ typedef enum {
e1000_82545,
e1000_82545_rev_3,
e1000_82546,
+ e1000_ce4100,
e1000_82546_rev_3,
e1000_82541,
e1000_82541_rev_2,
@@ -209,9 +210,11 @@ typedef enum {
} e1000_1000t_rx_status;
typedef enum {
- e1000_phy_m88 = 0,
- e1000_phy_igp,
- e1000_phy_undefined = 0xFF
+ e1000_phy_m88 = 0,
+ e1000_phy_igp,
+ e1000_phy_8211,
+ e1000_phy_8201,
+ e1000_phy_undefined = 0xFF
} e1000_phy_type;
typedef enum {
@@ -442,6 +445,7 @@ void e1000_io_write(struct e1000_hw *hw, unsigned long port, u32 value);
#define E1000_DEV_ID_82547EI 0x1019
#define E1000_DEV_ID_82547EI_MOBILE 0x101A
#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_INTEL_CE4100_GBE 0x2E6E
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -808,6 +812,16 @@ struct e1000_ffvt_entry {
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
+
+extern void __iomem *ce4100_gbe_mdio_base_virt;
+#define INTEL_CE_GBE_MDIO_RCOMP_BASE (ce4100_gbe_mdio_base_virt)
+#define E1000_MDIO_STS (INTEL_CE_GBE_MDIO_RCOMP_BASE + 0)
+#define E1000_MDIO_CMD (INTEL_CE_GBE_MDIO_RCOMP_BASE + 4)
+#define E1000_MDIO_DRV (INTEL_CE_GBE_MDIO_RCOMP_BASE + 8)
+#define E1000_MDC_CMD (INTEL_CE_GBE_MDIO_RCOMP_BASE + 0xC)
+#define E1000_RCOMP_CTL (INTEL_CE_GBE_MDIO_RCOMP_BASE + 0x20)
+#define E1000_RCOMP_STS (INTEL_CE_GBE_MDIO_RCOMP_BASE + 0x24)
+
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
@@ -820,6 +834,34 @@ struct e1000_ffvt_entry {
#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
+
+/* Auxiliary Control Register. This register is CE4100 specific,
+ * RMII/RGMII function is switched by this register - RW
+ * Following are bits definitions of the Auxiliary Control Register
+ */
+#define E1000_CTL_AUX 0x000E0
+#define E1000_CTL_AUX_END_SEL_SHIFT 10
+#define E1000_CTL_AUX_ENDIANESS_SHIFT 8
+#define E1000_CTL_AUX_RGMII_RMII_SHIFT 0
+
+/* descriptor and packet transfer use CTL_AUX.ENDIANESS */
+#define E1000_CTL_AUX_DES_PKT (0x0 << E1000_CTL_AUX_END_SEL_SHIFT)
+/* descriptor use CTL_AUX.ENDIANESS, packet use default */
+#define E1000_CTL_AUX_DES (0x1 << E1000_CTL_AUX_END_SEL_SHIFT)
+/* descriptor use default, packet use CTL_AUX.ENDIANESS */
+#define E1000_CTL_AUX_PKT (0x2 << E1000_CTL_AUX_END_SEL_SHIFT)
+/* all use CTL_AUX.ENDIANESS */
+#define E1000_CTL_AUX_ALL (0x3 << E1000_CTL_AUX_END_SEL_SHIFT)
+
+#define E1000_CTL_AUX_RGMII (0x0 << E1000_CTL_AUX_RGMII_RMII_SHIFT)
+#define E1000_CTL_AUX_RMII (0x1 << E1000_CTL_AUX_RGMII_RMII_SHIFT)
+
+/* LW little endian, Byte big endian */
+#define E1000_CTL_AUX_LWLE_BBE (0x0 << E1000_CTL_AUX_ENDIANESS_SHIFT)
+#define E1000_CTL_AUX_LWLE_BLE (0x1 << E1000_CTL_AUX_ENDIANESS_SHIFT)
+#define E1000_CTL_AUX_LWBE_BBE (0x2 << E1000_CTL_AUX_ENDIANESS_SHIFT)
+#define E1000_CTL_AUX_LWBE_BLE (0x3 << E1000_CTL_AUX_ENDIANESS_SHIFT)
+
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */
#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */
@@ -1011,6 +1053,7 @@ struct e1000_ffvt_entry {
* in more current versions of the 8254x. Despite the difference in location,
* the registers function in the same manner.
*/
+#define E1000_82542_CTL_AUX E1000_CTL_AUX
#define E1000_82542_CTRL E1000_CTRL
#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
#define E1000_82542_STATUS E1000_STATUS
@@ -1571,6 +1614,11 @@ struct e1000_hw {
#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
+#define INTEL_CE_GBE_MDIC_OP_WRITE 0x04000000
+#define INTEL_CE_GBE_MDIC_OP_READ 0x00000000
+#define INTEL_CE_GBE_MDIC_GO 0x80000000
+#define INTEL_CE_GBE_MDIC_READ_ERROR 0x80000000
+
#define E1000_KUMCTRLSTA_MASK 0x0000FFFF
#define E1000_KUMCTRLSTA_OFFSET 0x001F0000
#define E1000_KUMCTRLSTA_OFFSET_SHIFT 16
@@ -2871,6 +2919,11 @@ struct e1000_host_command_info {
#define M88E1111_I_PHY_ID 0x01410CC0
#define L1LXT971A_PHY_ID 0x001378E0
+#define RTL8211B_PHY_ID 0x001CC910
+#define RTL8201N_PHY_ID 0x8200
+#define RTL_PHY_CTRL_FD 0x0100 /* Full duplex.0=half; 1=full */
+#define RTL_PHY_CTRL_SPD_100 0x200000 /* Force 100Mb */
+
/* Bits...
* 15-5: page
* 4-0: register offset
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 4686c3983fc3..bfab14092d2c 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -28,10 +28,16 @@
#include "e1000.h"
#include <net/ip6_checksum.h>
+#include <linux/io.h>
+
+/* Intel Media SOC GbE MDIO physical base address */
+static unsigned long ce4100_gbe_mdio_base_phy;
+/* Intel Media SOC GbE MDIO virtual base address */
+void __iomem *ce4100_gbe_mdio_base_virt;
char e1000_driver_name[] = "e1000";
static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-#define DRV_VERSION "7.3.21-k6-NAPI"
+#define DRV_VERSION "7.3.21-k8-NAPI"
const char e1000_driver_version[] = DRV_VERSION;
static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -79,6 +85,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
INTEL_E1000_ETHERNET_DEVICE(0x108A),
INTEL_E1000_ETHERNET_DEVICE(0x1099),
INTEL_E1000_ETHERNET_DEVICE(0x10B5),
+ INTEL_E1000_ETHERNET_DEVICE(0x2E6E),
/* required last entry */
{0,}
};
@@ -459,6 +466,7 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
+ case e1000_ce4100:
case e1000_82546_rev_3:
case e1000_82541:
case e1000_82541_rev_2:
@@ -485,9 +493,6 @@ void e1000_down(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
u32 rctl, tctl;
- /* signal that we're down so the interrupt handler does not
- * reschedule our watchdog timer */
- set_bit(__E1000_DOWN, &adapter->flags);
/* disable receives in the hardware */
rctl = er32(RCTL);
@@ -508,6 +513,13 @@ void e1000_down(struct e1000_adapter *adapter)
e1000_irq_disable(adapter);
+ /*
+ * Setting DOWN must be after irq_disable to prevent
+ * a screaming interrupt. Setting DOWN also prevents
+ * timers and tasks from rescheduling.
+ */
+ set_bit(__E1000_DOWN, &adapter->flags);
+
del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -569,6 +581,7 @@ void e1000_reset(struct e1000_adapter *adapter)
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
+ case e1000_ce4100:
case e1000_82546_rev_3:
pba = E1000_PBA_48K;
break;
@@ -890,6 +903,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
static int global_quad_port_a = 0; /* global ksp3 port a indication */
int i, err, pci_using_dac;
u16 eeprom_data = 0;
+ u16 tmp = 0;
u16 eeprom_apme_mask = E1000_EEPROM_APME;
int bars, need_ioport;
@@ -967,11 +981,13 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
*/
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
pci_using_dac = 1;
- } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
} else {
- pr_err("No usable DMA config, aborting\n");
- goto err_dma;
+ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ pr_err("No usable DMA config, aborting\n");
+ goto err_dma;
+ }
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
}
netdev->netdev_ops = &e1000_netdev_ops;
@@ -990,6 +1006,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
goto err_sw_init;
err = -EIO;
+ if (hw->mac_type == e1000_ce4100) {
+ ce4100_gbe_mdio_base_phy = pci_resource_start(pdev, BAR_1);
+ ce4100_gbe_mdio_base_virt = ioremap(ce4100_gbe_mdio_base_phy,
+ pci_resource_len(pdev, BAR_1));
+
+ if (!ce4100_gbe_mdio_base_virt)
+ goto err_mdio_ioremap;
+ }
if (hw->mac_type >= e1000_82543) {
netdev->features = NETIF_F_SG |
@@ -1129,6 +1153,20 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
adapter->wol = adapter->eeprom_wol;
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ /* Auto detect PHY address */
+ if (hw->mac_type == e1000_ce4100) {
+ for (i = 0; i < 32; i++) {
+ hw->phy_addr = i;
+ e1000_read_phy_reg(hw, PHY_ID2, &tmp);
+ if (tmp == 0 || tmp == 0xFF) {
+ if (i == 31)
+ goto err_eeprom;
+ continue;
+ } else
+ break;
+ }
+ }
+
/* reset the hardware with the new settings */
e1000_reset(adapter);
@@ -1165,6 +1203,8 @@ err_eeprom:
kfree(adapter->rx_ring);
err_dma:
err_sw_init:
+err_mdio_ioremap:
+ iounmap(ce4100_gbe_mdio_base_virt);
iounmap(hw->hw_addr);
err_ioremap:
free_netdev(netdev);
@@ -1403,6 +1443,7 @@ static bool e1000_check_64k_bound(struct e1000_adapter *adapter, void *start,
/* First rev 82545 and 82546 need to not allow any memory
* write location to cross 64k boundary due to errata 23 */
if (hw->mac_type == e1000_82545 ||
+ hw->mac_type == e1000_ce4100 ||
hw->mac_type == e1000_82546) {
return ((begin ^ (end - 1)) >> 16) != 0 ? false : true;
}
@@ -1425,13 +1466,12 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
int size;
size = sizeof(struct e1000_buffer) * txdr->count;
- txdr->buffer_info = vmalloc(size);
+ txdr->buffer_info = vzalloc(size);
if (!txdr->buffer_info) {
e_err(probe, "Unable to allocate memory for the Tx descriptor "
"ring\n");
return -ENOMEM;
}
- memset(txdr->buffer_info, 0, size);
/* round up to nearest 4K */
@@ -1621,13 +1661,12 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
int size, desc_len;
size = sizeof(struct e1000_buffer) * rxdr->count;
- rxdr->buffer_info = vmalloc(size);
+ rxdr->buffer_info = vzalloc(size);
if (!rxdr->buffer_info) {
e_err(probe, "Unable to allocate memory for the Rx descriptor "
"ring\n");
return -ENOMEM;
}
- memset(rxdr->buffer_info, 0, size);
desc_len = sizeof(struct e1000_rx_desc);
@@ -2194,7 +2233,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
* addresses take precedence to avoid disabling unicast filtering
* when possible.
*
- * RAR 0 is used for the station MAC adddress
+ * RAR 0 is used for the station MAC address
* if there are not 14 addresses, go ahead and clear the filters
*/
i = 1;
@@ -2722,7 +2761,7 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
break;
}
- css = skb_transport_offset(skb);
+ css = skb_checksum_start_offset(skb);
i = tx_ring->next_to_use;
buffer_info = &tx_ring->buffer_info[i];
@@ -3439,9 +3478,17 @@ static irqreturn_t e1000_intr(int irq, void *data)
struct e1000_hw *hw = &adapter->hw;
u32 icr = er32(ICR);
- if (unlikely((!icr) || test_bit(__E1000_DOWN, &adapter->flags)))
+ if (unlikely((!icr)))
return IRQ_NONE; /* Not our interrupt */
+ /*
+ * we might have caused the interrupt, but the above
+ * read cleared it, and just in case the driver is
+ * down there is nothing to do so return handled
+ */
+ if (unlikely(test_bit(__E1000_DOWN, &adapter->flags)))
+ return IRQ_HANDLED;
+
if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
hw->get_link_status = 1;
/* guard against interrupt when we're going down */
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index edd1c75aa895..55c1711f1688 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -34,12 +34,21 @@
#ifndef _E1000_OSDEP_H_
#define _E1000_OSDEP_H_
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
#include <asm/io.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
+
+#define CONFIG_RAM_BASE 0x60000
+#define GBE_CONFIG_OFFSET 0x0
+
+#define GBE_CONFIG_RAM_BASE \
+ ((unsigned int)(CONFIG_RAM_BASE + GBE_CONFIG_OFFSET))
+
+#define GBE_CONFIG_BASE_VIRT phys_to_virt(GBE_CONFIG_RAM_BASE)
+
+#define GBE_CONFIG_FLASH_WRITE(base, offset, count, data) \
+ (iowrite16_rep(base + offset, data, count))
+
+#define GBE_CONFIG_FLASH_READ(base, offset, count, data) \
+ (ioread16_rep(base + (offset << 1), data, count))
#define er32(reg) \
(readl(hw->hw_addr + ((hw->mac_type >= e1000_82543) \
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 10d8d98bb797..1301eba8b57a 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -352,12 +352,13 @@ void __devinit e1000_check_options(struct e1000_adapter *adapter)
}
{ /* Flow Control */
- struct e1000_opt_list fc_list[] =
- {{ E1000_FC_NONE, "Flow Control Disabled" },
- { E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
- { E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
- { E1000_FC_FULL, "Flow Control Enabled" },
- { E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
+ static const struct e1000_opt_list fc_list[] = {
+ { E1000_FC_NONE, "Flow Control Disabled" },
+ { E1000_FC_RX_PAUSE, "Flow Control Receive Only" },
+ { E1000_FC_TX_PAUSE, "Flow Control Transmit Only" },
+ { E1000_FC_FULL, "Flow Control Enabled" },
+ { E1000_FC_DEFAULT, "Flow Control Hardware Default" }
+ };
opt = (struct e1000_option) {
.type = list_option,
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 7236f1a53ba0..89a69035e538 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -52,6 +52,7 @@
(ID_LED_DEF1_DEF2))
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
#define E1000_BASE1000T_STATUS 10
#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
#define E1000_RECEIVE_ERROR_COUNTER 21
@@ -74,6 +75,11 @@ static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
static s32 e1000_led_on_82574(struct e1000_hw *hw);
static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
+static s32 e1000_set_d0_lplu_state_82574(struct e1000_hw *hw, bool active);
+static s32 e1000_set_d3_lplu_state_82574(struct e1000_hw *hw, bool active);
/**
* e1000_init_phy_params_82571 - Init PHY func ptrs.
@@ -107,6 +113,10 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
case e1000_82574:
case e1000_82583:
phy->type = e1000_phy_bm;
+ phy->ops.acquire = e1000_get_hw_semaphore_82574;
+ phy->ops.release = e1000_put_hw_semaphore_82574;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82574;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82574;
break;
default:
return -E1000_ERR_PHY;
@@ -115,29 +125,36 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
/* This can only be done after all function pointers are setup. */
ret_val = e1000_get_phy_id_82571(hw);
+ if (ret_val) {
+ e_dbg("Error getting PHY ID\n");
+ return ret_val;
+ }
/* Verify phy id */
switch (hw->mac.type) {
case e1000_82571:
case e1000_82572:
if (phy->id != IGP01E1000_I_PHY_ID)
- return -E1000_ERR_PHY;
+ ret_val = -E1000_ERR_PHY;
break;
case e1000_82573:
if (phy->id != M88E1111_I_PHY_ID)
- return -E1000_ERR_PHY;
+ ret_val = -E1000_ERR_PHY;
break;
case e1000_82574:
case e1000_82583:
if (phy->id != BME1000_E_PHY_ID_R2)
- return -E1000_ERR_PHY;
+ ret_val = -E1000_ERR_PHY;
break;
default:
- return -E1000_ERR_PHY;
+ ret_val = -E1000_ERR_PHY;
break;
}
- return 0;
+ if (ret_val)
+ e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id);
+
+ return ret_val;
}
/**
@@ -200,6 +217,17 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
break;
}
+ /* Function Pointers */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ nvm->ops.acquire = e1000_get_hw_semaphore_82574;
+ nvm->ops.release = e1000_put_hw_semaphore_82574;
+ break;
+ default:
+ break;
+ }
+
return 0;
}
@@ -300,7 +328,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
/*
* Ensure that the inter-port SWSM.SMBI lock bit is clear before
- * first NVM or PHY acess. This should be done for single-port
+ * first NVM or PHY access. This should be done for single-port
* devices, and for one port only on dual-port devices so that
* for those devices we can still use the SMBI lock to synchronize
* inter-port accesses to the PHY & NVM.
@@ -542,6 +570,146 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
ew32(SWSM, swsm);
}
+/**
+ * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore during reset.
+ *
+ **/
+static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+ s32 ret_val = 0;
+ s32 i = 0;
+
+ 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);
+
+ if (i == MDIO_OWNERSHIP_TIMEOUT) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_82573(hw);
+ e_dbg("Driver can't access the PHY\n");
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82573 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used during reset.
+ *
+ **/
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+}
+
+static DEFINE_MUTEX(swflag_mutex);
+
+/**
+ * e1000_get_hw_semaphore_82574 - 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_82574(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ mutex_lock(&swflag_mutex);
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ if (ret_val)
+ mutex_unlock(&swflag_mutex);
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_82574 - 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_82574(struct e1000_hw *hw)
+{
+ e1000_put_hw_semaphore_82573(hw);
+ mutex_unlock(&swflag_mutex);
+}
+
+/**
+ * e1000_set_d0_lplu_state_82574 - 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.
+ * 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_82574(struct e1000_hw *hw, bool active)
+{
+ u16 data = er32(POEMB);
+
+ if (active)
+ data |= E1000_PHY_CTRL_D0A_LPLU;
+ else
+ data &= ~E1000_PHY_CTRL_D0A_LPLU;
+
+ ew32(POEMB, data);
+ return 0;
+}
+
+/**
+ * e1000_set_d3_lplu_state_82574 - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * when active is true, else clear lplu for D3. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+static s32 e1000_set_d3_lplu_state_82574(struct e1000_hw *hw, bool active)
+{
+ u16 data = er32(POEMB);
+
+ if (!active) {
+ data &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ } else if ((hw->phy.autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (hw->phy.autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (hw->phy.autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= E1000_PHY_CTRL_NOND0A_LPLU;
+ }
+
+ ew32(POEMB, data);
+ return 0;
+}
/**
* e1000_acquire_nvm_82571 - Request for access to the EEPROM
@@ -562,8 +730,6 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82573:
- case e1000_82574:
- case e1000_82583:
break;
default:
ret_val = e1000e_acquire_nvm(hw);
@@ -853,9 +1019,8 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
**/
static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
{
- u32 ctrl, extcnf_ctrl, ctrl_ext, icr;
+ u32 ctrl, ctrl_ext;
s32 ret_val;
- u16 i = 0;
/*
* Prevent the PCI-E bus from sticking if there is no TLP connection
@@ -880,33 +1045,33 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
*/
switch (hw->mac.type) {
case e1000_82573:
+ ret_val = e1000_get_hw_semaphore_82573(hw);
+ break;
case e1000_82574:
case e1000_82583:
- 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);
+ ret_val = e1000_get_hw_semaphore_82574(hw);
break;
default:
break;
}
+ if (ret_val)
+ e_dbg("Cannot acquire MDIO ownership\n");
ctrl = er32(CTRL);
e_dbg("Issuing a global reset to MAC\n");
ew32(CTRL, ctrl | E1000_CTRL_RST);
+ /* Must release MDIO ownership and mutex after MAC reset. */
+ switch (hw->mac.type) {
+ case e1000_82574:
+ case e1000_82583:
+ e1000_put_hw_semaphore_82574(hw);
+ break;
+ default:
+ break;
+ }
+
if (hw->nvm.type == e1000_nvm_flash_hw) {
udelay(10);
ctrl_ext = er32(CTRL_EXT);
@@ -938,7 +1103,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
/* Clear any pending interrupt events. */
ew32(IMC, 0xffffffff);
- icr = er32(ICR);
+ er32(ICR);
if (hw->mac.type == e1000_82571) {
/* Install any alternate MAC address into RAR0 */
@@ -1145,7 +1310,7 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
* apply workaround for hardware errata documented in errata
* docs Fixes issue where some error prone or unreliable PCIe
* completions are occurring, particularly with ASPM enabled.
- * Without fix, issue can cause tx timeouts.
+ * Without fix, issue can cause Tx timeouts.
*/
reg = er32(GCR2);
reg |= 1;
@@ -1402,6 +1567,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
u32 rxcw;
u32 ctrl;
u32 status;
+ u32 txcw;
+ u32 i;
s32 ret_val = 0;
ctrl = er32(CTRL);
@@ -1422,8 +1589,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = false;
e_dbg("AN_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = true;
}
- break;
+ break;
case e1000_serdes_link_forced_up:
/*
@@ -1431,8 +1600,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
* 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.
+ * If the partner code word is null, stop forcing
+ * and restart auto negotiation.
*/
- if (rxcw & E1000_RXCW_C) {
+ if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) {
/* Enable autoneg, and unforce link up */
ew32(TXCW, mac->txcw);
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -1440,6 +1611,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = false;
e_dbg("FORCED_UP -> AN_PROG\n");
+ } else {
+ mac->serdes_has_link = true;
}
break;
@@ -1495,6 +1668,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
mac->serdes_link_state =
e1000_serdes_link_autoneg_progress;
+ mac->serdes_has_link = false;
e_dbg("DOWN -> AN_PROG\n");
break;
}
@@ -1505,16 +1679,32 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
e_dbg("ANYSTATE -> DOWN\n");
} else {
/*
- * We have sync, and can tolerate one invalid (IV)
- * codeword before declaring link down, so reread
- * to look again.
+ * Check several times, if Sync and Config
+ * both are consistently 1 then simply ignore
+ * the Invalid bit and restart Autoneg
*/
- udelay(10);
- rxcw = er32(RXCW);
- if (rxcw & E1000_RXCW_IV) {
- mac->serdes_link_state = e1000_serdes_link_down;
+ for (i = 0; i < AN_RETRY_COUNT; i++) {
+ udelay(10);
+ rxcw = er32(RXCW);
+ if ((rxcw & E1000_RXCW_IV) &&
+ !((rxcw & E1000_RXCW_SYNCH) &&
+ (rxcw & E1000_RXCW_C))) {
+ mac->serdes_has_link = false;
+ mac->serdes_link_state =
+ e1000_serdes_link_down;
+ e_dbg("ANYSTATE -> DOWN\n");
+ break;
+ }
+ }
+
+ if (i == AN_RETRY_COUNT) {
+ txcw = er32(TXCW);
+ txcw |= E1000_TXCW_ANE;
+ ew32(TXCW, txcw);
+ mac->serdes_link_state =
+ e1000_serdes_link_autoneg_progress;
mac->serdes_has_link = false;
- e_dbg("ANYSTATE -> DOWN\n");
+ e_dbg("ANYSTATE -> AN_PROG\n");
}
}
}
@@ -1897,7 +2087,7 @@ struct e1000_info e1000_82574_info = {
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
.flags2 = FLAG2_CHECK_PHY_HANG,
- .pba = 36,
+ .pba = 32,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
@@ -1914,7 +2104,7 @@ struct e1000_info e1000_82583_info = {
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
- .pba = 36,
+ .pba = 32,
.max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile
index 360c91369f35..28519acacd2d 100644
--- a/drivers/net/e1000e/Makefile
+++ b/drivers/net/e1000e/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2008 Intel Corporation.
+# Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index d3f7a9c3f973..13149983d07e 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -488,6 +488,9 @@
#define E1000_BLK_PHY_RESET 12
#define E1000_ERR_SWFW_SYNC 13
#define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_INVALID_ARGUMENT 16
+#define E1000_ERR_NO_SPACE 17
+#define E1000_ERR_NVM_PBA_SECTION 18
/* Loop limit on how long we wait for auto-negotiation to complete */
#define FIBER_LINK_UP_LIMIT 50
@@ -516,6 +519,7 @@
#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
/* Receive Configuration Word */
+#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */
#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
#define E1000_RXCW_C 0x20000000 /* Receive config */
#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
@@ -649,13 +653,16 @@
/* Mask bits for fields in Word 0x03 of the EEPROM */
#define NVM_COMPAT_LOM 0x0800
+/* length of string needed to store PBA number */
+#define E1000_PBANUM_LENGTH 11
+
/* 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_PBA_PTR_GUARD 0xFAFA
#define NVM_WORD_SIZE_BASE_SHIFT 6
/* NVM Commands - SPI */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index fdc67fead4ea..e610e1369053 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -38,6 +38,7 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
+#include <linux/crc32.h>
#include "hw.h"
@@ -482,6 +483,7 @@ 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 void e1000e_led_blink_task(struct work_struct *work);
extern int e1000e_up(struct e1000_adapter *adapter);
extern void e1000e_down(struct e1000_adapter *adapter);
@@ -495,6 +497,8 @@ extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_update_stats(struct e1000_adapter *adapter);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
+extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
+extern void e1000e_release_hw_control(struct e1000_adapter *adapter);
extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
extern unsigned int copybreak;
@@ -513,7 +517,8 @@ extern struct e1000_info e1000_pch_info;
extern struct e1000_info e1000_pch2_info;
extern struct e1000_info e1000_es2_info;
-extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
+extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
extern s32 e1000e_commit_phy(struct e1000_hw *hw);
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index 24f8ac9cf703..2fefa820302b 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -100,8 +100,8 @@
* 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 const u16 e1000_gg82563_cable_length_table[] = {
+ 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
#define GG82563_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_gg82563_cable_length_table)
@@ -426,8 +426,8 @@ static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
{
u32 swfw_sync;
- while (e1000e_get_hw_semaphore(hw) != 0);
- /* Empty */
+ while (e1000e_get_hw_semaphore(hw) != 0)
+ ; /* Empty */
swfw_sync = er32(SW_FW_SYNC);
swfw_sync &= ~mask;
@@ -784,7 +784,7 @@ static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
**/
static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
{
- u32 ctrl, icr;
+ u32 ctrl;
s32 ret_val;
/*
@@ -818,7 +818,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
/* Clear any pending interrupt events. */
ew32(IMC, 0xffffffff);
- icr = er32(ICR);
+ er32(ICR);
ret_val = e1000_check_alt_mac_addr_generic(hw);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 8984d165a39b..fa08b6336cfb 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -45,63 +45,67 @@ struct e1000_stats {
int stat_offset;
};
-#define E1000_STAT(m) E1000_STATS, \
- sizeof(((struct e1000_adapter *)0)->m), \
- offsetof(struct e1000_adapter, m)
-#define E1000_NETDEV_STAT(m) NETDEV_STATS, \
- sizeof(((struct net_device *)0)->m), \
- offsetof(struct net_device, m)
+#define E1000_STAT(str, m) { \
+ .stat_string = str, \
+ .type = E1000_STATS, \
+ .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \
+ .stat_offset = offsetof(struct e1000_adapter, m) }
+#define E1000_NETDEV_STAT(str, m) { \
+ .stat_string = str, \
+ .type = NETDEV_STATS, \
+ .sizeof_stat = sizeof(((struct net_device *)0)->m), \
+ .stat_offset = offsetof(struct net_device, 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.gorc) },
- { "tx_bytes", E1000_STAT(stats.gotc) },
- { "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_NETDEV_STAT(stats.rx_errors) },
- { "tx_errors", E1000_NETDEV_STAT(stats.tx_errors) },
- { "tx_dropped", E1000_NETDEV_STAT(stats.tx_dropped) },
- { "multicast", E1000_STAT(stats.mprc) },
- { "collisions", E1000_STAT(stats.colc) },
- { "rx_length_errors", E1000_NETDEV_STAT(stats.rx_length_errors) },
- { "rx_over_errors", E1000_NETDEV_STAT(stats.rx_over_errors) },
- { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
- { "rx_frame_errors", E1000_NETDEV_STAT(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_NETDEV_STAT(stats.tx_fifo_errors) },
- { "tx_heartbeat_errors", E1000_NETDEV_STAT(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.gorc) },
- { "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) },
+ E1000_STAT("rx_packets", stats.gprc),
+ E1000_STAT("tx_packets", stats.gptc),
+ E1000_STAT("rx_bytes", stats.gorc),
+ E1000_STAT("tx_bytes", stats.gotc),
+ E1000_STAT("rx_broadcast", stats.bprc),
+ E1000_STAT("tx_broadcast", stats.bptc),
+ E1000_STAT("rx_multicast", stats.mprc),
+ E1000_STAT("tx_multicast", stats.mptc),
+ E1000_NETDEV_STAT("rx_errors", stats.rx_errors),
+ E1000_NETDEV_STAT("tx_errors", stats.tx_errors),
+ E1000_NETDEV_STAT("tx_dropped", stats.tx_dropped),
+ E1000_STAT("multicast", stats.mprc),
+ E1000_STAT("collisions", stats.colc),
+ E1000_NETDEV_STAT("rx_length_errors", stats.rx_length_errors),
+ E1000_NETDEV_STAT("rx_over_errors", stats.rx_over_errors),
+ E1000_STAT("rx_crc_errors", stats.crcerrs),
+ E1000_NETDEV_STAT("rx_frame_errors", stats.rx_frame_errors),
+ E1000_STAT("rx_no_buffer_count", stats.rnbc),
+ E1000_STAT("rx_missed_errors", stats.mpc),
+ E1000_STAT("tx_aborted_errors", stats.ecol),
+ E1000_STAT("tx_carrier_errors", stats.tncrs),
+ E1000_NETDEV_STAT("tx_fifo_errors", stats.tx_fifo_errors),
+ E1000_NETDEV_STAT("tx_heartbeat_errors", stats.tx_heartbeat_errors),
+ E1000_STAT("tx_window_errors", stats.latecol),
+ E1000_STAT("tx_abort_late_coll", stats.latecol),
+ E1000_STAT("tx_deferred_ok", stats.dc),
+ E1000_STAT("tx_single_coll_ok", stats.scc),
+ E1000_STAT("tx_multi_coll_ok", stats.mcc),
+ E1000_STAT("tx_timeout_count", tx_timeout_count),
+ E1000_STAT("tx_restart_queue", restart_queue),
+ E1000_STAT("rx_long_length_errors", stats.roc),
+ E1000_STAT("rx_short_length_errors", stats.ruc),
+ E1000_STAT("rx_align_errors", stats.algnerrc),
+ E1000_STAT("tx_tcp_seg_good", stats.tsctc),
+ E1000_STAT("tx_tcp_seg_failed", stats.tsctfc),
+ E1000_STAT("rx_flow_control_xon", stats.xonrxc),
+ E1000_STAT("rx_flow_control_xoff", stats.xoffrxc),
+ E1000_STAT("tx_flow_control_xon", stats.xontxc),
+ E1000_STAT("tx_flow_control_xoff", stats.xofftxc),
+ E1000_STAT("rx_long_byte_count", stats.gorc),
+ E1000_STAT("rx_csum_offload_good", hw_csum_good),
+ E1000_STAT("rx_csum_offload_errors", hw_csum_err),
+ E1000_STAT("rx_header_split", rx_hdr_split),
+ E1000_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
+ E1000_STAT("tx_smbus", stats.mgptc),
+ E1000_STAT("rx_smbus", stats.mgprc),
+ E1000_STAT("dropped_smbus", stats.mgpdc),
+ E1000_STAT("rx_dma_failed", rx_dma_failed),
+ E1000_STAT("tx_dma_failed", tx_dma_failed),
};
#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
@@ -194,20 +198,6 @@ static int e1000_get_settings(struct net_device *netdev,
return 0;
}
-static u32 e1000_get_link(struct net_device *netdev)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
-
- /*
- * Avoid touching hardware registers when possible, otherwise
- * link negotiation can get messed up when user-level scripts
- * are rapidly polling the driver to see if link is up.
- */
- return netif_running(netdev) ? netif_carrier_ok(netdev) :
- !!(er32(STATUS) & E1000_STATUS_LU);
-}
-
static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
{
struct e1000_mac_info *mac = &adapter->hw.mac;
@@ -634,20 +624,24 @@ static void e1000_get_drvinfo(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
char firmware_version[32];
- strncpy(drvinfo->driver, e1000e_driver_name, 32);
- strncpy(drvinfo->version, e1000e_driver_version, 32);
+ strncpy(drvinfo->driver, e1000e_driver_name,
+ sizeof(drvinfo->driver) - 1);
+ strncpy(drvinfo->version, e1000e_driver_version,
+ sizeof(drvinfo->version) - 1);
/*
* EEPROM image version # is reported as firmware version # for
* PCI-E controllers
*/
- sprintf(firmware_version, "%d.%d-%d",
+ snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
(adapter->eeprom_vers & 0xF000) >> 12,
(adapter->eeprom_vers & 0x0FF0) >> 4,
(adapter->eeprom_vers & 0x000F));
- strncpy(drvinfo->fw_version, firmware_version, 32);
- strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ strncpy(drvinfo->fw_version, firmware_version,
+ sizeof(drvinfo->fw_version) - 1);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info) - 1);
drvinfo->regdump_len = e1000_get_regs_len(netdev);
drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
}
@@ -763,8 +757,8 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
int reg, int offset, u32 mask, u32 write)
{
u32 pat, val;
- static const u32 test[] =
- {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+ static const u32 test[] = {
+ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
for (pat = 0; pat < ARRAY_SIZE(test); pat++) {
E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset,
(test[pat] & write));
@@ -1263,6 +1257,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
u32 ctrl_reg = 0;
u32 stat_reg = 0;
u16 phy_reg = 0;
+ s32 ret_val = 0;
hw->mac.autoneg = 0;
@@ -1322,7 +1317,13 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
case e1000_phy_82577:
case e1000_phy_82578:
/* Workaround: K1 must be disabled for stable 1Gbps operation */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val) {
+ e_err("Cannot setup 1Gbps loopback.\n");
+ return ret_val;
+ }
e1000_configure_k1_ich8lan(hw, false);
+ hw->phy.ops.release(hw);
break;
case e1000_phy_82579:
/* Disable PHY energy detect power down */
@@ -1707,6 +1708,19 @@ static void e1000_diag_test(struct net_device *netdev,
bool if_running = netif_running(netdev);
set_bit(__E1000_TESTING, &adapter->state);
+
+ if (!if_running) {
+ /* Get control of and reset hardware */
+ if (adapter->flags & FLAG_HAS_AMT)
+ e1000e_get_hw_control(adapter);
+
+ e1000e_power_up_phy(adapter);
+
+ adapter->hw.phy.autoneg_wait_to_complete = 1;
+ e1000e_reset(adapter);
+ adapter->hw.phy.autoneg_wait_to_complete = 0;
+ }
+
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
@@ -1720,8 +1734,6 @@ static void e1000_diag_test(struct net_device *netdev,
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;
@@ -1735,8 +1747,6 @@ static void e1000_diag_test(struct net_device *netdev,
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;
@@ -1758,28 +1768,29 @@ static void e1000_diag_test(struct net_device *netdev,
if (if_running)
dev_open(netdev);
} else {
- if (!if_running && (adapter->flags & FLAG_HAS_AMT)) {
- clear_bit(__E1000_TESTING, &adapter->state);
- dev_open(netdev);
- set_bit(__E1000_TESTING, &adapter->state);
- }
+ /* Online tests */
e_info("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 */
+ /* register, eeprom, intr and loopback tests not run online */
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
- if (!if_running && (adapter->flags & FLAG_HAS_AMT))
- dev_close(netdev);
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
clear_bit(__E1000_TESTING, &adapter->state);
}
+
+ if (!if_running) {
+ e1000e_reset(adapter);
+
+ if (adapter->flags & FLAG_HAS_AMT)
+ e1000e_release_hw_control(adapter);
+ }
+
msleep_interruptible(4 * 1000);
}
@@ -1860,7 +1871,7 @@ static int e1000_set_wol(struct net_device *netdev,
/* bit defines for adapter->led_status */
#define E1000_LED_ON 0
-static void e1000e_led_blink_task(struct work_struct *work)
+void e1000e_led_blink_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
struct e1000_adapter, led_blink_task);
@@ -1892,7 +1903,6 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
(hw->mac.type == e1000_pch2lan) ||
(hw->mac.type == e1000_82583) ||
(hw->mac.type == e1000_82574)) {
- INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
if (!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
adapter->blink_timer.function =
@@ -1986,6 +1996,9 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
p = (char *) adapter +
e1000_gstrings_stats[i].stat_offset;
break;
+ default:
+ data[i] = 0;
+ continue;
}
data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
@@ -2024,7 +2037,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_msglevel = e1000_get_msglevel,
.set_msglevel = e1000_set_msglevel,
.nway_reset = e1000_nway_reset,
- .get_link = e1000_get_link,
+ .get_link = ethtool_op_get_link,
.get_eeprom_len = e1000_get_eeprom_len,
.get_eeprom = e1000_get_eeprom,
.set_eeprom = e1000_set_eeprom,
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index ba302a5c2c30..bc0860a598c9 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -83,6 +83,7 @@ enum e1e_registers {
E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */
E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */
E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */
+#define E1000_POEMB E1000_PHY_CTRL /* PHY OEM Bits */
E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */
E1000_PBS = 0x01008, /* Packet Buffer Size */
E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
@@ -101,7 +102,7 @@ enum e1e_registers {
E1000_RDTR = 0x02820, /* Rx Delay Timer - RW */
E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
#define E1000_RXDCTL(_n) (E1000_RXDCTL_BASE + (_n << 8))
- E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+ E1000_RADV = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */
/* Convenience macros
*
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index e3374d9a2472..fb46974cfec1 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -321,7 +321,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
}
/*
- * Reset the PHY before any acccess to it. Doing so, ensures that
+ * Reset the PHY before any access to it. Doing so, ensures that
* the PHY is in a known good state before we read/write PHY registers.
* The generic reset is sufficient here, because we haven't determined
* the PHY type yet.
@@ -338,12 +338,17 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
}
phy->id = e1000_phy_unknown;
- ret_val = e1000e_get_phy_id(hw);
- if (ret_val)
- goto out;
- if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+ switch (hw->mac.type) {
+ default:
+ ret_val = e1000e_get_phy_id(hw);
+ if (ret_val)
+ goto out;
+ if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
+ break;
+ /* fall-through */
+ case e1000_pch2lan:
/*
- * In case the PHY needs to be in mdio slow mode (eg. 82577),
+ * In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
ret_val = e1000_set_mdio_slow_mode_hv(hw);
@@ -352,6 +357,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
ret_val = e1000e_get_phy_id(hw);
if (ret_val)
goto out;
+ break;
}
phy->type = e1000e_get_phy_type_from_id(phy->id);
@@ -1389,22 +1395,6 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
}
}
-static u32 e1000_calc_rx_da_crc(u8 mac[])
-{
- u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
- u32 i, j, mask, crc;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- crc = crc ^ mac[i];
- for (j = 8; j > 0; j--) {
- mask = (crc & 1) * (-1);
- crc = (crc >> 1) ^ (poly & mask);
- }
- }
- return ~crc;
-}
-
/**
* e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
* with 82579 PHY
@@ -1447,8 +1437,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
mac_addr[4] = (addr_high & 0xFF);
mac_addr[5] = ((addr_high >> 8) & 0xFF);
- ew32(PCH_RAICC(i),
- e1000_calc_rx_da_crc(mac_addr));
+ ew32(PCH_RAICC(i), ~ether_crc_le(ETH_ALEN, mac_addr));
}
/* Write Rx addresses to the PHY */
@@ -2303,11 +2292,10 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
*/
if (ret_val == 0) {
flash_data = er32flash(ICH_FLASH_FDATA0);
- if (size == 1) {
+ if (size == 1)
*data = (u8)(flash_data & 0x000000FF);
- } else if (size == 2) {
+ else if (size == 2)
*data = (u16)(flash_data & 0x0000FFFF);
- }
break;
} else {
/*
@@ -2972,7 +2960,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
u16 reg;
- u32 ctrl, icr, kab;
+ u32 ctrl, kab;
s32 ret_val;
/*
@@ -3062,7 +3050,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ew32(CRC_OFFSET, 0x65656565);
ew32(IMC, 0xffffffff);
- icr = er32(ICR);
+ er32(ICR);
kab = er32(KABGTXD);
kab |= E1000_KABGTXD_BGSQLBIAS;
@@ -3113,7 +3101,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
* Reset the phy after disabling host wakeup to reset the Rx buffer.
*/
if (hw->phy.type == e1000_phy_82578) {
- hw->phy.ops.read_reg(hw, BM_WUC, &i);
+ e1e_rphy(hw, BM_WUC, &i);
ret_val = e1000_phy_hw_reset_ich8lan(hw);
if (ret_val)
return ret_val;
@@ -3271,9 +3259,8 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
(hw->phy.type == e1000_phy_82577)) {
ew32(FCRTV_PCH, hw->fc.refresh_time);
- ret_val = hw->phy.ops.write_reg(hw,
- PHY_REG(BM_PORT_CTRL_PAGE, 27),
- hw->fc.pause_time);
+ ret_val = e1e_wphy(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27),
+ hw->fc.pause_time);
if (ret_val)
return ret_val;
}
@@ -3337,8 +3324,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
return ret_val;
break;
case e1000_phy_ife:
- ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
- &reg_data);
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &reg_data);
if (ret_val)
return ret_val;
@@ -3356,8 +3342,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
reg_data |= IFE_PMC_AUTO_MDIX;
break;
}
- ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
- reg_data);
+ ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data);
if (ret_val)
return ret_val;
break;
@@ -3591,7 +3576,7 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
ew32(PHY_CTRL, phy_ctrl);
if (hw->mac.type >= e1000_pchlan) {
- e1000_oem_bits_config_ich8lan(hw, true);
+ e1000_oem_bits_config_ich8lan(hw, false);
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return;
@@ -3641,7 +3626,8 @@ 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));
+ (IFE_PSCL_PROBE_MODE |
+ IFE_PSCL_PROBE_LEDS_OFF));
ew32(LEDCTL, hw->mac.ledctl_mode1);
return 0;
@@ -3655,8 +3641,7 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
**/
static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
{
- return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
- (u16)hw->mac.ledctl_mode1);
+ return e1e_wphy(hw, HV_LED_CONFIG, (u16)hw->mac.ledctl_mode1);
}
/**
@@ -3667,8 +3652,7 @@ static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
**/
static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
{
- return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
- (u16)hw->mac.ledctl_default);
+ return e1e_wphy(hw, HV_LED_CONFIG, (u16)hw->mac.ledctl_default);
}
/**
@@ -3699,7 +3683,7 @@ static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
}
}
- return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+ return e1e_wphy(hw, HV_LED_CONFIG, data);
}
/**
@@ -3730,7 +3714,7 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
}
}
- return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
+ return e1e_wphy(hw, HV_LED_CONFIG, data);
}
/**
@@ -3839,20 +3823,20 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
if ((hw->phy.type == e1000_phy_82578) ||
(hw->phy.type == e1000_phy_82579) ||
(hw->phy.type == e1000_phy_82577)) {
- hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
- hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
+ e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
+ e1e_rphy(hw, HV_SCC_LOWER, &phy_data);
+ e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
+ e1e_rphy(hw, HV_ECOL_LOWER, &phy_data);
+ e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
+ e1e_rphy(hw, HV_MCC_LOWER, &phy_data);
+ e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
+ e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data);
+ e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
+ e1e_rphy(hw, HV_COLC_LOWER, &phy_data);
+ e1e_rphy(hw, HV_DC_UPPER, &phy_data);
+ e1e_rphy(hw, HV_DC_LOWER, &phy_data);
+ e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
+ e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data);
}
}
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 0fd4eb5ac5fb..68aa1749bf66 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -493,9 +493,8 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
* different link partner.
*/
ret_val = e1000e_config_fc_after_link_up(hw);
- if (ret_val) {
+ if (ret_val)
e_dbg("Error configuring flow control\n");
- }
return ret_val;
}
@@ -534,7 +533,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
mac->autoneg_failed = 1;
return 0;
}
- e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+ e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
/* Disable auto-negotiation in the TXCW register */
ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -557,7 +556,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
* and disable forced link in the Device Control register
* in an attempt to auto-negotiate with our link partner.
*/
- e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
ew32(TXCW, mac->txcw);
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -599,7 +598,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
mac->autoneg_failed = 1;
return 0;
}
- e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+ e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
/* Disable auto-negotiation in the TXCW register */
ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -622,7 +621,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
* and disable forced link in the Device Control register
* in an attempt to auto-negotiate with our link partner.
*/
- e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
ew32(TXCW, mac->txcw);
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -801,9 +800,9 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
* 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).
+ * but not send pause frames).
* 2: Tx flow control is enabled (we can send pause frames but we
- * do not support receiving pause frames).
+ * do not support receiving pause frames).
* 3: Both Rx and Tx flow control (symmetric) are enabled.
*/
switch (hw->fc.current_mode) {
@@ -1032,9 +1031,9 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw)
* 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).
+ * 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).
+ * 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.
*/
@@ -1136,7 +1135,8 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
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);
+ ret_val =
+ e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
if (ret_val)
return ret_val;
@@ -1189,7 +1189,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
} else {
hw->fc.current_mode = e1000_fc_rx_pause;
e_dbg("Flow Control = "
- "RX PAUSE frames only.\r\n");
+ "Rx PAUSE frames only.\r\n");
}
}
/*
@@ -1496,9 +1496,8 @@ s32 e1000e_setup_led_generic(struct e1000_hw *hw)
{
u32 ledctl;
- if (hw->mac.ops.setup_led != e1000e_setup_led_generic) {
+ if (hw->mac.ops.setup_led != e1000e_setup_led_generic)
return -E1000_ERR_CONFIG;
- }
if (hw->phy.media_type == e1000_media_type_fiber) {
ledctl = er32(LEDCTL);
@@ -2139,6 +2138,119 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
}
/**
+ * e1000_read_pba_string_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ * @pba_num_size: size of part number buffer
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size)
+{
+ s32 ret_val;
+ u16 nvm_data;
+ u16 pba_ptr;
+ u16 offset;
+ u16 length;
+
+ if (pba_num == NULL) {
+ e_dbg("PBA string buffer was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ /*
+ * if nvm_data is not ptr guard the PBA must be in legacy format which
+ * means pba_ptr is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ e_dbg("NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (pba_num_size < 11) {
+ e_dbg("PBA string buffer too small\n");
+ return E1000_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pba_ptr */
+ pba_num[0] = (nvm_data >> 12) & 0xF;
+ pba_num[1] = (nvm_data >> 8) & 0xF;
+ pba_num[2] = (nvm_data >> 4) & 0xF;
+ pba_num[3] = nvm_data & 0xF;
+ pba_num[4] = (pba_ptr >> 12) & 0xF;
+ pba_num[5] = (pba_ptr >> 8) & 0xF;
+ pba_num[6] = '-';
+ pba_num[7] = 0;
+ pba_num[8] = (pba_ptr >> 4) & 0xF;
+ pba_num[9] = pba_ptr & 0xF;
+
+ /* put a null character on the end of our string */
+ pba_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (pba_num[offset] < 0xA)
+ pba_num[offset] += '0';
+ else if (pba_num[offset] < 0x10)
+ pba_num[offset] += 'A' - 0xA;
+ }
+
+ goto out;
+ }
+
+ ret_val = e1000_read_nvm(hw, pba_ptr, 1, &length);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ e_dbg("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+ /* check if pba_num buffer is big enough */
+ if (pba_num_size < (((u32)length * 2) - 1)) {
+ e_dbg("PBA string buffer too small\n");
+ ret_val = E1000_ERR_NO_SPACE;
+ goto out;
+ }
+
+ /* trim pba length from start of string */
+ pba_ptr++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = e1000_read_nvm(hw, pba_ptr + offset, 1, &nvm_data);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+ pba_num[offset * 2] = (u8)(nvm_data >> 8);
+ pba_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
+ }
+ pba_num[offset * 2] = '\0';
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_read_mac_addr_generic - Read device MAC address
* @hw: pointer to the HW structure
*
@@ -2579,25 +2691,3 @@ bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
out:
return ret_val;
}
-
-s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
-{
- s32 ret_val;
- u16 nvm_data;
-
- ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
- if (ret_val) {
- e_dbg("NVM Read Error\n");
- return ret_val;
- }
- *pba_num = (u32)(nvm_data << 16);
-
- ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
- if (ret_val) {
- e_dbg("NVM Read Error\n");
- return ret_val;
- }
- *pba_num |= nvm_data;
-
- return 0;
-}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index c4ca1629f532..1c18f26b0812 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -54,7 +54,7 @@
#define DRV_EXTRAVERSION "-k2"
-#define DRV_VERSION "1.2.7" DRV_EXTRAVERSION
+#define DRV_VERSION "1.2.20" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -77,17 +77,17 @@ struct e1000_reg_info {
char *name;
};
-#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
-#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
-#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
-#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
-#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
+#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
+#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
-#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
-#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
static const struct e1000_reg_info e1000_reg_info_tbl[] = {
@@ -99,7 +99,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
/* Interrupt Registers */
{E1000_ICR, "ICR"},
- /* RX Registers */
+ /* Rx Registers */
{E1000_RCTL, "RCTL"},
{E1000_RDLEN, "RDLEN"},
{E1000_RDH, "RDH"},
@@ -115,7 +115,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
{E1000_RDFTS, "RDFTS"},
{E1000_RDFPC, "RDFPC"},
- /* TX Registers */
+ /* Tx Registers */
{E1000_TCTL, "TCTL"},
{E1000_TDBAL, "TDBAL"},
{E1000_TDBAH, "TDBAH"},
@@ -160,7 +160,7 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
break;
default:
printk(KERN_INFO "%-15s %08x\n",
- reginfo->name, __er32(hw, reginfo->ofs));
+ reginfo->name, __er32(hw, reginfo->ofs));
return;
}
@@ -171,9 +171,8 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
printk(KERN_CONT "\n");
}
-
/*
- * e1000e_dump - Print registers, tx-ring and rx-ring
+ * e1000e_dump - Print registers, Tx-ring and Rx-ring
*/
static void e1000e_dump(struct e1000_adapter *adapter)
{
@@ -182,12 +181,20 @@ static void e1000e_dump(struct e1000_adapter *adapter)
struct e1000_reg_info *reginfo;
struct e1000_ring *tx_ring = adapter->tx_ring;
struct e1000_tx_desc *tx_desc;
- struct my_u0 { u64 a; u64 b; } *u0;
+ struct my_u0 {
+ u64 a;
+ u64 b;
+ } *u0;
struct e1000_buffer *buffer_info;
struct e1000_ring *rx_ring = adapter->rx_ring;
union e1000_rx_desc_packet_split *rx_desc_ps;
struct e1000_rx_desc *rx_desc;
- struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+ struct my_u1 {
+ u64 a;
+ u64 b;
+ u64 c;
+ u64 d;
+ } *u1;
u32 staterr;
int i = 0;
@@ -198,12 +205,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
if (netdev) {
dev_info(&adapter->pdev->dev, "Net device Info\n");
printk(KERN_INFO "Device Name state "
- "trans_start last_rx\n");
+ "trans_start last_rx\n");
printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
- netdev->name,
- netdev->state,
- netdev->trans_start,
- netdev->last_rx);
+ netdev->name, netdev->state, netdev->trans_start,
+ netdev->last_rx);
}
/* Print Registers */
@@ -214,26 +219,26 @@ static void e1000e_dump(struct e1000_adapter *adapter)
e1000_regdump(hw, reginfo);
}
- /* Print TX Ring Summary */
+ /* Print Tx Ring Summary */
if (!netdev || !netif_running(netdev))
goto exit;
- dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+ dev_info(&adapter->pdev->dev, "Tx Ring Summary\n");
printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma ]"
- " leng ntw timestamp\n");
+ " leng ntw timestamp\n");
buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
- 0, tx_ring->next_to_use, tx_ring->next_to_clean,
- (unsigned long long)buffer_info->dma,
- buffer_info->length,
- buffer_info->next_to_watch,
- (unsigned long long)buffer_info->time_stamp);
+ 0, tx_ring->next_to_use, tx_ring->next_to_clean,
+ (unsigned long long)buffer_info->dma,
+ buffer_info->length,
+ buffer_info->next_to_watch,
+ (unsigned long long)buffer_info->time_stamp);
- /* Print TX Rings */
+ /* Print Tx Ring */
if (!netif_msg_tx_done(adapter))
goto rx_ring_summary;
- dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+ dev_info(&adapter->pdev->dev, "Tx Ring Dump\n");
/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
*
@@ -263,22 +268,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
* 63 48 47 40 39 36 35 32 31 24 23 20 19 0
*/
printk(KERN_INFO "Tl[desc] [address 63:0 ] [SpeCssSCmCsLen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Legacy format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Legacy format\n");
printk(KERN_INFO "Tc[desc] [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Ext Context format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Ext Context format\n");
printk(KERN_INFO "Td[desc] [address 63:0 ] [VlaPoRSCm1Dlen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Ext Data format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Ext Data format\n");
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
printk(KERN_INFO "T%c[0x%03X] %016llX %016llX %016llX "
- "%04X %3X %016llX %p",
- (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
- ((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+ "%04X %3X %016llX %p",
+ (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
+ ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')), i,
(unsigned long long)le64_to_cpu(u0->a),
(unsigned long long)le64_to_cpu(u0->b),
(unsigned long long)buffer_info->dma,
@@ -296,22 +301,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
- 16, 1, phys_to_virt(buffer_info->dma),
- buffer_info->length, true);
+ 16, 1, phys_to_virt(buffer_info->dma),
+ buffer_info->length, true);
}
- /* Print RX Rings Summary */
+ /* Print Rx Ring Summary */
rx_ring_summary:
- dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+ dev_info(&adapter->pdev->dev, "Rx Ring Summary\n");
printk(KERN_INFO "Queue [NTU] [NTC]\n");
printk(KERN_INFO " %5d %5X %5X\n", 0,
- rx_ring->next_to_use, rx_ring->next_to_clean);
+ rx_ring->next_to_use, rx_ring->next_to_clean);
- /* Print RX Rings */
+ /* Print Rx Ring */
if (!netif_msg_rx_status(adapter))
goto exit;
- dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+ dev_info(&adapter->pdev->dev, "Rx Ring Dump\n");
switch (adapter->rx_ps_pages) {
case 1:
case 2:
@@ -329,7 +334,7 @@ rx_ring_summary:
* +-----------------------------------------------------+
*/
printk(KERN_INFO "R [desc] [buffer 0 63:0 ] "
- "[buffer 1 63:0 ] "
+ "[buffer 1 63:0 ] "
"[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma ] "
"[bi->skb] <-- Ext Pkt Split format\n");
/* [Extended] Receive Descriptor (Write-Back) Format
@@ -344,7 +349,7 @@ rx_ring_summary:
* 63 48 47 32 31 20 19 0
*/
printk(KERN_INFO "RWB[desc] [ck ipid mrqhsh] "
- "[vl l0 ee es] "
+ "[vl l0 ee es] "
"[ l3 l2 l1 hs] [reserved ] ---------------- "
"[bi->skb] <-- Ext Rx Write-Back format\n");
for (i = 0; i < rx_ring->count; i++) {
@@ -352,26 +357,26 @@ rx_ring_summary:
rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
u1 = (struct my_u1 *)rx_desc_ps;
staterr =
- le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+ le32_to_cpu(rx_desc_ps->wb.middle.status_error);
if (staterr & E1000_RXD_STAT_DD) {
/* Descriptor Done */
printk(KERN_INFO "RWB[0x%03X] %016llX "
- "%016llX %016llX %016llX "
- "---------------- %p", i,
- (unsigned long long)le64_to_cpu(u1->a),
- (unsigned long long)le64_to_cpu(u1->b),
- (unsigned long long)le64_to_cpu(u1->c),
- (unsigned long long)le64_to_cpu(u1->d),
- buffer_info->skb);
+ "%016llX %016llX %016llX "
+ "---------------- %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
+ buffer_info->skb);
} else {
printk(KERN_INFO "R [0x%03X] %016llX "
- "%016llX %016llX %016llX %016llX %p", i,
- (unsigned long long)le64_to_cpu(u1->a),
- (unsigned long long)le64_to_cpu(u1->b),
- (unsigned long long)le64_to_cpu(u1->c),
- (unsigned long long)le64_to_cpu(u1->d),
- (unsigned long long)buffer_info->dma,
- buffer_info->skb);
+ "%016llX %016llX %016llX %016llX %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
if (netif_msg_pktdata(adapter))
print_hex_dump(KERN_INFO, "",
@@ -400,18 +405,18 @@ rx_ring_summary:
* 63 48 47 40 39 32 31 16 15 0
*/
printk(KERN_INFO "Rl[desc] [address 63:0 ] "
- "[vl er S cks ln] [bi->dma ] [bi->skb] "
- "<-- Legacy format\n");
+ "[vl er S cks ln] [bi->dma ] [bi->skb] "
+ "<-- Legacy format\n");
for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
u0 = (struct my_u0 *)rx_desc;
printk(KERN_INFO "Rl[0x%03X] %016llX %016llX "
- "%016llX %p", i,
- (unsigned long long)le64_to_cpu(u0->a),
- (unsigned long long)le64_to_cpu(u0->b),
- (unsigned long long)buffer_info->dma,
- buffer_info->skb);
+ "%016llX %p", i,
+ (unsigned long long)le64_to_cpu(u0->a),
+ (unsigned long long)le64_to_cpu(u0->b),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
if (i == rx_ring->next_to_use)
printk(KERN_CONT " NTU\n");
else if (i == rx_ring->next_to_clean)
@@ -421,9 +426,10 @@ rx_ring_summary:
if (netif_msg_pktdata(adapter))
print_hex_dump(KERN_INFO, "",
- DUMP_PREFIX_ADDRESS,
- 16, 1, phys_to_virt(buffer_info->dma),
- adapter->rx_buffer_len, true);
+ DUMP_PREFIX_ADDRESS,
+ 16, 1,
+ phys_to_virt(buffer_info->dma),
+ adapter->rx_buffer_len, true);
}
}
@@ -450,8 +456,7 @@ static int e1000_desc_unused(struct e1000_ring *ring)
* @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,
+ struct net_device *netdev, struct sk_buff *skb,
u8 status, __le16 vlan)
{
skb->protocol = eth_type_trans(skb, netdev);
@@ -464,7 +469,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
}
/**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * e1000_rx_checksum - Receive Checksum Offload
* @adapter: board private structure
* @status_err: receive descriptor status and error fields
* @csum: receive descriptor csum field
@@ -548,7 +553,7 @@ map_skb:
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
- dev_err(&pdev->dev, "RX DMA map failed\n");
+ dev_err(&pdev->dev, "Rx DMA map failed\n");
adapter->rx_dma_failed++;
break;
}
@@ -601,7 +606,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
ps_page = &buffer_info->ps_pages[j];
if (j >= adapter->rx_ps_pages) {
/* all unused desc entries get hw null ptr */
- rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
+ rx_desc->read.buffer_addr[j + 1] =
+ ~cpu_to_le64(0);
continue;
}
if (!ps_page->page) {
@@ -617,7 +623,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
if (dma_mapping_error(&pdev->dev,
ps_page->dma)) {
dev_err(&adapter->pdev->dev,
- "RX DMA page map failed\n");
+ "Rx DMA page map failed\n");
adapter->rx_dma_failed++;
goto no_buffers;
}
@@ -627,8 +633,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
* didn't change because each write-back
* erases this info.
*/
- rx_desc->read.buffer_addr[j+1] =
- cpu_to_le64(ps_page->dma);
+ rx_desc->read.buffer_addr[j + 1] =
+ cpu_to_le64(ps_page->dma);
}
skb = netdev_alloc_skb_ip_align(netdev,
@@ -644,7 +650,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
adapter->rx_ps_bsize0,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
- dev_err(&pdev->dev, "RX DMA map failed\n");
+ dev_err(&pdev->dev, "Rx DMA map failed\n");
adapter->rx_dma_failed++;
/* cleanup skb */
dev_kfree_skb_any(skb);
@@ -662,7 +668,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
* such as IA-64).
*/
wmb();
- writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+ writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
}
i++;
@@ -1106,11 +1112,10 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
cleaned = 1;
cleaned_count++;
dma_unmap_single(&pdev->dev, buffer_info->dma,
- adapter->rx_ps_bsize0,
- DMA_FROM_DEVICE);
+ adapter->rx_ps_bsize0, DMA_FROM_DEVICE);
buffer_info->dma = 0;
- /* see !EOP comment in other rx routine */
+ /* see !EOP comment in other Rx routine */
if (!(staterr & E1000_RXD_STAT_EOP))
adapter->flags2 |= FLAG2_IS_DISCARDING;
@@ -1325,7 +1330,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
goto next_desc;
}
-#define rxtop rx_ring->rx_skb_top
+#define rxtop (rx_ring->rx_skb_top)
if (!(status & E1000_RXD_STAT_EOP)) {
/* this descriptor is only the beginning (or middle) */
if (!rxtop) {
@@ -1806,9 +1811,8 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
err = pci_enable_msix(adapter->pdev,
adapter->msix_entries,
adapter->num_vectors);
- if (err == 0) {
+ if (err == 0)
return;
- }
}
/* MSI-X failed, so fall through and try MSI */
e_err("Failed to initialize MSI-X interrupts. "
@@ -1981,15 +1985,15 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
}
/**
- * e1000_get_hw_control - get control of the h/w from f/w
+ * e1000e_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|SWSM}:DRV_LOAD bit.
+ * e1000e_get_hw_control sets {CTRL_EXT|SWSM}: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)
+void e1000e_get_hw_control(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_ext;
@@ -2006,16 +2010,16 @@ static void e1000_get_hw_control(struct e1000_adapter *adapter)
}
/**
- * e1000_release_hw_control - release control of the h/w to f/w
+ * e1000e_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|SWSM}:DRV_LOAD bit.
+ * e1000e_release_hw_control resets {CTRL_EXT|SWSM}: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)
+void e1000e_release_hw_control(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_ext;
@@ -2059,10 +2063,9 @@ int e1000e_setup_tx_resources(struct e1000_adapter *adapter)
int err = -ENOMEM, size;
size = sizeof(struct e1000_buffer) * tx_ring->count;
- tx_ring->buffer_info = vmalloc(size);
+ tx_ring->buffer_info = vzalloc(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);
@@ -2095,10 +2098,9 @@ int e1000e_setup_rx_resources(struct e1000_adapter *adapter)
int i, size, desc_len, err = -ENOMEM;
size = sizeof(struct e1000_buffer) * rx_ring->count;
- rx_ring->buffer_info = vmalloc(size);
+ rx_ring->buffer_info = vzalloc(size);
if (!rx_ring->buffer_info)
goto err;
- memset(rx_ring->buffer_info, 0, size);
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
@@ -2132,7 +2134,7 @@ err_pages:
}
err:
vfree(rx_ring->buffer_info);
- e_err("Unable to allocate memory for the transmit descriptor ring\n");
+ e_err("Unable to allocate memory for the receive descriptor ring\n");
return err;
}
@@ -2200,9 +2202,8 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
e1000_clean_rx_ring(adapter);
- for (i = 0; i < rx_ring->count; i++) {
+ for (i = 0; i < rx_ring->count; i++)
kfree(rx_ring->buffer_info[i].ps_pages);
- }
vfree(rx_ring->buffer_info);
rx_ring->buffer_info = NULL;
@@ -2242,20 +2243,18 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
/* handle TSO and jumbo frames */
if (bytes/packets > 8000)
retval = bulk_latency;
- else if ((packets < 5) && (bytes > 512)) {
+ 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) {
+ if (bytes/packets > 8000)
retval = bulk_latency;
- } else if ((packets < 10) || ((bytes/packets) > 1200)) {
+ else if ((packets < 10) || ((bytes/packets) > 1200))
retval = bulk_latency;
- } else if ((packets > 35)) {
+ else if ((packets > 35))
retval = lowest_latency;
- }
} else if (bytes/packets > 2000) {
retval = bulk_latency;
} else if (packets <= 2 && bytes < 512) {
@@ -2264,9 +2263,8 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
break;
case bulk_latency: /* 250 usec aka 4000 ints/s */
if (bytes > 25000) {
- if (packets > 35) {
+ if (packets > 35)
retval = low_latency;
- }
} else if (bytes < 6000) {
retval = low_latency;
}
@@ -2452,7 +2450,7 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
(vid == adapter->mng_vlan_id)) {
/* release control to f/w */
- e1000_release_hw_control(adapter);
+ e1000e_release_hw_control(adapter);
return;
}
@@ -2617,7 +2615,7 @@ static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
}
/**
- * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * e1000_configure_tx - Configure Transmit Unit after Reset
* @adapter: board private structure
*
* Configure the Tx unit of the MAC after a reset.
@@ -2670,7 +2668,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
* hthresh = 1 ==> prefetch when one or more available
* pthresh = 0x1f ==> prefetch if internal cache 31 or less
* BEWARE: this seems to work but should be considered first if
- * there are tx hangs or other tx related bugs
+ * there are Tx hangs or other Tx related bugs
*/
txdctl |= E1000_TXDCTL_DMA_BURST_ENABLE;
ew32(TXDCTL(0), txdctl);
@@ -2741,6 +2739,9 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
else
ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+
+ if (ret_val)
+ e_dbg("failed to enable jumbo frame workaround mode\n");
}
/* Program MC offset vector base */
@@ -2881,7 +2882,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
if (adapter->rx_ps_pages) {
/* this is a 32 byte descriptor */
rdlen = rx_ring->count *
- sizeof(union e1000_rx_desc_packet_split);
+ sizeof(union e1000_rx_desc_packet_split);
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
} else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
@@ -2904,7 +2905,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
/*
* set the writeback threshold (only takes effect if the RDTR
* is set). set GRAN=1 and write back up to 0x4 worth, and
- * enable prefetching of 0x20 rx descriptors
+ * enable prefetching of 0x20 Rx descriptors
* granularity = 01
* wthresh = 04,
* hthresh = 04,
@@ -2985,12 +2986,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* excessive C-state transition latencies result in
* dropped transactions.
*/
- pm_qos_update_request(
- &adapter->netdev->pm_qos_req, 55);
+ pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
} else {
- pm_qos_update_request(
- &adapter->netdev->pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&adapter->netdev->pm_qos_req,
+ PM_QOS_DEFAULT_VALUE);
}
}
@@ -3156,7 +3155,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
/*
- * the Tx fifo also stores 16 bytes of information about the tx
+ * 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 = (adapter->max_frame_size +
@@ -3179,7 +3178,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
pba -= min_tx_space - tx_space;
/*
- * if short on Rx space, Rx wins and must trump tx
+ * if short on Rx space, Rx wins and must trump Tx
* adjustment or use Early Receive if available
*/
if ((pba < min_rx_space) &&
@@ -3191,7 +3190,6 @@ void e1000e_reset(struct e1000_adapter *adapter)
ew32(PBA, pba);
}
-
/*
* flow control settings
*
@@ -3279,7 +3277,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
* that the network interface is in control
*/
if (adapter->flags & FLAG_HAS_AMT)
- e1000_get_hw_control(adapter);
+ e1000e_get_hw_control(adapter);
ew32(WUC, 0);
@@ -3292,6 +3290,13 @@ void e1000e_reset(struct e1000_adapter *adapter)
ew32(VET, ETH_P_8021Q);
e1000e_reset_adaptive(hw);
+
+ if (!netif_running(adapter->netdev) &&
+ !test_bit(__E1000_TESTING, &adapter->state)) {
+ e1000_power_down_phy(adapter);
+ return;
+ }
+
e1000_get_phy_info(hw);
if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) &&
@@ -3577,7 +3582,7 @@ static int e1000_open(struct net_device *netdev)
* interface is now open and reset the part to a known state.
*/
if (adapter->flags & FLAG_HAS_AMT) {
- e1000_get_hw_control(adapter);
+ e1000e_get_hw_control(adapter);
e1000e_reset(adapter);
}
@@ -3641,7 +3646,7 @@ static int e1000_open(struct net_device *netdev)
return 0;
err_req_irq:
- e1000_release_hw_control(adapter);
+ e1000e_release_hw_control(adapter);
e1000_power_down_phy(adapter);
e1000e_free_rx_resources(adapter);
err_setup_rx:
@@ -3696,8 +3701,9 @@ static int e1000_close(struct net_device *netdev)
* If AMT is enabled, let the firmware know that the network
* interface is now closed
*/
- if (adapter->flags & FLAG_HAS_AMT)
- e1000_release_hw_control(adapter);
+ if ((adapter->flags & FLAG_HAS_AMT) &&
+ !test_bit(__E1000_TESTING, &adapter->state))
+ e1000e_release_hw_control(adapter);
if ((adapter->flags & FLAG_HAS_ERT) ||
(adapter->hw.mac.type == e1000_pch2lan))
@@ -4036,11 +4042,11 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
adapter->netdev->name,
adapter->link_speed,
(adapter->link_duplex == FULL_DUPLEX) ?
- "Full Duplex" : "Half 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" )));
+ "Rx/Tx" :
+ ((ctrl & E1000_CTRL_RFCE) ? "Rx" :
+ ((ctrl & E1000_CTRL_TFCE) ? "Tx" : "None")));
}
static bool e1000e_has_link(struct e1000_adapter *adapter)
@@ -4335,7 +4341,7 @@ link_up:
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = 1;
- /* flush partial descriptors to memory before detecting tx hang */
+ /* flush partial descriptors to memory before detecting Tx hang */
if (adapter->flags2 & FLAG2_DMA_BURST) {
ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
@@ -4475,7 +4481,7 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
break;
}
- css = skb_transport_offset(skb);
+ css = skb_checksum_start_offset(skb);
i = tx_ring->next_to_use;
buffer_info = &tx_ring->buffer_info[i];
@@ -4526,7 +4532,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
buffer_info->next_to_watch = i;
buffer_info->dma = dma_map_single(&pdev->dev,
skb->data + offset,
- size, DMA_TO_DEVICE);
+ size, DMA_TO_DEVICE);
buffer_info->mapped_as_page = false;
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
@@ -4573,7 +4579,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
}
- segs = skb_shinfo(skb)->gso_segs ?: 1;
+ segs = skb_shinfo(skb)->gso_segs ? : 1;
/* multiply data chunks by size of headers */
bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
@@ -4585,17 +4591,17 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
return count;
dma_error:
- dev_err(&pdev->dev, "TX DMA map failed\n");
+ dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
if (count)
count--;
while (count--) {
- if (i==0)
+ if (i == 0)
i += tx_ring->count;
i--;
buffer_info = &tx_ring->buffer_info[i];
- e1000_put_txbuf(adapter, buffer_info);;
+ e1000_put_txbuf(adapter, buffer_info);
}
return 0;
@@ -4631,7 +4637,7 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
i = tx_ring->next_to_use;
- while (count--) {
+ do {
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);
@@ -4642,7 +4648,7 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
i++;
if (i == tx_ring->count)
i = 0;
- }
+ } while (--count > 0);
tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
@@ -5216,7 +5222,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,
* 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);
+ e1000e_release_hw_control(adapter);
pci_disable_device(pdev);
@@ -5373,7 +5379,7 @@ static int __e1000_resume(struct pci_dev *pdev)
* under the control of the driver.
*/
if (!(adapter->flags & FLAG_HAS_AMT))
- e1000_get_hw_control(adapter);
+ e1000e_get_hw_control(adapter);
return 0;
}
@@ -5465,6 +5471,36 @@ static void e1000_shutdown(struct pci_dev *pdev)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
+
+static irqreturn_t e1000_intr_msix(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ int vector, msix_irq;
+
+ if (adapter->msix_entries) {
+ vector = 0;
+ msix_irq = adapter->msix_entries[vector].vector;
+ disable_irq(msix_irq);
+ e1000_intr_msix_rx(msix_irq, netdev);
+ enable_irq(msix_irq);
+
+ vector++;
+ msix_irq = adapter->msix_entries[vector].vector;
+ disable_irq(msix_irq);
+ e1000_intr_msix_tx(msix_irq, netdev);
+ enable_irq(msix_irq);
+
+ vector++;
+ msix_irq = adapter->msix_entries[vector].vector;
+ disable_irq(msix_irq);
+ e1000_msix_other(msix_irq, netdev);
+ enable_irq(msix_irq);
+ }
+
+ return IRQ_HANDLED;
+}
+
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
@@ -5474,10 +5510,21 @@ 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);
-
- enable_irq(adapter->pdev->irq);
+ switch (adapter->int_mode) {
+ case E1000E_INT_MODE_MSIX:
+ e1000_intr_msix(adapter->pdev->irq, netdev);
+ break;
+ case E1000E_INT_MODE_MSI:
+ disable_irq(adapter->pdev->irq);
+ e1000_intr_msi(adapter->pdev->irq, netdev);
+ enable_irq(adapter->pdev->irq);
+ break;
+ default: /* E1000E_INT_MODE_LEGACY */
+ disable_irq(adapter->pdev->irq);
+ e1000_intr(adapter->pdev->irq, netdev);
+ enable_irq(adapter->pdev->irq);
+ break;
+ }
}
#endif
@@ -5579,7 +5626,7 @@ static void e1000_io_resume(struct pci_dev *pdev)
* under the control of the driver.
*/
if (!(adapter->flags & FLAG_HAS_AMT))
- e1000_get_hw_control(adapter);
+ e1000e_get_hw_control(adapter);
}
@@ -5587,7 +5634,8 @@ static void e1000_print_device_info(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
- u32 pba_num;
+ u32 ret_val;
+ u8 pba_str[E1000_PBANUM_LENGTH];
/* print bus type/speed/width info */
e_info("(PCI Express:2.5GB/s:%s) %pM\n",
@@ -5598,9 +5646,12 @@ static void e1000_print_device_info(struct e1000_adapter *adapter)
netdev->dev_addr);
e_info("Intel(R) PRO/%s Network Connection\n",
(hw->phy.type == e1000_phy_ife) ? "10/100" : "1000");
- e1000e_read_pba_num(hw, &pba_num);
- e_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type, (pba_num >> 8), (pba_num & 0xff));
+ ret_val = e1000_read_pba_string_generic(hw, pba_str,
+ E1000_PBANUM_LENGTH);
+ if (ret_val)
+ strncpy((char *)pba_str, "Unknown", sizeof(pba_str) - 1);
+ e_info("MAC: %d, PHY: %d, PBA No: %s\n",
+ hw->mac.type, hw->phy.type, pba_str);
}
static void e1000_eeprom_checks(struct e1000_adapter *adapter)
@@ -5864,6 +5915,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang);
+ INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
/* Initialize link parameters. User can change them with ethtool */
adapter->hw.mac.autoneg = 1;
@@ -5924,9 +5976,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
* under the control of the driver.
*/
if (!(adapter->flags & FLAG_HAS_AMT))
- e1000_get_hw_control(adapter);
+ e1000e_get_hw_control(adapter);
- strcpy(netdev->name, "eth%d");
+ strncpy(netdev->name, "eth%d", sizeof(netdev->name) - 1);
err = register_netdev(netdev);
if (err)
goto err_register;
@@ -5943,12 +5995,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
err_register:
if (!(adapter->flags & FLAG_HAS_AMT))
- e1000_release_hw_control(adapter);
+ e1000e_release_hw_control(adapter);
err_eeprom:
if (!e1000_check_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
err_hw_init:
-
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
err_sw_init:
@@ -5984,8 +6035,8 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
bool down = test_bit(__E1000_DOWN, &adapter->state);
/*
- * flush_scheduled work may reschedule our watchdog task, so
- * explicitly disable watchdog tasks from being rescheduled
+ * The timers may be rescheduled, so explicitly disable them
+ * from being rescheduled.
*/
if (!down)
set_bit(__E1000_DOWN, &adapter->state);
@@ -5996,8 +6047,8 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->downshift_task);
cancel_work_sync(&adapter->update_phy_task);
+ cancel_work_sync(&adapter->led_blink_task);
cancel_work_sync(&adapter->print_hang_task);
- flush_scheduled_work();
if (!(netdev->flags & IFF_UP))
e1000_power_down_phy(adapter);
@@ -6014,7 +6065,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
* 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);
+ e1000e_release_hw_control(adapter);
e1000e_reset_interrupt_capability(adapter);
kfree(adapter->tx_ring);
@@ -6145,7 +6196,7 @@ static int __init e1000_init_module(void)
int ret;
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright (c) 1999 - 2010 Intel Corporation.\n");
+ pr_info("Copyright(c) 1999 - 2011 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index 3d36911f77f3..4dd9b63273f6 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -62,10 +62,9 @@ MODULE_PARM_DESC(copybreak,
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
+ * Tx interrupt delay needs to typically be set to something non-zero
*
* Valid Range: 0-65535
*/
@@ -112,6 +111,7 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
+
/* IntMode (Interrupt Mode)
*
* Valid Range: 0 - 2
@@ -421,7 +421,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
static const struct e1000_option opt = {
.type = enable_option,
.name = "CRC Stripping",
- .err = "defaulting to enabled",
+ .err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 3d3dc0c82355..6bea051b134b 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -42,20 +42,20 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
u16 *data, bool read);
/* 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_m88_cable_length_table[] = {
+ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_m88_cable_length_table)
-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};
+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 \
ARRAY_SIZE(e1000_igp_2_cable_length_table)
@@ -226,6 +226,13 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
}
*data = (u16) mdic;
+ /*
+ * Allow some time after each MDIC transaction to avoid
+ * reading duplicate data in the next MDIC transaction.
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ udelay(100);
+
return 0;
}
@@ -279,6 +286,13 @@ s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
return -E1000_ERR_PHY;
}
+ /*
+ * Allow some time after each MDIC transaction to avoid
+ * reading duplicate data in the next MDIC transaction.
+ */
+ if (hw->mac.type == e1000_pch2lan)
+ udelay(100);
+
return 0;
}
@@ -623,12 +637,11 @@ s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
**/
s32 e1000_copper_link_setup_82577(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 = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data);
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
+ ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data);
if (ret_val)
goto out;
@@ -637,7 +650,7 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
/* Enable downshift */
phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
- ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
+ ret_val = e1e_wphy(hw, I82577_CFG_REG, phy_data);
out:
return ret_val;
@@ -760,16 +773,14 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
}
if (phy->type == e1000_phy_82578) {
- ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
- &phy_data);
+ ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
return ret_val;
/* 82578 PHY - set the downshift count to 1x. */
phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
- ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
- phy_data);
+ ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
if (ret_val)
return ret_val;
}
@@ -1043,9 +1054,8 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL)
ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- }
return ret_val;
}
@@ -1306,9 +1316,8 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
* We didn't get link.
* Reset the DSP and cross our fingers.
*/
- ret_val = e1e_wphy(hw,
- M88E1000_PHY_PAGE_SELECT,
- 0x001d);
+ ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
if (ret_val)
return ret_val;
ret_val = e1000e_phy_reset_dsp(hw);
@@ -1840,11 +1849,12 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
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};
+ static const 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++) {
@@ -2976,7 +2986,7 @@ s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data)
}
/**
- * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ * e1000_get_phy_addr_for_hv_page - Get PHY address based on page
* @page: page to be accessed
**/
static u32 e1000_get_phy_addr_for_hv_page(u32 page)
@@ -3057,12 +3067,12 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
goto out;
/* Do not apply workaround if in PHY loopback bit 14 set */
- hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
+ e1e_rphy(hw, PHY_CONTROL, &data);
if (data & PHY_CONTROL_LB)
goto out;
/* check if link is up and at 1Gbps */
- ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
+ ret_val = e1e_rphy(hw, BM_CS_STATUS, &data);
if (ret_val)
goto out;
@@ -3078,14 +3088,12 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
mdelay(200);
/* flush the packets in the fifo buffer */
- ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
- HV_MUX_DATA_CTRL_GEN_TO_MAC |
- HV_MUX_DATA_CTRL_FORCE_SPEED);
+ ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, HV_MUX_DATA_CTRL_GEN_TO_MAC |
+ HV_MUX_DATA_CTRL_FORCE_SPEED);
if (ret_val)
goto out;
- ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
- HV_MUX_DATA_CTRL_GEN_TO_MAC);
+ ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, HV_MUX_DATA_CTRL_GEN_TO_MAC);
out:
return ret_val;
@@ -3105,7 +3113,7 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw)
s32 ret_val;
u16 data;
- ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+ ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
if (!ret_val)
phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
@@ -3128,13 +3136,13 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
u16 phy_data;
bool link;
- ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
if (ret_val)
goto out;
e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
- ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
if (ret_val)
goto out;
@@ -3198,7 +3206,7 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
if (ret_val)
goto out;
- ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+ ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
if (ret_val)
goto out;
@@ -3210,7 +3218,7 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
if (ret_val)
goto out;
- ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+ ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
if (ret_val)
goto out;
@@ -3244,7 +3252,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
s32 ret_val;
u16 phy_data, length;
- ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+ ret_val = e1e_rphy(hw, I82577_PHY_DIAG_STATUS, &phy_data);
if (ret_val)
goto out;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 06e72fbef862..94ec973b2bdc 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -216,7 +216,7 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr)
printk(" %02X", station_addr[i]);
if (dev->irq < 2) {
- int irqlist[] = {15, 11, 10, 12, 5, 9, 3, 4};
+ static const int irqlist[] = {15, 11, 10, 12, 5, 9, 3, 4};
for (i = 0; i < ARRAY_SIZE(irqlist); i++)
if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) {
dev->irq = irqlist[i];
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 7c826319ee5a..eb35951a2442 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -302,7 +302,7 @@ struct eepro_local {
#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */
#define ee_id_eepro10p1 0x31
-#define TX_TIMEOUT 40
+#define TX_TIMEOUT ((4*HZ)/10)
/* Index to functions, as function prototypes. */
@@ -891,12 +891,13 @@ err:
there is non-reboot way to recover if something goes wrong.
*/
-static char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
+static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
static int eepro_grab_irq(struct net_device *dev)
{
- int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
- int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
+ static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
+ const int *irqp = irqlist;
+ int temp_reg, ioaddr = dev->base_addr;
eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
@@ -1760,7 +1761,7 @@ module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(mem, int, NULL, 0);
module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)");
+MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 12c37d264108..48ee51bb9e50 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -1103,7 +1103,7 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
{
- static char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};
+ static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
/* Use the IRQ from EEPROM if none was given */
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 8e745e74828d..6c7257bd73fc 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0106"
+#define DRV_VERSION "EHEA_0107"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
@@ -130,19 +130,6 @@
/* utility functions */
-#define ehea_info(fmt, args...) \
- printk(KERN_INFO DRV_NAME ": " fmt "\n", ## args)
-
-#define ehea_error(fmt, args...) \
- printk(KERN_ERR DRV_NAME ": Error in %s: " fmt "\n", __func__, ## args)
-
-#ifdef DEBUG
-#define ehea_debug(fmt, args...) \
- printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
-#else
-#define ehea_debug(fmt, args...) do {} while (0)
-#endif
-
void ehea_dump(void *adr, int len, char *msg);
#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
@@ -515,6 +502,4 @@ void ehea_set_ethtool_ops(struct net_device *netdev);
int ehea_sense_port_attr(struct ehea_port *port);
int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
-extern struct work_struct ehea_rereg_mr_task;
-
#endif /* __EHEA_H__ */
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 75b099ce49c9..3e2e734fecb7 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "ehea.h"
#include "ehea_phyp.h"
@@ -118,10 +120,10 @@ doit:
ret = ehea_set_portspeed(port, sp);
if (!ret)
- ehea_info("%s: Port speed successfully set: %dMbps "
- "%s Duplex",
- port->netdev->name, port->port_speed,
- port->full_duplex == 1 ? "Full" : "Half");
+ netdev_info(dev,
+ "Port speed successfully set: %dMbps %s Duplex\n",
+ port->port_speed,
+ port->full_duplex == 1 ? "Full" : "Half");
out:
return ret;
}
@@ -134,10 +136,10 @@ static int ehea_nway_reset(struct net_device *dev)
ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
if (!ret)
- ehea_info("%s: Port speed successfully set: %dMbps "
- "%s Duplex",
- port->netdev->name, port->port_speed,
- port->full_duplex == 1 ? "Full" : "Half");
+ netdev_info(port->netdev,
+ "Port speed successfully set: %dMbps %s Duplex\n",
+ port->port_speed,
+ port->full_duplex == 1 ? "Full" : "Half");
return ret;
}
@@ -261,6 +263,20 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
}
+static int ehea_set_flags(struct net_device *dev, u32 data)
+{
+ /* Avoid changing the VLAN flags */
+ if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) !=
+ (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN |
+ ETH_FLAG_TXVLAN))){
+ return -EINVAL;
+ }
+
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
+ | ETH_FLAG_TXVLAN
+ | ETH_FLAG_RXVLAN);
+}
+
const struct ethtool_ops ehea_ethtool_ops = {
.get_settings = ehea_get_settings,
.get_drvinfo = ehea_get_drvinfo,
@@ -273,6 +289,8 @@ const struct ethtool_ops ehea_ethtool_ops = {
.get_ethtool_stats = ehea_get_ethtool_stats,
.get_rx_csum = ehea_get_rx_csum,
.set_settings = ehea_set_settings,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ehea_set_flags,
.nway_reset = ehea_nway_reset, /* Restart autonegotiation */
};
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 182b2a7be8dc..f75d3144b8a5 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -101,7 +103,6 @@ MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
static int port_name_cnt;
static LIST_HEAD(adapter_list);
static unsigned long ehea_driver_flags;
-struct work_struct ehea_rereg_mr_task;
static DEFINE_MUTEX(dlpar_mem_lock);
struct ehea_fw_handle_array ehea_fw_handles;
struct ehea_bcmc_reg_array ehea_bcmc_regs;
@@ -136,8 +137,8 @@ void ehea_dump(void *adr, int len, char *msg)
int x;
unsigned char *deb = adr;
for (x = 0; x < len; x += 16) {
- printk(DRV_NAME " %s adr=%p ofs=%04x %016llx %016llx\n", msg,
- deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
+ pr_info("%s adr=%p ofs=%04x %016llx %016llx\n",
+ msg, deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
deb += 16;
}
}
@@ -337,7 +338,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
cb2 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb2) {
- ehea_error("no mem for cb2");
+ netdev_err(dev, "no mem for cb2\n");
goto out;
}
@@ -345,7 +346,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
port->logical_port_id,
H_PORT_CB2, H_PORT_CB2_ALL, cb2);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_port failed");
+ netdev_err(dev, "query_ehea_port failed\n");
goto out_herr;
}
@@ -400,6 +401,7 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
+ netdev_info(dev, "Unable to allocate enough skb in the array\n");
pr->rq1_skba.os_skbs = fill_wqes - i;
break;
}
@@ -422,13 +424,20 @@ static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
struct net_device *dev = pr->port->netdev;
int i;
- for (i = 0; i < pr->rq1_skba.len; i++) {
+ if (nr_rq1a > pr->rq1_skba.len) {
+ netdev_err(dev, "NR_RQ1A bigger than skb array len\n");
+ return;
+ }
+
+ for (i = 0; i < nr_rq1a; i++) {
skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
- if (!skb_arr_rq1[i])
+ if (!skb_arr_rq1[i]) {
+ netdev_info(dev, "Not enough memory to allocate skb array\n");
break;
+ }
}
/* Ring doorbell */
- ehea_update_rq1a(pr->qp, nr_rq1a);
+ ehea_update_rq1a(pr->qp, i - 1);
}
static int ehea_refill_rq_def(struct ehea_port_res *pr,
@@ -461,8 +470,9 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
if (!skb) {
q_skba->os_skbs = fill_wqes - i;
if (q_skba->os_skbs == q_skba->len - 2) {
- ehea_info("%s: rq%i ran dry - no mem for skb",
- pr->port->netdev->name, rq_nr);
+ netdev_info(pr->port->netdev,
+ "rq%i ran dry - no mem for skb\n",
+ rq_nr);
ret = -ENOMEM;
}
break;
@@ -627,8 +637,8 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
if (netif_msg_rx_err(pr->port)) {
- ehea_error("Critical receive error for QP %d. "
- "Resetting port.", pr->qp->init_attr.qp_nr);
+ pr_err("Critical receive error for QP %d. Resetting port.\n",
+ pr->qp->init_attr.qp_nr);
ehea_dump(cqe, sizeof(*cqe), "CQE");
}
ehea_schedule_port_reset(pr->port);
@@ -675,7 +685,7 @@ static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
int vlan_extracted = ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) &&
pr->port->vgrp);
- if (use_lro) {
+ if (skb->dev->features & NETIF_F_LRO) {
if (vlan_extracted)
lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
pr->port->vgrp,
@@ -730,13 +740,15 @@ static int ehea_proc_rwqes(struct net_device *dev,
skb_arr_rq1_len,
wqe_index);
if (unlikely(!skb)) {
- if (netif_msg_rx_err(port))
- ehea_error("LL rq1: skb=NULL");
+ netif_info(port, rx_err, dev,
+ "LL rq1: skb=NULL\n");
skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
- if (!skb)
+ if (!skb) {
+ netdev_err(dev, "Not enough memory to allocate skb\n");
break;
+ }
}
skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
@@ -746,8 +758,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
skb = get_skb_by_index(skb_arr_rq2,
skb_arr_rq2_len, cqe);
if (unlikely(!skb)) {
- if (netif_msg_rx_err(port))
- ehea_error("rq2: skb=NULL");
+ netif_err(port, rx_err, dev,
+ "rq2: skb=NULL\n");
break;
}
ehea_fill_skb(dev, skb, cqe);
@@ -757,8 +769,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
skb = get_skb_by_index(skb_arr_rq3,
skb_arr_rq3_len, cqe);
if (unlikely(!skb)) {
- if (netif_msg_rx_err(port))
- ehea_error("rq3: skb=NULL");
+ netif_err(port, rx_err, dev,
+ "rq3: skb=NULL\n");
break;
}
ehea_fill_skb(dev, skb, cqe);
@@ -777,7 +789,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- if (use_lro)
+ if (dev->features & NETIF_F_LRO)
lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
@@ -830,7 +842,7 @@ static void check_sqs(struct ehea_port *port)
msecs_to_jiffies(100));
if (!ret) {
- ehea_error("HW/SW queues out of sync");
+ pr_err("HW/SW queues out of sync\n");
ehea_schedule_port_reset(pr->port);
return;
}
@@ -863,14 +875,14 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
}
if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
- ehea_error("Bad send completion status=0x%04X",
- cqe->status);
+ pr_err("Bad send completion status=0x%04X\n",
+ cqe->status);
if (netif_msg_tx_err(pr->port))
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
if (cqe->status & EHEA_CQE_STAT_RESET_MASK) {
- ehea_error("Resetting port");
+ pr_err("Resetting port\n");
ehea_schedule_port_reset(pr->port);
break;
}
@@ -988,8 +1000,8 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
while (eqe) {
qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
- ehea_error("QP aff_err: entry=0x%llx, token=0x%x",
- eqe->entry, qp_token);
+ pr_err("QP aff_err: entry=0x%llx, token=0x%x\n",
+ eqe->entry, qp_token);
qp = port->port_res[qp_token].qp;
@@ -1007,7 +1019,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
}
if (reset_port) {
- ehea_error("Resetting port");
+ pr_err("Resetting port\n");
ehea_schedule_port_reset(port);
}
@@ -1035,7 +1047,7 @@ int ehea_sense_port_attr(struct ehea_port *port)
/* may be called via ehea_neq_tasklet() */
cb0 = (void *)get_zeroed_page(GFP_ATOMIC);
if (!cb0) {
- ehea_error("no mem for cb0");
+ pr_err("no mem for cb0\n");
ret = -ENOMEM;
goto out;
}
@@ -1127,7 +1139,7 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
cb4 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb4) {
- ehea_error("no mem for cb4");
+ pr_err("no mem for cb4\n");
ret = -ENOMEM;
goto out;
}
@@ -1178,16 +1190,16 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
break;
}
} else {
- ehea_error("Failed sensing port speed");
+ pr_err("Failed sensing port speed\n");
ret = -EIO;
}
} else {
if (hret == H_AUTHORITY) {
- ehea_info("Hypervisor denied setting port speed");
+ pr_info("Hypervisor denied setting port speed\n");
ret = -EPERM;
} else {
ret = -EIO;
- ehea_error("Failed setting port speed");
+ pr_err("Failed setting port speed\n");
}
}
if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP))
@@ -1204,80 +1216,78 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
u8 ec;
u8 portnum;
struct ehea_port *port;
+ struct net_device *dev;
ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
port = ehea_get_port(adapter, portnum);
+ dev = port->netdev;
switch (ec) {
case EHEA_EC_PORTSTATE_CHG: /* port state change */
if (!port) {
- ehea_error("unknown portnum %x", portnum);
+ netdev_err(dev, "unknown portnum %x\n", portnum);
break;
}
if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
- if (!netif_carrier_ok(port->netdev)) {
+ if (!netif_carrier_ok(dev)) {
ret = ehea_sense_port_attr(port);
if (ret) {
- ehea_error("failed resensing port "
- "attributes");
+ netdev_err(dev, "failed resensing port attributes\n");
break;
}
- if (netif_msg_link(port))
- ehea_info("%s: Logical port up: %dMbps "
- "%s Duplex",
- port->netdev->name,
- port->port_speed,
- port->full_duplex ==
- 1 ? "Full" : "Half");
+ netif_info(port, link, dev,
+ "Logical port up: %dMbps %s Duplex\n",
+ port->port_speed,
+ port->full_duplex == 1 ?
+ "Full" : "Half");
- netif_carrier_on(port->netdev);
- netif_wake_queue(port->netdev);
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
}
} else
- if (netif_carrier_ok(port->netdev)) {
- if (netif_msg_link(port))
- ehea_info("%s: Logical port down",
- port->netdev->name);
- netif_carrier_off(port->netdev);
- netif_stop_queue(port->netdev);
+ if (netif_carrier_ok(dev)) {
+ netif_info(port, link, dev,
+ "Logical port down\n");
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
}
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);
+ netif_info(port, link, dev,
+ "Physical port up\n");
if (prop_carrier_state)
- netif_carrier_on(port->netdev);
+ netif_carrier_on(dev);
} else {
port->phy_link = EHEA_PHY_LINK_DOWN;
- if (netif_msg_link(port))
- ehea_info("%s: Physical port down",
- port->netdev->name);
+ netif_info(port, link, dev,
+ "Physical port down\n");
if (prop_carrier_state)
- netif_carrier_off(port->netdev);
+ netif_carrier_off(dev);
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
- ehea_info("External switch port is primary port");
+ netdev_info(dev,
+ "External switch port is primary port\n");
else
- ehea_info("External switch port is backup port");
+ netdev_info(dev,
+ "External switch port is backup port\n");
break;
case EHEA_EC_ADAPTER_MALFUNC:
- ehea_error("Adapter malfunction");
+ netdev_err(dev, "Adapter malfunction\n");
break;
case EHEA_EC_PORT_MALFUNC:
- ehea_info("Port malfunction: Device: %s", port->netdev->name);
- netif_carrier_off(port->netdev);
- netif_stop_queue(port->netdev);
+ netdev_info(dev, "Port malfunction\n");
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
break;
default:
- ehea_error("unknown event code %x, eqe=0x%llX", ec, eqe);
+ netdev_err(dev, "unknown event code %x, eqe=0x%llX\n", ec, eqe);
break;
}
}
@@ -1289,13 +1299,13 @@ static void ehea_neq_tasklet(unsigned long data)
u64 event_mask;
eqe = ehea_poll_eq(adapter->neq);
- ehea_debug("eqe=%p", eqe);
+ pr_debug("eqe=%p\n", eqe);
while (eqe) {
- ehea_debug("*eqe=%lx", eqe->entry);
+ pr_debug("*eqe=%lx\n", (unsigned long) eqe->entry);
ehea_parse_eqe(adapter, eqe->entry);
eqe = ehea_poll_eq(adapter->neq);
- ehea_debug("next eqe=%p", eqe);
+ pr_debug("next eqe=%p\n", eqe);
}
event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
@@ -1319,9 +1329,7 @@ static int ehea_fill_port_res(struct ehea_port_res *pr)
int ret;
struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
- ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
- - init_attr->act_nr_rwqes_rq2
- - init_attr->act_nr_rwqes_rq3 - 1);
+ ehea_init_fill_rq1(pr, pr->rq1_skba.len);
ret = ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
@@ -1344,14 +1352,14 @@ static int ehea_reg_interrupts(struct net_device *dev)
ehea_qp_aff_irq_handler,
IRQF_DISABLED, port->int_aff_name, port);
if (ret) {
- ehea_error("failed registering irq for qp_aff_irq_handler:"
- "ist=%X", port->qp_eq->attr.ist1);
+ netdev_err(dev, "failed registering irq for qp_aff_irq_handler:ist=%X\n",
+ port->qp_eq->attr.ist1);
goto out_free_qpeq;
}
- if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
- "registered", port->qp_eq->attr.ist1);
+ netif_info(port, ifup, dev,
+ "irq_handle 0x%X for function qp_aff_irq_handler registered\n",
+ port->qp_eq->attr.ist1);
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
@@ -1363,14 +1371,13 @@ static int ehea_reg_interrupts(struct net_device *dev)
IRQF_DISABLED, pr->int_send_name,
pr);
if (ret) {
- ehea_error("failed registering irq for ehea_queue "
- "port_res_nr:%d, ist=%X", i,
- pr->eq->attr.ist1);
+ netdev_err(dev, "failed registering irq for ehea_queue port_res_nr:%d, ist=%X\n",
+ i, pr->eq->attr.ist1);
goto out_free_req;
}
- if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for function ehea_queue_int "
- "%d registered", pr->eq->attr.ist1, i);
+ netif_info(port, ifup, dev,
+ "irq_handle 0x%X for function ehea_queue_int %d registered\n",
+ pr->eq->attr.ist1, i);
}
out:
return ret;
@@ -1401,16 +1408,16 @@ static void ehea_free_interrupts(struct net_device *dev)
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
pr = &port->port_res[i];
ibmebus_free_irq(pr->eq->attr.ist1, pr);
- if (netif_msg_intr(port))
- ehea_info("free send irq for res %d with handle 0x%X",
- i, pr->eq->attr.ist1);
+ netif_info(port, intr, dev,
+ "free send irq for res %d with handle 0x%X\n",
+ i, pr->eq->attr.ist1);
}
/* associated events */
ibmebus_free_irq(port->qp_eq->attr.ist1, port);
- if (netif_msg_intr(port))
- ehea_info("associated event interrupt for handle 0x%X freed",
- port->qp_eq->attr.ist1);
+ netif_info(port, intr, dev,
+ "associated event interrupt for handle 0x%X freed\n",
+ port->qp_eq->attr.ist1);
}
static int ehea_configure_port(struct ehea_port *port)
@@ -1479,7 +1486,7 @@ int ehea_gen_smrs(struct ehea_port_res *pr)
out_free:
ehea_rem_mr(&pr->send_mr);
out:
- ehea_error("Generating SMRS failed\n");
+ pr_err("Generating SMRS failed\n");
return -EIO;
}
@@ -1496,12 +1503,10 @@ static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
{
int arr_size = sizeof(void *) * max_q_entries;
- q_skba->arr = vmalloc(arr_size);
+ q_skba->arr = vzalloc(arr_size);
if (!q_skba->arr)
return -ENOMEM;
- memset(q_skba->arr, 0, arr_size);
-
q_skba->len = max_q_entries;
q_skba->index = 0;
q_skba->os_skbs = 0;
@@ -1536,7 +1541,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
if (!pr->eq) {
- ehea_error("create_eq failed (eq)");
+ pr_err("create_eq failed (eq)\n");
goto out_free;
}
@@ -1544,7 +1549,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->eq->fw_handle,
port->logical_port_id);
if (!pr->recv_cq) {
- ehea_error("create_cq failed (cq_recv)");
+ pr_err("create_cq failed (cq_recv)\n");
goto out_free;
}
@@ -1552,19 +1557,19 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->eq->fw_handle,
port->logical_port_id);
if (!pr->send_cq) {
- ehea_error("create_cq failed (cq_send)");
+ pr_err("create_cq failed (cq_send)\n");
goto out_free;
}
if (netif_msg_ifup(port))
- ehea_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d",
- pr->send_cq->attr.act_nr_of_cqes,
- pr->recv_cq->attr.act_nr_of_cqes);
+ pr_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d\n",
+ pr->send_cq->attr.act_nr_of_cqes,
+ pr->recv_cq->attr.act_nr_of_cqes);
init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
if (!init_attr) {
ret = -ENOMEM;
- ehea_error("no mem for ehea_qp_init_attr");
+ pr_err("no mem for ehea_qp_init_attr\n");
goto out_free;
}
@@ -1589,18 +1594,18 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
if (!pr->qp) {
- ehea_error("create_qp failed");
+ pr_err("create_qp failed\n");
ret = -EIO;
goto out_free;
}
if (netif_msg_ifup(port))
- ehea_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n "
- "nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d", init_attr->qp_nr,
- init_attr->act_nr_send_wqes,
- init_attr->act_nr_rwqes_rq1,
- init_attr->act_nr_rwqes_rq2,
- init_attr->act_nr_rwqes_rq3);
+ pr_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d\n",
+ init_attr->qp_nr,
+ init_attr->act_nr_send_wqes,
+ init_attr->act_nr_rwqes_rq1,
+ init_attr->act_nr_rwqes_rq2,
+ init_attr->act_nr_rwqes_rq3);
pr->sq_skba_size = init_attr->act_nr_send_wqes + 1;
@@ -1751,7 +1756,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
swqe->descriptors++;
}
} else
- ehea_error("cannot handle fragmented headers");
+ pr_err("cannot handle fragmented headers\n");
}
static void write_swqe2_nonTSO(struct sk_buff *skb,
@@ -1847,8 +1852,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("%sregistering bc address failed (tagged)",
- hcallid == H_REG_BCMC ? "" : "de");
+ pr_err("%sregistering bc address failed (tagged)\n",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
goto out_herr;
}
@@ -1859,8 +1864,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("%sregistering bc address failed (vlan)",
- hcallid == H_REG_BCMC ? "" : "de");
+ pr_err("%sregistering bc address failed (vlan)\n",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
}
out_herr:
@@ -1882,7 +1887,7 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
cb0 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb0) {
- ehea_error("no mem for cb0");
+ pr_err("no mem for cb0\n");
ret = -ENOMEM;
goto out;
}
@@ -1930,11 +1935,11 @@ out:
static void ehea_promiscuous_error(u64 hret, int enable)
{
if (hret == H_AUTHORITY)
- ehea_info("Hypervisor denied %sabling promiscuous mode",
- enable == 1 ? "en" : "dis");
+ pr_info("Hypervisor denied %sabling promiscuous mode\n",
+ enable == 1 ? "en" : "dis");
else
- ehea_error("failed %sabling promiscuous mode",
- enable == 1 ? "en" : "dis");
+ pr_err("failed %sabling promiscuous mode\n",
+ enable == 1 ? "en" : "dis");
}
static void ehea_promiscuous(struct net_device *dev, int enable)
@@ -1948,7 +1953,7 @@ static void ehea_promiscuous(struct net_device *dev, int enable)
cb7 = (void *)get_zeroed_page(GFP_ATOMIC);
if (!cb7) {
- ehea_error("no mem for cb7");
+ pr_err("no mem for cb7\n");
goto out;
}
@@ -2008,7 +2013,7 @@ static int ehea_drop_multicast_list(struct net_device *dev)
hret = ehea_multicast_reg_helper(port, mc_entry->macaddr,
H_DEREG_BCMC);
if (hret) {
- ehea_error("failed deregistering mcast MAC");
+ pr_err("failed deregistering mcast MAC\n");
ret = -EIO;
}
@@ -2031,7 +2036,8 @@ static void ehea_allmulti(struct net_device *dev, int enable)
if (!hret)
port->allmulti = 1;
else
- ehea_error("failed enabling IFF_ALLMULTI");
+ netdev_err(dev,
+ "failed enabling IFF_ALLMULTI\n");
}
} else
if (!enable) {
@@ -2040,7 +2046,8 @@ static void ehea_allmulti(struct net_device *dev, int enable)
if (!hret)
port->allmulti = 0;
else
- ehea_error("failed disabling IFF_ALLMULTI");
+ netdev_err(dev,
+ "failed disabling IFF_ALLMULTI\n");
}
}
@@ -2051,7 +2058,7 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC);
if (!ehea_mcl_entry) {
- ehea_error("no mem for mcl_entry");
+ pr_err("no mem for mcl_entry\n");
return;
}
@@ -2064,7 +2071,7 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
if (!hret)
list_add(&ehea_mcl_entry->list, &port->mc_list->list);
else {
- ehea_error("failed registering mcast MAC");
+ pr_err("failed registering mcast MAC\n");
kfree(ehea_mcl_entry);
}
}
@@ -2097,9 +2104,8 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
if (netdev_mc_count(dev) > port->adapter->max_mc_mac) {
- ehea_info("Mcast registration limit reached (0x%llx). "
- "Use ALLMULTI!",
- port->adapter->max_mc_mac);
+ pr_info("Mcast registration limit reached (0x%llx). Use ALLMULTI!\n",
+ port->adapter->max_mc_mac);
goto out;
}
@@ -2305,10 +2311,10 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
pr->swqe_id_counter += 1;
- if (netif_msg_tx_queued(port)) {
- ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
+ netif_info(port, tx_queued, dev,
+ "post swqe on QP %d\n", pr->qp->init_attr.qp_nr);
+ if (netif_msg_tx_queued(port))
ehea_dump(swqe, 512, "swqe");
- }
if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
netif_stop_queue(dev);
@@ -2344,14 +2350,14 @@ static void ehea_vlan_rx_register(struct net_device *dev,
cb1 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb1) {
- ehea_error("no mem for cb1");
+ pr_err("no mem for cb1\n");
goto out;
}
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS)
- ehea_error("modify_ehea_port failed");
+ pr_err("modify_ehea_port failed\n");
free_page((unsigned long)cb1);
out:
@@ -2368,14 +2374,14 @@ static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
cb1 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb1) {
- ehea_error("no mem for cb1");
+ pr_err("no mem for cb1\n");
goto out;
}
hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_port failed");
+ pr_err("query_ehea_port failed\n");
goto out;
}
@@ -2385,7 +2391,7 @@ static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS)
- ehea_error("modify_ehea_port failed");
+ pr_err("modify_ehea_port failed\n");
out:
free_page((unsigned long)cb1);
return;
@@ -2403,14 +2409,14 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
cb1 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb1) {
- ehea_error("no mem for cb1");
+ pr_err("no mem for cb1\n");
goto out;
}
hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_port failed");
+ pr_err("query_ehea_port failed\n");
goto out;
}
@@ -2420,7 +2426,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS)
- ehea_error("modify_ehea_port failed");
+ pr_err("modify_ehea_port failed\n");
out:
free_page((unsigned long)cb1);
}
@@ -2442,7 +2448,7 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
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)");
+ pr_err("query_ehea_qp failed (1)\n");
goto out;
}
@@ -2451,14 +2457,14 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
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)");
+ pr_err("modify_ehea_qp failed (1)\n");
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)");
+ pr_err("query_ehea_qp failed (2)\n");
goto out;
}
@@ -2467,14 +2473,14 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
&dummy64, &dummy64, &dummy16, &dummy16);
if (hret != H_SUCCESS) {
- ehea_error("modify_ehea_qp failed (2)");
+ pr_err("modify_ehea_qp failed (2)\n");
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 (3)");
+ pr_err("query_ehea_qp failed (3)\n");
goto out;
}
@@ -2483,14 +2489,14 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
&dummy64, &dummy64, &dummy16, &dummy16);
if (hret != H_SUCCESS) {
- ehea_error("modify_ehea_qp failed (3)");
+ pr_err("modify_ehea_qp failed (3)\n");
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 (4)");
+ pr_err("query_ehea_qp failed (4)\n");
goto out;
}
@@ -2511,7 +2517,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
EHEA_MAX_ENTRIES_EQ, 1);
if (!port->qp_eq) {
ret = -EINVAL;
- ehea_error("ehea_create_eq failed (qp_eq)");
+ pr_err("ehea_create_eq failed (qp_eq)\n");
goto out_kill_eq;
}
@@ -2592,27 +2598,27 @@ static int ehea_up(struct net_device *dev)
ret = ehea_port_res_setup(port, port->num_def_qps,
port->num_add_tx_qps);
if (ret) {
- ehea_error("port_res_failed");
+ netdev_err(dev, "port_res_failed\n");
goto out;
}
/* Set default QP for this port */
ret = ehea_configure_port(port);
if (ret) {
- ehea_error("ehea_configure_port failed. ret:%d", ret);
+ netdev_err(dev, "ehea_configure_port failed. ret:%d\n", ret);
goto out_clean_pr;
}
ret = ehea_reg_interrupts(dev);
if (ret) {
- ehea_error("reg_interrupts failed. ret:%d", ret);
+ netdev_err(dev, "reg_interrupts failed. ret:%d\n", ret);
goto out_clean_pr;
}
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
if (ret) {
- ehea_error("activate_qp failed");
+ netdev_err(dev, "activate_qp failed\n");
goto out_free_irqs;
}
}
@@ -2620,7 +2626,7 @@ static int ehea_up(struct net_device *dev)
for (i = 0; i < port->num_def_qps; i++) {
ret = ehea_fill_port_res(&port->port_res[i]);
if (ret) {
- ehea_error("out_free_irqs");
+ netdev_err(dev, "out_free_irqs\n");
goto out_free_irqs;
}
}
@@ -2643,7 +2649,7 @@ out_clean_pr:
ehea_clean_all_portres(port);
out:
if (ret)
- ehea_info("Failed starting %s. ret=%i", dev->name, ret);
+ netdev_info(dev, "Failed starting. ret=%i\n", ret);
ehea_update_bcmc_registrations();
ehea_update_firmware_handles();
@@ -2674,8 +2680,7 @@ static int ehea_open(struct net_device *dev)
mutex_lock(&port->port_lock);
- if (netif_msg_ifup(port))
- ehea_info("enabling port %s", dev->name);
+ netif_info(port, ifup, dev, "enabling port\n");
ret = ehea_up(dev);
if (!ret) {
@@ -2710,8 +2715,7 @@ static int ehea_down(struct net_device *dev)
ret = ehea_clean_all_portres(port);
if (ret)
- ehea_info("Failed freeing resources for %s. ret=%i",
- dev->name, ret);
+ netdev_info(dev, "Failed freeing resources. ret=%i\n", ret);
ehea_update_firmware_handles();
@@ -2723,8 +2727,7 @@ static int ehea_stop(struct net_device *dev)
int ret;
struct ehea_port *port = netdev_priv(dev);
- if (netif_msg_ifdown(port))
- ehea_info("disabling port %s", dev->name);
+ netif_info(port, ifdown, dev, "disabling port\n");
set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
cancel_work_sync(&port->reset_task);
@@ -2765,7 +2768,7 @@ static void ehea_flush_sq(struct ehea_port *port)
msecs_to_jiffies(100));
if (!ret) {
- ehea_error("WARNING: sq not flushed completely");
+ pr_err("WARNING: sq not flushed completely\n");
break;
}
}
@@ -2801,7 +2804,7 @@ int ehea_stop_qps(struct net_device *dev)
EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
cb0);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_qp failed (1)");
+ pr_err("query_ehea_qp failed (1)\n");
goto out;
}
@@ -2813,7 +2816,7 @@ int ehea_stop_qps(struct net_device *dev)
1), cb0, &dummy64,
&dummy64, &dummy16, &dummy16);
if (hret != H_SUCCESS) {
- ehea_error("modify_ehea_qp failed (1)");
+ pr_err("modify_ehea_qp failed (1)\n");
goto out;
}
@@ -2821,14 +2824,14 @@ int ehea_stop_qps(struct net_device *dev)
EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
cb0);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_qp failed (2)");
+ pr_err("query_ehea_qp failed (2)\n");
goto out;
}
/* deregister shared memory regions */
dret = ehea_rem_smrs(pr);
if (dret) {
- ehea_error("unreg shared memory region failed");
+ pr_err("unreg shared memory region failed\n");
goto out;
}
}
@@ -2897,7 +2900,7 @@ int ehea_restart_qps(struct net_device *dev)
ret = ehea_gen_smrs(pr);
if (ret) {
- ehea_error("creation of shared memory regions failed");
+ netdev_err(dev, "creation of shared memory regions failed\n");
goto out;
}
@@ -2908,7 +2911,7 @@ int ehea_restart_qps(struct net_device *dev)
EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
cb0);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_qp failed (1)");
+ netdev_err(dev, "query_ehea_qp failed (1)\n");
goto out;
}
@@ -2920,7 +2923,7 @@ int ehea_restart_qps(struct net_device *dev)
1), cb0, &dummy64,
&dummy64, &dummy16, &dummy16);
if (hret != H_SUCCESS) {
- ehea_error("modify_ehea_qp failed (1)");
+ netdev_err(dev, "modify_ehea_qp failed (1)\n");
goto out;
}
@@ -2928,7 +2931,7 @@ int ehea_restart_qps(struct net_device *dev)
EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
cb0);
if (hret != H_SUCCESS) {
- ehea_error("query_ehea_qp failed (2)");
+ netdev_err(dev, "query_ehea_qp failed (2)\n");
goto out;
}
@@ -2965,8 +2968,7 @@ static void ehea_reset_port(struct work_struct *work)
ehea_set_multicast_list(dev);
- if (netif_msg_timer(port))
- ehea_info("Device %s resetted successfully", dev->name);
+ netif_info(port, timer, dev, "reset successful\n");
port_napi_enable(port);
@@ -2976,12 +2978,12 @@ out:
mutex_unlock(&dlpar_mem_lock);
}
-static void ehea_rereg_mrs(struct work_struct *work)
+static void ehea_rereg_mrs(void)
{
int ret, i;
struct ehea_adapter *adapter;
- ehea_info("LPAR memory changed - re-initializing driver");
+ pr_info("LPAR memory changed - re-initializing driver\n");
list_for_each_entry(adapter, &adapter_list, list)
if (adapter->active_ports) {
@@ -3013,8 +3015,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
/* Unregister old memory region */
ret = ehea_rem_mr(&adapter->mr);
if (ret) {
- ehea_error("unregister MR failed - driver"
- " inoperable!");
+ pr_err("unregister MR failed - driver inoperable!\n");
goto out;
}
}
@@ -3026,8 +3027,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
/* Register new memory region */
ret = ehea_reg_kernel_mr(adapter, &adapter->mr);
if (ret) {
- ehea_error("register MR failed - driver"
- " inoperable!");
+ pr_err("register MR failed - driver inoperable!\n");
goto out;
}
@@ -3050,7 +3050,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
}
}
}
- ehea_info("re-initializing driver complete");
+ pr_info("re-initializing driver complete\n");
out:
return;
}
@@ -3103,7 +3103,7 @@ int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
/* (Try to) enable *jumbo frames */
cb4 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb4) {
- ehea_error("no mem for cb4");
+ pr_err("no mem for cb4\n");
ret = -ENOMEM;
goto out;
} else {
@@ -3165,13 +3165,13 @@ static struct device *ehea_register_port(struct ehea_port *port,
ret = of_device_register(&port->ofdev);
if (ret) {
- ehea_error("failed to register device. ret=%d", ret);
+ pr_err("failed to register device. ret=%d\n", ret);
goto out;
}
ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
if (ret) {
- ehea_error("failed to register attributes, ret=%d", ret);
+ pr_err("failed to register attributes, ret=%d\n", ret);
goto out_unreg_of_dev;
}
@@ -3221,7 +3221,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev = alloc_etherdev(sizeof(struct ehea_port));
if (!dev) {
- ehea_error("no mem for net_device");
+ pr_err("no mem for net_device\n");
ret = -ENOMEM;
goto out_err;
}
@@ -3268,11 +3268,14 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
| NETIF_F_LLTX;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
+ if (use_lro)
+ dev->features |= NETIF_F_LRO;
+
INIT_WORK(&port->reset_task, ehea_reset_port);
ret = register_netdev(dev);
if (ret) {
- ehea_error("register_netdev failed. ret=%d", ret);
+ pr_err("register_netdev failed. ret=%d\n", ret);
goto out_unreg_port;
}
@@ -3280,11 +3283,10 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
ret = ehea_get_jumboframe_status(port, &jumbo);
if (ret)
- ehea_error("failed determining jumbo frame status for %s",
- port->netdev->name);
+ netdev_err(dev, "failed determining jumbo frame status\n");
- ehea_info("%s: Jumbo frames are %sabled", dev->name,
- jumbo == 1 ? "en" : "dis");
+ netdev_info(dev, "Jumbo frames are %sabled\n",
+ jumbo == 1 ? "en" : "dis");
adapter->active_ports++;
@@ -3300,14 +3302,16 @@ out_free_ethdev:
free_netdev(dev);
out_err:
- ehea_error("setting up logical port with id=%d failed, ret=%d",
- logical_port_id, ret);
+ pr_err("setting up logical port with id=%d failed, ret=%d\n",
+ logical_port_id, ret);
return NULL;
}
static void ehea_shutdown_single_port(struct ehea_port *port)
{
struct ehea_adapter *adapter = port->adapter;
+
+ cancel_work_sync(&port->reset_task);
unregister_netdev(port->netdev);
ehea_unregister_port(port);
kfree(port->mc_list);
@@ -3329,13 +3333,13 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
NULL);
if (!dn_log_port_id) {
- ehea_error("bad device node: eth_dn name=%s",
- eth_dn->full_name);
+ pr_err("bad device node: eth_dn name=%s\n",
+ eth_dn->full_name);
continue;
}
if (ehea_add_adapter_mr(adapter)) {
- ehea_error("creating MR failed");
+ pr_err("creating MR failed\n");
of_node_put(eth_dn);
return -EIO;
}
@@ -3344,9 +3348,8 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
*dn_log_port_id,
eth_dn);
if (adapter->port[i])
- ehea_info("%s -> logical port id #%d",
- adapter->port[i]->netdev->name,
- *dn_log_port_id);
+ netdev_info(adapter->port[i]->netdev,
+ "logical port id #%d\n", *dn_log_port_id);
else
ehea_remove_adapter_mr(adapter);
@@ -3391,21 +3394,20 @@ static ssize_t ehea_probe_port(struct device *dev,
port = ehea_get_port(adapter, logical_port_id);
if (port) {
- ehea_info("adding port with logical port id=%d failed. port "
- "already configured as %s.", logical_port_id,
- port->netdev->name);
+ netdev_info(port->netdev, "adding port with logical port id=%d failed: port already configured\n",
+ logical_port_id);
return -EINVAL;
}
eth_dn = ehea_get_eth_dn(adapter, logical_port_id);
if (!eth_dn) {
- ehea_info("no logical port with id %d found", logical_port_id);
+ pr_info("no logical port with id %d found\n", logical_port_id);
return -EINVAL;
}
if (ehea_add_adapter_mr(adapter)) {
- ehea_error("creating MR failed");
+ pr_err("creating MR failed\n");
return -EIO;
}
@@ -3420,8 +3422,8 @@ static ssize_t ehea_probe_port(struct device *dev,
break;
}
- ehea_info("added %s (logical port id=%d)", port->netdev->name,
- logical_port_id);
+ netdev_info(port->netdev, "added: (logical port id=%d)\n",
+ logical_port_id);
} else {
ehea_remove_adapter_mr(adapter);
return -EIO;
@@ -3444,8 +3446,8 @@ static ssize_t ehea_remove_port(struct device *dev,
port = ehea_get_port(adapter, logical_port_id);
if (port) {
- ehea_info("removed %s (logical port id=%d)", port->netdev->name,
- logical_port_id);
+ netdev_info(port->netdev, "removed: (logical port id=%d)\n",
+ logical_port_id);
ehea_shutdown_single_port(port);
@@ -3455,8 +3457,8 @@ static ssize_t ehea_remove_port(struct device *dev,
break;
}
} else {
- ehea_error("removing port with logical port id=%d failed. port "
- "not configured.", logical_port_id);
+ pr_err("removing port with logical port id=%d failed. port not configured.\n",
+ logical_port_id);
return -EINVAL;
}
@@ -3493,7 +3495,7 @@ static int __devinit ehea_probe_adapter(struct platform_device *dev,
int ret;
if (!dev || !dev->dev.of_node) {
- ehea_error("Invalid ibmebus device probed");
+ pr_err("Invalid ibmebus device probed\n");
return -EINVAL;
}
@@ -3597,8 +3599,6 @@ static int __devexit ehea_remove(struct platform_device *dev)
ehea_remove_device_sysfs(dev);
- flush_scheduled_work();
-
ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);
@@ -3641,21 +3641,21 @@ static int ehea_mem_notifier(struct notifier_block *nb,
switch (action) {
case MEM_CANCEL_OFFLINE:
- ehea_info("memory offlining canceled");
+ pr_info("memory offlining canceled");
/* Readd canceled memory block */
case MEM_ONLINE:
- ehea_info("memory is going online");
+ pr_info("memory is going online");
set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
goto out_unlock;
- ehea_rereg_mrs(NULL);
+ ehea_rereg_mrs();
break;
case MEM_GOING_OFFLINE:
- ehea_info("memory is going offline");
+ pr_info("memory is going offline");
set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
goto out_unlock;
- ehea_rereg_mrs(NULL);
+ ehea_rereg_mrs();
break;
default:
break;
@@ -3677,7 +3677,7 @@ static int ehea_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
if (action == SYS_RESTART) {
- ehea_info("Reboot: freeing all eHEA resources");
+ pr_info("Reboot: freeing all eHEA resources\n");
ibmebus_unregister_driver(&ehea_driver);
}
return NOTIFY_DONE;
@@ -3693,22 +3693,22 @@ static int check_module_parm(void)
if ((rq1_entries < EHEA_MIN_ENTRIES_QP) ||
(rq1_entries > EHEA_MAX_ENTRIES_RQ1)) {
- ehea_info("Bad parameter: rq1_entries");
+ pr_info("Bad parameter: rq1_entries\n");
ret = -EINVAL;
}
if ((rq2_entries < EHEA_MIN_ENTRIES_QP) ||
(rq2_entries > EHEA_MAX_ENTRIES_RQ2)) {
- ehea_info("Bad parameter: rq2_entries");
+ pr_info("Bad parameter: rq2_entries\n");
ret = -EINVAL;
}
if ((rq3_entries < EHEA_MIN_ENTRIES_QP) ||
(rq3_entries > EHEA_MAX_ENTRIES_RQ3)) {
- ehea_info("Bad parameter: rq3_entries");
+ pr_info("Bad parameter: rq3_entries\n");
ret = -EINVAL;
}
if ((sq_entries < EHEA_MIN_ENTRIES_QP) ||
(sq_entries > EHEA_MAX_ENTRIES_SQ)) {
- ehea_info("Bad parameter: sq_entries");
+ pr_info("Bad parameter: sq_entries\n");
ret = -EINVAL;
}
@@ -3728,11 +3728,8 @@ int __init ehea_module_init(void)
{
int ret;
- printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
- DRV_VERSION);
-
+ pr_info("IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION);
- INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
memset(&ehea_fw_handles, 0, sizeof(ehea_fw_handles));
memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
@@ -3749,27 +3746,27 @@ int __init ehea_module_init(void)
ret = register_reboot_notifier(&ehea_reboot_nb);
if (ret)
- ehea_info("failed registering reboot notifier");
+ pr_info("failed registering reboot notifier\n");
ret = register_memory_notifier(&ehea_mem_nb);
if (ret)
- ehea_info("failed registering memory remove notifier");
+ pr_info("failed registering memory remove notifier\n");
ret = crash_shutdown_register(ehea_crash_handler);
if (ret)
- ehea_info("failed registering crash handler");
+ pr_info("failed registering crash handler\n");
ret = ibmebus_register_driver(&ehea_driver);
if (ret) {
- ehea_error("failed registering eHEA device driver on ebus");
+ pr_err("failed registering eHEA device driver on ebus\n");
goto out2;
}
ret = driver_create_file(&ehea_driver.driver,
&driver_attr_capabilities);
if (ret) {
- ehea_error("failed to register capabilities attribute, ret=%d",
- ret);
+ pr_err("failed to register capabilities attribute, ret=%d\n",
+ ret);
goto out3;
}
@@ -3789,13 +3786,12 @@ static void __exit ehea_module_exit(void)
{
int ret;
- flush_scheduled_work();
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
unregister_reboot_notifier(&ehea_reboot_nb);
ret = crash_shutdown_unregister(ehea_crash_handler);
if (ret)
- ehea_info("failed unregistering crash handler");
+ pr_info("failed unregistering crash handler\n");
unregister_memory_notifier(&ehea_mem_nb);
kfree(ehea_fw_handles.arr);
kfree(ehea_bcmc_regs.arr);
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 8fe9dcaa7538..0506967b9044 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "ehea_phyp.h"
@@ -67,12 +69,11 @@ static long ehea_plpar_hcall_norets(unsigned long opcode,
}
if (ret < H_SUCCESS)
- ehea_error("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);
+ pr_err("opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx\n",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7);
return ret;
}
@@ -114,19 +115,18 @@ static long ehea_plpar_hcall9(unsigned long opcode,
&& (((cb_cat == H_PORT_CB4) && ((arg3 == H_PORT_CB4_JUMBO)
|| (arg3 == H_PORT_CB4_SPEED))) || ((cb_cat == H_PORT_CB7)
&& (arg3 == H_PORT_CB7_DUCQPN)))))
- ehea_error("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],
- outs[4], outs[5], outs[6], outs[7],
- outs[8]);
+ pr_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\n",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9,
+ outs[0], outs[1], outs[2], outs[3], outs[4],
+ outs[5], outs[6], outs[7], outs[8]);
return ret;
}
@@ -515,7 +515,7 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
const u64 log_pageaddr, const u64 count)
{
if ((count > 1) && (log_pageaddr & ~PAGE_MASK)) {
- ehea_error("not on pageboundary");
+ pr_err("not on pageboundary\n");
return H_PARAMETER;
}
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 89128b6373e3..cd44bb8017d9 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/mm.h>
#include <linux/slab.h>
#include "ehea.h"
@@ -45,7 +47,7 @@ static void *hw_qpageit_get_inc(struct hw_queue *queue)
queue->current_q_offset -= queue->pagesize;
retvalue = NULL;
} else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
- ehea_error("not on pageboundary");
+ pr_err("not on pageboundary\n");
retvalue = NULL;
}
return retvalue;
@@ -58,15 +60,15 @@ static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
int i, k;
if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
- ehea_error("pagesize conflict! kernel pagesize=%d, "
- "ehea pagesize=%d", (int)PAGE_SIZE, (int)pagesize);
+ pr_err("pagesize conflict! kernel pagesize=%d, ehea pagesize=%d\n",
+ (int)PAGE_SIZE, (int)pagesize);
return -EINVAL;
}
queue->queue_length = nr_of_pages * pagesize;
queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
if (!queue->queue_pages) {
- ehea_error("no mem for queue_pages");
+ pr_err("no mem for queue_pages\n");
return -ENOMEM;
}
@@ -130,7 +132,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
if (!cq) {
- ehea_error("no mem for cq");
+ pr_err("no mem for cq\n");
goto out_nomem;
}
@@ -147,7 +149,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
&cq->fw_handle, &cq->epas);
if (hret != H_SUCCESS) {
- ehea_error("alloc_resource_cq failed");
+ pr_err("alloc_resource_cq failed\n");
goto out_freemem;
}
@@ -159,7 +161,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
for (counter = 0; counter < cq->attr.nr_pages; counter++) {
vpage = hw_qpageit_get_inc(&cq->hw_queue);
if (!vpage) {
- ehea_error("hw_qpageit_get_inc failed");
+ pr_err("hw_qpageit_get_inc failed\n");
goto out_kill_hwq;
}
@@ -168,9 +170,8 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
0, EHEA_CQ_REGISTER_ORIG,
cq->fw_handle, rpage, 1);
if (hret < H_SUCCESS) {
- ehea_error("register_rpage_cq failed ehea_cq=%p "
- "hret=%llx counter=%i act_pages=%i",
- cq, hret, counter, cq->attr.nr_pages);
+ pr_err("register_rpage_cq failed ehea_cq=%p hret=%llx counter=%i act_pages=%i\n",
+ cq, hret, counter, cq->attr.nr_pages);
goto out_kill_hwq;
}
@@ -178,14 +179,14 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
vpage = hw_qpageit_get_inc(&cq->hw_queue);
if ((hret != H_SUCCESS) || (vpage)) {
- ehea_error("registration of pages not "
- "complete hret=%llx\n", hret);
+ pr_err("registration of pages not complete hret=%llx\n",
+ hret);
goto out_kill_hwq;
}
} else {
if (hret != H_PAGE_REGISTERED) {
- ehea_error("CQ: registration of page failed "
- "hret=%llx\n", hret);
+ pr_err("CQ: registration of page failed hret=%llx\n",
+ hret);
goto out_kill_hwq;
}
}
@@ -241,7 +242,7 @@ int ehea_destroy_cq(struct ehea_cq *cq)
}
if (hret != H_SUCCESS) {
- ehea_error("destroy CQ failed");
+ pr_err("destroy CQ failed\n");
return -EIO;
}
@@ -259,7 +260,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
eq = kzalloc(sizeof(*eq), GFP_KERNEL);
if (!eq) {
- ehea_error("no mem for eq");
+ pr_err("no mem for eq\n");
return NULL;
}
@@ -272,21 +273,21 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
hret = ehea_h_alloc_resource_eq(adapter->handle,
&eq->attr, &eq->fw_handle);
if (hret != H_SUCCESS) {
- ehea_error("alloc_resource_eq failed");
+ pr_err("alloc_resource_eq failed\n");
goto out_freemem;
}
ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages,
EHEA_PAGESIZE, sizeof(struct ehea_eqe));
if (ret) {
- ehea_error("can't allocate eq pages");
+ pr_err("can't allocate eq pages\n");
goto out_freeres;
}
for (i = 0; i < eq->attr.nr_pages; i++) {
vpage = hw_qpageit_get_inc(&eq->hw_queue);
if (!vpage) {
- ehea_error("hw_qpageit_get_inc failed");
+ pr_err("hw_qpageit_get_inc failed\n");
hret = H_RESOURCE;
goto out_kill_hwq;
}
@@ -370,7 +371,7 @@ int ehea_destroy_eq(struct ehea_eq *eq)
}
if (hret != H_SUCCESS) {
- ehea_error("destroy EQ failed");
+ pr_err("destroy EQ failed\n");
return -EIO;
}
@@ -395,7 +396,7 @@ int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
for (cnt = 0; cnt < nr_pages; cnt++) {
vpage = hw_qpageit_get_inc(hw_queue);
if (!vpage) {
- ehea_error("hw_qpageit_get_inc failed");
+ pr_err("hw_qpageit_get_inc failed\n");
goto out_kill_hwq;
}
rpage = virt_to_abs(vpage);
@@ -403,7 +404,7 @@ int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
0, h_call_q_selector,
qp->fw_handle, rpage, 1);
if (hret < H_SUCCESS) {
- ehea_error("register_rpage_qp failed");
+ pr_err("register_rpage_qp failed\n");
goto out_kill_hwq;
}
}
@@ -432,7 +433,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
if (!qp) {
- ehea_error("no mem for qp");
+ pr_err("no mem for qp\n");
return NULL;
}
@@ -441,7 +442,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd,
&qp->fw_handle, &qp->epas);
if (hret != H_SUCCESS) {
- ehea_error("ehea_h_alloc_resource_qp failed");
+ pr_err("ehea_h_alloc_resource_qp failed\n");
goto out_freemem;
}
@@ -455,7 +456,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
init_attr->act_wqe_size_enc_sq, adapter,
0);
if (ret) {
- ehea_error("can't register for sq ret=%x", ret);
+ pr_err("can't register for sq ret=%x\n", ret);
goto out_freeres;
}
@@ -465,7 +466,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
init_attr->act_wqe_size_enc_rq1,
adapter, 1);
if (ret) {
- ehea_error("can't register for rq1 ret=%x", ret);
+ pr_err("can't register for rq1 ret=%x\n", ret);
goto out_kill_hwsq;
}
@@ -476,7 +477,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
init_attr->act_wqe_size_enc_rq2,
adapter, 2);
if (ret) {
- ehea_error("can't register for rq2 ret=%x", ret);
+ pr_err("can't register for rq2 ret=%x\n", ret);
goto out_kill_hwr1q;
}
}
@@ -488,7 +489,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
init_attr->act_wqe_size_enc_rq3,
adapter, 3);
if (ret) {
- ehea_error("can't register for rq3 ret=%x", ret);
+ pr_err("can't register for rq3 ret=%x\n", ret);
goto out_kill_hwr2q;
}
}
@@ -553,7 +554,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
}
if (hret != H_SUCCESS) {
- ehea_error("destroy QP failed");
+ pr_err("destroy QP failed\n");
return -EIO;
}
@@ -842,7 +843,7 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
(hret != H_PAGE_REGISTERED)) {
ehea_h_free_resource(adapter->handle, mr->handle,
FORCE_FREE);
- ehea_error("register_rpage_mr failed");
+ pr_err("register_rpage_mr failed\n");
return hret;
}
}
@@ -896,7 +897,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
pt = (void *)get_zeroed_page(GFP_KERNEL);
if (!pt) {
- ehea_error("no mem");
+ pr_err("no mem\n");
ret = -ENOMEM;
goto out;
}
@@ -906,14 +907,14 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
&mr->handle, &mr->lkey);
if (hret != H_SUCCESS) {
- ehea_error("alloc_resource_mr failed");
+ pr_err("alloc_resource_mr failed\n");
ret = -EIO;
goto out;
}
if (!ehea_bmap) {
ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
- ehea_error("no busmap available");
+ pr_err("no busmap available\n");
ret = -EIO;
goto out;
}
@@ -929,7 +930,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
if (hret != H_SUCCESS) {
ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
- ehea_error("registering mr failed");
+ pr_err("registering mr failed\n");
ret = -EIO;
goto out;
}
@@ -952,7 +953,7 @@ int ehea_rem_mr(struct ehea_mr *mr)
hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
FORCE_FREE);
if (hret != H_SUCCESS) {
- ehea_error("destroy MR failed");
+ pr_err("destroy MR failed\n");
return -EIO;
}
@@ -987,14 +988,14 @@ void print_error_data(u64 *data)
length = EHEA_PAGESIZE;
if (type == EHEA_AER_RESTYPE_QP)
- ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, "
- "port=%llX", resource, data[6], data[12], data[22]);
+ pr_err("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, port=%llX\n",
+ resource, data[6], data[12], data[22]);
else if (type == EHEA_AER_RESTYPE_CQ)
- ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource,
- data[6]);
+ pr_err("CQ (resource=%llX) state: AER=0x%llX\n",
+ resource, data[6]);
else if (type == EHEA_AER_RESTYPE_EQ)
- ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource,
- data[6]);
+ pr_err("EQ (resource=%llX) state: AER=0x%llX\n",
+ resource, data[6]);
ehea_dump(data, length, "error data");
}
@@ -1008,7 +1009,7 @@ u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
rblock = (void *)get_zeroed_page(GFP_KERNEL);
if (!rblock) {
- ehea_error("Cannot allocate rblock memory.");
+ pr_err("Cannot allocate rblock memory\n");
goto out;
}
@@ -1020,9 +1021,9 @@ u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
*aerr = rblock[12];
print_error_data(rblock);
} else if (ret == H_R_STATE) {
- ehea_error("No error data available: %llX.", res_handle);
+ pr_err("No error data available: %llX\n", res_handle);
} else
- ehea_error("Error data could not be fetched: %llX", res_handle);
+ pr_err("Error data could not be fetched: %llX\n", res_handle);
free_page((unsigned long)rblock);
out:
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index c91d364c5527..a937f49d9db7 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -32,7 +32,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "1.4.1.6"
+#define DRV_VERSION "1.4.1.10"
#define DRV_COPYRIGHT "Copyright 2008-2010 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -61,6 +61,8 @@ struct enic_port_profile {
char name[PORT_PROFILE_MAX];
u8 instance_uuid[PORT_UUID_MAX];
u8 host_uuid[PORT_UUID_MAX];
+ u8 vf_mac[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
};
/* Per-instance private data structure */
@@ -78,8 +80,10 @@ struct enic {
spinlock_t devcmd_lock;
u8 mac_addr[ETH_ALEN];
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
+ u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN];
unsigned int flags;
unsigned int mc_count;
+ unsigned int uc_count;
int csum_rx_enabled;
u32 port_mtu;
u32 rx_coalesce_usecs;
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index a466ef91dd43..a0af48c51fb3 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -702,7 +702,7 @@ static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
{
unsigned int head_len = skb_headlen(skb);
unsigned int len_left = skb->len - head_len;
- unsigned int hdr_len = skb_transport_offset(skb);
+ unsigned int hdr_len = skb_checksum_start_offset(skb);
unsigned int csum_offset = hdr_len + skb->csum_offset;
int eop = (len_left == 0);
@@ -1002,7 +1002,7 @@ static int enic_dev_packet_filter(struct enic *enic, int directed,
return err;
}
-static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr)
+static int enic_dev_add_addr(struct enic *enic, u8 *addr)
{
int err;
@@ -1013,7 +1013,7 @@ static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr)
return err;
}
-static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr)
+static int enic_dev_del_addr(struct enic *enic, u8 *addr)
{
int err;
@@ -1024,29 +1024,19 @@ static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr)
return err;
}
-/* netif_tx_lock held, BHs disabled */
-static void enic_set_multicast_list(struct net_device *netdev)
+static void enic_add_multicast_addr_list(struct enic *enic)
{
- struct enic *enic = netdev_priv(netdev);
+ struct net_device *netdev = enic->netdev;
struct netdev_hw_addr *ha;
- int directed = 1;
- int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
- int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
- int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
unsigned int mc_count = netdev_mc_count(netdev);
- int allmulti = (netdev->flags & IFF_ALLMULTI) ||
- mc_count > ENIC_MULTICAST_PERFECT_FILTERS;
- unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0);
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
unsigned int i, j;
- if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
+ if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) {
+ netdev_warn(netdev, "Registering only %d out of %d "
+ "multicast addresses\n",
+ ENIC_MULTICAST_PERFECT_FILTERS, mc_count);
mc_count = ENIC_MULTICAST_PERFECT_FILTERS;
-
- if (enic->flags != flags) {
- enic->flags = flags;
- enic_dev_packet_filter(enic, directed,
- multicast, broadcast, promisc, allmulti);
}
/* Is there an easier way? Trying to minimize to
@@ -1068,7 +1058,7 @@ static void enic_set_multicast_list(struct net_device *netdev)
mc_addr[j]) == 0)
break;
if (j == mc_count)
- enic_dev_del_multicast_addr(enic, enic->mc_addr[i]);
+ enic_dev_del_addr(enic, enic->mc_addr[i]);
}
for (i = 0; i < mc_count; i++) {
@@ -1077,7 +1067,7 @@ static void enic_set_multicast_list(struct net_device *netdev)
enic->mc_addr[j]) == 0)
break;
if (j == enic->mc_count)
- enic_dev_add_multicast_addr(enic, mc_addr[i]);
+ enic_dev_add_addr(enic, mc_addr[i]);
}
/* Save the list to compare against next time
@@ -1089,6 +1079,89 @@ static void enic_set_multicast_list(struct net_device *netdev)
enic->mc_count = mc_count;
}
+static void enic_add_unicast_addr_list(struct enic *enic)
+{
+ struct net_device *netdev = enic->netdev;
+ struct netdev_hw_addr *ha;
+ unsigned int uc_count = netdev_uc_count(netdev);
+ u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN];
+ unsigned int i, j;
+
+ if (uc_count > ENIC_UNICAST_PERFECT_FILTERS) {
+ netdev_warn(netdev, "Registering only %d out of %d "
+ "unicast addresses\n",
+ ENIC_UNICAST_PERFECT_FILTERS, uc_count);
+ uc_count = ENIC_UNICAST_PERFECT_FILTERS;
+ }
+
+ /* Is there an easier way? Trying to minimize to
+ * calls to add/del unicast addrs. We keep the
+ * addrs from the last call in enic->uc_addr and
+ * look for changes to add/del.
+ */
+
+ i = 0;
+ netdev_for_each_uc_addr(ha, netdev) {
+ if (i == uc_count)
+ break;
+ memcpy(uc_addr[i++], ha->addr, ETH_ALEN);
+ }
+
+ for (i = 0; i < enic->uc_count; i++) {
+ for (j = 0; j < uc_count; j++)
+ if (compare_ether_addr(enic->uc_addr[i],
+ uc_addr[j]) == 0)
+ break;
+ if (j == uc_count)
+ enic_dev_del_addr(enic, enic->uc_addr[i]);
+ }
+
+ for (i = 0; i < uc_count; i++) {
+ for (j = 0; j < enic->uc_count; j++)
+ if (compare_ether_addr(uc_addr[i],
+ enic->uc_addr[j]) == 0)
+ break;
+ if (j == enic->uc_count)
+ enic_dev_add_addr(enic, uc_addr[i]);
+ }
+
+ /* Save the list to compare against next time
+ */
+
+ for (i = 0; i < uc_count; i++)
+ memcpy(enic->uc_addr[i], uc_addr[i], ETH_ALEN);
+
+ enic->uc_count = uc_count;
+}
+
+/* netif_tx_lock held, BHs disabled */
+static void enic_set_rx_mode(struct net_device *netdev)
+{
+ struct enic *enic = netdev_priv(netdev);
+ int directed = 1;
+ int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
+ int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
+ int promisc = (netdev->flags & IFF_PROMISC) ||
+ netdev_uc_count(netdev) > ENIC_UNICAST_PERFECT_FILTERS;
+ int allmulti = (netdev->flags & IFF_ALLMULTI) ||
+ netdev_mc_count(netdev) > ENIC_MULTICAST_PERFECT_FILTERS;
+ unsigned int flags = netdev->flags |
+ (allmulti ? IFF_ALLMULTI : 0) |
+ (promisc ? IFF_PROMISC : 0);
+
+ if (enic->flags != flags) {
+ enic->flags = flags;
+ enic_dev_packet_filter(enic, directed,
+ multicast, broadcast, promisc, allmulti);
+ }
+
+ if (!promisc) {
+ enic_add_unicast_addr_list(enic);
+ if (!allmulti)
+ enic_add_multicast_addr_list(enic);
+ }
+}
+
/* rtnl lock is held */
static void enic_vlan_rx_register(struct net_device *netdev,
struct vlan_group *vlan_group)
@@ -1158,11 +1231,31 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error)
return err;
}
+static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+ struct enic *enic = netdev_priv(netdev);
+
+ if (vf != PORT_SELF_VF)
+ return -EOPNOTSUPP;
+
+ /* Ignore the vf argument for now. We can assume the request
+ * is coming on a vf.
+ */
+ if (is_valid_ether_addr(mac)) {
+ memcpy(enic->pp.vf_mac, mac, ETH_ALEN);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
static int enic_set_port_profile(struct enic *enic, u8 *mac)
{
struct vic_provinfo *vp;
u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
+ u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX;
char uuid_str[38];
+ char client_mac_str[18];
+ u8 *client_mac;
int err;
err = enic_vnic_dev_deinit(enic);
@@ -1180,46 +1273,63 @@ static int enic_set_port_profile(struct enic *enic, u8 *mac)
return -EADDRNOTAVAIL;
vp = vic_provinfo_alloc(GFP_KERNEL, oui,
- VIC_PROVINFO_LINUX_TYPE);
+ VIC_PROVINFO_GENERIC_TYPE);
if (!vp)
return -ENOMEM;
vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+ VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
strlen(enic->pp.name) + 1, enic->pp.name);
+ if (!is_zero_ether_addr(enic->pp.mac_addr))
+ client_mac = enic->pp.mac_addr;
+ else
+ client_mac = mac;
+
+ vic_provinfo_add_tlv(vp,
+ VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
+ ETH_ALEN, client_mac);
+
+ sprintf(client_mac_str, "%pM", client_mac);
vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
- ETH_ALEN, mac);
+ VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
+ sizeof(client_mac_str), client_mac_str);
if (enic->pp.set & ENIC_SET_INSTANCE) {
sprintf(uuid_str, "%pUB", enic->pp.instance_uuid);
vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+ VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
sizeof(uuid_str), uuid_str);
}
if (enic->pp.set & ENIC_SET_HOST) {
sprintf(uuid_str, "%pUB", enic->pp.host_uuid);
vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+ VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
sizeof(uuid_str), uuid_str);
}
+ os_type = htons(os_type);
+ vic_provinfo_add_tlv(vp,
+ VIC_GENERIC_PROV_TLV_OS_TYPE,
+ sizeof(os_type), &os_type);
+
err = enic_dev_init_prov(enic, vp);
vic_provinfo_free(vp);
if (err)
return err;
+
+ enic->pp.set |= ENIC_SET_APPLIED;
break;
case PORT_REQUEST_DISASSOCIATE:
+ enic->pp.set &= ~ENIC_SET_APPLIED;
break;
default:
return -EINVAL;
}
- enic->pp.set |= ENIC_SET_APPLIED;
return 0;
}
@@ -1227,29 +1337,31 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
struct nlattr *port[])
{
struct enic *enic = netdev_priv(netdev);
+ struct enic_port_profile new_pp;
+ int err = 0;
- memset(&enic->pp, 0, sizeof(enic->pp));
+ memset(&new_pp, 0, sizeof(new_pp));
if (port[IFLA_PORT_REQUEST]) {
- enic->pp.set |= ENIC_SET_REQUEST;
- enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ new_pp.set |= ENIC_SET_REQUEST;
+ new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
}
if (port[IFLA_PORT_PROFILE]) {
- enic->pp.set |= ENIC_SET_NAME;
- memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+ new_pp.set |= ENIC_SET_NAME;
+ memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]),
PORT_PROFILE_MAX);
}
if (port[IFLA_PORT_INSTANCE_UUID]) {
- enic->pp.set |= ENIC_SET_INSTANCE;
- memcpy(enic->pp.instance_uuid,
+ new_pp.set |= ENIC_SET_INSTANCE;
+ memcpy(new_pp.instance_uuid,
nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
}
if (port[IFLA_PORT_HOST_UUID]) {
- enic->pp.set |= ENIC_SET_HOST;
- memcpy(enic->pp.host_uuid,
+ new_pp.set |= ENIC_SET_HOST;
+ memcpy(new_pp.host_uuid,
nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
}
@@ -1257,21 +1369,39 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
if (vf != PORT_SELF_VF)
return -EOPNOTSUPP;
- if (!(enic->pp.set & ENIC_SET_REQUEST))
+ if (!(new_pp.set & ENIC_SET_REQUEST))
return -EOPNOTSUPP;
- if (enic->pp.request == PORT_REQUEST_ASSOCIATE) {
-
- /* If the interface mac addr hasn't been assigned,
- * assign a random mac addr before setting port-
- * profile.
- */
+ if (new_pp.request == PORT_REQUEST_ASSOCIATE) {
+ /* Special case handling */
+ if (!is_zero_ether_addr(enic->pp.vf_mac))
+ memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN);
if (is_zero_ether_addr(netdev->dev_addr))
random_ether_addr(netdev->dev_addr);
+ } else if (new_pp.request == PORT_REQUEST_DISASSOCIATE) {
+ if (!is_zero_ether_addr(enic->pp.mac_addr))
+ enic_dev_del_addr(enic, enic->pp.mac_addr);
}
- return enic_set_port_profile(enic, netdev->dev_addr);
+ memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile));
+
+ err = enic_set_port_profile(enic, netdev->dev_addr);
+ if (err)
+ goto set_port_profile_cleanup;
+
+ if (!is_zero_ether_addr(enic->pp.mac_addr))
+ enic_dev_add_addr(enic, enic->pp.mac_addr);
+
+set_port_profile_cleanup:
+ memset(enic->pp.vf_mac, 0, ETH_ALEN);
+
+ if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) {
+ memset(netdev->dev_addr, 0, ETH_ALEN);
+ memset(enic->pp.mac_addr, 0, ETH_ALEN);
+ }
+
+ return err;
}
static int enic_get_vf_port(struct net_device *netdev, int vf,
@@ -1851,8 +1981,11 @@ static int enic_open(struct net_device *netdev)
for (i = 0; i < enic->rq_count; i++)
vnic_rq_enable(&enic->rq[i]);
- enic_dev_add_station_addr(enic);
- enic_set_multicast_list(netdev);
+ if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
+ enic_dev_add_addr(enic, enic->pp.mac_addr);
+ else
+ enic_dev_add_station_addr(enic);
+ enic_set_rx_mode(netdev);
netif_wake_queue(netdev);
@@ -1899,7 +2032,10 @@ static int enic_stop(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_disable(netdev);
- enic_dev_del_station_addr(enic);
+ if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
+ enic_dev_del_addr(enic, enic->pp.mac_addr);
+ else
+ enic_dev_del_station_addr(enic);
for (i = 0; i < enic->wq_count; i++) {
err = vnic_wq_disable(&enic->wq[i]);
@@ -1962,7 +2098,8 @@ static void enic_poll_controller(struct net_device *netdev)
case VNIC_DEV_INTR_MODE_MSIX:
for (i = 0; i < enic->rq_count; i++) {
intr = enic_msix_rq_intr(enic, i);
- enic_isr_msix_rq(enic->msix_entry[intr].vector, enic);
+ enic_isr_msix_rq(enic->msix_entry[intr].vector,
+ &enic->napi[i]);
}
intr = enic_msix_wq_intr(enic, i);
enic_isr_msix_wq(enic->msix_entry[intr].vector, enic);
@@ -2042,7 +2179,7 @@ static int enic_dev_hang_reset(struct enic *enic)
static int enic_set_rsskey(struct enic *enic)
{
- u64 rss_key_buf_pa;
+ dma_addr_t rss_key_buf_pa;
union vnic_rss_key *rss_key_buf_va = NULL;
union vnic_rss_key rss_key = {
.key[0].b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101},
@@ -2073,7 +2210,7 @@ static int enic_set_rsskey(struct enic *enic)
static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
{
- u64 rss_cpu_buf_pa;
+ dma_addr_t rss_cpu_buf_pa;
union vnic_rss_cpu *rss_cpu_buf_va = NULL;
unsigned int i;
int err;
@@ -2328,7 +2465,8 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {
.ndo_start_xmit = enic_hard_start_xmit,
.ndo_get_stats = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = enic_set_multicast_list,
+ .ndo_set_rx_mode = enic_set_rx_mode,
+ .ndo_set_multicast_list = enic_set_rx_mode,
.ndo_set_mac_address = enic_set_mac_address_dynamic,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_register = enic_vlan_rx_register,
@@ -2337,6 +2475,9 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {
.ndo_tx_timeout = enic_tx_timeout,
.ndo_set_vf_port = enic_set_vf_port,
.ndo_get_vf_port = enic_get_vf_port,
+#ifdef IFLA_VF_MAX
+ .ndo_set_vf_mac = enic_set_vf_mac,
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = enic_poll_controller,
#endif
@@ -2349,7 +2490,8 @@ static const struct net_device_ops enic_netdev_ops = {
.ndo_get_stats = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = enic_set_mac_address,
- .ndo_set_multicast_list = enic_set_multicast_list,
+ .ndo_set_rx_mode = enic_set_rx_mode,
+ .ndo_set_multicast_list = enic_set_rx_mode,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_register = enic_vlan_rx_register,
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
@@ -2693,7 +2835,7 @@ static void __devexit enic_remove(struct pci_dev *pdev)
if (netdev) {
struct enic *enic = netdev_priv(netdev);
- flush_scheduled_work();
+ cancel_work_sync(&enic->reset);
unregister_netdev(netdev);
enic_dev_deinit(enic);
vnic_dev_close(enic->vdev);
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 9a103d9ef9e2..25be2734c3fe 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -34,6 +34,7 @@
#define ENIC_MAX_MTU 9000
#define ENIC_MULTICAST_PERFECT_FILTERS 32
+#define ENIC_UNICAST_PERFECT_FILTERS 32
#define ENIC_NON_TSO_MAX_DESC 16
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
index 7e46e5e8600f..f700f5d9e81d 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/enic/vnic_vic.h
@@ -24,14 +24,29 @@
/* Note: String field lengths include null char */
#define VIC_PROVINFO_CISCO_OUI { 0x00, 0x00, 0x0c }
-#define VIC_PROVINFO_LINUX_TYPE 0x2
-
-enum vic_linux_prov_tlv_type {
- VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR = 0,
- VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR = 1, /* u8[6] */
- VIC_LINUX_PROV_TLV_CLIENT_NAME_STR = 2,
- VIC_LINUX_PROV_TLV_HOST_UUID_STR = 8,
- VIC_LINUX_PROV_TLV_CLIENT_UUID_STR = 9,
+#define VIC_PROVINFO_GENERIC_TYPE 0x4
+
+enum vic_generic_prov_tlv_type {
+ VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR = 0,
+ VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR = 1,
+ VIC_GENERIC_PROV_TLV_CLIENT_NAME_STR = 2,
+ VIC_GENERIC_PROV_TLV_CLUSTER_PORT_NAME_STR = 3,
+ VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR = 4,
+ VIC_GENERIC_PROV_TLV_CLUSTER_UUID_STR = 5,
+ VIC_GENERIC_PROV_TLV_CLUSTER_NAME_STR = 7,
+ VIC_GENERIC_PROV_TLV_HOST_UUID_STR = 8,
+ VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR = 9,
+ VIC_GENERIC_PROV_TLV_INCARNATION_NUMBER = 10,
+ VIC_GENERIC_PROV_TLV_OS_TYPE = 11,
+ VIC_GENERIC_PROV_TLV_OS_VENDOR = 12,
+ VIC_GENERIC_PROV_TLV_CLIENT_TYPE = 15,
+};
+
+enum vic_generic_prov_os_type {
+ VIC_GENERIC_PROV_OS_TYPE_UNKNOWN = 0,
+ VIC_GENERIC_PROV_OS_TYPE_ESX = 1,
+ VIC_GENERIC_PROV_OS_TYPE_LINUX = 2,
+ VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3,
};
struct vic_provinfo {
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index aa56963ad558..c353bf3113cc 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -935,7 +935,7 @@ static void epic_init_ring(struct net_device *dev)
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2);
ep->rx_skbuff[i] = skb;
if (skb == NULL)
break;
@@ -1233,7 +1233,7 @@ static int epic_rx(struct net_device *dev, int budget)
entry = ep->dirty_rx % RX_RING_SIZE;
if (ep->rx_skbuff[entry] == NULL) {
struct sk_buff *skb;
- skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);
+ skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2);
if (skb == NULL)
break;
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index c5a2fe099a8d..b79d7e1555d5 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <net/ethoc.h>
static int buffer_size = 0x8000; /* 32 KBytes */
@@ -184,7 +185,6 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
* @netdev: pointer to network device structure
* @napi: NAPI structure
* @msg_enable: device state flags
- * @rx_lock: receive lock
* @lock: device lock
* @phy: attached PHY
* @mdio: MDIO bus for PHY access
@@ -209,7 +209,6 @@ struct ethoc {
struct napi_struct napi;
u32 msg_enable;
- spinlock_t rx_lock;
spinlock_t lock;
struct phy_device *phy;
@@ -413,10 +412,21 @@ static int ethoc_rx(struct net_device *dev, int limit)
unsigned int entry;
struct ethoc_bd bd;
- entry = priv->num_tx + (priv->cur_rx % priv->num_rx);
+ entry = priv->num_tx + priv->cur_rx;
ethoc_read_bd(priv, entry, &bd);
- if (bd.stat & RX_BD_EMPTY)
- break;
+ if (bd.stat & RX_BD_EMPTY) {
+ ethoc_ack_irq(priv, INT_MASK_RX);
+ /* If packet (interrupt) came in between checking
+ * BD_EMTPY and clearing the interrupt source, then we
+ * risk missing the packet as the RX interrupt won't
+ * trigger right away when we reenable it; hence, check
+ * BD_EMTPY here again to make sure there isn't such a
+ * packet waiting for us...
+ */
+ ethoc_read_bd(priv, entry, &bd);
+ if (bd.stat & RX_BD_EMPTY)
+ break;
+ }
if (ethoc_update_rx_stats(priv, &bd) == 0) {
int size = bd.stat >> 16;
@@ -446,13 +456,14 @@ static int ethoc_rx(struct net_device *dev, int limit)
bd.stat &= ~RX_BD_STATS;
bd.stat |= RX_BD_EMPTY;
ethoc_write_bd(priv, entry, &bd);
- priv->cur_rx++;
+ if (++priv->cur_rx == priv->num_rx)
+ priv->cur_rx = 0;
}
return count;
}
-static int ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
+static void ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
{
struct net_device *netdev = dev->netdev;
@@ -482,32 +493,44 @@ static int ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
netdev->stats.collisions += (bd->stat >> 4) & 0xf;
netdev->stats.tx_bytes += bd->stat >> 16;
netdev->stats.tx_packets++;
- return 0;
}
-static void ethoc_tx(struct net_device *dev)
+static int ethoc_tx(struct net_device *dev, int limit)
{
struct ethoc *priv = netdev_priv(dev);
+ int count;
+ struct ethoc_bd bd;
- spin_lock(&priv->lock);
+ for (count = 0; count < limit; ++count) {
+ unsigned int entry;
- while (priv->dty_tx != priv->cur_tx) {
- unsigned int entry = priv->dty_tx % priv->num_tx;
- struct ethoc_bd bd;
+ entry = priv->dty_tx & (priv->num_tx-1);
ethoc_read_bd(priv, entry, &bd);
- if (bd.stat & TX_BD_READY)
- break;
- entry = (++priv->dty_tx) % priv->num_tx;
- (void)ethoc_update_tx_stats(priv, &bd);
+ if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) {
+ ethoc_ack_irq(priv, INT_MASK_TX);
+ /* If interrupt came in between reading in the BD
+ * and clearing the interrupt source, then we risk
+ * missing the event as the TX interrupt won't trigger
+ * right away when we reenable it; hence, check
+ * BD_EMPTY here again to make sure there isn't such an
+ * event pending...
+ */
+ ethoc_read_bd(priv, entry, &bd);
+ if (bd.stat & TX_BD_READY ||
+ (priv->dty_tx == priv->cur_tx))
+ break;
+ }
+
+ ethoc_update_tx_stats(priv, &bd);
+ priv->dty_tx++;
}
if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2))
netif_wake_queue(dev);
- ethoc_ack_irq(priv, INT_MASK_TX);
- spin_unlock(&priv->lock);
+ return count;
}
static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
@@ -515,32 +538,38 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct ethoc *priv = netdev_priv(dev);
u32 pending;
-
- ethoc_disable_irq(priv, INT_MASK_ALL);
+ u32 mask;
+
+ /* Figure out what triggered the interrupt...
+ * The tricky bit here is that the interrupt source bits get
+ * set in INT_SOURCE for an event irregardless of whether that
+ * event is masked or not. Thus, in order to figure out what
+ * triggered the interrupt, we need to remove the sources
+ * for all events that are currently masked. This behaviour
+ * is not particularly well documented but reasonable...
+ */
+ mask = ethoc_read(priv, INT_MASK);
pending = ethoc_read(priv, INT_SOURCE);
+ pending &= mask;
+
if (unlikely(pending == 0)) {
- ethoc_enable_irq(priv, INT_MASK_ALL);
return IRQ_NONE;
}
ethoc_ack_irq(priv, pending);
+ /* We always handle the dropped packet interrupt */
if (pending & INT_MASK_BUSY) {
dev_err(&dev->dev, "packet dropped\n");
dev->stats.rx_dropped++;
}
- if (pending & INT_MASK_RX) {
- if (napi_schedule_prep(&priv->napi))
- __napi_schedule(&priv->napi);
- } else {
- ethoc_enable_irq(priv, INT_MASK_RX);
+ /* Handle receive/transmit event by switching to polling */
+ if (pending & (INT_MASK_TX | INT_MASK_RX)) {
+ ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
+ napi_schedule(&priv->napi);
}
- if (pending & INT_MASK_TX)
- ethoc_tx(dev);
-
- ethoc_enable_irq(priv, INT_MASK_ALL & ~INT_MASK_RX);
return IRQ_HANDLED;
}
@@ -566,26 +595,29 @@ static int ethoc_get_mac_address(struct net_device *dev, void *addr)
static int ethoc_poll(struct napi_struct *napi, int budget)
{
struct ethoc *priv = container_of(napi, struct ethoc, napi);
- int work_done = 0;
+ int rx_work_done = 0;
+ int tx_work_done = 0;
+
+ rx_work_done = ethoc_rx(priv->netdev, budget);
+ tx_work_done = ethoc_tx(priv->netdev, budget);
- work_done = ethoc_rx(priv->netdev, budget);
- if (work_done < budget) {
- ethoc_enable_irq(priv, INT_MASK_RX);
+ if (rx_work_done < budget && tx_work_done < budget) {
napi_complete(napi);
+ ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
}
- return work_done;
+ return rx_work_done;
}
static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
{
- unsigned long timeout = jiffies + ETHOC_MII_TIMEOUT;
struct ethoc *priv = bus->priv;
+ int i;
ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
- while (time_before(jiffies, timeout)) {
+ for (i=0; i < 5; i++) {
u32 status = ethoc_read(priv, MIISTATUS);
if (!(status & MIISTATUS_BUSY)) {
u32 data = ethoc_read(priv, MIIRX_DATA);
@@ -593,8 +625,7 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
ethoc_write(priv, MIICOMMAND, 0);
return data;
}
-
- schedule();
+ usleep_range(100,200);
}
return -EBUSY;
@@ -602,22 +633,21 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
- unsigned long timeout = jiffies + ETHOC_MII_TIMEOUT;
struct ethoc *priv = bus->priv;
+ int i;
ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
ethoc_write(priv, MIITX_DATA, val);
ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
- while (time_before(jiffies, timeout)) {
+ for (i=0; i < 5; i++) {
u32 stat = ethoc_read(priv, MIISTATUS);
if (!(stat & MIISTATUS_BUSY)) {
/* reset MII command register */
ethoc_write(priv, MIICOMMAND, 0);
return 0;
}
-
- schedule();
+ usleep_range(100,200);
}
return -EBUSY;
@@ -971,9 +1001,17 @@ static int __devinit ethoc_probe(struct platform_device *pdev)
/* calculate the number of TX/RX buffers, maximum 128 supported */
num_bd = min_t(unsigned int,
128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ);
- priv->num_tx = max(2, num_bd / 4);
+ if (num_bd < 4) {
+ ret = -ENODEV;
+ goto error;
+ }
+ /* num_tx must be a power of two */
+ priv->num_tx = rounddown_pow_of_two(num_bd >> 1);
priv->num_rx = num_bd - priv->num_tx;
+ dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n",
+ priv->num_tx, priv->num_rx);
+
priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
if (!priv->vma) {
ret = -ENOMEM;
@@ -982,10 +1020,23 @@ static int __devinit ethoc_probe(struct platform_device *pdev)
/* Allow the platform setup code to pass in a MAC address. */
if (pdev->dev.platform_data) {
- struct ethoc_platform_data *pdata =
- (struct ethoc_platform_data *)pdev->dev.platform_data;
+ struct ethoc_platform_data *pdata = pdev->dev.platform_data;
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
priv->phy_id = pdata->phy_id;
+ } else {
+ priv->phy_id = -1;
+
+#ifdef CONFIG_OF
+ {
+ const uint8_t* mac;
+
+ mac = of_get_property(pdev->dev.of_node,
+ "local-mac-address",
+ NULL);
+ if (mac)
+ memcpy(netdev->dev_addr, mac, IFHWADDRLEN);
+ }
+#endif
}
/* Check that the given MAC address is valid. If it isn't, read the
@@ -1046,7 +1097,6 @@ static int __devinit ethoc_probe(struct platform_device *pdev)
/* setup NAPI */
netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
- spin_lock_init(&priv->rx_lock);
spin_lock_init(&priv->lock);
ret = register_netdev(netdev);
@@ -1113,6 +1163,16 @@ static int ethoc_resume(struct platform_device *pdev)
# define ethoc_resume NULL
#endif
+#ifdef CONFIG_OF
+static struct of_device_id ethoc_match[] = {
+ {
+ .compatible = "opencores,ethoc",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ethoc_match);
+#endif
+
static struct platform_driver ethoc_driver = {
.probe = ethoc_probe,
.remove = __devexit_p(ethoc_remove),
@@ -1120,6 +1180,10 @@ static struct platform_driver ethoc_driver = {
.resume = ethoc_resume,
.driver = {
.name = "ethoc",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = ethoc_match,
+#endif
},
};
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index cce32d43175f..2a71373719ae 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -17,6 +17,8 @@
*
* Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
* Copyright (c) 2004-2006 Macq Electronique SA.
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
*/
#include <linux/module.h>
@@ -45,29 +47,41 @@
#include <asm/cacheflush.h>
-#ifndef CONFIG_ARCH_MXC
+#ifndef CONFIG_ARM
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#endif
#include "fec.h"
-#ifdef CONFIG_ARCH_MXC
-#include <mach/hardware.h>
+#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
#define FEC_ALIGNMENT 0xf
#else
#define FEC_ALIGNMENT 0x3
#endif
-/*
- * Define the fixed address of the FEC hardware.
- */
-#if defined(CONFIG_M5272)
+#define DRIVER_NAME "fec"
+
+/* Controller is ENET-MAC */
+#define FEC_QUIRK_ENET_MAC (1 << 0)
+/* Controller needs driver to swap frame */
+#define FEC_QUIRK_SWAP_FRAME (1 << 1)
-static unsigned char fec_mac_default[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static struct platform_device_id fec_devtype[] = {
+ {
+ .name = DRIVER_NAME,
+ .driver_data = 0,
+ }, {
+ .name = "imx28-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
+ }
};
+static unsigned char macaddr[ETH_ALEN];
+module_param_array(macaddr, byte, NULL, 0);
+MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
+
+#if defined(CONFIG_M5272)
/*
* Some hardware gets it MAC address out of local flash memory.
* if this is non-zero then assume it is the address to get MAC from.
@@ -133,7 +147,8 @@ static unsigned char fec_mac_default[] = {
* account when setting it.
*/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
+ defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
#else
#define OPT_FRAME_SIZE 0
@@ -186,7 +201,6 @@ struct fec_enet_private {
int mii_timeout;
uint phy_speed;
phy_interface_t phy_interface;
- int index;
int link;
int full_duplex;
struct completion mdio_done;
@@ -213,10 +227,23 @@ static void fec_stop(struct net_device *dev);
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
+static void *swap_buffer(void *bufaddr, int len)
+{
+ int i;
+ unsigned int *buf = bufaddr;
+
+ for (i = 0; i < (len + 3) / 4; i++, buf++)
+ *buf = cpu_to_be32(*buf);
+
+ return bufaddr;
+}
+
static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
struct bufdesc *bdp;
void *bufaddr;
unsigned short status;
@@ -261,6 +288,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
bufaddr = fep->tx_bounce[index];
}
+ /*
+ * Some design made an incorrect assumption on endian mode of
+ * the system that it's running on. As the result, driver has to
+ * swap every frame going to and coming from the controller.
+ */
+ if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ swap_buffer(bufaddr, skb->len);
+
/* Save skb pointer */
fep->tx_skbuff[fep->skb_cur] = skb;
@@ -429,6 +464,8 @@ static void
fec_enet_rx(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
struct bufdesc *bdp;
unsigned short status;
struct sk_buff *skb;
@@ -492,6 +529,9 @@ fec_enet_rx(struct net_device *dev)
dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
DMA_FROM_DEVICE);
+ if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ swap_buffer(data, pkt_len);
+
/* This does 16 byte alignment, exactly what we need.
* The packet length includes FCS, but we don't want to
* include that when passing upstream as it messes up
@@ -538,37 +578,50 @@ rx_processing_done:
}
/* ------------------------------------------------------------------------- */
-#ifdef CONFIG_M5272
static void __inline__ fec_get_mac(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
unsigned char *iap, tmpaddr[ETH_ALEN];
- if (FEC_FLASHMAC) {
- /*
- * Get MAC address from FLASH.
- * If it is all 1's or 0's, use the default.
- */
- iap = (unsigned char *)FEC_FLASHMAC;
- if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
- (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
- iap = fec_mac_default;
- if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
- (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
- iap = fec_mac_default;
- } else {
- *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW);
- *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
+ /*
+ * try to get mac address in following order:
+ *
+ * 1) module parameter via kernel command line in form
+ * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0
+ */
+ iap = macaddr;
+
+ /*
+ * 2) from flash or fuse (via platform data)
+ */
+ if (!is_valid_ether_addr(iap)) {
+#ifdef CONFIG_M5272
+ if (FEC_FLASHMAC)
+ iap = (unsigned char *)FEC_FLASHMAC;
+#else
+ if (pdata)
+ memcpy(iap, pdata->mac, ETH_ALEN);
+#endif
+ }
+
+ /*
+ * 3) FEC mac registers set by bootloader
+ */
+ if (!is_valid_ether_addr(iap)) {
+ *((unsigned long *) &tmpaddr[0]) =
+ be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW));
+ *((unsigned short *) &tmpaddr[4]) =
+ be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
iap = &tmpaddr[0];
}
memcpy(dev->dev_addr, iap, ETH_ALEN);
- /* Adjust MAC if using default MAC address */
- if (iap == fec_mac_default)
- dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+ /* Adjust MAC if using macaddr */
+ if (iap == macaddr)
+ dev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id;
}
-#endif
/* ------------------------------------------------------------------------- */
@@ -651,8 +704,8 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
fep->mii_timeout = 0;
init_completion(&fep->mdio_done);
- /* start a read op */
- writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+ /* start a write op */
+ writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE |
FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
FEC_MMFR_TA | FEC_MMFR_DATA(value),
fep->hwp + FEC_MII_DATA);
@@ -681,6 +734,7 @@ static int fec_enet_mii_probe(struct net_device *dev)
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
int phy_id;
+ int dev_id = fep->pdev->id;
fep->phy_dev = NULL;
@@ -692,6 +746,8 @@ static int fec_enet_mii_probe(struct net_device *dev)
continue;
if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
continue;
+ if (dev_id--)
+ continue;
strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
break;
}
@@ -729,10 +785,35 @@ static int fec_enet_mii_probe(struct net_device *dev)
static int fec_enet_mii_init(struct platform_device *pdev)
{
+ static struct mii_bus *fec0_mii_bus;
struct net_device *dev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
int err = -ENXIO, i;
+ /*
+ * The dual fec interfaces are not equivalent with enet-mac.
+ * Here are the differences:
+ *
+ * - fec0 supports MII & RMII modes while fec1 only supports RMII
+ * - fec0 acts as the 1588 time master while fec1 is slave
+ * - external phys can only be configured by fec0
+ *
+ * That is to say fec1 can not work independently. It only works
+ * when fec0 is working. The reason behind this design is that the
+ * second interface is added primarily for Switch mode.
+ *
+ * Because of the last point above, both phys are attached on fec0
+ * mdio interface in board design, and need to be configured by
+ * fec0 mii_bus.
+ */
+ if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id) {
+ /* fec1 uses fec0 mii_bus */
+ fep->mii_bus = fec0_mii_bus;
+ return 0;
+ }
+
fep->mii_timeout = 0;
/*
@@ -769,6 +850,10 @@ static int fec_enet_mii_init(struct platform_device *pdev)
if (mdiobus_register(fep->mii_bus))
goto err_out_free_mdio_irq;
+ /* save fec0 mii_bus */
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ fec0_mii_bus = fep->mii_bus;
+
return 0;
err_out_free_mdio_irq:
@@ -1067,9 +1152,8 @@ static const struct net_device_ops fec_netdev_ops = {
/*
* XXX: We need to clean up on failure exits here.
*
- * index is only used in legacy code
*/
-static int fec_enet_init(struct net_device *dev, int index)
+static int fec_enet_init(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct bufdesc *cbd_base;
@@ -1086,26 +1170,11 @@ static int fec_enet_init(struct net_device *dev, int index)
spin_lock_init(&fep->hw_lock);
- fep->index = index;
fep->hwp = (void __iomem *)dev->base_addr;
fep->netdev = dev;
- /* Set the Ethernet address */
-#ifdef CONFIG_M5272
+ /* Get the Ethernet address */
fec_get_mac(dev);
-#else
- {
- unsigned long l;
- l = readl(fep->hwp + FEC_ADDR_LOW);
- dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24);
- dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16);
- dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8);
- dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0);
- l = readl(fep->hwp + FEC_ADDR_HIGH);
- dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24);
- dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16);
- }
-#endif
/* Set receive and transmit descriptor base. */
fep->rx_bd_base = cbd_base;
@@ -1156,12 +1225,25 @@ static void
fec_restart(struct net_device *dev, int duplex)
{
struct fec_enet_private *fep = netdev_priv(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
int i;
+ u32 val, temp_mac[2];
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
+ /*
+ * enet-mac reset will reset mac address registers too,
+ * so need to reconfigure it.
+ */
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
+ writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+ writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+ }
+
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
@@ -1208,20 +1290,45 @@ fec_restart(struct net_device *dev, int duplex)
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
-#ifdef FEC_MIIGSK_ENR
- if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
- /* disable the gasket and wait */
- writel(0, fep->hwp + FEC_MIIGSK_ENR);
- while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
- udelay(1);
+ /*
+ * The phy interface and speed need to get configured
+ * differently on enet-mac.
+ */
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ val = readl(fep->hwp + FEC_R_CNTRL);
- /* configure the gasket: RMII, 50 MHz, no loopback, no echo */
- writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+ /* MII or RMII */
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val |= (1 << 8);
+ else
+ val &= ~(1 << 8);
- /* re-enable the gasket */
- writel(2, fep->hwp + FEC_MIIGSK_ENR);
- }
+ /* 10M or 100M */
+ if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
+ val &= ~(1 << 9);
+ else
+ val |= (1 << 9);
+
+ writel(val, fep->hwp + FEC_R_CNTRL);
+ } else {
+#ifdef FEC_MIIGSK_ENR
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
+ /* disable the gasket and wait */
+ writel(0, fep->hwp + FEC_MIIGSK_ENR);
+ while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
+ udelay(1);
+
+ /*
+ * configure the gasket:
+ * RMII, 50 MHz, no loopback, no echo
+ */
+ writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+
+ /* re-enable the gasket */
+ writel(2, fep->hwp + FEC_MIIGSK_ENR);
+ }
#endif
+ }
/* And last, enable the transmit and receive processing */
writel(2, fep->hwp + FEC_ECNTRL);
@@ -1316,7 +1423,7 @@ fec_probe(struct platform_device *pdev)
}
clk_enable(fep->clk);
- ret = fec_enet_init(ndev, 0);
+ ret = fec_enet_init(ndev);
if (ret)
goto failed_init;
@@ -1380,8 +1487,10 @@ fec_suspend(struct device *dev)
if (ndev) {
fep = netdev_priv(ndev);
- if (netif_running(ndev))
- fec_enet_close(ndev);
+ if (netif_running(ndev)) {
+ fec_stop(ndev);
+ netif_device_detach(ndev);
+ }
clk_disable(fep->clk);
}
return 0;
@@ -1396,8 +1505,10 @@ fec_resume(struct device *dev)
if (ndev) {
fep = netdev_priv(ndev);
clk_enable(fep->clk);
- if (netif_running(ndev))
- fec_enet_open(ndev);
+ if (netif_running(ndev)) {
+ fec_restart(ndev, fep->full_duplex);
+ netif_device_attach(ndev);
+ }
}
return 0;
}
@@ -1414,12 +1525,13 @@ static const struct dev_pm_ops fec_pm_ops = {
static struct platform_driver fec_driver = {
.driver = {
- .name = "fec",
+ .name = DRIVER_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &fec_pm_ops,
#endif
},
+ .id_table = fec_devtype,
.probe = fec_probe,
.remove = __devexit_p(fec_drv_remove),
};
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 2c48b25668d5..ace318df4c8d 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -14,7 +14,8 @@
/****************************************************************************/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
+ defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
/*
* Just figures, Motorola would have to change the offsets for
* registers in the same peripheral device on different models
@@ -78,7 +79,7 @@
/*
* Define the buffer descriptor structure.
*/
-#ifdef CONFIG_ARCH_MXC
+#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
struct bufdesc {
unsigned short cbd_datlen; /* Data length */
unsigned short cbd_sc; /* Control and status info */
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e9f5d030bc26..50c1213f61fe 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -366,9 +366,8 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
while (bcom_buffer_done(priv->tx_dmatsk)) {
struct sk_buff *skb;
struct bcom_fec_bd *bd;
@@ -379,7 +378,7 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
dev_kfree_skb_irq(skb);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
netif_wake_queue(dev);
@@ -395,9 +394,8 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
struct bcom_fec_bd *bd;
u32 status, physaddr;
int length;
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
while (bcom_buffer_done(priv->rx_dmatsk)) {
@@ -429,7 +427,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
/* Process the received skb - Drop the spin lock while
* calling into the network stack */
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
dma_unmap_single(dev->dev.parent, physaddr, rskb->len,
DMA_FROM_DEVICE);
@@ -438,10 +436,10 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
rskb->protocol = eth_type_trans(rskb, dev);
netif_rx(rskb);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
return IRQ_HANDLED;
}
@@ -452,7 +450,6 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct mpc52xx_fec __iomem *fec = priv->fec;
u32 ievent;
- unsigned long flags;
ievent = in_be32(&fec->ievent);
@@ -470,9 +467,9 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock(&priv->lock);
mpc52xx_fec_reset(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->lock);
return IRQ_HANDLED;
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 0fa1776563a3..af09296ef0dd 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -39,6 +39,9 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define FORCEDETH_VERSION "0.64"
#define DRV_NAME "forcedeth"
@@ -60,18 +63,12 @@
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
-#if 0
-#define dprintk printk
-#else
-#define dprintk(x...) do { } while (0)
-#endif
-
#define TX_WORK_PER_LOOP 64
#define RX_WORK_PER_LOOP 64
@@ -186,9 +183,9 @@ enum {
NvRegSlotTime = 0x9c,
#define NVREG_SLOTTIME_LEGBF_ENABLED 0x80000000
#define NVREG_SLOTTIME_10_100_FULL 0x00007f00
-#define NVREG_SLOTTIME_1000_FULL 0x0003ff00
+#define NVREG_SLOTTIME_1000_FULL 0x0003ff00
#define NVREG_SLOTTIME_HALF 0x0000ff00
-#define NVREG_SLOTTIME_DEFAULT 0x00007f00
+#define NVREG_SLOTTIME_DEFAULT 0x00007f00
#define NVREG_SLOTTIME_MASK 0x000000ff
NvRegTxDeferral = 0xA0,
@@ -297,7 +294,7 @@ enum {
#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegMgmtUnitGetVersion = 0x204,
-#define NVREG_MGMTUNITGETVERSION 0x01
+#define NVREG_MGMTUNITGETVERSION 0x01
NvRegMgmtUnitVersion = 0x208,
#define NVREG_MGMTUNITVERSION 0x08
NvRegPowerCap = 0x268,
@@ -368,8 +365,8 @@ struct ring_desc_ex {
};
union ring_type {
- struct ring_desc* orig;
- struct ring_desc_ex* ex;
+ struct ring_desc *orig;
+ struct ring_desc_ex *ex;
};
#define FLAG_MASK_V1 0xffff0000
@@ -444,10 +441,10 @@ union ring_type {
#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF)
/* Miscelaneous hardware related defines: */
-#define NV_PCI_REGSZ_VER1 0x270
-#define NV_PCI_REGSZ_VER2 0x2d4
-#define NV_PCI_REGSZ_VER3 0x604
-#define NV_PCI_REGSZ_MAX 0x604
+#define NV_PCI_REGSZ_VER1 0x270
+#define NV_PCI_REGSZ_VER2 0x2d4
+#define NV_PCI_REGSZ_VER3 0x604
+#define NV_PCI_REGSZ_MAX 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -717,7 +714,7 @@ static const struct register_test nv_registers_test[] = {
{ NvRegMulticastAddrA, 0xffffffff },
{ NvRegTxWatermark, 0x0ff },
{ NvRegWakeUpFlags, 0x07777 },
- { 0,0 }
+ { 0, 0 }
};
struct nv_skb_map {
@@ -911,7 +908,7 @@ static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED;
* Power down phy when interface is down (persists through reboot;
* older Linux and other OSes may not power it up again)
*/
-static int phy_power_down = 0;
+static int phy_power_down;
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
@@ -948,7 +945,7 @@ static bool nv_optimized(struct fe_priv *np)
}
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
- int delay, int delaymax, const char *msg)
+ int delay, int delaymax)
{
u8 __iomem *base = get_hwbase(dev);
@@ -956,11 +953,8 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
do {
udelay(delay);
delaymax -= delay;
- if (delaymax < 0) {
- if (msg)
- printk("%s", msg);
+ if (delaymax < 0)
return 1;
- }
} while ((readl(base + offset) & mask) != target);
return 0;
}
@@ -984,12 +978,10 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
u8 __iomem *base = get_hwbase(dev);
if (!nv_optimized(np)) {
- if (rxtx_flags & NV_SETUP_RX_RING) {
+ if (rxtx_flags & NV_SETUP_RX_RING)
writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
- }
- if (rxtx_flags & NV_SETUP_TX_RING) {
+ if (rxtx_flags & NV_SETUP_TX_RING)
writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
- }
} else {
if (rxtx_flags & NV_SETUP_RX_RING) {
writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
@@ -1015,10 +1007,8 @@ static void free_rings(struct net_device *dev)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.ex, np->ring_addr);
}
- if (np->rx_skb)
- kfree(np->rx_skb);
- if (np->tx_skb)
- kfree(np->tx_skb);
+ kfree(np->rx_skb);
+ kfree(np->tx_skb);
}
static int using_multi_irqs(struct net_device *dev)
@@ -1145,23 +1135,15 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
writel(reg, base + NvRegMIIControl);
if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0,
- NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) {
- dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n",
- dev->name, miireg, addr);
+ NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX)) {
retval = -1;
} else if (value != MII_READ) {
/* it was a write operation - fewer failures are detectable */
- dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n",
- dev->name, value, miireg, addr);
retval = 0;
} else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) {
- dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n",
- dev->name, miireg, addr);
retval = -1;
} else {
retval = readl(base + NvRegMIIData);
- dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n",
- dev->name, miireg, addr, retval);
}
return retval;
@@ -1174,16 +1156,15 @@ static int phy_reset(struct net_device *dev, u32 bmcr_setup)
unsigned int tries = 0;
miicontrol = BMCR_RESET | bmcr_setup;
- if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol))
return -1;
- }
/* wait for 500ms */
msleep(500);
/* must wait till reset is deasserted */
while (miicontrol & BMCR_RESET) {
- msleep(10);
+ usleep_range(10000, 20000);
miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
/* FIXME: 100 tries seem excessive */
if (tries++ > 100)
@@ -1192,106 +1173,239 @@ static int phy_reset(struct net_device *dev, u32 bmcr_setup)
return 0;
}
+static int init_realtek_8211b(struct net_device *dev, struct fe_priv *np)
+{
+ static const struct {
+ int reg;
+ int init;
+ } ri[] = {
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 },
+ { PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2 },
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3 },
+ { PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4 },
+ { PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5 },
+ { PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6 },
+ { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ri); i++) {
+ if (mii_rw(dev, np->phyaddr, ri[i].reg, ri[i].init))
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
+static int init_realtek_8211c(struct net_device *dev, struct fe_priv *np)
+{
+ u32 reg;
+ u8 __iomem *base = get_hwbase(dev);
+ u32 powerstate = readl(base + NvRegPowerState2);
+
+ /* need to perform hw phy reset */
+ powerstate |= NVREG_POWERSTATE2_PHY_RESET;
+ writel(powerstate, base + NvRegPowerState2);
+ msleep(25);
+
+ powerstate &= ~NVREG_POWERSTATE2_PHY_RESET;
+ writel(powerstate, base + NvRegPowerState2);
+ msleep(25);
+
+ reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
+ reg |= PHY_REALTEK_INIT9;
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, reg))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10))
+ return PHY_ERROR;
+ reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, MII_READ);
+ if (!(reg & PHY_REALTEK_INIT11)) {
+ reg |= PHY_REALTEK_INIT11;
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, reg))
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1))
+ return PHY_ERROR;
+
+ return 0;
+}
+
+static int init_realtek_8201(struct net_device *dev, struct fe_priv *np)
+{
+ u32 phy_reserved;
+
+ if (np->driver_data & DEV_NEED_PHY_INIT_FIX) {
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG6, MII_READ);
+ phy_reserved |= PHY_REALTEK_INIT7;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG6, phy_reserved))
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
+static int init_realtek_8201_cross(struct net_device *dev, struct fe_priv *np)
+{
+ u32 phy_reserved;
+
+ if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG2, MII_READ);
+ phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
+ phy_reserved |= PHY_REALTEK_INIT3;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG2, phy_reserved))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1))
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
+static int init_cicada(struct net_device *dev, struct fe_priv *np,
+ u32 phyinterface)
+{
+ u32 phy_reserved;
+
+ if (phyinterface & PHY_RGMII) {
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
+ phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
+ phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
+ if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
+ phy_reserved |= PHY_CICADA_INIT5;
+ if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved))
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
+ phy_reserved |= PHY_CICADA_INIT6;
+ if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved))
+ return PHY_ERROR;
+
+ return 0;
+}
+
+static int init_vitesse(struct net_device *dev, struct fe_priv *np)
+{
+ u32 phy_reserved;
+
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG4, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG3, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+ phy_reserved |= PHY_VITESSE_INIT3;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG4, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+ phy_reserved |= PHY_VITESSE_INIT3;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG3, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG4, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved))
+ return PHY_ERROR;
+ phy_reserved = mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG3, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
+ phy_reserved |= PHY_VITESSE_INIT8;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT9))
+ return PHY_ERROR;
+ if (mii_rw(dev, np->phyaddr,
+ PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10))
+ return PHY_ERROR;
+
+ return 0;
+}
+
static int phy_init(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
u8 __iomem *base = get_hwbase(dev);
- u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
+ u32 phyinterface;
+ u32 mii_status, mii_control, mii_control_1000, reg;
/* phy errata for E3016 phy */
if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
reg &= ~PHY_MARVELL_E3016_INITMASK;
if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) {
- printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev));
+ netdev_info(dev, "%s: phy write to errata reg failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
}
if (np->phy_oui == PHY_OUI_REALTEK) {
if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
np->phy_rev == PHY_REV_REALTEK_8211B) {
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ if (init_realtek_8211b(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ } else if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
+ np->phy_rev == PHY_REV_REALTEK_8211C) {
+ if (init_realtek_8211c(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
- np->phy_rev == PHY_REV_REALTEK_8211C) {
- u32 powerstate = readl(base + NvRegPowerState2);
-
- /* need to perform hw phy reset */
- powerstate |= NVREG_POWERSTATE2_PHY_RESET;
- writel(powerstate, base + NvRegPowerState2);
- msleep(25);
-
- powerstate &= ~NVREG_POWERSTATE2_PHY_RESET;
- writel(powerstate, base + NvRegPowerState2);
- msleep(25);
-
- reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
- reg |= PHY_REALTEK_INIT9;
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, reg)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, MII_READ);
- if (!(reg & PHY_REALTEK_INIT11)) {
- reg |= PHY_REALTEK_INIT11;
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, reg)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ } else if (np->phy_model == PHY_MODEL_REALTEK_8201) {
+ if (init_realtek_8201(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
}
- if (np->phy_model == PHY_MODEL_REALTEK_8201) {
- if (np->driver_data & DEV_NEED_PHY_INIT_FIX) {
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
- phy_reserved |= PHY_REALTEK_INIT7;
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- }
}
/* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
- reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
+ reg |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL |
+ ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) {
- printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev));
+ netdev_info(dev, "%s: phy write to advertise failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
@@ -1302,7 +1416,8 @@ static int phy_init(struct net_device *dev)
mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
if (mii_status & PHY_GIGABIT) {
np->gigabit = PHY_GIGABIT;
- mii_control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ);
+ mii_control_1000 = mii_rw(dev, np->phyaddr,
+ MII_CTRL1000, MII_READ);
mii_control_1000 &= ~ADVERTISE_1000HALF;
if (phyinterface & PHY_RGMII)
mii_control_1000 |= ADVERTISE_1000FULL;
@@ -1310,11 +1425,11 @@ static int phy_init(struct net_device *dev)
mii_control_1000 &= ~ADVERTISE_1000FULL;
if (mii_rw(dev, np->phyaddr, MII_CTRL1000, mii_control_1000)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- }
- else
+ } else
np->gigabit = 0;
mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
@@ -1326,7 +1441,8 @@ static int phy_init(struct net_device *dev)
/* start autoneg since we already performed hw reset above */
mii_control |= BMCR_ANRESTART;
if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
- printk(KERN_INFO "%s: phy init failed\n", pci_name(np->pci_dev));
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
} else {
@@ -1334,164 +1450,41 @@ static int phy_init(struct net_device *dev)
* (certain phys need bmcr to be setup with reset)
*/
if (phy_reset(dev, mii_control)) {
- printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
+ netdev_info(dev, "%s: phy reset failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
}
/* phy vendor specific configuration */
- if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) {
- phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
- phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
- phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
- if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ if ((np->phy_oui == PHY_OUI_CICADA)) {
+ if (init_cicada(dev, np, phyinterface)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
- phy_reserved |= PHY_CICADA_INIT5;
- if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ } else if (np->phy_oui == PHY_OUI_VITESSE) {
+ if (init_vitesse(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- }
- if (np->phy_oui == PHY_OUI_CICADA) {
- phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
- phy_reserved |= PHY_CICADA_INIT6;
- if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (np->phy_oui == PHY_OUI_VITESSE) {
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
- phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
- phy_reserved |= PHY_VITESSE_INIT3;
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
- phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
- phy_reserved |= PHY_VITESSE_INIT3;
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
- phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
- phy_reserved |= PHY_VITESSE_INIT8;
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT9)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (np->phy_oui == PHY_OUI_REALTEK) {
+ } else if (np->phy_oui == PHY_OUI_REALTEK) {
if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
np->phy_rev == PHY_REV_REALTEK_8211B) {
/* reset could have cleared these out, set them back */
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ if (init_realtek_8211b(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ } else if (np->phy_model == PHY_MODEL_REALTEK_8201) {
+ if (init_realtek_8201(dev, np) ||
+ init_realtek_8201_cross(dev, np)) {
+ netdev_info(dev, "%s: phy init failed\n",
+ pci_name(np->pci_dev));
return PHY_ERROR;
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (np->phy_model == PHY_MODEL_REALTEK_8201) {
- if (np->driver_data & DEV_NEED_PHY_INIT_FIX) {
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
- phy_reserved |= PHY_REALTEK_INIT7;
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
- if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
- phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
- phy_reserved |= PHY_REALTEK_INIT3;
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- }
}
}
@@ -1501,12 +1494,10 @@ static int phy_init(struct net_device *dev)
/* restart auto negotiation, power down phy */
mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
- if (phy_power_down) {
+ if (phy_power_down)
mii_control |= BMCR_PDOWN;
- }
- if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
+ if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control))
return PHY_ERROR;
- }
return 0;
}
@@ -1517,7 +1508,6 @@ static void nv_start_rx(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 rx_ctrl = readl(base + NvRegReceiverControl);
- dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
/* Already running? Stop it. */
if ((readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) && !np->mac_in_use) {
rx_ctrl &= ~NVREG_RCVCTL_START;
@@ -1526,12 +1516,10 @@ static void nv_start_rx(struct net_device *dev)
}
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
- rx_ctrl |= NVREG_RCVCTL_START;
- if (np->mac_in_use)
+ rx_ctrl |= NVREG_RCVCTL_START;
+ if (np->mac_in_use)
rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN;
writel(rx_ctrl, base + NvRegReceiverControl);
- dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n",
- dev->name, np->duplex, np->linkspeed);
pci_push(base);
}
@@ -1541,15 +1529,15 @@ static void nv_stop_rx(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 rx_ctrl = readl(base + NvRegReceiverControl);
- dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
if (!np->mac_in_use)
rx_ctrl &= ~NVREG_RCVCTL_START;
else
rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN;
writel(rx_ctrl, base + NvRegReceiverControl);
- reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
- NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
- KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
+ if (reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
+ NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX))
+ netdev_info(dev, "%s: ReceiverStatus remained busy\n",
+ __func__);
udelay(NV_RXSTOP_DELAY2);
if (!np->mac_in_use)
@@ -1562,7 +1550,6 @@ static void nv_start_tx(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 tx_ctrl = readl(base + NvRegTransmitterControl);
- dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
tx_ctrl |= NVREG_XMITCTL_START;
if (np->mac_in_use)
tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN;
@@ -1576,15 +1563,15 @@ static void nv_stop_tx(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 tx_ctrl = readl(base + NvRegTransmitterControl);
- dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
if (!np->mac_in_use)
tx_ctrl &= ~NVREG_XMITCTL_START;
else
tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN;
writel(tx_ctrl, base + NvRegTransmitterControl);
- reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
- NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
- KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
+ if (reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
+ NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX))
+ netdev_info(dev, "%s: TransmitterStatus remained busy\n",
+ __func__);
udelay(NV_TXSTOP_DELAY2);
if (!np->mac_in_use)
@@ -1609,7 +1596,6 @@ static void nv_txrx_reset(struct net_device *dev)
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
@@ -1623,8 +1609,6 @@ static void nv_mac_reset(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 temp1, temp2, temp3;
- dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
-
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
@@ -1745,7 +1729,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
static int nv_alloc_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- struct ring_desc* less_rx;
+ struct ring_desc *less_rx;
less_rx = np->get_rx.orig;
if (less_rx-- == np->first_rx.orig)
@@ -1767,9 +1751,8 @@ static int nv_alloc_rx(struct net_device *dev)
np->put_rx.orig = np->first_rx.orig;
if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
np->put_rx_ctx = np->first_rx_ctx;
- } else {
+ } else
return 1;
- }
}
return 0;
}
@@ -1777,7 +1760,7 @@ static int nv_alloc_rx(struct net_device *dev)
static int nv_alloc_rx_optimized(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- struct ring_desc_ex* less_rx;
+ struct ring_desc_ex *less_rx;
less_rx = np->get_rx.ex;
if (less_rx-- == np->first_rx.ex)
@@ -1800,9 +1783,8 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
np->put_rx.ex = np->first_rx.ex;
if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
np->put_rx_ctx = np->first_rx_ctx;
- } else {
+ } else
return 1;
- }
}
return 0;
}
@@ -2018,24 +2000,24 @@ static void nv_legacybackoff_reseed(struct net_device *dev)
/* Known Good seed sets */
static const u32 main_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = {
- {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
- {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 385, 761, 790, 974},
- {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
- {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 386, 761, 790, 974},
- {266, 265, 276, 585, 397, 208, 345, 355, 365, 376, 385, 396, 771, 700, 984},
- {266, 265, 276, 586, 397, 208, 346, 355, 365, 376, 285, 396, 771, 700, 984},
- {366, 365, 376, 686, 497, 308, 447, 455, 466, 476, 485, 496, 871, 800, 84},
- {466, 465, 476, 786, 597, 408, 547, 555, 566, 576, 585, 597, 971, 900, 184}};
+ {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
+ {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 385, 761, 790, 974},
+ {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
+ {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 386, 761, 790, 974},
+ {266, 265, 276, 585, 397, 208, 345, 355, 365, 376, 385, 396, 771, 700, 984},
+ {266, 265, 276, 586, 397, 208, 346, 355, 365, 376, 285, 396, 771, 700, 984},
+ {366, 365, 376, 686, 497, 308, 447, 455, 466, 476, 485, 496, 871, 800, 84},
+ {466, 465, 476, 786, 597, 408, 547, 555, 566, 576, 585, 597, 971, 900, 184} };
static const u32 gear_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = {
- {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
- {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
- {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 397},
- {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
- {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
- {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
- {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
- {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}};
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 397},
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395} };
static void nv_gear_backoff_reseed(struct net_device *dev)
{
@@ -2083,13 +2065,12 @@ static void nv_gear_backoff_reseed(struct net_device *dev)
temp = NVREG_BKOFFCTRL_DEFAULT | (0 << NVREG_BKOFFCTRL_SELECT);
temp |= combinedSeed & NVREG_BKOFFCTRL_SEED_MASK;
temp |= combinedSeed >> NVREG_BKOFFCTRL_GEAR;
- writel(temp,base + NvRegBackOffControl);
+ writel(temp, base + NvRegBackOffControl);
- /* Setup seeds for all gear LFSRs. */
+ /* Setup seeds for all gear LFSRs. */
get_random_bytes(&seedset, sizeof(seedset));
seedset = seedset % BACKOFF_SEEDSET_ROWS;
- for (i = 1; i <= BACKOFF_SEEDSET_LFSRS; i++)
- {
+ for (i = 1; i <= BACKOFF_SEEDSET_LFSRS; i++) {
temp = NVREG_BKOFFCTRL_DEFAULT | (i << NVREG_BKOFFCTRL_SELECT);
temp |= main_seedset[seedset][i-1] & 0x3ff;
temp |= ((gear_seedset[seedset][i-1] & 0x3ff) << NVREG_BKOFFCTRL_GEAR);
@@ -2113,10 +2094,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 size = skb_headlen(skb);
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
u32 empty_slots;
- struct ring_desc* put_tx;
- struct ring_desc* start_tx;
- struct ring_desc* prev_tx;
- struct nv_skb_map* prev_tx_ctx;
+ struct ring_desc *put_tx;
+ struct ring_desc *start_tx;
+ struct ring_desc *prev_tx;
+ struct nv_skb_map *prev_tx_ctx;
unsigned long flags;
/* add fragments to entries count */
@@ -2204,18 +2185,6 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&np->lock, flags);
- dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
- dev->name, entries, tx_flags_extra);
- {
- int j;
- for (j=0; j<64; j++) {
- if ((j%16) == 0)
- dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)skb->data)[j]);
- }
- dprintk("\n");
- }
-
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
return NETDEV_TX_OK;
}
@@ -2233,11 +2202,11 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
u32 size = skb_headlen(skb);
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
u32 empty_slots;
- struct ring_desc_ex* put_tx;
- struct ring_desc_ex* start_tx;
- struct ring_desc_ex* prev_tx;
- struct nv_skb_map* prev_tx_ctx;
- struct nv_skb_map* start_tx_ctx;
+ struct ring_desc_ex *put_tx;
+ struct ring_desc_ex *start_tx;
+ struct ring_desc_ex *prev_tx;
+ struct nv_skb_map *prev_tx_ctx;
+ struct nv_skb_map *start_tx_ctx;
unsigned long flags;
/* add fragments to entries count */
@@ -2355,18 +2324,6 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
spin_unlock_irqrestore(&np->lock, flags);
- dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
- dev->name, entries, tx_flags_extra);
- {
- int j;
- for (j=0; j<64; j++) {
- if ((j%16) == 0)
- dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)skb->data)[j]);
- }
- dprintk("\n");
- }
-
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
return NETDEV_TX_OK;
}
@@ -2399,15 +2356,12 @@ static int nv_tx_done(struct net_device *dev, int limit)
struct fe_priv *np = netdev_priv(dev);
u32 flags;
int tx_work = 0;
- struct ring_desc* orig_get_tx = np->get_tx.orig;
+ struct ring_desc *orig_get_tx = np->get_tx.orig;
while ((np->get_tx.orig != np->put_tx.orig) &&
!((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID) &&
(tx_work < limit)) {
- dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
- dev->name, flags);
-
nv_unmap_txskb(np, np->get_tx_ctx);
if (np->desc_ver == DESC_VER_1) {
@@ -2464,15 +2418,12 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
struct fe_priv *np = netdev_priv(dev);
u32 flags;
int tx_work = 0;
- struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+ struct ring_desc_ex *orig_get_tx = np->get_tx.ex;
while ((np->get_tx.ex != np->put_tx.ex) &&
!((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX2_VALID) &&
(tx_work < limit)) {
- dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
- dev->name, flags);
-
nv_unmap_txskb(np, np->get_tx_ctx);
if (flags & NV_TX2_LASTPACKET) {
@@ -2491,9 +2442,8 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
np->get_tx_ctx->skb = NULL;
tx_work++;
- if (np->tx_limit) {
+ if (np->tx_limit)
nv_tx_flip_ownership(dev);
- }
}
if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
np->get_tx.ex = np->first_tx.ex;
@@ -2518,57 +2468,56 @@ static void nv_tx_timeout(struct net_device *dev)
u32 status;
union ring_type put_tx;
int saved_tx_limit;
+ int i;
if (np->msi_flags & NV_MSI_X_ENABLED)
status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
else
status = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
- printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, status);
-
- {
- int i;
-
- printk(KERN_INFO "%s: Ring at %lx\n",
- dev->name, (unsigned long)np->ring_addr);
- printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
- for (i=0;i<=np->register_size;i+= 32) {
- printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
- i,
- readl(base + i + 0), readl(base + i + 4),
- readl(base + i + 8), readl(base + i + 12),
- readl(base + i + 16), readl(base + i + 20),
- readl(base + i + 24), readl(base + i + 28));
- }
- printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
- for (i=0;i<np->tx_ring_size;i+= 4) {
- if (!nv_optimized(np)) {
- printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
- i,
- le32_to_cpu(np->tx_ring.orig[i].buf),
- le32_to_cpu(np->tx_ring.orig[i].flaglen),
- le32_to_cpu(np->tx_ring.orig[i+1].buf),
- le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
- le32_to_cpu(np->tx_ring.orig[i+2].buf),
- le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
- le32_to_cpu(np->tx_ring.orig[i+3].buf),
- le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
- } else {
- printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
- i,
- le32_to_cpu(np->tx_ring.ex[i].bufhigh),
- le32_to_cpu(np->tx_ring.ex[i].buflow),
- le32_to_cpu(np->tx_ring.ex[i].flaglen),
- le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
- le32_to_cpu(np->tx_ring.ex[i+1].buflow),
- le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
- le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
- le32_to_cpu(np->tx_ring.ex[i+2].buflow),
- le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
- le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
- le32_to_cpu(np->tx_ring.ex[i+3].buflow),
- le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
- }
+ netdev_info(dev, "Got tx_timeout. irq: %08x\n", status);
+
+ netdev_info(dev, "Ring at %lx\n", (unsigned long)np->ring_addr);
+ netdev_info(dev, "Dumping tx registers\n");
+ for (i = 0; i <= np->register_size; i += 32) {
+ netdev_info(dev,
+ "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ i,
+ readl(base + i + 0), readl(base + i + 4),
+ readl(base + i + 8), readl(base + i + 12),
+ readl(base + i + 16), readl(base + i + 20),
+ readl(base + i + 24), readl(base + i + 28));
+ }
+ netdev_info(dev, "Dumping tx ring\n");
+ for (i = 0; i < np->tx_ring_size; i += 4) {
+ if (!nv_optimized(np)) {
+ netdev_info(dev,
+ "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
+ i,
+ le32_to_cpu(np->tx_ring.orig[i].buf),
+ le32_to_cpu(np->tx_ring.orig[i].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+1].buf),
+ le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+2].buf),
+ le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+3].buf),
+ le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
+ } else {
+ netdev_info(dev,
+ "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+ i,
+ le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i].buflow),
+ le32_to_cpu(np->tx_ring.ex[i].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
}
}
@@ -2616,15 +2565,13 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
int protolen; /* length as stored in the proto field */
/* 1) calculate len according to header */
- if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
- protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+ if (((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
+ protolen = ntohs(((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto);
hdrlen = VLAN_HLEN;
} else {
- protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
+ protolen = ntohs(((struct ethhdr *)packet)->h_proto);
hdrlen = ETH_HLEN;
}
- dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
- dev->name, datalen, protolen, hdrlen);
if (protolen > ETH_DATA_LEN)
return datalen; /* Value in proto field not a len, no checks possible */
@@ -2635,26 +2582,18 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
/* more data on wire than in 802 header, trim of
* additional data.
*/
- dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
- dev->name, protolen);
return protolen;
} else {
/* less data on wire than mentioned in header.
* Discard the packet.
*/
- dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
- dev->name);
return -1;
}
} else {
/* short packet. Accept only if 802 values are also short */
if (protolen > ETH_ZLEN) {
- dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
- dev->name);
return -1;
}
- dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
- dev->name, datalen);
return datalen;
}
}
@@ -2667,13 +2606,10 @@ static int nv_rx_process(struct net_device *dev, int limit)
struct sk_buff *skb;
int len;
- while((np->get_rx.orig != np->put_rx.orig) &&
+ while ((np->get_rx.orig != np->put_rx.orig) &&
!((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
(rx_work < limit)) {
- dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
- dev->name, flags);
-
/*
* the packet is for us - immediately tear down the pci mapping.
* TODO: check if a prefetch of the first cacheline improves
@@ -2685,16 +2621,6 @@ static int nv_rx_process(struct net_device *dev, int limit)
skb = np->get_rx_ctx->skb;
np->get_rx_ctx->skb = NULL;
- {
- int j;
- dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
- for (j=0; j<64; j++) {
- if ((j%16) == 0)
- dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)skb->data)[j]);
- }
- dprintk("\n");
- }
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
if (likely(flags & NV_RX_DESCRIPTORVALID)) {
@@ -2710,9 +2636,8 @@ static int nv_rx_process(struct net_device *dev, int limit)
}
/* framing errors are soft errors */
else if ((flags & NV_RX_ERROR_MASK) == NV_RX_FRAMINGERR) {
- if (flags & NV_RX_SUBSTRACT1) {
+ if (flags & NV_RX_SUBSTRACT1)
len--;
- }
}
/* the rest are hard errors */
else {
@@ -2745,9 +2670,8 @@ static int nv_rx_process(struct net_device *dev, int limit)
}
/* framing errors are soft errors */
else if ((flags & NV_RX2_ERROR_MASK) == NV_RX2_FRAMINGERR) {
- if (flags & NV_RX2_SUBSTRACT1) {
+ if (flags & NV_RX2_SUBSTRACT1)
len--;
- }
}
/* the rest are hard errors */
else {
@@ -2771,8 +2695,6 @@ static int nv_rx_process(struct net_device *dev, int limit)
/* got a valid packet - forward it to the network core */
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, dev);
- dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
- dev->name, len, skb->protocol);
napi_gro_receive(&np->napi, skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
@@ -2797,13 +2719,10 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
struct sk_buff *skb;
int len;
- while((np->get_rx.ex != np->put_rx.ex) &&
+ while ((np->get_rx.ex != np->put_rx.ex) &&
!((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
(rx_work < limit)) {
- dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
- dev->name, flags);
-
/*
* the packet is for us - immediately tear down the pci mapping.
* TODO: check if a prefetch of the first cacheline improves
@@ -2815,16 +2734,6 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
skb = np->get_rx_ctx->skb;
np->get_rx_ctx->skb = NULL;
- {
- int j;
- dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
- for (j=0; j<64; j++) {
- if ((j%16) == 0)
- dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)skb->data)[j]);
- }
- dprintk("\n");
- }
/* look at what we actually got: */
if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
len = flags & LEN_MASK_V2;
@@ -2838,9 +2747,8 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
}
/* framing errors are soft errors */
else if ((flags & NV_RX2_ERROR_MASK) == NV_RX2_FRAMINGERR) {
- if (flags & NV_RX2_SUBSTRACT1) {
+ if (flags & NV_RX2_SUBSTRACT1)
len--;
- }
}
/* the rest are hard errors */
else {
@@ -2858,9 +2766,6 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
prefetch(skb->data);
- dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
- dev->name, len, skb->protocol);
-
if (likely(!np->vlangrp)) {
napi_gro_receive(&np->napi, skb);
} else {
@@ -2949,7 +2854,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
@@ -2986,7 +2891,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev)
static int nv_set_mac_address(struct net_device *dev, void *addr)
{
struct fe_priv *np = netdev_priv(dev);
- struct sockaddr *macaddr = (struct sockaddr*)addr;
+ struct sockaddr *macaddr = (struct sockaddr *)addr;
if (!is_valid_ether_addr(macaddr->sa_data))
return -EADDRNOTAVAIL;
@@ -3076,8 +2981,6 @@ static void nv_set_multicast(struct net_device *dev)
writel(mask[0], base + NvRegMulticastMaskA);
writel(mask[1], base + NvRegMulticastMaskB);
writel(pff, base + NvRegPacketFilterFlags);
- dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n",
- dev->name);
nv_start_rx(dev);
spin_unlock_irq(&np->lock);
}
@@ -3152,8 +3055,6 @@ static int nv_update_linkspeed(struct net_device *dev)
mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
if (!(mii_status & BMSR_LSTATUS)) {
- dprintk(KERN_DEBUG "%s: no link detected by phy - falling back to 10HD.\n",
- dev->name);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
retval = 0;
@@ -3161,8 +3062,6 @@ static int nv_update_linkspeed(struct net_device *dev)
}
if (np->autoneg == 0) {
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: autoneg off, PHY set to 0x%04x.\n",
- dev->name, np->fixed_mode);
if (np->fixed_mode & LPA_100FULL) {
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
newdup = 1;
@@ -3185,14 +3084,11 @@ static int nv_update_linkspeed(struct net_device *dev)
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
retval = 0;
- dprintk(KERN_DEBUG "%s: autoneg not completed - falling back to 10HD.\n", dev->name);
goto set_speed;
}
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
- dev->name, adv, lpa);
retval = 1;
if (np->gigabit == PHY_GIGABIT) {
@@ -3201,8 +3097,6 @@ static int nv_update_linkspeed(struct net_device *dev)
if ((control_1000 & ADVERTISE_1000FULL) &&
(status_1000 & LPA_1000FULL)) {
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",
- dev->name);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000;
newdup = 1;
goto set_speed;
@@ -3224,7 +3118,6 @@ static int nv_update_linkspeed(struct net_device *dev)
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
} else {
- dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, adv_lpa);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
newdup = 0;
}
@@ -3233,9 +3126,6 @@ set_speed:
if (np->duplex == newdup && np->linkspeed == newls)
return retval;
- dprintk(KERN_INFO "%s: changing link setting from %d/%d to %d/%d.\n",
- dev->name, np->linkspeed, np->duplex, newls, newdup);
-
np->duplex = newdup;
np->linkspeed = newls;
@@ -3302,7 +3192,7 @@ set_speed:
}
writel(txreg, base + NvRegTxWatermark);
- writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
+ writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1);
pci_push(base);
writel(np->linkspeed, base + NvRegLinkSpeed);
@@ -3312,8 +3202,8 @@ set_speed:
/* setup pause frame */
if (np->duplex != 0) {
if (np->autoneg && np->pause_flags & NV_PAUSEFRAME_AUTONEG) {
- adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM);
- lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
+ adv_pause = adv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+ lpa_pause = lpa & (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
switch (adv_pause) {
case ADVERTISE_PAUSE_CAP:
@@ -3324,22 +3214,17 @@ set_speed:
}
break;
case ADVERTISE_PAUSE_ASYM:
- if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
- {
+ if (lpa_pause == (LPA_PAUSE_CAP | LPA_PAUSE_ASYM))
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
- }
break;
- case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
- if (lpa_pause & LPA_PAUSE_CAP)
- {
+ case ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM:
+ if (lpa_pause & LPA_PAUSE_CAP) {
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
}
if (lpa_pause == LPA_PAUSE_ASYM)
- {
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
- }
break;
}
} else {
@@ -3361,14 +3246,14 @@ static void nv_linkchange(struct net_device *dev)
if (nv_update_linkspeed(dev)) {
if (!netif_carrier_ok(dev)) {
netif_carrier_on(dev);
- printk(KERN_INFO "%s: link up.\n", dev->name);
+ netdev_info(dev, "link up\n");
nv_txrx_gate(dev, false);
nv_start_rx(dev);
}
} else {
if (netif_carrier_ok(dev)) {
netif_carrier_off(dev);
- printk(KERN_INFO "%s: link down.\n", dev->name);
+ netdev_info(dev, "link down\n");
nv_txrx_gate(dev, true);
nv_stop_rx(dev);
}
@@ -3382,11 +3267,9 @@ static void nv_link_irq(struct net_device *dev)
miistat = readl(base + NvRegMIIStatus);
writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus);
- dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat);
if (miistat & (NVREG_MIISTAT_LINKCHANGE))
nv_linkchange(dev);
- dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
}
static void nv_msi_workaround(struct fe_priv *np)
@@ -3437,8 +3320,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
-
if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
np->events = readl(base + NvRegIrqStatus);
writel(np->events, base + NvRegIrqStatus);
@@ -3446,7 +3327,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
np->events = readl(base + NvRegMSIXIrqStatus);
writel(np->events, base + NvRegMSIXIrqStatus);
}
- dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
if (!(np->events & np->irqmask))
return IRQ_NONE;
@@ -3460,8 +3340,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
__napi_schedule(&np->napi);
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
-
return IRQ_HANDLED;
}
@@ -3476,8 +3354,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
-
if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
np->events = readl(base + NvRegIrqStatus);
writel(np->events, base + NvRegIrqStatus);
@@ -3485,7 +3361,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
np->events = readl(base + NvRegMSIXIrqStatus);
writel(np->events, base + NvRegMSIXIrqStatus);
}
- dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
if (!(np->events & np->irqmask))
return IRQ_NONE;
@@ -3498,7 +3373,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
writel(0, base + NvRegIrqMask);
__napi_schedule(&np->napi);
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
return IRQ_HANDLED;
}
@@ -3512,12 +3386,9 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
int i;
unsigned long flags;
- dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name);
-
- for (i=0; ; i++) {
+ for (i = 0;; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
- dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -3536,12 +3407,12 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
spin_unlock_irqrestore(&np->lock, flags);
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
+ netdev_dbg(dev, "%s: too many iterations (%d)\n",
+ __func__, i);
break;
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq_tx completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -3553,7 +3424,7 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
int retcode;
- int rx_count, tx_work=0, rx_work=0;
+ int rx_count, tx_work = 0, rx_work = 0;
do {
if (!nv_optimized(np)) {
@@ -3626,12 +3497,9 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
int i;
unsigned long flags;
- dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name);
-
- for (i=0; ; i++) {
+ for (i = 0;; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
- dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -3655,11 +3523,11 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
spin_unlock_irqrestore(&np->lock, flags);
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
+ netdev_dbg(dev, "%s: too many iterations (%d)\n",
+ __func__, i);
break;
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -3673,12 +3541,9 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
int i;
unsigned long flags;
- dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name);
-
- for (i=0; ; i++) {
+ for (i = 0;; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
- dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -3723,12 +3588,12 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
spin_unlock_irqrestore(&np->lock, flags);
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
+ netdev_dbg(dev, "%s: too many iterations (%d)\n",
+ __func__, i);
break;
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq_other completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -3740,8 +3605,6 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
u8 __iomem *base = get_hwbase(dev);
u32 events;
- dprintk(KERN_DEBUG "%s: nv_nic_irq_test\n", dev->name);
-
if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
writel(NVREG_IRQ_TIMER, base + NvRegIrqStatus);
@@ -3750,7 +3613,6 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
writel(NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus);
}
pci_push(base);
- dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & NVREG_IRQ_TIMER))
return IRQ_RETVAL(0);
@@ -3760,8 +3622,6 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
np->intr_test = 1;
spin_unlock(&np->lock);
- dprintk(KERN_DEBUG "%s: nv_nic_irq_test completed\n", dev->name);
-
return IRQ_RETVAL(1);
}
@@ -3776,17 +3636,15 @@ static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask)
* the remaining 8 interrupts.
*/
for (i = 0; i < 8; i++) {
- if ((irqmask >> i) & 0x1) {
+ if ((irqmask >> i) & 0x1)
msixmap |= vector << (i << 2);
- }
}
writel(readl(base + NvRegMSIXMap0) | msixmap, base + NvRegMSIXMap0);
msixmap = 0;
for (i = 0; i < 8; i++) {
- if ((irqmask >> (i + 8)) & 0x1) {
+ if ((irqmask >> (i + 8)) & 0x1)
msixmap |= vector << (i << 2);
- }
}
writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1);
}
@@ -3809,17 +3667,19 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
if (np->msi_flags & NV_MSI_X_CAPABLE) {
- for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
+ for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++)
np->msi_x_entry[i].entry = i;
- }
- if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) {
+ ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK));
+ if (ret == 0) {
np->msi_flags |= NV_MSI_X_ENABLED;
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
/* Request irq for rx handling */
sprintf(np->name_rx, "%s-rx", dev->name);
if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector,
nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret);
+ netdev_info(dev,
+ "request_irq failed for rx %d\n",
+ ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_err;
@@ -3828,7 +3688,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
sprintf(np->name_tx, "%s-tx", dev->name);
if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector,
nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret);
+ netdev_info(dev,
+ "request_irq failed for tx %d\n",
+ ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_free_rx;
@@ -3837,7 +3699,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
sprintf(np->name_other, "%s-other", dev->name);
if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector,
nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret);
+ netdev_info(dev,
+ "request_irq failed for link %d\n",
+ ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_free_tx;
@@ -3851,7 +3715,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
} else {
/* Request irq for all interrupts */
if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
+ netdev_info(dev,
+ "request_irq failed %d\n",
+ ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_err;
@@ -3864,11 +3730,13 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
}
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
- if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
+ ret = pci_enable_msi(np->pci_dev);
+ if (ret == 0) {
np->msi_flags |= NV_MSI_ENABLED;
dev->irq = np->pci_dev->irq;
if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
- printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
+ netdev_info(dev, "request_irq failed %d\n",
+ ret);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
dev->irq = np->pci_dev->irq;
@@ -3903,9 +3771,8 @@ static void nv_free_irq(struct net_device *dev)
int i;
if (np->msi_flags & NV_MSI_X_ENABLED) {
- for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
+ for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++)
free_irq(np->msi_x_entry[i].vector, dev);
- }
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
} else {
@@ -3954,7 +3821,7 @@ static void nv_do_nic_poll(unsigned long data)
if (np->recover_error) {
np->recover_error = 0;
- printk(KERN_INFO "%s: MAC in recoverable error state\n", dev->name);
+ netdev_info(dev, "MAC in recoverable error state\n");
if (netif_running(dev)) {
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
@@ -3975,7 +3842,7 @@ static void nv_do_nic_poll(unsigned long data)
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
@@ -4082,6 +3949,7 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
writel(flags, base + NvRegWakeUpFlags);
spin_unlock_irq(&np->lock);
}
+ device_set_wakeup_enable(&np->pci_dev->dev, np->wolenabled);
return 0;
}
@@ -4105,7 +3973,7 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_carrier_ok(dev)) {
- switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) {
+ switch (np->linkspeed & (NVREG_LINKSPEED_MASK)) {
case NVREG_LINKSPEED_10:
ecmd->speed = SPEED_10;
break;
@@ -4250,14 +4118,14 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_running(dev))
- printk(KERN_INFO "%s: link down.\n", dev->name);
+ netdev_info(dev, "link down\n");
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
bmcr |= BMCR_ANENABLE;
/* reset the phy in order for settings to stick,
* and cause autoneg to start */
if (phy_reset(dev, bmcr)) {
- printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ netdev_info(dev, "phy reset failed\n");
return -EINVAL;
}
} else {
@@ -4306,7 +4174,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (np->phy_oui == PHY_OUI_MARVELL) {
/* reset the phy in order for forced mode settings to stick */
if (phy_reset(dev, bmcr)) {
- printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ netdev_info(dev, "phy reset failed\n");
return -EINVAL;
}
} else {
@@ -4344,7 +4212,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void
regs->version = FORCEDETH_REGS_VER;
spin_lock_irq(&np->lock);
- for (i = 0;i <= np->register_size/sizeof(u32); i++)
+ for (i = 0; i <= np->register_size/sizeof(u32); i++)
rbuf[i] = readl(base + i*sizeof(u32));
spin_unlock_irq(&np->lock);
}
@@ -4368,7 +4236,7 @@ static int nv_nway_reset(struct net_device *dev)
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
- printk(KERN_INFO "%s: link down.\n", dev->name);
+ netdev_info(dev, "link down\n");
}
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
@@ -4376,7 +4244,7 @@ static int nv_nway_reset(struct net_device *dev)
bmcr |= BMCR_ANENABLE;
/* reset the phy in order for settings to stick*/
if (phy_reset(dev, bmcr)) {
- printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ netdev_info(dev, "phy reset failed\n");
return -EINVAL;
}
} else {
@@ -4464,10 +4332,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
rxtx_ring, ring_addr);
}
- if (rx_skbuff)
- kfree(rx_skbuff);
- if (tx_skbuff)
- kfree(tx_skbuff);
+
+ kfree(rx_skbuff);
+ kfree(tx_skbuff);
goto exit;
}
@@ -4491,14 +4358,14 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
np->tx_ring_size = ring->tx_pending;
if (!nv_optimized(np)) {
- np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
+ np->rx_ring.orig = (struct ring_desc *)rxtx_ring;
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
} else {
- np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
+ np->rx_ring.ex = (struct ring_desc_ex *)rxtx_ring;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skb = (struct nv_skb_map*)rx_skbuff;
- np->tx_skb = (struct nv_skb_map*)tx_skbuff;
+ np->rx_skb = (struct nv_skb_map *)rx_skbuff;
+ np->tx_skb = (struct nv_skb_map *)tx_skbuff;
np->ring_addr = ring_addr;
memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
@@ -4515,7 +4382,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
/* reinit nic view of the queues */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
@@ -4550,12 +4417,11 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
if ((!np->autoneg && np->duplex == 0) ||
(np->autoneg && !pause->autoneg && np->duplex == 0)) {
- printk(KERN_INFO "%s: can not set pause settings when forced link is in half duplex.\n",
- dev->name);
+ netdev_info(dev, "can not set pause settings when forced link is in half duplex\n");
return -EINVAL;
}
if (pause->tx_pause && !(np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)) {
- printk(KERN_INFO "%s: hardware does not support tx pause frames.\n", dev->name);
+ netdev_info(dev, "hardware does not support tx pause frames\n");
return -EINVAL;
}
@@ -4590,7 +4456,7 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
if (netif_running(dev))
- printk(KERN_INFO "%s: link down.\n", dev->name);
+ netdev_info(dev, "link down\n");
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
@@ -4841,7 +4707,7 @@ static int nv_loopback_test(struct net_device *dev)
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
@@ -4852,8 +4718,7 @@ static int nv_loopback_test(struct net_device *dev)
pkt_len = ETH_DATA_LEN;
tx_skb = dev_alloc_skb(pkt_len);
if (!tx_skb) {
- printk(KERN_ERR "dev_alloc_skb() failed during loopback test"
- " of %s\n", dev->name);
+ netdev_err(dev, "dev_alloc_skb() failed during loopback test\n");
ret = 0;
goto out;
}
@@ -4893,29 +4758,22 @@ static int nv_loopback_test(struct net_device *dev)
if (flags & NV_RX_ERROR)
ret = 0;
} else {
- if (flags & NV_RX2_ERROR) {
+ if (flags & NV_RX2_ERROR)
ret = 0;
- }
}
if (ret) {
if (len != pkt_len) {
ret = 0;
- dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
- dev->name, len, pkt_len);
} else {
rx_skb = np->rx_skb[0].skb;
for (i = 0; i < pkt_len; i++) {
if (rx_skb->data[i] != (u8)(i & 0xff)) {
ret = 0;
- dprintk(KERN_DEBUG "%s: loopback pattern check failed on byte %d\n",
- dev->name, i);
break;
}
}
}
- } else {
- dprintk(KERN_DEBUG "%s: loopback - did not receive test packet\n", dev->name);
}
pci_unmap_single(np->pci_dev, test_dma_addr,
@@ -4958,11 +4816,10 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
netif_addr_lock(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
- if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
- } else {
+ else
writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
- }
/* stop engines */
nv_stop_rxtx(dev);
nv_txrx_reset(dev);
@@ -5003,7 +4860,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
@@ -5106,8 +4963,7 @@ static int nv_mgmt_acquire_sema(struct net_device *dev)
((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) {
np->mgmt_sema = 1;
return 1;
- }
- else
+ } else
udelay(50);
}
@@ -5167,8 +5023,6 @@ static int nv_open(struct net_device *dev)
int oom, i;
u32 low;
- dprintk(KERN_DEBUG "nv_open: begin\n");
-
/* power up phy */
mii_rw(dev, np->phyaddr, MII_BMCR,
mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN);
@@ -5204,7 +5058,7 @@ static int nv_open(struct net_device *dev)
/* give hw rings */
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
- writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
+ writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
writel(np->linkspeed, base + NvRegLinkSpeed);
@@ -5216,9 +5070,11 @@ static int nv_open(struct net_device *dev)
writel(np->vlanctl_bits, base + NvRegVlanControl);
pci_push(base);
writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl);
- reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31,
- NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX,
- KERN_INFO "open: SetupReg5, Bit 31 remained off\n");
+ if (reg_delay(dev, NvRegUnknownSetupReg5,
+ NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31,
+ NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX))
+ netdev_info(dev,
+ "%s: SetupReg5, Bit 31 remained off\n", __func__);
writel(0, base + NvRegMIIMask);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
@@ -5251,8 +5107,7 @@ static int nv_open(struct net_device *dev)
writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
else
writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval);
- }
- else
+ } else
writel(poll_interval & 0xFFFF, base + NvRegPollingInterval);
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING,
@@ -5263,7 +5118,7 @@ static int nv_open(struct net_device *dev)
writel(NVREG_WAKEUPFLAGS_ENABLE , base + NvRegWakeUpFlags);
i = readl(base + NvRegPowerState);
- if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0)
+ if ((i & NVREG_POWERSTATE_POWEREDUP) == 0)
writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState);
pci_push(base);
@@ -5276,9 +5131,8 @@ static int nv_open(struct net_device *dev)
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
- if (nv_request_irq(dev, 0)) {
+ if (nv_request_irq(dev, 0))
goto out_drain;
- }
/* ask for interrupts */
nv_enable_hw_interrupts(dev, np->irqmask);
@@ -5296,7 +5150,6 @@ static int nv_open(struct net_device *dev)
u32 miistat;
miistat = readl(base + NvRegMIIStatus);
writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
- dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
}
/* set linkspeed to invalid value, thus force nv_update_linkspeed
* to init hw */
@@ -5309,7 +5162,7 @@ static int nv_open(struct net_device *dev)
if (ret) {
netif_carrier_on(dev);
} else {
- printk(KERN_INFO "%s: no link during initialization.\n", dev->name);
+ netdev_info(dev, "no link during initialization\n");
netif_carrier_off(dev);
}
if (oom)
@@ -5352,7 +5205,6 @@ static int nv_close(struct net_device *dev)
base = get_hwbase(dev);
nv_disable_hw_interrupts(dev, np->irqmask);
pci_push(base);
- dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);
spin_unlock_irq(&np->lock);
@@ -5421,8 +5273,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
static int printed_version;
if (!printed_version++)
- printk(KERN_INFO "%s: Reverse Engineered nForce ethernet"
- " driver. Version %s.\n", DRV_NAME, FORCEDETH_VERSION);
+ pr_info("Reverse Engineered nForce ethernet driver. Version %s.\n",
+ FORCEDETH_VERSION);
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -5465,10 +5317,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
err = -EINVAL;
addr = 0;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- dprintk(KERN_DEBUG "%s: resource %d start %p len %ld flags 0x%08lx.\n",
- pci_name(pci_dev), i, (void*)pci_resource_start(pci_dev, i),
- pci_resource_len(pci_dev, i),
- pci_resource_flags(pci_dev, i));
if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
pci_resource_len(pci_dev, i) >= np->register_size) {
addr = pci_resource_start(pci_dev, i);
@@ -5476,8 +5324,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
}
}
if (i == DEVICE_COUNT_RESOURCE) {
- dev_printk(KERN_INFO, &pci_dev->dev,
- "Couldn't find register window\n");
+ dev_info(&pci_dev->dev, "Couldn't find register window\n");
goto out_relreg;
}
@@ -5493,13 +5340,13 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
if (dma_64bit) {
if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(39)))
- dev_printk(KERN_INFO, &pci_dev->dev,
- "64-bit DMA failed, using 32-bit addressing\n");
+ dev_info(&pci_dev->dev,
+ "64-bit DMA failed, using 32-bit addressing\n");
else
dev->features |= NETIF_F_HIGHDMA;
if (pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(39))) {
- dev_printk(KERN_INFO, &pci_dev->dev,
- "64-bit DMA (consistent) failed, using 32-bit ring buffers\n");
+ dev_info(&pci_dev->dev,
+ "64-bit DMA (consistent) failed, using 32-bit ring buffers\n");
}
}
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
@@ -5620,7 +5467,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
- printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n");
+ dev_dbg(&pci_dev->dev,
+ "%s: set workaround bit for reversed mac addr\n",
+ __func__);
}
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
@@ -5629,28 +5478,21 @@ 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
*/
- dev_printk(KERN_ERR, &pci_dev->dev,
- "Invalid Mac address detected: %pM\n",
- dev->dev_addr);
- dev_printk(KERN_ERR, &pci_dev->dev,
- "Please complain to your hardware vendor. Switching to a random MAC.\n");
+ dev_err(&pci_dev->dev,
+ "Invalid MAC address detected: %pM - Please complain to your hardware vendor.\n",
+ dev->dev_addr);
random_ether_addr(dev->dev_addr);
+ dev_err(&pci_dev->dev,
+ "Using random MAC address: %pM\n", dev->dev_addr);
}
- dprintk(KERN_DEBUG "%s: MAC Address %pM\n",
- pci_name(pci_dev), dev->dev_addr);
-
/* set mac address */
nv_copy_mac_to_hw(dev);
- /* Workaround current PCI init glitch: wakeup bits aren't
- * being set from PCI PM capability.
- */
- device_init_wakeup(&pci_dev->dev, 1);
-
/* disable WOL */
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
+ device_set_wakeup_enable(&pci_dev->dev, false);
if (id->driver_data & DEV_HAS_POWER_CNTRL) {
@@ -5663,16 +5505,15 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
writel(powerstate, base + NvRegPowerState2);
}
- if (np->desc_ver == DESC_VER_1) {
+ if (np->desc_ver == DESC_VER_1)
np->tx_flags = NV_TX_VALID;
- } else {
+ else
np->tx_flags = NV_TX2_VALID;
- }
np->msi_flags = 0;
- if ((id->driver_data & DEV_HAS_MSI) && msi) {
+ if ((id->driver_data & DEV_HAS_MSI) && msi)
np->msi_flags |= NV_MSI_CAPABLE;
- }
+
if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
/* msix has had reported issues when modifying irqmask
as in the case of napi, therefore, disable for now
@@ -5702,11 +5543,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id->driver_data & DEV_NEED_TIMERIRQ)
np->irqmask |= NVREG_IRQ_TIMER;
if (id->driver_data & DEV_NEED_LINKTIMER) {
- dprintk(KERN_INFO "%s: link timer on.\n", pci_name(pci_dev));
np->need_linktimer = 1;
np->link_timeout = jiffies + LINK_TIMEOUT;
} else {
- dprintk(KERN_INFO "%s: link timer off.\n", pci_name(pci_dev));
np->need_linktimer = 0;
}
@@ -5735,19 +5574,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
nv_mgmt_acquire_sema(dev) &&
nv_mgmt_get_version(dev)) {
np->mac_in_use = 1;
- if (np->mgmt_version > 0) {
+ if (np->mgmt_version > 0)
np->mac_in_use = readl(base + NvRegMgmtUnitControl) & NVREG_MGMTUNITCONTROL_INUSE;
- }
- dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n",
- pci_name(pci_dev), np->mac_in_use);
/* management unit setup the phy already? */
if (np->mac_in_use &&
((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) ==
NVREG_XMITCTL_SYNC_PHY_INIT)) {
/* phy is inited by mgmt unit */
phyinitialized = 1;
- dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n",
- pci_name(pci_dev));
} else {
/* we need to init the phy */
}
@@ -5773,8 +5607,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->phy_model = id2 & PHYID2_MODEL_MASK;
id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
- dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
- pci_name(pci_dev), id1, id2, phyaddr);
np->phyaddr = phyaddr;
np->phy_oui = id1 | id2;
@@ -5788,8 +5620,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
break;
}
if (i == 33) {
- dev_printk(KERN_INFO, &pci_dev->dev,
- "open: Could not find a valid PHY.\n");
+ dev_info(&pci_dev->dev, "open: Could not find a valid PHY\n");
goto out_error;
}
@@ -5799,9 +5630,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
} else {
/* see if it is a gigabit phy */
u32 mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
- if (mii_status & PHY_GIGABIT) {
+ if (mii_status & PHY_GIGABIT)
np->gigabit = PHY_GIGABIT;
- }
}
/* set default link speed settings */
@@ -5811,37 +5641,27 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
err = register_netdev(dev);
if (err) {
- dev_printk(KERN_INFO, &pci_dev->dev,
- "unable to register netdev: %d\n", err);
+ dev_info(&pci_dev->dev, "unable to register netdev: %d\n", err);
goto out_error;
}
- dev_printk(KERN_INFO, &pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, "
- "addr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- dev->name,
- np->phy_oui,
- np->phyaddr,
- dev->dev_addr[0],
- dev->dev_addr[1],
- dev->dev_addr[2],
- dev->dev_addr[3],
- dev->dev_addr[4],
- dev->dev_addr[5]);
-
- dev_printk(KERN_INFO, &pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
- dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
- dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
- "csum " : "",
- dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
- "vlan " : "",
- id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "",
- id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "",
- id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "",
- np->gigabit == PHY_GIGABIT ? "gbit " : "",
- np->need_linktimer ? "lnktim " : "",
- np->msi_flags & NV_MSI_CAPABLE ? "msi " : "",
- np->msi_flags & NV_MSI_X_CAPABLE ? "msi-x " : "",
- np->desc_ver);
+ dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
+ dev->name, np->phy_oui, np->phyaddr, dev->dev_addr);
+
+ dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
+ dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
+ dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
+ "csum " : "",
+ dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
+ "vlan " : "",
+ id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "",
+ id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "",
+ id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "",
+ np->gigabit == PHY_GIGABIT ? "gbit " : "",
+ np->need_linktimer ? "lnktim " : "",
+ np->msi_flags & NV_MSI_CAPABLE ? "msi " : "",
+ np->msi_flags & NV_MSI_X_CAPABLE ? "msi-x " : "",
+ np->desc_ver);
return 0;
@@ -5923,44 +5743,37 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
}
#ifdef CONFIG_PM
-static int nv_suspend(struct pci_dev *pdev, pm_message_t state)
+static int nv_suspend(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int i;
if (netif_running(dev)) {
- // Gross.
+ /* Gross. */
nv_close(dev);
}
netif_device_detach(dev);
/* save non-pci configuration space */
- for (i = 0;i <= np->register_size/sizeof(u32); i++)
+ for (i = 0; i <= np->register_size/sizeof(u32); i++)
np->saved_config_space[i] = readl(base + i*sizeof(u32));
- pci_save_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
-static int nv_resume(struct pci_dev *pdev)
+static int nv_resume(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int i, rc = 0;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- /* ack any pending wake events, disable PME */
- pci_enable_wake(pdev, PCI_D0, 0);
-
/* restore non-pci configuration space */
- for (i = 0;i <= np->register_size/sizeof(u32); i++)
+ for (i = 0; i <= np->register_size/sizeof(u32); i++)
writel(np->saved_config_space[i], base+i*sizeof(u32));
if (np->driver_data & DEV_NEED_MSI_FIX)
@@ -5977,6 +5790,9 @@ static int nv_resume(struct pci_dev *pdev)
return rc;
}
+static SIMPLE_DEV_PM_OPS(nv_pm_ops, nv_suspend, nv_resume);
+#define NV_PM_OPS (&nv_pm_ops)
+
static void nv_shutdown(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -5990,9 +5806,8 @@ static void nv_shutdown(struct pci_dev *pdev)
* If we really go for poweroff, we must not restore the MAC,
* otherwise the MAC for WOL will be reversed at least on some boards.
*/
- if (system_state != SYSTEM_POWER_OFF) {
+ if (system_state != SYSTEM_POWER_OFF)
nv_restore_mac_addr(pdev);
- }
pci_disable_device(pdev);
/*
@@ -6000,15 +5815,13 @@ static void nv_shutdown(struct pci_dev *pdev)
* only put the device into D3 if we really go for poweroff.
*/
if (system_state == SYSTEM_POWER_OFF) {
- if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
- pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+ pci_wake_from_d3(pdev, np->wolenabled);
pci_set_power_state(pdev, PCI_D3hot);
}
}
#else
-#define nv_suspend NULL
+#define NV_PM_OPS NULL
#define nv_shutdown NULL
-#define nv_resume NULL
#endif /* CONFIG_PM */
static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
@@ -6180,9 +5993,8 @@ static struct pci_driver driver = {
.id_table = pci_tbl,
.probe = nv_probe,
.remove = __devexit_p(nv_remove),
- .suspend = nv_suspend,
- .resume = nv_resume,
.shutdown = nv_shutdown,
+ .driver.pm = NV_PM_OPS,
};
static int __init init_nic(void)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index d684f187de57..7a1f3d0ffa78 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -40,6 +40,7 @@
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
+#include <linux/of_net.h>
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 49e4ce1246a7..119aa2000c24 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -95,6 +95,7 @@
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/of.h>
+#include <linux/of_net.h>
#include "gianfar.h"
#include "fsl_pq_mdio.h"
@@ -143,7 +144,8 @@ void gfar_halt(struct net_device *dev);
static void gfar_halt_nodisable(struct net_device *dev);
void gfar_start(struct net_device *dev);
static void gfar_clear_exact_match(struct net_device *dev);
-static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
+static void gfar_set_mac_for_addr(struct net_device *dev, int num,
+ const u8 *addr);
static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
MODULE_AUTHOR("Freescale Semiconductor, Inc");
@@ -432,7 +434,6 @@ static void gfar_init_mac(struct net_device *ndev)
static struct net_device_stats *gfar_get_stats(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct netdev_queue *txq;
unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
unsigned long tx_packets = 0, tx_bytes = 0;
int i = 0;
@@ -448,9 +449,8 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
dev->stats.rx_dropped = rx_dropped;
for (i = 0; i < priv->num_tx_queues; i++) {
- txq = netdev_get_tx_queue(dev, i);
- tx_bytes += txq->tx_bytes;
- tx_packets += txq->tx_packets;
+ tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
+ tx_packets += priv->tx_queue[i]->stats.tx_packets;
}
dev->stats.tx_bytes = tx_bytes;
@@ -577,11 +577,10 @@ static int gfar_parse_group(struct device_node *np,
irq_of_parse_and_map(np, 1);
priv->gfargrp[priv->num_grps].interruptError =
irq_of_parse_and_map(np,2);
- if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 ||
- priv->gfargrp[priv->num_grps].interruptReceive < 0 ||
- priv->gfargrp[priv->num_grps].interruptError < 0) {
+ if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
+ priv->gfargrp[priv->num_grps].interruptReceive == NO_IRQ ||
+ priv->gfargrp[priv->num_grps].interruptError == NO_IRQ)
return -EINVAL;
- }
}
priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
@@ -2108,8 +2107,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Update transmit stats */
- txq->tx_bytes += skb->len;
- txq->tx_packets ++;
+ tx_queue->stats.tx_bytes += skb->len;
+ tx_queue->stats.tx_packets++;
txbdp = txbdp_start = tx_queue->cur_tx;
lstatus = txbdp->lstatus;
@@ -3095,10 +3094,10 @@ static void gfar_set_multi(struct net_device *dev)
static void gfar_clear_exact_match(struct net_device *dev)
{
int idx;
- u8 zero_arr[MAC_ADDR_LEN] = {0,0,0,0,0,0};
+ static const u8 zero_arr[MAC_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
- gfar_set_mac_for_addr(dev, idx, (u8 *)zero_arr);
+ gfar_set_mac_for_addr(dev, idx, zero_arr);
}
/* Set the appropriate hash bit for the given addr */
@@ -3133,7 +3132,8 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
/* There are multiple MAC Address register pairs on some controllers
* This function sets the numth pair to a given address
*/
-static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
+static void gfar_set_mac_for_addr(struct net_device *dev, int num,
+ const u8 *addr)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 68984eb88ae0..54de4135e932 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -907,12 +907,21 @@ enum {
MQ_MG_MODE
};
+/*
+ * Per TX queue stats
+ */
+struct tx_q_stats {
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
/**
* struct gfar_priv_tx_q - per tx queue structure
* @txlock: per queue tx spin lock
* @tx_skbuff:skb pointers
* @skb_curtx: to be used skb pointer
* @skb_dirtytx:the last used skb pointer
+ * @stats: bytes/packets stats
* @qindex: index of this queue
* @dev: back pointer to the dev structure
* @grp: back pointer to the group to which this queue belongs
@@ -934,6 +943,7 @@ struct gfar_priv_tx_q {
struct txbd8 *tx_bd_base;
struct txbd8 *cur_tx;
struct txbd8 *dirty_tx;
+ struct tx_q_stats stats;
struct net_device *dev;
struct gfar_priv_grp *grp;
u16 skb_curtx;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 5c566ebc54b8..3bc8e276ba4d 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -635,9 +635,10 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
+ device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
+
spin_lock_irqsave(&priv->bflock, flags);
- priv->wol_en = wol->wolopts & WAKE_MAGIC ? 1 : 0;
- device_set_wakeup_enable(&dev->dev, priv->wol_en);
+ priv->wol_en = !!device_may_wakeup(&dev->dev);
spin_unlock_irqrestore(&priv->bflock, flags);
return 0;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 27d6960ce09e..fdb0333f5cb6 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1,7 +1,7 @@
/*
* Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
*
- * 2005-2009 (c) Aeroflex Gaisler AB
+ * 2005-2010 (c) Aeroflex Gaisler AB
*
* This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
* available in the GRLIB VHDL IP core library.
@@ -356,6 +356,8 @@ static int greth_open(struct net_device *dev)
dev_dbg(&dev->dev, " starting queue\n");
netif_start_queue(dev);
+ GRETH_REGSAVE(greth->regs->status, 0xFF);
+
napi_enable(&greth->napi);
greth_enable_irqs(greth);
@@ -371,7 +373,9 @@ static int greth_close(struct net_device *dev)
napi_disable(&greth->napi);
+ greth_disable_irqs(greth);
greth_disable_tx(greth);
+ greth_disable_rx(greth);
netif_stop_queue(dev);
@@ -388,12 +392,20 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct greth_private *greth = netdev_priv(dev);
struct greth_bd *bdp;
int err = NETDEV_TX_OK;
- u32 status, dma_addr;
+ u32 status, dma_addr, ctrl;
+ unsigned long flags;
- bdp = greth->tx_bd_base + greth->tx_next;
+ /* Clean TX Ring */
+ greth_clean_tx(greth->netdev);
if (unlikely(greth->tx_free <= 0)) {
+ spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Enable TX IRQ only if not already in poll() routine */
+ if (ctrl & GRETH_RXI)
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
netif_stop_queue(dev);
+ spin_unlock_irqrestore(&greth->devlock, flags);
return NETDEV_TX_BUSY;
}
@@ -406,13 +418,14 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
}
+ bdp = greth->tx_bd_base + greth->tx_next;
dma_addr = greth_read_bd(&bdp->addr);
memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
- status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
+ status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
/* Wrap around descriptor ring */
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
@@ -422,22 +435,11 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
greth->tx_next = NEXT_TX(greth->tx_next);
greth->tx_free--;
- /* No more descriptors */
- if (unlikely(greth->tx_free == 0)) {
-
- /* Free transmitted descriptors */
- greth_clean_tx(dev);
-
- /* If nothing was cleaned, stop queue & wait for irq */
- if (unlikely(greth->tx_free == 0)) {
- status |= GRETH_BD_IE;
- netif_stop_queue(dev);
- }
- }
-
/* Write descriptor control word and enable transmission */
greth_write_bd(&bdp->stat, status);
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
greth_enable_tx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
out:
dev_kfree_skb(skb);
@@ -450,13 +452,23 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
{
struct greth_private *greth = netdev_priv(dev);
struct greth_bd *bdp;
- u32 status = 0, dma_addr;
+ u32 status = 0, dma_addr, ctrl;
int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
+ unsigned long flags;
nr_frags = skb_shinfo(skb)->nr_frags;
+ /* Clean TX Ring */
+ greth_clean_tx_gbit(dev);
+
if (greth->tx_free < nr_frags + 1) {
+ spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Enable TX IRQ only if not already in poll() routine */
+ if (ctrl & GRETH_RXI)
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
netif_stop_queue(dev);
+ spin_unlock_irqrestore(&greth->devlock, flags);
err = NETDEV_TX_BUSY;
goto out;
}
@@ -499,7 +511,7 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
greth->tx_skbuff[curr_tx] = NULL;
bdp = greth->tx_bd_base + curr_tx;
- status = GRETH_TXBD_CSALL;
+ status = GRETH_TXBD_CSALL | GRETH_BD_EN;
status |= frag->size & GRETH_BD_LEN;
/* Wrap around descriptor ring */
@@ -509,14 +521,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
/* More fragments left */
if (i < nr_frags - 1)
status |= GRETH_TXBD_MORE;
-
- /* ... last fragment, check if out of descriptors */
- else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
-
- /* Enable interrupts and stop queue */
- status |= GRETH_BD_IE;
- netif_stop_queue(dev);
- }
+ else
+ status |= GRETH_BD_IE; /* enable IRQ on last fragment */
greth_write_bd(&bdp->stat, status);
@@ -536,26 +542,29 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
wmb();
- /* Enable the descriptors that we configured ... */
- for (i = 0; i < nr_frags + 1; i++) {
- bdp = greth->tx_bd_base + greth->tx_next;
- greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
- greth->tx_next = NEXT_TX(greth->tx_next);
- greth->tx_free--;
- }
+ /* Enable the descriptor chain by enabling the first descriptor */
+ bdp = greth->tx_bd_base + greth->tx_next;
+ greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
+ greth->tx_next = curr_tx;
+ greth->tx_free -= nr_frags + 1;
+ wmb();
+
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
greth_enable_tx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
return NETDEV_TX_OK;
frag_map_error:
- /* Unmap SKB mappings that succeeded */
+ /* Unmap SKB mappings that succeeded and disable descriptor */
for (i = 0; greth->tx_next + i != curr_tx; i++) {
bdp = greth->tx_bd_base + greth->tx_next + i;
dma_unmap_single(greth->dev,
greth_read_bd(&bdp->addr),
greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
DMA_TO_DEVICE);
+ greth_write_bd(&bdp->stat, 0);
}
map_error:
if (net_ratelimit())
@@ -565,12 +574,11 @@ out:
return err;
}
-
static irqreturn_t greth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct greth_private *greth;
- u32 status;
+ u32 status, ctrl;
irqreturn_t retval = IRQ_NONE;
greth = netdev_priv(dev);
@@ -580,13 +588,15 @@ static irqreturn_t greth_interrupt(int irq, void *dev_id)
/* Get the interrupt events that caused us to be here. */
status = GRETH_REGLOAD(greth->regs->status);
- /* Handle rx and tx interrupts through poll */
- if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
-
- /* Clear interrupt status */
- GRETH_REGORIN(greth->regs->status,
- status & (GRETH_INT_RX | GRETH_INT_TX));
+ /* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be
+ * set regardless of whether IRQ is enabled or not. Especially
+ * important when shared IRQ.
+ */
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Handle rx and tx interrupts through poll */
+ if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
+ ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
retval = IRQ_HANDLED;
/* Disable interrupts and schedule poll() */
@@ -610,6 +620,8 @@ static void greth_clean_tx(struct net_device *dev)
while (1) {
bdp = greth->tx_bd_base + greth->tx_last;
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+ mb();
stat = greth_read_bd(&bdp->stat);
if (unlikely(stat & GRETH_BD_EN))
@@ -670,7 +682,10 @@ static void greth_clean_tx_gbit(struct net_device *dev)
/* We only clean fully completed SKBs */
bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
- stat = bdp_last_frag->stat;
+
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+ mb();
+ stat = greth_read_bd(&bdp_last_frag->stat);
if (stat & GRETH_BD_EN)
break;
@@ -702,21 +717,9 @@ static void greth_clean_tx_gbit(struct net_device *dev)
greth->tx_free += nr_frags+1;
dev_kfree_skb(skb);
}
- if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
- netif_wake_queue(dev);
- }
-}
-static int greth_pending_packets(struct greth_private *greth)
-{
- struct greth_bd *bdp;
- u32 status;
- bdp = greth->rx_bd_base + greth->rx_cur;
- status = greth_read_bd(&bdp->stat);
- if (status & GRETH_BD_EN)
- return 0;
- else
- return 1;
+ if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1)))
+ netif_wake_queue(dev);
}
static int greth_rx(struct net_device *dev, int limit)
@@ -727,20 +730,24 @@ static int greth_rx(struct net_device *dev, int limit)
int pkt_len;
int bad, count;
u32 status, dma_addr;
+ unsigned long flags;
greth = netdev_priv(dev);
for (count = 0; count < limit; ++count) {
bdp = greth->rx_bd_base + greth->rx_cur;
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+ mb();
status = greth_read_bd(&bdp->stat);
- dma_addr = greth_read_bd(&bdp->addr);
- bad = 0;
if (unlikely(status & GRETH_BD_EN)) {
break;
}
+ dma_addr = greth_read_bd(&bdp->addr);
+ bad = 0;
+
/* Check status for errors. */
if (unlikely(status & GRETH_RXBD_STATUS)) {
if (status & GRETH_RXBD_ERR_FT) {
@@ -802,7 +809,9 @@ static int greth_rx(struct net_device *dev, int limit)
dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
+ spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
greth_enable_rx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}
@@ -836,6 +845,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
int pkt_len;
int bad, count = 0;
u32 status, dma_addr;
+ unsigned long flags;
greth = netdev_priv(dev);
@@ -843,6 +853,8 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
bdp = greth->rx_bd_base + greth->rx_cur;
skb = greth->rx_skbuff[greth->rx_cur];
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+ mb();
status = greth_read_bd(&bdp->stat);
bad = 0;
@@ -865,10 +877,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
}
}
- /* Allocate new skb to replace current */
- newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
-
- if (!bad && newskb) {
+ /* Allocate new skb to replace current, not needed if the
+ * current skb can be reused */
+ if (!bad && (newskb=netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN))) {
skb_reserve(newskb, NET_IP_ALIGN);
dma_addr = dma_map_single(greth->dev,
@@ -905,11 +916,22 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
if (net_ratelimit())
dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
dev_kfree_skb(newskb);
+ /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
+ } else if (bad) {
+ /* Bad Frame transfer, the skb is reused */
+ dev->stats.rx_dropped++;
} else {
+ /* Failed Allocating a new skb. This is rather stupid
+ * but the current "filled" skb is reused, as if
+ * transfer failure. One could argue that RX descriptor
+ * table handling should be divided into cleaning and
+ * filling as the TX part of the driver
+ */
if (net_ratelimit())
dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
+ /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
@@ -920,7 +942,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
wmb();
greth_write_bd(&bdp->stat, status);
+ spin_lock_irqsave(&greth->devlock, flags);
greth_enable_rx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}
@@ -932,15 +956,18 @@ static int greth_poll(struct napi_struct *napi, int budget)
{
struct greth_private *greth;
int work_done = 0;
+ unsigned long flags;
+ u32 mask, ctrl;
greth = container_of(napi, struct greth_private, napi);
- if (greth->gbit_mac) {
- greth_clean_tx_gbit(greth->netdev);
- } else {
- greth_clean_tx(greth->netdev);
+restart_txrx_poll:
+ if (netif_queue_stopped(greth->netdev)) {
+ if (greth->gbit_mac)
+ greth_clean_tx_gbit(greth->netdev);
+ else
+ greth_clean_tx(greth->netdev);
}
-restart_poll:
if (greth->gbit_mac) {
work_done += greth_rx_gbit(greth->netdev, budget - work_done);
} else {
@@ -949,15 +976,29 @@ restart_poll:
if (work_done < budget) {
- napi_complete(napi);
+ spin_lock_irqsave(&greth->devlock, flags);
+
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ if (netif_queue_stopped(greth->netdev)) {
+ GRETH_REGSAVE(greth->regs->control,
+ ctrl | GRETH_TXI | GRETH_RXI);
+ mask = GRETH_INT_RX | GRETH_INT_RE |
+ GRETH_INT_TX | GRETH_INT_TE;
+ } else {
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
+ mask = GRETH_INT_RX | GRETH_INT_RE;
+ }
- if (greth_pending_packets(greth)) {
- napi_reschedule(napi);
- goto restart_poll;
+ if (GRETH_REGLOAD(greth->regs->status) & mask) {
+ GRETH_REGSAVE(greth->regs->control, ctrl);
+ spin_unlock_irqrestore(&greth->devlock, flags);
+ goto restart_txrx_poll;
+ } else {
+ __napi_complete(napi);
+ spin_unlock_irqrestore(&greth->devlock, flags);
}
}
- greth_enable_irqs(greth);
return work_done;
}
@@ -1152,11 +1193,11 @@ static const struct ethtool_ops greth_ethtool_ops = {
};
static struct net_device_ops greth_netdev_ops = {
- .ndo_open = greth_open,
- .ndo_stop = greth_close,
- .ndo_start_xmit = greth_start_xmit,
- .ndo_set_mac_address = greth_set_mac_add,
- .ndo_validate_addr = eth_validate_addr,
+ .ndo_open = greth_open,
+ .ndo_stop = greth_close,
+ .ndo_start_xmit = greth_start_xmit,
+ .ndo_set_mac_address = greth_set_mac_add,
+ .ndo_validate_addr = eth_validate_addr,
};
static inline int wait_for_mdio(struct greth_private *greth)
@@ -1217,29 +1258,26 @@ static void greth_link_change(struct net_device *dev)
struct greth_private *greth = netdev_priv(dev);
struct phy_device *phydev = greth->phy;
unsigned long flags;
-
int status_change = 0;
+ u32 ctrl;
spin_lock_irqsave(&greth->devlock, flags);
if (phydev->link) {
if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
-
- GRETH_REGANDIN(greth->regs->control,
- ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
+ ctrl = GRETH_REGLOAD(greth->regs->control) &
+ ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB);
if (phydev->duplex)
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
-
- if (phydev->speed == SPEED_100) {
-
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
- }
+ ctrl |= GRETH_CTRL_FD;
+ if (phydev->speed == SPEED_100)
+ ctrl |= GRETH_CTRL_SP;
else if (phydev->speed == SPEED_1000)
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
+ ctrl |= GRETH_CTRL_GB;
+ GRETH_REGSAVE(greth->regs->control, ctrl);
greth->speed = phydev->speed;
greth->duplex = phydev->duplex;
status_change = 1;
@@ -1600,6 +1638,9 @@ static struct of_device_id greth_of_match[] = {
{
.name = "GAISLER_ETHMAC",
},
+ {
+ .name = "01_01d",
+ },
{},
};
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
index 03ad903cd676..be0f2062bd14 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/greth.h
@@ -23,6 +23,7 @@
#define GRETH_BD_LEN 0x7FF
#define GRETH_TXEN 0x1
+#define GRETH_INT_TE 0x2
#define GRETH_INT_TX 0x8
#define GRETH_TXI 0x4
#define GRETH_TXBD_STATUS 0x0001C000
@@ -35,6 +36,7 @@
#define GRETH_TXBD_ERR_UE 0x4000
#define GRETH_TXBD_ERR_AL 0x8000
+#define GRETH_INT_RE 0x1
#define GRETH_INT_RX 0x4
#define GRETH_RXEN 0x2
#define GRETH_RXI 0x8
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 9a6485892b3d..80d25ed53344 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1202,7 +1202,7 @@ static void hamachi_init_ring(struct net_device *dev)
}
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2);
hmp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
@@ -1669,7 +1669,7 @@ static int hamachi_rx(struct net_device *dev)
entry = hmp->dirty_rx % RX_RING_SIZE;
desc = &(hmp->rx_ring[entry]);
if (hmp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2);
hmp->rx_skbuff[entry] = skb;
if (skb == NULL)
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 4e7d1d0a2340..7d9ced0738c5 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -396,7 +396,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate,
while (p) {
if (p->bitrate == bitrate) {
memcpy(p->bits, bits, YAM_FPGA_SIZE);
- return p->bits;
+ goto out;
}
p = p->next;
}
@@ -411,7 +411,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate,
p->bitrate = bitrate;
p->next = yam_data;
yam_data = p;
-
+ out:
release_firmware(fw);
return p->bits;
}
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index d15d2f2ba78e..ef2014375e62 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -162,9 +162,9 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
/* Snarf the interrupt now. Someday this could be moved to open(). */
if (dev->irq < 2) {
- int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
- int irq_8list[] = { 7, 5, 3, 4, 9, 0};
- int *irqp = wordmode ? irq_16list : irq_8list;
+ static const int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
+ static const int irq_8list[] = { 7, 5, 3, 4, 9, 0};
+ const int *irqp = wordmode ? irq_16list : irq_8list;
do {
int irq = *irqp;
if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 385dc3204cb7..6d9275c52e05 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1279,7 +1279,7 @@ static void emac_force_link_update(struct emac_instance *dev)
netif_carrier_off(dev->ndev);
smp_rmb();
if (dev->link_polling) {
- cancel_rearming_delayed_work(&dev->link_work);
+ cancel_delayed_work_sync(&dev->link_work);
if (dev->link_polling)
schedule_delayed_work(&dev->link_work, PHY_POLL_LINK_OFF);
}
@@ -1294,7 +1294,7 @@ static int emac_close(struct net_device *ndev)
if (dev->phy.address >= 0) {
dev->link_polling = 0;
- cancel_rearming_delayed_work(&dev->link_work);
+ cancel_delayed_work_sync(&dev->link_work);
}
mutex_lock(&dev->link_lock);
emac_netif_stop(dev);
@@ -2871,7 +2871,6 @@ static int __devinit emac_probe(struct platform_device *ofdev,
SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
netif_carrier_off(ndev);
- netif_stop_queue(ndev);
err = register_netdev(ndev);
if (err) {
@@ -2951,7 +2950,7 @@ static int __devexit emac_remove(struct platform_device *ofdev)
unregister_netdev(dev->ndev);
- flush_scheduled_work();
+ cancel_work_sync(&dev->reset_work);
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
tah_detach(dev->tah_dev, dev->tah_port);
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index c454b45ca7ec..5522d459654c 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -729,11 +729,6 @@ static void netdev_get_drvinfo(struct net_device *dev,
sizeof(info->version) - 1);
}
-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 = netdev_priv(dev);
@@ -918,7 +913,7 @@ static void ibmveth_get_ethtool_stats(struct net_device *dev,
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
- .get_link = netdev_get_link,
+ .get_link = ethtool_op_get_link,
.set_tx_csum = ibmveth_set_tx_csum,
.get_rx_csum = ibmveth_get_rx_csum,
.set_rx_csum = ibmveth_set_rx_csum,
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index ab9f675c5b8b..e07d487f015a 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -36,22 +36,10 @@
#include <net/pkt_sched.h>
#include <net/net_namespace.h>
-#define TX_TIMEOUT (2*HZ)
-
#define TX_Q_LIMIT 32
struct ifb_private {
struct tasklet_struct ifb_tasklet;
int tasklet_pending;
- /* mostly debug stats leave in for now */
- unsigned long st_task_enter; /* tasklet entered */
- unsigned long st_txq_refl_try; /* transmit queue refill attempt */
- unsigned long st_rxq_enter; /* receive queue entered */
- unsigned long st_rx2tx_tran; /* receive to trasmit transfers */
- unsigned long st_rxq_notenter; /*receiveQ not entered, resched */
- unsigned long st_rx_frm_egr; /* received from egress path */
- unsigned long st_rx_frm_ing; /* received from ingress path */
- unsigned long st_rxq_check;
- unsigned long st_rxq_rsch;
struct sk_buff_head rq;
struct sk_buff_head tq;
};
@@ -73,24 +61,17 @@ static void ri_tasklet(unsigned long dev)
struct sk_buff *skb;
txq = netdev_get_tx_queue(_dev, 0);
- dp->st_task_enter++;
if ((skb = skb_peek(&dp->tq)) == NULL) {
- dp->st_txq_refl_try++;
if (__netif_tx_trylock(txq)) {
- dp->st_rxq_enter++;
- while ((skb = skb_dequeue(&dp->rq)) != NULL) {
- skb_queue_tail(&dp->tq, skb);
- dp->st_rx2tx_tran++;
- }
+ skb_queue_splice_tail_init(&dp->rq, &dp->tq);
__netif_tx_unlock(txq);
} else {
/* reschedule */
- dp->st_rxq_notenter++;
goto resched;
}
}
- while ((skb = skb_dequeue(&dp->tq)) != NULL) {
+ while ((skb = __skb_dequeue(&dp->tq)) != NULL) {
u32 from = G_TC_FROM(skb->tc_verd);
skb->tc_verd = 0;
@@ -104,30 +85,28 @@ static void ri_tasklet(unsigned long dev)
rcu_read_unlock();
dev_kfree_skb(skb);
stats->tx_dropped++;
+ if (skb_queue_len(&dp->tq) != 0)
+ goto resched;
break;
}
rcu_read_unlock();
skb->skb_iif = _dev->ifindex;
if (from & AT_EGRESS) {
- dp->st_rx_frm_egr++;
dev_queue_xmit(skb);
} else if (from & AT_INGRESS) {
- dp->st_rx_frm_ing++;
skb_pull(skb, skb->dev->hard_header_len);
- netif_rx(skb);
+ netif_receive_skb(skb);
} else
BUG();
}
if (__netif_tx_trylock(txq)) {
- dp->st_rxq_check++;
if ((skb = skb_peek(&dp->rq)) == NULL) {
dp->tasklet_pending = 0;
if (netif_queue_stopped(_dev))
netif_wake_queue(_dev);
} else {
- dp->st_rxq_rsch++;
__netif_tx_unlock(txq);
goto resched;
}
@@ -147,6 +126,10 @@ static const struct net_device_ops ifb_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
+#define IFB_FEATURES (NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \
+ NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6 | \
+ NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
+
static void ifb_setup(struct net_device *dev)
{
/* Initialize the device structure. */
@@ -157,6 +140,9 @@ static void ifb_setup(struct net_device *dev)
ether_setup(dev);
dev->tx_queue_len = TX_Q_LIMIT;
+ dev->features |= IFB_FEATURES;
+ dev->vlan_features |= IFB_FEATURES;
+
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
@@ -182,7 +168,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- skb_queue_tail(&dp->rq, skb);
+ __skb_queue_tail(&dp->rq, skb);
if (!dp->tasklet_pending) {
dp->tasklet_pending = 1;
tasklet_schedule(&dp->ifb_tasklet);
@@ -197,8 +183,8 @@ static int ifb_close(struct net_device *dev)
tasklet_kill(&dp->ifb_tasklet);
netif_stop_queue(dev);
- skb_queue_purge(&dp->rq);
- skb_queue_purge(&dp->tq);
+ __skb_queue_purge(&dp->rq);
+ __skb_queue_purge(&dp->tq);
return 0;
}
@@ -207,8 +193,8 @@ static int ifb_open(struct net_device *dev)
struct ifb_private *dp = netdev_priv(dev);
tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev);
- skb_queue_head_init(&dp->rq);
- skb_queue_head_init(&dp->tq);
+ __skb_queue_head_init(&dp->rq);
+ __skb_queue_head_init(&dp->tq);
netif_start_queue(dev);
return 0;
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index bc183f5487cb..0a2368fa6bc6 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -134,6 +134,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_82580_COPPER_DUAL:
case E1000_DEV_ID_DH89XXCC_SGMII:
case E1000_DEV_ID_DH89XXCC_SERDES:
+ case E1000_DEV_ID_DH89XXCC_BACKPLANE:
+ case E1000_DEV_ID_DH89XXCC_SFP:
mac->type = e1000_82580;
break;
case E1000_DEV_ID_I350_COPPER:
@@ -1478,6 +1480,39 @@ out:
}
/**
+ * igb_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ * @pf: Physical Function pool - do not set anti-spoofing for the PF
+ *
+ * enables/disables L2 switch anti-spoofing functionality.
+ **/
+void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
+{
+ u32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ case e1000_i350:
+ dtxswc = rd32(E1000_DTXSWC);
+ if (enable) {
+ dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ /* The PF can spoof - it has to in order to
+ * support emulation mode NICs */
+ dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+ } else {
+ dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+ E1000_DTXSWC_VLAN_SPOOF_MASK);
+ }
+ wr32(E1000_DTXSWC, dtxswc);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
* igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
* @hw: pointer to the hardware struct
* @enable: state to enter, either enabled or disabled
@@ -1578,7 +1613,7 @@ static s32 igb_reset_mdicnfg_82580(struct e1000_hw *hw)
{
s32 ret_val = 0;
u32 mdicnfg;
- u16 nvm_data;
+ u16 nvm_data = 0;
if (hw->mac.type != e1000_82580)
goto out;
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index cbd1e1259e4d..1d01af2472e7 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -194,6 +194,10 @@ struct e1000_adv_tx_context_desc {
#define E1000_NVM_APME_82575 0x0400
#define MAX_NUM_VFS 8
+#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */
/* Easy defines for setting default pool, would normally be left a zero */
@@ -243,6 +247,7 @@ struct e1000_adv_tx_context_desc {
/* RX packet buffer size defines */
#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F
+void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *, bool, int);
void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
u16 igb_rxpbs_adjust_82580(u32 data);
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 62222796a8b3..6319ed902bc0 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -419,6 +419,9 @@
#define E1000_ERR_SWFW_SYNC 13
#define E1000_NOT_IMPLEMENTED 14
#define E1000_ERR_MBX 15
+#define E1000_ERR_INVALID_ARGUMENT 16
+#define E1000_ERR_NO_SPACE 17
+#define E1000_ERR_NVM_PBA_SECTION 18
/* Loop limit on how long we wait for auto-negotiation to complete */
#define COPPER_LINK_UP_LIMIT 10
@@ -580,11 +583,15 @@
/* Mask bits for fields in Word 0x1a of the NVM */
+/* length of string needed to store part num */
+#define E1000_PBANUM_LENGTH 11
+
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
#define NVM_SUM 0xBABA
#define NVM_PBA_OFFSET_0 8
#define NVM_PBA_OFFSET_1 9
+#define NVM_PBA_PTR_GUARD 0xFAFA
#define NVM_WORD_SIZE_BASE_SHIFT 6
/* NVM Commands - Microwire */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index c0b017f8d782..e2638afb8cdc 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -54,8 +54,10 @@ struct e1000_hw;
#define E1000_DEV_ID_82580_SERDES 0x1510
#define E1000_DEV_ID_82580_SGMII 0x1511
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
-#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436
-#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438
+#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
+#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
+#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
+#define E1000_DEV_ID_DH89XXCC_SFP 0x0440
#define E1000_DEV_ID_I350_COPPER 0x1521
#define E1000_DEV_ID_I350_FIBER 0x1522
#define E1000_DEV_ID_I350_SERDES 0x1523
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c
index d83b77fa4038..6b5cc2cc453d 100644
--- a/drivers/net/igb/e1000_nvm.c
+++ b/drivers/net/igb/e1000_nvm.c
@@ -445,31 +445,112 @@ out:
}
/**
- * igb_read_part_num - Read device part number
+ * igb_read_part_string - Read device part number
* @hw: pointer to the HW structure
* @part_num: pointer to device part number
+ * @part_num_size: size of part number buffer
*
* Reads the product board assembly (PBA) number from the EEPROM and stores
* the value in part_num.
**/
-s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num)
+s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num, u32 part_num_size)
{
- s32 ret_val;
+ s32 ret_val;
u16 nvm_data;
+ u16 pointer;
+ u16 offset;
+ u16 length;
+
+ if (part_num == NULL) {
+ hw_dbg("PBA string buffer was null\n");
+ ret_val = E1000_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
if (ret_val) {
hw_dbg("NVM Read Error\n");
goto out;
}
- *part_num = (u32)(nvm_data << 16);
- ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pointer);
+ if (ret_val) {
+ hw_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ /*
+ * if nvm_data is not ptr guard the PBA must be in legacy format which
+ * means pointer is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (nvm_data != NVM_PBA_PTR_GUARD) {
+ hw_dbg("NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (part_num_size < 11) {
+ hw_dbg("PBA string buffer too small\n");
+ return E1000_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pointer */
+ part_num[0] = (nvm_data >> 12) & 0xF;
+ part_num[1] = (nvm_data >> 8) & 0xF;
+ part_num[2] = (nvm_data >> 4) & 0xF;
+ part_num[3] = nvm_data & 0xF;
+ part_num[4] = (pointer >> 12) & 0xF;
+ part_num[5] = (pointer >> 8) & 0xF;
+ part_num[6] = '-';
+ part_num[7] = 0;
+ part_num[8] = (pointer >> 4) & 0xF;
+ part_num[9] = pointer & 0xF;
+
+ /* put a null character on the end of our string */
+ part_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (part_num[offset] < 0xA)
+ part_num[offset] += '0';
+ else if (part_num[offset] < 0x10)
+ part_num[offset] += 'A' - 0xA;
+ }
+
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.read(hw, pointer, 1, &length);
if (ret_val) {
hw_dbg("NVM Read Error\n");
goto out;
}
- *part_num |= nvm_data;
+
+ if (length == 0xFFFF || length == 0) {
+ hw_dbg("NVM PBA number section invalid length\n");
+ ret_val = E1000_ERR_NVM_PBA_SECTION;
+ goto out;
+ }
+ /* check if part_num buffer is big enough */
+ if (part_num_size < (((u32)length * 2) - 1)) {
+ hw_dbg("PBA string buffer too small\n");
+ ret_val = E1000_ERR_NO_SPACE;
+ goto out;
+ }
+
+ /* trim pba length from start of string */
+ pointer++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = hw->nvm.ops.read(hw, pointer + offset, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg("NVM Read Error\n");
+ goto out;
+ }
+ part_num[offset * 2] = (u8)(nvm_data >> 8);
+ part_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
+ }
+ part_num[offset * 2] = '\0';
out:
return ret_val;
diff --git a/drivers/net/igb/e1000_nvm.h b/drivers/net/igb/e1000_nvm.h
index 1041c34dcbe1..29c956a84bd0 100644
--- a/drivers/net/igb/e1000_nvm.h
+++ b/drivers/net/igb/e1000_nvm.h
@@ -32,6 +32,8 @@ s32 igb_acquire_nvm(struct e1000_hw *hw);
void igb_release_nvm(struct e1000_hw *hw);
s32 igb_read_mac_addr(struct e1000_hw *hw);
s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num);
+s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num,
+ u32 part_num_size);
s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
s32 igb_validate_nvm_checksum(struct e1000_hw *hw);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index ddd036a78999..6694bf3e5ad9 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -1757,11 +1757,12 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
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};
+ static const 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++) {
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index abb7333a1fbf..8ac83c5190d5 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -301,6 +301,7 @@
#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index edab9c442399..92a4ef09e55c 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -324,6 +324,7 @@ struct igb_adapter {
unsigned int vfs_allocated_count;
struct vf_data_storage *vf_data;
u32 rss_queues;
+ u32 wvbr;
};
#define IGB_FLAG_HAS_MSI (1 << 0)
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 892d196f17ac..58c665b7513d 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -73,6 +73,8 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },
@@ -1654,7 +1656,7 @@ void igb_reset(struct igb_adapter *adapter)
if (adapter->vfs_allocated_count) {
int i;
for (i = 0 ; i < adapter->vfs_allocated_count; i++)
- adapter->vf_data[i].flags = 0;
+ adapter->vf_data[i].flags &= IGB_VF_FLAG_PF_SET_MAC;
/* ping all the active vfs to let them know we are going down */
igb_ping_all_vfs(adapter);
@@ -1729,12 +1731,13 @@ static int __devinit igb_probe(struct pci_dev *pdev,
struct igb_adapter *adapter;
struct e1000_hw *hw;
u16 eeprom_data = 0;
+ s32 ret_val;
static int global_quad_port_a; /* global quad port a indication */
const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
unsigned long mmio_start, mmio_len;
int err, pci_using_dac;
u16 eeprom_apme_mask = IGB_EEPROM_APME;
- u32 part_num;
+ u8 part_str[E1000_PBANUM_LENGTH];
/* Catch broken hardware that put the wrong VF device ID in
* the PCIe SR-IOV capability.
@@ -2000,10 +2003,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
"unknown"),
netdev->dev_addr);
- igb_read_part_num(hw, &part_num);
- dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name,
- (part_num >> 8), (part_num & 0xff));
-
+ ret_val = igb_read_part_string(hw, part_str, E1000_PBANUM_LENGTH);
+ if (ret_val)
+ strcpy(part_str, "Unknown");
+ dev_info(&pdev->dev, "%s: PBA No: %s\n", netdev->name, part_str);
dev_info(&pdev->dev,
"Using %s interrupts. %d rx queue(s), %d tx queue(s)\n",
adapter->msix_entries ? "MSI-X" :
@@ -2049,13 +2052,16 @@ static void __devexit igb_remove(struct pci_dev *pdev)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- /* flush_scheduled work may reschedule our watchdog task, so
- * explicitly disable watchdog tasks from being rescheduled */
+ /*
+ * The watchdog timer may be rescheduled, so explicitly
+ * disable watchdog from being rescheduled.
+ */
set_bit(__IGB_DOWN, &adapter->state);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
- flush_scheduled_work();
+ cancel_work_sync(&adapter->reset_task);
+ cancel_work_sync(&adapter->watchdog_task);
#ifdef CONFIG_IGB_DCA
if (adapter->flags & IGB_FLAG_DCA_ENABLED) {
@@ -2436,10 +2442,9 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
int size;
size = sizeof(struct igb_buffer) * tx_ring->count;
- tx_ring->buffer_info = vmalloc(size);
+ tx_ring->buffer_info = vzalloc(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(union e1000_adv_tx_desc);
@@ -2587,10 +2592,9 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
int size, desc_len;
size = sizeof(struct igb_buffer) * rx_ring->count;
- rx_ring->buffer_info = vmalloc(size);
+ rx_ring->buffer_info = vzalloc(size);
if (!rx_ring->buffer_info)
goto err;
- memset(rx_ring->buffer_info, 0, size);
desc_len = sizeof(union e1000_adv_rx_desc);
@@ -3362,6 +3366,45 @@ static void igb_set_rx_mode(struct net_device *netdev)
igb_restore_vf_multicasts(adapter);
}
+static void igb_check_wvbr(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 wvbr = 0;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ case e1000_i350:
+ if (!(wvbr = rd32(E1000_WVBR)))
+ return;
+ break;
+ default:
+ break;
+ }
+
+ adapter->wvbr |= wvbr;
+}
+
+#define IGB_STAGGERED_QUEUE_OFFSET 8
+
+static void igb_spoof_check(struct igb_adapter *adapter)
+{
+ int j;
+
+ if (!adapter->wvbr)
+ return;
+
+ for(j = 0; j < adapter->vfs_allocated_count; j++) {
+ if (adapter->wvbr & (1 << j) ||
+ adapter->wvbr & (1 << (j + IGB_STAGGERED_QUEUE_OFFSET))) {
+ dev_warn(&adapter->pdev->dev,
+ "Spoof event(s) detected on VF %d\n", j);
+ adapter->wvbr &=
+ ~((1 << j) |
+ (1 << (j + IGB_STAGGERED_QUEUE_OFFSET)));
+ }
+ }
+}
+
/* Need to wait a few seconds after link up to get diagnostic information from
* the phy */
static void igb_update_phy_info(unsigned long data)
@@ -3521,6 +3564,8 @@ static void igb_watchdog_task(struct work_struct *work)
wr32(E1000_ICS, E1000_ICS_RXDMT0);
}
+ igb_spoof_check(adapter);
+
/* Reset the timer */
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer,
@@ -4517,6 +4562,10 @@ static irqreturn_t igb_msix_other(int irq, void *data)
if (icr & E1000_ICR_DOUTSYNC) {
/* HW is reporting DMA is out of sync */
adapter->stats.doosync++;
+ /* The DMA Out of Sync is also indication of a spoof event
+ * in IOV mode. Check the Wrong VM Behavior register to
+ * see if it is really a spoof event. */
+ igb_check_wvbr(adapter);
}
/* Check for a mailbox event */
@@ -4969,8 +5018,8 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
{
- /* clear flags */
- adapter->vf_data[vf].flags &= ~(IGB_VF_FLAG_PF_SET_MAC);
+ /* clear flags - except flag that indicates PF has set the MAC */
+ adapter->vf_data[vf].flags &= IGB_VF_FLAG_PF_SET_MAC;
adapter->vf_data[vf].last_nack = jiffies;
/* reset offloads to defaults */
@@ -5024,7 +5073,7 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
reg = rd32(E1000_VFRE);
wr32(E1000_VFRE, reg | (1 << vf));
- adapter->vf_data[vf].flags = IGB_VF_FLAG_CTS;
+ adapter->vf_data[vf].flags |= IGB_VF_FLAG_CTS;
/* reply to reset with ack and vf mac address */
msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
@@ -5103,7 +5152,14 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
switch ((msgbuf[0] & 0xFFFF)) {
case E1000_VF_SET_MAC_ADDR:
- retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
+ retval = -EINVAL;
+ if (!(vf_data->flags & IGB_VF_FLAG_PF_SET_MAC))
+ retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
+ else
+ dev_warn(&pdev->dev,
+ "VF %d attempted to override administratively "
+ "set MAC address\nReload the VF driver to "
+ "resume operations\n", vf);
break;
case E1000_VF_SET_PROMISC:
retval = igb_set_vf_promisc(adapter, msgbuf, vf);
@@ -5115,8 +5171,12 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
break;
case E1000_VF_SET_VLAN:
- if (adapter->vf_data[vf].pf_vlan)
- retval = -1;
+ retval = -1;
+ if (vf_data->pf_vlan)
+ dev_warn(&pdev->dev,
+ "VF %d attempted to override administratively "
+ "set VLAN tag\nReload the VF driver to "
+ "resume operations\n", vf);
else
retval = igb_set_vf_vlan(adapter, msgbuf, vf);
break;
@@ -6580,6 +6640,8 @@ static void igb_vmm_control(struct igb_adapter *adapter)
if (adapter->vfs_allocated_count) {
igb_vmdq_set_loopback_pf(hw, true);
igb_vmdq_set_replication_pf(hw, true);
+ igb_vmdq_set_anti_spoofing_pf(hw, true,
+ adapter->vfs_allocated_count);
} else {
igb_vmdq_set_loopback_pf(hw, false);
igb_vmdq_set_replication_pf(hw, false);
diff --git a/drivers/net/igbvf/Makefile b/drivers/net/igbvf/Makefile
index c2f150d8f2d9..0fa3db3dd8b6 100644
--- a/drivers/net/igbvf/Makefile
+++ b/drivers/net/igbvf/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel(R) 82576 Virtual Function Linux driver
-# Copyright(c) 2009 Intel Corporation.
+# Copyright(c) 2009 - 2010 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,
diff --git a/drivers/net/igbvf/defines.h b/drivers/net/igbvf/defines.h
index 88a47537518a..79f2604673fe 100644
--- a/drivers/net/igbvf/defines.h
+++ b/drivers/net/igbvf/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 33add708bcbe..ed6e3d910247 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
@@ -110,11 +110,6 @@ static int igbvf_get_settings(struct net_device *netdev,
return 0;
}
-static u32 igbvf_get_link(struct net_device *netdev)
-{
- return netif_carrier_ok(netdev);
-}
-
static int igbvf_set_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
@@ -515,7 +510,7 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
.get_msglevel = igbvf_get_msglevel,
.set_msglevel = igbvf_set_msglevel,
.nway_reset = igbvf_nway_reset,
- .get_link = igbvf_get_link,
+ .get_link = ethtool_op_get_link,
.get_eeprom_len = igbvf_get_eeprom_len,
.get_eeprom = igbvf_get_eeprom,
.set_eeprom = igbvf_set_eeprom,
diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h
index debeee2dc717..990c329e6c3b 100644
--- a/drivers/net/igbvf/igbvf.h
+++ b/drivers/net/igbvf/igbvf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
@@ -97,6 +97,7 @@ struct igbvf_adapter;
enum igbvf_boards {
board_vf,
+ board_i350_vf,
};
struct igbvf_queue_stats {
@@ -126,7 +127,6 @@ struct igbvf_buffer {
unsigned int page_offset;
};
};
- struct page *page;
};
union igbvf_desc {
diff --git a/drivers/net/igbvf/mbx.c b/drivers/net/igbvf/mbx.c
index 819a8ec901dc..3d6f4cc3998a 100644
--- a/drivers/net/igbvf/mbx.c
+++ b/drivers/net/igbvf/mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
diff --git a/drivers/net/igbvf/mbx.h b/drivers/net/igbvf/mbx.h
index 4938609dbfb5..c2883c45d477 100644
--- a/drivers/net/igbvf/mbx.h
+++ b/drivers/net/igbvf/mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 28af019c97bb..6352c8158e6d 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
@@ -44,12 +44,13 @@
#include "igbvf.h"
-#define DRV_VERSION "1.0.0-k0"
+#define DRV_VERSION "1.0.8-k0"
char igbvf_driver_name[] = "igbvf";
const char igbvf_driver_version[] = DRV_VERSION;
static const char igbvf_driver_string[] =
"Intel(R) Virtual Function Network Driver";
-static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
+static const char igbvf_copyright[] =
+ "Copyright (c) 2009 - 2010 Intel Corporation.";
static int igbvf_poll(struct napi_struct *napi, int budget);
static void igbvf_reset(struct igbvf_adapter *);
@@ -63,8 +64,16 @@ static struct igbvf_info igbvf_vf_info = {
.init_ops = e1000_init_function_pointers_vf,
};
+static struct igbvf_info igbvf_i350_vf_info = {
+ .mac = e1000_vfadapt_i350,
+ .flags = 0,
+ .pba = 10,
+ .init_ops = e1000_init_function_pointers_vf,
+};
+
static const struct igbvf_info *igbvf_info_tbl[] = {
[board_vf] = &igbvf_vf_info,
+ [board_i350_vf] = &igbvf_i350_vf_info,
};
/**
@@ -429,10 +438,9 @@ int igbvf_setup_tx_resources(struct igbvf_adapter *adapter,
int size;
size = sizeof(struct igbvf_buffer) * tx_ring->count;
- tx_ring->buffer_info = vmalloc(size);
+ tx_ring->buffer_info = vzalloc(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(union e1000_adv_tx_desc);
@@ -469,10 +477,9 @@ int igbvf_setup_rx_resources(struct igbvf_adapter *adapter,
int size, desc_len;
size = sizeof(struct igbvf_buffer) * rx_ring->count;
- rx_ring->buffer_info = vmalloc(size);
+ rx_ring->buffer_info = vzalloc(size);
if (!rx_ring->buffer_info)
goto err;
- memset(rx_ring->buffer_info, 0, size);
desc_len = sizeof(union e1000_adv_rx_desc);
@@ -1851,8 +1858,6 @@ static void igbvf_watchdog_task(struct work_struct *work)
if (link) {
if (!netif_carrier_ok(netdev)) {
- bool txb2b = 1;
-
mac->ops.get_link_up_info(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -1862,11 +1867,9 @@ static void igbvf_watchdog_task(struct work_struct *work)
adapter->tx_timeout_factor = 1;
switch (adapter->link_speed) {
case SPEED_10:
- txb2b = 0;
adapter->tx_timeout_factor = 16;
break;
case SPEED_100:
- txb2b = 0;
/* maybe add some timeout factor ? */
break;
}
@@ -2830,13 +2833,14 @@ static void __devexit igbvf_remove(struct pci_dev *pdev)
struct e1000_hw *hw = &adapter->hw;
/*
- * flush_scheduled work may reschedule our watchdog task, so
- * explicitly disable watchdog tasks from being rescheduled
+ * The watchdog timer may be rescheduled, so explicitly
+ * disable it from being rescheduled.
*/
set_bit(__IGBVF_DOWN, &adapter->state);
del_timer_sync(&adapter->watchdog_timer);
- flush_scheduled_work();
+ cancel_work_sync(&adapter->reset_task);
+ cancel_work_sync(&adapter->watchdog_task);
unregister_netdev(netdev);
@@ -2869,6 +2873,7 @@ static struct pci_error_handlers igbvf_err_handler = {
static DEFINE_PCI_DEVICE_TABLE(igbvf_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), board_vf },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_VF), board_i350_vf },
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, igbvf_pci_tbl);
diff --git a/drivers/net/igbvf/regs.h b/drivers/net/igbvf/regs.h
index b9e24ed70d0a..77e18d3d6b15 100644
--- a/drivers/net/igbvf/regs.h
+++ b/drivers/net/igbvf/regs.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
diff --git a/drivers/net/igbvf/vf.c b/drivers/net/igbvf/vf.c
index a9a61efa964c..74486a8b009a 100644
--- a/drivers/net/igbvf/vf.c
+++ b/drivers/net/igbvf/vf.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
@@ -362,8 +362,8 @@ static s32 e1000_check_for_link_vf(struct e1000_hw *hw)
* or a virtual function reset
*/
- /* If we were hit with a reset drop the link */
- if (!mbx->ops.check_for_rst(hw))
+ /* If we were hit with a reset or timeout drop the link */
+ if (!mbx->ops.check_for_rst(hw) || !mbx->timeout)
mac->get_link_status = true;
if (!mac->get_link_status)
diff --git a/drivers/net/igbvf/vf.h b/drivers/net/igbvf/vf.h
index 1e8ce3741a67..d7ed58fcd9bb 100644
--- a/drivers/net/igbvf/vf.h
+++ b/drivers/net/igbvf/vf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) 82576 Virtual Function Linux driver
- Copyright(c) 2009 Intel Corporation.
+ Copyright(c) 2009 - 2010 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,
@@ -39,6 +39,7 @@
struct e1000_hw;
#define E1000_DEV_ID_82576_VF 0x10CA
+#define E1000_DEV_ID_I350_VF 0x1520
#define E1000_REVISION_0 0
#define E1000_REVISION_1 1
#define E1000_REVISION_2 2
@@ -133,6 +134,7 @@ struct e1000_adv_tx_context_desc {
enum e1000_mac_type {
e1000_undefined = 0,
e1000_vfadapt,
+ e1000_vfadapt_i350,
e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
};
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index dc0198092343..aa93655c3aa7 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -88,16 +88,14 @@ 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 IP1000A"
};
static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
{ PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
{ PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
- { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
- { PCI_VDEVICE(DLINK, 0x9021), 3 },
- { PCI_VDEVICE(DLINK, 0x4020), 4 },
+ { PCI_VDEVICE(DLINK, 0x9021), 2 },
+ { PCI_VDEVICE(DLINK, 0x4020), 3 },
{ 0, }
};
diff --git a/drivers/net/irda/act200l-sir.c b/drivers/net/irda/act200l-sir.c
index 37ab8c855719..8ff084f1d236 100644
--- a/drivers/net/irda/act200l-sir.c
+++ b/drivers/net/irda/act200l-sir.c
@@ -199,7 +199,7 @@ static int act200l_reset(struct sir_dev *dev)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
- u8 control[9] = {
+ static const u8 control[9] = {
ACT200L_REG15,
ACT200L_REG13 | ACT200L_SHDW,
ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h
index b54a6f08db45..e3b285a67734 100644
--- a/drivers/net/irda/bfin_sir.h
+++ b/drivers/net/irda/bfin_sir.h
@@ -26,6 +26,8 @@
#include <asm/cacheflush.h>
#include <asm/dma.h>
#include <asm/portmux.h>
+#include <mach/bfin_serial_5xx.h>
+#undef DRIVER_NAME
#ifdef CONFIG_SIR_BFIN_DMA
struct dma_rx_buf {
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index b626cccbccd1..f81d944fc360 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -818,9 +818,9 @@ toshoboe_probe (struct toshoboe_cb *self)
{
int i, j, n;
#ifdef USE_MIR
- int bauds[] = { 9600, 115200, 4000000, 1152000 };
+ static const int bauds[] = { 9600, 115200, 4000000, 1152000 };
#else
- int bauds[] = { 9600, 115200, 4000000 };
+ static const int bauds[] = { 9600, 115200, 4000000 };
#endif
unsigned long flags;
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 4dc39e5f0156..77fcf4459161 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -30,7 +30,7 @@
* or the type-DO IR port.
*
* IrDA chip set list from Toshiba Computer Engineering Corp.
- * model method maker controler Version
+ * model method maker controller Version
* Portege 320CT FIR,SIR Toshiba Oboe(Triangle)
* Portege 3010CT FIR,SIR Toshiba Oboe(Sydney)
* Portege 3015CT FIR,SIR Toshiba Oboe(Sydney)
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 74b20f179cea..cc821de2c966 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -959,7 +959,7 @@ static void mcs_disconnect(struct usb_interface *intf)
if (!mcs)
return;
- flush_scheduled_work();
+ cancel_work_sync(&mcs->work);
unregister_netdev(mcs->netdev);
free_netdev(mcs->netdev);
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 00b38bccd6d0..52a7c86af663 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -258,7 +258,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
/* Baud Rate Error Correction x 10000 */
u32 rate_err_array[] = {
- 0000, 0625, 1250, 1875,
+ 0, 625, 1250, 1875,
2500, 3125, 3750, 4375,
5000, 5625, 6250, 6875,
7500, 8125, 8750, 9375,
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 8c57bfb5f098..1c1677cfea29 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -376,7 +376,7 @@ MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
static int pnp_driver_registered;
#ifdef CONFIG_PNP
-static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev,
+static int __devinit smsc_ircc_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
unsigned int firbase, sirbase;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 8df645e78f2e..9ece1fd9889d 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -885,17 +885,8 @@ static void veth_stop_connection(struct veth_lpar_connection *cnx)
veth_kick_statemachine(cnx);
spin_unlock_irq(&cnx->lock);
- /* There's a slim chance the reset code has just queued the
- * statemachine to run in five seconds. If so we need to cancel
- * that and requeue the work to run now. */
- if (cancel_delayed_work(&cnx->statemachine_wq)) {
- spin_lock_irq(&cnx->lock);
- veth_kick_statemachine(cnx);
- spin_unlock_irq(&cnx->lock);
- }
-
- /* Wait for the state machine to run. */
- flush_scheduled_work();
+ /* ensure the statemachine runs now and waits for its completion */
+ flush_delayed_work_sync(&cnx->statemachine_wq);
}
static void veth_destroy_connection(struct veth_lpar_connection *cnx)
@@ -1009,15 +1000,10 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return 0;
}
-static u32 veth_get_link(struct net_device *dev)
-{
- return 1;
-}
-
static const struct ethtool_ops ops = {
.get_drvinfo = veth_get_drvinfo,
.get_settings = veth_get_settings,
- .get_link = veth_get_link,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops veth_netdev_ops = {
@@ -1605,7 +1591,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
}
veth_dev[i] = dev;
- port = (struct veth_port*)netdev_priv(dev);
+ port = netdev_priv(dev);
/* Start the state machine on each connection on this vlan. If we're
* the first dev to do so this will commence link negotiation */
@@ -1658,15 +1644,14 @@ static void __exit veth_module_cleanup(void)
/* Disconnect our "irq" to stop events coming from the Hypervisor. */
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
- /* Make sure any work queued from Hypervisor callbacks is finished. */
- flush_scheduled_work();
-
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
cnx = veth_cnx[i];
if (!cnx)
continue;
+ /* Cancel work queued from Hypervisor callbacks */
+ cancel_delayed_work_sync(&cnx->statemachine_wq);
/* Remove the connection from sysfs */
kobject_del(&cnx->kobject);
/* Drop the driver's reference to the connection */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index caa8192fff2a..5639cccb4935 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -98,6 +98,8 @@ static void ixgb_alloc_rx_buffers(struct ixgb_adapter *, int);
static void ixgb_tx_timeout(struct net_device *dev);
static void ixgb_tx_timeout_task(struct work_struct *work);
+static void ixgb_vlan_strip_enable(struct ixgb_adapter *adapter);
+static void ixgb_vlan_strip_disable(struct ixgb_adapter *adapter);
static void ixgb_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp);
static void ixgb_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
@@ -525,7 +527,7 @@ ixgb_remove(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgb_adapter *adapter = netdev_priv(netdev);
- flush_scheduled_work();
+ cancel_work_sync(&adapter->tx_timeout_task);
unregister_netdev(netdev);
@@ -669,13 +671,12 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
int size;
size = sizeof(struct ixgb_buffer) * txdr->count;
- txdr->buffer_info = vmalloc(size);
+ txdr->buffer_info = vzalloc(size);
if (!txdr->buffer_info) {
netif_err(adapter, probe, adapter->netdev,
"Unable to allocate transmit descriptor ring memory\n");
return -ENOMEM;
}
- memset(txdr->buffer_info, 0, size);
/* round up to nearest 4K */
@@ -759,13 +760,12 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
int size;
size = sizeof(struct ixgb_buffer) * rxdr->count;
- rxdr->buffer_info = vmalloc(size);
+ rxdr->buffer_info = vzalloc(size);
if (!rxdr->buffer_info) {
netif_err(adapter, probe, adapter->netdev,
"Unable to allocate receive descriptor ring\n");
return -ENOMEM;
}
- memset(rxdr->buffer_info, 0, size);
/* Round up to nearest 4K */
@@ -1078,6 +1078,8 @@ ixgb_set_multi(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) {
rctl |= (IXGB_RCTL_UPE | IXGB_RCTL_MPE);
+ /* disable VLAN filtering */
+ rctl &= ~IXGB_RCTL_CFIEN;
rctl &= ~IXGB_RCTL_VFE;
} else {
if (netdev->flags & IFF_ALLMULTI) {
@@ -1086,7 +1088,9 @@ ixgb_set_multi(struct net_device *netdev)
} else {
rctl &= ~(IXGB_RCTL_UPE | IXGB_RCTL_MPE);
}
+ /* enable VLAN filtering */
rctl |= IXGB_RCTL_VFE;
+ rctl &= ~IXGB_RCTL_CFIEN;
}
if (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES) {
@@ -1105,6 +1109,12 @@ ixgb_set_multi(struct net_device *netdev)
ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0);
}
+
+ if (netdev->features & NETIF_F_HW_VLAN_RX)
+ ixgb_vlan_strip_enable(adapter);
+ else
+ ixgb_vlan_strip_disable(adapter);
+
}
/**
@@ -1252,7 +1262,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb)
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
struct ixgb_buffer *buffer_info;
- css = skb_transport_offset(skb);
+ css = skb_checksum_start_offset(skb);
cso = css + skb->csum_offset;
i = adapter->tx_ring.next_to_use;
@@ -2152,33 +2162,30 @@ static void
ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
- u32 ctrl, rctl;
- ixgb_irq_disable(adapter);
adapter->vlgrp = grp;
+}
- if (grp) {
- /* enable VLAN tag insert/strip */
- ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);
- ctrl |= IXGB_CTRL0_VME;
- IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);
-
- /* enable VLAN receive filtering */
+static void
+ixgb_vlan_strip_enable(struct ixgb_adapter *adapter)
+{
+ u32 ctrl;
- rctl = IXGB_READ_REG(&adapter->hw, RCTL);
- rctl &= ~IXGB_RCTL_CFIEN;
- IXGB_WRITE_REG(&adapter->hw, RCTL, rctl);
- } else {
- /* disable VLAN tag insert/strip */
+ /* enable VLAN tag insert/strip */
+ ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);
+ ctrl |= IXGB_CTRL0_VME;
+ IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);
+}
- ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);
- ctrl &= ~IXGB_CTRL0_VME;
- IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);
- }
+static void
+ixgb_vlan_strip_disable(struct ixgb_adapter *adapter)
+{
+ u32 ctrl;
- /* don't enable interrupts unless we are UP */
- if (adapter->netdev->flags & IFF_UP)
- ixgb_irq_enable(adapter);
+ /* disable VLAN tag insert/strip */
+ ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);
+ ctrl &= ~IXGB_CTRL0_VME;
+ IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);
}
static void
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index 88a08f056241..dd7fbeb1f7d1 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -191,9 +191,9 @@ struct ixgb_option {
} r;
struct { /* list_option info */
int nr;
- struct ixgb_opt_list {
+ const struct ixgb_opt_list {
int i;
- char *str;
+ const char *str;
} *p;
} l;
} arg;
@@ -226,7 +226,7 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt)
break;
case list_option: {
int i;
- struct ixgb_opt_list *ent;
+ const struct ixgb_opt_list *ent;
for (i = 0; i < opt->arg.l.nr; i++) {
ent = &opt->arg.l.p[i];
@@ -322,14 +322,15 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
{ /* Flow Control */
- struct ixgb_opt_list fc_list[] =
- {{ ixgb_fc_none, "Flow Control Disabled" },
- { ixgb_fc_rx_pause,"Flow Control Receive Only" },
- { ixgb_fc_tx_pause,"Flow Control Transmit Only" },
- { ixgb_fc_full, "Flow Control Enabled" },
- { ixgb_fc_default, "Flow Control Hardware Default" }};
+ static const struct ixgb_opt_list fc_list[] = {
+ { ixgb_fc_none, "Flow Control Disabled" },
+ { ixgb_fc_rx_pause, "Flow Control Receive Only" },
+ { ixgb_fc_tx_pause, "Flow Control Transmit Only" },
+ { ixgb_fc_full, "Flow Control Enabled" },
+ { ixgb_fc_default, "Flow Control Hardware Default" }
+ };
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
index 8f81efb49169..7d7387fbdecd 100644
--- a/drivers/net/ixgbe/Makefile
+++ b/drivers/net/ixgbe/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
- ixgbe_mbx.o
+ ixgbe_mbx.o ixgbe_x540.o
ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
ixgbe_dcb_82599.o ixgbe_dcb_nl.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index ed8703cfffb7..3b8c92463617 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -61,10 +61,8 @@
#define IXGBE_MIN_RXD 64
/* flow control */
-#define IXGBE_DEFAULT_FCRTL 0x10000
#define IXGBE_MIN_FCRTL 0x40
#define IXGBE_MAX_FCRTL 0x7FF80
-#define IXGBE_DEFAULT_FCRTH 0x20000
#define IXGBE_MIN_FCRTH 0x600
#define IXGBE_MAX_FCRTH 0x7FFF0
#define IXGBE_DEFAULT_FCPAUSE 0xFFFF
@@ -130,7 +128,9 @@ struct ixgbe_tx_buffer {
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
- u16 mapped_as_page;
+ unsigned int bytecount;
+ u16 gso_segs;
+ u8 mapped_as_page;
};
struct ixgbe_rx_buffer {
@@ -146,12 +146,56 @@ struct ixgbe_queue_stats {
u64 bytes;
};
+struct ixgbe_tx_queue_stats {
+ u64 restart_queue;
+ u64 tx_busy;
+ u64 completed;
+ u64 tx_done_old;
+};
+
+struct ixgbe_rx_queue_stats {
+ u64 rsc_count;
+ u64 rsc_flush;
+ u64 non_eop_descs;
+ u64 alloc_rx_page_failed;
+ u64 alloc_rx_buff_failed;
+};
+
+enum ixbge_ring_state_t {
+ __IXGBE_TX_FDIR_INIT_DONE,
+ __IXGBE_TX_DETECT_HANG,
+ __IXGBE_HANG_CHECK_ARMED,
+ __IXGBE_RX_PS_ENABLED,
+ __IXGBE_RX_RSC_ENABLED,
+};
+
+#define ring_is_ps_enabled(ring) \
+ test_bit(__IXGBE_RX_PS_ENABLED, &(ring)->state)
+#define set_ring_ps_enabled(ring) \
+ set_bit(__IXGBE_RX_PS_ENABLED, &(ring)->state)
+#define clear_ring_ps_enabled(ring) \
+ clear_bit(__IXGBE_RX_PS_ENABLED, &(ring)->state)
+#define check_for_tx_hang(ring) \
+ test_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+#define set_check_for_tx_hang(ring) \
+ set_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+#define clear_check_for_tx_hang(ring) \
+ clear_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+#define ring_is_rsc_enabled(ring) \
+ test_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
+#define set_ring_rsc_enabled(ring) \
+ set_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
+#define clear_ring_rsc_enabled(ring) \
+ clear_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
struct ixgbe_ring {
void *desc; /* descriptor ring memory */
+ struct device *dev; /* device for DMA mapping */
+ struct net_device *netdev; /* netdev ring belongs to */
union {
struct ixgbe_tx_buffer *tx_buffer_info;
struct ixgbe_rx_buffer *rx_buffer_info;
};
+ unsigned long state;
u8 atr_sample_rate;
u8 atr_count;
u16 count; /* amount of descriptors */
@@ -160,38 +204,30 @@ struct ixgbe_ring {
u16 next_to_clean;
u8 queue_index; /* needed for multiqueue queue management */
-
-#define IXGBE_RING_RX_PS_ENABLED (u8)(1)
- u8 flags; /* per ring feature flags */
- u16 head;
- u16 tail;
-
- unsigned int total_bytes;
- unsigned int total_packets;
-
-#ifdef CONFIG_IXGBE_DCA
- /* cpu for tx queue */
- int cpu;
-#endif
-
- u16 work_limit; /* max work per interrupt */
- u16 reg_idx; /* holds the special value that gets
+ u8 reg_idx; /* holds the special value that gets
* the hardware register offset
* associated with this ring, which is
* different for DCB and RSS modes
*/
+ u16 work_limit; /* max work per interrupt */
+
+ u8 __iomem *tail;
+
+ unsigned int total_bytes;
+ unsigned int total_packets;
+
struct ixgbe_queue_stats stats;
struct u64_stats_sync syncp;
+ union {
+ struct ixgbe_tx_queue_stats tx_stats;
+ struct ixgbe_rx_queue_stats rx_stats;
+ };
int numa_node;
- unsigned long reinit_state;
- u64 rsc_count; /* stat for coalesced packets */
- u64 rsc_flush; /* stats for flushed packets */
- u32 restart_queue; /* track tx queue restarts */
- u32 non_eop_descs; /* track hardware descriptor chaining */
-
unsigned int size; /* length in bytes */
dma_addr_t dma; /* phys. address of descriptor ring */
+ struct rcu_head rcu;
+ struct ixgbe_q_vector *q_vector; /* back-pointer to host q_vector */
} ____cacheline_internodealigned_in_smp;
enum ixgbe_ring_f_enum {
@@ -237,6 +273,9 @@ struct ixgbe_q_vector {
unsigned int v_idx; /* index of q_vector within array, also used for
* finding the bit in EICR and friends that
* represents the vector for this ring */
+#ifdef CONFIG_IXGBE_DCA
+ int cpu; /* CPU for DCA */
+#endif
struct napi_struct napi;
DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */
DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */
@@ -246,6 +285,7 @@ struct ixgbe_q_vector {
u8 rx_itr;
u32 eitr;
cpumask_var_t affinity_mask;
+ char name[IFNAMSIZ + 9];
};
/* Helper macros to switch between ints/sec and what the register uses.
@@ -294,7 +334,6 @@ struct ixgbe_adapter {
u16 bd_number;
struct work_struct reset_task;
struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
- char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
struct ixgbe_dcb_config dcb_cfg;
struct ixgbe_dcb_config temp_dcb_cfg;
u8 dcb_set_bitmap;
@@ -417,6 +456,7 @@ struct ixgbe_adapter {
int node;
struct work_struct check_overtemp_task;
u32 interrupt_event;
+ char lsc_int_name[IFNAMSIZ + 9];
/* SR-IOV */
DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
@@ -428,17 +468,25 @@ enum ixbge_state_t {
__IXGBE_TESTING,
__IXGBE_RESETTING,
__IXGBE_DOWN,
- __IXGBE_FDIR_INIT_DONE,
__IXGBE_SFP_MODULE_NOT_FOUND
};
+struct ixgbe_rsc_cb {
+ dma_addr_t dma;
+ u16 skb_cnt;
+ bool delay_unmap;
+};
+#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
+
enum ixgbe_boards {
board_82598,
board_82599,
+ board_X540,
};
extern struct ixgbe_info ixgbe_82598_info;
extern struct ixgbe_info ixgbe_82599_info;
+extern struct ixgbe_info ixgbe_X540_info;
#ifdef CONFIG_IXGBE_DCB
extern const struct dcbnl_rtnl_ops dcbnl_ops;
extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
@@ -454,50 +502,41 @@ extern void ixgbe_down(struct ixgbe_adapter *adapter);
extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
extern void ixgbe_reset(struct ixgbe_adapter *adapter);
extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
-extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
-extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
-extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
-extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern int ixgbe_setup_rx_resources(struct ixgbe_ring *);
+extern int ixgbe_setup_tx_resources(struct ixgbe_ring *);
+extern void ixgbe_free_rx_resources(struct ixgbe_ring *);
+extern void ixgbe_free_tx_resources(struct ixgbe_ring *);
extern void ixgbe_configure_rx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
extern void ixgbe_configure_tx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
+extern void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *);
extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
extern netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *,
- struct net_device *,
struct ixgbe_adapter *,
struct ixgbe_ring *);
-extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *,
+extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *,
struct ixgbe_tx_buffer *);
-extern void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring,
- int cleaned_count);
+extern void ixgbe_alloc_rx_buffers(struct ixgbe_ring *, u16);
extern void ixgbe_write_eitr(struct ixgbe_q_vector *);
extern int ethtool_ioctl(struct ifreq *ifr);
+extern u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 index);
extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw);
extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc);
extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc);
extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
- struct ixgbe_atr_input *input,
+ union ixgbe_atr_hash_dword input,
+ union ixgbe_atr_hash_dword common,
u8 queue);
extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
- struct ixgbe_atr_input *input,
+ union ixgbe_atr_input *input,
struct ixgbe_atr_input_masks *input_masks,
u16 soft_id, u8 queue);
-extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input,
- u16 vlan_id);
-extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input,
- u32 src_addr);
-extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input,
- u32 dst_addr);
-extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input,
- u16 src_port);
-extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input,
- u16 dst_port);
-extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input,
- u16 flex_byte);
-extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input,
- u8 l4type);
+extern void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring);
+extern void ixgbe_clear_rscctl(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring);
extern void ixgbe_set_rx_mode(struct net_device *netdev);
#ifdef IXGBE_FCOE
extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 9c02d6014cc4..d0f1d9d2c416 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -38,9 +38,6 @@
#define IXGBE_82598_MC_TBL_SIZE 128
#define IXGBE_82598_VFT_TBL_SIZE 128
-static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
- ixgbe_link_speed *speed,
- bool *autoneg);
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
@@ -156,7 +153,7 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw)
if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) {
mac->ops.setup_link = &ixgbe_setup_copper_link_82598;
mac->ops.get_link_capabilities =
- &ixgbe_get_copper_link_capabilities_82598;
+ &ixgbe_get_copper_link_capabilities_generic;
}
switch (hw->phy.type) {
@@ -274,37 +271,6 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw,
}
/**
- * ixgbe_get_copper_link_capabilities_82598 - Determines link capabilities
- * @hw: pointer to hardware structure
- * @speed: pointer to link speed
- * @autoneg: boolean auto-negotiation value
- *
- * Determines the link capabilities by reading the AUTOC register.
- **/
-static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
- ixgbe_link_speed *speed,
- bool *autoneg)
-{
- s32 status = IXGBE_ERR_LINK_SETUP;
- u16 speed_ability;
-
- *speed = 0;
- *autoneg = true;
-
- status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD,
- &speed_ability);
-
- if (status == 0) {
- if (speed_ability & MDIO_SPEED_10G)
- *speed |= IXGBE_LINK_SPEED_10GB_FULL;
- if (speed_ability & MDIO_PMA_SPEED_1000)
- *speed |= IXGBE_LINK_SPEED_1GB_FULL;
- }
-
- return status;
-}
-
-/**
* ixgbe_get_media_type_82598 - Determines media type
* @hw: pointer to hardware structure
*
@@ -357,6 +323,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
u32 fctrl_reg;
u32 rmcs_reg;
u32 reg;
+ u32 rx_pba_size;
u32 link_speed = 0;
bool link_up;
@@ -459,16 +426,18 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
/* Set up and enable Rx high/low water mark thresholds, enable XON. */
if (hw->fc.current_mode & 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);
- }
+ rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+ rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+
+ reg = (rx_pba_size - hw->fc.low_water) << 6;
+ if (hw->fc.send_xon)
+ reg |= IXGBE_FCRTL_XONE;
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), reg);
+
+ reg = (rx_pba_size - hw->fc.high_water) << 10;
+ reg |= IXGBE_FCRTH_FCEN;
- IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
- (hw->fc.high_water | IXGBE_FCRTH_FCEN));
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), reg);
}
/* Configure pause time (2 TCs per register) */
@@ -1222,6 +1191,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
.init_params = &ixgbe_init_eeprom_params_generic,
.read = &ixgbe_read_eerd_generic,
+ .calc_checksum = &ixgbe_calc_eeprom_checksum_generic,
.validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
.update_checksum = &ixgbe_update_eeprom_checksum_generic,
};
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 0bd8fbb5bfd0..a21f5817685b 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -56,9 +56,6 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
bool autoneg_wait_to_complete);
-static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw,
- ixgbe_link_speed *speed,
- bool *autoneg);
static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
@@ -68,9 +65,9 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
- if (hw->phy.multispeed_fiber) {
- /* Set up dual speed SFP+ support */
- mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
+
+ /* enable the laser control functions for SFP+ fiber */
+ if (mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) {
mac->ops.disable_tx_laser =
&ixgbe_disable_tx_laser_multispeed_fiber;
mac->ops.enable_tx_laser =
@@ -80,6 +77,12 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
mac->ops.disable_tx_laser = NULL;
mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL;
+ }
+
+ if (hw->phy.multispeed_fiber) {
+ /* Set up dual speed SFP+ support */
+ mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
+ } else {
if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) &&
(hw->phy.smart_speed == ixgbe_smart_speed_auto ||
@@ -93,6 +96,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
{
s32 ret_val = 0;
+ u32 reg_anlp1 = 0;
+ u32 i = 0;
u16 list_offset, data_offset, data_value;
if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
@@ -119,14 +124,34 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
IXGBE_WRITE_FLUSH(hw);
hw->eeprom.ops.read(hw, ++data_offset, &data_value);
}
- /* Now restart DSP by setting Restart_AN */
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC,
- (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART));
/* Release the semaphore */
ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
/* Delay obtaining semaphore again to allow FW access */
msleep(hw->eeprom.semaphore_delay);
+
+ /* Now restart DSP by setting Restart_AN and clearing LMS */
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw,
+ IXGBE_AUTOC) & ~IXGBE_AUTOC_LMS_MASK) |
+ IXGBE_AUTOC_AN_RESTART));
+
+ /* Wait for AN to leave state 0 */
+ for (i = 0; i < 10; i++) {
+ msleep(4);
+ reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+ if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)
+ break;
+ }
+ if (!(reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)) {
+ hw_dbg(hw, "sfp module setup not complete\n");
+ ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+ goto setup_sfp_out;
+ }
+
+ /* Restart DSP by setting Restart_AN and return to SFI mode */
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw,
+ IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL |
+ IXGBE_AUTOC_AN_RESTART));
}
setup_sfp_out:
@@ -174,7 +199,7 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) {
mac->ops.setup_link = &ixgbe_setup_copper_link_82599;
mac->ops.get_link_capabilities =
- &ixgbe_get_copper_link_capabilities_82599;
+ &ixgbe_get_copper_link_capabilities_generic;
}
/* Set necessary function pointers based on phy type */
@@ -184,6 +209,10 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
phy->ops.get_firmware_version =
&ixgbe_get_phy_firmware_version_tnx;
break;
+ case ixgbe_phy_aq:
+ phy->ops.get_firmware_version =
+ &ixgbe_get_phy_firmware_version_generic;
+ break;
default:
break;
}
@@ -290,37 +319,6 @@ out:
}
/**
- * ixgbe_get_copper_link_capabilities_82599 - Determines link capabilities
- * @hw: pointer to hardware structure
- * @speed: pointer to link speed
- * @autoneg: boolean auto-negotiation value
- *
- * Determines the link capabilities by reading the AUTOC register.
- **/
-static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw,
- ixgbe_link_speed *speed,
- bool *autoneg)
-{
- s32 status = IXGBE_ERR_LINK_SETUP;
- u16 speed_ability;
-
- *speed = 0;
- *autoneg = true;
-
- status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD,
- &speed_ability);
-
- if (status == 0) {
- if (speed_ability & MDIO_SPEED_10G)
- *speed |= IXGBE_LINK_SPEED_10GB_FULL;
- if (speed_ability & MDIO_PMA_SPEED_1000)
- *speed |= IXGBE_LINK_SPEED_1GB_FULL;
- }
-
- return status;
-}
-
-/**
* ixgbe_get_media_type_82599 - Get media type
* @hw: pointer to hardware structure
*
@@ -332,7 +330,8 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
/* Detect if there is a copper PHY attached. */
if (hw->phy.type == ixgbe_phy_cu_unknown ||
- hw->phy.type == ixgbe_phy_tn) {
+ hw->phy.type == ixgbe_phy_tn ||
+ hw->phy.type == ixgbe_phy_aq) {
media_type = ixgbe_media_type_copper;
goto out;
}
@@ -342,11 +341,13 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_82599_KX4_MEZZ:
case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
case IXGBE_DEV_ID_82599_KR:
+ case IXGBE_DEV_ID_82599_BACKPLANE_FCOE:
case IXGBE_DEV_ID_82599_XAUI_LOM:
/* Default device ID is mezzanine card KX/KX4 */
media_type = ixgbe_media_type_backplane;
break;
case IXGBE_DEV_ID_82599_SFP:
+ case IXGBE_DEV_ID_82599_SFP_FCOE:
case IXGBE_DEV_ID_82599_SFP_EM:
media_type = ixgbe_media_type_fiber;
break;
@@ -1002,7 +1003,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
udelay(10);
}
if (i >= IXGBE_FDIRCMD_CMD_POLL) {
- hw_dbg(hw ,"Flow Director previous command isn't complete, "
+ hw_dbg(hw, "Flow Director previous command isn't complete, "
"aborting table re-initialization.\n");
return IXGBE_ERR_FDIR_REINIT_FAILED;
}
@@ -1078,7 +1079,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
/*
* The defaults in the HW for RX PB 1-7 are not zero and so should be
- * intialized to zero for non DCB mode otherwise actual total RX PB
+ * initialized to zero for non DCB mode otherwise actual total RX PB
* would be bigger than programmed and filter space would run into
* the PB 0 region.
*/
@@ -1112,13 +1113,10 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
/* Move the flexible bytes to use the ethertype - shift 6 words */
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
- fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS;
/* Prime the keys for hashing */
- IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
- htonl(IXGBE_ATR_BUCKET_HASH_KEY));
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
- htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, IXGBE_ATR_SIGNATURE_HASH_KEY);
/*
* Poll init-done after we write the register. Estimated times:
@@ -1169,7 +1167,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
/*
* The defaults in the HW for RX PB 1-7 are not zero and so should be
- * intialized to zero for non DCB mode otherwise actual total RX PB
+ * initialized to zero for non DCB mode otherwise actual total RX PB
* would be bigger than programmed and filter space would run into
* the PB 0 region.
*/
@@ -1208,10 +1206,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
/* Prime the keys for hashing */
- IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
- htonl(IXGBE_ATR_BUCKET_HASH_KEY));
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
- htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, IXGBE_ATR_SIGNATURE_HASH_KEY);
/*
* Poll init-done after we write the register. Estimated times:
@@ -1250,8 +1246,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
* @stream: input bitstream to compute the hash on
* @key: 32-bit hash key
**/
-static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input,
- u32 key)
+static u32 ixgbe_atr_compute_hash_82599(union ixgbe_atr_input *atr_input,
+ u32 key)
{
/*
* The algorithm is as follows:
@@ -1271,410 +1267,250 @@ static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input,
* To simplify for programming, the algorithm is implemented
* in software this way:
*
- * Key[31:0], Stream[335:0]
+ * key[31:0], hi_hash_dword[31:0], lo_hash_dword[31:0], hash[15:0]
*
- * tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times
- * int_key[350:0] = tmp_key[351:1]
- * int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321]
+ * for (i = 0; i < 352; i+=32)
+ * hi_hash_dword[31:0] ^= Stream[(i+31):i];
*
- * hash[15:0] = 0;
- * for (i = 0; i < 351; i++) {
- * if (int_key[i])
- * hash ^= int_stream[(i + 15):i];
+ * lo_hash_dword[15:0] ^= Stream[15:0];
+ * lo_hash_dword[15:0] ^= hi_hash_dword[31:16];
+ * lo_hash_dword[31:16] ^= hi_hash_dword[15:0];
+ *
+ * hi_hash_dword[31:0] ^= Stream[351:320];
+ *
+ * if(key[0])
+ * hash[15:0] ^= Stream[15:0];
+ *
+ * for (i = 0; i < 16; i++) {
+ * if (key[i])
+ * hash[15:0] ^= lo_hash_dword[(i+15):i];
+ * if (key[i + 16])
+ * hash[15:0] ^= hi_hash_dword[(i+15):i];
* }
+ *
*/
+ __be32 common_hash_dword = 0;
+ u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
+ u32 hash_result = 0;
+ u8 i;
- union {
- u64 fill[6];
- u32 key[11];
- u8 key_stream[44];
- } tmp_key;
+ /* record the flow_vm_vlan bits as they are a key part to the hash */
+ flow_vm_vlan = ntohl(atr_input->dword_stream[0]);
- u8 *stream = (u8 *)atr_input;
- u8 int_key[44]; /* upper-most bit unused */
- u8 hash_str[46]; /* upper-most 2 bits unused */
- u16 hash_result = 0;
- int i, j, k, h;
+ /* generate common hash dword */
+ for (i = 10; i; i -= 2)
+ common_hash_dword ^= atr_input->dword_stream[i] ^
+ atr_input->dword_stream[i - 1];
- /*
- * Initialize the fill member to prevent warnings
- * on some compilers
- */
- tmp_key.fill[0] = 0;
+ hi_hash_dword = ntohl(common_hash_dword);
- /* First load the temporary key stream */
- for (i = 0; i < 6; i++) {
- u64 fillkey = ((u64)key << 32) | key;
- tmp_key.fill[i] = fillkey;
- }
+ /* low dword is word swapped version of common */
+ lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
- /*
- * Set the interim key for the hashing. Bit 352 is unused, so we must
- * shift and compensate when building the key.
- */
+ /* apply flow ID/VM pool/VLAN ID bits to hash words */
+ hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
- int_key[0] = tmp_key.key_stream[0] >> 1;
- for (i = 1, j = 0; i < 44; i++) {
- unsigned int this_key = tmp_key.key_stream[j] << 7;
- j++;
- int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1));
- }
+ /* Process bits 0 and 16 */
+ if (key & 0x0001) hash_result ^= lo_hash_dword;
+ if (key & 0x00010000) hash_result ^= hi_hash_dword;
/*
- * Set the interim bit string for the hashing. Bits 368 and 367 are
- * unused, so shift and compensate when building the string.
+ * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
+ * delay this because bit 0 of the stream should not be processed
+ * so we do not add the vlan until after bit 0 was processed
*/
- hash_str[0] = (stream[40] & 0x7f) >> 1;
- for (i = 1, j = 40; i < 46; i++) {
- unsigned int this_str = stream[j] << 7;
- j++;
- if (j > 41)
- j = 0;
- hash_str[i] = (u8)(this_str | (stream[j] >> 1));
- }
-
- /*
- * Now compute the hash. i is the index into hash_str, j is into our
- * key stream, k is counting the number of bits, and h interates within
- * each byte.
- */
- for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) {
- for (h = 0; h < 8 && k < 351; h++, k++) {
- if (int_key[j] & (1 << h)) {
- /*
- * Key bit is set, XOR in the current 16-bit
- * string. Example of processing:
- * h = 0,
- * tmp = (hash_str[i - 2] & 0 << 16) |
- * (hash_str[i - 1] & 0xff << 8) |
- * (hash_str[i] & 0xff >> 0)
- * So tmp = hash_str[15 + k:k], since the
- * i + 2 clause rolls off the 16-bit value
- * h = 7,
- * tmp = (hash_str[i - 2] & 0x7f << 9) |
- * (hash_str[i - 1] & 0xff << 1) |
- * (hash_str[i] & 0x80 >> 7)
- */
- int tmp = (hash_str[i] >> h);
- tmp |= (hash_str[i - 1] << (8 - h));
- tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1))
- << (16 - h);
- hash_result ^= (u16)tmp;
- }
- }
- }
-
- return hash_result;
-}
-
-/**
- * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream
- * @input: input stream to modify
- * @vlan: the VLAN id to load
- **/
-s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan)
-{
- input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8;
- input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address
- * @input: input stream to modify
- * @src_addr: the IP address to load
- **/
-s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr)
-{
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24;
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] =
- (src_addr >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] =
- (src_addr >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address
- * @input: input stream to modify
- * @dst_addr: the IP address to load
- **/
-s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
-{
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24;
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] =
- (dst_addr >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] =
- (dst_addr >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_src_port_82599 - Sets the source port
- * @input: input stream to modify
- * @src_port: the source port to load
- **/
-s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port)
-{
- input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8;
- input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_dst_port_82599 - Sets the destination port
- * @input: input stream to modify
- * @dst_port: the destination port to load
- **/
-s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port)
-{
- input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8;
- input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes
- * @input: input stream to modify
- * @flex_bytes: the flexible bytes to load
- **/
-s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte)
-{
- input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8;
- input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type
- * @input: input stream to modify
- * @l4type: the layer 4 type value to load
- **/
-s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type)
-{
- input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream
- * @input: input stream to search
- * @vlan: the VLAN id to load
- **/
-static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan)
-{
- *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET];
- *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8;
+ lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
- return 0;
-}
-/**
- * ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address
- * @input: input stream to search
- * @src_addr: the IP address to load
- **/
-static s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input,
- u32 *src_addr)
-{
- *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET];
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8;
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16;
- *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24;
+ /* process the remaining 30 bits in the key 2 bits at a time */
+ for (i = 15; i; i-- ) {
+ if (key & (0x0001 << i)) hash_result ^= lo_hash_dword >> i;
+ if (key & (0x00010000 << i)) hash_result ^= hi_hash_dword >> i;
+ }
- return 0;
+ return hash_result & IXGBE_ATR_HASH_MASK;
}
-/**
- * ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address
- * @input: input stream to search
- * @dst_addr: the IP address to load
- **/
-static s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input,
- u32 *dst_addr)
-{
- *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET];
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8;
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16;
- *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24;
-
- return 0;
-}
+/*
+ * These defines allow us to quickly generate all of the necessary instructions
+ * in the function below by simply calling out IXGBE_COMPUTE_SIG_HASH_ITERATION
+ * for values 0 through 15
+ */
+#define IXGBE_ATR_COMMON_HASH_KEY \
+ (IXGBE_ATR_BUCKET_HASH_KEY & IXGBE_ATR_SIGNATURE_HASH_KEY)
+#define IXGBE_COMPUTE_SIG_HASH_ITERATION(_n) \
+do { \
+ u32 n = (_n); \
+ if (IXGBE_ATR_COMMON_HASH_KEY & (0x01 << n)) \
+ common_hash ^= lo_hash_dword >> n; \
+ else if (IXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \
+ bucket_hash ^= lo_hash_dword >> n; \
+ else if (IXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << n)) \
+ sig_hash ^= lo_hash_dword << (16 - n); \
+ if (IXGBE_ATR_COMMON_HASH_KEY & (0x01 << (n + 16))) \
+ common_hash ^= hi_hash_dword >> n; \
+ else if (IXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \
+ bucket_hash ^= hi_hash_dword >> n; \
+ else if (IXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << (n + 16))) \
+ sig_hash ^= hi_hash_dword << (16 - n); \
+} while (0);
/**
- * ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address
- * @input: input stream to search
- * @src_addr_1: the first 4 bytes of the IP address to load
- * @src_addr_2: the second 4 bytes of the IP address to load
- * @src_addr_3: the third 4 bytes of the IP address to load
- * @src_addr_4: the fourth 4 bytes of the IP address to load
- **/
-static s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input,
- u32 *src_addr_1, u32 *src_addr_2,
- u32 *src_addr_3, u32 *src_addr_4)
-{
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12];
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8;
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16;
- *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24;
-
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8];
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8;
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16;
- *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24;
-
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4];
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8;
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16;
- *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24;
-
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET];
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8;
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16;
- *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_get_src_port_82599 - Gets the source port
- * @input: input stream to modify
- * @src_port: the source port to load
+ * ixgbe_atr_compute_sig_hash_82599 - Compute the signature hash
+ * @stream: input bitstream to compute the hash on
*
- * Even though the input is given in big-endian, the FDIRPORT registers
- * expect the ports to be programmed in little-endian. Hence the need to swap
- * endianness when retrieving the data. This can be confusing since the
- * internal hash engine expects it to be big-endian.
+ * This function is almost identical to the function above but contains
+ * several optomizations such as unwinding all of the loops, letting the
+ * compiler work out all of the conditional ifs since the keys are static
+ * defines, and computing two keys at once since the hashed dword stream
+ * will be the same for both keys.
**/
-static s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input,
- u16 *src_port)
+static u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input,
+ union ixgbe_atr_hash_dword common)
{
- *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8;
- *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1];
+ u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
+ u32 sig_hash = 0, bucket_hash = 0, common_hash = 0;
- return 0;
-}
+ /* record the flow_vm_vlan bits as they are a key part to the hash */
+ flow_vm_vlan = ntohl(input.dword);
-/**
- * ixgbe_atr_get_dst_port_82599 - Gets the destination port
- * @input: input stream to modify
- * @dst_port: the destination port to load
- *
- * Even though the input is given in big-endian, the FDIRPORT registers
- * expect the ports to be programmed in little-endian. Hence the need to swap
- * endianness when retrieving the data. This can be confusing since the
- * internal hash engine expects it to be big-endian.
- **/
-static s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input,
- u16 *dst_port)
-{
- *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8;
- *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1];
+ /* generate common hash dword */
+ hi_hash_dword = ntohl(common.dword);
- return 0;
-}
+ /* low dword is word swapped version of common */
+ lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
-/**
- * ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes
- * @input: input stream to modify
- * @flex_bytes: the flexible bytes to load
- **/
-static s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input,
- u16 *flex_byte)
-{
- *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET];
- *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8;
+ /* apply flow ID/VM pool/VLAN ID bits to hash words */
+ hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
- return 0;
-}
+ /* Process bits 0 and 16 */
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(0);
-/**
- * ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type
- * @input: input stream to modify
- * @l4type: the layer 4 type value to load
- **/
-static s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input,
- u8 *l4type)
-{
- *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET];
+ /*
+ * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
+ * delay this because bit 0 of the stream should not be processed
+ * so we do not add the vlan until after bit 0 was processed
+ */
+ lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
+
+ /* Process remaining 30 bit of the key */
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(1);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(2);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(3);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(4);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(5);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(6);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(7);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(8);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(9);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(10);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(11);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(12);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(13);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(14);
+ IXGBE_COMPUTE_SIG_HASH_ITERATION(15);
+
+ /* combine common_hash result with signature and bucket hashes */
+ bucket_hash ^= common_hash;
+ bucket_hash &= IXGBE_ATR_HASH_MASK;
- return 0;
+ sig_hash ^= common_hash << 16;
+ sig_hash &= IXGBE_ATR_HASH_MASK << 16;
+
+ /* return completed signature hash */
+ return sig_hash ^ bucket_hash;
}
/**
* ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter
* @hw: pointer to hardware structure
- * @stream: input bitstream
+ * @input: unique input dword
+ * @common: compressed common input dword
* @queue: queue index to direct traffic to
**/
s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
- struct ixgbe_atr_input *input,
+ union ixgbe_atr_hash_dword input,
+ union ixgbe_atr_hash_dword common,
u8 queue)
{
u64 fdirhashcmd;
- u64 fdircmd;
- u32 fdirhash;
- u16 bucket_hash, sig_hash;
- u8 l4type;
-
- bucket_hash = ixgbe_atr_compute_hash_82599(input,
- IXGBE_ATR_BUCKET_HASH_KEY);
-
- /* bucket_hash is only 15 bits */
- bucket_hash &= IXGBE_ATR_HASH_MASK;
-
- sig_hash = ixgbe_atr_compute_hash_82599(input,
- IXGBE_ATR_SIGNATURE_HASH_KEY);
-
- /* Get the l4type in order to program FDIRCMD properly */
- /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */
- ixgbe_atr_get_l4type_82599(input, &l4type);
+ u32 fdircmd;
/*
- * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
- * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH.
+ * Get the flow_type in order to program FDIRCMD properly
+ * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6
*/
- fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
-
- fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
- IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN);
-
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
- case IXGBE_ATR_L4TYPE_TCP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
- break;
- case IXGBE_ATR_L4TYPE_UDP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
- break;
- case IXGBE_ATR_L4TYPE_SCTP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
+ switch (input.formatted.flow_type) {
+ case IXGBE_ATR_FLOW_TYPE_TCPV4:
+ case IXGBE_ATR_FLOW_TYPE_UDPV4:
+ case IXGBE_ATR_FLOW_TYPE_SCTPV4:
+ case IXGBE_ATR_FLOW_TYPE_TCPV6:
+ case IXGBE_ATR_FLOW_TYPE_UDPV6:
+ case IXGBE_ATR_FLOW_TYPE_SCTPV6:
break;
default:
- hw_dbg(hw, "Error on l4type input\n");
+ hw_dbg(hw, " Error on flow type input\n");
return IXGBE_ERR_CONFIG;
}
- if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK)
- fdircmd |= IXGBE_FDIRCMD_IPV6;
+ /* configure FDIRCMD register */
+ fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
+ IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
+ fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
+ fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
- fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT);
- fdirhashcmd = ((fdircmd << 32) | fdirhash);
+ /*
+ * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
+ * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH.
+ */
+ fdirhashcmd = (u64)fdircmd << 32;
+ fdirhashcmd |= ixgbe_atr_compute_sig_hash_82599(input, common);
IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd);
+ hw_dbg(hw, "Tx Queue=%x hash=%x\n", queue, (u32)fdirhashcmd);
+
return 0;
}
/**
+ * ixgbe_get_fdirtcpm_82599 - generate a tcp port from atr_input_masks
+ * @input_mask: mask to be bit swapped
+ *
+ * The source and destination port masks for flow director are bit swapped
+ * in that bit 15 effects bit 0, 14 effects 1, 13, 2 etc. In order to
+ * generate a correctly swapped value we need to bit swap the mask and that
+ * is what is accomplished by this function.
+ **/
+static u32 ixgbe_get_fdirtcpm_82599(struct ixgbe_atr_input_masks *input_masks)
+{
+ u32 mask = ntohs(input_masks->dst_port_mask);
+ mask <<= IXGBE_FDIRTCPM_DPORTM_SHIFT;
+ mask |= ntohs(input_masks->src_port_mask);
+ mask = ((mask & 0x55555555) << 1) | ((mask & 0xAAAAAAAA) >> 1);
+ mask = ((mask & 0x33333333) << 2) | ((mask & 0xCCCCCCCC) >> 2);
+ mask = ((mask & 0x0F0F0F0F) << 4) | ((mask & 0xF0F0F0F0) >> 4);
+ return ((mask & 0x00FF00FF) << 8) | ((mask & 0xFF00FF00) >> 8);
+}
+
+/*
+ * These two macros are meant to address the fact that we have registers
+ * that are either all or in part big-endian. As a result on big-endian
+ * systems we will end up byte swapping the value to little-endian before
+ * it is byte swapped again and written to the hardware in the original
+ * big-endian format.
+ */
+#define IXGBE_STORE_AS_BE32(_value) \
+ (((u32)(_value) >> 24) | (((u32)(_value) & 0x00FF0000) >> 8) | \
+ (((u32)(_value) & 0x0000FF00) << 8) | ((u32)(_value) << 24))
+
+#define IXGBE_WRITE_REG_BE32(a, reg, value) \
+ IXGBE_WRITE_REG((a), (reg), IXGBE_STORE_AS_BE32(ntohl(value)))
+
+#define IXGBE_STORE_AS_BE16(_value) \
+ (((u16)(_value) >> 8) | ((u16)(_value) << 8))
+
+/**
* ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
* @hw: pointer to hardware structure
* @input: input bitstream
@@ -1686,135 +1522,139 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
* hardware writes must be protected from one another.
**/
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
- struct ixgbe_atr_input *input,
+ union ixgbe_atr_input *input,
struct ixgbe_atr_input_masks *input_masks,
u16 soft_id, u8 queue)
{
- u32 fdircmd = 0;
u32 fdirhash;
- u32 src_ipv4 = 0, dst_ipv4 = 0;
- u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4;
- u16 src_port, dst_port, vlan_id, flex_bytes;
- u16 bucket_hash;
- u8 l4type;
- u8 fdirm = 0;
-
- /* Get our input values */
- ixgbe_atr_get_l4type_82599(input, &l4type);
+ u32 fdircmd;
+ u32 fdirport, fdirtcpm;
+ u32 fdirvlan;
+ /* start with VLAN, flex bytes, VM pool, and IPv6 destination masked */
+ u32 fdirm = IXGBE_FDIRM_VLANID | IXGBE_FDIRM_VLANP | IXGBE_FDIRM_FLEX |
+ IXGBE_FDIRM_POOL | IXGBE_FDIRM_DIPv6;
/*
- * Check l4type formatting, and bail out before we touch the hardware
+ * Check flow_type formatting, and bail out before we touch the hardware
* if there's a configuration issue
*/
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
- case IXGBE_ATR_L4TYPE_TCP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
- break;
- case IXGBE_ATR_L4TYPE_UDP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
- break;
- case IXGBE_ATR_L4TYPE_SCTP:
- fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
+ switch (input->formatted.flow_type) {
+ case IXGBE_ATR_FLOW_TYPE_IPV4:
+ /* use the L4 protocol mask for raw IPv4/IPv6 traffic */
+ fdirm |= IXGBE_FDIRM_L4P;
+ case IXGBE_ATR_FLOW_TYPE_SCTPV4:
+ if (input_masks->dst_port_mask || input_masks->src_port_mask) {
+ hw_dbg(hw, " Error on src/dst port mask\n");
+ return IXGBE_ERR_CONFIG;
+ }
+ case IXGBE_ATR_FLOW_TYPE_TCPV4:
+ case IXGBE_ATR_FLOW_TYPE_UDPV4:
break;
default:
- hw_dbg(hw, "Error on l4type input\n");
+ hw_dbg(hw, " Error on flow type input\n");
return IXGBE_ERR_CONFIG;
}
- bucket_hash = ixgbe_atr_compute_hash_82599(input,
- IXGBE_ATR_BUCKET_HASH_KEY);
-
- /* bucket_hash is only 15 bits */
- bucket_hash &= IXGBE_ATR_HASH_MASK;
-
- ixgbe_atr_get_vlan_id_82599(input, &vlan_id);
- ixgbe_atr_get_src_port_82599(input, &src_port);
- ixgbe_atr_get_dst_port_82599(input, &dst_port);
- ixgbe_atr_get_flex_byte_82599(input, &flex_bytes);
-
- fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
-
- /* Now figure out if we're IPv4 or IPv6 */
- if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) {
- /* IPv6 */
- ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2,
- &src_ipv6_3, &src_ipv6_4);
-
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3);
- /* The last 4 bytes is the same register as IPv4 */
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4);
-
- fdircmd |= IXGBE_FDIRCMD_IPV6;
- fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH;
- } else {
- /* IPv4 */
- ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4);
- }
-
- ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4);
-
- IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id |
- (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT)));
- IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port |
- (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
-
/*
- * Program the relevant mask registers. L4type cannot be
- * masked out in this implementation.
+ * Program the relevant mask registers. If src/dst_port or src/dst_addr
+ * are zero, then assume a full mask for that field. Also assume that
+ * a VLAN of 0 is unspecified, so mask that out as well. L4type
+ * cannot be masked out in this implementation.
*
* This also assumes IPv4 only. IPv6 masking isn't supported at this
* point in time.
*/
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);
-
- switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
- case IXGBE_ATR_L4TYPE_TCP:
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, input_masks->src_port_mask);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
- (input_masks->dst_port_mask << 16)));
+
+ /* Program FDIRM */
+ switch (ntohs(input_masks->vlan_id_mask) & 0xEFFF) {
+ case 0xEFFF:
+ /* Unmask VLAN ID - bit 0 and fall through to unmask prio */
+ fdirm &= ~IXGBE_FDIRM_VLANID;
+ case 0xE000:
+ /* Unmask VLAN prio - bit 1 */
+ fdirm &= ~IXGBE_FDIRM_VLANP;
break;
- case IXGBE_ATR_L4TYPE_UDP:
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, input_masks->src_port_mask);
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
- (input_masks->src_port_mask << 16)));
+ case 0x0FFF:
+ /* Unmask VLAN ID - bit 0 */
+ fdirm &= ~IXGBE_FDIRM_VLANID;
break;
- default:
- /* this already would have failed above */
+ case 0x0000:
+ /* do nothing, vlans already masked */
break;
+ default:
+ hw_dbg(hw, " Error on VLAN mask\n");
+ return IXGBE_ERR_CONFIG;
}
- /* Program the last mask register, FDIRM */
- if (input_masks->vlan_id_mask)
- /* Mask both VLAN and VLANP - bits 0 and 1 */
- fdirm |= 0x3;
-
- if (input_masks->data_mask)
- /* Flex bytes need masking, so mask the whole thing - bit 4 */
- fdirm |= 0x10;
+ if (input_masks->flex_mask & 0xFFFF) {
+ if ((input_masks->flex_mask & 0xFFFF) != 0xFFFF) {
+ hw_dbg(hw, " Error on flexible byte mask\n");
+ return IXGBE_ERR_CONFIG;
+ }
+ /* Unmask Flex Bytes - bit 4 */
+ fdirm &= ~IXGBE_FDIRM_FLEX;
+ }
/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
- fdirm |= 0x24;
-
IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);
- fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW;
- fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE;
- fdircmd |= IXGBE_FDIRCMD_LAST;
- fdircmd |= IXGBE_FDIRCMD_QUEUE_EN;
- fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
+ /* store the TCP/UDP port masks, bit reversed from port layout */
+ fdirtcpm = ixgbe_get_fdirtcpm_82599(input_masks);
+
+ /* write both the same so that UDP and TCP use the same mask */
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm);
+
+ /* store source and destination IP masks (big-enian) */
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M,
+ ~input_masks->src_ip_mask[0]);
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRDIP4M,
+ ~input_masks->dst_ip_mask[0]);
+
+ /* Apply masks to input data */
+ input->formatted.vlan_id &= input_masks->vlan_id_mask;
+ input->formatted.flex_bytes &= input_masks->flex_mask;
+ input->formatted.src_port &= input_masks->src_port_mask;
+ input->formatted.dst_port &= input_masks->dst_port_mask;
+ input->formatted.src_ip[0] &= input_masks->src_ip_mask[0];
+ input->formatted.dst_ip[0] &= input_masks->dst_ip_mask[0];
+
+ /* record vlan (little-endian) and flex_bytes(big-endian) */
+ fdirvlan =
+ IXGBE_STORE_AS_BE16(ntohs(input->formatted.flex_bytes));
+ fdirvlan <<= IXGBE_FDIRVLAN_FLEX_SHIFT;
+ fdirvlan |= ntohs(input->formatted.vlan_id);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, fdirvlan);
+
+ /* record source and destination port (little-endian)*/
+ fdirport = ntohs(input->formatted.dst_port);
+ fdirport <<= IXGBE_FDIRPORT_DESTINATION_SHIFT;
+ fdirport |= ntohs(input->formatted.src_port);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, fdirport);
+
+ /* record the first 32 bits of the destination address (big-endian) */
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPDA, input->formatted.dst_ip[0]);
+
+ /* record the source address (big-endian) */
+ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPSA, input->formatted.src_ip[0]);
+
+ /* configure FDIRCMD register */
+ fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
+ IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
+ fdircmd |= input->formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
+ fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
+
+ /* we only want the bucket hash so drop the upper 16 bits */
+ fdirhash = ixgbe_atr_compute_hash_82599(input,
+ IXGBE_ATR_BUCKET_HASH_KEY);
+ fdirhash |= soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT;
IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash);
IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd);
return 0;
}
+
/**
* ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register
* @hw: pointer to hardware structure
@@ -1924,6 +1764,7 @@ static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw)
hw->phy.ops.identify(hw);
if (hw->phy.type == ixgbe_phy_tn ||
+ hw->phy.type == ixgbe_phy_aq ||
hw->phy.type == ixgbe_phy_cu_unknown) {
hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD,
&ext_ability);
@@ -2125,51 +1966,6 @@ fw_version_out:
return status;
}
-/**
- * ixgbe_get_wwn_prefix_82599 - Get alternative WWNN/WWPN prefix from
- * the EEPROM
- * @hw: pointer to hardware structure
- * @wwnn_prefix: the alternative WWNN prefix
- * @wwpn_prefix: the alternative WWPN prefix
- *
- * This function will read the EEPROM from the alternative SAN MAC address
- * block to check the support for the alternative WWNN/WWPN prefix support.
- **/
-static s32 ixgbe_get_wwn_prefix_82599(struct ixgbe_hw *hw, u16 *wwnn_prefix,
- u16 *wwpn_prefix)
-{
- u16 offset, caps;
- u16 alt_san_mac_blk_offset;
-
- /* clear output first */
- *wwnn_prefix = 0xFFFF;
- *wwpn_prefix = 0xFFFF;
-
- /* check if alternative SAN MAC is supported */
- hw->eeprom.ops.read(hw, IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR,
- &alt_san_mac_blk_offset);
-
- if ((alt_san_mac_blk_offset == 0) ||
- (alt_san_mac_blk_offset == 0xFFFF))
- goto wwn_prefix_out;
-
- /* check capability in alternative san mac address block */
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET;
- hw->eeprom.ops.read(hw, offset, &caps);
- if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN))
- goto wwn_prefix_out;
-
- /* get the corresponding prefix for WWNN/WWPN */
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET;
- hw->eeprom.ops.read(hw, offset, wwnn_prefix);
-
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET;
- hw->eeprom.ops.read(hw, offset, wwpn_prefix);
-
-wwn_prefix_out:
- return 0;
-}
-
static struct ixgbe_mac_operations mac_ops_82599 = {
.init_hw = &ixgbe_init_hw_generic,
.reset_hw = &ixgbe_reset_hw_82599,
@@ -2181,7 +1977,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
.get_mac_addr = &ixgbe_get_mac_addr_generic,
.get_san_mac_addr = &ixgbe_get_san_mac_addr_generic,
.get_device_caps = &ixgbe_get_device_caps_82599,
- .get_wwn_prefix = &ixgbe_get_wwn_prefix_82599,
+ .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic,
.stop_adapter = &ixgbe_stop_adapter_generic,
.get_bus_info = &ixgbe_get_bus_info_generic,
.set_lan_id = &ixgbe_set_lan_id_multi_port_pcie,
@@ -2208,12 +2004,15 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
.fc_enable = &ixgbe_fc_enable_generic,
.init_uta_tables = &ixgbe_init_uta_tables_generic,
.setup_sfp = &ixgbe_setup_sfp_modules_82599,
+ .set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing,
+ .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing,
};
static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
.init_params = &ixgbe_init_eeprom_params_generic,
.read = &ixgbe_read_eerd_generic,
.write = &ixgbe_write_eeprom_generic,
+ .calc_checksum = &ixgbe_calc_eeprom_checksum_generic,
.validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
.update_checksum = &ixgbe_update_eeprom_checksum_generic,
};
@@ -2240,5 +2039,5 @@ struct ixgbe_info ixgbe_82599_info = {
.mac_ops = &mac_ops_82599,
.eeprom_ops = &eeprom_ops_82599,
.phy_ops = &phy_ops_82599,
- .mbx_ops = &mbx_ops_82599,
+ .mbx_ops = &mbx_ops_generic,
};
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index e3eca1316389..d5ede2df3e42 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -45,14 +45,12 @@ static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count);
static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec);
static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec);
static void ixgbe_release_eeprom(struct ixgbe_hw *hw);
-static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index);
static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
-static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
/**
* ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -198,30 +196,110 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
}
/**
- * ixgbe_read_pba_num_generic - Reads part number from EEPROM
+ * ixgbe_read_pba_string_generic - Reads part number string from EEPROM
* @hw: pointer to hardware structure
- * @pba_num: stores the part number from the EEPROM
+ * @pba_num: stores the part number string from the EEPROM
+ * @pba_num_size: part number string buffer length
*
- * Reads the part number from the EEPROM.
+ * Reads the part number string from the EEPROM.
**/
-s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num)
+s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
+ u32 pba_num_size)
{
s32 ret_val;
u16 data;
+ u16 pba_ptr;
+ u16 offset;
+ u16 length;
+
+ if (pba_num == NULL) {
+ hw_dbg(hw, "PBA string buffer was null\n");
+ return IXGBE_ERR_INVALID_ARGUMENT;
+ }
ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data);
if (ret_val) {
hw_dbg(hw, "NVM Read Error\n");
return ret_val;
}
- *pba_num = (u32)(data << 16);
- ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &data);
+ ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &pba_ptr);
if (ret_val) {
hw_dbg(hw, "NVM Read Error\n");
return ret_val;
}
- *pba_num |= data;
+
+ /*
+ * if data is not ptr guard the PBA must be in legacy format which
+ * means pba_ptr is actually our second data word for the PBA number
+ * and we can decode it into an ascii string
+ */
+ if (data != IXGBE_PBANUM_PTR_GUARD) {
+ hw_dbg(hw, "NVM PBA number is not stored as string\n");
+
+ /* we will need 11 characters to store the PBA */
+ if (pba_num_size < 11) {
+ hw_dbg(hw, "PBA string buffer too small\n");
+ return IXGBE_ERR_NO_SPACE;
+ }
+
+ /* extract hex string from data and pba_ptr */
+ pba_num[0] = (data >> 12) & 0xF;
+ pba_num[1] = (data >> 8) & 0xF;
+ pba_num[2] = (data >> 4) & 0xF;
+ pba_num[3] = data & 0xF;
+ pba_num[4] = (pba_ptr >> 12) & 0xF;
+ pba_num[5] = (pba_ptr >> 8) & 0xF;
+ pba_num[6] = '-';
+ pba_num[7] = 0;
+ pba_num[8] = (pba_ptr >> 4) & 0xF;
+ pba_num[9] = pba_ptr & 0xF;
+
+ /* put a null character on the end of our string */
+ pba_num[10] = '\0';
+
+ /* switch all the data but the '-' to hex char */
+ for (offset = 0; offset < 10; offset++) {
+ if (pba_num[offset] < 0xA)
+ pba_num[offset] += '0';
+ else if (pba_num[offset] < 0x10)
+ pba_num[offset] += 'A' - 0xA;
+ }
+
+ return 0;
+ }
+
+ ret_val = hw->eeprom.ops.read(hw, pba_ptr, &length);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (length == 0xFFFF || length == 0) {
+ hw_dbg(hw, "NVM PBA number section invalid length\n");
+ return IXGBE_ERR_PBA_SECTION;
+ }
+
+ /* check if pba_num buffer is big enough */
+ if (pba_num_size < (((u32)length * 2) - 1)) {
+ hw_dbg(hw, "PBA string buffer too small\n");
+ return IXGBE_ERR_NO_SPACE;
+ }
+
+ /* trim pba length from start of string */
+ pba_ptr++;
+ length--;
+
+ for (offset = 0; offset < length; offset++) {
+ ret_val = hw->eeprom.ops.read(hw, pba_ptr + offset, &data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ pba_num[offset * 2] = (u8)(data >> 8);
+ pba_num[(offset * 2) + 1] = (u8)(data & 0xFF);
+ }
+ pba_num[offset * 2] = '\0';
return 0;
}
@@ -638,7 +716,7 @@ out:
* Polls the status bit (bit 1) of the EERD or EEWR to determine when the
* read or write is done respectively.
**/
-static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
+s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
{
u32 i;
u32 reg;
@@ -1009,7 +1087,7 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw)
* 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 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw)
{
u16 i;
u16 j;
@@ -1072,7 +1150,7 @@ s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
status = hw->eeprom.ops.read(hw, 0, &checksum);
if (status == 0) {
- checksum = ixgbe_calc_eeprom_checksum(hw);
+ checksum = hw->eeprom.ops.calc_checksum(hw);
hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
@@ -1110,7 +1188,7 @@ s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw)
status = hw->eeprom.ops.read(hw, 0, &checksum);
if (status == 0) {
- checksum = ixgbe_calc_eeprom_checksum(hw);
+ checksum = hw->eeprom.ops.calc_checksum(hw);
status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM,
checksum);
} else {
@@ -1595,6 +1673,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
u32 mflcn_reg, fccfg_reg;
u32 reg;
u32 rx_pba_size;
+ u32 fcrtl, fcrth;
#ifdef CONFIG_DCB
if (hw->fc.requested_mode == ixgbe_fc_pfc)
@@ -1671,41 +1750,21 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg);
IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg);
- reg = IXGBE_READ_REG(hw, IXGBE_MTQC);
- /* Thresholds are different for link flow control when in DCB mode */
- if (reg & IXGBE_MTQC_RT_ENA) {
- rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+ rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+ rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
- /* Always disable XON for LFC when in DCB mode */
- reg = (rx_pba_size >> 5) & 0xFFE0;
- IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg);
+ fcrth = (rx_pba_size - hw->fc.high_water) << 10;
+ fcrtl = (rx_pba_size - hw->fc.low_water) << 10;
- reg = (rx_pba_size >> 2) & 0xFFE0;
- if (hw->fc.current_mode & ixgbe_fc_tx_pause)
- reg |= IXGBE_FCRTH_FCEN;
- IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), reg);
- } else {
- /*
- * Set up and enable Rx high/low water mark thresholds,
- * enable XON.
- */
- if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
- if (hw->fc.send_xon) {
- IXGBE_WRITE_REG(hw,
- IXGBE_FCRTL_82599(packetbuf_num),
- (hw->fc.low_water |
- IXGBE_FCRTL_XONE));
- } else {
- IXGBE_WRITE_REG(hw,
- IXGBE_FCRTL_82599(packetbuf_num),
- hw->fc.low_water);
- }
-
- IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num),
- (hw->fc.high_water | IXGBE_FCRTH_FCEN));
- }
+ if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
+ fcrth |= IXGBE_FCRTH_FCEN;
+ if (hw->fc.send_xon)
+ fcrtl |= IXGBE_FCRTL_XONE;
}
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), fcrth);
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), fcrtl);
+
/* Configure pause time (2 TCs per register) */
reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2));
if ((packetbuf_num & 1) == 0)
@@ -2705,3 +2764,112 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
return 0;
}
+
+/**
+ * ixgbe_get_wwn_prefix_generic Get alternative WWNN/WWPN prefix from
+ * the EEPROM
+ * @hw: pointer to hardware structure
+ * @wwnn_prefix: the alternative WWNN prefix
+ * @wwpn_prefix: the alternative WWPN prefix
+ *
+ * This function will read the EEPROM from the alternative SAN MAC address
+ * block to check the support for the alternative WWNN/WWPN prefix support.
+ **/
+s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
+ u16 *wwpn_prefix)
+{
+ u16 offset, caps;
+ u16 alt_san_mac_blk_offset;
+
+ /* clear output first */
+ *wwnn_prefix = 0xFFFF;
+ *wwpn_prefix = 0xFFFF;
+
+ /* check if alternative SAN MAC is supported */
+ hw->eeprom.ops.read(hw, IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR,
+ &alt_san_mac_blk_offset);
+
+ if ((alt_san_mac_blk_offset == 0) ||
+ (alt_san_mac_blk_offset == 0xFFFF))
+ goto wwn_prefix_out;
+
+ /* check capability in alternative san mac address block */
+ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET;
+ hw->eeprom.ops.read(hw, offset, &caps);
+ if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN))
+ goto wwn_prefix_out;
+
+ /* get the corresponding prefix for WWNN/WWPN */
+ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET;
+ hw->eeprom.ops.read(hw, offset, wwnn_prefix);
+
+ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET;
+ hw->eeprom.ops.read(hw, offset, wwpn_prefix);
+
+wwn_prefix_out:
+ return 0;
+}
+
+/**
+ * ixgbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing
+ * @hw: pointer to hardware structure
+ * @enable: enable or disable switch for anti-spoofing
+ * @pf: Physical Function pool - do not enable anti-spoofing for the PF
+ *
+ **/
+void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf)
+{
+ int j;
+ int pf_target_reg = pf >> 3;
+ int pf_target_shift = pf % 8;
+ u32 pfvfspoof = 0;
+
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return;
+
+ if (enable)
+ pfvfspoof = IXGBE_SPOOF_MACAS_MASK;
+
+ /*
+ * PFVFSPOOF register array is size 8 with 8 bits assigned to
+ * MAC anti-spoof enables in each register array element.
+ */
+ for (j = 0; j < IXGBE_PFVFSPOOF_REG_COUNT; j++)
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(j), pfvfspoof);
+
+ /* If not enabling anti-spoofing then done */
+ if (!enable)
+ return;
+
+ /*
+ * The PF should be allowed to spoof so that it can support
+ * emulation mode NICs. Reset the bit assigned to the PF
+ */
+ pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(pf_target_reg));
+ pfvfspoof ^= (1 << pf_target_shift);
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(pf_target_reg), pfvfspoof);
+}
+
+/**
+ * ixgbe_set_vlan_anti_spoofing - Enable/Disable VLAN anti-spoofing
+ * @hw: pointer to hardware structure
+ * @enable: enable or disable switch for VLAN anti-spoofing
+ * @pf: Virtual Function pool - VF Pool to set for VLAN anti-spoofing
+ *
+ **/
+void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf)
+{
+ int vf_target_reg = vf >> 3;
+ int vf_target_shift = vf % 8 + IXGBE_SPOOF_VLANAS_SHIFT;
+ u32 pfvfspoof;
+
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return;
+
+ pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
+ if (enable)
+ pfvfspoof |= (1 << vf_target_shift);
+ else
+ pfvfspoof &= ~(1 << vf_target_shift);
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
+}
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 424c223437dc..66ed045a8cf0 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -35,7 +35,8 @@ s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw);
s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw);
s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw);
-s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num);
+s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr);
s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw);
void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw);
@@ -49,9 +50,11 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
u16 *data);
+u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw);
s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
u16 *checksum_val);
s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
+s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
u32 enable_addr);
@@ -81,9 +84,12 @@ s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw);
s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw,
ixgbe_link_speed *speed,
bool *link_up, bool link_up_wait_to_complete);
-
+s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
+ u16 *wwpn_prefix);
s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
+void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf);
+void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf);
#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c
index 0d44c6470ca3..d16c260c1f50 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ixgbe/ixgbe_dcb.c
@@ -42,7 +42,8 @@
* It should be called only after the rules are checked by
* ixgbe_dcb_check_config().
*/
-s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config,
+s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw,
+ struct ixgbe_dcb_config *dcb_config,
int max_frame, u8 direction)
{
struct tc_bw_alloc *p;
@@ -124,7 +125,8 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config,
* credit may not be enough to send out a TSO
* packet in descriptor plane arbitration.
*/
- if (credit_max &&
+ if ((hw->mac.type == ixgbe_mac_82598EB) &&
+ credit_max &&
(credit_max < MINIMUM_CREDIT_FOR_TSO))
credit_max = MINIMUM_CREDIT_FOR_TSO;
@@ -150,10 +152,17 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
ret = ixgbe_dcb_hw_config_82598(hw, dcb_config);
- else if (hw->mac.type == ixgbe_mac_82599EB)
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
ret = ixgbe_dcb_hw_config_82599(hw, dcb_config);
+ break;
+ default:
+ break;
+ }
return ret;
}
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index 0208a87b129e..1cfe38ee1644 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -150,7 +150,8 @@ struct ixgbe_dcb_config {
/* DCB driver APIs */
/* DCB credits calculation */
-s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, int, u8);
+s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *,
+ struct ixgbe_dcb_config *, int, u8);
/* DCB hw initialization */
s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index 50288bcadc59..9a5e89c12e05 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -256,21 +256,17 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
* for each traffic class.
*/
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
- if (dcb_config->rx_pba_cfg == pba_equal) {
- rx_pba_size = IXGBE_RXPBSIZE_64KB;
- } else {
- rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB
- : IXGBE_RXPBSIZE_48KB;
- }
+ rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+ rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+ reg = (rx_pba_size - hw->fc.low_water) << 10;
- reg = ((rx_pba_size >> 5) & 0xFFF0);
if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
reg |= IXGBE_FCRTL_XONE;
IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg);
- reg = ((rx_pba_size >> 2) & 0xFFF0);
+ reg = (rx_pba_size - hw->fc.high_water) << 10;
if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
reg |= IXGBE_FCRTH_FCEN;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 05f224715073..374e1f74d0f5 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -251,19 +251,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
/* Configure PFC Tx thresholds per TC */
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
- if (dcb_config->rx_pba_cfg == pba_equal)
- rx_pba_size = IXGBE_RXPBSIZE_64KB;
- else
- rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB
- : IXGBE_RXPBSIZE_48KB;
+ rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+ rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+
+ reg = (rx_pba_size - hw->fc.low_water) << 10;
- reg = ((rx_pba_size >> 5) & 0xFFE0);
if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
reg |= IXGBE_FCRTL_XONE;
IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
- reg = ((rx_pba_size >> 2) & 0xFFE0);
+ reg = (rx_pba_size - hw->fc.high_water) << 10;
if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
reg |= IXGBE_FCRTH_FCEN;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index b53b465e24af..bf566e8a455e 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -130,15 +130,21 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
netdev->netdev_ops->ndo_stop(netdev);
ixgbe_clear_interrupt_scheme(adapter);
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
adapter->last_lfc_mode = adapter->hw.fc.current_mode;
adapter->hw.fc.requested_mode = ixgbe_fc_none;
- }
- adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+ break;
+ default:
+ break;
}
+
adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
ixgbe_init_interrupt_scheme(adapter);
if (netif_running(netdev))
@@ -155,8 +161,14 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
adapter->dcb_cfg.pfc_mode_enable = false;
adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ break;
+ default:
+ break;
+ }
ixgbe_init_interrupt_scheme(adapter);
if (netif_running(netdev))
@@ -178,9 +190,14 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev,
for (i = 0; i < netdev->addr_len; i++)
perm_addr[i] = adapter->hw.mac.perm_addr[i];
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
for (j = 0; j < netdev->addr_len; j++, i++)
perm_addr[i] = adapter->hw.mac.san_addr[j];
+ break;
+ default:
+ break;
}
}
@@ -366,15 +383,29 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
}
if (adapter->dcb_cfg.pfc_mode_enable) {
- if ((adapter->hw.mac.type != ixgbe_mac_82598EB) &&
- (adapter->hw.fc.current_mode != ixgbe_fc_pfc))
- adapter->last_lfc_mode = adapter->hw.fc.current_mode;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ if (adapter->hw.fc.current_mode != ixgbe_fc_pfc)
+ adapter->last_lfc_mode =
+ adapter->hw.fc.current_mode;
+ break;
+ default:
+ break;
+ }
adapter->hw.fc.requested_mode = ixgbe_fc_pfc;
} else {
- if (adapter->hw.mac.type != ixgbe_mac_82598EB)
- adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
- else
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
adapter->hw.fc.requested_mode = ixgbe_fc_none;
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
+ break;
+ default:
+ break;
+ }
}
if (adapter->dcb_set_bitmap & BIT_RESETLINK) {
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3dc731c22ff2..2002ea88ca2a 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -185,6 +185,16 @@ static int ixgbe_get_settings(struct net_device *netdev,
ADVERTISED_FIBRE);
ecmd->port = PORT_FIBRE;
ecmd->autoneg = AUTONEG_DISABLE;
+ } else if ((hw->device_id == IXGBE_DEV_ID_82599_COMBO_BACKPLANE) ||
+ (hw->device_id == IXGBE_DEV_ID_82599_KX4_MEZZ)) {
+ ecmd->supported |= (SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE);
+ ecmd->advertising = (ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg |
+ ADVERTISED_FIBRE);
+ ecmd->port = PORT_FIBRE;
} else {
ecmd->supported |= (SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE);
@@ -204,6 +214,7 @@ static int ixgbe_get_settings(struct net_device *netdev,
/* Get PHY type */
switch (adapter->hw.phy.type) {
case ixgbe_phy_tn:
+ case ixgbe_phy_aq:
case ixgbe_phy_cu_unknown:
/* Copper 10G-BASET */
ecmd->port = PORT_TP;
@@ -332,13 +343,6 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
else
pause->autoneg = 1;
-#ifdef CONFIG_DCB
- if (hw->fc.current_mode == ixgbe_fc_pfc) {
- pause->rx_pause = 0;
- pause->tx_pause = 0;
- }
-
-#endif
if (hw->fc.current_mode == ixgbe_fc_rx_pause) {
pause->rx_pause = 1;
} else if (hw->fc.current_mode == ixgbe_fc_tx_pause) {
@@ -346,6 +350,11 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
} else if (hw->fc.current_mode == ixgbe_fc_full) {
pause->rx_pause = 1;
pause->tx_pause = 1;
+#ifdef CONFIG_DCB
+ } else if (hw->fc.current_mode == ixgbe_fc_pfc) {
+ pause->rx_pause = 0;
+ pause->tx_pause = 0;
+#endif
}
}
@@ -363,7 +372,6 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
return -EINVAL;
#endif
-
fc = hw->fc;
if (pause->autoneg != AUTONEG_ENABLE)
@@ -412,11 +420,6 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
else
adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
- if (netif_running(netdev))
- ixgbe_reinit_locked(adapter);
- else
- ixgbe_reset(adapter);
-
return 0;
}
@@ -428,16 +431,21 @@ static u32 ixgbe_get_tx_csum(struct net_device *netdev)
static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 feature_list;
- if (data) {
- netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
- netdev->features |= NETIF_F_SCTP_CSUM;
- } else {
- netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
- netdev->features &= ~NETIF_F_SCTP_CSUM;
+ feature_list = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ feature_list |= NETIF_F_SCTP_CSUM;
+ break;
+ default:
+ break;
}
+ if (data)
+ netdev->features |= feature_list;
+ else
+ netdev->features &= ~feature_list;
return 0;
}
@@ -530,10 +538,20 @@ static void ixgbe_get_regs(struct net_device *netdev,
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));
+ for (i = 0; i < 8; i++) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
+ regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
+ break;
+ case ixgbe_mac_82599EB:
+ regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
+ regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
+ break;
+ default:
+ break;
+ }
+ }
regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
@@ -615,6 +633,7 @@ static void ixgbe_get_regs(struct net_device *netdev,
regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT(0));
+ /* DCB */
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);
@@ -820,9 +839,10 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
char firmware_version[32];
- strncpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
+ strncpy(drvinfo->driver, ixgbe_driver_name,
+ sizeof(drvinfo->driver) - 1);
strncpy(drvinfo->version, ixgbe_driver_version,
- sizeof(drvinfo->version));
+ sizeof(drvinfo->version) - 1);
snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
(adapter->eeprom_version & 0xF000) >> 12,
@@ -905,13 +925,11 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
memcpy(&temp_tx_ring[i], adapter->tx_ring[i],
sizeof(struct ixgbe_ring));
temp_tx_ring[i].count = new_tx_count;
- err = ixgbe_setup_tx_resources(adapter,
- &temp_tx_ring[i]);
+ err = ixgbe_setup_tx_resources(&temp_tx_ring[i]);
if (err) {
while (i) {
i--;
- ixgbe_free_tx_resources(adapter,
- &temp_tx_ring[i]);
+ ixgbe_free_tx_resources(&temp_tx_ring[i]);
}
goto clear_reset;
}
@@ -930,13 +948,11 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
memcpy(&temp_rx_ring[i], adapter->rx_ring[i],
sizeof(struct ixgbe_ring));
temp_rx_ring[i].count = new_rx_count;
- err = ixgbe_setup_rx_resources(adapter,
- &temp_rx_ring[i]);
+ err = ixgbe_setup_rx_resources(&temp_rx_ring[i]);
if (err) {
while (i) {
i--;
- ixgbe_free_rx_resources(adapter,
- &temp_rx_ring[i]);
+ ixgbe_free_rx_resources(&temp_rx_ring[i]);
}
goto err_setup;
}
@@ -951,8 +967,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
/* tx */
if (new_tx_count != adapter->tx_ring_count) {
for (i = 0; i < adapter->num_tx_queues; i++) {
- ixgbe_free_tx_resources(adapter,
- adapter->tx_ring[i]);
+ ixgbe_free_tx_resources(adapter->tx_ring[i]);
memcpy(adapter->tx_ring[i], &temp_tx_ring[i],
sizeof(struct ixgbe_ring));
}
@@ -962,8 +977,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
/* rx */
if (new_rx_count != adapter->rx_ring_count) {
for (i = 0; i < adapter->num_rx_queues; i++) {
- ixgbe_free_rx_resources(adapter,
- adapter->rx_ring[i]);
+ ixgbe_free_rx_resources(adapter->rx_ring[i]);
memcpy(adapter->rx_ring[i], &temp_rx_ring[i],
sizeof(struct ixgbe_ring));
}
@@ -1144,7 +1158,7 @@ struct ixgbe_reg_test {
#define TABLE64_TEST_HI 6
/* default 82599 register test */
-static struct ixgbe_reg_test reg_test_82599[] = {
+static const struct ixgbe_reg_test reg_test_82599[] = {
{ IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
{ IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
{ IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
@@ -1168,7 +1182,7 @@ static struct ixgbe_reg_test reg_test_82599[] = {
};
/* default 82598 register test */
-static struct ixgbe_reg_test reg_test_82598[] = {
+static const struct ixgbe_reg_test reg_test_82598[] = {
{ IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
{ IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
{ IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
@@ -1195,18 +1209,22 @@ static struct ixgbe_reg_test reg_test_82598[] = {
{ 0, 0, 0, 0 }
};
+static const u32 register_test_patterns[] = {
+ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+};
+
#define REG_PATTERN_TEST(R, M, W) \
{ \
u32 pat, val, before; \
- const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
- for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \
+ for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \
before = readl(adapter->hw.hw_addr + R); \
- writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \
+ writel((register_test_patterns[pat] & W), \
+ (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
- if (val != (_test[pat] & W & M)) { \
- e_err(drv, "pattern test reg %04X failed: got " \
- "0x%08X expected 0x%08X\n", \
- R, val, (_test[pat] & W & M)); \
+ if (val != (register_test_patterns[pat] & W & M)) { \
+ e_err(drv, "pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ R, val, (register_test_patterns[pat] & W & M)); \
*data = R; \
writel(before, adapter->hw.hw_addr + R); \
return 1; \
@@ -1233,16 +1251,24 @@ static struct ixgbe_reg_test reg_test_82598[] = {
static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
{
- struct ixgbe_reg_test *test;
+ const struct ixgbe_reg_test *test;
u32 value, before, after;
u32 i, toggle;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- toggle = 0x7FFFF30F;
- test = reg_test_82599;
- } else {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
toggle = 0x7FFFF3FF;
test = reg_test_82598;
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ toggle = 0x7FFFF30F;
+ test = reg_test_82599;
+ break;
+ default:
+ *data = 1;
+ return 1;
+ break;
}
/*
@@ -1451,25 +1477,28 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
reg_ctl &= ~IXGBE_RXCTRL_RXEN;
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl);
- reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx));
- reg_ctl &= ~IXGBE_RXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx), reg_ctl);
+ ixgbe_disable_rx_queue(adapter, rx_ring);
/* now Tx */
reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx));
reg_ctl &= ~IXGBE_TXDCTL_ENABLE;
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx), reg_ctl);
- if (hw->mac.type == ixgbe_mac_82599EB) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
reg_ctl &= ~IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl);
+ break;
+ default:
+ break;
}
ixgbe_reset(adapter);
- ixgbe_free_tx_resources(adapter, &adapter->test_tx_ring);
- ixgbe_free_rx_resources(adapter, &adapter->test_rx_ring);
+ ixgbe_free_tx_resources(&adapter->test_tx_ring);
+ ixgbe_free_rx_resources(&adapter->test_rx_ring);
}
static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
@@ -1483,17 +1512,24 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
/* Setup Tx descriptor ring and Tx buffers */
tx_ring->count = IXGBE_DEFAULT_TXD;
tx_ring->queue_index = 0;
+ tx_ring->dev = &adapter->pdev->dev;
+ tx_ring->netdev = adapter->netdev;
tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx;
tx_ring->numa_node = adapter->node;
- err = ixgbe_setup_tx_resources(adapter, tx_ring);
+ err = ixgbe_setup_tx_resources(tx_ring);
if (err)
return 1;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
reg_data |= IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
+ break;
+ default:
+ break;
}
ixgbe_configure_tx_ring(adapter, tx_ring);
@@ -1501,11 +1537,13 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
/* Setup Rx Descriptor ring and Rx buffers */
rx_ring->count = IXGBE_DEFAULT_RXD;
rx_ring->queue_index = 0;
+ rx_ring->dev = &adapter->pdev->dev;
+ rx_ring->netdev = adapter->netdev;
rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
rx_ring->rx_buf_len = IXGBE_RXBUFFER_2048;
rx_ring->numa_node = adapter->node;
- err = ixgbe_setup_rx_resources(adapter, rx_ring);
+ err = ixgbe_setup_rx_resources(rx_ring);
if (err) {
ret_val = 4;
goto err_nomem;
@@ -1604,8 +1642,7 @@ static int ixgbe_check_lbtest_frame(struct sk_buff *skb,
return 13;
}
-static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring,
+static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
struct ixgbe_ring *tx_ring,
unsigned int size)
{
@@ -1627,7 +1664,7 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
/* unmap Rx buffer, will be remapped by alloc_rx_buffers */
- dma_unmap_single(&adapter->pdev->dev,
+ dma_unmap_single(rx_ring->dev,
rx_buffer_info->dma,
bufsz,
DMA_FROM_DEVICE);
@@ -1639,7 +1676,7 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
/* unmap buffer on Tx side */
tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
- ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
/* increment Rx/Tx next to clean counters */
rx_ntc++;
@@ -1655,7 +1692,7 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
}
/* re-map buffers to ring, store next to clean values */
- ixgbe_alloc_rx_buffers(adapter, rx_ring, count);
+ ixgbe_alloc_rx_buffers(rx_ring, count);
rx_ring->next_to_clean = rx_ntc;
tx_ring->next_to_clean = tx_ntc;
@@ -1699,7 +1736,6 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
for (i = 0; i < 64; i++) {
skb_get(skb);
tx_ret_val = ixgbe_xmit_frame_ring(skb,
- adapter->netdev,
adapter,
tx_ring);
if (tx_ret_val == NETDEV_TX_OK)
@@ -1714,8 +1750,7 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
/* allow 200 milliseconds for packets to go from Tx to Rx */
msleep(200);
- good_cnt = ixgbe_clean_test_rings(adapter, rx_ring,
- tx_ring, size);
+ good_cnt = ixgbe_clean_test_rings(rx_ring, tx_ring, size);
if (good_cnt != 64) {
ret_val = 13;
break;
@@ -1847,7 +1882,25 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
struct ixgbe_hw *hw = &adapter->hw;
int retval = 1;
+ /* WOL not supported except for the following */
switch(hw->device_id) {
+ case IXGBE_DEV_ID_82599_SFP:
+ /* Only this subdevice supports WOL */
+ if (hw->subsystem_device_id != IXGBE_SUBDEV_ID_82599_SFP) {
+ wol->supported = 0;
+ break;
+ }
+ retval = 0;
+ break;
+ case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
+ /* All except this subdevice support WOL */
+ if (hw->subsystem_device_id ==
+ IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ) {
+ wol->supported = 0;
+ break;
+ }
+ retval = 0;
+ break;
case IXGBE_DEV_ID_82599_KX4:
retval = 0;
break;
@@ -1985,6 +2038,41 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
return 0;
}
+/*
+ * this function must be called before setting the new value of
+ * rx_itr_setting
+ */
+static bool ixgbe_update_rsc(struct ixgbe_adapter *adapter,
+ struct ethtool_coalesce *ec)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
+ return false;
+
+ /* if interrupt rate is too high then disable RSC */
+ if (ec->rx_coalesce_usecs != 1 &&
+ ec->rx_coalesce_usecs <= 1000000/IXGBE_MAX_RSC_INT_RATE) {
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
+ e_info(probe, "rx-usecs set too low, "
+ "disabling RSC\n");
+ adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
+ return true;
+ }
+ } else {
+ /* check the feature flag value and enable RSC if necessary */
+ if ((netdev->features & NETIF_F_LRO) &&
+ !(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)) {
+ e_info(probe, "rx-usecs set to %d, "
+ "re-enabling RSC\n",
+ ec->rx_coalesce_usecs);
+ adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+ return true;
+ }
+ }
+ return false;
+}
+
static int ixgbe_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
@@ -2002,17 +2090,14 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
adapter->tx_ring[0]->work_limit = ec->tx_max_coalesced_frames_irq;
if (ec->rx_coalesce_usecs > 1) {
- u32 max_int;
- if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
- max_int = IXGBE_MAX_RSC_INT_RATE;
- else
- max_int = IXGBE_MAX_INT_RATE;
-
/* check the limits */
- if ((1000000/ec->rx_coalesce_usecs > max_int) ||
+ if ((1000000/ec->rx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
(1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE))
return -EINVAL;
+ /* check the old value and enable RSC if necessary */
+ need_reset = ixgbe_update_rsc(adapter, ec);
+
/* store the value in ints/second */
adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs;
@@ -2021,32 +2106,21 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
/* clear the lower bit as its used for dynamic state */
adapter->rx_itr_setting &= ~1;
} else if (ec->rx_coalesce_usecs == 1) {
+ /* check the old value and enable RSC if necessary */
+ need_reset = ixgbe_update_rsc(adapter, ec);
+
/* 1 means dynamic mode */
adapter->rx_eitr_param = 20000;
adapter->rx_itr_setting = 1;
} else {
+ /* check the old value and enable RSC if necessary */
+ need_reset = ixgbe_update_rsc(adapter, ec);
/*
* any other value means disable eitr, which is best
* served by setting the interrupt rate very high
*/
adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
adapter->rx_itr_setting = 0;
-
- /*
- * if hardware RSC is enabled, disable it when
- * setting low latency mode, to avoid errata, assuming
- * that when the user set low latency mode they want
- * it at the cost of anything else
- */
- if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
- adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
- if (netdev->features & NETIF_F_LRO) {
- netdev->features &= ~NETIF_F_LRO;
- e_info(probe, "rx-usecs set to 0, "
- "disabling RSC\n");
- }
- need_reset = true;
- }
}
if (ec->tx_coalesce_usecs > 1) {
@@ -2127,34 +2201,45 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
need_reset = (data & ETH_FLAG_RXVLAN) !=
(netdev->features & NETIF_F_HW_VLAN_RX);
- rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO |
+ rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE |
ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
if (rc)
return rc;
/* if state changes we need to update adapter->flags and reset */
- if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
- /*
- * cast both to bool and verify if they are set the same
- * but only enable RSC if itr is non-zero, as
- * itr=0 and RSC are mutually exclusive
- */
- if (((!!(data & ETH_FLAG_LRO)) !=
- (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) &&
- adapter->rx_itr_setting) {
+ if ((adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) &&
+ (!!(data & ETH_FLAG_LRO) !=
+ !!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
+ if ((data & ETH_FLAG_LRO) &&
+ (!adapter->rx_itr_setting ||
+ (adapter->rx_itr_setting > IXGBE_MAX_RSC_INT_RATE))) {
+ e_info(probe, "rx-usecs set too low, "
+ "not enabling RSC.\n");
+ } else {
adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
need_reset = true;
break;
+ case ixgbe_mac_X540: {
+ int i;
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct ixgbe_ring *ring =
+ adapter->rx_ring[i];
+ if (adapter->flags2 &
+ IXGBE_FLAG2_RSC_ENABLED) {
+ ixgbe_configure_rscctl(adapter,
+ ring);
+ } else {
+ ixgbe_clear_rscctl(adapter,
+ ring);
+ }
+ }
+ }
+ break;
default:
break;
}
- } else if (!adapter->rx_itr_setting) {
- netdev->features &= ~NETIF_F_LRO;
- if (data & ETH_FLAG_LRO)
- e_info(probe, "rx-usecs set to 0, "
- "LRO/RSC cannot be enabled.\n");
}
}
@@ -2192,10 +2277,11 @@ static int ixgbe_set_rx_ntuple(struct net_device *dev,
struct ethtool_rx_ntuple *cmd)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
- struct ethtool_rx_ntuple_flow_spec fs = cmd->fs;
- struct ixgbe_atr_input input_struct;
+ struct ethtool_rx_ntuple_flow_spec *fs = &cmd->fs;
+ union ixgbe_atr_input input_struct;
struct ixgbe_atr_input_masks input_masks;
int target_queue;
+ int err;
if (adapter->hw.mac.type == ixgbe_mac_82598EB)
return -EOPNOTSUPP;
@@ -2204,67 +2290,122 @@ static int ixgbe_set_rx_ntuple(struct net_device *dev,
* Don't allow programming if the action is a queue greater than
* the number of online Tx queues.
*/
- if ((fs.action >= adapter->num_tx_queues) ||
- (fs.action < ETHTOOL_RXNTUPLE_ACTION_DROP))
+ if ((fs->action >= adapter->num_tx_queues) ||
+ (fs->action < ETHTOOL_RXNTUPLE_ACTION_DROP))
return -EINVAL;
- memset(&input_struct, 0, sizeof(struct ixgbe_atr_input));
+ memset(&input_struct, 0, sizeof(union ixgbe_atr_input));
memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks));
- input_masks.src_ip_mask = fs.m_u.tcp_ip4_spec.ip4src;
- input_masks.dst_ip_mask = fs.m_u.tcp_ip4_spec.ip4dst;
- input_masks.src_port_mask = fs.m_u.tcp_ip4_spec.psrc;
- input_masks.dst_port_mask = fs.m_u.tcp_ip4_spec.pdst;
- input_masks.vlan_id_mask = fs.vlan_tag_mask;
- /* only use the lowest 2 bytes for flex bytes */
- input_masks.data_mask = (fs.data_mask & 0xffff);
-
- switch (fs.flow_type) {
+ /* record flow type */
+ switch (fs->flow_type) {
+ case IPV4_FLOW:
+ input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_IPV4;
+ break;
case TCP_V4_FLOW:
- ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_TCP);
+ input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
break;
case UDP_V4_FLOW:
- ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_UDP);
+ input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4;
break;
case SCTP_V4_FLOW:
- ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_SCTP);
+ input_struct.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4;
break;
default:
return -1;
}
- /* Mask bits from the inputs based on user-supplied mask */
- ixgbe_atr_set_src_ipv4_82599(&input_struct,
- (fs.h_u.tcp_ip4_spec.ip4src & ~fs.m_u.tcp_ip4_spec.ip4src));
- ixgbe_atr_set_dst_ipv4_82599(&input_struct,
- (fs.h_u.tcp_ip4_spec.ip4dst & ~fs.m_u.tcp_ip4_spec.ip4dst));
- /* 82599 expects these to be byte-swapped for perfect filtering */
- ixgbe_atr_set_src_port_82599(&input_struct,
- ((ntohs(fs.h_u.tcp_ip4_spec.psrc)) & ~fs.m_u.tcp_ip4_spec.psrc));
- ixgbe_atr_set_dst_port_82599(&input_struct,
- ((ntohs(fs.h_u.tcp_ip4_spec.pdst)) & ~fs.m_u.tcp_ip4_spec.pdst));
-
- /* VLAN and Flex bytes are either completely masked or not */
- if (!fs.vlan_tag_mask)
- ixgbe_atr_set_vlan_id_82599(&input_struct, fs.vlan_tag);
-
- if (!input_masks.data_mask)
- /* make sure we only use the first 2 bytes of user data */
- ixgbe_atr_set_flex_byte_82599(&input_struct,
- (fs.data & 0xffff));
+ /* copy vlan tag minus the CFI bit */
+ if ((fs->vlan_tag & 0xEFFF) || (~fs->vlan_tag_mask & 0xEFFF)) {
+ input_struct.formatted.vlan_id = htons(fs->vlan_tag & 0xEFFF);
+ if (!fs->vlan_tag_mask) {
+ input_masks.vlan_id_mask = htons(0xEFFF);
+ } else {
+ switch (~fs->vlan_tag_mask & 0xEFFF) {
+ /* all of these are valid vlan-mask values */
+ case 0xEFFF:
+ case 0xE000:
+ case 0x0FFF:
+ case 0x0000:
+ input_masks.vlan_id_mask =
+ htons(~fs->vlan_tag_mask);
+ break;
+ /* exit with error if vlan-mask is invalid */
+ default:
+ e_err(drv, "Partial VLAN ID or "
+ "priority mask in vlan-mask is not "
+ "supported by hardware\n");
+ return -1;
+ }
+ }
+ }
+
+ /* make sure we only use the first 2 bytes of user data */
+ if ((fs->data & 0xFFFF) || (~fs->data_mask & 0xFFFF)) {
+ input_struct.formatted.flex_bytes = htons(fs->data & 0xFFFF);
+ if (!(fs->data_mask & 0xFFFF)) {
+ input_masks.flex_mask = 0xFFFF;
+ } else if (~fs->data_mask & 0xFFFF) {
+ e_err(drv, "Partial user-def-mask is not "
+ "supported by hardware\n");
+ return -1;
+ }
+ }
+
+ /*
+ * Copy input into formatted structures
+ *
+ * These assignments are based on the following logic
+ * If neither input or mask are set assume value is masked out.
+ * If input is set, but mask is not mask should default to accept all.
+ * If input is not set, but mask is set then mask likely results in 0.
+ * If input is set and mask is set then assign both.
+ */
+ if (fs->h_u.tcp_ip4_spec.ip4src || ~fs->m_u.tcp_ip4_spec.ip4src) {
+ input_struct.formatted.src_ip[0] = fs->h_u.tcp_ip4_spec.ip4src;
+ if (!fs->m_u.tcp_ip4_spec.ip4src)
+ input_masks.src_ip_mask[0] = 0xFFFFFFFF;
+ else
+ input_masks.src_ip_mask[0] =
+ ~fs->m_u.tcp_ip4_spec.ip4src;
+ }
+ if (fs->h_u.tcp_ip4_spec.ip4dst || ~fs->m_u.tcp_ip4_spec.ip4dst) {
+ input_struct.formatted.dst_ip[0] = fs->h_u.tcp_ip4_spec.ip4dst;
+ if (!fs->m_u.tcp_ip4_spec.ip4dst)
+ input_masks.dst_ip_mask[0] = 0xFFFFFFFF;
+ else
+ input_masks.dst_ip_mask[0] =
+ ~fs->m_u.tcp_ip4_spec.ip4dst;
+ }
+ if (fs->h_u.tcp_ip4_spec.psrc || ~fs->m_u.tcp_ip4_spec.psrc) {
+ input_struct.formatted.src_port = fs->h_u.tcp_ip4_spec.psrc;
+ if (!fs->m_u.tcp_ip4_spec.psrc)
+ input_masks.src_port_mask = 0xFFFF;
+ else
+ input_masks.src_port_mask = ~fs->m_u.tcp_ip4_spec.psrc;
+ }
+ if (fs->h_u.tcp_ip4_spec.pdst || ~fs->m_u.tcp_ip4_spec.pdst) {
+ input_struct.formatted.dst_port = fs->h_u.tcp_ip4_spec.pdst;
+ if (!fs->m_u.tcp_ip4_spec.pdst)
+ input_masks.dst_port_mask = 0xFFFF;
+ else
+ input_masks.dst_port_mask = ~fs->m_u.tcp_ip4_spec.pdst;
+ }
/* determine if we need to drop or route the packet */
- if (fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
+ if (fs->action == ETHTOOL_RXNTUPLE_ACTION_DROP)
target_queue = MAX_RX_QUEUES - 1;
else
- target_queue = fs.action;
+ target_queue = fs->action;
spin_lock(&adapter->fdir_perfect_lock);
- ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, &input_struct,
- &input_masks, 0, target_queue);
+ err = ixgbe_fdir_add_perfect_filter_82599(&adapter->hw,
+ &input_struct,
+ &input_masks, 0,
+ target_queue);
spin_unlock(&adapter->fdir_perfect_lock);
- return 0;
+ return err ? -1 : 0;
}
static const struct ethtool_ops ixgbe_ethtool_ops = {
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index 05efa6a8ce8e..6342d4859790 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -68,7 +68,7 @@ static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc)
static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp)
{
ddp->len = 0;
- ddp->err = 0;
+ ddp->err = 1;
ddp->udl = NULL;
ddp->udp = 0UL;
ddp->sgl = NULL;
@@ -92,6 +92,7 @@ int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid)
struct ixgbe_fcoe *fcoe;
struct ixgbe_adapter *adapter;
struct ixgbe_fcoe_ddp *ddp;
+ u32 fcbuff;
if (!netdev)
goto out_ddp_put;
@@ -115,7 +116,14 @@ int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCBUFF, 0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW,
(xid | IXGBE_FCDMARW_WE));
+
+ /* guaranteed to be invalidated after 100us */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW,
+ (xid | IXGBE_FCDMARW_RE));
+ fcbuff = IXGBE_READ_REG(&adapter->hw, IXGBE_FCBUFF);
spin_unlock_bh(&fcoe->lock);
+ if (fcbuff & IXGBE_FCBUFF_VALID)
+ udelay(100);
}
if (ddp->sgl)
pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc,
@@ -168,6 +176,11 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
return 0;
}
+ /* no DDP if we are already down or resetting */
+ if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ test_bit(__IXGBE_RESETTING, &adapter->state))
+ return 0;
+
fcoe = &adapter->fcoe;
if (!fcoe->pool) {
e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 2bd3eb4ee5a1..602078b84892 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -52,13 +52,14 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.84-k2"
+#define DRV_VERSION "3.0.12-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
static const struct ixgbe_info *ixgbe_info_tbl[] = {
[board_82598] = &ixgbe_82598_info,
[board_82599] = &ixgbe_82599_info,
+ [board_X540] = &ixgbe_X540_info,
};
/* ixgbe_pci_tbl - PCI Device ID Table
@@ -108,10 +109,16 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4),
board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE),
+ board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE),
+ board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM),
board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE),
board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T),
+ board_X540 },
/* required last entry */
{0, }
@@ -560,6 +567,7 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
break;
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
if (direction == -1) {
/* other causes */
msix_vector |= IXGBE_IVAR_ALLOC_VAL;
@@ -589,29 +597,34 @@ static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
{
u32 mask;
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
- } else {
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
mask = (qmask & 0xFFFFFFFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
mask = (qmask >> 32);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask);
+ break;
+ default:
+ break;
}
}
-void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
- struct ixgbe_tx_buffer
- *tx_buffer_info)
+void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring,
+ struct ixgbe_tx_buffer *tx_buffer_info)
{
if (tx_buffer_info->dma) {
if (tx_buffer_info->mapped_as_page)
- dma_unmap_page(&adapter->pdev->dev,
+ dma_unmap_page(tx_ring->dev,
tx_buffer_info->dma,
tx_buffer_info->length,
DMA_TO_DEVICE);
else
- dma_unmap_single(&adapter->pdev->dev,
+ dma_unmap_single(tx_ring->dev,
tx_buffer_info->dma,
tx_buffer_info->length,
DMA_TO_DEVICE);
@@ -626,92 +639,166 @@ void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
}
/**
- * ixgbe_tx_xon_state - check the tx ring xon state
- * @adapter: the ixgbe adapter
- * @tx_ring: the corresponding tx_ring
+ * ixgbe_dcb_txq_to_tc - convert a reg index to a traffic class
+ * @adapter: driver private struct
+ * @index: reg idx of queue to query (0-127)
*
- * If not in DCB mode, checks TFCS.TXOFF, otherwise, find out the
- * corresponding TC of this tx_ring when checking TFCS.
+ * Helper function to determine the traffic index for a paticular
+ * register index.
*
- * Returns : true if in xon state (currently not paused)
+ * Returns : a tc index for use in range 0-7, or 0-3
*/
-static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 reg_idx)
{
- u32 txoff = IXGBE_TFCS_TXOFF;
+ int tc = -1;
+ int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
-#ifdef CONFIG_IXGBE_DCB
- if (adapter->dcb_cfg.pfc_mode_enable) {
- int tc;
- int reg_idx = tx_ring->reg_idx;
- int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
+ /* if DCB is not enabled the queues have no TC */
+ if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED))
+ return tc;
+
+ /* check valid range */
+ if (reg_idx >= adapter->hw.mac.max_tx_queues)
+ return tc;
+
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
+ tc = reg_idx >> 2;
+ break;
+ default:
+ if (dcb_i != 4 && dcb_i != 8)
+ break;
+
+ /* if VMDq is enabled the lowest order bits determine TC */
+ if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
+ IXGBE_FLAG_VMDQ_ENABLED)) {
+ tc = reg_idx & (dcb_i - 1);
+ break;
+ }
+
+ /*
+ * Convert the reg_idx into the correct TC. This bitmask
+ * targets the last full 32 ring traffic class and assigns
+ * it a value of 1. From there the rest of the rings are
+ * based on shifting the mask further up to include the
+ * reg_idx / 16 and then reg_idx / 8. It assumes dcB_i
+ * will only ever be 8 or 4 and that reg_idx will never
+ * be greater then 128. The code without the power of 2
+ * optimizations would be:
+ * (((reg_idx % 32) + 32) * dcb_i) >> (9 - reg_idx / 32)
+ */
+ tc = ((reg_idx & 0X1F) + 0x20) * dcb_i;
+ tc >>= 9 - (reg_idx >> 5);
+ }
- switch (adapter->hw.mac.type) {
+ return tc;
+}
+
+static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_hw_stats *hwstats = &adapter->stats;
+ u32 data = 0;
+ u32 xoff[8] = {0};
+ int i;
+
+ if ((hw->fc.current_mode == ixgbe_fc_full) ||
+ (hw->fc.current_mode == ixgbe_fc_rx_pause)) {
+ switch (hw->mac.type) {
case ixgbe_mac_82598EB:
- tc = reg_idx >> 2;
- txoff = IXGBE_TFCS_TXOFF0;
+ data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
break;
- case ixgbe_mac_82599EB:
- tc = 0;
- txoff = IXGBE_TFCS_TXOFF;
- if (dcb_i == 8) {
- /* TC0, TC1 */
- tc = reg_idx >> 5;
- if (tc == 2) /* TC2, TC3 */
- tc += (reg_idx - 64) >> 4;
- else if (tc == 3) /* TC4, TC5, TC6, TC7 */
- tc += 1 + ((reg_idx - 96) >> 3);
- } else if (dcb_i == 4) {
- /* TC0, TC1 */
- tc = reg_idx >> 6;
- if (tc == 1) {
- tc += (reg_idx - 64) >> 5;
- if (tc == 2) /* TC2, TC3 */
- tc += (reg_idx - 96) >> 4;
- }
- }
+ default:
+ data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
+ }
+ hwstats->lxoffrxc += data;
+
+ /* refill credits (no tx hang) if we received xoff */
+ if (!data)
+ return;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ clear_bit(__IXGBE_HANG_CHECK_ARMED,
+ &adapter->tx_ring[i]->state);
+ return;
+ } else if (!(adapter->dcb_cfg.pfc_mode_enable))
+ return;
+
+ /* update stats for each tc, only valid with PFC enabled */
+ for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ xoff[i] = IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
break;
default:
- tc = 0;
+ xoff[i] = IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i));
}
- txoff <<= tc;
+ hwstats->pxoffrxc[i] += xoff[i];
+ }
+
+ /* disarm tx queues that have received xoff frames */
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+ u32 tc = ixgbe_dcb_txq_to_tc(adapter, tx_ring->reg_idx);
+
+ if (xoff[tc])
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);
}
-#endif
- return IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & txoff;
}
-static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- unsigned int eop)
+static u64 ixgbe_get_tx_completed(struct ixgbe_ring *ring)
{
+ return ring->tx_stats.completed;
+}
+
+static u64 ixgbe_get_tx_pending(struct ixgbe_ring *ring)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(ring->netdev);
struct ixgbe_hw *hw = &adapter->hw;
- /* Detect a transmit hang in hardware, this serializes the
- * check with the clearing of time_stamp and movement of eop */
- adapter->detect_tx_hung = false;
- if (tx_ring->tx_buffer_info[eop].time_stamp &&
- time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
- ixgbe_tx_xon_state(adapter, tx_ring)) {
- /* detected Tx unit hang */
- union ixgbe_adv_tx_desc *tx_desc;
- tx_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
- e_err(drv, "Detected Tx Unit Hang\n"
- " Tx Queue <%d>\n"
- " TDH, TDT <%x>, <%x>\n"
- " next_to_use <%x>\n"
- " next_to_clean <%x>\n"
- "tx_buffer_info[next_to_clean]\n"
- " time_stamp <%lx>\n"
- " jiffies <%lx>\n",
- tx_ring->queue_index,
- IXGBE_READ_REG(hw, tx_ring->head),
- IXGBE_READ_REG(hw, tx_ring->tail),
- tx_ring->next_to_use, eop,
- tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
- return true;
+ u32 head = IXGBE_READ_REG(hw, IXGBE_TDH(ring->reg_idx));
+ u32 tail = IXGBE_READ_REG(hw, IXGBE_TDT(ring->reg_idx));
+
+ if (head != tail)
+ return (head < tail) ?
+ tail - head : (tail + ring->count - head);
+
+ return 0;
+}
+
+static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
+{
+ u32 tx_done = ixgbe_get_tx_completed(tx_ring);
+ u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
+ u32 tx_pending = ixgbe_get_tx_pending(tx_ring);
+ bool ret = false;
+
+ clear_check_for_tx_hang(tx_ring);
+
+ /*
+ * Check for a hung queue, but be thorough. This verifies
+ * that a transmit has been completed since the previous
+ * check AND there is at least one packet pending. The
+ * ARMED bit is set to indicate a potential hang. The
+ * bit is cleared if a pause frame is received to remove
+ * false hang detection due to PFC or 802.3x frames. By
+ * requiring this to fail twice we avoid races with
+ * pfc clearing the ARMED bit and conditions where we
+ * run the check_tx_hang logic with a transmit completion
+ * pending but without time to complete it yet.
+ */
+ if ((tx_done_old == tx_done) && tx_pending) {
+ /* make sure it is true for two checks in a row */
+ ret = test_and_set_bit(__IXGBE_HANG_CHECK_ARMED,
+ &tx_ring->state);
+ } else {
+ /* update completed stats and continue */
+ tx_ring->tx_stats.tx_done_old = tx_done;
+ /* reset the countdown */
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);
}
- return false;
+ return ret;
}
#define IXGBE_MAX_TXD_PWR 14
@@ -734,11 +821,10 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *tx_ring)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
- 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, count = 0;
unsigned int total_bytes = 0, total_packets = 0;
+ u16 i, eop, count = 0;
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
@@ -749,147 +835,182 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
bool cleaned = false;
rmb(); /* read buffer_info after eop_desc */
for ( ; !cleaned; count++) {
- struct sk_buff *skb;
tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
tx_buffer_info = &tx_ring->tx_buffer_info[i];
- cleaned = (i == eop);
- skb = tx_buffer_info->skb;
-
- if (cleaned && skb) {
- unsigned int segs, bytecount;
- unsigned int hlen = skb_headlen(skb);
-
- /* gso_segs is currently only valid for tcp */
- segs = skb_shinfo(skb)->gso_segs ?: 1;
-#ifdef IXGBE_FCOE
- /* adjust for FCoE Sequence Offload */
- if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
- && (skb->protocol == htons(ETH_P_FCOE)) &&
- skb_is_gso(skb)) {
- hlen = skb_transport_offset(skb) +
- sizeof(struct fc_frame_header) +
- sizeof(struct fcoe_crc_eof);
- segs = DIV_ROUND_UP(skb->len - hlen,
- skb_shinfo(skb)->gso_size);
- }
-#endif /* IXGBE_FCOE */
- /* multiply data chunks by size of headers */
- bytecount = ((segs - 1) * hlen) + skb->len;
- total_packets += segs;
- total_bytes += bytecount;
- }
-
- ixgbe_unmap_and_free_tx_resource(adapter,
- tx_buffer_info);
tx_desc->wb.status = 0;
+ cleaned = (i == eop);
i++;
if (i == tx_ring->count)
i = 0;
+
+ if (cleaned && tx_buffer_info->skb) {
+ total_bytes += tx_buffer_info->bytecount;
+ total_packets += tx_buffer_info->gso_segs;
+ }
+
+ ixgbe_unmap_and_free_tx_resource(tx_ring,
+ tx_buffer_info);
}
+ tx_ring->tx_stats.completed++;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
}
tx_ring->next_to_clean = i;
+ tx_ring->total_bytes += total_bytes;
+ tx_ring->total_packets += total_packets;
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->stats.packets += total_packets;
+ tx_ring->stats.bytes += total_bytes;
+ u64_stats_update_end(&tx_ring->syncp);
+
+ if (check_for_tx_hang(tx_ring) && ixgbe_check_tx_hang(tx_ring)) {
+ /* schedule immediate reset if we believe we hung */
+ struct ixgbe_hw *hw = &adapter->hw;
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
+ e_err(drv, "Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ IXGBE_READ_REG(hw, IXGBE_TDH(tx_ring->reg_idx)),
+ IXGBE_READ_REG(hw, IXGBE_TDT(tx_ring->reg_idx)),
+ tx_ring->next_to_use, eop,
+ tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+
+ netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+ e_info(probe,
+ "tx hang %d detected on queue %d, resetting adapter\n",
+ adapter->tx_timeout_count + 1, tx_ring->queue_index);
+
+ /* schedule immediate reset if we believe we hung */
+ ixgbe_tx_timeout(adapter->netdev);
+
+ /* the adapter is about to reset, no point in enabling stuff */
+ return true;
+ }
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
- if (unlikely(count && netif_carrier_ok(netdev) &&
+ if (unlikely(count && netif_carrier_ok(tx_ring->netdev) &&
(IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
*/
smp_mb();
- if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
+ if (__netif_subqueue_stopped(tx_ring->netdev, tx_ring->queue_index) &&
!test_bit(__IXGBE_DOWN, &adapter->state)) {
- netif_wake_subqueue(netdev, tx_ring->queue_index);
- ++tx_ring->restart_queue;
+ netif_wake_subqueue(tx_ring->netdev, tx_ring->queue_index);
+ ++tx_ring->tx_stats.restart_queue;
}
}
- if (adapter->detect_tx_hung) {
- if (ixgbe_check_tx_hang(adapter, tx_ring, i)) {
- /* schedule immediate reset if we believe we hung */
- e_info(probe, "tx hang %d detected, resetting "
- "adapter\n", adapter->tx_timeout_count + 1);
- ixgbe_tx_timeout(adapter->netdev);
- }
- }
-
- /* re-arm the interrupt */
- if (count >= tx_ring->work_limit)
- ixgbe_irq_rearm_queues(adapter, ((u64)1 << q_vector->v_idx));
-
- tx_ring->total_bytes += total_bytes;
- tx_ring->total_packets += total_packets;
- u64_stats_update_begin(&tx_ring->syncp);
- tx_ring->stats.packets += total_packets;
- tx_ring->stats.bytes += total_bytes;
- u64_stats_update_end(&tx_ring->syncp);
return count < tx_ring->work_limit;
}
#ifdef CONFIG_IXGBE_DCA
static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring,
+ int cpu)
{
+ struct ixgbe_hw *hw = &adapter->hw;
u32 rxctrl;
- int cpu = get_cpu();
- int q = rx_ring->reg_idx;
-
- if (rx_ring->cpu != cpu) {
- rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
- rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
- rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
- } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
- rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
- IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
- }
- rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
- rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
- rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
- rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
- IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
- rx_ring->cpu = cpu;
+ u8 reg_idx = rx_ring->reg_idx;
+
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(reg_idx));
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
+ rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
+ rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+ IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
+ break;
+ default:
+ break;
}
- put_cpu();
+ rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
+ rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
+ rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
+ rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
+ IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl);
}
static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring,
+ int cpu)
{
+ struct ixgbe_hw *hw = &adapter->hw;
u32 txctrl;
+ u8 reg_idx = tx_ring->reg_idx;
+
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(reg_idx));
+ txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
+ txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+ txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
+ txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx));
+ txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
+ txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+ IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
+ txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
+ txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl);
+ break;
+ default:
+ break;
+ }
+}
+
+static void ixgbe_update_dca(struct ixgbe_q_vector *q_vector)
+{
+ struct ixgbe_adapter *adapter = q_vector->adapter;
int cpu = get_cpu();
- int q = tx_ring->reg_idx;
- struct ixgbe_hw *hw = &adapter->hw;
+ long r_idx;
+ int i;
- if (tx_ring->cpu != cpu) {
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
- txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(q));
- txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
- txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
- txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(q), txctrl);
- } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(q));
- txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
- txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
- IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
- txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(q), txctrl);
- }
- tx_ring->cpu = cpu;
+ if (q_vector->cpu == cpu)
+ goto out_no_update;
+
+ r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+ for (i = 0; i < q_vector->txr_count; i++) {
+ ixgbe_update_tx_dca(adapter, adapter->tx_ring[r_idx], cpu);
+ r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+ r_idx + 1);
+ }
+
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ for (i = 0; i < q_vector->rxr_count; i++) {
+ ixgbe_update_rx_dca(adapter, adapter->rx_ring[r_idx], cpu);
+ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+ r_idx + 1);
}
+
+ q_vector->cpu = cpu;
+out_no_update:
put_cpu();
}
static void ixgbe_setup_dca(struct ixgbe_adapter *adapter)
{
+ int num_q_vectors;
int i;
if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED))
@@ -898,22 +1019,25 @@ static void ixgbe_setup_dca(struct ixgbe_adapter *adapter)
/* always use CB2 mode, difference is masked in the CB driver */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2);
- for (i = 0; i < adapter->num_tx_queues; i++) {
- adapter->tx_ring[i]->cpu = -1;
- ixgbe_update_tx_dca(adapter, adapter->tx_ring[i]);
- }
- for (i = 0; i < adapter->num_rx_queues; i++) {
- adapter->rx_ring[i]->cpu = -1;
- ixgbe_update_rx_dca(adapter, adapter->rx_ring[i]);
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ else
+ num_q_vectors = 1;
+
+ for (i = 0; i < num_q_vectors; i++) {
+ adapter->q_vector[i]->cpu = -1;
+ ixgbe_update_dca(adapter->q_vector[i]);
}
}
static int __ixgbe_notify_dca(struct device *dev, void *data)
{
- struct net_device *netdev = dev_get_drvdata(dev);
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_adapter *adapter = dev_get_drvdata(dev);
unsigned long event = *(unsigned long *)data;
+ if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED))
+ return 0;
+
switch (event) {
case DCA_PROVIDER_ADD:
/* if we're already enabled, don't do it again */
@@ -1012,8 +1136,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
- struct ixgbe_ring *rx_ring, u32 val)
+static inline void ixgbe_release_rx_desc(struct ixgbe_ring *rx_ring, u32 val)
{
/*
* Force memory writes to complete before letting h/w
@@ -1022,72 +1145,81 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
* such as IA-64).
*/
wmb();
- IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->reg_idx), val);
+ writel(val, rx_ring->tail);
}
/**
* ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
- * @adapter: address of board private structure
+ * @rx_ring: ring to place buffers on
+ * @cleaned_count: number of buffers to replace
**/
-void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring,
- int cleaned_count)
+void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 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 *bi;
- unsigned int i;
- unsigned int bufsz = rx_ring->rx_buf_len;
+ struct sk_buff *skb;
+ u16 i = rx_ring->next_to_use;
- i = rx_ring->next_to_use;
- bi = &rx_ring->rx_buffer_info[i];
+ /* do nothing if no valid netdev defined */
+ if (!rx_ring->netdev)
+ return;
while (cleaned_count--) {
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
+ bi = &rx_ring->rx_buffer_info[i];
+ skb = bi->skb;
- if (!bi->page_dma &&
- (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)) {
- if (!bi->page) {
- bi->page = netdev_alloc_page(netdev);
- if (!bi->page) {
- adapter->alloc_rx_page_failed++;
- goto no_buffers;
- }
- bi->page_offset = 0;
- } else {
- /* use a half page if we're re-using */
- bi->page_offset ^= (PAGE_SIZE / 2);
- }
-
- bi->page_dma = dma_map_page(&pdev->dev, bi->page,
- bi->page_offset,
- (PAGE_SIZE / 2),
- DMA_FROM_DEVICE);
- }
-
- if (!bi->skb) {
- struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev,
- bufsz);
- bi->skb = skb;
-
+ if (!skb) {
+ skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+ rx_ring->rx_buf_len);
if (!skb) {
- adapter->alloc_rx_buff_failed++;
+ rx_ring->rx_stats.alloc_rx_buff_failed++;
goto no_buffers;
}
/* initialize queue mapping */
skb_record_rx_queue(skb, rx_ring->queue_index);
+ bi->skb = skb;
}
if (!bi->dma) {
- bi->dma = dma_map_single(&pdev->dev,
- bi->skb->data,
+ bi->dma = dma_map_single(rx_ring->dev,
+ skb->data,
rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(rx_ring->dev, bi->dma)) {
+ rx_ring->rx_stats.alloc_rx_buff_failed++;
+ bi->dma = 0;
+ goto no_buffers;
+ }
}
- /* Refresh the desc even if buffer_addrs didn't change because
- * each write-back erases this info. */
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+
+ if (ring_is_ps_enabled(rx_ring)) {
+ if (!bi->page) {
+ bi->page = netdev_alloc_page(rx_ring->netdev);
+ if (!bi->page) {
+ rx_ring->rx_stats.alloc_rx_page_failed++;
+ goto no_buffers;
+ }
+ }
+
+ if (!bi->page_dma) {
+ /* use a half page if we're re-using */
+ bi->page_offset ^= PAGE_SIZE / 2;
+ bi->page_dma = dma_map_page(rx_ring->dev,
+ bi->page,
+ bi->page_offset,
+ PAGE_SIZE / 2,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(rx_ring->dev,
+ bi->page_dma)) {
+ rx_ring->rx_stats.alloc_rx_page_failed++;
+ bi->page_dma = 0;
+ goto no_buffers;
+ }
+ }
+
+ /* Refresh the desc even if buffer_addrs didn't change
+ * because each write-back erases this info. */
rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
} else {
@@ -1098,56 +1230,48 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
i++;
if (i == rx_ring->count)
i = 0;
- bi = &rx_ring->rx_buffer_info[i];
}
no_buffers:
if (rx_ring->next_to_use != i) {
rx_ring->next_to_use = i;
- if (i-- == 0)
- i = (rx_ring->count - 1);
-
- ixgbe_release_rx_desc(&adapter->hw, rx_ring, i);
+ ixgbe_release_rx_desc(rx_ring, i);
}
}
-static inline u16 ixgbe_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc)
+static inline u16 ixgbe_get_hlen(union ixgbe_adv_rx_desc *rx_desc)
{
- return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
-}
-
-static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
-{
- return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
-}
-
-static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
-{
- return (le32_to_cpu(rx_desc->wb.lower.lo_dword.data) &
- IXGBE_RXDADV_RSCCNT_MASK) >>
- IXGBE_RXDADV_RSCCNT_SHIFT;
+ /* HW will not DMA in data larger than the given buffer, even if it
+ * parses the (NFS, of course) header to be larger. In that case, it
+ * fills the header buffer and spills the rest into the page.
+ */
+ u16 hdr_info = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.hdr_info);
+ u16 hlen = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+ IXGBE_RXDADV_HDRBUFLEN_SHIFT;
+ if (hlen > IXGBE_RX_HDR_SIZE)
+ hlen = IXGBE_RX_HDR_SIZE;
+ return hlen;
}
/**
* ixgbe_transform_rsc_queue - change rsc queue into a full packet
* @skb: pointer to the last skb in the rsc queue
- * @count: pointer to number of packets coalesced in this context
*
* This function changes a queue full of hw rsc buffers into a completed
* packet. It uses the ->prev pointers to find the first packet and then
* turns it into the frag list owner.
**/
-static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
- u64 *count)
+static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb)
{
unsigned int frag_list_size = 0;
+ unsigned int skb_cnt = 1;
while (skb->prev) {
struct sk_buff *prev = skb->prev;
frag_list_size += skb->len;
skb->prev = NULL;
skb = prev;
- *count += 1;
+ skb_cnt++;
}
skb_shinfo(skb)->frag_list = skb->next;
@@ -1155,68 +1279,59 @@ static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
skb->len += frag_list_size;
skb->data_len += frag_list_size;
skb->truesize += frag_list_size;
+ IXGBE_RSC_CB(skb)->skb_cnt = skb_cnt;
+
return skb;
}
-struct ixgbe_rsc_cb {
- dma_addr_t dma;
- bool delay_unmap;
-};
-
-#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
+static inline bool ixgbe_get_rsc_state(union ixgbe_adv_rx_desc *rx_desc)
+{
+ return !!(le32_to_cpu(rx_desc->wb.lower.lo_dword.data) &
+ IXGBE_RXDADV_RSCCNT_MASK);
+}
-static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *rx_ring,
int *work_done, int work_to_do)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
- 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, rsc_count = 0;
- u32 len, staterr;
- u16 hdr_info;
- bool cleaned = false;
- int cleaned_count = 0;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ const int current_node = numa_node_id();
#ifdef IXGBE_FCOE
int ddp_bytes = 0;
#endif /* IXGBE_FCOE */
+ u32 staterr;
+ u16 i;
+ u16 cleaned_count = 0;
+ bool pkt_is_rsc = false;
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
- rx_buffer_info = &rx_ring->rx_buffer_info[i];
while (staterr & IXGBE_RXD_STAT_DD) {
u32 upper_len = 0;
- if (*work_done >= work_to_do)
- break;
- (*work_done)++;
rmb(); /* read descriptor and rx_buffer_info after status DD */
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
- hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc));
- len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
- IXGBE_RXDADV_HDRBUFLEN_SHIFT;
- upper_len = le16_to_cpu(rx_desc->wb.upper.length);
- if ((len > IXGBE_RX_HDR_SIZE) ||
- (upper_len && !(hdr_info & IXGBE_RXDADV_SPH)))
- len = IXGBE_RX_HDR_SIZE;
- } else {
- len = le16_to_cpu(rx_desc->wb.upper.length);
- }
- cleaned = true;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
skb = rx_buffer_info->skb;
- prefetch(skb->data);
rx_buffer_info->skb = NULL;
+ prefetch(skb->data);
+
+ if (ring_is_rsc_enabled(rx_ring))
+ pkt_is_rsc = ixgbe_get_rsc_state(rx_desc);
+ /* if this is a skb from previous receive DMA will be 0 */
if (rx_buffer_info->dma) {
- if ((adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
- (!(staterr & IXGBE_RXD_STAT_EOP)) &&
- (!(skb->prev))) {
+ u16 hlen;
+ if (pkt_is_rsc &&
+ !(staterr & IXGBE_RXD_STAT_EOP) &&
+ !skb->prev) {
/*
* When HWRSC is enabled, delay unmapping
* of the first packet. It carries the
@@ -1227,29 +1342,42 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
IXGBE_RSC_CB(skb)->delay_unmap = true;
IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
} else {
- dma_unmap_single(&pdev->dev,
+ dma_unmap_single(rx_ring->dev,
rx_buffer_info->dma,
rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
}
rx_buffer_info->dma = 0;
- skb_put(skb, len);
+
+ if (ring_is_ps_enabled(rx_ring)) {
+ hlen = ixgbe_get_hlen(rx_desc);
+ upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+ } else {
+ hlen = le16_to_cpu(rx_desc->wb.upper.length);
+ }
+
+ skb_put(skb, hlen);
+ } else {
+ /* assume packet split since header is unmapped */
+ upper_len = le16_to_cpu(rx_desc->wb.upper.length);
}
if (upper_len) {
- dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
- PAGE_SIZE / 2, DMA_FROM_DEVICE);
+ dma_unmap_page(rx_ring->dev,
+ rx_buffer_info->page_dma,
+ PAGE_SIZE / 2,
+ DMA_FROM_DEVICE);
rx_buffer_info->page_dma = 0;
skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
rx_buffer_info->page,
rx_buffer_info->page_offset,
upper_len);
- if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
- (page_count(rx_buffer_info->page) != 1))
- rx_buffer_info->page = NULL;
- else
+ if ((page_count(rx_buffer_info->page) == 1) &&
+ (page_to_nid(rx_buffer_info->page) == current_node))
get_page(rx_buffer_info->page);
+ else
+ rx_buffer_info->page = NULL;
skb->len += upper_len;
skb->data_len += upper_len;
@@ -1264,10 +1392,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
prefetch(next_rxd);
cleaned_count++;
- if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
- rsc_count = ixgbe_get_rsc_count(rx_desc);
-
- if (rsc_count) {
+ if (pkt_is_rsc) {
u32 nextp = (staterr & IXGBE_RXDADV_NEXTP_MASK) >>
IXGBE_RXDADV_NEXTP_SHIFT;
next_buffer = &rx_ring->rx_buffer_info[nextp];
@@ -1275,32 +1400,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
next_buffer = &rx_ring->rx_buffer_info[i];
}
- if (staterr & IXGBE_RXD_STAT_EOP) {
- if (skb->prev)
- skb = ixgbe_transform_rsc_queue(skb,
- &(rx_ring->rsc_count));
- if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
- if (IXGBE_RSC_CB(skb)->delay_unmap) {
- dma_unmap_single(&pdev->dev,
- IXGBE_RSC_CB(skb)->dma,
- rx_ring->rx_buf_len,
- DMA_FROM_DEVICE);
- IXGBE_RSC_CB(skb)->dma = 0;
- IXGBE_RSC_CB(skb)->delay_unmap = false;
- }
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
- rx_ring->rsc_count +=
- skb_shinfo(skb)->nr_frags;
- else
- rx_ring->rsc_count++;
- rx_ring->rsc_flush++;
- }
- u64_stats_update_begin(&rx_ring->syncp);
- rx_ring->stats.packets++;
- rx_ring->stats.bytes += skb->len;
- u64_stats_update_end(&rx_ring->syncp);
- } else {
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+ if (!(staterr & IXGBE_RXD_STAT_EOP)) {
+ if (ring_is_ps_enabled(rx_ring)) {
rx_buffer_info->skb = next_buffer->skb;
rx_buffer_info->dma = next_buffer->dma;
next_buffer->skb = skb;
@@ -1309,12 +1410,45 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
skb->next = next_buffer->skb;
skb->next->prev = skb;
}
- rx_ring->non_eop_descs++;
+ rx_ring->rx_stats.non_eop_descs++;
goto next_desc;
}
+ if (skb->prev) {
+ skb = ixgbe_transform_rsc_queue(skb);
+ /* if we got here without RSC the packet is invalid */
+ if (!pkt_is_rsc) {
+ __pskb_trim(skb, 0);
+ rx_buffer_info->skb = skb;
+ goto next_desc;
+ }
+ }
+
+ if (ring_is_rsc_enabled(rx_ring)) {
+ if (IXGBE_RSC_CB(skb)->delay_unmap) {
+ dma_unmap_single(rx_ring->dev,
+ IXGBE_RSC_CB(skb)->dma,
+ rx_ring->rx_buf_len,
+ DMA_FROM_DEVICE);
+ IXGBE_RSC_CB(skb)->dma = 0;
+ IXGBE_RSC_CB(skb)->delay_unmap = false;
+ }
+ }
+ if (pkt_is_rsc) {
+ if (ring_is_ps_enabled(rx_ring))
+ rx_ring->rx_stats.rsc_count +=
+ skb_shinfo(skb)->nr_frags;
+ else
+ rx_ring->rx_stats.rsc_count +=
+ IXGBE_RSC_CB(skb)->skb_cnt;
+ rx_ring->rx_stats.rsc_flush++;
+ }
+
+ /* ERR_MASK will only have valid bits if EOP set */
if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) {
- dev_kfree_skb_irq(skb);
+ /* trim packet back to size 0 and recycle it */
+ __pskb_trim(skb, 0);
+ rx_buffer_info->skb = skb;
goto next_desc;
}
@@ -1324,7 +1458,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
total_rx_bytes += skb->len;
total_rx_packets++;
- skb->protocol = eth_type_trans(skb, adapter->netdev);
+ skb->protocol = eth_type_trans(skb, rx_ring->netdev);
#ifdef IXGBE_FCOE
/* if ddp, not passing to ULD unless for FCP_RSP or error */
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
@@ -1338,16 +1472,18 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
next_desc:
rx_desc->wb.upper.status_error = 0;
+ (*work_done)++;
+ if (*work_done >= work_to_do)
+ break;
+
/* 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);
+ ixgbe_alloc_rx_buffers(rx_ring, cleaned_count);
cleaned_count = 0;
}
/* use prefetched values */
rx_desc = next_rxd;
- rx_buffer_info = &rx_ring->rx_buffer_info[i];
-
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
}
@@ -1355,14 +1491,14 @@ next_desc:
cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
if (cleaned_count)
- ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ ixgbe_alloc_rx_buffers(rx_ring, cleaned_count);
#ifdef IXGBE_FCOE
/* include DDPed FCoE data */
if (ddp_bytes > 0) {
unsigned int mss;
- mss = adapter->netdev->mtu - sizeof(struct fcoe_hdr) -
+ mss = rx_ring->netdev->mtu - sizeof(struct fcoe_hdr) -
sizeof(struct fc_frame_header) -
sizeof(struct fcoe_crc_eof);
if (mss > 512)
@@ -1374,8 +1510,10 @@ next_desc:
rx_ring->total_packets += total_rx_packets;
rx_ring->total_bytes += total_rx_bytes;
-
- return cleaned;
+ u64_stats_update_begin(&rx_ring->syncp);
+ rx_ring->stats.packets += total_rx_packets;
+ rx_ring->stats.bytes += total_rx_bytes;
+ u64_stats_update_end(&rx_ring->syncp);
}
static int ixgbe_clean_rxonly(struct napi_struct *, int);
@@ -1389,7 +1527,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *, int);
static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
{
struct ixgbe_q_vector *q_vector;
- int i, j, q_vectors, v_idx, r_idx;
+ int i, q_vectors, v_idx, r_idx;
u32 mask;
q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
@@ -1405,8 +1543,8 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- j = adapter->rx_ring[r_idx]->reg_idx;
- ixgbe_set_ivar(adapter, 0, j, v_idx);
+ u8 reg_idx = adapter->rx_ring[r_idx]->reg_idx;
+ ixgbe_set_ivar(adapter, 0, reg_idx, v_idx);
r_idx = find_next_bit(q_vector->rxr_idx,
adapter->num_rx_queues,
r_idx + 1);
@@ -1415,8 +1553,8 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- j = adapter->tx_ring[r_idx]->reg_idx;
- ixgbe_set_ivar(adapter, 1, j, v_idx);
+ u8 reg_idx = adapter->tx_ring[r_idx]->reg_idx;
+ ixgbe_set_ivar(adapter, 1, reg_idx, v_idx);
r_idx = find_next_bit(q_vector->txr_idx,
adapter->num_tx_queues,
r_idx + 1);
@@ -1447,11 +1585,19 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
}
}
- if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
ixgbe_set_ivar(adapter, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
v_idx);
- else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
ixgbe_set_ivar(adapter, -1, 1, v_idx);
+ break;
+
+ default:
+ break;
+ }
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
/* set up to autoclear timer, and the vectors */
@@ -1547,12 +1693,15 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
int v_idx = q_vector->v_idx;
u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr);
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
/* must write high and low 16 bits to reset counter */
itr_reg |= (itr_reg << 16);
- } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
/*
- * 82599 can support a value of zero, so allow it for
+ * 82599 and X540 can support a value of zero, so allow it for
* max interrupt rate, but there is an errata where it can
* not be zero with RSC
*/
@@ -1565,6 +1714,9 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
* immediate assertion of the interrupt
*/
itr_reg |= IXGBE_EITR_CNT_WDIS;
+ break;
+ default:
+ break;
}
IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg);
}
@@ -1572,14 +1724,13 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
+ int i, r_idx;
u32 new_itr;
u8 current_itr, ret_itr;
- int i, r_idx;
- struct ixgbe_ring *rx_ring, *tx_ring;
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- tx_ring = adapter->tx_ring[r_idx];
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
q_vector->tx_itr,
tx_ring->total_packets,
@@ -1594,7 +1745,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- rx_ring = adapter->rx_ring[r_idx];
+ struct ixgbe_ring *rx_ring = adapter->rx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
q_vector->rx_itr,
rx_ring->total_packets,
@@ -1625,7 +1776,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
if (new_itr != q_vector->eitr) {
/* do an exponential smoothing */
- new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
+ new_itr = ((q_vector->eitr * 9) + new_itr)/10;
/* save the algorithm value here, not the smoothed one */
q_vector->eitr = new_itr;
@@ -1693,17 +1844,18 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
{
struct ixgbe_hw *hw = &adapter->hw;
+ if (eicr & IXGBE_EICR_GPI_SDP2) {
+ /* Clear the interrupt */
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ schedule_work(&adapter->sfp_config_module_task);
+ }
+
if (eicr & IXGBE_EICR_GPI_SDP1) {
/* Clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
- schedule_work(&adapter->multispeed_fiber_task);
- } else if (eicr & IXGBE_EICR_GPI_SDP2) {
- /* Clear the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
- schedule_work(&adapter->sfp_config_module_task);
- } else {
- /* Interrupt isn't for us... */
- return;
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ schedule_work(&adapter->multispeed_fiber_task);
}
}
@@ -1743,16 +1895,16 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
if (eicr & IXGBE_EICR_MAILBOX)
ixgbe_msg_task(adapter);
- if (hw->mac.type == ixgbe_mac_82598EB)
- ixgbe_check_fan_failure(adapter, eicr);
-
- if (hw->mac.type == ixgbe_mac_82599EB) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
ixgbe_check_sfp_event(adapter, eicr);
- adapter->interrupt_event = eicr;
if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
- ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
+ ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
+ adapter->interrupt_event = eicr;
schedule_work(&adapter->check_overtemp_task);
-
+ }
+ /* now fallthrough to handle Flow Director */
+ case ixgbe_mac_X540:
/* Handle Flow Director Full threshold interrupt */
if (eicr & IXGBE_EICR_FLOW_DIR) {
int i;
@@ -1762,12 +1914,18 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
for (i = 0; i < adapter->num_tx_queues; i++) {
struct ixgbe_ring *tx_ring =
adapter->tx_ring[i];
- if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE,
- &tx_ring->reinit_state))
+ if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
+ &tx_ring->state))
schedule_work(&adapter->fdir_reinit_task);
}
}
+ break;
+ default:
+ break;
}
+
+ ixgbe_check_fan_failure(adapter, eicr);
+
if (!test_bit(__IXGBE_DOWN, &adapter->state))
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
@@ -1778,15 +1936,24 @@ static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
u64 qmask)
{
u32 mask;
+ struct ixgbe_hw *hw = &adapter->hw;
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
- } else {
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
mask = (qmask & 0xFFFFFFFF);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
mask = (qmask >> 32);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
+ break;
+ default:
+ break;
}
/* skip the flush */
}
@@ -1795,15 +1962,24 @@ static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
u64 qmask)
{
u32 mask;
+ struct ixgbe_hw *hw = &adapter->hw;
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask);
- } else {
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
mask = (qmask & 0xFFFFFFFF);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), mask);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
mask = (qmask >> 32);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), mask);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask);
+ break;
+ default:
+ break;
}
/* skip the flush */
}
@@ -1846,8 +2022,13 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
int r_idx;
int i;
+#ifdef CONFIG_IXGBE_DCA
+ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+ ixgbe_update_dca(q_vector);
+#endif
+
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
- for (i = 0; i < q_vector->rxr_count; i++) {
+ for (i = 0; i < q_vector->rxr_count; i++) {
rx_ring = adapter->rx_ring[r_idx];
rx_ring->total_bytes = 0;
rx_ring->total_packets = 0;
@@ -1858,7 +2039,6 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
if (!q_vector->rxr_count)
return IRQ_HANDLED;
- /* disable interrupts on this vector only */
/* EIAM disabled interrupts (on this vector) for us */
napi_schedule(&q_vector->napi);
@@ -1917,13 +2097,14 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
int work_done = 0;
long r_idx;
- r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
- rx_ring = adapter->rx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_rx_dca(adapter, rx_ring);
+ ixgbe_update_dca(q_vector);
#endif
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ rx_ring = adapter->rx_ring[r_idx];
+
ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
/* If all Rx work done, exit the polling mode */
@@ -1957,13 +2138,14 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
long r_idx;
bool tx_clean_complete = true;
+#ifdef CONFIG_IXGBE_DCA
+ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+ ixgbe_update_dca(q_vector);
+#endif
+
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
ring = adapter->tx_ring[r_idx];
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_tx_dca(adapter, ring);
-#endif
tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring);
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
r_idx + 1);
@@ -1976,10 +2158,6 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
ring = adapter->rx_ring[r_idx];
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_rx_dca(adapter, ring);
-#endif
ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget);
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
r_idx + 1);
@@ -2018,13 +2196,14 @@ static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
int work_done = 0;
long r_idx;
- r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
- tx_ring = adapter->tx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_tx_dca(adapter, tx_ring);
+ ixgbe_update_dca(q_vector);
#endif
+ r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+ tx_ring = adapter->tx_ring[r_idx];
+
if (!ixgbe_clean_tx_irq(q_vector, tx_ring))
work_done = budget;
@@ -2045,24 +2224,27 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
int r_idx)
{
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
+ struct ixgbe_ring *rx_ring = a->rx_ring[r_idx];
set_bit(r_idx, q_vector->rxr_idx);
q_vector->rxr_count++;
+ rx_ring->q_vector = q_vector;
}
static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
int t_idx)
{
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
+ struct ixgbe_ring *tx_ring = a->tx_ring[t_idx];
set_bit(t_idx, q_vector->txr_idx);
q_vector->txr_count++;
+ tx_ring->q_vector = q_vector;
}
/**
* ixgbe_map_rings_to_vectors - Maps descriptor rings to vectors
* @adapter: board private structure to initialize
- * @vectors: allotted vector count for descriptor rings
*
* This function maps descriptor rings to the queue-specific vectors
* we were allotted through the MSI-X enabling code. Ideally, we'd have
@@ -2070,9 +2252,9 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
* group the rings as "efficiently" as possible. You would add new
* mapping configurations in here.
**/
-static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
- int vectors)
+static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter)
{
+ int q_vectors;
int v_start = 0;
int rxr_idx = 0, txr_idx = 0;
int rxr_remaining = adapter->num_rx_queues;
@@ -2085,11 +2267,13 @@ static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
goto out;
+ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
/*
* The ideal configuration...
* We have enough vectors to map one per queue.
*/
- if (vectors == adapter->num_rx_queues + adapter->num_tx_queues) {
+ if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) {
for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++)
map_vector_to_rxq(adapter, v_start, rxr_idx);
@@ -2105,23 +2289,20 @@ static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
* multiple queues per vector.
*/
/* Re-adjusting *qpv takes care of the remainder. */
- for (i = v_start; i < vectors; i++) {
- rqpv = DIV_ROUND_UP(rxr_remaining, vectors - i);
+ for (i = v_start; i < q_vectors; i++) {
+ rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i);
for (j = 0; j < rqpv; j++) {
map_vector_to_rxq(adapter, i, rxr_idx);
rxr_idx++;
rxr_remaining--;
}
- }
- for (i = v_start; i < vectors; i++) {
- tqpv = DIV_ROUND_UP(txr_remaining, vectors - i);
+ tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i);
for (j = 0; j < tqpv; j++) {
map_vector_to_txq(adapter, i, txr_idx);
txr_idx++;
txr_remaining--;
}
}
-
out:
return err;
}
@@ -2143,30 +2324,36 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
/* Decrement for Other and TCP Timer vectors */
q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
- /* Map the Tx/Rx rings to the vectors we were allotted. */
- err = ixgbe_map_rings_to_vectors(adapter, q_vectors);
+ err = ixgbe_map_rings_to_vectors(adapter);
if (err)
- goto out;
+ return err;
-#define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \
- (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
- &ixgbe_msix_clean_many)
+#define SET_HANDLER(_v) (((_v)->rxr_count && (_v)->txr_count) \
+ ? &ixgbe_msix_clean_many : \
+ (_v)->rxr_count ? &ixgbe_msix_clean_rx : \
+ (_v)->txr_count ? &ixgbe_msix_clean_tx : \
+ NULL)
for (vector = 0; vector < q_vectors; vector++) {
- handler = SET_HANDLER(adapter->q_vector[vector]);
+ struct ixgbe_q_vector *q_vector = adapter->q_vector[vector];
+ handler = SET_HANDLER(q_vector);
if (handler == &ixgbe_msix_clean_rx) {
- sprintf(adapter->name[vector], "%s-%s-%d",
- netdev->name, "rx", ri++);
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+ "%s-%s-%d", netdev->name, "rx", ri++);
} else if (handler == &ixgbe_msix_clean_tx) {
- sprintf(adapter->name[vector], "%s-%s-%d",
- netdev->name, "tx", ti++);
- } else
- sprintf(adapter->name[vector], "%s-%s-%d",
- netdev->name, "TxRx", vector);
-
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+ "%s-%s-%d", netdev->name, "tx", ti++);
+ } else if (handler == &ixgbe_msix_clean_many) {
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+ "%s-%s-%d", netdev->name, "TxRx", ri++);
+ ti++;
+ } else {
+ /* skip this unused q_vector */
+ continue;
+ }
err = request_irq(adapter->msix_entries[vector].vector,
- handler, 0, adapter->name[vector],
- adapter->q_vector[vector]);
+ handler, 0, q_vector->name,
+ q_vector);
if (err) {
e_err(probe, "request_irq failed for MSIX interrupt "
"Error: %d\n", err);
@@ -2174,9 +2361,9 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
}
}
- sprintf(adapter->name[vector], "%s:lsc", netdev->name);
+ sprintf(adapter->lsc_int_name, "%s:lsc", netdev->name);
err = request_irq(adapter->msix_entries[vector].vector,
- ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
+ ixgbe_msix_lsc, 0, adapter->lsc_int_name, netdev);
if (err) {
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
goto free_queue_irqs;
@@ -2192,17 +2379,16 @@ free_queue_irqs:
pci_disable_msix(adapter->pdev);
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
-out:
return err;
}
static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
{
struct ixgbe_q_vector *q_vector = adapter->q_vector[0];
- u8 current_itr;
- u32 new_itr = q_vector->eitr;
struct ixgbe_ring *rx_ring = adapter->rx_ring[0];
struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
+ u32 new_itr = q_vector->eitr;
+ u8 current_itr;
q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr,
q_vector->tx_itr,
@@ -2232,9 +2418,9 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
if (new_itr != q_vector->eitr) {
/* do an exponential smoothing */
- new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
+ new_itr = ((q_vector->eitr * 9) + new_itr)/10;
- /* save the algorithm value here, not the smoothed one */
+ /* save the algorithm value here */
q_vector->eitr = new_itr;
ixgbe_write_eitr(q_vector);
@@ -2255,12 +2441,17 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
mask |= IXGBE_EIMS_GPI_SDP0;
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
mask |= IXGBE_EIMS_GPI_SDP1;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
mask |= IXGBE_EIMS_ECC;
mask |= IXGBE_EIMS_GPI_SDP1;
mask |= IXGBE_EIMS_GPI_SDP2;
if (adapter->num_vfs)
mask |= IXGBE_EIMS_MAILBOX;
+ break;
+ default:
+ break;
}
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
@@ -2316,13 +2507,20 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
if (eicr & IXGBE_EICR_LSC)
ixgbe_check_lsc(adapter);
- if (hw->mac.type == ixgbe_mac_82599EB)
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
ixgbe_check_sfp_event(adapter, eicr);
+ if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+ ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
+ adapter->interrupt_event = eicr;
+ schedule_work(&adapter->check_overtemp_task);
+ }
+ break;
+ default:
+ break;
+ }
ixgbe_check_fan_failure(adapter, eicr);
- if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
- ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)))
- schedule_work(&adapter->check_overtemp_task);
if (napi_schedule_prep(&(q_vector->napi))) {
adapter->tx_ring[0]->total_packets = 0;
@@ -2415,14 +2613,20 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
**/
static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
{
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
- } else {
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
if (adapter->num_vfs > 32)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0);
+ break;
+ default:
+ break;
}
IXGBE_WRITE_FLUSH(&adapter->hw);
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -2468,7 +2672,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
u64 tdba = ring->dma;
int wait_loop = 10;
u32 txdctl;
- u16 reg_idx = ring->reg_idx;
+ u8 reg_idx = ring->reg_idx;
/* disable queue to avoid issues while updating state */
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
@@ -2483,8 +2687,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
ring->count * sizeof(union ixgbe_adv_tx_desc));
IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
- ring->head = IXGBE_TDH(reg_idx);
- ring->tail = IXGBE_TDT(reg_idx);
+ ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx);
/* configure fetching thresholds */
if (adapter->rx_itr_setting == 0) {
@@ -2500,7 +2703,16 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
}
/* reinitialize flowdirector state */
- set_bit(__IXGBE_FDIR_INIT_DONE, &ring->reinit_state);
+ if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) &&
+ adapter->atr_sample_rate) {
+ ring->atr_sample_rate = adapter->atr_sample_rate;
+ ring->atr_count = 0;
+ set_bit(__IXGBE_TX_FDIR_INIT_DONE, &ring->state);
+ } else {
+ ring->atr_sample_rate = 0;
+ }
+
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
/* enable queue */
txdctl |= IXGBE_TXDCTL_ENABLE;
@@ -2591,16 +2803,22 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
struct ixgbe_ring *rx_ring)
{
u32 srrctl;
- int index;
- struct ixgbe_ring_feature *feature = adapter->ring_feature;
+ u8 reg_idx = rx_ring->reg_idx;
- index = rx_ring->reg_idx;
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
- unsigned long mask;
- mask = (unsigned long) feature[RING_F_RSS].mask;
- index = index & mask;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB: {
+ struct ixgbe_ring_feature *feature = adapter->ring_feature;
+ const int mask = feature[RING_F_RSS].mask;
+ reg_idx = reg_idx & mask;
+ }
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ default:
+ break;
}
- srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(index));
+
+ srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(reg_idx));
srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
@@ -2610,7 +2828,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
srrctl |= (IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
IXGBE_SRRCTL_BSIZEHDR_MASK;
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+ if (ring_is_ps_enabled(rx_ring)) {
#if (PAGE_SIZE / 2) > IXGBE_MAX_RXBUFFER
srrctl |= IXGBE_MAX_RXBUFFER >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
#else
@@ -2623,7 +2841,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
}
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(reg_idx), srrctl);
}
static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
@@ -2693,19 +2911,36 @@ static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
}
/**
+ * ixgbe_clear_rscctl - disable RSC for the indicated ring
+ * @adapter: address of board private structure
+ * @ring: structure containing ring specific data
+ **/
+void ixgbe_clear_rscctl(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 rscctrl;
+ u8 reg_idx = ring->reg_idx;
+
+ rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(reg_idx));
+ rscctrl &= ~IXGBE_RSCCTL_RSCEN;
+ IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(reg_idx), rscctrl);
+}
+
+/**
* ixgbe_configure_rscctl - enable RSC for the indicated ring
* @adapter: address of board private structure
* @index: index of ring to set
**/
-static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
+void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
struct ixgbe_ring *ring)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 rscctrl;
int rx_buf_len;
- u16 reg_idx = ring->reg_idx;
+ u8 reg_idx = ring->reg_idx;
- if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
+ if (!ring_is_rsc_enabled(ring))
return;
rx_buf_len = ring->rx_buf_len;
@@ -2716,7 +2951,7 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
* total size of max desc * buf_len is not greater
* than 65535
*/
- if (ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+ if (ring_is_ps_enabled(ring)) {
#if (MAX_SKB_FRAGS > 16)
rscctrl |= IXGBE_RSCCTL_MAXDESC_16;
#elif (MAX_SKB_FRAGS > 8)
@@ -2769,9 +3004,9 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
struct ixgbe_ring *ring)
{
struct ixgbe_hw *hw = &adapter->hw;
- int reg_idx = ring->reg_idx;
int wait_loop = IXGBE_MAX_RX_DESC_POLL;
u32 rxdctl;
+ u8 reg_idx = ring->reg_idx;
/* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
if (hw->mac.type == ixgbe_mac_82598EB &&
@@ -2789,19 +3024,47 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
}
}
+void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int wait_loop = IXGBE_MAX_RX_DESC_POLL;
+ u32 rxdctl;
+ u8 reg_idx = ring->reg_idx;
+
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+ rxdctl &= ~IXGBE_RXDCTL_ENABLE;
+
+ /* write value back with RXDCTL.ENABLE bit cleared */
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+
+ if (hw->mac.type == ixgbe_mac_82598EB &&
+ !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+ return;
+
+ /* the hardware may take up to 100us to really disable the rx queue */
+ do {
+ udelay(10);
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+ } while (--wait_loop && (rxdctl & IXGBE_RXDCTL_ENABLE));
+
+ if (!wait_loop) {
+ e_err(drv, "RXDCTL.ENABLE on Rx queue %d not cleared within "
+ "the polling period\n", reg_idx);
+ }
+}
+
void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
struct ixgbe_ring *ring)
{
struct ixgbe_hw *hw = &adapter->hw;
u64 rdba = ring->dma;
u32 rxdctl;
- u16 reg_idx = ring->reg_idx;
+ u8 reg_idx = ring->reg_idx;
/* disable queue to avoid issues while updating state */
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx),
- rxdctl & ~IXGBE_RXDCTL_ENABLE);
- IXGBE_WRITE_FLUSH(hw);
+ ixgbe_disable_rx_queue(adapter, ring);
IXGBE_WRITE_REG(hw, IXGBE_RDBAL(reg_idx), (rdba & DMA_BIT_MASK(32)));
IXGBE_WRITE_REG(hw, IXGBE_RDBAH(reg_idx), (rdba >> 32));
@@ -2809,8 +3072,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
ring->count * sizeof(union ixgbe_adv_rx_desc));
IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
- ring->head = IXGBE_RDH(reg_idx);
- ring->tail = IXGBE_RDT(reg_idx);
+ ring->tail = hw->hw_addr + IXGBE_RDT(reg_idx);
ixgbe_configure_srrctl(adapter, ring);
ixgbe_configure_rscctl(adapter, ring);
@@ -2832,7 +3094,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
- ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
+ ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));
}
static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
@@ -2898,6 +3160,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
/* enable Tx loopback for VF/PF communication */
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+ /* Enable MAC Anti-Spoofing */
+ hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0),
+ adapter->num_vfs);
}
static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
@@ -2955,24 +3220,32 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
rx_ring->rx_buf_len = rx_buf_len;
if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)
- rx_ring->flags |= IXGBE_RING_RX_PS_ENABLED;
+ set_ring_ps_enabled(rx_ring);
+ else
+ clear_ring_ps_enabled(rx_ring);
+
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
+ set_ring_rsc_enabled(rx_ring);
else
- rx_ring->flags &= ~IXGBE_RING_RX_PS_ENABLED;
+ clear_ring_rsc_enabled(rx_ring);
#ifdef IXGBE_FCOE
if (netdev->features & NETIF_F_FCOE_MTU) {
struct ixgbe_ring_feature *f;
f = &adapter->ring_feature[RING_F_FCOE];
if ((i >= f->mask) && (i < f->mask + f->indices)) {
- rx_ring->flags &= ~IXGBE_RING_RX_PS_ENABLED;
+ clear_ring_ps_enabled(rx_ring);
if (rx_buf_len < IXGBE_FCOE_JUMBO_FRAME_SIZE)
rx_ring->rx_buf_len =
IXGBE_FCOE_JUMBO_FRAME_SIZE;
+ } else if (!ring_is_rsc_enabled(rx_ring) &&
+ !ring_is_ps_enabled(rx_ring)) {
+ rx_ring->rx_buf_len =
+ IXGBE_FCOE_JUMBO_FRAME_SIZE;
}
}
#endif /* IXGBE_FCOE */
}
-
}
static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter)
@@ -2995,6 +3268,7 @@ static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter)
rdrxctl |= IXGBE_RDRXCTL_MVMEN;
break;
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
/* Disable RSC for ACK packets */
IXGBE_WRITE_REG(hw, IXGBE_RSCDBU,
(IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU)));
@@ -3122,6 +3396,7 @@ static void ixgbe_vlan_strip_disable(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
break;
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i]->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
@@ -3151,6 +3426,7 @@ static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
break;
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i]->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
@@ -3348,8 +3624,6 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
- u32 txdctl;
- int i, j;
if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) {
if (hw->mac.type == ixgbe_mac_82598EB)
@@ -3365,25 +3639,18 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE);
#endif
- ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame,
+ ixgbe_dcb_calculate_tc_credits(hw, &adapter->dcb_cfg, max_frame,
DCB_TX_CONFIG);
- ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame,
+ ixgbe_dcb_calculate_tc_credits(hw, &adapter->dcb_cfg, max_frame,
DCB_RX_CONFIG);
- /* reconfigure the hardware */
- ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg);
-
- for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i]->reg_idx;
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
- /* PThresh workaround for Tx hang with DFP enabled. */
- txdctl |= 32;
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
- }
/* Enable VLAN tag insert/strip */
adapter->netdev->features |= NETIF_F_HW_VLAN_RX;
hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
+
+ /* reconfigure the hardware */
+ ixgbe_dcb_hw_config(hw, &adapter->dcb_cfg);
}
#endif
@@ -3515,8 +3782,9 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
case ixgbe_mac_82598EB:
IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
break;
- default:
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ default:
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
break;
@@ -3560,13 +3828,24 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
else
ixgbe_configure_msi_and_legacy(adapter);
- /* enable the optics */
- if (hw->phy.multispeed_fiber)
+ /* enable the optics for both mult-speed fiber and 82599 SFP+ fiber */
+ if (hw->mac.ops.enable_tx_laser &&
+ ((hw->phy.multispeed_fiber) ||
+ ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
+ (hw->mac.type == ixgbe_mac_82599EB))))
hw->mac.ops.enable_tx_laser(hw);
clear_bit(__IXGBE_DOWN, &adapter->state);
ixgbe_napi_enable_all(adapter);
+ if (ixgbe_is_sfp(hw)) {
+ ixgbe_sfp_link_config(adapter);
+ } else {
+ err = ixgbe_non_sfp_link_config(hw);
+ if (err)
+ e_err(probe, "link_config FAILED %d\n", err);
+ }
+
/* clear any pending interrupts, may auto mask */
IXGBE_READ_REG(hw, IXGBE_EICR);
ixgbe_irq_enable(adapter, true, true);
@@ -3589,26 +3868,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
* If we're not hot-pluggable SFP+, we just need to configure link
* and bring it up.
*/
- if (hw->phy.type == ixgbe_phy_unknown) {
- err = hw->phy.ops.identify(hw);
- if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- /*
- * Take the device down and schedule the sfp tasklet
- * which will unregister_netdev and log it.
- */
- ixgbe_down(adapter);
- schedule_work(&adapter->sfp_config_module_task);
- return err;
- }
- }
-
- if (ixgbe_is_sfp(hw)) {
- ixgbe_sfp_link_config(adapter);
- } else {
- err = ixgbe_non_sfp_link_config(hw);
- if (err)
- e_err(probe, "link_config FAILED %d\n", err);
- }
+ if (hw->phy.type == ixgbe_phy_unknown)
+ schedule_work(&adapter->sfp_config_module_task);
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
@@ -3686,15 +3947,13 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
/**
* 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)
+static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
{
- struct pci_dev *pdev = adapter->pdev;
+ struct device *dev = rx_ring->dev;
unsigned long size;
- unsigned int i;
+ u16 i;
/* ring already cleared, nothing to do */
if (!rx_ring->rx_buffer_info)
@@ -3706,7 +3965,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
rx_buffer_info = &rx_ring->rx_buffer_info[i];
if (rx_buffer_info->dma) {
- dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
+ dma_unmap_single(rx_ring->dev, rx_buffer_info->dma,
rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
rx_buffer_info->dma = 0;
@@ -3717,7 +3976,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
do {
struct sk_buff *this = skb;
if (IXGBE_RSC_CB(this)->delay_unmap) {
- dma_unmap_single(&pdev->dev,
+ dma_unmap_single(dev,
IXGBE_RSC_CB(this)->dma,
rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
@@ -3731,7 +3990,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
if (!rx_buffer_info->page)
continue;
if (rx_buffer_info->page_dma) {
- dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
+ dma_unmap_page(dev, rx_buffer_info->page_dma,
PAGE_SIZE / 2, DMA_FROM_DEVICE);
rx_buffer_info->page_dma = 0;
}
@@ -3748,24 +4007,17 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
-
- if (rx_ring->head)
- writel(0, adapter->hw.hw_addr + rx_ring->head);
- if (rx_ring->tail)
- writel(0, adapter->hw.hw_addr + rx_ring->tail);
}
/**
* 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)
+static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring)
{
struct ixgbe_tx_buffer *tx_buffer_info;
unsigned long size;
- unsigned int i;
+ u16 i;
/* ring already cleared, nothing to do */
if (!tx_ring->tx_buffer_info)
@@ -3774,7 +4026,7 @@ static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
/* 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);
+ ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
}
size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
@@ -3785,11 +4037,6 @@ static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
-
- if (tx_ring->head)
- writel(0, adapter->hw.hw_addr + tx_ring->head);
- if (tx_ring->tail)
- writel(0, adapter->hw.hw_addr + tx_ring->tail);
}
/**
@@ -3801,7 +4048,7 @@ static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- ixgbe_clean_rx_ring(adapter, adapter->rx_ring[i]);
+ ixgbe_clean_rx_ring(adapter->rx_ring[i]);
}
/**
@@ -3813,7 +4060,7 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- ixgbe_clean_tx_ring(adapter, adapter->tx_ring[i]);
+ ixgbe_clean_tx_ring(adapter->tx_ring[i]);
}
void ixgbe_down(struct ixgbe_adapter *adapter)
@@ -3822,7 +4069,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
u32 rxctrl;
u32 txdctl;
- int i, j;
+ int i;
int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
/* signal that we are down to the interrupt handler */
@@ -3845,7 +4092,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
- IXGBE_WRITE_FLUSH(hw);
+ /* disable all enabled rx queues */
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ /* this call also flushes the previous write */
+ ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
+
msleep(10);
netif_tx_stop_all_queues(netdev);
@@ -3880,26 +4131,36 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* disable transmits in the hardware now that interrupts are off */
for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i]->reg_idx;
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
+ u8 reg_idx = adapter->tx_ring[i]->reg_idx;
+ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
(txdctl & ~IXGBE_TXDCTL_ENABLE));
}
/* Disable the Tx DMA engine on 82599 */
- if (hw->mac.type == ixgbe_mac_82599EB)
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
(IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
~IXGBE_DMATXCTL_TE));
-
- /* power down the optics */
- if (hw->phy.multispeed_fiber)
- hw->mac.ops.disable_tx_laser(hw);
+ break;
+ default:
+ break;
+ }
/* clear n-tuple filters that are cached */
ethtool_ntuple_flush(netdev);
if (!pci_channel_offline(adapter->pdev))
ixgbe_reset(adapter);
+
+ /* power down the optics for multispeed fiber and 82599 SFP+ fiber */
+ if (hw->mac.ops.disable_tx_laser &&
+ ((hw->phy.multispeed_fiber) ||
+ ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
+ (hw->mac.type == ixgbe_mac_82599EB))))
+ hw->mac.ops.disable_tx_laser(hw);
+
ixgbe_clean_all_tx_rings(adapter);
ixgbe_clean_all_rx_rings(adapter);
@@ -3924,10 +4185,8 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
int tx_clean_complete, work_done = 0;
#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
- ixgbe_update_tx_dca(adapter, adapter->tx_ring[0]);
- ixgbe_update_rx_dca(adapter, adapter->rx_ring[0]);
- }
+ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+ ixgbe_update_dca(q_vector);
#endif
tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring[0]);
@@ -3955,6 +4214,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ adapter->tx_timeout_count++;
+
/* Do the reset outside of interrupt context */
schedule_work(&adapter->reset_task);
}
@@ -3969,8 +4230,6 @@ static void ixgbe_reset_task(struct work_struct *work)
test_bit(__IXGBE_RESETTING, &adapter->state))
return;
- adapter->tx_timeout_count++;
-
ixgbe_dump(adapter);
netdev_err(adapter->netdev, "Reset adapter\n");
ixgbe_reinit_locked(adapter);
@@ -4220,19 +4479,16 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter)
{
int i;
- bool ret = false;
- if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
- for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i]->reg_idx = i;
- for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i]->reg_idx = i;
- ret = true;
- } else {
- ret = false;
- }
+ if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
+ return false;
- return ret;
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ adapter->rx_ring[i]->reg_idx = i;
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ adapter->tx_ring[i]->reg_idx = i;
+
+ return true;
}
#ifdef CONFIG_IXGBE_DCB
@@ -4249,71 +4505,67 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
bool ret = false;
int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
- /* the number of queues is assumed to be symmetric */
- for (i = 0; i < dcb_i; i++) {
- adapter->rx_ring[i]->reg_idx = i << 3;
- adapter->tx_ring[i]->reg_idx = i << 2;
- }
- ret = true;
- } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- if (dcb_i == 8) {
- /*
- * Tx TC0 starts at: descriptor queue 0
- * Tx TC1 starts at: descriptor queue 32
- * Tx TC2 starts at: descriptor queue 64
- * Tx TC3 starts at: descriptor queue 80
- * Tx TC4 starts at: descriptor queue 96
- * Tx TC5 starts at: descriptor queue 104
- * Tx TC6 starts at: descriptor queue 112
- * Tx TC7 starts at: descriptor queue 120
- *
- * Rx TC0-TC7 are offset by 16 queues each
- */
- for (i = 0; i < 3; i++) {
- adapter->tx_ring[i]->reg_idx = i << 5;
- adapter->rx_ring[i]->reg_idx = i << 4;
- }
- for ( ; i < 5; i++) {
- adapter->tx_ring[i]->reg_idx =
- ((i + 2) << 4);
- adapter->rx_ring[i]->reg_idx = i << 4;
- }
- for ( ; i < dcb_i; i++) {
- adapter->tx_ring[i]->reg_idx =
- ((i + 8) << 3);
- adapter->rx_ring[i]->reg_idx = i << 4;
- }
+ if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED))
+ return false;
- ret = true;
- } else if (dcb_i == 4) {
- /*
- * Tx TC0 starts at: descriptor queue 0
- * Tx TC1 starts at: descriptor queue 64
- * Tx TC2 starts at: descriptor queue 96
- * Tx TC3 starts at: descriptor queue 112
- *
- * Rx TC0-TC3 are offset by 32 queues each
- */
- adapter->tx_ring[0]->reg_idx = 0;
- adapter->tx_ring[1]->reg_idx = 64;
- adapter->tx_ring[2]->reg_idx = 96;
- adapter->tx_ring[3]->reg_idx = 112;
- for (i = 0 ; i < dcb_i; i++)
- adapter->rx_ring[i]->reg_idx = i << 5;
-
- ret = true;
- } else {
- ret = false;
+ /* the number of queues is assumed to be symmetric */
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
+ for (i = 0; i < dcb_i; i++) {
+ adapter->rx_ring[i]->reg_idx = i << 3;
+ adapter->tx_ring[i]->reg_idx = i << 2;
+ }
+ ret = true;
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ if (dcb_i == 8) {
+ /*
+ * Tx TC0 starts at: descriptor queue 0
+ * Tx TC1 starts at: descriptor queue 32
+ * Tx TC2 starts at: descriptor queue 64
+ * Tx TC3 starts at: descriptor queue 80
+ * Tx TC4 starts at: descriptor queue 96
+ * Tx TC5 starts at: descriptor queue 104
+ * Tx TC6 starts at: descriptor queue 112
+ * Tx TC7 starts at: descriptor queue 120
+ *
+ * Rx TC0-TC7 are offset by 16 queues each
+ */
+ for (i = 0; i < 3; i++) {
+ adapter->tx_ring[i]->reg_idx = i << 5;
+ adapter->rx_ring[i]->reg_idx = i << 4;
}
- } else {
- ret = false;
+ for ( ; i < 5; i++) {
+ adapter->tx_ring[i]->reg_idx = ((i + 2) << 4);
+ adapter->rx_ring[i]->reg_idx = i << 4;
+ }
+ for ( ; i < dcb_i; i++) {
+ adapter->tx_ring[i]->reg_idx = ((i + 8) << 3);
+ adapter->rx_ring[i]->reg_idx = i << 4;
+ }
+ ret = true;
+ } else if (dcb_i == 4) {
+ /*
+ * Tx TC0 starts at: descriptor queue 0
+ * Tx TC1 starts at: descriptor queue 64
+ * Tx TC2 starts at: descriptor queue 96
+ * Tx TC3 starts at: descriptor queue 112
+ *
+ * Rx TC0-TC3 are offset by 32 queues each
+ */
+ adapter->tx_ring[0]->reg_idx = 0;
+ adapter->tx_ring[1]->reg_idx = 64;
+ adapter->tx_ring[2]->reg_idx = 96;
+ adapter->tx_ring[3]->reg_idx = 112;
+ for (i = 0 ; i < dcb_i; i++)
+ adapter->rx_ring[i]->reg_idx = i << 5;
+ ret = true;
}
- } else {
- ret = false;
+ break;
+ default:
+ break;
}
-
return ret;
}
#endif
@@ -4353,55 +4605,55 @@ static inline bool ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
*/
static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
{
- int i, fcoe_rx_i = 0, fcoe_tx_i = 0;
- bool ret = false;
struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE];
+ int i;
+ u8 fcoe_rx_i = 0, fcoe_tx_i = 0;
+
+ if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
+ return false;
- if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
#ifdef CONFIG_IXGBE_DCB
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- struct ixgbe_fcoe *fcoe = &adapter->fcoe;
+ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ struct ixgbe_fcoe *fcoe = &adapter->fcoe;
- ixgbe_cache_ring_dcb(adapter);
- /* find out queues in TC for FCoE */
- fcoe_rx_i = adapter->rx_ring[fcoe->tc]->reg_idx + 1;
- fcoe_tx_i = adapter->tx_ring[fcoe->tc]->reg_idx + 1;
- /*
- * In 82599, the number of Tx queues for each traffic
- * class for both 8-TC and 4-TC modes are:
- * TCs : TC0 TC1 TC2 TC3 TC4 TC5 TC6 TC7
- * 8 TCs: 32 32 16 16 8 8 8 8
- * 4 TCs: 64 64 32 32
- * We have max 8 queues for FCoE, where 8 the is
- * FCoE redirection table size. If TC for FCoE is
- * less than or equal to TC3, we have enough queues
- * to add max of 8 queues for FCoE, so we start FCoE
- * tx descriptor from the next one, i.e., reg_idx + 1.
- * If TC for FCoE is above TC3, implying 8 TC mode,
- * and we need 8 for FCoE, we have to take all queues
- * in that traffic class for FCoE.
- */
- if ((f->indices == IXGBE_FCRETA_SIZE) && (fcoe->tc > 3))
- fcoe_tx_i--;
- }
+ ixgbe_cache_ring_dcb(adapter);
+ /* find out queues in TC for FCoE */
+ fcoe_rx_i = adapter->rx_ring[fcoe->tc]->reg_idx + 1;
+ fcoe_tx_i = adapter->tx_ring[fcoe->tc]->reg_idx + 1;
+ /*
+ * In 82599, the number of Tx queues for each traffic
+ * class for both 8-TC and 4-TC modes are:
+ * TCs : TC0 TC1 TC2 TC3 TC4 TC5 TC6 TC7
+ * 8 TCs: 32 32 16 16 8 8 8 8
+ * 4 TCs: 64 64 32 32
+ * We have max 8 queues for FCoE, where 8 the is
+ * FCoE redirection table size. If TC for FCoE is
+ * less than or equal to TC3, we have enough queues
+ * to add max of 8 queues for FCoE, so we start FCoE
+ * Tx queue from the next one, i.e., reg_idx + 1.
+ * If TC for FCoE is above TC3, implying 8 TC mode,
+ * and we need 8 for FCoE, we have to take all queues
+ * in that traffic class for FCoE.
+ */
+ if ((f->indices == IXGBE_FCRETA_SIZE) && (fcoe->tc > 3))
+ fcoe_tx_i--;
+ }
#endif /* CONFIG_IXGBE_DCB */
- if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
- if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
- (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
- ixgbe_cache_ring_fdir(adapter);
- else
- ixgbe_cache_ring_rss(adapter);
+ if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
+ if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+ (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+ ixgbe_cache_ring_fdir(adapter);
+ else
+ ixgbe_cache_ring_rss(adapter);
- fcoe_rx_i = f->mask;
- fcoe_tx_i = f->mask;
- }
- for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) {
- adapter->rx_ring[f->mask + i]->reg_idx = fcoe_rx_i;
- adapter->tx_ring[f->mask + i]->reg_idx = fcoe_tx_i;
- }
- ret = true;
+ fcoe_rx_i = f->mask;
+ fcoe_tx_i = f->mask;
}
- return ret;
+ for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) {
+ adapter->rx_ring[f->mask + i]->reg_idx = fcoe_rx_i;
+ adapter->tx_ring[f->mask + i]->reg_idx = fcoe_tx_i;
+ }
+ return true;
}
#endif /* IXGBE_FCOE */
@@ -4470,65 +4722,55 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
**/
static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
{
- int i;
- int orig_node = adapter->node;
+ int rx = 0, tx = 0, nid = adapter->node;
- for (i = 0; i < adapter->num_tx_queues; i++) {
- struct ixgbe_ring *ring = adapter->tx_ring[i];
- if (orig_node == -1) {
- int cur_node = next_online_node(adapter->node);
- if (cur_node == MAX_NUMNODES)
- cur_node = first_online_node;
- adapter->node = cur_node;
- }
- ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
- adapter->node);
+ if (nid < 0 || !node_online(nid))
+ nid = first_online_node;
+
+ for (; tx < adapter->num_tx_queues; tx++) {
+ struct ixgbe_ring *ring;
+
+ ring = kzalloc_node(sizeof(*ring), GFP_KERNEL, nid);
if (!ring)
- ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
- goto err_tx_ring_allocation;
+ goto err_allocation;
ring->count = adapter->tx_ring_count;
- ring->queue_index = i;
- ring->numa_node = adapter->node;
+ ring->queue_index = tx;
+ ring->numa_node = nid;
+ ring->dev = &adapter->pdev->dev;
+ ring->netdev = adapter->netdev;
- adapter->tx_ring[i] = ring;
+ adapter->tx_ring[tx] = ring;
}
- /* Restore the adapter's original node */
- adapter->node = orig_node;
+ for (; rx < adapter->num_rx_queues; rx++) {
+ struct ixgbe_ring *ring;
- for (i = 0; i < adapter->num_rx_queues; i++) {
- struct ixgbe_ring *ring = adapter->rx_ring[i];
- if (orig_node == -1) {
- int cur_node = next_online_node(adapter->node);
- if (cur_node == MAX_NUMNODES)
- cur_node = first_online_node;
- adapter->node = cur_node;
- }
- ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
- adapter->node);
+ ring = kzalloc_node(sizeof(*ring), GFP_KERNEL, nid);
if (!ring)
- ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
- goto err_rx_ring_allocation;
+ goto err_allocation;
ring->count = adapter->rx_ring_count;
- ring->queue_index = i;
- ring->numa_node = adapter->node;
+ ring->queue_index = rx;
+ ring->numa_node = nid;
+ ring->dev = &adapter->pdev->dev;
+ ring->netdev = adapter->netdev;
- adapter->rx_ring[i] = ring;
+ adapter->rx_ring[rx] = ring;
}
- /* Restore the adapter's original node */
- adapter->node = orig_node;
-
ixgbe_cache_ring_register(adapter);
return 0;
-err_rx_ring_allocation:
- for (i = 0; i < adapter->num_tx_queues; i++)
- kfree(adapter->tx_ring[i]);
-err_tx_ring_allocation:
+err_allocation:
+ while (tx)
+ kfree(adapter->tx_ring[--tx]);
+
+ while (rx)
+ kfree(adapter->rx_ring[--rx]);
return -ENOMEM;
}
@@ -4579,6 +4821,12 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+ if (adapter->flags & (IXGBE_FLAG_FDIR_HASH_CAPABLE |
+ IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) {
+ e_err(probe,
+ "Flow Director is not supported while multiple "
+ "queues are disabled. Disabling Flow Director\n");
+ }
adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
adapter->atr_sample_rate = 0;
@@ -4750,6 +4998,11 @@ err_set_interrupt:
return err;
}
+static void ring_free_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct ixgbe_ring, rcu));
+}
+
/**
* ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
* @adapter: board private structure to clear interrupt scheme on
@@ -4766,10 +5019,18 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
adapter->tx_ring[i] = NULL;
}
for (i = 0; i < adapter->num_rx_queues; i++) {
- kfree(adapter->rx_ring[i]);
+ struct ixgbe_ring *ring = adapter->rx_ring[i];
+
+ /* ixgbe_get_stats64() might access this ring, we must wait
+ * a grace period before freeing it.
+ */
+ call_rcu(&ring->rcu, ring_free_rcu);
adapter->rx_ring[i] = NULL;
}
+ adapter->num_tx_queues = 0;
+ adapter->num_rx_queues = 0;
+
ixgbe_free_q_vectors(adapter);
ixgbe_reset_interrupt_capability(adapter);
}
@@ -4843,6 +5104,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
int j;
struct tc_configuration *tc;
#endif
+ int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
/* PCI config space info */
@@ -4857,26 +5119,24 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->ring_feature[RING_F_RSS].indices = rss;
adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES;
- if (hw->mac.type == ixgbe_mac_82598EB) {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
if (hw->device_id == IXGBE_DEV_ID_82598AT)
adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
- } else if (hw->mac.type == ixgbe_mac_82599EB) {
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
- if (dev->features & NETIF_F_NTUPLE) {
- /* Flow Director perfect filter enabled */
- adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
- adapter->atr_sample_rate = 0;
- spin_lock_init(&adapter->fdir_perfect_lock);
- } else {
- /* Flow Director hash filters enabled */
- adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
- adapter->atr_sample_rate = 20;
- }
+ /* n-tuple support exists, always init our spinlock */
+ spin_lock_init(&adapter->fdir_perfect_lock);
+ /* Flow Director hash filters enabled */
+ adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ adapter->atr_sample_rate = 20;
adapter->ring_feature[RING_F_FDIR].indices =
IXGBE_MAX_FDIR_INDICES;
adapter->fdir_pballoc = 0;
@@ -4890,6 +5150,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->fcoe.up = IXGBE_FCOE_DEFTC;
#endif
#endif /* IXGBE_FCOE */
+ break;
+ default:
+ break;
}
#ifdef CONFIG_IXGBE_DCB
@@ -4919,8 +5182,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
#ifdef CONFIG_DCB
adapter->last_lfc_mode = hw->fc.current_mode;
#endif
- hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
- hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+ hw->fc.high_water = FC_HIGH_WATER(max_frame);
+ hw->fc.low_water = FC_LOW_WATER(max_frame);
hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
hw->fc.send_xon = true;
hw->fc.disable_fc_autoneg = false;
@@ -4958,30 +5221,27 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
/**
* ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)
- * @adapter: board private structure
* @tx_ring: tx descriptor ring (for a specific queue) to setup
*
* Return 0 on success, negative on failure
**/
-int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+int ixgbe_setup_tx_resources(struct ixgbe_ring *tx_ring)
{
- struct pci_dev *pdev = adapter->pdev;
+ struct device *dev = tx_ring->dev;
int size;
size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
- tx_ring->tx_buffer_info = vmalloc_node(size, tx_ring->numa_node);
+ tx_ring->tx_buffer_info = vzalloc_node(size, tx_ring->numa_node);
if (!tx_ring->tx_buffer_info)
- tx_ring->tx_buffer_info = vmalloc(size);
+ tx_ring->tx_buffer_info = vzalloc(size);
if (!tx_ring->tx_buffer_info)
goto err;
- memset(tx_ring->tx_buffer_info, 0, size);
/* round up to nearest 4K */
tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
- tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+ tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
&tx_ring->dma, GFP_KERNEL);
if (!tx_ring->desc)
goto err;
@@ -4994,7 +5254,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
err:
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
- e_err(probe, "Unable to allocate memory for the Tx descriptor ring\n");
+ dev_err(dev, "Unable to allocate memory for the Tx descriptor ring\n");
return -ENOMEM;
}
@@ -5013,7 +5273,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
int i, err = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
- err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]);
+ err = ixgbe_setup_tx_resources(adapter->tx_ring[i]);
if (!err)
continue;
e_err(probe, "Allocation for Tx Queue %u failed\n", i);
@@ -5025,48 +5285,40 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
/**
* ixgbe_setup_rx_resources - allocate Rx resources (Descriptors)
- * @adapter: board private structure
* @rx_ring: rx descriptor ring (for a specific queue) to setup
*
* Returns 0 on success, negative on failure
**/
-int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+int ixgbe_setup_rx_resources(struct ixgbe_ring *rx_ring)
{
- struct pci_dev *pdev = adapter->pdev;
+ struct device *dev = rx_ring->dev;
int size;
size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
- rx_ring->rx_buffer_info = vmalloc_node(size, adapter->node);
+ rx_ring->rx_buffer_info = vzalloc_node(size, rx_ring->numa_node);
if (!rx_ring->rx_buffer_info)
- rx_ring->rx_buffer_info = vmalloc(size);
- if (!rx_ring->rx_buffer_info) {
- e_err(probe, "vmalloc allocation failed for the Rx "
- "descriptor ring\n");
- goto alloc_failed;
- }
- memset(rx_ring->rx_buffer_info, 0, size);
+ rx_ring->rx_buffer_info = vzalloc(size);
+ if (!rx_ring->rx_buffer_info)
+ goto err;
/* Round up to nearest 4K */
rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
rx_ring->size = ALIGN(rx_ring->size, 4096);
- rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+ rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
&rx_ring->dma, GFP_KERNEL);
- if (!rx_ring->desc) {
- e_err(probe, "Memory allocation failed for the Rx "
- "descriptor ring\n");
- vfree(rx_ring->rx_buffer_info);
- goto alloc_failed;
- }
+ if (!rx_ring->desc)
+ goto err;
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
return 0;
-
-alloc_failed:
+err:
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+ dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n");
return -ENOMEM;
}
@@ -5080,13 +5332,12 @@ alloc_failed:
*
* 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]);
+ err = ixgbe_setup_rx_resources(adapter->rx_ring[i]);
if (!err)
continue;
e_err(probe, "Allocation for Rx Queue %u failed\n", i);
@@ -5098,23 +5349,23 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
/**
* 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
**/
-void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+void ixgbe_free_tx_resources(struct ixgbe_ring *tx_ring)
{
- struct pci_dev *pdev = adapter->pdev;
-
- ixgbe_clean_tx_ring(adapter, tx_ring);
+ ixgbe_clean_tx_ring(tx_ring);
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
- dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
- tx_ring->dma);
+ /* if not set, then don't free */
+ if (!tx_ring->desc)
+ return;
+
+ dma_free_coherent(tx_ring->dev, tx_ring->size,
+ tx_ring->desc, tx_ring->dma);
tx_ring->desc = NULL;
}
@@ -5131,28 +5382,28 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++)
if (adapter->tx_ring[i]->desc)
- ixgbe_free_tx_resources(adapter, adapter->tx_ring[i]);
+ ixgbe_free_tx_resources(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
**/
-void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+void ixgbe_free_rx_resources(struct ixgbe_ring *rx_ring)
{
- struct pci_dev *pdev = adapter->pdev;
-
- ixgbe_clean_rx_ring(adapter, rx_ring);
+ ixgbe_clean_rx_ring(rx_ring);
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
- dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
- rx_ring->dma);
+ /* if not set, then don't free */
+ if (!rx_ring->desc)
+ return;
+
+ dma_free_coherent(rx_ring->dev, rx_ring->size,
+ rx_ring->desc, rx_ring->dma);
rx_ring->desc = NULL;
}
@@ -5169,7 +5420,7 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++)
if (adapter->rx_ring[i]->desc)
- ixgbe_free_rx_resources(adapter, adapter->rx_ring[i]);
+ ixgbe_free_rx_resources(adapter->rx_ring[i]);
}
/**
@@ -5182,6 +5433,7 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
/* MTU < 68 is an error and causes problems on some kernels */
@@ -5192,6 +5444,9 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
/* must set new MTU before calling down or up */
netdev->mtu = new_mtu;
+ hw->fc.high_water = FC_HIGH_WATER(max_frame);
+ hw->fc.low_water = FC_LOW_WATER(max_frame);
+
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
@@ -5287,8 +5542,8 @@ static int ixgbe_close(struct net_device *netdev)
#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);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
u32 err;
pci_set_power_state(pdev, PCI_D0);
@@ -5319,7 +5574,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
if (netif_running(netdev)) {
- err = ixgbe_open(adapter->netdev);
+ err = ixgbe_open(netdev);
if (err)
return err;
}
@@ -5332,8 +5587,8 @@ static int ixgbe_resume(struct pci_dev *pdev)
static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u32 ctrl, fctrl;
u32 wufc = adapter->wol;
@@ -5350,6 +5605,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
ixgbe_free_all_rx_resources(adapter);
}
+ ixgbe_clear_interrupt_scheme(adapter);
+
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
if (retval)
@@ -5376,15 +5633,20 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
}
- if (wufc && hw->mac.type == ixgbe_mac_82599EB)
- pci_wake_from_d3(pdev, true);
- else
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
pci_wake_from_d3(pdev, false);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ pci_wake_from_d3(pdev, !!wufc);
+ break;
+ default:
+ break;
+ }
*enable_wake = !!wufc;
- ixgbe_clear_interrupt_scheme(adapter);
-
ixgbe_release_hw_control(adapter);
pci_disable_device(pdev);
@@ -5433,10 +5695,12 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_hw_stats *hwstats = &adapter->stats;
u64 total_mpc = 0;
u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
- u64 non_eop_descs = 0, restart_queue = 0;
- struct ixgbe_hw_stats *hwstats = &adapter->stats;
+ u64 non_eop_descs = 0, restart_queue = 0, tx_busy = 0;
+ u64 alloc_rx_page_failed = 0, alloc_rx_buff_failed = 0;
+ u64 bytes = 0, packets = 0;
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
test_bit(__IXGBE_RESETTING, &adapter->state))
@@ -5449,21 +5713,41 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
adapter->hw_rx_no_dma_resources +=
IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
for (i = 0; i < adapter->num_rx_queues; i++) {
- rsc_count += adapter->rx_ring[i]->rsc_count;
- rsc_flush += adapter->rx_ring[i]->rsc_flush;
+ rsc_count += adapter->rx_ring[i]->rx_stats.rsc_count;
+ rsc_flush += adapter->rx_ring[i]->rx_stats.rsc_flush;
}
adapter->rsc_total_count = rsc_count;
adapter->rsc_total_flush = rsc_flush;
}
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct ixgbe_ring *rx_ring = adapter->rx_ring[i];
+ non_eop_descs += rx_ring->rx_stats.non_eop_descs;
+ alloc_rx_page_failed += rx_ring->rx_stats.alloc_rx_page_failed;
+ alloc_rx_buff_failed += rx_ring->rx_stats.alloc_rx_buff_failed;
+ bytes += rx_ring->stats.bytes;
+ packets += rx_ring->stats.packets;
+ }
+ adapter->non_eop_descs = non_eop_descs;
+ adapter->alloc_rx_page_failed = alloc_rx_page_failed;
+ adapter->alloc_rx_buff_failed = alloc_rx_buff_failed;
+ netdev->stats.rx_bytes = bytes;
+ netdev->stats.rx_packets = packets;
+
+ bytes = 0;
+ packets = 0;
/* gather some stats to the adapter struct that are per queue */
- for (i = 0; i < adapter->num_tx_queues; i++)
- restart_queue += adapter->tx_ring[i]->restart_queue;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+ restart_queue += tx_ring->tx_stats.restart_queue;
+ tx_busy += tx_ring->tx_stats.tx_busy;
+ bytes += tx_ring->stats.bytes;
+ packets += tx_ring->stats.packets;
+ }
adapter->restart_queue = restart_queue;
-
- for (i = 0; i < adapter->num_rx_queues; i++)
- non_eop_descs += adapter->rx_ring[i]->non_eop_descs;
- adapter->non_eop_descs = non_eop_descs;
+ adapter->tx_busy = tx_busy;
+ netdev->stats.tx_bytes = bytes;
+ netdev->stats.tx_packets = packets;
hwstats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
for (i = 0; i < 8; i++) {
@@ -5478,17 +5762,18 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
- if (hw->mac.type == ixgbe_mac_82599EB) {
- hwstats->pxonrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
- hwstats->pxoffrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i));
- hwstats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
- } else {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
hwstats->pxonrxc[i] +=
IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
- hwstats->pxoffrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ hwstats->pxonrxc[i] +=
+ IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
+ break;
+ default:
+ break;
}
hwstats->pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
hwstats->pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
@@ -5497,21 +5782,25 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
/* work around hardware counting issue */
hwstats->gprc -= missed_rx;
+ ixgbe_update_xoff_received(adapter);
+
/* 82598 hardware only has a 32 bit counter in the high register */
- if (hw->mac.type == ixgbe_mac_82599EB) {
- u64 tmp;
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
- tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF;
- /* 4 high bits of GORC */
- hwstats->gorc += (tmp << 32);
+ IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
- tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF;
- /* 4 high bits of GOTC */
- hwstats->gotc += (tmp << 32);
+ IXGBE_READ_REG(hw, IXGBE_GOTCH); /* to clear */
hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORL);
- IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
+ IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
- hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
hwstats->fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
hwstats->fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
#ifdef IXGBE_FCOE
@@ -5522,12 +5811,9 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
hwstats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
hwstats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
#endif /* IXGBE_FCOE */
- } else {
- hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
- hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
- hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
- hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
- hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+ break;
+ default:
+ break;
}
bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
hwstats->bprc += bprc;
@@ -5700,8 +5986,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
for (i = 0; i < adapter->num_tx_queues; i++)
- set_bit(__IXGBE_FDIR_INIT_DONE,
- &(adapter->tx_ring[i]->reinit_state));
+ set_bit(__IXGBE_TX_FDIR_INIT_DONE,
+ &(adapter->tx_ring[i]->state));
} else {
e_err(probe, "failed to finish FDIR re-initialization, "
"ignored adding FDIR ATR filters\n");
@@ -5710,6 +5996,26 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
netif_tx_start_all_queues(adapter->netdev);
}
+static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
+{
+ u32 ssvpc;
+
+ /* Do not perform spoof check for 82598 */
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ return;
+
+ ssvpc = IXGBE_READ_REG(&adapter->hw, IXGBE_SSVPC);
+
+ /*
+ * ssvpc register is cleared on read, if zero then no
+ * spoofed packets in the last interval.
+ */
+ if (!ssvpc)
+ return;
+
+ e_warn(drv, "%d Spoofed packets detected\n", ssvpc);
+}
+
static DEFINE_MUTEX(ixgbe_watchdog_lock);
/**
@@ -5763,17 +6069,27 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (!netif_carrier_ok(netdev)) {
bool flow_rx, flow_tx;
- if (hw->mac.type == ixgbe_mac_82599EB) {
- u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
- u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
- flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
- } else {
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB: {
u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540: {
+ u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+ u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+ flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
+ }
+ break;
+ default:
+ flow_tx = false;
+ flow_rx = false;
+ break;
+ }
e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
(link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
@@ -5787,7 +6103,10 @@ static void ixgbe_watchdog_task(struct work_struct *work)
netif_carrier_on(netdev);
} else {
/* Force detection of hung controller */
- adapter->detect_tx_hung = true;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ tx_ring = adapter->tx_ring[i];
+ set_check_for_tx_hang(tx_ring);
+ }
}
} else {
adapter->link_up = false;
@@ -5817,13 +6136,14 @@ static void ixgbe_watchdog_task(struct work_struct *work)
}
}
+ ixgbe_spoof_check(adapter);
ixgbe_update_stats(adapter);
mutex_unlock(&ixgbe_watchdog_lock);
}
static int ixgbe_tso(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring, struct sk_buff *skb,
- u32 tx_flags, u8 *hdr_len)
+ u32 tx_flags, u8 *hdr_len, __be16 protocol)
{
struct ixgbe_adv_tx_context_desc *context_desc;
unsigned int i;
@@ -5841,7 +6161,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
l4len = tcp_hdrlen(skb);
*hdr_len += l4len;
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -5880,7 +6200,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
IXGBE_ADVTXD_DTYP_CTXT);
- if (skb->protocol == htons(ETH_P_IP))
+ if (protocol == htons(ETH_P_IP))
type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
@@ -5906,16 +6226,10 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
return false;
}
-static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
+static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb,
+ __be16 protocol)
{
u32 rtn = 0;
- __be16 protocol;
-
- if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
- protocol = ((const struct vlan_ethhdr *)skb->data)->
- h_vlan_encapsulated_proto;
- else
- protocol = skb->protocol;
switch (protocol) {
case cpu_to_be16(ETH_P_IP):
@@ -5943,7 +6257,7 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
default:
if (unlikely(net_ratelimit()))
e_warn(probe, "partial checksum but proto=%x!\n",
- skb->protocol);
+ protocol);
break;
}
@@ -5952,7 +6266,8 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags)
+ struct sk_buff *skb, u32 tx_flags,
+ __be16 protocol)
{
struct ixgbe_adv_tx_context_desc *context_desc;
unsigned int i;
@@ -5981,7 +6296,7 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
IXGBE_ADVTXD_DTYP_CTXT);
if (skb->ip_summed == CHECKSUM_PARTIAL)
- type_tucmd_mlhl |= ixgbe_psum(adapter, skb);
+ type_tucmd_mlhl |= ixgbe_psum(adapter, skb, protocol);
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
/* use index zero for tx checksum offload */
@@ -6004,15 +6319,17 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring,
struct sk_buff *skb, u32 tx_flags,
- unsigned int first)
+ unsigned int first, const u8 hdr_len)
{
- struct pci_dev *pdev = adapter->pdev;
+ struct device *dev = tx_ring->dev;
struct ixgbe_tx_buffer *tx_buffer_info;
unsigned int len;
unsigned int total = skb->len;
unsigned int offset = 0, size, count = 0, i;
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
unsigned int f;
+ unsigned int bytecount = skb->len;
+ u16 gso_segs = 1;
i = tx_ring->next_to_use;
@@ -6027,10 +6344,10 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
tx_buffer_info->length = size;
tx_buffer_info->mapped_as_page = false;
- tx_buffer_info->dma = dma_map_single(&pdev->dev,
+ tx_buffer_info->dma = dma_map_single(dev,
skb->data + offset,
size, DMA_TO_DEVICE);
- if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
+ if (dma_mapping_error(dev, tx_buffer_info->dma))
goto dma_error;
tx_buffer_info->time_stamp = jiffies;
tx_buffer_info->next_to_watch = i;
@@ -6063,12 +6380,12 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
tx_buffer_info->length = size;
- tx_buffer_info->dma = dma_map_page(&adapter->pdev->dev,
+ tx_buffer_info->dma = dma_map_page(dev,
frag->page,
offset, size,
DMA_TO_DEVICE);
tx_buffer_info->mapped_as_page = true;
- if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
+ if (dma_mapping_error(dev, tx_buffer_info->dma))
goto dma_error;
tx_buffer_info->time_stamp = jiffies;
tx_buffer_info->next_to_watch = i;
@@ -6082,6 +6399,19 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
break;
}
+ if (tx_flags & IXGBE_TX_FLAGS_TSO)
+ gso_segs = skb_shinfo(skb)->gso_segs;
+#ifdef IXGBE_FCOE
+ /* adjust for FCoE Sequence Offload */
+ else if (tx_flags & IXGBE_TX_FLAGS_FSO)
+ gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
+ skb_shinfo(skb)->gso_size);
+#endif /* IXGBE_FCOE */
+ bytecount += (gso_segs - 1) * hdr_len;
+
+ /* multiply data chunks by size of headers */
+ tx_ring->tx_buffer_info[i].bytecount = bytecount;
+ tx_ring->tx_buffer_info[i].gso_segs = gso_segs;
tx_ring->tx_buffer_info[i].skb = skb;
tx_ring->tx_buffer_info[first].next_to_watch = i;
@@ -6103,14 +6433,13 @@ dma_error:
i += tx_ring->count;
i--;
tx_buffer_info = &tx_ring->tx_buffer_info[i];
- ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
}
return 0;
}
-static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
+static void ixgbe_tx_queue(struct ixgbe_ring *tx_ring,
int tx_flags, int count, u32 paylen, u8 hdr_len)
{
union ixgbe_adv_tx_desc *tx_desc = NULL;
@@ -6175,60 +6504,100 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
wmb();
tx_ring->next_to_use = i;
- writel(i, adapter->hw.hw_addr + tx_ring->tail);
+ writel(i, tx_ring->tail);
}
-static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
- int queue, u32 tx_flags)
+static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
+ u32 tx_flags, __be16 protocol)
{
- struct ixgbe_atr_input atr_input;
+ struct ixgbe_q_vector *q_vector = ring->q_vector;
+ union ixgbe_atr_hash_dword input = { .dword = 0 };
+ union ixgbe_atr_hash_dword common = { .dword = 0 };
+ union {
+ unsigned char *network;
+ struct iphdr *ipv4;
+ struct ipv6hdr *ipv6;
+ } hdr;
struct tcphdr *th;
- struct iphdr *iph = ip_hdr(skb);
- struct ethhdr *eth = (struct ethhdr *)skb->data;
- u16 vlan_id, src_port, dst_port, flex_bytes;
- u32 src_ipv4_addr, dst_ipv4_addr;
- u8 l4type = 0;
-
- /* Right now, we support IPv4 only */
- if (skb->protocol != htons(ETH_P_IP))
+ __be16 vlan_id;
+
+ /* if ring doesn't have a interrupt vector, cannot perform ATR */
+ if (!q_vector)
return;
- /* check if we're UDP or TCP */
- if (iph->protocol == IPPROTO_TCP) {
- th = tcp_hdr(skb);
- src_port = th->source;
- dst_port = th->dest;
- l4type |= IXGBE_ATR_L4TYPE_TCP;
- /* l4type IPv4 type is 0, no need to assign */
- } else {
- /* Unsupported L4 header, just bail here */
+
+ /* do nothing if sampling is disabled */
+ if (!ring->atr_sample_rate)
return;
- }
- memset(&atr_input, 0, sizeof(struct ixgbe_atr_input));
+ ring->atr_count++;
+
+ /* snag network header to get L4 type and address */
+ hdr.network = skb_network_header(skb);
+
+ /* Currently only IPv4/IPv6 with TCP is supported */
+ if ((protocol != __constant_htons(ETH_P_IPV6) ||
+ hdr.ipv6->nexthdr != IPPROTO_TCP) &&
+ (protocol != __constant_htons(ETH_P_IP) ||
+ hdr.ipv4->protocol != IPPROTO_TCP))
+ return;
+
+ th = tcp_hdr(skb);
+
+ /* skip this packet since the socket is closing */
+ if (th->fin)
+ return;
+
+ /* sample on all syn packets or once every atr sample count */
+ if (!th->syn && (ring->atr_count < ring->atr_sample_rate))
+ return;
+
+ /* reset sample count */
+ ring->atr_count = 0;
+
+ vlan_id = htons(tx_flags >> IXGBE_TX_FLAGS_VLAN_SHIFT);
+
+ /*
+ * src and dst are inverted, think how the receiver sees them
+ *
+ * The input is broken into two sections, a non-compressed section
+ * containing vm_pool, vlan_id, and flow_type. The rest of the data
+ * is XORed together and stored in the compressed dword.
+ */
+ input.formatted.vlan_id = vlan_id;
- vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >>
- IXGBE_TX_FLAGS_VLAN_SHIFT;
- src_ipv4_addr = iph->saddr;
- dst_ipv4_addr = iph->daddr;
- flex_bytes = eth->h_proto;
+ /*
+ * since src port and flex bytes occupy the same word XOR them together
+ * and write the value to source port portion of compressed dword
+ */
+ if (vlan_id)
+ common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
+ else
+ common.port.src ^= th->dest ^ protocol;
+ common.port.dst ^= th->source;
- ixgbe_atr_set_vlan_id_82599(&atr_input, vlan_id);
- ixgbe_atr_set_src_port_82599(&atr_input, dst_port);
- ixgbe_atr_set_dst_port_82599(&atr_input, src_port);
- ixgbe_atr_set_flex_byte_82599(&atr_input, flex_bytes);
- ixgbe_atr_set_l4type_82599(&atr_input, l4type);
- /* src and dst are inverted, think how the receiver sees them */
- ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr);
- ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr);
+ if (protocol == __constant_htons(ETH_P_IP)) {
+ input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
+ common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
+ } else {
+ input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV6;
+ common.ip ^= hdr.ipv6->saddr.s6_addr32[0] ^
+ hdr.ipv6->saddr.s6_addr32[1] ^
+ hdr.ipv6->saddr.s6_addr32[2] ^
+ hdr.ipv6->saddr.s6_addr32[3] ^
+ hdr.ipv6->daddr.s6_addr32[0] ^
+ hdr.ipv6->daddr.s6_addr32[1] ^
+ hdr.ipv6->daddr.s6_addr32[2] ^
+ hdr.ipv6->daddr.s6_addr32[3];
+ }
/* This assumes the Rx queue and Tx queue are bound to the same CPU */
- ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue);
+ ixgbe_fdir_add_signature_filter_82599(&q_vector->adapter->hw,
+ input, common, ring->queue_index);
}
-static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
- struct ixgbe_ring *tx_ring, int size)
+static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, int size)
{
- netif_stop_subqueue(netdev, tx_ring->queue_index);
+ netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
/* Herbert's original patch had:
* smp_mb__after_netif_stop_queue();
* but since that doesn't exist yet, just open code it. */
@@ -6240,27 +6609,29 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
return -EBUSY;
/* A reprieve! - use start_queue because it doesn't call schedule */
- netif_start_subqueue(netdev, tx_ring->queue_index);
- ++tx_ring->restart_queue;
+ netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+ ++tx_ring->tx_stats.restart_queue;
return 0;
}
-static int ixgbe_maybe_stop_tx(struct net_device *netdev,
- struct ixgbe_ring *tx_ring, int size)
+static int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, int size)
{
if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
return 0;
- return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
+ return __ixgbe_maybe_stop_tx(tx_ring, size);
}
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
int txq = smp_processor_id();
-
#ifdef IXGBE_FCOE
- if ((skb->protocol == htons(ETH_P_FCOE)) ||
- (skb->protocol == htons(ETH_P_FIP))) {
+ __be16 protocol;
+
+ protocol = vlan_get_protocol(skb);
+
+ if ((protocol == htons(ETH_P_FCOE)) ||
+ (protocol == htons(ETH_P_FIP))) {
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
txq += adapter->ring_feature[RING_F_FCOE].mask;
@@ -6292,17 +6663,19 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
return skb_tx_hash(dev, skb);
}
-netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev,
+netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring)
{
- struct netdev_queue *txq;
unsigned int first;
unsigned int tx_flags = 0;
u8 hdr_len = 0;
int tso;
int count = 0;
unsigned int f;
+ __be16 protocol;
+
+ protocol = vlan_get_protocol(skb);
if (vlan_tx_tag_present(skb)) {
tx_flags |= vlan_tx_tag_get(skb);
@@ -6323,8 +6696,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
/* for FCoE with DCB, we force the priority to what
* was specified by the switch */
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
- (skb->protocol == htons(ETH_P_FCOE) ||
- skb->protocol == htons(ETH_P_FIP))) {
+ (protocol == htons(ETH_P_FCOE) ||
+ protocol == htons(ETH_P_FIP))) {
#ifdef CONFIG_IXGBE_DCB
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
@@ -6334,7 +6707,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
}
#endif
/* flag for FCoE offloads */
- if (skb->protocol == htons(ETH_P_FCOE))
+ if (protocol == htons(ETH_P_FCOE))
tx_flags |= IXGBE_TX_FLAGS_FCOE;
}
#endif
@@ -6350,8 +6723,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
- if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) {
- adapter->tx_busy++;
+ if (ixgbe_maybe_stop_tx(tx_ring, count)) {
+ tx_ring->tx_stats.tx_busy++;
return NETDEV_TX_BUSY;
}
@@ -6368,9 +6741,10 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
tx_flags |= IXGBE_TX_FLAGS_FSO;
#endif /* IXGBE_FCOE */
} else {
- if (skb->protocol == htons(ETH_P_IP))
+ if (protocol == htons(ETH_P_IP))
tx_flags |= IXGBE_TX_FLAGS_IPV4;
- tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+ tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len,
+ protocol);
if (tso < 0) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -6378,30 +6752,19 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
if (tso)
tx_flags |= IXGBE_TX_FLAGS_TSO;
- else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+ else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags,
+ protocol) &&
(skb->ip_summed == CHECKSUM_PARTIAL))
tx_flags |= IXGBE_TX_FLAGS_CSUM;
}
- count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first);
+ count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first, hdr_len);
if (count) {
/* add the ATR filter if ATR is on */
- if (tx_ring->atr_sample_rate) {
- ++tx_ring->atr_count;
- if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) &&
- test_bit(__IXGBE_FDIR_INIT_DONE,
- &tx_ring->reinit_state)) {
- ixgbe_atr(adapter, skb, tx_ring->queue_index,
- tx_flags);
- tx_ring->atr_count = 0;
- }
- }
- txq = netdev_get_tx_queue(netdev, tx_ring->queue_index);
- txq->tx_bytes += skb->len;
- txq->tx_packets++;
- ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len,
- hdr_len);
- ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
+ if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
+ ixgbe_atr(tx_ring, skb, tx_flags, protocol);
+ ixgbe_tx_queue(tx_ring, tx_flags, count, skb->len, hdr_len);
+ ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
} else {
dev_kfree_skb_any(skb);
@@ -6418,7 +6781,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netd
struct ixgbe_ring *tx_ring;
tx_ring = adapter->tx_ring[skb->queue_mapping];
- return ixgbe_xmit_frame_ring(skb, netdev, adapter, tx_ring);
+ return ixgbe_xmit_frame_ring(skb, adapter, tx_ring);
}
/**
@@ -6557,22 +6920,39 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
int i;
- /* accurate rx/tx bytes/packets stats */
- dev_txq_stats_fold(netdev, stats);
+ rcu_read_lock();
for (i = 0; i < adapter->num_rx_queues; i++) {
- struct ixgbe_ring *ring = adapter->rx_ring[i];
+ struct ixgbe_ring *ring = ACCESS_ONCE(adapter->rx_ring[i]);
u64 bytes, packets;
unsigned int start;
- do {
- start = u64_stats_fetch_begin_bh(&ring->syncp);
- packets = ring->stats.packets;
- bytes = ring->stats.bytes;
- } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
- stats->rx_packets += packets;
- stats->rx_bytes += bytes;
+ if (ring) {
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ packets = ring->stats.packets;
+ bytes = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->rx_packets += packets;
+ stats->rx_bytes += bytes;
+ }
}
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *ring = ACCESS_ONCE(adapter->tx_ring[i]);
+ u64 bytes, packets;
+ unsigned int start;
+
+ if (ring) {
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ packets = ring->stats.packets;
+ bytes = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->tx_packets += packets;
+ stats->tx_bytes += bytes;
+ }
+ }
+ rcu_read_unlock();
/* following stats updated by ixgbe_watchdog_task() */
stats->multicast = netdev->stats.multicast;
stats->rx_errors = netdev->stats.rx_errors;
@@ -6621,7 +7001,7 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
struct ixgbe_hw *hw = &adapter->hw;
int err;
- if (hw->mac.type != ixgbe_mac_82599EB || !max_vfs)
+ if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs)
return;
/* The 82599 supports up to 64 VFs per physical function
@@ -6687,11 +7067,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
static int cards_found;
int i, err, pci_using_dac;
+ u8 part_str[IXGBE_PBANUM_LENGTH];
unsigned int indices = num_possible_cpus();
#ifdef IXGBE_FCOE
u16 device_caps;
#endif
- u32 part_num, eec;
+ u32 eec;
/* Catch broken hardware that put the wrong VF device ID in
* the PCIe SR-IOV capability.
@@ -6754,8 +7135,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
- pci_set_drvdata(pdev, netdev);
adapter = netdev_priv(netdev);
+ pci_set_drvdata(pdev, adapter);
adapter->netdev = netdev;
adapter->pdev = pdev;
@@ -6778,7 +7159,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->netdev_ops = &ixgbe_netdev_ops;
ixgbe_set_ethtool_ops(netdev);
netdev->watchdog_timeo = 5 * HZ;
- strcpy(netdev->name, pci_name(pdev));
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
adapter->bd_number = cards_found;
@@ -6828,8 +7209,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_sw_init;
/* Make it possible the adapter to be woken up via WOL */
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
+ break;
+ default:
+ break;
+ }
/*
* If there is a fan on this device and it has failed log the
@@ -6937,8 +7324,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_eeprom;
}
- /* power down the optics */
- if (hw->phy.multispeed_fiber)
+ /* power down the optics for multispeed fiber and 82599 SFP+ fiber */
+ if (hw->mac.ops.disable_tx_laser &&
+ ((hw->phy.multispeed_fiber) ||
+ ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
+ (hw->mac.type == ixgbe_mac_82599EB))))
hw->mac.ops.disable_tx_laser(hw);
init_timer(&adapter->watchdog_timer);
@@ -6953,6 +7343,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_sw_init;
switch (pdev->device) {
+ case IXGBE_DEV_ID_82599_SFP:
+ /* Only this subdevice supports WOL */
+ if (pdev->subsystem_device == IXGBE_SUBDEV_ID_82599_SFP)
+ adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
+ IXGBE_WUFC_MC | IXGBE_WUFC_BC);
+ break;
+ case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
+ /* All except this subdevice support WOL */
+ if (pdev->subsystem_device != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ)
+ adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
+ IXGBE_WUFC_MC | IXGBE_WUFC_BC);
+ break;
case IXGBE_DEV_ID_82599_KX4:
adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
IXGBE_WUFC_MC | IXGBE_WUFC_BC);
@@ -6976,16 +7378,17 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->bus.width == ixgbe_bus_width_pcie_x1 ? "Width x1" :
"Unknown"),
netdev->dev_addr);
- ixgbe_read_pba_num_generic(hw, &part_num);
+
+ err = ixgbe_read_pba_string_generic(hw, part_str, IXGBE_PBANUM_LENGTH);
+ if (err)
+ strncpy(part_str, "Unknown", IXGBE_PBANUM_LENGTH);
if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
- e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
- "PBA No: %06x-%03x\n",
+ e_dev_info("MAC: %d, PHY: %d, SFP+: %d, PBA No: %s\n",
hw->mac.type, hw->phy.type, hw->phy.sfp_type,
- (part_num >> 8), (part_num & 0xff));
+ part_str);
else
- e_dev_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type,
- (part_num >> 8), (part_num & 0xff));
+ e_dev_info("MAC: %d, PHY: %d, PBA No: %s\n",
+ hw->mac.type, hw->phy.type, part_str);
if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
e_dev_warn("PCI-Express bandwidth available for this card is "
@@ -7078,17 +7481,19 @@ err_dma:
**/
static void __devexit ixgbe_remove(struct pci_dev *pdev)
{
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
set_bit(__IXGBE_DOWN, &adapter->state);
- /* clear the module not found bit to make sure the worker won't
- * reschedule
+
+ /*
+ * The timers may be rescheduled, so explicitly disable them
+ * from being rescheduled.
*/
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
del_timer_sync(&adapter->watchdog_timer);
-
del_timer_sync(&adapter->sfp_timer);
+
cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->sfp_task);
cancel_work_sync(&adapter->multispeed_fiber_task);
@@ -7096,7 +7501,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
cancel_work_sync(&adapter->fdir_reinit_task);
- flush_scheduled_work();
+ if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+ cancel_work_sync(&adapter->check_overtemp_task);
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
@@ -7149,8 +7555,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
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(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
netif_device_detach(netdev);
@@ -7173,8 +7579,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
*/
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(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
pci_ers_result_t result;
int err;
@@ -7212,8 +7617,8 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
*/
static void ixgbe_io_resume(struct pci_dev *pdev)
{
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
if (netif_running(netdev)) {
if (ixgbe_up(adapter)) {
@@ -7278,6 +7683,7 @@ static void __exit ixgbe_exit_module(void)
dca_unregister_notify(&dca_notifier);
#endif
pci_unregister_driver(&ixgbe_driver);
+ rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
#ifdef CONFIG_IXGBE_DCA
diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c
index 471f0f2cdb98..ea82c5a1cd3e 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ixgbe/ixgbe_mbx.c
@@ -319,8 +319,16 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
u32 vflre = 0;
s32 ret_val = IXGBE_ERR_MBX;
- if (hw->mac.type == ixgbe_mac_82599EB)
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset));
+ break;
+ case ixgbe_mac_X540:
+ vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
+ break;
+ default:
+ break;
+ }
if (vflre & (1 << vf_shift)) {
ret_val = 0;
@@ -439,22 +447,26 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
- if (hw->mac.type != ixgbe_mac_82599EB)
- return;
-
- mbx->timeout = 0;
- mbx->usec_delay = 0;
-
- mbx->size = IXGBE_VFMAILBOX_SIZE;
-
- mbx->stats.msgs_tx = 0;
- mbx->stats.msgs_rx = 0;
- mbx->stats.reqs = 0;
- mbx->stats.acks = 0;
- mbx->stats.rsts = 0;
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ mbx->timeout = 0;
+ mbx->usec_delay = 0;
+
+ mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+ mbx->stats.msgs_tx = 0;
+ mbx->stats.msgs_rx = 0;
+ mbx->stats.reqs = 0;
+ mbx->stats.acks = 0;
+ mbx->stats.rsts = 0;
+ break;
+ default:
+ break;
+ }
}
-struct ixgbe_mbx_operations mbx_ops_82599 = {
+struct ixgbe_mbx_operations mbx_ops_generic = {
.read = ixgbe_read_mbx_pf,
.write = ixgbe_write_mbx_pf,
.read_posted = ixgbe_read_posted_mbx,
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
index 7e0d08ff5b53..3df9b1590218 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ixgbe/ixgbe_mbx.h
@@ -88,6 +88,6 @@ s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16);
s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16);
void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
-extern struct ixgbe_mbx_operations mbx_ops_82599;
+extern struct ixgbe_mbx_operations mbx_ops_generic;
#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 6c0d42e33f21..8f7123e8fc0a 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -115,6 +115,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
case TN1010_PHY_ID:
phy_type = ixgbe_phy_tn;
break;
+ case X540_PHY_ID:
+ phy_type = ixgbe_phy_aq;
+ break;
case QT2022_PHY_ID:
phy_type = ixgbe_phy_qt;
break;
@@ -425,6 +428,39 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
}
/**
+ * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: boolean auto-negotiation value
+ *
+ * Determines the link capabilities by reading the AUTOC register.
+ */
+s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *autoneg)
+{
+ s32 status = IXGBE_ERR_LINK_SETUP;
+ u16 speed_ability;
+
+ *speed = 0;
+ *autoneg = true;
+
+ status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD,
+ &speed_ability);
+
+ if (status == 0) {
+ if (speed_ability & MDIO_SPEED_10G)
+ *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (speed_ability & MDIO_PMA_SPEED_1000)
+ *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+ if (speed_ability & MDIO_PMA_SPEED_100)
+ *speed |= IXGBE_LINK_SPEED_100_FULL;
+ }
+
+ return status;
+}
+
+/**
* ixgbe_reset_phy_nl - Performs a PHY reset
* @hw: pointer to hardware structure
**/
@@ -1378,6 +1414,22 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
}
/**
+ * ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version
+ * @hw: pointer to hardware structure
+ * @firmware_version: pointer to the PHY Firmware Version
+**/
+s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
+ u16 *firmware_version)
+{
+ s32 status = 0;
+
+ status = hw->phy.ops.read_reg(hw, AQ_FW_REV, MDIO_MMD_VEND1,
+ firmware_version);
+
+ return status;
+}
+
+/**
* ixgbe_tn_check_overtemp - Checks if an overtemp occured.
* @hw: pointer to hardware structure
*
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index fb3898f12fc5..e2c6b7eac641 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -96,6 +96,9 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
bool autoneg_wait_to_complete);
+s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *autoneg);
/* PHY specific */
s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw,
@@ -103,6 +106,8 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw,
bool *link_up);
s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
u16 *firmware_version);
+s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
+ u16 *firmware_version);
s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw);
s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index 5428153af8f3..47b15738b009 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -68,7 +68,7 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
* addresses
*/
for (i = 0; i < entries; i++) {
- vfinfo->vf_mc_hashes[i] = hash_list[i];;
+ vfinfo->vf_mc_hashes[i] = hash_list[i];
}
for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) {
@@ -178,8 +178,7 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
{
unsigned char vf_mac_addr[6];
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
unsigned int vfn = (event_mask & 0x3f);
bool enable = ((event_mask & 0x10000000U) != 0);
@@ -216,6 +215,11 @@ static inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
reg |= (reg | (1 << vf_shift));
IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg);
+ /* Enable counting of spoofed packets in the SSVPC register */
+ reg = IXGBE_READ_REG(hw, IXGBE_VMECM(reg_offset));
+ reg |= (1 << vf_shift);
+ IXGBE_WRITE_REG(hw, IXGBE_VMECM(reg_offset), reg);
+
ixgbe_vf_reset_event(adapter, vf);
}
@@ -228,6 +232,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
int entries;
u16 *hash_list;
int add, vid;
+ u8 *new_mac;
retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
@@ -245,15 +250,22 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
if (msgbuf[0] == IXGBE_VF_RESET) {
unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
- u8 *addr = (u8 *)(&msgbuf[1]);
+ new_mac = (u8 *)(&msgbuf[1]);
e_info(probe, "VF Reset msg received from vf %d\n", vf);
adapter->vfinfo[vf].clear_to_send = false;
ixgbe_vf_reset_msg(adapter, vf);
adapter->vfinfo[vf].clear_to_send = true;
+ if (is_valid_ether_addr(new_mac) &&
+ !adapter->vfinfo[vf].pf_set_mac)
+ ixgbe_set_vf_mac(adapter, vf, vf_mac);
+ else
+ ixgbe_set_vf_mac(adapter,
+ vf, adapter->vfinfo[vf].vf_mac_addresses);
+
/* reply to reset with ack and vf mac address */
msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
- memcpy(addr, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
+ memcpy(new_mac, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
/*
* Piggyback the multicast filter type so VF can compute the
* correct vectors
@@ -272,14 +284,16 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
switch ((msgbuf[0] & 0xFFFF)) {
case IXGBE_VF_SET_MAC_ADDR:
- {
- u8 *new_mac = ((u8 *)(&msgbuf[1]));
- if (is_valid_ether_addr(new_mac) &&
- !adapter->vfinfo[vf].pf_set_mac)
- ixgbe_set_vf_mac(adapter, vf, new_mac);
- else
- ixgbe_set_vf_mac(adapter,
- vf, adapter->vfinfo[vf].vf_mac_addresses);
+ new_mac = ((u8 *)(&msgbuf[1]));
+ if (is_valid_ether_addr(new_mac) &&
+ !adapter->vfinfo[vf].pf_set_mac) {
+ ixgbe_set_vf_mac(adapter, vf, new_mac);
+ } else if (memcmp(adapter->vfinfo[vf].vf_mac_addresses,
+ new_mac, ETH_ALEN)) {
+ e_warn(drv, "VF %d attempted to override "
+ "administratively set MAC address\nReload "
+ "the VF driver to resume operations\n", vf);
+ retval = -1;
}
break;
case IXGBE_VF_SET_MULTICAST:
@@ -296,7 +310,15 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
>> IXGBE_VT_MSGINFO_SHIFT;
vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
- retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+ if (adapter->vfinfo[vf].pf_vlan) {
+ e_warn(drv, "VF %d attempted to override "
+ "administratively set VLAN configuration\n"
+ "Reload the VF driver to resume operations\n",
+ vf);
+ retval = -1;
+ } else {
+ retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+ }
break;
default:
e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
@@ -395,6 +417,7 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
{
int err = 0;
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
return -EINVAL;
@@ -403,7 +426,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
if (err)
goto out;
ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
- ixgbe_set_vmolr(&adapter->hw, vf, false);
+ ixgbe_set_vmolr(hw, vf, false);
+ hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
adapter->vfinfo[vf].pf_vlan = vlan;
adapter->vfinfo[vf].pf_qos = qos;
dev_info(&adapter->pdev->dev,
@@ -420,7 +444,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
err = ixgbe_set_vf_vlan(adapter, false,
adapter->vfinfo[vf].pf_vlan, vf);
ixgbe_set_vmvir(adapter, vlan, vf);
- ixgbe_set_vmolr(&adapter->hw, vf, true);
+ ixgbe_set_vmolr(hw, vf, true);
+ hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
adapter->vfinfo[vf].pf_vlan = 0;
adapter->vfinfo[vf].pf_qos = 0;
}
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index d3cc6ce7c973..fd3358f54139 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -54,9 +54,14 @@
#define IXGBE_DEV_ID_82599_T3_LOM 0x151C
#define IXGBE_DEV_ID_82599_CX4 0x10F9
#define IXGBE_DEV_ID_82599_SFP 0x10FB
+#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152a
+#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
+#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
+#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C
+#define IXGBE_DEV_ID_X540T 0x1528
/* General Registers */
#define IXGBE_CTRL 0x00000
@@ -225,6 +230,7 @@
#define IXGBE_VT_CTL 0x051B0
#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4))
#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4))
+#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4))
#define IXGBE_QDE 0x2F04
#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */
#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4))
@@ -279,7 +285,8 @@
#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
#define IXGBE_DTXCTL 0x07E00
-#define IXGBE_DMATXCTL 0x04A80
+#define IXGBE_DMATXCTL 0x04A80
+#define IXGBE_PFVFSPOOF(_i) (0x08200 + ((_i) * 4)) /* 8 of these 0 - 7 */
#define IXGBE_PFDTXGSWC 0x08220
#define IXGBE_DTXMXSZRQ 0x08100
#define IXGBE_DTXTCPFLGL 0x04A88
@@ -293,6 +300,13 @@
#define IXGBE_DMATXCTL_VT_SHIFT 16 /* VLAN EtherType */
#define IXGBE_PFDTXGSWC_VT_LBEN 0x1 /* Local L2 VT switch enable */
+
+/* Anti-spoofing defines */
+#define IXGBE_SPOOF_MACAS_MASK 0xFF
+#define IXGBE_SPOOF_VLANAS_MASK 0xFF00
+#define IXGBE_SPOOF_VLANAS_SHIFT 8
+#define IXGBE_PFVFSPOOF_REG_COUNT 8
+
#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
/* Tx DCA Control register : 128 of these (0-127) */
#define IXGBE_DCA_TXCTRL_82599(_i) (0x0600C + ((_i) * 0x40))
@@ -994,8 +1008,10 @@
/* PHY IDs*/
#define TN1010_PHY_ID 0x00A19410
#define TNX_FW_REV 0xB
+#define X540_PHY_ID 0x01540200
#define QT2022_PHY_ID 0x0043A400
#define ATH_PHY_ID 0x03429050
+#define AQ_FW_REV 0x20
/* PHY Types */
#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0
@@ -1463,6 +1479,8 @@
#define IXGBE_ANLP1_PAUSE 0x0C00
#define IXGBE_ANLP1_SYM_PAUSE 0x0400
#define IXGBE_ANLP1_ASM_PAUSE 0x0800
+#define IXGBE_ANLP1_AN_STATE_MASK 0x000f0000
+
/* SW Semaphore Register bitmasks */
#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
@@ -1491,6 +1509,7 @@
#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */
#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */
#define IXGBE_EEC_FLUP 0x00800000 /* Flash update command */
+#define IXGBE_EEC_SEC1VAL 0x02000000 /* Sector 1 Valid */
#define IXGBE_EEC_FLUDONE 0x04000000 /* Flash update done */
/* EEPROM Addressing bits based on type (0-small, 1-large) */
#define IXGBE_EEC_ADDR_SIZE 0x00000400
@@ -1500,12 +1519,18 @@
#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6
#define IXGBE_EEPROM_OPCODE_BITS 8
+/* Part Number String Length */
+#define IXGBE_PBANUM_LENGTH 11
+
/* Checksum and EEPROM pointers */
+#define IXGBE_PBANUM_PTR_GUARD 0xFAFA
#define IXGBE_EEPROM_CHECKSUM 0x3F
#define IXGBE_EEPROM_SUM 0xBABA
#define IXGBE_PCIE_ANALOG_PTR 0x03
#define IXGBE_ATLAS0_CONFIG_PTR 0x04
+#define IXGBE_PHY_PTR 0x04
#define IXGBE_ATLAS1_CONFIG_PTR 0x05
+#define IXGBE_OPTION_ROM_PTR 0x05
#define IXGBE_PCIE_GENERAL_PTR 0x06
#define IXGBE_PCIE_CONFIG0_PTR 0x07
#define IXGBE_PCIE_CONFIG1_PTR 0x08
@@ -1922,10 +1947,9 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIRM_VLANID 0x00000001
#define IXGBE_FDIRM_VLANP 0x00000002
#define IXGBE_FDIRM_POOL 0x00000004
-#define IXGBE_FDIRM_L3P 0x00000008
-#define IXGBE_FDIRM_L4P 0x00000010
-#define IXGBE_FDIRM_FLEX 0x00000020
-#define IXGBE_FDIRM_DIPv6 0x00000040
+#define IXGBE_FDIRM_L4P 0x00000008
+#define IXGBE_FDIRM_FLEX 0x00000010
+#define IXGBE_FDIRM_DIPv6 0x00000020
#define IXGBE_FDIRFREE_FREE_MASK 0xFFFF
#define IXGBE_FDIRFREE_FREE_SHIFT 0
@@ -1965,6 +1989,7 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIRCMD_LAST 0x00000800
#define IXGBE_FDIRCMD_COLLISION 0x00001000
#define IXGBE_FDIRCMD_QUEUE_EN 0x00008000
+#define IXGBE_FDIRCMD_FLOW_TYPE_SHIFT 5
#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT 16
#define IXGBE_FDIRCMD_VT_POOL_SHIFT 24
#define IXGBE_FDIR_INIT_DONE_POLL 10
@@ -2113,57 +2138,95 @@ typedef u32 ixgbe_physical_layer;
#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000
#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000
+/* Flow Control Macros */
+#define PAUSE_RTT 8
+#define PAUSE_MTU(MTU) ((MTU + 1024 - 1) / 1024)
+
+#define FC_HIGH_WATER(MTU) ((((PAUSE_RTT + PAUSE_MTU(MTU)) * 144) + 99) / 100 +\
+ PAUSE_MTU(MTU))
+#define FC_LOW_WATER(MTU) (2 * (2 * PAUSE_MTU(MTU) + PAUSE_RTT))
+
/* Software ATR hash keys */
-#define IXGBE_ATR_BUCKET_HASH_KEY 0xE214AD3D
-#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17
-
-/* Software ATR input stream offsets and masks */
-#define IXGBE_ATR_VLAN_OFFSET 0
-#define IXGBE_ATR_SRC_IPV6_OFFSET 2
-#define IXGBE_ATR_SRC_IPV4_OFFSET 14
-#define IXGBE_ATR_DST_IPV6_OFFSET 18
-#define IXGBE_ATR_DST_IPV4_OFFSET 30
-#define IXGBE_ATR_SRC_PORT_OFFSET 34
-#define IXGBE_ATR_DST_PORT_OFFSET 36
-#define IXGBE_ATR_FLEX_BYTE_OFFSET 38
-#define IXGBE_ATR_VM_POOL_OFFSET 40
-#define IXGBE_ATR_L4TYPE_OFFSET 41
+#define IXGBE_ATR_BUCKET_HASH_KEY 0x3DAD14E2
+#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x174D3614
+/* Software ATR input stream values and masks */
+#define IXGBE_ATR_HASH_MASK 0x7fff
#define IXGBE_ATR_L4TYPE_MASK 0x3
-#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4
#define IXGBE_ATR_L4TYPE_UDP 0x1
#define IXGBE_ATR_L4TYPE_TCP 0x2
#define IXGBE_ATR_L4TYPE_SCTP 0x3
-#define IXGBE_ATR_HASH_MASK 0x7fff
+#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4
+enum ixgbe_atr_flow_type {
+ IXGBE_ATR_FLOW_TYPE_IPV4 = 0x0,
+ IXGBE_ATR_FLOW_TYPE_UDPV4 = 0x1,
+ IXGBE_ATR_FLOW_TYPE_TCPV4 = 0x2,
+ IXGBE_ATR_FLOW_TYPE_SCTPV4 = 0x3,
+ IXGBE_ATR_FLOW_TYPE_IPV6 = 0x4,
+ IXGBE_ATR_FLOW_TYPE_UDPV6 = 0x5,
+ IXGBE_ATR_FLOW_TYPE_TCPV6 = 0x6,
+ IXGBE_ATR_FLOW_TYPE_SCTPV6 = 0x7,
+};
/* Flow Director ATR input struct. */
-struct ixgbe_atr_input {
- /* Byte layout in order, all values with MSB first:
+union ixgbe_atr_input {
+ /*
+ * Byte layout in order, all values with MSB first:
*
+ * vm_pool - 1 byte
+ * flow_type - 1 byte
* vlan_id - 2 bytes
* src_ip - 16 bytes
* dst_ip - 16 bytes
* src_port - 2 bytes
* dst_port - 2 bytes
* flex_bytes - 2 bytes
- * vm_pool - 1 byte
- * l4type - 1 byte
+ * rsvd0 - 2 bytes - space reserved must be 0.
*/
- u8 byte_stream[42];
+ struct {
+ u8 vm_pool;
+ u8 flow_type;
+ __be16 vlan_id;
+ __be32 dst_ip[4];
+ __be32 src_ip[4];
+ __be16 src_port;
+ __be16 dst_port;
+ __be16 flex_bytes;
+ __be16 rsvd0;
+ } formatted;
+ __be32 dword_stream[11];
+};
+
+/* Flow Director compressed ATR hash input struct */
+union ixgbe_atr_hash_dword {
+ struct {
+ u8 vm_pool;
+ u8 flow_type;
+ __be16 vlan_id;
+ } formatted;
+ __be32 ip;
+ struct {
+ __be16 src;
+ __be16 dst;
+ } port;
+ __be16 flex_bytes;
+ __be32 dword;
};
struct ixgbe_atr_input_masks {
- u32 src_ip_mask;
- u32 dst_ip_mask;
- u16 src_port_mask;
- u16 dst_port_mask;
- u16 vlan_id_mask;
- u16 data_mask;
+ __be16 rsvd0;
+ __be16 vlan_id_mask;
+ __be32 dst_ip_mask[4];
+ __be32 src_ip_mask[4];
+ __be16 src_port_mask;
+ __be16 dst_port_mask;
+ __be16 flex_mask;
};
enum ixgbe_eeprom_type {
ixgbe_eeprom_uninitialized = 0,
ixgbe_eeprom_spi,
+ ixgbe_flash,
ixgbe_eeprom_none /* No NVM support */
};
@@ -2171,12 +2234,14 @@ enum ixgbe_mac_type {
ixgbe_mac_unknown = 0,
ixgbe_mac_82598EB,
ixgbe_mac_82599EB,
+ ixgbe_mac_X540,
ixgbe_num_macs
};
enum ixgbe_phy_type {
ixgbe_phy_unknown = 0,
ixgbe_phy_tn,
+ ixgbe_phy_aq,
ixgbe_phy_cu_unknown,
ixgbe_phy_qt,
ixgbe_phy_xaui,
@@ -2405,6 +2470,7 @@ struct ixgbe_eeprom_operations {
s32 (*write)(struct ixgbe_hw *, u16, u16);
s32 (*validate_checksum)(struct ixgbe_hw *, u16 *);
s32 (*update_checksum)(struct ixgbe_hw *);
+ u16 (*calc_checksum)(struct ixgbe_hw *);
};
struct ixgbe_mac_operations {
@@ -2454,6 +2520,8 @@ struct ixgbe_mac_operations {
s32 (*clear_vfta)(struct ixgbe_hw *);
s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
s32 (*init_uta_tables)(struct ixgbe_hw *);
+ void (*set_mac_anti_spoofing)(struct ixgbe_hw *, bool, int);
+ void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int);
/* Flow Control */
s32 (*fc_enable)(struct ixgbe_hw *, s32);
@@ -2574,6 +2642,7 @@ struct ixgbe_hw {
u16 subsystem_vendor_id;
u8 revision_id;
bool adapter_stopped;
+ bool force_full_reset;
};
struct ixgbe_info {
@@ -2614,6 +2683,9 @@ struct ixgbe_info {
#define IXGBE_ERR_NO_SPACE -25
#define IXGBE_ERR_OVERTEMP -26
#define IXGBE_ERR_RAR_INDEX -27
+#define IXGBE_ERR_SFP_SETUP_NOT_COMPLETE -30
+#define IXGBE_ERR_PBA_SECTION -31
+#define IXGBE_ERR_INVALID_ARGUMENT -32
#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c
new file mode 100644
index 000000000000..3a8923993ce3
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_x540.c
@@ -0,0 +1,724 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2010 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe.h"
+#include "ixgbe_phy.h"
+//#include "ixgbe_mbx.h"
+
+#define IXGBE_X540_MAX_TX_QUEUES 128
+#define IXGBE_X540_MAX_RX_QUEUES 128
+#define IXGBE_X540_RAR_ENTRIES 128
+#define IXGBE_X540_MC_TBL_SIZE 128
+#define IXGBE_X540_VFT_TBL_SIZE 128
+
+static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw);
+static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw);
+static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask);
+static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask);
+static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw);
+static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw);
+
+static enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw)
+{
+ return ixgbe_media_type_copper;
+}
+
+static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mac_info *mac = &hw->mac;
+
+ /* Call PHY identify routine to get the phy type */
+ ixgbe_identify_phy_generic(hw);
+
+ mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
+ mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
+ mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES;
+ mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES;
+ mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES;
+ mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_mac_link_X540 - Set the auto advertised capabilitires
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
+ **/
+static s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed, bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ return hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+}
+
+/**
+ * ixgbe_reset_hw_X540 - Perform hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by resetting the transmit and receive units, masks
+ * and clears all interrupts, perform a PHY reset, and perform a link (MAC)
+ * reset.
+ **/
+static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
+{
+ ixgbe_link_speed link_speed;
+ s32 status = 0;
+ u32 ctrl;
+ u32 ctrl_ext;
+ u32 reset_bit;
+ u32 i;
+ u32 autoc;
+ u32 autoc2;
+ bool link_up = false;
+
+ /* Call adapter stop to disable tx/rx and clear interrupts */
+ hw->mac.ops.stop_adapter(hw);
+
+ /*
+ * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+ * access and verify no pending requests before reset
+ */
+ status = ixgbe_disable_pcie_master(hw);
+ if (status != 0) {
+ status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ }
+
+ /*
+ * Issue global reset to the MAC. Needs to be SW reset if link is up.
+ * If link reset is used when link is up, it might reset the PHY when
+ * mng is using it. If link is down or the flag to force full link
+ * reset is set, then perform link reset.
+ */
+ if (hw->force_full_reset) {
+ reset_bit = IXGBE_CTRL_LNK_RST;
+ } else {
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+ if (!link_up)
+ reset_bit = IXGBE_CTRL_LNK_RST;
+ else
+ reset_bit = IXGBE_CTRL_RST;
+ }
+
+ 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");
+ }
+
+ /* Clear PF Reset Done bit so PF/VF Mail Ops can work */
+ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+ msleep(50);
+
+ /* Set the Rx packet buffer size. */
+ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), 384 << IXGBE_RXPBSIZE_SHIFT);
+
+ /* Store the permanent mac address */
+ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
+
+ /*
+ * Store the original AUTOC/AUTOC2 values if they have not been
+ * stored off yet. Otherwise restore the stored original
+ * values since the reset operation sets back to defaults.
+ */
+ autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+ if (hw->mac.orig_link_settings_stored == false) {
+ hw->mac.orig_autoc = autoc;
+ hw->mac.orig_autoc2 = autoc2;
+ hw->mac.orig_link_settings_stored = true;
+ } else {
+ if (autoc != hw->mac.orig_autoc)
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc |
+ IXGBE_AUTOC_AN_RESTART));
+
+ if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
+ (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) {
+ autoc2 &= ~IXGBE_AUTOC2_UPPER_MASK;
+ autoc2 |= (hw->mac.orig_autoc2 &
+ IXGBE_AUTOC2_UPPER_MASK);
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2);
+ }
+ }
+
+ /*
+ * Store MAC address from RAR0, clear receive address registers, and
+ * clear the multicast table. Also reset num_rar_entries to 128,
+ * since we modify this value when programming the SAN MAC address.
+ */
+ hw->mac.num_rar_entries = 128;
+ hw->mac.ops.init_rx_addrs(hw);
+
+ /* Store the permanent mac address */
+ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
+
+ /* Store the permanent SAN mac address */
+ hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr);
+
+ /* Add the SAN MAC address to the RAR only if it's a valid address */
+ if (ixgbe_validate_mac_addr(hw->mac.san_addr) == 0) {
+ hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1,
+ hw->mac.san_addr, 0, IXGBE_RAH_AV);
+
+ /* Reserve the last RAR for the SAN MAC address */
+ hw->mac.num_rar_entries--;
+ }
+
+ /* Store the alternative WWNN/WWPN prefix */
+ hw->mac.ops.get_wwn_prefix(hw, &hw->mac.wwnn_prefix,
+ &hw->mac.wwpn_prefix);
+
+ return status;
+}
+
+/**
+ * ixgbe_get_supported_physical_layer_X540 - Returns physical layer type
+ * @hw: pointer to hardware structure
+ *
+ * Determines physical layer capabilities of the current configuration.
+ **/
+static u32 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw)
+{
+ u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+ u16 ext_ability = 0;
+
+ hw->phy.ops.identify(hw);
+
+ hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD,
+ &ext_ability);
+ if (ext_ability & MDIO_PMA_EXTABLE_10GBT)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T;
+ if (ext_ability & MDIO_PMA_EXTABLE_1000BT)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
+ if (ext_ability & MDIO_PMA_EXTABLE_100BTX)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX;
+
+ return physical_layer;
+}
+
+/**
+ * ixgbe_init_eeprom_params_X540 - Initialize EEPROM params
+ * @hw: pointer to hardware structure
+ **/
+static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ u32 eec;
+ u16 eeprom_size;
+
+ if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ eeprom->semaphore_delay = 10;
+ eeprom->type = ixgbe_flash;
+
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
+ IXGBE_EEC_SIZE_SHIFT);
+ eeprom->word_size = 1 << (eeprom_size +
+ IXGBE_EEPROM_WORD_SIZE_SHIFT);
+
+ hw_dbg(hw, "Eeprom params: type = %d, size = %d\n",
+ eeprom->type, eeprom->word_size);
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_read_eerd_X540 - Read EEPROM word using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EERPOM
+ **/
+static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+ s32 status;
+
+ if (ixgbe_acquire_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM) == 0)
+ status = ixgbe_read_eerd_generic(hw, offset, data);
+ else
+ status = IXGBE_ERR_SWFW_SYNC;
+
+ ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+ return status;
+}
+
+/**
+ * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @data: word write to the EEPROM
+ *
+ * Write a 16 bit word to the EEPROM using the EEWR register.
+ **/
+static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+ u32 eewr;
+ s32 status;
+
+ hw->eeprom.ops.init_params(hw);
+
+ if (offset >= hw->eeprom.word_size) {
+ status = IXGBE_ERR_EEPROM;
+ goto out;
+ }
+
+ eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) |
+ (data << IXGBE_EEPROM_RW_REG_DATA) |
+ IXGBE_EEPROM_RW_REG_START;
+
+ if (ixgbe_acquire_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM) == 0) {
+ status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+ if (status != 0) {
+ hw_dbg(hw, "Eeprom write EEWR timed out\n");
+ goto out;
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+
+ status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+ if (status != 0) {
+ hw_dbg(hw, "Eeprom write EEWR timed out\n");
+ goto out;
+ }
+ } else {
+ status = IXGBE_ERR_SWFW_SYNC;
+ }
+
+out:
+ ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+ return status;
+}
+
+/**
+ * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ **/
+static u16 ixgbe_calc_eeprom_checksum_X540(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 (hw->eeprom.ops.read(hw, i, &word) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+ checksum += word;
+ }
+
+ /*
+ * Include all data from pointers 0x3, 0x6-0xE. This excludes the
+ * FW, PHY module, and PCIe Expansion/Option ROM pointers.
+ */
+ for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
+ if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
+ continue;
+
+ if (hw->eeprom.ops.read(hw, i, &pointer) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+
+ /* Skip pointer section if the pointer is invalid. */
+ if (pointer == 0xFFFF || pointer == 0 ||
+ pointer >= hw->eeprom.word_size)
+ continue;
+
+ if (hw->eeprom.ops.read(hw, pointer, &length) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+
+ /* Skip pointer section if length is invalid. */
+ if (length == 0xFFFF || length == 0 ||
+ (pointer + length) >= hw->eeprom.word_size)
+ continue;
+
+ for (j = pointer+1; j <= pointer+length; j++) {
+ if (hw->eeprom.ops.read(hw, j, &word) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+ checksum += word;
+ }
+ }
+
+ checksum = (u16)IXGBE_EEPROM_SUM - checksum;
+
+ return checksum;
+}
+
+/**
+ * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash
+ * @hw: pointer to hardware structure
+ *
+ * After writing EEPROM to shadow RAM using EEWR register, software calculates
+ * checksum and updates the EEPROM and instructs the hardware to update
+ * the flash.
+ **/
+static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw)
+{
+ s32 status;
+
+ status = ixgbe_update_eeprom_checksum_generic(hw);
+
+ if (status)
+ status = ixgbe_update_flash_X540(hw);
+
+ return status;
+}
+
+/**
+ * ixgbe_update_flash_X540 - Instruct HW to copy EEPROM to Flash device
+ * @hw: pointer to hardware structure
+ *
+ * Set FLUP (bit 23) of the EEC register to instruct Hardware to copy
+ * EEPROM from shadow RAM to the flash device.
+ **/
+static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
+{
+ u32 flup;
+ s32 status = IXGBE_ERR_EEPROM;
+
+ status = ixgbe_poll_flash_update_done_X540(hw);
+ if (status == IXGBE_ERR_EEPROM) {
+ hw_dbg(hw, "Flash update time out\n");
+ goto out;
+ }
+
+ flup = IXGBE_READ_REG(hw, IXGBE_EEC) | IXGBE_EEC_FLUP;
+ IXGBE_WRITE_REG(hw, IXGBE_EEC, flup);
+
+ status = ixgbe_poll_flash_update_done_X540(hw);
+ if (status)
+ hw_dbg(hw, "Flash update complete\n");
+ else
+ hw_dbg(hw, "Flash update time out\n");
+
+ if (hw->revision_id == 0) {
+ flup = IXGBE_READ_REG(hw, IXGBE_EEC);
+
+ if (flup & IXGBE_EEC_SEC1VAL) {
+ flup |= IXGBE_EEC_FLUP;
+ IXGBE_WRITE_REG(hw, IXGBE_EEC, flup);
+ }
+
+ status = ixgbe_poll_flash_update_done_X540(hw);
+ if (status)
+ hw_dbg(hw, "Flash update complete\n");
+ else
+ hw_dbg(hw, "Flash update time out\n");
+
+ }
+out:
+ return status;
+}
+
+/**
+ * ixgbe_poll_flash_update_done_X540 - Poll flash update status
+ * @hw: pointer to hardware structure
+ *
+ * Polls the FLUDONE (bit 26) of the EEC Register to determine when the
+ * flash update is done.
+ **/
+static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 reg;
+ s32 status = IXGBE_ERR_EEPROM;
+
+ for (i = 0; i < IXGBE_FLUDONE_ATTEMPTS; i++) {
+ reg = IXGBE_READ_REG(hw, IXGBE_EEC);
+ if (reg & IXGBE_EEC_FLUDONE) {
+ status = 0;
+ break;
+ }
+ udelay(5);
+ }
+ return status;
+}
+
+/**
+ * ixgbe_acquire_swfw_sync_X540 - Acquire SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to acquire
+ *
+ * Acquires the SWFW semaphore thought the SW_FW_SYNC register for
+ * the specified function (CSR, PHY0, PHY1, NVM, Flash)
+ **/
+static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+ u32 fwmask = mask << 5;
+ u32 hwmask = 0;
+ u32 timeout = 200;
+ u32 i;
+
+ if (swmask == IXGBE_GSSR_EEP_SM)
+ hwmask = IXGBE_GSSR_FLASH_SM;
+
+ for (i = 0; i < timeout; i++) {
+ /*
+ * SW NVM semaphore bit is used for access to all
+ * SW_FW_SYNC bits (not just NVM)
+ */
+ if (ixgbe_get_swfw_sync_semaphore(hw))
+ return IXGBE_ERR_SWFW_SYNC;
+
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask | hwmask))) {
+ swfw_sync |= swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+ ixgbe_release_swfw_sync_semaphore(hw);
+ break;
+ } else {
+ /*
+ * Firmware currently using resource (fwmask),
+ * hardware currently using resource (hwmask),
+ * or other software thread currently using
+ * resource (swmask)
+ */
+ ixgbe_release_swfw_sync_semaphore(hw);
+ msleep(5);
+ }
+ }
+
+ /*
+ * If the resource is not released by the FW/HW the SW can assume that
+ * the FW/HW malfunctions. In that case the SW should sets the
+ * SW bit(s) of the requested resource(s) while ignoring the
+ * corresponding FW/HW bits in the SW_FW_SYNC register.
+ */
+ if (i >= timeout) {
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ if (swfw_sync & (fwmask | hwmask)) {
+ if (ixgbe_get_swfw_sync_semaphore(hw))
+ return IXGBE_ERR_SWFW_SYNC;
+
+ swfw_sync |= swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+ ixgbe_release_swfw_sync_semaphore(hw);
+ }
+ }
+
+ msleep(5);
+ return 0;
+}
+
+/**
+ * ixgbe_release_swfw_sync_X540 - Release SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to release
+ *
+ * Releases the SWFW semaphore throught the SW_FW_SYNC register
+ * for the specified function (CSR, PHY0, PHY1, EVM, Flash)
+ **/
+static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+
+ ixgbe_get_swfw_sync_semaphore(hw);
+
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swfw_sync &= ~swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+
+ ixgbe_release_swfw_sync_semaphore(hw);
+ msleep(5);
+}
+
+/**
+ * ixgbe_get_nvm_semaphore - Get hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * Sets the hardware semaphores so SW/FW can gain control of shared resources
+ **/
+static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_ERR_EEPROM;
+ u32 timeout = 2000;
+ u32 i;
+ u32 swsm;
+
+ /* 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;
+ }
+ udelay(50);
+ }
+
+ /* Now get the semaphore between SW/FW through the REGSMP bit */
+ if (status) {
+ for (i = 0; i < timeout; i++) {
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ if (!(swsm & IXGBE_SWFW_REGSMP))
+ break;
+
+ udelay(50);
+ }
+ } else {
+ hw_dbg(hw, "Software semaphore SMBI between device drivers "
+ "not granted.\n");
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_release_nvm_semaphore - Release hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * This function clears hardware semaphore bits.
+ **/
+static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw)
+{
+ u32 swsm;
+
+ /* Release both semaphores by writing 0 to the bits REGSMP and SMBI */
+
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm &= ~IXGBE_SWSM_SMBI;
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swsm &= ~IXGBE_SWFW_REGSMP;
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swsm);
+
+ IXGBE_WRITE_FLUSH(hw);
+}
+
+static struct ixgbe_mac_operations mac_ops_X540 = {
+ .init_hw = &ixgbe_init_hw_generic,
+ .reset_hw = &ixgbe_reset_hw_X540,
+ .start_hw = &ixgbe_start_hw_generic,
+ .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic,
+ .get_media_type = &ixgbe_get_media_type_X540,
+ .get_supported_physical_layer =
+ &ixgbe_get_supported_physical_layer_X540,
+ .enable_rx_dma = &ixgbe_enable_rx_dma_generic,
+ .get_mac_addr = &ixgbe_get_mac_addr_generic,
+ .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic,
+ .get_device_caps = NULL,
+ .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic,
+ .stop_adapter = &ixgbe_stop_adapter_generic,
+ .get_bus_info = &ixgbe_get_bus_info_generic,
+ .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie,
+ .read_analog_reg8 = NULL,
+ .write_analog_reg8 = NULL,
+ .setup_link = &ixgbe_setup_mac_link_X540,
+ .check_link = &ixgbe_check_mac_link_generic,
+ .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic,
+ .led_on = &ixgbe_led_on_generic,
+ .led_off = &ixgbe_led_off_generic,
+ .blink_led_start = &ixgbe_blink_led_start_generic,
+ .blink_led_stop = &ixgbe_blink_led_stop_generic,
+ .set_rar = &ixgbe_set_rar_generic,
+ .clear_rar = &ixgbe_clear_rar_generic,
+ .set_vmdq = &ixgbe_set_vmdq_generic,
+ .clear_vmdq = &ixgbe_clear_vmdq_generic,
+ .init_rx_addrs = &ixgbe_init_rx_addrs_generic,
+ .update_uc_addr_list = &ixgbe_update_uc_addr_list_generic,
+ .update_mc_addr_list = &ixgbe_update_mc_addr_list_generic,
+ .enable_mc = &ixgbe_enable_mc_generic,
+ .disable_mc = &ixgbe_disable_mc_generic,
+ .clear_vfta = &ixgbe_clear_vfta_generic,
+ .set_vfta = &ixgbe_set_vfta_generic,
+ .fc_enable = &ixgbe_fc_enable_generic,
+ .init_uta_tables = &ixgbe_init_uta_tables_generic,
+ .setup_sfp = NULL,
+ .set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing,
+ .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing,
+};
+
+static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
+ .init_params = &ixgbe_init_eeprom_params_X540,
+ .read = &ixgbe_read_eerd_X540,
+ .write = &ixgbe_write_eewr_X540,
+ .calc_checksum = &ixgbe_calc_eeprom_checksum_X540,
+ .validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
+ .update_checksum = &ixgbe_update_eeprom_checksum_X540,
+};
+
+static struct ixgbe_phy_operations phy_ops_X540 = {
+ .identify = &ixgbe_identify_phy_generic,
+ .identify_sfp = &ixgbe_identify_sfp_module_generic,
+ .init = NULL,
+ .reset = &ixgbe_reset_phy_generic,
+ .read_reg = &ixgbe_read_phy_reg_generic,
+ .write_reg = &ixgbe_write_phy_reg_generic,
+ .setup_link = &ixgbe_setup_phy_link_generic,
+ .setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
+ .read_i2c_byte = &ixgbe_read_i2c_byte_generic,
+ .write_i2c_byte = &ixgbe_write_i2c_byte_generic,
+ .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic,
+ .write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic,
+ .check_overtemp = &ixgbe_tn_check_overtemp,
+};
+
+struct ixgbe_info ixgbe_X540_info = {
+ .mac = ixgbe_mac_X540,
+ .get_invariants = &ixgbe_get_invariants_X540,
+ .mac_ops = &mac_ops_X540,
+ .eeprom_ops = &eeprom_ops_X540,
+ .phy_ops = &phy_ops_X540,
+ .mbx_ops = &mbx_ops_generic,
+};
diff --git a/drivers/net/ixgbevf/Makefile b/drivers/net/ixgbevf/Makefile
index dd4e0d27e8cc..1f35d229e71a 100644
--- a/drivers/net/ixgbevf/Makefile
+++ b/drivers/net/ixgbevf/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel 82599 Virtual Function driver
-# Copyright(c) 1999 - 2009 Intel Corporation.
+# Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/ixgbevf/defines.h b/drivers/net/ixgbevf/defines.h
index ca2c81f49a05..de643eb2ada6 100644
--- a/drivers/net/ixgbevf/defines.h
+++ b/drivers/net/ixgbevf/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -30,6 +30,7 @@
/* Device IDs */
#define IXGBE_DEV_ID_82599_VF 0x10ED
+#define IXGBE_DEV_ID_X540_VF 0x1515
#define IXGBE_VF_IRQ_CLEAR_MASK 7
#define IXGBE_VF_MAX_TX_QUEUES 1
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 4cc817acfb62..fa29b3c8c464 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -544,7 +544,7 @@ struct ixgbevf_reg_test {
#define TABLE64_TEST_HI 6
/* default VF register test */
-static struct ixgbevf_reg_test reg_test_vf[] = {
+static const struct ixgbevf_reg_test reg_test_vf[] = {
{ IXGBE_VFRDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
{ IXGBE_VFRDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
{ IXGBE_VFRDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
@@ -557,19 +557,23 @@ static struct ixgbevf_reg_test reg_test_vf[] = {
{ 0, 0, 0, 0 }
};
+static const u32 register_test_patterns[] = {
+ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+};
+
#define REG_PATTERN_TEST(R, M, W) \
{ \
u32 pat, val, before; \
- const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
- for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \
+ for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \
before = readl(adapter->hw.hw_addr + R); \
- writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \
+ writel((register_test_patterns[pat] & W), \
+ (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
- if (val != (_test[pat] & W & M)) { \
+ if (val != (register_test_patterns[pat] & W & M)) { \
hw_dbg(&adapter->hw, \
"pattern test reg %04X failed: got " \
"0x%08X expected 0x%08X\n", \
- R, val, (_test[pat] & W & M)); \
+ R, val, (register_test_patterns[pat] & W & M)); \
*data = R; \
writel(before, adapter->hw.hw_addr + R); \
return 1; \
@@ -596,7 +600,7 @@ static struct ixgbevf_reg_test reg_test_vf[] = {
static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
{
- struct ixgbevf_reg_test *test;
+ const struct ixgbevf_reg_test *test;
u32 i;
test = reg_test_vf;
diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h
index da4033c6efa2..a63efcb2cf1b 100644
--- a/drivers/net/ixgbevf/ixgbevf.h
+++ b/drivers/net/ixgbevf/ixgbevf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -275,9 +275,11 @@ enum ixbgevf_state_t {
enum ixgbevf_boards {
board_82599_vf,
+ board_X540_vf,
};
-extern struct ixgbevf_info ixgbevf_vf_info;
+extern struct ixgbevf_info ixgbevf_82599_vf_info;
+extern struct ixgbevf_info ixgbevf_X540_vf_info;
extern struct ixgbe_mac_operations ixgbevf_mbx_ops;
/* needed by ethtool.c */
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index dc03c9652389..464e6c9d3fc2 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -51,12 +51,14 @@ char ixgbevf_driver_name[] = "ixgbevf";
static const char ixgbevf_driver_string[] =
"Intel(R) 82599 Virtual Function";
-#define DRV_VERSION "1.0.0-k0"
+#define DRV_VERSION "1.0.19-k0"
const char ixgbevf_driver_version[] = DRV_VERSION;
-static char ixgbevf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
+static char ixgbevf_copyright[] =
+ "Copyright (c) 2009 - 2010 Intel Corporation.";
static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
- [board_82599_vf] = &ixgbevf_vf_info,
+ [board_82599_vf] = &ixgbevf_82599_vf_info,
+ [board_X540_vf] = &ixgbevf_X540_vf_info,
};
/* ixgbevf_pci_tbl - PCI Device ID Table
@@ -70,6 +72,8 @@ static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
static struct pci_device_id ixgbevf_pci_tbl[] = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF),
board_82599_vf},
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF),
+ board_X540_vf},
/* required last entry */
{0, }
@@ -2488,10 +2492,9 @@ int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter,
int size;
size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count;
- tx_ring->tx_buffer_info = vmalloc(size);
+ tx_ring->tx_buffer_info = vzalloc(size);
if (!tx_ring->tx_buffer_info)
goto err;
- memset(tx_ring->tx_buffer_info, 0, size);
/* round up to nearest 4K */
tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
@@ -2555,14 +2558,13 @@ int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter,
int size;
size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count;
- rx_ring->rx_buffer_info = vmalloc(size);
+ rx_ring->rx_buffer_info = vzalloc(size);
if (!rx_ring->rx_buffer_info) {
hw_dbg(&adapter->hw,
"Unable to vmalloc buffer memory for "
"the receive descriptor ring\n");
goto alloc_failed;
}
- memset(rx_ring->rx_buffer_info, 0, size);
/* Round up to nearest 4K */
rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
@@ -3424,10 +3426,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
if (hw->mac.ops.get_bus_info)
hw->mac.ops.get_bus_info(hw);
-
- netif_carrier_off(netdev);
- netif_tx_stop_all_queues(netdev);
-
strcpy(netdev->name, "eth%d");
err = register_netdev(netdev);
@@ -3436,6 +3434,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
adapter->netdev_registered = true;
+ netif_carrier_off(netdev);
+
ixgbevf_init_last_counter_stats(adapter);
/* print the MAC address */
@@ -3487,10 +3487,9 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->watchdog_timer);
+ cancel_work_sync(&adapter->reset_task);
cancel_work_sync(&adapter->watchdog_task);
- flush_scheduled_work();
-
if (adapter->netdev_registered) {
unregister_netdev(netdev);
adapter->netdev_registered = false;
diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ixgbevf/mbx.c
index 84ac486f4a65..7a8833125770 100644
--- a/drivers/net/ixgbevf/mbx.c
+++ b/drivers/net/ixgbevf/mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h
index 8c063bebee7f..b2b5bf5daa3d 100644
--- a/drivers/net/ixgbevf/mbx.h
+++ b/drivers/net/ixgbevf/mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/ixgbevf/regs.h b/drivers/net/ixgbevf/regs.h
index 12f75960aec1..fb80ca1bcc93 100644
--- a/drivers/net/ixgbevf/regs.h
+++ b/drivers/net/ixgbevf/regs.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c
index bfe42c1fcfaf..eecd3bf6833f 100644
--- a/drivers/net/ixgbevf/vf.c
+++ b/drivers/net/ixgbevf/vf.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -381,8 +381,12 @@ static struct ixgbe_mac_operations ixgbevf_mac_ops = {
.set_vfta = ixgbevf_set_vfta_vf,
};
-struct ixgbevf_info ixgbevf_vf_info = {
+struct ixgbevf_info ixgbevf_82599_vf_info = {
.mac = ixgbe_mac_82599_vf,
.mac_ops = &ixgbevf_mac_ops,
};
+struct ixgbevf_info ixgbevf_X540_vf_info = {
+ .mac = ixgbe_mac_X540_vf,
+ .mac_ops = &ixgbevf_mac_ops,
+};
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h
index 61f9dc831424..23eb114c149f 100644
--- a/drivers/net/ixgbevf/vf.h
+++ b/drivers/net/ixgbevf/vf.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 82599 Virtual Function driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -73,6 +73,7 @@ struct ixgbe_mac_operations {
enum ixgbe_mac_type {
ixgbe_mac_unknown = 0,
ixgbe_mac_82599_vf,
+ ixgbe_mac_X540_vf,
ixgbe_num_macs
};
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index d85edf3119c2..e97ebef3cf47 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -135,7 +135,7 @@ jme_reset_phy_processor(struct jme_adapter *jme)
static void
jme_setup_wakeup_frame(struct jme_adapter *jme,
- u32 *mask, u32 crc, int fnr)
+ const u32 *mask, u32 crc, int fnr)
{
int i;
@@ -163,7 +163,7 @@ jme_setup_wakeup_frame(struct jme_adapter *jme,
static inline void
jme_reset_mac_processor(struct jme_adapter *jme)
{
- u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
+ static const u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0};
u32 crc = 0xCDCDCDCD;
u32 gpreg0;
int i;
@@ -2076,12 +2076,11 @@ jme_change_mtu(struct net_device *netdev, int new_mtu)
}
if (new_mtu > 1900) {
- netdev->features &= ~(NETIF_F_HW_CSUM |
- NETIF_F_TSO |
- NETIF_F_TSO6);
+ netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6);
} else {
if (test_bit(JME_FLAG_TXCSUM, &jme->flags))
- netdev->features |= NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
if (test_bit(JME_FLAG_TSO, &jme->flags))
netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
}
@@ -2514,10 +2513,12 @@ jme_set_tx_csum(struct net_device *netdev, u32 on)
if (on) {
set_bit(JME_FLAG_TXCSUM, &jme->flags);
if (netdev->mtu <= 1900)
- netdev->features |= NETIF_F_HW_CSUM;
+ netdev->features |=
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
} else {
clear_bit(JME_FLAG_TXCSUM, &jme->flags);
- netdev->features &= ~NETIF_F_HW_CSUM;
+ netdev->features &=
+ ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
}
return 0;
@@ -2797,7 +2798,8 @@ jme_init_one(struct pci_dev *pdev,
netdev->netdev_ops = &jme_netdev_ops;
netdev->ethtool_ops = &jme_ethtool_ops;
netdev->watchdog_timeo = TX_TIMEOUT;
- netdev->features = NETIF_F_HW_CSUM |
+ netdev->features = NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
NETIF_F_SG |
NETIF_F_TSO |
NETIF_F_TSO6 |
@@ -2955,11 +2957,7 @@ jme_init_one(struct pci_dev *pdev,
* Tell stack that we are not ready to work until open()
*/
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- /*
- * Register netdev
- */
rc = register_netdev(netdev);
if (rc) {
pr_err("Cannot register net device\n");
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 51919fcd50c2..0fa4a9887ba2 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -1545,6 +1545,37 @@ static int ks8851_read_selftest(struct ks8851_net *ks)
/* driver bus management functions */
+#ifdef CONFIG_PM
+static int ks8851_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct ks8851_net *ks = dev_get_drvdata(&spi->dev);
+ struct net_device *dev = ks->netdev;
+
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ ks8851_net_stop(dev);
+ }
+
+ return 0;
+}
+
+static int ks8851_resume(struct spi_device *spi)
+{
+ struct ks8851_net *ks = dev_get_drvdata(&spi->dev);
+ struct net_device *dev = ks->netdev;
+
+ if (netif_running(dev)) {
+ ks8851_net_open(dev);
+ netif_device_attach(dev);
+ }
+
+ return 0;
+}
+#else
+#define ks8851_suspend NULL
+#define ks8851_resume NULL
+#endif
+
static int __devinit ks8851_probe(struct spi_device *spi)
{
struct net_device *ndev;
@@ -1679,6 +1710,8 @@ static struct spi_driver ks8851_driver = {
},
.probe = ks8851_probe,
.remove = __devexit_p(ks8851_remove),
+ .suspend = ks8851_suspend,
+ .resume = ks8851_resume,
};
static int __init ks8851_init(void)
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index 37504a398906..540a8dcbcc46 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -3570,7 +3570,7 @@ static void hw_cfg_wol(struct ksz_hw *hw, u16 frame, int set)
* This routine is used to program Wake-on-LAN pattern.
*/
static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size,
- u8 *mask, uint frame_size, u8 *pattern)
+ const u8 *mask, uint frame_size, const u8 *pattern)
{
int bits;
int from;
@@ -3626,9 +3626,9 @@ static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size,
*
* This routine is used to add ARP pattern for waking up the host.
*/
-static void hw_add_wol_arp(struct ksz_hw *hw, u8 *ip_addr)
+static void hw_add_wol_arp(struct ksz_hw *hw, const u8 *ip_addr)
{
- u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 };
+ static const u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 };
u8 pattern[42] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -3651,8 +3651,8 @@ static void hw_add_wol_arp(struct ksz_hw *hw, u8 *ip_addr)
*/
static void hw_add_wol_bcast(struct ksz_hw *hw)
{
- u8 mask[] = { 0x3F };
- u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ static const u8 mask[] = { 0x3F };
+ static const u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern);
}
@@ -3669,7 +3669,7 @@ static void hw_add_wol_bcast(struct ksz_hw *hw)
*/
static void hw_add_wol_mcast(struct ksz_hw *hw)
{
- u8 mask[] = { 0x3F };
+ static const u8 mask[] = { 0x3F };
u8 pattern[] = { 0x33, 0x33, 0xFF, 0x00, 0x00, 0x00 };
memcpy(&pattern[3], &hw->override_addr[3], 3);
@@ -3687,7 +3687,7 @@ static void hw_add_wol_mcast(struct ksz_hw *hw)
*/
static void hw_add_wol_ucast(struct ksz_hw *hw)
{
- u8 mask[] = { 0x3F };
+ static const u8 mask[] = { 0x3F };
hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr);
}
@@ -3700,7 +3700,7 @@ static void hw_add_wol_ucast(struct ksz_hw *hw)
*
* This routine is used to enable Wake-on-LAN depending on driver settings.
*/
-static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, u8 *net_addr)
+static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, const u8 *net_addr)
{
hw_cfg_wol(hw, KS8841_WOL_MAGIC_ENABLE, (wol_enable & WAKE_MAGIC));
hw_cfg_wol(hw, KS8841_WOL_FRAME0_ENABLE, (wol_enable & WAKE_UCAST));
@@ -6208,7 +6208,7 @@ static int netdev_set_wol(struct net_device *dev,
struct dev_info *hw_priv = priv->adapter;
/* Need to find a way to retrieve the device IP address. */
- u8 net_addr[] = { 192, 168, 1, 1 };
+ static const u8 net_addr[] = { 192, 168, 1, 1 };
if (wol->wolopts & ~hw_priv->wol_support)
return -EINVAL;
@@ -6953,7 +6953,7 @@ static void read_other_addr(struct ksz_hw *hw)
#define PCI_VENDOR_ID_MICREL_KS 0x16c6
#endif
-static int __init pcidev_init(struct pci_dev *pdev,
+static int __devinit pcidev_init(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct net_device *dev;
@@ -7241,7 +7241,7 @@ static int pcidev_suspend(struct pci_dev *pdev, pm_message_t state)
struct ksz_hw *hw = &hw_priv->hw;
/* Need to find a way to retrieve the device IP address. */
- u8 net_addr[] = { 192, 168, 1, 1 };
+ static const u8 net_addr[] = { 192, 168, 1, 1 };
for (i = 0; i < hw->dev_count; i++) {
if (info->netdev[i]) {
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index f06296bfe293..02336edce748 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -207,7 +207,7 @@ tx_full and tbusy flags.
#define LANCE_BUS_IF 0x16
#define LANCE_TOTAL_SIZE 0x18
-#define TX_TIMEOUT 20
+#define TX_TIMEOUT (HZ/5)
/* The LANCE Rx and Tx ring descriptors. */
struct lance_rx_head {
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index c27f4291b350..9e042894479b 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -161,7 +161,7 @@ enum commands {
#define RX_SUSPEND 0x0030
#define RX_ABORT 0x0040
-#define TX_TIMEOUT 5
+#define TX_TIMEOUT (HZ/20)
struct i596_reg {
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index e7030ceb178b..da74db4a03d4 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -203,7 +203,7 @@ static void __NS8390_init(struct net_device *dev, int startp);
static int __ei_open(struct net_device *dev)
{
unsigned long flags;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = TX_TIMEOUT;
@@ -231,7 +231,7 @@ static int __ei_open(struct net_device *dev)
*/
static int __ei_close(struct net_device *dev)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned long flags;
/*
@@ -256,7 +256,7 @@ static int __ei_close(struct net_device *dev)
static void __ei_tx_timeout(struct net_device *dev)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
unsigned long flags;
@@ -303,7 +303,7 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int send_length = skb->len, output_page;
unsigned long flags;
char buf[ETH_ZLEN];
@@ -592,7 +592,7 @@ static void ei_tx_err(struct net_device *dev)
static void ei_tx_intr(struct net_device *dev)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int status = ei_inb(e8390_base + EN0_TSR);
ei_outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
@@ -675,7 +675,7 @@ static void ei_tx_intr(struct net_device *dev)
static void ei_receive(struct net_device *dev)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned char rxing_page, this_frame, next_frame;
unsigned short current_offset;
int rx_pkt_count = 0;
@@ -879,7 +879,7 @@ static void ei_rx_overrun(struct net_device *dev)
static struct net_device_stats *__ei_get_stats(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned long flags;
/* If the card is stopped, just return the present stats. */
@@ -927,7 +927,7 @@ static void do_set_multicast_list(struct net_device *dev)
{
unsigned long e8390_base = dev->base_addr;
int i;
- struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
{
@@ -981,7 +981,7 @@ static void do_set_multicast_list(struct net_device *dev)
static void __ei_set_multicast_list(struct net_device *dev)
{
unsigned long flags;
- struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
spin_lock_irqsave(&ei_local->page_lock, flags);
do_set_multicast_list(dev);
@@ -998,7 +998,7 @@ static void __ei_set_multicast_list(struct net_device *dev)
static void ethdev_setup(struct net_device *dev)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
if (ei_debug > 1)
printk(version);
@@ -1036,7 +1036,7 @@ static struct net_device *____alloc_ei_netdev(int size)
static void __NS8390_init(struct net_device *dev, int startp)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int i;
int endcfg = ei_local->word16
? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
@@ -1099,7 +1099,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
int start_page)
{
unsigned long e8390_base = dev->base_addr;
- struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev);
ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 9f8e7027b0b3..f35554d11441 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -238,7 +238,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
goto out;
}
/* allocate the tx and rx ring buffer descriptors. */
- /* returns a virtual addres and a physical address. */
+ /* returns a virtual address and a physical address. */
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->tx_bd_v) * TX_BD_NUM,
&lp->tx_bd_p, GFP_KERNEL);
@@ -692,7 +692,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cur_p->app0 = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- unsigned int csum_start_off = skb_transport_offset(skb);
+ unsigned int csum_start_off = skb_checksum_start_offset(skb);
unsigned int csum_index_off = csum_start_off + skb->csum_offset;
cur_p->app0 |= 1; /* TX Checksum Enabled */
@@ -952,7 +952,7 @@ static const struct attribute_group temac_attr_group = {
.attrs = temac_device_attrs,
};
-static int __init
+static int __devinit
temac_of_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *np;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 0fc9dc7f20db..6ed577b065df 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -38,6 +38,7 @@ struct macvlan_port {
struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
struct list_head vlans;
struct rcu_head rcu;
+ bool passthru;
};
#define macvlan_port_get_rcu(dev) \
@@ -169,6 +170,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
macvlan_broadcast(skb, port, NULL,
MACVLAN_MODE_PRIVATE |
MACVLAN_MODE_VEPA |
+ MACVLAN_MODE_PASSTHRU|
MACVLAN_MODE_BRIDGE);
else if (src->mode == MACVLAN_MODE_VEPA)
/* flood to everyone except source */
@@ -185,7 +187,10 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
return skb;
}
- vlan = macvlan_hash_lookup(port, eth->h_dest);
+ if (port->passthru)
+ vlan = list_first_entry(&port->vlans, struct macvlan_dev, list);
+ else
+ vlan = macvlan_hash_lookup(port, eth->h_dest);
if (vlan == NULL)
return skb;
@@ -243,18 +248,22 @@ xmit_world:
netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- int i = skb_get_queue_mapping(skb);
- struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
unsigned int len = skb->len;
int ret;
+ const struct macvlan_dev *vlan = netdev_priv(dev);
ret = macvlan_queue_xmit(skb, dev);
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
- txq->tx_packets++;
- txq->tx_bytes += len;
- } else
- txq->tx_dropped++;
+ struct macvlan_pcpu_stats *pcpu_stats;
+ pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
+ u64_stats_update_begin(&pcpu_stats->syncp);
+ pcpu_stats->tx_packets++;
+ pcpu_stats->tx_bytes += len;
+ u64_stats_update_end(&pcpu_stats->syncp);
+ } else {
+ this_cpu_inc(vlan->pcpu_stats->tx_dropped);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(macvlan_start_xmit);
@@ -284,6 +293,11 @@ static int macvlan_open(struct net_device *dev)
struct net_device *lowerdev = vlan->lowerdev;
int err;
+ if (vlan->port->passthru) {
+ dev_set_promiscuity(lowerdev, 1);
+ goto hash_add;
+ }
+
err = -EBUSY;
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
goto out;
@@ -296,6 +310,8 @@ static int macvlan_open(struct net_device *dev)
if (err < 0)
goto del_unicast;
}
+
+hash_add:
macvlan_hash_add(vlan);
return 0;
@@ -310,12 +326,18 @@ static int macvlan_stop(struct net_device *dev)
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
+ if (vlan->port->passthru) {
+ dev_set_promiscuity(lowerdev, -1);
+ goto hash_del;
+ }
+
dev_mc_unsync(lowerdev, dev);
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(lowerdev, -1);
dev_uc_del(lowerdev, dev->dev_addr);
+hash_del:
macvlan_hash_del(vlan);
return 0;
}
@@ -414,14 +436,15 @@ static int macvlan_init(struct net_device *dev)
dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
(lowerdev->state & MACVLAN_STATE_MASK);
dev->features = lowerdev->features & MACVLAN_FEATURES;
+ dev->features |= NETIF_F_LLTX;
dev->gso_max_size = lowerdev->gso_max_size;
dev->iflink = lowerdev->ifindex;
dev->hard_header_len = lowerdev->hard_header_len;
macvlan_set_lockdep_class(dev);
- vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats);
- if (!vlan->rx_stats)
+ vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats);
+ if (!vlan->pcpu_stats)
return -ENOMEM;
return 0;
@@ -431,7 +454,7 @@ static void macvlan_uninit(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- free_percpu(vlan->rx_stats);
+ free_percpu(vlan->pcpu_stats);
}
static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
@@ -439,33 +462,38 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
{
struct macvlan_dev *vlan = netdev_priv(dev);
- dev_txq_stats_fold(dev, stats);
-
- if (vlan->rx_stats) {
- struct macvlan_rx_stats *p, accum = {0};
- u64 rx_packets, rx_bytes, rx_multicast;
+ if (vlan->pcpu_stats) {
+ struct macvlan_pcpu_stats *p;
+ u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
+ u32 rx_errors = 0, tx_dropped = 0;
unsigned int start;
int i;
for_each_possible_cpu(i) {
- p = per_cpu_ptr(vlan->rx_stats, i);
+ p = per_cpu_ptr(vlan->pcpu_stats, i);
do {
start = u64_stats_fetch_begin_bh(&p->syncp);
rx_packets = p->rx_packets;
rx_bytes = p->rx_bytes;
rx_multicast = p->rx_multicast;
+ tx_packets = p->tx_packets;
+ tx_bytes = p->tx_bytes;
} while (u64_stats_fetch_retry_bh(&p->syncp, start));
- accum.rx_packets += rx_packets;
- accum.rx_bytes += rx_bytes;
- accum.rx_multicast += rx_multicast;
- /* rx_errors is an ulong, updated without syncp protection */
- accum.rx_errors += p->rx_errors;
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ stats->multicast += rx_multicast;
+ stats->tx_packets += tx_packets;
+ stats->tx_bytes += tx_bytes;
+ /* rx_errors & tx_dropped are u32, updated
+ * without syncp protection.
+ */
+ rx_errors += p->rx_errors;
+ tx_dropped += p->tx_dropped;
}
- stats->rx_packets = accum.rx_packets;
- stats->rx_bytes = accum.rx_bytes;
- stats->rx_errors = accum.rx_errors;
- stats->rx_dropped = accum.rx_errors;
- stats->multicast = accum.rx_multicast;
+ stats->rx_errors = rx_errors;
+ stats->rx_dropped = rx_errors;
+ stats->tx_dropped = tx_dropped;
}
return stats;
}
@@ -549,6 +577,7 @@ static int macvlan_port_create(struct net_device *dev)
if (port == NULL)
return -ENOMEM;
+ port->passthru = false;
port->dev = dev;
INIT_LIST_HEAD(&port->vlans);
for (i = 0; i < MACVLAN_HASH_SIZE; i++)
@@ -593,6 +622,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
case MACVLAN_MODE_PRIVATE:
case MACVLAN_MODE_VEPA:
case MACVLAN_MODE_BRIDGE:
+ case MACVLAN_MODE_PASSTHRU:
break;
default:
return -EINVAL;
@@ -601,25 +631,6 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
return 0;
}
-static int macvlan_get_tx_queues(struct net *net,
- struct nlattr *tb[],
- unsigned int *num_tx_queues,
- unsigned int *real_num_tx_queues)
-{
- struct net_device *real_dev;
-
- if (!tb[IFLA_LINK])
- return -EINVAL;
-
- real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
- if (!real_dev)
- return -ENODEV;
-
- *num_tx_queues = real_dev->num_tx_queues;
- *real_num_tx_queues = real_dev->real_num_tx_queues;
- return 0;
-}
-
int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
int (*receive)(struct sk_buff *skb),
@@ -661,6 +672,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
}
port = macvlan_port_get(lowerdev);
+ /* Only 1 macvlan device can be created in passthru mode */
+ if (port->passthru)
+ return -EINVAL;
+
vlan->lowerdev = lowerdev;
vlan->dev = dev;
vlan->port = port;
@@ -671,6 +686,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (data && data[IFLA_MACVLAN_MODE])
vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+ if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
+ if (!list_empty(&port->vlans))
+ return -EINVAL;
+ port->passthru = true;
+ memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
+ }
+
err = register_netdevice(dev);
if (err < 0)
goto destroy_port;
@@ -743,7 +765,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
{
/* common fields */
ops->priv_size = sizeof(struct macvlan_dev);
- ops->get_tx_queues = macvlan_get_tx_queues;
ops->validate = macvlan_validate;
ops->maxtype = IFLA_MACVLAN_MAX;
ops->policy = macvlan_policy;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 42567279843e..5933621ac3ff 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -504,8 +504,7 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- vnet_hdr->csum_start = skb->csum_start -
- skb_headroom(skb);
+ vnet_hdr->csum_start = skb_checksum_start_offset(skb);
vnet_hdr->csum_offset = skb->csum_offset;
} /* else everything is zero */
@@ -586,7 +585,7 @@ err:
rcu_read_lock_bh();
vlan = rcu_dereference(q->vlan);
if (vlan)
- netdev_get_tx_queue(vlan->dev, 0)->tx_dropped++;
+ vlan->dev->stats.tx_dropped++;
rcu_read_unlock_bh();
return err;
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index 8f4bf1f07c11..3a4277f6fac4 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -178,6 +178,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
} else {
int i;
+ buf->direct.buf = NULL;
buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
buf->npages = buf->nbufs;
buf->page_shift = PAGE_SHIFT;
@@ -229,7 +230,7 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf,
buf->direct.map);
else {
- if (BITS_PER_LONG == 64)
+ if (BITS_PER_LONG == 64 && buf->direct.buf)
vunmap(buf->direct.buf);
for (i = 0; i < buf->nbufs; ++i)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 6d6806b361e3..897f576b8b17 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -972,7 +972,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
int i;
int err;
- dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num);
+ dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
+ prof->tx_ring_num, prof->rx_ring_num);
if (dev == NULL) {
mlx4_err(mdev, "Net device allocation failed\n");
return -ENOMEM;
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index b68eee2414c2..5de1db897835 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -289,6 +289,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
dev_cap->bf_reg_size = 1 << (field & 0x1f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
+ if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size))
+ field = 3;
dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index dd2b6a71c6d7..02076e16542a 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1514,11 +1514,6 @@ static int mv643xx_eth_nway_reset(struct net_device *dev)
return genphy_restart_aneg(mp->phy);
}
-static u32 mv643xx_eth_get_link(struct net_device *dev)
-{
- return !!netif_carrier_ok(dev);
-}
-
static int
mv643xx_eth_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
{
@@ -1658,7 +1653,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.set_settings = mv643xx_eth_set_settings,
.get_drvinfo = mv643xx_eth_get_drvinfo,
.nway_reset = mv643xx_eth_nway_reset,
- .get_link = mv643xx_eth_get_link,
+ .get_link = ethtool_op_get_link,
.get_coalesce = mv643xx_eth_get_coalesce,
.set_coalesce = mv643xx_eth_set_coalesce,
.get_ringparam = mv643xx_eth_get_ringparam,
@@ -2983,7 +2978,7 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
unregister_netdev(mp->dev);
if (mp->phy != NULL)
phy_detach(mp->phy);
- flush_scheduled_work();
+ cancel_work_sync(&mp->tx_timeout_task);
free_netdev(mp->dev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 8524cc40ec57..ea5cfe2c3a04 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2736,7 +2736,7 @@ again:
odd_flag = 0;
flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST);
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
- cksum_offset = skb_transport_offset(skb);
+ cksum_offset = skb_checksum_start_offset(skb);
pseudo_hdr_offset = cksum_offset + skb->csum_offset;
/* If the headers are excessively large, then we must
* fall back to a software checksum */
@@ -3403,9 +3403,7 @@ static int myri10ge_resume(struct pci_dev *pdev)
return -EIO;
}
- status = pci_restore_state(pdev);
- if (status)
- return status;
+ pci_restore_state(pdev);
status = pci_enable_device(pdev);
if (status) {
@@ -4067,7 +4065,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
if (mgp == NULL)
return;
- flush_scheduled_work();
+ cancel_work_sync(&mgp->watchdog_work);
netdev = mgp->dev;
unregister_netdev(netdev);
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index e0b0ef11f110..30be8c634ebd 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -86,7 +86,7 @@ static u32 reg_offset[16];
static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int i;
unsigned char bus_width;
@@ -218,7 +218,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
int start_page, stop_page;
int reg0, ret;
static unsigned version_printed;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned char bus_width;
if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
@@ -371,7 +371,7 @@ static int ne_close(struct net_device *dev)
static void ne_reset_8390(struct net_device *dev)
{
unsigned long reset_start_time = jiffies;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
if (ei_debug > 1)
printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
@@ -397,7 +397,7 @@ static void ne_reset_8390(struct net_device *dev)
static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing)
@@ -437,7 +437,7 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, i
static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
#ifdef NE_SANITY_CHECK
int xfer_count = count;
#endif
@@ -507,7 +507,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
static void ne_block_output(struct net_device *dev, int count,
const unsigned char *buf, const int start_page)
{
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned long dma_start;
#ifdef NE_SANITY_CHECK
int retries = 0;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 94255f09093d..dfb67eb2a94b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -664,6 +664,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
unsigned long flags;
struct netconsole_target *nt;
struct net_device *dev = ptr;
+ bool stopped = false;
if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN))
@@ -690,15 +691,16 @@ static int netconsole_netdev_event(struct notifier_block *this,
case NETDEV_GOING_DOWN:
case NETDEV_BONDING_DESLAVE:
nt->enabled = 0;
+ stopped = true;
break;
}
}
netconsole_target_put(nt);
}
spin_unlock_irqrestore(&target_list_lock, flags);
- if (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE)
- printk(KERN_INFO "netconsole: network logging stopped, "
- "interface %s %s\n", dev->name,
+ if (stopped && (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE))
+ printk(KERN_INFO "netconsole: network logging stopped on "
+ "interface %s as it %s\n", dev->name,
event == NETDEV_UNREGISTER ? "unregistered" : "released slaves");
done:
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 8e8a97839cb0..a11380544e6c 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 74
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.74"
+#define _NETXEN_NIC_LINUX_SUBVERSION 75
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.75"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -1132,6 +1132,7 @@ typedef struct {
#define NETXEN_NIC_MSI_ENABLED 0x02
#define NETXEN_NIC_MSIX_ENABLED 0x04
#define NETXEN_NIC_LRO_ENABLED 0x08
+#define NETXEN_NIC_LRO_DISABLED 0x00
#define NETXEN_NIC_BRIDGE_ENABLED 0X10
#define NETXEN_NIC_DIAG_ENABLED 0x20
#define NETXEN_IS_MSI_FAMILY(adapter) \
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index b30de24f4a52..587498e140bb 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -720,7 +720,21 @@ static u32 netxen_nic_get_rx_csum(struct net_device *dev)
static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
{
struct netxen_adapter *adapter = netdev_priv(dev);
- adapter->rx_csum = !!data;
+
+ if (data) {
+ adapter->rx_csum = data;
+ return 0;
+ }
+
+ if (dev->features & NETIF_F_LRO) {
+ if (netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_DISABLED))
+ return -EIO;
+
+ dev->features &= ~NETIF_F_LRO;
+ netxen_send_lro_cleanup(adapter);
+ netdev_info(dev, "disabling LRO as rx_csum is off\n");
+ }
+ adapter->rx_csum = data;
return 0;
}
@@ -893,11 +907,19 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data)
if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO))
return -EINVAL;
+ if (!adapter->rx_csum) {
+ netdev_info(netdev, "rx csum is off, cannot toggle LRO\n");
+ return -EINVAL;
+ }
+
+ if (!!(data & ETH_FLAG_LRO) == !!(netdev->features & NETIF_F_LRO))
+ return 0;
+
if (data & ETH_FLAG_LRO) {
hw_lro = NETXEN_NIC_LRO_ENABLED;
netdev->features |= NETIF_F_LRO;
} else {
- hw_lro = 0;
+ hw_lro = NETXEN_NIC_LRO_DISABLED;
netdev->features &= ~NETIF_F_LRO;
}
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 37d3ebd65be8..5cef718fe35f 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -655,7 +655,7 @@ nx_p3_sre_macaddr_change(struct netxen_adapter *adapter, u8 *addr, unsigned op)
}
static int nx_p3_nic_add_mac(struct netxen_adapter *adapter,
- u8 *addr, struct list_head *del_list)
+ const u8 *addr, struct list_head *del_list)
{
struct list_head *head;
nx_mac_list_t *cur;
@@ -686,7 +686,9 @@ static void netxen_p3_nic_set_multi(struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
- u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ static const u8 bcast_addr[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
u32 mode = VPORT_MISS_MODE_DROP;
LIST_HEAD(del_list);
struct list_head *head;
@@ -807,9 +809,6 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable)
u64 word;
int rv = 0;
- if ((adapter->flags & NETXEN_NIC_LRO_ENABLED) == enable)
- return 0;
-
memset(&req, 0, sizeof(nx_nic_req_t));
req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
@@ -825,8 +824,6 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable)
"configure hw lro request\n");
}
- adapter->flags ^= NETXEN_NIC_LRO_ENABLED;
-
return rv;
}
@@ -869,9 +866,11 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
u64 word;
int i, rv;
- u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
- 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
- 0x255b0ec26d5a56daULL };
+ static const u64 key[] = {
+ 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+ 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+ 0x255b0ec26d5a56daULL
+ };
memset(&req, 0, sizeof(nx_nic_req_t));
@@ -895,7 +894,7 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
((u64)(enable & 0x1) << 8) |
((0x7ULL) << 48);
req.words[0] = cpu_to_le64(word);
- for (i = 0; i < 5; i++)
+ for (i = 0; i < ARRAY_SIZE(key); i++)
req.words[i+1] = cpu_to_le64(key[i]);
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 95fe552aa279..731077d8d962 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -214,13 +214,12 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
tx_ring->num_desc = adapter->num_txd;
tx_ring->txq = netdev_get_tx_queue(netdev, 0);
- cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
+ cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
if (cmd_buf_arr == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n",
netdev->name);
goto err_out;
}
- memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
tx_ring->cmd_buf_arr = cmd_buf_arr;
recv_ctx = &adapter->recv_ctx;
@@ -279,8 +278,7 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
break;
}
- rds_ring->rx_buf_arr = (struct netxen_rx_buffer *)
- vmalloc(RCV_BUFF_RINGSIZE(rds_ring));
+ rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
if (rds_ring->rx_buf_arr == NULL) {
printk(KERN_ERR "%s: Failed to allocate "
"rx buffer ring %d\n",
@@ -288,7 +286,6 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
/* free whatever was already allocated */
goto err_out;
}
- memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
INIT_LIST_HEAD(&rds_ring->free_list);
/*
* Now go through all of them, set reference handles
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 35ae1aa12896..33fac32e0d9f 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -38,12 +38,9 @@
#include <linux/sysfs.h>
#include <linux/aer.h>
-MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
+MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Intelligent Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
char netxen_nic_driver_name[] = "netxen_nic";
@@ -765,8 +762,6 @@ netxen_check_options(struct netxen_adapter *adapter)
if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222))
adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
- adapter->flags &= ~NETXEN_NIC_LRO_ENABLED;
-
if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
@@ -993,7 +988,7 @@ __netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
netxen_config_intr_coalesce(adapter);
- if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)
+ if (netdev->features & NETIF_F_LRO)
netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_ENABLED);
netxen_napi_enable(adapter);
@@ -1240,7 +1235,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
dev_warn(&pdev->dev, "failed to read mac addr\n");
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
err = register_netdev(netdev);
if (err) {
@@ -1281,6 +1275,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int i = 0, err;
int pci_func_id = PCI_FUNC(pdev->devfn);
uint8_t revision_id;
+ u32 val;
if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) {
pr_warning("%s: chip revisions between 0x%x-0x%x "
@@ -1356,8 +1351,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- if (reset_devices) {
- if (adapter->portnum == 0) {
+ if (adapter->portnum == 0) {
+ val = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
+ if (val != 0xffffffff && val != 0) {
NXWR32(adapter, NX_CRB_DEV_REF_COUNT, 0);
adapter->need_fw_reset = 1;
}
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 33618edc61f9..d973fc6c6b88 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -388,9 +388,9 @@ static long memend; /* e.g 0xd4000 */
struct net_device * __init ni52_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct priv));
- static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
+ static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
+ const int *port;
struct priv *p;
- int *port;
int err = 0;
if (!dev)
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index da228a0dd6cd..c75ae85eb918 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -361,8 +361,8 @@ static int dma;
struct net_device * __init ni65_probe(int unit)
{
struct net_device *dev = alloc_etherdev(0);
- static int ports[] = {0x360,0x300,0x320,0x340, 0};
- int *port;
+ static const int ports[] = { 0x360, 0x300, 0x320, 0x340, 0 };
+ const int *port;
int err = 0;
if (!dev)
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 781e368329f9..2541321bad82 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -6589,7 +6589,7 @@ static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
(ip_proto == IPPROTO_UDP ?
TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP));
- start = skb_transport_offset(skb) -
+ start = skb_checksum_start_offset(skb) -
(pad_bytes + sizeof(struct tx_pkt_hdr));
stuff = start + skb->csum_offset;
@@ -9917,7 +9917,7 @@ static int niu_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
- flush_scheduled_work();
+ flush_work_sync(&np->reset_task);
niu_netif_stop(np);
del_timer_sync(&np->timer);
diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c
index c8cc32c0edc9..c8c873b31a89 100644
--- a/drivers/net/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c
@@ -469,18 +469,6 @@ static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data)
}
/**
- * pch_gbe_get_tx_csum - Report whether transmit checksums are turned on or off
- * @netdev: Network interface device structure
- * Returns
- * true(1): Checksum On
- * false(0): Checksum Off
- */
-static u32 pch_gbe_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-/**
* pch_gbe_set_tx_csum - Turn transmit checksums on or off
* @netdev: Network interface device structure
* @data: Checksum on[true] or off[false]
@@ -493,11 +481,7 @@ static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data)
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
adapter->tx_csum = data;
- if (data)
- netdev->features |= NETIF_F_HW_CSUM;
- else
- netdev->features &= ~NETIF_F_HW_CSUM;
- return 0;
+ return ethtool_op_set_tx_ipv6_csum(netdev, data);
}
/**
@@ -572,7 +556,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = {
.set_pauseparam = pch_gbe_set_pauseparam,
.get_rx_csum = pch_gbe_get_rx_csum,
.set_rx_csum = pch_gbe_set_rx_csum,
- .get_tx_csum = pch_gbe_get_tx_csum,
.set_tx_csum = pch_gbe_set_tx_csum,
.get_strings = pch_gbe_get_strings,
.get_ethtool_stats = pch_gbe_get_ethtool_stats,
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index 472056b47440..d7355306a738 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
*
* This code was derived from the Intel e1000e Linux driver.
*
@@ -1523,12 +1523,11 @@ int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter,
int desNo;
size = (int)sizeof(struct pch_gbe_buffer) * tx_ring->count;
- tx_ring->buffer_info = vmalloc(size);
+ tx_ring->buffer_info = vzalloc(size);
if (!tx_ring->buffer_info) {
pr_err("Unable to allocate memory for the buffer infomation\n");
return -ENOMEM;
}
- memset(tx_ring->buffer_info, 0, size);
tx_ring->size = tx_ring->count * (int)sizeof(struct pch_gbe_tx_desc);
@@ -1573,12 +1572,11 @@ int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter,
int desNo;
size = (int)sizeof(struct pch_gbe_buffer) * rx_ring->count;
- rx_ring->buffer_info = vmalloc(size);
+ rx_ring->buffer_info = vzalloc(size);
if (!rx_ring->buffer_info) {
pr_err("Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
- memset(rx_ring->buffer_info, 0, size);
rx_ring->size = rx_ring->count * (int)sizeof(struct pch_gbe_rx_desc);
rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
&rx_ring->dma, GFP_KERNEL);
@@ -2321,7 +2319,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
netif_napi_add(netdev, &adapter->napi,
pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT);
- netdev->features = NETIF_F_HW_CSUM | NETIF_F_GRO;
+ netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO;
pch_gbe_set_ethtool_ops(netdev);
pch_gbe_mac_reset_hw(&adapter->hw);
@@ -2360,9 +2358,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
pch_gbe_check_options(adapter);
if (adapter->tx_csum)
- netdev->features |= NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
else
- netdev->features &= ~NETIF_F_HW_CSUM;
+ netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
/* initialize the wol settings based on the eeprom settings */
adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING;
@@ -2464,8 +2462,8 @@ static void __exit pch_gbe_exit_module(void)
module_init(pch_gbe_init_module);
module_exit(pch_gbe_exit_module);
-MODULE_DESCRIPTION("OKI semiconductor PCH Gigabit ethernet Driver");
-MODULE_AUTHOR("OKI semiconductor, <masa-korg@dsn.okisemi.com>");
+MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
+MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c
index 2510146fc560..ef0996a0eaaa 100644
--- a/drivers/net/pch_gbe/pch_gbe_param.c
+++ b/drivers/net/pch_gbe/pch_gbe_param.c
@@ -434,8 +434,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
.err = "using default of "
__MODULE_STRING(PCH_GBE_DEFAULT_TXD),
.def = PCH_GBE_DEFAULT_TXD,
- .arg = { .r = { .min = PCH_GBE_MIN_TXD } },
- .arg = { .r = { .max = PCH_GBE_MAX_TXD } }
+ .arg = { .r = { .min = PCH_GBE_MIN_TXD,
+ .max = PCH_GBE_MAX_TXD } }
};
struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
tx_ring->count = TxDescriptors;
@@ -450,8 +450,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
.err = "using default of "
__MODULE_STRING(PCH_GBE_DEFAULT_RXD),
.def = PCH_GBE_DEFAULT_RXD,
- .arg = { .r = { .min = PCH_GBE_MIN_RXD } },
- .arg = { .r = { .max = PCH_GBE_MAX_RXD } }
+ .arg = { .r = { .min = PCH_GBE_MIN_RXD,
+ .max = PCH_GBE_MAX_RXD } }
};
struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
rx_ring->count = RxDescriptors;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index d2e166e29dda..1f42f6ac8551 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -111,13 +111,14 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id);
typedef struct axnet_dev_t {
struct pcmcia_device *p_dev;
- caddr_t base;
- struct timer_list watchdog;
- int stale, fast_poll;
- u_short link_status;
- u_char duplex_flag;
- int phy_id;
- int flags;
+ caddr_t base;
+ struct timer_list watchdog;
+ int stale, fast_poll;
+ u_short link_status;
+ u_char duplex_flag;
+ int phy_id;
+ int flags;
+ int active_low;
} axnet_dev_t;
static inline axnet_dev_t *PRIV(struct net_device *dev)
@@ -322,6 +323,8 @@ static int axnet_config(struct pcmcia_device *link)
if (info->flags & IS_AX88790)
outb(0x10, dev->base_addr + AXNET_GPIO); /* select Internal PHY */
+ info->active_low = 0;
+
for (i = 0; i < 32; i++) {
j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
@@ -329,15 +332,18 @@ static int axnet_config(struct pcmcia_device *link)
if ((j != 0) && (j != 0xffff)) break;
}
- /* Maybe PHY is in power down mode. (PPD_SET = 1)
- Bit 2 of CCSR is active low. */
if (i == 32) {
+ /* Maybe PHY is in power down mode. (PPD_SET = 1)
+ Bit 2 of CCSR is active low. */
pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
for (i = 0; i < 32; i++) {
j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
if (j == j2) continue;
- if ((j != 0) && (j != 0xffff)) break;
+ if ((j != 0) && (j != 0xffff)) {
+ info->active_low = 1;
+ break;
+ }
}
}
@@ -383,8 +389,12 @@ static int axnet_suspend(struct pcmcia_device *link)
static int axnet_resume(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
+ axnet_dev_t *info = PRIV(dev);
if (link->open) {
+ if (info->active_low == 1)
+ pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
+
axnet_reset_8390(dev);
AX88190_init(dev, 1);
netif_device_attach(dev);
@@ -680,6 +690,7 @@ static void block_output(struct net_device *dev, int count,
static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
@@ -865,7 +876,7 @@ static void do_set_multicast_list(struct net_device *dev);
static int ax_open(struct net_device *dev)
{
unsigned long flags;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
/*
* Grab the page lock so we own the register set, then call
@@ -916,7 +927,7 @@ static int ax_close(struct net_device *dev)
static void axnet_tx_timeout(struct net_device *dev)
{
long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
unsigned long flags;
@@ -963,7 +974,7 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int length, send_length, output_page;
unsigned long flags;
u8 packet[ETH_ZLEN];
@@ -1260,7 +1271,7 @@ static void ei_tx_err(struct net_device *dev)
static void ei_tx_intr(struct net_device *dev)
{
long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int status = inb(e8390_base + EN0_TSR);
/*
@@ -1344,7 +1355,7 @@ static void ei_tx_intr(struct net_device *dev)
static void ei_receive(struct net_device *dev)
{
long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned char rxing_page, this_frame, next_frame;
unsigned short current_offset;
int rx_pkt_count = 0;
@@ -1529,7 +1540,7 @@ static void ei_rx_overrun(struct net_device *dev)
static struct net_device_stats *get_stats(struct net_device *dev)
{
long ioaddr = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
unsigned long flags;
/* If the card is stopped, just return the present stats. */
@@ -1578,7 +1589,7 @@ static void do_set_multicast_list(struct net_device *dev)
{
long e8390_base = dev->base_addr;
int i;
- struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
memset(ei_local->mcfilter, 0, 8);
@@ -1636,7 +1647,7 @@ static void AX88190_init(struct net_device *dev, int startp)
{
axnet_dev_t *info = PRIV(dev);
long e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local = netdev_priv(dev);
int i;
int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
@@ -1702,7 +1713,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
int start_page)
{
long e8390_base = dev->base_addr;
- struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+ struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev);
if (inb_p(e8390_base) & E8390_TRANS)
{
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 0a2b0f9cdf33..76683d97d83b 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1291,7 +1291,7 @@ updateCRC
static void updateCRC(int *CRC, int bit)
{
- int poly[]={
+ static const int poly[]={
1,1,1,0, 1,1,0,1,
1,0,1,1, 1,0,0,0,
1,0,0,0, 0,0,1,1,
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 03096c80103d..e953793a33ff 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1493,7 +1493,6 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
- PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
@@ -1536,6 +1535,8 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
+ PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether CF-TD LAN Card", 0x5261440f, 0x8797663b),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index cb3d13e4e074..35fda5ac8120 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -64,7 +64,7 @@ config BCM63XX_PHY
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
---help---
- Currently supports the IP175C PHY.
+ Currently supports the IP175C and IP1001 PHYs.
config REALTEK_PHY
tristate "Drivers for Realtek PHYs"
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index c1d2d251fe8b..9a09e24c30bc 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -30,7 +30,7 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-MODULE_DESCRIPTION("ICPlus IP175C PHY driver");
+MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers");
MODULE_AUTHOR("Michael Barkowski");
MODULE_LICENSE("GPL");
@@ -89,6 +89,33 @@ static int ip175c_config_init(struct phy_device *phydev)
return 0;
}
+static int ip1001_config_init(struct phy_device *phydev)
+{
+ int err, value;
+
+ /* Software Reset PHY */
+ value = phy_read(phydev, MII_BMCR);
+ value |= BMCR_RESET;
+ err = phy_write(phydev, MII_BMCR, value);
+ if (err < 0)
+ return err;
+
+ do {
+ value = phy_read(phydev, MII_BMCR);
+ } while (value & BMCR_RESET);
+
+ /* Additional delay (2ns) used to adjust RX clock phase
+ * at GMII/ RGMII interface */
+ value = phy_read(phydev, 16);
+ value |= 0x3;
+
+ err = phy_write(phydev, 16, value);
+ if (err < 0)
+ return err;
+
+ return err;
+}
+
static int ip175c_read_status(struct phy_device *phydev)
{
if (phydev->addr == 4) /* WAN port */
@@ -121,21 +148,43 @@ static struct phy_driver ip175c_driver = {
.driver = { .owner = THIS_MODULE,},
};
-static int __init ip175c_init(void)
+static struct phy_driver ip1001_driver = {
+ .phy_id = 0x02430d90,
+ .name = "ICPlus IP1001",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_GBIT_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause,
+ .config_init = &ip1001_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init icplus_init(void)
{
+ int ret = 0;
+
+ ret = phy_driver_register(&ip1001_driver);
+ if (ret < 0)
+ return -ENODEV;
+
return phy_driver_register(&ip175c_driver);
}
-static void __exit ip175c_exit(void)
+static void __exit icplus_exit(void)
{
+ phy_driver_unregister(&ip1001_driver);
phy_driver_unregister(&ip175c_driver);
}
-module_init(ip175c_init);
-module_exit(ip175c_exit);
+module_init(icplus_init);
+module_exit(icplus_exit);
static struct mdio_device_id __maybe_unused icplus_tbl[] = {
{ 0x02430d80, 0x0ffffff0 },
+ { 0x02430d90, 0x0ffffff0 },
{ }
};
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index e2afdce0a437..e8b9c53c304b 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -30,11 +30,14 @@
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/marvell_phy.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#define MII_MARVELL_PHY_PAGE 22
+
#define MII_M1011_IEVENT 0x13
#define MII_M1011_IEVENT_CLEAR 0x0000
@@ -74,13 +77,12 @@
#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4))
-#define MII_88EC048_PHY_MSCR1_REG 16
-#define MII_88EC048_PHY_MSCR1_PAD_ODD BIT(6)
+#define MII_88E1318S_PHY_MSCR1_REG 16
+#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
#define MII_88E1121_PHY_LED_CTRL 16
#define MII_88E1121_PHY_LED_PAGE 3
#define MII_88E1121_PHY_LED_DEF 0x0030
-#define MII_88E1121_PHY_PAGE 22
#define MII_M1011_PHY_STATUS 0x11
#define MII_M1011_PHY_STATUS_1000 0x8000
@@ -186,13 +188,94 @@ static int marvell_config_aneg(struct phy_device *phydev)
return 0;
}
+#ifdef CONFIG_OF_MDIO
+/*
+ * Set and/or override some configuration registers based on the
+ * marvell,reg-init property stored in the of_node for the phydev.
+ *
+ * marvell,reg-init = <reg-page reg mask value>,...;
+ *
+ * There may be one or more sets of <reg-page reg mask value>:
+ *
+ * reg-page: which register bank to use.
+ * reg: the register.
+ * mask: if non-zero, ANDed with existing register value.
+ * value: ORed with the masked value and written to the regiser.
+ *
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+ const __be32 *paddr;
+ int len, i, saved_page, current_page, page_changed, ret;
+
+ if (!phydev->dev.of_node)
+ return 0;
+
+ paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+ if (!paddr || len < (4 * sizeof(*paddr)))
+ return 0;
+
+ saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+ if (saved_page < 0)
+ return saved_page;
+ page_changed = 0;
+ current_page = saved_page;
+
+ ret = 0;
+ len /= sizeof(*paddr);
+ for (i = 0; i < len - 3; i += 4) {
+ u16 reg_page = be32_to_cpup(paddr + i);
+ u16 reg = be32_to_cpup(paddr + i + 1);
+ u16 mask = be32_to_cpup(paddr + i + 2);
+ u16 val_bits = be32_to_cpup(paddr + i + 3);
+ int val;
+
+ if (reg_page != current_page) {
+ current_page = reg_page;
+ page_changed = 1;
+ ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
+ if (ret < 0)
+ goto err;
+ }
+
+ val = 0;
+ if (mask) {
+ val = phy_read(phydev, reg);
+ if (val < 0) {
+ ret = val;
+ goto err;
+ }
+ val &= mask;
+ }
+ val |= val_bits;
+
+ ret = phy_write(phydev, reg, val);
+ if (ret < 0)
+ goto err;
+
+ }
+err:
+ if (page_changed) {
+ i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
+ if (ret == 0)
+ ret = i;
+ }
+ return ret;
+}
+#else
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
static int m88e1121_config_aneg(struct phy_device *phydev)
{
int err, oldpage, mscr;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
@@ -218,7 +301,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
return err;
}
- phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
@@ -229,36 +312,36 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
- phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
err = genphy_config_aneg(phydev);
return err;
}
-static int m88ec048_config_aneg(struct phy_device *phydev)
+static int m88e1318_config_aneg(struct phy_device *phydev)
{
int err, oldpage, mscr;
- oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
- err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
- mscr = phy_read(phydev, MII_88EC048_PHY_MSCR1_REG);
- mscr |= MII_88EC048_PHY_MSCR1_PAD_ODD;
+ mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
+ mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
- err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+ err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
if (err < 0)
return err;
- err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
if (err < 0)
return err;
@@ -368,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev)
return err;
}
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
@@ -398,7 +484,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
int err;
/* Change address */
- err = phy_write(phydev, 0x16, 0x0002);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
if (err < 0)
return err;
@@ -408,7 +494,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
return err;
/* Change address */
- err = phy_write(phydev, 0x16, 0x0003);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
if (err < 0)
return err;
@@ -420,8 +506,42 @@ static int m88e1118_config_init(struct phy_device *phydev)
if (err < 0)
return err;
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
/* Reset address */
- err = phy_write(phydev, 0x16, 0x0);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int m88e1149_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ /* Change address */
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+ if (err < 0)
+ return err;
+
+ /* Enable 1000 Mbit */
+ err = phy_write(phydev, 0x15, 0x1048);
+ if (err < 0)
+ return err;
+
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
+ /* Reset address */
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
if (err < 0)
return err;
@@ -491,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev)
}
}
+ err = marvell_of_reg_init(phydev);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -659,12 +783,12 @@ static struct phy_driver marvell_drivers[] = {
.driver = { .owner = THIS_MODULE },
},
{
- .phy_id = MARVELL_PHY_ID_88EC048,
+ .phy_id = MARVELL_PHY_ID_88E1318S,
.phy_id_mask = MARVELL_PHY_ID_MASK,
- .name = "Marvell 88EC048",
+ .name = "Marvell 88E1318S",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
- .config_aneg = &m88ec048_config_aneg,
+ .config_aneg = &m88e1318_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
@@ -685,6 +809,19 @@ static struct phy_driver marvell_drivers[] = {
.driver = { .owner = THIS_MODULE },
},
{
+ .phy_id = MARVELL_PHY_ID_88E1149R,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1149R",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &m88e1149_config_init,
+ .config_aneg = &m88e1118_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
+ {
.phy_id = MARVELL_PHY_ID_88E1240,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1240",
@@ -735,6 +872,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ 0x01410e10, 0xfffffff0 },
{ 0x01410cb0, 0xfffffff0 },
{ 0x01410cd0, 0xfffffff0 },
+ { 0x01410e50, 0xfffffff0 },
{ 0x01410e30, 0xfffffff0 },
{ 0x01410e90, 0xfffffff0 },
{ }
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7670aac0e93f..a8445c72fc13 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -47,11 +47,11 @@ void phy_print_status(struct phy_device *phydev)
pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
phydev->link ? "Up" : "Down");
if (phydev->link)
- printk(" - %d/%s", phydev->speed,
+ printk(KERN_CONT " - %d/%s", phydev->speed,
DUPLEX_FULL == phydev->duplex ?
"Full" : "Half");
- printk("\n");
+ printk(KERN_CONT "\n");
}
EXPORT_SYMBOL(phy_print_status);
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 78d70a6481bf..a1b82c9c67d2 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#include <asm/uaccess.h>
#include <asm/string.h>
@@ -542,7 +543,7 @@ ppp_async_encode(struct asyncppp *ap)
data = ap->tpkt->data;
count = ap->tpkt->len;
fcs = ap->tfcs;
- proto = (data[0] << 8) + data[1];
+ proto = get_unaligned_be16(data);
/*
* LCP packets with code values between 1 (configure-reqest)
@@ -963,7 +964,7 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
code = data[0];
if (code != CONFACK && code != CONFREQ)
return;
- dlen = (data[2] << 8) + data[3];
+ dlen = get_unaligned_be16(data + 2);
if (len < dlen)
return; /* packet got truncated or length is bogus */
@@ -997,15 +998,14 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) {
switch (data[0]) {
case LCP_MRU:
- val = (data[2] << 8) + data[3];
+ val = get_unaligned_be16(data + 2);
if (inbound)
ap->mru = val;
else
ap->chan.mtu = val;
break;
case LCP_ASYNCMAP:
- val = (data[2] << 24) + (data[3] << 16)
- + (data[4] << 8) + data[5];
+ val = get_unaligned_be32(data + 2);
if (inbound)
ap->raccm = val;
else
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 695bc83e0cfd..43583309a65d 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -41,6 +41,7 @@
#include <linux/ppp-comp.h>
#include <linux/zlib.h>
+#include <asm/unaligned.h>
/*
* State for a Deflate (de)compressor.
@@ -232,11 +233,9 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
*/
wptr[0] = PPP_ADDRESS(rptr);
wptr[1] = PPP_CONTROL(rptr);
- wptr[2] = PPP_COMP >> 8;
- wptr[3] = PPP_COMP;
+ put_unaligned_be16(PPP_COMP, wptr + 2);
wptr += PPP_HDRLEN;
- wptr[0] = state->seqno >> 8;
- wptr[1] = state->seqno;
+ put_unaligned_be16(state->seqno, wptr);
wptr += DEFLATE_OVHD;
olen = PPP_HDRLEN + DEFLATE_OVHD;
state->strm.next_out = wptr;
@@ -451,7 +450,7 @@ static int z_decompress(void *arg, unsigned char *ibuf, int isize,
}
/* Check the sequence number. */
- seq = (ibuf[PPP_HDRLEN] << 8) + ibuf[PPP_HDRLEN+1];
+ seq = get_unaligned_be16(ibuf + PPP_HDRLEN);
if (seq != (state->seqno & 0xffff)) {
if (state->debug)
printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 09cf56d0416a..c7a6c4466978 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -46,6 +46,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#include <net/slhc_vj.h>
#include <asm/atomic.h>
@@ -210,7 +211,7 @@ struct ppp_net {
};
/* Get the PPP protocol number from a skb */
-#define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1])
+#define PPP_PROTO(skb) get_unaligned_be16((skb)->data)
/* We limit the length of ppp->file.rq to this (arbitrary) value */
#define PPP_MAX_RQLEN 32
@@ -964,8 +965,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
pp = skb_push(skb, 2);
proto = npindex_to_proto[npi];
- pp[0] = proto >> 8;
- pp[1] = proto;
+ put_unaligned_be16(proto, pp);
netif_stop_queue(dev);
skb_queue_tail(&ppp->file.xq, skb);
@@ -1136,8 +1136,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
a four-byte PPP header on each packet */
*skb_push(skb, 2) = 1;
if (ppp->pass_filter &&
- sk_run_filter(skb, ppp->pass_filter,
- ppp->pass_len) == 0) {
+ sk_run_filter(skb, ppp->pass_filter) == 0) {
if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: outbound frame not passed\n");
kfree_skb(skb);
@@ -1145,8 +1144,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
}
/* if this packet passes the active filter, record the time */
if (!(ppp->active_filter &&
- sk_run_filter(skb, ppp->active_filter,
- ppp->active_len) == 0))
+ sk_run_filter(skb, ppp->active_filter) == 0))
ppp->last_xmit = jiffies;
skb_pull(skb, 2);
#else
@@ -1285,6 +1283,11 @@ ppp_push(struct ppp *ppp)
}
#ifdef CONFIG_PPP_MULTILINK
+static bool mp_protocol_compress __read_mostly = true;
+module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(mp_protocol_compress,
+ "compress protocol id in multilink fragments");
+
/*
* Divide a packet to be transmitted into fragments and
* send them out the individual links.
@@ -1347,10 +1350,10 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
if (nfree == 0 || nfree < navail / 2)
return 0; /* can't take now, leave it in xmit_pending */
- /* Do protocol field compression (XXX this should be optional) */
+ /* Do protocol field compression */
p = skb->data;
len = skb->len;
- if (*p == 0) {
+ if (*p == 0 && mp_protocol_compress) {
++p;
--len;
}
@@ -1470,8 +1473,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
q = skb_put(frag, flen + hdrlen);
/* make the MP header */
- q[0] = PPP_MP >> 8;
- q[1] = PPP_MP;
+ put_unaligned_be16(PPP_MP, q);
if (ppp->flags & SC_MP_XSHORTSEQ) {
q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
q[3] = ppp->nxseq;
@@ -1758,8 +1760,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
*skb_push(skb, 2) = 0;
if (ppp->pass_filter &&
- sk_run_filter(skb, ppp->pass_filter,
- ppp->pass_len) == 0) {
+ sk_run_filter(skb, ppp->pass_filter) == 0) {
if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: inbound frame "
"not passed\n");
@@ -1767,8 +1768,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
return;
}
if (!(ppp->active_filter &&
- sk_run_filter(skb, ppp->active_filter,
- ppp->active_len) == 0))
+ sk_run_filter(skb, ppp->active_filter) == 0))
ppp->last_recv = jiffies;
__skb_pull(skb, 2);
} else
@@ -2584,16 +2584,16 @@ ppp_create_interface(struct net *net, int unit, int *retp)
*/
dev_net_set(dev, net);
- ret = -EEXIST;
mutex_lock(&pn->all_ppp_mutex);
if (unit < 0) {
unit = unit_get(&pn->units_idr, ppp);
if (unit < 0) {
- *retp = unit;
+ ret = unit;
goto out2;
}
} else {
+ ret = -EEXIST;
if (unit_find(&pn->units_idr, unit))
goto out2; /* unit already exists */
/*
@@ -2668,10 +2668,10 @@ static void ppp_shutdown_interface(struct ppp *ppp)
ppp->closing = 1;
ppp_unlock(ppp);
unregister_netdev(ppp->dev);
+ unit_put(&pn->units_idr, ppp->file.index);
} else
ppp_unlock(ppp);
- unit_put(&pn->units_idr, ppp->file.index);
ppp->file.dead = 1;
ppp->owner = NULL;
wake_up_interruptible(&ppp->file.rwait);
@@ -2859,8 +2859,7 @@ static void __exit ppp_cleanup(void)
* by holding all_ppp_mutex
*/
-/* associate pointer with specified number */
-static int unit_set(struct idr *p, void *ptr, int n)
+static int __unit_alloc(struct idr *p, void *ptr, int n)
{
int unit, err;
@@ -2871,10 +2870,24 @@ again:
}
err = idr_get_new_above(p, ptr, n, &unit);
- if (err == -EAGAIN)
- goto again;
+ if (err < 0) {
+ if (err == -EAGAIN)
+ goto again;
+ return err;
+ }
- if (unit != n) {
+ return unit;
+}
+
+/* associate pointer with specified number */
+static int unit_set(struct idr *p, void *ptr, int n)
+{
+ int unit;
+
+ unit = __unit_alloc(p, ptr, n);
+ if (unit < 0)
+ return unit;
+ else if (unit != n) {
idr_remove(p, unit);
return -EINVAL;
}
@@ -2885,19 +2898,7 @@ again:
/* get new free unit number and associate pointer with it */
static int unit_get(struct idr *p, void *ptr)
{
- int unit, err;
-
-again:
- if (!idr_pre_get(p, GFP_KERNEL)) {
- printk(KERN_ERR "PPP: No free memory for idr\n");
- return -ENOMEM;
- }
-
- err = idr_get_new_above(p, ptr, 0, &unit);
- if (err == -EAGAIN)
- goto again;
-
- return unit;
+ return __unit_alloc(p, ptr, 0);
}
/* put unit number back to a pool */
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index 6d1a1b80cc3e..9a1849a83e2a 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -55,6 +55,7 @@
#include <linux/ppp_defs.h>
#include <linux/ppp-comp.h>
#include <linux/scatterlist.h>
+#include <asm/unaligned.h>
#include "ppp_mppe.h"
@@ -395,16 +396,14 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
*/
obuf[0] = PPP_ADDRESS(ibuf);
obuf[1] = PPP_CONTROL(ibuf);
- obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */
- obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */
+ put_unaligned_be16(PPP_COMP, obuf + 2);
obuf += PPP_HDRLEN;
state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
if (state->debug >= 7)
printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
state->ccount);
- obuf[0] = state->ccount >> 8;
- obuf[1] = state->ccount & 0xff;
+ put_unaligned_be16(state->ccount, obuf);
if (!state->stateful || /* stateless mode */
((state->ccount & 0xff) == 0xff) || /* "flag" packet */
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 4c95ec3fb8d4..4e6b72f57de8 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -45,6 +45,7 @@
#include <linux/completion.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#include <asm/uaccess.h>
#define PPP_VERSION "2.4.2"
@@ -563,7 +564,7 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
int islcp;
data = skb->data;
- proto = (data[0] << 8) + data[1];
+ proto = get_unaligned_be16(data);
/* LCP packets with codes between 1 (configure-request)
* and 7 (code-reject) must be sent as though no options
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index d72fb0519a2a..78c0e3c9b2b5 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -948,7 +948,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
abort:
kfree_skb(skb);
- return 0;
+ return 1;
}
/************************************************************************
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
index ccbc91326bfa..164cfad6ce79 100644
--- a/drivers/net/pptp.c
+++ b/drivers/net/pptp.c
@@ -277,7 +277,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
iph->tos = 0;
iph->daddr = rt->rt_dst;
iph->saddr = rt->rt_src;
- iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
+ iph->ttl = ip4_dst_hoplimit(&rt->dst);
iph->tot_len = htons(skb->len);
skb_dst_drop(skb);
@@ -673,8 +673,7 @@ static int __init pptp_init_module(void)
int err = 0;
pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n");
- callid_sock = __vmalloc((MAX_CALLID + 1) * sizeof(void *),
- GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ callid_sock = vzalloc((MAX_CALLID + 1) * sizeof(void *));
if (!callid_sock) {
pr_err("PPTP: cann't allocate memory\n");
return -ENOMEM;
diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c
index 18c0297743f1..1b63c8aef121 100644
--- a/drivers/net/pxa168_eth.c
+++ b/drivers/net/pxa168_eth.c
@@ -1450,16 +1450,11 @@ static void pxa168_get_drvinfo(struct net_device *dev,
strncpy(info->bus_info, "N/A", 32);
}
-static u32 pxa168_get_link(struct net_device *dev)
-{
- return !!netif_carrier_ok(dev);
-}
-
static const struct ethtool_ops pxa168_ethtool_ops = {
.get_settings = pxa168_get_settings,
.set_settings = pxa168_set_settings,
.get_drvinfo = pxa168_get_drvinfo,
- .get_link = pxa168_get_link,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops pxa168_eth_netdev_ops = {
@@ -1607,7 +1602,7 @@ static int pxa168_eth_remove(struct platform_device *pdev)
mdiobus_unregister(pep->smi_bus);
mdiobus_free(pep->smi_bus);
unregister_netdev(dev);
- flush_scheduled_work();
+ cancel_work_sync(&pep->tx_timeout_task);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 7496ed2c34ab..1a3584edd79c 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -2467,7 +2467,7 @@ map_error:
static netdev_tx_t ql3xxx_send(struct sk_buff *skb,
struct net_device *ndev)
{
- struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
struct ql_tx_buf_cb *tx_cb;
@@ -3390,7 +3390,7 @@ static void ql_set_mac_info(struct ql3_adapter *qdev)
static void ql_display_dev_info(struct net_device *ndev)
{
- struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
struct pci_dev *pdev = qdev->pdev;
netdev_info(ndev,
@@ -3573,7 +3573,7 @@ static int ql3xxx_open(struct net_device *ndev)
static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
{
- struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
struct sockaddr *addr = p;
@@ -3608,7 +3608,7 @@ static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
static void ql3xxx_tx_timeout(struct net_device *ndev)
{
- struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
netdev_err(ndev, "Resetting...\n");
/*
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 8ecc170c9b74..44e316fd67b8 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#ifndef _QLCNIC_H_
@@ -51,8 +34,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 11
-#define QLCNIC_LINUX_VERSIONID "5.0.11"
+#define _QLCNIC_LINUX_SUBVERSION 15
+#define QLCNIC_LINUX_VERSIONID "5.0.15"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -306,6 +289,26 @@ struct uni_data_desc{
u32 reserved[5];
};
+/* Flash Defines and Structures */
+#define QLCNIC_FLT_LOCATION 0x3F1000
+#define QLCNIC_FW_IMAGE_REGION 0x74
+struct qlcnic_flt_header {
+ u16 version;
+ u16 len;
+ u16 checksum;
+ u16 reserved;
+};
+
+struct qlcnic_flt_entry {
+ u8 region;
+ u8 reserved0;
+ u8 attrib;
+ u8 reserved1;
+ u32 size;
+ u32 start_addr;
+ u32 end_add;
+};
+
/* Magic number to let user know flash is programmed */
#define QLCNIC_BDINFO_MAGIC 0x12345678
@@ -798,7 +801,6 @@ struct qlcnic_nic_intr_coalesce {
#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16
#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17
#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18
-#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK 19
#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20
#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21
#define QLCNIC_C2C_OPCODE 22
@@ -923,6 +925,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_MACSPOOF 0x200
#define QLCNIC_MAC_OVERRIDE_DISABLED 0x400
#define QLCNIC_PROMISC_DISABLED 0x800
+#define QLCNIC_NEED_FLR 0x1000
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
@@ -942,6 +945,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
+#define QLCNIC_LED_TEST 3
#define QLCNIC_FILTER_AGE 80
#define QLCNIC_READD_AGE 20
@@ -1126,8 +1130,7 @@ struct qlcnic_eswitch {
/* Return codes for Error handling */
#define QL_STATUS_INVALID_PARAM -1
-#define MAX_BW 100
-#define MIN_BW 1
+#define MAX_BW 100 /* % of link speed */
#define MAX_VLAN_ID 4095
#define MIN_VLAN_ID 2
#define MAX_TX_QUEUES 1
@@ -1135,7 +1138,7 @@ struct qlcnic_eswitch {
#define DEFAULT_MAC_LEARN 1
#define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan < MAX_VLAN_ID)
-#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW)
+#define IS_VALID_BW(bw) (bw <= MAX_BW)
#define IS_VALID_TX_QUEUES(que) (que > 0 && que <= MAX_TX_QUEUES)
#define IS_VALID_RX_QUEUES(que) (que > 0 && que <= MAX_RX_QUEUES)
@@ -1314,21 +1317,15 @@ int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
-void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
-int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
/* Functions from qlcnic_main.c */
-int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter);
-void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter);
int qlcnic_reset_context(struct qlcnic_adapter *);
u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
-int qlcnic_check_loopback_buff(unsigned char *data);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
/* Management functions */
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
@@ -1377,6 +1374,8 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = {
"3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
{0x1077, 0x8020, 0x103c, 0x3733,
"NC523SFP 10Gb 2-port Server Adapter"},
+ {0x1077, 0x8020, 0x103c, 0x3346,
+ "CN1000Q Dual Port Converged Network Adapter"},
{0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
};
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 1cdc05dade6b..27631f23b3fd 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#include "qlcnic.h"
@@ -480,6 +463,11 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
{
int err;
+ if (adapter->flags & QLCNIC_NEED_FLR) {
+ pci_reset_function(adapter->pdev);
+ adapter->flags &= ~QLCNIC_NEED_FLR;
+ }
+
err = qlcnic_fw_cmd_create_rx_ctx(adapter);
if (err)
return err;
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index ec21d24015c4..4c14510e2a87 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#include <linux/types.h>
@@ -101,8 +84,7 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline",
- "Interrupt_Test_offline",
- "Loopback_Test_offline"
+ "Interrupt_Test_offline"
};
#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
@@ -643,104 +625,6 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
}
}
-#define QLC_ILB_PKT_SIZE 64
-#define QLC_NUM_ILB_PKT 16
-#define QLC_ILB_MAX_RCV_LOOP 10
-
-static void qlcnic_create_loopback_buff(unsigned char *data)
-{
- unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
- memset(data, 0x4e, QLC_ILB_PKT_SIZE);
- memset(data, 0xff, 12);
- memcpy(data + 12, random_data, sizeof(random_data));
-}
-
-int qlcnic_check_loopback_buff(unsigned char *data)
-{
- unsigned char buff[QLC_ILB_PKT_SIZE];
- qlcnic_create_loopback_buff(buff);
- return memcmp(data, buff, QLC_ILB_PKT_SIZE);
-}
-
-static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
-{
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
- struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
- struct sk_buff *skb;
- int i, loop, cnt = 0;
-
- for (i = 0; i < QLC_NUM_ILB_PKT; i++) {
- skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
- qlcnic_create_loopback_buff(skb->data);
- skb_put(skb, QLC_ILB_PKT_SIZE);
-
- adapter->diag_cnt = 0;
- qlcnic_xmit_frame(skb, adapter->netdev);
-
- loop = 0;
- do {
- msleep(1);
- qlcnic_process_rcv_ring_diag(sds_ring);
- } while (loop++ < QLC_ILB_MAX_RCV_LOOP &&
- !adapter->diag_cnt);
-
- dev_kfree_skb_any(skb);
-
- if (!adapter->diag_cnt)
- dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
- " not recevied\n", i + 1);
- else
- cnt++;
- }
- if (cnt != i) {
- dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
- return -1;
- }
- return 0;
-}
-
-static int qlcnic_loopback_test(struct net_device *netdev)
-{
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
- int max_sds_rings = adapter->max_sds_rings;
- int ret;
-
- if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(&adapter->pdev->dev, "Loopback test not supported"
- "for non privilege function\n");
- return 0;
- }
-
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- return -EIO;
-
- if (qlcnic_request_quiscent_mode(adapter)) {
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
- return -EIO;
- }
-
- ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
- if (ret)
- goto clear_it;
-
- ret = qlcnic_set_ilb_mode(adapter);
- if (ret)
- goto done;
-
- ret = qlcnic_do_ilb_test(adapter);
-
- qlcnic_clear_ilb_mode(adapter);
-
-done:
- qlcnic_diag_free_res(netdev, max_sds_rings);
-
-clear_it:
- qlcnic_clear_quiscent_mode(adapter);
- adapter->max_sds_rings = max_sds_rings;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
- return ret;
-}
-
static int qlcnic_irq_test(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -788,14 +672,11 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
if (data[1])
eth_test->flags |= ETH_TEST_FL_FAILED;
- if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ if (eth_test->flags & ETH_TEST_FL_OFFLINE) {
data[2] = qlcnic_irq_test(dev);
if (data[2])
eth_test->flags |= ETH_TEST_FL_FAILED;
- data[3] = qlcnic_loopback_test(dev);
- if (data[3])
- eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
@@ -925,9 +806,10 @@ static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
dev->features &= ~NETIF_F_LRO;
qlcnic_send_lro_cleanup(adapter);
+ dev_info(&adapter->pdev->dev,
+ "disabling LRO as rx_csum is off\n");
}
adapter->rx_csum = !!data;
- dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");
return 0;
}
@@ -952,16 +834,27 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data)
static int qlcnic_blink_led(struct net_device *dev, u32 val)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int max_sds_rings = adapter->max_sds_rings;
+ int dev_down = 0;
int ret;
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
- return -EIO;
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ dev_down = 1;
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+
+ ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST);
+ if (ret) {
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+ }
+ }
ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to set LED blink state.\n");
- return ret;
+ goto done;
}
msleep_interruptible(val * 1000);
@@ -970,10 +863,16 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to reset LED blink state.\n");
- return ret;
+ goto done;
}
- return 0;
+done:
+ if (dev_down) {
+ qlcnic_diag_free_res(dev, max_sds_rings);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ }
+ return ret;
+
}
static void
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index 4290b80cde1a..726ef555b6bc 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#ifndef __QLCNIC_HDR_H_
@@ -638,7 +621,7 @@ enum {
#define PCIX_INT_MASK (0x10104)
#define PCIX_OCM_WINDOW (0x10800)
-#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x20 * (func))
+#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x4 * (func))
#define PCIX_TARGET_STATUS (0x10118)
#define PCIX_TARGET_STATUS_F1 (0x10160)
@@ -722,7 +705,7 @@ enum {
#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
-#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) &= (1 << (FN * 4)))
+#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) & (1 << (FN * 4)))
#define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_CLR_REF_CNT(VAL, FN) ((VAL) &= ~(1 << (FN * 4)))
#define QLC_DEV_SET_RST_RDY(VAL, FN) ((VAL) |= (1 << (FN * 4)))
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 7a47a2a7ee27..616940f0a8d0 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#include "qlcnic.h"
@@ -398,7 +381,7 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
}
-static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
+static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
{
struct list_head *head;
struct qlcnic_mac_list_s *cur;
@@ -432,7 +415,9 @@ void qlcnic_set_multi(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
- u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ static const u8 bcast_addr[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
u32 mode = VPORT_MISS_MODE_DROP;
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
@@ -638,10 +623,11 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
u64 word;
int i, rv;
- const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
- 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
- 0x255b0ec26d5a56daULL };
-
+ static const u64 key[] = {
+ 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+ 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+ 0x255b0ec26d5a56daULL
+ };
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
@@ -1234,56 +1220,3 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
-
-static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
-{
- struct qlcnic_nic_req req;
- int rv;
- u64 word;
-
- memset(&req, 0, sizeof(struct qlcnic_nic_req));
- req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
-
- word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
- ((u64)adapter->portnum << 16);
- req.req_hdr = cpu_to_le64(word);
- req.words[0] = cpu_to_le64(flag);
-
- rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
- if (rv)
- dev_err(&adapter->pdev->dev,
- "%sting loopback mode failed.\n",
- flag ? "Set" : "Reset");
- return rv;
-}
-
-int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
-{
- if (qlcnic_set_fw_loopback(adapter, 1))
- return -EIO;
-
- if (qlcnic_nic_set_promisc(adapter,
- VPORT_MISS_MODE_ACCEPT_ALL)) {
- qlcnic_set_fw_loopback(adapter, 0);
- return -EIO;
- }
-
- msleep(1000);
- return 0;
-}
-
-void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
-{
- int mode = VPORT_MISS_MODE_DROP;
- struct net_device *netdev = adapter->netdev;
-
- qlcnic_set_fw_loopback(adapter, 0);
-
- if (netdev->flags & IFF_PROMISC)
- mode = VPORT_MISS_MODE_ACCEPT_ALL;
- else if (netdev->flags & IFF_ALLMULTI)
- mode = VPORT_MISS_MODE_ACCEPT_MULTI;
-
- qlcnic_nic_set_promisc(adapter, mode);
- msleep(1000);
-}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 0d180c6e41fe..a7f1d5b7e811 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#include <linux/netdevice.h>
@@ -236,12 +219,11 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
tx_ring->num_desc = adapter->num_txd;
tx_ring->txq = netdev_get_tx_queue(netdev, 0);
- cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
+ cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
if (cmd_buf_arr == NULL) {
dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
goto err_out;
}
- memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
tx_ring->cmd_buf_arr = cmd_buf_arr;
recv_ctx = &adapter->recv_ctx;
@@ -275,14 +257,12 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
rds_ring->dma_size + NET_IP_ALIGN;
break;
}
- rds_ring->rx_buf_arr = (struct qlcnic_rx_buffer *)
- vmalloc(RCV_BUFF_RINGSIZE(rds_ring));
+ rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
if (rds_ring->rx_buf_arr == NULL) {
dev_err(&netdev->dev, "Failed to allocate "
"rx buffer ring %d\n", ring);
goto err_out;
}
- memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
INIT_LIST_HEAD(&rds_ring->free_list);
/*
* Now go through all of them, set reference handles
@@ -647,12 +627,73 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
return 0;
}
+static int qlcnic_get_flt_entry(struct qlcnic_adapter *adapter, u8 region,
+ struct qlcnic_flt_entry *region_entry)
+{
+ struct qlcnic_flt_header flt_hdr;
+ struct qlcnic_flt_entry *flt_entry;
+ int i = 0, ret;
+ u32 entry_size;
+
+ memset(region_entry, 0, sizeof(struct qlcnic_flt_entry));
+ ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION,
+ (u8 *)&flt_hdr,
+ sizeof(struct qlcnic_flt_header));
+ if (ret) {
+ dev_warn(&adapter->pdev->dev,
+ "error reading flash layout header\n");
+ return -EIO;
+ }
+
+ entry_size = flt_hdr.len - sizeof(struct qlcnic_flt_header);
+ flt_entry = (struct qlcnic_flt_entry *)vzalloc(entry_size);
+ if (flt_entry == NULL) {
+ dev_warn(&adapter->pdev->dev, "error allocating memory\n");
+ return -EIO;
+ }
+
+ ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION +
+ sizeof(struct qlcnic_flt_header),
+ (u8 *)flt_entry, entry_size);
+ if (ret) {
+ dev_warn(&adapter->pdev->dev,
+ "error reading flash layout entries\n");
+ goto err_out;
+ }
+
+ while (i < (entry_size/sizeof(struct qlcnic_flt_entry))) {
+ if (flt_entry[i].region == region)
+ break;
+ i++;
+ }
+ if (i >= (entry_size/sizeof(struct qlcnic_flt_entry))) {
+ dev_warn(&adapter->pdev->dev,
+ "region=%x not found in %d regions\n", region, i);
+ ret = -EIO;
+ goto err_out;
+ }
+ memcpy(region_entry, &flt_entry[i], sizeof(struct qlcnic_flt_entry));
+
+err_out:
+ vfree(flt_entry);
+ return ret;
+}
+
int
qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
{
+ struct qlcnic_flt_entry fw_entry;
u32 ver = -1, min_ver;
+ int ret;
- qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET, (int *)&ver);
+ ret = qlcnic_get_flt_entry(adapter, QLCNIC_FW_IMAGE_REGION, &fw_entry);
+ if (!ret)
+ /* 0-4:-signature, 4-8:-fw version */
+ qlcnic_rom_fast_read(adapter, fw_entry.start_addr + 4,
+ (int *)&ver);
+ else
+ qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET,
+ (int *)&ver);
ver = QLCNIC_DECODE_VERSION(ver);
min_ver = QLCNIC_MIN_FW_VERSION;
@@ -1693,99 +1734,6 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
spin_unlock(&rds_ring->lock);
}
-static void dump_skb(struct sk_buff *skb)
-{
- int i;
- unsigned char *data = skb->data;
-
- for (i = 0; i < skb->len; i++) {
- printk("%02x ", data[i]);
- if ((i & 0x0f) == 8)
- printk("\n");
- }
-}
-
-static struct qlcnic_rx_buffer *
-qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
- struct qlcnic_host_sds_ring *sds_ring,
- int ring, u64 sts_data0)
-{
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
- struct qlcnic_rx_buffer *buffer;
- struct sk_buff *skb;
- struct qlcnic_host_rds_ring *rds_ring;
- int index, length, cksum, pkt_offset;
-
- if (unlikely(ring >= adapter->max_rds_rings))
- return NULL;
-
- rds_ring = &recv_ctx->rds_rings[ring];
-
- index = qlcnic_get_sts_refhandle(sts_data0);
- if (unlikely(index >= rds_ring->num_desc))
- return NULL;
-
- buffer = &rds_ring->rx_buf_arr[index];
-
- length = qlcnic_get_sts_totallength(sts_data0);
- cksum = qlcnic_get_sts_status(sts_data0);
- pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
-
- skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
- if (!skb)
- return buffer;
-
- if (length > rds_ring->skb_size)
- skb_put(skb, rds_ring->skb_size);
- else
- skb_put(skb, length);
-
- if (pkt_offset)
- skb_pull(skb, pkt_offset);
-
- if (!qlcnic_check_loopback_buff(skb->data))
- adapter->diag_cnt++;
- else
- dump_skb(skb);
-
- dev_kfree_skb_any(skb);
- adapter->stats.rx_pkts++;
- adapter->stats.rxbytes += length;
-
- return buffer;
-}
-
-void
-qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
-{
- struct qlcnic_adapter *adapter = sds_ring->adapter;
- struct status_desc *desc;
- struct qlcnic_rx_buffer *rxbuf;
- u64 sts_data0;
-
- int opcode, ring, desc_cnt;
- u32 consumer = sds_ring->consumer;
-
- desc = &sds_ring->desc_head[consumer];
- sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
-
- if (!(sts_data0 & STATUS_OWNER_HOST))
- return;
-
- desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
- opcode = qlcnic_get_sts_opcode(sts_data0);
-
- ring = qlcnic_get_sts_type(sts_data0);
- rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring,
- ring, sts_data0);
-
- desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
- consumer = get_next_index(consumer, sds_ring->num_desc);
-
- sds_ring->consumer = consumer;
- writel(consumer, sds_ring->crb_sts_consumer);
-}
-
void
qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
u8 alt_mac, u8 *mac)
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 7a298cdf9ab3..37c04b4fade3 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2009 - QLogic Corporation.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called "COPYING".
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2010 QLogic Corporation
*
+ * See LICENSE.qlcnic for copyright and licensing details.
*/
#include <linux/slab.h>
@@ -48,15 +31,15 @@ static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
static struct workqueue_struct *qlcnic_wq;
static int qlcnic_mac_learn;
-module_param(qlcnic_mac_learn, int, 0644);
+module_param(qlcnic_mac_learn, int, 0444);
MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
static int use_msi = 1;
-module_param(use_msi, int, 0644);
+module_param(use_msi, int, 0444);
MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
static int use_msi_x = 1;
-module_param(use_msi_x, int, 0644);
+module_param(use_msi_x, int, 0444);
MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
@@ -64,11 +47,11 @@ module_param(auto_fw_reset, int, 0644);
MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
static int load_fw_file;
-module_param(load_fw_file, int, 0644);
+module_param(load_fw_file, int, 0444);
MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
static int qlcnic_config_npars;
-module_param(qlcnic_config_npars, int, 0644);
+module_param(qlcnic_config_npars, int, 0444);
MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
static int __devinit qlcnic_probe(struct pci_dev *pdev,
@@ -1450,7 +1433,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
netdev->irq = adapter->msix_entries[0].vector;
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
err = register_netdev(netdev);
if (err) {
@@ -1547,6 +1529,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_iounmap;
+ adapter->flags |= QLCNIC_NEED_FLR;
+
err = adapter->nic_ops->start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
@@ -2855,61 +2839,6 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
qlcnic_api_unlock(adapter);
}
-/* Caller should held RESETTING bit.
- * This should be call in sync with qlcnic_request_quiscent_mode.
- */
-void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter)
-{
- qlcnic_clr_drv_state(adapter);
- qlcnic_api_lock(adapter);
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
- qlcnic_api_unlock(adapter);
-}
-
-/* Caller should held RESETTING bit.
- */
-int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter)
-{
- u8 timeo = adapter->dev_init_timeo / 2;
- u32 state;
-
- if (qlcnic_api_lock(adapter))
- return -EIO;
-
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (state != QLCNIC_DEV_READY)
- return -EIO;
-
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_QUISCENT);
- qlcnic_api_unlock(adapter);
- QLCDB(adapter, DRV, "NEED QUISCENT state set\n");
- qlcnic_idc_debug_info(adapter, 0);
-
- qlcnic_set_drv_state(adapter, QLCNIC_DEV_NEED_QUISCENT);
-
- do {
- msleep(2000);
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (state == QLCNIC_DEV_QUISCENT)
- return 0;
- if (!qlcnic_check_drv_state(adapter)) {
- if (qlcnic_api_lock(adapter))
- return -EIO;
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
- QLCNIC_DEV_QUISCENT);
- qlcnic_api_unlock(adapter);
- QLCDB(adapter, DRV, "QUISCENT mode set\n");
- return 0;
- }
- } while (--timeo);
-
- dev_err(&adapter->pdev->dev, "Failed to quiesce device, DRV_STATE=%08x"
- " DRV_ACTIVE=%08x\n", QLCRD32(adapter, QLCNIC_CRB_DRV_STATE),
- QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE));
- qlcnic_clear_quiscent_mode(adapter);
- return -EIO;
-}
-
/*Transit to RESET state from READY state only */
static void
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
@@ -3588,9 +3517,12 @@ validate_esw_config(struct qlcnic_adapter *adapter,
case QLCNIC_PORT_DEFAULTS:
if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
QLCNIC_NON_PRIV_FUNC) {
- esw_cfg[i].mac_anti_spoof = 0;
- esw_cfg[i].mac_override = 1;
- esw_cfg[i].promisc_mode = 1;
+ if (esw_cfg[i].mac_anti_spoof != 0)
+ return QL_STATUS_INVALID_PARAM;
+ if (esw_cfg[i].mac_override != 1)
+ return QL_STATUS_INVALID_PARAM;
+ if (esw_cfg[i].promisc_mode != 1)
+ return QL_STATUS_INVALID_PARAM;
}
break;
case QLCNIC_ADD_VLAN:
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 22821398fc63..4757c59a07a2 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -16,7 +16,7 @@
*/
#define DRV_NAME "qlge"
#define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION "v1.00.00.25.00.00-01"
+#define DRV_VERSION "v1.00.00.27.00.00-01"
#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */
@@ -2083,6 +2083,7 @@ struct ql_adapter {
u32 mailbox_in;
u32 mailbox_out;
struct mbox_params idc_mbc;
+ struct mutex mpi_mutex;
int tx_ring_size;
int rx_ring_size;
@@ -2221,6 +2222,7 @@ int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
int ql_unpause_mpi_risc(struct ql_adapter *qdev);
int ql_pause_mpi_risc(struct ql_adapter *qdev);
int ql_hard_reset_mpi_risc(struct ql_adapter *qdev);
+int ql_soft_reset_mpi_risc(struct ql_adapter *qdev);
int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
u32 ram_addr, int word_count);
int ql_core_dump(struct ql_adapter *qdev,
@@ -2236,6 +2238,7 @@ int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control);
int ql_mb_get_port_cfg(struct ql_adapter *qdev);
int ql_mb_set_port_cfg(struct ql_adapter *qdev);
int ql_wait_fifo_empty(struct ql_adapter *qdev);
+void ql_get_dump(struct ql_adapter *qdev, void *buff);
void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump);
netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 4747492935ef..fca804f36d61 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1317,9 +1317,28 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
if (status)
return;
+}
+
+void ql_get_dump(struct ql_adapter *qdev, void *buff)
+{
+ /*
+ * If the dump has already been taken and is stored
+ * in our internal buffer and if force dump is set then
+ * just start the spool to dump it to the log file
+ * and also, take a snapshot of the general regs to
+ * to the user's buffer or else take complete dump
+ * to the user's buffer if force is not set.
+ */
- if (test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ if (!test_bit(QL_FRC_COREDUMP, &qdev->flags)) {
+ if (!ql_core_dump(qdev, buff))
+ ql_soft_reset_mpi_risc(qdev);
+ else
+ netif_err(qdev, drv, qdev->ndev, "coredump failed!\n");
+ } else {
+ ql_gen_reg_dump(qdev, buff);
ql_get_core_dump(qdev);
+ }
}
/* Coredump to messages log file using separate worker thread */
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 4892d64f4e05..8149cc9de4ca 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -375,7 +375,10 @@ static void ql_get_drvinfo(struct net_device *ndev,
strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
drvinfo->n_stats = 0;
drvinfo->testinfo_len = 0;
- drvinfo->regdump_len = 0;
+ if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ drvinfo->regdump_len = sizeof(struct ql_mpi_coredump);
+ else
+ drvinfo->regdump_len = sizeof(struct ql_reg_dump);
drvinfo->eedump_len = 0;
}
@@ -547,7 +550,12 @@ static void ql_self_test(struct net_device *ndev,
static int ql_get_regs_len(struct net_device *ndev)
{
- return sizeof(struct ql_reg_dump);
+ struct ql_adapter *qdev = netdev_priv(ndev);
+
+ if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ return sizeof(struct ql_mpi_coredump);
+ else
+ return sizeof(struct ql_reg_dump);
}
static void ql_get_regs(struct net_device *ndev,
@@ -555,7 +563,12 @@ static void ql_get_regs(struct net_device *ndev,
{
struct ql_adapter *qdev = netdev_priv(ndev);
- ql_gen_reg_dump(qdev, p);
+ ql_get_dump(qdev, p);
+ qdev->core_is_dumped = 0;
+ if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ regs->len = sizeof(struct ql_mpi_coredump);
+ else
+ regs->len = sizeof(struct ql_reg_dump);
}
static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index c30e0fe55a31..49bfa5813068 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -62,15 +62,15 @@ static const u32 default_msg =
/* NETIF_MSG_PKTDATA | */
NETIF_MSG_HW | NETIF_MSG_WOL | 0;
-static int debug = 0x00007fff; /* defaults above */
-module_param(debug, int, 0);
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0664);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
#define MSIX_IRQ 0
#define MSI_IRQ 1
#define LEG_IRQ 2
static int qlge_irq_type = MSIX_IRQ;
-module_param(qlge_irq_type, int, MSIX_IRQ);
+module_param(qlge_irq_type, int, 0664);
MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
static int qlge_mpi_coredump;
@@ -3548,12 +3548,13 @@ err_irq:
static int ql_start_rss(struct ql_adapter *qdev)
{
- u8 init_hash_seed[] = {0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
- 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f,
- 0xb0, 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b,
- 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80,
- 0x30, 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b,
- 0xbe, 0xac, 0x01, 0xfa};
+ static const u8 init_hash_seed[] = {
+ 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+ 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+ 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+ 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+ 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
+ };
struct ricb *ricb = &qdev->ricb;
int status = 0;
int i;
@@ -3844,7 +3845,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
static void ql_display_dev_info(struct net_device *ndev)
{
- struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
netif_info(qdev, probe, qdev->ndev,
"Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, "
@@ -4264,7 +4265,7 @@ static struct net_device_stats *qlge_get_stats(struct net_device
static void qlge_set_multicast_list(struct net_device *ndev)
{
- struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
struct netdev_hw_addr *ha;
int i, status;
@@ -4354,7 +4355,7 @@ exit:
static int qlge_set_mac_address(struct net_device *ndev, void *p)
{
- struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
struct sockaddr *addr = p;
int status;
@@ -4377,7 +4378,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
static void qlge_tx_timeout(struct net_device *ndev)
{
- struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
ql_queue_asic_error(qdev);
}
@@ -4629,6 +4630,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
init_completion(&qdev->ide_completion);
+ mutex_init(&qdev->mpi_mutex);
if (!cards_found) {
dev_info(&pdev->dev, "%s\n", DRV_STRING);
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 0e7c7c7ee164..ff2bf8a4e247 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -87,7 +87,7 @@ exit:
return status;
}
-static int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
+int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
{
int status;
status = ql_write_mpi_reg(qdev, 0x00001010, 1);
@@ -534,6 +534,7 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
int status;
unsigned long count;
+ mutex_lock(&qdev->mpi_mutex);
/* Begin polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
@@ -603,6 +604,7 @@ done:
end:
/* End polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
+ mutex_unlock(&qdev->mpi_mutex);
return status;
}
@@ -1099,9 +1101,7 @@ int ql_wait_fifo_empty(struct ql_adapter *qdev)
static int ql_set_port_cfg(struct ql_adapter *qdev)
{
int status;
- rtnl_lock();
status = ql_mb_set_port_cfg(qdev);
- rtnl_unlock();
if (status)
return status;
status = ql_idc_wait(qdev);
@@ -1122,9 +1122,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
int status;
- rtnl_lock();
status = ql_mb_get_port_cfg(qdev);
- rtnl_unlock();
if (status) {
netif_err(qdev, drv, qdev->ndev,
"Bug: Failed to get port config data.\n");
@@ -1167,7 +1165,6 @@ void ql_mpi_idc_work(struct work_struct *work)
u32 aen;
int timeout;
- rtnl_lock();
aen = mbcp->mbox_out[1] >> 16;
timeout = (mbcp->mbox_out[1] >> 8) & 0xf;
@@ -1231,7 +1228,6 @@ void ql_mpi_idc_work(struct work_struct *work)
}
break;
}
- rtnl_unlock();
}
void ql_mpi_work(struct work_struct *work)
@@ -1242,7 +1238,7 @@ void ql_mpi_work(struct work_struct *work)
struct mbox_params *mbcp = &mbc;
int err = 0;
- rtnl_lock();
+ mutex_lock(&qdev->mpi_mutex);
/* Begin polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
@@ -1259,7 +1255,7 @@ void ql_mpi_work(struct work_struct *work)
/* End polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
- rtnl_unlock();
+ mutex_unlock(&qdev->mpi_mutex);
ql_enable_completion_interrupt(qdev, 0);
}
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 0b014c894686..27e6f6d43cac 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -1153,6 +1153,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
lp->mii_bus = mdiobus_alloc();
if (!lp->mii_bus) {
dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
+ err = -ENOMEM;
goto err_out_unmap;
}
@@ -1165,6 +1166,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
if (!lp->mii_bus->irq) {
dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
+ err = -ENOMEM;
goto err_out_mdio;
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index d88ce9fb1cbd..bde7d61f1930 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
+#include <linux/firmware.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -33,6 +34,9 @@
#define MODULENAME "r8169"
#define PFX MODULENAME ": "
+#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
+#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
+
#ifdef RTL8169_DEBUG
#define assert(expr) \
if (!(expr)) { \
@@ -63,7 +67,6 @@ static const int multicast_filter_limit = 32;
#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
@@ -118,7 +121,8 @@ enum mac_version {
RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D
- RTL_GIGA_MAC_VER_27 = 0x1b // 8168DP
+ RTL_GIGA_MAC_VER_27 = 0x1b, // 8168DP
+ RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP
};
#define _R(NAME,MAC,MASK) \
@@ -155,7 +159,8 @@ static const struct {
_R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
_R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E
_R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E
- _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880) // PCI-E
+ _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E
+ _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880) // PCI-E
};
#undef _R
@@ -227,7 +232,14 @@ enum rtl_registers {
IntrMitigate = 0xe2,
RxDescAddrLow = 0xe4,
RxDescAddrHigh = 0xe8,
- EarlyTxThres = 0xec,
+ EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
+
+#define NoEarlyTx 0x3f /* Max value : no early transmit. */
+
+ MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
+
+#define TxPacketMax (8064 >> 7)
+
FuncEvent = 0xf0,
FuncEventMask = 0xf4,
FuncPresetState = 0xf8,
@@ -248,7 +260,7 @@ enum rtl8168_8101_registers {
#define CSIAR_BYTE_ENABLE 0x0f
#define CSIAR_BYTE_ENABLE_SHIFT 12
#define CSIAR_ADDR_MASK 0x0fff
-
+ PMCH = 0x6f,
EPHYAR = 0x80,
#define EPHYAR_FLAG 0x80000000
#define EPHYAR_WRITE_CMD 0x80000000
@@ -267,6 +279,33 @@ enum rtl8168_8101_registers {
#define EFUSEAR_DATA_MASK 0xff
};
+enum rtl8168_registers {
+ ERIDR = 0x70,
+ ERIAR = 0x74,
+#define ERIAR_FLAG 0x80000000
+#define ERIAR_WRITE_CMD 0x80000000
+#define ERIAR_READ_CMD 0x00000000
+#define ERIAR_ADDR_BYTE_ALIGN 4
+#define ERIAR_EXGMAC 0
+#define ERIAR_MSIX 1
+#define ERIAR_ASF 2
+#define ERIAR_TYPE_SHIFT 16
+#define ERIAR_BYTEEN 0x0f
+#define ERIAR_BYTEEN_SHIFT 12
+ EPHY_RXER_NUM = 0x7c,
+ OCPDR = 0xb0, /* OCP GPHY access */
+#define OCPDR_WRITE_CMD 0x80000000
+#define OCPDR_READ_CMD 0x00000000
+#define OCPDR_REG_MASK 0x7f
+#define OCPDR_GPHY_REG_SHIFT 16
+#define OCPDR_DATA_MASK 0xffff
+ OCPAR = 0xb4,
+#define OCPAR_FLAG 0x80000000
+#define OCPAR_GPHY_WRITE_CMD 0x8000f060
+#define OCPAR_GPHY_READ_CMD 0x0000f060
+ RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */
+};
+
enum rtl_register_content {
/* InterruptStatusBits */
SYSErr = 0x8000,
@@ -490,11 +529,22 @@ struct rtl8169_private {
#ifdef CONFIG_R8169_VLAN
struct vlan_group *vlgrp;
#endif
+
+ struct mdio_ops {
+ void (*write)(void __iomem *, int, int);
+ int (*read)(void __iomem *, int);
+ } mdio_ops;
+
+ struct pll_power_ops {
+ void (*down)(struct rtl8169_private *);
+ void (*up)(struct rtl8169_private *);
+ } pll_power_ops;
+
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
- void (*phy_reset_enable)(void __iomem *);
+ void (*phy_reset_enable)(struct rtl8169_private *tp);
void (*hw_start)(struct net_device *);
- unsigned int (*phy_reset_pending)(void __iomem *);
+ unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
unsigned int (*link_ok)(void __iomem *);
int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
int pcie_cap;
@@ -504,6 +554,8 @@ struct rtl8169_private {
struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
+
+ const struct firmware *fw;
};
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -514,6 +566,8 @@ module_param_named(debug, debug.msg_enable, int, 0);
MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
MODULE_LICENSE("GPL");
MODULE_VERSION(RTL8169_VERSION);
+MODULE_FIRMWARE(FIRMWARE_8168D_1);
+MODULE_FIRMWARE(FIRMWARE_8168D_2);
static int rtl8169_open(struct net_device *dev);
static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -535,7 +589,82 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
-static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
+ for (i = 0; i < 20; i++) {
+ udelay(100);
+ if (RTL_R32(OCPAR) & OCPAR_FLAG)
+ break;
+ }
+ return RTL_R32(OCPDR);
+}
+
+static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ RTL_W32(OCPDR, data);
+ RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
+ for (i = 0; i < 20; i++) {
+ udelay(100);
+ if ((RTL_R32(OCPAR) & OCPAR_FLAG) == 0)
+ break;
+ }
+}
+
+static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
+{
+ int i;
+
+ RTL_W8(ERIDR, cmd);
+ RTL_W32(ERIAR, 0x800010e8);
+ msleep(2);
+ for (i = 0; i < 5; i++) {
+ udelay(100);
+ if (!(RTL_R32(ERIDR) & ERIAR_FLAG))
+ break;
+ }
+
+ ocp_write(ioaddr, 0x1, 0x30, 0x00000001);
+}
+
+#define OOB_CMD_RESET 0x00
+#define OOB_CMD_DRIVER_START 0x05
+#define OOB_CMD_DRIVER_STOP 0x06
+
+static void rtl8168_driver_start(struct rtl8169_private *tp)
+{
+ int i;
+
+ rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
+
+ for (i = 0; i < 10; i++) {
+ msleep(10);
+ if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800)
+ break;
+ }
+}
+
+static void rtl8168_driver_stop(struct rtl8169_private *tp)
+{
+ int i;
+
+ rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
+
+ for (i = 0; i < 10; i++) {
+ msleep(10);
+ if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0)
+ break;
+ }
+}
+
+
+static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
@@ -557,7 +686,7 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
udelay(20);
}
-static int mdio_read(void __iomem *ioaddr, int reg_addr)
+static int r8169_mdio_read(void __iomem *ioaddr, int reg_addr)
{
int i, value = -1;
@@ -583,34 +712,117 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
return value;
}
-static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value)
+static void r8168dp_1_mdio_access(void __iomem *ioaddr, int reg_addr, u32 data)
+{
+ int i;
+
+ RTL_W32(OCPDR, data |
+ ((reg_addr & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
+ RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
+ RTL_W32(EPHY_RXER_NUM, 0);
+
+ for (i = 0; i < 100; i++) {
+ mdelay(1);
+ if (!(RTL_R32(OCPAR) & OCPAR_FLAG))
+ break;
+ }
+}
+
+static void r8168dp_1_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+ r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_WRITE_CMD |
+ (value & OCPDR_DATA_MASK));
+}
+
+static int r8168dp_1_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+ int i;
+
+ r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_READ_CMD);
+
+ mdelay(1);
+ RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
+ RTL_W32(EPHY_RXER_NUM, 0);
+
+ for (i = 0; i < 100; i++) {
+ mdelay(1);
+ if (RTL_R32(OCPAR) & OCPAR_FLAG)
+ break;
+ }
+
+ return RTL_R32(OCPDR) & OCPDR_DATA_MASK;
+}
+
+#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
+
+static void r8168dp_2_mdio_start(void __iomem *ioaddr)
+{
+ RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
+}
+
+static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
+{
+ RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
+}
+
+static void r8168dp_2_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+ r8168dp_2_mdio_start(ioaddr);
+
+ r8169_mdio_write(ioaddr, reg_addr, value);
+
+ r8168dp_2_mdio_stop(ioaddr);
+}
+
+static int r8168dp_2_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+ int value;
+
+ r8168dp_2_mdio_start(ioaddr);
+
+ value = r8169_mdio_read(ioaddr, reg_addr);
+
+ r8168dp_2_mdio_stop(ioaddr);
+
+ return value;
+}
+
+static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
+{
+ tp->mdio_ops.write(tp->mmio_addr, location, val);
+}
+
+static int rtl_readphy(struct rtl8169_private *tp, int location)
{
- mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+ return tp->mdio_ops.read(tp->mmio_addr, location);
}
-static void mdio_plus_minus(void __iomem *ioaddr, int reg_addr, int p, int m)
+static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
+{
+ rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
+}
+
+static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
{
int val;
- val = mdio_read(ioaddr, reg_addr);
- mdio_write(ioaddr, reg_addr, (val | p) & ~m);
+ val = rtl_readphy(tp, reg_addr);
+ rtl_writephy(tp, reg_addr, (val | p) & ~m);
}
static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
int val)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- mdio_write(ioaddr, location, val);
+ rtl_writephy(tp, location, val);
}
static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- return mdio_read(ioaddr, location);
+ return rtl_readphy(tp, location);
}
static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value)
@@ -711,14 +923,16 @@ static void rtl8169_asic_down(void __iomem *ioaddr)
RTL_R16(CPlusCmd);
}
-static unsigned int rtl8169_tbi_reset_pending(void __iomem *ioaddr)
+static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
return RTL_R32(TBICSR) & TBIReset;
}
-static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr)
+static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
{
- return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
+ return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
}
static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
@@ -731,39 +945,51 @@ static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
return RTL_R8(PHYstatus) & LinkStatus;
}
-static void rtl8169_tbi_reset_enable(void __iomem *ioaddr)
+static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
}
-static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
+static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
{
unsigned int val;
- val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
- mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+ val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
+ rtl_writephy(tp, MII_BMCR, val & 0xffff);
}
-static void rtl8169_check_link_status(struct net_device *dev,
+static void __rtl8169_check_link_status(struct net_device *dev,
struct rtl8169_private *tp,
- void __iomem *ioaddr)
+ void __iomem *ioaddr,
+ bool pm)
{
unsigned long flags;
spin_lock_irqsave(&tp->lock, flags);
if (tp->link_ok(ioaddr)) {
/* This is to cancel a scheduled suspend if there's one. */
- pm_request_resume(&tp->pci_dev->dev);
+ if (pm)
+ pm_request_resume(&tp->pci_dev->dev);
netif_carrier_on(dev);
netif_info(tp, ifup, dev, "link up\n");
} else {
netif_carrier_off(dev);
netif_info(tp, ifdown, dev, "link down\n");
- pm_schedule_suspend(&tp->pci_dev->dev, 100);
+ if (pm)
+ pm_schedule_suspend(&tp->pci_dev->dev, 100);
}
spin_unlock_irqrestore(&tp->lock, flags);
}
+static void rtl8169_check_link_status(struct net_device *dev,
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr)
+{
+ __rtl8169_check_link_status(dev, tp, ioaddr, false);
+}
+
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
@@ -846,10 +1072,10 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
else
tp->features &= ~RTL_FEATURE_WOL;
__rtl8169_set_wol(tp, wol->wolopts);
- device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
-
spin_unlock_irq(&tp->lock);
+ device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
+
return 0;
}
@@ -895,18 +1121,17 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
u8 autoneg, u16 speed, u8 duplex)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
int giga_ctrl, bmcr;
if (autoneg == AUTONEG_ENABLE) {
int auto_nego;
- auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego = rtl_readphy(tp, MII_ADVERTISE);
auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
/* The 8100e/8101e/8102e do Fast Ethernet only. */
@@ -934,12 +1159,12 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
* Vendor specific (0x1f) and reserved (0x0e) MII
* registers.
*/
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_write(ioaddr, 0x0e, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0000);
}
- mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
- mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ rtl_writephy(tp, MII_ADVERTISE, auto_nego);
+ rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
} else {
giga_ctrl = 0;
@@ -953,21 +1178,21 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
if (duplex == DUPLEX_FULL)
bmcr |= BMCR_FULLDPLX;
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
tp->phy_1000_ctrl_reg = giga_ctrl;
- mdio_write(ioaddr, MII_BMCR, bmcr);
+ rtl_writephy(tp, MII_BMCR, bmcr);
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
- mdio_write(ioaddr, 0x17, 0x2138);
- mdio_write(ioaddr, 0x0e, 0x0260);
+ rtl_writephy(tp, 0x17, 0x2138);
+ rtl_writephy(tp, 0x0e, 0x0260);
} else {
- mdio_write(ioaddr, 0x17, 0x2108);
- mdio_write(ioaddr, 0x0e, 0x0000);
+ rtl_writephy(tp, 0x17, 0x2108);
+ rtl_writephy(tp, 0x0e, 0x0000);
}
}
@@ -1309,9 +1534,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
/* 8168D family. */
{ 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
{ 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
- { 0x7c800000, 0x28800000, RTL_GIGA_MAC_VER_27 },
{ 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
+ /* 8168DP family. */
+ { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
+ { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
+
/* 8168C family. */
{ 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
{ 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
@@ -1375,15 +1603,195 @@ struct phy_reg {
u16 val;
};
-static void rtl_phy_write(void __iomem *ioaddr, const struct phy_reg *regs, int len)
+static void rtl_writephy_batch(struct rtl8169_private *tp,
+ const struct phy_reg *regs, int len)
{
while (len-- > 0) {
- mdio_write(ioaddr, regs->reg, regs->val);
+ rtl_writephy(tp, regs->reg, regs->val);
regs++;
}
}
-static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
+#define PHY_READ 0x00000000
+#define PHY_DATA_OR 0x10000000
+#define PHY_DATA_AND 0x20000000
+#define PHY_BJMPN 0x30000000
+#define PHY_READ_EFUSE 0x40000000
+#define PHY_READ_MAC_BYTE 0x50000000
+#define PHY_WRITE_MAC_BYTE 0x60000000
+#define PHY_CLEAR_READCOUNT 0x70000000
+#define PHY_WRITE 0x80000000
+#define PHY_READCOUNT_EQ_SKIP 0x90000000
+#define PHY_COMP_EQ_SKIPN 0xa0000000
+#define PHY_COMP_NEQ_SKIPN 0xb0000000
+#define PHY_WRITE_PREVIOUS 0xc0000000
+#define PHY_SKIPN 0xd0000000
+#define PHY_DELAY_MS 0xe0000000
+#define PHY_WRITE_ERI_WORD 0xf0000000
+
+static void
+rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
+{
+ __le32 *phytable = (__le32 *)fw->data;
+ struct net_device *dev = tp->dev;
+ size_t index, fw_size = fw->size / sizeof(*phytable);
+ u32 predata, count;
+
+ if (fw->size % sizeof(*phytable)) {
+ netif_err(tp, probe, dev, "odd sized firmware %zd\n", fw->size);
+ return;
+ }
+
+ for (index = 0; index < fw_size; index++) {
+ u32 action = le32_to_cpu(phytable[index]);
+ u32 regno = (action & 0x0fff0000) >> 16;
+
+ switch(action & 0xf0000000) {
+ case PHY_READ:
+ case PHY_DATA_OR:
+ case PHY_DATA_AND:
+ case PHY_READ_EFUSE:
+ case PHY_CLEAR_READCOUNT:
+ case PHY_WRITE:
+ case PHY_WRITE_PREVIOUS:
+ case PHY_DELAY_MS:
+ break;
+
+ case PHY_BJMPN:
+ if (regno > index) {
+ netif_err(tp, probe, tp->dev,
+ "Out of range of firmware\n");
+ return;
+ }
+ break;
+ case PHY_READCOUNT_EQ_SKIP:
+ if (index + 2 >= fw_size) {
+ netif_err(tp, probe, tp->dev,
+ "Out of range of firmware\n");
+ return;
+ }
+ break;
+ case PHY_COMP_EQ_SKIPN:
+ case PHY_COMP_NEQ_SKIPN:
+ case PHY_SKIPN:
+ if (index + 1 + regno >= fw_size) {
+ netif_err(tp, probe, tp->dev,
+ "Out of range of firmware\n");
+ return;
+ }
+ break;
+
+ case PHY_READ_MAC_BYTE:
+ case PHY_WRITE_MAC_BYTE:
+ case PHY_WRITE_ERI_WORD:
+ default:
+ netif_err(tp, probe, tp->dev,
+ "Invalid action 0x%08x\n", action);
+ return;
+ }
+ }
+
+ predata = 0;
+ count = 0;
+
+ for (index = 0; index < fw_size; ) {
+ u32 action = le32_to_cpu(phytable[index]);
+ u32 data = action & 0x0000ffff;
+ u32 regno = (action & 0x0fff0000) >> 16;
+
+ if (!action)
+ break;
+
+ switch(action & 0xf0000000) {
+ case PHY_READ:
+ predata = rtl_readphy(tp, regno);
+ count++;
+ index++;
+ break;
+ case PHY_DATA_OR:
+ predata |= data;
+ index++;
+ break;
+ case PHY_DATA_AND:
+ predata &= data;
+ index++;
+ break;
+ case PHY_BJMPN:
+ index -= regno;
+ break;
+ case PHY_READ_EFUSE:
+ predata = rtl8168d_efuse_read(tp->mmio_addr, regno);
+ index++;
+ break;
+ case PHY_CLEAR_READCOUNT:
+ count = 0;
+ index++;
+ break;
+ case PHY_WRITE:
+ rtl_writephy(tp, regno, data);
+ index++;
+ break;
+ case PHY_READCOUNT_EQ_SKIP:
+ if (count == data)
+ index += 2;
+ else
+ index += 1;
+ break;
+ case PHY_COMP_EQ_SKIPN:
+ if (predata == data)
+ index += regno;
+ index++;
+ break;
+ case PHY_COMP_NEQ_SKIPN:
+ if (predata != data)
+ index += regno;
+ index++;
+ break;
+ case PHY_WRITE_PREVIOUS:
+ rtl_writephy(tp, regno, predata);
+ index++;
+ break;
+ case PHY_SKIPN:
+ index += regno + 1;
+ break;
+ case PHY_DELAY_MS:
+ mdelay(data);
+ index++;
+ break;
+
+ case PHY_READ_MAC_BYTE:
+ case PHY_WRITE_MAC_BYTE:
+ case PHY_WRITE_ERI_WORD:
+ default:
+ BUG();
+ }
+ }
+}
+
+static void rtl_release_firmware(struct rtl8169_private *tp)
+{
+ release_firmware(tp->fw);
+ tp->fw = NULL;
+}
+
+static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name)
+{
+ const struct firmware **fw = &tp->fw;
+ int rc = !*fw;
+
+ if (rc) {
+ rc = request_firmware(fw, fw_name, &tp->pci_dev->dev);
+ if (rc < 0)
+ goto out;
+ }
+
+ /* TODO: release firmware once rtl_phy_write_fw signals failures. */
+ rtl_phy_write_fw(tp, *fw);
+out:
+ return rc;
+}
+
+static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1447,10 +1855,10 @@ static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
{ 0x00, 0x9200 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0002 },
@@ -1458,11 +1866,10 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
u16 vendor_id, device_id;
@@ -1473,13 +1880,12 @@ static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp,
if ((vendor_id != PCI_VENDOR_ID_GIGABYTE) || (device_id != 0xe000))
return;
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_write(ioaddr, 0x10, 0xf01b);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0001);
+ rtl_writephy(tp, 0x10, 0xf01b);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1521,12 +1927,12 @@ static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp,
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- rtl8169scd_hw_phy_config_quirk(tp, ioaddr);
+ rtl8169scd_hw_phy_config_quirk(tp);
}
-static void rtl8169sce_hw_phy_config(void __iomem *ioaddr)
+static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1576,23 +1982,23 @@ static void rtl8169sce_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168bb_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x10, 0xf41b },
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_patch(ioaddr, 0x16, 1 << 0);
+ rtl_writephy(tp, 0x1f, 0x0001);
+ rtl_patchphy(tp, 0x16, 1 << 0);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1600,10 +2006,10 @@ static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0000 },
@@ -1613,10 +2019,10 @@ static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1624,14 +2030,14 @@ static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1653,14 +2059,14 @@ static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
{ 0x09, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1680,15 +2086,15 @@ static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x16, 1 << 0);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x16, 1 << 0);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1702,22 +2108,23 @@ static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x16, 1 << 0);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x16, 1 << 0);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
{
- rtl8168c_3_hw_phy_config(ioaddr);
+ rtl8168c_3_hw_phy_config(tp);
}
-static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init_0[] = {
+ /* Channel Estimation */
{ 0x1f, 0x0001 },
{ 0x06, 0x4064 },
{ 0x07, 0x2863 },
@@ -1734,378 +2141,39 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x12, 0xf49f },
{ 0x13, 0x070b },
{ 0x1a, 0x05ad },
- { 0x14, 0x94c0 }
- };
- static const struct phy_reg phy_reg_init_1[] = {
+ { 0x14, 0x94c0 },
+
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
{ 0x1f, 0x0005 },
{ 0x05, 0x8332 },
- { 0x06, 0x5561 }
- };
- static const struct phy_reg phy_reg_init_2[] = {
- { 0x1f, 0x0005 },
- { 0x05, 0xffc2 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8000 },
- { 0x06, 0xf8f9 },
- { 0x06, 0xfaef },
- { 0x06, 0x59ee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x00e0 },
- { 0x06, 0xf87c },
- { 0x06, 0xe1f8 },
- { 0x06, 0x7d59 },
- { 0x06, 0x0fef },
- { 0x06, 0x0139 },
- { 0x06, 0x029e },
- { 0x06, 0x06ef },
- { 0x06, 0x1039 },
- { 0x06, 0x089f },
- { 0x06, 0x2aee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x01e0 },
- { 0x06, 0xf87c },
- { 0x06, 0xe1f8 },
- { 0x06, 0x7d58 },
- { 0x06, 0x409e },
- { 0x06, 0x0f39 },
- { 0x06, 0x46aa },
- { 0x06, 0x0bbf },
- { 0x06, 0x8290 },
- { 0x06, 0xd682 },
- { 0x06, 0x9802 },
- { 0x06, 0x014f },
- { 0x06, 0xae09 },
- { 0x06, 0xbf82 },
- { 0x06, 0x98d6 },
- { 0x06, 0x82a0 },
- { 0x06, 0x0201 },
- { 0x06, 0x4fef },
- { 0x06, 0x95fe },
- { 0x06, 0xfdfc },
- { 0x06, 0x05f8 },
- { 0x06, 0xf9fa },
- { 0x06, 0xeef8 },
- { 0x06, 0xea00 },
- { 0x06, 0xeef8 },
- { 0x06, 0xeb00 },
- { 0x06, 0xe2f8 },
- { 0x06, 0x7ce3 },
- { 0x06, 0xf87d },
- { 0x06, 0xa511 },
- { 0x06, 0x1112 },
- { 0x06, 0xd240 },
- { 0x06, 0xd644 },
- { 0x06, 0x4402 },
- { 0x06, 0x8217 },
- { 0x06, 0xd2a0 },
- { 0x06, 0xd6aa },
- { 0x06, 0xaa02 },
- { 0x06, 0x8217 },
- { 0x06, 0xae0f },
- { 0x06, 0xa544 },
- { 0x06, 0x4402 },
- { 0x06, 0xae4d },
- { 0x06, 0xa5aa },
- { 0x06, 0xaa02 },
- { 0x06, 0xae47 },
- { 0x06, 0xaf82 },
- { 0x06, 0x13ee },
- { 0x06, 0x834e },
- { 0x06, 0x00ee },
- { 0x06, 0x834d },
- { 0x06, 0x0fee },
- { 0x06, 0x834c },
- { 0x06, 0x0fee },
- { 0x06, 0x834f },
- { 0x06, 0x00ee },
- { 0x06, 0x8351 },
- { 0x06, 0x00ee },
- { 0x06, 0x834a },
- { 0x06, 0xffee },
- { 0x06, 0x834b },
- { 0x06, 0xffe0 },
- { 0x06, 0x8330 },
- { 0x06, 0xe183 },
- { 0x06, 0x3158 },
- { 0x06, 0xfee4 },
- { 0x06, 0xf88a },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8be0 },
- { 0x06, 0x8332 },
- { 0x06, 0xe183 },
- { 0x06, 0x3359 },
- { 0x06, 0x0fe2 },
- { 0x06, 0x834d },
- { 0x06, 0x0c24 },
- { 0x06, 0x5af0 },
- { 0x06, 0x1e12 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ce5 },
- { 0x06, 0xf88d },
- { 0x06, 0xaf82 },
- { 0x06, 0x13e0 },
- { 0x06, 0x834f },
- { 0x06, 0x10e4 },
- { 0x06, 0x834f },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x009f },
- { 0x06, 0x0ae0 },
- { 0x06, 0x834f },
- { 0x06, 0xa010 },
- { 0x06, 0xa5ee },
- { 0x06, 0x834e },
- { 0x06, 0x01e0 },
- { 0x06, 0x834e },
- { 0x06, 0x7805 },
- { 0x06, 0x9e9a },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x049e },
- { 0x06, 0x10e0 },
- { 0x06, 0x834e },
- { 0x06, 0x7803 },
- { 0x06, 0x9e0f },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x019e },
- { 0x06, 0x05ae },
- { 0x06, 0x0caf },
- { 0x06, 0x81f8 },
- { 0x06, 0xaf81 },
- { 0x06, 0xa3af },
- { 0x06, 0x81dc },
- { 0x06, 0xaf82 },
- { 0x06, 0x13ee },
- { 0x06, 0x8348 },
- { 0x06, 0x00ee },
- { 0x06, 0x8349 },
- { 0x06, 0x00e0 },
- { 0x06, 0x8351 },
- { 0x06, 0x10e4 },
- { 0x06, 0x8351 },
- { 0x06, 0x5801 },
- { 0x06, 0x9fea },
- { 0x06, 0xd000 },
- { 0x06, 0xd180 },
- { 0x06, 0x1f66 },
- { 0x06, 0xe2f8 },
- { 0x06, 0xeae3 },
- { 0x06, 0xf8eb },
- { 0x06, 0x5af8 },
- { 0x06, 0x1e20 },
- { 0x06, 0xe6f8 },
- { 0x06, 0xeae5 },
- { 0x06, 0xf8eb },
- { 0x06, 0xd302 },
- { 0x06, 0xb3fe },
- { 0x06, 0xe2f8 },
- { 0x06, 0x7cef },
- { 0x06, 0x325b },
- { 0x06, 0x80e3 },
- { 0x06, 0xf87d },
- { 0x06, 0x9e03 },
- { 0x06, 0x7dff },
- { 0x06, 0xff0d },
- { 0x06, 0x581c },
- { 0x06, 0x551a },
- { 0x06, 0x6511 },
- { 0x06, 0xa190 },
- { 0x06, 0xd3e2 },
- { 0x06, 0x8348 },
- { 0x06, 0xe383 },
- { 0x06, 0x491b },
- { 0x06, 0x56ab },
- { 0x06, 0x08ef },
- { 0x06, 0x56e6 },
- { 0x06, 0x8348 },
- { 0x06, 0xe783 },
- { 0x06, 0x4910 },
- { 0x06, 0xd180 },
- { 0x06, 0x1f66 },
- { 0x06, 0xa004 },
- { 0x06, 0xb9e2 },
- { 0x06, 0x8348 },
- { 0x06, 0xe383 },
- { 0x06, 0x49ef },
- { 0x06, 0x65e2 },
- { 0x06, 0x834a },
- { 0x06, 0xe383 },
- { 0x06, 0x4b1b },
- { 0x06, 0x56aa },
- { 0x06, 0x0eef },
- { 0x06, 0x56e6 },
- { 0x06, 0x834a },
- { 0x06, 0xe783 },
- { 0x06, 0x4be2 },
- { 0x06, 0x834d },
- { 0x06, 0xe683 },
- { 0x06, 0x4ce0 },
- { 0x06, 0x834d },
- { 0x06, 0xa000 },
- { 0x06, 0x0caf },
- { 0x06, 0x81dc },
- { 0x06, 0xe083 },
- { 0x06, 0x4d10 },
- { 0x06, 0xe483 },
- { 0x06, 0x4dae },
- { 0x06, 0x0480 },
- { 0x06, 0xe483 },
- { 0x06, 0x4de0 },
- { 0x06, 0x834e },
- { 0x06, 0x7803 },
- { 0x06, 0x9e0b },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x049e },
- { 0x06, 0x04ee },
- { 0x06, 0x834e },
- { 0x06, 0x02e0 },
- { 0x06, 0x8332 },
- { 0x06, 0xe183 },
- { 0x06, 0x3359 },
- { 0x06, 0x0fe2 },
- { 0x06, 0x834d },
- { 0x06, 0x0c24 },
- { 0x06, 0x5af0 },
- { 0x06, 0x1e12 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ce5 },
- { 0x06, 0xf88d },
- { 0x06, 0xe083 },
- { 0x06, 0x30e1 },
- { 0x06, 0x8331 },
- { 0x06, 0x6801 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ae5 },
- { 0x06, 0xf88b },
- { 0x06, 0xae37 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e03 },
- { 0x06, 0xe083 },
- { 0x06, 0x4ce1 },
- { 0x06, 0x834d },
- { 0x06, 0x1b01 },
- { 0x06, 0x9e04 },
- { 0x06, 0xaaa1 },
- { 0x06, 0xaea8 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e04 },
- { 0x06, 0xee83 },
- { 0x06, 0x4f00 },
- { 0x06, 0xaeab },
- { 0x06, 0xe083 },
- { 0x06, 0x4f78 },
- { 0x06, 0x039f },
- { 0x06, 0x14ee },
- { 0x06, 0x834e },
- { 0x06, 0x05d2 },
- { 0x06, 0x40d6 },
- { 0x06, 0x5554 },
- { 0x06, 0x0282 },
- { 0x06, 0x17d2 },
- { 0x06, 0xa0d6 },
- { 0x06, 0xba00 },
- { 0x06, 0x0282 },
- { 0x06, 0x17fe },
- { 0x06, 0xfdfc },
- { 0x06, 0x05f8 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x60e1 },
- { 0x06, 0xf861 },
- { 0x06, 0x6802 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x60e5 },
- { 0x06, 0xf861 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x48e1 },
- { 0x06, 0xf849 },
- { 0x06, 0x580f },
- { 0x06, 0x1e02 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0xd000 },
- { 0x06, 0x0282 },
- { 0x06, 0x5bbf },
- { 0x06, 0x8350 },
- { 0x06, 0xef46 },
- { 0x06, 0xdc19 },
- { 0x06, 0xddd0 },
- { 0x06, 0x0102 },
- { 0x06, 0x825b },
- { 0x06, 0x0282 },
- { 0x06, 0x77e0 },
- { 0x06, 0xf860 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x6158 },
- { 0x06, 0xfde4 },
- { 0x06, 0xf860 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x61fc },
- { 0x06, 0x04f9 },
- { 0x06, 0xfafb },
- { 0x06, 0xc6bf },
- { 0x06, 0xf840 },
- { 0x06, 0xbe83 },
- { 0x06, 0x50a0 },
- { 0x06, 0x0101 },
- { 0x06, 0x071b },
- { 0x06, 0x89cf },
- { 0x06, 0xd208 },
- { 0x06, 0xebdb },
- { 0x06, 0x19b2 },
- { 0x06, 0xfbff },
- { 0x06, 0xfefd },
- { 0x06, 0x04f8 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x48e1 },
- { 0x06, 0xf849 },
- { 0x06, 0x6808 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0x58f7 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0xfc04 },
- { 0x06, 0x4d20 },
- { 0x06, 0x0002 },
- { 0x06, 0x4e22 },
- { 0x06, 0x0002 },
- { 0x06, 0x4ddf },
- { 0x06, 0xff01 },
- { 0x06, 0x4edd },
- { 0x06, 0xff01 },
- { 0x05, 0x83d4 },
- { 0x06, 0x8000 },
- { 0x05, 0x83d8 },
- { 0x06, 0x8051 },
- { 0x02, 0x6010 },
- { 0x03, 0xdc00 },
- { 0x05, 0xfff6 },
- { 0x06, 0x00fc },
- { 0x1f, 0x0000 },
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
{ 0x1f, 0x0000 },
- { 0x0d, 0xf880 },
- { 0x1f, 0x0000 }
+ { 0x0d, 0xf880 }
};
+ void __iomem *ioaddr = tp->mmio_addr;
- rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
-
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x0b, 0x0010, 0x00ef);
- mdio_plus_minus(ioaddr, 0x0c, 0xa200, 0x5d00);
+ rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+ /*
+ * Rx Error Issue
+ * Fine Tune Switching regulator parameter
+ */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
+ rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
@@ -2118,9 +2186,9 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
};
int val;
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- val = mdio_read(ioaddr, 0x0d);
+ val = rtl_readphy(tp, 0x0d);
if ((val & 0x00ff) != 0x006c) {
static const u32 set[] = {
@@ -2129,11 +2197,11 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
};
int i;
- mdio_write(ioaddr, 0x1f, 0x0002);
+ rtl_writephy(tp, 0x1f, 0x0002);
val &= 0xff00;
for (i = 0; i < ARRAY_SIZE(set); i++)
- mdio_write(ioaddr, 0x0d, val | set[i]);
+ rtl_writephy(tp, 0x0d, val | set[i]);
}
} else {
static const struct phy_reg phy_reg_init[] = {
@@ -2144,23 +2212,33 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0x6662 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_patch(ioaddr, 0x0d, 0x0300);
- mdio_patch(ioaddr, 0x0f, 0x0010);
-
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
- mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+ /* RSET couple improve */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_patchphy(tp, 0x0d, 0x0300);
+ rtl_patchphy(tp, 0x0f, 0x0010);
+
+ /* Fine tune PLL performance */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
+ rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
+
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x001b);
+ if ((rtl_readphy(tp, 0x06) != 0xbf00) ||
+ (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) {
+ netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
+ }
- rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init_0[] = {
+ /* Channel Estimation */
{ 0x1f, 0x0001 },
{ 0x06, 0x4064 },
{ 0x07, 0x2863 },
@@ -2179,326 +2257,29 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1a, 0x05ad },
{ 0x14, 0x94c0 },
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
{ 0x1f, 0x0005 },
{ 0x05, 0x8332 },
- { 0x06, 0x5561 }
- };
- static const struct phy_reg phy_reg_init_1[] = {
- { 0x1f, 0x0005 },
- { 0x05, 0xffc2 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8000 },
- { 0x06, 0xf8f9 },
- { 0x06, 0xfaee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x00e2 },
- { 0x06, 0xf87c },
- { 0x06, 0xe3f8 },
- { 0x06, 0x7da5 },
- { 0x06, 0x1111 },
- { 0x06, 0x12d2 },
- { 0x06, 0x40d6 },
- { 0x06, 0x4444 },
- { 0x06, 0x0281 },
- { 0x06, 0xc6d2 },
- { 0x06, 0xa0d6 },
- { 0x06, 0xaaaa },
- { 0x06, 0x0281 },
- { 0x06, 0xc6ae },
- { 0x06, 0x0fa5 },
- { 0x06, 0x4444 },
- { 0x06, 0x02ae },
- { 0x06, 0x4da5 },
- { 0x06, 0xaaaa },
- { 0x06, 0x02ae },
- { 0x06, 0x47af },
- { 0x06, 0x81c2 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e00 },
- { 0x06, 0xee83 },
- { 0x06, 0x4d0f },
- { 0x06, 0xee83 },
- { 0x06, 0x4c0f },
- { 0x06, 0xee83 },
- { 0x06, 0x4f00 },
- { 0x06, 0xee83 },
- { 0x06, 0x5100 },
- { 0x06, 0xee83 },
- { 0x06, 0x4aff },
- { 0x06, 0xee83 },
- { 0x06, 0x4bff },
- { 0x06, 0xe083 },
- { 0x06, 0x30e1 },
- { 0x06, 0x8331 },
- { 0x06, 0x58fe },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ae5 },
- { 0x06, 0xf88b },
- { 0x06, 0xe083 },
- { 0x06, 0x32e1 },
- { 0x06, 0x8333 },
- { 0x06, 0x590f },
- { 0x06, 0xe283 },
- { 0x06, 0x4d0c },
- { 0x06, 0x245a },
- { 0x06, 0xf01e },
- { 0x06, 0x12e4 },
- { 0x06, 0xf88c },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8daf },
- { 0x06, 0x81c2 },
- { 0x06, 0xe083 },
- { 0x06, 0x4f10 },
- { 0x06, 0xe483 },
- { 0x06, 0x4fe0 },
- { 0x06, 0x834e },
- { 0x06, 0x7800 },
- { 0x06, 0x9f0a },
- { 0x06, 0xe083 },
- { 0x06, 0x4fa0 },
- { 0x06, 0x10a5 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e01 },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x059e },
- { 0x06, 0x9ae0 },
- { 0x06, 0x834e },
- { 0x06, 0x7804 },
- { 0x06, 0x9e10 },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x039e },
- { 0x06, 0x0fe0 },
- { 0x06, 0x834e },
- { 0x06, 0x7801 },
- { 0x06, 0x9e05 },
- { 0x06, 0xae0c },
- { 0x06, 0xaf81 },
- { 0x06, 0xa7af },
- { 0x06, 0x8152 },
- { 0x06, 0xaf81 },
- { 0x06, 0x8baf },
- { 0x06, 0x81c2 },
- { 0x06, 0xee83 },
- { 0x06, 0x4800 },
- { 0x06, 0xee83 },
- { 0x06, 0x4900 },
- { 0x06, 0xe083 },
- { 0x06, 0x5110 },
- { 0x06, 0xe483 },
- { 0x06, 0x5158 },
- { 0x06, 0x019f },
- { 0x06, 0xead0 },
- { 0x06, 0x00d1 },
- { 0x06, 0x801f },
- { 0x06, 0x66e2 },
- { 0x06, 0xf8ea },
- { 0x06, 0xe3f8 },
- { 0x06, 0xeb5a },
- { 0x06, 0xf81e },
- { 0x06, 0x20e6 },
- { 0x06, 0xf8ea },
- { 0x06, 0xe5f8 },
- { 0x06, 0xebd3 },
- { 0x06, 0x02b3 },
- { 0x06, 0xfee2 },
- { 0x06, 0xf87c },
- { 0x06, 0xef32 },
- { 0x06, 0x5b80 },
- { 0x06, 0xe3f8 },
- { 0x06, 0x7d9e },
- { 0x06, 0x037d },
- { 0x06, 0xffff },
- { 0x06, 0x0d58 },
- { 0x06, 0x1c55 },
- { 0x06, 0x1a65 },
- { 0x06, 0x11a1 },
- { 0x06, 0x90d3 },
- { 0x06, 0xe283 },
- { 0x06, 0x48e3 },
- { 0x06, 0x8349 },
- { 0x06, 0x1b56 },
- { 0x06, 0xab08 },
- { 0x06, 0xef56 },
- { 0x06, 0xe683 },
- { 0x06, 0x48e7 },
- { 0x06, 0x8349 },
- { 0x06, 0x10d1 },
- { 0x06, 0x801f },
- { 0x06, 0x66a0 },
- { 0x06, 0x04b9 },
- { 0x06, 0xe283 },
- { 0x06, 0x48e3 },
- { 0x06, 0x8349 },
- { 0x06, 0xef65 },
- { 0x06, 0xe283 },
- { 0x06, 0x4ae3 },
- { 0x06, 0x834b },
- { 0x06, 0x1b56 },
- { 0x06, 0xaa0e },
- { 0x06, 0xef56 },
- { 0x06, 0xe683 },
- { 0x06, 0x4ae7 },
- { 0x06, 0x834b },
- { 0x06, 0xe283 },
- { 0x06, 0x4de6 },
- { 0x06, 0x834c },
- { 0x06, 0xe083 },
- { 0x06, 0x4da0 },
- { 0x06, 0x000c },
- { 0x06, 0xaf81 },
- { 0x06, 0x8be0 },
- { 0x06, 0x834d },
- { 0x06, 0x10e4 },
- { 0x06, 0x834d },
- { 0x06, 0xae04 },
- { 0x06, 0x80e4 },
- { 0x06, 0x834d },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x039e },
- { 0x06, 0x0be0 },
- { 0x06, 0x834e },
- { 0x06, 0x7804 },
- { 0x06, 0x9e04 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e02 },
- { 0x06, 0xe083 },
- { 0x06, 0x32e1 },
- { 0x06, 0x8333 },
- { 0x06, 0x590f },
- { 0x06, 0xe283 },
- { 0x06, 0x4d0c },
- { 0x06, 0x245a },
- { 0x06, 0xf01e },
- { 0x06, 0x12e4 },
- { 0x06, 0xf88c },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8de0 },
- { 0x06, 0x8330 },
- { 0x06, 0xe183 },
- { 0x06, 0x3168 },
- { 0x06, 0x01e4 },
- { 0x06, 0xf88a },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8bae },
- { 0x06, 0x37ee },
- { 0x06, 0x834e },
- { 0x06, 0x03e0 },
- { 0x06, 0x834c },
- { 0x06, 0xe183 },
- { 0x06, 0x4d1b },
- { 0x06, 0x019e },
- { 0x06, 0x04aa },
- { 0x06, 0xa1ae },
- { 0x06, 0xa8ee },
- { 0x06, 0x834e },
- { 0x06, 0x04ee },
- { 0x06, 0x834f },
- { 0x06, 0x00ae },
- { 0x06, 0xabe0 },
- { 0x06, 0x834f },
- { 0x06, 0x7803 },
- { 0x06, 0x9f14 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e05 },
- { 0x06, 0xd240 },
- { 0x06, 0xd655 },
- { 0x06, 0x5402 },
- { 0x06, 0x81c6 },
- { 0x06, 0xd2a0 },
- { 0x06, 0xd6ba },
- { 0x06, 0x0002 },
- { 0x06, 0x81c6 },
- { 0x06, 0xfefd },
- { 0x06, 0xfc05 },
- { 0x06, 0xf8e0 },
- { 0x06, 0xf860 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x6168 },
- { 0x06, 0x02e4 },
- { 0x06, 0xf860 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x61e0 },
- { 0x06, 0xf848 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x4958 },
- { 0x06, 0x0f1e },
- { 0x06, 0x02e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x49d0 },
- { 0x06, 0x0002 },
- { 0x06, 0x820a },
- { 0x06, 0xbf83 },
- { 0x06, 0x50ef },
- { 0x06, 0x46dc },
- { 0x06, 0x19dd },
- { 0x06, 0xd001 },
- { 0x06, 0x0282 },
- { 0x06, 0x0a02 },
- { 0x06, 0x8226 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x60e1 },
- { 0x06, 0xf861 },
- { 0x06, 0x58fd },
- { 0x06, 0xe4f8 },
- { 0x06, 0x60e5 },
- { 0x06, 0xf861 },
- { 0x06, 0xfc04 },
- { 0x06, 0xf9fa },
- { 0x06, 0xfbc6 },
- { 0x06, 0xbff8 },
- { 0x06, 0x40be },
- { 0x06, 0x8350 },
- { 0x06, 0xa001 },
- { 0x06, 0x0107 },
- { 0x06, 0x1b89 },
- { 0x06, 0xcfd2 },
- { 0x06, 0x08eb },
- { 0x06, 0xdb19 },
- { 0x06, 0xb2fb },
- { 0x06, 0xfffe },
- { 0x06, 0xfd04 },
- { 0x06, 0xf8e0 },
- { 0x06, 0xf848 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x4968 },
- { 0x06, 0x08e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x4958 },
- { 0x06, 0xf7e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x49fc },
- { 0x06, 0x044d },
- { 0x06, 0x2000 },
- { 0x06, 0x024e },
- { 0x06, 0x2200 },
- { 0x06, 0x024d },
- { 0x06, 0xdfff },
- { 0x06, 0x014e },
- { 0x06, 0xddff },
- { 0x06, 0x0100 },
- { 0x05, 0x83d8 },
- { 0x06, 0x8000 },
- { 0x03, 0xdc00 },
- { 0x05, 0xfff6 },
- { 0x06, 0x00fc },
- { 0x1f, 0x0000 },
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
{ 0x1f, 0x0000 },
- { 0x0d, 0xf880 },
- { 0x1f, 0x0000 }
+ { 0x0d, 0xf880 }
};
+ void __iomem *ioaddr = tp->mmio_addr;
- rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
@@ -2512,21 +2293,21 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
};
int val;
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- val = mdio_read(ioaddr, 0x0d);
+ val = rtl_readphy(tp, 0x0d);
if ((val & 0x00ff) != 0x006c) {
- u32 set[] = {
+ static const u32 set[] = {
0x0065, 0x0066, 0x0067, 0x0068,
0x0069, 0x006a, 0x006b, 0x006c
};
int i;
- mdio_write(ioaddr, 0x1f, 0x0002);
+ rtl_writephy(tp, 0x1f, 0x0002);
val &= 0xff00;
for (i = 0; i < ARRAY_SIZE(set); i++)
- mdio_write(ioaddr, 0x0d, val | set[i]);
+ rtl_writephy(tp, 0x0d, val | set[i]);
}
} else {
static const struct phy_reg phy_reg_init[] = {
@@ -2537,23 +2318,29 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0x2642 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
- mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+ /* Fine tune PLL performance */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
+ rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_write(ioaddr, 0x17, 0x0cc0);
+ /* Switching regulator Slew rate */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_patchphy(tp, 0x0f, 0x0017);
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_patch(ioaddr, 0x0f, 0x0017);
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x001b);
+ if ((rtl_readphy(tp, 0x06) != 0xb300) ||
+ (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) {
+ netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
+ }
- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0002 },
@@ -2611,10 +2398,26 @@ static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
+{
+ static const struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x002d },
+ { 0x18, 0x0040 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_patchphy(tp, 0x0d, 1 << 5);
}
-static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
+static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0003 },
@@ -2623,18 +2426,17 @@ static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_patch(ioaddr, 0x11, 1 << 12);
- mdio_patch(ioaddr, 0x19, 1 << 13);
- mdio_patch(ioaddr, 0x10, 1 << 15);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x11, 1 << 12);
+ rtl_patchphy(tp, 0x19, 1 << 13);
+ rtl_patchphy(tp, 0x10, 1 << 15);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
static void rtl_hw_phy_config(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
rtl8169_print_mac_version(tp);
@@ -2643,58 +2445,61 @@ static void rtl_hw_phy_config(struct net_device *dev)
break;
case RTL_GIGA_MAC_VER_02:
case RTL_GIGA_MAC_VER_03:
- rtl8169s_hw_phy_config(ioaddr);
+ rtl8169s_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_04:
- rtl8169sb_hw_phy_config(ioaddr);
+ rtl8169sb_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_05:
- rtl8169scd_hw_phy_config(tp, ioaddr);
+ rtl8169scd_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_06:
- rtl8169sce_hw_phy_config(ioaddr);
+ rtl8169sce_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_07:
case RTL_GIGA_MAC_VER_08:
case RTL_GIGA_MAC_VER_09:
- rtl8102e_hw_phy_config(ioaddr);
+ rtl8102e_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_11:
- rtl8168bb_hw_phy_config(ioaddr);
+ rtl8168bb_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_12:
- rtl8168bef_hw_phy_config(ioaddr);
+ rtl8168bef_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_17:
- rtl8168bef_hw_phy_config(ioaddr);
+ rtl8168bef_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_18:
- rtl8168cp_1_hw_phy_config(ioaddr);
+ rtl8168cp_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_1_hw_phy_config(ioaddr);
+ rtl8168c_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168c_2_hw_phy_config(ioaddr);
+ rtl8168c_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_21:
- rtl8168c_3_hw_phy_config(ioaddr);
+ rtl8168c_3_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_22:
- rtl8168c_4_hw_phy_config(ioaddr);
+ rtl8168c_4_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_23:
case RTL_GIGA_MAC_VER_24:
- rtl8168cp_2_hw_phy_config(ioaddr);
+ rtl8168cp_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_25:
- rtl8168d_1_hw_phy_config(ioaddr);
+ rtl8168d_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_26:
- rtl8168d_2_hw_phy_config(ioaddr);
+ rtl8168d_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_27:
- rtl8168d_3_hw_phy_config(ioaddr);
+ rtl8168d_3_hw_phy_config(tp);
+ break;
+ case RTL_GIGA_MAC_VER_28:
+ rtl8168d_4_hw_phy_config(tp);
break;
default:
@@ -2717,7 +2522,7 @@ static void rtl8169_phy_timer(unsigned long __opaque)
spin_lock_irq(&tp->lock);
- if (tp->phy_reset_pending(ioaddr)) {
+ if (tp->phy_reset_pending(tp)) {
/*
* A busy loop could burn quite a few cycles on nowadays CPU.
* Let's delay the execution of the timer for a few ticks.
@@ -2731,7 +2536,7 @@ static void rtl8169_phy_timer(unsigned long __opaque)
netif_warn(tp, link, dev, "PHY reset until link up\n");
- tp->phy_reset_enable(ioaddr);
+ tp->phy_reset_enable(tp);
out_mod_timer:
mod_timer(timer, jiffies + timeout);
@@ -2791,12 +2596,11 @@ static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
static void rtl8169_phy_reset(struct net_device *dev,
struct rtl8169_private *tp)
{
- void __iomem *ioaddr = tp->mmio_addr;
unsigned int i;
- tp->phy_reset_enable(ioaddr);
+ tp->phy_reset_enable(tp);
for (i = 0; i < 100; i++) {
- if (!tp->phy_reset_pending(ioaddr))
+ if (!tp->phy_reset_pending(tp))
return;
msleep(1);
}
@@ -2823,7 +2627,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8(0x82, 0x01);
dprintk("Set PHY Reg 0x0bh = 0x00h\n");
- mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
}
rtl8169_phy_reset(dev, tp);
@@ -2893,11 +2697,11 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat
return 0;
case SIOCGMIIREG:
- data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);
+ data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
return 0;
case SIOCSMIIREG:
- mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);
+ rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
return 0;
}
return -EOPNOTSUPP;
@@ -2931,7 +2735,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8168,
.region = 2,
.align = 8,
- .intr_event = SYSErr | RxFIFOOver | LinkChg | RxOverflow |
+ .intr_event = SYSErr | LinkChg | RxOverflow |
TxErr | TxOK | RxOK | RxErr,
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
@@ -2997,6 +2801,173 @@ static const struct net_device_ops rtl8169_netdev_ops = {
};
+static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
+{
+ struct mdio_ops *ops = &tp->mdio_ops;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_27:
+ ops->write = r8168dp_1_mdio_write;
+ ops->read = r8168dp_1_mdio_read;
+ break;
+ case RTL_GIGA_MAC_VER_28:
+ ops->write = r8168dp_2_mdio_write;
+ ops->read = r8168dp_2_mdio_read;
+ break;
+ default:
+ ops->write = r8169_mdio_write;
+ ops->read = r8169_mdio_read;
+ break;
+ }
+}
+
+static void r810x_phy_power_down(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+}
+
+static void r810x_phy_power_up(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
+}
+
+static void r810x_pll_power_down(struct rtl8169_private *tp)
+{
+ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, 0x0000);
+ return;
+ }
+
+ r810x_phy_power_down(tp);
+}
+
+static void r810x_pll_power_up(struct rtl8169_private *tp)
+{
+ r810x_phy_power_up(tp);
+}
+
+static void r8168_phy_power_up(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
+}
+
+static void r8168_phy_power_down(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0200);
+ rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+}
+
+static void r8168_pll_power_down(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ return;
+
+ if (((tp->mac_version == RTL_GIGA_MAC_VER_23) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_24)) &&
+ (RTL_R16(CPlusCmd) & ASF)) {
+ return;
+ }
+
+ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, 0x0000);
+
+ RTL_W32(RxConfig, RTL_R32(RxConfig) |
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
+ return;
+ }
+
+ r8168_phy_power_down(tp);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
+ break;
+ }
+}
+
+static void r8168_pll_power_up(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ return;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
+ break;
+ }
+
+ r8168_phy_power_up(tp);
+}
+
+static void rtl_pll_power_op(struct rtl8169_private *tp,
+ void (*op)(struct rtl8169_private *))
+{
+ if (op)
+ op(tp);
+}
+
+static void rtl_pll_power_down(struct rtl8169_private *tp)
+{
+ rtl_pll_power_op(tp, tp->pll_power_ops.down);
+}
+
+static void rtl_pll_power_up(struct rtl8169_private *tp)
+{
+ rtl_pll_power_op(tp, tp->pll_power_ops.up);
+}
+
+static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
+{
+ struct pll_power_ops *ops = &tp->pll_power_ops;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_07:
+ case RTL_GIGA_MAC_VER_08:
+ case RTL_GIGA_MAC_VER_09:
+ case RTL_GIGA_MAC_VER_10:
+ case RTL_GIGA_MAC_VER_16:
+ ops->down = r810x_pll_power_down;
+ ops->up = r810x_pll_power_up;
+ break;
+
+ case RTL_GIGA_MAC_VER_11:
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ case RTL_GIGA_MAC_VER_18:
+ case RTL_GIGA_MAC_VER_19:
+ case RTL_GIGA_MAC_VER_20:
+ case RTL_GIGA_MAC_VER_21:
+ case RTL_GIGA_MAC_VER_22:
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ case RTL_GIGA_MAC_VER_27:
+ case RTL_GIGA_MAC_VER_28:
+ ops->down = r8168_pll_power_down;
+ ops->up = r8168_pll_power_up;
+ break;
+
+ default:
+ ops->down = NULL;
+ ops->up = NULL;
+ break;
+ }
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -3115,6 +3086,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Identify chip attached to board */
rtl8169_get_mac_version(tp, ioaddr);
+ rtl_init_mdio_ops(tp);
+ rtl_init_pll_power_ops(tp);
+
/* Use appropriate default if unknown */
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
netif_notice(tp, probe, dev,
@@ -3205,14 +3179,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->base_addr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
- rtl8169_init_phy(dev, tp);
-
- /*
- * Pretend we are using VLANs; This bypasses a nasty bug where
- * Interrupts stop flowing on high load on 8110SCd controllers.
- */
- if (tp->mac_version == RTL_GIGA_MAC_VER_05)
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
+ rtl8168_driver_start(tp);
+ }
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
@@ -3240,7 +3210,14 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- flush_scheduled_work();
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
+ rtl8168_driver_stop(tp);
+ }
+
+ cancel_delayed_work_sync(&tp->task);
+
+ rtl_release_firmware(tp);
unregister_netdev(dev);
@@ -3258,6 +3235,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
static int rtl8169_open(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
int retval = -ENOMEM;
@@ -3293,6 +3271,17 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+ rtl8169_init_phy(dev, tp);
+
+ /*
+ * Pretend we are using VLANs; This bypasses a nasty bug where
+ * Interrupts stop flowing on high load on 8110SCd controllers.
+ */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
+
+ rtl_pll_power_up(tp);
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -3300,7 +3289,7 @@ static int rtl8169_open(struct net_device *dev)
tp->saved_wolopts = 0;
pm_runtime_put_noidle(&pdev->dev);
- rtl8169_check_link_status(dev, tp, tp->mmio_addr);
+ rtl8169_check_link_status(dev, tp, ioaddr);
out:
return retval;
@@ -3319,11 +3308,19 @@ err_pm_runtime_put:
goto out;
}
-static void rtl8169_hw_reset(void __iomem *ioaddr)
+static void rtl8169_hw_reset(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
/* Disable interrupts */
rtl8169_irq_mask_and_ack(ioaddr);
+ if (tp->mac_version == RTL_GIGA_MAC_VER_28) {
+ while (RTL_R8(TxPoll) & NPQ)
+ udelay(20);
+
+ }
+
/* Reset the chipset */
RTL_W8(ChipCmd, CmdReset);
@@ -3437,7 +3434,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
(tp->mac_version == RTL_GIGA_MAC_VER_04))
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(EarlyTxThres, NoEarlyTx);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
@@ -3507,12 +3504,22 @@ static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
}
}
-static void rtl_csi_access_enable(void __iomem *ioaddr)
+static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
{
u32 csi;
csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
- rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+ rtl_csi_write(ioaddr, 0x070c, csi | bits);
+}
+
+static void rtl_csi_access_enable_1(void __iomem *ioaddr)
+{
+ rtl_csi_access_enable(ioaddr, 0x17000000);
+}
+
+static void rtl_csi_access_enable_2(void __iomem *ioaddr)
+{
+ rtl_csi_access_enable(ioaddr, 0x27000000);
}
struct ephy_info {
@@ -3547,6 +3554,21 @@ static void rtl_disable_clock_request(struct pci_dev *pdev)
}
}
+static void rtl_enable_clock_request(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+ ctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
+ pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+ }
+}
+
#define R8168_CPCMD_QUIRK_MASK (\
EnableBist | \
Mac_dbgo_oe | \
@@ -3572,7 +3594,7 @@ static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev)
{
rtl_hw_start_8168bb(ioaddr, pdev);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
}
@@ -3600,7 +3622,7 @@ static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x07, 0, 0x2000 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
@@ -3609,7 +3631,7 @@ static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
@@ -3620,14 +3642,14 @@ static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
/* Magic. */
RTL_W8(DBG_REG, 0x20);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
@@ -3642,7 +3664,7 @@ static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x06, 0x0080, 0x0000 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
@@ -3658,7 +3680,7 @@ static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x03, 0x0400, 0x0220 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
@@ -3672,24 +3694,50 @@ static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
__rtl_hw_start_8168cp(ioaddr, pdev);
}
static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_disable_clock_request(pdev);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
}
+static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+ static const struct ephy_info e_info_8168d_4[] = {
+ { 0x0b, ~0, 0x48 },
+ { 0x19, 0x20, 0x50 },
+ { 0x0c, ~0, 0x20 }
+ };
+ int i;
+
+ rtl_csi_access_enable_1(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
+
+ for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
+ const struct ephy_info *e = e_info_8168d_4 + i;
+ u16 w;
+
+ w = rtl_ephy_read(ioaddr, e->offset);
+ rtl_ephy_write(ioaddr, 0x03, (w & e->mask) | e->bits);
+ }
+
+ rtl_enable_clock_request(pdev);
+}
+
static void rtl_hw_start_8168(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -3698,7 +3746,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
@@ -3767,6 +3815,10 @@ static void rtl_hw_start_8168(struct net_device *dev)
rtl_hw_start_8168d(ioaddr, pdev);
break;
+ case RTL_GIGA_MAC_VER_28:
+ rtl_hw_start_8168d_4(ioaddr, pdev);
+ break;
+
default:
printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
dev->name, tp->mac_version);
@@ -3808,7 +3860,7 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
};
u8 cfg1;
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(DBG_REG, FIX_NAK_1);
@@ -3829,7 +3881,7 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
@@ -3878,7 +3930,7 @@ static void rtl_hw_start_8101(struct net_device *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
@@ -4179,7 +4231,7 @@ static void rtl8169_tx_timeout(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- rtl8169_hw_reset(tp->mmio_addr);
+ rtl8169_hw_reset(tp);
/* Let's wait a bit while any (async) irq lands on */
rtl8169_schedule_work(dev, rtl8169_reset_task);
@@ -4337,7 +4389,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
struct pci_dev *pdev = tp->pci_dev;
- void __iomem *ioaddr = tp->mmio_addr;
u16 pci_status, pci_cmd;
pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
@@ -4368,13 +4419,15 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
/* The infamous DAC f*ckup only happens at boot time */
if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
+ void __iomem *ioaddr = tp->mmio_addr;
+
netif_info(tp, intr, dev, "disabling PCI DAC\n");
tp->cp_cmd &= ~PCIDAC;
RTL_W16(CPlusCmd, tp->cp_cmd);
dev->features &= ~NETIF_F_HIGHDMA;
}
- rtl8169_hw_reset(ioaddr);
+ rtl8169_hw_reset(tp);
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
@@ -4440,8 +4493,7 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
u32 status = opts1 & RxProtoMask;
if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
- ((status == RxProtoUDP) && !(opts1 & UDPFail)) ||
- ((status == RxProtoIP) && !(opts1 & IPFail)))
+ ((status == RxProtoUDP) && !(opts1 & UDPFail)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
@@ -4588,7 +4640,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
}
/* Work around for rx fifo overflow */
- if (unlikely(status & RxFIFOOver)) {
+ if (unlikely(status & RxFIFOOver) &&
+ (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
netif_stop_queue(dev);
rtl8169_tx_timeout(dev);
break;
@@ -4600,7 +4653,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
}
if (status & LinkChg)
- rtl8169_check_link_status(dev, tp, ioaddr);
+ __rtl8169_check_link_status(dev, tp, ioaddr, true);
/* We need to see the lastest version of tp->intr_mask to
* avoid ignoring an MSI interrupt and having to wait for
@@ -4701,6 +4754,8 @@ static void rtl8169_down(struct net_device *dev)
rtl8169_tx_clear(tp);
rtl8169_rx_clear(tp);
+
+ rtl_pll_power_down(tp);
}
static int rtl8169_close(struct net_device *dev)
@@ -4805,9 +4860,13 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
static void rtl8169_net_suspend(struct net_device *dev)
{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
if (!netif_running(dev))
return;
+ rtl_pll_power_down(tp);
+
netif_device_detach(dev);
netif_stop_queue(dev);
}
@@ -4826,7 +4885,12 @@ static int rtl8169_suspend(struct device *device)
static void __rtl8169_resume(struct net_device *dev)
{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
netif_device_attach(dev);
+
+ rtl_pll_power_up(tp);
+
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
@@ -4890,11 +4954,7 @@ static int rtl8169_runtime_idle(struct device *device)
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- if (!tp->TxDescArray)
- return 0;
-
- rtl8169_check_link_status(dev, tp, tp->mmio_addr);
- return -EBUSY;
+ return tp->TxDescArray ? -EBUSY : 0;
}
static const struct dev_pm_ops rtl8169_pm_ops = {
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index ecc25aab896a..39c17cecb8b9 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -88,14 +88,14 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.27"
+#define DRV_VERSION "2.0.26.28"
/* S2io Driver name & version. */
-static char s2io_driver_name[] = "Neterion";
-static char s2io_driver_version[] = DRV_VERSION;
+static const char s2io_driver_name[] = "Neterion";
+static const char s2io_driver_version[] = DRV_VERSION;
-static int rxd_size[2] = {32, 48};
-static int rxd_count[2] = {127, 85};
+static const int rxd_size[2] = {32, 48};
+static const int rxd_count[2] = {127, 85};
static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
@@ -3598,10 +3598,12 @@ static int s2io_set_swapper(struct s2io_nic *sp)
val64 = readq(&bar0->pif_rd_swapper_fb);
if (val64 != 0x0123456789ABCDEFULL) {
int i = 0;
- u64 value[] = { 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
- 0x8100008181000081ULL, /* FE=1, SE=0 */
- 0x4200004242000042ULL, /* FE=0, SE=1 */
- 0}; /* FE=0, SE=0 */
+ static const u64 value[] = {
+ 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */
+ 0x8100008181000081ULL, /* FE=1, SE=0 */
+ 0x4200004242000042ULL, /* FE=0, SE=1 */
+ 0 /* FE=0, SE=0 */
+ };
while (i < 4) {
writeq(value[i], &bar0->swapper_ctrl);
@@ -3627,10 +3629,12 @@ static int s2io_set_swapper(struct s2io_nic *sp)
if (val64 != valt) {
int i = 0;
- u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
- 0x0081810000818100ULL, /* FE=1, SE=0 */
- 0x0042420000424200ULL, /* FE=0, SE=1 */
- 0}; /* FE=0, SE=0 */
+ static const u64 value[] = {
+ 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */
+ 0x0081810000818100ULL, /* FE=1, SE=0 */
+ 0x0042420000424200ULL, /* FE=0, SE=1 */
+ 0 /* FE=0, SE=0 */
+ };
while (i < 4) {
writeq((value[i] | valr), &bar0->swapper_ctrl);
@@ -5568,30 +5572,27 @@ static void s2io_ethtool_gringparam(struct net_device *dev,
struct s2io_nic *sp = netdev_priv(dev);
int i, tx_desc_count = 0, rx_desc_count = 0;
- if (sp->rxd_mode == RXD_MODE_1)
+ if (sp->rxd_mode == RXD_MODE_1) {
ering->rx_max_pending = MAX_RX_DESC_1;
- else if (sp->rxd_mode == RXD_MODE_3B)
+ ering->rx_jumbo_max_pending = MAX_RX_DESC_1;
+ } else {
ering->rx_max_pending = MAX_RX_DESC_2;
+ ering->rx_jumbo_max_pending = MAX_RX_DESC_2;
+ }
+ ering->rx_mini_max_pending = 0;
ering->tx_max_pending = MAX_TX_DESC;
- for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
- tx_desc_count += sp->config.tx_cfg[i].fifo_len;
- DBG_PRINT(INFO_DBG, "max 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;
- ering->rx_mini_pending = 0;
- if (sp->rxd_mode == RXD_MODE_1)
- ering->rx_jumbo_max_pending = MAX_RX_DESC_1;
- else if (sp->rxd_mode == RXD_MODE_3B)
- ering->rx_jumbo_max_pending = MAX_RX_DESC_2;
ering->rx_jumbo_pending = rx_desc_count;
+ ering->rx_mini_pending = 0;
+
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ tx_desc_count += sp->config.tx_cfg[i].fifo_len;
+ ering->tx_pending = tx_desc_count;
+ DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds);
}
/**
@@ -7692,6 +7693,8 @@ static void s2io_init_pci(struct s2io_nic *sp)
static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
u8 *dev_multiq)
{
+ int i;
+
if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) {
DBG_PRINT(ERR_DBG, "Requested number of tx fifos "
"(%d) not supported\n", tx_fifo_num);
@@ -7750,6 +7753,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n");
rx_ring_mode = 1;
}
+
+ for (i = 0; i < MAX_RX_RINGS; i++)
+ if (rx_ring_sz[i] > MAX_RX_BLOCKS_PER_RING) {
+ DBG_PRINT(ERR_DBG, "Requested rx ring size not "
+ "supported\nDefaulting to %d\n",
+ MAX_RX_BLOCKS_PER_RING);
+ rx_ring_sz[i] = MAX_RX_BLOCKS_PER_RING;
+ }
+
return SUCCESS;
}
@@ -8321,8 +8333,7 @@ mem_alloc_failed:
static void __devexit s2io_rem_nic(struct pci_dev *pdev)
{
- struct net_device *dev =
- (struct net_device *)pci_get_drvdata(pdev);
+ struct net_device *dev = pci_get_drvdata(pdev);
struct s2io_nic *sp;
if (dev == NULL) {
@@ -8330,9 +8341,11 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
return;
}
- flush_scheduled_work();
-
sp = netdev_priv(dev);
+
+ cancel_work_sync(&sp->rst_timer_task);
+ cancel_work_sync(&sp->set_link_task);
+
unregister_netdev(dev);
free_shared_mem(sp);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 00b8614efe48..7d160306b651 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -355,13 +355,12 @@ struct stat_block {
#define FIFO_OTHER_MAX_NUM 1
-#define MAX_RX_DESC_1 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 127 )
-#define MAX_RX_DESC_2 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 )
-#define MAX_RX_DESC_3 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 )
+#define MAX_RX_DESC_1 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 128)
+#define MAX_RX_DESC_2 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 86)
#define MAX_TX_DESC (MAX_AVAILABLE_TXDS)
/* FIFO mappings for all possible number of fifos configured */
-static int fifo_map[][MAX_TX_FIFOS] = {
+static const int fifo_map[][MAX_TX_FIFOS] = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 1, 1, 1, 2, 2},
@@ -372,7 +371,7 @@ static int fifo_map[][MAX_TX_FIFOS] = {
{0, 1, 2, 3, 4, 5, 6, 7},
};
-static u16 fifo_selector[MAX_TX_FIFOS] = {0, 1, 3, 3, 7, 7, 7, 7};
+static const u16 fifo_selector[MAX_TX_FIFOS] = {0, 1, 3, 3, 7, 7, 7, 7};
/* Maintains Per FIFO related information. */
struct tx_fifo_config {
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 417adf372828..76290a8c3c14 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1449,7 +1449,8 @@ static int __devinit sc92031_probe(struct pci_dev *pdev,
dev->irq = pdev->irq;
/* faked with skb_copy_and_csum_dev */
- dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+ dev->features = NETIF_F_SG | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
dev->netdev_ops = &sc92031_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 05df20e47976..002bac743843 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -23,7 +23,6 @@
#include <linux/gfp.h>
#include "net_driver.h"
#include "efx.h"
-#include "mdio_10g.h"
#include "nic.h"
#include "mcdi.h"
@@ -197,7 +196,9 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
static void efx_remove_channels(struct efx_nic *efx);
static void efx_remove_port(struct efx_nic *efx);
+static void efx_init_napi(struct efx_nic *efx);
static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_napi_channel(struct efx_channel *channel);
static void efx_fini_struct(struct efx_nic *efx);
static void efx_start_all(struct efx_nic *efx);
static void efx_stop_all(struct efx_nic *efx);
@@ -335,8 +336,10 @@ void efx_process_channel_now(struct efx_channel *channel)
/* Disable interrupts and wait for ISRs to complete */
efx_nic_disable_interrupts(efx);
- if (efx->legacy_irq)
+ if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
+ efx->legacy_irq_enabled = false;
+ }
if (channel->irq)
synchronize_irq(channel->irq);
@@ -351,6 +354,8 @@ void efx_process_channel_now(struct efx_channel *channel)
efx_channel_processed(channel);
napi_enable(&channel->napi_str);
+ if (efx->legacy_irq)
+ efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
}
@@ -426,6 +431,7 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
*channel = *old_channel;
+ channel->napi_dev = NULL;
memset(&channel->eventq, 0, sizeof(channel->eventq));
rx_queue = &channel->rx_queue;
@@ -455,9 +461,6 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
}
}
- spin_lock_init(&channel->tx_stop_lock);
- atomic_set(&channel->tx_stop_count, 1);
-
rx_queue = &channel->rx_queue;
rx_queue->efx = efx;
setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
@@ -736,9 +739,13 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
if (rc)
goto rollback;
+ efx_init_napi(efx);
+
/* Destroy old channels */
- for (i = 0; i < efx->n_channels; i++)
+ for (i = 0; i < efx->n_channels; i++) {
+ efx_fini_napi_channel(other_channel[i]);
efx_remove_channel(other_channel[i]);
+ }
out:
/* Free unused channel structures */
for (i = 0; i < efx->n_channels; i++)
@@ -910,6 +917,7 @@ static void efx_mac_work(struct work_struct *data)
static int efx_probe_port(struct efx_nic *efx)
{
+ unsigned char *perm_addr;
int rc;
netif_dbg(efx, probe, efx->net_dev, "create port\n");
@@ -923,11 +931,12 @@ static int efx_probe_port(struct efx_nic *efx)
return rc;
/* Sanity check MAC address */
- if (is_valid_ether_addr(efx->mac_address)) {
- memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+ perm_addr = efx->net_dev->perm_addr;
+ if (is_valid_ether_addr(perm_addr)) {
+ memcpy(efx->net_dev->dev_addr, perm_addr, ETH_ALEN);
} else {
netif_err(efx, probe, efx->net_dev, "invalid MAC address %pM\n",
- efx->mac_address);
+ perm_addr);
if (!allow_bad_hwaddr) {
rc = -EINVAL;
goto err;
@@ -1144,6 +1153,9 @@ static int efx_wanted_channels(void)
int count;
int cpu;
+ if (rss_cpus)
+ return rss_cpus;
+
if (unlikely(!zalloc_cpumask_var(&core_mask, GFP_KERNEL))) {
printk(KERN_WARNING
"sfc: RSS disabled due to allocation failure\n");
@@ -1257,27 +1269,18 @@ static void efx_remove_interrupts(struct efx_nic *efx)
efx->legacy_irq = 0;
}
-struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
-{
- unsigned tx_channel_offset =
- separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
- EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
- type >= EFX_TXQ_TYPES);
- return &efx->channel[tx_channel_offset + index]->tx_queue[type];
-}
-
static void efx_set_channels(struct efx_nic *efx)
{
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
- unsigned tx_channel_offset =
+
+ efx->tx_channel_offset =
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
/* Channel pointers were set in efx_init_struct() but we now
* need to clear them for TX queues in any RX-only channels. */
efx_for_each_channel(channel, efx) {
- if (channel->channel - tx_channel_offset >=
+ if (channel->channel - efx->tx_channel_offset >=
efx->n_tx_channels) {
efx_for_each_channel_tx_queue(tx_queue, channel)
tx_queue->channel = NULL;
@@ -1394,12 +1397,14 @@ static void efx_start_all(struct efx_nic *efx)
* restart the transmit interface early so the watchdog timer stops */
efx_start_port(efx);
- efx_for_each_channel(channel, efx) {
- if (efx_dev_registered(efx))
- efx_wake_queue(channel);
+ if (efx_dev_registered(efx))
+ netif_tx_wake_all_queues(efx->net_dev);
+
+ efx_for_each_channel(channel, efx)
efx_start_channel(channel);
- }
+ if (efx->legacy_irq)
+ efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
/* Switch to event based MCDI completions after enabling interrupts.
@@ -1460,8 +1465,10 @@ static void efx_stop_all(struct efx_nic *efx)
/* Disable interrupts and wait for ISR to complete */
efx_nic_disable_interrupts(efx);
- if (efx->legacy_irq)
+ if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
+ efx->legacy_irq_enabled = false;
+ }
efx_for_each_channel(channel, efx) {
if (channel->irq)
synchronize_irq(channel->irq);
@@ -1482,9 +1489,7 @@ static void efx_stop_all(struct efx_nic *efx)
/* Stop the kernel transmit interface late, so the watchdog
* timer isn't ticking over the flush */
if (efx_dev_registered(efx)) {
- struct efx_channel *channel;
- efx_for_each_channel(channel, efx)
- efx_stop_queue(channel);
+ netif_tx_stop_all_queues(efx->net_dev);
netif_tx_lock_bh(efx->net_dev);
netif_tx_unlock_bh(efx->net_dev);
}
@@ -1593,7 +1598,7 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
*
**************************************************************************/
-static int efx_init_napi(struct efx_nic *efx)
+static void efx_init_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
@@ -1602,18 +1607,21 @@ static int efx_init_napi(struct efx_nic *efx)
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
}
- return 0;
+}
+
+static void efx_fini_napi_channel(struct efx_channel *channel)
+{
+ if (channel->napi_dev)
+ netif_napi_del(&channel->napi_str);
+ channel->napi_dev = NULL;
}
static void efx_fini_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
- efx_for_each_channel(channel, efx) {
- if (channel->napi_dev)
- netif_napi_del(&channel->napi_str);
- channel->napi_dev = NULL;
- }
+ efx_for_each_channel(channel, efx)
+ efx_fini_napi_channel(channel);
}
/**************************************************************************
@@ -1877,6 +1885,7 @@ static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL);
static int efx_register_netdev(struct efx_nic *efx)
{
struct net_device *net_dev = efx->net_dev;
+ struct efx_channel *channel;
int rc;
net_dev->watchdog_timeo = 5 * HZ;
@@ -1899,6 +1908,14 @@ static int efx_register_netdev(struct efx_nic *efx)
if (rc)
goto fail_locked;
+ efx_for_each_channel(channel, efx) {
+ struct efx_tx_queue *tx_queue;
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ tx_queue->core_txq = netdev_get_tx_queue(
+ efx->net_dev, tx_queue->queue / EFX_TXQ_TYPES);
+ }
+ }
+
/* Always start with carrier off; PHY events will detect the link */
netif_carrier_off(efx->net_dev);
@@ -1962,7 +1979,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
efx_stop_all(efx);
mutex_lock(&efx->mac_lock);
- mutex_lock(&efx->spi_lock);
efx_fini_channels(efx);
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
@@ -2004,7 +2020,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx_init_channels(efx);
efx_restore_filters(efx);
- mutex_unlock(&efx->spi_lock);
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
@@ -2014,7 +2029,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
fail:
efx->port_initialized = false;
- mutex_unlock(&efx->spi_lock);
mutex_unlock(&efx->mac_lock);
return rc;
@@ -2202,8 +2216,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
/* Initialise common structures */
memset(efx, 0, sizeof(*efx));
spin_lock_init(&efx->biu_lock);
- mutex_init(&efx->mdio_lock);
- mutex_init(&efx->spi_lock);
#ifdef CONFIG_SFC_MTD
INIT_LIST_HEAD(&efx->mtd_list);
#endif
@@ -2335,9 +2347,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
if (rc)
goto fail1;
- rc = efx_init_napi(efx);
- if (rc)
- goto fail2;
+ efx_init_napi(efx);
rc = efx->type->init(efx);
if (rc) {
@@ -2368,7 +2378,6 @@ static int efx_pci_probe_main(struct efx_nic *efx)
efx->type->fini(efx);
fail3:
efx_fini_napi(efx);
- fail2:
efx_remove_all(efx);
fail1:
return rc;
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 10a1bf40da96..d43a7e5212b1 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -36,8 +36,6 @@ efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
extern netdev_tx_t
efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
-extern void efx_stop_queue(struct efx_channel *channel);
-extern void efx_wake_queue(struct efx_channel *channel);
/* RX */
extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
@@ -74,9 +72,8 @@ extern int efx_filter_insert_filter(struct efx_nic *efx,
bool replace);
extern int efx_filter_remove_filter(struct efx_nic *efx,
struct efx_filter_spec *spec);
-extern void efx_filter_table_clear(struct efx_nic *efx,
- enum efx_filter_table_id table_id,
- enum efx_filter_priority priority);
+extern void efx_filter_clear_rx(struct efx_nic *efx,
+ enum efx_filter_priority priority);
/* Channels */
extern void efx_process_channel_now(struct efx_channel *channel);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index edb9d16b8b47..0e8bb19ed60d 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -11,14 +11,13 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
+#include <linux/in.h>
#include "net_driver.h"
#include "workarounds.h"
#include "selftest.h"
#include "efx.h"
#include "filter.h"
#include "nic.h"
-#include "spi.h"
-#include "mdio_10g.h"
struct ethtool_string {
char name[ETH_GSTRING_LEN];
@@ -560,12 +559,8 @@ static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
if (rc)
return rc;
- if (!(data & ETH_FLAG_NTUPLE)) {
- efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP,
- EFX_FILTER_PRI_MANUAL);
- efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC,
- EFX_FILTER_PRI_MANUAL);
- }
+ if (!(data & ETH_FLAG_NTUPLE))
+ efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
return 0;
}
@@ -584,6 +579,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
goto fail1;
}
+ netif_info(efx, drv, efx->net_dev, "starting %sline testing\n",
+ (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
+
/* We need rx buffers and interrupts. */
already_up = (efx->net_dev->flags & IFF_UP);
if (!already_up) {
@@ -602,9 +600,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
if (!already_up)
dev_close(efx->net_dev);
- netif_dbg(efx, drv, efx->net_dev, "%s %sline self-tests\n",
- rc == 0 ? "passed" : "failed",
- (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
+ netif_info(efx, drv, efx->net_dev, "%s %sline self-tests\n",
+ rc == 0 ? "passed" : "failed",
+ (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
fail2:
fail1:
@@ -622,68 +620,6 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev)
return mdio45_nway_restart(&efx->mdio);
}
-static u32 efx_ethtool_get_link(struct net_device *net_dev)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
-
- return efx->link_state.up;
-}
-
-static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_spi_device *spi = efx->spi_eeprom;
-
- if (!spi)
- return 0;
- return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) -
- min(spi->size, EFX_EEPROM_BOOTCONFIG_START);
-}
-
-static int efx_ethtool_get_eeprom(struct net_device *net_dev,
- struct ethtool_eeprom *eeprom, u8 *buf)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_spi_device *spi = efx->spi_eeprom;
- size_t len;
- int rc;
-
- rc = mutex_lock_interruptible(&efx->spi_lock);
- if (rc)
- return rc;
- rc = falcon_spi_read(efx, spi,
- eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
- eeprom->len, &len, buf);
- mutex_unlock(&efx->spi_lock);
-
- eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
- eeprom->len = len;
- return rc;
-}
-
-static int efx_ethtool_set_eeprom(struct net_device *net_dev,
- struct ethtool_eeprom *eeprom, u8 *buf)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_spi_device *spi = efx->spi_eeprom;
- size_t len;
- int rc;
-
- if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
- return -EINVAL;
-
- rc = mutex_lock_interruptible(&efx->spi_lock);
- if (rc)
- return rc;
- rc = falcon_spi_write(efx, spi,
- eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
- eeprom->len, &len, buf);
- mutex_unlock(&efx->spi_lock);
-
- eeprom->len = len;
- return rc;
-}
-
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce)
{
@@ -978,6 +914,7 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec;
struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec;
struct efx_filter_spec filter;
+ int rc;
/* Range-check action */
if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR ||
@@ -987,9 +924,16 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
if (~ntuple->fs.data_mask)
return -EINVAL;
+ efx_filter_init_rx(&filter, EFX_FILTER_PRI_MANUAL, 0,
+ (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) ?
+ 0xfff : ntuple->fs.action);
+
switch (ntuple->fs.flow_type) {
case TCP_V4_FLOW:
- case UDP_V4_FLOW:
+ case UDP_V4_FLOW: {
+ u8 proto = (ntuple->fs.flow_type == TCP_V4_FLOW ?
+ IPPROTO_TCP : IPPROTO_UDP);
+
/* Must match all of destination, */
if (ip_mask->ip4dst | ip_mask->pdst)
return -EINVAL;
@@ -1001,7 +945,22 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
/* and nothing else */
if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask)
return -EINVAL;
+
+ if (!ip_mask->ip4src)
+ rc = efx_filter_set_ipv4_full(&filter, proto,
+ ip_entry->ip4dst,
+ ip_entry->pdst,
+ ip_entry->ip4src,
+ ip_entry->psrc);
+ else
+ rc = efx_filter_set_ipv4_local(&filter, proto,
+ ip_entry->ip4dst,
+ ip_entry->pdst);
+ if (rc)
+ return rc;
break;
+ }
+
case ETHER_FLOW:
/* Must match all of destination, */
if (!is_zero_ether_addr(mac_mask->h_dest))
@@ -1014,58 +973,24 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
if (!is_broadcast_ether_addr(mac_mask->h_source) ||
mac_mask->h_proto != htons(0xffff))
return -EINVAL;
+
+ rc = efx_filter_set_eth_local(
+ &filter,
+ (ntuple->fs.vlan_tag_mask == 0xf000) ?
+ ntuple->fs.vlan_tag : EFX_FILTER_VID_UNSPEC,
+ mac_entry->h_dest);
+ if (rc)
+ return rc;
break;
+
default:
return -EINVAL;
}
- filter.priority = EFX_FILTER_PRI_MANUAL;
- filter.flags = 0;
-
- switch (ntuple->fs.flow_type) {
- case TCP_V4_FLOW:
- if (!ip_mask->ip4src)
- efx_filter_set_rx_tcp_full(&filter,
- htonl(ip_entry->ip4src),
- htons(ip_entry->psrc),
- htonl(ip_entry->ip4dst),
- htons(ip_entry->pdst));
- else
- efx_filter_set_rx_tcp_wild(&filter,
- htonl(ip_entry->ip4dst),
- htons(ip_entry->pdst));
- break;
- case UDP_V4_FLOW:
- if (!ip_mask->ip4src)
- efx_filter_set_rx_udp_full(&filter,
- htonl(ip_entry->ip4src),
- htons(ip_entry->psrc),
- htonl(ip_entry->ip4dst),
- htons(ip_entry->pdst));
- else
- efx_filter_set_rx_udp_wild(&filter,
- htonl(ip_entry->ip4dst),
- htons(ip_entry->pdst));
- break;
- case ETHER_FLOW:
- if (ntuple->fs.vlan_tag_mask == 0xf000)
- efx_filter_set_rx_mac_full(&filter,
- ntuple->fs.vlan_tag & 0xfff,
- mac_entry->h_dest);
- else
- efx_filter_set_rx_mac_wild(&filter, mac_entry->h_dest);
- break;
- }
-
- if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) {
+ if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR)
return efx_filter_remove_filter(efx, &filter);
- } else {
- if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
- filter.dmaq_id = 0xfff;
- else
- filter.dmaq_id = ntuple->fs.action;
+ else
return efx_filter_insert_filter(efx, &filter, true);
- }
}
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
@@ -1115,10 +1040,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_msglevel = efx_ethtool_get_msglevel,
.set_msglevel = efx_ethtool_set_msglevel,
.nway_reset = efx_ethtool_nway_reset,
- .get_link = efx_ethtool_get_link,
- .get_eeprom_len = efx_ethtool_get_eeprom_len,
- .get_eeprom = efx_ethtool_get_eeprom,
- .set_eeprom = efx_ethtool_set_eeprom,
+ .get_link = ethtool_op_get_link,
.get_coalesce = efx_ethtool_get_coalesce,
.set_coalesce = efx_ethtool_set_coalesce,
.get_ringparam = efx_ethtool_get_ringparam,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 267019bb2b15..61ddd2c6e750 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -24,7 +24,6 @@
#include "nic.h"
#include "regs.h"
#include "io.h"
-#include "mdio_10g.h"
#include "phy.h"
#include "workarounds.h"
@@ -255,7 +254,6 @@ int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi,
/* Input validation */
if (len > FALCON_SPI_MAX_LEN)
return -EINVAL;
- BUG_ON(!mutex_is_locked(&efx->spi_lock));
/* Check that previous command is not still running */
rc = falcon_spi_poll(efx);
@@ -719,6 +717,7 @@ static int falcon_mdio_write(struct net_device *net_dev,
int prtad, int devad, u16 addr, u16 value)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
int rc;
@@ -726,7 +725,7 @@ static int falcon_mdio_write(struct net_device *net_dev,
"writing MDIO %d register %d.%d with 0x%04x\n",
prtad, devad, addr, value);
- mutex_lock(&efx->mdio_lock);
+ mutex_lock(&nic_data->mdio_lock);
/* Check MDIO not currently being accessed */
rc = falcon_gmii_wait(efx);
@@ -762,7 +761,7 @@ static int falcon_mdio_write(struct net_device *net_dev,
}
out:
- mutex_unlock(&efx->mdio_lock);
+ mutex_unlock(&nic_data->mdio_lock);
return rc;
}
@@ -771,10 +770,11 @@ static int falcon_mdio_read(struct net_device *net_dev,
int prtad, int devad, u16 addr)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
int rc;
- mutex_lock(&efx->mdio_lock);
+ mutex_lock(&nic_data->mdio_lock);
/* Check MDIO not currently being accessed */
rc = falcon_gmii_wait(efx);
@@ -813,7 +813,7 @@ static int falcon_mdio_read(struct net_device *net_dev,
}
out:
- mutex_unlock(&efx->mdio_lock);
+ mutex_unlock(&nic_data->mdio_lock);
return rc;
}
@@ -841,6 +841,7 @@ static int falcon_probe_port(struct efx_nic *efx)
}
/* Fill out MDIO structure and loopback modes */
+ mutex_init(&nic_data->mdio_lock);
efx->mdio.mdio_read = falcon_mdio_read;
efx->mdio.mdio_write = falcon_mdio_write;
rc = efx->phy_op->probe(efx);
@@ -880,6 +881,41 @@ static void falcon_remove_port(struct efx_nic *efx)
efx_nic_free_buffer(efx, &efx->stats_buffer);
}
+/* Global events are basically PHY events */
+static bool
+falcon_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR))
+ /* Ignored */
+ return true;
+
+ if ((efx_nic_rev(efx) == EFX_REV_FALCON_B0) &&
+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
+ nic_data->xmac_poll_required = true;
+ return true;
+ }
+
+ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
+ EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
+ netif_err(efx, rx_err, efx->net_dev,
+ "channel %d seen global RX_RESET event. Resetting.\n",
+ channel->channel);
+
+ atomic_inc(&efx->rx_reset);
+ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+ return true;
+ }
+
+ return false;
+}
+
/**************************************************************************
*
* Falcon test code
@@ -889,6 +925,7 @@ static void falcon_remove_port(struct efx_nic *efx)
static int
falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
struct falcon_nvconfig *nvconfig;
struct efx_spi_device *spi;
void *region;
@@ -896,8 +933,11 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
__le16 *word, *limit;
u32 csum;
- spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
- if (!spi)
+ if (efx_spi_present(&nic_data->spi_flash))
+ spi = &nic_data->spi_flash;
+ else if (efx_spi_present(&nic_data->spi_eeprom))
+ spi = &nic_data->spi_eeprom;
+ else
return -EINVAL;
region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
@@ -905,12 +945,13 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
return -ENOMEM;
nvconfig = region + FALCON_NVCONFIG_OFFSET;
- mutex_lock(&efx->spi_lock);
+ mutex_lock(&nic_data->spi_lock);
rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region);
- mutex_unlock(&efx->spi_lock);
+ mutex_unlock(&nic_data->spi_lock);
if (rc) {
netif_err(efx, hw, efx->net_dev, "Failed to read %s\n",
- efx->spi_flash ? "flash" : "EEPROM");
+ efx_spi_present(&nic_data->spi_flash) ?
+ "flash" : "EEPROM");
rc = -EIO;
goto out;
}
@@ -1012,7 +1053,7 @@ static int falcon_b0_test_registers(struct efx_nic *efx)
/* Resets NIC to known state. This routine must be called in process
* context and is allowed to sleep. */
-static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
{
struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t glb_ctl_reg_ker;
@@ -1066,22 +1107,9 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* Restore PCI configuration if needed */
if (method == RESET_TYPE_WORLD) {
- if (efx_nic_is_dual_func(efx)) {
- rc = pci_restore_state(nic_data->pci_dev2);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for "
- "the secondary function\n");
- goto fail3;
- }
- }
- rc = pci_restore_state(efx->pci_dev);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for the "
- "primary function\n");
- goto fail4;
- }
+ if (efx_nic_is_dual_func(efx))
+ pci_restore_state(nic_data->pci_dev2);
+ pci_restore_state(efx->pci_dev);
netif_dbg(efx, drv, efx->net_dev,
"successfully restored PCI config\n");
}
@@ -1092,7 +1120,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
rc = -ETIMEDOUT;
netif_err(efx, hw, efx->net_dev,
"timed out waiting for hardware reset\n");
- goto fail5;
+ goto fail3;
}
netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
@@ -1100,11 +1128,21 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* pci_save_state() and pci_restore_state() MUST be called in pairs */
fail2:
-fail3:
pci_restore_state(efx->pci_dev);
fail1:
-fail4:
-fail5:
+fail3:
+ return rc;
+}
+
+static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ int rc;
+
+ mutex_lock(&nic_data->spi_lock);
+ rc = __falcon_reset_hw(efx, method);
+ mutex_unlock(&nic_data->spi_lock);
+
return rc;
}
@@ -1189,16 +1227,11 @@ static int falcon_reset_sram(struct efx_nic *efx)
return -ETIMEDOUT;
}
-static int falcon_spi_device_init(struct efx_nic *efx,
- struct efx_spi_device **spi_device_ret,
+static void falcon_spi_device_init(struct efx_nic *efx,
+ struct efx_spi_device *spi_device,
unsigned int device_id, u32 device_type)
{
- struct efx_spi_device *spi_device;
-
if (device_type != 0) {
- spi_device = kzalloc(sizeof(*spi_device), GFP_KERNEL);
- if (!spi_device)
- return -ENOMEM;
spi_device->device_id = device_id;
spi_device->size =
1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
@@ -1215,27 +1248,15 @@ static int falcon_spi_device_init(struct efx_nic *efx,
1 << SPI_DEV_TYPE_FIELD(device_type,
SPI_DEV_TYPE_BLOCK_SIZE);
} else {
- spi_device = NULL;
+ spi_device->size = 0;
}
-
- kfree(*spi_device_ret);
- *spi_device_ret = spi_device;
- return 0;
-}
-
-static void falcon_remove_spi_devices(struct efx_nic *efx)
-{
- kfree(efx->spi_eeprom);
- efx->spi_eeprom = NULL;
- kfree(efx->spi_flash);
- efx->spi_flash = NULL;
}
/* Extract non-volatile configuration */
static int falcon_probe_nvconfig(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
struct falcon_nvconfig *nvconfig;
- int board_rev;
int rc;
nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
@@ -1243,55 +1264,32 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
return -ENOMEM;
rc = falcon_read_nvram(efx, nvconfig);
- if (rc == -EINVAL) {
- netif_err(efx, probe, efx->net_dev,
- "NVRAM is invalid therefore using defaults\n");
- efx->phy_type = PHY_TYPE_NONE;
- efx->mdio.prtad = MDIO_PRTAD_NONE;
- board_rev = 0;
- rc = 0;
- } else if (rc) {
- goto fail1;
- } else {
- struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
- struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
-
- efx->phy_type = v2->port0_phy_type;
- efx->mdio.prtad = v2->port0_phy_addr;
- board_rev = le16_to_cpu(v2->board_revision);
-
- if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
- rc = falcon_spi_device_init(
- efx, &efx->spi_flash, FFE_AB_SPI_DEVICE_FLASH,
- le32_to_cpu(v3->spi_device_type
- [FFE_AB_SPI_DEVICE_FLASH]));
- if (rc)
- goto fail2;
- rc = falcon_spi_device_init(
- efx, &efx->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM,
- le32_to_cpu(v3->spi_device_type
- [FFE_AB_SPI_DEVICE_EEPROM]));
- if (rc)
- goto fail2;
- }
+ if (rc)
+ goto out;
+
+ efx->phy_type = nvconfig->board_v2.port0_phy_type;
+ efx->mdio.prtad = nvconfig->board_v2.port0_phy_addr;
+
+ if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
+ falcon_spi_device_init(
+ efx, &nic_data->spi_flash, FFE_AB_SPI_DEVICE_FLASH,
+ le32_to_cpu(nvconfig->board_v3
+ .spi_device_type[FFE_AB_SPI_DEVICE_FLASH]));
+ falcon_spi_device_init(
+ efx, &nic_data->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM,
+ le32_to_cpu(nvconfig->board_v3
+ .spi_device_type[FFE_AB_SPI_DEVICE_EEPROM]));
}
/* Read the MAC addresses */
- memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
+ memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN);
netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
efx->phy_type, efx->mdio.prtad);
- rc = falcon_probe_board(efx, board_rev);
- if (rc)
- goto fail2;
-
- kfree(nvconfig);
- return 0;
-
- fail2:
- falcon_remove_spi_devices(efx);
- fail1:
+ rc = falcon_probe_board(efx,
+ le16_to_cpu(nvconfig->board_v2.board_revision));
+out:
kfree(nvconfig);
return rc;
}
@@ -1299,6 +1297,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
/* Probe all SPI devices on the NIC */
static void falcon_probe_spi_devices(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
int boot_dev;
@@ -1327,12 +1326,14 @@ static void falcon_probe_spi_devices(struct efx_nic *efx)
efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
}
+ mutex_init(&nic_data->spi_lock);
+
if (boot_dev == FFE_AB_SPI_DEVICE_FLASH)
- falcon_spi_device_init(efx, &efx->spi_flash,
+ falcon_spi_device_init(efx, &nic_data->spi_flash,
FFE_AB_SPI_DEVICE_FLASH,
default_flash_type);
if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM)
- falcon_spi_device_init(efx, &efx->spi_eeprom,
+ falcon_spi_device_init(efx, &nic_data->spi_eeprom,
FFE_AB_SPI_DEVICE_EEPROM,
large_eeprom_type);
}
@@ -1397,7 +1398,7 @@ static int falcon_probe_nic(struct efx_nic *efx)
}
/* Now we can reset the NIC */
- rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+ rc = __falcon_reset_hw(efx, RESET_TYPE_ALL);
if (rc) {
netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
goto fail3;
@@ -1419,8 +1420,11 @@ static int falcon_probe_nic(struct efx_nic *efx)
/* Read in the non-volatile configuration */
rc = falcon_probe_nvconfig(efx);
- if (rc)
+ if (rc) {
+ if (rc == -EINVAL)
+ netif_err(efx, probe, efx->net_dev, "NVRAM is invalid\n");
goto fail5;
+ }
/* Initialise I2C adapter */
board = falcon_board(efx);
@@ -1452,7 +1456,6 @@ static int falcon_probe_nic(struct efx_nic *efx)
BUG_ON(i2c_del_adapter(&board->i2c_adap));
memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
fail5:
- falcon_remove_spi_devices(efx);
efx_nic_free_buffer(efx, &efx->irq_status);
fail4:
fail3:
@@ -1606,10 +1609,9 @@ static void falcon_remove_nic(struct efx_nic *efx)
BUG_ON(rc);
memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
- falcon_remove_spi_devices(efx);
efx_nic_free_buffer(efx, &efx->irq_status);
- falcon_reset_hw(efx, RESET_TYPE_ALL);
+ __falcon_reset_hw(efx, RESET_TYPE_ALL);
/* Release the second function after the reset */
if (nic_data->pci_dev2) {
@@ -1720,6 +1722,7 @@ struct efx_nic_type falcon_a1_nic_type = {
.reset = falcon_reset_hw,
.probe_port = falcon_probe_port,
.remove_port = falcon_remove_port,
+ .handle_global_event = falcon_handle_global_event,
.prepare_flush = falcon_prepare_flush,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
@@ -1760,6 +1763,7 @@ struct efx_nic_type falcon_b0_nic_type = {
.reset = falcon_reset_hw,
.probe_port = falcon_probe_port,
.remove_port = falcon_remove_port,
+ .handle_global_event = falcon_handle_global_event,
.prepare_flush = falcon_prepare_flush,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index cfc6a5b5a477..2dd16f0b3ced 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -13,8 +13,6 @@
#include "phy.h"
#include "efx.h"
#include "nic.h"
-#include "regs.h"
-#include "io.h"
#include "workarounds.h"
/* Macros for unpacking the board revision */
@@ -30,17 +28,28 @@
#define FALCON_BOARD_SFN4112F 0x52
/* Board temperature is about 15°C above ambient when air flow is
- * limited. */
+ * limited. The maximum acceptable ambient temperature varies
+ * depending on the PHY specifications but the critical temperature
+ * above which we should shut down to avoid damage is 80°C. */
#define FALCON_BOARD_TEMP_BIAS 15
+#define FALCON_BOARD_TEMP_CRIT (80 + FALCON_BOARD_TEMP_BIAS)
/* SFC4000 datasheet says: 'The maximum permitted junction temperature
* is 125°C; the thermal design of the environment for the SFC4000
* should aim to keep this well below 100°C.' */
+#define FALCON_JUNC_TEMP_MIN 0
#define FALCON_JUNC_TEMP_MAX 90
+#define FALCON_JUNC_TEMP_CRIT 125
/*****************************************************************************
* Support for LM87 sensor chip used on several boards
*/
+#define LM87_REG_TEMP_HW_INT_LOCK 0x13
+#define LM87_REG_TEMP_HW_EXT_LOCK 0x14
+#define LM87_REG_TEMP_HW_INT 0x17
+#define LM87_REG_TEMP_HW_EXT 0x18
+#define LM87_REG_TEMP_EXT1 0x26
+#define LM87_REG_TEMP_INT 0x27
#define LM87_REG_ALARMS1 0x41
#define LM87_REG_ALARMS2 0x42
#define LM87_IN_LIMITS(nr, _min, _max) \
@@ -57,6 +66,27 @@
#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
+static int efx_poke_lm87(struct i2c_client *client, const u8 *reg_values)
+{
+ while (*reg_values) {
+ u8 reg = *reg_values++;
+ u8 value = *reg_values++;
+ int rc = i2c_smbus_write_byte_data(client, reg, value);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+static const u8 falcon_lm87_common_regs[] = {
+ LM87_REG_TEMP_HW_INT_LOCK, FALCON_BOARD_TEMP_CRIT,
+ LM87_REG_TEMP_HW_INT, FALCON_BOARD_TEMP_CRIT,
+ LM87_TEMP_EXT1_LIMITS(FALCON_JUNC_TEMP_MIN, FALCON_JUNC_TEMP_MAX),
+ LM87_REG_TEMP_HW_EXT_LOCK, FALCON_JUNC_TEMP_CRIT,
+ LM87_REG_TEMP_HW_EXT, FALCON_JUNC_TEMP_CRIT,
+ 0
+};
+
static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
const u8 *reg_values)
{
@@ -67,13 +97,16 @@ static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
if (!client)
return -EIO;
- while (*reg_values) {
- u8 reg = *reg_values++;
- u8 value = *reg_values++;
- rc = i2c_smbus_write_byte_data(client, reg, value);
- if (rc)
- goto err;
- }
+ /* Read-to-clear alarm/interrupt status */
+ i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+ i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+
+ rc = efx_poke_lm87(client, reg_values);
+ if (rc)
+ goto err;
+ rc = efx_poke_lm87(client, falcon_lm87_common_regs);
+ if (rc)
+ goto err;
board->hwmon_client = client;
return 0;
@@ -91,36 +124,56 @@ static void efx_fini_lm87(struct efx_nic *efx)
static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
{
struct i2c_client *client = falcon_board(efx)->hwmon_client;
- s32 alarms1, alarms2;
+ bool temp_crit, elec_fault, is_failure;
+ u16 alarms;
+ s32 reg;
/* If link is up then do not monitor temperature */
if (EFX_WORKAROUND_7884(efx) && efx->link_state.up)
return 0;
- alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
- alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
- if (alarms1 < 0)
- return alarms1;
- if (alarms2 < 0)
- return alarms2;
- alarms1 &= mask;
- alarms2 &= mask >> 8;
- if (alarms1 || alarms2) {
+ reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+ if (reg < 0)
+ return reg;
+ alarms = reg;
+ reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+ if (reg < 0)
+ return reg;
+ alarms |= reg << 8;
+ alarms &= mask;
+
+ temp_crit = false;
+ if (alarms & LM87_ALARM_TEMP_INT) {
+ reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_INT);
+ if (reg < 0)
+ return reg;
+ if (reg > FALCON_BOARD_TEMP_CRIT)
+ temp_crit = true;
+ }
+ if (alarms & LM87_ALARM_TEMP_EXT1) {
+ reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_EXT1);
+ if (reg < 0)
+ return reg;
+ if (reg > FALCON_JUNC_TEMP_CRIT)
+ temp_crit = true;
+ }
+ elec_fault = alarms & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1);
+ is_failure = temp_crit || elec_fault;
+
+ if (alarms)
netif_err(efx, hw, efx->net_dev,
- "LM87 detected a hardware failure (status %02x:%02x)"
- "%s%s%s\n",
- alarms1, alarms2,
- (alarms1 & LM87_ALARM_TEMP_INT) ?
+ "LM87 detected a hardware %s (status %02x:%02x)"
+ "%s%s%s%s\n",
+ is_failure ? "failure" : "problem",
+ alarms & 0xff, alarms >> 8,
+ (alarms & LM87_ALARM_TEMP_INT) ?
"; board is overheating" : "",
- (alarms1 & LM87_ALARM_TEMP_EXT1) ?
+ (alarms & LM87_ALARM_TEMP_EXT1) ?
"; controller is overheating" : "",
- (alarms1 & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1)
- || alarms2) ?
- "; electrical fault" : "");
- return -ERANGE;
- }
+ temp_crit ? "; reached critical temperature" : "",
+ elec_fault ? "; electrical fault" : "");
- return 0;
+ return is_failure ? -ERANGE : 0;
}
#else /* !CONFIG_SENSORS_LM87 */
@@ -325,7 +378,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
new_mode = old_mode & ~PHY_MODE_SPECIAL;
else
new_mode = PHY_MODE_SPECIAL;
- if (old_mode == new_mode) {
+ if (!((old_mode ^ new_mode) & PHY_MODE_SPECIAL)) {
err = 0;
} else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
err = -EBUSY;
@@ -362,10 +415,11 @@ static void sfe4001_fini(struct efx_nic *efx)
static int sfe4001_check_hw(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
s32 status;
/* If XAUI link is up then do not monitor */
- if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
+ if (EFX_WORKAROUND_7884(efx) && !nic_data->xmac_poll_required)
return 0;
/* Check the powered status of the PHY. Lack of power implies that
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index b31f595ebb5b..b49e84394641 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -16,7 +16,6 @@
#include "io.h"
#include "mac.h"
#include "mdio_10g.h"
-#include "phy.h"
#include "workarounds.h"
/**************************************************************************
@@ -88,6 +87,7 @@ int falcon_reset_xaui(struct efx_nic *efx)
static void falcon_ack_status_intr(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
@@ -99,7 +99,7 @@ static void falcon_ack_status_intr(struct efx_nic *efx)
/* We can only use this interrupt to signal the negative edge of
* xaui_align [we have to poll the positive edge]. */
- if (efx->xmac_poll_required)
+ if (nic_data->xmac_poll_required)
return;
efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
@@ -277,12 +277,14 @@ static bool falcon_xmac_check_fault(struct efx_nic *efx)
static int falcon_reconfigure_xmac(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
falcon_reconfigure_xgxs_core(efx);
falcon_reconfigure_xmac_core(efx);
falcon_reconfigure_mac_wrapper(efx);
- efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
+ nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
falcon_ack_status_intr(efx);
return 0;
@@ -350,11 +352,13 @@ static void falcon_update_stats_xmac(struct efx_nic *efx)
void falcon_poll_xmac(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up ||
- !efx->xmac_poll_required)
+ !nic_data->xmac_poll_required)
return;
- efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
+ nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
falcon_ack_status_intr(efx);
}
diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c
index 52cb6082b910..d4722c41c4ce 100644
--- a/drivers/net/sfc/filter.c
+++ b/drivers/net/sfc/filter.c
@@ -7,6 +7,7 @@
* by the Free Software Foundation, incorporated herein by reference.
*/
+#include <linux/in.h>
#include "efx.h"
#include "filter.h"
#include "io.h"
@@ -26,19 +27,26 @@
*/
#define FILTER_CTL_SRCH_MAX 200
+enum efx_filter_table_id {
+ EFX_FILTER_TABLE_RX_IP = 0,
+ EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_TABLE_COUNT,
+};
+
struct efx_filter_table {
+ enum efx_filter_table_id id;
u32 offset; /* address of table relative to BAR */
unsigned size; /* number of entries */
unsigned step; /* step between entries */
unsigned used; /* number currently used */
unsigned long *used_bitmap;
struct efx_filter_spec *spec;
+ unsigned search_depth[EFX_FILTER_TYPE_COUNT];
};
struct efx_filter_state {
spinlock_t lock;
struct efx_filter_table table[EFX_FILTER_TABLE_COUNT];
- unsigned search_depth[EFX_FILTER_TYPE_COUNT];
};
/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
@@ -65,68 +73,203 @@ static u16 efx_filter_increment(u32 key)
}
static enum efx_filter_table_id
-efx_filter_type_table_id(enum efx_filter_type type)
+efx_filter_spec_table_id(const struct efx_filter_spec *spec)
+{
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_TCP_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_TCP_WILD >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2));
+ EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC);
+ return spec->type >> 2;
+}
+
+static struct efx_filter_table *
+efx_filter_spec_table(struct efx_filter_state *state,
+ const struct efx_filter_spec *spec)
{
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_FULL >> 2));
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_WILD >> 2));
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_FULL >> 2));
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_WILD >> 2));
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_FULL >> 2));
- BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_WILD >> 2));
- return type >> 2;
+ if (spec->type == EFX_FILTER_UNSPEC)
+ return NULL;
+ else
+ return &state->table[efx_filter_spec_table_id(spec)];
}
-static void
-efx_filter_table_reset_search_depth(struct efx_filter_state *state,
- enum efx_filter_table_id table_id)
+static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
{
- memset(state->search_depth + (table_id << 2), 0,
- sizeof(state->search_depth[0]) << 2);
+ memset(table->search_depth, 0, sizeof(table->search_depth));
}
static void efx_filter_push_rx_limits(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
+ struct efx_filter_table *table;
efx_oword_t filter_ctl;
efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
+ table = &state->table[EFX_FILTER_TABLE_RX_IP];
EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_TCP_FULL] +
+ table->search_depth[EFX_FILTER_TCP_FULL] +
FILTER_CTL_SRCH_FUDGE_FULL);
EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_TCP_WILD] +
+ table->search_depth[EFX_FILTER_TCP_WILD] +
FILTER_CTL_SRCH_FUDGE_WILD);
EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_UDP_FULL] +
+ table->search_depth[EFX_FILTER_UDP_FULL] +
FILTER_CTL_SRCH_FUDGE_FULL);
EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_UDP_WILD] +
+ table->search_depth[EFX_FILTER_UDP_WILD] +
FILTER_CTL_SRCH_FUDGE_WILD);
- if (state->table[EFX_FILTER_TABLE_RX_MAC].size) {
+ table = &state->table[EFX_FILTER_TABLE_RX_MAC];
+ if (table->size) {
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_MAC_FULL] +
+ table->search_depth[EFX_FILTER_MAC_FULL] +
FILTER_CTL_SRCH_FUDGE_FULL);
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
- state->search_depth[EFX_FILTER_RX_MAC_WILD] +
+ table->search_depth[EFX_FILTER_MAC_WILD] +
FILTER_CTL_SRCH_FUDGE_WILD);
}
efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
}
+static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec,
+ __be32 host1, __be16 port1,
+ __be32 host2, __be16 port2)
+{
+ spec->data[0] = ntohl(host1) << 16 | ntohs(port1);
+ spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16;
+ spec->data[2] = ntohl(host2);
+}
+
+/**
+ * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port
+ * @spec: Specification to initialise
+ * @proto: Transport layer protocol number
+ * @host: Local host address (network byte order)
+ * @port: Local port (network byte order)
+ */
+int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
+ __be32 host, __be16 port)
+{
+ __be32 host1;
+ __be16 port1;
+
+ EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
+
+ /* This cannot currently be combined with other filtering */
+ if (spec->type != EFX_FILTER_UNSPEC)
+ return -EPROTONOSUPPORT;
+
+ if (port == 0)
+ return -EINVAL;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ spec->type = EFX_FILTER_TCP_WILD;
+ break;
+ case IPPROTO_UDP:
+ spec->type = EFX_FILTER_UDP_WILD;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ /* Filter is constructed in terms of source and destination,
+ * with the odd wrinkle that the ports are swapped in a UDP
+ * wildcard filter. We need to convert from local and remote
+ * (= zero for wildcard) addresses.
+ */
+ host1 = 0;
+ if (proto != IPPROTO_UDP) {
+ port1 = 0;
+ } else {
+ port1 = port;
+ port = 0;
+ }
+
+ __efx_filter_set_ipv4(spec, host1, port1, host, port);
+ return 0;
+}
+
+/**
+ * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports
+ * @spec: Specification to initialise
+ * @proto: Transport layer protocol number
+ * @host: Local host address (network byte order)
+ * @port: Local port (network byte order)
+ * @rhost: Remote host address (network byte order)
+ * @rport: Remote port (network byte order)
+ */
+int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto,
+ __be32 host, __be16 port,
+ __be32 rhost, __be16 rport)
+{
+ EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
+
+ /* This cannot currently be combined with other filtering */
+ if (spec->type != EFX_FILTER_UNSPEC)
+ return -EPROTONOSUPPORT;
+
+ if (port == 0 || rport == 0)
+ return -EINVAL;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ spec->type = EFX_FILTER_TCP_FULL;
+ break;
+ case IPPROTO_UDP:
+ spec->type = EFX_FILTER_UDP_FULL;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ __efx_filter_set_ipv4(spec, rhost, rport, host, port);
+ return 0;
+}
+
+/**
+ * efx_filter_set_eth_local - specify local Ethernet address and optional VID
+ * @spec: Specification to initialise
+ * @vid: VLAN ID to match, or %EFX_FILTER_VID_UNSPEC
+ * @addr: Local Ethernet MAC address
+ */
+int efx_filter_set_eth_local(struct efx_filter_spec *spec,
+ u16 vid, const u8 *addr)
+{
+ EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
+
+ /* This cannot currently be combined with other filtering */
+ if (spec->type != EFX_FILTER_UNSPEC)
+ return -EPROTONOSUPPORT;
+
+ if (vid == EFX_FILTER_VID_UNSPEC) {
+ spec->type = EFX_FILTER_MAC_WILD;
+ spec->data[0] = 0;
+ } else {
+ spec->type = EFX_FILTER_MAC_FULL;
+ spec->data[0] = vid;
+ }
+
+ spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5];
+ spec->data[2] = addr[0] << 8 | addr[1];
+ return 0;
+}
+
/* Build a filter entry and return its n-tuple key. */
static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
{
u32 data3;
- switch (efx_filter_type_table_id(spec->type)) {
+ switch (efx_filter_spec_table_id(spec)) {
case EFX_FILTER_TABLE_RX_IP: {
- bool is_udp = (spec->type == EFX_FILTER_RX_UDP_FULL ||
- spec->type == EFX_FILTER_RX_UDP_WILD);
+ bool is_udp = (spec->type == EFX_FILTER_UDP_FULL ||
+ spec->type == EFX_FILTER_UDP_WILD);
EFX_POPULATE_OWORD_7(
*filter,
FRF_BZ_RSS_EN,
@@ -143,7 +286,7 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
}
case EFX_FILTER_TABLE_RX_MAC: {
- bool is_wild = spec->type == EFX_FILTER_RX_MAC_WILD;
+ bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
EFX_POPULATE_OWORD_8(
*filter,
FRF_CZ_RMFT_RSS_EN,
@@ -206,6 +349,14 @@ found:
return filter_idx;
}
+/* Construct/deconstruct external filter IDs */
+
+static inline int
+efx_filter_make_id(enum efx_filter_table_id table_id, unsigned index)
+{
+ return table_id << 16 | index;
+}
+
/**
* efx_filter_insert_filter - add or replace a filter
* @efx: NIC in which to insert the filter
@@ -213,30 +364,28 @@ found:
* @replace: Flag for whether the specified filter may replace a filter
* with an identical match expression and equal or lower priority
*
- * On success, return the filter index within its table.
+ * On success, return the filter ID.
* On failure, return a negative error code.
*/
int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
bool replace)
{
struct efx_filter_state *state = efx->filter_state;
- enum efx_filter_table_id table_id =
- efx_filter_type_table_id(spec->type);
- struct efx_filter_table *table = &state->table[table_id];
+ struct efx_filter_table *table = efx_filter_spec_table(state, spec);
struct efx_filter_spec *saved_spec;
efx_oword_t filter;
int filter_idx, depth;
u32 key;
int rc;
- if (table->size == 0)
+ if (!table || table->size == 0)
return -EINVAL;
key = efx_filter_build(&filter, spec);
netif_vdbg(efx, hw, efx->net_dev,
"%s: type %d search_depth=%d", __func__, spec->type,
- state->search_depth[spec->type]);
+ table->search_depth[spec->type]);
spin_lock_bh(&state->lock);
@@ -263,8 +412,8 @@ int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
}
*saved_spec = *spec;
- if (state->search_depth[spec->type] < depth) {
- state->search_depth[spec->type] = depth;
+ if (table->search_depth[spec->type] < depth) {
+ table->search_depth[spec->type] = depth;
efx_filter_push_rx_limits(efx);
}
@@ -273,6 +422,7 @@ int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
netif_vdbg(efx, hw, efx->net_dev,
"%s: filter type %d index %d rxq %u set",
__func__, spec->type, filter_idx, spec->dmaq_id);
+ rc = efx_filter_make_id(table->id, filter_idx);
out:
spin_unlock_bh(&state->lock);
@@ -306,15 +456,16 @@ static void efx_filter_table_clear_entry(struct efx_nic *efx,
int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec)
{
struct efx_filter_state *state = efx->filter_state;
- enum efx_filter_table_id table_id =
- efx_filter_type_table_id(spec->type);
- struct efx_filter_table *table = &state->table[table_id];
+ struct efx_filter_table *table = efx_filter_spec_table(state, spec);
struct efx_filter_spec *saved_spec;
efx_oword_t filter;
int filter_idx, depth;
u32 key;
int rc;
+ if (!table)
+ return -EINVAL;
+
key = efx_filter_build(&filter, spec);
spin_lock_bh(&state->lock);
@@ -332,7 +483,7 @@ int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec)
efx_filter_table_clear_entry(efx, table, filter_idx);
if (table->used == 0)
- efx_filter_table_reset_search_depth(state, table_id);
+ efx_filter_table_reset_search_depth(table);
rc = 0;
out:
@@ -340,15 +491,9 @@ out:
return rc;
}
-/**
- * efx_filter_table_clear - remove filters from a table by priority
- * @efx: NIC from which to remove the filters
- * @table_id: Table from which to remove the filters
- * @priority: Maximum priority to remove
- */
-void efx_filter_table_clear(struct efx_nic *efx,
- enum efx_filter_table_id table_id,
- enum efx_filter_priority priority)
+static void efx_filter_table_clear(struct efx_nic *efx,
+ enum efx_filter_table_id table_id,
+ enum efx_filter_priority priority)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table = &state->table[table_id];
@@ -360,11 +505,22 @@ void efx_filter_table_clear(struct efx_nic *efx,
if (table->spec[filter_idx].priority <= priority)
efx_filter_table_clear_entry(efx, table, filter_idx);
if (table->used == 0)
- efx_filter_table_reset_search_depth(state, table_id);
+ efx_filter_table_reset_search_depth(table);
spin_unlock_bh(&state->lock);
}
+/**
+ * efx_filter_clear_rx - remove RX filters by priority
+ * @efx: NIC from which to remove the filters
+ * @priority: Maximum priority to remove
+ */
+void efx_filter_clear_rx(struct efx_nic *efx, enum efx_filter_priority priority)
+{
+ efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP, priority);
+ efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC, priority);
+}
+
/* Restore filter stater after reset */
void efx_restore_filters(struct efx_nic *efx)
{
@@ -407,6 +563,7 @@ int efx_probe_filters(struct efx_nic *efx)
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
table = &state->table[EFX_FILTER_TABLE_RX_IP];
+ table->id = EFX_FILTER_TABLE_RX_IP;
table->offset = FR_BZ_RX_FILTER_TBL0;
table->size = FR_BZ_RX_FILTER_TBL0_ROWS;
table->step = FR_BZ_RX_FILTER_TBL0_STEP;
@@ -414,6 +571,7 @@ int efx_probe_filters(struct efx_nic *efx)
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
table = &state->table[EFX_FILTER_TABLE_RX_MAC];
+ table->id = EFX_FILTER_TABLE_RX_MAC;
table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
@@ -428,10 +586,9 @@ int efx_probe_filters(struct efx_nic *efx)
GFP_KERNEL);
if (!table->used_bitmap)
goto fail;
- table->spec = vmalloc(table->size * sizeof(*table->spec));
+ table->spec = vzalloc(table->size * sizeof(*table->spec));
if (!table->spec)
goto fail;
- memset(table->spec, 0, table->size * sizeof(*table->spec));
}
return 0;
diff --git a/drivers/net/sfc/filter.h b/drivers/net/sfc/filter.h
index a53319ded79c..872f2132a496 100644
--- a/drivers/net/sfc/filter.h
+++ b/drivers/net/sfc/filter.h
@@ -12,31 +12,27 @@
#include <linux/types.h>
-enum efx_filter_table_id {
- EFX_FILTER_TABLE_RX_IP = 0,
- EFX_FILTER_TABLE_RX_MAC,
- EFX_FILTER_TABLE_COUNT,
-};
-
/**
* enum efx_filter_type - type of hardware filter
- * @EFX_FILTER_RX_TCP_FULL: RX, matching TCP/IPv4 4-tuple
- * @EFX_FILTER_RX_TCP_WILD: RX, matching TCP/IPv4 destination (host, port)
- * @EFX_FILTER_RX_UDP_FULL: RX, matching UDP/IPv4 4-tuple
- * @EFX_FILTER_RX_UDP_WILD: RX, matching UDP/IPv4 destination (host, port)
- * @EFX_FILTER_RX_MAC_FULL: RX, matching Ethernet destination MAC address, VID
- * @EFX_FILTER_RX_MAC_WILD: RX, matching Ethernet destination MAC address
+ * @EFX_FILTER_TCP_FULL: Matching TCP/IPv4 4-tuple
+ * @EFX_FILTER_TCP_WILD: Matching TCP/IPv4 destination (host, port)
+ * @EFX_FILTER_UDP_FULL: Matching UDP/IPv4 4-tuple
+ * @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port)
+ * @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID
+ * @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address
+ * @EFX_FILTER_UNSPEC: Match type is unspecified
*
- * Falcon NICs only support the RX TCP/IPv4 and UDP/IPv4 filter types.
+ * Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types.
*/
enum efx_filter_type {
- EFX_FILTER_RX_TCP_FULL = 0,
- EFX_FILTER_RX_TCP_WILD,
- EFX_FILTER_RX_UDP_FULL,
- EFX_FILTER_RX_UDP_WILD,
- EFX_FILTER_RX_MAC_FULL = 4,
- EFX_FILTER_RX_MAC_WILD,
- EFX_FILTER_TYPE_COUNT,
+ EFX_FILTER_TCP_FULL = 0,
+ EFX_FILTER_TCP_WILD,
+ EFX_FILTER_UDP_FULL,
+ EFX_FILTER_UDP_WILD,
+ EFX_FILTER_MAC_FULL = 4,
+ EFX_FILTER_MAC_WILD,
+ EFX_FILTER_TYPE_COUNT, /* number of specific types */
+ EFX_FILTER_UNSPEC = 0xf,
};
/**
@@ -63,13 +59,13 @@ enum efx_filter_priority {
* @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override
* any IP filter that matches the same packet. By default, IP
* filters take precedence.
- *
- * Currently, no flags are defined for TX filters.
+ * @EFX_FILTER_FLAG_RX: Filter is for RX
*/
enum efx_filter_flags {
EFX_FILTER_FLAG_RX_RSS = 0x01,
EFX_FILTER_FLAG_RX_SCATTER = 0x02,
EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04,
+ EFX_FILTER_FLAG_RX = 0x08,
};
/**
@@ -91,99 +87,26 @@ struct efx_filter_spec {
u32 data[3];
};
-/**
- * efx_filter_set_rx_tcp_full - specify RX filter with TCP/IPv4 full match
- * @spec: Specification to initialise
- * @shost: Source host address (host byte order)
- * @sport: Source port (host byte order)
- * @dhost: Destination host address (host byte order)
- * @dport: Destination port (host byte order)
- */
-static inline void
-efx_filter_set_rx_tcp_full(struct efx_filter_spec *spec,
- u32 shost, u16 sport, u32 dhost, u16 dport)
-{
- spec->type = EFX_FILTER_RX_TCP_FULL;
- spec->data[0] = sport | shost << 16;
- spec->data[1] = dport << 16 | shost >> 16;
- spec->data[2] = dhost;
-}
-
-/**
- * efx_filter_set_rx_tcp_wild - specify RX filter with TCP/IPv4 wildcard match
- * @spec: Specification to initialise
- * @dhost: Destination host address (host byte order)
- * @dport: Destination port (host byte order)
- */
-static inline void
-efx_filter_set_rx_tcp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport)
-{
- spec->type = EFX_FILTER_RX_TCP_WILD;
- spec->data[0] = 0;
- spec->data[1] = dport << 16;
- spec->data[2] = dhost;
-}
-
-/**
- * efx_filter_set_rx_udp_full - specify RX filter with UDP/IPv4 full match
- * @spec: Specification to initialise
- * @shost: Source host address (host byte order)
- * @sport: Source port (host byte order)
- * @dhost: Destination host address (host byte order)
- * @dport: Destination port (host byte order)
- */
-static inline void
-efx_filter_set_rx_udp_full(struct efx_filter_spec *spec,
- u32 shost, u16 sport, u32 dhost, u16 dport)
-{
- spec->type = EFX_FILTER_RX_UDP_FULL;
- spec->data[0] = sport | shost << 16;
- spec->data[1] = dport << 16 | shost >> 16;
- spec->data[2] = dhost;
-}
-
-/**
- * efx_filter_set_rx_udp_wild - specify RX filter with UDP/IPv4 wildcard match
- * @spec: Specification to initialise
- * @dhost: Destination host address (host byte order)
- * @dport: Destination port (host byte order)
- */
-static inline void
-efx_filter_set_rx_udp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport)
+static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
+ enum efx_filter_priority priority,
+ enum efx_filter_flags flags,
+ unsigned rxq_id)
{
- spec->type = EFX_FILTER_RX_UDP_WILD;
- spec->data[0] = dport;
- spec->data[1] = 0;
- spec->data[2] = dhost;
+ spec->type = EFX_FILTER_UNSPEC;
+ spec->priority = priority;
+ spec->flags = EFX_FILTER_FLAG_RX | flags;
+ spec->dmaq_id = rxq_id;
}
-/**
- * efx_filter_set_rx_mac_full - specify RX filter with MAC full match
- * @spec: Specification to initialise
- * @vid: VLAN ID
- * @addr: Destination MAC address
- */
-static inline void efx_filter_set_rx_mac_full(struct efx_filter_spec *spec,
- u16 vid, const u8 *addr)
-{
- spec->type = EFX_FILTER_RX_MAC_FULL;
- spec->data[0] = vid;
- spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5];
- spec->data[2] = addr[0] << 8 | addr[1];
-}
-
-/**
- * efx_filter_set_rx_mac_full - specify RX filter with MAC wildcard match
- * @spec: Specification to initialise
- * @addr: Destination MAC address
- */
-static inline void efx_filter_set_rx_mac_wild(struct efx_filter_spec *spec,
- const u8 *addr)
-{
- spec->type = EFX_FILTER_RX_MAC_WILD;
- spec->data[0] = 0;
- spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5];
- spec->data[2] = addr[0] << 8 | addr[1];
-}
+extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
+ __be32 host, __be16 port);
+extern int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto,
+ __be32 host, __be16 port,
+ __be32 rhost, __be16 rport);
+extern int efx_filter_set_eth_local(struct efx_filter_spec *spec,
+ u16 vid, const u8 *addr);
+enum {
+ EFX_FILTER_VID_UNSPEC = 0xffff,
+};
#endif /* EFX_FILTER_H */
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index 85a99fe87437..6da4ae20a039 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -22,28 +22,39 @@
*
* Notes on locking strategy:
*
- * Most NIC registers require 16-byte (or 8-byte, for SRAM) atomic writes
- * which necessitates locking.
- * Under normal operation few writes to NIC registers are made and these
- * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
- * cased to allow 4-byte (hence lockless) accesses.
+ * Most CSRs are 128-bit (oword) and therefore cannot be read or
+ * written atomically. Access from the host is buffered by the Bus
+ * Interface Unit (BIU). Whenever the host reads from the lowest
+ * address of such a register, or from the address of a different such
+ * register, the BIU latches the register's value. Subsequent reads
+ * from higher addresses of the same register will read the latched
+ * value. Whenever the host writes part of such a register, the BIU
+ * collects the written value and does not write to the underlying
+ * register until all 4 dwords have been written. A similar buffering
+ * scheme applies to host access to the NIC's 64-bit SRAM.
*
- * It *is* safe to write to these 4-byte registers in the middle of an
- * access to an 8-byte or 16-byte register. We therefore use a
- * spinlock to protect accesses to the larger registers, but no locks
- * for the 4-byte registers.
+ * Access to different CSRs and 64-bit SRAM words must be serialised,
+ * since interleaved access can result in lost writes or lost
+ * information from read-to-clear fields. We use efx_nic::biu_lock
+ * for this. (We could use separate locks for read and write, but
+ * this is not normally a performance bottleneck.)
*
- * A write barrier is needed to ensure that DW3 is written after DW0/1/2
- * due to the way the 16byte registers are "collected" in the BIU.
+ * The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are
+ * 128-bit but are special-cased in the BIU to avoid the need for
+ * locking in the host:
*
- * We also lock when carrying out reads, to ensure consistency of the
- * data (made possible since the BIU reads all 128 bits into a cache).
- * Reads are very rare, so this isn't a significant performance
- * impact. (Most data transferred from NIC to host is DMAed directly
- * into host memory).
- *
- * I/O BAR access uses locks for both reads and writes (but is only provided
- * for testing purposes).
+ * - They are write-only.
+ * - The semantics of writing to these registers are such that
+ * replacing the low 96 bits with zero does not affect functionality.
+ * - If the host writes to the last dword address of such a register
+ * (i.e. the high 32 bits) the underlying register will always be
+ * written. If the collector does not hold values for the low 96
+ * bits of the register, they will be written as zero. Writing to
+ * the last qword does not have this effect and must not be done.
+ * - If the host writes to the address of any other part of such a
+ * register while the collector already holds values for some other
+ * register, the write is discarded and the collector maintains its
+ * current state.
*/
#if BITS_PER_LONG == 64
@@ -72,7 +83,7 @@ static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg)
return (__force __le32)__raw_readl(efx->membase + reg);
}
-/* Writes to a normal 16-byte Efx register, locking as appropriate. */
+/* Write a normal 128-bit CSR, locking as appropriate. */
static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg)
{
@@ -85,21 +96,18 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef EFX_USE_QWORD_IO
_efx_writeq(efx, value->u64[0], reg + 0);
- wmb();
_efx_writeq(efx, value->u64[1], reg + 8);
#else
_efx_writed(efx, value->u32[0], reg + 0);
_efx_writed(efx, value->u32[1], reg + 4);
_efx_writed(efx, value->u32[2], reg + 8);
- wmb();
_efx_writed(efx, value->u32[3], reg + 12);
#endif
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
-/* Write an 8-byte NIC SRAM entry through the supplied mapping,
- * locking as appropriate. */
+/* Write 64-bit SRAM through the supplied mapping, locking as appropriate. */
static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
efx_qword_t *value, unsigned int index)
{
@@ -115,36 +123,25 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
__raw_writeq((__force u64)value->u64[0], membase + addr);
#else
__raw_writel((__force u32)value->u32[0], membase + addr);
- wmb();
__raw_writel((__force u32)value->u32[1], membase + addr + 4);
#endif
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
-/* Write dword to NIC register that allows partial writes
- *
- * Some registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
- * TX_DESC_UPD_REG) can be written to as a single dword. This allows
- * for lockless writes.
- */
+/* Write a 32-bit CSR or the last dword of a special 128-bit CSR */
static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
netif_vdbg(efx, hw, efx->net_dev,
- "writing partial register %x with "EFX_DWORD_FMT"\n",
+ "writing register %x with "EFX_DWORD_FMT"\n",
reg, EFX_DWORD_VAL(*value));
/* No lock required */
_efx_writed(efx, value->u32[0], reg);
}
-/* Read from a NIC register
- *
- * This reads an entire 16-byte register in one go, locking as
- * appropriate. It is essential to read the first dword first, as this
- * prompts the NIC to load the current value into the shadow register.
- */
+/* Read a 128-bit CSR, locking as appropriate. */
static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg)
{
@@ -152,7 +149,6 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
spin_lock_irqsave(&efx->biu_lock, flags);
value->u32[0] = _efx_readd(efx, reg + 0);
- rmb();
value->u32[1] = _efx_readd(efx, reg + 4);
value->u32[2] = _efx_readd(efx, reg + 8);
value->u32[3] = _efx_readd(efx, reg + 12);
@@ -163,8 +159,7 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
EFX_OWORD_VAL(*value));
}
-/* Read an 8-byte SRAM entry through supplied mapping,
- * locking as appropriate. */
+/* Read 64-bit SRAM through the supplied mapping, locking as appropriate. */
static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
efx_qword_t *value, unsigned int index)
{
@@ -176,7 +171,6 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
value->u64[0] = (__force __le64)__raw_readq(membase + addr);
#else
value->u32[0] = (__force __le32)__raw_readl(membase + addr);
- rmb();
value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
@@ -186,7 +180,7 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
addr, EFX_QWORD_VAL(*value));
}
-/* Read dword from register that allows partial writes (sic) */
+/* Read a 32-bit CSR or SRAM */
static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
@@ -196,28 +190,28 @@ static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
reg, EFX_DWORD_VAL(*value));
}
-/* Write to a register forming part of a table */
+/* Write a 128-bit CSR forming part of a table */
static inline void efx_writeo_table(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int index)
{
efx_writeo(efx, value, reg + index * sizeof(efx_oword_t));
}
-/* Read to a register forming part of a table */
+/* Read a 128-bit CSR forming part of a table */
static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int index)
{
efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
}
-/* Write to a dword register forming part of a table */
+/* Write a 32-bit CSR forming part of a table, or 32-bit SRAM */
static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg, unsigned int index)
{
efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
}
-/* Read from a dword register forming part of a table */
+/* Read a 32-bit CSR forming part of a table, or 32-bit SRAM */
static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg, unsigned int index)
{
@@ -231,29 +225,54 @@ static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value,
#define EFX_PAGED_REG(page, reg) \
((page) * EFX_PAGE_BLOCK_SIZE + (reg))
-/* As for efx_writeo(), but for a page-mapped register. */
-static inline void efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg, unsigned int page)
+/* Write the whole of RX_DESC_UPD or TX_DESC_UPD */
+static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int page)
{
- efx_writeo(efx, value, EFX_PAGED_REG(page, reg));
-}
+ reg = EFX_PAGED_REG(page, reg);
-/* As for efx_writed(), but for a page-mapped register. */
-static inline void efx_writed_page(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg, unsigned int page)
+ netif_vdbg(efx, hw, efx->net_dev,
+ "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+
+#ifdef EFX_USE_QWORD_IO
+ _efx_writeq(efx, value->u64[0], reg + 0);
+#else
+ _efx_writed(efx, value->u32[0], reg + 0);
+ _efx_writed(efx, value->u32[1], reg + 4);
+#endif
+ _efx_writed(efx, value->u32[2], reg + 8);
+ _efx_writed(efx, value->u32[3], reg + 12);
+}
+#define efx_writeo_page(efx, value, reg, page) \
+ _efx_writeo_page(efx, value, \
+ reg + \
+ BUILD_BUG_ON_ZERO((reg) != 0x830 && (reg) != 0xa10), \
+ page)
+
+/* Write a page-mapped 32-bit CSR (EVQ_RPTR or the high bits of
+ * RX_DESC_UPD or TX_DESC_UPD)
+ */
+static inline void _efx_writed_page(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int page)
{
efx_writed(efx, value, EFX_PAGED_REG(page, reg));
}
-
-/* Write dword to page-mapped register with an extra lock.
- *
- * As for efx_writed_page(), but for a register that suffers from
- * SFC bug 3181. Take out a lock so the BIU collector cannot be
- * confused. */
-static inline void efx_writed_page_locked(struct efx_nic *efx,
- efx_dword_t *value,
- unsigned int reg,
- unsigned int page)
+#define efx_writed_page(efx, value, reg, page) \
+ _efx_writed_page(efx, value, \
+ reg + \
+ BUILD_BUG_ON_ZERO((reg) != 0x400 && (reg) != 0x83c \
+ && (reg) != 0xa1c), \
+ page)
+
+/* Write TIMER_COMMAND. This is a page-mapped 32-bit CSR, but a bug
+ * in the BIU means that writes to TIMER_COMMAND[0] invalidate the
+ * collector register.
+ */
+static inline void _efx_writed_page_locked(struct efx_nic *efx,
+ efx_dword_t *value,
+ unsigned int reg,
+ unsigned int page)
{
unsigned long flags __attribute__ ((unused));
@@ -265,5 +284,9 @@ static inline void efx_writed_page_locked(struct efx_nic *efx,
efx_writed(efx, value, EFX_PAGED_REG(page, reg));
}
}
+#define efx_writed_page_locked(efx, value, reg, page) \
+ _efx_writed_page_locked(efx, value, \
+ reg + BUILD_BUG_ON_ZERO((reg) != 0x420), \
+ page)
#endif /* EFX_IO_H */
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 12cf910c2ce7..b716e827b291 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -381,7 +381,7 @@ int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
-rc);
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
} else
- netif_err(efx, hw, efx->net_dev,
+ netif_dbg(efx, hw, efx->net_dev,
"MC command 0x%x inlen %d failed rc=%d\n",
cmd, (int)inlen, -rc);
}
@@ -463,6 +463,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
if (mcdi->mode == MCDI_MODE_EVENTS) {
mcdi->resprc = rc;
mcdi->resplen = 0;
+ ++mcdi->credits;
}
} else
/* Nobody was waiting for an MCDI request, so trigger a reset */
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index c992742446b1..0e97eed663c6 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -16,7 +16,6 @@
#include "phy.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
-#include "mdio_10g.h"
#include "nic.h"
#include "selftest.h"
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 98d946020429..56b0266b441f 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -15,7 +15,6 @@
#include "net_driver.h"
#include "mdio_10g.h"
#include "workarounds.h"
-#include "nic.h"
unsigned efx_mdio_id_oui(u32 id)
{
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index 02e54b4f701f..d38627448c22 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -321,14 +321,15 @@ static int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
struct efx_mtd *efx_mtd = mtd->priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = efx_mtd->efx;
+ struct falcon_nic_data *nic_data = efx->nic_data;
int rc;
- rc = mutex_lock_interruptible(&efx->spi_lock);
+ rc = mutex_lock_interruptible(&nic_data->spi_lock);
if (rc)
return rc;
rc = falcon_spi_read(efx, spi, part->offset + start, len,
retlen, buffer);
- mutex_unlock(&efx->spi_lock);
+ mutex_unlock(&nic_data->spi_lock);
return rc;
}
@@ -337,13 +338,14 @@ static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
struct efx_mtd *efx_mtd = mtd->priv;
struct efx_nic *efx = efx_mtd->efx;
+ struct falcon_nic_data *nic_data = efx->nic_data;
int rc;
- rc = mutex_lock_interruptible(&efx->spi_lock);
+ rc = mutex_lock_interruptible(&nic_data->spi_lock);
if (rc)
return rc;
rc = efx_spi_erase(part, part->offset + start, len);
- mutex_unlock(&efx->spi_lock);
+ mutex_unlock(&nic_data->spi_lock);
return rc;
}
@@ -354,14 +356,15 @@ static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
struct efx_mtd *efx_mtd = mtd->priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = efx_mtd->efx;
+ struct falcon_nic_data *nic_data = efx->nic_data;
int rc;
- rc = mutex_lock_interruptible(&efx->spi_lock);
+ rc = mutex_lock_interruptible(&nic_data->spi_lock);
if (rc)
return rc;
rc = falcon_spi_write(efx, spi, part->offset + start, len,
retlen, buffer);
- mutex_unlock(&efx->spi_lock);
+ mutex_unlock(&nic_data->spi_lock);
return rc;
}
@@ -370,11 +373,12 @@ static int falcon_mtd_sync(struct mtd_info *mtd)
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
struct efx_mtd *efx_mtd = mtd->priv;
struct efx_nic *efx = efx_mtd->efx;
+ struct falcon_nic_data *nic_data = efx->nic_data;
int rc;
- mutex_lock(&efx->spi_lock);
+ mutex_lock(&nic_data->spi_lock);
rc = efx_spi_slow_wait(part, true);
- mutex_unlock(&efx->spi_lock);
+ mutex_unlock(&nic_data->spi_lock);
return rc;
}
@@ -387,35 +391,67 @@ static struct efx_mtd_ops falcon_mtd_ops = {
static int falcon_mtd_probe(struct efx_nic *efx)
{
- struct efx_spi_device *spi = efx->spi_flash;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ struct efx_spi_device *spi;
struct efx_mtd *efx_mtd;
- int rc;
+ int rc = -ENODEV;
ASSERT_RTNL();
- if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START)
- return -ENODEV;
-
- efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]),
- GFP_KERNEL);
- if (!efx_mtd)
- return -ENOMEM;
-
- efx_mtd->spi = spi;
- efx_mtd->name = "flash";
- efx_mtd->ops = &falcon_mtd_ops;
+ spi = &nic_data->spi_flash;
+ if (efx_spi_present(spi) && spi->size > FALCON_FLASH_BOOTCODE_START) {
+ efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]),
+ GFP_KERNEL);
+ if (!efx_mtd)
+ return -ENOMEM;
+
+ efx_mtd->spi = spi;
+ efx_mtd->name = "flash";
+ efx_mtd->ops = &falcon_mtd_ops;
+
+ efx_mtd->n_parts = 1;
+ efx_mtd->part[0].mtd.type = MTD_NORFLASH;
+ efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH;
+ efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
+ efx_mtd->part[0].mtd.erasesize = spi->erase_size;
+ efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START;
+ efx_mtd->part[0].type_name = "sfc_flash_bootrom";
+
+ rc = efx_mtd_probe_device(efx, efx_mtd);
+ if (rc) {
+ kfree(efx_mtd);
+ return rc;
+ }
+ }
- efx_mtd->n_parts = 1;
- efx_mtd->part[0].mtd.type = MTD_NORFLASH;
- efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH;
- efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
- efx_mtd->part[0].mtd.erasesize = spi->erase_size;
- efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START;
- efx_mtd->part[0].type_name = "sfc_flash_bootrom";
+ spi = &nic_data->spi_eeprom;
+ if (efx_spi_present(spi) && spi->size > EFX_EEPROM_BOOTCONFIG_START) {
+ efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]),
+ GFP_KERNEL);
+ if (!efx_mtd)
+ return -ENOMEM;
+
+ efx_mtd->spi = spi;
+ efx_mtd->name = "EEPROM";
+ efx_mtd->ops = &falcon_mtd_ops;
+
+ efx_mtd->n_parts = 1;
+ efx_mtd->part[0].mtd.type = MTD_RAM;
+ efx_mtd->part[0].mtd.flags = MTD_CAP_RAM;
+ efx_mtd->part[0].mtd.size =
+ min(spi->size, EFX_EEPROM_BOOTCONFIG_END) -
+ EFX_EEPROM_BOOTCONFIG_START;
+ efx_mtd->part[0].mtd.erasesize = spi->erase_size;
+ efx_mtd->part[0].offset = EFX_EEPROM_BOOTCONFIG_START;
+ efx_mtd->part[0].type_name = "sfc_bootconfig";
+
+ rc = efx_mtd_probe_device(efx, efx_mtd);
+ if (rc) {
+ kfree(efx_mtd);
+ return rc;
+ }
+ }
- rc = efx_mtd_probe_device(efx, efx_mtd);
- if (rc)
- kfree(efx_mtd);
return rc;
}
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 0a7e26d73b52..28df8665256a 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -136,14 +136,19 @@ struct efx_tx_buffer {
* @efx: The associated Efx NIC
* @queue: DMA queue number
* @channel: The associated channel
+ * @core_txq: The networking core TX queue structure
* @buffer: The software buffer ring
* @txd: The hardware descriptor ring
* @ptr_mask: The size of the ring minus 1.
* @flushed: Used when handling queue flushing
* @read_count: Current read pointer.
* This is the number of buffers that have been removed from both rings.
- * @stopped: Stopped count.
- * Set if this TX queue is currently stopping its port.
+ * @old_write_count: The value of @write_count when last checked.
+ * This is here for performance reasons. The xmit path will
+ * only get the up-to-date value of @write_count if this
+ * variable indicates that the queue is empty. This is to
+ * avoid cache-line ping-pong between the xmit path and the
+ * completion path.
* @insert_count: Current insert pointer
* This is the number of buffers that have been added to the
* software ring.
@@ -163,13 +168,17 @@ struct efx_tx_buffer {
* @tso_long_headers: Number of packets with headers too long for standard
* blocks
* @tso_packets: Number of packets via the TSO xmit path
+ * @pushes: Number of times the TX push feature has been used
+ * @empty_read_count: If the completion path has seen the queue as empty
+ * and the transmission path has not yet checked this, the value of
+ * @read_count bitwise-added to %EFX_EMPTY_COUNT_VALID; otherwise 0.
*/
struct efx_tx_queue {
/* Members which don't change on the fast path */
struct efx_nic *efx ____cacheline_aligned_in_smp;
unsigned queue;
struct efx_channel *channel;
- struct efx_nic *nic;
+ struct netdev_queue *core_txq;
struct efx_tx_buffer *buffer;
struct efx_special_buffer txd;
unsigned int ptr_mask;
@@ -177,7 +186,7 @@ struct efx_tx_queue {
/* Members used mainly on the completion path */
unsigned int read_count ____cacheline_aligned_in_smp;
- int stopped;
+ unsigned int old_write_count;
/* Members used only on the xmit path */
unsigned int insert_count ____cacheline_aligned_in_smp;
@@ -187,6 +196,11 @@ struct efx_tx_queue {
unsigned int tso_bursts;
unsigned int tso_long_headers;
unsigned int tso_packets;
+ unsigned int pushes;
+
+ /* Members shared between paths and sometimes updated */
+ unsigned int empty_read_count ____cacheline_aligned_in_smp;
+#define EFX_EMPTY_COUNT_VALID 0x80000000
};
/**
@@ -305,7 +319,6 @@ enum efx_rx_alloc_method {
* @irq_moderation: IRQ moderation value (in hardware ticks)
* @napi_dev: Net device used with NAPI
* @napi_str: NAPI control structure
- * @reset_work: Scheduled reset work thread
* @work_pending: Is work pending via NAPI?
* @eventq: Event queue buffer
* @eventq_mask: Event queue pointer mask
@@ -326,8 +339,6 @@ enum efx_rx_alloc_method {
* @n_rx_overlength: Count of RX_OVERLENGTH errors
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
* @rx_queue: RX queue for this channel
- * @tx_stop_count: Core TX queue stop count
- * @tx_stop_lock: Core TX queue stop lock
* @tx_queue: TX queues for this channel
*/
struct efx_channel {
@@ -366,10 +377,6 @@ struct efx_channel {
bool rx_pkt_csummed;
struct efx_rx_queue rx_queue;
-
- atomic_t tx_stop_count;
- spinlock_t tx_stop_lock;
-
struct efx_tx_queue tx_queue[2];
};
@@ -621,14 +628,13 @@ struct efx_filter_state;
* @pci_dev: The PCI device
* @type: Controller type attributes
* @legacy_irq: IRQ number
+ * @legacy_irq_enabled: Are IRQs enabled on NIC (INT_EN_KER register)?
* @workqueue: Workqueue for port reconfigures and the HW monitor.
* Work items do not hold and must not acquire RTNL.
* @workqueue_name: Name of workqueue
* @reset_work: Scheduled reset workitem
- * @monitor_work: Hardware monitor workitem
* @membase_phys: Memory BAR value as physical address
* @membase: Memory BAR value
- * @biu_lock: BIU (bus interface unit) lock
* @interrupt_mode: Interrupt mode
* @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
* @irq_rx_moderation: IRQ moderation time for RX event queues
@@ -647,23 +653,14 @@ struct efx_filter_state;
* @n_tx_channels: Number of channels used for TX
* @rx_buffer_len: RX buffer length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @rx_hash_key: Toeplitz hash key for RSS
* @rx_indir_table: Indirection table for RSS
* @int_error_count: Number of internal errors seen recently
* @int_error_expire: Time at which error count will be expired
* @irq_status: Interrupt status buffer
- * @last_irq_cpu: Last CPU to handle interrupt.
- * This register is written with the SMP processor ID whenever an
- * interrupt is handled. It is used by efx_nic_test_interrupt()
- * to verify that an interrupt has occurred.
* @irq_zero_count: Number of legacy IRQs seen with queue flags == 0
* @fatal_irq_level: IRQ level (bit number) used for serious errors
- * @spi_flash: SPI flash device
- * This field will be %NULL if no flash device is present (or for Siena).
- * @spi_eeprom: SPI EEPROM device
- * This field will be %NULL if no EEPROM device is present (or for Siena).
- * @spi_lock: SPI bus lock
* @mtd_list: List of MTDs attached to the NIC
- * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
* @nic_data: Hardware dependant state
* @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
* @port_inhibited, efx_monitor() and efx_reconfigure_port()
@@ -676,21 +673,14 @@ struct efx_filter_state;
* @port_initialized: Port initialized?
* @net_dev: Operating system network device. Consider holding the rtnl lock
* @rx_checksum_enabled: RX checksumming enabled
- * @mac_stats: MAC statistics. These include all statistics the MACs
- * can provide. Generic code converts these into a standard
- * &struct net_device_stats.
* @stats_buffer: DMA buffer for statistics
- * @stats_lock: Statistics update lock. Serialises statistics fetches
* @mac_op: MAC interface
- * @mac_address: Permanent MAC address
* @phy_type: PHY type
- * @mdio_lock: MDIO lock
* @phy_op: PHY interface
* @phy_data: PHY private data (including PHY-specific stats)
* @mdio: PHY MDIO interface
* @mdio_bus: PHY MDIO bus ID (only used by Siena)
* @phy_mode: PHY operating mode. Serialised by @mac_lock.
- * @xmac_poll_required: XMAC link state needs polling
* @link_advertising: Autonegotiation advertising flags
* @link_state: Current state of the link
* @n_link_state_changes: Number of times the link has changed state
@@ -701,21 +691,34 @@ struct efx_filter_state;
* @loopback_mode: Loopback status
* @loopback_modes: Supported loopback mode bitmask
* @loopback_selftest: Offline self-test private state
+ * @monitor_work: Hardware monitor workitem
+ * @biu_lock: BIU (bus interface unit) lock
+ * @last_irq_cpu: Last CPU to handle interrupt.
+ * This register is written with the SMP processor ID whenever an
+ * interrupt is handled. It is used by efx_nic_test_interrupt()
+ * to verify that an interrupt has occurred.
+ * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
+ * @mac_stats: MAC statistics. These include all statistics the MACs
+ * can provide. Generic code converts these into a standard
+ * &struct net_device_stats.
+ * @stats_lock: Statistics update lock. Serialises statistics fetches
*
* This is stored in the private area of the &struct net_device.
*/
struct efx_nic {
+ /* The following fields should be written very rarely */
+
char name[IFNAMSIZ];
struct pci_dev *pci_dev;
const struct efx_nic_type *type;
int legacy_irq;
+ bool legacy_irq_enabled;
struct workqueue_struct *workqueue;
char workqueue_name[16];
struct work_struct reset_work;
- struct delayed_work monitor_work;
resource_size_t membase_phys;
void __iomem *membase;
- spinlock_t biu_lock;
+
enum efx_int_mode interrupt_mode;
bool irq_rx_adaptive;
unsigned int irq_rx_moderation;
@@ -732,6 +735,7 @@ struct efx_nic {
unsigned next_buffer_table;
unsigned n_channels;
unsigned n_rx_channels;
+ unsigned tx_channel_offset;
unsigned n_tx_channels;
unsigned int rx_buffer_len;
unsigned int rx_buffer_order;
@@ -742,19 +746,13 @@ struct efx_nic {
unsigned long int_error_expire;
struct efx_buffer irq_status;
- volatile signed int last_irq_cpu;
unsigned irq_zero_count;
unsigned fatal_irq_level;
- struct efx_spi_device *spi_flash;
- struct efx_spi_device *spi_eeprom;
- struct mutex spi_lock;
#ifdef CONFIG_SFC_MTD
struct list_head mtd_list;
#endif
- unsigned n_rx_nodesc_drop_cnt;
-
void *nic_data;
struct mutex mac_lock;
@@ -766,22 +764,17 @@ struct efx_nic {
struct net_device *net_dev;
bool rx_checksum_enabled;
- struct efx_mac_stats mac_stats;
struct efx_buffer stats_buffer;
- spinlock_t stats_lock;
struct efx_mac_operations *mac_op;
- unsigned char mac_address[ETH_ALEN];
unsigned int phy_type;
- struct mutex mdio_lock;
struct efx_phy_operations *phy_op;
void *phy_data;
struct mdio_if_info mdio;
unsigned int mdio_bus;
enum efx_phy_mode phy_mode;
- bool xmac_poll_required;
u32 link_advertising;
struct efx_link_state link_state;
unsigned int n_link_state_changes;
@@ -797,6 +790,15 @@ struct efx_nic {
void *loopback_selftest;
struct efx_filter_state *filter_state;
+
+ /* The following fields may be written more often */
+
+ struct delayed_work monitor_work ____cacheline_aligned_in_smp;
+ spinlock_t biu_lock;
+ volatile signed int last_irq_cpu;
+ unsigned n_rx_nodesc_drop_cnt;
+ struct efx_mac_stats mac_stats;
+ spinlock_t stats_lock;
};
static inline int efx_dev_registered(struct efx_nic *efx)
@@ -829,6 +831,7 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* be called while the controller is uninitialised.
* @probe_port: Probe the MAC and PHY
* @remove_port: Free resources allocated by probe_port()
+ * @handle_global_event: Handle a "global" event (may be %NULL)
* @prepare_flush: Prepare the hardware for flushing the DMA queues
* @update_stats: Update statistics not provided by event handling
* @start_stats: Start the regular fetching of statistics
@@ -873,6 +876,7 @@ struct efx_nic_type {
int (*reset)(struct efx_nic *efx, enum reset_type method);
int (*probe_port)(struct efx_nic *efx);
void (*remove_port)(struct efx_nic *efx);
+ bool (*handle_global_event)(struct efx_channel *channel, efx_qword_t *);
void (*prepare_flush)(struct efx_nic *efx);
void (*update_stats)(struct efx_nic *efx);
void (*start_stats)(struct efx_nic *efx);
@@ -926,8 +930,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
(_efx)->channel[_channel->channel + 1] : NULL)
-extern struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type);
+static inline struct efx_tx_queue *
+efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
+{
+ EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
+ type >= EFX_TXQ_TYPES);
+ return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type];
+}
static inline struct efx_tx_queue *
efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 41c36b9a4244..da386599ab68 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -362,6 +362,35 @@ static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue);
}
+/* Write pointer and first descriptor for TX descriptor ring */
+static inline void efx_push_tx_desc(struct efx_tx_queue *tx_queue,
+ const efx_qword_t *txd)
+{
+ unsigned write_ptr;
+ efx_oword_t reg;
+
+ BUILD_BUG_ON(FRF_AZ_TX_DESC_LBN != 0);
+ BUILD_BUG_ON(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0);
+
+ write_ptr = tx_queue->write_count & tx_queue->ptr_mask;
+ EFX_POPULATE_OWORD_2(reg, FRF_AZ_TX_DESC_PUSH_CMD, true,
+ FRF_AZ_TX_DESC_WPTR, write_ptr);
+ reg.qword[0] = *txd;
+ efx_writeo_page(tx_queue->efx, &reg,
+ FR_BZ_TX_DESC_UPD_P0, tx_queue->queue);
+}
+
+static inline bool
+efx_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count)
+{
+ unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
+
+ if (empty_read_count == 0)
+ return false;
+
+ tx_queue->empty_read_count = 0;
+ return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0;
+}
/* For each entry inserted into the software descriptor ring, create a
* descriptor in the hardware TX descriptor ring (in host memory), and
@@ -373,6 +402,7 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
struct efx_tx_buffer *buffer;
efx_qword_t *txd;
unsigned write_ptr;
+ unsigned old_write_count = tx_queue->write_count;
BUG_ON(tx_queue->write_count == tx_queue->insert_count);
@@ -391,7 +421,15 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
} while (tx_queue->write_count != tx_queue->insert_count);
wmb(); /* Ensure descriptors are written before they are fetched */
- efx_notify_tx_desc(tx_queue);
+
+ if (efx_may_push_tx_desc(tx_queue, old_write_count)) {
+ txd = efx_tx_desc(tx_queue,
+ old_write_count & tx_queue->ptr_mask);
+ efx_push_tx_desc(tx_queue, txd);
+ ++tx_queue->pushes;
+ } else {
+ efx_notify_tx_desc(tx_queue);
+ }
}
/* Allocate hardware resources for a TX queue */
@@ -894,46 +932,6 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
channel->channel, EFX_QWORD_VAL(*event));
}
-/* Global events are basically PHY events */
-static void
-efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
-{
- struct efx_nic *efx = channel->efx;
- bool handled = false;
-
- if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
- EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
- EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
- /* Ignored */
- handled = true;
- }
-
- if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) &&
- EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
- efx->xmac_poll_required = true;
- handled = true;
- }
-
- if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
- EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
- EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
- netif_err(efx, rx_err, efx->net_dev,
- "channel %d seen global RX_RESET event. Resetting.\n",
- channel->channel);
-
- atomic_inc(&efx->rx_reset);
- efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
- RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
- handled = true;
- }
-
- if (!handled)
- netif_err(efx, hw, efx->net_dev,
- "channel %d unknown global event "
- EFX_QWORD_FMT "\n", channel->channel,
- EFX_QWORD_VAL(*event));
-}
-
static void
efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
{
@@ -1050,15 +1048,17 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
case FSE_AZ_EV_CODE_DRV_GEN_EV:
efx_handle_generated_event(channel, &event);
break;
- case FSE_AZ_EV_CODE_GLOBAL_EV:
- efx_handle_global_event(channel, &event);
- break;
case FSE_AZ_EV_CODE_DRIVER_EV:
efx_handle_driver_event(channel, &event);
break;
case FSE_CZ_EV_CODE_MCDI_EV:
efx_mcdi_process_event(channel, &event);
break;
+ case FSE_AZ_EV_CODE_GLOBAL_EV:
+ if (efx->type->handle_global_event &&
+ efx->type->handle_global_event(channel, &event))
+ break;
+ /* else fall through */
default:
netif_err(channel->efx, hw, channel->efx->net_dev,
"channel %d unknown event type %d (data "
@@ -1418,6 +1418,12 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
u32 queues;
int syserr;
+ /* Could this be ours? If interrupts are disabled then the
+ * channel state may not be valid.
+ */
+ if (!efx->legacy_irq_enabled)
+ return result;
+
/* Read the ISR which also ACKs the interrupts */
efx_readd(efx, &reg, FR_BZ_INT_ISR0);
queues = EFX_EXTRACT_DWORD(reg, 0, 31);
@@ -1664,7 +1670,7 @@ void efx_nic_init_common(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
- EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 1);
EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
/* Enable SW_EV to inherit in char driver - assume harmless here */
EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 0438dc98722d..eb0586925b51 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -15,6 +15,7 @@
#include "net_driver.h"
#include "efx.h"
#include "mcdi.h"
+#include "spi.h"
/*
* Falcon hardware control
@@ -113,6 +114,11 @@ struct falcon_board {
* @stats_pending: Is there a pending DMA of MAC statistics.
* @stats_timer: A timer for regularly fetching MAC statistics.
* @stats_dma_done: Pointer to the flag which indicates DMA completion.
+ * @spi_flash: SPI flash device
+ * @spi_eeprom: SPI EEPROM device
+ * @spi_lock: SPI bus lock
+ * @mdio_lock: MDIO bus lock
+ * @xmac_poll_required: XMAC link state needs polling
*/
struct falcon_nic_data {
struct pci_dev *pci_dev2;
@@ -121,6 +127,11 @@ struct falcon_nic_data {
bool stats_pending;
struct timer_list stats_timer;
u32 *stats_dma_done;
+ struct efx_spi_device spi_flash;
+ struct efx_spi_device spi_eeprom;
+ struct mutex spi_lock;
+ struct mutex mdio_lock;
+ bool xmac_poll_required;
};
static inline struct falcon_board *falcon_board(struct efx_nic *efx)
@@ -135,7 +146,6 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
* @fw_build: Firmware build number
* @mcdi: Management-Controller-to-Driver Interface
* @wol_filter_id: Wake-on-LAN packet filter id
- * @ipv6_rss_key: Toeplitz hash key for IPv6 RSS
*/
struct siena_nic_data {
u64 fw_version;
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 68813d1d85f3..ea3ae0089315 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -41,6 +41,8 @@
#define PCS_UC_STATUS_LBN 0
#define PCS_UC_STATUS_WIDTH 8
#define PCS_UC_STATUS_FW_SAVE 0x20
+#define PMA_PMD_MODE_REG 0xc301
+#define PMA_PMD_RXIN_SEL_LBN 6
#define PMA_PMD_FTX_CTRL2_REG 0xc309
#define PMA_PMD_FTX_STATIC_LBN 13
#define PMA_PMD_VEND1_REG 0xc001
@@ -282,6 +284,10 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx)
* slow) reload of the firmware image (the microcontroller's code
* memory is not affected by the microcontroller reset). */
efx_mdio_write(efx, 1, 0xc317, 0x00ff);
+ /* PMA/PMD loopback sets RXIN to inverse polarity and the firmware
+ * restart doesn't reset it. We need to do that ourselves. */
+ efx_mdio_set_flag(efx, 1, PMA_PMD_MODE_REG,
+ 1 << PMA_PMD_RXIN_SEL_LBN, false);
efx_mdio_write(efx, 1, 0xc300, 0x0002);
msleep(20);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 6d0959b5158e..3925fd621177 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -37,7 +37,7 @@
* This driver supports two methods for allocating and using RX buffers:
* each RX buffer may be backed by an skb or by an order-n page.
*
- * When LRO is in use then the second method has a lower overhead,
+ * When GRO is in use then the second method has a lower overhead,
* since we don't have to allocate then free skbs on reassembled frames.
*
* Values:
@@ -50,25 +50,25 @@
*
* - Since pushing and popping descriptors are separated by the rx_queue
* size, so the watermarks should be ~rxd_size.
- * - The performance win by using page-based allocation for LRO is less
- * than the performance hit of using page-based allocation of non-LRO,
+ * - The performance win by using page-based allocation for GRO is less
+ * than the performance hit of using page-based allocation of non-GRO,
* so the watermarks should reflect this.
*
* Per channel we maintain a single variable, updated by each channel:
*
- * rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
+ * rx_alloc_level += (gro_performed ? RX_ALLOC_FACTOR_GRO :
* RX_ALLOC_FACTOR_SKB)
* Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
* limits the hysteresis), and update the allocation strategy:
*
- * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
+ * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_GRO ?
* RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
*/
static int rx_alloc_method = RX_ALLOC_METHOD_AUTO;
-#define RX_ALLOC_LEVEL_LRO 0x2000
+#define RX_ALLOC_LEVEL_GRO 0x2000
#define RX_ALLOC_LEVEL_MAX 0x3000
-#define RX_ALLOC_FACTOR_LRO 1
+#define RX_ALLOC_FACTOR_GRO 1
#define RX_ALLOC_FACTOR_SKB (-2)
/* This is the percentage fill level below which new RX descriptors
@@ -441,19 +441,19 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
efx_rx_queue_channel(rx_queue)->n_rx_overlength++;
}
-/* Pass a received packet up through the generic LRO stack
+/* Pass a received packet up through the generic GRO stack
*
* Handles driverlink veto, and passes the fragment up via
- * the appropriate LRO method
+ * the appropriate GRO method
*/
-static void efx_rx_packet_lro(struct efx_channel *channel,
+static void efx_rx_packet_gro(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf,
bool checksummed)
{
struct napi_struct *napi = &channel->napi_str;
gro_result_t gro_result;
- /* Pass the skb/page into the LRO engine */
+ /* Pass the skb/page into the GRO engine */
if (rx_buf->page) {
struct efx_nic *efx = channel->efx;
struct page *page = rx_buf->page;
@@ -499,7 +499,7 @@ static void efx_rx_packet_lro(struct efx_channel *channel,
if (gro_result == GRO_NORMAL) {
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
} else if (gro_result != GRO_DROP) {
- channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_GRO;
channel->irq_mod_score += 2;
}
}
@@ -605,7 +605,7 @@ void __efx_rx_packet(struct efx_channel *channel,
}
if (likely(checksummed || rx_buf->page)) {
- efx_rx_packet_lro(channel, rx_buf, checksummed);
+ efx_rx_packet_gro(channel, rx_buf, checksummed);
return;
}
@@ -628,7 +628,7 @@ void efx_rx_strategy(struct efx_channel *channel)
{
enum efx_rx_alloc_method method = rx_alloc_method;
- /* Only makes sense to use page based allocation if LRO is enabled */
+ /* Only makes sense to use page based allocation if GRO is enabled */
if (!(channel->efx->net_dev->features & NETIF_F_GRO)) {
method = RX_ALLOC_METHOD_SKB;
} else if (method == RX_ALLOC_METHOD_AUTO) {
@@ -639,7 +639,7 @@ void efx_rx_strategy(struct efx_channel *channel)
channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
/* Decide on the allocation method */
- method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
+ method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_GRO) ?
RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
}
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 45236f58a258..bf8456176443 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -194,13 +194,7 @@ static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
static int siena_probe_nvconfig(struct efx_nic *efx)
{
- int rc;
-
- rc = efx_mcdi_get_board_cfg(efx, efx->mac_address, NULL);
- if (rc)
- return rc;
-
- return 0;
+ return efx_mcdi_get_board_cfg(efx, efx->net_dev->perm_addr, NULL);
}
static int siena_probe_nic(struct efx_nic *efx)
@@ -562,7 +556,7 @@ static int siena_set_wol(struct efx_nic *efx, u32 type)
if (nic_data->wol_filter_id != -1)
efx_mcdi_wol_filter_remove(efx,
nic_data->wol_filter_id);
- rc = efx_mcdi_wol_filter_set_magic(efx, efx->mac_address,
+ rc = efx_mcdi_wol_filter_set_magic(efx, efx->net_dev->dev_addr,
&nic_data->wol_filter_id);
if (rc)
goto fail;
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
index 8bf4fce0813a..879b7f6bde3d 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/sfc/spi.h
@@ -61,6 +61,11 @@ struct efx_spi_device {
unsigned int block_size;
};
+static inline bool efx_spi_present(const struct efx_spi_device *spi)
+{
+ return spi->size != 0;
+}
+
int falcon_spi_cmd(struct efx_nic *efx,
const struct efx_spi_device *spi, unsigned int command,
int address, const void* in, void *out, size_t len);
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 1bc6c48c96ee..f102912eba91 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -15,9 +15,7 @@
#include "mdio_10g.h"
#include "nic.h"
#include "phy.h"
-#include "regs.h"
#include "workarounds.h"
-#include "selftest.h"
/* We expect these MMDs to be in the package. */
#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 11726989fe2d..2f5e9da657bf 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -30,50 +30,6 @@
*/
#define EFX_TXQ_THRESHOLD(_efx) ((_efx)->txq_entries / 2u)
-/* We need to be able to nest calls to netif_tx_stop_queue(), partly
- * because of the 2 hardware queues associated with each core queue,
- * but also so that we can inhibit TX for reasons other than a full
- * hardware queue. */
-void efx_stop_queue(struct efx_channel *channel)
-{
- struct efx_nic *efx = channel->efx;
- struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0);
-
- if (!tx_queue)
- return;
-
- spin_lock_bh(&channel->tx_stop_lock);
- netif_vdbg(efx, tx_queued, efx->net_dev, "stop TX queue\n");
-
- atomic_inc(&channel->tx_stop_count);
- netif_tx_stop_queue(
- netdev_get_tx_queue(efx->net_dev,
- tx_queue->queue / EFX_TXQ_TYPES));
-
- spin_unlock_bh(&channel->tx_stop_lock);
-}
-
-/* Decrement core TX queue stop count and wake it if the count is 0 */
-void efx_wake_queue(struct efx_channel *channel)
-{
- struct efx_nic *efx = channel->efx;
- struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0);
-
- if (!tx_queue)
- return;
-
- local_bh_disable();
- if (atomic_dec_and_lock(&channel->tx_stop_count,
- &channel->tx_stop_lock)) {
- netif_vdbg(efx, tx_queued, efx->net_dev, "waking TX queue\n");
- netif_tx_wake_queue(
- netdev_get_tx_queue(efx->net_dev,
- tx_queue->queue / EFX_TXQ_TYPES));
- spin_unlock(&channel->tx_stop_lock);
- }
- local_bh_enable();
-}
-
static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
struct efx_tx_buffer *buffer)
{
@@ -234,21 +190,22 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
* checked. Update the xmit path's
* copy of read_count.
*/
- ++tx_queue->stopped;
+ netif_tx_stop_queue(tx_queue->core_txq);
/* This memory barrier protects the
- * change of stopped from the access
+ * change of queue state from the access
* of read_count. */
smp_mb();
tx_queue->old_read_count =
- *(volatile unsigned *)
- &tx_queue->read_count;
+ ACCESS_ONCE(tx_queue->read_count);
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
q_space = efx->txq_entries - 1 - fill_level;
- if (unlikely(q_space-- <= 0))
- goto stop;
+ if (unlikely(q_space-- <= 0)) {
+ rc = NETDEV_TX_BUSY;
+ goto unwind;
+ }
smp_mb();
- --tx_queue->stopped;
+ netif_tx_start_queue(tx_queue->core_txq);
}
insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
@@ -308,13 +265,6 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
/* Mark the packet as transmitted, and free the SKB ourselves */
dev_kfree_skb_any(skb);
- goto unwind;
-
- stop:
- rc = NETDEV_TX_BUSY;
-
- if (tx_queue->stopped == 1)
- efx_stop_queue(tx_queue->channel);
unwind:
/* Work backwards until we hit the original insert pointer value */
@@ -407,22 +357,25 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
efx_dequeue_buffers(tx_queue, index);
/* See if we need to restart the netif queue. This barrier
- * separates the update of read_count from the test of
- * stopped. */
+ * separates the update of read_count from the test of the
+ * queue state. */
smp_mb();
- if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) {
+ if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) &&
+ likely(efx->port_enabled)) {
fill_level = tx_queue->insert_count - tx_queue->read_count;
if (fill_level < EFX_TXQ_THRESHOLD(efx)) {
EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
+ netif_tx_wake_queue(tx_queue->core_txq);
+ }
+ }
- /* Do this under netif_tx_lock(), to avoid racing
- * with efx_xmit(). */
- netif_tx_lock(efx->net_dev);
- if (tx_queue->stopped) {
- tx_queue->stopped = 0;
- efx_wake_queue(tx_queue->channel);
- }
- netif_tx_unlock(efx->net_dev);
+ /* Check whether the hardware queue is now empty */
+ if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
+ tx_queue->old_write_count = ACCESS_ONCE(tx_queue->write_count);
+ if (tx_queue->read_count == tx_queue->old_write_count) {
+ smp_mb();
+ tx_queue->empty_read_count =
+ tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
}
}
}
@@ -470,9 +423,10 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
tx_queue->insert_count = 0;
tx_queue->write_count = 0;
+ tx_queue->old_write_count = 0;
tx_queue->read_count = 0;
tx_queue->old_read_count = 0;
- BUG_ON(tx_queue->stopped);
+ tx_queue->empty_read_count = 0 | EFX_EMPTY_COUNT_VALID;
/* Set up TX descriptor ring */
efx_nic_init_tx(tx_queue);
@@ -508,12 +462,6 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
/* Free up TSO header cache */
efx_fini_tso(tx_queue);
-
- /* Release queue's stop on port, if any */
- if (tx_queue->stopped) {
- tx_queue->stopped = 0;
- efx_wake_queue(tx_queue->channel);
- }
}
void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
@@ -755,12 +703,12 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
* since the xmit path last checked. Update
* the xmit path's copy of read_count.
*/
- ++tx_queue->stopped;
+ netif_tx_stop_queue(tx_queue->core_txq);
/* This memory barrier protects the change of
- * stopped from the access of read_count. */
+ * queue state from the access of read_count. */
smp_mb();
tx_queue->old_read_count =
- *(volatile unsigned *)&tx_queue->read_count;
+ ACCESS_ONCE(tx_queue->read_count);
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
q_space = efx->txq_entries - 1 - fill_level;
@@ -769,7 +717,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
return 1;
}
smp_mb();
- --tx_queue->stopped;
+ netif_tx_start_queue(tx_queue->core_txq);
}
insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
@@ -1109,8 +1057,10 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
while (1) {
rc = tso_fill_packet_with_fragment(tx_queue, skb, &state);
- if (unlikely(rc))
- goto stop;
+ if (unlikely(rc)) {
+ rc2 = NETDEV_TX_BUSY;
+ goto unwind;
+ }
/* Move onto the next fragment? */
if (state.in_len == 0) {
@@ -1139,14 +1089,6 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
netif_err(efx, tx_err, efx->net_dev,
"Out of memory for TSO headers, or PCI mapping error\n");
dev_kfree_skb_any(skb);
- goto unwind;
-
- stop:
- rc2 = NETDEV_TX_BUSY;
-
- /* Stop the queue if it wasn't stopped before. */
- if (tx_queue->stopped == 1)
- efx_stop_queue(tx_queue->channel);
unwind:
/* Free the DMA mapping we were in the process of writing out */
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 50259dfec583..819c1750e2ab 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -45,9 +45,9 @@ static void sh_eth_set_duplex(struct net_device *ndev)
u32 ioaddr = ndev->base_addr;
if (mdp->duplex) /* Full */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
else /* Half */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
}
static void sh_eth_set_rate(struct net_device *ndev)
@@ -57,10 +57,10 @@ static void sh_eth_set_rate(struct net_device *ndev)
switch (mdp->speed) {
case 10: /* 10BASE */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR);
break;
case 100:/* 100BASE */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR);
break;
default:
break;
@@ -96,9 +96,9 @@ static void sh_eth_set_duplex(struct net_device *ndev)
u32 ioaddr = ndev->base_addr;
if (mdp->duplex) /* Full */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
else /* Half */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
}
static void sh_eth_set_rate(struct net_device *ndev)
@@ -108,10 +108,10 @@ static void sh_eth_set_rate(struct net_device *ndev)
switch (mdp->speed) {
case 10: /* 10BASE */
- ctrl_outl(0, ioaddr + RTRATE);
+ writel(0, ioaddr + RTRATE);
break;
case 100:/* 100BASE */
- ctrl_outl(1, ioaddr + RTRATE);
+ writel(1, ioaddr + RTRATE);
break;
default:
break;
@@ -143,7 +143,7 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
static void sh_eth_chip_reset(struct net_device *ndev)
{
/* reset device */
- ctrl_outl(ARSTR_ARSTR, ARSTR);
+ writel(ARSTR_ARSTR, ARSTR);
mdelay(1);
}
@@ -152,10 +152,10 @@ static void sh_eth_reset(struct net_device *ndev)
u32 ioaddr = ndev->base_addr;
int cnt = 100;
- ctrl_outl(EDSR_ENALL, ioaddr + EDSR);
- ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+ writel(EDSR_ENALL, ioaddr + EDSR);
+ writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
while (cnt > 0) {
- if (!(ctrl_inl(ioaddr + EDMR) & 0x3))
+ if (!(readl(ioaddr + EDMR) & 0x3))
break;
mdelay(1);
cnt--;
@@ -164,14 +164,14 @@ static void sh_eth_reset(struct net_device *ndev)
printk(KERN_ERR "Device reset fail\n");
/* Table Init */
- ctrl_outl(0x0, ioaddr + TDLAR);
- ctrl_outl(0x0, ioaddr + TDFAR);
- ctrl_outl(0x0, ioaddr + TDFXR);
- ctrl_outl(0x0, ioaddr + TDFFR);
- ctrl_outl(0x0, ioaddr + RDLAR);
- ctrl_outl(0x0, ioaddr + RDFAR);
- ctrl_outl(0x0, ioaddr + RDFXR);
- ctrl_outl(0x0, ioaddr + RDFFR);
+ writel(0x0, ioaddr + TDLAR);
+ writel(0x0, ioaddr + TDFAR);
+ writel(0x0, ioaddr + TDFXR);
+ writel(0x0, ioaddr + TDFFR);
+ writel(0x0, ioaddr + RDLAR);
+ writel(0x0, ioaddr + RDFAR);
+ writel(0x0, ioaddr + RDFXR);
+ writel(0x0, ioaddr + RDFFR);
}
static void sh_eth_set_duplex(struct net_device *ndev)
@@ -180,9 +180,9 @@ static void sh_eth_set_duplex(struct net_device *ndev)
u32 ioaddr = ndev->base_addr;
if (mdp->duplex) /* Full */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
else /* Half */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+ writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
}
static void sh_eth_set_rate(struct net_device *ndev)
@@ -192,13 +192,13 @@ static void sh_eth_set_rate(struct net_device *ndev)
switch (mdp->speed) {
case 10: /* 10BASE */
- ctrl_outl(GECMR_10, ioaddr + GECMR);
+ writel(GECMR_10, ioaddr + GECMR);
break;
case 100:/* 100BASE */
- ctrl_outl(GECMR_100, ioaddr + GECMR);
+ writel(GECMR_100, ioaddr + GECMR);
break;
case 1000: /* 1000BASE */
- ctrl_outl(GECMR_1000, ioaddr + GECMR);
+ writel(GECMR_1000, ioaddr + GECMR);
break;
default:
break;
@@ -283,9 +283,9 @@ static void sh_eth_reset(struct net_device *ndev)
{
u32 ioaddr = ndev->base_addr;
- ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+ writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
mdelay(3);
- ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
+ writel(readl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
}
#endif
@@ -336,10 +336,10 @@ static void update_mac_address(struct net_device *ndev)
{
u32 ioaddr = ndev->base_addr;
- ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
+ writel((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
(ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]),
ioaddr + MAHR);
- ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]),
+ writel((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]),
ioaddr + MALR);
}
@@ -358,12 +358,12 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac)
if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
memcpy(ndev->dev_addr, mac, 6);
} else {
- ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
- ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
- ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
- ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
- ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
- ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+ ndev->dev_addr[0] = (readl(ioaddr + MAHR) >> 24);
+ ndev->dev_addr[1] = (readl(ioaddr + MAHR) >> 16) & 0xFF;
+ ndev->dev_addr[2] = (readl(ioaddr + MAHR) >> 8) & 0xFF;
+ ndev->dev_addr[3] = (readl(ioaddr + MAHR) & 0xFF);
+ ndev->dev_addr[4] = (readl(ioaddr + MALR) >> 8) & 0xFF;
+ ndev->dev_addr[5] = (readl(ioaddr + MALR) & 0xFF);
}
}
@@ -379,19 +379,19 @@ struct bb_info {
/* PHY bit set */
static void bb_set(u32 addr, u32 msk)
{
- ctrl_outl(ctrl_inl(addr) | msk, addr);
+ writel(readl(addr) | msk, addr);
}
/* PHY bit clear */
static void bb_clr(u32 addr, u32 msk)
{
- ctrl_outl((ctrl_inl(addr) & ~msk), addr);
+ writel((readl(addr) & ~msk), addr);
}
/* PHY bit read */
static int bb_read(u32 addr, u32 msk)
{
- return (ctrl_inl(addr) & msk) != 0;
+ return (readl(addr) & msk) != 0;
}
/* Data I/O pin control */
@@ -506,9 +506,9 @@ static void sh_eth_ring_format(struct net_device *ndev)
rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
/* Rx descriptor address set */
if (i == 0) {
- ctrl_outl(mdp->rx_desc_dma, ioaddr + RDLAR);
+ writel(mdp->rx_desc_dma, ioaddr + RDLAR);
#if defined(CONFIG_CPU_SUBTYPE_SH7763)
- ctrl_outl(mdp->rx_desc_dma, ioaddr + RDFAR);
+ writel(mdp->rx_desc_dma, ioaddr + RDFAR);
#endif
}
}
@@ -528,9 +528,9 @@ static void sh_eth_ring_format(struct net_device *ndev)
txdesc->buffer_length = 0;
if (i == 0) {
/* Tx descriptor address set */
- ctrl_outl(mdp->tx_desc_dma, ioaddr + TDLAR);
+ writel(mdp->tx_desc_dma, ioaddr + TDLAR);
#if defined(CONFIG_CPU_SUBTYPE_SH7763)
- ctrl_outl(mdp->tx_desc_dma, ioaddr + TDFAR);
+ writel(mdp->tx_desc_dma, ioaddr + TDFAR);
#endif
}
}
@@ -623,71 +623,71 @@ static int sh_eth_dev_init(struct net_device *ndev)
/* Descriptor format */
sh_eth_ring_format(ndev);
if (mdp->cd->rpadir)
- ctrl_outl(mdp->cd->rpadir_value, ioaddr + RPADIR);
+ writel(mdp->cd->rpadir_value, ioaddr + RPADIR);
/* all sh_eth int mask */
- ctrl_outl(0, ioaddr + EESIPR);
+ writel(0, ioaddr + EESIPR);
#if defined(__LITTLE_ENDIAN__)
if (mdp->cd->hw_swap)
- ctrl_outl(EDMR_EL, ioaddr + EDMR);
+ writel(EDMR_EL, ioaddr + EDMR);
else
#endif
- ctrl_outl(0, ioaddr + EDMR);
+ writel(0, ioaddr + EDMR);
/* FIFO size set */
- ctrl_outl(mdp->cd->fdr_value, ioaddr + FDR);
- ctrl_outl(0, ioaddr + TFTR);
+ writel(mdp->cd->fdr_value, ioaddr + FDR);
+ writel(0, ioaddr + TFTR);
/* Frame recv control */
- ctrl_outl(mdp->cd->rmcr_value, ioaddr + RMCR);
+ writel(mdp->cd->rmcr_value, ioaddr + RMCR);
rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5;
tx_int_var = mdp->tx_int_var = DESC_I_TINT2;
- ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER);
+ writel(rx_int_var | tx_int_var, ioaddr + TRSCER);
if (mdp->cd->bculr)
- ctrl_outl(0x800, ioaddr + BCULR); /* Burst sycle set */
+ writel(0x800, ioaddr + BCULR); /* Burst sycle set */
- ctrl_outl(mdp->cd->fcftr_value, ioaddr + FCFTR);
+ writel(mdp->cd->fcftr_value, ioaddr + FCFTR);
if (!mdp->cd->no_trimd)
- ctrl_outl(0, ioaddr + TRIMD);
+ writel(0, ioaddr + TRIMD);
/* Recv frame limit set register */
- ctrl_outl(RFLR_VALUE, ioaddr + RFLR);
+ writel(RFLR_VALUE, ioaddr + RFLR);
- ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR);
- ctrl_outl(mdp->cd->eesipr_value, ioaddr + EESIPR);
+ writel(readl(ioaddr + EESR), ioaddr + EESR);
+ writel(mdp->cd->eesipr_value, ioaddr + EESIPR);
/* PAUSE Prohibition */
- val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) |
+ val = (readl(ioaddr + ECMR) & ECMR_DM) |
ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
- ctrl_outl(val, ioaddr + ECMR);
+ writel(val, ioaddr + ECMR);
if (mdp->cd->set_rate)
mdp->cd->set_rate(ndev);
/* E-MAC Status Register clear */
- ctrl_outl(mdp->cd->ecsr_value, ioaddr + ECSR);
+ writel(mdp->cd->ecsr_value, ioaddr + ECSR);
/* E-MAC Interrupt Enable register */
- ctrl_outl(mdp->cd->ecsipr_value, ioaddr + ECSIPR);
+ writel(mdp->cd->ecsipr_value, ioaddr + ECSIPR);
/* Set MAC address */
update_mac_address(ndev);
/* mask reset */
if (mdp->cd->apr)
- ctrl_outl(APR_AP, ioaddr + APR);
+ writel(APR_AP, ioaddr + APR);
if (mdp->cd->mpr)
- ctrl_outl(MPR_MP, ioaddr + MPR);
+ writel(MPR_MP, ioaddr + MPR);
if (mdp->cd->tpauser)
- ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
+ writel(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
/* Setting the Rx mode will start the Rx process. */
- ctrl_outl(EDRRR_R, ioaddr + EDRRR);
+ writel(EDRRR_R, ioaddr + EDRRR);
netif_start_queue(ndev);
@@ -811,8 +811,8 @@ static int sh_eth_rx(struct net_device *ndev)
/* Restart Rx engine if stopped. */
/* If we don't need to check status, don't. -KDU */
- if (!(ctrl_inl(ndev->base_addr + EDRRR) & EDRRR_R))
- ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR);
+ if (!(readl(ndev->base_addr + EDRRR) & EDRRR_R))
+ writel(EDRRR_R, ndev->base_addr + EDRRR);
return 0;
}
@@ -827,8 +827,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
u32 mask;
if (intr_status & EESR_ECI) {
- felic_stat = ctrl_inl(ioaddr + ECSR);
- ctrl_outl(felic_stat, ioaddr + ECSR); /* clear int */
+ felic_stat = readl(ioaddr + ECSR);
+ writel(felic_stat, ioaddr + ECSR); /* clear int */
if (felic_stat & ECSR_ICD)
mdp->stats.tx_carrier_errors++;
if (felic_stat & ECSR_LCHNG) {
@@ -839,25 +839,25 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
else
link_stat = PHY_ST_LINK;
} else {
- link_stat = (ctrl_inl(ioaddr + PSR));
+ link_stat = (readl(ioaddr + PSR));
if (mdp->ether_link_active_low)
link_stat = ~link_stat;
}
if (!(link_stat & PHY_ST_LINK)) {
/* Link Down : disable tx and rx */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) &
+ writel(readl(ioaddr + ECMR) &
~(ECMR_RE | ECMR_TE), ioaddr + ECMR);
} else {
/* Link Up */
- ctrl_outl(ctrl_inl(ioaddr + EESIPR) &
+ writel(readl(ioaddr + EESIPR) &
~DMAC_M_ECI, ioaddr + EESIPR);
/*clear int */
- ctrl_outl(ctrl_inl(ioaddr + ECSR),
+ writel(readl(ioaddr + ECSR),
ioaddr + ECSR);
- ctrl_outl(ctrl_inl(ioaddr + EESIPR) |
+ writel(readl(ioaddr + EESIPR) |
DMAC_M_ECI, ioaddr + EESIPR);
/* enable tx and rx */
- ctrl_outl(ctrl_inl(ioaddr + ECMR) |
+ writel(readl(ioaddr + ECMR) |
(ECMR_RE | ECMR_TE), ioaddr + ECMR);
}
}
@@ -888,8 +888,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
/* Receive Descriptor Empty int */
mdp->stats.rx_over_errors++;
- if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R)
- ctrl_outl(EDRRR_R, ioaddr + EDRRR);
+ if (readl(ioaddr + EDRRR) ^ EDRRR_R)
+ writel(EDRRR_R, ioaddr + EDRRR);
dev_err(&ndev->dev, "Receive Descriptor Empty\n");
}
if (intr_status & EESR_RFE) {
@@ -903,7 +903,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
mask &= ~EESR_ADE;
if (intr_status & mask) {
/* Tx error */
- u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR);
+ u32 edtrr = readl(ndev->base_addr + EDTRR);
/* dmesg */
dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ",
intr_status, mdp->cur_tx);
@@ -915,7 +915,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
/* SH7712 BUG */
if (edtrr ^ EDTRR_TRNS) {
/* tx dma start */
- ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR);
+ writel(EDTRR_TRNS, ndev->base_addr + EDTRR);
}
/* wakeup */
netif_wake_queue(ndev);
@@ -934,12 +934,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
spin_lock(&mdp->lock);
/* Get interrpt stat */
- intr_status = ctrl_inl(ioaddr + EESR);
+ intr_status = readl(ioaddr + EESR);
/* Clear interrupt */
if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
cd->tx_check | cd->eesr_err_check)) {
- ctrl_outl(intr_status, ioaddr + EESR);
+ writel(intr_status, ioaddr + EESR);
ret = IRQ_HANDLED;
} else
goto other_irq;
@@ -1000,7 +1000,7 @@ static void sh_eth_adjust_link(struct net_device *ndev)
mdp->cd->set_rate(ndev);
}
if (mdp->link == PHY_DOWN) {
- ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF)
+ writel((readl(ioaddr + ECMR) & ~ECMR_TXF)
| ECMR_DM, ioaddr + ECMR);
new_state = 1;
mdp->link = phydev->link;
@@ -1125,7 +1125,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
/* worning message out. */
printk(KERN_WARNING "%s: transmit timed out, status %8.8x,"
- " resetting...\n", ndev->name, (int)ctrl_inl(ioaddr + EESR));
+ " resetting...\n", ndev->name, (int)readl(ioaddr + EESR));
/* tx_errors count up */
mdp->stats.tx_errors++;
@@ -1196,8 +1196,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
mdp->cur_tx++;
- if (!(ctrl_inl(ndev->base_addr + EDTRR) & EDTRR_TRNS))
- ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR);
+ if (!(readl(ndev->base_addr + EDTRR) & EDTRR_TRNS))
+ writel(EDTRR_TRNS, ndev->base_addr + EDTRR);
return NETDEV_TX_OK;
}
@@ -1212,11 +1212,11 @@ static int sh_eth_close(struct net_device *ndev)
netif_stop_queue(ndev);
/* Disable interrupts by clearing the interrupt mask. */
- ctrl_outl(0x0000, ioaddr + EESIPR);
+ writel(0x0000, ioaddr + EESIPR);
/* Stop the chip's Tx and Rx processes. */
- ctrl_outl(0, ioaddr + EDTRR);
- ctrl_outl(0, ioaddr + EDRRR);
+ writel(0, ioaddr + EDTRR);
+ writel(0, ioaddr + EDRRR);
/* PHY Disconnect */
if (mdp->phydev) {
@@ -1251,20 +1251,20 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
pm_runtime_get_sync(&mdp->pdev->dev);
- mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
- ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
- mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
- ctrl_outl(0, ioaddr + CDCR); /* (write clear) */
- mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + LCCR);
- ctrl_outl(0, ioaddr + LCCR); /* (write clear) */
+ mdp->stats.tx_dropped += readl(ioaddr + TROCR);
+ writel(0, ioaddr + TROCR); /* (write clear) */
+ mdp->stats.collisions += readl(ioaddr + CDCR);
+ writel(0, ioaddr + CDCR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += readl(ioaddr + LCCR);
+ writel(0, ioaddr + LCCR); /* (write clear) */
#if defined(CONFIG_CPU_SUBTYPE_SH7763)
- mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CERCR);/* CERCR */
- ctrl_outl(0, ioaddr + CERCR); /* (write clear) */
- mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CEECR);/* CEECR */
- ctrl_outl(0, ioaddr + CEECR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += readl(ioaddr + CERCR);/* CERCR */
+ writel(0, ioaddr + CERCR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += readl(ioaddr + CEECR);/* CEECR */
+ writel(0, ioaddr + CEECR); /* (write clear) */
#else
- mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
- ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += readl(ioaddr + CNDCR);
+ writel(0, ioaddr + CNDCR); /* (write clear) */
#endif
pm_runtime_put_sync(&mdp->pdev->dev);
@@ -1295,11 +1295,11 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)
if (ndev->flags & IFF_PROMISC) {
/* Set promiscuous. */
- ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM,
+ writel((readl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM,
ioaddr + ECMR);
} else {
/* Normal, unicast/broadcast-only mode. */
- ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT,
+ writel((readl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT,
ioaddr + ECMR);
}
}
@@ -1307,30 +1307,30 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)
/* SuperH's TSU register init function */
static void sh_eth_tsu_init(u32 ioaddr)
{
- ctrl_outl(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */
- ctrl_outl(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */
- ctrl_outl(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */
- ctrl_outl(0xc, ioaddr + TSU_BSYSL0);
- ctrl_outl(0xc, ioaddr + TSU_BSYSL1);
- ctrl_outl(0, ioaddr + TSU_PRISL0);
- ctrl_outl(0, ioaddr + TSU_PRISL1);
- ctrl_outl(0, ioaddr + TSU_FWSL0);
- ctrl_outl(0, ioaddr + TSU_FWSL1);
- ctrl_outl(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC);
+ writel(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */
+ writel(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */
+ writel(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */
+ writel(0xc, ioaddr + TSU_BSYSL0);
+ writel(0xc, ioaddr + TSU_BSYSL1);
+ writel(0, ioaddr + TSU_PRISL0);
+ writel(0, ioaddr + TSU_PRISL1);
+ writel(0, ioaddr + TSU_FWSL0);
+ writel(0, ioaddr + TSU_FWSL1);
+ writel(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC);
#if defined(CONFIG_CPU_SUBTYPE_SH7763)
- ctrl_outl(0, ioaddr + TSU_QTAG0); /* Disable QTAG(0->1) */
- ctrl_outl(0, ioaddr + TSU_QTAG1); /* Disable QTAG(1->0) */
+ writel(0, ioaddr + TSU_QTAG0); /* Disable QTAG(0->1) */
+ writel(0, ioaddr + TSU_QTAG1); /* Disable QTAG(1->0) */
#else
- ctrl_outl(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */
- ctrl_outl(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */
+ writel(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */
+ writel(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */
#endif
- ctrl_outl(0, ioaddr + TSU_FWSR); /* all interrupt status clear */
- ctrl_outl(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */
- ctrl_outl(0, ioaddr + TSU_TEN); /* Disable all CAM entry */
- ctrl_outl(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */
- ctrl_outl(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */
- ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */
- ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */
+ writel(0, ioaddr + TSU_FWSR); /* all interrupt status clear */
+ writel(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */
+ writel(0, ioaddr + TSU_TEN); /* Disable all CAM entry */
+ writel(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */
+ writel(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */
+ writel(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */
+ writel(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */
}
#endif /* SH_ETH_HAS_TSU */
@@ -1552,7 +1552,6 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
sh_mdio_release(ndev);
unregister_netdev(ndev);
- flush_scheduled_work();
pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 8b47763958f2..efa64221eede 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index a5d6a6bd0c1a..3406ed870917 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1915,9 +1915,10 @@ err_release_board:
static void __devexit sis190_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct sis190_private *tp = netdev_priv(dev);
sis190_mii_remove(dev);
- flush_scheduled_work();
+ cancel_work_sync(&tp->phy_task);
unregister_netdev(dev);
sis190_release_board(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 581836867098..5976d1d51df1 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -36,7 +36,7 @@
Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@pobox.com> some bug fix and cleaning
Rev 1.07.05 Nov. 6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support
- Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule
+ Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalizer workaround rule
Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring
Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@pobox.com> softnet and init for kernel 2.4
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 0a66fed52e8e..16c62659cdd9 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -412,7 +412,7 @@ static int skfp_driver_init(struct net_device *dev)
bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev,
bp->SharedMemSize,
&bp->SharedMemDMA);
- if (!bp->SharedMemSize) {
+ if (!bp->SharedMemAddr) {
printk("could not allocate mem for ");
printk("hardware module: %ld byte\n",
bp->SharedMemSize);
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 2d9941c045bc..1e1bd0c201c8 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -1263,7 +1263,7 @@ void smt_set_timestamp(struct s_smc *smc, u_char *p)
static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy)
{
int i ;
- u_char *map ;
+ const u_char *map ;
u_short in ;
u_short out ;
@@ -1271,7 +1271,7 @@ static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy)
* MIB para 101b (fddiSMTConnectionPolicy) coding
* is different from 0005 coding
*/
- static u_char ansi_weirdness[16] = {
+ static const u_char ansi_weirdness[16] = {
0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15
} ;
SMTSETPARA(policy,SMT_P_POLICY) ;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index bfec2e0f5275..42daf98ba736 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -1191,7 +1191,7 @@ static void genesis_init(struct skge_hw *hw)
static void genesis_reset(struct skge_hw *hw, int port)
{
- const u8 zero[8] = { 0 };
+ static const u8 zero[8] = { 0 };
u32 reg;
skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
@@ -1557,7 +1557,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN;
int i;
u32 r;
- const u8 zero[6] = { 0 };
+ static const u8 zero[6] = { 0 };
for (i = 0; i < 10; i++) {
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
@@ -2764,7 +2764,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
td->dma_hi = map >> 32;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const int offset = skb_transport_offset(skb);
+ const int offset = skb_checksum_start_offset(skb);
/* This seems backwards, but it is what the sk98lin
* does. Looks like hardware is wrong?
@@ -3858,7 +3858,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
/* device is off until link detection */
netif_carrier_off(dev);
- netif_stop_queue(dev);
return dev;
}
@@ -4013,8 +4012,6 @@ static void __devexit skge_remove(struct pci_dev *pdev)
if (!hw)
return;
- flush_scheduled_work();
-
dev1 = hw->dev[1];
if (dev1)
unregister_netdev(dev1);
@@ -4045,53 +4042,40 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
+static int skge_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i, err, wol = 0;
+ int i;
if (!hw)
return 0;
- err = pci_save_state(pdev);
- if (err)
- return err;
-
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
struct skge_port *skge = netdev_priv(dev);
if (netif_running(dev))
skge_down(dev);
+
if (skge->wol)
skge_wol_init(skge);
-
- wol |= skge->wol;
}
skge_write32(hw, B0_IMSK, 0);
- pci_prepare_to_sleep(pdev);
-
return 0;
}
-static int skge_resume(struct pci_dev *pdev)
+static int skge_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, err;
if (!hw)
return 0;
- err = pci_back_from_sleep(pdev);
- if (err)
- goto out;
-
- err = pci_restore_state(pdev);
- if (err)
- goto out;
-
err = skge_reset(hw);
if (err)
goto out;
@@ -4112,12 +4096,19 @@ static int skge_resume(struct pci_dev *pdev)
out:
return err;
}
+
+static SIMPLE_DEV_PM_OPS(skge_pm_ops, skge_suspend, skge_resume);
+#define SKGE_PM_OPS (&skge_pm_ops)
+
+#else
+
+#define SKGE_PM_OPS NULL
#endif
static void skge_shutdown(struct pci_dev *pdev)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
+ int i;
if (!hw)
return;
@@ -4128,15 +4119,10 @@ static void skge_shutdown(struct pci_dev *pdev)
if (skge->wol)
skge_wol_init(skge);
- wol |= skge->wol;
}
- if (pci_enable_wake(pdev, PCI_D3cold, wol))
- pci_enable_wake(pdev, PCI_D3hot, wol);
-
- pci_disable_device(pdev);
+ pci_wake_from_d3(pdev, device_may_wakeup(&pdev->dev));
pci_set_power_state(pdev, PCI_D3hot);
-
}
static struct pci_driver skge_driver = {
@@ -4144,11 +4130,8 @@ static struct pci_driver skge_driver = {
.id_table = skge_id_table,
.probe = skge_probe,
.remove = __devexit_p(skge_remove),
-#ifdef CONFIG_PM
- .suspend = skge_suspend,
- .resume = skge_resume,
-#endif
.shutdown = skge_shutdown,
+ .driver.pm = SKGE_PM_OPS,
};
static struct dmi_system_id skge_32bit_dma_boards[] = {
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index d6577084ce70..7d85a38377a1 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -46,10 +46,6 @@
#include <asm/irq.h>
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define SKY2_VLAN_TAG_USED 1
-#endif
-
#include "sky2.h"
#define DRV_NAME "sky2"
@@ -1326,39 +1322,34 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;
}
-#ifdef SKY2_VLAN_TAG_USED
-static void sky2_set_vlan_mode(struct sky2_hw *hw, u16 port, bool onoff)
-{
- if (onoff) {
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
- RX_VLAN_STRIP_ON);
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_VLAN_TAG_ON);
- } else {
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
- RX_VLAN_STRIP_OFF);
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_VLAN_TAG_OFF);
- }
-}
+#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)
-static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+static void sky2_vlan_mode(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
u16 port = sky2->port;
- netif_tx_lock_bh(dev);
- napi_disable(&hw->napi);
+ if (dev->features & NETIF_F_HW_VLAN_RX)
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
+ RX_VLAN_STRIP_ON);
+ else
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
+ RX_VLAN_STRIP_OFF);
- sky2->vlgrp = grp;
- sky2_set_vlan_mode(hw, port, grp != NULL);
+ dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN;
+ if (dev->features & NETIF_F_HW_VLAN_TX)
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_VLAN_TAG_ON);
+ else {
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_VLAN_TAG_OFF);
- sky2_read32(hw, B0_Y2_SP_LISR);
- napi_enable(&hw->napi);
- netif_tx_unlock_bh(dev);
+ /* Can't do transmit offload of vlan without hw vlan */
+ dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG
+ | NETIF_F_ALL_CSUM);
+ }
}
-#endif
/* Amount of required worst case padding in rx buffer */
static inline unsigned sky2_rx_pad(const struct sky2_hw *hw)
@@ -1635,9 +1626,7 @@ static void sky2_hw_up(struct sky2_port *sky2)
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
sky2->tx_ring_size - 1);
-#ifdef SKY2_VLAN_TAG_USED
- sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
-#endif
+ sky2_vlan_mode(sky2->netdev);
sky2_rx_start(sky2);
}
@@ -1780,7 +1769,7 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
}
ctrl = 0;
-#ifdef SKY2_VLAN_TAG_USED
+
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
if (vlan_tx_tag_present(skb)) {
if (!le) {
@@ -1792,7 +1781,6 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
le->length = cpu_to_be16(vlan_tx_tag_get(skb));
ctrl |= INS_VLAN;
}
-#endif
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -1917,8 +1905,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
netif_printk(sky2, tx_done, KERN_DEBUG, dev,
"tx done %u\n", idx);
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ u64_stats_update_begin(&sky2->tx_stats.syncp);
+ ++sky2->tx_stats.packets;
+ sky2->tx_stats.bytes += skb->len;
+ u64_stats_update_end(&sky2->tx_stats.syncp);
re->skb = NULL;
dev_kfree_skb_any(skb);
@@ -2430,11 +2420,8 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
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 (status & GMR_FS_VLAN)
+ count -= VLAN_HLEN; /* Account for vlan tag */
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
"rx slot %u status 0x%x len %d\n",
@@ -2460,7 +2447,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
/* if length reported by DMA does not match PHY, packet was truncated */
if (length != count)
- goto len_error;
+ goto error;
okay:
if (length < copybreak)
@@ -2475,34 +2462,13 @@ resubmit:
return skb;
-len_error:
- /* Truncation of overlength packets
- causes PHY length to not match MAC length */
- ++dev->stats.rx_length_errors;
- if (net_ratelimit())
- netif_info(sky2, rx_err, dev,
- "rx length error: status %#x length %d\n",
- status, length);
- goto resubmit;
-
error:
++dev->stats.rx_errors;
- if (status & GMR_FS_RX_FF_OV) {
- dev->stats.rx_over_errors++;
- goto resubmit;
- }
if (net_ratelimit())
netif_info(sky2, rx_err, dev,
"rx error, status 0x%x length %d\n", status, length);
- if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
- dev->stats.rx_length_errors++;
- if (status & GMR_FS_FRAGMENT)
- dev->stats.rx_frame_errors++;
- if (status & GMR_FS_CRC_ERR)
- dev->stats.rx_crc_errors++;
-
goto resubmit;
}
@@ -2523,17 +2489,9 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
static inline void sky2_skb_rx(const struct sky2_port *sky2,
u32 status, struct sk_buff *skb)
{
-#ifdef SKY2_VLAN_TAG_USED
- u16 vlan_tag = be16_to_cpu(sky2->rx_tag);
- if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
- if (skb->ip_summed == CHECKSUM_NONE)
- vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag);
- else
- vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp,
- vlan_tag, skb);
- return;
- }
-#endif
+ if (status & GMR_FS_VLAN)
+ __vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
+
if (skb->ip_summed == CHECKSUM_NONE)
netif_receive_skb(skb);
else
@@ -2543,14 +2501,19 @@ static inline void sky2_skb_rx(const struct sky2_port *sky2,
static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
unsigned packets, unsigned bytes)
{
- if (packets) {
- struct net_device *dev = hw->dev[port];
+ struct net_device *dev = hw->dev[port];
+ struct sky2_port *sky2 = netdev_priv(dev);
- dev->stats.rx_packets += packets;
- dev->stats.rx_bytes += bytes;
- dev->last_rx = jiffies;
- sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
- }
+ if (packets == 0)
+ return;
+
+ u64_stats_update_begin(&sky2->rx_stats.syncp);
+ sky2->rx_stats.packets += packets;
+ sky2->rx_stats.bytes += bytes;
+ u64_stats_update_end(&sky2->rx_stats.syncp);
+
+ dev->last_rx = jiffies;
+ sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
}
static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
@@ -2645,7 +2608,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
goto exit_loop;
break;
-#ifdef SKY2_VLAN_TAG_USED
case OP_RXVLAN:
sky2->rx_tag = length;
break;
@@ -2653,7 +2615,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
case OP_RXCHKSVLAN:
sky2->rx_tag = length;
/* fall through */
-#endif
case OP_RXCHKS:
if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
sky2_rx_checksum(sky2, status);
@@ -3056,6 +3017,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
| SKY2_HW_NEW_LE
| SKY2_HW_AUTO_TX_SUM
| SKY2_HW_ADV_POWER_CTL;
+
+ /* The workaround for status conflicts VLAN tag detection. */
+ if (hw->chip_rev == CHIP_REV_YU_FE2_A0)
+ hw->flags |= SKY2_HW_VLAN_BROKEN;
break;
case CHIP_ID_YUKON_SUPR:
@@ -3398,12 +3363,24 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
+ bool enable_wakeup = false;
+ int i;
if ((wol->wolopts & ~sky2_wol_supported(sky2->hw)) ||
!device_can_wakeup(&hw->pdev->dev))
return -EOPNOTSUPP;
sky2->wol = wol->wolopts;
+
+ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (sky2->wol)
+ enable_wakeup = true;
+ }
+ device_set_wakeup_enable(&hw->pdev->dev, enable_wakeup);
+
return 0;
}
@@ -3413,18 +3390,15 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw)
u32 modes = SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_TP;
+ | SUPPORTED_100baseT_Full;
if (hw->flags & SKY2_HW_GIGABIT)
modes |= SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full;
return modes;
} else
- return SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg
- | SUPPORTED_FIBRE;
+ return SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full;
}
static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -3438,9 +3412,11 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (sky2_is_copper(hw)) {
ecmd->port = PORT_TP;
ecmd->speed = sky2->speed;
+ ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_TP;
} else {
ecmd->speed = SPEED_1000;
ecmd->port = PORT_FIBRE;
+ ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_FIBRE;
}
ecmd->advertising = sky2->advertising;
@@ -3457,8 +3433,19 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
u32 supported = sky2_supported_modes(hw);
if (ecmd->autoneg == AUTONEG_ENABLE) {
+ if (ecmd->advertising & ~supported)
+ return -EINVAL;
+
+ if (sky2_is_copper(hw))
+ sky2->advertising = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
+ else
+ sky2->advertising = ecmd->advertising |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+
sky2->flags |= SKY2_FLAG_AUTO_SPEED;
- ecmd->advertising = supported;
sky2->duplex = -1;
sky2->speed = -1;
} else {
@@ -3502,8 +3489,6 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
sky2->flags &= ~SKY2_FLAG_AUTO_SPEED;
}
- sky2->advertising = ecmd->advertising;
-
if (netif_running(dev)) {
sky2_phy_reinit(sky2);
sky2_set_multicast(dev);
@@ -3614,13 +3599,11 @@ static void sky2_phy_stats(struct sky2_port *sky2, u64 * data, unsigned count)
unsigned port = sky2->port;
int i;
- data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32
- | (u64) gma_read32(hw, port, GM_TXO_OK_LO);
- data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
- | (u64) gma_read32(hw, port, GM_RXO_OK_LO);
+ data[0] = get_stats64(hw, port, GM_TXO_OK_LO);
+ data[1] = get_stats64(hw, port, GM_RXO_OK_LO);
for (i = 2; i < count; i++)
- data[i] = (u64) gma_read32(hw, port, sky2_stats[i].offset);
+ data[i] = get_stats32(hw, port, sky2_stats[i].offset);
}
static void sky2_set_msglevel(struct net_device *netdev, u32 value)
@@ -3738,6 +3721,51 @@ static void sky2_set_multicast(struct net_device *dev)
gma_write16(hw, port, GM_RX_CTRL, reg);
}
+static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ unsigned int start;
+ u64 _bytes, _packets;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
+ _bytes = sky2->rx_stats.bytes;
+ _packets = sky2->rx_stats.packets;
+ } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
+
+ stats->rx_packets = _packets;
+ stats->rx_bytes = _bytes;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
+ _bytes = sky2->tx_stats.bytes;
+ _packets = sky2->tx_stats.packets;
+ } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
+
+ stats->tx_packets = _packets;
+ stats->tx_bytes = _bytes;
+
+ stats->multicast = get_stats32(hw, port, GM_RXF_MC_OK)
+ + get_stats32(hw, port, GM_RXF_BC_OK);
+
+ stats->collisions = get_stats32(hw, port, GM_TXF_COL);
+
+ stats->rx_length_errors = get_stats32(hw, port, GM_RXF_LNG_ERR);
+ stats->rx_crc_errors = get_stats32(hw, port, GM_RXF_FCS_ERR);
+ stats->rx_frame_errors = get_stats32(hw, port, GM_RXF_SHT)
+ + get_stats32(hw, port, GM_RXE_FRAG);
+ stats->rx_over_errors = get_stats32(hw, port, GM_RXE_FIFO_OV);
+
+ stats->rx_dropped = dev->stats.rx_dropped;
+ stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
+ stats->tx_fifo_errors = dev->stats.tx_fifo_errors;
+
+ return stats;
+}
+
/* Can have one global because blinking is controlled by
* ethtool and that is always under RTNL mutex
*/
@@ -4188,15 +4216,28 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
static int sky2_set_flags(struct net_device *dev, u32 data)
{
struct sky2_port *sky2 = netdev_priv(dev);
- u32 supported =
- (sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
+ unsigned long old_feat = dev->features;
+ u32 supported = 0;
int rc;
+ if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN))
+ supported |= ETH_FLAG_RXHASH;
+
+ if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN))
+ supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
+
+ printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n",
+ supported, data);
+
rc = ethtool_op_set_flags(dev, data, supported);
if (rc)
return rc;
- rx_set_rss(dev);
+ if ((old_feat ^ dev->features) & NETIF_F_RXHASH)
+ rx_set_rss(dev);
+
+ if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN)
+ sky2_vlan_mode(dev);
return 0;
}
@@ -4232,6 +4273,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_sset_count = sky2_get_sset_count,
.get_ethtool_stats = sky2_get_ethtool_stats,
.set_flags = sky2_set_flags,
+ .get_flags = ethtool_op_get_flags,
};
#ifdef CONFIG_SKY2_DEBUG
@@ -4512,9 +4554,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_set_multicast_list = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
.ndo_tx_timeout = sky2_tx_timeout,
-#ifdef SKY2_VLAN_TAG_USED
- .ndo_vlan_rx_register = sky2_vlan_rx_register,
-#endif
+ .ndo_get_stats64 = sky2_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = sky2_netpoll,
#endif
@@ -4529,9 +4569,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_set_multicast_list = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
.ndo_tx_timeout = sky2_tx_timeout,
-#ifdef SKY2_VLAN_TAG_USED
- .ndo_vlan_rx_register = sky2_vlan_rx_register,
-#endif
+ .ndo_get_stats64 = sky2_get_stats,
},
};
@@ -4582,7 +4620,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
- | NETIF_F_TSO | NETIF_F_GRO;
+ | NETIF_F_TSO | NETIF_F_GRO;
+
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
@@ -4590,13 +4629,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
dev->features |= NETIF_F_RXHASH;
-#ifdef SKY2_VLAN_TAG_USED
- /* 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)) {
+ if (!(hw->flags & SKY2_HW_VLAN_BROKEN))
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- }
-#endif
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
@@ -4920,10 +4954,11 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
+static int sky2_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct sky2_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
+ int i;
if (!hw)
return 0;
@@ -4940,41 +4975,24 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
if (sky2->wol)
sky2_wol_init(sky2);
-
- wol |= sky2->wol;
}
- device_set_wakeup_enable(&pdev->dev, wol != 0);
-
sky2_power_aux(hw);
rtnl_unlock();
- pci_save_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
return 0;
}
#ifdef CONFIG_PM
-static int sky2_resume(struct pci_dev *pdev)
+static int sky2_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct sky2_hw *hw = pci_get_drvdata(pdev);
int err;
if (!hw)
return 0;
- err = pci_set_power_state(pdev, PCI_D0);
- if (err)
- goto out;
-
- err = pci_restore_state(pdev);
- if (err)
- goto out;
-
- pci_enable_wake(pdev, PCI_D0, 0);
-
/* Re-enable all clocks */
err = pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
if (err) {
@@ -4994,11 +5012,20 @@ out:
pci_disable_device(pdev);
return err;
}
+
+static SIMPLE_DEV_PM_OPS(sky2_pm_ops, sky2_suspend, sky2_resume);
+#define SKY2_PM_OPS (&sky2_pm_ops)
+
+#else
+
+#define SKY2_PM_OPS NULL
#endif
static void sky2_shutdown(struct pci_dev *pdev)
{
- sky2_suspend(pdev, PMSG_SUSPEND);
+ sky2_suspend(&pdev->dev);
+ pci_wake_from_d3(pdev, device_may_wakeup(&pdev->dev));
+ pci_set_power_state(pdev, PCI_D3hot);
}
static struct pci_driver sky2_driver = {
@@ -5006,11 +5033,8 @@ static struct pci_driver sky2_driver = {
.id_table = sky2_id_table,
.probe = sky2_probe,
.remove = __devexit_p(sky2_remove),
-#ifdef CONFIG_PM
- .suspend = sky2_suspend,
- .resume = sky2_resume,
-#endif
.shutdown = sky2_shutdown,
+ .driver.pm = SKY2_PM_OPS,
};
static int __init sky2_init_module(void)
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 61891a6cacc2..6861b0e8db9a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2200,6 +2200,12 @@ enum flow_control {
FC_BOTH = 3,
};
+struct sky2_stats {
+ struct u64_stats_sync syncp;
+ u64 packets;
+ u64 bytes;
+};
+
struct sky2_port {
struct sky2_hw *hw;
struct net_device *netdev;
@@ -2209,6 +2215,8 @@ struct sky2_port {
struct tx_ring_info *tx_ring;
struct sky2_tx_le *tx_le;
+ struct sky2_stats tx_stats;
+
u16 tx_ring_size;
u16 tx_cons; /* next le to check */
u16 tx_prod; /* next le to use */
@@ -2221,17 +2229,15 @@ struct sky2_port {
struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp;
struct sky2_rx_le *rx_le;
+ struct sky2_stats rx_stats;
u16 rx_next; /* next re to check */
u16 rx_put; /* next le index to use */
u16 rx_pending;
u16 rx_data_size;
u16 rx_nfrags;
-
-#ifdef SKY2_VLAN_TAG_USED
u16 rx_tag;
- struct vlan_group *vlgrp;
-#endif
+
struct {
unsigned long last;
u32 mac_rp;
@@ -2275,6 +2281,7 @@ struct sky2_hw {
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
#define SKY2_HW_RSS_BROKEN 0x00000100
+#define SKY2_HW_VLAN_BROKEN 0x00000200
u8 chip_id;
u8 chip_rev;
@@ -2346,6 +2353,39 @@ static inline u32 gma_read32(struct sky2_hw *hw, unsigned port, unsigned reg)
| (u32) sky2_read16(hw, base+4) << 16;
}
+static inline u64 gma_read64(struct sky2_hw *hw, unsigned port, unsigned reg)
+{
+ unsigned base = SK_GMAC_REG(port, reg);
+
+ return (u64) sky2_read16(hw, base)
+ | (u64) sky2_read16(hw, base+4) << 16
+ | (u64) sky2_read16(hw, base+8) << 32
+ | (u64) sky2_read16(hw, base+12) << 48;
+}
+
+/* There is no way to atomically read32 bit values from PHY, so retry */
+static inline u32 get_stats32(struct sky2_hw *hw, unsigned port, unsigned reg)
+{
+ u32 val;
+
+ do {
+ val = gma_read32(hw, port, reg);
+ } while (gma_read32(hw, port, reg) != val);
+
+ return val;
+}
+
+static inline u64 get_stats64(struct sky2_hw *hw, unsigned port, unsigned reg)
+{
+ u64 val;
+
+ do {
+ val = gma_read64(hw, port, reg);
+ } while (gma_read64(hw, port, reg) != val);
+
+ return val;
+}
+
static inline void gma_write16(const struct sky2_hw *hw, unsigned port, int r, u16 v)
{
sky2_write16(hw, SK_GMAC_REG(port,r), v);
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d2dd8e6113ab..235a3c6c9f91 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -277,8 +277,12 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
{
- int addr_tbl[4] = {0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000};
- short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff};
+ static const int addr_tbl[4] = {
+ 0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000
+ };
+ static const short num_pages_tbl[4] = {
+ 0x20, 0x40, 0x80, 0xff
+ };
dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
num_pages = num_pages_tbl[(addr >> 4) & 3];
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index 52f38e12a879..50f712e99e96 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -22,7 +22,7 @@
#define __SMSC911X_H__
#define TX_FIFO_LOW_THRESHOLD ((u32)1600)
-#define SMSC911X_EEPROM_SIZE ((u32)7)
+#define SMSC911X_EEPROM_SIZE ((u32)128)
#define USE_DEBUG 0
/* This is the maximum number of packets to be received every
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 4adf12422787..a4f2bd52e546 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -148,7 +148,7 @@ static int full_duplex[MAX_UNITS] = {0, };
* This SUCKS.
* We need a much better method to determine if dma_addr_t is 64-bit.
*/
-#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)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || (defined(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
#define netdrv_addr_t __le64
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index 79bdc2e13224..5f06c4706abe 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -20,7 +20,7 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#define DRV_MODULE_VERSION "Apr_2010"
+#define DRV_MODULE_VERSION "Nov_2010"
#include <linux/platform_device.h>
#include <linux/stmmac.h>
@@ -37,7 +37,6 @@ struct stmmac_priv {
unsigned int cur_tx;
unsigned int dirty_tx;
unsigned int dma_tx_size;
- int tx_coe;
int tx_coalesce;
struct dma_desc *dma_rx ;
@@ -48,7 +47,6 @@ struct stmmac_priv {
struct sk_buff_head rx_recycle;
struct net_device *dev;
- int is_gmac;
dma_addr_t dma_rx_phy;
unsigned int dma_rx_size;
unsigned int dma_buf_sz;
@@ -60,14 +58,11 @@ struct stmmac_priv {
struct napi_struct napi;
phy_interface_t phy_interface;
- int pbl;
- int bus_id;
int phy_addr;
int phy_mask;
int (*phy_reset) (void *priv);
- void (*fix_mac_speed) (void *priv, unsigned int speed);
- void (*bus_setup)(void __iomem *ioaddr);
- void *bsp_priv;
+ int rx_coe;
+ int no_csum_insertion;
int phy_irq;
struct phy_device *phydev;
@@ -77,47 +72,20 @@ struct stmmac_priv {
unsigned int flow_ctrl;
unsigned int pause;
struct mii_bus *mii;
- int mii_clk_csr;
u32 msg_enable;
spinlock_t lock;
int wolopts;
int wolenabled;
- int shutdown;
#ifdef CONFIG_STMMAC_TIMER
struct stmmac_timer *tm;
#endif
#ifdef STMMAC_VLAN_TAG_USED
struct vlan_group *vlgrp;
#endif
- int enh_desc;
- int rx_coe;
- int bugged_jumbo;
- int no_csum_insertion;
+ struct plat_stmmacenet_data *plat;
};
-#ifdef CONFIG_STM_DRIVERS
-#include <linux/stm/pad.h>
-static inline int stmmac_claim_resource(struct platform_device *pdev)
-{
- int ret = 0;
- struct plat_stmmacenet_data *plat_dat = pdev->dev.platform_data;
-
- /* Pad routing setup */
- if (IS_ERR(devm_stm_pad_claim(&pdev->dev, plat_dat->pad_config,
- dev_name(&pdev->dev)))) {
- printk(KERN_ERR "%s: Failed to request pads!\n", __func__);
- ret = -ENODEV;
- }
- return ret;
-}
-#else
-static inline int stmmac_claim_resource(struct platform_device *pdev)
-{
- return 0;
-}
-#endif
-
extern int stmmac_mdio_unregister(struct net_device *ndev);
extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 6d65482e789a..fd719edc7f7c 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -94,7 +94,7 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
{
struct stmmac_priv *priv = netdev_priv(dev);
- if (!priv->is_gmac)
+ if (!priv->plat->has_gmac)
strcpy(info->driver, MAC100_ETHTOOL_NAME);
else
strcpy(info->driver, GMAC_ETHTOOL_NAME);
@@ -176,7 +176,7 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
memset(reg_space, 0x0, REG_SPACE_SIZE);
- if (!priv->is_gmac) {
+ if (!priv->plat->has_gmac) {
/* MAC registers */
for (i = 0; i < 12; i++)
reg_space[i] = readl(priv->ioaddr + (i * 4));
@@ -197,16 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
}
}
-static int stmmac_ethtool_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 u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -370,7 +360,7 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_rx_csum = stmmac_ethtool_get_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = stmmac_ethtool_set_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_pauseparam = stmmac_get_pauseparam,
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 06bc6034ce81..34a0af3837f9 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -186,6 +186,18 @@ static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
}
+/* On some ST platforms, some HW system configuraton registers have to be
+ * set according to the link speed negotiated.
+ */
+static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
+{
+ struct phy_device *phydev = priv->phydev;
+
+ if (likely(priv->plat->fix_mac_speed))
+ priv->plat->fix_mac_speed(priv->plat->bsp_priv,
+ phydev->speed);
+}
+
/**
* stmmac_adjust_link
* @dev: net device structure
@@ -228,15 +240,13 @@ static void stmmac_adjust_link(struct net_device *dev)
new_state = 1;
switch (phydev->speed) {
case 1000:
- if (likely(priv->is_gmac))
+ if (likely(priv->plat->has_gmac))
ctrl &= ~priv->hw->link.port;
- if (likely(priv->fix_mac_speed))
- priv->fix_mac_speed(priv->bsp_priv,
- phydev->speed);
+ stmmac_hw_fix_mac_speed(priv);
break;
case 100:
case 10:
- if (priv->is_gmac) {
+ if (priv->plat->has_gmac) {
ctrl |= priv->hw->link.port;
if (phydev->speed == SPEED_100) {
ctrl |= priv->hw->link.speed;
@@ -246,9 +256,7 @@ static void stmmac_adjust_link(struct net_device *dev)
} else {
ctrl &= ~priv->hw->link.port;
}
- if (likely(priv->fix_mac_speed))
- priv->fix_mac_speed(priv->bsp_priv,
- phydev->speed);
+ stmmac_hw_fix_mac_speed(priv);
break;
default:
if (netif_msg_link(priv))
@@ -305,7 +313,7 @@ static int stmmac_init_phy(struct net_device *dev)
return 0;
}
- snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
+ snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
priv->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id);
@@ -552,7 +560,7 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
*/
static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
- if (likely((priv->tx_coe) && (!priv->no_csum_insertion))) {
+ if (likely((priv->plat->tx_coe) && (!priv->no_csum_insertion))) {
/* In case of GMAC, SF mode has to be enabled
* to perform the TX COE. This depends on:
* 1) TX COE if actually supported
@@ -814,7 +822,7 @@ static int stmmac_open(struct net_device *dev)
init_dma_desc_rings(dev);
/* DMA initialization and SW reset */
- if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->pbl,
+ if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl,
priv->dma_tx_phy,
priv->dma_rx_phy) < 0)) {
@@ -825,19 +833,17 @@ static int stmmac_open(struct net_device *dev)
/* Copy the MAC addr into the HW */
priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
/* If required, perform hw setup of the bus. */
- if (priv->bus_setup)
- priv->bus_setup(priv->ioaddr);
+ if (priv->plat->bus_setup)
+ priv->plat->bus_setup(priv->ioaddr);
/* Initialize the MAC Core */
priv->hw->mac->core_init(priv->ioaddr);
priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
if (priv->rx_coe)
pr_info("stmmac: Rx Checksum Offload Engine supported\n");
- if (priv->tx_coe)
+ if (priv->plat->tx_coe)
pr_info("\tTX Checksum insertion supported\n");
- priv->shutdown = 0;
-
/* Initialise the MMC (if present) to disable all interrupts. */
writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK);
@@ -943,7 +949,7 @@ static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb)
skb, skb->len);
segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
goto sw_tso_end;
do {
@@ -1042,7 +1048,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return stmmac_sw_tso(priv, skb);
if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
- if (unlikely((!priv->tx_coe) || (priv->no_csum_insertion)))
+ if (unlikely((!priv->plat->tx_coe) ||
+ (priv->no_csum_insertion)))
skb_checksum_help(skb);
else
csum_insertion = 1;
@@ -1146,7 +1153,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
DMA_FROM_DEVICE);
(p + entry)->des2 = priv->rx_skbuff_dma[entry];
- if (unlikely(priv->is_gmac)) {
+ if (unlikely(priv->plat->has_gmac)) {
if (bfsize >= BUF_SIZE_8KiB)
(p + entry)->des3 =
(p + entry)->des2 + BUF_SIZE_8KiB;
@@ -1356,7 +1363,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
return -EBUSY;
}
- if (priv->is_gmac)
+ if (priv->plat->has_gmac)
max_mtu = JUMBO_LEN;
else
max_mtu = ETH_DATA_LEN;
@@ -1370,7 +1377,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
* needs to have the Tx COE disabled for oversized frames
* (due to limited buffer sizes). In this case we disable
* the TX csum insertionin the TDES and not use SF. */
- if ((priv->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN))
+ if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN))
priv->no_csum_insertion = 1;
else
priv->no_csum_insertion = 0;
@@ -1390,7 +1397,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
- if (priv->is_gmac)
+ if (priv->plat->has_gmac)
/* To handle GMAC own interrupts */
priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr);
@@ -1487,7 +1494,8 @@ static int stmmac_probe(struct net_device *dev)
dev->netdev_ops = &stmmac_netdev_ops;
stmmac_set_ethtool_ops(dev);
- dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA);
+ dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
@@ -1509,6 +1517,8 @@ static int stmmac_probe(struct net_device *dev)
pr_warning("\tno valid MAC address;"
"please, use ifconfig or nwhwconfig!\n");
+ spin_lock_init(&priv->lock);
+
ret = register_netdev(dev);
if (ret) {
pr_err("%s: ERROR %i registering the device\n",
@@ -1518,9 +1528,7 @@ static int stmmac_probe(struct net_device *dev)
DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n",
dev->name, (dev->features & NETIF_F_SG) ? "on" : "off",
- (dev->features & NETIF_F_HW_CSUM) ? "on" : "off");
-
- spin_lock_init(&priv->lock);
+ (dev->features & NETIF_F_IP_CSUM) ? "on" : "off");
return ret;
}
@@ -1536,7 +1544,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
struct mac_device_info *device;
- if (priv->is_gmac)
+ if (priv->plat->has_gmac)
device = dwmac1000_setup(priv->ioaddr);
else
device = dwmac100_setup(priv->ioaddr);
@@ -1544,7 +1552,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
if (!device)
return -ENOMEM;
- if (priv->enh_desc) {
+ if (priv->plat->enh_desc) {
device->desc = &enh_desc_ops;
pr_info("\tEnhanced descriptor structure\n");
} else
@@ -1598,7 +1606,7 @@ static int stmmac_associate_phy(struct device *dev, void *data)
plat_dat->bus_id);
/* Check that this phy is for the MAC being initialised */
- if (priv->bus_id != plat_dat->bus_id)
+ if (priv->plat->bus_id != plat_dat->bus_id)
return 0;
/* OK, this PHY is connected to the MAC.
@@ -1634,15 +1642,13 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
struct resource *res;
void __iomem *addr = NULL;
struct net_device *ndev = NULL;
- struct stmmac_priv *priv;
+ struct stmmac_priv *priv = NULL;
struct plat_stmmacenet_data *plat_dat;
pr_info("STMMAC driver:\n\tplatform registration... ");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENODEV;
- goto out;
- }
+ if (!res)
+ return -ENODEV;
pr_info("\tdone!\n");
if (!request_mem_region(res->start, resource_size(res),
@@ -1650,22 +1656,21 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
pr_err("%s: ERROR: memory allocation failed"
"cannot get the I/O addr 0x%x\n",
__func__, (unsigned int)res->start);
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
addr = ioremap(res->start, resource_size(res));
if (!addr) {
pr_err("%s: ERROR: memory mapping failed\n", __func__);
ret = -ENOMEM;
- goto out;
+ goto out_release_region;
}
ndev = alloc_etherdev(sizeof(struct stmmac_priv));
if (!ndev) {
pr_err("%s: ERROR: allocating the device\n", __func__);
ret = -ENOMEM;
- goto out;
+ goto out_unmap;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
@@ -1675,21 +1680,17 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
if (ndev->irq == -ENXIO) {
pr_err("%s: ERROR: MAC IRQ configuration "
"information not found\n", __func__);
- ret = -ENODEV;
- goto out;
+ ret = -ENXIO;
+ goto out_free_ndev;
}
priv = netdev_priv(ndev);
priv->device = &(pdev->dev);
priv->dev = ndev;
plat_dat = pdev->dev.platform_data;
- priv->bus_id = plat_dat->bus_id;
- priv->pbl = plat_dat->pbl; /* TLI */
- priv->mii_clk_csr = plat_dat->clk_csr;
- priv->tx_coe = plat_dat->tx_coe;
- priv->bugged_jumbo = plat_dat->bugged_jumbo;
- priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */
- priv->enh_desc = plat_dat->enh_desc;
+
+ priv->plat = plat_dat;
+
priv->ioaddr = addr;
/* PMT module is not integrated in all the MAC devices. */
@@ -1703,20 +1704,22 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
/* Set the I/O base addr */
ndev->base_addr = (unsigned long)addr;
- /* Verify embedded resource for the platform */
- ret = stmmac_claim_resource(pdev);
- if (ret < 0)
- goto out;
+ /* Custom initialisation */
+ if (priv->plat->init) {
+ ret = priv->plat->init(pdev);
+ if (unlikely(ret))
+ goto out_free_ndev;
+ }
/* MAC HW revice detection */
ret = stmmac_mac_device_setup(ndev);
if (ret < 0)
- goto out;
+ goto out_plat_exit;
/* Network Device Registration */
ret = stmmac_probe(ndev);
if (ret < 0)
- goto out;
+ goto out_plat_exit;
/* associate a PHY - it is provided by another platform bus */
if (!driver_for_each_device
@@ -1724,31 +1727,33 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
stmmac_associate_phy)) {
pr_err("No PHY device is associated with this MAC!\n");
ret = -ENODEV;
- goto out;
+ goto out_unregister;
}
- priv->fix_mac_speed = plat_dat->fix_mac_speed;
- priv->bus_setup = plat_dat->bus_setup;
- priv->bsp_priv = plat_dat->bsp_priv;
-
pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
"\tIO base addr: 0x%p)\n", ndev->name, pdev->name,
pdev->id, ndev->irq, addr);
/* MDIO bus Registration */
- pr_debug("\tMDIO bus (id: %d)...", priv->bus_id);
+ pr_debug("\tMDIO bus (id: %d)...", priv->plat->bus_id);
ret = stmmac_mdio_register(ndev);
if (ret < 0)
- goto out;
+ goto out_unregister;
pr_debug("registered!\n");
+ return 0;
-out:
- if (ret < 0) {
- platform_set_drvdata(pdev, NULL);
- release_mem_region(res->start, resource_size(res));
- if (addr != NULL)
- iounmap(addr);
- }
+out_unregister:
+ unregister_netdev(ndev);
+out_plat_exit:
+ if (priv->plat->exit)
+ priv->plat->exit(pdev);
+out_free_ndev:
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+out_unmap:
+ iounmap(addr);
+out_release_region:
+ release_mem_region(res->start, resource_size(res));
return ret;
}
@@ -1777,6 +1782,9 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
stmmac_mdio_unregister(ndev);
+ if (priv->plat->exit)
+ priv->plat->exit(pdev);
+
platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
@@ -1790,69 +1798,54 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
+static int stmmac_suspend(struct device *dev)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct stmmac_priv *priv = netdev_priv(dev);
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
int dis_ic = 0;
- if (!dev || !netif_running(dev))
+ if (!ndev || !netif_running(ndev))
return 0;
spin_lock(&priv->lock);
- if (state.event == PM_EVENT_SUSPEND) {
- netif_device_detach(dev);
- netif_stop_queue(dev);
- if (priv->phydev)
- phy_stop(priv->phydev);
+ netif_device_detach(ndev);
+ netif_stop_queue(ndev);
+ if (priv->phydev)
+ phy_stop(priv->phydev);
#ifdef CONFIG_STMMAC_TIMER
- priv->tm->timer_stop();
- if (likely(priv->tm->enable))
- dis_ic = 1;
+ priv->tm->timer_stop();
+ if (likely(priv->tm->enable))
+ dis_ic = 1;
#endif
- napi_disable(&priv->napi);
-
- /* Stop TX/RX DMA */
- priv->hw->dma->stop_tx(priv->ioaddr);
- priv->hw->dma->stop_rx(priv->ioaddr);
- /* Clear the Rx/Tx descriptors */
- priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
- dis_ic);
- priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
-
- /* Enable Power down mode by programming the PMT regs */
- if (device_can_wakeup(priv->device))
- priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
- else
- stmmac_disable_mac(priv->ioaddr);
- } else {
- priv->shutdown = 1;
- /* Although this can appear slightly redundant it actually
- * makes fast the standby operation and guarantees the driver
- * working if hibernation is on media. */
- stmmac_release(dev);
- }
+ napi_disable(&priv->napi);
+
+ /* Stop TX/RX DMA */
+ priv->hw->dma->stop_tx(priv->ioaddr);
+ priv->hw->dma->stop_rx(priv->ioaddr);
+ /* Clear the Rx/Tx descriptors */
+ priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
+ dis_ic);
+ priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+
+ /* Enable Power down mode by programming the PMT regs */
+ if (device_may_wakeup(priv->device))
+ priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
+ else
+ stmmac_disable_mac(priv->ioaddr);
spin_unlock(&priv->lock);
return 0;
}
-static int stmmac_resume(struct platform_device *pdev)
+static int stmmac_resume(struct device *dev)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct stmmac_priv *priv = netdev_priv(dev);
-
- if (!netif_running(dev))
- return 0;
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
- if (priv->shutdown) {
- /* Re-open the interface and re-init the MAC/DMA
- and the rings (i.e. on hibernation stage) */
- stmmac_open(dev);
+ if (!netif_running(ndev))
return 0;
- }
spin_lock(&priv->lock);
@@ -1861,10 +1854,10 @@ static int stmmac_resume(struct platform_device *pdev)
* is received. Anyway, it's better to manually clear
* this bit because it can generate problems while resuming
* from another devices (e.g. serial console). */
- if (device_can_wakeup(priv->device))
+ if (device_may_wakeup(priv->device))
priv->hw->mac->pmt(priv->ioaddr, 0);
- netif_device_attach(dev);
+ netif_device_attach(ndev);
/* Enable the MAC and DMA */
stmmac_enable_mac(priv->ioaddr);
@@ -1872,31 +1865,59 @@ static int stmmac_resume(struct platform_device *pdev)
priv->hw->dma->start_rx(priv->ioaddr);
#ifdef CONFIG_STMMAC_TIMER
- priv->tm->timer_start(tmrate);
+ if (likely(priv->tm->enable))
+ priv->tm->timer_start(tmrate);
#endif
napi_enable(&priv->napi);
if (priv->phydev)
phy_start(priv->phydev);
- netif_start_queue(dev);
+ netif_start_queue(ndev);
spin_unlock(&priv->lock);
return 0;
}
-#endif
-static struct platform_driver stmmac_driver = {
- .driver = {
- .name = STMMAC_RESOURCE_NAME,
- },
- .probe = stmmac_dvr_probe,
- .remove = stmmac_dvr_remove,
-#ifdef CONFIG_PM
+static int stmmac_freeze(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ if (!ndev || !netif_running(ndev))
+ return 0;
+
+ return stmmac_release(ndev);
+}
+
+static int stmmac_restore(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+
+ if (!ndev || !netif_running(ndev))
+ return 0;
+
+ return stmmac_open(ndev);
+}
+
+static const struct dev_pm_ops stmmac_pm_ops = {
.suspend = stmmac_suspend,
.resume = stmmac_resume,
-#endif
+ .freeze = stmmac_freeze,
+ .thaw = stmmac_restore,
+ .restore = stmmac_restore,
+};
+#else
+static const struct dev_pm_ops stmmac_pm_ops;
+#endif /* CONFIG_PM */
+static struct platform_driver stmmac_driver = {
+ .probe = stmmac_dvr_probe,
+ .remove = stmmac_dvr_remove,
+ .driver = {
+ .name = STMMAC_RESOURCE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &stmmac_pm_ops,
+ },
};
/**
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c
index d7441616357d..234b4068a1fc 100644
--- a/drivers/net/stmmac/stmmac_mdio.c
+++ b/drivers/net/stmmac/stmmac_mdio.c
@@ -53,7 +53,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
int data;
u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
((phyreg << 6) & (0x000007C0)));
- regValue |= MII_BUSY | ((priv->mii_clk_csr & 7) << 2);
+ regValue |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2);
do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
writel(regValue, priv->ioaddr + mii_address);
@@ -85,7 +85,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
(((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
| MII_WRITE;
- value |= MII_BUSY | ((priv->mii_clk_csr & 7) << 2);
+ value |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2);
/* Wait until any existing MII operation is complete */
@@ -114,7 +114,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
if (priv->phy_reset) {
pr_debug("stmmac_mdio_reset: calling phy_reset\n");
- priv->phy_reset(priv->bsp_priv);
+ priv->phy_reset(priv->plat->bsp_priv);
}
/* This is a workaround for problems with the STE101P PHY.
@@ -157,7 +157,7 @@ int stmmac_mdio_register(struct net_device *ndev)
new_bus->read = &stmmac_mdio_read;
new_bus->write = &stmmac_mdio_write;
new_bus->reset = &stmmac_mdio_reset;
- snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
new_bus->priv = ndev;
new_bus->irq = irqlist;
new_bus->phy_mask = priv->phy_mask;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 3ed2a67bd6d3..4793df843c24 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -294,6 +294,9 @@ enum alta_offsets {
/* Aliased and bogus values! */
RxStatus = 0x0c,
};
+
+#define ASIC_HI_WORD(x) ((x) + 2)
+
enum ASICCtrl_HiWord_bit {
GlobalReset = 0x0001,
RxReset = 0x0002,
@@ -431,6 +434,7 @@ static void netdev_error(struct net_device *dev, int intr_status);
static void netdev_error(struct net_device *dev, int intr_status);
static void set_rx_mode(struct net_device *dev);
static int __set_mac_addr(struct net_device *dev);
+static int sundance_set_mac_addr(struct net_device *dev, void *data);
static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
@@ -464,7 +468,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = tx_timeout,
.ndo_change_mtu = change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = sundance_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -1016,7 +1020,7 @@ static void init_ring(struct net_device *dev)
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2);
np->rx_skbuff[i] = skb;
if (skb == NULL)
break;
@@ -1407,7 +1411,7 @@ static void refill_rx (struct net_device *dev)
struct sk_buff *skb;
entry = np->dirty_rx % RX_RING_SIZE;
if (np->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb(np->rx_buf_sz);
+ skb = dev_alloc_skb(np->rx_buf_sz + 2);
np->rx_skbuff[entry] = skb;
if (skb == NULL)
break; /* Better luck next round. */
@@ -1592,6 +1596,19 @@ static int __set_mac_addr(struct net_device *dev)
return 0;
}
+/* Invoked with rtnl_lock held */
+static int sundance_set_mac_addr(struct net_device *dev, void *data)
+{
+ const struct sockaddr *addr = data;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+ __set_mac_addr(dev);
+
+ return 0;
+}
+
static const struct {
const char name[ETH_GSTRING_LEN];
} sundance_stats[] = {
@@ -1772,10 +1789,10 @@ static int netdev_close(struct net_device *dev)
}
iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
- ioaddr +ASICCtrl + 2);
+ ioaddr + ASIC_HI_WORD(ASICCtrl));
for (i = 2000; i > 0; i--) {
- if ((ioread16(ioaddr + ASICCtrl +2) & ResetBusy) == 0)
+ if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0)
break;
mdelay(1);
}
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 4ceb3cf6a9a9..1c5408f83937 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1004,7 +1004,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
ctrl = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const u64 csum_start_off = skb_transport_offset(skb);
+ const u64 csum_start_off = skb_checksum_start_offset(skb);
const u64 csum_stuff_off = csum_start_off + skb->csum_offset;
ctrl = (TXDCTRL_CENAB |
@@ -2380,10 +2380,8 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
*/
mutex_unlock(&gp->pm_mutex);
- /* Wait for a pending reset task to complete */
- while (gp->reset_task_pending)
- yield();
- flush_scheduled_work();
+ /* Wait for the pending reset task to complete */
+ flush_work_sync(&gp->reset_task);
/* Shut the PHY down eventually and setup WOL */
gem_stop_phy(gp, gp->asleep_wol);
@@ -2928,10 +2926,8 @@ static void gem_remove_one(struct pci_dev *pdev)
/* We shouldn't need any locking here */
gem_get_cell(gp);
- /* Wait for a pending reset task to complete */
- while (gp->reset_task_pending)
- yield();
- flush_scheduled_work();
+ /* Cancel reset task */
+ cancel_work_sync(&gp->reset_task);
/* Shut the PHY down */
gem_stop_phy(gp, 0);
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 5e28c414421a..55bbb9c15d96 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2266,7 +2266,7 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
tx_flags = TXFLAG_OWN;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const u32 csum_start_off = skb_transport_offset(skb);
+ const u32 csum_start_off = skb_checksum_start_offset(skb);
const u32 csum_stuff_off = csum_start_off + skb->csum_offset;
tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE |
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 2cf84e5968b2..767e1e2b210d 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1295,17 +1295,9 @@ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvin
strcpy(info->version, "2.02");
}
-static u32 sparc_lance_get_link(struct net_device *dev)
-{
- /* We really do not keep track of this, but this
- * is better than not reporting anything at all.
- */
- return 1;
-}
-
static const struct ethtool_ops sparc_lance_ethtool_ops = {
.get_drvinfo = sparc_lance_get_drvinfo,
- .get_link = sparc_lance_get_link,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops sparc_lance_ops = {
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 8b3dc1eb4015..3397618d4d96 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -12,7 +12,7 @@
/*
* RX HW/SW interaction overview
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * There are 2 types of RX communication channels betwean driver and NIC.
+ * There are 2 types of RX communication channels between 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
@@ -324,7 +324,7 @@ static int bdx_fw_load(struct bdx_priv *priv)
ENTER;
master = READ_REG(priv, regINIT_SEMAPHORE);
if (!READ_REG(priv, regINIT_STATUS) && master) {
- rc = request_firmware(&fw, "tehuti/firmware.bin", &priv->pdev->dev);
+ rc = request_firmware(&fw, "tehuti/bdx.bin", &priv->pdev->dev);
if (rc)
goto out;
bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size);
@@ -821,7 +821,7 @@ static void bdx_setmulti(struct net_device *ndev)
}
/* use PMF to accept first MAC_MCST_NUM (15) addresses */
- /* TBD: sort addreses and write them in ascending order
+ /* TBD: sort addresses and write them in ascending order
* into RX_MAC_MCST regs. we skip this phase now and accept ALL
* multicast frames throu IMF */
/* accept the rest of addresses throu IMF */
@@ -1346,7 +1346,7 @@ static void print_rxfd(struct rxf_desc *rxfd)
/*
* TX HW/SW interaction overview
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * There are 2 types of TX communication channels betwean driver and NIC.
+ * There are 2 types of TX communication channels between driver and NIC.
* 1) TX Free Fifo - TXF - holds ack descriptors for sent packets
* 2) TX Data Fifo - TXD - holds descriptors of full buffers.
*
@@ -2510,4 +2510,4 @@ module_exit(bdx_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(BDX_DRV_DESC);
-MODULE_FIRMWARE("tehuti/firmware.bin");
+MODULE_FIRMWARE("tehuti/bdx.bin");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 30ccbb6d097a..7841a8f69998 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -32,6 +32,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
+#include <linux/mdio.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/brcmphy.h>
@@ -69,10 +70,10 @@
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 115
+#define TG3_MIN_NUM 116
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "October 14, 2010"
+#define DRV_MODULE_RELDATE "December 3, 2010"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -1769,9 +1770,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
if (tp->link_config.autoneg == AUTONEG_ENABLE &&
current_link_up == 1 &&
- (tp->link_config.active_speed == SPEED_1000 ||
- (tp->link_config.active_speed == SPEED_100 &&
- tp->link_config.active_duplex == DUPLEX_FULL))) {
+ tp->link_config.active_duplex == DUPLEX_FULL &&
+ (tp->link_config.active_speed == SPEED_100 ||
+ tp->link_config.active_speed == SPEED_1000)) {
u32 eeectl;
if (tp->link_config.active_speed == SPEED_1000)
@@ -1781,7 +1782,8 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
tw32(TG3_CPMU_EEE_CTRL, eeectl);
- tg3_phy_cl45_read(tp, 0x7, TG3_CL45_D7_EEERES_STAT, &val);
+ tg3_phy_cl45_read(tp, MDIO_MMD_AN,
+ TG3_CL45_D7_EEERES_STAT, &val);
if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
@@ -2549,39 +2551,35 @@ static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
tw32(MAC_TX_BACKOFF_SEED, addr_high);
}
-static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
+static void tg3_enable_register_access(struct tg3 *tp)
{
- u32 misc_host_ctrl;
- bool device_should_wake, do_low_power;
-
- /* Make sure register accesses (indirect or otherwise)
- * will function correctly.
+ /*
+ * Make sure register accesses (indirect or otherwise) will function
+ * correctly.
*/
pci_write_config_dword(tp->pdev,
- TG3PCI_MISC_HOST_CTRL,
- tp->misc_host_ctrl);
+ TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+}
- switch (state) {
- case PCI_D0:
- pci_enable_wake(tp->pdev, state, false);
- pci_set_power_state(tp->pdev, PCI_D0);
+static int tg3_power_up(struct tg3 *tp)
+{
+ tg3_enable_register_access(tp);
- /* Switch out of Vaux if it is a NIC */
- if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
- tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100);
+ pci_set_power_state(tp->pdev, PCI_D0);
- return 0;
+ /* Switch out of Vaux if it is a NIC */
+ if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
+ tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100);
- case PCI_D1:
- case PCI_D2:
- case PCI_D3hot:
- break;
+ return 0;
+}
- default:
- netdev_err(tp->dev, "Invalid power state (D%d) requested\n",
- state);
- return -EINVAL;
- }
+static int tg3_power_down_prepare(struct tg3 *tp)
+{
+ u32 misc_host_ctrl;
+ bool device_should_wake, do_low_power;
+
+ tg3_enable_register_access(tp);
/* Restore the CLKREQ setting. */
if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) {
@@ -2600,8 +2598,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tw32(TG3PCI_MISC_HOST_CTRL,
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
- device_should_wake = pci_pme_capable(tp->pdev, state) &&
- device_may_wakeup(&tp->pdev->dev) &&
+ device_should_wake = device_may_wakeup(&tp->pdev->dev) &&
(tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
@@ -2728,12 +2725,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)))
mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
- mac_mode |= tp->mac_mode &
- (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
- if (mac_mode & MAC_MODE_APE_TX_EN)
- mac_mode |= MAC_MODE_TDE_ENABLE;
- }
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ mac_mode |= MAC_MODE_APE_TX_EN |
+ MAC_MODE_APE_RX_EN |
+ MAC_MODE_TDE_ENABLE;
tw32_f(MAC_MODE, mac_mode);
udelay(100);
@@ -2823,13 +2818,15 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
- if (device_should_wake)
- pci_enable_wake(tp->pdev, state, true);
+ return 0;
+}
- /* Finally, set the new power state. */
- pci_set_power_state(tp->pdev, state);
+static void tg3_power_down(struct tg3 *tp)
+{
+ tg3_power_down_prepare(tp);
- return 0;
+ pci_wake_from_d3(tp->pdev, tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
+ pci_set_power_state(tp->pdev, PCI_D3hot);
}
static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
@@ -2969,7 +2966,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
}
if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
- u32 val = 0;
+ u32 val;
tw32(TG3_CPMU_EEE_MODE,
tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
@@ -2986,19 +2983,18 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2,
val | MII_TG3_DSP_CH34TP2_HIBW01);
+ val = 0;
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
/* Advertise 100-BaseTX EEE ability */
if (tp->link_config.advertising &
- (ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full))
- val |= TG3_CL45_D7_EEEADV_CAP_100TX;
+ ADVERTISED_100baseT_Full)
+ val |= MDIO_AN_EEE_ADV_100TX;
/* Advertise 1000-BaseT EEE ability */
if (tp->link_config.advertising &
- (ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full))
- val |= TG3_CL45_D7_EEEADV_CAP_1000T;
+ ADVERTISED_1000baseT_Full)
+ val |= MDIO_AN_EEE_ADV_1000T;
}
- tg3_phy_cl45_write(tp, 0x7, TG3_CL45_D7_EEEADV_CAP, val);
+ tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
/* Turn off SM_DSP clock. */
val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
@@ -5763,7 +5759,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
- !mss && skb->len > ETH_DATA_LEN)
+ !mss && skb->len > VLAN_ETH_FRAME_LEN)
base_flags |= TXD_FLAG_JMB_PKT;
tg3_set_txd(tnapi, entry, mapping, len, base_flags,
@@ -5997,7 +5993,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
#endif
if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
- !mss && skb->len > ETH_DATA_LEN)
+ !mss && skb->len > VLAN_ETH_FRAME_LEN)
base_flags |= TXD_FLAG_JMB_PKT;
len = skb_headlen(skb);
@@ -6339,13 +6335,13 @@ static void tg3_rx_prodring_fini(struct tg3 *tp,
kfree(tpr->rx_jmb_buffers);
tpr->rx_jmb_buffers = NULL;
if (tpr->rx_std) {
- pci_free_consistent(tp->pdev, TG3_RX_STD_RING_BYTES(tp),
- tpr->rx_std, tpr->rx_std_mapping);
+ dma_free_coherent(&tp->pdev->dev, TG3_RX_STD_RING_BYTES(tp),
+ tpr->rx_std, tpr->rx_std_mapping);
tpr->rx_std = NULL;
}
if (tpr->rx_jmb) {
- pci_free_consistent(tp->pdev, TG3_RX_JMB_RING_BYTES(tp),
- tpr->rx_jmb, tpr->rx_jmb_mapping);
+ dma_free_coherent(&tp->pdev->dev, TG3_RX_JMB_RING_BYTES(tp),
+ tpr->rx_jmb, tpr->rx_jmb_mapping);
tpr->rx_jmb = NULL;
}
}
@@ -6358,8 +6354,10 @@ static int tg3_rx_prodring_init(struct tg3 *tp,
if (!tpr->rx_std_buffers)
return -ENOMEM;
- tpr->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_STD_RING_BYTES(tp),
- &tpr->rx_std_mapping);
+ tpr->rx_std = dma_alloc_coherent(&tp->pdev->dev,
+ TG3_RX_STD_RING_BYTES(tp),
+ &tpr->rx_std_mapping,
+ GFP_KERNEL);
if (!tpr->rx_std)
goto err_out;
@@ -6370,9 +6368,10 @@ static int tg3_rx_prodring_init(struct tg3 *tp,
if (!tpr->rx_jmb_buffers)
goto err_out;
- tpr->rx_jmb = pci_alloc_consistent(tp->pdev,
- TG3_RX_JMB_RING_BYTES(tp),
- &tpr->rx_jmb_mapping);
+ tpr->rx_jmb = dma_alloc_coherent(&tp->pdev->dev,
+ TG3_RX_JMB_RING_BYTES(tp),
+ &tpr->rx_jmb_mapping,
+ GFP_KERNEL);
if (!tpr->rx_jmb)
goto err_out;
}
@@ -6491,7 +6490,7 @@ static void tg3_free_consistent(struct tg3 *tp)
struct tg3_napi *tnapi = &tp->napi[i];
if (tnapi->tx_ring) {
- pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES,
+ dma_free_coherent(&tp->pdev->dev, TG3_TX_RING_BYTES,
tnapi->tx_ring, tnapi->tx_desc_mapping);
tnapi->tx_ring = NULL;
}
@@ -6500,25 +6499,26 @@ static void tg3_free_consistent(struct tg3 *tp)
tnapi->tx_buffers = NULL;
if (tnapi->rx_rcb) {
- pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp),
- tnapi->rx_rcb,
- tnapi->rx_rcb_mapping);
+ dma_free_coherent(&tp->pdev->dev,
+ TG3_RX_RCB_RING_BYTES(tp),
+ tnapi->rx_rcb,
+ tnapi->rx_rcb_mapping);
tnapi->rx_rcb = NULL;
}
tg3_rx_prodring_fini(tp, &tnapi->prodring);
if (tnapi->hw_status) {
- pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE,
- tnapi->hw_status,
- tnapi->status_mapping);
+ dma_free_coherent(&tp->pdev->dev, TG3_HW_STATUS_SIZE,
+ tnapi->hw_status,
+ tnapi->status_mapping);
tnapi->hw_status = NULL;
}
}
if (tp->hw_stats) {
- pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats),
- tp->hw_stats, tp->stats_mapping);
+ dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
+ tp->hw_stats, tp->stats_mapping);
tp->hw_stats = NULL;
}
}
@@ -6531,9 +6531,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
{
int i;
- tp->hw_stats = pci_alloc_consistent(tp->pdev,
- sizeof(struct tg3_hw_stats),
- &tp->stats_mapping);
+ tp->hw_stats = dma_alloc_coherent(&tp->pdev->dev,
+ sizeof(struct tg3_hw_stats),
+ &tp->stats_mapping,
+ GFP_KERNEL);
if (!tp->hw_stats)
goto err_out;
@@ -6543,9 +6544,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
struct tg3_napi *tnapi = &tp->napi[i];
struct tg3_hw_status *sblk;
- tnapi->hw_status = pci_alloc_consistent(tp->pdev,
- TG3_HW_STATUS_SIZE,
- &tnapi->status_mapping);
+ tnapi->hw_status = dma_alloc_coherent(&tp->pdev->dev,
+ TG3_HW_STATUS_SIZE,
+ &tnapi->status_mapping,
+ GFP_KERNEL);
if (!tnapi->hw_status)
goto err_out;
@@ -6566,9 +6568,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
if (!tnapi->tx_buffers)
goto err_out;
- tnapi->tx_ring = pci_alloc_consistent(tp->pdev,
- TG3_TX_RING_BYTES,
- &tnapi->tx_desc_mapping);
+ tnapi->tx_ring = dma_alloc_coherent(&tp->pdev->dev,
+ TG3_TX_RING_BYTES,
+ &tnapi->tx_desc_mapping,
+ GFP_KERNEL);
if (!tnapi->tx_ring)
goto err_out;
}
@@ -6601,9 +6604,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS))
continue;
- tnapi->rx_rcb = pci_alloc_consistent(tp->pdev,
- TG3_RX_RCB_RING_BYTES(tp),
- &tnapi->rx_rcb_mapping);
+ tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev,
+ TG3_RX_RCB_RING_BYTES(tp),
+ &tnapi->rx_rcb_mapping,
+ GFP_KERNEL);
if (!tnapi->rx_rcb)
goto err_out;
@@ -6987,7 +6991,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
- pcie_set_readrq(tp->pdev, 4096);
+ pcie_set_readrq(tp->pdev, tp->pcie_readrq);
else {
pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
tp->pci_cacheline_sz);
@@ -7181,7 +7185,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tp->pcie_cap + PCI_EXP_DEVCTL,
val16);
- pcie_set_readrq(tp->pdev, 4096);
+ pcie_set_readrq(tp->pdev, tp->pcie_readrq);
/* Clear error status */
pci_write_config_word(tp->pdev,
@@ -7222,19 +7226,21 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ tp->mac_mode = MAC_MODE_APE_TX_EN |
+ MAC_MODE_APE_RX_EN |
+ MAC_MODE_TDE_ENABLE;
+
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
- tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
- tw32_f(MAC_MODE, tp->mac_mode);
+ tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+ val = tp->mac_mode;
} else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
- tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
- tw32_f(MAC_MODE, tp->mac_mode);
- } else if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
- tp->mac_mode &= (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
- if (tp->mac_mode & MAC_MODE_APE_TX_EN)
- tp->mac_mode |= MAC_MODE_TDE_ENABLE;
- tw32_f(MAC_MODE, tp->mac_mode);
+ tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ val = tp->mac_mode;
} else
- tw32_f(MAC_MODE, 0);
+ val = 0;
+
+ tw32_f(MAC_MODE, val);
udelay(40);
tg3_ape_unlock(tp, TG3_APE_LOCK_GRC);
@@ -7801,6 +7807,37 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
tg3_abort_hw(tp, 1);
+ /* Enable MAC control of LPI */
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+ tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
+ TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+ TG3_CPMU_EEE_LNKIDL_UART_IDL);
+
+ tw32_f(TG3_CPMU_EEE_CTRL,
+ TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+ val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+ TG3_CPMU_EEEMD_LPI_IN_TX |
+ TG3_CPMU_EEEMD_LPI_IN_RX |
+ TG3_CPMU_EEEMD_EEE_ENABLE;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
+
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
+
+ tw32_f(TG3_CPMU_EEE_MODE, val);
+
+ tw32_f(TG3_CPMU_EEE_DBTMR1,
+ TG3_CPMU_DBTMR1_PCIEXIT_2047US |
+ TG3_CPMU_DBTMR1_LNKIDLE_2047US);
+
+ tw32_f(TG3_CPMU_EEE_DBTMR2,
+ TG3_CPMU_DBTMR1_APE_TX_2047US |
+ TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
+ }
+
if (reset_phy)
tg3_phy_reset(tp);
@@ -7860,18 +7897,21 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(GRC_MODE, grc_mode);
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
- u32 grc_mode = tr32(GRC_MODE);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+ u32 grc_mode = tr32(GRC_MODE);
- /* Access the lower 1K of PL PCIE block registers. */
- val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
- tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
+ /* Access the lower 1K of PL PCIE block registers. */
+ val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+ tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
- val = tr32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL5);
- tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL5,
- val | TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ);
+ val = tr32(TG3_PCIE_TLDLPL_PORT +
+ TG3_PCIE_PL_LO_PHYCTL5);
+ tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL5,
+ val | TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ);
- tw32(GRC_MODE, grc_mode);
+ tw32(GRC_MODE, grc_mode);
+ }
val = tr32(TG3_CPMU_LSPD_10MB_CLK);
val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
@@ -7879,22 +7919,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_CPMU_LSPD_10MB_CLK, val);
}
- /* Enable MAC control of LPI */
- if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
- tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
- TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
- TG3_CPMU_EEE_LNKIDL_UART_IDL);
-
- tw32_f(TG3_CPMU_EEE_CTRL,
- TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
-
- tw32_f(TG3_CPMU_EEE_MODE,
- TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
- TG3_CPMU_EEEMD_LPI_IN_TX |
- TG3_CPMU_EEEMD_LPI_IN_RX |
- TG3_CPMU_EEEMD_EEE_ENABLE);
- }
-
/* 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
@@ -8162,8 +8186,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
@@ -8203,6 +8226,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
val = tr32(TG3_RDMA_RSRVCTRL_REG);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ val &= ~TG3_RDMA_RSRVCTRL_TXMRGN_MASK;
+ val |= TG3_RDMA_RSRVCTRL_TXMRGN_320B;
+ }
tw32(TG3_RDMA_RSRVCTRL_REG,
val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
}
@@ -8280,7 +8307,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
- tp->mac_mode &= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+ tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
else
tp->mac_mode = 0;
tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
@@ -9031,8 +9058,14 @@ static bool tg3_enable_msix(struct tg3 *tp)
pci_disable_msix(tp->pdev);
return false;
}
- if (tp->irq_cnt > 1)
+
+ if (tp->irq_cnt > 1) {
tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
+ netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1);
+ }
+ }
return true;
}
@@ -9101,7 +9134,7 @@ static int tg3_open(struct net_device *dev)
netif_carrier_off(tp->dev);
- err = tg3_set_power_state(tp, PCI_D0);
+ err = tg3_power_up(tp);
if (err)
return err;
@@ -9266,7 +9299,7 @@ static int tg3_close(struct net_device *dev)
tg3_free_consistent(tp);
- tg3_set_power_state(tp, PCI_D3hot);
+ tg3_power_down(tp);
netif_carrier_off(tp->dev);
@@ -11068,7 +11101,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
struct tg3 *tp = netdev_priv(dev);
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
- tg3_set_power_state(tp, PCI_D0);
+ tg3_power_up(tp);
memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
@@ -11136,7 +11169,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_phy_start(tp);
}
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
- tg3_set_power_state(tp, PCI_D3hot);
+ tg3_power_down(tp);
}
@@ -12411,8 +12444,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (cfg2 & (1 << 18))
tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
- if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
- GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) &&
+ if (((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) ||
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+ GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) &&
(cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
@@ -12548,9 +12582,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
}
- if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pci_chip_rev_id != CHIPREV_ID_57765_A0))
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+ ((tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
@@ -12658,7 +12694,7 @@ static void __devinit tg3_read_vpd(struct tg3 *tp)
cnt = pci_read_vpd(tp->pdev, pos,
TG3_NVM_VPD_LEN - pos,
&vpd_data[pos]);
- if (cnt == -ETIMEDOUT || -EINTR)
+ if (cnt == -ETIMEDOUT || cnt == -EINTR)
cnt = 0;
else if (cnt < 0)
goto out_not_found;
@@ -13047,17 +13083,15 @@ static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
return 512;
}
+DEFINE_PCI_DEVICE_TABLE(write_reorder_chipsets) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8385_0) },
+ { },
+};
+
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
- static struct pci_device_id write_reorder_chipsets[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD_FE_GATE_700C) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD_8131_BRIDGE) },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_8385_0) },
- { },
- };
u32 misc_ctrl_reg;
u32 pci_state_reg, grc_misc_cfg;
u32 val;
@@ -13359,7 +13393,45 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
- pcie_set_readrq(tp->pdev, 4096);
+ tp->pcie_readrq = 4096;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ u16 word;
+
+ pci_read_config_word(tp->pdev,
+ tp->pcie_cap + PCI_EXP_LNKSTA,
+ &word);
+ switch (word & PCI_EXP_LNKSTA_CLS) {
+ case PCI_EXP_LNKSTA_CLS_2_5GB:
+ word &= PCI_EXP_LNKSTA_NLW;
+ word >>= PCI_EXP_LNKSTA_NLW_SHIFT;
+ switch (word) {
+ case 2:
+ tp->pcie_readrq = 2048;
+ break;
+ case 4:
+ tp->pcie_readrq = 1024;
+ break;
+ }
+ break;
+
+ case PCI_EXP_LNKSTA_CLS_5_0GB:
+ word &= PCI_EXP_LNKSTA_NLW;
+ word >>= PCI_EXP_LNKSTA_NLW_SHIFT;
+ switch (word) {
+ case 1:
+ tp->pcie_readrq = 2048;
+ break;
+ case 2:
+ tp->pcie_readrq = 1024;
+ break;
+ case 4:
+ tp->pcie_readrq = 512;
+ break;
+ }
+ }
+ }
+
+ pcie_set_readrq(tp->pdev, tp->pcie_readrq);
pci_read_config_word(tp->pdev,
tp->pcie_cap + PCI_EXP_LNKCTL,
@@ -13546,7 +13618,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
(tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
- /* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
+ /* Set up tp->grc_local_ctrl before calling tg_power_up().
* GPIO1 driven high will bring 5700's external PHY out of reset.
* It is also used as eeprom write protect on LOMs.
*/
@@ -13577,7 +13649,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
/* Force the chip into D0. */
- err = tg3_set_power_state(tp, PCI_D0);
+ err = tg3_power_up(tp);
if (err) {
dev_err(&tp->pdev->dev, "Transition to D0 failed\n");
return err;
@@ -13722,8 +13794,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Preserve the APE MAC_MODE bits */
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
- tp->mac_mode = tr32(MAC_MODE) |
- MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+ tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
else
tp->mac_mode = TG3_DEF_MAC_MODE;
@@ -14153,13 +14224,19 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm
#define TEST_BUFFER_SIZE 0x2000
+DEFINE_PCI_DEVICE_TABLE(dma_wait_state_chipsets) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_PCI15) },
+ { },
+};
+
static int __devinit tg3_test_dma(struct tg3 *tp)
{
dma_addr_t buf_dma;
u32 *buf, saved_dma_rwctrl;
int ret = 0;
- buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma);
+ buf = dma_alloc_coherent(&tp->pdev->dev, TEST_BUFFER_SIZE,
+ &buf_dma, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out_nofree;
@@ -14321,11 +14398,6 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
}
if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
DMA_RWCTRL_WRITE_BNDRY_16) {
- static struct pci_device_id dma_wait_state_chipsets[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_APPLE,
- PCI_DEVICE_ID_APPLE_UNI_N_PCI15) },
- { },
- };
/* DMA test passed without adjusting DMA boundary,
* now look for chipsets that are known to expose the
@@ -14343,7 +14415,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
}
out:
- pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
+ dma_free_coherent(&tp->pdev->dev, TEST_BUFFER_SIZE, buf, buf_dma);
out_nofree:
return ret;
}
@@ -14957,7 +15029,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (tp->fw)
release_firmware(tp->fw);
- flush_scheduled_work();
+ cancel_work_sync(&tp->reset_task);
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
tg3_phy_fini(tp);
@@ -14980,23 +15052,18 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
}
}
-static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tg3_suspend(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct tg3 *tp = netdev_priv(dev);
- pci_power_t target_state;
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;
- flush_scheduled_work();
+ flush_work_sync(&tp->reset_task);
tg3_phy_stop(tp);
tg3_netif_stop(tp);
@@ -15013,9 +15080,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_full_unlock(tp);
- target_state = pdev->pm_cap ? pci_target_state(pdev) : PCI_D3hot;
-
- err = tg3_set_power_state(tp, target_state);
+ err = tg3_power_down_prepare(tp);
if (err) {
int err2;
@@ -15042,21 +15107,16 @@ out:
return err;
}
-static int tg3_resume(struct pci_dev *pdev)
+static int tg3_resume(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct tg3 *tp = netdev_priv(dev);
int err;
- pci_restore_state(tp->pdev);
-
if (!netif_running(dev))
return 0;
- err = tg3_set_power_state(tp, PCI_D0);
- if (err)
- return err;
-
netif_device_attach(dev);
tg3_full_lock(tp, 0);
@@ -15080,13 +15140,21 @@ out:
return err;
}
+static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
+#define TG3_PM_OPS (&tg3_pm_ops)
+
+#else
+
+#define TG3_PM_OPS NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
static struct pci_driver tg3_driver = {
.name = DRV_MODULE_NAME,
.id_table = tg3_pci_tbl,
.probe = tg3_init_one,
.remove = __devexit_p(tg3_remove_one),
- .suspend = tg3_suspend,
- .resume = tg3_resume
+ .driver.pm = TG3_PM_OPS,
};
static int __init tg3_init(void)
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 4a1974804b9f..d62c8d937c82 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1094,13 +1094,19 @@
/* 0x3664 --> 0x36b0 unused */
#define TG3_CPMU_EEE_MODE 0x000036b0
-#define TG3_CPMU_EEEMD_ERLY_L1_XIT_DET 0x00000008
-#define TG3_CPMU_EEEMD_LPI_ENABLE 0x00000080
-#define TG3_CPMU_EEEMD_LPI_IN_TX 0x00000100
-#define TG3_CPMU_EEEMD_LPI_IN_RX 0x00000200
-#define TG3_CPMU_EEEMD_EEE_ENABLE 0x00100000
-/* 0x36b4 --> 0x36b8 unused */
-
+#define TG3_CPMU_EEEMD_APE_TX_DET_EN 0x00000004
+#define TG3_CPMU_EEEMD_ERLY_L1_XIT_DET 0x00000008
+#define TG3_CPMU_EEEMD_SND_IDX_DET_EN 0x00000040
+#define TG3_CPMU_EEEMD_LPI_ENABLE 0x00000080
+#define TG3_CPMU_EEEMD_LPI_IN_TX 0x00000100
+#define TG3_CPMU_EEEMD_LPI_IN_RX 0x00000200
+#define TG3_CPMU_EEEMD_EEE_ENABLE 0x00100000
+#define TG3_CPMU_EEE_DBTMR1 0x000036b4
+#define TG3_CPMU_DBTMR1_PCIEXIT_2047US 0x07ff0000
+#define TG3_CPMU_DBTMR1_LNKIDLE_2047US 0x000070ff
+#define TG3_CPMU_EEE_DBTMR2 0x000036b8
+#define TG3_CPMU_DBTMR1_APE_TX_2047US 0x07ff0000
+#define TG3_CPMU_DBTMR2_TXIDXEQ_2047US 0x000070ff
#define TG3_CPMU_EEE_LNKIDL_CTRL 0x000036bc
#define TG3_CPMU_EEE_LNKIDL_PCIE_NL0 0x01000000
#define TG3_CPMU_EEE_LNKIDL_UART_IDL 0x00000004
@@ -1327,6 +1333,8 @@
#define TG3_RDMA_RSRVCTRL_REG 0x00004900
#define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX 0x00000004
+#define TG3_RDMA_RSRVCTRL_TXMRGN_320B 0x28000000
+#define TG3_RDMA_RSRVCTRL_TXMRGN_MASK 0xffe00000
/* 0x4904 --> 0x4910 unused */
#define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910
@@ -2170,9 +2178,6 @@
#define MII_TG3_TEST1_CRC_EN 0x8000
/* Clause 45 expansion registers */
-#define TG3_CL45_D7_EEEADV_CAP 0x003c
-#define TG3_CL45_D7_EEEADV_CAP_100TX 0x0002
-#define TG3_CL45_D7_EEEADV_CAP_1000T 0x0004
#define TG3_CL45_D7_EEERES_STAT 0x803e
#define TG3_CL45_D7_EEERES_STAT_LP_100TX 0x0002
#define TG3_CL45_D7_EEERES_STAT_LP_1000T 0x0004
@@ -2562,10 +2567,6 @@ struct ring_info {
DEFINE_DMA_UNMAP_ADDR(mapping);
};
-struct tg3_config_info {
- u32 flags;
-};
-
struct tg3_link_config {
/* Describes what we're trying to get. */
u32 advertising;
@@ -2713,17 +2714,17 @@ struct tg3_napi {
u32 last_irq_tag;
u32 int_mbox;
u32 coal_now;
- u32 tx_prod;
- u32 tx_cons;
- u32 tx_pending;
- u32 prodmbox;
- u32 consmbox;
+ u32 consmbox ____cacheline_aligned;
u32 rx_rcb_ptr;
u16 *rx_rcb_prod_idx;
struct tg3_rx_prodring_set prodring;
-
struct tg3_rx_buffer_desc *rx_rcb;
+
+ u32 tx_prod ____cacheline_aligned;
+ u32 tx_cons;
+ u32 tx_pending;
+ u32 prodmbox;
struct tg3_tx_buffer_desc *tx_ring;
struct ring_info *tx_buffers;
@@ -2946,6 +2947,7 @@ struct tg3 {
int pcix_cap;
int pcie_cap;
};
+ int pcie_readrq;
struct mii_bus *mdio_bus;
int mdio_irq[PHY_MAX_ADDR];
diff --git a/drivers/net/tile/Makefile b/drivers/net/tile/Makefile
new file mode 100644
index 000000000000..f634f142cab4
--- /dev/null
+++ b/drivers/net/tile/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the TILE on-chip networking support.
+#
+
+obj-$(CONFIG_TILE_NET) += tile_net.o
+ifdef CONFIG_TILEGX
+tile_net-objs := tilegx.o mpipe.o iorpc_mpipe.o dma_queue.o
+else
+tile_net-objs := tilepro.o
+endif
diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c
new file mode 100644
index 000000000000..7cb301da7474
--- /dev/null
+++ b/drivers/net/tile/tilepro.c
@@ -0,0 +1,2398 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/skbuff.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/hugetlb.h>
+#include <linux/in6.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <asm/checksum.h>
+#include <asm/homecache.h>
+
+#include <hv/drv_xgbe_intf.h>
+#include <hv/drv_xgbe_impl.h>
+#include <hv/hypervisor.h>
+#include <hv/netio_intf.h>
+
+/* For TSO */
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+
+/* There is no singlethread_cpu, so schedule work on the current cpu. */
+#define singlethread_cpu -1
+
+
+/*
+ * First, "tile_net_init_module()" initializes all four "devices" which
+ * can be used by linux.
+ *
+ * Then, "ifconfig DEVICE up" calls "tile_net_open()", which analyzes
+ * the network cpus, then uses "tile_net_open_aux()" to initialize
+ * LIPP/LEPP, and then uses "tile_net_open_inner()" to register all
+ * the tiles, provide buffers to LIPP, allow ingress to start, and
+ * turn on hypervisor interrupt handling (and NAPI) on all tiles.
+ *
+ * If registration fails due to the link being down, then "retry_work"
+ * is used to keep calling "tile_net_open_inner()" until it succeeds.
+ *
+ * If "ifconfig DEVICE down" is called, it uses "tile_net_stop()" to
+ * stop egress, drain the LIPP buffers, unregister all the tiles, stop
+ * LIPP/LEPP, and wipe the LEPP queue.
+ *
+ * We start out with the ingress interrupt enabled on each CPU. When
+ * this interrupt fires, we disable it, and call "napi_schedule()".
+ * This will cause "tile_net_poll()" to be called, which will pull
+ * packets from the netio queue, filtering them out, or passing them
+ * to "netif_receive_skb()". If our budget is exhausted, we will
+ * return, knowing we will be called again later. Otherwise, we
+ * reenable the ingress interrupt, and call "napi_complete()".
+ *
+ *
+ * NOTE: The use of "native_driver" ensures that EPP exists, and that
+ * "epp_sendv" is legal, and that "LIPP" is being used.
+ *
+ * NOTE: Failing to free completions for an arbitrarily long time
+ * (which is defined to be illegal) does in fact cause bizarre
+ * problems. The "egress_timer" helps prevent this from happening.
+ *
+ * NOTE: The egress code can be interrupted by the interrupt handler.
+ */
+
+
+/* HACK: Allow use of "jumbo" packets. */
+/* This should be 1500 if "jumbo" is not set in LIPP. */
+/* This should be at most 10226 (10240 - 14) if "jumbo" is set in LIPP. */
+/* ISSUE: This has not been thoroughly tested (except at 1500). */
+#define TILE_NET_MTU 1500
+
+/* HACK: Define to support GSO. */
+/* ISSUE: This may actually hurt performance of the TCP blaster. */
+/* #define TILE_NET_GSO */
+
+/* Define this to collapse "duplicate" acks. */
+/* #define IGNORE_DUP_ACKS */
+
+/* HACK: Define this to verify incoming packets. */
+/* #define TILE_NET_VERIFY_INGRESS */
+
+/* Use 3000 to enable the Linux Traffic Control (QoS) layer, else 0. */
+#define TILE_NET_TX_QUEUE_LEN 0
+
+/* Define to dump packets (prints out the whole packet on tx and rx). */
+/* #define TILE_NET_DUMP_PACKETS */
+
+/* Define to enable debug spew (all PDEBUG's are enabled). */
+/* #define TILE_NET_DEBUG */
+
+
+/* Define to activate paranoia checks. */
+/* #define TILE_NET_PARANOIA */
+
+/* Default transmit lockup timeout period, in jiffies. */
+#define TILE_NET_TIMEOUT (5 * HZ)
+
+/* Default retry interval for bringing up the NetIO interface, in jiffies. */
+#define TILE_NET_RETRY_INTERVAL (5 * HZ)
+
+/* Number of ports (xgbe0, xgbe1, gbe0, gbe1). */
+#define TILE_NET_DEVS 4
+
+
+
+/* Paranoia. */
+#if NET_IP_ALIGN != LIPP_PACKET_PADDING
+#error "NET_IP_ALIGN must match LIPP_PACKET_PADDING."
+#endif
+
+
+/* Debug print. */
+#ifdef TILE_NET_DEBUG
+#define PDEBUG(fmt, args...) net_printk(fmt, ## args)
+#else
+#define PDEBUG(fmt, args...)
+#endif
+
+
+MODULE_AUTHOR("Tilera");
+MODULE_LICENSE("GPL");
+
+/*
+ * Queue of incoming packets for a specific cpu and device.
+ *
+ * Includes a pointer to the "system" data, and the actual "user" data.
+ */
+struct tile_netio_queue {
+ netio_queue_impl_t *__system_part;
+ netio_queue_user_impl_t __user_part;
+
+};
+
+
+/*
+ * Statistics counters for a specific cpu and device.
+ */
+struct tile_net_stats_t {
+ u32 rx_packets;
+ u32 rx_bytes;
+ u32 tx_packets;
+ u32 tx_bytes;
+};
+
+
+/*
+ * Info for a specific cpu and device.
+ *
+ * ISSUE: There is a "dev" pointer in "napi" as well.
+ */
+struct tile_net_cpu {
+ /* The NAPI struct. */
+ struct napi_struct napi;
+ /* Packet queue. */
+ struct tile_netio_queue queue;
+ /* Statistics. */
+ struct tile_net_stats_t stats;
+ /* ISSUE: Is this needed? */
+ bool napi_enabled;
+ /* True if this tile has succcessfully registered with the IPP. */
+ bool registered;
+ /* True if the link was down last time we tried to register. */
+ bool link_down;
+ /* True if "egress_timer" is scheduled. */
+ bool egress_timer_scheduled;
+ /* Number of small sk_buffs which must still be provided. */
+ unsigned int num_needed_small_buffers;
+ /* Number of large sk_buffs which must still be provided. */
+ unsigned int num_needed_large_buffers;
+ /* A timer for handling egress completions. */
+ struct timer_list egress_timer;
+};
+
+
+/*
+ * Info for a specific device.
+ */
+struct tile_net_priv {
+ /* Our network device. */
+ struct net_device *dev;
+ /* The actual egress queue. */
+ lepp_queue_t *epp_queue;
+ /* Protects "epp_queue->cmd_tail" and "epp_queue->comp_tail" */
+ spinlock_t cmd_lock;
+ /* Protects "epp_queue->comp_head". */
+ spinlock_t comp_lock;
+ /* The hypervisor handle for this interface. */
+ int hv_devhdl;
+ /* The intr bit mask that IDs this device. */
+ u32 intr_id;
+ /* True iff "tile_net_open_aux()" has succeeded. */
+ int partly_opened;
+ /* True iff "tile_net_open_inner()" has succeeded. */
+ int fully_opened;
+ /* Effective network cpus. */
+ struct cpumask network_cpus_map;
+ /* Number of network cpus. */
+ int network_cpus_count;
+ /* Credits per network cpu. */
+ int network_cpus_credits;
+ /* Network stats. */
+ struct net_device_stats stats;
+ /* For NetIO bringup retries. */
+ struct delayed_work retry_work;
+ /* Quick access to per cpu data. */
+ struct tile_net_cpu *cpu[NR_CPUS];
+};
+
+
+/*
+ * The actual devices (xgbe0, xgbe1, gbe0, gbe1).
+ */
+static struct net_device *tile_net_devs[TILE_NET_DEVS];
+
+/*
+ * The "tile_net_cpu" structures for each device.
+ */
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe0);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe1);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe0);
+static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe1);
+
+
+/*
+ * True if "network_cpus" was specified.
+ */
+static bool network_cpus_used;
+
+/*
+ * The actual cpus in "network_cpus".
+ */
+static struct cpumask network_cpus_map;
+
+
+
+#ifdef TILE_NET_DEBUG
+/*
+ * printk with extra stuff.
+ *
+ * We print the CPU we're running in brackets.
+ */
+static void net_printk(char *fmt, ...)
+{
+ int i;
+ int len;
+ va_list args;
+ static char buf[256];
+
+ len = sprintf(buf, "tile_net[%2.2d]: ", smp_processor_id());
+ va_start(args, fmt);
+ i = vscnprintf(buf + len, sizeof(buf) - len - 1, fmt, args);
+ va_end(args);
+ buf[255] = '\0';
+ pr_notice(buf);
+}
+#endif
+
+
+#ifdef TILE_NET_DUMP_PACKETS
+/*
+ * Dump a packet.
+ */
+static void dump_packet(unsigned char *data, unsigned long length, char *s)
+{
+ unsigned long i;
+ static unsigned int count;
+
+ pr_info("dump_packet(data %p, length 0x%lx s %s count 0x%x)\n",
+ data, length, s, count++);
+
+ pr_info("\n");
+
+ for (i = 0; i < length; i++) {
+ if ((i & 0xf) == 0)
+ sprintf(buf, "%8.8lx:", i);
+ sprintf(buf + strlen(buf), " %2.2x", data[i]);
+ if ((i & 0xf) == 0xf || i == length - 1)
+ pr_info("%s\n", buf);
+ }
+}
+#endif
+
+
+/*
+ * Provide support for the __netio_fastio1() swint
+ * (see <hv/drv_xgbe_intf.h> for how it is used).
+ *
+ * The fastio swint2 call may clobber all the caller-saved registers.
+ * It rarely clobbers memory, but we allow for the possibility in
+ * the signature just to be on the safe side.
+ *
+ * Also, gcc doesn't seem to allow an input operand to be
+ * clobbered, so we fake it with dummy outputs.
+ *
+ * This function can't be static because of the way it is declared
+ * in the netio header.
+ */
+inline int __netio_fastio1(u32 fastio_index, u32 arg0)
+{
+ long result, clobber_r1, clobber_r10;
+ asm volatile("swint2"
+ : "=R00" (result),
+ "=R01" (clobber_r1), "=R10" (clobber_r10)
+ : "R10" (fastio_index), "R01" (arg0)
+ : "memory", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9",
+ "r11", "r12", "r13", "r14",
+ "r15", "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29");
+ return result;
+}
+
+
+/*
+ * Provide a linux buffer to LIPP.
+ */
+static void tile_net_provide_linux_buffer(struct tile_net_cpu *info,
+ void *va, bool small)
+{
+ struct tile_netio_queue *queue = &info->queue;
+
+ /* Convert "va" and "small" to "linux_buffer_t". */
+ unsigned int buffer = ((unsigned int)(__pa(va) >> 7) << 1) + small;
+
+ __netio_fastio_free_buffer(queue->__user_part.__fastio_index, buffer);
+}
+
+
+/*
+ * Provide a linux buffer for LIPP.
+ */
+static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
+ bool small)
+{
+ /* ISSUE: What should we use here? */
+ unsigned int large_size = NET_IP_ALIGN + TILE_NET_MTU + 100;
+
+ /* Round up to ensure to avoid "false sharing" with last cache line. */
+ unsigned int buffer_size =
+ (((small ? LIPP_SMALL_PACKET_SIZE : large_size) +
+ CHIP_L2_LINE_SIZE() - 1) & -CHIP_L2_LINE_SIZE());
+
+ /*
+ * ISSUE: Since CPAs are 38 bits, and we can only encode the
+ * high 31 bits in a "linux_buffer_t", the low 7 bits must be
+ * zero, and thus, we must align the actual "va" mod 128.
+ */
+ const unsigned long align = 128;
+
+ struct sk_buff *skb;
+ void *va;
+
+ struct sk_buff **skb_ptr;
+
+ /* Note that "dev_alloc_skb()" adds NET_SKB_PAD more bytes, */
+ /* and also "reserves" that many bytes. */
+ /* ISSUE: Can we "share" the NET_SKB_PAD bytes with "skb_ptr"? */
+ int len = sizeof(*skb_ptr) + align + buffer_size;
+
+ while (1) {
+
+ /* Allocate (or fail). */
+ skb = dev_alloc_skb(len);
+ if (skb == NULL)
+ return false;
+
+ /* Make room for a back-pointer to 'skb'. */
+ skb_reserve(skb, sizeof(*skb_ptr));
+
+ /* Make sure we are aligned. */
+ skb_reserve(skb, -(long)skb->data & (align - 1));
+
+ /* This address is given to IPP. */
+ va = skb->data;
+
+ if (small)
+ break;
+
+ /* ISSUE: This has never been observed! */
+ /* Large buffers must not span a huge page. */
+ if (((((long)va & ~HPAGE_MASK) + 1535) & HPAGE_MASK) == 0)
+ break;
+ pr_err("Leaking unaligned linux buffer at %p.\n", va);
+ }
+
+ /* Skip two bytes to satisfy LIPP assumptions. */
+ /* Note that this aligns IP on a 16 byte boundary. */
+ /* ISSUE: Do this when the packet arrives? */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ /* Save a back-pointer to 'skb'. */
+ skb_ptr = va - sizeof(*skb_ptr);
+ *skb_ptr = skb;
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(skb->data, buffer_size);
+
+ /* Make sure "skb_ptr" has been flushed. */
+ __insn_mf();
+
+#ifdef TILE_NET_PARANOIA
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default) {
+ HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va);
+ if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
+ panic("Non-coherent ingress buffer!");
+ }
+#endif
+#endif
+
+ /* Provide the new buffer. */
+ tile_net_provide_linux_buffer(info, va, small);
+
+ return true;
+}
+
+
+/*
+ * Provide linux buffers for LIPP.
+ */
+static void tile_net_provide_needed_buffers(struct tile_net_cpu *info)
+{
+ while (info->num_needed_small_buffers != 0) {
+ if (!tile_net_provide_needed_buffer(info, true))
+ goto oops;
+ info->num_needed_small_buffers--;
+ }
+
+ while (info->num_needed_large_buffers != 0) {
+ if (!tile_net_provide_needed_buffer(info, false))
+ goto oops;
+ info->num_needed_large_buffers--;
+ }
+
+ return;
+
+oops:
+
+ /* Add a description to the page allocation failure dump. */
+ pr_notice("Could not provide a linux buffer to LIPP.\n");
+}
+
+
+/*
+ * Grab some LEPP completions, and store them in "comps", of size
+ * "comps_size", and return the number of completions which were
+ * stored, so the caller can free them.
+ *
+ * If "pending" is not NULL, it will be set to true if there might
+ * still be some pending completions caused by this tile, else false.
+ */
+static unsigned int tile_net_lepp_grab_comps(struct net_device *dev,
+ struct sk_buff *comps[],
+ unsigned int comps_size,
+ bool *pending)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ unsigned int n = 0;
+
+ unsigned int comp_head;
+ unsigned int comp_busy;
+ unsigned int comp_tail;
+
+ spin_lock(&priv->comp_lock);
+
+ comp_head = eq->comp_head;
+ comp_busy = eq->comp_busy;
+ comp_tail = eq->comp_tail;
+
+ while (comp_head != comp_busy && n < comps_size) {
+ comps[n++] = eq->comps[comp_head];
+ LEPP_QINC(comp_head);
+ }
+
+ if (pending != NULL)
+ *pending = (comp_head != comp_tail);
+
+ eq->comp_head = comp_head;
+
+ spin_unlock(&priv->comp_lock);
+
+ return n;
+}
+
+
+/*
+ * Make sure the egress timer is scheduled.
+ *
+ * Note that we use "schedule if not scheduled" logic instead of the more
+ * obvious "reschedule" logic, because "reschedule" is fairly expensive.
+ */
+static void tile_net_schedule_egress_timer(struct tile_net_cpu *info)
+{
+ if (!info->egress_timer_scheduled) {
+ mod_timer_pinned(&info->egress_timer, jiffies + 1);
+ info->egress_timer_scheduled = true;
+ }
+}
+
+
+/*
+ * The "function" for "info->egress_timer".
+ *
+ * This timer will reschedule itself as long as there are any pending
+ * completions expected (on behalf of any tile).
+ *
+ * ISSUE: Realistically, will the timer ever stop scheduling itself?
+ *
+ * ISSUE: This timer is almost never actually needed, so just use a global
+ * timer that can run on any tile.
+ *
+ * ISSUE: Maybe instead track number of expected completions, and free
+ * only that many, resetting to zero if "pending" is ever false.
+ */
+static void tile_net_handle_egress_timer(unsigned long arg)
+{
+ struct tile_net_cpu *info = (struct tile_net_cpu *)arg;
+ struct net_device *dev = info->napi.dev;
+
+ struct sk_buff *olds[32];
+ unsigned int wanted = 32;
+ unsigned int i, nolds = 0;
+ bool pending;
+
+ /* The timer is no longer scheduled. */
+ info->egress_timer_scheduled = false;
+
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, &pending);
+
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* Reschedule timer if needed. */
+ if (pending)
+ tile_net_schedule_egress_timer(info);
+}
+
+
+#ifdef IGNORE_DUP_ACKS
+
+/*
+ * Help detect "duplicate" ACKs. These are sequential packets (for a
+ * given flow) which are exactly 66 bytes long, sharing everything but
+ * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32,
+ * Tstamps=10@0x38. The ID's are +1, the Hsum's are -1, the Ack's are
+ * +N, and the Tstamps are usually identical.
+ *
+ * NOTE: Apparently truly duplicate acks (with identical "ack" values),
+ * should not be collapsed, as they are used for some kind of flow control.
+ */
+static bool is_dup_ack(char *s1, char *s2, unsigned int len)
+{
+ int i;
+
+ unsigned long long ignorable = 0;
+
+ /* Identification. */
+ ignorable |= (1ULL << 0x12);
+ ignorable |= (1ULL << 0x13);
+
+ /* Header checksum. */
+ ignorable |= (1ULL << 0x18);
+ ignorable |= (1ULL << 0x19);
+
+ /* ACK. */
+ ignorable |= (1ULL << 0x2a);
+ ignorable |= (1ULL << 0x2b);
+ ignorable |= (1ULL << 0x2c);
+ ignorable |= (1ULL << 0x2d);
+
+ /* WinSize. */
+ ignorable |= (1ULL << 0x30);
+ ignorable |= (1ULL << 0x31);
+
+ /* Checksum. */
+ ignorable |= (1ULL << 0x32);
+ ignorable |= (1ULL << 0x33);
+
+ for (i = 0; i < len; i++, ignorable >>= 1) {
+
+ if ((ignorable & 1) || (s1[i] == s2[i]))
+ continue;
+
+#ifdef TILE_NET_DEBUG
+ /* HACK: Mention non-timestamp diffs. */
+ if (i < 0x38 && i != 0x2f &&
+ net_ratelimit())
+ pr_info("Diff at 0x%x\n", i);
+#endif
+
+ return false;
+ }
+
+#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS
+ /* HACK: Do not suppress truly duplicate ACKs. */
+ /* ISSUE: Is this actually necessary or helpful? */
+ if (s1[0x2a] == s2[0x2a] &&
+ s1[0x2b] == s2[0x2b] &&
+ s1[0x2c] == s2[0x2c] &&
+ s1[0x2d] == s2[0x2d]) {
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+#endif
+
+
+
+/*
+ * Like "tile_net_handle_packets()", but just discard packets.
+ */
+static void tile_net_discard_packets(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ while (qup->__packet_receive_read !=
+ qsp->__packet_receive_queue.__packet_write) {
+
+ int index = qup->__packet_receive_read;
+
+ int index2_aux = index + sizeof(netio_pkt_t);
+ int index2 =
+ ((index2_aux ==
+ qsp->__packet_receive_queue.__last_packet_plus_one) ?
+ 0 : index2_aux);
+
+ netio_pkt_t *pkt = (netio_pkt_t *)
+ ((unsigned long) &qsp[1] + index);
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer = pkt->__packet.word;
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ kfree_skb(skb);
+
+ /* Consume this packet. */
+ qup->__packet_receive_read = index2;
+ }
+}
+
+
+/*
+ * Handle the next packet. Return true if "processed", false if "filtered".
+ */
+static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
+{
+ struct net_device *dev = info->napi.dev;
+
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+ struct tile_net_stats_t *stats = &info->stats;
+
+ int filter;
+
+ int index2_aux = index + sizeof(netio_pkt_t);
+ int index2 =
+ ((index2_aux ==
+ qsp->__packet_receive_queue.__last_packet_plus_one) ?
+ 0 : index2_aux);
+
+ netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
+
+ netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt);
+
+ /* Extract the packet size. */
+ unsigned long len =
+ (NETIO_PKT_CUSTOM_LENGTH(pkt) +
+ NET_IP_ALIGN - NETIO_PACKET_PADDING);
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer = pkt->__packet.word;
+
+ /* Extract "small" (vs "large"). */
+ bool small = ((buffer & 1) != 0);
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Extract the packet data pointer. */
+ /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
+ unsigned char *buf = va + NET_IP_ALIGN;
+
+#ifdef IGNORE_DUP_ACKS
+
+ static int other;
+ static int final;
+ static int keep;
+ static int skip;
+
+#endif
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(buf, len);
+
+ /* ISSUE: Is this needed? */
+ dev->last_rx = jiffies;
+
+#ifdef TILE_NET_DUMP_PACKETS
+ dump_packet(buf, len, "rx");
+#endif /* TILE_NET_DUMP_PACKETS */
+
+#ifdef TILE_NET_VERIFY_INGRESS
+ if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) &&
+ NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) {
+ /*
+ * FIXME: This complains about UDP packets
+ * with a "zero" checksum (bug 6624).
+ */
+#ifdef TILE_NET_PANIC_ON_BAD
+ dump_packet(buf, len, "rx");
+ panic("Bad L4 checksum.");
+#else
+ pr_warning("Bad L4 checksum on %d byte packet.\n", len);
+#endif
+ }
+ if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) &&
+ NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) {
+ dump_packet(buf, len, "rx");
+ panic("Bad L3 checksum.");
+ }
+ switch (NETIO_PKT_STATUS_M(metadata, pkt)) {
+ case NETIO_PKT_STATUS_OVERSIZE:
+ if (len >= 64) {
+ dump_packet(buf, len, "rx");
+ panic("Unexpected OVERSIZE.");
+ }
+ break;
+ case NETIO_PKT_STATUS_BAD:
+#ifdef TILE_NET_PANIC_ON_BAD
+ dump_packet(buf, len, "rx");
+ panic("Unexpected BAD packet.");
+#else
+ pr_warning("Unexpected BAD %d byte packet.\n", len);
+#endif
+ }
+#endif
+
+ filter = 0;
+
+ if (!(dev->flags & IFF_UP)) {
+ /* Filter packets received before we're up. */
+ filter = 1;
+ } else if (!(dev->flags & IFF_PROMISC)) {
+ /*
+ * FIXME: Implement HW multicast filter.
+ */
+ if (is_unicast_ether_addr(buf)) {
+ /* Filter packets not for our address. */
+ const u8 *mine = dev->dev_addr;
+ filter = compare_ether_addr(mine, buf);
+ }
+ }
+
+#ifdef IGNORE_DUP_ACKS
+
+ if (len != 66) {
+ /* FIXME: Must check "is_tcp_ack(buf, len)" somehow. */
+
+ other++;
+
+ } else if (index2 ==
+ qsp->__packet_receive_queue.__packet_write) {
+
+ final++;
+
+ } else {
+
+ netio_pkt_t *pkt2 = (netio_pkt_t *)
+ ((unsigned long) &qsp[1] + index2);
+
+ netio_pkt_metadata_t *metadata2 =
+ NETIO_PKT_METADATA(pkt2);
+
+ /* Extract the packet size. */
+ unsigned long len2 =
+ (NETIO_PKT_CUSTOM_LENGTH(pkt2) +
+ NET_IP_ALIGN - NETIO_PACKET_PADDING);
+
+ if (len2 == 66 &&
+ NETIO_PKT_FLOW_HASH_M(metadata, pkt) ==
+ NETIO_PKT_FLOW_HASH_M(metadata2, pkt2)) {
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer2 = pkt2->__packet.word;
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va2 =
+ __va((phys_addr_t)(buffer2 >> 1) << 7);
+
+ /* Extract the packet data pointer. */
+ /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
+ unsigned char *buf2 = va2 + NET_IP_ALIGN;
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(buf2, len2);
+
+ if (is_dup_ack(buf, buf2, len)) {
+ skip++;
+ filter = 1;
+ } else {
+ keep++;
+ }
+ }
+ }
+
+ if (net_ratelimit())
+ pr_info("Other %d Final %d Keep %d Skip %d.\n",
+ other, final, keep, skip);
+
+#endif
+
+ if (filter) {
+
+ /* ISSUE: Update "drop" statistics? */
+
+ tile_net_provide_linux_buffer(info, va, small);
+
+ } else {
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ /* Paranoia. */
+ if (skb->data != buf)
+ panic("Corrupt linux buffer from LIPP! "
+ "VA=%p, skb=%p, skb->data=%p\n",
+ va, skb, skb->data);
+
+ /* Encode the actual packet length. */
+ skb_put(skb, len);
+
+ /* NOTE: This call also sets "skb->dev = dev". */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* ISSUE: Discard corrupt packets? */
+ /* ISSUE: Discard packets with bad checksums? */
+
+ /* Avoid recomputing TCP/UDP checksums. */
+ if (NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+
+ if (small)
+ info->num_needed_small_buffers++;
+ else
+ info->num_needed_large_buffers++;
+ }
+
+ /* Return four credits after every fourth packet. */
+ if (--qup->__receive_credit_remaining == 0) {
+ u32 interval = qup->__receive_credit_interval;
+ qup->__receive_credit_remaining = interval;
+ __netio_fastio_return_credits(qup->__fastio_index, interval);
+ }
+
+ /* Consume this packet. */
+ qup->__packet_receive_read = index2;
+
+ return !filter;
+}
+
+
+/*
+ * Handle some packets for the given device on the current CPU.
+ *
+ * ISSUE: The "rotting packet" race condition occurs if a packet
+ * arrives after the queue appears to be empty, and before the
+ * hypervisor interrupt is re-enabled.
+ */
+static int tile_net_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *dev = napi->dev;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ unsigned int work = 0;
+
+ while (1) {
+ int index = qup->__packet_receive_read;
+ if (index == qsp->__packet_receive_queue.__packet_write)
+ break;
+
+ if (tile_net_poll_aux(info, index)) {
+ if (++work >= budget)
+ goto done;
+ }
+ }
+
+ napi_complete(&info->napi);
+
+ /* Re-enable hypervisor interrupts. */
+ enable_percpu_irq(priv->intr_id);
+
+ /* HACK: Avoid the "rotting packet" problem. */
+ if (qup->__packet_receive_read !=
+ qsp->__packet_receive_queue.__packet_write)
+ napi_schedule(&info->napi);
+
+ /* ISSUE: Handle completions? */
+
+done:
+
+ tile_net_provide_needed_buffers(info);
+
+ return work;
+}
+
+
+/*
+ * Handle an ingress interrupt for the given device on the current cpu.
+ */
+static irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Disable hypervisor interrupt. */
+ disable_percpu_irq(priv->intr_id);
+
+ napi_schedule(&info->napi);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * One time initialization per interface.
+ */
+static int tile_net_open_aux(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ int ret;
+ int dummy;
+ unsigned int epp_lotar;
+
+ /*
+ * Find out where EPP memory should be homed.
+ */
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&epp_lotar, sizeof(epp_lotar),
+ NETIO_EPP_SHM_OFF);
+ if (ret < 0) {
+ pr_err("could not read epp_shm_queue lotar.\n");
+ return -EIO;
+ }
+
+ /*
+ * Home the page on the EPP.
+ */
+ {
+ int epp_home = hv_lotar_to_cpu(epp_lotar);
+ struct page *page = virt_to_page(priv->epp_queue);
+ homecache_change_page_home(page, 0, epp_home);
+ }
+
+ /*
+ * Register the EPP shared memory queue.
+ */
+ {
+ netio_ipp_address_t ea = {
+ .va = 0,
+ .pa = __pa(priv->epp_queue),
+ .pte = hv_pte(0),
+ .size = PAGE_SIZE,
+ };
+ ea.pte = hv_pte_set_lotar(ea.pte, epp_lotar);
+ ea.pte = hv_pte_set_mode(ea.pte, HV_PTE_MODE_CACHE_TILE_L3);
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&ea,
+ sizeof(ea),
+ NETIO_EPP_SHM_OFF);
+ if (ret < 0)
+ return -EIO;
+ }
+
+ /*
+ * Start LIPP/LEPP.
+ */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) {
+ pr_warning("Failed to start LIPP/LEPP.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Register with hypervisor on each CPU.
+ *
+ * Strangely, this function does important things even if it "fails",
+ * which is especially common if the link is not up yet. Hopefully
+ * these things are all "harmless" if done twice!
+ */
+static void tile_net_register(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info;
+
+ struct tile_netio_queue *queue;
+
+ /* Only network cpus can receive packets. */
+ int queue_id =
+ cpumask_test_cpu(my_cpu, &priv->network_cpus_map) ? 0 : 255;
+
+ netio_input_config_t config = {
+ .flags = 0,
+ .num_receive_packets = priv->network_cpus_credits,
+ .queue_id = queue_id
+ };
+
+ int ret = 0;
+ netio_queue_impl_t *queuep;
+
+ PDEBUG("tile_net_register(queue_id %d)\n", queue_id);
+
+ if (!strcmp(dev->name, "xgbe0"))
+ info = &__get_cpu_var(hv_xgbe0);
+ else if (!strcmp(dev->name, "xgbe1"))
+ info = &__get_cpu_var(hv_xgbe1);
+ else if (!strcmp(dev->name, "gbe0"))
+ info = &__get_cpu_var(hv_gbe0);
+ else if (!strcmp(dev->name, "gbe1"))
+ info = &__get_cpu_var(hv_gbe1);
+ else
+ BUG();
+
+ /* Initialize the egress timer. */
+ init_timer(&info->egress_timer);
+ info->egress_timer.data = (long)info;
+ info->egress_timer.function = tile_net_handle_egress_timer;
+
+ priv->cpu[my_cpu] = info;
+
+ /*
+ * Register ourselves with the IPP.
+ */
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&config,
+ sizeof(netio_input_config_t),
+ NETIO_IPP_INPUT_REGISTER_OFF);
+ PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
+ ret);
+ if (ret < 0) {
+ printk(KERN_DEBUG "hv_dev_pwrite NETIO_IPP_INPUT_REGISTER_OFF"
+ " failure %d\n", ret);
+ info->link_down = (ret == NETIO_LINK_DOWN);
+ return;
+ }
+
+ /*
+ * Get the pointer to our queue's system part.
+ */
+
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&queuep,
+ sizeof(netio_queue_impl_t *),
+ NETIO_IPP_INPUT_REGISTER_OFF);
+ PDEBUG("hv_dev_pread(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
+ ret);
+ PDEBUG("queuep %p\n", queuep);
+ if (ret <= 0) {
+ /* ISSUE: Shouldn't this be a fatal error? */
+ pr_err("hv_dev_pread NETIO_IPP_INPUT_REGISTER_OFF failure\n");
+ return;
+ }
+
+ queue = &info->queue;
+
+ queue->__system_part = queuep;
+
+ memset(&queue->__user_part, 0, sizeof(netio_queue_user_impl_t));
+
+ /* This is traditionally "config.num_receive_packets / 2". */
+ queue->__user_part.__receive_credit_interval = 4;
+ queue->__user_part.__receive_credit_remaining =
+ queue->__user_part.__receive_credit_interval;
+
+ /*
+ * Get a fastio index from the hypervisor.
+ * ISSUE: Shouldn't this check the result?
+ */
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)&queue->__user_part.__fastio_index,
+ sizeof(queue->__user_part.__fastio_index),
+ NETIO_IPP_GET_FASTIO_OFF);
+ PDEBUG("hv_dev_pread(NETIO_IPP_GET_FASTIO_OFF) returned %d\n", ret);
+
+ netif_napi_add(dev, &info->napi, tile_net_poll, 64);
+
+ /* Now we are registered. */
+ info->registered = true;
+}
+
+
+/*
+ * Unregister with hypervisor on each CPU.
+ */
+static void tile_net_unregister(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ int ret = 0;
+ int dummy = 0;
+
+ /* Do nothing if never registered. */
+ if (info == NULL)
+ return;
+
+ /* Do nothing if already unregistered. */
+ if (!info->registered)
+ return;
+
+ /*
+ * Unregister ourselves with LIPP.
+ */
+ ret = hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_INPUT_UNREGISTER_OFF);
+ PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_UNREGISTER_OFF) returned %d\n",
+ ret);
+ if (ret < 0) {
+ /* FIXME: Just panic? */
+ pr_err("hv_dev_pwrite NETIO_IPP_INPUT_UNREGISTER_OFF"
+ " failure %d\n", ret);
+ }
+
+ /*
+ * Discard all packets still in our NetIO queue. Hopefully,
+ * once the unregister call is complete, there will be no
+ * packets still in flight on the IDN.
+ */
+ tile_net_discard_packets(dev);
+
+ /* Reset state. */
+ info->num_needed_small_buffers = 0;
+ info->num_needed_large_buffers = 0;
+
+ /* Cancel egress timer. */
+ del_timer(&info->egress_timer);
+ info->egress_timer_scheduled = false;
+
+ netif_napi_del(&info->napi);
+
+ /* Now we are unregistered. */
+ info->registered = false;
+}
+
+
+/*
+ * Helper function for "tile_net_stop()".
+ *
+ * Also used to handle registration failure in "tile_net_open_inner()",
+ * when "fully_opened" is known to be false, and the various extra
+ * steps in "tile_net_stop()" are not necessary. ISSUE: It might be
+ * simpler if we could just call "tile_net_stop()" anyway.
+ */
+static void tile_net_stop_aux(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ int dummy = 0;
+
+ /* Unregister all tiles, so LIPP will stop delivering packets. */
+ on_each_cpu(tile_net_unregister, (void *)dev, 1);
+
+ /* Stop LIPP/LEPP. */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_STOP_SHIM_OFF) < 0)
+ panic("Failed to stop LIPP/LEPP!\n");
+
+ priv->partly_opened = 0;
+}
+
+
+/*
+ * Disable ingress interrupts for the given device on the current cpu.
+ */
+static void tile_net_disable_intr(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Disable hypervisor interrupt. */
+ disable_percpu_irq(priv->intr_id);
+
+ /* Disable NAPI if needed. */
+ if (info != NULL && info->napi_enabled) {
+ napi_disable(&info->napi);
+ info->napi_enabled = false;
+ }
+}
+
+
+/*
+ * Enable ingress interrupts for the given device on the current cpu.
+ */
+static void tile_net_enable_intr(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Enable hypervisor interrupt. */
+ enable_percpu_irq(priv->intr_id);
+
+ /* Enable NAPI. */
+ napi_enable(&info->napi);
+ info->napi_enabled = true;
+}
+
+
+/*
+ * tile_net_open_inner does most of the work of bringing up the interface.
+ * It's called from tile_net_open(), and also from tile_net_retry_open().
+ * The return value is 0 if the interface was brought up, < 0 if
+ * tile_net_open() should return the return value as an error, and > 0 if
+ * tile_net_open() should return success and schedule a work item to
+ * periodically retry the bringup.
+ */
+static int tile_net_open_inner(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info;
+ struct tile_netio_queue *queue;
+ unsigned int irq;
+ int i;
+
+ /*
+ * First try to register just on the local CPU, and handle any
+ * semi-expected "link down" failure specially. Note that we
+ * do NOT call "tile_net_stop_aux()", unlike below.
+ */
+ tile_net_register(dev);
+ info = priv->cpu[my_cpu];
+ if (!info->registered) {
+ if (info->link_down)
+ return 1;
+ return -EAGAIN;
+ }
+
+ /*
+ * Now register everywhere else. If any registration fails,
+ * even for "link down" (which might not be possible), we
+ * clean up using "tile_net_stop_aux()".
+ */
+ smp_call_function(tile_net_register, (void *)dev, 1);
+ for_each_online_cpu(i) {
+ if (!priv->cpu[i]->registered) {
+ tile_net_stop_aux(dev);
+ return -EAGAIN;
+ }
+ }
+
+ queue = &info->queue;
+
+ /*
+ * Set the device intr bit mask.
+ * The tile_net_register above sets per tile __intr_id.
+ */
+ priv->intr_id = queue->__system_part->__intr_id;
+ BUG_ON(!priv->intr_id);
+
+ /*
+ * Register the device interrupt handler.
+ * The __ffs() function returns the index into the interrupt handler
+ * table from the interrupt bit mask which should have one bit
+ * and one bit only set.
+ */
+ irq = __ffs(priv->intr_id);
+ tile_irq_activate(irq, TILE_IRQ_PERCPU);
+ BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt,
+ 0, dev->name, (void *)dev) != 0);
+
+ /* ISSUE: How could "priv->fully_opened" ever be "true" here? */
+
+ if (!priv->fully_opened) {
+
+ int dummy = 0;
+
+ /* Allocate initial buffers. */
+
+ int max_buffers =
+ priv->network_cpus_count * priv->network_cpus_credits;
+
+ info->num_needed_small_buffers =
+ min(LIPP_SMALL_BUFFERS, max_buffers);
+
+ info->num_needed_large_buffers =
+ min(LIPP_LARGE_BUFFERS, max_buffers);
+
+ tile_net_provide_needed_buffers(info);
+
+ if (info->num_needed_small_buffers != 0 ||
+ info->num_needed_large_buffers != 0)
+ panic("Insufficient memory for buffer stack!");
+
+ /* Start LIPP/LEPP and activate "ingress" at the shim. */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0)
+ panic("Failed to activate the LIPP Shim!\n");
+
+ priv->fully_opened = 1;
+ }
+
+ /* On each tile, enable the hypervisor to trigger interrupts. */
+ /* ISSUE: Do this before starting LIPP/LEPP? */
+ on_each_cpu(tile_net_enable_intr, (void *)dev, 1);
+
+ /* Start our transmit queue. */
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+
+/*
+ * Called periodically to retry bringing up the NetIO interface,
+ * if it doesn't come up cleanly during tile_net_open().
+ */
+static void tile_net_open_retry(struct work_struct *w)
+{
+ struct delayed_work *dw =
+ container_of(w, struct delayed_work, work);
+
+ struct tile_net_priv *priv =
+ container_of(dw, struct tile_net_priv, retry_work);
+
+ /*
+ * Try to bring the NetIO interface up. If it fails, reschedule
+ * ourselves to try again later; otherwise, tell Linux we now have
+ * a working link. ISSUE: What if the return value is negative?
+ */
+ if (tile_net_open_inner(priv->dev))
+ schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
+ TILE_NET_RETRY_INTERVAL);
+ else
+ netif_carrier_on(priv->dev);
+}
+
+
+/*
+ * Called when a network interface is made active.
+ *
+ * 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.
+ *
+ * If the actual link is not available yet, then we tell Linux that
+ * we have no carrier, and we keep checking until the link comes up.
+ */
+static int tile_net_open(struct net_device *dev)
+{
+ int ret = 0;
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ /*
+ * We rely on priv->partly_opened to tell us if this is the
+ * first time this interface is being brought up. If it is
+ * set, the IPP was already initialized and should not be
+ * initialized again.
+ */
+ if (!priv->partly_opened) {
+
+ int count;
+ int credits;
+
+ /* Initialize LIPP/LEPP, and start the Shim. */
+ ret = tile_net_open_aux(dev);
+ if (ret < 0) {
+ pr_err("tile_net_open_aux failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Analyze the network cpus. */
+
+ if (network_cpus_used)
+ cpumask_copy(&priv->network_cpus_map,
+ &network_cpus_map);
+ else
+ cpumask_copy(&priv->network_cpus_map, cpu_online_mask);
+
+
+ count = cpumask_weight(&priv->network_cpus_map);
+
+ /* Limit credits to available buffers, and apply min. */
+ credits = max(16, (LIPP_LARGE_BUFFERS / count) & ~1);
+
+ /* Apply "GBE" max limit. */
+ /* ISSUE: Use higher limit for XGBE? */
+ credits = min(NETIO_MAX_RECEIVE_PKTS, credits);
+
+ priv->network_cpus_count = count;
+ priv->network_cpus_credits = credits;
+
+#ifdef TILE_NET_DEBUG
+ pr_info("Using %d network cpus, with %d credits each\n",
+ priv->network_cpus_count, priv->network_cpus_credits);
+#endif
+
+ priv->partly_opened = 1;
+ }
+
+ /*
+ * Attempt to bring up the link.
+ */
+ ret = tile_net_open_inner(dev);
+ if (ret <= 0) {
+ if (ret == 0)
+ netif_carrier_on(dev);
+ return ret;
+ }
+
+ /*
+ * We were unable to bring up the NetIO interface, but we want to
+ * try again in a little bit. Tell Linux that we have no carrier
+ * so it doesn't try to use the interface before the link comes up
+ * and then remember to try again later.
+ */
+ netif_carrier_off(dev);
+ schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
+ TILE_NET_RETRY_INTERVAL);
+
+ return 0;
+}
+
+
+/*
+ * Disables a network interface.
+ *
+ * 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.
+ *
+ * ISSUE: Can this can be called while "tile_net_poll()" is running?
+ */
+static int tile_net_stop(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ bool pending = true;
+
+ PDEBUG("tile_net_stop()\n");
+
+ /* ISSUE: Only needed if not yet fully open. */
+ cancel_delayed_work_sync(&priv->retry_work);
+
+ /* Can't transmit any more. */
+ netif_stop_queue(dev);
+
+ /*
+ * Disable hypervisor interrupts on each tile.
+ */
+ on_each_cpu(tile_net_disable_intr, (void *)dev, 1);
+
+ /*
+ * Unregister the interrupt handler.
+ * The __ffs() function returns the index into the interrupt handler
+ * table from the interrupt bit mask which should have one bit
+ * and one bit only set.
+ */
+ if (priv->intr_id)
+ free_irq(__ffs(priv->intr_id), dev);
+
+ /*
+ * Drain all the LIPP buffers.
+ */
+
+ while (true) {
+ int buffer;
+
+ /* NOTE: This should never fail. */
+ if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer,
+ sizeof(buffer), NETIO_IPP_DRAIN_OFF) < 0)
+ break;
+
+ /* Stop when done. */
+ if (buffer == 0)
+ break;
+
+ {
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ kfree_skb(skb);
+ }
+ }
+
+ /* Stop LIPP/LEPP. */
+ tile_net_stop_aux(dev);
+
+
+ priv->fully_opened = 0;
+
+
+ /*
+ * XXX: ISSUE: It appears that, in practice anyway, by the
+ * time we get here, there are no pending completions.
+ */
+ while (pending) {
+
+ struct sk_buff *olds[32];
+ unsigned int wanted = 32;
+ unsigned int i, nolds = 0;
+
+ nolds = tile_net_lepp_grab_comps(dev, olds,
+ wanted, &pending);
+
+ /* ISSUE: We have never actually seen this debug spew. */
+ if (nolds != 0)
+ pr_info("During tile_net_stop(), grabbed %d comps.\n",
+ nolds);
+
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+ }
+
+
+ /* Wipe the EPP queue. */
+ memset(priv->epp_queue, 0, sizeof(lepp_queue_t));
+
+ /* Evict the EPP queue. */
+ finv_buffer(priv->epp_queue, PAGE_SIZE);
+
+ return 0;
+}
+
+
+/*
+ * Prepare the "frags" info for the resulting LEPP command.
+ *
+ * If needed, flush the memory used by the frags.
+ */
+static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
+ struct sk_buff *skb,
+ void *b_data, unsigned int b_len)
+{
+ unsigned int i, n = 0;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ phys_addr_t cpa;
+
+ if (b_len != 0) {
+
+ if (!hash_default)
+ finv_buffer_remote(b_data, b_len);
+
+ cpa = __pa(b_data);
+ frags[n].cpa_lo = cpa;
+ frags[n].cpa_hi = cpa >> 32;
+ frags[n].length = b_len;
+ frags[n].hash_for_home = hash_default;
+ n++;
+ }
+
+ for (i = 0; i < sh->nr_frags; i++) {
+
+ skb_frag_t *f = &sh->frags[i];
+ unsigned long pfn = page_to_pfn(f->page);
+
+ /* FIXME: Compute "hash_for_home" properly. */
+ /* ISSUE: The hypervisor checks CHIP_HAS_REV1_DMA_PACKETS(). */
+ int hash_for_home = hash_default;
+
+ /* FIXME: Hmmm. */
+ if (!hash_default) {
+ void *va = pfn_to_kaddr(pfn) + f->page_offset;
+ BUG_ON(PageHighMem(f->page));
+ finv_buffer_remote(va, f->size);
+ }
+
+ cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
+ frags[n].cpa_lo = cpa;
+ frags[n].cpa_hi = cpa >> 32;
+ frags[n].length = f->size;
+ frags[n].hash_for_home = hash_for_home;
+ n++;
+ }
+
+ return n;
+}
+
+
+/*
+ * This function takes "skb", consisting of a header template and a
+ * payload, and hands it to LEPP, to emit as one or more segments,
+ * each consisting of a possibly modified header, plus a piece of the
+ * payload, via a process known as "tcp segmentation offload".
+ *
+ * Usually, "data" will contain the header template, of size "sh_len",
+ * and "sh->frags" will contain "skb->data_len" bytes of payload, and
+ * there will be "sh->gso_segs" segments.
+ *
+ * Sometimes, if "sendfile()" requires copying, we will be called with
+ * "data" containing the header and payload, with "frags" being empty.
+ *
+ * In theory, "sh->nr_frags" could be 3, but in practice, it seems
+ * that this will never actually happen.
+ *
+ * See "emulate_large_send_offload()" for some reference code, which
+ * does not handle checksumming.
+ *
+ * ISSUE: How do we make sure that high memory DMA does not migrate?
+ */
+static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_net_stats_t *stats = &info->stats;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ unsigned char *data = skb->data;
+
+ /* The ip header follows the ethernet header. */
+ struct iphdr *ih = ip_hdr(skb);
+ unsigned int ih_len = ih->ihl * 4;
+
+ /* Note that "nh == ih", by definition. */
+ unsigned char *nh = skb_network_header(skb);
+ unsigned int eh_len = nh - data;
+
+ /* The tcp header follows the ip header. */
+ struct tcphdr *th = (struct tcphdr *)(nh + ih_len);
+ unsigned int th_len = th->doff * 4;
+
+ /* The total number of header bytes. */
+ /* NOTE: This may be less than skb_headlen(skb). */
+ unsigned int sh_len = eh_len + ih_len + th_len;
+
+ /* The number of payload bytes at "skb->data + sh_len". */
+ /* This is non-zero for sendfile() without HIGHDMA. */
+ unsigned int b_len = skb_headlen(skb) - sh_len;
+
+ /* The total number of payload bytes. */
+ unsigned int d_len = b_len + skb->data_len;
+
+ /* The maximum payload size. */
+ unsigned int p_len = sh->gso_size;
+
+ /* The total number of segments. */
+ unsigned int num_segs = sh->gso_segs;
+
+ /* The temporary copy of the command. */
+ u32 cmd_body[(LEPP_MAX_CMD_SIZE + 3) / 4];
+ lepp_tso_cmd_t *cmd = (lepp_tso_cmd_t *)cmd_body;
+
+ /* Analyze the "frags". */
+ unsigned int num_frags =
+ tile_net_tx_frags(cmd->frags, skb, data + sh_len, b_len);
+
+ /* The size of the command, including frags and header. */
+ size_t cmd_size = LEPP_TSO_CMD_SIZE(num_frags, sh_len);
+
+ /* The command header. */
+ lepp_tso_cmd_t cmd_init = {
+ .tso = true,
+ .header_size = sh_len,
+ .ip_offset = eh_len,
+ .tcp_offset = eh_len + ih_len,
+ .payload_size = p_len,
+ .num_frags = num_frags,
+ };
+
+ unsigned long irqflags;
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ struct sk_buff *olds[4];
+ unsigned int wanted = 4;
+ unsigned int i, nolds = 0;
+
+ unsigned int cmd_head, cmd_tail, cmd_next;
+ unsigned int comp_tail;
+
+ unsigned int free_slots;
+
+
+ /* Paranoia. */
+ BUG_ON(skb->protocol != htons(ETH_P_IP));
+ BUG_ON(ih->protocol != IPPROTO_TCP);
+ BUG_ON(skb->ip_summed != CHECKSUM_PARTIAL);
+ BUG_ON(num_frags > LEPP_MAX_FRAGS);
+ /*--BUG_ON(num_segs != (d_len + (p_len - 1)) / p_len); */
+ BUG_ON(num_segs <= 1);
+
+
+ /* Finish preparing the command. */
+
+ /* Copy the command header. */
+ *cmd = cmd_init;
+
+ /* Copy the "header". */
+ memcpy(&cmd->frags[num_frags], data, sh_len);
+
+
+ /* Prefetch and wait, to minimize time spent holding the spinlock. */
+ prefetch_L1(&eq->comp_tail);
+ prefetch_L1(&eq->cmd_tail);
+ mb();
+
+
+ /* Enqueue the command. */
+
+ spin_lock_irqsave(&priv->cmd_lock, irqflags);
+
+ /*
+ * Handle completions if needed to make room.
+ * HACK: Spin until there is sufficient room.
+ */
+ free_slots = lepp_num_free_comp_slots(eq);
+ if (free_slots < 1) {
+spin:
+ nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
+ wanted - nolds, NULL);
+ if (lepp_num_free_comp_slots(eq) < 1)
+ goto spin;
+ }
+
+ cmd_head = eq->cmd_head;
+ cmd_tail = eq->cmd_tail;
+
+ /* NOTE: The "gotos" below are untested. */
+
+ /* Prepare to advance, detecting full queue. */
+ cmd_next = cmd_tail + cmd_size;
+ if (cmd_tail < cmd_head && cmd_next >= cmd_head)
+ goto spin;
+ if (cmd_next > LEPP_CMD_LIMIT) {
+ cmd_next = 0;
+ if (cmd_next == cmd_head)
+ goto spin;
+ }
+
+ /* Copy the command. */
+ memcpy(&eq->cmds[cmd_tail], cmd, cmd_size);
+
+ /* Advance. */
+ cmd_tail = cmd_next;
+
+ /* Record "skb" for eventual freeing. */
+ comp_tail = eq->comp_tail;
+ eq->comps[comp_tail] = skb;
+ LEPP_QINC(comp_tail);
+ eq->comp_tail = comp_tail;
+
+ /* Flush before allowing LEPP to handle the command. */
+ __insn_mf();
+
+ eq->cmd_tail = cmd_tail;
+
+ spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
+
+ if (nolds == 0)
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+
+ /* Handle completions. */
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* Update stats. */
+ stats->tx_packets += num_segs;
+ stats->tx_bytes += (num_segs * sh_len) + d_len;
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+
+/*
+ * Transmit a packet (called by the kernel via "hard_start_xmit" hook).
+ */
+static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+ struct tile_net_stats_t *stats = &info->stats;
+
+ unsigned long irqflags;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ unsigned int len = skb->len;
+ unsigned char *data = skb->data;
+
+ unsigned int csum_start = skb->csum_start - skb_headroom(skb);
+
+ lepp_frag_t frags[LEPP_MAX_FRAGS];
+
+ unsigned int num_frags;
+
+ lepp_queue_t *eq = priv->epp_queue;
+
+ struct sk_buff *olds[4];
+ unsigned int wanted = 4;
+ unsigned int i, nolds = 0;
+
+ unsigned int cmd_size = sizeof(lepp_cmd_t);
+
+ unsigned int cmd_head, cmd_tail, cmd_next;
+ unsigned int comp_tail;
+
+ lepp_cmd_t cmds[LEPP_MAX_FRAGS];
+
+ unsigned int free_slots;
+
+
+ /*
+ * This is paranoia, since we think that if the link doesn't come
+ * up, telling Linux we have no carrier will keep it from trying
+ * to transmit. If it does, though, we can't execute this routine,
+ * since data structures we depend on aren't set up yet.
+ */
+ if (!info->registered)
+ return NETDEV_TX_BUSY;
+
+
+ /* Save the timestamp. */
+ dev->trans_start = jiffies;
+
+
+#ifdef TILE_NET_PARANOIA
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default) {
+ HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)data);
+ if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
+ panic("Non-coherent egress buffer!");
+ }
+#endif
+#endif
+
+
+#ifdef TILE_NET_DUMP_PACKETS
+ /* ISSUE: Does not dump the "frags". */
+ dump_packet(data, skb_headlen(skb), "tx");
+#endif /* TILE_NET_DUMP_PACKETS */
+
+
+ if (sh->gso_size != 0)
+ return tile_net_tx_tso(skb, dev);
+
+
+ /* Prepare the commands. */
+
+ num_frags = tile_net_tx_frags(frags, skb, data, skb_headlen(skb));
+
+ for (i = 0; i < num_frags; i++) {
+
+ bool final = (i == num_frags - 1);
+
+ lepp_cmd_t cmd = {
+ .cpa_lo = frags[i].cpa_lo,
+ .cpa_hi = frags[i].cpa_hi,
+ .length = frags[i].length,
+ .hash_for_home = frags[i].hash_for_home,
+ .send_completion = final,
+ .end_of_packet = final
+ };
+
+ if (i == 0 && skb->ip_summed == CHECKSUM_PARTIAL) {
+ cmd.compute_checksum = 1;
+ cmd.checksum_data.bits.start_byte = csum_start;
+ cmd.checksum_data.bits.count = len - csum_start;
+ cmd.checksum_data.bits.destination_byte =
+ csum_start + skb->csum_offset;
+ }
+
+ cmds[i] = cmd;
+ }
+
+
+ /* Prefetch and wait, to minimize time spent holding the spinlock. */
+ prefetch_L1(&eq->comp_tail);
+ prefetch_L1(&eq->cmd_tail);
+ mb();
+
+
+ /* Enqueue the commands. */
+
+ spin_lock_irqsave(&priv->cmd_lock, irqflags);
+
+ /*
+ * Handle completions if needed to make room.
+ * HACK: Spin until there is sufficient room.
+ */
+ free_slots = lepp_num_free_comp_slots(eq);
+ if (free_slots < 1) {
+spin:
+ nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
+ wanted - nolds, NULL);
+ if (lepp_num_free_comp_slots(eq) < 1)
+ goto spin;
+ }
+
+ cmd_head = eq->cmd_head;
+ cmd_tail = eq->cmd_tail;
+
+ /* NOTE: The "gotos" below are untested. */
+
+ /* Copy the commands, or fail. */
+ for (i = 0; i < num_frags; i++) {
+
+ /* Prepare to advance, detecting full queue. */
+ cmd_next = cmd_tail + cmd_size;
+ if (cmd_tail < cmd_head && cmd_next >= cmd_head)
+ goto spin;
+ if (cmd_next > LEPP_CMD_LIMIT) {
+ cmd_next = 0;
+ if (cmd_next == cmd_head)
+ goto spin;
+ }
+
+ /* Copy the command. */
+ *(lepp_cmd_t *)&eq->cmds[cmd_tail] = cmds[i];
+
+ /* Advance. */
+ cmd_tail = cmd_next;
+ }
+
+ /* Record "skb" for eventual freeing. */
+ comp_tail = eq->comp_tail;
+ eq->comps[comp_tail] = skb;
+ LEPP_QINC(comp_tail);
+ eq->comp_tail = comp_tail;
+
+ /* Flush before allowing LEPP to handle the command. */
+ __insn_mf();
+
+ eq->cmd_tail = cmd_tail;
+
+ spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
+
+ if (nolds == 0)
+ nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+
+ /* Handle completions. */
+ for (i = 0; i < nolds; i++)
+ kfree_skb(olds[i]);
+
+ /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
+ stats->tx_packets++;
+ stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN);
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+
+/*
+ * Deal with a transmit timeout.
+ */
+static void tile_net_tx_timeout(struct net_device *dev)
+{
+ PDEBUG("tile_net_tx_timeout()\n");
+ PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies,
+ jiffies - dev->trans_start);
+
+ /* XXX: ISSUE: This doesn't seem useful for us. */
+ netif_wake_queue(dev);
+}
+
+
+/*
+ * Ioctl commands.
+ */
+static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+
+/*
+ * Get System Network Statistics.
+ *
+ * Returns the address of the device statistics structure.
+ */
+static struct net_device_stats *tile_net_get_stats(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ u32 rx_packets = 0;
+ u32 tx_packets = 0;
+ u32 rx_bytes = 0;
+ u32 tx_bytes = 0;
+ int i;
+
+ for_each_online_cpu(i) {
+ if (priv->cpu[i]) {
+ rx_packets += priv->cpu[i]->stats.rx_packets;
+ rx_bytes += priv->cpu[i]->stats.rx_bytes;
+ tx_packets += priv->cpu[i]->stats.tx_packets;
+ tx_bytes += priv->cpu[i]->stats.tx_bytes;
+ }
+ }
+
+ priv->stats.rx_packets = rx_packets;
+ priv->stats.rx_bytes = rx_bytes;
+ priv->stats.tx_packets = tx_packets;
+ priv->stats.tx_bytes = tx_bytes;
+
+ return &priv->stats;
+}
+
+
+/*
+ * Change the "mtu".
+ *
+ * The "change_mtu" method is usually not needed.
+ * If you need it, it must be like this.
+ */
+static int tile_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ PDEBUG("tile_net_change_mtu()\n");
+
+ /* Check ranges. */
+ if ((new_mtu < 68) || (new_mtu > 1500))
+ return -EINVAL;
+
+ /* Accept the value. */
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+
+/*
+ * Change the Ethernet Address of the NIC.
+ *
+ * The hypervisor driver does not support changing MAC address. However,
+ * the IPP does not do anything with the MAC address, so the address which
+ * gets used on outgoing packets, and which is accepted on incoming packets,
+ * is completely up to the NetIO program or kernel driver which is actually
+ * handling them.
+ *
+ * Returns 0 on success, negative on failure.
+ */
+static int tile_net_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ /* ISSUE: Note that "dev_addr" is now a pointer. */
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ return 0;
+}
+
+
+/*
+ * Obtain the MAC address from the hypervisor.
+ * This must be done before opening the device.
+ */
+static int tile_net_get_mac(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ char hv_dev_name[32];
+ int len;
+
+ __netio_getset_offset_t offset = { .word = NETIO_IPP_PARAM_OFF };
+
+ int ret;
+
+ /* For example, "xgbe0". */
+ strcpy(hv_dev_name, dev->name);
+ len = strlen(hv_dev_name);
+
+ /* For example, "xgbe/0". */
+ hv_dev_name[len] = hv_dev_name[len - 1];
+ hv_dev_name[len - 1] = '/';
+ len++;
+
+ /* For example, "xgbe/0/native_hash". */
+ strcpy(hv_dev_name + len, hash_default ? "/native_hash" : "/native");
+
+ /* Get the hypervisor handle for this device. */
+ priv->hv_devhdl = hv_dev_open((HV_VirtAddr)hv_dev_name, 0);
+ PDEBUG("hv_dev_open(%s) returned %d %p\n",
+ hv_dev_name, priv->hv_devhdl, &priv->hv_devhdl);
+ if (priv->hv_devhdl < 0) {
+ if (priv->hv_devhdl == HV_ENODEV)
+ printk(KERN_DEBUG "Ignoring unconfigured device %s\n",
+ hv_dev_name);
+ else
+ printk(KERN_DEBUG "hv_dev_open(%s) returned %d\n",
+ hv_dev_name, priv->hv_devhdl);
+ return -1;
+ }
+
+ /*
+ * Read the hardware address from the hypervisor.
+ * ISSUE: Note that "dev_addr" is now a pointer.
+ */
+ offset.bits.class = NETIO_PARAM;
+ offset.bits.addr = NETIO_PARAM_MAC;
+ ret = hv_dev_pread(priv->hv_devhdl, 0,
+ (HV_VirtAddr)dev->dev_addr, dev->addr_len,
+ offset.word);
+ PDEBUG("hv_dev_pread(NETIO_PARAM_MAC) returned %d\n", ret);
+ if (ret <= 0) {
+ printk(KERN_DEBUG "hv_dev_pread(NETIO_PARAM_MAC) %s failed\n",
+ dev->name);
+ /*
+ * Since the device is configured by the hypervisor but we
+ * can't get its MAC address, we are most likely running
+ * the simulator, so let's generate a random MAC address.
+ */
+ random_ether_addr(dev->dev_addr);
+ }
+
+ return 0;
+}
+
+
+static struct net_device_ops tile_net_ops = {
+ .ndo_open = tile_net_open,
+ .ndo_stop = tile_net_stop,
+ .ndo_start_xmit = tile_net_tx,
+ .ndo_do_ioctl = tile_net_ioctl,
+ .ndo_get_stats = tile_net_get_stats,
+ .ndo_change_mtu = tile_net_change_mtu,
+ .ndo_tx_timeout = tile_net_tx_timeout,
+ .ndo_set_mac_address = tile_net_set_mac_address
+};
+
+
+/*
+ * The setup function.
+ *
+ * This uses ether_setup() to assign various fields in dev, including
+ * setting IFF_BROADCAST and IFF_MULTICAST, then sets some extra fields.
+ */
+static void tile_net_setup(struct net_device *dev)
+{
+ PDEBUG("tile_net_setup()\n");
+
+ ether_setup(dev);
+
+ dev->netdev_ops = &tile_net_ops;
+
+ dev->watchdog_timeo = TILE_NET_TIMEOUT;
+
+ /* We want lockless xmit. */
+ dev->features |= NETIF_F_LLTX;
+
+ /* We support hardware tx checksums. */
+ dev->features |= NETIF_F_HW_CSUM;
+
+ /* We support scatter/gather. */
+ dev->features |= NETIF_F_SG;
+
+ /* We support TSO. */
+ dev->features |= NETIF_F_TSO;
+
+#ifdef TILE_NET_GSO
+ /* We support GSO. */
+ dev->features |= NETIF_F_GSO;
+#endif
+
+ if (hash_default)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ /* ISSUE: We should support NETIF_F_UFO. */
+
+ dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
+
+ dev->mtu = TILE_NET_MTU;
+}
+
+
+/*
+ * Allocate the device structure, register the device, and obtain the
+ * MAC address from the hypervisor.
+ */
+static struct net_device *tile_net_dev_init(const char *name)
+{
+ int ret;
+ struct net_device *dev;
+ struct tile_net_priv *priv;
+ struct page *page;
+
+ /*
+ * Allocate the device structure. This allocates "priv", calls
+ * tile_net_setup(), and saves "name". Normally, "name" is a
+ * template, instantiated by register_netdev(), but not for us.
+ */
+ dev = alloc_netdev(sizeof(*priv), name, tile_net_setup);
+ if (!dev) {
+ pr_err("alloc_netdev(%s) failed\n", name);
+ return NULL;
+ }
+
+ priv = netdev_priv(dev);
+
+ /* Initialize "priv". */
+
+ memset(priv, 0, sizeof(*priv));
+
+ /* Save "dev" for "tile_net_open_retry()". */
+ priv->dev = dev;
+
+ INIT_DELAYED_WORK(&priv->retry_work, tile_net_open_retry);
+
+ spin_lock_init(&priv->cmd_lock);
+ spin_lock_init(&priv->comp_lock);
+
+ /* Allocate "epp_queue". */
+ BUG_ON(get_order(sizeof(lepp_queue_t)) != 0);
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
+ if (!page) {
+ free_netdev(dev);
+ return NULL;
+ }
+ priv->epp_queue = page_address(page);
+
+ /* Register the network device. */
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("register_netdev %s failed %d\n", dev->name, ret);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ return NULL;
+ }
+
+ /* Get the MAC address. */
+ ret = tile_net_get_mac(dev);
+ if (ret < 0) {
+ unregister_netdev(dev);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+
+/*
+ * Module cleanup.
+ */
+static void tile_net_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < TILE_NET_DEVS; i++) {
+ if (tile_net_devs[i]) {
+ struct net_device *dev = tile_net_devs[i];
+ struct tile_net_priv *priv = netdev_priv(dev);
+ unregister_netdev(dev);
+ finv_buffer(priv->epp_queue, PAGE_SIZE);
+ free_page((unsigned long)priv->epp_queue);
+ free_netdev(dev);
+ }
+ }
+}
+
+
+/*
+ * Module initialization.
+ */
+static int tile_net_init_module(void)
+{
+ pr_info("Tilera IPP Net Driver\n");
+
+ tile_net_devs[0] = tile_net_dev_init("xgbe0");
+ tile_net_devs[1] = tile_net_dev_init("xgbe1");
+ tile_net_devs[2] = tile_net_dev_init("gbe0");
+ tile_net_devs[3] = tile_net_dev_init("gbe1");
+
+ return 0;
+}
+
+
+#ifndef MODULE
+/*
+ * The "network_cpus" boot argument specifies the cpus that are dedicated
+ * to handle ingress packets.
+ *
+ * The parameter should be in the form "network_cpus=m-n[,x-y]", where
+ * m, n, x, y are integer numbers that represent the cpus that can be
+ * neither a dedicated cpu nor a dataplane cpu.
+ */
+static int __init network_cpus_setup(char *str)
+{
+ int rc = cpulist_parse_crop(str, &network_cpus_map);
+ if (rc != 0) {
+ pr_warning("network_cpus=%s: malformed cpu list\n",
+ str);
+ } else {
+
+ /* Remove dedicated cpus. */
+ cpumask_and(&network_cpus_map, &network_cpus_map,
+ cpu_possible_mask);
+
+
+ if (cpumask_empty(&network_cpus_map)) {
+ pr_warning("Ignoring network_cpus='%s'.\n",
+ str);
+ } else {
+ char buf[1024];
+ cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
+ pr_info("Linux network CPUs: %s\n", buf);
+ network_cpus_used = true;
+ }
+ }
+
+ return 0;
+}
+__setup("network_cpus=", network_cpus_setup);
+#endif
+
+
+module_init(tile_net_init_module);
+module_exit(tile_net_cleanup);
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 91e6c78271a3..4786497de03e 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -657,8 +657,9 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
#ifndef PCMCIA
/* finish figuring the shared RAM address */
if (cardpresent == TR_ISA) {
- static __u32 ram_bndry_mask[] =
- { 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 };
+ static const __u32 ram_bndry_mask[] = {
+ 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000
+ };
__u32 new_base, rrr_32, chk_base, rbm;
rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 28e1ffb13db9..b13c6b040be3 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -964,7 +964,7 @@ static void de_set_media (struct de_private *de)
dw32(MacMode, macmode);
}
-static void de_next_media (struct de_private *de, u32 *media,
+static void de_next_media (struct de_private *de, const u32 *media,
unsigned int n_media)
{
unsigned int i;
@@ -1008,10 +1008,10 @@ static void de21040_media_timer (unsigned long data)
return;
if (de->media_type == DE_MEDIA_AUI) {
- u32 next_state = DE_MEDIA_TP;
+ static const u32 next_state = DE_MEDIA_TP;
de_next_media(de, &next_state, 1);
} else {
- u32 next_state = DE_MEDIA_AUI;
+ static const u32 next_state = DE_MEDIA_AUI;
de_next_media(de, &next_state, 1);
}
@@ -1136,13 +1136,19 @@ static void de21041_media_timer (unsigned long data)
* simply resets the PHY and reloads the current media settings.
*/
if (de->media_type == DE_MEDIA_AUI) {
- u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+ static const u32 next_states[] = {
+ DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
+ };
de_next_media(de, next_states, ARRAY_SIZE(next_states));
} else if (de->media_type == DE_MEDIA_BNC) {
- u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI };
+ static const u32 next_states[] = {
+ DE_MEDIA_TP_AUTO, DE_MEDIA_AUI
+ };
de_next_media(de, next_states, ARRAY_SIZE(next_states));
} else {
- u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+ static const u32 next_states[] = {
+ DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
+ };
de_next_media(de, next_states, ARRAY_SIZE(next_states));
}
@@ -2021,7 +2027,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
de->media_timer.data = (unsigned long) de;
netif_carrier_off(dev);
- netif_stop_queue(dev);
/* wake up device, assign resources */
rc = pci_enable_device(pdev);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index a9f7d5d1a269..7064e035757a 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -688,9 +688,6 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
DMFE_DBUG(0, "dmfe_start_xmit", 0);
- /* Resource flag check */
- netif_stop_queue(dev);
-
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
pr_err("big packet = %d\n", (u16)skb->len);
@@ -698,6 +695,9 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+ /* Resource flag check */
+ netif_stop_queue(dev);
+
spin_lock_irqsave(&db->lock, flags);
/* No Tx resource check, it never happen nromally */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 2c39f2591216..5c01e260f1ba 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1302,17 +1302,18 @@ static const struct net_device_ops tulip_netdev_ops = {
#endif
};
+DEFINE_PCI_DEVICE_TABLE(early_486_chipsets) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496) },
+ { },
+};
+
static int __devinit tulip_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct tulip_private *tp;
/* See note below on the multiport cards. */
static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
- static struct pci_device_id early_486_chipsets[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424) },
- { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496) },
- { },
- };
static int last_irq;
static int multiport_cnt; /* For four-port boards w/one EEPROM */
int i, irq;
@@ -1682,7 +1683,9 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->full_duplex_lock = 1;
if (tulip_media_cap[tp->default_port] & MediaIsMII) {
- u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ static const u16 media2advert[] = {
+ 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200
+ };
tp->mii_advertise = media2advert[tp->default_port - 9];
tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 55f3a3e667a9..b100bd50a0d7 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -757,7 +757,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- gso.csum_start = skb->csum_start - skb_headroom(skb);
+ gso.csum_start = skb_checksum_start_offset(skb);
gso.csum_offset = skb->csum_offset;
} /* else everything is zero */
@@ -1309,7 +1309,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
break;
case SIOCGIFHWADDR:
- /* Get hw addres */
+ /* Get hw address */
memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
ifr.ifr_hwaddr.sa_family = tun->dev->type;
if (copy_to_user(argp, &ifr, ifreq_len))
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 5b83c3f35f47..a3c46f6a15e7 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1004,7 +1004,6 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
}
strcpy(info->driver, KBUILD_MODNAME);
- strcpy(info->version, UTS_RELEASE);
strcpy(info->bus_info, pci_name(pci_dev));
}
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index a4c3f5708246..715e7b47e7e9 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -28,6 +28,7 @@
#include <linux/phy.h>
#include <linux/workqueue.h>
#include <linux/of_mdio.h>
+#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <asm/uaccess.h>
@@ -2031,7 +2032,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev) {
/* Only support group multicast for now.
*/
- if (!(ha->addr[0] & 1))
+ if (!is_multicast_ether_addr(ha->addr))
continue;
/* Ask CPM to run CRC and set bit in
@@ -2050,12 +2051,16 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
ugeth_vdbg("%s: IN", __func__);
+ /*
+ * Tell the kernel the link is down.
+ * Must be done before disabling the controller
+ * or deadlock may happen.
+ */
+ phy_stop(phydev);
+
/* Disable the controller */
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
- /* Tell the kernel the link is down */
- phy_stop(phydev);
-
/* Mask all interrupts */
out_be32(ugeth->uccf->p_uccm, 0x00000000);
@@ -2065,9 +2070,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
/* Disable Rx and Tx */
clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
- phy_disconnect(ugeth->phydev);
- ugeth->phydev = NULL;
-
ucc_geth_memclean(ugeth);
}
@@ -3550,7 +3552,10 @@ static int ucc_geth_close(struct net_device *dev)
napi_disable(&ugeth->napi);
+ cancel_work_sync(&ugeth->timeout_work);
ucc_geth_stop(ugeth);
+ phy_disconnect(ugeth->phydev);
+ ugeth->phydev = NULL;
free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
@@ -3579,8 +3584,12 @@ static void ucc_geth_timeout_work(struct work_struct *work)
* Must reset MAC *and* PHY. This is done by reopening
* the device.
*/
- ucc_geth_close(dev);
- ucc_geth_open(dev);
+ netif_tx_stop_all_queues(dev);
+ ucc_geth_stop(ugeth);
+ ucc_geth_init_mac(ugeth);
+ /* Must start PHY here */
+ phy_start(ugeth->phydev);
+ netif_tx_start_all_queues(dev);
}
netif_tx_schedule_all(dev);
@@ -3594,7 +3603,6 @@ static void ucc_geth_timeout(struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
- netif_carrier_off(dev);
schedule_work(&ugeth->timeout_work);
}
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 05a95586f3c5..055b87ab4f07 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -899,7 +899,8 @@ struct ucc_geth_hardware_statistics {
#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size
*/
#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */
-#define UCC_GETH_UTFTT_INIT 512
+#define UCC_GETH_UTFTT_INIT 256 /* 1/2 utfs
+ due to errata */
/* Gigabit Ethernet (1000 Mbps) */
#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual
FIFO size */
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 52ffabe6db0e..6f600cced6e1 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -196,6 +196,25 @@ config USB_NET_CDC_EEM
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
+config USB_NET_CDC_NCM
+ tristate "CDC NCM support"
+ depends on USB_USBNET
+ default y
+ help
+ This driver provides support for CDC NCM (Network Control Model
+ Device USB Class Specification). The CDC NCM specification is
+ available from <http://www.usb.org/>.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module.
+
+ This driver should work with at least the following devices:
+ * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design)
+ * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design)
+ * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design)
+ * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design)
+ * Ericsson F5521gw Mobile Broadband Module
+
config USB_NET_DM9601
tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index a19b0259ae16..cac170301187 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -26,4 +26,5 @@ obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o
obj-$(CONFIG_USB_IPHETH) += ipheth.o
obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o
+obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index aea4645be7f6..6140b56cce53 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1508,6 +1508,10 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x0b95, 0x1780),
.driver_info = (unsigned long) &ax88178_info,
}, {
+ // Logitec LAN-GTJ/U2A
+ USB_DEVICE (0x0789, 0x0160),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
// Linksys USB200M Rev 2
USB_DEVICE (0x13b1, 0x0018),
.driver_info = (unsigned long) &ax88772_info,
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index b3fe0de40469..9a60e415d76b 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -99,9 +99,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
*/
buf = dev->udev->actconfig->extra;
len = dev->udev->actconfig->extralen;
- if (len)
- dev_dbg(&intf->dev,
- "CDC descriptors on config\n");
+ dev_dbg(&intf->dev, "CDC descriptors on config\n");
}
/* Maybe CDC descriptors are after the endpoint? This bug has
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
new file mode 100644
index 000000000000..d776c4a8d3c1
--- /dev/null
+++ b/drivers/net/usb/cdc_ncm.c
@@ -0,0 +1,1215 @@
+/*
+ * cdc_ncm.c
+ *
+ * Copyright (C) ST-Ericsson 2010
+ * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
+ * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
+ *
+ * USB Host Driver for Network Control Model (NCM)
+ * http://www.usb.org/developers/devclass_docs/NCM10.zip
+ *
+ * The NCM encoding, decoding and initialization logic
+ * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose this file to be licensed under the terms
+ * of the GNU General Public License (GPL) Version 2 or the 2-clause
+ * BSD license listed below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc.h>
+
+#define DRIVER_VERSION "30-Nov-2010"
+
+/* CDC NCM subclass 3.2.1 */
+#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
+
+/* Maximum NTB length */
+#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */
+#define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */
+
+/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
+#define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */
+
+#define CDC_NCM_MIN_TX_PKT 512 /* bytes */
+
+/* Default value for MaxDatagramSize */
+#define CDC_NCM_MAX_DATAGRAM_SIZE 2048 /* bytes */
+
+/*
+ * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting
+ * the last NULL entry. Any additional datagrams in NTB would be discarded.
+ */
+#define CDC_NCM_DPT_DATAGRAMS_MAX 32
+
+/* Restart the timer, if amount of datagrams is less than given value */
+#define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3
+
+/* The following macro defines the minimum header space */
+#define CDC_NCM_MIN_HDR_SIZE \
+ (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
+ (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
+
+struct connection_speed_change {
+ __le32 USBitRate; /* holds 3GPP downlink value, bits per second */
+ __le32 DSBitRate; /* holds 3GPP uplink value, bits per second */
+} __attribute__ ((packed));
+
+struct cdc_ncm_data {
+ struct usb_cdc_ncm_nth16 nth16;
+ struct usb_cdc_ncm_ndp16 ndp16;
+ struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1];
+};
+
+struct cdc_ncm_ctx {
+ struct cdc_ncm_data rx_ncm;
+ struct cdc_ncm_data tx_ncm;
+ struct usb_cdc_ncm_ntb_parameters ncm_parm;
+ struct timer_list tx_timer;
+
+ const struct usb_cdc_ncm_desc *func_desc;
+ const struct usb_cdc_header_desc *header_desc;
+ const struct usb_cdc_union_desc *union_desc;
+ const struct usb_cdc_ether_desc *ether_desc;
+
+ struct net_device *netdev;
+ struct usb_device *udev;
+ struct usb_host_endpoint *in_ep;
+ struct usb_host_endpoint *out_ep;
+ struct usb_host_endpoint *status_ep;
+ struct usb_interface *intf;
+ struct usb_interface *control;
+ struct usb_interface *data;
+
+ struct sk_buff *tx_curr_skb;
+ struct sk_buff *tx_rem_skb;
+
+ spinlock_t mtx;
+
+ u32 tx_timer_pending;
+ u32 tx_curr_offset;
+ u32 tx_curr_last_offset;
+ u32 tx_curr_frame_num;
+ u32 rx_speed;
+ u32 tx_speed;
+ u32 rx_max;
+ u32 tx_max;
+ u32 max_datagram_size;
+ u16 tx_max_datagrams;
+ u16 tx_remainder;
+ u16 tx_modulus;
+ u16 tx_ndp_modulus;
+ u16 tx_seq;
+ u16 connected;
+ u8 data_claimed;
+ u8 control_claimed;
+};
+
+static void cdc_ncm_tx_timeout(unsigned long arg);
+static const struct driver_info cdc_ncm_info;
+static struct usb_driver cdc_ncm_driver;
+static struct ethtool_ops cdc_ncm_ethtool_ops;
+
+static const struct usb_device_id cdc_devs[] = {
+ { USB_INTERFACE_INFO(USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&cdc_ncm_info,
+ },
+ {
+ },
+};
+
+MODULE_DEVICE_TABLE(usb, cdc_devs);
+
+static void
+cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ strncpy(info->driver, dev->driver_name, sizeof(info->driver));
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ strncpy(info->fw_version, dev->driver_info->description,
+ sizeof(info->fw_version));
+ usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
+}
+
+static int
+cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req,
+ void *data, u16 flags, u16 *actlen, u16 timeout)
+{
+ int err;
+
+ err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ?
+ usb_rcvctrlpipe(ctx->udev, 0) :
+ usb_sndctrlpipe(ctx->udev, 0),
+ req->bNotificationType, req->bmRequestType,
+ req->wValue,
+ req->wIndex, data,
+ req->wLength, timeout);
+
+ if (err < 0) {
+ if (actlen)
+ *actlen = 0;
+ return err;
+ }
+
+ if (actlen)
+ *actlen = err;
+
+ return 0;
+}
+
+static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
+{
+ struct usb_cdc_notification req;
+ u32 val;
+ __le16 max_datagram_size;
+ u8 flags;
+ u8 iface_no;
+ int err;
+
+ iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+
+ req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+ req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16(iface_no);
+ req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm));
+
+ err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000);
+ if (err) {
+ pr_debug("failed GET_NTB_PARAMETERS\n");
+ return 1;
+ }
+
+ /* read correct set of parameters according to device mode */
+ ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+ ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+ ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+ ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+ ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
+
+ if (ctx->func_desc != NULL)
+ flags = ctx->func_desc->bmNetworkCapabilities;
+ else
+ flags = 0;
+
+ pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
+ "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
+ "wNdpOutAlignment=%u flags=0x%x\n",
+ ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
+ ctx->tx_ndp_modulus, flags);
+
+ /* max count of tx datagrams without terminating NULL entry */
+ ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+
+ /* verify maximum size of received NTB in bytes */
+ if ((ctx->rx_max <
+ (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+ (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX)) {
+ pr_debug("Using default maximum receive length=%d\n",
+ CDC_NCM_NTB_MAX_SIZE_RX);
+ ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
+ }
+
+ /* verify maximum size of transmitted NTB in bytes */
+ if ((ctx->tx_max <
+ (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+ (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) {
+ pr_debug("Using default maximum transmit length=%d\n",
+ CDC_NCM_NTB_MAX_SIZE_TX);
+ ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
+ }
+
+ /*
+ * verify that the structure alignment is:
+ * - power of two
+ * - not greater than the maximum transmit length
+ * - not less than four bytes
+ */
+ val = ctx->tx_ndp_modulus;
+
+ if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+ (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+ pr_debug("Using default alignment: 4 bytes\n");
+ ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+ }
+
+ /*
+ * verify that the payload alignment is:
+ * - power of two
+ * - not greater than the maximum transmit length
+ * - not less than four bytes
+ */
+ val = ctx->tx_modulus;
+
+ if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+ (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+ pr_debug("Using default transmit modulus: 4 bytes\n");
+ ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+ }
+
+ /* verify the payload remainder */
+ if (ctx->tx_remainder >= ctx->tx_modulus) {
+ pr_debug("Using default transmit remainder: 0 bytes\n");
+ ctx->tx_remainder = 0;
+ }
+
+ /* adjust TX-remainder according to NCM specification. */
+ ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) &
+ (ctx->tx_modulus - 1));
+
+ /* additional configuration */
+
+ /* set CRC Mode */
+ req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+ req.bNotificationType = USB_CDC_SET_CRC_MODE;
+ req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
+ req.wIndex = cpu_to_le16(iface_no);
+ req.wLength = 0;
+
+ err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+ if (err)
+ pr_debug("Setting CRC mode off failed\n");
+
+ /* set NTB format */
+ req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+ req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
+ req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
+ req.wIndex = cpu_to_le16(iface_no);
+ req.wLength = 0;
+
+ err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+ if (err)
+ pr_debug("Setting NTB format to 16-bit failed\n");
+
+ /* set Max Datagram Size (MTU) */
+ req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+ req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16(iface_no);
+ req.wLength = cpu_to_le16(2);
+
+ err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, 1000);
+ if (err) {
+ pr_debug(" GET_MAX_DATAGRAM_SIZE failed, using size=%u\n",
+ CDC_NCM_MIN_DATAGRAM_SIZE);
+ /* use default */
+ ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+ } else {
+ ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+
+ if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
+ ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+ else if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
+ ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
+ }
+
+ if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
+ ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN;
+
+ return 0;
+}
+
+static void
+cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf)
+{
+ struct usb_host_endpoint *e;
+ u8 ep;
+
+ for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
+
+ e = intf->cur_altsetting->endpoint + ep;
+ switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_INT:
+ if (usb_endpoint_dir_in(&e->desc)) {
+ if (ctx->status_ep == NULL)
+ ctx->status_ep = e;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ if (usb_endpoint_dir_in(&e->desc)) {
+ if (ctx->in_ep == NULL)
+ ctx->in_ep = e;
+ } else {
+ if (ctx->out_ep == NULL)
+ ctx->out_ep = e;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ del_timer_sync(&ctx->tx_timer);
+
+ if (ctx->data_claimed) {
+ usb_set_intfdata(ctx->data, NULL);
+ usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
+ }
+
+ if (ctx->control_claimed) {
+ usb_set_intfdata(ctx->control, NULL);
+ usb_driver_release_interface(driver_of(ctx->intf),
+ ctx->control);
+ }
+
+ if (ctx->tx_rem_skb != NULL) {
+ dev_kfree_skb_any(ctx->tx_rem_skb);
+ ctx->tx_rem_skb = NULL;
+ }
+
+ if (ctx->tx_curr_skb != NULL) {
+ dev_kfree_skb_any(ctx->tx_curr_skb);
+ ctx->tx_curr_skb = NULL;
+ }
+
+ kfree(ctx);
+}
+
+static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct cdc_ncm_ctx *ctx;
+ struct usb_driver *driver;
+ u8 *buf;
+ int len;
+ int temp;
+ u8 iface_no;
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx == NULL)
+ goto error;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ init_timer(&ctx->tx_timer);
+ spin_lock_init(&ctx->mtx);
+ ctx->netdev = dev->net;
+
+ /* store ctx pointer in device data field */
+ dev->data[0] = (unsigned long)ctx;
+
+ /* get some pointers */
+ driver = driver_of(intf);
+ buf = intf->cur_altsetting->extra;
+ len = intf->cur_altsetting->extralen;
+
+ ctx->udev = dev->udev;
+ ctx->intf = intf;
+
+ /* parse through descriptors associated with control interface */
+ while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) {
+
+ if (buf[1] != USB_DT_CS_INTERFACE)
+ goto advance;
+
+ switch (buf[2]) {
+ case USB_CDC_UNION_TYPE:
+ if (buf[0] < sizeof(*(ctx->union_desc)))
+ break;
+
+ ctx->union_desc =
+ (const struct usb_cdc_union_desc *)buf;
+
+ ctx->control = usb_ifnum_to_if(dev->udev,
+ ctx->union_desc->bMasterInterface0);
+ ctx->data = usb_ifnum_to_if(dev->udev,
+ ctx->union_desc->bSlaveInterface0);
+ break;
+
+ case USB_CDC_ETHERNET_TYPE:
+ if (buf[0] < sizeof(*(ctx->ether_desc)))
+ break;
+
+ ctx->ether_desc =
+ (const struct usb_cdc_ether_desc *)buf;
+
+ dev->hard_mtu =
+ le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+ if (dev->hard_mtu <
+ (CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN))
+ dev->hard_mtu =
+ CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN;
+
+ else if (dev->hard_mtu >
+ (CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN))
+ dev->hard_mtu =
+ CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN;
+ break;
+
+ case USB_CDC_NCM_TYPE:
+ if (buf[0] < sizeof(*(ctx->func_desc)))
+ break;
+
+ ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf;
+ break;
+
+ default:
+ break;
+ }
+advance:
+ /* advance to next descriptor */
+ temp = buf[0];
+ buf += temp;
+ len -= temp;
+ }
+
+ /* check if we got everything */
+ if ((ctx->control == NULL) || (ctx->data == NULL) ||
+ (ctx->ether_desc == NULL))
+ goto error;
+
+ /* claim interfaces, if any */
+ if (ctx->data != intf) {
+ temp = usb_driver_claim_interface(driver, ctx->data, dev);
+ if (temp)
+ goto error;
+ ctx->data_claimed = 1;
+ }
+
+ if (ctx->control != intf) {
+ temp = usb_driver_claim_interface(driver, ctx->control, dev);
+ if (temp)
+ goto error;
+ ctx->control_claimed = 1;
+ }
+
+ iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
+
+ /* reset data interface */
+ temp = usb_set_interface(dev->udev, iface_no, 0);
+ if (temp)
+ goto error;
+
+ /* initialize data interface */
+ if (cdc_ncm_setup(ctx))
+ goto error;
+
+ /* configure data interface */
+ temp = usb_set_interface(dev->udev, iface_no, 1);
+ if (temp)
+ goto error;
+
+ cdc_ncm_find_endpoints(ctx, ctx->data);
+ cdc_ncm_find_endpoints(ctx, ctx->control);
+
+ if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
+ (ctx->status_ep == NULL))
+ goto error;
+
+ dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+
+ usb_set_intfdata(ctx->data, dev);
+ usb_set_intfdata(ctx->control, dev);
+ usb_set_intfdata(ctx->intf, dev);
+
+ temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
+ if (temp)
+ goto error;
+
+ dev_info(&dev->udev->dev, "MAC-Address: "
+ "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
+
+ dev->in = usb_rcvbulkpipe(dev->udev,
+ ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ dev->out = usb_sndbulkpipe(dev->udev,
+ ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ dev->status = ctx->status_ep;
+ dev->rx_urb_size = ctx->rx_max;
+
+ /*
+ * We should get an event when network connection is "connected" or
+ * "disconnected". Set network connection in "disconnected" state
+ * (carrier is OFF) during attach, so the IP network stack does not
+ * start IPv6 negotiation and more.
+ */
+ netif_carrier_off(dev->net);
+ ctx->tx_speed = ctx->rx_speed = 0;
+ return 0;
+
+error:
+ cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
+ dev->data[0] = 0;
+ dev_info(&dev->udev->dev, "Descriptor failure\n");
+ return -ENODEV;
+}
+
+static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ struct usb_driver *driver;
+
+ if (ctx == NULL)
+ return; /* no setup */
+
+ driver = driver_of(intf);
+
+ usb_set_intfdata(ctx->data, NULL);
+ usb_set_intfdata(ctx->control, NULL);
+ usb_set_intfdata(ctx->intf, NULL);
+
+ /* release interfaces, if any */
+ if (ctx->data_claimed) {
+ usb_driver_release_interface(driver, ctx->data);
+ ctx->data_claimed = 0;
+ }
+
+ if (ctx->control_claimed) {
+ usb_driver_release_interface(driver, ctx->control);
+ ctx->control_claimed = 0;
+ }
+
+ cdc_ncm_free(ctx);
+}
+
+static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
+{
+ if (first >= max)
+ return;
+ if (first >= end)
+ return;
+ if (end > max)
+ end = max;
+ memset(ptr + first, 0, end - first);
+}
+
+static struct sk_buff *
+cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
+{
+ struct sk_buff *skb_out;
+ u32 rem;
+ u32 offset;
+ u32 last_offset;
+ u16 n = 0;
+ u8 timeout = 0;
+
+ /* if there is a remaining skb, it gets priority */
+ if (skb != NULL)
+ swap(skb, ctx->tx_rem_skb);
+ else
+ timeout = 1;
+
+ /*
+ * +----------------+
+ * | skb_out |
+ * +----------------+
+ * ^ offset
+ * ^ last_offset
+ */
+
+ /* check if we are resuming an OUT skb */
+ if (ctx->tx_curr_skb != NULL) {
+ /* pop variables */
+ skb_out = ctx->tx_curr_skb;
+ offset = ctx->tx_curr_offset;
+ last_offset = ctx->tx_curr_last_offset;
+ n = ctx->tx_curr_frame_num;
+
+ } else {
+ /* reset variables */
+ skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC);
+ if (skb_out == NULL) {
+ if (skb != NULL) {
+ dev_kfree_skb_any(skb);
+ ctx->netdev->stats.tx_dropped++;
+ }
+ goto exit_no_skb;
+ }
+
+ /* make room for NTH and NDP */
+ offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+ ctx->tx_ndp_modulus) +
+ sizeof(struct usb_cdc_ncm_ndp16) +
+ (ctx->tx_max_datagrams + 1) *
+ sizeof(struct usb_cdc_ncm_dpe16);
+
+ /* store last valid offset before alignment */
+ last_offset = offset;
+ /* align first Datagram offset correctly */
+ offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+ /* zero buffer till the first IP datagram */
+ cdc_ncm_zero_fill(skb_out->data, 0, offset, offset);
+ n = 0;
+ ctx->tx_curr_frame_num = 0;
+ }
+
+ for (; n < ctx->tx_max_datagrams; n++) {
+ /* check if end of transmit buffer is reached */
+ if (offset >= ctx->tx_max)
+ break;
+
+ /* compute maximum buffer size */
+ rem = ctx->tx_max - offset;
+
+ if (skb == NULL) {
+ skb = ctx->tx_rem_skb;
+ ctx->tx_rem_skb = NULL;
+
+ /* check for end of skb */
+ if (skb == NULL)
+ break;
+ }
+
+ if (skb->len > rem) {
+ if (n == 0) {
+ /* won't fit, MTU problem? */
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+ ctx->netdev->stats.tx_dropped++;
+ } else {
+ /* no room for skb - store for later */
+ if (ctx->tx_rem_skb != NULL) {
+ dev_kfree_skb_any(ctx->tx_rem_skb);
+ ctx->netdev->stats.tx_dropped++;
+ }
+ ctx->tx_rem_skb = skb;
+ skb = NULL;
+
+ /* loop one more time */
+ timeout = 1;
+ }
+ break;
+ }
+
+ memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len);
+
+ ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len);
+ ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset);
+
+ /* update offset */
+ offset += skb->len;
+
+ /* store last valid offset before alignment */
+ last_offset = offset;
+
+ /* align offset correctly */
+ offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+
+ /* zero padding */
+ cdc_ncm_zero_fill(skb_out->data, last_offset, offset,
+ ctx->tx_max);
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+ }
+
+ /* free up any dangling skb */
+ if (skb != NULL) {
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+ ctx->netdev->stats.tx_dropped++;
+ }
+
+ ctx->tx_curr_frame_num = n;
+
+ if (n == 0) {
+ /* wait for more frames */
+ /* push variables */
+ ctx->tx_curr_skb = skb_out;
+ ctx->tx_curr_offset = offset;
+ ctx->tx_curr_last_offset = last_offset;
+ goto exit_no_skb;
+
+ } else if ((n < ctx->tx_max_datagrams) && (timeout == 0)) {
+ /* wait for more frames */
+ /* push variables */
+ ctx->tx_curr_skb = skb_out;
+ ctx->tx_curr_offset = offset;
+ ctx->tx_curr_last_offset = last_offset;
+ /* set the pending count */
+ if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
+ ctx->tx_timer_pending = 2;
+ goto exit_no_skb;
+
+ } else {
+ /* frame goes out */
+ /* variables will be reset at next call */
+ }
+
+ /* check for overflow */
+ if (last_offset > ctx->tx_max)
+ last_offset = ctx->tx_max;
+
+ /* revert offset */
+ offset = last_offset;
+
+ /*
+ * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes,
+ * we send buffers as it is. If we get more data, it would be more
+ * efficient for USB HS mobile device with DMA engine to receive a full
+ * size NTB, than canceling DMA transfer and receiving a short packet.
+ */
+ if (offset > CDC_NCM_MIN_TX_PKT)
+ offset = ctx->tx_max;
+
+ /* final zero padding */
+ cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max);
+
+ /* store last offset */
+ last_offset = offset;
+
+ if ((last_offset < ctx->tx_max) && ((last_offset %
+ le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) {
+ /* force short packet */
+ *(((u8 *)skb_out->data) + last_offset) = 0;
+ last_offset++;
+ }
+
+ /* zero the rest of the DPEs plus the last NULL entry */
+ for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) {
+ ctx->tx_ncm.dpe16[n].wDatagramLength = 0;
+ ctx->tx_ncm.dpe16[n].wDatagramIndex = 0;
+ }
+
+ /* fill out 16-bit NTB header */
+ ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
+ ctx->tx_ncm.nth16.wHeaderLength =
+ cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
+ ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
+ ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
+ ctx->tx_ncm.nth16.wFpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+ ctx->tx_ndp_modulus);
+
+ memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
+ ctx->tx_seq++;
+
+ /* fill out 16-bit NDP table */
+ ctx->tx_ncm.ndp16.dwSignature =
+ cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN);
+ rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
+ sizeof(struct usb_cdc_ncm_dpe16));
+ ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
+ ctx->tx_ncm.ndp16.wNextFpIndex = 0; /* reserved */
+
+ memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex,
+ &(ctx->tx_ncm.ndp16),
+ sizeof(ctx->tx_ncm.ndp16));
+
+ memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex +
+ sizeof(ctx->tx_ncm.ndp16),
+ &(ctx->tx_ncm.dpe16),
+ (ctx->tx_curr_frame_num + 1) *
+ sizeof(struct usb_cdc_ncm_dpe16));
+
+ /* set frame length */
+ skb_put(skb_out, last_offset);
+
+ /* return skb */
+ ctx->tx_curr_skb = NULL;
+ return skb_out;
+
+exit_no_skb:
+ return NULL;
+}
+
+static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
+{
+ /* start timer, if not already started */
+ if (timer_pending(&ctx->tx_timer) == 0) {
+ ctx->tx_timer.function = &cdc_ncm_tx_timeout;
+ ctx->tx_timer.data = (unsigned long)ctx;
+ ctx->tx_timer.expires = jiffies + ((HZ + 999) / 1000);
+ add_timer(&ctx->tx_timer);
+ }
+}
+
+static void cdc_ncm_tx_timeout(unsigned long arg)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)arg;
+ u8 restart;
+
+ spin_lock(&ctx->mtx);
+ if (ctx->tx_timer_pending != 0) {
+ ctx->tx_timer_pending--;
+ restart = 1;
+ } else
+ restart = 0;
+
+ spin_unlock(&ctx->mtx);
+
+ if (restart)
+ cdc_ncm_tx_timeout_start(ctx);
+ else if (ctx->netdev != NULL)
+ usbnet_start_xmit(NULL, ctx->netdev);
+}
+
+static struct sk_buff *
+cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+ struct sk_buff *skb_out;
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ u8 need_timer = 0;
+
+ /*
+ * The Ethernet API we are using does not support transmitting
+ * multiple Ethernet frames in a single call. This driver will
+ * accumulate multiple Ethernet frames and send out a larger
+ * USB frame when the USB buffer is full or when a single jiffies
+ * timeout happens.
+ */
+ if (ctx == NULL)
+ goto error;
+
+ spin_lock(&ctx->mtx);
+ skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
+ if (ctx->tx_curr_skb != NULL)
+ need_timer = 1;
+ spin_unlock(&ctx->mtx);
+
+ /* Start timer, if there is a remaining skb */
+ if (need_timer)
+ cdc_ncm_tx_timeout_start(ctx);
+
+ if (skb_out)
+ dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+ return skb_out;
+
+error:
+ if (skb != NULL)
+ dev_kfree_skb_any(skb);
+
+ return NULL;
+}
+
+static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
+{
+ struct sk_buff *skb;
+ struct cdc_ncm_ctx *ctx;
+ int sumlen;
+ int actlen;
+ int temp;
+ int nframes;
+ int x;
+ int offset;
+
+ ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ if (ctx == NULL)
+ goto error;
+
+ actlen = skb_in->len;
+ sumlen = CDC_NCM_NTB_MAX_SIZE_RX;
+
+ if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) {
+ pr_debug("frame too short\n");
+ goto error;
+ }
+
+ memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data),
+ sizeof(ctx->rx_ncm.nth16));
+
+ if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) !=
+ USB_CDC_NCM_NTH16_SIGN) {
+ pr_debug("invalid NTH16 signature <%u>\n",
+ le32_to_cpu(ctx->rx_ncm.nth16.dwSignature));
+ goto error;
+ }
+
+ temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength);
+ if (temp > sumlen) {
+ pr_debug("unsupported NTB block length %u/%u\n", temp, sumlen);
+ goto error;
+ }
+
+ temp = le16_to_cpu(ctx->rx_ncm.nth16.wFpIndex);
+ if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) {
+ pr_debug("invalid DPT16 index\n");
+ goto error;
+ }
+
+ memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp,
+ sizeof(ctx->rx_ncm.ndp16));
+
+ if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) !=
+ USB_CDC_NCM_NDP16_NOCRC_SIGN) {
+ pr_debug("invalid DPT16 signature <%u>\n",
+ le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+ goto error;
+ }
+
+ if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) <
+ USB_CDC_NCM_NDP16_LENGTH_MIN) {
+ pr_debug("invalid DPT16 length <%u>\n",
+ le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+ goto error;
+ }
+
+ nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) -
+ sizeof(struct usb_cdc_ncm_ndp16)) /
+ sizeof(struct usb_cdc_ncm_dpe16));
+ nframes--; /* we process NDP entries except for the last one */
+
+ pr_debug("nframes = %u\n", nframes);
+
+ temp += sizeof(ctx->rx_ncm.ndp16);
+
+ if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) {
+ pr_debug("Invalid nframes = %d\n", nframes);
+ goto error;
+ }
+
+ if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) {
+ pr_debug("Truncating number of frames from %u to %u\n",
+ nframes, CDC_NCM_DPT_DATAGRAMS_MAX);
+ nframes = CDC_NCM_DPT_DATAGRAMS_MAX;
+ }
+
+ memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp,
+ nframes * (sizeof(struct usb_cdc_ncm_dpe16)));
+
+ for (x = 0; x < nframes; x++) {
+ offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex);
+ temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength);
+
+ /*
+ * CDC NCM ch. 3.7
+ * All entries after first NULL entry are to be ignored
+ */
+ if ((offset == 0) || (temp == 0)) {
+ if (!x)
+ goto error; /* empty NTB */
+ break;
+ }
+
+ /* sanity checking */
+ if (((offset + temp) > actlen) ||
+ (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
+ pr_debug("invalid frame detected (ignored)"
+ "offset[%u]=%u, length=%u, skb=%p\n",
+ x, offset, temp, skb_in);
+ if (!x)
+ goto error;
+ break;
+
+ } else {
+ skb = skb_clone(skb_in, GFP_ATOMIC);
+ if (!skb)
+ goto error;
+ skb->len = temp;
+ skb->data = ((u8 *)skb_in->data) + offset;
+ skb_set_tail_pointer(skb, temp);
+ usbnet_skb_return(dev, skb);
+ }
+ }
+ return 1;
+error:
+ return 0;
+}
+
+static void
+cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
+ struct connection_speed_change *data)
+{
+ uint32_t rx_speed = le32_to_cpu(data->USBitRate);
+ uint32_t tx_speed = le32_to_cpu(data->DSBitRate);
+
+ /*
+ * Currently the USB-NET API does not support reporting the actual
+ * device speed. Do print it instead.
+ */
+ if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) {
+ ctx->tx_speed = tx_speed;
+ ctx->rx_speed = rx_speed;
+
+ if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
+ printk(KERN_INFO KBUILD_MODNAME
+ ": %s: %u mbit/s downlink "
+ "%u mbit/s uplink\n",
+ ctx->netdev->name,
+ (unsigned int)(rx_speed / 1000000U),
+ (unsigned int)(tx_speed / 1000000U));
+ } else {
+ printk(KERN_INFO KBUILD_MODNAME
+ ": %s: %u kbit/s downlink "
+ "%u kbit/s uplink\n",
+ ctx->netdev->name,
+ (unsigned int)(rx_speed / 1000U),
+ (unsigned int)(tx_speed / 1000U));
+ }
+ }
+}
+
+static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
+{
+ struct cdc_ncm_ctx *ctx;
+ struct usb_cdc_notification *event;
+
+ ctx = (struct cdc_ncm_ctx *)dev->data[0];
+
+ if (urb->actual_length < sizeof(*event))
+ return;
+
+ /* test for split data in 8-byte chunks */
+ if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+ cdc_ncm_speed_change(ctx,
+ (struct connection_speed_change *)urb->transfer_buffer);
+ return;
+ }
+
+ event = urb->transfer_buffer;
+
+ switch (event->bNotificationType) {
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+ /*
+ * According to the CDC NCM specification ch.7.1
+ * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
+ * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
+ */
+ ctx->connected = event->wValue;
+
+ printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:"
+ " %sconnected\n",
+ ctx->netdev->name, ctx->connected ? "" : "dis");
+
+ if (ctx->connected)
+ netif_carrier_on(dev->net);
+ else {
+ netif_carrier_off(dev->net);
+ ctx->tx_speed = ctx->rx_speed = 0;
+ }
+ break;
+
+ case USB_CDC_NOTIFY_SPEED_CHANGE:
+ if (urb->actual_length <
+ (sizeof(*event) + sizeof(struct connection_speed_change)))
+ set_bit(EVENT_STS_SPLIT, &dev->flags);
+ else
+ cdc_ncm_speed_change(ctx,
+ (struct connection_speed_change *) &event[1]);
+ break;
+
+ default:
+ dev_err(&dev->udev->dev, "NCM: unexpected "
+ "notification 0x%02x!\n", event->bNotificationType);
+ break;
+ }
+}
+
+static int cdc_ncm_check_connect(struct usbnet *dev)
+{
+ struct cdc_ncm_ctx *ctx;
+
+ ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ if (ctx == NULL)
+ return 1; /* disconnected */
+
+ return !ctx->connected;
+}
+
+static int
+cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod)
+{
+ return usbnet_probe(udev, prod);
+}
+
+static void cdc_ncm_disconnect(struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ if (dev == NULL)
+ return; /* already disconnected */
+
+ usbnet_disconnect(intf);
+}
+
+static int cdc_ncm_manage_power(struct usbnet *dev, int status)
+{
+ dev->intf->needs_remote_wakeup = status;
+ return 0;
+}
+
+static const struct driver_info cdc_ncm_info = {
+ .description = "CDC NCM",
+ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+ .bind = cdc_ncm_bind,
+ .unbind = cdc_ncm_unbind,
+ .check_connect = cdc_ncm_check_connect,
+ .manage_power = cdc_ncm_manage_power,
+ .status = cdc_ncm_status,
+ .rx_fixup = cdc_ncm_rx_fixup,
+ .tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static struct usb_driver cdc_ncm_driver = {
+ .name = "cdc_ncm",
+ .id_table = cdc_devs,
+ .probe = cdc_ncm_probe,
+ .disconnect = cdc_ncm_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+ .supports_autosuspend = 1,
+};
+
+static struct ethtool_ops cdc_ncm_ethtool_ops = {
+ .get_drvinfo = cdc_ncm_get_drvinfo,
+ .get_link = usbnet_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int __init cdc_ncm_init(void)
+{
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION "\n");
+ return usb_register(&cdc_ncm_driver);
+}
+
+module_init(cdc_ncm_init);
+
+static void __exit cdc_ncm_exit(void)
+{
+ usb_deregister(&cdc_ncm_driver);
+}
+
+module_exit(cdc_ncm_exit);
+
+MODULE_AUTHOR("Hans Petter Selasky");
+MODULE_DESCRIPTION("USB CDC NCM host driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index b154a94de03e..bed8fcedff49 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -958,10 +958,6 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
/* Packet is complete. Inject into stack. */
/* We have IP packet here */
odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP);
- /* don't check it */
- odev->skb_rx_buf->ip_summed =
- CHECKSUM_UNNECESSARY;
-
skb_reset_mac_header(odev->skb_rx_buf);
/* Ship it off to the kernel */
@@ -1001,6 +997,18 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
}
}
+static void fix_crc_bug(struct urb *urb, __le16 max_packet_size)
+{
+ static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
+ u32 rest = urb->actual_length % le16_to_cpu(max_packet_size);
+
+ if (((rest == 5) || (rest == 6)) &&
+ !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4,
+ crc_check, 4)) {
+ urb->actual_length -= 4;
+ }
+}
+
/* Moving data from usb to kernel (in interrupt state) */
static void read_bulk_callback(struct urb *urb)
{
@@ -1029,17 +1037,8 @@ static void read_bulk_callback(struct urb *urb)
return;
}
- if (odev->parent->port_spec & HSO_INFO_CRC_BUG) {
- u32 rest;
- u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
- rest = urb->actual_length %
- le16_to_cpu(odev->in_endp->wMaxPacketSize);
- if (((rest == 5) || (rest == 6)) &&
- !memcmp(((u8 *) urb->transfer_buffer) +
- urb->actual_length - 4, crc_check, 4)) {
- urb->actual_length -= 4;
- }
- }
+ if (odev->parent->port_spec & HSO_INFO_CRC_BUG)
+ fix_crc_bug(urb, odev->in_endp->wMaxPacketSize);
/* do we even have a packet? */
if (urb->actual_length) {
@@ -1231,18 +1230,8 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
return;
if (status == 0) {
- if (serial->parent->port_spec & HSO_INFO_CRC_BUG) {
- u32 rest;
- u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
- rest =
- urb->actual_length %
- le16_to_cpu(serial->in_endp->wMaxPacketSize);
- if (((rest == 5) || (rest == 6)) &&
- !memcmp(((u8 *) urb->transfer_buffer) +
- urb->actual_length - 4, crc_check, 4)) {
- urb->actual_length -= 4;
- }
- }
+ if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
+ fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
/* Valid data, handle RX data */
spin_lock(&serial->serial_lock);
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
@@ -1745,7 +1734,6 @@ static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hso_serial *serial = get_serial_by_tty(tty);
- void __user *uarg = (void __user *)arg;
int ret = 0;
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
@@ -2994,12 +2982,14 @@ static int hso_probe(struct usb_interface *interface,
case HSO_INTF_BULK:
/* It's a regular bulk interface */
- if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) &&
- !disable_net)
- hso_dev = hso_create_net_device(interface, port_spec);
- else
+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
+ if (!disable_net)
+ hso_dev =
+ hso_create_net_device(interface, port_spec);
+ } else {
hso_dev =
hso_create_bulk_serial_device(interface, port_spec);
+ }
if (!hso_dev)
goto exit;
break;
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index b2bcf99e6f08..7d42f9a2c068 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -363,7 +363,7 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
/* Paranoid */
if (skb->len > IPHETH_BUF_SIZE) {
- WARN(1, "%s: skb too large: %d bytes", __func__, skb->len);
+ WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
dev->net->stats.tx_dropped++;
dev_kfree_skb_irq(skb);
return NETDEV_TX_OK;
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index a6281e3987b5..2b791392e788 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -1,5 +1,5 @@
/*
- * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices
+ * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
*
* based on usbnet.c, asix.c and the vendor provided mcs7830 driver
*
@@ -11,6 +11,9 @@
*
* Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
*
+ * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"),
+ * per active notification by manufacturer
+ *
* TODO:
* - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
* - implement ethtool_ops get_pauseparam/set_pauseparam
@@ -60,6 +63,7 @@
#define MCS7830_MAX_MCAST 64
#define MCS7830_VENDOR_ID 0x9710
+#define MCS7832_PRODUCT_ID 0x7832
#define MCS7830_PRODUCT_ID 0x7830
#define MCS7730_PRODUCT_ID 0x7730
@@ -351,7 +355,7 @@ static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART );
- return ret < 0 ? : 0;
+ return ret;
}
@@ -626,7 +630,7 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
static const struct driver_info moschip_info = {
- .description = "MOSCHIP 7830/7730 usb-NET adapter",
+ .description = "MOSCHIP 7830/7832/7730 usb-NET adapter",
.bind = mcs7830_bind,
.rx_fixup = mcs7830_rx_fixup,
.flags = FLAG_ETHER,
@@ -645,6 +649,10 @@ static const struct driver_info sitecom_info = {
static const struct usb_device_id products[] = {
{
+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID),
+ .driver_info = (unsigned long) &moschip_info,
+ },
+ {
USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
.driver_info = (unsigned long) &moschip_info,
},
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 6710f09346d6..ef3667690b12 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -359,7 +359,7 @@ fail:
static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
- pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
+ pegasus_t *pegasus = netdev_priv(dev);
u16 res;
read_mii_word(pegasus, phy_id, loc, &res);
@@ -397,7 +397,7 @@ fail:
static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
{
- pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
+ pegasus_t *pegasus = netdev_priv(dev);
write_mii_word(pegasus, phy_id, loc, val);
}
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index d1ac15c95faf..ed1b43210584 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -802,10 +802,9 @@ static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
dev_dbg(&dev->udev->dev, "%s", __func__);
- /* Kill the timer then flush the work queue */
+ /* kill the timer and work */
del_timer_sync(&priv->sync_timer);
-
- flush_scheduled_work();
+ cancel_work_sync(&priv->sierra_net_kevent);
/* tell modem we are going away */
status = sierra_net_send_cmd(dev, priv->shdwn_msg,
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 65cb1abfbe57..bc86f4b6ecc2 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1163,9 +1163,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
{
- int len = skb->data - skb->head;
- u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len);
- u16 low_16 = (u16)(skb->csum_start - len);
+ u16 low_16 = (u16)skb_checksum_start_offset(skb);
+ u16 high_16 = low_16 + skb->csum_offset;
return (high_16 << 16) | low_16;
}
@@ -1193,7 +1192,7 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
if (skb->len <= 45) {
/* workaround - hardware tx checksum does not work
* properly with extremely small packets */
- long csstart = skb->csum_start - skb_headroom(skb);
+ long csstart = skb_checksum_start_offset(skb);
__wsum calc = csum_partial(skb->data + csstart,
skb->len - csstart, 0);
*((__sum16 *)(skb->data + csstart
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ca7fc9df1ccf..ed9a41643ff4 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -45,6 +45,7 @@
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
#define DRIVER_VERSION "22-Aug-2005"
@@ -390,14 +391,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
goto error;
// else network stack removes extra byte if we forced a short packet
- if (skb->len)
- usbnet_skb_return (dev, skb);
- else {
- netif_dbg(dev, rx_err, dev->net, "drop\n");
-error:
- dev->net->stats.rx_errors++;
- skb_queue_tail (&dev->done, skb);
+ if (skb->len) {
+ /* all data was already cloned from skb inside the driver */
+ if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+ dev_kfree_skb_any(skb);
+ else
+ usbnet_skb_return(dev, skb);
+ return;
}
+
+ netif_dbg(dev, rx_err, dev->net, "drop\n");
+error:
+ dev->net->stats.rx_errors++;
+ skb_queue_tail(&dev->done, skb);
}
/*-------------------------------------------------------------------------*/
@@ -970,7 +976,8 @@ static void tx_complete (struct urb *urb)
struct usbnet *dev = entry->dev;
if (urb->status == 0) {
- dev->net->stats.tx_packets++;
+ if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
+ dev->net->stats.tx_packets++;
dev->net->stats.tx_bytes += entry->length;
} else {
dev->net->stats.tx_errors++;
@@ -1043,8 +1050,13 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (info->tx_fixup) {
skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
if (!skb) {
- netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
- goto drop;
+ if (netif_msg_tx_err(dev)) {
+ netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
+ goto drop;
+ } else {
+ /* cdc_ncm collected packet; waits for more */
+ goto not_drop;
+ }
}
}
length = skb->len;
@@ -1066,13 +1078,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
/* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect
* the ZLP here, but ignore the one-byte packet.
+ * NOTE2: CDC NCM specification is different from CDC ECM when
+ * handling ZLP/short packets, so cdc_ncm driver will make short
+ * packet itself if needed.
*/
if (length % dev->maxpacket == 0) {
if (!(info->flags & FLAG_SEND_ZLP)) {
- urb->transfer_buffer_length++;
- if (skb_tailroom(skb)) {
- skb->data[skb->len] = 0;
- __skb_put(skb, 1);
+ if (!(info->flags & FLAG_MULTI_PACKET)) {
+ urb->transfer_buffer_length++;
+ if (skb_tailroom(skb)) {
+ skb->data[skb->len] = 0;
+ __skb_put(skb, 1);
+ }
}
} else
urb->transfer_flags |= URB_ZERO_PACKET;
@@ -1121,6 +1138,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
drop:
dev->net->stats.tx_dropped++;
+not_drop:
if (skb)
dev_kfree_skb_any (skb);
usb_free_urb (urb);
@@ -1230,8 +1248,7 @@ void usbnet_disconnect (struct usb_interface *intf)
net = dev->net;
unregister_netdev (net);
- /* we don't hold rtnl here ... */
- flush_scheduled_work ();
+ cancel_work_sync(&dev->kevent);
if (dev->driver_info->unbind)
dev->driver_info->unbind (dev, intf);
@@ -1273,6 +1290,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct usb_device *xdev;
int status;
const char *name;
+ struct usb_driver *driver = to_usb_driver(udev->dev.driver);
+
+ /* usbnet already took usb runtime pm, so have to enable the feature
+ * for usb interface, otherwise usb_autopm_get_interface may return
+ * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+ */
+ if (!driver->supports_autosuspend) {
+ driver->supports_autosuspend = 1;
+ pm_runtime_enable(&udev->dev);
+ }
name = udev->dev.driver->name;
info = (struct driver_info *) prod->driver_info;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 0bbc0c323135..cc83fa71c3ff 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -166,7 +166,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (!(rcv->flags & IFF_UP))
goto tx_drop;
- if (dev->features & NETIF_F_NO_CSUM)
+ /* don't change ip_summed == CHECKSUM_PARTIAL, as that
+ will cause bad checksum on forwarded packets */
+ if (skb->ip_summed == CHECKSUM_NONE)
skb->ip_summed = rcv_priv->ip_summed;
length = skb->len + ETH_HLEN;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 4930f9dbc493..5e7f069eab53 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -30,8 +30,8 @@
*/
#define DRV_NAME "via-rhine"
-#define DRV_VERSION "1.4.3"
-#define DRV_RELDATE "2007-03-06"
+#define DRV_VERSION "1.5.0"
+#define DRV_RELDATE "2010-10-09"
/* A few user-configurable values.
@@ -100,6 +100,7 @@ static const int multicast_filter_limit = 32;
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
+#include <linux/if_vlan.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
@@ -133,6 +134,9 @@ MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
+#define MCAM_SIZE 32
+#define VCAM_SIZE 32
+
/*
Theory of Operation
@@ -279,15 +283,16 @@ MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
/* Offsets to the device registers. */
enum register_offsets {
StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
- ChipCmd1=0x09,
+ ChipCmd1=0x09, TQWake=0x0A,
IntrStatus=0x0C, IntrEnable=0x0E,
MulticastFilter0=0x10, MulticastFilter1=0x14,
RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
- MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
+ MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, PCIBusConfig1=0x6F,
MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
StickyHW=0x83, IntrStatus2=0x84,
+ CamMask=0x88, CamCon=0x92, CamAddr=0x93,
WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4,
WOLcrClr1=0xA6, WOLcgClr=0xA7,
PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
@@ -299,6 +304,40 @@ enum backoff_bits {
BackCaptureEffect=0x04, BackRandom=0x08
};
+/* Bits in the TxConfig (TCR) register */
+enum tcr_bits {
+ TCR_PQEN=0x01,
+ TCR_LB0=0x02, /* loopback[0] */
+ TCR_LB1=0x04, /* loopback[1] */
+ TCR_OFSET=0x08,
+ TCR_RTGOPT=0x10,
+ TCR_RTFT0=0x20,
+ TCR_RTFT1=0x40,
+ TCR_RTSF=0x80,
+};
+
+/* Bits in the CamCon (CAMC) register */
+enum camcon_bits {
+ CAMC_CAMEN=0x01,
+ CAMC_VCAMSL=0x02,
+ CAMC_CAMWR=0x04,
+ CAMC_CAMRD=0x08,
+};
+
+/* Bits in the PCIBusConfig1 (BCR1) register */
+enum bcr1_bits {
+ BCR1_POT0=0x01,
+ BCR1_POT1=0x02,
+ BCR1_POT2=0x04,
+ BCR1_CTFT0=0x08,
+ BCR1_CTFT1=0x10,
+ BCR1_CTSF=0x20,
+ BCR1_TXQNOBK=0x40, /* for VT6105 */
+ BCR1_VIDFR=0x80, /* for VT6105 */
+ BCR1_MED0=0x40, /* for VT6102 */
+ BCR1_MED1=0x80, /* for VT6102 */
+};
+
#ifdef USE_MMIO
/* Registers we check that mmio and reg are the same. */
static const int mmio_verify_registers[] = {
@@ -356,6 +395,11 @@ enum desc_status_bits {
DescOwn=0x80000000
};
+/* Bits in *_desc.*_length */
+enum desc_length_bits {
+ DescTag=0x00010000
+};
+
/* Bits in ChipCmd. */
enum chip_cmd_bits {
CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08,
@@ -365,6 +409,9 @@ enum chip_cmd_bits {
};
struct rhine_private {
+ /* Bit mask for configured VLAN ids */
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+
/* Descriptor rings */
struct rx_desc *rx_ring;
struct tx_desc *tx_ring;
@@ -405,6 +452,23 @@ struct rhine_private {
void __iomem *base;
};
+#define BYTE_REG_BITS_ON(x, p) do { iowrite8((ioread8((p))|(x)), (p)); } while (0)
+#define WORD_REG_BITS_ON(x, p) do { iowrite16((ioread16((p))|(x)), (p)); } while (0)
+#define DWORD_REG_BITS_ON(x, p) do { iowrite32((ioread32((p))|(x)), (p)); } while (0)
+
+#define BYTE_REG_BITS_IS_ON(x, p) (ioread8((p)) & (x))
+#define WORD_REG_BITS_IS_ON(x, p) (ioread16((p)) & (x))
+#define DWORD_REG_BITS_IS_ON(x, p) (ioread32((p)) & (x))
+
+#define BYTE_REG_BITS_OFF(x, p) do { iowrite8(ioread8((p)) & (~(x)), (p)); } while (0)
+#define WORD_REG_BITS_OFF(x, p) do { iowrite16(ioread16((p)) & (~(x)), (p)); } while (0)
+#define DWORD_REG_BITS_OFF(x, p) do { iowrite32(ioread32((p)) & (~(x)), (p)); } while (0)
+
+#define BYTE_REG_BITS_SET(x, m, p) do { iowrite8((ioread8((p)) & (~(m)))|(x), (p)); } while (0)
+#define WORD_REG_BITS_SET(x, m, p) do { iowrite16((ioread16((p)) & (~(m)))|(x), (p)); } while (0)
+#define DWORD_REG_BITS_SET(x, m, p) do { iowrite32((ioread32((p)) & (~(m)))|(x), (p)); } while (0)
+
+
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int rhine_open(struct net_device *dev);
@@ -422,6 +486,14 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static int rhine_close(struct net_device *dev);
static void rhine_shutdown (struct pci_dev *pdev);
+static void rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
+static void rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
+static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr);
+static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr);
+static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask);
+static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
+static void rhine_init_cam_filter(struct net_device *dev);
+static void rhine_update_vcam(struct net_device *dev);
#define RHINE_WAIT_FOR(condition) do { \
int i=1024; \
@@ -629,6 +701,8 @@ static const struct net_device_ops rhine_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = rhine_tx_timeout,
+ .ndo_vlan_rx_add_vid = rhine_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = rhine_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rhine_poll,
#endif
@@ -795,6 +869,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+ if (pdev->revision >= VT6105M)
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
/* dev->name not defined before register_netdev()! */
rc = register_netdev(dev);
if (rc)
@@ -1040,6 +1118,167 @@ static void rhine_set_carrier(struct mii_if_info *mii)
netif_carrier_ok(mii->dev));
}
+/**
+ * rhine_set_cam - set CAM multicast filters
+ * @ioaddr: register block of this Rhine
+ * @idx: multicast CAM index [0..MCAM_SIZE-1]
+ * @addr: multicast address (6 bytes)
+ *
+ * Load addresses into multicast filters.
+ */
+static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr)
+{
+ int i;
+
+ iowrite8(CAMC_CAMEN, ioaddr + CamCon);
+ wmb();
+
+ /* Paranoid -- idx out of range should never happen */
+ idx &= (MCAM_SIZE - 1);
+
+ iowrite8((u8) idx, ioaddr + CamAddr);
+
+ for (i = 0; i < 6; i++, addr++)
+ iowrite8(*addr, ioaddr + MulticastFilter0 + i);
+ udelay(10);
+ wmb();
+
+ iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
+ udelay(10);
+
+ iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_vlan_cam - set CAM VLAN filters
+ * @ioaddr: register block of this Rhine
+ * @idx: VLAN CAM index [0..VCAM_SIZE-1]
+ * @addr: VLAN ID (2 bytes)
+ *
+ * Load addresses into VLAN filters.
+ */
+static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr)
+{
+ iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
+ wmb();
+
+ /* Paranoid -- idx out of range should never happen */
+ idx &= (VCAM_SIZE - 1);
+
+ iowrite8((u8) idx, ioaddr + CamAddr);
+
+ iowrite16(*((u16 *) addr), ioaddr + MulticastFilter0 + 6);
+ udelay(10);
+ wmb();
+
+ iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
+ udelay(10);
+
+ iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_cam_mask - set multicast CAM mask
+ * @ioaddr: register block of this Rhine
+ * @mask: multicast CAM mask
+ *
+ * Mask sets multicast filters active/inactive.
+ */
+static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask)
+{
+ iowrite8(CAMC_CAMEN, ioaddr + CamCon);
+ wmb();
+
+ /* write mask */
+ iowrite32(mask, ioaddr + CamMask);
+
+ /* disable CAMEN */
+ iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_vlan_cam_mask - set VLAN CAM mask
+ * @ioaddr: register block of this Rhine
+ * @mask: VLAN CAM mask
+ *
+ * Mask sets VLAN filters active/inactive.
+ */
+static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask)
+{
+ iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
+ wmb();
+
+ /* write mask */
+ iowrite32(mask, ioaddr + CamMask);
+
+ /* disable CAMEN */
+ iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_init_cam_filter - initialize CAM filters
+ * @dev: network device
+ *
+ * Initialize (disable) hardware VLAN and multicast support on this
+ * Rhine.
+ */
+static void rhine_init_cam_filter(struct net_device *dev)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+
+ /* Disable all CAMs */
+ rhine_set_vlan_cam_mask(ioaddr, 0);
+ rhine_set_cam_mask(ioaddr, 0);
+
+ /* disable hardware VLAN support */
+ BYTE_REG_BITS_ON(TCR_PQEN, ioaddr + TxConfig);
+ BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+}
+
+/**
+ * rhine_update_vcam - update VLAN CAM filters
+ * @rp: rhine_private data of this Rhine
+ *
+ * Update VLAN CAM filters to match configuration change.
+ */
+static void rhine_update_vcam(struct net_device *dev)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+ u16 vid;
+ u32 vCAMmask = 0; /* 32 vCAMs (6105M and better) */
+ unsigned int i = 0;
+
+ for_each_set_bit(vid, rp->active_vlans, VLAN_N_VID) {
+ rhine_set_vlan_cam(ioaddr, i, (u8 *)&vid);
+ vCAMmask |= 1 << i;
+ if (++i >= VCAM_SIZE)
+ break;
+ }
+ rhine_set_vlan_cam_mask(ioaddr, vCAMmask);
+}
+
+static void rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+
+ spin_lock_irq(&rp->lock);
+ set_bit(vid, rp->active_vlans);
+ rhine_update_vcam(dev);
+ spin_unlock_irq(&rp->lock);
+}
+
+static void rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+
+ spin_lock_irq(&rp->lock);
+ clear_bit(vid, rp->active_vlans);
+ rhine_update_vcam(dev);
+ spin_unlock_irq(&rp->lock);
+}
+
static void init_registers(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -1061,6 +1300,9 @@ static void init_registers(struct net_device *dev)
rhine_set_rx_mode(dev);
+ if (rp->pdev->revision >= VT6105M)
+ rhine_init_cam_filter(dev);
+
napi_enable(&rp->napi);
/* Enable interrupts by setting the interrupt mask. */
@@ -1276,16 +1518,28 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
rp->tx_ring[entry].desc_length =
cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ if (unlikely(vlan_tx_tag_present(skb))) {
+ rp->tx_ring[entry].tx_status = cpu_to_le32((vlan_tx_tag_get(skb)) << 16);
+ /* request tagging */
+ rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
+ }
+ else
+ rp->tx_ring[entry].tx_status = 0;
+
/* lock eth irq */
spin_lock_irqsave(&rp->lock, flags);
wmb();
- rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+ rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
wmb();
rp->cur_tx++;
/* Non-x86 Todo: explicitly flush cache lines here. */
+ if (vlan_tx_tag_present(skb))
+ /* Tx queues are bits 7-0 (first Tx queue: bit 7) */
+ BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
+
/* Wake the potentially-idle transmit channel */
iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
ioaddr + ChipCmd1);
@@ -1437,6 +1691,21 @@ static void rhine_tx(struct net_device *dev)
spin_unlock(&rp->lock);
}
+/**
+ * rhine_get_vlan_tci - extract TCI from Rx data buffer
+ * @skb: pointer to sk_buff
+ * @data_size: used data area of the buffer including CRC
+ *
+ * If hardware VLAN tag extraction is enabled and the chip indicates a 802.1Q
+ * packet, the extracted 802.1Q header (2 bytes TPID + 2 bytes TCI) is 4-byte
+ * aligned following the CRC.
+ */
+static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
+{
+ u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2;
+ return ntohs(*(u16 *)trailer);
+}
+
/* Process up to limit frames from receive ring */
static int rhine_rx(struct net_device *dev, int limit)
{
@@ -1454,6 +1723,7 @@ static int rhine_rx(struct net_device *dev, int limit)
for (count = 0; count < limit; ++count) {
struct rx_desc *desc = rp->rx_head_desc;
u32 desc_status = le32_to_cpu(desc->rx_status);
+ u32 desc_length = le32_to_cpu(desc->desc_length);
int data_size = desc_status >> 16;
if (desc_status & DescOwn)
@@ -1498,6 +1768,7 @@ static int rhine_rx(struct net_device *dev, int limit)
struct sk_buff *skb = NULL;
/* Length should omit the CRC */
int pkt_len = data_size - 4;
+ u16 vlan_tci = 0;
/* Check if the packet is long enough to accept without
copying to a minimally-sized skbuff. */
@@ -1532,7 +1803,14 @@ static int rhine_rx(struct net_device *dev, int limit)
rp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
}
+
+ if (unlikely(desc_length & DescTag))
+ vlan_tci = rhine_get_vlan_tci(skb, data_size);
+
skb->protocol = eth_type_trans(skb, dev);
+
+ if (unlikely(desc_length & DescTag))
+ __vlan_hwaccel_put_tag(skb, vlan_tci);
netif_receive_skb(skb);
dev->stats.rx_bytes += pkt_len;
dev->stats.rx_packets++;
@@ -1596,6 +1874,11 @@ static void rhine_restart_tx(struct net_device *dev) {
iowrite8(ioread8(ioaddr + ChipCmd) | CmdTxOn,
ioaddr + ChipCmd);
+
+ if (rp->tx_ring[entry].desc_length & cpu_to_le32(0x020000))
+ /* Tx queues are bits 7-0 (first Tx queue: bit 7) */
+ BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
+
iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
ioaddr + ChipCmd1);
IOSYNC;
@@ -1631,7 +1914,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
}
if (intr_status & IntrTxUnderrun) {
if (rp->tx_thresh < 0xE0)
- iowrite8(rp->tx_thresh += 0x20, ioaddr + TxConfig);
+ BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
if (debug > 1)
printk(KERN_INFO "%s: Transmitter underrun, Tx "
"threshold now %2.2x.\n",
@@ -1646,7 +1929,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
(intr_status & (IntrTxAborted |
IntrTxUnderrun | IntrTxDescRace)) == 0) {
if (rp->tx_thresh < 0xE0) {
- iowrite8(rp->tx_thresh += 0x20, ioaddr + TxConfig);
+ BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
}
if (debug > 1)
printk(KERN_INFO "%s: Unspecified error. Tx "
@@ -1688,7 +1971,8 @@ static void rhine_set_rx_mode(struct net_device *dev)
struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
u32 mc_filter[2]; /* Multicast hash filter */
- u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */
+ u8 rx_mode = 0x0C; /* Note: 0x02=accept runt, 0x01=accept errs */
+ struct netdev_hw_addr *ha;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
rx_mode = 0x1C;
@@ -1699,10 +1983,18 @@ static void rhine_set_rx_mode(struct net_device *dev)
/* Too many to match, or accept all multicasts. */
iowrite32(0xffffffff, ioaddr + MulticastFilter0);
iowrite32(0xffffffff, ioaddr + MulticastFilter1);
- rx_mode = 0x0C;
+ } else if (rp->pdev->revision >= VT6105M) {
+ int i = 0;
+ u32 mCAMmask = 0; /* 32 mCAMs (6105M and better) */
+ netdev_for_each_mc_addr(ha, dev) {
+ if (i == MCAM_SIZE)
+ break;
+ rhine_set_cam(ioaddr, i, ha->addr);
+ mCAMmask |= 1 << i;
+ i++;
+ }
+ rhine_set_cam_mask(ioaddr, mCAMmask);
} else {
- struct netdev_hw_addr *ha;
-
memset(mc_filter, 0, sizeof(mc_filter));
netdev_for_each_mc_addr(ha, dev) {
int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
@@ -1711,9 +2003,15 @@ static void rhine_set_rx_mode(struct net_device *dev)
}
iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
- rx_mode = 0x0C;
}
- iowrite8(rp->rx_thresh | rx_mode, ioaddr + RxConfig);
+ /* enable/disable VLAN receive filtering */
+ if (rp->pdev->revision >= VT6105M) {
+ if (dev->flags & IFF_PROMISC)
+ BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+ else
+ BYTE_REG_BITS_ON(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+ }
+ BYTE_REG_BITS_ON(rx_mode, ioaddr + RxConfig);
}
static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -1966,7 +2264,7 @@ static int rhine_resume(struct pci_dev *pdev)
if (!netif_running(dev))
return 0;
- if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
+ if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name);
ret = pci_set_power_state(pdev, PCI_D0);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index cab96ad49e60..09cac704fdd7 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -898,7 +898,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
set_mii_flow_control(vptr);
/*
- Check if new status is consisent with current status
+ Check if new status is consistent with current status
if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) ||
(mii_status==curr_status)) {
vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bb6b67f6b0cc..90a23e410d1b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -519,7 +519,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
if (skb->ip_summed == CHECKSUM_PARTIAL) {
hdr->hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- hdr->hdr.csum_start = skb->csum_start - skb_headroom(skb);
+ hdr->hdr.csum_start = skb_checksum_start_offset(skb);
hdr->hdr.csum_offset = skb->csum_offset;
} else {
hdr->hdr.flags = 0;
@@ -986,9 +986,15 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
- vi->status = VIRTIO_NET_S_LINK_UP;
- virtnet_update_status(vi);
- netif_carrier_on(dev);
+ /* Assume link up if device can't report link status,
+ otherwise get link status from config. */
+ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+ netif_carrier_off(dev);
+ virtnet_update_status(vi);
+ } else {
+ vi->status = VIRTIO_NET_S_LINK_UP;
+ netif_carrier_on(dev);
+ }
pr_debug("virtnet: registered device %s\n", dev->name);
return 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index e3658e10db39..d143e8b72b5b 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -44,6 +44,9 @@ MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
static atomic_t devices_found;
+#define VMXNET3_MAX_DEVICES 10
+static int enable_mq = 1;
+static int irq_share_mode;
/*
* Enable/Disable the given intr
@@ -99,7 +102,7 @@ vmxnet3_ack_events(struct vmxnet3_adapter *adapter, u32 events)
static bool
vmxnet3_tq_stopped(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
{
- return netif_queue_stopped(adapter->netdev);
+ return tq->stopped;
}
@@ -107,7 +110,7 @@ static void
vmxnet3_tq_start(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
{
tq->stopped = false;
- netif_start_queue(adapter->netdev);
+ netif_start_subqueue(adapter->netdev, tq - adapter->tx_queue);
}
@@ -115,7 +118,7 @@ static void
vmxnet3_tq_wake(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
{
tq->stopped = false;
- netif_wake_queue(adapter->netdev);
+ netif_wake_subqueue(adapter->netdev, (tq - adapter->tx_queue));
}
@@ -124,7 +127,7 @@ vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
{
tq->stopped = true;
tq->num_stop++;
- netif_stop_queue(adapter->netdev);
+ netif_stop_subqueue(adapter->netdev, (tq - adapter->tx_queue));
}
@@ -135,6 +138,7 @@ static void
vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
{
u32 ret;
+ int i;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
@@ -145,22 +149,28 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
if (!netif_carrier_ok(adapter->netdev))
netif_carrier_on(adapter->netdev);
- if (affectTxQueue)
- vmxnet3_tq_start(&adapter->tx_queue, adapter);
+ if (affectTxQueue) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_start(&adapter->tx_queue[i],
+ adapter);
+ }
} else {
printk(KERN_INFO "%s: NIC Link is Down\n",
adapter->netdev->name);
if (netif_carrier_ok(adapter->netdev))
netif_carrier_off(adapter->netdev);
- if (affectTxQueue)
- vmxnet3_tq_stop(&adapter->tx_queue, adapter);
+ if (affectTxQueue) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_stop(&adapter->tx_queue[i], adapter);
+ }
}
}
static void
vmxnet3_process_events(struct vmxnet3_adapter *adapter)
{
+ int i;
u32 events = le32_to_cpu(adapter->shared->ecr);
if (!events)
return;
@@ -176,16 +186,18 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_GET_QUEUE_STATUS);
- if (adapter->tqd_start->status.stopped) {
- printk(KERN_ERR "%s: tq error 0x%x\n",
- adapter->netdev->name,
- le32_to_cpu(adapter->tqd_start->status.error));
- }
- if (adapter->rqd_start->status.stopped) {
- printk(KERN_ERR "%s: rq error 0x%x\n",
- adapter->netdev->name,
- adapter->rqd_start->status.error);
- }
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ if (adapter->tqd_start[i].status.stopped)
+ dev_err(&adapter->netdev->dev,
+ "%s: tq[%d] error 0x%x\n",
+ adapter->netdev->name, i, le32_to_cpu(
+ adapter->tqd_start[i].status.error));
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ if (adapter->rqd_start[i].status.stopped)
+ dev_err(&adapter->netdev->dev,
+ "%s: rq[%d] error 0x%x\n",
+ adapter->netdev->name, i,
+ adapter->rqd_start[i].status.error);
schedule_work(&adapter->work);
}
@@ -410,7 +422,7 @@ vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq,
}
-void
+static void
vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
@@ -437,6 +449,17 @@ vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
}
+/* Destroy all tx queues */
+void
+vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_destroy(&adapter->tx_queue[i], adapter);
+}
+
+
static void
vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
@@ -518,6 +541,14 @@ err:
return -ENOMEM;
}
+static void
+vmxnet3_tq_cleanup_all(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_cleanup(&adapter->tx_queue[i], adapter);
+}
/*
* starting from ring->next2fill, allocate rx buffers for the given ring
@@ -732,6 +763,17 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
}
+/* Init all tx queues */
+static void
+vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_init(&adapter->tx_queue[i], adapter);
+}
+
+
/*
* parse and copy relevant protocol headers:
* For a tso pkt, relevant headers are L2/3/4 including options
@@ -756,7 +798,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
{
struct Vmxnet3_TxDataDesc *tdd;
- if (ctx->mss) {
+ if (ctx->mss) { /* TSO */
ctx->eth_ip_hdr_size = skb_transport_offset(skb);
ctx->l4_hdr_size = ((struct tcphdr *)
skb_transport_header(skb))->doff * 4;
@@ -765,7 +807,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
unsigned int pull_size;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- ctx->eth_ip_hdr_size = skb_transport_offset(skb);
+ ctx->eth_ip_hdr_size = skb_checksum_start_offset(skb);
if (ctx->ipv4) {
struct iphdr *iph = (struct iphdr *)
@@ -873,7 +915,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) +
skb_shinfo(skb)->nr_frags + 1;
- ctx.ipv4 = (skb->protocol == __constant_ntohs(ETH_P_IP));
+ ctx.ipv4 = (skb->protocol == cpu_to_be16(ETH_P_IP));
ctx.mss = skb_shinfo(skb)->gso_size;
if (ctx.mss) {
@@ -903,6 +945,21 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
}
+ spin_lock_irqsave(&tq->tx_lock, flags);
+
+ if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
+ tq->stats.tx_ring_full++;
+ dev_dbg(&adapter->netdev->dev,
+ "tx queue stopped on %s, next2comp %u"
+ " next2fill %u\n", adapter->netdev->name,
+ tq->tx_ring.next2comp, tq->tx_ring.next2fill);
+
+ vmxnet3_tq_stop(tq, adapter);
+ spin_unlock_irqrestore(&tq->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+
ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter);
if (ret >= 0) {
BUG_ON(ret <= 0 && ctx.copy_size != 0);
@@ -923,21 +980,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
} else {
tq->stats.drop_hdr_inspect_err++;
- goto drop_pkt;
- }
-
- spin_lock_irqsave(&tq->tx_lock, flags);
-
- if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
- tq->stats.tx_ring_full++;
- dev_dbg(&adapter->netdev->dev,
- "tx queue stopped on %s, next2comp %u"
- " next2fill %u\n", adapter->netdev->name,
- tq->tx_ring.next2comp, tq->tx_ring.next2fill);
-
- vmxnet3_tq_stop(tq, adapter);
- spin_unlock_irqrestore(&tq->tx_lock, flags);
- return NETDEV_TX_BUSY;
+ goto unlock_drop_pkt;
}
/* fill tx descs related to addr & len */
@@ -1000,7 +1043,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
if (le32_to_cpu(tq->shared->txNumDeferred) >=
le32_to_cpu(tq->shared->txThreshold)) {
tq->shared->txNumDeferred = 0;
- VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_TXPROD,
+ VMXNET3_WRITE_BAR0_REG(adapter,
+ VMXNET3_REG_TXPROD + tq->qid * 8,
tq->tx_ring.next2fill);
}
@@ -1008,6 +1052,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
hdr_too_big:
tq->stats.drop_oversized_hdr++;
+unlock_drop_pkt:
+ spin_unlock_irqrestore(&tq->tx_lock, flags);
drop_pkt:
tq->stats.drop_total++;
dev_kfree_skb(skb);
@@ -1020,7 +1066,10 @@ vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- return vmxnet3_tq_xmit(skb, &adapter->tx_queue, adapter, netdev);
+ BUG_ON(skb->queue_mapping > adapter->num_tx_queues);
+ return vmxnet3_tq_xmit(skb,
+ &adapter->tx_queue[skb->queue_mapping],
+ adapter, netdev);
}
@@ -1082,7 +1131,9 @@ static int
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter, int quota)
{
- static u32 rxprod_reg[2] = {VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2};
+ static const u32 rxprod_reg[2] = {
+ VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2
+ };
u32 num_rxd = 0;
struct Vmxnet3_RxCompDesc *rcd;
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
@@ -1106,9 +1157,9 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
break;
}
num_rxd++;
-
+ BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
idx = rcd->rxdIdx;
- ring_idx = rcd->rqID == rq->qid ? 0 : 1;
+ ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
vmxnet3_getRxDesc(rxd, &rq->rx_ring[ring_idx].base[idx].rxd,
&rxCmdDesc);
rbi = rq->buf_info[ring_idx] + idx;
@@ -1260,6 +1311,16 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
}
+static void
+vmxnet3_rq_cleanup_all(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ vmxnet3_rq_cleanup(&adapter->rx_queue[i], adapter);
+}
+
+
void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
@@ -1351,6 +1412,25 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
static int
+vmxnet3_rq_init_all(struct vmxnet3_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = vmxnet3_rq_init(&adapter->rx_queue[i], adapter);
+ if (unlikely(err)) {
+ dev_err(&adapter->netdev->dev, "%s: failed to "
+ "initialize rx queue%i\n",
+ adapter->netdev->name, i);
+ break;
+ }
+ }
+ return err;
+
+}
+
+
+static int
vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
{
int i;
@@ -1398,33 +1478,177 @@ err:
static int
+vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = vmxnet3_rq_create(&adapter->rx_queue[i], adapter);
+ if (unlikely(err)) {
+ dev_err(&adapter->netdev->dev,
+ "%s: failed to create rx queue%i\n",
+ adapter->netdev->name, i);
+ goto err_out;
+ }
+ }
+ return err;
+err_out:
+ vmxnet3_rq_destroy_all(adapter);
+ return err;
+
+}
+
+/* Multiple queue aware polling function for tx and rx */
+
+static int
vmxnet3_do_poll(struct vmxnet3_adapter *adapter, int budget)
{
+ int rcd_done = 0, i;
if (unlikely(adapter->shared->ecr))
vmxnet3_process_events(adapter);
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ vmxnet3_tq_tx_complete(&adapter->tx_queue[i], adapter);
- vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
- return vmxnet3_rq_rx_complete(&adapter->rx_queue, adapter, budget);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ rcd_done += vmxnet3_rq_rx_complete(&adapter->rx_queue[i],
+ adapter, budget);
+ return rcd_done;
}
static int
vmxnet3_poll(struct napi_struct *napi, int budget)
{
- struct vmxnet3_adapter *adapter = container_of(napi,
- struct vmxnet3_adapter, napi);
+ struct vmxnet3_rx_queue *rx_queue = container_of(napi,
+ struct vmxnet3_rx_queue, napi);
+ int rxd_done;
+
+ rxd_done = vmxnet3_do_poll(rx_queue->adapter, budget);
+
+ if (rxd_done < budget) {
+ napi_complete(napi);
+ vmxnet3_enable_all_intrs(rx_queue->adapter);
+ }
+ return rxd_done;
+}
+
+/*
+ * NAPI polling function for MSI-X mode with multiple Rx queues
+ * Returns the # of the NAPI credit consumed (# of rx descriptors processed)
+ */
+
+static int
+vmxnet3_poll_rx_only(struct napi_struct *napi, int budget)
+{
+ struct vmxnet3_rx_queue *rq = container_of(napi,
+ struct vmxnet3_rx_queue, napi);
+ struct vmxnet3_adapter *adapter = rq->adapter;
int rxd_done;
- rxd_done = vmxnet3_do_poll(adapter, budget);
+ /* When sharing interrupt with corresponding tx queue, process
+ * tx completions in that queue as well
+ */
+ if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE) {
+ struct vmxnet3_tx_queue *tq =
+ &adapter->tx_queue[rq - adapter->rx_queue];
+ vmxnet3_tq_tx_complete(tq, adapter);
+ }
+
+ rxd_done = vmxnet3_rq_rx_complete(rq, adapter, budget);
if (rxd_done < budget) {
napi_complete(napi);
- vmxnet3_enable_intr(adapter, 0);
+ vmxnet3_enable_intr(adapter, rq->comp_ring.intr_idx);
}
return rxd_done;
}
+#ifdef CONFIG_PCI_MSI
+
+/*
+ * Handle completion interrupts on tx queues
+ * Returns whether or not the intr is handled
+ */
+
+static irqreturn_t
+vmxnet3_msix_tx(int irq, void *data)
+{
+ struct vmxnet3_tx_queue *tq = data;
+ struct vmxnet3_adapter *adapter = tq->adapter;
+
+ if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
+ vmxnet3_disable_intr(adapter, tq->comp_ring.intr_idx);
+
+ /* Handle the case where only one irq is allocate for all tx queues */
+ if (adapter->share_intr == VMXNET3_INTR_TXSHARE) {
+ int i;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct vmxnet3_tx_queue *txq = &adapter->tx_queue[i];
+ vmxnet3_tq_tx_complete(txq, adapter);
+ }
+ } else {
+ vmxnet3_tq_tx_complete(tq, adapter);
+ }
+ vmxnet3_enable_intr(adapter, tq->comp_ring.intr_idx);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Handle completion interrupts on rx queues. Returns whether or not the
+ * intr is handled
+ */
+
+static irqreturn_t
+vmxnet3_msix_rx(int irq, void *data)
+{
+ struct vmxnet3_rx_queue *rq = data;
+ struct vmxnet3_adapter *adapter = rq->adapter;
+
+ /* disable intr if needed */
+ if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
+ vmxnet3_disable_intr(adapter, rq->comp_ring.intr_idx);
+ napi_schedule(&rq->napi);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * vmxnet3_msix_event --
+ *
+ * vmxnet3 msix event intr handler
+ *
+ * Result:
+ * whether or not the intr is handled
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static irqreturn_t
+vmxnet3_msix_event(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct vmxnet3_adapter *adapter = netdev_priv(dev);
+
+ /* disable intr if needed */
+ if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
+ vmxnet3_disable_intr(adapter, adapter->intr.event_intr_idx);
+
+ if (adapter->shared->ecr)
+ vmxnet3_process_events(adapter);
+
+ vmxnet3_enable_intr(adapter, adapter->intr.event_intr_idx);
+
+ return IRQ_HANDLED;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+
/* Interrupt handler for vmxnet3 */
static irqreturn_t
vmxnet3_intr(int irq, void *dev_id)
@@ -1432,7 +1656,7 @@ vmxnet3_intr(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct vmxnet3_adapter *adapter = netdev_priv(dev);
- if (unlikely(adapter->intr.type == VMXNET3_IT_INTX)) {
+ if (adapter->intr.type == VMXNET3_IT_INTX) {
u32 icr = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
if (unlikely(icr == 0))
/* not ours */
@@ -1442,77 +1666,144 @@ vmxnet3_intr(int irq, void *dev_id)
/* disable intr if needed */
if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
- vmxnet3_disable_intr(adapter, 0);
+ vmxnet3_disable_all_intrs(adapter);
- napi_schedule(&adapter->napi);
+ napi_schedule(&adapter->rx_queue[0].napi);
return IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-
/* netpoll callback. */
static void
vmxnet3_netpoll(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- int irq;
-#ifdef CONFIG_PCI_MSI
- if (adapter->intr.type == VMXNET3_IT_MSIX)
- irq = adapter->intr.msix_entries[0].vector;
- else
-#endif
- irq = adapter->pdev->irq;
+ if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
+ vmxnet3_disable_all_intrs(adapter);
+
+ vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
+ vmxnet3_enable_all_intrs(adapter);
- disable_irq(irq);
- vmxnet3_intr(irq, netdev);
- enable_irq(irq);
}
-#endif
+#endif /* CONFIG_NET_POLL_CONTROLLER */
static int
vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
{
- int err;
+ struct vmxnet3_intr *intr = &adapter->intr;
+ int err = 0, i;
+ int vector = 0;
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
- /* we only use 1 MSI-X vector */
- err = request_irq(adapter->intr.msix_entries[0].vector,
- vmxnet3_intr, 0, adapter->netdev->name,
- adapter->netdev);
- } else if (adapter->intr.type == VMXNET3_IT_MSI) {
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE) {
+ sprintf(adapter->tx_queue[i].name, "%s-tx-%d",
+ adapter->netdev->name, vector);
+ err = request_irq(
+ intr->msix_entries[vector].vector,
+ vmxnet3_msix_tx, 0,
+ adapter->tx_queue[i].name,
+ &adapter->tx_queue[i]);
+ } else {
+ sprintf(adapter->tx_queue[i].name, "%s-rxtx-%d",
+ adapter->netdev->name, vector);
+ }
+ if (err) {
+ dev_err(&adapter->netdev->dev,
+ "Failed to request irq for MSIX, %s, "
+ "error %d\n",
+ adapter->tx_queue[i].name, err);
+ return err;
+ }
+
+ /* Handle the case where only 1 MSIx was allocated for
+ * all tx queues */
+ if (adapter->share_intr == VMXNET3_INTR_TXSHARE) {
+ for (; i < adapter->num_tx_queues; i++)
+ adapter->tx_queue[i].comp_ring.intr_idx
+ = vector;
+ vector++;
+ break;
+ } else {
+ adapter->tx_queue[i].comp_ring.intr_idx
+ = vector++;
+ }
+ }
+ if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE)
+ vector = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE)
+ sprintf(adapter->rx_queue[i].name, "%s-rx-%d",
+ adapter->netdev->name, vector);
+ else
+ sprintf(adapter->rx_queue[i].name, "%s-rxtx-%d",
+ adapter->netdev->name, vector);
+ err = request_irq(intr->msix_entries[vector].vector,
+ vmxnet3_msix_rx, 0,
+ adapter->rx_queue[i].name,
+ &(adapter->rx_queue[i]));
+ if (err) {
+ printk(KERN_ERR "Failed to request irq for MSIX"
+ ", %s, error %d\n",
+ adapter->rx_queue[i].name, err);
+ return err;
+ }
+
+ adapter->rx_queue[i].comp_ring.intr_idx = vector++;
+ }
+
+ sprintf(intr->event_msi_vector_name, "%s-event-%d",
+ adapter->netdev->name, vector);
+ err = request_irq(intr->msix_entries[vector].vector,
+ vmxnet3_msix_event, 0,
+ intr->event_msi_vector_name, adapter->netdev);
+ intr->event_intr_idx = vector;
+
+ } else if (intr->type == VMXNET3_IT_MSI) {
+ adapter->num_rx_queues = 1;
err = request_irq(adapter->pdev->irq, vmxnet3_intr, 0,
adapter->netdev->name, adapter->netdev);
- } else
+ } else {
#endif
- {
+ adapter->num_rx_queues = 1;
err = request_irq(adapter->pdev->irq, vmxnet3_intr,
IRQF_SHARED, adapter->netdev->name,
adapter->netdev);
+#ifdef CONFIG_PCI_MSI
}
-
- if (err)
+#endif
+ intr->num_intrs = vector + 1;
+ if (err) {
printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
- ":%d\n", adapter->netdev->name, adapter->intr.type, err);
+ ":%d\n", adapter->netdev->name, intr->type, err);
+ } else {
+ /* Number of rx queues will not change after this */
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+ rq->qid = i;
+ rq->qid2 = i + adapter->num_rx_queues;
+ }
- if (!err) {
- int i;
- /* init our intr settings */
- for (i = 0; i < adapter->intr.num_intrs; i++)
- adapter->intr.mod_levels[i] = UPT1_IML_ADAPTIVE;
- /* next setup intr index for all intr sources */
- adapter->tx_queue.comp_ring.intr_idx = 0;
- adapter->rx_queue.comp_ring.intr_idx = 0;
- adapter->intr.event_intr_idx = 0;
+ /* init our intr settings */
+ for (i = 0; i < intr->num_intrs; i++)
+ intr->mod_levels[i] = UPT1_IML_ADAPTIVE;
+ if (adapter->intr.type != VMXNET3_IT_MSIX) {
+ adapter->intr.event_intr_idx = 0;
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ adapter->tx_queue[i].comp_ring.intr_idx = 0;
+ adapter->rx_queue[0].comp_ring.intr_idx = 0;
+ }
printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
- "allocated\n", adapter->netdev->name, adapter->intr.type,
- adapter->intr.mask_mode, adapter->intr.num_intrs);
+ "allocated\n", adapter->netdev->name, intr->type,
+ intr->mask_mode, intr->num_intrs);
}
return err;
@@ -1522,18 +1813,32 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
static void
vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
{
- BUG_ON(adapter->intr.type == VMXNET3_IT_AUTO ||
- adapter->intr.num_intrs <= 0);
+ struct vmxnet3_intr *intr = &adapter->intr;
+ BUG_ON(intr->type == VMXNET3_IT_AUTO || intr->num_intrs <= 0);
- switch (adapter->intr.type) {
+ switch (intr->type) {
#ifdef CONFIG_PCI_MSI
case VMXNET3_IT_MSIX:
{
- int i;
+ int i, vector = 0;
+
+ if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE) {
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ free_irq(intr->msix_entries[vector++].vector,
+ &(adapter->tx_queue[i]));
+ if (adapter->share_intr == VMXNET3_INTR_TXSHARE)
+ break;
+ }
+ }
- for (i = 0; i < adapter->intr.num_intrs; i++)
- free_irq(adapter->intr.msix_entries[i].vector,
- adapter->netdev);
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ free_irq(intr->msix_entries[vector++].vector,
+ &(adapter->rx_queue[i]));
+ }
+
+ free_irq(intr->msix_entries[vector].vector,
+ adapter->netdev);
+ BUG_ON(vector >= intr->num_intrs);
break;
}
#endif
@@ -1727,6 +2032,15 @@ vmxnet3_set_mc(struct net_device *netdev)
kfree(new_table);
}
+void
+vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ vmxnet3_rq_destroy(&adapter->rx_queue[i], adapter);
+}
+
/*
* Set up driver_shared based on settings in adapter.
@@ -1774,40 +2088,72 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
devRead->misc.queueDescPA = cpu_to_le64(adapter->queue_desc_pa);
devRead->misc.queueDescLen = cpu_to_le32(
- sizeof(struct Vmxnet3_TxQueueDesc) +
- sizeof(struct Vmxnet3_RxQueueDesc));
+ adapter->num_tx_queues * sizeof(struct Vmxnet3_TxQueueDesc) +
+ adapter->num_rx_queues * sizeof(struct Vmxnet3_RxQueueDesc));
/* tx queue settings */
- BUG_ON(adapter->tx_queue.tx_ring.base == NULL);
-
- devRead->misc.numTxQueues = 1;
- tqc = &adapter->tqd_start->conf;
- tqc->txRingBasePA = cpu_to_le64(adapter->tx_queue.tx_ring.basePA);
- tqc->dataRingBasePA = cpu_to_le64(adapter->tx_queue.data_ring.basePA);
- tqc->compRingBasePA = cpu_to_le64(adapter->tx_queue.comp_ring.basePA);
- tqc->ddPA = cpu_to_le64(virt_to_phys(
- adapter->tx_queue.buf_info));
- tqc->txRingSize = cpu_to_le32(adapter->tx_queue.tx_ring.size);
- tqc->dataRingSize = cpu_to_le32(adapter->tx_queue.data_ring.size);
- tqc->compRingSize = cpu_to_le32(adapter->tx_queue.comp_ring.size);
- tqc->ddLen = cpu_to_le32(sizeof(struct vmxnet3_tx_buf_info) *
- tqc->txRingSize);
- tqc->intrIdx = adapter->tx_queue.comp_ring.intr_idx;
+ devRead->misc.numTxQueues = adapter->num_tx_queues;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
+ BUG_ON(adapter->tx_queue[i].tx_ring.base == NULL);
+ tqc = &adapter->tqd_start[i].conf;
+ tqc->txRingBasePA = cpu_to_le64(tq->tx_ring.basePA);
+ tqc->dataRingBasePA = cpu_to_le64(tq->data_ring.basePA);
+ tqc->compRingBasePA = cpu_to_le64(tq->comp_ring.basePA);
+ tqc->ddPA = cpu_to_le64(virt_to_phys(tq->buf_info));
+ tqc->txRingSize = cpu_to_le32(tq->tx_ring.size);
+ tqc->dataRingSize = cpu_to_le32(tq->data_ring.size);
+ tqc->compRingSize = cpu_to_le32(tq->comp_ring.size);
+ tqc->ddLen = cpu_to_le32(
+ sizeof(struct vmxnet3_tx_buf_info) *
+ tqc->txRingSize);
+ tqc->intrIdx = tq->comp_ring.intr_idx;
+ }
/* rx queue settings */
- devRead->misc.numRxQueues = 1;
- rqc = &adapter->rqd_start->conf;
- rqc->rxRingBasePA[0] = cpu_to_le64(adapter->rx_queue.rx_ring[0].basePA);
- rqc->rxRingBasePA[1] = cpu_to_le64(adapter->rx_queue.rx_ring[1].basePA);
- rqc->compRingBasePA = cpu_to_le64(adapter->rx_queue.comp_ring.basePA);
- rqc->ddPA = cpu_to_le64(virt_to_phys(
- adapter->rx_queue.buf_info));
- rqc->rxRingSize[0] = cpu_to_le32(adapter->rx_queue.rx_ring[0].size);
- rqc->rxRingSize[1] = cpu_to_le32(adapter->rx_queue.rx_ring[1].size);
- rqc->compRingSize = cpu_to_le32(adapter->rx_queue.comp_ring.size);
- rqc->ddLen = cpu_to_le32(sizeof(struct vmxnet3_rx_buf_info) *
- (rqc->rxRingSize[0] + rqc->rxRingSize[1]));
- rqc->intrIdx = adapter->rx_queue.comp_ring.intr_idx;
+ devRead->misc.numRxQueues = adapter->num_rx_queues;
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+ rqc = &adapter->rqd_start[i].conf;
+ rqc->rxRingBasePA[0] = cpu_to_le64(rq->rx_ring[0].basePA);
+ rqc->rxRingBasePA[1] = cpu_to_le64(rq->rx_ring[1].basePA);
+ rqc->compRingBasePA = cpu_to_le64(rq->comp_ring.basePA);
+ rqc->ddPA = cpu_to_le64(virt_to_phys(
+ rq->buf_info));
+ rqc->rxRingSize[0] = cpu_to_le32(rq->rx_ring[0].size);
+ rqc->rxRingSize[1] = cpu_to_le32(rq->rx_ring[1].size);
+ rqc->compRingSize = cpu_to_le32(rq->comp_ring.size);
+ rqc->ddLen = cpu_to_le32(
+ sizeof(struct vmxnet3_rx_buf_info) *
+ (rqc->rxRingSize[0] +
+ rqc->rxRingSize[1]));
+ rqc->intrIdx = rq->comp_ring.intr_idx;
+ }
+
+#ifdef VMXNET3_RSS
+ memset(adapter->rss_conf, 0, sizeof(*adapter->rss_conf));
+
+ if (adapter->rss) {
+ struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+ devRead->misc.uptFeatures |= UPT1_F_RSS;
+ devRead->misc.numRxQueues = adapter->num_rx_queues;
+ rssConf->hashType = UPT1_RSS_HASH_TYPE_TCP_IPV4 |
+ UPT1_RSS_HASH_TYPE_IPV4 |
+ UPT1_RSS_HASH_TYPE_TCP_IPV6 |
+ UPT1_RSS_HASH_TYPE_IPV6;
+ rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
+ rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
+ rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
+ get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
+ for (i = 0; i < rssConf->indTableSize; i++)
+ rssConf->indTable[i] = i % adapter->num_rx_queues;
+
+ devRead->rssConfDesc.confVer = 1;
+ devRead->rssConfDesc.confLen = sizeof(*rssConf);
+ devRead->rssConfDesc.confPA = virt_to_phys(rssConf);
+ }
+
+#endif /* VMXNET3_RSS */
/* intr settings */
devRead->intrConf.autoMask = adapter->intr.mask_mode ==
@@ -1829,18 +2175,18 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
int
vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
{
- int err;
+ int err, i;
u32 ret;
- dev_dbg(&adapter->netdev->dev,
- "%s: skb_buf_size %d, rx_buf_per_pkt %d, ring sizes"
- " %u %u %u\n", adapter->netdev->name, adapter->skb_buf_size,
- adapter->rx_buf_per_pkt, adapter->tx_queue.tx_ring.size,
- adapter->rx_queue.rx_ring[0].size,
- adapter->rx_queue.rx_ring[1].size);
-
- vmxnet3_tq_init(&adapter->tx_queue, adapter);
- err = vmxnet3_rq_init(&adapter->rx_queue, adapter);
+ dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
+ " ring sizes %u %u %u\n", adapter->netdev->name,
+ adapter->skb_buf_size, adapter->rx_buf_per_pkt,
+ adapter->tx_queue[0].tx_ring.size,
+ adapter->rx_queue[0].rx_ring[0].size,
+ adapter->rx_queue[0].rx_ring[1].size);
+
+ vmxnet3_tq_init_all(adapter);
+ err = vmxnet3_rq_init_all(adapter);
if (err) {
printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
adapter->netdev->name, err);
@@ -1870,10 +2216,15 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
err = -EINVAL;
goto activate_err;
}
- VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD,
- adapter->rx_queue.rx_ring[0].next2fill);
- VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD2,
- adapter->rx_queue.rx_ring[1].next2fill);
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ VMXNET3_WRITE_BAR0_REG(adapter,
+ VMXNET3_REG_RXPROD + i * VMXNET3_REG_ALIGN,
+ adapter->rx_queue[i].rx_ring[0].next2fill);
+ VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_RXPROD2 +
+ (i * VMXNET3_REG_ALIGN)),
+ adapter->rx_queue[i].rx_ring[1].next2fill);
+ }
/* Apply the rx filter settins last. */
vmxnet3_set_mc(adapter->netdev);
@@ -1883,8 +2234,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
* tx queue if the link is up.
*/
vmxnet3_check_link(adapter, true);
-
- napi_enable(&adapter->napi);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ napi_enable(&adapter->rx_queue[i].napi);
vmxnet3_enable_all_intrs(adapter);
clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
return 0;
@@ -1896,7 +2247,7 @@ activate_err:
irq_err:
rq_err:
/* free up buffers we allocated */
- vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
+ vmxnet3_rq_cleanup_all(adapter);
return err;
}
@@ -1911,6 +2262,7 @@ vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
int
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
{
+ int i;
if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state))
return 0;
@@ -1919,13 +2271,14 @@ vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
VMXNET3_CMD_QUIESCE_DEV);
vmxnet3_disable_all_intrs(adapter);
- napi_disable(&adapter->napi);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ napi_disable(&adapter->rx_queue[i].napi);
netif_tx_disable(adapter->netdev);
adapter->link_speed = 0;
netif_carrier_off(adapter->netdev);
- vmxnet3_tq_cleanup(&adapter->tx_queue, adapter);
- vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
+ vmxnet3_tq_cleanup_all(adapter);
+ vmxnet3_rq_cleanup_all(adapter);
vmxnet3_free_irqs(adapter);
return 0;
}
@@ -2047,7 +2400,9 @@ vmxnet3_free_pci_resources(struct vmxnet3_adapter *adapter)
static void
vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
{
- size_t sz;
+ size_t sz, i, ring0_size, ring1_size, comp_size;
+ struct vmxnet3_rx_queue *rq = &adapter->rx_queue[0];
+
if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE -
VMXNET3_MAX_ETH_HDR_SIZE) {
@@ -2069,11 +2424,19 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
* rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN
*/
sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
- adapter->rx_queue.rx_ring[0].size = (adapter->rx_queue.rx_ring[0].size +
- sz - 1) / sz * sz;
- adapter->rx_queue.rx_ring[0].size = min_t(u32,
- adapter->rx_queue.rx_ring[0].size,
- VMXNET3_RX_RING_MAX_SIZE / sz * sz);
+ ring0_size = adapter->rx_queue[0].rx_ring[0].size;
+ ring0_size = (ring0_size + sz - 1) / sz * sz;
+ ring0_size = min_t(u32, rq->rx_ring[0].size, VMXNET3_RX_RING_MAX_SIZE /
+ sz * sz);
+ ring1_size = adapter->rx_queue[0].rx_ring[1].size;
+ comp_size = ring0_size + ring1_size;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rq = &adapter->rx_queue[i];
+ rq->rx_ring[0].size = ring0_size;
+ rq->rx_ring[1].size = ring1_size;
+ rq->comp_ring.size = comp_size;
+ }
}
@@ -2081,29 +2444,53 @@ int
vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
u32 rx_ring_size, u32 rx_ring2_size)
{
- int err;
-
- adapter->tx_queue.tx_ring.size = tx_ring_size;
- adapter->tx_queue.data_ring.size = tx_ring_size;
- adapter->tx_queue.comp_ring.size = tx_ring_size;
- adapter->tx_queue.shared = &adapter->tqd_start->ctrl;
- adapter->tx_queue.stopped = true;
- err = vmxnet3_tq_create(&adapter->tx_queue, adapter);
- if (err)
- return err;
+ int err = 0, i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
+ tq->tx_ring.size = tx_ring_size;
+ tq->data_ring.size = tx_ring_size;
+ tq->comp_ring.size = tx_ring_size;
+ tq->shared = &adapter->tqd_start[i].ctrl;
+ tq->stopped = true;
+ tq->adapter = adapter;
+ tq->qid = i;
+ err = vmxnet3_tq_create(tq, adapter);
+ /*
+ * Too late to change num_tx_queues. We cannot do away with
+ * lesser number of queues than what we asked for
+ */
+ if (err)
+ goto queue_err;
+ }
- adapter->rx_queue.rx_ring[0].size = rx_ring_size;
- adapter->rx_queue.rx_ring[1].size = rx_ring2_size;
+ adapter->rx_queue[0].rx_ring[0].size = rx_ring_size;
+ adapter->rx_queue[0].rx_ring[1].size = rx_ring2_size;
vmxnet3_adjust_rx_ring_size(adapter);
- adapter->rx_queue.comp_ring.size = adapter->rx_queue.rx_ring[0].size +
- adapter->rx_queue.rx_ring[1].size;
- adapter->rx_queue.qid = 0;
- adapter->rx_queue.qid2 = 1;
- adapter->rx_queue.shared = &adapter->rqd_start->ctrl;
- err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
- if (err)
- vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
-
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+ /* qid and qid2 for rx queues will be assigned later when num
+ * of rx queues is finalized after allocating intrs */
+ rq->shared = &adapter->rqd_start[i].ctrl;
+ rq->adapter = adapter;
+ err = vmxnet3_rq_create(rq, adapter);
+ if (err) {
+ if (i == 0) {
+ printk(KERN_ERR "Could not allocate any rx"
+ "queues. Aborting.\n");
+ goto queue_err;
+ } else {
+ printk(KERN_INFO "Number of rx queues changed "
+ "to : %d.\n", i);
+ adapter->num_rx_queues = i;
+ err = 0;
+ break;
+ }
+ }
+ }
+ return err;
+queue_err:
+ vmxnet3_tq_destroy_all(adapter);
return err;
}
@@ -2111,11 +2498,12 @@ static int
vmxnet3_open(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter;
- int err;
+ int err, i;
adapter = netdev_priv(netdev);
- spin_lock_init(&adapter->tx_queue.tx_lock);
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ spin_lock_init(&adapter->tx_queue[i].tx_lock);
err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE,
VMXNET3_DEF_RX_RING_SIZE,
@@ -2130,8 +2518,8 @@ vmxnet3_open(struct net_device *netdev)
return 0;
activate_err:
- vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
- vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+ vmxnet3_rq_destroy_all(adapter);
+ vmxnet3_tq_destroy_all(adapter);
queue_err:
return err;
}
@@ -2151,8 +2539,8 @@ vmxnet3_close(struct net_device *netdev)
vmxnet3_quiesce_dev(adapter);
- vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
- vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+ vmxnet3_rq_destroy_all(adapter);
+ vmxnet3_tq_destroy_all(adapter);
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
@@ -2164,6 +2552,8 @@ vmxnet3_close(struct net_device *netdev)
void
vmxnet3_force_close(struct vmxnet3_adapter *adapter)
{
+ int i;
+
/*
* we must clear VMXNET3_STATE_BIT_RESETTING, otherwise
* vmxnet3_close() will deadlock.
@@ -2171,7 +2561,8 @@ vmxnet3_force_close(struct vmxnet3_adapter *adapter)
BUG_ON(test_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state));
/* we need to enable NAPI, otherwise dev_close will deadlock */
- napi_enable(&adapter->napi);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ napi_enable(&adapter->rx_queue[i].napi);
dev_close(adapter->netdev);
}
@@ -2202,14 +2593,11 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
vmxnet3_reset_dev(adapter);
/* we need to re-create the rx queue based on the new mtu */
- vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+ vmxnet3_rq_destroy_all(adapter);
vmxnet3_adjust_rx_ring_size(adapter);
- adapter->rx_queue.comp_ring.size =
- adapter->rx_queue.rx_ring[0].size +
- adapter->rx_queue.rx_ring[1].size;
- err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
+ err = vmxnet3_rq_create_all(adapter);
if (err) {
- printk(KERN_ERR "%s: failed to re-create rx queue,"
+ printk(KERN_ERR "%s: failed to re-create rx queues,"
" error %d. Closing it.\n", netdev->name, err);
goto out;
}
@@ -2274,6 +2662,55 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
mac[5] = (tmp >> 8) & 0xff;
}
+#ifdef CONFIG_PCI_MSI
+
+/*
+ * Enable MSIx vectors.
+ * Returns :
+ * 0 on successful enabling of required vectors,
+ * VMXNET3_LINUX_MIN_MSIX_VECT when only minumum number of vectors required
+ * could be enabled.
+ * number of vectors which can be enabled otherwise (this number is smaller
+ * than VMXNET3_LINUX_MIN_MSIX_VECT)
+ */
+
+static int
+vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
+ int vectors)
+{
+ int err = 0, vector_threshold;
+ vector_threshold = VMXNET3_LINUX_MIN_MSIX_VECT;
+
+ while (vectors >= vector_threshold) {
+ err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
+ vectors);
+ if (!err) {
+ adapter->intr.num_intrs = vectors;
+ return 0;
+ } else if (err < 0) {
+ printk(KERN_ERR "Failed to enable MSI-X for %s, error"
+ " %d\n", adapter->netdev->name, err);
+ vectors = 0;
+ } else if (err < vector_threshold) {
+ break;
+ } else {
+ /* If fails to enable required number of MSI-x vectors
+ * try enabling 3 of them. One each for rx, tx and event
+ */
+ vectors = vector_threshold;
+ printk(KERN_ERR "Failed to enable %d MSI-X for %s, try"
+ " %d instead\n", vectors, adapter->netdev->name,
+ vector_threshold);
+ }
+ }
+
+ printk(KERN_INFO "Number of MSI-X interrupts which can be allocatedi"
+ " are lower than min threshold required.\n");
+ return err;
+}
+
+
+#endif /* CONFIG_PCI_MSI */
static void
vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
@@ -2293,16 +2730,47 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
- int err;
-
- adapter->intr.msix_entries[0].entry = 0;
- err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
- VMXNET3_LINUX_MAX_MSIX_VECT);
- if (!err) {
- adapter->intr.num_intrs = 1;
- adapter->intr.type = VMXNET3_IT_MSIX;
+ int vector, err = 0;
+
+ adapter->intr.num_intrs = (adapter->share_intr ==
+ VMXNET3_INTR_TXSHARE) ? 1 :
+ adapter->num_tx_queues;
+ adapter->intr.num_intrs += (adapter->share_intr ==
+ VMXNET3_INTR_BUDDYSHARE) ? 0 :
+ adapter->num_rx_queues;
+ adapter->intr.num_intrs += 1; /* for link event */
+
+ adapter->intr.num_intrs = (adapter->intr.num_intrs >
+ VMXNET3_LINUX_MIN_MSIX_VECT
+ ? adapter->intr.num_intrs :
+ VMXNET3_LINUX_MIN_MSIX_VECT);
+
+ for (vector = 0; vector < adapter->intr.num_intrs; vector++)
+ adapter->intr.msix_entries[vector].entry = vector;
+
+ err = vmxnet3_acquire_msix_vectors(adapter,
+ adapter->intr.num_intrs);
+ /* If we cannot allocate one MSIx vector per queue
+ * then limit the number of rx queues to 1
+ */
+ if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
+ if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
+ || adapter->num_rx_queues != 2) {
+ adapter->share_intr = VMXNET3_INTR_TXSHARE;
+ printk(KERN_ERR "Number of rx queues : 1\n");
+ adapter->num_rx_queues = 1;
+ adapter->intr.num_intrs =
+ VMXNET3_LINUX_MIN_MSIX_VECT;
+ }
return;
}
+ if (!err)
+ return;
+
+ /* If we cannot allocate MSIx vectors use only one rx queue */
+ printk(KERN_INFO "Failed to enable MSI-X for %s, error %d."
+ "#rx queues : 1, try MSI\n", adapter->netdev->name, err);
+
adapter->intr.type = VMXNET3_IT_MSI;
}
@@ -2310,12 +2778,15 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
int err;
err = pci_enable_msi(adapter->pdev);
if (!err) {
+ adapter->num_rx_queues = 1;
adapter->intr.num_intrs = 1;
return;
}
}
#endif /* CONFIG_PCI_MSI */
+ adapter->num_rx_queues = 1;
+ printk(KERN_INFO "Using INTx interrupt, #Rx queues: 1.\n");
adapter->intr.type = VMXNET3_IT_INTX;
/* INT-X related setting */
@@ -2343,6 +2814,7 @@ vmxnet3_tx_timeout(struct net_device *netdev)
printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
schedule_work(&adapter->work);
+ netif_wake_queue(adapter->netdev);
}
@@ -2399,8 +2871,29 @@ vmxnet3_probe_device(struct pci_dev *pdev,
struct net_device *netdev;
struct vmxnet3_adapter *adapter;
u8 mac[ETH_ALEN];
+ int size;
+ int num_tx_queues;
+ int num_rx_queues;
+
+#ifdef VMXNET3_RSS
+ if (enable_mq)
+ num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
+ (int)num_online_cpus());
+ else
+#endif
+ num_rx_queues = 1;
+
+ if (enable_mq)
+ num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES,
+ (int)num_online_cpus());
+ else
+ num_tx_queues = 1;
+
+ netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
+ max(num_tx_queues, num_rx_queues));
+ printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
+ num_tx_queues, num_rx_queues);
- netdev = alloc_etherdev(sizeof(struct vmxnet3_adapter));
if (!netdev) {
printk(KERN_ERR "Failed to alloc ethernet device for adapter "
"%s\n", pci_name(pdev));
@@ -2422,9 +2915,12 @@ vmxnet3_probe_device(struct pci_dev *pdev,
goto err_alloc_shared;
}
- adapter->tqd_start = pci_alloc_consistent(adapter->pdev,
- sizeof(struct Vmxnet3_TxQueueDesc) +
- sizeof(struct Vmxnet3_RxQueueDesc),
+ adapter->num_rx_queues = num_rx_queues;
+ adapter->num_tx_queues = num_tx_queues;
+
+ size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
+ size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues;
+ adapter->tqd_start = pci_alloc_consistent(adapter->pdev, size,
&adapter->queue_desc_pa);
if (!adapter->tqd_start) {
@@ -2433,8 +2929,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
err = -ENOMEM;
goto err_alloc_queue_desc;
}
- adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start
- + 1);
+ adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start +
+ adapter->num_tx_queues);
adapter->pm_conf = kmalloc(sizeof(struct Vmxnet3_PMConf), GFP_KERNEL);
if (adapter->pm_conf == NULL) {
@@ -2444,6 +2940,17 @@ vmxnet3_probe_device(struct pci_dev *pdev,
goto err_alloc_pm;
}
+#ifdef VMXNET3_RSS
+
+ adapter->rss_conf = kmalloc(sizeof(struct UPT1_RSSConf), GFP_KERNEL);
+ if (adapter->rss_conf == NULL) {
+ printk(KERN_ERR "Failed to allocate memory for %s\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_alloc_rss;
+ }
+#endif /* VMXNET3_RSS */
+
err = vmxnet3_alloc_pci_resources(adapter, &dma64);
if (err < 0)
goto err_alloc_pci;
@@ -2471,18 +2978,48 @@ vmxnet3_probe_device(struct pci_dev *pdev,
vmxnet3_declare_features(adapter, dma64);
adapter->dev_number = atomic_read(&devices_found);
+
+ adapter->share_intr = irq_share_mode;
+ if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE &&
+ adapter->num_tx_queues != adapter->num_rx_queues)
+ adapter->share_intr = VMXNET3_INTR_DONTSHARE;
+
vmxnet3_alloc_intr_resources(adapter);
+#ifdef VMXNET3_RSS
+ if (adapter->num_rx_queues > 1 &&
+ adapter->intr.type == VMXNET3_IT_MSIX) {
+ adapter->rss = true;
+ printk(KERN_INFO "RSS is enabled.\n");
+ } else {
+ adapter->rss = false;
+ }
+#endif
+
vmxnet3_read_mac_addr(adapter, mac);
memcpy(netdev->dev_addr, mac, netdev->addr_len);
netdev->netdev_ops = &vmxnet3_netdev_ops;
- netdev->watchdog_timeo = 5 * HZ;
vmxnet3_set_ethtool_ops(netdev);
+ netdev->watchdog_timeo = 5 * HZ;
INIT_WORK(&adapter->work, vmxnet3_reset_work);
- netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64);
+ if (adapter->intr.type == VMXNET3_IT_MSIX) {
+ int i;
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ netif_napi_add(adapter->netdev,
+ &adapter->rx_queue[i].napi,
+ vmxnet3_poll_rx_only, 64);
+ }
+ } else {
+ netif_napi_add(adapter->netdev, &adapter->rx_queue[0].napi,
+ vmxnet3_poll, 64);
+ }
+
+ netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
+ netif_set_real_num_rx_queues(adapter->netdev, adapter->num_rx_queues);
+
SET_NETDEV_DEV(netdev, &pdev->dev);
err = register_netdev(netdev);
@@ -2502,11 +3039,14 @@ err_register:
err_ver:
vmxnet3_free_pci_resources(adapter);
err_alloc_pci:
+#ifdef VMXNET3_RSS
+ kfree(adapter->rss_conf);
+err_alloc_rss:
+#endif
kfree(adapter->pm_conf);
err_alloc_pm:
- pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
- sizeof(struct Vmxnet3_RxQueueDesc),
- adapter->tqd_start, adapter->queue_desc_pa);
+ pci_free_consistent(adapter->pdev, size, adapter->tqd_start,
+ adapter->queue_desc_pa);
err_alloc_queue_desc:
pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
adapter->shared, adapter->shared_pa);
@@ -2522,17 +3062,32 @@ vmxnet3_remove_device(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ int size = 0;
+ int num_rx_queues;
- flush_scheduled_work();
+#ifdef VMXNET3_RSS
+ if (enable_mq)
+ num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
+ (int)num_online_cpus());
+ else
+#endif
+ num_rx_queues = 1;
+
+ cancel_work_sync(&adapter->work);
unregister_netdev(netdev);
vmxnet3_free_intr_resources(adapter);
vmxnet3_free_pci_resources(adapter);
+#ifdef VMXNET3_RSS
+ kfree(adapter->rss_conf);
+#endif
kfree(adapter->pm_conf);
- pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
- sizeof(struct Vmxnet3_RxQueueDesc),
- adapter->tqd_start, adapter->queue_desc_pa);
+
+ size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
+ size += sizeof(struct Vmxnet3_RxQueueDesc) * num_rx_queues;
+ pci_free_consistent(adapter->pdev, size, adapter->tqd_start,
+ adapter->queue_desc_pa);
pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
adapter->shared, adapter->shared_pa);
free_netdev(netdev);
@@ -2563,7 +3118,7 @@ vmxnet3_suspend(struct device *device)
vmxnet3_free_intr_resources(adapter);
netif_device_detach(netdev);
- netif_stop_queue(netdev);
+ netif_tx_stop_all_queues(netdev);
/* Create wake-up filters. */
pmConf = adapter->pm_conf;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index b79070bcc92e..8e17fc8a7fe7 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -151,44 +151,42 @@ vmxnet3_get_stats(struct net_device *netdev)
struct UPT1_TxStats *devTxStats;
struct UPT1_RxStats *devRxStats;
struct net_device_stats *net_stats = &netdev->stats;
+ int i;
adapter = netdev_priv(netdev);
/* Collect the dev stats into the shared area */
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
- /* Assuming that we have a single queue device */
- devTxStats = &adapter->tqd_start->stats;
- devRxStats = &adapter->rqd_start->stats;
-
- /* Get access to the driver stats per queue */
- drvTxStats = &adapter->tx_queue.stats;
- drvRxStats = &adapter->rx_queue.stats;
-
memset(net_stats, 0, sizeof(*net_stats));
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ devTxStats = &adapter->tqd_start[i].stats;
+ drvTxStats = &adapter->tx_queue[i].stats;
+ net_stats->tx_packets += devTxStats->ucastPktsTxOK +
+ devTxStats->mcastPktsTxOK +
+ devTxStats->bcastPktsTxOK;
+ net_stats->tx_bytes += devTxStats->ucastBytesTxOK +
+ devTxStats->mcastBytesTxOK +
+ devTxStats->bcastBytesTxOK;
+ net_stats->tx_errors += devTxStats->pktsTxError;
+ net_stats->tx_dropped += drvTxStats->drop_total;
+ }
- net_stats->rx_packets = devRxStats->ucastPktsRxOK +
- devRxStats->mcastPktsRxOK +
- devRxStats->bcastPktsRxOK;
-
- net_stats->tx_packets = devTxStats->ucastPktsTxOK +
- devTxStats->mcastPktsTxOK +
- devTxStats->bcastPktsTxOK;
-
- net_stats->rx_bytes = devRxStats->ucastBytesRxOK +
- devRxStats->mcastBytesRxOK +
- devRxStats->bcastBytesRxOK;
-
- net_stats->tx_bytes = devTxStats->ucastBytesTxOK +
- devTxStats->mcastBytesTxOK +
- devTxStats->bcastBytesTxOK;
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ devRxStats = &adapter->rqd_start[i].stats;
+ drvRxStats = &adapter->rx_queue[i].stats;
+ net_stats->rx_packets += devRxStats->ucastPktsRxOK +
+ devRxStats->mcastPktsRxOK +
+ devRxStats->bcastPktsRxOK;
- net_stats->rx_errors = devRxStats->pktsRxError;
- net_stats->tx_errors = devTxStats->pktsTxError;
- net_stats->rx_dropped = drvRxStats->drop_total;
- net_stats->tx_dropped = drvTxStats->drop_total;
- net_stats->multicast = devRxStats->mcastPktsRxOK;
+ net_stats->rx_bytes += devRxStats->ucastBytesRxOK +
+ devRxStats->mcastBytesRxOK +
+ devRxStats->bcastBytesRxOK;
+ net_stats->rx_errors += devRxStats->pktsRxError;
+ net_stats->rx_dropped += drvRxStats->drop_total;
+ net_stats->multicast += devRxStats->mcastPktsRxOK;
+ }
return net_stats;
}
@@ -307,24 +305,26 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u8 *base;
int i;
+ int j = 0;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
/* this does assume each counter is 64-bit wide */
+/* TODO change this for multiple queues */
- base = (u8 *)&adapter->tqd_start->stats;
+ base = (u8 *)&adapter->tqd_start[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
- base = (u8 *)&adapter->tx_queue.stats;
+ base = (u8 *)&adapter->tx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
- base = (u8 *)&adapter->rqd_start->stats;
+ base = (u8 *)&adapter->rqd_start[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
- base = (u8 *)&adapter->rx_queue.stats;
+ base = (u8 *)&adapter->rx_queue[j].stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
*buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
@@ -339,6 +339,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u32 *buf = p;
+ int i = 0;
memset(p, 0, vmxnet3_get_regs_len(netdev));
@@ -347,28 +348,29 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
/* Update vmxnet3_get_regs_len if we want to dump more registers */
/* make each ring use multiple of 16 bytes */
- buf[0] = adapter->tx_queue.tx_ring.next2fill;
- buf[1] = adapter->tx_queue.tx_ring.next2comp;
- buf[2] = adapter->tx_queue.tx_ring.gen;
+/* TODO change this for multiple queues */
+ buf[0] = adapter->tx_queue[i].tx_ring.next2fill;
+ buf[1] = adapter->tx_queue[i].tx_ring.next2comp;
+ buf[2] = adapter->tx_queue[i].tx_ring.gen;
buf[3] = 0;
- buf[4] = adapter->tx_queue.comp_ring.next2proc;
- buf[5] = adapter->tx_queue.comp_ring.gen;
- buf[6] = adapter->tx_queue.stopped;
+ buf[4] = adapter->tx_queue[i].comp_ring.next2proc;
+ buf[5] = adapter->tx_queue[i].comp_ring.gen;
+ buf[6] = adapter->tx_queue[i].stopped;
buf[7] = 0;
- buf[8] = adapter->rx_queue.rx_ring[0].next2fill;
- buf[9] = adapter->rx_queue.rx_ring[0].next2comp;
- buf[10] = adapter->rx_queue.rx_ring[0].gen;
+ buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
+ buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp;
+ buf[10] = adapter->rx_queue[i].rx_ring[0].gen;
buf[11] = 0;
- buf[12] = adapter->rx_queue.rx_ring[1].next2fill;
- buf[13] = adapter->rx_queue.rx_ring[1].next2comp;
- buf[14] = adapter->rx_queue.rx_ring[1].gen;
+ buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill;
+ buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
+ buf[14] = adapter->rx_queue[i].rx_ring[1].gen;
buf[15] = 0;
- buf[16] = adapter->rx_queue.comp_ring.next2proc;
- buf[17] = adapter->rx_queue.comp_ring.gen;
+ buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
+ buf[17] = adapter->rx_queue[i].comp_ring.gen;
buf[18] = 0;
buf[19] = 0;
}
@@ -435,8 +437,10 @@ vmxnet3_get_ringparam(struct net_device *netdev,
param->rx_mini_max_pending = 0;
param->rx_jumbo_max_pending = 0;
- param->rx_pending = adapter->rx_queue.rx_ring[0].size;
- param->tx_pending = adapter->tx_queue.tx_ring.size;
+ param->rx_pending = adapter->rx_queue[0].rx_ring[0].size *
+ adapter->num_rx_queues;
+ param->tx_pending = adapter->tx_queue[0].tx_ring.size *
+ adapter->num_tx_queues;
param->rx_mini_pending = 0;
param->rx_jumbo_pending = 0;
}
@@ -480,8 +484,8 @@ vmxnet3_set_ringparam(struct net_device *netdev,
sz) != 0)
return -EINVAL;
- if (new_tx_ring_size == adapter->tx_queue.tx_ring.size &&
- new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) {
+ if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size &&
+ new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) {
return 0;
}
@@ -498,11 +502,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,
/* recreate the rx queue and the tx queue based on the
* new sizes */
- vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
- vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+ vmxnet3_tq_destroy_all(adapter);
+ vmxnet3_rq_destroy_all(adapter);
err = vmxnet3_create_queues(adapter, new_tx_ring_size,
new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
+
if (err) {
/* failed, most likely because of OOM, try default
* size */
@@ -535,6 +540,66 @@ out:
}
+static int
+vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
+ void *rules)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ switch (info->cmd) {
+ case ETHTOOL_GRXRINGS:
+ info->data = adapter->num_rx_queues;
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+#ifdef VMXNET3_RSS
+static int
+vmxnet3_get_rss_indir(struct net_device *netdev,
+ struct ethtool_rxfh_indir *p)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+ unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize);
+
+ p->size = rssConf->indTableSize;
+ while (n--)
+ p->ring_index[n] = rssConf->indTable[n];
+ return 0;
+
+}
+
+static int
+vmxnet3_set_rss_indir(struct net_device *netdev,
+ const struct ethtool_rxfh_indir *p)
+{
+ unsigned int i;
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+
+ if (p->size != rssConf->indTableSize)
+ return -EINVAL;
+ for (i = 0; i < rssConf->indTableSize; i++) {
+ /*
+ * Return with error code if any of the queue indices
+ * is out of range
+ */
+ if (p->ring_index[i] < 0 ||
+ p->ring_index[i] >= adapter->num_rx_queues)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rssConf->indTableSize; i++)
+ rssConf->indTable[i] = p->ring_index[i];
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_RSSIDT);
+
+ return 0;
+
+}
+#endif
+
static struct ethtool_ops vmxnet3_ethtool_ops = {
.get_settings = vmxnet3_get_settings,
.get_drvinfo = vmxnet3_get_drvinfo,
@@ -558,6 +623,11 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
.get_ethtool_stats = vmxnet3_get_ethtool_stats,
.get_ringparam = vmxnet3_get_ringparam,
.set_ringparam = vmxnet3_set_ringparam,
+ .get_rxnfc = vmxnet3_get_rxnfc,
+#ifdef VMXNET3_RSS
+ .get_rxfh_indir = vmxnet3_get_rss_indir,
+ .set_rxfh_indir = vmxnet3_set_rss_indir,
+#endif
};
void vmxnet3_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 8a2f4712284c..7fadeed37f03 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -68,11 +68,15 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.0.14.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.16.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01000E00
+#define VMXNET3_DRIVER_VERSION_NUM 0x01001000
+#if defined(CONFIG_PCI_MSI)
+ /* RSS only makes sense if MSI-X is supported. */
+ #define VMXNET3_RSS
+#endif
/*
* Capabilities
@@ -218,16 +222,19 @@ struct vmxnet3_tx_ctx {
};
struct vmxnet3_tx_queue {
+ char name[IFNAMSIZ+8]; /* To identify interrupt */
+ struct vmxnet3_adapter *adapter;
spinlock_t tx_lock;
struct vmxnet3_cmd_ring tx_ring;
- struct vmxnet3_tx_buf_info *buf_info;
+ struct vmxnet3_tx_buf_info *buf_info;
struct vmxnet3_tx_data_ring data_ring;
struct vmxnet3_comp_ring comp_ring;
- struct Vmxnet3_TxQueueCtrl *shared;
+ struct Vmxnet3_TxQueueCtrl *shared;
struct vmxnet3_tq_driver_stats stats;
bool stopped;
int num_stop; /* # of times the queue is
* stopped */
+ int qid;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
enum vmxnet3_rx_buf_type {
@@ -259,6 +266,9 @@ struct vmxnet3_rq_driver_stats {
};
struct vmxnet3_rx_queue {
+ char name[IFNAMSIZ + 8]; /* To identify interrupt */
+ struct vmxnet3_adapter *adapter;
+ struct napi_struct napi;
struct vmxnet3_cmd_ring rx_ring[2];
struct vmxnet3_comp_ring comp_ring;
struct vmxnet3_rx_ctx rx_ctx;
@@ -271,7 +281,16 @@ struct vmxnet3_rx_queue {
struct vmxnet3_rq_driver_stats stats;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
-#define VMXNET3_LINUX_MAX_MSIX_VECT 1
+#define VMXNET3_DEVICE_MAX_TX_QUEUES 8
+#define VMXNET3_DEVICE_MAX_RX_QUEUES 8 /* Keep this value as a power of 2 */
+
+/* Should be less than UPT1_RSS_MAX_IND_TABLE_SIZE */
+#define VMXNET3_RSS_IND_TABLE_SIZE (VMXNET3_DEVICE_MAX_RX_QUEUES * 4)
+
+#define VMXNET3_LINUX_MAX_MSIX_VECT (VMXNET3_DEVICE_MAX_TX_QUEUES + \
+ VMXNET3_DEVICE_MAX_RX_QUEUES + 1)
+#define VMXNET3_LINUX_MIN_MSIX_VECT 3 /* 1 for each : tx, rx and event */
+
struct vmxnet3_intr {
enum vmxnet3_intr_mask_mode mask_mode;
@@ -279,27 +298,32 @@ struct vmxnet3_intr {
u8 num_intrs; /* # of intr vectors */
u8 event_intr_idx; /* idx of the intr vector for event */
u8 mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
+ char event_msi_vector_name[IFNAMSIZ+11];
#ifdef CONFIG_PCI_MSI
struct msix_entry msix_entries[VMXNET3_LINUX_MAX_MSIX_VECT];
#endif
};
+/* Interrupt sharing schemes, share_intr */
+#define VMXNET3_INTR_BUDDYSHARE 0 /* Corresponding tx,rx queues share irq */
+#define VMXNET3_INTR_TXSHARE 1 /* All tx queues share one irq */
+#define VMXNET3_INTR_DONTSHARE 2 /* each queue has its own irq */
+
+
#define VMXNET3_STATE_BIT_RESETTING 0
#define VMXNET3_STATE_BIT_QUIESCED 1
struct vmxnet3_adapter {
- struct vmxnet3_tx_queue tx_queue;
- struct vmxnet3_rx_queue rx_queue;
- struct napi_struct napi;
- struct vlan_group *vlan_grp;
-
- struct vmxnet3_intr intr;
-
- struct Vmxnet3_DriverShared *shared;
- struct Vmxnet3_PMConf *pm_conf;
- struct Vmxnet3_TxQueueDesc *tqd_start; /* first tx queue desc */
- struct Vmxnet3_RxQueueDesc *rqd_start; /* first rx queue desc */
- struct net_device *netdev;
- struct pci_dev *pdev;
+ struct vmxnet3_tx_queue tx_queue[VMXNET3_DEVICE_MAX_TX_QUEUES];
+ struct vmxnet3_rx_queue rx_queue[VMXNET3_DEVICE_MAX_RX_QUEUES];
+ struct vlan_group *vlan_grp;
+ struct vmxnet3_intr intr;
+ struct Vmxnet3_DriverShared *shared;
+ struct Vmxnet3_PMConf *pm_conf;
+ struct Vmxnet3_TxQueueDesc *tqd_start; /* all tx queue desc */
+ struct Vmxnet3_RxQueueDesc *rqd_start; /* all rx queue desc */
+ struct net_device *netdev;
+ struct net_device_stats net_stats;
+ struct pci_dev *pdev;
u8 __iomem *hw_addr0; /* for BAR 0 */
u8 __iomem *hw_addr1; /* for BAR 1 */
@@ -308,6 +332,12 @@ struct vmxnet3_adapter {
bool rxcsum;
bool lro;
bool jumbo_frame;
+#ifdef VMXNET3_RSS
+ struct UPT1_RSSConf *rss_conf;
+ bool rss;
+#endif
+ u32 num_rx_queues;
+ u32 num_tx_queues;
/* rx buffer related */
unsigned skb_buf_size;
@@ -327,17 +357,18 @@ struct vmxnet3_adapter {
unsigned long state; /* VMXNET3_STATE_BIT_xxx */
int dev_number;
+ int share_intr;
};
#define VMXNET3_WRITE_BAR0_REG(adapter, reg, val) \
- writel(cpu_to_le32(val), (adapter)->hw_addr0 + (reg))
+ writel((val), (adapter)->hw_addr0 + (reg))
#define VMXNET3_READ_BAR0_REG(adapter, reg) \
- le32_to_cpu(readl((adapter)->hw_addr0 + (reg)))
+ readl((adapter)->hw_addr0 + (reg))
#define VMXNET3_WRITE_BAR1_REG(adapter, reg, val) \
- writel(cpu_to_le32(val), (adapter)->hw_addr1 + (reg))
+ writel((val), (adapter)->hw_addr1 + (reg))
#define VMXNET3_READ_BAR1_REG(adapter, reg) \
- le32_to_cpu(readl((adapter)->hw_addr1 + (reg)))
+ readl((adapter)->hw_addr1 + (reg))
#define VMXNET3_WAKE_QUEUE_THRESHOLD(tq) (5)
#define VMXNET3_RX_ALLOC_THRESHOLD(rq, ring_idx, adapter) \
@@ -366,12 +397,10 @@ void
vmxnet3_reset_dev(struct vmxnet3_adapter *adapter);
void
-vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
- struct vmxnet3_adapter *adapter);
+vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter);
void
-vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
- struct vmxnet3_adapter *adapter);
+vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
int
vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 906a3ca3676b..01c05f53e2f9 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -19,109 +19,128 @@
#include "vxge-traffic.h"
#include "vxge-config.h"
-
-static enum vxge_hw_status
-__vxge_hw_fifo_create(
- struct __vxge_hw_vpath_handle *vpath_handle,
- struct vxge_hw_fifo_attr *attr);
-
-static enum vxge_hw_status
-__vxge_hw_fifo_abort(
- struct __vxge_hw_fifo *fifoh);
-
-static enum vxge_hw_status
-__vxge_hw_fifo_reset(
- struct __vxge_hw_fifo *ringh);
-
-static enum vxge_hw_status
-__vxge_hw_fifo_delete(
- struct __vxge_hw_vpath_handle *vpath_handle);
-
-static struct __vxge_hw_blockpool_entry *
-__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *hldev,
- u32 size);
+#include "vxge-main.h"
+
+#define VXGE_HW_VPATH_STATS_PIO_READ(offset) { \
+ status = __vxge_hw_vpath_stats_access(vpath, \
+ VXGE_HW_STATS_OP_READ, \
+ offset, \
+ &val64); \
+ if (status != VXGE_HW_OK) \
+ return status; \
+}
static void
-__vxge_hw_blockpool_block_free(struct __vxge_hw_device *hldev,
- struct __vxge_hw_blockpool_entry *entry);
-
-static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
- void *block_addr,
- u32 length,
- struct pci_dev *dma_h,
- struct pci_dev *acc_handle);
-
-static enum vxge_hw_status
-__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
- struct __vxge_hw_blockpool *blockpool,
- u32 pool_size,
- u32 pool_max);
+vxge_hw_vpath_set_zero_rx_frm_len(struct vxge_hw_vpath_reg __iomem *vp_reg)
+{
+ u64 val64;
-static void
-__vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool);
+ val64 = readq(&vp_reg->rxmac_vcfg0);
+ val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
+ writeq(val64, &vp_reg->rxmac_vcfg0);
+ val64 = readq(&vp_reg->rxmac_vcfg0);
+}
-static void *
-__vxge_hw_blockpool_malloc(struct __vxge_hw_device *hldev,
- u32 size,
- struct vxge_hw_mempool_dma *dma_object);
+/*
+ * vxge_hw_vpath_wait_receive_idle - Wait for Rx to become idle
+ */
+int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+ struct __vxge_hw_virtualpath *vpath;
+ u64 val64, rxd_count, rxd_spat;
+ int count = 0, total_count = 0;
-static void
-__vxge_hw_blockpool_free(struct __vxge_hw_device *hldev,
- void *memblock,
- u32 size,
- struct vxge_hw_mempool_dma *dma_object);
+ vpath = &hldev->virtual_paths[vp_id];
+ vp_reg = vpath->vp_reg;
+ vxge_hw_vpath_set_zero_rx_frm_len(vp_reg);
-static struct __vxge_hw_channel*
-__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
- enum __vxge_hw_channel_type type, u32 length,
- u32 per_dtr_space, void *userdata);
+ /* Check that the ring controller for this vpath has enough free RxDs
+ * to send frames to the host. This is done by reading the
+ * PRC_RXD_DOORBELL_VPn register and comparing the read value to the
+ * RXD_SPAT value for the vpath.
+ */
+ val64 = readq(&vp_reg->prc_cfg6);
+ rxd_spat = VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val64) + 1;
+ /* Use a factor of 2 when comparing rxd_count against rxd_spat for some
+ * leg room.
+ */
+ rxd_spat *= 2;
-static void
-__vxge_hw_channel_free(
- struct __vxge_hw_channel *channel);
+ do {
+ mdelay(1);
-static enum vxge_hw_status
-__vxge_hw_channel_initialize(
- struct __vxge_hw_channel *channel);
+ rxd_count = readq(&vp_reg->prc_rxd_doorbell);
-static enum vxge_hw_status
-__vxge_hw_channel_reset(
- struct __vxge_hw_channel *channel);
+ /* Check that the ring controller for this vpath does
+ * not have any frame in its pipeline.
+ */
+ val64 = readq(&vp_reg->frm_in_progress_cnt);
+ if ((rxd_count <= rxd_spat) || (val64 > 0))
+ count = 0;
+ else
+ count++;
+ total_count++;
+ } while ((count < VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT) &&
+ (total_count < VXGE_HW_MAX_POLLING_COUNT));
-static enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp);
+ if (total_count >= VXGE_HW_MAX_POLLING_COUNT)
+ printk(KERN_ALERT "%s: Still Receiving traffic. Abort wait\n",
+ __func__);
-static enum vxge_hw_status
-__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config);
+ return total_count;
+}
-static enum vxge_hw_status
-__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config);
+/* vxge_hw_device_wait_receive_idle - This function waits until all frames
+ * stored in the frame buffer for each vpath assigned to the given
+ * function (hldev) have been sent to the host.
+ */
+void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev)
+{
+ int i, total_count = 0;
-static void
-__vxge_hw_device_id_get(struct __vxge_hw_device *hldev);
+ for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+ if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+ continue;
-static void
-__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
+ total_count += vxge_hw_vpath_wait_receive_idle(hldev, i);
+ if (total_count >= VXGE_HW_MAX_POLLING_COUNT)
+ break;
+ }
+}
+/*
+ * __vxge_hw_device_register_poll
+ * Will poll certain register for specified amount of time.
+ * Will poll until masked bit is not cleared.
+ */
static enum vxge_hw_status
-__vxge_hw_vpath_card_info_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info);
+__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
+{
+ u64 val64;
+ u32 i = 0;
+ enum vxge_hw_status ret = VXGE_HW_FAIL;
-static enum vxge_hw_status
-__vxge_hw_device_initialize(struct __vxge_hw_device *hldev);
+ udelay(10);
-static void
-__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev);
+ do {
+ val64 = readq(reg);
+ if (!(val64 & mask))
+ return VXGE_HW_OK;
+ udelay(100);
+ } while (++i <= 9);
-static enum vxge_hw_status
-__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev);
+ i = 0;
+ do {
+ val64 = readq(reg);
+ if (!(val64 & mask))
+ return VXGE_HW_OK;
+ mdelay(1);
+ } while (++i <= max_millis);
-static enum vxge_hw_status
-__vxge_hw_device_register_poll(
- void __iomem *reg,
- u64 mask, u32 max_millis);
+ return ret;
+}
static inline enum vxge_hw_status
__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
@@ -129,139 +148,258 @@ __vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
{
__vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
wmb();
-
__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
wmb();
- return __vxge_hw_device_register_poll(addr, mask, max_millis);
+ return __vxge_hw_device_register_poll(addr, mask, max_millis);
}
-static struct vxge_hw_mempool*
-__vxge_hw_mempool_create(struct __vxge_hw_device *devh, u32 memblock_size,
- u32 item_size, u32 private_size, u32 items_initial,
- u32 items_max, struct vxge_hw_mempool_cbs *mp_callback,
- void *userdata);
-static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool);
-
static enum vxge_hw_status
-__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_vpath_stats_hw_info *hw_stats);
+vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action,
+ u32 fw_memo, u32 offset, u64 *data0, u64 *data1,
+ u64 *steer_ctrl)
+{
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+ enum vxge_hw_status status;
+ u64 val64;
+ u32 retry = 0, max_retry = 100;
-static enum vxge_hw_status
-vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vpath_handle);
+ vp_reg = vpath->vp_reg;
-static enum vxge_hw_status
-__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg);
+ if (vpath->vp_open) {
+ max_retry = 3;
+ spin_lock(&vpath->lock);
+ }
-static u64
-__vxge_hw_vpath_pci_func_mode_get(u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg);
+ writeq(*data0, &vp_reg->rts_access_steer_data0);
+ writeq(*data1, &vp_reg->rts_access_steer_data1);
+ wmb();
-static u32
-__vxge_hw_vpath_func_id_get(u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg);
+ val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(fw_memo) |
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset) |
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
+ *steer_ctrl;
-static enum vxge_hw_status
-__vxge_hw_vpath_addr_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
- u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN]);
+ status = __vxge_hw_pio_mem_write64(val64,
+ &vp_reg->rts_access_steer_ctrl,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+ VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+ /* The __vxge_hw_device_register_poll can udelay for a significant
+ * amount of time, blocking other proccess from the CPU. If it delays
+ * for ~5secs, a NMI error can occur. A way around this is to give up
+ * the processor via msleep, but this is not allowed is under lock.
+ * So, only allow it to sleep for ~4secs if open. Otherwise, delay for
+ * 1sec and sleep for 10ms until the firmware operation has completed
+ * or timed-out.
+ */
+ while ((status != VXGE_HW_OK) && retry++ < max_retry) {
+ if (!vpath->vp_open)
+ msleep(20);
+ status = __vxge_hw_device_register_poll(
+ &vp_reg->rts_access_steer_ctrl,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
+ VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+ }
-static enum vxge_hw_status
-__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath);
+ if (status != VXGE_HW_OK)
+ goto out;
+ val64 = readq(&vp_reg->rts_access_steer_ctrl);
+ if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+ *data0 = readq(&vp_reg->rts_access_steer_data0);
+ *data1 = readq(&vp_reg->rts_access_steer_data1);
+ *steer_ctrl = val64;
+ } else
+ status = VXGE_HW_FAIL;
-static enum vxge_hw_status
-__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *devh, u32 vp_id);
+out:
+ if (vpath->vp_open)
+ spin_unlock(&vpath->lock);
+ return status;
+}
-static enum vxge_hw_status
-__vxge_hw_vpath_fw_ver_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info);
+enum vxge_hw_status
+vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major,
+ u32 *minor, u32 *build)
+{
+ u64 data0 = 0, data1 = 0, steer_ctrl = 0;
+ struct __vxge_hw_virtualpath *vpath;
+ enum vxge_hw_status status;
-static enum vxge_hw_status
-__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh, u32 vp_id);
+ vpath = &hldev->virtual_paths[hldev->first_vp_id];
-static void
-__vxge_hw_vp_terminate(struct __vxge_hw_device *devh, u32 vp_id);
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_FW_UPGRADE_ACTION,
+ VXGE_HW_FW_UPGRADE_MEMO,
+ VXGE_HW_FW_UPGRADE_OFFSET_READ,
+ &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ return status;
-static enum vxge_hw_status
-__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
- u32 operation, u32 offset, u64 *stat);
+ *major = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0);
+ *minor = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0);
+ *build = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0);
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_tx_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats);
+ return status;
+}
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats);
+enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev)
+{
+ u64 data0 = 0, data1 = 0, steer_ctrl = 0;
+ struct __vxge_hw_virtualpath *vpath;
+ enum vxge_hw_status status;
+ u32 ret;
-/*
- * __vxge_hw_channel_allocate - Allocate memory for channel
- * This function allocates required memory for the channel and various arrays
- * in the channel
- */
-struct __vxge_hw_channel*
-__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
- enum __vxge_hw_channel_type type,
- u32 length, u32 per_dtr_space, void *userdata)
+ vpath = &hldev->virtual_paths[hldev->first_vp_id];
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_FW_UPGRADE_ACTION,
+ VXGE_HW_FW_UPGRADE_MEMO,
+ VXGE_HW_FW_UPGRADE_OFFSET_COMMIT,
+ &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: FW upgrade failed", __func__);
+ goto exit;
+ }
+
+ ret = VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(steer_ctrl) & 0x7F;
+ if (ret != 1) {
+ vxge_debug_init(VXGE_ERR, "%s: FW commit failed with error %d",
+ __func__, ret);
+ status = VXGE_HW_FAIL;
+ }
+
+exit:
+ return status;
+}
+
+enum vxge_hw_status
+vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *fwdata, int size)
{
- struct __vxge_hw_channel *channel;
- struct __vxge_hw_device *hldev;
- int size = 0;
- u32 vp_id;
+ u64 data0 = 0, data1 = 0, steer_ctrl = 0;
+ struct __vxge_hw_virtualpath *vpath;
+ enum vxge_hw_status status;
+ int ret_code, sec_code;
- hldev = vph->vpath->hldev;
- vp_id = vph->vpath->vp_id;
+ vpath = &hldev->virtual_paths[hldev->first_vp_id];
- switch (type) {
- case VXGE_HW_CHANNEL_TYPE_FIFO:
- size = sizeof(struct __vxge_hw_fifo);
- break;
- case VXGE_HW_CHANNEL_TYPE_RING:
- size = sizeof(struct __vxge_hw_ring);
- break;
- default:
- break;
+ /* send upgrade start command */
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_FW_UPGRADE_ACTION,
+ VXGE_HW_FW_UPGRADE_MEMO,
+ VXGE_HW_FW_UPGRADE_OFFSET_START,
+ &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, " %s: Upgrade start cmd failed",
+ __func__);
+ return status;
}
- channel = kzalloc(size, GFP_KERNEL);
- if (channel == NULL)
- goto exit0;
- INIT_LIST_HEAD(&channel->item);
+ /* Transfer fw image to adapter 16 bytes at a time */
+ for (; size > 0; size -= VXGE_HW_FW_UPGRADE_BLK_SIZE) {
+ steer_ctrl = 0;
- channel->common_reg = hldev->common_reg;
- channel->first_vp_id = hldev->first_vp_id;
- channel->type = type;
- channel->devh = hldev;
- channel->vph = vph;
- channel->userdata = userdata;
- channel->per_dtr_space = per_dtr_space;
- channel->length = length;
- channel->vp_id = vp_id;
+ /* The next 128bits of fwdata to be loaded onto the adapter */
+ data0 = *((u64 *)fwdata);
+ data1 = *((u64 *)fwdata + 1);
- channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
- if (channel->work_arr == NULL)
- goto exit1;
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_FW_UPGRADE_ACTION,
+ VXGE_HW_FW_UPGRADE_MEMO,
+ VXGE_HW_FW_UPGRADE_OFFSET_SEND,
+ &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: Upgrade send failed",
+ __func__);
+ goto out;
+ }
- channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
- if (channel->free_arr == NULL)
- goto exit1;
- channel->free_ptr = length;
+ ret_code = VXGE_HW_UPGRADE_GET_RET_ERR_CODE(data0);
+ switch (ret_code) {
+ case VXGE_HW_FW_UPGRADE_OK:
+ /* All OK, send next 16 bytes. */
+ break;
+ case VXGE_FW_UPGRADE_BYTES2SKIP:
+ /* skip bytes in the stream */
+ fwdata += (data0 >> 8) & 0xFFFFFFFF;
+ break;
+ case VXGE_HW_FW_UPGRADE_DONE:
+ goto out;
+ case VXGE_HW_FW_UPGRADE_ERR:
+ sec_code = VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(data0);
+ switch (sec_code) {
+ case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1:
+ case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7:
+ printk(KERN_ERR
+ "corrupted data from .ncf file\n");
+ break;
+ case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3:
+ case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4:
+ case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5:
+ case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6:
+ case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8:
+ printk(KERN_ERR "invalid .ncf file\n");
+ break;
+ case VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW:
+ printk(KERN_ERR "buffer overflow\n");
+ break;
+ case VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH:
+ printk(KERN_ERR "failed to flash the image\n");
+ break;
+ case VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN:
+ printk(KERN_ERR
+ "generic error. Unknown error type\n");
+ break;
+ default:
+ printk(KERN_ERR "Unknown error of type %d\n",
+ sec_code);
+ break;
+ }
+ status = VXGE_HW_FAIL;
+ goto out;
+ default:
+ printk(KERN_ERR "Unknown FW error: %d\n", ret_code);
+ status = VXGE_HW_FAIL;
+ goto out;
+ }
+ /* point to next 16 bytes */
+ fwdata += VXGE_HW_FW_UPGRADE_BLK_SIZE;
+ }
+out:
+ return status;
+}
- channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
- if (channel->reserve_arr == NULL)
- goto exit1;
- channel->reserve_ptr = length;
- channel->reserve_top = 0;
+enum vxge_hw_status
+vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev,
+ struct eprom_image *img)
+{
+ u64 data0 = 0, data1 = 0, steer_ctrl = 0;
+ struct __vxge_hw_virtualpath *vpath;
+ enum vxge_hw_status status;
+ int i;
- channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
- if (channel->orig_arr == NULL)
- goto exit1;
+ vpath = &hldev->virtual_paths[hldev->first_vp_id];
- return channel;
-exit1:
- __vxge_hw_channel_free(channel);
+ for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) {
+ data0 = VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(i);
+ data1 = steer_ctrl = 0;
-exit0:
- return NULL;
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ VXGE_HW_FW_API_GET_EPROM_REV,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ break;
+
+ img[i].is_valid = VXGE_HW_GET_EPROM_IMAGE_VALID(data0);
+ img[i].index = VXGE_HW_GET_EPROM_IMAGE_INDEX(data0);
+ img[i].type = VXGE_HW_GET_EPROM_IMAGE_TYPE(data0);
+ img[i].version = VXGE_HW_GET_EPROM_IMAGE_REV(data0);
+ }
+
+ return status;
}
/*
@@ -269,7 +407,7 @@ exit0:
* This function deallocates memory from the channel and various arrays
* in the channel
*/
-void __vxge_hw_channel_free(struct __vxge_hw_channel *channel)
+static void __vxge_hw_channel_free(struct __vxge_hw_channel *channel)
{
kfree(channel->work_arr);
kfree(channel->free_arr);
@@ -283,7 +421,7 @@ void __vxge_hw_channel_free(struct __vxge_hw_channel *channel)
* This function initializes a channel by properly setting the
* various references
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_channel_initialize(struct __vxge_hw_channel *channel)
{
u32 i;
@@ -318,7 +456,7 @@ __vxge_hw_channel_initialize(struct __vxge_hw_channel *channel)
* __vxge_hw_channel_reset - Resets a channel
* This function resets a channel by properly setting the various references
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_channel_reset(struct __vxge_hw_channel *channel)
{
u32 i;
@@ -345,8 +483,7 @@ __vxge_hw_channel_reset(struct __vxge_hw_channel *channel)
* Initialize certain PCI/PCI-X configuration registers
* with recommended values. Save config space for future hw resets.
*/
-void
-__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
+static void __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
{
u16 cmd = 0;
@@ -358,39 +495,7 @@ __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
pci_save_state(hldev->pdev);
}
-/*
- * __vxge_hw_device_register_poll
- * Will poll certain register for specified amount of time.
- * Will poll until masked bit is not cleared.
- */
-static enum vxge_hw_status
-__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
-{
- u64 val64;
- u32 i = 0;
- enum vxge_hw_status ret = VXGE_HW_FAIL;
-
- udelay(10);
-
- do {
- val64 = readq(reg);
- if (!(val64 & mask))
- return VXGE_HW_OK;
- udelay(100);
- } while (++i <= 9);
-
- i = 0;
- do {
- val64 = readq(reg);
- if (!(val64 & mask))
- return VXGE_HW_OK;
- mdelay(1);
- } while (++i <= max_millis);
-
- return ret;
-}
-
- /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset
+/* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset
* in progress
* This routine checks the vpath reset in progress register is turned zero
*/
@@ -405,6 +510,60 @@ __vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
}
/*
+ * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
+ * Set the swapper bits appropriately for the lagacy section.
+ */
+static enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
+{
+ u64 val64;
+ enum vxge_hw_status status = VXGE_HW_OK;
+
+ val64 = readq(&legacy_reg->toc_swapper_fb);
+
+ wmb();
+
+ switch (val64) {
+ case VXGE_HW_SWAPPER_INITIAL_VALUE:
+ return status;
+
+ case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED:
+ writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+ &legacy_reg->pifm_rd_swap_en);
+ writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+ &legacy_reg->pifm_rd_flip_en);
+ writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+ &legacy_reg->pifm_wr_swap_en);
+ writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+ &legacy_reg->pifm_wr_flip_en);
+ break;
+
+ case VXGE_HW_SWAPPER_BYTE_SWAPPED:
+ writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
+ &legacy_reg->pifm_rd_swap_en);
+ writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
+ &legacy_reg->pifm_wr_swap_en);
+ break;
+
+ case VXGE_HW_SWAPPER_BIT_FLIPPED:
+ writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
+ &legacy_reg->pifm_rd_flip_en);
+ writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
+ &legacy_reg->pifm_wr_flip_en);
+ break;
+ }
+
+ wmb();
+
+ val64 = readq(&legacy_reg->toc_swapper_fb);
+
+ if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE)
+ status = VXGE_HW_ERR_SWAPPER_CTRL;
+
+ return status;
+}
+
+/*
* __vxge_hw_device_toc_get
* This routine sets the swapper and reads the toc pointer and returns the
* memory mapped address of the toc
@@ -435,7 +594,7 @@ exit:
* register location pointers in the device object. It waits until the ric is
* completed initializing registers.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
{
u64 val64;
@@ -496,26 +655,6 @@ exit:
}
/*
- * __vxge_hw_device_id_get
- * This routine returns sets the device id and revision numbers into the device
- * structure
- */
-void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev)
-{
- u64 val64;
-
- val64 = readq(&hldev->common_reg->titan_asic_id);
- hldev->device_id =
- (u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64);
-
- hldev->major_revision =
- (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64);
-
- hldev->minor_revision =
- (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64);
-}
-
-/*
* __vxge_hw_device_access_rights_get: Get Access Rights of the driver
* This routine returns the Access Rights of the driver
*/
@@ -568,10 +707,25 @@ __vxge_hw_device_is_privilaged(u32 host_type, u32 func_id)
}
/*
+ * __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
+ * Returns the function number of the vpath.
+ */
+static u32
+__vxge_hw_vpath_func_id_get(struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
+{
+ u64 val64;
+
+ val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1);
+
+ return
+ (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64);
+}
+
+/*
* __vxge_hw_device_host_info_get
* This routine returns the host type assignments
*/
-void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
+static void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
{
u64 val64;
u32 i;
@@ -584,16 +738,18 @@ void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments);
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
if (!(hldev->vpath_assignments & vxge_mBIT(i)))
continue;
hldev->func_id =
- __vxge_hw_vpath_func_id_get(i, hldev->vpmgmt_reg[i]);
+ __vxge_hw_vpath_func_id_get(hldev->vpmgmt_reg[i]);
hldev->access_rights = __vxge_hw_device_access_rights_get(
hldev->host_type, hldev->func_id);
+ hldev->virtual_paths[i].vp_open = VXGE_HW_VP_NOT_OPEN;
+ hldev->virtual_paths[i].vp_reg = hldev->vpath_reg[i];
+
hldev->first_vp_id = i;
break;
}
@@ -634,7 +790,8 @@ __vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev)
* __vxge_hw_device_initialize
* Initialize Titan-V hardware.
*/
-enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev)
+static enum vxge_hw_status
+__vxge_hw_device_initialize(struct __vxge_hw_device *hldev)
{
enum vxge_hw_status status = VXGE_HW_OK;
@@ -650,6 +807,196 @@ exit:
return status;
}
+/*
+ * __vxge_hw_vpath_fw_ver_get - Get the fw version
+ * Returns FW Version
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_device_hw_info *hw_info)
+{
+ struct vxge_hw_device_version *fw_version = &hw_info->fw_version;
+ struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
+ struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
+ struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
+ u64 data0, data1 = 0, steer_ctrl = 0;
+ enum vxge_hw_status status;
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ fw_date->day =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(data0);
+ fw_date->month =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(data0);
+ fw_date->year =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(data0);
+
+ snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
+ fw_date->month, fw_date->day, fw_date->year);
+
+ fw_version->major =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0);
+ fw_version->minor =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0);
+ fw_version->build =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0);
+
+ snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+ fw_version->major, fw_version->minor, fw_version->build);
+
+ flash_date->day =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data1);
+ flash_date->month =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data1);
+ flash_date->year =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data1);
+
+ snprintf(flash_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
+ flash_date->month, flash_date->day, flash_date->year);
+
+ flash_version->major =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data1);
+ flash_version->minor =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data1);
+ flash_version->build =
+ (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data1);
+
+ snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
+ flash_version->major, flash_version->minor,
+ flash_version->build);
+
+exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_card_info_get - Get the serial numbers,
+ * part number and product description.
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_device_hw_info *hw_info)
+{
+ enum vxge_hw_status status;
+ u64 data0, data1 = 0, steer_ctrl = 0;
+ u8 *serial_number = hw_info->serial_number;
+ u8 *part_number = hw_info->part_number;
+ u8 *product_desc = hw_info->product_desc;
+ u32 i, j = 0;
+
+ data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER;
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ return status;
+
+ ((u64 *)serial_number)[0] = be64_to_cpu(data0);
+ ((u64 *)serial_number)[1] = be64_to_cpu(data1);
+
+ data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER;
+ data1 = steer_ctrl = 0;
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ return status;
+
+ ((u64 *)part_number)[0] = be64_to_cpu(data0);
+ ((u64 *)part_number)[1] = be64_to_cpu(data1);
+
+ for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0;
+ i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) {
+ data0 = i;
+ data1 = steer_ctrl = 0;
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ return status;
+
+ ((u64 *)product_desc)[j++] = be64_to_cpu(data0);
+ ((u64 *)product_desc)[j++] = be64_to_cpu(data1);
+ }
+
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode
+ * Returns pci function mode
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_device_hw_info *hw_info)
+{
+ u64 data0, data1 = 0, steer_ctrl = 0;
+ enum vxge_hw_status status;
+
+ data0 = 0;
+
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_FW_API_GET_FUNC_MODE,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ return status;
+
+ hw_info->function_mode = VXGE_HW_GET_FUNC_MODE_VAL(data0);
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
+ * from MAC address table.
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_addr_get(struct __vxge_hw_virtualpath *vpath,
+ u8 *macaddr, u8 *macaddr_mask)
+{
+ u64 action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY,
+ data0 = 0, data1 = 0, steer_ctrl = 0;
+ enum vxge_hw_status status;
+ int i;
+
+ do {
+ status = vxge_hw_vpath_fw_api(vpath, action,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
+ 0, &data0, &data1, &steer_ctrl);
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data0);
+ data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(
+ data1);
+
+ for (i = ETH_ALEN; i > 0; i--) {
+ macaddr[i - 1] = (u8) (data0 & 0xFF);
+ data0 >>= 8;
+
+ macaddr_mask[i - 1] = (u8) (data1 & 0xFF);
+ data1 >>= 8;
+ }
+
+ action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY;
+ data0 = 0, data1 = 0, steer_ctrl = 0;
+
+ } while (!is_valid_ether_addr(macaddr));
+exit:
+ return status;
+}
+
/**
* vxge_hw_device_hw_info_get - Get the hw information
* Returns the vpath mask that has the bits set for each vpath allocated
@@ -665,9 +1012,9 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
struct vxge_hw_toc_reg __iomem *toc;
struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg;
struct vxge_hw_common_reg __iomem *common_reg;
- struct vxge_hw_vpath_reg __iomem *vpath_reg;
struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
enum vxge_hw_status status;
+ struct __vxge_hw_virtualpath vpath;
memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
@@ -693,7 +1040,6 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
(u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
continue;
@@ -702,7 +1048,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *)
(bar0 + val64);
- hw_info->func_id = __vxge_hw_vpath_func_id_get(i, vpmgmt_reg);
+ hw_info->func_id = __vxge_hw_vpath_func_id_get(vpmgmt_reg);
if (__vxge_hw_device_access_rights_get(hw_info->host_type,
hw_info->func_id) &
VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
@@ -718,16 +1064,19 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
val64 = readq(&toc->toc_vpath_pointer[i]);
- vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+ vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *)
+ (bar0 + val64);
+ vpath.vp_open = 0;
- hw_info->function_mode =
- __vxge_hw_vpath_pci_func_mode_get(i, vpath_reg);
+ status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info);
+ if (status != VXGE_HW_OK)
+ goto exit;
- status = __vxge_hw_vpath_fw_ver_get(i, vpath_reg, hw_info);
+ status = __vxge_hw_vpath_fw_ver_get(&vpath, hw_info);
if (status != VXGE_HW_OK)
goto exit;
- status = __vxge_hw_vpath_card_info_get(i, vpath_reg, hw_info);
+ status = __vxge_hw_vpath_card_info_get(&vpath, hw_info);
if (status != VXGE_HW_OK)
goto exit;
@@ -735,14 +1084,15 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
}
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
continue;
val64 = readq(&toc->toc_vpath_pointer[i]);
- vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64);
+ vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *)
+ (bar0 + val64);
+ vpath.vp_open = 0;
- status = __vxge_hw_vpath_addr_get(i, vpath_reg,
+ status = __vxge_hw_vpath_addr_get(&vpath,
hw_info->mac_addrs[i],
hw_info->mac_addr_masks[i]);
if (status != VXGE_HW_OK)
@@ -753,6 +1103,218 @@ exit:
}
/*
+ * __vxge_hw_blockpool_destroy - Deallocates the block pool
+ */
+static void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool)
+{
+ struct __vxge_hw_device *hldev;
+ struct list_head *p, *n;
+ u16 ret;
+
+ if (blockpool == NULL) {
+ ret = 1;
+ goto exit;
+ }
+
+ hldev = blockpool->hldev;
+
+ list_for_each_safe(p, n, &blockpool->free_block_list) {
+ pci_unmap_single(hldev->pdev,
+ ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
+ ((struct __vxge_hw_blockpool_entry *)p)->length,
+ PCI_DMA_BIDIRECTIONAL);
+
+ vxge_os_dma_free(hldev->pdev,
+ ((struct __vxge_hw_blockpool_entry *)p)->memblock,
+ &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
+
+ list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
+ kfree(p);
+ blockpool->pool_size--;
+ }
+
+ list_for_each_safe(p, n, &blockpool->free_entry_list) {
+ list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
+ kfree((void *)p);
+ }
+ ret = 0;
+exit:
+ return;
+}
+
+/*
+ * __vxge_hw_blockpool_create - Create block pool
+ */
+static enum vxge_hw_status
+__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
+ struct __vxge_hw_blockpool *blockpool,
+ u32 pool_size,
+ u32 pool_max)
+{
+ u32 i;
+ struct __vxge_hw_blockpool_entry *entry = NULL;
+ void *memblock;
+ dma_addr_t dma_addr;
+ struct pci_dev *dma_handle;
+ struct pci_dev *acc_handle;
+ enum vxge_hw_status status = VXGE_HW_OK;
+
+ if (blockpool == NULL) {
+ status = VXGE_HW_FAIL;
+ goto blockpool_create_exit;
+ }
+
+ blockpool->hldev = hldev;
+ blockpool->block_size = VXGE_HW_BLOCK_SIZE;
+ blockpool->pool_size = 0;
+ blockpool->pool_max = pool_max;
+ blockpool->req_out = 0;
+
+ INIT_LIST_HEAD(&blockpool->free_block_list);
+ INIT_LIST_HEAD(&blockpool->free_entry_list);
+
+ for (i = 0; i < pool_size + pool_max; i++) {
+ entry = kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
+ GFP_KERNEL);
+ if (entry == NULL) {
+ __vxge_hw_blockpool_destroy(blockpool);
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto blockpool_create_exit;
+ }
+ list_add(&entry->item, &blockpool->free_entry_list);
+ }
+
+ for (i = 0; i < pool_size; i++) {
+ memblock = vxge_os_dma_malloc(
+ hldev->pdev,
+ VXGE_HW_BLOCK_SIZE,
+ &dma_handle,
+ &acc_handle);
+ if (memblock == NULL) {
+ __vxge_hw_blockpool_destroy(blockpool);
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto blockpool_create_exit;
+ }
+
+ dma_addr = pci_map_single(hldev->pdev, memblock,
+ VXGE_HW_BLOCK_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(hldev->pdev,
+ dma_addr))) {
+ vxge_os_dma_free(hldev->pdev, memblock, &acc_handle);
+ __vxge_hw_blockpool_destroy(blockpool);
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto blockpool_create_exit;
+ }
+
+ if (!list_empty(&blockpool->free_entry_list))
+ entry = (struct __vxge_hw_blockpool_entry *)
+ list_first_entry(&blockpool->free_entry_list,
+ struct __vxge_hw_blockpool_entry,
+ item);
+
+ if (entry == NULL)
+ entry =
+ kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
+ GFP_KERNEL);
+ if (entry != NULL) {
+ list_del(&entry->item);
+ entry->length = VXGE_HW_BLOCK_SIZE;
+ entry->memblock = memblock;
+ entry->dma_addr = dma_addr;
+ entry->acc_handle = acc_handle;
+ entry->dma_handle = dma_handle;
+ list_add(&entry->item,
+ &blockpool->free_block_list);
+ blockpool->pool_size++;
+ } else {
+ __vxge_hw_blockpool_destroy(blockpool);
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto blockpool_create_exit;
+ }
+ }
+
+blockpool_create_exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_device_fifo_config_check - Check fifo configuration.
+ * Check the fifo configuration
+ */
+static enum vxge_hw_status
+__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config)
+{
+ if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) ||
+ (fifo_config->fifo_blocks > VXGE_HW_MAX_FIFO_BLOCKS))
+ return VXGE_HW_BADCFG_FIFO_BLOCKS;
+
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_vpath_config_check - Check vpath configuration.
+ * Check the vpath configuration
+ */
+static enum vxge_hw_status
+__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config)
+{
+ enum vxge_hw_status status;
+
+ if ((vp_config->min_bandwidth < VXGE_HW_VPATH_BANDWIDTH_MIN) ||
+ (vp_config->min_bandwidth > VXGE_HW_VPATH_BANDWIDTH_MAX))
+ return VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH;
+
+ status = __vxge_hw_device_fifo_config_check(&vp_config->fifo);
+ if (status != VXGE_HW_OK)
+ return status;
+
+ if ((vp_config->mtu != VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) &&
+ ((vp_config->mtu < VXGE_HW_VPATH_MIN_INITIAL_MTU) ||
+ (vp_config->mtu > VXGE_HW_VPATH_MAX_INITIAL_MTU)))
+ return VXGE_HW_BADCFG_VPATH_MTU;
+
+ if ((vp_config->rpa_strip_vlan_tag !=
+ VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) &&
+ (vp_config->rpa_strip_vlan_tag !=
+ VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) &&
+ (vp_config->rpa_strip_vlan_tag !=
+ VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE))
+ return VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG;
+
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_config_check - Check device configuration.
+ * Check the device configuration
+ */
+static enum vxge_hw_status
+__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config)
+{
+ u32 i;
+ enum vxge_hw_status status;
+
+ if ((new_config->intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
+ (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
+ (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
+ (new_config->intr_mode != VXGE_HW_INTR_MODE_DEF))
+ return VXGE_HW_BADCFG_INTR_MODE;
+
+ if ((new_config->rts_mac_en != VXGE_HW_RTS_MAC_DISABLE) &&
+ (new_config->rts_mac_en != VXGE_HW_RTS_MAC_ENABLE))
+ return VXGE_HW_BADCFG_RTS_MAC_EN;
+
+ for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+ status = __vxge_hw_device_vpath_config_check(
+ &new_config->vp_config[i]);
+ if (status != VXGE_HW_OK)
+ return status;
+ }
+
+ return VXGE_HW_OK;
+}
+
+/*
* vxge_hw_device_initialize - Initialize Titan device.
* Initialize Titan device. Note that all the arguments of this public API
* are 'IN', including @hldev. Driver cooperates with
@@ -776,14 +1338,12 @@ vxge_hw_device_initialize(
if (status != VXGE_HW_OK)
goto exit;
- hldev = (struct __vxge_hw_device *)
- vmalloc(sizeof(struct __vxge_hw_device));
+ hldev = vzalloc(sizeof(struct __vxge_hw_device));
if (hldev == NULL) {
status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto exit;
}
- memset(hldev, 0, sizeof(struct __vxge_hw_device));
hldev->magic = VXGE_HW_DEVICE_MAGIC;
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL);
@@ -806,7 +1366,6 @@ vxge_hw_device_initialize(
vfree(hldev);
goto exit;
}
- __vxge_hw_device_id_get(hldev);
__vxge_hw_device_host_info_get(hldev);
@@ -814,7 +1373,6 @@ vxge_hw_device_initialize(
nblocks++;
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
if (!(hldev->vpath_assignments & vxge_mBIT(i)))
continue;
@@ -839,7 +1397,6 @@ vxge_hw_device_initialize(
}
status = __vxge_hw_device_initialize(hldev);
-
if (status != VXGE_HW_OK) {
vxge_hw_device_terminate(hldev);
goto exit;
@@ -865,6 +1422,242 @@ vxge_hw_device_terminate(struct __vxge_hw_device *hldev)
}
/*
+ * __vxge_hw_vpath_stats_access - Get the statistics from the given location
+ * and offset and perform an operation
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
+ u32 operation, u32 offset, u64 *stat)
+{
+ u64 val64;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+ status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+ goto vpath_stats_access_exit;
+ }
+
+ vp_reg = vpath->vp_reg;
+
+ val64 = VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(operation) |
+ VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE |
+ VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(offset);
+
+ status = __vxge_hw_pio_mem_write64(val64,
+ &vp_reg->xmac_stats_access_cmd,
+ VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE,
+ vpath->hldev->config.device_poll_millis);
+ if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
+ *stat = readq(&vp_reg->xmac_stats_access_data);
+ else
+ *stat = 0;
+
+vpath_stats_access_exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_xmac_tx_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats)
+{
+ u64 *val64;
+ int i;
+ u32 offset = VXGE_HW_STATS_VPATH_TX_OFFSET;
+ enum vxge_hw_status status = VXGE_HW_OK;
+
+ val64 = (u64 *)vpath_tx_stats;
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+ status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+ goto exit;
+ }
+
+ for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_tx_stats) / 8; i++) {
+ status = __vxge_hw_vpath_stats_access(vpath,
+ VXGE_HW_STATS_OP_READ,
+ offset, val64);
+ if (status != VXGE_HW_OK)
+ goto exit;
+ offset++;
+ val64++;
+ }
+exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
+{
+ u64 *val64;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ int i;
+ u32 offset = VXGE_HW_STATS_VPATH_RX_OFFSET;
+ val64 = (u64 *) vpath_rx_stats;
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+ status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+ goto exit;
+ }
+ for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_rx_stats) / 8; i++) {
+ status = __vxge_hw_vpath_stats_access(vpath,
+ VXGE_HW_STATS_OP_READ,
+ offset >> 3, val64);
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ offset += 8;
+ val64++;
+ }
+exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_vpath_stats_get - Get the vpath hw statistics.
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_vpath_stats_hw_info *hw_stats)
+{
+ u64 val64;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+ status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+ goto exit;
+ }
+ vp_reg = vpath->vp_reg;
+
+ val64 = readq(&vp_reg->vpath_debug_stats0);
+ hw_stats->ini_num_mwr_sent =
+ (u32)VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats1);
+ hw_stats->ini_num_mrd_sent =
+ (u32)VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats2);
+ hw_stats->ini_num_cpl_rcvd =
+ (u32)VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats3);
+ hw_stats->ini_num_mwr_byte_sent =
+ VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats4);
+ hw_stats->ini_num_cpl_byte_rcvd =
+ VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats5);
+ hw_stats->wrcrdtarb_xoff =
+ (u32)VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(val64);
+
+ val64 = readq(&vp_reg->vpath_debug_stats6);
+ hw_stats->rdcrdtarb_xoff =
+ (u32)VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count01);
+ hw_stats->vpath_genstats_count0 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(
+ val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count01);
+ hw_stats->vpath_genstats_count1 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(
+ val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count23);
+ hw_stats->vpath_genstats_count2 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(
+ val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count01);
+ hw_stats->vpath_genstats_count3 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(
+ val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count4);
+ hw_stats->vpath_genstats_count4 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(
+ val64);
+
+ val64 = readq(&vp_reg->vpath_genstats_count5);
+ hw_stats->vpath_genstats_count5 =
+ (u32)VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(
+ val64);
+
+ status = __vxge_hw_vpath_xmac_tx_stats_get(vpath, &hw_stats->tx_stats);
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ status = __vxge_hw_vpath_xmac_rx_stats_get(vpath, &hw_stats->rx_stats);
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ VXGE_HW_VPATH_STATS_PIO_READ(
+ VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET);
+
+ hw_stats->prog_event_vnum0 =
+ (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(val64);
+
+ hw_stats->prog_event_vnum1 =
+ (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(val64);
+
+ VXGE_HW_VPATH_STATS_PIO_READ(
+ VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET);
+
+ hw_stats->prog_event_vnum2 =
+ (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(val64);
+
+ hw_stats->prog_event_vnum3 =
+ (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(val64);
+
+ val64 = readq(&vp_reg->rx_multi_cast_stats);
+ hw_stats->rx_multi_cast_frame_discard =
+ (u16)VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(val64);
+
+ val64 = readq(&vp_reg->rx_frm_transferred);
+ hw_stats->rx_frm_transferred =
+ (u32)VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(val64);
+
+ val64 = readq(&vp_reg->rxd_returned);
+ hw_stats->rxd_returned =
+ (u16)VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(val64);
+
+ val64 = readq(&vp_reg->dbg_stats_rx_mpa);
+ hw_stats->rx_mpa_len_fail_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(val64);
+ hw_stats->rx_mpa_mrk_fail_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(val64);
+ hw_stats->rx_mpa_crc_fail_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(val64);
+
+ val64 = readq(&vp_reg->dbg_stats_rx_fau);
+ hw_stats->rx_permitted_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(val64);
+ hw_stats->rx_vp_reset_discarded_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val64);
+ hw_stats->rx_wol_frms =
+ (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(val64);
+
+ val64 = readq(&vp_reg->tx_vp_reset_discarded_frms);
+ hw_stats->tx_vp_reset_discarded_frms =
+ (u16)VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(
+ val64);
+exit:
+ return status;
+}
+
+/*
* vxge_hw_device_stats_get - Get the device hw statistics.
* Returns the vpath h/w stats for the device.
*/
@@ -876,7 +1669,6 @@ vxge_hw_device_stats_get(struct __vxge_hw_device *hldev,
enum vxge_hw_status status = VXGE_HW_OK;
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
if (!(hldev->vpaths_deployed & vxge_mBIT(i)) ||
(hldev->virtual_paths[i].vp_open ==
VXGE_HW_VP_NOT_OPEN))
@@ -1031,7 +1823,6 @@ vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *hldev,
status = vxge_hw_device_xmac_aggr_stats_get(hldev,
0, &xmac_stats->aggr_stats[0]);
-
if (status != VXGE_HW_OK)
goto exit;
@@ -1165,7 +1956,6 @@ exit:
* It can be used to set or reset Pause frame generation or reception
* support of the NIC.
*/
-
enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev,
u32 port, u32 tx, u32 rx)
{
@@ -1407,190 +2197,359 @@ exit:
}
/*
- * __vxge_hw_ring_create - Create a Ring
- * This function creates Ring and initializes it.
- *
+ * __vxge_hw_channel_allocate - Allocate memory for channel
+ * This function allocates required memory for the channel and various arrays
+ * in the channel
*/
-static enum vxge_hw_status
-__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
- struct vxge_hw_ring_attr *attr)
+static struct __vxge_hw_channel *
+__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
+ enum __vxge_hw_channel_type type,
+ u32 length, u32 per_dtr_space,
+ void *userdata)
{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct __vxge_hw_ring *ring;
- u32 ring_length;
- struct vxge_hw_ring_config *config;
+ struct __vxge_hw_channel *channel;
struct __vxge_hw_device *hldev;
+ int size = 0;
u32 vp_id;
- struct vxge_hw_mempool_cbs ring_mp_callback;
- if ((vp == NULL) || (attr == NULL)) {
+ hldev = vph->vpath->hldev;
+ vp_id = vph->vpath->vp_id;
+
+ switch (type) {
+ case VXGE_HW_CHANNEL_TYPE_FIFO:
+ size = sizeof(struct __vxge_hw_fifo);
+ break;
+ case VXGE_HW_CHANNEL_TYPE_RING:
+ size = sizeof(struct __vxge_hw_ring);
+ break;
+ default:
+ break;
+ }
+
+ channel = kzalloc(size, GFP_KERNEL);
+ if (channel == NULL)
+ goto exit0;
+ INIT_LIST_HEAD(&channel->item);
+
+ channel->common_reg = hldev->common_reg;
+ channel->first_vp_id = hldev->first_vp_id;
+ channel->type = type;
+ channel->devh = hldev;
+ channel->vph = vph;
+ channel->userdata = userdata;
+ channel->per_dtr_space = per_dtr_space;
+ channel->length = length;
+ channel->vp_id = vp_id;
+
+ channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+ if (channel->work_arr == NULL)
+ goto exit1;
+
+ channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+ if (channel->free_arr == NULL)
+ goto exit1;
+ channel->free_ptr = length;
+
+ channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+ if (channel->reserve_arr == NULL)
+ goto exit1;
+ channel->reserve_ptr = length;
+ channel->reserve_top = 0;
+
+ channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL);
+ if (channel->orig_arr == NULL)
+ goto exit1;
+
+ return channel;
+exit1:
+ __vxge_hw_channel_free(channel);
+
+exit0:
+ return NULL;
+}
+
+/*
+ * vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async
+ * Adds a block to block pool
+ */
+static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
+ void *block_addr,
+ u32 length,
+ struct pci_dev *dma_h,
+ struct pci_dev *acc_handle)
+{
+ struct __vxge_hw_blockpool *blockpool;
+ struct __vxge_hw_blockpool_entry *entry = NULL;
+ dma_addr_t dma_addr;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ u32 req_out;
+
+ blockpool = &devh->block_pool;
+
+ if (block_addr == NULL) {
+ blockpool->req_out--;
status = VXGE_HW_FAIL;
goto exit;
}
- hldev = vp->vpath->hldev;
- vp_id = vp->vpath->vp_id;
+ dma_addr = pci_map_single(devh->pdev, block_addr, length,
+ PCI_DMA_BIDIRECTIONAL);
- config = &hldev->config.vp_config[vp_id].ring;
+ if (unlikely(pci_dma_mapping_error(devh->pdev, dma_addr))) {
+ vxge_os_dma_free(devh->pdev, block_addr, &acc_handle);
+ blockpool->req_out--;
+ status = VXGE_HW_FAIL;
+ goto exit;
+ }
- ring_length = config->ring_blocks *
- vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+ if (!list_empty(&blockpool->free_entry_list))
+ entry = (struct __vxge_hw_blockpool_entry *)
+ list_first_entry(&blockpool->free_entry_list,
+ struct __vxge_hw_blockpool_entry,
+ item);
- ring = (struct __vxge_hw_ring *)__vxge_hw_channel_allocate(vp,
- VXGE_HW_CHANNEL_TYPE_RING,
- ring_length,
- attr->per_rxd_space,
- attr->userdata);
+ if (entry == NULL)
+ entry = vmalloc(sizeof(struct __vxge_hw_blockpool_entry));
+ else
+ list_del(&entry->item);
- if (ring == NULL) {
+ if (entry != NULL) {
+ entry->length = length;
+ entry->memblock = block_addr;
+ entry->dma_addr = dma_addr;
+ entry->acc_handle = acc_handle;
+ entry->dma_handle = dma_h;
+ list_add(&entry->item, &blockpool->free_block_list);
+ blockpool->pool_size++;
+ status = VXGE_HW_OK;
+ } else
status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto exit;
- }
- vp->vpath->ringh = ring;
- ring->vp_id = vp_id;
- ring->vp_reg = vp->vpath->vp_reg;
- ring->common_reg = hldev->common_reg;
- ring->stats = &vp->vpath->sw_stats->ring_stats;
- ring->config = config;
- ring->callback = attr->callback;
- ring->rxd_init = attr->rxd_init;
- ring->rxd_term = attr->rxd_term;
- ring->buffer_mode = config->buffer_mode;
- ring->rxds_limit = config->rxds_limit;
+ blockpool->req_out--;
- ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode);
- ring->rxd_priv_size =
- sizeof(struct __vxge_hw_ring_rxd_priv) + attr->per_rxd_space;
- ring->per_rxd_space = attr->per_rxd_space;
+ req_out = blockpool->req_out;
+exit:
+ return;
+}
- ring->rxd_priv_size =
- ((ring->rxd_priv_size + VXGE_CACHE_LINE_SIZE - 1) /
- VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
+static inline void
+vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh, unsigned long size)
+{
+ gfp_t flags;
+ void *vaddr;
- /* how many RxDs can fit into one block. Depends on configured
- * buffer_mode. */
- ring->rxds_per_block =
- vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+ if (in_interrupt())
+ flags = GFP_ATOMIC | GFP_DMA;
+ else
+ flags = GFP_KERNEL | GFP_DMA;
- /* calculate actual RxD block private size */
- ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
- ring_mp_callback.item_func_alloc = __vxge_hw_ring_mempool_item_alloc;
- ring->mempool = __vxge_hw_mempool_create(hldev,
- VXGE_HW_BLOCK_SIZE,
- VXGE_HW_BLOCK_SIZE,
- ring->rxdblock_priv_size,
- ring->config->ring_blocks,
- ring->config->ring_blocks,
- &ring_mp_callback,
- ring);
+ vaddr = kmalloc((size), flags);
- if (ring->mempool == NULL) {
- __vxge_hw_ring_delete(vp);
- return VXGE_HW_ERR_OUT_OF_MEMORY;
- }
+ vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
+}
- status = __vxge_hw_channel_initialize(&ring->channel);
- if (status != VXGE_HW_OK) {
- __vxge_hw_ring_delete(vp);
- goto exit;
+/*
+ * __vxge_hw_blockpool_blocks_add - Request additional blocks
+ */
+static
+void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool)
+{
+ u32 nreq = 0, i;
+
+ if ((blockpool->pool_size + blockpool->req_out) <
+ VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE) {
+ nreq = VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE;
+ blockpool->req_out += nreq;
}
- /* Note:
- * Specifying rxd_init callback means two things:
- * 1) rxds need to be initialized by driver at channel-open time;
- * 2) rxds need to be posted at channel-open time
- * (that's what the initial_replenish() below does)
- * Currently we don't have a case when the 1) is done without the 2).
- */
- if (ring->rxd_init) {
- status = vxge_hw_ring_replenish(ring);
- if (status != VXGE_HW_OK) {
- __vxge_hw_ring_delete(vp);
+ for (i = 0; i < nreq; i++)
+ vxge_os_dma_malloc_async(
+ ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+ blockpool->hldev, VXGE_HW_BLOCK_SIZE);
+}
+
+/*
+ * __vxge_hw_blockpool_malloc - Allocate a memory block from pool
+ * Allocates a block of memory of given size, either from block pool
+ * or by calling vxge_os_dma_malloc()
+ */
+static void *__vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size,
+ struct vxge_hw_mempool_dma *dma_object)
+{
+ struct __vxge_hw_blockpool_entry *entry = NULL;
+ struct __vxge_hw_blockpool *blockpool;
+ void *memblock = NULL;
+ enum vxge_hw_status status = VXGE_HW_OK;
+
+ blockpool = &devh->block_pool;
+
+ if (size != blockpool->block_size) {
+
+ memblock = vxge_os_dma_malloc(devh->pdev, size,
+ &dma_object->handle,
+ &dma_object->acc_handle);
+
+ if (memblock == NULL) {
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto exit;
}
- }
- /* initial replenish will increment the counter in its post() routine,
- * we have to reset it */
- ring->stats->common_stats.usage_cnt = 0;
+ dma_object->addr = pci_map_single(devh->pdev, memblock, size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (unlikely(pci_dma_mapping_error(devh->pdev,
+ dma_object->addr))) {
+ vxge_os_dma_free(devh->pdev, memblock,
+ &dma_object->acc_handle);
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto exit;
+ }
+
+ } else {
+
+ if (!list_empty(&blockpool->free_block_list))
+ entry = (struct __vxge_hw_blockpool_entry *)
+ list_first_entry(&blockpool->free_block_list,
+ struct __vxge_hw_blockpool_entry,
+ item);
+
+ if (entry != NULL) {
+ list_del(&entry->item);
+ dma_object->addr = entry->dma_addr;
+ dma_object->handle = entry->dma_handle;
+ dma_object->acc_handle = entry->acc_handle;
+ memblock = entry->memblock;
+
+ list_add(&entry->item,
+ &blockpool->free_entry_list);
+ blockpool->pool_size--;
+ }
+
+ if (memblock != NULL)
+ __vxge_hw_blockpool_blocks_add(blockpool);
+ }
exit:
- return status;
+ return memblock;
}
/*
- * __vxge_hw_ring_abort - Returns the RxD
- * This function terminates the RxDs of ring
+ * __vxge_hw_blockpool_blocks_remove - Free additional blocks
*/
-static enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
+static void
+__vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
{
- void *rxdh;
- struct __vxge_hw_channel *channel;
-
- channel = &ring->channel;
+ struct list_head *p, *n;
- for (;;) {
- vxge_hw_channel_dtr_try_complete(channel, &rxdh);
+ list_for_each_safe(p, n, &blockpool->free_block_list) {
- if (rxdh == NULL)
+ if (blockpool->pool_size < blockpool->pool_max)
break;
- vxge_hw_channel_dtr_complete(channel);
+ pci_unmap_single(
+ ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+ ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
+ ((struct __vxge_hw_blockpool_entry *)p)->length,
+ PCI_DMA_BIDIRECTIONAL);
- if (ring->rxd_term)
- ring->rxd_term(rxdh, VXGE_HW_RXD_STATE_POSTED,
- channel->userdata);
+ vxge_os_dma_free(
+ ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
+ ((struct __vxge_hw_blockpool_entry *)p)->memblock,
+ &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
- vxge_hw_channel_dtr_free(channel, rxdh);
- }
+ list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
- return VXGE_HW_OK;
+ list_add(p, &blockpool->free_entry_list);
+
+ blockpool->pool_size--;
+
+ }
}
/*
- * __vxge_hw_ring_reset - Resets the ring
- * This function resets the ring during vpath reset operation
+ * __vxge_hw_blockpool_free - Frees the memory allcoated with
+ * __vxge_hw_blockpool_malloc
*/
-static enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
+static void __vxge_hw_blockpool_free(struct __vxge_hw_device *devh,
+ void *memblock, u32 size,
+ struct vxge_hw_mempool_dma *dma_object)
{
+ struct __vxge_hw_blockpool_entry *entry = NULL;
+ struct __vxge_hw_blockpool *blockpool;
enum vxge_hw_status status = VXGE_HW_OK;
- struct __vxge_hw_channel *channel;
- channel = &ring->channel;
+ blockpool = &devh->block_pool;
- __vxge_hw_ring_abort(ring);
+ if (size != blockpool->block_size) {
+ pci_unmap_single(devh->pdev, dma_object->addr, size,
+ PCI_DMA_BIDIRECTIONAL);
+ vxge_os_dma_free(devh->pdev, memblock, &dma_object->acc_handle);
+ } else {
- status = __vxge_hw_channel_reset(channel);
+ if (!list_empty(&blockpool->free_entry_list))
+ entry = (struct __vxge_hw_blockpool_entry *)
+ list_first_entry(&blockpool->free_entry_list,
+ struct __vxge_hw_blockpool_entry,
+ item);
- if (status != VXGE_HW_OK)
- goto exit;
+ if (entry == NULL)
+ entry = vmalloc(sizeof(
+ struct __vxge_hw_blockpool_entry));
+ else
+ list_del(&entry->item);
- if (ring->rxd_init) {
- status = vxge_hw_ring_replenish(ring);
- if (status != VXGE_HW_OK)
- goto exit;
+ if (entry != NULL) {
+ entry->length = size;
+ entry->memblock = memblock;
+ entry->dma_addr = dma_object->addr;
+ entry->acc_handle = dma_object->acc_handle;
+ entry->dma_handle = dma_object->handle;
+ list_add(&entry->item,
+ &blockpool->free_block_list);
+ blockpool->pool_size++;
+ status = VXGE_HW_OK;
+ } else
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+
+ if (status == VXGE_HW_OK)
+ __vxge_hw_blockpool_blocks_remove(blockpool);
}
-exit:
- return status;
}
/*
- * __vxge_hw_ring_delete - Removes the ring
- * This function freeup the memory pool and removes the ring
+ * vxge_hw_mempool_destroy
*/
-static enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
+static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
{
- struct __vxge_hw_ring *ring = vp->vpath->ringh;
+ u32 i, j;
+ struct __vxge_hw_device *devh = mempool->devh;
- __vxge_hw_ring_abort(ring);
+ for (i = 0; i < mempool->memblocks_allocated; i++) {
+ struct vxge_hw_mempool_dma *dma_object;
- if (ring->mempool)
- __vxge_hw_mempool_destroy(ring->mempool);
+ vxge_assert(mempool->memblocks_arr[i]);
+ vxge_assert(mempool->memblocks_dma_arr + i);
- vp->vpath->ringh = NULL;
- __vxge_hw_channel_free(&ring->channel);
+ dma_object = mempool->memblocks_dma_arr + i;
- return VXGE_HW_OK;
+ for (j = 0; j < mempool->items_per_memblock; j++) {
+ u32 index = i * mempool->items_per_memblock + j;
+
+ /* to skip last partially filled(if any) memblock */
+ if (index >= mempool->items_current)
+ break;
+ }
+
+ vfree(mempool->memblocks_priv_arr[i]);
+
+ __vxge_hw_blockpool_free(devh, mempool->memblocks_arr[i],
+ mempool->memblock_size, dma_object);
+ }
+
+ vfree(mempool->items_arr);
+ vfree(mempool->memblocks_dma_arr);
+ vfree(mempool->memblocks_priv_arr);
+ vfree(mempool->memblocks_arr);
+ vfree(mempool);
}
/*
@@ -1627,15 +2586,12 @@ __vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate,
* allocate new memblock and its private part at once.
* This helps to minimize memory usage a lot. */
mempool->memblocks_priv_arr[i] =
- vmalloc(mempool->items_priv_size * n_items);
+ vzalloc(mempool->items_priv_size * n_items);
if (mempool->memblocks_priv_arr[i] == NULL) {
status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto exit;
}
- memset(mempool->memblocks_priv_arr[i], 0,
- mempool->items_priv_size * n_items);
-
/* allocate DMA-capable memblock */
mempool->memblocks_arr[i] =
__vxge_hw_blockpool_malloc(mempool->devh,
@@ -1686,16 +2642,15 @@ exit:
* with size enough to hold %items_initial number of items. Memory is
* DMA-able but client must map/unmap before interoperating with the device.
*/
-static struct vxge_hw_mempool*
-__vxge_hw_mempool_create(
- struct __vxge_hw_device *devh,
- u32 memblock_size,
- u32 item_size,
- u32 items_priv_size,
- u32 items_initial,
- u32 items_max,
- struct vxge_hw_mempool_cbs *mp_callback,
- void *userdata)
+static struct vxge_hw_mempool *
+__vxge_hw_mempool_create(struct __vxge_hw_device *devh,
+ u32 memblock_size,
+ u32 item_size,
+ u32 items_priv_size,
+ u32 items_initial,
+ u32 items_max,
+ struct vxge_hw_mempool_cbs *mp_callback,
+ void *userdata)
{
enum vxge_hw_status status = VXGE_HW_OK;
u32 memblocks_to_allocate;
@@ -1707,13 +2662,11 @@ __vxge_hw_mempool_create(
goto exit;
}
- mempool = (struct vxge_hw_mempool *)
- vmalloc(sizeof(struct vxge_hw_mempool));
+ mempool = vzalloc(sizeof(struct vxge_hw_mempool));
if (mempool == NULL) {
status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto exit;
}
- memset(mempool, 0, sizeof(struct vxge_hw_mempool));
mempool->devh = devh;
mempool->memblock_size = memblock_size;
@@ -1733,53 +2686,43 @@ __vxge_hw_mempool_create(
/* allocate array of memblocks */
mempool->memblocks_arr =
- (void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+ vzalloc(sizeof(void *) * mempool->memblocks_max);
if (mempool->memblocks_arr == NULL) {
__vxge_hw_mempool_destroy(mempool);
status = VXGE_HW_ERR_OUT_OF_MEMORY;
mempool = NULL;
goto exit;
}
- memset(mempool->memblocks_arr, 0,
- sizeof(void *) * mempool->memblocks_max);
/* allocate array of private parts of items per memblocks */
mempool->memblocks_priv_arr =
- (void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+ vzalloc(sizeof(void *) * mempool->memblocks_max);
if (mempool->memblocks_priv_arr == NULL) {
__vxge_hw_mempool_destroy(mempool);
status = VXGE_HW_ERR_OUT_OF_MEMORY;
mempool = NULL;
goto exit;
}
- memset(mempool->memblocks_priv_arr, 0,
- sizeof(void *) * mempool->memblocks_max);
/* allocate array of memblocks DMA objects */
- mempool->memblocks_dma_arr = (struct vxge_hw_mempool_dma *)
- vmalloc(sizeof(struct vxge_hw_mempool_dma) *
+ mempool->memblocks_dma_arr =
+ vzalloc(sizeof(struct vxge_hw_mempool_dma) *
mempool->memblocks_max);
-
if (mempool->memblocks_dma_arr == NULL) {
__vxge_hw_mempool_destroy(mempool);
status = VXGE_HW_ERR_OUT_OF_MEMORY;
mempool = NULL;
goto exit;
}
- memset(mempool->memblocks_dma_arr, 0,
- sizeof(struct vxge_hw_mempool_dma) *
- mempool->memblocks_max);
/* allocate hash array of items */
- mempool->items_arr =
- (void **) vmalloc(sizeof(void *) * mempool->items_max);
+ mempool->items_arr = vzalloc(sizeof(void *) * mempool->items_max);
if (mempool->items_arr == NULL) {
__vxge_hw_mempool_destroy(mempool);
status = VXGE_HW_ERR_OUT_OF_MEMORY;
mempool = NULL;
goto exit;
}
- memset(mempool->items_arr, 0, sizeof(void *) * mempool->items_max);
/* calculate initial number of memblocks */
memblocks_to_allocate = (mempool->items_initial +
@@ -1801,122 +2744,188 @@ exit:
}
/*
- * vxge_hw_mempool_destroy
+ * __vxge_hw_ring_abort - Returns the RxD
+ * This function terminates the RxDs of ring
*/
-static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
+static enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
{
- u32 i, j;
- struct __vxge_hw_device *devh = mempool->devh;
-
- for (i = 0; i < mempool->memblocks_allocated; i++) {
- struct vxge_hw_mempool_dma *dma_object;
+ void *rxdh;
+ struct __vxge_hw_channel *channel;
- vxge_assert(mempool->memblocks_arr[i]);
- vxge_assert(mempool->memblocks_dma_arr + i);
+ channel = &ring->channel;
- dma_object = mempool->memblocks_dma_arr + i;
+ for (;;) {
+ vxge_hw_channel_dtr_try_complete(channel, &rxdh);
- for (j = 0; j < mempool->items_per_memblock; j++) {
- u32 index = i * mempool->items_per_memblock + j;
+ if (rxdh == NULL)
+ break;
- /* to skip last partially filled(if any) memblock */
- if (index >= mempool->items_current)
- break;
- }
+ vxge_hw_channel_dtr_complete(channel);
- vfree(mempool->memblocks_priv_arr[i]);
+ if (ring->rxd_term)
+ ring->rxd_term(rxdh, VXGE_HW_RXD_STATE_POSTED,
+ channel->userdata);
- __vxge_hw_blockpool_free(devh, mempool->memblocks_arr[i],
- mempool->memblock_size, dma_object);
+ vxge_hw_channel_dtr_free(channel, rxdh);
}
- vfree(mempool->items_arr);
+ return VXGE_HW_OK;
+}
- vfree(mempool->memblocks_dma_arr);
+/*
+ * __vxge_hw_ring_reset - Resets the ring
+ * This function resets the ring during vpath reset operation
+ */
+static enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct __vxge_hw_channel *channel;
- vfree(mempool->memblocks_priv_arr);
+ channel = &ring->channel;
- vfree(mempool->memblocks_arr);
+ __vxge_hw_ring_abort(ring);
- vfree(mempool);
+ status = __vxge_hw_channel_reset(channel);
+
+ if (status != VXGE_HW_OK)
+ goto exit;
+
+ if (ring->rxd_init) {
+ status = vxge_hw_ring_replenish(ring);
+ if (status != VXGE_HW_OK)
+ goto exit;
+ }
+exit:
+ return status;
}
/*
- * __vxge_hw_device_fifo_config_check - Check fifo configuration.
- * Check the fifo configuration
+ * __vxge_hw_ring_delete - Removes the ring
+ * This function freeup the memory pool and removes the ring
*/
-enum vxge_hw_status
-__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config)
+static enum vxge_hw_status
+__vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
{
- if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) ||
- (fifo_config->fifo_blocks > VXGE_HW_MAX_FIFO_BLOCKS))
- return VXGE_HW_BADCFG_FIFO_BLOCKS;
+ struct __vxge_hw_ring *ring = vp->vpath->ringh;
+
+ __vxge_hw_ring_abort(ring);
+
+ if (ring->mempool)
+ __vxge_hw_mempool_destroy(ring->mempool);
+
+ vp->vpath->ringh = NULL;
+ __vxge_hw_channel_free(&ring->channel);
return VXGE_HW_OK;
}
/*
- * __vxge_hw_device_vpath_config_check - Check vpath configuration.
- * Check the vpath configuration
+ * __vxge_hw_ring_create - Create a Ring
+ * This function creates Ring and initializes it.
*/
static enum vxge_hw_status
-__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config)
+__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
+ struct vxge_hw_ring_attr *attr)
{
- enum vxge_hw_status status;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct __vxge_hw_ring *ring;
+ u32 ring_length;
+ struct vxge_hw_ring_config *config;
+ struct __vxge_hw_device *hldev;
+ u32 vp_id;
+ struct vxge_hw_mempool_cbs ring_mp_callback;
- if ((vp_config->min_bandwidth < VXGE_HW_VPATH_BANDWIDTH_MIN) ||
- (vp_config->min_bandwidth >
- VXGE_HW_VPATH_BANDWIDTH_MAX))
- return VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH;
+ if ((vp == NULL) || (attr == NULL)) {
+ status = VXGE_HW_FAIL;
+ goto exit;
+ }
- status = __vxge_hw_device_fifo_config_check(&vp_config->fifo);
- if (status != VXGE_HW_OK)
- return status;
+ hldev = vp->vpath->hldev;
+ vp_id = vp->vpath->vp_id;
- if ((vp_config->mtu != VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) &&
- ((vp_config->mtu < VXGE_HW_VPATH_MIN_INITIAL_MTU) ||
- (vp_config->mtu > VXGE_HW_VPATH_MAX_INITIAL_MTU)))
- return VXGE_HW_BADCFG_VPATH_MTU;
+ config = &hldev->config.vp_config[vp_id].ring;
- if ((vp_config->rpa_strip_vlan_tag !=
- VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) &&
- (vp_config->rpa_strip_vlan_tag !=
- VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) &&
- (vp_config->rpa_strip_vlan_tag !=
- VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE))
- return VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG;
+ ring_length = config->ring_blocks *
+ vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
- return VXGE_HW_OK;
-}
+ ring = (struct __vxge_hw_ring *)__vxge_hw_channel_allocate(vp,
+ VXGE_HW_CHANNEL_TYPE_RING,
+ ring_length,
+ attr->per_rxd_space,
+ attr->userdata);
+ if (ring == NULL) {
+ status = VXGE_HW_ERR_OUT_OF_MEMORY;
+ goto exit;
+ }
-/*
- * __vxge_hw_device_config_check - Check device configuration.
- * Check the device configuration
- */
-enum vxge_hw_status
-__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config)
-{
- u32 i;
- enum vxge_hw_status status;
+ vp->vpath->ringh = ring;
+ ring->vp_id = vp_id;
+ ring->vp_reg = vp->vpath->vp_reg;
+ ring->common_reg = hldev->common_reg;
+ ring->stats = &vp->vpath->sw_stats->ring_stats;
+ ring->config = config;
+ ring->callback = attr->callback;
+ ring->rxd_init = attr->rxd_init;
+ ring->rxd_term = attr->rxd_term;
+ ring->buffer_mode = config->buffer_mode;
+ ring->rxds_limit = config->rxds_limit;
- if ((new_config->intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
- (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
- (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
- (new_config->intr_mode != VXGE_HW_INTR_MODE_DEF))
- return VXGE_HW_BADCFG_INTR_MODE;
+ ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode);
+ ring->rxd_priv_size =
+ sizeof(struct __vxge_hw_ring_rxd_priv) + attr->per_rxd_space;
+ ring->per_rxd_space = attr->per_rxd_space;
- if ((new_config->rts_mac_en != VXGE_HW_RTS_MAC_DISABLE) &&
- (new_config->rts_mac_en != VXGE_HW_RTS_MAC_ENABLE))
- return VXGE_HW_BADCFG_RTS_MAC_EN;
+ ring->rxd_priv_size =
+ ((ring->rxd_priv_size + VXGE_CACHE_LINE_SIZE - 1) /
+ VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
- for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
- status = __vxge_hw_device_vpath_config_check(
- &new_config->vp_config[i]);
- if (status != VXGE_HW_OK)
- return status;
+ /* how many RxDs can fit into one block. Depends on configured
+ * buffer_mode. */
+ ring->rxds_per_block =
+ vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+
+ /* calculate actual RxD block private size */
+ ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
+ ring_mp_callback.item_func_alloc = __vxge_hw_ring_mempool_item_alloc;
+ ring->mempool = __vxge_hw_mempool_create(hldev,
+ VXGE_HW_BLOCK_SIZE,
+ VXGE_HW_BLOCK_SIZE,
+ ring->rxdblock_priv_size,
+ ring->config->ring_blocks,
+ ring->config->ring_blocks,
+ &ring_mp_callback,
+ ring);
+ if (ring->mempool == NULL) {
+ __vxge_hw_ring_delete(vp);
+ return VXGE_HW_ERR_OUT_OF_MEMORY;
}
- return VXGE_HW_OK;
+ status = __vxge_hw_channel_initialize(&ring->channel);
+ if (status != VXGE_HW_OK) {
+ __vxge_hw_ring_delete(vp);
+ goto exit;
+ }
+
+ /* Note:
+ * Specifying rxd_init callback means two things:
+ * 1) rxds need to be initialized by driver at channel-open time;
+ * 2) rxds need to be posted at channel-open time
+ * (that's what the initial_replenish() below does)
+ * Currently we don't have a case when the 1) is done without the 2).
+ */
+ if (ring->rxd_init) {
+ status = vxge_hw_ring_replenish(ring);
+ if (status != VXGE_HW_OK) {
+ __vxge_hw_ring_delete(vp);
+ goto exit;
+ }
+ }
+
+ /* initial replenish will increment the counter in its post() routine,
+ * we have to reset it */
+ ring->stats->common_stats.usage_cnt = 0;
+exit:
+ return status;
}
/*
@@ -1938,7 +2947,6 @@ vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config)
device_config->rts_mac_en = VXGE_HW_RTS_MAC_DEFAULT;
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
device_config->vp_config[i].vp_id = i;
device_config->vp_config[i].min_bandwidth =
@@ -2078,61 +3086,6 @@ vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config)
}
/*
- * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
- * Set the swapper bits appropriately for the lagacy section.
- */
-static enum vxge_hw_status
-__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
-{
- u64 val64;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- val64 = readq(&legacy_reg->toc_swapper_fb);
-
- wmb();
-
- switch (val64) {
-
- case VXGE_HW_SWAPPER_INITIAL_VALUE:
- return status;
-
- case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED:
- writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
- &legacy_reg->pifm_rd_swap_en);
- writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
- &legacy_reg->pifm_rd_flip_en);
- writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
- &legacy_reg->pifm_wr_swap_en);
- writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
- &legacy_reg->pifm_wr_flip_en);
- break;
-
- case VXGE_HW_SWAPPER_BYTE_SWAPPED:
- writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
- &legacy_reg->pifm_rd_swap_en);
- writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
- &legacy_reg->pifm_wr_swap_en);
- break;
-
- case VXGE_HW_SWAPPER_BIT_FLIPPED:
- writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
- &legacy_reg->pifm_rd_flip_en);
- writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
- &legacy_reg->pifm_wr_flip_en);
- break;
- }
-
- wmb();
-
- val64 = readq(&legacy_reg->toc_swapper_fb);
-
- if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE)
- status = VXGE_HW_ERR_SWAPPER_CTRL;
-
- return status;
-}
-
-/*
* __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath.
* Set the swapper bits appropriately for the vpath.
*/
@@ -2156,9 +3109,8 @@ __vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
* Set the swapper bits appropriately for the vpath.
*/
static enum vxge_hw_status
-__vxge_hw_kdfc_swapper_set(
- struct vxge_hw_legacy_reg __iomem *legacy_reg,
- struct vxge_hw_vpath_reg __iomem *vpath_reg)
+__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg,
+ struct vxge_hw_vpath_reg __iomem *vpath_reg)
{
u64 val64;
@@ -2408,6 +3360,69 @@ exit:
}
/*
+ * __vxge_hw_fifo_abort - Returns the TxD
+ * This function terminates the TxDs of fifo
+ */
+static enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
+{
+ void *txdlh;
+
+ for (;;) {
+ vxge_hw_channel_dtr_try_complete(&fifo->channel, &txdlh);
+
+ if (txdlh == NULL)
+ break;
+
+ vxge_hw_channel_dtr_complete(&fifo->channel);
+
+ if (fifo->txdl_term) {
+ fifo->txdl_term(txdlh,
+ VXGE_HW_TXDL_STATE_POSTED,
+ fifo->channel.userdata);
+ }
+
+ vxge_hw_channel_dtr_free(&fifo->channel, txdlh);
+ }
+
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_fifo_reset - Resets the fifo
+ * This function resets the fifo during vpath reset operation
+ */
+static enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+
+ __vxge_hw_fifo_abort(fifo);
+ status = __vxge_hw_channel_reset(&fifo->channel);
+
+ return status;
+}
+
+/*
+ * __vxge_hw_fifo_delete - Removes the FIFO
+ * This function freeup the memory pool and removes the FIFO
+ */
+static enum vxge_hw_status
+__vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp)
+{
+ struct __vxge_hw_fifo *fifo = vp->vpath->fifoh;
+
+ __vxge_hw_fifo_abort(fifo);
+
+ if (fifo->mempool)
+ __vxge_hw_mempool_destroy(fifo->mempool);
+
+ vp->vpath->fifoh = NULL;
+
+ __vxge_hw_channel_free(&fifo->channel);
+
+ return VXGE_HW_OK;
+}
+
+/*
* __vxge_hw_fifo_mempool_item_alloc - Allocate List blocks for TxD
* list callback
* This function is callback passed to __vxge_hw_mempool_create to create memory
@@ -2453,7 +3468,7 @@ __vxge_hw_fifo_mempool_item_alloc(
* __vxge_hw_fifo_create - Create a FIFO
* This function creates FIFO and initializes it.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp,
struct vxge_hw_fifo_attr *attr)
{
@@ -2572,68 +3587,6 @@ exit:
}
/*
- * __vxge_hw_fifo_abort - Returns the TxD
- * This function terminates the TxDs of fifo
- */
-static enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
-{
- void *txdlh;
-
- for (;;) {
- vxge_hw_channel_dtr_try_complete(&fifo->channel, &txdlh);
-
- if (txdlh == NULL)
- break;
-
- vxge_hw_channel_dtr_complete(&fifo->channel);
-
- if (fifo->txdl_term) {
- fifo->txdl_term(txdlh,
- VXGE_HW_TXDL_STATE_POSTED,
- fifo->channel.userdata);
- }
-
- vxge_hw_channel_dtr_free(&fifo->channel, txdlh);
- }
-
- return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_fifo_reset - Resets the fifo
- * This function resets the fifo during vpath reset operation
- */
-static enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
-
- __vxge_hw_fifo_abort(fifo);
- status = __vxge_hw_channel_reset(&fifo->channel);
-
- return status;
-}
-
-/*
- * __vxge_hw_fifo_delete - Removes the FIFO
- * This function freeup the memory pool and removes the FIFO
- */
-enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp)
-{
- struct __vxge_hw_fifo *fifo = vp->vpath->fifoh;
-
- __vxge_hw_fifo_abort(fifo);
-
- if (fifo->mempool)
- __vxge_hw_mempool_destroy(fifo->mempool);
-
- vp->vpath->fifoh = NULL;
-
- __vxge_hw_channel_free(&fifo->channel);
-
- return VXGE_HW_OK;
-}
-
-/*
* __vxge_hw_vpath_pci_read - Read the content of given address
* in pci config space.
* Read from the vpath pci config space.
@@ -2675,297 +3628,6 @@ exit:
return status;
}
-/*
- * __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
- * Returns the function number of the vpath.
- */
-static u32
-__vxge_hw_vpath_func_id_get(u32 vp_id,
- struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
-{
- u64 val64;
-
- val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1);
-
- return
- (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64);
-}
-
-/*
- * __vxge_hw_read_rts_ds - Program RTS steering critieria
- */
-static inline void
-__vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg,
- u64 dta_struct_sel)
-{
- writeq(0, &vpath_reg->rts_access_steer_ctrl);
- wmb();
- writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0);
- writeq(0, &vpath_reg->rts_access_steer_data1);
- wmb();
-}
-
-
-/*
- * __vxge_hw_vpath_card_info_get - Get the serial numbers,
- * part number and product description.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_card_info_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info)
-{
- u32 i, j;
- u64 val64;
- u64 data1 = 0ULL;
- u64 data2 = 0ULL;
- enum vxge_hw_status status = VXGE_HW_OK;
- u8 *serial_number = hw_info->serial_number;
- u8 *part_number = hw_info->part_number;
- u8 *product_desc = hw_info->product_desc;
-
- __vxge_hw_read_rts_ds(vpath_reg,
- VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER);
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- return status;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- ((u64 *)serial_number)[0] = be64_to_cpu(data1);
-
- data2 = readq(&vpath_reg->rts_access_steer_data1);
- ((u64 *)serial_number)[1] = be64_to_cpu(data2);
- status = VXGE_HW_OK;
- } else
- *serial_number = 0;
-
- __vxge_hw_read_rts_ds(vpath_reg,
- VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER);
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- return status;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
-
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- ((u64 *)part_number)[0] = be64_to_cpu(data1);
-
- data2 = readq(&vpath_reg->rts_access_steer_data1);
- ((u64 *)part_number)[1] = be64_to_cpu(data2);
-
- status = VXGE_HW_OK;
-
- } else
- *part_number = 0;
-
- j = 0;
-
- for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0;
- i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) {
-
- __vxge_hw_read_rts_ds(vpath_reg, i);
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- return status;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
-
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- ((u64 *)product_desc)[j++] = be64_to_cpu(data1);
-
- data2 = readq(&vpath_reg->rts_access_steer_data1);
- ((u64 *)product_desc)[j++] = be64_to_cpu(data2);
-
- status = VXGE_HW_OK;
- } else
- *product_desc = 0;
- }
-
- return status;
-}
-
-/*
- * __vxge_hw_vpath_fw_ver_get - Get the fw version
- * Returns FW Version
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_fw_ver_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info)
-{
- u64 val64;
- u64 data1 = 0ULL;
- u64 data2 = 0ULL;
- struct vxge_hw_device_version *fw_version = &hw_info->fw_version;
- struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
- struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
- struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- goto exit;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
-
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- data2 = readq(&vpath_reg->rts_access_steer_data1);
-
- fw_date->day =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(
- data1);
- fw_date->month =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(
- data1);
- fw_date->year =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(
- data1);
-
- snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
- fw_date->month, fw_date->day, fw_date->year);
-
- fw_version->major =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data1);
- fw_version->minor =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data1);
- fw_version->build =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data1);
-
- snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
- fw_version->major, fw_version->minor, fw_version->build);
-
- flash_date->day =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data2);
- flash_date->month =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data2);
- flash_date->year =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data2);
-
- snprintf(flash_date->date, VXGE_HW_FW_STRLEN,
- "%2.2d/%2.2d/%4.4d",
- flash_date->month, flash_date->day, flash_date->year);
-
- flash_version->major =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data2);
- flash_version->minor =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data2);
- flash_version->build =
- (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data2);
-
- snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
- flash_version->major, flash_version->minor,
- flash_version->build);
-
- status = VXGE_HW_OK;
-
- } else
- status = VXGE_HW_FAIL;
-exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode
- * Returns pci function mode
- */
-static u64
-__vxge_hw_vpath_pci_func_mode_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg)
-{
- u64 val64;
- u64 data1 = 0ULL;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- __vxge_hw_read_rts_ds(vpath_reg,
- VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE);
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- goto exit;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- status = VXGE_HW_OK;
- } else {
- data1 = 0;
- status = VXGE_HW_FAIL;
- }
-exit:
- return data1;
-}
-
/**
* vxge_hw_device_flick_link_led - Flick (blink) link LED.
* @hldev: HW device.
@@ -2974,37 +3636,24 @@ exit:
* Flicker the link LED.
*/
enum vxge_hw_status
-vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev,
- u64 on_off)
+vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev, u64 on_off)
{
- u64 val64;
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
+ struct __vxge_hw_virtualpath *vpath;
+ u64 data0, data1 = 0, steer_ctrl = 0;
+ enum vxge_hw_status status;
if (hldev == NULL) {
status = VXGE_HW_ERR_INVALID_DEVICE;
goto exit;
}
- vp_reg = hldev->vpath_reg[hldev->first_vp_id];
+ vpath = &hldev->virtual_paths[hldev->first_vp_id];
- writeq(0, &vp_reg->rts_access_steer_ctrl);
- wmb();
- writeq(on_off, &vp_reg->rts_access_steer_data0);
- writeq(0, &vp_reg->rts_access_steer_data1);
- wmb();
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vp_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+ data0 = on_off;
+ status = vxge_hw_vpath_fw_api(vpath,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL,
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
+ 0, &data0, &data1, &steer_ctrl);
exit:
return status;
}
@@ -3013,63 +3662,38 @@ exit:
* __vxge_hw_vpath_rts_table_get - Get the entries from RTS access tables
*/
enum vxge_hw_status
-__vxge_hw_vpath_rts_table_get(
- struct __vxge_hw_vpath_handle *vp,
- u32 action, u32 rts_table, u32 offset, u64 *data1, u64 *data2)
+__vxge_hw_vpath_rts_table_get(struct __vxge_hw_vpath_handle *vp,
+ u32 action, u32 rts_table, u32 offset,
+ u64 *data0, u64 *data1)
{
- u64 val64;
- struct __vxge_hw_virtualpath *vpath;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
-
- enum vxge_hw_status status = VXGE_HW_OK;
+ enum vxge_hw_status status;
+ u64 steer_ctrl = 0;
if (vp == NULL) {
status = VXGE_HW_ERR_INVALID_HANDLE;
goto exit;
}
- vpath = vp->vpath;
- vp_reg = vpath->vp_reg;
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset);
-
if ((rts_table ==
- VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) ||
+ VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) ||
(rts_table ==
- VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) ||
+ VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) ||
(rts_table ==
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) ||
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) ||
(rts_table ==
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) {
- val64 = val64 | VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL;
+ VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) {
+ steer_ctrl = VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL;
}
- status = __vxge_hw_pio_mem_write64(val64,
- &vp_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- vpath->hldev->config.device_poll_millis);
-
+ status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset,
+ data0, data1, &steer_ctrl);
if (status != VXGE_HW_OK)
goto exit;
- val64 = readq(&vp_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
-
- *data1 = readq(&vp_reg->rts_access_steer_data0);
-
- if ((rts_table ==
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
- (rts_table ==
- VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) {
- *data2 = readq(&vp_reg->rts_access_steer_data1);
- }
- status = VXGE_HW_OK;
- } else
- status = VXGE_HW_FAIL;
+ if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
+ (rts_table !=
+ VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
+ *data1 = 0;
exit:
return status;
}
@@ -3078,107 +3702,27 @@ exit:
* __vxge_hw_vpath_rts_table_set - Set the entries of RTS access tables
*/
enum vxge_hw_status
-__vxge_hw_vpath_rts_table_set(
- struct __vxge_hw_vpath_handle *vp, u32 action, u32 rts_table,
- u32 offset, u64 data1, u64 data2)
+__vxge_hw_vpath_rts_table_set(struct __vxge_hw_vpath_handle *vp, u32 action,
+ u32 rts_table, u32 offset, u64 steer_data0,
+ u64 steer_data1)
{
- u64 val64;
- struct __vxge_hw_virtualpath *vpath;
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
+ u64 data0, data1 = 0, steer_ctrl = 0;
+ enum vxge_hw_status status;
if (vp == NULL) {
status = VXGE_HW_ERR_INVALID_HANDLE;
goto exit;
}
- vpath = vp->vpath;
- vp_reg = vpath->vp_reg;
-
- writeq(data1, &vp_reg->rts_access_steer_data0);
- wmb();
+ data0 = steer_data0;
if ((rts_table == VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
(rts_table ==
- VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) {
- writeq(data2, &vp_reg->rts_access_steer_data1);
- wmb();
- }
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vp_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- vpath->hldev->config.device_poll_millis);
-
- if (status != VXGE_HW_OK)
- goto exit;
-
- val64 = readq(&vp_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS)
- status = VXGE_HW_OK;
- else
- status = VXGE_HW_FAIL;
-exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
- * from MAC address table.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_addr_get(
- u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
- u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN])
-{
- u32 i;
- u64 val64;
- u64 data1 = 0ULL;
- u64 data2 = 0ULL;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
- VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vpath_reg->rts_access_steer_ctrl,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
- VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
- if (status != VXGE_HW_OK)
- goto exit;
-
- val64 = readq(&vpath_reg->rts_access_steer_ctrl);
-
- if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
+ VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
+ data1 = steer_data1;
- data1 = readq(&vpath_reg->rts_access_steer_data0);
- data2 = readq(&vpath_reg->rts_access_steer_data1);
-
- data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
- data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(
- data2);
-
- for (i = ETH_ALEN; i > 0; i--) {
- macaddr[i-1] = (u8)(data1 & 0xFF);
- data1 >>= 8;
-
- macaddr_mask[i-1] = (u8)(data2 & 0xFF);
- data2 >>= 8;
- }
- status = VXGE_HW_OK;
- } else
- status = VXGE_HW_FAIL;
+ status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset,
+ &data0, &data1, &steer_ctrl);
exit:
return status;
}
@@ -3204,6 +3748,8 @@ enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY,
VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG,
0, &data0, &data1);
+ if (status != VXGE_HW_OK)
+ goto exit;
data0 &= ~(VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(0xf) |
VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(0x3));
@@ -3771,10 +4317,10 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
vp_reg = vpath->vp_reg;
config = vpath->vp_config;
- writeq((u64)0, &vp_reg->tim_dest_addr);
- writeq((u64)0, &vp_reg->tim_vpath_map);
- writeq((u64)0, &vp_reg->tim_bitmap);
- writeq((u64)0, &vp_reg->tim_remap);
+ writeq(0, &vp_reg->tim_dest_addr);
+ writeq(0, &vp_reg->tim_vpath_map);
+ writeq(0, &vp_reg->tim_bitmap);
+ writeq(0, &vp_reg->tim_remap);
if (config->ring.enable == VXGE_HW_RING_ENABLE)
writeq(VXGE_HW_TIM_RING_ASSN_INT_NUM(
@@ -3876,8 +4422,7 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
if (config->tti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
- val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
- config->tti.util_sel);
+ val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(vp_id);
}
if (config->tti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
@@ -3981,8 +4526,7 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
if (config->rti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
- val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(
- config->rti.util_sel);
+ val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(vp_id);
}
if (config->rti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
@@ -4003,11 +4547,15 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_BMAP]);
writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_BMAP]);
+ val64 = VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(150);
+ val64 |= VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(0);
+ val64 |= VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(3);
+ writeq(val64, &vp_reg->tim_wrkld_clc);
+
return status;
}
-void
-vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
+void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
{
struct __vxge_hw_virtualpath *vpath;
struct vxge_hw_vpath_reg __iomem *vp_reg;
@@ -4018,17 +4566,15 @@ vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
vp_reg = vpath->vp_reg;
config = vpath->vp_config;
- if (config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
+ if (config->fifo.enable == VXGE_HW_FIFO_ENABLE &&
+ config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) {
+ config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE;
val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
-
- if (config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) {
- config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE;
- val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
- writeq(val64,
- &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
- }
+ val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+ writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
}
}
+
/*
* __vxge_hw_vpath_initialize
* This routine is the final phase of init which initializes the
@@ -4052,22 +4598,18 @@ __vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
vp_reg = vpath->vp_reg;
status = __vxge_hw_vpath_swapper_set(vpath->vp_reg);
-
if (status != VXGE_HW_OK)
goto exit;
status = __vxge_hw_vpath_mac_configure(hldev, vp_id);
-
if (status != VXGE_HW_OK)
goto exit;
status = __vxge_hw_vpath_kdfc_configure(hldev, vp_id);
-
if (status != VXGE_HW_OK)
goto exit;
status = __vxge_hw_vpath_tim_configure(hldev, vp_id);
-
if (status != VXGE_HW_OK)
goto exit;
@@ -4075,7 +4617,6 @@ __vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
/* Get MRRS value from device control */
status = __vxge_hw_vpath_pci_read(vpath, 1, 0x78, &val32);
-
if (status == VXGE_HW_OK) {
val32 = (val32 & VXGE_HW_PCI_EXP_DEVCTL_READRQ) >> 12;
val64 &=
@@ -4099,6 +4640,28 @@ exit:
}
/*
+ * __vxge_hw_vp_terminate - Terminate Virtual Path structure
+ * This routine closes all channels it opened and freeup memory
+ */
+static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+ struct __vxge_hw_virtualpath *vpath;
+
+ vpath = &hldev->virtual_paths[vp_id];
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN)
+ goto exit;
+
+ VXGE_HW_DEVICE_TIM_INT_MASK_RESET(vpath->hldev->tim_int_mask0,
+ vpath->hldev->tim_int_mask1, vpath->vp_id);
+ hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL;
+
+ memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+exit:
+ return;
+}
+
+/*
* __vxge_hw_vp_initialize - Initialize Virtual Path structure
* This routine is the initial phase of init which resets the vpath and
* initializes the software support structures.
@@ -4117,6 +4680,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
vpath = &hldev->virtual_paths[vp_id];
+ spin_lock_init(&hldev->virtual_paths[vp_id].lock);
vpath->vp_id = vp_id;
vpath->vp_open = VXGE_HW_VP_OPEN;
vpath->hldev = hldev;
@@ -4127,14 +4691,12 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
__vxge_hw_vpath_reset(hldev, vp_id);
status = __vxge_hw_vpath_reset_check(vpath);
-
if (status != VXGE_HW_OK) {
memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
goto exit;
}
status = __vxge_hw_vpath_mgmt_read(hldev, vpath);
-
if (status != VXGE_HW_OK) {
memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
goto exit;
@@ -4148,7 +4710,6 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
hldev->tim_int_mask1, vp_id);
status = __vxge_hw_vpath_initialize(hldev, vp_id);
-
if (status != VXGE_HW_OK)
__vxge_hw_vp_terminate(hldev, vp_id);
exit:
@@ -4156,29 +4717,6 @@ exit:
}
/*
- * __vxge_hw_vp_terminate - Terminate Virtual Path structure
- * This routine closes all channels it opened and freeup memory
- */
-static void
-__vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
-{
- struct __vxge_hw_virtualpath *vpath;
-
- vpath = &hldev->virtual_paths[vp_id];
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN)
- goto exit;
-
- VXGE_HW_DEVICE_TIM_INT_MASK_RESET(vpath->hldev->tim_int_mask0,
- vpath->hldev->tim_int_mask1, vpath->vp_id);
- hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL;
-
- memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
-exit:
- return;
-}
-
-/*
* vxge_hw_vpath_mtu_set - Set MTU.
* Set new MTU value. Example, to use jumbo frames:
* vxge_hw_vpath_mtu_set(my_device, 9600);
@@ -4215,6 +4753,64 @@ exit:
}
/*
+ * vxge_hw_vpath_stats_enable - Enable vpath h/wstatistics.
+ * Enable the DMA vpath statistics. The function is to be called to re-enable
+ * the adapter to update stats into the host memory
+ */
+static enum vxge_hw_status
+vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct __vxge_hw_virtualpath *vpath;
+
+ vpath = vp->vpath;
+
+ if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
+ status = VXGE_HW_ERR_VPATH_NOT_OPEN;
+ goto exit;
+ }
+
+ memcpy(vpath->hw_stats_sav, vpath->hw_stats,
+ sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+ status = __vxge_hw_vpath_stats_get(vpath, vpath->hw_stats);
+exit:
+ return status;
+}
+
+/*
+ * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool
+ * This function allocates a block from block pool or from the system
+ */
+static struct __vxge_hw_blockpool_entry *
+__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size)
+{
+ struct __vxge_hw_blockpool_entry *entry = NULL;
+ struct __vxge_hw_blockpool *blockpool;
+
+ blockpool = &devh->block_pool;
+
+ if (size == blockpool->block_size) {
+
+ if (!list_empty(&blockpool->free_block_list))
+ entry = (struct __vxge_hw_blockpool_entry *)
+ list_first_entry(&blockpool->free_block_list,
+ struct __vxge_hw_blockpool_entry,
+ item);
+
+ if (entry != NULL) {
+ list_del(&entry->item);
+ blockpool->pool_size--;
+ }
+ }
+
+ if (entry != NULL)
+ __vxge_hw_blockpool_blocks_add(blockpool);
+
+ return entry;
+}
+
+/*
* vxge_hw_vpath_open - Open a virtual path on a given adapter
* This function is used to open access to virtual path of an
* adapter for offload, GRO operations. This function returns
@@ -4238,19 +4834,15 @@ vxge_hw_vpath_open(struct __vxge_hw_device *hldev,
status = __vxge_hw_vp_initialize(hldev, attr->vp_id,
&hldev->config.vp_config[attr->vp_id]);
-
if (status != VXGE_HW_OK)
goto vpath_open_exit1;
- vp = (struct __vxge_hw_vpath_handle *)
- vmalloc(sizeof(struct __vxge_hw_vpath_handle));
+ vp = vzalloc(sizeof(struct __vxge_hw_vpath_handle));
if (vp == NULL) {
status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto vpath_open_exit2;
}
- memset(vp, 0, sizeof(struct __vxge_hw_vpath_handle));
-
vp->vpath = vpath;
if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
@@ -4273,7 +4865,6 @@ vxge_hw_vpath_open(struct __vxge_hw_device *hldev,
vpath->stats_block = __vxge_hw_blockpool_block_allocate(hldev,
VXGE_HW_BLOCK_SIZE);
-
if (vpath->stats_block == NULL) {
status = VXGE_HW_ERR_OUT_OF_MEMORY;
goto vpath_open_exit8;
@@ -4332,19 +4923,20 @@ vpath_open_exit1:
* This function is used to close access to virtual path opened
* earlier.
*/
-void
-vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp)
+void vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp)
{
- struct __vxge_hw_virtualpath *vpath = NULL;
+ struct __vxge_hw_virtualpath *vpath = vp->vpath;
+ struct __vxge_hw_ring *ring = vpath->ringh;
+ struct vxgedev *vdev = netdev_priv(vpath->hldev->ndev);
u64 new_count, val64, val164;
- struct __vxge_hw_ring *ring;
- vpath = vp->vpath;
- ring = vpath->ringh;
+ if (vdev->titan1) {
+ new_count = readq(&vpath->vp_reg->rxdmem_size);
+ new_count &= 0x1fff;
+ } else
+ new_count = ring->config->ring_blocks * VXGE_HW_BLOCK_SIZE / 8;
- new_count = readq(&vpath->vp_reg->rxdmem_size);
- new_count &= 0x1fff;
- val164 = (VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count));
+ val164 = VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count);
writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val164),
&vpath->vp_reg->prc_rxd_doorbell);
@@ -4367,6 +4959,29 @@ vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp)
}
/*
+ * __vxge_hw_blockpool_block_free - Frees a block from block pool
+ * @devh: Hal device
+ * @entry: Entry of block to be freed
+ *
+ * This function frees a block from block pool
+ */
+static void
+__vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh,
+ struct __vxge_hw_blockpool_entry *entry)
+{
+ struct __vxge_hw_blockpool *blockpool;
+
+ blockpool = &devh->block_pool;
+
+ if (entry->length == blockpool->block_size) {
+ list_add(&entry->item, &blockpool->free_block_list);
+ blockpool->pool_size++;
+ }
+
+ __vxge_hw_blockpool_blocks_remove(blockpool);
+}
+
+/*
* vxge_hw_vpath_close - Close the handle got from previous vpath (vpath) open
* This function is used to close access to virtual path opened
* earlier.
@@ -4414,7 +5029,9 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp)
__vxge_hw_vp_terminate(devh, vp_id);
+ spin_lock(&vpath->lock);
vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
+ spin_unlock(&vpath->lock);
vpath_close_exit:
return status;
@@ -4515,730 +5132,3 @@ vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp)
__vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
&hldev->common_reg->cmn_rsthdlr_cfg1);
}
-
-/*
- * vxge_hw_vpath_stats_enable - Enable vpath h/wstatistics.
- * Enable the DMA vpath statistics. The function is to be called to re-enable
- * the adapter to update stats into the host memory
- */
-static enum vxge_hw_status
-vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct __vxge_hw_virtualpath *vpath;
-
- vpath = vp->vpath;
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
- status = VXGE_HW_ERR_VPATH_NOT_OPEN;
- goto exit;
- }
-
- memcpy(vpath->hw_stats_sav, vpath->hw_stats,
- sizeof(struct vxge_hw_vpath_stats_hw_info));
-
- status = __vxge_hw_vpath_stats_get(vpath, vpath->hw_stats);
-exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_stats_access - Get the statistics from the given location
- * and offset and perform an operation
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
- u32 operation, u32 offset, u64 *stat)
-{
- u64 val64;
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
- status = VXGE_HW_ERR_VPATH_NOT_OPEN;
- goto vpath_stats_access_exit;
- }
-
- vp_reg = vpath->vp_reg;
-
- val64 = VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(operation) |
- VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE |
- VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(offset);
-
- status = __vxge_hw_pio_mem_write64(val64,
- &vp_reg->xmac_stats_access_cmd,
- VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE,
- vpath->hldev->config.device_poll_millis);
-
- if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
- *stat = readq(&vp_reg->xmac_stats_access_data);
- else
- *stat = 0;
-
-vpath_stats_access_exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_tx_stats_get(
- struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats)
-{
- u64 *val64;
- int i;
- u32 offset = VXGE_HW_STATS_VPATH_TX_OFFSET;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- val64 = (u64 *) vpath_tx_stats;
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
- status = VXGE_HW_ERR_VPATH_NOT_OPEN;
- goto exit;
- }
-
- for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_tx_stats) / 8; i++) {
- status = __vxge_hw_vpath_stats_access(vpath,
- VXGE_HW_STATS_OP_READ,
- offset, val64);
- if (status != VXGE_HW_OK)
- goto exit;
- offset++;
- val64++;
- }
-exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
-{
- u64 *val64;
- enum vxge_hw_status status = VXGE_HW_OK;
- int i;
- u32 offset = VXGE_HW_STATS_VPATH_RX_OFFSET;
- val64 = (u64 *) vpath_rx_stats;
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
- status = VXGE_HW_ERR_VPATH_NOT_OPEN;
- goto exit;
- }
- for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_rx_stats) / 8; i++) {
- status = __vxge_hw_vpath_stats_access(vpath,
- VXGE_HW_STATS_OP_READ,
- offset >> 3, val64);
- if (status != VXGE_HW_OK)
- goto exit;
-
- offset += 8;
- val64++;
- }
-exit:
- return status;
-}
-
-/*
- * __vxge_hw_vpath_stats_get - Get the vpath hw statistics.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_vpath_stats_hw_info *hw_stats)
-{
- u64 val64;
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
-
- if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
- status = VXGE_HW_ERR_VPATH_NOT_OPEN;
- goto exit;
- }
- vp_reg = vpath->vp_reg;
-
- val64 = readq(&vp_reg->vpath_debug_stats0);
- hw_stats->ini_num_mwr_sent =
- (u32)VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats1);
- hw_stats->ini_num_mrd_sent =
- (u32)VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats2);
- hw_stats->ini_num_cpl_rcvd =
- (u32)VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats3);
- hw_stats->ini_num_mwr_byte_sent =
- VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats4);
- hw_stats->ini_num_cpl_byte_rcvd =
- VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats5);
- hw_stats->wrcrdtarb_xoff =
- (u32)VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(val64);
-
- val64 = readq(&vp_reg->vpath_debug_stats6);
- hw_stats->rdcrdtarb_xoff =
- (u32)VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count01);
- hw_stats->vpath_genstats_count0 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(
- val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count01);
- hw_stats->vpath_genstats_count1 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(
- val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count23);
- hw_stats->vpath_genstats_count2 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(
- val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count01);
- hw_stats->vpath_genstats_count3 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(
- val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count4);
- hw_stats->vpath_genstats_count4 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(
- val64);
-
- val64 = readq(&vp_reg->vpath_genstats_count5);
- hw_stats->vpath_genstats_count5 =
- (u32)VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(
- val64);
-
- status = __vxge_hw_vpath_xmac_tx_stats_get(vpath, &hw_stats->tx_stats);
- if (status != VXGE_HW_OK)
- goto exit;
-
- status = __vxge_hw_vpath_xmac_rx_stats_get(vpath, &hw_stats->rx_stats);
- if (status != VXGE_HW_OK)
- goto exit;
-
- VXGE_HW_VPATH_STATS_PIO_READ(
- VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET);
-
- hw_stats->prog_event_vnum0 =
- (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(val64);
-
- hw_stats->prog_event_vnum1 =
- (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(val64);
-
- VXGE_HW_VPATH_STATS_PIO_READ(
- VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET);
-
- hw_stats->prog_event_vnum2 =
- (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(val64);
-
- hw_stats->prog_event_vnum3 =
- (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(val64);
-
- val64 = readq(&vp_reg->rx_multi_cast_stats);
- hw_stats->rx_multi_cast_frame_discard =
- (u16)VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(val64);
-
- val64 = readq(&vp_reg->rx_frm_transferred);
- hw_stats->rx_frm_transferred =
- (u32)VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(val64);
-
- val64 = readq(&vp_reg->rxd_returned);
- hw_stats->rxd_returned =
- (u16)VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(val64);
-
- val64 = readq(&vp_reg->dbg_stats_rx_mpa);
- hw_stats->rx_mpa_len_fail_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(val64);
- hw_stats->rx_mpa_mrk_fail_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(val64);
- hw_stats->rx_mpa_crc_fail_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(val64);
-
- val64 = readq(&vp_reg->dbg_stats_rx_fau);
- hw_stats->rx_permitted_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(val64);
- hw_stats->rx_vp_reset_discarded_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val64);
- hw_stats->rx_wol_frms =
- (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(val64);
-
- val64 = readq(&vp_reg->tx_vp_reset_discarded_frms);
- hw_stats->tx_vp_reset_discarded_frms =
- (u16)VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(
- val64);
-exit:
- return status;
-}
-
-
-static void vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh,
- unsigned long size)
-{
- gfp_t flags;
- void *vaddr;
-
- if (in_interrupt())
- flags = GFP_ATOMIC | GFP_DMA;
- else
- flags = GFP_KERNEL | GFP_DMA;
-
- vaddr = kmalloc((size), flags);
-
- vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
-}
-
-static void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
- struct pci_dev **p_dma_acch)
-{
- unsigned long misaligned = *(unsigned long *)p_dma_acch;
- u8 *tmp = (u8 *)vaddr;
- tmp -= misaligned;
- kfree((void *)tmp);
-}
-
-/*
- * __vxge_hw_blockpool_create - Create block pool
- */
-
-enum vxge_hw_status
-__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
- struct __vxge_hw_blockpool *blockpool,
- u32 pool_size,
- u32 pool_max)
-{
- u32 i;
- struct __vxge_hw_blockpool_entry *entry = NULL;
- void *memblock;
- dma_addr_t dma_addr;
- struct pci_dev *dma_handle;
- struct pci_dev *acc_handle;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- if (blockpool == NULL) {
- status = VXGE_HW_FAIL;
- goto blockpool_create_exit;
- }
-
- blockpool->hldev = hldev;
- blockpool->block_size = VXGE_HW_BLOCK_SIZE;
- blockpool->pool_size = 0;
- blockpool->pool_max = pool_max;
- blockpool->req_out = 0;
-
- INIT_LIST_HEAD(&blockpool->free_block_list);
- INIT_LIST_HEAD(&blockpool->free_entry_list);
-
- for (i = 0; i < pool_size + pool_max; i++) {
- entry = kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
- GFP_KERNEL);
- if (entry == NULL) {
- __vxge_hw_blockpool_destroy(blockpool);
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto blockpool_create_exit;
- }
- list_add(&entry->item, &blockpool->free_entry_list);
- }
-
- for (i = 0; i < pool_size; i++) {
-
- memblock = vxge_os_dma_malloc(
- hldev->pdev,
- VXGE_HW_BLOCK_SIZE,
- &dma_handle,
- &acc_handle);
-
- if (memblock == NULL) {
- __vxge_hw_blockpool_destroy(blockpool);
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto blockpool_create_exit;
- }
-
- dma_addr = pci_map_single(hldev->pdev, memblock,
- VXGE_HW_BLOCK_SIZE, PCI_DMA_BIDIRECTIONAL);
-
- if (unlikely(pci_dma_mapping_error(hldev->pdev,
- dma_addr))) {
-
- vxge_os_dma_free(hldev->pdev, memblock, &acc_handle);
- __vxge_hw_blockpool_destroy(blockpool);
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto blockpool_create_exit;
- }
-
- if (!list_empty(&blockpool->free_entry_list))
- entry = (struct __vxge_hw_blockpool_entry *)
- list_first_entry(&blockpool->free_entry_list,
- struct __vxge_hw_blockpool_entry,
- item);
-
- if (entry == NULL)
- entry =
- kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
- GFP_KERNEL);
- if (entry != NULL) {
- list_del(&entry->item);
- entry->length = VXGE_HW_BLOCK_SIZE;
- entry->memblock = memblock;
- entry->dma_addr = dma_addr;
- entry->acc_handle = acc_handle;
- entry->dma_handle = dma_handle;
- list_add(&entry->item,
- &blockpool->free_block_list);
- blockpool->pool_size++;
- } else {
- __vxge_hw_blockpool_destroy(blockpool);
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto blockpool_create_exit;
- }
- }
-
-blockpool_create_exit:
- return status;
-}
-
-/*
- * __vxge_hw_blockpool_destroy - Deallocates the block pool
- */
-
-void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool)
-{
-
- struct __vxge_hw_device *hldev;
- struct list_head *p, *n;
- u16 ret;
-
- if (blockpool == NULL) {
- ret = 1;
- goto exit;
- }
-
- hldev = blockpool->hldev;
-
- list_for_each_safe(p, n, &blockpool->free_block_list) {
-
- pci_unmap_single(hldev->pdev,
- ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
- ((struct __vxge_hw_blockpool_entry *)p)->length,
- PCI_DMA_BIDIRECTIONAL);
-
- vxge_os_dma_free(hldev->pdev,
- ((struct __vxge_hw_blockpool_entry *)p)->memblock,
- &((struct __vxge_hw_blockpool_entry *) p)->acc_handle);
-
- list_del(
- &((struct __vxge_hw_blockpool_entry *)p)->item);
- kfree(p);
- blockpool->pool_size--;
- }
-
- list_for_each_safe(p, n, &blockpool->free_entry_list) {
- list_del(
- &((struct __vxge_hw_blockpool_entry *)p)->item);
- kfree((void *)p);
- }
- ret = 0;
-exit:
- return;
-}
-
-/*
- * __vxge_hw_blockpool_blocks_add - Request additional blocks
- */
-static
-void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool)
-{
- u32 nreq = 0, i;
-
- if ((blockpool->pool_size + blockpool->req_out) <
- VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE) {
- nreq = VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE;
- blockpool->req_out += nreq;
- }
-
- for (i = 0; i < nreq; i++)
- vxge_os_dma_malloc_async(
- ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
- blockpool->hldev, VXGE_HW_BLOCK_SIZE);
-}
-
-/*
- * __vxge_hw_blockpool_blocks_remove - Free additional blocks
- */
-static
-void __vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &blockpool->free_block_list) {
-
- if (blockpool->pool_size < blockpool->pool_max)
- break;
-
- pci_unmap_single(
- ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
- ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
- ((struct __vxge_hw_blockpool_entry *)p)->length,
- PCI_DMA_BIDIRECTIONAL);
-
- vxge_os_dma_free(
- ((struct __vxge_hw_device *)blockpool->hldev)->pdev,
- ((struct __vxge_hw_blockpool_entry *)p)->memblock,
- &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
-
- list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
-
- list_add(p, &blockpool->free_entry_list);
-
- blockpool->pool_size--;
-
- }
-}
-
-/*
- * vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async
- * Adds a block to block pool
- */
-static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
- void *block_addr,
- u32 length,
- struct pci_dev *dma_h,
- struct pci_dev *acc_handle)
-{
- struct __vxge_hw_blockpool *blockpool;
- struct __vxge_hw_blockpool_entry *entry = NULL;
- dma_addr_t dma_addr;
- enum vxge_hw_status status = VXGE_HW_OK;
- u32 req_out;
-
- blockpool = &devh->block_pool;
-
- if (block_addr == NULL) {
- blockpool->req_out--;
- status = VXGE_HW_FAIL;
- goto exit;
- }
-
- dma_addr = pci_map_single(devh->pdev, block_addr, length,
- PCI_DMA_BIDIRECTIONAL);
-
- if (unlikely(pci_dma_mapping_error(devh->pdev, dma_addr))) {
-
- vxge_os_dma_free(devh->pdev, block_addr, &acc_handle);
- blockpool->req_out--;
- status = VXGE_HW_FAIL;
- goto exit;
- }
-
-
- if (!list_empty(&blockpool->free_entry_list))
- entry = (struct __vxge_hw_blockpool_entry *)
- list_first_entry(&blockpool->free_entry_list,
- struct __vxge_hw_blockpool_entry,
- item);
-
- if (entry == NULL)
- entry = (struct __vxge_hw_blockpool_entry *)
- vmalloc(sizeof(struct __vxge_hw_blockpool_entry));
- else
- list_del(&entry->item);
-
- if (entry != NULL) {
- entry->length = length;
- entry->memblock = block_addr;
- entry->dma_addr = dma_addr;
- entry->acc_handle = acc_handle;
- entry->dma_handle = dma_h;
- list_add(&entry->item, &blockpool->free_block_list);
- blockpool->pool_size++;
- status = VXGE_HW_OK;
- } else
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
-
- blockpool->req_out--;
-
- req_out = blockpool->req_out;
-exit:
- return;
-}
-
-/*
- * __vxge_hw_blockpool_malloc - Allocate a memory block from pool
- * Allocates a block of memory of given size, either from block pool
- * or by calling vxge_os_dma_malloc()
- */
-void *
-__vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size,
- struct vxge_hw_mempool_dma *dma_object)
-{
- struct __vxge_hw_blockpool_entry *entry = NULL;
- struct __vxge_hw_blockpool *blockpool;
- void *memblock = NULL;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- blockpool = &devh->block_pool;
-
- if (size != blockpool->block_size) {
-
- memblock = vxge_os_dma_malloc(devh->pdev, size,
- &dma_object->handle,
- &dma_object->acc_handle);
-
- if (memblock == NULL) {
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto exit;
- }
-
- dma_object->addr = pci_map_single(devh->pdev, memblock, size,
- PCI_DMA_BIDIRECTIONAL);
-
- if (unlikely(pci_dma_mapping_error(devh->pdev,
- dma_object->addr))) {
- vxge_os_dma_free(devh->pdev, memblock,
- &dma_object->acc_handle);
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
- goto exit;
- }
-
- } else {
-
- if (!list_empty(&blockpool->free_block_list))
- entry = (struct __vxge_hw_blockpool_entry *)
- list_first_entry(&blockpool->free_block_list,
- struct __vxge_hw_blockpool_entry,
- item);
-
- if (entry != NULL) {
- list_del(&entry->item);
- dma_object->addr = entry->dma_addr;
- dma_object->handle = entry->dma_handle;
- dma_object->acc_handle = entry->acc_handle;
- memblock = entry->memblock;
-
- list_add(&entry->item,
- &blockpool->free_entry_list);
- blockpool->pool_size--;
- }
-
- if (memblock != NULL)
- __vxge_hw_blockpool_blocks_add(blockpool);
- }
-exit:
- return memblock;
-}
-
-/*
- * __vxge_hw_blockpool_free - Frees the memory allcoated with
- __vxge_hw_blockpool_malloc
- */
-void
-__vxge_hw_blockpool_free(struct __vxge_hw_device *devh,
- void *memblock, u32 size,
- struct vxge_hw_mempool_dma *dma_object)
-{
- struct __vxge_hw_blockpool_entry *entry = NULL;
- struct __vxge_hw_blockpool *blockpool;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- blockpool = &devh->block_pool;
-
- if (size != blockpool->block_size) {
- pci_unmap_single(devh->pdev, dma_object->addr, size,
- PCI_DMA_BIDIRECTIONAL);
- vxge_os_dma_free(devh->pdev, memblock, &dma_object->acc_handle);
- } else {
-
- if (!list_empty(&blockpool->free_entry_list))
- entry = (struct __vxge_hw_blockpool_entry *)
- list_first_entry(&blockpool->free_entry_list,
- struct __vxge_hw_blockpool_entry,
- item);
-
- if (entry == NULL)
- entry = (struct __vxge_hw_blockpool_entry *)
- vmalloc(sizeof(
- struct __vxge_hw_blockpool_entry));
- else
- list_del(&entry->item);
-
- if (entry != NULL) {
- entry->length = size;
- entry->memblock = memblock;
- entry->dma_addr = dma_object->addr;
- entry->acc_handle = dma_object->acc_handle;
- entry->dma_handle = dma_object->handle;
- list_add(&entry->item,
- &blockpool->free_block_list);
- blockpool->pool_size++;
- status = VXGE_HW_OK;
- } else
- status = VXGE_HW_ERR_OUT_OF_MEMORY;
-
- if (status == VXGE_HW_OK)
- __vxge_hw_blockpool_blocks_remove(blockpool);
- }
-}
-
-/*
- * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool
- * This function allocates a block from block pool or from the system
- */
-struct __vxge_hw_blockpool_entry *
-__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size)
-{
- struct __vxge_hw_blockpool_entry *entry = NULL;
- struct __vxge_hw_blockpool *blockpool;
-
- blockpool = &devh->block_pool;
-
- if (size == blockpool->block_size) {
-
- if (!list_empty(&blockpool->free_block_list))
- entry = (struct __vxge_hw_blockpool_entry *)
- list_first_entry(&blockpool->free_block_list,
- struct __vxge_hw_blockpool_entry,
- item);
-
- if (entry != NULL) {
- list_del(&entry->item);
- blockpool->pool_size--;
- }
- }
-
- if (entry != NULL)
- __vxge_hw_blockpool_blocks_add(blockpool);
-
- return entry;
-}
-
-/*
- * __vxge_hw_blockpool_block_free - Frees a block from block pool
- * @devh: Hal device
- * @entry: Entry of block to be freed
- *
- * This function frees a block from block pool
- */
-void
-__vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh,
- struct __vxge_hw_blockpool_entry *entry)
-{
- struct __vxge_hw_blockpool *blockpool;
-
- blockpool = &devh->block_pool;
-
- if (entry->length == blockpool->block_size) {
- list_add(&entry->item, &blockpool->free_block_list);
- blockpool->pool_size++;
- }
-
- __vxge_hw_blockpool_blocks_remove(blockpool);
-}
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 5c00861b6c2c..e249e288d160 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -20,13 +20,6 @@
#define VXGE_CACHE_LINE_SIZE 128
#endif
-#define vxge_os_vaprintf(level, mask, fmt, ...) { \
- char buff[255]; \
- snprintf(buff, 255, fmt, __VA_ARGS__); \
- printk(buff); \
- printk("\n"); \
-}
-
#ifndef VXGE_ALIGN
#define VXGE_ALIGN(adrs, size) \
(((size) - (((u64)adrs) & ((size)-1))) & ((size)-1))
@@ -36,8 +29,16 @@
#define VXGE_HW_MAX_MTU 9600
#define VXGE_HW_DEFAULT_MTU 1500
-#ifdef VXGE_DEBUG_ASSERT
+#define VXGE_HW_MAX_ROM_IMAGES 8
+struct eprom_image {
+ u8 is_valid:1;
+ u8 index;
+ u8 type;
+ u16 version;
+};
+
+#ifdef VXGE_DEBUG_ASSERT
/**
* vxge_assert
* @test: C-condition to check
@@ -48,16 +49,13 @@
* compilation
* time.
*/
-#define vxge_assert(test) { \
- if (!(test)) \
- vxge_os_bug("bad cond: "#test" at %s:%d\n", \
- __FILE__, __LINE__); }
+#define vxge_assert(test) BUG_ON(!(test))
#else
#define vxge_assert(test)
#endif /* end of VXGE_DEBUG_ASSERT */
/**
- * enum enum vxge_debug_level
+ * enum vxge_debug_level
* @VXGE_NONE: debug disabled
* @VXGE_ERR: all errors going to be logged out
* @VXGE_TRACE: all errors plus all kind of verbose tracing print outs
@@ -159,6 +157,47 @@ enum vxge_hw_device_link_state {
};
/**
+ * enum enum vxge_hw_fw_upgrade_code - FW upgrade return codes.
+ * @VXGE_HW_FW_UPGRADE_OK: All OK send next 16 bytes
+ * @VXGE_HW_FW_UPGRADE_DONE: upload completed
+ * @VXGE_HW_FW_UPGRADE_ERR: upload error
+ * @VXGE_FW_UPGRADE_BYTES2SKIP: skip bytes in the stream
+ *
+ */
+enum vxge_hw_fw_upgrade_code {
+ VXGE_HW_FW_UPGRADE_OK = 0,
+ VXGE_HW_FW_UPGRADE_DONE = 1,
+ VXGE_HW_FW_UPGRADE_ERR = 2,
+ VXGE_FW_UPGRADE_BYTES2SKIP = 3
+};
+
+/**
+ * enum enum vxge_hw_fw_upgrade_err_code - FW upgrade error codes.
+ * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1: corrupt data
+ * @VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW: buffer overflow
+ * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3: invalid .ncf file
+ * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4: invalid .ncf file
+ * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5: invalid .ncf file
+ * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6: invalid .ncf file
+ * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7: corrupt data
+ * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8: invalid .ncf file
+ * @VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN: generic error unknown type
+ * @VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH: failed to flash image check failed
+ */
+enum vxge_hw_fw_upgrade_err_code {
+ VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1 = 1,
+ VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW = 2,
+ VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3 = 3,
+ VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4 = 4,
+ VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5 = 5,
+ VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6 = 6,
+ VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7 = 7,
+ VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8 = 8,
+ VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN = 9,
+ VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH = 10
+};
+
+/**
* struct vxge_hw_device_date - Date Format
* @day: Day
* @month: Month
@@ -275,9 +314,9 @@ struct vxge_hw_ring_config {
#define VXGE_HW_RING_DEFAULT 1
u32 ring_blocks;
-#define VXGE_HW_MIN_RING_BLOCKS 1
-#define VXGE_HW_MAX_RING_BLOCKS 128
-#define VXGE_HW_DEF_RING_BLOCKS 2
+#define VXGE_HW_MIN_RING_BLOCKS 1
+#define VXGE_HW_MAX_RING_BLOCKS 128
+#define VXGE_HW_DEF_RING_BLOCKS 2
u32 buffer_mode;
#define VXGE_HW_RING_RXD_BUFFER_MODE_1 1
@@ -465,7 +504,6 @@ struct vxge_hw_device_config {
* See also: vxge_hw_driver_initialize().
*/
struct vxge_hw_uld_cbs {
-
void (*link_up)(struct __vxge_hw_device *devh);
void (*link_down)(struct __vxge_hw_device *devh);
void (*crit_err)(struct __vxge_hw_device *devh,
@@ -652,6 +690,7 @@ struct __vxge_hw_virtualpath {
struct vxge_hw_vpath_stats_hw_info *hw_stats;
struct vxge_hw_vpath_stats_hw_info *hw_stats_sav;
struct vxge_hw_vpath_stats_sw_info *sw_stats;
+ spinlock_t lock;
};
/*
@@ -661,7 +700,7 @@ struct __vxge_hw_virtualpath {
*
* This structure is used to store the callback information.
*/
-struct __vxge_hw_vpath_handle{
+struct __vxge_hw_vpath_handle {
struct list_head item;
struct __vxge_hw_virtualpath *vpath;
};
@@ -674,9 +713,6 @@ struct __vxge_hw_vpath_handle{
/**
* struct __vxge_hw_device - Hal device object
* @magic: Magic Number
- * @device_id: PCI Device Id of the adapter
- * @major_revision: PCI Device major revision
- * @minor_revision: PCI Device minor revision
* @bar0: BAR0 virtual address.
* @pdev: Physical device handle
* @config: Confguration passed by the LL driver at initialization
@@ -688,9 +724,6 @@ struct __vxge_hw_device {
u32 magic;
#define VXGE_HW_DEVICE_MAGIC 0x12345678
#define VXGE_HW_DEVICE_DEAD 0xDEADDEAD
- u16 device_id;
- u8 major_revision;
- u8 minor_revision;
void __iomem *bar0;
struct pci_dev *pdev;
struct net_device *ndev;
@@ -731,6 +764,7 @@ struct __vxge_hw_device {
u32 debug_level;
u32 level_err;
u32 level_trace;
+ u16 eprom_versions[VXGE_HW_MAX_ROM_IMAGES];
};
#define VXGE_HW_INFO_LEN 64
@@ -781,8 +815,8 @@ struct vxge_hw_device_hw_info {
u8 serial_number[VXGE_HW_INFO_LEN];
u8 part_number[VXGE_HW_INFO_LEN];
u8 product_desc[VXGE_HW_INFO_LEN];
- u8 (mac_addrs)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
- u8 (mac_addr_masks)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+ u8 mac_addrs[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
+ u8 mac_addr_masks[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
};
/**
@@ -829,20 +863,10 @@ struct vxge_hw_device_attr {
loc, \
offset, \
&val64); \
- \
if (status != VXGE_HW_OK) \
return status; \
}
-#define VXGE_HW_VPATH_STATS_PIO_READ(offset) { \
- status = __vxge_hw_vpath_stats_access(vpath, \
- VXGE_HW_STATS_OP_READ, \
- offset, \
- &val64); \
- if (status != VXGE_HW_OK) \
- return status; \
-}
-
/*
* struct __vxge_hw_ring - Ring channel.
* @channel: Channel "base" of this ring, the common part of all HW
@@ -1114,7 +1138,7 @@ struct __vxge_hw_non_offload_db_wrapper {
* lookup to determine the transmit port.
* 01: Send on physical Port1.
* 10: Send on physical Port0.
- * 11: Send on both ports.
+ * 11: Send on both ports.
* Bits 18 to 21 - Reserved
* Bits 22 to 23 - Gather_Code. This field is set by the host and
* is used to describe how individual buffers comprise a frame.
@@ -1413,12 +1437,12 @@ enum vxge_hw_rth_algoritms {
* See also: vxge_hw_vpath_rts_rth_set(), vxge_hw_vpath_rts_rth_get().
*/
struct vxge_hw_rth_hash_types {
- u8 hash_type_tcpipv4_en;
- u8 hash_type_ipv4_en;
- u8 hash_type_tcpipv6_en;
- u8 hash_type_ipv6_en;
- u8 hash_type_tcpipv6ex_en;
- u8 hash_type_ipv6ex_en;
+ u8 hash_type_tcpipv4_en:1,
+ hash_type_ipv4_en:1,
+ hash_type_tcpipv6_en:1,
+ hash_type_ipv6_en:1,
+ hash_type_tcpipv6ex_en:1,
+ hash_type_ipv6ex_en:1;
};
void vxge_hw_device_debug_set(
@@ -1893,6 +1917,15 @@ out:
return vaddr;
}
+static inline void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
+ struct pci_dev **p_dma_acch)
+{
+ unsigned long misaligned = *(unsigned long *)p_dma_acch;
+ u8 *tmp = (u8 *)vaddr;
+ tmp -= misaligned;
+ kfree((void *)tmp);
+}
+
/*
* __vxge_hw_mempool_item_priv - will return pointer on per item private space
*/
@@ -1962,7 +1995,6 @@ enum vxge_hw_status vxge_hw_vpath_mtu_set(
void
vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp);
-
#ifndef readq
static inline u64 readq(void __iomem *addr)
{
@@ -2000,7 +2032,7 @@ enum vxge_hw_status
vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
/**
- * vxge_debug
+ * vxge_debug_ll
* @level: level of debug verbosity.
* @mask: mask for the debug
* @buf: Circular buffer for tracing
@@ -2012,26 +2044,13 @@ vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
* may be compiled out if DEBUG macro was never defined.
* See also: enum vxge_debug_level{}.
*/
-
-#define vxge_trace_aux(level, mask, fmt, ...) \
-{\
- vxge_os_vaprintf(level, mask, fmt, __VA_ARGS__);\
-}
-
-#define vxge_debug(module, level, mask, fmt, ...) { \
-if ((level >= VXGE_TRACE && ((module & VXGE_DEBUG_TRACE_MASK) == module)) || \
- (level >= VXGE_ERR && ((module & VXGE_DEBUG_ERR_MASK) == module))) {\
- if ((mask & VXGE_DEBUG_MASK) == mask)\
- vxge_trace_aux(level, mask, fmt, __VA_ARGS__); \
-} \
-}
-
#if (VXGE_COMPONENT_LL & VXGE_DEBUG_MODULE_MASK)
-#define vxge_debug_ll(level, mask, fmt, ...) \
-{\
- vxge_debug(VXGE_COMPONENT_LL, level, mask, fmt, __VA_ARGS__);\
-}
-
+#define vxge_debug_ll(level, mask, fmt, ...) do { \
+ if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) || \
+ (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\
+ if ((mask & VXGE_DEBUG_MASK) == mask) \
+ printk(fmt "\n", __VA_ARGS__); \
+} while (0)
#else
#define vxge_debug_ll(level, mask, fmt, ...)
#endif
@@ -2051,4 +2070,26 @@ enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
enum vxge_hw_status
__vxge_hw_device_is_privilaged(u32 host_type, u32 func_id);
+
+#define VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT 5
+#define VXGE_HW_MAX_POLLING_COUNT 100
+
+void
+vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major,
+ u32 *minor, u32 *build);
+
+enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev);
+
+enum vxge_hw_status
+vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *filebuf,
+ int size);
+
+enum vxge_hw_status
+vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev,
+ struct eprom_image *eprom_image_data);
+
+int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id);
#endif
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index b67746eef923..1dd3a21b3a43 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -11,7 +11,7 @@
* Virtualized Server Adapter.
* Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
-#include<linux/ethtool.h>
+#include <linux/ethtool.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
@@ -29,7 +29,6 @@
* Return value:
* 0 on success.
*/
-
static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info)
{
/* We currently only support 10Gb/FULL */
@@ -79,10 +78,9 @@ static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
* Returns driver specefic information like name, version etc.. to ethtool.
*/
static void vxge_ethtool_gdrvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
+ struct ethtool_drvinfo *info)
{
- struct vxgedev *vdev;
- vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME));
strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN);
@@ -104,15 +102,14 @@ static void vxge_ethtool_gdrvinfo(struct net_device *dev,
* buffer area.
*/
static void vxge_ethtool_gregs(struct net_device *dev,
- struct ethtool_regs *regs, void *space)
+ struct ethtool_regs *regs, void *space)
{
int index, offset;
enum vxge_hw_status status;
u64 reg;
- u64 *reg_space = (u64 *) space;
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)
- pci_get_drvdata(vdev->pdev);
+ u64 *reg_space = (u64 *)space;
+ struct vxgedev *vdev = netdev_priv(dev);
+ struct __vxge_hw_device *hldev = vdev->devh;
regs->len = sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
regs->version = vdev->pdev->subsystem_device;
@@ -147,9 +144,8 @@ static void vxge_ethtool_gregs(struct net_device *dev,
*/
static int vxge_ethtool_idnic(struct net_device *dev, u32 data)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)
- pci_get_drvdata(vdev->pdev);
+ struct vxgedev *vdev = netdev_priv(dev);
+ struct __vxge_hw_device *hldev = vdev->devh;
vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON);
msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME);
@@ -168,11 +164,10 @@ static int vxge_ethtool_idnic(struct net_device *dev, u32 data)
* void
*/
static void vxge_ethtool_getpause_data(struct net_device *dev,
- struct ethtool_pauseparam *ep)
+ struct ethtool_pauseparam *ep)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)
- pci_get_drvdata(vdev->pdev);
+ struct vxgedev *vdev = netdev_priv(dev);
+ struct __vxge_hw_device *hldev = vdev->devh;
vxge_hw_device_getpause_data(hldev, 0, &ep->tx_pause, &ep->rx_pause);
}
@@ -188,11 +183,10 @@ static void vxge_ethtool_getpause_data(struct net_device *dev,
* int, returns 0 on Success
*/
static int vxge_ethtool_setpause_data(struct net_device *dev,
- struct ethtool_pauseparam *ep)
+ struct ethtool_pauseparam *ep)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)
- pci_get_drvdata(vdev->pdev);
+ struct vxgedev *vdev = netdev_priv(dev);
+ struct __vxge_hw_device *hldev = vdev->devh;
vxge_hw_device_setpause_data(hldev, 0, ep->tx_pause, ep->rx_pause);
@@ -209,9 +203,8 @@ static void vxge_get_ethtool_stats(struct net_device *dev,
enum vxge_hw_status status;
enum vxge_hw_status swstatus;
struct vxge_vpath *vpath = NULL;
-
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
- struct __vxge_hw_device *hldev = vdev->devh;
+ struct vxgedev *vdev = netdev_priv(dev);
+ struct __vxge_hw_device *hldev = vdev->devh;
struct vxge_hw_xmac_stats *xmac_stats;
struct vxge_hw_device_stats_sw_info *sw_stats;
struct vxge_hw_device_stats_hw_info *hw_stats;
@@ -574,12 +567,12 @@ static void vxge_get_ethtool_stats(struct net_device *dev,
kfree(hw_stats);
}
-static void vxge_ethtool_get_strings(struct net_device *dev,
- u32 stringset, u8 *data)
+static void vxge_ethtool_get_strings(struct net_device *dev, u32 stringset,
+ u8 *data)
{
int stat_size = 0;
int i, j;
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
switch (stringset) {
case ETH_SS_STATS:
vxge_add_string("VPATH STATISTICS%s\t\t\t",
@@ -1066,21 +1059,21 @@ static void vxge_ethtool_get_strings(struct net_device *dev,
static int vxge_ethtool_get_regs_len(struct net_device *dev)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
}
static u32 vxge_get_rx_csum(struct net_device *dev)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
return vdev->rx_csum;
}
static int vxge_set_rx_csum(struct net_device *dev, u32 data)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
if (data)
vdev->rx_csum = 1;
@@ -1102,7 +1095,7 @@ static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data)
static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
{
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
switch (sset) {
case ETH_SS_STATS:
@@ -1119,6 +1112,59 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
}
}
+static int vxge_set_flags(struct net_device *dev, u32 data)
+{
+ struct vxgedev *vdev = netdev_priv(dev);
+ enum vxge_hw_status status;
+
+ if (data & ~ETH_FLAG_RXHASH)
+ return -EOPNOTSUPP;
+
+ if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en)
+ return 0;
+
+ if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING))
+ return -EINVAL;
+
+ vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH);
+
+ /* Enabling RTH requires some of the logic in vxge_device_register and a
+ * vpath reset. Due to these restrictions, only allow modification
+ * while the interface is down.
+ */
+ status = vxge_reset_all_vpaths(vdev);
+ if (status != VXGE_HW_OK) {
+ vdev->devh->config.rth_en = !vdev->devh->config.rth_en;
+ return -EFAULT;
+ }
+
+ if (vdev->devh->config.rth_en)
+ dev->features |= NETIF_F_RXHASH;
+ else
+ dev->features &= ~NETIF_F_RXHASH;
+
+ return 0;
+}
+
+static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms)
+{
+ struct vxgedev *vdev = netdev_priv(dev);
+
+ if (vdev->max_vpath_supported != VXGE_HW_MAX_VIRTUAL_PATHS) {
+ printk(KERN_INFO "Single Function Mode is required to flash the"
+ " firmware\n");
+ return -EINVAL;
+ }
+
+ if (netif_running(dev)) {
+ printk(KERN_INFO "Interface %s must be down to flash the "
+ "firmware\n", dev->name);
+ return -EBUSY;
+ }
+
+ return vxge_fw_upgrade(vdev, parms->data, 1);
+}
+
static const struct ethtool_ops vxge_ethtool_ops = {
.get_settings = vxge_ethtool_gset,
.set_settings = vxge_ethtool_sset,
@@ -1131,7 +1177,7 @@ static const struct ethtool_ops vxge_ethtool_ops = {
.get_rx_csum = vxge_get_rx_csum,
.set_rx_csum = vxge_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
@@ -1140,6 +1186,8 @@ static const struct ethtool_ops vxge_ethtool_ops = {
.phys_id = vxge_ethtool_idnic,
.get_sset_count = vxge_ethtool_get_sset_count,
.get_ethtool_stats = vxge_get_ethtool_stats,
+ .set_flags = vxge_set_flags,
+ .flash_device = vxge_fw_flash,
};
void vxge_initialize_ethtool_ops(struct net_device *ndev)
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index 813829f3d024..c81a6512c683 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -50,6 +50,8 @@
#include <net/ip.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#include <linux/net_tstamp.h>
#include "vxge-main.h"
#include "vxge-reg.h"
@@ -82,16 +84,6 @@ module_param_array(bw_percentage, uint, NULL, 0);
static struct vxge_drv_config *driver_config;
-static enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac);
-static enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac);
-static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac);
-static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac);
-static enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath);
-static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath);
-static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
-
static inline int is_vxge_card_up(struct vxgedev *vdev)
{
return test_bit(__VXGE_STATE_CARD_UP, &vdev->state);
@@ -148,11 +140,10 @@ static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev)
* This function is called during interrupt context to notify link up state
* change.
*/
-static void
-vxge_callback_link_up(struct __vxge_hw_device *hldev)
+static void vxge_callback_link_up(struct __vxge_hw_device *hldev)
{
struct net_device *dev = hldev->ndev;
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
vdev->ndev->name, __func__, __LINE__);
@@ -172,11 +163,10 @@ vxge_callback_link_up(struct __vxge_hw_device *hldev)
* This function is called during interrupt context to notify link down state
* change.
*/
-static void
-vxge_callback_link_down(struct __vxge_hw_device *hldev)
+static void vxge_callback_link_down(struct __vxge_hw_device *hldev)
{
struct net_device *dev = hldev->ndev;
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
@@ -195,7 +185,7 @@ vxge_callback_link_down(struct __vxge_hw_device *hldev)
*
* Allocate SKB.
*/
-static struct sk_buff*
+static struct sk_buff *
vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size)
{
struct net_device *dev;
@@ -369,7 +359,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
u8 t_code, void *userdata)
{
struct vxge_ring *ring = (struct vxge_ring *)userdata;
- struct net_device *dev = ring->ndev;
+ struct net_device *dev = ring->ndev;
unsigned int dma_sizes;
void *first_dtr = NULL;
int dtr_cnt = 0;
@@ -413,7 +403,6 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
prefetch((char *)skb + L1_CACHE_BYTES);
if (unlikely(t_code)) {
-
if (vxge_hw_ring_handle_tcode(ringh, dtr, t_code) !=
VXGE_HW_OK) {
@@ -436,9 +425,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
}
if (pkt_length > VXGE_LL_RX_COPY_THRESHOLD) {
-
if (vxge_rx_alloc(dtr, ring, data_size) != NULL) {
-
if (!vxge_rx_map(dtr, ring)) {
skb_put(skb, pkt_length);
@@ -513,6 +500,23 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
else
skb_checksum_none_assert(skb);
+
+ if (ring->rx_hwts) {
+ struct skb_shared_hwtstamps *skb_hwts;
+ u32 ns = *(u32 *)(skb->head + pkt_length);
+
+ skb_hwts = skb_hwtstamps(skb);
+ skb_hwts->hwtstamp = ns_to_ktime(ns);
+ skb_hwts->syststamp.tv64 = 0;
+ }
+
+ /* rth_hash_type and rth_it_hit are non-zero regardless of
+ * whether rss is enabled. Only the rth_value is zero/non-zero
+ * if rss is disabled/enabled, so key off of that.
+ */
+ if (ext_info.rth_value)
+ skb->rxhash = ext_info.rth_value;
+
vxge_rx_complete(ring, skb, ext_info.vlan,
pkt_length, &ext_info);
@@ -660,6 +664,65 @@ static enum vxge_hw_status vxge_search_mac_addr_in_list(
return FALSE;
}
+static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
+{
+ struct vxge_mac_addrs *new_mac_entry;
+ u8 *mac_address = NULL;
+
+ if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT)
+ return TRUE;
+
+ new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC);
+ if (!new_mac_entry) {
+ vxge_debug_mem(VXGE_ERR,
+ "%s: memory allocation failed",
+ VXGE_DRIVER_NAME);
+ return FALSE;
+ }
+
+ list_add(&new_mac_entry->item, &vpath->mac_addr_list);
+
+ /* Copy the new mac address to the list */
+ mac_address = (u8 *)&new_mac_entry->macaddr;
+ memcpy(mac_address, mac->macaddr, ETH_ALEN);
+
+ new_mac_entry->state = mac->state;
+ vpath->mac_addr_cnt++;
+
+ /* Is this a multicast address */
+ if (0x01 & mac->macaddr[0])
+ vpath->mcast_addr_cnt++;
+
+ return TRUE;
+}
+
+/* Add a mac address to DA table */
+static enum vxge_hw_status
+vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_vpath *vpath;
+ enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode;
+
+ if (0x01 & mac->macaddr[0]) /* multicast address */
+ duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE;
+ else
+ duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE;
+
+ vpath = &vdev->vpaths[mac->vpath_no];
+ status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr,
+ mac->macmask, duplicate_mode);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "DA config add entry failed for vpath:%d",
+ vpath->device_id);
+ } else
+ if (FALSE == vxge_mac_list_add(vpath, mac))
+ status = -EPERM;
+
+ return status;
+}
+
static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
{
struct macInfo mac_info;
@@ -670,7 +733,7 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
struct vxge_vpath *vpath = NULL;
struct __vxge_hw_device *hldev;
- hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ hldev = pci_get_drvdata(vdev->pdev);
mac_address = (u8 *)&mac_addr;
memcpy(mac_address, mac_header, ETH_ALEN);
@@ -769,7 +832,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
if (unlikely(!is_vxge_card_up(vdev))) {
vxge_debug_tx(VXGE_ERR,
@@ -1005,6 +1068,50 @@ vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata)
"%s:%d Exiting...", __func__, __LINE__);
}
+static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
+{
+ struct list_head *entry, *next;
+ u64 del_mac = 0;
+ u8 *mac_address = (u8 *) (&del_mac);
+
+ /* Copy the mac address to delete from the list */
+ memcpy(mac_address, mac->macaddr, ETH_ALEN);
+
+ list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+ if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) {
+ list_del(entry);
+ kfree((struct vxge_mac_addrs *)entry);
+ vpath->mac_addr_cnt--;
+
+ /* Is this a multicast address */
+ if (0x01 & mac->macaddr[0])
+ vpath->mcast_addr_cnt--;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* delete a mac address from DA table */
+static enum vxge_hw_status
+vxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_vpath *vpath;
+
+ vpath = &vdev->vpaths[mac->vpath_no];
+ status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr,
+ mac->macmask);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "DA config delete entry failed for vpath:%d",
+ vpath->device_id);
+ } else
+ vxge_mac_list_del(vpath, mac);
+ return status;
+}
+
/**
* vxge_set_multicast
* @dev: pointer to the device structure
@@ -1034,7 +1141,7 @@ static void vxge_set_multicast(struct net_device *dev)
vxge_debug_entryexit(VXGE_TRACE,
"%s:%d", __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
hldev = (struct __vxge_hw_device *)vdev->devh;
if (unlikely(!is_vxge_card_up(vdev)))
@@ -1094,7 +1201,7 @@ static void vxge_set_multicast(struct net_device *dev)
/* Delete previous MC's */
for (i = 0; i < mcast_cnt; i++) {
list_for_each_safe(entry, next, list_head) {
- mac_entry = (struct vxge_mac_addrs *) entry;
+ mac_entry = (struct vxge_mac_addrs *)entry;
/* Copy the mac address to delete */
mac_address = (u8 *)&mac_entry->macaddr;
memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
@@ -1137,7 +1244,7 @@ _set_all_mcast:
/* Delete previous MC's */
for (i = 0; i < mcast_cnt; i++) {
list_for_each_safe(entry, next, list_head) {
- mac_entry = (struct vxge_mac_addrs *) entry;
+ mac_entry = (struct vxge_mac_addrs *)entry;
/* Copy the mac address to delete */
mac_address = (u8 *)&mac_entry->macaddr;
memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
@@ -1184,14 +1291,14 @@ static int vxge_set_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
struct vxgedev *vdev;
- struct __vxge_hw_device *hldev;
+ struct __vxge_hw_device *hldev;
enum vxge_hw_status status = VXGE_HW_OK;
struct macInfo mac_info_new, mac_info_old;
int vpath_idx = 0;
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
hldev = vdev->devh;
if (!is_valid_ether_addr(addr->sa_data))
@@ -1292,8 +1399,13 @@ static void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
static void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
{
struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
+ struct __vxge_hw_device *hldev;
int msix_id;
+ hldev = pci_get_drvdata(vdev->pdev);
+
+ vxge_hw_vpath_wait_receive_idle(hldev, vpath->device_id);
+
vxge_hw_vpath_intr_disable(vpath->handle);
if (vdev->config.intr_type == INTA)
@@ -1310,6 +1422,95 @@ static void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
}
}
+/* list all mac addresses from DA table */
+static enum vxge_hw_status
+vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath, struct macInfo *mac)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ unsigned char macmask[ETH_ALEN];
+ unsigned char macaddr[ETH_ALEN];
+
+ status = vxge_hw_vpath_mac_addr_get(vpath->handle,
+ macaddr, macmask);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "DA config list entry failed for vpath:%d",
+ vpath->device_id);
+ return status;
+ }
+
+ while (memcmp(mac->macaddr, macaddr, ETH_ALEN)) {
+ status = vxge_hw_vpath_mac_addr_get_next(vpath->handle,
+ macaddr, macmask);
+ if (status != VXGE_HW_OK)
+ break;
+ }
+
+ return status;
+}
+
+/* Store all mac addresses from the list to the DA table */
+static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct macInfo mac_info;
+ u8 *mac_address = NULL;
+ struct list_head *entry, *next;
+
+ memset(&mac_info, 0, sizeof(struct macInfo));
+
+ if (vpath->is_open) {
+ list_for_each_safe(entry, next, &vpath->mac_addr_list) {
+ mac_address =
+ (u8 *)&
+ ((struct vxge_mac_addrs *)entry)->macaddr;
+ memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
+ ((struct vxge_mac_addrs *)entry)->state =
+ VXGE_LL_MAC_ADDR_IN_DA_TABLE;
+ /* does this mac address already exist in da table? */
+ status = vxge_search_mac_addr_in_da_table(vpath,
+ &mac_info);
+ if (status != VXGE_HW_OK) {
+ /* Add this mac address to the DA table */
+ status = vxge_hw_vpath_mac_addr_add(
+ vpath->handle, mac_info.macaddr,
+ mac_info.macmask,
+ VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "DA add entry failed for vpath:%d",
+ vpath->device_id);
+ ((struct vxge_mac_addrs *)entry)->state
+ = VXGE_LL_MAC_ADDR_IN_LIST;
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+/* Store all vlan ids from the list to the vid table */
+static enum vxge_hw_status
+vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
+{
+ enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxgedev *vdev = vpath->vdev;
+ u16 vid;
+
+ if (vdev->vlgrp && vpath->is_open) {
+
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
+ if (!vlan_group_get_device(vdev->vlgrp, vid))
+ continue;
+ /* Add these vlan to the vid table */
+ status = vxge_hw_vpath_vid_add(vpath->handle, vid);
+ }
+ }
+
+ return status;
+}
+
/*
* vxge_reset_vpath
* @vdev: pointer to vdev
@@ -1405,12 +1606,16 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
}
if (event == VXGE_LL_FULL_RESET) {
+ netif_carrier_off(vdev->ndev);
+
/* wait for all the vpath reset to complete */
for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
while (test_bit(vp_id, &vdev->vp_reset))
msleep(50);
}
+ netif_carrier_on(vdev->ndev);
+
/* if execution mode is set to debug, don't reset the adapter */
if (unlikely(vdev->exec_mode)) {
vxge_debug_init(VXGE_ERR,
@@ -1423,6 +1628,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
}
if (event == VXGE_LL_FULL_RESET) {
+ vxge_hw_device_wait_receive_idle(vdev->devh);
vxge_hw_device_intr_disable(vdev->devh);
switch (vdev->cric_err_event) {
@@ -1563,9 +1769,14 @@ out:
*
* driver may reset the chip on events of serr, eccerr, etc
*/
-static int vxge_reset(struct vxgedev *vdev)
+static void vxge_reset(struct work_struct *work)
{
- return do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
+ struct vxgedev *vdev = container_of(work, struct vxgedev, reset_task);
+
+ if (!netif_running(vdev->ndev))
+ return;
+
+ do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
}
/**
@@ -1608,8 +1819,7 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget)
int budget_org = budget;
struct vxge_ring *ring;
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)
- pci_get_drvdata(vdev->pdev);
+ struct __vxge_hw_device *hldev = pci_get_drvdata(vdev->pdev);
for (i = 0; i < vdev->no_of_vpath; i++) {
ring = &vdev->vpaths[i].ring;
@@ -1645,11 +1855,11 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget)
*/
static void vxge_netpoll(struct net_device *dev)
{
- struct __vxge_hw_device *hldev;
+ struct __vxge_hw_device *hldev;
struct vxgedev *vdev;
- vdev = (struct vxgedev *)netdev_priv(dev);
- hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+ vdev = netdev_priv(dev);
+ hldev = pci_get_drvdata(vdev->pdev);
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
@@ -1689,15 +1899,6 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
mtable[index] = index % vdev->no_of_vpath;
}
- /* Fill RTH hash types */
- hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4;
- hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4;
- hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6;
- hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6;
- hash_types.hash_type_tcpipv6ex_en =
- vdev->config.rth_hash_type_tcpipv6ex;
- hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex;
-
/* set indirection table, bucket-to-vpath mapping */
status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles,
vdev->no_of_vpath,
@@ -1710,19 +1911,27 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
return status;
}
+ /* Fill RTH hash types */
+ hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4;
+ hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4;
+ hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6;
+ hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6;
+ hash_types.hash_type_tcpipv6ex_en =
+ vdev->config.rth_hash_type_tcpipv6ex;
+ hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex;
+
/*
- * Because the itable_set() method uses the active_table field
- * for the target virtual path the RTH config should be updated
- * for all VPATHs. The h/w only uses the lowest numbered VPATH
- * when steering frames.
- */
+ * Because the itable_set() method uses the active_table field
+ * for the target virtual path the RTH config should be updated
+ * for all VPATHs. The h/w only uses the lowest numbered VPATH
+ * when steering frames.
+ */
for (index = 0; index < vdev->no_of_vpath; index++) {
status = vxge_hw_vpath_rts_rth_set(
vdev->vpaths[index].handle,
vdev->config.rth_algorithm,
&hash_types,
vdev->config.rth_bkt_sz);
-
if (status != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"RTH configuration failed for vpath:%d",
@@ -1734,201 +1943,8 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
return status;
}
-static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
-{
- struct vxge_mac_addrs *new_mac_entry;
- u8 *mac_address = NULL;
-
- if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT)
- return TRUE;
-
- new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC);
- if (!new_mac_entry) {
- vxge_debug_mem(VXGE_ERR,
- "%s: memory allocation failed",
- VXGE_DRIVER_NAME);
- return FALSE;
- }
-
- list_add(&new_mac_entry->item, &vpath->mac_addr_list);
-
- /* Copy the new mac address to the list */
- mac_address = (u8 *)&new_mac_entry->macaddr;
- memcpy(mac_address, mac->macaddr, ETH_ALEN);
-
- new_mac_entry->state = mac->state;
- vpath->mac_addr_cnt++;
-
- /* Is this a multicast address */
- if (0x01 & mac->macaddr[0])
- vpath->mcast_addr_cnt++;
-
- return TRUE;
-}
-
-/* Add a mac address to DA table */
-static enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_vpath *vpath;
- enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode;
-
- if (0x01 & mac->macaddr[0]) /* multicast address */
- duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE;
- else
- duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE;
-
- vpath = &vdev->vpaths[mac->vpath_no];
- status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr,
- mac->macmask, duplicate_mode);
- if (status != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "DA config add entry failed for vpath:%d",
- vpath->device_id);
- } else
- if (FALSE == vxge_mac_list_add(vpath, mac))
- status = -EPERM;
-
- return status;
-}
-
-static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
-{
- struct list_head *entry, *next;
- u64 del_mac = 0;
- u8 *mac_address = (u8 *) (&del_mac);
-
- /* Copy the mac address to delete from the list */
- memcpy(mac_address, mac->macaddr, ETH_ALEN);
-
- list_for_each_safe(entry, next, &vpath->mac_addr_list) {
- if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) {
- list_del(entry);
- kfree((struct vxge_mac_addrs *)entry);
- vpath->mac_addr_cnt--;
-
- /* Is this a multicast address */
- if (0x01 & mac->macaddr[0])
- vpath->mcast_addr_cnt--;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-/* delete a mac address from DA table */
-static enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxge_vpath *vpath;
-
- vpath = &vdev->vpaths[mac->vpath_no];
- status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr,
- mac->macmask);
- if (status != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "DA config delete entry failed for vpath:%d",
- vpath->device_id);
- } else
- vxge_mac_list_del(vpath, mac);
- return status;
-}
-
-/* list all mac addresses from DA table */
-enum vxge_hw_status
-static vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath,
- struct macInfo *mac)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- unsigned char macmask[ETH_ALEN];
- unsigned char macaddr[ETH_ALEN];
-
- status = vxge_hw_vpath_mac_addr_get(vpath->handle,
- macaddr, macmask);
- if (status != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "DA config list entry failed for vpath:%d",
- vpath->device_id);
- return status;
- }
-
- while (memcmp(mac->macaddr, macaddr, ETH_ALEN)) {
-
- status = vxge_hw_vpath_mac_addr_get_next(vpath->handle,
- macaddr, macmask);
- if (status != VXGE_HW_OK)
- break;
- }
-
- return status;
-}
-
-/* Store all vlan ids from the list to the vid table */
-static enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct vxgedev *vdev = vpath->vdev;
- u16 vid;
-
- if (vdev->vlgrp && vpath->is_open) {
-
- for (vid = 0; vid < VLAN_N_VID; vid++) {
- if (!vlan_group_get_device(vdev->vlgrp, vid))
- continue;
- /* Add these vlan to the vid table */
- status = vxge_hw_vpath_vid_add(vpath->handle, vid);
- }
- }
-
- return status;
-}
-
-/* Store all mac addresses from the list to the DA table */
-static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
- struct macInfo mac_info;
- u8 *mac_address = NULL;
- struct list_head *entry, *next;
-
- memset(&mac_info, 0, sizeof(struct macInfo));
-
- if (vpath->is_open) {
-
- list_for_each_safe(entry, next, &vpath->mac_addr_list) {
- mac_address =
- (u8 *)&
- ((struct vxge_mac_addrs *)entry)->macaddr;
- memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
- ((struct vxge_mac_addrs *)entry)->state =
- VXGE_LL_MAC_ADDR_IN_DA_TABLE;
- /* does this mac address already exist in da table? */
- status = vxge_search_mac_addr_in_da_table(vpath,
- &mac_info);
- if (status != VXGE_HW_OK) {
- /* Add this mac address to the DA table */
- status = vxge_hw_vpath_mac_addr_add(
- vpath->handle, mac_info.macaddr,
- mac_info.macmask,
- VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE);
- if (status != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "DA add entry failed for vpath:%d",
- vpath->device_id);
- ((struct vxge_mac_addrs *)entry)->state
- = VXGE_LL_MAC_ADDR_IN_LIST;
- }
- }
- }
- }
-
- return status;
-}
-
/* reset vpaths */
-static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath;
@@ -1988,8 +2004,23 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
for (i = 0; i < vdev->no_of_vpath; i++) {
vpath = &vdev->vpaths[i];
-
vxge_assert(vpath->is_configured);
+
+ if (!vdev->titan1) {
+ struct vxge_hw_vp_config *vcfg;
+ vcfg = &vdev->devh->config.vp_config[vpath->device_id];
+
+ vcfg->rti.urange_a = RTI_T1A_RX_URANGE_A;
+ vcfg->rti.urange_b = RTI_T1A_RX_URANGE_B;
+ vcfg->rti.urange_c = RTI_T1A_RX_URANGE_C;
+ vcfg->tti.uec_a = TTI_T1A_TX_UFC_A;
+ vcfg->tti.uec_b = TTI_T1A_TX_UFC_B;
+ vcfg->tti.uec_c = TTI_T1A_TX_UFC_C(vdev->mtu);
+ vcfg->tti.uec_d = TTI_T1A_TX_UFC_D(vdev->mtu);
+ vcfg->tti.ltimer_val = VXGE_T1A_TTI_LTIMER_VAL;
+ vcfg->tti.rtimer_val = VXGE_T1A_TTI_RTIMER_VAL;
+ }
+
attr.vp_id = vpath->device_id;
attr.fifo_attr.callback = vxge_xmit_compl;
attr.fifo_attr.txdl_term = vxge_tx_term;
@@ -2004,6 +2035,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
vpath->ring.ndev = vdev->ndev;
vpath->ring.pdev = vdev->pdev;
+
status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle);
if (status == VXGE_HW_OK) {
vpath->fifo.handle =
@@ -2024,6 +2056,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
vdev->config.fifo_indicate_max_pkts;
vpath->ring.rx_vector_no = 0;
vpath->ring.rx_csum = vdev->rx_csum;
+ vpath->ring.rx_hwts = vdev->rx_hwts;
vpath->is_open = 1;
vdev->vp_handles[i] = vpath->handle;
vpath->ring.gro_enable = vdev->config.gro_enable;
@@ -2031,11 +2064,10 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
vdev->stats.vpaths_open++;
} else {
vdev->stats.vpath_open_fail++;
- vxge_debug_init(VXGE_ERR,
- "%s: vpath: %d failed to open "
- "with status: %d",
- vdev->ndev->name, vpath->device_id,
- status);
+ vxge_debug_init(VXGE_ERR, "%s: vpath: %d failed to "
+ "open with status: %d",
+ vdev->ndev->name, vpath->device_id,
+ status);
vxge_close_vpaths(vdev, 0);
return -EPERM;
}
@@ -2043,6 +2075,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
vp_id = vpath->handle->vpath->vp_id;
vdev->vpaths_deployed |= vxge_mBIT(vp_id);
}
+
return VXGE_HW_OK;
}
@@ -2062,21 +2095,20 @@ static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
struct __vxge_hw_device *hldev;
u64 reason;
enum vxge_hw_status status;
- struct vxgedev *vdev = (struct vxgedev *) dev_id;;
+ struct vxgedev *vdev = (struct vxgedev *)dev_id;
vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
dev = vdev->ndev;
- hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
+ hldev = pci_get_drvdata(vdev->pdev);
if (pci_channel_offline(vdev->pdev))
return IRQ_NONE;
if (unlikely(!is_vxge_card_up(vdev)))
- return IRQ_NONE;
+ return IRQ_HANDLED;
- status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode,
- &reason);
+ status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode, &reason);
if (status == VXGE_HW_OK) {
vxge_hw_device_mask_all(hldev);
@@ -2301,8 +2333,8 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev)
static void vxge_rem_isr(struct vxgedev *vdev)
{
- struct __vxge_hw_device *hldev;
- hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ struct __vxge_hw_device *hldev;
+ hldev = pci_get_drvdata(vdev->pdev);
#ifdef CONFIG_PCI_MSI
if (vdev->config.intr_type == MSI_X) {
@@ -2529,8 +2561,7 @@ static void vxge_poll_vp_lockup(unsigned long data)
* Return value: '0' on success and an appropriate (-)ve integer as
* defined in errno.h file on failure.
*/
-static int
-vxge_open(struct net_device *dev)
+static int vxge_open(struct net_device *dev)
{
enum vxge_hw_status status;
struct vxgedev *vdev;
@@ -2539,11 +2570,12 @@ vxge_open(struct net_device *dev)
int ret = 0;
int i;
u64 val64, function_mode;
+
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d", dev->name, __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
- hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ vdev = netdev_priv(dev);
+ hldev = pci_get_drvdata(vdev->pdev);
function_mode = vdev->config.device_hw_info.function_mode;
/* make sure you have link off by default every time Nic is
@@ -2598,6 +2630,8 @@ vxge_open(struct net_device *dev)
goto out2;
}
}
+ printk(KERN_INFO "%s: Receive Hashing Offload %s\n", dev->name,
+ hldev->config.rth_en ? "enabled" : "disabled");
for (i = 0; i < vdev->no_of_vpath; i++) {
vpath = &vdev->vpaths[i];
@@ -2683,9 +2717,10 @@ vxge_open(struct net_device *dev)
vxge_os_timer(vdev->vp_reset_timer,
vxge_poll_vp_reset, vdev, (HZ/2));
- if (vdev->vp_lockup_timer.function == NULL)
- vxge_os_timer(vdev->vp_lockup_timer,
- vxge_poll_vp_lockup, vdev, (HZ/2));
+ /* There is no need to check for RxD leak and RxD lookup on Titan1A */
+ if (vdev->titan1 && vdev->vp_lockup_timer.function == NULL)
+ vxge_os_timer(vdev->vp_lockup_timer, vxge_poll_vp_lockup, vdev,
+ HZ / 2);
set_bit(__VXGE_STATE_CARD_UP, &vdev->state);
@@ -2767,8 +2802,8 @@ static int do_vxge_close(struct net_device *dev, int do_io)
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
dev->name, __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
- hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ vdev = netdev_priv(dev);
+ hldev = pci_get_drvdata(vdev->pdev);
if (unlikely(!is_vxge_card_up(vdev)))
return 0;
@@ -2778,7 +2813,6 @@ static int do_vxge_close(struct net_device *dev, int do_io)
while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
msleep(50);
- clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
if (do_io) {
/* Put the vpath back in normal mode */
vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id);
@@ -2789,7 +2823,6 @@ static int do_vxge_close(struct net_device *dev, int do_io)
struct vxge_hw_mrpcim_reg,
rts_mgr_cbasin_cfg),
&val64);
-
if (status == VXGE_HW_OK) {
val64 &= ~vpath_vector;
status = vxge_hw_mgmt_reg_write(vdev->devh,
@@ -2818,10 +2851,17 @@ static int do_vxge_close(struct net_device *dev, int do_io)
smp_wmb();
}
- del_timer_sync(&vdev->vp_lockup_timer);
+
+ if (vdev->titan1)
+ del_timer_sync(&vdev->vp_lockup_timer);
del_timer_sync(&vdev->vp_reset_timer);
+ if (do_io)
+ vxge_hw_device_wait_receive_idle(hldev);
+
+ clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+
/* Disable napi */
if (vdev->config.intr_type != MSI_X)
napi_disable(&vdev->napi);
@@ -2838,8 +2878,6 @@ static int do_vxge_close(struct net_device *dev, int do_io)
if (do_io)
vxge_hw_device_intr_disable(vdev->devh);
- mdelay(1000);
-
vxge_rem_isr(vdev);
vxge_napi_del_all(vdev);
@@ -2868,8 +2906,7 @@ static int do_vxge_close(struct net_device *dev, int do_io)
* Return value: '0' on success and an appropriate (-)ve integer as
* defined in errno.h file on failure.
*/
-static int
-vxge_close(struct net_device *dev)
+static int vxge_close(struct net_device *dev)
{
do_vxge_close(dev, 1);
return 0;
@@ -2943,9 +2980,7 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes;
net_stats->rx_errors += vdev->vpaths[k].ring.stats.rx_errors;
net_stats->multicast += vdev->vpaths[k].ring.stats.rx_mcast;
- net_stats->rx_dropped +=
- vdev->vpaths[k].ring.stats.rx_dropped;
-
+ net_stats->rx_dropped += vdev->vpaths[k].ring.stats.rx_dropped;
net_stats->tx_packets += vdev->vpaths[k].fifo.stats.tx_frms;
net_stats->tx_bytes += vdev->vpaths[k].fifo.stats.tx_bytes;
net_stats->tx_errors += vdev->vpaths[k].fifo.stats.tx_errors;
@@ -2954,6 +2989,101 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
return net_stats;
}
+static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev,
+ int enable)
+{
+ enum vxge_hw_status status;
+ u64 val64;
+
+ /* Timestamp is passed to the driver via the FCS, therefore we
+ * must disable the FCS stripping by the adapter. Since this is
+ * required for the driver to load (due to a hardware bug),
+ * there is no need to do anything special here.
+ */
+ if (enable)
+ val64 = VXGE_HW_XMAC_TIMESTAMP_EN |
+ VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) |
+ VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0);
+ else
+ val64 = 0;
+
+ status = vxge_hw_mgmt_reg_write(vdev->devh,
+ vxge_hw_mgmt_reg_type_mrpcim,
+ 0,
+ offsetof(struct vxge_hw_mrpcim_reg,
+ xmac_timestamp),
+ val64);
+ vxge_hw_device_flush_io(vdev->devh);
+ return status;
+}
+
+static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data)
+{
+ struct hwtstamp_config config;
+ enum vxge_hw_status status;
+ int i;
+
+ if (copy_from_user(&config, data, sizeof(config)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ /* Transmit HW Timestamp not supported */
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ break;
+ case HWTSTAMP_TX_ON:
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ status = vxge_timestamp_config(vdev, 0);
+ if (status != VXGE_HW_OK)
+ return -EFAULT;
+
+ vdev->rx_hwts = 0;
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ status = vxge_timestamp_config(vdev, 1);
+ if (status != VXGE_HW_OK)
+ return -EFAULT;
+
+ vdev->rx_hwts = 1;
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+
+ default:
+ return -ERANGE;
+ }
+
+ for (i = 0; i < vdev->no_of_vpath; i++)
+ vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts;
+
+ if (copy_to_user(data, &config, sizeof(config)))
+ return -EFAULT;
+
+ return 0;
+}
+
/**
* vxge_ioctl
* @dev: Device pointer.
@@ -2966,7 +3096,20 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
*/
static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- return -EOPNOTSUPP;
+ struct vxgedev *vdev = netdev_priv(dev);
+ int ret;
+
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ ret = vxge_hwtstamp_ioctl(vdev, rq->ifr_data);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
}
/**
@@ -2977,18 +3120,17 @@ static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
* This function is triggered if the Tx Queue is stopped
* for a pre-defined amount of time when the Interface is still up.
*/
-static void
-vxge_tx_watchdog(struct net_device *dev)
+static void vxge_tx_watchdog(struct net_device *dev)
{
struct vxgedev *vdev;
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
vdev->cric_err_event = VXGE_HW_EVENT_RESET_START;
- vxge_reset(vdev);
+ schedule_work(&vdev->reset_task);
vxge_debug_entryexit(VXGE_TRACE,
"%s:%d Exiting...", __func__, __LINE__);
}
@@ -3012,7 +3154,7 @@ vxge_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
vpath = &vdev->vpaths[0];
if ((NULL == grp) && (vpath->is_open)) {
@@ -3061,7 +3203,7 @@ vxge_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
struct vxge_vpath *vpath;
int vp_id;
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
/* Add these vlan to the vid table */
for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
@@ -3088,7 +3230,7 @@ vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- vdev = (struct vxgedev *)netdev_priv(dev);
+ vdev = netdev_priv(dev);
vlan_group_set_device(vdev->vlgrp, vid, NULL);
@@ -3110,21 +3252,31 @@ static const struct net_device_ops vxge_netdev_ops = {
.ndo_start_xmit = vxge_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = vxge_set_multicast,
-
.ndo_do_ioctl = vxge_ioctl,
-
.ndo_set_mac_address = vxge_set_mac_addr,
.ndo_change_mtu = vxge_change_mtu,
.ndo_vlan_rx_register = vxge_vlan_rx_register,
.ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid,
.ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid,
-
.ndo_tx_timeout = vxge_tx_watchdog,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = vxge_netpoll,
#endif
};
+static int __devinit vxge_device_revision(struct vxgedev *vdev)
+{
+ int ret;
+ u8 revision;
+
+ ret = pci_read_config_byte(vdev->pdev, PCI_REVISION_ID, &revision);
+ if (ret)
+ return -EIO;
+
+ vdev->titan1 = (revision == VXGE_HW_TITAN1_PCI_REVISION);
+ return 0;
+}
+
static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
struct vxge_config *config,
int high_dma, int no_of_vpath,
@@ -3163,6 +3315,11 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
vdev->pdev = hldev->pdev;
memcpy(&vdev->config, config, sizeof(struct vxge_config));
vdev->rx_csum = 1; /* Enable Rx CSUM by default. */
+ vdev->rx_hwts = 0;
+
+ ret = vxge_device_revision(vdev);
+ if (ret < 0)
+ goto _out1;
SET_NETDEV_DEV(ndev, &vdev->pdev->dev);
@@ -3175,9 +3332,15 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
ndev->netdev_ops = &vxge_netdev_ops;
ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT;
+ INIT_WORK(&vdev->reset_task, vxge_reset);
vxge_initialize_ethtool_ops(ndev);
+ if (vdev->config.rth_steering != NO_STEERING) {
+ ndev->features |= NETIF_F_RXHASH;
+ hldev->config.rth_en = VXGE_HW_RTH_ENABLE;
+ }
+
/* Allocate memory for vpath */
vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) *
no_of_vpath, GFP_KERNEL);
@@ -3191,7 +3354,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
ndev->features |= NETIF_F_SG;
- ndev->features |= NETIF_F_HW_CSUM;
+ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
"%s : checksuming enabled", __func__);
@@ -3227,6 +3390,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
"%s: Ethernet device registered",
ndev->name);
+ hldev->ndev = ndev;
*vdev_out = vdev;
/* Resetting the Device stats */
@@ -3261,36 +3425,29 @@ _out0:
*
* This function will unregister and free network device
*/
-static void
-vxge_device_unregister(struct __vxge_hw_device *hldev)
+static void vxge_device_unregister(struct __vxge_hw_device *hldev)
{
struct vxgedev *vdev;
struct net_device *dev;
char buf[IFNAMSIZ];
-#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
- (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
- u32 level_trace;
-#endif
dev = hldev->ndev;
vdev = netdev_priv(dev);
-#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
- (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
- level_trace = vdev->level_trace;
-#endif
- vxge_debug_entryexit(level_trace,
- "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
- memcpy(buf, vdev->ndev->name, IFNAMSIZ);
+ vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d", vdev->ndev->name,
+ __func__, __LINE__);
+
+ strncpy(buf, dev->name, IFNAMSIZ);
+
+ flush_work_sync(&vdev->reset_task);
/* in 2.6 will call stop() if device is up */
unregister_netdev(dev);
- flush_scheduled_work();
-
- vxge_debug_init(level_trace, "%s: ethernet device unregistered", buf);
- vxge_debug_entryexit(level_trace,
- "%s: %s:%d Exiting...", buf, __func__, __LINE__);
+ vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered",
+ buf);
+ vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d Exiting...", buf,
+ __func__, __LINE__);
}
/*
@@ -3304,7 +3461,7 @@ vxge_callback_crit_err(struct __vxge_hw_device *hldev,
enum vxge_hw_event type, u64 vp_id)
{
struct net_device *dev = hldev->ndev;
- struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxgedev *vdev = netdev_priv(dev);
struct vxge_vpath *vpath = NULL;
int vpath_idx;
@@ -3527,9 +3684,9 @@ static int __devinit vxge_config_vpaths(
device_config->vp_config[i].tti.timer_ac_en =
VXGE_HW_TIM_TIMER_AC_ENABLE;
- /* For msi-x with napi (each vector
- has a handler of its own) -
- Set CI to OFF for all vpaths */
+ /* For msi-x with napi (each vector has a handler of its own) -
+ * Set CI to OFF for all vpaths
+ */
device_config->vp_config[i].tti.timer_ci_en =
VXGE_HW_TIM_TIMER_CI_DISABLE;
@@ -3559,10 +3716,13 @@ static int __devinit vxge_config_vpaths(
device_config->vp_config[i].ring.ring_blocks =
VXGE_HW_DEF_RING_BLOCKS;
+
device_config->vp_config[i].ring.buffer_mode =
VXGE_HW_RING_RXD_BUFFER_MODE_1;
+
device_config->vp_config[i].ring.rxds_limit =
VXGE_HW_DEF_RING_RXDS_LIMIT;
+
device_config->vp_config[i].ring.scatter_mode =
VXGE_HW_RING_SCATTER_MODE_A;
@@ -3642,6 +3802,7 @@ static void __devinit vxge_device_config_init(
device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX;
break;
}
+
/* Timer period between device poll */
device_config->device_poll_millis = VXGE_TIMER_DELAY;
@@ -3653,16 +3814,10 @@ static void __devinit vxge_device_config_init(
vxge_debug_ll_config(VXGE_TRACE, "%s : Device Config Params ",
__func__);
- vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_initial : %d",
- device_config->dma_blockpool_initial);
- vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_max : %d",
- device_config->dma_blockpool_max);
vxge_debug_ll_config(VXGE_TRACE, "intr_mode : %d",
device_config->intr_mode);
vxge_debug_ll_config(VXGE_TRACE, "device_poll_millis : %d",
device_config->device_poll_millis);
- vxge_debug_ll_config(VXGE_TRACE, "rts_mac_en : %d",
- device_config->rts_mac_en);
vxge_debug_ll_config(VXGE_TRACE, "rth_en : %d",
device_config->rth_en);
vxge_debug_ll_config(VXGE_TRACE, "rth_it_type : %d",
@@ -3751,9 +3906,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
vxge_debug_init(VXGE_TRACE,
"%s: MAC Address learning enabled", vdev->ndev->name);
- vxge_debug_init(VXGE_TRACE,
- "%s: Rx doorbell mode enabled", vdev->ndev->name);
-
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
if (!vxge_bVALn(vpath_mask, i, 1))
continue;
@@ -3766,14 +3918,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
((struct __vxge_hw_device *)(vdev->devh))->
config.vp_config[i].rpa_strip_vlan_tag
? "Enabled" : "Disabled");
- vxge_debug_init(VXGE_TRACE,
- "%s: Ring blocks : %d", vdev->ndev->name,
- ((struct __vxge_hw_device *)(vdev->devh))->
- config.vp_config[i].ring.ring_blocks);
- vxge_debug_init(VXGE_TRACE,
- "%s: Fifo blocks : %d", vdev->ndev->name,
- ((struct __vxge_hw_device *)(vdev->devh))->
- config.vp_config[i].fifo.fifo_blocks);
vxge_debug_ll_config(VXGE_TRACE,
"%s: Max frags : %d", vdev->ndev->name,
((struct __vxge_hw_device *)(vdev->devh))->
@@ -3813,8 +3957,7 @@ static int vxge_pm_resume(struct pci_dev *pdev)
static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(pdev);
+ struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
struct net_device *netdev = hldev->ndev;
netif_device_detach(netdev);
@@ -3843,8 +3986,7 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
*/
static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
{
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(pdev);
+ struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
struct net_device *netdev = hldev->ndev;
struct vxgedev *vdev = netdev_priv(netdev);
@@ -3855,7 +3997,7 @@ static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
}
pci_set_master(pdev);
- vxge_reset(vdev);
+ do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -3869,8 +4011,7 @@ static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
*/
static void vxge_io_resume(struct pci_dev *pdev)
{
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(pdev);
+ struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
struct net_device *netdev = hldev->ndev;
if (netif_running(netdev)) {
@@ -3914,6 +4055,157 @@ static inline u32 vxge_get_num_vfs(u64 function_mode)
return num_functions;
}
+int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override)
+{
+ struct __vxge_hw_device *hldev = vdev->devh;
+ u32 maj, min, bld, cmaj, cmin, cbld;
+ enum vxge_hw_status status;
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, fw_name, &vdev->pdev->dev);
+ if (ret) {
+ vxge_debug_init(VXGE_ERR, "%s: Firmware file '%s' not found",
+ VXGE_DRIVER_NAME, fw_name);
+ goto out;
+ }
+
+ /* Load the new firmware onto the adapter */
+ status = vxge_update_fw_image(hldev, fw->data, fw->size);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "%s: FW image download to adapter failed '%s'.",
+ VXGE_DRIVER_NAME, fw_name);
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Read the version of the new firmware */
+ status = vxge_hw_upgrade_read_version(hldev, &maj, &min, &bld);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "%s: Upgrade read version failed '%s'.",
+ VXGE_DRIVER_NAME, fw_name);
+ ret = -EIO;
+ goto out;
+ }
+
+ cmaj = vdev->config.device_hw_info.fw_version.major;
+ cmin = vdev->config.device_hw_info.fw_version.minor;
+ cbld = vdev->config.device_hw_info.fw_version.build;
+ /* It's possible the version in /lib/firmware is not the latest version.
+ * If so, we could get into a loop of trying to upgrade to the latest
+ * and flashing the older version.
+ */
+ if (VXGE_FW_VER(maj, min, bld) == VXGE_FW_VER(cmaj, cmin, cbld) &&
+ !override) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ printk(KERN_NOTICE "Upgrade to firmware version %d.%d.%d commencing\n",
+ maj, min, bld);
+
+ /* Flash the adapter with the new firmware */
+ status = vxge_hw_flash_fw(hldev);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: Upgrade commit failed '%s'.",
+ VXGE_DRIVER_NAME, fw_name);
+ ret = -EIO;
+ goto out;
+ }
+
+ printk(KERN_NOTICE "Upgrade of firmware successful! Adapter must be "
+ "hard reset before using, thus requiring a system reboot or a "
+ "hotplug event.\n");
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static int vxge_probe_fw_update(struct vxgedev *vdev)
+{
+ u32 maj, min, bld;
+ int ret, gpxe = 0;
+ char *fw_name;
+
+ maj = vdev->config.device_hw_info.fw_version.major;
+ min = vdev->config.device_hw_info.fw_version.minor;
+ bld = vdev->config.device_hw_info.fw_version.build;
+
+ if (VXGE_FW_VER(maj, min, bld) == VXGE_CERT_FW_VER)
+ return 0;
+
+ /* Ignore the build number when determining if the current firmware is
+ * "too new" to load the driver
+ */
+ if (VXGE_FW_VER(maj, min, 0) > VXGE_CERT_FW_VER) {
+ vxge_debug_init(VXGE_ERR, "%s: Firmware newer than last known "
+ "version, unable to load driver\n",
+ VXGE_DRIVER_NAME);
+ return -EINVAL;
+ }
+
+ /* Firmware 1.4.4 and older cannot be upgraded, and is too ancient to
+ * work with this driver.
+ */
+ if (VXGE_FW_VER(maj, min, bld) <= VXGE_FW_DEAD_VER) {
+ vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d cannot be "
+ "upgraded\n", VXGE_DRIVER_NAME, maj, min, bld);
+ return -EINVAL;
+ }
+
+ /* If file not specified, determine gPXE or not */
+ if (VXGE_FW_VER(maj, min, bld) >= VXGE_EPROM_FW_VER) {
+ int i;
+ for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++)
+ if (vdev->devh->eprom_versions[i]) {
+ gpxe = 1;
+ break;
+ }
+ }
+ if (gpxe)
+ fw_name = "vxge/X3fw-pxe.ncf";
+ else
+ fw_name = "vxge/X3fw.ncf";
+
+ ret = vxge_fw_upgrade(vdev, fw_name, 0);
+ /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on
+ * probe, so ignore them
+ */
+ if (ret != -EINVAL && ret != -ENOENT)
+ return -EIO;
+ else
+ ret = 0;
+
+ if (VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, VXGE_CERT_FW_VER_MINOR, 0) >
+ VXGE_FW_VER(maj, min, 0)) {
+ vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d is too old to"
+ " be used with this driver.\n"
+ "Please get the latest version from "
+ "ftp://ftp.s2io.com/pub/X3100-Drivers/FIRMWARE",
+ VXGE_DRIVER_NAME, maj, min, bld);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int __devinit is_sriov_initialized(struct pci_dev *pdev)
+{
+ int pos;
+ u16 ctrl;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos) {
+ pci_read_config_word(pdev, pos + PCI_SRIOV_CTRL, &ctrl);
+ if (ctrl & PCI_SRIOV_CTRL_VFE)
+ return 1;
+ }
+ return 0;
+}
+
/**
* vxge_probe
* @pdev : structure containing the PCI related information of the device.
@@ -3928,7 +4220,7 @@ static inline u32 vxge_get_num_vfs(u64 function_mode)
static int __devinit
vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
{
- struct __vxge_hw_device *hldev;
+ struct __vxge_hw_device *hldev;
enum vxge_hw_status status;
int ret;
int high_dma = 0;
@@ -3951,9 +4243,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
attr.pdev = pdev;
/* In SRIOV-17 mode, functions of the same adapter
- * can be deployed on different buses */
- if ((!pdev->is_virtfn) && ((bus != pdev->bus->number) ||
- (device != PCI_SLOT(pdev->devfn))))
+ * can be deployed on different buses
+ */
+ if (((bus != pdev->bus->number) || (device != PCI_SLOT(pdev->devfn))) &&
+ !pdev->is_virtfn)
new_device = 1;
bus = pdev->bus->number;
@@ -3971,6 +4264,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
driver_config->config_dev_cnt = 0;
driver_config->total_dev_cnt = 0;
}
+
/* Now making the CPU based no of vpath calculation
* applicable for individual functions as well.
*/
@@ -3993,11 +4287,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit0;
}
- ll_config = kzalloc(sizeof(*ll_config), GFP_KERNEL);
+ ll_config = kzalloc(sizeof(struct vxge_config), GFP_KERNEL);
if (!ll_config) {
ret = -ENOMEM;
vxge_debug_init(VXGE_ERR,
- "ll_config : malloc failed %s %d",
+ "device_config : malloc failed %s %d",
__FILE__, __LINE__);
goto _exit0;
}
@@ -4041,7 +4335,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit1;
}
- if (pci_request_regions(pdev, VXGE_DRIVER_NAME)) {
+ if (pci_request_region(pdev, 0, VXGE_DRIVER_NAME)) {
vxge_debug_init(VXGE_ERR,
"%s : request regions failed", __func__);
ret = -ENODEV;
@@ -4072,16 +4366,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
- if (ll_config->device_hw_info.fw_version.major !=
- VXGE_DRIVER_FW_VERSION_MAJOR) {
- vxge_debug_init(VXGE_ERR,
- "%s: Incorrect firmware version."
- "Please upgrade the firmware to version 1.x.x",
- VXGE_DRIVER_NAME);
- ret = -EINVAL;
- goto _exit3;
- }
-
vpath_mask = ll_config->device_hw_info.vpath_mask;
if (vpath_mask == 0) {
vxge_debug_ll_config(VXGE_TRACE,
@@ -4110,14 +4394,13 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
num_vfs = vxge_get_num_vfs(function_mode) - 1;
/* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
- if (is_sriov(function_mode) && (max_config_dev > 1) &&
- (ll_config->intr_type != INTA) &&
- (is_privileged == VXGE_HW_OK)) {
- ret = pci_enable_sriov(pdev, ((max_config_dev - 1) < num_vfs)
- ? (max_config_dev - 1) : num_vfs);
+ if (is_sriov(function_mode) && !is_sriov_initialized(pdev) &&
+ (ll_config->intr_type != INTA)) {
+ ret = pci_enable_sriov(pdev, num_vfs);
if (ret)
vxge_debug_ll_config(VXGE_ERR,
"Failed in enabling SRIOV mode: %d\n", ret);
+ /* No need to fail out, as an error here is non-fatal */
}
/*
@@ -4145,11 +4428,37 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
+ if (VXGE_FW_VER(ll_config->device_hw_info.fw_version.major,
+ ll_config->device_hw_info.fw_version.minor,
+ ll_config->device_hw_info.fw_version.build) >=
+ VXGE_EPROM_FW_VER) {
+ struct eprom_image img[VXGE_HW_MAX_ROM_IMAGES];
+
+ status = vxge_hw_vpath_eprom_img_ver_get(hldev, img);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: Reading of EPROM failed",
+ VXGE_DRIVER_NAME);
+ /* This is a non-fatal error, continue */
+ }
+
+ for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) {
+ hldev->eprom_versions[i] = img[i].version;
+ if (!img[i].is_valid)
+ break;
+ vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version "
+ "%d.%d.%d.%d\n", VXGE_DRIVER_NAME, i,
+ VXGE_EPROM_IMG_MAJOR(img[i].version),
+ VXGE_EPROM_IMG_MINOR(img[i].version),
+ VXGE_EPROM_IMG_FIX(img[i].version),
+ VXGE_EPROM_IMG_BUILD(img[i].version));
+ }
+ }
+
/* if FCS stripping is not disabled in MAC fail driver load */
- if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "%s: FCS stripping is not disabled in MAC"
- " failing driver load", VXGE_DRIVER_NAME);
+ status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC"
+ " failing driver load", VXGE_DRIVER_NAME);
ret = -EINVAL;
goto _exit4;
}
@@ -4163,28 +4472,32 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
ll_config->addr_learn_en = addr_learn_en;
ll_config->rth_algorithm = RTH_ALG_JENKINS;
- ll_config->rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
- ll_config->rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config->rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config->rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config->rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config->rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_tcpipv4 = 1;
+ ll_config->rth_hash_type_ipv4 = 0;
+ ll_config->rth_hash_type_tcpipv6 = 0;
+ ll_config->rth_hash_type_ipv6 = 0;
+ ll_config->rth_hash_type_tcpipv6ex = 0;
+ ll_config->rth_hash_type_ipv6ex = 0;
ll_config->rth_bkt_sz = RTH_BUCKET_SIZE;
ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
- if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath,
- &vdev)) {
+ ret = vxge_device_register(hldev, ll_config, high_dma, no_of_vpath,
+ &vdev);
+ if (ret) {
ret = -EINVAL;
goto _exit4;
}
+ ret = vxge_probe_fw_update(vdev);
+ if (ret)
+ goto _exit5;
+
vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
vxge_hw_device_trace_level_get(hldev));
/* set private HW device info */
- hldev->ndev = vdev->ndev;
vdev->mtu = VXGE_HW_DEFAULT_MTU;
vdev->bar0 = attr.bar0;
vdev->max_vpath_supported = max_vpath_supported;
@@ -4278,15 +4591,13 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Copy the station mac address to the list */
for (i = 0; i < vdev->no_of_vpath; i++) {
- entry = (struct vxge_mac_addrs *)
- kzalloc(sizeof(struct vxge_mac_addrs),
- GFP_KERNEL);
+ entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_KERNEL);
if (NULL == entry) {
vxge_debug_init(VXGE_ERR,
"%s: mac_addr_list : memory allocation failed",
vdev->ndev->name);
ret = -EPERM;
- goto _exit5;
+ goto _exit6;
}
macaddr = (u8 *)&entry->macaddr;
memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4326,10 +4637,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
kfree(ll_config);
return 0;
-_exit5:
+_exit6:
for (i = 0; i < vdev->no_of_vpath; i++)
vxge_free_mac_add_list(&vdev->vpaths[i]);
-
+_exit5:
vxge_device_unregister(hldev);
_exit4:
pci_disable_sriov(pdev);
@@ -4337,7 +4648,7 @@ _exit4:
_exit3:
iounmap(attr.bar0);
_exit2:
- pci_release_regions(pdev);
+ pci_release_region(pdev, 0);
_exit1:
pci_disable_device(pdev);
_exit0:
@@ -4354,34 +4665,25 @@ _exit0:
* Description: This function is called by the Pci subsystem to release a
* PCI device and free up all resource held up by the device.
*/
-static void __devexit
-vxge_remove(struct pci_dev *pdev)
+static void __devexit vxge_remove(struct pci_dev *pdev)
{
- struct __vxge_hw_device *hldev;
+ struct __vxge_hw_device *hldev;
struct vxgedev *vdev = NULL;
struct net_device *dev;
int i = 0;
-#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
- (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
- u32 level_trace;
-#endif
- hldev = (struct __vxge_hw_device *) pci_get_drvdata(pdev);
+ hldev = pci_get_drvdata(pdev);
if (hldev == NULL)
return;
+
dev = hldev->ndev;
vdev = netdev_priv(dev);
-#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \
- (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK))
- level_trace = vdev->level_trace;
-#endif
- vxge_debug_entryexit(level_trace,
- "%s:%d", __func__, __LINE__);
+ vxge_debug_entryexit(vdev->level_trace, "%s:%d", __func__, __LINE__);
- vxge_debug_init(level_trace,
- "%s : removing PCI device...", __func__);
+ vxge_debug_init(vdev->level_trace, "%s : removing PCI device...",
+ __func__);
vxge_device_unregister(hldev);
for (i = 0; i < vdev->no_of_vpath; i++) {
@@ -4394,21 +4696,19 @@ vxge_remove(struct pci_dev *pdev)
iounmap(vdev->bar0);
- pci_disable_sriov(pdev);
-
/* we are safe to free it now */
free_netdev(dev);
- vxge_debug_init(level_trace,
- "%s:%d Device unregistered", __func__, __LINE__);
+ vxge_debug_init(vdev->level_trace, "%s:%d Device unregistered",
+ __func__, __LINE__);
vxge_hw_device_terminate(hldev);
pci_disable_device(pdev);
- pci_release_regions(pdev);
+ pci_release_region(pdev, 0);
pci_set_drvdata(pdev, NULL);
- vxge_debug_entryexit(level_trace,
- "%s:%d Exiting...", __func__, __LINE__);
+ vxge_debug_entryexit(vdev->level_trace, "%s:%d Exiting...", __func__,
+ __LINE__);
}
static struct pci_error_handlers vxge_err_handler = {
@@ -4444,6 +4744,10 @@ vxge_starter(void)
return -ENOMEM;
ret = pci_register_driver(&vxge_driver);
+ if (ret) {
+ kfree(driver_config);
+ goto err;
+ }
if (driver_config->config_dev_cnt &&
(driver_config->config_dev_cnt != driver_config->total_dev_cnt))
@@ -4451,10 +4755,7 @@ vxge_starter(void)
"%s: Configured %d of %d devices",
VXGE_DRIVER_NAME, driver_config->config_dev_cnt,
driver_config->total_dev_cnt);
-
- if (ret)
- kfree(driver_config);
-
+err:
return ret;
}
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index de64536cb7d0..5746fedc356f 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -29,6 +29,9 @@
#define PCI_DEVICE_ID_TITAN_WIN 0x5733
#define PCI_DEVICE_ID_TITAN_UNI 0x5833
+#define VXGE_HW_TITAN1_PCI_REVISION 1
+#define VXGE_HW_TITAN1A_PCI_REVISION 2
+
#define VXGE_USE_DEFAULT 0xffffffff
#define VXGE_HW_VPATH_MSIX_ACTIVE 4
#define VXGE_ALARM_MSIX_ID 2
@@ -53,11 +56,13 @@
#define VXGE_TTI_BTIMER_VAL 250000
-#define VXGE_TTI_LTIMER_VAL 1000
-#define VXGE_TTI_RTIMER_VAL 0
-#define VXGE_RTI_BTIMER_VAL 250
-#define VXGE_RTI_LTIMER_VAL 100
-#define VXGE_RTI_RTIMER_VAL 0
+#define VXGE_TTI_LTIMER_VAL 1000
+#define VXGE_T1A_TTI_LTIMER_VAL 80
+#define VXGE_TTI_RTIMER_VAL 0
+#define VXGE_T1A_TTI_RTIMER_VAL 400
+#define VXGE_RTI_BTIMER_VAL 250
+#define VXGE_RTI_LTIMER_VAL 100
+#define VXGE_RTI_RTIMER_VAL 0
#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH
#define VXGE_ISR_POLLING_CNT 8
#define VXGE_MAX_CONFIG_DEV 0xFF
@@ -76,14 +81,32 @@
#define TTI_TX_UFC_B 40
#define TTI_TX_UFC_C 60
#define TTI_TX_UFC_D 100
+#define TTI_T1A_TX_UFC_A 30
+#define TTI_T1A_TX_UFC_B 80
+/* Slope - (max_mtu - min_mtu)/(max_mtu_ufc - min_mtu_ufc) */
+/* Slope - 93 */
+/* 60 - 9k Mtu, 140 - 1.5k mtu */
+#define TTI_T1A_TX_UFC_C(mtu) (60 + ((VXGE_HW_MAX_MTU - mtu) / 93))
+
+/* Slope - 37 */
+/* 100 - 9k Mtu, 300 - 1.5k mtu */
+#define TTI_T1A_TX_UFC_D(mtu) (100 + ((VXGE_HW_MAX_MTU - mtu) / 37))
+
+
+#define RTI_RX_URANGE_A 5
+#define RTI_RX_URANGE_B 15
+#define RTI_RX_URANGE_C 40
+#define RTI_T1A_RX_URANGE_A 1
+#define RTI_T1A_RX_URANGE_B 20
+#define RTI_T1A_RX_URANGE_C 50
+#define RTI_RX_UFC_A 1
+#define RTI_RX_UFC_B 5
+#define RTI_RX_UFC_C 10
+#define RTI_RX_UFC_D 15
+#define RTI_T1A_RX_UFC_B 20
+#define RTI_T1A_RX_UFC_C 50
+#define RTI_T1A_RX_UFC_D 60
-#define RTI_RX_URANGE_A 5
-#define RTI_RX_URANGE_B 15
-#define RTI_RX_URANGE_C 40
-#define RTI_RX_UFC_A 1
-#define RTI_RX_UFC_B 5
-#define RTI_RX_UFC_C 10
-#define RTI_RX_UFC_D 15
/* Milli secs timer period */
#define VXGE_TIMER_DELAY 10000
@@ -145,15 +168,15 @@ struct vxge_config {
int addr_learn_en;
- int rth_steering;
- int rth_algorithm;
- int rth_hash_type_tcpipv4;
- int rth_hash_type_ipv4;
- int rth_hash_type_tcpipv6;
- int rth_hash_type_ipv6;
- int rth_hash_type_tcpipv6ex;
- int rth_hash_type_ipv6ex;
- int rth_bkt_sz;
+ u32 rth_steering:2,
+ rth_algorithm:2,
+ rth_hash_type_tcpipv4:1,
+ rth_hash_type_ipv4:1,
+ rth_hash_type_tcpipv6:1,
+ rth_hash_type_ipv6:1,
+ rth_hash_type_tcpipv6ex:1,
+ rth_hash_type_ipv6ex:1,
+ rth_bkt_sz:8;
int rth_jhash_golden_ratio;
int tx_steering_type;
int fifo_indicate_max_pkts;
@@ -248,8 +271,9 @@ struct vxge_ring {
*/
int driver_id;
- /* copy of the flag indicating whether rx_csum is to be used */
- u32 rx_csum;
+ /* copy of the flag indicating whether rx_csum is to be used */
+ u32 rx_csum:1,
+ rx_hwts:1;
int pkts_processed;
int budget;
@@ -281,8 +305,8 @@ struct vxge_vpath {
int is_configured;
int is_open;
struct vxgedev *vdev;
- u8 (macaddr)[ETH_ALEN];
- u8 (macmask)[ETH_ALEN];
+ u8 macaddr[ETH_ALEN];
+ u8 macmask[ETH_ALEN];
#define VXGE_MAX_LEARN_MAC_ADDR_CNT 2048
/* mac addresses currently programmed into NIC */
@@ -327,7 +351,9 @@ struct vxgedev {
u16 all_multi_flg;
/* A flag indicating whether rx_csum is to be used or not. */
- u32 rx_csum;
+ u32 rx_csum:1,
+ rx_hwts:1,
+ titan1:1;
struct vxge_msix_entry *vxge_entries;
struct msix_entry *entries;
@@ -369,6 +395,7 @@ struct vxgedev {
u32 level_err;
u32 level_trace;
char fw_version[VXGE_HW_FW_STRLEN];
+ struct work_struct reset_task;
};
struct vxge_rx_priv {
@@ -387,8 +414,6 @@ struct vxge_tx_priv {
static int p = val; \
module_param(p, int, 0)
-#define vxge_os_bug(fmt...) { printk(fmt); BUG(); }
-
#define vxge_os_timer(timer, handle, arg, exp) do { \
init_timer(&timer); \
timer.function = handle; \
@@ -396,7 +421,10 @@ struct vxge_tx_priv {
mod_timer(&timer, (jiffies + exp)); \
} while (0);
-extern void vxge_initialize_ethtool_ops(struct net_device *ndev);
+void vxge_initialize_ethtool_ops(struct net_device *ndev);
+enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
+int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override);
+
/**
* #define VXGE_DEBUG_INIT: debug for initialization functions
* #define VXGE_DEBUG_TX : debug transmit related functions
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 3dd5c9615ef9..3e658b175947 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -49,6 +49,33 @@
#define VXGE_HW_TITAN_VPMGMT_REG_SPACES 17
#define VXGE_HW_TITAN_VPATH_REG_SPACES 17
+#define VXGE_HW_FW_API_GET_EPROM_REV 31
+
+#define VXGE_EPROM_IMG_MAJOR(val) (u32) vxge_bVALn(val, 48, 4)
+#define VXGE_EPROM_IMG_MINOR(val) (u32) vxge_bVALn(val, 52, 4)
+#define VXGE_EPROM_IMG_FIX(val) (u32) vxge_bVALn(val, 56, 4)
+#define VXGE_EPROM_IMG_BUILD(val) (u32) vxge_bVALn(val, 60, 4)
+
+#define VXGE_HW_GET_EPROM_IMAGE_INDEX(val) vxge_bVALn(val, 16, 8)
+#define VXGE_HW_GET_EPROM_IMAGE_VALID(val) vxge_bVALn(val, 31, 1)
+#define VXGE_HW_GET_EPROM_IMAGE_TYPE(val) vxge_bVALn(val, 40, 8)
+#define VXGE_HW_GET_EPROM_IMAGE_REV(val) vxge_bVALn(val, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(val) vxge_vBIT(val, 16, 8)
+
+#define VXGE_HW_FW_API_GET_FUNC_MODE 29
+#define VXGE_HW_GET_FUNC_MODE_VAL(val) (val & 0xFF)
+
+#define VXGE_HW_FW_UPGRADE_MEMO 13
+#define VXGE_HW_FW_UPGRADE_ACTION 16
+#define VXGE_HW_FW_UPGRADE_OFFSET_START 2
+#define VXGE_HW_FW_UPGRADE_OFFSET_SEND 3
+#define VXGE_HW_FW_UPGRADE_OFFSET_COMMIT 4
+#define VXGE_HW_FW_UPGRADE_OFFSET_READ 5
+
+#define VXGE_HW_FW_UPGRADE_BLK_SIZE 16
+#define VXGE_HW_UPGRADE_GET_RET_ERR_CODE(val) (val & 0xff)
+#define VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(val) ((val >> 8) & 0xff)
+
#define VXGE_HW_ASIC_MODE_RESERVED 0
#define VXGE_HW_ASIC_MODE_NO_IOV 1
#define VXGE_HW_ASIC_MODE_SR_IOV 2
@@ -165,13 +192,13 @@
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE 2
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN 3
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG 5
-#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6
+#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG 7
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK 8
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY 9
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS 10
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS 11
-#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12
+#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12
#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO 13
#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
@@ -437,6 +464,7 @@
#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \
vxge_bVALn(bits, 48, 16)
#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16)
+#define VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(bits) vxge_bVALn(bits, 0, 8)
#define VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\
vxge_bVALn(bits, 0, 18)
@@ -3998,6 +4026,7 @@ struct vxge_hw_vpath_reg {
#define VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN vxge_mBIT(9)
#define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9)
#define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9)
+#define VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val) vxge_bVALn(val, 36, 9)
/*0x00a78*/ u64 prc_cfg7;
#define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2)
#define VXGE_HW_PRC_CFG7_SMART_SCAT_EN vxge_mBIT(11)
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index 4bdb611a6842..4c10d6c4075f 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -17,13 +17,6 @@
#include "vxge-config.h"
#include "vxge-main.h"
-static enum vxge_hw_status
-__vxge_hw_device_handle_error(struct __vxge_hw_device *hldev,
- u32 vp_id, enum vxge_hw_event type);
-static enum vxge_hw_status
-__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
- u32 skip_alarms);
-
/*
* vxge_hw_vpath_intr_enable - Enable vpath interrupts.
* @vp: Virtual Path handle.
@@ -419,6 +412,384 @@ void vxge_hw_device_flush_io(struct __vxge_hw_device *hldev)
}
/**
+ * __vxge_hw_device_handle_error - Handle error
+ * @hldev: HW device
+ * @vp_id: Vpath Id
+ * @type: Error type. Please see enum vxge_hw_event{}
+ *
+ * Handle error.
+ */
+static enum vxge_hw_status
+__vxge_hw_device_handle_error(struct __vxge_hw_device *hldev, u32 vp_id,
+ enum vxge_hw_event type)
+{
+ switch (type) {
+ case VXGE_HW_EVENT_UNKNOWN:
+ break;
+ case VXGE_HW_EVENT_RESET_START:
+ case VXGE_HW_EVENT_RESET_COMPLETE:
+ case VXGE_HW_EVENT_LINK_DOWN:
+ case VXGE_HW_EVENT_LINK_UP:
+ goto out;
+ case VXGE_HW_EVENT_ALARM_CLEARED:
+ goto out;
+ case VXGE_HW_EVENT_ECCERR:
+ case VXGE_HW_EVENT_MRPCIM_ECCERR:
+ goto out;
+ case VXGE_HW_EVENT_FIFO_ERR:
+ case VXGE_HW_EVENT_VPATH_ERR:
+ case VXGE_HW_EVENT_CRITICAL_ERR:
+ case VXGE_HW_EVENT_SERR:
+ break;
+ case VXGE_HW_EVENT_SRPCIM_SERR:
+ case VXGE_HW_EVENT_MRPCIM_SERR:
+ goto out;
+ case VXGE_HW_EVENT_SLOT_FREEZE:
+ break;
+ default:
+ vxge_assert(0);
+ goto out;
+ }
+
+ /* notify driver */
+ if (hldev->uld_callbacks.crit_err)
+ hldev->uld_callbacks.crit_err(
+ (struct __vxge_hw_device *)hldev,
+ type, vp_id);
+out:
+
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_handle_link_down_ind
+ * @hldev: HW device handle.
+ *
+ * Link down indication handler. The function is invoked by HW when
+ * Titan indicates that the link is down.
+ */
+static enum vxge_hw_status
+__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
+{
+ /*
+ * If the previous link state is not down, return.
+ */
+ if (hldev->link_state == VXGE_HW_LINK_DOWN)
+ goto exit;
+
+ hldev->link_state = VXGE_HW_LINK_DOWN;
+
+ /* notify driver */
+ if (hldev->uld_callbacks.link_down)
+ hldev->uld_callbacks.link_down(hldev);
+exit:
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_device_handle_link_up_ind
+ * @hldev: HW device handle.
+ *
+ * Link up indication handler. The function is invoked by HW when
+ * Titan indicates that the link is up for programmable amount of time.
+ */
+static enum vxge_hw_status
+__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
+{
+ /*
+ * If the previous link state is not down, return.
+ */
+ if (hldev->link_state == VXGE_HW_LINK_UP)
+ goto exit;
+
+ hldev->link_state = VXGE_HW_LINK_UP;
+
+ /* notify driver */
+ if (hldev->uld_callbacks.link_up)
+ hldev->uld_callbacks.link_up(hldev);
+exit:
+ return VXGE_HW_OK;
+}
+
+/*
+ * __vxge_hw_vpath_alarm_process - Process Alarms.
+ * @vpath: Virtual Path.
+ * @skip_alarms: Do not clear the alarms
+ *
+ * Process vpath alarms.
+ *
+ */
+static enum vxge_hw_status
+__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
+ u32 skip_alarms)
+{
+ u64 val64;
+ u64 alarm_status;
+ u64 pic_status;
+ struct __vxge_hw_device *hldev = NULL;
+ enum vxge_hw_event alarm_event = VXGE_HW_EVENT_UNKNOWN;
+ u64 mask64;
+ struct vxge_hw_vpath_stats_sw_info *sw_stats;
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+
+ if (vpath == NULL) {
+ alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
+ alarm_event);
+ goto out2;
+ }
+
+ hldev = vpath->hldev;
+ vp_reg = vpath->vp_reg;
+ alarm_status = readq(&vp_reg->vpath_general_int_status);
+
+ if (alarm_status == VXGE_HW_ALL_FOXES) {
+ alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE,
+ alarm_event);
+ goto out;
+ }
+
+ sw_stats = vpath->sw_stats;
+
+ if (alarm_status & ~(
+ VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT |
+ VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT |
+ VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT |
+ VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) {
+ sw_stats->error_stats.unknown_alarms++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
+ alarm_event);
+ goto out;
+ }
+
+ if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) {
+
+ val64 = readq(&vp_reg->xgmac_vp_int_status);
+
+ if (val64 &
+ VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) {
+
+ val64 = readq(&vp_reg->asic_ntwk_vp_err_reg);
+
+ if (((val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) &&
+ (!(val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) ||
+ ((val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) &&
+ (!(val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
+ ))) {
+ sw_stats->error_stats.network_sustained_fault++;
+
+ writeq(
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT,
+ &vp_reg->asic_ntwk_vp_err_mask);
+
+ __vxge_hw_device_handle_link_down_ind(hldev);
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_LINK_DOWN, alarm_event);
+ }
+
+ if (((val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) &&
+ (!(val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) ||
+ ((val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) &&
+ (!(val64 &
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
+ ))) {
+
+ sw_stats->error_stats.network_sustained_ok++;
+
+ writeq(
+ VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK,
+ &vp_reg->asic_ntwk_vp_err_mask);
+
+ __vxge_hw_device_handle_link_up_ind(hldev);
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_LINK_UP, alarm_event);
+ }
+
+ writeq(VXGE_HW_INTR_MASK_ALL,
+ &vp_reg->asic_ntwk_vp_err_reg);
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_ALARM_CLEARED, alarm_event);
+
+ if (skip_alarms)
+ return VXGE_HW_OK;
+ }
+ }
+
+ if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT) {
+
+ pic_status = readq(&vp_reg->vpath_ppif_int_status);
+
+ if (pic_status &
+ VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT) {
+
+ val64 = readq(&vp_reg->general_errors_reg);
+ mask64 = readq(&vp_reg->general_errors_mask);
+
+ if ((val64 &
+ VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET) &
+ ~mask64) {
+ sw_stats->error_stats.ini_serr_det++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_SERR, alarm_event);
+ }
+
+ if ((val64 &
+ VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW) &
+ ~mask64) {
+ sw_stats->error_stats.dblgen_fifo0_overflow++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_FIFO_ERR, alarm_event);
+ }
+
+ if ((val64 &
+ VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR) &
+ ~mask64)
+ sw_stats->error_stats.statsb_pif_chain_error++;
+
+ if ((val64 &
+ VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ) &
+ ~mask64)
+ sw_stats->error_stats.statsb_drop_timeout++;
+
+ if ((val64 &
+ VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS) &
+ ~mask64)
+ sw_stats->error_stats.target_illegal_access++;
+
+ if (!skip_alarms) {
+ writeq(VXGE_HW_INTR_MASK_ALL,
+ &vp_reg->general_errors_reg);
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_ALARM_CLEARED,
+ alarm_event);
+ }
+ }
+
+ if (pic_status &
+ VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT) {
+
+ val64 = readq(&vp_reg->kdfcctl_errors_reg);
+ mask64 = readq(&vp_reg->kdfcctl_errors_mask);
+
+ if ((val64 &
+ VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR) &
+ ~mask64) {
+ sw_stats->error_stats.kdfcctl_fifo0_overwrite++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_FIFO_ERR,
+ alarm_event);
+ }
+
+ if ((val64 &
+ VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON) &
+ ~mask64) {
+ sw_stats->error_stats.kdfcctl_fifo0_poison++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_FIFO_ERR,
+ alarm_event);
+ }
+
+ if ((val64 &
+ VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR) &
+ ~mask64) {
+ sw_stats->error_stats.kdfcctl_fifo0_dma_error++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_FIFO_ERR,
+ alarm_event);
+ }
+
+ if (!skip_alarms) {
+ writeq(VXGE_HW_INTR_MASK_ALL,
+ &vp_reg->kdfcctl_errors_reg);
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_ALARM_CLEARED,
+ alarm_event);
+ }
+ }
+
+ }
+
+ if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT) {
+
+ val64 = readq(&vp_reg->wrdma_alarm_status);
+
+ if (val64 & VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT) {
+
+ val64 = readq(&vp_reg->prc_alarm_reg);
+ mask64 = readq(&vp_reg->prc_alarm_mask);
+
+ if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP)&
+ ~mask64)
+ sw_stats->error_stats.prc_ring_bumps++;
+
+ if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR) &
+ ~mask64) {
+ sw_stats->error_stats.prc_rxdcm_sc_err++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_VPATH_ERR,
+ alarm_event);
+ }
+
+ if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT)
+ & ~mask64) {
+ sw_stats->error_stats.prc_rxdcm_sc_abort++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_VPATH_ERR,
+ alarm_event);
+ }
+
+ if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR)
+ & ~mask64) {
+ sw_stats->error_stats.prc_quanta_size_err++;
+
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_VPATH_ERR,
+ alarm_event);
+ }
+
+ if (!skip_alarms) {
+ writeq(VXGE_HW_INTR_MASK_ALL,
+ &vp_reg->prc_alarm_reg);
+ alarm_event = VXGE_HW_SET_LEVEL(
+ VXGE_HW_EVENT_ALARM_CLEARED,
+ alarm_event);
+ }
+ }
+ }
+out:
+ hldev->stats.sw_dev_err_stats.vpath_alarms++;
+out2:
+ if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) ||
+ (alarm_event == VXGE_HW_EVENT_UNKNOWN))
+ return VXGE_HW_OK;
+
+ __vxge_hw_device_handle_error(hldev, vpath->vp_id, alarm_event);
+
+ if (alarm_event == VXGE_HW_EVENT_SERR)
+ return VXGE_HW_ERR_CRITICAL;
+
+ return (alarm_event == VXGE_HW_EVENT_SLOT_FREEZE) ?
+ VXGE_HW_ERR_SLOT_FREEZE :
+ (alarm_event == VXGE_HW_EVENT_FIFO_ERR) ? VXGE_HW_ERR_FIFO :
+ VXGE_HW_ERR_VPATH;
+}
+
+/**
* vxge_hw_device_begin_irq - Begin IRQ processing.
* @hldev: HW device handle.
* @skip_alarms: Do not clear the alarms
@@ -513,108 +884,6 @@ exit:
return ret;
}
-/*
- * __vxge_hw_device_handle_link_up_ind
- * @hldev: HW device handle.
- *
- * Link up indication handler. The function is invoked by HW when
- * Titan indicates that the link is up for programmable amount of time.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
-{
- /*
- * If the previous link state is not down, return.
- */
- if (hldev->link_state == VXGE_HW_LINK_UP)
- goto exit;
-
- hldev->link_state = VXGE_HW_LINK_UP;
-
- /* notify driver */
- if (hldev->uld_callbacks.link_up)
- hldev->uld_callbacks.link_up(hldev);
-exit:
- return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_handle_link_down_ind
- * @hldev: HW device handle.
- *
- * Link down indication handler. The function is invoked by HW when
- * Titan indicates that the link is down.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
-{
- /*
- * If the previous link state is not down, return.
- */
- if (hldev->link_state == VXGE_HW_LINK_DOWN)
- goto exit;
-
- hldev->link_state = VXGE_HW_LINK_DOWN;
-
- /* notify driver */
- if (hldev->uld_callbacks.link_down)
- hldev->uld_callbacks.link_down(hldev);
-exit:
- return VXGE_HW_OK;
-}
-
-/**
- * __vxge_hw_device_handle_error - Handle error
- * @hldev: HW device
- * @vp_id: Vpath Id
- * @type: Error type. Please see enum vxge_hw_event{}
- *
- * Handle error.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_error(
- struct __vxge_hw_device *hldev,
- u32 vp_id,
- enum vxge_hw_event type)
-{
- switch (type) {
- case VXGE_HW_EVENT_UNKNOWN:
- break;
- case VXGE_HW_EVENT_RESET_START:
- case VXGE_HW_EVENT_RESET_COMPLETE:
- case VXGE_HW_EVENT_LINK_DOWN:
- case VXGE_HW_EVENT_LINK_UP:
- goto out;
- case VXGE_HW_EVENT_ALARM_CLEARED:
- goto out;
- case VXGE_HW_EVENT_ECCERR:
- case VXGE_HW_EVENT_MRPCIM_ECCERR:
- goto out;
- case VXGE_HW_EVENT_FIFO_ERR:
- case VXGE_HW_EVENT_VPATH_ERR:
- case VXGE_HW_EVENT_CRITICAL_ERR:
- case VXGE_HW_EVENT_SERR:
- break;
- case VXGE_HW_EVENT_SRPCIM_SERR:
- case VXGE_HW_EVENT_MRPCIM_SERR:
- goto out;
- case VXGE_HW_EVENT_SLOT_FREEZE:
- break;
- default:
- vxge_assert(0);
- goto out;
- }
-
- /* notify driver */
- if (hldev->uld_callbacks.crit_err)
- hldev->uld_callbacks.crit_err(
- (struct __vxge_hw_device *)hldev,
- type, vp_id);
-out:
-
- return VXGE_HW_OK;
-}
-
/**
* vxge_hw_device_clear_tx_rx - Acknowledge (that is, clear) the
* condition that has caused the Tx and RX interrupt.
@@ -699,8 +968,8 @@ _alloc_after_swap:
* Posts a dtr to work array.
*
*/
-static void vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel,
- void *dtrh)
+static void
+vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh)
{
vxge_assert(channel->work_arr[channel->post_index] == NULL);
@@ -911,10 +1180,6 @@ void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh)
*/
void vxge_hw_ring_rxd_post_post_wmb(struct __vxge_hw_ring *ring, void *rxdh)
{
- struct __vxge_hw_channel *channel;
-
- channel = &ring->channel;
-
wmb();
vxge_hw_ring_rxd_post_post(ring, rxdh);
}
@@ -975,7 +1240,7 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
*t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(control_0);
/* check whether it is not the end */
- if (!own || ((*t_code == VXGE_HW_RING_T_CODE_FRM_DROP) && own)) {
+ if (!own || *t_code == VXGE_HW_RING_T_CODE_FRM_DROP) {
vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control !=
0);
@@ -1868,284 +2133,6 @@ exit:
}
/*
- * __vxge_hw_vpath_alarm_process - Process Alarms.
- * @vpath: Virtual Path.
- * @skip_alarms: Do not clear the alarms
- *
- * Process vpath alarms.
- *
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
- u32 skip_alarms)
-{
- u64 val64;
- u64 alarm_status;
- u64 pic_status;
- struct __vxge_hw_device *hldev = NULL;
- enum vxge_hw_event alarm_event = VXGE_HW_EVENT_UNKNOWN;
- u64 mask64;
- struct vxge_hw_vpath_stats_sw_info *sw_stats;
- struct vxge_hw_vpath_reg __iomem *vp_reg;
-
- if (vpath == NULL) {
- alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
- alarm_event);
- goto out2;
- }
-
- hldev = vpath->hldev;
- vp_reg = vpath->vp_reg;
- alarm_status = readq(&vp_reg->vpath_general_int_status);
-
- if (alarm_status == VXGE_HW_ALL_FOXES) {
- alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE,
- alarm_event);
- goto out;
- }
-
- sw_stats = vpath->sw_stats;
-
- if (alarm_status & ~(
- VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT |
- VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT |
- VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT |
- VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) {
- sw_stats->error_stats.unknown_alarms++;
-
- alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
- alarm_event);
- goto out;
- }
-
- if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) {
-
- val64 = readq(&vp_reg->xgmac_vp_int_status);
-
- if (val64 &
- VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) {
-
- val64 = readq(&vp_reg->asic_ntwk_vp_err_reg);
-
- if (((val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) &&
- (!(val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) ||
- ((val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) &&
- (!(val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
- ))) {
- sw_stats->error_stats.network_sustained_fault++;
-
- writeq(
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT,
- &vp_reg->asic_ntwk_vp_err_mask);
-
- __vxge_hw_device_handle_link_down_ind(hldev);
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_LINK_DOWN, alarm_event);
- }
-
- if (((val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) &&
- (!(val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) ||
- ((val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) &&
- (!(val64 &
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
- ))) {
-
- sw_stats->error_stats.network_sustained_ok++;
-
- writeq(
- VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK,
- &vp_reg->asic_ntwk_vp_err_mask);
-
- __vxge_hw_device_handle_link_up_ind(hldev);
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_LINK_UP, alarm_event);
- }
-
- writeq(VXGE_HW_INTR_MASK_ALL,
- &vp_reg->asic_ntwk_vp_err_reg);
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_ALARM_CLEARED, alarm_event);
-
- if (skip_alarms)
- return VXGE_HW_OK;
- }
- }
-
- if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT) {
-
- pic_status = readq(&vp_reg->vpath_ppif_int_status);
-
- if (pic_status &
- VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT) {
-
- val64 = readq(&vp_reg->general_errors_reg);
- mask64 = readq(&vp_reg->general_errors_mask);
-
- if ((val64 &
- VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET) &
- ~mask64) {
- sw_stats->error_stats.ini_serr_det++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_SERR, alarm_event);
- }
-
- if ((val64 &
- VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW) &
- ~mask64) {
- sw_stats->error_stats.dblgen_fifo0_overflow++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_FIFO_ERR, alarm_event);
- }
-
- if ((val64 &
- VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR) &
- ~mask64)
- sw_stats->error_stats.statsb_pif_chain_error++;
-
- if ((val64 &
- VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ) &
- ~mask64)
- sw_stats->error_stats.statsb_drop_timeout++;
-
- if ((val64 &
- VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS) &
- ~mask64)
- sw_stats->error_stats.target_illegal_access++;
-
- if (!skip_alarms) {
- writeq(VXGE_HW_INTR_MASK_ALL,
- &vp_reg->general_errors_reg);
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_ALARM_CLEARED,
- alarm_event);
- }
- }
-
- if (pic_status &
- VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT) {
-
- val64 = readq(&vp_reg->kdfcctl_errors_reg);
- mask64 = readq(&vp_reg->kdfcctl_errors_mask);
-
- if ((val64 &
- VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR) &
- ~mask64) {
- sw_stats->error_stats.kdfcctl_fifo0_overwrite++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_FIFO_ERR,
- alarm_event);
- }
-
- if ((val64 &
- VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON) &
- ~mask64) {
- sw_stats->error_stats.kdfcctl_fifo0_poison++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_FIFO_ERR,
- alarm_event);
- }
-
- if ((val64 &
- VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR) &
- ~mask64) {
- sw_stats->error_stats.kdfcctl_fifo0_dma_error++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_FIFO_ERR,
- alarm_event);
- }
-
- if (!skip_alarms) {
- writeq(VXGE_HW_INTR_MASK_ALL,
- &vp_reg->kdfcctl_errors_reg);
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_ALARM_CLEARED,
- alarm_event);
- }
- }
-
- }
-
- if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT) {
-
- val64 = readq(&vp_reg->wrdma_alarm_status);
-
- if (val64 & VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT) {
-
- val64 = readq(&vp_reg->prc_alarm_reg);
- mask64 = readq(&vp_reg->prc_alarm_mask);
-
- if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP)&
- ~mask64)
- sw_stats->error_stats.prc_ring_bumps++;
-
- if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR) &
- ~mask64) {
- sw_stats->error_stats.prc_rxdcm_sc_err++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_VPATH_ERR,
- alarm_event);
- }
-
- if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT)
- & ~mask64) {
- sw_stats->error_stats.prc_rxdcm_sc_abort++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_VPATH_ERR,
- alarm_event);
- }
-
- if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR)
- & ~mask64) {
- sw_stats->error_stats.prc_quanta_size_err++;
-
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_VPATH_ERR,
- alarm_event);
- }
-
- if (!skip_alarms) {
- writeq(VXGE_HW_INTR_MASK_ALL,
- &vp_reg->prc_alarm_reg);
- alarm_event = VXGE_HW_SET_LEVEL(
- VXGE_HW_EVENT_ALARM_CLEARED,
- alarm_event);
- }
- }
- }
-out:
- hldev->stats.sw_dev_err_stats.vpath_alarms++;
-out2:
- if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) ||
- (alarm_event == VXGE_HW_EVENT_UNKNOWN))
- return VXGE_HW_OK;
-
- __vxge_hw_device_handle_error(hldev, vpath->vp_id, alarm_event);
-
- if (alarm_event == VXGE_HW_EVENT_SERR)
- return VXGE_HW_ERR_CRITICAL;
-
- return (alarm_event == VXGE_HW_EVENT_SLOT_FREEZE) ?
- VXGE_HW_ERR_SLOT_FREEZE :
- (alarm_event == VXGE_HW_EVENT_FIFO_ERR) ? VXGE_HW_ERR_FIFO :
- VXGE_HW_ERR_VPATH;
-}
-
-/*
* vxge_hw_vpath_alarm_process - Process Alarms.
* @vpath: Virtual Path.
* @skip_alarms: Do not clear the alarms
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 9890d4d596d0..d48486d6afa1 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -1695,7 +1695,7 @@ struct vxge_hw_device_stats_sw_err {
* struct vxge_hw_device_stats - Contains HW per-device statistics,
* including hw.
* @devh: HW device handle.
- * @dma_addr: DMA addres of the %hw_info. Given to device to fill-in the stats.
+ * @dma_addr: DMA address of the %hw_info. Given to device to fill-in the stats.
* @hw_info_dmah: DMA handle used to map hw statistics onto the device memory
* space.
* @hw_info_dma_acch: One more DMA handle used subsequently to free the
@@ -1904,34 +1904,6 @@ enum vxge_hw_ring_tcode {
VXGE_HW_RING_T_CODE_MULTI_ERR = 0xF
};
-/**
- * enum enum vxge_hw_ring_hash_type - RTH hash types
- * @VXGE_HW_RING_HASH_TYPE_NONE: No Hash
- * @VXGE_HW_RING_HASH_TYPE_TCP_IPV4: TCP IPv4
- * @VXGE_HW_RING_HASH_TYPE_UDP_IPV4: UDP IPv4
- * @VXGE_HW_RING_HASH_TYPE_IPV4: IPv4
- * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6: TCP IPv6
- * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6: UDP IPv6
- * @VXGE_HW_RING_HASH_TYPE_IPV6: IPv6
- * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX: TCP IPv6 extension
- * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX: UDP IPv6 extension
- * @VXGE_HW_RING_HASH_TYPE_IPV6_EX: IPv6 extension
- *
- * RTH hash types
- */
-enum vxge_hw_ring_hash_type {
- VXGE_HW_RING_HASH_TYPE_NONE = 0x0,
- VXGE_HW_RING_HASH_TYPE_TCP_IPV4 = 0x1,
- VXGE_HW_RING_HASH_TYPE_UDP_IPV4 = 0x2,
- VXGE_HW_RING_HASH_TYPE_IPV4 = 0x3,
- VXGE_HW_RING_HASH_TYPE_TCP_IPV6 = 0x4,
- VXGE_HW_RING_HASH_TYPE_UDP_IPV6 = 0x5,
- VXGE_HW_RING_HASH_TYPE_IPV6 = 0x6,
- VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX = 0x7,
- VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX = 0x8,
- VXGE_HW_RING_HASH_TYPE_IPV6_EX = 0x9
-};
-
enum vxge_hw_status vxge_hw_ring_rxd_reserve(
struct __vxge_hw_ring *ring_handle,
void **rxdh);
@@ -2109,10 +2081,6 @@ struct __vxge_hw_ring_rxd_priv {
#endif
};
-/* ========================= FIFO PRIVATE API ============================= */
-
-struct vxge_hw_fifo_attr;
-
struct vxge_hw_mempool_cbs {
void (*item_func_alloc)(
struct vxge_hw_mempool *mempoolh,
@@ -2186,27 +2154,27 @@ enum vxge_hw_vpath_mac_addr_add_mode {
enum vxge_hw_status
vxge_hw_vpath_mac_addr_add(
struct __vxge_hw_vpath_handle *vpath_handle,
- u8 (macaddr)[ETH_ALEN],
- u8 (macaddr_mask)[ETH_ALEN],
+ u8 *macaddr,
+ u8 *macaddr_mask,
enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode);
enum vxge_hw_status
vxge_hw_vpath_mac_addr_get(
struct __vxge_hw_vpath_handle *vpath_handle,
- u8 (macaddr)[ETH_ALEN],
- u8 (macaddr_mask)[ETH_ALEN]);
+ u8 *macaddr,
+ u8 *macaddr_mask);
enum vxge_hw_status
vxge_hw_vpath_mac_addr_get_next(
struct __vxge_hw_vpath_handle *vpath_handle,
- u8 (macaddr)[ETH_ALEN],
- u8 (macaddr_mask)[ETH_ALEN]);
+ u8 *macaddr,
+ u8 *macaddr_mask);
enum vxge_hw_status
vxge_hw_vpath_mac_addr_delete(
struct __vxge_hw_vpath_handle *vpath_handle,
- u8 (macaddr)[ETH_ALEN],
- u8 (macaddr_mask)[ETH_ALEN]);
+ u8 *macaddr,
+ u8 *macaddr_mask);
enum vxge_hw_status
vxge_hw_vpath_vid_add(
@@ -2313,6 +2281,7 @@ vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh);
int
vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel);
+
void
vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id);
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 53fefe137368..ad2f99b9bcf3 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -15,8 +15,35 @@
#define VXGE_VERSION_H
#define VXGE_VERSION_MAJOR "2"
-#define VXGE_VERSION_MINOR "0"
-#define VXGE_VERSION_FIX "9"
-#define VXGE_VERSION_BUILD "20840"
+#define VXGE_VERSION_MINOR "5"
+#define VXGE_VERSION_FIX "1"
+#define VXGE_VERSION_BUILD "22082"
#define VXGE_VERSION_FOR "k"
+
+#define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld))
+
+#define VXGE_DEAD_FW_VER_MAJOR 1
+#define VXGE_DEAD_FW_VER_MINOR 4
+#define VXGE_DEAD_FW_VER_BUILD 4
+
+#define VXGE_FW_DEAD_VER VXGE_FW_VER(VXGE_DEAD_FW_VER_MAJOR, \
+ VXGE_DEAD_FW_VER_MINOR, \
+ VXGE_DEAD_FW_VER_BUILD)
+
+#define VXGE_EPROM_FW_VER_MAJOR 1
+#define VXGE_EPROM_FW_VER_MINOR 6
+#define VXGE_EPROM_FW_VER_BUILD 1
+
+#define VXGE_EPROM_FW_VER VXGE_FW_VER(VXGE_EPROM_FW_VER_MAJOR, \
+ VXGE_EPROM_FW_VER_MINOR, \
+ VXGE_EPROM_FW_VER_BUILD)
+
+#define VXGE_CERT_FW_VER_MAJOR 1
+#define VXGE_CERT_FW_VER_MINOR 8
+#define VXGE_CERT_FW_VER_BUILD 1
+
+#define VXGE_CERT_FW_VER VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, \
+ VXGE_CERT_FW_VER_MINOR, \
+ VXGE_CERT_FW_VER_BUILD)
+
#endif
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index d45b08d1dbc9..4578e5b4b411 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -125,7 +125,7 @@ static u32 dscc4_pci_config_store[16];
/* Module parameters */
MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");
-MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler");
+MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
MODULE_LICENSE("GPL");
module_param(debug, int, 0);
MODULE_PARM_DESC(debug,"Enable/disable extra messages");
@@ -1358,7 +1358,7 @@ static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return ret;
}
-static int dscc4_match(struct thingie *p, int value)
+static int dscc4_match(const struct thingie *p, int value)
{
int i;
@@ -1403,7 +1403,7 @@ done:
static int dscc4_encoding_setting(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
- struct thingie encoding[] = {
+ static const struct thingie encoding[] = {
{ ENCODING_NRZ, 0x00000000 },
{ ENCODING_NRZI, 0x00200000 },
{ ENCODING_FM_MARK, 0x00400000 },
@@ -1442,7 +1442,7 @@ static int dscc4_loopback_setting(struct dscc4_dev_priv *dpriv,
static int dscc4_crc_setting(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
- struct thingie crc[] = {
+ static const struct thingie crc[] = {
{ PARITY_CRC16_PR0_CCITT, 0x00000010 },
{ PARITY_CRC16_PR1_CCITT, 0x00000000 },
{ PARITY_CRC32_PR0_CCITT, 0x00000011 },
diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c
index ea476cbd38b5..e305274f83fb 100644
--- a/drivers/net/wan/hd64572.c
+++ b/drivers/net/wan/hd64572.c
@@ -293,6 +293,7 @@ static inline void sca_tx_done(port_t *port)
struct net_device *dev = port->netdev;
card_t* card = port->card;
u8 stat;
+ unsigned count = 0;
spin_lock(&port->lock);
@@ -316,10 +317,12 @@ static inline void sca_tx_done(port_t *port)
dev->stats.tx_bytes += readw(&desc->len);
}
writeb(0, &desc->stat); /* Free descriptor */
+ count++;
port->txlast = (port->txlast + 1) % card->tx_ring_buffers;
}
- netif_wake_queue(dev);
+ if (count)
+ netif_wake_queue(dev);
spin_unlock(&port->lock);
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d81ad8397885..24297b274cd4 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -498,7 +498,6 @@ norbuff:
static int x25_asy_close(struct net_device *dev)
{
struct x25_asy *sl = netdev_priv(dev);
- int err;
spin_lock(&sl->lock);
if (sl->tty)
@@ -507,10 +506,6 @@ static int x25_asy_close(struct net_device *dev)
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
- err = lapb_unregister(dev);
- if (err != LAPB_OK)
- printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
- err);
spin_unlock(&sl->lock);
return 0;
}
@@ -582,7 +577,7 @@ static int x25_asy_open_tty(struct tty_struct *tty)
if (err)
return err;
/* Done. We have linked the TTY line to a channel. */
- return sl->dev->base_addr;
+ return 0;
}
@@ -595,6 +590,7 @@ static int x25_asy_open_tty(struct tty_struct *tty)
static void x25_asy_close_tty(struct tty_struct *tty)
{
struct x25_asy *sl = tty->disc_data;
+ int err;
/* First make sure we're connected. */
if (!sl || sl->magic != X25_ASY_MAGIC)
@@ -605,6 +601,11 @@ static void x25_asy_close_tty(struct tty_struct *tty)
dev_close(sl->dev);
rtnl_unlock();
+ err = lapb_unregister(sl->dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+ err);
+
tty->disc_data = NULL;
sl->tty = NULL;
x25_asy_free(sl);
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index f1549fff0edc..8831a3393ecf 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -275,7 +275,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr+WD_NIC_OFFSET;
if (dev->irq < 2) {
- int irqmap[] = {9,3,5,7,10,11,15,4};
+ static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4};
int reg1 = inb(ioaddr+1);
int reg4 = inb(ioaddr+4);
if (ancient || reg1 == 0xff) { /* Ack!! No way to read the IRQ! */
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index cdedab46ba21..65bc334ed57b 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -92,54 +92,6 @@ MODULE_PARM_DESC(barkers,
"signal; values are appended to a list--setting one value "
"as zero cleans the existing list and starts a new one.");
-static
-struct i2400m_work *__i2400m_work_setup(
- struct i2400m *i2400m, void (*fn)(struct work_struct *),
- gfp_t gfp_flags, const void *pl, size_t pl_size)
-{
- struct i2400m_work *iw;
-
- iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags);
- if (iw == NULL)
- return NULL;
- iw->i2400m = i2400m_get(i2400m);
- iw->pl_size = pl_size;
- memcpy(iw->pl, pl, pl_size);
- INIT_WORK(&iw->ws, fn);
- return iw;
-}
-
-
-/*
- * Schedule i2400m's specific work on the system's queue.
- *
- * Used for a few cases where we really need it; otherwise, identical
- * to i2400m_queue_work().
- *
- * Returns < 0 errno code on error, 1 if ok.
- *
- * If it returns zero, something really bad happened, as it means the
- * works struct was already queued, but we have just allocated it, so
- * it should not happen.
- */
-static int i2400m_schedule_work(struct i2400m *i2400m,
- void (*fn)(struct work_struct *), gfp_t gfp_flags,
- const void *pl, size_t pl_size)
-{
- int result;
- struct i2400m_work *iw;
-
- result = -ENOMEM;
- iw = __i2400m_work_setup(i2400m, fn, gfp_flags, pl, pl_size);
- if (iw != NULL) {
- result = schedule_work(&iw->ws);
- if (WARN_ON(result == 0))
- result = -ENXIO;
- }
- return result;
-}
-
-
/*
* WiMAX stack operation: relay a message from user space
*
@@ -280,7 +232,7 @@ int i2400m_check_mac_addr(struct i2400m *i2400m)
result);
goto error;
}
- /* Extract MAC addresss */
+ /* Extract MAC address */
ddi = (void *) skb->data;
BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address));
d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n",
@@ -648,17 +600,11 @@ EXPORT_SYMBOL_GPL(i2400m_post_reset);
static
void __i2400m_dev_reset_handle(struct work_struct *ws)
{
- int result;
- struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws);
- const char *reason;
- struct i2400m *i2400m = iw->i2400m;
+ struct i2400m *i2400m = container_of(ws, struct i2400m, reset_ws);
+ const char *reason = i2400m->reset_reason;
struct device *dev = i2400m_dev(i2400m);
struct i2400m_reset_ctx *ctx = i2400m->reset_ctx;
-
- if (WARN_ON(iw->pl_size != sizeof(reason)))
- reason = "SW BUG: reason n/a";
- else
- memcpy(&reason, iw->pl, sizeof(reason));
+ int result;
d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason);
@@ -733,8 +679,6 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
}
}
out:
- i2400m_put(i2400m);
- kfree(iw);
d_fnend(3, dev, "(ws %p i2400m %p reason %s) = void\n",
ws, i2400m, reason);
}
@@ -754,8 +698,8 @@ out:
*/
int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason)
{
- return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
- GFP_ATOMIC, &reason, sizeof(reason));
+ i2400m->reset_reason = reason;
+ return schedule_work(&i2400m->reset_ws);
}
EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
@@ -768,14 +712,9 @@ EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
static
void __i2400m_error_recovery(struct work_struct *ws)
{
- struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws);
- struct i2400m *i2400m = iw->i2400m;
+ struct i2400m *i2400m = container_of(ws, struct i2400m, recovery_ws);
i2400m_reset(i2400m, I2400M_RT_BUS);
-
- i2400m_put(i2400m);
- kfree(iw);
- return;
}
/*
@@ -805,18 +744,10 @@ void __i2400m_error_recovery(struct work_struct *ws)
*/
void i2400m_error_recovery(struct i2400m *i2400m)
{
- struct device *dev = i2400m_dev(i2400m);
-
- if (atomic_add_return(1, &i2400m->error_recovery) == 1) {
- if (i2400m_schedule_work(i2400m, __i2400m_error_recovery,
- GFP_ATOMIC, NULL, 0) < 0) {
- dev_err(dev, "run out of memory for "
- "scheduling an error recovery ?\n");
- atomic_dec(&i2400m->error_recovery);
- }
- } else
+ if (atomic_add_return(1, &i2400m->error_recovery) == 1)
+ schedule_work(&i2400m->recovery_ws);
+ else
atomic_dec(&i2400m->error_recovery);
- return;
}
EXPORT_SYMBOL_GPL(i2400m_error_recovery);
@@ -886,6 +817,10 @@ void i2400m_init(struct i2400m *i2400m)
mutex_init(&i2400m->init_mutex);
/* wake_tx_ws is initialized in i2400m_tx_setup() */
+
+ INIT_WORK(&i2400m->reset_ws, __i2400m_dev_reset_handle);
+ INIT_WORK(&i2400m->recovery_ws, __i2400m_error_recovery);
+
atomic_set(&i2400m->bus_reset_retries, 0);
i2400m->alive = 0;
@@ -1040,6 +975,9 @@ void i2400m_release(struct i2400m *i2400m)
i2400m_dev_stop(i2400m);
+ cancel_work_sync(&i2400m->reset_ws);
+ cancel_work_sync(&i2400m->recovery_ws);
+
i2400m_debugfs_rm(i2400m);
sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj,
&i2400m_dev_attr_group);
@@ -1083,8 +1021,6 @@ module_init(i2400m_driver_init);
static
void __exit i2400m_driver_exit(void)
{
- /* for scheds i2400m_dev_reset_handle() */
- flush_scheduled_work();
i2400m_barker_db_exit();
}
module_exit(i2400m_driver_exit);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 59ac7705e76e..030cbfd31704 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -186,7 +186,7 @@ enum {
* struct i2400m_poke_table - Hardware poke table for the Intel 2400m
*
* This structure will be used to create a device specific poke table
- * to put the device in a consistant state at boot time.
+ * to put the device in a consistent state at boot time.
*
* @address: The device address to poke
*
@@ -632,6 +632,11 @@ struct i2400m {
struct work_struct wake_tx_ws;
struct sk_buff *wake_tx_skb;
+ struct work_struct reset_ws;
+ const char *reset_reason;
+
+ struct work_struct recovery_ws;
+
struct dentry *debugfs_dentry;
const char *fw_name; /* name of the current firmware image */
unsigned long fw_version; /* version of the firmware interface */
@@ -698,7 +703,7 @@ enum i2400m_bm_cmd_flags {
* @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot
* rom after reading the MAC address. This is quite a dirty hack,
* if you ask me -- the device requires the bootrom to be
- * intialized after reading the MAC address.
+ * initialized after reading the MAC address.
*/
enum i2400m_bri {
I2400M_BRI_SOFT = 1 << 1,
@@ -896,20 +901,6 @@ struct device *i2400m_dev(struct i2400m *i2400m)
return i2400m->wimax_dev.net_dev->dev.parent;
}
-/*
- * Helper for scheduling simple work functions
- *
- * This struct can get any kind of payload attached (normally in the
- * form of a struct where you pack the stuff you want to pass to the
- * _work function).
- */
-struct i2400m_work {
- struct work_struct ws;
- struct i2400m *i2400m;
- size_t pl_size;
- u8 pl[0];
-};
-
extern int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *,
char *, size_t);
extern int i2400m_msg_size_check(struct i2400m *,
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 9bfc26e1bc6b..be428cae28d8 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -590,7 +590,6 @@ module_init(i2400ms_driver_init);
static
void __exit i2400ms_driver_exit(void)
{
- flush_scheduled_work(); /* for the stuff we schedule */
sdio_unregister_driver(&i2400m_sdio_driver);
}
module_exit(i2400ms_driver_exit);
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index d3365ac85dde..298f2b0b6311 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -514,7 +514,7 @@ int i2400mu_probe(struct usb_interface *iface,
#ifdef CONFIG_PM
iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */
device_init_wakeup(dev, 1);
- usb_dev->autosuspend_delay = 15 * HZ;
+ pm_runtime_set_autosuspend_delay(&usb_dev->dev, 15000);
usb_enable_autosuspend(usb_dev);
#endif
@@ -780,7 +780,6 @@ module_init(i2400mu_driver_init);
static
void __exit i2400mu_driver_exit(void)
{
- flush_scheduled_work(); /* for the stuff we schedule from sysfs.c */
usb_deregister(&i2400mu_driver);
}
module_exit(i2400mu_driver_exit);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 4de4410cd38e..b4338f389394 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -279,6 +279,7 @@ source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 06f8ca26c5c1..9760561a27a5 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_B43LEGACY) += b43legacy/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
obj-$(CONFIG_RTL8180) += rtl818x/
obj-$(CONFIG_RTL8187) += rtl818x/
+obj-$(CONFIG_RTL8192CE) += rtlwifi/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a36e7870b03e..57a79b0475f6 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -4652,24 +4652,18 @@ static ssize_t proc_write( struct file *file,
size_t len,
loff_t *offset )
{
- loff_t pos = *offset;
+ ssize_t ret;
struct proc_data *priv = file->private_data;
if (!priv->wbuffer)
return -EINVAL;
- if (pos < 0)
- return -EINVAL;
- if (pos >= priv->maxwritelen)
- return 0;
- if (len > priv->maxwritelen - pos)
- len = priv->maxwritelen - pos;
- if (copy_from_user(priv->wbuffer + pos, buffer, len))
- return -EFAULT;
- if ( pos + len > priv->writelen )
- priv->writelen = len + file->f_pos;
- *offset = pos + len;
- return len;
+ ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset,
+ buffer, len);
+ if (ret > 0)
+ priv->writelen = max_t(int, priv->writelen, *offset);
+
+ return ret;
}
static int proc_status_open(struct inode *inode, struct file *file)
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index 4604de09a8b2..6452c5055a63 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
@@ -54,7 +54,7 @@ int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len)
int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
{
- __le32 buf[2] = {
+ const __le32 buf[2] = {
cpu_to_le32(reg),
cpu_to_le32(val),
};
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 5dbb5361fd51..d3be6f9816b5 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -161,8 +161,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
{
struct sk_buff *skb = urb->context;
- struct ar9170_usb *aru = (struct ar9170_usb *)
- usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+ struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
if (unlikely(!aru)) {
dev_kfree_skb_irq(skb);
@@ -219,8 +218,7 @@ free:
static void ar9170_usb_rx_completed(struct urb *urb)
{
struct sk_buff *skb = urb->context;
- struct ar9170_usb *aru = (struct ar9170_usb *)
- usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+ struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
int err;
if (!aru)
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 501050c0296f..e43210c8585c 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -126,6 +126,7 @@ struct ath_bus_ops {
void (*read_cachesize)(struct ath_common *common, int *csz);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
+ void (*extn_synch_en)(struct ath_common *common);
};
struct ath_common {
@@ -162,6 +163,8 @@ struct ath_common {
struct ath_regulatory regulatory;
const struct ath_ops *ops;
const struct ath_bus_ops *bus_ops;
+
+ bool btcoex_enabled;
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
@@ -178,4 +181,112 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry);
void ath_hw_cycle_counters_update(struct ath_common *common);
int32_t ath_hw_get_listen_time(struct ath_common *common);
+extern __attribute__ ((format (printf, 3, 4))) int
+ath_printk(const char *level, struct ath_common *common, const char *fmt, ...);
+
+#define ath_emerg(common, fmt, ...) \
+ ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__)
+#define ath_alert(common, fmt, ...) \
+ ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__)
+#define ath_crit(common, fmt, ...) \
+ ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__)
+#define ath_err(common, fmt, ...) \
+ ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__)
+#define ath_warn(common, fmt, ...) \
+ ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__)
+#define ath_notice(common, fmt, ...) \
+ ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__)
+#define ath_info(common, fmt, ...) \
+ ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__)
+
+/**
+ * enum ath_debug_level - atheros wireless debug level
+ *
+ * @ATH_DBG_RESET: reset processing
+ * @ATH_DBG_QUEUE: hardware queue management
+ * @ATH_DBG_EEPROM: eeprom processing
+ * @ATH_DBG_CALIBRATE: periodic calibration
+ * @ATH_DBG_INTERRUPT: interrupt processing
+ * @ATH_DBG_REGULATORY: regulatory processing
+ * @ATH_DBG_ANI: adaptive noise immunitive processing
+ * @ATH_DBG_XMIT: basic xmit operation
+ * @ATH_DBG_BEACON: beacon handling
+ * @ATH_DBG_CONFIG: configuration of the hardware
+ * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT
+ * @ATH_DBG_PS: power save processing
+ * @ATH_DBG_HWTIMER: hardware timer handling
+ * @ATH_DBG_BTCOEX: bluetooth coexistance
+ * @ATH_DBG_BSTUCK: stuck beacons
+ * @ATH_DBG_ANY: enable all debugging
+ *
+ * The debug level is used to control the amount and type of debugging output
+ * we want to see. Each driver has its own method for enabling debugging and
+ * modifying debug level states -- but this is typically done through a
+ * module parameter 'debug' along with a respective 'debug' debugfs file
+ * entry.
+ */
+enum ATH_DEBUG {
+ ATH_DBG_RESET = 0x00000001,
+ ATH_DBG_QUEUE = 0x00000002,
+ ATH_DBG_EEPROM = 0x00000004,
+ ATH_DBG_CALIBRATE = 0x00000008,
+ ATH_DBG_INTERRUPT = 0x00000010,
+ ATH_DBG_REGULATORY = 0x00000020,
+ ATH_DBG_ANI = 0x00000040,
+ ATH_DBG_XMIT = 0x00000080,
+ ATH_DBG_BEACON = 0x00000100,
+ ATH_DBG_CONFIG = 0x00000200,
+ ATH_DBG_FATAL = 0x00000400,
+ ATH_DBG_PS = 0x00000800,
+ ATH_DBG_HWTIMER = 0x00001000,
+ ATH_DBG_BTCOEX = 0x00002000,
+ ATH_DBG_WMI = 0x00004000,
+ ATH_DBG_BSTUCK = 0x00008000,
+ ATH_DBG_ANY = 0xffffffff
+};
+
+#define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
+
+#ifdef CONFIG_ATH_DEBUG
+
+#define ath_dbg(common, dbg_mask, fmt, ...) \
+({ \
+ int rtn; \
+ if ((common)->debug_mask & dbg_mask) \
+ rtn = ath_printk(KERN_DEBUG, common, fmt, \
+ ##__VA_ARGS__); \
+ else \
+ rtn = 0; \
+ \
+ rtn; \
+})
+#define ATH_DBG_WARN(foo, arg...) WARN(foo, arg)
+#define ATH_DBG_WARN_ON_ONCE(foo) WARN_ON_ONCE(foo)
+
+#else
+
+static inline __attribute__ ((format (printf, 3, 4))) int
+ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask,
+ const char *fmt, ...)
+{
+ return 0;
+}
+#define ATH_DBG_WARN(foo, arg...) do {} while (0)
+#define ATH_DBG_WARN_ON_ONCE(foo) ({ \
+ int __ret_warn_once = !!(foo); \
+ unlikely(__ret_warn_once); \
+})
+
+#endif /* CONFIG_ATH_DEBUG */
+
+/** Returns string describing opmode, or NULL if unknown mode. */
+#ifdef CONFIG_ATH_DEBUG
+const char *ath_opmode_to_string(enum nl80211_iftype opmode);
+#else
+static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode)
+{
+ return "UNKNOWN";
+}
+#endif
+
#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index eb83b7b4d0e3..e0793319389d 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,9 +1,12 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
- depends on PCI && MAC80211
+ depends on (PCI || ATHEROS_AR231X) && MAC80211
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
+ select AVERAGE
+ select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
+ select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
---help---
This module adds support for wireless adapters based on
Atheros 5xxx chipset.
@@ -37,3 +40,16 @@ config ATH5K_DEBUG
modprobe ath5k debug=0x00000400
+config ATH5K_AHB
+ bool "Atheros 5xxx AHB bus support"
+ depends on (ATHEROS_AR231X && !PCI)
+ ---help---
+ This adds support for WiSoC type chipsets of the 5xxx Atheros
+ family.
+
+config ATH5K_PCI
+ bool "Atheros 5xxx PCI bus support"
+ depends on (!ATHEROS_AR231X && PCI)
+ ---help---
+ This adds support for PCI type chipsets of the 5xxx Atheros
+ family.
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index 2242a140e4fe..f60b3899afc4 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -14,5 +14,8 @@ ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
ath5k-y += sysfs.o
+ath5k-y += mac80211-ops.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
+ath5k-$(CONFIG_ATH5K_AHB) += ahb.o
+ath5k-$(CONFIG_ATH5K_PCI) += pci.o
obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
new file mode 100644
index 000000000000..707cde149248
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/platform_device.h>
+#include <ar231x_platform.h>
+#include "ath5k.h"
+#include "debug.h"
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+
+/* return bus cachesize in 4B word units */
+static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
+{
+ *csz = L1_CACHE_BYTES >> 2;
+}
+
+bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
+{
+ struct ath5k_softc *sc = common->priv;
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ u16 *eeprom, *eeprom_end;
+
+
+
+ bcfg = pdev->dev.platform_data;
+ eeprom = (u16 *) bcfg->radio;
+ eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
+
+ eeprom += off;
+ if (eeprom > eeprom_end)
+ return -EINVAL;
+
+ *data = *eeprom;
+ return 0;
+}
+
+int ath5k_hw_read_srev(struct ath5k_hw *ah)
+{
+ struct ath5k_softc *sc = ah->ah_sc;
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ ah->ah_mac_srev = bcfg->devid;
+ return 0;
+}
+
+static const struct ath_bus_ops ath_ahb_bus_ops = {
+ .ath_bus_type = ATH_AHB,
+ .read_cachesize = ath5k_ahb_read_cachesize,
+ .eeprom_read = ath5k_ahb_eeprom_read,
+};
+
+/*Initialization*/
+static int ath_ahb_probe(struct platform_device *pdev)
+{
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ struct ath5k_softc *sc;
+ struct ieee80211_hw *hw;
+ struct resource *res;
+ void __iomem *mem;
+ int irq;
+ int ret = 0;
+ u32 reg;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ ret = -ENXIO;
+ goto err_out;
+ }
+
+ mem = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (mem == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no IRQ resource found\n");
+ ret = -ENXIO;
+ goto err_out;
+ }
+
+ irq = res->start;
+
+ hw = ieee80211_alloc_hw(sizeof(struct ath5k_softc), &ath5k_hw_ops);
+ if (hw == NULL) {
+ dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->dev = &pdev->dev;
+ sc->iobase = mem;
+ sc->irq = irq;
+ sc->devid = bcfg->devid;
+
+ if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
+ /* Enable WMAC AHB arbitration */
+ reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
+ __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+
+ /* Enable global WMAC swapping */
+ reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP);
+ reg |= AR5K_AR2315_BYTESWAP_WMAC;
+ __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
+ } else {
+ /* Enable WMAC DMA access (assuming 5312 or 231x*/
+ /* TODO: check other platforms */
+ reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+ if (to_platform_device(sc->dev)->id == 0)
+ reg |= AR5K_AR5312_ENABLE_WLAN0;
+ else
+ reg |= AR5K_AR5312_ENABLE_WLAN1;
+ __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+ }
+
+ ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
+ ret = -ENODEV;
+ goto err_free_hw;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ return 0;
+
+ err_free_hw:
+ ieee80211_free_hw(hw);
+ platform_set_drvdata(pdev, NULL);
+ err_out:
+ return ret;
+}
+
+static int ath_ahb_remove(struct platform_device *pdev)
+{
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct ath5k_softc *sc;
+ u32 reg;
+
+ if (!hw)
+ return 0;
+
+ sc = hw->priv;
+
+ if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
+ /* Disable WMAC AHB arbitration */
+ reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
+ __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ } else {
+ /*Stop DMA access */
+ reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+ if (to_platform_device(sc->dev)->id == 0)
+ reg &= ~AR5K_AR5312_ENABLE_WLAN0;
+ else
+ reg &= ~AR5K_AR5312_ENABLE_WLAN1;
+ __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+ }
+
+ ath5k_deinit_softc(sc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ath_ahb_driver = {
+ .probe = ath_ahb_probe,
+ .remove = ath_ahb_remove,
+ .driver = {
+ .name = "ar231x-wmac",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+ath5k_ahb_init(void)
+{
+ return platform_driver_register(&ath_ahb_driver);
+}
+
+static void __exit
+ath5k_ahb_exit(void)
+{
+ platform_driver_unregister(&ath_ahb_driver);
+}
+
+module_init(ath5k_ahb_init);
+module_exit(ath5k_ahb_exit);
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index f1419198a479..f915f404302d 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -58,20 +58,20 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
{
/* TODO:
* ANI documents suggest the following five levels to use, but the HAL
- * and ath9k use only use the last two levels, making this
+ * and ath9k use only the last two levels, making this
* essentially an on/off option. There *may* be a reason for this (???),
* so i stick with the HAL version for now...
*/
#if 0
- const s8 hi[] = { -18, -18, -16, -14, -12 };
- const s8 lo[] = { -52, -56, -60, -64, -70 };
- const s8 sz[] = { -34, -41, -48, -55, -62 };
- const s8 fr[] = { -70, -72, -75, -78, -80 };
+ static const s8 lo[] = { -52, -56, -60, -64, -70 };
+ static const s8 hi[] = { -18, -18, -16, -14, -12 };
+ static const s8 sz[] = { -34, -41, -48, -55, -62 };
+ static const s8 fr[] = { -70, -72, -75, -78, -80 };
#else
- const s8 sz[] = { -55, -62 };
- const s8 lo[] = { -64, -70 };
- const s8 hi[] = { -14, -12 };
- const s8 fr[] = { -78, -80 };
+ static const s8 lo[] = { -64, -70 };
+ static const s8 hi[] = { -14, -12 };
+ static const s8 sz[] = { -55, -62 };
+ static const s8 fr[] = { -78, -80 };
#endif
if (level < 0 || level >= ARRAY_SIZE(sz)) {
ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range",
@@ -102,7 +102,7 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
void
ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
{
- const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+ static const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
if (level < 0 || level >= ARRAY_SIZE(val) ||
level > ah->ah_sc->ani_state.max_spur_level) {
@@ -127,7 +127,7 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
void
ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
{
- const int val[] = { 0, 4, 8 };
+ static const int val[] = { 0, 4, 8 };
if (level < 0 || level >= ARRAY_SIZE(val)) {
ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level);
@@ -151,12 +151,12 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
void
ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
{
- const int m1l[] = { 127, 50 };
- const int m2l[] = { 127, 40 };
- const int m1[] = { 127, 0x4d };
- const int m2[] = { 127, 0x40 };
- const int m2cnt[] = { 31, 16 };
- const int m2lcnt[] = { 63, 48 };
+ static const int m1l[] = { 127, 50 };
+ static const int m2l[] = { 127, 40 };
+ static const int m1[] = { 127, 0x4d };
+ static const int m2[] = { 127, 0x40 };
+ static const int m2cnt[] = { 31, 16 };
+ static const int m2lcnt[] = { 63, 48 };
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]);
@@ -192,7 +192,7 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
void
ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
{
- const int val[] = { 8, 6 };
+ static const int val[] = { 8, 6 };
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR,
AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]);
ah->ah_sc->ani_state.cck_weak_sig = on;
@@ -216,7 +216,7 @@ static void
ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
bool ofdm_trigger)
{
- int rssi = ah->ah_beacon_rssi_avg.avg;
+ int rssi = ewma_read(&ah->ah_beacon_rssi_avg);
ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)",
ofdm_trigger ? "ODFM" : "CCK");
@@ -301,7 +301,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
static void
ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
{
- int rssi = ah->ah_beacon_rssi_avg.avg;
+ int rssi = ewma_read(&ah->ah_beacon_rssi_avg);
ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity");
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 308b79e1ff08..407e39c2b10b 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/types.h>
+#include <linux/average.h>
#include <net/mac80211.h>
/* RX/TX descriptor hw structs
@@ -153,19 +154,6 @@
udelay(1); \
} while (0)
-/* Register dumps are done per operation mode */
-#define AR5K_INI_RFGAIN_5GHZ 0
-#define AR5K_INI_RFGAIN_2GHZ 1
-
-/* TODO: Clean this up */
-#define AR5K_INI_VAL_11A 0
-#define AR5K_INI_VAL_11A_TURBO 1
-#define AR5K_INI_VAL_11B 2
-#define AR5K_INI_VAL_11G 3
-#define AR5K_INI_VAL_11G_TURBO 4
-#define AR5K_INI_VAL_XR 0
-#define AR5K_INI_VAL_MAX 5
-
/*
* Some tuneable values (these should be changeable by the user)
* TODO: Make use of them and add more options OR use debug/configfs
@@ -221,42 +209,66 @@
/* Initial values */
#define AR5K_INIT_CYCRSSI_THR1 2
-#define AR5K_INIT_TX_LATENCY 502
-#define AR5K_INIT_USEC 39
-#define AR5K_INIT_USEC_TURBO 79
-#define AR5K_INIT_USEC_32 31
-#define AR5K_INIT_SLOT_TIME 396
-#define AR5K_INIT_SLOT_TIME_TURBO 480
-#define AR5K_INIT_ACK_CTS_TIMEOUT 1024
-#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800
-#define AR5K_INIT_PROG_IFS 920
-#define AR5K_INIT_PROG_IFS_TURBO 960
-#define AR5K_INIT_EIFS 3440
-#define AR5K_INIT_EIFS_TURBO 6880
-#define AR5K_INIT_SIFS 560
-#define AR5K_INIT_SIFS_TURBO 480
+
+/* Tx retry limits */
#define AR5K_INIT_SH_RETRY 10
#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY
+/* For station mode */
#define AR5K_INIT_SSH_RETRY 32
#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY
#define AR5K_INIT_TX_RETRY 10
-#define AR5K_INIT_TRANSMIT_LATENCY ( \
- (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
- (AR5K_INIT_USEC) \
-)
-#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \
- (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
- (AR5K_INIT_USEC_TURBO) \
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL ( \
- (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \
- (AR5K_INIT_PROG_IFS) \
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \
- (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
- (AR5K_INIT_PROG_IFS_TURBO) \
-)
+
+/* Slot time */
+#define AR5K_INIT_SLOT_TIME_TURBO 6
+#define AR5K_INIT_SLOT_TIME_DEFAULT 9
+#define AR5K_INIT_SLOT_TIME_HALF_RATE 13
+#define AR5K_INIT_SLOT_TIME_QUARTER_RATE 21
+#define AR5K_INIT_SLOT_TIME_B 20
+#define AR5K_SLOT_TIME_MAX 0xffff
+
+/* SIFS */
+#define AR5K_INIT_SIFS_TURBO 6
+/* XXX: 8 from initvals 10 from standard */
+#define AR5K_INIT_SIFS_DEFAULT_BG 8
+#define AR5K_INIT_SIFS_DEFAULT_A 16
+#define AR5K_INIT_SIFS_HALF_RATE 32
+#define AR5K_INIT_SIFS_QUARTER_RATE 64
+
+/* Used to calculate tx time for non 5/10/40MHz
+ * operation */
+/* It's preamble time + signal time (16 + 4) */
+#define AR5K_INIT_OFDM_PREAMPLE_TIME 20
+/* Preamble time for 40MHz (turbo) operation (min ?) */
+#define AR5K_INIT_OFDM_PREAMBLE_TIME_MIN 14
+#define AR5K_INIT_OFDM_SYMBOL_TIME 4
+#define AR5K_INIT_OFDM_PLCP_BITS 22
+
+/* Rx latency for 5 and 10MHz operation (max ?) */
+#define AR5K_INIT_RX_LAT_MAX 63
+/* Tx latencies from initvals (5212 only but no problem
+ * because we only tweak them on 5212) */
+#define AR5K_INIT_TX_LAT_A 54
+#define AR5K_INIT_TX_LAT_BG 384
+/* Tx latency for 40MHz (turbo) operation (min ?) */
+#define AR5K_INIT_TX_LAT_MIN 32
+/* Default Tx/Rx latencies (same for 5211)*/
+#define AR5K_INIT_TX_LATENCY_5210 54
+#define AR5K_INIT_RX_LATENCY_5210 29
+
+/* Tx frame to Tx data start delay */
+#define AR5K_INIT_TXF2TXD_START_DEFAULT 14
+#define AR5K_INIT_TXF2TXD_START_DELAY_10MHZ 12
+#define AR5K_INIT_TXF2TXD_START_DELAY_5MHZ 13
+
+/* We need to increase PHY switch and agc settling time
+ * on turbo mode */
+#define AR5K_SWITCH_SETTLING 5760
+#define AR5K_SWITCH_SETTLING_TURBO 7168
+
+#define AR5K_AGC_SETTLING 28
+/* 38 on 5210 but shouldn't matter */
+#define AR5K_AGC_SETTLING_TURBO 37
/* GENERIC CHIPSET DEFINITIONS */
@@ -303,12 +315,19 @@ struct ath5k_srev_name {
#define AR5K_SREV_AR5311B 0x30 /* Spirit */
#define AR5K_SREV_AR5211 0x40 /* Oahu */
#define AR5K_SREV_AR5212 0x50 /* Venice */
+#define AR5K_SREV_AR5312_R2 0x52 /* AP31 */
#define AR5K_SREV_AR5212_V4 0x54 /* ??? */
#define AR5K_SREV_AR5213 0x55 /* ??? */
+#define AR5K_SREV_AR5312_R7 0x57 /* AP30 */
+#define AR5K_SREV_AR2313_R8 0x58 /* AP43 */
#define AR5K_SREV_AR5213A 0x59 /* Hainan */
#define AR5K_SREV_AR2413 0x78 /* Griffin lite */
#define AR5K_SREV_AR2414 0x70 /* Griffin */
+#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */
+#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */
#define AR5K_SREV_AR5424 0x90 /* Condor */
+#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */
+#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */
#define AR5K_SREV_AR5413 0xa4 /* Eagle lite */
#define AR5K_SREV_AR5414 0xa0 /* Eagle */
#define AR5K_SREV_AR2415 0xb0 /* Talon */
@@ -404,12 +423,10 @@ struct ath5k_srev_name {
enum ath5k_driver_mode {
AR5K_MODE_11A = 0,
- AR5K_MODE_11A_TURBO = 1,
- AR5K_MODE_11B = 2,
- AR5K_MODE_11G = 3,
- AR5K_MODE_11G_TURBO = 4,
+ AR5K_MODE_11B = 1,
+ AR5K_MODE_11G = 2,
AR5K_MODE_XR = 0,
- AR5K_MODE_MAX = 5
+ AR5K_MODE_MAX = 3
};
enum ath5k_ant_mode {
@@ -423,6 +440,12 @@ enum ath5k_ant_mode {
AR5K_ANTMODE_MAX,
};
+enum ath5k_bw_mode {
+ AR5K_BWMODE_DEFAULT = 0, /* 20MHz, default operation */
+ AR5K_BWMODE_5MHZ = 1, /* Quarter rate */
+ AR5K_BWMODE_10MHZ = 2, /* Half rate */
+ AR5K_BWMODE_40MHZ = 3 /* Turbo */
+};
/****************\
TX DEFINITIONS
@@ -655,7 +678,6 @@ struct ath5k_gain {
/* channel_flags */
#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */
-#define CHANNEL_TURBO 0x0010 /* Turbo Channel */
#define CHANNEL_CCK 0x0020 /* CCK channel */
#define CHANNEL_OFDM 0x0040 /* OFDM channel */
#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */
@@ -667,16 +689,10 @@ struct ath5k_gain {
#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
-#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define CHANNEL_108A CHANNEL_T
-#define CHANNEL_108G CHANNEL_TG
#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
-#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
- CHANNEL_TURBO)
+#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ)
-#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL & ~CHANNEL_TURBO)
#define CHANNEL_MODES CHANNEL_ALL
/*
@@ -1025,7 +1041,6 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
struct ieee80211_channel *ah_current_channel;
- bool ah_turbo;
bool ah_calibration;
bool ah_single_chip;
@@ -1034,6 +1049,7 @@ struct ath5k_hw {
u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
+ u16 ah_mac_revision;
u16 ah_phy_revision;
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
@@ -1043,6 +1059,8 @@ struct ath5k_hw {
u32 ah_limit_tx_retries;
u8 ah_coverage_class;
+ bool ah_ack_bitrate_high;
+ u8 ah_bwmode;
/* Antenna Control */
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1085,12 +1103,14 @@ struct ath5k_hw {
/* Values in 0.25dB units */
s16 txp_min_pwr;
s16 txp_max_pwr;
+ s16 txp_cur_pwr;
/* Values in 0.5dB units */
s16 txp_offset;
s16 txp_ofdm;
s16 txp_cck_ofdm_gainf_delta;
/* Value in dB units */
s16 txp_cck_ofdm_pwr_delta;
+ bool txp_setup;
} ah_txpower;
struct {
@@ -1102,7 +1122,7 @@ struct ath5k_hw {
struct ath5k_nfcal_hist ah_nfcal_hist;
/* average beacon RSSI in our BSS (used by ANI) */
- struct ath5k_avg_val ah_beacon_rssi_avg;
+ struct ewma ah_beacon_rssi_avg;
/* noise floor from last periodic calibration */
s32 ah_noise_floor;
@@ -1131,36 +1151,50 @@ struct ath5k_hw {
/*
* Prototypes
*/
+extern const struct ieee80211_ops ath5k_hw_ops;
-/* Attach/Detach Functions */
-int ath5k_hw_attach(struct ath5k_softc *sc);
-void ath5k_hw_detach(struct ath5k_hw *ah);
+/* Initialization and detach functions */
+int ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops);
+void ath5k_deinit_softc(struct ath5k_softc *sc);
+int ath5k_hw_init(struct ath5k_softc *sc);
+void ath5k_hw_deinit(struct ath5k_hw *ah);
int ath5k_sysfs_register(struct ath5k_softc *sc);
void ath5k_sysfs_unregister(struct ath5k_softc *sc);
+/*Chip id helper functions */
+const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
+int ath5k_hw_read_srev(struct ath5k_hw *ah);
+
/* LED functions */
int ath5k_init_leds(struct ath5k_softc *sc);
void ath5k_led_enable(struct ath5k_softc *sc);
void ath5k_led_off(struct ath5k_softc *sc);
void ath5k_unregister_leds(struct ath5k_softc *sc);
+
/* Reset Functions */
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
int ath5k_hw_on_hold(struct ath5k_hw *ah);
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
- struct ieee80211_channel *channel, bool change_channel);
+ struct ieee80211_channel *channel, bool fast, bool skip_pcu);
int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
bool is_set);
/* Power management functions */
+
+/* Clock rate related functions */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
+void ath5k_hw_set_clockrate(struct ath5k_hw *ah);
+
+
/* DMA Related Functions */
void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
-void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue);
u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
u32 phys_addr);
@@ -1170,38 +1204,43 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah);
+/* Init/Stop functions */
+void ath5k_hw_dma_init(struct ath5k_hw *ah);
+int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah);
void ath5k_eeprom_detach(struct ath5k_hw *ah);
int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+
/* Protocol Control Unit Functions */
+/* Helpers */
+int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+ int len, struct ieee80211_rate *rate);
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
-/* BSSID Functions */
+/* RX filter control*/
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
void ath5k_hw_set_bssid(struct ath5k_hw *ah);
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
-/* Receive start/stop functions */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
-/* RX Filter functions */
void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* Receive (DRU) start/stop functions */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
/* Beacon control functions */
u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
-/* ACK bit rate */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
-/* Clock rate related functions */
-unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
-unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
-void ath5k_hw_set_clockrate(struct ath5k_hw *ah);
+/* Init function */
+void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ u8 mode);
/* Queue Control Unit, DFS Control Unit Functions */
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
@@ -1214,7 +1253,9 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time);
+/* Init function */
+int ath5k_hw_init_queues(struct ath5k_hw *ah);
/* Hardware Descriptor Functions */
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
@@ -1224,6 +1265,7 @@ int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3);
+
/* GPIO Functions */
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
@@ -1233,11 +1275,13 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
u32 interrupt_level);
-/* rfkill Functions */
+
+/* RFkill Functions */
void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
-/* Misc functions */
+
+/* Misc functions TODO: Cleanup */
int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
int ath5k_hw_get_capability(struct ath5k_hw *ah,
enum ath5k_capability_type cap_type, u32 capability,
@@ -1245,19 +1289,20 @@ int ath5k_hw_get_capability(struct ath5k_hw *ah,
int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
+
/* Initial register settings functions */
int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
-/* Initialize RF */
-int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
- struct ieee80211_channel *channel,
- unsigned int mode);
-int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+
+/* PHY functions */
+/* Misc PHY functions */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* Gain_F optimization */
enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
/* PHY/RF channel functions */
bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
-int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
/* PHY calibration */
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
@@ -1266,18 +1311,14 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
-void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
- struct ieee80211_channel *channel);
-/* Misc PHY functions */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
-int ath5k_hw_phy_disable(struct ath5k_hw *ah);
/* Antenna control */
void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
/* TX power setup */
-int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
- u8 ee_mode, u8 txpower);
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
+/* Init function */
+int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+ u8 mode, bool fast);
/*
* Functions used internaly
@@ -1293,6 +1334,32 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
return &(ath5k_hw_common(ah)->regulatory);
}
+#ifdef CONFIG_ATHEROS_AR231X
+#define AR5K_AR2315_PCI_BASE ((void __iomem *)0xb0100000)
+
+static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
+{
+ /* On AR2315 and AR2317 the PCI clock domain registers
+ * are outside of the WMAC register space */
+ if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
+ (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
+ return AR5K_AR2315_PCI_BASE + reg;
+
+ return ah->ah_iobase + reg;
+}
+
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+ return __raw_readl(ath5k_ahb_reg(ah, reg));
+}
+
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+ __raw_writel(val, ath5k_ahb_reg(ah, reg));
+}
+
+#else
+
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
{
return ioread32(ah->ah_iobase + reg);
@@ -1303,6 +1370,24 @@ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
iowrite32(val, ah->ah_iobase + reg);
}
+#endif
+
+static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
+{
+ return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
+}
+
+static inline void ath5k_read_cachesize(struct ath_common *common, int *csz)
+{
+ common->bus_ops->read_cachesize(common, csz);
+}
+
+static inline bool ath5k_hw_nvram_read(struct ath5k_hw *ah, u32 off, u16 *data)
+{
+ struct ath_common *common = ath5k_hw_common(ah);
+ return common->bus_ops->eeprom_read(common, off, data);
+}
+
static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
{
u32 retval = 0, bit, i;
@@ -1315,27 +1400,4 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
return retval;
}
-#define AVG_SAMPLES 8
-#define AVG_FACTOR 1000
-
-/**
- * ath5k_moving_average - Exponentially weighted moving average
- * @avg: average structure
- * @val: current value
- *
- * This implementation make use of a struct ath5k_avg_val to prevent rounding
- * errors.
- */
-static inline struct ath5k_avg_val
-ath5k_moving_average(const struct ath5k_avg_val avg, const int val)
-{
- struct ath5k_avg_val new;
- new.avg_weight = avg.avg_weight ?
- (((avg.avg_weight * ((AVG_SAMPLES) - 1)) +
- (val * (AVG_FACTOR))) / (AVG_SAMPLES)) :
- (val * (AVG_FACTOR));
- new.avg = new.avg_weight / (AVG_FACTOR);
- return new;
-}
-
#endif
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index fbe8aca975d8..cdac5cff0177 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -93,16 +93,16 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
}
/**
- * ath5k_hw_attach - Check if hw is supported and init the needed structs
+ * ath5k_hw_init - Check if hw is supported and init the needed structs
*
- * @sc: The &struct ath5k_softc we got from the driver's attach function
+ * @sc: The &struct ath5k_softc we got from the driver's init_softc function
*
* Check if the device is supported, perform a POST and initialize the needed
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
-int ath5k_hw_attach(struct ath5k_softc *sc)
+int ath5k_hw_init(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
@@ -115,7 +115,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
* HW information
*/
ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
- ah->ah_turbo = false;
+ ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_imr = 0;
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
@@ -128,7 +128,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
/*
* Find the mac version
*/
- srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+ ath5k_hw_read_srev(ah);
+ srev = ah->ah_mac_srev;
if (srev < AR5K_SREV_AR5311)
ah->ah_version = AR5K_AR5210;
else if (srev < AR5K_SREV_AR5212)
@@ -136,6 +137,10 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
else
ah->ah_version = AR5K_AR5212;
+ /* Get the MAC revision */
+ ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+ ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+
/* Fill the ath5k_hw struct with the needed functions */
ret = ath5k_hw_init_desc_functions(ah);
if (ret)
@@ -146,9 +151,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
if (ret)
goto err;
- /* Get MAC, PHY and RADIO revisions */
- ah->ah_mac_srev = srev;
- ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+ /* Get PHY and RADIO revisions */
ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
0xffffffff;
ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
@@ -273,7 +276,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
/*
* Write PCI-E power save settings
*/
- if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
+ if ((ah->ah_version == AR5K_AR5212) && pdev && (pci_is_pcie(pdev))) {
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
@@ -305,8 +308,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
/* Get misc capabilities */
ret = ath5k_hw_set_capabilities(ah);
if (ret) {
- ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
- sc->pdev->device);
+ ATH5K_ERR(sc, "unable to get device capabilities\n");
goto err;
}
@@ -346,11 +348,11 @@ err:
}
/**
- * ath5k_hw_detach - Free the ath5k_hw struct
+ * ath5k_hw_deinit - Free the ath5k_hw struct
*
* @ah: The &struct ath5k_hw
*/
-void ath5k_hw_detach(struct ath5k_hw *ah)
+void ath5k_hw_deinit(struct ath5k_hw *ah)
{
__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 8251946842e6..019a74d533a6 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -47,8 +47,6 @@
#include <linux/io.h>
#include <linux/netdevice.h>
#include <linux/cache.h>
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
#include <linux/ethtool.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
@@ -62,10 +60,9 @@
#include "reg.h"
#include "debug.h"
#include "ani.h"
-#include "../debug.h"
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+int ath5k_modparam_nohwcrypt;
+module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static int modparam_all_channels;
@@ -78,39 +75,24 @@ MODULE_AUTHOR("Nick Kossifidis");
MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
-
-static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
-static int ath5k_beacon_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
-
-/* Known PCI ids */
-static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
- { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
- { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
- { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
- { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
- { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
- { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */
- { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */
- { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
- { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
- { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
- { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
- { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
+
+static int ath5k_init(struct ieee80211_hw *hw);
+static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+ bool skip_pcu);
+int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
/* Known SREVs */
static const struct ath5k_srev_name srev_names[] = {
+#ifdef CONFIG_ATHEROS_AR231X
+ { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R2 },
+ { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R7 },
+ { "2313", AR5K_VERSION_MAC, AR5K_SREV_AR2313_R8 },
+ { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R6 },
+ { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R7 },
+ { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R1 },
+ { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R2 },
+#else
{ "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 },
{ "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 },
{ "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A },
@@ -129,6 +111,7 @@ static const struct ath5k_srev_name srev_names[] = {
{ "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 },
{ "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 },
{ "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 },
+#endif
{ "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN },
{ "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 },
{ "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 },
@@ -142,10 +125,12 @@ static const struct ath5k_srev_name srev_names[] = {
{ "2112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112B },
{ "2413", AR5K_VERSION_RAD, AR5K_SREV_RAD_2413 },
{ "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 },
- { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 },
- { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 },
{ "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 },
{ "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 },
+#ifdef CONFIG_ATHEROS_AR231X
+ { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 },
+ { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 },
+#endif
{ "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN },
};
@@ -191,38 +176,6 @@ static const struct ieee80211_rate ath5k_rates[] = {
/* XR missing */
};
-static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
- struct ath5k_buf *bf)
-{
- BUG_ON(!bf);
- if (!bf->skb)
- return;
- pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_any(bf->skb);
- bf->skb = NULL;
- bf->skbaddr = 0;
- bf->desc->ds_data = 0;
-}
-
-static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
- struct ath5k_buf *bf)
-{
- struct ath5k_hw *ah = sc->ah;
- struct ath_common *common = ath5k_hw_common(ah);
-
- BUG_ON(!bf);
- if (!bf->skb)
- return;
- pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(bf->skb);
- bf->skb = NULL;
- bf->skbaddr = 0;
- bf->desc->ds_data = 0;
-}
-
-
static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
{
u64 tsf = ath5k_hw_get_tsf64(ah);
@@ -233,7 +186,7 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
return (tsf & ~0x7fff) | rstamp;
}
-static const char *
+const char *
ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
{
const char *name = "xxxxx";
@@ -327,14 +280,12 @@ ath5k_copy_channels(struct ath5k_hw *ah,
switch (mode) {
case AR5K_MODE_11A:
- case AR5K_MODE_11A_TURBO:
/* 1..220, but 2GHz frequencies are filtered by check_channel */
size = 220 ;
chfreq = CHANNEL_5GHZ;
break;
case AR5K_MODE_11B:
case AR5K_MODE_11G:
- case AR5K_MODE_11G_TURBO:
size = 26;
chfreq = CHANNEL_2GHZ;
break;
@@ -363,11 +314,6 @@ ath5k_copy_channels(struct ath5k_hw *ah,
case AR5K_MODE_11G:
channels[count].hw_value = chfreq | CHANNEL_OFDM;
break;
- case AR5K_MODE_11A_TURBO:
- case AR5K_MODE_11G_TURBO:
- channels[count].hw_value = chfreq |
- CHANNEL_OFDM | CHANNEL_TURBO;
- break;
case AR5K_MODE_11B:
channels[count].hw_value = CHANNEL_B;
}
@@ -483,7 +429,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
*
* Called with sc->lock.
*/
-static int
+int
ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
{
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
@@ -496,7 +442,7 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
* hardware at the new frequency, and then re-enable
* the relevant bits of the h/w.
*/
- return ath5k_reset(sc, chan);
+ return ath5k_reset(sc, chan, true);
}
static void
@@ -549,7 +495,7 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
/* Calculate combined mode - when APs are active, operate in AP mode.
* Otherwise use the mode of the new interface. This can currently
* only deal with combinations of APs and STAs. Only one ad-hoc
- * interfaces is allowed above.
+ * interfaces is allowed.
*/
if (avf->opmode == NL80211_IFTYPE_AP)
iter_data->opmode = NL80211_IFTYPE_AP;
@@ -558,16 +504,9 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
iter_data->opmode = avf->opmode;
}
-static void ath_do_set_opmode(struct ath5k_softc *sc)
-{
- struct ath5k_hw *ah = sc->ah;
- ath5k_hw_set_opmode(ah, sc->opmode);
- ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n",
- sc->opmode, ath_opmode_to_string(sc->opmode));
-}
-
-void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
- struct ieee80211_vif *vif)
+void
+ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
+ struct ieee80211_vif *vif)
{
struct ath_common *common = ath5k_hw_common(sc->ah);
struct ath_vif_iter_data iter_data;
@@ -595,7 +534,9 @@ void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
/* Nothing active, default to station mode */
sc->opmode = NL80211_IFTYPE_STATION;
- ath_do_set_opmode(sc);
+ ath5k_hw_set_opmode(sc->ah, sc->opmode);
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n",
+ sc->opmode, ath_opmode_to_string(sc->opmode));
if (iter_data.need_set_hw_addr && iter_data.found_active)
ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac);
@@ -604,7 +545,7 @@ void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
}
-static void
+void
ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif)
{
struct ath5k_hw *ah = sc->ah;
@@ -659,10 +600,11 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
return NULL;
}
- *skb_addr = pci_map_single(sc->pdev,
+ *skb_addr = dma_map_single(sc->dev,
skb->data, common->rx_bufsize,
- PCI_DMA_FROMDEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
+ DMA_FROM_DEVICE);
+
+ if (unlikely(dma_mapping_error(sc->dev, *skb_addr))) {
ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
dev_kfree_skb(skb);
return NULL;
@@ -758,8 +700,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
/* XXX endianness */
- bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
+ bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
rate = ieee80211_get_tx_rate(sc->hw, info);
if (!rate) {
@@ -839,7 +781,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
return 0;
err_unmap:
- pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
return ret;
}
@@ -848,7 +790,7 @@ err_unmap:
\*******************/
static int
-ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
+ath5k_desc_alloc(struct ath5k_softc *sc)
{
struct ath5k_desc *ds;
struct ath5k_buf *bf;
@@ -859,7 +801,9 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
/* allocate descriptors */
sc->desc_len = sizeof(struct ath5k_desc) *
(ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
- sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
+
+ sc->desc = dma_alloc_coherent(sc->dev, sc->desc_len,
+ &sc->desc_daddr, GFP_KERNEL);
if (sc->desc == NULL) {
ATH5K_ERR(sc, "can't allocate descriptors\n");
ret = -ENOMEM;
@@ -905,14 +849,45 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
return 0;
err_free:
- pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+ dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
err:
sc->desc = NULL;
return ret;
}
+void
+ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+ BUG_ON(!bf);
+ if (!bf->skb)
+ return;
+ dma_unmap_single(sc->dev, bf->skbaddr, bf->skb->len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(bf->skb);
+ bf->skb = NULL;
+ bf->skbaddr = 0;
+ bf->desc->ds_data = 0;
+}
+
+void
+ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
+
+ BUG_ON(!bf);
+ if (!bf->skb)
+ return;
+ dma_unmap_single(sc->dev, bf->skbaddr, common->rx_bufsize,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(bf->skb);
+ bf->skb = NULL;
+ bf->skbaddr = 0;
+ bf->desc->ds_data = 0;
+}
+
static void
-ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
+ath5k_desc_free(struct ath5k_softc *sc)
{
struct ath5k_buf *bf;
@@ -924,7 +899,7 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
ath5k_txbuf_free_skb(sc, bf);
/* Free memory associated with all descriptors */
- pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+ dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
sc->desc = NULL;
sc->desc_daddr = 0;
@@ -1069,62 +1044,44 @@ err:
return ret;
}
+/**
+ * ath5k_drain_tx_buffs - Empty tx buffers
+ *
+ * @sc The &struct ath5k_softc
+ *
+ * Empty tx buffers from all queues in preparation
+ * of a reset or during shutdown.
+ *
+ * NB: this assumes output has been stopped and
+ * we do not need to block ath5k_tx_tasklet
+ */
static void
-ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+ath5k_drain_tx_buffs(struct ath5k_softc *sc)
{
+ struct ath5k_txq *txq;
struct ath5k_buf *bf, *bf0;
+ int i;
- /*
- * NB: this assumes output has been stopped and
- * we do not need to block ath5k_tx_tasklet
- */
- spin_lock_bh(&txq->lock);
- list_for_each_entry_safe(bf, bf0, &txq->q, list) {
- ath5k_debug_printtxbuf(sc, bf);
-
- ath5k_txbuf_free_skb(sc, bf);
+ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
+ if (sc->txqs[i].setup) {
+ txq = &sc->txqs[i];
+ spin_lock_bh(&txq->lock);
+ list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+ ath5k_debug_printtxbuf(sc, bf);
- spin_lock_bh(&sc->txbuflock);
- list_move_tail(&bf->list, &sc->txbuf);
- sc->txbuf_len++;
- txq->txq_len--;
- spin_unlock_bh(&sc->txbuflock);
- }
- txq->link = NULL;
- txq->txq_poll_mark = false;
- spin_unlock_bh(&txq->lock);
-}
+ ath5k_txbuf_free_skb(sc, bf);
-/*
- * Drain the transmit queues and reclaim resources.
- */
-static void
-ath5k_txq_cleanup(struct ath5k_softc *sc)
-{
- struct ath5k_hw *ah = sc->ah;
- unsigned int i;
-
- /* XXX return value */
- if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
- /* don't touch the hardware if marked invalid */
- ath5k_hw_stop_tx_dma(ah, sc->bhalq);
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
- ath5k_hw_get_txdp(ah, sc->bhalq));
- for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
- if (sc->txqs[i].setup) {
- ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
- "link %p\n",
- sc->txqs[i].qnum,
- ath5k_hw_get_txdp(ah,
- sc->txqs[i].qnum),
- sc->txqs[i].link);
+ spin_lock_bh(&sc->txbuflock);
+ list_move_tail(&bf->list, &sc->txbuf);
+ sc->txbuf_len++;
+ txq->txq_len--;
+ spin_unlock_bh(&sc->txbuflock);
}
+ txq->link = NULL;
+ txq->txq_poll_mark = false;
+ spin_unlock_bh(&txq->lock);
+ }
}
-
- for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
- if (sc->txqs[i].setup)
- ath5k_txq_drainq(sc, &sc->txqs[i]);
}
static void
@@ -1184,16 +1141,19 @@ err:
}
/*
- * Disable the receive h/w in preparation for a reset.
+ * Disable the receive logic on PCU (DRU)
+ * In preparation for a shutdown.
+ *
+ * Note: Doesn't stop rx DMA, ath5k_hw_dma_stop
+ * does.
*/
static void
ath5k_rx_stop(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
- ath5k_hw_stop_rx_pcu(ah); /* disable PCU */
ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */
- ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
+ ath5k_hw_stop_rx_pcu(ah); /* disable PCU */
ath5k_debug_printrxbuffs(sc, ah);
}
@@ -1307,8 +1267,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
return;
- ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg,
- rssi);
+ ewma_add(&ah->ah_beacon_rssi_avg, rssi);
/* in IBSS mode we should keep RSSI statistics per neighbour */
/* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
@@ -1551,9 +1510,9 @@ ath5k_tasklet_rx(unsigned long data)
if (!next_skb)
goto next;
- pci_unmap_single(sc->pdev, bf->skbaddr,
+ dma_unmap_single(sc->dev, bf->skbaddr,
common->rx_bufsize,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
skb_put(skb, rs.rs_datalen);
@@ -1574,8 +1533,9 @@ unlock:
* TX Handling *
\*************/
-static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ath5k_txq *txq)
+int
+ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
@@ -1716,8 +1676,9 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
skb = bf->skb;
bf->skb = NULL;
- pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
- PCI_DMA_TODEVICE);
+
+ dma_unmap_single(sc->dev, bf->skbaddr, skb->len,
+ DMA_TO_DEVICE);
ath5k_tx_frame_completed(sc, skb, &ts);
}
@@ -1771,12 +1732,13 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
u32 flags;
const int padsize = 0;
- bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
+ bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
"skbaddr %llx\n", skb, skb->data, skb->len,
(unsigned long long)bf->skbaddr);
- if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) {
+
+ if (dma_mapping_error(sc->dev, bf->skbaddr)) {
ATH5K_ERR(sc, "beacon DMA mapping failed\n");
return -EIO;
}
@@ -1828,7 +1790,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
return 0;
err_unmap:
- pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
return ret;
}
@@ -1839,7 +1801,7 @@ err_unmap:
*
* Called with the beacon lock.
*/
-static int
+int
ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
int ret;
@@ -1917,7 +1879,8 @@ ath5k_beacon_send(struct ath5k_softc *sc)
sc->bmisscount = 0;
}
- if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+ if ((sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT) {
u64 tsf = ath5k_hw_get_tsf64(ah);
u32 tsftu = TSF_TO_TU(tsf);
int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
@@ -1944,13 +1907,14 @@ ath5k_beacon_send(struct ath5k_softc *sc)
* This should never fail since we check above that no frames
* are still pending on the queue.
*/
- if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
+ if (unlikely(ath5k_hw_stop_beacon_queue(ah, sc->bhalq))) {
ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq);
/* NB: hw still stops DMA, so proceed */
}
- /* refresh the beacon for AP mode */
- if (sc->opmode == NL80211_IFTYPE_AP)
+ /* refresh the beacon for AP or MESH mode */
+ if (sc->opmode == NL80211_IFTYPE_AP ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT)
ath5k_beacon_update(sc->hw, vif);
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
@@ -1983,7 +1947,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
* when we otherwise know we have to update the timers, but we keep it in this
* function to have it all together in one place.
*/
-static void
+void
ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
{
struct ath5k_hw *ah = sc->ah;
@@ -2085,7 +2049,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
* In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
* interrupts to detect TSF updates only.
*/
-static void
+void
ath5k_beacon_config(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
@@ -2113,7 +2077,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
} else
ath5k_beacon_update_timers(sc, -1);
} else {
- ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
+ ath5k_hw_stop_beacon_queue(sc->ah, sc->bhalq);
}
ath5k_hw_set_imr(ah, sc->imask);
@@ -2175,7 +2139,7 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
* AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
}
-static irqreturn_t
+irqreturn_t
ath5k_intr(int irq, void *dev_id)
{
struct ath5k_softc *sc = dev_id;
@@ -2184,7 +2148,8 @@ ath5k_intr(int irq, void *dev_id)
unsigned int counter = 1000;
if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
- !ath5k_hw_is_intr_pending(ah)))
+ ((ath5k_get_bus_type(ah) != ATH_AHB) &&
+ !ath5k_hw_is_intr_pending(ah))))
return IRQ_NONE;
do {
@@ -2250,6 +2215,10 @@ ath5k_intr(int irq, void *dev_id)
tasklet_schedule(&sc->rf_kill.toggleq);
}
+
+ if (ath5k_get_bus_type(ah) == ATH_AHB)
+ break;
+
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
if (unlikely(!counter))
@@ -2349,7 +2318,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
if (needreset) {
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
"TX queues stuck, resetting\n");
- ath5k_reset(sc, sc->curchan);
+ ath5k_reset(sc, NULL, true);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2361,6 +2330,163 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
* Initialization routines *
\*************************/
+int
+ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_common *common;
+ int ret;
+ int csz;
+
+ /* Initialize driver private data */
+ SET_IEEE80211_DEV(hw, sc->dev);
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ /* both antennas can be configured as RX or TX */
+ hw->wiphy->available_antennas_tx = 0x3;
+ hw->wiphy->available_antennas_rx = 0x3;
+
+ hw->extra_tx_headroom = 2;
+ hw->channel_change_time = 5000;
+
+ /*
+ * Mark the device as detached to avoid processing
+ * interrupts until setup is complete.
+ */
+ __set_bit(ATH_STAT_INVALID, sc->status);
+
+ sc->opmode = NL80211_IFTYPE_STATION;
+ sc->bintval = 1000;
+ mutex_init(&sc->lock);
+ spin_lock_init(&sc->rxbuflock);
+ spin_lock_init(&sc->txbuflock);
+ spin_lock_init(&sc->block);
+
+
+ /* Setup interrupt handler */
+ ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+ if (ret) {
+ ATH5K_ERR(sc, "request_irq failed\n");
+ goto err;
+ }
+
+ /* If we passed the test, malloc an ath5k_hw struct */
+ sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+ if (!sc->ah) {
+ ret = -ENOMEM;
+ ATH5K_ERR(sc, "out of memory\n");
+ goto err_irq;
+ }
+
+ sc->ah->ah_sc = sc;
+ sc->ah->ah_iobase = sc->iobase;
+ common = ath5k_hw_common(sc->ah);
+ common->ops = &ath5k_common_ops;
+ common->bus_ops = bus_ops;
+ common->ah = sc->ah;
+ common->hw = hw;
+ common->priv = sc;
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ ath5k_read_cachesize(common, &csz);
+ common->cachelsz = csz << 2; /* convert to bytes */
+
+ spin_lock_init(&common->cc_lock);
+
+ /* Initialize device */
+ ret = ath5k_hw_init(sc);
+ if (ret)
+ goto err_free_ah;
+
+ /* set up multi-rate retry capabilities */
+ if (sc->ah->ah_version == AR5K_AR5212) {
+ hw->max_rates = 4;
+ hw->max_rate_tries = 11;
+ }
+
+ hw->vif_data_size = sizeof(struct ath5k_vif);
+
+ /* Finish private driver data initialization */
+ ret = ath5k_init(hw);
+ if (ret)
+ goto err_ah;
+
+ ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
+ sc->ah->ah_mac_srev,
+ sc->ah->ah_phy_revision);
+
+ if (!sc->ah->ah_single_chip) {
+ /* Single chip radio (!RF5111) */
+ if (sc->ah->ah_radio_5ghz_revision &&
+ !sc->ah->ah_radio_2ghz_revision) {
+ /* No 5GHz support -> report 2GHz radio */
+ if (!test_bit(AR5K_MODE_11A,
+ sc->ah->ah_capabilities.cap_mode)) {
+ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ /* No 2GHz support (5110 and some
+ * 5Ghz only cards) -> report 5Ghz radio */
+ } else if (!test_bit(AR5K_MODE_11B,
+ sc->ah->ah_capabilities.cap_mode)) {
+ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ /* Multiband radio */
+ } else {
+ ATH5K_INFO(sc, "RF%s multiband radio found"
+ " (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ }
+ }
+ /* Multi chip radio (RF5111 - RF2111) ->
+ * report both 2GHz/5GHz radios */
+ else if (sc->ah->ah_radio_5ghz_revision &&
+ sc->ah->ah_radio_2ghz_revision){
+ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_2ghz_revision),
+ sc->ah->ah_radio_2ghz_revision);
+ }
+ }
+
+ ath5k_debug_init_device(sc);
+
+ /* ready to process interrupts */
+ __clear_bit(ATH_STAT_INVALID, sc->status);
+
+ return 0;
+err_ah:
+ ath5k_hw_deinit(sc->ah);
+err_free_ah:
+ kfree(sc->ah);
+err_irq:
+ free_irq(sc->irq, sc);
+err:
+ return ret;
+}
+
static int
ath5k_stop_locked(struct ath5k_softc *sc)
{
@@ -2389,19 +2515,18 @@ ath5k_stop_locked(struct ath5k_softc *sc)
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
ath5k_led_off(sc);
ath5k_hw_set_imr(ah, 0);
- synchronize_irq(sc->pdev->irq);
- }
- ath5k_txq_cleanup(sc);
- if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+ synchronize_irq(sc->irq);
ath5k_rx_stop(sc);
+ ath5k_hw_dma_stop(ah);
+ ath5k_drain_tx_buffs(sc);
ath5k_hw_phy_disable(ah);
}
return 0;
}
-static int
-ath5k_init(struct ath5k_softc *sc)
+int
+ath5k_init_hw(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
@@ -2430,7 +2555,7 @@ ath5k_init(struct ath5k_softc *sc)
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
- ret = ath5k_reset(sc, NULL);
+ ret = ath5k_reset(sc, NULL, false);
if (ret)
goto done;
@@ -2443,7 +2568,9 @@ ath5k_init(struct ath5k_softc *sc)
for (i = 0; i < common->keymax; i++)
ath_hw_keyreset(common, (u16) i);
- ath5k_hw_set_ack_bitrate_high(ah, true);
+ /* Use higher rates for acks instead of base
+ * rate */
+ ah->ah_ack_bitrate_high = true;
for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
sc->bslot[i] = NULL;
@@ -2474,7 +2601,7 @@ static void stop_tasklets(struct ath5k_softc *sc)
* if another thread does a system call and the thread doing the
* stop is preempted).
*/
-static int
+int
ath5k_stop_hw(struct ath5k_softc *sc)
{
int ret;
@@ -2527,25 +2654,35 @@ ath5k_stop_hw(struct ath5k_softc *sc)
* This should be called with sc->lock.
*/
static int
-ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
+ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+ bool skip_pcu)
{
struct ath5k_hw *ah = sc->ah;
- int ret;
+ struct ath_common *common = ath5k_hw_common(ah);
+ int ret, ani_mode;
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
ath5k_hw_set_imr(ah, 0);
- synchronize_irq(sc->pdev->irq);
+ synchronize_irq(sc->irq);
stop_tasklets(sc);
- if (chan) {
- ath5k_txq_cleanup(sc);
- ath5k_rx_stop(sc);
+ /* Save ani mode and disable ANI durring
+ * reset. If we don't we might get false
+ * PHY error interrupts. */
+ ani_mode = ah->ah_sc->ani_state.ani_mode;
+ ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
+ /* We are going to empty hw queues
+ * so we should also free any remaining
+ * tx buffers */
+ ath5k_drain_tx_buffs(sc);
+ if (chan) {
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
+ skip_pcu);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
@@ -2557,11 +2694,20 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
goto err;
}
- ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
+ ath5k_ani_init(ah, ani_mode);
ah->ah_cal_next_full = jiffies;
ah->ah_cal_next_ani = jiffies;
ah->ah_cal_next_nf = jiffies;
+ ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
+
+ /* clear survey data and cycle counters */
+ memset(&sc->survey, 0, sizeof(sc->survey));
+ spin_lock_bh(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
+ memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+ memset(&common->cc_ani, 0, sizeof(common->cc_ani));
+ spin_unlock_bh(&common->cc_lock);
/*
* Change channels and update the h/w rate map if we're switching;
@@ -2590,13 +2736,14 @@ static void ath5k_reset_work(struct work_struct *work)
reset_work);
mutex_lock(&sc->lock);
- ath5k_reset(sc, sc->curchan);
+ ath5k_reset(sc, NULL, true);
mutex_unlock(&sc->lock);
}
static int
-ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+ath5k_init(struct ieee80211_hw *hw)
{
+
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
@@ -2604,7 +2751,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
u8 mac[ETH_ALEN] = {};
int ret;
- ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
/*
* Check if the MAC has multi-rate retry support.
@@ -2641,7 +2787,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
/*
* Allocate tx+rx descriptors and populate the lists.
*/
- ret = ath5k_desc_alloc(sc, pdev);
+ ret = ath5k_desc_alloc(sc);
if (ret) {
ATH5K_ERR(sc, "can't allocate descriptors\n");
goto err;
@@ -2666,33 +2812,46 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_bhal;
}
- /* This order matches mac80211's queue priority, so we can
- * directly use the mac80211 queue number without any mapping */
- txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO);
- if (IS_ERR(txq)) {
- ATH5K_ERR(sc, "can't setup xmit queue\n");
- ret = PTR_ERR(txq);
- goto err_queues;
- }
- txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI);
- if (IS_ERR(txq)) {
- ATH5K_ERR(sc, "can't setup xmit queue\n");
- ret = PTR_ERR(txq);
- goto err_queues;
- }
- txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
- if (IS_ERR(txq)) {
- ATH5K_ERR(sc, "can't setup xmit queue\n");
- ret = PTR_ERR(txq);
- goto err_queues;
- }
- txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
- if (IS_ERR(txq)) {
- ATH5K_ERR(sc, "can't setup xmit queue\n");
- ret = PTR_ERR(txq);
- goto err_queues;
+ /* 5211 and 5212 usually support 10 queues but we better rely on the
+ * capability information */
+ if (ah->ah_capabilities.cap_queues.q_tx_num >= 6) {
+ /* This order matches mac80211's queue priority, so we can
+ * directly use the mac80211 queue number without any mapping */
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ hw->queues = 4;
+ } else {
+ /* older hardware (5210) can only support one data queue */
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ hw->queues = 1;
}
- hw->queues = 4;
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
@@ -2705,8 +2864,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
ret = ath5k_eeprom_read_mac(ah, mac);
if (ret) {
- ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
- sc->pdev->device);
+ ATH5K_ERR(sc, "unable to read address from EEPROM\n");
goto err_queues;
}
@@ -2741,15 +2899,15 @@ err_queues:
err_bhal:
ath5k_hw_release_tx_queue(ah, sc->bhalq);
err_desc:
- ath5k_desc_free(sc, pdev);
+ ath5k_desc_free(sc);
err:
return ret;
}
-static void
-ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+void
+ath5k_deinit_softc(struct ath5k_softc *sc)
{
- struct ath5k_softc *sc = hw->priv;
+ struct ieee80211_hw *hw = sc->hw;
/*
* NB: the order of these is important:
@@ -2764,8 +2922,9 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
* XXX: ??? detach ath5k_hw ???
* Other than that, it's straightforward...
*/
+ ath5k_debug_finish_device(sc);
ieee80211_unregister_hw(hw);
- ath5k_desc_free(sc, pdev);
+ ath5k_desc_free(sc);
ath5k_txq_release(sc);
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
ath5k_unregister_leds(sc);
@@ -2776,231 +2935,12 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
* returns because we'll get called back to reclaim node
* state and potentially want to use them.
*/
+ ath5k_hw_deinit(sc->ah);
+ free_irq(sc->irq, sc);
}
-/********************\
-* Mac80211 functions *
-\********************/
-
-static int
-ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct ath5k_softc *sc = hw->priv;
- u16 qnum = skb_get_queue_mapping(skb);
-
- if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
- dev_kfree_skb_any(skb);
- return 0;
- }
-
- return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
-}
-
-static int ath5k_start(struct ieee80211_hw *hw)
-{
- return ath5k_init(hw->priv);
-}
-
-static void ath5k_stop(struct ieee80211_hw *hw)
-{
- ath5k_stop_hw(hw->priv);
-}
-
-static int ath5k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct ath5k_softc *sc = hw->priv;
- int ret;
- struct ath5k_vif *avf = (void *)vif->drv_priv;
-
- mutex_lock(&sc->lock);
-
- if ((vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC)
- && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
- ret = -ELNRNG;
- goto end;
- }
-
- /* Don't allow other interfaces if one ad-hoc is configured.
- * TODO: Fix the problems with ad-hoc and multiple other interfaces.
- * We would need to operate the HW in ad-hoc mode to allow TSF updates
- * for the IBSS, but this breaks with additional AP or STA interfaces
- * at the moment. */
- if (sc->num_adhoc_vifs ||
- (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
- ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
- ret = -ELNRNG;
- goto end;
- }
-
- switch (vif->type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- avf->opmode = vif->type;
- break;
- default:
- ret = -EOPNOTSUPP;
- goto end;
- }
-
- sc->nvifs++;
- ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
-
- /* Assign the vap/adhoc to a beacon xmit slot. */
- if ((avf->opmode == NL80211_IFTYPE_AP) ||
- (avf->opmode == NL80211_IFTYPE_ADHOC)) {
- int slot;
-
- WARN_ON(list_empty(&sc->bcbuf));
- avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
- list);
- list_del(&avf->bbuf->list);
-
- avf->bslot = 0;
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- if (!sc->bslot[slot]) {
- avf->bslot = slot;
- break;
- }
- }
- BUG_ON(sc->bslot[avf->bslot] != NULL);
- sc->bslot[avf->bslot] = vif;
- if (avf->opmode == NL80211_IFTYPE_AP)
- sc->num_ap_vifs++;
- else
- sc->num_adhoc_vifs++;
- }
-
- /* Any MAC address is fine, all others are included through the
- * filter.
- */
- memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
- ath5k_hw_set_lladdr(sc->ah, vif->addr);
-
- memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
-
- ath5k_mode_setup(sc, vif);
-
- ret = 0;
-end:
- mutex_unlock(&sc->lock);
- return ret;
-}
-
-static void
-ath5k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_vif *avf = (void *)vif->drv_priv;
- unsigned int i;
-
- mutex_lock(&sc->lock);
- sc->nvifs--;
-
- if (avf->bbuf) {
- ath5k_txbuf_free_skb(sc, avf->bbuf);
- list_add_tail(&avf->bbuf->list, &sc->bcbuf);
- for (i = 0; i < ATH_BCBUF; i++) {
- if (sc->bslot[i] == vif) {
- sc->bslot[i] = NULL;
- break;
- }
- }
- avf->bbuf = NULL;
- }
- if (avf->opmode == NL80211_IFTYPE_AP)
- sc->num_ap_vifs--;
- else if (avf->opmode == NL80211_IFTYPE_ADHOC)
- sc->num_adhoc_vifs--;
-
- ath5k_update_bssid_mask_and_opmode(sc, NULL);
- mutex_unlock(&sc->lock);
-}
-
-/*
- * TODO: Phy disable/diversity etc
- */
-static int
-ath5k_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- struct ieee80211_conf *conf = &hw->conf;
- int ret = 0;
-
- mutex_lock(&sc->lock);
-
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = ath5k_chan_set(sc, conf->channel);
- if (ret < 0)
- goto unlock;
- }
-
- if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
- (sc->power_level != conf->power_level)) {
- sc->power_level = conf->power_level;
-
- /* Half dB steps */
- ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
- }
-
- /* TODO:
- * 1) Move this on config_interface and handle each case
- * separately eg. when we have only one STA vif, use
- * AR5K_ANTMODE_SINGLE_AP
- *
- * 2) Allow the user to change antenna mode eg. when only
- * one antenna is present
- *
- * 3) Allow the user to set default/tx antenna when possible
- *
- * 4) Default mode should handle 90% of the cases, together
- * with fixed a/b and single AP modes we should be able to
- * handle 99%. Sectored modes are extreme cases and i still
- * haven't found a usage for them. If we decide to support them,
- * then we must allow the user to set how many tx antennas we
- * have available
- */
- ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
-
-unlock:
- mutex_unlock(&sc->lock);
- return ret;
-}
-
-static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
- struct netdev_hw_addr_list *mc_list)
-{
- u32 mfilt[2], val;
- u8 pos;
- struct netdev_hw_addr *ha;
-
- mfilt[0] = 0;
- mfilt[1] = 1;
-
- netdev_hw_addr_list_for_each(ha, mc_list) {
- /* calculate XOR of eight 6-bit values */
- val = get_unaligned_le32(ha->addr + 0);
- pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- val = get_unaligned_le32(ha->addr + 3);
- pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- pos &= 0x3f;
- mfilt[pos / 32] |= (1 << (pos % 32));
- /* XXX: we might be able to just do this instead,
- * but not sure, needs testing, if we do use this we'd
- * neet to inform below to not reset the mcast */
- /* ath5k_hw_set_mcast_filterindex(ah,
- * ha->addr[5]); */
- }
-
- return ((u64)(mfilt[1]) << 32) | mfilt[0];
-}
-
-static bool ath_any_vif_assoc(struct ath5k_softc *sc)
+bool
+ath_any_vif_assoc(struct ath5k_softc *sc)
{
struct ath_vif_iter_data iter_data;
iter_data.hw_macaddr = NULL;
@@ -3013,242 +2953,7 @@ static bool ath_any_vif_assoc(struct ath5k_softc *sc)
return iter_data.any_assoc;
}
-#define SUPPORTED_FIF_FLAGS \
- FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
- FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
- FIF_BCN_PRBRESP_PROMISC
-/*
- * o always accept unicast, broadcast, and multicast traffic
- * o multicast traffic for all BSSIDs will be enabled if mac80211
- * says it should be
- * o maintain current state of phy ofdm or phy cck error reception.
- * If the hardware detects any of these type of errors then
- * ath5k_hw_get_rx_filter() will pass to us the respective
- * hardware filters to be able to receive these type of frames.
- * o probe request frames are accepted only when operating in
- * hostap, adhoc, or monitor modes
- * o enable promiscuous mode according to the interface state
- * o accept beacons:
- * - when operating in adhoc mode so the 802.11 layer creates
- * node table entries for peers,
- * - when operating in station mode for collecting rssi data when
- * the station is otherwise quiet, or
- * - when scanning
- */
-static void ath5k_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *new_flags,
- u64 multicast)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- u32 mfilt[2], rfilt;
-
- mutex_lock(&sc->lock);
-
- mfilt[0] = multicast;
- mfilt[1] = multicast >> 32;
-
- /* Only deal with supported flags */
- changed_flags &= SUPPORTED_FIF_FLAGS;
- *new_flags &= SUPPORTED_FIF_FLAGS;
-
- /* If HW detects any phy or radar errors, leave those filters on.
- * Also, always enable Unicast, Broadcasts and Multicast
- * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
- rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
- (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
- AR5K_RX_FILTER_MCAST);
-
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
- if (*new_flags & FIF_PROMISC_IN_BSS) {
- __set_bit(ATH_STAT_PROMISC, sc->status);
- } else {
- __clear_bit(ATH_STAT_PROMISC, sc->status);
- }
- }
-
- if (test_bit(ATH_STAT_PROMISC, sc->status))
- rfilt |= AR5K_RX_FILTER_PROM;
-
- /* Note, AR5K_RX_FILTER_MCAST is already enabled */
- if (*new_flags & FIF_ALLMULTI) {
- mfilt[0] = ~0;
- mfilt[1] = ~0;
- }
-
- /* This is the best we can do */
- if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
- rfilt |= AR5K_RX_FILTER_PHYERR;
-
- /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
- * and probes for any BSSID */
- if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
- rfilt |= AR5K_RX_FILTER_BEACON;
-
- /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
- * set we should only pass on control frames for this
- * station. This needs testing. I believe right now this
- * enables *all* control frames, which is OK.. but
- * but we should see if we can improve on granularity */
- if (*new_flags & FIF_CONTROL)
- rfilt |= AR5K_RX_FILTER_CONTROL;
-
- /* Additional settings per mode -- this is per ath5k */
-
- /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
-
- switch (sc->opmode) {
- case NL80211_IFTYPE_MESH_POINT:
- rfilt |= AR5K_RX_FILTER_CONTROL |
- AR5K_RX_FILTER_BEACON |
- AR5K_RX_FILTER_PROBEREQ |
- AR5K_RX_FILTER_PROM;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- rfilt |= AR5K_RX_FILTER_PROBEREQ |
- AR5K_RX_FILTER_BEACON;
- break;
- case NL80211_IFTYPE_STATION:
- if (sc->assoc)
- rfilt |= AR5K_RX_FILTER_BEACON;
- default:
- break;
- }
-
- /* Set filters */
- ath5k_hw_set_rx_filter(ah, rfilt);
-
- /* Set multicast bits */
- ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
- /* Set the cached hw filter flags, this will later actually
- * be set in HW */
- sc->filter_flags = rfilt;
-
- mutex_unlock(&sc->lock);
-}
-
-static int
-ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- struct ath_common *common = ath5k_hw_common(ah);
- int ret = 0;
-
- if (modparam_nohwcrypt)
- return -EOPNOTSUPP;
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- case WLAN_CIPHER_SUITE_TKIP:
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
- break;
- return -EOPNOTSUPP;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- mutex_lock(&sc->lock);
-
- switch (cmd) {
- case SET_KEY:
- ret = ath_key_config(common, vif, sta, key);
- if (ret >= 0) {
- key->hw_key_idx = ret;
- /* push IV and Michael MIC generation to stack */
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
- key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
- ret = 0;
- }
- break;
- case DISABLE_KEY:
- ath_key_delete(common, key);
- break;
- default:
- ret = -EINVAL;
- }
-
- mmiowb();
- mutex_unlock(&sc->lock);
- return ret;
-}
-
-static int
-ath5k_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
-{
- struct ath5k_softc *sc = hw->priv;
-
- /* Force update */
- ath5k_hw_update_mib_counters(sc->ah);
-
- stats->dot11ACKFailureCount = sc->stats.ack_fail;
- stats->dot11RTSFailureCount = sc->stats.rts_fail;
- stats->dot11RTSSuccessCount = sc->stats.rts_ok;
- stats->dot11FCSErrorCount = sc->stats.fcs_error;
-
- return 0;
-}
-
-static int ath5k_get_survey(struct ieee80211_hw *hw, int idx,
- struct survey_info *survey)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ieee80211_conf *conf = &hw->conf;
-
- if (idx != 0)
- return -ENOENT;
-
- survey->channel = conf->channel;
- survey->filled = SURVEY_INFO_NOISE_DBM;
- survey->noise = sc->ah->ah_noise_floor;
-
- return 0;
-}
-
-static u64
-ath5k_get_tsf(struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
-
- return ath5k_hw_get_tsf64(sc->ah);
-}
-
-static void
-ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
-{
- struct ath5k_softc *sc = hw->priv;
-
- ath5k_hw_set_tsf64(sc->ah, tsf);
-}
-
-static void
-ath5k_reset_tsf(struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
-
- /*
- * in IBSS mode we need to update the beacon timers too.
- * this will also reset the TSF if we call it with 0
- */
- if (sc->opmode == NL80211_IFTYPE_ADHOC)
- ath5k_beacon_update_timers(sc, 0);
- else
- ath5k_hw_reset_tsf(sc->ah);
-}
-
-static void
+void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
struct ath5k_softc *sc = hw->priv;
@@ -3262,494 +2967,3 @@ set_beacon_filter(struct ieee80211_hw *hw, bool enable)
ath5k_hw_set_rx_filter(ah, rfilt);
sc->filter_flags = rfilt;
}
-
-static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes)
-{
- struct ath5k_vif *avf = (void *)vif->drv_priv;
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- struct ath_common *common = ath5k_hw_common(ah);
- unsigned long flags;
-
- mutex_lock(&sc->lock);
-
- if (changes & BSS_CHANGED_BSSID) {
- /* Cache for later use during resets */
- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
- common->curaid = 0;
- ath5k_hw_set_bssid(ah);
- mmiowb();
- }
-
- if (changes & BSS_CHANGED_BEACON_INT)
- sc->bintval = bss_conf->beacon_int;
-
- if (changes & BSS_CHANGED_ASSOC) {
- avf->assoc = bss_conf->assoc;
- if (bss_conf->assoc)
- sc->assoc = bss_conf->assoc;
- else
- sc->assoc = ath_any_vif_assoc(sc);
-
- if (sc->opmode == NL80211_IFTYPE_STATION)
- set_beacon_filter(hw, sc->assoc);
- ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
- AR5K_LED_ASSOC : AR5K_LED_INIT);
- if (bss_conf->assoc) {
- ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
- "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, common->curbssid);
- common->curaid = bss_conf->aid;
- ath5k_hw_set_bssid(ah);
- /* Once ANI is available you would start it here */
- }
- }
-
- if (changes & BSS_CHANGED_BEACON) {
- spin_lock_irqsave(&sc->block, flags);
- ath5k_beacon_update(hw, vif);
- spin_unlock_irqrestore(&sc->block, flags);
- }
-
- if (changes & BSS_CHANGED_BEACON_ENABLED)
- sc->enable_beacon = bss_conf->enable_beacon;
-
- if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_BEACON_INT))
- ath5k_beacon_config(sc);
-
- mutex_unlock(&sc->lock);
-}
-
-static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
- if (!sc->assoc)
- ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
-}
-
-static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
- ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
- AR5K_LED_ASSOC : AR5K_LED_INIT);
-}
-
-/**
- * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
- *
- * @hw: struct ieee80211_hw pointer
- * @coverage_class: IEEE 802.11 coverage class number
- *
- * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
- * coverage class. The values are persistent, they are restored after device
- * reset.
- */
-static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
-{
- struct ath5k_softc *sc = hw->priv;
-
- mutex_lock(&sc->lock);
- ath5k_hw_set_coverage_class(sc->ah, coverage_class);
- mutex_unlock(&sc->lock);
-}
-
-static int ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- struct ath5k_txq_info qi;
- int ret = 0;
-
- if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
- return 0;
-
- mutex_lock(&sc->lock);
-
- ath5k_hw_get_tx_queueprops(ah, queue, &qi);
-
- qi.tqi_aifs = params->aifs;
- qi.tqi_cw_min = params->cw_min;
- qi.tqi_cw_max = params->cw_max;
- qi.tqi_burst_time = params->txop;
-
- ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
- "Configure tx [queue %d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- queue, params->aifs, params->cw_min,
- params->cw_max, params->txop);
-
- if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
- ATH5K_ERR(sc,
- "Unable to update hardware queue %u!\n", queue);
- ret = -EIO;
- } else
- ath5k_hw_reset_tx_queue(ah, queue);
-
- mutex_unlock(&sc->lock);
-
- return ret;
-}
-
-static const struct ieee80211_ops ath5k_hw_ops = {
- .tx = ath5k_tx,
- .start = ath5k_start,
- .stop = ath5k_stop,
- .add_interface = ath5k_add_interface,
- .remove_interface = ath5k_remove_interface,
- .config = ath5k_config,
- .prepare_multicast = ath5k_prepare_multicast,
- .configure_filter = ath5k_configure_filter,
- .set_key = ath5k_set_key,
- .get_stats = ath5k_get_stats,
- .get_survey = ath5k_get_survey,
- .conf_tx = ath5k_conf_tx,
- .get_tsf = ath5k_get_tsf,
- .set_tsf = ath5k_set_tsf,
- .reset_tsf = ath5k_reset_tsf,
- .bss_info_changed = ath5k_bss_info_changed,
- .sw_scan_start = ath5k_sw_scan_start,
- .sw_scan_complete = ath5k_sw_scan_complete,
- .set_coverage_class = ath5k_set_coverage_class,
-};
-
-/********************\
-* PCI Initialization *
-\********************/
-
-static int __devinit
-ath5k_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- void __iomem *mem;
- struct ath5k_softc *sc;
- struct ath_common *common;
- struct ieee80211_hw *hw;
- int ret;
- u8 csz;
-
- /*
- * L0s needs to be disabled on all ath5k cards.
- *
- * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
- * by default in the future in 2.6.36) this will also mean both L1 and
- * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
- * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
- * though but cannot currently undue the effect of a blacklist, for
- * details you can read pcie_aspm_sanity_check() and see how it adjusts
- * the device link capability.
- *
- * It may be possible in the future to implement some PCI API to allow
- * drivers to override blacklists for pre 1.1 PCIe but for now it is
- * best to accept that both L0s and L1 will be disabled completely for
- * distributions shipping with CONFIG_PCIEASPM rather than having this
- * issue present. Motivation for adding this new API will be to help
- * with power consumption for some of these devices.
- */
- pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
-
- ret = pci_enable_device(pdev);
- if (ret) {
- dev_err(&pdev->dev, "can't enable device\n");
- goto err;
- }
-
- /* XXX 32-bit addressing only */
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(&pdev->dev, "32-bit DMA not available\n");
- goto err_dis;
- }
-
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
- if (csz == 0) {
- /*
- * Linux 2.4.18 (at least) writes the cache line size
- * register as a 16-bit wide register which is wrong.
- * We must have this setup properly for rx buffer
- * DMA to work so force a reasonable value here if it
- * comes up zero.
- */
- csz = L1_CACHE_BYTES >> 2;
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
- }
- /*
- * The default setting of latency timer yields poor results,
- * set it to the value used by other systems. It may be worth
- * tweaking this setting more.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
-
- /* Enable bus mastering */
- pci_set_master(pdev);
-
- /*
- * Disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state.
- */
- pci_write_config_byte(pdev, 0x41, 0);
-
- ret = pci_request_region(pdev, 0, "ath5k");
- if (ret) {
- dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
- goto err_dis;
- }
-
- mem = pci_iomap(pdev, 0, 0);
- if (!mem) {
- dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
- ret = -EIO;
- goto err_reg;
- }
-
- /*
- * Allocate hw (mac80211 main struct)
- * and hw->priv (driver private data)
- */
- hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
- if (hw == NULL) {
- dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
- ret = -ENOMEM;
- goto err_map;
- }
-
- dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
-
- /* Initialize driver private data */
- SET_IEEE80211_DEV(hw, &pdev->dev);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
-
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- hw->extra_tx_headroom = 2;
- hw->channel_change_time = 5000;
- sc = hw->priv;
- sc->hw = hw;
- sc->pdev = pdev;
-
- /*
- * Mark the device as detached to avoid processing
- * interrupts until setup is complete.
- */
- __set_bit(ATH_STAT_INVALID, sc->status);
-
- sc->iobase = mem; /* So we can unmap it on detach */
- sc->opmode = NL80211_IFTYPE_STATION;
- sc->bintval = 1000;
- mutex_init(&sc->lock);
- spin_lock_init(&sc->rxbuflock);
- spin_lock_init(&sc->txbuflock);
- spin_lock_init(&sc->block);
-
- /* Set private data */
- pci_set_drvdata(pdev, sc);
-
- /* Setup interrupt handler */
- ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (ret) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_free;
- }
-
- /* If we passed the test, malloc an ath5k_hw struct */
- sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
- if (!sc->ah) {
- ret = -ENOMEM;
- ATH5K_ERR(sc, "out of memory\n");
- goto err_irq;
- }
-
- sc->ah->ah_sc = sc;
- sc->ah->ah_iobase = sc->iobase;
- common = ath5k_hw_common(sc->ah);
- common->ops = &ath5k_common_ops;
- common->ah = sc->ah;
- common->hw = hw;
- common->cachelsz = csz << 2; /* convert to bytes */
- spin_lock_init(&common->cc_lock);
-
- /* Initialize device */
- ret = ath5k_hw_attach(sc);
- if (ret) {
- goto err_free_ah;
- }
-
- /* set up multi-rate retry capabilities */
- if (sc->ah->ah_version == AR5K_AR5212) {
- hw->max_rates = 4;
- hw->max_rate_tries = 11;
- }
-
- hw->vif_data_size = sizeof(struct ath5k_vif);
-
- /* Finish private driver data initialization */
- ret = ath5k_attach(pdev, hw);
- if (ret)
- goto err_ah;
-
- ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
- sc->ah->ah_mac_srev,
- sc->ah->ah_phy_revision);
-
- if (!sc->ah->ah_single_chip) {
- /* Single chip radio (!RF5111) */
- if (sc->ah->ah_radio_5ghz_revision &&
- !sc->ah->ah_radio_2ghz_revision) {
- /* No 5GHz support -> report 2GHz radio */
- if (!test_bit(AR5K_MODE_11A,
- sc->ah->ah_capabilities.cap_mode)) {
- ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- /* No 2GHz support (5110 and some
- * 5Ghz only cards) -> report 5Ghz radio */
- } else if (!test_bit(AR5K_MODE_11B,
- sc->ah->ah_capabilities.cap_mode)) {
- ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- /* Multiband radio */
- } else {
- ATH5K_INFO(sc, "RF%s multiband radio found"
- " (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- }
- }
- /* Multi chip radio (RF5111 - RF2111) ->
- * report both 2GHz/5GHz radios */
- else if (sc->ah->ah_radio_5ghz_revision &&
- sc->ah->ah_radio_2ghz_revision){
- ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_2ghz_revision),
- sc->ah->ah_radio_2ghz_revision);
- }
- }
-
- ath5k_debug_init_device(sc);
-
- /* ready to process interrupts */
- __clear_bit(ATH_STAT_INVALID, sc->status);
-
- return 0;
-err_ah:
- ath5k_hw_detach(sc->ah);
-err_free_ah:
- kfree(sc->ah);
-err_irq:
- free_irq(pdev->irq, sc);
-err_free:
- ieee80211_free_hw(hw);
-err_map:
- pci_iounmap(pdev, mem);
-err_reg:
- pci_release_region(pdev, 0);
-err_dis:
- pci_disable_device(pdev);
-err:
- return ret;
-}
-
-static void __devexit
-ath5k_pci_remove(struct pci_dev *pdev)
-{
- struct ath5k_softc *sc = pci_get_drvdata(pdev);
-
- ath5k_debug_finish_device(sc);
- ath5k_detach(pdev, sc->hw);
- ath5k_hw_detach(sc->ah);
- kfree(sc->ah);
- free_irq(pdev->irq, sc);
- pci_iounmap(pdev, sc->iobase);
- pci_release_region(pdev, 0);
- pci_disable_device(pdev);
- ieee80211_free_hw(sc->hw);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ath5k_pci_suspend(struct device *dev)
-{
- struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
-
- ath5k_led_off(sc);
- return 0;
-}
-
-static int ath5k_pci_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct ath5k_softc *sc = pci_get_drvdata(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_write_config_byte(pdev, 0x41, 0);
-
- ath5k_led_enable(sc);
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
-#define ATH5K_PM_OPS (&ath5k_pm_ops)
-#else
-#define ATH5K_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
-
-static struct pci_driver ath5k_pci_driver = {
- .name = KBUILD_MODNAME,
- .id_table = ath5k_pci_id_table,
- .probe = ath5k_pci_probe,
- .remove = __devexit_p(ath5k_pci_remove),
- .driver.pm = ATH5K_PM_OPS,
-};
-
-/*
- * Module init/exit functions
- */
-static int __init
-init_ath5k_pci(void)
-{
- int ret;
-
- ret = pci_register_driver(&ath5k_pci_driver);
- if (ret) {
- printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
- return ret;
- }
-
- return 0;
-}
-
-static void __exit
-exit_ath5k_pci(void)
-{
- pci_unregister_driver(&ath5k_pci_driver);
-}
-
-module_init(init_ath5k_pci);
-module_exit(exit_ath5k_pci);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 9a79773cdc2a..6d511476e4d2 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -169,7 +169,10 @@ struct ath5k_vif {
/* Software Carrier, keeps track of the driver state
* associated with an instance of a device */
struct ath5k_softc {
- struct pci_dev *pdev; /* for dma mapping */
+ struct pci_dev *pdev;
+ struct device *dev; /* for dma mapping */
+ int irq;
+ u16 devid;
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
struct ieee80211_hw *hw; /* IEEE 802.11 common */
@@ -255,6 +258,8 @@ struct ath5k_softc {
struct tasklet_struct ani_tasklet; /* ANI calibration */
struct delayed_work tx_complete_work;
+
+ struct survey_info survey; /* collected survey info */
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index beae519aa735..31cad80e9b01 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -49,7 +49,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
/* Set supported modes */
__set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
- __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
} else {
/*
* XXX The tranceiver supports frequencies from 4920 to 6100GHz
@@ -74,11 +73,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
/* Set supported modes */
__set_bit(AR5K_MODE_11A,
ah->ah_capabilities.cap_mode);
- __set_bit(AR5K_MODE_11A_TURBO,
- ah->ah_capabilities.cap_mode);
- if (ah->ah_version == AR5K_AR5212)
- __set_bit(AR5K_MODE_11G_TURBO,
- ah->ah_capabilities.cap_mode);
}
/* Enable 802.11b if a 2GHz capable radio (2111/5112) is
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index acda56ee521b..d2f84d76bb07 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -60,7 +60,6 @@
#include "base.h"
#include "debug.h"
-#include "../debug.h"
static unsigned int ath5k_debug;
module_param_named(debug, ath5k_debug, uint, 0);
@@ -312,6 +311,7 @@ static const struct {
{ ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
{ ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
+ { ATH5K_DEBUG_DMA, "dma", "dma start/stop" },
{ ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" },
{ ATH5K_DEBUG_DESC, "desc", "descriptor chains" },
{ ATH5K_DEBUG_ANY, "all", "show all debug levels" },
@@ -554,63 +554,63 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
len += snprintf(buf+len, sizeof(buf)-len,
"RX\n---------------------\n");
- len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%u\t(%u%%)\n",
st->rxerr_crc,
st->rx_all_count > 0 ?
st->rxerr_crc*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%u\t(%u%%)\n",
st->rxerr_phy,
st->rx_all_count > 0 ?
st->rxerr_phy*100/st->rx_all_count : 0);
for (i = 0; i < 32; i++) {
if (st->rxerr_phy_code[i])
len += snprintf(buf+len, sizeof(buf)-len,
- " phy_err[%d]\t%d\n",
+ " phy_err[%u]\t%u\n",
i, st->rxerr_phy_code[i]);
}
- len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n",
st->rxerr_fifo,
st->rx_all_count > 0 ?
st->rxerr_fifo*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%u\t(%u%%)\n",
st->rxerr_decrypt,
st->rx_all_count > 0 ?
st->rxerr_decrypt*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%u\t(%u%%)\n",
st->rxerr_mic,
st->rx_all_count > 0 ?
st->rxerr_mic*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "process\t%u\t(%u%%)\n",
st->rxerr_proc,
st->rx_all_count > 0 ?
st->rxerr_proc*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%u\t(%u%%)\n",
st->rxerr_jumbo,
st->rx_all_count > 0 ?
st->rxerr_jumbo*100/st->rx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%u]\n",
st->rx_all_count);
- len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%u\n",
st->rx_bytes_count);
len += snprintf(buf+len, sizeof(buf)-len,
"\nTX\n---------------------\n");
- len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "retry\t%u\t(%u%%)\n",
st->txerr_retry,
st->tx_all_count > 0 ?
st->txerr_retry*100/st->tx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n",
st->txerr_fifo,
st->tx_all_count > 0 ?
st->txerr_fifo*100/st->tx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "filter\t%u\t(%u%%)\n",
st->txerr_filt,
st->tx_all_count > 0 ?
st->txerr_filt*100/st->tx_all_count : 0);
- len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%u]\n",
st->tx_all_count);
- len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n",
+ len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%u\n",
st->tx_bytes_count);
if (len > sizeof(buf))
@@ -719,7 +719,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
st->mib_intr);
len += snprintf(buf+len, sizeof(buf)-len,
"beacon RSSI average:\t%d\n",
- sc->ah->ah_beacon_rssi_avg.avg);
+ (int)ewma_read(&sc->ah->ah_beacon_rssi_avg));
#define CC_PRINT(_struct, _field) \
_struct._field, \
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index 236edbd2507d..3e34428d5126 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -95,6 +95,7 @@ struct ath5k_dbg_info {
* @ATH5K_DEBUG_DUMP_RX: print received skb content
* @ATH5K_DEBUG_DUMP_TX: print transmit skb content
* @ATH5K_DEBUG_DUMPBANDS: dump bands
+ * @ATH5K_DEBUG_DMA: debug dma start/stop
* @ATH5K_DEBUG_TRACE: trace function calls
* @ATH5K_DEBUG_DESC: descriptor setup
* @ATH5K_DEBUG_ANY: show at any debug level
@@ -118,6 +119,7 @@ enum ath5k_debug_level {
ATH5K_DEBUG_DUMP_RX = 0x00000100,
ATH5K_DEBUG_DUMP_TX = 0x00000200,
ATH5K_DEBUG_DUMPBANDS = 0x00000400,
+ ATH5K_DEBUG_DMA = 0x00000800,
ATH5K_DEBUG_ANI = 0x00002000,
ATH5K_DEBUG_DESC = 0x00004000,
ATH5K_DEBUG_ANY = 0xffffffff
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 43244382f213..16b44ff7dd3e 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -26,9 +26,10 @@
#include "debug.h"
#include "base.h"
-/*
- * TX Descriptors
- */
+
+/************************\
+* TX Control descriptors *
+\************************/
/*
* Initialize the 2-word tx control descriptor on 5210/5211
@@ -335,6 +336,11 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0;
}
+
+/***********************\
+* TX Status descriptors *
+\***********************/
+
/*
* Proccess the tx status descriptor on 5210/5211
*/
@@ -476,9 +482,10 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
return 0;
}
-/*
- * RX Descriptors
- */
+
+/****************\
+* RX Descriptors *
+\****************/
/*
* Initialize an rx control descriptor
@@ -666,6 +673,11 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
return 0;
}
+
+/********\
+* Attach *
+\********/
+
/*
* Init function pointers inside ath5k_hw struct
*/
diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h
index b2adb2a281c2..2509d0bf037d 100644
--- a/drivers/net/wireless/ath/ath5k/desc.h
+++ b/drivers/net/wireless/ath/ath5k/desc.h
@@ -26,7 +26,7 @@
struct ath5k_hw_rx_ctl {
u32 rx_control_0; /* RX control word 0 */
u32 rx_control_1; /* RX control word 1 */
-} __packed;
+} __packed __aligned(4);
/* RX control word 1 fields/flags */
#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */
@@ -39,7 +39,7 @@ struct ath5k_hw_rx_ctl {
struct ath5k_hw_rx_status {
u32 rx_status_0; /* RX status word 0 */
u32 rx_status_1; /* RX status word 1 */
-} __packed;
+} __packed __aligned(4);
/* 5210/5211 */
/* RX status word 0 fields/flags */
@@ -129,7 +129,7 @@ enum ath5k_phy_error_code {
struct ath5k_hw_2w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */
u32 tx_control_1; /* TX control word 1 */
-} __packed;
+} __packed __aligned(4);
/* TX control word 0 fields/flags */
#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */
@@ -185,7 +185,7 @@ struct ath5k_hw_4w_tx_ctl {
u32 tx_control_1; /* TX control word 1 */
u32 tx_control_2; /* TX control word 2 */
u32 tx_control_3; /* TX control word 3 */
-} __packed;
+} __packed __aligned(4);
/* TX control word 0 fields/flags */
#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */
@@ -244,7 +244,7 @@ struct ath5k_hw_4w_tx_ctl {
struct ath5k_hw_tx_status {
u32 tx_status_0; /* TX status word 0 */
u32 tx_status_1; /* TX status word 1 */
-} __packed;
+} __packed __aligned(4);
/* TX status word 0 fields/flags */
#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 /* TX success */
@@ -282,7 +282,7 @@ struct ath5k_hw_tx_status {
struct ath5k_hw_5210_tx_desc {
struct ath5k_hw_2w_tx_ctl tx_ctl;
struct ath5k_hw_tx_status tx_stat;
-} __packed;
+} __packed __aligned(4);
/*
* 5212 hardware TX descriptor
@@ -290,7 +290,7 @@ struct ath5k_hw_5210_tx_desc {
struct ath5k_hw_5212_tx_desc {
struct ath5k_hw_4w_tx_ctl tx_ctl;
struct ath5k_hw_tx_status tx_stat;
-} __packed;
+} __packed __aligned(4);
/*
* Common hardware RX descriptor
@@ -298,7 +298,7 @@ struct ath5k_hw_5212_tx_desc {
struct ath5k_hw_all_rx_desc {
struct ath5k_hw_rx_ctl rx_ctl;
struct ath5k_hw_rx_status rx_stat;
-} __packed;
+} __packed __aligned(4);
/*
* Atheros hardware DMA descriptor
@@ -313,7 +313,7 @@ struct ath5k_desc {
struct ath5k_hw_5212_tx_desc ds_tx5212;
struct ath5k_hw_all_rx_desc ds_rx;
} ud;
-} __packed;
+} __packed __aligned(4);
#define AR5K_RXDESC_INTREQ 0x0020
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 923c9ca5c4f0..0064be7ce5c9 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -37,6 +37,7 @@
#include "debug.h"
#include "base.h"
+
/*********\
* Receive *
\*********/
@@ -57,7 +58,7 @@ void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
*
* @ah: The &struct ath5k_hw
*/
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
{
unsigned int i;
@@ -69,7 +70,11 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
for (i = 1000; i > 0 &&
(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
i--)
- udelay(10);
+ udelay(100);
+
+ if (!i)
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "failed to stop RX DMA !\n");
return i ? 0 : -EBUSY;
}
@@ -90,11 +95,18 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
* @ah: The &struct ath5k_hw
* @phys_addr: RX descriptor address
*
- * XXX: Should we check if rx is enabled before setting rxdp ?
+ * Returns -EIO if rx is active
*/
-void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
{
+ if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "tried to set RXDP while rx was active !\n");
+ return -EIO;
+ }
+
ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+ return 0;
}
@@ -125,7 +137,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Return if queue is declared inactive */
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
- return -EIO;
+ return -EINVAL;
if (ah->ah_version == AR5K_AR5210) {
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
@@ -173,10 +185,10 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
*
* Stop DMA transmit on a specific hw queue and drain queue so we don't
* have any pending frames. Returns -EBUSY if we still have pending frames,
- * -EINVAL if queue number is out of range.
+ * -EINVAL if queue number is out of range or inactive.
*
*/
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
{
unsigned int i = 40;
u32 tx_queue, pending;
@@ -185,7 +197,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Return if queue is declared inactive */
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
- return -EIO;
+ return -EINVAL;
if (ah->ah_version == AR5K_AR5210) {
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
@@ -211,12 +223,31 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
} else {
+
+ /*
+ * Enable DCU early termination to quickly
+ * flush any pending frames from QCU
+ */
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ AR5K_QCU_MISC_DCU_EARLY);
+
/*
* Schedule TX disable and wait until queue is empty
*/
AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
- /*Check for pending frames*/
+ /* Wait for queue to stop */
+ for (i = 1000; i > 0 &&
+ (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue) != 0);
+ i--)
+ udelay(100);
+
+ if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "queue %i didn't stop !\n", queue);
+
+ /* Check for pending frames */
+ i = 1000;
do {
pending = ath5k_hw_reg_read(ah,
AR5K_QUEUE_STATUS(queue)) &
@@ -247,12 +278,12 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
/* Wait a while and disable mechanism */
- udelay(200);
+ udelay(400);
AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
AR5K_QUIET_CTL1_QT_EN);
/* Re-check for pending frames */
- i = 40;
+ i = 100;
do {
pending = ath5k_hw_reg_read(ah,
AR5K_QUEUE_STATUS(queue)) &
@@ -262,12 +293,27 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
+
+ if (pending)
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "quiet mechanism didn't work q:%i !\n",
+ queue);
}
+ /*
+ * Disable DCU early termination
+ */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ AR5K_QCU_MISC_DCU_EARLY);
+
/* Clear register */
ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
- if (pending)
+ if (pending) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "tx dma didn't stop (q:%i, frm:%i) !\n",
+ queue, pending);
return -EBUSY;
+ }
}
/* TODO: Check for success on 5210 else return error */
@@ -275,6 +321,26 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
}
/**
+ * ath5k_hw_stop_beacon_queue - Stop beacon queue
+ *
+ * @ah The &struct ath5k_hw
+ * @queue The queue number
+ *
+ * Returns -EIO if queue didn't stop
+ */
+int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+ int ret;
+ ret = ath5k_hw_stop_tx_dma(ah, queue);
+ if (ret) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+ "beacon queue didn't stop !\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
* ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
*
* @ah: The &struct ath5k_hw
@@ -427,6 +493,7 @@ done:
return ret;
}
+
/*******************\
* Interrupt masking *
\*******************/
@@ -688,3 +755,92 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
return old_mask;
}
+
+/********************\
+ Init/Stop functions
+\********************/
+
+/**
+ * ath5k_hw_dma_init - Initialize DMA unit
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Set DMA size and pre-enable interrupts
+ * (driver handles tx/rx buffer setup and
+ * dma start/stop)
+ *
+ * XXX: Save/restore RXDP/TXDP registers ?
+ */
+void ath5k_hw_dma_init(struct ath5k_hw *ah)
+{
+ /*
+ * Set Rx/Tx DMA Configuration
+ *
+ * Set standard DMA size (128). Note that
+ * a DMA size of 512 causes rx overruns and tx errors
+ * on pci-e cards (tested on 5424 but since rx overruns
+ * also occur on 5416/5418 with madwifi we set 128
+ * for all PCI-E cards to be safe).
+ *
+ * XXX: need to check 5210 for this
+ * TODO: Check out tx triger level, it's always 64 on dumps but I
+ * guess we can tweak it and see how it goes ;-)
+ */
+ if (ah->ah_version != AR5K_AR5210) {
+ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+ }
+
+ /* Pre-enable interrupts on 5211/5212*/
+ if (ah->ah_version != AR5K_AR5210)
+ ath5k_hw_set_imr(ah, ah->ah_imr);
+
+}
+
+/**
+ * ath5k_hw_dma_stop - stop DMA unit
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stop tx/rx DMA and interrupts. Returns
+ * -EBUSY if tx or rx dma failed to stop.
+ *
+ * XXX: Sometimes DMA unit hangs and we have
+ * stuck frames on tx queues, only a reset
+ * can fix that.
+ */
+int ath5k_hw_dma_stop(struct ath5k_hw *ah)
+{
+ int i, qmax, err;
+ err = 0;
+
+ /* Disable interrupts */
+ ath5k_hw_set_imr(ah, 0);
+
+ /* Stop rx dma */
+ err = ath5k_hw_stop_rx_dma(ah);
+ if (err)
+ return err;
+
+ /* Clear any pending interrupts
+ * and disable tx dma */
+ if (ah->ah_version != AR5K_AR5210) {
+ ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+ qmax = AR5K_NUM_TX_QUEUES;
+ } else {
+ /* PISR/SISR Not available on 5210 */
+ ath5k_hw_reg_read(ah, AR5K_ISR);
+ qmax = AR5K_NUM_TX_QUEUES_NOQCU;
+ }
+
+ for (i = 0; i < qmax; i++) {
+ err = ath5k_hw_stop_tx_dma(ah, i);
+ /* -EINVAL -> queue inactive */
+ if (err != -EINVAL)
+ return err;
+ }
+
+ return err;
+}
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 39722dd73e43..80e625608bac 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -28,45 +28,16 @@
#include "debug.h"
#include "base.h"
-/*
- * Read from eeprom
- */
-static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
-{
- u32 status, timeout;
-
- /*
- * Initialize EEPROM access
- */
- if (ah->ah_version == AR5K_AR5210) {
- AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
- (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
- } else {
- ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
- AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
- AR5K_EEPROM_CMD_READ);
- }
-
- for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
- status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
- if (status & AR5K_EEPROM_STAT_RDDONE) {
- if (status & AR5K_EEPROM_STAT_RDERR)
- return -EIO;
- *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
- 0xffff);
- return 0;
- }
- udelay(15);
- }
- return -ETIMEDOUT;
-}
+/******************\
+* Helper functions *
+\******************/
/*
* Translate binary channel representation in EEPROM to frequency
*/
static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
- unsigned int mode)
+ unsigned int mode)
{
u16 val;
@@ -89,6 +60,11 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
return val;
}
+
+/*********\
+* Parsers *
+\*********/
+
/*
* Initialize eeprom & capabilities structs
*/
@@ -198,7 +174,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
*
* XXX: Serdes values seem to be fixed so
* no need to read them here, we write them
- * during ath5k_hw_attach */
+ * during ath5k_hw_init */
AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
true : false;
@@ -647,6 +623,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
return 0;
}
+
/*
* Read power calibration for RF5111 chips
*
@@ -1514,6 +1491,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
return 0;
}
+
/*
* Read per channel calibration info from EEPROM
*
@@ -1607,15 +1585,6 @@ ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
return 0;
}
-void
-ath5k_eeprom_detach(struct ath5k_hw *ah)
-{
- u8 mode;
-
- for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
- ath5k_eeprom_free_pcal_info(ah, mode);
-}
-
/* Read conformance test limits used for regulatory control */
static int
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@@ -1757,6 +1726,44 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
}
/*
+ * Read the MAC address from eeprom
+ */
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+ u8 mac_d[ETH_ALEN] = {};
+ u32 total, offset;
+ u16 data;
+ int octet, ret;
+
+ ret = ath5k_hw_nvram_read(ah, 0x20, &data);
+ if (ret)
+ return ret;
+
+ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+ ret = ath5k_hw_nvram_read(ah, offset, &data);
+ if (ret)
+ return ret;
+
+ total += data;
+ mac_d[octet + 1] = data & 0xff;
+ mac_d[octet] = data >> 8;
+ octet += 2;
+ }
+
+ if (!total || total == 3 * 0xffff)
+ return -EINVAL;
+
+ memcpy(mac, mac_d, ETH_ALEN);
+
+ return 0;
+}
+
+
+/***********************\
+* Init/Detach functions *
+\***********************/
+
+/*
* Initialize eeprom data structure
*/
int
@@ -1787,35 +1794,27 @@ ath5k_eeprom_init(struct ath5k_hw *ah)
return 0;
}
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+void
+ath5k_eeprom_detach(struct ath5k_hw *ah)
{
- u8 mac_d[ETH_ALEN] = {};
- u32 total, offset;
- u16 data;
- int octet, ret;
-
- ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
- if (ret)
- return ret;
+ u8 mode;
- for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
- ret = ath5k_hw_eeprom_read(ah, offset, &data);
- if (ret)
- return ret;
+ for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
+ ath5k_eeprom_free_pcal_info(ah, mode);
+}
- total += data;
- mac_d[octet + 1] = data & 0xff;
- mac_d[octet] = data >> 8;
- octet += 2;
+int
+ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
+{
+ switch (channel->hw_value & CHANNEL_MODES) {
+ case CHANNEL_A:
+ case CHANNEL_XR:
+ return AR5K_EEPROM_MODE_11A;
+ case CHANNEL_G:
+ return AR5K_EEPROM_MODE_11G;
+ case CHANNEL_B:
+ return AR5K_EEPROM_MODE_11B;
+ default:
+ return -1;
}
-
- if (!total || total == 3 * 0xffff)
- return -EINVAL;
-
- memcpy(mac, mac_d, ETH_ALEN);
-
- return 0;
}
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h
index c4a6d5f26af4..7c09e150dbdc 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath/ath5k/eeprom.h
@@ -241,7 +241,7 @@ enum ath5k_eeprom_freq_bands{
#define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250
#define AR5K_EEPROM_READ(_o, _v) do { \
- ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \
+ ret = ath5k_hw_nvram_read(ah, (_o), &(_v)); \
if (ret) \
return ret; \
} while (0)
@@ -517,3 +517,5 @@ struct ath5k_eeprom_info {
u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
+int
+ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 8fa439308828..e49340d18df4 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -44,7 +44,7 @@ struct ath5k_ini {
struct ath5k_ini_mode {
u16 mode_register;
- u32 mode_value[5];
+ u32 mode_value[3];
};
/* Initial register settings for AR5210 */
@@ -391,76 +391,74 @@ static const struct ath5k_ini ar5211_ini[] = {
*/
static const struct ath5k_ini_mode ar5211_ini_mode[] = {
{ AR5K_TXCFG,
- /* a aTurbo b g (OFDM) */
- { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
+ /* A/XR B G */
+ { 0x00000015, 0x0000001d, 0x00000015 } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_DCU_GBL_IFS_SLOT,
- { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
+ { 0x00000168, 0x000001b8, 0x00000168 } },
{ AR5K_DCU_GBL_IFS_SIFS,
- { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
+ { 0x00000230, 0x000000b0, 0x00000230 } },
{ AR5K_DCU_GBL_IFS_EIFS,
- { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
+ { 0x00000d98, 0x00001f48, 0x00000d98 } },
{ AR5K_DCU_GBL_IFS_MISC,
- { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
+ { 0x0000a0e0, 0x00005880, 0x0000a0e0 } },
{ AR5K_TIME_OUT,
- { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
+ { 0x04000400, 0x20003000, 0x04000400 } },
{ AR5K_USEC_5211,
- { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
- { AR5K_PHY_TURBO,
- { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
+ { 0x0e8d8fa7, 0x01608f95, 0x0e8d8fa7 } },
{ AR5K_PHY(8),
- { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
- { AR5K_PHY(9),
- { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
- { AR5K_PHY(10),
- { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
- { AR5K_PHY(13),
- { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
- { AR5K_PHY(14),
- { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
- { AR5K_PHY(17),
- { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
- { AR5K_PHY(18),
- { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
- { AR5K_PHY(20),
- { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+ { 0x02020200, 0x02010200, 0x02020200 } },
+ { AR5K_PHY_RF_CTL2,
+ { 0x00000e0e, 0x00000707, 0x00000e0e } },
+ { AR5K_PHY_RF_CTL3,
+ { 0x0a020001, 0x05010000, 0x0a020001 } },
+ { AR5K_PHY_RF_CTL4,
+ { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+ { AR5K_PHY_PA_CTL,
+ { 0x00000007, 0x0000000b, 0x0000000b } },
+ { AR5K_PHY_SETTLING,
+ { 0x1372169c, 0x137216a8, 0x1372169c } },
+ { AR5K_PHY_GAIN,
+ { 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
+ { AR5K_PHY_DESIRED_SIZE,
+ { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
{ AR5K_PHY_SIG,
- { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
+ { 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
+ { 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
{ AR5K_PHY_AGCCTL,
- { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
+ { 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
{ AR5K_PHY_NF,
- { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+ { 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
{ AR5K_PHY_RX_DELAY,
- { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
+ { 0x00002710, 0x0000157c, 0x00002710 } },
{ AR5K_PHY(70),
- { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
+ { 0x00000190, 0x00000084, 0x00000190 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
+ { 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
{ AR5K_PHY_PCDAC_TXPOWER_BASE,
- { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
+ { 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
{ AR5K_RF_BUFFER_CONTROL_4,
- { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
+ { 0x00000010, 0x00000010, 0x00000010 } },
};
/* Initial register settings for AR5212 */
@@ -677,89 +675,87 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ /* A/XR B G */
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
- { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+ { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
{ AR5K_DCU_GBL_IFS_SIFS,
- { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+ { 0x00000230, 0x000000b0, 0x00000160 } },
{ AR5K_DCU_GBL_IFS_SLOT,
- { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+ { 0x00000168, 0x000001b8, 0x0000018c } },
{ AR5K_DCU_GBL_IFS_EIFS,
- { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+ { 0x00000e60, 0x00001f1c, 0x00003e38 } },
{ AR5K_DCU_GBL_IFS_MISC,
- { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+ { 0x0000a0e0, 0x00005880, 0x0000b0e0 } },
{ AR5K_TIME_OUT,
- { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
- { AR5K_PHY_TURBO,
- { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+ { 0x03e803e8, 0x04200420, 0x08400840 } },
{ AR5K_PHY(8),
- { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+ { 0x02020200, 0x02010200, 0x02020200 } },
{ AR5K_PHY_RF_CTL2,
- { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+ { 0x00000e0e, 0x00000707, 0x00000e0e } },
{ AR5K_PHY_SETTLING,
- { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+ { 0x1372161c, 0x13721722, 0x137216a2 } },
{ AR5K_PHY_AGCCTL,
- { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
+ { 0x00009d10, 0x00009d18, 0x00009d18 } },
{ AR5K_PHY_NF,
- { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+ { 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
- { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+ { 0x409a4190, 0x409a4190, 0x409a4190 } },
{ AR5K_PHY(70),
- { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+ { 0x000001b8, 0x00000084, 0x00000108 } },
{ AR5K_PHY_OFDM_SELFCORR,
- { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+ { 0x10058a05, 0x10058a05, 0x10058a05 } },
{ 0xa230,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+ { 0x00000000, 0x00000000, 0x00000108 } },
};
/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
{ AR5K_TXCFG,
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+ /* A/XR B G */
+ { 0x00008015, 0x00008015, 0x00008015 } },
{ AR5K_USEC_5211,
- { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+ { 0x128d8fa7, 0x04e00f95, 0x12e00fab } },
{ AR5K_PHY_RF_CTL3,
- { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+ { 0x0a020001, 0x05010100, 0x0a020001 } },
{ AR5K_PHY_RF_CTL4,
- { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+ { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
{ AR5K_PHY_PA_CTL,
- { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+ { 0x00000007, 0x0000000b, 0x0000000b } },
{ AR5K_PHY_GAIN,
- { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+ { 0x0018da5a, 0x0018ca69, 0x0018ca69 } },
{ AR5K_PHY_DESIRED_SIZE,
- { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+ { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
{ AR5K_PHY_SIG,
- { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+ { 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+ { 0x3137665e, 0x3137665e, 0x3137665e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
- { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+ { 0x050cb081, 0x050cb081, 0x050cb080 } },
{ AR5K_PHY_RX_DELAY,
- { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+ { 0x00002710, 0x0000157c, 0x00002af8 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+ { 0xf7b81020, 0xf7b80d20, 0xf7b81020 } },
{ AR5K_PHY_GAIN_2GHZ,
- { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+ { 0x642c416a, 0x6440416a, 0x6440416a } },
{ AR5K_PHY_CCK_RX_CTL_4,
- { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+ { 0x1883800a, 0x1873800a, 0x1883800a } },
};
static const struct ath5k_ini rf5111_ini_common_end[] = {
@@ -782,38 +778,38 @@ static const struct ath5k_ini rf5111_ini_common_end[] = {
/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
{ AR5K_TXCFG,
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+ /* A/XR B G */
+ { 0x00008015, 0x00008015, 0x00008015 } },
{ AR5K_USEC_5211,
- { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+ { 0x128d93a7, 0x04e01395, 0x12e013ab } },
{ AR5K_PHY_RF_CTL3,
- { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+ { 0x0a020001, 0x05020100, 0x0a020001 } },
{ AR5K_PHY_RF_CTL4,
- { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+ { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
{ AR5K_PHY_PA_CTL,
- { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+ { 0x00000007, 0x0000000b, 0x0000000b } },
{ AR5K_PHY_GAIN,
- { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+ { 0x0018da6d, 0x0018ca75, 0x0018ca75 } },
{ AR5K_PHY_DESIRED_SIZE,
- { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+ { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
{ AR5K_PHY_SIG,
- { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
+ { 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+ { 0x3137665e, 0x3137665e, 0x3137665e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
- { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+ { 0x050cb081, 0x050cb081, 0x050cb081 } },
{ AR5K_PHY_RX_DELAY,
- { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+ { 0x000007d0, 0x0000044c, 0x00000898 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+ { 0xf7b81020, 0xf7b80d10, 0xf7b81010 } },
{ AR5K_PHY_CCKTXCTL,
- { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+ { 0x00000000, 0x00000008, 0x00000008 } },
{ AR5K_PHY_CCK_CROSSCORR,
- { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+ { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
{ AR5K_PHY_GAIN_2GHZ,
- { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+ { 0x642c0140, 0x6442c160, 0x6442c160 } },
{ AR5K_PHY_CCK_RX_CTL_4,
- { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+ { 0x1883800a, 0x1873800a, 0x1883800a } },
};
static const struct ath5k_ini rf5112_ini_common_end[] = {
@@ -833,66 +829,66 @@ static const struct ath5k_ini rf5112_ini_common_end[] = {
/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
{ AR5K_TXCFG,
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+ /* A/XR B G */
+ { 0x00000015, 0x00000015, 0x00000015 } },
{ AR5K_USEC_5211,
- { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+ { 0x128d93a7, 0x04e01395, 0x12e013ab } },
{ AR5K_PHY_RF_CTL3,
- { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+ { 0x0a020001, 0x05020100, 0x0a020001 } },
{ AR5K_PHY_RF_CTL4,
- { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+ { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
{ AR5K_PHY_PA_CTL,
- { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+ { 0x00000007, 0x0000000b, 0x0000000b } },
{ AR5K_PHY_GAIN,
- { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+ { 0x0018fa61, 0x001a1a63, 0x001a1a63 } },
{ AR5K_PHY_DESIRED_SIZE,
- { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+ { 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da } },
{ AR5K_PHY_SIG,
- { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+ { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+ { 0x3139605e, 0x3139605e, 0x3139605e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
- { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+ { 0x050cb081, 0x050cb081, 0x050cb081 } },
{ AR5K_PHY_RX_DELAY,
- { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+ { 0x000007d0, 0x0000044c, 0x00000898 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+ { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
{ AR5K_PHY_CCKTXCTL,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x00000000, 0x00000000, 0x00000000 } },
{ AR5K_PHY_CCK_CROSSCORR,
- { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+ { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
{ AR5K_PHY_GAIN_2GHZ,
- { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+ { 0x002ec1e0, 0x002ac120, 0x002ac120 } },
{ AR5K_PHY_CCK_RX_CTL_4,
- { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+ { 0x1883800a, 0x1863800a, 0x1883800a } },
{ 0xa300,
- { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+ { 0x18010000, 0x18010000, 0x18010000 } },
{ 0xa304,
- { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+ { 0x30032602, 0x30032602, 0x30032602 } },
{ 0xa308,
- { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+ { 0x48073e06, 0x48073e06, 0x48073e06 } },
{ 0xa30c,
- { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+ { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
{ 0xa310,
- { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+ { 0x641a600f, 0x641a600f, 0x641a600f } },
{ 0xa314,
- { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+ { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
{ 0xa318,
- { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+ { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
{ 0xa31c,
- { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+ { 0x90cf865b, 0x8ecf865b, 0x8ecf865b } },
{ 0xa320,
- { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+ { 0x9d4f970f, 0x9b4f970f, 0x9b4f970f } },
{ 0xa324,
- { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+ { 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f } },
{ 0xa328,
- { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+ { 0xb55faf1f, 0xb35faf1f, 0xb35faf1f } },
{ 0xa32c,
- { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+ { 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f } },
{ 0xa330,
- { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+ { 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f } },
{ 0xa334,
- { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+ { 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
};
static const struct ath5k_ini rf5413_ini_common_end[] = {
@@ -972,38 +968,38 @@ static const struct ath5k_ini rf5413_ini_common_end[] = {
/* XXX: a mode ? */
static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
{ AR5K_TXCFG,
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+ /* A/XR B G */
+ { 0x00000015, 0x00000015, 0x00000015 } },
{ AR5K_USEC_5211,
- { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+ { 0x128d93a7, 0x04e01395, 0x12e013ab } },
{ AR5K_PHY_RF_CTL3,
- { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
+ { 0x0a020001, 0x05020000, 0x0a020001 } },
{ AR5K_PHY_RF_CTL4,
- { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
+ { 0x00000e00, 0x00000e00, 0x00000e00 } },
{ AR5K_PHY_PA_CTL,
- { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
+ { 0x00000002, 0x0000000a, 0x0000000a } },
{ AR5K_PHY_GAIN,
- { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+ { 0x0018da6d, 0x001a6a64, 0x001a6a64 } },
{ AR5K_PHY_DESIRED_SIZE,
- { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
+ { 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da } },
{ AR5K_PHY_SIG,
- { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
+ { 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
+ { 0x3137665e, 0x3137665e, 0x3139605e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
- { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+ { 0x050cb081, 0x050cb081, 0x050cb081 } },
{ AR5K_PHY_RX_DELAY,
- { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+ { 0x000007d0, 0x0000044c, 0x00000898 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+ { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
{ AR5K_PHY_CCKTXCTL,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x00000000, 0x00000000, 0x00000000 } },
{ AR5K_PHY_CCK_CROSSCORR,
- { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+ { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
{ AR5K_PHY_GAIN_2GHZ,
- { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
+ { 0x002c0140, 0x0042c140, 0x0042c140 } },
{ AR5K_PHY_CCK_RX_CTL_4,
- { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+ { 0x1883800a, 0x1863800a, 0x1883800a } },
};
static const struct ath5k_ini rf2413_ini_common_end[] = {
@@ -1094,52 +1090,50 @@ static const struct ath5k_ini rf2413_ini_common_end[] = {
/* XXX: a mode ? */
static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
{ AR5K_TXCFG,
- /* a/XR aTurbo b g (DYN) gTurbo */
- { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+ /* A/XR B G */
+ { 0x00000015, 0x00000015, 0x00000015 } },
{ AR5K_USEC_5211,
- { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
- { AR5K_PHY_TURBO,
- { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
+ { 0x128d93a7, 0x04e01395, 0x12e013ab } },
{ AR5K_PHY_RF_CTL3,
- { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+ { 0x0a020001, 0x05020100, 0x0a020001 } },
{ AR5K_PHY_RF_CTL4,
- { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+ { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
{ AR5K_PHY_PA_CTL,
- { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
+ { 0x00000003, 0x0000000b, 0x0000000b } },
{ AR5K_PHY_SETTLING,
- { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
+ { 0x1372161c, 0x13721722, 0x13721422 } },
{ AR5K_PHY_GAIN,
- { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
+ { 0x0018fa61, 0x00199a65, 0x00199a65 } },
{ AR5K_PHY_DESIRED_SIZE,
- { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+ { 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da } },
{ AR5K_PHY_SIG,
- { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+ { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
{ AR5K_PHY_AGCCOARSE,
- { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+ { 0x3139605e, 0x3139605e, 0x3139605e } },
{ AR5K_PHY_WEAK_OFDM_LOW_THR,
- { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+ { 0x050cb081, 0x050cb081, 0x050cb081 } },
{ AR5K_PHY_RX_DELAY,
- { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+ { 0x000007d0, 0x0000044c, 0x00000898 } },
{ AR5K_PHY_FRAME_CTL_5211,
- { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+ { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
{ AR5K_PHY_CCKTXCTL,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+ { 0x00000000, 0x00000000, 0x00000000 } },
{ AR5K_PHY_CCK_CROSSCORR,
- { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+ { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
{ AR5K_PHY_GAIN_2GHZ,
- { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
+ { 0x00000140, 0x0052c140, 0x0052c140 } },
{ AR5K_PHY_CCK_RX_CTL_4,
- { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+ { 0x1883800a, 0x1863800a, 0x1883800a } },
{ 0xa324,
- { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+ { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
{ 0xa328,
- { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+ { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
{ 0xa32c,
- { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+ { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
{ 0xa330,
- { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+ { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
{ 0xa334,
- { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+ { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
};
static const struct ath5k_ini rf2425_ini_common_end[] = {
@@ -1368,15 +1362,15 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = {
* Write initial register dump
*/
static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
- const struct ath5k_ini *ini_regs, bool change_channel)
+ const struct ath5k_ini *ini_regs, bool skip_pcu)
{
unsigned int i;
/* Write initial registers */
for (i = 0; i < size; i++) {
- /* On channel change there is
- * no need to mess with PCU */
- if (change_channel &&
+ /* Skip PCU registers if
+ * requested */
+ if (skip_pcu &&
ini_regs[i].ini_register >= AR5K_PCU_MIN &&
ini_regs[i].ini_register <= AR5K_PCU_MAX)
continue;
@@ -1409,7 +1403,7 @@ static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
}
-int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
{
/*
* Write initial register settings
@@ -1427,7 +1421,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
* Write initial settings common for all modes
*/
ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
- ar5212_ini_common_start, change_channel);
+ ar5212_ini_common_start, skip_pcu);
/* Second set of mode-specific settings */
switch (ah->ah_radio) {
@@ -1439,12 +1433,12 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5111_ini_common_end),
- rf5111_ini_common_end, change_channel);
+ rf5111_ini_common_end, skip_pcu);
/* Baseband gain table */
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5111_ini_bbgain),
- rf5111_ini_bbgain, change_channel);
+ rf5111_ini_bbgain, skip_pcu);
break;
case AR5K_RF5112:
@@ -1455,11 +1449,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_common_end),
- rf5112_ini_common_end, change_channel);
+ rf5112_ini_common_end, skip_pcu);
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
- rf5112_ini_bbgain, change_channel);
+ rf5112_ini_bbgain, skip_pcu);
break;
case AR5K_RF5413:
@@ -1470,11 +1464,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5413_ini_common_end),
- rf5413_ini_common_end, change_channel);
+ rf5413_ini_common_end, skip_pcu);
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
- rf5112_ini_bbgain, change_channel);
+ rf5112_ini_bbgain, skip_pcu);
break;
case AR5K_RF2316:
@@ -1486,7 +1480,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf2413_ini_common_end),
- rf2413_ini_common_end, change_channel);
+ rf2413_ini_common_end, skip_pcu);
/* Override settings from rf2413_ini_common_end */
if (ah->ah_radio == AR5K_RF2316) {
@@ -1498,9 +1492,32 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
- rf5112_ini_bbgain, change_channel);
+ rf5112_ini_bbgain, skip_pcu);
break;
case AR5K_RF2317:
+
+ ath5k_hw_ini_mode_registers(ah,
+ ARRAY_SIZE(rf2413_ini_mode_end),
+ rf2413_ini_mode_end, mode);
+
+ ath5k_hw_ini_registers(ah,
+ ARRAY_SIZE(rf2425_ini_common_end),
+ rf2425_ini_common_end, skip_pcu);
+
+ /* Override settings from rf2413_ini_mode_end */
+ ath5k_hw_reg_write(ah, 0x00180a65, AR5K_PHY_GAIN);
+
+ /* Override settings from rf2413_ini_common_end */
+ ath5k_hw_reg_write(ah, 0x00004000, AR5K_PHY_AGC);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TPC_RG5,
+ AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP, 0xa);
+ ath5k_hw_reg_write(ah, 0x800000a8, 0x8140);
+ ath5k_hw_reg_write(ah, 0x000000ff, 0x9958);
+
+ ath5k_hw_ini_registers(ah,
+ ARRAY_SIZE(rf5112_ini_bbgain),
+ rf5112_ini_bbgain, skip_pcu);
+ break;
case AR5K_RF2425:
ath5k_hw_ini_mode_registers(ah,
@@ -1509,11 +1526,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf2425_ini_common_end),
- rf2425_ini_common_end, change_channel);
+ rf2425_ini_common_end, skip_pcu);
ath5k_hw_ini_registers(ah,
ARRAY_SIZE(rf5112_ini_bbgain),
- rf5112_ini_bbgain, change_channel);
+ rf5112_ini_bbgain, skip_pcu);
break;
default:
return -EINVAL;
@@ -1538,17 +1555,17 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
* Write initial settings common for all modes
*/
ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
- ar5211_ini, change_channel);
+ ar5211_ini, skip_pcu);
/* AR5211 only comes with 5111 */
/* Baseband gain table */
ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
- rf5111_ini_bbgain, change_channel);
+ rf5111_ini_bbgain, skip_pcu);
/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
} else if (ah->ah_version == AR5K_AR5210) {
ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
- ar5210_ini, change_channel);
+ ar5210_ini, skip_pcu);
}
return 0;
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 67aa52e9bf94..576edf2965dc 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -133,7 +133,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
led->led_dev.default_trigger = trigger;
led->led_dev.brightness_set = ath5k_led_brightness_set;
- err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
+ err = led_classdev_register(sc->dev, &led->led_dev);
if (err) {
ATH5K_WARN(sc, "could not register LED %s\n", name);
led->sc = NULL;
@@ -161,11 +161,20 @@ int ath5k_init_leds(struct ath5k_softc *sc)
{
int ret = 0;
struct ieee80211_hw *hw = sc->hw;
+#ifndef CONFIG_ATHEROS_AR231X
struct pci_dev *pdev = sc->pdev;
+#endif
char name[ATH5K_LED_MAX_NAME_LEN + 1];
const struct pci_device_id *match;
+ if (!sc->pdev)
+ return 0;
+
+#ifdef CONFIG_ATHEROS_AR231X
+ match = NULL;
+#else
match = pci_match_id(&ath5k_led_devices[0], pdev);
+#endif
if (match) {
__set_bit(ATH_STAT_LEDSOFT, sc->status);
sc->led_pin = ATH_PIN(match->driver_data);
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
new file mode 100644
index 000000000000..d76d68c99f72
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -0,0 +1,774 @@
+/*-
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+#include <asm/unaligned.h>
+
+#include "base.h"
+#include "reg.h"
+
+extern int ath5k_modparam_nohwcrypt;
+
+/* functions used from base.c */
+void set_beacon_filter(struct ieee80211_hw *hw, bool enable);
+bool ath_any_vif_assoc(struct ath5k_softc *sc);
+int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
+int ath5k_init_hw(struct ath5k_softc *sc);
+int ath5k_stop_hw(struct ath5k_softc *sc);
+void ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif);
+void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
+ struct ieee80211_vif *vif);
+int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan);
+void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
+int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void ath5k_beacon_config(struct ath5k_softc *sc);
+void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
+void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf);
+
+/********************\
+* Mac80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct ath5k_softc *sc = hw->priv;
+ u16 qnum = skb_get_queue_mapping(skb);
+
+ if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
+}
+
+
+static int
+ath5k_start(struct ieee80211_hw *hw)
+{
+ return ath5k_init_hw(hw->priv);
+}
+
+
+static void
+ath5k_stop(struct ieee80211_hw *hw)
+{
+ ath5k_stop_hw(hw->priv);
+}
+
+
+static int
+ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct ath5k_softc *sc = hw->priv;
+ int ret;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+
+ mutex_lock(&sc->lock);
+
+ if ((vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC)
+ && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
+ ret = -ELNRNG;
+ goto end;
+ }
+
+ /* Don't allow other interfaces if one ad-hoc is configured.
+ * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+ * We would need to operate the HW in ad-hoc mode to allow TSF updates
+ * for the IBSS, but this breaks with additional AP or STA interfaces
+ * at the moment. */
+ if (sc->num_adhoc_vifs ||
+ (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
+ ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
+ ret = -ELNRNG;
+ goto end;
+ }
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ avf->opmode = vif->type;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto end;
+ }
+
+ sc->nvifs++;
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
+
+ /* Assign the vap/adhoc to a beacon xmit slot. */
+ if ((avf->opmode == NL80211_IFTYPE_AP) ||
+ (avf->opmode == NL80211_IFTYPE_ADHOC) ||
+ (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ int slot;
+
+ WARN_ON(list_empty(&sc->bcbuf));
+ avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
+ list);
+ list_del(&avf->bbuf->list);
+
+ avf->bslot = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (!sc->bslot[slot]) {
+ avf->bslot = slot;
+ break;
+ }
+ }
+ BUG_ON(sc->bslot[avf->bslot] != NULL);
+ sc->bslot[avf->bslot] = vif;
+ if (avf->opmode == NL80211_IFTYPE_AP)
+ sc->num_ap_vifs++;
+ else if (avf->opmode == NL80211_IFTYPE_ADHOC)
+ sc->num_adhoc_vifs++;
+ }
+
+ /* Any MAC address is fine, all others are included through the
+ * filter.
+ */
+ memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
+ ath5k_hw_set_lladdr(sc->ah, vif->addr);
+
+ memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
+
+ ath5k_mode_setup(sc, vif);
+
+ ret = 0;
+end:
+ mutex_unlock(&sc->lock);
+ return ret;
+}
+
+
+static void
+ath5k_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+ unsigned int i;
+
+ mutex_lock(&sc->lock);
+ sc->nvifs--;
+
+ if (avf->bbuf) {
+ ath5k_txbuf_free_skb(sc, avf->bbuf);
+ list_add_tail(&avf->bbuf->list, &sc->bcbuf);
+ for (i = 0; i < ATH_BCBUF; i++) {
+ if (sc->bslot[i] == vif) {
+ sc->bslot[i] = NULL;
+ break;
+ }
+ }
+ avf->bbuf = NULL;
+ }
+ if (avf->opmode == NL80211_IFTYPE_AP)
+ sc->num_ap_vifs--;
+ else if (avf->opmode == NL80211_IFTYPE_ADHOC)
+ sc->num_adhoc_vifs--;
+
+ ath5k_update_bssid_mask_and_opmode(sc, NULL);
+ mutex_unlock(&sc->lock);
+}
+
+
+/*
+ * TODO: Phy disable/diversity etc
+ */
+static int
+ath5k_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ieee80211_conf *conf = &hw->conf;
+ int ret = 0;
+
+ mutex_lock(&sc->lock);
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = ath5k_chan_set(sc, conf->channel);
+ if (ret < 0)
+ goto unlock;
+ }
+
+ if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
+ (sc->power_level != conf->power_level)) {
+ sc->power_level = conf->power_level;
+
+ /* Half dB steps */
+ ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
+ }
+
+ /* TODO:
+ * 1) Move this on config_interface and handle each case
+ * separately eg. when we have only one STA vif, use
+ * AR5K_ANTMODE_SINGLE_AP
+ *
+ * 2) Allow the user to change antenna mode eg. when only
+ * one antenna is present
+ *
+ * 3) Allow the user to set default/tx antenna when possible
+ *
+ * 4) Default mode should handle 90% of the cases, together
+ * with fixed a/b and single AP modes we should be able to
+ * handle 99%. Sectored modes are extreme cases and i still
+ * haven't found a usage for them. If we decide to support them,
+ * then we must allow the user to set how many tx antennas we
+ * have available
+ */
+ ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
+
+unlock:
+ mutex_unlock(&sc->lock);
+ return ret;
+}
+
+
+static void
+ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf, u32 changes)
+{
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
+ unsigned long flags;
+
+ mutex_lock(&sc->lock);
+
+ if (changes & BSS_CHANGED_BSSID) {
+ /* Cache for later use during resets */
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = 0;
+ ath5k_hw_set_bssid(ah);
+ mmiowb();
+ }
+
+ if (changes & BSS_CHANGED_BEACON_INT)
+ sc->bintval = bss_conf->beacon_int;
+
+ if (changes & BSS_CHANGED_ASSOC) {
+ avf->assoc = bss_conf->assoc;
+ if (bss_conf->assoc)
+ sc->assoc = bss_conf->assoc;
+ else
+ sc->assoc = ath_any_vif_assoc(sc);
+
+ if (sc->opmode == NL80211_IFTYPE_STATION)
+ set_beacon_filter(hw, sc->assoc);
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+ if (bss_conf->assoc) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
+ common->curaid = bss_conf->aid;
+ ath5k_hw_set_bssid(ah);
+ /* Once ANI is available you would start it here */
+ }
+ }
+
+ if (changes & BSS_CHANGED_BEACON) {
+ spin_lock_irqsave(&sc->block, flags);
+ ath5k_beacon_update(hw, vif);
+ spin_unlock_irqrestore(&sc->block, flags);
+ }
+
+ if (changes & BSS_CHANGED_BEACON_ENABLED)
+ sc->enable_beacon = bss_conf->enable_beacon;
+
+ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON_INT))
+ ath5k_beacon_config(sc);
+
+ mutex_unlock(&sc->lock);
+}
+
+
+static u64
+ath5k_prepare_multicast(struct ieee80211_hw *hw,
+ struct netdev_hw_addr_list *mc_list)
+{
+ u32 mfilt[2], val;
+ u8 pos;
+ struct netdev_hw_addr *ha;
+
+ mfilt[0] = 0;
+ mfilt[1] = 1;
+
+ netdev_hw_addr_list_for_each(ha, mc_list) {
+ /* calculate XOR of eight 6-bit values */
+ val = get_unaligned_le32(ha->addr + 0);
+ pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ val = get_unaligned_le32(ha->addr + 3);
+ pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+ pos &= 0x3f;
+ mfilt[pos / 32] |= (1 << (pos % 32));
+ /* XXX: we might be able to just do this instead,
+ * but not sure, needs testing, if we do use this we'd
+ * neet to inform below to not reset the mcast */
+ /* ath5k_hw_set_mcast_filterindex(ah,
+ * ha->addr[5]); */
+ }
+
+ return ((u64)(mfilt[1]) << 32) | mfilt[0];
+}
+
+
+/*
+ * o always accept unicast, broadcast, and multicast traffic
+ * o multicast traffic for all BSSIDs will be enabled if mac80211
+ * says it should be
+ * o maintain current state of phy ofdm or phy cck error reception.
+ * If the hardware detects any of these type of errors then
+ * ath5k_hw_get_rx_filter() will pass to us the respective
+ * hardware filters to be able to receive these type of frames.
+ * o probe request frames are accepted only when operating in
+ * hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ * - when operating in adhoc mode so the 802.11 layer creates
+ * node table entries for peers,
+ * - when operating in station mode for collecting rssi data when
+ * the station is otherwise quiet, or
+ * - when scanning
+ */
+static void
+ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
+ unsigned int *new_flags, u64 multicast)
+{
+#define SUPPORTED_FIF_FLAGS \
+ (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
+ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
+ FIF_BCN_PRBRESP_PROMISC)
+
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ u32 mfilt[2], rfilt;
+
+ mutex_lock(&sc->lock);
+
+ mfilt[0] = multicast;
+ mfilt[1] = multicast >> 32;
+
+ /* Only deal with supported flags */
+ changed_flags &= SUPPORTED_FIF_FLAGS;
+ *new_flags &= SUPPORTED_FIF_FLAGS;
+
+ /* If HW detects any phy or radar errors, leave those filters on.
+ * Also, always enable Unicast, Broadcasts and Multicast
+ * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
+ rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
+ (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
+ AR5K_RX_FILTER_MCAST);
+
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+ if (*new_flags & FIF_PROMISC_IN_BSS)
+ __set_bit(ATH_STAT_PROMISC, sc->status);
+ else
+ __clear_bit(ATH_STAT_PROMISC, sc->status);
+ }
+
+ if (test_bit(ATH_STAT_PROMISC, sc->status))
+ rfilt |= AR5K_RX_FILTER_PROM;
+
+ /* Note, AR5K_RX_FILTER_MCAST is already enabled */
+ if (*new_flags & FIF_ALLMULTI) {
+ mfilt[0] = ~0;
+ mfilt[1] = ~0;
+ }
+
+ /* This is the best we can do */
+ if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
+ rfilt |= AR5K_RX_FILTER_PHYERR;
+
+ /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
+ * and probes for any BSSID */
+ if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
+ rfilt |= AR5K_RX_FILTER_BEACON;
+
+ /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
+ * set we should only pass on control frames for this
+ * station. This needs testing. I believe right now this
+ * enables *all* control frames, which is OK.. but
+ * but we should see if we can improve on granularity */
+ if (*new_flags & FIF_CONTROL)
+ rfilt |= AR5K_RX_FILTER_CONTROL;
+
+ /* Additional settings per mode -- this is per ath5k */
+
+ /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
+
+ switch (sc->opmode) {
+ case NL80211_IFTYPE_MESH_POINT:
+ rfilt |= AR5K_RX_FILTER_CONTROL |
+ AR5K_RX_FILTER_BEACON |
+ AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_PROM;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ rfilt |= AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_BEACON;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (sc->assoc)
+ rfilt |= AR5K_RX_FILTER_BEACON;
+ default:
+ break;
+ }
+
+ /* Set filters */
+ ath5k_hw_set_rx_filter(ah, rfilt);
+
+ /* Set multicast bits */
+ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
+ /* Set the cached hw filter flags, this will later actually
+ * be set in HW */
+ sc->filter_flags = rfilt;
+
+ mutex_unlock(&sc->lock);
+}
+
+
+static int
+ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
+ int ret = 0;
+
+ if (ath5k_modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
+ break;
+ return -EOPNOTSUPP;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ mutex_lock(&sc->lock);
+
+ switch (cmd) {
+ case SET_KEY:
+ ret = ath_key_config(common, vif, sta, key);
+ if (ret >= 0) {
+ key->hw_key_idx = ret;
+ /* push IV and Michael MIC generation to stack */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
+ ret = 0;
+ }
+ break;
+ case DISABLE_KEY:
+ ath_key_delete(common, key);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mmiowb();
+ mutex_unlock(&sc->lock);
+ return ret;
+}
+
+
+static void
+ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (!sc->assoc)
+ ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+
+static void
+ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
+
+
+static int
+ath5k_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ /* Force update */
+ ath5k_hw_update_mib_counters(sc->ah);
+
+ stats->dot11ACKFailureCount = sc->stats.ack_fail;
+ stats->dot11RTSFailureCount = sc->stats.rts_fail;
+ stats->dot11RTSSuccessCount = sc->stats.rts_ok;
+ stats->dot11FCSErrorCount = sc->stats.fcs_error;
+
+ return 0;
+}
+
+
+static int
+ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath5k_txq_info qi;
+ int ret = 0;
+
+ if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
+ return 0;
+
+ mutex_lock(&sc->lock);
+
+ ath5k_hw_get_tx_queueprops(ah, queue, &qi);
+
+ qi.tqi_aifs = params->aifs;
+ qi.tqi_cw_min = params->cw_min;
+ qi.tqi_cw_max = params->cw_max;
+ qi.tqi_burst_time = params->txop;
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
+ "Configure tx [queue %d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
+
+ if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
+ ATH5K_ERR(sc,
+ "Unable to update hardware queue %u!\n", queue);
+ ret = -EIO;
+ } else
+ ath5k_hw_reset_tx_queue(ah, queue);
+
+ mutex_unlock(&sc->lock);
+
+ return ret;
+}
+
+
+static u64
+ath5k_get_tsf(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ return ath5k_hw_get_tsf64(sc->ah);
+}
+
+
+static void
+ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ ath5k_hw_set_tsf64(sc->ah, tsf);
+}
+
+
+static void
+ath5k_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ /*
+ * in IBSS mode we need to update the beacon timers too.
+ * this will also reset the TSF if we call it with 0
+ */
+ if (sc->opmode == NL80211_IFTYPE_ADHOC)
+ ath5k_beacon_update_timers(sc, 0);
+ else
+ ath5k_hw_reset_tsf(sc->ah);
+}
+
+
+static int
+ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct ath_common *common = ath5k_hw_common(sc->ah);
+ struct ath_cycle_counters *cc = &common->cc_survey;
+ unsigned int div = common->clockrate * 1000;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ spin_lock_bh(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
+ if (cc->cycles > 0) {
+ sc->survey.channel_time += cc->cycles / div;
+ sc->survey.channel_time_busy += cc->rx_busy / div;
+ sc->survey.channel_time_rx += cc->rx_frame / div;
+ sc->survey.channel_time_tx += cc->tx_frame / div;
+ }
+ memset(cc, 0, sizeof(*cc));
+ spin_unlock_bh(&common->cc_lock);
+
+ memcpy(survey, &sc->survey, sizeof(*survey));
+
+ survey->channel = conf->channel;
+ survey->noise = sc->ah->ah_noise_floor;
+ survey->filled = SURVEY_INFO_NOISE_DBM |
+ SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+
+ return 0;
+}
+
+
+/**
+ * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
+ *
+ * @hw: struct ieee80211_hw pointer
+ * @coverage_class: IEEE 802.11 coverage class number
+ *
+ * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
+ * coverage class. The values are persistent, they are restored after device
+ * reset.
+ */
+static void
+ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ mutex_lock(&sc->lock);
+ ath5k_hw_set_coverage_class(sc->ah, coverage_class);
+ mutex_unlock(&sc->lock);
+}
+
+
+static int
+ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ if (tx_ant == 1 && rx_ant == 1)
+ ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
+ else if (tx_ant == 2 && rx_ant == 2)
+ ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
+ else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
+ ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
+ else
+ return -EINVAL;
+ return 0;
+}
+
+
+static int
+ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ switch (sc->ah->ah_ant_mode) {
+ case AR5K_ANTMODE_FIXED_A:
+ *tx_ant = 1; *rx_ant = 1; break;
+ case AR5K_ANTMODE_FIXED_B:
+ *tx_ant = 2; *rx_ant = 2; break;
+ case AR5K_ANTMODE_DEFAULT:
+ *tx_ant = 3; *rx_ant = 3; break;
+ }
+ return 0;
+}
+
+
+const struct ieee80211_ops ath5k_hw_ops = {
+ .tx = ath5k_tx,
+ .start = ath5k_start,
+ .stop = ath5k_stop,
+ .add_interface = ath5k_add_interface,
+ /* .change_interface = not implemented */
+ .remove_interface = ath5k_remove_interface,
+ .config = ath5k_config,
+ .bss_info_changed = ath5k_bss_info_changed,
+ .prepare_multicast = ath5k_prepare_multicast,
+ .configure_filter = ath5k_configure_filter,
+ /* .set_tim = not implemented */
+ .set_key = ath5k_set_key,
+ /* .update_tkip_key = not implemented */
+ /* .hw_scan = not implemented */
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
+ .get_stats = ath5k_get_stats,
+ /* .get_tkip_seq = not implemented */
+ /* .set_frag_threshold = not implemented */
+ /* .set_rts_threshold = not implemented */
+ /* .sta_add = not implemented */
+ /* .sta_remove = not implemented */
+ /* .sta_notify = not implemented */
+ .conf_tx = ath5k_conf_tx,
+ .get_tsf = ath5k_get_tsf,
+ .set_tsf = ath5k_set_tsf,
+ .reset_tsf = ath5k_reset_tsf,
+ /* .tx_last_beacon = not implemented */
+ /* .ampdu_action = not needed */
+ .get_survey = ath5k_get_survey,
+ .set_coverage_class = ath5k_set_coverage_class,
+ /* .rfkill_poll = not implemented */
+ /* .flush = not implemented */
+ /* .channel_switch = not implemented */
+ /* .napi_poll = not implemented */
+ .set_antenna = ath5k_set_antenna,
+ .get_antenna = ath5k_get_antenna,
+};
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
new file mode 100644
index 000000000000..7f8c5b0e9d2a
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include "../ath.h"
+#include "ath5k.h"
+#include "debug.h"
+#include "base.h"
+#include "reg.h"
+
+/* Known PCI ids */
+static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
+ { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
+ { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
+ { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
+ { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
+ { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
+ { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */
+ { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
+ { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
+
+/* return bus cachesize in 4B word units */
+static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz)
+{
+ struct ath5k_softc *sc = (struct ath5k_softc *) common->priv;
+ u8 u8tmp;
+
+ pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, &u8tmp);
+ *csz = (int)u8tmp;
+
+ /*
+ * This check was put in to avoid "unplesant" consequences if
+ * the bootrom has not fully initialized all PCI devices.
+ * Sometimes the cache line size register is not set
+ */
+
+ if (*csz == 0)
+ *csz = L1_CACHE_BYTES >> 2; /* Use the default size */
+}
+
+/*
+ * Read from eeprom
+ */
+bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
+{
+ struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
+ u32 status, timeout;
+
+ /*
+ * Initialize EEPROM access
+ */
+ if (ah->ah_version == AR5K_AR5210) {
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+ (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+ } else {
+ ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+ AR5K_EEPROM_CMD_READ);
+ }
+
+ for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+ status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+ if (status & AR5K_EEPROM_STAT_RDDONE) {
+ if (status & AR5K_EEPROM_STAT_RDERR)
+ return -EIO;
+ *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+ 0xffff);
+ return 0;
+ }
+ udelay(15);
+ }
+
+ return -ETIMEDOUT;
+}
+
+int ath5k_hw_read_srev(struct ath5k_hw *ah)
+{
+ ah->ah_mac_srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+ return 0;
+}
+
+/* Common ath_bus_opts structure */
+static const struct ath_bus_ops ath_pci_bus_ops = {
+ .ath_bus_type = ATH_PCI,
+ .read_cachesize = ath5k_pci_read_cachesize,
+ .eeprom_read = ath5k_pci_eeprom_read,
+};
+
+/********************\
+* PCI Initialization *
+\********************/
+
+static int __devinit
+ath5k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *mem;
+ struct ath5k_softc *sc;
+ struct ieee80211_hw *hw;
+ int ret;
+ u8 csz;
+
+ /*
+ * L0s needs to be disabled on all ath5k cards.
+ *
+ * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
+ * by default in the future in 2.6.36) this will also mean both L1 and
+ * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
+ * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
+ * though but cannot currently undue the effect of a blacklist, for
+ * details you can read pcie_aspm_sanity_check() and see how it adjusts
+ * the device link capability.
+ *
+ * It may be possible in the future to implement some PCI API to allow
+ * drivers to override blacklists for pre 1.1 PCIe but for now it is
+ * best to accept that both L0s and L1 will be disabled completely for
+ * distributions shipping with CONFIG_PCIEASPM rather than having this
+ * issue present. Motivation for adding this new API will be to help
+ * with power consumption for some of these devices.
+ */
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "can't enable device\n");
+ goto err;
+ }
+
+ /* XXX 32-bit addressing only */
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "32-bit DMA not available\n");
+ goto err_dis;
+ }
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+ if (csz == 0) {
+ /*
+ * Linux 2.4.18 (at least) writes the cache line size
+ * register as a 16-bit wide register which is wrong.
+ * We must have this setup properly for rx buffer
+ * DMA to work so force a reasonable value here if it
+ * comes up zero.
+ */
+ csz = L1_CACHE_BYTES >> 2;
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+ }
+ /*
+ * The default setting of latency timer yields poor results,
+ * set it to the value used by other systems. It may be worth
+ * tweaking this setting more.
+ */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /*
+ * Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
+ pci_write_config_byte(pdev, 0x41, 0);
+
+ ret = pci_request_region(pdev, 0, "ath5k");
+ if (ret) {
+ dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+ goto err_dis;
+ }
+
+ mem = pci_iomap(pdev, 0, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+ ret = -EIO;
+ goto err_reg;
+ }
+
+ /*
+ * Allocate hw (mac80211 main struct)
+ * and hw->priv (driver private data)
+ */
+ hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
+ if (hw == NULL) {
+ dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
+ ret = -ENOMEM;
+ goto err_map;
+ }
+
+ dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
+
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->pdev = pdev;
+ sc->dev = &pdev->dev;
+ sc->irq = pdev->irq;
+ sc->devid = id->device;
+ sc->iobase = mem; /* So we can unmap it on detach */
+
+ /* Initialize */
+ ret = ath5k_init_softc(sc, &ath_pci_bus_ops);
+ if (ret)
+ goto err_free;
+
+ /* Set private data */
+ pci_set_drvdata(pdev, hw);
+
+ return 0;
+err_free:
+ ieee80211_free_hw(hw);
+err_map:
+ pci_iounmap(pdev, mem);
+err_reg:
+ pci_release_region(pdev, 0);
+err_dis:
+ pci_disable_device(pdev);
+err:
+ return ret;
+}
+
+static void __devexit
+ath5k_pci_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath5k_softc *sc = hw->priv;
+
+ ath5k_deinit_softc(sc);
+ pci_iounmap(pdev, sc->iobase);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(hw);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ath5k_pci_suspend(struct device *dev)
+{
+ struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
+
+ ath5k_led_off(sc);
+ return 0;
+}
+
+static int ath5k_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ath5k_softc *sc = pci_get_drvdata(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_write_config_byte(pdev, 0x41, 0);
+
+ ath5k_led_enable(sc);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+#define ATH5K_PM_OPS (&ath5k_pm_ops)
+#else
+#define ATH5K_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct pci_driver ath5k_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ath5k_pci_id_table,
+ .probe = ath5k_pci_probe,
+ .remove = __devexit_p(ath5k_pci_remove),
+ .driver.pm = ATH5K_PM_OPS,
+};
+
+/*
+ * Module init/exit functions
+ */
+static int __init
+init_ath5k_pci(void)
+{
+ int ret;
+
+ ret = pci_register_driver(&ath5k_pci_driver);
+ if (ret) {
+ printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit
+exit_ath5k_pci(void)
+{
+ pci_unregister_driver(&ath5k_pci_driver);
+}
+
+module_init(init_ath5k_pci);
+module_exit(exit_ath5k_pci);
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 074b4c644399..e5f2b96a4c63 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -31,87 +31,163 @@
#include "debug.h"
#include "base.h"
+/*
+ * AR5212+ can use higher rates for ack transmition
+ * based on current tx rate instead of the base rate.
+ * It does this to better utilize channel usage.
+ * This is a mapping between G rates (that cover both
+ * CCK and OFDM) and ack rates that we use when setting
+ * rate -> duration table. This mapping is hw-based so
+ * don't change anything.
+ *
+ * To enable this functionality we must set
+ * ah->ah_ack_bitrate_high to true else base rate is
+ * used (1Mb for CCK, 6Mb for OFDM).
+ */
+static const unsigned int ack_rates_high[] =
+/* Tx -> ACK */
+/* 1Mb -> 1Mb */ { 0,
+/* 2MB -> 2Mb */ 1,
+/* 5.5Mb -> 2Mb */ 1,
+/* 11Mb -> 2Mb */ 1,
+/* 6Mb -> 6Mb */ 4,
+/* 9Mb -> 6Mb */ 4,
+/* 12Mb -> 12Mb */ 6,
+/* 18Mb -> 12Mb */ 6,
+/* 24Mb -> 24Mb */ 8,
+/* 36Mb -> 24Mb */ 8,
+/* 48Mb -> 24Mb */ 8,
+/* 54Mb -> 24Mb */ 8 };
+
/*******************\
-* Generic functions *
+* Helper functions *
\*******************/
/**
- * ath5k_hw_set_opmode - Set PCU operating mode
+ * ath5k_hw_get_frame_duration - Get tx time of a frame
*
* @ah: The &struct ath5k_hw
- * @op_mode: &enum nl80211_iftype operating mode
+ * @len: Frame's length in bytes
+ * @rate: The @struct ieee80211_rate
*
- * Initialize PCU for the various operating modes (AP/STA etc)
+ * Calculate tx duration of a frame given it's rate and length
+ * It extends ieee80211_generic_frame_duration for non standard
+ * bwmodes.
*/
-int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
+int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+ int len, struct ieee80211_rate *rate)
{
- struct ath_common *common = ath5k_hw_common(ah);
- u32 pcu_reg, beacon_reg, low_id, high_id;
+ struct ath5k_softc *sc = ah->ah_sc;
+ int sifs, preamble, plcp_bits, sym_time;
+ int bitrate, bits, symbols, symbol_bits;
+ int dur;
+
+ /* Fallback */
+ if (!ah->ah_bwmode) {
+ dur = ieee80211_generic_frame_duration(sc->hw,
+ NULL, len, rate);
+ return dur;
+ }
- ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
+ bitrate = rate->bitrate;
+ preamble = AR5K_INIT_OFDM_PREAMPLE_TIME;
+ plcp_bits = AR5K_INIT_OFDM_PLCP_BITS;
+ sym_time = AR5K_INIT_OFDM_SYMBOL_TIME;
- /* Preserve rest settings */
- pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
- pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
- | AR5K_STA_ID1_KEYSRCH_MODE
- | (ah->ah_version == AR5K_AR5210 ?
- (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
+ sifs = AR5K_INIT_SIFS_TURBO;
+ preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN;
+ break;
+ case AR5K_BWMODE_10MHZ:
+ sifs = AR5K_INIT_SIFS_HALF_RATE;
+ preamble *= 2;
+ sym_time *= 2;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ sifs = AR5K_INIT_SIFS_QUARTER_RATE;
+ preamble *= 4;
+ sym_time *= 4;
+ break;
+ default:
+ sifs = AR5K_INIT_SIFS_DEFAULT_BG;
+ break;
+ }
- beacon_reg = 0;
+ bits = plcp_bits + (len << 3);
+ /* Bit rate is in 100Kbits */
+ symbol_bits = bitrate * sym_time;
+ symbols = DIV_ROUND_UP(bits * 10, symbol_bits);
- switch (op_mode) {
- case NL80211_IFTYPE_ADHOC:
- pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
- beacon_reg |= AR5K_BCR_ADHOC;
- if (ah->ah_version == AR5K_AR5210)
- pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
- else
- AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
- break;
+ dur = sifs + preamble + (sym_time * symbols);
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
- beacon_reg |= AR5K_BCR_AP;
- if (ah->ah_version == AR5K_AR5210)
- pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
- else
- AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
- break;
+ return dur;
+}
- case NL80211_IFTYPE_STATION:
- pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
- | (ah->ah_version == AR5K_AR5210 ?
- AR5K_STA_ID1_PWR_SV : 0);
- case NL80211_IFTYPE_MONITOR:
- pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
- | (ah->ah_version == AR5K_AR5210 ?
- AR5K_STA_ID1_NO_PSPOLL : 0);
- break;
+/**
+ * ath5k_hw_get_default_slottime - Get the default slot time for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+ unsigned int slot_time;
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
+ slot_time = AR5K_INIT_SLOT_TIME_TURBO;
+ break;
+ case AR5K_BWMODE_10MHZ:
+ slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
+ break;
+ case AR5K_BWMODE_DEFAULT:
+ slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
default:
- return -EINVAL;
+ if (channel->hw_value & CHANNEL_CCK)
+ slot_time = AR5K_INIT_SLOT_TIME_B;
+ break;
}
- /*
- * Set PCU registers
- */
- low_id = get_unaligned_le32(common->macaddr);
- high_id = get_unaligned_le16(common->macaddr + 4);
- ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
- ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+ return slot_time;
+}
- /*
- * Set Beacon Control Register on 5210
- */
- if (ah->ah_version == AR5K_AR5210)
- ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+/**
+ * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+ unsigned int sifs;
- return 0;
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
+ sifs = AR5K_INIT_SIFS_TURBO;
+ break;
+ case AR5K_BWMODE_10MHZ:
+ sifs = AR5K_INIT_SIFS_HALF_RATE;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ sifs = AR5K_INIT_SIFS_QUARTER_RATE;
+ break;
+ case AR5K_BWMODE_DEFAULT:
+ sifs = AR5K_INIT_SIFS_DEFAULT_BG;
+ default:
+ if (channel->hw_value & CHANNEL_5GHZ)
+ sifs = AR5K_INIT_SIFS_DEFAULT_A;
+ break;
+ }
+
+ return sifs;
}
/**
- * ath5k_hw_update - Update MIB counters (mac layer statistics)
+ * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics)
*
* @ah: The &struct ath5k_hw
*
@@ -133,36 +209,88 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
}
+
+/******************\
+* ACK/CTS Timeouts *
+\******************/
+
/**
- * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
*
- * @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmission rate
- * for ACKs or not
+ * @ah: the &struct ath5k_hw
+ * @mode: one of enum ath5k_driver_mode
+ *
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preamble
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates.
*
- * If high flag is set, we tell hw to use a set of control rates based on
- * the current transmission rate (check out control_rates array inside reset.c).
- * If not hw just uses the lowest rate available for the current modulation
- * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
*/
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
{
- if (ah->ah_version != AR5K_AR5212)
- return;
- else {
- u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
- if (high)
- AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+ struct ath5k_softc *sc = ah->ah_sc;
+ struct ieee80211_rate *rate;
+ unsigned int i;
+ /* 802.11g covers both OFDM and CCK */
+ u8 band = IEEE80211_BAND_2GHZ;
+
+ /* Write rate duration table */
+ for (i = 0; i < sc->sbands[band].n_bitrates; i++) {
+ u32 reg;
+ u16 tx_time;
+
+ if (ah->ah_ack_bitrate_high)
+ rate = &sc->sbands[band].bitrates[ack_rates_high[i]];
+ /* CCK -> 1Mb */
+ else if (i < 4)
+ rate = &sc->sbands[band].bitrates[0];
+ /* OFDM -> 6Mb */
else
- AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+ rate = &sc->sbands[band].bitrates[4];
+
+ /* Set ACK timeout */
+ reg = AR5K_RATE_DUR(rate->hw_value);
+
+ /* An ACK frame consists of 10 bytes. If you add the FCS,
+ * which ieee80211_generic_frame_duration() adds,
+ * its 14 bytes. Note we use the control rate and not the
+ * actual rate for this rate. See mac80211 tx.c
+ * ieee80211_duration() for a brief description of
+ * what rate we should choose to TX ACKs. */
+ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+
+ tx_time = le16_to_cpu(tx_time);
+
+ ath5k_hw_reg_write(ah, tx_time, reg);
+
+ if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
+ continue;
+
+ /*
+ * We're not distinguishing short preamble here,
+ * This is true, all we'll get is a longer value here
+ * which is not necessarilly bad. We could use
+ * export ieee80211_frame_duration() but that needs to be
+ * fixed first to be properly used by mac802111 drivers:
+ *
+ * - remove erp stuff and let the routine figure ofdm
+ * erp rates
+ * - remove passing argument ieee80211_local as
+ * drivers don't have access to it
+ * - move drivers using ieee80211_generic_frame_duration()
+ * to this
+ */
+ ath5k_hw_reg_write(ah, tx_time,
+ reg + (AR5K_SET_SHORT_PREAMBLE << 2));
}
}
-
-/******************\
-* ACK/CTS Timeouts *
-\******************/
-
/**
* ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
*
@@ -199,88 +327,10 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
return 0;
}
-/**
- * ath5k_hw_htoclock - Translate usec to hw clock units
- *
- * @ah: The &struct ath5k_hw
- * @usec: value in microseconds
- */
-unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
-{
- struct ath_common *common = ath5k_hw_common(ah);
- return usec * common->clockrate;
-}
-
-/**
- * ath5k_hw_clocktoh - Translate hw clock units to usec
- * @clock: value in hw clock units
- */
-unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
-{
- struct ath_common *common = ath5k_hw_common(ah);
- return clock / common->clockrate;
-}
-
-/**
- * ath5k_hw_set_clockrate - Set common->clockrate for the current channel
- *
- * @ah: The &struct ath5k_hw
- */
-void ath5k_hw_set_clockrate(struct ath5k_hw *ah)
-{
- struct ieee80211_channel *channel = ah->ah_current_channel;
- struct ath_common *common = ath5k_hw_common(ah);
- int clock;
-
- if (channel->hw_value & CHANNEL_5GHZ)
- clock = 40; /* 802.11a */
- else if (channel->hw_value & CHANNEL_CCK)
- clock = 22; /* 802.11b */
- else
- clock = 44; /* 802.11g */
-
- /* Clock rate in turbo modes is twice the normal rate */
- if (channel->hw_value & CHANNEL_TURBO)
- clock *= 2;
-
- common->clockrate = clock;
-}
-
-/**
- * ath5k_hw_get_default_slottime - Get the default slot time for current mode
- *
- * @ah: The &struct ath5k_hw
- */
-static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
-{
- struct ieee80211_channel *channel = ah->ah_current_channel;
-
- if (channel->hw_value & CHANNEL_TURBO)
- return 6; /* both turbo modes */
-
- if (channel->hw_value & CHANNEL_CCK)
- return 20; /* 802.11b */
-
- return 9; /* 802.11 a/g */
-}
-
-/**
- * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
- *
- * @ah: The &struct ath5k_hw
- */
-static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
-{
- struct ieee80211_channel *channel = ah->ah_current_channel;
-
- if (channel->hw_value & CHANNEL_TURBO)
- return 8; /* both turbo modes */
- if (channel->hw_value & CHANNEL_5GHZ)
- return 16; /* 802.11a */
-
- return 10; /* 802.11 b/g */
-}
+/*******************\
+* RX filter Control *
+\*******************/
/**
* ath5k_hw_set_lladdr - Set station id
@@ -362,39 +412,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
ath_hw_setbssidmask(common);
}
-/************\
-* RX Control *
-\************/
-
-/**
- * ath5k_hw_start_rx_pcu - Start RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Starts RX engine on PCU so that hw can process RXed frames
- * (ACK etc).
- *
- * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
- */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
-{
- AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
-/**
- * at5k_hw_stop_rx_pcu - Stop RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Stops RX engine on PCU
- *
- * TODO: Detach ANI here
- */
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
-{
- AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
/*
* Set multicast filter
*/
@@ -746,7 +763,7 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
* @ah: The &struct ath5k_hw
* @coverage_class: IEEE 802.11 coverage class number
*
- * Sets slot time, ACK timeout and CTS timeout for given coverage class.
+ * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
*/
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
{
@@ -755,9 +772,175 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
int cts_timeout = ack_timeout;
- ath5k_hw_set_slot_time(ah, slot_time);
+ ath5k_hw_set_ifs_intervals(ah, slot_time);
ath5k_hw_set_ack_timeout(ah, ack_timeout);
ath5k_hw_set_cts_timeout(ah, cts_timeout);
ah->ah_coverage_class = coverage_class;
}
+
+/***************************\
+* Init/Start/Stop functions *
+\***************************/
+
+/**
+ * ath5k_hw_start_rx_pcu - Start RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Starts RX engine on PCU so that hw can process RXed frames
+ * (ACK etc).
+ *
+ * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * at5k_hw_stop_rx_pcu - Stop RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stops RX engine on PCU
+ */
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+{
+ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * ath5k_hw_set_opmode - Set PCU operating mode
+ *
+ * @ah: The &struct ath5k_hw
+ * @op_mode: &enum nl80211_iftype operating mode
+ *
+ * Configure PCU for the various operating modes (AP/STA etc)
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
+{
+ struct ath_common *common = ath5k_hw_common(ah);
+ u32 pcu_reg, beacon_reg, low_id, high_id;
+
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
+
+ /* Preserve rest settings */
+ pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+ pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+ | AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
+ (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
+ beacon_reg = 0;
+
+ switch (op_mode) {
+ case NL80211_IFTYPE_ADHOC:
+ pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
+ beacon_reg |= AR5K_BCR_ADHOC;
+ if (ah->ah_version == AR5K_AR5210)
+ pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+ else
+ AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
+ break;
+
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
+ beacon_reg |= AR5K_BCR_AP;
+ if (ah->ah_version == AR5K_AR5210)
+ pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+ else
+ AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
+ AR5K_STA_ID1_PWR_SV : 0);
+ case NL80211_IFTYPE_MONITOR:
+ pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
+ AR5K_STA_ID1_NO_PSPOLL : 0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Set PCU registers
+ */
+ low_id = get_unaligned_le32(common->macaddr);
+ high_id = get_unaligned_le16(common->macaddr + 4);
+ ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+ ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+ /*
+ * Set Beacon Control Register on 5210
+ */
+ if (ah->ah_version == AR5K_AR5210)
+ ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+ return 0;
+}
+
+void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ u8 mode)
+{
+ /* Set bssid and bssid mask */
+ ath5k_hw_set_bssid(ah);
+
+ /* Set PCU config */
+ ath5k_hw_set_opmode(ah, op_mode);
+
+ /* Write rate duration table only on AR5212 and if
+ * virtual interface has already been brought up
+ * XXX: rethink this after new mode changes to
+ * mac80211 are integrated */
+ if (ah->ah_version == AR5K_AR5212 &&
+ ah->ah_sc->nvifs)
+ ath5k_hw_write_rate_duration(ah);
+
+ /* Set RSSI/BRSSI thresholds
+ *
+ * Note: If we decide to set this value
+ * dynamicaly, have in mind that when AR5K_RSSI_THR
+ * register is read it might return 0x40 if we haven't
+ * wrote anything to it plus BMISS RSSI threshold is zeroed.
+ * So doing a save/restore procedure here isn't the right
+ * choice. Instead store it on ath5k_hw */
+ ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+ AR5K_TUNE_BMISS_THRES <<
+ AR5K_RSSI_THR_BMISS_S),
+ AR5K_RSSI_THR);
+
+ /* MIC QoS support */
+ if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+ ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+ ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
+ }
+
+ /* QoS NOACK Policy */
+ if (ah->ah_version == AR5K_AR5212) {
+ ath5k_hw_reg_write(ah,
+ AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+ AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) |
+ AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+ AR5K_QOS_NOACK);
+ }
+
+ /* Restore slot time and ACK timeouts */
+ if (ah->ah_coverage_class > 0)
+ ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
+
+ /* Set ACK bitrate mode (see ack_rates_high) */
+ if (ah->ah_version == AR5K_AR5212) {
+ u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+ if (ah->ah_ack_bitrate_high)
+ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+ else
+ AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+ }
+ return;
+}
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 219367884e64..78c26fdccad1 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -29,6 +29,95 @@
#include "rfbuffer.h"
#include "rfgain.h"
+
+/******************\
+* Helper functions *
+\******************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+ unsigned int i;
+ u32 srev;
+ u16 ret;
+
+ /*
+ * Set the radio chip access register
+ */
+ switch (chan) {
+ case CHANNEL_2GHZ:
+ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+ break;
+ case CHANNEL_5GHZ:
+ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+ break;
+ default:
+ return 0;
+ }
+
+ mdelay(2);
+
+ /* ...wait until PHY is ready and read the selected radio revision */
+ ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+ for (i = 0; i < 8; i++)
+ ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+ if (ah->ah_version == AR5K_AR5210) {
+ srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+ ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+ } else {
+ srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+ ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+ ((srev & 0x0f) << 4), 8);
+ }
+
+ /* Reset to the 5GHz mode */
+ ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+ return ret;
+}
+
+/*
+ * Check if a channel is supported
+ */
+bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+ /* Check if the channel is in our supported range */
+ if (flags & CHANNEL_2GHZ) {
+ if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+ (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+ return true;
+ } else if (flags & CHANNEL_5GHZ)
+ if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+ (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+ return true;
+
+ return false;
+}
+
+bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel)
+{
+ u8 refclk_freq;
+
+ if ((ah->ah_radio == AR5K_RF5112) ||
+ (ah->ah_radio == AR5K_RF5413) ||
+ (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+ refclk_freq = 40;
+ else
+ refclk_freq = 32;
+
+ if ((channel->center_freq % refclk_freq != 0) &&
+ ((channel->center_freq % refclk_freq < 10) ||
+ (channel->center_freq % refclk_freq > 22)))
+ return true;
+ else
+ return false;
+}
+
/*
* Used to modify RF Banks before writing them to AR5K_RF_BUFFER
*/
@@ -110,6 +199,90 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
return data;
}
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_phy_init.
+ *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
+ */
+static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel)
+{
+ /* Get exponent and mantissa and set it */
+ u32 coef_scaled, coef_exp, coef_man,
+ ds_coef_exp, ds_coef_man, clock;
+
+ BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
+ !(channel->hw_value & CHANNEL_OFDM));
+
+ /* Get coefficient
+ * ALGO: coef = (5 * clock / carrier_freq) / 2
+ * we scale coef by shifting clock value by 24 for
+ * better precision since we use integers */
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
+ clock = 40 * 2;
+ break;
+ case AR5K_BWMODE_10MHZ:
+ clock = 40 / 2;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ clock = 40 / 4;
+ break;
+ default:
+ clock = 40;
+ break;
+ }
+ coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
+
+ /* Get exponent
+ * ALGO: coef_exp = 14 - highest set bit position */
+ coef_exp = ilog2(coef_scaled);
+
+ /* Doesn't make sense if it's zero*/
+ if (!coef_scaled || !coef_exp)
+ return -EINVAL;
+
+ /* Note: we've shifted coef_scaled by 24 */
+ coef_exp = 14 - (coef_exp - 24);
+
+
+ /* Get mantissa (significant digits)
+ * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
+ coef_man = coef_scaled +
+ (1 << (24 - coef_exp - 1));
+
+ /* Calculate delta slope coefficient exponent
+ * and mantissa (remove scaling) and set them on hw */
+ ds_coef_man = coef_man >> (24 - coef_exp);
+ ds_coef_exp = coef_exp - 16;
+
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+ AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+ AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+ return 0;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+ /*Just a try M.F.*/
+ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+ return 0;
+}
+
+
/**********************\
* RF Gain optimization *
\**********************/
@@ -436,10 +609,10 @@ done:
/* Write initial RF gain table to set the RF sensitivity
* this one works on all RF chips and has nothing to do
* with gain_F calibration */
-int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
+static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band)
{
const struct ath5k_ini_rfgain *ath5k_rfg;
- unsigned int i, size;
+ unsigned int i, size, index;
switch (ah->ah_radio) {
case AR5K_RF5111:
@@ -471,17 +644,11 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
return -EINVAL;
}
- switch (freq) {
- case AR5K_INI_RFGAIN_2GHZ:
- case AR5K_INI_RFGAIN_5GHZ:
- break;
- default:
- return -EINVAL;
- }
+ index = (band == IEEE80211_BAND_2GHZ) ? 1 : 0;
for (i = 0; i < size; i++) {
AR5K_REG_WAIT(i);
- ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+ ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[index],
(u32)ath5k_rfg[i].rfg_register);
}
@@ -494,12 +661,11 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
* RF Registers setup *
\********************/
-
/*
* Setup RF registers by writing RF buffer on hw
*/
-int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
- unsigned int mode)
+static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel, unsigned int mode)
{
const struct ath5k_rf_reg *rf_regs;
const struct ath5k_ini_rfbuffer *ini_rfb;
@@ -652,6 +818,11 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
g_step = &go->go_step[ah->ah_gain.g_step_idx];
+ /* Set turbo mode (N/A on RF5413) */
+ if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) &&
+ (ah->ah_radio != AR5K_RF5413))
+ ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_TURBO, false);
+
/* Bank Modifications (chip-specific) */
if (ah->ah_radio == AR5K_RF5111) {
@@ -691,7 +862,23 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
AR5K_RF_PLO_SEL, true);
- /* TODO: Half/quarter channel support */
+ /* Tweak power detectors for half/quarter rate support */
+ if (ah->ah_bwmode == AR5K_BWMODE_5MHZ ||
+ ah->ah_bwmode == AR5K_BWMODE_10MHZ) {
+ u8 wait_i;
+
+ ath5k_hw_rfb_op(ah, rf_regs, 0x1f,
+ AR5K_RF_WAIT_S, true);
+
+ wait_i = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ?
+ 0x1f : 0x10;
+
+ ath5k_hw_rfb_op(ah, rf_regs, wait_i,
+ AR5K_RF_WAIT_I, true);
+ ath5k_hw_rfb_op(ah, rf_regs, 3,
+ AR5K_RF_MAX_TIME, true);
+
+ }
}
if (ah->ah_radio == AR5K_RF5112) {
@@ -789,8 +976,20 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
AR5K_RF_GAIN_I, true);
- /* TODO: Half/quarter channel support */
+ /* Tweak power detector for half/quarter rates */
+ if (ah->ah_bwmode == AR5K_BWMODE_5MHZ ||
+ ah->ah_bwmode == AR5K_BWMODE_10MHZ) {
+ u8 pd_delay;
+ pd_delay = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ?
+ 0xf : 0x8;
+
+ ath5k_hw_rfb_op(ah, rf_regs, pd_delay,
+ AR5K_RF_PD_PERIOD_A, true);
+ ath5k_hw_rfb_op(ah, rf_regs, 0xf,
+ AR5K_RF_PD_DELAY_A, true);
+
+ }
}
if (ah->ah_radio == AR5K_RF5413 &&
@@ -822,24 +1021,6 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
\**************************/
/*
- * Check if a channel is supported
- */
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
-{
- /* Check if the channel is in our supported range */
- if (flags & CHANNEL_2GHZ) {
- if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
- (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
- return true;
- } else if (flags & CHANNEL_5GHZ)
- if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
- (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
- return true;
-
- return false;
-}
-
-/*
* Convertion needed for RF5110
*/
static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
@@ -1045,7 +1226,8 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
/*
* Set a channel on the radio chip
*/
-int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+static int ath5k_hw_channel(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel)
{
int ret;
/*
@@ -1092,8 +1274,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
}
ah->ah_current_channel = channel;
- ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
- ath5k_hw_set_clockrate(ah);
return 0;
}
@@ -1102,18 +1282,12 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
PHY calibration
\*****************/
-static int sign_extend(int val, const int nbits)
-{
- int order = BIT(nbits-1);
- return (val ^ order) - order;
-}
-
static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
{
s32 val;
val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
- return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
+ return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 8);
}
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
@@ -1181,22 +1355,7 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
return;
}
- switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- case CHANNEL_T:
- case CHANNEL_XR:
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- case CHANNEL_G:
- case CHANNEL_TG:
- ee_mode = AR5K_EEPROM_MODE_11G;
- break;
- default:
- case CHANNEL_B:
- ee_mode = AR5K_EEPROM_MODE_11B;
- break;
- }
-
+ ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
/* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah);
@@ -1425,31 +1584,12 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
return ret;
}
+
/***************************\
* Spur mitigation functions *
\***************************/
-bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
- struct ieee80211_channel *channel)
-{
- u8 refclk_freq;
-
- if ((ah->ah_radio == AR5K_RF5112) ||
- (ah->ah_radio == AR5K_RF5413) ||
- (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
- refclk_freq = 40;
- else
- refclk_freq = 32;
-
- if ((channel->center_freq % refclk_freq != 0) &&
- ((channel->center_freq % refclk_freq < 10) ||
- (channel->center_freq % refclk_freq > 22)))
- return true;
- else
- return false;
-}
-
-void
+static void
ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
@@ -1478,7 +1618,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
spur_chan_fbin = AR5K_EEPROM_NO_SPUR;
spur_detection_window = AR5K_SPUR_CHAN_WIDTH;
/* XXX: Half/Quarter channels ?*/
- if (channel->hw_value & CHANNEL_TURBO)
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
spur_detection_window *= 2;
for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) {
@@ -1507,32 +1647,43 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
* Calculate deltas:
* spur_freq_sigma_delta -> spur_offset / sample_freq << 21
* spur_delta_phase -> spur_offset / chip_freq << 11
- * Note: Both values have 100KHz resolution
+ * Note: Both values have 100Hz resolution
*/
- /* XXX: Half/Quarter rate channels ? */
- switch (channel->hw_value) {
- case CHANNEL_A:
- /* Both sample_freq and chip_freq are 40MHz */
- spur_delta_phase = (spur_offset << 17) / 25;
- spur_freq_sigma_delta = (spur_delta_phase >> 10);
- symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
- break;
- case CHANNEL_G:
- /* sample_freq -> 40MHz chip_freq -> 44MHz
- * (for b compatibility) */
- spur_freq_sigma_delta = (spur_offset << 8) / 55;
- spur_delta_phase = (spur_offset << 17) / 25;
- symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
- break;
- case CHANNEL_T:
- case CHANNEL_TG:
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
/* Both sample_freq and chip_freq are 80MHz */
spur_delta_phase = (spur_offset << 16) / 25;
spur_freq_sigma_delta = (spur_delta_phase >> 10);
- symbol_width = AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz;
+ symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz * 2;
break;
+ case AR5K_BWMODE_10MHZ:
+ /* Both sample_freq and chip_freq are 20MHz (?) */
+ spur_delta_phase = (spur_offset << 18) / 25;
+ spur_freq_sigma_delta = (spur_delta_phase >> 10);
+ symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
+ case AR5K_BWMODE_5MHZ:
+ /* Both sample_freq and chip_freq are 10MHz (?) */
+ spur_delta_phase = (spur_offset << 19) / 25;
+ spur_freq_sigma_delta = (spur_delta_phase >> 10);
+ symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
default:
- return;
+ if (channel->hw_value == CHANNEL_A) {
+ /* Both sample_freq and chip_freq are 40MHz */
+ spur_delta_phase = (spur_offset << 17) / 25;
+ spur_freq_sigma_delta =
+ (spur_delta_phase >> 10);
+ symbol_width =
+ AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
+ } else {
+ /* sample_freq -> 40MHz chip_freq -> 44MHz
+ * (for b compatibility) */
+ spur_delta_phase = (spur_offset << 17) / 25;
+ spur_freq_sigma_delta =
+ (spur_offset << 8) / 55;
+ symbol_width =
+ AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
+ }
+ break;
}
/* Calculate pilot and magnitude masks */
@@ -1672,63 +1823,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
}
}
-/********************\
- Misc PHY functions
-\********************/
-
-int ath5k_hw_phy_disable(struct ath5k_hw *ah)
-{
- /*Just a try M.F.*/
- ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-
- return 0;
-}
-
-/*
- * Get the PHY Chip revision
- */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
-{
- unsigned int i;
- u32 srev;
- u16 ret;
-
- /*
- * Set the radio chip access register
- */
- switch (chan) {
- case CHANNEL_2GHZ:
- ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
- break;
- case CHANNEL_5GHZ:
- ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
- break;
- default:
- return 0;
- }
-
- mdelay(2);
-
- /* ...wait until PHY is ready and read the selected radio revision */
- ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
-
- for (i = 0; i < 8; i++)
- ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
-
- if (ah->ah_version == AR5K_AR5210) {
- srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
- ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
- } else {
- srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
- ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
- ((srev & 0x0f) << 4), 8);
- }
-
- /* Reset to the 5GHz mode */
- ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-
- return ret;
-}
/*****************\
* Antenna control *
@@ -1822,7 +1916,8 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
- u8 def_ant, tx_ant, ee_mode;
+ int ee_mode;
+ u8 def_ant, tx_ant;
u32 sta_id1 = 0;
/* if channel is not initialized yet we can't set the antennas
@@ -1834,20 +1929,8 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
def_ant = ah->ah_def_ant;
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- case CHANNEL_T:
- case CHANNEL_XR:
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- case CHANNEL_G:
- case CHANNEL_TG:
- ee_mode = AR5K_EEPROM_MODE_11G;
- break;
- case CHANNEL_B:
- ee_mode = AR5K_EEPROM_MODE_11B;
- break;
- default:
+ ee_mode = ath5k_eeprom_mode_from_channel(channel);
+ if (ee_mode < 0) {
ATH5K_ERR(ah->ah_sc,
"invalid channel: %d\n", channel->center_freq);
return;
@@ -2275,20 +2358,20 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
- ctl_mode |= AR5K_CTL_11A;
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+ ctl_mode |= AR5K_CTL_TURBO;
+ else
+ ctl_mode |= AR5K_CTL_11A;
break;
case CHANNEL_G:
- ctl_mode |= AR5K_CTL_11G;
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+ ctl_mode |= AR5K_CTL_TURBOG;
+ else
+ ctl_mode |= AR5K_CTL_11G;
break;
case CHANNEL_B:
ctl_mode |= AR5K_CTL_11B;
break;
- case CHANNEL_T:
- ctl_mode |= AR5K_CTL_TURBO;
- break;
- case CHANNEL_TG:
- ctl_mode |= AR5K_CTL_TURBOG;
- break;
case CHANNEL_XR:
/* Fall through */
default:
@@ -2482,7 +2565,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
/* Write PCDAC values on hw */
static void
-ath5k_setup_pcdac_table(struct ath5k_hw *ah)
+ath5k_write_pcdac_table(struct ath5k_hw *ah)
{
u8 *pcdac_out = ah->ah_txpower.txp_pd_table;
int i;
@@ -2631,10 +2714,12 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
/* Write PDADC values on hw */
static void
-ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah,
- u8 pdcurves, u8 *pdg_to_idx)
+ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
+ u8 *pdg_to_idx = ee->ee_pdc_to_idx[ee_mode];
+ u8 pdcurves = ee->ee_pd_gains[ee_mode];
u32 reg;
u8 i;
@@ -2844,8 +2929,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
(s16) pcinfo_R->freq,
pcinfo_L->max_pwr, pcinfo_R->max_pwr);
- /* We are ready to go, fill PCDAC/PDADC
- * table and write settings on hardware */
+ /* Fill PCDAC/PDADC table */
switch (type) {
case AR5K_PWRTABLE_LINEAR_PCDAC:
/* For RF5112 we can have one or two curves
@@ -2858,9 +2942,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
* match max power value with max
* table index */
ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
-
- /* Write settings on hw */
- ath5k_setup_pcdac_table(ah);
break;
case AR5K_PWRTABLE_PWR_TO_PCDAC:
/* We are done for RF5111 since it has only
@@ -2870,9 +2951,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
/* No rate powertable adjustment for RF5111 */
ah->ah_txpower.txp_min_idx = 0;
ah->ah_txpower.txp_offset = 0;
-
- /* Write settings on hw */
- ath5k_setup_pcdac_table(ah);
break;
case AR5K_PWRTABLE_PWR_TO_PDADC:
/* Set PDADC boundaries and fill
@@ -2880,9 +2958,6 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
ee->ee_pd_gains[ee_mode]);
- /* Write settings on hw */
- ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
-
/* Set txp.offset, note that table_min
* can be negative */
ah->ah_txpower.txp_offset = table_min[0];
@@ -2891,9 +2966,20 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
return -EINVAL;
}
+ ah->ah_txpower.txp_setup = true;
+
return 0;
}
+/* Write power table for current channel to hw */
+static void
+ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type)
+{
+ if (type == AR5K_PWRTABLE_PWR_TO_PDADC)
+ ath5k_write_pwr_to_pdadc_table(ah, ee_mode);
+ else
+ ath5k_write_pcdac_table(ah);
+}
/*
* Per-rate tx power setting
@@ -2982,7 +3068,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
/* Min/max in 0.25dB units */
ah->ah_txpower.txp_min_pwr = 2 * rates[7];
- ah->ah_txpower.txp_max_pwr = 2 * rates[0];
+ ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
ah->ah_txpower.txp_ofdm = rates[7];
}
@@ -2990,11 +3076,13 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
/*
* Set transmission power
*/
-int
+static int
ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
- u8 ee_mode, u8 txpower)
+ u8 txpower)
{
struct ath5k_rate_pcal_info rate_info;
+ struct ieee80211_channel *curr_channel = ah->ah_current_channel;
+ int ee_mode;
u8 type;
int ret;
@@ -3003,14 +3091,18 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
- /* Reset TX power values */
- memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
- ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
- ah->ah_txpower.txp_min_pwr = 0;
- ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
+ ee_mode = ath5k_eeprom_mode_from_channel(channel);
+ if (ee_mode < 0) {
+ ATH5K_ERR(ah->ah_sc,
+ "invalid channel: %d\n", channel->center_freq);
+ return -EINVAL;
+ }
/* Initialize TX power table */
switch (ah->ah_radio) {
+ case AR5K_RF5110:
+ /* TODO */
+ return 0;
case AR5K_RF5111:
type = AR5K_PWRTABLE_PWR_TO_PCDAC;
break;
@@ -3028,10 +3120,26 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
- /* FIXME: Only on channel/mode change */
- ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
- if (ret)
- return ret;
+ /*
+ * If we don't change channel/mode skip tx powertable calculation
+ * and use the cached one.
+ */
+ if (!ah->ah_txpower.txp_setup ||
+ (channel->hw_value != curr_channel->hw_value) ||
+ (channel->center_freq != curr_channel->center_freq)) {
+ /* Reset TX power values */
+ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+ ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+
+ /* Calculate the powertable */
+ ret = ath5k_setup_channel_powertable(ah, channel,
+ ee_mode, type);
+ if (ret)
+ return ret;
+ }
+
+ /* Write table on hw */
+ ath5k_write_channel_powertable(ah, ee_mode, type);
/* Limit max power if we have a CTL available */
ath5k_get_max_ctl_power(ah, channel);
@@ -3086,31 +3194,219 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
- /*Just a try M.F.*/
- struct ieee80211_channel *channel = ah->ah_current_channel;
- u8 ee_mode;
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
+ "changing txpower to %d\n", txpower);
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- case CHANNEL_T:
- case CHANNEL_XR:
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- case CHANNEL_G:
- case CHANNEL_TG:
- ee_mode = AR5K_EEPROM_MODE_11G;
- break;
- case CHANNEL_B:
- ee_mode = AR5K_EEPROM_MODE_11B;
- break;
- default:
- ATH5K_ERR(ah->ah_sc,
- "invalid channel: %d\n", channel->center_freq);
+ return ath5k_hw_txpower(ah, ah->ah_current_channel, txpower);
+}
+
+/*************\
+ Init function
+\*************/
+
+int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+ u8 mode, bool fast)
+{
+ struct ieee80211_channel *curr_channel;
+ int ret, i;
+ u32 phy_tst1;
+ ret = 0;
+
+ /*
+ * Sanity check for fast flag
+ * Don't try fast channel change when changing modulation
+ * mode/band. We check for chip compatibility on
+ * ath5k_hw_reset.
+ */
+ curr_channel = ah->ah_current_channel;
+ if (fast && (channel->hw_value != curr_channel->hw_value))
return -EINVAL;
+
+ /*
+ * On fast channel change we only set the synth parameters
+ * while PHY is running, enable calibration and skip the rest.
+ */
+ if (fast) {
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+ AR5K_PHY_RFBUS_REQ_REQUEST);
+ for (i = 0; i < 100; i++) {
+ if (ath5k_hw_reg_read(ah, AR5K_PHY_RFBUS_GRANT))
+ break;
+ udelay(5);
+ }
+ /* Failed */
+ if (i >= 100)
+ return -EIO;
}
- ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
- "changing txpower to %d\n", txpower);
+ /*
+ * Set TX power
+ *
+ * Note: We need to do that before we set
+ * RF buffer settings on 5211/5212+ so that we
+ * properly set curve indices.
+ */
+ ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ?
+ ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER);
+ if (ret)
+ return ret;
+
+ /*
+ * For 5210 we do all initialization using
+ * initvals, so we don't have to modify
+ * any settings (5210 also only supports
+ * a/aturbo modes)
+ */
+ if ((ah->ah_version != AR5K_AR5210) && !fast) {
+
+ /*
+ * Write initial RF gain settings
+ * This should work for both 5111/5112
+ */
+ ret = ath5k_hw_rfgain_init(ah, channel->band);
+ if (ret)
+ return ret;
+
+ mdelay(1);
+
+ /*
+ * Write RF buffer
+ */
+ ret = ath5k_hw_rfregs_init(ah, channel, mode);
+ if (ret)
+ return ret;
+
+ /* Write OFDM timings on 5212*/
+ if (ah->ah_version == AR5K_AR5212 &&
+ channel->hw_value & CHANNEL_OFDM) {
+
+ ret = ath5k_hw_write_ofdm_timings(ah, channel);
+ if (ret)
+ return ret;
+
+ /* Spur info is available only from EEPROM versions
+ * greater than 5.3, but the EEPROM routines will use
+ * static values for older versions */
+ if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
+ ath5k_hw_set_spur_mitigation_filter(ah,
+ channel);
+ }
+
+ /*Enable/disable 802.11b mode on 5111
+ (enable 2111 frequency converter + CCK)*/
+ if (ah->ah_radio == AR5K_RF5111) {
+ if (mode == AR5K_MODE_11B)
+ AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_B_MODE);
+ else
+ AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_B_MODE);
+ }
+
+ } else if (ah->ah_version == AR5K_AR5210) {
+ mdelay(1);
+ /* Disable phy and wait */
+ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+ mdelay(1);
+ }
+
+ /* Set channel on PHY */
+ ret = ath5k_hw_channel(ah, channel);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable the PHY and wait until completion
+ * This includes BaseBand and Synthesizer
+ * activation.
+ */
+ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+ /*
+ * On 5211+ read activation -> rx delay
+ * and use it.
+ */
+ if (ah->ah_version != AR5K_AR5210) {
+ u32 delay;
+ delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+ AR5K_PHY_RX_DELAY_M;
+ delay = (channel->hw_value & CHANNEL_CCK) ?
+ ((delay << 2) / 22) : (delay / 10);
+ if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
+ delay = delay << 1;
+ if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
+ delay = delay << 2;
+ /* XXX: /2 on turbo ? Let's be safe
+ * for now */
+ udelay(100 + delay);
+ } else {
+ mdelay(1);
+ }
+
+ if (fast)
+ /*
+ * Release RF Bus grant
+ */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+ AR5K_PHY_RFBUS_REQ_REQUEST);
+ else {
+ /*
+ * Perform ADC test to see if baseband is ready
+ * Set tx hold and check adc test register
+ */
+ phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+ ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+ for (i = 0; i <= 20; i++) {
+ if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+ break;
+ udelay(200);
+ }
+ ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+ }
+
+ /*
+ * Start automatic gain control calibration
+ *
+ * During AGC calibration RX path is re-routed to
+ * a power detector so we don't receive anything.
+ *
+ * This method is used to calibrate some static offsets
+ * used together with on-the fly I/Q calibration (the
+ * one performed via ath5k_hw_phy_calibrate), which doesn't
+ * interrupt rx path.
+ *
+ * While rx path is re-routed to the power detector we also
+ * start a noise floor calibration to measure the
+ * card's noise floor (the noise we measure when we are not
+ * transmitting or receiving anything).
+ *
+ * If we are in a noisy environment, AGC calibration may time
+ * out and/or noise floor calibration might timeout.
+ */
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+ AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
+
+ /* At the same time start I/Q calibration for QAM constellation
+ * -no need for CCK- */
+ ah->ah_calibration = false;
+ if (!(mode == AR5K_MODE_11B)) {
+ ah->ah_calibration = true;
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_RUN);
+ }
+
+ /* Wait for gain calibration to finish (we check for I/Q calibration
+ * during ath5k_phy_calibrate) */
+ if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+ AR5K_PHY_AGCCTL_CAL, 0, false)) {
+ ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
+ channel->center_freq);
+ }
+
+ /* Restore antenna mode */
+ ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
- return ath5k_hw_txpower(ah, channel, ee_mode, txpower);
+ return ret;
}
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 84c717ded1c5..2c9c9e793d4e 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -25,14 +25,52 @@ Queue Control Unit, DFS Control Unit Functions
#include "debug.h"
#include "base.h"
+
+/******************\
+* Helper functions *
+\******************/
+
/*
- * Get properties for a transmit queue
+ * Get number of pending frames
+ * for a specific queue [5211+]
*/
-int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
- struct ath5k_txq_info *queue_info)
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
{
- memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
- return 0;
+ u32 pending;
+ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+ /* Return if queue is declared inactive */
+ if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+ return false;
+
+ /* XXX: How about AR5K_CFG_TXCNT ? */
+ if (ah->ah_version == AR5K_AR5210)
+ return false;
+
+ pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
+ pending &= AR5K_QCU_STS_FRMPENDCNT;
+
+ /* It's possible to have no frames pending even if TXE
+ * is set. To indicate that q has not stopped return
+ * true */
+ if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+ return true;
+
+ return pending;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+ if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
+ return;
+
+ /* This queue will be skipped in further operations */
+ ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
+ /*For SIMR setup*/
+ AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
}
/*
@@ -50,6 +88,16 @@ static u16 ath5k_cw_validate(u16 cw_req)
}
/*
+ * Get properties for a transmit queue
+ */
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+ struct ath5k_txq_info *queue_info)
+{
+ memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
+ return 0;
+}
+
+/*
* Set properties for a transmit queue
*/
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
@@ -104,8 +152,8 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
/*
* Get queue by type
*/
- /*5210 only has 2 queues*/
- if (ah->ah_version == AR5K_AR5210) {
+ /* 5210 only has 2 queues */
+ if (ah->ah_capabilities.cap_queues.q_tx_num == 2) {
switch (queue_type) {
case AR5K_TX_QUEUE_DATA:
queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
@@ -172,113 +220,18 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
return queue;
}
-/*
- * Get number of pending frames
- * for a specific queue [5211+]
- */
-u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
-{
- u32 pending;
- AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
- /* Return if queue is declared inactive */
- if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
- return false;
-
- /* XXX: How about AR5K_CFG_TXCNT ? */
- if (ah->ah_version == AR5K_AR5210)
- return false;
-
- pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
- pending &= AR5K_QCU_STS_FRMPENDCNT;
-
- /* It's possible to have no frames pending even if TXE
- * is set. To indicate that q has not stopped return
- * true */
- if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
- return true;
-
- return pending;
-}
-
-/*
- * Set a transmit queue inactive
- */
-void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
-{
- if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
- return;
- /* This queue will be skipped in further operations */
- ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
- /*For SIMR setup*/
- AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
-}
+/*******************************\
+* Single QCU/DCU initialization *
+\*******************************/
/*
- * Set DFS properties for a transmit queue on DCU
+ * Set tx retry limits on DCU
*/
-int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
+ unsigned int queue)
{
u32 retry_lg, retry_sh;
- struct ath5k_txq_info *tq = &ah->ah_txq[queue];
-
- AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
- tq = &ah->ah_txq[queue];
-
- if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
- return 0;
-
- if (ah->ah_version == AR5K_AR5210) {
- /* Only handle data queues, others will be ignored */
- if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
- return 0;
-
- /* Set Slot time */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
- AR5K_SLOT_TIME);
- /* Set ACK_CTS timeout */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
- AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
- /* Set Transmit Latency */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- AR5K_INIT_TRANSMIT_LATENCY_TURBO :
- AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
-
- /* Set IFS0 */
- if (ah->ah_turbo) {
- ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
- tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
- AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
- AR5K_IFS0);
- } else {
- ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
- tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
- AR5K_IFS0_DIFS_S) |
- AR5K_INIT_SIFS, AR5K_IFS0);
- }
-
- /* Set IFS1 */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
- AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
- /* Set AR5K_PHY_SETTLING */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
- | 0x38 :
- (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
- | 0x1C,
- AR5K_PHY_SETTLING);
- /* Set Frame Control Register */
- ath5k_hw_reg_write(ah, ah->ah_turbo ?
- (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
- AR5K_PHY_TURBO_SHORT | 0x2020) :
- (AR5K_PHY_FRAME_CTL_INI | 0x1020),
- AR5K_PHY_FRAME_CTL_5210);
- }
/*
* Calculate and set retry limits
@@ -293,8 +246,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
retry_sh = AR5K_INIT_SH_RETRY;
}
- /*No QCU/DCU [5210]*/
+ /* Single data queue on AR5210 */
if (ah->ah_version == AR5K_AR5210) {
+ struct ath5k_txq_info *tq = &ah->ah_txq[queue];
+
+ if (queue > 0)
+ return;
+
ath5k_hw_reg_write(ah,
(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
@@ -304,8 +262,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
AR5K_NODCU_RETRY_LMT);
+ /* DCU on AR5211+ */
} else {
- /*QCU/DCU [5211+]*/
ath5k_hw_reg_write(ah,
AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
AR5K_DCU_RETRY_LMT_SLG_RETRY) |
@@ -314,219 +272,393 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+ }
+ return;
+}
- /*===Rest is also for QCU/DCU only [5211+]===*/
+/**
+ * ath5k_hw_reset_tx_queue - Initialize a single hw queue
+ *
+ * @ah The &struct ath5k_hw
+ * @queue The hw queue number
+ *
+ * Set DFS properties for the given transmit queue on DCU
+ * and configures all queue-specific parameters.
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+ struct ath5k_txq_info *tq = &ah->ah_txq[queue];
- /*
- * Set contention window (cw_min/cw_max)
- * and arbitrated interframe space (aifs)...
- */
- ath5k_hw_reg_write(ah,
- AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
- AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
- AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
- AR5K_QUEUE_DFS_LOCAL_IFS(queue));
-
- /*
- * Set misc registers
- */
- /* Enable DCU early termination for this queue */
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_DCU_EARLY);
+ AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+ tq = &ah->ah_txq[queue];
+
+ /* Skip if queue inactive or if we are on AR5210
+ * that doesn't have QCU/DCU */
+ if ((ah->ah_version == AR5K_AR5210) ||
+ (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
+ return 0;
+
+ /*
+ * Set contention window (cw_min/cw_max)
+ * and arbitrated interframe space (aifs)...
+ */
+ ath5k_hw_reg_write(ah,
+ AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+ AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+ AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
+ AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+ /*
+ * Set tx retry limits for this queue
+ */
+ ath5k_hw_set_tx_retry_limits(ah, queue);
+
+
+ /*
+ * Set misc registers
+ */
+
+ /* Enable DCU to wait for next fragment from QCU */
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+ AR5K_DCU_MISC_FRAG_WAIT);
- /* Enable DCU to wait for next fragment from QCU */
+ /* On Maui and Spirit use the global seqnum on DCU */
+ if (ah->ah_mac_version < AR5K_SREV_AR5211)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
- AR5K_DCU_MISC_FRAG_WAIT);
-
- /* On Maui and Spirit use the global seqnum on DCU */
- if (ah->ah_mac_version < AR5K_SREV_AR5211)
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
- AR5K_DCU_MISC_SEQNUM_CTL);
-
- if (tq->tqi_cbr_period) {
- ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
- AR5K_QCU_CBRCFG_INTVAL) |
- AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
- AR5K_QCU_CBRCFG_ORN_THRES),
- AR5K_QUEUE_CBRCFG(queue));
+ AR5K_DCU_MISC_SEQNUM_CTL);
+
+ /* Constant bit rate period */
+ if (tq->tqi_cbr_period) {
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+ AR5K_QCU_CBRCFG_INTVAL) |
+ AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+ AR5K_QCU_CBRCFG_ORN_THRES),
+ AR5K_QUEUE_CBRCFG(queue));
+
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ AR5K_QCU_MISC_FRSHED_CBR);
+
+ if (tq->tqi_cbr_overflow_limit)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_FRSHED_CBR);
- if (tq->tqi_cbr_overflow_limit)
- AR5K_REG_ENABLE_BITS(ah,
- AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_CBR_THRES_ENABLE);
- }
+ }
- if (tq->tqi_ready_time &&
- (tq->tqi_type != AR5K_TX_QUEUE_CAB))
- ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
- AR5K_QCU_RDYTIMECFG_INTVAL) |
- AR5K_QCU_RDYTIMECFG_ENABLE,
- AR5K_QUEUE_RDYTIMECFG(queue));
-
- if (tq->tqi_burst_time) {
- ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
- AR5K_DCU_CHAN_TIME_DUR) |
- AR5K_DCU_CHAN_TIME_ENABLE,
- AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
-
- if (tq->tqi_flags
- & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
- AR5K_REG_ENABLE_BITS(ah,
- AR5K_QUEUE_MISC(queue),
+ /* Ready time interval */
+ if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+ AR5K_QCU_RDYTIMECFG_INTVAL) |
+ AR5K_QCU_RDYTIMECFG_ENABLE,
+ AR5K_QUEUE_RDYTIMECFG(queue));
+
+ if (tq->tqi_burst_time) {
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+ AR5K_DCU_CHAN_TIME_DUR) |
+ AR5K_DCU_CHAN_TIME_ENABLE,
+ AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_RDY_VEOL_POLICY);
- }
+ }
- if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
- ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
- AR5K_QUEUE_DFS_MISC(queue));
+ /* Enable/disable Post frame backoff */
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+ ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+ AR5K_QUEUE_DFS_MISC(queue));
- if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
- ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
- AR5K_QUEUE_DFS_MISC(queue));
+ /* Enable/disable fragmentation burst backoff */
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+ ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+ AR5K_QUEUE_DFS_MISC(queue));
- /*
- * Set registers by queue type
- */
- switch (tq->tqi_type) {
- case AR5K_TX_QUEUE_BEACON:
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ /*
+ * Set registers by queue type
+ */
+ switch (tq->tqi_type) {
+ case AR5K_TX_QUEUE_BEACON:
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_FRSHED_DBA_GT |
AR5K_QCU_MISC_CBREXP_BCN_DIS |
AR5K_QCU_MISC_BCN_ENABLE);
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
AR5K_DCU_MISC_ARBLOCK_CTL_S) |
AR5K_DCU_MISC_ARBLOCK_IGNORE |
AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
AR5K_DCU_MISC_BCN_ENABLE);
- break;
+ break;
- case AR5K_TX_QUEUE_CAB:
- /* XXX: use BCN_SENT_GT, if we can figure out how */
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_FRSHED_DBA_GT |
- AR5K_QCU_MISC_CBREXP_DIS |
- AR5K_QCU_MISC_CBREXP_BCN_DIS);
+ case AR5K_TX_QUEUE_CAB:
+ /* XXX: use BCN_SENT_GT, if we can figure out how */
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ AR5K_QCU_MISC_FRSHED_DBA_GT |
+ AR5K_QCU_MISC_CBREXP_DIS |
+ AR5K_QCU_MISC_CBREXP_BCN_DIS);
- ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
- (AR5K_TUNE_SW_BEACON_RESP -
- AR5K_TUNE_DMA_BEACON_RESP) -
+ ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
+ (AR5K_TUNE_SW_BEACON_RESP -
+ AR5K_TUNE_DMA_BEACON_RESP) -
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
- AR5K_QCU_RDYTIMECFG_ENABLE,
- AR5K_QUEUE_RDYTIMECFG(queue));
+ AR5K_QCU_RDYTIMECFG_ENABLE,
+ AR5K_QUEUE_RDYTIMECFG(queue));
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
- (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
- AR5K_DCU_MISC_ARBLOCK_CTL_S));
- break;
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+ (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+ AR5K_DCU_MISC_ARBLOCK_CTL_S));
+ break;
- case AR5K_TX_QUEUE_UAPSD:
- AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_CBREXP_DIS);
- break;
+ case AR5K_TX_QUEUE_UAPSD:
+ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+ AR5K_QCU_MISC_CBREXP_DIS);
+ break;
- case AR5K_TX_QUEUE_DATA:
- default:
+ case AR5K_TX_QUEUE_DATA:
+ default:
break;
- }
-
- /* TODO: Handle frame compression */
-
- /*
- * Enable interrupts for this tx queue
- * in the secondary interrupt mask registers
- */
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
-
- if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
- AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
-
- /* Update secondary interrupt mask registers */
-
- /* Filter out inactive queues */
- ah->ah_txq_imr_txok &= ah->ah_txq_status;
- ah->ah_txq_imr_txerr &= ah->ah_txq_status;
- ah->ah_txq_imr_txurn &= ah->ah_txq_status;
- ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
- ah->ah_txq_imr_txeol &= ah->ah_txq_status;
- ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
- ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
- ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
- ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
-
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
- AR5K_SIMR0_QCU_TXOK) |
- AR5K_REG_SM(ah->ah_txq_imr_txdesc,
- AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
- AR5K_SIMR1_QCU_TXERR) |
- AR5K_REG_SM(ah->ah_txq_imr_txeol,
- AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
- /* Update simr2 but don't overwrite rest simr2 settings */
- AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
- AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
- AR5K_REG_SM(ah->ah_txq_imr_txurn,
- AR5K_SIMR2_QCU_TXURN));
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
- AR5K_SIMR3_QCBRORN) |
- AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
- AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
- AR5K_SIMR4_QTRIG), AR5K_SIMR4);
- /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
- AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
- /* No queue has TXNOFRM enabled, disable the interrupt
- * by setting AR5K_TXNOFRM to zero */
- if (ah->ah_txq_imr_nofrm == 0)
- ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
-
- /* Set QCU mask for this DCU to save power */
- AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
}
+ /* TODO: Handle frame compression */
+
+ /*
+ * Enable interrupts for this tx queue
+ * in the secondary interrupt mask registers
+ */
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
+
+ /* Update secondary interrupt mask registers */
+
+ /* Filter out inactive queues */
+ ah->ah_txq_imr_txok &= ah->ah_txq_status;
+ ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+ ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+ ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+ ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+ ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
+ ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
+ ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
+ ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
+
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+ AR5K_SIMR0_QCU_TXOK) |
+ AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+ AR5K_SIMR0_QCU_TXDESC),
+ AR5K_SIMR0);
+
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+ AR5K_SIMR1_QCU_TXERR) |
+ AR5K_REG_SM(ah->ah_txq_imr_txeol,
+ AR5K_SIMR1_QCU_TXEOL),
+ AR5K_SIMR1);
+
+ /* Update SIMR2 but don't overwrite rest simr2 settings */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
+ AR5K_REG_SM(ah->ah_txq_imr_txurn,
+ AR5K_SIMR2_QCU_TXURN));
+
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
+ AR5K_SIMR3_QCBRORN) |
+ AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
+ AR5K_SIMR3_QCBRURN),
+ AR5K_SIMR3);
+
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
+ AR5K_SIMR4_QTRIG), AR5K_SIMR4);
+
+ /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
+ AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
+
+ /* No queue has TXNOFRM enabled, disable the interrupt
+ * by setting AR5K_TXNOFRM to zero */
+ if (ah->ah_txq_imr_nofrm == 0)
+ ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
+
+ /* Set QCU mask for this DCU to save power */
+ AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
+
return 0;
}
-/*
- * Set slot time on DCU
+
+/**************************\
+* Global QCU/DCU functions *
+\**************************/
+
+/**
+ * ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU
+ *
+ * @ah The &struct ath5k_hw
+ * @slot_time Slot time in us
+ *
+ * Sets the global IFS intervals on DCU (also works on AR5210) for
+ * the given slot time and the current bwmode.
*/
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+ struct ath5k_softc *sc = ah->ah_sc;
+ struct ieee80211_rate *rate;
+ u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
return -EINVAL;
- if (ah->ah_version == AR5K_AR5210)
- ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
+ sifs = ath5k_hw_get_default_sifs(ah);
+ sifs_clock = ath5k_hw_htoclock(ah, sifs);
+
+ /* EIFS
+ * Txtime of ack at lowest rate + SIFS + DIFS
+ * (DIFS = SIFS + 2 * Slot time)
+ *
+ * Note: HAL has some predefined values for EIFS
+ * Turbo: (37 + 2 * 6)
+ * Default: (74 + 2 * 9)
+ * Half: (149 + 2 * 13)
+ * Quarter: (298 + 2 * 21)
+ *
+ * (74 + 2 * 6) for AR5210 default and turbo !
+ *
+ * According to the formula we have
+ * ack_tx_time = 25 for turbo and
+ * ack_tx_time = 42.5 * clock multiplier
+ * for default/half/quarter.
+ *
+ * This can't be right, 42 is what we would get
+ * from ath5k_hw_get_frame_dur_for_bwmode or
+ * ieee80211_generic_frame_duration for zero frame
+ * length and without SIFS !
+ *
+ * Also we have different lowest rate for 802.11a
+ */
+ if (channel->hw_value & CHANNEL_5GHZ)
+ rate = &sc->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
else
- ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
+ rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
+
+ ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+
+ /* ack_tx_time includes an SIFS already */
+ eifs = ack_tx_time + sifs + 2 * slot_time;
+ eifs_clock = ath5k_hw_htoclock(ah, eifs);
+
+ /* Set IFS settings on AR5210 */
+ if (ah->ah_version == AR5K_AR5210) {
+ u32 pifs, pifs_clock, difs, difs_clock;
+
+ /* Set slot time */
+ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
+
+ /* Set EIFS */
+ eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
+
+ /* PIFS = Slot time + SIFS */
+ pifs = slot_time + sifs;
+ pifs_clock = ath5k_hw_htoclock(ah, pifs);
+ pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
+
+ /* DIFS = SIFS + 2 * Slot time */
+ difs = sifs + 2 * slot_time;
+ difs_clock = ath5k_hw_htoclock(ah, difs);
+
+ /* Set SIFS/DIFS */
+ ath5k_hw_reg_write(ah, (difs_clock <<
+ AR5K_IFS0_DIFS_S) | sifs_clock,
+ AR5K_IFS0);
+
+ /* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
+ ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
+ (AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
+ AR5K_IFS1);
+
+ return 0;
+ }
+
+ /* Set IFS slot time */
+ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
+
+ /* Set EIFS interval */
+ ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
+
+ /* Set SIFS interval in usecs */
+ AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+ AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
+ sifs);
+
+ /* Set SIFS interval in clock cycles */
+ ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
return 0;
}
+
+int ath5k_hw_init_queues(struct ath5k_hw *ah)
+{
+ int i, ret;
+
+ /* TODO: HW Compression support for data queues */
+ /* TODO: Burst prefetch for data queues */
+
+ /*
+ * Reset queues and start beacon timers at the end of the reset routine
+ * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+ * Note: If we want we can assign multiple qcus on one dcu.
+ */
+ if (ah->ah_version != AR5K_AR5210)
+ for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
+ ret = ath5k_hw_reset_tx_queue(ah, i);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc,
+ "failed to reset TX queue #%d\n", i);
+ return ret;
+ }
+ }
+ else
+ /* No QCU/DCU on AR5210, just set tx
+ * retry limits. We set IFS parameters
+ * on ath5k_hw_set_ifs_intervals */
+ ath5k_hw_set_tx_retry_limits(ah, 0);
+
+ /* Set the turbo flag when operating on 40MHz */
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+ AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+ AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
+
+ /* If we didn't set IFS timings through
+ * ath5k_hw_set_coverage_class make sure
+ * we set them here */
+ if (!ah->ah_coverage_class) {
+ unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
+ ath5k_hw_set_ifs_intervals(ah, slot_time);
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index ca79ecd832fd..fd14b9103951 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -787,6 +787,7 @@
#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */
#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */
#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC_S 4
#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */
#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S 10
#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */
@@ -1063,7 +1064,7 @@
/*
* EEPROM command register
*/
-#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */
+#define AR5K_EEPROM_CMD 0x6008 /* Register Address */
#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */
#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */
#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */
@@ -1083,7 +1084,7 @@
/*
* EEPROM config register
*/
-#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */
+#define AR5K_EEPROM_CFG 0x6010 /* Register Address */
#define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */
#define AR5K_EEPROM_CFG_SIZE_AUTO 0
#define AR5K_EEPROM_CFG_SIZE_4KBIT 1
@@ -1125,7 +1126,7 @@
* Second station id register (Upper 16 bits of MAC address + PCU settings)
*/
#define AR5K_STA_ID1 0x8004 /* Register Address */
-#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */
+#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC address */
#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */
#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */
#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */
@@ -1311,7 +1312,7 @@
#define AR5K_IFS1_EIFS 0x03fff000
#define AR5K_IFS1_EIFS_S 12
#define AR5K_IFS1_CS_EN 0x04000000
-
+#define AR5K_IFS1_CS_EN_S 26
/*
* CFP duration register
@@ -2058,6 +2059,7 @@
#define AR5K_PHY_SCAL 0x9878
#define AR5K_PHY_SCAL_32MHZ 0x0000000e
+#define AR5K_PHY_SCAL_32MHZ_5311 0x00000008
#define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a
#define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032
@@ -2244,6 +2246,8 @@
#define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \
AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
/*---[5111+]---*/
+#define AR5K_PHY_FRAME_CTL_WIN_LEN 0x00000003 /* Force window length (?) */
+#define AR5K_PHY_FRAME_CTL_WIN_LEN_S 0
#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */
#define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3
#define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */
@@ -2558,3 +2562,28 @@
*/
#define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280
#define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * Platform registers for WiSoC
+ */
+#define AR5K_AR5312_RESET 0xbc003020
+#define AR5K_AR5312_RESET_BB0_COLD 0x00000004
+#define AR5K_AR5312_RESET_BB1_COLD 0x00000200
+#define AR5K_AR5312_RESET_WMAC0 0x00002000
+#define AR5K_AR5312_RESET_BB0_WARM 0x00004000
+#define AR5K_AR5312_RESET_WMAC1 0x00020000
+#define AR5K_AR5312_RESET_BB1_WARM 0x00040000
+
+#define AR5K_AR5312_ENABLE 0xbc003080
+#define AR5K_AR5312_ENABLE_WLAN0 0x00000001
+#define AR5K_AR5312_ENABLE_WLAN1 0x00000008
+
+#define AR5K_AR2315_RESET 0xb1000004
+#define AR5K_AR2315_RESET_WMAC 0x00000001
+#define AR5K_AR2315_RESET_BB_WARM 0x00000002
+
+#define AR5K_AR2315_AHB_ARB_CTL 0xb1000008
+#define AR5K_AR2315_AHB_ARB_CTL_WLAN 0x00000002
+
+#define AR5K_AR2315_BYTESWAP 0xb100000c
+#define AR5K_AR2315_BYTESWAP_WMAC 0x00000002
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 5b179d01f97d..84206898f77d 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -27,11 +27,17 @@
#include <linux/pci.h> /* To determine if a card is pci-e */
#include <linux/log2.h>
+#include <linux/platform_device.h>
#include "ath5k.h"
#include "reg.h"
#include "base.h"
#include "debug.h"
+
+/******************\
+* Helper functions *
+\******************/
+
/*
* Check if a register write has been completed
*/
@@ -53,146 +59,267 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
return (i <= 0) ? -EAGAIN : 0;
}
+
+/*************************\
+* Clock related functions *
+\*************************/
+
/**
- * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ * ath5k_hw_htoclock - Translate usec to hw clock units
*
- * @ah: the &struct ath5k_hw
- * @channel: the currently set channel upon reset
- *
- * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
- * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
+ * @ah: The &struct ath5k_hw
+ * @usec: value in microseconds
+ */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
+{
+ struct ath_common *common = ath5k_hw_common(ah);
+ return usec * common->clockrate;
+}
+
+/**
+ * ath5k_hw_clocktoh - Translate hw clock units to usec
+ * @clock: value in hw clock units
+ */
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
+{
+ struct ath_common *common = ath5k_hw_common(ah);
+ return clock / common->clockrate;
+}
+
+/**
+ * ath5k_hw_init_core_clock - Initialize core clock
*
- * Since delta slope is floating point we split it on its exponent and
- * mantissa and provide these values on hw.
+ * @ah The &struct ath5k_hw
*
- * For more infos i think this patent is related
- * http://www.freepatentsonline.com/7184495.html
+ * Initialize core clock parameters (usec, usec32, latencies etc).
*/
-static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
- struct ieee80211_channel *channel)
+static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
{
- /* Get exponent and mantissa and set it */
- u32 coef_scaled, coef_exp, coef_man,
- ds_coef_exp, ds_coef_man, clock;
-
- BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
- !(channel->hw_value & CHANNEL_OFDM));
-
- /* Get coefficient
- * ALGO: coef = (5 * clock / carrier_freq) / 2
- * we scale coef by shifting clock value by 24 for
- * better precision since we use integers */
- /* TODO: Half/quarter rate */
- clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
- coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
-
- /* Get exponent
- * ALGO: coef_exp = 14 - highest set bit position */
- coef_exp = ilog2(coef_scaled);
-
- /* Doesn't make sense if it's zero*/
- if (!coef_scaled || !coef_exp)
- return -EINVAL;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+ struct ath_common *common = ath5k_hw_common(ah);
+ u32 usec_reg, txlat, rxlat, usec, clock, sclock, txf2txs;
+
+ /*
+ * Set core clock frequency
+ */
+ if (channel->hw_value & CHANNEL_5GHZ)
+ clock = 40; /* 802.11a */
+ else if (channel->hw_value & CHANNEL_CCK)
+ clock = 22; /* 802.11b */
+ else
+ clock = 44; /* 802.11g */
+
+ /* Use clock multiplier for non-default
+ * bwmode */
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_40MHZ:
+ clock *= 2;
+ break;
+ case AR5K_BWMODE_10MHZ:
+ clock /= 2;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ clock /= 4;
+ break;
+ default:
+ break;
+ }
- /* Note: we've shifted coef_scaled by 24 */
- coef_exp = 14 - (coef_exp - 24);
+ common->clockrate = clock;
+ /*
+ * Set USEC parameters
+ */
+ /* Set USEC counter on PCU*/
+ usec = clock - 1;
+ usec = AR5K_REG_SM(usec, AR5K_USEC_1);
- /* Get mantissa (significant digits)
- * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
- coef_man = coef_scaled +
- (1 << (24 - coef_exp - 1));
+ /* Set usec duration on DCU */
+ if (ah->ah_version != AR5K_AR5210)
+ AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+ AR5K_DCU_GBL_IFS_MISC_USEC_DUR,
+ clock);
- /* Calculate delta slope coefficient exponent
- * and mantissa (remove scaling) and set them on hw */
- ds_coef_man = coef_man >> (24 - coef_exp);
- ds_coef_exp = coef_exp - 16;
+ /* Set 32MHz USEC counter */
+ if ((ah->ah_radio == AR5K_RF5112) ||
+ (ah->ah_radio == AR5K_RF5413) ||
+ (ah->ah_radio == AR5K_RF2316) ||
+ (ah->ah_radio == AR5K_RF2317))
+ /* Remain on 40MHz clock ? */
+ sclock = 40 - 1;
+ else
+ sclock = 32 - 1;
+ sclock = AR5K_REG_SM(sclock, AR5K_USEC_32);
- AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
- AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
- AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
- AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+ /*
+ * Set tx/rx latencies
+ */
+ usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+ txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211);
+ rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
- return 0;
-}
+ /*
+ * 5210 initvals don't include usec settings
+ * so we need to use magic values here for
+ * tx/rx latencies
+ */
+ if (ah->ah_version == AR5K_AR5210) {
+ /* same for turbo */
+ txlat = AR5K_INIT_TX_LATENCY_5210;
+ rxlat = AR5K_INIT_RX_LATENCY_5210;
+ }
+ if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+ /* 5311 has different tx/rx latency masks
+ * from 5211, since we deal 5311 the same
+ * as 5211 when setting initvals, shift
+ * values here to their proper locations
+ *
+ * Note: Initvals indicate tx/rx/ latencies
+ * are the same for turbo mode */
+ txlat = AR5K_REG_SM(txlat, AR5K_USEC_TX_LATENCY_5210);
+ rxlat = AR5K_REG_SM(rxlat, AR5K_USEC_RX_LATENCY_5210);
+ } else
+ switch (ah->ah_bwmode) {
+ case AR5K_BWMODE_10MHZ:
+ txlat = AR5K_REG_SM(txlat * 2,
+ AR5K_USEC_TX_LATENCY_5211);
+ rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
+ AR5K_USEC_RX_LATENCY_5211);
+ txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_10MHZ;
+ break;
+ case AR5K_BWMODE_5MHZ:
+ txlat = AR5K_REG_SM(txlat * 4,
+ AR5K_USEC_TX_LATENCY_5211);
+ rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
+ AR5K_USEC_RX_LATENCY_5211);
+ txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_5MHZ;
+ break;
+ case AR5K_BWMODE_40MHZ:
+ txlat = AR5K_INIT_TX_LAT_MIN;
+ rxlat = AR5K_REG_SM(rxlat / 2,
+ AR5K_USEC_RX_LATENCY_5211);
+ txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
+ break;
+ default:
+ break;
+ }
-/*
- * index into rates for control rates, we can set it up like this because
- * this is only used for AR5212 and we know it supports G mode
- */
-static const unsigned int control_rates[] =
- { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
+ usec_reg = (usec | sclock | txlat | rxlat);
+ ath5k_hw_reg_write(ah, usec_reg, AR5K_USEC);
-/**
- * ath5k_hw_write_rate_duration - fill rate code to duration table
- *
- * @ah: the &struct ath5k_hw
- * @mode: one of enum ath5k_driver_mode
- *
- * Write the rate code to duration table upon hw reset. This is a helper for
- * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
- * the hardware, based on current mode, for each rate. The rates which are
- * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
- * different rate code so we write their value twice (one for long preample
- * and one for short).
+ /* On 5112 set tx frane to tx data start delay */
+ if (ah->ah_radio == AR5K_RF5112) {
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL2,
+ AR5K_PHY_RF_CTL2_TXF2TXD_START,
+ txf2txs);
+ }
+}
+
+/*
+ * If there is an external 32KHz crystal available, use it
+ * as ref. clock instead of 32/40MHz clock and baseband clocks
+ * to save power during sleep or restore normal 32/40MHz
+ * operation.
*
- * Note: Band doesn't matter here, if we set the values for OFDM it works
- * on both a and g modes. So all we have to do is set values for all g rates
- * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
- * quarter rate mode, we need to use another set of bitrates (that's why we
- * need the mode parameter) but we don't handle these proprietary modes yet.
+ * XXX: When operating on 32KHz certain PHY registers (27 - 31,
+ * 123 - 127) require delay on access.
*/
-static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
- unsigned int mode)
+static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
{
- struct ath5k_softc *sc = ah->ah_sc;
- struct ieee80211_rate *rate;
- unsigned int i;
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ u32 scal, spending;
+
+ /* Only set 32KHz settings if we have an external
+ * 32KHz crystal present */
+ if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
+ AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
+ enable) {
- /* Write rate duration table */
- for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) {
- u32 reg;
- u16 tx_time;
+ /* 1 usec/cycle */
+ AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
+ /* Set up tsf increment on each cycle */
+ AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
- rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]];
+ /* Set baseband sleep control registers
+ * and sleep control rate */
+ ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+
+ if ((ah->ah_radio == AR5K_RF5112) ||
+ (ah->ah_radio == AR5K_RF5413) ||
+ (ah->ah_radio == AR5K_RF2316) ||
+ (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+ spending = 0x14;
+ else
+ spending = 0x18;
+ ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
- /* Set ACK timeout */
- reg = AR5K_RATE_DUR(rate->hw_value);
+ if ((ah->ah_radio == AR5K_RF5112) ||
+ (ah->ah_radio == AR5K_RF5413) ||
+ (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+ ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
+ ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
+ ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
+ ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+ AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
+ } else {
+ ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
+ ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
+ ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
+ ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+ AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
+ }
- /* An ACK frame consists of 10 bytes. If you add the FCS,
- * which ieee80211_generic_frame_duration() adds,
- * its 14 bytes. Note we use the control rate and not the
- * actual rate for this rate. See mac80211 tx.c
- * ieee80211_duration() for a brief description of
- * what rate we should choose to TX ACKs. */
- tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
- NULL, 10, rate));
+ /* Enable sleep clock operation */
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
+ AR5K_PCICFG_SLEEP_CLOCK_EN);
- ath5k_hw_reg_write(ah, tx_time, reg);
+ } else {
- if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
- continue;
+ /* Disable sleep clock operation and
+ * restore default parameters */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+ AR5K_PCICFG_SLEEP_CLOCK_EN);
- /*
- * We're not distinguishing short preamble here,
- * This is true, all we'll get is a longer value here
- * which is not necessarilly bad. We could use
- * export ieee80211_frame_duration() but that needs to be
- * fixed first to be properly used by mac802111 drivers:
- *
- * - remove erp stuff and let the routine figure ofdm
- * erp rates
- * - remove passing argument ieee80211_local as
- * drivers don't have access to it
- * - move drivers using ieee80211_generic_frame_duration()
- * to this
- */
- ath5k_hw_reg_write(ah, tx_time,
- reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+ AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+ AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
+
+ /* Set DAC/ADC delays */
+ ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+ ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+
+ if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+ scal = AR5K_PHY_SCAL_32MHZ_2417;
+ else if (ee->ee_is_hb63)
+ scal = AR5K_PHY_SCAL_32MHZ_HB63;
+ else
+ scal = AR5K_PHY_SCAL_32MHZ;
+ ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+
+ ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+ ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+
+ if ((ah->ah_radio == AR5K_RF5112) ||
+ (ah->ah_radio == AR5K_RF5413) ||
+ (ah->ah_radio == AR5K_RF2316) ||
+ (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+ spending = 0x14;
+ else
+ spending = 0x18;
+ ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+ /* Set up tsf increment on each cycle */
+ AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
}
}
+
+/*********************\
+* Reset/Sleep control *
+\*********************/
+
/*
* Reset chipset
*/
@@ -236,6 +363,64 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
}
/*
+ * Reset AHB chipset
+ * AR5K_RESET_CTL_PCU flag resets WMAC
+ * AR5K_RESET_CTL_BASEBAND flag resets WBB
+ */
+static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
+{
+ u32 mask = flags ? flags : ~0U;
+ volatile u32 *reg;
+ u32 regval;
+ u32 val = 0;
+
+ /* ah->ah_mac_srev is not available at this point yet */
+ if (ah->ah_sc->devid >= AR5K_SREV_AR2315_R6) {
+ reg = (u32 *) AR5K_AR2315_RESET;
+ if (mask & AR5K_RESET_CTL_PCU)
+ val |= AR5K_AR2315_RESET_WMAC;
+ if (mask & AR5K_RESET_CTL_BASEBAND)
+ val |= AR5K_AR2315_RESET_BB_WARM;
+ } else {
+ reg = (u32 *) AR5K_AR5312_RESET;
+ if (to_platform_device(ah->ah_sc->dev)->id == 0) {
+ if (mask & AR5K_RESET_CTL_PCU)
+ val |= AR5K_AR5312_RESET_WMAC0;
+ if (mask & AR5K_RESET_CTL_BASEBAND)
+ val |= AR5K_AR5312_RESET_BB0_COLD |
+ AR5K_AR5312_RESET_BB0_WARM;
+ } else {
+ if (mask & AR5K_RESET_CTL_PCU)
+ val |= AR5K_AR5312_RESET_WMAC1;
+ if (mask & AR5K_RESET_CTL_BASEBAND)
+ val |= AR5K_AR5312_RESET_BB1_COLD |
+ AR5K_AR5312_RESET_BB1_WARM;
+ }
+ }
+
+ /* Put BB/MAC into reset */
+ regval = __raw_readl(reg);
+ __raw_writel(regval | val, reg);
+ regval = __raw_readl(reg);
+ udelay(100);
+
+ /* Bring BB/MAC out of reset */
+ __raw_writel(regval & ~val, reg);
+ regval = __raw_readl(reg);
+
+ /*
+ * Reset configuration register (for hw byte-swap). Note that this
+ * is only set for big endian. We do the necessary magic in
+ * AR5K_INIT_CFG.
+ */
+ if ((flags & AR5K_RESET_CTL_PCU) == 0)
+ ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+ return 0;
+}
+
+
+/*
* Sleep control
*/
static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
@@ -334,6 +519,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
u32 bus_flags;
int ret;
+ if (ath5k_get_bus_type(ah) == ATH_AHB)
+ return 0;
+
/* Make sure device is awake */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
if (ret) {
@@ -349,7 +537,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
*/
- bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+ bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
if (ah->ah_version == AR5K_AR5210) {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@@ -378,7 +566,6 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
/*
* Bring up MAC + PHY Chips and program PLL
- * TODO: Half/Quarter rate support
*/
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
{
@@ -390,11 +577,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode = 0;
clock = 0;
- /* Wakeup the device */
- ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
- if (ret) {
- ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
- return ret;
+ if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) {
+ /* Wakeup the device */
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+ return ret;
+ }
}
/*
@@ -405,7 +594,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
*/
- bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+ bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
if (ah->ah_version == AR5K_AR5210) {
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@@ -413,8 +602,12 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
mdelay(2);
} else {
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
- AR5K_RESET_CTL_BASEBAND | bus_flags);
+ if (ath5k_get_bus_type(ah) == ATH_AHB)
+ ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND);
+ else
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
}
if (ret) {
@@ -429,9 +622,15 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
return ret;
}
- /* ...clear reset control register and pull device out of
- * warm reset */
- if (ath5k_hw_nic_reset(ah, 0)) {
+ /* ...reset configuration regiter on Wisoc ...
+ * ...clear reset control register and pull device out of
+ * warm reset on others */
+ if (ath5k_get_bus_type(ah) == ATH_AHB)
+ ret = ath5k_hw_wisoc_reset(ah, 0);
+ else
+ ret = ath5k_hw_nic_reset(ah, 0);
+
+ if (ret) {
ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
return -EIO;
}
@@ -466,7 +665,8 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
* CCK headers) operation. We need to test
* this, 5211 might support ofdm-only g after
* all, there are also initial register values
- * in the code for g mode (see initvals.c). */
+ * in the code for g mode (see initvals.c).
+ */
if (ah->ah_version == AR5K_AR5211)
mode |= AR5K_PHY_MODE_MOD_OFDM;
else
@@ -479,6 +679,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
} else if (flags & CHANNEL_5GHZ) {
mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+ /* Different PLL setting for 5413 */
if (ah->ah_radio == AR5K_RF5413)
clock = AR5K_PHY_PLL_40MHZ_5413;
else
@@ -496,12 +697,29 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
return -EINVAL;
}
- if (flags & CHANNEL_TURBO)
- turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+ /*XXX: Can bwmode be used with dynamic mode ?
+ * (I don't think it supports 44MHz) */
+ /* On 2425 initvals TURBO_SHORT is not pressent */
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
+ turbo = AR5K_PHY_TURBO_MODE |
+ (ah->ah_radio == AR5K_RF2425) ? 0 :
+ AR5K_PHY_TURBO_SHORT;
+ } else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) {
+ if (ah->ah_radio == AR5K_RF5413) {
+ mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
+ AR5K_PHY_MODE_HALF_RATE :
+ AR5K_PHY_MODE_QUARTER_RATE;
+ } else if (ah->ah_version == AR5K_AR5212) {
+ clock |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
+ AR5K_PHY_PLL_HALF_RATE :
+ AR5K_PHY_PLL_QUARTER_RATE;
+ }
+ }
+
} else { /* Reset the device */
/* ...enable Atheros turbo mode if requested */
- if (flags & CHANNEL_TURBO)
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
AR5K_PHY_TURBO);
}
@@ -522,107 +740,10 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
return 0;
}
-/*
- * If there is an external 32KHz crystal available, use it
- * as ref. clock instead of 32/40MHz clock and baseband clocks
- * to save power during sleep or restore normal 32/40MHz
- * operation.
- *
- * XXX: When operating on 32KHz certain PHY registers (27 - 31,
- * 123 - 127) require delay on access.
- */
-static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
-{
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- u32 scal, spending, usec32;
- /* Only set 32KHz settings if we have an external
- * 32KHz crystal present */
- if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
- AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
- enable) {
-
- /* 1 usec/cycle */
- AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
- /* Set up tsf increment on each cycle */
- AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
-
- /* Set baseband sleep control registers
- * and sleep control rate */
- ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
-
- if ((ah->ah_radio == AR5K_RF5112) ||
- (ah->ah_radio == AR5K_RF5413) ||
- (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
- spending = 0x14;
- else
- spending = 0x18;
- ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
-
- if ((ah->ah_radio == AR5K_RF5112) ||
- (ah->ah_radio == AR5K_RF5413) ||
- (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
- ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
- ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
- ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
- ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
- AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
- AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
- } else {
- ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
- ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
- ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
- ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
- AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
- AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
- }
-
- /* Enable sleep clock operation */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
- AR5K_PCICFG_SLEEP_CLOCK_EN);
-
- } else {
-
- /* Disable sleep clock operation and
- * restore default parameters */
- AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
- AR5K_PCICFG_SLEEP_CLOCK_EN);
-
- AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
- AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
-
- ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
- ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
-
- if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
- scal = AR5K_PHY_SCAL_32MHZ_2417;
- else if (ee->ee_is_hb63)
- scal = AR5K_PHY_SCAL_32MHZ_HB63;
- else
- scal = AR5K_PHY_SCAL_32MHZ;
- ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
-
- ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
- ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
-
- if ((ah->ah_radio == AR5K_RF5112) ||
- (ah->ah_radio == AR5K_RF5413) ||
- (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
- spending = 0x14;
- else
- spending = 0x18;
- ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
-
- if ((ah->ah_radio == AR5K_RF5112) ||
- (ah->ah_radio == AR5K_RF5413))
- usec32 = 39;
- else
- usec32 = 31;
- AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32);
-
- AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
- }
-}
+/**************************************\
+* Post-initvals register modifications *
+\**************************************/
/* TODO: Half/Quarter rate */
static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
@@ -663,22 +784,10 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
AR5K_TXCFG_DCU_DBL_BUF_DIS);
- /* Set DAC/ADC delays */
- if (ah->ah_version == AR5K_AR5212) {
- u32 scal;
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
- scal = AR5K_PHY_SCAL_32MHZ_2417;
- else if (ee->ee_is_hb63)
- scal = AR5K_PHY_SCAL_32MHZ_HB63;
- else
- scal = AR5K_PHY_SCAL_32MHZ;
- ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
- }
-
/* Set fast ADC */
if ((ah->ah_radio == AR5K_RF5413) ||
- (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+ (ah->ah_radio == AR5K_RF2317) ||
+ (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
u32 fast_adc = true;
if (channel->center_freq == 2462 ||
@@ -706,33 +815,68 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
}
if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
- u32 usec_reg;
- /* 5311 has different tx/rx latency masks
- * from 5211, since we deal 5311 the same
- * as 5211 when setting initvals, shift
- * values here to their proper locations */
- usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
- ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
- AR5K_USEC_32 |
- AR5K_USEC_TX_LATENCY_5211 |
- AR5K_REG_SM(29,
- AR5K_USEC_RX_LATENCY_5210)),
- AR5K_USEC_5211);
/* Clear QCU/DCU clock gating register */
ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
/* Set DAC/ADC delays */
- ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+ ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ_5311,
+ AR5K_PHY_SCAL);
/* Enable PCU FIFO corruption ECO */
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
AR5K_DIAG_SW_ECO_ENABLE);
}
+
+ if (ah->ah_bwmode) {
+ /* Increase PHY switch and AGC settling time
+ * on turbo mode (ath5k_hw_commit_eeprom_settings
+ * will override settling time if available) */
+ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
+
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+ AR5K_PHY_SETTLING_AGC,
+ AR5K_AGC_SETTLING_TURBO);
+
+ /* XXX: Initvals indicate we only increase
+ * switch time on AR5212, 5211 and 5210
+ * only change agc time (bug?) */
+ if (ah->ah_version == AR5K_AR5212)
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+ AR5K_PHY_SETTLING_SWITCH,
+ AR5K_SWITCH_SETTLING_TURBO);
+
+ if (ah->ah_version == AR5K_AR5210) {
+ /* Set Frame Control Register */
+ ath5k_hw_reg_write(ah,
+ (AR5K_PHY_FRAME_CTL_INI |
+ AR5K_PHY_TURBO_MODE |
+ AR5K_PHY_TURBO_SHORT | 0x2020),
+ AR5K_PHY_FRAME_CTL_5210);
+ }
+ /* On 5413 PHY force window length for half/quarter rate*/
+ } else if ((ah->ah_mac_srev >= AR5K_SREV_AR5424) &&
+ (ah->ah_mac_srev <= AR5K_SREV_AR5414)) {
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL_5211,
+ AR5K_PHY_FRAME_CTL_WIN_LEN,
+ 3);
+ }
+ } else if (ah->ah_version == AR5K_AR5210) {
+ /* Set Frame Control Register for normal operation */
+ ath5k_hw_reg_write(ah, (AR5K_PHY_FRAME_CTL_INI | 0x1020),
+ AR5K_PHY_FRAME_CTL_5210);
+ }
}
static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
- struct ieee80211_channel *channel, u8 ee_mode)
+ struct ieee80211_channel *channel)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
s16 cck_ofdm_pwr_delta;
+ u8 ee_mode;
+
+ /* TODO: Add support for AR5210 EEPROM */
+ if (ah->ah_version == AR5K_AR5210)
+ return;
+
+ ee_mode = ath5k_eeprom_mode_from_channel(channel);
/* Adjust power delta for channel 14 */
if (channel->center_freq == 2484)
@@ -772,7 +916,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
AR5K_PHY_NFTHRES);
- if ((channel->hw_value & CHANNEL_TURBO) &&
+ if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) &&
(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
/* Switch settling time (Turbo) */
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
@@ -870,143 +1014,172 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
}
-/*
- * Main reset function
- */
+
+/*********************\
+* Main reset function *
+\*********************/
+
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
- struct ieee80211_channel *channel, bool change_channel)
+ struct ieee80211_channel *channel, bool fast, bool skip_pcu)
{
- struct ath_common *common = ath5k_hw_common(ah);
- u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo;
- u32 phy_tst1;
- u8 mode, freq, ee_mode;
+ u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
+ u8 mode;
int i, ret;
- ee_mode = 0;
- staid1_flags = 0;
tsf_up = 0;
tsf_lo = 0;
- freq = 0;
mode = 0;
/*
- * Save some registers before a reset
+ * Sanity check for fast flag
+ * Fast channel change only available
+ * on AR2413/AR5413.
*/
- /*DCU/Antenna selection not available on 5210*/
- if (ah->ah_version != AR5K_AR5210) {
+ if (fast && (ah->ah_radio != AR5K_RF2413) &&
+ (ah->ah_radio != AR5K_RF5413))
+ fast = 0;
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- mode = AR5K_MODE_11A;
- freq = AR5K_INI_RFGAIN_5GHZ;
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- case CHANNEL_G:
- mode = AR5K_MODE_11G;
- freq = AR5K_INI_RFGAIN_2GHZ;
- ee_mode = AR5K_EEPROM_MODE_11G;
- break;
- case CHANNEL_B:
- mode = AR5K_MODE_11B;
- freq = AR5K_INI_RFGAIN_2GHZ;
- ee_mode = AR5K_EEPROM_MODE_11B;
- break;
- case CHANNEL_T:
- mode = AR5K_MODE_11A_TURBO;
- freq = AR5K_INI_RFGAIN_5GHZ;
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- case CHANNEL_TG:
- if (ah->ah_version == AR5K_AR5211) {
- ATH5K_ERR(ah->ah_sc,
- "TurboG mode not available on 5211");
- return -EINVAL;
- }
- mode = AR5K_MODE_11G_TURBO;
- freq = AR5K_INI_RFGAIN_2GHZ;
- ee_mode = AR5K_EEPROM_MODE_11G;
- break;
- case CHANNEL_XR:
- if (ah->ah_version == AR5K_AR5211) {
- ATH5K_ERR(ah->ah_sc,
- "XR mode not available on 5211");
- return -EINVAL;
- }
- mode = AR5K_MODE_XR;
- freq = AR5K_INI_RFGAIN_5GHZ;
- ee_mode = AR5K_EEPROM_MODE_11A;
- break;
- default:
+ /* Disable sleep clock operation
+ * to avoid register access delay on certain
+ * PHY registers */
+ if (ah->ah_version == AR5K_AR5212)
+ ath5k_hw_set_sleep_clock(ah, false);
+
+ /*
+ * Stop PCU
+ */
+ ath5k_hw_stop_rx_pcu(ah);
+
+ /*
+ * Stop DMA
+ *
+ * Note: If DMA didn't stop continue
+ * since only a reset will fix it.
+ */
+ ret = ath5k_hw_dma_stop(ah);
+
+ /* RF Bus grant won't work if we have pending
+ * frames */
+ if (ret && fast) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+ "DMA didn't stop, falling back to normal reset\n");
+ fast = 0;
+ /* Non fatal, just continue with
+ * normal reset */
+ ret = 0;
+ }
+
+ switch (channel->hw_value & CHANNEL_MODES) {
+ case CHANNEL_A:
+ mode = AR5K_MODE_11A;
+ break;
+ case CHANNEL_G:
+
+ if (ah->ah_version <= AR5K_AR5211) {
ATH5K_ERR(ah->ah_sc,
- "invalid channel: %d\n", channel->center_freq);
+ "G mode not available on 5210/5211");
return -EINVAL;
}
- if (change_channel) {
- /*
- * Save frame sequence count
- * For revs. after Oahu, only save
- * seq num for DCU 0 (Global seq num)
- */
- if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-
- for (i = 0; i < 10; i++)
- s_seq[i] = ath5k_hw_reg_read(ah,
- AR5K_QUEUE_DCU_SEQNUM(i));
+ mode = AR5K_MODE_11G;
+ break;
+ case CHANNEL_B:
- } else {
- s_seq[0] = ath5k_hw_reg_read(ah,
- AR5K_QUEUE_DCU_SEQNUM(0));
- }
+ if (ah->ah_version < AR5K_AR5211) {
+ ATH5K_ERR(ah->ah_sc,
+ "B mode not available on 5210");
+ return -EINVAL;
+ }
- /* TSF accelerates on AR5211 during reset
- * As a workaround save it here and restore
- * it later so that it's back in time after
- * reset. This way it'll get re-synced on the
- * next beacon without breaking ad-hoc.
- *
- * On AR5212 TSF is almost preserved across a
- * reset so it stays back in time anyway and
- * we don't have to save/restore it.
- *
- * XXX: Since this breaks power saving we have
- * to disable power saving until we receive the
- * next beacon, so we can resync beacon timers */
- if (ah->ah_version == AR5K_AR5211) {
- tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
- tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
- }
+ mode = AR5K_MODE_11B;
+ break;
+ case CHANNEL_XR:
+ if (ah->ah_version == AR5K_AR5211) {
+ ATH5K_ERR(ah->ah_sc,
+ "XR mode not available on 5211");
+ return -EINVAL;
}
+ mode = AR5K_MODE_XR;
+ break;
+ default:
+ ATH5K_ERR(ah->ah_sc,
+ "invalid channel: %d\n", channel->center_freq);
+ return -EINVAL;
+ }
- if (ah->ah_version == AR5K_AR5212) {
- /* Restore normal 32/40MHz clock operation
- * to avoid register access delay on certain
- * PHY registers */
- ath5k_hw_set_sleep_clock(ah, false);
+ /*
+ * If driver requested fast channel change and DMA has stopped
+ * go on. If it fails continue with a normal reset.
+ */
+ if (fast) {
+ ret = ath5k_hw_phy_init(ah, channel, mode, true);
+ if (ret) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+ "fast chan change failed, falling back to normal reset\n");
+ /* Non fatal, can happen eg.
+ * on mode change */
+ ret = 0;
+ } else
+ return 0;
+ }
- /* Since we are going to write rf buffer
- * check if we have any pending gain_F
- * optimization settings */
- if (change_channel && ah->ah_rf_banks != NULL)
- ath5k_hw_gainf_calibrate(ah);
+ /*
+ * Save some registers before a reset
+ */
+ if (ah->ah_version != AR5K_AR5210) {
+ /*
+ * Save frame sequence count
+ * For revs. after Oahu, only save
+ * seq num for DCU 0 (Global seq num)
+ */
+ if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+
+ for (i = 0; i < 10; i++)
+ s_seq[i] = ath5k_hw_reg_read(ah,
+ AR5K_QUEUE_DCU_SEQNUM(i));
+
+ } else {
+ s_seq[0] = ath5k_hw_reg_read(ah,
+ AR5K_QUEUE_DCU_SEQNUM(0));
+ }
+
+ /* TSF accelerates on AR5211 during reset
+ * As a workaround save it here and restore
+ * it later so that it's back in time after
+ * reset. This way it'll get re-synced on the
+ * next beacon without breaking ad-hoc.
+ *
+ * On AR5212 TSF is almost preserved across a
+ * reset so it stays back in time anyway and
+ * we don't have to save/restore it.
+ *
+ * XXX: Since this breaks power saving we have
+ * to disable power saving until we receive the
+ * next beacon, so we can resync beacon timers */
+ if (ah->ah_version == AR5K_AR5211) {
+ tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+ tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
}
}
+
/*GPIOs*/
s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
AR5K_PCICFG_LEDSTATE;
s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
- /* AR5K_STA_ID1 flags, only preserve antenna
- * settings and ack/cts rate mode */
- staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
- (AR5K_STA_ID1_DEFAULT_ANTENNA |
- AR5K_STA_ID1_DESC_ANTENNA |
- AR5K_STA_ID1_RTS_DEF_ANTENNA |
- AR5K_STA_ID1_ACKCTS_6MB |
- AR5K_STA_ID1_BASE_RATE_11B |
- AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+ /*
+ * Since we are going to write rf buffer
+ * check if we have any pending gain_F
+ * optimization settings
+ */
+ if (ah->ah_version == AR5K_AR5212 &&
+ (ah->ah_radio <= AR5K_RF5112)) {
+ if (!fast && ah->ah_rf_banks != NULL)
+ ath5k_hw_gainf_calibrate(ah);
+ }
/* Wakeup the device */
ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
@@ -1021,121 +1194,42 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
AR5K_PHY(0));
/* Write initial settings */
- ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+ ret = ath5k_hw_write_initvals(ah, mode, skip_pcu);
if (ret)
return ret;
+ /* Initialize core clock settings */
+ ath5k_hw_init_core_clock(ah);
+
/*
- * 5211/5212 Specific
+ * Tweak initval settings for revised
+ * chipsets and add some more config
+ * bits
*/
- if (ah->ah_version != AR5K_AR5210) {
-
- /*
- * Write initial RF gain settings
- * This should work for both 5111/5112
- */
- ret = ath5k_hw_rfgain_init(ah, freq);
- if (ret)
- return ret;
-
- mdelay(1);
-
- /*
- * Tweak initval settings for revised
- * chipsets and add some more config
- * bits
- */
- ath5k_hw_tweak_initval_settings(ah, channel);
-
- /*
- * Set TX power
- */
- ret = ath5k_hw_txpower(ah, channel, ee_mode,
- ah->ah_txpower.txp_max_pwr / 2);
- if (ret)
- return ret;
+ ath5k_hw_tweak_initval_settings(ah, channel);
- /* Write rate duration table only on AR5212 and if
- * virtual interface has already been brought up
- * XXX: rethink this after new mode changes to
- * mac80211 are integrated */
- if (ah->ah_version == AR5K_AR5212 &&
- ah->ah_sc->nvifs)
- ath5k_hw_write_rate_duration(ah, mode);
+ /* Commit values from EEPROM */
+ ath5k_hw_commit_eeprom_settings(ah, channel);
- /*
- * Write RF buffer
- */
- ret = ath5k_hw_rfregs_init(ah, channel, mode);
- if (ret)
- return ret;
-
-
- /* Write OFDM timings on 5212*/
- if (ah->ah_version == AR5K_AR5212 &&
- channel->hw_value & CHANNEL_OFDM) {
-
- ret = ath5k_hw_write_ofdm_timings(ah, channel);
- if (ret)
- return ret;
-
- /* Spur info is available only from EEPROM versions
- * greater than 5.3, but the EEPROM routines will use
- * static values for older versions */
- if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
- ath5k_hw_set_spur_mitigation_filter(ah,
- channel);
- }
-
- /*Enable/disable 802.11b mode on 5111
- (enable 2111 frequency converter + CCK)*/
- if (ah->ah_radio == AR5K_RF5111) {
- if (mode == AR5K_MODE_11B)
- AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
- AR5K_TXCFG_B_MODE);
- else
- AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
- AR5K_TXCFG_B_MODE);
- }
-
- /* Commit values from EEPROM */
- ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
-
- } else {
- /*
- * For 5210 we do all initialization using
- * initvals, so we don't have to modify
- * any settings (5210 also only supports
- * a/aturbo modes)
- */
- mdelay(1);
- /* Disable phy and wait */
- ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
- mdelay(1);
- }
/*
* Restore saved values
*/
- /*DCU/Antenna selection not available on 5210*/
+ /* Seqnum, TSF */
if (ah->ah_version != AR5K_AR5210) {
+ if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+ for (i = 0; i < 10; i++)
+ ath5k_hw_reg_write(ah, s_seq[i],
+ AR5K_QUEUE_DCU_SEQNUM(i));
+ } else {
+ ath5k_hw_reg_write(ah, s_seq[0],
+ AR5K_QUEUE_DCU_SEQNUM(0));
+ }
- if (change_channel) {
- if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
- for (i = 0; i < 10; i++)
- ath5k_hw_reg_write(ah, s_seq[i],
- AR5K_QUEUE_DCU_SEQNUM(i));
- } else {
- ath5k_hw_reg_write(ah, s_seq[0],
- AR5K_QUEUE_DCU_SEQNUM(0));
- }
-
-
- if (ah->ah_version == AR5K_AR5211) {
- ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
- ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
- }
+ if (ah->ah_version == AR5K_AR5211) {
+ ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
+ ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
}
}
@@ -1146,203 +1240,34 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
- /* Restore sta_id flags and preserve our mac address*/
- ath5k_hw_reg_write(ah,
- get_unaligned_le32(common->macaddr),
- AR5K_STA_ID0);
- ath5k_hw_reg_write(ah,
- staid1_flags | get_unaligned_le16(common->macaddr + 4),
- AR5K_STA_ID1);
-
-
/*
- * Configure PCU
+ * Initialize PCU
*/
-
- /* Restore bssid and bssid mask */
- ath5k_hw_set_bssid(ah);
-
- /* Set PCU config */
- ath5k_hw_set_opmode(ah, op_mode);
-
- /* Clear any pending interrupts
- * PISR/SISR Not available on 5210 */
- if (ah->ah_version != AR5K_AR5210)
- ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
-
- /* Set RSSI/BRSSI thresholds
- *
- * Note: If we decide to set this value
- * dynamically, keep in mind that when AR5K_RSSI_THR
- * register is read, it might return 0x40 if we haven't
- * written anything to it. Also, BMISS RSSI threshold is zeroed.
- * So doing a save/restore procedure here isn't the right
- * choice. Instead, store it in ath5k_hw */
- ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
- AR5K_TUNE_BMISS_THRES <<
- AR5K_RSSI_THR_BMISS_S),
- AR5K_RSSI_THR);
-
- /* MIC QoS support */
- if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
- ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
- ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
- }
-
- /* QoS NOACK Policy */
- if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah,
- AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
- AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) |
- AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
- AR5K_QOS_NOACK);
- }
-
+ ath5k_hw_pcu_init(ah, op_mode, mode);
/*
- * Configure PHY
+ * Initialize PHY
*/
-
- /* Set channel on PHY */
- ret = ath5k_hw_channel(ah, channel);
- if (ret)
+ ret = ath5k_hw_phy_init(ah, channel, mode, false);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc,
+ "failed to initialize PHY (%i) !\n", ret);
return ret;
-
- /*
- * Enable the PHY and wait until completion
- * This includes BaseBand and Synthesizer
- * activation.
- */
- ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-
- /*
- * On 5211+ read activation -> rx delay
- * and use it.
- *
- * TODO: Half/quarter rate support
- */
- if (ah->ah_version != AR5K_AR5210) {
- u32 delay;
- delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
- AR5K_PHY_RX_DELAY_M;
- delay = (channel->hw_value & CHANNEL_CCK) ?
- ((delay << 2) / 22) : (delay / 10);
-
- udelay(100 + (2 * delay));
- } else {
- mdelay(1);
}
/*
- * Perform ADC test to see if baseband is ready
- * Set TX hold and check ADC test register
- */
- phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
- ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
- for (i = 0; i <= 20; i++) {
- if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
- break;
- udelay(200);
- }
- ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
-
- /*
- * Start automatic gain control calibration
- *
- * During AGC calibration RX path is re-routed to
- * a power detector so we don't receive anything.
- *
- * This method is used to calibrate some static offsets
- * used together with on-the fly I/Q calibration (the
- * one performed via ath5k_hw_phy_calibrate), which doesn't
- * interrupt rx path.
- *
- * While rx path is re-routed to the power detector we also
- * start a noise floor calibration to measure the
- * card's noise floor (the noise we measure when we are not
- * transmitting or receiving anything).
- *
- * If we are in a noisy environment, AGC calibration may time
- * out and/or noise floor calibration might timeout.
- */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
-
- /* At the same time start I/Q calibration for QAM constellation
- * -no need for CCK- */
- ah->ah_calibration = false;
- if (!(mode == AR5K_MODE_11B)) {
- ah->ah_calibration = true;
- AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
- AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
- AR5K_PHY_IQ_RUN);
- }
-
- /* Wait for gain calibration to finish (we check for I/Q calibration
- * during ath5k_phy_calibrate) */
- if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_CAL, 0, false)) {
- ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
- channel->center_freq);
- }
-
- /* Restore antenna mode */
- ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
-
- /* Restore slot time and ACK timeouts */
- if (ah->ah_coverage_class > 0)
- ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
-
- /*
* Configure QCUs/DCUs
*/
+ ret = ath5k_hw_init_queues(ah);
+ if (ret)
+ return ret;
- /* TODO: HW Compression support for data queues */
- /* TODO: Burst prefetch for data queues */
-
- /*
- * Reset queues and start beacon timers at the end of the reset routine
- * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
- * Note: If we want we can assign multiple qcus on one dcu.
- */
- for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
- ret = ath5k_hw_reset_tx_queue(ah, i);
- if (ret) {
- ATH5K_ERR(ah->ah_sc,
- "failed to reset TX queue #%d\n", i);
- return ret;
- }
- }
-
-
- /*
- * Configure DMA/Interrupts
- */
/*
- * Set Rx/Tx DMA Configuration
- *
- * Set standard DMA size (128). Note that
- * a DMA size of 512 causes rx overruns and tx errors
- * on pci-e cards (tested on 5424 but since rx overruns
- * also occur on 5416/5418 with madwifi we set 128
- * for all PCI-E cards to be safe).
- *
- * XXX: need to check 5210 for this
- * TODO: Check out tx triger level, it's always 64 on dumps but I
- * guess we can tweak it and see how it goes ;-)
+ * Initialize DMA/Interrupts
*/
- if (ah->ah_version != AR5K_AR5210) {
- AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
- AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
- AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
- AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
- }
+ ath5k_hw_dma_init(ah);
- /* Pre-enable interrupts on 5211/5212*/
- if (ah->ah_version != AR5K_AR5210)
- ath5k_hw_set_imr(ah, ah->ah_imr);
/* Enable 32KHz clock function for AR5212+ chips
* Set clocks to 32KHz operation and use an
diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h
index 3ac4cff4239d..16b67e84906d 100644
--- a/drivers/net/wireless/ath/ath5k/rfbuffer.h
+++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h
@@ -51,7 +51,7 @@
struct ath5k_ini_rfbuffer {
u8 rfb_bank; /* RF Bank number */
u16 rfb_ctrl_register; /* RF Buffer control register */
- u32 rfb_mode_data[5]; /* RF Buffer data for each mode */
+ u32 rfb_mode_data[3]; /* RF Buffer data for each mode */
};
/*
@@ -79,8 +79,10 @@ struct ath5k_rf_reg {
* life easier by using an index for each register
* instead of a full rfb_field */
enum ath5k_rf_regs_idx {
+ /* BANK 2 */
+ AR5K_RF_TURBO = 0,
/* BANK 6 */
- AR5K_RF_OB_2GHZ = 0,
+ AR5K_RF_OB_2GHZ,
AR5K_RF_OB_5GHZ,
AR5K_RF_DB_2GHZ,
AR5K_RF_DB_5GHZ,
@@ -134,6 +136,9 @@ enum ath5k_rf_regs_idx {
* RF5111 (Sombrero) *
\*******************/
+/* BANK 2 len pos col */
+#define AR5K_RF5111_RF_TURBO { 1, 3, 0 }
+
/* BANK 6 len pos col */
#define AR5K_RF5111_OB_2GHZ { 3, 119, 0 }
#define AR5K_RF5111_DB_2GHZ { 3, 122, 0 }
@@ -158,6 +163,7 @@ enum ath5k_rf_regs_idx {
#define AR5K_RF5111_MAX_TIME { 2, 49, 0 }
static const struct ath5k_rf_reg rf_regs_5111[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF5111_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF5111_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF5111_DB_2GHZ},
{6, AR5K_RF_OB_5GHZ, AR5K_RF5111_OB_5GHZ},
@@ -177,97 +183,52 @@ static const struct ath5k_rf_reg rf_regs_5111[] = {
/* Default mode specific settings */
static const struct ath5k_ini_rfbuffer rfb_5111[] = {
- { 0, 0x989c,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 0, 0x989c,
- { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
- { 0, 0x989c,
- { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
- { 0, 0x98d4,
- { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
- { 1, 0x98d4,
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d4,
- { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
- { 3, 0x98d8,
- { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
- { 6, 0x989c,
- { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
- { 6, 0x989c,
- { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
- { 6, 0x989c,
- { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
- { 6, 0x989c,
- { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
- { 6, 0x989c,
- { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
- { 6, 0x98d4,
- { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
- { 7, 0x989c,
- { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
- { 7, 0x989c,
- { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
- { 7, 0x989c,
- { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
- { 7, 0x989c,
- { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
- { 7, 0x989c,
- { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
- { 7, 0x989c,
- { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
- { 7, 0x989c,
- { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00380000, 0x00380000, 0x00380000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 0, 0x989c, { 0x00000000, 0x000000c0, 0x00000080 } },
+ { 0, 0x989c, { 0x000400f9, 0x000400ff, 0x000400fd } },
+ { 0, 0x98d4, { 0x00000000, 0x00000004, 0x00000004 } },
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d4, { 0x00000010, 0x00000010, 0x00000010 } },
+ { 3, 0x98d8, { 0x00601068, 0x00601068, 0x00601068 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+ { 6, 0x989c, { 0x04000000, 0x04000000, 0x04000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x0a000000, 0x00000000 } },
+ { 6, 0x989c, { 0x003800c0, 0x023800c0, 0x003800c0 } },
+ { 6, 0x989c, { 0x00020006, 0x00000006, 0x00020006 } },
+ { 6, 0x989c, { 0x00000089, 0x00000089, 0x00000089 } },
+ { 6, 0x989c, { 0x000000a0, 0x000000a0, 0x000000a0 } },
+ { 6, 0x989c, { 0x00040007, 0x00040007, 0x00040007 } },
+ { 6, 0x98d4, { 0x0000001a, 0x0000001a, 0x0000001a } },
+ { 7, 0x989c, { 0x00000040, 0x00000040, 0x00000040 } },
+ { 7, 0x989c, { 0x00000010, 0x00000010, 0x00000010 } },
+ { 7, 0x989c, { 0x00000008, 0x00000008, 0x00000008 } },
+ { 7, 0x989c, { 0x0000004f, 0x0000004f, 0x0000004f } },
+ { 7, 0x989c, { 0x000000f1, 0x00000061, 0x000000f1 } },
+ { 7, 0x989c, { 0x0000904f, 0x0000904c, 0x0000904f } },
+ { 7, 0x989c, { 0x0000125a, 0x0000129a, 0x0000125a } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000f, 0x0000000e } },
};
@@ -276,6 +237,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
* RF5112/RF2112 (Derby) *
\***********************/
+/* BANK 2 (Common) len pos col */
+#define AR5K_RF5112X_RF_TURBO { 1, 1, 2 }
+
/* BANK 7 (Common) len pos col */
#define AR5K_RF5112X_GAIN_I { 6, 14, 0 }
#define AR5K_RF5112X_MIXVGA_OVR { 1, 36, 0 }
@@ -307,6 +271,7 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
#define AR5K_RF5112_PWD(_n) { 1, (302 - _n), 3 }
static const struct ath5k_rf_reg rf_regs_5112[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF5112X_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF5112_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF5112_DB_2GHZ},
{6, AR5K_RF_OB_5GHZ, AR5K_RF5112_OB_5GHZ},
@@ -335,115 +300,61 @@ static const struct ath5k_rf_reg rf_regs_5112[] = {
/* Default mode specific settings */
static const struct ath5k_ini_rfbuffer rfb_5112[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
- { 3, 0x98dc,
- { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
- { 6, 0x989c,
- { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
- { 6, 0x989c,
- { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
- { 6, 0x989c,
- { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
- { 6, 0x989c,
- { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
- { 6, 0x989c,
- { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
- { 6, 0x989c,
- { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
- { 6, 0x989c,
- { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
- { 6, 0x989c,
- { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
- { 6, 0x989c,
- { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
- { 6, 0x989c,
- { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
- { 6, 0x989c,
- { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
- { 6, 0x989c,
- { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
- { 6, 0x989c,
- { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
- { 6, 0x989c,
- { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
- { 6, 0x989c,
- { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
- { 6, 0x989c,
- { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
- { 6, 0x989c,
- { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
- { 6, 0x989c,
- { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
- { 6, 0x989c,
- { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
- { 6, 0x989c,
- { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
- { 6, 0x989c,
- { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
- { 6, 0x989c,
- { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
- { 6, 0x989c,
- { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
- { 6, 0x989c,
- { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
- { 6, 0x989c,
- { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
- { 6, 0x989c,
- { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
- { 6, 0x989c,
- { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
- { 6, 0x989c,
- { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
- { 6, 0x989c,
- { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
- { 6, 0x98d0,
- { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
- { 7, 0x989c,
- { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
- { 7, 0x989c,
- { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
- { 7, 0x989c,
- { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
- { 7, 0x989c,
- { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
- { 7, 0x989c,
- { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
- { 7, 0x989c,
- { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
- { 7, 0x989c,
- { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
- { 7, 0x989c,
- { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
- { 7, 0x989c,
- { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
- { 7, 0x989c,
- { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
- { 7, 0x989c,
- { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
- { 7, 0x989c,
- { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
- { 7, 0x98c4,
- { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x03060408, 0x03060408, 0x03060408 } },
+ { 3, 0x98dc, { 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+ { 6, 0x989c, { 0x00a00000, 0x00a00000, 0x00a00000 } },
+ { 6, 0x989c, { 0x000a0000, 0x000a0000, 0x000a0000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00660000, 0x00660000, 0x00660000 } },
+ { 6, 0x989c, { 0x00db0000, 0x00db0000, 0x00db0000 } },
+ { 6, 0x989c, { 0x00f10000, 0x00f10000, 0x00f10000 } },
+ { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+ { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+ { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x008b0000, 0x008b0000, 0x008b0000 } },
+ { 6, 0x989c, { 0x00600000, 0x00600000, 0x00600000 } },
+ { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+ { 6, 0x989c, { 0x00840000, 0x00840000, 0x00840000 } },
+ { 6, 0x989c, { 0x00640000, 0x00640000, 0x00640000 } },
+ { 6, 0x989c, { 0x00200000, 0x00200000, 0x00200000 } },
+ { 6, 0x989c, { 0x00240000, 0x00240000, 0x00240000 } },
+ { 6, 0x989c, { 0x00250000, 0x00250000, 0x00250000 } },
+ { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+ { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+ { 6, 0x989c, { 0x00510000, 0x00510000, 0x00510000 } },
+ { 6, 0x989c, { 0x1c040000, 0x1c040000, 0x1c040000 } },
+ { 6, 0x989c, { 0x000a0000, 0x000a0000, 0x000a0000 } },
+ { 6, 0x989c, { 0x00a10000, 0x00a10000, 0x00a10000 } },
+ { 6, 0x989c, { 0x00400000, 0x00400000, 0x00400000 } },
+ { 6, 0x989c, { 0x03090000, 0x03090000, 0x03090000 } },
+ { 6, 0x989c, { 0x06000000, 0x06000000, 0x06000000 } },
+ { 6, 0x989c, { 0x000000b0, 0x000000a8, 0x000000a8 } },
+ { 6, 0x989c, { 0x0000002e, 0x0000002e, 0x0000002e } },
+ { 6, 0x989c, { 0x006c4a41, 0x006c4af1, 0x006c4a61 } },
+ { 6, 0x989c, { 0x0050892a, 0x0050892b, 0x0050892b } },
+ { 6, 0x989c, { 0x00842400, 0x00842400, 0x00842400 } },
+ { 6, 0x989c, { 0x00c69200, 0x00c69200, 0x00c69200 } },
+ { 6, 0x98d0, { 0x0002000c, 0x0002000c, 0x0002000c } },
+ { 7, 0x989c, { 0x00000094, 0x00000094, 0x00000094 } },
+ { 7, 0x989c, { 0x00000091, 0x00000091, 0x00000091 } },
+ { 7, 0x989c, { 0x0000000a, 0x00000012, 0x00000012 } },
+ { 7, 0x989c, { 0x00000080, 0x00000080, 0x00000080 } },
+ { 7, 0x989c, { 0x000000c1, 0x000000c1, 0x000000c1 } },
+ { 7, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+ { 7, 0x989c, { 0x000000f0, 0x000000f0, 0x000000f0 } },
+ { 7, 0x989c, { 0x00000022, 0x00000022, 0x00000022 } },
+ { 7, 0x989c, { 0x00000092, 0x00000092, 0x00000092 } },
+ { 7, 0x989c, { 0x000000d4, 0x000000d4, 0x000000d4 } },
+ { 7, 0x989c, { 0x000014cc, 0x000014cc, 0x000014cc } },
+ { 7, 0x989c, { 0x0000048c, 0x0000048c, 0x0000048c } },
+ { 7, 0x98c4, { 0x00000003, 0x00000003, 0x00000003 } },
};
/* RFX112A (Derby 2) */
@@ -477,6 +388,7 @@ static const struct ath5k_ini_rfbuffer rfb_5112[] = {
#define AR5K_RF5112A_XB5_LVL { 2, 3, 3 }
static const struct ath5k_rf_reg rf_regs_5112a[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF5112X_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF5112A_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF5112A_DB_2GHZ},
{6, AR5K_RF_OB_5GHZ, AR5K_RF5112A_OB_5GHZ},
@@ -515,119 +427,63 @@ static const struct ath5k_rf_reg rf_regs_5112a[] = {
/* Default mode specific settings */
static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
- { 6, 0x989c,
- { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
- { 6, 0x989c,
- { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
- { 6, 0x989c,
- { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
- { 6, 0x989c,
- { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
- { 6, 0x989c,
- { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
- { 6, 0x989c,
- { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
- { 6, 0x989c,
- { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
- { 6, 0x989c,
- { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
- { 6, 0x989c,
- { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
- { 6, 0x989c,
- { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
- { 6, 0x989c,
- { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
- { 6, 0x989c,
- { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
- { 6, 0x989c,
- { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
- { 6, 0x989c,
- { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
- { 6, 0x989c,
- { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
- { 6, 0x989c,
- { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
- { 6, 0x989c,
- { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
- { 6, 0x989c,
- { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
- { 6, 0x989c,
- { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
- { 6, 0x989c,
- { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
- { 6, 0x989c,
- { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
- { 6, 0x989c,
- { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
- { 6, 0x989c,
- { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
- { 6, 0x989c,
- { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
- { 6, 0x989c,
- { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
- { 6, 0x989c,
- { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
- { 6, 0x989c,
- { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
- { 6, 0x989c,
- { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
- { 6, 0x98d8,
- { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
- { 7, 0x989c,
- { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
- { 7, 0x989c,
- { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
- { 7, 0x989c,
- { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
- { 7, 0x989c,
- { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
- { 7, 0x989c,
- { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
- { 7, 0x989c,
- { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
- { 7, 0x989c,
- { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
- { 7, 0x989c,
- { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
- { 7, 0x989c,
- { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
- { 7, 0x989c,
- { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
- { 7, 0x989c,
- { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
- { 7, 0x989c,
- { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
- { 7, 0x98c4,
- { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x03060408, 0x03060408, 0x03060408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0x0f000000, 0x0f000000, 0x0f000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00800000, 0x00800000, 0x00800000 } },
+ { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+ { 6, 0x989c, { 0x00010000, 0x00010000, 0x00010000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00180000, 0x00180000, 0x00180000 } },
+ { 6, 0x989c, { 0x00600000, 0x006e0000, 0x006e0000 } },
+ { 6, 0x989c, { 0x00c70000, 0x00c70000, 0x00c70000 } },
+ { 6, 0x989c, { 0x004b0000, 0x004b0000, 0x004b0000 } },
+ { 6, 0x989c, { 0x04480000, 0x04480000, 0x04480000 } },
+ { 6, 0x989c, { 0x004c0000, 0x004c0000, 0x004c0000 } },
+ { 6, 0x989c, { 0x00e40000, 0x00e40000, 0x00e40000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x043f0000, 0x043f0000, 0x043f0000 } },
+ { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+ { 6, 0x989c, { 0x02190000, 0x02190000, 0x02190000 } },
+ { 6, 0x989c, { 0x00240000, 0x00240000, 0x00240000 } },
+ { 6, 0x989c, { 0x00b40000, 0x00b40000, 0x00b40000 } },
+ { 6, 0x989c, { 0x00990000, 0x00990000, 0x00990000 } },
+ { 6, 0x989c, { 0x00500000, 0x00500000, 0x00500000 } },
+ { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+ { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+ { 6, 0x989c, { 0xc0320000, 0xc0320000, 0xc0320000 } },
+ { 6, 0x989c, { 0x01740000, 0x01740000, 0x01740000 } },
+ { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+ { 6, 0x989c, { 0x86280000, 0x86280000, 0x86280000 } },
+ { 6, 0x989c, { 0x31840000, 0x31840000, 0x31840000 } },
+ { 6, 0x989c, { 0x00f20080, 0x00f20080, 0x00f20080 } },
+ { 6, 0x989c, { 0x00270019, 0x00270019, 0x00270019 } },
+ { 6, 0x989c, { 0x00000003, 0x00000003, 0x00000003 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x000000b2, 0x000000b2, 0x000000b2 } },
+ { 6, 0x989c, { 0x00b02084, 0x00b02084, 0x00b02084 } },
+ { 6, 0x989c, { 0x004125a4, 0x004125a4, 0x004125a4 } },
+ { 6, 0x989c, { 0x00119220, 0x00119220, 0x00119220 } },
+ { 6, 0x989c, { 0x001a4800, 0x001a4800, 0x001a4800 } },
+ { 6, 0x98d8, { 0x000b0230, 0x000b0230, 0x000b0230 } },
+ { 7, 0x989c, { 0x00000094, 0x00000094, 0x00000094 } },
+ { 7, 0x989c, { 0x00000091, 0x00000091, 0x00000091 } },
+ { 7, 0x989c, { 0x00000012, 0x00000012, 0x00000012 } },
+ { 7, 0x989c, { 0x00000080, 0x00000080, 0x00000080 } },
+ { 7, 0x989c, { 0x000000d9, 0x000000d9, 0x000000d9 } },
+ { 7, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+ { 7, 0x989c, { 0x000000f0, 0x000000f0, 0x000000f0 } },
+ { 7, 0x989c, { 0x000000a2, 0x000000a2, 0x000000a2 } },
+ { 7, 0x989c, { 0x00000052, 0x00000052, 0x00000052 } },
+ { 7, 0x989c, { 0x000000d4, 0x000000d4, 0x000000d4 } },
+ { 7, 0x989c, { 0x000014cc, 0x000014cc, 0x000014cc } },
+ { 7, 0x989c, { 0x0000048c, 0x0000048c, 0x0000048c } },
+ { 7, 0x98c4, { 0x00000003, 0x00000003, 0x00000003 } },
};
@@ -636,11 +492,15 @@ static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
* RF2413 (Griffin) *
\******************/
+/* BANK 2 len pos col */
+#define AR5K_RF2413_RF_TURBO { 1, 1, 2 }
+
/* BANK 6 len pos col */
#define AR5K_RF2413_OB_2GHZ { 3, 168, 0 }
#define AR5K_RF2413_DB_2GHZ { 3, 165, 0 }
static const struct ath5k_rf_reg rf_regs_2413[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF2413_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF2413_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF2413_DB_2GHZ},
};
@@ -649,73 +509,40 @@ static const struct ath5k_rf_reg rf_regs_2413[] = {
* XXX: a/aTurbo ???
*/
static const struct ath5k_ini_rfbuffer rfb_2413[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
- { 6, 0x989c,
- { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
- { 6, 0x989c,
- { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
- { 6, 0x989c,
- { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
- { 6, 0x989c,
- { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
- { 6, 0x989c,
- { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
- { 6, 0x989c,
- { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
- { 6, 0x989c,
- { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
- { 6, 0x989c,
- { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
- { 6, 0x989c,
- { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
- { 6, 0x989c,
- { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
- { 6, 0x989c,
- { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
- { 6, 0x989c,
- { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
- { 6, 0x98d8,
- { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0xf0000000, 0xf0000000, 0xf0000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x03000000, 0x03000000, 0x03000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x40400000, 0x40400000, 0x40400000 } },
+ { 6, 0x989c, { 0x65050000, 0x65050000, 0x65050000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00420000, 0x00420000, 0x00420000 } },
+ { 6, 0x989c, { 0x00b50000, 0x00b50000, 0x00b50000 } },
+ { 6, 0x989c, { 0x00030000, 0x00030000, 0x00030000 } },
+ { 6, 0x989c, { 0x00f70000, 0x00f70000, 0x00f70000 } },
+ { 6, 0x989c, { 0x009d0000, 0x009d0000, 0x009d0000 } },
+ { 6, 0x989c, { 0x00220000, 0x00220000, 0x00220000 } },
+ { 6, 0x989c, { 0x04220000, 0x04220000, 0x04220000 } },
+ { 6, 0x989c, { 0x00230018, 0x00230018, 0x00230018 } },
+ { 6, 0x989c, { 0x00280000, 0x00280060, 0x00280060 } },
+ { 6, 0x989c, { 0x005000c0, 0x005000c3, 0x005000c3 } },
+ { 6, 0x989c, { 0x0004007f, 0x0004007f, 0x0004007f } },
+ { 6, 0x989c, { 0x00000458, 0x00000458, 0x00000458 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x0000c000, 0x0000c000, 0x0000c000 } },
+ { 6, 0x98d8, { 0x00400230, 0x00400230, 0x00400230 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
@@ -724,88 +551,57 @@ static const struct ath5k_ini_rfbuffer rfb_2413[] = {
* RF2315/RF2316 (Cobra SoC) *
\***************************/
+/* BANK 2 len pos col */
+#define AR5K_RF2316_RF_TURBO { 1, 1, 2 }
+
/* BANK 6 len pos col */
#define AR5K_RF2316_OB_2GHZ { 3, 178, 0 }
#define AR5K_RF2316_DB_2GHZ { 3, 175, 0 }
static const struct ath5k_rf_reg rf_regs_2316[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF2316_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF2316_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF2316_DB_2GHZ},
};
/* Default mode specific settings */
static const struct ath5k_ini_rfbuffer rfb_2316[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
- { 6, 0x989c,
- { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
- { 6, 0x989c,
- { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
- { 6, 0x989c,
- { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
- { 6, 0x989c,
- { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
- { 6, 0x989c,
- { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
- { 6, 0x989c,
- { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
- { 6, 0x989c,
- { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
- { 6, 0x989c,
- { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
- { 6, 0x989c,
- { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
- { 6, 0x989c,
- { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
- { 6, 0x989c,
- { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
- { 6, 0x989c,
- { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
- { 6, 0x989c,
- { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
- { 6, 0x989c,
- { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
- { 6, 0x989c,
- { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
- { 6, 0x989c,
- { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
- { 6, 0x989c,
- { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
- { 6, 0x98c0,
- { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0xc0000000, 0xc0000000, 0xc0000000 } },
+ { 6, 0x989c, { 0x0f000000, 0x0f000000, 0x0f000000 } },
+ { 6, 0x989c, { 0x02000000, 0x02000000, 0x02000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0xf8000000, 0xf8000000, 0xf8000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x95150000, 0x95150000, 0x95150000 } },
+ { 6, 0x989c, { 0xc1000000, 0xc1000000, 0xc1000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00080000, 0x00080000, 0x00080000 } },
+ { 6, 0x989c, { 0x00d50000, 0x00d50000, 0x00d50000 } },
+ { 6, 0x989c, { 0x000e0000, 0x000e0000, 0x000e0000 } },
+ { 6, 0x989c, { 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
+ { 6, 0x989c, { 0x00770000, 0x00770000, 0x00770000 } },
+ { 6, 0x989c, { 0x008a0000, 0x008a0000, 0x008a0000 } },
+ { 6, 0x989c, { 0x10880000, 0x10880000, 0x10880000 } },
+ { 6, 0x989c, { 0x008c0060, 0x008c0060, 0x008c0060 } },
+ { 6, 0x989c, { 0x00a00000, 0x00a00080, 0x00a00080 } },
+ { 6, 0x989c, { 0x00400000, 0x0040000d, 0x0040000d } },
+ { 6, 0x989c, { 0x00110400, 0x00110400, 0x00110400 } },
+ { 6, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+ { 6, 0x989c, { 0x00000001, 0x00000001, 0x00000001 } },
+ { 6, 0x989c, { 0x00000b00, 0x00000b00, 0x00000b00 } },
+ { 6, 0x989c, { 0x00000be8, 0x00000be8, 0x00000be8 } },
+ { 6, 0x98c0, { 0x00010000, 0x00010000, 0x00010000 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
@@ -835,93 +631,50 @@ static const struct ath5k_rf_reg rf_regs_5413[] = {
/* Default mode specific settings */
static const struct ath5k_ini_rfbuffer rfb_5413[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
- { 3, 0x98dc,
- { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
- { 6, 0x989c,
- { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
- { 6, 0x989c,
- { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
- { 6, 0x989c,
- { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
- { 6, 0x989c,
- { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
- { 6, 0x989c,
- { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
- { 6, 0x989c,
- { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
- { 6, 0x989c,
- { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
- { 6, 0x989c,
- { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
- { 6, 0x989c,
- { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
- { 6, 0x989c,
- { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
- { 6, 0x989c,
- { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
- { 6, 0x989c,
- { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
- { 6, 0x989c,
- { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
- { 6, 0x989c,
- { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
- { 6, 0x989c,
- { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
- { 6, 0x989c,
- { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
- { 6, 0x989c,
- { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
- { 6, 0x989c,
- { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
- { 6, 0x989c,
- { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
- { 6, 0x989c,
- { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } },
- { 6, 0x989c,
- { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
- { 6, 0x989c,
- { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } },
- { 6, 0x98c8,
- { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x00000008, 0x00000008, 0x00000008 } },
+ { 3, 0x98dc, { 0x00a000c0, 0x00e000c0, 0x00e000c0 } },
+ { 6, 0x989c, { 0x33000000, 0x33000000, 0x33000000 } },
+ { 6, 0x989c, { 0x01000000, 0x01000000, 0x01000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x1f000000, 0x1f000000, 0x1f000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00b80000, 0x00b80000, 0x00b80000 } },
+ { 6, 0x989c, { 0x00b70000, 0x00b70000, 0x00b70000 } },
+ { 6, 0x989c, { 0x00840000, 0x00840000, 0x00840000 } },
+ { 6, 0x989c, { 0x00980000, 0x00980000, 0x00980000 } },
+ { 6, 0x989c, { 0x00c00000, 0x00c00000, 0x00c00000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+ { 6, 0x989c, { 0x00d70000, 0x00d70000, 0x00d70000 } },
+ { 6, 0x989c, { 0x00610000, 0x00610000, 0x00610000 } },
+ { 6, 0x989c, { 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+ { 6, 0x989c, { 0x00de0000, 0x00de0000, 0x00de0000 } },
+ { 6, 0x989c, { 0x007f0000, 0x007f0000, 0x007f0000 } },
+ { 6, 0x989c, { 0x043d0000, 0x043d0000, 0x043d0000 } },
+ { 6, 0x989c, { 0x00770000, 0x00770000, 0x00770000 } },
+ { 6, 0x989c, { 0x00440000, 0x00440000, 0x00440000 } },
+ { 6, 0x989c, { 0x00980000, 0x00980000, 0x00980000 } },
+ { 6, 0x989c, { 0x00100080, 0x00100080, 0x00100080 } },
+ { 6, 0x989c, { 0x0005c034, 0x0005c034, 0x0005c034 } },
+ { 6, 0x989c, { 0x003100f0, 0x003100f0, 0x003100f0 } },
+ { 6, 0x989c, { 0x000c011f, 0x000c011f, 0x000c011f } },
+ { 6, 0x989c, { 0x00510040, 0x00510040, 0x00510040 } },
+ { 6, 0x989c, { 0x005000da, 0x005000da, 0x005000da } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00004044, 0x00004044, 0x00004044 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x000060c0, 0x000060c0, 0x000060c0 } },
+ { 6, 0x989c, { 0x00002c00, 0x00003600, 0x00003600 } },
+ { 6, 0x98c8, { 0x00000403, 0x00040403, 0x00040403 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
@@ -931,92 +684,59 @@ static const struct ath5k_ini_rfbuffer rfb_5413[] = {
* AR2317 (Spider SoC) *
\***************************/
+/* BANK 2 len pos col */
+#define AR5K_RF2425_RF_TURBO { 1, 1, 2 }
+
/* BANK 6 len pos col */
#define AR5K_RF2425_OB_2GHZ { 3, 193, 0 }
#define AR5K_RF2425_DB_2GHZ { 3, 190, 0 }
static const struct ath5k_rf_reg rf_regs_2425[] = {
+ {2, AR5K_RF_TURBO, AR5K_RF2425_RF_TURBO},
{6, AR5K_RF_OB_2GHZ, AR5K_RF2425_OB_2GHZ},
{6, AR5K_RF_DB_2GHZ, AR5K_RF2425_DB_2GHZ},
};
/* Default mode specific settings
- * XXX: a/aTurbo ?
*/
static const struct ath5k_ini_rfbuffer rfb_2425[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
- { 6, 0x989c,
- { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
- { 6, 0x989c,
- { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
- { 6, 0x989c,
- { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
- { 6, 0x989c,
- { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
- { 6, 0x989c,
- { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
- { 6, 0x989c,
- { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
- { 6, 0x989c,
- { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
- { 6, 0x989c,
- { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
- { 6, 0x989c,
- { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
- { 6, 0x989c,
- { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
- { 6, 0x989c,
- { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
- { 6, 0x98c4,
- { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+ { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+ { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+ { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+ { 6, 0x989c, { 0x00e70000, 0x00e70000, 0x00e70000 } },
+ { 6, 0x989c, { 0x00140000, 0x00140000, 0x00140000 } },
+ { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+ { 6, 0x989c, { 0x0007001a, 0x0007001a, 0x0007001a } },
+ { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+ { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+ { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+ { 6, 0x989c, { 0x00001688, 0x00001688, 0x00001688 } },
+ { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
/*
@@ -1024,158 +744,85 @@ static const struct ath5k_ini_rfbuffer rfb_2425[] = {
* bank modification and get rid of this
*/
static const struct ath5k_ini_rfbuffer rfb_2317[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
- { 6, 0x989c,
- { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
- { 6, 0x989c,
- { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
- { 6, 0x989c,
- { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
- { 6, 0x989c,
- { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
- { 6, 0x989c,
- { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
- { 6, 0x989c,
- { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
- { 6, 0x989c,
- { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
- { 6, 0x989c,
- { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
- { 6, 0x989c,
- { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
- { 6, 0x989c,
- { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
- { 6, 0x989c,
- { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
- { 6, 0x98c4,
- { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+ { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+ { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+ { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+ { 6, 0x989c, { 0x00e70000, 0x00e70000, 0x00e70000 } },
+ { 6, 0x989c, { 0x00140100, 0x00140100, 0x00140100 } },
+ { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+ { 6, 0x989c, { 0x0007001a, 0x0007001a, 0x0007001a } },
+ { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+ { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+ { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+ { 6, 0x989c, { 0x00009688, 0x00009688, 0x00009688 } },
+ { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
/*
* TODO: Handle the few differences with swan during
* bank modification and get rid of this
- * XXX: a/aTurbo ?
*/
static const struct ath5k_ini_rfbuffer rfb_2417[] = {
- { 1, 0x98d4,
- /* mode a/XR mode aTurbo mode b mode g mode gTurbo */
- { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
- { 2, 0x98d0,
- { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
- { 3, 0x98dc,
- { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
- { 6, 0x989c,
- { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
- { 6, 0x989c,
- { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
- { 6, 0x989c,
- { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
- { 6, 0x989c,
- { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
- { 6, 0x989c,
- { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
- { 6, 0x989c,
- { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
- { 6, 0x989c,
- { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
- { 6, 0x989c,
- { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
- { 6, 0x989c,
- { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
- { 6, 0x989c,
- { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
- { 6, 0x989c,
- { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
- { 6, 0x989c,
- { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
- { 6, 0x989c,
- { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
- { 6, 0x98c4,
- { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
- { 7, 0x989c,
- { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
- { 7, 0x989c,
- { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
- { 7, 0x98cc,
- { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+ /* BANK / C.R. A/XR B G */
+ { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+ { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+ { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+ { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+ { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+ { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+ { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+ { 6, 0x989c, { 0x00e70000, 0x80e70000, 0x80e70000 } },
+ { 6, 0x989c, { 0x00140000, 0x00140000, 0x00140000 } },
+ { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+ { 6, 0x989c, { 0x0007001a, 0x0207001a, 0x0207001a } },
+ { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+ { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+ { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+ { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+ { 6, 0x989c, { 0x00001688, 0x00001688, 0x00001688 } },
+ { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+ { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+ { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+ { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
};
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
index 90757de7bf59..929c68cdf8ab 100644
--- a/drivers/net/wireless/ath/ath5k/sysfs.c
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -95,7 +95,7 @@ static struct attribute_group ath5k_attribute_group_ani = {
int
ath5k_sysfs_register(struct ath5k_softc *sc)
{
- struct device *dev = &sc->pdev->dev;
+ struct device *dev = sc->dev;
int err;
err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani);
@@ -110,7 +110,7 @@ ath5k_sysfs_register(struct ath5k_softc *sc)
void
ath5k_sysfs_unregister(struct ath5k_softc *sc)
{
- struct device *dev = &sc->pdev->dev;
+ struct device *dev = sc->dev;
sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani);
}
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 1a984b02e9e5..25a6e4417cdb 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -35,10 +35,9 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
pdata = (struct ath9k_platform_data *) pdev->dev.platform_data;
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
- ath_print(common, ATH_DBG_FATAL,
- "%s: flash read failed, offset %08x "
- "is out of range\n",
- __func__, off);
+ ath_err(common,
+ "%s: flash read failed, offset %08x is out of range\n",
+ __func__, off);
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 63ccb39cdcd4..2e31c775351f 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -135,8 +135,8 @@ static void ath9k_ani_restart(struct ath_hw *ah)
cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
}
- ath_print(common, ATH_DBG_ANI,
- "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base);
ENABLE_REGWRITE_BUFFER(ah);
@@ -267,11 +267,11 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
aniState->noiseFloor = BEACON_RSSI(ah);
- ath_print(common, ATH_DBG_ANI,
- "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
- aniState->ofdmNoiseImmunityLevel,
- immunityLevel, aniState->noiseFloor,
- aniState->rssiThrLow, aniState->rssiThrHigh);
+ ath_dbg(common, ATH_DBG_ANI,
+ "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->ofdmNoiseImmunityLevel,
+ immunityLevel, aniState->noiseFloor,
+ aniState->rssiThrLow, aniState->rssiThrHigh);
aniState->ofdmNoiseImmunityLevel = immunityLevel;
@@ -334,11 +334,11 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
const struct ani_cck_level_entry *entry_cck;
aniState->noiseFloor = BEACON_RSSI(ah);
- ath_print(common, ATH_DBG_ANI,
- "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
- aniState->cckNoiseImmunityLevel, immunityLevel,
- aniState->noiseFloor, aniState->rssiThrLow,
- aniState->rssiThrHigh);
+ ath_dbg(common, ATH_DBG_ANI,
+ "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->cckNoiseImmunityLevel, immunityLevel,
+ aniState->noiseFloor, aniState->rssiThrLow,
+ aniState->rssiThrHigh);
if ((ah->opmode == NL80211_IFTYPE_STATION ||
ah->opmode == NL80211_IFTYPE_ADHOC) &&
@@ -358,7 +358,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
entry_cck->fir_step_level);
/* Skip MRC CCK for pre AR9003 families */
- if (!AR_SREV_9300_20_OR_LATER(ah))
+ if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
return;
if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
@@ -478,8 +478,8 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
if (ah->opmode != NL80211_IFTYPE_STATION
&& ah->opmode != NL80211_IFTYPE_ADHOC) {
- ath_print(common, ATH_DBG_ANI,
- "Reset ANI state opmode %u\n", ah->opmode);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Reset ANI state opmode %u\n", ah->opmode);
ah->stats.ast_ani_reset++;
if (ah->opmode == NL80211_IFTYPE_AP) {
@@ -584,16 +584,14 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
ATH9K_ANI_OFDM_DEF_LEVEL ||
aniState->cckNoiseImmunityLevel !=
ATH9K_ANI_CCK_DEF_LEVEL) {
- ath_print(common, ATH_DBG_ANI,
- "Restore defaults: opmode %u "
- "chan %d Mhz/0x%x is_scanning=%d "
- "ofdm:%d cck:%d\n",
- ah->opmode,
- chan->channel,
- chan->channelFlags,
- is_scanning,
- aniState->ofdmNoiseImmunityLevel,
- aniState->cckNoiseImmunityLevel);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags,
+ is_scanning,
+ aniState->ofdmNoiseImmunityLevel,
+ aniState->cckNoiseImmunityLevel);
ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
@@ -602,16 +600,14 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
/*
* restore historical levels for this channel
*/
- ath_print(common, ATH_DBG_ANI,
- "Restore history: opmode %u "
- "chan %d Mhz/0x%x is_scanning=%d "
- "ofdm:%d cck:%d\n",
- ah->opmode,
- chan->channel,
- chan->channelFlags,
- is_scanning,
- aniState->ofdmNoiseImmunityLevel,
- aniState->cckNoiseImmunityLevel);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags,
+ is_scanning,
+ aniState->ofdmNoiseImmunityLevel,
+ aniState->cckNoiseImmunityLevel);
ath9k_hw_set_ofdm_nil(ah,
aniState->ofdmNoiseImmunityLevel);
@@ -666,19 +662,17 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
if (phyCnt1 < ofdm_base) {
- ath_print(common, ATH_DBG_ANI,
- "phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt1, ofdm_base);
+ ath_dbg(common, ATH_DBG_ANI,
+ "phyCnt1 0x%x, resetting counter value to 0x%x\n",
+ phyCnt1, ofdm_base);
REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
AR_PHY_ERR_OFDM_TIMING);
}
if (phyCnt2 < cck_base) {
- ath_print(common, ATH_DBG_ANI,
- "phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt2, cck_base);
+ ath_dbg(common, ATH_DBG_ANI,
+ "phyCnt2 0x%x, resetting counter value to 0x%x\n",
+ phyCnt2, cck_base);
REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
AR_PHY_ERR_CCK_TIMING);
@@ -719,13 +713,12 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
cckPhyErrRate = aniState->cckPhyErrCount * 1000 /
aniState->listenTime;
- ath_print(common, ATH_DBG_ANI,
- "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
- "errs=%d/s ofdm_turn=%d\n",
- aniState->listenTime,
- aniState->ofdmNoiseImmunityLevel,
- ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
- cckPhyErrRate, aniState->ofdmsTurn);
+ ath_dbg(common, ATH_DBG_ANI,
+ "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
+ aniState->listenTime,
+ aniState->ofdmNoiseImmunityLevel,
+ ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
+ cckPhyErrRate, aniState->ofdmsTurn);
if (aniState->listenTime > 5 * ah->aniperiod) {
if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
@@ -755,7 +748,7 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n");
+ ath_dbg(common, ATH_DBG_ANI, "Enable MIB counters\n");
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -777,7 +770,7 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n");
+ ath_dbg(common, ATH_DBG_ANI, "Disable MIB counters\n");
REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -834,10 +827,10 @@ void ath9k_hw_ani_setup(struct ath_hw *ah)
{
int i;
- const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
- const int coarseHigh[] = { -14, -14, -14, -14, -12 };
- const int coarseLow[] = { -64, -64, -64, -64, -70 };
- const int firpwr[] = { -78, -78, -78, -78, -80 };
+ static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+ static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+ static const int coarseLow[] = { -64, -64, -64, -64, -70 };
+ static const int firpwr[] = { -78, -78, -78, -78, -80 };
for (i = 0; i < 5; i++) {
ah->totalSizeDesired[i] = totalSizeDesired[i];
@@ -852,7 +845,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
int i;
- ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
+ ath_dbg(common, ATH_DBG_ANI, "Initialize ANI\n");
if (use_new_ani(ah)) {
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index ea9f4497f58c..ffcf44a4058b 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -130,9 +130,8 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
/* pre-reverse this field */
tmp_reg = ath9k_hw_reverse_bits(new_bias, 3);
- ath_print(common, ATH_DBG_CONFIG,
- "Force rf_pwd_icsyndiv to %1d on %4d\n",
- new_bias, synth_freq);
+ ath_dbg(common, ATH_DBG_CONFIG, "Force rf_pwd_icsyndiv to %1d on %4d\n",
+ new_bias, synth_freq);
/* swizzle rf_pwd_icsyndiv */
ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
@@ -173,8 +172,7 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ((freq - 704) * 2 - 3040) / 10;
bModeSynth = 1;
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_err(common, "Invalid channel %u MHz\n", freq);
return -EINVAL;
}
@@ -206,8 +204,7 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_err(common, "Invalid channel %u MHz\n", freq);
return -EINVAL;
}
@@ -244,13 +241,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
int upper, lower, cur_vit_mask;
int tmp, new;
int i;
- int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
- AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+ static int pilot_mask_reg[4] = {
+ AR_PHY_TIMING7, AR_PHY_TIMING8,
+ AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
};
- int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
- AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+ static int chan_mask_reg[4] = {
+ AR_PHY_TIMING9, AR_PHY_TIMING10,
+ AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
};
- int inc[4] = { 0, 100, 0, 0 };
+ static int inc[4] = { 0, 100, 0, 0 };
int8_t mask_m[123];
int8_t mask_p[123];
@@ -446,8 +445,7 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
#define ATH_ALLOC_BANK(bank, size) do { \
bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
if (!bank) { \
- ath_print(common, ATH_DBG_FATAL, \
- "Cannot allocate RF banks\n"); \
+ ath_err(common, "Cannot allocate RF banks\n"); \
return -ENOMEM; \
} \
} while (0);
@@ -873,12 +871,11 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit));
+ (u32) regulatory->power_limit), false);
/* Write analog registers */
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "ar5416SetRfRegs failed\n");
+ ath_err(ath9k_hw_common(ah), "ar5416SetRfRegs failed\n");
return -EIO;
}
@@ -964,18 +961,6 @@ static void ar5008_hw_rfbus_done(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
}
-static void ar5008_hw_enable_rfkill(struct ath_hw *ah)
-{
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
- REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
- AR_GPIO_INPUT_MUX2_RFSILENT);
-
- ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
- REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-
static void ar5008_restore_chainmask(struct ath_hw *ah)
{
int rx_chainmask = ah->rxchainmask;
@@ -1056,10 +1041,9 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
- ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
+ ath_dbg(common, ATH_DBG_ANI,
+ "level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(ah->totalSizeDesired));
return false;
}
@@ -1084,12 +1068,12 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
break;
}
case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
- const int m1ThreshLow[] = { 127, 50 };
- const int m2ThreshLow[] = { 127, 40 };
- const int m1Thresh[] = { 127, 0x4d };
- const int m2Thresh[] = { 127, 0x40 };
- const int m2CountThr[] = { 31, 16 };
- const int m2CountThrLow[] = { 63, 48 };
+ static const int m1ThreshLow[] = { 127, 50 };
+ static const int m2ThreshLow[] = { 127, 40 };
+ static const int m1Thresh[] = { 127, 0x4d };
+ static const int m2Thresh[] = { 127, 0x40 };
+ static const int m2CountThr[] = { 31, 16 };
+ static const int m2CountThrLow[] = { 63, 48 };
u32 on = param ? 1 : 0;
REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
@@ -1141,7 +1125,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
break;
}
case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
- const int weakSigThrCck[] = { 8, 6 };
+ static const int weakSigThrCck[] = { 8, 6 };
u32 high = param ? 1 : 0;
REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
@@ -1157,14 +1141,13 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
break;
}
case ATH9K_ANI_FIRSTEP_LEVEL:{
- const int firstep[] = { 0, 4, 8 };
+ static const int firstep[] = { 0, 4, 8 };
u32 level = param;
if (level >= ARRAY_SIZE(firstep)) {
- ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(firstep));
+ ath_dbg(common, ATH_DBG_ANI,
+ "level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(firstep));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
@@ -1178,14 +1161,13 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
break;
}
case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
- const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+ static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
u32 level = param;
if (level >= ARRAY_SIZE(cycpwrThr1)) {
- ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(cycpwrThr1));
+ ath_dbg(common, ATH_DBG_ANI,
+ "level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(cycpwrThr1));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
@@ -1201,25 +1183,22 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
case ATH9K_ANI_PRESENT:
break;
default:
- ath_print(common, ATH_DBG_ANI,
- "invalid cmd %u\n", cmd);
+ ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd);
return false;
}
- ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
- ath_print(common, ATH_DBG_ANI,
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
- "ofdmWeakSigDetectOff=%d\n",
- aniState->noiseImmunityLevel,
- aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
- ath_print(common, ATH_DBG_ANI,
- "cckWeakSigThreshold=%d, "
- "firstepLevel=%d, listenTime=%d\n",
- aniState->cckWeakSigThreshold,
- aniState->firstepLevel,
- aniState->listenTime);
- ath_print(common, ATH_DBG_ANI,
+ ath_dbg(common, ATH_DBG_ANI, "ANI parameters:\n");
+ ath_dbg(common, ATH_DBG_ANI,
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
+ aniState->noiseImmunityLevel,
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff);
+ ath_dbg(common, ATH_DBG_ANI,
+ "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
+ aniState->cckWeakSigThreshold,
+ aniState->firstepLevel,
+ aniState->listenTime);
+ ath_dbg(common, ATH_DBG_ANI,
"ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
@@ -1304,12 +1283,12 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
if (!on != aniState->ofdmWeakSigDetectOff) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: ofdm weak signal: %s=>%s\n",
- chan->channel,
- !aniState->ofdmWeakSigDetectOff ?
- "on" : "off",
- on ? "on" : "off");
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: ofdm weak signal: %s=>%s\n",
+ chan->channel,
+ !aniState->ofdmWeakSigDetectOff ?
+ "on" : "off",
+ on ? "on" : "off");
if (on)
ah->stats.ast_ani_ofdmon++;
else
@@ -1322,11 +1301,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(firstep_table)) {
- ath_print(common, ATH_DBG_ANI,
- "ATH9K_ANI_FIRSTEP_LEVEL: level "
- "out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(firstep_table));
+ ath_dbg(common, ATH_DBG_ANI,
+ "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(firstep_table));
return false;
}
@@ -1361,24 +1338,22 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
if (level != aniState->firstepLevel) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "firstep[level]=%d ini=%d\n",
- chan->channel,
- aniState->firstepLevel,
- level,
- ATH9K_ANI_FIRSTEP_LVL_NEW,
- value,
- aniState->iniDef.firstep);
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "firstep_low[level]=%d ini=%d\n",
- chan->channel,
- aniState->firstepLevel,
- level,
- ATH9K_ANI_FIRSTEP_LVL_NEW,
- value2,
- aniState->iniDef.firstepLow);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value,
+ aniState->iniDef.firstep);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value2,
+ aniState->iniDef.firstepLow);
if (level > aniState->firstepLevel)
ah->stats.ast_ani_stepup++;
else if (level < aniState->firstepLevel)
@@ -1391,11 +1366,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
- ath_print(common, ATH_DBG_ANI,
- "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
- "out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(cycpwrThr1_table));
+ ath_dbg(common, ATH_DBG_ANI,
+ "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(cycpwrThr1_table));
return false;
}
/*
@@ -1429,24 +1402,22 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
if (level != aniState->spurImmunityLevel) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "cycpwrThr1[level]=%d ini=%d\n",
- chan->channel,
- aniState->spurImmunityLevel,
- level,
- ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
- value,
- aniState->iniDef.cycpwrThr1);
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "cycpwrThr1Ext[level]=%d ini=%d\n",
- chan->channel,
- aniState->spurImmunityLevel,
- level,
- ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
- value2,
- aniState->iniDef.cycpwrThr1Ext);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value,
+ aniState->iniDef.cycpwrThr1);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value2,
+ aniState->iniDef.cycpwrThr1Ext);
if (level > aniState->spurImmunityLevel)
ah->stats.ast_ani_spurup++;
else if (level < aniState->spurImmunityLevel)
@@ -1465,22 +1436,19 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
case ATH9K_ANI_PRESENT:
break;
default:
- ath_print(common, ATH_DBG_ANI,
- "invalid cmd %u\n", cmd);
+ ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd);
return false;
}
- ath_print(common, ATH_DBG_ANI,
- "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
- "MRCcck=%s listenTime=%d "
- "ofdmErrs=%d cckErrs=%d\n",
- aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff ? "on" : "off",
- aniState->firstepLevel,
- !aniState->mrcCCKOff ? "on" : "off",
- aniState->listenTime,
- aniState->ofdmPhyErrCount,
- aniState->cckPhyErrCount);
+ ath_dbg(common, ATH_DBG_ANI,
+ "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+ aniState->firstepLevel,
+ !aniState->mrcCCKOff ? "on" : "off",
+ aniState->listenTime,
+ aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
return true;
}
@@ -1490,25 +1458,25 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah,
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
- nfarray[0] = sign_extend(nf, 9);
+ nfarray[0] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
- nfarray[1] = sign_extend(nf, 9);
+ nfarray[1] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
- nfarray[2] = sign_extend(nf, 9);
+ nfarray[2] = sign_extend32(nf, 8);
if (!IS_CHAN_HT40(ah->curchan))
return;
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
- nfarray[3] = sign_extend(nf, 9);
+ nfarray[3] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
- nfarray[4] = sign_extend(nf, 9);
+ nfarray[4] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
- nfarray[5] = sign_extend(nf, 9);
+ nfarray[5] = sign_extend32(nf, 8);
}
/*
@@ -1526,13 +1494,12 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
iniDef = &aniState->iniDef;
- ath_print(common, ATH_DBG_ANI,
- "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
- ah->hw_version.macVersion,
- ah->hw_version.macRev,
- ah->opmode,
- chan->channel,
- chan->channelFlags);
+ ath_dbg(common, ATH_DBG_ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+ ah->hw_version.macVersion,
+ ah->hw_version.macRev,
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags);
val = REG_READ(ah, AR_PHY_SFCORR);
iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
@@ -1579,10 +1546,55 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
}
+static void ar5008_hw_set_radar_params(struct ath_hw *ah,
+ struct ath_hw_radar_conf *conf)
+{
+ u32 radar_0 = 0, radar_1 = 0;
+
+ if (!conf) {
+ REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+ return;
+ }
+
+ radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA;
+ radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR);
+ radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI);
+ radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT);
+ radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
+ radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+
+ radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
+ radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
+ radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
+ radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH);
+ radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH);
+
+ REG_WRITE(ah, AR_PHY_RADAR_0, radar_0);
+ REG_WRITE(ah, AR_PHY_RADAR_1, radar_1);
+ if (conf->ext_channel)
+ REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+ else
+ REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+}
+
+static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
+{
+ struct ath_hw_radar_conf *conf = &ah->radar_conf;
+
+ conf->fir_power = -33;
+ conf->radar_rssi = 20;
+ conf->pulse_height = 10;
+ conf->pulse_rssi = 24;
+ conf->pulse_inband = 15;
+ conf->pulse_maxlen = 255;
+ conf->pulse_inband_step = 12;
+ conf->radar_inband = 8;
+}
+
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
- const u32 ar5416_cca_regs[6] = {
+ static const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
AR_PHY_CH2_CCA,
@@ -1605,10 +1617,10 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->set_delta_slope = ar5008_hw_set_delta_slope;
priv_ops->rfbus_req = ar5008_hw_rfbus_req;
priv_ops->rfbus_done = ar5008_hw_rfbus_done;
- priv_ops->enable_rfkill = ar5008_hw_enable_rfkill;
priv_ops->restore_chainmask = ar5008_restore_chainmask;
priv_ops->set_diversity = ar5008_set_diversity;
priv_ops->do_getnf = ar5008_hw_do_getnf;
+ priv_ops->set_radar_params = ar5008_hw_set_radar_params;
if (modparam_force_new_ani) {
priv_ops->ani_control = ar5008_hw_ani_control_new;
@@ -1624,5 +1636,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
ar5008_hw_set_nf_limits(ah);
+ ar5008_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 15f62cd0cc38..ea2e7d714bda 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -39,18 +39,18 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah,
switch (currCal->calData->calType) {
case IQ_MISMATCH_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting IQ Mismatch Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "starting IQ Mismatch Calibration\n");
break;
case ADC_GAIN_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting ADC Gain Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "starting ADC Gain Calibration\n");
break;
case ADC_DC_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting ADC DC Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "starting ADC DC Calibration\n");
break;
}
@@ -107,11 +107,11 @@ static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
ah->totalIqCorrMeas[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ah->cal_samples, i, ah->totalPowerMeasI[i],
- ah->totalPowerMeasQ[i],
- ah->totalIqCorrMeas[i]);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ah->cal_samples, i, ah->totalPowerMeasI[i],
+ ah->totalPowerMeasQ[i],
+ ah->totalIqCorrMeas[i]);
}
}
@@ -129,14 +129,13 @@ static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
ah->totalAdcQEvenPhase[i] +=
REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcIOddPhase[i],
- ah->totalAdcIEvenPhase[i],
- ah->totalAdcQOddPhase[i],
- ah->totalAdcQEvenPhase[i]);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcIOddPhase[i],
+ ah->totalAdcIEvenPhase[i],
+ ah->totalAdcQOddPhase[i],
+ ah->totalAdcQEvenPhase[i]);
}
}
@@ -154,14 +153,13 @@ static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
ah->totalAdcDcOffsetQEvenPhase[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcDcOffsetIOddPhase[i],
- ah->totalAdcDcOffsetIEvenPhase[i],
- ah->totalAdcDcOffsetQOddPhase[i],
- ah->totalAdcDcOffsetQEvenPhase[i]);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcDcOffsetIOddPhase[i],
+ ah->totalAdcDcOffsetIEvenPhase[i],
+ ah->totalAdcDcOffsetQOddPhase[i],
+ ah->totalAdcDcOffsetQEvenPhase[i]);
}
}
@@ -178,13 +176,13 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
powerMeasQ = ah->totalPowerMeasQ[i];
iqCorrMeas = ah->totalIqCorrMeas[i];
- ath_print(common, ATH_DBG_CALIBRATE,
- "Starting IQ Cal and Correction for Chain %d\n",
- i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Orignal: Chn %diq_corr_meas = 0x%08x\n",
- i, ah->totalIqCorrMeas[i]);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ah->totalIqCorrMeas[i]);
iqCorrNeg = 0;
@@ -193,12 +191,12 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
iqCorrNeg = 1;
}
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
- ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
- iqCorrNeg);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
qCoffDenom = powerMeasQ / 64;
@@ -207,14 +205,14 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
(qCoffDenom != 0)) {
iCoff = iqCorrMeas / iCoffDenom;
qCoff = powerMeasI / qCoffDenom - 64;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d iCoff = 0x%08x\n", i, iCoff);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d qCoff = 0x%08x\n", i, qCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
iCoff = iCoff & 0x3f;
- ath_print(common, ATH_DBG_CALIBRATE,
- "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
if (iqCorrNeg == 0x0)
iCoff = 0x40 - iCoff;
@@ -223,9 +221,9 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
else if (qCoff <= -16)
qCoff = -16;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
- i, iCoff, qCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
@@ -233,9 +231,9 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
qCoff);
- ath_print(common, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction done for Chain %d\n",
- i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n",
+ i);
}
}
@@ -255,21 +253,21 @@ static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcQOddPhase[i];
qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
- ath_print(common, ATH_DBG_CALIBRATE,
- "Starting ADC Gain Cal for Chain %d\n", i);
-
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
- iOddMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = 0x%08x\n", i,
- iEvenMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
- qOddMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = 0x%08x\n", i,
- qEvenMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Starting ADC Gain Cal for Chain %d\n", i);
+
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+ iOddMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+ iEvenMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+ qOddMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+ qEvenMeasOffset);
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
iGainMismatch =
@@ -279,20 +277,20 @@ static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
((qOddMeasOffset * 32) /
qEvenMeasOffset) & 0x3f;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_i = 0x%08x\n", i,
- iGainMismatch);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_q = 0x%08x\n", i,
- qGainMismatch);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_i = 0x%08x\n", i,
+ iGainMismatch);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_q = 0x%08x\n", i,
+ qGainMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xfffff000;
val |= (qGainMismatch) | (iGainMismatch << 6);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- ath_print(common, ATH_DBG_CALIBRATE,
- "ADC Gain Cal done for Chain %d\n", i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "ADC Gain Cal done for Chain %d\n", i);
}
}
@@ -317,41 +315,41 @@ static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
- ath_print(common, ATH_DBG_CALIBRATE,
- "Starting ADC DC Offset Cal for Chain %d\n", i);
-
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = %d\n", i,
- iOddMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = %d\n", i,
- iEvenMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = %d\n", i,
- qOddMeasOffset);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = %d\n", i,
- qEvenMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = %d\n", i,
+ iOddMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = %d\n", i,
+ iEvenMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = %d\n", i,
+ qOddMeasOffset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = %d\n", i,
+ qEvenMeasOffset);
iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
numSamples) & 0x1ff;
qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
numSamples) & 0x1ff;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
- iDcMismatch);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
- qDcMismatch);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+ iDcMismatch);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+ qDcMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xc0000fff;
val |= (qDcMismatch << 12) | (iDcMismatch << 21);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- ath_print(common, ATH_DBG_CALIBRATE,
- "ADC DC Offset Cal done for Chain %d\n", i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "ADC DC Offset Cal done for Chain %d\n", i);
}
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
@@ -540,7 +538,7 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
{ 0x7838, 0 },
};
- ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
/* PA CAL is not needed for high power solution */
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
@@ -721,9 +719,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
- ath_print(common, ATH_DBG_CALIBRATE, "offset "
- "calibration failed to complete in "
- "1ms; noisy ??\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to complete in 1ms; noisy environment?\n");
return false;
}
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
@@ -736,8 +733,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
- "failed to complete in 1ms; noisy ??\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to complete in 1ms; noisy environment?\n");
return false;
}
@@ -829,9 +826,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "offset calibration failed to "
- "complete in 1ms; noisy environment?\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to complete in 1ms; noisy environment?\n");
return false;
}
@@ -866,19 +862,19 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling ADC Gain Calibration.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling ADC Gain Calibration.\n");
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling ADC DC Calibration.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling ADC DC Calibration.\n");
}
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
ah->cal_list_curr = ah->cal_list;
@@ -958,6 +954,9 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
&adc_dc_cal_multi_sample;
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+
+ if (AR_SREV_9287(ah))
+ ah->supp_cals &= ~ADC_GAIN_CAL;
}
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index a0471f2e1c7a..f8a7771faee2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -22,28 +22,10 @@
int modparam_force_new_ani;
module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
-MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002");
+MODULE_PARM_DESC(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002");
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
-static bool ar9002_hw_macversion_supported(u32 macversion)
-{
- switch (macversion) {
- case AR_SREV_VERSION_5416_PCI:
- case AR_SREV_VERSION_5416_PCIE:
- case AR_SREV_VERSION_9160:
- case AR_SREV_VERSION_9100:
- case AR_SREV_VERSION_9280:
- case AR_SREV_VERSION_9285:
- case AR_SREV_VERSION_9287:
- case AR_SREV_VERSION_9271:
- return true;
- default:
- break;
- }
- return false;
-}
-
static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
{
if (AR_SREV_9271(ah)) {
@@ -410,6 +392,9 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
}
+ if (AR_SREV_9280(ah))
+ val |= AR_WA_BIT22;
+
if (AR_SREV_9285E_20(ah))
val |= AR_WA_BIT23;
@@ -491,9 +476,9 @@ int ar9002_hw_rf_claim(struct ath_hw *ah)
case AR_RAD2122_SREV_MAJOR:
break;
default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Radio Chip Rev 0x%02X not supported\n",
- val & AR_RADIO_SREV_MAJOR);
+ ath_err(ath9k_hw_common(ah),
+ "Radio Chip Rev 0x%02X not supported\n",
+ val & AR_RADIO_SREV_MAJOR);
return -EOPNOTSUPP;
}
@@ -562,7 +547,6 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
- priv_ops->macversion_supported = ar9002_hw_macversion_supported;
ops->config_pci_powersave = ar9002_hw_configpcipowersave;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 50dda394f8be..399ab3bb299b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -90,13 +90,10 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
*masked = isr & ATH9K_INT_COMMON;
- if (ah->config.rx_intr_mitigation) {
- if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
- *masked |= ATH9K_INT_RX;
- }
-
- if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
+ if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM |
+ AR_ISR_RXOK | AR_ISR_RXERR))
*masked |= ATH9K_INT_RX;
+
if (isr &
(AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
AR_ISR_TXEOL)) {
@@ -114,16 +111,8 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
}
if (isr & AR_ISR_RXORN) {
- ath_print(common, ATH_DBG_INTERRUPT,
- "receive FIFO overrun interrupt\n");
- }
-
- if (!AR_SREV_9100(ah)) {
- if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
- u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
- if (isr5 & AR_ISR_S5_TIM_TIMER)
- *masked |= ATH9K_INT_TIM_TIMER;
- }
+ ath_dbg(common, ATH_DBG_INTERRUPT,
+ "receive FIFO overrun interrupt\n");
}
*masked |= mask2;
@@ -136,17 +125,18 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
u32 s5_s;
s5_s = REG_READ(ah, AR_ISR_S5_S);
- if (isr & AR_ISR_GENTMR) {
- ah->intr_gen_timer_trigger =
+ ah->intr_gen_timer_trigger =
MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
- ah->intr_gen_timer_thresh =
- MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
+ ah->intr_gen_timer_thresh =
+ MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
- if (ah->intr_gen_timer_trigger)
- *masked |= ATH9K_INT_GENTIMER;
+ if (ah->intr_gen_timer_trigger)
+ *masked |= ATH9K_INT_GENTIMER;
- }
+ if ((s5_s & AR_ISR_S5_TIM_TIMER) &&
+ !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ *masked |= ATH9K_INT_TIM_TIMER;
}
if (sync_cause) {
@@ -157,25 +147,25 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
if (fatal_int) {
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
- ath_print(common, ATH_DBG_ANY,
- "received PCI FATAL interrupt\n");
+ ath_dbg(common, ATH_DBG_ANY,
+ "received PCI FATAL interrupt\n");
}
if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
- ath_print(common, ATH_DBG_ANY,
- "received PCI PERR interrupt\n");
+ ath_dbg(common, ATH_DBG_ANY,
+ "received PCI PERR interrupt\n");
}
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
- ath_print(common, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+ ath_dbg(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
REG_WRITE(ah, AR_RC, 0);
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
- ath_print(common, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+ ath_dbg(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
}
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
@@ -218,77 +208,70 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts)
{
struct ar5416_desc *ads = AR5416DESC(ds);
+ u32 status;
- if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+ status = ACCESS_ONCE(ads->ds_txstatus9);
+ if ((status & AR_TxDone) == 0)
return -EINPROGRESS;
- ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
ts->ts_tstamp = ads->AR_SendTimestamp;
ts->ts_status = 0;
ts->ts_flags = 0;
- if (ads->ds_txstatus1 & AR_FrmXmitOK)
+ if (status & AR_TxOpExceeded)
+ ts->ts_status |= ATH9K_TXERR_XTXOP;
+ ts->tid = MS(status, AR_TxTid);
+ ts->ts_rateindex = MS(status, AR_FinalTxIdx);
+ ts->ts_seqnum = MS(status, AR_SeqNum);
+
+ status = ACCESS_ONCE(ads->ds_txstatus0);
+ ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
+ ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
+ ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02);
+ if (status & AR_TxBaStatus) {
+ ts->ts_flags |= ATH9K_TX_BA;
+ ts->ba_low = ads->AR_BaBitmapLow;
+ ts->ba_high = ads->AR_BaBitmapHigh;
+ }
+
+ status = ACCESS_ONCE(ads->ds_txstatus1);
+ if (status & AR_FrmXmitOK)
ts->ts_status |= ATH9K_TX_ACKED;
- if (ads->ds_txstatus1 & AR_ExcessiveRetries)
- ts->ts_status |= ATH9K_TXERR_XRETRY;
- if (ads->ds_txstatus1 & AR_Filtered)
- ts->ts_status |= ATH9K_TXERR_FILT;
- if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
- ts->ts_status |= ATH9K_TXERR_FIFO;
- ath9k_hw_updatetxtriglevel(ah, true);
+ else {
+ if (status & AR_ExcessiveRetries)
+ ts->ts_status |= ATH9K_TXERR_XRETRY;
+ if (status & AR_Filtered)
+ ts->ts_status |= ATH9K_TXERR_FILT;
+ if (status & AR_FIFOUnderrun) {
+ ts->ts_status |= ATH9K_TXERR_FIFO;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
}
- if (ads->ds_txstatus9 & AR_TxOpExceeded)
- ts->ts_status |= ATH9K_TXERR_XTXOP;
- if (ads->ds_txstatus1 & AR_TxTimerExpired)
+ if (status & AR_TxTimerExpired)
ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
- if (ads->ds_txstatus1 & AR_DescCfgErr)
+ if (status & AR_DescCfgErr)
ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
- if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+ if (status & AR_TxDataUnderrun) {
ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
ath9k_hw_updatetxtriglevel(ah, true);
}
- if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+ if (status & AR_TxDelimUnderrun) {
ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
ath9k_hw_updatetxtriglevel(ah, true);
}
- if (ads->ds_txstatus0 & AR_TxBaStatus) {
- ts->ts_flags |= ATH9K_TX_BA;
- ts->ba_low = ads->AR_BaBitmapLow;
- ts->ba_high = ads->AR_BaBitmapHigh;
- }
+ ts->ts_shortretry = MS(status, AR_RTSFailCnt);
+ ts->ts_longretry = MS(status, AR_DataFailCnt);
+ ts->ts_virtcol = MS(status, AR_VirtRetryCnt);
- ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
- switch (ts->ts_rateindex) {
- case 0:
- ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
- break;
- case 1:
- ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
- break;
- case 2:
- ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
- break;
- case 3:
- ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
- break;
- }
+ status = ACCESS_ONCE(ads->ds_txstatus5);
+ ts->ts_rssi = MS(status, AR_TxRSSICombined);
+ ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10);
+ ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
+ ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
- ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
- ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
- ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
- ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
- ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
- ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
- ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
ts->evm0 = ads->AR_TxEVM0;
ts->evm1 = ads->AR_TxEVM1;
ts->evm2 = ads->AR_TxEVM2;
- ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
- ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
- ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
- ts->tid = MS(ads->ds_txstatus9, AR_TxTid);
- ts->ts_antenna = 0;
return 0;
}
@@ -300,7 +283,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
{
struct ar5416_desc *ads = AR5416DESC(ds);
- txPower += ah->txpower_indexoffset;
if (txPower > 63)
txPower = 63;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index c00cdc67b55b..7d68d61e406b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -175,13 +175,15 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
int upper, lower, cur_vit_mask;
int tmp, newVal;
int i;
- int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
- AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+ static const int pilot_mask_reg[4] = {
+ AR_PHY_TIMING7, AR_PHY_TIMING8,
+ AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
};
- int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
- AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+ static const int chan_mask_reg[4] = {
+ AR_PHY_TIMING9, AR_PHY_TIMING10,
+ AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
};
- int inc[4] = { 0, 100, 0, 0 };
+ static const int inc[4] = { 0, 100, 0, 0 };
struct chan_centers centers;
int8_t mask_m[123];
@@ -201,13 +203,14 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+ if (AR_NO_SPUR == cur_bb_spur)
+ break;
+
if (is2GHz)
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
else
cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
- if (AR_NO_SPUR == cur_bb_spur)
- break;
cur_bb_spur = cur_bb_spur - freq;
if (IS_CHAN_HT40(chan)) {
@@ -473,21 +476,21 @@ static void ar9002_hw_do_getnf(struct ath_hw *ah,
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
- nfarray[0] = sign_extend(nf, 9);
+ nfarray[0] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
if (IS_CHAN_HT40(ah->curchan))
- nfarray[3] = sign_extend(nf, 9);
+ nfarray[3] = sign_extend32(nf, 8);
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
return;
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
- nfarray[1] = sign_extend(nf, 9);
+ nfarray[1] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR);
if (IS_CHAN_HT40(ah->curchan))
- nfarray[4] = sign_extend(nf, 9);
+ nfarray[4] = sign_extend32(nf, 8);
}
static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index a14a5e43cf56..81f9cf294dec 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -34,9 +34,9 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -56,21 +56,21 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
- {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
- {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
- {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
- {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
- {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
- {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
- {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
- {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
- {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -88,44 +88,44 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
- {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
- {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
- {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
- {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
- {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
- {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
- {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
- {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
- {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
@@ -638,6 +638,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
{0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f},
{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
@@ -680,7 +681,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000981c, 0x00020028},
{0x00009834, 0x6400a290},
{0x00009838, 0x0108ecff},
- {0x0000983c, 0x14750600},
+ {0x0000983c, 0x0d000600},
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
@@ -722,7 +723,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a220, 0x00000000},
{0x0000a224, 0x00000000},
{0x0000a228, 0x10002310},
- {0x0000a22c, 0x01036a27},
{0x0000a23c, 0x00000000},
{0x0000a244, 0x0c000000},
{0x0000a2a0, 0x00000001},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 9e6edffe0bd1..4a4cd88429c0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -18,6 +18,16 @@
#include "hw-ops.h"
#include "ar9003_phy.h"
+#define MPASS 3
+#define MAX_MEASUREMENT 8
+#define MAX_DIFFERENCE 10
+
+struct coeff {
+ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
+ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
+ int iqc_coeff[2];
+};
+
enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0),
TEMP_COMP_CAL = BIT(1),
@@ -40,8 +50,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
currCal->calData->calCountMax);
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting IQ Mismatch Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "starting IQ Mismatch Calibration\n");
/* Kick-off cal */
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
@@ -52,8 +62,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
AR_PHY_65NM_CH0_THERM_START, 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting Temperature Compensation Calibration\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "starting Temperature Compensation Calibration\n");
break;
}
}
@@ -181,11 +191,11 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
ah->totalIqCorrMeas[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ah->cal_samples, i, ah->totalPowerMeasI[i],
- ah->totalPowerMeasQ[i],
- ah->totalIqCorrMeas[i]);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ah->cal_samples, i, ah->totalPowerMeasI[i],
+ ah->totalPowerMeasQ[i],
+ ah->totalIqCorrMeas[i]);
}
}
@@ -196,7 +206,7 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
u32 qCoffDenom, iCoffDenom;
int32_t qCoff, iCoff;
int iqCorrNeg, i;
- const u_int32_t offset_array[3] = {
+ static const u_int32_t offset_array[3] = {
AR_PHY_RX_IQCAL_CORR_B0,
AR_PHY_RX_IQCAL_CORR_B1,
AR_PHY_RX_IQCAL_CORR_B2,
@@ -207,13 +217,13 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
powerMeasQ = ah->totalPowerMeasQ[i];
iqCorrMeas = ah->totalIqCorrMeas[i];
- ath_print(common, ATH_DBG_CALIBRATE,
- "Starting IQ Cal and Correction for Chain %d\n",
- i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Orignal: Chn %diq_corr_meas = 0x%08x\n",
- i, ah->totalIqCorrMeas[i]);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ah->totalIqCorrMeas[i]);
iqCorrNeg = 0;
@@ -222,12 +232,12 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
iqCorrNeg = 1;
}
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
- ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
- iqCorrNeg);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
qCoffDenom = powerMeasQ / 64;
@@ -235,10 +245,10 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
iCoff = iqCorrMeas / iCoffDenom;
qCoff = powerMeasI / qCoffDenom - 64;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d iCoff = 0x%08x\n", i, iCoff);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d qCoff = 0x%08x\n", i, qCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
/* Force bounds on iCoff */
if (iCoff >= 63)
@@ -259,14 +269,13 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
iCoff = iCoff & 0x7f;
qCoff = qCoff & 0x7f;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
- i, iCoff, qCoff);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Register offset (0x%04x) "
- "before update = 0x%x\n",
- offset_array[i],
- REG_READ(ah, offset_array[i]));
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Register offset (0x%04x) before update = 0x%x\n",
+ offset_array[i],
+ REG_READ(ah, offset_array[i]));
REG_RMW_FIELD(ah, offset_array[i],
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
@@ -274,33 +283,29 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
REG_RMW_FIELD(ah, offset_array[i],
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
qCoff);
- ath_print(common, ATH_DBG_CALIBRATE,
- "Register offset (0x%04x) QI COFF "
- "(bitfields 0x%08x) after update = 0x%x\n",
- offset_array[i],
- AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
- REG_READ(ah, offset_array[i]));
- ath_print(common, ATH_DBG_CALIBRATE,
- "Register offset (0x%04x) QQ COFF "
- "(bitfields 0x%08x) after update = 0x%x\n",
- offset_array[i],
- AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
- REG_READ(ah, offset_array[i]));
-
- ath_print(common, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction done for Chain %d\n",
- i);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
+ offset_array[i],
+ AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
+ REG_READ(ah, offset_array[i]));
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
+ offset_array[i],
+ AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
+ REG_READ(ah, offset_array[i]));
+
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n", i);
}
}
REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
- ath_print(common, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction (offset 0x%04x) enabled "
- "(bit position 0x%08x). New Value 0x%08x\n",
- (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
- AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
- REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
+ (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
+ AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
+ REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
}
static const struct ath9k_percal_data iq_cal_single_sample = {
@@ -340,7 +345,7 @@ static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
f2 = (f1 * f1 + f3 * f3) / result_shift;
if (!f2) {
- ath_print(common, ATH_DBG_CALIBRATE, "Divide by 0\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0\n");
return false;
}
@@ -461,11 +466,14 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
(i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Divide by 0:\na0_d0=%d\n"
- "a0_d1=%d\na2_d0=%d\na1_d1=%d\n",
- i2_p_q2_a0_d0, i2_p_q2_a0_d1,
- i2_p_q2_a1_d0, i2_p_q2_a1_d1);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Divide by 0:\n"
+ "a0_d0=%d\n"
+ "a0_d1=%d\n"
+ "a2_d0=%d\n"
+ "a1_d1=%d\n",
+ i2_p_q2_a0_d0, i2_p_q2_a0_d1,
+ i2_p_q2_a1_d0, i2_p_q2_a1_d1);
return false;
}
@@ -498,9 +506,9 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
if ((mag1 == 0) || (mag2 == 0)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Divide by 0: mag1=%d, mag2=%d\n",
- mag1, mag2);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Divide by 0: mag1=%d, mag2=%d\n",
+ mag1, mag2);
return false;
}
@@ -517,8 +525,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
mag_a0_d0, phs_a0_d0,
mag_a1_d0,
phs_a1_d0, solved_eq)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Call to ar9003_hw_solve_iq_cal() failed.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Call to ar9003_hw_solve_iq_cal() failed.\n");
return false;
}
@@ -527,14 +535,14 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
mag_rx = solved_eq[2];
phs_rx = solved_eq[3];
- ath_print(common, ATH_DBG_CALIBRATE,
- "chain %d: mag mismatch=%d phase mismatch=%d\n",
- chain_idx, mag_tx/res_scale, phs_tx/res_scale);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "chain %d: mag mismatch=%d phase mismatch=%d\n",
+ chain_idx, mag_tx/res_scale, phs_tx/res_scale);
if (res_scale == mag_tx) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Divide by 0: mag_tx=%d, res_scale=%d\n",
- mag_tx, res_scale);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Divide by 0: mag_tx=%d, res_scale=%d\n",
+ mag_tx, res_scale);
return false;
}
@@ -545,9 +553,9 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
q_q_coff = (mag_corr_tx * 128 / res_scale);
q_i_coff = (phs_corr_tx * 256 / res_scale);
- ath_print(common, ATH_DBG_CALIBRATE,
- "tx chain %d: mag corr=%d phase corr=%d\n",
- chain_idx, q_q_coff, q_i_coff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "tx chain %d: mag corr=%d phase corr=%d\n",
+ chain_idx, q_q_coff, q_i_coff);
if (q_i_coff < -63)
q_i_coff = -63;
@@ -560,14 +568,14 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
- ath_print(common, ATH_DBG_CALIBRATE,
- "tx chain %d: iq corr coeff=%x\n",
- chain_idx, iqc_coeff[0]);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "tx chain %d: iq corr coeff=%x\n",
+ chain_idx, iqc_coeff[0]);
if (-mag_rx == res_scale) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Divide by 0: mag_rx=%d, res_scale=%d\n",
- mag_rx, res_scale);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Divide by 0: mag_rx=%d, res_scale=%d\n",
+ mag_rx, res_scale);
return false;
}
@@ -578,9 +586,9 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
q_q_coff = (mag_corr_rx * 128 / res_scale);
q_i_coff = (phs_corr_rx * 256 / res_scale);
- ath_print(common, ATH_DBG_CALIBRATE,
- "rx chain %d: mag corr=%d phase corr=%d\n",
- chain_idx, q_q_coff, q_i_coff);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "rx chain %d: mag corr=%d phase corr=%d\n",
+ chain_idx, q_q_coff, q_i_coff);
if (q_i_coff < -63)
q_i_coff = -63;
@@ -593,140 +601,367 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
- ath_print(common, ATH_DBG_CALIBRATE,
- "rx chain %d: iq corr coeff=%x\n",
- chain_idx, iqc_coeff[1]);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "rx chain %d: iq corr coeff=%x\n",
+ chain_idx, iqc_coeff[1]);
+
+ return true;
+}
+
+static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
+{
+ int diff[MPASS];
+
+ diff[0] = abs(mp_coeff[0] - mp_coeff[1]);
+ diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
+ diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
+
+ if (diff[0] > MAX_DIFFERENCE &&
+ diff[1] > MAX_DIFFERENCE &&
+ diff[2] > MAX_DIFFERENCE)
+ return false;
+
+ if (diff[0] <= diff[1] && diff[0] <= diff[2])
+ *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2;
+ else if (diff[1] <= diff[2])
+ *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2;
+ else
+ *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2;
return true;
}
+static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
+ u8 num_chains,
+ struct coeff *coeff)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ int i, im, nmeasurement;
+ int magnitude, phase;
+ u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+
+ memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
+ for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
+ tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
+ if (!AR_SREV_9485(ah)) {
+ tx_corr_coeff[i * 2][1] =
+ tx_corr_coeff[(i * 2) + 1][1] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
+
+ tx_corr_coeff[i * 2][2] =
+ tx_corr_coeff[(i * 2) + 1][2] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
+ }
+ }
+
+ /* Load the average of 2 passes */
+ for (i = 0; i < num_chains; i++) {
+ if (AR_SREV_9485(ah))
+ nmeasurement = REG_READ_FIELD(ah,
+ AR_PHY_TX_IQCAL_STATUS_B0_9485,
+ AR_PHY_CALIBRATED_GAINS_0);
+ else
+ nmeasurement = REG_READ_FIELD(ah,
+ AR_PHY_TX_IQCAL_STATUS_B0,
+ AR_PHY_CALIBRATED_GAINS_0);
+
+ if (nmeasurement > MAX_MEASUREMENT)
+ nmeasurement = MAX_MEASUREMENT;
+
+ for (im = 0; im < nmeasurement; im++) {
+ /*
+ * Determine which 2 passes are closest and compute avg
+ * magnitude
+ */
+ if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im],
+ &magnitude))
+ goto disable_txiqcal;
+
+ /*
+ * Determine which 2 passes are closest and compute avg
+ * phase
+ */
+ if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im],
+ &phase))
+ goto disable_txiqcal;
+
+ coeff->iqc_coeff[0] = (magnitude & 0x7f) |
+ ((phase & 0x7f) << 7);
+
+ if ((im % 2) == 0)
+ REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+ AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
+ coeff->iqc_coeff[0]);
+ else
+ REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+ AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
+ coeff->iqc_coeff[0]);
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+ AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
+ REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+ AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
+
+ return;
+
+disable_txiqcal:
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+ AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0);
+ REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+ AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0);
+
+ ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
+}
+
static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+ static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_TX_IQCAL_STATUS_B1,
AR_PHY_TX_IQCAL_STATUS_B2,
};
- const u32 tx_corr_coeff[AR9300_MAX_CHAINS] = {
- AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
- AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
- AR_PHY_TX_IQCAL_CORR_COEFF_01_B2,
- };
- const u32 rx_corr[AR9300_MAX_CHAINS] = {
- AR_PHY_RX_IQCAL_CORR_B0,
- AR_PHY_RX_IQCAL_CORR_B1,
- AR_PHY_RX_IQCAL_CORR_B2,
- };
- const u_int32_t chan_info_tab[] = {
+ static const u32 chan_info_tab[] = {
AR_PHY_CHAN_INFO_TAB_0,
AR_PHY_CHAN_INFO_TAB_1,
AR_PHY_CHAN_INFO_TAB_2,
};
+ struct coeff coeff;
s32 iq_res[6];
- s32 iqc_coeff[2];
- s32 i, j;
- u32 num_chains = 0;
+ s32 i, j, ip, im, nmeasurement;
+ u8 nchains = get_streams(common->tx_chainmask);
+
+ for (ip = 0; ip < MPASS; ip++) {
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+ AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+ DELPT);
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+ AR_PHY_TX_IQCAL_START_DO_CAL,
+ AR_PHY_TX_IQCAL_START_DO_CAL);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+ AR_PHY_TX_IQCAL_START_DO_CAL,
+ 0, AH_WAIT_TIMEOUT)) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Tx IQ Cal not complete.\n");
+ goto TX_IQ_CAL_FAILED;
+ }
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (ah->txchainmask & (1 << i))
- num_chains++;
- }
+ nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
+ AR_PHY_CALIBRATED_GAINS_0);
+ if (nmeasurement > MAX_MEASUREMENT)
+ nmeasurement = MAX_MEASUREMENT;
+
+ for (i = 0; i < nchains; i++) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Doing Tx IQ Cal for chain %d.\n", i);
+ for (im = 0; im < nmeasurement; im++) {
+ if (REG_READ(ah, txiqcal_status[i]) &
+ AR_PHY_TX_IQCAL_STATUS_FAILED) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Tx IQ Cal failed for chain %d.\n", i);
+ goto TX_IQ_CAL_FAILED;
+ }
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
- AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
- DELPT);
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
- AR_PHY_TX_IQCAL_START_DO_CAL,
- AR_PHY_TX_IQCAL_START_DO_CAL);
+ for (j = 0; j < 3; j++) {
+ u8 idx = 2 * j,
+ offset = 4 * (3 * im + j);
- if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
- AR_PHY_TX_IQCAL_START_DO_CAL,
- 0, AH_WAIT_TIMEOUT)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Tx IQ Cal not complete.\n");
- goto TX_IQ_CAL_FAILED;
- }
+ REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_TAB_S2_READ,
+ 0);
- for (i = 0; i < num_chains; i++) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Doing Tx IQ Cal for chain %d.\n", i);
+ /* 32 bits */
+ iq_res[idx] = REG_READ(ah,
+ chan_info_tab[i] +
+ offset);
- if (REG_READ(ah, txiqcal_status[i]) &
- AR_PHY_TX_IQCAL_STATUS_FAILED) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Tx IQ Cal failed for chain %d.\n", i);
- goto TX_IQ_CAL_FAILED;
- }
+ REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_TAB_S2_READ,
+ 1);
- for (j = 0; j < 3; j++) {
- u_int8_t idx = 2 * j,
- offset = 4 * j;
+ /* 16 bits */
+ iq_res[idx+1] = 0xffff & REG_READ(ah,
+ chan_info_tab[i] +
+ offset);
- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
- AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
-
- /* 32 bits */
- iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
+ idx, iq_res[idx], idx+1, iq_res[idx+1]);
+ }
- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
- AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
+ if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+ coeff.iqc_coeff)) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Failed in calculation of IQ correction.\n");
+ goto TX_IQ_CAL_FAILED;
+ }
+ coeff.mag_coeff[i][im][ip] =
+ coeff.iqc_coeff[0] & 0x7f;
+ coeff.phs_coeff[i][im][ip] =
+ (coeff.iqc_coeff[0] >> 7) & 0x7f;
- /* 16 bits */
- iq_res[idx+1] = 0xffff & REG_READ(ah,
- chan_info_tab[i] +
- offset);
+ if (coeff.mag_coeff[i][im][ip] > 63)
+ coeff.mag_coeff[i][im][ip] -= 128;
+ if (coeff.phs_coeff[i][im][ip] > 63)
+ coeff.phs_coeff[i][im][ip] -= 128;
- ath_print(common, ATH_DBG_CALIBRATE,
- "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
- idx, iq_res[idx], idx+1, iq_res[idx+1]);
- }
-
- if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Failed in calculation of IQ correction.\n");
- goto TX_IQ_CAL_FAILED;
+ }
}
-
- ath_print(common, ATH_DBG_CALIBRATE,
- "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n",
- iqc_coeff[0], iqc_coeff[1]);
-
- REG_RMW_FIELD(ah, tx_corr_coeff[i],
- AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
- iqc_coeff[0]);
- REG_RMW_FIELD(ah, rx_corr[i],
- AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF,
- iqc_coeff[1] >> 7);
- REG_RMW_FIELD(ah, rx_corr[i],
- AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF,
- iqc_coeff[1]);
}
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
- AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
- REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
- AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
+ ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
return;
TX_IQ_CAL_FAILED:
- ath_print(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+}
+
+static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
+{
+ u8 tx_gain_forced;
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485,
+ AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
+ tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TXGAIN_FORCE);
+ if (tx_gain_forced)
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TXGAIN_FORCE, 0);
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485,
+ AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1);
}
+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+ AR_PHY_TX_IQCAL_STATUS_B0_9485,
+ AR_PHY_TX_IQCAL_STATUS_B1,
+ AR_PHY_TX_IQCAL_STATUS_B2,
+ };
+ const u_int32_t chan_info_tab[] = {
+ AR_PHY_CHAN_INFO_TAB_0,
+ AR_PHY_CHAN_INFO_TAB_1,
+ AR_PHY_CHAN_INFO_TAB_2,
+ };
+ struct coeff coeff;
+ s32 iq_res[6];
+ u8 num_chains = 0;
+ int i, ip, im, j;
+ int nmeasurement;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (ah->txchainmask & (1 << i))
+ num_chains++;
+ }
+
+ for (ip = 0; ip < MPASS; ip++) {
+ for (i = 0; i < num_chains; i++) {
+ nmeasurement = REG_READ_FIELD(ah,
+ AR_PHY_TX_IQCAL_STATUS_B0_9485,
+ AR_PHY_CALIBRATED_GAINS_0);
+ if (nmeasurement > MAX_MEASUREMENT)
+ nmeasurement = MAX_MEASUREMENT;
+
+ for (im = 0; im < nmeasurement; im++) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Doing Tx IQ Cal for chain %d.\n", i);
+
+ if (REG_READ(ah, txiqcal_status[i]) &
+ AR_PHY_TX_IQCAL_STATUS_FAILED) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Tx IQ Cal failed for chain %d.\n", i);
+ goto tx_iqcal_fail;
+ }
+
+ for (j = 0; j < 3; j++) {
+ u32 idx = 2 * j, offset = 4 * (3 * im + j);
+
+ REG_RMW_FIELD(ah,
+ AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_TAB_S2_READ,
+ 0);
+
+ /* 32 bits */
+ iq_res[idx] = REG_READ(ah,
+ chan_info_tab[i] +
+ offset);
+
+ REG_RMW_FIELD(ah,
+ AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_TAB_S2_READ,
+ 1);
+
+ /* 16 bits */
+ iq_res[idx + 1] = 0xffff & REG_READ(ah,
+ chan_info_tab[i] + offset);
+
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ RES[%d]=0x%x"
+ "IQ_RES[%d]=0x%x\n",
+ idx, iq_res[idx], idx + 1,
+ iq_res[idx + 1]);
+ }
+
+ if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+ coeff.iqc_coeff)) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Failed in calculation of IQ correction.\n");
+ goto tx_iqcal_fail;
+ }
+
+ coeff.mag_coeff[i][im][ip] =
+ coeff.iqc_coeff[0] & 0x7f;
+ coeff.phs_coeff[i][im][ip] =
+ (coeff.iqc_coeff[0] >> 7) & 0x7f;
+
+ if (coeff.mag_coeff[i][im][ip] > 63)
+ coeff.mag_coeff[i][im][ip] -= 128;
+ if (coeff.phs_coeff[i][im][ip] > 63)
+ coeff.phs_coeff[i][im][ip] -= 128;
+ }
+ }
+ }
+ ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
+
+ return;
+
+tx_iqcal_fail:
+ ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+ return;
+}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
+ int val;
- /*
- * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain mode before
- * running AGC/TxIQ cals
- */
- ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+ val = REG_READ(ah, AR_ENT_OTP);
+ ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val);
+
+ if (AR_SREV_9485(ah))
+ ar9003_hw_set_chain_masks(ah, 0x1, 0x1);
+ else if (val & AR_ENT_OTP_CHAIN2_DISABLE)
+ ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
+ else
+ /*
+ * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain
+ * mode before running AGC/TxIQ cals
+ */
+ ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
/* Do Tx IQ Calibration */
- ar9003_hw_tx_iq_cal(ah);
+ if (AR_SREV_9485(ah))
+ ar9003_hw_tx_iq_cal_run(ah);
+ else
+ ar9003_hw_tx_iq_cal(ah);
+
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
@@ -739,12 +974,14 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
/* Poll for offset calibration complete */
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "offset calibration failed to "
- "complete in 1ms; noisy environment?\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to complete in 1ms; noisy environment?\n");
return false;
}
+ if (AR_SREV_9485(ah))
+ ar9003_hw_tx_iq_cal_post_proc(ah);
+
/* Revert chainmasks to their original values before NF cal */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
@@ -757,15 +994,15 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (ah->supp_cals & IQ_MISMATCH_CAL) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
}
if (ah->supp_cals & TEMP_COMP_CAL) {
INIT_CAL(&ah->tempCompCalData);
INSERT_CAL(ah, &ah->tempCompCalData);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling Temperature Compensation Calibration.\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling Temperature Compensation Calibration.\n");
}
/* Initialize current pointer to first element in list */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index c4182359bee4..4819747fa4c3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -22,12 +22,14 @@
#define COMP_CKSUM_LEN 2
#define AR_CH0_TOP (0x00016288)
-#define AR_CH0_TOP_XPABIASLVL (0x3)
+#define AR_CH0_TOP_XPABIASLVL (0x300)
#define AR_CH0_TOP_XPABIASLVL_S (8)
#define AR_CH0_THERM (0x00016290)
-#define AR_CH0_THERM_SPARE (0x3f)
-#define AR_CH0_THERM_SPARE_S (0)
+#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
+#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
+#define AR_CH0_THERM_XPASHORT2GND 0x4
+#define AR_CH0_THERM_XPASHORT2GND_S 2
#define AR_SWITCH_TABLE_COM_ALL (0xffff)
#define AR_SWITCH_TABLE_COM_ALL_S (0)
@@ -55,6 +57,14 @@
#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */
#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */
+#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
+
+#define EEPROM_DATA_LEN_9485 1088
+
+static int ar9003_hw_power_interpolate(int32_t x,
+ int32_t *px, int32_t *py, u_int16_t np);
+
+
static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
@@ -65,7 +75,7 @@ static const struct ar9300_eeprom ar9300_default = {
.regDmn = { LE16(0), LE16(0x1f) },
.txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
.opCapFlags = {
- .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A,
+ .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
.eepMisc = 0,
},
.rfSilent = 0,
@@ -144,13 +154,16 @@ static const struct ar9300_eeprom ar9300_default = {
.txEndToRxOn = 0x2,
.txFrameToXpaOn = 0xe,
.thresh62 = 28,
- .papdRateMaskHt20 = LE32(0x80c080),
- .papdRateMaskHt40 = LE32(0x80c080),
+ .papdRateMaskHt20 = LE32(0x0cf0e0e0),
+ .papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
},
+ .base_ext1 = {
+ .ant_div_control = 0,
+ .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
.calFreqPier2G = {
FREQ2FBIN(2412, 1),
FREQ2FBIN(2437, 1),
@@ -285,25 +298,25 @@ static const struct ar9300_eeprom ar9300_default = {
/* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
/* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
/* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
- /* Data[11].ctlEdges[3].bChannel */
- FREQ2FBIN(2462, 1),
+ /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
}
},
.ctlPowerData_2G = {
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
- { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
- { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
- { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
- { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
},
.modalHeader5G = {
/* 4 idle,t1,t2,b (4 bits per setting) */
@@ -343,13 +356,20 @@ static const struct ar9300_eeprom ar9300_default = {
.txEndToRxOn = 0x2,
.txFrameToXpaOn = 0xe,
.thresh62 = 28,
- .papdRateMaskHt20 = LE32(0xf0e0e0),
- .papdRateMaskHt40 = LE32(0xf0e0e0),
+ .papdRateMaskHt20 = LE32(0x0c80c080),
+ .papdRateMaskHt40 = LE32(0x0080c080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
},
+ .base_ext2 = {
+ .tempSlopeLow = 0,
+ .tempSlopeHigh = 0,
+ .xatten1DBLow = {0, 0, 0},
+ .xatten1MarginLow = {0, 0, 0},
+ .xatten1DBHigh = {0, 0, 0},
+ .xatten1MarginHigh = {0, 0, 0}
+ },
.calFreqPier5G = {
FREQ2FBIN(5180, 0),
FREQ2FBIN(5220, 0),
@@ -568,64 +588,2396 @@ static const struct ar9300_eeprom ar9300_default = {
.ctlPowerData_5G = {
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ }
+ },
+ }
+};
+
+static const struct ar9300_eeprom ar9300_x113 = {
+ .eepromVersion = 2,
+ .templateVersion = 6,
+ .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+ .custData = {"x113-023-f0000"},
+ .baseEepHeader = {
+ .regDmn = { LE16(0), LE16(0x1f) },
+ .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
+ .opCapFlags = {
+ .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .eepMisc = 0,
+ },
+ .rfSilent = 0,
+ .blueToothOptions = 0,
+ .deviceCap = 0,
+ .deviceType = 5, /* takes lower byte in eeprom location */
+ .pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+ .params_for_tuning_caps = {0, 0},
+ .featureEnable = 0x0d,
+ /*
+ * bit0 - enable tx temp comp - disabled
+ * bit1 - enable tx volt comp - disabled
+ * bit2 - enable fastClock - enabled
+ * bit3 - enable doubling - enabled
+ * bit4 - enable internal regulator - disabled
+ * bit5 - enable pa predistortion - disabled
+ */
+ .miscConfiguration = 0, /* bit0 - turn down drivestrength */
+ .eepromWriteEnableGpio = 6,
+ .wlanDisableGpio = 0,
+ .wlanLedGpio = 8,
+ .rxBandSelectGpio = 0xff,
+ .txrxgain = 0x21,
+ .swreg = 0,
+ },
+ .modalHeader2G = {
+ /* ar9300_modal_eep_header 2g */
+ /* 4 idle,t1,t2,b(4 bits per setting) */
+ .antCtrlCommon = LE32(0x110),
+ /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+ .antCtrlCommon2 = LE32(0x44444),
+
+ /*
+ * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+ * rx1, rx12, b (2 bits each)
+ */
+ .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+ /*
+ * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db
+ * for ar9280 (0xa20c/b20c 5:0)
+ */
+ .xatten1DB = {0, 0, 0},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for ar9280 (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0, 0, 0},
+ .tempSlope = 25,
+ .voltSlope = 0,
+
+ /*
+ * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+ * channels in usual fbin coding format
+ */
+ .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+ /*
+ * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+ * if the register is per chain
+ */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {1, 1, 1},/* 3 chain */
+ .db_stage2 = {1, 1, 1}, /* 3 chain */
+ .db_stage3 = {0, 0, 0},
+ .db_stage4 = {0, 0, 0},
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2c,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0c80c080),
+ .papdRateMaskHt40 = LE32(0x0080c080),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext1 = {
+ .ant_div_control = 0,
+ .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ .calFreqPier2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ /* ar9300_cal_data_per_freq_op_loop 2g */
+ .calPierData2G = {
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ },
+ .calTarget_freqbin_Cck = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ .calTarget_freqbin_2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT20 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT40 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTargetPowerCck = {
+ /* 1L-5L,5S,11L,11S */
+ { {34, 34, 34, 34} },
+ { {34, 34, 34, 34} },
+ },
+ .calTargetPower2G = {
+ /* 6-24,36,48,54 */
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ },
+ .calTargetPower2GHT20 = {
+ { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+ { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+ { {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+ },
+ .calTargetPower2GHT40 = {
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ },
+ .ctlIndex_2G = {
+ 0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+ 0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+ },
+ .ctl_freqbin_2G = {
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2457, 1),
+ FREQ2FBIN(2462, 1)
+ },
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+ {
+ FREQ2FBIN(2422, 1),
+ FREQ2FBIN(2427, 1),
+ FREQ2FBIN(2447, 1),
+ FREQ2FBIN(2452, 1)
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ },
+
+ {
+ /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ }
+ },
+ .ctlPowerData_2G = {
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ },
+ .modalHeader5G = {
+ /* 4 idle,t1,t2,b (4 bits per setting) */
+ .antCtrlCommon = LE32(0x220),
+ /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+ .antCtrlCommon2 = LE32(0x11111),
+ /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+ .antCtrlChain = {
+ LE16(0x150), LE16(0x150), LE16(0x150),
+ },
+ /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+ .xatten1DB = {0, 0, 0},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for merlin (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0, 0, 0},
+ .tempSlope = 68,
+ .voltSlope = 0,
+ /* spurChans spur channels in usual fbin coding format */
+ .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0},
+ /* noiseFloorThreshCh Check if the register is per chain */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {3, 3, 3}, /* 3 chain */
+ .db_stage2 = {3, 3, 3}, /* 3 chain */
+ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2d,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0cf0e0e0),
+ .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext2 = {
+ .tempSlopeLow = 72,
+ .tempSlopeHigh = 105,
+ .xatten1DBLow = {0, 0, 0},
+ .xatten1MarginLow = {0, 0, 0},
+ .xatten1DBHigh = {0, 0, 0},
+ .xatten1MarginHigh = {0, 0, 0}
+ },
+ .calFreqPier5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5785, 0)
+ },
+ .calPierData5G = {
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+
+ },
+ .calTarget_freqbin_5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5785, 0)
+ },
+ .calTarget_freqbin_5GHT20 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT40 = {
+ FREQ2FBIN(5190, 0),
+ FREQ2FBIN(5230, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5410, 0),
+ FREQ2FBIN(5510, 0),
+ FREQ2FBIN(5670, 0),
+ FREQ2FBIN(5755, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTargetPower5G = {
+ /* 6-24,36,48,54 */
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ { {42, 40, 40, 34} },
+ },
+ .calTargetPower5GHT20 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+ { {38, 38, 38, 38, 32, 28, 38, 38, 32, 28, 38, 38, 32, 26} },
+ { {36, 36, 36, 36, 32, 28, 36, 36, 32, 28, 36, 36, 32, 26} },
+ },
+ .calTargetPower5GHT40 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+ { {36, 36, 36, 36, 30, 26, 36, 36, 30, 26, 36, 36, 30, 24} },
+ { {34, 34, 34, 34, 30, 26, 34, 34, 30, 26, 34, 34, 30, 24} },
+ },
+ .ctlIndex_5G = {
+ 0x10, 0x16, 0x18, 0x40, 0x46,
+ 0x48, 0x30, 0x36, 0x38
+ },
+ .ctl_freqbin_5G = {
+ {
+ /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+ {
+ /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+ /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+ },
+
+ {
+ /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[3].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[3].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[4].ctlEdges[4].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[5].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+ /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[5].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[5].ctlEdges[7].bChannel */ 0xFF
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+ /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+ /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+ /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+ }
+ },
+ .ctlPowerData_5G = {
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ }
+ },
+ }
+};
+
+
+static const struct ar9300_eeprom ar9300_h112 = {
+ .eepromVersion = 2,
+ .templateVersion = 3,
+ .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+ .custData = {"h112-241-f0000"},
+ .baseEepHeader = {
+ .regDmn = { LE16(0), LE16(0x1f) },
+ .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
+ .opCapFlags = {
+ .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .eepMisc = 0,
+ },
+ .rfSilent = 0,
+ .blueToothOptions = 0,
+ .deviceCap = 0,
+ .deviceType = 5, /* takes lower byte in eeprom location */
+ .pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+ .params_for_tuning_caps = {0, 0},
+ .featureEnable = 0x0d,
+ /*
+ * bit0 - enable tx temp comp - disabled
+ * bit1 - enable tx volt comp - disabled
+ * bit2 - enable fastClock - enabled
+ * bit3 - enable doubling - enabled
+ * bit4 - enable internal regulator - disabled
+ * bit5 - enable pa predistortion - disabled
+ */
+ .miscConfiguration = 0, /* bit0 - turn down drivestrength */
+ .eepromWriteEnableGpio = 6,
+ .wlanDisableGpio = 0,
+ .wlanLedGpio = 8,
+ .rxBandSelectGpio = 0xff,
+ .txrxgain = 0x10,
+ .swreg = 0,
+ },
+ .modalHeader2G = {
+ /* ar9300_modal_eep_header 2g */
+ /* 4 idle,t1,t2,b(4 bits per setting) */
+ .antCtrlCommon = LE32(0x110),
+ /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+ .antCtrlCommon2 = LE32(0x44444),
+
+ /*
+ * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+ * rx1, rx12, b (2 bits each)
+ */
+ .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+ /*
+ * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db
+ * for ar9280 (0xa20c/b20c 5:0)
+ */
+ .xatten1DB = {0, 0, 0},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for ar9280 (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0, 0, 0},
+ .tempSlope = 25,
+ .voltSlope = 0,
+
+ /*
+ * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+ * channels in usual fbin coding format
+ */
+ .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+ /*
+ * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+ * if the register is per chain
+ */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {1, 1, 1},/* 3 chain */
+ .db_stage2 = {1, 1, 1}, /* 3 chain */
+ .db_stage3 = {0, 0, 0},
+ .db_stage4 = {0, 0, 0},
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2c,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x80c080),
+ .papdRateMaskHt40 = LE32(0x80c080),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext1 = {
+ .ant_div_control = 0,
+ .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ .calFreqPier2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ /* ar9300_cal_data_per_freq_op_loop 2g */
+ .calPierData2G = {
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ },
+ .calTarget_freqbin_Cck = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2484, 1),
+ },
+ .calTarget_freqbin_2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT20 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT40 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTargetPowerCck = {
+ /* 1L-5L,5S,11L,11S */
+ { {34, 34, 34, 34} },
+ { {34, 34, 34, 34} },
+ },
+ .calTargetPower2G = {
+ /* 6-24,36,48,54 */
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ },
+ .calTargetPower2GHT20 = {
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+ },
+ .calTargetPower2GHT40 = {
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+ },
+ .ctlIndex_2G = {
+ 0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+ 0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+ },
+ .ctl_freqbin_2G = {
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2457, 1),
+ FREQ2FBIN(2462, 1)
+ },
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+ {
+ FREQ2FBIN(2422, 1),
+ FREQ2FBIN(2427, 1),
+ FREQ2FBIN(2447, 1),
+ FREQ2FBIN(2452, 1)
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ },
+
+ {
+ /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ }
+ },
+ .ctlPowerData_2G = {
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ },
+ .modalHeader5G = {
+ /* 4 idle,t1,t2,b (4 bits per setting) */
+ .antCtrlCommon = LE32(0x220),
+ /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+ .antCtrlCommon2 = LE32(0x44444),
+ /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+ .antCtrlChain = {
+ LE16(0x150), LE16(0x150), LE16(0x150),
+ },
+ /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+ .xatten1DB = {0, 0, 0},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for merlin (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0, 0, 0},
+ .tempSlope = 45,
+ .voltSlope = 0,
+ /* spurChans spur channels in usual fbin coding format */
+ .spurChans = {0, 0, 0, 0, 0},
+ /* noiseFloorThreshCh Check if the register is per chain */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {3, 3, 3}, /* 3 chain */
+ .db_stage2 = {3, 3, 3}, /* 3 chain */
+ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2d,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0cf0e0e0),
+ .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext2 = {
+ .tempSlopeLow = 40,
+ .tempSlopeHigh = 50,
+ .xatten1DBLow = {0, 0, 0},
+ .xatten1MarginLow = {0, 0, 0},
+ .xatten1DBHigh = {0, 0, 0},
+ .xatten1MarginHigh = {0, 0, 0}
+ },
+ .calFreqPier5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calPierData5G = {
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+
+ },
+ .calTarget_freqbin_5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT20 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT40 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTargetPower5G = {
+ /* 6-24,36,48,54 */
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ },
+ .calTargetPower5GHT20 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} },
+ { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} },
+ { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} },
+ { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} },
+ { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} },
+ { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} },
+ { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} },
+ { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} },
+ },
+ .calTargetPower5GHT40 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} },
+ { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} },
+ { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} },
+ { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} },
+ { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} },
+ { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} },
+ { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} },
+ { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} },
+ },
+ .ctlIndex_5G = {
+ 0x10, 0x16, 0x18, 0x40, 0x46,
+ 0x48, 0x30, 0x36, 0x38
+ },
+ .ctl_freqbin_5G = {
+ {
+ /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+ {
+ /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+ /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+ },
+
+ {
+ /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[3].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[3].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[4].ctlEdges[4].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[5].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+ /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[5].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[5].ctlEdges[7].bChannel */ 0xFF
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+ /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+ /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+ /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+ }
+ },
+ .ctlPowerData_5G = {
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ }
+ },
+ }
+};
+
+
+static const struct ar9300_eeprom ar9300_x112 = {
+ .eepromVersion = 2,
+ .templateVersion = 5,
+ .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+ .custData = {"x112-041-f0000"},
+ .baseEepHeader = {
+ .regDmn = { LE16(0), LE16(0x1f) },
+ .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
+ .opCapFlags = {
+ .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .eepMisc = 0,
+ },
+ .rfSilent = 0,
+ .blueToothOptions = 0,
+ .deviceCap = 0,
+ .deviceType = 5, /* takes lower byte in eeprom location */
+ .pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+ .params_for_tuning_caps = {0, 0},
+ .featureEnable = 0x0d,
+ /*
+ * bit0 - enable tx temp comp - disabled
+ * bit1 - enable tx volt comp - disabled
+ * bit2 - enable fastclock - enabled
+ * bit3 - enable doubling - enabled
+ * bit4 - enable internal regulator - disabled
+ * bit5 - enable pa predistortion - disabled
+ */
+ .miscConfiguration = 0, /* bit0 - turn down drivestrength */
+ .eepromWriteEnableGpio = 6,
+ .wlanDisableGpio = 0,
+ .wlanLedGpio = 8,
+ .rxBandSelectGpio = 0xff,
+ .txrxgain = 0x0,
+ .swreg = 0,
+ },
+ .modalHeader2G = {
+ /* ar9300_modal_eep_header 2g */
+ /* 4 idle,t1,t2,b(4 bits per setting) */
+ .antCtrlCommon = LE32(0x110),
+ /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+ .antCtrlCommon2 = LE32(0x22222),
+
+ /*
+ * antCtrlChain[ar9300_max_chains]; 6 idle, t, r,
+ * rx1, rx12, b (2 bits each)
+ */
+ .antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) },
+
+ /*
+ * xatten1DB[AR9300_max_chains]; 3 xatten1_db
+ * for ar9280 (0xa20c/b20c 5:0)
+ */
+ .xatten1DB = {0x1b, 0x1b, 0x1b},
+
+ /*
+ * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin
+ * for ar9280 (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0x15, 0x15, 0x15},
+ .tempSlope = 50,
+ .voltSlope = 0,
+
+ /*
+ * spurChans[OSPrey_eeprom_modal_sPURS]; spur
+ * channels in usual fbin coding format
+ */
+ .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+ /*
+ * noiseFloorThreshch[ar9300_max_cHAINS]; 3 Check
+ * if the register is per chain
+ */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {1, 1, 1},/* 3 chain */
+ .db_stage2 = {1, 1, 1}, /* 3 chain */
+ .db_stage3 = {0, 0, 0},
+ .db_stage4 = {0, 0, 0},
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2c,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0c80c080),
+ .papdRateMaskHt40 = LE32(0x0080c080),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext1 = {
+ .ant_div_control = 0,
+ .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ .calFreqPier2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ /* ar9300_cal_data_per_freq_op_loop 2g */
+ .calPierData2G = {
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ },
+ .calTarget_freqbin_Cck = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ .calTarget_freqbin_2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT20 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT40 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTargetPowerCck = {
+ /* 1L-5L,5S,11L,11s */
+ { {38, 38, 38, 38} },
+ { {38, 38, 38, 38} },
+ },
+ .calTargetPower2G = {
+ /* 6-24,36,48,54 */
+ { {38, 38, 36, 34} },
+ { {38, 38, 36, 34} },
+ { {38, 38, 34, 32} },
+ },
+ .calTargetPower2GHT20 = {
+ { {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} },
+ { {36, 36, 36, 36, 36, 34, 36, 34, 32, 30, 30, 30, 28, 26} },
+ { {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} },
+ },
+ .calTargetPower2GHT40 = {
+ { {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} },
+ { {36, 36, 36, 36, 34, 32, 34, 32, 30, 28, 28, 28, 28, 24} },
+ { {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} },
+ },
+ .ctlIndex_2G = {
+ 0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+ 0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+ },
+ .ctl_freqbin_2G = {
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2457, 1),
+ FREQ2FBIN(2462, 1)
+ },
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+ {
+ FREQ2FBIN(2422, 1),
+ FREQ2FBIN(2427, 1),
+ FREQ2FBIN(2447, 1),
+ FREQ2FBIN(2452, 1)
+ },
+
+ {
+ /* Data[4].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[4].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ /* Data[4].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+ /* Data[4].ctledges[3].bchannel */ FREQ2FBIN(2484, 1),
+ },
+
+ {
+ /* Data[5].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[5].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ /* Data[5].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[6].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[6].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[7].ctledges[0].bchannel */ FREQ2FBIN(2422, 1),
+ /* Data[7].ctledges[1].bchannel */ FREQ2FBIN(2427, 1),
+ /* Data[7].ctledges[2].bchannel */ FREQ2FBIN(2447, 1),
+ /* Data[7].ctledges[3].bchannel */ FREQ2FBIN(2462, 1),
+ },
+
+ {
+ /* Data[8].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[8].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ /* Data[8].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+ },
+
+ {
+ /* Data[9].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[9].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ /* Data[9].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[10].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+ /* Data[10].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+ /* Data[10].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[11].ctledges[0].bchannel */ FREQ2FBIN(2422, 1),
+ /* Data[11].ctledges[1].bchannel */ FREQ2FBIN(2427, 1),
+ /* Data[11].ctledges[2].bchannel */ FREQ2FBIN(2447, 1),
+ /* Data[11].ctledges[3].bchannel */ FREQ2FBIN(2462, 1),
+ }
+ },
+ .ctlPowerData_2G = {
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ },
+ .modalHeader5G = {
+ /* 4 idle,t1,t2,b (4 bits per setting) */
+ .antCtrlCommon = LE32(0x110),
+ /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+ .antCtrlCommon2 = LE32(0x22222),
+ /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+ .antCtrlChain = {
+ LE16(0x0), LE16(0x0), LE16(0x0),
+ },
+ /* xatten1DB 3 xatten1_db for ar9280 (0xa20c/b20c 5:0) */
+ .xatten1DB = {0x13, 0x19, 0x17},
+
+ /*
+ * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin
+ * for merlin (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0x19, 0x19, 0x19},
+ .tempSlope = 70,
+ .voltSlope = 15,
+ /* spurChans spur channels in usual fbin coding format */
+ .spurChans = {0, 0, 0, 0, 0},
+ /* noiseFloorThreshch check if the register is per chain */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {3, 3, 3}, /* 3 chain */
+ .db_stage2 = {3, 3, 3}, /* 3 chain */
+ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2d,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0cf0e0e0),
+ .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext2 = {
+ .tempSlopeLow = 72,
+ .tempSlopeHigh = 105,
+ .xatten1DBLow = {0x10, 0x14, 0x10},
+ .xatten1MarginLow = {0x19, 0x19 , 0x19},
+ .xatten1DBHigh = {0x1d, 0x20, 0x24},
+ .xatten1MarginHigh = {0x10, 0x10, 0x10}
+ },
+ .calFreqPier5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5785, 0)
+ },
+ .calPierData5G = {
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+
+ },
+ .calTarget_freqbin_5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5725, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT20 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5725, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT40 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5725, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTargetPower5G = {
+ /* 6-24,36,48,54 */
+ { {32, 32, 28, 26} },
+ { {32, 32, 28, 26} },
+ { {32, 32, 28, 26} },
+ { {32, 32, 26, 24} },
+ { {32, 32, 26, 24} },
+ { {32, 32, 24, 22} },
+ { {30, 30, 24, 22} },
+ { {30, 30, 24, 22} },
+ },
+ .calTargetPower5GHT20 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 22, 22, 20, 20} },
+ { {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 20, 18, 16, 16} },
+ { {32, 32, 32, 32, 28, 26, 32, 24, 20, 16, 18, 16, 14, 14} },
+ { {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} },
+ { {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} },
+ },
+ .calTargetPower5GHT40 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+ { {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 22, 22, 20, 20} },
+ { {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 20, 18, 16, 16} },
+ { {32, 32, 32, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+ { {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+ { {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+ },
+ .ctlIndex_5G = {
+ 0x10, 0x16, 0x18, 0x40, 0x46,
+ 0x48, 0x30, 0x36, 0x38
+ },
+ .ctl_freqbin_5G = {
+ {
+ /* Data[0].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[0].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[0].ctledges[2].bchannel */ FREQ2FBIN(5280, 0),
+ /* Data[0].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[0].ctledges[4].bchannel */ FREQ2FBIN(5600, 0),
+ /* Data[0].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[0].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+ /* Data[0].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+ },
+ {
+ /* Data[1].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[1].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[1].ctledges[2].bchannel */ FREQ2FBIN(5280, 0),
+ /* Data[1].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[1].ctledges[4].bchannel */ FREQ2FBIN(5520, 0),
+ /* Data[1].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[1].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+ /* Data[1].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[2].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+ /* Data[2].ctledges[1].bchannel */ FREQ2FBIN(5230, 0),
+ /* Data[2].ctledges[2].bchannel */ FREQ2FBIN(5270, 0),
+ /* Data[2].ctledges[3].bchannel */ FREQ2FBIN(5310, 0),
+ /* Data[2].ctledges[4].bchannel */ FREQ2FBIN(5510, 0),
+ /* Data[2].ctledges[5].bchannel */ FREQ2FBIN(5550, 0),
+ /* Data[2].ctledges[6].bchannel */ FREQ2FBIN(5670, 0),
+ /* Data[2].ctledges[7].bchannel */ FREQ2FBIN(5755, 0)
+ },
+
+ {
+ /* Data[3].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[3].ctledges[1].bchannel */ FREQ2FBIN(5200, 0),
+ /* Data[3].ctledges[2].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[3].ctledges[3].bchannel */ FREQ2FBIN(5320, 0),
+ /* Data[3].ctledges[4].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[3].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[3].ctledges[6].bchannel */ 0xFF,
+ /* Data[3].ctledges[7].bchannel */ 0xFF,
+ },
+
+ {
+ /* Data[4].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[4].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[4].ctledges[2].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[4].ctledges[3].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[4].ctledges[4].bchannel */ 0xFF,
+ /* Data[4].ctledges[5].bchannel */ 0xFF,
+ /* Data[4].ctledges[6].bchannel */ 0xFF,
+ /* Data[4].ctledges[7].bchannel */ 0xFF,
+ },
+
+ {
+ /* Data[5].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+ /* Data[5].ctledges[1].bchannel */ FREQ2FBIN(5270, 0),
+ /* Data[5].ctledges[2].bchannel */ FREQ2FBIN(5310, 0),
+ /* Data[5].ctledges[3].bchannel */ FREQ2FBIN(5510, 0),
+ /* Data[5].ctledges[4].bchannel */ FREQ2FBIN(5590, 0),
+ /* Data[5].ctledges[5].bchannel */ FREQ2FBIN(5670, 0),
+ /* Data[5].ctledges[6].bchannel */ 0xFF,
+ /* Data[5].ctledges[7].bchannel */ 0xFF
+ },
+
+ {
+ /* Data[6].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[6].ctledges[1].bchannel */ FREQ2FBIN(5200, 0),
+ /* Data[6].ctledges[2].bchannel */ FREQ2FBIN(5220, 0),
+ /* Data[6].ctledges[3].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[6].ctledges[4].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[6].ctledges[5].bchannel */ FREQ2FBIN(5600, 0),
+ /* Data[6].ctledges[6].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[6].ctledges[7].bchannel */ FREQ2FBIN(5745, 0)
+ },
+
+ {
+ /* Data[7].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+ /* Data[7].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+ /* Data[7].ctledges[2].bchannel */ FREQ2FBIN(5320, 0),
+ /* Data[7].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+ /* Data[7].ctledges[4].bchannel */ FREQ2FBIN(5560, 0),
+ /* Data[7].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+ /* Data[7].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+ /* Data[7].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[8].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+ /* Data[8].ctledges[1].bchannel */ FREQ2FBIN(5230, 0),
+ /* Data[8].ctledges[2].bchannel */ FREQ2FBIN(5270, 0),
+ /* Data[8].ctledges[3].bchannel */ FREQ2FBIN(5510, 0),
+ /* Data[8].ctledges[4].bchannel */ FREQ2FBIN(5550, 0),
+ /* Data[8].ctledges[5].bchannel */ FREQ2FBIN(5670, 0),
+ /* Data[8].ctledges[6].bchannel */ FREQ2FBIN(5755, 0),
+ /* Data[8].ctledges[7].bchannel */ FREQ2FBIN(5795, 0)
+ }
+ },
+ .ctlPowerData_5G = {
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ }
+ },
+ {
+ {
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ }
+ },
+ }
+};
+
+static const struct ar9300_eeprom ar9300_h116 = {
+ .eepromVersion = 2,
+ .templateVersion = 4,
+ .macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+ .custData = {"h116-041-f0000"},
+ .baseEepHeader = {
+ .regDmn = { LE16(0), LE16(0x1f) },
+ .txrxMask = 0x33, /* 4 bits tx and 4 bits rx */
+ .opCapFlags = {
+ .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .eepMisc = 0,
+ },
+ .rfSilent = 0,
+ .blueToothOptions = 0,
+ .deviceCap = 0,
+ .deviceType = 5, /* takes lower byte in eeprom location */
+ .pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+ .params_for_tuning_caps = {0, 0},
+ .featureEnable = 0x0d,
+ /*
+ * bit0 - enable tx temp comp - disabled
+ * bit1 - enable tx volt comp - disabled
+ * bit2 - enable fastClock - enabled
+ * bit3 - enable doubling - enabled
+ * bit4 - enable internal regulator - disabled
+ * bit5 - enable pa predistortion - disabled
+ */
+ .miscConfiguration = 0, /* bit0 - turn down drivestrength */
+ .eepromWriteEnableGpio = 6,
+ .wlanDisableGpio = 0,
+ .wlanLedGpio = 8,
+ .rxBandSelectGpio = 0xff,
+ .txrxgain = 0x10,
+ .swreg = 0,
+ },
+ .modalHeader2G = {
+ /* ar9300_modal_eep_header 2g */
+ /* 4 idle,t1,t2,b(4 bits per setting) */
+ .antCtrlCommon = LE32(0x110),
+ /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+ .antCtrlCommon2 = LE32(0x44444),
+
+ /*
+ * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+ * rx1, rx12, b (2 bits each)
+ */
+ .antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) },
+
+ /*
+ * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db
+ * for ar9280 (0xa20c/b20c 5:0)
+ */
+ .xatten1DB = {0x1f, 0x1f, 0x1f},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for ar9280 (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0x12, 0x12, 0x12},
+ .tempSlope = 25,
+ .voltSlope = 0,
+
+ /*
+ * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+ * channels in usual fbin coding format
+ */
+ .spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+ /*
+ * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+ * if the register is per chain
+ */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {1, 1, 1},/* 3 chain */
+ .db_stage2 = {1, 1, 1}, /* 3 chain */
+ .db_stage3 = {0, 0, 0},
+ .db_stage4 = {0, 0, 0},
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2c,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0c80C080),
+ .papdRateMaskHt40 = LE32(0x0080C080),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext1 = {
+ .ant_div_control = 0,
+ .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ .calFreqPier2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ /* ar9300_cal_data_per_freq_op_loop 2g */
+ .calPierData2G = {
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+ },
+ .calTarget_freqbin_Cck = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2472, 1),
+ },
+ .calTarget_freqbin_2G = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT20 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTarget_freqbin_2GHT40 = {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2437, 1),
+ FREQ2FBIN(2472, 1)
+ },
+ .calTargetPowerCck = {
+ /* 1L-5L,5S,11L,11S */
+ { {34, 34, 34, 34} },
+ { {34, 34, 34, 34} },
+ },
+ .calTargetPower2G = {
+ /* 6-24,36,48,54 */
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ { {34, 34, 32, 32} },
+ },
+ .calTargetPower2GHT20 = {
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+ { {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+ },
+ .calTargetPower2GHT40 = {
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ { {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+ },
+ .ctlIndex_2G = {
+ 0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+ 0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+ },
+ .ctl_freqbin_2G = {
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2457, 1),
+ FREQ2FBIN(2462, 1)
+ },
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+
+ {
+ FREQ2FBIN(2412, 1),
+ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2462, 1),
+ 0xFF,
+ },
+ {
+ FREQ2FBIN(2422, 1),
+ FREQ2FBIN(2427, 1),
+ FREQ2FBIN(2447, 1),
+ FREQ2FBIN(2452, 1)
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ FREQ2FBIN(2472, 1),
+ 0,
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ },
+
+ {
+ /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+ /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+ /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+ 0
+ },
+
+ {
+ /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+ /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+ /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+ /* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+ }
+ },
+ .ctlPowerData_2G = {
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+ { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+ },
+ .modalHeader5G = {
+ /* 4 idle,t1,t2,b (4 bits per setting) */
+ .antCtrlCommon = LE32(0x220),
+ /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+ .antCtrlCommon2 = LE32(0x44444),
+ /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+ .antCtrlChain = {
+ LE16(0x150), LE16(0x150), LE16(0x150),
+ },
+ /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+ .xatten1DB = {0x19, 0x19, 0x19},
+
+ /*
+ * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+ * for merlin (0xa20c/b20c 16:12
+ */
+ .xatten1Margin = {0x14, 0x14, 0x14},
+ .tempSlope = 70,
+ .voltSlope = 0,
+ /* spurChans spur channels in usual fbin coding format */
+ .spurChans = {0, 0, 0, 0, 0},
+ /* noiseFloorThreshCh Check if the register is per chain */
+ .noiseFloorThreshCh = {-1, 0, 0},
+ .ob = {3, 3, 3}, /* 3 chain */
+ .db_stage2 = {3, 3, 3}, /* 3 chain */
+ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */
+ .xpaBiasLvl = 0,
+ .txFrameToDataStart = 0x0e,
+ .txFrameToPaOn = 0x0e,
+ .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+ .antennaGain = 0,
+ .switchSettling = 0x2d,
+ .adcDesiredSize = -30,
+ .txEndToXpaOff = 0,
+ .txEndToRxOn = 0x2,
+ .txFrameToXpaOn = 0xe,
+ .thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0x0cf0e0e0),
+ .papdRateMaskHt40 = LE32(0x6cf0e0e0),
+ .futureModal = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ .base_ext2 = {
+ .tempSlopeLow = 35,
+ .tempSlopeHigh = 50,
+ .xatten1DBLow = {0, 0, 0},
+ .xatten1MarginLow = {0, 0, 0},
+ .xatten1DBHigh = {0, 0, 0},
+ .xatten1MarginHigh = {0, 0, 0}
+ },
+ .calFreqPier5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5220, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5785, 0)
+ },
+ .calPierData5G = {
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+ {
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0},
+ },
+
+ },
+ .calTarget_freqbin_5G = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5600, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT20 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTarget_freqbin_5GHT40 = {
+ FREQ2FBIN(5180, 0),
+ FREQ2FBIN(5240, 0),
+ FREQ2FBIN(5320, 0),
+ FREQ2FBIN(5400, 0),
+ FREQ2FBIN(5500, 0),
+ FREQ2FBIN(5700, 0),
+ FREQ2FBIN(5745, 0),
+ FREQ2FBIN(5825, 0)
+ },
+ .calTargetPower5G = {
+ /* 6-24,36,48,54 */
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ { {30, 30, 28, 24} },
+ },
+ .calTargetPower5GHT20 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} },
+ { {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} },
+ { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} },
+ { {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} },
+ { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} },
+ { {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} },
+ { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} },
+ { {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} },
+ },
+ .calTargetPower5GHT40 = {
+ /*
+ * 0_8_16,1-3_9-11_17-19,
+ * 4,5,6,7,12,13,14,15,20,21,22,23
+ */
+ { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} },
+ { {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} },
+ { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} },
+ { {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} },
+ { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} },
+ { {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} },
+ { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} },
+ { {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} },
+ },
+ .ctlIndex_5G = {
+ 0x10, 0x16, 0x18, 0x40, 0x46,
+ 0x48, 0x30, 0x36, 0x38
+ },
+ .ctl_freqbin_5G = {
+ {
+ /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+ {
+ /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+ /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+ /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+ },
+
+ {
+ /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[3].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[3].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[4].ctlEdges[4].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[5].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[4].ctlEdges[7].bChannel */ 0xFF,
+ },
+
+ {
+ /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+ /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+ /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[5].ctlEdges[6].bChannel */ 0xFF,
+ /* Data[5].ctlEdges[7].bChannel */ 0xFF
+ },
+
+ {
+ /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+ /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+ /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+ /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+ },
+
+ {
+ /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+ /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+ /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+ /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+ /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+ /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+ /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+ /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+ },
+
+ {
+ /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+ /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+ /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+ /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+ /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+ /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+ /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+ /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+ }
+ },
+ .ctlPowerData_5G = {
+ {
+ {
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 0}, {60, 1}, {60, 0}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
+ CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
}
},
{
{
- {60, 0}, {60, 1}, {60, 1}, {60, 0},
- {60, 1}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
- {60, 0}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+ CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 0}, {60, 0}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 1},
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
}
},
{
{
- {60, 1}, {60, 1}, {60, 0}, {60, 1},
- {60, 1}, {60, 1}, {60, 1}, {60, 0},
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
}
},
{
{
- {60, 1}, {60, 0}, {60, 1}, {60, 1},
- {60, 1}, {60, 1}, {60, 0}, {60, 1},
+ CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+ CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
}
},
}
};
+
+static const struct ar9300_eeprom *ar9300_eep_templates[] = {
+ &ar9300_default,
+ &ar9300_x112,
+ &ar9300_h116,
+ &ar9300_h112,
+ &ar9300_x113,
+};
+
+static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id)
+{
+#define N_LOOP (sizeof(ar9300_eep_templates) / sizeof(ar9300_eep_templates[0]))
+ int it;
+
+ for (it = 0; it < N_LOOP; it++)
+ if (ar9300_eep_templates[it]->templateVersion == id)
+ return ar9300_eep_templates[it];
+ return NULL;
+#undef N_LOOP
+}
+
+
static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
{
- if (fbin == AR9300_BCHAN_UNUSED)
+ if (fbin == AR5416_BCHAN_UNUSED)
return fbin;
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
@@ -636,6 +2988,16 @@ static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
return 0;
}
+static int interpolate(int x, int xa, int xb, int ya, int yb)
+{
+ int bf, factor, plus;
+
+ bf = 2 * (yb - ya) * (x - xa) / (xb - xa);
+ factor = bf / 2;
+ plus = bf % 2;
+ return ya + factor + plus;
+}
+
static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
@@ -673,6 +3035,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
return le32_to_cpu(pBase->swreg);
case EEP_PAPRD:
return !!(pBase->featureEnable & BIT(5));
+ case EEP_CHAIN_MASK_REDUCE:
+ return (pBase->miscConfiguration >> 0x3) & 0x1;
+ case EEP_ANT_DIV_CTL1:
+ return le32_to_cpu(eep->base_ext1.ant_div_control);
default:
return 0;
}
@@ -711,8 +3077,8 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
int i;
if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
- ath_print(common, ATH_DBG_EEPROM,
- "eeprom address not in range\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "eeprom address not in range\n");
return false;
}
@@ -743,11 +3109,41 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
return true;
error:
- ath_print(common, ATH_DBG_EEPROM,
- "unable to read eeprom region at offset %d\n", address);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "unable to read eeprom region at offset %d\n", address);
return false;
}
+static bool ar9300_otp_read_word(struct ath_hw *ah, int addr, u32 *data)
+{
+ REG_READ(ah, AR9300_OTP_BASE + (4 * addr));
+
+ if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS, AR9300_OTP_STATUS_TYPE,
+ AR9300_OTP_STATUS_VALID, 1000))
+ return false;
+
+ *data = REG_READ(ah, AR9300_OTP_READ_DATA);
+ return true;
+}
+
+static bool ar9300_read_otp(struct ath_hw *ah, int address, u8 *buffer,
+ int count)
+{
+ u32 data;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ int offset = 8 * ((address - i) % 4);
+ if (!ar9300_otp_read_word(ah, (address - i) / 4, &data))
+ return false;
+
+ buffer[i] = (data >> offset) & 0xff;
+ }
+
+ return true;
+}
+
+
static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
int *length, int *major, int *minor)
{
@@ -798,17 +3194,15 @@ static bool ar9300_uncompress_block(struct ath_hw *ah,
length &= 0xff;
if (length > 0 && spot >= 0 && spot+length <= mdataSize) {
- ath_print(common, ATH_DBG_EEPROM,
- "Restore at %d: spot=%d "
- "offset=%d length=%d\n",
- it, spot, offset, length);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Restore at %d: spot=%d offset=%d length=%d\n",
+ it, spot, offset, length);
memcpy(&mptr[spot], &block[it+2], length);
spot += length;
} else if (length > 0) {
- ath_print(common, ATH_DBG_EEPROM,
- "Bad restore at %d: spot=%d "
- "offset=%d length=%d\n",
- it, spot, offset, length);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Bad restore at %d: spot=%d offset=%d length=%d\n",
+ it, spot, offset, length);
return false;
}
}
@@ -824,45 +3218,80 @@ static int ar9300_compress_decision(struct ath_hw *ah,
{
struct ath_common *common = ath9k_hw_common(ah);
u8 *dptr;
+ const struct ar9300_eeprom *eep = NULL;
switch (code) {
case _CompressNone:
if (length != mdata_size) {
- ath_print(common, ATH_DBG_EEPROM,
- "EEPROM structure size mismatch"
- "memory=%d eeprom=%d\n", mdata_size, length);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "EEPROM structure size mismatch memory=%d eeprom=%d\n",
+ mdata_size, length);
return -1;
}
memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length);
- ath_print(common, ATH_DBG_EEPROM, "restored eeprom %d:"
- " uncompressed, length %d\n", it, length);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "restored eeprom %d: uncompressed, length %d\n",
+ it, length);
break;
case _CompressBlock:
if (reference == 0) {
dptr = mptr;
} else {
- if (reference != 2) {
- ath_print(common, ATH_DBG_EEPROM,
- "cant find reference eeprom"
- "struct %d\n", reference);
+ eep = ar9003_eeprom_struct_find_by_id(reference);
+ if (eep == NULL) {
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "cant find reference eeprom struct %d\n",
+ reference);
return -1;
}
- memcpy(mptr, &ar9300_default, mdata_size);
+ memcpy(mptr, eep, mdata_size);
}
- ath_print(common, ATH_DBG_EEPROM,
- "restore eeprom %d: block, reference %d,"
- " length %d\n", it, reference, length);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "restore eeprom %d: block, reference %d, length %d\n",
+ it, reference, length);
ar9300_uncompress_block(ah, mptr, mdata_size,
(u8 *) (word + COMP_HDR_LEN), length);
break;
default:
- ath_print(common, ATH_DBG_EEPROM, "unknown compression"
- " code %d\n", code);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "unknown compression code %d\n", code);
return -1;
}
return 0;
}
+typedef bool (*eeprom_read_op)(struct ath_hw *ah, int address, u8 *buffer,
+ int count);
+
+static bool ar9300_check_header(void *data)
+{
+ u32 *word = data;
+ return !(*word == 0 || *word == ~0);
+}
+
+static bool ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read,
+ int base_addr)
+{
+ u8 header[4];
+
+ if (!read(ah, base_addr, header, 4))
+ return false;
+
+ return ar9300_check_header(header);
+}
+
+static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr,
+ int mdata_size)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ u16 *data = (u16 *) mptr;
+ int i;
+
+ for (i = 0; i < mdata_size / 2; i++, data++)
+ ath9k_hw_nvram_read(common, i, data);
+
+ return 0;
+}
/*
* Read the configuration data from the eeprom.
* The data can be put in any specified memory buffer.
@@ -883,6 +3312,10 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
int it;
u16 checksum, mchecksum;
struct ath_common *common = ath9k_hw_common(ah);
+ eeprom_read_op read;
+
+ if (ath9k_hw_use_flash(ah))
+ return ar9300_eeprom_restore_flash(ah, mptr, mdata_size);
word = kzalloc(2048, GFP_KERNEL);
if (!word)
@@ -890,43 +3323,73 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
memcpy(mptr, &ar9300_default, mdata_size);
+ read = ar9300_read_eeprom;
+ if (AR_SREV_9485(ah))
+ cptr = AR9300_BASE_ADDR_4K;
+ else
+ cptr = AR9300_BASE_ADDR;
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Trying EEPROM accesss at Address 0x%04x\n", cptr);
+ if (ar9300_check_eeprom_header(ah, read, cptr))
+ goto found;
+
+ cptr = AR9300_BASE_ADDR_512;
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Trying EEPROM accesss at Address 0x%04x\n", cptr);
+ if (ar9300_check_eeprom_header(ah, read, cptr))
+ goto found;
+
+ read = ar9300_read_otp;
cptr = AR9300_BASE_ADDR;
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Trying OTP accesss at Address 0x%04x\n", cptr);
+ if (ar9300_check_eeprom_header(ah, read, cptr))
+ goto found;
+
+ cptr = AR9300_BASE_ADDR_512;
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Trying OTP accesss at Address 0x%04x\n", cptr);
+ if (ar9300_check_eeprom_header(ah, read, cptr))
+ goto found;
+
+ goto fail;
+
+found:
+ ath_dbg(common, ATH_DBG_EEPROM, "Found valid EEPROM data\n");
+
for (it = 0; it < MSTATE; it++) {
- if (!ar9300_read_eeprom(ah, cptr, word, COMP_HDR_LEN))
+ if (!read(ah, cptr, word, COMP_HDR_LEN))
goto fail;
- if ((word[0] == 0 && word[1] == 0 && word[2] == 0 &&
- word[3] == 0) || (word[0] == 0xff && word[1] == 0xff
- && word[2] == 0xff && word[3] == 0xff))
+ if (!ar9300_check_header(word))
break;
ar9300_comp_hdr_unpack(word, &code, &reference,
&length, &major, &minor);
- ath_print(common, ATH_DBG_EEPROM,
- "Found block at %x: code=%d ref=%d"
- "length=%d major=%d minor=%d\n", cptr, code,
- reference, length, major, minor);
- if (length >= 1024) {
- ath_print(common, ATH_DBG_EEPROM,
- "Skipping bad header\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n",
+ cptr, code, reference, length, major, minor);
+ if ((!AR_SREV_9485(ah) && length >= 1024) ||
+ (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) {
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Skipping bad header\n");
cptr -= COMP_HDR_LEN;
continue;
}
osize = length;
- ar9300_read_eeprom(ah, cptr, word,
- COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
+ read(ah, cptr, word, COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length);
mchecksum = word[COMP_HDR_LEN + osize] |
(word[COMP_HDR_LEN + osize + 1] << 8);
- ath_print(common, ATH_DBG_EEPROM,
- "checksum %x %x\n", checksum, mchecksum);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "checksum %x %x\n", checksum, mchecksum);
if (checksum == mchecksum) {
ar9300_compress_decision(ah, it, code, reference, mptr,
word, length, mdata_size);
} else {
- ath_print(common, ATH_DBG_EEPROM,
- "skipping block with bad checksum\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "skipping block with bad checksum\n");
}
cptr -= (COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
}
@@ -967,18 +3430,6 @@ static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah)
return 0;
}
-static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
- enum ath9k_hal_freq_band freq_band)
-{
- return 1;
-}
-
-static u32 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- return -EINVAL;
-}
-
static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
@@ -992,9 +3443,15 @@ static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz)
static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
{
int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz);
- REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, (bias & 0x3));
- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_SPARE,
- ((bias >> 2) & 0x3));
+
+ if (AR_SREV_9485(ah))
+ REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
+ else {
+ REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
+ REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB,
+ bias >> 2);
+ REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1);
+ }
}
static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
@@ -1049,11 +3506,25 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
- value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value);
+ if (!AR_SREV_9485(ah)) {
+ value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
+ REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL,
+ value);
+
+ value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz);
+ REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL,
+ value);
+ }
- value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value);
+ if (AR_SREV_9485(ah)) {
+ value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_CTRL_ALL,
+ value);
+ REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE,
+ value >> 6);
+ REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE,
+ value >> 7);
+ }
}
static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
@@ -1097,28 +3568,177 @@ static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg);
}
+static u16 ar9003_hw_atten_chain_get(struct ath_hw *ah, int chain,
+ struct ath9k_channel *chan)
+{
+ int f[3], t[3];
+ u16 value;
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+ if (chain >= 0 && chain < 3) {
+ if (IS_CHAN_2GHZ(chan))
+ return eep->modalHeader2G.xatten1DB[chain];
+ else if (eep->base_ext2.xatten1DBLow[chain] != 0) {
+ t[0] = eep->base_ext2.xatten1DBLow[chain];
+ f[0] = 5180;
+ t[1] = eep->modalHeader5G.xatten1DB[chain];
+ f[1] = 5500;
+ t[2] = eep->base_ext2.xatten1DBHigh[chain];
+ f[2] = 5785;
+ value = ar9003_hw_power_interpolate((s32) chan->channel,
+ f, t, 3);
+ return value;
+ } else
+ return eep->modalHeader5G.xatten1DB[chain];
+ }
+
+ return 0;
+}
+
+
+static u16 ar9003_hw_atten_chain_get_margin(struct ath_hw *ah, int chain,
+ struct ath9k_channel *chan)
+{
+ int f[3], t[3];
+ u16 value;
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+ if (chain >= 0 && chain < 3) {
+ if (IS_CHAN_2GHZ(chan))
+ return eep->modalHeader2G.xatten1Margin[chain];
+ else if (eep->base_ext2.xatten1MarginLow[chain] != 0) {
+ t[0] = eep->base_ext2.xatten1MarginLow[chain];
+ f[0] = 5180;
+ t[1] = eep->modalHeader5G.xatten1Margin[chain];
+ f[1] = 5500;
+ t[2] = eep->base_ext2.xatten1MarginHigh[chain];
+ f[2] = 5785;
+ value = ar9003_hw_power_interpolate((s32) chan->channel,
+ f, t, 3);
+ return value;
+ } else
+ return eep->modalHeader5G.xatten1Margin[chain];
+ }
+
+ return 0;
+}
+
+static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ int i;
+ u16 value;
+ unsigned long ext_atten_reg[3] = {AR_PHY_EXT_ATTEN_CTL_0,
+ AR_PHY_EXT_ATTEN_CTL_1,
+ AR_PHY_EXT_ATTEN_CTL_2,
+ };
+
+ /* Test value. if 0 then attenuation is unused. Don't load anything. */
+ for (i = 0; i < 3; i++) {
+ value = ar9003_hw_atten_chain_get(ah, i, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[i],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+ value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[i],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
+ }
+}
+
+static bool is_pmu_set(struct ath_hw *ah, u32 pmu_reg, int pmu_set)
+{
+ int timeout = 100;
+
+ while (pmu_set != REG_READ(ah, pmu_reg)) {
+ if (timeout-- == 0)
+ return false;
+ REG_WRITE(ah, pmu_reg, pmu_set);
+ udelay(10);
+ }
+
+ return true;
+}
+
static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
{
int internal_regulator =
ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR);
if (internal_regulator) {
- /* Internal regulator is ON. Write swreg register. */
- int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
- REG_WRITE(ah, AR_RTC_REG_CONTROL1,
- REG_READ(ah, AR_RTC_REG_CONTROL1) &
- (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
- REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
- /* Set REG_CONTROL1.SWREG_PROGRAM */
- REG_WRITE(ah, AR_RTC_REG_CONTROL1,
- REG_READ(ah,
- AR_RTC_REG_CONTROL1) |
- AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
+ if (AR_SREV_9485(ah)) {
+ int reg_pmu_set;
+
+ reg_pmu_set = REG_READ(ah, AR_PHY_PMU2) & ~AR_PHY_PMU2_PGM;
+ REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+ if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+ return;
+
+ reg_pmu_set = (5 << 1) | (7 << 4) | (1 << 8) |
+ (7 << 14) | (6 << 17) | (1 << 20) |
+ (3 << 24) | (1 << 28);
+
+ REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set);
+ if (!is_pmu_set(ah, AR_PHY_PMU1, reg_pmu_set))
+ return;
+
+ reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0xFFC00000)
+ | (4 << 26);
+ REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+ if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+ return;
+
+ reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0x00200000)
+ | (1 << 21);
+ REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+ if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+ return;
+ } else {
+ /* Internal regulator is ON. Write swreg register. */
+ int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
+ REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+ REG_READ(ah, AR_RTC_REG_CONTROL1) &
+ (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
+ REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
+ /* Set REG_CONTROL1.SWREG_PROGRAM */
+ REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+ REG_READ(ah,
+ AR_RTC_REG_CONTROL1) |
+ AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
+ }
} else {
- REG_WRITE(ah, AR_RTC_SLEEP_CLK,
- (REG_READ(ah,
- AR_RTC_SLEEP_CLK) |
- AR_RTC_FORCE_SWREG_PRD));
+ if (AR_SREV_9485(ah)) {
+ REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0);
+ while (REG_READ_FIELD(ah, AR_PHY_PMU2,
+ AR_PHY_PMU2_PGM))
+ udelay(10);
+
+ REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1);
+ while (!REG_READ_FIELD(ah, AR_PHY_PMU1,
+ AR_PHY_PMU1_PWD))
+ udelay(10);
+ REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0x1);
+ while (!REG_READ_FIELD(ah, AR_PHY_PMU2,
+ AR_PHY_PMU2_PGM))
+ udelay(10);
+ } else
+ REG_WRITE(ah, AR_RTC_SLEEP_CLK,
+ (REG_READ(ah,
+ AR_RTC_SLEEP_CLK) |
+ AR_RTC_FORCE_SWREG_PRD));
+ }
+
+}
+
+static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0];
+
+ if (eep->baseEepHeader.featureEnable & 0x40) {
+ tuning_caps_param &= 0x7f;
+ REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPINDAC,
+ tuning_caps_param);
+ REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPOUTDAC,
+ tuning_caps_param);
}
}
@@ -1128,7 +3748,10 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan));
ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
ar9003_hw_drive_strength_apply(ah);
+ ar9003_hw_atten_apply(ah, chan);
ar9003_hw_internal_regulator_apply(ah);
+ if (AR_SREV_9485(ah))
+ ar9003_hw_apply_tuning_caps(ah);
}
static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah,
@@ -1189,7 +3812,7 @@ static int ar9003_hw_power_interpolate(int32_t x,
if (hx == lx)
y = ly;
else /* interpolate */
- y = ly + (((x - lx) * (hy - ly)) / (hx - lx));
+ y = interpolate(x, lx, hx, ly, hy);
} else /* only low is good, use it */
y = ly;
} else if (hhave) /* only high is good, use it */
@@ -1558,22 +4181,9 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
is2GHz) + ht40PowerIncForPdadc;
- while (i < ar9300RateSize) {
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
-
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
-
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
-
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
- i++;
+ for (i = 0; i < ar9300RateSize; i++) {
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
}
}
@@ -1592,18 +4202,17 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
struct ath_common *common = ath9k_hw_common(ah);
if (ichain >= AR9300_MAX_CHAINS) {
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid chain index, must be less than %d\n",
- AR9300_MAX_CHAINS);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Invalid chain index, must be less than %d\n",
+ AR9300_MAX_CHAINS);
return -1;
}
if (mode) { /* 5GHz */
if (ipier >= AR9300_NUM_5G_CAL_PIERS) {
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid 5GHz cal pier index, must "
- "be less than %d\n",
- AR9300_NUM_5G_CAL_PIERS);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Invalid 5GHz cal pier index, must be less than %d\n",
+ AR9300_NUM_5G_CAL_PIERS);
return -1;
}
pCalPier = &(eep->calFreqPier5G[ipier]);
@@ -1611,9 +4220,9 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
is2GHz = 0;
} else {
if (ipier >= AR9300_NUM_2G_CAL_PIERS) {
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid 2GHz cal pier index, must "
- "be less than %d\n", AR9300_NUM_2G_CAL_PIERS);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Invalid 2GHz cal pier index, must be less than %d\n",
+ AR9300_NUM_2G_CAL_PIERS);
return -1;
}
@@ -1637,27 +4246,32 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
{
int tempSlope = 0;
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ int f[3], t[3];
REG_RMW(ah, AR_PHY_TPC_11_B0,
(correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
AR_PHY_TPC_OLPC_GAIN_DELTA);
- REG_RMW(ah, AR_PHY_TPC_11_B1,
- (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
- AR_PHY_TPC_OLPC_GAIN_DELTA);
- REG_RMW(ah, AR_PHY_TPC_11_B2,
- (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
- AR_PHY_TPC_OLPC_GAIN_DELTA);
+ if (ah->caps.tx_chainmask & BIT(1))
+ REG_RMW(ah, AR_PHY_TPC_11_B1,
+ (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+ AR_PHY_TPC_OLPC_GAIN_DELTA);
+ if (ah->caps.tx_chainmask & BIT(2))
+ REG_RMW(ah, AR_PHY_TPC_11_B2,
+ (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+ AR_PHY_TPC_OLPC_GAIN_DELTA);
/* enable open loop power control on chip */
REG_RMW(ah, AR_PHY_TPC_6_B0,
(3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
AR_PHY_TPC_6_ERROR_EST_MODE);
- REG_RMW(ah, AR_PHY_TPC_6_B1,
- (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
- AR_PHY_TPC_6_ERROR_EST_MODE);
- REG_RMW(ah, AR_PHY_TPC_6_B2,
- (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
- AR_PHY_TPC_6_ERROR_EST_MODE);
+ if (ah->caps.tx_chainmask & BIT(1))
+ REG_RMW(ah, AR_PHY_TPC_6_B1,
+ (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+ AR_PHY_TPC_6_ERROR_EST_MODE);
+ if (ah->caps.tx_chainmask & BIT(2))
+ REG_RMW(ah, AR_PHY_TPC_6_B2,
+ (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+ AR_PHY_TPC_6_ERROR_EST_MODE);
/*
* enable temperature compensation
@@ -1665,7 +4279,16 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
*/
if (frequency < 4000)
tempSlope = eep->modalHeader2G.tempSlope;
- else
+ else if (eep->base_ext2.tempSlopeLow != 0) {
+ t[0] = eep->base_ext2.tempSlopeLow;
+ f[0] = 5180;
+ t[1] = eep->modalHeader5G.tempSlope;
+ f[1] = 5500;
+ t[2] = eep->base_ext2.tempSlopeHigh;
+ f[2] = 5785;
+ tempSlope = ar9003_hw_power_interpolate((s32) frequency,
+ f, t, 3);
+ } else
tempSlope = eep->modalHeader5G.tempSlope;
REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
@@ -1753,11 +4376,11 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
/* interpolate */
for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
- ath_print(common, ATH_DBG_EEPROM,
- "ch=%d f=%d low=%d %d h=%d %d\n",
- ichain, frequency, lfrequency[ichain],
- lcorrection[ichain], hfrequency[ichain],
- hcorrection[ichain]);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "ch=%d f=%d low=%d %d h=%d %d\n",
+ ichain, frequency, lfrequency[ichain],
+ lcorrection[ichain], hfrequency[ichain],
+ hcorrection[ichain]);
/* they're the same, so just pick one */
if (hfrequency[ichain] == lfrequency[ichain]) {
correction[ichain] = lcorrection[ichain];
@@ -1769,25 +4392,23 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
/* so is the high frequency, interpolate */
if (hfrequency[ichain] - frequency < 1000) {
- correction[ichain] = lcorrection[ichain] +
- (((frequency - lfrequency[ichain]) *
- (hcorrection[ichain] -
- lcorrection[ichain])) /
- (hfrequency[ichain] - lfrequency[ichain]));
-
- temperature[ichain] = ltemperature[ichain] +
- (((frequency - lfrequency[ichain]) *
- (htemperature[ichain] -
- ltemperature[ichain])) /
- (hfrequency[ichain] - lfrequency[ichain]));
-
- voltage[ichain] =
- lvoltage[ichain] +
- (((frequency -
- lfrequency[ichain]) * (hvoltage[ichain] -
- lvoltage[ichain]))
- / (hfrequency[ichain] -
- lfrequency[ichain]));
+ correction[ichain] = interpolate(frequency,
+ lfrequency[ichain],
+ hfrequency[ichain],
+ lcorrection[ichain],
+ hcorrection[ichain]);
+
+ temperature[ichain] = interpolate(frequency,
+ lfrequency[ichain],
+ hfrequency[ichain],
+ ltemperature[ichain],
+ htemperature[ichain]);
+
+ voltage[ichain] = interpolate(frequency,
+ lfrequency[ichain],
+ hfrequency[ichain],
+ lvoltage[ichain],
+ hvoltage[ichain]);
}
/* only low is good, use it */
else {
@@ -1811,9 +4432,9 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
ar9003_hw_power_control_override(ah, frequency, correction, voltage,
temperature);
- ath_print(common, ATH_DBG_EEPROM,
- "for frequency=%d, calibration correction = %d %d %d\n",
- frequency, correction[0], correction[1], correction[2]);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "for frequency=%d, calibration correction = %d %d %d\n",
+ frequency, correction[0], correction[1], correction[2]);
return 0;
}
@@ -1827,9 +4448,9 @@ static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
if (is2GHz)
- return ctl_2g[idx].ctlEdges[edge].tPower;
+ return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]);
else
- return ctl_5g[idx].ctlEdges[edge].tPower;
+ return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]);
}
static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
@@ -1847,15 +4468,15 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
if (is2GHz) {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
- ctl_2g[idx].ctlEdges[edge - 1].flag)
- return ctl_2g[idx].ctlEdges[edge - 1].tPower;
+ CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1]))
+ return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]);
} else {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
- ctl_5g[idx].ctlEdges[edge - 1].flag)
- return ctl_5g[idx].ctlEdges[edge - 1].tPower;
+ CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1]))
+ return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]);
}
- return AR9300_MAX_RATE_POWER;
+ return MAX_RATE_POWER;
}
/*
@@ -1864,7 +4485,7 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
u16 freq, int idx, bool is2GHz)
{
- u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
u8 *ctl_freqbin = is2GHz ?
&eep->ctl_freqbin_2G[idx][0] :
&eep->ctl_freqbin_5G[idx][0];
@@ -1874,7 +4495,7 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
/* Get the edge power */
for (edge = 0;
- (edge < num_edges) && (ctl_freqbin[edge] != AR9300_BCHAN_UNUSED);
+ (edge < num_edges) && (ctl_freqbin[edge] != AR5416_BCHAN_UNUSED);
edge++) {
/*
* If there's an exact channel match or an inband flag set
@@ -1912,21 +4533,23 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_common *common = ath9k_hw_common(ah);
struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
- u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
static const u16 tpScaleReductionTable[5] = {
- 0, 3, 6, 9, AR9300_MAX_RATE_POWER
+ 0, 3, 6, 9, MAX_RATE_POWER
};
int i;
int16_t twiceLargestAntenna;
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11a[] = {
+ static const u16 ctlModesFor11a[] = {
CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
};
- u16 ctlModesFor11g[] = {
+ static const u16 ctlModesFor11g[] = {
CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT,
CTL_11G_EXT, CTL_2GHT40
};
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ u16 numCtlModes;
+ const u16 *pCtlMode;
+ u16 ctlMode, freq;
struct chan_centers centers;
u8 *ctlIndex;
u8 ctlNum;
@@ -2016,11 +4639,10 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
else
freq = centers.ctl_center;
- ath_print(common, ATH_DBG_REGULATORY,
- "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
- "EXT_ADDITIVE %d\n",
- ctlMode, numCtlModes, isHt40CtlMode,
- (pCtlMode[ctlMode] & EXT_ADDITIVE));
+ ath_dbg(common, ATH_DBG_REGULATORY,
+ "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, EXT_ADDITIVE %d\n",
+ ctlMode, numCtlModes, isHt40CtlMode,
+ (pCtlMode[ctlMode] & EXT_ADDITIVE));
/* walk through each CTL index stored in EEPROM */
if (is2ghz) {
@@ -2032,12 +4654,10 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
}
for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
- ath_print(common, ATH_DBG_REGULATORY,
- "LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
- "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
- "chan %dn",
- i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
- chan->channel);
+ ath_dbg(common, ATH_DBG_REGULATORY,
+ "LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n",
+ i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
+ chan->channel);
/*
* compare test group from regulatory
@@ -2076,11 +4696,10 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
- ath_print(common, ATH_DBG_REGULATORY,
- "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d "
- "sP %d minCtlPwr %d\n",
- ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
- scaledPower, minCtlPower);
+ ath_dbg(common, ATH_DBG_REGULATORY,
+ "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
/* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) {
@@ -2127,40 +4746,101 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
} /* end ctl mode checking */
}
+static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx)
+{
+ u8 mod_idx = mcs_idx % 8;
+
+ if (mod_idx <= 3)
+ return mod_idx ? (base_pwridx + 1) : base_pwridx;
+ else
+ return base_pwridx + 4 * (mcs_idx / 8) + mod_idx - 2;
+}
+
static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+ u8 powerLimit, bool test)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_common *common = ath9k_hw_common(ah);
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_modal_eep_header *modal_hdr;
u8 targetPowerValT2[ar9300RateSize];
- unsigned int i = 0;
+ u8 target_power_val_t2_eep[ar9300RateSize];
+ unsigned int i = 0, paprd_scale_factor = 0;
+ u8 pwr_idx, min_pwridx = 0;
ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
+
+ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
+ if (IS_CHAN_2GHZ(chan))
+ modal_hdr = &eep->modalHeader2G;
+ else
+ modal_hdr = &eep->modalHeader5G;
+
+ ah->paprd_ratemask =
+ le32_to_cpu(modal_hdr->papdRateMaskHt20) &
+ AR9300_PAPRD_RATE_MASK;
+
+ ah->paprd_ratemask_ht40 =
+ le32_to_cpu(modal_hdr->papdRateMaskHt40) &
+ AR9300_PAPRD_RATE_MASK;
+
+ paprd_scale_factor = ar9003_get_paprd_scale_factor(ah, chan);
+ min_pwridx = IS_CHAN_HT40(chan) ? ALL_TARGET_HT40_0_8_16 :
+ ALL_TARGET_HT20_0_8_16;
+
+ if (!ah->paprd_table_write_done) {
+ memcpy(target_power_val_t2_eep, targetPowerValT2,
+ sizeof(targetPowerValT2));
+ for (i = 0; i < 24; i++) {
+ pwr_idx = mcsidx_to_tgtpwridx(i, min_pwridx);
+ if (ah->paprd_ratemask & (1 << i)) {
+ if (targetPowerValT2[pwr_idx] &&
+ targetPowerValT2[pwr_idx] ==
+ target_power_val_t2_eep[pwr_idx])
+ targetPowerValT2[pwr_idx] -=
+ paprd_scale_factor;
+ }
+ }
+ }
+ memcpy(target_power_val_t2_eep, targetPowerValT2,
+ sizeof(targetPowerValT2));
+ }
+
ar9003_hw_set_power_per_rate_table(ah, chan,
targetPowerValT2, cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower,
powerLimit);
- while (i < ar9300RateSize) {
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
- i++;
- ath_print(common, ATH_DBG_EEPROM,
- "TPC[%02d] 0x%08x\n\n", i, targetPowerValT2[i]);
- i++;
+ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
+ for (i = 0; i < ar9300RateSize; i++) {
+ if ((ah->paprd_ratemask & (1 << i)) &&
+ (abs(targetPowerValT2[i] -
+ target_power_val_t2_eep[i]) >
+ paprd_scale_factor)) {
+ ah->paprd_ratemask &= ~(1 << i);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "paprd disabled for mcs %d\n", i);
+ }
+ }
}
- /* Write target power array to registers */
- ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+ regulatory->max_power_level = 0;
+ for (i = 0; i < ar9300RateSize; i++) {
+ if (targetPowerValT2[i] > regulatory->max_power_level)
+ regulatory->max_power_level = targetPowerValT2[i];
+ }
+
+ if (test)
+ return;
+
+ for (i = 0; i < ar9300RateSize; i++) {
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
+ }
/*
* This is the TX power we send back to driver core,
@@ -2180,8 +4860,24 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
i = ALL_TARGET_HT20_0_8_16; /* ht20 */
ah->txpower_limit = targetPowerValT2[i];
+ regulatory->max_power_level = targetPowerValT2[i];
+ /* Write target power array to registers */
+ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
ar9003_hw_calibration_apply(ah, chan->channel);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ if (IS_CHAN_HT40(chan))
+ i = ALL_TARGET_HT40_0_8_16;
+ else
+ i = ALL_TARGET_HT20_0_8_16;
+ } else {
+ if (IS_CHAN_HT40(chan))
+ i = ALL_TARGET_HT40_7;
+ else
+ i = ALL_TARGET_HT20_7;
+ }
+ ah->paprd_target_power = targetPowerValT2[i];
}
static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
@@ -2204,14 +4900,43 @@ s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah)
return (eep->baseEepHeader.txrxgain) & 0xf; /* bits 3:0 */
}
+u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+ if (is_2ghz)
+ return eep->modalHeader2G.spurChans;
+ else
+ return eep->modalHeader5G.spurChans;
+}
+
+unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+ if (IS_CHAN_2GHZ(chan))
+ return MS(le32_to_cpu(eep->modalHeader2G.papdRateMaskHt20),
+ AR9300_PAPRD_SCALE_1);
+ else {
+ if (chan->channel >= 5700)
+ return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
+ AR9300_PAPRD_SCALE_1);
+ else if (chan->channel >= 5400)
+ return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
+ AR9300_PAPRD_SCALE_2);
+ else
+ return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
+ AR9300_PAPRD_SCALE_1);
+ }
+}
+
const struct eeprom_ops eep_ar9300_ops = {
.check_eeprom = ath9k_hw_ar9300_check_eeprom,
.get_eeprom = ath9k_hw_ar9300_get_eeprom,
.fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
.get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_ar9300_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_ar9300_get_eeprom_antenna_cfg,
.set_board_values = ath9k_hw_ar9300_set_board_values,
.set_addac = ath9k_hw_ar9300_set_addac,
.set_txpower = ath9k_hw_ar9300_set_txpower,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 3c533bb983c7..afb0b5ee1865 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -20,47 +20,22 @@
/* #define AR9300_NUM_CTLS 21 */
#define AR9300_NUM_CTLS_5G 9
#define AR9300_NUM_CTLS_2G 12
-#define AR9300_CTL_MODE_M 0xF
#define AR9300_NUM_BAND_EDGES_5G 8
#define AR9300_NUM_BAND_EDGES_2G 4
-#define AR9300_NUM_PD_GAINS 4
-#define AR9300_PD_GAINS_IN_MASK 4
-#define AR9300_PD_GAIN_ICEPTS 5
-#define AR9300_EEPROM_MODAL_SPURS 5
-#define AR9300_MAX_RATE_POWER 63
-#define AR9300_NUM_PDADC_VALUES 128
-#define AR9300_NUM_RATES 16
-#define AR9300_BCHAN_UNUSED 0xFF
-#define AR9300_MAX_PWR_RANGE_IN_HALF_DB 64
-#define AR9300_OPFLAGS_11A 0x01
-#define AR9300_OPFLAGS_11G 0x02
-#define AR9300_OPFLAGS_5G_HT40 0x04
-#define AR9300_OPFLAGS_2G_HT40 0x08
-#define AR9300_OPFLAGS_5G_HT20 0x10
-#define AR9300_OPFLAGS_2G_HT20 0x20
#define AR9300_EEPMISC_BIG_ENDIAN 0x01
#define AR9300_EEPMISC_WOW 0x02
#define AR9300_CUSTOMER_DATA_SIZE 20
-#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x))
#define AR9300_MAX_CHAINS 3
#define AR9300_ANT_16S 25
#define AR9300_FUTURE_MODAL_SZ 6
-#define AR9300_NUM_ANT_CHAIN_FIELDS 7
-#define AR9300_NUM_ANT_COMMON_FIELDS 4
-#define AR9300_SIZE_ANT_CHAIN_FIELD 3
-#define AR9300_SIZE_ANT_COMMON_FIELD 4
-#define AR9300_ANT_CHAIN_MASK 0x7
-#define AR9300_ANT_COMMON_MASK 0xf
-#define AR9300_CHAIN_0_IDX 0
-#define AR9300_CHAIN_1_IDX 1
-#define AR9300_CHAIN_2_IDX 2
-
-#define AR928X_NUM_ANT_CHAIN_FIELDS 6
-#define AR928X_SIZE_ANT_CHAIN_FIELD 2
-#define AR928X_ANT_CHAIN_MASK 0x3
+#define AR9300_PAPRD_RATE_MASK 0x01ffffff
+#define AR9300_PAPRD_SCALE_1 0x0e000000
+#define AR9300_PAPRD_SCALE_1_S 25
+#define AR9300_PAPRD_SCALE_2 0x70000000
+#define AR9300_PAPRD_SCALE_2_S 28
/* Delta from which to start power to pdadc table */
/* This offset is used in both open loop and closed loop power control
@@ -71,14 +46,20 @@
*/
#define AR9300_PWR_TABLE_OFFSET 0
-/* enable flags for voltage and temp compensation */
-#define ENABLE_TEMP_COMPENSATION 0x01
-#define ENABLE_VOLT_COMPENSATION 0x02
/* byte addressable */
#define AR9300_EEPROM_SIZE (16*1024)
-#define FIXED_CCA_THRESHOLD 15
+#define AR9300_BASE_ADDR_4K 0xfff
#define AR9300_BASE_ADDR 0x3ff
+#define AR9300_BASE_ADDR_512 0x1ff
+
+#define AR9300_OTP_BASE 0x14000
+#define AR9300_OTP_STATUS 0x15f18
+#define AR9300_OTP_STATUS_TYPE 0x7
+#define AR9300_OTP_STATUS_VALID 0x4
+#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
+#define AR9300_OTP_STATUS_SM_BUSY 0x1
+#define AR9300_OTP_READ_DATA 0x15f1c
enum targetPowerHTRates {
HT_TARGET_RATE_0_8_16,
@@ -216,7 +197,7 @@ struct ar9300_modal_eep_header {
int8_t tempSlope;
int8_t voltSlope;
/* spur channels in usual fbin coding format */
- u8 spurChans[AR9300_EEPROM_MODAL_SPURS];
+ u8 spurChans[AR_EEPROM_MODAL_SPURS];
/* 3 Check if the register is per chain */
int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
u8 ob[AR9300_MAX_CHAINS];
@@ -236,7 +217,7 @@ struct ar9300_modal_eep_header {
u8 thresh62;
__le32 papdRateMaskHt20;
__le32 papdRateMaskHt40;
- u8 futureModal[24];
+ u8 futureModal[10];
} __packed;
struct ar9300_cal_data_per_freq_op_loop {
@@ -261,17 +242,26 @@ struct cal_tgt_pow_ht {
u8 tPow2x[14];
} __packed;
-struct cal_ctl_edge_pwr {
- u8 tPower:6,
- flag:2;
-} __packed;
-
struct cal_ctl_data_2g {
- struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G];
+ u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G];
} __packed;
struct cal_ctl_data_5g {
- struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+ u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+} __packed;
+
+struct ar9300_BaseExtension_1 {
+ u8 ant_div_control;
+ u8 future[13];
+} __packed;
+
+struct ar9300_BaseExtension_2 {
+ int8_t tempSlopeLow;
+ int8_t tempSlopeHigh;
+ u8 xatten1DBLow[AR9300_MAX_CHAINS];
+ u8 xatten1MarginLow[AR9300_MAX_CHAINS];
+ u8 xatten1DBHigh[AR9300_MAX_CHAINS];
+ u8 xatten1MarginHigh[AR9300_MAX_CHAINS];
} __packed;
struct ar9300_eeprom {
@@ -283,6 +273,7 @@ struct ar9300_eeprom {
struct ar9300_base_eep_hdr baseEepHeader;
struct ar9300_modal_eep_header modalHeader2G;
+ struct ar9300_BaseExtension_1 base_ext1;
u8 calFreqPier2G[AR9300_NUM_2G_CAL_PIERS];
struct ar9300_cal_data_per_freq_op_loop
calPierData2G[AR9300_MAX_CHAINS][AR9300_NUM_2G_CAL_PIERS];
@@ -302,6 +293,7 @@ struct ar9300_eeprom {
u8 ctl_freqbin_2G[AR9300_NUM_CTLS_2G][AR9300_NUM_BAND_EDGES_2G];
struct cal_ctl_data_2g ctlPowerData_2G[AR9300_NUM_CTLS_2G];
struct ar9300_modal_eep_header modalHeader5G;
+ struct ar9300_BaseExtension_2 base_ext2;
u8 calFreqPier5G[AR9300_NUM_5G_CAL_PIERS];
struct ar9300_cal_data_per_freq_op_loop
calPierData5G[AR9300_MAX_CHAINS][AR9300_NUM_5G_CAL_PIERS];
@@ -322,4 +314,8 @@ struct ar9300_eeprom {
s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah);
s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah);
+u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz);
+
+unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
+ struct ath9k_channel *chan);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index c2a057156bfa..6137634e46ca 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -17,20 +17,10 @@
#include "hw.h"
#include "ar9003_mac.h"
#include "ar9003_2p2_initvals.h"
+#include "ar9485_initvals.h"
/* General hardware code for the AR9003 hadware family */
-static bool ar9003_hw_macversion_supported(u32 macversion)
-{
- switch (macversion) {
- case AR_SREV_VERSION_9300:
- return true;
- default:
- break;
- }
- return false;
-}
-
/*
* The AR9003 family uses a new INI format (pre, core, post
* arrays per subsystem). This provides support for the
@@ -38,72 +28,134 @@ static bool ar9003_hw_macversion_supported(u32 macversion)
*/
static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
{
- /* mac */
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
- ar9300_2p2_mac_core,
- ARRAY_SIZE(ar9300_2p2_mac_core), 2);
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
- ar9300_2p2_mac_postamble,
- ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
-
- /* bb */
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
- ar9300_2p2_baseband_core,
- ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
- ar9300_2p2_baseband_postamble,
- ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
-
- /* radio */
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
- ar9300_2p2_radio_core,
- ARRAY_SIZE(ar9300_2p2_radio_core), 2);
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
- ar9300_2p2_radio_postamble,
- ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
-
- /* soc */
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
- ar9300_2p2_soc_preamble,
- ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
- ar9300_2p2_soc_postamble,
- ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
-
- /* rx/tx gain */
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
- 5);
-
- /* Load PCIE SERDES settings from INI */
-
- /* Awake Setting */
-
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
- ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
- 2);
-
- /* Sleep Setting */
-
- INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
- ar9300PciePhy_clkreq_enable_L1_2p2,
- ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
- 2);
-
- /* Fast clock modal settings */
- INIT_INI_ARRAY(&ah->iniModesAdditional,
- ar9300Modes_fast_clock_2p2,
- ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
- 3);
+ if (AR_SREV_9485(ah)) {
+ /* mac */
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ ar9485_1_0_mac_core,
+ ARRAY_SIZE(ar9485_1_0_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9485_1_0_mac_postamble,
+ ARRAY_SIZE(ar9485_1_0_mac_postamble), 5);
+
+ /* bb */
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0,
+ ARRAY_SIZE(ar9485_1_0), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9485_1_0_baseband_core,
+ ARRAY_SIZE(ar9485_1_0_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9485_1_0_baseband_postamble,
+ ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5);
+
+ /* radio */
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9485_1_0_radio_core,
+ ARRAY_SIZE(ar9485_1_0_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9485_1_0_radio_postamble,
+ ARRAY_SIZE(ar9485_1_0_radio_postamble), 2);
+
+ /* soc */
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9485_1_0_soc_preamble,
+ ARRAY_SIZE(ar9485_1_0_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
+
+ /* rx/tx gain */
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9485Common_rx_gain_1_0,
+ ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_lowest_ob_db_tx_gain_1_0,
+ ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ 5);
+
+ /* Load PCIE SERDES settings from INI */
+
+ /* Awake Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1,
+ ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1),
+ 2);
+
+ /* Sleep Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+ ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1,
+ ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1),
+ 2);
+ } else {
+ /* mac */
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ ar9300_2p2_mac_core,
+ ARRAY_SIZE(ar9300_2p2_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9300_2p2_mac_postamble,
+ ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
+
+ /* bb */
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9300_2p2_baseband_core,
+ ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9300_2p2_baseband_postamble,
+ ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
+
+ /* radio */
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9300_2p2_radio_core,
+ ARRAY_SIZE(ar9300_2p2_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9300_2p2_radio_postamble,
+ ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
+
+ /* soc */
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9300_2p2_soc_preamble,
+ ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9300_2p2_soc_postamble,
+ ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
+
+ /* rx/tx gain */
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
+
+ /* Load PCIE SERDES settings from INI */
+
+ /* Awake Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+ 2);
+
+ /* Sleep Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+ ar9300PciePhy_clkreq_enable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+ 2);
+
+ /* Fast clock modal settings */
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9300Modes_fast_clock_2p2,
+ ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
+ 3);
+ }
}
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
@@ -111,22 +163,52 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
- 5);
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_lowest_ob_db_tx_gain_1_0,
+ ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
- 5);
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_high_ob_db_tx_gain_1_0,
+ ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 2:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_low_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
- 5);
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_low_ob_db_tx_gain_1_0,
+ ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+ 5);
+ break;
+ case 3:
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_high_power_tx_gain_1_0,
+ ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_power_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2),
+ 5);
break;
}
}
@@ -136,16 +218,28 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_rx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
- 2);
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9485Common_rx_gain_1_0,
+ ARRAY_SIZE(ar9485Common_rx_gain_1_0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+ 2);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
- 2);
+ if (AR_SREV_9485(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9485Common_wo_xlna_rx_gain_1_0,
+ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+ 2);
break;
}
}
@@ -216,7 +310,6 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
- priv_ops->macversion_supported = ar9003_hw_macversion_supported;
ops->config_pci_powersave = ar9003_hw_configpcipowersave;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 3b424ca1ba84..4ceddbbdfcee 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -182,8 +182,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
}
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
- ath_print(common, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+ ath_dbg(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
@@ -237,73 +237,76 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts)
{
struct ar9003_txs *ads;
+ u32 status;
ads = &ah->ts_ring[ah->ts_tail];
- if ((ads->status8 & AR_TxDone) == 0)
+ status = ACCESS_ONCE(ads->status8);
+ if ((status & AR_TxDone) == 0)
return -EINPROGRESS;
ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
(MS(ads->ds_info, AR_TxRxDesc) != 1)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
- "Tx Descriptor error %x\n", ads->ds_info);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT,
+ "Tx Descriptor error %x\n", ads->ds_info);
memset(ads, 0, sizeof(*ads));
return -EIO;
}
+ if (status & AR_TxOpExceeded)
+ ts->ts_status |= ATH9K_TXERR_XTXOP;
+ ts->ts_rateindex = MS(status, AR_FinalTxIdx);
+ ts->ts_seqnum = MS(status, AR_SeqNum);
+ ts->tid = MS(status, AR_TxTid);
+
ts->qid = MS(ads->ds_info, AR_TxQcuNum);
ts->desc_id = MS(ads->status1, AR_TxDescId);
- ts->ts_seqnum = MS(ads->status8, AR_SeqNum);
ts->ts_tstamp = ads->status4;
ts->ts_status = 0;
ts->ts_flags = 0;
- if (ads->status3 & AR_ExcessiveRetries)
+ status = ACCESS_ONCE(ads->status2);
+ ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
+ ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
+ ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02);
+ if (status & AR_TxBaStatus) {
+ ts->ts_flags |= ATH9K_TX_BA;
+ ts->ba_low = ads->status5;
+ ts->ba_high = ads->status6;
+ }
+
+ status = ACCESS_ONCE(ads->status3);
+ if (status & AR_ExcessiveRetries)
ts->ts_status |= ATH9K_TXERR_XRETRY;
- if (ads->status3 & AR_Filtered)
+ if (status & AR_Filtered)
ts->ts_status |= ATH9K_TXERR_FILT;
- if (ads->status3 & AR_FIFOUnderrun) {
+ if (status & AR_FIFOUnderrun) {
ts->ts_status |= ATH9K_TXERR_FIFO;
ath9k_hw_updatetxtriglevel(ah, true);
}
- if (ads->status8 & AR_TxOpExceeded)
- ts->ts_status |= ATH9K_TXERR_XTXOP;
- if (ads->status3 & AR_TxTimerExpired)
+ if (status & AR_TxTimerExpired)
ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
- if (ads->status3 & AR_DescCfgErr)
+ if (status & AR_DescCfgErr)
ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
- if (ads->status3 & AR_TxDataUnderrun) {
+ if (status & AR_TxDataUnderrun) {
ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
ath9k_hw_updatetxtriglevel(ah, true);
}
- if (ads->status3 & AR_TxDelimUnderrun) {
+ if (status & AR_TxDelimUnderrun) {
ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
ath9k_hw_updatetxtriglevel(ah, true);
}
- if (ads->status2 & AR_TxBaStatus) {
- ts->ts_flags |= ATH9K_TX_BA;
- ts->ba_low = ads->status5;
- ts->ba_high = ads->status6;
- }
+ ts->ts_shortretry = MS(status, AR_RTSFailCnt);
+ ts->ts_longretry = MS(status, AR_DataFailCnt);
+ ts->ts_virtcol = MS(status, AR_VirtRetryCnt);
- ts->ts_rateindex = MS(ads->status8, AR_FinalTxIdx);
-
- ts->ts_rssi = MS(ads->status7, AR_TxRSSICombined);
- ts->ts_rssi_ctl0 = MS(ads->status2, AR_TxRSSIAnt00);
- ts->ts_rssi_ctl1 = MS(ads->status2, AR_TxRSSIAnt01);
- ts->ts_rssi_ctl2 = MS(ads->status2, AR_TxRSSIAnt02);
- ts->ts_rssi_ext0 = MS(ads->status7, AR_TxRSSIAnt10);
- ts->ts_rssi_ext1 = MS(ads->status7, AR_TxRSSIAnt11);
- ts->ts_rssi_ext2 = MS(ads->status7, AR_TxRSSIAnt12);
- ts->ts_shortretry = MS(ads->status3, AR_RTSFailCnt);
- ts->ts_longretry = MS(ads->status3, AR_DataFailCnt);
- ts->ts_virtcol = MS(ads->status3, AR_VirtRetryCnt);
- ts->ts_antenna = 0;
-
- ts->tid = MS(ads->status8, AR_TxTid);
+ status = ACCESS_ONCE(ads->status7);
+ ts->ts_rssi = MS(status, AR_TxRSSICombined);
+ ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10);
+ ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
+ ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
memset(ads, 0, sizeof(*ads));
@@ -319,7 +322,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
if (txpower > ah->txpower_limit)
txpower = ah->txpower_limit;
- txpower += ah->txpower_indexoffset;
if (txpower > 63)
txpower = 63;
@@ -407,12 +409,36 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
u32 aggrLen)
{
+#define FIRST_DESC_NDELIMS 60
struct ar9003_txc *ads = (struct ar9003_txc *) ds;
ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
- ads->ctl17 &= ~AR_AggrLen;
- ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+ if (ah->ent_mode & AR_ENT_OTP_MPSD) {
+ u32 ctl17, ndelim;
+ /*
+ * Add delimiter when using RTS/CTS with aggregation
+ * and non enterprise AR9003 card
+ */
+ ctl17 = ads->ctl17;
+ ndelim = MS(ctl17, AR_PadDelim);
+
+ if (ndelim < FIRST_DESC_NDELIMS) {
+ aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4;
+ ndelim = FIRST_DESC_NDELIMS;
+ }
+
+ ctl17 &= ~AR_AggrLen;
+ ctl17 |= SM(aggrLen, AR_AggrLen);
+
+ ctl17 &= ~AR_PadDelim;
+ ctl17 |= SM(ndelim, AR_PadDelim);
+
+ ads->ctl17 = ctl17;
+ } else {
+ ads->ctl17 &= ~AR_AggrLen;
+ ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+ }
}
static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
@@ -587,9 +613,9 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
* possibly be reviewing the last subframe. AR_CRCErr
* is the CRC of the actual data.
*/
- if (rxsp->status11 & AR_CRCErr) {
+ if (rxsp->status11 & AR_CRCErr)
rxs->rs_status |= ATH9K_RXERR_CRC;
- } else if (rxsp->status11 & AR_PHYErr) {
+ if (rxsp->status11 & AR_PHYErr) {
phyerr = MS(rxsp->status11, AR_PHYErrCode);
/*
* If we reach a point here where AR_PostDelimCRCErr is
@@ -612,11 +638,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_phyerr = phyerr;
}
- } else if (rxsp->status11 & AR_DecryptCRCErr) {
+ }
+ if (rxsp->status11 & AR_DecryptCRCErr)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
- } else if (rxsp->status11 & AR_MichaelErr) {
+ if (rxsp->status11 & AR_MichaelErr)
rxs->rs_status |= ATH9K_RXERR_MIC;
- } else if (rxsp->status11 & AR_KeyMiss)
+ if (rxsp->status11 & AR_KeyMiss)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
}
@@ -631,10 +658,10 @@ void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah)
memset((void *) ah->ts_ring, 0,
ah->ts_size * sizeof(struct ar9003_txs));
- ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
- "TS Start 0x%x End 0x%x Virt %p, Size %d\n",
- ah->ts_paddr_start, ah->ts_paddr_end,
- ah->ts_ring, ah->ts_size);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT,
+ "TS Start 0x%x End 0x%x Virt %p, Size %d\n",
+ ah->ts_paddr_start, ah->ts_paddr_end,
+ ah->ts_ring, ah->ts_size);
REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start);
REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index 9f2cea70a840..45cc7e80436c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -65,7 +65,7 @@ struct ar9003_rxs {
u32 status9;
u32 status10;
u32 status11;
-} __packed;
+} __packed __aligned(4);
/* Transmit Control Descriptor */
struct ar9003_txc {
@@ -93,7 +93,7 @@ struct ar9003_txc {
u32 ctl21; /* DMA control 21 */
u32 ctl22; /* DMA control 22 */
u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */
-} __packed;
+} __packed __aligned(4);
struct ar9003_txs {
u32 ds_info;
@@ -105,7 +105,7 @@ struct ar9003_txs {
u32 status6;
u32 status7;
u32 status8;
-} __packed;
+} __packed __aligned(4);
void ar9003_hw_attach_mac_ops(struct ath_hw *hw);
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 716db414c258..356d2fd78822 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -19,45 +19,124 @@
void ar9003_paprd_enable(struct ath_hw *ah, bool val)
{
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath9k_channel *chan = ah->curchan;
+
+ if (val) {
+ ah->paprd_table_write_done = true;
+
+ ah->eep_ops->set_txpower(ah, chan,
+ ath9k_regd_get_ctl(regulatory, chan),
+ chan->chan->max_antenna_gain * 2,
+ chan->chan->max_power * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) regulatory->power_limit), false);
+ }
+
REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
- AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
- AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+ if (ah->caps.tx_chainmask & BIT(1))
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+ if (ah->caps.tx_chainmask & BIT(2))
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
}
EXPORT_SYMBOL(ar9003_paprd_enable);
-static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+static int ar9003_get_training_power_2g(struct ath_hw *ah)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
+ unsigned int power, scale, delta;
+
+ scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1);
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+ delta = abs((int) ah->paprd_target_power - (int) power);
+ if (delta > scale)
+ return -1;
+
+ if (delta < 4)
+ power -= 4 - delta;
+
+ return power;
+}
+
+static int ar9003_get_training_power_5g(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
- struct ar9300_modal_eep_header *hdr;
- const u32 ctrl0[3] = {
+ struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
+ struct ath9k_channel *chan = ah->curchan;
+ unsigned int power, scale, delta;
+
+ if (chan->channel >= 5700)
+ scale = MS(le32_to_cpu(hdr->papdRateMaskHt20),
+ AR9300_PAPRD_SCALE_1);
+ else if (chan->channel >= 5400)
+ scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+ AR9300_PAPRD_SCALE_2);
+ else
+ scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+ AR9300_PAPRD_SCALE_1);
+
+ if (IS_CHAN_HT40(chan))
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
+ AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
+ else
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
+ AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
+
+ power += scale;
+ delta = abs((int) ah->paprd_target_power - (int) power);
+ if (delta > scale)
+ return -1;
+
+ power += 2 * get_streams(common->tx_chainmask);
+ return power;
+}
+
+static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ static const u32 ctrl0[3] = {
AR_PHY_PAPRD_CTRL0_B0,
AR_PHY_PAPRD_CTRL0_B1,
AR_PHY_PAPRD_CTRL0_B2
};
- const u32 ctrl1[3] = {
+ static const u32 ctrl1[3] = {
AR_PHY_PAPRD_CTRL1_B0,
AR_PHY_PAPRD_CTRL1_B1,
AR_PHY_PAPRD_CTRL1_B2
};
- u32 am_mask, ht40_mask;
+ int training_power;
int i;
- if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
- hdr = &eep->modalHeader5G;
+ if (IS_CHAN_2GHZ(ah->curchan))
+ training_power = ar9003_get_training_power_2g(ah);
else
- hdr = &eep->modalHeader2G;
-
- am_mask = le32_to_cpu(hdr->papdRateMaskHt20);
- ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40);
+ training_power = ar9003_get_training_power_5g(ah);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
-
- for (i = 0; i < 3; i++) {
+ if (training_power < 0) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "PAPRD target power delta out of range");
+ return -ERANGE;
+ }
+ ah->paprd_training_power = training_power;
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Training power: %d, Target power: %d\n",
+ ah->paprd_training_power, ah->paprd_target_power);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
+ ah->paprd_ratemask);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
+ ah->paprd_ratemask);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
+ ah->paprd_ratemask_ht40);
+
+ for (i = 0; i < ah->caps.max_txchains; i++) {
REG_RMW_FIELD(ah, ctrl0[i],
AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
REG_RMW_FIELD(ah, ctrl1[i],
@@ -102,8 +181,14 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
- AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
+ if (AR_SREV_9485(ah))
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ -3);
+ else
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ -6);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
-15);
@@ -132,6 +217,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+ return 0;
}
static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
@@ -586,15 +672,10 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
{
u32 *paprd_table_val = caldata->pa_table[chain];
u32 small_signal_gain = caldata->small_signal_gain[chain];
- u32 training_power;
+ u32 training_power = ah->paprd_training_power;
u32 reg = 0;
int i;
- training_power =
- REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
- AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
- training_power -= 4;
-
if (chain == 0)
reg = AR_PHY_PAPRD_MEM_TAB_B0;
else if (chain == 1)
@@ -620,26 +701,22 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
training_power);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
- AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
- training_power);
+ if (ah->caps.tx_chainmask & BIT(1))
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+ training_power);
- REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
- AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
- training_power);
+ if (ah->caps.tx_chainmask & BIT(2))
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+ training_power);
}
EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
{
-
unsigned int i, desired_gain, gain_index;
- unsigned int train_power;
-
- train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
- AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-
- train_power = train_power - 4;
+ unsigned int train_power = ah->paprd_training_power;
desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
@@ -705,7 +782,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve);
int ar9003_paprd_init_table(struct ath_hw *ah)
{
- ar9003_paprd_setup_single_table(ah);
+ int ret;
+
+ ret = ar9003_paprd_setup_single_table(ah);
+ if (ret < 0)
+ return ret;
+
ar9003_paprd_get_gain_table(ah);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 669b777729b3..8d60f4f09acc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -75,7 +75,10 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
freq = centers.synth_center;
if (freq < 4800) { /* 2 GHz, fractional mode */
- channelSel = CHANSEL_2G(freq);
+ if (AR_SREV_9485(ah))
+ channelSel = CHANSEL_2G_9485(freq);
+ else
+ channelSel = CHANSEL_2G(freq);
/* Set to 2G mode */
bMode = 1;
} else {
@@ -128,24 +131,53 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- u32 spur_freq[4] = { 2420, 2440, 2464, 2480 };
+ static const u32 spur_freq[4] = { 2420, 2440, 2464, 2480 };
int cur_bb_spur, negative = 0, cck_spur_freq;
int i;
+ int range, max_spur_cnts, synth_freq;
+ u8 *spur_fbin_ptr = NULL;
/*
* Need to verify range +/- 10 MHz in control channel, otherwise spur
* is out-of-band and can be ignored.
*/
- for (i = 0; i < 4; i++) {
+ if (AR_SREV_9485(ah)) {
+ spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
+ IS_CHAN_2GHZ(chan));
+ if (spur_fbin_ptr[0] == 0) /* No spur */
+ return;
+ max_spur_cnts = 5;
+ if (IS_CHAN_HT40(chan)) {
+ range = 19;
+ if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+ AR_PHY_GC_DYN2040_PRI_CH) == 0)
+ synth_freq = chan->channel + 10;
+ else
+ synth_freq = chan->channel - 10;
+ } else {
+ range = 10;
+ synth_freq = chan->channel;
+ }
+ } else {
+ range = 10;
+ max_spur_cnts = 4;
+ synth_freq = chan->channel;
+ }
+
+ for (i = 0; i < max_spur_cnts; i++) {
negative = 0;
- cur_bb_spur = spur_freq[i] - chan->channel;
+ if (AR_SREV_9485(ah))
+ cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
+ IS_CHAN_2GHZ(chan)) - synth_freq;
+ else
+ cur_bb_spur = spur_freq[i] - synth_freq;
if (cur_bb_spur < 0) {
negative = 1;
cur_bb_spur = -cur_bb_spur;
}
- if (cur_bb_spur < 10) {
+ if (cur_bb_spur < range) {
cck_spur_freq = (int)((cur_bb_spur << 19) / 11);
if (negative == 1)
@@ -487,7 +519,11 @@ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
break;
}
- REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
+ REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
+ else
+ REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+
if (tx == 0x5) {
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
@@ -542,10 +578,7 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah,
u32 reg = INI_RA(iniArr, i, 0);
u32 val = INI_RA(iniArr, i, column);
- if (reg >= 0x16000 && reg < 0x17000)
- ath9k_hw_analog_shift_regwrite(ah, reg, val);
- else
- REG_WRITE(ah, reg, val);
+ REG_WRITE(ah, reg, val);
DO_DELAY(regWrites);
}
@@ -614,7 +647,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit));
+ (u32) regulatory->power_limit), false);
return 0;
}
@@ -712,28 +745,6 @@ static void ar9003_hw_rfbus_done(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
}
-/*
- * Set the interrupt and GPIO values so the ISR can disable RF
- * on a switch signal. Assumes GPIO port and interrupt polarity
- * are set prior to call.
- */
-static void ar9003_hw_enable_rfkill(struct ath_hw *ah)
-{
- /* Connect rfsilent_bb_l to baseband */
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
- /* Set input mux for rfsilent_bb_l to GPIO #0 */
- REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
- AR_GPIO_INPUT_MUX2_RFSILENT);
-
- /*
- * Configure the desired GPIO port for input and
- * enable baseband rf silence.
- */
- ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
- REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-
static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
{
u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
@@ -820,12 +831,12 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
if (!on != aniState->ofdmWeakSigDetectOff) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: ofdm weak signal: %s=>%s\n",
- chan->channel,
- !aniState->ofdmWeakSigDetectOff ?
- "on" : "off",
- on ? "on" : "off");
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: ofdm weak signal: %s=>%s\n",
+ chan->channel,
+ !aniState->ofdmWeakSigDetectOff ?
+ "on" : "off",
+ on ? "on" : "off");
if (on)
ah->stats.ast_ani_ofdmon++;
else
@@ -838,11 +849,9 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(firstep_table)) {
- ath_print(common, ATH_DBG_ANI,
- "ATH9K_ANI_FIRSTEP_LEVEL: level "
- "out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(firstep_table));
+ ath_dbg(common, ATH_DBG_ANI,
+ "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(firstep_table));
return false;
}
@@ -877,24 +886,22 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
if (level != aniState->firstepLevel) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "firstep[level]=%d ini=%d\n",
- chan->channel,
- aniState->firstepLevel,
- level,
- ATH9K_ANI_FIRSTEP_LVL_NEW,
- value,
- aniState->iniDef.firstep);
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "firstep_low[level]=%d ini=%d\n",
- chan->channel,
- aniState->firstepLevel,
- level,
- ATH9K_ANI_FIRSTEP_LVL_NEW,
- value2,
- aniState->iniDef.firstepLow);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value,
+ aniState->iniDef.firstep);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value2,
+ aniState->iniDef.firstepLow);
if (level > aniState->firstepLevel)
ah->stats.ast_ani_stepup++;
else if (level < aniState->firstepLevel)
@@ -907,11 +914,9 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
- ath_print(common, ATH_DBG_ANI,
- "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
- "out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(cycpwrThr1_table));
+ ath_dbg(common, ATH_DBG_ANI,
+ "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
+ level, ARRAY_SIZE(cycpwrThr1_table));
return false;
}
/*
@@ -945,24 +950,22 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
AR_PHY_EXT_CYCPWR_THR1, value2);
if (level != aniState->spurImmunityLevel) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "cycpwrThr1[level]=%d ini=%d\n",
- chan->channel,
- aniState->spurImmunityLevel,
- level,
- ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
- value,
- aniState->iniDef.cycpwrThr1);
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: level %d=>%d[def:%d] "
- "cycpwrThr1Ext[level]=%d ini=%d\n",
- chan->channel,
- aniState->spurImmunityLevel,
- level,
- ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
- value2,
- aniState->iniDef.cycpwrThr1Ext);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value,
+ aniState->iniDef.cycpwrThr1);
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value2,
+ aniState->iniDef.cycpwrThr1Ext);
if (level > aniState->spurImmunityLevel)
ah->stats.ast_ani_spurup++;
else if (level < aniState->spurImmunityLevel)
@@ -982,11 +985,11 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
AR_PHY_MRC_CCK_MUX_REG, is_on);
if (!is_on != aniState->mrcCCKOff) {
- ath_print(common, ATH_DBG_ANI,
- "** ch %d: MRC CCK: %s=>%s\n",
- chan->channel,
- !aniState->mrcCCKOff ? "on" : "off",
- is_on ? "on" : "off");
+ ath_dbg(common, ATH_DBG_ANI,
+ "** ch %d: MRC CCK: %s=>%s\n",
+ chan->channel,
+ !aniState->mrcCCKOff ? "on" : "off",
+ is_on ? "on" : "off");
if (is_on)
ah->stats.ast_ani_ccklow++;
else
@@ -998,22 +1001,19 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
case ATH9K_ANI_PRESENT:
break;
default:
- ath_print(common, ATH_DBG_ANI,
- "invalid cmd %u\n", cmd);
+ ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd);
return false;
}
- ath_print(common, ATH_DBG_ANI,
- "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
- "MRCcck=%s listenTime=%d "
- "ofdmErrs=%d cckErrs=%d\n",
- aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff ? "on" : "off",
- aniState->firstepLevel,
- !aniState->mrcCCKOff ? "on" : "off",
- aniState->listenTime,
- aniState->ofdmPhyErrCount,
- aniState->cckPhyErrCount);
+ ath_dbg(common, ATH_DBG_ANI,
+ "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+ aniState->firstepLevel,
+ !aniState->mrcCCKOff ? "on" : "off",
+ aniState->listenTime,
+ aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
return true;
}
@@ -1023,25 +1023,25 @@ static void ar9003_hw_do_getnf(struct ath_hw *ah,
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
- nfarray[0] = sign_extend(nf, 9);
+ nfarray[0] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
- nfarray[1] = sign_extend(nf, 9);
+ nfarray[1] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
- nfarray[2] = sign_extend(nf, 9);
+ nfarray[2] = sign_extend32(nf, 8);
if (!IS_CHAN_HT40(ah->curchan))
return;
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
- nfarray[3] = sign_extend(nf, 9);
+ nfarray[3] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
- nfarray[4] = sign_extend(nf, 9);
+ nfarray[4] = sign_extend32(nf, 8);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
- nfarray[5] = sign_extend(nf, 9);
+ nfarray[5] = sign_extend32(nf, 8);
}
static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
@@ -1070,13 +1070,13 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
aniState = &ah->curchan->ani;
iniDef = &aniState->iniDef;
- ath_print(common, ATH_DBG_ANI,
- "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
- ah->hw_version.macVersion,
- ah->hw_version.macRev,
- ah->opmode,
- chan->channel,
- chan->channelFlags);
+ ath_dbg(common, ATH_DBG_ANI,
+ "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+ ah->hw_version.macVersion,
+ ah->hw_version.macRev,
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags);
val = REG_READ(ah, AR_PHY_SFCORR);
iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
@@ -1113,10 +1113,55 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
}
+static void ar9003_hw_set_radar_params(struct ath_hw *ah,
+ struct ath_hw_radar_conf *conf)
+{
+ u32 radar_0 = 0, radar_1 = 0;
+
+ if (!conf) {
+ REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+ return;
+ }
+
+ radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA;
+ radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR);
+ radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI);
+ radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT);
+ radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
+ radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+
+ radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
+ radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
+ radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
+ radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH);
+ radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH);
+
+ REG_WRITE(ah, AR_PHY_RADAR_0, radar_0);
+ REG_WRITE(ah, AR_PHY_RADAR_1, radar_1);
+ if (conf->ext_channel)
+ REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+ else
+ REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+}
+
+static void ar9003_hw_set_radar_conf(struct ath_hw *ah)
+{
+ struct ath_hw_radar_conf *conf = &ah->radar_conf;
+
+ conf->fir_power = -28;
+ conf->radar_rssi = 0;
+ conf->pulse_height = 10;
+ conf->pulse_rssi = 24;
+ conf->pulse_inband = 8;
+ conf->pulse_maxlen = 255;
+ conf->pulse_inband_step = 12;
+ conf->radar_inband = 8;
+}
+
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
- const u32 ar9300_cca_regs[6] = {
+ static const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
AR_PHY_CCA_2,
@@ -1136,13 +1181,14 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
priv_ops->rfbus_req = ar9003_hw_rfbus_req;
priv_ops->rfbus_done = ar9003_hw_rfbus_done;
- priv_ops->enable_rfkill = ar9003_hw_enable_rfkill;
priv_ops->set_diversity = ar9003_hw_set_diversity;
priv_ops->ani_control = ar9003_hw_ani_control;
priv_ops->do_getnf = ar9003_hw_do_getnf;
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
+ priv_ops->set_radar_params = ar9003_hw_set_radar_params;
ar9003_hw_set_nf_limits(ah);
+ ar9003_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
}
@@ -1165,7 +1211,7 @@ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
AR_PHY_WATCHDOG_IDLE_ENABLE));
- ath_print(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
+ ath_dbg(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
return;
}
@@ -1201,9 +1247,9 @@ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
AR_PHY_WATCHDOG_IDLE_MASK |
(AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
- ath_print(common, ATH_DBG_RESET,
- "Enabled BB Watchdog timeout (%u ms)\n",
- idle_tmo_ms);
+ ath_dbg(common, ATH_DBG_RESET,
+ "Enabled BB Watchdog timeout (%u ms)\n",
+ idle_tmo_ms);
}
void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
@@ -1231,37 +1277,35 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
return;
status = ah->bb_watchdog_last_status;
- ath_print(common, ATH_DBG_RESET,
- "\n==== BB update: BB status=0x%08x ====\n", status);
- ath_print(common, ATH_DBG_RESET,
- "** BB state: wd=%u det=%u rdar=%u rOFDM=%d "
- "rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
- MS(status, AR_PHY_WATCHDOG_INFO),
- MS(status, AR_PHY_WATCHDOG_DET_HANG),
- MS(status, AR_PHY_WATCHDOG_RADAR_SM),
- MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
- MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
- MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
- MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
- MS(status, AR_PHY_WATCHDOG_AGC_SM),
- MS(status,AR_PHY_WATCHDOG_SRCH_SM));
-
- ath_print(common, ATH_DBG_RESET,
- "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
- REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
- REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
- ath_print(common, ATH_DBG_RESET,
- "** BB mode: BB_gen_controls=0x%08x **\n",
- REG_READ(ah, AR_PHY_GEN_CTRL));
+ ath_dbg(common, ATH_DBG_RESET,
+ "\n==== BB update: BB status=0x%08x ====\n", status);
+ ath_dbg(common, ATH_DBG_RESET,
+ "** BB state: wd=%u det=%u rdar=%u rOFDM=%d rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
+ MS(status, AR_PHY_WATCHDOG_INFO),
+ MS(status, AR_PHY_WATCHDOG_DET_HANG),
+ MS(status, AR_PHY_WATCHDOG_RADAR_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_AGC_SM),
+ MS(status, AR_PHY_WATCHDOG_SRCH_SM));
+
+ ath_dbg(common, ATH_DBG_RESET,
+ "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
+ ath_dbg(common, ATH_DBG_RESET,
+ "** BB mode: BB_gen_controls=0x%08x **\n",
+ REG_READ(ah, AR_PHY_GEN_CTRL));
#define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles)
if (common->cc_survey.cycles)
- ath_print(common, ATH_DBG_RESET,
- "** BB busy times: rx_clear=%d%%, "
- "rx_frame=%d%%, tx_frame=%d%% **\n",
- PCT(rx_busy), PCT(rx_frame), PCT(tx_frame));
+ ath_dbg(common, ATH_DBG_RESET,
+ "** BB busy times: rx_clear=%d%%, rx_frame=%d%%, tx_frame=%d%% **\n",
+ PCT(rx_busy), PCT(rx_frame), PCT(tx_frame));
- ath_print(common, ATH_DBG_RESET,
- "==== BB update: done ====\n\n");
+ ath_dbg(common, ATH_DBG_RESET,
+ "==== BB update: done ====\n\n");
}
EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 3394dfe52b42..59bab6bd8a74 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -260,7 +260,13 @@
#define AR_PHY_CCA_0 (AR_AGC_BASE + 0x1c)
#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20)
#define AR_PHY_RESTART (AR_AGC_BASE + 0x24)
+
#define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28)
+#define AR_ANT_DIV_CTRL_ALL 0x7e000000
+#define AR_ANT_DIV_CTRL_ALL_S 25
+#define AR_ANT_DIV_ENABLE 0x1000000
+#define AR_ANT_DIV_ENABLE_S 24
+
#define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c)
#define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30)
#define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34)
@@ -271,7 +277,11 @@
#define AR_PHY_RX_GAIN_BOUNDS_2 (AR_AGC_BASE + 0x48)
#define AR_PHY_RSSI_0 (AR_AGC_BASE + 0x180)
#define AR_PHY_SPUR_CCK_REP0 (AR_AGC_BASE + 0x184)
+
#define AR_PHY_CCK_DETECT (AR_AGC_BASE + 0x1c0)
+#define AR_FAST_DIV_ENABLE 0x2000
+#define AR_FAST_DIV_ENABLE_S 13
+
#define AR_PHY_DAG_CTRLCCK (AR_AGC_BASE + 0x1c4)
#define AR_PHY_IQCORR_CTRL_CCK (AR_AGC_BASE + 0x1c8)
@@ -536,10 +546,18 @@
#define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300)
+#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4)
+#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000
+#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31
+#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8)
+#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0)
+
#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448)
#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440)
#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c)
-#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0 (AR_SM_BASE + 0x450)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \
+ (AR_SREV_9485(ah) ? \
+ 0x3d0 : 0x450) + ((_i) << 2))
#define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0)
#define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4)
@@ -568,7 +586,7 @@
#define AR_PHY_65NM_CH0_BIAS2 0x160c4
#define AR_PHY_65NM_CH0_BIAS4 0x160cc
#define AR_PHY_65NM_CH0_RXTX4 0x1610c
-#define AR_PHY_65NM_CH0_THERM 0x16290
+#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290)
#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000
#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
@@ -584,6 +602,24 @@
#define AR_PHY_65NM_CH2_RXTX1 0x16900
#define AR_PHY_65NM_CH2_RXTX2 0x16904
+#define AR_CH0_TOP2 (AR_SREV_9485(ah) ? 0x00016284 : 0x0001628c)
+#define AR_CH0_TOP2_XPABIASLVL 0xf000
+#define AR_CH0_TOP2_XPABIASLVL_S 12
+
+#define AR_CH0_XTAL (AR_SREV_9485(ah) ? 0x16290 : 0x16294)
+#define AR_CH0_XTAL_CAPINDAC 0x7f000000
+#define AR_CH0_XTAL_CAPINDAC_S 24
+#define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000
+#define AR_CH0_XTAL_CAPOUTDAC_S 17
+
+#define AR_PHY_PMU1 0x16c40
+#define AR_PHY_PMU1_PWD 0x1
+#define AR_PHY_PMU1_PWD_S 0
+
+#define AR_PHY_PMU2 0x16c44
+#define AR_PHY_PMU2_PGM 0x00200000
+#define AR_PHY_PMU2_PGM_S 21
+
#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT 0x00380000
#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT_S 19
#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT 0x00c00000
@@ -683,6 +719,7 @@
#define AR_PHY_TPCGR1_FORCED_DAC_GAIN_S 1
#define AR_PHY_TPCGR1_FORCE_DAC_GAIN 0x00000001
#define AR_PHY_TXGAIN_FORCE 0x00000001
+#define AR_PHY_TXGAIN_FORCE_S 0
#define AR_PHY_TXGAIN_FORCED_PADVGNRA 0x00003c00
#define AR_PHY_TXGAIN_FORCED_PADVGNRA_S 10
#define AR_PHY_TXGAIN_FORCED_PADVGNRB 0x0003c000
@@ -725,8 +762,13 @@
#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0
#define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001
-#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x00003fff
-#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 0
+#define AR_PHY_CALIBRATED_GAINS_0 0x3e
+#define AR_PHY_CALIBRATED_GAINS_0_S 1
+
+#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE 0x00003fff
+#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE_S 0
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x0fffc000
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 14
#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000
#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28
@@ -785,7 +827,7 @@
#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220)
#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + 0x240)
#define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c)
-#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B1 (AR_SM1_BASE + 0x450)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM_BASE + 0x450 + ((_i) << 2))
/*
* Channel 2 Register Map
@@ -838,7 +880,7 @@
#define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220)
#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240)
#define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c)
-#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B2 (AR_SM2_BASE + 0x450)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i) (AR_SM2_BASE + 0x450 + ((_i) << 2))
#define AR_PHY_TX_IQCAL_STATUS_B2_FAILED 0x00000001
@@ -945,7 +987,9 @@
#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT 0x0ffe0000
#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S 17
-#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + 0x490)
+#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + \
+ (AR_SREV_9485(ah) ? \
+ 0x580 : 0x490))
#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE 0x00000001
#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S 0
#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING 0x0000007e
@@ -961,11 +1005,15 @@
#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP 0x0003f000
#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S 12
-#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + 0x494)
+#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + \
+ (AR_SREV_9485(ah) ? \
+ 0x584 : 0x494))
#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN 0xFFFFFFFF
#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S 0
-#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + 0x498)
+#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + \
+ (AR_SREV_9485(ah) ? \
+ 0x588 : 0x498))
#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE 0x0000003f
#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S 0
#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP 0x00000fc0
@@ -981,7 +1029,9 @@
#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE 0x20000000
#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S 29
-#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + 0x49c)
+#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + \
+ (AR_SREV_9485(ah) ? \
+ 0x58c : 0x49c))
#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES 0x03ff0000
#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S 16
#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA 0x0000f000
@@ -1040,6 +1090,14 @@
#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F
#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0
+#define AR_PHY_POWERTX_RATE6 (AR_SM_BASE + 0x1d4)
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5 0x3F00
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S 8
+
+#define AR_PHY_POWERTX_RATE8 (AR_SM_BASE + 0x1dc)
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8
+
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
#endif /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
new file mode 100644
index 000000000000..70de3d89a7b5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9485_H
+#define INITVALS_9485_H
+
+static const u32 ar9485Common_1_0[][2] = {
+ /* Addr allmodes */
+ {0x00007010, 0x00000022},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+};
+
+static const u32 ar9485_1_0_mac_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x10212e5e},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0000580c},
+};
+
+static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x01800082},
+ {0x0000a014, 0x01820181},
+ {0x0000a018, 0x01840183},
+ {0x0000a01c, 0x01880185},
+ {0x0000a020, 0x018a0189},
+ {0x0000a024, 0x02850284},
+ {0x0000a028, 0x02890288},
+ {0x0000a02c, 0x03850384},
+ {0x0000a030, 0x03890388},
+ {0x0000a034, 0x038b038a},
+ {0x0000a038, 0x038d038c},
+ {0x0000a03c, 0x03910390},
+ {0x0000a040, 0x03930392},
+ {0x0000a044, 0x03950394},
+ {0x0000a048, 0x00000396},
+ {0x0000a04c, 0x00000000},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x28282828},
+ {0x0000a084, 0x28282828},
+ {0x0000a088, 0x28282828},
+ {0x0000a08c, 0x28282828},
+ {0x0000a090, 0x28282828},
+ {0x0000a094, 0x21212128},
+ {0x0000a098, 0x171c1c1c},
+ {0x0000a09c, 0x02020212},
+ {0x0000a0a0, 0x00000202},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x111f1100},
+ {0x0000a0c8, 0x111d111e},
+ {0x0000a0cc, 0x111b111c},
+ {0x0000a0d0, 0x22032204},
+ {0x0000a0d4, 0x22012202},
+ {0x0000a0d8, 0x221f2200},
+ {0x0000a0dc, 0x221d221e},
+ {0x0000a0e0, 0x33013302},
+ {0x0000a0e4, 0x331f3300},
+ {0x0000a0e8, 0x4402331e},
+ {0x0000a0ec, 0x44004401},
+ {0x0000a0f0, 0x441e441f},
+ {0x0000a0f4, 0x55015502},
+ {0x0000a0f8, 0x551f5500},
+ {0x0000a0fc, 0x6602551e},
+ {0x0000a100, 0x66006601},
+ {0x0000a104, 0x661e661f},
+ {0x0000a108, 0x7703661d},
+ {0x0000a10c, 0x77017702},
+ {0x0000a110, 0x00007700},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x111f1100},
+ {0x0000a148, 0x111d111e},
+ {0x0000a14c, 0x111b111c},
+ {0x0000a150, 0x22032204},
+ {0x0000a154, 0x22012202},
+ {0x0000a158, 0x221f2200},
+ {0x0000a15c, 0x221d221e},
+ {0x0000a160, 0x33013302},
+ {0x0000a164, 0x331f3300},
+ {0x0000a168, 0x4402331e},
+ {0x0000a16c, 0x44004401},
+ {0x0000a170, 0x441e441f},
+ {0x0000a174, 0x55015502},
+ {0x0000a178, 0x551f5500},
+ {0x0000a17c, 0x6602551e},
+ {0x0000a180, 0x66006601},
+ {0x0000a184, 0x661e661f},
+ {0x0000a188, 0x7703661d},
+ {0x0000a18c, 0x77017702},
+ {0x0000a190, 0x00007700},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000296},
+};
+
+static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+ {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
+};
+
+static const u32 ar9485_1_0[][2] = {
+ /* Addr allmodes */
+ {0x0000a580, 0x00000000},
+ {0x0000a584, 0x00000000},
+ {0x0000a588, 0x00000000},
+ {0x0000a58c, 0x00000000},
+ {0x0000a590, 0x00000000},
+ {0x0000a594, 0x00000000},
+ {0x0000a598, 0x00000000},
+ {0x0000a59c, 0x00000000},
+ {0x0000a5a0, 0x00000000},
+ {0x0000a5a4, 0x00000000},
+ {0x0000a5a8, 0x00000000},
+ {0x0000a5ac, 0x00000000},
+ {0x0000a5b0, 0x00000000},
+ {0x0000a5b4, 0x00000000},
+ {0x0000a5b8, 0x00000000},
+ {0x0000a5bc, 0x00000000},
+};
+
+static const u32 ar9485_1_0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73800000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x00016048, 0x6c92426e},
+ {0x0001604c, 0x000f0278},
+ {0x00016050, 0x6db6db6c},
+ {0x00016054, 0x6db60000},
+ {0x00016080, 0x00080000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x14214514},
+ {0x0001608c, 0x119f081e},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd28b3330},
+ {0x000160a0, 0xc2108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480040},
+ {0x000160c0, 0x006db6db},
+ {0x000160c4, 0x0186db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x6de6fbe0},
+ {0x000160d0, 0xf7dfcf3c},
+ {0x00016100, 0x04cb0001},
+ {0x00016104, 0xfff80015},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x01884080},
+ {0x00016148, 0x00008040},
+ {0x00016180, 0x08453333},
+ {0x00016184, 0x18e82f01},
+ {0x00016188, 0x00000000},
+ {0x0001618c, 0x00000000},
+ {0x00016240, 0x08400000},
+ {0x00016244, 0x1bf90f00},
+ {0x00016248, 0x00000000},
+ {0x0001624c, 0x00000000},
+ {0x00016280, 0x01000015},
+ {0x00016284, 0x00d30000},
+ {0x00016288, 0x00318000},
+ {0x0001628c, 0x50000000},
+ {0x00016290, 0x4b96210f},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016c40, 0x1319c178},
+ {0x00016c44, 0x10000000},
+};
+
+static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+ {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
+};
+
+static const u32 ar9485_1_0_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a8f6b},
+ {0x0000980c, 0x04800000},
+ {0x00009814, 0x9280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x5f3ca3de},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x14750600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x52440bbe},
+ {0x000098bc, 0x00000002},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009c04, 0x00000000},
+ {0x00009c08, 0x03200000},
+ {0x00009c0c, 0x00000000},
+ {0x00009c10, 0x00000000},
+ {0x00009c14, 0x00046384},
+ {0x00009c18, 0x05b6b440},
+ {0x00009c1c, 0x00b6b440},
+ {0x00009d00, 0xc080a333},
+ {0x00009d04, 0x40206c10},
+ {0x00009d08, 0x009c4060},
+ {0x00009d0c, 0x1883800a},
+ {0x00009d10, 0x01834061},
+ {0x00009d14, 0x00c00400},
+ {0x00009d18, 0x00000000},
+ {0x00009d1c, 0x00000000},
+ {0x00009e08, 0x0038233c},
+ {0x00009e24, 0x990bb515},
+ {0x00009e28, 0x0a6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009fc0, 0x80be4788},
+ {0x00009fc4, 0x0001efb5},
+ {0x00009fcc, 0x40000014},
+ {0x0000a20c, 0x00000000},
+ {0x0000a210, 0x00000000},
+ {0x0000a220, 0x00000000},
+ {0x0000a224, 0x00000000},
+ {0x0000a228, 0x10002310},
+ {0x0000a23c, 0x00000000},
+ {0x0000a244, 0x0c000000},
+ {0x0000a2a0, 0x00000001},
+ {0x0000a2c0, 0x00000001},
+ {0x0000a2c8, 0x00000000},
+ {0x0000a2cc, 0x18c43433},
+ {0x0000a2d4, 0x00000000},
+ {0x0000a2dc, 0x00000000},
+ {0x0000a2e0, 0x00000000},
+ {0x0000a2e4, 0x00000000},
+ {0x0000a2e8, 0x00000000},
+ {0x0000a2ec, 0x00000000},
+ {0x0000a2f0, 0x00000000},
+ {0x0000a2f4, 0x00000000},
+ {0x0000a2f8, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a34c, 0x00000000},
+ {0x0000a350, 0x0000a000},
+ {0x0000a364, 0x00000000},
+ {0x0000a370, 0x00000000},
+ {0x0000a390, 0x00000001},
+ {0x0000a394, 0x00000444},
+ {0x0000a398, 0x001f0e0f},
+ {0x0000a39c, 0x0075393f},
+ {0x0000a3a0, 0xb79f6427},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0xaaaaaaaa},
+ {0x0000a3ac, 0x3c466478},
+ {0x0000a3c0, 0x20202020},
+ {0x0000a3c4, 0x22222220},
+ {0x0000a3c8, 0x20200020},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3d8, 0x20202020},
+ {0x0000a3dc, 0x20202020},
+ {0x0000a3e0, 0x20202020},
+ {0x0000a3e4, 0x20202020},
+ {0x0000a3e8, 0x20202020},
+ {0x0000a3ec, 0x20202020},
+ {0x0000a3f0, 0x00000000},
+ {0x0000a3f4, 0x00000006},
+ {0x0000a3f8, 0x0cdbd380},
+ {0x0000a3fc, 0x000f0f01},
+ {0x0000a400, 0x8fa91f01},
+ {0x0000a404, 0x00000000},
+ {0x0000a408, 0x0e79e5c6},
+ {0x0000a40c, 0x00820820},
+ {0x0000a414, 0x1ce739ce},
+ {0x0000a418, 0x2d0011ce},
+ {0x0000a41c, 0x1ce739ce},
+ {0x0000a420, 0x000001ce},
+ {0x0000a424, 0x1ce739ce},
+ {0x0000a428, 0x000001ce},
+ {0x0000a42c, 0x1ce739ce},
+ {0x0000a430, 0x1ce739ce},
+ {0x0000a434, 0x00000000},
+ {0x0000a438, 0x00001801},
+ {0x0000a43c, 0x00000000},
+ {0x0000a440, 0x00000000},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x04000000},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a458, 0x00000000},
+ {0x0000a5c4, 0x3fad9d74},
+ {0x0000a5c8, 0x0048060a},
+ {0x0000a5cc, 0x00000637},
+ {0x0000a760, 0x03020100},
+ {0x0000a764, 0x09080504},
+ {0x0000a768, 0x0d0c0b0a},
+ {0x0000a76c, 0x13121110},
+ {0x0000a770, 0x31301514},
+ {0x0000a774, 0x35343332},
+ {0x0000a778, 0x00000036},
+ {0x0000a780, 0x00000838},
+ {0x0000a7c0, 0x00000000},
+ {0x0000a7c4, 0xfffffffc},
+ {0x0000a7c8, 0x00000000},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000001},
+};
+
+static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+ {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
+};
+
+static const u32 ar9485Common_rx_gain_1_0[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x01800082},
+ {0x0000a014, 0x01820181},
+ {0x0000a018, 0x01840183},
+ {0x0000a01c, 0x01880185},
+ {0x0000a020, 0x018a0189},
+ {0x0000a024, 0x02850284},
+ {0x0000a028, 0x02890288},
+ {0x0000a02c, 0x03850384},
+ {0x0000a030, 0x03890388},
+ {0x0000a034, 0x038b038a},
+ {0x0000a038, 0x038d038c},
+ {0x0000a03c, 0x03910390},
+ {0x0000a040, 0x03930392},
+ {0x0000a044, 0x03950394},
+ {0x0000a048, 0x00000396},
+ {0x0000a04c, 0x00000000},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x28282828},
+ {0x0000a084, 0x28282828},
+ {0x0000a088, 0x28282828},
+ {0x0000a08c, 0x28282828},
+ {0x0000a090, 0x28282828},
+ {0x0000a094, 0x21212128},
+ {0x0000a098, 0x171c1c1c},
+ {0x0000a09c, 0x02020212},
+ {0x0000a0a0, 0x00000202},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x111f1100},
+ {0x0000a0c8, 0x111d111e},
+ {0x0000a0cc, 0x111b111c},
+ {0x0000a0d0, 0x22032204},
+ {0x0000a0d4, 0x22012202},
+ {0x0000a0d8, 0x221f2200},
+ {0x0000a0dc, 0x221d221e},
+ {0x0000a0e0, 0x33013302},
+ {0x0000a0e4, 0x331f3300},
+ {0x0000a0e8, 0x4402331e},
+ {0x0000a0ec, 0x44004401},
+ {0x0000a0f0, 0x441e441f},
+ {0x0000a0f4, 0x55015502},
+ {0x0000a0f8, 0x551f5500},
+ {0x0000a0fc, 0x6602551e},
+ {0x0000a100, 0x66006601},
+ {0x0000a104, 0x661e661f},
+ {0x0000a108, 0x7703661d},
+ {0x0000a10c, 0x77017702},
+ {0x0000a110, 0x00007700},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x111f1100},
+ {0x0000a148, 0x111d111e},
+ {0x0000a14c, 0x111b111c},
+ {0x0000a150, 0x22032204},
+ {0x0000a154, 0x22012202},
+ {0x0000a158, 0x221f2200},
+ {0x0000a15c, 0x221d221e},
+ {0x0000a160, 0x33013302},
+ {0x0000a164, 0x331f3300},
+ {0x0000a168, 0x4402331e},
+ {0x0000a16c, 0x44004401},
+ {0x0000a170, 0x441e441f},
+ {0x0000a174, 0x55015502},
+ {0x0000a178, 0x551f5500},
+ {0x0000a17c, 0x6602551e},
+ {0x0000a180, 0x66006601},
+ {0x0000a184, 0x661e661f},
+ {0x0000a188, 0x7703661d},
+ {0x0000a18c, 0x77017702},
+ {0x0000a190, 0x00007700},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000296},
+};
+
+static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x10252e5e},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0000580c},
+};
+
+static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x10253e5e},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0000580c},
+};
+
+static const u32 ar9485_1_0_soc_preamble[][2] = {
+ /* Addr allmodes */
+ {0x000040a4, 0x00a0c9c9},
+ {0x00007048, 0x00000004},
+};
+
+static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = {
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00009e00, 0x03721821, 0x03721821},
+ {0x0000a230, 0x0000400b, 0x00004016},
+ {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9485_1_0_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
+ {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
+ {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
+ {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
+ {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+ {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
+ {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
+ {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
+ {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+ {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
+ {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+ {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+ {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
+ {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
+};
+
+static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x10213e5e},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0000580c},
+};
+
+static const u32 ar9485_1_0_radio_postamble[][2] = {
+ /* Addr allmodes */
+ {0x0001609c, 0x0b283f31},
+ {0x000160ac, 0x24611800},
+ {0x000160b0, 0x03284f3e},
+ {0x0001610c, 0x00170000},
+ {0x00016140, 0x10804008},
+};
+
+static const u32 ar9485_1_0_mac_core[][2] = {
+ /* Addr allmodes */
+ {0x00000008, 0x00000000},
+ {0x00000030, 0x00020085},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000000},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x000010f0, 0x00000100},
+ {0x00001270, 0x00000000},
+ {0x000012b0, 0x00000000},
+ {0x000012f0, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00008000, 0x00000000},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000000},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008040, 0x00000000},
+ {0x00008044, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x0000804c, 0xffffffff},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000310},
+ {0x00008074, 0x00000020},
+ {0x00008078, 0x00000000},
+ {0x0000809c, 0x0000000f},
+ {0x000080a0, 0x00000000},
+ {0x000080a4, 0x02ff0000},
+ {0x000080a8, 0x0e070605},
+ {0x000080ac, 0x0000000d},
+ {0x000080b0, 0x00000000},
+ {0x000080b4, 0x00000000},
+ {0x000080b8, 0x00000000},
+ {0x000080bc, 0x00000000},
+ {0x000080c0, 0x2a800000},
+ {0x000080c4, 0x06900168},
+ {0x000080c8, 0x13881c20},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00252500},
+ {0x000080d4, 0x00a00000},
+ {0x000080d8, 0x00400000},
+ {0x000080dc, 0x00000000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x3f3f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00000000},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000000},
+ {0x00008114, 0x000007ff},
+ {0x00008118, 0x000000aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x0000ffff},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x18486200},
+ {0x00008174, 0x33332210},
+ {0x00008178, 0x00000000},
+ {0x0000817c, 0x00020000},
+ {0x000081c0, 0x00000000},
+ {0x000081c4, 0x33332210},
+ {0x000081c8, 0x00000000},
+ {0x000081cc, 0x00000000},
+ {0x000081d4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000800},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x40000000},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x9ca00010},
+ {0x00008268, 0xffffffff},
+ {0x0000826c, 0x0000ffff},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000004},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x000000ff},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000140},
+ {0x00008314, 0x00000000},
+ {0x0000831c, 0x0000010d},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000700},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x02400000},
+ {0x00008340, 0x000107ff},
+ {0x00008344, 0xa248105b},
+ {0x00008348, 0x008f0000},
+ {0x0000835c, 0x00000000},
+ {0x00008360, 0xffffffff},
+ {0x00008364, 0xffffffff},
+ {0x00008368, 0x00000000},
+ {0x00008370, 0x00000000},
+ {0x00008374, 0x000000ff},
+ {0x00008378, 0x00000000},
+ {0x0000837c, 0x00000000},
+ {0x00008380, 0xffffffff},
+ {0x00008384, 0xffffffff},
+ {0x00008390, 0xffffffff},
+ {0x00008394, 0xffffffff},
+ {0x00008398, 0x00000000},
+ {0x0000839c, 0x00000000},
+ {0x000083a0, 0x00000000},
+ {0x000083a4, 0x0000fa14},
+ {0x000083a8, 0x000f0c00},
+ {0x000083ac, 0x33332210},
+ {0x000083b0, 0x33332210},
+ {0x000083b4, 0x33332210},
+ {0x000083b8, 0x33332210},
+ {0x000083bc, 0x00000000},
+ {0x000083c0, 0x00000000},
+ {0x000083c4, 0x00000000},
+ {0x000083c8, 0x00000000},
+ {0x000083cc, 0x00000200},
+ {0x000083d0, 0x000301ff},
+};
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9b8e7e3fcebd..3681caf54282 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -21,6 +21,7 @@
#include <linux/device.h>
#include <linux/leds.h>
#include <linux/completion.h>
+#include <linux/pm_qos_params.h>
#include "debug.h"
#include "common.h"
@@ -56,6 +57,8 @@ struct ath_node;
#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ATH9K_PM_QOS_DEFAULT_VALUE 55
+
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
@@ -86,33 +89,19 @@ struct ath_config {
/**
* enum buffer_type - Buffer type flags
*
- * @BUF_HT: Send this buffer using HT capabilities
* @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
* @BUF_AGGR: Indicates whether the buffer can be aggregated
* (used in aggregation scheduling)
- * @BUF_RETRY: Indicates whether the buffer is retried
* @BUF_XRETRY: To denote excessive retries of the buffer
*/
enum buffer_type {
- BUF_HT = BIT(1),
BUF_AMPDU = BIT(2),
BUF_AGGR = BIT(3),
- BUF_RETRY = BIT(4),
BUF_XRETRY = BIT(5),
};
-#define bf_nframes bf_state.bfs_nframes
-#define bf_al bf_state.bfs_al
-#define bf_frmlen bf_state.bfs_frmlen
-#define bf_retries bf_state.bfs_retries
-#define bf_seqno bf_state.bfs_seqno
-#define bf_tidno bf_state.bfs_tidno
-#define bf_keyix bf_state.bfs_keyix
-#define bf_keytype bf_state.bfs_keytype
-#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT)
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
-#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
#define ATH_TXSTATUS_RING_SIZE 64
@@ -177,8 +166,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
/* returns delimiter padding required given the packet length */
#define ATH_AGGR_GET_NDELIM(_len) \
- (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
- (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
+ (((_len) >= ATH_AGGR_MINPLEN) ? 0 : \
+ DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ))
#define BAW_WITHIN(_start, _bawsz, _seqno) \
((((_seqno) - (_start)) & 4095) < (_bawsz))
@@ -195,12 +184,12 @@ enum ATH_AGGR_STATUS {
#define ATH_TXFIFO_DEPTH 8
struct ath_txq {
- int axq_class;
u32 axq_qnum;
u32 *axq_link;
struct list_head axq_q;
spinlock_t axq_lock;
u32 axq_depth;
+ u32 axq_ampdu_depth;
bool stopped;
bool axq_tx_inprogress;
struct list_head axq_acq;
@@ -208,27 +197,28 @@ struct ath_txq {
struct list_head txq_fifo_pending;
u8 txq_headidx;
u8 txq_tailidx;
+ int pending_frames;
};
struct ath_atx_ac {
+ struct ath_txq *txq;
int sched;
- int qnum;
struct list_head list;
struct list_head tid_q;
};
+struct ath_frame_info {
+ int framelen;
+ u32 keyix;
+ enum ath9k_key_type keytype;
+ u8 retries;
+ u16 seqno;
+};
+
struct ath_buf_state {
- int bfs_nframes;
- u16 bfs_al;
- u16 bfs_frmlen;
- int bfs_seqno;
- int bfs_tidno;
- int bfs_retries;
u8 bf_type;
u8 bfs_paprd;
- unsigned long bfs_paprd_timestamp;
- u32 bfs_keyix;
- enum ath9k_key_type bfs_keytype;
+ enum ath9k_internal_frame_type bfs_ftype;
};
struct ath_buf {
@@ -241,7 +231,6 @@ struct ath_buf {
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
bool bf_stale;
- bool bf_tx_aborted;
u16 bf_flags;
struct ath_buf_state bf_state;
struct ath_wiphy *aphy;
@@ -270,7 +259,6 @@ struct ath_node {
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
- int last_rssi;
};
#define AGGR_CLEANUP BIT(1)
@@ -279,6 +267,7 @@ struct ath_node {
struct ath_tx_control {
struct ath_txq *txq;
+ struct ath_node *an;
int if_id;
enum ath9k_internal_frame_type frame_type;
u8 paprd;
@@ -291,12 +280,11 @@ struct ath_tx_control {
struct ath_tx {
u16 seq_no;
u32 txqsetup;
- int hwq_map[WME_NUM_AC];
spinlock_t txbuflock;
struct list_head txbuf;
struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
struct ath_descdma txdma;
- int pending_frames[WME_NUM_AC];
+ struct ath_txq *txq_map[WME_NUM_AC];
};
struct ath_rx_edma {
@@ -310,7 +298,6 @@ struct ath_rx {
u8 rxotherant;
u32 *rxlink;
unsigned int rxfilter;
- spinlock_t pcu_lock;
spinlock_t rxbuflock;
struct list_head rxbuf;
struct ath_descdma rxdma;
@@ -327,8 +314,7 @@ void ath_rx_cleanup(struct ath_softc *sc);
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-int ath_tx_setup(struct ath_softc *sc, int haltype);
-void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
+bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
void ath_draintxq(struct ath_softc *sc,
struct ath_txq *txq, bool retry_tx);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
@@ -342,7 +328,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl);
void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc);
-void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
@@ -563,6 +548,7 @@ struct ath_ant_comb {
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
#define SC_OP_BT_SCAN BIT(13)
#define SC_OP_ANI_RUN BIT(14)
+#define SC_OP_ENABLE_APM BIT(15)
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
@@ -600,13 +586,14 @@ struct ath_softc {
struct ath_hw *sc_ah;
void __iomem *mem;
int irq;
- spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
spinlock_t sc_pm_lock;
+ spinlock_t sc_pcu_lock;
struct mutex mutex;
struct work_struct paprd_work;
struct work_struct hw_check_work;
struct completion paprd_complete;
+ bool paprd_pending;
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
@@ -646,6 +633,8 @@ struct ath_softc {
struct ath_descdma txsdma;
struct ath_ant_comb ant_comb;
+
+ struct pm_qos_request_list pm_qos_req;
};
struct ath_wiphy {
@@ -662,11 +651,11 @@ struct ath_wiphy {
bool idle;
int chan_idx;
int chan_is_ht;
+ int last_rssi;
};
void ath9k_tasklet(unsigned long data);
int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
@@ -675,17 +664,19 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
}
extern struct ieee80211_ops ath9k_ops;
-extern int modparam_nohwcrypt;
+extern int ath9k_modparam_nohwcrypt;
extern int led_blink;
+extern int ath9k_pm_qos_value;
+extern bool is_ath9k_unloaded;
irqreturn_t ath_isr(int irq, void *dev);
+void ath9k_init_crypto(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *ichan);
-void ath_update_chainmask(struct ath_softc *sc, int is_ht);
int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *hchan);
@@ -712,10 +703,12 @@ static inline void ath_ahb_exit(void) {};
void ath9k_ps_wakeup(struct ath_softc *sc);
void ath9k_ps_restore(struct ath_softc *sc);
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
+
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int ath9k_wiphy_add(struct ath_softc *sc);
int ath9k_wiphy_del(struct ath_wiphy *aphy);
-void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
+void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype);
int ath9k_wiphy_pause(struct ath_wiphy *aphy);
int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
int ath9k_wiphy_select(struct ath_wiphy *aphy);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 19891e7d49ae..385ba03134ba 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -28,7 +28,7 @@ int ath_beaconq_config(struct ath_softc *sc)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi, qi_be;
- int qnum;
+ struct ath_txq *txq;
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
@@ -38,16 +38,16 @@ int ath_beaconq_config(struct ath_softc *sc)
qi.tqi_cwmax = 0;
} else {
/* Adhoc mode; important thing is to use 2x cwmin. */
- qnum = sc->tx.hwq_map[WME_AC_BE];
- ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+ txq = sc->tx.txq_map[WME_AC_BE];
+ ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
}
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to update h/w beacon queue parameters\n");
+ ath_err(common,
+ "Unable to update h/w beacon queue parameters\n");
return 0;
} else {
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
@@ -103,12 +103,32 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
series[0].Tries = 1;
series[0].Rate = rate;
- series[0].ChSel = common->tx_chainmask;
+ series[0].ChSel = ath_txchainmask_reduction(sc,
+ common->tx_chainmask, series[0].Rate);
series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
series, 4, 0);
}
+static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_tx_control txctl;
+
+ memset(&txctl, 0, sizeof(struct ath_tx_control));
+ txctl.txq = sc->beacon.cabq;
+
+ ath_dbg(common, ATH_DBG_XMIT,
+ "transmitting CABQ packet, skb: %p\n", skb);
+
+ if (ath_tx_start(hw, skb, &txctl) != 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "CABQ TX failed\n");
+ dev_kfree_skb_any(skb);
+ }
+}
+
static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -169,8 +189,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(common, ATH_DBG_FATAL,
- "dma_mapping_error on beaconing\n");
+ ath_err(common, "dma_mapping_error on beaconing\n");
return NULL;
}
@@ -190,8 +209,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
if (skb && cabq_depth) {
if (sc->nvifs > 1) {
- ath_print(common, ATH_DBG_BEACON,
- "Flushing previous cabq traffic\n");
+ ath_dbg(common, ATH_DBG_BEACON,
+ "Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq, false);
}
}
@@ -263,7 +282,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
/* NB: the beacon data buffer must be 32-bit aligned. */
skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL) {
- ath_print(common, ATH_DBG_BEACON, "cannot get skb\n");
+ ath_dbg(common, ATH_DBG_BEACON, "cannot get skb\n");
return -ENOMEM;
}
@@ -287,10 +306,9 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
- ath_print(common, ATH_DBG_BEACON,
- "stagger beacons, bslot %d intval "
- "%u tsfadjust %llu\n",
- avp->av_bslot, intval, (unsigned long long)tsfadjust);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
+ avp->av_bslot, intval, (unsigned long long)tsfadjust);
((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
avp->tsf_adjust;
@@ -304,8 +322,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(common, ATH_DBG_FATAL,
- "dma_mapping_error on beacon alloc\n");
+ ath_err(common, "dma_mapping_error on beacon alloc\n");
return -ENOMEM;
}
@@ -362,13 +379,13 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.bmisscnt++;
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
- ath_print(common, ATH_DBG_BSTUCK,
- "missed %u consecutive beacons\n",
- sc->beacon.bmisscnt);
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
ath9k_hw_bstuck_nfcal(ah);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
- ath_print(common, ATH_DBG_BSTUCK,
- "beacon is officially stuck\n");
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
ath_reset(sc, true);
}
@@ -377,9 +394,9 @@ void ath_beacon_tasklet(unsigned long data)
}
if (sc->beacon.bmisscnt != 0) {
- ath_print(common, ATH_DBG_BSTUCK,
- "resume beacon xmit after %u misses\n",
- sc->beacon.bmisscnt);
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
sc->beacon.bmisscnt = 0;
}
@@ -405,9 +422,9 @@ void ath_beacon_tasklet(unsigned long data)
vif = sc->beacon.bslot[slot];
aphy = sc->beacon.bslot_aphy[slot];
- ath_print(common, ATH_DBG_BEACON,
- "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
- slot, tsf, tsftu, intval, vif);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+ slot, tsf, tsftu, intval, vif);
bfaddr = 0;
if (vif) {
@@ -449,8 +466,8 @@ void ath_beacon_tasklet(unsigned long data)
* are still pending on the queue.
*/
if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
- ath_print(common, ATH_DBG_FATAL,
- "beacon queue %u did not stop?\n", sc->beacon.beaconq);
+ ath_err(common, "beacon queue %u did not stop?\n",
+ sc->beacon.beaconq);
}
/* NB: cabq traffic should already be queued and primed */
@@ -503,7 +520,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -536,8 +553,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
/* No need to configure beacon if we are not associated */
if (!common->curaid) {
- ath_print(common, ATH_DBG_BEACON,
- "STA is not yet associated..skipping beacon config\n");
+ ath_dbg(common, ATH_DBG_BEACON,
+ "STA is not yet associated..skipping beacon config\n");
return;
}
@@ -549,8 +566,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
* last beacon we received (which may be none).
*/
dtimperiod = conf->dtim_period;
- if (dtimperiod <= 0) /* NB: 0 if not known */
- dtimperiod = 1;
dtimcount = conf->dtim_count;
if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0;
@@ -558,8 +573,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
cfpcount = 0;
sleepduration = conf->listen_interval * intval;
- if (sleepduration <= 0)
- sleepduration = intval;
/*
* Pull nexttbtt forward to reflect the current
@@ -630,23 +643,22 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
/* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
- ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
- ath_print(common, ATH_DBG_BEACON,
- "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration,
- bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+ ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+ bs.bs_bmissthreshold, bs.bs_sleepduration,
+ bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
/* Set the computed STA beacon timers */
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS;
ath9k_hw_set_interrupts(ah, ah->imask);
}
static void ath_beacon_config_adhoc(struct ath_softc *sc,
- struct ath_beacon_config *conf,
- struct ieee80211_vif *vif)
+ struct ath_beacon_config *conf)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@@ -670,9 +682,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
nexttbtt += intval;
} while (nexttbtt < tsftu);
- ath_print(common, ATH_DBG_BEACON,
- "IBSS nexttbtt %u intval %u (%u)\n",
- nexttbtt, intval, conf->beacon_interval);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "IBSS nexttbtt %u intval %u (%u)\n",
+ nexttbtt, intval, conf->beacon_interval);
/*
* In IBSS mode enable the beacon timers but only enable SWBA interrupts
@@ -686,7 +698,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
/* Set the computed ADHOC beacon timers */
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -701,18 +713,17 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
/* Setup the beacon configuration parameters */
if (vif) {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-
iftype = vif->type;
-
cur_conf->beacon_interval = bss_conf->beacon_int;
cur_conf->dtim_period = bss_conf->dtim_period;
+ } else {
+ iftype = sc->sc_ah->opmode;
+ }
+
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
- } else {
- iftype = sc->sc_ah->opmode;
- }
/*
* It looks like mac80211 may end up using beacon interval of zero in
@@ -723,20 +734,27 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->beacon_interval == 0)
cur_conf->beacon_interval = 100;
+ /*
+ * Some times we dont parse dtim period from mac80211, in that case
+ * use a default value
+ */
+ if (cur_conf->dtim_period == 0)
+ cur_conf->dtim_period = 1;
+
switch (iftype) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
- ath_beacon_config_adhoc(sc, cur_conf, vif);
+ ath_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);
break;
default:
- ath_print(common, ATH_DBG_CONFIG,
- "Unsupported beaconing mode\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Unsupported beaconing mode\n");
return;
}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 6a92e57fddf0..d33bf204c995 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -35,29 +35,6 @@ struct ath_btcoex_config {
bool bt_hold_rx_clear;
};
-static const u16 ath_subsysid_tbl[] = {
- AR9280_COEX2WIRE_SUBSYSID,
- AT9285_COEX3WIRE_SA_SUBSYSID,
- AT9285_COEX3WIRE_DA_SUBSYSID
-};
-
-/*
- * Checks the subsystem id of the device to see if it
- * supports btcoex
- */
-bool ath9k_hw_btcoex_supported(struct ath_hw *ah)
-{
- int i;
-
- if (!ah->hw_version.subsysid)
- return false;
-
- for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
- if (ah->hw_version.subsysid == ath_subsysid_tbl[i])
- return true;
-
- return false;
-}
void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
{
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 1ee5a15ccbb1..588dfd464dd1 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -49,7 +49,6 @@ struct ath_btcoex_hw {
u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
};
-bool ath9k_hw_btcoex_supported(struct ath_hw *ah);
void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 6d509484b5f6..b68a1acbddd0 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -97,12 +97,12 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
if (h[i].privNF > limit->max) {
high_nf_mid = true;
- ath_print(common, ATH_DBG_CALIBRATE,
- "NFmid[%d] (%d) > MAX (%d), %s\n",
- i, h[i].privNF, limit->max,
- (cal->nfcal_interference ?
- "not corrected (due to interference)" :
- "correcting to MAX"));
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "NFmid[%d] (%d) > MAX (%d), %s\n",
+ i, h[i].privNF, limit->max,
+ (cal->nfcal_interference ?
+ "not corrected (due to interference)" :
+ "correcting to MAX"));
/*
* Normally we limit the average noise floor by the
@@ -180,18 +180,18 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
return true;
if (currCal->calState != CAL_DONE) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "Calibration state incorrect, %d\n",
- currCal->calState);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Calibration state incorrect, %d\n",
+ currCal->calState);
return true;
}
if (!(ah->supp_cals & currCal->calData->calType))
return true;
- ath_print(common, ATH_DBG_CALIBRATE,
- "Resetting Cal %d state for channel %u\n",
- currCal->calData->calType, conf->channel->center_freq);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Resetting Cal %d state for channel %u\n",
+ currCal->calData->calType, conf->channel->center_freq);
ah->caldata->CalValid &= ~currCal->calData->calType;
currCal->calState = CAL_WAITING;
@@ -279,9 +279,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
* noisefloor until the next calibration timer.
*/
if (j == 1000) {
- ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
- "to load: AR_PHY_AGC_CONTROL=0x%x\n",
- REG_READ(ah, AR_PHY_AGC_CONTROL));
+ ath_dbg(common, ATH_DBG_ANY,
+ "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
+ REG_READ(ah, AR_PHY_AGC_CONTROL));
return;
}
@@ -318,19 +318,19 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
if (!nf[i])
continue;
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [%s] [chain %d] is %d\n",
- (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [%s] [chain %d] is %d\n",
+ (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
if (nf[i] > ATH9K_NF_TOO_HIGH) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF[%d] (%d) > MAX (%d), correcting to MAX",
- i, nf[i], ATH9K_NF_TOO_HIGH);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "NF[%d] (%d) > MAX (%d), correcting to MAX\n",
+ i, nf[i], ATH9K_NF_TOO_HIGH);
nf[i] = limit->max;
} else if (nf[i] < limit->min) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF[%d] (%d) < MIN (%d), correcting to NOM",
- i, nf[i], limit->min);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "NF[%d] (%d) < MIN (%d), correcting to NOM\n",
+ i, nf[i], limit->min);
nf[i] = limit->nominal;
}
}
@@ -347,8 +347,8 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
chan->channelFlags &= (~CHANNEL_CW_INT);
if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF did not complete in calibration window\n");
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "NF did not complete in calibration window\n");
return false;
}
@@ -357,10 +357,9 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
nf = nfarray[0];
if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
&& nf > nfThresh) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "noise floor failed detected; "
- "detected %d, threshold %d\n",
- nf, nfThresh);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "noise floor failed detected; detected %d, threshold %d\n",
+ nf, nfThresh);
chan->channelFlags |= CHANNEL_CW_INT;
}
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index f43a2d98421c..df1998d48253 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -107,12 +107,10 @@ static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan,
/*
* Update internal channel flags.
*/
-void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
- struct ath9k_channel *ichan)
+void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
- struct ieee80211_channel *chan = hw->conf.channel;
- struct ieee80211_conf *conf = &hw->conf;
-
ichan->channel = chan->center_freq;
ichan->chan = chan;
@@ -124,9 +122,8 @@ void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
}
- if (conf_is_ht(conf))
- ichan->chanmode = ath9k_get_extchanmode(chan,
- conf->channel_type);
+ if (channel_type != NL80211_CHAN_NO_HT)
+ ichan->chanmode = ath9k_get_extchanmode(chan, channel_type);
}
EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
@@ -142,7 +139,7 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
chan_idx = curchan->hw_value;
channel = &ah->channels[chan_idx];
- ath9k_cmn_update_ichannel(hw, channel);
+ ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type);
return channel;
}
@@ -183,8 +180,8 @@ void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
AR_STOMP_NONE_WLAN_WGHT);
break;
default:
- ath_print(common, ATH_DBG_BTCOEX,
- "Invalid Stomptype\n");
+ ath_dbg(common, ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index fea3b3315391..a126bddebb0a 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -17,7 +17,6 @@
#include <net/mac80211.h>
#include "../ath.h"
-#include "../debug.h"
#include "hw.h"
#include "hw-ops.h"
@@ -31,10 +30,11 @@
#define WME_MAX_BA WME_BA_BMP_SIZE
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
-#define WME_AC_BE 0
-#define WME_AC_BK 1
-#define WME_AC_VI 2
-#define WME_AC_VO 3
+/* These must match mac80211 skb queue mapping numbers */
+#define WME_AC_VO 0
+#define WME_AC_VI 1
+#define WME_AC_BE 2
+#define WME_AC_BK 3
#define WME_NUM_AC 4
#define ATH_RSSI_DUMMY_MARKER 0x127
@@ -62,8 +62,9 @@ enum ath_stomp_type {
int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
-void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
- struct ath9k_channel *ichan);
+void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
struct ath_hw *ah);
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 43e71a944cb1..3586c43077a7 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -24,8 +24,6 @@
#define REG_READ_D(_ah, _reg) \
ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
-static struct dentry *ath9k_debugfs_root;
-
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -461,16 +459,16 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
/* Put variable-length stuff down here, and check for overflows. */
for (i = 0; i < sc->num_sec_wiphy; i++) {
- struct ath_wiphy *aphy = sc->sec_wiphy[i];
- if (aphy == NULL)
+ struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i];
+ if (aphy_tmp == NULL)
continue;
- chan = aphy->hw->conf.channel;
+ chan = aphy_tmp->hw->conf.channel;
len += snprintf(buf + len, sizeof(buf) - len,
"secondary: %s (%s chan=%d ht=%d)\n",
- wiphy_name(aphy->hw->wiphy),
- ath_wiphy_state_str(aphy->state),
+ wiphy_name(aphy_tmp->hw->wiphy),
+ ath_wiphy_state_str(aphy_tmp->state),
ieee80211_frequency_to_channel(chan->center_freq),
- aphy->chan_is_ht);
+ aphy_tmp->chan_is_ht);
}
if (len > sizeof(buf))
len = sizeof(buf);
@@ -585,10 +583,10 @@ static const struct file_operations fops_wiphy = {
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
- sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BE]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BK]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VI]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VO]].elem); \
+ sc->debug.stats.txstats[WME_AC_BE].elem, \
+ sc->debug.stats.txstats[WME_AC_BK].elem, \
+ sc->debug.stats.txstats[WME_AC_VI].elem, \
+ sc->debug.stats.txstats[WME_AC_VO].elem); \
} while(0)
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
@@ -630,33 +628,35 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
return retval;
}
-void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_buf *bf, struct ath_tx_status *ts)
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_status *ts)
{
- TX_STAT_INC(txq->axq_qnum, tx_pkts_all);
- sc->debug.stats.txstats[txq->axq_qnum].tx_bytes_all += bf->bf_mpdu->len;
+ int qnum = skb_get_queue_mapping(bf->bf_mpdu);
+
+ TX_STAT_INC(qnum, tx_pkts_all);
+ sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
if (bf_isampdu(bf)) {
if (bf_isxretried(bf))
- TX_STAT_INC(txq->axq_qnum, a_xretries);
+ TX_STAT_INC(qnum, a_xretries);
else
- TX_STAT_INC(txq->axq_qnum, a_completed);
+ TX_STAT_INC(qnum, a_completed);
} else {
- TX_STAT_INC(txq->axq_qnum, completed);
+ TX_STAT_INC(qnum, completed);
}
if (ts->ts_status & ATH9K_TXERR_FIFO)
- TX_STAT_INC(txq->axq_qnum, fifo_underrun);
+ TX_STAT_INC(qnum, fifo_underrun);
if (ts->ts_status & ATH9K_TXERR_XTXOP)
- TX_STAT_INC(txq->axq_qnum, xtxop);
+ TX_STAT_INC(qnum, xtxop);
if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
- TX_STAT_INC(txq->axq_qnum, timer_exp);
+ TX_STAT_INC(qnum, timer_exp);
if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
- TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
+ TX_STAT_INC(qnum, desc_cfg_err);
if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
- TX_STAT_INC(txq->axq_qnum, data_underrun);
+ TX_STAT_INC(qnum, data_underrun);
if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
- TX_STAT_INC(txq->axq_qnum, delim_underrun);
+ TX_STAT_INC(qnum, delim_underrun);
}
static const struct file_operations fops_xmit = {
@@ -876,11 +876,8 @@ int ath9k_init_debug(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ath_softc *sc = (struct ath_softc *) common->priv;
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
- ath9k_debugfs_root);
+ sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
+ sc->hw->wiphy->debugfsdir);
if (!sc->debug.debugfs_phy)
return -ENOMEM;
@@ -933,29 +930,7 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.regidx = 0;
return 0;
err:
- ath9k_exit_debug(ah);
- return -ENOMEM;
-}
-
-void ath9k_exit_debug(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
-
debugfs_remove_recursive(sc->debug.debugfs_phy);
-}
-
-int ath9k_debug_create_root(void)
-{
- ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- return 0;
-}
-
-void ath9k_debug_remove_root(void)
-{
- debugfs_remove(ath9k_debugfs_root);
- ath9k_debugfs_root = NULL;
+ sc->debug.debugfs_phy = NULL;
+ return -ENOMEM;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index bb0823242ba0..1e5078bd0344 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -164,13 +164,10 @@ struct ath9k_debug {
};
int ath9k_init_debug(struct ath_hw *ah);
-void ath9k_exit_debug(struct ath_hw *ah);
-int ath9k_debug_create_root(void);
-void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
-void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_buf *bf, struct ath_tx_status *ts);
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_status *ts);
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
#else
@@ -180,26 +177,12 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
return 0;
}
-static inline void ath9k_exit_debug(struct ath_hw *ah)
-{
-}
-
-static inline int ath9k_debug_create_root(void)
-{
- return 0;
-}
-
-static inline void ath9k_debug_remove_root(void)
-{
-}
-
static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
enum ath9k_int status)
{
}
static inline void ath_debug_stat_tx(struct ath_softc *sc,
- struct ath_txq *txq,
struct ath_buf *bf,
struct ath_tx_status *ts)
{
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 1266333f586d..d05163159572 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -234,22 +234,22 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
bool is2GHz, int num_band_edges)
{
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
int i;
for (i = 0; (i < num_band_edges) &&
(pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
- twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+ twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
break;
} else if ((i > 0) &&
(freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
is2GHz))) {
if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
is2GHz) < freq &&
- pRdEdgesPower[i - 1].flag) {
+ CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
twiceMaxEdgePower =
- pRdEdgesPower[i - 1].tPower;
+ CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
}
break;
}
@@ -273,12 +273,225 @@ void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
break;
default:
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
break;
}
}
+void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ void *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+ int pdgain_boundary_default;
+ struct cal_data_per_freq *data_def = pRawDataSet;
+ struct cal_data_per_freq_4k *data_4k = pRawDataSet;
+ struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
+ bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
+ int intercepts;
+
+ if (AR_SREV_9287(ah))
+ intercepts = AR9287_PD_GAIN_ICEPTS;
+ else
+ intercepts = AR5416_PD_GAIN_ICEPTS;
+
+ memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans, numPiers, &idxL, &idxR);
+
+ if (match) {
+ if (AR_SREV_9287(ah)) {
+ /* FIXME: array overrun? */
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ data_9287[idxL].pwrPdg[i],
+ data_9287[idxL].vpdPdg[i],
+ intercepts,
+ vpdTableI[i]);
+ }
+ } else if (eeprom_4k) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ data_4k[idxL].pwrPdg[i],
+ data_4k[idxL].vpdPdg[i],
+ intercepts,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ data_def[idxL].pwrPdg[i],
+ data_def[idxL].vpdPdg[i],
+ intercepts,
+ vpdTableI[i]);
+ }
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ if (AR_SREV_9287(ah)) {
+ pVpdL = data_9287[idxL].vpdPdg[i];
+ pPwrL = data_9287[idxL].pwrPdg[i];
+ pVpdR = data_9287[idxR].vpdPdg[i];
+ pPwrR = data_9287[idxR].pwrPdg[i];
+ } else if (eeprom_4k) {
+ pVpdL = data_4k[idxL].vpdPdg[i];
+ pPwrL = data_4k[idxL].pwrPdg[i];
+ pVpdR = data_4k[idxR].vpdPdg[i];
+ pPwrR = data_4k[idxR].pwrPdg[i];
+ } else {
+ pVpdL = data_def[idxL].vpdPdg[i];
+ pPwrL = data_def[idxL].pwrPdg[i];
+ pVpdR = data_def[idxR].vpdPdg[i];
+ pPwrR = data_def[idxR].pwrPdg[i];
+ }
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[intercepts - 1],
+ pPwrR[intercepts - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ intercepts,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ intercepts,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+
+ k = 0;
+
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t)((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+ }
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex >= maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+ (ss - maxIndex + 1) * vpdStep));
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ if (eeprom_4k)
+ pdgain_boundary_default = 58;
+ else
+ pdgain_boundary_default = pPdGainBoundaries[i - 1];
+
+ while (i < AR5416_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pdgain_boundary_default;
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+}
+
int ath9k_hw_eeprom_init(struct ath_hw *ah)
{
int status;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index dacb45e1b906..58e2ddc927a9 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -17,12 +17,12 @@
#ifndef EEPROM_H
#define EEPROM_H
+#define AR_EEPROM_MODAL_SPURS 5
+
#include "../ath.h"
#include <net/cfg80211.h>
#include "ar9003_eeprom.h"
-#define AH_USE_EEPROM 0x1
-
#ifdef __BIG_ENDIAN
#define AR5416_EEPROM_MAGIC 0x5aa5
#else
@@ -149,8 +149,6 @@
#define AR5416_NUM_PD_GAINS 4
#define AR5416_PD_GAINS_IN_MASK 4
#define AR5416_PD_GAIN_ICEPTS 5
-#define AR5416_EEPROM_MODAL_SPURS 5
-#define AR5416_MAX_RATE_POWER 63
#define AR5416_NUM_PDADC_VALUES 128
#define AR5416_BCHAN_UNUSED 0xFF
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
@@ -175,8 +173,6 @@
#define AR5416_EEP4K_NUM_CTLS 12
#define AR5416_EEP4K_NUM_BAND_EDGES 4
#define AR5416_EEP4K_NUM_PD_GAINS 2
-#define AR5416_EEP4K_PD_GAINS_IN_MASK 4
-#define AR5416_EEP4K_PD_GAIN_ICEPTS 5
#define AR5416_EEP4K_MAX_CHAINS 1
#define AR9280_TX_GAIN_TABLE_SIZE 22
@@ -198,41 +194,30 @@
#define AR9287_NUM_2G_40_TARGET_POWERS 3
#define AR9287_NUM_CTLS 12
#define AR9287_NUM_BAND_EDGES 4
-#define AR9287_NUM_PD_GAINS 4
-#define AR9287_PD_GAINS_IN_MASK 4
#define AR9287_PD_GAIN_ICEPTS 1
-#define AR9287_EEPROM_MODAL_SPURS 5
-#define AR9287_MAX_RATE_POWER 63
-#define AR9287_NUM_PDADC_VALUES 128
-#define AR9287_NUM_RATES 16
-#define AR9287_BCHAN_UNUSED 0xFF
-#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64
-#define AR9287_OPFLAGS_11A 0x01
-#define AR9287_OPFLAGS_11G 0x02
-#define AR9287_OPFLAGS_2G_HT40 0x08
-#define AR9287_OPFLAGS_2G_HT20 0x20
-#define AR9287_OPFLAGS_5G_HT40 0x04
-#define AR9287_OPFLAGS_5G_HT20 0x10
#define AR9287_EEPMISC_BIG_ENDIAN 0x01
#define AR9287_EEPMISC_WOW 0x02
#define AR9287_MAX_CHAINS 2
#define AR9287_ANT_16S 32
-#define AR9287_custdatasize 20
-
-#define AR9287_NUM_ANT_CHAIN_FIELDS 6
-#define AR9287_NUM_ANT_COMMON_FIELDS 4
-#define AR9287_SIZE_ANT_CHAIN_FIELD 2
-#define AR9287_SIZE_ANT_COMMON_FIELD 4
-#define AR9287_ANT_CHAIN_MASK 0x3
-#define AR9287_ANT_COMMON_MASK 0xf
-#define AR9287_CHAIN_0_IDX 0
-#define AR9287_CHAIN_1_IDX 1
+
#define AR9287_DATA_SZ 32
#define AR9287_PWR_TABLE_OFFSET_DB -5
#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
+#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f)
+#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03)
+
+#define LNA_CTL_BUF_MODE BIT(0)
+#define LNA_CTL_ISEL_LO BIT(1)
+#define LNA_CTL_ISEL_HI BIT(2)
+#define LNA_CTL_BUF_IN BIT(3)
+#define LNA_CTL_FEM_BAND BIT(4)
+#define LNA_CTL_LOCAL_BIAS BIT(5)
+#define LNA_CTL_FORCE_XPA BIT(6)
+#define LNA_CTL_USE_ANT1 BIT(7)
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
@@ -268,6 +253,7 @@ enum eeprom_param {
EEP_PAPRD,
EEP_MODAL_VER,
EEP_ANT_DIV_CTL1,
+ EEP_CHAIN_MASK_REDUCE
};
enum ar5416_rates {
@@ -378,15 +364,12 @@ struct modal_eep_header {
u8 xatten2Margin[AR5416_MAX_CHAINS];
u8 ob_ch1;
u8 db_ch1;
- u8 useAnt1:1,
- force_xpaon:1,
- local_bias:1,
- femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
+ u8 lna_ctl;
u8 miscBits;
u16 xpaBiasLvlFreq[3];
u8 futureModal[6];
- struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+ struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed;
struct calDataPerFreqOpLoop {
@@ -454,7 +437,7 @@ struct modal_eep_4k_header {
u8 db2_4:4, reserved:4;
#endif
u8 futureModal[4];
- struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+ struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed;
struct base_eep_ar9287_header {
@@ -512,7 +495,7 @@ struct modal_eep_ar9287_header {
u8 ob_qam;
u8 ob_pal_off;
u8 futureModal[30];
- struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
+ struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed;
struct cal_data_per_freq {
@@ -521,8 +504,8 @@ struct cal_data_per_freq {
} __packed;
struct cal_data_per_freq_4k {
- u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
- u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+ u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
} __packed;
struct cal_target_power_leg {
@@ -535,18 +518,10 @@ struct cal_target_power_ht {
u8 tPow2x[8];
} __packed;
-
-#ifdef __BIG_ENDIAN_BITFIELD
struct cal_ctl_edges {
u8 bChannel;
- u8 flag:2, tPower:6;
+ u8 ctl;
} __packed;
-#else
-struct cal_ctl_edges {
- u8 bChannel;
- u8 tPower:6, flag:2;
-} __packed;
-#endif
struct cal_data_op_loop_ar9287 {
u8 pwrPdg[2][5];
@@ -556,8 +531,8 @@ struct cal_data_op_loop_ar9287 {
} __packed;
struct cal_data_per_freq_ar9287 {
- u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
- u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+ u8 pwrPdg[AR5416_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR5416_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
} __packed;
union cal_data_per_freq_ar9287_u {
@@ -672,15 +647,12 @@ struct eeprom_ops {
bool (*fill_eeprom)(struct ath_hw *hw);
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
- u8 (*get_num_ant_config)(struct ath_hw *hw,
- enum ath9k_hal_freq_band band);
- u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
- struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
u16 cfgCtl, u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower, u8 powerLimit);
+ u8 twiceMaxRegulatoryPower, u8 powerLimit,
+ bool test);
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
};
@@ -713,6 +685,14 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
int ath9k_hw_eeprom_init(struct ath_hw *ah);
+void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ void *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains);
+
#define ar5416_get_ntxchains(_txchainmask) \
(((_txchainmask >> 2) & 1) + \
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 4fa4d8e28c64..fbdff7e47952 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -37,14 +37,14 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
eep_start_loc = 64;
if (!ath9k_hw_use_flash(ah)) {
- ath_print(common, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
- ath_print(common, ATH_DBG_EEPROM,
- "Unable to read eeprom region\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region\n");
return false;
}
eep_data++;
@@ -69,13 +69,12 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (!ath9k_hw_use_flash(ah)) {
if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
&magic)) {
- ath_print(common, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ ath_err(common, "Reading Magic # failed\n");
return false;
}
- ath_print(common, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -90,16 +89,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ ath_err(common,
+ "Invalid EEPROM Magic. Endianness mismatch.\n");
return -EINVAL;
}
}
}
- ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map4k.baseEepHeader.length);
@@ -120,8 +118,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
u32 integer;
u16 word;
- ath_print(common, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -155,7 +153,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
eep->modalHeader.antCtrlChain[i] = integer;
}
- for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
word = swab16(eep->modalHeader.spurChans[i].spurChan);
eep->modalHeader.spurChans[i].spurChan = word;
}
@@ -163,9 +161,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_print(common, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -230,173 +227,6 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
}
}
-static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq_4k *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
-{
-#define TMP_VAL_VPD_TABLE \
- ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
- u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
-#define PD_GAIN_BOUNDARY_DEFAULT 58;
-
- memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
- }
-
- match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)), bChans, numPiers,
- &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] =
- min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1],
- pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]);
-
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR5416_EEP4K_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
- }
- }
- }
-
- k = 0;
-
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16)(maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
-
- pPdGainBoundaries[i] =
- min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
-
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
-
- if (i == 0) {
- if (AR_SREV_9280_20_OR_LATER(ah))
- ss = (int16_t)(0 - (minPwrT4[i] / 2));
- else
- ss = 0;
- } else {
- ss = (int16_t)((pPdGainBoundaries[i - 1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
- vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
- (minPwrT4[i] / 2));
- maxIndex = (tgtIndex < sizeCurrVpdTable) ?
- tgtIndex : sizeCurrVpdTable;
-
- while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1)))
- pPDADCValues[k++] = vpdTableI[i][ss++];
-
- vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex >= maxIndex) {
- while ((ss <= tgtIndex) &&
- (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
- ss++;
- }
- }
- }
-
- while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT;
- i++;
- }
-
- while (k < AR5416_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k - 1];
- k++;
- }
-
- return;
-#undef TMP_VAL_VPD_TABLE
-}
-
static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
@@ -407,7 +237,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
u8 *pCalBChans = NULL;
u16 pdGainOverlap_t2;
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
- u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers, i, j;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
@@ -429,12 +259,12 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
numXpdGain = 0;
- for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) {
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS)
break;
xpdGainValues[numXpdGain] =
- (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i);
+ (u16)(AR5416_PD_GAINS_IN_MASK - i);
numXpdGain++;
}
}
@@ -458,7 +288,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
if (pEepData->baseEepHeader.txMask & (1 << i)) {
pRawDataset = pEepData->calPierData2G[i];
- ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
+ ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
pRawDataset, pCalBChans,
numPiers, pdGainOverlap_t2,
gainBoundaries,
@@ -488,21 +318,20 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3, pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -532,14 +361,16 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
int i;
int16_t twiceLargestAntenna;
u16 twiceMinEdgePower;
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ u16 numCtlModes;
+ const u16 *pCtlMode;
+ u16 ctlMode, freq;
struct chan_centers centers;
struct cal_ctl_data_4k *rep;
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ { 0, 3, 6, 9, MAX_RATE_POWER };
struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
0, { 0, 0, 0, 0}
};
@@ -550,10 +381,10 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
0, {0, 0, 0, 0}
};
- u16 ctlModesFor11g[] =
- { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
- CTL_2GHT40
- };
+ static const u16 ctlModesFor11g[] = {
+ CTL_11B, CTL_11G, CTL_2GHT20,
+ CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+ };
ath9k_hw_get_channel_centers(ah, chan, &centers);
@@ -615,7 +446,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ twiceMaxEdgePower = MAX_RATE_POWER;
for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) {
@@ -726,7 +557,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+ u8 powerLimit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
@@ -751,15 +582,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
+ regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
+ if (ratesArray[i] > MAX_RATE_POWER)
+ ratesArray[i] = MAX_RATE_POWER;
+
+ if (ratesArray[i] > regulatory->max_power_level)
+ regulatory->max_power_level = ratesArray[i];
}
+ if (test)
+ return;
/* Update regulatory */
-
i = rate6mb;
if (IS_CHAN_HT40(chan))
i = rateHt40_0;
@@ -934,8 +770,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
pModal = &eep->modalHeader;
txRxAttenLocal = 23;
- REG_WRITE(ah, AR_PHY_SWITCH_COM,
- ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
/* Single chain for 4K EEPROM*/
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal);
@@ -1151,21 +986,6 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
}
}
-static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- struct modal_eep_4k_header *pModal = &eep->modalHeader;
-
- return pModal->antCtrlCommon;
-}
-
-static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
- enum ath9k_hal_freq_band freq_band)
-{
- return 1;
-}
-
static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_MAP4K_SPURCHAN \
@@ -1174,17 +994,17 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
u16 spur_val = AR_NO_SPUR;
- ath_print(common, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur idx:%d is2Ghz:%d val:%x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- ath_print(common, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP4K_SPURCHAN;
@@ -1202,8 +1022,6 @@ const struct eeprom_ops eep_4k_ops = {
.fill_eeprom = ath9k_hw_4k_fill_eeprom,
.get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_4k_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg,
.set_board_values = ath9k_hw_4k_set_board_values,
.set_addac = ath9k_hw_4k_set_addac,
.set_txpower = ath9k_hw_4k_set_txpower,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 966b9496a9dd..9b6bc8a953bc 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -37,21 +37,21 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
int addr, eep_start_loc;
eep_data = (u16 *)eep;
- if (ah->hw_version.devid == 0x7015)
+ if (common->bus_ops->ath_bus_type == ATH_USB)
eep_start_loc = AR9287_HTC_EEP_START_LOC;
else
eep_start_loc = AR9287_EEP_START_LOC;
if (!ath9k_hw_use_flash(ah)) {
- ath_print(common, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
eep_data)) {
- ath_print(common, ATH_DBG_EEPROM,
- "Unable to read eeprom region\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region\n");
return false;
}
eep_data++;
@@ -72,13 +72,12 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
if (!ath9k_hw_use_flash(ah)) {
if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
&magic)) {
- ath_print(common, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ ath_err(common, "Reading Magic # failed\n");
return false;
}
- ath_print(common, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -93,16 +92,15 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "Endianness mismatch.\n");
+ ath_err(common,
+ "Invalid EEPROM Magic. Endianness mismatch.\n");
return -EINVAL;
}
}
}
- ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -152,7 +150,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
eep->modalHeader.antCtrlChain[i] = integer;
}
- for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) {
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
word = swab16(eep->modalHeader.spurChans[i].spurChan);
eep->modalHeader.spurChans[i].spurChan = word;
}
@@ -160,9 +158,8 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
|| ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_print(common, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -223,163 +220,6 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
}
}
-static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq_ar9287 *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap,
- u16 *pPdGainBoundaries,
- u8 *pPDADCValues,
- u16 numXpdGains)
-{
-#define TMP_VAL_VPD_TABLE \
- ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
-
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR9287_NUM_PD_GAINS];
- u8 maxPwrT4[AR9287_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
- static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR9287_BCHAN_UNUSED)
- break;
- }
-
- match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
- bChans, numPiers, &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR9287_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] = min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
- pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] = (u8)(ath9k_hw_interpolate(
- (u16)FREQ2FBIN(centers. synth_center,
- IS_CHAN_2GHZ(chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
- }
- }
- }
-
- k = 0;
-
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16)(maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
-
- pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
- pPdGainBoundaries[i]);
-
-
- minDelta = 0;
-
- if (i == 0) {
- if (AR_SREV_9280_20_OR_LATER(ah))
- ss = (int16_t)(0 - (minPwrT4[i] / 2));
- else
- ss = 0;
- } else {
- ss = (int16_t)((pPdGainBoundaries[i-1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
-
- vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8)(pPdGainBoundaries[i] +
- tPdGainOverlap - (minPwrT4[i] / 2));
- maxIndex = (tgtIndex < sizeCurrVpdTable) ?
- tgtIndex : sizeCurrVpdTable;
-
- while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1)))
- pPDADCValues[k++] = vpdTableI[i][ss++];
-
- vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex > maxIndex) {
- while ((ss <= tgtIndex) &&
- (k < (AR9287_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
- pPDADCValues[k++] =
- (u8)((tmpVal > 255) ? 255 : tmpVal);
- ss++;
- }
- }
- }
-
- while (i < AR9287_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = pPdGainBoundaries[i-1];
- i++;
- }
-
- while (k < AR9287_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k-1];
- k++;
- }
-
-#undef TMP_VAL_VPD_TABLE
-}
-
static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
struct ath9k_channel *chan,
struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
@@ -392,7 +232,7 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED)
+ if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
break;
}
@@ -458,11 +298,11 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
u8 *pCalBChans = NULL;
u16 pdGainOverlap_t2;
- u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
- u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
+ u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers = 0, i, j;
u16 numXpdGain, xpdMask;
- u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
+ u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
u32 reg32, regOffset, regChainOffset, regval;
int16_t modalIdx, diff = 0;
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
@@ -490,12 +330,12 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
numXpdGain = 0;
/* Calculate the value of xpdgains from the xpdGain Mask */
- for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
- if (numXpdGain >= AR9287_NUM_PD_GAINS)
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
break;
xpdGainValues[numXpdGain] =
- (u16)(AR9287_PD_GAINS_IN_MASK-i);
+ (u16)(AR5416_PD_GAINS_IN_MASK-i);
numXpdGain++;
}
}
@@ -528,7 +368,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
(struct cal_data_per_freq_ar9287 *)
pEepData->calPierData2G[i];
- ath9k_hw_get_ar9287_gain_boundaries_pdadcs(ah, chan,
+ ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
pRawDataset,
pCalBChans, numPiers,
pdGainOverlap_t2,
@@ -564,13 +404,13 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
(int32_t)AR9287_PWR_TABLE_OFFSET_DB);
diff *= 2;
- for (j = 0; j < ((u16)AR9287_NUM_PDADC_VALUES-diff); j++)
+ for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++)
pdadcValues[j] = pdadcValues[j+diff];
- for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
- j < AR9287_NUM_PDADC_VALUES; j++)
+ for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff);
+ j < AR5416_NUM_PDADC_VALUES; j++)
pdadcValues[j] =
- pdadcValues[AR9287_NUM_PDADC_VALUES-diff];
+ pdadcValues[AR5416_NUM_PDADC_VALUES-diff];
}
if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
@@ -613,9 +453,9 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ { 0, 3, 6, 9, MAX_RATE_POWER };
int i;
int16_t twiceLargestAntenna;
struct cal_ctl_data_ar9287 *rep;
@@ -626,13 +466,13 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
struct cal_target_power_ht targetPowerHt20,
targetPowerHt40 = {0, {0, 0, 0, 0} };
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11g[] = {CTL_11B,
- CTL_11G,
- CTL_2GHT20,
- CTL_11B_EXT,
- CTL_11G_EXT,
- CTL_2GHT40};
- u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
+ static const u16 ctlModesFor11g[] = {
+ CTL_11B, CTL_11G, CTL_2GHT20,
+ CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+ };
+ u16 numCtlModes = 0;
+ const u16 *pCtlMode = NULL;
+ u16 ctlMode, freq;
struct chan_centers centers;
int tx_chainmask;
u16 twiceMinEdgePower;
@@ -853,7 +693,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+ u8 powerLimit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
@@ -877,12 +717,26 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+ regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR9287_MAX_RATE_POWER)
- ratesArray[i] = AR9287_MAX_RATE_POWER;
+ if (ratesArray[i] > MAX_RATE_POWER)
+ ratesArray[i] = MAX_RATE_POWER;
+
+ if (ratesArray[i] > regulatory->max_power_level)
+ regulatory->max_power_level = ratesArray[i];
}
+ if (test)
+ return;
+
+ if (IS_CHAN_2GHZ(chan))
+ i = rate1l;
+ else
+ i = rate6mb;
+
+ regulatory->max_power_level = ratesArray[i];
+
if (AR_SREV_9280_20_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++)
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
@@ -971,17 +825,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
-
- if (IS_CHAN_2GHZ(chan))
- i = rate1l;
- else
- i = rate6mb;
-
- if (AR_SREV_9280_20_OR_LATER(ah))
- regulatory->max_power_level =
- ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
- else
- regulatory->max_power_level = ratesArray[i];
}
static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
@@ -1023,8 +866,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
}
- REG_WRITE(ah, AR_PHY_SWITCH_COM,
- ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
regChainOffset = i * 0x1000;
@@ -1125,21 +967,6 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
pModal->xpaBiasLvl);
}
-static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
- enum ath9k_hal_freq_band freq_band)
-{
- return 1;
-}
-
-static u32 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ar9287_eeprom *eep = &ah->eeprom.map9287;
- struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
-
- return pModal->antCtrlCommon;
-}
-
static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
u16 i, bool is2GHz)
{
@@ -1149,17 +976,17 @@ static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- ath_print(common, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur idx:%d is2Ghz:%d val:%x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- ath_print(common, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP9287_SPURCHAN;
@@ -1177,8 +1004,6 @@ const struct eeprom_ops eep_ar9287_ops = {
.fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
.get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_ar9287_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_ar9287_get_eeprom_antenna_cfg,
.set_board_values = ath9k_hw_ar9287_set_board_values,
.set_addac = ath9k_hw_ar9287_set_addac,
.set_txpower = ath9k_hw_ar9287_set_txpower,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 76b4d65472dd..749a93608664 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -96,8 +96,8 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc,
eep_data)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Unable to read eeprom region\n");
+ ath_err(ath9k_hw_common(ah),
+ "Unable to read eeprom region\n");
return false;
}
eep_data++;
@@ -117,13 +117,13 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
int i, addr, size;
if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n");
+ ath_err(common, "Reading Magic # failed\n");
return false;
}
if (!ath9k_hw_use_flash(ah)) {
- ath_print(common, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -139,16 +139,15 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "Endianness mismatch.\n");
+ ath_err(common,
+ "Invalid EEPROM Magic. Endianness mismatch.\n");
return -EINVAL;
}
}
}
- ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.def.baseEepHeader.length);
@@ -169,8 +168,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
u32 integer, j;
u16 word;
- ath_print(common, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing.\n");
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing.\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -207,7 +206,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
pModal->antCtrlChain[i] = integer;
}
- for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
word = swab16(pModal->spurChans[i].spurChan);
pModal->spurChans[i].spurChan = word;
}
@@ -216,8 +215,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_print(common, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -228,6 +226,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
eep->baseEepHeader.pwdclkind == 0)
ah->need_an_top2_fixup = 1;
+ if ((common->bus_ops->ath_bus_type == ATH_USB) &&
+ (AR_SREV_9280(ah)))
+ eep->modalHeader[0].xpaBiasLvl = 0;
+
return 0;
}
@@ -376,8 +378,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
- REG_WRITE(ah, AR_PHY_SWITCH_COM,
- ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon & 0xffff);
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
if (AR_SREV_9280(ah)) {
@@ -451,9 +452,10 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
AR_AN_TOP2_LOCALBIAS,
AR_AN_TOP2_LOCALBIAS_S,
- pModal->local_bias);
+ !!(pModal->lna_ctl &
+ LNA_CTL_LOCAL_BIAS));
REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
- pModal->force_xpaon);
+ !!(pModal->lna_ctl & LNA_CTL_FORCE_XPA));
}
REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
@@ -589,168 +591,6 @@ static void ath9k_hw_def_set_addac(struct ath_hw *ah,
#undef XPA_LVL_FREQ
}
-static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
-{
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- static u8 vpdTableL[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR5416_NUM_PD_GAINS];
- u8 maxPwrT4[AR5416_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
-
- memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
- }
-
- match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)),
- bChans, numPiers, &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR5416_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] =
- min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
- pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
- }
- }
- }
-
- k = 0;
-
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16)(maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
-
- pPdGainBoundaries[i] =
- min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
-
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
-
- if (i == 0) {
- if (AR_SREV_9280_20_OR_LATER(ah))
- ss = (int16_t)(0 - (minPwrT4[i] / 2));
- else
- ss = 0;
- } else {
- ss = (int16_t)((pPdGainBoundaries[i - 1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
- vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
- (minPwrT4[i] / 2));
- maxIndex = (tgtIndex < sizeCurrVpdTable) ?
- tgtIndex : sizeCurrVpdTable;
-
- while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- pPDADCValues[k++] = vpdTableI[i][ss++];
- }
-
- vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex >= maxIndex) {
- while ((ss <= tgtIndex) &&
- (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
- (ss - maxIndex + 1) * vpdStep));
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
- ss++;
- }
- }
- }
-
- while (i < AR5416_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
- i++;
- }
-
- while (k < AR5416_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k - 1];
- k++;
- }
-}
-
static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
u16 *gb,
u16 numXpdGain,
@@ -783,7 +623,7 @@ static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
/* Because of a hardware limitation, ensure the gain boundary
* is not larger than (63 - overlap)
*/
- gb_limit = (u16)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
+ gb_limit = (u16)(MAX_RATE_POWER - pdGainOverlap_t2);
for (k = 0; k < numXpdGain; k++)
gb[k] = (u16)min(gb_limit, gb[k]);
@@ -917,7 +757,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
ath9k_olc_get_pdadcs(ah, pcdacIdx,
txPower/2, pdadcValues);
} else {
- ath9k_hw_get_def_gain_boundaries_pdadcs(ah,
+ ath9k_hw_get_gain_boundaries_pdadcs(ah,
chan, pRawDataset,
pCalBChans, numPiers,
pdGainOverlap_t2,
@@ -965,20 +805,19 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC: Chain %d | PDADC %3d "
- "Value %3d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | PDADC %3d "
- "Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_dbg(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | PDADC %3d "
+ "Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d "
+ "Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3, pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -1003,9 +842,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ u16 twiceMaxEdgePower = MAX_RATE_POWER;
static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ { 0, 3, 6, 9, MAX_RATE_POWER };
int i;
int16_t twiceLargestAntenna;
@@ -1021,13 +860,16 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
0, {0, 0, 0, 0}
};
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11a[] =
- { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
- u16 ctlModesFor11g[] =
- { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
- CTL_2GHT40
- };
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ static const u16 ctlModesFor11a[] = {
+ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+ };
+ static const u16 ctlModesFor11g[] = {
+ CTL_11B, CTL_11G, CTL_2GHT20,
+ CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+ };
+ u16 numCtlModes;
+ const u16 *pCtlMode;
+ u16 ctlMode, freq;
struct chan_centers centers;
int tx_chainmask;
u16 twiceMinEdgePower;
@@ -1062,15 +904,19 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
case 1:
break;
case 2:
- scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ else
+ scaledPower = 0;
break;
case 3:
- scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ else
+ scaledPower = 0;
break;
}
- scaledPower = max((u16)0, scaledPower);
-
if (IS_CHAN_2GHZ(chan)) {
numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
SUB_NUM_CTL_MODES_AT_2G_40;
@@ -1143,7 +989,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ twiceMaxEdgePower = MAX_RATE_POWER;
for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
if ((((cfgCtl & ~CTL_MODE_M) |
@@ -1258,7 +1104,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+ u8 powerLimit, bool test)
{
#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
@@ -1285,12 +1131,44 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
+ regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
+ if (ratesArray[i] > MAX_RATE_POWER)
+ ratesArray[i] = MAX_RATE_POWER;
+ if (ratesArray[i] > regulatory->max_power_level)
+ regulatory->max_power_level = ratesArray[i];
+ }
+
+ if (!test) {
+ i = rate6mb;
+
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ regulatory->max_power_level = ratesArray[i];
+ }
+
+ switch(ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
}
+ if (test)
+ return;
+
if (AR_SREV_9280_20_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++) {
int8_t pwr_table_offset;
@@ -1387,62 +1265,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
| ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
-
- i = rate6mb;
-
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
-
- if (AR_SREV_9280_20_OR_LATER(ah))
- regulatory->max_power_level =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
- else
- regulatory->max_power_level = ratesArray[i];
-
- switch(ar5416_get_ntxchains(ah->txchainmask)) {
- case 1:
- break;
- case 2:
- regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
- break;
- case 3:
- regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
- break;
- default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
- break;
- }
-}
-
-static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
- enum ath9k_hal_freq_band freq_band)
-{
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[freq_band]);
- struct base_eep_header *pBase = &eep->baseEepHeader;
- u8 num_ant_config;
-
- num_ant_config = 1;
-
- if (pBase->version >= 0x0E0D)
- if (pModal->useAnt1)
- num_ant_config += 1;
-
- return num_ant_config;
-}
-
-static u32 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ar5416_eeprom_def *eep = &ah->eeprom.def;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
- return pModal->antCtrlCommon;
}
static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
@@ -1453,17 +1275,17 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
u16 spur_val = AR_NO_SPUR;
- ath_print(common, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur idx:%d is2Ghz:%d val:%x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- ath_print(common, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_dbg(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_DEF_SPURCHAN;
@@ -1481,8 +1303,6 @@ const struct eeprom_ops eep_def_ops = {
.fill_eeprom = ath9k_hw_def_fill_eeprom,
.get_eeprom_ver = ath9k_hw_def_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_def_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_def_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg,
.set_board_values = ath9k_hw_def_set_board_values,
.set_addac = ath9k_hw_def_set_addac,
.set_txpower = ath9k_hw_def_set_txpower,
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 4a9a68bba324..133764069246 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -103,8 +103,8 @@ static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
if (ret)
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Failed to register led:%s", led->name);
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "Failed to register led:%s", led->name);
else
led->registered = 1;
return ret;
@@ -236,13 +236,13 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
/* Detect if colocated bt started scanning */
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
- "BT scan detected");
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT scan detected\n");
sc->sc_flags |= (SC_OP_BT_SCAN |
SC_OP_BT_PRIORITY_DETECTED);
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
- "BT priority traffic detected");
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected\n");
sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
}
@@ -259,7 +259,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ah->imask |= ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->imask);
}
@@ -273,7 +273,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
/* if no timer is enabled, turn off interrupt mask */
if (timer_table->timer_mask.val == 0) {
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ah->imask &= ~ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->imask);
}
@@ -310,10 +310,8 @@ static void ath_btcoex_period_timer(unsigned long data)
timer_period = is_btscan ? btcoex->btscan_no_stomp :
btcoex->btcoex_no_stomp;
- ath9k_gen_timer_start(ah,
- btcoex->no_stomp_timer,
- (ath9k_hw_gettsf32(ah) +
- timer_period), timer_period * 10);
+ ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0,
+ timer_period * 10);
btcoex->hw_timer_enabled = true;
}
@@ -333,8 +331,8 @@ static void ath_btcoex_no_stomp_timer(void *arg)
struct ath_common *common = ath9k_hw_common(ah);
bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
- ath_print(common, ATH_DBG_BTCOEX,
- "no stomp timer running\n");
+ ath_dbg(common, ATH_DBG_BTCOEX,
+ "no stomp timer running\n");
spin_lock_bh(&btcoex->btcoex_lock);
@@ -380,8 +378,8 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_hw *ah = sc->sc_ah;
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "Starting btcoex timers");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Starting btcoex timers\n");
/* make sure duty cycle timer is also stopped when resuming */
if (btcoex->hw_timer_enabled)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 6576f683dba0..5ab3084eb9cb 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -28,15 +28,30 @@ MODULE_FIRMWARE(FIRMWARE_AR9271);
static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
{ USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
- { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */
- { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */
{ USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
- { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */
{ USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
{ USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
{ USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */
+ { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
- { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
+ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
+ { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
+
+ { USB_DEVICE(0x0cf3, 0x7015),
+ .driver_info = AR9287_USB }, /* Atheros */
+ { USB_DEVICE(0x1668, 0x1200),
+ .driver_info = AR9287_USB }, /* Verizon */
+
+ { USB_DEVICE(0x0cf3, 0x7010),
+ .driver_info = AR9280_USB }, /* Atheros */
+ { USB_DEVICE(0x0846, 0x9018),
+ .driver_info = AR9280_USB }, /* Netgear WNDA3200 */
+ { USB_DEVICE(0x083A, 0xA704),
+ .driver_info = AR9280_USB }, /* SMC Networks */
+
{ },
};
@@ -138,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ENODEV:
case -ESHUTDOWN:
/*
- * The URB has been killed, free the SKBs
- * and return.
+ * The URB has been killed, free the SKBs.
*/
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
- return;
+
+ /*
+ * If the URBs are being flushed, no need to add this
+ * URB to the free list.
+ */
+ spin_lock(&hif_dev->tx.tx_lock);
+ if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
+ spin_unlock(&hif_dev->tx.tx_lock);
+ return;
+ }
+ spin_unlock(&hif_dev->tx.tx_lock);
+
+ /*
+ * In the stop() case, this URB has to be added to
+ * the free list.
+ */
+ goto add_free;
default:
break;
}
- /* Check if TX has been stopped */
+ /*
+ * Check if TX has been stopped, this is needed because
+ * this CB could have been invoked just after the TX lock
+ * was released in hif_stop() and kill_urb() hasn't been
+ * called yet.
+ */
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
spin_unlock(&hif_dev->tx.tx_lock);
@@ -299,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
static void hif_usb_stop(void *hif_handle, u8 pipe_id)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+ struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
@@ -306,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+
+ /* The pending URBs have to be canceled. */
+ list_for_each_entry_safe(tx_buf, tx_buf_tmp,
+ &hif_dev->tx.tx_pending, list) {
+ usb_kill_urb(tx_buf->urb);
+ }
}
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
@@ -347,9 +389,9 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
struct sk_buff *skb)
{
struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
- int index = 0, i = 0, chk_idx, len = skb->len;
- int rx_remain_len = 0, rx_pkt_len = 0;
- u16 pkt_len, pkt_tag, pool_index = 0;
+ int index = 0, i = 0, len = skb->len;
+ int rx_remain_len, rx_pkt_len;
+ u16 pool_index = 0;
u8 *ptr;
spin_lock(&hif_dev->rx_lock);
@@ -383,64 +425,64 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
spin_unlock(&hif_dev->rx_lock);
while (index < len) {
+ u16 pkt_len;
+ u16 pkt_tag;
+ u16 pad_len;
+ int chk_idx;
+
ptr = (u8 *) skb->data;
pkt_len = ptr[index] + (ptr[index+1] << 8);
pkt_tag = ptr[index+2] + (ptr[index+3] << 8);
- if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) {
- u16 pad_len;
-
- pad_len = 4 - (pkt_len & 0x3);
- if (pad_len == 4)
- pad_len = 0;
-
- chk_idx = index;
- index = index + 4 + pkt_len + pad_len;
-
- if (index > MAX_RX_BUF_SIZE) {
- spin_lock(&hif_dev->rx_lock);
- hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
- hif_dev->rx_transfer_len =
- MAX_RX_BUF_SIZE - chk_idx - 4;
- hif_dev->rx_pad_len = pad_len;
-
- nskb = __dev_alloc_skb(pkt_len + 32,
- GFP_ATOMIC);
- if (!nskb) {
- dev_err(&hif_dev->udev->dev,
- "ath9k_htc: RX memory allocation"
- " error\n");
- spin_unlock(&hif_dev->rx_lock);
- goto err;
- }
- skb_reserve(nskb, 32);
- RX_STAT_INC(skb_allocated);
-
- memcpy(nskb->data, &(skb->data[chk_idx+4]),
- hif_dev->rx_transfer_len);
-
- /* Record the buffer pointer */
- hif_dev->remain_skb = nskb;
+ if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) {
+ RX_STAT_INC(skb_dropped);
+ return;
+ }
+
+ pad_len = 4 - (pkt_len & 0x3);
+ if (pad_len == 4)
+ pad_len = 0;
+
+ chk_idx = index;
+ index = index + 4 + pkt_len + pad_len;
+
+ if (index > MAX_RX_BUF_SIZE) {
+ spin_lock(&hif_dev->rx_lock);
+ hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
+ hif_dev->rx_transfer_len =
+ MAX_RX_BUF_SIZE - chk_idx - 4;
+ hif_dev->rx_pad_len = pad_len;
+
+ nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
+ if (!nskb) {
+ dev_err(&hif_dev->udev->dev,
+ "ath9k_htc: RX memory allocation error\n");
spin_unlock(&hif_dev->rx_lock);
- } else {
- nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
- if (!nskb) {
- dev_err(&hif_dev->udev->dev,
- "ath9k_htc: RX memory allocation"
- " error\n");
- goto err;
- }
- skb_reserve(nskb, 32);
- RX_STAT_INC(skb_allocated);
-
- memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
- skb_put(nskb, pkt_len);
- skb_pool[pool_index++] = nskb;
+ goto err;
}
+ skb_reserve(nskb, 32);
+ RX_STAT_INC(skb_allocated);
+
+ memcpy(nskb->data, &(skb->data[chk_idx+4]),
+ hif_dev->rx_transfer_len);
+
+ /* Record the buffer pointer */
+ hif_dev->remain_skb = nskb;
+ spin_unlock(&hif_dev->rx_lock);
} else {
- RX_STAT_INC(skb_dropped);
- return;
+ nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
+ if (!nskb) {
+ dev_err(&hif_dev->udev->dev,
+ "ath9k_htc: RX memory allocation error\n");
+ goto err;
+ }
+ skb_reserve(nskb, 32);
+ RX_STAT_INC(skb_allocated);
+
+ memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
+ skb_put(nskb, pkt_len);
+ skb_pool[pool_index++] = nskb;
}
}
@@ -455,7 +497,7 @@ err:
static void ath9k_hif_usb_rx_cb(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+ struct hif_device_usb *hif_dev =
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
int ret;
@@ -502,7 +544,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct sk_buff *nskb;
- struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+ struct hif_device_usb *hif_dev =
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
int ret;
@@ -540,11 +582,11 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
return;
}
- usb_fill_int_urb(urb, hif_dev->udev,
+ usb_fill_bulk_urb(urb, hif_dev->udev,
usb_rcvbulkpipe(hif_dev->udev,
USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE,
- ath9k_hif_usb_reg_in_cb, nskb, 1);
+ ath9k_hif_usb_reg_in_cb, nskb);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
@@ -572,6 +614,7 @@ free:
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
{
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
+ unsigned long flags;
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_buf, list) {
@@ -582,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf);
}
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+ hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
@@ -720,11 +767,11 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
if (!skb)
goto err;
- usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
+ usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
usb_rcvbulkpipe(hif_dev->udev,
USB_REG_IN_PIPE),
skb->data, MAX_REG_IN_BUF_SIZE,
- ath9k_hif_usb_reg_in_cb, skb, 1);
+ ath9k_hif_usb_reg_in_cb, skb);
if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
goto err;
@@ -770,7 +817,8 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
}
-static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
+static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev,
+ u32 drv_info)
{
int transfer, err;
const void *data = hif_dev->firmware->data;
@@ -801,16 +849,10 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
}
kfree(buf);
- switch (hif_dev->device_id) {
- case 0x7010:
- case 0x7015:
- case 0x9018:
+ if (IS_AR7010_DEVICE(drv_info))
firm_offset = AR7010_FIRMWARE_TEXT;
- break;
- default:
+ else
firm_offset = AR9271_FIRMWARE_TEXT;
- break;
- }
/*
* Issue FW download complete command to firmware.
@@ -828,7 +870,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
return 0;
}
-static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
+static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info)
{
int ret, idx;
struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
@@ -843,16 +885,8 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
goto err_fw_req;
}
- /* Alloc URBs */
- ret = ath9k_hif_usb_alloc_urbs(hif_dev);
- if (ret) {
- dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Unable to allocate URBs\n");
- goto err_urb;
- }
-
/* Download firmware */
- ret = ath9k_hif_usb_download_fw(hif_dev);
+ ret = ath9k_hif_usb_download_fw(hif_dev, drv_info);
if (ret) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: Firmware - %s download failed\n",
@@ -866,21 +900,27 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
*/
for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
endp = &alt->endpoint[idx].desc;
- if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
- == 0x04) &&
- ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT)) {
+ if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
endp->bInterval = 0;
}
}
+ /* Alloc URBs */
+ ret = ath9k_hif_usb_alloc_urbs(hif_dev);
+ if (ret) {
+ dev_err(&hif_dev->udev->dev,
+ "ath9k_htc: Unable to allocate URBs\n");
+ goto err_urb;
+ }
+
return 0;
-err_fw_download:
- ath9k_hif_usb_dealloc_urbs(hif_dev);
err_urb:
+ ath9k_hif_usb_dealloc_urbs(hif_dev);
+err_fw_download:
release_firmware(hif_dev->firmware);
err_fw_req:
hif_dev->firmware = NULL;
@@ -925,21 +965,15 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
/* Find out which firmware to load */
- switch(hif_dev->device_id) {
- case 0x7010:
- case 0x7015:
- case 0x9018:
+ if (IS_AR7010_DEVICE(id->driver_info))
if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
hif_dev->fw_name = FIRMWARE_AR7010_1_1;
else
hif_dev->fw_name = FIRMWARE_AR7010;
- break;
- default:
+ else
hif_dev->fw_name = FIRMWARE_AR9271;
- break;
- }
- ret = ath9k_hif_usb_dev_init(hif_dev);
+ ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info);
if (ret) {
ret = -EINVAL;
goto err_hif_init_usb;
@@ -947,7 +981,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
&hif_dev->udev->dev, hif_dev->device_id,
- hif_dev->udev->product);
+ hif_dev->udev->product, id->driver_info);
if (ret) {
ret = -EINVAL;
goto err_htc_hw_init;
@@ -990,18 +1024,17 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev)
static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
{
struct usb_device *udev = interface_to_usbdev(interface);
- struct hif_device_usb *hif_dev =
- (struct hif_device_usb *) usb_get_intfdata(interface);
+ struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
+ bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
if (hif_dev) {
- ath9k_htc_hw_deinit(hif_dev->htc_handle,
- (udev->state == USB_STATE_NOTATTACHED) ? true : false);
+ ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
usb_set_intfdata(interface, NULL);
}
- if (hif_dev->flags & HIF_USB_START)
+ if (!unplugged && (hif_dev->flags & HIF_USB_START))
ath9k_hif_usb_reboot(udev);
kfree(hif_dev);
@@ -1013,8 +1046,14 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
static int ath9k_hif_usb_suspend(struct usb_interface *interface,
pm_message_t message)
{
- struct hif_device_usb *hif_dev =
- (struct hif_device_usb *) usb_get_intfdata(interface);
+ struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
+
+ /*
+ * The device has to be set to FULLSLEEP mode in case no
+ * interface is up.
+ */
+ if (!(hif_dev->flags & HIF_USB_START))
+ ath9k_htc_suspend(hif_dev->htc_handle);
ath9k_hif_usb_dealloc_urbs(hif_dev);
@@ -1023,8 +1062,8 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
static int ath9k_hif_usb_resume(struct usb_interface *interface)
{
- struct hif_device_usb *hif_dev =
- (struct hif_device_usb *) usb_get_intfdata(interface);
+ struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
+ struct htc_target *htc_handle = hif_dev->htc_handle;
int ret;
ret = ath9k_hif_usb_alloc_urbs(hif_dev);
@@ -1032,7 +1071,8 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface)
return ret;
if (hif_dev->firmware) {
- ret = ath9k_hif_usb_download_fw(hif_dev);
+ ret = ath9k_hif_usb_download_fw(hif_dev,
+ htc_handle->drv_priv->ah->hw_version.usbdev);
if (ret)
goto fail_resume;
} else {
@@ -1042,7 +1082,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface)
mdelay(100);
- ret = ath9k_htc_resume(hif_dev->htc_handle);
+ ret = ath9k_htc_resume(htc_handle);
if (ret)
goto fail_resume;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 2daf97b11c08..7b9d863d4035 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -17,6 +17,8 @@
#ifndef HTC_USB_H
#define HTC_USB_H
+#define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
+
#define AR9271_FIRMWARE 0x501000
#define AR9271_FIRMWARE_TEXT 0x903000
#define AR7010_FIRMWARE_TEXT 0x906000
@@ -62,6 +64,7 @@ struct tx_buf {
};
#define HIF_USB_TX_STOP BIT(0)
+#define HIF_USB_TX_FLUSH BIT(1)
struct hif_usb_tx {
u8 flags;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 75ecf6a30d25..1ce506f23110 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -331,17 +331,15 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
#define OP_INVALID BIT(0)
#define OP_SCANNING BIT(1)
-#define OP_FULL_RESET BIT(2)
-#define OP_LED_ASSOCIATED BIT(3)
-#define OP_LED_ON BIT(4)
-#define OP_PREAMBLE_SHORT BIT(5)
-#define OP_PROTECT_ENABLE BIT(6)
-#define OP_ASSOCIATED BIT(7)
-#define OP_ENABLE_BEACON BIT(8)
-#define OP_LED_DEINIT BIT(9)
-#define OP_UNPLUGGED BIT(10)
-#define OP_BT_PRIORITY_DETECTED BIT(11)
-#define OP_BT_SCAN BIT(12)
+#define OP_LED_ASSOCIATED BIT(2)
+#define OP_LED_ON BIT(3)
+#define OP_PREAMBLE_SHORT BIT(4)
+#define OP_PROTECT_ENABLE BIT(5)
+#define OP_ASSOCIATED BIT(6)
+#define OP_ENABLE_BEACON BIT(7)
+#define OP_LED_DEINIT BIT(8)
+#define OP_BT_PRIORITY_DETECTED BIT(9)
+#define OP_BT_SCAN BIT(10)
struct ath9k_htc_priv {
struct device *dev;
@@ -368,7 +366,7 @@ struct ath9k_htc_priv {
u16 seq_no;
u32 bmiss_cnt;
- struct ath9k_hw_cal_data caldata[38];
+ struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS];
spinlock_t beacon_lock;
@@ -378,7 +376,7 @@ struct ath9k_htc_priv {
struct ieee80211_vif *vif;
struct htc_beacon_config cur_beacon_conf;
unsigned int rxfilter;
- struct tasklet_struct wmi_tasklet;
+ struct tasklet_struct swba_tasklet;
struct tasklet_struct rx_tasklet;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath9k_htc_rx rx;
@@ -386,6 +384,7 @@ struct ath9k_htc_priv {
struct sk_buff_head tx_queue;
struct delayed_work ath9k_ani_work;
struct work_struct ps_work;
+ struct work_struct fatal_work;
struct mutex htc_pm_lock;
unsigned long ps_usecount;
@@ -420,6 +419,8 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
common->bus_ops->read_cachesize(common, csz);
}
+void ath9k_htc_reset(struct ath9k_htc_priv *priv);
+
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
@@ -432,9 +433,11 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok);
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
void ath9k_htc_station_work(struct work_struct *work);
void ath9k_htc_aggr_work(struct work_struct *work);
void ath9k_ani_work(struct work_struct *work);;
+void ath_start_ani(struct ath9k_htc_priv *priv);
int ath9k_tx_init(struct ath9k_htc_priv *priv);
void ath9k_tx_tasklet(unsigned long data);
@@ -455,15 +458,23 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv);
void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv);
void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
void ath9k_ps_work(struct work_struct *work);
+bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+ enum ath9k_power_mode mode);
+void ath_update_txpow(struct ath9k_htc_priv *priv);
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
+void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
+void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
+void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
+void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv);
void ath9k_init_leds(struct ath9k_htc_priv *priv);
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
- u16 devid, char *product);
+ u16 devid, char *product, u32 drv_info);
void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
#ifdef CONFIG_PM
+void ath9k_htc_suspend(struct htc_target *htc_handle);
int ath9k_htc_resume(struct htc_target *htc_handle);
#endif
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 1b72aa482ac7..87cc65a78a3f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -123,11 +123,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
/* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
- ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
- ath_print(common, ATH_DBG_BEACON,
- "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration,
- bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+ ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+ bs.bs_bmissthreshold, bs.bs_sleepduration,
+ bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
/* Set the computed STA beacon timers */
@@ -154,9 +154,9 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
if (priv->op_flags & OP_ENABLE_BEACON)
imask |= ATH9K_INT_SWBA;
- ath_print(common, ATH_DBG_BEACON,
- "IBSS Beacon config, intval: %d, imask: 0x%x\n",
- bss_conf->beacon_interval, imask);
+ ath_dbg(common, ATH_DBG_BEACON,
+ "IBSS Beacon config, intval: %d, imask: 0x%x\n",
+ bss_conf->beacon_interval, imask);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
@@ -246,8 +246,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
qi.tqi_cwmax = qi_be.tqi_cwmax;
if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Unable to update beacon queue %u!\n", qnum);
+ ath_err(ath9k_hw_common(ah),
+ "Unable to update beacon queue %u!\n", qnum);
} else {
ath9k_hw_resettxqueue(ah, priv->beaconq);
}
@@ -278,8 +278,8 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
break;
default:
- ath_print(common, ATH_DBG_CONFIG,
- "Unsupported beaconing mode\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Unsupported beaconing mode\n");
return;
}
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 50eec9a3b88c..fe70f67aa088 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
#include "htc.h"
/******************/
@@ -20,13 +36,13 @@ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
/* Detect if colocated bt started scanning */
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "BT scan detected");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "BT scan detected\n");
priv->op_flags |= (OP_BT_SCAN |
OP_BT_PRIORITY_DETECTED);
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "BT priority traffic detected");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected\n");
priv->op_flags |= OP_BT_PRIORITY_DETECTED;
}
@@ -83,8 +99,8 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
struct ath_common *common = ath9k_hw_common(ah);
bool is_btscan = priv->op_flags & OP_BT_SCAN;
- ath_print(common, ATH_DBG_BTCOEX,
- "time slice work for bt and wlan\n");
+ ath_dbg(common, ATH_DBG_BTCOEX,
+ "time slice work for bt and wlan\n");
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
@@ -114,8 +130,7 @@ void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
struct ath_btcoex *btcoex = &priv->btcoex;
struct ath_hw *ah = priv->ah;
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "Starting btcoex work");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n");
btcoex->bt_priority_cnt = 0;
btcoex->bt_priority_time = jiffies;
@@ -132,3 +147,314 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
cancel_delayed_work_sync(&priv->coex_period_work);
cancel_delayed_work_sync(&priv->duty_cycle_work);
}
+
+/*******/
+/* LED */
+/*******/
+
+static void ath9k_led_blink_work(struct work_struct *work)
+{
+ struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+ ath9k_led_blink_work.work);
+
+ if (!(priv->op_flags & OP_LED_ASSOCIATED))
+ return;
+
+ if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
+ (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
+ else
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+ (priv->op_flags & OP_LED_ON) ? 1 : 0);
+
+ ieee80211_queue_delayed_work(priv->hw,
+ &priv->ath9k_led_blink_work,
+ (priv->op_flags & OP_LED_ON) ?
+ msecs_to_jiffies(priv->led_off_duration) :
+ msecs_to_jiffies(priv->led_on_duration));
+
+ priv->led_on_duration = priv->led_on_cnt ?
+ max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
+ ATH_LED_ON_DURATION_IDLE;
+ priv->led_off_duration = priv->led_off_cnt ?
+ max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
+ ATH_LED_OFF_DURATION_IDLE;
+ priv->led_on_cnt = priv->led_off_cnt = 0;
+
+ if (priv->op_flags & OP_LED_ON)
+ priv->op_flags &= ~OP_LED_ON;
+ else
+ priv->op_flags |= OP_LED_ON;
+}
+
+static void ath9k_led_brightness_work(struct work_struct *work)
+{
+ struct ath_led *led = container_of(work, struct ath_led,
+ brightness_work.work);
+ struct ath9k_htc_priv *priv = led->priv;
+
+ switch (led->brightness) {
+ case LED_OFF:
+ if (led->led_type == ATH_LED_ASSOC ||
+ led->led_type == ATH_LED_RADIO) {
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+ (led->led_type == ATH_LED_RADIO));
+ priv->op_flags &= ~OP_LED_ASSOCIATED;
+ if (led->led_type == ATH_LED_RADIO)
+ priv->op_flags &= ~OP_LED_ON;
+ } else {
+ priv->led_off_cnt++;
+ }
+ break;
+ case LED_FULL:
+ if (led->led_type == ATH_LED_ASSOC) {
+ priv->op_flags |= OP_LED_ASSOCIATED;
+ ieee80211_queue_delayed_work(priv->hw,
+ &priv->ath9k_led_blink_work, 0);
+ } else if (led->led_type == ATH_LED_RADIO) {
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
+ priv->op_flags |= OP_LED_ON;
+ } else {
+ priv->led_on_cnt++;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath9k_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
+ struct ath9k_htc_priv *priv = led->priv;
+
+ led->brightness = brightness;
+ if (!(priv->op_flags & OP_LED_DEINIT))
+ ieee80211_queue_delayed_work(priv->hw,
+ &led->brightness_work, 0);
+}
+
+void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
+{
+ cancel_delayed_work_sync(&priv->radio_led.brightness_work);
+ cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
+ cancel_delayed_work_sync(&priv->tx_led.brightness_work);
+ cancel_delayed_work_sync(&priv->rx_led.brightness_work);
+}
+
+static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
+ char *trigger)
+{
+ int ret;
+
+ led->priv = priv;
+ led->led_cdev.name = led->name;
+ led->led_cdev.default_trigger = trigger;
+ led->led_cdev.brightness_set = ath9k_led_brightness;
+
+ ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
+ if (ret)
+ ath_err(ath9k_hw_common(priv->ah),
+ "Failed to register led:%s", led->name);
+ else
+ led->registered = 1;
+
+ INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
+
+ return ret;
+}
+
+static void ath9k_unregister_led(struct ath_led *led)
+{
+ if (led->registered) {
+ led_classdev_unregister(&led->led_cdev);
+ led->registered = 0;
+ }
+}
+
+void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
+{
+ priv->op_flags |= OP_LED_DEINIT;
+ ath9k_unregister_led(&priv->assoc_led);
+ priv->op_flags &= ~OP_LED_ASSOCIATED;
+ ath9k_unregister_led(&priv->tx_led);
+ ath9k_unregister_led(&priv->rx_led);
+ ath9k_unregister_led(&priv->radio_led);
+}
+
+void ath9k_init_leds(struct ath9k_htc_priv *priv)
+{
+ char *trigger;
+ int ret;
+
+ if (AR_SREV_9287(priv->ah))
+ priv->ah->led_pin = ATH_LED_PIN_9287;
+ else if (AR_SREV_9271(priv->ah))
+ priv->ah->led_pin = ATH_LED_PIN_9271;
+ else if (AR_DEVID_7010(priv->ah))
+ priv->ah->led_pin = ATH_LED_PIN_7010;
+ else
+ priv->ah->led_pin = ATH_LED_PIN_DEF;
+
+ /* Configure gpio 1 for output */
+ ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ /* LED off, active low */
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
+
+ INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
+
+ trigger = ieee80211_get_radio_led_name(priv->hw);
+ snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
+ "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
+ ret = ath9k_register_led(priv, &priv->radio_led, trigger);
+ priv->radio_led.led_type = ATH_LED_RADIO;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_assoc_led_name(priv->hw);
+ snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
+ "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
+ ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
+ priv->assoc_led.led_type = ATH_LED_ASSOC;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_tx_led_name(priv->hw);
+ snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
+ "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
+ ret = ath9k_register_led(priv, &priv->tx_led, trigger);
+ priv->tx_led.led_type = ATH_LED_TX;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_rx_led_name(priv->hw);
+ snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
+ "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
+ ret = ath9k_register_led(priv, &priv->rx_led, trigger);
+ priv->rx_led.led_type = ATH_LED_RX;
+ if (ret)
+ goto fail;
+
+ priv->op_flags &= ~OP_LED_DEINIT;
+
+ return;
+
+fail:
+ cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+ ath9k_deinit_leds(priv);
+}
+
+/*******************/
+/* Rfkill */
+/*******************/
+
+static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
+{
+ return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
+ priv->ah->rfkill_polarity;
+}
+
+void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ bool blocked = !!ath_is_rfkill_set(priv);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+
+void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
+{
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ wiphy_rfkill_start_polling(priv->hw->wiphy);
+}
+
+void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
+ if (ret) {
+ ath_err(common,
+ "Unable to reset hardware; reset status %d (freq %u MHz)\n",
+ ret, ah->curchan->channel);
+ }
+
+ ath_update_txpow(priv);
+
+ /* Start RX */
+ WMI_CMD(WMI_START_RECV_CMDID);
+ ath9k_host_rx_init(priv);
+
+ /* Start TX */
+ htc_start(priv->htc);
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_queues_stop = false;
+ spin_unlock_bh(&priv->tx_lock);
+ ieee80211_wake_queues(hw);
+
+ WMI_CMD(WMI_ENABLE_INTR_CMDID);
+
+ /* Enable LED */
+ ath9k_hw_cfg_output(ah, ah->led_pin,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+}
+
+void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ ath9k_htc_ps_wakeup(priv);
+
+ /* Disable LED */
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+
+ WMI_CMD(WMI_DISABLE_INTR_CMDID);
+
+ /* Stop TX */
+ ieee80211_stop_queues(hw);
+ htc_stop(priv->htc);
+ WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+ skb_queue_purge(&priv->tx_queue);
+
+ /* Stop RX */
+ WMI_CMD(WMI_STOP_RECV_CMDID);
+
+ /*
+ * The MIB counters have to be disabled here,
+ * since the target doesn't do it.
+ */
+ ath9k_hw_disable_mib_counters(ah);
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
+ if (ret) {
+ ath_err(common,
+ "Unable to reset hardware; reset status %d (freq %u MHz)\n",
+ ret, ah->curchan->channel);
+ }
+
+ /* Disable the PHY */
+ ath9k_hw_phy_disable(ah);
+
+ ath9k_htc_ps_restore(priv);
+ ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 3d7b97f1b3ae..38433f9bfe59 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -142,7 +142,7 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{
ath9k_htc_exit_debug(priv->ah);
ath9k_hw_deinit(priv->ah);
- tasklet_kill(&priv->wmi_tasklet);
+ tasklet_kill(&priv->swba_tasklet);
tasklet_kill(&priv->rx_tasklet);
tasklet_kill(&priv->tx_tasklet);
kfree(priv->ah);
@@ -181,7 +181,8 @@ static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
return htc_connect_service(priv->htc, &req, ep_id);
}
-static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
+static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
+ u32 drv_info)
{
int ret;
@@ -245,15 +246,10 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
* the HIF layer, shouldn't matter much.
*/
- switch(devid) {
- case 0x7010:
- case 0x7015:
- case 0x9018:
+ if (IS_AR7010_DEVICE(drv_info))
priv->htc->credits = 45;
- break;
- default:
+ else
priv->htc->credits = 33;
- }
ret = htc_init(priv->htc);
if (ret)
@@ -292,9 +288,9 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
(u8 *) &val, sizeof(val),
100);
if (unlikely(r)) {
- ath_print(common, ATH_DBG_WMI,
- "REGISTER READ FAILED: (0x%04x, %d)\n",
- reg_offset, r);
+ ath_dbg(common, ATH_DBG_WMI,
+ "REGISTER READ FAILED: (0x%04x, %d)\n",
+ reg_offset, r);
return -EIO;
}
@@ -306,7 +302,7 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
- __be32 buf[2] = {
+ const __be32 buf[2] = {
cpu_to_be32(reg_offset),
cpu_to_be32(val),
};
@@ -317,9 +313,9 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
(u8 *) &val, sizeof(val),
100);
if (unlikely(r)) {
- ath_print(common, ATH_DBG_WMI,
- "REGISTER WRITE FAILED:(0x%04x, %d)\n",
- reg_offset, r);
+ ath_dbg(common, ATH_DBG_WMI,
+ "REGISTER WRITE FAILED:(0x%04x, %d)\n",
+ reg_offset, r);
}
}
@@ -349,9 +345,9 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
(u8 *) &rsp_status, sizeof(rsp_status),
100);
if (unlikely(r)) {
- ath_print(common, ATH_DBG_WMI,
- "REGISTER WRITE FAILED, multi len: %d\n",
- priv->wmi->multi_write_idx);
+ ath_dbg(common, ATH_DBG_WMI,
+ "REGISTER WRITE FAILED, multi len: %d\n",
+ priv->wmi->multi_write_idx);
}
priv->wmi->multi_write_idx = 0;
}
@@ -399,9 +395,9 @@ static void ath9k_regwrite_flush(void *hw_priv)
(u8 *) &rsp_status, sizeof(rsp_status),
100);
if (unlikely(r)) {
- ath_print(common, ATH_DBG_WMI,
- "REGISTER WRITE FAILED, multi len: %d\n",
- priv->wmi->multi_write_idx);
+ ath_dbg(common, ATH_DBG_WMI,
+ "REGISTER WRITE FAILED, multi len: %d\n",
+ priv->wmi->multi_write_idx);
}
priv->wmi->multi_write_idx = 0;
}
@@ -473,9 +469,9 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv,
tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
- ath_print(common, ATH_DBG_CONFIG,
- "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
if (tx_streams != rx_streams) {
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
@@ -499,37 +495,31 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
if (priv->beaconq == -1) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup BEACON xmit queue\n");
+ ath_err(common, "Unable to setup BEACON xmit queue\n");
goto err;
}
priv->cabq = ath9k_htc_cabq_setup(priv);
if (priv->cabq == -1) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup CAB xmit queue\n");
+ ath_err(common, "Unable to setup CAB xmit queue\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BE traffic\n");
+ ath_err(common, "Unable to setup xmit queue for BE traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BK traffic\n");
+ ath_err(common, "Unable to setup xmit queue for BK traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VI traffic\n");
+ ath_err(common, "Unable to setup xmit queue for VI traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VO traffic\n");
+ ath_err(common, "Unable to setup xmit queue for VO traffic\n");
goto err;
}
@@ -547,9 +537,9 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
/* Get the hardware key cache size. */
common->keymax = priv->ah->caps.keycache_size;
if (common->keymax > ATH_KEYMAX) {
- ath_print(common, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, common->keymax);
+ ath_dbg(common, ATH_DBG_ANY,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, common->keymax);
common->keymax = ATH_KEYMAX;
}
@@ -625,7 +615,8 @@ static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
}
static int ath9k_init_priv(struct ath9k_htc_priv *priv,
- u16 devid, char *product)
+ u16 devid, char *product,
+ u32 drv_info)
{
struct ath_hw *ah = NULL;
struct ath_common *common;
@@ -639,6 +630,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
ah->hw_version.devid = devid;
ah->hw_version.subsysid = 0; /* FIXME */
+ ah->hw_version.usbdev = drv_info;
+ ah->ah_flags |= AH_USE_EEPROM;
priv->ah = ah;
common = ath9k_hw_common(ah);
@@ -654,13 +647,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
spin_lock_init(&priv->tx_lock);
mutex_init(&priv->mutex);
mutex_init(&priv->htc_pm_lock);
- tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
+ tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
(unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv);
- tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
+ tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+ (unsigned long)priv);
INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work);
+ INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
/*
* Cache line size is used to size and align various
@@ -671,16 +666,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
ret = ath9k_hw_init(ah);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to initialize hardware; "
- "initialization status: %d\n", ret);
+ ath_err(common,
+ "Unable to initialize hardware; initialization status: %d\n",
+ ret);
goto err_hw;
}
ret = ath9k_htc_init_debug(ah);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to create debugfs files\n");
+ ath_err(common, "Unable to create debugfs files\n");
goto err_debug;
}
@@ -760,7 +754,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
}
static int ath9k_init_device(struct ath9k_htc_priv *priv,
- u16 devid, char *product)
+ u16 devid, char *product, u32 drv_info)
{
struct ieee80211_hw *hw = priv->hw;
struct ath_common *common;
@@ -769,7 +763,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
struct ath_regulatory *reg;
/* Bring up device */
- error = ath9k_init_priv(priv, devid, product);
+ error = ath9k_init_priv(priv, devid, product, drv_info);
if (error != 0)
goto err_init;
@@ -827,7 +821,7 @@ err_init:
}
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
- u16 devid, char *product)
+ u16 devid, char *product, u32 drv_info)
{
struct ieee80211_hw *hw;
struct ath9k_htc_priv *priv;
@@ -854,14 +848,11 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
goto err_free;
}
- ret = ath9k_init_htc_services(priv, devid);
+ ret = ath9k_init_htc_services(priv, devid, drv_info);
if (ret)
goto err_init;
- /* The device may have been unplugged earlier. */
- priv->op_flags &= ~OP_UNPLUGGED;
-
- ret = ath9k_init_device(priv, devid, product);
+ ret = ath9k_init_device(priv, devid, product, drv_info);
if (ret)
goto err_init;
@@ -880,7 +871,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
/* Check if the device has been yanked out. */
if (hotunplug)
- htc_handle->drv_priv->op_flags |= OP_UNPLUGGED;
+ htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(htc_handle->drv_priv);
ath9k_deinit_wmi(htc_handle->drv_priv);
@@ -889,16 +880,23 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
}
#ifdef CONFIG_PM
+
+void ath9k_htc_suspend(struct htc_target *htc_handle)
+{
+ ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
+}
+
int ath9k_htc_resume(struct htc_target *htc_handle)
{
+ struct ath9k_htc_priv *priv = htc_handle->drv_priv;
int ret;
- ret = ath9k_htc_wait_for_target(htc_handle->drv_priv);
+ ret = ath9k_htc_wait_for_target(priv);
if (ret)
return ret;
- ret = ath9k_init_htc_services(htc_handle->drv_priv,
- htc_handle->drv_priv->ah->hw_version.devid);
+ ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
+ priv->ah->hw_version.usbdev);
return ret;
}
#endif
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9a3be8da755d..f4d576bc3ccd 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -24,12 +24,12 @@ static struct dentry *ath9k_debugfs_root;
/* Utilities */
/*************/
-static void ath_update_txpow(struct ath9k_htc_priv *priv)
+void ath_update_txpow(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
if (priv->curtxpow != priv->txpowlimit) {
- ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
+ ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false);
/* read back in case value is clamped */
priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
}
@@ -63,8 +63,8 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
return mode;
}
-static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
- enum ath9k_power_mode mode)
+bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+ enum ath9k_power_mode mode)
{
bool ret;
@@ -116,6 +116,60 @@ void ath9k_ps_work(struct work_struct *work)
ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
}
+void ath9k_htc_reset(struct ath9k_htc_priv *priv)
+{
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_channel *channel = priv->hw->conf.channel;
+ struct ath9k_hw_cal_data *caldata;
+ enum htc_phymode mode;
+ __be16 htc_mode;
+ u8 cmd_rsp;
+ int ret;
+
+ mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+
+ if (priv->op_flags & OP_ASSOCIATED)
+ cancel_delayed_work_sync(&priv->ath9k_ani_work);
+
+ ieee80211_stop_queues(priv->hw);
+ htc_stop(priv->htc);
+ WMI_CMD(WMI_DISABLE_INTR_CMDID);
+ WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+ WMI_CMD(WMI_STOP_RECV_CMDID);
+
+ caldata = &priv->caldata[channel->hw_value];
+ ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
+ if (ret) {
+ ath_err(common,
+ "Unable to reset device (%u Mhz) reset status %d\n",
+ channel->center_freq, ret);
+ }
+
+ ath_update_txpow(priv);
+
+ WMI_CMD(WMI_START_RECV_CMDID);
+ ath9k_host_rx_init(priv);
+
+ mode = ath9k_htc_get_curmode(priv, ah->curchan);
+ htc_mode = cpu_to_be16(mode);
+ WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
+
+ WMI_CMD(WMI_ENABLE_INTR_CMDID);
+ htc_start(priv->htc);
+
+ if (priv->op_flags & OP_ASSOCIATED) {
+ ath9k_htc_beacon_config(priv, priv->vif);
+ ath_start_ani(priv);
+ }
+
+ ieee80211_wake_queues(priv->hw);
+
+ ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
+}
+
static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw,
struct ath9k_channel *hchan)
@@ -123,7 +177,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
- bool fastcc = true;
+ bool fastcc;
struct ieee80211_channel *channel = hw->conf.channel;
struct ath9k_hw_cal_data *caldata;
enum htc_phymode mode;
@@ -134,8 +188,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (priv->op_flags & OP_INVALID)
return -EIO;
- if (priv->op_flags & OP_FULL_RESET)
- fastcc = false;
+ fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
@@ -143,18 +196,18 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
- ath_print(common, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
- priv->ah->curchan->channel,
- channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
- fastcc);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
+ priv->ah->curchan->channel,
+ channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
+ fastcc);
caldata = &priv->caldata[channel->hw_value];
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset channel (%u Mhz) "
- "reset status %d\n", channel->center_freq, ret);
+ ath_err(common,
+ "Unable to reset channel (%u Mhz) reset status %d\n",
+ channel->center_freq, ret);
goto err;
}
@@ -177,23 +230,43 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
goto err;
htc_start(priv->htc);
-
- priv->op_flags &= ~OP_FULL_RESET;
err:
ath9k_htc_ps_restore(priv);
return ret;
}
+static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_vif hvif;
+ int ret = 0;
+ u8 cmd_rsp;
+
+ memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+ memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
+ hvif.index = 0; /* Should do for now */
+ WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+ priv->nvifs--;
+}
+
static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_target_vif hvif;
+ struct ath9k_htc_target_sta tsta;
int ret = 0;
u8 cmd_rsp;
if (priv->nvifs > 0)
return -ENOBUFS;
+ if (priv->nstations >= ATH9K_HTC_MAX_STA)
+ return -ENOBUFS;
+
+ /*
+ * Add an interface.
+ */
+
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
@@ -206,23 +279,68 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
return ret;
priv->nvifs++;
+
+ /*
+ * Associate a station with the interface for packet injection.
+ */
+
+ memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
+
+ memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN);
+
+ tsta.is_vif_sta = 1;
+ tsta.sta_index = priv->nstations;
+ tsta.vif_index = hvif.index;
+ tsta.maxampdu = 0xffff;
+
+ WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
+ if (ret) {
+ ath_err(common, "Unable to add station entry for monitor mode\n");
+ goto err_vif;
+ }
+
+ priv->nstations++;
+
+ /*
+ * Set chainmask etc. on the target.
+ */
+ ret = ath9k_htc_update_cap_target(priv);
+ if (ret)
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Failed to update capability in target\n");
+
+ priv->ah->is_monitoring = true;
+
return 0;
+
+err_vif:
+ /*
+ * Remove the interface from the target.
+ */
+ __ath9k_htc_remove_monitor_interface(priv);
+ return ret;
}
static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- struct ath9k_htc_target_vif hvif;
int ret = 0;
- u8 cmd_rsp;
+ u8 cmd_rsp, sta_idx;
- memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
- memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
- hvif.index = 0; /* Should do for now */
- WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
- priv->nvifs--;
+ __ath9k_htc_remove_monitor_interface(priv);
- return ret;
+ sta_idx = 0; /* Only single interface, for now */
+
+ WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
+ if (ret) {
+ ath_err(common, "Unable to remove station entry for monitor mode\n");
+ return ret;
+ }
+
+ priv->nstations--;
+ priv->ah->is_monitoring = false;
+
+ return 0;
}
static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
@@ -263,15 +381,16 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) {
if (sta)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to add station entry for: %pM\n", sta->addr);
+ ath_err(common,
+ "Unable to add station entry for: %pM\n",
+ sta->addr);
return ret;
}
if (sta)
- ath_print(common, ATH_DBG_CONFIG,
- "Added a station entry for: %pM (idx: %d)\n",
- sta->addr, tsta.sta_index);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Added a station entry for: %pM (idx: %d)\n",
+ sta->addr, tsta.sta_index);
priv->nstations++;
return 0;
@@ -296,22 +415,22 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
if (ret) {
if (sta)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to remove station entry for: %pM\n",
- sta->addr);
+ ath_err(common,
+ "Unable to remove station entry for: %pM\n",
+ sta->addr);
return ret;
}
if (sta)
- ath_print(common, ATH_DBG_CONFIG,
- "Removed a station entry for: %pM (idx: %d)\n",
- sta->addr, sta_idx);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Removed a station entry for: %pM (idx: %d)\n",
+ sta->addr, sta_idx);
priv->nstations--;
return 0;
}
-static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
{
struct ath9k_htc_cap_target tcap;
int ret;
@@ -390,8 +509,8 @@ static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to initialize Rate information on target\n");
+ ath_err(common,
+ "Unable to initialize Rate information on target\n");
}
return ret;
@@ -408,9 +527,9 @@ static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
ath9k_htc_setup_rate(priv, sta, &trate);
ret = ath9k_htc_send_rate_cmd(priv, &trate);
if (!ret)
- ath_print(common, ATH_DBG_CONFIG,
- "Updated target sta: %pM, rate caps: 0x%X\n",
- sta->addr, be32_to_cpu(trate.capflags));
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ sta->addr, be32_to_cpu(trate.capflags));
}
static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
@@ -435,9 +554,9 @@ static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
ret = ath9k_htc_send_rate_cmd(priv, &trate);
if (!ret)
- ath_print(common, ATH_DBG_CONFIG,
- "Updated target sta: %pM, rate caps: 0x%X\n",
- bss_conf->bssid, be32_to_cpu(trate.capflags));
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ bss_conf->bssid, be32_to_cpu(trate.capflags));
}
static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
@@ -464,14 +583,14 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
if (ret)
- ath_print(common, ATH_DBG_CONFIG,
- "Unable to %s TX aggregation for (%pM, %d)\n",
- (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Unable to %s TX aggregation for (%pM, %d)\n",
+ (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
else
- ath_print(common, ATH_DBG_CONFIG,
- "%s TX aggregation for (%pM, %d)\n",
- (aggr.aggr_enable) ? "Starting" : "Stopping",
- sta->addr, tid);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "%s TX aggregation for (%pM, %d)\n",
+ (aggr.aggr_enable) ? "Starting" : "Stopping",
+ sta->addr, tid);
spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
@@ -689,7 +808,7 @@ void ath9k_htc_debug_remove_root(void)
/* ANI */
/*******/
-static void ath_start_ani(struct ath9k_htc_priv *priv)
+void ath_start_ani(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
unsigned long timestamp = jiffies_to_msecs(jiffies);
@@ -724,7 +843,7 @@ void ath9k_ani_work(struct work_struct *work)
/* Long calibration runs independently of short calibration. */
if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
- ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+ ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
common->ani.longcal_timer = timestamp;
}
@@ -733,8 +852,8 @@ void ath9k_ani_work(struct work_struct *work)
if ((timestamp - common->ani.shortcal_timer) >=
short_cal_interval) {
shortcal = true;
- ath_print(common, ATH_DBG_ANI,
- "shortcal @%lu\n", jiffies);
+ ath_dbg(common, ATH_DBG_ANI,
+ "shortcal @%lu\n", jiffies);
common->ani.shortcal_timer = timestamp;
common->ani.resetcal_timer = timestamp;
}
@@ -788,317 +907,6 @@ set_timer:
msecs_to_jiffies(cal_interval));
}
-/*******/
-/* LED */
-/*******/
-
-static void ath9k_led_blink_work(struct work_struct *work)
-{
- struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
- ath9k_led_blink_work.work);
-
- if (!(priv->op_flags & OP_LED_ASSOCIATED))
- return;
-
- if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
- (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
- else
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
- (priv->op_flags & OP_LED_ON) ? 1 : 0);
-
- ieee80211_queue_delayed_work(priv->hw,
- &priv->ath9k_led_blink_work,
- (priv->op_flags & OP_LED_ON) ?
- msecs_to_jiffies(priv->led_off_duration) :
- msecs_to_jiffies(priv->led_on_duration));
-
- priv->led_on_duration = priv->led_on_cnt ?
- max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
- ATH_LED_ON_DURATION_IDLE;
- priv->led_off_duration = priv->led_off_cnt ?
- max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
- ATH_LED_OFF_DURATION_IDLE;
- priv->led_on_cnt = priv->led_off_cnt = 0;
-
- if (priv->op_flags & OP_LED_ON)
- priv->op_flags &= ~OP_LED_ON;
- else
- priv->op_flags |= OP_LED_ON;
-}
-
-static void ath9k_led_brightness_work(struct work_struct *work)
-{
- struct ath_led *led = container_of(work, struct ath_led,
- brightness_work.work);
- struct ath9k_htc_priv *priv = led->priv;
-
- switch (led->brightness) {
- case LED_OFF:
- if (led->led_type == ATH_LED_ASSOC ||
- led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
- (led->led_type == ATH_LED_RADIO));
- priv->op_flags &= ~OP_LED_ASSOCIATED;
- if (led->led_type == ATH_LED_RADIO)
- priv->op_flags &= ~OP_LED_ON;
- } else {
- priv->led_off_cnt++;
- }
- break;
- case LED_FULL:
- if (led->led_type == ATH_LED_ASSOC) {
- priv->op_flags |= OP_LED_ASSOCIATED;
- ieee80211_queue_delayed_work(priv->hw,
- &priv->ath9k_led_blink_work, 0);
- } else if (led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
- priv->op_flags |= OP_LED_ON;
- } else {
- priv->led_on_cnt++;
- }
- break;
- default:
- break;
- }
-}
-
-static void ath9k_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
- struct ath9k_htc_priv *priv = led->priv;
-
- led->brightness = brightness;
- if (!(priv->op_flags & OP_LED_DEINIT))
- ieee80211_queue_delayed_work(priv->hw,
- &led->brightness_work, 0);
-}
-
-static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
-{
- cancel_delayed_work_sync(&priv->radio_led.brightness_work);
- cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
- cancel_delayed_work_sync(&priv->tx_led.brightness_work);
- cancel_delayed_work_sync(&priv->rx_led.brightness_work);
-}
-
-static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
- char *trigger)
-{
- int ret;
-
- led->priv = priv;
- led->led_cdev.name = led->name;
- led->led_cdev.default_trigger = trigger;
- led->led_cdev.brightness_set = ath9k_led_brightness;
-
- ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
- if (ret)
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
- "Failed to register led:%s", led->name);
- else
- led->registered = 1;
-
- INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
-
- return ret;
-}
-
-static void ath9k_unregister_led(struct ath_led *led)
-{
- if (led->registered) {
- led_classdev_unregister(&led->led_cdev);
- led->registered = 0;
- }
-}
-
-void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
-{
- priv->op_flags |= OP_LED_DEINIT;
- ath9k_unregister_led(&priv->assoc_led);
- priv->op_flags &= ~OP_LED_ASSOCIATED;
- ath9k_unregister_led(&priv->tx_led);
- ath9k_unregister_led(&priv->rx_led);
- ath9k_unregister_led(&priv->radio_led);
-}
-
-void ath9k_init_leds(struct ath9k_htc_priv *priv)
-{
- char *trigger;
- int ret;
-
- if (AR_SREV_9287(priv->ah))
- priv->ah->led_pin = ATH_LED_PIN_9287;
- else if (AR_SREV_9271(priv->ah))
- priv->ah->led_pin = ATH_LED_PIN_9271;
- else if (AR_DEVID_7010(priv->ah))
- priv->ah->led_pin = ATH_LED_PIN_7010;
- else
- priv->ah->led_pin = ATH_LED_PIN_DEF;
-
- /* Configure gpio 1 for output */
- ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- /* LED off, active low */
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
-
- INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
- "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->radio_led, trigger);
- priv->radio_led.led_type = ATH_LED_RADIO;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
- "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
- priv->assoc_led.led_type = ATH_LED_ASSOC;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
- "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->tx_led, trigger);
- priv->tx_led.led_type = ATH_LED_TX;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
- "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->rx_led, trigger);
- priv->rx_led.led_type = ATH_LED_RX;
- if (ret)
- goto fail;
-
- priv->op_flags &= ~OP_LED_DEINIT;
-
- return;
-
-fail:
- cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
- ath9k_deinit_leds(priv);
-}
-
-/*******************/
-/* Rfkill */
-/*******************/
-
-static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
-{
- return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
- priv->ah->rfkill_polarity;
-}
-
-static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
- bool blocked = !!ath_is_rfkill_set(priv);
-
- wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
-}
-
-void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
-{
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- wiphy_rfkill_start_polling(priv->hw->wiphy);
-}
-
-static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
- struct ath_hw *ah = priv->ah;
- struct ath_common *common = ath9k_hw_common(ah);
- int ret;
- u8 cmd_rsp;
-
- if (!ah->curchan)
- ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
-
- /* Reset the HW */
- ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
- if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", ret, ah->curchan->channel);
- }
-
- ath_update_txpow(priv);
-
- /* Start RX */
- WMI_CMD(WMI_START_RECV_CMDID);
- ath9k_host_rx_init(priv);
-
- /* Start TX */
- htc_start(priv->htc);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
- ieee80211_wake_queues(hw);
-
- WMI_CMD(WMI_ENABLE_INTR_CMDID);
-
- /* Enable LED */
- ath9k_hw_cfg_output(ah, ah->led_pin,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-}
-
-static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
- struct ath_hw *ah = priv->ah;
- struct ath_common *common = ath9k_hw_common(ah);
- int ret;
- u8 cmd_rsp;
-
- ath9k_htc_ps_wakeup(priv);
-
- /* Disable LED */
- ath9k_hw_set_gpio(ah, ah->led_pin, 1);
- ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-
- WMI_CMD(WMI_DISABLE_INTR_CMDID);
-
- /* Stop TX */
- ieee80211_stop_queues(hw);
- htc_stop(priv->htc);
- WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
- skb_queue_purge(&priv->tx_queue);
-
- /* Stop RX */
- WMI_CMD(WMI_STOP_RECV_CMDID);
-
- /*
- * The MIB counters have to be disabled here,
- * since the target doesn't do it.
- */
- ath9k_hw_disable_mib_counters(ah);
-
- if (!ah->curchan)
- ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
-
- /* Reset the HW */
- ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
- if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", ret, ah->curchan->channel);
- }
-
- /* Disable the PHY */
- ath9k_hw_phy_disable(ah);
-
- ath9k_htc_ps_restore(priv);
- ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
-}
-
/**********************/
/* mac80211 Callbacks */
/**********************/
@@ -1124,15 +932,15 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ret = ath9k_htc_tx_start(priv, skb);
if (ret != 0) {
if (ret == -ENOMEM) {
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Stopping TX queues\n");
+ ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Stopping TX queues\n");
ieee80211_stop_queues(hw);
spin_lock_bh(&priv->tx_lock);
priv->tx_queues_stop = true;
spin_unlock_bh(&priv->tx_lock);
} else {
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Tx failed");
+ ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Tx failed\n");
}
goto fail_tx;
}
@@ -1158,9 +966,9 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
mutex_lock(&priv->mutex);
- ath_print(common, ATH_DBG_CONFIG,
- "Starting driver with initial channel: %d MHz\n",
- curchan->center_freq);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Starting driver with initial channel: %d MHz\n",
+ curchan->center_freq);
/* Ensure that HW is awake before flushing RX */
ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
@@ -1169,15 +977,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
/* setup initial channel */
init_channel = ath9k_cmn_get_curchannel(hw, ah);
- /* Reset SERDES registers */
- ath9k_hw_configpcipowersave(ah, 0, 0);
-
ath9k_hw_htc_resetinit(ah);
ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", ret, curchan->center_freq);
+ ath_err(common,
+ "Unable to reset hardware; reset status %d (freq %u MHz)\n",
+ ret, curchan->center_freq);
mutex_unlock(&priv->mutex);
return ret;
}
@@ -1220,19 +1025,20 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
int ret = 0;
u8 cmd_rsp;
+ /* Cancel all the running timers/work .. */
+ cancel_work_sync(&priv->fatal_work);
+ cancel_work_sync(&priv->ps_work);
+ cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+ ath9k_led_stop_brightness(priv);
+
mutex_lock(&priv->mutex);
if (priv->op_flags & OP_INVALID) {
- ath_print(common, ATH_DBG_ANY, "Device not present\n");
+ ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&priv->mutex);
return;
}
- /* Cancel all the running timers/work .. */
- cancel_work_sync(&priv->ps_work);
- cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
- ath9k_led_stop_brightness(priv);
-
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
@@ -1243,11 +1049,10 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
/* Remove monitor interface here */
if (ah->opmode == NL80211_IFTYPE_MONITOR) {
if (ath9k_htc_remove_monitor_interface(priv))
- ath_print(common, ATH_DBG_FATAL,
- "Unable to remove monitor interface\n");
+ ath_err(common, "Unable to remove monitor interface\n");
else
- ath_print(common, ATH_DBG_CONFIG,
- "Monitor interface removed\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Monitor interface removed\n");
}
if (ah->btcoex_hw.enabled) {
@@ -1258,13 +1063,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
ath9k_hw_phy_disable(ah);
ath9k_hw_disable(ah);
- ath9k_hw_configpcipowersave(ah, 1, 1);
ath9k_htc_ps_restore(priv);
ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
priv->op_flags |= OP_INVALID;
- ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
mutex_unlock(&priv->mutex);
}
@@ -1298,14 +1102,14 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
hvif.opmode = cpu_to_be32(HTC_M_IBSS);
break;
default:
- ath_print(common, ATH_DBG_FATAL,
+ ath_err(common,
"Interface type %d not yet supported\n", vif->type);
ret = -EOPNOTSUPP;
goto out;
}
- ath_print(common, ATH_DBG_CONFIG,
- "Attach a VIF of type: %d\n", vif->type);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Attach a VIF of type: %d\n", vif->type);
priv->ah->opmode = vif->type;
@@ -1328,8 +1132,8 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
ret = ath9k_htc_update_cap_target(priv);
if (ret)
- ath_print(common, ATH_DBG_CONFIG, "Failed to update"
- " capability in target \n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Failed to update capability in target\n");
priv->vif = vif;
out:
@@ -1349,7 +1153,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
int ret = 0;
u8 cmd_rsp;
- ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
@@ -1386,30 +1190,46 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
mutex_unlock(&priv->htc_pm_lock);
if (enable_radio) {
- ath_print(common, ATH_DBG_CONFIG,
- "not-idle: enabling radio\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
ath9k_htc_radio_enable(hw);
}
}
+ /*
+ * Monitor interface should be added before
+ * IEEE80211_CONF_CHANGE_CHANNEL is handled.
+ */
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+ if (conf->flags & IEEE80211_CONF_MONITOR) {
+ if (ath9k_htc_add_monitor_interface(priv))
+ ath_err(common, "Failed to set monitor mode\n");
+ else
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "HW opmode set to Monitor mode\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
- ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
- curchan->center_freq);
+ ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ curchan->center_freq);
- ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
+ ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
+ hw->conf.channel,
+ hw->conf.channel_type);
if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to set channel\n");
+ ath_err(common, "Unable to set channel\n");
mutex_unlock(&priv->mutex);
return -EINVAL;
}
}
+
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
@@ -1421,15 +1241,9 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- if (conf->flags & IEEE80211_CONF_MONITOR) {
- if (ath9k_htc_add_monitor_interface(priv))
- ath_print(common, ATH_DBG_FATAL,
- "Failed to set monitor mode\n");
- else
- ath_print(common, ATH_DBG_CONFIG,
- "HW opmode set to Monitor mode\n");
- }
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ priv->txpowlimit = 2 * conf->power_level;
+ ath_update_txpow(priv);
}
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
@@ -1440,8 +1254,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
mutex_unlock(&priv->htc_pm_lock);
- ath_print(common, ATH_DBG_CONFIG,
- "idle: disabling radio\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "idle: disabling radio\n");
ath9k_htc_radio_disable(hw);
}
@@ -1478,8 +1292,8 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
rfilt = ath9k_htc_calcrxfilter(priv);
ath9k_hw_setrxfilter(priv->ah, rfilt);
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
- "Set HW RX filter: 0x%x\n", rfilt);
+ ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
+ "Set HW RX filter: 0x%x\n", rfilt);
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
@@ -1542,15 +1356,14 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
qnum = get_hw_qnum(queue, priv->hwq_map);
- ath_print(common, ATH_DBG_CONFIG,
- "Configure tx [queue/hwq] [%d/%d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- queue, qnum, params->aifs, params->cw_min,
- params->cw_max, params->txop);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Configure tx [queue/hwq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, qnum, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
ret = ath_htc_txq_update(priv, qnum, &qi);
if (ret) {
- ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+ ath_err(common, "TXQ Update failed\n");
goto out;
}
@@ -1578,7 +1391,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
return -ENOSPC;
mutex_lock(&priv->mutex);
- ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
ath9k_htc_ps_wakeup(priv);
switch (cmd) {
@@ -1624,7 +1437,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
common->curaid = bss_conf->assoc ?
bss_conf->aid : 0;
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc);
if (bss_conf->assoc) {
@@ -1641,9 +1454,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
ath9k_hw_write_associd(ah);
- ath_print(common, ATH_DBG_CONFIG,
- "BSSID: %pM aid: 0x%x\n",
- common->curbssid, common->curaid);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "BSSID: %pM aid: 0x%x\n",
+ common->curbssid, common->curaid);
}
if ((changed & BSS_CHANGED_BEACON_INT) ||
@@ -1661,8 +1474,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
- bss_conf->use_short_preamble);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
priv->op_flags |= OP_PREAMBLE_SHORT;
else
@@ -1670,8 +1483,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
- bss_conf->use_cts_prot);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
+ bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
priv->op_flags |= OP_PROTECT_ENABLE;
@@ -1762,8 +1575,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
spin_unlock_bh(&priv->tx_lock);
break;
default:
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
- "Unknown AMPDU action\n");
+ ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
}
return ret;
@@ -1792,7 +1604,6 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
spin_lock_bh(&priv->beacon_lock);
priv->op_flags &= ~OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
- priv->op_flags |= OP_FULL_RESET;
if (priv->op_flags & OP_ASSOCIATED) {
ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 3d19b5bc937f..33f36029fa4f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -20,8 +20,15 @@
/* TX */
/******/
+static const int subtype_txq_to_hwq[] = {
+ [WME_AC_BE] = ATH_TXQ_AC_BE,
+ [WME_AC_BK] = ATH_TXQ_AC_BK,
+ [WME_AC_VI] = ATH_TXQ_AC_VI,
+ [WME_AC_VO] = ATH_TXQ_AC_VO,
+};
+
#define ATH9K_HTC_INIT_TXQ(subtype) do { \
- qi.tqi_subtype = subtype; \
+ qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \
qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \
qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \
qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \
@@ -62,8 +69,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
qi.tqi_readyTime = qinfo->tqi_readyTime;
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Unable to update hardware queue %u!\n", qnum);
+ ath_err(ath9k_hw_common(ah),
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum);
@@ -121,7 +128,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
tx_hdr.data_type = ATH9K_HTC_NORMAL;
}
- if (ieee80211_is_data(fc)) {
+ if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
@@ -244,7 +251,7 @@ void ath9k_tx_tasklet(unsigned long data)
ista = (struct ath9k_htc_sta *)sta->drv_priv;
if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
- ieee80211_start_tx_ba_session(sta, tid);
+ ieee80211_start_tx_ba_session(sta, tid, 0);
spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = AGGR_PROGRESS;
spin_unlock_bh(&priv->tx_lock);
@@ -263,8 +270,8 @@ void ath9k_tx_tasklet(unsigned long data)
if (priv->tx_queues_stop) {
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Waking up TX queues\n");
+ ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Waking up TX queues\n");
ieee80211_wake_queues(priv->hw);
return;
}
@@ -289,8 +296,7 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
(ep_id == priv->data_vo_ep)) {
skb_pull(skb, sizeof(struct tx_frame_hdr));
} else {
- ath_print(common, ATH_DBG_FATAL,
- "Unsupported TX EPID: %d\n", ep_id);
+ ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
dev_kfree_skb_any(skb);
return;
}
@@ -330,9 +336,8 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
return false;
if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
- ath_print(common, ATH_DBG_FATAL,
- "qnum %u out of range, max %u!\n",
- qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map));
+ ath_err(common, "qnum %u out of range, max %zu!\n",
+ qnum, ARRAY_SIZE(priv->hwq_map));
ath9k_hw_releasetxqueue(ah, qnum);
return false;
}
@@ -483,8 +488,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
__le16 fc;
if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
- ath_print(common, ATH_DBG_FATAL,
- "Corrupted RX frame, dropping\n");
+ ath_err(common, "Corrupted RX frame, dropping\n");
goto rx_next;
}
@@ -492,10 +496,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
if (be16_to_cpu(rxstatus->rs_datalen) -
(skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Corrupted RX data len, dropping "
- "(dlen: %d, skblen: %d)\n",
- rxstatus->rs_datalen, skb->len);
+ ath_err(common,
+ "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n",
+ rxstatus->rs_datalen, skb->len);
goto rx_next;
}
@@ -678,8 +681,8 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
spin_unlock(&priv->rx.rxbuflock);
if (rxbuf == NULL) {
- ath_print(common, ATH_DBG_ANY,
- "No free RX buffer\n");
+ ath_dbg(common, ATH_DBG_ANY,
+ "No free RX buffer\n");
goto err;
}
@@ -721,8 +724,7 @@ int ath9k_rx_init(struct ath9k_htc_priv *priv)
for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
if (rxbuf == NULL) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to allocate RX buffers\n");
+ ath_err(common, "Unable to allocate RX buffers\n");
goto err;
}
list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 861ec9269309..c41ab8c30161 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -462,9 +462,10 @@ void ath9k_htc_hw_free(struct htc_target *htc)
}
int ath9k_htc_hw_init(struct htc_target *target,
- struct device *dev, u16 devid, char *product)
+ struct device *dev, u16 devid,
+ char *product, u32 drv_info)
{
- if (ath9k_htc_probe_device(target, dev, devid, product)) {
+ if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
printk(KERN_ERR "Failed to initialize the device\n");
return -ENODEV;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index 07b6509d5896..ecd018798c47 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -77,20 +77,6 @@ struct htc_config_pipe_msg {
u8 credits;
} __packed;
-struct htc_packet {
- void *pktcontext;
- u8 *buf;
- u8 *buf_payload;
- u32 buflen;
- u32 payload_len;
-
- int endpoint;
- int status;
-
- void *context;
- u32 reserved;
-};
-
struct htc_ep_callbacks {
void *priv;
void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok);
@@ -123,11 +109,6 @@ struct htc_endpoint {
#define HTC_CONTROL_BUFFER_SIZE \
(HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
-struct htc_control_buf {
- struct htc_packet htc_pkt;
- u8 buf[HTC_CONTROL_BUFFER_SIZE];
-};
-
#define HTC_OP_START_WAIT BIT(0)
#define HTC_OP_CONFIG_PIPE_CREDITS BIT(1)
@@ -239,7 +220,8 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
struct device *dev);
void ath9k_htc_hw_free(struct htc_target *htc);
int ath9k_htc_hw_init(struct htc_target *target,
- struct device *dev, u16 devid, char *product);
+ struct device *dev, u16 devid, char *product,
+ u32 drv_info);
void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
#endif /* HTC_HST_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 0a4ad348b699..c8f254fe0f0b 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -223,11 +223,6 @@ static inline void ath9k_hw_rfbus_done(struct ath_hw *ah)
return ath9k_hw_private_ops(ah)->rfbus_done(ah);
}
-static inline void ath9k_enable_rfkill(struct ath_hw *ah)
-{
- return ath9k_hw_private_ops(ah)->enable_rfkill(ah);
-}
-
static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah)
{
if (!ath9k_hw_private_ops(ah)->restore_chainmask)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index cc13ee117823..1afb8bb85756 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -54,13 +54,6 @@ static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
ath9k_hw_private_ops(ah)->init_mode_regs(ah);
}
-static bool ath9k_hw_macversion_supported(struct ath_hw *ah)
-{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-
- return priv_ops->macversion_supported(ah->hw_version.macVersion);
-}
-
static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -129,9 +122,9 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
udelay(AH_TIME_QUANTUM);
}
- ath_print(ath9k_hw_common(ah), ATH_DBG_ANY,
- "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
- timeout, reg, REG_READ(ah, reg), mask, val);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_ANY,
+ "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+ timeout, reg, REG_READ(ah, reg), mask, val);
return false;
}
@@ -211,8 +204,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
}
break;
default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Unknown phy %u (rate ix %u)\n", phy, rateix);
+ ath_err(ath9k_hw_common(ah),
+ "Unknown phy %u (rate ix %u)\n", phy, rateix);
txTime = 0;
break;
}
@@ -284,11 +277,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
static void ath9k_hw_disablepcie(struct ath_hw *ah)
{
- if (AR_SREV_9100(ah))
+ if (!AR_SREV_5416(ah))
return;
- ENABLE_REGWRITE_BUFFER(ah);
-
REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
@@ -300,8 +291,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
- REGWRITE_BUFFER_FLUSH(ah);
}
/* This should work for all families including legacy */
@@ -310,10 +299,9 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
u32 regAddr[2] = { AR_STA_ID0 };
u32 regHold[2];
- u32 patternData[4] = { 0x55555555,
- 0xaaaaaaaa,
- 0x66666666,
- 0x99999999 };
+ static const u32 patternData[4] = {
+ 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999
+ };
int i, j, loop_max;
if (!AR_SREV_9300_20_OR_LATER(ah)) {
@@ -332,11 +320,9 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (rdData != wrData) {
- ath_print(common, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != "
- "rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_err(common,
+ "address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -345,11 +331,9 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (wrData != rdData) {
- ath_print(common, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != "
- "rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_err(common,
+ "address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -419,17 +403,12 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->hw_version.magic = AR5416_MAGIC;
ah->hw_version.subvendorid = 0;
- ah->ah_flags = 0;
- if (!AR_SREV_9100(ah))
- ah->ah_flags = AH_USE_EEPROM;
-
ah->atim_window = 0;
ah->sta_id1_defaults =
AR_STA_ID1_CRPT_MIC_ENABLE |
AR_STA_ID1_MCAST_KSRCH;
- ah->beacon_interval = 100;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
- ah->slottime = (u32) -1;
+ ah->slottime = 20;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
}
@@ -440,7 +419,7 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
u32 sum;
int i;
u16 eeval;
- u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
+ static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
sum = 0;
for (i = 0; i < 3; i++) {
@@ -457,9 +436,10 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
static int ath9k_hw_post_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int ecode;
- if (!AR_SREV_9271(ah)) {
+ if (common->bus_ops->ath_bus_type != ATH_USB) {
if (!ath9k_hw_chip_test(ah))
return -ENODEV;
}
@@ -474,16 +454,16 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
if (ecode != 0)
return ecode;
- ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG,
- "Eeprom VER: %d, REV: %d\n",
- ah->eep_ops->get_eeprom_ver(ah),
- ah->eep_ops->get_eeprom_rev(ah));
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CONFIG,
+ "Eeprom VER: %d, REV: %d\n",
+ ah->eep_ops->get_eeprom_ver(ah),
+ ah->eep_ops->get_eeprom_rev(ah));
ecode = ath9k_hw_rf_alloc_ext_banks(ah);
if (ecode) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Failed allocating banks for "
- "external radio\n");
+ ath_err(ath9k_hw_common(ah),
+ "Failed allocating banks for external radio\n");
+ ath9k_hw_rf_free_ext_banks(ah);
return ecode;
}
@@ -513,8 +493,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ah->hw_version.macVersion = AR_SREV_VERSION_9100;
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- ath_print(common, ATH_DBG_FATAL,
- "Couldn't reset chip\n");
+ ath_err(common, "Couldn't reset chip\n");
return -EIO;
}
@@ -524,7 +503,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ath9k_hw_attach_ops(ah);
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ ath_err(common, "Couldn't wakeup chip\n");
return -EIO;
}
@@ -540,7 +519,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
}
}
- ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ath_dbg(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
ah->config.serialize_regmode);
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
@@ -548,11 +527,22 @@ static int __ath9k_hw_init(struct ath_hw *ah)
else
ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
- if (!ath9k_hw_macversion_supported(ah)) {
- ath_print(common, ATH_DBG_FATAL,
- "Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", ah->hw_version.macVersion,
- ah->hw_version.macRev);
+ switch (ah->hw_version.macVersion) {
+ case AR_SREV_VERSION_5416_PCI:
+ case AR_SREV_VERSION_5416_PCIE:
+ case AR_SREV_VERSION_9160:
+ case AR_SREV_VERSION_9100:
+ case AR_SREV_VERSION_9280:
+ case AR_SREV_VERSION_9285:
+ case AR_SREV_VERSION_9287:
+ case AR_SREV_VERSION_9271:
+ case AR_SREV_VERSION_9300:
+ case AR_SREV_VERSION_9485:
+ break;
+ default:
+ ath_err(common,
+ "Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
+ ah->hw_version.macVersion, ah->hw_version.macRev);
return -EOPNOTSUPP;
}
@@ -598,8 +588,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
r = ath9k_hw_init_macaddr(ah);
if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Failed to initialize MAC address\n");
+ ath_err(common, "Failed to initialize MAC address\n");
return r;
}
@@ -633,21 +622,21 @@ int ath9k_hw_init(struct ath_hw *ah)
case AR9287_DEVID_PCIE:
case AR2427_DEVID_PCIE:
case AR9300_DEVID_PCIE:
+ case AR9300_DEVID_AR9485_PCIE:
break;
default:
if (common->bus_ops->ath_bus_type == ATH_USB)
break;
- ath_print(common, ATH_DBG_FATAL,
- "Hardware device ID 0x%04x not supported\n",
- ah->hw_version.devid);
+ ath_err(common, "Hardware device ID 0x%04x not supported\n",
+ ah->hw_version.devid);
return -EOPNOTSUPP;
}
ret = __ath9k_hw_init(ah);
if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to initialize hardware; "
- "initialization status: %d\n", ret);
+ ath_err(common,
+ "Unable to initialize hardware; initialization status: %d\n",
+ ret);
return ret;
}
@@ -679,7 +668,12 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
static void ath9k_hw_init_pll(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- u32 pll = ath9k_hw_compute_pll_control(ah, chan);
+ u32 pll;
+
+ if (AR_SREV_9485(ah))
+ REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
+
+ pll = ath9k_hw_compute_pll_control(ah, chan);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
@@ -771,8 +765,8 @@ static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
{
if (tu > 0xFFFF) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
- "bad global tx timeout %u\n", tu);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT,
+ "bad global tx timeout %u\n", tu);
ah->globaltxtimeout = (u32) -1;
return false;
} else {
@@ -789,8 +783,8 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
int slottime;
int sifstime;
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
- ah->misc_mode);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
+ ah->misc_mode);
if (ah->misc_mode != 0)
REG_WRITE(ah, AR_PCU_MISC,
@@ -815,7 +809,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ)
acktimeout += 64 - sifstime - ah->slottime;
- ath9k_hw_setslottime(ah, slottime);
+ ath9k_hw_setslottime(ah, ah->slottime);
ath9k_hw_set_ack_timeout(ah, acktimeout);
ath9k_hw_set_cts_timeout(ah, acktimeout);
if (ah->globaltxtimeout != (u32) -1)
@@ -952,9 +946,12 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
break;
case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_MONITOR:
REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
break;
+ default:
+ if (ah->is_monitoring)
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+ break;
}
}
@@ -1030,8 +1027,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
REG_WRITE(ah, AR_RTC_RC, 0);
if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "RTC stuck in MAC reset\n");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC stuck in MAC reset\n");
return false;
}
@@ -1077,8 +1074,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
AR_RTC_STATUS_M,
AR_RTC_STATUS_ON,
AH_WAIT_TIMEOUT)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "RTC not waking up\n");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC not waking up\n");
return false;
}
@@ -1138,16 +1135,14 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) {
- ath_print(common, ATH_DBG_QUEUE,
- "Transmit frames pending on "
- "queue %d\n", qnum);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Transmit frames pending on queue %d\n", qnum);
return false;
}
}
if (!ath9k_hw_rfbus_req(ah)) {
- ath_print(common, ATH_DBG_FATAL,
- "Could not kill baseband RX\n");
+ ath_err(common, "Could not kill baseband RX\n");
return false;
}
@@ -1155,8 +1150,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
r = ath9k_hw_rf_set_freq(ah, chan);
if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Failed to set channel\n");
+ ath_err(common, "Failed to set channel\n");
return false;
}
ath9k_hw_set_clockrate(ah);
@@ -1166,7 +1160,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit));
+ (u32) regulatory->power_limit), false);
ath9k_hw_rfbus_done(ah);
@@ -1220,10 +1214,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ah->txchainmask = common->tx_chainmask;
ah->rxchainmask = common->rx_chainmask;
- if (!ah->chip_fullsleep) {
+ if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) {
ath9k_hw_abortpcurecv(ah);
if (!ath9k_hw_stopdmarecv(ah)) {
- ath_print(common, ATH_DBG_XMIT,
+ ath_dbg(common, ATH_DBG_XMIT,
"Failed to stop receive dma\n");
bChannelChange = false;
}
@@ -1279,6 +1273,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_mark_phy_inactive(ah);
+ ah->paprd_table_write_done = false;
+
/* Only required on the first reset */
if (AR_SREV_9271(ah) && ah->htc_reset_init) {
REG_WRITE(ah,
@@ -1288,7 +1284,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
if (!ath9k_hw_chip_reset(ah, chan)) {
- ath_print(common, ATH_DBG_FATAL, "Chip reset failed\n");
+ ath_err(common, "Chip reset failed\n");
return -EINVAL;
}
@@ -1390,7 +1386,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_qos(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- ath9k_enable_rfkill(ah);
+ ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
ath9k_hw_init_global_settings(ah);
@@ -1435,13 +1431,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 mask;
mask = REG_READ(ah, AR_CFG);
if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
- ath_print(common, ATH_DBG_RESET,
+ ath_dbg(common, ATH_DBG_RESET,
"CFG Byte Swap Set 0x%x\n", mask);
} else {
mask =
INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
REG_WRITE(ah, AR_CFG, mask);
- ath_print(common, ATH_DBG_RESET,
+ ath_dbg(common, ATH_DBG_RESET,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
@@ -1569,9 +1565,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
AR_RTC_FORCE_WAKE_EN);
}
if (i == 0) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Failed to wakeup in %uus\n",
- POWER_UP_TIME / 20);
+ ath_err(ath9k_hw_common(ah),
+ "Failed to wakeup in %uus\n",
+ POWER_UP_TIME / 20);
return false;
}
}
@@ -1595,8 +1591,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
if (ah->power_mode == mode)
return status;
- ath_print(common, ATH_DBG_RESET, "%s -> %s\n",
- modes[ah->power_mode], modes[mode]);
+ ath_dbg(common, ATH_DBG_RESET, "%s -> %s\n",
+ modes[ah->power_mode], modes[mode]);
switch (mode) {
case ATH9K_PM_AWAKE:
@@ -1610,12 +1606,20 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
ath9k_set_power_network_sleep(ah, setChip);
break;
default:
- ath_print(common, ATH_DBG_FATAL,
- "Unknown power mode %u\n", mode);
+ ath_err(common, "Unknown power mode %u\n", mode);
return false;
}
ah->power_mode = mode;
+ /*
+ * XXX: If this warning never comes up after a while then
+ * simply keep the ATH_DBG_WARN_ON_ONCE() but make
+ * ath9k_hw_setpower() return type void.
+ */
+
+ if (!(ah->ah_flags & AH_UNPLUGGED))
+ ATH_DBG_WARN_ON_ONCE(!status);
+
return status;
}
EXPORT_SYMBOL(ath9k_hw_setpower);
@@ -1628,18 +1632,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
{
int flags = 0;
- ah->beacon_interval = beacon_period;
-
ENABLE_REGWRITE_BUFFER(ah);
switch (ah->opmode) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_MONITOR:
- REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
- REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
- REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
- flags |= AR_TBTT_TIMER_EN;
- break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
REG_SET_BIT(ah, AR_TXCFG,
@@ -1663,9 +1658,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
break;
default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON,
- "%s: unsupported opmode: %d\n",
- __func__, ah->opmode);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BEACON,
+ "%s: unsupported opmode: %d\n",
+ __func__, ah->opmode);
return;
break;
}
@@ -1721,10 +1716,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
else
nextTbtt = bs->bs_nexttbtt;
- ath_print(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
- ath_print(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
- ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
- ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
+ ath_dbg(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
+ ath_dbg(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
+ ath_dbg(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
+ ath_dbg(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
ENABLE_REGWRITE_BUFFER(ah);
@@ -1770,7 +1765,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u16 capField = 0, eeval;
- u8 ant_div_ctl1;
+ u8 ant_div_ctl1, tx_chainmask, rx_chainmask;
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
regulatory->current_rd = eeval;
@@ -1789,14 +1784,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
regulatory->current_rd += 5;
else if (regulatory->current_rd == 0x41)
regulatory->current_rd = 0x43;
- ath_print(common, ATH_DBG_REGULATORY,
- "regdomain mapped to 0x%x\n", regulatory->current_rd);
+ ath_dbg(common, ATH_DBG_REGULATORY,
+ "regdomain mapped to 0x%x\n", regulatory->current_rd);
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
- ath_print(common, ATH_DBG_FATAL,
- "no band has been marked as supported in EEPROM.\n");
+ ath_err(common,
+ "no band has been marked as supported in EEPROM\n");
return -EINVAL;
}
@@ -1822,6 +1817,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
+ /* enable key search for every frame in an aggregate */
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH;
+
pCap->low_2ghz_chan = 2312;
pCap->high_2ghz_chan = 2732;
@@ -1910,13 +1909,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
AR_SREV_5416(ah))
pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
- pCap->num_antcfg_5ghz =
- ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
- pCap->num_antcfg_2ghz =
- ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
-
- if (AR_SREV_9280_20_OR_LATER(ah) &&
- ath9k_hw_btcoex_supported(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
@@ -1931,8 +1924,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
if (AR_SREV_9300_20_OR_LATER(ah)) {
- pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC |
- ATH9K_HW_CAP_FASTCLOCK;
+ pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK;
+ if (!AR_SREV_9485(ah))
+ pCap->hw_caps |= ATH9K_HW_CAP_LDPC;
+
pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH;
pCap->rx_status_len = sizeof(struct ar9003_rxs);
@@ -1952,6 +1947,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ ah->ent_mode = REG_READ(ah, AR_ENT_OTP);
+
if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
@@ -1962,6 +1960,29 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
}
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
+ pCap->hw_caps |= ATH9K_HW_CAP_APM;
+ }
+
+
+
+ if (AR_SREV_9485_10(ah)) {
+ pCap->pcie_lcr_extsync_en = true;
+ pCap->pcie_lcr_offset = 0x80;
+ }
+
+ tx_chainmask = pCap->tx_chainmask;
+ rx_chainmask = pCap->rx_chainmask;
+ while (tx_chainmask || rx_chainmask) {
+ if (tx_chainmask & BIT(0))
+ pCap->max_txchains++;
+ if (rx_chainmask & BIT(0))
+ pCap->max_rxchains++;
+
+ tx_chainmask >>= 1;
+ rx_chainmask >>= 1;
+ }
return 0;
}
@@ -2033,7 +2054,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
val = REG_READ(ah, AR7010_GPIO_IN);
return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
} else if (AR_SREV_9300_20_OR_LATER(ah))
- return MS_REG_READ(AR9300, gpio) != 0;
+ return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
+ AR_GPIO_BIT(gpio)) != 0;
else if (AR_SREV_9271(ah))
return MS_REG_READ(AR9271, gpio) != 0;
else if (AR_SREV_9287_11_OR_LATER(ah))
@@ -2165,7 +2187,7 @@ bool ath9k_hw_disable(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable);
-void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath9k_channel *chan = ah->curchan;
@@ -2178,7 +2200,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit));
+ (u32) regulatory->power_limit), test);
}
EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
@@ -2238,8 +2260,8 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
AH_TSF_WRITE_TIMEOUT))
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
}
@@ -2312,11 +2334,10 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
return timer_table->gen_timer_index[b];
}
-u32 ath9k_hw_gettsf32(struct ath_hw *ah)
+static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
}
-EXPORT_SYMBOL(ath9k_hw_gettsf32);
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
@@ -2330,9 +2351,9 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
if (timer == NULL) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "Failed to allocate memory"
- "for hw timer[%d]\n", timer_index);
+ ath_err(ath9k_hw_common(ah),
+ "Failed to allocate memory for hw timer[%d]\n",
+ timer_index);
return NULL;
}
@@ -2361,9 +2382,9 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
tsf = ath9k_hw_gettsf32(ah);
- ath_print(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
- "curent tsf %x period %x"
- "timer_next %x\n", tsf, timer_period, timer_next);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
+ "current tsf %x period %x timer_next %x\n",
+ tsf, timer_period, timer_next);
/*
* Pull timer_next forward if the current TSF already passed it
@@ -2443,8 +2464,8 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &thresh_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- ath_print(common, ATH_DBG_HWTIMER,
- "TSF overflow for Gen timer %d\n", index);
+ ath_dbg(common, ATH_DBG_HWTIMER,
+ "TSF overflow for Gen timer %d\n", index);
timer->overflow(timer->arg);
}
@@ -2452,8 +2473,8 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &trigger_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- ath_print(common, ATH_DBG_HWTIMER,
- "Gen timer[%d] trigger\n", index);
+ ath_dbg(common, ATH_DBG_HWTIMER,
+ "Gen timer[%d] trigger\n", index);
timer->trigger(timer->arg);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index d032939768b0..5a3dfec45e96 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -30,7 +30,6 @@
#include "btcoex.h"
#include "../regd.h"
-#include "../debug.h"
#define ATHEROS_VENDOR_ID 0x168c
@@ -44,6 +43,7 @@
#define AR9287_DEVID_PCI 0x002d
#define AR9287_DEVID_PCIE 0x002e
#define AR9300_DEVID_PCIE 0x0030
+#define AR9300_DEVID_AR9485_PCIE 0x0032
#define AR5416_AR9100_DEVID 0x000b
@@ -157,6 +157,13 @@
#define PAPRD_GAIN_TABLE_ENTRIES 32
#define PAPRD_TABLE_SZ 24
+enum ath_hw_txq_subtype {
+ ATH_TXQ_AC_BE = 0,
+ ATH_TXQ_AC_BK = 1,
+ ATH_TXQ_AC_VI = 2,
+ ATH_TXQ_AC_VO = 3,
+};
+
enum ath_ini_subsys {
ATH_INI_PRE = 0,
ATH_INI_CORE,
@@ -180,6 +187,7 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12),
ATH9K_HW_CAP_2GHZ = BIT(13),
ATH9K_HW_CAP_5GHZ = BIT(14),
+ ATH9K_HW_CAP_APM = BIT(15),
};
struct ath9k_hw_capabilities {
@@ -191,16 +199,18 @@ struct ath9k_hw_capabilities {
u16 rts_aggr_limit;
u8 tx_chainmask;
u8 rx_chainmask;
+ u8 max_txchains;
+ u8 max_rxchains;
u16 tx_triglevel_max;
u16 reg_cap;
u8 num_gpio_pins;
- u8 num_antcfg_2ghz;
- u8 num_antcfg_5ghz;
u8 rx_hp_qdepth;
u8 rx_lp_qdepth;
u8 rx_status_len;
u8 tx_desc_len;
u8 txs_len;
+ u16 pcie_lcr_offset;
+ bool pcie_lcr_extsync_en;
};
struct ath9k_ops_config {
@@ -226,7 +236,6 @@ struct ath9k_ops_config {
#define SPUR_DISABLE 0
#define SPUR_ENABLE_IOCTL 1
#define SPUR_ENABLE_EEPROM 2
-#define AR_EEPROM_MODAL_SPURS 5
#define AR_SPUR_5413_1 1640
#define AR_SPUR_5413_2 1200
#define AR_NO_SPUR 0x8000
@@ -434,6 +443,7 @@ struct ath9k_hw_version {
u16 analog5GhzRev;
u16 analog2GhzRev;
u16 subsysid;
+ enum ath_usb_dev usbdev;
};
/* Generic TSF timer definitions */
@@ -478,6 +488,40 @@ struct ath_hw_antcomb_conf {
};
/**
+ * struct ath_hw_radar_conf - radar detection initialization parameters
+ *
+ * @pulse_inband: threshold for checking the ratio of in-band power
+ * to total power for short radar pulses (half dB steps)
+ * @pulse_inband_step: threshold for checking an in-band power to total
+ * power ratio increase for short radar pulses (half dB steps)
+ * @pulse_height: threshold for detecting the beginning of a short
+ * radar pulse (dB step)
+ * @pulse_rssi: threshold for detecting if a short radar pulse is
+ * gone (dB step)
+ * @pulse_maxlen: maximum pulse length (0.8 us steps)
+ *
+ * @radar_rssi: RSSI threshold for starting long radar detection (dB steps)
+ * @radar_inband: threshold for checking the ratio of in-band power
+ * to total power for long radar pulses (half dB steps)
+ * @fir_power: threshold for detecting the end of a long radar pulse (dB)
+ *
+ * @ext_channel: enable extension channel radar detection
+ */
+struct ath_hw_radar_conf {
+ unsigned int pulse_inband;
+ unsigned int pulse_inband_step;
+ unsigned int pulse_height;
+ unsigned int pulse_rssi;
+ unsigned int pulse_maxlen;
+
+ unsigned int radar_rssi;
+ unsigned int radar_inband;
+ int fir_power;
+
+ bool ext_channel;
+};
+
+/**
* struct ath_hw_private_ops - callbacks used internally by hardware code
*
* This structure contains private callbacks designed to only be used internally
@@ -488,7 +532,6 @@ struct ath_hw_antcomb_conf {
*
* @init_mode_regs: Initializes mode registers
* @init_mode_gain_regs: Initialize TX/RX gain registers
- * @macversion_supported: If this specific mac revision is supported
*
* @rf_set_freq: change frequency
* @spur_mitigate_freq: spur mitigation
@@ -510,7 +553,6 @@ struct ath_hw_private_ops {
void (*init_mode_regs)(struct ath_hw *ah);
void (*init_mode_gain_regs)(struct ath_hw *ah);
- bool (*macversion_supported)(u32 macversion);
void (*setup_calibration)(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
@@ -534,7 +576,6 @@ struct ath_hw_private_ops {
void (*set_delta_slope)(struct ath_hw *ah, struct ath9k_channel *chan);
bool (*rfbus_req)(struct ath_hw *ah);
void (*rfbus_done)(struct ath_hw *ah);
- void (*enable_rfkill)(struct ath_hw *ah);
void (*restore_chainmask)(struct ath_hw *ah);
void (*set_diversity)(struct ath_hw *ah, bool value);
u32 (*compute_pll_control)(struct ath_hw *ah,
@@ -542,6 +583,8 @@ struct ath_hw_private_ops {
bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
int param);
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
+ void (*set_radar_params)(struct ath_hw *ah,
+ struct ath_hw_radar_conf *conf);
/* ANI */
void (*ani_cache_ini_regs)(struct ath_hw *ah);
@@ -603,6 +646,10 @@ struct ath_nf_limits {
s16 nominal;
};
+/* ah_flags */
+#define AH_USE_EEPROM 0x1
+#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
+
struct ath_hw {
struct ieee80211_hw *hw;
struct ath_common common;
@@ -622,6 +669,7 @@ struct ath_hw {
bool sw_mgmt_crypto;
bool is_pciexpress;
+ bool is_monitoring;
bool need_an_top2_fixup;
u16 tx_trig_level;
@@ -717,9 +765,7 @@ struct ath_hw {
u32 *bank6Temp;
u8 txpower_limit;
- int16_t txpower_indexoffset;
int coverage_class;
- u32 beacon_interval;
u32 slottime;
u32 globaltxtimeout;
@@ -739,6 +785,8 @@ struct ath_hw {
u8 txchainmask;
u8 rxchainmask;
+ struct ath_hw_radar_conf radar_conf;
+
u32 originalGain[22];
int initPDADC;
int PDADCdelta;
@@ -788,6 +836,11 @@ struct ath_hw {
u32 bb_watchdog_last_status;
u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
+ unsigned int paprd_target_power;
+ unsigned int paprd_training_power;
+ unsigned int paprd_ratemask;
+ unsigned int paprd_ratemask_ht40;
+ bool paprd_table_write_done;
u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
/*
@@ -796,6 +849,9 @@ struct ath_hw {
* this register when in sleep states.
*/
u32 WARegVal;
+
+ /* Enterprise mode cap */
+ u32 ent_mode;
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -818,10 +874,9 @@ static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah)
return &ah->ops;
}
-static inline int sign_extend(int val, const int nbits)
+static inline u8 get_streams(int mask)
{
- int order = BIT(nbits-1);
- return (val ^ order) - order;
+ return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
}
/* Initialization, Detach, Reset */
@@ -860,7 +915,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
bool ath9k_hw_phy_disable(struct ath_hw *ah);
bool ath9k_hw_disable(struct ath_hw *ah);
-void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
void ath9k_hw_setbssidmask(struct ath_hw *ah);
@@ -892,7 +947,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_isr(struct ath_hw *hw);
-u32 ath9k_hw_gettsf32(struct ath_hw *ah);
void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 95b41db0d86b..767d8b86f1e1 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -29,17 +29,27 @@ static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
module_param_named(debug, ath9k_debug, uint, 0);
MODULE_PARM_DESC(debug, "Debugging mask");
-int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+int ath9k_modparam_nohwcrypt;
+module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
int led_blink;
module_param_named(blink, led_blink, int, 0444);
MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+static int ath9k_btcoex_enable;
+module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
+MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
+
+int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE;
+module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(pmqos, "User specified PM-QOS value");
+
+bool is_ath9k_unloaded;
/* We use the hw_value as an index into our private channel structure */
#define CHAN2G(_freq, _idx) { \
+ .band = IEEE80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 20, \
@@ -206,7 +216,9 @@ static void setup_ht_cap(struct ath_softc *sc,
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
- if (AR_SREV_9300_20_OR_LATER(ah))
+ if (AR_SREV_9485(ah))
+ max_streams = 1;
+ else if (AR_SREV_9300_20_OR_LATER(ah))
max_streams = 3;
else
max_streams = 2;
@@ -222,9 +234,9 @@ static void setup_ht_cap(struct ath_softc *sc,
tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
- ath_print(common, ATH_DBG_CONFIG,
- "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
if (tx_streams != rx_streams) {
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
@@ -267,8 +279,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct ath_buf *bf;
int i, bsize, error, desc_len;
- ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
- name, nbuf, ndesc);
+ ath_dbg(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+ name, nbuf, ndesc);
INIT_LIST_HEAD(head);
@@ -279,8 +291,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
/* ath_desc must be a multiple of DWORDs */
if ((desc_len % 4) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "ath_desc not DWORD aligned\n");
+ ath_err(common, "ath_desc not DWORD aligned\n");
BUG_ON((desc_len % 4) != 0);
error = -ENOMEM;
goto fail;
@@ -314,9 +325,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
goto fail;
}
ds = (u8 *) dd->dd_desc;
- ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
- name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+ ath_dbg(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+ name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
/* allocate buffers */
bsize = sizeof(struct ath_buf) * nbuf;
@@ -362,7 +373,7 @@ fail:
#undef DS2PHYS
}
-static void ath9k_init_crypto(struct ath_softc *sc)
+void ath9k_init_crypto(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i = 0;
@@ -370,9 +381,9 @@ static void ath9k_init_crypto(struct ath_softc *sc)
/* Get the hardware key cache size. */
common->keymax = sc->sc_ah->caps.keycache_size;
if (common->keymax > ATH_KEYMAX) {
- ath_print(common, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, common->keymax);
+ ath_dbg(common, ATH_DBG_ANY,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, common->keymax);
common->keymax = ATH_KEYMAX;
}
@@ -395,7 +406,8 @@ static void ath9k_init_crypto(struct ath_softc *sc)
static int ath9k_init_btcoex(struct ath_softc *sc)
{
- int r, qnum;
+ struct ath_txq *txq;
+ int r;
switch (sc->sc_ah->btcoex_hw.scheme) {
case ATH_BTCOEX_CFG_NONE:
@@ -408,8 +420,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
r = ath_init_btcoex_timer(sc);
if (r)
return -1;
- qnum = sc->tx.hwq_map[WME_AC_BE];
- ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
+ txq = sc->tx.txq_map[WME_AC_BE];
+ ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
break;
default:
@@ -422,59 +434,18 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
static int ath9k_init_queues(struct ath_softc *sc)
{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i = 0;
- for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
- sc->tx.hwq_map[i] = -1;
-
sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
- if (sc->beacon.beaconq == -1) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup a beacon xmit queue\n");
- goto err;
- }
-
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
- if (sc->beacon.cabq == NULL) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup CAB xmit queue\n");
- goto err;
- }
sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
ath_cabq_update(sc);
- if (!ath_tx_setup(sc, WME_AC_BK)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BK traffic\n");
- goto err;
- }
-
- if (!ath_tx_setup(sc, WME_AC_BE)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BE traffic\n");
- goto err;
- }
- if (!ath_tx_setup(sc, WME_AC_VI)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VI traffic\n");
- goto err;
- }
- if (!ath_tx_setup(sc, WME_AC_VO)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VO traffic\n");
- goto err;
- }
+ for (i = 0; i < WME_NUM_AC; i++)
+ sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
return 0;
-
-err:
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
- return -EIO;
}
static int ath9k_init_channels_rates(struct ath_softc *sc)
@@ -570,6 +541,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
+ if (!sc->dev->platform_data)
+ ah->ah_flags |= AH_USE_EEPROM;
+
common = ath9k_hw_common(ah);
common->ops = &ath9k_common_ops;
common->bus_ops = bus_ops;
@@ -577,10 +551,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
common->hw = sc->hw;
common->priv = sc;
common->debug_mask = ath9k_debug;
+ common->btcoex_enabled = ath9k_btcoex_enable == 1;
spin_lock_init(&common->cc_lock);
spin_lock_init(&sc->wiphy_lock);
- spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
@@ -600,13 +574,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
if (ret)
goto err_hw;
- ret = ath9k_init_debug(ah);
- if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to create debugfs files\n");
- goto err_debug;
- }
-
ret = ath9k_init_queues(sc);
if (ret)
goto err_queues;
@@ -629,8 +596,6 @@ err_btcoex:
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
err_queues:
- ath9k_exit_debug(ah);
-err_debug:
ath9k_hw_deinit(ah);
err_hw:
tasklet_kill(&sc->intr_tq);
@@ -642,6 +607,37 @@ err_hw:
return ret;
}
+static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+ int i;
+
+ sband = &sc->sbands[band];
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ ah->curchan = &ah->channels[chan->hw_value];
+ ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20);
+ ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
+ chan->max_power = reg->max_power_level / 2;
+ }
+}
+
+static void ath9k_init_txpower_limits(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_channel *curchan = ah->curchan;
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+ ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+ ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
+
+ ah->curchan = curchan;
+}
+
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -657,10 +653,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
- if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
+ if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_STATION) |
@@ -703,6 +701,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops)
{
struct ieee80211_hw *hw = sc->hw;
+ struct ath_wiphy *aphy = hw->priv;
struct ath_common *common;
struct ath_hw *ah;
int error = 0;
@@ -735,11 +734,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
if (error != 0)
goto error_rx;
+ ath9k_init_txpower_limits(sc);
+
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
goto error_register;
+ error = ath9k_init_debug(ah);
+ if (error) {
+ ath_err(common, "Unable to create debugfs files\n");
+ goto error_world;
+ }
+
/* Handle world regulatory */
if (!ath_is_world_regd(reg)) {
error = regulatory_hint(hw->wiphy, reg->alpha2);
@@ -752,10 +759,14 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(500);
+ aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
ath_init_leds(sc);
ath_start_rfkill_poll(sc);
+ pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
return 0;
error_world:
@@ -794,7 +805,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
- ath9k_exit_debug(sc->sc_ah);
ath9k_hw_deinit(sc->sc_ah);
tasklet_kill(&sc->intr_tq);
@@ -824,6 +834,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
}
ieee80211_unregister_hw(hw);
+ pm_qos_remove_request(&sc->pm_qos_req);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
ath9k_deinit_softc(sc);
@@ -860,20 +871,12 @@ static int __init ath9k_init(void)
goto err_out;
}
- error = ath9k_debug_create_root();
- if (error) {
- printk(KERN_ERR
- "ath9k: Unable to create debugfs root: %d\n",
- error);
- goto err_rate_unregister;
- }
-
error = ath_pci_init();
if (error < 0) {
printk(KERN_ERR
"ath9k: No PCI devices found, driver not installed.\n");
error = -ENODEV;
- goto err_remove_root;
+ goto err_rate_unregister;
}
error = ath_ahb_init();
@@ -887,8 +890,6 @@ static int __init ath9k_init(void)
err_pci_exit:
ath_pci_exit();
- err_remove_root:
- ath9k_debug_remove_root();
err_rate_unregister:
ath_rate_control_unregister();
err_out:
@@ -898,9 +899,9 @@ module_init(ath9k_init);
static void __exit ath9k_exit(void)
{
+ is_ath9k_unloaded = true;
ath_ahb_exit();
ath_pci_exit();
- ath9k_debug_remove_root();
ath_rate_control_unregister();
printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 8c13479b17cd..180170d3ce25 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -20,11 +20,11 @@
static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
struct ath9k_tx_queue_info *qi)
{
- ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
- "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
- ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
- ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
- ah->txurn_interrupt_mask);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
+ "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+ ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
+ ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
+ ah->txurn_interrupt_mask);
ENABLE_REGWRITE_BUFFER(ah);
@@ -56,8 +56,8 @@ EXPORT_SYMBOL(ath9k_hw_puttxbuf);
void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
{
- ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
- "Enable TXE on queue: %u\n", q);
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_QUEUE,
+ "Enable TXE on queue: %u\n", q);
REG_WRITE(ah, AR_Q_TXE, 1 << q);
}
EXPORT_SYMBOL(ath9k_hw_txstart);
@@ -117,12 +117,11 @@ EXPORT_SYMBOL(ath9k_hw_numtxpending);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
{
u32 txcfg, curLevel, newLevel;
- enum ath9k_int omask;
if (ah->tx_trig_level >= ah->config.max_txtrig_level)
return false;
- omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
+ ath9k_hw_disable_interrupts(ah);
txcfg = REG_READ(ah, AR_TXCFG);
curLevel = MS(txcfg, AR_FTRIG);
@@ -136,7 +135,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
REG_WRITE(ah, AR_TXCFG,
(txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
- ath9k_hw_set_interrupts(ah, omask);
+ ath9k_hw_enable_interrupts(ah);
ah->tx_trig_level = newLevel;
@@ -155,15 +154,15 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
if (q >= pCap->total_queues) {
- ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "invalid queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Stopping TX DMA, invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "inactive queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Stopping TX DMA, inactive queue: %u\n", q);
return false;
}
@@ -176,9 +175,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
}
if (ath9k_hw_numtxpending(ah, q)) {
- ath_print(common, ATH_DBG_QUEUE,
- "%s: Num of pending TX Frames %d on Q %d\n",
- __func__, ath9k_hw_numtxpending(ah, q), q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "%s: Num of pending TX Frames %d on Q %d\n",
+ __func__, ath9k_hw_numtxpending(ah, q), q);
for (j = 0; j < 2; j++) {
tsfLow = REG_READ(ah, AR_TSF_L32);
@@ -192,9 +191,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
break;
- ath_print(common, ATH_DBG_QUEUE,
- "TSF has moved while trying to set "
- "quiet time TSF: 0x%08x\n", tsfLow);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "TSF has moved while trying to set quiet time TSF: 0x%08x\n",
+ tsfLow);
}
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
@@ -205,9 +204,8 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
wait = wait_time;
while (ath9k_hw_numtxpending(ah, q)) {
if ((--wait) == 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Failed to stop TX DMA in 100 "
- "msec after killing last frame\n");
+ ath_err(common,
+ "Failed to stop TX DMA in 100 msec after killing last frame\n");
break;
}
udelay(ATH9K_TIME_QUANTUM);
@@ -240,19 +238,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Set TXQ properties, invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Set TXQ properties, inactive queue: %u\n", q);
return false;
}
- ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
qi->tqi_ver = qinfo->tqi_ver;
qi->tqi_subtype = qinfo->tqi_subtype;
@@ -311,15 +309,15 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Get TXQ properties, invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Get TXQ properties, inactive queue: %u\n", q);
return false;
}
@@ -369,23 +367,20 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
ATH9K_TX_QUEUE_INACTIVE)
break;
if (q == pCap->total_queues) {
- ath_print(common, ATH_DBG_FATAL,
- "No available TX queue\n");
+ ath_err(common, "No available TX queue\n");
return -1;
}
break;
default:
- ath_print(common, ATH_DBG_FATAL,
- "Invalid TX queue type: %u\n", type);
+ ath_err(common, "Invalid TX queue type: %u\n", type);
return -1;
}
- ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
qi = &ah->txq[q];
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_FATAL,
- "TX queue: %u already active\n", q);
+ ath_err(common, "TX queue: %u already active\n", q);
return -1;
}
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -417,18 +412,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
- "invalid queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Release TXQ, invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
- "inactive queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Release TXQ, inactive queue: %u\n", q);
return false;
}
- ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
ah->txok_interrupt_mask &= ~(1 << q);
@@ -451,19 +446,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
u32 cwMin, chanCwMin, value;
if (q >= pCap->total_queues) {
- ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
- "invalid queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Reset TXQ, invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
- "inactive queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "Reset TXQ, inactive queue: %u\n", q);
return true;
}
- ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
+ ath_dbg(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
if (chan && IS_CHAN_B(chan))
@@ -697,16 +692,16 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
if (ads.ds_rxstatus8 & AR_CRCErr)
rs->rs_status |= ATH9K_RXERR_CRC;
- else if (ads.ds_rxstatus8 & AR_PHYErr) {
+ if (ads.ds_rxstatus8 & AR_PHYErr) {
rs->rs_status |= ATH9K_RXERR_PHY;
phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
rs->rs_phyerr = phyerr;
- } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+ }
+ if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
- else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
- rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
+ if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
- else if (ads.ds_rxstatus8 & AR_KeyMiss)
+ if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
}
@@ -736,9 +731,9 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
AR_DIAG_RX_ABORT));
reg = REG_READ(ah, AR_OBS_BUS_1);
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "RX failed to go idle in 10 ms RXSM=0x%x\n",
- reg);
+ ath_err(ath9k_hw_common(ah),
+ "RX failed to go idle in 10 ms RXSM=0x%x\n",
+ reg);
return false;
}
@@ -767,14 +762,6 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning)
}
EXPORT_SYMBOL(ath9k_hw_startpcureceive);
-void ath9k_hw_stoppcurecv(struct ath_hw *ah)
-{
- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-
- ath9k_hw_disable_mib_counters(ah);
-}
-EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
-
void ath9k_hw_abortpcurecv(struct ath_hw *ah)
{
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
@@ -800,12 +787,11 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
}
if (i == 0) {
- ath_print(common, ATH_DBG_FATAL,
- "DMA failed to stop in %d ms "
- "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
- AH_RX_STOP_DMA_TIMEOUT / 1000,
- REG_READ(ah, AR_CR),
- REG_READ(ah, AR_DIAG_SW));
+ ath_err(common,
+ "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+ AH_RX_STOP_DMA_TIMEOUT / 1000,
+ REG_READ(ah, AR_CR),
+ REG_READ(ah, AR_DIAG_SW));
return false;
} else {
return true;
@@ -849,28 +835,59 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_intrpend);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
- enum ath9k_int ints)
+void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
+ REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+ (void) REG_READ(ah, AR_IER);
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
+ (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
+
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+ (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
+ }
+}
+EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
+
+void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!(ah->imask & ATH9K_INT_GLOBAL))
+ return;
+
+ ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
+ REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
+ AR_INTR_MAC_IRQ);
+ REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
+
+
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
+ AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_MASK,
+ AR_INTR_SYNC_DEFAULT);
+ }
+ ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+ REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+}
+EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
+
+void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{
enum ath9k_int omask = ah->imask;
u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
- ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+ if (!(ints & ATH9K_INT_GLOBAL))
+ ath9k_hw_enable_interrupts(ah);
- if (omask & ATH9K_INT_GLOBAL) {
- ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
- REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
- (void) REG_READ(ah, AR_IER);
- if (!AR_SREV_9100(ah)) {
- REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
- (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
-
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
- (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
- }
- }
+ ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
/* TODO: global int Ref count */
mask = ints & ATH9K_INT_COMMON;
@@ -931,7 +948,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
mask2 |= AR_IMR_S2_CST;
}
- ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
+ ath_dbg(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
REG_WRITE(ah, AR_IMR, mask);
ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
@@ -946,24 +963,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
}
- if (ints & ATH9K_INT_GLOBAL) {
- ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
- REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
- if (!AR_SREV_9100(ah)) {
- REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
- AR_INTR_MAC_IRQ);
- REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
-
-
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
- AR_INTR_SYNC_DEFAULT);
- REG_WRITE(ah, AR_INTR_SYNC_MASK,
- AR_INTR_SYNC_DEFAULT);
- }
- ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
- REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
- }
+ ath9k_hw_enable_interrupts(ah);
- return omask;
+ return;
}
EXPORT_SYMBOL(ath9k_hw_set_interrupts);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 7c1a34d64f6d..7512f97e8f49 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -104,13 +104,11 @@ struct ath_tx_status {
u32 ts_tstamp;
u16 ts_seqnum;
u8 ts_status;
- u8 ts_ratecode;
u8 ts_rateindex;
int8_t ts_rssi;
u8 ts_shortretry;
u8 ts_longretry;
u8 ts_virtcol;
- u8 ts_antenna;
u8 ts_flags;
int8_t ts_rssi_ctl0;
int8_t ts_rssi_ctl1;
@@ -121,7 +119,6 @@ struct ath_tx_status {
u8 qid;
u16 desc_id;
u8 tid;
- u8 pad[2];
u32 ba_low;
u32 ba_high;
u32 evm0;
@@ -240,7 +237,7 @@ struct ath_desc {
u32 ds_ctl1;
u32 ds_hw[20];
void *ds_vdata;
-} __packed;
+} __packed __aligned(4);
#define ATH9K_TXDESC_CLRDMASK 0x0001
#define ATH9K_TXDESC_NOACK 0x0002
@@ -310,7 +307,7 @@ struct ar5416_desc {
u32 status8;
} rx;
} u;
-} __packed;
+} __packed __aligned(4);
#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds))
#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds))
@@ -669,6 +666,7 @@ enum ath9k_key_type {
struct ath_hw;
struct ath9k_channel;
+enum ath9k_int;
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
@@ -693,15 +691,15 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
-void ath9k_hw_stoppcurecv(struct ath_hw *ah);
void ath9k_hw_abortpcurecv(struct ath_hw *ah);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
int ath9k_hw_beaconq_setup(struct ath_hw *ah);
/* Interrupt Handling */
bool ath9k_hw_intrpend(struct ath_hw *ah);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
- enum ath9k_int ints);
+void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
+void ath9k_hw_enable_interrupts(struct ath_hw *ah);
+void ath9k_hw_disable_interrupts(struct ath_hw *ah);
void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index b52f1cf8a603..f90a6ca94a76 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -23,7 +23,7 @@ static void ath_update_txpow(struct ath_softc *sc)
struct ath_hw *ah = sc->sc_ah;
if (sc->curtxpow != sc->config.txpowlimit) {
- ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
+ ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
/* read back in case value is clamped */
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
}
@@ -93,11 +93,13 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long flags;
+ enum ath9k_power_mode power_mode;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (++sc->ps_usecount != 1)
goto unlock;
+ power_mode = sc->sc_ah->power_mode;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
/*
@@ -105,10 +107,12 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
* useful data. Better clear them now so that they don't mess up
* survey data results.
*/
- spin_lock(&common->cc_lock);
- ath_hw_cycle_counters_update(common);
- memset(&common->cc_survey, 0, sizeof(common->cc_survey));
- spin_unlock(&common->cc_lock);
+ if (power_mode != ATH9K_PM_AWAKE) {
+ spin_lock(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
+ memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+ spin_unlock(&common->cc_lock);
+ }
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -230,6 +234,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
ath9k_ps_wakeup(sc);
+ spin_lock_bh(&sc->sc_pcu_lock);
+
/*
* This is only performed if the channel settings have
* actually changed.
@@ -239,12 +245,11 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
* hardware at the new frequency, and then re-enable
* the relevant bits of the h/w.
*/
- ath9k_hw_set_interrupts(ah, 0);
- ath_drain_all_txq(sc, false);
-
- spin_lock_bh(&sc->rx.pcu_lock);
+ ath9k_hw_disable_interrupts(ah);
+ stopped = ath_drain_all_txq(sc, false);
- stopped = ath_stoprecv(sc);
+ if (!ath_stoprecv(sc))
+ stopped = false;
/* XXX: do not flush receive queue here. We don't want
* to flush data frames already in queue because of
@@ -256,46 +261,39 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
caldata = &aphy->caldata;
- ath_print(common, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
- sc->sc_ah->curchan->channel,
- channel->center_freq, conf_is_ht40(conf),
- fastcc);
-
- spin_lock_bh(&sc->sc_resetlock);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
+ sc->sc_ah->curchan->channel,
+ channel->center_freq, conf_is_ht40(conf),
+ fastcc);
r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset channel (%u MHz), "
- "reset status %d\n",
- channel->center_freq, r);
- spin_unlock_bh(&sc->sc_resetlock);
- spin_unlock_bh(&sc->rx.pcu_lock);
+ ath_err(common,
+ "Unable to reset channel (%u MHz), reset status %d\n",
+ channel->center_freq, r);
goto ps_restore;
}
- spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
+ ath_err(common, "Unable to restart recv logic\n");
r = -EIO;
- spin_unlock_bh(&sc->rx.pcu_lock);
goto ps_restore;
}
- spin_unlock_bh(&sc->rx.pcu_lock);
-
ath_update_txpow(sc);
ath9k_hw_set_interrupts(ah, ah->imask);
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
- ath_beacon_config(sc, NULL);
+ if (sc->sc_flags & SC_OP_BEACONS)
+ ath_beacon_config(sc, NULL);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ath_start_ani(common);
}
ps_restore:
+ spin_unlock_bh(&sc->sc_pcu_lock);
+
ath9k_ps_restore(sc);
return r;
}
@@ -323,6 +321,42 @@ static void ath_paprd_activate(struct ath_softc *sc)
ath9k_ps_restore(sc);
}
+static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_control txctl;
+ int time_left;
+
+ memset(&txctl, 0, sizeof(txctl));
+ txctl.txq = sc->tx.txq_map[WME_AC_BE];
+
+ memset(tx_info, 0, sizeof(*tx_info));
+ tx_info->band = hw->conf.channel->band;
+ tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ tx_info->control.rates[0].idx = 0;
+ tx_info->control.rates[0].count = 1;
+ tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+ tx_info->control.rates[1].idx = -1;
+
+ init_completion(&sc->paprd_complete);
+ sc->paprd_pending = true;
+ txctl.paprd = BIT(chain);
+ if (ath_tx_start(hw, skb, &txctl) != 0)
+ return false;
+
+ time_left = wait_for_completion_timeout(&sc->paprd_complete,
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+ sc->paprd_pending = false;
+
+ if (!time_left)
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CALIBRATE,
+ "Timeout waiting for paprd training on TX chain %d\n",
+ chain);
+
+ return !!time_left;
+}
+
void ath_paprd_calibrate(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
@@ -330,28 +364,23 @@ void ath_paprd_calibrate(struct work_struct *work)
struct ath_hw *ah = sc->sc_ah;
struct ieee80211_hdr *hdr;
struct sk_buff *skb = NULL;
- struct ieee80211_tx_info *tx_info;
- int band = hw->conf.channel->band;
- struct ieee80211_supported_band *sband = &sc->sbands[band];
- struct ath_tx_control txctl;
struct ath9k_hw_cal_data *caldata = ah->caldata;
struct ath_common *common = ath9k_hw_common(ah);
- int qnum, ftype;
+ int ftype;
int chain_ok = 0;
int chain;
int len = 1800;
- int time_left;
- int i;
if (!caldata)
return;
+ if (ar9003_paprd_init_table(ah) < 0)
+ return;
+
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return;
- tx_info = IEEE80211_SKB_CB(skb);
-
skb_put(skb, len);
memset(skb->data, 0, len);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -362,40 +391,25 @@ void ath_paprd_calibrate(struct work_struct *work)
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
- memset(&txctl, 0, sizeof(txctl));
- qnum = sc->tx.hwq_map[WME_AC_BE];
- txctl.txq = &sc->tx.txq[qnum];
-
ath9k_ps_wakeup(sc);
- ar9003_paprd_init_table(ah);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(common->tx_chainmask & BIT(chain)))
continue;
chain_ok = 0;
- memset(tx_info, 0, sizeof(*tx_info));
- tx_info->band = band;
- for (i = 0; i < 4; i++) {
- tx_info->control.rates[i].idx = sband->n_bitrates - 1;
- tx_info->control.rates[i].count = 6;
- }
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Sending PAPRD frame for thermal measurement "
+ "on chain %d\n", chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
+ goto fail_paprd;
- init_completion(&sc->paprd_complete);
ar9003_paprd_setup_gain_table(ah, chain);
- txctl.paprd = BIT(chain);
- if (ath_tx_start(hw, skb, &txctl) != 0)
- break;
- time_left = wait_for_completion_timeout(&sc->paprd_complete,
- msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
- if (!time_left) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "Timeout waiting for paprd training on "
- "TX chain %d\n",
- chain);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Sending PAPRD training frame on chain %d\n", chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
goto fail_paprd;
- }
if (!ar9003_paprd_is_done(ah))
break;
@@ -452,7 +466,7 @@ void ath_ani_calibrate(unsigned long data)
/* Long calibration runs independently of short calibration. */
if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
longcal = true;
- ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+ ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
common->ani.longcal_timer = timestamp;
}
@@ -460,8 +474,8 @@ void ath_ani_calibrate(unsigned long data)
if (!common->ani.caldone) {
if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
shortcal = true;
- ath_print(common, ATH_DBG_ANI,
- "shortcal @%lu\n", jiffies);
+ ath_dbg(common, ATH_DBG_ANI,
+ "shortcal @%lu\n", jiffies);
common->ani.shortcal_timer = timestamp;
common->ani.resetcal_timer = timestamp;
}
@@ -520,49 +534,25 @@ set_timer:
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
if (!ah->caldata->paprd_done)
ieee80211_queue_work(sc->hw, &sc->paprd_work);
- else
+ else if (!ah->paprd_table_write_done)
ath_paprd_activate(sc);
}
}
-/*
- * Update tx/rx chainmask. For legacy association,
- * hard code chainmask to 1x1, for 11n association, use
- * the chainmask configuration, for bt coexistence, use
- * the chainmask configuration even in legacy mode.
- */
-void ath_update_chainmask(struct ath_softc *sc, int is_ht)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if ((sc->sc_flags & SC_OP_OFFCHANNEL) || is_ht ||
- (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) {
- common->tx_chainmask = ah->caps.tx_chainmask;
- common->rx_chainmask = ah->caps.rx_chainmask;
- } else {
- common->tx_chainmask = 1;
- common->rx_chainmask = 1;
- }
-
- ath_print(common, ATH_DBG_CONFIG,
- "tx chmask: %d, rx chmask: %d\n",
- common->tx_chainmask,
- common->rx_chainmask);
-}
-
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an;
-
+ struct ath_hw *ah = sc->sc_ah;
an = (struct ath_node *)sta->drv_priv;
+ if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
+ sc->sc_flags |= SC_OP_ENABLE_APM;
+
if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an);
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
- an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}
@@ -610,6 +600,8 @@ void ath9k_tasklet(unsigned long data)
return;
}
+ spin_lock(&sc->sc_pcu_lock);
+
if (!ath9k_hw_check_alive(ah))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
@@ -620,15 +612,12 @@ void ath9k_tasklet(unsigned long data)
rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
if (status & rxmask) {
- spin_lock_bh(&sc->rx.pcu_lock);
-
/* Check for high priority Rx first */
if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
(status & ATH9K_INT_RXHP))
ath_rx_tasklet(sc, 0, true);
ath_rx_tasklet(sc, 0, false);
- spin_unlock_bh(&sc->rx.pcu_lock);
}
if (status & ATH9K_INT_TX) {
@@ -643,8 +632,8 @@ void ath9k_tasklet(unsigned long data)
* TSF sync does not look correct; remain awake to sync with
* the next Beacon.
*/
- ath_print(common, ATH_DBG_PS,
- "TSFOOR - Sync with next Beacon\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "TSFOOR - Sync with next Beacon\n");
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
}
@@ -653,7 +642,9 @@ void ath9k_tasklet(unsigned long data)
ath_gen_timer_isr(sc->sc_ah);
/* re-enable hardware interrupt */
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_enable_interrupts(ah);
+
+ spin_unlock(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
}
@@ -752,7 +743,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* interrupt; otherwise it will continue to
* fire.
*/
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
/*
* Let the hal handle the event. We assume
* it will clear whatever condition caused
@@ -761,11 +752,13 @@ irqreturn_t ath_isr(int irq, void *dev)
spin_lock(&common->cc_lock);
ath9k_hw_proc_mib_event(ah);
spin_unlock(&common->cc_lock);
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_enable_interrupts(ah);
}
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
if (status & ATH9K_INT_TIM_TIMER) {
+ if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
+ goto chip_reset;
/* Clear RxAbort bit so that we can
* receive frames */
ath9k_setpower(sc, ATH9K_PM_AWAKE);
@@ -778,8 +771,8 @@ chip_reset:
ath_debug_stat_interrupt(sc, status);
if (sched) {
- /* turn off every interrupt except SWBA */
- ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA));
+ /* turn off every interrupt */
+ ath9k_hw_disable_interrupts(ah);
tasklet_schedule(&sc->intr_tq);
}
@@ -831,16 +824,18 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
+ struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
+ struct ath_wiphy *aphy = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
if (bss_conf->assoc) {
- ath_print(common, ATH_DBG_CONFIG,
- "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, common->curbssid);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
/* New association, store aid */
common->curaid = bss_conf->aid;
@@ -857,12 +852,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
ath_beacon_config(sc, vif);
/* Reset rssi stats */
+ aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
} else {
- ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
common->curaid = 0;
/* Stop ANI */
sc->sc_flags &= ~SC_OP_ANI_RUN;
@@ -878,31 +874,25 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
int r;
ath9k_ps_wakeup(sc);
+ spin_lock_bh(&sc->sc_pcu_lock);
+
ath9k_hw_configpcipowersave(ah, 0, 0);
if (!ah->curchan)
ah->curchan = ath_get_curchannel(sc, sc->hw);
- spin_lock_bh(&sc->rx.pcu_lock);
- spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset channel (%u MHz), "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_err(common,
+ "Unable to reset channel (%u MHz), reset status %d\n",
+ channel->center_freq, r);
}
- spin_unlock_bh(&sc->sc_resetlock);
ath_update_txpow(sc);
if (ath_startrecv(sc) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
- spin_unlock_bh(&sc->rx.pcu_lock);
- return;
+ ath_err(common, "Unable to restart recv logic\n");
+ goto out;
}
- spin_unlock_bh(&sc->rx.pcu_lock);
-
if (sc->sc_flags & SC_OP_BEACONS)
ath_beacon_config(sc, NULL); /* restart beacons */
@@ -915,6 +905,9 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
ieee80211_wake_queues(hw);
+out:
+ spin_unlock_bh(&sc->sc_pcu_lock);
+
ath9k_ps_restore(sc);
}
@@ -925,6 +918,8 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
int r;
ath9k_ps_wakeup(sc);
+ spin_lock_bh(&sc->sc_pcu_lock);
+
ieee80211_stop_queues(hw);
/*
@@ -937,34 +932,30 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
}
/* Disable interrupts */
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ath_drain_all_txq(sc, false); /* clear pending tx frames */
- spin_lock_bh(&sc->rx.pcu_lock);
-
ath_stoprecv(sc); /* turn off frame recv */
ath_flushrecv(sc); /* flush recv queue */
if (!ah->curchan)
ah->curchan = ath_get_curchannel(sc, hw);
- spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
if (r) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Unable to reset channel (%u MHz), "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "Unable to reset channel (%u MHz), reset status %d\n",
+ channel->center_freq, r);
}
- spin_unlock_bh(&sc->sc_resetlock);
ath9k_hw_phy_disable(ah);
- spin_unlock_bh(&sc->rx.pcu_lock);
-
ath9k_hw_configpcipowersave(ah, 1, 1);
+
+ spin_unlock_bh(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
+
ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
}
@@ -978,28 +969,23 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
/* Stop ANI */
del_timer_sync(&common->ani.timer);
+ spin_lock_bh(&sc->sc_pcu_lock);
+
ieee80211_stop_queues(hw);
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
ath_drain_all_txq(sc, retry_tx);
- spin_lock_bh(&sc->rx.pcu_lock);
-
ath_stoprecv(sc);
ath_flushrecv(sc);
- spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
if (r)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n", r);
- spin_unlock_bh(&sc->sc_resetlock);
+ ath_err(common,
+ "Unable to reset hardware; reset status %d\n", r);
if (ath_startrecv(sc) != 0)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to start recv logic\n");
-
- spin_unlock_bh(&sc->rx.pcu_lock);
+ ath_err(common, "Unable to start recv logic\n");
/*
* We may be doing a reset in response to a request
@@ -1025,6 +1011,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
}
ieee80211_wake_queues(hw);
+ spin_unlock_bh(&sc->sc_pcu_lock);
/* Start ANI */
ath_start_ani(common);
@@ -1032,56 +1019,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
return r;
}
-static int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case 0:
- qnum = sc->tx.hwq_map[WME_AC_VO];
- break;
- case 1:
- qnum = sc->tx.hwq_map[WME_AC_VI];
- break;
- case 2:
- qnum = sc->tx.hwq_map[WME_AC_BE];
- break;
- case 3:
- qnum = sc->tx.hwq_map[WME_AC_BK];
- break;
- default:
- qnum = sc->tx.hwq_map[WME_AC_BE];
- break;
- }
-
- return qnum;
-}
-
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case WME_AC_VO:
- qnum = 0;
- break;
- case WME_AC_VI:
- qnum = 1;
- break;
- case WME_AC_BE:
- qnum = 2;
- break;
- case WME_AC_BK:
- qnum = 3;
- break;
- default:
- qnum = -1;
- break;
- }
-
- return qnum;
-}
-
/* XXX: Remove me once we don't depend on ath9k_channel for all
* this redundant data */
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
@@ -1120,9 +1057,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
struct ath9k_channel *init_channel;
int r;
- ath_print(common, ATH_DBG_CONFIG,
- "Starting driver with initial channel: %d MHz\n",
- curchan->center_freq);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Starting driver with initial channel: %d MHz\n",
+ curchan->center_freq);
mutex_lock(&sc->mutex);
@@ -1163,19 +1100,15 @@ static int ath9k_start(struct ieee80211_hw *hw)
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
- spin_lock_bh(&sc->rx.pcu_lock);
- spin_lock_bh(&sc->sc_resetlock);
+ spin_lock_bh(&sc->sc_pcu_lock);
r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", r,
- curchan->center_freq);
- spin_unlock_bh(&sc->sc_resetlock);
- spin_unlock_bh(&sc->rx.pcu_lock);
+ ath_err(common,
+ "Unable to reset hardware; reset status %d (freq %u MHz)\n",
+ r, curchan->center_freq);
+ spin_unlock_bh(&sc->sc_pcu_lock);
goto mutex_unlock;
}
- spin_unlock_bh(&sc->sc_resetlock);
/*
* This is needed only to setup initial state
@@ -1191,13 +1124,12 @@ static int ath9k_start(struct ieee80211_hw *hw)
* here except setup the interrupt mask.
*/
if (ath_startrecv(sc) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to start recv logic\n");
+ ath_err(common, "Unable to start recv logic\n");
r = -EIO;
- spin_unlock_bh(&sc->rx.pcu_lock);
+ spin_unlock_bh(&sc->sc_pcu_lock);
goto mutex_unlock;
}
- spin_unlock_bh(&sc->rx.pcu_lock);
+ spin_unlock_bh(&sc->sc_pcu_lock);
/* Setup our intr mask. */
ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
@@ -1217,6 +1149,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
ah->imask |= ATH9K_INT_CST;
sc->sc_flags &= ~SC_OP_INVALID;
+ sc->sc_ah->is_monitoring = false;
/* Disable BMISS interrupt when we're not associated */
ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
@@ -1238,6 +1171,15 @@ static int ath9k_start(struct ieee80211_hw *hw)
ath9k_btcoex_timer_resume(sc);
}
+ /* User has the option to provide pm-qos value as a module
+ * parameter rather than using the default value of
+ * 'ATH9K_PM_QOS_DEFAULT_VALUE'.
+ */
+ pm_qos_update_request(&sc->pm_qos_req, ath9k_pm_qos_value);
+
+ if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
+ common->bus_ops->extn_synch_en(common);
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -1247,19 +1189,16 @@ mutex_unlock:
static int ath9k_tx(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
- int padpos, padsize;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- int qnum;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
- ath_print(common, ATH_DBG_XMIT,
- "ath9k: %s: TX in unexpected wiphy state "
- "%d\n", wiphy_name(hw->wiphy), aphy->state);
+ ath_dbg(common, ATH_DBG_XMIT,
+ "ath9k: %s: TX in unexpected wiphy state %d\n",
+ wiphy_name(hw->wiphy), aphy->state);
goto exit;
}
@@ -1271,8 +1210,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control) &&
!ieee80211_has_pm(hdr->frame_control)) {
- ath_print(common, ATH_DBG_PS, "Add PM=1 for a TX frame "
- "while in PS mode\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "Add PM=1 for a TX frame while in PS mode\n");
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
}
}
@@ -1287,12 +1226,12 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
- ath_print(common, ATH_DBG_PS,
- "Sending PS-Poll to pick a buffered frame\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "Sending PS-Poll to pick a buffered frame\n");
sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
} else {
- ath_print(common, ATH_DBG_PS,
- "Wake up to complete TX\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "Wake up to complete TX\n");
sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
}
/*
@@ -1304,36 +1243,12 @@ static int ath9k_tx(struct ieee80211_hw *hw,
}
memset(&txctl, 0, sizeof(struct ath_tx_control));
+ txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
- /*
- * As a temporary workaround, assign seq# here; this will likely need
- * to be cleaned up to work better with Beacon transmission and virtual
- * BSSes.
- */
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- sc->tx.seq_no += 0x10;
- hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
- }
-
- /* Add the padding after the header if this is not already done */
- padpos = ath9k_cmn_padpos(hdr->frame_control);
- padsize = padpos & 3;
- if (padsize && skb->len>padpos) {
- if (skb_headroom(skb) < padsize)
- return -1;
- skb_push(skb, padsize);
- memmove(skb->data, skb->data + padsize, padpos);
- }
-
- qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
- txctl.txq = &sc->tx.txq[qnum];
-
- ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
+ ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- ath_print(common, ATH_DBG_XMIT, "TX failed\n");
+ ath_dbg(common, ATH_DBG_XMIT, "TX failed\n");
goto exit;
}
@@ -1373,7 +1288,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
}
if (sc->sc_flags & SC_OP_INVALID) {
- ath_print(common, ATH_DBG_ANY, "Device not present\n");
+ ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
}
@@ -1392,32 +1307,38 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_btcoex_timer_pause(sc);
}
+ spin_lock_bh(&sc->sc_pcu_lock);
+
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
- ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_disable_interrupts(ah);
- spin_lock_bh(&sc->rx.pcu_lock);
if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_drain_all_txq(sc, false);
ath_stoprecv(sc);
ath9k_hw_phy_disable(ah);
} else
sc->rx.rxlink = NULL;
- spin_unlock_bh(&sc->rx.pcu_lock);
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(ah);
ath9k_hw_configpcipowersave(ah, 1, 1);
+
+ spin_unlock_bh(&sc->sc_pcu_lock);
+
ath9k_ps_restore(sc);
- /* Finally, put the chip in FULL SLEEP mode */
- ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
+ sc->ps_idle = true;
+ ath9k_set_wiphy_idle(aphy, true);
+ ath_radio_disable(sc, hw);
sc->sc_flags |= SC_OP_INVALID;
+ pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE);
+
mutex_unlock(&sc->mutex);
- ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
@@ -1450,14 +1371,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ic_opmode = vif->type;
break;
default:
- ath_print(common, ATH_DBG_FATAL,
- "Interface type %d not yet supported\n", vif->type);
+ ath_err(common, "Interface type %d not yet supported\n",
+ vif->type);
ret = -EOPNOTSUPP;
goto out;
}
- ath_print(common, ATH_DBG_CONFIG,
- "Attach a VIF of type: %d\n", ic_opmode);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Attach a VIF of type: %d\n", ic_opmode);
/* Set the VIF opmode */
avp->av_opmode = ic_opmode;
@@ -1493,8 +1414,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(ah, ah->imask);
if (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MONITOR) {
+ vif->type == NL80211_IFTYPE_ADHOC) {
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
}
@@ -1504,16 +1424,83 @@ out:
return ret;
}
+static void ath9k_reclaim_beacon(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ /* Disable SWBA interrupt */
+ sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+ tasklet_kill(&sc->bcon_tasklet);
+ ath9k_ps_restore(sc);
+
+ ath_beacon_return(sc, avp);
+ sc->sc_flags &= ~SC_OP_BEACONS;
+
+ if (sc->nbcnvifs > 0) {
+ /* Re-enable beaconing */
+ sc->sc_ah->imask |= ATH9K_INT_SWBA;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+ ath9k_ps_restore(sc);
+ }
+}
+
+static int ath9k_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type,
+ bool p2p)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int ret = 0;
+
+ ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
+ mutex_lock(&sc->mutex);
+
+ switch (new_type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ if (sc->nbcnvifs >= ATH_BCBUF) {
+ ath_err(common, "No beacon slot available\n");
+ ret = -ENOBUFS;
+ goto out;
+ }
+ break;
+ case NL80211_IFTYPE_STATION:
+ /* Stop ANI */
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ del_timer_sync(&common->ani.timer);
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC))
+ ath9k_reclaim_beacon(sc, vif);
+ break;
+ default:
+ ath_err(common, "Interface type %d not yet supported\n",
+ vif->type);
+ ret = -ENOTSUPP;
+ goto out;
+ }
+ vif->type = new_type;
+ vif->p2p = p2p;
+
+out:
+ mutex_unlock(&sc->mutex);
+ return ret;
+}
+
static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp = (void *)vif->drv_priv;
- int i;
- ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&sc->mutex);
@@ -1524,23 +1511,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
/* Reclaim beacon resources */
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
- ath9k_ps_wakeup(sc);
- ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
- ath9k_ps_restore(sc);
- }
-
- ath_beacon_return(sc, avp);
- sc->sc_flags &= ~SC_OP_BEACONS;
-
- for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
- if (sc->beacon.bslot[i] == vif) {
- printk(KERN_DEBUG "%s: vif had allocated beacon "
- "slot\n", __func__);
- sc->beacon.bslot[i] = NULL;
- sc->beacon.bslot_aphy[i] = NULL;
- }
- }
+ (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT))
+ ath9k_reclaim_beacon(sc, vif);
sc->nvifs--;
@@ -1620,8 +1592,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (enable_radio) {
sc->ps_idle = false;
ath_radio_enable(sc, hw);
- ath_print(common, ATH_DBG_CONFIG,
- "not-idle: enabling radio\n");
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
}
}
@@ -1643,9 +1615,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (conf->flags & IEEE80211_CONF_MONITOR) {
- ath_print(common, ATH_DBG_CONFIG,
- "HW opmode set to Monitor mode\n");
- sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Monitor mode is enabled\n");
+ sc->sc_ah->is_monitoring = true;
+ } else {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Monitor mode is disabled\n");
+ sc->sc_ah->is_monitoring = false;
}
}
@@ -1676,14 +1652,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
goto skip_chan_change;
}
- ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
- curchan->center_freq);
+ ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ curchan->center_freq);
/* XXX: remove me eventualy */
ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
- ath_update_chainmask(sc, conf_is_ht(conf));
-
/* update survey stats for the old channel before switching */
spin_lock_irqsave(&common->cc_lock, flags);
ath_update_survey_stats(sc);
@@ -1710,8 +1684,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to set channel\n");
+ ath_err(common, "Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL;
}
@@ -1736,7 +1709,7 @@ skip_chan_change:
spin_unlock_bh(&sc->wiphy_lock);
if (disable_radio) {
- ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
sc->ps_idle = true;
ath_radio_disable(sc, hw);
}
@@ -1775,8 +1748,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
- "Set HW RX filter: 0x%x\n", rfilt);
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Set HW RX filter: 0x%x\n", rfilt);
}
static int ath9k_sta_add(struct ieee80211_hw *hw,
@@ -1809,12 +1782,15 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_txq *txq;
struct ath9k_tx_queue_info qi;
- int ret = 0, qnum;
+ int ret = 0;
if (queue >= WME_NUM_AC)
return 0;
+ txq = sc->tx.txq_map[queue];
+
mutex_lock(&sc->mutex);
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -1823,20 +1799,18 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
qi.tqi_cwmin = params->cw_min;
qi.tqi_cwmax = params->cw_max;
qi.tqi_burstTime = params->txop;
- qnum = ath_get_hal_qnum(queue, sc);
- ath_print(common, ATH_DBG_CONFIG,
- "Configure tx [queue/halq] [%d/%d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- queue, qnum, params->aifs, params->cw_min,
- params->cw_max, params->txop);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, txq->axq_qnum, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
- ret = ath_txq_update(sc, qnum, &qi);
+ ret = ath_txq_update(sc, txq->axq_qnum, &qi);
if (ret)
- ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+ ath_err(common, "TXQ Update failed\n");
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
- if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret)
+ if (queue == WME_AC_BE && !ret)
ath_beaconq_config(sc);
mutex_unlock(&sc->mutex);
@@ -1855,12 +1829,12 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
- if (modparam_nohwcrypt)
+ if (ath9k_modparam_nohwcrypt)
return -ENOSPC;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
- ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
@@ -1915,13 +1889,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
/* Set aggregation protection mode parameters */
sc->config.ath_aggr_prot = 0;
- /* Only legacy IBSS for now */
- if (vif->type == NL80211_IFTYPE_ADHOC)
- ath_update_chainmask(sc, 0);
-
- ath_print(common, ATH_DBG_CONFIG,
- "BSSID: %pM aid: 0x%x\n",
- common->curbssid, common->curaid);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
+ common->curbssid, common->curaid);
/* need to reconfigure the beacon */
sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -1977,8 +1946,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
- bss_conf->use_short_preamble);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
else
@@ -1986,8 +1955,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
- bss_conf->use_cts_prot);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
+ bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
sc->sc_flags |= SC_OP_PROTECT_ENABLE;
@@ -1996,9 +1965,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ASSOC) {
- ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc);
- ath9k_bss_assoc_info(sc, vif, bss_conf);
+ ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
}
mutex_unlock(&sc->mutex);
@@ -2011,7 +1980,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
+ ath9k_ps_wakeup(sc);
tsf = ath9k_hw_gettsf64(sc->sc_ah);
+ ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
return tsf;
@@ -2023,7 +1994,9 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
+ ath9k_ps_wakeup(sc);
ath9k_hw_settsf64(sc->sc_ah, tsf);
+ ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
}
@@ -2061,6 +2034,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
+ if (!(sc->sc_flags & SC_OP_TXAGGR))
+ return -EOPNOTSUPP;
+
ath9k_ps_wakeup(sc);
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (!ret)
@@ -2079,8 +2055,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath9k_ps_restore(sc);
break;
default:
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Unknown AMPDU action\n");
+ ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
}
local_bh_enable();
@@ -2180,6 +2155,7 @@ struct ieee80211_ops ath9k_ops = {
.start = ath9k_start,
.stop = ath9k_stop,
.add_interface = ath9k_add_interface,
+ .change_interface = ath9k_change_interface,
.remove_interface = ath9k_remove_interface,
.config = ath9k_config,
.configure_filter = ath9k_configure_filter,
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index b5b651413e77..78ef1f13386f 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -16,6 +16,7 @@
#include <linux/nl80211.h>
#include <linux/pci.h>
+#include <linux/ath9k_platform.h>
#include "ath9k.h"
static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
@@ -29,6 +30,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
+ { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */
{ 0 }
};
@@ -53,21 +55,35 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_hw *ah = (struct ath_hw *) common->ah;
-
- common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
- if (!ath9k_hw_wait(ah,
- AR_EEPROM_STATUS_DATA,
- AR_EEPROM_STATUS_DATA_BUSY |
- AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
- AH_WAIT_TIMEOUT)) {
- return false;
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath9k_platform_data *pdata = sc->dev->platform_data;
+
+ if (pdata) {
+ if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
+ ath_err(common,
+ "%s: eeprom read failed, offset %08x is out of range\n",
+ __func__, off);
+ }
+
+ *data = pdata->eeprom_data[off];
+ } else {
+ struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+ common->ops->read(ah, AR5416_EEPROM_OFFSET +
+ (off << AR5416_EEPROM_S));
+
+ if (!ath9k_hw_wait(ah,
+ AR_EEPROM_STATUS_DATA,
+ AR_EEPROM_STATUS_DATA_BUSY |
+ AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+ AH_WAIT_TIMEOUT)) {
+ return false;
+ }
+
+ *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
+ AR_EEPROM_STATUS_DATA_VAL);
}
- *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
- AR_EEPROM_STATUS_DATA_VAL);
-
return true;
}
@@ -80,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
struct pci_dev *pdev = to_pci_dev(sc->dev);
u8 aspm;
- if (!pdev->is_pcie)
+ if (!pci_is_pcie(pdev))
return;
pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
@@ -88,11 +104,23 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
}
+static void ath_pci_extn_synch_enable(struct ath_common *common)
+{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+ u8 lnkctl;
+
+ pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl);
+ lnkctl |= PCI_EXP_LNKCTL_ES;
+ pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
+}
+
static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath_pci_read_cachesize,
.eeprom_read = ath_pci_eeprom_read,
.bt_coex_prep = ath_pci_bt_coex_prep,
+ .extn_synch_en = ath_pci_extn_synch_enable,
};
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -236,6 +264,8 @@ static void ath_pci_remove(struct pci_dev *pdev)
struct ath_softc *sc = aphy->sc;
void __iomem *mem = sc->mem;
+ if (!is_ath9k_unloaded)
+ sc->sc_ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
@@ -247,34 +277,25 @@ static void ath_pci_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
-static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ath_pci_suspend(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
return 0;
}
-static int ath_pci_resume(struct pci_dev *pdev)
+static int ath_pci_resume(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
u32 val;
- int err;
-
- pci_restore_state(pdev);
-
- err = pci_enable_device(pdev);
- if (err)
- return err;
/*
* Suspend/Resume resets the PCI configuration space, so we have to
@@ -290,10 +311,38 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+ /*
+ * Reset key cache to sane defaults (all entries cleared) instead of
+ * semi-random values after suspend/resume.
+ */
+ ath9k_ps_wakeup(sc);
+ ath9k_init_crypto(sc);
+ ath9k_ps_restore(sc);
+
+ sc->ps_idle = true;
+ ath9k_set_wiphy_idle(aphy, true);
+ ath_radio_disable(sc, hw);
+
return 0;
}
-#endif /* CONFIG_PM */
+static const struct dev_pm_ops ath9k_pm_ops = {
+ .suspend = ath_pci_suspend,
+ .resume = ath_pci_resume,
+ .freeze = ath_pci_suspend,
+ .thaw = ath_pci_resume,
+ .poweroff = ath_pci_suspend,
+ .restore = ath_pci_resume,
+};
+
+#define ATH9K_PM_OPS (&ath9k_pm_ops)
+
+#else /* !CONFIG_PM */
+
+#define ATH9K_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
+
MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
@@ -302,10 +351,7 @@ static struct pci_driver ath_pci_driver = {
.id_table = ath_pci_id_table,
.probe = ath_pci_probe,
.remove = ath_pci_remove,
-#ifdef CONFIG_PM
- .suspend = ath_pci_suspend,
- .resume = ath_pci_resume,
-#endif /* CONFIG_PM */
+ .driver.pm = ATH9K_PM_OPS,
};
int ath_pci_init(void)
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 17969af842f6..5e3d7496986e 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -19,6 +19,7 @@
#define CHANSEL_DIV 15
#define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV)
+#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV)
#define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV)
#define AR_PHY_BASE 0x9800
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 89978d71617f..e45147820eae 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -381,25 +381,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
struct ieee80211_tx_rate *rate);
-static inline int8_t median(int8_t a, int8_t b, int8_t c)
-{
- if (a >= b) {
- if (b >= c)
- return b;
- else if (a > c)
- return c;
- else
- return a;
- } else {
- if (a >= c)
- return a;
- else if (b >= c)
- return c;
- else
- return b;
- }
-}
-
static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv)
{
@@ -419,7 +400,7 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
}
}
-static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
+static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv)
{
u8 i;
@@ -427,7 +408,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
ath_rc_priv->valid_rate_index[i] = 0;
}
-static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
+static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
BUG_ON(index > ath_rc_priv->rate_table_size);
@@ -508,7 +489,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
+ ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1);
hi = i;
}
}
@@ -551,7 +532,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy]
[valid_rate_count] = j;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
+ ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
@@ -587,7 +568,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy]
[ath_rc_priv->valid_phy_ratecnt[phy]] = j;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
+ ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
@@ -883,7 +864,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
bool state_change = false;
int count, n_bad_frames;
u8 last_per;
- static u32 nretry_to_per_lookup[10] = {
+ static const u32 nretry_to_per_lookup[10] = {
100 * 0 / 1,
100 * 1 / 4,
100 * 1 / 2,
@@ -1106,13 +1087,13 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
struct ieee80211_tx_rate *rate)
{
int rix = 0, i = 0;
- int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
+ static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
while (rate->idx > mcs_rix_off[i] &&
- i < sizeof(mcs_rix_off)/sizeof(int)) {
+ i < ARRAY_SIZE(mcs_rix_off)) {
rix++; i++;
}
@@ -1203,7 +1184,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
return &ar5416_11na_ratetable;
return &ar5416_11a_ratetable;
default:
- ath_print(common, ATH_DBG_CONFIG, "Invalid band\n");
+ ath_dbg(common, ATH_DBG_CONFIG, "Invalid band\n");
return NULL;
}
}
@@ -1229,7 +1210,7 @@ static void ath_rc_init(struct ath_softc *sc,
}
/* Determine the valid rates */
- ath_rc_init_valid_txmask(ath_rc_priv);
+ ath_rc_init_valid_rate_idx(ath_rc_priv);
for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < MAX_TX_RATE_PHY; j++)
@@ -1278,9 +1259,9 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
ath_rc_priv->rate_table = rate_table;
- ath_print(common, ATH_DBG_CONFIG,
- "RC Initialized with capabilities: 0x%x\n",
- ath_rc_priv->ht_cap);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "RC Initialized with capabilities: 0x%x\n",
+ ath_rc_priv->ht_cap);
}
static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1340,7 +1321,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ath_rate_priv *ath_rc_priv = priv_sta;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
- int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
+ int final_ts_idx = 0, tx_status = 0;
int long_retry = 0;
__le16 fc;
int i;
@@ -1373,32 +1354,17 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_info->status.ampdu_len = 1;
}
- /*
- * If an underrun error is seen assume it as an excessive retry only
- * if max frame trigger level has been reached (2 KB for singel stream,
- * and 4 KB for dual stream). Adjust the long retry as if the frame was
- * tried hw->max_rate_tries times to affect how ratectrl updates PER for
- * the failed rate. In case of congestion on the bus penalizing these
- * type of underruns should help hardware actually transmit new frames
- * successfully by eventually preferring slower rates. This itself
- * should also alleviate congestion on the bus.
- */
- if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
- (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
- tx_status = 1;
- is_underrun = 1;
- }
-
- if (tx_info->pad[0] & ATH_TX_INFO_XRETRY)
+ if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- (is_underrun) ? sc->hw->max_rate_tries : long_retry);
+ long_retry);
/* Check if aggregation has to be enabled for this tid */
if (conf_is_ht(&sc->hw->conf) &&
!(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- if (ieee80211_is_data_qos(fc)) {
+ if (ieee80211_is_data_qos(fc) &&
+ skb_get_queue_mapping(skb) != IEEE80211_AC_VO) {
u8 *qc, tid;
struct ath_node *an;
@@ -1407,7 +1373,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
an = (struct ath_node *)sta->drv_priv;
if(ath_tx_aggr_check(sc, an, tid))
- ieee80211_start_tx_ba_session(sta, tid);
+ ieee80211_start_tx_ba_session(sta, tid, 0);
}
}
@@ -1444,12 +1410,12 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
- is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ is_cw40 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
if (is_cw40)
- is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+ is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
- is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+ is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
/* Choose rate table first */
@@ -1468,10 +1434,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table = NULL;
bool oper_cw40 = false, oper_sgi;
- bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
- true : false;
- bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
- true : false;
+ bool local_cw40 = !!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
+ bool local_sgi = !!(ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG);
/* FIXME: Handle AP mode later when we support CWM */
@@ -1499,9 +1463,9 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
oper_cw40, oper_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
- "Operating HT Bandwidth changed to: %d\n",
- sc->hw->conf.channel_type);
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Operating HT Bandwidth changed to: %d\n",
+ sc->hw->conf.channel_type);
}
}
}
@@ -1612,13 +1576,11 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
if (!rate_priv) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Unable to allocate private rc structure\n");
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "Unable to allocate private rc structure\n");
return NULL;
}
- rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
-
return rate_priv;
}
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 2f46a2266ba1..5d984b8acdb1 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -195,7 +195,6 @@ struct ath_rc_stats {
* @rate_max_phy: phy index for the max rate
* @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
- * @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
* @neg_rates: Negotatied rates
* @neg_ht_rates: Negotiated HT rates
@@ -214,22 +213,14 @@ struct ath_rate_priv {
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
- u32 prev_data_rix;
- u32 tx_triglevel_max;
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
- struct ath_rate_softc *asc;
const struct ath_rate_table *rate_table;
struct dentry *debugfs_rcstats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
};
-#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0)
-#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1)
-#define ATH_TX_INFO_XRETRY (1 << 3)
-#define ATH_TX_INFO_UNDERRUN (1 << 4)
-
enum ath9k_internal_frame_type {
ATH9K_IFT_NOT_INTERNAL,
ATH9K_IFT_PAUSE,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index fddb0129bb57..b2497b8601e5 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -165,7 +165,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,
u32 nbuf = 0;
if (list_empty(&sc->rx.rxbuf)) {
- ath_print(common, ATH_DBG_QUEUE, "No free rx buf available\n");
+ ath_dbg(common, ATH_DBG_QUEUE, "No free rx buf available\n");
return;
}
@@ -269,7 +269,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(common, ATH_DBG_FATAL,
+ ath_err(common,
"dma_mapping_error() on RX init\n");
error = -ENOMEM;
goto rx_init_fail;
@@ -317,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
struct ath_buf *bf;
int error = 0;
- spin_lock_init(&sc->rx.pcu_lock);
+ spin_lock_init(&sc->sc_pcu_lock);
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->rx.rxbuflock);
@@ -327,17 +327,17 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(common->cachelsz, (u16)64));
- ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- common->cachelsz, common->rx_bufsize);
+ ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+ common->cachelsz, common->rx_bufsize);
/* Initialize rx descriptors */
error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
"rx", nbufs, 1, 0);
if (error != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "failed to allocate rx descriptors: %d\n",
- error);
+ ath_err(common,
+ "failed to allocate rx descriptors: %d\n",
+ error);
goto err;
}
@@ -358,8 +358,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(common, ATH_DBG_FATAL,
- "dma_mapping_error() on RX init\n");
+ ath_err(common,
+ "dma_mapping_error() on RX init\n");
error = -ENOMEM;
goto err;
}
@@ -441,7 +441,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
*/
if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
(sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR))
+ (sc->sc_ah->is_monitoring))
rfilt |= ATH9K_RX_FILTER_PROM;
if (sc->rx.rxfilter & FIF_CONTROL)
@@ -518,7 +518,7 @@ bool ath_stoprecv(struct ath_softc *sc)
bool stopped;
spin_lock_bh(&sc->rx.rxbuflock);
- ath9k_hw_stoppcurecv(ah);
+ ath9k_hw_abortpcurecv(ah);
ath9k_hw_setrxfilter(ah, 0);
stopped = ath9k_hw_stopdmarecv(ah);
@@ -528,6 +528,13 @@ bool ath_stoprecv(struct ath_softc *sc)
sc->rx.rxlink = NULL;
spin_unlock_bh(&sc->rx.rxbuflock);
+ if (!(ah->ah_flags & AH_UNPLUGGED) &&
+ unlikely(!stopped)) {
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "Could not stop RX, we could be "
+ "confusing the DMA engine when we start RX up\n");
+ ATH_DBG_WARN_ON_ONCE(!stopped);
+ }
return stopped;
}
@@ -588,9 +595,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (sc->ps_flags & PS_BEACON_SYNC) {
sc->ps_flags &= ~PS_BEACON_SYNC;
- ath_print(common, ATH_DBG_PS,
- "Reconfigure Beacon timers based on "
- "timestamp from the AP\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "Reconfigure Beacon timers based on timestamp from the AP\n");
ath_beacon_config(sc, NULL);
}
@@ -602,8 +608,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* a backup trigger for returning into NETWORK SLEEP state,
* so we are waiting for it as well.
*/
- ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
- "buffered broadcast/multicast frame(s)\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "Received DTIM beacon indicating buffered broadcast/multicast frame(s)\n");
sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON;
return;
}
@@ -615,8 +621,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* been delivered.
*/
sc->ps_flags &= ~PS_WAIT_FOR_CAB;
- ath_print(common, ATH_DBG_PS,
- "PS wait for CAB frames timed out\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "PS wait for CAB frames timed out\n");
}
}
@@ -641,15 +647,14 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* point.
*/
sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON);
- ath_print(common, ATH_DBG_PS,
- "All PS CAB frames received, back to sleep\n");
+ ath_dbg(common, ATH_DBG_PS,
+ "All PS CAB frames received, back to sleep\n");
} else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
- ath_print(common, ATH_DBG_PS,
- "Going back to sleep after having received "
- "PS-Poll data (0x%lx)\n",
+ ath_dbg(common, ATH_DBG_PS,
+ "Going back to sleep after having received PS-Poll data (0x%lx)\n",
sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA |
@@ -658,8 +663,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
}
static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
- struct ath_softc *sc, struct sk_buff *skb,
- struct ieee80211_rx_status *rxs)
+ struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -838,6 +842,10 @@ static bool ath9k_rx_accept(struct ath_common *common,
struct ath_rx_status *rx_stats,
bool *decrypt_error)
{
+#define is_mc_or_valid_tkip_keyix ((is_mc || \
+ (rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && \
+ test_bit(rx_stats->rs_keyix, common->tkip_keymap))))
+
struct ath_hw *ah = common->ah;
__le16 fc;
u8 rx_status_len = ah->caps.rx_status_len;
@@ -879,15 +887,18 @@ static bool ath9k_rx_accept(struct ath_common *common,
if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
*decrypt_error = true;
} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+ bool is_mc;
/*
* The MIC error bit is only valid if the frame
* is not a control frame or fragment, and it was
* decrypted using a valid TKIP key.
*/
+ is_mc = !!is_multicast_ether_addr(hdr->addr1);
+
if (!ieee80211_is_ctl(fc) &&
!ieee80211_has_morefrags(fc) &&
!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
- test_bit(rx_stats->rs_keyix, common->tkip_keymap))
+ is_mc_or_valid_tkip_keyix)
rxs->flag |= RX_FLAG_MMIC_ERROR;
else
rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
@@ -897,7 +908,7 @@ static bool ath9k_rx_accept(struct ath_common *common,
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
- if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+ if (ah->is_monitoring) {
if (rx_stats->rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_CRC))
@@ -951,8 +962,9 @@ static int ath9k_process_rate(struct ath_common *common,
* No valid hardware bitrate found -- we should not get here
* because hardware has already validated this frame as OK.
*/
- ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
- "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
+ ath_dbg(common, ATH_DBG_XMIT,
+ "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
+ rx_stats->rs_rate);
return -EINVAL;
}
@@ -962,36 +974,23 @@ static void ath9k_process_rssi(struct ath_common *common,
struct ieee80211_hdr *hdr,
struct ath_rx_status *rx_stats)
{
+ struct ath_wiphy *aphy = hw->priv;
struct ath_hw *ah = common->ah;
- struct ieee80211_sta *sta;
- struct ath_node *an;
- int last_rssi = ATH_RSSI_DUMMY_MARKER;
+ int last_rssi;
__le16 fc;
+ if (ah->opmode != NL80211_IFTYPE_STATION)
+ return;
+
fc = hdr->frame_control;
+ if (!ieee80211_is_beacon(fc) ||
+ compare_ether_addr(hdr->addr3, common->curbssid))
+ return;
- rcu_read_lock();
- /*
- * XXX: use ieee80211_find_sta! This requires quite a bit of work
- * under the current ath9k virtual wiphy implementation as we have
- * no way of tying a vif to wiphy. Typically vifs are attached to
- * at least one sdata of a wiphy on mac80211 but with ath9k virtual
- * wiphy you'd have to iterate over every wiphy and each sdata.
- */
- if (is_multicast_ether_addr(hdr->addr1))
- sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
- else
- sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, hdr->addr1);
-
- if (sta) {
- an = (struct ath_node *) sta->drv_priv;
- if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
- !rx_stats->rs_moreaggr)
- ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
- last_rssi = an->last_rssi;
- }
- rcu_read_unlock();
+ if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
+ ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi);
+ last_rssi = aphy->last_rssi;
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
ATH_RSSI_EP_MULTIPLIER);
@@ -999,8 +998,7 @@ static void ath9k_process_rssi(struct ath_common *common,
rx_stats->rs_rssi = 0;
/* Update Beacon RSSI, this is used by ANI. */
- if (ieee80211_is_beacon(fc))
- ah->stats.avgbrssi = rx_stats->rs_rssi;
+ ah->stats.avgbrssi = rx_stats->rs_rssi;
}
/*
@@ -1630,7 +1628,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
/*
- * The hw can techncically differ from common->hw when using ath9k
+ * The hw can technically differ from common->hw when using ath9k
* virtual wiphy so to account for that we iterate over the active
* wiphys and find the appropriate wiphy and therefore hw.
*/
@@ -1737,9 +1735,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(common, ATH_DBG_FATAL,
- "dma_mapping_error() on RX\n");
- ath_rx_send_to_mac80211(hw, sc, skb, rxs);
+ ath_err(common, "dma_mapping_error() on RX\n");
+ ath_rx_send_to_mac80211(hw, sc, skb);
break;
}
@@ -1755,17 +1752,18 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
}
spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (unlikely(ath9k_check_auto_sleep(sc) ||
- (sc->ps_flags & (PS_WAIT_FOR_BEACON |
+
+ if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
- PS_WAIT_FOR_PSPOLL_DATA))))
+ PS_WAIT_FOR_PSPOLL_DATA)) ||
+ unlikely(ath9k_check_auto_sleep(sc)))
ath_rx_ps(sc, skb);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
ath_ant_comb_scan(sc, &rs);
- ath_rx_send_to_mac80211(hw, sc, skb, rxs);
+ ath_rx_send_to_mac80211(hw, sc, skb);
requeue:
if (edma) {
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 42976b0a01c1..4df5659c6c16 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -703,6 +703,7 @@
#define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
#define AR_WA_ANALOG_SHIFT (1 << 20)
#define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */
+#define AR_WA_BIT22 (1 << 22)
#define AR9285_WA_DEFAULT 0x004a050b
#define AR9280_WA_DEFAULT 0x0040073b
#define AR_WA_DEFAULT 0x0000073f
@@ -786,6 +787,8 @@
#define AR_SREV_REVISION_9271_11 1
#define AR_SREV_VERSION_9300 0x1c0
#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
+#define AR_SREV_VERSION_9485 0x240
+#define AR_SREV_REVISION_9485_10 0
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -858,14 +861,24 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
+#define AR_SREV_9485(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
+#define AR_SREV_9485_10(_ah) \
+ (AR_SREV_9485(_ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
+
#define AR_SREV_9285E_20(_ah) \
(AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
+enum ath_usb_dev {
+ AR9280_USB = 1, /* AR7010 + AR9280, UB94 */
+ AR9287_USB = 2, /* AR7010 + AR9287, UB95 */
+};
+
#define AR_DEVID_7010(_ah) \
- (((_ah)->hw_version.devid == 0x7010) || \
- ((_ah)->hw_version.devid == 0x7015) || \
- ((_ah)->hw_version.devid == 0x9018))
+ (((_ah)->hw_version.usbdev == AR9280_USB) || \
+ ((_ah)->hw_version.usbdev == AR9287_USB))
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
@@ -977,11 +990,13 @@ enum {
#define AR9287_GPIO_IN_VAL_S 11
#define AR9271_GPIO_IN_VAL 0xFFFF0000
#define AR9271_GPIO_IN_VAL_S 16
-#define AR9300_GPIO_IN_VAL 0x0001FFFF
-#define AR9300_GPIO_IN_VAL_S 0
#define AR7010_GPIO_IN_VAL 0x0000FFFF
#define AR7010_GPIO_IN_VAL_S 0
+#define AR_GPIO_IN 0x404c
+#define AR9300_GPIO_IN_VAL 0x0001FFFF
+#define AR9300_GPIO_IN_VAL_S 0
+
#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
#define AR_GPIO_OE_OUT_DRV 0x3
#define AR_GPIO_OE_OUT_DRV_NO 0x0
@@ -1065,6 +1080,9 @@ enum {
#define AR_INTR_PRIO_ASYNC_MASK 0x40c8
#define AR_INTR_PRIO_SYNC_MASK 0x40cc
#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4
+#define AR_ENT_OTP 0x40d8
+#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000
+#define AR_ENT_OTP_MPSD 0x00800000
#define AR_RTC_9300_PLL_DIV 0x000003ff
#define AR_RTC_9300_PLL_DIV_S 0
@@ -1102,6 +1120,8 @@ enum {
#define AR_RTC_PLL_CONTROL \
((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014)
+#define AR_RTC_PLL_CONTROL2 0x703c
+
#define AR_RTC_PLL_DIV 0x0000001f
#define AR_RTC_PLL_DIV_S 0
#define AR_RTC_PLL_DIV2 0x00000020
@@ -1565,6 +1585,7 @@ enum {
#define AR_PCU_TBTT_PROTECT 0x00200000
#define AR_PCU_CLEAR_VMF 0x01000000
#define AR_PCU_CLEAR_BA_VALID 0x04000000
+#define AR_PCU_ALWAYS_PERFORM_KEYSEARCH 0x10000000
#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000
#define AR_PCU_BT_ANT_PREVENT_RX_S 20
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index ec7cf5ee56bc..2dc7095e56d1 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -107,6 +107,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
aphy->sc = sc;
aphy->hw = hw;
sc->sec_wiphy[i] = aphy;
+ aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
spin_unlock_bh(&sc->wiphy_lock);
memcpy(addr, common->macaddr, ETH_ALEN);
@@ -186,7 +187,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
info->control.rates[1].idx = -1;
memset(&txctl, 0, sizeof(struct ath_tx_control));
- txctl.txq = &sc->tx.txq[sc->tx.hwq_map[WME_AC_VO]];
+ txctl.txq = sc->tx.txq_map[WME_AC_VO];
txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
@@ -287,7 +288,6 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
/* sync hw configuration for hw code */
common->hw = aphy->hw;
- ath_update_chainmask(sc, sc->chan_is_ht);
if (ath_set_channel(sc, aphy->hw,
&sc->sc_ah->channels[sc->chan_idx]) < 0) {
printk(KERN_DEBUG "ath9k: Failed to set channel for new "
@@ -304,13 +304,12 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
* ath9k version of ieee80211_tx_status() for TX frames that are generated
* internally in the driver.
*/
-void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype)
{
struct ath_wiphy *aphy = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) &&
- aphy->state == ATH_WIPHY_PAUSING) {
+ if (ftype == ATH9K_IFT_PAUSE && aphy->state == ATH_WIPHY_PAUSING) {
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
"frame\n", wiphy_name(hw->wiphy));
@@ -656,10 +655,9 @@ void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
struct ath_softc *sc = aphy->sc;
aphy->idle = idle;
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
- "Marking %s as %s\n",
- wiphy_name(aphy->hw->wiphy),
- idle ? "idle" : "not-idle");
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Marking %s as %sidle\n",
+ wiphy_name(aphy->hw->wiphy), idle ? "" : "not-");
}
/* Only bother starting a queue on an active virtual wiphy */
bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 93a8bda09c25..dc862f5e1162 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -120,17 +120,27 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi);
}
-void ath9k_wmi_tasklet(unsigned long data)
+void ath9k_swba_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
struct ath_common *common = ath9k_hw_common(priv->ah);
- ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");
+ ath_dbg(common, ATH_DBG_WMI, "SWBA Event received\n");
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
}
+void ath9k_fatal_work(struct work_struct *work)
+{
+ struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+ fatal_work);
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+
+ ath_dbg(common, ATH_DBG_FATAL, "FATAL Event received, resetting device\n");
+ ath9k_htc_reset(priv);
+}
+
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
{
skb_pull(skb, sizeof(struct wmi_cmd_hdr));
@@ -163,7 +173,11 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
switch (cmd_id) {
case WMI_SWBA_EVENTID:
wmi->beacon_pending = *(u8 *)wmi_event;
- tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
+ tasklet_schedule(&wmi->drv_priv->swba_tasklet);
+ break;
+ case WMI_FATAL_EVENTID:
+ ieee80211_queue_work(wmi->drv_priv->hw,
+ &wmi->drv_priv->fatal_work);
break;
case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
@@ -250,7 +264,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
int time_left, ret = 0;
unsigned long flags;
- if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
+ if (ah->ah_flags & AH_UNPLUGGED)
return 0;
skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
@@ -286,9 +300,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
if (!time_left) {
- ath_print(common, ATH_DBG_WMI,
- "Timeout waiting for WMI command: %s\n",
- wmi_cmd_to_name(cmd_id));
+ ath_dbg(common, ATH_DBG_WMI,
+ "Timeout waiting for WMI command: %s\n",
+ wmi_cmd_to_name(cmd_id));
mutex_unlock(&wmi->op_mutex);
return -ETIMEDOUT;
}
@@ -298,8 +312,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
return 0;
out:
- ath_print(common, ATH_DBG_WMI,
- "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
+ ath_dbg(common, ATH_DBG_WMI,
+ "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
mutex_unlock(&wmi->op_mutex);
kfree_skb(skb);
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index ac61074af8ac..42084277522d 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -117,7 +117,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
u8 *cmd_buf, u32 cmd_len,
u8 *rsp_buf, u32 rsp_len,
u32 timeout);
-void ath9k_wmi_tasklet(unsigned long data);
+void ath9k_swba_tasklet(unsigned long data);
+void ath9k_fatal_work(struct work_struct *work);
#define WMI_CMD(_wmi_cmd) \
do { \
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index f2ade2402ce2..332d1feb5c18 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -48,19 +48,17 @@ static u16 bits_per_symbol[][2] = {
#define IS_HT_RATE(_rate) ((_rate) & 0x80)
-static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid,
- struct list_head *bf_head);
+static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
struct ath_txq *txq, struct list_head *bf_q,
struct ath_tx_status *ts, int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head);
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
-static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
- struct ath_tx_status *ts, int txok);
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
- int nbad, int txok, bool update_rc);
+ int nframes, int nbad, int txok, bool update_rc);
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
int seqno);
@@ -124,7 +122,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
- struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
+ struct ath_txq *txq = tid->ac->txq;
WARN_ON(!tid->paused);
@@ -140,12 +138,21 @@ unlock:
spin_unlock_bh(&txq->axq_lock);
}
+static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ BUILD_BUG_ON(sizeof(struct ath_frame_info) >
+ sizeof(tx_info->rate_driver_data));
+ return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
+}
+
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
- struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
+ struct ath_txq *txq = tid->ac->txq;
struct ath_buf *bf;
struct list_head bf_head;
struct ath_tx_status ts;
+ struct ath_frame_info *fi;
INIT_LIST_HEAD(&bf_head);
@@ -156,12 +163,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
list_move_tail(&bf->list, &bf_head);
- if (bf_isretried(bf)) {
- ath_tx_update_baw(sc, tid, bf->bf_seqno);
+ spin_unlock_bh(&txq->axq_lock);
+ fi = get_frame_info(bf->bf_mpdu);
+ if (fi->retries) {
+ ath_tx_update_baw(sc, tid, fi->seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
} else {
- ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
+ ath_tx_send_normal(sc, txq, tid, &bf_head);
}
+ spin_lock_bh(&txq->axq_lock);
}
spin_unlock_bh(&txq->axq_lock);
@@ -184,14 +194,11 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
}
static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
- struct ath_buf *bf)
+ u16 seqno)
{
int index, cindex;
- if (bf_isretried(bf))
- return;
-
- index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
+ index = ATH_BA_INDEX(tid->seq_start, seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
__set_bit(cindex, tid->tx_buf);
@@ -215,6 +222,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf;
struct list_head bf_head;
struct ath_tx_status ts;
+ struct ath_frame_info *fi;
memset(&ts, 0, sizeof(ts));
INIT_LIST_HEAD(&bf_head);
@@ -226,8 +234,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
list_move_tail(&bf->list, &bf_head);
- if (bf_isretried(bf))
- ath_tx_update_baw(sc, tid, bf->bf_seqno);
+ fi = get_frame_info(bf->bf_mpdu);
+ if (fi->retries)
+ ath_tx_update_baw(sc, tid, fi->seqno);
spin_unlock(&txq->axq_lock);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
@@ -239,16 +248,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
}
static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_buf *bf)
+ struct sk_buff *skb)
{
- struct sk_buff *skb;
+ struct ath_frame_info *fi = get_frame_info(skb);
struct ieee80211_hdr *hdr;
- bf->bf_state.bf_type |= BUF_RETRY;
- bf->bf_retries++;
TX_STAT_INC(txq->axq_qnum, a_retries);
+ if (fi->retries++ > 0)
+ return;
- skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
}
@@ -298,9 +306,41 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
return tbf;
}
+static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_status *ts, int txok,
+ int *nframes, int *nbad)
+{
+ struct ath_frame_info *fi;
+ u16 seq_st = 0;
+ u32 ba[WME_BA_BMP_SIZE >> 5];
+ int ba_index;
+ int isaggr = 0;
+
+ *nbad = 0;
+ *nframes = 0;
+
+ isaggr = bf_isaggr(bf);
+ if (isaggr) {
+ seq_st = ts->ts_seqnum;
+ memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
+ }
+
+ while (bf) {
+ fi = get_frame_info(bf->bf_mpdu);
+ ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
+
+ (*nframes)++;
+ if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
+ (*nbad)++;
+
+ bf = bf->bf_next;
+ }
+}
+
+
static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct list_head *bf_q,
- struct ath_tx_status *ts, int txok)
+ struct ath_tx_status *ts, int txok, bool retry)
{
struct ath_node *an = NULL;
struct sk_buff *skb;
@@ -316,7 +356,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
struct ieee80211_tx_rate rates[4];
+ struct ath_frame_info *fi;
int nframes;
+ u8 tidno;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -325,7 +367,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
hw = bf->aphy->hw;
memcpy(rates, tx_info->control.rates, sizeof(rates));
- nframes = bf->bf_nframes;
rcu_read_lock();
@@ -342,7 +383,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!bf->bf_stale || bf_next != NULL)
list_move_tail(&bf->list, &bf_head);
- ath_tx_rc_status(bf, ts, 1, 0, false);
+ ath_tx_rc_status(bf, ts, 1, 1, 0, false);
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
0, 0);
@@ -352,14 +393,15 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
an = (struct ath_node *)sta->drv_priv;
- tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+ tid = ATH_AN_2_TID(an, tidno);
/*
* The hardware occasionally sends a tx status for the wrong TID.
* In this case, the BA status cannot be considered valid and all
* subframes need to be retransmitted
*/
- if (bf->bf_tidno != ts->tid)
+ if (tidno != ts->tid)
txok = false;
isaggr = bf_isaggr(bf);
@@ -385,15 +427,16 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_pending);
INIT_LIST_HEAD(&bf_head);
- nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
+ ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
while (bf) {
txfail = txpending = 0;
bf_next = bf->bf_next;
skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
+ fi = get_frame_info(skb);
- if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
+ if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
/* transmit completion, subframe is
* acked by block ack */
acked_cnt++;
@@ -401,10 +444,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* transmit completion */
acked_cnt++;
} else {
- if (!(tid->state & AGGR_CLEANUP) &&
- !bf_last->bf_tx_aborted) {
- if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, txq, bf);
+ if (!(tid->state & AGGR_CLEANUP) && retry) {
+ if (fi->retries < ATH_MAX_SW_RETRIES) {
+ ath_tx_set_retry(sc, txq, bf->bf_mpdu);
txpending = 1;
} else {
bf->bf_state.bf_type |= BUF_XRETRY;
@@ -442,16 +484,15 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* block-ack window
*/
spin_lock_bh(&txq->axq_lock);
- ath_tx_update_baw(sc, tid, bf->bf_seqno);
+ ath_tx_update_baw(sc, tid, fi->seqno);
spin_unlock_bh(&txq->axq_lock);
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
memcpy(tx_info->control.rates, rates, sizeof(rates));
- bf->bf_nframes = nframes;
- ath_tx_rc_status(bf, ts, nbad, txok, true);
+ ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
rc_update = false;
} else {
- ath_tx_rc_status(bf, ts, nbad, txok, false);
+ ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
@@ -470,14 +511,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
*/
if (!tbf) {
spin_lock_bh(&txq->axq_lock);
- ath_tx_update_baw(sc, tid,
- bf->bf_seqno);
+ ath_tx_update_baw(sc, tid, fi->seqno);
spin_unlock_bh(&txq->axq_lock);
bf->bf_state.bf_type |=
BUF_XRETRY;
- ath_tx_rc_status(bf, ts, nbad,
- 0, false);
+ ath_tx_rc_status(bf, ts, nframes,
+ nbad, 0, false);
ath_tx_complete_buf(sc, bf, txq,
&bf_head,
ts, 0, 0);
@@ -611,6 +651,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
u16 minlen;
u8 flags, rix;
int width, streams, half_gi, ndelim, mindelim;
+ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
/* Select standard number of delimiters based on frame length alone */
ndelim = ATH_AGGR_GET_NDELIM(frmlen);
@@ -621,7 +662,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* TODO - this could be improved to be dependent on the rate.
* The hardware can keep up at lower rates, but not higher rates
*/
- if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
+ if (fi->keyix != ATH9K_TXKEYIX_INVALID)
ndelim += ATH_AGGR_ENCRYPTDELIM;
/*
@@ -665,7 +706,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_atx_tid *tid,
- struct list_head *bf_q)
+ struct list_head *bf_q,
+ int *aggr_len)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf, *bf_first, *bf_prev = NULL;
@@ -674,14 +716,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
al_delta, h_baw = tid->baw_size / 2;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
struct ieee80211_tx_info *tx_info;
+ struct ath_frame_info *fi;
bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
do {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
+ fi = get_frame_info(bf->bf_mpdu);
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
status = ATH_AGGR_BAW_CLOSED;
break;
}
@@ -692,7 +736,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
}
/* do not exceed aggregation limit */
- al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
+ al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
if (nframes &&
(aggr_limit < (al + bpad + al_delta + prev_al))) {
@@ -719,14 +763,15 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
* Get the delimiters needed to meet the MPDU
* density for this node.
*/
- ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
+ ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
bpad = PADBYTES(al_delta) + (ndelim << 2);
bf->bf_next = NULL;
ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
/* link buffers of this frame to the aggregate */
- ath_tx_addto_baw(sc, tid, bf);
+ if (!fi->retries)
+ ath_tx_addto_baw(sc, tid, fi->seqno);
ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
list_move_tail(&bf->list, bf_q);
if (bf_prev) {
@@ -738,8 +783,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
} while (!list_empty(&tid->buf_q));
- bf_first->bf_al = al;
- bf_first->bf_nframes = nframes;
+ *aggr_len = al;
return status;
#undef PADBYTES
@@ -750,7 +794,9 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
enum ATH_AGGR_STATUS status;
+ struct ath_frame_info *fi;
struct list_head bf_q;
+ int aggr_len;
do {
if (list_empty(&tid->buf_q))
@@ -758,7 +804,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_q);
- status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
+ status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
/*
* no frames picked up to be aggregated;
@@ -771,18 +817,20 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
/* if only one frame, send as non-aggregate */
- if (bf->bf_nframes == 1) {
+ if (bf == bf->bf_lastbf) {
+ fi = get_frame_info(bf->bf_mpdu);
+
bf->bf_state.bf_type &= ~BUF_AGGR;
ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- ath_buf_set_rate(sc, bf);
+ ath_buf_set_rate(sc, bf, fi->framelen);
ath_tx_txqaddbuf(sc, txq, &bf_q);
continue;
}
/* setup first desc of aggregate */
bf->bf_state.bf_type |= BUF_AGGR;
- ath_buf_set_rate(sc, bf);
- ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
+ ath_buf_set_rate(sc, bf, aggr_len);
+ ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
/* anchor last desc of aggregate */
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
@@ -790,7 +838,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_txqaddbuf(sc, txq, &bf_q);
TX_STAT_INC(txq->axq_qnum, a_aggr);
- } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
+ } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED);
}
@@ -817,7 +865,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
- struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
+ struct ath_txq *txq = txtid->ac->txq;
if (txtid->state & AGGR_CLEANUP)
return;
@@ -888,10 +936,16 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
+ static const int subtype_txq_to_hwq[] = {
+ [WME_AC_BE] = ATH_TXQ_AC_BE,
+ [WME_AC_BK] = ATH_TXQ_AC_BK,
+ [WME_AC_VI] = ATH_TXQ_AC_VI,
+ [WME_AC_VO] = ATH_TXQ_AC_VO,
+ };
int qnum, i;
memset(&qi, 0, sizeof(qi));
- qi.tqi_subtype = subtype;
+ qi.tqi_subtype = subtype_txq_to_hwq[subtype];
qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
@@ -931,22 +985,21 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return NULL;
}
if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
- ath_print(common, ATH_DBG_FATAL,
- "qnum %u out of range, max %u!\n",
- qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
+ ath_err(common, "qnum %u out of range, max %zu!\n",
+ qnum, ARRAY_SIZE(sc->tx.txq));
ath9k_hw_releasetxqueue(ah, qnum);
return NULL;
}
if (!ATH_TXQ_SETUP(sc, qnum)) {
struct ath_txq *txq = &sc->tx.txq[qnum];
- txq->axq_class = subtype;
txq->axq_qnum = qnum;
txq->axq_link = NULL;
INIT_LIST_HEAD(&txq->axq_q);
INIT_LIST_HEAD(&txq->axq_acq);
spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0;
+ txq->axq_ampdu_depth = 0;
txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
@@ -985,8 +1038,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
qi.tqi_readyTime = qinfo->tqi_readyTime;
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Unable to update hardware queue %u!\n", qnum);
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum);
@@ -1016,6 +1069,12 @@ int ath_cabq_update(struct ath_softc *sc)
return 0;
}
+static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+}
+
/*
* Drain a given TX queue (could be Beacon or Data)
*
@@ -1062,8 +1121,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
}
lastbf = bf->bf_lastbf;
- if (!retry_tx)
- lastbf->bf_tx_aborted = true;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
list_cut_position(&bf_head,
@@ -1076,11 +1133,13 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
}
txq->axq_depth--;
-
+ if (bf_is_ampdu_not_probing(bf))
+ txq->axq_ampdu_depth--;
spin_unlock_bh(&txq->axq_lock);
if (bf_isampdu(bf))
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
+ ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
+ retry_tx);
else
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
}
@@ -1101,7 +1160,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head,
- &ts, 0);
+ &ts, 0, retry_tx);
else
ath_tx_complete_buf(sc, bf, txq, &bf_head,
&ts, 0, 0);
@@ -1120,7 +1179,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
}
}
-void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1128,7 +1187,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
int i, npend = 0;
if (sc->sc_flags & SC_OP_INVALID)
- return;
+ return true;
/* Stop beacon queue */
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
@@ -1142,25 +1201,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
}
}
- if (npend) {
- int r;
-
- ath_print(common, ATH_DBG_FATAL,
- "Failed to stop TX DMA. Resetting hardware!\n");
-
- spin_lock_bh(&sc->sc_resetlock);
- r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
- if (r)
- ath_print(common, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n",
- r);
- spin_unlock_bh(&sc->sc_resetlock);
- }
+ if (npend)
+ ath_err(common, "Failed to stop TX DMA!\n");
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i))
ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
}
+
+ return !npend;
}
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
@@ -1212,24 +1261,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
}
}
-int ath_tx_setup(struct ath_softc *sc, int haltype)
-{
- struct ath_txq *txq;
-
- if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
- haltype, ARRAY_SIZE(sc->tx.hwq_map));
- return 0;
- }
- txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
- if (txq != NULL) {
- sc->tx.hwq_map[haltype] = txq->axq_qnum;
- return 1;
- } else
- return 0;
-}
-
/***********/
/* TX, DMA */
/***********/
@@ -1255,8 +1286,8 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(head, struct ath_buf, list);
- ath_print(common, ATH_DBG_QUEUE,
- "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+ ath_dbg(common, ATH_DBG_QUEUE,
+ "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
@@ -1264,47 +1295,45 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
return;
}
if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
- ath_print(common, ATH_DBG_XMIT,
- "Initializing tx fifo %d which "
- "is non-empty\n",
- txq->txq_headidx);
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Initializing tx fifo %d which is non-empty\n",
+ txq->txq_headidx);
INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- ath_print(common, ATH_DBG_XMIT,
- "TXDP[%u] = %llx (%p)\n",
- txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+ ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
} else {
list_splice_tail_init(head, &txq->axq_q);
if (txq->axq_link == NULL) {
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- ath_print(common, ATH_DBG_XMIT,
- "TXDP[%u] = %llx (%p)\n",
- txq->axq_qnum, ito64(bf->bf_daddr),
- bf->bf_desc);
+ ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr),
+ bf->bf_desc);
} else {
*txq->axq_link = bf->bf_daddr;
- ath_print(common, ATH_DBG_XMIT,
- "link[%u] (%p)=%llx (%p)\n",
- txq->axq_qnum, txq->axq_link,
- ito64(bf->bf_daddr), bf->bf_desc);
+ ath_dbg(common, ATH_DBG_XMIT,
+ "link[%u] (%p)=%llx (%p)\n",
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
}
ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
&txq->axq_link);
ath9k_hw_txstart(ah, txq->axq_qnum);
}
txq->axq_depth++;
+ if (bf_is_ampdu_not_probing(bf))
+ txq->axq_ampdu_depth++;
}
static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
- struct list_head *bf_head,
- struct ath_tx_control *txctl)
+ struct ath_buf *bf, struct ath_tx_control *txctl)
{
- struct ath_buf *bf;
+ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
+ struct list_head bf_head;
- bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type |= BUF_AMPDU;
TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
@@ -1316,56 +1345,47 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
* - h/w queue depth exceeds low water mark
*/
if (!list_empty(&tid->buf_q) || tid->paused ||
- !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
- txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
+ !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
+ txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
/*
* Add this frame to software queue for scheduling later
* for aggregation.
*/
- list_move_tail(&bf->list, &tid->buf_q);
+ list_add_tail(&bf->list, &tid->buf_q);
ath_tx_queue_tid(txctl->txq, tid);
return;
}
+ INIT_LIST_HEAD(&bf_head);
+ list_add(&bf->list, &bf_head);
+
/* Add sub-frame to BAW */
- ath_tx_addto_baw(sc, tid, bf);
+ if (!fi->retries)
+ ath_tx_addto_baw(sc, tid, fi->seqno);
/* Queue to h/w without aggregation */
- bf->bf_nframes = 1;
bf->bf_lastbf = bf;
- ath_buf_set_rate(sc, bf);
- ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
+ ath_buf_set_rate(sc, bf, fi->framelen);
+ ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
}
-static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid,
- struct list_head *bf_head)
+static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ struct list_head *bf_head)
{
+ struct ath_frame_info *fi;
struct ath_buf *bf;
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type &= ~BUF_AMPDU;
/* update starting sequence number for subsequent ADDBA request */
- INCR(tid->seq_start, IEEE80211_SEQ_MAX);
-
- bf->bf_nframes = 1;
- bf->bf_lastbf = bf;
- ath_buf_set_rate(sc, bf);
- ath_tx_txqaddbuf(sc, txq, bf_head);
- TX_STAT_INC(txq->axq_qnum, queued);
-}
-
-static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
- struct list_head *bf_head)
-{
- struct ath_buf *bf;
-
- bf = list_first_entry(bf_head, struct ath_buf, list);
+ if (tid)
+ INCR(tid->seq_start, IEEE80211_SEQ_MAX);
bf->bf_lastbf = bf;
- bf->bf_nframes = 1;
- ath_buf_set_rate(sc, bf);
+ fi = get_frame_info(bf->bf_mpdu);
+ ath_buf_set_rate(sc, bf, fi->framelen);
ath_tx_txqaddbuf(sc, txq, bf_head);
TX_STAT_INC(txq->axq_qnum, queued);
}
@@ -1393,40 +1413,52 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
return htype;
}
-static void assign_aggr_tid_seqno(struct sk_buff *skb,
- struct ath_buf *bf)
+static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
+ int framelen)
{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = tx_info->control.sta;
+ struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
struct ieee80211_hdr *hdr;
+ struct ath_frame_info *fi = get_frame_info(skb);
struct ath_node *an;
struct ath_atx_tid *tid;
- __le16 fc;
- u8 *qc;
+ enum ath9k_key_type keytype;
+ u16 seqno = 0;
+ u8 tidno;
- if (!tx_info->control.sta)
- return;
+ keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
- an = (struct ath_node *)tx_info->control.sta->drv_priv;
hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
+ if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+ conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
+
+ an = (struct ath_node *) sta->drv_priv;
+ tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
- bf->bf_tidno = qc[0] & 0xf;
+ /*
+ * Override seqno set by upper layer with the one
+ * in tx aggregation state.
+ */
+ tid = ATH_AN_2_TID(an, tidno);
+ seqno = tid->seq_next;
+ hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+ INCR(tid->seq_next, IEEE80211_SEQ_MAX);
}
- /*
- * For HT capable stations, we save tidno for later use.
- * We also override seqno set by upper layer with the one
- * in tx aggregation state.
- */
- tid = ATH_AN_2_TID(an, bf->bf_tidno);
- hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
- bf->bf_seqno = tid->seq_next;
- INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+ memset(fi, 0, sizeof(*fi));
+ if (hw_key)
+ fi->keyix = hw_key->hw_key_idx;
+ else
+ fi->keyix = ATH9K_TXKEYIX_INVALID;
+ fi->keytype = keytype;
+ fi->framelen = framelen;
+ fi->seqno = seqno;
}
-static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
+static int setup_tx_flags(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int flags = 0;
@@ -1437,7 +1469,7 @@ static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= ATH9K_TXDESC_NOACK;
- if (use_ldpc)
+ if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
flags |= ATH9K_TXDESC_LDPC;
return flags;
@@ -1449,13 +1481,11 @@ static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
* width - 0 for 20 MHz, 1 for 40 MHz
* half_gi - to use 4us v/s 3.6 us for symbol time
*/
-static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
int width, int half_gi, bool shortPreamble)
{
u32 nbits, nsymbits, duration, nsymbols;
- int streams, pktlen;
-
- pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
+ int streams;
/* find number of symbols: PLCP + data */
streams = HT_RC_2_STREAMS(rix);
@@ -1474,7 +1504,19 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
return duration;
}
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_channel *curchan = ah->curchan;
+ if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
+ (curchan->channelFlags & CHANNEL_5GHZ) &&
+ (chainmask == 0x7) && (rate < 0x90))
+ return 0x3;
+ else
+ return chainmask;
+}
+
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_11n_rate_series series[4];
@@ -1514,7 +1556,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- series[i].ChSel = common->tx_chainmask;
if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
@@ -1537,14 +1578,16 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
if (rates[i].flags & IEEE80211_TX_RC_MCS) {
/* MCS rates */
series[i].Rate = rix | 0x80;
- series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+ series[i].ChSel = ath_txchainmask_reduction(sc,
+ common->tx_chainmask, series[i].Rate);
+ series[i].PktDuration = ath_pkt_duration(sc, rix, len,
is_40, is_sgi, is_sp);
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
series[i].RateFlags |= ATH9K_RATESERIES_STBC;
continue;
}
- /* legcay rates */
+ /* legacy rates */
if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
phy = WLAN_RC_PHY_CCK;
@@ -1560,12 +1603,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
is_sp = false;
}
+ if (bf->bf_state.bfs_paprd)
+ series[i].ChSel = common->tx_chainmask;
+ else
+ series[i].ChSel = ath_txchainmask_reduction(sc,
+ common->tx_chainmask, series[i].Rate);
+
series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
- phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
+ phy, rate->bitrate * 100, len, rix, is_sp);
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
- if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
+ if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
flags &= ~ATH9K_TXDESC_RTSENA;
/* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
@@ -1582,67 +1631,29 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
}
-static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
- struct sk_buff *skb,
- struct ath_tx_control *txctl)
+static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
+ struct ath_txq *txq,
+ struct sk_buff *skb)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- int hdrlen;
- __le16 fc;
- int padpos, padsize;
- bool use_ldpc = false;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_frame_info *fi = get_frame_info(skb);
+ struct ath_buf *bf;
+ struct ath_desc *ds;
+ int frm_type;
- tx_info->pad[0] = 0;
- switch (txctl->frame_type) {
- case ATH9K_IFT_NOT_INTERNAL:
- break;
- case ATH9K_IFT_PAUSE:
- tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
- /* fall through */
- case ATH9K_IFT_UNPAUSE:
- tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
- break;
+ bf = ath_tx_get_buffer(sc);
+ if (!bf) {
+ ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
+ return NULL;
}
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
ATH_TXBUF_RESET(bf);
bf->aphy = aphy;
- bf->bf_frmlen = skb->len + FCS_LEN;
- /* Remove the padding size from bf_frmlen, if any */
- padpos = ath9k_cmn_padpos(hdr->frame_control);
- padsize = padpos & 3;
- if (padsize && skb->len>padpos+padsize) {
- bf->bf_frmlen -= padsize;
- }
-
- if (!txctl->paprd && conf_is_ht(&hw->conf)) {
- bf->bf_state.bf_type |= BUF_HT;
- if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
- use_ldpc = true;
- }
-
- bf->bf_state.bfs_paprd = txctl->paprd;
- if (txctl->paprd)
- bf->bf_state.bfs_paprd_timestamp = jiffies;
- bf->bf_flags = setup_tx_flags(skb, use_ldpc);
-
- bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
- if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
- bf->bf_frmlen += tx_info->control.hw_key->icv_len;
- bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
- } else {
- bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
- }
-
- if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
- (sc->sc_flags & SC_OP_TXAGGR))
- assign_aggr_tid_seqno(skb, bf);
-
+ bf->bf_flags = setup_tx_flags(skb);
bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
@@ -1650,42 +1661,19 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
bf->bf_mpdu = NULL;
bf->bf_buf_addr = 0;
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "dma_mapping_error() on TX\n");
- return -ENOMEM;
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "dma_mapping_error() on TX\n");
+ ath_tx_return_buffer(sc, bf);
+ return NULL;
}
- bf->bf_tx_aborted = false;
-
- return 0;
-}
-
-/* FIXME: tx power */
-static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
- struct ath_tx_control *txctl)
-{
- struct sk_buff *skb = bf->bf_mpdu;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ath_node *an = NULL;
- struct list_head bf_head;
- struct ath_desc *ds;
- struct ath_atx_tid *tid;
- struct ath_hw *ah = sc->sc_ah;
- int frm_type;
- __le16 fc;
-
frm_type = get_hw_packet_type(skb);
- fc = hdr->frame_control;
-
- INIT_LIST_HEAD(&bf_head);
- list_add_tail(&bf->list, &bf_head);
ds = bf->bf_desc;
ath9k_hw_set_desc_link(ah, ds, 0);
- ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
- bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
+ ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
+ fi->keyix, fi->keytype, bf->bf_flags);
ath9k_hw_filltxdesc(ah, ds,
skb->len, /* segment length */
@@ -1693,42 +1681,53 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
true, /* last segment */
ds, /* first descriptor */
bf->bf_buf_addr,
- txctl->txq->axq_qnum);
+ txq->axq_qnum);
+
- if (bf->bf_state.bfs_paprd)
- ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
+ return bf;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_control *txctl)
+{
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct list_head bf_head;
+ struct ath_atx_tid *tid = NULL;
+ u8 tidno;
spin_lock_bh(&txctl->txq->axq_lock);
- if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
- tx_info->control.sta) {
- an = (struct ath_node *)tx_info->control.sta->drv_priv;
- tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ if (ieee80211_is_data_qos(hdr->frame_control) && txctl->an) {
+ tidno = ieee80211_get_qos_ctl(hdr)[0] &
+ IEEE80211_QOS_CTL_TID_MASK;
+ tid = ATH_AN_2_TID(txctl->an, tidno);
- if (!ieee80211_is_data_qos(fc)) {
- ath_tx_send_normal(sc, txctl->txq, &bf_head);
- goto tx_done;
- }
+ WARN_ON(tid->ac->txq != txctl->txq);
+ }
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
- /*
- * Try aggregation if it's a unicast data frame
- * and the destination is HT capable.
- */
- ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
- } else {
- /*
- * Send this frame as regular when ADDBA
- * exchange is neither complete nor pending.
- */
- ath_tx_send_ht_normal(sc, txctl->txq,
- tid, &bf_head);
- }
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
+ /*
+ * Try aggregation if it's a unicast data frame
+ * and the destination is HT capable.
+ */
+ ath_tx_send_ampdu(sc, tid, bf, txctl);
} else {
- ath_tx_send_normal(sc, txctl->txq, &bf_head);
+ INIT_LIST_HEAD(&bf_head);
+ list_add_tail(&bf->list, &bf_head);
+
+ bf->bf_state.bfs_ftype = txctl->frame_type;
+ bf->bf_state.bfs_paprd = txctl->paprd;
+
+ if (bf->bf_state.bfs_paprd)
+ ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
+ bf->bf_state.bfs_paprd);
+
+ ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
}
-tx_done:
spin_unlock_bh(&txctl->txq->axq_lock);
}
@@ -1736,66 +1735,23 @@ tx_done:
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = info->control.sta;
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_txq *txq = txctl->txq;
struct ath_buf *bf;
- int q, r;
-
- bf = ath_tx_get_buffer(sc);
- if (!bf) {
- ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
- return -1;
- }
-
- r = ath_tx_setup_buffer(hw, bf, skb, txctl);
- if (unlikely(r)) {
- ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
-
- /* upon ath_tx_processq() this TX queue will be resumed, we
- * guarantee this will happen by knowing beforehand that
- * we will at least have to run TX completionon one buffer
- * on the queue */
- spin_lock_bh(&txq->axq_lock);
- if (!txq->stopped && txq->axq_depth > 1) {
- ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
- txq->stopped = 1;
- }
- spin_unlock_bh(&txq->axq_lock);
-
- ath_tx_return_buffer(sc, bf);
-
- return r;
- }
-
- q = skb_get_queue_mapping(skb);
- if (q >= 4)
- q = 0;
-
- spin_lock_bh(&txq->axq_lock);
- if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
- ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
- txq->stopped = 1;
- }
- spin_unlock_bh(&txq->axq_lock);
-
- ath_tx_start_dma(sc, bf, txctl);
-
- return 0;
-}
-
-void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
int padpos, padsize;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ath_tx_control txctl;
+ int frmlen = skb->len + FCS_LEN;
+ int q;
+
+ /* NOTE: sta can be NULL according to net/mac80211.h */
+ if (sta)
+ txctl->an = (struct ath_node *)sta->drv_priv;
- memset(&txctl, 0, sizeof(struct ath_tx_control));
+ if (info->control.hw_key)
+ frmlen += info->control.hw_key->icv_len;
/*
* As a temporary workaround, assign seq# here; this will likely need
@@ -1812,30 +1768,37 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
/* Add the padding after the header if this is not already done */
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
- if (padsize && skb->len>padpos) {
- if (skb_headroom(skb) < padsize) {
- ath_print(common, ATH_DBG_XMIT,
- "TX CABQ padding failed\n");
- dev_kfree_skb_any(skb);
- return;
- }
+ if (padsize && skb->len > padpos) {
+ if (skb_headroom(skb) < padsize)
+ return -ENOMEM;
+
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos);
}
- txctl.txq = sc->beacon.cabq;
+ setup_frame_info(hw, skb, frmlen);
- ath_print(common, ATH_DBG_XMIT,
- "transmitting CABQ packet, skb: %p\n", skb);
+ /*
+ * At this point, the vif, hw_key and sta pointers in the tx control
+ * info are no longer valid (overwritten by the ath_frame_info data.
+ */
+
+ bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
+ if (unlikely(!bf))
+ return -ENOMEM;
- if (ath_tx_start(hw, skb, &txctl) != 0) {
- ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
- goto exit;
+ q = skb_get_queue_mapping(skb);
+ spin_lock_bh(&txq->axq_lock);
+ if (txq == sc->tx.txq_map[q] &&
+ ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
+ ath_mac80211_stop_queue(sc, q);
+ txq->stopped = 1;
}
+ spin_unlock_bh(&txq->axq_lock);
- return;
-exit:
- dev_kfree_skb_any(skb);
+ ath_tx_start_dma(sc, bf, txctl);
+
+ return 0;
}
/*****************/
@@ -1843,7 +1806,8 @@ exit:
/*****************/
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- struct ath_wiphy *aphy, int tx_flags)
+ struct ath_wiphy *aphy, int tx_flags, int ftype,
+ struct ath_txq *txq)
{
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -1851,7 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int q, padpos, padsize;
- ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+ ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
if (aphy)
hw = aphy->hw;
@@ -1877,24 +1841,24 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
- ath_print(common, ATH_DBG_PS,
- "Going back to sleep after having "
- "received TX status (0x%lx)\n",
+ ath_dbg(common, ATH_DBG_PS,
+ "Going back to sleep after having received TX status (0x%lx)\n",
sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA |
PS_WAIT_FOR_TX_ACK));
}
- if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
- ath9k_tx_status(hw, skb);
+ if (unlikely(ftype))
+ ath9k_tx_status(hw, skb, ftype);
else {
q = skb_get_queue_mapping(skb);
- if (q >= 4)
- q = 0;
-
- if (--sc->tx.pending_frames[q] < 0)
- sc->tx.pending_frames[q] = 0;
+ if (txq == sc->tx.txq_map[q]) {
+ spin_lock_bh(&txq->axq_lock);
+ if (WARN_ON(--txq->pending_frames < 0))
+ txq->pending_frames = 0;
+ spin_unlock_bh(&txq->axq_lock);
+ }
ieee80211_tx_status(hw, skb);
}
@@ -1922,15 +1886,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
bf->bf_buf_addr = 0;
if (bf->bf_state.bfs_paprd) {
- if (time_after(jiffies,
- bf->bf_state.bfs_paprd_timestamp +
- msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
+ if (!sc->paprd_pending)
dev_kfree_skb_any(skb);
else
complete(&sc->paprd_complete);
} else {
- ath_debug_stat_tx(sc, txq, bf, ts);
- ath_tx_complete(sc, skb, bf->aphy, tx_flags);
+ ath_debug_stat_tx(sc, bf, ts);
+ ath_tx_complete(sc, skb, bf->aphy, tx_flags,
+ bf->bf_state.bfs_ftype, txq);
}
/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
* accidentally reference it later.
@@ -1945,42 +1908,15 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
}
-static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
- struct ath_tx_status *ts, int txok)
-{
- u16 seq_st = 0;
- u32 ba[WME_BA_BMP_SIZE >> 5];
- int ba_index;
- int nbad = 0;
- int isaggr = 0;
-
- if (bf->bf_lastbf->bf_tx_aborted)
- return 0;
-
- isaggr = bf_isaggr(bf);
- if (isaggr) {
- seq_st = ts->ts_seqnum;
- memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
- }
-
- while (bf) {
- ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
- if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
- nbad++;
-
- bf = bf->bf_next;
- }
-
- return nbad;
-}
-
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
- int nbad, int txok, bool update_rc)
+ int nframes, int nbad, int txok, bool update_rc)
{
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = bf->aphy->hw;
+ struct ath_softc *sc = bf->aphy->sc;
+ struct ath_hw *ah = sc->sc_ah;
u8 i, tx_rateindex;
if (txok)
@@ -1994,22 +1930,32 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
- BUG_ON(nbad > bf->bf_nframes);
+ BUG_ON(nbad > nframes);
- tx_info->status.ampdu_len = bf->bf_nframes;
- tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
+ tx_info->status.ampdu_len = nframes;
+ tx_info->status.ampdu_ack_len = nframes - nbad;
}
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
- if (ieee80211_is_data(hdr->frame_control)) {
- if (ts->ts_flags &
- (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
- tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
- if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
- (ts->ts_status & ATH9K_TXERR_FIFO))
- tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
- }
+ /*
+ * If an underrun error is seen assume it as an excessive
+ * retry only if max frame trigger level has been reached
+ * (2 KB for single stream, and 4 KB for dual stream).
+ * Adjust the long retry as if the frame was tried
+ * hw->max_rate_tries times to affect how rate control updates
+ * PER for the failed rate.
+ * In case of congestion on the bus penalizing this type of
+ * underruns should help hardware actually transmit new frames
+ * successfully by eventually preferring slower rates.
+ * This itself should also alleviate congestion on the bus.
+ */
+ if (ieee80211_is_data(hdr->frame_control) &&
+ (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
+ ATH9K_TX_DELIM_UNDERRUN)) &&
+ ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
+ tx_info->status.rates[tx_rateindex].count =
+ hw->max_rate_tries;
}
for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
@@ -2020,16 +1966,13 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
}
-static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
+static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
{
- int qnum;
-
- qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
- if (qnum == -1)
- return;
+ struct ath_txq *txq;
+ txq = sc->tx.txq_map[qnum];
spin_lock_bh(&txq->axq_lock);
- if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
+ if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
if (ath_mac80211_start_queue(sc, qnum))
txq->stopped = 0;
}
@@ -2046,10 +1989,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
struct ath_tx_status ts;
int txok;
int status;
+ int qnum;
- ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
- txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
- txq->axq_link);
+ ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
+ txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link);
for (;;) {
spin_lock_bh(&txq->axq_lock);
@@ -2106,6 +2050,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_tx_inprogress = false;
if (bf_held)
list_del(&bf_held->list);
+
+ if (bf_is_ampdu_not_probing(bf))
+ txq->axq_ampdu_depth--;
spin_unlock_bh(&txq->axq_lock);
if (bf_held)
@@ -2118,15 +2065,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
*/
if (ts.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
- ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
+ ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
}
+ qnum = skb_get_queue_mapping(bf->bf_mpdu);
+
if (bf_isampdu(bf))
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
+ ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
+ true);
else
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
- ath_wake_mac80211_queue(sc, txq);
+ if (txq == sc->tx.txq_map[qnum])
+ ath_wake_mac80211_queue(sc, qnum);
spin_lock_bh(&txq->axq_lock);
if (sc->sc_flags & SC_OP_TXAGGR)
@@ -2160,8 +2111,8 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
}
if (needreset) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
- "tx hung, resetting the chip\n");
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
+ "tx hung, resetting the chip\n");
ath9k_ps_wakeup(sc);
ath_reset(sc, true);
ath9k_ps_restore(sc);
@@ -2196,14 +2147,15 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
struct list_head bf_head;
int status;
int txok;
+ int qnum;
for (;;) {
status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
if (status == -EINPROGRESS)
break;
if (status == -EIO) {
- ath_print(common, ATH_DBG_XMIT,
- "Error processing tx status\n");
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Error processing tx status\n");
break;
}
@@ -2229,6 +2181,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
txq->axq_depth--;
txq->axq_tx_inprogress = false;
+ if (bf_is_ampdu_not_probing(bf))
+ txq->axq_ampdu_depth--;
spin_unlock_bh(&txq->axq_lock);
txok = !(txs.ts_status & ATH9K_TXERR_MASK);
@@ -2236,16 +2190,20 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
if (!bf_isampdu(bf)) {
if (txs.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
- ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
+ ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
}
+ qnum = skb_get_queue_mapping(bf->bf_mpdu);
+
if (bf_isampdu(bf))
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
+ ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
+ txok, true);
else
ath_tx_complete_buf(sc, bf, txq, &bf_head,
&txs, txok, 0);
- ath_wake_mac80211_queue(sc, txq);
+ if (txq == sc->tx.txq_map[qnum])
+ ath_wake_mac80211_queue(sc, qnum);
spin_lock_bh(&txq->axq_lock);
if (!list_empty(&txq->txq_fifo_pending)) {
@@ -2310,16 +2268,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
"tx", nbufs, 1, 1);
if (error != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Failed to allocate tx descriptors: %d\n", error);
+ ath_err(common,
+ "Failed to allocate tx descriptors: %d\n", error);
goto err;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
"beacon", ATH_BCBUF, 1, 1);
if (error != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Failed to allocate beacon descriptors: %d\n", error);
+ ath_err(common,
+ "Failed to allocate beacon descriptors: %d\n", error);
goto err;
}
@@ -2377,7 +2335,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
for (acno = 0, ac = &an->ac[acno];
acno < WME_NUM_AC; acno++, ac++) {
ac->sched = false;
- ac->qnum = sc->tx.hwq_map[acno];
+ ac->txq = sc->tx.txq_map[acno];
INIT_LIST_HEAD(&ac->tid_q);
}
}
@@ -2387,17 +2345,13 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_ac *ac;
struct ath_atx_tid *tid;
struct ath_txq *txq;
- int i, tidno;
+ int tidno;
for (tidno = 0, tid = &an->tid[tidno];
tidno < WME_NUM_TID; tidno++, tid++) {
- i = tid->ac->qnum;
-
- if (!ATH_TXQ_SETUP(sc, i))
- continue;
- txq = &sc->tx.txq[i];
ac = tid->ac;
+ txq = ac->txq;
spin_lock_bh(&txq->axq_lock);
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 6cf0c9ef47aa..d07ff7f2fd92 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -48,7 +48,7 @@
#include <linux/usb.h>
#ifdef CONFIG_CARL9170_LEDS
#include <linux/leds.h>
-#endif /* CONFIG_CARL170_LEDS */
+#endif /* CONFIG_CARL9170_LEDS */
#ifdef CONFIG_CARL9170_WPC
#include <linux/input.h>
#endif /* CONFIG_CARL9170_WPC */
@@ -215,7 +215,7 @@ enum carl9170_restart_reasons {
CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS,
CARL9170_RR_WATCHDOG,
CARL9170_RR_STUCK_TX,
- CARL9170_RR_SLOW_SYSTEM,
+ CARL9170_RR_UNRESPONSIVE_DEVICE,
CARL9170_RR_COMMAND_TIMEOUT,
CARL9170_RR_TOO_MANY_PHY_ERRORS,
CARL9170_RR_LOST_RSP,
@@ -287,6 +287,7 @@ struct ar9170 {
/* reset / stuck frames/queue detection */
struct work_struct restart_work;
+ struct work_struct ping_work;
unsigned int restart_counter;
unsigned long queue_stop_timeout[__AR9170_NUM_TXQ];
unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ];
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index c21f3364bfec..cdfc94c371b4 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -41,7 +41,7 @@
int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
{
- __le32 buf[2] = {
+ const __le32 buf[2] = {
cpu_to_le32(reg),
cpu_to_le32(val),
};
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index ae6c006bbc56..546b4e4ec5ea 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -291,7 +291,8 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_WLANTX_CAB)) {
ar->hw->wiphy->interface_modes |=
- BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO);
}
}
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
index d552166db505..3680dfc70f46 100644
--- a/drivers/net/wireless/ath/carl9170/fwcmd.h
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -97,13 +97,13 @@ struct carl9170_set_key_cmd {
__le16 type;
u8 macAddr[6];
u32 key[4];
-} __packed;
+} __packed __aligned(4);
#define CARL9170_SET_KEY_CMD_SIZE 28
struct carl9170_disable_key_cmd {
__le16 user;
__le16 padding;
-} __packed;
+} __packed __aligned(4);
#define CARL9170_DISABLE_KEY_CMD_SIZE 4
struct carl9170_u32_list {
@@ -206,7 +206,7 @@ struct carl9170_cmd {
struct carl9170_rx_filter_cmd rx_filter;
u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
} __packed;
-} __packed;
+} __packed __aligned(4);
#define CARL9170_TX_STATUS_QUEUE 3
#define CARL9170_TX_STATUS_QUEUE_S 0
@@ -216,6 +216,7 @@ struct carl9170_cmd {
#define CARL9170_TX_STATUS_TRIES (7 << CARL9170_TX_STATUS_TRIES_S)
#define CARL9170_TX_STATUS_SUCCESS 0x80
+#ifdef __CARL9170FW__
/*
* NOTE:
* Both structs [carl9170_tx_status and _carl9170_tx_status]
@@ -232,6 +233,8 @@ struct carl9170_tx_status {
u8 tries:3;
u8 success:1;
} __packed;
+#endif /* __CARL9170FW__ */
+
struct _carl9170_tx_status {
/*
* This version should be immune to all alignment bugs.
@@ -272,13 +275,15 @@ struct carl9170_rsp {
struct carl9170_rf_init_result rf_init_res;
struct carl9170_u32_list rreg_res;
struct carl9170_u32_list echo;
+#ifdef __CARL9170FW__
struct carl9170_tx_status tx_status[0];
+#endif /* __CARL9170FW__ */
struct _carl9170_tx_status _tx_status[0];
struct carl9170_gpio gpio;
struct carl9170_tsf_rsp tsf;
struct carl9170_psm psm;
u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
} __packed;
-} __packed;
+} __packed __aligned(4);
#endif /* __CARL9170_SHARED_FWCMD_H */
diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h
index 2f471b3f05af..e85df6edfed3 100644
--- a/drivers/net/wireless/ath/carl9170/hw.h
+++ b/drivers/net/wireless/ath/carl9170/hw.h
@@ -712,7 +712,8 @@ struct ar9170_stream {
__le16 tag;
u8 payload[0];
-};
+} __packed __aligned(4);
+#define AR9170_STREAM_LEN 4
#define AR9170_MAX_ACKTABLE_ENTRIES 8
#define AR9170_MAX_VIRTUAL_MAC 7
@@ -736,4 +737,8 @@ struct ar9170_stream {
#define MOD_VAL(reg, value, newvalue) \
(((value) & ~reg) | (((newvalue) << reg##_S) & reg))
+
+#define GET_VAL(reg, value) \
+ (((value) & reg) >> reg##_S)
+
#endif /* __CARL9170_SHARED_HW_H */
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c
index 2305bc27151c..385cf508479b 100644
--- a/drivers/net/wireless/ath/carl9170/mac.c
+++ b/drivers/net/wireless/ath/carl9170/mac.c
@@ -205,8 +205,8 @@ int carl9170_init_mac(struct ar9170 *ar)
carl9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105);
/* Aggregation MAX number and timeout */
- carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0xa);
- carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a00);
+ carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0x8000a);
+ carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a07);
carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
AR9170_MAC_FTF_DEFAULTS);
@@ -457,8 +457,9 @@ int carl9170_set_beacon_timers(struct ar9170 *ar)
int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct carl9170_vif_info *cvif;
+ struct ieee80211_tx_info *txinfo;
__le32 *data, *old = NULL;
u32 word, off, addr, len;
int i = 0, err = 0;
@@ -487,7 +488,13 @@ found:
if (!skb) {
err = -ENOMEM;
- goto out_unlock;
+ goto err_free;
+ }
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ if (txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS) {
+ err = -EINVAL;
+ goto err_free;
}
spin_lock_bh(&ar->beacon_lock);
@@ -504,11 +511,8 @@ found:
wiphy_err(ar->hw->wiphy, "beacon does not "
"fit into device memory!\n");
}
-
- spin_unlock_bh(&ar->beacon_lock);
- dev_kfree_skb_any(skb);
err = -EINVAL;
- goto out_unlock;
+ goto err_unlock;
}
if (len > AR9170_MAC_BCN_LENGTH_MAX) {
@@ -518,22 +522,22 @@ found:
AR9170_MAC_BCN_LENGTH_MAX, len);
}
- spin_unlock_bh(&ar->beacon_lock);
- dev_kfree_skb_any(skb);
err = -EMSGSIZE;
- goto out_unlock;
+ goto err_unlock;
}
- carl9170_async_regwrite_begin(ar);
+ i = txinfo->control.rates[0].idx;
+ if (txinfo->band != IEEE80211_BAND_2GHZ)
+ i += 4;
- /* XXX: use skb->cb info */
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
- carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
- ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400);
- } else {
- carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
- ((skb->len + FCS_LEN) << 16) + 0x001b);
- }
+ word = __carl9170_ratetable[i].hw_value & 0xf;
+ if (i < 4)
+ word |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
+ else
+ word |= ((skb->len + FCS_LEN) << 16) + 0x0010;
+
+ carl9170_async_regwrite_begin(ar);
+ carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, word);
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
/*
@@ -557,7 +561,7 @@ found:
cvif->beacon = skb;
spin_unlock_bh(&ar->beacon_lock);
if (err)
- goto out_unlock;
+ goto err_free;
if (submit) {
err = carl9170_bcn_ctrl(ar, cvif->id,
@@ -565,10 +569,18 @@ found:
addr, skb->len + FCS_LEN);
if (err)
- goto out_unlock;
+ goto err_free;
}
out_unlock:
rcu_read_unlock();
+ return 0;
+
+err_unlock:
+ spin_unlock_bh(&ar->beacon_lock);
+
+err_free:
+ rcu_read_unlock();
+ dev_kfree_skb_any(skb);
return err;
}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 980ae70ea424..870df8c42622 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -428,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar)
cancel_delayed_work_sync(&ar->led_work);
#endif /* CONFIG_CARL9170_LEDS */
cancel_work_sync(&ar->ps_work);
+ cancel_work_sync(&ar->ping_work);
cancel_work_sync(&ar->ampdu_work);
}
@@ -533,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
*/
}
+static void carl9170_ping_work(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170, ping_work);
+ int err;
+
+ if (!IS_STARTED(ar))
+ return;
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_echo_test(ar, 0xdeadbeef);
+ if (err)
+ carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE);
+ mutex_unlock(&ar->mutex);
+}
+
static int carl9170_init_interface(struct ar9170 *ar,
struct ieee80211_vif *vif)
{
@@ -647,7 +663,7 @@ init:
}
unlock:
- if (err && (vif_id != -1)) {
+ if (err && (vif_id >= 0)) {
vif_priv->active = false;
bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
ar->vifs--;
@@ -1614,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size)
skb_queue_head_init(&ar->tx_pending[i]);
}
INIT_WORK(&ar->ps_work, carl9170_ps_work);
+ INIT_WORK(&ar->ping_work, carl9170_ping_work);
INIT_WORK(&ar->restart_work, carl9170_restart_work);
INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
@@ -1631,7 +1648,8 @@ void *carl9170_alloc(size_t priv_size)
* supports these modes. The code which will add the
* additional interface_modes is in fw.c.
*/
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
@@ -1828,7 +1846,7 @@ int carl9170_register(struct ar9170 *ar)
err = carl9170_led_register(ar);
if (err)
goto err_unreg;
-#endif /* CONFIG_CAR9L170_LEDS */
+#endif /* CONFIG_CARL9170_LEDS */
#ifdef CONFIG_CARL9170_WPC
err = carl9170_register_wps_button(ar);
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index 89deca37a988..b6b0de600506 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1029,8 +1029,6 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
if (err)
return err;
- msleep(20);
-
return 0;
}
@@ -1554,15 +1552,6 @@ static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
return carl9170_regwrite_result();
}
-/* TODO: replace this with sign_extend32(noise, 8) */
-static int carl9170_calc_noise_dbm(u32 raw_noise)
-{
- if (raw_noise & 0x100)
- return ~0x1ff | raw_noise;
- else
- return raw_noise;
-}
-
int carl9170_get_noisefloor(struct ar9170 *ar)
{
static const u32 phy_regs[] = {
@@ -1578,11 +1567,11 @@ int carl9170_get_noisefloor(struct ar9170 *ar)
return err;
for (i = 0; i < 2; i++) {
- ar->noise[i] = carl9170_calc_noise_dbm(
- (phy_res[i] >> 19) & 0x1ff);
+ ar->noise[i] = sign_extend32(GET_VAL(
+ AR9170_PHY_CCA_MIN_PWR, phy_res[i]), 8);
- ar->noise[i + 2] = carl9170_calc_noise_dbm(
- (phy_res[i + 2] >> 23) & 0x1ff);
+ ar->noise[i + 2] = sign_extend32(GET_VAL(
+ AR9170_PHY_EXT_CCA_MIN_PWR, phy_res[i + 2]), 8);
}
return 0;
@@ -1669,12 +1658,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return err;
cmd = CARL9170_CMD_RF_INIT;
-
- msleep(100);
-
- err = carl9170_echo_test(ar, 0xaabbccdd);
- if (err)
- return err;
} else {
cmd = CARL9170_CMD_FREQUENCY;
}
@@ -1685,6 +1668,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
0x200);
+ if (err)
+ return err;
err = carl9170_init_rf_bank4_pwr(ar,
channel->band == IEEE80211_BAND_5GHZ,
diff --git a/drivers/net/wireless/ath/carl9170/phy.h b/drivers/net/wireless/ath/carl9170/phy.h
index 02c34eb4ebde..024fb42bc787 100644
--- a/drivers/net/wireless/ath/carl9170/phy.h
+++ b/drivers/net/wireless/ath/carl9170/phy.h
@@ -139,8 +139,8 @@
#define AR9170_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000
#define AR9170_PHY_REG_CCA (AR9170_PHY_REG_BASE + 0x0064)
-#define AR9170_PHY_CCA_MINCCA_PWR 0x0ff80000
-#define AR9170_PHY_CCA_MINCCA_PWR_S 19
+#define AR9170_PHY_CCA_MIN_PWR 0x0ff80000
+#define AR9170_PHY_CCA_MIN_PWR_S 19
#define AR9170_PHY_CCA_THRESH62 0x0007f000
#define AR9170_PHY_CCA_THRESH62_S 12
@@ -338,8 +338,8 @@
#define AR9170_PHY_EXT_CCA_CYCPWR_THR1_S 9
#define AR9170_PHY_EXT_CCA_THRESH62 0x007f0000
#define AR9170_PHY_EXT_CCA_THRESH62_S 16
-#define AR9170_PHY_EXT_MINCCA_PWR 0xff800000
-#define AR9170_PHY_EXT_MINCCA_PWR_S 23
+#define AR9170_PHY_EXT_CCA_MIN_PWR 0xff800000
+#define AR9170_PHY_EXT_CCA_MIN_PWR_S 23
#define AR9170_PHY_REG_SFCORR_EXT (AR9170_PHY_REG_BASE + 0x01c0)
#define AR9170_PHY_SFCORR_EXT_M1_THRESH 0x0000007f
@@ -546,19 +546,19 @@
#define AR9170_PHY_FORCE_XPA_CFG_S 0
#define AR9170_PHY_REG_CH1_CCA (AR9170_PHY_REG_BASE + 0x1064)
-#define AR9170_PHY_CH1_MINCCA_PWR 0x0ff80000
-#define AR9170_PHY_CH1_MINCCA_PWR_S 19
+#define AR9170_PHY_CH1_CCA_MIN_PWR 0x0ff80000
+#define AR9170_PHY_CH1_CCA_MIN_PWR_S 19
#define AR9170_PHY_REG_CH2_CCA (AR9170_PHY_REG_BASE + 0x2064)
-#define AR9170_PHY_CH2_MINCCA_PWR 0x0ff80000
-#define AR9170_PHY_CH2_MINCCA_PWR_S 19
+#define AR9170_PHY_CH2_CCA_MIN_PWR 0x0ff80000
+#define AR9170_PHY_CH2_CCA_MIN_PWR_S 19
#define AR9170_PHY_REG_CH1_EXT_CCA (AR9170_PHY_REG_BASE + 0x11bc)
-#define AR9170_PHY_CH1_EXT_MINCCA_PWR 0xff800000
-#define AR9170_PHY_CH1_EXT_MINCCA_PWR_S 23
+#define AR9170_PHY_CH1_EXT_CCA_MIN_PWR 0xff800000
+#define AR9170_PHY_CH1_EXT_CCA_MIN_PWR_S 23
#define AR9170_PHY_REG_CH2_EXT_CCA (AR9170_PHY_REG_BASE + 0x21bc)
-#define AR9170_PHY_CH2_EXT_MINCCA_PWR 0xff800000
-#define AR9170_PHY_CH2_EXT_MINCCA_PWR_S 23
+#define AR9170_PHY_CH2_EXT_CCA_MIN_PWR 0xff800000
+#define AR9170_PHY_CH2_EXT_CCA_MIN_PWR_S 23
#endif /* __CARL9170_SHARED_PHY_H */
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index b575c865142d..6cc58e052d10 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -242,9 +242,11 @@ static void carl9170_tx_release(struct kref *ref)
ar->tx_ampdu_schedule = true;
if (txinfo->flags & IEEE80211_TX_STAT_AMPDU) {
- txinfo->status.ampdu_len = txinfo->pad[0];
- txinfo->status.ampdu_ack_len = txinfo->pad[1];
- txinfo->pad[0] = txinfo->pad[1] = 0;
+ struct _carl9170_tx_superframe *super;
+
+ super = (void *)skb->data;
+ txinfo->status.ampdu_len = super->s.rix;
+ txinfo->status.ampdu_ack_len = super->s.cnt;
} else if (txinfo->flags & IEEE80211_TX_STAT_ACK) {
/*
* drop redundant tx_status reports:
@@ -337,7 +339,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
u8 tid;
if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
- txinfo->flags & IEEE80211_TX_CTL_INJECTED)
+ txinfo->flags & IEEE80211_TX_CTL_INJECTED ||
+ (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
return;
tx_info = IEEE80211_SKB_CB(skb);
@@ -389,8 +392,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
sta_info->stats[tid].ampdu_ack_len++;
if (super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_IMM_BA)) {
- txinfo->pad[0] = sta_info->stats[tid].ampdu_len;
- txinfo->pad[1] = sta_info->stats[tid].ampdu_ack_len;
+ super->s.rix = sta_info->stats[tid].ampdu_len;
+ super->s.cnt = sta_info->stats[tid].ampdu_ack_len;
txinfo->flags |= IEEE80211_TX_STAT_AMPDU;
sta_info->stats[tid].clear = true;
}
@@ -524,6 +527,59 @@ next:
}
}
+static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
+{
+ struct carl9170_sta_tid *iter;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+ struct carl9170_tx_info *arinfo;
+ struct _carl9170_tx_superframe *super;
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif;
+ struct ieee80211_hdr *hdr;
+ unsigned int vif_id;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) {
+ if (iter->state < CARL9170_TID_STATE_IDLE)
+ continue;
+
+ spin_lock_bh(&iter->lock);
+ skb = skb_peek(&iter->queue);
+ if (!skb)
+ goto unlock;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ arinfo = (void *)txinfo->rate_driver_data;
+ if (time_is_after_jiffies(arinfo->timeout +
+ msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
+ goto unlock;
+
+ super = (void *) skb->data;
+ hdr = (void *) super->frame_data;
+
+ vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
+ CARL9170_TX_SUPER_MISC_VIF_ID_S;
+
+ if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC))
+ goto unlock;
+
+ vif = rcu_dereference(ar->vif_priv[vif_id].vif);
+ if (WARN_ON(!vif))
+ goto unlock;
+
+ sta = ieee80211_find_sta(vif, hdr->addr1);
+ if (WARN_ON(!sta))
+ goto unlock;
+
+ ieee80211_stop_tx_ba_session(sta, iter->tid);
+unlock:
+ spin_unlock_bh(&iter->lock);
+
+ }
+ rcu_read_unlock();
+}
+
void carl9170_tx_janitor(struct work_struct *work)
{
struct ar9170 *ar = container_of(work, struct ar9170,
@@ -534,6 +590,7 @@ void carl9170_tx_janitor(struct work_struct *work)
ar->tx_janitor_last_run = jiffies;
carl9170_check_queue_stop_timeout(ar);
+ carl9170_tx_ampdu_timeout(ar);
if (!atomic_read(&ar->tx_total_queued))
return;
@@ -810,7 +867,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
AR9170_TX_MAC_BACKOFF);
- mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &&
+ mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &
AR9170_TX_MAC_QOS);
no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
@@ -842,10 +899,8 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
if (unlikely(!sta || !cvif))
goto err_out;
- factor = min_t(unsigned int, 1u,
- info->control.sta->ht_cap.ampdu_factor);
-
- density = info->control.sta->ht_cap.ampdu_density;
+ factor = min_t(unsigned int, 1u, sta->ht_cap.ampdu_factor);
+ density = sta->ht_cap.ampdu_density;
if (density) {
/*
@@ -1206,6 +1261,7 @@ static void carl9170_tx(struct ar9170 *ar)
static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
struct ieee80211_sta *sta, struct sk_buff *skb)
{
+ struct _carl9170_tx_superframe *super = (void *) skb->data;
struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *agg;
struct sk_buff *iter;
@@ -1274,6 +1330,7 @@ err_unlock:
err_unlock_rcu:
rcu_read_unlock();
+ super->f.mac_control &= ~cpu_to_le16(AR9170_TX_MAC_AGGR);
carl9170_tx_status(ar, skb, false);
ar->tx_dropped++;
return false;
@@ -1302,9 +1359,6 @@ int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
*/
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- if (WARN_ON_ONCE(!sta))
- goto err_free;
-
run = carl9170_tx_ampdu_queue(ar, sta, skb);
if (run)
carl9170_tx_ampdu(ar);
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index d8607f4c144d..537732e5964f 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -82,9 +82,11 @@ static struct usb_device_id carl9170_usb_ids[] = {
{ USB_DEVICE(0x07d1, 0x3c10) },
/* D-Link DWA 160 A2 */
{ USB_DEVICE(0x07d1, 0x3a09) },
+ /* D-Link DWA 130 D */
+ { USB_DEVICE(0x07d1, 0x3a0f) },
/* Netgear WNA1000 */
{ USB_DEVICE(0x0846, 0x9040) },
- /* Netgear WNDA3100 */
+ /* Netgear WNDA3100 (v1) */
{ USB_DEVICE(0x0846, 0x9010) },
/* Netgear WN111 v2 */
{ USB_DEVICE(0x0846, 0x9001), .driver_info = CARL9170_ONE_LED },
@@ -158,8 +160,7 @@ err_acc:
static void carl9170_usb_tx_data_complete(struct urb *urb)
{
- struct ar9170 *ar = (struct ar9170 *)
- usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+ struct ar9170 *ar = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
if (WARN_ON_ONCE(!ar)) {
dev_kfree_skb_irq(urb->context);
@@ -431,7 +432,7 @@ static void carl9170_usb_rx_complete(struct urb *urb)
* device.
*/
- carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM);
+ ieee80211_queue_work(ar->hw, &ar->ping_work);
}
} else {
/*
@@ -551,12 +552,12 @@ static int carl9170_usb_flush(struct ar9170 *ar)
usb_free_urb(urb);
}
- ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ);
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, 1000);
if (ret == 0)
err = -ETIMEDOUT;
/* lets wait a while until the tx - queues are dried out */
- ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ);
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, 1000);
if (ret == 0)
err = -ETIMEDOUT;
@@ -833,7 +834,7 @@ static int carl9170_usb_load_firmware(struct ar9170 *ar)
if (err)
goto err_out;
- /* firmware restarts cmd counter */
+ /* now, start the command response counter */
ar->cmd_seq = -1;
return 0;
@@ -850,7 +851,12 @@ int carl9170_usb_restart(struct ar9170 *ar)
if (ar->intf->condition != USB_INTERFACE_BOUND)
return 0;
- /* Disable command response sequence counter. */
+ /*
+ * Disable the command response sequence counter check.
+ * We already know that the device/firmware is in a bad state.
+ * So, no extra points are awarded to anyone who reminds the
+ * driver about that.
+ */
ar->cmd_seq = -2;
err = carl9170_reboot(ar);
@@ -902,6 +908,15 @@ static int carl9170_usb_init_device(struct ar9170 *ar)
{
int err;
+ /*
+ * The carl9170 firmware let's the driver know when it's
+ * ready for action. But we have to be prepared to gracefully
+ * handle all spurious [flushed] messages after each (re-)boot.
+ * Thus the command response counter remains disabled until it
+ * can be safely synchronized.
+ */
+ ar->cmd_seq = -2;
+
err = carl9170_usb_send_rx_irq_urb(ar);
if (err)
goto err_out;
@@ -910,14 +925,21 @@ static int carl9170_usb_init_device(struct ar9170 *ar)
if (err)
goto err_unrx;
+ err = carl9170_usb_open(ar);
+ if (err)
+ goto err_unrx;
+
mutex_lock(&ar->mutex);
err = carl9170_usb_load_firmware(ar);
mutex_unlock(&ar->mutex);
if (err)
- goto err_unrx;
+ goto err_stop;
return 0;
+err_stop:
+ carl9170_usb_stop(ar);
+
err_unrx:
carl9170_usb_cancel_urbs(ar);
@@ -963,10 +985,6 @@ static void carl9170_usb_firmware_finish(struct ar9170 *ar)
if (err)
goto err_freefw;
- err = carl9170_usb_open(ar);
- if (err)
- goto err_unrx;
-
err = carl9170_register(ar);
carl9170_usb_stop(ar);
@@ -1042,7 +1060,6 @@ static int carl9170_usb_probe(struct usb_interface *intf,
atomic_set(&ar->rx_work_urbs, 0);
atomic_set(&ar->rx_anch_urbs, 0);
atomic_set(&ar->rx_pool_urbs, 0);
- ar->cmd_seq = -2;
usb_get_dev(ar->udev);
@@ -1089,10 +1106,6 @@ static int carl9170_usb_suspend(struct usb_interface *intf,
carl9170_usb_cancel_urbs(ar);
- /*
- * firmware automatically reboots for usb suspend.
- */
-
return 0;
}
@@ -1105,12 +1118,20 @@ static int carl9170_usb_resume(struct usb_interface *intf)
return -ENODEV;
usb_unpoison_anchored_urbs(&ar->rx_anch);
+ carl9170_set_state(ar, CARL9170_STOPPED);
- err = carl9170_usb_init_device(ar);
- if (err)
- goto err_unrx;
+ /*
+ * The USB documentation demands that [for suspend] all traffic
+ * to and from the device has to stop. This would be fine, but
+ * there's a catch: the device[usb phy] does not come back.
+ *
+ * Upon resume the firmware will "kill" itself and the
+ * boot-code sorts out the magic voodoo.
+ * Not very nice, but there's not much what could go wrong.
+ */
+ msleep(1100);
- err = carl9170_usb_open(ar);
+ err = carl9170_usb_init_device(ar);
if (err)
goto err_unrx;
@@ -1132,6 +1153,7 @@ static struct usb_driver carl9170_driver = {
#ifdef CONFIG_PM
.suspend = carl9170_usb_suspend,
.resume = carl9170_usb_resume,
+ .reset_resume = carl9170_usb_resume,
#endif /* CONFIG_PM */
};
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
index ff53f078a0b5..ee0f84f2a2f6 100644
--- a/drivers/net/wireless/ath/carl9170/version.h
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -1,7 +1,7 @@
#ifndef __CARL9170_SHARED_VERSION_H
#define __CARL9170_SHARED_VERSION_H
#define CARL9170FW_VERSION_YEAR 10
-#define CARL9170FW_VERSION_MONTH 9
-#define CARL9170FW_VERSION_DAY 28
-#define CARL9170FW_VERSION_GIT "1.8.8.3"
+#define CARL9170FW_VERSION_MONTH 10
+#define CARL9170FW_VERSION_DAY 29
+#define CARL9170FW_VERSION_GIT "1.9.0"
#endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c
index dacfb234f491..5367b1086e09 100644
--- a/drivers/net/wireless/ath/debug.c
+++ b/drivers/net/wireless/ath/debug.c
@@ -15,21 +15,6 @@
*/
#include "ath.h"
-#include "debug.h"
-
-void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
-{
- va_list args;
-
- if (likely(!(common->debug_mask & dbg_mask)))
- return;
-
- va_start(args, fmt);
- printk(KERN_DEBUG "ath: ");
- vprintk(fmt, args);
- va_end(args);
-}
-EXPORT_SYMBOL(ath_print);
const char *ath_opmode_to_string(enum nl80211_iftype opmode)
{
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h
deleted file mode 100644
index 64e4af2c2887..000000000000
--- a/drivers/net/wireless/ath/debug.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef ATH_DEBUG_H
-#define ATH_DEBUG_H
-
-#include "ath.h"
-
-/**
- * enum ath_debug_level - atheros wireless debug level
- *
- * @ATH_DBG_RESET: reset processing
- * @ATH_DBG_QUEUE: hardware queue management
- * @ATH_DBG_EEPROM: eeprom processing
- * @ATH_DBG_CALIBRATE: periodic calibration
- * @ATH_DBG_INTERRUPT: interrupt processing
- * @ATH_DBG_REGULATORY: regulatory processing
- * @ATH_DBG_ANI: adaptive noise immunitive processing
- * @ATH_DBG_XMIT: basic xmit operation
- * @ATH_DBG_BEACON: beacon handling
- * @ATH_DBG_CONFIG: configuration of the hardware
- * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT
- * @ATH_DBG_PS: power save processing
- * @ATH_DBG_HWTIMER: hardware timer handling
- * @ATH_DBG_BTCOEX: bluetooth coexistance
- * @ATH_DBG_BSTUCK: stuck beacons
- * @ATH_DBG_ANY: enable all debugging
- *
- * The debug level is used to control the amount and type of debugging output
- * we want to see. Each driver has its own method for enabling debugging and
- * modifying debug level states -- but this is typically done through a
- * module parameter 'debug' along with a respective 'debug' debugfs file
- * entry.
- */
-enum ATH_DEBUG {
- ATH_DBG_RESET = 0x00000001,
- ATH_DBG_QUEUE = 0x00000002,
- ATH_DBG_EEPROM = 0x00000004,
- ATH_DBG_CALIBRATE = 0x00000008,
- ATH_DBG_INTERRUPT = 0x00000010,
- ATH_DBG_REGULATORY = 0x00000020,
- ATH_DBG_ANI = 0x00000040,
- ATH_DBG_XMIT = 0x00000080,
- ATH_DBG_BEACON = 0x00000100,
- ATH_DBG_CONFIG = 0x00000200,
- ATH_DBG_FATAL = 0x00000400,
- ATH_DBG_PS = 0x00000800,
- ATH_DBG_HWTIMER = 0x00001000,
- ATH_DBG_BTCOEX = 0x00002000,
- ATH_DBG_WMI = 0x00004000,
- ATH_DBG_BSTUCK = 0x00008000,
- ATH_DBG_ANY = 0xffffffff
-};
-
-#define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
-
-#ifdef CONFIG_ATH_DEBUG
-void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
- __attribute__ ((format (printf, 3, 4)));
-#else
-static inline void __attribute__ ((format (printf, 3, 4)))
-ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
-{
-}
-#endif /* CONFIG_ATH_DEBUG */
-
-/** Returns string describing opmode, or NULL if unknown mode. */
-#ifdef CONFIG_ATH_DEBUG
-const char *ath_opmode_to_string(enum nl80211_iftype opmode);
-#else
-static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode)
-{
- return "UNKNOWN";
-}
-#endif
-
-#endif /* ATH_DEBUG_H */
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index bd21a4d82085..5d465e5fcf24 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -20,7 +20,6 @@
#include "ath.h"
#include "reg.h"
-#include "debug.h"
#define REG_READ (common->ops->read)
#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg)
@@ -37,8 +36,7 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_print(common, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_err(common, "keycache entry %u out of range\n", entry);
return false;
}
@@ -60,6 +58,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+ if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
}
@@ -67,15 +67,15 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
}
EXPORT_SYMBOL(ath_hw_keyreset);
-bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
+static bool ath_hw_keysetmac(struct ath_common *common,
+ u16 entry, const u8 *mac)
{
u32 macHi, macLo;
u32 unicast_flag = AR_KEYTABLE_VALID;
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_print(common, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_err(common, "keycache entry %u out of range\n", entry);
return false;
}
@@ -107,17 +107,16 @@ bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
return true;
}
-bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
- const struct ath_keyval *k,
- const u8 *mac)
+static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
+ const struct ath_keyval *k,
+ const u8 *mac)
{
void *ah = common->ah;
u32 key0, key1, key2, key3, key4;
u32 keyType;
if (entry >= common->keymax) {
- ath_print(common, ATH_DBG_FATAL,
- "keycache entry %u out of range\n", entry);
+ ath_err(common, "keycache entry %u out of range\n", entry);
return false;
}
@@ -127,8 +126,8 @@ bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
break;
case ATH_CIPHER_AES_CCM:
if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) {
- ath_print(common, ATH_DBG_ANY,
- "AES-CCM not supported by this mac rev\n");
+ ath_dbg(common, ATH_DBG_ANY,
+ "AES-CCM not supported by this mac rev\n");
return false;
}
keyType = AR_KEYTABLE_TYPE_CCM;
@@ -136,15 +135,15 @@ bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
case ATH_CIPHER_TKIP:
keyType = AR_KEYTABLE_TYPE_TKIP;
if (entry + 64 >= common->keymax) {
- ath_print(common, ATH_DBG_ANY,
- "entry %u inappropriate for TKIP\n", entry);
+ ath_dbg(common, ATH_DBG_ANY,
+ "entry %u inappropriate for TKIP\n", entry);
return false;
}
break;
case ATH_CIPHER_WEP:
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
- ath_print(common, ATH_DBG_ANY,
- "WEP key length %u too small\n", k->kv_len);
+ ath_dbg(common, ATH_DBG_ANY,
+ "WEP key length %u too small\n", k->kv_len);
return false;
}
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
@@ -158,8 +157,7 @@ bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
keyType = AR_KEYTABLE_TYPE_CLR;
break;
default:
- ath_print(common, ATH_DBG_FATAL,
- "cipher %u not supported\n", k->kv_type);
+ ath_err(common, "cipher %u not supported\n", k->kv_type);
return false;
}
@@ -340,8 +338,7 @@ static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
- ath_print(common, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
+ ath_err(common, "Setting TX MIC Key Failed\n");
return 0;
}
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
index 487193f1de1a..c325202fdc5f 100644
--- a/drivers/net/wireless/ath/main.c
+++ b/drivers/net/wireless/ath/main.c
@@ -56,3 +56,23 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
return skb;
}
EXPORT_SYMBOL(ath_rxbuf_alloc);
+
+int ath_printk(const char *level, struct ath_common *common,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int rtn;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ rtn = printk("%sath: %pV", level, &vaf);
+
+ va_end(args);
+
+ return rtn;
+}
+EXPORT_SYMBOL(ath_printk);
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 3f4244f56ce5..2b14775e6bc6 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -342,6 +342,14 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
/* We always apply this */
ath_reg_apply_radar_flags(wiphy);
+ /*
+ * This would happen when we have sent a custom regulatory request
+ * a world regulatory domain and the scheduler hasn't yet processed
+ * any pending requests in the queue.
+ */
+ if (!request)
+ return 0;
+
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
case NL80211_REGDOM_SET_BY_CORE:
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index c8f7090b27d3..46e382ed46aa 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1161,7 +1161,7 @@ static irqreturn_t service_interrupt(int irq, void *dev_id)
struct atmel_private *priv = netdev_priv(dev);
u8 isr;
int i = -1;
- static u8 irq_order[] = {
+ static const u8 irq_order[] = {
ISR_OUT_OF_RANGE,
ISR_RxCOMPLETE,
ISR_TxCOMPLETE,
@@ -3771,7 +3771,9 @@ static int probe_atmel_card(struct net_device *dev)
if (rc) {
if (dev->dev_addr[0] == 0xFF) {
- u8 default_mac[] = {0x00, 0x04, 0x25, 0x00, 0x00, 0x00};
+ static const u8 default_mac[] = {
+ 0x00, 0x04, 0x25, 0x00, 0x00, 0x00
+ };
printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
memcpy(dev->dev_addr, default_mac, 6);
}
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 0a00d42642cd..47033f6a1c2b 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -86,15 +86,16 @@ config B43_PIO
select SSB_BLOCKIO
default y
-config B43_NPHY
- bool "Pre IEEE 802.11n support (BROKEN)"
- depends on B43 && EXPERIMENTAL && BROKEN
+config B43_PHY_N
+ bool "Support for 802.11n (N-PHY) devices (EXPERIMENTAL)"
+ depends on B43 && EXPERIMENTAL
---help---
- Support for the IEEE 802.11n draft.
+ Support for the N-PHY.
- THIS IS BROKEN AND DOES NOT WORK YET.
+ This enables support for devices with N-PHY revision up to 2.
- SAY N.
+ Say N if you expect high stability and performance. Saying Y will not
+ affect other devices support and may provide support for basic needs.
config B43_PHY_LP
bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 69d4af09a6cb..cef334a8c669 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -1,12 +1,12 @@
b43-y += main.o
b43-y += tables.o
-b43-$(CONFIG_B43_NPHY) += tables_nphy.o
-b43-$(CONFIG_B43_NPHY) += radio_2055.o
-b43-$(CONFIG_B43_NPHY) += radio_2056.o
+b43-$(CONFIG_B43_PHY_N) += tables_nphy.o
+b43-$(CONFIG_B43_PHY_N) += radio_2055.o
+b43-$(CONFIG_B43_PHY_N) += radio_2056.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o
-b43-$(CONFIG_B43_NPHY) += phy_n.o
+b43-$(CONFIG_B43_PHY_N) += phy_n.o
b43-$(CONFIG_B43_PHY_LP) += phy_lp.o
b43-$(CONFIG_B43_PHY_LP) += tables_lpphy.o
b43-y += sysfs.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 72821c456b02..bd4cb75b6ca3 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -153,6 +153,19 @@
#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna
* with bluetooth */
+/* SPROM boardflags2_lo values */
+#define B43_BFL2_RXBB_INT_REG_DIS 0x0001 /* external RX BB regulator present */
+#define B43_BFL2_APLL_WAR 0x0002 /* alternative A-band PLL settings implemented */
+#define B43_BFL2_TXPWRCTRL_EN 0x0004 /* permits enabling TX Power Control */
+#define B43_BFL2_2X4_DIV 0x0008 /* 2x4 diversity switch */
+#define B43_BFL2_5G_PWRGAIN 0x0010 /* supports 5G band power gain */
+#define B43_BFL2_PCIEWAR_OVR 0x0020 /* overrides ASPM and Clkreq settings */
+#define B43_BFL2_CAESERS_BRD 0x0040 /* is Caesers board (unused) */
+#define B43_BFL2_BTC3WIRE 0x0080 /* used 3-wire bluetooth coexist */
+#define B43_BFL2_SKWRKFEM_BRD 0x0100 /* 4321mcm93 uses Skyworks FEM */
+#define B43_BFL2_SPUR_WAR 0x0200 /* has a workaround for clock-harmonic spurs */
+#define B43_BFL2_GPLL_WAR 0x0400 /* altenative G-band PLL settings implemented */
+
/* GPIO register offset, in both ChipCommon and PCI core. */
#define B43_GPIO_CONTROL 0x6c
@@ -403,10 +416,10 @@ enum {
/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
-#define B43_TMSLOW_PHYCLKSPEED 0x00C00000 /* PHY clock speed mask (N-PHY only) */
-#define B43_TMSLOW_PHYCLKSPEED_40MHZ 0x00000000 /* 40 MHz PHY */
-#define B43_TMSLOW_PHYCLKSPEED_80MHZ 0x00400000 /* 80 MHz PHY */
-#define B43_TMSLOW_PHYCLKSPEED_160MHZ 0x00800000 /* 160 MHz PHY */
+#define B43_TMSLOW_PHY_BANDWIDTH 0x00C00000 /* PHY band width and clock speed mask (N-PHY only) */
+#define B43_TMSLOW_PHY_BANDWIDTH_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */
+#define B43_TMSLOW_PHY_BANDWIDTH_20MHZ 0x00400000 /* 20 MHz bandwidth, 80 MHz PHY */
+#define B43_TMSLOW_PHY_BANDWIDTH_40MHZ 0x00800000 /* 40 MHz bandwidth, 160 MHz PHY */
#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select (rev >= 5) */
#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 10d0aaf754c5..3d5566e7af0a 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -415,11 +415,6 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
static void free_ringmemory(struct b43_dmaring *ring)
{
- gfp_t flags = GFP_KERNEL;
-
- if (ring->type == B43_DMA_64BIT)
- flags |= GFP_DMA;
-
dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase);
}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index a1186525c70d..22bc9f17f634 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -322,59 +322,83 @@ static int b43_ratelimit(struct b43_wl *wl)
void b43info(struct b43_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
if (b43_modparam_verbose < B43_VERBOSITY_INFO)
return;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_INFO "b43-%s: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
void b43err(struct b43_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
return;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_ERR "b43-%s ERROR: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
void b43warn(struct b43_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
if (b43_modparam_verbose < B43_VERBOSITY_WARN)
return;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_WARNING "b43-%s warning: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
void b43dbg(struct b43_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
return;
+
va_start(args, fmt);
- printk(KERN_DEBUG "b43-%s debug: ",
- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
- vprintk(fmt, args);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_DEBUG "b43-%s debug: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
@@ -1126,6 +1150,8 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
flags |= B43_TMSLOW_PHYCLKEN;
flags |= B43_TMSLOW_PHYRESET;
+ if (dev->phy.type == B43_PHYTYPE_N)
+ flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
ssb_device_enable(dev->dev, flags);
msleep(2); /* Wait for the PLL to turn on. */
@@ -2095,8 +2121,10 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
filename = "ucode13";
else if (rev == 14)
filename = "ucode14";
- else if (rev >= 15)
+ else if (rev == 15)
filename = "ucode15";
+ else if ((rev >= 16) && (rev <= 20))
+ filename = "ucode16_mimo";
else
goto err_no_ucode;
err = b43_do_request_fw(ctx, filename, &fw->ucode);
@@ -2139,7 +2167,9 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
goto err_no_initvals;
break;
case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
+ if (rev >= 16)
+ filename = "n0initvals16";
+ else if ((rev >= 11) && (rev <= 12))
filename = "n0initvals11";
else
goto err_no_initvals;
@@ -2183,7 +2213,9 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
goto err_no_initvals;
break;
case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
+ if (rev >= 16)
+ filename = "n0bsinitvals16";
+ else if ((rev >= 11) && (rev <= 12))
filename = "n0bsinitvals11";
else
goto err_no_initvals;
@@ -4022,9 +4054,9 @@ static int b43_phy_versioning(struct b43_wldev *dev)
if (phy_rev > 9)
unsupported = 1;
break;
-#ifdef CONFIG_B43_NPHY
+#ifdef CONFIG_B43_PHY_N
case B43_PHYTYPE_N:
- if (phy_rev > 4)
+ if (phy_rev > 9)
unsupported = 1;
break;
#endif
@@ -5067,7 +5099,7 @@ static void b43_print_driverinfo(void)
#ifdef CONFIG_B43_PCMCIA
feat_pcmcia = "M";
#endif
-#ifdef CONFIG_B43_NPHY
+#ifdef CONFIG_B43_PHY_N
feat_nphy = "N";
#endif
#ifdef CONFIG_B43_LEDS
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 7b2ea6781457..b5c5ce94d3fd 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -50,7 +50,7 @@ int b43_phy_allocate(struct b43_wldev *dev)
phy->ops = &b43_phyops_g;
break;
case B43_PHYTYPE_N:
-#ifdef CONFIG_B43_NPHY
+#ifdef CONFIG_B43_PHY_N
phy->ops = &b43_phyops_n;
#endif
break;
@@ -231,6 +231,7 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
+ dev->phy.writes_counter = 0;
return dev->phy.ops->phy_read(dev, reg);
}
@@ -238,6 +239,10 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
assert_mac_suspended(dev);
dev->phy.ops->phy_write(dev, reg, value);
+ if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
+ b43_read16(dev, B43_MMIO_PHY_VER);
+ dev->phy.writes_counter = 0;
+ }
}
void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
@@ -424,12 +429,21 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
}
+
+bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type)
+{
+ return (channel_type == NL80211_CHAN_HT40MINUS ||
+ channel_type == NL80211_CHAN_HT40PLUS);
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
struct b43_c32 b43_cordic(int theta)
{
- u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
- 58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
- 229, 115, 57, 29, };
+ static const u32 arctg[] = {
+ 2949120, 1740967, 919879, 466945, 234379, 117304,
+ 58666, 29335, 14668, 7334, 3667, 1833,
+ 917, 458, 229, 115, 57, 29,
+ };
u8 i;
s32 tmp;
s8 signx = 1;
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 0e6194228845..2401bee8b081 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -39,6 +39,9 @@ struct b43_c32 { s32 i, q; };
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
+/* PHY writes need to be flushed if we reach limit */
+#define B43_MAX_WRITES_IN_ROW 24
+
/**
* enum b43_interference_mitigation - Interference Mitigation mode
*
@@ -232,6 +235,9 @@ struct b43_phy {
/* PHY revision number. */
u8 rev;
+ /* Count writes since last read */
+ u8 writes_counter;
+
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
@@ -430,6 +436,8 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
*/
void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
+bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type);
+
struct b43_c32 b43_cordic(int theta);
#endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 0dc33b65e86b..be4828167012 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -1919,7 +1919,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
}
-/* Intialize B/G PHY power control */
+/* Initialize B/G PHY power control */
static void b43_phy_init_pctl(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index e0f2d122e124..ab81ed8b19d7 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -67,6 +67,18 @@ enum b43_nphy_rf_sequence {
B43_RFSEQ_UPDATE_GAINU,
};
+enum b43_nphy_rssi_type {
+ B43_NPHY_RSSI_X = 0,
+ B43_NPHY_RSSI_Y,
+ B43_NPHY_RSSI_Z,
+ B43_NPHY_RSSI_PWRDET,
+ B43_NPHY_RSSI_TSSI_I,
+ B43_NPHY_RSSI_TSSI_Q,
+ B43_NPHY_RSSI_TBD,
+};
+
+static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev,
+ bool enable);
static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
u8 *events, u8 *delays, u8 length);
static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
@@ -76,13 +88,6 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
u16 value, u8 core);
-static inline bool b43_channel_type_is_40mhz(
- enum nl80211_channel_type channel_type)
-{
- return (channel_type == NL80211_CHAN_HT40MINUS ||
- channel_type == NL80211_CHAN_HT40PLUS);
-}
-
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
}
@@ -134,6 +139,99 @@ static void b43_chantab_radio_upload(struct b43_wldev *dev,
b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
}
+static void b43_chantab_radio_2056_upload(struct b43_wldev *dev,
+ const struct b43_nphy_channeltab_entry_rev3 *e)
+{
+ b43_radio_write(dev, B2056_SYN_PLL_VCOCAL1, e->radio_syn_pll_vcocal1);
+ b43_radio_write(dev, B2056_SYN_PLL_VCOCAL2, e->radio_syn_pll_vcocal2);
+ b43_radio_write(dev, B2056_SYN_PLL_REFDIV, e->radio_syn_pll_refdiv);
+ b43_radio_write(dev, B2056_SYN_PLL_MMD2, e->radio_syn_pll_mmd2);
+ b43_radio_write(dev, B2056_SYN_PLL_MMD1, e->radio_syn_pll_mmd1);
+ b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1,
+ e->radio_syn_pll_loopfilter1);
+ b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2,
+ e->radio_syn_pll_loopfilter2);
+ b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER3,
+ e->radio_syn_pll_loopfilter3);
+ b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4,
+ e->radio_syn_pll_loopfilter4);
+ b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER5,
+ e->radio_syn_pll_loopfilter5);
+ b43_radio_write(dev, B2056_SYN_RESERVED_ADDR27,
+ e->radio_syn_reserved_addr27);
+ b43_radio_write(dev, B2056_SYN_RESERVED_ADDR28,
+ e->radio_syn_reserved_addr28);
+ b43_radio_write(dev, B2056_SYN_RESERVED_ADDR29,
+ e->radio_syn_reserved_addr29);
+ b43_radio_write(dev, B2056_SYN_LOGEN_VCOBUF1,
+ e->radio_syn_logen_vcobuf1);
+ b43_radio_write(dev, B2056_SYN_LOGEN_MIXER2, e->radio_syn_logen_mixer2);
+ b43_radio_write(dev, B2056_SYN_LOGEN_BUF3, e->radio_syn_logen_buf3);
+ b43_radio_write(dev, B2056_SYN_LOGEN_BUF4, e->radio_syn_logen_buf4);
+
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA_TUNE,
+ e->radio_rx0_lnaa_tune);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG_TUNE,
+ e->radio_rx0_lnag_tune);
+
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAA_BOOST_TUNE,
+ e->radio_tx0_intpaa_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAG_BOOST_TUNE,
+ e->radio_tx0_intpag_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE,
+ e->radio_tx0_pada_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE,
+ e->radio_tx0_padg_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE,
+ e->radio_tx0_pgaa_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE,
+ e->radio_tx0_pgag_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE,
+ e->radio_tx0_mixa_boost_tune);
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE,
+ e->radio_tx0_mixg_boost_tune);
+
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA_TUNE,
+ e->radio_rx1_lnaa_tune);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG_TUNE,
+ e->radio_rx1_lnag_tune);
+
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAA_BOOST_TUNE,
+ e->radio_tx1_intpaa_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAG_BOOST_TUNE,
+ e->radio_tx1_intpag_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE,
+ e->radio_tx1_pada_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE,
+ e->radio_tx1_padg_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE,
+ e->radio_tx1_pgaa_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE,
+ e->radio_tx1_pgag_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE,
+ e->radio_tx1_mixa_boost_tune);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE,
+ e->radio_tx1_mixg_boost_tune);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */
+static void b43_radio_2056_setup(struct b43_wldev *dev,
+ const struct b43_nphy_channeltab_entry_rev3 *e)
+{
+ B43_WARN_ON(dev->phy.rev < 3);
+
+ b43_chantab_radio_2056_upload(dev, e);
+ /* TODO */
+ udelay(50);
+ /* VCO calibration */
+ b43_radio_write(dev, B2056_SYN_PLL_VCOCAL12, 0x00);
+ b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
+ b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x18);
+ b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
+ b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x39);
+ udelay(300);
+}
+
static void b43_chantab_phy_upload(struct b43_wldev *dev,
const struct b43_phy_n_sfo_cfg *e)
{
@@ -145,9 +243,154 @@ static void b43_chantab_phy_upload(struct b43_wldev *dev,
b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
+static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 i;
+ u16 tmp;
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ nphy->txpwrctrl = enable;
+ if (!enable) {
+ if (dev->phy.rev >= 3)
+ ; /* TODO */
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840);
+ for (i = 0; i < 84; i++)
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6C40);
+ for (i = 0; i < 84; i++)
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+
+ tmp = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+ if (dev->phy.rev >= 3)
+ tmp |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+ b43_phy_mask(dev, B43_NPHY_TXPCTL_CMD, ~tmp);
+
+ if (dev->phy.rev >= 3) {
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+ } else {
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+ }
+
+ if (dev->phy.rev == 2)
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+ ~B43_NPHY_BPHY_CTL3_SCALE, 0x53);
+ else if (dev->phy.rev < 2)
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+ ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
+
+ if (dev->phy.rev < 2 && 0)
+ ; /* TODO */
+ } else {
+ b43err(dev->wl, "enabling tx pwr ctrl not implemented yet\n");
+ }
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
{
- //TODO
+ struct b43_phy_n *nphy = dev->phy.n;
+ struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+ u8 txpi[2], bbmult, i;
+ u16 tmp, radio_gain, dac_gain;
+ u16 freq = dev->phy.channel_freq;
+ u32 txgain;
+ /* u32 gaintbl; rev3+ */
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ if (dev->phy.rev >= 3) {
+ txpi[0] = 40;
+ txpi[1] = 40;
+ } else if (sprom->revision < 4) {
+ txpi[0] = 72;
+ txpi[1] = 72;
+ } else {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ txpi[0] = sprom->txpid2g[0];
+ txpi[1] = sprom->txpid2g[1];
+ } else if (freq >= 4900 && freq < 5100) {
+ txpi[0] = sprom->txpid5gl[0];
+ txpi[1] = sprom->txpid5gl[1];
+ } else if (freq >= 5100 && freq < 5500) {
+ txpi[0] = sprom->txpid5g[0];
+ txpi[1] = sprom->txpid5g[1];
+ } else if (freq >= 5500) {
+ txpi[0] = sprom->txpid5gh[0];
+ txpi[1] = sprom->txpid5gh[1];
+ } else {
+ txpi[0] = 91;
+ txpi[1] = 91;
+ }
+ }
+
+ /*
+ for (i = 0; i < 2; i++) {
+ nphy->txpwrindex[i].index_internal = txpi[i];
+ nphy->txpwrindex[i].index_internal_save = txpi[i];
+ }
+ */
+
+ for (i = 0; i < 2; i++) {
+ if (dev->phy.rev >= 3) {
+ /* FIXME: support 5GHz */
+ txgain = b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]];
+ radio_gain = (txgain >> 16) & 0x1FFFF;
+ } else {
+ txgain = b43_ntab_tx_gain_rev0_1_2[txpi[i]];
+ radio_gain = (txgain >> 16) & 0x1FFF;
+ }
+
+ dac_gain = (txgain >> 8) & 0x3F;
+ bbmult = txgain & 0xFF;
+
+ if (dev->phy.rev >= 3) {
+ if (i == 0)
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+ else
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+ } else {
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+ }
+
+ if (i == 0)
+ b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN1, dac_gain);
+ else
+ b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D10 + i);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, radio_gain);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
+ tmp = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+
+ if (i == 0)
+ tmp = (tmp & 0x00FF) | (bbmult << 8);
+ else
+ tmp = (tmp & 0xFF00) | bbmult;
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, tmp);
+
+ if (0)
+ ; /* TODO */
+ }
+
+ b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
}
@@ -191,7 +434,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
binfo->type != 0x46D ||
binfo->rev < 0x41);
else
- workaround = ((sprom->boardflags_hi & B43_BFH_NOPA) == 0);
+ workaround =
+ !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS);
b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
if (workaround) {
@@ -240,23 +484,55 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
static void b43_radio_init2055(struct b43_wldev *dev)
{
b43_radio_init2055_pre(dev);
- if (b43_status(dev) < B43_STAT_INITIALIZED)
- b2055_upload_inittab(dev, 0, 1);
- else
- b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ /* Follow wl, not specs. Do not force uploading all regs */
+ b2055_upload_inittab(dev, 0, 0);
+ } else {
+ bool ghz5 = b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ;
+ b2055_upload_inittab(dev, ghz5, 0);
+ }
b43_radio_init2055_post(dev);
}
+static void b43_radio_init2056_pre(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+ /* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_OEPORFORCE);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ ~B43_NPHY_RFCTL_CMD_OEPORFORCE);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_CHIP0PU);
+}
+
+static void b43_radio_init2056_post(struct b43_wldev *dev)
+{
+ b43_radio_set(dev, B2056_SYN_COM_CTRL, 0xB);
+ b43_radio_set(dev, B2056_SYN_COM_PU, 0x2);
+ b43_radio_set(dev, B2056_SYN_COM_RESET, 0x2);
+ msleep(1);
+ b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
+ b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
+ b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
+ /*
+ if (nphy->init_por)
+ Call Radio 2056 Recalibrate
+ */
+}
+
/*
* Initialize a Broadcom 2056 N-radio
* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init
*/
static void b43_radio_init2056(struct b43_wldev *dev)
{
- /* TODO */
+ b43_radio_init2056_pre(dev);
+ b2056_upload_inittabs(dev, 0, 0);
+ b43_radio_init2056_post(dev);
}
-
/*
* Upload the N-PHY tables.
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
@@ -453,6 +729,8 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
}
}
+#if 0
+/* Ready but not used anywhere */
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core)
{
@@ -534,6 +812,7 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1));
b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core));
}
+#endif
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
@@ -569,7 +848,6 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
ii = est.i1_pwr;
qq = est.q1_pwr;
} else {
- B43_WARN_ON(1);
continue;
}
@@ -651,7 +929,8 @@ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
-static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+static void b43_nphy_write_clip_detection(struct b43_wldev *dev,
+ const u16 *clip_st)
{
b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]);
b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]);
@@ -727,7 +1006,7 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
struct b43_phy_n *nphy = phy->n;
if (enable) {
- u16 clip[] = { 0xFFFF, 0xFFFF };
+ static const u16 clip[] = { 0xFFFF, 0xFFFF };
if (nphy->deaf_count++ == 0) {
nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
b43_nphy_classifier(dev, 0x7, 0);
@@ -839,7 +1118,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
u16 data[4];
s16 gain[2];
u16 minmax[2];
- u16 lna_gain[4] = { -2, 10, 19, 25 };
+ static const u16 lna_gain[4] = { -2, 10, 19, 25 };
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 1);
@@ -871,7 +1150,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
data[2] = lna_gain[2] + gain[i];
data[3] = lna_gain[3] + gain[i];
}
- b43_ntab_write_bulk(dev, B43_NTAB16(10, 8), 4, data);
+ b43_ntab_write_bulk(dev, B43_NTAB16(i, 8), 4, data);
minmax[i] = 23 + gain[i];
}
@@ -891,6 +1170,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
struct b43_phy_n *nphy = dev->phy.n;
u8 i, j;
u8 code;
+ u16 tmp;
/* TODO: for PHY >= 3
s8 *lna1_gain, *lna2_gain;
@@ -913,15 +1193,15 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
B43_NPHY_C2_CGAINI_CL2DETECT);
/* Set narrowband clip threshold */
- b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
- b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
+ b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
+ b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
if (!dev->phy.is_40mhz) {
/* Set dwell lengths */
- b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
- b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
- b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
- b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
+ b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
+ b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
+ b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
+ b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
}
/* Set wideband clip 2 threshold */
@@ -943,7 +1223,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
}
- b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+ b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
if (nphy->gain_boost) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
@@ -964,10 +1244,10 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
- (code << 8 | 0x7C));
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
- (code << 8 | 0x7C));
+ /* specs say about 2 loops, but wl does 4 */
+ for (i = 0; i < 4; i++)
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x7C));
b43_nphy_adjust_lna_gain_table(dev);
@@ -985,19 +1265,21 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
- (code << 8 | 0x74));
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
- (code << 8 | 0x74));
+ /* specs say about 2 loops, but wl does 4 */
+ for (i = 0; i < 4; i++)
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x74));
}
if (dev->phy.rev == 2) {
for (i = 0; i < 4; i++) {
b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
(0x0400 * i) + 0x0020);
- for (j = 0; j < 21; j++)
+ for (j = 0; j < 21; j++) {
+ tmp = j * (i < 2 ? 3 : 1);
b43_phy_write(dev,
- B43_NPHY_TABLE_DATALO, 3 * j);
+ B43_NPHY_TABLE_DATALO, tmp);
+ }
}
b43_nphy_set_rf_sequence(dev, 5,
@@ -1026,7 +1308,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
- if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
b43_nphy_classifier(dev, 1, 0);
else
b43_nphy_classifier(dev, 1, 1);
@@ -1049,29 +1331,18 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
}
- /* TODO: convert to b43_ntab_write? */
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
if (dev->phy.rev < 2) {
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800);
}
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
@@ -1565,19 +1836,20 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
}
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */
static void b43_nphy_bphy_init(struct b43_wldev *dev)
{
unsigned int i;
u16 val;
val = 0x1E1F;
- for (i = 0; i < 14; i++) {
+ for (i = 0; i < 16; i++) {
b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
val -= 0x202;
}
val = 0x3E3F;
for (i = 0; i < 16; i++) {
- b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
val -= 0x202;
}
b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
@@ -1585,7 +1857,8 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
- s8 offset, u8 core, u8 rail, u8 type)
+ s8 offset, u8 core, u8 rail,
+ enum b43_nphy_rssi_type type)
{
u16 tmp;
bool core1or5 = (core == 1) || (core == 5);
@@ -1594,53 +1867,59 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
offset = clamp_val(offset, -32, 31);
tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
- if (core1or5 && (rail == 0) && (type == 2))
+ if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
- if (core1or5 && (rail == 1) && (type == 2))
+ if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
- if (core2or5 && (rail == 0) && (type == 2))
+ if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
- if (core2or5 && (rail == 1) && (type == 2))
+ if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
- if (core1or5 && (rail == 0) && (type == 0))
+
+ if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
- if (core1or5 && (rail == 1) && (type == 0))
+ if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
- if (core2or5 && (rail == 0) && (type == 0))
+ if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
- if (core2or5 && (rail == 1) && (type == 0))
+ if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
- if (core1or5 && (rail == 0) && (type == 1))
+
+ if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
- if (core1or5 && (rail == 1) && (type == 1))
+ if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
- if (core2or5 && (rail == 0) && (type == 1))
+ if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
- if (core2or5 && (rail == 1) && (type == 1))
+ if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
- if (core1or5 && (rail == 0) && (type == 6))
+
+ if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
- if (core1or5 && (rail == 1) && (type == 6))
+ if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
- if (core2or5 && (rail == 0) && (type == 6))
+ if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
- if (core2or5 && (rail == 1) && (type == 6))
+ if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
- if (core1or5 && (rail == 0) && (type == 3))
+
+ if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
- if (core1or5 && (rail == 1) && (type == 3))
+ if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
- if (core2or5 && (rail == 0) && (type == 3))
+ if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
- if (core2or5 && (rail == 1) && (type == 3))
+ if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
- if (core1or5 && (type == 4))
+
+ if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
- if (core2or5 && (type == 4))
+ if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
- if (core1or5 && (type == 5))
+
+ if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
- if (core2or5 && (type == 5))
+ if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
}
@@ -1668,27 +1947,39 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
(type + 1) << 4);
}
- /* TODO use some definitions */
if (code == 0) {
- b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
if (type < 3) {
- b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0);
- b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0);
- b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ ~(B43_NPHY_RFCTL_CMD_RXEN |
+ B43_NPHY_RFCTL_CMD_CORESEL));
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
+ ~(0x1 << 12 |
+ 0x1 << 5 |
+ 0x1 << 1 |
+ 0x1));
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+ ~B43_NPHY_RFCTL_CMD_START);
udelay(20);
- b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
}
} else {
- b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
- 0x3000);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
if (type < 3) {
b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
- 0xFEC7, 0x0180);
- b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
- 0xEFDC, (code << 1 | 0x1021));
- b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1);
+ ~(B43_NPHY_RFCTL_CMD_RXEN |
+ B43_NPHY_RFCTL_CMD_CORESEL),
+ (B43_NPHY_RFCTL_CMD_RXEN |
+ code << B43_NPHY_RFCTL_CMD_CORESEL_SHIFT));
+ b43_phy_set(dev, B43_NPHY_RFCTL_OVER,
+ (0x1 << 12 |
+ 0x1 << 5 |
+ 0x1 << 1 |
+ 0x1));
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_START);
udelay(20);
- b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
}
}
}
@@ -1837,6 +2128,14 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+ } else if (dev->phy.rev == 2) {
+ save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+ save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+ save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_RFCTL_CMD);
+ save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
+ save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
+ save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
}
b43_nphy_rssi_select(dev, 5, type);
@@ -1880,6 +2179,14 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
+ } else if (dev->phy.rev == 2) {
+ b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[0]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[2]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_CMD, save_regs_phy[3]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_OVER, save_regs_phy[4]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, save_regs_phy[5]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, save_regs_phy[6]);
}
return out;
@@ -1894,7 +2201,10 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
u16 class, override;
u8 regs_save_radio[2];
u16 regs_save_phy[2];
+
s8 offset[4];
+ u8 core;
+ u8 rail;
u16 clip_state[2];
u16 clip_off[2] = { 0xFFFF, 0xFFFF };
@@ -1995,16 +2305,15 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
if (results_min[i] == 248)
offset[i] = code - 32;
- if (i % 2 == 0)
- b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0,
- type);
- else
- b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1,
- type);
+ core = (i / 2) ? 2 : 1;
+ rail = (i % 2) ? 1 : 0;
+
+ b43_nphy_scale_offset_rssi(dev, 0, offset[i], core, rail,
+ type);
}
b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
- b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]);
+ b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, state[1]);
switch (state[2]) {
case 1:
@@ -2042,6 +2351,9 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
b43_nphy_classifier(dev, 7, class);
b43_nphy_write_clip_detection(dev, clip_state);
+ /* Specs don't say about reset here, but it makes wl and b43 dumps
+ identical, it really seems wl performs this */
+ b43_nphy_reset_cca(dev);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
@@ -2059,9 +2371,9 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev)
if (dev->phy.rev >= 3) {
b43_nphy_rev3_rssi_cal(dev);
} else {
- b43_nphy_rev2_rssi_cal(dev, 2);
- b43_nphy_rev2_rssi_cal(dev, 0);
- b43_nphy_rev2_rssi_cal(dev, 1);
+ b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Z);
+ b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_X);
+ b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Y);
}
}
@@ -2295,7 +2607,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
{
int i, j;
/* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */
- u16 offset[] = { 0x186, 0x195, 0x2C5 };
+ static const u16 offset[] = { 0x186, 0x195, 0x2C5 };
for (i = 0; i < 3; i++)
for (j = 0; j < 15; j++)
@@ -2327,7 +2639,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
struct nphy_txgains target;
const u32 *table = NULL;
- if (nphy->txpwrctrl == 0) {
+ if (!nphy->txpwrctrl) {
int i;
if (nphy->hang_avoid)
@@ -2884,7 +3196,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
u8 rfctl[2];
u8 afectl_core;
u16 tmp[6];
- u16 cur_hpf1, cur_hpf2, cur_lna;
+ u16 uninitialized_var(cur_hpf1), uninitialized_var(cur_hpf2), cur_lna;
u32 real, imag;
enum ieee80211_band band;
@@ -3077,9 +3389,9 @@ static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
{
u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
if (on)
- tmslow |= SSB_TMSLOW_PHYCLK;
+ tmslow |= B43_TMSLOW_MACPHYCLKEN;
else
- tmslow &= ~SSB_TMSLOW_PHYCLK;
+ tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
}
@@ -3088,7 +3400,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;
- u16 buf[16];
+ /* u16 buf[16]; it's rev3+ */
nphy->phyrxchain = mask;
@@ -3232,10 +3544,12 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_nphy_classifier(dev, 0, 0);
b43_nphy_read_clip_detection(dev, clip);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_nphy_bphy_init(dev);
+
tx_pwr_state = nphy->txpwrctrl;
- /* TODO N PHY TX power control with argument 0
- (turning off power control) */
- /* TODO Fix the TX Power Settings */
+ b43_nphy_tx_power_ctrl(dev, false);
+ b43_nphy_tx_power_fix(dev);
/* TODO N PHY TX Power Control Idle TSSI */
/* TODO N PHY TX Power Control Setup */
@@ -3292,21 +3606,18 @@ int b43_phy_initn(struct b43_wldev *dev)
/* TODO N PHY Pre Calibrate TX Gain */
target = b43_nphy_get_tx_gains(dev);
}
- }
+ if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false))
+ if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
+ b43_nphy_save_cal(dev);
+ } else if (nphy->mphase_cal_phase_id == 0)
+ ;/* N PHY Periodic Calibration with arg 3 */
+ } else {
+ b43_nphy_restore_cal(dev);
}
}
- if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) {
- if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
- b43_nphy_save_cal(dev);
- else if (nphy->mphase_cal_phase_id == 0)
- ;/* N PHY Periodic Calibration with argument 3 */
- } else {
- b43_nphy_restore_cal(dev);
- }
-
b43_nphy_tx_pwr_ctrl_coef_setup(dev);
- /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */
+ b43_nphy_tx_power_ctrl(dev, tx_pwr_state);
b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
if (phy->rev >= 3 && phy->rev <= 6)
@@ -3315,7 +3626,6 @@ int b43_phy_initn(struct b43_wldev *dev)
if (phy->rev >= 3)
b43_nphy_spur_workaround(dev);
- b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
return 0;
}
@@ -3357,7 +3667,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840);
}
- if (nphy->txpwrctrl)
+ if (!nphy->txpwrctrl)
b43_nphy_tx_power_fix(dev);
if (dev->phy.rev < 3)
@@ -3381,7 +3691,6 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
enum nl80211_channel_type channel_type)
{
struct b43_phy *phy = &dev->phy;
- struct b43_phy_n *nphy = dev->phy.n;
const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
@@ -3391,7 +3700,6 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
if (dev->phy.rev >= 3) {
tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
channel->center_freq);
- tabent_r3 = NULL;
if (!tabent_r3)
return -ESRCH;
} else {
@@ -3420,7 +3728,7 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
if (dev->phy.rev >= 3) {
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
- /* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
+ b43_radio_2056_setup(dev, tabent_r3);
b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel);
} else {
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050;
@@ -3451,7 +3759,11 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
memset(nphy, 0, sizeof(*nphy));
- //TODO init struct b43_phy_n
+ nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
+ nphy->gain_boost = true; /* this way we follow wl, assume it is true */
+ nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
+ nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
+ nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */
}
static void b43_nphy_op_free(struct b43_wldev *dev)
@@ -3500,6 +3812,15 @@ static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
+static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+{
+ check_phyreg(dev, reg);
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+}
+
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
@@ -3524,8 +3845,6 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
bool blocked)
{
- struct b43_phy_n *nphy = dev->phy.n;
-
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
@@ -3596,6 +3915,7 @@ const struct b43_phy_operations b43_phyops_n = {
.init = b43_nphy_op_init,
.phy_read = b43_nphy_op_read,
.phy_write = b43_nphy_op_write,
+ .phy_maskset = b43_nphy_op_maskset,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
.software_rfkill = b43_nphy_op_software_rfkill,
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index c144e59a708b..001e841f118c 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -782,7 +782,7 @@ struct b43_phy_n {
u16 mphase_txcal_numcmds;
u16 mphase_txcal_bestcoeffs[11];
- u8 txpwrctrl;
+ bool txpwrctrl;
u16 txcal_bbmult;
u16 txiqlocal_bestc[11];
bool txiqlocal_coeffsvalid;
diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c
index 1b5316586cbf..44c6dea66882 100644
--- a/drivers/net/wireless/b43/radio_2055.c
+++ b/drivers/net/wireless/b43/radio_2055.c
@@ -244,7 +244,7 @@ static const struct b2055_inittab_entry b2055_inittab [] = {
[0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCE] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
[0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
@@ -256,7 +256,7 @@ static const struct b2055_inittab_entry b2055_inittab [] = {
[0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xDA] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
[0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
[0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
@@ -304,178 +304,178 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
{ .channel = 184,
.freq = 4920, /* MHz */
.unk2 = 3280,
- RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xEC, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
+ PHYREGS(0x07B4, 0x07B0, 0x07AC, 0x0214, 0x0215, 0x0216),
},
{ .channel = 186,
.freq = 4930, /* MHz */
.unk2 = 3287,
- RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xED, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
+ PHYREGS(0x07B8, 0x07B4, 0x07B0, 0x0213, 0x0214, 0x0215),
},
{ .channel = 188,
.freq = 4940, /* MHz */
.unk2 = 3293,
- RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xEE, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
+ PHYREGS(0x07BC, 0x07B8, 0x07B4, 0x0212, 0x0213, 0x0214),
},
{ .channel = 190,
.freq = 4950, /* MHz */
.unk2 = 3300,
- RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xEF, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
+ PHYREGS(0x07C0, 0x07BC, 0x07B8, 0x0211, 0x0212, 0x0213),
},
{ .channel = 192,
.freq = 4960, /* MHz */
.unk2 = 3307,
- RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF0, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
+ PHYREGS(0x07C4, 0x07C0, 0x07BC, 0x020F, 0x0211, 0x0212),
},
{ .channel = 194,
.freq = 4970, /* MHz */
.unk2 = 3313,
- RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF1, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
+ PHYREGS(0x07C8, 0x07C4, 0x07C0, 0x020E, 0x020F, 0x0211),
},
{ .channel = 196,
.freq = 4980, /* MHz */
.unk2 = 3320,
- RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF2, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
+ PHYREGS(0x07CC, 0x07C8, 0x07C4, 0x020D, 0x020E, 0x020F),
},
{ .channel = 198,
.freq = 4990, /* MHz */
.unk2 = 3327,
- RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF3, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
+ PHYREGS(0x07D0, 0x07CC, 0x07C8, 0x020C, 0x020D, 0x020E),
},
{ .channel = 200,
.freq = 5000, /* MHz */
.unk2 = 3333,
- RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF4, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
+ PHYREGS(0x07D4, 0x07D0, 0x07CC, 0x020B, 0x020C, 0x020D),
},
{ .channel = 202,
.freq = 5010, /* MHz */
.unk2 = 3340,
- RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF5, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
+ PHYREGS(0x07D8, 0x07D4, 0x07D0, 0x020A, 0x020B, 0x020C),
},
{ .channel = 204,
.freq = 5020, /* MHz */
.unk2 = 3347,
- RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF6, 0x01, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
+ PHYREGS(0x07DC, 0x07D8, 0x07D4, 0x0209, 0x020A, 0x020B),
},
{ .channel = 206,
.freq = 5030, /* MHz */
.unk2 = 3353,
- RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF7, 0x01, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
+ PHYREGS(0x07E0, 0x07DC, 0x07D8, 0x0208, 0x0209, 0x020A),
},
{ .channel = 208,
.freq = 5040, /* MHz */
.unk2 = 3360,
- RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF8, 0x01, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
+ PHYREGS(0x07E4, 0x07E0, 0x07DC, 0x0207, 0x0208, 0x0209),
},
{ .channel = 210,
.freq = 5050, /* MHz */
.unk2 = 3367,
- RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xF9, 0x01, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
+ PHYREGS(0x07E8, 0x07E4, 0x07E0, 0x0206, 0x0207, 0x0208),
},
{ .channel = 212,
.freq = 5060, /* MHz */
.unk2 = 3373,
- RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFA, 0x01, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
- PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
+ PHYREGS(0x07EC, 0x07E8, 0x07E4, 0x0205, 0x0206, 0x0207),
},
{ .channel = 214,
.freq = 5070, /* MHz */
.unk2 = 3380,
- RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFB, 0x01, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
- PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
+ PHYREGS(0x07F0, 0x07EC, 0x07E8, 0x0204, 0x0205, 0x0206),
},
{ .channel = 216,
.freq = 5080, /* MHz */
.unk2 = 3387,
- RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFC, 0x01, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
- PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
+ PHYREGS(0x07F4, 0x07F0, 0x07EC, 0x0203, 0x0204, 0x0205),
},
{ .channel = 218,
.freq = 5090, /* MHz */
.unk2 = 3393,
- RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFD, 0x01, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
- PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
+ PHYREGS(0x07F8, 0x07F4, 0x07F0, 0x0202, 0x0203, 0x0204),
},
{ .channel = 220,
.freq = 5100, /* MHz */
.unk2 = 3400,
- RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFE, 0x01, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
- PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
+ PHYREGS(0x07FC, 0x07F8, 0x07F4, 0x0201, 0x0202, 0x0203),
},
{ .channel = 222,
.freq = 5110, /* MHz */
.unk2 = 3407,
- RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0xFF, 0x01, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
- PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
+ PHYREGS(0x0800, 0x07FC, 0x07F8, 0x0200, 0x0201, 0x0202),
},
{ .channel = 224,
.freq = 5120, /* MHz */
.unk2 = 3413,
- RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x00, 0x02, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
- PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
+ PHYREGS(0x0804, 0x0800, 0x07FC, 0x01FF, 0x0200, 0x0201),
},
{ .channel = 226,
.freq = 5130, /* MHz */
.unk2 = 3420,
- RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x01, 0x02, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
- PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01FE, 0x01FF, 0x0200),
},
{ .channel = 228,
.freq = 5140, /* MHz */
@@ -483,815 +483,815 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
- PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
+ PHYREGS(0x080C, 0x0808, 0x0804, 0x01FD, 0x01FE, 0x01FF),
},
{ .channel = 32,
.freq = 5160, /* MHz */
.unk2 = 3440,
- RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x04, 0x02, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
- PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
+ PHYREGS(0x0814, 0x0810, 0x080C, 0x01FB, 0x01FC, 0x01FD),
},
{ .channel = 34,
.freq = 5170, /* MHz */
.unk2 = 3447,
- RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x05, 0x02, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
- PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01FA, 0x01FB, 0x01FC),
},
{ .channel = 36,
.freq = 5180, /* MHz */
.unk2 = 3453,
- RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x06, 0x02, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
- PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
+ PHYREGS(0x081C, 0x0818, 0x0814, 0x01F9, 0x01FA, 0x01FB),
},
{ .channel = 38,
.freq = 5190, /* MHz */
.unk2 = 3460,
- RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x07, 0x02, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
- PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
+ PHYREGS(0x0820, 0x081C, 0x0818, 0x01F8, 0x01F9, 0x01FA),
},
{ .channel = 40,
.freq = 5200, /* MHz */
.unk2 = 3467,
- RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x08, 0x02, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
- PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
+ PHYREGS(0x0824, 0x0820, 0x081C, 0x01F7, 0x01F8, 0x01F9),
},
{ .channel = 42,
.freq = 5210, /* MHz */
.unk2 = 3473,
- RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x09, 0x02, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
- PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01F6, 0x01F7, 0x01F8),
},
{ .channel = 44,
.freq = 5220, /* MHz */
.unk2 = 3480,
- RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0A, 0x02, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
- PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
+ PHYREGS(0x082C, 0x0828, 0x0824, 0x01F5, 0x01F6, 0x01F7),
},
{ .channel = 46,
.freq = 5230, /* MHz */
.unk2 = 3487,
- RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0B, 0x02, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
- PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
+ PHYREGS(0x0830, 0x082C, 0x0828, 0x01F4, 0x01F5, 0x01F6),
},
{ .channel = 48,
.freq = 5240, /* MHz */
.unk2 = 3493,
- RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0C, 0x02, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
- PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
+ PHYREGS(0x0834, 0x0830, 0x082C, 0x01F3, 0x01F4, 0x01F5),
},
{ .channel = 50,
.freq = 5250, /* MHz */
.unk2 = 3500,
- RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0D, 0x02, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
- PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01F2, 0x01F3, 0x01F4),
},
{ .channel = 52,
.freq = 5260, /* MHz */
.unk2 = 3507,
- RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0E, 0x02, 0x0A, 0x98, 0x01, 0x04, 0x0A,
0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
- PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
+ PHYREGS(0x083C, 0x0838, 0x0834, 0x01F1, 0x01F2, 0x01F3),
},
{ .channel = 54,
.freq = 5270, /* MHz */
.unk2 = 3513,
- RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x0F, 0x02, 0x0A, 0x98, 0x01, 0x04, 0x0A,
0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
- PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
+ PHYREGS(0x0840, 0x083C, 0x0838, 0x01F0, 0x01F1, 0x01F2),
},
{ .channel = 56,
.freq = 5280, /* MHz */
.unk2 = 3520,
- RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x10, 0x02, 0x09, 0x91, 0x01, 0x04, 0x0A,
0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
- PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
+ PHYREGS(0x0844, 0x0840, 0x083C, 0x01F0, 0x01F0, 0x01F1),
},
{ .channel = 58,
.freq = 5290, /* MHz */
.unk2 = 3527,
- RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x11, 0x02, 0x09, 0x91, 0x01, 0x04, 0x0A,
0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
- PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01EF, 0x01F0, 0x01F0),
},
{ .channel = 60,
.freq = 5300, /* MHz */
.unk2 = 3533,
- RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x12, 0x02, 0x09, 0x8A, 0x01, 0x04, 0x0A,
0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
- PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
+ PHYREGS(0x084C, 0x0848, 0x0844, 0x01EE, 0x01EF, 0x01F0),
},
{ .channel = 62,
.freq = 5310, /* MHz */
.unk2 = 3540,
- RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x13, 0x02, 0x09, 0x8A, 0x01, 0x04, 0x0A,
0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
- PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
+ PHYREGS(0x0850, 0x084C, 0x0848, 0x01ED, 0x01EE, 0x01EF),
},
{ .channel = 64,
.freq = 5320, /* MHz */
.unk2 = 3547,
- RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x14, 0x02, 0x09, 0x83, 0x01, 0x04, 0x0A,
0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
- PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
+ PHYREGS(0x0854, 0x0850, 0x084C, 0x01EC, 0x01ED, 0x01EE),
},
{ .channel = 66,
.freq = 5330, /* MHz */
.unk2 = 3553,
- RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x15, 0x02, 0x09, 0x83, 0x01, 0x04, 0x0A,
0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
- PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01EB, 0x01EC, 0x01ED),
},
{ .channel = 68,
.freq = 5340, /* MHz */
.unk2 = 3560,
- RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x16, 0x02, 0x08, 0x7C, 0x01, 0x04, 0x0A,
0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
- PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
+ PHYREGS(0x085C, 0x0858, 0x0854, 0x01EA, 0x01EB, 0x01EC),
},
{ .channel = 70,
.freq = 5350, /* MHz */
.unk2 = 3567,
- RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x17, 0x02, 0x08, 0x7C, 0x01, 0x04, 0x0A,
0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
- PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
+ PHYREGS(0x0860, 0x085C, 0x0858, 0x01E9, 0x01EA, 0x01EB),
},
{ .channel = 72,
.freq = 5360, /* MHz */
.unk2 = 3573,
- RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x18, 0x02, 0x08, 0x75, 0x01, 0x04, 0x0A,
0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
- PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
+ PHYREGS(0x0864, 0x0860, 0x085C, 0x01E8, 0x01E9, 0x01EA),
},
{ .channel = 74,
.freq = 5370, /* MHz */
.unk2 = 3580,
- RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x19, 0x02, 0x08, 0x75, 0x01, 0x04, 0x0A,
0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
- PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01E7, 0x01E8, 0x01E9),
},
{ .channel = 76,
.freq = 5380, /* MHz */
.unk2 = 3587,
- RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1A, 0x02, 0x08, 0x6E, 0x01, 0x04, 0x0A,
0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
- PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
+ PHYREGS(0x086C, 0x0868, 0x0864, 0x01E6, 0x01E7, 0x01E8),
},
{ .channel = 78,
.freq = 5390, /* MHz */
.unk2 = 3593,
- RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1B, 0x02, 0x08, 0x6E, 0x01, 0x04, 0x0A,
0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
- PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
+ PHYREGS(0x0870, 0x086C, 0x0868, 0x01E5, 0x01E6, 0x01E7),
},
{ .channel = 80,
.freq = 5400, /* MHz */
.unk2 = 3600,
- RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1C, 0x02, 0x07, 0x67, 0x01, 0x04, 0x0A,
0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
- PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
+ PHYREGS(0x0874, 0x0870, 0x086C, 0x01E5, 0x01E5, 0x01E6),
},
{ .channel = 82,
.freq = 5410, /* MHz */
.unk2 = 3607,
- RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1D, 0x02, 0x07, 0x67, 0x01, 0x04, 0x0A,
0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
- PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01E4, 0x01E5, 0x01E5),
},
{ .channel = 84,
.freq = 5420, /* MHz */
.unk2 = 3613,
- RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1E, 0x02, 0x07, 0x61, 0x01, 0x04, 0x0A,
0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
- PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
+ PHYREGS(0x087C, 0x0878, 0x0874, 0x01E3, 0x01E4, 0x01E5),
},
{ .channel = 86,
.freq = 5430, /* MHz */
.unk2 = 3620,
- RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x1F, 0x02, 0x07, 0x61, 0x01, 0x04, 0x0A,
0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
- PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
+ PHYREGS(0x0880, 0x087C, 0x0878, 0x01E2, 0x01E3, 0x01E4),
},
{ .channel = 88,
.freq = 5440, /* MHz */
.unk2 = 3627,
- RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x20, 0x02, 0x07, 0x5A, 0x01, 0x04, 0x0A,
0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
- PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
+ PHYREGS(0x0884, 0x0880, 0x087C, 0x01E1, 0x01E2, 0x01E3),
},
{ .channel = 90,
.freq = 5450, /* MHz */
.unk2 = 3633,
- RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x21, 0x02, 0x07, 0x5A, 0x01, 0x04, 0x0A,
0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
- PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01E0, 0x01E1, 0x01E2),
},
{ .channel = 92,
.freq = 5460, /* MHz */
.unk2 = 3640,
- RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x22, 0x02, 0x06, 0x53, 0x01, 0x04, 0x0A,
0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
- PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
+ PHYREGS(0x088C, 0x0888, 0x0884, 0x01DF, 0x01E0, 0x01E1),
},
{ .channel = 94,
.freq = 5470, /* MHz */
.unk2 = 3647,
- RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x23, 0x02, 0x06, 0x53, 0x01, 0x04, 0x0A,
0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
- PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
+ PHYREGS(0x0890, 0x088C, 0x0888, 0x01DE, 0x01DF, 0x01E0),
},
{ .channel = 96,
.freq = 5480, /* MHz */
.unk2 = 3653,
- RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x24, 0x02, 0x06, 0x4D, 0x01, 0x04, 0x0A,
0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
+ PHYREGS(0x0894, 0x0890, 0x088C, 0x01DD, 0x01DE, 0x01DF),
},
{ .channel = 98,
.freq = 5490, /* MHz */
.unk2 = 3660,
- RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x25, 0x02, 0x06, 0x4D, 0x01, 0x04, 0x0A,
0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01DD, 0x01DD, 0x01DE),
},
{ .channel = 100,
.freq = 5500, /* MHz */
.unk2 = 3667,
- RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x26, 0x02, 0x06, 0x47, 0x01, 0x04, 0x0A,
0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
+ PHYREGS(0x089C, 0x0898, 0x0894, 0x01DC, 0x01DD, 0x01DD),
},
{ .channel = 102,
.freq = 5510, /* MHz */
.unk2 = 3673,
- RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x27, 0x02, 0x06, 0x47, 0x01, 0x04, 0x0A,
0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
+ PHYREGS(0x08A0, 0x089C, 0x0898, 0x01DB, 0x01DC, 0x01DD),
},
{ .channel = 104,
.freq = 5520, /* MHz */
.unk2 = 3680,
- RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x28, 0x02, 0x05, 0x40, 0x01, 0x04, 0x0A,
0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
+ PHYREGS(0x08A4, 0x08A0, 0x089C, 0x01DA, 0x01DB, 0x01DC),
},
{ .channel = 106,
.freq = 5530, /* MHz */
.unk2 = 3687,
- RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x29, 0x02, 0x05, 0x40, 0x01, 0x04, 0x0A,
0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
+ PHYREGS(0x08A8, 0x08A4, 0x08A0, 0x01D9, 0x01DA, 0x01DB),
},
{ .channel = 108,
.freq = 5540, /* MHz */
.unk2 = 3693,
- RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2A, 0x02, 0x05, 0x3A, 0x01, 0x04, 0x0A,
0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
+ PHYREGS(0x08AC, 0x08A8, 0x08A4, 0x01D8, 0x01D9, 0x01DA),
},
{ .channel = 110,
.freq = 5550, /* MHz */
.unk2 = 3700,
- RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2B, 0x02, 0x05, 0x3A, 0x01, 0x04, 0x0A,
0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
+ PHYREGS(0x08B0, 0x08AC, 0x08A8, 0x01D7, 0x01D8, 0x01D9),
},
{ .channel = 112,
.freq = 5560, /* MHz */
.unk2 = 3707,
- RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2C, 0x02, 0x05, 0x34, 0x01, 0x04, 0x0A,
0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
+ PHYREGS(0x08B4, 0x08B0, 0x08AC, 0x01D7, 0x01D7, 0x01D8),
},
{ .channel = 114,
.freq = 5570, /* MHz */
.unk2 = 3713,
- RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2D, 0x02, 0x05, 0x34, 0x01, 0x04, 0x0A,
0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
+ PHYREGS(0x08B8, 0x08B4, 0x08B0, 0x01D6, 0x01D7, 0x01D7),
},
{ .channel = 116,
.freq = 5580, /* MHz */
.unk2 = 3720,
- RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2E, 0x02, 0x04, 0x2E, 0x01, 0x04, 0x0A,
0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
+ PHYREGS(0x08BC, 0x08B8, 0x08B4, 0x01D5, 0x01D6, 0x01D7),
},
{ .channel = 118,
.freq = 5590, /* MHz */
.unk2 = 3727,
- RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x2F, 0x02, 0x04, 0x2E, 0x01, 0x04, 0x0A,
0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
+ PHYREGS(0x08C0, 0x08BC, 0x08B8, 0x01D4, 0x01D5, 0x01D6),
},
{ .channel = 120,
.freq = 5600, /* MHz */
.unk2 = 3733,
- RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x30, 0x02, 0x04, 0x28, 0x01, 0x04, 0x0A,
0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
+ PHYREGS(0x08C4, 0x08C0, 0x08BC, 0x01D3, 0x01D4, 0x01D5),
},
{ .channel = 122,
.freq = 5610, /* MHz */
.unk2 = 3740,
- RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x31, 0x02, 0x04, 0x28, 0x01, 0x04, 0x0A,
0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
+ PHYREGS(0x08C8, 0x08C4, 0x08C0, 0x01D2, 0x01D3, 0x01D4),
},
{ .channel = 124,
.freq = 5620, /* MHz */
.unk2 = 3747,
- RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x32, 0x02, 0x04, 0x21, 0x01, 0x04, 0x0A,
0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
+ PHYREGS(0x08CC, 0x08C8, 0x08C4, 0x01D2, 0x01D2, 0x01D3),
},
{ .channel = 126,
.freq = 5630, /* MHz */
.unk2 = 3753,
- RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x33, 0x02, 0x04, 0x21, 0x01, 0x04, 0x0A,
0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
+ PHYREGS(0x08D0, 0x08CC, 0x08C8, 0x01D1, 0x01D2, 0x01D2),
},
{ .channel = 128,
.freq = 5640, /* MHz */
.unk2 = 3760,
- RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x34, 0x02, 0x03, 0x1C, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
+ PHYREGS(0x08D4, 0x08D0, 0x08CC, 0x01D0, 0x01D1, 0x01D2),
},
{ .channel = 130,
.freq = 5650, /* MHz */
.unk2 = 3767,
- RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x35, 0x02, 0x03, 0x1C, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
+ PHYREGS(0x08D8, 0x08D4, 0x08D0, 0x01CF, 0x01D0, 0x01D1),
},
{ .channel = 132,
.freq = 5660, /* MHz */
.unk2 = 3773,
- RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x36, 0x02, 0x03, 0x16, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
+ PHYREGS(0x08DC, 0x08D8, 0x08D4, 0x01CE, 0x01CF, 0x01D0),
},
{ .channel = 134,
.freq = 5670, /* MHz */
.unk2 = 3780,
- RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x37, 0x02, 0x03, 0x16, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
+ PHYREGS(0x08E0, 0x08DC, 0x08D8, 0x01CE, 0x01CE, 0x01CF),
},
{ .channel = 136,
.freq = 5680, /* MHz */
.unk2 = 3787,
- RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x38, 0x02, 0x03, 0x10, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
+ PHYREGS(0x08E4, 0x08E0, 0x08DC, 0x01CD, 0x01CE, 0x01CE),
},
{ .channel = 138,
.freq = 5690, /* MHz */
.unk2 = 3793,
- RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x39, 0x02, 0x03, 0x10, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
+ PHYREGS(0x08E8, 0x08E4, 0x08E0, 0x01CC, 0x01CD, 0x01CE),
},
{ .channel = 140,
.freq = 5700, /* MHz */
.unk2 = 3800,
- RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3A, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
+ PHYREGS(0x08EC, 0x08E8, 0x08E4, 0x01CB, 0x01CC, 0x01CD),
},
{ .channel = 142,
.freq = 5710, /* MHz */
.unk2 = 3807,
- RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3B, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
+ PHYREGS(0x08F0, 0x08EC, 0x08E8, 0x01CA, 0x01CB, 0x01CC),
},
{ .channel = 144,
.freq = 5720, /* MHz */
.unk2 = 3813,
- RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3C, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
+ PHYREGS(0x08F4, 0x08F0, 0x08EC, 0x01C9, 0x01CA, 0x01CB),
},
{ .channel = 145,
.freq = 5725, /* MHz */
.unk2 = 3817,
- RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+ RADIOREGS(0x72, 0x79, 0x04, 0x02, 0x03, 0x01, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
+ PHYREGS(0x08F6, 0x08F2, 0x08EE, 0x01C9, 0x01CA, 0x01CB),
},
{ .channel = 146,
.freq = 5730, /* MHz */
.unk2 = 3820,
- RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3D, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
+ PHYREGS(0x08F8, 0x08F4, 0x08F0, 0x01C9, 0x01C9, 0x01CA),
},
{ .channel = 147,
.freq = 5735, /* MHz */
.unk2 = 3823,
- RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+ RADIOREGS(0x72, 0x7B, 0x04, 0x02, 0x03, 0x01, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
+ PHYREGS(0x08FA, 0x08F6, 0x08F2, 0x01C8, 0x01C9, 0x01CA),
},
{ .channel = 148,
.freq = 5740, /* MHz */
.unk2 = 3827,
- RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3E, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
+ PHYREGS(0x08FC, 0x08F8, 0x08F4, 0x01C8, 0x01C9, 0x01C9),
},
{ .channel = 149,
.freq = 5745, /* MHz */
.unk2 = 3830,
- RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x7D, 0x04, 0x02, 0xFE, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
+ PHYREGS(0x08FE, 0x08FA, 0x08F6, 0x01C8, 0x01C8, 0x01C9),
},
{ .channel = 150,
.freq = 5750, /* MHz */
.unk2 = 3833,
- RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x3F, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
+ PHYREGS(0x0900, 0x08FC, 0x08F8, 0x01C7, 0x01C8, 0x01C9),
},
{ .channel = 151,
.freq = 5755, /* MHz */
.unk2 = 3837,
- RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x7F, 0x04, 0x02, 0xFE, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
+ PHYREGS(0x0902, 0x08FE, 0x08FA, 0x01C7, 0x01C8, 0x01C8),
},
{ .channel = 152,
.freq = 5760, /* MHz */
.unk2 = 3840,
- RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x40, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
+ PHYREGS(0x0904, 0x0900, 0x08FC, 0x01C6, 0x01C7, 0x01C8),
},
{ .channel = 153,
.freq = 5765, /* MHz */
.unk2 = 3843,
- RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x81, 0x04, 0x02, 0xF8, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
+ PHYREGS(0x0906, 0x0902, 0x08FE, 0x01C6, 0x01C7, 0x01C8),
},
{ .channel = 154,
.freq = 5770, /* MHz */
.unk2 = 3847,
- RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x41, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01C6, 0x01C6, 0x01C7),
},
{ .channel = 155,
.freq = 5775, /* MHz */
.unk2 = 3850,
- RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x83, 0x04, 0x02, 0xF8, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
+ PHYREGS(0x090A, 0x0906, 0x0902, 0x01C5, 0x01C6, 0x01C7),
},
{ .channel = 156,
.freq = 5780, /* MHz */
.unk2 = 3853,
- RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x42, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
+ PHYREGS(0x090C, 0x0908, 0x0904, 0x01C5, 0x01C6, 0x01C6),
},
{ .channel = 157,
.freq = 5785, /* MHz */
.unk2 = 3857,
- RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x85, 0x04, 0x02, 0xF2, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
+ PHYREGS(0x090E, 0x090A, 0x0906, 0x01C4, 0x01C5, 0x01C6),
},
{ .channel = 158,
.freq = 5790, /* MHz */
.unk2 = 3860,
- RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x43, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
+ PHYREGS(0x0910, 0x090C, 0x0908, 0x01C4, 0x01C5, 0x01C6),
},
{ .channel = 159,
.freq = 5795, /* MHz */
.unk2 = 3863,
- RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x87, 0x04, 0x02, 0xF2, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
+ PHYREGS(0x0912, 0x090E, 0x090A, 0x01C4, 0x01C4, 0x01C5),
},
{ .channel = 160,
.freq = 5800, /* MHz */
.unk2 = 3867,
- RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x44, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
+ PHYREGS(0x0914, 0x0910, 0x090C, 0x01C3, 0x01C4, 0x01C5),
},
{ .channel = 161,
.freq = 5805, /* MHz */
.unk2 = 3870,
- RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x89, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
+ PHYREGS(0x0916, 0x0912, 0x090E, 0x01C3, 0x01C4, 0x01C4),
},
{ .channel = 162,
.freq = 5810, /* MHz */
.unk2 = 3873,
- RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x45, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01C2, 0x01C3, 0x01C4),
},
{ .channel = 163,
.freq = 5815, /* MHz */
.unk2 = 3877,
- RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x8B, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
+ PHYREGS(0x091A, 0x0916, 0x0912, 0x01C2, 0x01C3, 0x01C4),
},
{ .channel = 164,
.freq = 5820, /* MHz */
.unk2 = 3880,
- RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x46, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
+ PHYREGS(0x091C, 0x0918, 0x0914, 0x01C2, 0x01C2, 0x01C3),
},
{ .channel = 165,
.freq = 5825, /* MHz */
.unk2 = 3883,
- RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+ RADIOREGS(0x72, 0x8D, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
+ PHYREGS(0x091E, 0x091A, 0x0916, 0x01C1, 0x01C2, 0x01C3),
},
{ .channel = 166,
.freq = 5830, /* MHz */
.unk2 = 3887,
- RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x47, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
+ PHYREGS(0x0920, 0x091C, 0x0918, 0x01C1, 0x01C2, 0x01C2),
},
{ .channel = 168,
.freq = 5840, /* MHz */
.unk2 = 3893,
- RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x48, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
+ PHYREGS(0x0924, 0x0920, 0x091C, 0x01C0, 0x01C1, 0x01C2),
},
{ .channel = 170,
.freq = 5850, /* MHz */
.unk2 = 3900,
- RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x49, 0x02, 0x01, 0xE0, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01BF, 0x01C0, 0x01C1),
},
{ .channel = 172,
.freq = 5860, /* MHz */
.unk2 = 3907,
- RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4A, 0x02, 0x01, 0xDE, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
+ PHYREGS(0x092C, 0x0928, 0x0924, 0x01BF, 0x01BF, 0x01C0),
},
{ .channel = 174,
.freq = 5870, /* MHz */
.unk2 = 3913,
- RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4B, 0x02, 0x00, 0xDB, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
+ PHYREGS(0x0930, 0x092C, 0x0928, 0x01BE, 0x01BF, 0x01BF),
},
{ .channel = 176,
.freq = 5880, /* MHz */
.unk2 = 3920,
- RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4C, 0x02, 0x00, 0xD8, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
+ PHYREGS(0x0934, 0x0930, 0x092C, 0x01BD, 0x01BE, 0x01BF),
},
{ .channel = 178,
.freq = 5890, /* MHz */
.unk2 = 3927,
- RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4D, 0x02, 0x00, 0xD6, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01BC, 0x01BD, 0x01BE),
},
{ .channel = 180,
.freq = 5900, /* MHz */
.unk2 = 3933,
- RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4E, 0x02, 0x00, 0xD3, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
+ PHYREGS(0x093C, 0x0938, 0x0934, 0x01BC, 0x01BC, 0x01BD),
},
{ .channel = 182,
.freq = 5910, /* MHz */
.unk2 = 3940,
- RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ RADIOREGS(0x71, 0x4F, 0x02, 0x00, 0xD6, 0x00, 0x04, 0x0A,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
+ PHYREGS(0x0940, 0x093C, 0x0938, 0x01BB, 0x01BC, 0x01BC),
},
{ .channel = 1,
.freq = 2412, /* MHz */
.unk2 = 3216,
- RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x6C, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
- PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
+ PHYREGS(0x03C9, 0x03C5, 0x03C1, 0x043A, 0x043F, 0x0443),
},
{ .channel = 2,
.freq = 2417, /* MHz */
.unk2 = 3223,
- RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x71, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
- PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
+ PHYREGS(0x03CB, 0x03C7, 0x03C3, 0x0438, 0x043D, 0x0441),
},
{ .channel = 3,
.freq = 2422, /* MHz */
.unk2 = 3229,
- RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x76, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
- PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
+ PHYREGS(0x03CD, 0x03C9, 0x03C5, 0x0436, 0x043A, 0x043F),
},
{ .channel = 4,
.freq = 2427, /* MHz */
.unk2 = 3236,
- RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x7B, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
- PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
+ PHYREGS(0x03CF, 0x03CB, 0x03C7, 0x0434, 0x0438, 0x043D),
},
{ .channel = 5,
.freq = 2432, /* MHz */
.unk2 = 3243,
- RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x80, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
- PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
+ PHYREGS(0x03D1, 0x03CD, 0x03C9, 0x0431, 0x0436, 0x043A),
},
{ .channel = 6,
.freq = 2437, /* MHz */
.unk2 = 3249,
- RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x85, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
- PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
+ PHYREGS(0x03D3, 0x03CF, 0x03CB, 0x042F, 0x0434, 0x0438),
},
{ .channel = 7,
.freq = 2442, /* MHz */
.unk2 = 3256,
- RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x8A, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
- PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
+ PHYREGS(0x03D5, 0x03D1, 0x03CD, 0x042D, 0x0431, 0x0436),
},
{ .channel = 8,
.freq = 2447, /* MHz */
.unk2 = 3263,
- RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x8F, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
- PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
+ PHYREGS(0x03D7, 0x03D3, 0x03CF, 0x042B, 0x042F, 0x0434),
},
{ .channel = 9,
.freq = 2452, /* MHz */
.unk2 = 3269,
- RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x94, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
- PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
+ PHYREGS(0x03D9, 0x03D5, 0x03D1, 0x0429, 0x042D, 0x0431),
},
{ .channel = 10,
.freq = 2457, /* MHz */
.unk2 = 3276,
- RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x99, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
- PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
+ PHYREGS(0x03DB, 0x03D7, 0x03D3, 0x0427, 0x042B, 0x042F),
},
{ .channel = 11,
.freq = 2462, /* MHz */
.unk2 = 3283,
- RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0x9E, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
- PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
+ PHYREGS(0x03DD, 0x03D9, 0x03D5, 0x0424, 0x0429, 0x042D),
},
{ .channel = 12,
.freq = 2467, /* MHz */
.unk2 = 3289,
- RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0xA3, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
- PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
+ PHYREGS(0x03DF, 0x03DB, 0x03D7, 0x0422, 0x0427, 0x042B),
},
{ .channel = 13,
.freq = 2472, /* MHz */
.unk2 = 3296,
- RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0xA8, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
- PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
+ PHYREGS(0x03E1, 0x03DD, 0x03D9, 0x0420, 0x0424, 0x0429),
},
{ .channel = 14,
.freq = 2484, /* MHz */
.unk2 = 3312,
- RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+ RADIOREGS(0x73, 0xB4, 0x09, 0x0F, 0xFF, 0x01, 0x07, 0x15,
0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
- PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
+ PHYREGS(0x03E6, 0x03E2, 0x03DE, 0x041B, 0x041F, 0x0424),
},
};
@@ -1299,7 +1299,7 @@ void b2055_upload_inittab(struct b43_wldev *dev,
bool ghz5, bool ignore_uploadflag)
{
const struct b2055_inittab_entry *e;
- unsigned int i;
+ unsigned int i, writes = 0;
u16 value;
for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
@@ -1312,6 +1312,8 @@ void b2055_upload_inittab(struct b43_wldev *dev,
else
value = e->ghz2;
b43_radio_write16(dev, i, value);
+ if (++writes % 4 == 0)
+ b43_read32(dev, B43_MMIO_MACCTL); /* flush */
}
}
}
diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c
index d8563192ce56..8890df067029 100644
--- a/drivers/net/wireless/b43/radio_2056.c
+++ b/drivers/net/wireless/b43/radio_2056.c
@@ -24,17 +24,9073 @@
#include "radio_2056.h"
#include "phy_common.h"
+struct b2056_inittab_entry {
+ /* Value to write if we use the 5GHz band. */
+ u16 ghz5;
+ /* Value to write if we use the 2.4GHz band. */
+ u16 ghz2;
+ /* Flags */
+ u8 flags;
+};
+#define B2056_INITTAB_ENTRY_OK 0x01
+#define B2056_INITTAB_UPLOAD 0x02
+#define UPLOAD .flags = B2056_INITTAB_ENTRY_OK | B2056_INITTAB_UPLOAD
+#define NOUPLOAD .flags = B2056_INITTAB_ENTRY_OK
+
+struct b2056_inittabs_pts {
+ const struct b2056_inittab_entry *syn;
+ unsigned int syn_length;
+ const struct b2056_inittab_entry *tx;
+ unsigned int tx_length;
+ const struct b2056_inittab_entry *rx;
+ unsigned int rx_length;
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev3_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev3_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x002d, .ghz2 = 0x002d, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0074, .ghz2 = 0x0074, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev3_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0099, .ghz2 = 0x0099, NOUPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0044, .ghz2 = 0x0044, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0099, .ghz2 = 0x0099, NOUPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x0057, .ghz2 = 0x0057, NOUPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x0057, .ghz2 = 0x0057, NOUPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev4_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev4_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x002d, .ghz2 = 0x002d, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0072, .ghz2 = 0x0072, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev4_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0044, .ghz2 = 0x0044, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x002f, .ghz2 = 0x002f, UPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev5_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev5_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x002d, .ghz2 = 0x002d, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC0] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC1] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC2] = { .ghz5 = 0x0071, .ghz2 = 0x0071, UPLOAD, },
+ [B2056_TX_GMBB_IDAC3] = { .ghz5 = 0x0071, .ghz2 = 0x0071, UPLOAD, },
+ [B2056_TX_GMBB_IDAC4] = { .ghz5 = 0x0072, .ghz2 = 0x0072, UPLOAD, },
+ [B2056_TX_GMBB_IDAC5] = { .ghz5 = 0x0073, .ghz2 = 0x0073, UPLOAD, },
+ [B2056_TX_GMBB_IDAC6] = { .ghz5 = 0x0074, .ghz2 = 0x0074, UPLOAD, },
+ [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev5_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev6_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev6_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x00ee, .ghz2 = 0x00ee, UPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0030, .ghz2 = 0x0030, UPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC0] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC1] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC2] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC3] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC4] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC5] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC6] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev6_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev7_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev7_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x00ee, .ghz2 = 0x00ee, UPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0030, .ghz2 = 0x0030, UPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC0] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC1] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC2] = { .ghz5 = 0x0071, .ghz2 = 0x0071, UPLOAD, },
+ [B2056_TX_GMBB_IDAC3] = { .ghz5 = 0x0071, .ghz2 = 0x0071, UPLOAD, },
+ [B2056_TX_GMBB_IDAC4] = { .ghz5 = 0x0072, .ghz2 = 0x0072, UPLOAD, },
+ [B2056_TX_GMBB_IDAC5] = { .ghz5 = 0x0073, .ghz2 = 0x0073, UPLOAD, },
+ [B2056_TX_GMBB_IDAC6] = { .ghz5 = 0x0074, .ghz2 = 0x0074, UPLOAD, },
+ [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0075, .ghz2 = 0x0075, UPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev7_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev8_syn[] = {
+ [B2056_SYN_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_PU] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_GPIO_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_MASTER] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_TOPBIAS_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_AFEREG] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSEIDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_TEMPPROCSENSERCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LPO] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_VDDCAL_STATUS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCAL_CODE_OUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL1] = { .ghz5 = 0x001f, .ghz2 = 0x001f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL2] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL3] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_RCCAL_CTRL11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_ZCAL_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST1] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST2] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_MAST3] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2056_SYN_PLL_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL1] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL3] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL5] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_SYN_PLL_XTAL6] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_REFDIV] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_PFD] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_CP1] = { .ghz5 = 0x000f, .ghz2 = 0x000f, NOUPLOAD, },
+ [B2056_SYN_PLL_CP2] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_SYN_PLL_CP3] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER1] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER2] = { .ghz5 = 0x000d, .ghz2 = 0x000d, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER3] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER4] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_PLL_LOOPFILTER5] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD1] = { .ghz5 = 0x001c, .ghz2 = 0x001c, NOUPLOAD, },
+ [B2056_SYN_PLL_MMD2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO1] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCO2] = { .ghz5 = 0x00f7, .ghz2 = 0x00f7, UPLOAD, },
+ [B2056_SYN_PLL_MONITOR1] = { .ghz5 = 0x00b4, .ghz2 = 0x00b4, NOUPLOAD, },
+ [B2056_SYN_PLL_MONITOR2] = { .ghz5 = 0x00d2, .ghz2 = 0x00d2, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL4] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL6] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL7] = { .ghz5 = 0x003e, .ghz2 = 0x003e, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_SYN_PLL_VCOCAL12] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_SYN_PLL_VCOCAL13] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_SYN_PLL_VREG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_PLL_STATUS3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU2] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PU8] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BIAS_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RCCR1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF1] = { .ghz5 = 0x0060, .ghz2 = 0x0060, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER2] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF1] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGENBUF2] = { .ghz5 = 0x008f, .ghz2 = 0x008f, UPLOAD, },
+ [B2056_SYN_LOGEN_BUF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF4] = { .ghz5 = 0x00cc, .ghz2 = 0x00cc, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV1] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV2] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_DIV3] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLOUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACLCAL3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_CALEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_PEAKDET1] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_DIFF_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_ACL_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_VCOBUF2_OVRVAL]= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_SYN_LOGEN_MIXER3_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF5_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_BUF6_OVRVAL] = { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CBUFTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSRX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX1_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX2_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX3_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CMOSTX4_OVRVAL]= { .ghz5 = 0x0066, .ghz2 = 0x0066, NOUPLOAD, },
+ [B2056_SYN_LOGEN_ACL_WAITCNT] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_SYN_LOGEN_CORE_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_RX_CMOS_CALVALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_SYN_LOGEN_TX_CMOS_VALID] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev8_tx[] = {
+ [B2056_TX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_GAIN_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_FINE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_I] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_LOFT_COARSE_Q] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER1] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_TX_COM_MASTER2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_RXIQCAL_TXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_IQCAL_VCM_HG] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_IQCAL_IDAC] = { .ghz5 = 0x0037, .ghz2 = 0x0037, NOUPLOAD, },
+ [B2056_TX_TSSI_VCM] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_TX_AMP_DET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TX_SSI_MUX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSIA] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSIG] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TSSI_MISC3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PA_SPARE1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_TX_PA_SPARE2] = { .ghz5 = 0x00ee, .ghz2 = 0x00ee, UPLOAD, },
+ [B2056_TX_INTPAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAA_IAUX_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_STAT] = { .ghz5 = 0x0050, .ghz2 = 0x0050, UPLOAD, },
+ [B2056_TX_INTPAA_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAA_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAA_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAA_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_BOOST_TUNE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_STAT] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_TX_INTPAG_IAUX_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_STAT] = { .ghz5 = 0x001e, .ghz2 = 0x001e, NOUPLOAD, },
+ [B2056_TX_INTPAG_IMAIN_DYN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_INTPAG_CASCBIAS] = { .ghz5 = 0x006e, .ghz2 = 0x006e, NOUPLOAD, },
+ [B2056_TX_INTPAG_PASLOPE] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_TX_INTPAG_PA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PADA_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADA_BOOST_TUNE] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2056_TX_PADA_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PADG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PADG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PADG_CASCBIAS] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_TX_PADG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PADG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PADG_SLOPE] = { .ghz5 = 0x0070, .ghz2 = 0x0070, UPLOAD, },
+ [B2056_TX_PGAA_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAA_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_TX_PGAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAA_BOOST_TUNE] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2056_TX_PGAA_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAA_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_MASTER] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_PGAG_IDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_TX_PGAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_PGAG_BOOST_TUNE] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_TX_PGAG_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, UPLOAD, },
+ [B2056_TX_PGAG_MISC] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_TX_MIXA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXA_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_MIXG] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_MIXG_BOOST_TUNE] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_TX_BB_GM_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_GM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_TX_TXLPF_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_RCCAL_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_BW] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_TX_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_0] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_1] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_2] = { .ghz5 = 0x000e, .ghz2 = 0x000e, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_4] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_5] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_IDAC_6] = { .ghz5 = 0x001b, .ghz2 = 0x001b, NOUPLOAD, },
+ [B2056_TX_TXLPF_OPAMP_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_TX_TXLPF_MISC] = { .ghz5 = 0x005b, .ghz2 = 0x005b, NOUPLOAD, },
+ [B2056_TX_TXSPARE1] = { .ghz5 = 0x0030, .ghz2 = 0x0030, UPLOAD, },
+ [B2056_TX_TXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_TXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_INTPA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PAD_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_PGA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_GM_TXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_STATUS_TXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC0] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC1] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC2] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC3] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC4] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC5] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC6] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2056_TX_GMBB_IDAC7] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+};
+
+static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = {
+ [B2056_RX_RESERVED_ADDR2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_CTRL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_OVR] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RESET] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RCAL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_TXLPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_COM_RC_RXHPF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR17] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR18] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR19] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR20] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR21] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR22] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR23] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR24] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR25] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR26] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR27] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR28] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR29] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR30] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RESERVED_ADDR31] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXIQCAL_RXMUX] = { .ghz5 = 0x0003, .ghz2 = 0x0003, NOUPLOAD, },
+ [B2056_RX_RSSI_PU] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_SEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RSSI_GAIN] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_RSSI_NB_IDAC] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2I_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2056_RX_RSSI_WB2Q_IDAC_2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, NOUPLOAD, },
+ [B2056_RX_RSSI_POLE] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_RSSI_WB1_IDAC] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_RSSI_MISC] = { .ghz5 = 0x0090, .ghz2 = 0x0090, NOUPLOAD, },
+ [B2056_RX_LNAA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAA_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAA_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_A_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAA1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAA2_IDAC] = { .ghz5 = 0x00ff, .ghz2 = 0x00ff, UPLOAD, },
+ [B2056_RX_LNA1A_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_LNAG_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_LNAG_TUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2056_RX_LNAG_GAIN] = { .ghz5 = 0x0032, .ghz2 = 0x0032, NOUPLOAD, },
+ [B2056_RX_LNA_G_SLOPE] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2056_RX_BIASPOLE_LNAG1_IDAC] = { .ghz5 = 0x0017, .ghz2 = 0x0017, UPLOAD, },
+ [B2056_RX_LNAG2_IDAC] = { .ghz5 = 0x00f0, .ghz2 = 0x00f0, UPLOAD, },
+ [B2056_RX_LNA1G_MISC] = { .ghz5 = 0x0020, .ghz2 = 0x0020, NOUPLOAD, },
+ [B2056_RX_MIXA_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXA_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXA_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_LOB_BIAS] = { .ghz5 = 0x0088, .ghz2 = 0x0088, UPLOAD, },
+ [B2056_RX_MIXA_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXA_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2056_RX_MIXA_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXA_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXA_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_MIXG_VCM] = { .ghz5 = 0x0055, .ghz2 = 0x0055, UPLOAD, },
+ [B2056_RX_MIXG_CTRLPTAT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_LOB_BIAS] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2056_RX_MIXG_CORE_IDAC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_MIXG_CMFB_IDAC] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_AUX] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MAIN] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2056_RX_MIXG_BIAS_MISC] = { .ghz5 = 0x0004, .ghz2 = 0x0004, NOUPLOAD, },
+ [B2056_RX_MIXG_MAST_BIAS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_MASTER] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_IOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_QOPAMP] = { .ghz5 = 0x0026, .ghz2 = 0x0026, UPLOAD, },
+ [B2056_RX_TIA_IMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_QMISC] = { .ghz5 = 0x000f, .ghz2 = 0x000f, UPLOAD, },
+ [B2056_RX_TIA_GAIN] = { .ghz5 = 0x0044, .ghz2 = 0x0044, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TIA_SPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_BB_LPF_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_AACI_MASTER] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2056_RX_RXLPF_IDAC] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_LOWQ] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_OPAMPBIAS_HIGHQ]= { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_RXLPF_BIAS_DCCANCEL] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2056_RX_RXLPF_OUTVCM] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2056_RX_RXLPF_INVCM_BODY] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2056_RX_RXLPF_CC_OP] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2056_RX_RXLPF_GAIN] = { .ghz5 = 0x0023, .ghz2 = 0x0023, NOUPLOAD, },
+ [B2056_RX_RXLPF_Q_BW] = { .ghz5 = 0x0041, .ghz2 = 0x0041, NOUPLOAD, },
+ [B2056_RX_RXLPF_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_HPC] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXHPF_OFF7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_RCCAL_LPC] = { .ghz5 = 0x000c, .ghz2 = 0x000c, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXLPF_OFF_4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_UNUSED] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_VGA_MASTER] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGA_BIAS_DCCANCEL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, UPLOAD, },
+ [B2056_RX_VGA_GAIN] = { .ghz5 = 0x000a, .ghz2 = 0x000a, NOUPLOAD, },
+ [B2056_RX_VGA_HP_CORNER_BW] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2056_RX_VGABUF_BIAS] = { .ghz5 = 0x0022, .ghz2 = 0x0022, NOUPLOAD, },
+ [B2056_RX_VGABUF_GAIN_BW] = { .ghz5 = 0x0030, .ghz2 = 0x0030, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_A] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_TXFBMIX_G] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE3] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+ [B2056_RX_RXSPARE4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE6] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE10] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE11] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_RXSPARE16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_LNAG_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_MIXTIA_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_VGA_BUF_GAIN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_Q] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_BUF_BW] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_VGA_HPC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_RXLPF_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2056_RX_STATUS_HPC_RC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+#define INITTABSPTS(prefix) \
+ .syn = prefix##_syn, \
+ .syn_length = ARRAY_SIZE(prefix##_syn), \
+ .tx = prefix##_tx, \
+ .tx_length = ARRAY_SIZE(prefix##_tx), \
+ .rx = prefix##_rx, \
+ .rx_length = ARRAY_SIZE(prefix##_rx)
+
+struct b2056_inittabs_pts b2056_inittabs[] = {
+ [3] = { INITTABSPTS(b2056_inittab_rev3) },
+ [4] = { INITTABSPTS(b2056_inittab_rev4) },
+ [5] = { INITTABSPTS(b2056_inittab_rev5) },
+ [6] = { INITTABSPTS(b2056_inittab_rev6) },
+ [7] = { INITTABSPTS(b2056_inittab_rev7) },
+ [8] = { INITTABSPTS(b2056_inittab_rev8) },
+ [9] = { INITTABSPTS(b2056_inittab_rev7) },
+};
+
+#define RADIOREGS3(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
+ r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
+ r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, \
+ r30, r31, r32, r33, r34, r35, r36) \
+ .radio_syn_pll_vcocal1 = r00, \
+ .radio_syn_pll_vcocal2 = r01, \
+ .radio_syn_pll_refdiv = r02, \
+ .radio_syn_pll_mmd2 = r03, \
+ .radio_syn_pll_mmd1 = r04, \
+ .radio_syn_pll_loopfilter1 = r05, \
+ .radio_syn_pll_loopfilter2 = r06, \
+ .radio_syn_pll_loopfilter3 = r07, \
+ .radio_syn_pll_loopfilter4 = r08, \
+ .radio_syn_pll_loopfilter5 = r09, \
+ .radio_syn_reserved_addr27 = r10, \
+ .radio_syn_reserved_addr28 = r11, \
+ .radio_syn_reserved_addr29 = r12, \
+ .radio_syn_logen_vcobuf1 = r13, \
+ .radio_syn_logen_mixer2 = r14, \
+ .radio_syn_logen_buf3 = r15, \
+ .radio_syn_logen_buf4 = r16, \
+ .radio_rx0_lnaa_tune = r17, \
+ .radio_rx0_lnag_tune = r18, \
+ .radio_tx0_intpaa_boost_tune = r19, \
+ .radio_tx0_intpag_boost_tune = r20, \
+ .radio_tx0_pada_boost_tune = r21, \
+ .radio_tx0_padg_boost_tune = r22, \
+ .radio_tx0_pgaa_boost_tune = r23, \
+ .radio_tx0_pgag_boost_tune = r24, \
+ .radio_tx0_mixa_boost_tune = r25, \
+ .radio_tx0_mixg_boost_tune = r26, \
+ .radio_rx1_lnaa_tune = r27, \
+ .radio_rx1_lnag_tune = r28, \
+ .radio_tx1_intpaa_boost_tune = r29, \
+ .radio_tx1_intpag_boost_tune = r30, \
+ .radio_tx1_pada_boost_tune = r31, \
+ .radio_tx1_padg_boost_tune = r32, \
+ .radio_tx1_pgaa_boost_tune = r33, \
+ .radio_tx1_pgag_boost_tune = r34, \
+ .radio_tx1_mixa_boost_tune = r35, \
+ .radio_tx1_mixg_boost_tune = r36
+
+#define PHYREGS(r0, r1, r2, r3, r4, r5) \
+ .phy_regs.phy_bw1a = r0, \
+ .phy_regs.phy_bw2 = r1, \
+ .phy_regs.phy_bw3 = r2, \
+ .phy_regs.phy_bw4 = r3, \
+ .phy_regs.phy_bw5 = r4, \
+ .phy_regs.phy_bw6 = r5
+
+/* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */
static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xef, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfc, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x8f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x7e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x7d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x7d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x5d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x5c, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x5c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x2b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x2b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x2a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf6, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05,
+ 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x05, 0x00, 0xf2, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05,
+ 0x00, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x05, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfa, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf7, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xf7, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf6, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x00, 0xf6, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf5, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x00, 0xf5, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x00, 0xf4, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf3, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x00, 0xf3, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x00, 0xf2, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x00, 0xf0, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
+};
+
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev4[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xef, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xef, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x8f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x7e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x7d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x7d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x5d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x5c, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x5c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x5c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x2b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x2b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x2a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x2a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x1a, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x07, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x07, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf0, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf0, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfd, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xfd, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfb, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xfa, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf7, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf7, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf6, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf5, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf5, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf4, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf3, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf3, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
+};
+
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev5[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00,
+ 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6b, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x5b, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x5a, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00,
+ 0xff, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x5a, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x5a, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x5a, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x5a, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x59, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x59, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x59, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00,
+ 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00,
+ 0x84, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x75, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x75, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x75, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00,
+ 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x74, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x84, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x83, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00,
+ 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00,
+ 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x82, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x72, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x72, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x72, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x72, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x71, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x71, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x88, 0x04, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x71, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x71, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x87, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x71, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0b),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x00, 0x07, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
+};
+
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev6[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00,
+ 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00,
+ 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00,
+ 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x57, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x23, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x12, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
+};
+
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev7_9[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xfe, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x6e, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6e, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xed, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00,
+ 0xed, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x6d, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00,
+ 0xed, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdb, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xcb, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xca, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x6b, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xca, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x7b, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x7a, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x7a, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x7a, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb7, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x7a, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xa7, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x7a, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00,
+ 0xa6, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x79, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0xa6, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x79, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x79, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x79, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x94, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x79, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x83, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x72, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x72, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x78, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x71, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x77, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x76, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x60, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x86, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x85, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x85, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x85, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x84, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x84, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x10, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0b, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0b),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x22, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x11, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
};
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev8[] = {
+ { .freq = 4920,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216),
+ },
+ { .freq = 4930,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215),
+ },
+ { .freq = 4940,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214),
+ },
+ { .freq = 4950,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213),
+ },
+ { .freq = 4960,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212),
+ },
+ { .freq = 4970,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211),
+ },
+ { .freq = 4980,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f),
+ },
+ { .freq = 4990,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e),
+ },
+ { .freq = 5000,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d),
+ },
+ { .freq = 5010,
+ RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c),
+ },
+ { .freq = 5020,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b),
+ },
+ { .freq = 5030,
+ RADIOREGS3(0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a),
+ },
+ { .freq = 5040,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209),
+ },
+ { .freq = 5050,
+ RADIOREGS3(0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208),
+ },
+ { .freq = 5060,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207),
+ },
+ { .freq = 5070,
+ RADIOREGS3(0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206),
+ },
+ { .freq = 5080,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205),
+ },
+ { .freq = 5090,
+ RADIOREGS3(0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204),
+ },
+ { .freq = 5100,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203),
+ },
+ { .freq = 5110,
+ RADIOREGS3(0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202),
+ },
+ { .freq = 5120,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201),
+ },
+ { .freq = 5130,
+ RADIOREGS3(0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200),
+ },
+ { .freq = 5140,
+ RADIOREGS3(0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00),
+ PHYREGS(0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff),
+ },
+ { .freq = 5160,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd),
+ },
+ { .freq = 5170,
+ RADIOREGS3(0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc),
+ },
+ { .freq = 5180,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ { .freq = 5190,
+ RADIOREGS3(0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa),
+ },
+ { .freq = 5200,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ { .freq = 5210,
+ RADIOREGS3(0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00,
+ 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8),
+ },
+ { .freq = 5220,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ { .freq = 5230,
+ RADIOREGS3(0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6),
+ },
+ { .freq = 5240,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ { .freq = 5250,
+ RADIOREGS3(0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00,
+ 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4),
+ },
+ { .freq = 5260,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00,
+ 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ { .freq = 5270,
+ RADIOREGS3(0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00,
+ 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2),
+ },
+ { .freq = 5280,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ { .freq = 5290,
+ RADIOREGS3(0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0),
+ },
+ { .freq = 5300,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ { .freq = 5310,
+ RADIOREGS3(0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef),
+ },
+ { .freq = 5320,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00,
+ 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ { .freq = 5330,
+ RADIOREGS3(0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed),
+ },
+ { .freq = 5340,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00,
+ 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec),
+ },
+ { .freq = 5350,
+ RADIOREGS3(0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb),
+ },
+ { .freq = 5360,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea),
+ },
+ { .freq = 5370,
+ RADIOREGS3(0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00,
+ 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9),
+ },
+ { .freq = 5380,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8),
+ },
+ { .freq = 5390,
+ RADIOREGS3(0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7),
+ },
+ { .freq = 5400,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6),
+ },
+ { .freq = 5410,
+ RADIOREGS3(0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5),
+ },
+ { .freq = 5420,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00,
+ 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5),
+ },
+ { .freq = 5430,
+ RADIOREGS3(0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00,
+ 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4),
+ },
+ { .freq = 5440,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3),
+ },
+ { .freq = 5450,
+ RADIOREGS3(0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2),
+ },
+ { .freq = 5460,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1),
+ },
+ { .freq = 5470,
+ RADIOREGS3(0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00,
+ 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0),
+ },
+ { .freq = 5480,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df),
+ },
+ { .freq = 5490,
+ RADIOREGS3(0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de),
+ },
+ { .freq = 5500,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ { .freq = 5510,
+ RADIOREGS3(0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd),
+ },
+ { .freq = 5520,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00,
+ 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ { .freq = 5530,
+ RADIOREGS3(0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db),
+ },
+ { .freq = 5540,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00,
+ 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ { .freq = 5550,
+ RADIOREGS3(0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9),
+ },
+ { .freq = 5560,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ { .freq = 5570,
+ RADIOREGS3(0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x09, 0x00,
+ 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7),
+ },
+ { .freq = 5580,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ { .freq = 5590,
+ RADIOREGS3(0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x04, 0x04, 0x04, 0x89, 0x08, 0x00,
+ 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6),
+ },
+ { .freq = 5600,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ { .freq = 5610,
+ RADIOREGS3(0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4),
+ },
+ { .freq = 5620,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x89, 0x08, 0x00,
+ 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ { .freq = 5630,
+ RADIOREGS3(0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2),
+ },
+ { .freq = 5640,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ { .freq = 5650,
+ RADIOREGS3(0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1),
+ },
+ { .freq = 5660,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ { .freq = 5670,
+ RADIOREGS3(0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x88, 0x07, 0x00,
+ 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf),
+ },
+ { .freq = 5680,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ { .freq = 5690,
+ RADIOREGS3(0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00),
+ PHYREGS(0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce),
+ },
+ { .freq = 5700,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ { .freq = 5710,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc),
+ },
+ { .freq = 5720,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5725,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x06, 0x00,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb),
+ },
+ { .freq = 5730,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00),
+ PHYREGS(0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca),
+ },
+ { .freq = 5735,
+ RADIOREGS3(0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca),
+ },
+ { .freq = 5740,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9),
+ },
+ { .freq = 5745,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ { .freq = 5750,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6d, 0x00),
+ PHYREGS(0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9),
+ },
+ { .freq = 5755,
+ RADIOREGS3(0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x87, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8),
+ },
+ { .freq = 5760,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5765,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x05, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ { .freq = 5770,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7),
+ },
+ { .freq = 5775,
+ RADIOREGS3(0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7),
+ },
+ { .freq = 5780,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x05, 0x05, 0x05, 0x86, 0x04, 0x00,
+ 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6),
+ },
+ { .freq = 5785,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5790,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6),
+ },
+ { .freq = 5795,
+ RADIOREGS3(0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5),
+ },
+ { .freq = 5800,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00),
+ PHYREGS(0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5),
+ },
+ { .freq = 5805,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ { .freq = 5810,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5815,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4),
+ },
+ { .freq = 5820,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00),
+ PHYREGS(0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3),
+ },
+ { .freq = 5825,
+ RADIOREGS3(0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04,
+ 0x10, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
+ { .freq = 5830,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00),
+ PHYREGS(0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2),
+ },
+ { .freq = 5840,
+ RADIOREGS3(0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x86, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2),
+ },
+ { .freq = 5850,
+ RADIOREGS3(0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1),
+ },
+ { .freq = 5860,
+ RADIOREGS3(0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00),
+ PHYREGS(0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0),
+ },
+ { .freq = 5870,
+ RADIOREGS3(0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf),
+ },
+ { .freq = 5880,
+ RADIOREGS3(0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf),
+ },
+ { .freq = 5890,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be),
+ },
+ { .freq = 5900,
+ RADIOREGS3(0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd),
+ },
+ { .freq = 5910,
+ RADIOREGS3(0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04,
+ 0x0c, 0x01, 0x06, 0x06, 0x06, 0x85, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00),
+ PHYREGS(0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc),
+ },
+ { .freq = 2412,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ { .freq = 2417,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ { .freq = 2422,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ { .freq = 2427,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ { .freq = 2432,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ { .freq = 2437,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ { .freq = 2442,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ { .freq = 2447,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ { .freq = 2452,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ { .freq = 2457,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ { .freq = 2462,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
+ { .freq = 2467,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
+ },
+ { .freq = 2472,
+ RADIOREGS3(0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
+ },
+ { .freq = 2484,
+ RADIOREGS3(0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04,
+ 0x16, 0x01, 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09),
+ PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424),
+ },
+};
+
+static void b2056_upload_inittab(struct b43_wldev *dev, bool ghz5,
+ bool ignore_uploadflag, u16 routing,
+ const struct b2056_inittab_entry *e,
+ unsigned int length)
+{
+ unsigned int i;
+ u16 value;
+
+ for (i = 0; i < length; i++, e++) {
+ if (!(e->flags & B2056_INITTAB_ENTRY_OK))
+ continue;
+ if ((e->flags & B2056_INITTAB_UPLOAD) || ignore_uploadflag) {
+ if (ghz5)
+ value = e->ghz5;
+ else
+ value = e->ghz2;
+ b43_radio_write(dev, routing | i, value);
+ }
+ }
+}
+
+void b2056_upload_inittabs(struct b43_wldev *dev,
+ bool ghz5, bool ignore_uploadflag)
+{
+ struct b2056_inittabs_pts *pts;
+
+ if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
+ B43_WARN_ON(1);
+ return;
+ }
+ pts = &b2056_inittabs[dev->phy.rev];
+
+ b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
+ B2056_SYN, pts->syn, pts->syn_length);
+ b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
+ B2056_TX0, pts->tx, pts->tx_length);
+ b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
+ B2056_TX1, pts->tx, pts->tx_length);
+ b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
+ B2056_RX0, pts->rx, pts->rx_length);
+ b2056_upload_inittab(dev, ghz5, ignore_uploadflag,
+ B2056_RX1, pts->rx, pts->rx_length);
+}
+
const struct b43_nphy_channeltab_entry_rev3 *
b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq)
{
const struct b43_nphy_channeltab_entry_rev3 *e;
- unsigned int i;
+ unsigned int length, i;
+
+ switch (dev->phy.rev) {
+ case 3:
+ e = b43_nphy_channeltab_rev3;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev3);
+ break;
+ case 4:
+ e = b43_nphy_channeltab_rev4;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev4);
+ break;
+ case 5:
+ e = b43_nphy_channeltab_rev5;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev5);
+ break;
+ case 6:
+ e = b43_nphy_channeltab_rev6;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev6);
+ break;
+ case 7:
+ case 9:
+ e = b43_nphy_channeltab_rev7_9;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev7_9);
+ break;
+ case 8:
+ e = b43_nphy_channeltab_rev8;
+ length = ARRAY_SIZE(b43_nphy_channeltab_rev8);
+ break;
+ default:
+ B43_WARN_ON(1);
+ return NULL;
+ }
- for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) {
- e = &(b43_nphy_channeltab_rev3[i]);
+ for (i = 0; i < length; i++, e++) {
if (e->freq == freq)
return e;
}
diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h
index fda6dafecb8c..d601f6e7e313 100644
--- a/drivers/net/wireless/b43/radio_2056.h
+++ b/drivers/net/wireless/b43/radio_2056.h
@@ -4,6 +4,9 @@
Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
+ Some parts of the code in this file are derived from the brcm80211
+ driver Copyright (c) 2010 Broadcom Corporation
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -28,15 +31,1090 @@
#include "tables_nphy.h"
+#define B2056_SYN (0x0 << 12)
+#define B2056_TX0 (0x2 << 12)
+#define B2056_TX1 (0x3 << 12)
+#define B2056_RX0 (0x6 << 12)
+#define B2056_RX1 (0x7 << 12)
+#define B2056_ALLTX (0xE << 12)
+#define B2056_ALLRX (0xF << 12)
+
+#define B2056_SYN_RESERVED_ADDR0 0x00
+#define B2056_SYN_IDCODE 0x01
+#define B2056_SYN_RESERVED_ADDR2 0x02
+#define B2056_SYN_RESERVED_ADDR3 0x03
+#define B2056_SYN_RESERVED_ADDR4 0x04
+#define B2056_SYN_RESERVED_ADDR5 0x05
+#define B2056_SYN_RESERVED_ADDR6 0x06
+#define B2056_SYN_RESERVED_ADDR7 0x07
+#define B2056_SYN_COM_CTRL 0x08
+#define B2056_SYN_COM_PU 0x09
+#define B2056_SYN_COM_OVR 0x0A
+#define B2056_SYN_COM_RESET 0x0B
+#define B2056_SYN_COM_RCAL 0x0C
+#define B2056_SYN_COM_RC_RXLPF 0x0D
+#define B2056_SYN_COM_RC_TXLPF 0x0E
+#define B2056_SYN_COM_RC_RXHPF 0x0F
+#define B2056_SYN_RESERVED_ADDR16 0x10
+#define B2056_SYN_RESERVED_ADDR17 0x11
+#define B2056_SYN_RESERVED_ADDR18 0x12
+#define B2056_SYN_RESERVED_ADDR19 0x13
+#define B2056_SYN_RESERVED_ADDR20 0x14
+#define B2056_SYN_RESERVED_ADDR21 0x15
+#define B2056_SYN_RESERVED_ADDR22 0x16
+#define B2056_SYN_RESERVED_ADDR23 0x17
+#define B2056_SYN_RESERVED_ADDR24 0x18
+#define B2056_SYN_RESERVED_ADDR25 0x19
+#define B2056_SYN_RESERVED_ADDR26 0x1A
+#define B2056_SYN_RESERVED_ADDR27 0x1B
+#define B2056_SYN_RESERVED_ADDR28 0x1C
+#define B2056_SYN_RESERVED_ADDR29 0x1D
+#define B2056_SYN_RESERVED_ADDR30 0x1E
+#define B2056_SYN_RESERVED_ADDR31 0x1F
+#define B2056_SYN_GPIO_MASTER1 0x20
+#define B2056_SYN_GPIO_MASTER2 0x21
+#define B2056_SYN_TOPBIAS_MASTER 0x22
+#define B2056_SYN_TOPBIAS_RCAL 0x23
+#define B2056_SYN_AFEREG 0x24
+#define B2056_SYN_TEMPPROCSENSE 0x25
+#define B2056_SYN_TEMPPROCSENSEIDAC 0x26
+#define B2056_SYN_TEMPPROCSENSERCAL 0x27
+#define B2056_SYN_LPO 0x28
+#define B2056_SYN_VDDCAL_MASTER 0x29
+#define B2056_SYN_VDDCAL_IDAC 0x2A
+#define B2056_SYN_VDDCAL_STATUS 0x2B
+#define B2056_SYN_RCAL_MASTER 0x2C
+#define B2056_SYN_RCAL_CODE_OUT 0x2D
+#define B2056_SYN_RCCAL_CTRL0 0x2E
+#define B2056_SYN_RCCAL_CTRL1 0x2F
+#define B2056_SYN_RCCAL_CTRL2 0x30
+#define B2056_SYN_RCCAL_CTRL3 0x31
+#define B2056_SYN_RCCAL_CTRL4 0x32
+#define B2056_SYN_RCCAL_CTRL5 0x33
+#define B2056_SYN_RCCAL_CTRL6 0x34
+#define B2056_SYN_RCCAL_CTRL7 0x35
+#define B2056_SYN_RCCAL_CTRL8 0x36
+#define B2056_SYN_RCCAL_CTRL9 0x37
+#define B2056_SYN_RCCAL_CTRL10 0x38
+#define B2056_SYN_RCCAL_CTRL11 0x39
+#define B2056_SYN_ZCAL_SPARE1 0x3A
+#define B2056_SYN_ZCAL_SPARE2 0x3B
+#define B2056_SYN_PLL_MAST1 0x3C
+#define B2056_SYN_PLL_MAST2 0x3D
+#define B2056_SYN_PLL_MAST3 0x3E
+#define B2056_SYN_PLL_BIAS_RESET 0x3F
+#define B2056_SYN_PLL_XTAL0 0x40
+#define B2056_SYN_PLL_XTAL1 0x41
+#define B2056_SYN_PLL_XTAL3 0x42
+#define B2056_SYN_PLL_XTAL4 0x43
+#define B2056_SYN_PLL_XTAL5 0x44
+#define B2056_SYN_PLL_XTAL6 0x45
+#define B2056_SYN_PLL_REFDIV 0x46
+#define B2056_SYN_PLL_PFD 0x47
+#define B2056_SYN_PLL_CP1 0x48
+#define B2056_SYN_PLL_CP2 0x49
+#define B2056_SYN_PLL_CP3 0x4A
+#define B2056_SYN_PLL_LOOPFILTER1 0x4B
+#define B2056_SYN_PLL_LOOPFILTER2 0x4C
+#define B2056_SYN_PLL_LOOPFILTER3 0x4D
+#define B2056_SYN_PLL_LOOPFILTER4 0x4E
+#define B2056_SYN_PLL_LOOPFILTER5 0x4F
+#define B2056_SYN_PLL_MMD1 0x50
+#define B2056_SYN_PLL_MMD2 0x51
+#define B2056_SYN_PLL_VCO1 0x52
+#define B2056_SYN_PLL_VCO2 0x53
+#define B2056_SYN_PLL_MONITOR1 0x54
+#define B2056_SYN_PLL_MONITOR2 0x55
+#define B2056_SYN_PLL_VCOCAL1 0x56
+#define B2056_SYN_PLL_VCOCAL2 0x57
+#define B2056_SYN_PLL_VCOCAL4 0x58
+#define B2056_SYN_PLL_VCOCAL5 0x59
+#define B2056_SYN_PLL_VCOCAL6 0x5A
+#define B2056_SYN_PLL_VCOCAL7 0x5B
+#define B2056_SYN_PLL_VCOCAL8 0x5C
+#define B2056_SYN_PLL_VCOCAL9 0x5D
+#define B2056_SYN_PLL_VCOCAL10 0x5E
+#define B2056_SYN_PLL_VCOCAL11 0x5F
+#define B2056_SYN_PLL_VCOCAL12 0x60
+#define B2056_SYN_PLL_VCOCAL13 0x61
+#define B2056_SYN_PLL_VREG 0x62
+#define B2056_SYN_PLL_STATUS1 0x63
+#define B2056_SYN_PLL_STATUS2 0x64
+#define B2056_SYN_PLL_STATUS3 0x65
+#define B2056_SYN_LOGEN_PU0 0x66
+#define B2056_SYN_LOGEN_PU1 0x67
+#define B2056_SYN_LOGEN_PU2 0x68
+#define B2056_SYN_LOGEN_PU3 0x69
+#define B2056_SYN_LOGEN_PU5 0x6A
+#define B2056_SYN_LOGEN_PU6 0x6B
+#define B2056_SYN_LOGEN_PU7 0x6C
+#define B2056_SYN_LOGEN_PU8 0x6D
+#define B2056_SYN_LOGEN_BIAS_RESET 0x6E
+#define B2056_SYN_LOGEN_RCCR1 0x6F
+#define B2056_SYN_LOGEN_VCOBUF1 0x70
+#define B2056_SYN_LOGEN_MIXER1 0x71
+#define B2056_SYN_LOGEN_MIXER2 0x72
+#define B2056_SYN_LOGEN_BUF1 0x73
+#define B2056_SYN_LOGENBUF2 0x74
+#define B2056_SYN_LOGEN_BUF3 0x75
+#define B2056_SYN_LOGEN_BUF4 0x76
+#define B2056_SYN_LOGEN_DIV1 0x77
+#define B2056_SYN_LOGEN_DIV2 0x78
+#define B2056_SYN_LOGEN_DIV3 0x79
+#define B2056_SYN_LOGEN_ACL1 0x7A
+#define B2056_SYN_LOGEN_ACL2 0x7B
+#define B2056_SYN_LOGEN_ACL3 0x7C
+#define B2056_SYN_LOGEN_ACL4 0x7D
+#define B2056_SYN_LOGEN_ACL5 0x7E
+#define B2056_SYN_LOGEN_ACL6 0x7F
+#define B2056_SYN_LOGEN_ACLOUT 0x80
+#define B2056_SYN_LOGEN_ACLCAL1 0x81
+#define B2056_SYN_LOGEN_ACLCAL2 0x82
+#define B2056_SYN_LOGEN_ACLCAL3 0x83
+#define B2056_SYN_CALEN 0x84
+#define B2056_SYN_LOGEN_PEAKDET1 0x85
+#define B2056_SYN_LOGEN_CORE_ACL_OVR 0x86
+#define B2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87
+#define B2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88
+#define B2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89
+#define B2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8A
+#define B2056_SYN_LOGEN_VCOBUF2 0x8B
+#define B2056_SYN_LOGEN_MIXER3 0x8C
+#define B2056_SYN_LOGEN_BUF5 0x8D
+#define B2056_SYN_LOGEN_BUF6 0x8E
+#define B2056_SYN_LOGEN_CBUFRX1 0x8F
+#define B2056_SYN_LOGEN_CBUFRX2 0x90
+#define B2056_SYN_LOGEN_CBUFRX3 0x91
+#define B2056_SYN_LOGEN_CBUFRX4 0x92
+#define B2056_SYN_LOGEN_CBUFTX1 0x93
+#define B2056_SYN_LOGEN_CBUFTX2 0x94
+#define B2056_SYN_LOGEN_CBUFTX3 0x95
+#define B2056_SYN_LOGEN_CBUFTX4 0x96
+#define B2056_SYN_LOGEN_CMOSRX1 0x97
+#define B2056_SYN_LOGEN_CMOSRX2 0x98
+#define B2056_SYN_LOGEN_CMOSRX3 0x99
+#define B2056_SYN_LOGEN_CMOSRX4 0x9A
+#define B2056_SYN_LOGEN_CMOSTX1 0x9B
+#define B2056_SYN_LOGEN_CMOSTX2 0x9C
+#define B2056_SYN_LOGEN_CMOSTX3 0x9D
+#define B2056_SYN_LOGEN_CMOSTX4 0x9E
+#define B2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9F
+#define B2056_SYN_LOGEN_MIXER3_OVRVAL 0xA0
+#define B2056_SYN_LOGEN_BUF5_OVRVAL 0xA1
+#define B2056_SYN_LOGEN_BUF6_OVRVAL 0xA2
+#define B2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xA3
+#define B2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xA4
+#define B2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xA5
+#define B2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xA6
+#define B2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xA7
+#define B2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xA8
+#define B2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xA9
+#define B2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xAA
+#define B2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xAB
+#define B2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xAC
+#define B2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xAD
+#define B2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xAE
+#define B2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xAF
+#define B2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xB0
+#define B2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xB1
+#define B2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xB2
+#define B2056_SYN_LOGEN_ACL_WAITCNT 0xB3
+#define B2056_SYN_LOGEN_CORE_CALVALID 0xB4
+#define B2056_SYN_LOGEN_RX_CMOS_CALVALID 0xB5
+#define B2056_SYN_LOGEN_TX_CMOS_VALID 0xB6
+
+#define B2056_TX_RESERVED_ADDR0 0x00
+#define B2056_TX_IDCODE 0x01
+#define B2056_TX_RESERVED_ADDR2 0x02
+#define B2056_TX_RESERVED_ADDR3 0x03
+#define B2056_TX_RESERVED_ADDR4 0x04
+#define B2056_TX_RESERVED_ADDR5 0x05
+#define B2056_TX_RESERVED_ADDR6 0x06
+#define B2056_TX_RESERVED_ADDR7 0x07
+#define B2056_TX_COM_CTRL 0x08
+#define B2056_TX_COM_PU 0x09
+#define B2056_TX_COM_OVR 0x0A
+#define B2056_TX_COM_RESET 0x0B
+#define B2056_TX_COM_RCAL 0x0C
+#define B2056_TX_COM_RC_RXLPF 0x0D
+#define B2056_TX_COM_RC_TXLPF 0x0E
+#define B2056_TX_COM_RC_RXHPF 0x0F
+#define B2056_TX_RESERVED_ADDR16 0x10
+#define B2056_TX_RESERVED_ADDR17 0x11
+#define B2056_TX_RESERVED_ADDR18 0x12
+#define B2056_TX_RESERVED_ADDR19 0x13
+#define B2056_TX_RESERVED_ADDR20 0x14
+#define B2056_TX_RESERVED_ADDR21 0x15
+#define B2056_TX_RESERVED_ADDR22 0x16
+#define B2056_TX_RESERVED_ADDR23 0x17
+#define B2056_TX_RESERVED_ADDR24 0x18
+#define B2056_TX_RESERVED_ADDR25 0x19
+#define B2056_TX_RESERVED_ADDR26 0x1A
+#define B2056_TX_RESERVED_ADDR27 0x1B
+#define B2056_TX_RESERVED_ADDR28 0x1C
+#define B2056_TX_RESERVED_ADDR29 0x1D
+#define B2056_TX_RESERVED_ADDR30 0x1E
+#define B2056_TX_RESERVED_ADDR31 0x1F
+#define B2056_TX_IQCAL_GAIN_BW 0x20
+#define B2056_TX_LOFT_FINE_I 0x21
+#define B2056_TX_LOFT_FINE_Q 0x22
+#define B2056_TX_LOFT_COARSE_I 0x23
+#define B2056_TX_LOFT_COARSE_Q 0x24
+#define B2056_TX_TX_COM_MASTER1 0x25
+#define B2056_TX_TX_COM_MASTER2 0x26
+#define B2056_TX_RXIQCAL_TXMUX 0x27
+#define B2056_TX_TX_SSI_MASTER 0x28
+#define B2056_TX_IQCAL_VCM_HG 0x29
+#define B2056_TX_IQCAL_IDAC 0x2A
+#define B2056_TX_TSSI_VCM 0x2B
+#define B2056_TX_TX_AMP_DET 0x2C
+#define B2056_TX_TX_SSI_MUX 0x2D
+#define B2056_TX_TSSIA 0x2E
+#define B2056_TX_TSSIG 0x2F
+#define B2056_TX_TSSI_MISC1 0x30
+#define B2056_TX_TSSI_MISC2 0x31
+#define B2056_TX_TSSI_MISC3 0x32
+#define B2056_TX_PA_SPARE1 0x33
+#define B2056_TX_PA_SPARE2 0x34
+#define B2056_TX_INTPAA_MASTER 0x35
+#define B2056_TX_INTPAA_GAIN 0x36
+#define B2056_TX_INTPAA_BOOST_TUNE 0x37
+#define B2056_TX_INTPAA_IAUX_STAT 0x38
+#define B2056_TX_INTPAA_IAUX_DYN 0x39
+#define B2056_TX_INTPAA_IMAIN_STAT 0x3A
+#define B2056_TX_INTPAA_IMAIN_DYN 0x3B
+#define B2056_TX_INTPAA_CASCBIAS 0x3C
+#define B2056_TX_INTPAA_PASLOPE 0x3D
+#define B2056_TX_INTPAA_PA_MISC 0x3E
+#define B2056_TX_INTPAG_MASTER 0x3F
+#define B2056_TX_INTPAG_GAIN 0x40
+#define B2056_TX_INTPAG_BOOST_TUNE 0x41
+#define B2056_TX_INTPAG_IAUX_STAT 0x42
+#define B2056_TX_INTPAG_IAUX_DYN 0x43
+#define B2056_TX_INTPAG_IMAIN_STAT 0x44
+#define B2056_TX_INTPAG_IMAIN_DYN 0x45
+#define B2056_TX_INTPAG_CASCBIAS 0x46
+#define B2056_TX_INTPAG_PASLOPE 0x47
+#define B2056_TX_INTPAG_PA_MISC 0x48
+#define B2056_TX_PADA_MASTER 0x49
+#define B2056_TX_PADA_IDAC 0x4A
+#define B2056_TX_PADA_CASCBIAS 0x4B
+#define B2056_TX_PADA_GAIN 0x4C
+#define B2056_TX_PADA_BOOST_TUNE 0x4D
+#define B2056_TX_PADA_SLOPE 0x4E
+#define B2056_TX_PADG_MASTER 0x4F
+#define B2056_TX_PADG_IDAC 0x50
+#define B2056_TX_PADG_CASCBIAS 0x51
+#define B2056_TX_PADG_GAIN 0x52
+#define B2056_TX_PADG_BOOST_TUNE 0x53
+#define B2056_TX_PADG_SLOPE 0x54
+#define B2056_TX_PGAA_MASTER 0x55
+#define B2056_TX_PGAA_IDAC 0x56
+#define B2056_TX_PGAA_GAIN 0x57
+#define B2056_TX_PGAA_BOOST_TUNE 0x58
+#define B2056_TX_PGAA_SLOPE 0x59
+#define B2056_TX_PGAA_MISC 0x5A
+#define B2056_TX_PGAG_MASTER 0x5B
+#define B2056_TX_PGAG_IDAC 0x5C
+#define B2056_TX_PGAG_GAIN 0x5D
+#define B2056_TX_PGAG_BOOST_TUNE 0x5E
+#define B2056_TX_PGAG_SLOPE 0x5F
+#define B2056_TX_PGAG_MISC 0x60
+#define B2056_TX_MIXA_MASTER 0x61
+#define B2056_TX_MIXA_BOOST_TUNE 0x62
+#define B2056_TX_MIXG 0x63
+#define B2056_TX_MIXG_BOOST_TUNE 0x64
+#define B2056_TX_BB_GM_MASTER 0x65
+#define B2056_TX_GMBB_GM 0x66
+#define B2056_TX_GMBB_IDAC 0x67
+#define B2056_TX_TXLPF_MASTER 0x68
+#define B2056_TX_TXLPF_RCCAL 0x69
+#define B2056_TX_TXLPF_RCCAL_OFF0 0x6A
+#define B2056_TX_TXLPF_RCCAL_OFF1 0x6B
+#define B2056_TX_TXLPF_RCCAL_OFF2 0x6C
+#define B2056_TX_TXLPF_RCCAL_OFF3 0x6D
+#define B2056_TX_TXLPF_RCCAL_OFF4 0x6E
+#define B2056_TX_TXLPF_RCCAL_OFF5 0x6F
+#define B2056_TX_TXLPF_RCCAL_OFF6 0x70
+#define B2056_TX_TXLPF_BW 0x71
+#define B2056_TX_TXLPF_GAIN 0x72
+#define B2056_TX_TXLPF_IDAC 0x73
+#define B2056_TX_TXLPF_IDAC_0 0x74
+#define B2056_TX_TXLPF_IDAC_1 0x75
+#define B2056_TX_TXLPF_IDAC_2 0x76
+#define B2056_TX_TXLPF_IDAC_3 0x77
+#define B2056_TX_TXLPF_IDAC_4 0x78
+#define B2056_TX_TXLPF_IDAC_5 0x79
+#define B2056_TX_TXLPF_IDAC_6 0x7A
+#define B2056_TX_TXLPF_OPAMP_IDAC 0x7B
+#define B2056_TX_TXLPF_MISC 0x7C
+#define B2056_TX_TXSPARE1 0x7D
+#define B2056_TX_TXSPARE2 0x7E
+#define B2056_TX_TXSPARE3 0x7F
+#define B2056_TX_TXSPARE4 0x80
+#define B2056_TX_TXSPARE5 0x81
+#define B2056_TX_TXSPARE6 0x82
+#define B2056_TX_TXSPARE7 0x83
+#define B2056_TX_TXSPARE8 0x84
+#define B2056_TX_TXSPARE9 0x85
+#define B2056_TX_TXSPARE10 0x86
+#define B2056_TX_TXSPARE11 0x87
+#define B2056_TX_TXSPARE12 0x88
+#define B2056_TX_TXSPARE13 0x89
+#define B2056_TX_TXSPARE14 0x8A
+#define B2056_TX_TXSPARE15 0x8B
+#define B2056_TX_TXSPARE16 0x8C
+#define B2056_TX_STATUS_INTPA_GAIN 0x8D
+#define B2056_TX_STATUS_PAD_GAIN 0x8E
+#define B2056_TX_STATUS_PGA_GAIN 0x8F
+#define B2056_TX_STATUS_GM_TXLPF_GAIN 0x90
+#define B2056_TX_STATUS_TXLPF_BW 0x91
+#define B2056_TX_STATUS_TXLPF_RC 0x92
+#define B2056_TX_GMBB_IDAC0 0x93
+#define B2056_TX_GMBB_IDAC1 0x94
+#define B2056_TX_GMBB_IDAC2 0x95
+#define B2056_TX_GMBB_IDAC3 0x96
+#define B2056_TX_GMBB_IDAC4 0x97
+#define B2056_TX_GMBB_IDAC5 0x98
+#define B2056_TX_GMBB_IDAC6 0x99
+#define B2056_TX_GMBB_IDAC7 0x9A
+
+#define B2056_RX_RESERVED_ADDR0 0x00
+#define B2056_RX_IDCODE 0x01
+#define B2056_RX_RESERVED_ADDR2 0x02
+#define B2056_RX_RESERVED_ADDR3 0x03
+#define B2056_RX_RESERVED_ADDR4 0x04
+#define B2056_RX_RESERVED_ADDR5 0x05
+#define B2056_RX_RESERVED_ADDR6 0x06
+#define B2056_RX_RESERVED_ADDR7 0x07
+#define B2056_RX_COM_CTRL 0x08
+#define B2056_RX_COM_PU 0x09
+#define B2056_RX_COM_OVR 0x0A
+#define B2056_RX_COM_RESET 0x0B
+#define B2056_RX_COM_RCAL 0x0C
+#define B2056_RX_COM_RC_RXLPF 0x0D
+#define B2056_RX_COM_RC_TXLPF 0x0E
+#define B2056_RX_COM_RC_RXHPF 0x0F
+#define B2056_RX_RESERVED_ADDR16 0x10
+#define B2056_RX_RESERVED_ADDR17 0x11
+#define B2056_RX_RESERVED_ADDR18 0x12
+#define B2056_RX_RESERVED_ADDR19 0x13
+#define B2056_RX_RESERVED_ADDR20 0x14
+#define B2056_RX_RESERVED_ADDR21 0x15
+#define B2056_RX_RESERVED_ADDR22 0x16
+#define B2056_RX_RESERVED_ADDR23 0x17
+#define B2056_RX_RESERVED_ADDR24 0x18
+#define B2056_RX_RESERVED_ADDR25 0x19
+#define B2056_RX_RESERVED_ADDR26 0x1A
+#define B2056_RX_RESERVED_ADDR27 0x1B
+#define B2056_RX_RESERVED_ADDR28 0x1C
+#define B2056_RX_RESERVED_ADDR29 0x1D
+#define B2056_RX_RESERVED_ADDR30 0x1E
+#define B2056_RX_RESERVED_ADDR31 0x1F
+#define B2056_RX_RXIQCAL_RXMUX 0x20
+#define B2056_RX_RSSI_PU 0x21
+#define B2056_RX_RSSI_SEL 0x22
+#define B2056_RX_RSSI_GAIN 0x23
+#define B2056_RX_RSSI_NB_IDAC 0x24
+#define B2056_RX_RSSI_WB2I_IDAC_1 0x25
+#define B2056_RX_RSSI_WB2I_IDAC_2 0x26
+#define B2056_RX_RSSI_WB2Q_IDAC_1 0x27
+#define B2056_RX_RSSI_WB2Q_IDAC_2 0x28
+#define B2056_RX_RSSI_POLE 0x29
+#define B2056_RX_RSSI_WB1_IDAC 0x2A
+#define B2056_RX_RSSI_MISC 0x2B
+#define B2056_RX_LNAA_MASTER 0x2C
+#define B2056_RX_LNAA_TUNE 0x2D
+#define B2056_RX_LNAA_GAIN 0x2E
+#define B2056_RX_LNA_A_SLOPE 0x2F
+#define B2056_RX_BIASPOLE_LNAA1_IDAC 0x30
+#define B2056_RX_LNAA2_IDAC 0x31
+#define B2056_RX_LNA1A_MISC 0x32
+#define B2056_RX_LNAG_MASTER 0x33
+#define B2056_RX_LNAG_TUNE 0x34
+#define B2056_RX_LNAG_GAIN 0x35
+#define B2056_RX_LNA_G_SLOPE 0x36
+#define B2056_RX_BIASPOLE_LNAG1_IDAC 0x37
+#define B2056_RX_LNAG2_IDAC 0x38
+#define B2056_RX_LNA1G_MISC 0x39
+#define B2056_RX_MIXA_MASTER 0x3A
+#define B2056_RX_MIXA_VCM 0x3B
+#define B2056_RX_MIXA_CTRLPTAT 0x3C
+#define B2056_RX_MIXA_LOB_BIAS 0x3D
+#define B2056_RX_MIXA_CORE_IDAC 0x3E
+#define B2056_RX_MIXA_CMFB_IDAC 0x3F
+#define B2056_RX_MIXA_BIAS_AUX 0x40
+#define B2056_RX_MIXA_BIAS_MAIN 0x41
+#define B2056_RX_MIXA_BIAS_MISC 0x42
+#define B2056_RX_MIXA_MAST_BIAS 0x43
+#define B2056_RX_MIXG_MASTER 0x44
+#define B2056_RX_MIXG_VCM 0x45
+#define B2056_RX_MIXG_CTRLPTAT 0x46
+#define B2056_RX_MIXG_LOB_BIAS 0x47
+#define B2056_RX_MIXG_CORE_IDAC 0x48
+#define B2056_RX_MIXG_CMFB_IDAC 0x49
+#define B2056_RX_MIXG_BIAS_AUX 0x4A
+#define B2056_RX_MIXG_BIAS_MAIN 0x4B
+#define B2056_RX_MIXG_BIAS_MISC 0x4C
+#define B2056_RX_MIXG_MAST_BIAS 0x4D
+#define B2056_RX_TIA_MASTER 0x4E
+#define B2056_RX_TIA_IOPAMP 0x4F
+#define B2056_RX_TIA_QOPAMP 0x50
+#define B2056_RX_TIA_IMISC 0x51
+#define B2056_RX_TIA_QMISC 0x52
+#define B2056_RX_TIA_GAIN 0x53
+#define B2056_RX_TIA_SPARE1 0x54
+#define B2056_RX_TIA_SPARE2 0x55
+#define B2056_RX_BB_LPF_MASTER 0x56
+#define B2056_RX_AACI_MASTER 0x57
+#define B2056_RX_RXLPF_IDAC 0x58
+#define B2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59
+#define B2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5A
+#define B2056_RX_RXLPF_BIAS_DCCANCEL 0x5B
+#define B2056_RX_RXLPF_OUTVCM 0x5C
+#define B2056_RX_RXLPF_INVCM_BODY 0x5D
+#define B2056_RX_RXLPF_CC_OP 0x5E
+#define B2056_RX_RXLPF_GAIN 0x5F
+#define B2056_RX_RXLPF_Q_BW 0x60
+#define B2056_RX_RXLPF_HP_CORNER_BW 0x61
+#define B2056_RX_RXLPF_RCCAL_HPC 0x62
+#define B2056_RX_RXHPF_OFF0 0x63
+#define B2056_RX_RXHPF_OFF1 0x64
+#define B2056_RX_RXHPF_OFF2 0x65
+#define B2056_RX_RXHPF_OFF3 0x66
+#define B2056_RX_RXHPF_OFF4 0x67
+#define B2056_RX_RXHPF_OFF5 0x68
+#define B2056_RX_RXHPF_OFF6 0x69
+#define B2056_RX_RXHPF_OFF7 0x6A
+#define B2056_RX_RXLPF_RCCAL_LPC 0x6B
+#define B2056_RX_RXLPF_OFF_0 0x6C
+#define B2056_RX_RXLPF_OFF_1 0x6D
+#define B2056_RX_RXLPF_OFF_2 0x6E
+#define B2056_RX_RXLPF_OFF_3 0x6F
+#define B2056_RX_RXLPF_OFF_4 0x70
+#define B2056_RX_UNUSED 0x71
+#define B2056_RX_VGA_MASTER 0x72
+#define B2056_RX_VGA_BIAS 0x73
+#define B2056_RX_VGA_BIAS_DCCANCEL 0x74
+#define B2056_RX_VGA_GAIN 0x75
+#define B2056_RX_VGA_HP_CORNER_BW 0x76
+#define B2056_RX_VGABUF_BIAS 0x77
+#define B2056_RX_VGABUF_GAIN_BW 0x78
+#define B2056_RX_TXFBMIX_A 0x79
+#define B2056_RX_TXFBMIX_G 0x7A
+#define B2056_RX_RXSPARE1 0x7B
+#define B2056_RX_RXSPARE2 0x7C
+#define B2056_RX_RXSPARE3 0x7D
+#define B2056_RX_RXSPARE4 0x7E
+#define B2056_RX_RXSPARE5 0x7F
+#define B2056_RX_RXSPARE6 0x80
+#define B2056_RX_RXSPARE7 0x81
+#define B2056_RX_RXSPARE8 0x82
+#define B2056_RX_RXSPARE9 0x83
+#define B2056_RX_RXSPARE10 0x84
+#define B2056_RX_RXSPARE11 0x85
+#define B2056_RX_RXSPARE12 0x86
+#define B2056_RX_RXSPARE13 0x87
+#define B2056_RX_RXSPARE14 0x88
+#define B2056_RX_RXSPARE15 0x89
+#define B2056_RX_RXSPARE16 0x8A
+#define B2056_RX_STATUS_LNAA_GAIN 0x8B
+#define B2056_RX_STATUS_LNAG_GAIN 0x8C
+#define B2056_RX_STATUS_MIXTIA_GAIN 0x8D
+#define B2056_RX_STATUS_RXLPF_GAIN 0x8E
+#define B2056_RX_STATUS_VGA_BUF_GAIN 0x8F
+#define B2056_RX_STATUS_RXLPF_Q 0x90
+#define B2056_RX_STATUS_RXLPF_BUF_BW 0x91
+#define B2056_RX_STATUS_RXLPF_VGA_HPC 0x92
+#define B2056_RX_STATUS_RXLPF_RC 0x93
+#define B2056_RX_STATUS_HPC_RC 0x94
+
+#define B2056_LNA1_A_PU 0x01
+#define B2056_LNA2_A_PU 0x02
+#define B2056_LNA1_G_PU 0x01
+#define B2056_LNA2_G_PU 0x02
+#define B2056_MIXA_PU_I 0x01
+#define B2056_MIXA_PU_Q 0x02
+#define B2056_MIXA_PU_GM 0x10
+#define B2056_MIXG_PU_I 0x01
+#define B2056_MIXG_PU_Q 0x02
+#define B2056_MIXG_PU_GM 0x10
+#define B2056_TIA_PU 0x01
+#define B2056_BB_LPF_PU 0x20
+#define B2056_W1_PU 0x02
+#define B2056_W2_PU 0x04
+#define B2056_NB_PU 0x08
+#define B2056_RSSI_W1_SEL 0x02
+#define B2056_RSSI_W2_SEL 0x04
+#define B2056_RSSI_NB_SEL 0x08
+#define B2056_VCM_MASK 0x1C
+#define B2056_RSSI_VCM_SHIFT 0x02
+
+#define B2056_SYN (0x0 << 12)
+#define B2056_TX0 (0x2 << 12)
+#define B2056_TX1 (0x3 << 12)
+#define B2056_RX0 (0x6 << 12)
+#define B2056_RX1 (0x7 << 12)
+#define B2056_ALLTX (0xE << 12)
+#define B2056_ALLRX (0xF << 12)
+
+#define B2056_SYN_RESERVED_ADDR0 0x00
+#define B2056_SYN_IDCODE 0x01
+#define B2056_SYN_RESERVED_ADDR2 0x02
+#define B2056_SYN_RESERVED_ADDR3 0x03
+#define B2056_SYN_RESERVED_ADDR4 0x04
+#define B2056_SYN_RESERVED_ADDR5 0x05
+#define B2056_SYN_RESERVED_ADDR6 0x06
+#define B2056_SYN_RESERVED_ADDR7 0x07
+#define B2056_SYN_COM_CTRL 0x08
+#define B2056_SYN_COM_PU 0x09
+#define B2056_SYN_COM_OVR 0x0A
+#define B2056_SYN_COM_RESET 0x0B
+#define B2056_SYN_COM_RCAL 0x0C
+#define B2056_SYN_COM_RC_RXLPF 0x0D
+#define B2056_SYN_COM_RC_TXLPF 0x0E
+#define B2056_SYN_COM_RC_RXHPF 0x0F
+#define B2056_SYN_RESERVED_ADDR16 0x10
+#define B2056_SYN_RESERVED_ADDR17 0x11
+#define B2056_SYN_RESERVED_ADDR18 0x12
+#define B2056_SYN_RESERVED_ADDR19 0x13
+#define B2056_SYN_RESERVED_ADDR20 0x14
+#define B2056_SYN_RESERVED_ADDR21 0x15
+#define B2056_SYN_RESERVED_ADDR22 0x16
+#define B2056_SYN_RESERVED_ADDR23 0x17
+#define B2056_SYN_RESERVED_ADDR24 0x18
+#define B2056_SYN_RESERVED_ADDR25 0x19
+#define B2056_SYN_RESERVED_ADDR26 0x1A
+#define B2056_SYN_RESERVED_ADDR27 0x1B
+#define B2056_SYN_RESERVED_ADDR28 0x1C
+#define B2056_SYN_RESERVED_ADDR29 0x1D
+#define B2056_SYN_RESERVED_ADDR30 0x1E
+#define B2056_SYN_RESERVED_ADDR31 0x1F
+#define B2056_SYN_GPIO_MASTER1 0x20
+#define B2056_SYN_GPIO_MASTER2 0x21
+#define B2056_SYN_TOPBIAS_MASTER 0x22
+#define B2056_SYN_TOPBIAS_RCAL 0x23
+#define B2056_SYN_AFEREG 0x24
+#define B2056_SYN_TEMPPROCSENSE 0x25
+#define B2056_SYN_TEMPPROCSENSEIDAC 0x26
+#define B2056_SYN_TEMPPROCSENSERCAL 0x27
+#define B2056_SYN_LPO 0x28
+#define B2056_SYN_VDDCAL_MASTER 0x29
+#define B2056_SYN_VDDCAL_IDAC 0x2A
+#define B2056_SYN_VDDCAL_STATUS 0x2B
+#define B2056_SYN_RCAL_MASTER 0x2C
+#define B2056_SYN_RCAL_CODE_OUT 0x2D
+#define B2056_SYN_RCCAL_CTRL0 0x2E
+#define B2056_SYN_RCCAL_CTRL1 0x2F
+#define B2056_SYN_RCCAL_CTRL2 0x30
+#define B2056_SYN_RCCAL_CTRL3 0x31
+#define B2056_SYN_RCCAL_CTRL4 0x32
+#define B2056_SYN_RCCAL_CTRL5 0x33
+#define B2056_SYN_RCCAL_CTRL6 0x34
+#define B2056_SYN_RCCAL_CTRL7 0x35
+#define B2056_SYN_RCCAL_CTRL8 0x36
+#define B2056_SYN_RCCAL_CTRL9 0x37
+#define B2056_SYN_RCCAL_CTRL10 0x38
+#define B2056_SYN_RCCAL_CTRL11 0x39
+#define B2056_SYN_ZCAL_SPARE1 0x3A
+#define B2056_SYN_ZCAL_SPARE2 0x3B
+#define B2056_SYN_PLL_MAST1 0x3C
+#define B2056_SYN_PLL_MAST2 0x3D
+#define B2056_SYN_PLL_MAST3 0x3E
+#define B2056_SYN_PLL_BIAS_RESET 0x3F
+#define B2056_SYN_PLL_XTAL0 0x40
+#define B2056_SYN_PLL_XTAL1 0x41
+#define B2056_SYN_PLL_XTAL3 0x42
+#define B2056_SYN_PLL_XTAL4 0x43
+#define B2056_SYN_PLL_XTAL5 0x44
+#define B2056_SYN_PLL_XTAL6 0x45
+#define B2056_SYN_PLL_REFDIV 0x46
+#define B2056_SYN_PLL_PFD 0x47
+#define B2056_SYN_PLL_CP1 0x48
+#define B2056_SYN_PLL_CP2 0x49
+#define B2056_SYN_PLL_CP3 0x4A
+#define B2056_SYN_PLL_LOOPFILTER1 0x4B
+#define B2056_SYN_PLL_LOOPFILTER2 0x4C
+#define B2056_SYN_PLL_LOOPFILTER3 0x4D
+#define B2056_SYN_PLL_LOOPFILTER4 0x4E
+#define B2056_SYN_PLL_LOOPFILTER5 0x4F
+#define B2056_SYN_PLL_MMD1 0x50
+#define B2056_SYN_PLL_MMD2 0x51
+#define B2056_SYN_PLL_VCO1 0x52
+#define B2056_SYN_PLL_VCO2 0x53
+#define B2056_SYN_PLL_MONITOR1 0x54
+#define B2056_SYN_PLL_MONITOR2 0x55
+#define B2056_SYN_PLL_VCOCAL1 0x56
+#define B2056_SYN_PLL_VCOCAL2 0x57
+#define B2056_SYN_PLL_VCOCAL4 0x58
+#define B2056_SYN_PLL_VCOCAL5 0x59
+#define B2056_SYN_PLL_VCOCAL6 0x5A
+#define B2056_SYN_PLL_VCOCAL7 0x5B
+#define B2056_SYN_PLL_VCOCAL8 0x5C
+#define B2056_SYN_PLL_VCOCAL9 0x5D
+#define B2056_SYN_PLL_VCOCAL10 0x5E
+#define B2056_SYN_PLL_VCOCAL11 0x5F
+#define B2056_SYN_PLL_VCOCAL12 0x60
+#define B2056_SYN_PLL_VCOCAL13 0x61
+#define B2056_SYN_PLL_VREG 0x62
+#define B2056_SYN_PLL_STATUS1 0x63
+#define B2056_SYN_PLL_STATUS2 0x64
+#define B2056_SYN_PLL_STATUS3 0x65
+#define B2056_SYN_LOGEN_PU0 0x66
+#define B2056_SYN_LOGEN_PU1 0x67
+#define B2056_SYN_LOGEN_PU2 0x68
+#define B2056_SYN_LOGEN_PU3 0x69
+#define B2056_SYN_LOGEN_PU5 0x6A
+#define B2056_SYN_LOGEN_PU6 0x6B
+#define B2056_SYN_LOGEN_PU7 0x6C
+#define B2056_SYN_LOGEN_PU8 0x6D
+#define B2056_SYN_LOGEN_BIAS_RESET 0x6E
+#define B2056_SYN_LOGEN_RCCR1 0x6F
+#define B2056_SYN_LOGEN_VCOBUF1 0x70
+#define B2056_SYN_LOGEN_MIXER1 0x71
+#define B2056_SYN_LOGEN_MIXER2 0x72
+#define B2056_SYN_LOGEN_BUF1 0x73
+#define B2056_SYN_LOGENBUF2 0x74
+#define B2056_SYN_LOGEN_BUF3 0x75
+#define B2056_SYN_LOGEN_BUF4 0x76
+#define B2056_SYN_LOGEN_DIV1 0x77
+#define B2056_SYN_LOGEN_DIV2 0x78
+#define B2056_SYN_LOGEN_DIV3 0x79
+#define B2056_SYN_LOGEN_ACL1 0x7A
+#define B2056_SYN_LOGEN_ACL2 0x7B
+#define B2056_SYN_LOGEN_ACL3 0x7C
+#define B2056_SYN_LOGEN_ACL4 0x7D
+#define B2056_SYN_LOGEN_ACL5 0x7E
+#define B2056_SYN_LOGEN_ACL6 0x7F
+#define B2056_SYN_LOGEN_ACLOUT 0x80
+#define B2056_SYN_LOGEN_ACLCAL1 0x81
+#define B2056_SYN_LOGEN_ACLCAL2 0x82
+#define B2056_SYN_LOGEN_ACLCAL3 0x83
+#define B2056_SYN_CALEN 0x84
+#define B2056_SYN_LOGEN_PEAKDET1 0x85
+#define B2056_SYN_LOGEN_CORE_ACL_OVR 0x86
+#define B2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87
+#define B2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88
+#define B2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89
+#define B2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8A
+#define B2056_SYN_LOGEN_VCOBUF2 0x8B
+#define B2056_SYN_LOGEN_MIXER3 0x8C
+#define B2056_SYN_LOGEN_BUF5 0x8D
+#define B2056_SYN_LOGEN_BUF6 0x8E
+#define B2056_SYN_LOGEN_CBUFRX1 0x8F
+#define B2056_SYN_LOGEN_CBUFRX2 0x90
+#define B2056_SYN_LOGEN_CBUFRX3 0x91
+#define B2056_SYN_LOGEN_CBUFRX4 0x92
+#define B2056_SYN_LOGEN_CBUFTX1 0x93
+#define B2056_SYN_LOGEN_CBUFTX2 0x94
+#define B2056_SYN_LOGEN_CBUFTX3 0x95
+#define B2056_SYN_LOGEN_CBUFTX4 0x96
+#define B2056_SYN_LOGEN_CMOSRX1 0x97
+#define B2056_SYN_LOGEN_CMOSRX2 0x98
+#define B2056_SYN_LOGEN_CMOSRX3 0x99
+#define B2056_SYN_LOGEN_CMOSRX4 0x9A
+#define B2056_SYN_LOGEN_CMOSTX1 0x9B
+#define B2056_SYN_LOGEN_CMOSTX2 0x9C
+#define B2056_SYN_LOGEN_CMOSTX3 0x9D
+#define B2056_SYN_LOGEN_CMOSTX4 0x9E
+#define B2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9F
+#define B2056_SYN_LOGEN_MIXER3_OVRVAL 0xA0
+#define B2056_SYN_LOGEN_BUF5_OVRVAL 0xA1
+#define B2056_SYN_LOGEN_BUF6_OVRVAL 0xA2
+#define B2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xA3
+#define B2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xA4
+#define B2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xA5
+#define B2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xA6
+#define B2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xA7
+#define B2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xA8
+#define B2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xA9
+#define B2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xAA
+#define B2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xAB
+#define B2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xAC
+#define B2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xAD
+#define B2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xAE
+#define B2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xAF
+#define B2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xB0
+#define B2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xB1
+#define B2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xB2
+#define B2056_SYN_LOGEN_ACL_WAITCNT 0xB3
+#define B2056_SYN_LOGEN_CORE_CALVALID 0xB4
+#define B2056_SYN_LOGEN_RX_CMOS_CALVALID 0xB5
+#define B2056_SYN_LOGEN_TX_CMOS_VALID 0xB6
+
+#define B2056_TX_RESERVED_ADDR0 0x00
+#define B2056_TX_IDCODE 0x01
+#define B2056_TX_RESERVED_ADDR2 0x02
+#define B2056_TX_RESERVED_ADDR3 0x03
+#define B2056_TX_RESERVED_ADDR4 0x04
+#define B2056_TX_RESERVED_ADDR5 0x05
+#define B2056_TX_RESERVED_ADDR6 0x06
+#define B2056_TX_RESERVED_ADDR7 0x07
+#define B2056_TX_COM_CTRL 0x08
+#define B2056_TX_COM_PU 0x09
+#define B2056_TX_COM_OVR 0x0A
+#define B2056_TX_COM_RESET 0x0B
+#define B2056_TX_COM_RCAL 0x0C
+#define B2056_TX_COM_RC_RXLPF 0x0D
+#define B2056_TX_COM_RC_TXLPF 0x0E
+#define B2056_TX_COM_RC_RXHPF 0x0F
+#define B2056_TX_RESERVED_ADDR16 0x10
+#define B2056_TX_RESERVED_ADDR17 0x11
+#define B2056_TX_RESERVED_ADDR18 0x12
+#define B2056_TX_RESERVED_ADDR19 0x13
+#define B2056_TX_RESERVED_ADDR20 0x14
+#define B2056_TX_RESERVED_ADDR21 0x15
+#define B2056_TX_RESERVED_ADDR22 0x16
+#define B2056_TX_RESERVED_ADDR23 0x17
+#define B2056_TX_RESERVED_ADDR24 0x18
+#define B2056_TX_RESERVED_ADDR25 0x19
+#define B2056_TX_RESERVED_ADDR26 0x1A
+#define B2056_TX_RESERVED_ADDR27 0x1B
+#define B2056_TX_RESERVED_ADDR28 0x1C
+#define B2056_TX_RESERVED_ADDR29 0x1D
+#define B2056_TX_RESERVED_ADDR30 0x1E
+#define B2056_TX_RESERVED_ADDR31 0x1F
+#define B2056_TX_IQCAL_GAIN_BW 0x20
+#define B2056_TX_LOFT_FINE_I 0x21
+#define B2056_TX_LOFT_FINE_Q 0x22
+#define B2056_TX_LOFT_COARSE_I 0x23
+#define B2056_TX_LOFT_COARSE_Q 0x24
+#define B2056_TX_TX_COM_MASTER1 0x25
+#define B2056_TX_TX_COM_MASTER2 0x26
+#define B2056_TX_RXIQCAL_TXMUX 0x27
+#define B2056_TX_TX_SSI_MASTER 0x28
+#define B2056_TX_IQCAL_VCM_HG 0x29
+#define B2056_TX_IQCAL_IDAC 0x2A
+#define B2056_TX_TSSI_VCM 0x2B
+#define B2056_TX_TX_AMP_DET 0x2C
+#define B2056_TX_TX_SSI_MUX 0x2D
+#define B2056_TX_TSSIA 0x2E
+#define B2056_TX_TSSIG 0x2F
+#define B2056_TX_TSSI_MISC1 0x30
+#define B2056_TX_TSSI_MISC2 0x31
+#define B2056_TX_TSSI_MISC3 0x32
+#define B2056_TX_PA_SPARE1 0x33
+#define B2056_TX_PA_SPARE2 0x34
+#define B2056_TX_INTPAA_MASTER 0x35
+#define B2056_TX_INTPAA_GAIN 0x36
+#define B2056_TX_INTPAA_BOOST_TUNE 0x37
+#define B2056_TX_INTPAA_IAUX_STAT 0x38
+#define B2056_TX_INTPAA_IAUX_DYN 0x39
+#define B2056_TX_INTPAA_IMAIN_STAT 0x3A
+#define B2056_TX_INTPAA_IMAIN_DYN 0x3B
+#define B2056_TX_INTPAA_CASCBIAS 0x3C
+#define B2056_TX_INTPAA_PASLOPE 0x3D
+#define B2056_TX_INTPAA_PA_MISC 0x3E
+#define B2056_TX_INTPAG_MASTER 0x3F
+#define B2056_TX_INTPAG_GAIN 0x40
+#define B2056_TX_INTPAG_BOOST_TUNE 0x41
+#define B2056_TX_INTPAG_IAUX_STAT 0x42
+#define B2056_TX_INTPAG_IAUX_DYN 0x43
+#define B2056_TX_INTPAG_IMAIN_STAT 0x44
+#define B2056_TX_INTPAG_IMAIN_DYN 0x45
+#define B2056_TX_INTPAG_CASCBIAS 0x46
+#define B2056_TX_INTPAG_PASLOPE 0x47
+#define B2056_TX_INTPAG_PA_MISC 0x48
+#define B2056_TX_PADA_MASTER 0x49
+#define B2056_TX_PADA_IDAC 0x4A
+#define B2056_TX_PADA_CASCBIAS 0x4B
+#define B2056_TX_PADA_GAIN 0x4C
+#define B2056_TX_PADA_BOOST_TUNE 0x4D
+#define B2056_TX_PADA_SLOPE 0x4E
+#define B2056_TX_PADG_MASTER 0x4F
+#define B2056_TX_PADG_IDAC 0x50
+#define B2056_TX_PADG_CASCBIAS 0x51
+#define B2056_TX_PADG_GAIN 0x52
+#define B2056_TX_PADG_BOOST_TUNE 0x53
+#define B2056_TX_PADG_SLOPE 0x54
+#define B2056_TX_PGAA_MASTER 0x55
+#define B2056_TX_PGAA_IDAC 0x56
+#define B2056_TX_PGAA_GAIN 0x57
+#define B2056_TX_PGAA_BOOST_TUNE 0x58
+#define B2056_TX_PGAA_SLOPE 0x59
+#define B2056_TX_PGAA_MISC 0x5A
+#define B2056_TX_PGAG_MASTER 0x5B
+#define B2056_TX_PGAG_IDAC 0x5C
+#define B2056_TX_PGAG_GAIN 0x5D
+#define B2056_TX_PGAG_BOOST_TUNE 0x5E
+#define B2056_TX_PGAG_SLOPE 0x5F
+#define B2056_TX_PGAG_MISC 0x60
+#define B2056_TX_MIXA_MASTER 0x61
+#define B2056_TX_MIXA_BOOST_TUNE 0x62
+#define B2056_TX_MIXG 0x63
+#define B2056_TX_MIXG_BOOST_TUNE 0x64
+#define B2056_TX_BB_GM_MASTER 0x65
+#define B2056_TX_GMBB_GM 0x66
+#define B2056_TX_GMBB_IDAC 0x67
+#define B2056_TX_TXLPF_MASTER 0x68
+#define B2056_TX_TXLPF_RCCAL 0x69
+#define B2056_TX_TXLPF_RCCAL_OFF0 0x6A
+#define B2056_TX_TXLPF_RCCAL_OFF1 0x6B
+#define B2056_TX_TXLPF_RCCAL_OFF2 0x6C
+#define B2056_TX_TXLPF_RCCAL_OFF3 0x6D
+#define B2056_TX_TXLPF_RCCAL_OFF4 0x6E
+#define B2056_TX_TXLPF_RCCAL_OFF5 0x6F
+#define B2056_TX_TXLPF_RCCAL_OFF6 0x70
+#define B2056_TX_TXLPF_BW 0x71
+#define B2056_TX_TXLPF_GAIN 0x72
+#define B2056_TX_TXLPF_IDAC 0x73
+#define B2056_TX_TXLPF_IDAC_0 0x74
+#define B2056_TX_TXLPF_IDAC_1 0x75
+#define B2056_TX_TXLPF_IDAC_2 0x76
+#define B2056_TX_TXLPF_IDAC_3 0x77
+#define B2056_TX_TXLPF_IDAC_4 0x78
+#define B2056_TX_TXLPF_IDAC_5 0x79
+#define B2056_TX_TXLPF_IDAC_6 0x7A
+#define B2056_TX_TXLPF_OPAMP_IDAC 0x7B
+#define B2056_TX_TXLPF_MISC 0x7C
+#define B2056_TX_TXSPARE1 0x7D
+#define B2056_TX_TXSPARE2 0x7E
+#define B2056_TX_TXSPARE3 0x7F
+#define B2056_TX_TXSPARE4 0x80
+#define B2056_TX_TXSPARE5 0x81
+#define B2056_TX_TXSPARE6 0x82
+#define B2056_TX_TXSPARE7 0x83
+#define B2056_TX_TXSPARE8 0x84
+#define B2056_TX_TXSPARE9 0x85
+#define B2056_TX_TXSPARE10 0x86
+#define B2056_TX_TXSPARE11 0x87
+#define B2056_TX_TXSPARE12 0x88
+#define B2056_TX_TXSPARE13 0x89
+#define B2056_TX_TXSPARE14 0x8A
+#define B2056_TX_TXSPARE15 0x8B
+#define B2056_TX_TXSPARE16 0x8C
+#define B2056_TX_STATUS_INTPA_GAIN 0x8D
+#define B2056_TX_STATUS_PAD_GAIN 0x8E
+#define B2056_TX_STATUS_PGA_GAIN 0x8F
+#define B2056_TX_STATUS_GM_TXLPF_GAIN 0x90
+#define B2056_TX_STATUS_TXLPF_BW 0x91
+#define B2056_TX_STATUS_TXLPF_RC 0x92
+#define B2056_TX_GMBB_IDAC0 0x93
+#define B2056_TX_GMBB_IDAC1 0x94
+#define B2056_TX_GMBB_IDAC2 0x95
+#define B2056_TX_GMBB_IDAC3 0x96
+#define B2056_TX_GMBB_IDAC4 0x97
+#define B2056_TX_GMBB_IDAC5 0x98
+#define B2056_TX_GMBB_IDAC6 0x99
+#define B2056_TX_GMBB_IDAC7 0x9A
+
+#define B2056_RX_RESERVED_ADDR0 0x00
+#define B2056_RX_IDCODE 0x01
+#define B2056_RX_RESERVED_ADDR2 0x02
+#define B2056_RX_RESERVED_ADDR3 0x03
+#define B2056_RX_RESERVED_ADDR4 0x04
+#define B2056_RX_RESERVED_ADDR5 0x05
+#define B2056_RX_RESERVED_ADDR6 0x06
+#define B2056_RX_RESERVED_ADDR7 0x07
+#define B2056_RX_COM_CTRL 0x08
+#define B2056_RX_COM_PU 0x09
+#define B2056_RX_COM_OVR 0x0A
+#define B2056_RX_COM_RESET 0x0B
+#define B2056_RX_COM_RCAL 0x0C
+#define B2056_RX_COM_RC_RXLPF 0x0D
+#define B2056_RX_COM_RC_TXLPF 0x0E
+#define B2056_RX_COM_RC_RXHPF 0x0F
+#define B2056_RX_RESERVED_ADDR16 0x10
+#define B2056_RX_RESERVED_ADDR17 0x11
+#define B2056_RX_RESERVED_ADDR18 0x12
+#define B2056_RX_RESERVED_ADDR19 0x13
+#define B2056_RX_RESERVED_ADDR20 0x14
+#define B2056_RX_RESERVED_ADDR21 0x15
+#define B2056_RX_RESERVED_ADDR22 0x16
+#define B2056_RX_RESERVED_ADDR23 0x17
+#define B2056_RX_RESERVED_ADDR24 0x18
+#define B2056_RX_RESERVED_ADDR25 0x19
+#define B2056_RX_RESERVED_ADDR26 0x1A
+#define B2056_RX_RESERVED_ADDR27 0x1B
+#define B2056_RX_RESERVED_ADDR28 0x1C
+#define B2056_RX_RESERVED_ADDR29 0x1D
+#define B2056_RX_RESERVED_ADDR30 0x1E
+#define B2056_RX_RESERVED_ADDR31 0x1F
+#define B2056_RX_RXIQCAL_RXMUX 0x20
+#define B2056_RX_RSSI_PU 0x21
+#define B2056_RX_RSSI_SEL 0x22
+#define B2056_RX_RSSI_GAIN 0x23
+#define B2056_RX_RSSI_NB_IDAC 0x24
+#define B2056_RX_RSSI_WB2I_IDAC_1 0x25
+#define B2056_RX_RSSI_WB2I_IDAC_2 0x26
+#define B2056_RX_RSSI_WB2Q_IDAC_1 0x27
+#define B2056_RX_RSSI_WB2Q_IDAC_2 0x28
+#define B2056_RX_RSSI_POLE 0x29
+#define B2056_RX_RSSI_WB1_IDAC 0x2A
+#define B2056_RX_RSSI_MISC 0x2B
+#define B2056_RX_LNAA_MASTER 0x2C
+#define B2056_RX_LNAA_TUNE 0x2D
+#define B2056_RX_LNAA_GAIN 0x2E
+#define B2056_RX_LNA_A_SLOPE 0x2F
+#define B2056_RX_BIASPOLE_LNAA1_IDAC 0x30
+#define B2056_RX_LNAA2_IDAC 0x31
+#define B2056_RX_LNA1A_MISC 0x32
+#define B2056_RX_LNAG_MASTER 0x33
+#define B2056_RX_LNAG_TUNE 0x34
+#define B2056_RX_LNAG_GAIN 0x35
+#define B2056_RX_LNA_G_SLOPE 0x36
+#define B2056_RX_BIASPOLE_LNAG1_IDAC 0x37
+#define B2056_RX_LNAG2_IDAC 0x38
+#define B2056_RX_LNA1G_MISC 0x39
+#define B2056_RX_MIXA_MASTER 0x3A
+#define B2056_RX_MIXA_VCM 0x3B
+#define B2056_RX_MIXA_CTRLPTAT 0x3C
+#define B2056_RX_MIXA_LOB_BIAS 0x3D
+#define B2056_RX_MIXA_CORE_IDAC 0x3E
+#define B2056_RX_MIXA_CMFB_IDAC 0x3F
+#define B2056_RX_MIXA_BIAS_AUX 0x40
+#define B2056_RX_MIXA_BIAS_MAIN 0x41
+#define B2056_RX_MIXA_BIAS_MISC 0x42
+#define B2056_RX_MIXA_MAST_BIAS 0x43
+#define B2056_RX_MIXG_MASTER 0x44
+#define B2056_RX_MIXG_VCM 0x45
+#define B2056_RX_MIXG_CTRLPTAT 0x46
+#define B2056_RX_MIXG_LOB_BIAS 0x47
+#define B2056_RX_MIXG_CORE_IDAC 0x48
+#define B2056_RX_MIXG_CMFB_IDAC 0x49
+#define B2056_RX_MIXG_BIAS_AUX 0x4A
+#define B2056_RX_MIXG_BIAS_MAIN 0x4B
+#define B2056_RX_MIXG_BIAS_MISC 0x4C
+#define B2056_RX_MIXG_MAST_BIAS 0x4D
+#define B2056_RX_TIA_MASTER 0x4E
+#define B2056_RX_TIA_IOPAMP 0x4F
+#define B2056_RX_TIA_QOPAMP 0x50
+#define B2056_RX_TIA_IMISC 0x51
+#define B2056_RX_TIA_QMISC 0x52
+#define B2056_RX_TIA_GAIN 0x53
+#define B2056_RX_TIA_SPARE1 0x54
+#define B2056_RX_TIA_SPARE2 0x55
+#define B2056_RX_BB_LPF_MASTER 0x56
+#define B2056_RX_AACI_MASTER 0x57
+#define B2056_RX_RXLPF_IDAC 0x58
+#define B2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59
+#define B2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5A
+#define B2056_RX_RXLPF_BIAS_DCCANCEL 0x5B
+#define B2056_RX_RXLPF_OUTVCM 0x5C
+#define B2056_RX_RXLPF_INVCM_BODY 0x5D
+#define B2056_RX_RXLPF_CC_OP 0x5E
+#define B2056_RX_RXLPF_GAIN 0x5F
+#define B2056_RX_RXLPF_Q_BW 0x60
+#define B2056_RX_RXLPF_HP_CORNER_BW 0x61
+#define B2056_RX_RXLPF_RCCAL_HPC 0x62
+#define B2056_RX_RXHPF_OFF0 0x63
+#define B2056_RX_RXHPF_OFF1 0x64
+#define B2056_RX_RXHPF_OFF2 0x65
+#define B2056_RX_RXHPF_OFF3 0x66
+#define B2056_RX_RXHPF_OFF4 0x67
+#define B2056_RX_RXHPF_OFF5 0x68
+#define B2056_RX_RXHPF_OFF6 0x69
+#define B2056_RX_RXHPF_OFF7 0x6A
+#define B2056_RX_RXLPF_RCCAL_LPC 0x6B
+#define B2056_RX_RXLPF_OFF_0 0x6C
+#define B2056_RX_RXLPF_OFF_1 0x6D
+#define B2056_RX_RXLPF_OFF_2 0x6E
+#define B2056_RX_RXLPF_OFF_3 0x6F
+#define B2056_RX_RXLPF_OFF_4 0x70
+#define B2056_RX_UNUSED 0x71
+#define B2056_RX_VGA_MASTER 0x72
+#define B2056_RX_VGA_BIAS 0x73
+#define B2056_RX_VGA_BIAS_DCCANCEL 0x74
+#define B2056_RX_VGA_GAIN 0x75
+#define B2056_RX_VGA_HP_CORNER_BW 0x76
+#define B2056_RX_VGABUF_BIAS 0x77
+#define B2056_RX_VGABUF_GAIN_BW 0x78
+#define B2056_RX_TXFBMIX_A 0x79
+#define B2056_RX_TXFBMIX_G 0x7A
+#define B2056_RX_RXSPARE1 0x7B
+#define B2056_RX_RXSPARE2 0x7C
+#define B2056_RX_RXSPARE3 0x7D
+#define B2056_RX_RXSPARE4 0x7E
+#define B2056_RX_RXSPARE5 0x7F
+#define B2056_RX_RXSPARE6 0x80
+#define B2056_RX_RXSPARE7 0x81
+#define B2056_RX_RXSPARE8 0x82
+#define B2056_RX_RXSPARE9 0x83
+#define B2056_RX_RXSPARE10 0x84
+#define B2056_RX_RXSPARE11 0x85
+#define B2056_RX_RXSPARE12 0x86
+#define B2056_RX_RXSPARE13 0x87
+#define B2056_RX_RXSPARE14 0x88
+#define B2056_RX_RXSPARE15 0x89
+#define B2056_RX_RXSPARE16 0x8A
+#define B2056_RX_STATUS_LNAA_GAIN 0x8B
+#define B2056_RX_STATUS_LNAG_GAIN 0x8C
+#define B2056_RX_STATUS_MIXTIA_GAIN 0x8D
+#define B2056_RX_STATUS_RXLPF_GAIN 0x8E
+#define B2056_RX_STATUS_VGA_BUF_GAIN 0x8F
+#define B2056_RX_STATUS_RXLPF_Q 0x90
+#define B2056_RX_STATUS_RXLPF_BUF_BW 0x91
+#define B2056_RX_STATUS_RXLPF_VGA_HPC 0x92
+#define B2056_RX_STATUS_RXLPF_RC 0x93
+#define B2056_RX_STATUS_HPC_RC 0x94
+
+#define B2056_LNA1_A_PU 0x01
+#define B2056_LNA2_A_PU 0x02
+#define B2056_LNA1_G_PU 0x01
+#define B2056_LNA2_G_PU 0x02
+#define B2056_MIXA_PU_I 0x01
+#define B2056_MIXA_PU_Q 0x02
+#define B2056_MIXA_PU_GM 0x10
+#define B2056_MIXG_PU_I 0x01
+#define B2056_MIXG_PU_Q 0x02
+#define B2056_MIXG_PU_GM 0x10
+#define B2056_TIA_PU 0x01
+#define B2056_BB_LPF_PU 0x20
+#define B2056_W1_PU 0x02
+#define B2056_W2_PU 0x04
+#define B2056_NB_PU 0x08
+#define B2056_RSSI_W1_SEL 0x02
+#define B2056_RSSI_W2_SEL 0x04
+#define B2056_RSSI_NB_SEL 0x08
+#define B2056_VCM_MASK 0x1C
+#define B2056_RSSI_VCM_SHIFT 0x02
+
struct b43_nphy_channeltab_entry_rev3 {
- /* The channel number */
- u8 channel;
/* The channel frequency in MHz */
u16 freq;
/* Radio register values on channelswitch */
- /* TODO */
+ u8 radio_syn_pll_vcocal1;
+ u8 radio_syn_pll_vcocal2;
+ u8 radio_syn_pll_refdiv;
+ u8 radio_syn_pll_mmd2;
+ u8 radio_syn_pll_mmd1;
+ u8 radio_syn_pll_loopfilter1;
+ u8 radio_syn_pll_loopfilter2;
+ u8 radio_syn_pll_loopfilter3;
+ u8 radio_syn_pll_loopfilter4;
+ u8 radio_syn_pll_loopfilter5;
+ u8 radio_syn_reserved_addr27;
+ u8 radio_syn_reserved_addr28;
+ u8 radio_syn_reserved_addr29;
+ u8 radio_syn_logen_vcobuf1;
+ u8 radio_syn_logen_mixer2;
+ u8 radio_syn_logen_buf3;
+ u8 radio_syn_logen_buf4;
+ u8 radio_rx0_lnaa_tune;
+ u8 radio_rx0_lnag_tune;
+ u8 radio_tx0_intpaa_boost_tune;
+ u8 radio_tx0_intpag_boost_tune;
+ u8 radio_tx0_pada_boost_tune;
+ u8 radio_tx0_padg_boost_tune;
+ u8 radio_tx0_pgaa_boost_tune;
+ u8 radio_tx0_pgag_boost_tune;
+ u8 radio_tx0_mixa_boost_tune;
+ u8 radio_tx0_mixg_boost_tune;
+ u8 radio_rx1_lnaa_tune;
+ u8 radio_rx1_lnag_tune;
+ u8 radio_tx1_intpaa_boost_tune;
+ u8 radio_tx1_intpag_boost_tune;
+ u8 radio_tx1_pada_boost_tune;
+ u8 radio_tx1_padg_boost_tune;
+ u8 radio_tx1_pgaa_boost_tune;
+ u8 radio_tx1_pgag_boost_tune;
+ u8 radio_tx1_mixa_boost_tune;
+ u8 radio_tx1_mixg_boost_tune;
/* PHY register values on channelswitch */
struct b43_phy_n_sfo_cfg phy_regs;
};
+void b2056_upload_inittabs(struct b43_wldev *dev,
+ bool ghz5, bool ignore_uploadflag);
+
#endif /* B43_RADIO_2056_H_ */
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index 78016ae21c50..86bc0a0f735c 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -28,23 +28,8 @@
/* Returns TRUE, if the radio is enabled in hardware. */
bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
{
- if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) {
- if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
- & B43_MMIO_RADIO_HWENABLED_HI_MASK))
- return 1;
- } else {
- /* To prevent CPU fault on PPC, do not read a register
- * unless the interface is started; however, on resume
- * for hibernation, this routine is entered early. When
- * that happens, unconditionally return TRUE.
- */
- if (b43_status(dev) < B43_STAT_STARTED)
- return 1;
- if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
- & B43_MMIO_RADIO_HWENABLED_LO_MASK)
- return 1;
- }
- return 0;
+ return !(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
+ & B43_MMIO_RADIO_HWENABLED_HI_MASK);
}
/* The poll callback for the hardware button. */
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
index 9a55338d957f..09e2dfd7b175 100644
--- a/drivers/net/wireless/b43/sdio.c
+++ b/drivers/net/wireless/b43/sdio.c
@@ -163,6 +163,7 @@ static int b43_sdio_probe(struct sdio_func *func,
err_free_ssb:
kfree(sdio);
err_disable_func:
+ sdio_claim_host(func);
sdio_disable_func(func);
err_release_host:
sdio_release_host(func);
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index d60db078eae2..dc8ef09a8552 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -28,41 +28,41 @@
#include "phy_n.h"
static const u8 b43_ntab_adjustpower0[] = {
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
- 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
- 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
- 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
- 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
- 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
- 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
- 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
- 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
- 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
- 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
- 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const u8 b43_ntab_adjustpower1[] = {
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
- 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
- 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
- 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
- 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
- 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
- 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
- 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
- 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
- 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
- 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
- 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
- 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
- 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const u16 b43_ntab_bdi[] = {
@@ -130,8 +130,8 @@ static const u32 b43_ntab_framestruct[] = {
0x09804506, 0x00100030, 0x09804507, 0x00100030,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
- 0x0980450E, 0x00100038, 0x0980450F, 0x00100038,
+ 0x08004A0C, 0x00100004, 0x01000A0D, 0x00100024,
+ 0x0980450E, 0x00100034, 0x0980450F, 0x00100034,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
@@ -202,13 +202,13 @@ static const u32 b43_ntab_framestruct[] = {
0x53028A06, 0x01900060, 0x53028A07, 0x01900060,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x4002140C, 0x000F4810, 0x6203140D, 0x00100050,
- 0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070,
+ 0x4002140C, 0x000F4808, 0x6203140D, 0x00100048,
+ 0x53028A0E, 0x01900068, 0x53028A0F, 0x01900068,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
- 0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
- 0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+ 0x00000A0C, 0x00100004, 0x11008A0D, 0x00100024,
+ 0x1980C50E, 0x00100034, 0x2181050E, 0x00100034,
+ 0x2181050E, 0x00100034, 0x0180050C, 0x00100038,
0x1180850D, 0x00100038, 0x1181850D, 0x00100038,
0x2981450F, 0x01100038, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -238,9 +238,9 @@ static const u32 b43_ntab_framestruct[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
- 0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
- 0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+ 0x4002140C, 0x00100008, 0x0200140D, 0x00100048,
+ 0x0B004A0E, 0x01900068, 0x13008A0E, 0x01900068,
+ 0x13008A0E, 0x01900068, 0x43020A0C, 0x00100070,
0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070,
0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -337,73 +337,73 @@ static const u32 b43_ntab_framestruct[] = {
};
static const u32 b43_ntab_gainctl0[] = {
- 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
- 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
- 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
- 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
- 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
- 0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
- 0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
- 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
- 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
- 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
- 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
- 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
- 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
- 0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
- 0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
- 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
- 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
- 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
- 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
- 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
- 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
- 0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
- 0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
- 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
- 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
- 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
- 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
- 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
- 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
- 0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
- 0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
- 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+ 0x03CC2B44, 0x03CC2B42, 0x03CC2B40, 0x03CC2B3E,
+ 0x03CC2B3D, 0x03CC2B3B, 0x03C82B44, 0x03C82B42,
+ 0x03C82B40, 0x03C82B3E, 0x03C82B3D, 0x03C82B3B,
+ 0x03C82B39, 0x03C82B38, 0x03C82B36, 0x03C82B34,
+ 0x03C42B44, 0x03C42B42, 0x03C42B40, 0x03C42B3E,
+ 0x03C42B3D, 0x03C42B3B, 0x03C42B39, 0x03C42B38,
+ 0x03C42B36, 0x03C42B34, 0x03C42B33, 0x03C42B32,
+ 0x03C42B30, 0x03C42B2F, 0x03C42B2D, 0x03C02B44,
+ 0x03C02B42, 0x03C02B40, 0x03C02B3E, 0x03C02B3D,
+ 0x03C02B3B, 0x03C02B39, 0x03C02B38, 0x03C02B36,
+ 0x03C02B34, 0x03B02B44, 0x03B02B42, 0x03B02B40,
+ 0x03B02B3E, 0x03B02B3D, 0x03B02B3B, 0x03B02B39,
+ 0x03B02B38, 0x03B02B36, 0x03B02B34, 0x03B02B33,
+ 0x03B02B32, 0x03B02B30, 0x03B02B2F, 0x03B02B2D,
+ 0x03A02B44, 0x03A02B42, 0x03A02B40, 0x03A02B3E,
+ 0x03A02B3D, 0x03A02B3B, 0x03A02B39, 0x03A02B38,
+ 0x03A02B36, 0x03A02B34, 0x03902B44, 0x03902B42,
+ 0x03902B40, 0x03902B3E, 0x03902B3D, 0x03902B3B,
+ 0x03902B39, 0x03902B38, 0x03902B36, 0x03902B34,
+ 0x03902B33, 0x03902B32, 0x03902B30, 0x03802B44,
+ 0x03802B42, 0x03802B40, 0x03802B3E, 0x03802B3D,
+ 0x03802B3B, 0x03802B39, 0x03802B38, 0x03802B36,
+ 0x03802B34, 0x03802B33, 0x03802B32, 0x03802B30,
+ 0x03802B2F, 0x03802B2D, 0x03802B2C, 0x03802B2B,
+ 0x03802B2A, 0x03802B29, 0x03802B27, 0x03802B26,
+ 0x03802B25, 0x03802B24, 0x03802B23, 0x03802B22,
+ 0x03802B21, 0x03802B20, 0x03802B1F, 0x03802B1E,
+ 0x03802B1E, 0x03802B1D, 0x03802B1C, 0x03802B1B,
+ 0x03802B1A, 0x03802B1A, 0x03802B19, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x00002B00,
};
static const u32 b43_ntab_gainctl1[] = {
- 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
- 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
- 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
- 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
- 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
- 0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
- 0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
- 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
- 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
- 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
- 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
- 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
- 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
- 0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
- 0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
- 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
- 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
- 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
- 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
- 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
- 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
- 0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
- 0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
- 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
- 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
- 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
- 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
- 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
- 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
- 0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
- 0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
- 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+ 0x03CC2B44, 0x03CC2B42, 0x03CC2B40, 0x03CC2B3E,
+ 0x03CC2B3D, 0x03CC2B3B, 0x03C82B44, 0x03C82B42,
+ 0x03C82B40, 0x03C82B3E, 0x03C82B3D, 0x03C82B3B,
+ 0x03C82B39, 0x03C82B38, 0x03C82B36, 0x03C82B34,
+ 0x03C42B44, 0x03C42B42, 0x03C42B40, 0x03C42B3E,
+ 0x03C42B3D, 0x03C42B3B, 0x03C42B39, 0x03C42B38,
+ 0x03C42B36, 0x03C42B34, 0x03C42B33, 0x03C42B32,
+ 0x03C42B30, 0x03C42B2F, 0x03C42B2D, 0x03C02B44,
+ 0x03C02B42, 0x03C02B40, 0x03C02B3E, 0x03C02B3D,
+ 0x03C02B3B, 0x03C02B39, 0x03C02B38, 0x03C02B36,
+ 0x03C02B34, 0x03B02B44, 0x03B02B42, 0x03B02B40,
+ 0x03B02B3E, 0x03B02B3D, 0x03B02B3B, 0x03B02B39,
+ 0x03B02B38, 0x03B02B36, 0x03B02B34, 0x03B02B33,
+ 0x03B02B32, 0x03B02B30, 0x03B02B2F, 0x03B02B2D,
+ 0x03A02B44, 0x03A02B42, 0x03A02B40, 0x03A02B3E,
+ 0x03A02B3D, 0x03A02B3B, 0x03A02B39, 0x03A02B38,
+ 0x03A02B36, 0x03A02B34, 0x03902B44, 0x03902B42,
+ 0x03902B40, 0x03902B3E, 0x03902B3D, 0x03902B3B,
+ 0x03902B39, 0x03902B38, 0x03902B36, 0x03902B34,
+ 0x03902B33, 0x03902B32, 0x03902B30, 0x03802B44,
+ 0x03802B42, 0x03802B40, 0x03802B3E, 0x03802B3D,
+ 0x03802B3B, 0x03802B39, 0x03802B38, 0x03802B36,
+ 0x03802B34, 0x03802B33, 0x03802B32, 0x03802B30,
+ 0x03802B2F, 0x03802B2D, 0x03802B2C, 0x03802B2B,
+ 0x03802B2A, 0x03802B29, 0x03802B27, 0x03802B26,
+ 0x03802B25, 0x03802B24, 0x03802B23, 0x03802B22,
+ 0x03802B21, 0x03802B20, 0x03802B1F, 0x03802B1E,
+ 0x03802B1E, 0x03802B1D, 0x03802B1C, 0x03802B1B,
+ 0x03802B1A, 0x03802B1A, 0x03802B19, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x03802B18,
+ 0x03802B18, 0x03802B18, 0x03802B18, 0x00002B00,
};
static const u32 b43_ntab_intlevel[] = {
@@ -1811,9 +1811,7 @@ void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
}
#define ntab_upload(dev, offset, data) do { \
- unsigned int i; \
- for (i = 0; i < (offset##_SIZE); i++) \
- b43_ntab_write(dev, (offset) + i, (data)[i]); \
+ b43_ntab_write_bulk(dev, offset, offset##_SIZE, data); \
} while (0)
void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
@@ -1825,24 +1823,24 @@ void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
- ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
- ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
-
- /* Volatile tables */
ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+
+ /* Volatile tables */
+ ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+ ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+ ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+ ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
- ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
- ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 67f18ecdb3bf..1f11e1670bf0 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -181,52 +181,75 @@ static int b43legacy_ratelimit(struct b43legacy_wl *wl)
void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_INFO "b43legacy-%s: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_ERR "b43legacy-%s ERROR: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_WARNING "b43legacy-%s warning: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
#if B43legacy_DEBUG
void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
{
+ struct va_format vaf;
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);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_DEBUG "b43legacy-%s debug: %pV",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+
va_end(args);
}
#endif /* DEBUG */
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 35033dd342ce..28e477d01587 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -153,7 +153,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
phy->calibrated = 1;
}
-/* intialize B PHY power control
+/* initialize B PHY power control
* as described in http://bcm-specs.sipsolutions.net/InitPowerControl
*/
static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index d579df72b783..b90f223fb31c 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -29,7 +29,7 @@
/* Returns TRUE, if the radio is enabled in hardware. */
bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
{
- if (dev->phy.rev >= 3) {
+ if (dev->dev->id.revision >= 3) {
if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
& B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index dbb986946e1a..18d63f57777d 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -858,7 +858,10 @@ void hostap_free_data(struct ap_data *ap)
return;
}
+ flush_work_sync(&ap->add_sta_proc_queue);
+
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
+ flush_work_sync(&ap->wds_oper_queue);
if (ap->crypt)
ap->crypt->deinit(ap->crypt_priv);
ap->crypt = ap->crypt_priv = NULL;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index bd8a4134edeb..2176edede39b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -518,22 +518,21 @@ static int prism2_config(struct pcmcia_device *link)
hw_priv->link = link;
/*
- * Make sure the IRQ handler cannot proceed until at least
- * dev->base_addr is initialized.
+ * We enable IRQ here, but IRQ handler will not proceed
+ * until dev->base_addr is set below. This protect us from
+ * receive interrupts when driver is not initialized.
*/
- spin_lock_irqsave(&local->irq_init_lock, flags);
-
ret = pcmcia_request_irq(link, prism2_interrupt);
if (ret)
- goto failed_unlock;
+ goto failed;
ret = pcmcia_enable_device(link);
if (ret)
- goto failed_unlock;
+ goto failed;
+ spin_lock_irqsave(&local->irq_init_lock, flags);
dev->irq = link->irq;
dev->base_addr = link->resource[0]->start;
-
spin_unlock_irqrestore(&local->irq_init_lock, flags);
local->shutdown = 0;
@@ -546,8 +545,6 @@ static int prism2_config(struct pcmcia_device *link)
return ret;
- failed_unlock:
- spin_unlock_irqrestore(&local->irq_init_lock, flags);
failed:
kfree(hw_priv);
prism2_release((u_long)link);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index b7cb165d612b..a8bddd81b4d1 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3317,7 +3317,13 @@ static void prism2_free_local_data(struct net_device *dev)
unregister_netdev(local->dev);
- flush_scheduled_work();
+ flush_work_sync(&local->reset_queue);
+ flush_work_sync(&local->set_multicast_list_queue);
+ flush_work_sync(&local->set_tim_queue);
+#ifndef PRISM2_NO_STATION_MODES
+ flush_work_sync(&local->info_queue);
+#endif
+ flush_work_sync(&local->comms_qual_update);
lib80211_crypt_info_free(&local->crypt_info);
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 25a2722c8a98..1d9aed645723 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -891,7 +891,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops);
- netif_stop_queue(dev);
}
static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 8d6ed5f6f46f..ae438ed80c2f 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -1973,6 +1973,13 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
inta = ipw_read32(priv, IPW_INTA_RW);
inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
+
+ if (inta == 0xFFFFFFFF) {
+ /* Hardware disappeared */
+ IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
+ /* Only handle the cached INTA values */
+ inta = 0;
+ }
inta &= (IPW_INTA_MASK_ALL & inta_mask);
/* Add any cached INTA values that need to be handled */
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index 32dee2ce5d31..d5ef696298ee 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -54,6 +54,7 @@
#define DRV_DESCRIPTION "802.11 data/management/control stack"
#define DRV_NAME "libipw"
+#define DRV_PROCNAME "ieee80211"
#define DRV_VERSION LIBIPW_VERSION
#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
@@ -293,16 +294,16 @@ static int __init libipw_init(void)
struct proc_dir_entry *e;
libipw_debug_level = debug;
- libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
+ libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
if (libipw_proc == NULL) {
- LIBIPW_ERROR("Unable to create " DRV_NAME
+ LIBIPW_ERROR("Unable to create " DRV_PROCNAME
" proc directory\n");
return -EIO;
}
e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
&debug_level_proc_fops);
if (!e) {
- remove_proc_entry(DRV_NAME, init_net.proc_net);
+ remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
libipw_proc = NULL;
return -EIO;
}
@@ -319,7 +320,7 @@ static void __exit libipw_exit(void)
#ifdef CONFIG_LIBIPW_DEBUG
if (libipw_proc) {
remove_proc_entry("debug_level", libipw_proc);
- remove_proc_entry(DRV_NAME, init_net.proc_net);
+ remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
libipw_proc = NULL;
}
#endif /* CONFIG_LIBIPW_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index b82364258dc5..ed424574160e 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -106,6 +106,9 @@ config IWL5000
Intel WiFi Link 1000BGN
Intel Wireless WiFi 5150AGN
Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
+ Intel 6000 Gen 2 Series Wi-Fi Adapters (6000G2A and 6000G2B)
+ Intel WIreless WiFi Link 6050BGN Gen 2 Adapter
+ Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN)
config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 63edbe2e557f..93380f97835f 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -2,20 +2,27 @@ obj-$(CONFIG_IWLWIFI) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o
iwlcore-objs += iwl-scan.o iwl-led.o
+iwlcore-$(CONFIG_IWL3945) += iwl-legacy.o
+iwlcore-$(CONFIG_IWL4965) += iwl-legacy.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+# If 3945 is selected only, iwl-legacy.o will be added
+# to iwlcore-m above, but it needs to be built in.
+iwlcore-objs += $(iwlcore-m)
+
CFLAGS_iwl-devtrace.o := -I$(src)
# AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
-iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
+iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o
iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
+iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index db540910b110..ba78bc8a259f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -147,7 +147,11 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
- priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ if (priv->cfg->rx_with_siso_diversity)
+ priv->hw_params.rx_chains_num = 1;
+ else
+ priv->hw_params.rx_chains_num =
+ num_of_ant(priv->cfg->valid_rx_ant);
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
@@ -211,14 +215,16 @@ static struct iwl_lib_ops iwl1000_lib = {
.calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
+ .isr_ops = {
+ .isr = iwl_isr_ict,
+ .free = iwl_free_isr_ict,
+ .alloc = iwl_alloc_isr_ict,
+ .reset = iwl_reset_ict,
+ .disable = iwl_disable_ict,
+ },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -226,7 +232,6 @@ static struct iwl_lib_ops iwl1000_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
@@ -243,6 +248,7 @@ static const struct iwl_ops iwl1000_ops = {
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl1000_base_params = {
@@ -259,7 +265,7 @@ static struct iwl_base_params iwl1000_base_params = {
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 128,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
@@ -270,66 +276,49 @@ static struct iwl_ht_params iwl1000_ht_params = {
.use_rts_for_aggregation = true, /* use rts/cts protection */
};
+#define IWL_DEVICE_1000 \
+ .fw_name_pre = IWL1000_FW_PRE, \
+ .ucode_api_max = IWL1000_UCODE_API_MAX, \
+ .ucode_api_min = IWL1000_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
+ .ops = &iwl1000_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl1000_base_params, \
+ .led_mode = IWL_LED_BLINK
+
struct iwl_cfg iwl1000_bgn_cfg = {
.name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
- .fw_name_pre = IWL1000_FW_PRE,
- .ucode_api_max = IWL1000_UCODE_API_MAX,
- .ucode_api_min = IWL1000_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
- .ops = &iwl1000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl1000_base_params,
+ IWL_DEVICE_1000,
.ht_params = &iwl1000_ht_params,
};
struct iwl_cfg iwl1000_bg_cfg = {
.name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
- .fw_name_pre = IWL1000_FW_PRE,
- .ucode_api_max = IWL1000_UCODE_API_MAX,
- .ucode_api_min = IWL1000_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
- .ops = &iwl1000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl1000_base_params,
+ IWL_DEVICE_1000,
};
+#define IWL_DEVICE_100 \
+ .fw_name_pre = IWL100_FW_PRE, \
+ .ucode_api_max = IWL100_UCODE_API_MAX, \
+ .ucode_api_min = IWL100_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
+ .ops = &iwl1000_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl1000_base_params, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .rx_with_siso_diversity = true
+
struct iwl_cfg iwl100_bgn_cfg = {
- .name = "Intel(R) 100 Series 1x1 BGN",
- .fw_name_pre = IWL100_FW_PRE,
- .ucode_api_max = IWL100_UCODE_API_MAX,
- .ucode_api_min = IWL100_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_A,
- .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
- .ops = &iwl1000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl1000_base_params,
+ .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
+ IWL_DEVICE_100,
.ht_params = &iwl1000_ht_params,
};
struct iwl_cfg iwl100_bg_cfg = {
- .name = "Intel(R) 100 Series 1x1 BG",
- .fw_name_pre = IWL100_FW_PRE,
- .ucode_api_max = IWL100_UCODE_API_MAX,
- .ucode_api_min = IWL100_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_A,
- .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
- .ops = &iwl1000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl1000_base_params,
+ .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
+ IWL_DEVICE_100,
};
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 176e52577673..a9b852be4509 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -51,6 +51,7 @@
#include "iwl-led.h"
#include "iwl-3945-led.h"
#include "iwl-3945-debugfs.h"
+#include "iwl-legacy.h"
#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
@@ -115,7 +116,7 @@ void iwl3945_disable_events(struct iwl_priv *priv)
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] = {
+ static const u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {
0x00000000, /* 31 - 0 Event id numbers */
0x00000000, /* 63 - 32 */
0x00000000, /* 95 - 64 */
@@ -296,7 +297,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
(txq_id != IWL39_CMD_QUEUE_NUM) &&
priv->mac80211_registered)
- iwl_wake_queue(priv, txq_id);
+ iwl_wake_queue(priv, txq);
}
/**
@@ -324,6 +325,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
return;
}
+ txq->time_stamp = jiffies;
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
ieee80211_tx_info_clear_status(info);
@@ -1451,6 +1453,10 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
};
u16 chan;
+ if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
+ "TX Power requested while scanning!\n"))
+ return -EAGAIN;
+
chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel);
txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
@@ -1779,6 +1785,9 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
int rc = 0;
bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EINVAL;
+
if (!iwl_is_alive(priv))
return -1;
@@ -2722,11 +2731,9 @@ static struct iwl_lib_ops iwl3945_lib = {
},
.send_tx_power = iwl3945_send_tx_power,
.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
- .post_associate = iwl3945_post_associate,
- .isr = iwl_isr_legacy,
- .config_ap = iwl3945_config_ap,
- .manage_ibss_station = iwl3945_manage_ibss_station,
- .recover_from_tx_stall = iwl_bg_monitor_recover,
+ .isr_ops = {
+ .isr = iwl_isr_legacy,
+ },
.check_plcp_health = iwl3945_good_plcp_health,
.debugfs_ops = {
@@ -2736,10 +2743,16 @@ static struct iwl_lib_ops iwl3945_lib = {
},
};
+static const struct iwl_legacy_ops iwl3945_legacy_ops = {
+ .post_associate = iwl3945_post_associate,
+ .config_ap = iwl3945_config_ap,
+ .manage_ibss_station = iwl3945_manage_ibss_station,
+};
+
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
- .tx_cmd_protection = iwlcore_tx_cmd_protection,
+ .tx_cmd_protection = iwl_legacy_tx_cmd_protection,
.request_scan = iwl3945_request_scan,
.post_scan = iwl3945_post_scan,
};
@@ -2749,6 +2762,8 @@ static const struct iwl_ops iwl3945_ops = {
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
.led = &iwl3945_led_ops,
+ .legacy = &iwl3945_legacy_ops,
+ .ieee80211_ops = &iwl3945_hw_ops,
};
static struct iwl_base_params iwl3945_base_params = {
@@ -2761,7 +2776,7 @@ static struct iwl_base_params iwl3945_base_params = {
.led_compensation = 64,
.broken_powersave = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
.tx_power_by_driver = true,
};
@@ -2776,6 +2791,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params,
.base_params = &iwl3945_base_params,
+ .led_mode = IWL_LED_BLINK,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2788,6 +2804,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params,
.base_params = &iwl3945_base_params,
+ .led_mode = IWL_LED_BLINK,
};
DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 09391f0ee61f..3eef1eb74a78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -264,10 +264,8 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
extern void iwl3945_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
-extern void iwl3945_post_associate(struct iwl_priv *priv,
- struct ieee80211_vif *vif);
-extern void iwl3945_config_ap(struct iwl_priv *priv,
- struct ieee80211_vif *vif);
+extern void iwl3945_post_associate(struct iwl_priv *priv);
+extern void iwl3945_config_ap(struct iwl_priv *priv);
extern int iwl3945_commit_rxon(struct iwl_priv *priv,
struct iwl_rxon_context *ctx);
@@ -282,6 +280,8 @@ extern int iwl3945_commit_rxon(struct iwl_priv *priv,
*/
extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+extern struct ieee80211_ops iwl3945_hw_ops;
+
/*
* Forward declare iwl-3945.c functions for iwl-base.c
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index b207e3e9299f..3f1e5f1bf847 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -48,6 +48,7 @@
#include "iwl-agn-led.h"
#include "iwl-agn.h"
#include "iwl-agn-debugfs.h"
+#include "iwl-legacy.h"
static int iwl4965_send_tx_power(struct iwl_priv *priv);
static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -1377,13 +1378,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
u8 ctrl_chan_high = 0;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- 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_WARN(priv, "TX Power requested while scanning!\n");
+ if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
+ "TX Power requested while scanning!\n"))
return -EAGAIN;
- }
band = priv->band == IEEE80211_BAND_2GHZ;
@@ -1447,6 +1444,142 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
return ret;
}
+static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
+ int ret;
+ bool new_assoc =
+ !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+
+ if (!iwl_is_alive(priv))
+ return -EBUSY;
+
+ if (!ctx->is_active)
+ return 0;
+
+ /* always get timestamp with Rx frame */
+ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ ret = iwl_check_rxon_cmd(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * receive commit_rxon request
+ * abort any previous channel switch if still in process
+ */
+ if (priv->switch_rxon.switch_in_progress &&
+ (priv->switch_rxon.channel != ctx->staging.channel)) {
+ IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
+ le16_to_cpu(priv->switch_rxon.channel));
+ iwl_chswitch_done(priv, false);
+ }
+
+ /* 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, ctx)) {
+ ret = iwl_send_rxon_assoc(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
+ return ret;
+ }
+
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+ iwl_print_rx_config_cmd(priv, ctx);
+ 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_ctx(ctx) && new_assoc) {
+ IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd),
+ active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (ret) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
+ return ret;
+ }
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ IWL_DEBUG_INFO(priv, "Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %pM\n",
+ (new_assoc ? "" : "out"),
+ le16_to_cpu(ctx->staging.channel),
+ ctx->staging.bssid_addr);
+
+ iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+
+ /* Apply the new configuration
+ * RXON unassoc clears the station table in uCode so restoration of
+ * stations is needed after it (the RXON command) completes
+ */
+ if (!new_assoc) {
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
+ if (ret) {
+ IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+ return ret;
+ }
+ IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+ return ret;
+ }
+ }
+ if (new_assoc) {
+ priv->start_calib = 0;
+ /* Apply the new configuration
+ * RXON assoc doesn't clear the station table in uCode,
+ */
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
+ if (ret) {
+ IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+ return ret;
+ }
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+ }
+ iwl_print_rx_config_cmd(priv, ctx);
+
+ iwl_init_sensitivity(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 */
+ ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ if (ret) {
+ IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch)
{
@@ -1554,22 +1687,6 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
}
/**
- * 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_hw_get_temperature - return the calibrated temperature (in Kelvin)
* @statistics: Provides the temperature reading from the uCode
*
@@ -1606,9 +1723,9 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
* "initialize" ALIVE response.
*/
if (!test_bit(STATUS_TEMPERATURE, &priv->status))
- vt = sign_extend(R4, 23);
+ vt = sign_extend32(R4, 23);
else
- vt = sign_extend(le32_to_cpu(priv->_agn.statistics.
+ vt = sign_extend32(le32_to_cpu(priv->_agn.statistics.
general.common.temperature), 23);
IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
@@ -2081,6 +2198,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
return;
}
+ txq->time_stamp = jiffies;
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
@@ -2121,12 +2239,8 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
- (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
- if (agg->state == IWL_AGG_OFF)
- iwl_wake_queue(priv, txq_id);
- else
- iwl_wake_queue(priv, txq->swq_id);
- }
+ (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+ iwl_wake_queue(priv, txq);
}
} else {
info->status.rates[0].count = tx_resp->failure_frame + 1;
@@ -2150,7 +2264,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark))
- iwl_wake_queue(priv, txq_id);
+ iwl_wake_queue(priv, txq);
}
if (qc && likely(sta_id != IWL_INVALID_STATION))
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
@@ -2216,7 +2330,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
- .commit_rxon = iwlagn_commit_rxon,
+ .commit_rxon = iwl4965_commit_rxon,
.set_rxon_chain = iwlagn_set_rxon_chain,
.send_bt_config = iwl_send_bt_config,
};
@@ -2233,12 +2347,155 @@ static void iwl4965_post_scan(struct iwl_priv *priv)
iwlcore_commit_rxon(priv, ctx);
}
+static void iwl4965_post_associate(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct ieee80211_vif *vif = ctx->vif;
+ struct ieee80211_conf *conf = NULL;
+ int ret = 0;
+
+ if (!vif || !priv->is_open)
+ return;
+
+ if (vif->type == NL80211_IFTYPE_AP) {
+ IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
+ return;
+ }
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ iwl_scan_cancel_timeout(priv, 200);
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
+
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret)
+ IWL_WARN(priv, "RXON timing - "
+ "Attempting to continue.\n");
+
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+
+ ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+
+ IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
+ vif->bss_conf.aid, vif->bss_conf.beacon_int);
+
+ if (vif->bss_conf.use_short_preamble)
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
+ if (vif->bss_conf.use_short_slot)
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+
+ iwlcore_commit_rxon(priv, ctx);
+
+ IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
+ vif->bss_conf.aid, ctx->active.bssid_addr);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ iwlagn_send_beacon_cmd(priv);
+ break;
+ default:
+ IWL_ERR(priv, "%s Should not be called in %d mode\n",
+ __func__, vif->type);
+ break;
+ }
+
+ /* the chain noise calibration will enabled PM upon completion
+ * If chain noise has already been run, then we need to enable
+ * power management here */
+ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+ iwl_power_update_mode(priv, false);
+
+ /* Enable Rx differential gain and sensitivity calibrations */
+ iwl_chain_noise_reset(priv);
+ priv->start_calib = 1;
+}
+
+static void iwl4965_config_ap(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct ieee80211_vif *vif = ctx->vif;
+ int ret = 0;
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ /* The following should be done only at AP bring up */
+ if (!iwl_is_associated_ctx(ctx)) {
+
+ /* RXON - unassoc (to set timing command) */
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
+
+ /* RXON Timing */
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret)
+ IWL_WARN(priv, "RXON timing failed - "
+ "Attempting to continue.\n");
+
+ /* AP has all antennas */
+ priv->chain_noise_data.active_chains =
+ priv->hw_params.valid_rx_ant;
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+
+ ctx->staging.assoc_id = 0;
+
+ if (vif->bss_conf.use_short_preamble)
+ ctx->staging.flags |=
+ RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ ctx->staging.flags &=
+ ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
+ if (vif->bss_conf.use_short_slot)
+ ctx->staging.flags |=
+ RXON_FLG_SHORT_SLOT_MSK;
+ else
+ ctx->staging.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+ /* need to send beacon cmd before committing assoc RXON! */
+ iwlagn_send_beacon_cmd(priv);
+ /* restore RXON assoc */
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
+ }
+ iwlagn_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 struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
- .tx_cmd_protection = iwlcore_tx_cmd_protection,
+ .tx_cmd_protection = iwl_legacy_tx_cmd_protection,
.calc_rssi = iwl4965_calc_rssi,
.request_scan = iwlagn_request_scan,
.post_scan = iwl4965_post_scan,
@@ -2285,14 +2542,12 @@ static struct iwl_lib_ops iwl4965_lib = {
},
.send_tx_power = iwl4965_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
- .post_associate = iwl_post_associate,
- .config_ap = iwl_config_ap,
- .isr = iwl_isr_legacy,
+ .isr_ops = {
+ .isr = iwl_isr_legacy,
+ },
.temp_ops = {
.temperature = iwl4965_temperature_calib,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -2300,15 +2555,46 @@ static struct iwl_lib_ops iwl4965_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
};
+static const struct iwl_legacy_ops iwl4965_legacy_ops = {
+ .post_associate = iwl4965_post_associate,
+ .config_ap = iwl4965_config_ap,
+ .manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
+};
+
+struct ieee80211_ops iwl4965_hw_ops = {
+ .tx = iwlagn_mac_tx,
+ .start = iwlagn_mac_start,
+ .stop = iwlagn_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .change_interface = iwl_mac_change_interface,
+ .config = iwl_legacy_mac_config,
+ .configure_filter = iwlagn_configure_filter,
+ .set_key = iwlagn_mac_set_key,
+ .update_tkip_key = iwlagn_mac_update_tkip_key,
+ .conf_tx = iwl_mac_conf_tx,
+ .reset_tsf = iwl_legacy_mac_reset_tsf,
+ .bss_info_changed = iwl_legacy_mac_bss_info_changed,
+ .ampdu_action = iwlagn_mac_ampdu_action,
+ .hw_scan = iwl_mac_hw_scan,
+ .sta_add = iwlagn_mac_sta_add,
+ .sta_remove = iwl_mac_sta_remove,
+ .channel_switch = iwlagn_mac_channel_switch,
+ .flush = iwlagn_mac_flush,
+ .tx_last_beacon = iwl_mac_tx_last_beacon,
+};
+
static const struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
.led = &iwlagn_led_ops,
+ .legacy = &iwl4965_legacy_ops,
+ .ieee80211_ops = &iwl4965_hw_ops,
};
static struct iwl_base_params iwl4965_base_params = {
@@ -2323,13 +2609,14 @@ static struct iwl_base_params iwl4965_base_params = {
.led_compensation = 61,
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .wd_timeout = IWL_DEF_WD_TIMEOUT,
.temperature_kelvin = true,
.max_event_log_size = 512,
.tx_power_by_driver = true,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .no_agg_framecnt_info = true,
};
struct iwl_cfg iwl4965_agn_cfg = {
@@ -2337,7 +2624,6 @@ struct iwl_cfg iwl4965_agn_cfg = {
.fw_name_pre = IWL4965_FW_PRE,
.ucode_api_max = IWL4965_UCODE_API_MAX,
.ucode_api_min = IWL4965_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
@@ -2345,6 +2631,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
.ops = &iwl4965_ops,
.mod_params = &iwlagn_mod_params,
.base_params = &iwl4965_base_params,
+ .led_mode = IWL_LED_BLINK,
/*
* Force use of chains B and C for scan RX on 5 GHz band
* because the device has off-channel reception on chain A.
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index fd9fbc93ea1b..79ab0a6b1386 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -385,14 +385,16 @@ static struct iwl_lib_ops iwl5000_lib = {
.calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
+ .isr_ops = {
+ .isr = iwl_isr_ict,
+ .free = iwl_free_isr_ict,
+ .alloc = iwl_alloc_isr_ict,
+ .reset = iwl_reset_ict,
+ .disable = iwl_disable_ict,
+ },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -400,7 +402,6 @@ static struct iwl_lib_ops iwl5000_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
@@ -453,14 +454,16 @@ static struct iwl_lib_ops iwl5150_lib = {
.calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
+ .isr_ops = {
+ .isr = iwl_isr_ict,
+ .free = iwl_free_isr_ict,
+ .alloc = iwl_alloc_isr_ict,
+ .reset = iwl_reset_ict,
+ .disable = iwl_disable_ict,
+ },
.temp_ops = {
.temperature = iwl5150_temperature,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -468,7 +471,6 @@ static struct iwl_lib_ops iwl5150_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
@@ -485,6 +487,7 @@ static const struct iwl_ops iwl5000_ops = {
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl5150_ops = {
@@ -492,6 +495,7 @@ static const struct iwl_ops iwl5150_ops = {
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl5000_base_params = {
@@ -505,7 +509,7 @@ static struct iwl_base_params iwl5000_base_params = {
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
+ .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
@@ -516,66 +520,43 @@ static struct iwl_ht_params iwl5000_ht_params = {
.use_rts_for_aggregation = true, /* use rts/cts protection */
};
+#define IWL_DEVICE_5000 \
+ .fw_name_pre = IWL5000_FW_PRE, \
+ .ucode_api_max = IWL5000_UCODE_API_MAX, \
+ .ucode_api_min = IWL5000_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \
+ .ops = &iwl5000_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl5000_base_params, \
+ .led_mode = IWL_LED_BLINK
+
struct iwl_cfg iwl5300_agn_cfg = {
.name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
- .fw_name_pre = IWL5000_FW_PRE,
- .ucode_api_max = IWL5000_UCODE_API_MAX,
- .ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .ops = &iwl5000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
+ IWL_DEVICE_5000,
.ht_params = &iwl5000_ht_params,
};
struct iwl_cfg iwl5100_bgn_cfg = {
.name = "Intel(R) WiFi Link 5100 BGN",
- .fw_name_pre = IWL5000_FW_PRE,
- .ucode_api_max = IWL5000_UCODE_API_MAX,
- .ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .ops = &iwl5000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
+ IWL_DEVICE_5000,
+ .valid_tx_ant = ANT_B, /* .cfg overwrite */
+ .valid_rx_ant = ANT_AB, /* .cfg overwrite */
.ht_params = &iwl5000_ht_params,
};
struct iwl_cfg iwl5100_abg_cfg = {
.name = "Intel(R) WiFi Link 5100 ABG",
- .fw_name_pre = IWL5000_FW_PRE,
- .ucode_api_max = IWL5000_UCODE_API_MAX,
- .ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .ops = &iwl5000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
+ IWL_DEVICE_5000,
+ .valid_tx_ant = ANT_B, /* .cfg overwrite */
+ .valid_rx_ant = ANT_AB, /* .cfg overwrite */
};
struct iwl_cfg iwl5100_agn_cfg = {
.name = "Intel(R) WiFi Link 5100 AGN",
- .fw_name_pre = IWL5000_FW_PRE,
- .ucode_api_max = IWL5000_UCODE_API_MAX,
- .ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .ops = &iwl5000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
+ IWL_DEVICE_5000,
+ .valid_tx_ant = ANT_B, /* .cfg overwrite */
+ .valid_rx_ant = ANT_AB, /* .cfg overwrite */
.ht_params = &iwl5000_ht_params,
};
@@ -584,48 +565,39 @@ struct iwl_cfg iwl5350_agn_cfg = {
.fw_name_pre = IWL5000_FW_PRE,
.ucode_api_max = IWL5000_UCODE_API_MAX,
.ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
.ops = &iwl5000_ops,
.mod_params = &iwlagn_mod_params,
.base_params = &iwl5000_base_params,
.ht_params = &iwl5000_ht_params,
+ .led_mode = IWL_LED_BLINK,
+ .internal_wimax_coex = true,
};
+#define IWL_DEVICE_5150 \
+ .fw_name_pre = IWL5150_FW_PRE, \
+ .ucode_api_max = IWL5150_UCODE_API_MAX, \
+ .ucode_api_min = IWL5150_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
+ .ops = &iwl5150_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl5000_base_params, \
+ .need_dc_calib = true, \
+ .led_mode = IWL_LED_BLINK, \
+ .internal_wimax_coex = true
+
struct iwl_cfg iwl5150_agn_cfg = {
.name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
- .fw_name_pre = IWL5150_FW_PRE,
- .ucode_api_max = IWL5150_UCODE_API_MAX,
- .ucode_api_min = IWL5150_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
- .ops = &iwl5150_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
+ IWL_DEVICE_5150,
.ht_params = &iwl5000_ht_params,
- .need_dc_calib = true,
+
};
struct iwl_cfg iwl5150_abg_cfg = {
.name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
- .fw_name_pre = IWL5150_FW_PRE,
- .ucode_api_max = IWL5150_UCODE_API_MAX,
- .ucode_api_min = IWL5150_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
- .ops = &iwl5150_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl5000_base_params,
- .need_dc_calib = true,
+ IWL_DEVICE_5150,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 11e6532fc573..af505bcd7ae0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -53,13 +53,11 @@
#define IWL6000_UCODE_API_MAX 4
#define IWL6050_UCODE_API_MAX 5
#define IWL6000G2_UCODE_API_MAX 5
-#define IWL130_UCODE_API_MAX 5
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 4
#define IWL6050_UCODE_API_MIN 4
#define IWL6000G2_UCODE_API_MIN 4
-#define IWL130_UCODE_API_MIN 5
#define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@@ -77,10 +75,6 @@
#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
-#define IWL130_FW_PRE "iwlwifi-130-"
-#define _IWL130_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode"
-#define IWL130_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api)
-
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
@@ -188,7 +182,11 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
- priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ if (priv->cfg->rx_with_siso_diversity)
+ priv->hw_params.rx_chains_num = 1;
+ else
+ priv->hw_params.rx_chains_num =
+ num_of_ant(priv->cfg->valid_rx_ant);
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
@@ -328,14 +326,16 @@ static struct iwl_lib_ops iwl6000_lib = {
.query_addr = iwlagn_eeprom_query_addr,
.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
},
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
+ .isr_ops = {
+ .isr = iwl_isr_ict,
+ .free = iwl_free_isr_ict,
+ .alloc = iwl_alloc_isr_ict,
+ .reset = iwl_reset_ict,
+ .disable = iwl_disable_ict,
+ },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -343,7 +343,6 @@ static struct iwl_lib_ops iwl6000_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
@@ -399,14 +398,16 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
.query_addr = iwlagn_eeprom_query_addr,
.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
},
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
+ .isr_ops = {
+ .isr = iwl_isr_ict,
+ .free = iwl_free_isr_ict,
+ .alloc = iwl_alloc_isr_ict,
+ .reset = iwl_reset_ict,
+ .disable = iwl_disable_ict,
+ },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -414,7 +415,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
.bt_stats_read = iwl_ucode_bt_stats_read,
.reply_tx_error = iwl_reply_tx_error_read,
},
- .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
@@ -439,6 +439,7 @@ static const struct iwl_ops iwl6000_ops = {
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6050_ops = {
@@ -447,6 +448,7 @@ static const struct iwl_ops iwl6050_ops = {
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.nic = &iwl6050_nic_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6050g2_ops = {
@@ -455,6 +457,7 @@ static const struct iwl_ops iwl6050g2_ops = {
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
.nic = &iwl6050g2_nic_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6000g2b_ops = {
@@ -462,6 +465,7 @@ static const struct iwl_ops iwl6000g2b_ops = {
.hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
+ .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl6000_base_params = {
@@ -480,11 +484,12 @@ static struct iwl_base_params iwl6000_base_params = {
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .shadow_reg_enable = true,
};
static struct iwl_base_params iwl6050_base_params = {
@@ -503,13 +508,14 @@ static struct iwl_base_params iwl6050_base_params = {
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1500,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 1024,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .shadow_reg_enable = true,
};
-static struct iwl_base_params iwl6000_coex_base_params = {
+static struct iwl_base_params iwl6000_g2_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
@@ -518,18 +524,19 @@ static struct iwl_base_params iwl6000_coex_base_params = {
.use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
- .led_compensation = 51,
+ .led_compensation = 57,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
+ .wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .shadow_reg_enable = true,
};
static struct iwl_ht_params iwl6000_ht_params = {
@@ -541,262 +548,164 @@ static struct iwl_bt_params iwl6000_bt_params = {
.bt_statistics = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
+ .agg_time_limit = BT_AGG_THRESHOLD_DEF,
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+ .bt_sco_disable = true,
+};
+
+#define IWL_DEVICE_6005 \
+ .fw_name_pre = IWL6000G2A_FW_PRE, \
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \
+ .ops = &iwl6000_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl6000_g2_base_params, \
+ .need_dc_calib = true, \
+ .need_temp_offset_calib = true, \
+ .led_mode = IWL_LED_RF_STATE
+
+struct iwl_cfg iwl6005_2agn_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
+ IWL_DEVICE_6005,
+ .ht_params = &iwl6000_ht_params,
};
-struct iwl_cfg iwl6000g2a_2agn_cfg = {
- .name = "6000 Series 2x2 AGN Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
+struct iwl_cfg iwl6005_2abg_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
+ IWL_DEVICE_6005,
+};
+
+struct iwl_cfg iwl6005_2bg_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
+ IWL_DEVICE_6005,
+};
+
+#define IWL_DEVICE_6030 \
+ .fw_name_pre = IWL6000G2B_FW_PRE, \
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \
+ .ops = &iwl6000g2b_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl6000_g2_base_params, \
+ .bt_params = &iwl6000_bt_params, \
+ .need_dc_calib = true, \
+ .need_temp_offset_calib = true, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .adv_pm = true \
+
+struct iwl_cfg iwl6030_2agn_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
+ IWL_DEVICE_6030,
.ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
-};
-
-struct iwl_cfg iwl6000g2a_2abg_cfg = {
- .name = "6000 Series 2x2 ABG Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
-};
-
-struct iwl_cfg iwl6000g2a_2bg_cfg = {
- .name = "6000 Series 2x2 BG Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
-};
-
-struct iwl_cfg iwl6000g2b_2agn_cfg = {
- .name = "6000 Series 2x2 AGN Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
+};
+
+struct iwl_cfg iwl6030_2abg_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
+ IWL_DEVICE_6030,
+};
+
+struct iwl_cfg iwl6030_2bgn_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
+ IWL_DEVICE_6030,
.ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl6000g2b_2abg_cfg = {
- .name = "6000 Series 2x2 ABG Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl6000g2b_2bgn_cfg = {
- .name = "6000 Series 2x2 BGN Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
+};
+
+struct iwl_cfg iwl6030_2bg_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
+ IWL_DEVICE_6030,
+};
+
+struct iwl_cfg iwl1030_bgn_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
+ IWL_DEVICE_6030,
.ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl6000g2b_2bg_cfg = {
- .name = "6000 Series 2x2 BG Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl6000g2b_bgn_cfg = {
- .name = "6000 Series 1x2 BGN Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
+};
+
+struct iwl_cfg iwl1030_bg_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
+ IWL_DEVICE_6030,
+};
+
+struct iwl_cfg iwl130_bgn_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
+ IWL_DEVICE_6030,
.ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl6000g2b_bg_cfg = {
- .name = "6000 Series 1x2 BG Gen2b",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
- .need_dc_calib = true,
- .need_temp_offset_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .rx_with_siso_diversity = true,
+};
+
+struct iwl_cfg iwl130_bg_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
+ IWL_DEVICE_6030,
+ .rx_with_siso_diversity = true,
};
/*
* "i": Internal configuration, use internal Power Amplifier
*/
+#define IWL_DEVICE_6000i \
+ .fw_name_pre = IWL6000_FW_PRE, \
+ .ucode_api_max = IWL6000_UCODE_API_MAX, \
+ .ucode_api_min = IWL6000_UCODE_API_MIN, \
+ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \
+ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \
+ .ops = &iwl6000_ops, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl6000_base_params, \
+ .pa_type = IWL_PA_INTERNAL, \
+ .led_mode = IWL_LED_BLINK
+
struct iwl_cfg iwl6000i_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
- .fw_name_pre = IWL6000_FW_PRE,
- .ucode_api_max = IWL6000_UCODE_API_MAX,
- .ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
+ IWL_DEVICE_6000i,
.ht_params = &iwl6000_ht_params,
- .pa_type = IWL_PA_INTERNAL,
};
struct iwl_cfg iwl6000i_2abg_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
- .fw_name_pre = IWL6000_FW_PRE,
- .ucode_api_max = IWL6000_UCODE_API_MAX,
- .ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
- .pa_type = IWL_PA_INTERNAL,
+ IWL_DEVICE_6000i,
};
struct iwl_cfg iwl6000i_2bg_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
- .fw_name_pre = IWL6000_FW_PRE,
- .ucode_api_max = IWL6000_UCODE_API_MAX,
- .ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_base_params,
- .pa_type = IWL_PA_INTERNAL,
-};
+ IWL_DEVICE_6000i,
+};
+
+#define IWL_DEVICE_6050 \
+ .fw_name_pre = IWL6050_FW_PRE, \
+ .ucode_api_max = IWL6050_UCODE_API_MAX, \
+ .ucode_api_min = IWL6050_UCODE_API_MIN, \
+ .ops = &iwl6050_ops, \
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \
+ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \
+ .mod_params = &iwlagn_mod_params, \
+ .base_params = &iwl6050_base_params, \
+ .need_dc_calib = true, \
+ .led_mode = IWL_LED_BLINK, \
+ .internal_wimax_coex = true
struct iwl_cfg iwl6050_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
- .fw_name_pre = IWL6050_FW_PRE,
- .ucode_api_max = IWL6050_UCODE_API_MAX,
- .ucode_api_min = IWL6050_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .ops = &iwl6050_ops,
- .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6050_base_params,
+ IWL_DEVICE_6050,
.ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
};
-struct iwl_cfg iwl6050g2_bgn_cfg = {
- .name = "6050 Series 1x2 BGN Gen2",
+struct iwl_cfg iwl6050_2abg_cfg = {
+ .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
+ IWL_DEVICE_6050,
+};
+
+struct iwl_cfg iwl6150_bgn_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
.fw_name_pre = IWL6050_FW_PRE,
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
.ops = &iwl6050g2_ops,
@@ -804,22 +713,8 @@ struct iwl_cfg iwl6050g2_bgn_cfg = {
.base_params = &iwl6050_base_params,
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
-};
-
-struct iwl_cfg iwl6050_2abg_cfg = {
- .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
- .fw_name_pre = IWL6050_FW_PRE,
- .ucode_api_max = IWL6050_UCODE_API_MAX,
- .ucode_api_min = IWL6050_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
- .ops = &iwl6050_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6050_base_params,
- .need_dc_calib = true,
+ .led_mode = IWL_LED_RF_STATE,
+ .internal_wimax_coex = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -827,9 +722,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
.ops = &iwl6000_ops,
@@ -837,49 +729,10 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.base_params = &iwl6000_base_params,
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
-};
-
-struct iwl_cfg iwl130_bgn_cfg = {
- .name = "Intel(R) 130 Series 1x1 BGN",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL130_UCODE_API_MAX,
- .ucode_api_min = IWL130_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_A,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
- .ht_params = &iwl6000_ht_params,
- .need_dc_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
-};
-
-struct iwl_cfg iwl130_bg_cfg = {
- .name = "Intel(R) 130 Series 1x2 BG",
- .fw_name_pre = IWL6000G2B_FW_PRE,
- .ucode_api_max = IWL130_UCODE_API_MAX,
- .ucode_api_min = IWL130_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_A,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .ops = &iwl6000g2b_ops,
- .mod_params = &iwlagn_mod_params,
- .base_params = &iwl6000_coex_base_params,
- .bt_params = &iwl6000_bt_params,
- .need_dc_calib = true,
- /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
- .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .led_mode = IWL_LED_BLINK,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL130_MODULE_FIRMWARE(IWL130_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index e2019e756936..d16bb5ede014 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -732,8 +732,122 @@ static inline u8 find_first_chain(u8 mask)
return CHAIN_C;
}
+/**
+ * Run disconnected antenna algorithm to find out which antennas are
+ * disconnected.
+ */
+static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
+ struct iwl_chain_noise_data *data)
+{
+ u32 active_chains = 0;
+ u32 max_average_sig;
+ u16 max_average_sig_antenna_i;
+ u8 num_tx_chains;
+ u8 first_chain;
+ u16 i = 0;
+
+ average_sig[0] = data->chain_signal_a /
+ priv->cfg->base_params->chain_noise_num_beacons;
+ average_sig[1] = data->chain_signal_b /
+ priv->cfg->base_params->chain_noise_num_beacons;
+ average_sig[2] = data->chain_signal_c /
+ priv->cfg->base_params->chain_noise_num_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(priv, "average_sig: a %d b %d c %d\n",
+ average_sig[0], average_sig[1], average_sig[2]);
+ IWL_DEBUG_CALIB(priv, "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(priv, "i = %d rssiDelta = %d "
+ "disconn_array[i] = %d\n",
+ i, rssi_delta, data->disconn_array[i]);
+ }
+ }
+
+ /*
+ * The above algorithm sometimes fails when the ucode
+ * reports 0 for all chains. It's not clear why that
+ * happens to start with, but it is then causing trouble
+ * because this can make us enable more chains than the
+ * hardware really has.
+ *
+ * To be safe, simply mask out any chains that we know
+ * are not on the device.
+ */
+ active_chains &= priv->hw_params.valid_rx_ant;
+
+ num_tx_chains = 0;
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ /* loops on all the bits of
+ * priv->hw_setting.valid_tx_ant */
+ u8 ant_msk = (1 << i);
+ if (!(priv->hw_params.valid_tx_ant & ant_msk))
+ continue;
+
+ num_tx_chains++;
+ if (data->disconn_array[i] == 0)
+ /* there is a Tx antenna connected */
+ break;
+ if (num_tx_chains == priv->hw_params.tx_chains_num &&
+ data->disconn_array[i]) {
+ /*
+ * If all chains are disconnected
+ * connect the first valid tx chain
+ */
+ first_chain =
+ find_first_chain(priv->cfg->valid_tx_ant);
+ data->disconn_array[first_chain] = 0;
+ active_chains |= BIT(first_chain);
+ IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected \
+ W/A - declare %d as connected\n",
+ first_chain);
+ break;
+ }
+ }
+
+ if (active_chains != priv->hw_params.valid_rx_ant &&
+ active_chains != priv->chain_noise_data.active_chains)
+ IWL_DEBUG_CALIB(priv,
+ "Detected that not all antennas are connected! "
+ "Connected: %#x, valid: %#x.\n",
+ active_chains, priv->hw_params.valid_rx_ant);
+
+ /* Save for use within RXON, TX, SCAN commands, etc. */
+ data->active_chains = active_chains;
+ IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
+ active_chains);
+}
+
+
/*
- * Accumulate 20 beacons of signal and noise statistics for each of
+ * Accumulate 16 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.
@@ -750,8 +864,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
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;
@@ -759,11 +871,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
u16 stat_chnum = INITIALIZATION_VALUE;
u8 rxon_band24;
u8 stat_band24;
- u32 active_chains = 0;
- u8 num_tx_chains;
unsigned long flags;
struct statistics_rx_non_phy *rx_info;
- u8 first_chain;
+
/*
* MULTI-FIXME:
* When we support multiple interfaces on different channels,
@@ -869,108 +979,16 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
return;
/* Analyze signal for disconnected antenna */
- average_sig[0] = data->chain_signal_a /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_sig[1] = data->chain_signal_b /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_sig[2] = data->chain_signal_c /
- priv->cfg->base_params->chain_noise_num_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(priv, "average_sig: a %d b %d c %d\n",
- average_sig[0], average_sig[1], average_sig[2]);
- IWL_DEBUG_CALIB(priv, "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(priv, "i = %d rssiDelta = %d "
- "disconn_array[i] = %d\n",
- i, rssi_delta, data->disconn_array[i]);
- }
- }
-
- /*
- * The above algorithm sometimes fails when the ucode
- * reports 0 for all chains. It's not clear why that
- * happens to start with, but it is then causing trouble
- * because this can make us enable more chains than the
- * hardware really has.
- *
- * To be safe, simply mask out any chains that we know
- * are not on the device.
- */
if (priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist &&
- priv->bt_full_concurrent) {
- /* operated as 1x1 in full concurrency mode */
- active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ /* Disable disconnected antenna algorithm for advanced
+ bt coex, assuming valid antennas are connected */
+ data->active_chains = priv->hw_params.valid_rx_ant;
+ for (i = 0; i < NUM_RX_CHAINS; i++)
+ if (!(data->active_chains & (1<<i)))
+ data->disconn_array[i] = 1;
} else
- active_chains &= priv->hw_params.valid_rx_ant;
-
- num_tx_chains = 0;
- for (i = 0; i < NUM_RX_CHAINS; i++) {
- /* loops on all the bits of
- * priv->hw_setting.valid_tx_ant */
- u8 ant_msk = (1 << i);
- if (!(priv->hw_params.valid_tx_ant & ant_msk))
- continue;
-
- num_tx_chains++;
- if (data->disconn_array[i] == 0)
- /* there is a Tx antenna connected */
- break;
- if (num_tx_chains == priv->hw_params.tx_chains_num &&
- data->disconn_array[i]) {
- /*
- * If all chains are disconnected
- * connect the first valid tx chain
- */
- first_chain =
- find_first_chain(priv->cfg->valid_tx_ant);
- data->disconn_array[first_chain] = 0;
- active_chains |= BIT(first_chain);
- IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n",
- first_chain);
- break;
- }
- }
-
- if (active_chains != priv->hw_params.valid_rx_ant &&
- active_chains != priv->chain_noise_data.active_chains)
- IWL_DEBUG_CALIB(priv,
- "Detected that not all antennas are connected! "
- "Connected: %#x, valid: %#x.\n",
- active_chains, priv->hw_params.valid_rx_ant);
-
- /* Save for use within RXON, TX, SCAN commands, etc. */
- priv->chain_noise_data.active_chains = active_chains;
- IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
- active_chains);
+ iwl_find_disconn_antenna(priv, average_sig, data);
/* Analyze noise for rx balance */
average_noise[0] = data->chain_noise_a /
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index a358d4334a1a..a6dbd8983dac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -856,6 +856,9 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
if (!iwl_is_alive(priv))
return -EAGAIN;
+ if (!priv->bt_enable_flag)
+ return -EINVAL;
+
/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
index a650baba0809..97906dd442e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -75,109 +75,6 @@
#include "iwl-agn.h"
#include "iwl-io.h"
-/************************** 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.
- *
- *********************************************************************/
-
-/**
- * struct iwl_txpwr_section: eeprom section information
- * @offset: indirect address into eeprom image
- * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
- * @band: band type for the section
- * @is_common - true: common section, false: channel section
- * @is_cck - true: cck section, false: not cck section
- * @is_ht_40 - true: all channel in the section are HT40 channel,
- * false: legacy or HT 20 MHz
- * ignore if it is common section
- * @iwl_eeprom_section_channel: channel array in the section,
- * ignore if common section
- */
-struct iwl_txpwr_section {
- u32 offset;
- u8 count;
- enum ieee80211_band band;
- bool is_common;
- bool is_cck;
- bool is_ht40;
- u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
-};
-
-/**
- * section 1 - 3 are regulatory tx power apply to all channels based on
- * modulation: CCK, OFDM
- * Band: 2.4GHz, 5.2GHz
- * section 4 - 10 are regulatory tx power apply to specified channels
- * For example:
- * 1L - Channel 1 Legacy
- * 1HT - Channel 1 HT
- * (1,+1) - Channel 1 HT40 "_above_"
- *
- * Section 1: all CCK channels
- * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
- * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
- * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
- * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
- * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
- * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
- * Section 8: 2.4 GHz channel: 13L, 13HT
- * Section 9: 2.4 GHz channel: 140L, 140HT
- * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
- *
- */
-static const struct iwl_txpwr_section enhinfo[] = {
- { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
- { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
- { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
- { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
- false, false, false,
- {1, 1, 2, 2, 10, 10, 11, 11 } },
- { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
- false, false, true,
- { 1, 2, 6, 7, 9 } },
- { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
- false, false, false,
- { 36, 64, 100, 36, 64, 100 } },
- { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
- false, false, true,
- { 36, 60, 100 } },
- { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
- false, false, false,
- { 13, 13 } },
- { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
- false, false, false,
- { 140, 140 } },
- { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
- false, false, true,
- { 132, 44 } },
-};
-
/******************************************************************************
*
* EEPROM related functions
@@ -248,6 +145,47 @@ err:
}
+int iwl_eeprom_check_sku(struct iwl_priv *priv)
+{
+ u16 eeprom_sku;
+ u16 radio_cfg;
+
+ eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
+
+ priv->cfg->sku = ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
+ EEPROM_SKU_CAP_BAND_POS);
+ if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
+ priv->cfg->sku |= IWL_SKU_N;
+
+ if (!priv->cfg->sku) {
+ IWL_ERR(priv, "Invalid device sku\n");
+ return -EINVAL;
+ }
+
+ IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
+
+ if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
+ /* not using .cfg overwrite */
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+ priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+ priv->cfg->valid_rx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+ if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
+ IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
+ priv->cfg->valid_tx_ant,
+ priv->cfg->valid_rx_ant);
+ return -EINVAL;
+ }
+ IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
+ priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
+ }
+ /*
+ * for some special cases,
+ * EEPROM did not reflect the correct antenna setting
+ * so overwrite the valid tx/rx antenna from .cfg
+ */
+ return 0;
+}
+
void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
{
const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv,
@@ -265,15 +203,6 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
{
s8 max_txpower_avg = 0; /* (dBm) */
- IWL_DEBUG_INFO(priv, "%d - "
- "chain_a: %d dB chain_b: %d dB "
- "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
- element,
- enhanced_txpower[element].chain_a_max >> 1,
- enhanced_txpower[element].chain_b_max >> 1,
- enhanced_txpower[element].chain_c_max >> 1,
- enhanced_txpower[element].mimo2_max >> 1,
- enhanced_txpower[element].mimo3_max >> 1);
/* Take the highest tx power from any valid chains */
if ((priv->cfg->valid_tx_ant & ANT_A) &&
(enhanced_txpower[element].chain_a_max > max_txpower_avg))
@@ -303,152 +232,106 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
}
-/**
- * iwl_update_common_txpower: update channel tx power
- * update tx power per band based on EEPROM enhanced tx power info.
- */
-static s8 iwl_update_common_txpower(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element, s8 *max_txpower_in_half_dbm)
+static void
+iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *txp,
+ s8 max_txpower_avg)
{
- struct iwl_channel_info *ch_info;
- int ch;
- bool is_ht40 = false;
- s8 max_txpower_avg; /* (dBm) */
-
- /* it is common section, contain all type (Legacy, HT and HT40)
- * based on the element in the section to determine
- * is it HT 40 or not
- */
- if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
- is_ht40 = true;
- max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower,
- element, max_txpower_in_half_dbm);
-
- ch_info = priv->channel_info;
-
- for (ch = 0; ch < priv->channel_count; ch++) {
- /* find matching band and update tx power if needed */
- if ((ch_info->band == enhinfo[section].band) &&
- (ch_info->max_power_avg < max_txpower_avg) &&
- (!is_ht40)) {
- /* Update regulatory-based run-time data */
- ch_info->max_power_avg = ch_info->curr_txpow =
- max_txpower_avg;
+ int ch_idx;
+ bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
+ enum ieee80211_band band;
+
+ band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+ IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+ for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
+ struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
+
+ /* update matching channel or from common data only */
+ if (txp->channel != 0 && ch_info->channel != txp->channel)
+ continue;
+
+ /* update matching band only */
+ if (band != ch_info->band)
+ continue;
+
+ if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
+ ch_info->max_power_avg = max_txpower_avg;
+ ch_info->curr_txpow = max_txpower_avg;
ch_info->scan_power = max_txpower_avg;
}
- if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
- (ch_info->ht40_max_power_avg < max_txpower_avg)) {
- /* Update regulatory-based run-time data */
+
+ if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
ch_info->ht40_max_power_avg = max_txpower_avg;
- }
- ch_info++;
}
- return max_txpower_avg;
}
-/**
- * iwl_update_channel_txpower: update channel tx power
- * update channel tx power based on EEPROM enhanced tx power info.
- */
-static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element, s8 *max_txpower_in_half_dbm)
-{
- struct iwl_channel_info *ch_info;
- int ch;
- u8 channel;
- s8 max_txpower_avg; /* (dBm) */
-
- channel = enhinfo[section].iwl_eeprom_section_channel[element];
- max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower,
- element, max_txpower_in_half_dbm);
-
- ch_info = priv->channel_info;
- for (ch = 0; ch < priv->channel_count; ch++) {
- /* find matching channel and update tx power if needed */
- if (ch_info->channel == channel) {
- if ((ch_info->max_power_avg < max_txpower_avg) &&
- (!enhinfo[section].is_ht40)) {
- /* Update regulatory-based run-time data */
- ch_info->max_power_avg = max_txpower_avg;
- ch_info->curr_txpow = max_txpower_avg;
- ch_info->scan_power = max_txpower_avg;
- }
- if ((enhinfo[section].is_ht40) &&
- (ch_info->ht40_max_power_avg < max_txpower_avg)) {
- /* Update regulatory-based run-time data */
- ch_info->ht40_max_power_avg = max_txpower_avg;
- }
- break;
- }
- ch_info++;
- }
- return max_txpower_avg;
-}
+#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
+ ? # x " " : "")
-/**
- * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
- */
void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
{
- int eeprom_section_count = 0;
- int section, element;
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
- u32 offset;
- s8 max_txpower_avg; /* (dBm) */
- s8 max_txpower_in_half_dbm; /* (half-dBm) */
-
- /* Loop through all the sections
- * adjust bands and channel's max tx power
- * Set the tx_power_user_lmt to the highest power
- * supported by any channels and chains
- */
- for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
- eeprom_section_count = enhinfo[section].count;
- offset = enhinfo[section].offset;
- enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
- iwl_eeprom_query_addr(priv, offset);
+ struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+ int idx, entries;
+ __le16 *txp_len;
+ s8 max_txp_avg, max_txp_avg_halfdbm;
+
+ BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+ /* the length is in 16-bit words, but we want entries */
+ txp_len = (__le16 *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
+ entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+ txp_array = (void *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
+
+ for (idx = 0; idx < entries; idx++) {
+ txp = &txp_array[idx];
+ /* skip invalid entries */
+ if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+ continue;
+
+ IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
+ (txp->channel && (txp->flags &
+ IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
+ "Common " : (txp->channel) ?
+ "Channel" : "Common",
+ (txp->channel),
+ TXP_CHECK_AND_PRINT(VALID),
+ TXP_CHECK_AND_PRINT(BAND_52G),
+ TXP_CHECK_AND_PRINT(OFDM),
+ TXP_CHECK_AND_PRINT(40MHZ),
+ TXP_CHECK_AND_PRINT(HT_AP),
+ TXP_CHECK_AND_PRINT(RES1),
+ TXP_CHECK_AND_PRINT(RES2),
+ TXP_CHECK_AND_PRINT(COMMON_TYPE),
+ txp->flags);
+ IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
+ "chain_B: 0X%02x chain_C: 0X%02x\n",
+ txp->chain_a_max, txp->chain_b_max,
+ txp->chain_c_max);
+ IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
+ "MIMO3: 0x%02x High 20_on_40: 0x%02x "
+ "Low 20_on_40: 0x%02x\n",
+ txp->mimo2_max, txp->mimo3_max,
+ ((txp->delta_20_in_40 & 0xf0) >> 4),
+ (txp->delta_20_in_40 & 0x0f));
+
+ max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+ &max_txp_avg_halfdbm);
/*
- * check for valid entry -
- * different version of EEPROM might contain different set
- * of enhanced tx power table
- * always check for valid entry before process
- * the information
+ * Update the user limit values values to the highest
+ * power supported by any channel
*/
- if (!enhanced_txpower->common || enhanced_txpower->reserved)
- continue;
+ if (max_txp_avg > priv->tx_power_user_lmt)
+ priv->tx_power_user_lmt = max_txp_avg;
+ if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
+ priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
- for (element = 0; element < eeprom_section_count; element++) {
- if (enhinfo[section].is_common)
- max_txpower_avg =
- iwl_update_common_txpower(priv,
- enhanced_txpower, section,
- element,
- &max_txpower_in_half_dbm);
- else
- max_txpower_avg =
- iwl_update_channel_txpower(priv,
- enhanced_txpower, section,
- element,
- &max_txpower_in_half_dbm);
-
- /* Update the tx_power_user_lmt to the highest power
- * supported by any channel */
- if (max_txpower_avg > priv->tx_power_user_lmt)
- priv->tx_power_user_lmt = max_txpower_avg;
-
- /*
- * Update the tx_power_lmt_in_half_dbm to
- * the highest power supported by any channel
- */
- if (max_txpower_in_half_dbm >
- priv->tx_power_lmt_in_half_dbm)
- priv->tx_power_lmt_in_half_dbm =
- max_txpower_in_half_dbm;
- }
+ iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index ffb2f4111ad0..366340f3fb0f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -307,6 +307,7 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
if (ctx_bss->vif && ctx_pan->vif) {
int bcnint = ctx_pan->vif->bss_conf.beacon_int;
+ int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
/* should be set, but seems unused?? */
cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
@@ -329,10 +330,10 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
if (test_bit(STATUS_SCAN_HW, &priv->status) ||
(!ctx_bss->vif->bss_conf.idle &&
!ctx_bss->vif->bss_conf.assoc)) {
- slot0 = bcnint * 3 - 20;
+ slot0 = dtim * bcnint * 3 - 20;
slot1 = 20;
} else if (!ctx_pan->vif->bss_conf.idle &&
- !ctx_pan->vif->bss_conf.assoc) {
+ !ctx_pan->vif->bss_conf.assoc) {
slot1 = bcnint * 3 - 20;
slot0 = 20;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
index a5dbfea1bfad..b5cb3be0eb4b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
@@ -197,7 +197,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
none:
/* re-enable interrupts here since we don't have anything to service. */
- /* only Re-enable if diabled by irq and no schedules tasklet. */
+ /* only Re-enable if disabled by irq and no schedules tasklet. */
if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
iwl_enable_interrupts(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index b555edd53354..3dee87e8f55d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -405,6 +405,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
return;
}
+ txq->time_stamp = jiffies;
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
@@ -445,22 +446,17 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
- (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
- if (agg->state == IWL_AGG_OFF)
- iwl_wake_queue(priv, txq_id);
- else
- iwl_wake_queue(priv, txq->swq_id);
- }
+ (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+ iwl_wake_queue(priv, txq);
}
} else {
- BUG_ON(txq_id != txq->swq_id);
iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark))
- iwl_wake_queue(priv, txq_id);
+ iwl_wake_queue(priv, txq);
}
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
@@ -496,6 +492,10 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd;
+ if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
+ "TX Power requested while scanning!\n"))
+ return -EAGAIN;
+
/* half dBm need to multiply */
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
@@ -522,9 +522,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
else
tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
- return iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
- sizeof(tx_power_cmd), &tx_power_cmd,
- NULL);
+ return iwl_send_cmd_pdu(priv, tx_ant_cfg_cmd, sizeof(tx_power_cmd),
+ &tx_power_cmd);
}
void iwlagn_temperature(struct iwl_priv *priv)
@@ -569,6 +568,12 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
case INDIRECT_REGULATORY:
offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY);
break;
+ case INDIRECT_TXP_LIMIT:
+ offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT);
+ break;
+ case INDIRECT_TXP_LIMIT_SIZE:
+ offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE);
+ break;
case INDIRECT_CALIBRATION:
offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION);
break;
@@ -750,6 +755,12 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
} else
iwlagn_txq_ctx_reset(priv);
+ if (priv->cfg->base_params->shadow_reg_enable) {
+ /* enable shadow regs in HW */
+ iwl_set_bit(priv, CSR_MAC_SHADOW_REG_CTRL,
+ 0x800FFFFF);
+ }
+
set_bit(STATUS_INIT, &priv->status);
return 0;
@@ -1481,15 +1492,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->cfg->scan_rx_antennas[band])
rx_ant = priv->cfg->scan_rx_antennas[band];
- if (priv->cfg->scan_tx_antennas[band])
- scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
-
- if (priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist &&
- priv->bt_full_concurrent) {
- /* operated as 1x1 in full concurrency mode */
- scan_tx_antennas = first_antenna(
- priv->cfg->scan_tx_antennas[band]);
+ if (band == IEEE80211_BAND_2GHZ &&
+ priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ /* transmit 2.4 GHz probes only on first antenna */
+ scan_tx_antennas = first_antenna(scan_tx_antennas);
}
priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
@@ -1584,22 +1591,6 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
return ret;
}
-void iwlagn_post_scan(struct iwl_priv *priv)
-{
- struct iwl_rxon_context *ctx;
-
- /*
- * Since setting the RXON may have been deferred while
- * performing the scan, fire one off if needed
- */
- for_each_context(priv, ctx)
- if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
- iwlagn_commit_rxon(priv, ctx);
-
- if (priv->cfg->ops->hcmd->set_pan_params)
- priv->cfg->ops->hcmd->set_pan_params(priv);
-}
-
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add)
{
@@ -1790,7 +1781,7 @@ static const __le32 iwlagn_def_3w_lookup[12] = {
cpu_to_le32(0xc0004000),
cpu_to_le32(0x00004000),
cpu_to_le32(0xf0005000),
- cpu_to_le32(0xf0004000),
+ cpu_to_le32(0xf0005000),
};
static const __le32 iwlagn_concurrent_lookup[12] = {
@@ -1826,6 +1817,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
bt_cmd.prio_boost = 0;
bt_cmd.kill_ack_mask = priv->kill_ack_mask;
bt_cmd.kill_cts_mask = priv->kill_cts_mask;
+
bt_cmd.valid = priv->bt_valid;
bt_cmd.tx_prio_boost = 0;
bt_cmd.rx_prio_boost = 0;
@@ -1841,10 +1833,15 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
} else {
bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_sco_disable)
+ bt_cmd.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+
if (priv->bt_ch_announce)
bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags);
}
+ priv->bt_enable_flag = bt_cmd.flags;
if (priv->bt_full_concurrent)
memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup,
sizeof(iwlagn_concurrent_lookup));
@@ -1884,12 +1881,20 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
struct iwl_rxon_context *ctx;
int smps_request = -1;
+ /*
+ * Note: bt_traffic_load can be overridden by scan complete and
+ * coex profile notifications. Ignore that since only bad consequence
+ * can be not matching debug print with actual state.
+ */
IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n",
priv->bt_traffic_load);
switch (priv->bt_traffic_load) {
case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
- smps_request = IEEE80211_SMPS_AUTOMATIC;
+ if (priv->bt_status)
+ smps_request = IEEE80211_SMPS_DYNAMIC;
+ else
+ smps_request = IEEE80211_SMPS_AUTOMATIC;
break;
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
smps_request = IEEE80211_SMPS_DYNAMIC;
@@ -1906,6 +1911,16 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
mutex_lock(&priv->mutex);
+ /*
+ * We can not send command to firmware while scanning. When the scan
+ * complete we will schedule this work again. We do check with mutex
+ * locked to prevent new scan request to arrive. We do not check
+ * STATUS_SCANNING to avoid race when queue_work two times from
+ * different notifications, but quit and not perform any work at all.
+ */
+ if (test_bit(STATUS_SCAN_HW, &priv->status))
+ goto out;
+
if (priv->cfg->ops->lib->update_chain_flags)
priv->cfg->ops->lib->update_chain_flags(priv);
@@ -1915,7 +1930,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
ieee80211_request_smps(ctx->vif, smps_request);
}
}
-
+out:
mutex_unlock(&priv->mutex);
}
@@ -1986,24 +2001,29 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv,
BT_UART_MSG_FRAME7CONNECTABLE_POS);
}
-static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv,
- struct iwl_bt_uart_msg *uart_msg)
+static void iwlagn_set_kill_msk(struct iwl_priv *priv,
+ struct iwl_bt_uart_msg *uart_msg)
{
- u8 kill_ack_msk;
- __le32 bt_kill_ack_msg[2] = {
- cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) };
-
- kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK |
- BT_UART_MSG_FRAME3SNIFF_MSK |
- BT_UART_MSG_FRAME3SCOESCO_MSK) &
- uart_msg->frame3) == 0) ? 1 : 0;
- if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) {
+ u8 kill_msk;
+ static const __le32 bt_kill_ack_msg[2] = {
+ IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
+ IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
+ static const __le32 bt_kill_cts_msg[2] = {
+ IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
+ IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
+
+ kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
+ ? 1 : 0;
+ if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
+ priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
- priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk];
+ priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
+ priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
+ priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
+
/* schedule to send runtime bt_config */
queue_work(priv->workqueue, &priv->bt_runtime_config);
}
-
}
void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
@@ -2014,7 +2034,6 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
- u8 last_traffic_load;
IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n");
IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status);
@@ -2023,11 +2042,10 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
coex->bt_ci_compliance);
iwlagn_print_uartmsg(priv, uart_msg);
- last_traffic_load = priv->notif_bt_traffic_load;
- priv->notif_bt_traffic_load = coex->bt_traffic_load;
+ priv->last_bt_traffic_load = priv->bt_traffic_load;
if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
if (priv->bt_status != coex->bt_status ||
- last_traffic_load != coex->bt_traffic_load) {
+ priv->last_bt_traffic_load != coex->bt_traffic_load) {
if (coex->bt_status) {
/* BT on */
if (!priv->bt_ch_announce)
@@ -2056,7 +2074,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
}
}
- iwlagn_set_kill_ack_msk(priv, uart_msg);
+ iwlagn_set_kill_msk(priv, uart_msg);
/* FIXME: based on notification, adjust the prio_boost */
@@ -2276,7 +2294,7 @@ static const char *get_csr_string(int cmd)
void iwl_dump_csr(struct iwl_priv *priv)
{
int i;
- u32 csr_tbl[] = {
+ static const u32 csr_tbl[] = {
CSR_HW_IF_CONFIG_REG,
CSR_INT_COALESCING,
CSR_INT,
@@ -2335,7 +2353,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
int pos = 0;
size_t bufsz = 0;
#endif
- u32 fh_tbl[] = {
+ static const u32 fh_tbl[] = {
FH_RSCSR_CHNL0_STTS_WPTR_REG,
FH_RSCSR_CHNL0_RBDCB_BASE_REG,
FH_RSCSR_CHNL0_WPTR,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 065553629de5..75fcd30a7c13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -387,7 +387,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
if (load > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
sta->addr, tid);
- ret = ieee80211_start_tx_ba_session(sta, tid);
+ ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
if (ret == -EAGAIN) {
/*
* driver and mac80211 is out of sync
@@ -833,17 +833,23 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct iwl_lq_sta *lq_sta)
{
struct iwl_scale_tbl_info *tbl;
- bool full_concurrent;
+ bool full_concurrent = priv->bt_full_concurrent;
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
- full_concurrent = true;
- else
- full_concurrent = false;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->bt_full_concurrent != full_concurrent) {
+ if (priv->bt_ant_couple_ok) {
+ /*
+ * Is there a need to switch between
+ * full concurrency and 3-wire?
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
+ full_concurrent = true;
+ else
+ full_concurrent = false;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
+ (priv->bt_full_concurrent != full_concurrent)) {
priv->bt_full_concurrent = full_concurrent;
/* Update uCode's rate table. */
@@ -1040,8 +1046,7 @@ done:
if (sta && sta->supp_rates[sband->band])
rs_rate_scale_perform(priv, skb, sta, lq_sta);
- /* Is there a need to switch between full concurrency and 3-wire? */
- if (priv->bt_ant_couple_ok)
+ if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
rs_bt_update_lq(priv, ctx, lq_sta);
}
@@ -2868,6 +2873,10 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_agg = 0;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ lq_sta->dbg_fixed_rate = 0;
+#endif
+
rs_initialize_lq(priv, conf, sta, lq_sta);
}
@@ -3010,10 +3019,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
*/
if (priv && priv->cfg->bt_params &&
priv->cfg->bt_params->agg_time_limit &&
- priv->cfg->bt_params->agg_time_limit >=
- LINK_QUAL_AGG_TIME_LIMIT_MIN &&
- priv->cfg->bt_params->agg_time_limit <=
- LINK_QUAL_AGG_TIME_LIMIT_MAX)
+ priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
lq_cmd->agg_params.agg_time_limit =
cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
new file mode 100644
index 000000000000..6d140bd53291
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -0,0 +1,642 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include "iwl-dev.h"
+#include "iwl-agn.h"
+#include "iwl-sta.h"
+#include "iwl-core.h"
+#include "iwl-agn-calib.h"
+
+static int iwlagn_disable_bss(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct iwl_rxon_cmd *send)
+{
+ __le32 old_filter = send->filter_flags;
+ int ret;
+
+ send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+
+ send->filter_flags = old_filter;
+
+ if (ret)
+ IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+
+ return ret;
+}
+
+static int iwlagn_disable_pan(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct iwl_rxon_cmd *send)
+{
+ __le32 old_filter = send->filter_flags;
+ u8 old_dev_type = send->dev_type;
+ int ret;
+
+ send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ send->dev_type = RXON_DEV_TYPE_P2P;
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+
+ send->filter_flags = old_filter;
+ send->dev_type = old_dev_type;
+
+ if (ret)
+ IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
+
+ /* FIXME: WAIT FOR PAN DISABLE */
+ msleep(300);
+
+ return ret;
+}
+
+static void iwlagn_update_qos(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ int ret;
+
+ if (!ctx->is_active)
+ return;
+
+ ctx->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (ctx->qos_data.qos_active)
+ ctx->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ if (ctx->ht.enabled)
+ ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+ IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+ ctx->qos_data.qos_active,
+ ctx->qos_data.def_qos_parm.qos_flags);
+
+ ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd,
+ sizeof(struct iwl_qosparam_cmd),
+ &ctx->qos_data.def_qos_parm);
+ if (ret)
+ IWL_ERR(priv, "Failed to update QoS\n");
+}
+
+static int iwlagn_update_beacon(struct iwl_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ lockdep_assert_held(&priv->mutex);
+
+ dev_kfree_skb(priv->beacon_skb);
+ priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
+ if (!priv->beacon_skb)
+ return -ENOMEM;
+ return iwlagn_send_beacon_cmd(priv);
+}
+
+/**
+ * iwlagn_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is committed 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.
+ */
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active = (void *)&ctx->active;
+ bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+ bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
+ int ret;
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EINVAL;
+
+ if (!iwl_is_alive(priv))
+ return -EBUSY;
+
+ /* This function hardcodes a bunch of dual-mode assumptions */
+ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+ if (!ctx->is_active)
+ return 0;
+
+ /* always get timestamp with Rx frame */
+ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
+ !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ ret = iwl_check_rxon_cmd(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * receive commit_rxon request
+ * abort any previous channel switch if still in process
+ */
+ if (priv->switch_rxon.switch_in_progress &&
+ (priv->switch_rxon.channel != ctx->staging.channel)) {
+ IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
+ le16_to_cpu(priv->switch_rxon.channel));
+ iwl_chswitch_done(priv, false);
+ }
+
+ /*
+ * 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, ctx)) {
+ ret = iwl_send_rxon_assoc(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
+ return ret;
+ }
+
+ memcpy(active, &ctx->staging, sizeof(*active));
+ iwl_print_rx_config_cmd(priv, ctx);
+ return 0;
+ }
+
+ if (priv->cfg->ops->hcmd->set_pan_params) {
+ ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+ if (ret)
+ return ret;
+ }
+
+ iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+
+ IWL_DEBUG_INFO(priv,
+ "Going to commit RXON\n"
+ " * with%s RXON_FILTER_ASSOC_MSK\n"
+ " * channel = %d\n"
+ " * bssid = %pM\n",
+ (new_assoc ? "" : "out"),
+ le16_to_cpu(ctx->staging.channel),
+ ctx->staging.bssid_addr);
+
+ /*
+ * Always clear associated first, but with the correct config.
+ * This is required as for example station addition for the
+ * AP station must be done after the BSSID is set to correctly
+ * set up filters in the device.
+ */
+ if ((old_assoc && new_assoc) || !new_assoc) {
+ if (ctx->ctxid == IWL_RXON_CTX_BSS)
+ ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
+ else
+ ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+ if (ret)
+ return ret;
+
+ memcpy(active, &ctx->staging, sizeof(*active));
+
+ /*
+ * Un-assoc RXON clears the station table and WEP
+ * keys, so we have to restore those afterwards.
+ */
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ /* RXON timing must be before associated RXON */
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+ return ret;
+ }
+
+ if (new_assoc) {
+ /* QoS info may be cleared by previous un-assoc RXON */
+ iwlagn_update_qos(priv, ctx);
+
+ /*
+ * We'll run into this code path when beaconing is
+ * enabled, but then we also need to send the beacon
+ * to the device.
+ */
+ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
+ ret = iwlagn_update_beacon(priv, ctx->vif);
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending required beacon (%d)!\n",
+ ret);
+ return ret;
+ }
+ }
+
+ priv->start_calib = 0;
+ /*
+ * Apply the new configuration.
+ *
+ * Associated RXON doesn't clear the station table in uCode,
+ * so we don't need to restore stations etc. after this.
+ */
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
+ if (ret) {
+ IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+ return ret;
+ }
+ memcpy(active, &ctx->staging, sizeof(*active));
+
+ iwl_reprogram_ap_sta(priv, ctx);
+
+ /* IBSS beacon needs to be sent after setting assoc */
+ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
+ if (iwlagn_update_beacon(priv, ctx->vif))
+ IWL_ERR(priv, "Error sending IBSS beacon\n");
+ }
+
+ iwl_print_rx_config_cmd(priv, ctx);
+
+ iwl_init_sensitivity(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.
+ *
+ * FIXME: which RXON requires a tune? Can we optimise this out in
+ * some cases?
+ */
+ ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ if (ret) {
+ IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_channel *channel = conf->channel;
+ const struct iwl_channel_info *ch_info;
+ int ret = 0;
+ bool ht_changed[NUM_IWL_RXON_CTX] = {};
+
+ IWL_DEBUG_MAC80211(priv, "changed %#x", changed);
+
+ mutex_lock(&priv->mutex);
+
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+ goto out;
+ }
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ goto out;
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ /* mac80211 uses static for non-HT which is what we want */
+ priv->current_ht_config.smps = conf->smps_mode;
+
+ /*
+ * Recalculate chain counts.
+ *
+ * If monitor mode is enabled then mac80211 will
+ * set up the SM PS mode to OFF if an HT channel is
+ * configured.
+ */
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ for_each_context(priv, ctx)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ unsigned long flags;
+
+ ch_info = iwl_get_channel_info(priv, channel->band,
+ channel->hw_value);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for_each_context(priv, ctx) {
+ /* Configure HT40 channels */
+ if (ctx->ht.enabled != conf_is_ht(conf)) {
+ ctx->ht.enabled = conf_is_ht(conf);
+ ht_changed[ctx->ctxid] = true;
+ }
+
+ if (ctx->ht.enabled) {
+ if (conf_is_ht40_minus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ctx->ht.is_40mhz = true;
+ } else if (conf_is_ht40_plus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ctx->ht.is_40mhz = true;
+ } else {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ctx->ht.is_40mhz = false;
+ }
+ } else
+ ctx->ht.is_40mhz = false;
+
+ /*
+ * Default to no protection. Protection mode will
+ * later be set from BSS config in iwl_ht_conf
+ */
+ ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if (le16_to_cpu(ctx->staging.channel) !=
+ channel->hw_value)
+ ctx->staging.flags = 0;
+
+ iwl_set_rxon_channel(priv, channel, ctx);
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+
+ iwl_set_flags_for_band(priv, ctx, channel->band,
+ ctx->vif);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_update_bcast_stations(priv);
+
+ /*
+ * The list of supported rates and rate mask can be different
+ * for each band; since the band may have changed, reset
+ * the rate mask to what mac80211 lists.
+ */
+ iwl_set_rate(priv);
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_PS |
+ IEEE80211_CONF_CHANGE_IDLE)) {
+ ret = iwl_power_update_mode(priv, false);
+ if (ret)
+ IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+ priv->tx_power_user_lmt, conf->power_level);
+
+ iwl_set_tx_power(priv, conf->power_level, false);
+ }
+
+ for_each_context(priv, ctx) {
+ if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ continue;
+ iwlagn_commit_rxon(priv, ctx);
+ if (ht_changed[ctx->ctxid])
+ iwlagn_update_qos(priv, ctx);
+ }
+ out:
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+
+static void iwlagn_check_needed_chains(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct ieee80211_vif *vif = ctx->vif;
+ struct iwl_rxon_context *tmp;
+ struct ieee80211_sta *sta;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ bool need_multiple;
+
+ lockdep_assert_held(&priv->mutex);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (sta) {
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ int maxstreams;
+
+ maxstreams = (ht_cap->mcs.tx_params &
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+ >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+ maxstreams += 1;
+
+ need_multiple = true;
+
+ if ((ht_cap->mcs.rx_mask[1] == 0) &&
+ (ht_cap->mcs.rx_mask[2] == 0))
+ need_multiple = false;
+ if (maxstreams <= 1)
+ need_multiple = false;
+ } else {
+ /*
+ * If at all, this can only happen through a race
+ * when the AP disconnects us while we're still
+ * setting up the connection, in that case mac80211
+ * will soon tell us about that.
+ */
+ need_multiple = false;
+ }
+ rcu_read_unlock();
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ /* currently */
+ need_multiple = false;
+ break;
+ default:
+ /* only AP really */
+ need_multiple = true;
+ break;
+ }
+
+ ctx->ht_need_multiple_chains = need_multiple;
+
+ if (!need_multiple) {
+ /* check all contexts */
+ for_each_context(priv, tmp) {
+ if (!tmp->vif)
+ continue;
+ if (tmp->ht_need_multiple_chains) {
+ need_multiple = true;
+ break;
+ }
+ }
+ }
+
+ ht_conf->single_chain_sufficient = !need_multiple;
+}
+
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+ int ret;
+ bool force = false;
+
+ mutex_lock(&priv->mutex);
+
+ if (unlikely(!iwl_is_ready(priv))) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (unlikely(!ctx->vif)) {
+ IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (changes & BSS_CHANGED_BEACON_INT)
+ force = true;
+
+ if (changes & BSS_CHANGED_QOS) {
+ ctx->qos_data.qos_active = bss_conf->qos;
+ iwlagn_update_qos(priv, ctx);
+ }
+
+ ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+ if (vif->bss_conf.use_short_preamble)
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (changes & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ iwl_led_associate(priv);
+ priv->timestamp = bss_conf->timestamp;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ } else {
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_led_disassociate(priv);
+ }
+ }
+
+ if (ctx->ht.enabled) {
+ ctx->ht.protection = bss_conf->ht_operation_mode &
+ IEEE80211_HT_OP_MODE_PROTECTION;
+ ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
+ IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ iwlagn_check_needed_chains(priv, ctx, bss_conf);
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+
+ if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+ ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+
+ if (bss_conf->use_cts_prot)
+ ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+
+ memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
+
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC) {
+ if (vif->bss_conf.enable_beacon) {
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ priv->beacon_ctx = ctx;
+ } else {
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ priv->beacon_ctx = NULL;
+ }
+ }
+
+ if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ iwlagn_commit_rxon(priv, ctx);
+
+ if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
+ /*
+ * The chain noise calibration will enable PM upon
+ * completion. If calibration has already been run
+ * then we need to enable power management here.
+ */
+ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+ iwl_power_update_mode(priv, false);
+
+ /* Enable RX differential gain and sensitivity calibrations */
+ iwl_chain_noise_reset(priv);
+ priv->start_calib = 1;
+ }
+
+ if (changes & BSS_CHANGED_IBSS) {
+ ret = iwlagn_manage_ibss_station(priv, vif,
+ bss_conf->ibss_joined);
+ if (ret)
+ IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+ bss_conf->ibss_joined ? "add" : "remove",
+ bss_conf->bssid);
+ }
+
+ if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
+ priv->beacon_ctx) {
+ if (iwlagn_update_beacon(priv, vif))
+ IWL_ERR(priv, "Error sending IBSS beacon\n");
+ }
+
+ mutex_unlock(&priv->mutex);
+}
+
+void iwlagn_post_scan(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx;
+
+ /*
+ * Since setting the RXON may have been deferred while
+ * performing the scan, fire one off if needed
+ */
+ for_each_context(priv, ctx)
+ if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ iwlagn_commit_rxon(priv, ctx);
+
+ if (priv->cfg->ops->hcmd->set_pan_params)
+ priv->cfg->ops->hcmd->set_pan_params(priv);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 35a30d2e0734..35f085ac336b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -684,7 +684,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
-void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
unsigned long flags;
@@ -714,3 +714,33 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
+
+void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+ int sta_id;
+
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ WARN_ON(!sta_priv->client);
+ sta_priv->asleep = true;
+ if (atomic_read(&sta_priv->pending_frames) > 0)
+ ieee80211_sta_block_awake(hw, sta, true);
+ break;
+ case STA_NOTIFY_AWAKE:
+ WARN_ON(!sta_priv->client);
+ if (!sta_priv->asleep)
+ break;
+ sta_priv->asleep = false;
+ sta_id = iwl_sta_id(sta);
+ if (sta_id != IWL_INVALID_STATION)
+ iwl_sta_modify_ps_wake(priv, sta_id);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 2b078a995729..24a11b8f73bc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -67,8 +67,14 @@
*/
static const u8 tid_to_ac[] = {
- /* this matches the mac80211 numbers */
- 2, 3, 3, 2, 1, 1, 0, 0
+ IEEE80211_AC_BE,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BE,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VO,
+ IEEE80211_AC_VO
};
static inline int get_ac_from_tid(u16 tid)
@@ -518,11 +524,11 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl_cmd_meta *out_meta;
struct iwl_tx_cmd *tx_cmd;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- int swq_id, txq_id;
+ int txq_id;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
- u16 len, len_org, firstlen, secondlen;
+ u16 len, firstlen, secondlen;
u16 seq_number = 0;
__le16 fc;
u8 hdr_len;
@@ -531,6 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 tid = 0;
u8 *qc = NULL;
unsigned long flags;
+ bool is_agg = false;
if (info->control.vif)
ctx = iwl_rxon_ctx_from_vif(info->control.vif);
@@ -567,8 +574,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta)
sta_priv = (void *)sta->drv_priv;
- if (sta_priv && sta_priv->asleep) {
- WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+ if (sta_priv && sta_priv->asleep &&
+ (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
/*
* This sends an asynchronous command to the device,
* but we can rely on it being processed before the
@@ -616,11 +623,11 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_AMPDU &&
priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+ is_agg = true;
}
}
txq = &priv->txq[txq_id];
- swq_id = txq->swq_id;
q = &txq->q;
if (unlikely(iwl_queue_space(q) < q->high_mark)) {
@@ -687,30 +694,23 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
*/
len = sizeof(struct iwl_tx_cmd) +
sizeof(struct iwl_cmd_header) + hdr_len;
-
- len_org = len;
- firstlen = len = (len + 3) & ~3;
-
- if (len_org != len)
- len_org = 1;
- else
- len_org = 0;
+ firstlen = (len + 3) & ~3;
/* Tell NIC about any 2-byte padding after MAC header */
- if (len_org)
+ if (firstlen != len)
tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
txcmd_phys = pci_map_single(priv->pci_dev,
- &out_cmd->hdr, len,
+ &out_cmd->hdr, firstlen,
PCI_DMA_BIDIRECTIONAL);
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
- dma_unmap_len_set(out_meta, len, len);
+ dma_unmap_len_set(out_meta, len, firstlen);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- txcmd_phys, len, 1, 0);
+ txcmd_phys, firstlen, 1, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -721,23 +721,21 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
- secondlen = len = skb->len - hdr_len;
- if (len) {
+ secondlen = skb->len - hdr_len;
+ if (secondlen > 0) {
phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
- len, PCI_DMA_TODEVICE);
+ secondlen, PCI_DMA_TODEVICE);
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- phys_addr, len,
+ phys_addr, secondlen,
0, 0);
}
scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
- len = sizeof(struct iwl_tx_cmd) +
- sizeof(struct iwl_cmd_header) + hdr_len;
/* take back ownership of DMA buffer to enable update */
pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
- len, PCI_DMA_BIDIRECTIONAL);
+ firstlen, PCI_DMA_BIDIRECTIONAL);
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
@@ -753,7 +751,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
le16_to_cpu(tx_cmd->len));
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
- len, PCI_DMA_BIDIRECTIONAL);
+ firstlen, PCI_DMA_BIDIRECTIONAL);
trace_iwlwifi_dev_tx(priv,
&((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
@@ -773,8 +771,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
* whether or not we should update the write pointer.
*/
- /* avoid atomic ops if it isn't an associated client */
- if (sta_priv && sta_priv->client)
+ /*
+ * Avoid atomic ops if it isn't an associated client.
+ * Also, if this is a packet for aggregation, don't
+ * increase the counter because the ucode will stop
+ * aggregation queues when their respective station
+ * goes to sleep.
+ */
+ if (sta_priv && sta_priv->client && !is_agg)
atomic_inc(&sta_priv->pending_frames);
if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
@@ -784,7 +788,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
} else {
- iwl_stop_queue(priv, txq->swq_id);
+ iwl_stop_queue(priv, txq);
}
}
@@ -1013,7 +1017,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data = &priv->stations[sta_id].tid[tid];
*ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
- priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(get_ac_from_tid(tid), txq_id);
+ iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
spin_unlock_irqrestore(&priv->sta_lock, flags);
ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
@@ -1153,14 +1157,15 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
return 0;
}
-static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
+static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ const u8 *addr1)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
struct ieee80211_sta *sta;
struct iwl_station_priv *sta_priv;
rcu_read_lock();
- sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1);
+ sta = ieee80211_find_sta(ctx->vif, addr1);
if (sta) {
sta_priv = (void *)sta->drv_priv;
/* avoid atomic ops if this isn't a client */
@@ -1169,6 +1174,15 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
ieee80211_sta_block_awake(priv->hw, sta, false);
}
rcu_read_unlock();
+}
+
+static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info,
+ bool is_agg)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
+
+ if (!is_agg)
+ iwlagn_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1);
ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
}
@@ -1193,7 +1207,8 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- iwlagn_tx_status(priv, tx_info);
+ iwlagn_tx_status(priv, tx_info,
+ txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
hdr = (struct ieee80211_hdr *)tx_info->skb->data;
if (hdr && ieee80211_is_data_qos(hdr->frame_control))
@@ -1222,7 +1237,6 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
int i, sh, ack;
u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
- u64 bitmap, sent_bitmap;
int successes = 0;
struct ieee80211_tx_info *info;
@@ -1241,40 +1255,68 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
if (sh < 0) /* tbw something is wrong with indices */
sh += 0x100;
- /* don't use 64-bit values for now */
- bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
-
if (agg->frame_count > (64 - sh)) {
IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
return -1;
}
+ if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
+ /*
+ * sent and ack information provided by uCode
+ * use it instead of figure out ourself
+ */
+ if (ba_resp->txed_2_done > ba_resp->txed) {
+ IWL_DEBUG_TX_REPLY(priv,
+ "bogus sent(%d) and ack(%d) count\n",
+ ba_resp->txed, ba_resp->txed_2_done);
+ /*
+ * set txed_2_done = txed,
+ * so it won't impact rate scale
+ */
+ ba_resp->txed = ba_resp->txed_2_done;
+ }
+ IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
+ ba_resp->txed, ba_resp->txed_2_done);
+ } else {
+ u64 bitmap, sent_bitmap;
+
+ /* don't use 64-bit values for now */
+ bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
+
+ /* check for success or failure according to the
+ * transmitted bitmap and block-ack bitmap */
+ sent_bitmap = bitmap & agg->bitmap;
+
+ /* For each frame attempted in aggregation,
+ * update driver's record of tx frame's status. */
+ i = 0;
+ while (sent_bitmap) {
+ ack = sent_bitmap & 1ULL;
+ successes += ack;
+ IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
+ ack ? "ACK" : "NACK", i,
+ (agg->start_idx + i) & 0xff,
+ agg->start_idx + i);
+ sent_bitmap >>= 1;
+ ++i;
+ }
- /* check for success or failure according to the
- * transmitted bitmap and block-ack bitmap */
- sent_bitmap = bitmap & agg->bitmap;
-
- /* For each frame attempted in aggregation,
- * update driver's record of tx frame's status. */
- i = 0;
- while (sent_bitmap) {
- ack = sent_bitmap & 1ULL;
- successes += ack;
- IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
- ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
- agg->start_idx + i);
- sent_bitmap >>= 1;
- ++i;
+ IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n",
+ (unsigned long long)bitmap);
}
info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
memset(&info->status, 0, sizeof(info->status));
info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
- info->status.ampdu_ack_len = successes;
- info->status.ampdu_len = agg->frame_count;
- iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
+ if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
+ info->status.ampdu_ack_len = ba_resp->txed_2_done;
+ info->status.ampdu_len = ba_resp->txed;
- IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
+ } else {
+ info->status.ampdu_ack_len = successes;
+ info->status.ampdu_len = agg->frame_count;
+ }
+ iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
return 0;
}
@@ -1385,7 +1427,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
priv->mac80211_registered &&
(agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
- iwl_wake_queue(priv, txq->swq_id);
+ iwl_wake_queue(priv, txq);
iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 703621107dac..24dabcd2a36c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -40,30 +40,36 @@
#include "iwl-agn.h"
#include "iwl-agn-calib.h"
-static const s8 iwlagn_default_queue_to_tx_fifo[] = {
- IWL_TX_FIFO_VO,
- IWL_TX_FIFO_VI,
- IWL_TX_FIFO_BE,
- IWL_TX_FIFO_BK,
- IWLAGN_CMD_FIFO_NUM,
- IWL_TX_FIFO_UNUSED,
- IWL_TX_FIFO_UNUSED,
- IWL_TX_FIFO_UNUSED,
- IWL_TX_FIFO_UNUSED,
- IWL_TX_FIFO_UNUSED,
+#define IWL_AC_UNSET -1
+
+struct queue_to_fifo_ac {
+ s8 fifo, ac;
+};
+
+static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
+ { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+ { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
};
-static const s8 iwlagn_ipan_queue_to_tx_fifo[] = {
- IWL_TX_FIFO_VO,
- IWL_TX_FIFO_VI,
- IWL_TX_FIFO_BE,
- IWL_TX_FIFO_BK,
- IWL_TX_FIFO_BK_IPAN,
- IWL_TX_FIFO_BE_IPAN,
- IWL_TX_FIFO_VI_IPAN,
- IWL_TX_FIFO_VO_IPAN,
- IWL_TX_FIFO_BE_IPAN,
- IWLAGN_CMD_FIFO_NUM,
+static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
+ { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+ { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
+ { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_BE_IPAN, 2, },
+ { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
};
static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
@@ -429,7 +435,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
int iwlagn_alive_notify(struct iwl_priv *priv)
{
- const s8 *queues;
+ const struct queue_to_fifo_ac *queue_to_fifo;
u32 a;
unsigned long flags;
int i, chan;
@@ -492,9 +498,9 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
/* map queues to FIFOs */
if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
- queues = iwlagn_ipan_queue_to_tx_fifo;
+ queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
else
- queues = iwlagn_default_queue_to_tx_fifo;
+ queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0);
@@ -510,18 +516,25 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
for (i = 0; i < 10; i++) {
- int ac = queues[i];
+ int fifo = queue_to_fifo[i].fifo;
+ int ac = queue_to_fifo[i].ac;
iwl_txq_ctx_activate(priv, i);
- if (ac == IWL_TX_FIFO_UNUSED)
+ if (fifo == IWL_TX_FIFO_UNUSED)
continue;
- iwlagn_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+ if (ac != IWL_AC_UNSET)
+ iwl_set_swq_id(&priv->txq[i], ac, i);
+ iwlagn_tx_queue_set_status(priv, &priv->txq[i], fifo, 0);
}
spin_unlock_irqrestore(&priv->lock, flags);
+ /* Enable L1-Active */
+ iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
iwlagn_send_wimax_coex(priv);
iwlagn_set_Xtal_calib(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c2636a7ab9ee..36335b1b54d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -90,170 +90,6 @@ MODULE_ALIAS("iwl4965");
static int iwlagn_ant_coupling;
static bool iwlagn_bt_ch_announce = 1;
-/**
- * iwlagn_commit_rxon - commit staging_rxon to hardware
- *
- * The RXON command in staging_rxon is committed 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.
- */
-int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
- /* cast away the const for active_rxon in this function */
- struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
- int ret;
- bool new_assoc =
- !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
- bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
-
- if (!iwl_is_alive(priv))
- return -EBUSY;
-
- if (!ctx->is_active)
- return 0;
-
- /* always get timestamp with Rx frame */
- ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
-
- ret = iwl_check_rxon_cmd(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
- return -EINVAL;
- }
-
- /*
- * receive commit_rxon request
- * abort any previous channel switch if still in process
- */
- if (priv->switch_rxon.switch_in_progress &&
- (priv->switch_rxon.channel != ctx->staging.channel)) {
- IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
- le16_to_cpu(priv->switch_rxon.channel));
- iwl_chswitch_done(priv, false);
- }
-
- /* 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, ctx)) {
- ret = iwl_send_rxon_assoc(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
- return ret;
- }
-
- memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
- iwl_print_rx_config_cmd(priv, ctx);
- 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_ctx(ctx) && new_assoc) {
- IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
- active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
- sizeof(struct iwl_rxon_cmd),
- active_rxon);
-
- /* If the mask clearing failed then we set
- * active_rxon back to what it was previously */
- if (ret) {
- active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
- IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
- return ret;
- }
- iwl_clear_ucode_stations(priv, ctx);
- iwl_restore_stations(priv, ctx);
- ret = iwl_restore_default_wep_keys(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
- return ret;
- }
- }
-
- IWL_DEBUG_INFO(priv, "Sending RXON\n"
- "* with%s RXON_FILTER_ASSOC_MSK\n"
- "* channel = %d\n"
- "* bssid = %pM\n",
- (new_assoc ? "" : "out"),
- le16_to_cpu(ctx->staging.channel),
- ctx->staging.bssid_addr);
-
- iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
-
- if (!old_assoc) {
- /*
- * First of all, before setting associated, we need to
- * send RXON timing so the device knows about the DTIM
- * period and other timing values
- */
- ret = iwl_send_rxon_timing(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Error setting RXON timing!\n");
- return ret;
- }
- }
-
- if (priv->cfg->ops->hcmd->set_pan_params) {
- ret = priv->cfg->ops->hcmd->set_pan_params(priv);
- if (ret)
- return ret;
- }
-
- /* Apply the new configuration
- * RXON unassoc clears the station table in uCode so restoration of
- * stations is needed after it (the RXON command) completes
- */
- if (!new_assoc) {
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
- sizeof(struct iwl_rxon_cmd), &ctx->staging);
- if (ret) {
- IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
- return ret;
- }
- IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
- memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
- iwl_clear_ucode_stations(priv, ctx);
- iwl_restore_stations(priv, ctx);
- ret = iwl_restore_default_wep_keys(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
- return ret;
- }
- }
- if (new_assoc) {
- priv->start_calib = 0;
- /* Apply the new configuration
- * RXON assoc doesn't clear the station table in uCode,
- */
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
- sizeof(struct iwl_rxon_cmd), &ctx->staging);
- if (ret) {
- IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
- return ret;
- }
- memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
- }
- iwl_print_rx_config_cmd(priv, ctx);
-
- iwl_init_sensitivity(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 */
- ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
- if (ret) {
- IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
- return ret;
- }
-
- return 0;
-}
-
void iwl_update_chain_flags(struct iwl_priv *priv)
{
struct iwl_rxon_context *ctx;
@@ -261,7 +97,8 @@ void iwl_update_chain_flags(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_rxon_chain) {
for_each_context(priv, ctx) {
priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- iwlcore_commit_rxon(priv, ctx);
+ if (ctx->active.rx_chain != ctx->staging.rx_chain)
+ iwlcore_commit_rxon(priv, ctx);
}
}
}
@@ -411,7 +248,8 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
return sizeof(*tx_beacon_cmd) + frame_size;
}
-static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
{
struct iwl_frame *frame;
unsigned int frame_size;
@@ -661,7 +499,7 @@ static void iwl_bg_beacon_update(struct work_struct *work)
priv->beacon_skb = beacon;
- iwl_send_beacon_cmd(priv);
+ iwlagn_send_beacon_cmd(priv);
out:
mutex_unlock(&priv->mutex);
}
@@ -1316,7 +1154,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
/* Re-enable all interrupts */
- /* only Re-enable if diabled by irq */
+ /* only Re-enable if disabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_enable_interrupts(priv);
@@ -1530,7 +1368,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
}
/* Re-enable all interrupts */
- /* only Re-enable if diabled by irq */
+ /* only Re-enable if disabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_enable_interrupts(priv);
}
@@ -2664,7 +2502,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
return pos;
}
- /* enable/disable bt channel announcement */
+ /* enable/disable bt channel inhibition */
priv->bt_ch_announce = iwlagn_bt_ch_announce;
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -2816,13 +2654,8 @@ static void iwl_alive_start(struct iwl_priv *priv)
/* After the ALIVE response, we can send host commands to the uCode */
set_bit(STATUS_ALIVE, &priv->status);
- if (priv->cfg->ops->lib->recover_from_tx_stall) {
- /* Enable timer to monitor the driver queues */
- mod_timer(&priv->monitor_recover,
- jiffies +
- msecs_to_jiffies(
- priv->cfg->base_params->monitor_recover_period));
- }
+ /* Enable watchdog to monitor the driver tx queues */
+ iwl_setup_watchdog(priv);
if (iwl_is_rfkill(priv))
return;
@@ -2879,6 +2712,8 @@ static void iwl_alive_start(struct iwl_priv *priv)
iwl_reset_run_time_calib(priv);
+ set_bit(STATUS_READY, &priv->status);
+
/* Configure the adapter for unassociated operation */
iwlcore_commit_rxon(priv, ctx);
@@ -2888,7 +2723,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
iwl_leds_init(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- set_bit(STATUS_READY, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
iwl_power_update_mode(priv, true);
@@ -2916,8 +2750,7 @@ static void __iwl_down(struct iwl_priv *priv)
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
* to prevent rearm timer */
- if (priv->cfg->ops->lib->recover_from_tx_stall)
- del_timer_sync(&priv->monitor_recover);
+ del_timer_sync(&priv->watchdog);
iwl_clear_ucode_stations(priv, NULL);
iwl_dealloc_bcast_stations(priv);
@@ -2978,7 +2811,8 @@ static void __iwl_down(struct iwl_priv *priv)
STATUS_EXIT_PENDING;
/* device going down, Stop using ICT table */
- iwl_disable_ict(priv);
+ if (priv->cfg->ops->lib->isr_ops.disable)
+ priv->cfg->ops->lib->isr_ops.disable(priv);
iwlagn_txq_ctx_stop(priv);
iwlagn_rxq_stop(priv);
@@ -3201,7 +3035,8 @@ static void iwl_bg_alive_start(struct work_struct *data)
return;
/* enable dram interrupt */
- iwl_reset_ict(priv);
+ if (priv->cfg->ops->lib->isr_ops.reset)
+ priv->cfg->ops->lib->isr_ops.reset(priv);
mutex_lock(&priv->mutex);
iwl_alive_start(priv);
@@ -3309,92 +3144,6 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-
-void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
- struct iwl_rxon_context *ctx;
- struct ieee80211_conf *conf = NULL;
- int ret = 0;
-
- if (!vif || !priv->is_open)
- return;
-
- ctx = iwl_rxon_ctx_from_vif(vif);
-
- if (vif->type == NL80211_IFTYPE_AP) {
- IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
- return;
- }
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- iwl_scan_cancel_timeout(priv, 200);
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv, ctx);
-
- ret = iwl_send_rxon_timing(priv, ctx);
- if (ret)
- IWL_WARN(priv, "RXON timing - "
- "Attempting to continue.\n");
-
- ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-
- iwl_set_rxon_ht(priv, &priv->current_ht_config);
-
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-
- ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
-
- IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
- vif->bss_conf.aid, vif->bss_conf.beacon_int);
-
- if (vif->bss_conf.use_short_preamble)
- ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
- else
- ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-
- if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.use_short_slot)
- ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
- else
- ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- }
-
- iwlcore_commit_rxon(priv, ctx);
-
- IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
- vif->bss_conf.aid, ctx->active.bssid_addr);
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- break;
- case NL80211_IFTYPE_ADHOC:
- iwl_send_beacon_cmd(priv);
- break;
- default:
- IWL_ERR(priv, "%s Should not be called in %d mode\n",
- __func__, vif->type);
- break;
- }
-
- /* the chain noise calibration will enabled PM upon completion
- * If chain noise has already been run, then we need to enable
- * power management here */
- if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
- iwl_power_update_mode(priv, false);
-
- /* Enable Rx differential gain and sensitivity calibrations */
- iwl_chain_noise_reset(priv);
- priv->start_calib = 1;
-
-}
-
/*****************************************************************************
*
* mac80211 entry point functions
@@ -3420,7 +3169,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_NEED_DTIM_PERIOD |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS;
if (!priv->cfg->base_params->broken_powersave)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
@@ -3474,7 +3224,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
}
-static int iwl_mac_start(struct ieee80211_hw *hw)
+int iwlagn_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
@@ -3515,7 +3265,7 @@ out:
return 0;
}
-static void iwl_mac_stop(struct ieee80211_hw *hw)
+void iwlagn_mac_stop(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -3530,14 +3280,15 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue);
- /* enable interrupts again in order to receive rfkill changes */
+ /* User space software may expect getting rfkill changes
+ * even if interface is down */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl_enable_interrupts(priv);
+ iwl_enable_rfkill_int(priv);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
@@ -3553,73 +3304,12 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
- struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
- int ret = 0;
-
- lockdep_assert_held(&priv->mutex);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- /* The following should be done only at AP bring up */
- if (!iwl_is_associated_ctx(ctx)) {
-
- /* RXON - unassoc (to set timing command) */
- ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv, ctx);
-
- /* RXON Timing */
- ret = iwl_send_rxon_timing(priv, ctx);
- if (ret)
- IWL_WARN(priv, "RXON timing failed - "
- "Attempting to continue.\n");
-
- /* AP has all antennas */
- priv->chain_noise_data.active_chains =
- priv->hw_params.valid_rx_ant;
- iwl_set_rxon_ht(priv, &priv->current_ht_config);
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-
- ctx->staging.assoc_id = 0;
-
- if (vif->bss_conf.use_short_preamble)
- ctx->staging.flags |=
- RXON_FLG_SHORT_PREAMBLE_MSK;
- else
- ctx->staging.flags &=
- ~RXON_FLG_SHORT_PREAMBLE_MSK;
-
- if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.use_short_slot)
- ctx->staging.flags |=
- RXON_FLG_SHORT_SLOT_MSK;
- else
- ctx->staging.flags &=
- ~RXON_FLG_SHORT_SLOT_MSK;
- }
- /* need to send beacon cmd before committing assoc RXON! */
- iwl_send_beacon_cmd(priv);
- /* restore RXON assoc */
- ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv, ctx);
- }
- 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 void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_key_conf *keyconf,
- struct ieee80211_sta *sta,
- u32 iv32, u16 *phase1key)
+void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta,
+ u32 iv32, u16 *phase1key)
{
-
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3631,10 +3321,9 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
{
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3701,10 +3390,10 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_priv *priv = hw->priv;
int ret = -EINVAL;
@@ -3785,39 +3474,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
return ret;
}
-static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta)
-{
- struct iwl_priv *priv = hw->priv;
- struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- int sta_id;
-
- switch (cmd) {
- case STA_NOTIFY_SLEEP:
- WARN_ON(!sta_priv->client);
- sta_priv->asleep = true;
- if (atomic_read(&sta_priv->pending_frames) > 0)
- ieee80211_sta_block_awake(hw, sta, true);
- break;
- case STA_NOTIFY_AWAKE:
- WARN_ON(!sta_priv->client);
- if (!sta_priv->asleep)
- break;
- sta_priv->asleep = false;
- sta_id = iwl_sta_id(sta);
- if (sta_id != IWL_INVALID_STATION)
- iwl_sta_modify_ps_wake(priv, sta_id);
- break;
- default:
- break;
- }
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct iwl_priv *priv = hw->priv;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
@@ -3858,8 +3517,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
return 0;
}
-static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
- struct ieee80211_channel_switch *ch_switch)
+void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_channel_switch *ch_switch)
{
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
@@ -3956,10 +3615,10 @@ out_exit:
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static void iwlagn_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags,
- u64 multicast)
+void iwlagn_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast)
{
struct iwl_priv *priv = hw->priv;
__le32 filter_or = 0, filter_nand = 0;
@@ -3976,7 +3635,8 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
changed_flags, *total_flags);
CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
- CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
+ /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+ CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
#undef CHK
@@ -3986,7 +3646,11 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
for_each_context(priv, ctx) {
ctx->staging.filter_flags &= ~filter_nand;
ctx->staging.filter_flags |= filter_or;
- iwlcore_commit_rxon(priv, ctx);
+
+ /*
+ * Not committing directly because hardware can perform a scan,
+ * but we'll eventually commit the filter flags change anyway.
+ */
}
mutex_unlock(&priv->mutex);
@@ -4001,7 +3665,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
-static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
+void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct iwl_priv *priv = hw->priv;
@@ -4074,12 +3738,9 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
priv->ucode_trace.data = (unsigned long)priv;
priv->ucode_trace.function = iwl_bg_ucode_trace;
- if (priv->cfg->ops->lib->recover_from_tx_stall) {
- init_timer(&priv->monitor_recover);
- priv->monitor_recover.data = (unsigned long)priv;
- priv->monitor_recover.function =
- priv->cfg->ops->lib->recover_from_tx_stall;
- }
+ init_timer(&priv->watchdog);
+ priv->watchdog.data = (unsigned long)priv;
+ priv->watchdog.function = iwl_bg_watchdog;
if (!priv->cfg->base_params->use_isr_legacy)
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
@@ -4172,13 +3833,13 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
priv->bt_duration = BT_DURATION_LIMIT_DEF;
priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
- priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF;
}
/* Set the tx_power_user_lmt to the lowest power level
* this value will get overwritten by channel max power avg
* from eeprom */
priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
+ priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN;
ret = iwl_init_channel_map(priv);
if (ret) {
@@ -4209,28 +3870,30 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
kfree(priv->scan_cmd);
}
-static struct ieee80211_ops iwl_hw_ops = {
- .tx = iwl_mac_tx,
- .start = iwl_mac_start,
- .stop = iwl_mac_stop,
+#ifdef CONFIG_IWL5000
+struct ieee80211_ops iwlagn_hw_ops = {
+ .tx = iwlagn_mac_tx,
+ .start = iwlagn_mac_start,
+ .stop = iwlagn_mac_stop,
.add_interface = iwl_mac_add_interface,
.remove_interface = iwl_mac_remove_interface,
- .config = iwl_mac_config,
+ .change_interface = iwl_mac_change_interface,
+ .config = iwlagn_mac_config,
.configure_filter = iwlagn_configure_filter,
- .set_key = iwl_mac_set_key,
- .update_tkip_key = iwl_mac_update_tkip_key,
+ .set_key = iwlagn_mac_set_key,
+ .update_tkip_key = iwlagn_mac_update_tkip_key,
.conf_tx = iwl_mac_conf_tx,
- .reset_tsf = iwl_mac_reset_tsf,
- .bss_info_changed = iwl_bss_info_changed,
- .ampdu_action = iwl_mac_ampdu_action,
+ .bss_info_changed = iwlagn_bss_info_changed,
+ .ampdu_action = iwlagn_mac_ampdu_action,
.hw_scan = iwl_mac_hw_scan,
- .sta_notify = iwl_mac_sta_notify,
+ .sta_notify = iwlagn_mac_sta_notify,
.sta_add = iwlagn_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
- .channel_switch = iwl_mac_channel_switch,
- .flush = iwl_mac_flush,
+ .channel_switch = iwlagn_mac_channel_switch,
+ .flush = iwlagn_mac_flush,
.tx_last_beacon = iwl_mac_tx_last_beacon,
};
+#endif
static void iwl_hw_detect(struct iwl_priv *priv)
{
@@ -4298,10 +3961,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (cfg->mod_params->disable_hw_scan) {
dev_printk(KERN_DEBUG, &(pdev->dev),
"sw scan support is deprecated\n");
- iwl_hw_ops.hw_scan = NULL;
+#ifdef CONFIG_IWL5000
+ iwlagn_hw_ops.hw_scan = NULL;
+#endif
+#ifdef CONFIG_IWL4965
+ iwl4965_hw_ops.hw_scan = NULL;
+#endif
}
- hw = iwl_alloc_all(cfg, &iwl_hw_ops);
+ hw = iwl_alloc_all(cfg);
if (!hw) {
err = -ENOMEM;
goto out;
@@ -4333,6 +4001,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
BIT(NL80211_IFTYPE_ADHOC);
priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
BIT(NL80211_IFTYPE_STATION);
+ priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
@@ -4368,8 +4037,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
(iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
true : false;
- /* enable/disable bt channel announcement */
+ /* enable/disable bt channel inhibition */
priv->bt_ch_announce = iwlagn_bt_ch_announce;
+ IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
+ (priv->bt_ch_announce) ? "On" : "Off");
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
@@ -4461,6 +4132,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_free_eeprom;
+ err = iwl_eeprom_check_sku(priv);
+ if (err)
+ goto out_free_eeprom;
+
/* extract MAC Address */
iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
@@ -4500,8 +4175,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_enable_msi(priv->pci_dev);
- iwl_alloc_isr_ict(priv);
- err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
+ if (priv->cfg->ops->lib->isr_ops.alloc)
+ priv->cfg->ops->lib->isr_ops.alloc(priv);
+
+ err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -4515,14 +4192,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* 8. Enable interrupts and read RFKILL state
*********************************************/
- /* enable interrupts if needed: hw bug w/a */
+ /* enable rfkill interrupt: hw bug w/a */
pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
}
- iwl_enable_interrupts(priv);
+ iwl_enable_rfkill_int(priv);
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -4548,7 +4225,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
free_irq(priv->pci_dev->irq, priv);
- iwl_free_isr_ict(priv);
+ if (priv->cfg->ops->lib->isr_ops.free)
+ priv->cfg->ops->lib->isr_ops.free(priv);
out_disable_msi:
pci_disable_msi(priv->pci_dev);
iwl_uninit_drv(priv);
@@ -4643,7 +4321,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_uninit_drv(priv);
- iwl_free_isr_ict(priv);
+ if (priv->cfg->ops->lib->isr_ops.free)
+ priv->cfg->ops->lib->isr_ops.free(priv);
dev_kfree_skb(priv->beacon_skb);
@@ -4734,51 +4413,32 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
-/* 6x00 Series Gen2a */
- {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
-
-/* 6x00 Series Gen2b */
- {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
- {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
- {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
- {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
- {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
- {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
+/* 6x05 Series */
+ {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
+
+/* 6x30 Series */
+ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
/* 6x50 WiFi/WiMax Series */
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -4788,13 +4448,13 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
-/* 6x50 WiFi/WiMax Series Gen2 */
- {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6050g2_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6050g2_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6050g2_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6050g2_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6050g2_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6050g2_bgn_cfg)},
+/* 6150 WiFi/WiMax Series */
+ {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6150_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6150_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6150_bgn_cfg)},
/* 1000 Series WiFi */
{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
@@ -4812,10 +4472,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
/* 100 Series WiFi */
{IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
{IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
{IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
- {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
- {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)},
+ {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
/* 130 Series WiFi */
{IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
@@ -4836,10 +4497,7 @@ static struct pci_driver iwl_driver = {
.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
+ .driver.pm = IWL_PM_OPS,
};
static int __init iwl_init(void)
@@ -4925,6 +4583,6 @@ module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO);
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (defualt: 0 dB)");
-module_param_named(bt_ch_announce, iwlagn_bt_ch_announce, bool, S_IRUGO);
-MODULE_PARM_DESC(bt_ch_announce,
- "Enable BT channel announcement mode (default: enable)");
+module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO);
+MODULE_PARM_DESC(bt_ch_inhibition,
+ "Disable BT channel inhibition (default: enable)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index f525d55f2c0f..da303585f801 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -74,22 +74,22 @@ extern struct iwl_cfg iwl5100_bgn_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
extern struct iwl_cfg iwl5150_abg_cfg;
-extern struct iwl_cfg iwl6000g2a_2agn_cfg;
-extern struct iwl_cfg iwl6000g2a_2abg_cfg;
-extern struct iwl_cfg iwl6000g2a_2bg_cfg;
-extern struct iwl_cfg iwl6000g2b_bgn_cfg;
-extern struct iwl_cfg iwl6000g2b_bg_cfg;
-extern struct iwl_cfg iwl6000g2b_2agn_cfg;
-extern struct iwl_cfg iwl6000g2b_2abg_cfg;
-extern struct iwl_cfg iwl6000g2b_2bgn_cfg;
-extern struct iwl_cfg iwl6000g2b_2bg_cfg;
+extern struct iwl_cfg iwl6005_2agn_cfg;
+extern struct iwl_cfg iwl6005_2abg_cfg;
+extern struct iwl_cfg iwl6005_2bg_cfg;
+extern struct iwl_cfg iwl1030_bgn_cfg;
+extern struct iwl_cfg iwl1030_bg_cfg;
+extern struct iwl_cfg iwl6030_2agn_cfg;
+extern struct iwl_cfg iwl6030_2abg_cfg;
+extern struct iwl_cfg iwl6030_2bgn_cfg;
+extern struct iwl_cfg iwl6030_2bg_cfg;
extern struct iwl_cfg iwl6000i_2agn_cfg;
extern struct iwl_cfg iwl6000i_2abg_cfg;
extern struct iwl_cfg iwl6000i_2bg_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl6050g2_bgn_cfg;
+extern struct iwl_cfg iwl6150_bgn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
extern struct iwl_cfg iwl1000_bg_cfg;
extern struct iwl_cfg iwl100_bgn_cfg;
@@ -102,6 +102,9 @@ extern struct iwl_hcmd_ops iwlagn_hcmd;
extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
+extern struct ieee80211_ops iwlagn_hw_ops;
+extern struct ieee80211_ops iwl4965_hw_ops;
+
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
int iwl_alloc_isr_ict(struct iwl_priv *priv);
@@ -132,6 +135,11 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
/* RXON */
int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed);
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes);
/* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
@@ -249,6 +257,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
struct iwl_rxon_context *ctx);
int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
/* bt coex */
void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
@@ -292,9 +301,12 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
int tid, u16 ssn);
int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
int tid);
-void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
int iwl_update_bcast_stations(struct iwl_priv *priv);
+void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta);
/* rate */
static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
@@ -318,4 +330,31 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
+/* mac80211 handlers (for 4965) */
+int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+int iwlagn_mac_start(struct ieee80211_hw *hw);
+void iwlagn_mac_stop(struct ieee80211_hw *hw);
+void iwlagn_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast);
+int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta,
+ u32 iv32, u16 *phase1key);
+int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_channel_switch *ch_switch);
+void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
+
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 424801abc80e..f893d4a6aa87 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2022,6 +2022,9 @@ struct iwl_compressed_ba_resp {
__le64 bitmap;
__le16 scd_flow;
__le16 scd_ssn;
+ /* following only for 5000 series and up */
+ u8 txed; /* number of frames sent */
+ u8 txed_2_done; /* number of frames acked */
} __packed;
/*
@@ -2407,9 +2410,9 @@ struct iwl_link_quality_cmd {
#define BT_FRAG_THRESHOLD_MAX 0
#define BT_FRAG_THRESHOLD_MIN 0
-#define BT_AGG_THRESHOLD_DEF 0
-#define BT_AGG_THRESHOLD_MAX 0
-#define BT_AGG_THRESHOLD_MIN 0
+#define BT_AGG_THRESHOLD_DEF 1200
+#define BT_AGG_THRESHOLD_MAX 8000
+#define BT_AGG_THRESHOLD_MIN 400
/*
* REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
@@ -2436,8 +2439,9 @@ struct iwl_bt_cmd {
#define IWLAGN_BT_FLAG_COEX_MODE_3W 2
#define IWLAGN_BT_FLAG_COEX_MODE_4W 3
-#define IWLAGN_BT_FLAG_UCODE_DEFAULT BIT(6)
-#define IWLAGN_BT_FLAG_NOCOEX_NOTIF BIT(7)
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT BIT(6)
+/* Disable Sync PSPoll on SCO/eSCO */
+#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE BIT(7)
#define IWLAGN_BT_PRIO_BOOST_MAX 0xFF
#define IWLAGN_BT_PRIO_BOOST_MIN 0x00
@@ -2447,8 +2451,9 @@ struct iwl_bt_cmd {
#define IWLAGN_BT3_T7_DEFAULT 1
-#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffffffff)
-#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO cpu_to_le32(0xffffffff)
#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
@@ -2664,9 +2669,16 @@ struct iwl_spectrum_notification {
#define IWL_POWER_VEC_SIZE 5
#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_SAVE_ENA_MSK cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK cpu_to_le16(BIT(1))
#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2))
#define IWL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3))
#define IWL_POWER_FAST_PD cpu_to_le16(BIT(4))
+#define IWL_POWER_BEACON_FILTERING cpu_to_le16(BIT(5))
+#define IWL_POWER_SHADOW_REG_ENA cpu_to_le16(BIT(6))
+#define IWL_POWER_CT_KILL_SET cpu_to_le16(BIT(7))
+#define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8))
+#define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9))
struct iwl3945_powertable_cmd {
__le16 flags;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 25fb3912342c..efbde1f1a8bf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -77,15 +77,15 @@ EXPORT_SYMBOL(iwl_bcast_addr);
/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
- struct ieee80211_ops *hw_ops)
+struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
{
struct iwl_priv *priv;
-
/* mac80211 allocates memory for this device instance, including
* space for this driver's private structure */
- struct ieee80211_hw *hw =
- ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops);
+ struct ieee80211_hw *hw;
+
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv),
+ cfg->ops->ieee80211_ops);
if (hw == NULL) {
pr_err("%s: Can not allocate network device\n",
cfg->name);
@@ -100,35 +100,6 @@ out:
}
EXPORT_SYMBOL(iwl_alloc_all);
-/*
- * QoS support
-*/
-static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- if (!ctx->is_active)
- return;
-
- ctx->qos_data.def_qos_parm.qos_flags = 0;
-
- if (ctx->qos_data.qos_active)
- ctx->qos_data.def_qos_parm.qos_flags |=
- QOS_PARAM_FLG_UPDATE_EDCA_MSK;
-
- if (ctx->ht.enabled)
- ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
-
- IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
- ctx->qos_data.qos_active,
- ctx->qos_data.def_qos_parm.qos_flags);
-
- iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
- sizeof(struct iwl_qosparam_cmd),
- &ctx->qos_data.def_qos_parm, NULL);
-}
-
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@@ -317,40 +288,6 @@ void iwlcore_free_geos(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_free_geos);
-/*
- * iwlcore_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
- * function.
- */
-void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
- struct ieee80211_tx_info *info,
- __le16 fc, __le32 *tx_flags)
-{
- if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- *tx_flags |= TX_CMD_FLG_RTS_MSK;
- *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
-
- if (!ieee80211_is_mgmt(fc))
- return;
-
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
- *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- *tx_flags |= TX_CMD_FLG_CTS_MSK;
- break;
- }
- } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- *tx_flags |= TX_CMD_FLG_CTS_MSK;
- *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
- }
-}
-EXPORT_SYMBOL(iwlcore_tx_cmd_protection);
-
-
static bool iwl_is_channel_extension(struct iwl_priv *priv,
enum ieee80211_band band,
u16 channel, u8 extension_chan_offset)
@@ -1020,6 +957,22 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
/* Cancel currently queued command. */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
+ if (priv->cfg->internal_wimax_coex &&
+ (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
+ APMS_CLK_VAL_MRB_FUNC_MODE) ||
+ (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
+ APMG_PS_CTRL_VAL_RESET_REQ))) {
+ 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);
+ IWL_ERR(priv, "RF is used by WiMAX\n");
+ return;
+ }
+
IWL_ERR(priv, "Loaded firmware version: %s\n",
priv->hw->wiphy->fw_version);
@@ -1206,8 +1159,16 @@ EXPORT_SYMBOL(iwl_apm_init);
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
- int ret = 0;
- s8 prev_tx_power = priv->tx_power_user_lmt;
+ int ret;
+ s8 prev_tx_power;
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (priv->tx_power_user_lmt == tx_power && !force)
+ return 0;
+
+ if (!priv->cfg->ops->lib->send_tx_power)
+ return -EOPNOTSUPP;
if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
IWL_WARN(priv,
@@ -1224,93 +1185,29 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
return -EINVAL;
}
- if (priv->tx_power_user_lmt != tx_power)
- force = true;
+ if (!iwl_is_ready_rf(priv))
+ return -EIO;
- /* if nic is not up don't send command */
- if (iwl_is_ready_rf(priv)) {
- priv->tx_power_user_lmt = tx_power;
- if (force && priv->cfg->ops->lib->send_tx_power)
- ret = priv->cfg->ops->lib->send_tx_power(priv);
- else if (!priv->cfg->ops->lib->send_tx_power)
- ret = -EOPNOTSUPP;
- /*
- * if fail to set tx_power, restore the orig. tx power
- */
- if (ret)
- priv->tx_power_user_lmt = prev_tx_power;
+ /* scan complete use tx_power_next, need to be updated */
+ priv->tx_power_next = tx_power;
+ if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
+ IWL_DEBUG_INFO(priv, "Deferring tx power set while scanning\n");
+ return 0;
}
- /*
- * Even this is an async host command, the command
- * will always report success from uCode
- * So once driver can placing the command into the queue
- * successfully, driver can use priv->tx_power_user_lmt
- * to reflect the current tx power
- */
- return ret;
-}
-EXPORT_SYMBOL(iwl_set_tx_power);
+ prev_tx_power = priv->tx_power_user_lmt;
+ priv->tx_power_user_lmt = tx_power;
-irqreturn_t iwl_isr_legacy(int irq, void *data)
-{
- struct iwl_priv *priv = data;
- u32 inta, inta_mask;
- u32 inta_fh;
- unsigned long flags;
- if (!priv)
- return IRQ_NONE;
-
- spin_lock_irqsave(&priv->lock, flags);
+ ret = priv->cfg->ops->lib->send_tx_power(priv);
- /* 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(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n");
- goto none;
+ /* if fail to set tx_power, restore the orig. tx power */
+ if (ret) {
+ priv->tx_power_user_lmt = prev_tx_power;
+ priv->tx_power_next = prev_tx_power;
}
-
- if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
- /* Hardware disappeared. It might have already raised
- * an interrupt */
- IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
- goto unplugged;
- }
-
- IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
- inta, inta_mask, inta_fh);
-
- inta &= ~CSR_INT_BIT_SCD;
-
- /* iwl_irq_tasklet() will service interrupts and re-enable them */
- if (likely(inta || inta_fh))
- tasklet_schedule(&priv->irq_tasklet);
-
- unplugged:
- spin_unlock_irqrestore(&priv->lock, flags);
- return IRQ_HANDLED;
-
- none:
- /* re-enable interrupts here since we don't have anything to service. */
- /* only Re-enable if diabled by irq */
- if (test_bit(STATUS_INT_ENABLED, &priv->status))
- iwl_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
- return IRQ_NONE;
+ return ret;
}
-EXPORT_SYMBOL(iwl_isr_legacy);
+EXPORT_SYMBOL(iwl_set_tx_power);
void iwl_send_bt_config(struct iwl_priv *priv)
{
@@ -1326,6 +1223,7 @@ void iwl_send_bt_config(struct iwl_priv *priv)
else
bt_cmd.flags = BT_COEX_ENABLE;
+ priv->bt_enable_flag = bt_cmd.flags;
IWL_DEBUG_INFO(priv, "BT coex %s\n",
(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
@@ -1452,318 +1350,51 @@ int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon);
-static void iwl_ht_conf(struct iwl_priv *priv,
- struct ieee80211_vif *vif)
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
- struct iwl_ht_config *ht_conf = &priv->current_ht_config;
- struct ieee80211_sta *sta;
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
- IWL_DEBUG_MAC80211(priv, "enter:\n");
-
- if (!ctx->ht.enabled)
- return;
-
- ctx->ht.protection =
- bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
- ctx->ht.non_gf_sta_present =
- !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
- ht_conf->single_chain_sufficient = false;
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, bss_conf->bssid);
- if (sta) {
- struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- int maxstreams;
-
- maxstreams = (ht_cap->mcs.tx_params &
- IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
- >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
- maxstreams += 1;
-
- if ((ht_cap->mcs.rx_mask[1] == 0) &&
- (ht_cap->mcs.rx_mask[2] == 0))
- ht_conf->single_chain_sufficient = true;
- if (maxstreams <= 1)
- ht_conf->single_chain_sufficient = true;
- } else {
- /*
- * If at all, this can only happen through a race
- * when the AP disconnects us while we're still
- * setting up the connection, in that case mac80211
- * will soon tell us about that.
- */
- ht_conf->single_chain_sufficient = true;
- }
- rcu_read_unlock();
- break;
- case NL80211_IFTYPE_ADHOC:
- ht_conf->single_chain_sufficient = true;
- break;
- default:
- break;
- }
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-}
+ iwl_connection_init_rx_config(priv, ctx);
-static inline void iwl_set_no_assoc(struct iwl_priv *priv,
- struct ieee80211_vif *vif)
-{
- struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- iwl_led_disassociate(priv);
- /*
- * inform the ucode that there is no longer an
- * association and that no more packets should be
- * sent
- */
- ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- ctx->staging.assoc_id = 0;
- iwlcore_commit_rxon(priv, ctx);
+ return iwlcore_commit_rxon(priv, ctx);
}
-static void iwlcore_beacon_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int iwl_setup_interface(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- __le64 timestamp;
- struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
-
- if (!skb)
- return;
-
- IWL_DEBUG_ASSOC(priv, "enter\n");
+ struct ieee80211_vif *vif = ctx->vif;
+ int err;
lockdep_assert_held(&priv->mutex);
- if (!priv->beacon_ctx) {
- IWL_ERR(priv, "update beacon but no beacon context!\n");
- dev_kfree_skb(skb);
- return;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->beacon_skb)
- dev_kfree_skb(priv->beacon_skb);
-
- priv->beacon_skb = skb;
-
- timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp);
-
- IWL_DEBUG_ASSOC(priv, "leave\n");
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return;
- }
-
- priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif);
-}
-
-void iwl_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes)
-{
- struct iwl_priv *priv = hw->priv;
- struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
- int ret;
-
- IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
-
- if (!iwl_is_alive(priv))
- return;
-
- mutex_lock(&priv->mutex);
-
- if (changes & BSS_CHANGED_QOS) {
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- ctx->qos_data.qos_active = bss_conf->qos;
- iwl_update_qos(priv, ctx);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
-
- if (changes & BSS_CHANGED_BEACON_ENABLED) {
- /*
- * the add_interface code must make sure we only ever
- * have a single interface that could be beaconing at
- * any time.
- */
- if (vif->bss_conf.enable_beacon)
- priv->beacon_ctx = ctx;
- else
- priv->beacon_ctx = NULL;
- }
-
- if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
- dev_kfree_skb(priv->beacon_skb);
- priv->beacon_skb = ieee80211_beacon_get(hw, vif);
- }
-
- if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
- iwl_send_rxon_timing(priv, ctx);
-
- if (changes & BSS_CHANGED_BSSID) {
- IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
-
- /*
- * If there is currently a HW scan going on in the
- * background then we need to cancel it else the RXON
- * below/in post_associate will fail.
- */
- if (iwl_scan_cancel_timeout(priv, 100)) {
- IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
- IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
- /* mac80211 only sets assoc when in STATION mode */
- if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
- memcpy(ctx->staging.bssid_addr,
- bss_conf->bssid, ETH_ALEN);
-
- /* currently needed in a few places */
- memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
- } else {
- ctx->staging.filter_flags &=
- ~RXON_FILTER_ASSOC_MSK;
- }
-
- }
-
/*
- * This needs to be after setting the BSSID in case
- * mac80211 decides to do both changes at once because
- * it will invoke post_associate.
+ * This variable will be correct only when there's just
+ * a single context, but all code using it is for hardware
+ * that supports only one context.
*/
- if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
- iwlcore_beacon_update(hw, vif);
-
- if (changes & BSS_CHANGED_ERP_PREAMBLE) {
- IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
- bss_conf->use_short_preamble);
- if (bss_conf->use_short_preamble)
- ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
- else
- ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
- }
-
- if (changes & BSS_CHANGED_ERP_CTS_PROT) {
- IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
- if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
- ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
- else
- ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
- if (bss_conf->use_cts_prot)
- ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
- else
- ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
- }
-
- if (changes & BSS_CHANGED_BASIC_RATES) {
- /* XXX use this information
- *
- * To do that, remove code from iwl_set_rate() and put something
- * like this here:
- *
- if (A-band)
- ctx->staging.ofdm_basic_rates =
- bss_conf->basic_rates;
- else
- ctx->staging.ofdm_basic_rates =
- bss_conf->basic_rates >> 4;
- ctx->staging.cck_basic_rates =
- bss_conf->basic_rates & 0xF;
- */
- }
-
- if (changes & BSS_CHANGED_HT) {
- iwl_ht_conf(priv, vif);
-
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- }
-
- if (changes & BSS_CHANGED_ASSOC) {
- IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
- if (bss_conf->assoc) {
- priv->timestamp = bss_conf->timestamp;
-
- iwl_led_associate(priv);
-
- if (!iwl_is_rfkill(priv))
- priv->cfg->ops->lib->post_associate(priv, vif);
- } else
- iwl_set_no_assoc(priv, vif);
- }
-
- if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
- IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
- changes);
- ret = iwl_send_rxon_assoc(priv, ctx);
- if (!ret) {
- /* Sync active_rxon with latest change. */
- memcpy((void *)&ctx->active,
- &ctx->staging,
- sizeof(struct iwl_rxon_cmd));
- }
- }
+ priv->iw_mode = vif->type;
- if (changes & BSS_CHANGED_BEACON_ENABLED) {
- if (vif->bss_conf.enable_beacon) {
- memcpy(ctx->staging.bssid_addr,
- bss_conf->bssid, ETH_ALEN);
- memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
- iwl_led_associate(priv);
- iwlcore_config_ap(priv, vif);
- } else
- iwl_set_no_assoc(priv, vif);
- }
+ ctx->is_active = true;
- if (changes & BSS_CHANGED_IBSS) {
- ret = priv->cfg->ops->lib->manage_ibss_station(priv, vif,
- bss_conf->ibss_joined);
- if (ret)
- IWL_ERR(priv, "failed to %s IBSS station %pM\n",
- bss_conf->ibss_joined ? "add" : "remove",
- bss_conf->bssid);
+ err = iwl_set_mode(priv, ctx);
+ if (err) {
+ if (!ctx->always_active)
+ ctx->is_active = false;
+ return err;
}
- if (changes & BSS_CHANGED_IDLE &&
- priv->cfg->ops->hcmd->set_pan_params) {
- if (priv->cfg->ops->hcmd->set_pan_params(priv))
- IWL_ERR(priv, "failed to update PAN params\n");
+ if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+ vif->type == NL80211_IFTYPE_ADHOC) {
+ /*
+ * pretend to have high BT traffic as long as we
+ * are operating in IBSS mode, as this will cause
+ * the rate scaling etc. to behave as intended.
+ */
+ priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
}
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-EXPORT_SYMBOL(iwl_bss_info_changed);
-
-static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
- struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
- iwl_connection_init_rx_config(priv, ctx);
-
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-
- return iwlcore_commit_rxon(priv, ctx);
+ return 0;
}
int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
@@ -1771,7 +1402,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
struct iwl_rxon_context *tmp, *ctx = NULL;
- int err = 0;
+ int err;
IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
vif->type, vif->addr);
@@ -1813,36 +1444,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
vif_priv->ctx = ctx;
ctx->vif = vif;
- /*
- * This variable will be correct only when there's just
- * a single context, but all code using it is for hardware
- * that supports only one context.
- */
- priv->iw_mode = vif->type;
-
- ctx->is_active = true;
- err = iwl_set_mode(priv, vif);
- if (err) {
- if (!ctx->always_active)
- ctx->is_active = false;
- goto out_err;
- }
-
- if (priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist &&
- vif->type == NL80211_IFTYPE_ADHOC) {
- /*
- * pretend to have high BT traffic as long as we
- * are operating in IBSS mode, as this will cause
- * the rate scaling etc. to behave as intended.
- */
- priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
- }
-
- goto out;
+ err = iwl_setup_interface(priv, ctx);
+ if (!err)
+ goto out;
- out_err:
ctx->vif = NULL;
priv->iw_mode = NL80211_IFTYPE_STATION;
out:
@@ -1853,27 +1459,24 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
}
EXPORT_SYMBOL(iwl_mac_add_interface);
-void iwl_mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static void iwl_teardown_interface(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ bool mode_change)
{
- struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- mutex_lock(&priv->mutex);
-
- WARN_ON(ctx->vif != vif);
- ctx->vif = NULL;
+ lockdep_assert_held(&priv->mutex);
if (priv->scan_vif == vif) {
iwl_scan_cancel_timeout(priv, 200);
iwl_force_scan_end(priv);
}
- iwl_set_mode(priv, vif);
- if (!ctx->always_active)
- ctx->is_active = false;
+ if (!mode_change) {
+ iwl_set_mode(priv, ctx);
+ if (!ctx->always_active)
+ ctx->is_active = false;
+ }
/*
* When removing the IBSS interface, overwrite the
@@ -1883,211 +1486,31 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
* both values are the same and zero.
*/
if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->bt_traffic_load = priv->notif_bt_traffic_load;
-
- memset(priv->bssid, 0, ETH_ALEN);
- mutex_unlock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
-EXPORT_SYMBOL(iwl_mac_remove_interface);
-
-/**
- * iwl_mac_config - mac80211 config callback
- */
-int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct iwl_priv *priv = hw->priv;
- const struct iwl_channel_info *ch_info;
- struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_channel *channel = conf->channel;
- struct iwl_ht_config *ht_conf = &priv->current_ht_config;
- struct iwl_rxon_context *ctx;
- unsigned long flags = 0;
- int ret = 0;
- u16 ch;
- int scan_active = 0;
-
- mutex_lock(&priv->mutex);
-
- IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
- channel->hw_value, changed);
-
- if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
- test_bit(STATUS_SCANNING, &priv->status))) {
- scan_active = 1;
- IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
- }
-
- if (changed & (IEEE80211_CONF_CHANGE_SMPS |
- IEEE80211_CONF_CHANGE_CHANNEL)) {
- /* mac80211 uses static for non-HT which is what we want */
- priv->current_ht_config.smps = conf->smps_mode;
-
- /*
- * Recalculate chain counts.
- *
- * If monitor mode is enabled then mac80211 will
- * set up the SM PS mode to OFF if an HT channel is
- * configured.
- */
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- for_each_context(priv, ctx)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- }
-
- /* during scanning mac80211 will delay channel setting until
- * scan finish with changed = 0
- */
- if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
- if (scan_active)
- goto set_ch_out;
-
- ch = channel->hw_value;
- ch_info = iwl_get_channel_info(priv, channel->band, ch);
- if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
- ret = -EINVAL;
- goto set_ch_out;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- for_each_context(priv, ctx) {
- /* Configure HT40 channels */
- ctx->ht.enabled = conf_is_ht(conf);
- if (ctx->ht.enabled) {
- if (conf_is_ht40_minus(conf)) {
- ctx->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- ctx->ht.is_40mhz = true;
- } else if (conf_is_ht40_plus(conf)) {
- ctx->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- ctx->ht.is_40mhz = true;
- } else {
- ctx->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_NONE;
- ctx->ht.is_40mhz = false;
- }
- } else
- ctx->ht.is_40mhz = false;
-
- /*
- * Default to no protection. Protection mode will
- * later be set from BSS config in iwl_ht_conf
- */
- ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
-
- /* if we are switching from ht to 2.4 clear flags
- * from any ht related info since 2.4 does not
- * support ht */
- if ((le16_to_cpu(ctx->staging.channel) != ch))
- ctx->staging.flags = 0;
-
- iwl_set_rxon_channel(priv, channel, ctx);
- iwl_set_rxon_ht(priv, ht_conf);
-
- iwl_set_flags_for_band(priv, ctx, channel->band,
- ctx->vif);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->cfg->ops->lib->update_bcast_stations)
- ret = priv->cfg->ops->lib->update_bcast_stations(priv);
-
- set_ch_out:
- /* The list of supported rates and rate mask can be different
- * for each band; since the band may have changed, reset
- * the rate mask to what mac80211 lists */
- iwl_set_rate(priv);
- }
-
- if (changed & (IEEE80211_CONF_CHANGE_PS |
- IEEE80211_CONF_CHANGE_IDLE)) {
- ret = iwl_power_update_mode(priv, false);
- if (ret)
- IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
- }
-
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
- IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
- priv->tx_power_user_lmt, conf->power_level);
-
- iwl_set_tx_power(priv, conf->power_level, false);
- }
-
- if (!iwl_is_ready(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- goto out;
- }
-
- if (scan_active)
- goto out;
-
- for_each_context(priv, ctx) {
- if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
- iwlcore_commit_rxon(priv, ctx);
- else
- IWL_DEBUG_INFO(priv,
- "Not re-sending same RXON configuration.\n");
- }
-
-out:
- IWL_DEBUG_MAC80211(priv, "leave\n");
- mutex_unlock(&priv->mutex);
- return ret;
+ priv->bt_traffic_load = priv->last_bt_traffic_load;
}
-EXPORT_SYMBOL(iwl_mac_config);
-void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- /* IBSS can only be the IWL_RXON_CTX_BSS context */
- struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
- mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "enter\n");
- spin_lock_irqsave(&priv->lock, flags);
- memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
- spin_unlock_irqrestore(&priv->lock, flags);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* new association get rid of ibss beacon skb */
- if (priv->beacon_skb)
- dev_kfree_skb(priv->beacon_skb);
-
- priv->beacon_skb = NULL;
-
- priv->timestamp = 0;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- iwl_scan_cancel_timeout(priv, 100);
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- mutex_unlock(&priv->mutex);
- return;
- }
+ mutex_lock(&priv->mutex);
- /* we are restarting association process
- * clear RXON_FILTER_ASSOC_MSK bit
- */
- ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv, ctx);
+ WARN_ON(ctx->vif != vif);
+ ctx->vif = NULL;
- iwl_set_rate(priv);
+ iwl_teardown_interface(priv, vif, false);
+ memset(priv->bssid, 0, ETH_ALEN);
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
+
}
-EXPORT_SYMBOL(iwl_mac_reset_tsf);
+EXPORT_SYMBOL(iwl_mac_remove_interface);
int iwl_alloc_txq_mem(struct iwl_priv *priv)
{
@@ -2431,77 +1854,115 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
return 0;
}
-/**
- * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
- *
- * During normal condition (no queue is stuck), the timer is continually set to
- * execute every monitor_recover_period milliseconds after the last timer
- * expired. When the queue read_ptr is at the same place, the timer is
- * shorten to 100mSecs. This is
- * 1) to reduce the chance that the read_ptr may wrap around (not stuck)
- * 2) to detect the stuck queues quicker before the station and AP can
- * disassociate each other.
- *
- * This function monitors all the tx queues and recover from it if any
- * of the queues are stuck.
- * 1. It first check the cmd queue for stuck conditions. If it is stuck,
- * it will recover by resetting the firmware and return.
- * 2. Then, it checks for station association. If it associates it will check
- * other queues. If any queue is stuck, it will recover by resetting
- * the firmware.
- * Note: It the number of times the queue read_ptr to be at the same place to
- * be MAX_REPEAT+1 in order to consider to be stuck.
- */
+int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum nl80211_iftype newtype, bool newp2p)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+ struct iwl_rxon_context *tmp;
+ u32 interface_modes;
+ int err;
+
+ newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+ mutex_lock(&priv->mutex);
+
+ interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+
+ if (!(interface_modes & BIT(newtype))) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (ctx->exclusive_interface_modes & BIT(newtype)) {
+ for_each_context(priv, tmp) {
+ if (ctx == tmp)
+ continue;
+
+ if (!tmp->vif)
+ continue;
+
+ /*
+ * The current mode switch would be exclusive, but
+ * another context is active ... refuse the switch.
+ */
+ err = -EBUSY;
+ goto out;
+ }
+ }
+
+ /* success */
+ iwl_teardown_interface(priv, vif, true);
+ vif->type = newtype;
+ err = iwl_setup_interface(priv, ctx);
+ WARN_ON(err);
+ /*
+ * We've switched internally, but submitting to the
+ * device may have failed for some reason. Mask this
+ * error, because otherwise mac80211 will not switch
+ * (and set the interface type back) and we'll be
+ * out of sync with it.
+ */
+ err = 0;
+
+ out:
+ mutex_unlock(&priv->mutex);
+ return err;
+}
+EXPORT_SYMBOL(iwl_mac_change_interface);
+
/*
- * The maximum number of times the read pointer of the tx queue at the
- * same place without considering to be stuck.
+ * On every watchdog tick we check (latest) time stamp. If it does not
+ * change during timeout period and queue is not empty we reset firmware.
*/
-#define MAX_REPEAT (2)
static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
{
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
+ struct iwl_tx_queue *txq = &priv->txq[cnt];
+ struct iwl_queue *q = &txq->q;
+ unsigned long timeout;
+ int ret;
- txq = &priv->txq[cnt];
- q = &txq->q;
- /* queue is empty, skip */
- if (q->read_ptr == q->write_ptr)
+ if (q->read_ptr == q->write_ptr) {
+ txq->time_stamp = jiffies;
return 0;
+ }
- if (q->read_ptr == q->last_read_ptr) {
- /* a queue has not been read from last time */
- if (q->repeat_same_read_ptr > MAX_REPEAT) {
- IWL_ERR(priv,
- "queue %d stuck %d time. Fw reload.\n",
- q->id, q->repeat_same_read_ptr);
- q->repeat_same_read_ptr = 0;
- iwl_force_reset(priv, IWL_FW_RESET, false);
- } else {
- q->repeat_same_read_ptr++;
- IWL_DEBUG_RADIO(priv,
- "queue %d, not read %d time\n",
- q->id,
- q->repeat_same_read_ptr);
- mod_timer(&priv->monitor_recover,
- jiffies + msecs_to_jiffies(
- IWL_ONE_HUNDRED_MSECS));
- return 1;
- }
- } else {
- q->last_read_ptr = q->read_ptr;
- q->repeat_same_read_ptr = 0;
+ timeout = txq->time_stamp +
+ msecs_to_jiffies(priv->cfg->base_params->wd_timeout);
+
+ if (time_after(jiffies, timeout)) {
+ IWL_ERR(priv, "Queue %d stuck for %u ms.\n",
+ q->id, priv->cfg->base_params->wd_timeout);
+ ret = iwl_force_reset(priv, IWL_FW_RESET, false);
+ return (ret == -EAGAIN) ? 0 : 1;
}
+
return 0;
}
-void iwl_bg_monitor_recover(unsigned long data)
+/*
+ * Making watchdog tick be a quarter of timeout assure we will
+ * discover the queue hung between timeout and 1.25*timeout
+ */
+#define IWL_WD_TICK(timeout) ((timeout) / 4)
+
+/*
+ * Watchdog timer callback, we check each tx queue for stuck, if if hung
+ * we reset the firmware. If everything is fine just rearm the timer.
+ */
+void iwl_bg_watchdog(unsigned long data)
{
struct iwl_priv *priv = (struct iwl_priv *)data;
int cnt;
+ unsigned long timeout;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
+ timeout = priv->cfg->base_params->wd_timeout;
+ if (timeout == 0)
+ return;
+
/* monitor and check for stuck cmd queue */
if (iwl_check_stuck_queue(priv, priv->cmd_queue))
return;
@@ -2516,17 +1977,23 @@ void iwl_bg_monitor_recover(unsigned long data)
return;
}
}
- if (priv->cfg->base_params->monitor_recover_period) {
- /*
- * Reschedule the timer to occur in
- * priv->cfg->base_params->monitor_recover_period
- */
- mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
- priv->cfg->base_params->monitor_recover_period));
- }
+
+ mod_timer(&priv->watchdog, jiffies +
+ msecs_to_jiffies(IWL_WD_TICK(timeout)));
}
-EXPORT_SYMBOL(iwl_bg_monitor_recover);
+EXPORT_SYMBOL(iwl_bg_watchdog);
+
+void iwl_setup_watchdog(struct iwl_priv *priv)
+{
+ unsigned int timeout = priv->cfg->base_params->wd_timeout;
+ if (timeout)
+ mod_timer(&priv->watchdog,
+ jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
+ else
+ del_timer(&priv->watchdog);
+}
+EXPORT_SYMBOL(iwl_setup_watchdog);
/*
* extended beacon time format
@@ -2584,8 +2051,9 @@ EXPORT_SYMBOL(iwl_add_beacon_time);
#ifdef CONFIG_PM
-int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+int iwl_pci_suspend(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct iwl_priv *priv = pci_get_drvdata(pdev);
/*
@@ -2597,18 +2065,14 @@ int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
*/
iwl_apm_stop(priv);
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
return 0;
}
EXPORT_SYMBOL(iwl_pci_suspend);
-int iwl_pci_resume(struct pci_dev *pdev)
+int iwl_pci_resume(struct device *device)
{
+ struct pci_dev *pdev = to_pci_dev(device);
struct iwl_priv *priv = pci_get_drvdata(pdev);
- int ret;
bool hw_rfkill = false;
/*
@@ -2617,11 +2081,6 @@ int iwl_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
- pci_set_power_state(pdev, PCI_D0);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
- pci_restore_state(pdev);
iwl_enable_interrupts(priv);
if (!(iwl_read32(priv, CSR_GP_CNTRL) &
@@ -2639,4 +2098,14 @@ int iwl_pci_resume(struct pci_dev *pdev)
}
EXPORT_SYMBOL(iwl_pci_resume);
+const struct dev_pm_ops iwl_pm_ops = {
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
+ .freeze = iwl_pci_suspend,
+ .thaw = iwl_pci_resume,
+ .poweroff = iwl_pci_suspend,
+ .restore = iwl_pci_resume,
+};
+EXPORT_SYMBOL(iwl_pm_ops);
+
#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 64527def059f..a3474376fdbc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -120,6 +120,14 @@ struct iwl_apm_ops {
void (*config)(struct iwl_priv *priv);
};
+struct iwl_isr_ops {
+ irqreturn_t (*isr) (int irq, void *data);
+ void (*free)(struct iwl_priv *priv);
+ int (*alloc)(struct iwl_priv *priv);
+ int (*reset)(struct iwl_priv *priv);
+ void (*disable)(struct iwl_priv *priv);
+};
+
struct iwl_debugfs_ops {
ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
@@ -193,22 +201,15 @@ struct iwl_lib_ops {
/* power */
int (*send_tx_power) (struct iwl_priv *priv);
void (*update_chain_flags)(struct iwl_priv *priv);
- void (*post_associate)(struct iwl_priv *priv,
- struct ieee80211_vif *vif);
- void (*config_ap)(struct iwl_priv *priv, struct ieee80211_vif *vif);
- irqreturn_t (*isr) (int irq, void *data);
+
+ /* isr */
+ struct iwl_isr_ops isr_ops;
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
/* temperature */
struct iwl_temp_ops temp_ops;
- /* station management */
- int (*manage_ibss_station)(struct iwl_priv *priv,
- struct ieee80211_vif *vif, bool add);
- int (*update_bcast_stations)(struct iwl_priv *priv);
- /* recover from tx queue stall */
- void (*recover_from_tx_stall)(unsigned long data);
/* check for plcp health */
bool (*check_plcp_health)(struct iwl_priv *priv,
struct iwl_rx_packet *pkt);
@@ -235,12 +236,23 @@ struct iwl_nic_ops {
void (*additional_nic_config)(struct iwl_priv *priv);
};
+struct iwl_legacy_ops {
+ void (*post_associate)(struct iwl_priv *priv);
+ void (*config_ap)(struct iwl_priv *priv);
+ /* station management */
+ int (*update_bcast_stations)(struct iwl_priv *priv);
+ int (*manage_ibss_station)(struct iwl_priv *priv,
+ struct ieee80211_vif *vif, bool add);
+};
+
struct iwl_ops {
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
const struct iwl_led_ops *led;
const struct iwl_nic_ops *nic;
+ const struct iwl_legacy_ops *legacy;
+ const struct ieee80211_ops *ieee80211_ops;
};
struct iwl_mod_params {
@@ -266,7 +278,7 @@ struct iwl_mod_params {
* @plcp_delta_threshold: plcp error rate threshold used to trigger
* radio tuning when there is a high receiving plcp error rate
* @chain_noise_scale: default chain noise scale used for gain computation
- * @monitor_recover_period: default timer used to check stuck queues
+ * @wd_timeout: TX queues watchdog timeout
* @temperature_kelvin: temperature report by uCode in kelvin
* @max_event_log_size: size of event log buffer size for ucode event logging
* @tx_power_by_driver: tx power calibration performed by driver
@@ -276,7 +288,10 @@ struct iwl_mod_params {
* sensitivity calibration operation
* @chain_noise_calib_by_driver: driver has the capability to perform
* chain noise calibration operation
-*/
+ * @shadow_reg_enable: HW shadhow register bit
+ * @no_agg_framecnt_info: uCode do not provide aggregation frame count
+ * information
+ */
struct iwl_base_params {
int eeprom_size;
int num_of_queues; /* def: HW dependent */
@@ -298,14 +313,15 @@ struct iwl_base_params {
const bool support_wimax_coexist;
u8 plcp_delta_threshold;
s32 chain_noise_scale;
- /* timer period for monitor the driver queues */
- u32 monitor_recover_period;
+ unsigned int wd_timeout;
bool temperature_kelvin;
u32 max_event_log_size;
const bool tx_power_by_driver;
const bool ucode_tracing;
const bool sensitivity_calib_by_driver;
const bool chain_noise_calib_by_driver;
+ const bool shadow_reg_enable;
+ const bool no_agg_framecnt_info;
};
/*
* @advanced_bt_coexist: support advanced bt coexist
@@ -315,6 +331,7 @@ struct iwl_base_params {
* @agg_time_limit: maximum number of uSec in aggregation
* @ampdu_factor: Maximum A-MPDU length factor
* @ampdu_density: Minimum A-MPDU spacing
+ * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
*/
struct iwl_bt_params {
bool advanced_bt_coexist;
@@ -324,6 +341,7 @@ struct iwl_bt_params {
u16 agg_time_limit;
u8 ampdu_factor;
u8 ampdu_density;
+ bool bt_sco_disable;
};
/*
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
@@ -344,6 +362,10 @@ struct iwl_ht_params {
* @need_dc_calib: need to perform init dc calibration
* @need_temp_offset_calib: need to perform temperature offset calibration
* @scan_antennas: available antenna for scan operation
+ * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
+ * @adv_pm: advance power management
+ * @rx_with_siso_diversity: 1x1 device with rx antenna diversity
+ * @internal_wimax_coex: internal wifi/wimax combo device
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -389,15 +411,17 @@ struct iwl_cfg {
const bool need_dc_calib; /* if used set to true */
const bool need_temp_offset_calib; /* if used set to true */
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
- u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+ enum iwl_led_mode led_mode;
+ const bool adv_pm;
+ const bool rx_with_siso_diversity;
+ const bool internal_wimax_coex;
};
/***************************
* L i b *
***************************/
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
- struct ieee80211_ops *hw_ops);
+struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
@@ -425,23 +449,16 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
u32 decrypt_res,
struct ieee80211_rx_status *stats);
void iwl_irq_handle_error(struct iwl_priv *priv);
-void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
-void iwl_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
-int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
-void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
+int iwl_mac_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype newtype, bool newp2p);
int iwl_alloc_txq_mem(struct iwl_priv *priv);
void iwl_free_txq_mem(struct iwl_priv *priv);
-void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
- struct ieee80211_tx_info *info,
- __le16 fc, __le32 *tx_flags);
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -529,6 +546,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
+void iwl_setup_watchdog(struct iwl_priv *priv);
/*****************************************************
* TX power
****************************************************/
@@ -598,7 +616,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
/*****************************************************
* PCI *
*****************************************************/
-irqreturn_t iwl_isr_legacy(int irq, void *data);
static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
{
@@ -609,15 +626,23 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
return pci_lnk_ctl;
}
-void iwl_bg_monitor_recover(unsigned long data);
+void iwl_bg_watchdog(unsigned long data);
u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
u32 addon, u32 beacon_interval);
#ifdef CONFIG_PM
-int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
-int iwl_pci_resume(struct pci_dev *pdev);
-#endif /* CONFIG_PM */
+int iwl_pci_suspend(struct device *device);
+int iwl_pci_resume(struct device *device);
+extern const struct dev_pm_ops iwl_pm_ops;
+
+#define IWL_PM_OPS (&iwl_pm_ops)
+
+#else /* !CONFIG_PM */
+
+#define IWL_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
/*****************************************************
* Error Handling Debugging
@@ -724,11 +749,6 @@ static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
{
return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
}
-static inline void iwlcore_config_ap(struct iwl_priv *priv,
- struct ieee80211_vif *vif)
-{
- priv->cfg->ops->lib->config_ap(priv, vif);
-}
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
struct iwl_priv *priv, enum ieee80211_band band)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 2aa15ab13892..b80bf7dff55b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -132,6 +132,8 @@
#define CSR_LED_REG (CSR_BASE+0x094)
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
+#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */
+
/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 0b961a353ff6..ebdea3be3ef9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -120,6 +120,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
/* 0x000000F0 - 0x00000010 */
#define IWL_DL_MACDUMP (1 << 4)
#define IWL_DL_HCMD_DUMP (1 << 5)
+#define IWL_DL_EEPROM (1 << 6)
#define IWL_DL_RADIO (1 << 7)
/* 0x00000F00 - 0x00000100 */
#define IWL_DL_POWER (1 << 8)
@@ -164,6 +165,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
#define IWL_DEBUG_HC_DUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD_DUMP, f, ## a)
+#define IWL_DEBUG_EEPROM(p, f, a...) IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
#define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 8fdd4efdb1d3..6fe80b5e7a15 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -992,11 +992,8 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
" swq_id=%#.2x (ac %d/hwq %d)\n",
cnt, q->read_ptr, q->write_ptr,
!!test_bit(cnt, priv->queue_stopped),
- txq->swq_id,
- txq->swq_id & 0x80 ? txq->swq_id & 3 :
- txq->swq_id,
- txq->swq_id & 0x80 ? (txq->swq_id >> 2) &
- 0x1f : txq->swq_id);
+ txq->swq_id, txq->swq_id & 3,
+ (txq->swq_id >> 2) & 0x1f);
if (cnt >= 4)
continue;
/* for the ACs, display the stop count too */
@@ -1537,32 +1534,26 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
user_buf, count, ppos);
}
-static ssize_t iwl_dbgfs_monitor_period_write(struct file *file,
+static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
- int period;
+ int timeout;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
- if (sscanf(buf, "%d", &period) != 1)
+ if (sscanf(buf, "%d", &timeout) != 1)
return -EINVAL;
- if (period < 0 || period > IWL_MAX_MONITORING_PERIOD)
- priv->cfg->base_params->monitor_recover_period =
- IWL_DEF_MONITORING_PERIOD;
- else
- priv->cfg->base_params->monitor_recover_period = period;
+ if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
+ timeout = IWL_DEF_WD_TIMEOUT;
- if (priv->cfg->base_params->monitor_recover_period)
- mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
- priv->cfg->base_params->monitor_recover_period));
- else
- del_timer_sync(&priv->monitor_recover);
+ priv->cfg->base_params->wd_timeout = timeout;
+ iwl_setup_watchdog(priv);
return count;
}
@@ -1576,11 +1567,18 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
const size_t bufsz = sizeof(buf);
ssize_t ret;
+ if (!priv->bt_enable_flag) {
+ pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
+ priv->bt_enable_flag);
pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
priv->bt_full_concurrent ? "full concurrency" : "3-wire");
pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
"last traffic notif: %d\n",
- priv->bt_status ? "On" : "Off", priv->notif_bt_traffic_load);
+ priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load);
pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
"sco_active: %d, kill_ack_mask: %x, "
"kill_cts_mask: %x\n",
@@ -1689,7 +1687,7 @@ DEBUGFS_READ_FILE_OPS(rxon_flags);
DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
-DEBUGFS_WRITE_FILE_OPS(monitor_period);
+DEBUGFS_WRITE_FILE_OPS(wd_timeout);
DEBUGFS_READ_FILE_OPS(bt_traffic);
DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
DEBUGFS_READ_FILE_OPS(reply_tx_error);
@@ -1766,7 +1764,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
if (priv->cfg->base_params->sensitivity_calib_by_driver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 70e07fa48405..8dda67850af4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -129,9 +129,6 @@ struct iwl_queue {
int write_ptr; /* 1-st empty entry (index) host_w*/
int read_ptr; /* last used entry (index) host_r*/
/* use for monitoring and recovering the stuck queue */
- int last_read_ptr; /* storing the last read_ptr */
- /* number of time read_ptr and last_read_ptr are the same */
- u8 repeat_same_read_ptr;
dma_addr_t dma_addr; /* physical addr for BD's */
int n_window; /* safe queue window */
u32 id;
@@ -155,6 +152,7 @@ struct iwl_tx_info {
* @meta: array of meta data for each command/tx buffer
* @dma_addr_cmd: physical address of cmd/tx buffer array
* @txb: array of per-TFD driver data
+ * @time_stamp: time (in jiffies) of last read_ptr change
* @need_update: indicates need to update read/write index
* @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
*
@@ -170,6 +168,7 @@ struct iwl_tx_queue {
struct iwl_device_cmd **cmd;
struct iwl_cmd_meta *meta;
struct iwl_tx_info *txb;
+ unsigned long time_stamp;
u8 need_update;
u8 sched_retry;
u8 active;
@@ -1104,11 +1103,10 @@ struct iwl_event_log {
#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
-/* timer constants use to monitor and recover stuck tx queues in mSecs */
-#define IWL_DEF_MONITORING_PERIOD (1000)
-#define IWL_LONG_MONITORING_PERIOD (5000)
-#define IWL_ONE_HUNDRED_MSECS (100)
-#define IWL_MAX_MONITORING_PERIOD (60000)
+/* TX queue watchdog timeouts in mSecs */
+#define IWL_DEF_WD_TIMEOUT (2000)
+#define IWL_LONG_WD_TIMEOUT (10000)
+#define IWL_MAX_WD_TIMEOUT (120000)
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
@@ -1162,6 +1160,8 @@ struct iwl_rxon_context {
*/
bool always_active, is_active;
+ bool ht_need_multiple_chains;
+
enum iwl_rxon_context_id ctxid;
u32 interface_modes, exclusive_interface_modes;
@@ -1468,8 +1468,9 @@ struct iwl_priv {
};
/* bt coex */
+ u8 bt_enable_flag;
u8 bt_status;
- u8 bt_traffic_load, notif_bt_traffic_load;
+ u8 bt_traffic_load, last_bt_traffic_load;
bool bt_ch_announce;
bool bt_sco_active;
bool bt_full_concurrent;
@@ -1480,7 +1481,6 @@ struct iwl_priv {
u16 bt_on_thresh;
u16 bt_duration;
u16 dynamic_frag_thresh;
- u16 dynamic_agg_thresh;
u8 bt_ci_compliance;
struct work_struct bt_traffic_change_work;
@@ -1517,6 +1517,7 @@ struct iwl_priv {
s8 tx_power_user_lmt;
s8 tx_power_device_lmt;
s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
+ s8 tx_power_next;
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -1542,7 +1543,7 @@ struct iwl_priv {
struct work_struct run_time_calib_work;
struct timer_list statistics_periodic;
struct timer_list ucode_trace;
- struct timer_list monitor_recover;
+ struct timer_list watchdog;
bool hw_ready;
struct iwl_event_log event_log;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 87cd10ff285d..358cfd7e5af1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -147,7 +147,7 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
int ret = 0;
- IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp);
+ IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
switch (gp) {
case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
@@ -354,7 +354,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
*/
valid_addr = next_link_addr;
next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
- IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
+ IWL_DEBUG_EEPROM(priv, "OTP blocks %d addr 0x%x\n",
usedblocks, next_link_addr);
if (iwl_read_otp_word(priv, next_link_addr, &link_value))
return -EINVAL;
@@ -374,7 +374,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
} while (usedblocks <= priv->cfg->base_params->max_ll_items);
/* OTP has no valid blocks */
- IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n");
+ IWL_DEBUG_EEPROM(priv, "OTP has no valid blocks\n");
return -EINVAL;
}
@@ -414,7 +414,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
return -ENOENT;
/* allocate eeprom */
sz = priv->cfg->base_params->eeprom_size;
- IWL_DEBUG_INFO(priv, "NVM size = %d\n", sz);
+ IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
ret = -ENOMEM;
@@ -492,7 +492,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
}
}
- IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
+ IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
? "OTP" : "EEPROM",
iwl_eeprom_query16(priv, EEPROM_VERSION));
@@ -594,7 +594,7 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
if (!is_channel_valid(ch_info))
return -1;
- IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
+ IWL_DEBUG_EEPROM(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
" Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
@@ -634,11 +634,11 @@ int iwl_init_channel_map(struct iwl_priv *priv)
struct iwl_channel_info *ch_info;
if (priv->channel_count) {
- IWL_DEBUG_INFO(priv, "Channel map already initialized.\n");
+ IWL_DEBUG_EEPROM(priv, "Channel map already initialized.\n");
return 0;
}
- IWL_DEBUG_INFO(priv, "Initializing regulatory info from EEPROM\n");
+ IWL_DEBUG_EEPROM(priv, "Initializing regulatory info from EEPROM\n");
priv->channel_count =
ARRAY_SIZE(iwl_eeprom_band_1) +
@@ -647,7 +647,8 @@ int iwl_init_channel_map(struct iwl_priv *priv)
ARRAY_SIZE(iwl_eeprom_band_4) +
ARRAY_SIZE(iwl_eeprom_band_5);
- IWL_DEBUG_INFO(priv, "Parsing data for %d channels.\n", priv->channel_count);
+ IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
+ priv->channel_count);
priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
priv->channel_count, GFP_KERNEL);
@@ -686,7 +687,8 @@ int iwl_init_channel_map(struct iwl_priv *priv)
IEEE80211_CHAN_NO_HT40;
if (!(is_channel_valid(ch_info))) {
- IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - "
+ IWL_DEBUG_EEPROM(priv,
+ "Ch. %d Flags %x [%sGHz] - "
"No traffic\n",
ch_info->channel,
ch_info->flags,
@@ -702,7 +704,8 @@ int iwl_init_channel_map(struct iwl_priv *priv)
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
ch_info->min_power = 0;
- IWL_DEBUG_INFO(priv, "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm):"
+ IWL_DEBUG_EEPROM(priv, "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) ?
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index d9b590625ae4..9e6f31355eee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -110,9 +110,18 @@ enum {
};
/* SKU Capabilities */
+/* 3945 only */
#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
+/* 5000 and up */
+#define EEPROM_SKU_CAP_BAND_POS (4)
+#define EEPROM_SKU_CAP_BAND_SELECTION \
+ (3 << EEPROM_SKU_CAP_BAND_POS)
+#define EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
+#define EEPROM_SKU_CAP_AMT_ENABLE (1 << 7)
+#define EEPROM_SKU_CAP_IPAN_ENABLE (1 << 8)
+
/* *regulatory* channel data format in eeprom, one for each channel.
* There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
struct iwl_eeprom_channel {
@@ -120,6 +129,17 @@ struct iwl_eeprom_channel {
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
} __packed;
+enum iwl_eeprom_enhanced_txpwr_flags {
+ IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
+ IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
+ IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
+ IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
+ IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
+ IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
+ IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
+ IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
+};
+
/**
* iwl_eeprom_enhanced_txpwr structure
* This structure presents the enhanced regulatory tx power limit layout
@@ -127,21 +147,23 @@ struct iwl_eeprom_channel {
* Enhanced regulatory tx power portion of eeprom image can be broken down
* into individual structures; each one is 8 bytes in size and contain the
* following information
- * @common: (desc + channel) not used by driver, should _NOT_ be "zero"
+ * @flags: entry flags
+ * @channel: channel number
* @chain_a_max_pwr: chain a max power in 1/2 dBm
* @chain_b_max_pwr: chain b max power in 1/2 dBm
* @chain_c_max_pwr: chain c max power in 1/2 dBm
- * @reserved: not used, should be "zero"
+ * @delta_20_in_40: 20-in-40 deltas (hi/lo)
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
*
*/
struct iwl_eeprom_enhanced_txpwr {
- __le16 common;
+ u8 flags;
+ u8 channel;
s8 chain_a_max;
s8 chain_b_max;
s8 chain_c_max;
- s8 reserved;
+ u8 delta_20_in_40;
s8 mimo2_max;
s8 mimo3_max;
} __packed;
@@ -186,6 +208,8 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_LINK_CALIBRATION (2*0x67)
#define EEPROM_LINK_PROCESS_ADJST (2*0x68)
#define EEPROM_LINK_OTHERS (2*0x69)
+#define EEPROM_LINK_TXP_LIMIT (2*0x6a)
+#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b)
/* agn regulatory - indirect access */
#define EEPROM_REG_BAND_1_CHANNELS ((0x08)\
@@ -207,59 +231,6 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS ((0x80)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
-/* 6000 and up regulatory tx power - indirect access */
-/* max. elements per section */
-#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8)
-#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2)
-
-/**
- * Partition the enhanced tx power portion of eeprom image into
- * 10 sections based on band, modulation, frequency and channel
- *
- * Section 1: all CCK channels
- * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels
- * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
- * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT
- * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_)
- * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT
- * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_)
- * Section 8: 2.4 GHz channel 13, Both Legacy and HT
- * Section 9: 2.4 GHz channel 140, Both Legacy and HT
- * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_)
- */
-/* 2.4 GHz band: CCK */
-#define EEPROM_LB_CCK_20_COMMON ((0xA8)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */
-/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
-#define EEPROM_LB_OFDM_COMMON ((0xB0)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
-/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
-#define EEPROM_HB_OFDM_COMMON ((0xC8)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
-/* 2.4GHz band channels:
- * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */
-#define EEPROM_LB_OFDM_20_BAND ((0xE0)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */
-/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */
-#define EEPROM_LB_OFDM_HT40_BAND ((0x120)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */
-/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */
-#define EEPROM_HB_OFDM_20_BAND ((0x148)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */
-/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */
-#define EEPROM_HB_OFDM_HT40_BAND ((0x178)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
-/* 2.4 GHz band, channnel 13: Legacy, HT */
-#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x190)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
-/* 5.2 GHz band, channnel 140: Legacy, HT */
-#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A0)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
-/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */
-#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B0)\
- | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
-
-
/* 5050 Specific */
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
@@ -389,6 +360,8 @@ struct iwl_eeprom_calib_info {
#define INDIRECT_CALIBRATION 0x00040000
#define INDIRECT_PROCESS_ADJST 0x00050000
#define INDIRECT_OTHERS 0x00060000
+#define INDIRECT_TXP_LIMIT 0x00070000
+#define INDIRECT_TXP_LIMIT_SIZE 0x00080000
#define INDIRECT_ADDRESS 0x00100000
/* General */
@@ -397,11 +370,10 @@ struct iwl_eeprom_calib_info {
#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
-#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
+#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
-#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */
#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
@@ -504,6 +476,7 @@ struct iwl_eeprom_ops {
int iwl_eeprom_init(struct iwl_priv *priv);
void iwl_eeprom_free(struct iwl_priv *priv);
int iwl_eeprom_check_version(struct iwl_priv *priv);
+int iwl_eeprom_check_sku(struct iwl_priv *priv);
const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 1aaef70deaec..8821f088ba7f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -44,15 +44,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf(
return &hw->conf;
}
-static inline unsigned long elapsed_jiffies(unsigned long start,
- unsigned long end)
-{
- if (end >= start)
- return end - start;
-
- return end + (MAX_JIFFY_OFFSET - start) + 1;
-}
-
/**
* iwl_queue_inc_wrap - increment queue index, wrap back to beginning
* @index -- current index
@@ -104,42 +95,36 @@ static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
* | | | | | | | |
* | | | | | | +-+-------- AC queue (0-3)
* | | | | | |
- * | +-+-+-+-+------------ HW A-MPDU queue
+ * | +-+-+-+-+------------ HW queue ID
* |
- * +---------------------- indicates agg queue
+ * +---------------------- unused
*/
-static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq)
+static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
{
BUG_ON(ac > 3); /* only have 2 bits */
- BUG_ON(hwq > 31); /* only have 5 bits */
+ BUG_ON(hwq > 31); /* only use 5 bits */
- return 0x80 | (hwq << 2) | ac;
+ txq->swq_id = (hwq << 2) | ac;
}
-static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue)
+static inline void iwl_wake_queue(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
{
- u8 ac = queue;
- u8 hwq = queue;
-
- if (queue & 0x80) {
- ac = queue & 3;
- hwq = (queue >> 2) & 0x1f;
- }
+ u8 queue = txq->swq_id;
+ u8 ac = queue & 3;
+ u8 hwq = (queue >> 2) & 0x1f;
if (test_and_clear_bit(hwq, priv->queue_stopped))
if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0)
ieee80211_wake_queue(priv->hw, ac);
}
-static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
+static inline void iwl_stop_queue(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
{
- u8 ac = queue;
- u8 hwq = queue;
-
- if (queue & 0x80) {
- ac = queue & 3;
- hwq = (queue >> 2) & 0x1f;
- }
+ u8 queue = txq->swq_id;
+ u8 ac = queue & 3;
+ u8 hwq = (queue >> 2) & 0x1f;
if (!test_and_set_bit(hwq, priv->queue_stopped))
if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0)
@@ -163,6 +148,12 @@ static inline void iwl_disable_interrupts(struct iwl_priv *priv)
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
}
+static inline void iwl_enable_rfkill_int(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
+ iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
static inline void iwl_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 86c2b6fed0c6..46ccdf406e8e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -45,9 +45,8 @@
/* default: IWL_LED_BLINK(0) using blinking index table */
static int led_mode;
module_param(led_mode, int, S_IRUGO);
-MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
- "(default 0)");
-
+MODULE_PARM_DESC(led_mode, "0=system default, "
+ "1=On(RF On)/Off(RF Off), 2=blinking");
static const struct {
u16 tpt; /* Mb/s */
@@ -128,12 +127,13 @@ EXPORT_SYMBOL(iwl_led_start);
int iwl_led_associate(struct iwl_priv *priv)
{
IWL_DEBUG_LED(priv, "Associated\n");
- if (led_mode == IWL_LED_BLINK)
+ if (priv->cfg->led_mode == IWL_LED_BLINK)
priv->allow_blinking = 1;
priv->last_blink_time = jiffies;
return 0;
}
+EXPORT_SYMBOL(iwl_led_associate);
int iwl_led_disassociate(struct iwl_priv *priv)
{
@@ -141,6 +141,7 @@ int iwl_led_disassociate(struct iwl_priv *priv)
return 0;
}
+EXPORT_SYMBOL(iwl_led_disassociate);
/*
* calculate blink rate according to last second Tx/Rx activities
@@ -221,5 +222,8 @@ void iwl_leds_init(struct iwl_priv *priv)
priv->last_blink_rate = 0;
priv->last_blink_time = 0;
priv->allow_blinking = 0;
+ if (led_mode != IWL_LED_DEFAULT &&
+ led_mode != priv->cfg->led_mode)
+ priv->cfg->led_mode = led_mode;
}
EXPORT_SYMBOL(iwl_leds_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 49a70baa3fb6..9079b33486ef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -47,14 +47,16 @@ enum led_type {
/*
* LED mode
- * IWL_LED_BLINK: adjust led blink rate based on blink table
+ * IWL_LED_DEFAULT: use system default
* IWL_LED_RF_STATE: turn LED on/off based on RF state
* LED ON = RF ON
* LED OFF = RF OFF
+ * IWL_LED_BLINK: adjust led blink rate based on blink table
*/
enum iwl_led_mode {
- IWL_LED_BLINK,
+ IWL_LED_DEFAULT,
IWL_LED_RF_STATE,
+ IWL_LED_BLINK,
};
void iwl_leds_init(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c
new file mode 100644
index 000000000000..bb1a742a98a0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c
@@ -0,0 +1,662 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * 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:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <net/mac80211.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-helpers.h"
+#include "iwl-legacy.h"
+
+static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!ctx->is_active)
+ return;
+
+ ctx->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (ctx->qos_data.qos_active)
+ ctx->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ if (ctx->ht.enabled)
+ ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+ IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+ ctx->qos_data.qos_active,
+ ctx->qos_data.def_qos_parm.qos_flags);
+
+ iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
+ sizeof(struct iwl_qosparam_cmd),
+ &ctx->qos_data.def_qos_parm, NULL);
+}
+
+/**
+ * iwl_legacy_mac_config - mac80211 config callback
+ */
+int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_channel *channel = conf->channel;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ struct iwl_rxon_context *ctx;
+ unsigned long flags = 0;
+ int ret = 0;
+ u16 ch;
+ int scan_active = 0;
+ bool ht_changed[NUM_IWL_RXON_CTX] = {};
+
+ if (WARN_ON(!priv->cfg->ops->legacy))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
+ channel->hw_value, changed);
+
+ if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ scan_active = 1;
+ IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ /* mac80211 uses static for non-HT which is what we want */
+ priv->current_ht_config.smps = conf->smps_mode;
+
+ /*
+ * Recalculate chain counts.
+ *
+ * If monitor mode is enabled then mac80211 will
+ * set up the SM PS mode to OFF if an HT channel is
+ * configured.
+ */
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ for_each_context(priv, ctx)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ }
+
+ /* during scanning mac80211 will delay channel setting until
+ * scan finish with changed = 0
+ */
+ if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ if (scan_active)
+ goto set_ch_out;
+
+ ch = channel->hw_value;
+ ch_info = iwl_get_channel_info(priv, channel->band, ch);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
+ ret = -EINVAL;
+ goto set_ch_out;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for_each_context(priv, ctx) {
+ /* Configure HT40 channels */
+ if (ctx->ht.enabled != conf_is_ht(conf)) {
+ ctx->ht.enabled = conf_is_ht(conf);
+ ht_changed[ctx->ctxid] = true;
+ }
+ if (ctx->ht.enabled) {
+ if (conf_is_ht40_minus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ctx->ht.is_40mhz = true;
+ } else if (conf_is_ht40_plus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ctx->ht.is_40mhz = true;
+ } else {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ctx->ht.is_40mhz = false;
+ }
+ } else
+ ctx->ht.is_40mhz = false;
+
+ /*
+ * Default to no protection. Protection mode will
+ * later be set from BSS config in iwl_ht_conf
+ */
+ ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(ctx->staging.channel) != ch))
+ ctx->staging.flags = 0;
+
+ iwl_set_rxon_channel(priv, channel, ctx);
+ iwl_set_rxon_ht(priv, ht_conf);
+
+ iwl_set_flags_for_band(priv, ctx, channel->band,
+ ctx->vif);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->cfg->ops->legacy->update_bcast_stations)
+ ret = priv->cfg->ops->legacy->update_bcast_stations(priv);
+
+ set_ch_out:
+ /* The list of supported rates and rate mask can be different
+ * for each band; since the band may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_PS |
+ IEEE80211_CONF_CHANGE_IDLE)) {
+ ret = iwl_power_update_mode(priv, false);
+ if (ret)
+ IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+ priv->tx_power_user_lmt, conf->power_level);
+
+ iwl_set_tx_power(priv, conf->power_level, false);
+ }
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ goto out;
+ }
+
+ if (scan_active)
+ goto out;
+
+ for_each_context(priv, ctx) {
+ if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
+ iwlcore_commit_rxon(priv, ctx);
+ else
+ IWL_DEBUG_INFO(priv,
+ "Not re-sending same RXON configuration.\n");
+ if (ht_changed[ctx->ctxid])
+ iwl_update_qos(priv, ctx);
+ }
+
+out:
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_legacy_mac_config);
+
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ /* IBSS can only be the IWL_RXON_CTX_BSS context */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+ if (WARN_ON(!priv->cfg->ops->legacy))
+ return;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
+
+ priv->beacon_skb = NULL;
+
+ priv->timestamp = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_scan_cancel_timeout(priv, 100);
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ /* we are restarting association process
+ * clear RXON_FILTER_ASSOC_MSK bit
+ */
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf);
+
+static void iwl_ht_conf(struct iwl_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ struct ieee80211_sta *sta;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+ IWL_DEBUG_ASSOC(priv, "enter:\n");
+
+ if (!ctx->ht.enabled)
+ return;
+
+ ctx->ht.protection =
+ bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ ctx->ht.non_gf_sta_present =
+ !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+ ht_conf->single_chain_sufficient = false;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (sta) {
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ int maxstreams;
+
+ maxstreams = (ht_cap->mcs.tx_params &
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+ >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+ maxstreams += 1;
+
+ if ((ht_cap->mcs.rx_mask[1] == 0) &&
+ (ht_cap->mcs.rx_mask[2] == 0))
+ ht_conf->single_chain_sufficient = true;
+ if (maxstreams <= 1)
+ ht_conf->single_chain_sufficient = true;
+ } else {
+ /*
+ * If at all, this can only happen through a race
+ * when the AP disconnects us while we're still
+ * setting up the connection, in that case mac80211
+ * will soon tell us about that.
+ */
+ ht_conf->single_chain_sufficient = true;
+ }
+ rcu_read_unlock();
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ht_conf->single_chain_sufficient = true;
+ break;
+ default:
+ break;
+ }
+
+ IWL_DEBUG_ASSOC(priv, "leave\n");
+}
+
+static inline void iwl_set_no_assoc(struct iwl_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+ iwl_led_disassociate(priv);
+ /*
+ * inform the ucode that there is no longer an
+ * association and that no more packets should be
+ * sent
+ */
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ ctx->staging.assoc_id = 0;
+ iwlcore_commit_rxon(priv, ctx);
+}
+
+static void iwlcore_beacon_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ __le64 timestamp;
+ struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+
+ if (!skb)
+ return;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (!priv->beacon_ctx) {
+ IWL_ERR(priv, "update beacon but no beacon context!\n");
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
+
+ priv->beacon_skb = skb;
+
+ timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+ priv->timestamp = le64_to_cpu(timestamp);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return;
+ }
+
+ priv->cfg->ops->legacy->post_associate(priv);
+}
+
+void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+ int ret;
+
+ if (WARN_ON(!priv->cfg->ops->legacy))
+ return;
+
+ IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
+
+ if (!iwl_is_alive(priv))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (changes & BSS_CHANGED_QOS) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ctx->qos_data.qos_active = bss_conf->qos;
+ iwl_update_qos(priv, ctx);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ if (changes & BSS_CHANGED_BEACON_ENABLED) {
+ /*
+ * the add_interface code must make sure we only ever
+ * have a single interface that could be beaconing at
+ * any time.
+ */
+ if (vif->bss_conf.enable_beacon)
+ priv->beacon_ctx = ctx;
+ else
+ priv->beacon_ctx = NULL;
+ }
+
+ if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
+ dev_kfree_skb(priv->beacon_skb);
+ priv->beacon_skb = ieee80211_beacon_get(hw, vif);
+ }
+
+ if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
+ iwl_send_rxon_timing(priv, ctx);
+
+ if (changes & BSS_CHANGED_BSSID) {
+ IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
+
+ /*
+ * If there is currently a HW scan going on in the
+ * background then we need to cancel it else the RXON
+ * below/in post_associate will fail.
+ */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ /* mac80211 only sets assoc when in STATION mode */
+ if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
+ memcpy(ctx->staging.bssid_addr,
+ bss_conf->bssid, ETH_ALEN);
+
+ /* currently needed in a few places */
+ memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+ } else {
+ ctx->staging.filter_flags &=
+ ~RXON_FILTER_ASSOC_MSK;
+ }
+
+ }
+
+ /*
+ * This needs to be after setting the BSSID in case
+ * mac80211 decides to do both changes at once because
+ * it will invoke post_associate.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
+ iwlcore_beacon_update(hw, vif);
+
+ if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+ IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
+ if (bss_conf->use_short_preamble)
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ }
+
+ if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+ IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
+ if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+ ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
+ else
+ ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+ if (bss_conf->use_cts_prot)
+ ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+ }
+
+ if (changes & BSS_CHANGED_BASIC_RATES) {
+ /* XXX use this information
+ *
+ * To do that, remove code from iwl_set_rate() and put something
+ * like this here:
+ *
+ if (A-band)
+ ctx->staging.ofdm_basic_rates =
+ bss_conf->basic_rates;
+ else
+ ctx->staging.ofdm_basic_rates =
+ bss_conf->basic_rates >> 4;
+ ctx->staging.cck_basic_rates =
+ bss_conf->basic_rates & 0xF;
+ */
+ }
+
+ if (changes & BSS_CHANGED_HT) {
+ iwl_ht_conf(priv, vif);
+
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ }
+
+ if (changes & BSS_CHANGED_ASSOC) {
+ IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
+ if (bss_conf->assoc) {
+ priv->timestamp = bss_conf->timestamp;
+
+ iwl_led_associate(priv);
+
+ if (!iwl_is_rfkill(priv))
+ priv->cfg->ops->legacy->post_associate(priv);
+ } else
+ iwl_set_no_assoc(priv, vif);
+ }
+
+ if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
+ IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
+ changes);
+ ret = iwl_send_rxon_assoc(priv, ctx);
+ if (!ret) {
+ /* Sync active_rxon with latest change. */
+ memcpy((void *)&ctx->active,
+ &ctx->staging,
+ sizeof(struct iwl_rxon_cmd));
+ }
+ }
+
+ if (changes & BSS_CHANGED_BEACON_ENABLED) {
+ if (vif->bss_conf.enable_beacon) {
+ memcpy(ctx->staging.bssid_addr,
+ bss_conf->bssid, ETH_ALEN);
+ memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+ iwl_led_associate(priv);
+ priv->cfg->ops->legacy->config_ap(priv);
+ } else
+ iwl_set_no_assoc(priv, vif);
+ }
+
+ if (changes & BSS_CHANGED_IBSS) {
+ ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif,
+ bss_conf->ibss_joined);
+ if (ret)
+ IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+ bss_conf->ibss_joined ? "add" : "remove",
+ bss_conf->bssid);
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed);
+
+irqreturn_t iwl_isr_legacy(int irq, void *data)
+{
+ struct iwl_priv *priv = data;
+ u32 inta, inta_mask;
+ u32 inta_fh;
+ unsigned long flags;
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* 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(priv,
+ "Ignore interrupt, inta == 0, inta_fh == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared. It might have already raised
+ * an interrupt */
+ IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+ goto unplugged;
+ }
+
+ IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+
+ inta &= ~CSR_INT_BIT_SCD;
+
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
+ if (likely(inta || inta_fh))
+ tasklet_schedule(&priv->irq_tasklet);
+
+unplugged:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_HANDLED;
+
+none:
+ /* re-enable interrupts here since we don't have anything to service. */
+ /* only Re-enable if disabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &priv->status))
+ iwl_enable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_NONE;
+}
+EXPORT_SYMBOL(iwl_isr_legacy);
+
+/*
+ * iwl_legacy_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
+ * function.
+ */
+void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags)
+{
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ *tx_flags |= TX_CMD_FLG_RTS_MSK;
+ *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ if (!ieee80211_is_mgmt(fc))
+ return;
+
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ break;
+ }
+ } else if (info->control.rates[0].flags &
+ IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+ }
+}
+EXPORT_SYMBOL(iwl_legacy_tx_cmd_protection);
diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.h b/drivers/net/wireless/iwlwifi/iwl-legacy.h
new file mode 100644
index 000000000000..9f7b2f935964
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-legacy.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * 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) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * 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:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2010 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_legacy_h__
+#define __iwl_legacy_h__
+
+/* mac80211 handlers */
+int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
+void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes);
+void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags);
+
+irqreturn_t iwl_isr_legacy(int irq, void *data);
+
+#endif /* __iwl_legacy_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 49d7788937a9..1eec18d909d8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -75,6 +75,10 @@ struct iwl_power_vec_entry {
#define NOSLP cpu_to_le16(0), 0, 0
#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK | \
+ IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
+ IWL_POWER_ADVANCE_PM_ENA_MSK)
+#define ASLP_TOUT(T) cpu_to_le32(T)
#define TU_TO_USEC 1024
#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
@@ -114,6 +118,52 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
};
+/* advance power management */
+/* DTIM 0 - 2 */
+static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
+
+/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
+/* DTIM 3 - 10 */
+static const struct iwl_power_vec_entry apm_range_1[IWL_POWER_NUM] = {
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
+};
+
+/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
+static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+ {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+ SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
static void iwl_static_sleep_cmd(struct iwl_priv *priv,
struct iwl_powertable_cmd *cmd,
enum iwl_power_level lvl, int period)
@@ -124,11 +174,19 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
u8 skip;
u32 slp_itrvl;
- table = range_2;
- if (period <= IWL_DTIM_RANGE_1_MAX)
- table = range_1;
- if (period <= IWL_DTIM_RANGE_0_MAX)
- table = range_0;
+ if (priv->cfg->adv_pm) {
+ table = apm_range_2;
+ if (period <= IWL_DTIM_RANGE_1_MAX)
+ table = apm_range_1;
+ if (period <= IWL_DTIM_RANGE_0_MAX)
+ table = apm_range_0;
+ } else {
+ table = range_2;
+ if (period <= IWL_DTIM_RANGE_1_MAX)
+ table = range_1;
+ if (period <= IWL_DTIM_RANGE_0_MAX)
+ table = range_0;
+ }
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
@@ -163,6 +221,20 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
else
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ if (priv->cfg->base_params->shadow_reg_enable)
+ cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
+ else
+ cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
+
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ if (!priv->cfg->bt_params->bt_sco_disable)
+ cmd->flags |= IWL_POWER_BT_SCO_ENA;
+ else
+ cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
+ }
+
+
slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
@@ -236,6 +308,19 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ if (priv->cfg->base_params->shadow_reg_enable)
+ cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
+ else
+ cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
+
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ if (!priv->cfg->bt_params->bt_sco_disable)
+ cmd->flags |= IWL_POWER_BT_SCO_ENA;
+ else
+ cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
+ }
+
cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms);
cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms);
@@ -263,70 +348,95 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
sizeof(struct iwl_powertable_cmd), cmd);
}
-/* priv->mutex must be held */
-int iwl_power_update_mode(struct iwl_priv *priv, bool force)
+static void iwl_power_build_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd)
{
- int ret = 0;
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
- bool update_chains;
- struct iwl_powertable_cmd cmd;
int dtimper;
- /* Don't update the RX chain when chain noise calibration is running */
- update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
- priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
-
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
if (priv->cfg->base_params->broken_powersave)
- iwl_power_sleep_cam_cmd(priv, &cmd);
+ iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->cfg->base_params->supports_idle &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
- iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
+ iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
priv->cfg->ops->lib->tt_ops.tt_power_mode &&
priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
/* in thermal throttling low power state */
- iwl_static_sleep_cmd(priv, &cmd,
+ iwl_static_sleep_cmd(priv, cmd,
priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
} else if (!enabled)
- iwl_power_sleep_cam_cmd(priv, &cmd);
+ iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->power_data.debug_sleep_level_override >= 0)
- iwl_static_sleep_cmd(priv, &cmd,
+ iwl_static_sleep_cmd(priv, cmd,
priv->power_data.debug_sleep_level_override,
dtimper);
else if (no_sleep_autoadjust)
- iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper);
+ iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper);
else
- iwl_power_fill_sleep_cmd(priv, &cmd,
+ iwl_power_fill_sleep_cmd(priv, cmd,
priv->hw->conf.dynamic_ps_timeout,
priv->hw->conf.max_sleep_period);
+}
+
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+ bool force)
+{
+ int ret;
+ bool update_chains;
+
+ lockdep_assert_held(&priv->mutex);
+
+ /* Don't update the RX chain when chain noise calibration is running */
+ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
+ priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
+
+ if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
+ return 0;
+
+ if (!iwl_is_ready_rf(priv))
+ return -EIO;
- if (iwl_is_ready_rf(priv) &&
- (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) {
- if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
- set_bit(STATUS_POWER_PMI, &priv->status);
-
- ret = iwl_set_power(priv, &cmd);
- if (!ret) {
- if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
- clear_bit(STATUS_POWER_PMI, &priv->status);
-
- if (priv->cfg->ops->lib->update_chain_flags &&
- update_chains)
- priv->cfg->ops->lib->update_chain_flags(priv);
- else if (priv->cfg->ops->lib->update_chain_flags)
- IWL_DEBUG_POWER(priv,
+ /* scan complete use sleep_power_next, need to be updated */
+ memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
+ if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
+ IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
+ return 0;
+ }
+
+ if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
+ set_bit(STATUS_POWER_PMI, &priv->status);
+
+ ret = iwl_set_power(priv, cmd);
+ if (!ret) {
+ if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+
+ if (priv->cfg->ops->lib->update_chain_flags && update_chains)
+ priv->cfg->ops->lib->update_chain_flags(priv);
+ else if (priv->cfg->ops->lib->update_chain_flags)
+ IWL_DEBUG_POWER(priv,
"Cannot update the power, chain noise "
"calibration running: %d\n",
priv->chain_noise_data.state);
- memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd));
- } else
- IWL_ERR(priv, "set power fail, ret = %d", ret);
- }
+
+ memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
+ } else
+ IWL_ERR(priv, "set power fail, ret = %d", ret);
return ret;
}
+EXPORT_SYMBOL(iwl_power_set_mode);
+
+int iwl_power_update_mode(struct iwl_priv *priv, bool force)
+{
+ struct iwl_powertable_cmd cmd;
+
+ iwl_power_build_cmd(priv, &cmd);
+ return iwl_power_set_mode(priv, &cmd, force);
+}
EXPORT_SYMBOL(iwl_power_update_mode);
/* initialize to default */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df81565a7cc4..fe012032c28c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -41,10 +41,13 @@ enum iwl_power_level {
struct iwl_power_mgr {
struct iwl_powertable_cmd sleep_cmd;
+ struct iwl_powertable_cmd sleep_cmd_next;
int debug_sleep_level_override;
bool pci_pm;
};
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+ bool force);
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
void iwl_power_initialize(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 5469655646ae..86f5123bccda 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -83,10 +83,10 @@
#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
+#define APMS_CLK_VAL_MRB_FUNC_MODE (0x00000001)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
-
#define APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000)
#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index f436270ca39a..87a6fd84d4d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -134,28 +134,37 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
if (q->need_update == 0)
goto exit_unlock;
- /* If power-saving is in use, make sure device is awake */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
- reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (priv->cfg->base_params->shadow_reg_enable) {
+ /* shadow register enabled */
+ /* Device expects a multiple of 8 */
+ q->write_actual = (q->write & ~0x7);
+ iwl_write32(priv, rx_wrt_ptr_reg, q->write_actual);
+ } else {
+ /* If power-saving is in use, make sure device is awake */
+ 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_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n",
- reg);
- iwl_set_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- goto exit_unlock;
- }
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO(priv,
+ "Rx queue requesting wakeup,"
+ " GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
- q->write_actual = (q->write & ~0x7);
- iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
+ q->write_actual = (q->write & ~0x7);
+ iwl_write_direct32(priv, rx_wrt_ptr_reg,
+ q->write_actual);
- /* Else device is assumed to be awake */
- } else {
- /* Device expects a multiple of 8 */
- q->write_actual = (q->write & ~0x7);
- iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
+ /* Else device is assumed to be awake */
+ } else {
+ /* Device expects a multiple of 8 */
+ q->write_actual = (q->write & ~0x7);
+ iwl_write_direct32(priv, rx_wrt_ptr_reg,
+ q->write_actual);
+ }
}
-
q->need_update = 0;
exit_unlock:
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 67da31295781..12d9363d0afe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -252,8 +252,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
(priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
- jiffies_to_msecs(elapsed_jiffies
- (priv->scan_start, jiffies)));
+ jiffies_to_msecs(jiffies - priv->scan_start));
queue_work(priv->workqueue, &priv->scan_completed);
@@ -603,13 +602,16 @@ out_settings:
if (!iwl_is_ready_rf(priv))
goto out;
- /* Since setting the TXPOWER may have been deferred while
- * performing the scan, fire one off */
- iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ /*
+ * We do not commit power settings while scan is pending,
+ * do it now if the settings changed.
+ */
+ iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
+ iwl_set_tx_power(priv, priv->tx_power_next, false);
priv->cfg->ops->utils->post_scan(priv);
- out:
+out:
mutex_unlock(&priv->mutex);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 7c7f7dcb1b1e..49493d176515 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -107,7 +107,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
/*
* XXX: The MAC address in the command buffer is often changed from
* the original sent to the device. That is, the MAC address
- * written to the command buffer often is not the same MAC adress
+ * written to the command buffer often is not the same MAC address
* read from the command buffer when the command returns. This
* issue has not yet been resolved and this debugging is left to
* observe the problem.
@@ -400,7 +400,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
}
static int iwl_send_remove_station(struct iwl_priv *priv,
- const u8 *addr, int sta_id)
+ const u8 *addr, int sta_id,
+ bool temporary)
{
struct iwl_rx_packet *pkt;
int ret;
@@ -436,9 +437,11 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
if (!ret) {
switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- iwl_sta_ucode_deactivate(priv, sta_id);
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ if (!temporary) {
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ iwl_sta_ucode_deactivate(priv, sta_id);
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ }
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
break;
default:
@@ -505,7 +508,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_remove_station(priv, addr, sta_id);
+ return iwl_send_remove_station(priv, addr, sta_id, false);
out_err:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return -EINVAL;
@@ -624,6 +627,49 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
}
EXPORT_SYMBOL(iwl_restore_stations);
+void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+ unsigned long flags;
+ int sta_id = ctx->ap_sta_id;
+ int ret;
+ struct iwl_addsta_cmd sta_cmd;
+ struct iwl_link_quality_cmd lq;
+ bool active;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return;
+ }
+
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+ sta_cmd.mode = 0;
+ memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+
+ active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
+ priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ if (active) {
+ ret = iwl_send_remove_station(
+ priv, priv->stations[sta_id].sta.sta.addr,
+ sta_id, true);
+ if (ret)
+ IWL_ERR(priv, "failed to remove STA %pM (%d)\n",
+ priv->stations[sta_id].sta.sta.addr, ret);
+ }
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+ if (ret)
+ IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
+ priv->stations[sta_id].sta.sta.addr, ret);
+ iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+}
+EXPORT_SYMBOL(iwl_reprogram_ap_sta);
+
int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{
int i;
@@ -736,6 +782,14 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
return -EINVAL;
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
iwl_dump_lq_cmd(priv, lq);
BUG_ON(init && (cmd.flags & CMD_ASYNC));
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 06475872eee4..206f1e1a0caf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -63,6 +63,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct iwl_link_quality_cmd *lq, u8 flags, bool init);
+void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
/**
* iwl_clear_driver_stations - clear knowledge of all stations from driver
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 7261ee49f282..073b6ce6141c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -49,30 +49,39 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
if (txq->need_update == 0)
return;
- /* 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(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n",
- txq_id, reg);
- iwl_set_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- return;
- }
-
- iwl_write_direct32(priv, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
-
- /* 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
+ if (priv->cfg->base_params->shadow_reg_enable) {
+ /* shadow register enabled */
iwl_write32(priv, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
+ } else {
+ /* 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(priv,
+ "Tx queue %d requesting wakeup,"
+ " GP1 = 0x%x\n", txq_id, reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return;
+ }
+
+ iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+ txq->q.write_ptr | (txq_id << 8));
+ /*
+ * 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.write_ptr | (txq_id << 8));
+ }
txq->need_update = 0;
}
EXPORT_SYMBOL(iwl_txq_update_write_ptr);
@@ -254,8 +263,6 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
q->high_mark = 2;
q->write_ptr = q->read_ptr = 0;
- q->last_read_ptr = 0;
- q->repeat_same_read_ptr = 0;
return 0;
}
@@ -350,13 +357,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
/*
- * Aggregation TX queues will get their ID when aggregation begins;
- * they overwrite the setting done here. The command FIFO doesn't
- * need an swq_id so don't set one to catch errors, all others can
- * be set up to the identity mapping.
+ * For the default queues 0-3, set up the swq_id
+ * already -- all others need to get one later
+ * (if they need one at all).
*/
- if (txq_id != priv->cmd_queue)
- txq->swq_id = txq_id;
+ if (txq_id < 4)
+ iwl_set_swq_id(txq, txq_id, txq_id);
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 8f8c4b73f8b9..371abbf60eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -61,6 +61,7 @@
#include "iwl-helpers.h"
#include "iwl-dev.h"
#include "iwl-spectrum.h"
+#include "iwl-legacy.h"
/*
* module name, copyright, version, etc.
@@ -474,7 +475,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
int txq_id = skb_get_queue_mapping(skb);
- u16 len, idx, len_org, hdr_len; /* TODO: len_org is not used */
+ u16 len, idx, hdr_len;
u8 id;
u8 unicast;
u8 sta_id;
@@ -611,15 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
*/
len = sizeof(struct iwl3945_tx_cmd) +
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;
-
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr,
@@ -661,7 +655,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
spin_unlock_irqrestore(&priv->lock, flags);
}
- iwl_stop_queue(priv, skb_get_queue_mapping(skb));
+ iwl_stop_queue(priv, txq);
}
return 0;
@@ -2515,13 +2509,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
/* After the ALIVE response, we can send commands to 3945 uCode */
set_bit(STATUS_ALIVE, &priv->status);
- if (priv->cfg->ops->lib->recover_from_tx_stall) {
- /* Enable timer to monitor the driver queues */
- mod_timer(&priv->monitor_recover,
- jiffies +
- msecs_to_jiffies(
- priv->cfg->base_params->monitor_recover_period));
- }
+ /* Enable watchdog to monitor the driver tx queues */
+ iwl_setup_watchdog(priv);
if (iwl_is_rfkill(priv))
return;
@@ -2578,8 +2567,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
* to prevent rearm timer */
- if (priv->cfg->ops->lib->recover_from_tx_stall)
- del_timer_sync(&priv->monitor_recover);
+ del_timer_sync(&priv->watchdog);
/* Station information will now be cleared in device */
iwl_clear_ucode_stations(priv, NULL);
@@ -3057,22 +3045,22 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
-void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
+void iwl3945_post_associate(struct iwl_priv *priv)
{
int rc = 0;
struct ieee80211_conf *conf = NULL;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- if (!vif || !priv->is_open)
+ if (!ctx->vif || !priv->is_open)
return;
- if (vif->type == NL80211_IFTYPE_AP) {
+ if (ctx->vif->type == NL80211_IFTYPE_AP) {
IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
return;
}
IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
- vif->bss_conf.aid, ctx->active.bssid_addr);
+ ctx->vif->bss_conf.aid, ctx->active.bssid_addr);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -3091,18 +3079,18 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
- ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+ ctx->staging.assoc_id = cpu_to_le16(ctx->vif->bss_conf.aid);
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
- vif->bss_conf.aid, vif->bss_conf.beacon_int);
+ ctx->vif->bss_conf.aid, ctx->vif->bss_conf.beacon_int);
- if (vif->bss_conf.use_short_preamble)
+ if (ctx->vif->bss_conf.use_short_preamble)
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.use_short_slot)
+ if (ctx->vif->bss_conf.use_short_slot)
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
@@ -3110,7 +3098,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
iwl3945_commit_rxon(priv, ctx);
- switch (vif->type) {
+ switch (ctx->vif->type) {
case NL80211_IFTYPE_STATION:
iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
break;
@@ -3119,7 +3107,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
break;
default:
IWL_ERR(priv, "%s Should not be called in %d mode\n",
- __func__, vif->type);
+ __func__, ctx->vif->type);
break;
}
}
@@ -3234,9 +3222,10 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
+void iwl3945_config_ap(struct iwl_priv *priv)
{
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct ieee80211_vif *vif = ctx->vif;
int rc = 0;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -3407,9 +3396,9 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
ctx->staging.filter_flags |= filter_or;
/*
- * Committing directly here breaks for some reason,
- * but we'll eventually commit the filter flags
- * change anyway.
+ * Not committing directly because hardware can perform a scan,
+ * but even if hw is ready, committing here breaks for some reason,
+ * we'll eventually commit the filter flags change anyway.
*/
mutex_unlock(&priv->mutex);
@@ -3780,12 +3769,9 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
iwl3945_hw_setup_deferred_work(priv);
- if (priv->cfg->ops->lib->recover_from_tx_stall) {
- init_timer(&priv->monitor_recover);
- priv->monitor_recover.data = (unsigned long)priv;
- priv->monitor_recover.function =
- priv->cfg->ops->lib->recover_from_tx_stall;
- }
+ init_timer(&priv->watchdog);
+ priv->watchdog.data = (unsigned long)priv;
+ priv->watchdog.function = iwl_bg_watchdog;
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl3945_irq_tasklet, (unsigned long)priv);
@@ -3824,18 +3810,19 @@ static struct attribute_group iwl3945_attribute_group = {
.attrs = iwl3945_sysfs_entries,
};
-static struct ieee80211_ops iwl3945_hw_ops = {
+struct ieee80211_ops iwl3945_hw_ops = {
.tx = iwl3945_mac_tx,
.start = iwl3945_mac_start,
.stop = iwl3945_mac_stop,
.add_interface = iwl_mac_add_interface,
.remove_interface = iwl_mac_remove_interface,
- .config = iwl_mac_config,
+ .change_interface = iwl_mac_change_interface,
+ .config = iwl_legacy_mac_config,
.configure_filter = iwl3945_configure_filter,
.set_key = iwl3945_mac_set_key,
.conf_tx = iwl_mac_conf_tx,
- .reset_tsf = iwl_mac_reset_tsf,
- .bss_info_changed = iwl_bss_info_changed,
+ .reset_tsf = iwl_legacy_mac_reset_tsf,
+ .bss_info_changed = iwl_legacy_mac_bss_info_changed,
.hw_scan = iwl_mac_hw_scan,
.sta_add = iwl3945_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
@@ -3865,7 +3852,15 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
priv->iw_mode = NL80211_IFTYPE_STATION;
priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+ /* initialize force reset */
+ priv->force_reset[IWL_RF_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_RF_RESET;
+ priv->force_reset[IWL_FW_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_FW_RELOAD;
+
+
priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
+ priv->tx_power_next = IWL_DEFAULT_TX_POWER;
if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n",
@@ -3965,7 +3960,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/* mac80211 allocates memory for this device instance, including
* space for this driver's private structure */
- hw = iwl_alloc_all(cfg, &iwl3945_hw_ops);
+ hw = iwl_alloc_all(cfg);
if (hw == NULL) {
pr_err("Can not allocate network device\n");
err = -ENOMEM;
@@ -4000,7 +3995,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
* "the hard way", rather than using device's scan.
*/
if (iwl3945_mod_params.disable_hw_scan) {
- IWL_ERR(priv, "sw scan support is deprecated\n");
+ dev_printk(KERN_DEBUG, &(pdev->dev),
+ "sw scan support is deprecated\n");
iwl3945_hw_ops.hw_scan = NULL;
}
@@ -4116,7 +4112,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_enable_msi(priv->pci_dev);
- err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
+ err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -4274,10 +4270,7 @@ static struct pci_driver iwl3945_driver = {
.id_table = iwl3945_hw_card_ids,
.probe = iwl3945_pci_probe,
.remove = __devexit_p(iwl3945_pci_remove),
-#ifdef CONFIG_PM
- .suspend = iwl_pci_suspend,
- .resume = iwl_pci_resume,
-#endif
+ .driver.pm = IWL_PM_OPS,
};
static int __init iwl3945_init(void)
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index c6c0eff9b5ed..5a4982271e96 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -225,7 +225,8 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
struct net_device *ndev,
- u8 key_index)
+ u8 key_index, bool unicast,
+ bool multicast)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 330c7d9cf101..50dee6a0a5ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -908,7 +908,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
return ret;
}
- iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX;
+ iwm->scan_id = (iwm->scan_id + 1) % IWM_SCAN_ID_MAX;
return 0;
}
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 5046a0005034..698a1f7694ed 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -9,8 +9,6 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <asm/unaligned.h>
@@ -619,7 +617,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
print_ssid(ssid_buf, ssid, ssid_len),
LBS_SCAN_RSSI_TO_MBM(rssi)/100);
- if (channel ||
+ if (channel &&
!(channel->flags & IEEE80211_CHAN_DISABLED))
cfg80211_inform_bss(wiphy, channel,
bssid, le64_to_cpu(*(__le64 *)tsfdesc),
@@ -700,8 +698,9 @@ static void lbs_scan_worker(struct work_struct *work)
if (priv->scan_channel < priv->scan_req->n_channels) {
cancel_delayed_work(&priv->scan_work);
- queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(300));
+ if (!priv->stopping)
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(300));
}
/* This is the final data we are about to send */
@@ -1423,7 +1422,8 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
static int lbs_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *netdev,
- u8 key_index)
+ u8 key_index, bool unicast,
+ bool multicast)
{
struct lbs_private *priv = wiphy_priv(wiphy);
@@ -2061,7 +2061,7 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
};
/* Section 5.17.2 */
- static struct region_code_mapping regmap[] = {
+ static const struct region_code_mapping regmap[] = {
{"US ", 0x10}, /* US FCC */
{"CA ", 0x20}, /* Canada */
{"EU ", 0x30}, /* ETSI */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 70745928f3f8..78c4da150a74 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -177,6 +177,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct cmd_ds_host_sleep cmd_config;
int ret;
+ /*
+ * Certain firmware versions do not support EHS_REMOVE_WAKEUP command
+ * and the card will return a failure. Since we need to be
+ * able to reset the mask, in those cases we set a 0 mask instead.
+ */
+ if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
+ criteria = 0;
+
cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
cmd_config.criteria = cpu_to_le32(criteria);
cmd_config.gpio = priv->wol_gpio;
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f062ed583901..18dd9a02c459 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -36,6 +36,7 @@ struct lbs_private {
/* CFG80211 */
struct wireless_dev *wdev;
bool wiphy_registered;
+ bool stopping;
struct cfg80211_scan_request *scan_req;
u8 assoc_bss[ETH_ALEN];
u8 disassoc_reason;
@@ -137,6 +138,7 @@ struct lbs_private {
uint32_t wol_criteria;
uint8_t wol_gpio;
uint8_t wol_gap;
+ bool ehs_remove_supported;
/* Transmitting */
int tx_pending_len; /* -1 while building packet */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index e5685dc317a8..b4de0ca10feb 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1170,7 +1170,6 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
- card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 79bcb4e5d2ca..00600239a053 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -784,7 +784,7 @@ static int lbs_spi_thread(void *data)
up(&card->spi_thread_terminated);
do_exit(0);
}
- } while (err == EINTR);
+ } while (err == -EINTR);
/* Read the host interrupt status register to see what we
* can do. */
@@ -1055,7 +1055,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_stop_card(priv);
lbs_remove_card(priv); /* will call free_netdev */
- priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
if (card->pdata->teardown)
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index efaf85032208..6524c70363d9 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -345,6 +345,13 @@ static int if_usb_probe(struct usb_interface *intf,
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
+ /*
+ * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
+ */
+ priv->wol_criteria = EHS_REMOVE_WAKEUP;
+ if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
+ priv->ehs_remove_supported = false;
+
return 0;
err_start_card:
@@ -1090,12 +1097,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->psstate != PS_STATE_FULL_POWER)
return -1;
- if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("Suspend attempt without "
- "configuring wake params!\n");
- return -ENOSYS;
- }
-
ret = lbs_suspend(priv);
if (ret)
goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 47ce5a6ba120..6836a6dd9853 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -104,6 +104,7 @@ static int lbs_dev_open(struct net_device *dev)
lbs_deb_enter(LBS_DEB_NET);
spin_lock_irq(&priv->driver_lock);
+ priv->stopping = false;
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
@@ -131,10 +132,16 @@ static int lbs_eth_stop(struct net_device *dev)
lbs_deb_enter(LBS_DEB_NET);
spin_lock_irq(&priv->driver_lock);
+ priv->stopping = true;
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
schedule_work(&priv->mcast_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ if (priv->scan_req) {
+ cfg80211_scan_done(priv->scan_req, false);
+ priv->scan_req = NULL;
+ }
lbs_deb_leave(LBS_DEB_NET);
return 0;
@@ -844,9 +851,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
- priv->wol_criteria = 0xffffffff;
+ priv->wol_criteria = EHS_REMOVE_WAKEUP;
priv->wol_gpio = 0xff;
priv->wol_gap = 20;
+ priv->ehs_remove_supported = true;
goto done;
@@ -908,8 +916,6 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_free_adapter(priv);
lbs_cfg_free(priv);
-
- priv->dev = NULL;
free_netdev(dev);
lbs_deb_leave(LBS_DEB_MAIN);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a4d0bca9ef2c..a2b1df21d286 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -55,7 +55,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
struct rxpd *p_rx_pd;
int hdrchop;
struct ethhdr *p_ethhdr;
- const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ static const u8 rfc1042_eth_hdr[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
+ };
lbs_deb_enter(LBS_DEB_RX);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7eaaa3bab547..454f045ddff3 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -309,6 +309,8 @@ struct mac80211_hwsim_data {
*/
u64 group;
struct dentry *debugfs_group;
+
+ int power_level;
};
@@ -497,7 +499,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
/* TODO: simulate real signal strength (and optional packet loss) */
- rx_status.signal = -50;
+ rx_status.signal = data->power_level - 50;
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -698,6 +700,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
data->channel = conf->channel;
+ data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
del_timer(&data->beacon_timer);
else
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f152a25be59f..9ecf8407cb1b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -29,6 +29,12 @@
#define MWL8K_NAME KBUILD_MODNAME
#define MWL8K_VERSION "0.12"
+/* Module parameters */
+static unsigned ap_mode_default;
+module_param(ap_mode_default, bool, 0);
+MODULE_PARM_DESC(ap_mode_default,
+ "Set to 1 to make ap mode the default instead of sta mode");
+
/* Register definitions */
#define MWL8K_HIU_GEN_PTR 0x00000c10
#define MWL8K_MODE_STA 0x0000005a
@@ -92,8 +98,10 @@ struct rxd_ops {
struct mwl8k_device_info {
char *part_name;
char *helper_image;
- char *fw_image;
+ char *fw_image_sta;
+ char *fw_image_ap;
struct rxd_ops *ap_rxd_ops;
+ u32 fw_api_ap;
};
struct mwl8k_rx_queue {
@@ -136,8 +144,8 @@ struct mwl8k_priv {
void __iomem *regs;
/* firmware */
- struct firmware *fw_helper;
- struct firmware *fw_ucode;
+ const struct firmware *fw_helper;
+ const struct firmware *fw_ucode;
/* hardware/firmware parameters */
bool ap_fw;
@@ -210,6 +218,18 @@ struct mwl8k_priv {
/* Most recently reported noise in dBm */
s8 noise;
+
+ /*
+ * preserve the queue configurations so they can be restored if/when
+ * the firmware image is swapped.
+ */
+ struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
+
+ /* async firmware loading state */
+ unsigned fw_state;
+ char *fw_pref;
+ char *fw_alt;
+ struct completion firmware_loading_complete;
};
/* Per interface specific private data */
@@ -285,8 +305,9 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
};
/* Set or get info from Firmware */
-#define MWL8K_CMD_SET 0x0001
#define MWL8K_CMD_GET 0x0000
+#define MWL8K_CMD_SET 0x0001
+#define MWL8K_CMD_SET_LIST 0x0002
/* Firmware command codes */
#define MWL8K_CMD_CODE_DNLD 0x0001
@@ -296,6 +317,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
#define MWL8K_CMD_GET_STAT 0x0014
#define MWL8K_CMD_RADIO_CONTROL 0x001c
#define MWL8K_CMD_RF_TX_POWER 0x001e
+#define MWL8K_CMD_TX_POWER 0x001f
#define MWL8K_CMD_RF_ANTENNA 0x0020
#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */
#define MWL8K_CMD_SET_PRE_SCAN 0x0107
@@ -333,6 +355,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
MWL8K_CMDNAME(GET_STAT);
MWL8K_CMDNAME(RADIO_CONTROL);
MWL8K_CMDNAME(RF_TX_POWER);
+ MWL8K_CMDNAME(TX_POWER);
MWL8K_CMDNAME(RF_ANTENNA);
MWL8K_CMDNAME(SET_BEACON);
MWL8K_CMDNAME(SET_PRE_SCAN);
@@ -372,7 +395,7 @@ static void mwl8k_hw_reset(struct mwl8k_priv *priv)
}
/* Release fw image */
-static void mwl8k_release_fw(struct firmware **fw)
+static void mwl8k_release_fw(const struct firmware **fw)
{
if (*fw == NULL)
return;
@@ -386,37 +409,68 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv)
mwl8k_release_fw(&priv->fw_helper);
}
+/* states for asynchronous f/w loading */
+static void mwl8k_fw_state_machine(const struct firmware *fw, void *context);
+enum {
+ FW_STATE_INIT = 0,
+ FW_STATE_LOADING_PREF,
+ FW_STATE_LOADING_ALT,
+ FW_STATE_ERROR,
+};
+
/* Request fw image */
static int mwl8k_request_fw(struct mwl8k_priv *priv,
- const char *fname, struct firmware **fw)
+ const char *fname, const struct firmware **fw,
+ bool nowait)
{
/* release current image */
if (*fw != NULL)
mwl8k_release_fw(fw);
- return request_firmware((const struct firmware **)fw,
- fname, &priv->pdev->dev);
+ if (nowait)
+ return request_firmware_nowait(THIS_MODULE, 1, fname,
+ &priv->pdev->dev, GFP_KERNEL,
+ priv, mwl8k_fw_state_machine);
+ else
+ return request_firmware(fw, fname, &priv->pdev->dev);
}
-static int mwl8k_request_firmware(struct mwl8k_priv *priv)
+static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image,
+ bool nowait)
{
struct mwl8k_device_info *di = priv->device_info;
int rc;
if (di->helper_image != NULL) {
- rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
- if (rc) {
- printk(KERN_ERR "%s: Error requesting helper "
- "firmware file %s\n", pci_name(priv->pdev),
- di->helper_image);
+ if (nowait)
+ rc = mwl8k_request_fw(priv, di->helper_image,
+ &priv->fw_helper, true);
+ else
+ rc = mwl8k_request_fw(priv, di->helper_image,
+ &priv->fw_helper, false);
+ if (rc)
+ printk(KERN_ERR "%s: Error requesting helper fw %s\n",
+ pci_name(priv->pdev), di->helper_image);
+
+ if (rc || nowait)
return rc;
- }
}
- rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode);
+ if (nowait) {
+ /*
+ * if we get here, no helper image is needed. Skip the
+ * FW_STATE_INIT state.
+ */
+ priv->fw_state = FW_STATE_LOADING_PREF;
+ rc = mwl8k_request_fw(priv, fw_image,
+ &priv->fw_ucode,
+ true);
+ } else
+ rc = mwl8k_request_fw(priv, fw_image,
+ &priv->fw_ucode, false);
if (rc) {
printk(KERN_ERR "%s: Error requesting firmware file %s\n",
- pci_name(priv->pdev), di->fw_image);
+ pci_name(priv->pdev), fw_image);
mwl8k_release_fw(&priv->fw_helper);
return rc;
}
@@ -577,12 +631,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
static int mwl8k_load_firmware(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
- struct firmware *fw = priv->fw_ucode;
+ const struct firmware *fw = priv->fw_ucode;
int rc;
int loops;
if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
- struct firmware *helper = priv->fw_helper;
+ const struct firmware *helper = priv->fw_helper;
if (helper == NULL) {
printk(KERN_ERR "%s: helper image needed but none "
@@ -1811,6 +1865,7 @@ struct mwl8k_cmd_get_hw_spec_ap {
__le32 wcbbase1;
__le32 wcbbase2;
__le32 wcbbase3;
+ __le32 fw_api_version;
} __packed;
static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
@@ -1818,6 +1873,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_get_hw_spec_ap *cmd;
int rc;
+ u32 api_version;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
@@ -1834,6 +1890,16 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
if (!rc) {
int off;
+ api_version = le32_to_cpu(cmd->fw_api_version);
+ if (priv->device_info->fw_api_ap != api_version) {
+ printk(KERN_ERR "%s: Unsupported fw API version for %s."
+ " Expected %d got %d.\n", MWL8K_NAME,
+ priv->device_info->part_name,
+ priv->device_info->fw_api_ap,
+ api_version);
+ rc = -EINVAL;
+ goto done;
+ }
SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr);
priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
@@ -1861,6 +1927,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
iowrite32(priv->txq[3].txd_dma, priv->sram + off);
}
+done:
kfree(cmd);
return rc;
}
@@ -2084,7 +2151,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
/*
* CMD_RF_TX_POWER.
*/
-#define MWL8K_TX_POWER_LEVEL_TOTAL 8
+#define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8
struct mwl8k_cmd_rf_tx_power {
struct mwl8k_cmd_pkt header;
@@ -2092,7 +2159,7 @@ struct mwl8k_cmd_rf_tx_power {
__le16 support_level;
__le16 current_level;
__le16 reserved;
- __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
+ __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL];
} __packed;
static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
@@ -2116,6 +2183,65 @@ static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
}
/*
+ * CMD_TX_POWER.
+ */
+#define MWL8K_TX_POWER_LEVEL_TOTAL 12
+
+struct mwl8k_cmd_tx_power {
+ struct mwl8k_cmd_pkt header;
+ __le16 action;
+ __le16 band;
+ __le16 channel;
+ __le16 bw;
+ __le16 sub_ch;
+ __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
+} __attribute__((packed));
+
+static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf,
+ unsigned short pwr)
+{
+ struct ieee80211_channel *channel = conf->channel;
+ struct mwl8k_cmd_tx_power *cmd;
+ int rc;
+ int i;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST);
+
+ if (channel->band == IEEE80211_BAND_2GHZ)
+ cmd->band = cpu_to_le16(0x1);
+ else if (channel->band == IEEE80211_BAND_5GHZ)
+ cmd->band = cpu_to_le16(0x4);
+
+ cmd->channel = channel->hw_value;
+
+ if (conf->channel_type == NL80211_CHAN_NO_HT ||
+ conf->channel_type == NL80211_CHAN_HT20) {
+ cmd->bw = cpu_to_le16(0x2);
+ } else {
+ cmd->bw = cpu_to_le16(0x4);
+ if (conf->channel_type == NL80211_CHAN_HT40MINUS)
+ cmd->sub_ch = cpu_to_le16(0x3);
+ else if (conf->channel_type == NL80211_CHAN_HT40PLUS)
+ cmd->sub_ch = cpu_to_le16(0x1);
+ }
+
+ for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++)
+ cmd->power_level_list[i] = cpu_to_le16(pwr);
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
* CMD_RF_ANTENNA.
*/
struct mwl8k_cmd_rf_antenna {
@@ -3283,13 +3409,16 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
}
+static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image);
+
static int mwl8k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_vif *mwl8k_vif;
u32 macids_supported;
- int macid;
+ int macid, rc;
+ struct mwl8k_device_info *di;
/*
* Reject interface creation if sniffer mode is active, as
@@ -3302,12 +3431,28 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
return -EINVAL;
}
-
+ di = priv->device_info;
switch (vif->type) {
case NL80211_IFTYPE_AP:
+ if (!priv->ap_fw && di->fw_image_ap) {
+ /* we must load the ap fw to meet this request */
+ if (!list_empty(&priv->vif_list))
+ return -EBUSY;
+ rc = mwl8k_reload_firmware(hw, di->fw_image_ap);
+ if (rc)
+ return rc;
+ }
macids_supported = priv->ap_macids_supported;
break;
case NL80211_IFTYPE_STATION:
+ if (priv->ap_fw && di->fw_image_sta) {
+ /* we must load the sta fw to meet this request */
+ if (!list_empty(&priv->vif_list))
+ return -EBUSY;
+ rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
+ if (rc)
+ return rc;
+ }
macids_supported = priv->sta_macids_supported;
break;
default:
@@ -3377,15 +3522,19 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
if (conf->power_level > 18)
conf->power_level = 18;
- rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
- if (rc)
- goto out;
if (priv->ap_fw) {
+ rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level);
+ if (rc)
+ goto out;
+
rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7);
if (!rc)
rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
} else {
+ rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
+ if (rc)
+ goto out;
rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7);
}
@@ -3739,6 +3888,9 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
rc = mwl8k_fw_lock(hw);
if (!rc) {
+ BUG_ON(queue > MWL8K_TX_QUEUES - 1);
+ memcpy(&priv->wmm_params[queue], params, sizeof(*params));
+
if (!priv->wmm_enabled)
rc = mwl8k_cmd_set_wmm_mode(hw, 1);
@@ -3838,21 +3990,27 @@ enum {
MWL8366,
};
+#define MWL8K_8366_AP_FW_API 1
+#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
+#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
+
static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
[MWL8363] = {
.part_name = "88w8363",
.helper_image = "mwl8k/helper_8363.fw",
- .fw_image = "mwl8k/fmimage_8363.fw",
+ .fw_image_sta = "mwl8k/fmimage_8363.fw",
},
[MWL8687] = {
.part_name = "88w8687",
.helper_image = "mwl8k/helper_8687.fw",
- .fw_image = "mwl8k/fmimage_8687.fw",
+ .fw_image_sta = "mwl8k/fmimage_8687.fw",
},
[MWL8366] = {
.part_name = "88w8366",
.helper_image = "mwl8k/helper_8366.fw",
- .fw_image = "mwl8k/fmimage_8366.fw",
+ .fw_image_sta = "mwl8k/fmimage_8366.fw",
+ .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API),
+ .fw_api_ap = MWL8K_8366_AP_FW_API,
.ap_rxd_ops = &rxd_8366_ap_ops,
},
};
@@ -3863,6 +4021,7 @@ MODULE_FIRMWARE("mwl8k/helper_8687.fw");
MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
MODULE_FIRMWARE("mwl8k/helper_8366.fw");
MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");
+MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
{ PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
@@ -3876,94 +4035,133 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
-static int __devinit mwl8k_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int mwl8k_request_alt_fw(struct mwl8k_priv *priv)
{
- static int printed_version = 0;
- struct ieee80211_hw *hw;
- struct mwl8k_priv *priv;
int rc;
- int i;
-
- if (!printed_version) {
- printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
- printed_version = 1;
- }
-
-
- rc = pci_enable_device(pdev);
+ printk(KERN_ERR "%s: Error requesting preferred fw %s.\n"
+ "Trying alternative firmware %s\n", pci_name(priv->pdev),
+ priv->fw_pref, priv->fw_alt);
+ rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true);
if (rc) {
- printk(KERN_ERR "%s: Cannot enable new PCI device\n",
- MWL8K_NAME);
+ printk(KERN_ERR "%s: Error requesting alt fw %s\n",
+ pci_name(priv->pdev), priv->fw_alt);
return rc;
}
+ return 0;
+}
- rc = pci_request_regions(pdev, MWL8K_NAME);
- if (rc) {
- printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
- MWL8K_NAME);
- goto err_disable_device;
- }
-
- pci_set_master(pdev);
-
-
- hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
- if (hw == NULL) {
- printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
- rc = -ENOMEM;
- goto err_free_reg;
- }
+static int mwl8k_firmware_load_success(struct mwl8k_priv *priv);
+static void mwl8k_fw_state_machine(const struct firmware *fw, void *context)
+{
+ struct mwl8k_priv *priv = context;
+ struct mwl8k_device_info *di = priv->device_info;
+ int rc;
- SET_IEEE80211_DEV(hw, &pdev->dev);
- pci_set_drvdata(pdev, hw);
+ switch (priv->fw_state) {
+ case FW_STATE_INIT:
+ if (!fw) {
+ printk(KERN_ERR "%s: Error requesting helper fw %s\n",
+ pci_name(priv->pdev), di->helper_image);
+ goto fail;
+ }
+ priv->fw_helper = fw;
+ rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode,
+ true);
+ if (rc && priv->fw_alt) {
+ rc = mwl8k_request_alt_fw(priv);
+ if (rc)
+ goto fail;
+ priv->fw_state = FW_STATE_LOADING_ALT;
+ } else if (rc)
+ goto fail;
+ else
+ priv->fw_state = FW_STATE_LOADING_PREF;
+ break;
- priv = hw->priv;
- priv->hw = hw;
- priv->pdev = pdev;
- priv->device_info = &mwl8k_info_tbl[id->driver_data];
+ case FW_STATE_LOADING_PREF:
+ if (!fw) {
+ if (priv->fw_alt) {
+ rc = mwl8k_request_alt_fw(priv);
+ if (rc)
+ goto fail;
+ priv->fw_state = FW_STATE_LOADING_ALT;
+ } else
+ goto fail;
+ } else {
+ priv->fw_ucode = fw;
+ rc = mwl8k_firmware_load_success(priv);
+ if (rc)
+ goto fail;
+ else
+ complete(&priv->firmware_loading_complete);
+ }
+ break;
+ case FW_STATE_LOADING_ALT:
+ if (!fw) {
+ printk(KERN_ERR "%s: Error requesting alt fw %s\n",
+ pci_name(priv->pdev), di->helper_image);
+ goto fail;
+ }
+ priv->fw_ucode = fw;
+ rc = mwl8k_firmware_load_success(priv);
+ if (rc)
+ goto fail;
+ else
+ complete(&priv->firmware_loading_complete);
+ break;
- priv->sram = pci_iomap(pdev, 0, 0x10000);
- if (priv->sram == NULL) {
- wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
- goto err_iounmap;
+ default:
+ printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n",
+ MWL8K_NAME, priv->fw_state);
+ BUG_ON(1);
}
- /*
- * If BAR0 is a 32 bit BAR, the register BAR will be BAR1.
- * If BAR0 is a 64 bit BAR, the register BAR will be BAR2.
- */
- priv->regs = pci_iomap(pdev, 1, 0x10000);
- if (priv->regs == NULL) {
- priv->regs = pci_iomap(pdev, 2, 0x10000);
- if (priv->regs == NULL) {
- wiphy_err(hw->wiphy, "Cannot map device registers\n");
- goto err_iounmap;
- }
- }
+ return;
+fail:
+ priv->fw_state = FW_STATE_ERROR;
+ complete(&priv->firmware_loading_complete);
+ device_release_driver(&priv->pdev->dev);
+ mwl8k_release_firmware(priv);
+}
+
+static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
+ bool nowait)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int rc;
/* Reset firmware and hardware */
mwl8k_hw_reset(priv);
/* Ask userland hotplug daemon for the device firmware */
- rc = mwl8k_request_firmware(priv);
+ rc = mwl8k_request_firmware(priv, fw_image, nowait);
if (rc) {
wiphy_err(hw->wiphy, "Firmware files not found\n");
- goto err_stop_firmware;
+ return rc;
}
+ if (nowait)
+ return rc;
+
/* Load firmware into hardware */
rc = mwl8k_load_firmware(hw);
- if (rc) {
+ if (rc)
wiphy_err(hw->wiphy, "Cannot start firmware\n");
- goto err_stop_firmware;
- }
/* Reclaim memory once firmware is successfully loaded */
mwl8k_release_firmware(priv);
+ return rc;
+}
+
+/* initialize hw after successfully loading a firmware image */
+static int mwl8k_probe_hw(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int rc = 0;
+ int i;
if (priv->ap_fw) {
priv->rxd_ops = priv->device_info->ap_rxd_ops;
@@ -3980,58 +4178,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
priv->wmm_enabled = false;
priv->pending_tx_pkts = 0;
-
- /*
- * Extra headroom is the size of the required DMA header
- * minus the size of the smallest 802.11 frame (CTS frame).
- */
- hw->extra_tx_headroom =
- sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
-
- hw->channel_change_time = 10;
-
- hw->queues = MWL8K_TX_QUEUES;
-
- /* Set rssi values to dBm */
- hw->flags |= IEEE80211_HW_SIGNAL_DBM;
- hw->vif_data_size = sizeof(struct mwl8k_vif);
- hw->sta_data_size = sizeof(struct mwl8k_sta);
-
- priv->macids_used = 0;
- INIT_LIST_HEAD(&priv->vif_list);
-
- /* Set default radio state and preamble */
- priv->radio_on = 0;
- priv->radio_short_preamble = 0;
-
- /* Finalize join worker */
- INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
-
- /* TX reclaim and RX tasklets. */
- tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
- tasklet_disable(&priv->poll_tx_task);
- tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
- tasklet_disable(&priv->poll_rx_task);
-
- /* Power management cookie */
- priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
- if (priv->cookie == NULL)
- goto err_stop_firmware;
-
rc = mwl8k_rxq_init(hw, 0);
if (rc)
- goto err_free_cookie;
+ goto err_stop_firmware;
rxq_refill(hw, 0, INT_MAX);
- mutex_init(&priv->fw_mutex);
- priv->fw_mutex_owner = NULL;
- priv->fw_mutex_depth = 0;
- priv->hostcmd_wait = NULL;
-
- spin_lock_init(&priv->tx_lock);
-
- priv->tx_wait = NULL;
-
for (i = 0; i < MWL8K_TX_QUEUES; i++) {
rc = mwl8k_txq_init(hw, i);
if (rc)
@@ -4071,13 +4222,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_free_irq;
}
- hw->wiphy->interface_modes = 0;
- if (priv->ap_macids_supported)
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
- if (priv->sta_macids_supported)
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
-
-
/* Turn radio off */
rc = mwl8k_cmd_radio_disable(hw);
if (rc) {
@@ -4096,12 +4240,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
free_irq(priv->pdev->irq, hw);
- rc = ieee80211_register_hw(hw);
- if (rc) {
- wiphy_err(hw->wiphy, "Cannot register device\n");
- goto err_free_queues;
- }
-
wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n",
priv->device_info->part_name,
priv->hw_rev, hw->wiphy->perm_addr,
@@ -4120,14 +4258,238 @@ err_free_queues:
mwl8k_txq_deinit(hw, i);
mwl8k_rxq_deinit(hw, 0);
+err_stop_firmware:
+ mwl8k_hw_reset(priv);
+
+ return rc;
+}
+
+/*
+ * invoke mwl8k_reload_firmware to change the firmware image after the device
+ * has already been registered
+ */
+static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
+{
+ int i, rc = 0;
+ struct mwl8k_priv *priv = hw->priv;
+
+ mwl8k_stop(hw);
+ mwl8k_rxq_deinit(hw, 0);
+
+ for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ mwl8k_txq_deinit(hw, i);
+
+ rc = mwl8k_init_firmware(hw, fw_image, false);
+ if (rc)
+ goto fail;
+
+ rc = mwl8k_probe_hw(hw);
+ if (rc)
+ goto fail;
+
+ rc = mwl8k_start(hw);
+ if (rc)
+ goto fail;
+
+ rc = mwl8k_config(hw, ~0);
+ if (rc)
+ goto fail;
+
+ for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+ rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]);
+ if (rc)
+ goto fail;
+ }
+
+ return rc;
+
+fail:
+ printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n");
+ return rc;
+}
+
+static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ int i, rc;
+
+ rc = mwl8k_load_firmware(hw);
+ mwl8k_release_firmware(priv);
+ if (rc) {
+ wiphy_err(hw->wiphy, "Cannot start firmware\n");
+ return rc;
+ }
+
+ /*
+ * Extra headroom is the size of the required DMA header
+ * minus the size of the smallest 802.11 frame (CTS frame).
+ */
+ hw->extra_tx_headroom =
+ sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
+
+ hw->channel_change_time = 10;
+
+ hw->queues = MWL8K_TX_QUEUES;
+
+ /* Set rssi values to dBm */
+ hw->flags |= IEEE80211_HW_SIGNAL_DBM;
+ hw->vif_data_size = sizeof(struct mwl8k_vif);
+ hw->sta_data_size = sizeof(struct mwl8k_sta);
+
+ priv->macids_used = 0;
+ INIT_LIST_HEAD(&priv->vif_list);
+
+ /* Set default radio state and preamble */
+ priv->radio_on = 0;
+ priv->radio_short_preamble = 0;
+
+ /* Finalize join worker */
+ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
+
+ /* TX reclaim and RX tasklets. */
+ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
+ tasklet_disable(&priv->poll_tx_task);
+ tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
+ tasklet_disable(&priv->poll_rx_task);
+
+ /* Power management cookie */
+ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
+ if (priv->cookie == NULL)
+ return -ENOMEM;
+
+ mutex_init(&priv->fw_mutex);
+ priv->fw_mutex_owner = NULL;
+ priv->fw_mutex_depth = 0;
+ priv->hostcmd_wait = NULL;
+
+ spin_lock_init(&priv->tx_lock);
+
+ priv->tx_wait = NULL;
+
+ rc = mwl8k_probe_hw(hw);
+ if (rc)
+ goto err_free_cookie;
+
+ hw->wiphy->interface_modes = 0;
+ if (priv->ap_macids_supported || priv->device_info->fw_image_ap)
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+ if (priv->sta_macids_supported || priv->device_info->fw_image_sta)
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
+
+ rc = ieee80211_register_hw(hw);
+ if (rc) {
+ wiphy_err(hw->wiphy, "Cannot register device\n");
+ goto err_unprobe_hw;
+ }
+
+ return 0;
+
+err_unprobe_hw:
+ for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ mwl8k_txq_deinit(hw, i);
+ mwl8k_rxq_deinit(hw, 0);
+
err_free_cookie:
if (priv->cookie != NULL)
pci_free_consistent(priv->pdev, 4,
priv->cookie, priv->cookie_dma);
+ return rc;
+}
+static int __devinit mwl8k_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static int printed_version;
+ struct ieee80211_hw *hw;
+ struct mwl8k_priv *priv;
+ struct mwl8k_device_info *di;
+ int rc;
+
+ if (!printed_version) {
+ printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
+ printed_version = 1;
+ }
+
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR "%s: Cannot enable new PCI device\n",
+ MWL8K_NAME);
+ return rc;
+ }
+
+ rc = pci_request_regions(pdev, MWL8K_NAME);
+ if (rc) {
+ printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
+ MWL8K_NAME);
+ goto err_disable_device;
+ }
+
+ pci_set_master(pdev);
+
+
+ hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
+ if (hw == NULL) {
+ printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
+ rc = -ENOMEM;
+ goto err_free_reg;
+ }
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ pci_set_drvdata(pdev, hw);
+
+ priv = hw->priv;
+ priv->hw = hw;
+ priv->pdev = pdev;
+ priv->device_info = &mwl8k_info_tbl[id->driver_data];
+
+
+ priv->sram = pci_iomap(pdev, 0, 0x10000);
+ if (priv->sram == NULL) {
+ wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
+ goto err_iounmap;
+ }
+
+ /*
+ * If BAR0 is a 32 bit BAR, the register BAR will be BAR1.
+ * If BAR0 is a 64 bit BAR, the register BAR will be BAR2.
+ */
+ priv->regs = pci_iomap(pdev, 1, 0x10000);
+ if (priv->regs == NULL) {
+ priv->regs = pci_iomap(pdev, 2, 0x10000);
+ if (priv->regs == NULL) {
+ wiphy_err(hw->wiphy, "Cannot map device registers\n");
+ goto err_iounmap;
+ }
+ }
+
+ /*
+ * Choose the initial fw image depending on user input. If a second
+ * image is available, make it the alternative image that will be
+ * loaded if the first one fails.
+ */
+ init_completion(&priv->firmware_loading_complete);
+ di = priv->device_info;
+ if (ap_mode_default && di->fw_image_ap) {
+ priv->fw_pref = di->fw_image_ap;
+ priv->fw_alt = di->fw_image_sta;
+ } else if (!ap_mode_default && di->fw_image_sta) {
+ priv->fw_pref = di->fw_image_sta;
+ priv->fw_alt = di->fw_image_ap;
+ } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
+ printk(KERN_WARNING "AP fw is unavailable. Using STA fw.");
+ priv->fw_pref = di->fw_image_sta;
+ } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) {
+ printk(KERN_WARNING "STA fw is unavailable. Using AP fw.");
+ priv->fw_pref = di->fw_image_ap;
+ }
+ rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
+ if (rc)
+ goto err_stop_firmware;
+ return rc;
+
err_stop_firmware:
mwl8k_hw_reset(priv);
- mwl8k_release_firmware(priv);
err_iounmap:
if (priv->regs != NULL)
@@ -4163,6 +4525,13 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
return;
priv = hw->priv;
+ wait_for_completion(&priv->firmware_loading_complete);
+
+ if (priv->fw_state == FW_STATE_ERROR) {
+ mwl8k_hw_reset(priv);
+ goto unmap;
+ }
+
ieee80211_stop_queues(hw);
ieee80211_unregister_hw(hw);
@@ -4185,6 +4554,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);
+unmap:
pci_iounmap(pdev, priv->regs);
pci_iounmap(pdev, priv->sram);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index e8e2d0f4763d..f3d396e7544b 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -1392,10 +1392,9 @@ static void orinoco_process_scan_results(struct work_struct *work)
orinoco_add_hostscan_results(priv, buf, len);
kfree(buf);
- } else if (priv->scan_request) {
+ } else {
/* Either abort or complete the scan */
- cfg80211_scan_done(priv->scan_request, (len < 0));
- priv->scan_request = NULL;
+ orinoco_scan_done(priv, (len < 0));
}
spin_lock_irqsave(&priv->scan_lock, flags);
@@ -1684,6 +1683,8 @@ static int __orinoco_down(struct orinoco_private *priv)
hermes_write_regn(hw, EVACK, 0xffff);
}
+ orinoco_scan_done(priv, true);
+
/* firmware will have to reassociate */
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
@@ -1762,10 +1763,7 @@ void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags);
/* Scanning support: Notify scan cancellation */
- if (priv->scan_request) {
- cfg80211_scan_done(priv->scan_request, 1);
- priv->scan_request = NULL;
- }
+ orinoco_scan_done(priv, true);
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
@@ -1813,6 +1811,12 @@ static int __orinoco_commit(struct orinoco_private *priv)
struct net_device *dev = priv->ndev;
int err = 0;
+ /* If we've called commit, we are reconfiguring or bringing the
+ * interface up. Maintaining countermeasures across this would
+ * be confusing, so note that we've disabled them. The port will
+ * be enabled later in orinoco_commit or __orinoco_up. */
+ priv->tkip_cm_active = 0;
+
err = orinoco_hw_program_rids(priv);
/* FIXME: what about netif_tx_lock */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index 71b3d68b9403..32954c4b243a 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -151,20 +151,20 @@ orinoco_cs_config(struct pcmcia_device *link)
goto failed;
}
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
mem = ioport_map(link->resource[0]->start,
resource_size(link->resource[0]));
if (!mem)
goto failed;
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
+ if (ret)
+ goto failed;
+
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index a38a7bd25f19..b9aedf18a046 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -57,7 +57,6 @@
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/timer.h>
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 4300d9db7d8c..86cb54c842e7 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -229,3 +229,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
priv->scan_request = NULL;
}
}
+
+void orinoco_scan_done(struct orinoco_private *priv, bool abort)
+{
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
+}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
index 2dc4e046dbdb..27281fb0a6dc 100644
--- a/drivers/net/wireless/orinoco/scan.h
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -16,5 +16,6 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
void orinoco_add_hostscan_results(struct orinoco_private *dev,
unsigned char *buf,
size_t len);
+void orinoco_scan_done(struct orinoco_private *priv, bool abort);
#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index fb859a5ad2eb..db34c282e59b 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -214,21 +214,21 @@ spectrum_cs_config(struct pcmcia_device *link)
goto failed;
}
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
mem = ioport_map(link->resource[0]->start,
resource_size(link->resource[0]));
if (!mem)
goto failed;
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
hw->eeprom_pda = true;
+ ret = pcmcia_request_irq(link, orinoco_interrupt);
+ if (ret)
+ goto failed;
+
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 93505f93bf97..e793679e2e19 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -893,6 +893,14 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
*/
break;
+ case IW_AUTH_MFP:
+ /* Management Frame Protection not supported.
+ * Only fail if set to required.
+ */
+ if (param->value == IW_AUTH_MFP_REQUIRED)
+ ret = -EINVAL;
+ break;
+
case IW_AUTH_KEY_MGMT:
/* wl_lkm implies value 2 == PSK for Hermes I
* which ties in with WEXT
@@ -911,10 +919,10 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
*/
if (param->value) {
priv->tkip_cm_active = 1;
- ret = hermes_enable_port(hw, 0);
+ ret = hermes_disable_port(hw, 0);
} else {
priv->tkip_cm_active = 0;
- ret = hermes_disable_port(hw, 0);
+ ret = hermes_enable_port(hw, 0);
}
break;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index d5bc21e5a02c..21713a7638c4 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -43,6 +43,7 @@ MODULE_FIRMWARE("isl3887usb");
static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
+ {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */
{USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
{USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
@@ -56,9 +57,13 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
{USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
+ {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
{USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
{USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+ {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
+ {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
{USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
+ {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
{USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
{USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
{USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
@@ -94,6 +99,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
{USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
{USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
{USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
@@ -183,7 +189,7 @@ static void p54u_rx_cb(struct urb *urb)
static void p54u_tx_cb(struct urb *urb)
{
struct sk_buff *skb = urb->context;
- struct ieee80211_hw *dev = (struct ieee80211_hw *)
+ struct ieee80211_hw *dev =
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
p54_free_skb(dev, skb);
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 76b2318a7dc7..f618b9623e5a 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -618,7 +618,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
else
*burst_possible = false;
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 2c8cc954d1b6..ec2c75d77cea 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -630,7 +630,7 @@ islpci_alloc_memory(islpci_private *priv)
printk(KERN_DEBUG "islpci_alloc_memory\n");
#endif
- /* remap the PCI device base address to accessable */
+ /* remap the PCI device base address to accessible */
if (!(priv->device_base =
ioremap(pci_resource_start(priv->pdev, 0),
ISL38XX_PCI_MEM_SIZE))) {
@@ -709,7 +709,7 @@ islpci_alloc_memory(islpci_private *priv)
PCI_DMA_FROMDEVICE);
if (!priv->pci_map_rx_address[counter]) {
/* error mapping the buffer to device
- accessable memory address */
+ accessible memory address */
printk(KERN_ERR "failed to map skb DMA'able\n");
goto out_free;
}
@@ -773,7 +773,7 @@ islpci_free_memory(islpci_private *priv)
priv->data_low_rx[counter] = NULL;
}
- /* Free the acces control list and the WPA list */
+ /* Free the access control list and the WPA list */
prism54_acl_clean(&priv->acl);
prism54_wpa_bss_ie_clean(priv);
mgt_clean(priv);
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 2fc52bc2d7dd..d44f8e20cce0 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv)
MAX_FRAGMENT_SIZE_RX + 2,
PCI_DMA_FROMDEVICE);
if (unlikely(!priv->pci_map_rx_address[index])) {
- /* error mapping the buffer to device accessable memory address */
+ /* error mapping the buffer to device accessible memory address */
DEBUG(SHOW_ERROR_MESSAGES,
"Error mapping DMA address\n");
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 97007d9e2c1f..0764d1a30d13 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1776,11 +1776,8 @@ static void ray_update_multi_list(struct net_device *dev, int all)
/* Copy the kernel's list of MC addresses to card */
netdev_for_each_mc_addr(ha, dev) {
memcpy_toio(p, ha->addr, ETH_ALEN);
- dev_dbg(&link->dev,
- "ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",
- ha->addr[0], ha->addr[1],
- ha->addr[2], ha->addr[3],
- ha->addr[4], ha->addr[5]);
+ dev_dbg(&link->dev, "ray_update_multi add addr %pm\n",
+ ha->addr);
p += ETH_ALEN;
i++;
}
@@ -2015,11 +2012,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
memcpy_fromio(&local->bss_id,
prcs->var.rejoin_net_complete.
bssid, ADDRLEN);
- dev_dbg(&link->dev,
- "ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",
- local->bss_id[0], local->bss_id[1],
- local->bss_id[2], local->bss_id[3],
- local->bss_id[4], local->bss_id[5]);
+ dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n",
+ local->bss_id);
if (!sniffer)
authenticate(local);
}
@@ -2286,8 +2280,8 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
struct ethhdr *peth;
UCHAR srcaddr[ADDRLEN];
UCHAR destaddr[ADDRLEN];
- static UCHAR org_bridge[3] = { 0, 0, 0xf8 };
- static UCHAR org_1042[3] = { 0, 0, 0 };
+ static const UCHAR org_bridge[3] = { 0, 0, 0xf8 };
+ static const UCHAR org_1042[3] = { 0, 0, 0 };
memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 71b5971da597..848cc2cce247 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -129,6 +129,7 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_802_11_RTS_THRESHOLD cpu_to_le32(0x0d01020a)
#define OID_802_11_SUPPORTED_RATES cpu_to_le32(0x0d01020e)
#define OID_802_11_CONFIGURATION cpu_to_le32(0x0d010211)
+#define OID_802_11_POWER_MODE cpu_to_le32(0x0d010216)
#define OID_802_11_BSSID_LIST cpu_to_le32(0x0d010217)
@@ -156,6 +157,12 @@ MODULE_PARM_DESC(workaround_interval,
#define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012)
+/* Known device types */
+#define RNDIS_UNKNOWN 0
+#define RNDIS_BCM4320A 1
+#define RNDIS_BCM4320B 2
+
+
/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
* slightly modified for datatype endianess, etc
*/
@@ -233,6 +240,12 @@ enum ndis_80211_addwep_bits {
NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
};
+enum ndis_80211_power_mode {
+ NDIS_80211_POWER_MODE_CAM,
+ NDIS_80211_POWER_MODE_MAX_PSP,
+ NDIS_80211_POWER_MODE_FAST_PSP,
+};
+
struct ndis_80211_auth_request {
__le32 length;
u8 bssid[6];
@@ -472,12 +485,16 @@ struct rndis_wlan_private {
struct mutex command_lock;
unsigned long work_pending;
int last_qual;
+ s32 cqm_rssi_thold;
+ u32 cqm_rssi_hyst;
+ int last_cqm_event_rssi;
struct ieee80211_supported_band band;
struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)];
+ int device_type;
int caps;
int multicast_size;
@@ -493,10 +510,10 @@ struct rndis_wlan_private {
/* hardware state */
bool radio_on;
+ int power_mode;
int infra_mode;
bool connected;
u8 bssid[ETH_ALEN];
- struct ndis_80211_ssid essid;
__le32 current_command_oid;
/* encryption stuff */
@@ -547,7 +564,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr);
static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index);
+ u8 key_index, bool unicast, bool multicast);
static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_info *sinfo);
@@ -563,7 +580,14 @@ static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);
-static struct cfg80211_ops rndis_config_ops = {
+static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout);
+
+static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst);
+
+static const struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
.set_wiphy_params = rndis_set_wiphy_params,
@@ -582,6 +606,8 @@ static struct cfg80211_ops rndis_config_ops = {
.set_pmksa = rndis_set_pmksa,
.del_pmksa = rndis_del_pmksa,
.flush_pmksa = rndis_flush_pmksa,
+ .set_power_mgmt = rndis_set_power_mgmt,
+ .set_cqm_rssi_config = rndis_set_cqm_rssi_config,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
@@ -680,6 +706,7 @@ static const char *oid_to_string(__le32 oid)
OID_STR(OID_802_11_ADD_KEY);
OID_STR(OID_802_11_REMOVE_KEY);
OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
+ OID_STR(OID_802_11_CAPABILITY);
OID_STR(OID_802_11_PMKID);
OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
@@ -690,6 +717,7 @@ static const char *oid_to_string(__le32 oid)
OID_STR(OID_802_11_RTS_THRESHOLD);
OID_STR(OID_802_11_SUPPORTED_RATES);
OID_STR(OID_802_11_CONFIGURATION);
+ OID_STR(OID_802_11_POWER_MODE);
OID_STR(OID_802_11_BSSID_LIST);
#undef OID_STR
}
@@ -810,7 +838,8 @@ exit_unlock:
return ret;
}
-static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
+static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data,
+ int len)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
union {
@@ -994,7 +1023,18 @@ static int level_to_qual(int level)
*/
static int set_infra_mode(struct usbnet *usbdev, int mode);
static void restore_keys(struct usbnet *usbdev);
-static int rndis_check_bssid_list(struct usbnet *usbdev);
+static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
+ bool *matched);
+
+static int rndis_start_bssid_list_scan(struct usbnet *usbdev)
+{
+ __le32 tmp;
+
+ /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */
+ tmp = cpu_to_le32(1);
+ return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
+ sizeof(tmp));
+}
static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
@@ -1007,7 +1047,6 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
return ret;
}
if (ret == 0) {
- memcpy(&priv->essid, ssid, sizeof(priv->essid));
priv->radio_on = true;
netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__);
}
@@ -1015,7 +1054,7 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
return ret;
}
-static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
+static int set_bssid(struct usbnet *usbdev, const u8 *bssid)
{
int ret;
@@ -1031,7 +1070,9 @@ static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
static int clear_bssid(struct usbnet *usbdev)
{
- u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const u8 broadcast_mac[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
return set_bssid(usbdev, broadcast_mac);
}
@@ -1904,14 +1945,14 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int ret;
- __le32 tmp;
+ int delay = SCAN_DELAY_JIFFIES;
netdev_dbg(usbdev->net, "cfg80211.scan\n");
/* Get current bssid list from device before new scan, as new scan
* clears internal bssid list.
*/
- rndis_check_bssid_list(usbdev);
+ rndis_check_bssid_list(usbdev, NULL, NULL);
if (!request)
return -EINVAL;
@@ -1921,13 +1962,13 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
priv->scan_request = request;
- tmp = cpu_to_le32(1);
- ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
- sizeof(tmp));
+ ret = rndis_start_bssid_list_scan(usbdev);
if (ret == 0) {
+ if (priv->device_type == RNDIS_BCM4320A)
+ delay = HZ;
+
/* Wait before retrieving scan results from device */
- queue_delayed_work(priv->workqueue, &priv->scan_work,
- SCAN_DELAY_JIFFIES);
+ queue_delayed_work(priv->workqueue, &priv->scan_work, delay);
}
return ret;
@@ -1946,8 +1987,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
int ie_len, bssid_len;
u8 *ie;
- netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM]\n",
- bssid->ssid.essid, bssid->mac);
+ netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n",
+ bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length));
/* parse bssid structure */
bssid_len = le32_to_cpu(bssid->length);
@@ -1981,49 +2022,98 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
GFP_KERNEL);
}
-static int rndis_check_bssid_list(struct usbnet *usbdev)
+static struct ndis_80211_bssid_ex *next_bssid_list_item(
+ struct ndis_80211_bssid_ex *bssid,
+ int *bssid_len, void *buf, int len)
+{
+ void *buf_end, *bssid_end;
+
+ buf_end = (char *)buf + len;
+ bssid_end = (char *)bssid + *bssid_len;
+
+ if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) {
+ *bssid_len = 0;
+ return NULL;
+ } else {
+ bssid = (void *)((char *)bssid + *bssid_len);
+ *bssid_len = le32_to_cpu(bssid->length);
+ return bssid;
+ }
+}
+
+static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid,
+ int bssid_len, void *buf, int len)
+{
+ void *buf_end, *bssid_end;
+
+ if (!bssid || bssid_len <= 0 || bssid_len > len)
+ return false;
+
+ buf_end = (char *)buf + len;
+ bssid_end = (char *)bssid + bssid_len;
+
+ return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0;
+}
+
+static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
+ bool *matched)
{
void *buf = NULL;
struct ndis_80211_bssid_list_ex *bssid_list;
struct ndis_80211_bssid_ex *bssid;
- int ret = -EINVAL, len, count, bssid_len;
- bool resized = false;
+ int ret = -EINVAL, len, count, bssid_len, real_count, new_len;
- netdev_dbg(usbdev->net, "check_bssid_list\n");
+ netdev_dbg(usbdev->net, "%s()\n", __func__);
len = CONTROL_BUFFER_SIZE;
resize_buf:
- buf = kmalloc(len, GFP_KERNEL);
+ buf = kzalloc(len, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out;
}
- ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
- if (ret != 0)
+ /* BSSID-list might have got bigger last time we checked, keep
+ * resizing until it won't get any bigger.
+ */
+ new_len = len;
+ ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &new_len);
+ if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex))
goto out;
- if (!resized && len > CONTROL_BUFFER_SIZE) {
- resized = true;
+ if (new_len > len) {
+ len = new_len;
kfree(buf);
goto resize_buf;
}
+ len = new_len;
+
bssid_list = buf;
- bssid = bssid_list->bssid;
- bssid_len = le32_to_cpu(bssid->length);
count = le32_to_cpu(bssid_list->num_items);
- netdev_dbg(usbdev->net, "check_bssid_list: %d BSSIDs found (buflen: %d)\n",
- count, len);
+ real_count = 0;
+ netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len);
+
+ bssid_len = 0;
+ bssid = next_bssid_list_item(bssid_list->bssid, &bssid_len, buf, len);
- while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
- rndis_bss_info_update(usbdev, bssid);
+ /* Device returns incorrect 'num_items'. Workaround by ignoring the
+ * received 'num_items' and walking through full bssid buffer instead.
+ */
+ while (check_bssid_list_item(bssid, bssid_len, buf, len)) {
+ if (rndis_bss_info_update(usbdev, bssid) && match_bssid &&
+ matched) {
+ if (compare_ether_addr(bssid->mac, match_bssid))
+ *matched = true;
+ }
- bssid = (void *)bssid + bssid_len;
- bssid_len = le32_to_cpu(bssid->length);
- count--;
+ real_count++;
+ bssid = next_bssid_list_item(bssid, &bssid_len, buf, len);
}
+ netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:"
+ " %d\n", __func__, count, real_count);
+
out:
kfree(buf);
return ret;
@@ -2041,7 +2131,7 @@ static void rndis_get_scan_results(struct work_struct *work)
if (!priv->scan_request)
return;
- ret = rndis_check_bssid_list(usbdev);
+ ret = rndis_check_bssid_list(usbdev, NULL, NULL);
cfg80211_scan_done(priv->scan_request, ret < 0);
@@ -2355,7 +2445,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
}
static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index)
+ u8 key_index, bool unicast, bool multicast)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
@@ -2365,6 +2455,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
priv->encr_tx_key_index = key_index;
+ if (is_wpa_key(priv, key_index))
+ return 0;
+
key = priv->encr_keys[key_index];
return add_wep_key(usbdev, key.material, key.len, key_index);
@@ -2495,6 +2588,136 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid));
}
+static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ int power_mode;
+ __le32 mode;
+ int ret;
+
+ netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__,
+ enabled ? "enabled" : "disabled",
+ timeout);
+
+ if (enabled)
+ power_mode = NDIS_80211_POWER_MODE_FAST_PSP;
+ else
+ power_mode = NDIS_80211_POWER_MODE_CAM;
+
+ if (power_mode == priv->power_mode)
+ return 0;
+
+ priv->power_mode = power_mode;
+
+ mode = cpu_to_le32(power_mode);
+ ret = rndis_set_oid(usbdev, OID_802_11_POWER_MODE, &mode, sizeof(mode));
+
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_POWER_MODE -> %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+
+ priv->cqm_rssi_thold = rssi_thold;
+ priv->cqm_rssi_hyst = rssi_hyst;
+ priv->last_cqm_event_rssi = 0;
+
+ return 0;
+}
+
+static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
+ struct ndis_80211_assoc_info *info)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct ieee80211_channel *channel;
+ struct ndis_80211_conf config;
+ struct ndis_80211_ssid ssid;
+ s32 signal;
+ u64 timestamp;
+ u16 capability;
+ u16 beacon_interval;
+ __le32 rssi;
+ u8 ie_buf[34];
+ int len, ret, ie_len;
+
+ /* Get signal quality, in case of error use rssi=0 and ignore error. */
+ len = sizeof(rssi);
+ rssi = 0;
+ ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
+ signal = level_to_qual(le32_to_cpu(rssi));
+
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_RSSI -> %d, "
+ "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi),
+ level_to_qual(le32_to_cpu(rssi)));
+
+ /* Get AP capabilities */
+ if (info) {
+ capability = le16_to_cpu(info->resp_ie.capa);
+ } else {
+ /* Set atleast ESS/IBSS capability */
+ capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ?
+ WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS;
+ }
+
+ /* Get channel and beacon interval */
+ len = sizeof(config);
+ ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_CONFIGURATION -> %d\n",
+ __func__, ret);
+ if (ret >= 0) {
+ beacon_interval = le16_to_cpu(config.beacon_period);
+ channel = ieee80211_get_channel(priv->wdev.wiphy,
+ KHZ_TO_MHZ(le32_to_cpu(config.ds_config)));
+ if (!channel) {
+ netdev_warn(usbdev->net, "%s(): could not get channel."
+ "\n", __func__);
+ return;
+ }
+ } else {
+ netdev_warn(usbdev->net, "%s(): could not get configuration.\n",
+ __func__);
+ return;
+ }
+
+ /* Get SSID, in case of error, use zero length SSID and ignore error. */
+ len = sizeof(ssid);
+ memset(&ssid, 0, sizeof(ssid));
+ ret = rndis_query_oid(usbdev, OID_802_11_SSID, &ssid, &len);
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_SSID -> %d, len: %d, ssid: "
+ "'%.32s'\n", __func__, ret,
+ le32_to_cpu(ssid.length), ssid.essid);
+
+ if (le32_to_cpu(ssid.length) > 32)
+ ssid.length = cpu_to_le32(32);
+
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = le32_to_cpu(ssid.length);
+ memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length));
+
+ ie_len = le32_to_cpu(ssid.length) + 2;
+
+ /* no tsf */
+ timestamp = 0;
+
+ netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, "
+ "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), "
+ "signal:%d\n", __func__, (channel ? channel->center_freq : -1),
+ bssid, (u32)timestamp, capability, beacon_interval, ie_len,
+ ssid.essid, signal);
+
+ cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
+ timestamp, capability, beacon_interval, ie_buf, ie_len,
+ signal, GFP_KERNEL);
+}
+
/*
* workers, indication handlers, device poller
*/
@@ -2507,6 +2730,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
u8 *req_ie, *resp_ie;
int ret, offset;
bool roamed = false;
+ bool match_bss;
if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) {
/* received media connect indication while connected, either
@@ -2558,6 +2782,13 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
resp_ie_len =
CONTROL_BUFFER_SIZE - offset;
}
+ } else {
+ /* Since rndis_wlan_craft_connected_bss() might use info
+ * later and expects info to contain valid data if
+ * non-null, free info and set NULL here.
+ */
+ kfree(info);
+ info = NULL;
}
} else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
return;
@@ -2569,13 +2800,26 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
netdev_dbg(usbdev->net, "link up work: [%pM]%s\n",
bssid, roamed ? " roamed" : "");
- /* Internal bss list in device always contains at least the currently
+ /* Internal bss list in device should contain at least the currently
* connected bss and we can get it to cfg80211 with
* rndis_check_bssid_list().
- * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS
- * spec.
+ *
+ * NDIS spec says: "If the device is associated, but the associated
+ * BSSID is not in its BSSID scan list, then the driver must add an
+ * entry for the BSSID at the end of the data that it returns in
+ * response to query of OID_802_11_BSSID_LIST."
+ *
+ * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a.
*/
- rndis_check_bssid_list(usbdev);
+ match_bss = false;
+ rndis_check_bssid_list(usbdev, bssid, &match_bss);
+
+ if (!is_zero_ether_addr(bssid) && !match_bss) {
+ /* Couldn't get bss from device, we need to manually craft bss
+ * for cfg80211.
+ */
+ rndis_wlan_craft_connected_bss(usbdev, bssid, info);
+ }
if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
if (!roamed)
@@ -2918,6 +3162,32 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy)
return retval;
}
+static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ enum nl80211_cqm_rssi_threshold_event event;
+ int thold, hyst, last_event;
+
+ if (priv->cqm_rssi_thold >= 0 || rssi >= 0)
+ return;
+ if (priv->infra_mode != NDIS_80211_INFRA_INFRA)
+ return;
+
+ last_event = priv->last_cqm_event_rssi;
+ thold = priv->cqm_rssi_thold;
+ hyst = priv->cqm_rssi_hyst;
+
+ if (rssi < thold && (last_event == 0 || rssi < last_event - hyst))
+ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+ else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst))
+ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+ else
+ return;
+
+ priv->last_cqm_event_rssi = rssi;
+ cfg80211_cqm_rssi_notify(usbdev->net, event, GFP_KERNEL);
+}
+
#define DEVICE_POLLER_JIFFIES (HZ)
static void rndis_device_poller(struct work_struct *work)
{
@@ -2934,13 +3204,28 @@ static void rndis_device_poller(struct work_struct *work)
* also polls device with rndis_command() and catches for media link
* indications.
*/
- if (!is_associated(usbdev))
+ if (!is_associated(usbdev)) {
+ /* Workaround bad scanning in BCM4320a devices with active
+ * background scanning when not associated.
+ */
+ if (priv->device_type == RNDIS_BCM4320A && priv->radio_on &&
+ !priv->scan_request) {
+ /* Get previous scan results */
+ rndis_check_bssid_list(usbdev, NULL, NULL);
+
+ /* Initiate new scan */
+ rndis_start_bssid_list_scan(usbdev);
+ }
+
goto end;
+ }
len = sizeof(rssi);
ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
- if (ret == 0)
+ if (ret == 0) {
priv->last_qual = level_to_qual(le32_to_cpu(rssi));
+ rndis_do_cqm(usbdev, le32_to_cpu(rssi));
+ }
netdev_dbg(usbdev->net, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n",
ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
@@ -2992,10 +3277,12 @@ end:
/*
* driver/device initialization
*/
-static void rndis_copy_module_params(struct usbnet *usbdev)
+static void rndis_copy_module_params(struct usbnet *usbdev, int device_type)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ priv->device_type = device_type;
+
priv->param_country[0] = modparam_country[0];
priv->param_country[1] = modparam_country[1];
priv->param_country[2] = 0;
@@ -3038,12 +3325,25 @@ static void rndis_copy_module_params(struct usbnet *usbdev)
priv->param_workaround_interval = modparam_workaround_interval;
}
+static int unknown_early_init(struct usbnet *usbdev)
+{
+ /* copy module parameters for unknown so that iwconfig reports txpower
+ * and workaround parameter is copied to private structure correctly.
+ */
+ rndis_copy_module_params(usbdev, RNDIS_UNKNOWN);
+
+ /* This is unknown device, so do not try set configuration parameters.
+ */
+
+ return 0;
+}
+
static int bcm4320a_early_init(struct usbnet *usbdev)
{
/* copy module parameters for bcm4320a so that iwconfig reports txpower
* and workaround parameter is copied to private structure correctly.
*/
- rndis_copy_module_params(usbdev);
+ rndis_copy_module_params(usbdev, RNDIS_BCM4320A);
/* bcm4320a doesn't handle configuration parameters well. Try
* set any and you get partially zeroed mac and broken device.
@@ -3057,7 +3357,7 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
char buf[8];
- rndis_copy_module_params(usbdev);
+ rndis_copy_module_params(usbdev, RNDIS_BCM4320B);
/* Early initialization settings, setting these won't have effect
* if called after generic_rndis_bind().
@@ -3187,13 +3487,15 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
+ priv->power_mode = -1;
+
/* set default rts/frag */
rndis_set_wiphy_params(wiphy,
WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
- /* turn radio on */
- priv->radio_on = true;
- disassociate(usbdev, true);
+ /* turn radio off on init */
+ priv->radio_on = false;
+ disassociate(usbdev, false);
netif_carrier_off(usbdev->net);
return 0;
@@ -3320,7 +3622,7 @@ static const struct driver_info rndis_wlan_info = {
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
- .early_init = bcm4320a_early_init,
+ .early_init = unknown_early_init,
.indication = rndis_wlan_indication,
};
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index eea1ef2f502b..6f383cd684b0 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -53,51 +53,41 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci.
-config RT2800PCI_PCI
- boolean
- depends on PCI
- default y
-
-config RT2800PCI_SOC
- boolean
- depends on RALINK_RT288X || RALINK_RT305X
- default y
-
config RT2800PCI
- tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)"
- depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
+ tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
+ depends on PCI || RALINK_RT288X || RALINK_RT305X
select RT2800_LIB
- select RT2X00_LIB_PCI if RT2800PCI_PCI
- select RT2X00_LIB_SOC if RT2800PCI_SOC
+ select RT2X00_LIB_PCI if PCI
+ select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X
select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
select EEPROM_93CX6
---help---
- This adds support for rt2800/rt3000/rt3500 wireless chipset family.
- Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
-
- This driver is non-functional at the moment and is intended for
- developers.
+ This adds support for rt27xx/rt28xx/rt30xx wireless chipset family.
+ Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890, RT3052,
+ RT3090, RT3091 & RT3092
When compiled as a module, this driver will be called "rt2800pci.ko".
if RT2800PCI
-config RT2800PCI_RT30XX
- bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices"
- default y
+config RT2800PCI_RT33XX
+ bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default n
---help---
- This adds support for rt30xx wireless chipset family to the
+ This adds support for rt33xx wireless chipset family to the
rt2800pci driver.
- Supported chips: RT3090, RT3091 & RT3092
+ Supported chips: RT3390
Support for these devices is non-functional at the moment and is
intended for testers and developers.
config RT2800PCI_RT35XX
- bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices"
+ bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
default n
---help---
This adds support for rt35xx wireless chipset family to the
@@ -134,8 +124,8 @@ config RT73USB
When compiled as a module, this driver will be called rt73usb.
config RT2800USB
- tristate "Ralink rt2800 (USB) support (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "Ralink rt27xx/rt28xx/rt30xx (USB) support"
+ depends on USB
select RT2800_LIB
select RT2X00_LIB_USB
select RT2X00_LIB_HT
@@ -143,30 +133,28 @@ config RT2800USB
select RT2X00_LIB_CRYPTO
select CRC_CCITT
---help---
- This adds experimental support for rt2800 wireless chipset family.
- Supported chips: RT2770, RT2870 & RT3070.
-
- Known issues:
- - support for RT2870 chips doesn't work with 802.11n APs yet
- - support for RT3070 chips is non-functional at the moment
+ This adds support for rt27xx/rt28xx/rt30xx wireless chipset family.
+ Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072
When compiled as a module, this driver will be called "rt2800usb.ko".
if RT2800USB
-config RT2800USB_RT30XX
- bool "rt2800usb - Include support for rt30xx (USB) devices"
- default y
+config RT2800USB_RT33XX
+ bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default n
---help---
- This adds support for rt30xx wireless chipset family to the
+ This adds support for rt33xx wireless chipset family to the
rt2800usb driver.
- Supported chips: RT3070, RT3071 & RT3072
+ Supported chips: RT3370
Support for these devices is non-functional at the moment and is
intended for testers and developers.
config RT2800USB_RT35XX
- bool "rt2800usb - Include support for rt35xx (USB) devices"
+ bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
default n
---help---
This adds support for rt35xx wireless chipset family to the
@@ -180,9 +168,9 @@ config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
---help---
- This adds support for rt2800 family devices that are known to
- have a rt2800 family chipset, but for which the exact chipset
- is unknown.
+ This adds support for rt2800usb devices that are known to
+ have a rt28xx family compatible chipset, but for which the exact
+ chipset is unknown.
Support status for these devices is unknown, and enabling these
devices may or may not work.
@@ -221,9 +209,6 @@ config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
-comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00"
- depends on RT2X00_LIB=y && LEDS_CLASS=m
-
config RT2X00_LIB_DEBUGFS
bool "Ralink debugfs support"
depends on RT2X00_LIB && MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 4f420a9ec5dc..54ca49ad3472 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -633,6 +633,88 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev,
}
/*
+ * Queue handlers.
+ */
+static void rt2400pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ 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, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2400pci_get_entry_state(struct queue_entry *entry)
@@ -878,18 +960,6 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* 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) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -988,12 +1058,6 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2400pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt2400pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1125,32 +1189,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2400pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2400pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1284,13 +1322,13 @@ static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VO);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VI);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -1612,6 +1650,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
@@ -1627,10 +1666,11 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.link_stats = rt2400pci_link_stats,
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
+ .start_queue = rt2400pci_start_queue,
+ .kick_queue = rt2400pci_kick_queue,
+ .stop_queue = rt2400pci_stop_queue,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
- .kick_tx_queue = rt2400pci_kick_tx_queue,
- .kill_tx_queue = rt2400pci_kill_tx_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
.config_filter = rt2400pci_config_filter,
.config_intf = rt2400pci_config_intf,
@@ -1640,28 +1680,28 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
};
static const struct data_queue_desc rt2400pci_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 24,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 24,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_bcn = {
- .entry_num = BEACON_ENTRIES,
+ .entry_num = 1,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_atim = {
- .entry_num = ATIM_ENTRIES,
+ .entry_num = 8,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index c048b18f4133..d3a4a68cc439 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -809,8 +809,8 @@
/*
* DMA descriptor defines.
*/
-#define TXD_DESC_SIZE ( 8 * sizeof(__le32) )
-#define RXD_DESC_SIZE ( 8 * sizeof(__le32) )
+#define TXD_DESC_SIZE (8 * sizeof(__le32))
+#define RXD_DESC_SIZE (8 * sizeof(__le32))
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
@@ -948,6 +948,6 @@
((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
#define TXPOWER_TO_DEV(__txpower) \
- MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER)
+ (MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER))
#endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 97feb7aef809..a9ff26a27724 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -723,6 +723,88 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt2500pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ 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, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2500pci_get_entry_state(struct queue_entry *entry)
@@ -1033,18 +1115,6 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* 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) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1143,12 +1213,6 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt2500pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1193,9 +1257,9 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry,
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs);
- rt2x00_set_field32(&word, TXD_W2_CWMIN, txdesc->cw_min);
- rt2x00_set_field32(&word, TXD_W2_CWMAX, txdesc->cw_max);
+ rt2x00_set_field32(&word, TXD_W2_AIFS, entry->queue->aifs);
+ rt2x00_set_field32(&word, TXD_W2_CWMIN, entry->queue->cw_min);
+ rt2x00_set_field32(&word, TXD_W2_CWMAX, entry->queue->cw_max);
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 3, &word);
@@ -1279,32 +1343,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2500pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2500pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1417,13 +1455,13 @@ static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VO);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VI);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -1909,6 +1947,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
@@ -1924,10 +1963,11 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.link_stats = rt2500pci_link_stats,
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
+ .start_queue = rt2500pci_start_queue,
+ .kick_queue = rt2500pci_kick_queue,
+ .stop_queue = rt2500pci_stop_queue,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
- .kick_tx_queue = rt2500pci_kick_tx_queue,
- .kill_tx_queue = rt2500pci_kill_tx_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
.config_filter = rt2500pci_config_filter,
.config_intf = rt2500pci_config_intf,
@@ -1937,28 +1977,28 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
};
static const struct data_queue_desc rt2500pci_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_bcn = {
- .entry_num = BEACON_ENTRIES,
+ .entry_num = 1,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_atim = {
- .entry_num = ATIM_ENTRIES,
+ .entry_num = 8,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index d708031361ac..2aad7ba8a100 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1088,8 +1088,8 @@
/*
* DMA descriptor defines.
*/
-#define TXD_DESC_SIZE ( 11 * sizeof(__le32) )
-#define RXD_DESC_SIZE ( 11 * sizeof(__le32) )
+#define TXD_DESC_SIZE (11 * sizeof(__le32))
+#define RXD_DESC_SIZE (11 * sizeof(__le32))
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 93e44c7f3a74..6b3b1de46792 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -39,7 +39,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 0;
+static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -739,6 +739,55 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
}
/*
+ * Queue handlers.
+ */
+static void rt2500usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ 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, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
@@ -931,18 +980,6 @@ static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* 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) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-}
-
static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1018,12 +1055,6 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt2500usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1081,9 +1112,9 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry,
rt2x00_desc_read(txd, 1, &word);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
- rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_AIFS, entry->queue->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
@@ -1206,14 +1237,6 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
-static void rt2500usb_kill_tx_queue(struct data_queue *queue)
-{
- if (queue->qid == QID_BEACON)
- rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0);
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -1801,6 +1824,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1813,11 +1837,13 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt2500usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2500usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2500usb_kill_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_shared_key = rt2500usb_config_key,
.config_pairwise_key = rt2500usb_config_key,
@@ -1829,28 +1855,28 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
};
static const struct data_queue_desc rt2500usb_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2500usb_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2500usb_queue_bcn = {
- .entry_num = BEACON_ENTRIES,
+ .entry_num = 1,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_bcn),
};
static const struct data_queue_desc rt2500usb_queue_atim = {
- .entry_num = ATIM_ENTRIES,
+ .entry_num = 8,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index eb8b6cab9925..4c55e8525cad 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -46,7 +46,11 @@
* RF2020 2.4G B/G
* RF3021 2.4G 1T2R
* RF3022 2.4G 2T2R
- * RF3052 2.4G 2T2R
+ * RF3052 2.4G/5G 2T2R
+ * RF2853 2.4G/5G 3T3R
+ * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
+ * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
+ * RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
*/
#define RF2820 0x0001
#define RF2850 0x0002
@@ -57,7 +61,10 @@
#define RF3021 0x0007
#define RF3022 0x0008
#define RF3052 0x0009
+#define RF2853 0x000a
#define RF3320 0x000b
+#define RF3322 0x000c
+#define RF3853 0x000d
/*
* Chipset revisions.
@@ -206,10 +213,10 @@
/*
* WMM_AIFSN_CFG: Aifsn for each EDCA AC
- * AIFSN0: AC_BE
- * AIFSN1: AC_BK
- * AIFSN2: AC_VI
- * AIFSN3: AC_VO
+ * AIFSN0: AC_VO
+ * AIFSN1: AC_VI
+ * AIFSN2: AC_BE
+ * AIFSN3: AC_BK
*/
#define WMM_AIFSN_CFG 0x0214
#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
@@ -219,10 +226,10 @@
/*
* WMM_CWMIN_CSR: CWmin for each EDCA AC
- * CWMIN0: AC_BE
- * CWMIN1: AC_BK
- * CWMIN2: AC_VI
- * CWMIN3: AC_VO
+ * CWMIN0: AC_VO
+ * CWMIN1: AC_VI
+ * CWMIN2: AC_BE
+ * CWMIN3: AC_BK
*/
#define WMM_CWMIN_CFG 0x0218
#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
@@ -232,10 +239,10 @@
/*
* WMM_CWMAX_CSR: CWmax for each EDCA AC
- * CWMAX0: AC_BE
- * CWMAX1: AC_BK
- * CWMAX2: AC_VI
- * CWMAX3: AC_VO
+ * CWMAX0: AC_VO
+ * CWMAX1: AC_VI
+ * CWMAX2: AC_BE
+ * CWMAX3: AC_BK
*/
#define WMM_CWMAX_CFG 0x021c
#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
@@ -244,18 +251,18 @@
#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)
/*
- * AC_TXOP0: AC_BK/AC_BE TXOP register
- * AC0TXOP: AC_BK in unit of 32us
- * AC1TXOP: AC_BE in unit of 32us
+ * AC_TXOP0: AC_VO/AC_VI TXOP register
+ * AC0TXOP: AC_VO in unit of 32us
+ * AC1TXOP: AC_VI in unit of 32us
*/
#define WMM_TXOP0_CFG 0x0220
#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)
/*
- * AC_TXOP1: AC_VO/AC_VI TXOP register
- * AC2TXOP: AC_VI in unit of 32us
- * AC3TXOP: AC_VO in unit of 32us
+ * AC_TXOP1: AC_BE/AC_BK TXOP register
+ * AC2TXOP: AC_BE in unit of 32us
+ * AC3TXOP: AC_BK in unit of 32us
*/
#define WMM_TXOP1_CFG 0x0224
#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
@@ -281,7 +288,7 @@
#define MCU_CMD_CFG 0x022c
/*
- * AC_BK register offsets
+ * AC_VO register offsets
*/
#define TX_BASE_PTR0 0x0230
#define TX_MAX_CNT0 0x0234
@@ -289,7 +296,7 @@
#define TX_DTX_IDX0 0x023c
/*
- * AC_BE register offsets
+ * AC_VI register offsets
*/
#define TX_BASE_PTR1 0x0240
#define TX_MAX_CNT1 0x0244
@@ -297,7 +304,7 @@
#define TX_DTX_IDX1 0x024c
/*
- * AC_VI register offsets
+ * AC_BE register offsets
*/
#define TX_BASE_PTR2 0x0250
#define TX_MAX_CNT2 0x0254
@@ -305,7 +312,7 @@
#define TX_DTX_IDX2 0x025c
/*
- * AC_VO register offsets
+ * AC_BK register offsets
*/
#define TX_BASE_PTR3 0x0260
#define TX_MAX_CNT3 0x0264
@@ -412,10 +419,22 @@
#define BCN_OFFSET1_BCN7 FIELD32(0xff000000)
/*
- * PBF registers
- * Most are for debug. Driver doesn't touch PBF register.
+ * TXRXQ_PCNT: PBF register
+ * PCNT_TX0Q: Page count for TX hardware queue 0
+ * PCNT_TX1Q: Page count for TX hardware queue 1
+ * PCNT_TX2Q: Page count for TX hardware queue 2
+ * PCNT_RX0Q: Page count for RX hardware queue
*/
#define TXRXQ_PCNT 0x0438
+#define TXRXQ_PCNT_TX0Q FIELD32(0x000000ff)
+#define TXRXQ_PCNT_TX1Q FIELD32(0x0000ff00)
+#define TXRXQ_PCNT_TX2Q FIELD32(0x00ff0000)
+#define TXRXQ_PCNT_RX0Q FIELD32(0xff000000)
+
+/*
+ * PBF register
+ * Debug. Driver doesn't touch PBF register.
+ */
#define PBF_DBG 0x043c
/*
@@ -686,8 +705,18 @@
/*
* CH_TIME_CFG: count as channel busy
+ * EIFS_BUSY: Count EIFS as channel busy
+ * NAV_BUSY: Count NAS as channel busy
+ * RX_BUSY: Count RX as channel busy
+ * TX_BUSY: Count TX as channel busy
+ * TMR_EN: Enable channel statistics timer
*/
#define CH_TIME_CFG 0x110c
+#define CH_TIME_CFG_EIFS_BUSY FIELD32(0x00000010)
+#define CH_TIME_CFG_NAV_BUSY FIELD32(0x00000008)
+#define CH_TIME_CFG_RX_BUSY FIELD32(0x00000004)
+#define CH_TIME_CFG_TX_BUSY FIELD32(0x00000002)
+#define CH_TIME_CFG_TMR_EN FIELD32(0x00000001)
/*
* PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us
@@ -960,8 +989,31 @@
/*
* TXOP_CTRL_CFG:
+ * TIMEOUT_TRUN_EN: Enable/Disable TXOP timeout truncation
+ * AC_TRUN_EN: Enable/Disable truncation for AC change
+ * TXRATEGRP_TRUN_EN: Enable/Disable truncation for TX rate group change
+ * USER_MODE_TRUN_EN: Enable/Disable truncation for user TXOP mode
+ * MIMO_PS_TRUN_EN: Enable/Disable truncation for MIMO PS RTS/CTS
+ * RESERVED_TRUN_EN: Reserved
+ * LSIG_TXOP_EN: Enable/Disable L-SIG TXOP protection
+ * EXT_CCA_EN: Enable/Disable extension channel CCA reference (Defer 40Mhz
+ * transmissions if extension CCA is clear).
+ * EXT_CCA_DLY: Extension CCA signal delay time (unit: us)
+ * EXT_CWMIN: CwMin for extension channel backoff
+ * 0: Disabled
+ *
*/
#define TXOP_CTRL_CFG 0x1340
+#define TXOP_CTRL_CFG_TIMEOUT_TRUN_EN FIELD32(0x00000001)
+#define TXOP_CTRL_CFG_AC_TRUN_EN FIELD32(0x00000002)
+#define TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN FIELD32(0x00000004)
+#define TXOP_CTRL_CFG_USER_MODE_TRUN_EN FIELD32(0x00000008)
+#define TXOP_CTRL_CFG_MIMO_PS_TRUN_EN FIELD32(0x00000010)
+#define TXOP_CTRL_CFG_RESERVED_TRUN_EN FIELD32(0x00000020)
+#define TXOP_CTRL_CFG_LSIG_TXOP_EN FIELD32(0x00000040)
+#define TXOP_CTRL_CFG_EXT_CCA_EN FIELD32(0x00000080)
+#define TXOP_CTRL_CFG_EXT_CCA_DLY FIELD32(0x0000ff00)
+#define TXOP_CTRL_CFG_EXT_CWMIN FIELD32(0x000f0000)
/*
* TX_RTS_CFG:
@@ -1485,17 +1537,17 @@
#define SHARED_KEY_MODE_BASE 0x7000
#define MAC_WCID_ENTRY(__idx) \
- ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) )
+ (MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)))
#define PAIRWISE_KEY_ENTRY(__idx) \
- ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+ (PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)))
#define MAC_IVEIV_ENTRY(__idx) \
- ( MAC_IVEIV_TABLE_BASE + ((__idx) * sizeof(struct mac_iveiv_entry)) )
+ (MAC_IVEIV_TABLE_BASE + ((__idx) * sizeof(struct mac_iveiv_entry)))
#define MAC_WCID_ATTR_ENTRY(__idx) \
- ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) )
+ (MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)))
#define SHARED_KEY_ENTRY(__idx) \
- ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+ (SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)))
#define SHARED_KEY_MODE_ENTRY(__idx) \
- ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) )
+ (SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)))
struct mac_wcid_entry {
u8 mac[6];
@@ -1635,9 +1687,9 @@ struct mac_iveiv_entry {
#define HW_BEACON_BASE7 0x5bc0
#define HW_BEACON_OFFSET(__index) \
- ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \
- (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \
- (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) )
+ (((__index) < 4) ? (HW_BEACON_BASE0 + (__index * 0x0200)) : \
+ (((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \
+ (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))))
/*
* BBP registers.
@@ -1805,32 +1857,51 @@ struct mac_iveiv_entry {
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
- * EEPROM ANTENNA config
+ * EEPROM NIC Configuration 0
* RXPATH: 1: 1R, 2: 2R, 3: 3R
- * TXPATH: 1: 1T, 2: 2T
- */
-#define EEPROM_ANTENNA 0x001a
-#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f)
-#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0)
-#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00)
-
-/*
- * EEPROM NIC config
- * CARDBUS_ACCEL: 0 - enable, 1 - disable
- */
-#define EEPROM_NIC 0x001b
-#define EEPROM_NIC_HW_RADIO FIELD16(0x0001)
-#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002)
-#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004)
-#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008)
-#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010)
-#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020)
-#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040)
-#define EEPROM_NIC_WPS_PBC FIELD16(0x0080)
-#define EEPROM_NIC_BW40M_BG FIELD16(0x0100)
-#define EEPROM_NIC_BW40M_A FIELD16(0x0200)
-#define EEPROM_NIC_ANT_DIVERSITY FIELD16(0x0800)
-#define EEPROM_NIC_DAC_TEST FIELD16(0x8000)
+ * TXPATH: 1: 1T, 2: 2T, 3: 3T
+ * RF_TYPE: RFIC type
+ */
+#define EEPROM_NIC_CONF0 0x001a
+#define EEPROM_NIC_CONF0_RXPATH FIELD16(0x000f)
+#define EEPROM_NIC_CONF0_TXPATH FIELD16(0x00f0)
+#define EEPROM_NIC_CONF0_RF_TYPE FIELD16(0x0f00)
+
+/*
+ * EEPROM NIC Configuration 1
+ * HW_RADIO: 0: disable, 1: enable
+ * EXTERNAL_TX_ALC: 0: disable, 1: enable
+ * EXTERNAL_LNA_2G: 0: disable, 1: enable
+ * EXTERNAL_LNA_5G: 0: disable, 1: enable
+ * CARDBUS_ACCEL: 0: enable, 1: disable
+ * BW40M_SB_2G: 0: disable, 1: enable
+ * BW40M_SB_5G: 0: disable, 1: enable
+ * WPS_PBC: 0: disable, 1: enable
+ * BW40M_2G: 0: enable, 1: disable
+ * BW40M_5G: 0: enable, 1: disable
+ * BROADBAND_EXT_LNA: 0: disable, 1: enable
+ * ANT_DIVERSITY: 00: Disable, 01: Diversity,
+ * 10: Main antenna, 11: Aux antenna
+ * INTERNAL_TX_ALC: 0: disable, 1: enable
+ * BT_COEXIST: 0: disable, 1: enable
+ * DAC_TEST: 0: disable, 1: enable
+ */
+#define EEPROM_NIC_CONF1 0x001b
+#define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
+#define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G FIELD16(0x0004)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_5G FIELD16(0x0008)
+#define EEPROM_NIC_CONF1_CARDBUS_ACCEL FIELD16(0x0010)
+#define EEPROM_NIC_CONF1_BW40M_SB_2G FIELD16(0x0020)
+#define EEPROM_NIC_CONF1_BW40M_SB_5G FIELD16(0x0040)
+#define EEPROM_NIC_CONF1_WPS_PBC FIELD16(0x0080)
+#define EEPROM_NIC_CONF1_BW40M_2G FIELD16(0x0100)
+#define EEPROM_NIC_CONF1_BW40M_5G FIELD16(0x0200)
+#define EEPROM_NIC_CONF1_BROADBAND_EXT_LNA FIELD16(0x400)
+#define EEPROM_NIC_CONF1_ANT_DIVERSITY FIELD16(0x1800)
+#define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
+#define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
+#define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)
/*
* EEPROM frequency
@@ -1852,9 +1923,9 @@ struct mac_iveiv_entry {
* POLARITY_GPIO_4: Polarity GPIO4 setting.
* LED_MODE: Led mode.
*/
-#define EEPROM_LED1 0x001e
-#define EEPROM_LED2 0x001f
-#define EEPROM_LED3 0x0020
+#define EEPROM_LED_AG_CONF 0x001e
+#define EEPROM_LED_ACT_CONF 0x001f
+#define EEPROM_LED_POLARITY 0x0020
#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001)
#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
@@ -1866,6 +1937,17 @@ struct mac_iveiv_entry {
#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
/*
+ * EEPROM NIC Configuration 2
+ * RX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved
+ */
+#define EEPROM_NIC_CONF2 0x0021
+#define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f)
+#define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0)
+#define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600)
+
+/*
* EEPROM LNA
*/
#define EEPROM_LNA 0x0022
@@ -1915,7 +1997,7 @@ struct mac_iveiv_entry {
/*
* EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
- * This is delta in 40MHZ.
+ * This is delta in 40MHZ.
* VALUE: Tx Power dalta value (MAX=4)
* TYPE: 1: Plus the delta value, 0: minus the delta value
* TXPOWER: Enable:
@@ -1971,9 +2053,9 @@ struct mac_iveiv_entry {
#define MCU_CURRENT 0x36
#define MCU_LED 0x50
#define MCU_LED_STRENGTH 0x51
-#define MCU_LED_1 0x52
-#define MCU_LED_2 0x53
-#define MCU_LED_3 0x54
+#define MCU_LED_AG_CONF 0x52
+#define MCU_LED_ACT_CONF 0x53
+#define MCU_LED_LED_POLARITY 0x54
#define MCU_RADAR 0x60
#define MCU_BOOT_SIGNAL 0x72
#define MCU_BBP_SIGNAL 0x80
@@ -1987,8 +2069,8 @@ struct mac_iveiv_entry {
/*
* DMA descriptor defines.
*/
-#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) )
-#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+#define TXWI_DESC_SIZE (4 * sizeof(__le32))
+#define RXWI_DESC_SIZE (4 * sizeof(__le32))
/*
* TX WI structure
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 5f00e00789d8..54917a281398 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -277,13 +277,17 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
unsigned int i;
u32 reg;
+ /*
+ * Some devices are really slow to respond here. Wait a whole second
+ * before timing out.
+ */
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
!rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
return 0;
- msleep(1);
+ msleep(10);
}
ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
@@ -483,7 +487,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
- rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, txdesc->qid);
+ rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid);
rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);
rt2x00_desc_write(txwi, 1, word);
@@ -727,7 +731,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
* that the TX_STA_FIFO stack has a size of 16. We stick to our
* tx ring size for now.
*/
- for (i = 0; i < TX_ENTRIES; i++) {
+ for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
break;
@@ -768,6 +772,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -802,11 +807,13 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with TXWI to register.
+ * Write entire beacon with TXWI and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2800_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -824,7 +831,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
}
EXPORT_SYMBOL_GPL(rt2800_write_beacon);
-static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
+static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
unsigned int beacon_base)
{
int i;
@@ -1144,6 +1151,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
struct rt2x00intf_conf *conf, const unsigned int flags)
{
u32 reg;
+ bool update_bssid = false;
if (flags & CONFIG_UPDATE_TYPE) {
/*
@@ -1173,6 +1181,16 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
}
if (flags & CONFIG_UPDATE_MAC) {
+ if (flags & CONFIG_UPDATE_TYPE &&
+ conf->sync == TSF_SYNC_AP_NONE) {
+ /*
+ * The BSSID register has to be set to our own mac
+ * address in AP mode.
+ */
+ memcpy(conf->bssid, conf->mac, sizeof(conf->mac));
+ update_bssid = true;
+ }
+
if (!is_zero_ether_addr((const u8 *)conf->mac)) {
reg = le32_to_cpu(conf->mac[1]);
rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
@@ -1183,7 +1201,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
conf->mac, sizeof(conf->mac));
}
- if (flags & CONFIG_UPDATE_BSSID) {
+ if ((flags & CONFIG_UPDATE_BSSID) || update_bssid) {
if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
reg = le32_to_cpu(conf->bssid[1]);
rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
@@ -1529,7 +1547,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_rf(rt2x00dev, RF3020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022) ||
- rt2x00_rf(rt2x00dev, RF3052))
+ rt2x00_rf(rt2x00dev, RF3052) ||
+ rt2x00_rf(rt2x00dev, RF3320))
rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -1609,6 +1628,13 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
}
msleep(1);
+
+ /*
+ * Clear channel statistic counters
+ */
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
}
static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
@@ -1914,8 +1940,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2800_register_write(rt2x00dev, TX_SW_CFG2,
0x0000002c);
else
@@ -2097,7 +2123,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
}
- rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f);
+ /*
+ * The legacy driver also sets TXOP_CTRL_CFG_RESERVED_TRUN_EN to 1
+ * although it is reserved.
+ */
+ rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG, &reg);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_TIMEOUT_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_AC_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_USER_MODE_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_MIMO_PS_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_RESERVED_TRUN_EN, 1);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_LSIG_TXOP_EN, 0);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CCA_EN, 0);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CCA_DLY, 88);
+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CWMIN, 0);
+ rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, reg);
+
rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002);
rt2800_register_read(rt2x00dev, TX_RTS_CFG, &reg);
@@ -2134,7 +2176,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
SHARED_KEY_MODE_ENTRY(i), 0);
for (i = 0; i < 256; i++) {
- u32 wcid[2] = { 0xffffffff, 0x00ffffff };
+ static const u32 wcid[2] = { 0xffffffff, 0x00ffffff };
rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
wcid, sizeof(wcid));
@@ -2227,6 +2269,17 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
+ /*
+ * Set up channel statistics timer
+ */
+ rt2800_register_read(rt2x00dev, CH_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_EIFS_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_NAV_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_RX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TMR_EN, 1);
+ rt2800_register_write(rt2x00dev, CH_TIME_CFG, reg);
+
return 0;
}
@@ -2344,10 +2397,10 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2x00_rt(rt2x00dev, RT3390)) {
rt2800_bbp_read(rt2x00dev, 138, &value);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
value |= 0x20;
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
value &= ~0x02;
rt2800_bbp_write(rt2x00dev, 138, value);
@@ -2559,8 +2612,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
else
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
@@ -2633,10 +2686,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT3090)) {
rt2800_bbp_read(rt2x00dev, 138, &bbp);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
rt2800_bbp_write(rt2x00dev, 138, bbp);
@@ -2735,16 +2788,16 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize LED control
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff,
word & 0xff, (word >> 8) & 0xff);
return 0;
@@ -2838,38 +2891,41 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
- if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2)
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
}
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_WPS_PBC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BROADBAND_EXT_LNA, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_ANT_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
@@ -2884,9 +2940,9 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
}
@@ -2950,12 +3006,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read EEPROM word for configuration.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
/*
* Identify RF chipset.
*/
- value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
@@ -2981,7 +3037,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF2020) &&
!rt2x00_rf(rt2x00dev, RF3021) &&
!rt2x00_rf(rt2x00dev, RF3022) &&
- !rt2x00_rf(rt2x00dev, RF3052)) {
+ !rt2x00_rf(rt2x00dev, RF3052) &&
+ !rt2x00_rf(rt2x00dev, RF3320)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -2990,9 +3047,9 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH);
rt2x00dev->default_ant.rx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH);
/*
* Read frequency offset and RF programming sequence.
@@ -3003,17 +3060,17 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read external LNA informations.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
*/
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
@@ -3225,7 +3282,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->max_report_rates = 7;
rt2x00dev->hw->max_rate_tries = 1;
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
/*
* Initialize hw_mode information.
@@ -3245,7 +3302,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
} else if (rt2x00_rf(rt2x00dev, RF3020) ||
rt2x00_rf(rt2x00dev, RF2020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
- rt2x00_rf(rt2x00dev, RF3022)) {
+ rt2x00_rf(rt2x00dev, RF3022) ||
+ rt2x00_rf(rt2x00dev, RF3320)) {
spec->num_channels = 14;
spec->channels = rf_vals_3x;
} else if (rt2x00_rf(rt2x00dev, RF3052)) {
@@ -3268,11 +3326,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40;
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) >= 2)
spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
spec->ht.cap |=
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) <<
IEEE80211_HT_CAP_RX_STBC_SHIFT;
spec->ht.ampdu_factor = 3;
@@ -3280,10 +3338,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
- ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
+ ((rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
- switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
@@ -3502,6 +3560,37 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ u32 idle, busy, busy_ext;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
+
+ if (idle || busy) {
+ survey->filled = SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+
+ survey->channel_time = (idle + busy) / 1000;
+ survey->channel_time_busy = busy / 1000;
+ survey->channel_time_ext_busy = busy_ext / 1000;
+ }
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(rt2800_get_survey);
+
MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 library");
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 81cbc92e7857..e3c995a9dec4 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -199,5 +199,7 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey);
#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b26739535986..aa97971a38af 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -84,20 +84,22 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
-#ifdef CONFIG_RT2800PCI_SOC
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
- u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
+ void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+
+ iounmap(base_addr);
}
#else
static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
}
-#endif /* CONFIG_RT2800PCI_SOC */
+#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
{
struct rt2x00_dev *rt2x00dev = eeprom->data;
@@ -181,7 +183,78 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
}
-#endif /* CONFIG_RT2800PCI_PCI */
+#endif /* CONFIG_PCI */
+
+/*
+ * Queue handlers.
+ */
+static void rt2800pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ };
+}
+
+static void rt2800pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
+ break;
+ case QID_MGMT:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
/*
* Firmware functions
@@ -321,18 +394,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON) ||
- (state == STATE_RADIO_RX_ON_LINK));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -442,7 +503,7 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
* if the device is booting and wasn't asleep it will return
* failure when attempting to wakeup.
*/
- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
+ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2);
if (state == STATE_AWAKE) {
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0);
@@ -476,12 +537,6 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_disable_radio(rt2x00dev);
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt2800pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -567,41 +622,6 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
}
/*
- * TX data initialization
- */
-static void rt2800pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
- unsigned int qidx;
-
- if (queue->qid == QID_MGMT)
- qidx = 5;
- else
- qidx = queue->qid;
-
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
-}
-
-static void rt2800pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
- return;
- }
-
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-}
-
-/*
* RX control handlers
*/
static void rt2800pci_fill_rxdone(struct queue_entry *entry,
@@ -668,14 +688,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
u32 status;
u8 qid;
- while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
- /* Now remove the tx status from the FIFO */
- if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
- sizeof(status)) != sizeof(status)) {
- WARN_ON(1);
- break;
- }
-
+ while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
if (qid >= QID_RX) {
/*
@@ -683,7 +696,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* this tx status.
*/
WARNING(rt2x00dev, "Got TX status report with "
- "unexpected pid %u, dropping", qid);
+ "unexpected pid %u, dropping\n", qid);
break;
}
@@ -694,7 +707,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* processing here and drop the tx status
*/
WARNING(rt2x00dev, "Got TX status for an unavailable "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}
@@ -704,7 +717,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* and drop the tx status.
*/
WARNING(rt2x00dev, "Got TX status for an empty "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}
@@ -777,20 +790,13 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
* Since we have only one producer and one consumer we don't
* need to lock the kfifo.
*/
- for (i = 0; i < TX_ENTRIES; i++) {
+ for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
- if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
- WARNING(rt2x00dev, "TX status FIFO overrun,"
- " drop tx status report.\n");
- break;
- }
-
- if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
- sizeof(status)) != sizeof(status)) {
+ if (!kfifo_put(&rt2x00dev->txstatus_fifo, &status)) {
WARNING(rt2x00dev, "TX status FIFO overrun,"
"drop tx status report.\n");
break;
@@ -912,6 +918,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
@@ -943,6 +950,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
+ .flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
@@ -975,11 +984,12 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .start_queue = rt2800pci_start_queue,
+ .kick_queue = rt2800pci_kick_queue,
+ .stop_queue = rt2800pci_stop_queue,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
- .kick_tx_queue = rt2800pci_kick_tx_queue,
- .kill_tx_queue = rt2800pci_kill_tx_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
@@ -991,21 +1001,21 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
};
static const struct data_queue_desc rt2800pci_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 128,
.data_size = AGGREGATION_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2800pci_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 64,
.data_size = AGGREGATION_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2800pci_queue_bcn = {
- .entry_num = 8 * BEACON_ENTRIES,
+ .entry_num = 8,
.data_size = 0, /* No DMA required for beacons */
.desc_size = TXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
@@ -1033,12 +1043,15 @@ static const struct rt2x00_ops rt2800pci_ops = {
/*
* RT2800pci module information.
*/
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
@@ -1046,12 +1059,10 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
-#ifdef CONFIG_RT2800PCI_RT30XX
- { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+#ifdef CONFIG_RT2800PCI_RT33XX
+ { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) },
#endif
#ifdef CONFIG_RT2800PCI_RT35XX
{ PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
@@ -1062,19 +1073,19 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
#endif
{ 0, }
};
-#endif /* CONFIG_RT2800PCI_PCI */
+#endif /* CONFIG_PCI */
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards");
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
MODULE_FIRMWARE(FIRMWARE_RT2860);
MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
-#endif /* CONFIG_RT2800PCI_PCI */
+#endif /* CONFIG_PCI */
MODULE_LICENSE("GPL");
-#ifdef CONFIG_RT2800PCI_SOC
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
static int rt2800soc_probe(struct platform_device *pdev)
{
return rt2x00soc_probe(pdev, &rt2800pci_ops);
@@ -1091,9 +1102,9 @@ static struct platform_driver rt2800soc_driver = {
.suspend = rt2x00soc_suspend,
.resume = rt2x00soc_resume,
};
-#endif /* CONFIG_RT2800PCI_SOC */
+#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
static struct pci_driver rt2800pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2800pci_device_table,
@@ -1102,21 +1113,21 @@ static struct pci_driver rt2800pci_driver = {
.suspend = rt2x00pci_suspend,
.resume = rt2x00pci_resume,
};
-#endif /* CONFIG_RT2800PCI_PCI */
+#endif /* CONFIG_PCI */
static int __init rt2800pci_init(void)
{
int ret = 0;
-#ifdef CONFIG_RT2800PCI_SOC
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
ret = platform_driver_register(&rt2800soc_driver);
if (ret)
return ret;
#endif
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
ret = pci_register_driver(&rt2800pci_driver);
if (ret) {
-#ifdef CONFIG_RT2800PCI_SOC
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
platform_driver_unregister(&rt2800soc_driver);
#endif
return ret;
@@ -1128,10 +1139,10 @@ static int __init rt2800pci_init(void)
static void __exit rt2800pci_exit(void)
{
-#ifdef CONFIG_RT2800PCI_PCI
+#ifdef CONFIG_PCI
pci_unregister_driver(&rt2800pci_driver);
#endif
-#ifdef CONFIG_RT2800PCI_SOC
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
platform_driver_unregister(&rt2800soc_driver);
#endif
}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
index 5a8dda9b5b5a..70e050d904c8 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.h
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -38,10 +38,10 @@
* Queue register offset macros
*/
#define TX_QUEUE_REG_OFFSET 0x10
-#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET)
-#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET)
-#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
-#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_BASE_PTR(__x) (TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET))
+#define TX_MAX_CNT(__x) (TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET))
+#define TX_CTX_IDX(__x) (TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET))
+#define TX_DTX_IDX(__x) (TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET))
/*
* 8051 firmware image.
@@ -52,8 +52,8 @@
/*
* DMA descriptor defines.
*/
-#define TXD_DESC_SIZE ( 4 * sizeof(__le32) )
-#define RXD_DESC_SIZE ( 4 * sizeof(__le32) )
+#define TXD_DESC_SIZE (4 * sizeof(__le32))
+#define RXD_DESC_SIZE (4 * sizeof(__le32))
/*
* TX descriptor format for TX, PRIO and Beacon Ring.
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 3dff56ec195a..b97a4a54ff4c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -45,11 +45,60 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 0;
+static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
+ * Queue handlers.
+ */
+static void rt2800usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -107,18 +156,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Device state switch handlers.
*/
-static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON) ||
- (state == STATE_RADIO_RX_ON_LINK));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -165,7 +202,8 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
* this limit so reduce the number to prevent errors.
*/
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_LIMIT,
- ((RX_ENTRIES * DATA_FRAME_SIZE) / 1024) - 3);
+ ((rt2x00dev->ops->rx->entry_num * DATA_FRAME_SIZE)
+ / 1024) - 3);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_EN, 1);
rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
@@ -183,9 +221,9 @@ static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
if (state == STATE_AWAKE)
- rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 2);
else
- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
+ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2);
return 0;
}
@@ -214,12 +252,6 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_disable_radio(rt2x00dev);
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt2800usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -245,6 +277,49 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
}
/*
+ * Watchdog handlers
+ */
+static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+ if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
+ WARNING(rt2x00dev, "TX HW queue 0 timed out,"
+ " invoke forced kick\n");
+
+ rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);
+
+ for (i = 0; i < 10; i++) {
+ udelay(10);
+ if (!rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q))
+ break;
+ }
+
+ rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+ }
+
+ rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+ if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
+ WARNING(rt2x00dev, "TX HW queue 1 timed out,"
+ " invoke forced kick\n");
+
+ rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
+
+ for (i = 0; i < 10; i++) {
+ udelay(10);
+ if (!rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q))
+ break;
+ }
+
+ rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+ }
+
+ rt2x00usb_watchdog(rt2x00dev);
+}
+
+/*
* TX descriptor initialization
*/
static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
@@ -266,8 +341,14 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
* Initialize TXINFO descriptor
*/
rt2x00_desc_read(txi, 0, &word);
+
+ /*
+ * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is
+ * TXWI + 802.11 header + L2 pad + payload + pad,
+ * so need to decrease size of TXINFO and USB end pad.
+ */
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
- entry->skb->len - TXINFO_DESC_SIZE);
+ entry->skb->len - TXINFO_DESC_SIZE - 4);
rt2x00_set_field32(&word, TXINFO_W0_WIV,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -285,22 +366,37 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
}
-/*
- * TX data initialization
- */
-static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
+static void rt2800usb_write_tx_data(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
- int length;
+ unsigned int len;
+ int err;
+
+ rt2800_write_tx_data(entry, txdesc);
/*
- * The length _must_ include 4 bytes padding,
- * it should always be multiple of 4,
- * but it must _not_ be a multiple of the USB packet size.
+ * pad(1~3 bytes) is added after each 802.11 payload.
+ * USB end pad(4 bytes) is added at each USB bulk out packet end.
+ * TX frame format is :
+ * | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
+ * |<------------- tx_pkt_len ------------->|
*/
- length = roundup(entry->skb->len + 4, 4);
- length += (4 * !(length % entry->queue->usb_maxpacket));
+ len = roundup(entry->skb->len, 4) + 4;
+ err = skb_padto(entry->skb, len);
+ if (unlikely(err)) {
+ WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
+ return;
+ }
- return length;
+ entry->skb->len = len;
+}
+
+/*
+ * TX data initialization
+ */
+static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
+{
+ return entry->skb->len;
}
/*
@@ -335,14 +431,6 @@ static void rt2800usb_work_txdone(struct work_struct *work)
}
}
-static void rt2800usb_kill_tx_queue(struct data_queue *queue)
-{
- if (queue->qid == QID_BEACON)
- rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -507,6 +595,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
+ .flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};
static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -535,13 +625,15 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
- .watchdog = rt2x00usb_watchdog,
+ .watchdog = rt2800usb_watchdog,
+ .start_queue = rt2800usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2800usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2800usb_write_tx_desc,
- .write_tx_data = rt2800_write_tx_data,
+ .write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2800usb_kill_tx_queue,
.fill_rxdone = rt2800usb_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
@@ -553,21 +645,21 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
};
static const struct data_queue_desc rt2800usb_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 128,
.data_size = AGGREGATION_SIZE,
.desc_size = RXINFO_DESC_SIZE + RXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2800usb_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 64,
.data_size = AGGREGATION_SIZE,
.desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2800usb_queue_bcn = {
- .entry_num = 8 * BEACON_ENTRIES,
+ .entry_num = 8,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
@@ -599,11 +691,19 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Abocom */
{ USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* AirTies */
+ { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Allwin */
{ USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amit */
{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Askey */
@@ -612,8 +712,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -624,6 +729,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -632,17 +738,36 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Draytek */
+ { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Edimax */
+ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Encore */
+ { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Hawking */
{ USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -651,6 +776,10 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* I-O DATA */
+ { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Linksys */
{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -658,17 +787,44 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Motorola */
{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
/* MSI */
+ { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Para */
+ { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Pegatron */
+ { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Philips */
{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Planex */
+ { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Quanta */
+ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
+ { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Samsung */
{ USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Siemens */
@@ -681,13 +837,22 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sparklan */
{ USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -701,101 +866,16 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zyxel */
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
-#ifdef CONFIG_RT2800USB_RT30XX
- /* Abocom */
- { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* AirTies */
- { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Allwin */
- { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* ASUS */
- { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* AzureWave */
- { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Conceptronic */
- { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Corega */
- { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* D-Link */
- { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Draytek */
- { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Edimax */
- { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Encore */
- { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* EnGenius */
- { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Gigabyte */
- { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* I-O DATA */
- { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Logitec */
- { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* MSI */
- { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Para */
- { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Pegatron */
- { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Planex */
- { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Quanta */
- { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
+#ifdef CONFIG_RT2800USB_RT33XX
/* Ralink */
- { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* SMC */
- { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Zinwell */
- { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
#endif
#ifdef CONFIG_RT2800USB_RT35XX
/* Allwin */
@@ -809,12 +889,9 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* I-O DATA */
{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
- { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
#endif
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 0722badccf86..671ea3592610 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -40,8 +40,8 @@
/*
* DMA descriptor defines.
*/
-#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
-#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
+#define TXINFO_DESC_SIZE (1 * sizeof(__le32))
+#define RXINFO_DESC_SIZE (1 * sizeof(__le32))
/*
* TX Info structure
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 94fe589acfaa..84aaf393da43 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -66,7 +66,7 @@
#ifdef CONFIG_RT2X00_DEBUG
#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
- DEBUG_PRINTK_MSG(__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)
@@ -347,6 +347,10 @@ struct link {
struct delayed_work watchdog_work;
};
+enum rt2x00_delayed_flags {
+ DELAYED_UPDATE_BEACON,
+};
+
/*
* Interface structure
* Per interface configuration details, this structure
@@ -354,22 +358,6 @@ struct link {
*/
struct rt2x00_intf {
/*
- * All fields within the rt2x00_intf structure
- * must be protected with a spinlock.
- */
- spinlock_t lock;
-
- /*
- * MAC of the device.
- */
- u8 mac[ETH_ALEN];
-
- /*
- * BBSID of the AP to associate with.
- */
- u8 bssid[ETH_ALEN];
-
- /*
* beacon->skb must be protected with the mutex.
*/
struct mutex beacon_skb_mutex;
@@ -384,8 +372,7 @@ struct rt2x00_intf {
/*
* Actions that needed rescheduling.
*/
- unsigned int delayed_flags;
-#define DELAYED_UPDATE_BEACON 0x00000001
+ unsigned long delayed_flags;
/*
* Software sequence counter, this is only required
@@ -567,7 +554,15 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
+
+ /*
+ * Data queue handlers.
+ */
void (*watchdog) (struct rt2x00_dev *rt2x00dev);
+ void (*start_queue) (struct data_queue *queue);
+ void (*kick_queue) (struct data_queue *queue);
+ void (*stop_queue) (struct data_queue *queue);
+ void (*flush_queue) (struct data_queue *queue);
/*
* TX control handlers
@@ -579,8 +574,6 @@ struct rt2x00lib_ops {
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
- void (*kick_tx_queue) (struct data_queue *queue);
- void (*kill_tx_queue) (struct data_queue *queue);
/*
* RX control handlers
@@ -664,6 +657,7 @@ enum rt2x00_flags {
DRIVER_REQUIRE_COPY_IV,
DRIVER_REQUIRE_L2PAD,
DRIVER_REQUIRE_TXSTATUS_FIFO,
+ DRIVER_REQUIRE_TASKLET_CONTEXT,
/*
* Driver features
@@ -901,7 +895,7 @@ struct rt2x00_dev {
/*
* FIFO for storing tx status reports between isr and tasklet.
*/
- struct kfifo txstatus_fifo;
+ DECLARE_KFIFO_PTR(txstatus_fifo, u32);
/*
* Tasklet for processing tx status reports (rt2800pci).
@@ -915,7 +909,7 @@ struct rt2x00_dev {
* in those cases REGISTER_BUSY_COUNT attempts should be
* taken with a REGISTER_BUSY_DELAY interval.
*/
-#define REGISTER_BUSY_COUNT 5
+#define REGISTER_BUSY_COUNT 100
#define REGISTER_BUSY_DELAY 100
/*
@@ -1067,6 +1061,78 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
+/**
+ * rt2x00queue_pause_queue - Pause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will pause the data queue locally, preventing
+ * new frames to be added to the queue (while the hardware is
+ * still allowed to run).
+ */
+void rt2x00queue_pause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_unpause_queue - unpause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will unpause the data queue locally, allowing
+ * new frames to be added to the queue again.
+ */
+void rt2x00queue_unpause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_start_queue - Start a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will start handling all pending frames in the queue.
+ */
+void rt2x00queue_start_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_stop_queue - Halt a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will stop all pending frames in the queue.
+ */
+void rt2x00queue_stop_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_flush_queue - Flush a data queue
+ * @queue: Pointer to &struct data_queue.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will flush the queue. After this call
+ * the queue is guarenteed to be empty.
+ */
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop);
+
+/**
+ * rt2x00queue_start_queues - Start all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to start them
+ */
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00queue_stop_queues - Halt all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to stop
+ * any pending frames.
+ */
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00queue_flush_queues - Flush all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will loop through all available queues to flush
+ * any pending frames.
+ */
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop);
+
/*
* Debugfs handlers.
*/
@@ -1092,6 +1158,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmastart(struct queue_entry *entry);
void rt2x00lib_dmadone(struct queue_entry *entry);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
@@ -1133,6 +1200,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
+void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 54ffb5aeb34e..e7f67d5eda52 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -62,13 +62,13 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
* This will prevent the device being confused when it wants
* to ACK frames or consideres itself associated.
*/
- memset(&conf.mac, 0, sizeof(conf.mac));
+ memset(conf.mac, 0, sizeof(conf.mac));
if (mac)
- memcpy(&conf.mac, mac, ETH_ALEN);
+ memcpy(conf.mac, mac, ETH_ALEN);
- memset(&conf.bssid, 0, sizeof(conf.bssid));
+ memset(conf.bssid, 0, sizeof(conf.bssid));
if (bssid)
- memcpy(&conf.bssid, bssid, ETH_ALEN);
+ memcpy(conf.bssid, bssid, ETH_ALEN);
flags |= CONFIG_UPDATE_TYPE;
if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
@@ -133,7 +133,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
*/
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
- else if(config.rx == ANTENNA_SW_DIVERSITY)
+ else if (config.rx == ANTENNA_SW_DIVERSITY)
config.rx = active->rx;
if (!(ant->flags & ANTENNA_TX_DIVERSITY))
@@ -146,7 +146,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
+ rt2x00queue_stop_queue(rt2x00dev->rx);
/*
* Write new antenna setup to device and reset the link tuner.
@@ -160,7 +160,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
memcpy(active, &config, sizeof(config));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
+ rt2x00queue_start_queue(rt2x00dev->rx);
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index fcdb6b0dc40f..c92db3264741 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -162,11 +162,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
struct timeval timestamp;
u32 data_len;
- do_gettimeofday(&timestamp);
-
- if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
+ if (likely(!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)))
return;
+ do_gettimeofday(&timestamp);
+
if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
return;
@@ -339,18 +339,19 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
return -ENOMEM;
temp = data +
- sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
+ sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
queue_for_each(intf->rt2x00dev, queue) {
- spin_lock_irqsave(&queue->lock, irqflags);
+ spin_lock_irqsave(&queue->index_lock, irqflags);
- temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
+ temp += sprintf(temp, "%d\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n",
+ queue->qid, (unsigned int)queue->flags,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
queue->index[Q_INDEX_DMA_DONE],
queue->index[Q_INDEX_DONE]);
- spin_unlock_irqrestore(&queue->lock, irqflags);
+ spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
size = strlen(data);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 5ba79b935f09..9597a03242cc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -66,20 +66,16 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
/*
- * Enable RX.
+ * Enable queues.
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00queue_start_queues(rt2x00dev);
+ rt2x00link_start_tuner(rt2x00dev);
/*
* Start watchdog monitoring.
*/
rt2x00link_start_watchdog(rt2x00dev);
- /*
- * Start the TX queues.
- */
- ieee80211_wake_queues(rt2x00dev->hw);
-
return 0;
}
@@ -89,20 +85,16 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Stop the TX queues in mac80211.
- */
- ieee80211_stop_queues(rt2x00dev->hw);
- rt2x00queue_stop_queues(rt2x00dev);
-
- /*
* Stop watchdog monitoring.
*/
rt2x00link_stop_watchdog(rt2x00dev);
/*
- * Disable RX.
+ * Stop all queues
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00link_stop_tuner(rt2x00dev);
+ rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00queue_flush_queues(rt2x00dev, true);
/*
* Disable radio.
@@ -113,41 +105,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00leds_led_radio(rt2x00dev, false);
}
-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)
- rt2x00link_stop_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)
- rt2x00link_start_tuner(rt2x00dev);
-}
-
static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int delayed_flags;
-
- /*
- * Copy all data we need during this action under the protection
- * of a spinlock. Otherwise race conditions might occur which results
- * into an invalid configuration.
- */
- spin_lock(&intf->lock);
-
- delayed_flags = intf->delayed_flags;
- intf->delayed_flags = 0;
-
- spin_unlock(&intf->lock);
/*
* It is possible the radio was disabled while the work had been
@@ -158,7 +120,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- if (delayed_flags & DELAYED_UPDATE_BEACON)
+ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
rt2x00queue_update_beacon(rt2x00dev, vif, true);
}
@@ -251,8 +213,16 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+void rt2x00lib_dmastart(struct queue_entry *entry)
+{
+ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
+
void rt2x00lib_dmadone(struct queue_entry *entry)
{
+ set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
}
@@ -264,11 +234,9 @@ void rt2x00lib_txdone(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
- unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+ unsigned int header_length, i;
u8 rate_idx, rate_flags, retry_rates;
u8 skbdesc_flags = skbdesc->flags;
- unsigned int i;
bool success;
/*
@@ -287,6 +255,11 @@ void rt2x00lib_txdone(struct queue_entry *entry,
skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
/*
+ * Determine the length of 802.11 header.
+ */
+ header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+
+ /*
* Remove L2 padding which was added during
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
@@ -390,9 +363,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* through a mac80211 library call (RTS/CTS) then we should not
* send the status report back.
*/
- if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- ieee80211_tx_status(rt2x00dev->hw, entry->skb);
- else
+ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
+ if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags))
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+ else
+ ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
+ } else
dev_kfree_skb_any(entry->skb);
/*
@@ -411,7 +387,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_threshold(entry->queue))
- ieee80211_wake_queue(rt2x00dev->hw, qid);
+ rt2x00queue_unpause_queue(entry->queue);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -483,6 +459,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
unsigned int header_length;
int rate_idx;
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+ !test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ goto submit_entry;
+
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
goto submit_entry;
@@ -567,9 +547,11 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
entry->skb = skb;
submit_entry:
- rt2x00dev->ops->lib->clear_entry(entry);
- rt2x00queue_index_inc(entry->queue, Q_INDEX);
+ entry->flags = 0;
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+ test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2x00dev->ops->lib->clear_entry(entry);
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -678,7 +660,7 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry,
{
entry->flags = 0;
entry->bitrate = rate->bitrate;
- entry->hw_value =index;
+ entry->hw_value = index;
entry->hw_value_short = index;
if (rate->flags & DEV_RATE_SHORT_PREAMBLE)
@@ -818,8 +800,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Allocate tx status FIFO for driver use.
*/
- if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->txstatus_tasklet) {
+ if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
/*
* Allocate txstatus fifo and tasklet, we use a size of 512
* for the kfifo which is big enough to store 512/4=128 tx
@@ -833,9 +814,10 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
return status;
/* tasklet for processing the tx status reports. */
- tasklet_init(&rt2x00dev->txstatus_tasklet,
- rt2x00dev->ops->lib->txstatus_tasklet,
- (unsigned long)rt2x00dev);
+ if (rt2x00dev->ops->lib->txstatus_tasklet)
+ tasklet_init(&rt2x00dev->txstatus_tasklet,
+ rt2x00dev->ops->lib->txstatus_tasklet,
+ (unsigned long)rt2x00dev);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index c637bcaec5f8..b7ad46ecaa1d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -40,8 +40,6 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
if (tx_info->control.sta)
txdesc->mpdu_density =
tx_info->control.sta->ht_cap.ampdu_density;
- else
- txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 619da23b7b56..a105c500627b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -57,7 +57,7 @@ static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value)
}
#define RATE_MCS(__mode, __mcs) \
- ( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) )
+ ((((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff))
static inline int rt2x00_get_rate_mcs(const u16 mcs_value)
{
@@ -69,7 +69,6 @@ static inline int rt2x00_get_rate_mcs(const u16 mcs_value)
*/
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);
/*
* Initialization handlers.
@@ -179,15 +178,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
/**
- * rt2x00queue_stop_queues - Halt all data queues
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- *
- * This function will loop through all available queues to stop
- * any pending outgoing frames.
- */
-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
-
-/**
* rt2x00queue_init_queues - Initialize all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index b971d8798ebf..bfda60eaf4ef 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -67,7 +67,7 @@
(__avg).avg_weight ? \
((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
((__val) * (AVG_FACTOR))) / \
- (AVG_SAMPLES) ) : \
+ (AVG_SAMPLES)) : \
((__val) * (AVG_FACTOR)); \
__new.avg = __new.avg_weight / (AVG_FACTOR); \
__new; \
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c3c206a97d54..f3da051df39e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -104,7 +104,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
enum data_queue_qid qid = skb_get_queue_mapping(skb);
- struct data_queue *queue;
+ struct data_queue *queue = NULL;
/*
* Mac80211 might be calling this function while we are trying
@@ -153,7 +153,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
goto exit_fail;
if (rt2x00queue_threshold(queue))
- ieee80211_stop_queue(rt2x00dev->hw, qid);
+ rt2x00queue_pause_queue(queue);
return NETDEV_TX_OK;
@@ -268,13 +268,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
else
rt2x00dev->intf_sta_count++;
- spin_lock_init(&intf->lock);
spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
/*
- * The MAC adddress must be configured after the device
+ * The MAC address must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
* The BSSID address must only be configured in AP mode,
@@ -282,15 +281,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* STA interfaces at this time, since this can cause
* invalid behavior in the device.
*/
- memcpy(&intf->mac, vif->addr, ETH_ALEN);
- if (vif->type == NL80211_IFTYPE_AP) {
- memcpy(&intf->bssid, vif->addr, ETH_ALEN);
- rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
- intf->mac, intf->bssid);
- } else {
- rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
- intf->mac, NULL);
- }
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+ vif->addr, NULL);
/*
* Some filters depend on the current working mode. We can force
@@ -358,7 +350,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
+ rt2x00queue_stop_queue(rt2x00dev->rx);
/*
* When we've just turned on the radio, we want to reprogram
@@ -376,7 +368,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Turn RX back on */
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
+ rt2x00queue_start_queue(rt2x00dev->rx);
return 0;
}
@@ -451,9 +443,7 @@ static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
- spin_lock(&intf->lock);
- intf->delayed_flags |= DELAYED_UPDATE_BEACON;
- spin_unlock(&intf->lock);
+ set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags);
}
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
@@ -478,17 +468,17 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
- memcpy(&crypto->key,
+ memcpy(crypto->key,
&key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
sizeof(crypto->key));
if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
- memcpy(&crypto->tx_mic,
+ memcpy(crypto->tx_mic,
&key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
sizeof(crypto->tx_mic));
if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
- memcpy(&crypto->rx_mic,
+ memcpy(crypto->rx_mic,
&key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
sizeof(crypto->rx_mic));
}
@@ -498,7 +488,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(vif);
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
@@ -522,7 +511,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (rt2x00dev->intf_sta_count)
crypto.bssidx = 0;
else
- crypto.bssidx = intf->mac[5] & (rt2x00dev->ops->max_ap_intf - 1);
+ crypto.bssidx = vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
@@ -540,7 +529,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (crypto.cipher == CIPHER_TKIP)
memcpy_tkip(&crypto, &key->key[0], key->keylen);
else
- memcpy(&crypto.key, &key->key[0], key->keylen);
+ memcpy(crypto.key, &key->key[0], key->keylen);
/*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
@@ -620,22 +609,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
- spin_lock(&intf->lock);
-
/*
- * conf->bssid can be NULL if coming from the internal
- * beacon update routine.
- */
- if (changes & BSS_CHANGED_BSSID)
- memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
-
- spin_unlock(&intf->lock);
-
- /*
- * Call rt2x00_config_intf() outside of the spinlock context since
- * the call will sleep for USB drivers. By using the ieee80211_if_conf
- * values as arguments we make keep access to rt2x00_intf thread safe
- * even without the lock.
+ * Update the BSSID.
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
@@ -719,3 +694,13 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(hw->wiphy, !active);
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
+
+void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_flush);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 2449d785cf8d..ace0b668c04e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -82,6 +82,13 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
skbdesc->desc_len = entry->queue->desc_size;
/*
+ * DMA is already done, notify rt2x00lib that
+ * it finished successfully.
+ */
+ rt2x00lib_dmastart(entry);
+ rt2x00lib_dmadone(entry);
+
+ /*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry);
@@ -105,7 +112,7 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
*/
addr = dma_alloc_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
- &dma, GFP_KERNEL | GFP_DMA);
+ &dma, GFP_KERNEL);
if (!addr)
return -ENOMEM;
@@ -279,7 +286,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
- if (pci_dev->is_pcie)
+ if (pci_is_pcie(pci_dev))
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
else
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
@@ -356,12 +363,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
struct rt2x00_dev *rt2x00dev = hw->priv;
if (pci_set_power_state(pci_dev, PCI_D0) ||
- pci_enable_device(pci_dev) ||
- pci_restore_state(pci_dev)) {
+ pci_enable_device(pci_dev)) {
ERROR(rt2x00dev, "Failed to resume device.\n");
return -EIO;
}
+ pci_restore_state(pci_dev);
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index b854d62ff99b..746ce8fe8cf4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -64,7 +64,7 @@ static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const void *value,
const u32 length)
{
- memcpy_toio(rt2x00dev->csr.base + offset, value, length);
+ __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
}
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index e360d287defb..ca82b3a91697 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -199,7 +199,12 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
{
- unsigned int l2pad = L2PAD_SIZE(header_length);
+ /*
+ * L2 padding is only present if the skb contains more than just the
+ * IEEE 802.11 header.
+ */
+ unsigned int l2pad = (skb->len > header_length) ?
+ L2PAD_SIZE(header_length) : 0;
if (!l2pad)
return;
@@ -311,14 +316,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
memset(txdesc, 0, sizeof(*txdesc));
/*
- * Initialize information from queue
- */
- txdesc->qid = entry->queue->qid;
- txdesc->cw_min = entry->queue->cw_min;
- txdesc->cw_max = entry->queue->cw_max;
- txdesc->aifs = entry->queue->aifs;
-
- /*
* Header and frame information.
*/
txdesc->length = entry->skb->len;
@@ -460,12 +457,9 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
-static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
+static void rt2x00queue_kick_tx_queue(struct data_queue *queue,
struct txentry_desc *txdesc)
{
- struct data_queue *queue = entry->queue;
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-
/*
* Check if we need to kick the queue, there are however a few rules
* 1) Don't kick unless this is the last in frame in a burst.
@@ -477,7 +471,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
*/
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
- rt2x00dev->ops->lib->kick_tx_queue(queue);
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
}
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -567,7 +561,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
rt2x00queue_index_inc(queue, Q_INDEX);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
- rt2x00queue_kick_tx_queue(entry, &txdesc);
+ rt2x00queue_kick_tx_queue(queue, &txdesc);
return 0;
}
@@ -591,7 +585,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_free_skb(intf->beacon);
if (!enable_beacon) {
- rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
+ rt2x00queue_stop_queue(intf->beacon->queue);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
@@ -649,10 +643,10 @@ void rt2x00queue_for_each_entry(struct data_queue *queue,
* it should not be kicked during this run, since it
* is part of another TX operation.
*/
- spin_lock_irqsave(&queue->lock, irqflags);
+ spin_lock_irqsave(&queue->index_lock, irqflags);
index_start = queue->index[start];
index_end = queue->index[end];
- spin_unlock_irqrestore(&queue->lock, irqflags);
+ spin_unlock_irqrestore(&queue->index_lock, irqflags);
/*
* Start from the TX done pointer, this guarentees that we will
@@ -706,11 +700,11 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
return NULL;
}
- spin_lock_irqsave(&queue->lock, irqflags);
+ spin_lock_irqsave(&queue->index_lock, irqflags);
entry = &queue->entries[queue->index[index]];
- spin_unlock_irqrestore(&queue->lock, irqflags);
+ spin_unlock_irqrestore(&queue->index_lock, irqflags);
return entry;
}
@@ -726,7 +720,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
return;
}
- spin_lock_irqsave(&queue->lock, irqflags);
+ spin_lock_irqsave(&queue->index_lock, irqflags);
queue->index[index]++;
if (queue->index[index] >= queue->limit)
@@ -741,15 +735,219 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
queue->count++;
}
- spin_unlock_irqrestore(&queue->lock, irqflags);
+ spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ /*
+ * For TX queues, we have to disable the queue
+ * inside mac80211.
+ */
+ ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
+
+void rt2x00queue_unpause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ !test_and_clear_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ /*
+ * For TX queues, we have to enable the queue
+ * inside mac80211.
+ */
+ ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ case QID_RX:
+ /*
+ * For RX we need to kick the queue now in order to
+ * receive frames.
+ */
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_unpause_queue);
+
+void rt2x00queue_start_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ test_and_set_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ set_bit(QUEUE_PAUSED, &queue->flags);
+
+ queue->rt2x00dev->ops->lib->start_queue(queue);
+
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queue);
+
+void rt2x00queue_stop_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_and_clear_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ rt2x00queue_pause_queue(queue);
+
+ queue->rt2x00dev->ops->lib->stop_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
+
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+ bool started;
+ bool tx_queue =
+ (queue->qid == QID_AC_VO) ||
+ (queue->qid == QID_AC_VI) ||
+ (queue->qid == QID_AC_BE) ||
+ (queue->qid == QID_AC_BK);
+
+ mutex_lock(&queue->status_lock);
+
+ /*
+ * If the queue has been started, we must stop it temporarily
+ * to prevent any new frames to be queued on the device. If
+ * we are not dropping the pending frames, the queue must
+ * only be stopped in the software and not the hardware,
+ * otherwise the queue will never become empty on its own.
+ */
+ started = test_bit(QUEUE_STARTED, &queue->flags);
+ if (started) {
+ /*
+ * Pause the queue
+ */
+ rt2x00queue_pause_queue(queue);
+
+ /*
+ * If we are not supposed to drop any pending
+ * frames, this means we must force a start (=kick)
+ * to the queue to make sure the hardware will
+ * start transmitting.
+ */
+ if (!drop && tx_queue)
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ }
+
+ /*
+ * Check if driver supports flushing, we can only guarentee
+ * full support for flushing if the driver is able
+ * to cancel all pending frames (drop = true).
+ */
+ if (drop && queue->rt2x00dev->ops->lib->flush_queue)
+ queue->rt2x00dev->ops->lib->flush_queue(queue);
+
+ /*
+ * When we don't want to drop any frames, or when
+ * the driver doesn't fully flush the queue correcly,
+ * we must wait for the queue to become empty.
+ */
+ for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
+ msleep(10);
+
+ /*
+ * The queue flush has failed...
+ */
+ if (unlikely(!rt2x00queue_empty(queue)))
+ WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid);
+
+ /*
+ * Restore the queue to the previous status
+ */
+ if (started)
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
+
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_start_queue will call ieee80211_wake_queue
+ * for each queue after is has been properly initialized.
+ */
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_start_queue(queue);
+
+ rt2x00queue_start_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queues);
+
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_stop_queue will call ieee80211_stop_queue
+ * as well, but we are completely shutting doing everything
+ * now, so it is much safer to stop all TX queues at once,
+ * and use rt2x00queue_stop_queue for cleaning up.
+ */
+ ieee80211_stop_queues(rt2x00dev->hw);
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_stop_queue(queue);
+
+ rt2x00queue_stop_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);
+
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
+
+ rt2x00queue_flush_queue(rt2x00dev->rx, drop);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queues);
+
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
unsigned int i;
- spin_lock_irqsave(&queue->lock, irqflags);
+ spin_lock_irqsave(&queue->index_lock, irqflags);
queue->count = 0;
queue->length = 0;
@@ -759,15 +957,7 @@ static void rt2x00queue_reset(struct data_queue *queue)
queue->last_action[i] = jiffies;
}
- spin_unlock_irqrestore(&queue->lock, irqflags);
-}
-
-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- txall_queue_for_each(rt2x00dev, queue)
- rt2x00dev->ops->lib->kill_tx_queue(queue);
+ spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -778,11 +968,8 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);
- for (i = 0; i < queue->limit; i++) {
+ for (i = 0; i < queue->limit; i++)
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
- if (queue->qid == QID_RX)
- rt2x00queue_index_inc(queue, Q_INDEX);
- }
}
}
@@ -809,8 +996,8 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
return -ENOMEM;
#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
- ( ((char *)(__base)) + ((__limit) * (__esize)) + \
- ((__index) * (__psize)) )
+ (((char *)(__base)) + ((__limit) * (__esize)) + \
+ ((__index) * (__psize)))
for (i = 0; i < queue->limit; i++) {
entries[i].flags = 0;
@@ -911,7 +1098,8 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, enum data_queue_qid qid)
{
- spin_lock_init(&queue->lock);
+ mutex_init(&queue->status_lock);
+ spin_lock_init(&queue->index_lock);
queue->rt2x00dev = rt2x00dev;
queue->qid = qid;
@@ -953,7 +1141,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
/*
* Initialize queue parameters.
* RX: qid = QID_RX
- * TX: qid = QID_AC_BE + index
+ * TX: qid = QID_AC_VO + index
* TX: cw_min: 2^5 = 32.
* TX: cw_max: 2^10 = 1024.
* BCN: qid = QID_BEACON
@@ -961,7 +1149,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/
rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
- qid = QID_AC_BE;
+ qid = QID_AC_VO;
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_init(rt2x00dev, queue, qid++);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index d81d85f34866..fab8e2687f29 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -43,28 +43,12 @@
#define AGGREGATION_SIZE 3840
/**
- * DOC: Number of entries per queue
- *
- * Under normal load without fragmentation, 12 entries are sufficient
- * without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code, we need to add some additional margins to
- * make sure the queue will never (or only under extreme load) fill up
- * completely.
- * Since we don't use preallocated DMA, having a large number of queue entries
- * will have minimal impact on the memory requirements for the queue.
- */
-#define RX_ENTRIES 24
-#define TX_ENTRIES 24
-#define BEACON_ENTRIES 1
-#define ATIM_ENTRIES 8
-
-/**
* enum data_queue_qid: Queue identification
*
+ * @QID_AC_VO: AC VO queue
+ * @QID_AC_VI: AC VI queue
* @QID_AC_BE: AC BE queue
* @QID_AC_BK: AC BK queue
- * @QID_AC_VI: AC VI queue
- * @QID_AC_VO: AC VO queue
* @QID_HCCA: HCCA queue
* @QID_MGMT: MGMT queue (prio queue)
* @QID_RX: RX queue
@@ -73,10 +57,10 @@
* @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
*/
enum data_queue_qid {
- QID_AC_BE = 0,
- QID_AC_BK = 1,
- QID_AC_VI = 2,
- QID_AC_VO = 3,
+ QID_AC_VO = 0,
+ QID_AC_VI = 1,
+ QID_AC_BE = 2,
+ QID_AC_BK = 3,
QID_HCCA = 4,
QID_MGMT = 13,
QID_RX = 14,
@@ -296,7 +280,6 @@ enum txentry_desc_flags {
* Summary of information for the frame descriptor before sending a TX frame.
*
* @flags: Descriptor flags (See &enum queue_entry_flags).
- * @qid: Queue identification (See &enum data_queue_qid).
* @length: Length of the entire frame.
* @header_length: Length of 802.11 header.
* @length_high: PLCP length high word.
@@ -309,11 +292,8 @@ enum txentry_desc_flags {
* @rate_mode: Rate mode (See @enum rate_modulation).
* @mpdu_density: MDPU density.
* @retry_limit: Max number of retries.
- * @aifs: AIFS value.
* @ifs: IFS value.
* @txop: IFS value for 11n capable chips.
- * @cw_min: cwmin value.
- * @cw_max: cwmax value.
* @cipher: Cipher type used for encryption.
* @key_idx: Key index used for encryption.
* @iv_offset: Position where IV should be inserted by hardware.
@@ -322,8 +302,6 @@ enum txentry_desc_flags {
struct txentry_desc {
unsigned long flags;
- enum data_queue_qid qid;
-
u16 length;
u16 header_length;
@@ -339,11 +317,8 @@ struct txentry_desc {
u16 mpdu_density;
short retry_limit;
- short aifs;
short ifs;
short txop;
- short cw_min;
- short cw_max;
enum cipher cipher;
u16 key_idx;
@@ -365,12 +340,16 @@ struct txentry_desc {
* @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
* while transfering the data to the hardware. No TX status report will
* be expected from the hardware.
+ * @ENTRY_DATA_STATUS_PENDING: The entry has been send to the device and
+ * returned. It is now waiting for the status reporting before the
+ * entry can be reused again.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
- ENTRY_DATA_IO_FAILED
+ ENTRY_DATA_IO_FAILED,
+ ENTRY_DATA_STATUS_PENDING,
};
/**
@@ -417,13 +396,33 @@ enum queue_index {
};
/**
+ * enum data_queue_flags: Status flags for data queues
+ *
+ * @QUEUE_STARTED: The queue has been started. Fox RX queues this means the
+ * device might be DMA'ing skbuffers. TX queues will accept skbuffers to
+ * be transmitted and beacon queues will start beaconing the configured
+ * beacons.
+ * @QUEUE_PAUSED: The queue has been started but is currently paused.
+ * When this bit is set, the queue has been stopped in mac80211,
+ * preventing new frames to be enqueued. However, a few frames
+ * might still appear shortly after the pausing...
+ */
+enum data_queue_flags {
+ QUEUE_STARTED,
+ QUEUE_PAUSED,
+};
+
+/**
* struct data_queue: Data queue
*
* @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
* @entries: Base address of the &struct queue_entry which are
* part of this queue.
* @qid: The queue identification, see &enum data_queue_qid.
- * @lock: Spinlock to protect index handling. Whenever @index, @index_done or
+ * @flags: Entry flags, see &enum queue_entry_flags.
+ * @status_lock: The mutex for protecting the start/stop/flush
+ * handling on this queue.
+ * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
* @index_crypt needs to be changed this lock should be grabbed to prevent
* index corruption due to concurrency.
* @count: Number of frames handled in the queue.
@@ -446,8 +445,11 @@ struct data_queue {
struct queue_entry *entries;
enum data_queue_qid qid;
+ unsigned long flags;
+
+ struct mutex status_lock;
+ spinlock_t index_lock;
- spinlock_t lock;
unsigned int count;
unsigned short limit;
unsigned short threshold;
@@ -618,10 +620,10 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
}
/**
- * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts
+ * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports
* @queue: Queue to check.
*/
-static inline int rt2x00queue_timeout(struct data_queue *queue)
+static inline int rt2x00queue_status_timeout(struct data_queue *queue)
{
return time_after(queue->last_action[Q_INDEX_DMA_DONE],
queue->last_action[Q_INDEX_DONE] + (HZ / 10));
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index cef94621cef7..e8259ae48ced 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -83,10 +83,6 @@ enum dev_state {
*/
STATE_RADIO_ON,
STATE_RADIO_OFF,
- STATE_RADIO_RX_ON,
- STATE_RADIO_RX_OFF,
- STATE_RADIO_RX_ON_LINK,
- STATE_RADIO_RX_OFF_LINK,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
STATE_RADIO_IRQ_ON_ISR,
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c
index fc98063de71d..2aa5c38022f3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00soc.c
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
@@ -40,6 +40,8 @@ static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev)
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
+
+ iounmap(rt2x00dev->csr.base);
}
static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
@@ -51,9 +53,9 @@ static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
if (!res)
return -ENODEV;
- rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start);
+ rt2x00dev->csr.base = ioremap(res->start, resource_size(res));
if (!rt2x00dev->csr.base)
- goto exit;
+ return -ENOMEM;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index b3317df7a7d4..1a9937d5aff6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -195,7 +195,8 @@ static void rt2x00usb_work_txdone(struct work_struct *work)
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
rt2x00usb_work_txdone_entry(entry);
@@ -226,9 +227,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* Schedule the delayed work for reading the TX status
* from the device.
*/
- if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
}
static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
@@ -237,8 +236,10 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
u32 length;
+ int status;
- if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+ if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
return;
/*
@@ -253,121 +254,15 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
}
-void rt2x00usb_kick_tx_queue(struct data_queue *queue)
-{
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kick_tx_entry);
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
-
-static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
-
- if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
-
- usb_kill_urb(entry_priv->urb);
-
- /*
- * Kill guardian urb (if required by driver).
- */
- if ((entry->queue->qid == QID_BEACON) &&
- (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
- usb_kill_urb(bcn_priv->guardian_urb);
-}
-
-void rt2x00usb_kill_tx_queue(struct data_queue *queue)
-{
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kill_tx_entry);
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
-
-static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- unsigned short threshold = queue->threshold;
-
- WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
- " invoke forced forced reset", queue->qid);
-
- /*
- * Temporarily disable the TX queue, this will force mac80211
- * to use the other queues until this queue has been restored.
- *
- * Set the queue threshold to the queue limit. This prevents the
- * queue from being enabled during the txdone handler.
- */
- queue->threshold = queue->limit;
- ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
-
- /*
- * Kill all entries in the queue, afterwards we need to
- * wait a bit for all URBs to be cancelled.
- */
- rt2x00usb_kill_tx_queue(queue);
-
- /*
- * In case that a driver has overriden the txdone_work
- * function, we invoke the TX done through there.
- */
- rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
-
- /*
- * Security measure: if the driver did override the
- * txdone_work function, and the hardware did arrive
- * in a state which causes it to malfunction, it is
- * possible that the driver couldn't handle the txdone
- * event correctly. So after giving the driver the
- * chance to cleanup, we now force a cleanup of any
- * leftovers.
- */
- if (!rt2x00queue_empty(queue)) {
- WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
- " status handling failed, invoke hard reset", queue->qid);
- rt2x00usb_work_txdone(&rt2x00dev->txdone_work);
- }
-
- /*
- * The queue has been reset, and mac80211 is allowed to use the
- * queue again.
- */
- queue->threshold = threshold;
- ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
-}
-
-static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
-{
- WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
- " invoke forced tx handler", queue->qid);
-
- ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
-}
-
-void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- tx_queue_for_each(rt2x00dev, queue) {
- if (!rt2x00queue_empty(queue)) {
- if (rt2x00queue_dma_timeout(queue))
- rt2x00usb_watchdog_tx_dma(queue);
- if (rt2x00queue_timeout(queue))
- rt2x00usb_watchdog_tx_status(queue);
- }
- }
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
-
/*
* RX data handlers.
*/
@@ -382,7 +277,8 @@ static void rt2x00usb_work_rxdone(struct work_struct *work)
while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
/*
@@ -424,11 +320,157 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
* Schedule the delayed work for reading the RX status
* from the device.
*/
- if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
}
+static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ int status;
+
+ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ return;
+
+ rt2x00lib_dmastart(entry);
+
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint),
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
+
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ rt2x00lib_dmadone(entry);
+ }
+}
+
+void rt2x00usb_kick_queue(struct data_queue *queue)
+{
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ if (!rt2x00queue_empty(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_tx_entry);
+ break;
+ case QID_RX:
+ if (!rt2x00queue_full(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_rx_entry);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
+
+static void rt2x00usb_flush_entry(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ usb_kill_urb(entry_priv->urb);
+
+ /*
+ * Kill guardian urb (if required by driver).
+ */
+ if ((entry->queue->qid == QID_BEACON) &&
+ (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+ usb_kill_urb(bcn_priv->guardian_urb);
+}
+
+void rt2x00usb_flush_queue(struct data_queue *queue)
+{
+ struct work_struct *completion;
+ unsigned int i;
+
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_flush_entry);
+
+ /*
+ * Obtain the queue completion handler
+ */
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ completion = &queue->rt2x00dev->txdone_work;
+ break;
+ case QID_RX:
+ completion = &queue->rt2x00dev->rxdone_work;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 20; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * Schedule the completion handler manually, when this
+ * worker function runs, it should cleanup the queue.
+ */
+ ieee80211_queue_work(queue->rt2x00dev->hw, completion);
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(10);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);
+
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+ " invoke forced forced reset\n", queue->qid);
+
+ rt2x00queue_flush_queue(queue, true);
+}
+
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+ " invoke forced tx handler\n", queue->qid);
+
+ ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
+}
+
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ if (!rt2x00queue_empty(queue)) {
+ if (rt2x00queue_dma_timeout(queue))
+ rt2x00usb_watchdog_tx_dma(queue);
+ if (rt2x00queue_status_timeout(queue))
+ rt2x00usb_watchdog_tx_status(queue);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
+
/*
* Radio handlers
*/
@@ -436,12 +478,6 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
-
- /*
- * The USB version of kill_tx_queue also works
- * on the RX queue.
- */
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@@ -450,25 +486,10 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
*/
void rt2x00usb_clear_entry(struct queue_entry *entry)
{
- struct usb_device *usb_dev =
- to_usb_device_intf(entry->queue->rt2x00dev->dev);
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- int pipe;
-
entry->flags = 0;
- if (entry->queue->qid == QID_RX) {
- pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
- usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
- entry->skb->data, entry->skb->len,
- rt2x00usb_interrupt_rxdone, entry);
-
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
- set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
- rt2x00lib_dmadone(entry);
- }
- }
+ if (entry->queue->qid == QID_RX)
+ rt2x00usb_kick_rx_entry(entry);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index c2d997f67b3e..6aaf51fc7ad8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -378,22 +378,22 @@ struct queue_entry_priv_usb_bcn {
};
/**
- * rt2x00usb_kick_tx_queue - Kick data queue
+ * rt2x00usb_kick_queue - Kick data queue
* @queue: Data queue to kick
*
* This will walk through all entries of the queue and push all pending
* frames to the hardware as a single burst.
*/
-void rt2x00usb_kick_tx_queue(struct data_queue *queue);
+void rt2x00usb_kick_queue(struct data_queue *queue);
/**
- * rt2x00usb_kill_tx_queue - Kill data queue
- * @queue: Data queue to kill
+ * rt2x00usb_flush_queue - Flush data queue
+ * @queue: Data queue to stop
*
* This will walk through all entries of the queue and kill all
- * previously kicked frames before they can be send.
+ * URB's which were send to the device.
*/
-void rt2x00usb_kill_tx_queue(struct data_queue *queue);
+void rt2x00usb_flush_queue(struct data_queue *queue);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index af548c87f108..8de44dd401e0 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1140,6 +1140,106 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt61pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ 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, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1616,18 +1716,6 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* 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) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1744,12 +1832,6 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt61pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt61pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1789,10 +1871,10 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
- rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
@@ -1820,7 +1902,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
- if (txdesc->qid != QID_BEACON) {
+ if (entry->queue->qid != QID_BEACON) {
rt2x00_desc_read(txd, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
skbdesc->skb_dma);
@@ -1866,8 +1948,8 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
* Register descriptor details in skb frame descriptor.
*/
skbdesc->desc = txd;
- skbdesc->desc_len =
- (txdesc->qid == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE;
+ skbdesc->desc_len = (entry->queue->qid == QID_BEACON) ? TXINFO_SIZE :
+ TXD_DESC_SIZE;
}
/*
@@ -1879,6 +1961,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -1900,13 +1983,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
entry_priv->desc, TXINFO_SIZE);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
- entry->skb->data, entry->skb->len);
+ entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1928,37 +2014,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
entry->skb = NULL;
}
-static void rt61pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO));
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
-}
-
-static void rt61pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
- return;
- }
-
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
-}
-
/*
* RX control handlers
*/
@@ -2078,7 +2133,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
* that the TX_STA_FIFO stack has a size of 16. We stick to our
* tx ring size for now.
*/
- for (i = 0; i < TX_ENTRIES; i++) {
+ for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
break;
@@ -2824,6 +2879,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.conf_tx = rt61pci_conf_tx,
.get_tsf = rt61pci_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -2842,10 +2898,11 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.link_stats = rt61pci_link_stats,
.reset_tuner = rt61pci_reset_tuner,
.link_tuner = rt61pci_link_tuner,
+ .start_queue = rt61pci_start_queue,
+ .kick_queue = rt61pci_kick_queue,
+ .stop_queue = rt61pci_stop_queue,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
- .kick_tx_queue = rt61pci_kick_tx_queue,
- .kill_tx_queue = rt61pci_kill_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone,
.config_shared_key = rt61pci_config_shared_key,
.config_pairwise_key = rt61pci_config_pairwise_key,
@@ -2857,21 +2914,21 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
};
static const struct data_queue_desc rt61pci_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt61pci_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt61pci_queue_bcn = {
- .entry_num = 4 * BEACON_ENTRIES,
+ .entry_num = 4,
.data_size = 0, /* No DMA required for beacons */
.desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci),
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index e2e728ab0b2e..e3cd6db76b0e 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -412,7 +412,7 @@ struct hw_pairwise_ta_entry {
* 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.
+ * DROP_ACK_CTS: Drop received ACK and CTS.
*/
#define TXRX_CSR0 0x3040
#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
@@ -784,25 +784,25 @@ struct hw_pairwise_ta_entry {
*/
/*
- * AC0_BASE_CSR: AC_BK base address.
+ * AC0_BASE_CSR: AC_VO base address.
*/
#define AC0_BASE_CSR 0x3400
#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC1_BASE_CSR: AC_BE base address.
+ * AC1_BASE_CSR: AC_VI base address.
*/
#define AC1_BASE_CSR 0x3404
#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC2_BASE_CSR: AC_VI base address.
+ * AC2_BASE_CSR: AC_BE base address.
*/
#define AC2_BASE_CSR 0x3408
#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC3_BASE_CSR: AC_VO base address.
+ * AC3_BASE_CSR: AC_BK base address.
*/
#define AC3_BASE_CSR 0x340c
#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
@@ -814,7 +814,7 @@ struct hw_pairwise_ta_entry {
#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ * TX_RING_CSR0: TX Ring size for AC_VO, AC_VI, AC_BE, AC_BK.
*/
#define TX_RING_CSR0 0x3418
#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
@@ -833,10 +833,10 @@ struct hw_pairwise_ta_entry {
/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x3420
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -846,10 +846,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x3424
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -859,10 +859,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x3428
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -883,14 +883,14 @@ struct hw_pairwise_ta_entry {
/*
* 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.
+ * KICK_TX_AC0: For AC_VO.
+ * KICK_TX_AC1: For AC_VI.
+ * KICK_TX_AC2: For AC_BE.
+ * KICK_TX_AC3: For AC_BK.
+ * ABORT_TX_AC0: For AC_VO.
+ * ABORT_TX_AC1: For AC_VI.
+ * ABORT_TX_AC2: For AC_BE.
+ * ABORT_TX_AC3: For AC_BK.
*/
#define TX_CNTL_CSR 0x3430
#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
@@ -1010,18 +1010,18 @@ struct hw_pairwise_ta_entry {
#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.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, 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.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x3478
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 9be8089317e4..0b4e8590cbb7 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -40,7 +40,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 0;
+static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -1031,6 +1031,55 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt73usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_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, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt73usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1324,18 +1373,6 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF) ||
- (state == STATE_RADIO_RX_OFF_LINK));
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1402,12 +1439,6 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt73usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_ON_LINK:
- case STATE_RADIO_RX_OFF:
- case STATE_RADIO_RX_OFF_LINK:
- rt73usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1472,10 +1503,10 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
rt2x00_desc_write(txd, 0, word);
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
- rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
- rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
- rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
@@ -1515,6 +1546,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -1542,11 +1574,13 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1582,14 +1616,6 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
-static void rt73usb_kill_tx_queue(struct data_queue *queue)
-{
- if (queue->qid == QID_BEACON)
- rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -2264,6 +2290,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.conf_tx = rt73usb_conf_tx,
.get_tsf = rt73usb_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
+ .flush = rt2x00mac_flush,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2280,11 +2307,13 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt73usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt73usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt73usb_kill_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,
.config_pairwise_key = rt73usb_config_pairwise_key,
@@ -2296,21 +2325,21 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
};
static const struct data_queue_desc rt73usb_queue_rx = {
- .entry_num = RX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_tx = {
- .entry_num = TX_ENTRIES,
+ .entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_bcn = {
- .entry_num = 4 * BEACON_ENTRIES,
+ .entry_num = 4,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 44d5b2bebd39..9f6b470414d3 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -322,7 +322,7 @@ struct hw_pairwise_ta_entry {
* 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.
+ * DROP_ACK_CTS: Drop received ACK and CTS.
*/
#define TXRX_CSR0 0x3040
#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
@@ -689,10 +689,10 @@ struct hw_pairwise_ta_entry {
/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x0400
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -702,10 +702,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x0404
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -715,10 +715,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x0408
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -727,18 +727,18 @@ struct hw_pairwise_ta_entry {
#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.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, 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.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x0410
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
index 93cbfbedb46d..997569076923 100644
--- a/drivers/net/wireless/rtl818x/Makefile
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -1,7 +1,2 @@
-rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o
-
-obj-$(CONFIG_RTL8180) += rtl8180.o
-obj-$(CONFIG_RTL8187) += rtl8187.o
-
-
+obj-$(CONFIG_RTL8180) += rtl8180/
+obj-$(CONFIG_RTL8187) += rtl8187/
diff --git a/drivers/net/wireless/rtl818x/rtl8180/Makefile b/drivers/net/wireless/rtl818x/rtl8180/Makefile
new file mode 100644
index 000000000000..cb4fb8596f0b
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8180/Makefile
@@ -0,0 +1,5 @@
+rtl8180-objs := dev.o rtl8225.o sa2400.o max2820.o grf5101.o
+
+obj-$(CONFIG_RTL8180) += rtl8180.o
+
+ccflags-y += -Idrivers/net/wireless/rtl818x
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 707c688da618..5851cbc1e957 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -24,10 +24,10 @@
#include <net/mac80211.h>
#include "rtl8180.h"
-#include "rtl8180_rtl8225.h"
-#include "rtl8180_sa2400.h"
-#include "rtl8180_max2820.h"
-#include "rtl8180_grf5101.h"
+#include "rtl8225.h"
+#include "sa2400.h"
+#include "max2820.h"
+#include "grf5101.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c
index 5cab9dfa8c07..5ee7589dd546 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c
@@ -25,7 +25,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
-#include "rtl8180_grf5101.h"
+#include "grf5101.h"
static const int grf5101_encode[] = {
0x0, 0x8, 0x4, 0xC,
diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180/grf5101.h
index 76647111bcff..76647111bcff 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_grf5101.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.h
diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180/max2820.c
index 16c4655181c0..667b3363d437 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_max2820.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.c
@@ -24,7 +24,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
-#include "rtl8180_max2820.h"
+#include "max2820.h"
static const u32 max2820_chan[] = {
12, /* CH 1 */
diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180/max2820.h
index 61cf6d1e7d57..61cf6d1e7d57 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_max2820.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.h
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
index 30523314da43..30523314da43 100644
--- a/drivers/net/wireless/rtl818x/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h
diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
index 69e4d4745dae..7c4574ba9d75 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
@@ -21,7 +21,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
-#include "rtl8180_rtl8225.h"
+#include "rtl8225.h"
static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
{
diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.h
index 310013a2d726..310013a2d726 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.h
diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c
index d064fcc5ec08..44771a6286af 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c
@@ -25,7 +25,7 @@
#include <net/mac80211.h>
#include "rtl8180.h"
-#include "rtl8180_sa2400.h"
+#include "sa2400.h"
static const u32 sa2400_chan[] = {
0x00096c, /* ch1 */
diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180/sa2400.h
index a4aaa0d413f1..a4aaa0d413f1 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_sa2400.h
+++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.h
diff --git a/drivers/net/wireless/rtl818x/rtl8187/Makefile b/drivers/net/wireless/rtl818x/rtl8187/Makefile
new file mode 100644
index 000000000000..7b6299268ecf
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187/Makefile
@@ -0,0 +1,5 @@
+rtl8187-objs := dev.o rtl8225.o leds.o rfkill.o
+
+obj-$(CONFIG_RTL8187) += rtl8187.o
+
+ccflags-y += -Idrivers/net/wireless/rtl818x
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 38fa8244cc96..6b82cac37ee3 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -29,11 +29,11 @@
#include <net/mac80211.h>
#include "rtl8187.h"
-#include "rtl8187_rtl8225.h"
+#include "rtl8225.h"
#ifdef CONFIG_RTL8187_LEDS
-#include "rtl8187_leds.h"
+#include "leds.h"
#endif
-#include "rtl8187_rfkill.h"
+#include "rfkill.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -553,6 +553,46 @@ static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
return ret;
}
+static void rtl8187_set_anaparam(struct rtl8187_priv *priv, bool rfon)
+{
+ u32 anaparam, anaparam2;
+ u8 anaparam3, reg;
+
+ if (!priv->is_rtl8187b) {
+ if (rfon) {
+ anaparam = RTL8187_RTL8225_ANAPARAM_ON;
+ anaparam2 = RTL8187_RTL8225_ANAPARAM2_ON;
+ } else {
+ anaparam = RTL8187_RTL8225_ANAPARAM_OFF;
+ anaparam2 = RTL8187_RTL8225_ANAPARAM2_OFF;
+ }
+ } else {
+ if (rfon) {
+ anaparam = RTL8187B_RTL8225_ANAPARAM_ON;
+ anaparam2 = RTL8187B_RTL8225_ANAPARAM2_ON;
+ anaparam3 = RTL8187B_RTL8225_ANAPARAM3_ON;
+ } else {
+ anaparam = RTL8187B_RTL8225_ANAPARAM_OFF;
+ anaparam2 = RTL8187B_RTL8225_ANAPARAM2_OFF;
+ anaparam3 = RTL8187B_RTL8225_ANAPARAM3_OFF;
+ }
+ }
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ reg |= RTL818X_CONFIG3_ANAPARAM_WRITE;
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2);
+ if (priv->is_rtl8187b)
+ rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, anaparam3);
+ reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE;
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
+ RTL818X_EEPROM_CMD_NORMAL);
+}
+
static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
@@ -603,19 +643,7 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
int res;
/* reset */
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_CONFIG);
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
- RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
- RTL8187_RTL8225_ANAPARAM_ON);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
- RTL8187_RTL8225_ANAPARAM2_ON);
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
- ~RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_NORMAL);
+ rtl8187_set_anaparam(priv, true);
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
@@ -629,17 +657,7 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
if (res)
return res;
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- rtl818x_iowrite8(priv, &priv->map->CONFIG3,
- reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
- RTL8187_RTL8225_ANAPARAM_ON);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
- RTL8187_RTL8225_ANAPARAM2_ON);
- rtl818x_iowrite8(priv, &priv->map->CONFIG3,
- reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+ rtl8187_set_anaparam(priv, true);
/* setup card */
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
@@ -712,10 +730,9 @@ static const u8 rtl8187b_reg_table[][3] = {
{0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1},
{0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1},
- {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1},
- {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1},
- {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1},
- {0xF7, 0x07, 1}, {0xF8, 0x08, 1},
+ {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1},
+ {0xF2, 0x02, 1}, {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1},
+ {0xF6, 0x06, 1}, {0xF7, 0x07, 1}, {0xF8, 0x08, 1},
{0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2},
{0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2},
@@ -723,14 +740,13 @@ static const u8 rtl8187b_reg_table[][3] = {
{0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2},
{0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2},
{0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2},
- {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2},
- {0x73, 0x9A, 2},
+ {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2},
- {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0},
- {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0},
- {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0},
- {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0},
- {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2},
+ {0x5B, 0x40, 0}, {0x84, 0x88, 0}, {0x85, 0x24, 0}, {0x88, 0x54, 0},
+ {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, {0x8D, 0x00, 0}, {0x94, 0x1B, 0},
+ {0x95, 0x12, 0}, {0x96, 0x00, 0}, {0x97, 0x06, 0}, {0x9D, 0x1A, 0},
+ {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, {0xBE, 0x80, 0}, {0xDB, 0x00, 0},
+ {0xEE, 0x00, 0}, {0x4C, 0x00, 2},
{0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0},
{0x8F, 0x00, 0}
@@ -742,48 +758,34 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
int res, i;
u8 reg;
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_CONFIG);
-
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
- RTL8187B_RTL8225_ANAPARAM2_ON);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
- RTL8187B_RTL8225_ANAPARAM_ON);
- rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
- RTL8187B_RTL8225_ANAPARAM3_ON);
+ rtl8187_set_anaparam(priv, true);
+ /* Reset PLL sequence on 8187B. Realtek note: reduces power
+ * consumption about 30 mA */
rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5));
rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5));
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE;
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
-
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_NORMAL);
-
res = rtl8187_cmd_reset(dev);
if (res)
return res;
- rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF);
+ rtl8187_set_anaparam(priv, true);
+
+ /* BRSR (Basic Rate Set Register) on 8187B looks to be the same as
+ * RESP_RATE on 8187L in Realtek sources: each bit should be each
+ * one of the 12 rates, all are enabled */
+ rtl818x_iowrite16(priv, (__le16 *)0xFF34, 0x0FFF);
+
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
- reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
- reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT |
- RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
- rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+ /* Auto Rate Fallback Register (ARFR): 1M-54M setting */
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1);
+ rtl818x_iowrite8_idx(priv, (u8 *)0xFFE2, 0x00, 1);
- rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
- rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -811,16 +813,9 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001);
+ /* RFSW_CTRL register */
rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2);
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_CONFIG);
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- reg |= RTL818X_CONFIG3_ANAPARAM_WRITE;
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
- RTL818X_EEPROM_CMD_NORMAL);
-
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
@@ -929,6 +924,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
priv->rx_conf = reg;
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+ reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+ rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
rtl818x_iowrite32(priv, &priv->map->TX_CONF,
RTL818X_TX_CONF_HW_SEQNUM |
RTL818X_TX_CONF_DISREQQSIZE |
@@ -1002,6 +1003,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
priv->rf->stop(dev);
+ rtl8187_set_anaparam(priv, false);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187/leds.c
index 4637337d5ce6..2e0de2f5f0f9 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/leds.c
@@ -20,7 +20,7 @@
#include <linux/eeprom_93cx6.h>
#include "rtl8187.h"
-#include "rtl8187_leds.h"
+#include "leds.h"
static void led_turn_on(struct work_struct *work)
{
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187/leds.h
index d743c96d4a20..d743c96d4a20 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/leds.h
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
index 03555e1e0cab..34116719974a 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
@@ -18,7 +18,7 @@
#include <net/mac80211.h>
#include "rtl8187.h"
-#include "rtl8187_rfkill.h"
+#include "rfkill.h"
static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
{
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h b/drivers/net/wireless/rtl818x/rtl8187/rfkill.h
index e12575e96d11..e12575e96d11 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.h
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
index 98878160a65a..0d7b1423f77b 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
@@ -16,7 +16,7 @@
#define RTL8187_H
#include "rtl818x.h"
-#include "rtl8187_leds.h"
+#include "leds.h"
#define RTL8187_EEPROM_TXPWR_BASE 0x05
#define RTL8187_EEPROM_MAC_ADDR 0x07
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
index 97eebdcf7eb9..908903f721f5 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
@@ -21,7 +21,7 @@
#include <net/mac80211.h>
#include "rtl8187.h"
-#include "rtl8187_rtl8225.h"
+#include "rtl8225.h"
static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
{
@@ -898,29 +898,7 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
static void rtl8225_rf_stop(struct ieee80211_hw *dev)
{
- u8 reg;
- struct rtl8187_priv *priv = dev->priv;
-
rtl8225_write(dev, 0x4, 0x1f);
-
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
- reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- if (!priv->is_rtl8187b) {
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
- RTL8187_RTL8225_ANAPARAM2_OFF);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
- RTL8187_RTL8225_ANAPARAM_OFF);
- } else {
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
- RTL8187B_RTL8225_ANAPARAM2_OFF);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
- RTL8187B_RTL8225_ANAPARAM_OFF);
- rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
- RTL8187B_RTL8225_ANAPARAM3_OFF);
- }
- rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
}
static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h
index 20c5b6ead0f6..20c5b6ead0f6 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.h
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
new file mode 100644
index 000000000000..7f6573f7f470
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -0,0 +1,15 @@
+config RTL8192CE
+ tristate "Realtek RTL8192CE/RTL8188SE Wireless Network Adapter"
+ depends on MAC80211 && EXPERIMENTAL
+ select FW_LOADER
+ select RTLWIFI
+ ---help---
+ This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8192ce
+
+config RTLWIFI
+ tristate
+ depends on RTL8192CE
+ default m
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
new file mode 100644
index 000000000000..2a7a4384f8ee
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_RTLWIFI) += rtlwifi.o
+rtlwifi-objs := \
+ base.o \
+ cam.o \
+ core.o \
+ debug.o \
+ efuse.o \
+ pci.o \
+ ps.o \
+ rc.o \
+ regd.o
+
+obj-$(CONFIG_RTL8192CE) += rtl8192ce/
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
new file mode 100644
index 000000000000..cf0b73e51fc2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -0,0 +1,956 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/ip.h>
+#include "wifi.h"
+#include "rc.h"
+#include "base.h"
+#include "efuse.h"
+#include "cam.h"
+#include "ps.h"
+#include "regd.h"
+
+/*
+ *NOTICE!!!: This file will be very big, we hsould
+ *keep it clear under follwing roles:
+ *
+ *This file include follwing part, so, if you add new
+ *functions into this file, please check which part it
+ *should includes. or check if you should add new part
+ *for this file:
+ *
+ *1) mac80211 init functions
+ *2) tx information functions
+ *3) functions called by core.c
+ *4) wq & timer callback functions
+ *5) frame process functions
+ *6) sysfs functions
+ *7) ...
+ */
+
+/*********************************************************
+ *
+ * mac80211 init functions
+ *
+ *********************************************************/
+static struct ieee80211_channel rtl_channeltable[] = {
+ {.center_freq = 2412, .hw_value = 1,},
+ {.center_freq = 2417, .hw_value = 2,},
+ {.center_freq = 2422, .hw_value = 3,},
+ {.center_freq = 2427, .hw_value = 4,},
+ {.center_freq = 2432, .hw_value = 5,},
+ {.center_freq = 2437, .hw_value = 6,},
+ {.center_freq = 2442, .hw_value = 7,},
+ {.center_freq = 2447, .hw_value = 8,},
+ {.center_freq = 2452, .hw_value = 9,},
+ {.center_freq = 2457, .hw_value = 10,},
+ {.center_freq = 2462, .hw_value = 11,},
+ {.center_freq = 2467, .hw_value = 12,},
+ {.center_freq = 2472, .hw_value = 13,},
+ {.center_freq = 2484, .hw_value = 14,},
+};
+
+static struct ieee80211_rate rtl_ratetable[] = {
+ {.bitrate = 10, .hw_value = 0x00,},
+ {.bitrate = 20, .hw_value = 0x01,},
+ {.bitrate = 55, .hw_value = 0x02,},
+ {.bitrate = 110, .hw_value = 0x03,},
+ {.bitrate = 60, .hw_value = 0x04,},
+ {.bitrate = 90, .hw_value = 0x05,},
+ {.bitrate = 120, .hw_value = 0x06,},
+ {.bitrate = 180, .hw_value = 0x07,},
+ {.bitrate = 240, .hw_value = 0x08,},
+ {.bitrate = 360, .hw_value = 0x09,},
+ {.bitrate = 480, .hw_value = 0x0a,},
+ {.bitrate = 540, .hw_value = 0x0b,},
+};
+
+static const struct ieee80211_supported_band rtl_band_2ghz = {
+ .band = IEEE80211_BAND_2GHZ,
+
+ .channels = rtl_channeltable,
+ .n_channels = ARRAY_SIZE(rtl_channeltable),
+
+ .bitrates = rtl_ratetable,
+ .n_bitrates = ARRAY_SIZE(rtl_ratetable),
+
+ .ht_cap = {0},
+};
+
+static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_sta_ht_cap *ht_cap)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ ht_cap->ht_supported = true;
+ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
+
+ /*
+ *Maximum length of AMPDU that the STA can receive.
+ *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+
+ /*Minimum MPDU start spacing , */
+ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+
+ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ /*
+ *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ *base on ant_num
+ *rx_mask: RX mask
+ *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7
+ *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15
+ *if rx_ant >=3 rx_mask[2]=0xff;
+ *if BW_40 rx_mask[4]=0x01;
+ *highest supported RX rate
+ */
+ if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) {
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("1T2R or 2T2R\n"));
+
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15;
+ } else if (get_rf_type(rtlphy) == RF_1T1R) {
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("1T1R\n"));
+
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0x00;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7;
+ }
+}
+
+static void _rtl_init_mac80211(struct ieee80211_hw *hw)
+{
+ struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct ieee80211_supported_band *sband;
+
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
+ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+ /*
+ * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ * to default value(1T1R)
+ */
+ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
+ sizeof(struct ieee80211_supported_band));
+
+ /* <3> init ht cap base on ant_num */
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+ /* <4> set mac->sband to wiphy->sband */
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+ /* <5> set hw caps */
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/
+ /*IEEE80211_HW_SUPPORTS_PS | */
+ /*IEEE80211_HW_PS_NULLFUNC_STACK | */
+ /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
+
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+
+ hw->wiphy->rts_threshold = 2347;
+
+ hw->queues = AC_MAX;
+ hw->extra_tx_headroom = RTL_TX_HEADER_SIZE;
+
+ /* TODO: Correct this value for our hw */
+ /* TODO: define these hard code value */
+ hw->channel_change_time = 100;
+ hw->max_listen_interval = 5;
+ hw->max_rate_tries = 4;
+ /* hw->max_rates = 1; */
+
+ /* <6> mac address */
+ if (is_valid_ether_addr(rtlefuse->dev_addr)) {
+ SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr);
+ } else {
+ u8 rtlmac[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 };
+ get_random_bytes((rtlmac + (ETH_ALEN - 1)), 1);
+ SET_IEEE80211_PERM_ADDR(hw, rtlmac);
+ }
+
+}
+
+static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /* <1> timer */
+ init_timer(&rtlpriv->works.watchdog_timer);
+ setup_timer(&rtlpriv->works.watchdog_timer,
+ rtl_watch_dog_timer_callback, (unsigned long)hw);
+
+ /* <2> work queue */
+ rtlpriv->works.hw = hw;
+ rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
+ INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
+ (void *)rtl_watchdog_wq_callback);
+ INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
+ (void *)rtl_ips_nic_off_wq_callback);
+
+}
+
+void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ del_timer_sync(&rtlpriv->works.watchdog_timer);
+
+ cancel_delayed_work(&rtlpriv->works.watchdog_wq);
+ cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
+}
+
+void rtl_init_rfkill(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ bool radio_state;
+ bool blocked;
+ u8 valid = 0;
+
+ radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
+
+ /*set init state to that of switch */
+ rtlpriv->rfkill.rfkill_state = radio_state;
+ printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
+ rtlpriv->rfkill.rfkill_state ? "on" : "off");
+
+ if (valid) {
+ rtlpriv->rfkill.rfkill_state = radio_state;
+
+ blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+ }
+
+ wiphy_rfkill_start_polling(hw->wiphy);
+}
+
+void rtl_deinit_rfkill(struct ieee80211_hw *hw)
+{
+ wiphy_rfkill_stop_polling(hw->wiphy);
+}
+
+int rtl_init_core(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+
+ /* <1> init mac80211 */
+ _rtl_init_mac80211(hw);
+ rtlmac->hw = hw;
+
+ /* <2> rate control register */
+ if (rtl_rate_control_register()) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("rtl: Unable to register rtl_rc,"
+ "use default RC !!\n"));
+ } else {
+ hw->rate_control_algorithm = "rtl_rc";
+ }
+
+ /*
+ * <3> init CRDA must come after init
+ * mac80211 hw in _rtl_init_mac80211.
+ */
+ if (rtl_regd_init(hw, rtl_reg_notifier)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("REGD init failed\n"));
+ return 1;
+ } else {
+ /* CRDA regd hint must after init CRDA */
+ if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("regulatory_hint fail\n"));
+ }
+ }
+
+ /* <4> locks */
+ mutex_init(&rtlpriv->locks.conf_mutex);
+ spin_lock_init(&rtlpriv->locks.ips_lock);
+ spin_lock_init(&rtlpriv->locks.irq_th_lock);
+ spin_lock_init(&rtlpriv->locks.h2c_lock);
+ spin_lock_init(&rtlpriv->locks.rf_ps_lock);
+ spin_lock_init(&rtlpriv->locks.rf_lock);
+ spin_lock_init(&rtlpriv->locks.lps_lock);
+
+ rtlmac->link_state = MAC80211_NOLINK;
+
+ /* <5> init deferred work */
+ _rtl_init_deferred_work(hw);
+
+ return 0;
+}
+
+void rtl_deinit_core(struct ieee80211_hw *hw)
+{
+ /*RC*/
+ rtl_rate_control_unregister();
+}
+
+void rtl_init_rx_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER,
+ (u8 *) (&mac->rx_mgt_filter));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER,
+ (u8 *) (&mac->rx_ctrl_filter));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER,
+ (u8 *) (&mac->rx_data_filter));
+}
+
+/*********************************************************
+ *
+ * tx information functions
+ *
+ *********************************************************/
+static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
+ struct rtl_tcb_desc *tcb_desc,
+ struct ieee80211_tx_info *info)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 rate_flag = info->control.rates[0].flags;
+
+ tcb_desc->use_shortpreamble = false;
+
+ /* 1M can only use Long Preamble. 11B spec */
+ if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M])
+ return;
+ else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ tcb_desc->use_shortpreamble = true;
+
+ return;
+}
+
+static void _rtl_query_shortgi(struct ieee80211_hw *hw,
+ struct rtl_tcb_desc *tcb_desc,
+ struct ieee80211_tx_info *info)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 rate_flag = info->control.rates[0].flags;
+
+ tcb_desc->use_shortgi = false;
+
+ if (!mac->ht_enable)
+ return;
+
+ if (!mac->sgi_40 && !mac->sgi_20)
+ return;
+
+ if ((mac->bw_40 == true) && mac->sgi_40)
+ tcb_desc->use_shortgi = true;
+ else if ((mac->bw_40 == false) && mac->sgi_20)
+ tcb_desc->use_shortgi = true;
+
+ if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
+ tcb_desc->use_shortgi = false;
+
+}
+
+static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
+ struct rtl_tcb_desc *tcb_desc,
+ struct ieee80211_tx_info *info)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 rate_flag = info->control.rates[0].flags;
+
+ /* Common Settings */
+ tcb_desc->b_rts_stbc = false;
+ tcb_desc->b_cts_enable = false;
+ tcb_desc->rts_sc = 0;
+ tcb_desc->b_rts_bw = false;
+ tcb_desc->b_rts_use_shortpreamble = false;
+ tcb_desc->b_rts_use_shortgi = false;
+
+ if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ /* Use CTS-to-SELF in protection mode. */
+ tcb_desc->b_rts_enable = true;
+ tcb_desc->b_cts_enable = true;
+ tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
+ } else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
+ /* Use RTS-CTS in protection mode. */
+ tcb_desc->b_rts_enable = true;
+ tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
+ }
+
+}
+
+static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
+ struct rtl_tcb_desc *tcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ tcb_desc->ratr_index = 0;
+ else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (tcb_desc->b_multicast || tcb_desc->b_broadcast) {
+ tcb_desc->hw_rate =
+ rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
+ tcb_desc->use_driver_rate = 1;
+ } else {
+ /* TODO */
+ }
+ }
+ }
+
+ if (rtlpriv->dm.b_useramask) {
+ /* TODO we will differentiate adhoc and station futrue */
+ tcb_desc->mac_id = 0;
+
+ if ((mac->mode == WIRELESS_MODE_N_24G) ||
+ (mac->mode == WIRELESS_MODE_N_5G)) {
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
+ } else if (mac->mode & WIRELESS_MODE_G) {
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
+ } else if (mac->mode & WIRELESS_MODE_B) {
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+ }
+ }
+
+}
+
+static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
+ struct rtl_tcb_desc *tcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ tcb_desc->b_packet_bw = false;
+
+ if (!mac->bw_40 || !mac->ht_enable)
+ return;
+
+ if (tcb_desc->b_multicast || tcb_desc->b_broadcast)
+ return;
+
+ /*use legency rate, shall use 20MHz */
+ if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M])
+ return;
+
+ tcb_desc->b_packet_bw = true;
+}
+
+static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 hw_rate;
+
+ if (get_rf_type(rtlphy) == RF_2T2R)
+ hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15];
+ else
+ hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7];
+
+ return hw_rate;
+}
+
+void rtl_get_tcb_desc(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info,
+ struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ struct ieee80211_rate *txrate;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+ if (ieee80211_is_data(fc)) {
+ txrate = ieee80211_get_tx_rate(hw, info);
+ tcb_desc->hw_rate = txrate->hw_value;
+
+ /*
+ *we set data rate RTL_RC_CCK_RATE1M
+ *in rtl_rc.c if skb is special data or
+ *mgt which need low data rate.
+ */
+
+ /*
+ *So tcb_desc->hw_rate is just used for
+ *special data and mgt frames
+ */
+ if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) {
+ tcb_desc->use_driver_rate = true;
+ tcb_desc->ratr_index = 7;
+
+ tcb_desc->hw_rate =
+ rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ tcb_desc->disable_ratefallback = 1;
+ } else {
+ /*
+ *because hw will nerver use hw_rate
+ *when tcb_desc->use_driver_rate = false
+ *so we never set highest N rate here,
+ *and N rate will all be controled by FW
+ *when tcb_desc->use_driver_rate = false
+ */
+ if (rtlmac->ht_enable) {
+ tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw);
+ } else {
+ if (rtlmac->mode == WIRELESS_MODE_B) {
+ tcb_desc->hw_rate =
+ rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
+ } else {
+ tcb_desc->hw_rate =
+ rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+ }
+ }
+ }
+
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
+ tcb_desc->b_multicast = 1;
+ else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+ tcb_desc->b_broadcast = 1;
+
+ _rtl_txrate_selectmode(hw, tcb_desc);
+ _rtl_query_bandwidth_mode(hw, tcb_desc);
+ _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
+ _rtl_query_shortgi(hw, tcb_desc, info);
+ _rtl_query_protection_mode(hw, tcb_desc, info);
+ } else {
+ tcb_desc->use_driver_rate = true;
+ tcb_desc->ratr_index = 7;
+ tcb_desc->disable_ratefallback = 1;
+ tcb_desc->mac_id = 0;
+
+ tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ }
+}
+EXPORT_SYMBOL(rtl_get_tcb_desc);
+
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ if (ieee80211_is_auth(fc)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+ rtl_ips_nic_on(hw);
+
+ mac->link_state = MAC80211_LINKING;
+ }
+
+ return true;
+}
+
+bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN));
+ u8 category;
+
+ if (!ieee80211_is_action(fc))
+ return true;
+
+ category = *act;
+ act++;
+ switch (category) {
+ case ACT_CAT_BA:
+ switch (*act) {
+ case ACT_ADDBAREQ:
+ if (mac->act_scanning)
+ return false;
+
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+ ("%s ACT_ADDBAREQ From :" MAC_FMT "\n",
+ is_tx ? "Tx" : "Rx", MAC_ARG(hdr->addr2)));
+ break;
+ case ACT_ADDBARSP:
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+ ("%s ACT_ADDBARSP From :" MAC_FMT "\n",
+ is_tx ? "Tx" : "Rx", MAC_ARG(hdr->addr2)));
+ break;
+ case ACT_DELBA:
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+ ("ACT_ADDBADEL From :" MAC_FMT "\n",
+ MAC_ARG(hdr->addr2)));
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/*should call before software enc*/
+u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u16 ether_type;
+ u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+ const struct iphdr *ip;
+
+ if (!ieee80211_is_data(fc))
+ goto end;
+
+ if (ieee80211_is_nullfunc(fc))
+ return true;
+
+ ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
+ SNAP_SIZE + PROTOC_TYPE_SIZE);
+ ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
+ ether_type = ntohs(ether_type);
+
+ if (ETH_P_IP == ether_type) {
+ if (IPPROTO_UDP == ip->protocol) {
+ struct udphdr *udp = (struct udphdr *)((u8 *) ip +
+ (ip->ihl << 2));
+ if (((((u8 *) udp)[1] == 68) &&
+ (((u8 *) udp)[3] == 67)) ||
+ ((((u8 *) udp)[1] == 67) &&
+ (((u8 *) udp)[3] == 68))) {
+ /*
+ * 68 : UDP BOOTP client
+ * 67 : UDP BOOTP server
+ */
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV),
+ DBG_DMESG, ("dhcp %s !!\n",
+ (is_tx) ? "Tx" : "Rx"));
+
+ if (is_tx) {
+ rtl_lps_leave(hw);
+ ppsc->last_delaylps_stamp_jiffies =
+ jiffies;
+ }
+
+ return true;
+ }
+ }
+ } else if (ETH_P_ARP == ether_type) {
+ if (is_tx) {
+ rtl_lps_leave(hw);
+ ppsc->last_delaylps_stamp_jiffies = jiffies;
+ }
+
+ return true;
+ } else if (ETH_P_PAE == ether_type) {
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+ ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"));
+
+ if (is_tx) {
+ rtl_lps_leave(hw);
+ ppsc->last_delaylps_stamp_jiffies = jiffies;
+ }
+
+ return true;
+ } else if (0x86DD == ether_type) {
+ return true;
+ }
+
+end:
+ return false;
+}
+
+/*********************************************************
+ *
+ * functions called by core.c
+ *
+ *********************************************************/
+int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_tid_data *tid_data;
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ ("on ra = %pM tid = %d\n", ra, tid));
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Start AGG when state is not RTL_AGG_OFF !\n"));
+ return -ENXIO;
+ }
+
+ tid_data = &mac->tids[tid];
+ *ssn = SEQ_TO_SN(tid_data->seq_number);
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ ("HW queue is empty tid:%d\n", tid));
+ tid_data->agg.agg_state = RTL_AGG_ON;
+
+ ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+
+ return 0;
+}
+
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid)
+{
+ int ssn = -1;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_tid_data *tid_data;
+
+ if (!ra) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+ return -EINVAL;
+ }
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ if (mac->tids[tid].agg.agg_state != RTL_AGG_ON)
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Stopping AGG while state not ON or starting\n"));
+
+ tid_data = &mac->tids[tid];
+ ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+
+ mac->tids[tid].agg.agg_state = RTL_AGG_OFF;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+
+ return 0;
+}
+
+/*********************************************************
+ *
+ * wq & timer callback functions
+ *
+ *********************************************************/
+void rtl_watchdog_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks = container_of_dwork_rtl(data,
+ struct rtl_works,
+ watchdog_wq);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ bool b_busytraffic = false;
+ bool b_higher_busytraffic = false;
+ bool b_higher_busyrxtraffic = false;
+ bool b_higher_busytxtraffic = false;
+
+ u8 idx = 0;
+ u32 rx_cnt_inp4eriod = 0;
+ u32 tx_cnt_inp4eriod = 0;
+ u32 aver_rx_cnt_inperiod = 0;
+ u32 aver_tx_cnt_inperiod = 0;
+
+ bool benter_ps = false;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ /* <1> Determine if action frame is allowed */
+ if (mac->link_state > MAC80211_NOLINK) {
+ if (mac->cnt_after_linked < 20)
+ mac->cnt_after_linked++;
+ } else {
+ mac->cnt_after_linked = 0;
+ }
+
+ /* <2> DM */
+ rtlpriv->cfg->ops->dm_watchdog(hw);
+
+ /*
+ *<3> to check if traffic busy, if
+ * busytraffic we don't change channel
+ */
+ if (mac->link_state >= MAC80211_LINKED) {
+
+ /* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */
+ for (idx = 0; idx <= 2; idx++) {
+ rtlpriv->link_info.num_rx_in4period[idx] =
+ rtlpriv->link_info.num_rx_in4period[idx + 1];
+ rtlpriv->link_info.num_tx_in4period[idx] =
+ rtlpriv->link_info.num_tx_in4period[idx + 1];
+ }
+ rtlpriv->link_info.num_rx_in4period[3] =
+ rtlpriv->link_info.num_rx_inperiod;
+ rtlpriv->link_info.num_tx_in4period[3] =
+ rtlpriv->link_info.num_tx_inperiod;
+ for (idx = 0; idx <= 3; idx++) {
+ rx_cnt_inp4eriod +=
+ rtlpriv->link_info.num_rx_in4period[idx];
+ tx_cnt_inp4eriod +=
+ rtlpriv->link_info.num_tx_in4period[idx];
+ }
+ aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4;
+ aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
+
+ /* (2) check traffic busy */
+ if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
+ b_busytraffic = true;
+
+ /* Higher Tx/Rx data. */
+ if (aver_rx_cnt_inperiod > 4000 ||
+ aver_tx_cnt_inperiod > 4000) {
+ b_higher_busytraffic = true;
+
+ /* Extremely high Rx data. */
+ if (aver_rx_cnt_inperiod > 5000)
+ b_higher_busyrxtraffic = true;
+ else
+ b_higher_busytxtraffic = false;
+ }
+
+ if (((rtlpriv->link_info.num_rx_inperiod +
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2))
+ benter_ps = false;
+ else
+ benter_ps = true;
+
+ /* LeisurePS only work in infra mode. */
+ if (benter_ps)
+ rtl_lps_enter(hw);
+ else
+ rtl_lps_leave(hw);
+ }
+
+ rtlpriv->link_info.num_rx_inperiod = 0;
+ rtlpriv->link_info.num_tx_inperiod = 0;
+
+ rtlpriv->link_info.b_busytraffic = b_busytraffic;
+ rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic;
+ rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic;
+
+}
+
+void rtl_watch_dog_timer_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.watchdog_wq, 0);
+
+ mod_timer(&rtlpriv->works.watchdog_timer,
+ jiffies + MSECS(RTL_WATCH_DOG_TIME));
+}
+
+/*********************************************************
+ *
+ * sysfs functions
+ *
+ *********************************************************/
+static ssize_t rtl_show_debug_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ieee80211_hw *hw = dev_get_drvdata(d);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ return sprintf(buf, "0x%08X\n", rtlpriv->dbg.global_debuglevel);
+}
+
+static ssize_t rtl_store_debug_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ieee80211_hw *hw = dev_get_drvdata(d);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret) {
+ printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf);
+ } else {
+ rtlpriv->dbg.global_debuglevel = val;
+ printk(KERN_DEBUG "debuglevel:%x\n",
+ rtlpriv->dbg.global_debuglevel);
+ }
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ rtl_show_debug_level, rtl_store_debug_level);
+
+static struct attribute *rtl_sysfs_entries[] = {
+
+ &dev_attr_debug_level.attr,
+
+ NULL
+};
+
+/*
+ * "name" is folder name witch will be
+ * put in device directory like :
+ * sys/devices/pci0000:00/0000:00:1c.4/
+ * 0000:06:00.0/rtl_sysfs
+ */
+struct attribute_group rtl_attribute_group = {
+ .name = "rtlsysfs",
+ .attrs = rtl_sysfs_entries,
+};
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
+
+static int __init rtl_core_module_init(void)
+{
+ return 0;
+}
+
+static void __exit rtl_core_module_exit(void)
+{
+}
+
+module_init(rtl_core_module_init);
+module_exit(rtl_core_module_exit);
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
new file mode 100644
index 000000000000..3de5a14745f1
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *****************************************************************************/
+
+#ifndef __RTL_BASE_H__
+#define __RTL_BASE_H__
+
+#define RTL_DUMMY_OFFSET 0
+#define RTL_DUMMY_UNIT 8
+#define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT)
+#define RTL_TX_DESC_SIZE 32
+#define RTL_TX_HEADER_SIZE (RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE)
+
+#define HT_AMSDU_SIZE_4K 3839
+#define HT_AMSDU_SIZE_8K 7935
+
+#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */
+#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */
+
+#define RTL_RATE_COUNT_LEGACY 12
+#define RTL_CHANNEL_COUNT 14
+
+#define FRAME_OFFSET_FRAME_CONTROL 0
+#define FRAME_OFFSET_DURATION 2
+#define FRAME_OFFSET_ADDRESS1 4
+#define FRAME_OFFSET_ADDRESS2 10
+#define FRAME_OFFSET_ADDRESS3 16
+#define FRAME_OFFSET_SEQUENCE 22
+#define FRAME_OFFSET_ADDRESS4 24
+
+#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \
+ WRITEEF2BYTE(_hdr, _val)
+#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \
+ WRITEEF1BYTE(_hdr, _val)
+#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \
+ SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val)
+#define SET_80211_HDR_TO_DS(_hdr, _val) \
+ SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val)
+
+#define SET_80211_PS_POLL_AID(_hdr, _val) \
+ WRITEEF2BYTE(((u8 *)(_hdr)) + 2, _val)
+#define SET_80211_PS_POLL_BSSID(_hdr, _val) \
+ CP_MACADDR(((u8 *)(_hdr)) + 4, (u8 *)(_val))
+#define SET_80211_PS_POLL_TA(_hdr, _val) \
+ CP_MACADDR(((u8 *)(_hdr)) + 10, (u8 *)(_val))
+
+#define SET_80211_HDR_DURATION(_hdr, _val) \
+ WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_DURATION, _val)
+#define SET_80211_HDR_ADDRESS1(_hdr, _val) \
+ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val))
+#define SET_80211_HDR_ADDRESS2(_hdr, _val) \
+ CP_MACADDR((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val))
+#define SET_80211_HDR_ADDRESS3(_hdr, _val) \
+ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val))
+#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \
+ WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val)
+
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \
+ WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val)
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \
+ WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val)
+#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \
+ WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val)
+#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \
+ READEF2BYTE(((u8 *)(__phdr)) + 34)
+#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+ WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val)
+#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+ SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
+ (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))
+
+int rtl_init_core(struct ieee80211_hw *hw);
+void rtl_deinit_core(struct ieee80211_hw *hw);
+void rtl_init_rx_config(struct ieee80211_hw *hw);
+void rtl_init_rfkill(struct ieee80211_hw *hw);
+void rtl_deinit_rfkill(struct ieee80211_hw *hw);
+
+void rtl_watch_dog_timer_callback(unsigned long data);
+void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
+
+bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
+u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
+
+void rtl_watch_dog_timer_callback(unsigned long data);
+int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
+ u16 tid, u16 *ssn);
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid);
+void rtl_watchdog_wq_callback(void *data);
+
+void rtl_get_tcb_desc(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info,
+ struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
+
+extern struct attribute_group rtl_attribute_group;
+#endif
diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c
new file mode 100644
index 000000000000..52c9c1367cac
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/cam.c
@@ -0,0 +1,291 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "cam.h"
+
+void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->sec.use_defaultkey = false;
+ rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;
+ rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;
+ memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);
+ memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);
+ rtlpriv->sec.pairwise_key = NULL;
+}
+
+static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
+ u8 *mac_addr, u8 *key_cont_128, u16 us_config)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u32 target_command;
+ u32 target_content = 0;
+ u8 entry_i;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n",
+ key_cont_128[0], key_cont_128[1],
+ key_cont_128[2], key_cont_128[3],
+ key_cont_128[4], key_cont_128[5]));
+
+ for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+ target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
+ target_command = target_command | BIT(31) | BIT(16);
+
+ if (entry_i == 0) {
+ target_content = (u32) (*(mac_addr + 0)) << 16 |
+ (u32) (*(mac_addr + 1)) << 24 | (u32) us_config;
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+ target_content);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+ target_command);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): "
+ "WRITE %x: %x\n",
+ rtlpriv->cfg->maps[WCAMI], target_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("The Key ID is %d\n", entry_no));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): "
+ "WRITE %x: %x\n",
+ rtlpriv->cfg->maps[RWCAM], target_command));
+
+ } else if (entry_i == 1) {
+
+ target_content = (u32) (*(mac_addr + 5)) << 24 |
+ (u32) (*(mac_addr + 4)) << 16 |
+ (u32) (*(mac_addr + 3)) << 8 |
+ (u32) (*(mac_addr + 2));
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+ target_content);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+ target_command);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): WRITE A4: %x\n",
+ target_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): WRITE A0: %x\n",
+ target_command));
+
+ } else {
+
+ target_content =
+ (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
+ 24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2))
+ << 16 |
+ (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
+ | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0));
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+ target_content);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+ target_command);
+ udelay(100);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): WRITE A4: %x\n",
+ target_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_program_entry(): WRITE A0: %x\n",
+ target_command));
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("after set key, usconfig:%x\n", us_config));
+}
+
+u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+ u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
+ u32 ul_default_key, u8 *key_content)
+{
+ u32 us_config;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, "
+ "ulUseDK=%x MacAddr" MAC_FMT "\n",
+ ul_entry_idx, ul_key_id, ul_enc_alg,
+ ul_default_key, MAC_ARG(mac_addr)));
+
+ if (ul_key_id == TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("<=== ulKeyId exceed!\n"));
+ return 0;
+ }
+
+ if (ul_default_key == 1) {
+ us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);
+ } else {
+ us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
+ }
+
+ rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
+ (u8 *) key_content, us_config);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("<===\n"));
+
+ return 1;
+
+}
+EXPORT_SYMBOL(rtl_cam_add_one_entry);
+
+int rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
+ u8 *mac_addr, u32 ul_key_id)
+{
+ u32 ul_command;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id));
+
+ ul_command = ul_key_id * CAM_CONTENT_COUNT;
+ ul_command = ul_command | BIT(31) | BIT(16);
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_delete_one_entry(): WRITE A0: %x\n", ul_command));
+
+ return 0;
+
+}
+EXPORT_SYMBOL(rtl_cam_delete_one_entry);
+
+void rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
+{
+ u32 ul_command;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ ul_command = BIT(31) | BIT(30);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+}
+EXPORT_SYMBOL(rtl_cam_reset_all_entry);
+
+void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u32 ul_command;
+ u32 ul_content;
+ u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+
+ switch (rtlpriv->sec.pairwise_enc_algorithm) {
+ case WEP40_ENCRYPTION:
+ ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
+ break;
+ case WEP104_ENCRYPTION:
+ ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
+ break;
+ case TKIP_ENCRYPTION:
+ ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
+ break;
+ case AESCCMP_ENCRYPTION:
+ ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ break;
+ default:
+ ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ }
+
+ ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2);
+
+ ul_content |= BIT(15);
+ ul_command = CAM_CONTENT_COUNT * uc_index;
+ ul_command = ul_command | BIT(31) | BIT(16);
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command));
+}
+EXPORT_SYMBOL(rtl_cam_mark_invalid);
+
+void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u32 ul_command;
+ u32 ul_content;
+ u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ u8 entry_i;
+
+ switch (rtlpriv->sec.pairwise_enc_algorithm) {
+ case WEP40_ENCRYPTION:
+ ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
+ break;
+ case WEP104_ENCRYPTION:
+ ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
+ break;
+ case TKIP_ENCRYPTION:
+ ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
+ break;
+ case AESCCMP_ENCRYPTION:
+ ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ break;
+ default:
+ ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ }
+
+ for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+
+ if (entry_i == 0) {
+ ul_content =
+ (uc_index & 0x03) | ((u16) (ul_encalgo) << 2);
+ ul_content |= BIT(15);
+
+ } else {
+ ul_content = 0;
+ }
+
+ ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
+ ul_command = ul_command | BIT(31) | BIT(16);
+
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
+ rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("rtl_cam_empty_entry(): WRITE A4: %x\n",
+ ul_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("rtl_cam_empty_entry(): WRITE A0: %x\n",
+ ul_command));
+ }
+
+}
+EXPORT_SYMBOL(rtl_cam_empty_entry);
diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h
new file mode 100644
index 000000000000..dd82f057d53d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/cam.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_CAM_H_
+#define __RTL_CAM_H_
+
+#define TOTAL_CAM_ENTRY 32
+#define CAM_CONTENT_COUNT 8
+
+#define CFG_DEFAULT_KEY BIT(5)
+#define CFG_VALID BIT(15)
+
+#define PAIRWISE_KEYIDX 0
+#define CAM_PAIRWISE_KEY_POSITION 4
+
+#define CAM_CONFIG_USEDK 1
+#define CAM_CONFIG_NO_USEDK 0
+
+extern void rtl_cam_reset_all_entry(struct ieee80211_hw *hw);
+extern u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+ u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
+ u32 ul_default_key, u8 *key_content);
+int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+ u32 ul_key_id);
+void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
+void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index);
+void rtl_cam_reset_sec_info(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
new file mode 100644
index 000000000000..d6a924a05654
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -0,0 +1,1029 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "core.h"
+#include "cam.h"
+#include "base.h"
+#include "ps.h"
+
+/*mutex for start & stop is must here. */
+static int rtl_op_start(struct ieee80211_hw *hw)
+{
+ int err = 0;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (!is_hal_stop(rtlhal))
+ return 0;
+ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+ return 0;
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+ err = rtlpriv->intf_ops->adapter_start(hw);
+ if (err)
+ goto out;
+ rtl_watch_dog_timer_callback((unsigned long)hw);
+out:
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+ return err;
+}
+
+static void rtl_op_stop(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
+ rtl_ips_nic_on(hw);
+ mdelay(1);
+ }
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+
+ mac->link_state = MAC80211_NOLINK;
+ memset(mac->bssid, 0, 6);
+
+ /*reset sec info */
+ rtl_cam_reset_sec_info(hw);
+
+ rtl_deinit_deferred_work(hw);
+ rtlpriv->intf_ops->adapter_stop(hw);
+
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+static int rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
+ goto err_free;
+
+ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+ goto err_free;
+
+
+ rtlpriv->intf_ops->adapter_tx(hw, skb);
+
+ return NETDEV_TX_OK;
+
+err_free:
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static int rtl_op_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ int err = 0;
+
+ if (mac->vif) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("vif has been set!! mac->vif = 0x%p\n", mac->vif));
+ return -EOPNOTSUPP;
+ }
+
+ rtl_ips_nic_on(hw);
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (mac->beacon_enabled == 1) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("NL80211_IFTYPE_STATION\n"));
+ mac->beacon_enabled = 0;
+ rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+ rtlpriv->cfg->maps
+ [RTL_IBSS_INT_MASKS]);
+ }
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("NL80211_IFTYPE_ADHOC\n"));
+
+ mac->link_state = MAC80211_LINKED;
+ rtlpriv->cfg->ops->set_bcn_reg(hw);
+ break;
+ case NL80211_IFTYPE_AP:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("NL80211_IFTYPE_AP\n"));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("operation mode %d is not support!\n", vif->type));
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ mac->vif = vif;
+ mac->opmode = vif->type;
+ rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+ memcpy(mac->mac_addr, vif->addr, ETH_ALEN);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+
+out:
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+ return err;
+}
+
+static void rtl_op_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+
+ /* Free beacon resources */
+ if ((mac->opmode == NL80211_IFTYPE_AP) ||
+ (mac->opmode == NL80211_IFTYPE_ADHOC) ||
+ (mac->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ if (mac->beacon_enabled == 1) {
+ mac->beacon_enabled = 0;
+ rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+ rtlpriv->cfg->maps
+ [RTL_IBSS_INT_MASKS]);
+ }
+ }
+
+ /*
+ *Note: We assume NL80211_IFTYPE_UNSPECIFIED as
+ *NO LINK for our hardware.
+ */
+ mac->vif = NULL;
+ mac->link_state = MAC80211_NOLINK;
+ memset(mac->bssid, 0, 6);
+ mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
+ rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+
+static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct ieee80211_conf *conf = &hw->conf;
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n"));
+ }
+
+ /*For IPS */
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ if (hw->conf.flags & IEEE80211_CONF_IDLE)
+ rtl_ips_nic_off(hw);
+ else
+ rtl_ips_nic_on(hw);
+ } else {
+ /*
+ *although rfoff may not cause by ips, but we will
+ *check the reason in set_rf_power_state function
+ */
+ if (unlikely(ppsc->rfpwr_state == ERFOFF))
+ rtl_ips_nic_on(hw);
+ }
+
+ /*For LPS */
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ if (conf->flags & IEEE80211_CONF_PS)
+ rtl_lps_enter(hw);
+ else
+ rtl_lps_leave(hw);
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n",
+ hw->conf.long_frame_max_tx_count));
+ mac->retry_long = hw->conf.long_frame_max_tx_count;
+ mac->retry_short = hw->conf.long_frame_max_tx_count;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
+ (u8 *) (&hw->conf.
+ long_frame_max_tx_count));
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ struct ieee80211_channel *channel = hw->conf.channel;
+ u8 wide_chan = (u8) channel->hw_value;
+
+ /*
+ *because we should back channel to
+ *current_network.chan in in scanning,
+ *So if set_chan == current_network.chan
+ *we should set it.
+ *because mac80211 tell us wrong bw40
+ *info for cisco1253 bw20, so we modify
+ *it here based on UPPER & LOWER
+ */
+ switch (hw->conf.channel_type) {
+ case NL80211_CHAN_HT20:
+ case NL80211_CHAN_NO_HT:
+ /* SC */
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_DONT_CARE;
+ rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20;
+ mac->bw_40 = false;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ /* SC */
+ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER;
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_20_40;
+ mac->bw_40 = true;
+
+ /*wide channel */
+ wide_chan -= 2;
+
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ /* SC */
+ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER;
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_20_40;
+ mac->bw_40 = true;
+
+ /*wide channel */
+ wide_chan += 2;
+
+ break;
+ default:
+ mac->bw_40 = false;
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not processed\n"));
+ break;
+ }
+
+ if (wide_chan <= 0)
+ wide_chan = 1;
+ rtlphy->current_channel = wide_chan;
+
+ rtlpriv->cfg->ops->set_channel_access(hw);
+ rtlpriv->cfg->ops->switch_channel(hw);
+ rtlpriv->cfg->ops->set_bw_mode(hw,
+ hw->conf.channel_type);
+ }
+
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+
+ return 0;
+}
+
+static void rtl_op_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *new_flags, u64 multicast)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ *new_flags &= RTL_SUPPORTED_FILTERS;
+ if (!changed_flags)
+ return;
+
+ /*TODO: we disable broadcase now, so enable here */
+ if (changed_flags & FIF_ALLMULTI) {
+ if (*new_flags & FIF_ALLMULTI) {
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+ rtlpriv->cfg->maps[MAC_RCR_AB];
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Enable receive multicast frame.\n"));
+ } else {
+ mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+ rtlpriv->cfg->maps[MAC_RCR_AB]);
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Disable receive multicast frame.\n"));
+ }
+ }
+
+ if (changed_flags & FIF_FCSFAIL) {
+ if (*new_flags & FIF_FCSFAIL) {
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Enable receive FCS error frame.\n"));
+ } else {
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Disable receive FCS error frame.\n"));
+ }
+ }
+
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ /*
+ *TODO: BIT(5) is probe response BIT(8) is beacon
+ *TODO: Use define for BIT(5) and BIT(8)
+ */
+ if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+ mac->rx_mgt_filter |= (BIT(5) | BIT(8));
+ else
+ mac->rx_mgt_filter &= ~(BIT(5) | BIT(8));
+ }
+
+ if (changed_flags & FIF_CONTROL) {
+ if (*new_flags & FIF_CONTROL) {
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+ mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER;
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Enable receive control frame.\n"));
+ } else {
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+ mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER;
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Disable receive control frame.\n"));
+ }
+ }
+
+ if (changed_flags & FIF_OTHER_BSS) {
+ if (*new_flags & FIF_OTHER_BSS) {
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Enable receive other BSS's frame.\n"));
+ } else {
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("Disable receive other BSS's frame.\n"));
+ }
+ }
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER,
+ (u8 *) (&mac->rx_mgt_filter));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER,
+ (u8 *) (&mac->rx_ctrl_filter));
+}
+
+static int _rtl_get_hal_qnum(u16 queue)
+{
+ int qnum;
+
+ switch (queue) {
+ case 0:
+ qnum = AC3_VO;
+ break;
+ case 1:
+ qnum = AC2_VI;
+ break;
+ case 2:
+ qnum = AC0_BE;
+ break;
+ case 3:
+ qnum = AC1_BK;
+ break;
+ default:
+ qnum = AC0_BE;
+ break;
+ }
+ return qnum;
+}
+
+/*
+ *for mac80211 VO=0, VI=1, BE=2, BK=3
+ *for rtl819x BE=0, BK=1, VI=2, VO=3
+ */
+static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *param)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ int aci;
+
+ if (queue >= AC_MAX) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("queue number %d is incorrect!\n", queue));
+ return -EINVAL;
+ }
+
+ aci = _rtl_get_hal_qnum(queue);
+ mac->ac[aci].aifs = param->aifs;
+ mac->ac[aci].cw_min = param->cw_min;
+ mac->ac[aci].cw_max = param->cw_max;
+ mac->ac[aci].tx_op = param->txop;
+ memcpy(&mac->edca_param[aci], param, sizeof(*param));
+ rtlpriv->cfg->ops->set_qos(hw, aci);
+ return 0;
+}
+
+static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf, u32 changed)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+
+ if ((vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) {
+
+ if ((changed & BSS_CHANGED_BEACON) ||
+ (changed & BSS_CHANGED_BEACON_ENABLED &&
+ bss_conf->enable_beacon)) {
+
+ if (mac->beacon_enabled == 0) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("BSS_CHANGED_BEACON_ENABLED\n"));
+
+ /*start hw beacon interrupt. */
+ /*rtlpriv->cfg->ops->set_bcn_reg(hw); */
+ mac->beacon_enabled = 1;
+ rtlpriv->cfg->ops->update_interrupt_mask(hw,
+ rtlpriv->cfg->maps
+ [RTL_IBSS_INT_MASKS],
+ 0);
+ }
+ } else {
+ if (mac->beacon_enabled == 1) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("ADHOC DISABLE BEACON\n"));
+
+ mac->beacon_enabled = 0;
+ rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+ rtlpriv->cfg->maps
+ [RTL_IBSS_INT_MASKS]);
+ }
+ }
+
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE,
+ ("BSS_CHANGED_BEACON_INT\n"));
+ mac->beacon_interval = bss_conf->beacon_int;
+ rtlpriv->cfg->ops->set_bcn_intv(hw);
+ }
+ }
+
+ /*TODO: reference to enum ieee80211_bss_change */
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ mac->link_state = MAC80211_LINKED;
+ mac->cnt_after_linked = 0;
+ mac->assoc_id = bss_conf->aid;
+ memcpy(mac->bssid, bss_conf->bssid, 6);
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("BSS_CHANGED_ASSOC\n"));
+ } else {
+ if (mac->link_state == MAC80211_LINKED)
+ rtl_lps_leave(hw);
+
+ mac->link_state = MAC80211_NOLINK;
+ memset(mac->bssid, 0, 6);
+
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("BSS_CHANGED_UN_ASSOC\n"));
+ }
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("BSS_CHANGED_ERP_CTS_PROT\n"));
+ mac->use_cts_protect = bss_conf->use_cts_prot;
+ }
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n",
+ bss_conf->use_short_preamble));
+
+ mac->short_preamble = bss_conf->use_short_preamble;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
+ (u8 *) (&mac->short_preamble));
+ }
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("BSS_CHANGED_ERP_SLOT\n"));
+
+ if (bss_conf->use_short_slot)
+ mac->slot_time = RTL_SLOT_TIME_9;
+ else
+ mac->slot_time = RTL_SLOT_TIME_20;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *) (&mac->slot_time));
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ struct ieee80211_sta *sta = NULL;
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("BSS_CHANGED_HT\n"));
+
+ sta = ieee80211_find_sta(mac->vif, mac->bssid);
+
+ if (sta) {
+ if (sta->ht_cap.ampdu_density >
+ mac->current_ampdu_density)
+ mac->current_ampdu_density =
+ sta->ht_cap.ampdu_density;
+ if (sta->ht_cap.ampdu_factor <
+ mac->current_ampdu_factor)
+ mac->current_ampdu_factor =
+ sta->ht_cap.ampdu_factor;
+ }
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY,
+ (u8 *) (&mac->max_mss_density));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR,
+ &mac->current_ampdu_factor);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE,
+ &mac->current_ampdu_density);
+ }
+
+ if (changed & BSS_CHANGED_BSSID) {
+ struct ieee80211_sta *sta = NULL;
+ u32 basic_rates;
+ u8 i;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
+ (u8 *) bss_conf->bssid);
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ (MAC_FMT "\n", MAC_ARG(bss_conf->bssid)));
+
+ memcpy(mac->bssid, bss_conf->bssid, 6);
+ if (is_valid_ether_addr(bss_conf->bssid)) {
+ switch (vif->type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ break;
+ case NL80211_IFTYPE_STATION:
+ break;
+ case NL80211_IFTYPE_AP:
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+ } else
+ rtlpriv->cfg->ops->set_network_type(hw,
+ NL80211_IFTYPE_UNSPECIFIED);
+
+ memset(mac->mcs, 0, 16);
+ mac->ht_enable = false;
+ mac->sgi_40 = false;
+ mac->sgi_20 = false;
+
+ if (!bss_conf->use_short_slot)
+ mac->mode = WIRELESS_MODE_B;
+ else
+ mac->mode = WIRELESS_MODE_G;
+
+ sta = ieee80211_find_sta(mac->vif, mac->bssid);
+
+ if (sta) {
+ if (sta->ht_cap.ht_supported) {
+ mac->mode = WIRELESS_MODE_N_24G;
+ mac->ht_enable = true;
+ }
+
+ if (mac->ht_enable) {
+ u16 ht_cap = sta->ht_cap.cap;
+ memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16);
+
+ for (i = 0; i < 16; i++)
+ RT_TRACE(rtlpriv, COMP_MAC80211,
+ DBG_LOUD, ("%x ",
+ mac->mcs[i]));
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ ("\n"));
+
+ if (ht_cap & IEEE80211_HT_CAP_SGI_40)
+ mac->sgi_40 = true;
+
+ if (ht_cap & IEEE80211_HT_CAP_SGI_20)
+ mac->sgi_20 = true;
+
+ /*
+ * for cisco 1252 bw20 it's wrong
+ * if (ht_cap &
+ * IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ * mac->bw_40 = true;
+ * }
+ */
+ }
+ }
+
+ /*mac80211 just give us CCK rates any time
+ *So we add G rate in basic rates when
+ not in B mode*/
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (mac->mode == WIRELESS_MODE_B)
+ basic_rates = bss_conf->basic_rates | 0x00f;
+ else
+ basic_rates = bss_conf->basic_rates | 0xff0;
+
+ if (!vif)
+ goto out;
+
+ mac->basic_rates = basic_rates;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *) (&basic_rates));
+
+ if (rtlpriv->dm.b_useramask)
+ rtlpriv->cfg->ops->update_rate_mask(hw, 0);
+ else
+ rtlpriv->cfg->ops->update_rate_table(hw);
+
+ }
+ }
+
+ /*
+ * For FW LPS:
+ * To tell firmware we have connected
+ * to an AP. For 92SE/CE power save v2.
+ */
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ if (ppsc->b_fwctrl_lps) {
+ u8 mstatus = RT_MEDIA_CONNECT;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_JOINBSSRPT,
+ (u8 *) (&mstatus));
+ ppsc->report_linked = true;
+ }
+ } else {
+ if (ppsc->b_fwctrl_lps) {
+ u8 mstatus = RT_MEDIA_DISCONNECT;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_JOINBSSRPT,
+ (u8 *)(&mstatus));
+ ppsc->report_linked = false;
+ }
+ }
+ }
+
+out:
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u64 tsf;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&tsf));
+ return tsf;
+}
+
+static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;;
+
+ mac->tsf = tsf;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
+}
+
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp = 0;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *) (&tmp));
+}
+
+static void rtl_op_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ break;
+ case STA_NOTIFY_AWAKE:
+ break;
+ default:
+ break;
+ }
+}
+
+static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 * ssn)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid));
+ return rtl_tx_agg_start(hw, sta->addr, tid, ssn);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid));
+ return rtl_tx_agg_stop(hw, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid));
+ break;
+ case IEEE80211_AMPDU_RX_START:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("IEEE80211_AMPDU_RX_START:TID:%d\n", tid));
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ ("IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("IEEE80211_AMPDU_ERR!!!!:\n"));
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ mac->act_scanning = true;
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n"));
+
+ if (mac->link_state == MAC80211_LINKED) {
+ rtl_lps_leave(hw);
+ mac->link_state = MAC80211_LINKED_SCANNING;
+ } else
+ rtl_ips_nic_on(hw);
+
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY);
+ rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP);
+}
+
+static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n"));
+
+ rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
+ mac->act_scanning = false;
+ if (mac->link_state == MAC80211_LINKED_SCANNING) {
+ mac->link_state = MAC80211_LINKED;
+
+ /* fix fwlps issue */
+ rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+
+ if (rtlpriv->dm.b_useramask)
+ rtlpriv->cfg->ops->update_rate_mask(hw, 0);
+ else
+ rtlpriv->cfg->ops->update_rate_table(hw);
+
+ }
+
+}
+
+static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 key_type = NO_ENCRYPTION;
+ u8 key_idx;
+ bool group_key = false;
+ bool wep_only = false;
+ int err = 0;
+ u8 mac_addr[ETH_ALEN];
+ u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ u8 zero_addr[ETH_ALEN] = { 0 };
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("not open hw encryption\n"));
+ return -ENOSPC; /*User disabled HW-crypto */
+ }
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("%s hardware based encryption for keyidx: %d, mac: %pM\n",
+ cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+ sta ? sta->addr : bcast_addr));
+ rtlpriv->sec.being_setkey = true;
+ rtl_ips_nic_on(hw);
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+ /* <1> get encryption alg */
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key_type = WEP40_ENCRYPTION;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n"));
+ rtlpriv->sec.use_defaultkey = true;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("alg:WEP104\n"));
+ key_type = WEP104_ENCRYPTION;
+ rtlpriv->sec.use_defaultkey = true;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key_type = TKIP_ENCRYPTION;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n"));
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ rtlpriv->sec.use_defaultkey = true;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key_type = AESCCMP_ENCRYPTION;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n"));
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ rtlpriv->sec.use_defaultkey = true;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("alg_err:%x!!!!:\n", key->cipher));
+ goto out_unlock;
+ }
+ /* <2> get key_idx */
+ key_idx = (u8) (key->keyidx);
+ if (key_idx > 3)
+ goto out_unlock;
+ /* <3> if pairwise key enable_hw_sec */
+ group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
+ if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
+ rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
+ if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION &&
+ (key_type == WEP40_ENCRYPTION ||
+ key_type == WEP104_ENCRYPTION))
+ wep_only = true;
+ rtlpriv->sec.pairwise_enc_algorithm = key_type;
+ rtlpriv->cfg->ops->enable_hw_sec(hw);
+ }
+ /* <4> set key based on cmd */
+ switch (cmd) {
+ case SET_KEY:
+ if (wep_only) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set WEP(group/pairwise) key\n"));
+ /* Pairwise key with an assigned MAC address. */
+ rtlpriv->sec.pairwise_enc_algorithm = key_type;
+ rtlpriv->sec.group_enc_algorithm = key_type;
+ /*set local buf about wep key. */
+ memcpy(rtlpriv->sec.key_buf[key_idx],
+ key->key, key->keylen);
+ rtlpriv->sec.key_len[key_idx] = key->keylen;
+ memcpy(mac_addr, zero_addr, ETH_ALEN);
+ } else if (group_key) { /* group key */
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set group key\n"));
+ /* group key */
+ rtlpriv->sec.group_enc_algorithm = key_type;
+ /*set local buf about group key. */
+ memcpy(rtlpriv->sec.key_buf[key_idx],
+ key->key, key->keylen);
+ rtlpriv->sec.key_len[key_idx] = key->keylen;
+ memcpy(mac_addr, bcast_addr, ETH_ALEN);
+ } else { /* pairwise key */
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set pairwise key\n"));
+ if (!sta) {
+ RT_ASSERT(false, ("pairwise key withnot"
+ "mac_addr\n"));
+ err = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ /* Pairwise key with an assigned MAC address. */
+ rtlpriv->sec.pairwise_enc_algorithm = key_type;
+ /*set local buf about pairwise key. */
+ memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX],
+ key->key, key->keylen);
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen;
+ rtlpriv->sec.pairwise_key =
+ rtlpriv->sec.key_buf[PAIRWISE_KEYIDX];
+ memcpy(mac_addr, sta->addr, ETH_ALEN);
+ }
+ rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr,
+ group_key, key_type, wep_only,
+ false);
+ /* <5> tell mac80211 do something: */
+ /*must use sw generate IV, or can not work !!!!. */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ key->hw_key_idx = key_idx;
+ if (key_type == TKIP_ENCRYPTION)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ break;
+ case DISABLE_KEY:
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("disable key delete one entry\n"));
+ /*set local buf about wep key. */
+ memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen);
+ rtlpriv->sec.key_len[key_idx] = 0;
+ memcpy(mac_addr, zero_addr, ETH_ALEN);
+ /*
+ *mac80211 will delete entrys one by one,
+ *so don't use rtl_cam_reset_all_entry
+ *or clear all entry here.
+ */
+ rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("cmd_err:%x!!!!:\n", cmd));
+ }
+out_unlock:
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+ rtlpriv->sec.being_setkey = false;
+ return err;
+}
+
+static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ bool radio_state;
+ bool blocked;
+ u8 valid = 0;
+
+ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+ return;
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+
+ /*if Radio On return true here */
+ radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
+
+ if (valid) {
+ if (unlikely(radio_state != rtlpriv->rfkill.rfkill_state)) {
+ rtlpriv->rfkill.rfkill_state = radio_state;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ (KERN_INFO "wireless radio switch turned %s\n",
+ radio_state ? "on" : "off"));
+
+ blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+ }
+ }
+
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+const struct ieee80211_ops rtl_ops = {
+ .start = rtl_op_start,
+ .stop = rtl_op_stop,
+ .tx = rtl_op_tx,
+ .add_interface = rtl_op_add_interface,
+ .remove_interface = rtl_op_remove_interface,
+ .config = rtl_op_config,
+ .configure_filter = rtl_op_configure_filter,
+ .set_key = rtl_op_set_key,
+ .conf_tx = rtl_op_conf_tx,
+ .bss_info_changed = rtl_op_bss_info_changed,
+ .get_tsf = rtl_op_get_tsf,
+ .set_tsf = rtl_op_set_tsf,
+ .reset_tsf = rtl_op_reset_tsf,
+ .sta_notify = rtl_op_sta_notify,
+ .ampdu_action = rtl_op_ampdu_action,
+ .sw_scan_start = rtl_op_sw_scan_start,
+ .sw_scan_complete = rtl_op_sw_scan_complete,
+ .rfkill_poll = rtl_op_rfkill_poll,
+};
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
new file mode 100644
index 000000000000..0ef31c3c6196
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *****************************************************************************/
+
+#ifndef __RTL_CORE_H__
+#define __RTL_CORE_H__
+
+#define RTL_SUPPORTED_FILTERS \
+ (FIF_PROMISC_IN_BSS | \
+ FIF_ALLMULTI | FIF_CONTROL | \
+ FIF_OTHER_BSS | \
+ FIF_FCSFAIL | \
+ FIF_BCN_PRBRESP_PROMISC)
+
+#define RTL_SUPPORTED_CTRL_FILTER 0xFF
+
+extern const struct ieee80211_ops rtl_ops;
+#endif
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
new file mode 100644
index 000000000000..5fa73852cb66
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *****************************************************************************/
+
+#include "wifi.h"
+
+void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 i;
+
+ rtlpriv->dbg.global_debuglevel = DBG_EMERG;
+
+ rtlpriv->dbg.global_debugcomponents =
+ COMP_ERR | COMP_FW | COMP_INIT | COMP_RECV | COMP_SEND |
+ COMP_MLME | COMP_SCAN | COMP_INTR | COMP_LED | COMP_SEC |
+ COMP_BEACON | COMP_RATE | COMP_RXDESC | COMP_DIG | COMP_TXAGC |
+ COMP_POWER | COMP_POWER_TRACKING | COMP_BB_POWERSAVING | COMP_SWAS |
+ COMP_RF | COMP_TURBO | COMP_RATR | COMP_CMD |
+ COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN;
+
+ for (i = 0; i < DBGP_TYPE_MAX; i++)
+ rtlpriv->dbg.dbgp_type[i] = 0;
+
+ /*Init Debug flag enable condition */
+}
diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h
new file mode 100644
index 000000000000..08bdec2ceda4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/debug.h
@@ -0,0 +1,212 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *****************************************************************************/
+
+#ifndef __RTL_DEBUG_H__
+#define __RTL_DEBUG_H__
+
+/*--------------------------------------------------------------
+ Debug level
+--------------------------------------------------------------*/
+/*
+ *Fatal bug.
+ *For example, Tx/Rx/IO locked up,
+ *memory access violation,
+ *resource allocation failed,
+ *unexpected HW behavior, HW BUG
+ *and so on.
+ */
+#define DBG_EMERG 0
+
+/*
+ *Abnormal, rare, or unexpeted cases.
+ *For example, Packet/IO Ctl canceled,
+ *device suprisely unremoved and so on.
+ */
+#define DBG_WARNING 2
+
+/*
+ *Normal case driver developer should
+ *open, we can see link status like
+ *assoc/AddBA/DHCP/adapter start and
+ *so on basic and useful infromations.
+ */
+#define DBG_DMESG 3
+
+/*
+ *Normal case with useful information
+ *about current SW or HW state.
+ *For example, Tx/Rx descriptor to fill,
+ *Tx/Rx descriptor completed status,
+ *SW protocol state change, dynamic
+ *mechanism state change and so on.
+ */
+#define DBG_LOUD 4
+
+/*
+ *Normal case with detail execution
+ *flow or information.
+ */
+#define DBG_TRACE 5
+
+/*--------------------------------------------------------------
+ Define the rt_trace components
+--------------------------------------------------------------*/
+#define COMP_ERR BIT(0)
+#define COMP_FW BIT(1)
+#define COMP_INIT BIT(2) /*For init/deinit */
+#define COMP_RECV BIT(3) /*For Rx. */
+#define COMP_SEND BIT(4) /*For Tx. */
+#define COMP_MLME BIT(5) /*For MLME. */
+#define COMP_SCAN BIT(6) /*For Scan. */
+#define COMP_INTR BIT(7) /*For interrupt Related. */
+#define COMP_LED BIT(8) /*For LED. */
+#define COMP_SEC BIT(9) /*For sec. */
+#define COMP_BEACON BIT(10) /*For beacon. */
+#define COMP_RATE BIT(11) /*For rate. */
+#define COMP_RXDESC BIT(12) /*For rx desc. */
+#define COMP_DIG BIT(13) /*For DIG */
+#define COMP_TXAGC BIT(14) /*For Tx power */
+#define COMP_HIPWR BIT(15) /*For High Power Mechanism */
+#define COMP_POWER BIT(16) /*For lps/ips/aspm. */
+#define COMP_POWER_TRACKING BIT(17) /*For TX POWER TRACKING */
+#define COMP_BB_POWERSAVING BIT(18)
+#define COMP_SWAS BIT(19) /*For SW Antenna Switch */
+#define COMP_RF BIT(20) /*For RF. */
+#define COMP_TURBO BIT(21) /*For EDCA TURBO. */
+#define COMP_RATR BIT(22)
+#define COMP_CMD BIT(23)
+#define COMP_EFUSE BIT(24)
+#define COMP_QOS BIT(25)
+#define COMP_MAC80211 BIT(26)
+#define COMP_REGD BIT(27)
+#define COMP_CHAN BIT(28)
+
+/*--------------------------------------------------------------
+ Define the rt_print components
+--------------------------------------------------------------*/
+/* Define EEPROM and EFUSE check module bit*/
+#define EEPROM_W BIT(0)
+#define EFUSE_PG BIT(1)
+#define EFUSE_READ_ALL BIT(2)
+
+/* Define init check for module bit*/
+#define INIT_EEPROM BIT(0)
+#define INIT_TxPower BIT(1)
+#define INIT_IQK BIT(2)
+#define INIT_RF BIT(3)
+
+/* Define PHY-BB/RF/MAC check module bit */
+#define PHY_BBR BIT(0)
+#define PHY_BBW BIT(1)
+#define PHY_RFR BIT(2)
+#define PHY_RFW BIT(3)
+#define PHY_MACR BIT(4)
+#define PHY_MACW BIT(5)
+#define PHY_ALLR BIT(6)
+#define PHY_ALLW BIT(7)
+#define PHY_TXPWR BIT(8)
+#define PHY_PWRDIFF BIT(9)
+
+enum dbgp_flag_e {
+ FQOS = 0,
+ FTX = 1,
+ FRX = 2,
+ FSEC = 3,
+ FMGNT = 4,
+ FMLME = 5,
+ FRESOURCE = 6,
+ FBEACON = 7,
+ FISR = 8,
+ FPHY = 9,
+ FMP = 10,
+ FEEPROM = 11,
+ FPWR = 12,
+ FDM = 13,
+ FDBGCtrl = 14,
+ FC2H = 15,
+ FBT = 16,
+ FINIT = 17,
+ FIOCTL = 18,
+ DBGP_TYPE_MAX
+};
+
+#define RT_ASSERT(_exp, fmt) \
+ do { \
+ if (!(_exp)) { \
+ printk(KERN_DEBUG "%s:%s(): ", KBUILD_MODNAME, \
+ __func__); \
+ printk fmt; \
+ } \
+ } while (0);
+
+#define RT_TRACE(rtlpriv, comp, level, fmt)\
+ do { \
+ if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \
+ ((level) <= rtlpriv->dbg.global_debuglevel))) {\
+ printk(KERN_DEBUG "%s:%s():<%lx-%x> ", KBUILD_MODNAME, \
+ __func__, in_interrupt(), in_atomic()); \
+ printk fmt; \
+ } \
+ } while (0);
+
+#define RTPRINT(rtlpriv, dbgtype, dbgflag, printstr) \
+ do { \
+ if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) { \
+ printk(KERN_DEBUG "%s: ", KBUILD_MODNAME); \
+ printk printstr; \
+ } \
+ } while (0);
+
+#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \
+ _hexdatalen) \
+ do {\
+ if (unlikely(((_comp) & rtlpriv->dbg.global_debugcomponents) &&\
+ (_level <= rtlpriv->dbg.global_debuglevel))) { \
+ int __i; \
+ u8* ptr = (u8 *)_hexdata; \
+ printk(KERN_DEBUG "%s: ", KBUILD_MODNAME); \
+ printk("In process \"%s\" (pid %i):", current->comm,\
+ current->pid); \
+ printk(_titlestring); \
+ for (__i = 0; __i < (int)_hexdatalen; __i++) { \
+ printk("%02X%s", ptr[__i], (((__i + 1) % 4)\
+ == 0) ? " " : " ");\
+ if (((__i + 1) % 16) == 0) \
+ printk("\n"); \
+ } \
+ printk(KERN_DEBUG "\n"); \
+ } \
+ } while (0);
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) \
+ ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2],\
+ ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5]
+
+void rtl_dbgp_flag_init(struct ieee80211_hw *hw);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
new file mode 100644
index 000000000000..b8433f3a9bc2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -0,0 +1,1189 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "efuse.h"
+
+static const u8 MAX_PGPKT_SIZE = 9;
+static const u8 PGPKT_DATA_SIZE = 8;
+static const int EFUSE_MAX_SIZE = 512;
+
+static const u8 EFUSE_OOB_PROTECT_BYTES = 15;
+
+static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
+ {0, 0, 0, 2},
+ {0, 1, 0, 2},
+ {0, 2, 0, 2},
+ {1, 0, 0, 1},
+ {1, 0, 1, 1},
+ {1, 1, 0, 1},
+ {1, 1, 1, 3},
+ {1, 3, 0, 17},
+ {3, 3, 1, 48},
+ {10, 0, 0, 6},
+ {10, 3, 0, 1},
+ {10, 3, 1, 1},
+ {11, 0, 0, 28}
+};
+
+static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset,
+ u8 *pbuf);
+static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,
+ u8 *value);
+static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,
+ u16 *value);
+static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset,
+ u32 *value);
+static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset,
+ u8 value);
+static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset,
+ u16 value);
+static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset,
+ u32 value);
+static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr,
+ u8 *data);
+static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr,
+ u8 data);
+static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse);
+static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset,
+ u8 *data);
+static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset,
+ u8 word_en, u8 *data);
+static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
+ u8 *targetdata);
+static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
+ u16 efuse_addr, u8 word_en, u8 *data);
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite,
+ u8 pwrstate);
+static u16 efuse_get_current_size(struct ieee80211_hw *hw);
+static u8 efuse_calculate_word_cnts(u8 word_en);
+
+void efuse_initialize(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bytetemp;
+ u8 temp;
+
+ bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1);
+ temp = bytetemp | 0x20;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp);
+
+ bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1);
+ temp = bytetemp & 0xFE;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp);
+
+ bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3);
+ temp = bytetemp | 0x80;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp);
+
+ rtl_write_byte(rtlpriv, 0x2F8, 0x3);
+
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);
+
+}
+
+u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 data;
+ u8 bytetemp;
+ u8 temp;
+ u32 k = 0;
+
+ if (address < EFUSE_REAL_CONTENT_LEN) {
+ temp = address & 0xFF;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+ temp);
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+ temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+ temp);
+
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+ temp = bytetemp & 0x7F;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,
+ temp);
+
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+ while (!(bytetemp & 0x80)) {
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->
+ maps[EFUSE_CTRL] + 3);
+ k++;
+ if (k == 1000) {
+ k = 0;
+ break;
+ }
+ }
+ data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+ return data;
+ } else
+ return 0xFF;
+
+}
+EXPORT_SYMBOL(efuse_read_1byte);
+
+void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bytetemp;
+ u8 temp;
+ u32 k = 0;
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("Addr=%x Data =%x\n", address, value));
+
+ if (address < EFUSE_REAL_CONTENT_LEN) {
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value);
+
+ temp = address & 0xFF;
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+ temp);
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+
+ temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp);
+
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+ temp = bytetemp | 0x80;
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp);
+
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+
+ while (bytetemp & 0x80) {
+ bytetemp = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->
+ maps[EFUSE_CTRL] + 3);
+ k++;
+ if (k == 100) {
+ k = 0;
+ break;
+ }
+ }
+ }
+
+}
+
+static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 value32;
+ u8 readbyte;
+ u16 retry;
+
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+ (_offset & 0xff));
+ readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+ ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+ readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,
+ (readbyte & 0x7f));
+
+ retry = 0;
+ value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {
+ value32 = rtl_read_dword(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL]);
+ retry++;
+ }
+
+ udelay(50);
+ value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+
+ *pbuf = (u8) (value32 & 0xff);
+}
+
+void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 efuse_tbl[EFUSE_MAP_LEN];
+ u8 rtemp8[1];
+ u16 efuse_addr = 0;
+ u8 offset, wren;
+ u16 i;
+ u16 j;
+ u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT];
+ u16 efuse_utilized = 0;
+ u8 efuse_usage;
+
+ if ((_offset + _size_byte) > EFUSE_MAP_LEN) {
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("read_efuse(): Invalid offset(%#x) with read "
+ "bytes(%#x)!!\n", _offset, _size_byte));
+ return;
+ }
+
+ for (i = 0; i < EFUSE_MAX_SECTION; i++)
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+ efuse_word[i][j] = 0xFFFF;
+
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+ if (*rtemp8 != 0xFF) {
+ efuse_utilized++;
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+ ("Addr=%d\n", efuse_addr));
+ efuse_addr++;
+ }
+
+ while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) {
+ offset = ((*rtemp8 >> 4) & 0x0f);
+
+ if (offset < EFUSE_MAX_SECTION) {
+ wren = (*rtemp8 & 0x0f);
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+ ("offset-%d Worden=%x\n", offset, wren));
+
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+ if (!(wren & 0x01)) {
+ RTPRINT(rtlpriv, FEEPROM,
+ EFUSE_READ_ALL, ("Addr=%d\n",
+ efuse_addr));
+
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+ efuse_addr++;
+ efuse_utilized++;
+ efuse_word[offset][i] = (*rtemp8 & 0xff);
+
+ if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+ break;
+
+ RTPRINT(rtlpriv, FEEPROM,
+ EFUSE_READ_ALL, ("Addr=%d\n",
+ efuse_addr));
+
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+ efuse_addr++;
+ efuse_utilized++;
+ efuse_word[offset][i] |=
+ (((u16)*rtemp8 << 8) & 0xff00);
+
+ if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+ break;
+ }
+
+ wren >>= 1;
+ }
+ }
+
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+ ("Addr=%d\n", efuse_addr));
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+ if (*rtemp8 != 0xFF && (efuse_addr < 512)) {
+ efuse_utilized++;
+ efuse_addr++;
+ }
+ }
+
+ for (i = 0; i < EFUSE_MAX_SECTION; i++) {
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+ efuse_tbl[(i * 8) + (j * 2)] =
+ (efuse_word[i][j] & 0xff);
+ efuse_tbl[(i * 8) + ((j * 2) + 1)] =
+ ((efuse_word[i][j] >> 8) & 0xff);
+ }
+ }
+
+ for (i = 0; i < _size_byte; i++)
+ pbuf[i] = efuse_tbl[_offset + i];
+
+ rtlefuse->efuse_usedbytes = efuse_utilized;
+ efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN);
+ rtlefuse->efuse_usedpercentage = efuse_usage;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,
+ (u8 *)&efuse_utilized);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,
+ (u8 *)&efuse_usage);
+}
+
+bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 section_idx, i, Base;
+ u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used;
+ bool bwordchanged, bresult = true;
+
+ for (section_idx = 0; section_idx < 16; section_idx++) {
+ Base = section_idx * 8;
+ bwordchanged = false;
+
+ for (i = 0; i < 8; i = i + 2) {
+ if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] !=
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i]) ||
+ (rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i + 1] !=
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i +
+ 1])) {
+ words_need++;
+ bwordchanged = true;
+ }
+ }
+
+ if (bwordchanged == true)
+ hdr_num++;
+ }
+
+ totalbytes = hdr_num + words_need * 2;
+ efuse_used = rtlefuse->efuse_usedbytes;
+
+ if ((totalbytes + efuse_used) >=
+ (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
+ bresult = false;
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("efuse_shadow_update_chk(): totalbytes(%#x), "
+ "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n",
+ totalbytes, hdr_num, words_need, efuse_used));
+
+ return bresult;
+}
+
+void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
+ u16 offset, u32 *value)
+{
+ if (type == 1)
+ efuse_shadow_read_1byte(hw, offset, (u8 *) value);
+ else if (type == 2)
+ efuse_shadow_read_2byte(hw, offset, (u16 *) value);
+ else if (type == 4)
+ efuse_shadow_read_4byte(hw, offset, (u32 *) value);
+
+}
+
+void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,
+ u32 value)
+{
+ if (type == 1)
+ efuse_shadow_write_1byte(hw, offset, (u8) value);
+ else if (type == 2)
+ efuse_shadow_write_2byte(hw, offset, (u16) value);
+ else if (type == 4)
+ efuse_shadow_write_4byte(hw, offset, (u32) value);
+
+}
+
+bool efuse_shadow_update(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u16 i, offset, base;
+ u8 word_en = 0x0F;
+ u8 first_pg = false;
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("--->\n"));
+
+ if (!efuse_shadow_update_chk(hw)) {
+ efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+ memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+ (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("<---efuse out of capacity!!\n"));
+ return false;
+ }
+ efuse_power_switch(hw, true, true);
+
+ for (offset = 0; offset < 16; offset++) {
+
+ word_en = 0x0F;
+ base = offset * 8;
+
+ for (i = 0; i < 8; i++) {
+ if (first_pg == true) {
+
+ word_en &= ~(BIT(i / 2));
+
+ rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];
+ } else {
+
+ if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] !=
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) {
+ word_en &= ~(BIT(i / 2));
+
+ rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];
+ }
+ }
+ }
+
+ if (word_en != 0x0F) {
+ u8 tmpdata[8];
+ memcpy((void *)tmpdata,
+ (void *)(&rtlefuse->
+ efuse_map[EFUSE_MODIFY_MAP][base]), 8);
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("U-efuse\n"), tmpdata, 8);
+
+ if (!efuse_pg_packet_write(hw, (u8) offset, word_en,
+ tmpdata)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("PG section(%#x) fail!!\n", offset));
+ break;
+ }
+ }
+
+ }
+
+ efuse_power_switch(hw, true, false);
+ efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+
+ memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+ (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n"));
+ return true;
+}
+
+void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ if (rtlefuse->autoload_failflag == true) {
+ memset((void *)(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 128,
+ 0xFF);
+ } else
+ efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+
+ memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+ (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+
+}
+EXPORT_SYMBOL(rtl_efuse_shadow_map_update);
+
+void efuse_force_write_vendor_Id(struct ieee80211_hw *hw)
+{
+ u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ efuse_power_switch(hw, true, true);
+
+ efuse_pg_packet_write(hw, 1, 0xD, tmpdata);
+
+ efuse_power_switch(hw, true, false);
+
+}
+
+void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx)
+{
+}
+
+static void efuse_shadow_read_1byte(struct ieee80211_hw *hw,
+ u16 offset, u8 *value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+}
+
+static void efuse_shadow_read_2byte(struct ieee80211_hw *hw,
+ u16 offset, u16 *value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+ *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;
+
+}
+
+static void efuse_shadow_read_4byte(struct ieee80211_hw *hw,
+ u16 offset, u32 *value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+ *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;
+ *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16;
+ *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24;
+}
+
+static void efuse_shadow_write_1byte(struct ieee80211_hw *hw,
+ u16 offset, u8 value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value;
+}
+
+static void efuse_shadow_write_2byte(struct ieee80211_hw *hw,
+ u16 offset, u16 value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF;
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8;
+
+}
+
+static void efuse_shadow_write_4byte(struct ieee80211_hw *hw,
+ u16 offset, u32 value)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] =
+ (u8) (value & 0x000000FF);
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] =
+ (u8) ((value >> 8) & 0x0000FF);
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] =
+ (u8) ((value >> 16) & 0x00FF);
+ rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] =
+ (u8) ((value >> 24) & 0xFF);
+
+}
+
+static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmpidx = 0;
+ int bresult;
+
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+ (u8) (addr & 0xff));
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+ ((u8) ((addr >> 8) & 0x03)) |
+ (rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 2) &
+ 0xFC));
+
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);
+
+ while (!(0x80 & rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3))
+ && (tmpidx < 100)) {
+ tmpidx++;
+ }
+
+ if (tmpidx < 100) {
+ *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+ bresult = true;
+ } else {
+ *data = 0xff;
+ bresult = false;
+ }
+ return bresult;
+}
+
+static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmpidx = 0;
+ bool bresult;
+
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("Addr = %x Data=%x\n", addr, data));
+
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff));
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+ (rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] +
+ 2) & 0xFC) | (u8) ((addr >> 8) & 0x03));
+
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data);
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2);
+
+ while ((0x80 & rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_CTRL] + 3))
+ && (tmpidx < 100)) {
+ tmpidx++;
+ }
+
+ if (tmpidx < 100)
+ bresult = true;
+ else
+ bresult = false;
+
+ return bresult;
+}
+
+static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse)
+{
+ efuse_power_switch(hw, false, true);
+ read_efuse(hw, 0, 128, efuse);
+ efuse_power_switch(hw, false, false);
+}
+
+static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
+ u8 efuse_data, u8 offset, u8 *tmpdata,
+ u8 *readstate)
+{
+ bool bdataempty = true;
+ u8 hoffset;
+ u8 tmpidx;
+ u8 hworden;
+ u8 word_cnts;
+
+ hoffset = (efuse_data >> 4) & 0x0F;
+ hworden = efuse_data & 0x0F;
+ word_cnts = efuse_calculate_word_cnts(hworden);
+
+ if (hoffset == offset) {
+ for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) {
+ if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx,
+ &efuse_data)) {
+ tmpdata[tmpidx] = efuse_data;
+ if (efuse_data != 0xff)
+ bdataempty = true;
+ }
+ }
+
+ if (bdataempty == true)
+ *readstate = PG_STATE_DATA;
+ else {
+ *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
+ *readstate = PG_STATE_HEADER;
+ }
+
+ } else {
+ *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
+ *readstate = PG_STATE_HEADER;
+ }
+}
+
+static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
+{
+ u8 readstate = PG_STATE_HEADER;
+
+ bool bcontinual = true;
+
+ u8 efuse_data, word_cnts = 0;
+ u16 efuse_addr = 0;
+ u8 hworden;
+ u8 tmpdata[8];
+
+ if (data == NULL)
+ return false;
+ if (offset > 15)
+ return false;
+
+ memset((void *)data, PGPKT_DATA_SIZE * sizeof(u8), 0xff);
+ memset((void *)tmpdata, PGPKT_DATA_SIZE * sizeof(u8), 0xff);
+
+ while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) {
+ if (readstate & PG_STATE_HEADER) {
+ if (efuse_one_byte_read(hw, efuse_addr, &efuse_data)
+ && (efuse_data != 0xFF))
+ efuse_read_data_case1(hw, &efuse_addr,
+ efuse_data,
+ offset, tmpdata,
+ &readstate);
+ else
+ bcontinual = false;
+ } else if (readstate & PG_STATE_DATA) {
+ efuse_word_enable_data_read(hworden, tmpdata, data);
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+ readstate = PG_STATE_HEADER;
+ }
+
+ }
+
+ if ((data[0] == 0xff) && (data[1] == 0xff) &&
+ (data[2] == 0xff) && (data[3] == 0xff) &&
+ (data[4] == 0xff) && (data[5] == 0xff) &&
+ (data[6] == 0xff) && (data[7] == 0xff))
+ return false;
+ else
+ return true;
+
+}
+
+static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
+ u8 efuse_data, u8 offset, int *bcontinual,
+ u8 *write_state, struct pgpkt_struct target_pkt,
+ int *repeat_times, int *bresult, u8 word_en)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct pgpkt_struct tmp_pkt;
+ int bdataempty = true;
+ u8 originaldata[8 * sizeof(u8)];
+ u8 badworden = 0x0F;
+ u8 match_word_en, tmp_word_en;
+ u8 tmpindex;
+ u8 tmp_header = efuse_data;
+ u8 tmp_word_cnts;
+
+ tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
+ tmp_pkt.word_en = tmp_header & 0x0F;
+ tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
+
+ if (tmp_pkt.offset != target_pkt.offset) {
+ efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+ *write_state = PG_STATE_HEADER;
+ } else {
+ for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
+ u16 address = *efuse_addr + 1 + tmpindex;
+ if (efuse_one_byte_read(hw, address,
+ &efuse_data) && (efuse_data != 0xFF))
+ bdataempty = false;
+ }
+
+ if (bdataempty == false) {
+ efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+ *write_state = PG_STATE_HEADER;
+ } else {
+ match_word_en = 0x0F;
+ if (!((target_pkt.word_en & BIT(0)) |
+ (tmp_pkt.word_en & BIT(0))))
+ match_word_en &= (~BIT(0));
+
+ if (!((target_pkt.word_en & BIT(1)) |
+ (tmp_pkt.word_en & BIT(1))))
+ match_word_en &= (~BIT(1));
+
+ if (!((target_pkt.word_en & BIT(2)) |
+ (tmp_pkt.word_en & BIT(2))))
+ match_word_en &= (~BIT(2));
+
+ if (!((target_pkt.word_en & BIT(3)) |
+ (tmp_pkt.word_en & BIT(3))))
+ match_word_en &= (~BIT(3));
+
+ if ((match_word_en & 0x0F) != 0x0F) {
+ badworden = efuse_word_enable_data_write(
+ hw, *efuse_addr + 1,
+ tmp_pkt.word_en,
+ target_pkt.data);
+
+ if (0x0F != (badworden & 0x0F)) {
+ u8 reorg_offset = offset;
+ u8 reorg_worden = badworden;
+ efuse_pg_packet_write(hw, reorg_offset,
+ reorg_worden,
+ originaldata);
+ }
+
+ tmp_word_en = 0x0F;
+ if ((target_pkt.word_en & BIT(0)) ^
+ (match_word_en & BIT(0)))
+ tmp_word_en &= (~BIT(0));
+
+ if ((target_pkt.word_en & BIT(1)) ^
+ (match_word_en & BIT(1)))
+ tmp_word_en &= (~BIT(1));
+
+ if ((target_pkt.word_en & BIT(2)) ^
+ (match_word_en & BIT(2)))
+ tmp_word_en &= (~BIT(2));
+
+ if ((target_pkt.word_en & BIT(3)) ^
+ (match_word_en & BIT(3)))
+ tmp_word_en &= (~BIT(3));
+
+ if ((tmp_word_en & 0x0F) != 0x0F) {
+ *efuse_addr = efuse_get_current_size(hw);
+ target_pkt.offset = offset;
+ target_pkt.word_en = tmp_word_en;
+ } else
+ *bcontinual = false;
+ *write_state = PG_STATE_HEADER;
+ *repeat_times += 1;
+ if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+ *bcontinual = false;
+ *bresult = false;
+ }
+ } else {
+ *efuse_addr += (2 * tmp_word_cnts) + 1;
+ target_pkt.offset = offset;
+ target_pkt.word_en = word_en;
+ *write_state = PG_STATE_HEADER;
+ }
+ }
+ }
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER-1\n"));
+}
+
+static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
+ int *bcontinual, u8 *write_state,
+ struct pgpkt_struct target_pkt,
+ int *repeat_times, int *bresult)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct pgpkt_struct tmp_pkt;
+ u8 pg_header;
+ u8 tmp_header;
+ u8 originaldata[8 * sizeof(u8)];
+ u8 tmp_word_cnts;
+ u8 badworden = 0x0F;
+
+ pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en;
+ efuse_one_byte_write(hw, *efuse_addr, pg_header);
+ efuse_one_byte_read(hw, *efuse_addr, &tmp_header);
+
+ if (tmp_header == pg_header)
+ *write_state = PG_STATE_DATA;
+ else if (tmp_header == 0xFF) {
+ *write_state = PG_STATE_HEADER;
+ *repeat_times += 1;
+ if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+ *bcontinual = false;
+ *bresult = false;
+ }
+ } else {
+ tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
+ tmp_pkt.word_en = tmp_header & 0x0F;
+
+ tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
+
+ memset((void *)originaldata, 8 * sizeof(u8), 0xff);
+
+ if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) {
+ badworden = efuse_word_enable_data_write(hw,
+ *efuse_addr + 1, tmp_pkt.word_en,
+ originaldata);
+
+ if (0x0F != (badworden & 0x0F)) {
+ u8 reorg_offset = tmp_pkt.offset;
+ u8 reorg_worden = badworden;
+ efuse_pg_packet_write(hw, reorg_offset,
+ reorg_worden,
+ originaldata);
+ *efuse_addr = efuse_get_current_size(hw);
+ } else
+ *efuse_addr = *efuse_addr + (tmp_word_cnts * 2)
+ + 1;
+ } else
+ *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+
+ *write_state = PG_STATE_HEADER;
+ *repeat_times += 1;
+ if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+ *bcontinual = false;
+ *bresult = false;
+ }
+
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+ ("efuse PG_STATE_HEADER-2\n"));
+ }
+}
+
+static int efuse_pg_packet_write(struct ieee80211_hw *hw,
+ u8 offset, u8 word_en, u8 *data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct pgpkt_struct target_pkt;
+ u8 write_state = PG_STATE_HEADER;
+ int bcontinual = true, bdataempty = true, bresult = true;
+ u16 efuse_addr = 0;
+ u8 efuse_data;
+ u8 target_word_cnts = 0;
+ u8 badworden = 0x0F;
+ static int repeat_times;
+
+ if (efuse_get_current_size(hw) >=
+ (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+ ("efuse_pg_packet_write error\n"));
+ return false;
+ }
+
+ target_pkt.offset = offset;
+ target_pkt.word_en = word_en;
+
+ memset((void *)target_pkt.data, 8 * sizeof(u8), 0xFF);
+
+ efuse_word_enable_data_read(word_en, data, target_pkt.data);
+ target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en);
+
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n"));
+
+ while (bcontinual && (efuse_addr <
+ (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
+
+ if (write_state == PG_STATE_HEADER) {
+ bdataempty = true;
+ badworden = 0x0F;
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+ ("efuse PG_STATE_HEADER\n"));
+
+ if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+ (efuse_data != 0xFF))
+ efuse_write_data_case1(hw, &efuse_addr,
+ efuse_data, offset,
+ &bcontinual,
+ &write_state, target_pkt,
+ &repeat_times, &bresult,
+ word_en);
+ else
+ efuse_write_data_case2(hw, &efuse_addr,
+ &bcontinual,
+ &write_state,
+ target_pkt,
+ &repeat_times,
+ &bresult);
+
+ } else if (write_state == PG_STATE_DATA) {
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+ ("efuse PG_STATE_DATA\n"));
+ badworden = 0x0f;
+ badworden =
+ efuse_word_enable_data_write(hw, efuse_addr + 1,
+ target_pkt.word_en,
+ target_pkt.data);
+
+ if ((badworden & 0x0F) == 0x0F) {
+ bcontinual = false;
+ } else {
+ efuse_addr =
+ efuse_addr + (2 * target_word_cnts) + 1;
+
+ target_pkt.offset = offset;
+ target_pkt.word_en = badworden;
+ target_word_cnts =
+ efuse_calculate_word_cnts(target_pkt.
+ word_en);
+ write_state = PG_STATE_HEADER;
+ repeat_times++;
+ if (repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+ bcontinual = false;
+ bresult = false;
+ }
+ RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+ ("efuse PG_STATE_HEADER-3\n"));
+ }
+ }
+ }
+
+ if (efuse_addr >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("efuse_addr(%#x) Out of size!!\n", efuse_addr));
+ }
+
+ return true;
+}
+
+static void efuse_word_enable_data_read(u8 word_en,
+ u8 *sourdata, u8 *targetdata)
+{
+ if (!(word_en & BIT(0))) {
+ targetdata[0] = sourdata[0];
+ targetdata[1] = sourdata[1];
+ }
+
+ if (!(word_en & BIT(1))) {
+ targetdata[2] = sourdata[2];
+ targetdata[3] = sourdata[3];
+ }
+
+ if (!(word_en & BIT(2))) {
+ targetdata[4] = sourdata[4];
+ targetdata[5] = sourdata[5];
+ }
+
+ if (!(word_en & BIT(3))) {
+ targetdata[6] = sourdata[6];
+ targetdata[7] = sourdata[7];
+ }
+}
+
+static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
+ u16 efuse_addr, u8 word_en, u8 *data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 tmpaddr;
+ u16 start_addr = efuse_addr;
+ u8 badworden = 0x0F;
+ u8 tmpdata[8];
+
+ memset((void *)tmpdata, PGPKT_DATA_SIZE, 0xff);
+ RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+ ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr));
+
+ if (!(word_en & BIT(0))) {
+ tmpaddr = start_addr;
+ efuse_one_byte_write(hw, start_addr++, data[0]);
+ efuse_one_byte_write(hw, start_addr++, data[1]);
+
+ efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]);
+ efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]);
+ if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+ badworden &= (~BIT(0));
+ }
+
+ if (!(word_en & BIT(1))) {
+ tmpaddr = start_addr;
+ efuse_one_byte_write(hw, start_addr++, data[2]);
+ efuse_one_byte_write(hw, start_addr++, data[3]);
+
+ efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]);
+ efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]);
+ if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+ badworden &= (~BIT(1));
+ }
+
+ if (!(word_en & BIT(2))) {
+ tmpaddr = start_addr;
+ efuse_one_byte_write(hw, start_addr++, data[4]);
+ efuse_one_byte_write(hw, start_addr++, data[5]);
+
+ efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]);
+ efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]);
+ if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+ badworden &= (~BIT(2));
+ }
+
+ if (!(word_en & BIT(3))) {
+ tmpaddr = start_addr;
+ efuse_one_byte_write(hw, start_addr++, data[6]);
+ efuse_one_byte_write(hw, start_addr++, data[7]);
+
+ efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]);
+ efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]);
+ if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+ badworden &= (~BIT(3));
+ }
+
+ return badworden;
+}
+
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tempval;
+ u16 tmpV16;
+
+ if (pwrstate == true) {
+ tmpV16 = rtl_read_word(rtlpriv,
+ rtlpriv->cfg->maps[SYS_ISO_CTRL]);
+ if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
+ tmpV16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V];
+ rtl_write_word(rtlpriv,
+ rtlpriv->cfg->maps[SYS_ISO_CTRL],
+ tmpV16);
+ }
+
+ tmpV16 = rtl_read_word(rtlpriv,
+ rtlpriv->cfg->maps[SYS_FUNC_EN]);
+ if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) {
+ tmpV16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR];
+ rtl_write_word(rtlpriv,
+ rtlpriv->cfg->maps[SYS_FUNC_EN], tmpV16);
+ }
+
+ tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]);
+ if ((!(tmpV16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) ||
+ (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) {
+ tmpV16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] |
+ rtlpriv->cfg->maps[EFUSE_ANA8M]);
+ rtl_write_word(rtlpriv,
+ rtlpriv->cfg->maps[SYS_CLK], tmpV16);
+ }
+ }
+
+ if (pwrstate == true) {
+ if (bwrite == true) {
+ tempval = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_TEST] +
+ 3);
+ tempval &= 0x0F;
+ tempval |= (VOLTAGE_V25 << 4);
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_TEST] + 3,
+ (tempval | 0x80));
+ }
+
+ } else {
+ if (bwrite == true) {
+ tempval = rtl_read_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_TEST] +
+ 3);
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_TEST] + 3,
+ (tempval & 0x7F));
+ }
+
+ }
+
+}
+
+static u16 efuse_get_current_size(struct ieee80211_hw *hw)
+{
+ int bcontinual = true;
+ u16 efuse_addr = 0;
+ u8 hoffset, hworden;
+ u8 efuse_data, word_cnts;
+
+ while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
+ && (efuse_addr < EFUSE_MAX_SIZE)) {
+ if (efuse_data != 0xFF) {
+ hoffset = (efuse_data >> 4) & 0x0F;
+ hworden = efuse_data & 0x0F;
+ word_cnts = efuse_calculate_word_cnts(hworden);
+ efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+ } else {
+ bcontinual = false;
+ }
+ }
+
+ return efuse_addr;
+}
+
+static u8 efuse_calculate_word_cnts(u8 word_en)
+{
+ u8 word_cnts = 0;
+ if (!(word_en & BIT(0)))
+ word_cnts++;
+ if (!(word_en & BIT(1)))
+ word_cnts++;
+ if (!(word_en & BIT(2)))
+ word_cnts++;
+ if (!(word_en & BIT(3)))
+ word_cnts++;
+ return word_cnts;
+}
+
+void efuse_reset_loader(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 tmp_u2b;
+
+ tmp_u2b = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN]);
+ rtl_write_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN],
+ (tmp_u2b & ~(BIT(12))));
+ udelay(10000);
+ rtl_write_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN],
+ (tmp_u2b | BIT(12)));
+ udelay(10000);
+}
+
+bool efuse_program_map(struct ieee80211_hw *hw, char *p_filename, u8 tabletype)
+{
+ return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
new file mode 100644
index 000000000000..2d39a4df181b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_EFUSE_H_
+#define __RTL_EFUSE_H_
+
+#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_MAP_LEN 128
+#define EFUSE_MAX_SECTION 16
+#define EFUSE_MAX_WORD_UNIT 4
+
+#define EFUSE_INIT_MAP 0
+#define EFUSE_MODIFY_MAP 1
+
+#define PG_STATE_HEADER 0x01
+#define PG_STATE_WORD_0 0x02
+#define PG_STATE_WORD_1 0x04
+#define PG_STATE_WORD_2 0x08
+#define PG_STATE_WORD_3 0x10
+#define PG_STATE_DATA 0x20
+
+#define PG_SWBYTE_H 0x01
+#define PG_SWBYTE_L 0x02
+
+#define _POWERON_DELAY_
+#define _PRE_EXECUTE_READ_CMD_
+
+#define EFUSE_REPEAT_THRESHOLD_ 3
+
+struct efuse_map {
+ u8 offset;
+ u8 word_start;
+ u8 byte_start;
+ u8 byte_cnts;
+};
+
+struct pgpkt_struct {
+ u8 offset;
+ u8 word_en;
+ u8 data[8];
+};
+
+enum efuse_data_item {
+ EFUSE_CHIP_ID = 0,
+ EFUSE_LDO_SETTING,
+ EFUSE_CLK_SETTING,
+ EFUSE_SDIO_SETTING,
+ EFUSE_CCCR,
+ EFUSE_SDIO_MODE,
+ EFUSE_OCR,
+ EFUSE_F0CIS,
+ EFUSE_F1CIS,
+ EFUSE_MAC_ADDR,
+ EFUSE_EEPROM_VER,
+ EFUSE_CHAN_PLAN,
+ EFUSE_TXPW_TAB
+};
+
+enum {
+ VOLTAGE_V25 = 0x03,
+ LDOE25_SHIFT = 28,
+};
+
+struct efuse_priv {
+ u8 id[2];
+ u8 ldo_setting[2];
+ u8 clk_setting[2];
+ u8 cccr;
+ u8 sdio_mode;
+ u8 ocr[3];
+ u8 cis0[17];
+ u8 cis1[48];
+ u8 mac_addr[6];
+ u8 eeprom_verno;
+ u8 channel_plan;
+ u8 tx_power_b[14];
+ u8 tx_power_g[14];
+};
+
+extern void efuse_initialize(struct ieee80211_hw *hw);
+extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
+extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
+extern void read_efuse(struct ieee80211_hw *hw, u16 _offset,
+ u16 _size_byte, u8 *pbuf);
+extern void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
+ u16 offset, u32 *value);
+extern void efuse_shadow_write(struct ieee80211_hw *hw, u8 type,
+ u16 offset, u32 value);
+extern bool efuse_shadow_update(struct ieee80211_hw *hw);
+extern bool efuse_shadow_update_chk(struct ieee80211_hw *hw);
+extern void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw);
+extern void efuse_force_write_vendor_Id(struct ieee80211_hw *hw);
+extern void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx);
+extern bool efuse_program_map(struct ieee80211_hw *hw,
+ char *p_filename, u8 tabletype);
+extern void efuse_reset_loader(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
new file mode 100644
index 000000000000..0fa36aa6701a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -0,0 +1,1945 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "core.h"
+#include "wifi.h"
+#include "pci.h"
+#include "base.h"
+#include "ps.h"
+
+static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
+ INTEL_VENDOR_ID,
+ ATI_VENDOR_ID,
+ AMD_VENDOR_ID,
+ SIS_VENDOR_ID
+};
+
+/* Update PCI dependent default settings*/
+static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+
+ ppsc->reg_rfps_level = 0;
+ ppsc->b_support_aspm = 0;
+
+ /*Update PCI ASPM setting */
+ ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm;
+ switch (rtlpci->const_pci_aspm) {
+ case 0:
+ /*No ASPM */
+ break;
+
+ case 1:
+ /*ASPM dynamically enabled/disable. */
+ ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM;
+ break;
+
+ case 2:
+ /*ASPM with Clock Req dynamically enabled/disable. */
+ ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM |
+ RT_RF_OFF_LEVL_CLK_REQ);
+ break;
+
+ case 3:
+ /*
+ * Always enable ASPM and Clock Req
+ * from initialization to halt.
+ * */
+ ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM);
+ ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM |
+ RT_RF_OFF_LEVL_CLK_REQ);
+ break;
+
+ case 4:
+ /*
+ * Always enable ASPM without Clock Req
+ * from initialization to halt.
+ * */
+ ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM |
+ RT_RF_OFF_LEVL_CLK_REQ);
+ ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM;
+ break;
+ }
+
+ ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;
+
+ /*Update Radio OFF setting */
+ switch (rtlpci->const_hwsw_rfoff_d3) {
+ case 1:
+ if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
+ ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
+ break;
+
+ case 2:
+ if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
+ ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
+ ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;
+ break;
+
+ case 3:
+ ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3;
+ break;
+ }
+
+ /*Set HW definition to determine if it supports ASPM. */
+ switch (rtlpci->const_support_pciaspm) {
+ case 0:{
+ /*Not support ASPM. */
+ bool b_support_aspm = false;
+ ppsc->b_support_aspm = b_support_aspm;
+ break;
+ }
+ case 1:{
+ /*Support ASPM. */
+ bool b_support_aspm = true;
+ bool b_support_backdoor = true;
+ ppsc->b_support_aspm = b_support_aspm;
+
+ /*if(priv->oem_id == RT_CID_TOSHIBA &&
+ !priv->ndis_adapter.amd_l1_patch)
+ b_support_backdoor = false; */
+
+ ppsc->b_support_backdoor = b_support_backdoor;
+
+ break;
+ }
+ case 2:
+ /*ASPM value set by chipset. */
+ if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
+ bool b_support_aspm = true;
+ ppsc->b_support_aspm = b_support_aspm;
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+}
+
+static bool _rtl_pci_platform_switch_device_pci_aspm(
+ struct ieee80211_hw *hw,
+ u8 value)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ bool bresult = false;
+
+ value |= 0x40;
+
+ pci_write_config_byte(rtlpci->pdev, 0x80, value);
+
+ return bresult;
+}
+
+/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
+static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 buffer;
+ bool bresult = false;
+
+ buffer = value;
+
+ pci_write_config_byte(rtlpci->pdev, 0x81, value);
+ bresult = true;
+
+ return bresult;
+}
+
+/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
+static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+ u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+ u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
+ /*Retrieve original configuration settings. */
+ u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
+ u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
+ pcibridge_linkctrlreg;
+ u16 aspmlevel = 0;
+
+ if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("PCI(Bridge) UNKNOWN.\n"));
+
+ return;
+ }
+
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
+ _rtl_pci_switch_clk_req(hw, 0x0);
+ }
+
+ if (1) {
+ /*for promising device will in L0 state after an I/O. */
+ u8 tmp_u1b;
+ pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
+ }
+
+ /*Set corresponding value. */
+ aspmlevel |= BIT(0) | BIT(1);
+ linkctrl_reg &= ~aspmlevel;
+ pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1));
+
+ _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg);
+ udelay(50);
+
+ /*4 Disable Pci Bridge ASPM */
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + (num4bytes << 2));
+ rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
+
+ udelay(50);
+
+}
+
+/*
+ *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for
+ *power saving We should follow the sequence to enable
+ *RTL8192SE first then enable Pci Bridge ASPM
+ *or the system will show bluescreen.
+ */
+static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
+ u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
+ u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
+ u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+ u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+ u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
+ u16 aspmlevel;
+ u8 u_pcibridge_aspmsetting;
+ u8 u_device_aspmsetting;
+
+ if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("PCI(Bridge) UNKNOWN.\n"));
+ return;
+ }
+
+ /*4 Enable Pci Bridge ASPM */
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + (num4bytes << 2));
+
+ u_pcibridge_aspmsetting =
+ pcipriv->ndis_adapter.pcibridge_linkctrlreg |
+ rtlpci->const_hostpci_aspm_setting;
+
+ if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
+ u_pcibridge_aspmsetting &= ~BIT(0);
+
+ rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("PlatformEnableASPM():PciBridge busnumber[%x], "
+ "DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
+ pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
+ (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
+ u_pcibridge_aspmsetting));
+
+ udelay(50);
+
+ /*Get ASPM level (with/without Clock Req) */
+ aspmlevel = rtlpci->const_devicepci_aspm_setting;
+ u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg;
+
+ /*_rtl_pci_platform_switch_device_pci_aspm(dev,*/
+ /*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */
+
+ u_device_aspmsetting |= aspmlevel;
+
+ _rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting);
+
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
+ _rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level &
+ RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
+ }
+ udelay(200);
+}
+
+static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+
+ bool status = false;
+ u8 offset_e0;
+ unsigned offset_e4;
+
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + 0xE0);
+ rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0);
+
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + 0xE0);
+ rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0);
+
+ if (offset_e0 == 0xA0) {
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + 0xE4);
+ rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4);
+ if (offset_e4 & BIT(23))
+ status = true;
+ }
+
+ return status;
+}
+
+static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
+ u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+ u8 linkctrl_reg;
+ u8 num4bBytes;
+
+ num4bBytes = (capabilityoffset + 0x10) / 4;
+
+ /*Read Link Control Register */
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+ pcicfg_addrport + (num4bBytes << 2));
+ rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
+
+ pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
+}
+
+static void rtl_pci_parse_configuration(struct pci_dev *pdev,
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+ u8 tmp;
+ int pos;
+ u8 linkctrl_reg;
+
+ /*Link Control Register */
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
+ pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Link Control Register =%x\n",
+ pcipriv->ndis_adapter.linkctrl_reg));
+
+ pci_read_config_byte(pdev, 0x98, &tmp);
+ tmp |= BIT(4);
+ pci_write_config_byte(pdev, 0x98, tmp);
+
+ tmp = 0x17;
+ pci_write_config_byte(pdev, 0x70f, tmp);
+}
+
+static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
+{
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ _rtl_pci_update_default_setting(hw);
+
+ if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) {
+ /*Always enable ASPM & Clock Req. */
+ rtl_pci_enable_aspm(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM);
+ }
+
+}
+
+static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /*
+ * ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ * */
+ rtlpci->const_pci_aspm = 3;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /*
+ * In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 0;
+
+ /*
+ * This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 1;
+
+ _rtl_pci_initialize_adapter_common(hw);
+}
+
+static void _rtl_pci_io_handler_init(struct device *dev,
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->io.dev = dev;
+
+ rtlpriv->io.write8_async = pci_write8_async;
+ rtlpriv->io.write16_async = pci_write16_async;
+ rtlpriv->io.write32_async = pci_write32_async;
+
+ rtlpriv->io.read8_sync = pci_read8_sync;
+ rtlpriv->io.read16_sync = pci_read16_sync;
+ rtlpriv->io.read32_sync = pci_read32_sync;
+
+}
+
+static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
+{
+}
+
+static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+
+ u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
+ HW_DESC_OWN);
+
+ /*
+ *beacon packet will only use the first
+ *descriptor defautly,and the own may not
+ *be cleared by the hardware
+ */
+ if (own)
+ return;
+ ring->idx = (ring->idx + 1) % ring->entries;
+
+ skb = __skb_dequeue(&ring->queue);
+ pci_unmap_single(rtlpci->pdev,
+ le32_to_cpu(rtlpriv->cfg->ops->
+ get_desc((u8 *) entry, true,
+ HW_DESC_TXBUFF_ADDR)),
+ skb->len, PCI_DMA_TODEVICE);
+
+ RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE,
+ ("new ring->idx:%d, "
+ "free: skb_queue_len:%d, free: seq:%x\n",
+ ring->idx,
+ skb_queue_len(&ring->queue),
+ *(u16 *) (skb->data + 22)));
+
+ info = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(info);
+
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ /*info->status.rates[0].count = 1; */
+
+ ieee80211_tx_status_irqsafe(hw, skb);
+
+ if ((ring->entries - skb_queue_len(&ring->queue))
+ == 2) {
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+ ("more desc left, wake"
+ "skb_queue@%d,ring->idx = %d,"
+ "skb_queue_len = 0x%d\n",
+ prio, ring->idx,
+ skb_queue_len(&ring->queue)));
+
+ ieee80211_wake_queue(hw,
+ skb_get_queue_mapping
+ (skb));
+ }
+
+ skb = NULL;
+ }
+
+ if (((rtlpriv->link_info.num_rx_inperiod +
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2)) {
+ rtl_lps_leave(hw);
+ }
+}
+
+static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE;
+
+ struct ieee80211_rx_status rx_status = { 0 };
+ unsigned int count = rtlpci->rxringcount;
+ u8 own;
+ u8 tmp_one;
+ u32 bufferaddress;
+ bool unicast = false;
+
+ struct rtl_stats stats = {
+ .signal = 0,
+ .noise = -98,
+ .rate = 0,
+ };
+
+ /*RX NORMAL PKT */
+ while (count--) {
+ /*rx descriptor */
+ struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[
+ rtlpci->rx_ring[rx_queue_idx].idx];
+ /*rx pkt */
+ struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[
+ rtlpci->rx_ring[rx_queue_idx].idx];
+
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
+ false, HW_DESC_OWN);
+
+ if (own) {
+ /*wait data to be filled by hardware */
+ return;
+ } else {
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ struct sk_buff *new_skb = NULL;
+
+ rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
+ &rx_status,
+ (u8 *) pdesc, skb);
+
+ pci_unmap_single(rtlpci->pdev,
+ *((dma_addr_t *) skb->cb),
+ rtlpci->rxbuffersize,
+ PCI_DMA_FROMDEVICE);
+
+ skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
+ false,
+ HW_DESC_RXPKT_LEN));
+ skb_reserve(skb,
+ stats.rx_drvinfo_size + stats.rx_bufshift);
+
+ /*
+ *NOTICE This can not be use for mac80211,
+ *this is done in mac80211 code,
+ *if you done here sec DHCP will fail
+ *skb_trim(skb, skb->len - 4);
+ */
+
+ hdr = (struct ieee80211_hdr *)(skb->data);
+ fc = le16_to_cpu(hdr->frame_control);
+
+ if (!stats.b_crc) {
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
+ sizeof(rx_status));
+
+ if (is_broadcast_ether_addr(hdr->addr1))
+ ;/*TODO*/
+ else {
+ if (is_multicast_ether_addr(hdr->addr1))
+ ;/*TODO*/
+ else {
+ unicast = true;
+ rtlpriv->stats.rxbytesunicast +=
+ skb->len;
+ }
+ }
+
+ rtl_is_special_data(hw, skb, false);
+
+ if (ieee80211_is_data(fc)) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_RX);
+
+ if (unicast)
+ rtlpriv->link_info.
+ num_rx_inperiod++;
+ }
+
+ if (unlikely(!rtl_action_proc(hw, skb,
+ false))) {
+ dev_kfree_skb_any(skb);
+ } else {
+ struct sk_buff *uskb = NULL;
+ u8 *pdata;
+ uskb = dev_alloc_skb(skb->len + 128);
+ memcpy(IEEE80211_SKB_RXCB(uskb),
+ &rx_status,
+ sizeof(rx_status));
+ pdata = (u8 *)skb_put(uskb, skb->len);
+ memcpy(pdata, skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+
+ ieee80211_rx_irqsafe(hw, uskb);
+ }
+ } else {
+ dev_kfree_skb_any(skb);
+ }
+
+ if (((rtlpriv->link_info.num_rx_inperiod +
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2)) {
+ rtl_lps_leave(hw);
+ }
+
+ new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+ if (unlikely(!new_skb)) {
+ RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
+ DBG_DMESG,
+ ("can't alloc skb for rx\n"));
+ goto done;
+ }
+ skb = new_skb;
+ /*skb->dev = dev; */
+
+ rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
+ rx_ring
+ [rx_queue_idx].
+ idx] = skb;
+ *((dma_addr_t *) skb->cb) =
+ pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
+ rtlpci->rxbuffersize,
+ PCI_DMA_FROMDEVICE);
+
+ }
+done:
+ bufferaddress = cpu_to_le32(*((dma_addr_t *) skb->cb));
+ tmp_one = 1;
+ rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
+ HW_DESC_RXBUFF_ADDR,
+ (u8 *)&bufferaddress);
+ rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+ (u8 *)&tmp_one);
+ rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ HW_DESC_RXPKT_LEN,
+ (u8 *)&rtlpci->rxbuffersize);
+
+ if (rtlpci->rx_ring[rx_queue_idx].idx ==
+ rtlpci->rxringcount - 1)
+ rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ HW_DESC_RXERO,
+ (u8 *)&tmp_one);
+
+ rtlpci->rx_ring[rx_queue_idx].idx =
+ (rtlpci->rx_ring[rx_queue_idx].idx + 1) %
+ rtlpci->rxringcount;
+ }
+
+}
+
+void _rtl_pci_tx_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ int prio;
+
+ for (prio = 0; prio < RTL_PCI_MAX_TX_QUEUE_COUNT; prio++) {
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+ u8 own;
+
+ /*
+ *beacon packet will only use the first
+ *descriptor defautly, and the own may not
+ *be cleared by the hardware, and
+ *beacon will free in prepare beacon
+ */
+ if (prio == BEACON_QUEUE || prio == TXCMD_QUEUE ||
+ prio == HCCA_QUEUE)
+ break;
+
+ own = (u8)rtlpriv->cfg->ops->get_desc((u8 *)entry,
+ true,
+ HW_DESC_OWN);
+
+ if (own)
+ break;
+
+ skb = __skb_dequeue(&ring->queue);
+ pci_unmap_single(rtlpci->pdev,
+ le32_to_cpu(rtlpriv->cfg->ops->
+ get_desc((u8 *) entry,
+ true,
+ HW_DESC_TXBUFF_ADDR)),
+ skb->len, PCI_DMA_TODEVICE);
+
+ ring->idx = (ring->idx + 1) % ring->entries;
+
+ info = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(info);
+
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ /*info->status.rates[0].count = 1; */
+
+ ieee80211_tx_status_irqsafe(hw, skb);
+
+ if ((ring->entries - skb_queue_len(&ring->queue))
+ == 2 && prio != BEACON_QUEUE) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("more desc left, wake "
+ "skb_queue@%d,ring->idx = %d,"
+ "skb_queue_len = 0x%d\n",
+ prio, ring->idx,
+ skb_queue_len(&ring->queue)));
+
+ ieee80211_wake_queue(hw,
+ skb_get_queue_mapping
+ (skb));
+ }
+
+ skb = NULL;
+ }
+ }
+}
+
+static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
+{
+ struct ieee80211_hw *hw = dev_id;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ unsigned long flags;
+ u32 inta = 0;
+ u32 intb = 0;
+
+ if (rtlpci->irq_enabled == 0)
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ /*read ISR: 4/8bytes */
+ rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
+
+ /*Shared IRQ or HW disappared */
+ if (!inta || inta == 0xffff)
+ goto done;
+
+ /*<1> beacon related */
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("beacon ok interrupt!\n"));
+ }
+
+ if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("beacon err interrupt!\n"));
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("beacon interrupt!\n"));
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("prepare beacon for interrupt!\n"));
+ tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
+ }
+
+ /*<3> Tx related */
+ if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("IMR_TXFOVW!\n"));
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("Manage ok interrupt!\n"));
+ _rtl_pci_tx_isr(hw, MGNT_QUEUE);
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("HIGH_QUEUE ok interrupt!\n"));
+ _rtl_pci_tx_isr(hw, HIGH_QUEUE);
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) {
+ rtlpriv->link_info.num_tx_inperiod++;
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("BK Tx OK interrupt!\n"));
+ _rtl_pci_tx_isr(hw, BK_QUEUE);
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) {
+ rtlpriv->link_info.num_tx_inperiod++;
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("BE TX OK interrupt!\n"));
+ _rtl_pci_tx_isr(hw, BE_QUEUE);
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) {
+ rtlpriv->link_info.num_tx_inperiod++;
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("VI TX OK interrupt!\n"));
+ _rtl_pci_tx_isr(hw, VI_QUEUE);
+ }
+
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) {
+ rtlpriv->link_info.num_tx_inperiod++;
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("Vo TX OK interrupt!\n"));
+ _rtl_pci_tx_isr(hw, VO_QUEUE);
+ }
+
+ /*<2> Rx related */
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n"));
+ tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ }
+
+ if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("rx descriptor unavailable!\n"));
+ tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ }
+
+ if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
+ tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ }
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+ return IRQ_HANDLED;
+
+done:
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
+{
+ _rtl_pci_rx_interrupt(hw);
+}
+
+static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+ struct ieee80211_hdr *hdr = NULL;
+ struct ieee80211_tx_info *info = NULL;
+ struct sk_buff *pskb = NULL;
+ struct rtl_tx_desc *pdesc = NULL;
+ unsigned int queue_index;
+ u8 temp_one = 1;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ /*NB: the beacon data buffer must be 32-bit aligned. */
+ pskb = ieee80211_beacon_get(hw, mac->vif);
+ if (pskb == NULL)
+ return;
+ hdr = (struct ieee80211_hdr *)(pskb->data);
+ info = IEEE80211_SKB_CB(pskb);
+
+ queue_index = BEACON_QUEUE;
+
+ pdesc = &ring->desc[0];
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+ info, pskb, queue_index);
+
+ __skb_queue_tail(&ring->queue, pskb);
+
+ rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
+ (u8 *)&temp_one);
+
+ return;
+}
+
+static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 i;
+
+ for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+ rtlpci->txringcount[i] = RT_TXDESC_NUM;
+
+ /*
+ *we just alloc 2 desc for beacon queue,
+ *because we just need first desc in hw beacon.
+ */
+ rtlpci->txringcount[BEACON_QUEUE] = 2;
+
+ /*
+ *BE queue need more descriptor for performance
+ *consideration or, No more tx desc will happen,
+ *and may cause mac80211 mem leakage.
+ */
+ rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE;
+
+ rtlpci->rxbuffersize = 9100; /*2048/1024; */
+ rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT; /*64; */
+}
+
+static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
+ struct pci_dev *pdev)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ rtlpci->up_first_time = true;
+ rtlpci->being_init_adapter = false;
+
+ rtlhal->hw = hw;
+ rtlpci->pdev = pdev;
+
+ ppsc->b_inactiveps = false;
+ ppsc->b_leisure_ps = true;
+ ppsc->b_fwctrl_lps = true;
+ ppsc->b_reg_fwctrl_lps = 3;
+ ppsc->reg_max_lps_awakeintvl = 5;
+
+ if (ppsc->b_reg_fwctrl_lps == 1)
+ ppsc->fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (ppsc->b_reg_fwctrl_lps == 2)
+ ppsc->fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (ppsc->b_reg_fwctrl_lps == 3)
+ ppsc->fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /*Tx/Rx related var */
+ _rtl_pci_init_trx_var(hw);
+
+ /*IBSS*/ mac->beacon_interval = 100;
+
+ /*AMPDU*/ mac->min_space_cfg = 0;
+ mac->max_mss_density = 0;
+ /*set sane AMPDU defaults */
+ mac->current_ampdu_density = 7;
+ mac->current_ampdu_factor = 3;
+
+ /*QOS*/ rtlpci->acm_method = eAcmWay2_SW;
+
+ /*task */
+ tasklet_init(&rtlpriv->works.irq_tasklet,
+ (void (*)(unsigned long))_rtl_pci_irq_tasklet,
+ (unsigned long)hw);
+ tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
+ (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
+ (unsigned long)hw);
+}
+
+static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
+ unsigned int prio, unsigned int entries)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_tx_desc *ring;
+ dma_addr_t dma;
+ u32 nextdescaddress;
+ int i;
+
+ ring = pci_alloc_consistent(rtlpci->pdev,
+ sizeof(*ring) * entries, &dma);
+
+ if (!ring || (unsigned long)ring & 0xFF) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Cannot allocate TX ring (prio = %d)\n", prio));
+ return -ENOMEM;
+ }
+
+ memset(ring, 0, sizeof(*ring) * entries);
+ rtlpci->tx_ring[prio].desc = ring;
+ rtlpci->tx_ring[prio].dma = dma;
+ rtlpci->tx_ring[prio].idx = 0;
+ rtlpci->tx_ring[prio].entries = entries;
+ skb_queue_head_init(&rtlpci->tx_ring[prio].queue);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("queue:%d, ring_addr:%p\n", prio, ring));
+
+ for (i = 0; i < entries; i++) {
+ nextdescaddress = cpu_to_le32((u32) dma +
+ ((i + 1) % entries) *
+ sizeof(*ring));
+
+ rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
+ true, HW_DESC_TX_NEXTDESC_ADDR,
+ (u8 *)&nextdescaddress);
+ }
+
+ return 0;
+}
+
+static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_rx_desc *entry = NULL;
+ int i, rx_queue_idx;
+ u8 tmp_one = 1;
+
+ /*
+ *rx_queue_idx 0:RX_MPDU_QUEUE
+ *rx_queue_idx 1:RX_CMD_QUEUE
+ */
+ for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
+ rx_queue_idx++) {
+ rtlpci->rx_ring[rx_queue_idx].desc =
+ pci_alloc_consistent(rtlpci->pdev,
+ sizeof(*rtlpci->rx_ring[rx_queue_idx].
+ desc) * rtlpci->rxringcount,
+ &rtlpci->rx_ring[rx_queue_idx].dma);
+
+ if (!rtlpci->rx_ring[rx_queue_idx].desc ||
+ (unsigned long)rtlpci->rx_ring[rx_queue_idx].desc & 0xFF) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Cannot allocate RX ring\n"));
+ return -ENOMEM;
+ }
+
+ memset(rtlpci->rx_ring[rx_queue_idx].desc, 0,
+ sizeof(*rtlpci->rx_ring[rx_queue_idx].desc) *
+ rtlpci->rxringcount);
+
+ rtlpci->rx_ring[rx_queue_idx].idx = 0;
+
+ for (i = 0; i < rtlpci->rxringcount; i++) {
+ struct sk_buff *skb =
+ dev_alloc_skb(rtlpci->rxbuffersize);
+ u32 bufferaddress;
+ entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
+ if (!skb)
+ return 0;
+
+ /*skb->dev = dev; */
+
+ rtlpci->rx_ring[rx_queue_idx].rx_buf[i] = skb;
+
+ /*
+ *just set skb->cb to mapping addr
+ *for pci_unmap_single use
+ */
+ *((dma_addr_t *) skb->cb) =
+ pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
+ rtlpci->rxbuffersize,
+ PCI_DMA_FROMDEVICE);
+
+ bufferaddress = cpu_to_le32(*((dma_addr_t *)skb->cb));
+ rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ HW_DESC_RXBUFF_ADDR,
+ (u8 *)&bufferaddress);
+ rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ HW_DESC_RXPKT_LEN,
+ (u8 *)&rtlpci->
+ rxbuffersize);
+ rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+ HW_DESC_RXOWN,
+ (u8 *)&tmp_one);
+ }
+
+ rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+ HW_DESC_RXERO, (u8 *)&tmp_one);
+ }
+ return 0;
+}
+
+static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
+ unsigned int prio)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+ pci_unmap_single(rtlpci->pdev,
+ le32_to_cpu(rtlpriv->cfg->
+ ops->get_desc((u8 *) entry, true,
+ HW_DESC_TXBUFF_ADDR)),
+ skb->len, PCI_DMA_TODEVICE);
+ kfree_skb(skb);
+ ring->idx = (ring->idx + 1) % ring->entries;
+ }
+
+ pci_free_consistent(rtlpci->pdev,
+ sizeof(*ring->desc) * ring->entries,
+ ring->desc, ring->dma);
+ ring->desc = NULL;
+}
+
+static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci)
+{
+ int i, rx_queue_idx;
+
+ /*rx_queue_idx 0:RX_MPDU_QUEUE */
+ /*rx_queue_idx 1:RX_CMD_QUEUE */
+ for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
+ rx_queue_idx++) {
+ for (i = 0; i < rtlpci->rxringcount; i++) {
+ struct sk_buff *skb =
+ rtlpci->rx_ring[rx_queue_idx].rx_buf[i];
+ if (!skb)
+ continue;
+
+ pci_unmap_single(rtlpci->pdev,
+ *((dma_addr_t *) skb->cb),
+ rtlpci->rxbuffersize,
+ PCI_DMA_FROMDEVICE);
+ kfree_skb(skb);
+ }
+
+ pci_free_consistent(rtlpci->pdev,
+ sizeof(*rtlpci->rx_ring[rx_queue_idx].
+ desc) * rtlpci->rxringcount,
+ rtlpci->rx_ring[rx_queue_idx].desc,
+ rtlpci->rx_ring[rx_queue_idx].dma);
+ rtlpci->rx_ring[rx_queue_idx].desc = NULL;
+ }
+}
+
+static int _rtl_pci_init_trx_ring(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ int ret;
+ int i;
+
+ ret = _rtl_pci_init_rx_ring(hw);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
+ ret = _rtl_pci_init_tx_ring(hw, i,
+ rtlpci->txringcount[i]);
+ if (ret)
+ goto err_free_rings;
+ }
+
+ return 0;
+
+err_free_rings:
+ _rtl_pci_free_rx_ring(rtlpci);
+
+ for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+ if (rtlpci->tx_ring[i].desc)
+ _rtl_pci_free_tx_ring(hw, i);
+
+ return 1;
+}
+
+static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 i;
+
+ /*free rx rings */
+ _rtl_pci_free_rx_ring(rtlpci);
+
+ /*free tx rings */
+ for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+ _rtl_pci_free_tx_ring(hw, i);
+
+ return 0;
+}
+
+int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ int i, rx_queue_idx;
+ unsigned long flags;
+ u8 tmp_one = 1;
+
+ /*rx_queue_idx 0:RX_MPDU_QUEUE */
+ /*rx_queue_idx 1:RX_CMD_QUEUE */
+ for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
+ rx_queue_idx++) {
+ /*
+ *force the rx_ring[RX_MPDU_QUEUE/
+ *RX_CMD_QUEUE].idx to the first one
+ */
+ if (rtlpci->rx_ring[rx_queue_idx].desc) {
+ struct rtl_rx_desc *entry = NULL;
+
+ for (i = 0; i < rtlpci->rxringcount; i++) {
+ entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
+ rtlpriv->cfg->ops->set_desc((u8 *) entry,
+ false,
+ HW_DESC_RXOWN,
+ (u8 *)&tmp_one);
+ }
+ rtlpci->rx_ring[rx_queue_idx].idx = 0;
+ }
+ }
+
+ /*
+ *after reset, release previous pending packet,
+ *and force the tx idx to the first one
+ */
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+ for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
+ if (rtlpci->tx_ring[i].desc) {
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry =
+ &ring->desc[ring->idx];
+ struct sk_buff *skb =
+ __skb_dequeue(&ring->queue);
+
+ pci_unmap_single(rtlpci->pdev,
+ le32_to_cpu(rtlpriv->cfg->ops->
+ get_desc((u8 *)
+ entry,
+ true,
+ HW_DESC_TXBUFF_ADDR)),
+ skb->len, PCI_DMA_TODEVICE);
+ kfree_skb(skb);
+ ring->idx = (ring->idx + 1) % ring->entries;
+ }
+ ring->idx = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ return 0;
+}
+
+unsigned int _rtl_mac_to_hwqueue(u16 fc,
+ unsigned int mac80211_queue_index)
+{
+ unsigned int hw_queue_index;
+
+ if (unlikely(ieee80211_is_beacon(fc))) {
+ hw_queue_index = BEACON_QUEUE;
+ goto out;
+ }
+
+ if (ieee80211_is_mgmt(fc)) {
+ hw_queue_index = MGNT_QUEUE;
+ goto out;
+ }
+
+ switch (mac80211_queue_index) {
+ case 0:
+ hw_queue_index = VO_QUEUE;
+ break;
+ case 1:
+ hw_queue_index = VI_QUEUE;
+ break;
+ case 2:
+ hw_queue_index = BE_QUEUE;;
+ break;
+ case 3:
+ hw_queue_index = BK_QUEUE;
+ break;
+ default:
+ hw_queue_index = BE_QUEUE;
+ RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n",
+ mac80211_queue_index));
+ break;
+ }
+
+out:
+ return hw_queue_index;
+}
+
+int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ u8 idx;
+ unsigned int queue_index, hw_queue;
+ unsigned long flags;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u8 *pda_addr = hdr->addr1;
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ /*ssn */
+ u8 *qc = NULL;
+ u8 tid = 0;
+ u16 seq_number = 0;
+ u8 own;
+ u8 temp_one = 1;
+
+ if (ieee80211_is_mgmt(fc))
+ rtl_tx_mgmt_proc(hw, skb);
+ rtl_action_proc(hw, skb, true);
+
+ queue_index = skb_get_queue_mapping(skb);
+ hw_queue = _rtl_mac_to_hwqueue(fc, queue_index);
+
+ if (is_multicast_ether_addr(pda_addr))
+ rtlpriv->stats.txbytesmulticast += skb->len;
+ else if (is_broadcast_ether_addr(pda_addr))
+ rtlpriv->stats.txbytesbroadcast += skb->len;
+ else
+ rtlpriv->stats.txbytesunicast += skb->len;
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ ring = &rtlpci->tx_ring[hw_queue];
+ if (hw_queue != BEACON_QUEUE)
+ idx = (ring->idx + skb_queue_len(&ring->queue)) %
+ ring->entries;
+ else
+ idx = 0;
+
+ pdesc = &ring->desc[idx];
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
+ true, HW_DESC_OWN);
+
+ if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("No more TX desc@%d, ring->idx = %d,"
+ "idx = %d, skb_queue_len = 0x%d\n",
+ hw_queue, ring->idx, idx,
+ skb_queue_len(&ring->queue)));
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+ return skb->len;
+ }
+
+ /*
+ *if(ieee80211_is_nullfunc(fc)) {
+ * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+ * return 1;
+ *}
+ */
+
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+
+ seq_number = mac->tids[tid].seq_number;
+ seq_number &= IEEE80211_SCTL_SEQ;
+ /*
+ *hdr->seq_ctrl = hdr->seq_ctrl &
+ *cpu_to_le16(IEEE80211_SCTL_FRAG);
+ *hdr->seq_ctrl |= cpu_to_le16(seq_number);
+ */
+
+ seq_number += 1;
+ }
+
+ if (ieee80211_is_data(fc))
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
+
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+ info, skb, hw_queue);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true,
+ HW_DESC_OWN, (u8 *)&temp_one);
+
+ if (!ieee80211_has_morefrags(hdr->frame_control)) {
+ if (qc)
+ mac->tids[tid].seq_number = seq_number;
+ }
+
+ if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
+ hw_queue != BEACON_QUEUE) {
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+ ("less desc left, stop skb_queue@%d, "
+ "ring->idx = %d,"
+ "idx = %d, skb_queue_len = 0x%d\n",
+ hw_queue, ring->idx, idx,
+ skb_queue_len(&ring->queue)));
+
+ ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
+ }
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, hw_queue);
+
+ return 0;
+}
+
+void rtl_pci_deinit(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ _rtl_pci_deinit_trx_ring(hw);
+
+ synchronize_irq(rtlpci->pdev->irq);
+ tasklet_kill(&rtlpriv->works.irq_tasklet);
+
+ flush_workqueue(rtlpriv->works.rtl_wq);
+ destroy_workqueue(rtlpriv->works.rtl_wq);
+
+}
+
+int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int err;
+
+ _rtl_pci_init_struct(hw, pdev);
+
+ err = _rtl_pci_init_trx_ring(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("tx ring initialization failed"));
+ return err;
+ }
+
+ return 1;
+}
+
+int rtl_pci_start(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ int err;
+
+ rtl_pci_reset_trx_ring(hw);
+
+ rtlpci->driver_is_goingto_unload = false;
+ err = rtlpriv->cfg->ops->hw_init(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("Failed to config hardware!\n"));
+ return err;
+ }
+
+ rtlpriv->cfg->ops->enable_interrupt(hw);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n"));
+
+ rtl_init_rx_config(hw);
+
+ /*should after adapter start and interrupt enable. */
+ set_hal_start(rtlhal);
+
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+ rtlpci->up_first_time = false;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n"));
+ return 0;
+}
+
+void rtl_pci_stop(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ unsigned long flags;
+ u8 RFInProgressTimeOut = 0;
+
+ /*
+ *should before disable interrrupt&adapter
+ *and will do it immediately.
+ */
+ set_hal_stop(rtlhal);
+
+ rtlpriv->cfg->ops->disable_interrupt(hw);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
+ while (ppsc->rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
+ if (RFInProgressTimeOut > 100) {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
+ break;
+ }
+ mdelay(1);
+ RFInProgressTimeOut++;
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
+ }
+ ppsc->rfchange_inprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
+
+ rtlpci->driver_is_goingto_unload = true;
+ rtlpriv->cfg->ops->hw_disable(hw);
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
+
+ rtl_pci_enable_aspm(hw);
+}
+
+static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct pci_dev *bridge_pdev = pdev->bus->self;
+ u16 venderid;
+ u16 deviceid;
+ u8 revisionid;
+ u16 irqline;
+ u8 tmp;
+
+ venderid = pdev->vendor;
+ deviceid = pdev->device;
+ pci_read_config_byte(pdev, 0x8, &revisionid);
+ pci_read_config_word(pdev, 0x3C, &irqline);
+
+ if (deviceid == RTL_PCI_8192_DID ||
+ deviceid == RTL_PCI_0044_DID ||
+ deviceid == RTL_PCI_0047_DID ||
+ deviceid == RTL_PCI_8192SE_DID ||
+ deviceid == RTL_PCI_8174_DID ||
+ deviceid == RTL_PCI_8173_DID ||
+ deviceid == RTL_PCI_8172_DID ||
+ deviceid == RTL_PCI_8171_DID) {
+ switch (revisionid) {
+ case RTL_PCI_REVISION_ID_8192PCIE:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("8192 PCI-E is found - "
+ "vid/did=%x/%x\n", venderid, deviceid));
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8192E;
+ break;
+ case RTL_PCI_REVISION_ID_8192SE:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("8192SE is found - "
+ "vid/did=%x/%x\n", venderid, deviceid));
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Err: Unknown device - "
+ "vid/did=%x/%x\n", venderid, deviceid));
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
+ break;
+
+ }
+ } else if (deviceid == RTL_PCI_8192CET_DID ||
+ deviceid == RTL_PCI_8192CE_DID ||
+ deviceid == RTL_PCI_8191CE_DID ||
+ deviceid == RTL_PCI_8188CE_DID) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("8192C PCI-E is found - "
+ "vid/did=%x/%x\n", venderid, deviceid));
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Err: Unknown device -"
+ " vid/did=%x/%x\n", venderid, deviceid));
+
+ rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
+ }
+
+ /*find bus info */
+ pcipriv->ndis_adapter.busnumber = pdev->bus->number;
+ pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
+ pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
+
+ /*find bridge info */
+ pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
+ for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
+ if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
+ pcipriv->ndis_adapter.pcibridge_vendor = tmp;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("Pci Bridge Vendor is found index: %d\n",
+ tmp));
+ break;
+ }
+ }
+
+ if (pcipriv->ndis_adapter.pcibridge_vendor !=
+ PCI_BRIDGE_VENDOR_UNKNOWN) {
+ pcipriv->ndis_adapter.pcibridge_busnum =
+ bridge_pdev->bus->number;
+ pcipriv->ndis_adapter.pcibridge_devnum =
+ PCI_SLOT(bridge_pdev->devfn);
+ pcipriv->ndis_adapter.pcibridge_funcnum =
+ PCI_FUNC(bridge_pdev->devfn);
+ pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
+ pci_pcie_cap(bridge_pdev);
+ pcipriv->ndis_adapter.pcicfg_addrport =
+ (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
+ (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
+ (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
+ pcipriv->ndis_adapter.num4bytes =
+ (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
+
+ rtl_pci_get_linkcontrol_field(hw);
+
+ if (pcipriv->ndis_adapter.pcibridge_vendor ==
+ PCI_BRIDGE_VENDOR_AMD) {
+ pcipriv->ndis_adapter.amd_l1_patch =
+ rtl_pci_get_amd_l1_patch(hw);
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("pcidev busnumber:devnumber:funcnumber:"
+ "vendor:link_ctl %d:%d:%d:%x:%x\n",
+ pcipriv->ndis_adapter.busnumber,
+ pcipriv->ndis_adapter.devnumber,
+ pcipriv->ndis_adapter.funcnumber,
+ pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("pci_bridge busnumber:devnumber:funcnumber:vendor:"
+ "pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n",
+ pcipriv->ndis_adapter.pcibridge_busnum,
+ pcipriv->ndis_adapter.pcibridge_devnum,
+ pcipriv->ndis_adapter.pcibridge_funcnum,
+ pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor],
+ pcipriv->ndis_adapter.pcibridge_pciehdr_offset,
+ pcipriv->ndis_adapter.pcibridge_linkctrlreg,
+ pcipriv->ndis_adapter.amd_l1_patch));
+
+ rtl_pci_parse_configuration(pdev, hw);
+
+ return true;
+}
+
+int __devinit rtl_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct ieee80211_hw *hw = NULL;
+
+ struct rtl_priv *rtlpriv = NULL;
+ struct rtl_pci_priv *pcipriv = NULL;
+ struct rtl_pci *rtlpci;
+ unsigned long pmem_start, pmem_len, pmem_flags;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ RT_ASSERT(false,
+ ("%s : Cannot enable new PCI device\n",
+ pci_name(pdev)));
+ return err;
+ }
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ RT_ASSERT(false, ("Unable to obtain 32bit DMA "
+ "for consistent allocations\n"));
+ pci_disable_device(pdev);
+ return -ENOMEM;
+ }
+ }
+
+ pci_set_master(pdev);
+
+ hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) +
+ sizeof(struct rtl_priv), &rtl_ops);
+ if (!hw) {
+ RT_ASSERT(false,
+ ("%s : ieee80211 alloc failed\n", pci_name(pdev)));
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ pci_set_drvdata(pdev, hw);
+
+ rtlpriv = hw->priv;
+ pcipriv = (void *)rtlpriv->priv;
+ pcipriv->dev.pdev = pdev;
+
+ /*
+ *init dbgp flags before all
+ *other functions, because we will
+ *use it in other funtions like
+ *RT_TRACE/RT_PRINT/RTL_PRINT_DATA
+ *you can not use these macro
+ *before this
+ */
+ rtl_dbgp_flag_init(hw);
+
+ /* MEM map */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ RT_ASSERT(false, ("Can't obtain PCI resources\n"));
+ return err;
+ }
+
+ pmem_start = pci_resource_start(pdev, 2);
+ pmem_len = pci_resource_len(pdev, 2);
+ pmem_flags = pci_resource_flags(pdev, 2);
+
+ /*shared mem start */
+ rtlpriv->io.pci_mem_start =
+ (unsigned long)pci_iomap(pdev, 2, pmem_len);
+ if (rtlpriv->io.pci_mem_start == 0) {
+ RT_ASSERT(false, ("Can't map PCI mem\n"));
+ goto fail2;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("mem mapped space: start: 0x%08lx len:%08lx "
+ "flags:%08lx, after map:0x%08lx\n",
+ pmem_start, pmem_len, pmem_flags,
+ rtlpriv->io.pci_mem_start));
+
+ /* Disable Clk Request */
+ pci_write_config_byte(pdev, 0x81, 0);
+ /* leave D3 mode */
+ pci_write_config_byte(pdev, 0x44, 0);
+ pci_write_config_byte(pdev, 0x04, 0x06);
+ pci_write_config_byte(pdev, 0x04, 0x07);
+
+ /* init cfg & intf_ops */
+ rtlpriv->rtlhal.interface = INTF_PCI;
+ rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
+ rtlpriv->intf_ops = &rtl_pci_ops;
+
+ /* find adapter */
+ _rtl_pci_find_adapter(pdev, hw);
+
+ /* Init IO handler */
+ _rtl_pci_io_handler_init(&pdev->dev, hw);
+
+ /*like read eeprom and so on */
+ rtlpriv->cfg->ops->read_eeprom_info(hw);
+
+ if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't init_sw_vars.\n"));
+ goto fail3;
+ }
+
+ rtlpriv->cfg->ops->init_sw_leds(hw);
+
+ /*aspm */
+ rtl_pci_init_aspm(hw);
+
+ /* Init mac80211 sw */
+ err = rtl_init_core(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't allocate sw for mac80211.\n"));
+ goto fail3;
+ }
+
+ /* Init PCI sw */
+ err = !rtl_pci_init(hw, pdev);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to init PCI.\n"));
+ goto fail3;
+ }
+
+ err = ieee80211_register_hw(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't register mac80211 hw.\n"));
+ goto fail3;
+ } else {
+ rtlpriv->mac80211.mac80211_registered = 1;
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("failed to create sysfs device attributes\n"));
+ goto fail3;
+ }
+
+ /*init rfkill */
+ rtl_init_rfkill(hw);
+
+ rtlpci = rtl_pcidev(pcipriv);
+ err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("%s: failed to register IRQ handler\n",
+ wiphy_name(hw->wiphy)));
+ goto fail3;
+ } else {
+ rtlpci->irq_alloc = 1;
+ }
+
+ set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+ return 0;
+
+fail3:
+ pci_set_drvdata(pdev, NULL);
+ rtl_deinit_core(hw);
+ _rtl_pci_io_handler_release(hw);
+ ieee80211_free_hw(hw);
+
+ if (rtlpriv->io.pci_mem_start != 0)
+ pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start);
+
+fail2:
+ pci_release_regions(pdev);
+
+fail1:
+
+ pci_disable_device(pdev);
+
+ return -ENODEV;
+
+}
+EXPORT_SYMBOL(rtl_pci_probe);
+
+void rtl_pci_disconnect(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+ struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
+
+ clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+
+ sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
+
+ /*ieee80211_unregister_hw will call ops_stop */
+ if (rtlmac->mac80211_registered == 1) {
+ ieee80211_unregister_hw(hw);
+ rtlmac->mac80211_registered = 0;
+ } else {
+ rtl_deinit_deferred_work(hw);
+ rtlpriv->intf_ops->adapter_stop(hw);
+ }
+
+ /*deinit rfkill */
+ rtl_deinit_rfkill(hw);
+
+ rtl_pci_deinit(hw);
+ rtl_deinit_core(hw);
+ rtlpriv->cfg->ops->deinit_sw_leds(hw);
+ _rtl_pci_io_handler_release(hw);
+ rtlpriv->cfg->ops->deinit_sw_vars(hw);
+
+ if (rtlpci->irq_alloc) {
+ free_irq(rtlpci->pdev->irq, hw);
+ rtlpci->irq_alloc = 0;
+ }
+
+ if (rtlpriv->io.pci_mem_start != 0) {
+ pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start);
+ pci_release_regions(pdev);
+ }
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ ieee80211_free_hw(hw);
+}
+EXPORT_SYMBOL(rtl_pci_disconnect);
+
+/***************************************
+kernel pci power state define:
+PCI_D0 ((pci_power_t __force) 0)
+PCI_D1 ((pci_power_t __force) 1)
+PCI_D2 ((pci_power_t __force) 2)
+PCI_D3hot ((pci_power_t __force) 3)
+PCI_D3cold ((pci_power_t __force) 4)
+PCI_UNKNOWN ((pci_power_t __force) 5)
+
+This function is called when system
+goes into suspend state mac80211 will
+call rtl_mac_stop() from the mac80211
+suspend function first, So there is
+no need to call hw_disable here.
+****************************************/
+int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+EXPORT_SYMBOL(rtl_pci_suspend);
+
+int rtl_pci_resume(struct pci_dev *pdev)
+{
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ RT_ASSERT(false, ("ERR: <======\n"));
+ return ret;
+ }
+
+ pci_restore_state(pdev);
+
+ return 0;
+}
+EXPORT_SYMBOL(rtl_pci_resume);
+
+struct rtl_intf_ops rtl_pci_ops = {
+ .adapter_start = rtl_pci_start,
+ .adapter_stop = rtl_pci_stop,
+ .adapter_tx = rtl_pci_tx,
+ .reset_trx_ring = rtl_pci_reset_trx_ring,
+
+ .disable_aspm = rtl_pci_disable_aspm,
+ .enable_aspm = rtl_pci_enable_aspm,
+};
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
new file mode 100644
index 000000000000..d36a66939958
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -0,0 +1,302 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_PCI_H__
+#define __RTL_PCI_H__
+
+#include <linux/pci.h>
+/*
+1: MSDU packet queue,
+2: Rx Command Queue
+*/
+#define RTL_PCI_RX_MPDU_QUEUE 0
+#define RTL_PCI_RX_CMD_QUEUE 1
+#define RTL_PCI_MAX_RX_QUEUE 2
+
+#define RTL_PCI_MAX_RX_COUNT 64
+#define RTL_PCI_MAX_TX_QUEUE_COUNT 9
+
+#define RT_TXDESC_NUM 128
+#define RT_TXDESC_NUM_BE_QUEUE 256
+
+#define BK_QUEUE 0
+#define BE_QUEUE 1
+#define VI_QUEUE 2
+#define VO_QUEUE 3
+#define BEACON_QUEUE 4
+#define TXCMD_QUEUE 5
+#define MGNT_QUEUE 6
+#define HIGH_QUEUE 7
+#define HCCA_QUEUE 8
+
+#define RTL_PCI_DEVICE(vend, dev, cfg) \
+ .vendor = (vend), \
+ .device = (dev), \
+ .subvendor = PCI_ANY_ID, \
+ .subdevice = PCI_ANY_ID,\
+ .driver_data = (kernel_ulong_t)&(cfg)
+
+#define INTEL_VENDOR_ID 0x8086
+#define SIS_VENDOR_ID 0x1039
+#define ATI_VENDOR_ID 0x1002
+#define ATI_DEVICE_ID 0x7914
+#define AMD_VENDOR_ID 0x1022
+
+#define PCI_MAX_BRIDGE_NUMBER 255
+#define PCI_MAX_DEVICES 32
+#define PCI_MAX_FUNCTION 8
+
+#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */
+#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */
+
+#define PCI_CLASS_BRIDGE_DEV 0x06
+#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04
+#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10
+#define PCI_CAP_ID_EXP 0x10
+
+#define U1DONTCARE 0xFF
+#define U2DONTCARE 0xFFFF
+#define U4DONTCARE 0xFFFFFFFF
+
+#define RTL_PCI_8192_DID 0x8192 /*8192 PCI-E */
+#define RTL_PCI_8192SE_DID 0x8192 /*8192 SE */
+#define RTL_PCI_8174_DID 0x8174 /*8192 SE */
+#define RTL_PCI_8173_DID 0x8173 /*8191 SE Crab */
+#define RTL_PCI_8172_DID 0x8172 /*8191 SE RE */
+#define RTL_PCI_8171_DID 0x8171 /*8191 SE Unicron */
+#define RTL_PCI_0045_DID 0x0045 /*8190 PCI for Ceraga */
+#define RTL_PCI_0046_DID 0x0046 /*8190 Cardbus for Ceraga */
+#define RTL_PCI_0044_DID 0x0044 /*8192e PCIE for Ceraga */
+#define RTL_PCI_0047_DID 0x0047 /*8192e Express Card for Ceraga */
+#define RTL_PCI_700F_DID 0x700F
+#define RTL_PCI_701F_DID 0x701F
+#define RTL_PCI_DLINK_DID 0x3304
+#define RTL_PCI_8192CET_DID 0x8191 /*8192ce */
+#define RTL_PCI_8192CE_DID 0x8178 /*8192ce */
+#define RTL_PCI_8191CE_DID 0x8177 /*8192ce */
+#define RTL_PCI_8188CE_DID 0x8176 /*8192ce */
+#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */
+#define RTL_PCI_8192DE_DID 0x092D /*8192ce */
+#define RTL_PCI_8192DU_DID 0x092D /*8192ce */
+
+/*8192 support 16 pages of IO registers*/
+#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000
+#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE 0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192SE 0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192CE 0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192DE 0x4000
+
+#define RTL_PCI_REVISION_ID_8190PCI 0x00
+#define RTL_PCI_REVISION_ID_8192PCIE 0x01
+#define RTL_PCI_REVISION_ID_8192SE 0x10
+#define RTL_PCI_REVISION_ID_8192CE 0x1
+#define RTL_PCI_REVISION_ID_8192DE 0x0
+
+#define RTL_DEFAULT_HARDWARE_TYPE HARDWARE_TYPE_RTL8192CE
+
+enum pci_bridge_vendor {
+ PCI_BRIDGE_VENDOR_INTEL = 0x0, /*0b'0000,0001 */
+ PCI_BRIDGE_VENDOR_ATI, /*0b'0000,0010*/
+ PCI_BRIDGE_VENDOR_AMD, /*0b'0000,0100*/
+ PCI_BRIDGE_VENDOR_SIS, /*0b'0000,1000*/
+ PCI_BRIDGE_VENDOR_UNKNOWN, /*0b'0100,0000*/
+ PCI_BRIDGE_VENDOR_MAX,
+};
+
+struct rtl_rx_desc {
+ u32 dword[8];
+} __packed;
+
+struct rtl_tx_desc {
+ u32 dword[16];
+} __packed;
+
+struct rtl_tx_cmd_desc {
+ u32 dword[16];
+} __packed;
+
+struct rtl8192_tx_ring {
+ struct rtl_tx_desc *desc;
+ dma_addr_t dma;
+ unsigned int idx;
+ unsigned int entries;
+ struct sk_buff_head queue;
+};
+
+struct rtl8192_rx_ring {
+ struct rtl_rx_desc *desc;
+ dma_addr_t dma;
+ unsigned int idx;
+ struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT];
+};
+
+struct rtl_pci {
+ struct pci_dev *pdev;
+
+ bool driver_is_goingto_unload;
+ bool up_first_time;
+ bool being_init_adapter;
+ bool irq_enabled;
+
+ /*Tx */
+ struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT];
+ int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT];
+ u32 transmit_config;
+
+ /*Rx */
+ struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE];
+ int rxringcount;
+ u16 rxbuffersize;
+ u32 receive_config;
+
+ /*irq */
+ u8 irq_alloc;
+ u32 irq_mask[2];
+
+ /*Bcn control register setting */
+ u32 reg_bcn_ctrl_val;
+
+ /*ASPM*/ u8 const_pci_aspm;
+ u8 const_amdpci_aspm;
+ u8 const_hwsw_rfoff_d3;
+ u8 const_support_pciaspm;
+ /*pci-e bridge */
+ u8 const_hostpci_aspm_setting;
+ /*pci-e device */
+ u8 const_devicepci_aspm_setting;
+ /*If it supports ASPM, Offset[560h] = 0x40,
+ otherwise Offset[560h] = 0x00. */
+ bool b_support_aspm;
+ bool b_support_backdoor;
+
+ /*QOS & EDCA */
+ enum acm_method acm_method;
+};
+
+struct mp_adapter {
+ u8 linkctrl_reg;
+
+ u8 busnumber;
+ u8 devnumber;
+ u8 funcnumber;
+
+ u8 pcibridge_busnum;
+ u8 pcibridge_devnum;
+ u8 pcibridge_funcnum;
+
+ u8 pcibridge_vendor;
+ u16 pcibridge_vendorid;
+ u16 pcibridge_deviceid;
+
+ u32 pcicfg_addrport;
+ u8 num4bytes;
+
+ u8 pcibridge_pciehdr_offset;
+ u8 pcibridge_linkctrlreg;
+
+ bool amd_l1_patch;
+};
+
+struct rtl_pci_priv {
+ struct rtl_pci dev;
+ struct mp_adapter ndis_adapter;
+ struct rtl_led_ctl ledctl;
+};
+
+#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
+#define rtl_pcidev(pcipriv) (&((pcipriv)->dev))
+
+int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw);
+
+extern struct rtl_intf_ops rtl_pci_ops;
+
+int __devinit rtl_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+void rtl_pci_disconnect(struct pci_dev *pdev);
+int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+int rtl_pci_resume(struct pci_dev *pdev);
+
+static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return 0xff & readb((u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return readw((u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return readl((u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val)
+{
+ writeb(val, (u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write16_async(struct rtl_priv *rtlpriv,
+ u32 addr, u16 val)
+{
+ writew(val, (u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write32_async(struct rtl_priv *rtlpriv,
+ u32 addr, u32 val)
+{
+ writel(val, (u8 *) rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val)
+{
+ outl(val, port);
+}
+
+static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val)
+{
+ outb(val, port);
+}
+
+static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval)
+{
+ *pval = inb(port);
+}
+
+static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval)
+{
+ *pval = inw(port);
+}
+
+static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval)
+{
+ *pval = inl(port);
+}
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
new file mode 100644
index 000000000000..d2326c13449e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -0,0 +1,493 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "base.h"
+#include "ps.h"
+
+bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool init_status = true;
+
+ /*<1> reset trx ring */
+ if (rtlhal->interface == INTF_PCI)
+ rtlpriv->intf_ops->reset_trx_ring(hw);
+
+ if (is_hal_stop(rtlhal))
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Driver is already down!\n"));
+
+ /*<2> Enable Adapter */
+ rtlpriv->cfg->ops->hw_init(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ /*init_status = false; */
+
+ /*<3> Enable Interrupt */
+ rtlpriv->cfg->ops->enable_interrupt(hw);
+
+ /*<enable timer> */
+ rtl_watch_dog_timer_callback((unsigned long)hw);
+
+ return init_status;
+}
+EXPORT_SYMBOL(rtl_ps_enable_nic);
+
+bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
+{
+ bool status = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /*<1> Stop all timer */
+ rtl_deinit_deferred_work(hw);
+
+ /*<2> Disable Interrupt */
+ rtlpriv->cfg->ops->disable_interrupt(hw);
+
+ /*<3> Disable Adapter */
+ rtlpriv->cfg->ops->hw_disable(hw);
+
+ return status;
+}
+EXPORT_SYMBOL(rtl_ps_disable_nic);
+
+bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate state_toset,
+ u32 changesource, bool protect_or_not)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum rf_pwrstate rtstate;
+ bool b_actionallowed = false;
+ u16 rfwait_cnt = 0;
+ unsigned long flag;
+
+ /*protect_or_not = true; */
+
+ if (protect_or_not)
+ goto no_protect;
+
+ /*
+ *Only one thread can change
+ *the RF state at one time, and others
+ *should wait to be executed.
+ */
+ while (true) {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
+ flag);
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("RF Change in progress!"
+ "Wait to set..state_toset(%d).\n",
+ state_toset));
+
+ /* Set RF after the previous action is done. */
+ while (ppsc->rfchange_inprogress) {
+ rfwait_cnt++;
+ mdelay(1);
+
+ /*
+ *Wait too long, return false to avoid
+ *to be stuck here.
+ */
+ if (rfwait_cnt > 100)
+ return false;
+ }
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
+ flag);
+ break;
+ }
+ }
+
+no_protect:
+ rtstate = ppsc->rfpwr_state;
+
+ switch (state_toset) {
+ case ERFON:
+ ppsc->rfoff_reason &= (~changesource);
+
+ if ((changesource == RF_CHANGE_BY_HW) &&
+ (ppsc->b_hwradiooff == true)) {
+ ppsc->b_hwradiooff = false;
+ }
+
+ if (!ppsc->rfoff_reason) {
+ ppsc->rfoff_reason = 0;
+ b_actionallowed = true;
+ }
+
+ break;
+
+ case ERFOFF:
+
+ if ((changesource == RF_CHANGE_BY_HW)
+ && (ppsc->b_hwradiooff == false)) {
+ ppsc->b_hwradiooff = true;
+ }
+
+ ppsc->rfoff_reason |= changesource;
+ b_actionallowed = true;
+ break;
+
+ case ERFSLEEP:
+ ppsc->rfoff_reason |= changesource;
+ b_actionallowed = true;
+ break;
+
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ if (b_actionallowed)
+ rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
+
+ if (!protect_or_not) {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ return b_actionallowed;
+}
+EXPORT_SYMBOL(rtl_ps_set_rf_state);
+
+static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ ppsc->b_swrf_processing = true;
+
+ if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
+ if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) &&
+ rtlhal->interface == INTF_PCI) {
+ rtlpriv->intf_ops->disable_aspm(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+ }
+
+ rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
+ RF_CHANGE_BY_IPS, false);
+
+ if (ppsc->inactive_pwrstate == ERFOFF &&
+ rtlhal->interface == INTF_PCI) {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
+ rtlpriv->intf_ops->enable_aspm(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+ }
+
+ ppsc->b_swrf_processing = false;
+}
+
+void rtl_ips_nic_off_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks =
+ container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum rf_pwrstate rtstate;
+
+ if (mac->opmode != NL80211_IFTYPE_STATION) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("not station return\n"));
+ return;
+ }
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if (rtlpriv->sec.being_setkey)
+ return;
+
+ if (ppsc->b_inactiveps) {
+ rtstate = ppsc->rfpwr_state;
+
+ /*
+ *Do not enter IPS in the following conditions:
+ *(1) RF is already OFF or Sleep
+ *(2) b_swrf_processing (indicates the IPS is still under going)
+ *(3) Connectted (only disconnected can trigger IPS)
+ *(4) IBSS (send Beacon)
+ *(5) AP mode (send Beacon)
+ *(6) monitor mode (rcv packet)
+ */
+
+ if (rtstate == ERFON &&
+ !ppsc->b_swrf_processing &&
+ (mac->link_state == MAC80211_NOLINK) &&
+ !mac->act_scanning) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ ("IPSEnter(): Turn off RF.\n"));
+
+ ppsc->inactive_pwrstate = ERFOFF;
+ ppsc->b_in_powersavemode = true;
+
+ /*rtl_pci_reset_trx_ring(hw); */
+ _rtl_ps_inactive_ps(hw);
+ }
+ }
+}
+
+void rtl_ips_nic_off(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /*
+ *because when link with ap, mac80211 will ask us
+ *to disable nic quickly after scan before linking,
+ *this will cause link failed, so we delay 100ms here
+ */
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.ips_nic_off_wq, MSECS(100));
+}
+
+void rtl_ips_nic_on(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum rf_pwrstate rtstate;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
+
+ if (ppsc->b_inactiveps) {
+ rtstate = ppsc->rfpwr_state;
+
+ if (rtstate != ERFON &&
+ !ppsc->b_swrf_processing &&
+ ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
+
+ ppsc->inactive_pwrstate = ERFON;
+ ppsc->b_in_powersavemode = false;
+
+ _rtl_ps_inactive_ps(hw);
+ }
+ }
+
+ spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
+}
+
+/*for FW LPS*/
+
+/*
+ *Determine if we can set Fw into PS mode
+ *in current condition.Return TRUE if it
+ *can enter PS mode.
+ */
+static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u32 ps_timediff;
+
+ ps_timediff = jiffies_to_msecs(jiffies -
+ ppsc->last_delaylps_stamp_jiffies);
+
+ if (ps_timediff < 2000) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Delay enter Fw LPS for DHCP, ARP,"
+ " or EAPOL exchanging state.\n"));
+ return false;
+ }
+
+ if (mac->link_state != MAC80211_LINKED)
+ return false;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ return false;
+
+ return true;
+}
+
+/* Change current and default preamble mode.*/
+static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 rpwm_val, fw_pwrmode;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ return;
+
+ if (mac->link_state != MAC80211_LINKED)
+ return;
+
+ if (ppsc->dot11_psmode == rt_psmode)
+ return;
+
+ /* Update power save mode configured. */
+ ppsc->dot11_psmode = rt_psmode;
+
+ /*
+ *<FW control LPS>
+ *1. Enter PS mode
+ * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
+ * cmd to set Fw into PS mode.
+ *2. Leave PS mode
+ * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
+ * mode and set RPWM to turn RF on.
+ */
+
+ if ((ppsc->b_fwctrl_lps) && (ppsc->b_leisure_ps) &&
+ ppsc->report_linked) {
+ bool b_fw_current_inps;
+ if (ppsc->dot11_psmode == EACTIVE) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("FW LPS leave ps_mode:%x\n",
+ FW_PS_ACTIVE_MODE));
+
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *) (&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *) (&fw_pwrmode));
+ b_fw_current_inps = false;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *) (&b_fw_current_inps));
+
+ } else {
+ if (rtl_get_fwlps_doze(hw)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("FW LPS enter ps_mode:%x\n",
+ ppsc->fwctrl_psmode));
+
+ rpwm_val = 0x02; /* RF off */
+ b_fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *) (&b_fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *) (&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *) (&rpwm_val));
+ } else {
+ /* Reset the power save related parameters. */
+ ppsc->dot11_psmode = EACTIVE;
+ }
+ }
+ }
+}
+
+/*Enter the leisure power save mode.*/
+void rtl_lps_enter(struct ieee80211_hw *hw)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned long flag;
+
+ if (!(ppsc->b_fwctrl_lps && ppsc->b_leisure_ps))
+ return;
+
+ if (rtlpriv->sec.being_setkey)
+ return;
+
+ if (rtlpriv->link_info.b_busytraffic)
+ return;
+
+ /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
+ if (mac->cnt_after_linked < 5)
+ return;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ return;
+
+ if (mac->link_state != MAC80211_LINKED)
+ return;
+
+ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+
+ if (ppsc->b_leisure_ps) {
+ /* Idle for a while if we connect to AP a while ago. */
+ if (mac->cnt_after_linked >= 2) {
+ if (ppsc->dot11_psmode == EACTIVE) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Enter 802.11 power save mode...\n"));
+
+ rtl_lps_set_psmode(hw, EAUTOPS);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+
+/*Leave the leisure power save mode.*/
+void rtl_lps_leave(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ unsigned long flag;
+
+ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+
+ if (ppsc->b_fwctrl_lps && ppsc->b_leisure_ps) {
+ if (ppsc->dot11_psmode != EACTIVE) {
+
+ /*FIX ME */
+ rtlpriv->cfg->ops->enable_interrupt(hw);
+
+ if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) &&
+ rtlhal->interface == INTF_PCI) {
+ rtlpriv->intf_ops->disable_aspm(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM);
+ }
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Busy Traffic,Leave 802.11 power save..\n"));
+
+ rtl_lps_set_psmode(hw, EACTIVE);
+ }
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
new file mode 100644
index 000000000000..ae56da801a23
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __REALTEK_RTL_PCI_PS_H__
+#define __REALTEK_RTL_PCI_PS_H__
+
+bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate state_toset, u32 changesource,
+ bool protect_or_not);
+bool rtl_ps_enable_nic(struct ieee80211_hw *hw);
+bool rtl_ps_disable_nic(struct ieee80211_hw *hw);
+void rtl_ips_nic_off(struct ieee80211_hw *hw);
+void rtl_ips_nic_on(struct ieee80211_hw *hw);
+void rtl_ips_nic_off_wq_callback(void *data);
+void rtl_lps_enter(struct ieee80211_hw *hw);
+void rtl_lps_leave(struct ieee80211_hw *hw);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
new file mode 100644
index 000000000000..91634107434a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -0,0 +1,329 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "base.h"
+#include "rc.h"
+
+/*
+ *Finds the highest rate index we can use
+ *if skb is special data like DHCP/EAPOL, we set should
+ *it to lowest rate CCK_1M, otherwise we set rate to
+ *CCK11M or OFDM_54M based on wireless mode.
+ */
+static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
+ struct sk_buff *skb, bool not_data)
+{
+ struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
+
+ /*
+ *mgt use 1M, although we have check it
+ *before this function use rate_control_send_low,
+ *we still check it here
+ */
+ if (not_data)
+ return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+
+ /*
+ *this rate is no use for true rate, firmware
+ *will control rate at all it just used for
+ *1.show in iwconfig in B/G mode
+ *2.in rtl_get_tcb_desc when we check rate is
+ * 1M we will not use FW rate but user rate.
+ */
+ if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) {
+ return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ } else {
+ if (rtlmac->mode == WIRELESS_MODE_B)
+ return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
+ else
+ return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+ }
+}
+
+static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
+ struct ieee80211_tx_rate *rate,
+ struct ieee80211_tx_rate_control *txrc,
+ u8 tries, u8 rix, int rtsctsenable,
+ bool not_data)
+{
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+ rate->count = tries;
+ rate->idx = (rix > 0x2) ? rix : 0x2;
+
+ if (!not_data) {
+ if (txrc->short_preamble)
+ rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+ if (mac->bw_40)
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (mac->sgi_20 || mac->sgi_40)
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (mac->ht_enable)
+ rate->flags |= IEEE80211_TX_RC_MCS;
+ }
+}
+
+static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
+ void *priv_sta, struct ieee80211_tx_rate_control *txrc)
+{
+ struct rtl_priv *rtlpriv = ppriv;
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *rates = tx_info->control.rates;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ __le16 fc = hdr->frame_control;
+ u8 try_per_rate, i, rix;
+ bool not_data = !ieee80211_is_data(fc);
+
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data);
+
+ try_per_rate = 1;
+ _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc,
+ try_per_rate, rix, 1, not_data);
+
+ if (!not_data) {
+ for (i = 1; i < 4; i++)
+ _rtl_rc_rate_set_series(rtlpriv, &rates[i],
+ txrc, i, (rix - i), 1,
+ not_data);
+ }
+}
+
+static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid)
+{
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+ if (mac->act_scanning)
+ return false;
+
+ if (mac->cnt_after_linked < 3)
+ return false;
+
+ if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF)
+ return true;
+
+ return false;
+}
+
+/*mac80211 Rate Control callbacks*/
+static void rtl_tx_status(void *ppriv,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = ppriv;
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+ struct ieee80211_hdr *hdr;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ if (!priv_sta || !ieee80211_is_data(fc))
+ return;
+
+ if (rtl_is_special_data(mac->hw, skb, true))
+ return;
+
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr))
+ || is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+ return;
+
+ /* Check if aggregation has to be enabled for this tid */
+ if (conf_is_ht(&mac->hw->conf) &&
+ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+ if (ieee80211_is_data_qos(fc)) {
+ u8 *qc, tid;
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+
+ if (_rtl_tx_aggr_check(rtlpriv, tid))
+ ieee80211_start_tx_ba_session(sta, tid, 5000);
+ }
+ }
+}
+
+static void rtl_rate_init(void *ppriv,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct rtl_priv *rtlpriv = ppriv;
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+ u8 is_ht = conf_is_ht(&mac->hw->conf);
+
+ if ((mac->opmode == NL80211_IFTYPE_STATION) ||
+ (mac->opmode == NL80211_IFTYPE_MESH_POINT) ||
+ (mac->opmode == NL80211_IFTYPE_ADHOC)) {
+
+ switch (sband->band) {
+ case IEEE80211_BAND_2GHZ:
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_G;
+ if (is_ht)
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_A;
+ if (is_ht)
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Invalid band\n"));
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ }
+
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG,
+ ("Choosing rate table index: %d\n",
+ rtlpriv->rate_priv->cur_ratetab_idx));
+
+ }
+
+}
+
+static void rtl_rate_update(void *ppriv,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ u32 changed,
+ enum nl80211_channel_type oper_chan_type)
+{
+ struct rtl_priv *rtlpriv = ppriv;
+ struct rtl_mac *mac = rtl_mac(rtlpriv);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ bool oper_cw40 = false, oper_sgi40;
+ bool local_cw40 = mac->bw_40;
+ bool local_sgi40 = mac->sgi_40;
+ u8 is_ht = conf_is_ht(&mac->hw->conf);
+
+ if (changed & IEEE80211_RC_HT_CHANGED) {
+ if (mac->opmode != NL80211_IFTYPE_STATION)
+ return;
+
+ if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
+ rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
+ oper_cw40 = true;
+
+ oper_sgi40 = mac->sgi_40;
+
+ if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
+ switch (sband->band) {
+ case IEEE80211_BAND_2GHZ:
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_G;
+ if (is_ht)
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_A;
+ if (is_ht)
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Invalid band\n"));
+ rtlpriv->rate_priv->cur_ratetab_idx =
+ RATR_INX_WIRELESS_NGB;
+ break;
+ }
+ }
+ }
+}
+
+static void *rtl_rate_alloc(struct ieee80211_hw *hw,
+ struct dentry *debugfsdir)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ return rtlpriv;
+}
+
+static void rtl_rate_free(void *rtlpriv)
+{
+ return;
+}
+
+static void *rtl_rate_alloc_sta(void *ppriv,
+ struct ieee80211_sta *sta, gfp_t gfp)
+{
+ struct rtl_priv *rtlpriv = ppriv;
+ struct rtl_rate_priv *rate_priv;
+
+ rate_priv = kzalloc(sizeof(struct rtl_rate_priv), gfp);
+ if (!rate_priv) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unable to allocate private rc structure\n"));
+ return NULL;
+ }
+
+ rtlpriv->rate_priv = rate_priv;
+
+ return rate_priv;
+}
+
+static void rtl_rate_free_sta(void *rtlpriv,
+ struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct rtl_rate_priv *rate_priv = priv_sta;
+ kfree(rate_priv);
+}
+
+static struct rate_control_ops rtl_rate_ops = {
+ .module = NULL,
+ .name = "rtl_rc",
+ .alloc = rtl_rate_alloc,
+ .free = rtl_rate_free,
+ .alloc_sta = rtl_rate_alloc_sta,
+ .free_sta = rtl_rate_free_sta,
+ .rate_init = rtl_rate_init,
+ .rate_update = rtl_rate_update,
+ .tx_status = rtl_tx_status,
+ .get_rate = rtl_get_rate,
+};
+
+int rtl_rate_control_register(void)
+{
+ return ieee80211_rate_control_register(&rtl_rate_ops);
+}
+
+void rtl_rate_control_unregister(void)
+{
+ ieee80211_rate_control_unregister(&rtl_rate_ops);
+}
diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h
new file mode 100644
index 000000000000..b4667c035f0b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rc.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_RC_H__
+#define __RTL_RC_H__
+
+struct rtl_rate_priv {
+ u8 cur_ratetab_idx;
+ u8 ht_cap;
+};
+
+int rtl_rate_control_register(void);
+void rtl_rate_control_unregister(void);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
new file mode 100644
index 000000000000..3336ca999dfd
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -0,0 +1,400 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "regd.h"
+
+static struct country_code_to_enum_rd allCountries[] = {
+ {COUNTRY_CODE_FCC, "US"},
+ {COUNTRY_CODE_IC, "US"},
+ {COUNTRY_CODE_ETSI, "EC"},
+ {COUNTRY_CODE_SPAIN, "EC"},
+ {COUNTRY_CODE_FRANCE, "EC"},
+ {COUNTRY_CODE_MKK, "JP"},
+ {COUNTRY_CODE_MKK1, "JP"},
+ {COUNTRY_CODE_ISRAEL, "EC"},
+ {COUNTRY_CODE_TELEC, "JP"},
+ {COUNTRY_CODE_MIC, "JP"},
+ {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
+ {COUNTRY_CODE_WORLD_WIDE_13, "EC"},
+ {COUNTRY_CODE_TELEC_NETGEAR, "EC"},
+};
+
+/*
+ *Only these channels all allow active
+ *scan on all world regulatory domains
+ */
+#define RTL819x_2GHZ_CH01_11 \
+ REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
+
+/*
+ *We enable active scan on these a case
+ *by case basis by regulatory domain
+ */
+#define RTL819x_2GHZ_CH12_13 \
+ REG_RULE(2467-10, 2472+10, 40, 0, 20,\
+ NL80211_RRF_PASSIVE_SCAN)
+
+#define RTL819x_2GHZ_CH14 \
+ REG_RULE(2484-10, 2484+10, 40, 0, 20, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_OFDM)
+
+static const struct ieee80211_regdomain rtl_regdom_11 = {
+ .n_reg_rules = 1,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_global = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_2GHZ_CH14,
+ }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_world = {
+ .n_reg_rules = 2,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ }
+};
+
+static bool _rtl_is_radar_freq(u16 center_freq)
+{
+ return (center_freq >= 5260 && center_freq <= 5700);
+}
+
+static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
+{
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ const struct ieee80211_reg_rule *reg_rule;
+ struct ieee80211_channel *ch;
+ unsigned int i;
+ u32 bandwidth = 0;
+ int r;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+
+ if (!wiphy->bands[band])
+ continue;
+
+ sband = wiphy->bands[band];
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (_rtl_is_radar_freq(ch->center_freq) ||
+ (ch->flags & IEEE80211_CHAN_RADAR))
+ continue;
+ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+ r = freq_reg_info(wiphy, ch->center_freq,
+ bandwidth, &reg_rule);
+ if (r)
+ continue;
+
+ /*
+ *If 11d had a rule for this channel ensure
+ *we enable adhoc/beaconing if it allows us to
+ *use it. Note that we would have disabled it
+ *by applying our static world regdomain by
+ *default during init, prior to calling our
+ *regulatory_hint().
+ */
+
+ if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
+ ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+ if (!(reg_rule->
+ flags & NL80211_RRF_PASSIVE_SCAN))
+ ch->flags &=
+ ~IEEE80211_CHAN_PASSIVE_SCAN;
+ } else {
+ if (ch->beacon_found)
+ ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN);
+ }
+ }
+ }
+}
+
+/* Allows active scan scan on Ch 12 and 13 */
+static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator
+ initiator)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ const struct ieee80211_reg_rule *reg_rule;
+ u32 bandwidth = 0;
+ int r;
+
+ sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+
+ /*
+ *If no country IE has been received always enable active scan
+ *on these channels. This is only done for specific regulatory SKUs
+ */
+ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+ ch = &sband->channels[11]; /* CH 12 */
+ if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ ch = &sband->channels[12]; /* CH 13 */
+ if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ return;
+ }
+
+ /*
+ *If a country IE has been recieved check its rule for this
+ *channel first before enabling active scan. The passive scan
+ *would have been enforced by the initial processing of our
+ *custom regulatory domain.
+ */
+
+ ch = &sband->channels[11]; /* CH 12 */
+ r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
+ if (!r) {
+ if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+ if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+
+ ch = &sband->channels[12]; /* CH 13 */
+ r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
+ if (!r) {
+ if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+ if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+}
+
+/*
+ *Always apply Radar/DFS rules on
+ *freq range 5260 MHz - 5700 MHz
+ */
+static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ unsigned int i;
+
+ if (!wiphy->bands[IEEE80211_BAND_5GHZ])
+ return;
+
+ sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (!_rtl_is_radar_freq(ch->center_freq))
+ continue;
+
+ /*
+ *We always enable radar detection/DFS on this
+ *frequency range. Additionally we also apply on
+ *this frequency range:
+ *- If STA mode does not yet have DFS supports disable
+ * active scanning
+ *- If adhoc mode does not support DFS yet then disable
+ * adhoc in the frequency.
+ *- If AP mode does not yet support radar detection/DFS
+ *do not allow AP mode
+ */
+ if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+ ch->flags |= IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+}
+
+static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct rtl_regulatory *reg)
+{
+ _rtl_reg_apply_beaconing_flags(wiphy, initiator);
+ _rtl_reg_apply_active_scan_flags(wiphy, initiator);
+ return;
+}
+
+static void _rtl_dump_channel_map(struct wiphy *wiphy)
+{
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ unsigned int i;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!wiphy->bands[band])
+ continue;
+ sband = wiphy->bands[band];
+ for (i = 0; i < sband->n_channels; i++)
+ ch = &sband->channels[i];
+ }
+}
+
+static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct rtl_regulatory *reg)
+{
+ /* We always apply this */
+ _rtl_reg_apply_radar_flags(wiphy);
+
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ case NL80211_REGDOM_SET_BY_CORE:
+ case NL80211_REGDOM_SET_BY_USER:
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ _rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
+ break;
+ }
+
+ _rtl_dump_channel_map(wiphy);
+
+ return 0;
+}
+
+static const struct ieee80211_regdomain *_rtl_regdomain_select(
+ struct rtl_regulatory *reg)
+{
+ switch (reg->country_code) {
+ case COUNTRY_CODE_FCC:
+ case COUNTRY_CODE_IC:
+ return &rtl_regdom_11;
+ case COUNTRY_CODE_ETSI:
+ case COUNTRY_CODE_SPAIN:
+ case COUNTRY_CODE_FRANCE:
+ case COUNTRY_CODE_ISRAEL:
+ case COUNTRY_CODE_TELEC_NETGEAR:
+ return &rtl_regdom_world;
+ case COUNTRY_CODE_MKK:
+ case COUNTRY_CODE_MKK1:
+ case COUNTRY_CODE_TELEC:
+ case COUNTRY_CODE_MIC:
+ return &rtl_regdom_global;
+ case COUNTRY_CODE_GLOBAL_DOMAIN:
+ return &rtl_regdom_global;
+ case COUNTRY_CODE_WORLD_WIDE_13:
+ return &rtl_regdom_world;
+ default:
+ return &rtl_regdom_world;
+ }
+}
+
+static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
+ struct wiphy *wiphy,
+ int (*reg_notifier) (struct wiphy *wiphy,
+ struct regulatory_request *
+ request))
+{
+ const struct ieee80211_regdomain *regd;
+
+ wiphy->reg_notifier = reg_notifier;
+ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
+ wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+ regd = _rtl_regdomain_select(reg);
+ wiphy_apply_custom_regulatory(wiphy, regd);
+ _rtl_reg_apply_radar_flags(wiphy);
+ _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+ return 0;
+}
+
+static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (allCountries[i].countrycode == countrycode)
+ return &allCountries[i];
+ }
+ return NULL;
+}
+
+int rtl_regd_init(struct ieee80211_hw *hw,
+ int (*reg_notifier) (struct wiphy *wiphy,
+ struct regulatory_request *request))
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct wiphy *wiphy = hw->wiphy;
+ struct country_code_to_enum_rd *country = NULL;
+
+ if (wiphy == NULL || &rtlpriv->regd == NULL)
+ return -EINVAL;
+
+ /* force the channel plan to world wide 13 */
+ rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
+
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
+ (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
+ rtlpriv->regd.country_code));
+
+ if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
+ (KERN_DEBUG "rtl: EEPROM indicates invalid contry code"
+ "world wide 13 should be used\n"));
+
+ rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
+ }
+
+ country = _rtl_regd_find_country(rtlpriv->regd.country_code);
+
+ if (country) {
+ rtlpriv->regd.alpha2[0] = country->isoName[0];
+ rtlpriv->regd.alpha2[1] = country->isoName[1];
+ } else {
+ rtlpriv->regd.alpha2[0] = '0';
+ rtlpriv->regd.alpha2[1] = '0';
+ }
+
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
+ (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n",
+ rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]));
+
+ _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
+
+ return 0;
+}
+
+int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, ("\n"));
+
+ return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
+}
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
new file mode 100644
index 000000000000..4cdbc4ae76d4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_REGD_H__
+#define __RTL_REGD_H__
+
+struct country_code_to_enum_rd {
+ u16 countrycode;
+ const char *isoName;
+};
+
+enum country_code_type_t {
+ COUNTRY_CODE_FCC = 0,
+ COUNTRY_CODE_IC = 1,
+ COUNTRY_CODE_ETSI = 2,
+ COUNTRY_CODE_SPAIN = 3,
+ COUNTRY_CODE_FRANCE = 4,
+ COUNTRY_CODE_MKK = 5,
+ COUNTRY_CODE_MKK1 = 6,
+ COUNTRY_CODE_ISRAEL = 7,
+ COUNTRY_CODE_TELEC = 8,
+ COUNTRY_CODE_MIC = 9,
+ COUNTRY_CODE_GLOBAL_DOMAIN = 10,
+ COUNTRY_CODE_WORLD_WIDE_13 = 11,
+ COUNTRY_CODE_TELEC_NETGEAR = 12,
+
+ /*add new channel plan above this line */
+ COUNTRY_CODE_MAX
+};
+
+int rtl_regd_init(struct ieee80211_hw *hw,
+ int (*reg_notifier) (struct wiphy *wiphy,
+ struct regulatory_request *request));
+int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile
new file mode 100644
index 000000000000..0f0be7c763b8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile
@@ -0,0 +1,12 @@
+rtl8192ce-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o
+
+obj-$(CONFIG_RTL8192CE) += rtl8192ce.o
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
new file mode 100644
index 000000000000..83cd64895292
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -0,0 +1,257 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_DEF_H__
+#define __RTL92C_DEF_H__
+
+#define HAL_RETRY_LIMIT_INFRA 48
+#define HAL_RETRY_LIMIT_AP_ADHOC 7
+
+#define PHY_RSSI_SLID_WIN_MAX 100
+#define PHY_LINKQUALITY_SLID_WIN_MAX 20
+#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
+
+#define RESET_DELAY_8185 20
+
+#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE 10
+#define NUM_OF_PAGES_IN_FW 0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00
+
+#define MAX_LINES_HWCONFIG_TXT 1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT 256
+
+#define SW_THREE_WIRE 0
+#define HW_THREE_WIRE 2
+
+#define BT_DEMO_BOARD 0
+#define BT_QA_BOARD 1
+#define BT_FPGA 2
+
+#define RX_SMOOTH_FACTOR 20
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
+#define HAL_PRIME_CHNL_OFFSET_LOWER 1
+#define HAL_PRIME_CHNL_OFFSET_UPPER 2
+
+#define MAX_H2C_QUEUE_NUM 10
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+#define AC2QUEUEID(_AC) (_AC)
+
+#define C2H_RX_CMD_HDR_LEN 8
+#define GET_C2H_CMD_CMD_LEN(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define GET_C2H_CMD_CONTINUE(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define GET_C2H_CMD_CONTENT(__prxhdr) \
+ ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_VER_B BIT(4)
+#define CHIP_92C_BITMASK BIT(0)
+#define CHIP_92C_1T2R 0x03
+#define CHIP_92C 0x01
+#define CHIP_88C 0x00
+
+enum version_8192c {
+ VERSION_A_CHIP_92C = 0x01,
+ VERSION_A_CHIP_88C = 0x00,
+ VERSION_B_CHIP_92C = 0x11,
+ VERSION_B_CHIP_88C = 0x10,
+ VERSION_UNKNOWN = 0x88,
+};
+
+#define IS_CHIP_VER_B(version) ((version & CHIP_VER_B) ? true : false)
+#define IS_92C_SERIAL(version) ((version & CHIP_92C_BITMASK) ? true : false)
+
+enum rtl819x_loopback_e {
+ RTL819X_NO_LOOPBACK = 0,
+ RTL819X_MAC_LOOPBACK = 1,
+ RTL819X_DMA_LOOPBACK = 2,
+ RTL819X_CCK_LOOPBACK = 3,
+};
+
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum rf_power_state {
+ RF_ON,
+ RF_OFF,
+ RF_SLEEP,
+ RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+ POWER_SAVE_MODE_ACTIVE,
+ POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+ POWERCFG_MAX_POWER_SAVINGS,
+ POWERCFG_GLOBAL_POWER_SAVINGS,
+ POWERCFG_LOCAL_POWER_SAVINGS,
+ POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+ INTF_SEL1_MINICARD = 0,
+ INTF_SEL0_PCIE = 1,
+ INTF_SEL2_RSV = 2,
+ INTF_SEL3_RSV = 3,
+};
+
+enum hal_fw_c2h_cmd_id {
+ HAL_FW_C2H_CMD_Read_MACREG = 0,
+ HAL_FW_C2H_CMD_Read_BBREG = 1,
+ HAL_FW_C2H_CMD_Read_RFREG = 2,
+ HAL_FW_C2H_CMD_Read_EEPROM = 3,
+ HAL_FW_C2H_CMD_Read_EFUSE = 4,
+ HAL_FW_C2H_CMD_Read_CAM = 5,
+ HAL_FW_C2H_CMD_Get_BasicRate = 6,
+ HAL_FW_C2H_CMD_Get_DataRate = 7,
+ HAL_FW_C2H_CMD_Survey = 8,
+ HAL_FW_C2H_CMD_SurveyDone = 9,
+ HAL_FW_C2H_CMD_JoinBss = 10,
+ HAL_FW_C2H_CMD_AddSTA = 11,
+ HAL_FW_C2H_CMD_DelSTA = 12,
+ HAL_FW_C2H_CMD_AtimDone = 13,
+ HAL_FW_C2H_CMD_TX_Report = 14,
+ HAL_FW_C2H_CMD_CCX_Report = 15,
+ HAL_FW_C2H_CMD_DTM_Report = 16,
+ HAL_FW_C2H_CMD_TX_Rate_Statistics = 17,
+ HAL_FW_C2H_CMD_C2HLBK = 18,
+ HAL_FW_C2H_CMD_C2HDBG = 19,
+ HAL_FW_C2H_CMD_C2HFEEDBACK = 20,
+ HAL_FW_C2H_CMD_MAX
+};
+
+enum rtl_desc_qsel {
+ QSLT_BK = 0x2,
+ QSLT_BE = 0x0,
+ QSLT_VI = 0x5,
+ QSLT_VO = 0x7,
+ QSLT_BEACON = 0x10,
+ QSLT_HIGH = 0x11,
+ QSLT_MGNT = 0x12,
+ QSLT_CMD = 0x13,
+};
+
+enum rtl_desc92c_rate {
+ DESC92C_RATE1M = 0x00,
+ DESC92C_RATE2M = 0x01,
+ DESC92C_RATE5_5M = 0x02,
+ DESC92C_RATE11M = 0x03,
+
+ DESC92C_RATE6M = 0x04,
+ DESC92C_RATE9M = 0x05,
+ DESC92C_RATE12M = 0x06,
+ DESC92C_RATE18M = 0x07,
+ DESC92C_RATE24M = 0x08,
+ DESC92C_RATE36M = 0x09,
+ DESC92C_RATE48M = 0x0a,
+ DESC92C_RATE54M = 0x0b,
+
+ DESC92C_RATEMCS0 = 0x0c,
+ DESC92C_RATEMCS1 = 0x0d,
+ DESC92C_RATEMCS2 = 0x0e,
+ DESC92C_RATEMCS3 = 0x0f,
+ DESC92C_RATEMCS4 = 0x10,
+ DESC92C_RATEMCS5 = 0x11,
+ DESC92C_RATEMCS6 = 0x12,
+ DESC92C_RATEMCS7 = 0x13,
+ DESC92C_RATEMCS8 = 0x14,
+ DESC92C_RATEMCS9 = 0x15,
+ DESC92C_RATEMCS10 = 0x16,
+ DESC92C_RATEMCS11 = 0x17,
+ DESC92C_RATEMCS12 = 0x18,
+ DESC92C_RATEMCS13 = 0x19,
+ DESC92C_RATEMCS14 = 0x1a,
+ DESC92C_RATEMCS15 = 0x1b,
+ DESC92C_RATEMCS15_SG = 0x1c,
+ DESC92C_RATEMCS32 = 0x20,
+};
+
+struct phy_sts_cck_8192s_t {
+ u8 adc_pwdb_X[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8192c {
+ u8 element_id;
+ u32 cmd_len;
+ u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
new file mode 100644
index 000000000000..62e7c64e087b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
@@ -0,0 +1,1473 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+
+struct dig_t dm_digtable;
+static struct ps_t dm_pstable;
+
+static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
+ 0x7f8001fe,
+ 0x788001e2,
+ 0x71c001c7,
+ 0x6b8001ae,
+ 0x65400195,
+ 0x5fc0017f,
+ 0x5a400169,
+ 0x55400155,
+ 0x50800142,
+ 0x4c000130,
+ 0x47c0011f,
+ 0x43c0010f,
+ 0x40000100,
+ 0x3c8000f2,
+ 0x390000e4,
+ 0x35c000d7,
+ 0x32c000cb,
+ 0x300000c0,
+ 0x2d4000b5,
+ 0x2ac000ab,
+ 0x288000a2,
+ 0x26000098,
+ 0x24000090,
+ 0x22000088,
+ 0x20000080,
+ 0x1e400079,
+ 0x1c800072,
+ 0x1b00006c,
+ 0x19800066,
+ 0x18000060,
+ 0x16c0005b,
+ 0x15800056,
+ 0x14400051,
+ 0x1300004c,
+ 0x12000048,
+ 0x11000044,
+ 0x10000040,
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04},
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03},
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03},
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03},
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02},
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02},
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02},
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02},
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},
+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02},
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},
+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01},
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01},
+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01},
+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01},
+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01},
+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01},
+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01},
+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01},
+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01},
+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01},
+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01},
+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00},
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00},
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00},
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00},
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00},
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00},
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00},
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00},
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},
+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00},
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},
+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00},
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00},
+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},
+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},
+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00},
+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},
+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},
+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},
+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},
+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},
+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},
+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
+};
+
+static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
+{
+ dm_digtable.dig_enable_flag = true;
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ dm_digtable.cur_igvalue = 0x20;
+ dm_digtable.pre_igvalue = 0x0;
+ dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT;
+ dm_digtable.presta_connectstate = DIG_STA_DISCONNECT;
+ dm_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT;
+ dm_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW;
+ dm_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH;
+ dm_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ dm_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+ dm_digtable.rx_gain_range_max = DM_DIG_MAX;
+ dm_digtable.rx_gain_range_min = DM_DIG_MIN;
+ dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX;
+ dm_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN;
+ dm_digtable.pre_cck_pd_state = CCK_PD_STAGE_MAX;
+ dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX;
+}
+
+static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ long rssi_val_min = 0;
+
+ if ((dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) &&
+ (dm_digtable.cursta_connectctate == DIG_STA_CONNECT)) {
+ if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0)
+ rssi_val_min =
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb >
+ rtlpriv->dm.undecorated_smoothed_pwdb) ?
+ rtlpriv->dm.undecorated_smoothed_pwdb :
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ else
+ rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
+ } else if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT ||
+ dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT) {
+ rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
+ } else if (dm_digtable.curmultista_connectstate ==
+ DIG_MULTISTA_CONNECT) {
+ rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ }
+
+ return (u8) rssi_val_min;
+}
+
+static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ u32 ret_value;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+ falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+ falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+ falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+ falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+ falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal +
+ falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail;
+
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
+ falsealm_cnt->cnt_cck_fail = ret_value;
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
+ falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+ falsealm_cnt->cnt_all = (falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal +
+ falsealm_cnt->cnt_crc8_fail +
+ falsealm_cnt->cnt_mcs_fail +
+ falsealm_cnt->cnt_cck_fail);
+
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+ "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+ falsealm_cnt->cnt_parity_fail,
+ falsealm_cnt->cnt_rate_illegal,
+ falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail));
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
+ falsealm_cnt->cnt_ofdm_fail,
+ falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all));
+}
+
+static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value_igi = dm_digtable.cur_igvalue;
+
+ if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+ value_igi--;
+ else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1)
+ value_igi += 0;
+ else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2)
+ value_igi++;
+ else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2)
+ value_igi += 2;
+ if (value_igi > DM_DIG_FA_UPPER)
+ value_igi = DM_DIG_FA_UPPER;
+ else if (value_igi < DM_DIG_FA_LOWER)
+ value_igi = DM_DIG_FA_LOWER;
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ value_igi = 0x32;
+
+ dm_digtable.cur_igvalue = value_igi;
+ rtl92c_dm_write_dig(hw);
+}
+
+static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable.fa_highthresh) {
+ if ((dm_digtable.backoff_val - 2) <
+ dm_digtable.backoff_val_range_min)
+ dm_digtable.backoff_val =
+ dm_digtable.backoff_val_range_min;
+ else
+ dm_digtable.backoff_val -= 2;
+ } else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable.fa_lowthresh) {
+ if ((dm_digtable.backoff_val + 2) >
+ dm_digtable.backoff_val_range_max)
+ dm_digtable.backoff_val =
+ dm_digtable.backoff_val_range_max;
+ else
+ dm_digtable.backoff_val += 2;
+ }
+
+ if ((dm_digtable.rssi_val_min + 10 - dm_digtable.backoff_val) >
+ dm_digtable.rx_gain_range_max)
+ dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_max;
+ else if ((dm_digtable.rssi_val_min + 10 -
+ dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
+ dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_min;
+ else
+ dm_digtable.cur_igvalue = dm_digtable.rssi_val_min + 10 -
+ dm_digtable.backoff_val;
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("rssi_val_min = %x backoff_val %x\n",
+ dm_digtable.rssi_val_min, dm_digtable.backoff_val));
+
+ rtl92c_dm_write_dig(hw);
+}
+
+static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
+{
+ static u8 binitialized; /* initialized to false */
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ bool b_multi_sta = false;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ b_multi_sta = true;
+
+ if ((b_multi_sta == false) || (dm_digtable.cursta_connectctate !=
+ DIG_STA_DISCONNECT)) {
+ binitialized = false;
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ return;
+ } else if (binitialized == false) {
+ binitialized = true;
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
+ dm_digtable.cur_igvalue = 0x20;
+ rtl92c_dm_write_dig(hw);
+ }
+
+ if (dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) {
+ if ((rssi_strength < dm_digtable.rssi_lowthresh) &&
+ (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) {
+
+ if (dm_digtable.dig_ext_port_stage ==
+ DIG_EXT_PORT_STAGE_2) {
+ dm_digtable.cur_igvalue = 0x20;
+ rtl92c_dm_write_dig(hw);
+ }
+
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_1;
+ } else if (rssi_strength > dm_digtable.rssi_highthresh) {
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_2;
+ rtl92c_dm_ctrl_initgain_by_fa(hw);
+ }
+ } else if (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) {
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
+ dm_digtable.cur_igvalue = 0x20;
+ rtl92c_dm_write_dig(hw);
+ }
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("curmultista_connectstate = "
+ "%x dig_ext_port_stage %x\n",
+ dm_digtable.curmultista_connectstate,
+ dm_digtable.dig_ext_port_stage));
+}
+
+static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("presta_connectstate = %x,"
+ " cursta_connectctate = %x\n",
+ dm_digtable.presta_connectstate,
+ dm_digtable.cursta_connectctate));
+
+ if (dm_digtable.presta_connectstate == dm_digtable.cursta_connectctate
+ || dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT
+ || dm_digtable.cursta_connectctate == DIG_STA_CONNECT) {
+
+ if (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) {
+ dm_digtable.rssi_val_min =
+ rtl92c_dm_initial_gain_min_pwdb(hw);
+ rtl92c_dm_ctrl_initgain_by_rssi(hw);
+ }
+ } else {
+ dm_digtable.rssi_val_min = 0;
+ dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_digtable.cur_igvalue = 0x20;
+ dm_digtable.pre_igvalue = 0;
+ rtl92c_dm_write_dig(hw);
+ }
+}
+
+static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT) {
+ dm_digtable.rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);
+
+ if (dm_digtable.pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+ if (dm_digtable.rssi_val_min <= 25)
+ dm_digtable.cur_cck_pd_state =
+ CCK_PD_STAGE_LowRssi;
+ else
+ dm_digtable.cur_cck_pd_state =
+ CCK_PD_STAGE_HighRssi;
+ } else {
+ if (dm_digtable.rssi_val_min <= 20)
+ dm_digtable.cur_cck_pd_state =
+ CCK_PD_STAGE_LowRssi;
+ else
+ dm_digtable.cur_cck_pd_state =
+ CCK_PD_STAGE_HighRssi;
+ }
+ } else {
+ dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX;
+ }
+
+ if (dm_digtable.pre_cck_pd_state != dm_digtable.cur_cck_pd_state) {
+ if (dm_digtable.cur_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800)
+ dm_digtable.cur_cck_fa_state =
+ CCK_FA_STAGE_High;
+ else
+ dm_digtable.cur_cck_fa_state = CCK_FA_STAGE_Low;
+
+ if (dm_digtable.pre_cck_fa_state !=
+ dm_digtable.cur_cck_fa_state) {
+ if (dm_digtable.cur_cck_fa_state ==
+ CCK_FA_STAGE_Low)
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
+ 0x83);
+ else
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
+ 0xcd);
+
+ dm_digtable.pre_cck_fa_state =
+ dm_digtable.cur_cck_fa_state;
+ }
+
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40);
+
+ if (IS_92C_SERIAL(rtlhal->version))
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
+ MASKBYTE2, 0xd7);
+ } else {
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47);
+
+ if (IS_92C_SERIAL(rtlhal->version))
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
+ MASKBYTE2, 0xd3);
+ }
+ dm_digtable.pre_cck_pd_state = dm_digtable.cur_cck_pd_state;
+ }
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("CCKPDStage=%x\n", dm_digtable.cur_cck_pd_state));
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ ("is92C=%x\n", IS_92C_SERIAL(rtlhal->version)));
+}
+
+static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ if (mac->act_scanning == true)
+ return;
+
+ if ((mac->link_state > MAC80211_NOLINK) &&
+ (mac->link_state < MAC80211_LINKED))
+ dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT;
+ else if (mac->link_state >= MAC80211_LINKED)
+ dm_digtable.cursta_connectctate = DIG_STA_CONNECT;
+ else
+ dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT;
+
+ rtl92c_dm_initial_gain_sta(hw);
+ rtl92c_dm_initial_gain_multi_sta(hw);
+ rtl92c_dm_cck_packet_detection_thresh(hw);
+
+ dm_digtable.presta_connectstate = dm_digtable.cursta_connectctate;
+
+}
+
+static void rtl92c_dm_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.b_dm_initialgain_enable == false)
+ return;
+ if (dm_digtable.dig_enable_flag == false)
+ return;
+
+ rtl92c_dm_ctrl_initgain_by_twoport(hw);
+
+}
+
+static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.bdynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+
+static void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undecorated_smoothed_pwdb;
+
+ if (!rtlpriv->dm.bdynamic_txpower_enable)
+ return;
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Not connected to any\n"));
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Client PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("STA Default Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Ext Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+
+ if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"));
+ } else if ((undecorated_smoothed_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+ (undecorated_smoothed_pwdb >=
+ TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"));
+ } else if (undecorated_smoothed_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_NORMAL\n"));
+ }
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("PHY_SetTxPowerLevel8192S() Channel = %d\n",
+ rtlphy->current_channel));
+ rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+ }
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ ("cur_igvalue = 0x%x, "
+ "pre_igvalue = 0x%x, backoff_val = %d\n",
+ dm_digtable.cur_igvalue, dm_digtable.pre_igvalue,
+ dm_digtable.backoff_val));
+
+ if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) {
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
+ dm_digtable.cur_igvalue);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f,
+ dm_digtable.cur_igvalue);
+
+ dm_digtable.pre_igvalue = dm_digtable.cur_igvalue;
+ }
+}
+
+static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff;
+
+ u8 h2c_parameter[3] = { 0 };
+
+ return;
+
+ if (tmpentry_max_pwdb != 0) {
+ rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb =
+ tmpentry_max_pwdb;
+ } else {
+ rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0;
+ }
+
+ if (tmpentry_min_pwdb != 0xff) {
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb =
+ tmpentry_min_pwdb;
+ } else {
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0;
+ }
+
+ h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF);
+ h2c_parameter[0] = 0;
+
+ rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
+}
+
+void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtlpriv->dm.bcurrent_turbo_edca = false;
+ rtlpriv->dm.bis_any_nonbepkts = false;
+ rtlpriv->dm.bis_cur_rdlstate = false;
+}
+
+static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ u64 cur_txok_cnt;
+ u64 cur_rxok_cnt;
+ u32 edca_be_ul = 0x5ea42b;
+ u32 edca_be_dl = 0x5ea42b;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ goto dm_checkedcaturbo_exit;
+
+ if (mac->link_state != MAC80211_LINKED) {
+ rtlpriv->dm.bcurrent_turbo_edca = false;
+ return;
+ }
+
+ if (!mac->ht_enable) { /*FIX MERGE */
+ if (!(edca_be_ul & 0xffff0000))
+ edca_be_ul |= 0x005e0000;
+
+ if (!(edca_be_dl & 0xffff0000))
+ edca_be_dl |= 0x005e0000;
+ }
+
+ if ((!rtlpriv->dm.bis_any_nonbepkts) &&
+ (!rtlpriv->dm.b_disable_framebursting)) {
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+ if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+ if (!rtlpriv->dm.bis_cur_rdlstate ||
+ !rtlpriv->dm.bcurrent_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_dl);
+ rtlpriv->dm.bis_cur_rdlstate = true;
+ }
+ } else {
+ if (rtlpriv->dm.bis_cur_rdlstate ||
+ !rtlpriv->dm.bcurrent_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_ul);
+ rtlpriv->dm.bis_cur_rdlstate = false;
+ }
+ }
+ rtlpriv->dm.bcurrent_turbo_edca = true;
+ } else {
+ if (rtlpriv->dm.bcurrent_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *) (&tmp));
+ rtlpriv->dm.bcurrent_turbo_edca = false;
+ }
+ }
+
+dm_checkedcaturbo_exit:
+ rtlpriv->dm.bis_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
+ *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 thermalvalue, delta, delta_lck, delta_iqk;
+ long ele_a, ele_d, temp_cck, val_x, value32;
+ long val_y, ele_c;
+ u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old;
+ int i;
+ bool is2t = IS_92C_SERIAL(rtlhal->version);
+ u8 txpwr_level[2] = {0, 0};
+ u8 ofdm_min_index = 6, rf;
+
+ rtlpriv->dm.btxpower_trackingInit = true;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n"));
+
+ thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter));
+
+ rtl92c_phy_ap_calibrate(hw, (thermalvalue -
+ rtlefuse->eeprom_thermalmeter));
+ if (is2t)
+ rf = 2;
+ else
+ rf = 1;
+
+ if (thermalvalue) {
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD) & MASKOFDM_D;
+
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_index_old[0] = (u8) i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Initial pathA ele_d reg0x%x = 0x%lx, "
+ "ofdm_index=0x%x\n",
+ ROFDM0_XATXIQIMBALANCE,
+ ele_d, ofdm_index_old[0]));
+ break;
+ }
+ }
+
+ if (is2t) {
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD) & MASKOFDM_D;
+
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_index_old[1] = (u8) i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ ("Initial pathB ele_d reg0x%x = "
+ "0x%lx, ofdm_index=0x%x\n",
+ ROFDM0_XBTXIQIMBALANCE, ele_d,
+ ofdm_index_old[1]));
+ break;
+ }
+ }
+ }
+
+ temp_cck =
+ rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK;
+
+ for (i = 0; i < CCK_TABLE_LENGTH; i++) {
+ if (rtlpriv->dm.b_cck_inch14) {
+ if (memcmp((void *)&temp_cck,
+ (void *)&cckswing_table_ch14[i][2],
+ 4) == 0) {
+ cck_index_old = (u8) i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ ("Initial reg0x%x = 0x%lx, "
+ "cck_index=0x%x, ch 14 %d\n",
+ RCCK0_TXFILTER2, temp_cck,
+ cck_index_old,
+ rtlpriv->dm.b_cck_inch14));
+ break;
+ }
+ } else {
+ if (memcmp((void *)&temp_cck,
+ (void *)
+ &cckswing_table_ch1ch13[i][2],
+ 4) == 0) {
+ cck_index_old = (u8) i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ ("Initial reg0x%x = 0x%lx, "
+ "cck_index=0x%x, ch14 %d\n",
+ RCCK0_TXFILTER2, temp_cck,
+ cck_index_old,
+ rtlpriv->dm.b_cck_inch14));
+ break;
+ }
+ }
+ }
+
+ if (!rtlpriv->dm.thermalvalue) {
+ rtlpriv->dm.thermalvalue =
+ rtlefuse->eeprom_thermalmeter;
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
+ rtlpriv->dm.cck_index = cck_index_old;
+ }
+
+ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue) :
+ (rtlpriv->dm.thermalvalue - thermalvalue);
+
+ delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+ (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+
+ delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+ (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x delta 0x%x "
+ "delta_lck 0x%x delta_iqk 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter, delta, delta_lck,
+ delta_iqk));
+
+ if (delta_lck > 1) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtl92c_phy_lc_calibrate(hw);
+ }
+
+ if (delta > 0 && rtlpriv->dm.txpower_track_control) {
+ if (thermalvalue > rtlpriv->dm.thermalvalue) {
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] -= delta;
+ rtlpriv->dm.cck_index -= delta;
+ } else {
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] += delta;
+ rtlpriv->dm.cck_index += delta;
+ }
+
+ if (is2t) {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("temp OFDM_A_index=0x%x, "
+ "OFDM_B_index=0x%x,"
+ "cck_index=0x%x\n",
+ rtlpriv->dm.ofdm_index[0],
+ rtlpriv->dm.ofdm_index[1],
+ rtlpriv->dm.cck_index));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("temp OFDM_A_index=0x%x,"
+ "cck_index=0x%x\n",
+ rtlpriv->dm.ofdm_index[0],
+ rtlpriv->dm.cck_index));
+ }
+
+ if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] =
+ rtlpriv->dm.ofdm_index[i]
+ + 1;
+ cck_index = rtlpriv->dm.cck_index + 1;
+ } else {
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] =
+ rtlpriv->dm.ofdm_index[i];
+ cck_index = rtlpriv->dm.cck_index;
+ }
+
+ for (i = 0; i < rf; i++) {
+ if (txpwr_level[i] >= 0 &&
+ txpwr_level[i] <= 26) {
+ if (thermalvalue >
+ rtlefuse->eeprom_thermalmeter) {
+ if (delta < 5)
+ ofdm_index[i] -= 1;
+
+ else
+ ofdm_index[i] -= 2;
+ } else if (delta > 5 && thermalvalue <
+ rtlefuse->
+ eeprom_thermalmeter) {
+ ofdm_index[i] += 1;
+ }
+ } else if (txpwr_level[i] >= 27 &&
+ txpwr_level[i] <= 32
+ && thermalvalue >
+ rtlefuse->eeprom_thermalmeter) {
+ if (delta < 5)
+ ofdm_index[i] -= 1;
+
+ else
+ ofdm_index[i] -= 2;
+ } else if (txpwr_level[i] >= 32 &&
+ txpwr_level[i] <= 38 &&
+ thermalvalue >
+ rtlefuse->eeprom_thermalmeter
+ && delta > 5) {
+ ofdm_index[i] -= 1;
+ }
+ }
+
+ if (txpwr_level[i] >= 0 && txpwr_level[i] <= 26) {
+ if (thermalvalue >
+ rtlefuse->eeprom_thermalmeter) {
+ if (delta < 5)
+ cck_index -= 1;
+
+ else
+ cck_index -= 2;
+ } else if (delta > 5 && thermalvalue <
+ rtlefuse->eeprom_thermalmeter) {
+ cck_index += 1;
+ }
+ } else if (txpwr_level[i] >= 27 &&
+ txpwr_level[i] <= 32 &&
+ thermalvalue >
+ rtlefuse->eeprom_thermalmeter) {
+ if (delta < 5)
+ cck_index -= 1;
+
+ else
+ cck_index -= 2;
+ } else if (txpwr_level[i] >= 32 &&
+ txpwr_level[i] <= 38 &&
+ thermalvalue > rtlefuse->eeprom_thermalmeter
+ && delta > 5) {
+ cck_index -= 1;
+ }
+
+ for (i = 0; i < rf; i++) {
+ if (ofdm_index[i] > OFDM_TABLE_SIZE - 1)
+ ofdm_index[i] = OFDM_TABLE_SIZE - 1;
+
+ else if (ofdm_index[i] < ofdm_min_index)
+ ofdm_index[i] = ofdm_min_index;
+ }
+
+ if (cck_index > CCK_TABLE_SIZE - 1)
+ cck_index = CCK_TABLE_SIZE - 1;
+ else if (cck_index < 0)
+ cck_index = 0;
+
+ if (is2t) {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("new OFDM_A_index=0x%x, "
+ "OFDM_B_index=0x%x,"
+ "cck_index=0x%x\n",
+ ofdm_index[0], ofdm_index[1],
+ cck_index));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("new OFDM_A_index=0x%x,"
+ "cck_index=0x%x\n",
+ ofdm_index[0], cck_index));
+ }
+ }
+
+ if (rtlpriv->dm.txpower_track_control && delta != 0) {
+ ele_d =
+ (ofdmswing_table[ofdm_index[0]] & 0xFFC00000) >> 22;
+ val_x = rtlphy->reg_e94;
+ val_y = rtlphy->reg_e9c;
+
+ if (val_x != 0) {
+ if ((val_x & 0x00000200) != 0)
+ val_x = val_x | 0xFFFFFC00;
+ ele_a = ((val_x * ele_d) >> 8) & 0x000003FF;
+
+ if ((val_y & 0x00000200) != 0)
+ val_y = val_y | 0xFFFFFC00;
+ ele_c = ((val_y * ele_d) >> 8) & 0x000003FF;
+
+ value32 = (ele_d << 22) |
+ ((ele_c & 0x3F) << 16) | ele_a;
+
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD, value32);
+
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
+ value32);
+
+ value32 = ((val_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(31), value32);
+
+ value32 = ((val_y * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(29), value32);
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD,
+ ofdmswing_table[ofdm_index[0]]);
+
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
+ 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(31) | BIT(29), 0x00);
+ }
+
+ if (!rtlpriv->dm.b_cck_inch14) {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch1ch13[cck_index]
+ [0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch1ch13[cck_index]
+ [1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch1ch13[cck_index]
+ [2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch1ch13[cck_index]
+ [3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch1ch13[cck_index]
+ [4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch1ch13[cck_index]
+ [5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch1ch13[cck_index]
+ [6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch1ch13[cck_index]
+ [7]);
+ } else {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch14[cck_index]
+ [0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch14[cck_index]
+ [1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch14[cck_index]
+ [2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch14[cck_index]
+ [3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch14[cck_index]
+ [4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch14[cck_index]
+ [5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch14[cck_index]
+ [6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch14[cck_index]
+ [7]);
+ }
+
+ if (is2t) {
+ ele_d = (ofdmswing_table[ofdm_index[1]] &
+ 0xFFC00000) >> 22;
+
+ val_x = rtlphy->reg_eb4;
+ val_y = rtlphy->reg_ebc;
+
+ if (val_x != 0) {
+ if ((val_x & 0x00000200) != 0)
+ val_x = val_x | 0xFFFFFC00;
+ ele_a = ((val_x * ele_d) >> 8) &
+ 0x000003FF;
+
+ if ((val_y & 0x00000200) != 0)
+ val_y = val_y | 0xFFFFFC00;
+ ele_c = ((val_y * ele_d) >> 8) &
+ 0x00003FF;
+
+ value32 = (ele_d << 22) |
+ ((ele_c & 0x3F) << 16) | ele_a;
+ rtl_set_bbreg(hw,
+ ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD, value32);
+
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
+ MASKH4BITS, value32);
+
+ value32 = ((val_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(27), value32);
+
+ value32 = ((val_y * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(25), value32);
+ } else {
+ rtl_set_bbreg(hw,
+ ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD,
+ ofdmswing_table[ofdm_index
+ [1]]);
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
+ MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(27) | BIT(25), 0x00);
+ }
+
+ }
+ }
+
+ if (delta_iqk > 3) {
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ rtl92c_phy_iq_calibrate(hw, false);
+ }
+
+ if (rtlpriv->dm.txpower_track_control)
+ rtlpriv->dm.thermalvalue = thermalvalue;
+ }
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("<===\n"));
+
+}
+
+static void rtl92c_dm_initialize_txpower_tracking_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.btxpower_tracking = true;
+ rtlpriv->dm.btxpower_trackingInit = false;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("pMgntInfo->btxpower_tracking = %d\n",
+ rtlpriv->dm.btxpower_tracking));
+}
+
+static void rtl92c_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
+{
+ rtl92c_dm_initialize_txpower_tracking_thermalmeter(hw);
+}
+
+static void rtl92c_dm_txpower_tracking_directcall(struct ieee80211_hw *hw)
+{
+ rtl92c_dm_txpower_tracking_callback_thermalmeter(hw);
+}
+
+static void rtl92c_dm_check_txpower_tracking_thermal_meter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ static u8 tm_trigger;
+
+ if (!rtlpriv->dm.btxpower_tracking)
+ return;
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK,
+ 0x60);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Trigger 92S Thermal Meter!!\n"));
+ tm_trigger = 1;
+ return;
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Schedule TxPowerTracking direct call!!\n"));
+ rtl92c_dm_txpower_tracking_directcall(hw);
+ tm_trigger = 0;
+ }
+}
+
+void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+ rtl92c_dm_check_txpower_tracking_thermal_meter(hw);
+}
+
+void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+
+ p_ra->ratr_state = DM_RATR_STA_INIT;
+ p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.b_useramask = true;
+ else
+ rtlpriv->dm.b_useramask = false;
+
+}
+
+static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+ u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ ("<---- driver is going to unload\n"));
+ return;
+ }
+
+ if (!rtlpriv->dm.b_useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ ("<---- driver does not control rate adaptive mask\n"));
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED) {
+
+ switch (p_ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ high_rssithresh_for_ra = 55;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 25;
+ break;
+ default:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ }
+
+ if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)high_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)low_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ p_ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ ("RSSI = %ld\n",
+ rtlpriv->dm.undecorated_smoothed_pwdb));
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ ("RSSI_LEVEL = %d\n", p_ra->ratr_state));
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ ("PreState = %d, CurState = %d\n",
+ p_ra->pre_ratr_state, p_ra->ratr_state));
+
+ rtlpriv->cfg->ops->update_rate_mask(hw,
+ p_ra->ratr_state);
+
+ p_ra->pre_ratr_state = p_ra->ratr_state;
+ }
+ }
+}
+
+static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+ dm_pstable.pre_ccastate = CCA_MAX;
+ dm_pstable.cur_ccasate = CCA_MAX;
+ dm_pstable.pre_rfstate = RF_MAX;
+ dm_pstable.cur_rfstate = RF_MAX;
+ dm_pstable.rssi_val_min = 0;
+}
+
+static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (dm_pstable.rssi_val_min != 0) {
+ if (dm_pstable.pre_ccastate == CCA_2R) {
+ if (dm_pstable.rssi_val_min >= 35)
+ dm_pstable.cur_ccasate = CCA_1R;
+ else
+ dm_pstable.cur_ccasate = CCA_2R;
+ } else {
+ if (dm_pstable.rssi_val_min <= 30)
+ dm_pstable.cur_ccasate = CCA_2R;
+ else
+ dm_pstable.cur_ccasate = CCA_1R;
+ }
+ } else {
+ dm_pstable.cur_ccasate = CCA_MAX;
+ }
+
+ if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) {
+ if (dm_pstable.cur_ccasate == CCA_1R) {
+ if (get_rf_type(rtlphy) == RF_2T2R) {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x13);
+ rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20);
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x23);
+ rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c);
+ }
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0,
+ 0x33);
+ rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63);
+ }
+ dm_pstable.pre_ccastate = dm_pstable.cur_ccasate;
+ }
+
+ RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n",
+ (dm_pstable.cur_ccasate ==
+ 0) ? "1RCCA" : "2RCCA"));
+}
+
+void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
+{
+ static u8 initialize;
+ static u32 reg_874, reg_c70, reg_85c, reg_a74;
+
+ if (initialize == 0) {
+ reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+ MASKDWORD) & 0x1CC000) >> 14;
+
+ reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
+ MASKDWORD) & BIT(3)) >> 3;
+
+ reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+ MASKDWORD) & 0xFF000000) >> 24;
+
+ reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12;
+
+ initialize = 1;
+ }
+
+ if (!bforce_in_normal) {
+ if (dm_pstable.rssi_val_min != 0) {
+ if (dm_pstable.pre_rfstate == RF_NORMAL) {
+ if (dm_pstable.rssi_val_min >= 30)
+ dm_pstable.cur_rfstate = RF_SAVE;
+ else
+ dm_pstable.cur_rfstate = RF_NORMAL;
+ } else {
+ if (dm_pstable.rssi_val_min <= 25)
+ dm_pstable.cur_rfstate = RF_NORMAL;
+ else
+ dm_pstable.cur_rfstate = RF_SAVE;
+ }
+ } else {
+ dm_pstable.cur_rfstate = RF_MAX;
+ }
+ } else {
+ dm_pstable.cur_rfstate = RF_NORMAL;
+ }
+
+ if (dm_pstable.pre_rfstate != dm_pstable.cur_rfstate) {
+ if (dm_pstable.cur_rfstate == RF_SAVE) {
+ rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+ 0x1C0000, 0x2);
+ rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0);
+ rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+ 0xFF000000, 0x63);
+ rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+ 0xC000, 0x2);
+ rtl_set_bbreg(hw, 0xa74, 0xF000, 0x3);
+ rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
+ rtl_set_bbreg(hw, 0x818, BIT(28), 0x1);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+ 0x1CC000, reg_874);
+ rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3),
+ reg_c70);
+ rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000,
+ reg_85c);
+ rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74);
+ rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
+ }
+
+ dm_pstable.pre_rfstate = dm_pstable.cur_rfstate;
+ }
+}
+
+static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (((mac->link_state == MAC80211_NOLINK)) &&
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+ dm_pstable.rssi_val_min = 0;
+ RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+ ("Not connected to any\n"));
+ }
+
+ if (mac->link_state == MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ dm_pstable.rssi_val_min =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+ ("AP Client PWDB = 0x%lx\n",
+ dm_pstable.rssi_val_min));
+ } else {
+ dm_pstable.rssi_val_min =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+ ("STA Default Port PWDB = 0x%lx\n",
+ dm_pstable.rssi_val_min));
+ }
+ } else {
+ dm_pstable.rssi_val_min =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+ RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+ ("AP Ext Port PWDB = 0x%lx\n",
+ dm_pstable.rssi_val_min));
+ }
+
+ if (IS_92C_SERIAL(rtlhal->version))
+ rtl92c_dm_1r_cca(hw);
+}
+
+void rtl92c_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtl92c_dm_diginit(hw);
+ rtl92c_dm_init_dynamic_txpower(hw);
+ rtl92c_dm_init_edca_turbo(hw);
+ rtl92c_dm_init_rate_adaptive_mask(hw);
+ rtl92c_dm_initialize_txpower_tracking(hw);
+ rtl92c_dm_init_dynamic_bb_powersaving(hw);
+}
+
+void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool b_fw_current_inpsmode = false;
+ bool b_fw_ps_awake = true;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *) (&b_fw_current_inpsmode));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+ (u8 *) (&b_fw_ps_awake));
+
+ if ((ppsc->rfpwr_state == ERFON) && ((!b_fw_current_inpsmode) &&
+ b_fw_ps_awake)
+ && (!ppsc->rfchange_inprogress)) {
+ rtl92c_dm_pwdb_monitor(hw);
+ rtl92c_dm_dig(hw);
+ rtl92c_dm_false_alarm_counter_statistics(hw);
+ rtl92c_dm_dynamic_bb_powersaving(hw);
+ rtl92c_dm_dynamic_txpower(hw);
+ rtl92c_dm_check_txpower_tracking(hw);
+ rtl92c_dm_refresh_rate_adaptive_mask(hw);
+ rtl92c_dm_check_edca_turbo(hw);
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
new file mode 100644
index 000000000000..463439e4074c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_DM_H__
+#define __RTL92C_DM_H__
+
+#define HAL_DM_DIG_DISABLE BIT(0)
+#define HAL_DM_HIPWR_DISABLE BIT(1)
+
+#define OFDM_TABLE_LENGTH 37
+#define CCK_TABLE_LENGTH 33
+
+#define OFDM_TABLE_SIZE 37
+#define CCK_TABLE_SIZE 33
+
+#define BW_AUTO_SWITCH_HIGH_LOW 25
+#define BW_AUTO_SWITCH_LOW_HIGH 30
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+
+#define DM_FALSEALARM_THRESH_LOW 400
+#define DM_FALSEALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1e
+
+#define DM_DIG_FA_UPPER 0x32
+#define DM_DIG_FA_LOWER 0x20
+#define DM_DIG_FA_TH0 0x20
+#define DM_DIG_FA_TH1 0x100
+#define DM_DIG_FA_TH2 0x200
+
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+#define RXPATHSELECTION_SS_TH_lOW 30
+#define RXPATHSELECTION_DIFF_TH 18
+
+#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
+
+#define CTS2SELF_THVAL 30
+#define REGC38_TH 20
+
+#define WAIOTTHVal 25
+
+#define TXHIGHPWRLEVEL_NORMAL 0
+#define TXHIGHPWRLEVEL_LEVEL1 1
+#define TXHIGHPWRLEVEL_LEVEL2 2
+#define TXHIGHPWRLEVEL_BT1 3
+#define TXHIGHPWRLEVEL_BT2 4
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+
+struct ps_t {
+ u8 pre_ccastate;
+ u8 cur_ccasate;
+ u8 pre_rfstate;
+ u8 cur_rfstate;
+ long rssi_val_min;
+};
+
+struct dig_t {
+ u8 dig_enable_flag;
+ u8 dig_ext_port_stage;
+ u32 rssi_lowthresh;
+ u32 rssi_highthresh;
+ u32 fa_lowthresh;
+ u32 fa_highthresh;
+ u8 cursta_connectctate;
+ u8 presta_connectstate;
+ u8 curmultista_connectstate;
+ u8 pre_igvalue;
+ u8 cur_igvalue;
+ char backoff_val;
+ char backoff_val_range_max;
+ char backoff_val_range_min;
+ u8 rx_gain_range_max;
+ u8 rx_gain_range_min;
+ u8 rssi_val_min;
+ u8 pre_cck_pd_state;
+ u8 cur_cck_pd_state;
+ u8 pre_cck_fa_state;
+ u8 cur_cck_fa_state;
+ u8 pre_ccastate;
+ u8 cur_ccasate;
+};
+
+struct swat_t {
+ u8 failure_cnt;
+ u8 try_flag;
+ u8 stop_trying;
+ long pre_rssi;
+ long trying_threshold;
+ u8 cur_antenna;
+ u8 pre_antenna;
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+ DIG_TYPE_THRESH_HIGH = 0,
+ DIG_TYPE_THRESH_LOW = 1,
+ DIG_TYPE_BACKOFF = 2,
+ DIG_TYPE_RX_GAIN_MIN = 3,
+ DIG_TYPE_RX_GAIN_MAX = 4,
+ DIG_TYPE_ENABLE = 5,
+ DIG_TYPE_DISABLE = 6,
+ DIG_OP_TYPE_MAX
+};
+
+enum tag_cck_packet_detection_threshold_type_definition {
+ CCK_PD_STAGE_LowRssi = 0,
+ CCK_PD_STAGE_HighRssi = 1,
+ CCK_FA_STAGE_Low = 2,
+ CCK_FA_STAGE_High = 3,
+ CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_1r_cca_e {
+ CCA_1R = 0,
+ CCA_2R = 1,
+ CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+ RF_SAVE = 0,
+ RF_NORMAL = 1,
+ RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+ ANS_ANTENNA_B = 1,
+ ANS_ANTENNA_A = 2,
+ ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_MULTISTA_DISCONNECT = 3,
+ DIG_MULTISTA_CONNECT = 4,
+ DIG_CONNECT_MAX
+};
+
+extern struct dig_t dm_digtable;
+void rtl92c_dm_init(struct ieee80211_hw *hw);
+void rtl92c_dm_watchdog(struct ieee80211_hw *hw);
+void rtl92c_dm_write_dig(struct ieee80211_hw *hw);
+void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/fw.c
new file mode 100644
index 000000000000..11dd22b987e7
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/fw.c
@@ -0,0 +1,804 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/firmware.h>
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+#include "table.h"
+
+static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
+ u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ if (enable)
+ value32 |= MCUFWDL_EN;
+ else
+ value32 &= ~MCUFWDL_EN;
+ rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+ } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
+ u8 tmp;
+ if (enable) {
+
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
+ tmp | 0x04);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+ } else {
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+ }
+ }
+}
+
+static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
+ const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 blockSize = sizeof(u32);
+ u8 *bufferPtr = (u8 *) buffer;
+ u32 *pu4BytePtr = (u32 *) buffer;
+ u32 i, offset, blockCount, remainSize;
+
+ blockCount = size / blockSize;
+ remainSize = size % blockSize;
+
+ for (i = 0; i < blockCount; i++) {
+ offset = i * blockSize;
+ rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+ *(pu4BytePtr + i));
+ }
+
+ if (remainSize) {
+ offset = blockCount * blockSize;
+ bufferPtr += offset;
+ for (i = 0; i < remainSize; i++) {
+ rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
+ offset + i), *(bufferPtr + i));
+ }
+ }
+}
+
+static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
+ u32 page, const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value8;
+ u8 u8page = (u8) (page & 0x07);
+
+ value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+ rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+ _rtl92c_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+ u32 fwlen = *pfwlen;
+ u8 remain = (u8) (fwlen % 4);
+
+ remain = (remain == 0) ? 0 : (4 - remain);
+
+ while (remain > 0) {
+ pfwbuf[fwlen] = 0;
+ fwlen++;
+ remain--;
+ }
+
+ *pfwlen = fwlen;
+}
+
+static void _rtl92c_write_fw(struct ieee80211_hw *hw,
+ enum version_8192c version, u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool is_version_b;
+ u8 *bufferPtr = (u8 *) buffer;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
+
+ is_version_b = IS_CHIP_VER_B(version);
+ if (is_version_b) {
+ u32 pageNums, remainSize;
+ u32 page, offset;
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
+ _rtl92c_fill_dummy(bufferPtr, &size);
+
+ pageNums = size / FW_8192C_PAGE_SIZE;
+ remainSize = size % FW_8192C_PAGE_SIZE;
+
+ if (pageNums > 4) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Page numbers should not greater then 4\n"));
+ }
+
+ for (page = 0; page < pageNums; page++) {
+ offset = page * FW_8192C_PAGE_SIZE;
+ _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
+ FW_8192C_PAGE_SIZE);
+ }
+
+ if (remainSize) {
+ offset = pageNums * FW_8192C_PAGE_SIZE;
+ page = pageNums;
+ _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
+ remainSize);
+ }
+ } else {
+ _rtl92c_fw_block_write(hw, buffer, size);
+ }
+}
+
+static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int err = -EIO;
+ u32 counter = 0;
+ u32 value32;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+ (!(value32 & FWDL_ChkSum_rpt)));
+
+ if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+ value32));
+ goto exit;
+ }
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
+
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ value32 |= MCUFWDL_RDY;
+ value32 &= ~WINTINI_RDY;
+ rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+ counter = 0;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ if (value32 & WINTINI_RDY) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ ("Polling FW ready success!!"
+ " REG_MCUFWDL:0x%08x .\n",
+ value32));
+ err = 0;
+ goto exit;
+ }
+
+ mdelay(FW_8192C_POLLING_DELAY);
+
+ } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
+
+exit:
+ return err;
+}
+
+int rtl92c_download_fw(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl92c_firmware_header *pfwheader;
+ u8 *pfwdata;
+ u32 fwsize;
+ int err;
+ enum version_8192c version = rtlhal->version;
+
+ const struct firmware *firmware = NULL;
+
+ err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to request firmware!\n"));
+ return 1;
+ }
+
+ if (firmware->size > 0x4000) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Firmware is too big!\n"));
+ release_firmware(firmware);
+ return 1;
+ }
+
+ memcpy(rtlhal->pfirmware, firmware->data, firmware->size);
+ fwsize = firmware->size;
+ release_firmware(firmware);
+
+ pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+ pfwdata = (u8 *) rtlhal->pfirmware;
+
+ if (IS_FW_HEADER_EXIST(pfwheader)) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
+ pfwheader->version, pfwheader->signature,
+ (uint)sizeof(struct rtl92c_firmware_header)));
+
+ pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+ fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+ }
+
+ _rtl92c_enable_fw_download(hw, true);
+ _rtl92c_write_fw(hw, version, pfwdata, fwsize);
+ _rtl92c_enable_fw_download(hw, false);
+
+ err = _rtl92c_fw_free_to_go(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Firmware is not ready to run!\n"));
+ } else {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ ("Firmware is ready to run!\n"));
+ }
+
+ return 0;
+}
+
+static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 val_hmetfr, val_mcutst_1;
+ bool result = false;
+
+ val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+ val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
+
+ if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
+ result = true;
+ return result;
+}
+
+static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 boxnum;
+ u16 box_reg, box_extreg;
+ u8 u1b_tmp;
+ bool isfw_read = false;
+ u8 buf_index;
+ bool bwrite_sucess = false;
+ u8 wait_h2c_limmit = 100;
+ u8 wait_writeh2c_limmit = 100;
+ u8 boxcontent[4], boxextcontent[2];
+ u32 h2c_waitcounter = 0;
+ unsigned long flag;
+ u8 idx;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
+
+ while (true) {
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ if (rtlhal->b_h2c_setinprogress) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("H2C set in progress! Wait to set.."
+ "element_id(%d).\n", element_id));
+
+ while (rtlhal->b_h2c_setinprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+ flag);
+ h2c_waitcounter++;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Wait 100 us (%d times)...\n",
+ h2c_waitcounter));
+ udelay(100);
+
+ if (h2c_waitcounter > 1000)
+ return;
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+ flag);
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ } else {
+ rtlhal->b_h2c_setinprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ break;
+ }
+ }
+
+ while (!bwrite_sucess) {
+ wait_writeh2c_limmit--;
+ if (wait_writeh2c_limmit == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Write H2C fail because no trigger "
+ "for FW INT!\n"));
+ break;
+ }
+
+ boxnum = rtlhal->last_hmeboxnum;
+ switch (boxnum) {
+ case 0:
+ box_reg = REG_HMEBOX_0;
+ box_extreg = REG_HMEBOX_EXT_0;
+ break;
+ case 1:
+ box_reg = REG_HMEBOX_1;
+ box_extreg = REG_HMEBOX_EXT_1;
+ break;
+ case 2:
+ box_reg = REG_HMEBOX_2;
+ box_extreg = REG_HMEBOX_EXT_2;
+ break;
+ case 3:
+ box_reg = REG_HMEBOX_3;
+ box_extreg = REG_HMEBOX_EXT_3;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
+ while (!isfw_read) {
+
+ wait_h2c_limmit--;
+ if (wait_h2c_limmit == 0) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Wating too long for FW read "
+ "clear HMEBox(%d)!\n", boxnum));
+ break;
+ }
+
+ udelay(10);
+
+ isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
+ u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Wating for FW read clear HMEBox(%d)!!! "
+ "0x1BF = %2x\n", boxnum, u1b_tmp));
+ }
+
+ if (!isfw_read) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Write H2C register BOX[%d] fail!!!!! "
+ "Fw do not read.\n", boxnum));
+ break;
+ }
+
+ memset(boxcontent, 0, sizeof(boxcontent));
+ memset(boxextcontent, 0, sizeof(boxextcontent));
+ boxcontent[0] = element_id;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Write element_id box_reg(%4x) = %2x\n",
+ box_reg, element_id));
+
+ switch (cmd_len) {
+ case 1:
+ boxcontent[0] &= ~(BIT(7));
+ memcpy((u8 *) (boxcontent) + 1,
+ p_cmdbuffer + buf_index, 1);
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ case 2:
+ boxcontent[0] &= ~(BIT(7));
+ memcpy((u8 *) (boxcontent) + 1,
+ p_cmdbuffer + buf_index, 2);
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ case 3:
+ boxcontent[0] &= ~(BIT(7));
+ memcpy((u8 *) (boxcontent) + 1,
+ p_cmdbuffer + buf_index, 3);
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ case 4:
+ boxcontent[0] |= (BIT(7));
+ memcpy((u8 *) (boxextcontent),
+ p_cmdbuffer + buf_index, 2);
+ memcpy((u8 *) (boxcontent) + 1,
+ p_cmdbuffer + buf_index + 2, 2);
+
+ for (idx = 0; idx < 2; idx++) {
+ rtl_write_byte(rtlpriv, box_extreg + idx,
+ boxextcontent[idx]);
+ }
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ case 5:
+ boxcontent[0] |= (BIT(7));
+ memcpy((u8 *) (boxextcontent),
+ p_cmdbuffer + buf_index, 2);
+ memcpy((u8 *) (boxcontent) + 1,
+ p_cmdbuffer + buf_index + 2, 3);
+
+ for (idx = 0; idx < 2; idx++) {
+ rtl_write_byte(rtlpriv, box_extreg + idx,
+ boxextcontent[idx]);
+ }
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxcontent[idx]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ bwrite_sucess = true;
+
+ rtlhal->last_hmeboxnum = boxnum + 1;
+ if (rtlhal->last_hmeboxnum == 4)
+ rtlhal->last_hmeboxnum = 0;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("pHalData->last_hmeboxnum = %d\n",
+ rtlhal->last_hmeboxnum));
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ rtlhal->b_h2c_setinprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
+}
+
+void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 tmp_cmdbuf[2];
+
+ if (rtlhal->bfw_ready == false) {
+ RT_ASSERT(false, ("return H2C cmd because of Fw "
+ "download fail!!!\n"));
+ return;
+ }
+
+ memset(tmp_cmdbuf, 0, 8);
+ memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
+ _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
+
+ return;
+}
+
+void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
+{
+ u8 u1b_tmp;
+ u8 delay = 100;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+
+ while (u1b_tmp & BIT(2)) {
+ delay--;
+ if (delay == 0) {
+ RT_ASSERT(false, ("8051 reset fail.\n"));
+ break;
+ }
+ udelay(50);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ }
+}
+
+void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1_h2c_set_pwrmode[3] = {0};
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
+
+ SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+ SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
+ ppsc->reg_max_lps_awakeintvl);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
+ u1_h2c_set_pwrmode, 3);
+ rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
+
+}
+
+static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ u8 own;
+ unsigned long flags;
+ struct sk_buff *pskb = NULL;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+
+#define BEACON_PG 0 /*->1*/
+#define PSPOLL_PG 2
+#define NULL_PG 3
+#define PROBERSP_PG 4 /*->5*/
+
+#define TOTAL_RESERVED_PKT_LEN 768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+ /* page 0 beacon */
+ 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 1 beacon */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 2 ps-poll */
+ 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 3 null */
+ 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 4 probe_resp */
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 5 probe_resp */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct sk_buff *skb = NULL;
+
+ u32 totalpacketlen;
+ bool rtstatus;
+ u8 u1RsvdPageLoc[3] = {0};
+ bool b_dlok = false;
+
+ u8 *beacon;
+ u8 *p_pspoll;
+ u8 *nullfunc;
+ u8 *p_probersp;
+ /*---------------------------------------------------------
+ (1) beacon
+ ---------------------------------------------------------*/
+ beacon = &reserved_page_packet[BEACON_PG * 128];
+ SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+ /*-------------------------------------------------------
+ (2) ps-poll
+ --------------------------------------------------------*/
+ p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+ SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+ SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+ SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+ /*--------------------------------------------------------
+ (3) null data
+ ---------------------------------------------------------*/
+ nullfunc = &reserved_page_packet[NULL_PG * 128];
+ SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+ SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+ /*---------------------------------------------------------
+ (4) probe response
+ ----------------------------------------------------------*/
+ p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+ SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+ SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+
+ totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ &reserved_page_packet[0], totalpacketlen);
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ u1RsvdPageLoc, 3);
+
+
+ skb = dev_alloc_skb(totalpacketlen);
+ memcpy((u8 *) skb_put(skb, totalpacketlen),
+ &reserved_page_packet, totalpacketlen);
+
+ rtstatus = _rtl92c_cmd_send_packet(hw, skb);
+
+ if (rtstatus)
+ b_dlok = true;
+
+ if (b_dlok) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Set RSVD page location to Fw.\n"));
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "H2C_RSVDPAGE:\n",
+ u1RsvdPageLoc, 3);
+ rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
+ sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+ } else
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
+}
+
+void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+ u8 u1_joinbssrpt_parm[1] = {0};
+
+ SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+ rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/fw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/fw.h
new file mode 100644
index 000000000000..3db33bd14666
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/fw.h
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C__FW__H__
+#define __RTL92C__FW__H__
+
+#define FW_8192C_SIZE 0x3000
+#define FW_8192C_START_ADDRESS 0x1000
+#define FW_8192C_END_ADDRESS 0x3FFF
+#define FW_8192C_PAGE_SIZE 4096
+#define FW_8192C_POLLING_DELAY 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT 100
+
+#define IS_FW_HEADER_EXIST(_pfwhdr) \
+ ((_pfwhdr->signature&0xFFF0) == 0x92C0 ||\
+ (_pfwhdr->signature&0xFFF0) == 0x88C0)
+
+struct rtl92c_firmware_header {
+ u16 signature;
+ u8 category;
+ u8 function;
+ u16 version;
+ u8 subversion;
+ u8 rsvd1;
+ u8 month;
+ u8 date;
+ u8 hour;
+ u8 minute;
+ u16 ramcodeSize;
+ u16 rsvd2;
+ u32 svnindex;
+ u32 rsvd3;
+ u32 rsvd4;
+ u32 rsvd5;
+};
+
+enum rtl8192c_h2c_cmd {
+ H2C_AP_OFFLOAD = 0,
+ H2C_SETPWRMODE = 1,
+ H2C_JOINBSSRPT = 2,
+ H2C_RSVDPAGE = 3,
+ H2C_RSSI_REPORT = 5,
+ H2C_RA_MASK = 6,
+ MAX_H2CCMD
+};
+
+#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+int rtl92c_download_fw(struct ieee80211_hw *hw);
+void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer);
+void rtl92c_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
new file mode 100644
index 000000000000..1c41a0c93506
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -0,0 +1,2162 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+
+#define LLT_CONFIG 5
+
+static void _rtl92ce_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+ u8 set_bits, u8 clear_bits)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpci->reg_bcn_ctrl_val |= set_bits;
+ rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl92ce_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl92ce_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte |= BIT(0);
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl92ce_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl92ce_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl92ce_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR:
+ *((u32 *) (val)) = rtlpci->receive_config;
+ break;
+ case HW_VAR_RF_STATE:
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ case HW_VAR_FWLPS_RF_ON:{
+ enum rf_pwrstate rfState;
+ u32 val_rcr;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw,
+ HW_VAR_RF_STATE,
+ (u8 *) (&rfState));
+ if (rfState == ERFOFF) {
+ *((bool *) (val)) = true;
+ } else {
+ val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ val_rcr &= 0x00070000;
+ if (val_rcr)
+ *((bool *) (val)) = false;
+ else
+ *((bool *) (val)) = true;
+ }
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS:
+ *((bool *) (val)) = ppsc->b_fw_current_inpsmode;
+ break;
+ case HW_VAR_CORRECT_TSF:{
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ *((u64 *) (val)) = tsf;
+
+ break;
+ }
+ case HW_VAR_MGT_FILTER:
+ *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0);
+ break;
+ case HW_VAR_CTRL_FILTER:
+ *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1);
+ break;
+ case HW_VAR_DATA_FILTER:
+ *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+}
+
+void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 idx;
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:{
+ for (idx = 0; idx < ETH_ALEN; idx++) {
+ rtl_write_byte(rtlpriv, (REG_MACID + idx),
+ val[idx]);
+ }
+ break;
+ }
+ case HW_VAR_BASIC_RATE:{
+ u16 b_rate_cfg = ((u16 *) val)[0];
+ u8 rate_index = 0;
+ b_rate_cfg = b_rate_cfg & 0x15f;
+ b_rate_cfg |= 0x01;
+ rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, REG_RRSR + 1,
+ (b_rate_cfg >> 8)&0xff);
+ while (b_rate_cfg > 0x1) {
+ b_rate_cfg = (b_rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL,
+ rate_index);
+ break;
+ }
+ case HW_VAR_BSSID:{
+ for (idx = 0; idx < ETH_ALEN; idx++) {
+ rtl_write_byte(rtlpriv, (REG_BSSID + idx),
+ val[idx]);
+ }
+ break;
+ }
+ case HW_VAR_SIFS:{
+ rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+ rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+ if (!mac->ht_enable)
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+ 0x0e0e);
+ else
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+ *((u16 *) val));
+ break;
+ }
+ case HW_VAR_SLOT_TIME:{
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("HW_VAR_SLOT_TIME %x\n", val[0]));
+
+ rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *) (&e_aci));
+ }
+ break;
+ }
+ case HW_VAR_ACK_PREAMBLE:{
+ u8 reg_tmp;
+ u8 short_preamble = (bool) (*(u8 *) val);
+ reg_tmp = (mac->cur_40_prime_sc) << 5;
+ if (short_preamble)
+ reg_tmp |= 0x80;
+
+ rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp);
+ break;
+ }
+ case HW_VAR_AMPDU_MIN_SPACE:{
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *((u8 *) val);
+ if (min_spacing_to_set <= 7) {
+ sec_min_space = 0;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+
+ mac->min_space_cfg = ((mac->min_space_cfg &
+ 0xf8) |
+ min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break;
+ }
+ case HW_VAR_SHORTGI_DENSITY:{
+ u8 density_to_set;
+
+ density_to_set = *((u8 *) val);
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+
+ break;
+ }
+ case HW_VAR_AMPDU_FACTOR:{
+ u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+
+ u8 factor_toset;
+ u8 *p_regtoset = NULL;
+ u8 index = 0;
+
+ p_regtoset = regtoset_normal;
+
+ factor_toset = *((u8 *) val);
+ if (factor_toset <= 3) {
+ factor_toset = (1 << (factor_toset + 2));
+ if (factor_toset > 0xf)
+ factor_toset = 0xf;
+
+ for (index = 0; index < 4; index++) {
+ if ((p_regtoset[index] & 0xf0) >
+ (factor_toset << 4))
+ p_regtoset[index] =
+ (p_regtoset[index] & 0x0f) |
+ (factor_toset << 4);
+
+ if ((p_regtoset[index] & 0x0f) >
+ factor_toset)
+ p_regtoset[index] =
+ (p_regtoset[index] & 0xf0) |
+ (factor_toset);
+
+ rtl_write_byte(rtlpriv,
+ (REG_AGGLEN_LMT + index),
+ p_regtoset[index]);
+
+ }
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_FACTOR: %#x\n",
+ factor_toset));
+ }
+ break;
+ }
+ case HW_VAR_AC_PARAM:{
+ u8 e_aci = *((u8 *) val);
+ u32 u4b_ac_param = 0;
+
+ u4b_ac_param |= (u32) mac->ac[e_aci].aifs;
+ u4b_ac_param |= ((u32) mac->ac[e_aci].cw_min
+ & 0xF) << AC_PARAM_ECW_MIN_OFFSET;
+ u4b_ac_param |= ((u32) mac->ac[e_aci].cw_max &
+ 0xF) << AC_PARAM_ECW_MAX_OFFSET;
+ u4b_ac_param |= (u32) mac->ac[e_aci].tx_op
+ << AC_PARAM_TXOP_LIMIT_OFFSET;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("queue:%x, ac_param:%x\n", e_aci,
+ u4b_ac_param));
+
+ switch (e_aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM,
+ u4b_ac_param);
+ break;
+ case AC0_BE:
+ rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM,
+ u4b_ac_param);
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM,
+ u4b_ac_param);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM,
+ u4b_ac_param);
+ break;
+ default:
+ RT_ASSERT(false,
+ ("SetHwReg8185(): invalid aci: %d !\n",
+ e_aci));
+ break;
+ }
+
+ if (rtlpci->acm_method != eAcmWay2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_ACM_CTRL,
+ (u8 *) (&e_aci));
+ break;
+ }
+ case HW_VAR_ACM_CTRL:{
+ u8 e_aci = *((u8 *) val);
+ union aci_aifsn *p_aci_aifsn =
+ (union aci_aifsn *)(&(mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+ acm_ctrl =
+ acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= AcmHw_BeqEn;
+ break;
+ case AC2_VI:
+ acm_ctrl |= AcmHw_ViqEn;
+ break;
+ case AC3_VO:
+ acm_ctrl |= AcmHw_VoqEn;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("HW_VAR_ACM_CTRL acm set "
+ "failed: eACI is %d\n", acm));
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~AcmHw_ViqEn);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ ("SetHwReg8190pci(): [HW_VAR_ACM_CTRL] "
+ "Write 0x%X\n", acm_ctrl));
+ rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+ break;
+ }
+ case HW_VAR_RCR:{
+ rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]);
+ rtlpci->receive_config = ((u32 *) (val))[0];
+ break;
+ }
+ case HW_VAR_RETRY_LIMIT:{
+ u8 retry_limit = ((u8 *) (val))[0];
+
+ rtl_write_word(rtlpriv, REG_RL,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break;
+ }
+ case HW_VAR_DUAL_TSF_RST:
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+ break;
+ case HW_VAR_EFUSE_BYTES:
+ rtlefuse->efuse_usedbytes = *((u16 *) val);
+ break;
+ case HW_VAR_EFUSE_USAGE:
+ rtlefuse->efuse_usedpercentage = *((u8 *) val);
+ break;
+ case HW_VAR_IO_CMD:
+ rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val));
+ break;
+ case HW_VAR_WPA_CONFIG:
+ rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+ break;
+ case HW_VAR_SET_RPWM:{
+ u8 rpwm_val;
+
+ rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+ udelay(1);
+
+ if (rpwm_val & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ (*(u8 *) val));
+ } else {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ ((*(u8 *) val) | BIT(7)));
+ }
+
+ break;
+ }
+ case HW_VAR_H2C_FW_PWRMODE:{
+ u8 psmode = (*(u8 *) val);
+
+ if ((psmode != FW_PS_ACTIVE_MODE) &&
+ (!IS_92C_SERIAL(rtlhal->version))) {
+ rtl92c_dm_rf_saving(hw, true);
+ }
+
+ rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS:
+ ppsc->b_fw_current_inpsmode = *((bool *) val);
+ break;
+ case HW_VAR_H2C_FW_JOINBSSRPT:{
+ u8 mstatus = (*(u8 *) val);
+ u8 tmp_regcr, tmp_reg422;
+ bool b_recover = false;
+
+ if (mstatus == RT_MEDIA_CONNECT) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID,
+ NULL);
+
+ tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+ rtl_write_byte(rtlpriv, REG_CR + 1,
+ (tmp_regcr | BIT(0)));
+
+ _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(3));
+ _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+ tmp_reg422 =
+ rtl_read_byte(rtlpriv,
+ REG_FWHW_TXQ_CTRL + 2);
+ if (tmp_reg422 & BIT(6))
+ b_recover = true;
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422 & (~BIT(6)));
+
+ rtl92c_set_fw_rsvdpagepkt(hw, 0);
+
+ _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0);
+ _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+ if (b_recover) {
+ rtl_write_byte(rtlpriv,
+ REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422);
+ }
+
+ rtl_write_byte(rtlpriv, REG_CR + 1,
+ (tmp_regcr & ~(BIT(0))));
+ }
+ rtl92c_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+
+ break;
+ }
+ case HW_VAR_AID:{
+ u16 u2btmp;
+ u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+ u2btmp &= 0xC000;
+ rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
+ mac->assoc_id));
+
+ break;
+ }
+ case HW_VAR_CORRECT_TSF:{
+ u8 btype_ibss = ((u8 *) (val))[0];
+
+ /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ?
+ 1 : 0;*/
+
+ if (btype_ibss == true)
+ _rtl92ce_stop_tx_beacon(hw);
+
+ _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+ rtl_write_dword(rtlpriv, REG_TSFTR,
+ (u32) (mac->tsf & 0xffffffff));
+ rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+ (u32) ((mac->tsf >> 32)&0xffffffff));
+
+ _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+ if (btype_ibss == true)
+ _rtl92ce_resume_tx_beacon(hw);
+
+ break;
+
+ }
+ case HW_VAR_MGT_FILTER:
+ rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val);
+ break;
+ case HW_VAR_CTRL_FILTER:
+ rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val);
+ break;
+ case HW_VAR_DATA_FILTER:
+ rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case "
+ "not process\n"));
+ break;
+ }
+}
+
+static bool _rtl92ce_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool status = true;
+ long count = 0;
+ u32 value = _LLT_INIT_ADDR(address) |
+ _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS);
+
+ rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+ do {
+ value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+ break;
+
+ if (count > POLLING_LLT_THRESHOLD) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to polling write LLT done at "
+ "address %d!\n", address));
+ status = false;
+ break;
+ }
+ } while (++count);
+
+ return status;
+}
+
+static bool _rtl92ce_llt_table_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned short i;
+ u8 txpktbuf_bndy;
+ u8 maxPage;
+ bool status;
+
+#if LLT_CONFIG == 1
+ maxPage = 255;
+ txpktbuf_bndy = 252;
+#elif LLT_CONFIG == 2
+ maxPage = 127;
+ txpktbuf_bndy = 124;
+#elif LLT_CONFIG == 3
+ maxPage = 255;
+ txpktbuf_bndy = 174;
+#elif LLT_CONFIG == 4
+ maxPage = 255;
+ txpktbuf_bndy = 246;
+#elif LLT_CONFIG == 5
+ maxPage = 255;
+ txpktbuf_bndy = 246;
+#endif
+
+#if LLT_CONFIG == 1
+ rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x1c);
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80a71c1c);
+#elif LLT_CONFIG == 2
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x845B1010);
+#elif LLT_CONFIG == 3
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x84838484);
+#elif LLT_CONFIG == 4
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80bd1c1c);
+#elif LLT_CONFIG == 5
+ rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000);
+
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80b01c29);
+#endif
+
+ rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy));
+ rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_PBP, 0x11);
+ rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+ for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+ status = _rtl92ce_llt_write(hw, i, i + 1);
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl92ce_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+ if (true != status)
+ return status;
+
+ for (i = txpktbuf_bndy; i < maxPage; i++) {
+ status = _rtl92ce_llt_write(hw, i, (i + 1));
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl92ce_llt_write(hw, maxPage, txpktbuf_bndy);
+ if (true != status)
+ return status;
+
+ return true;
+}
+
+static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpci->up_first_time)
+ return;
+
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl92ce_sw_led_on(hw, pLed0);
+ else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+ rtl92ce_sw_led_on(hw, pLed0);
+ else
+ rtl92ce_sw_led_off(hw, pLed0);
+
+}
+
+static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ unsigned char bytetmp;
+ unsigned short wordtmp;
+ u16 retry;
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0);
+ udelay(2);
+
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+ udelay(2);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+ udelay(2);
+
+ retry = 0;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("reg0xec:%x:%x\n",
+ rtl_read_dword(rtlpriv, 0xEC),
+ bytetmp));
+
+ while ((bytetmp & BIT(0)) && retry < 1000) {
+ retry++;
+ udelay(50);
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("reg0xec:%x:%x\n",
+ rtl_read_dword(rtlpriv,
+ 0xEC),
+ bytetmp));
+ udelay(50);
+ }
+
+ rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x1012);
+
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82);
+ udelay(2);
+
+ rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+
+ if (_rtl92ce_llt_table_init(hw) == false)
+ return false;;
+
+ rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+ rtl_write_byte(rtlpriv, REG_HISRE, 0xff);
+
+ rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff);
+
+ wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+ wordtmp &= 0xf;
+ wordtmp |= 0xF771;
+ rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+ rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+ rtl_write_byte(rtlpriv, 0x4d0, 0x0);
+
+ rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+ ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+ (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+ (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+ (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+ (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+ (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_HQ_DESA,
+ (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_RX_DESA,
+ (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+ DMA_BIT_MASK(32));
+
+ if (IS_92C_SERIAL(rtlhal->version))
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x77);
+ else
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x22);
+
+ rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6));
+ do {
+ retry++;
+ bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+ } while ((retry < 200) && (bytetmp & BIT(7)));
+
+ _rtl92ce_gen_refresh_led_state(hw);
+
+ rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+
+ return true;;
+}
+
+static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 reg_bw_opmode;
+ u32 reg_ratr, reg_prsr;
+
+ reg_bw_opmode = BW_OPMODE_20MHZ;
+ reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+ RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
+ reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
+
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+
+ rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+
+ rtl_write_byte(rtlpriv, REG_SLOT, 0x09);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0);
+
+ rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80);
+
+ rtl_write_word(rtlpriv, REG_RL, 0x0707);
+
+ rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802);
+
+ rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+
+ rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000);
+ rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504);
+ rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
+ rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
+
+ rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
+
+ rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2);
+
+ rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff);
+
+ rtlpci->reg_bcn_ctrl_val = 0x1f;
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val);
+
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+
+ rtl_write_byte(rtlpriv, REG_PIFS, 0x1C);
+ rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
+
+ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+
+ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+
+ rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
+
+ rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
+
+ rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010);
+ rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010);
+
+ rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010);
+
+ rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010);
+
+ rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff);
+ rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff);
+
+}
+
+static void _rtl92ce_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ rtl_write_byte(rtlpriv, 0x34b, 0x93);
+ rtl_write_word(rtlpriv, 0x350, 0x870c);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+
+ if (ppsc->b_support_backdoor)
+ rtl_write_byte(rtlpriv, 0x349, 0x1b);
+ else
+ rtl_write_byte(rtlpriv, 0x349, 0x03);
+
+ rtl_write_word(rtlpriv, 0x350, 0x2718);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+}
+
+void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm));
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("not open "
+ "hw encryption\n"));
+ return;
+ }
+
+ sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TxUseDK;
+ sec_reg_value |= SCR_RxUseDK;
+ }
+
+ sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+ rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The SECR-value %x\n", sec_reg_value));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+
+}
+
+int rtl92ce_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ static bool iqk_initialized; /* initialized to false */
+ bool rtstatus = true;
+ bool is92c;
+ int err;
+ u8 tmp_u1b;
+
+ rtlpci->being_init_adapter = true;
+ rtlpriv->intf_ops->disable_aspm(hw);
+ rtstatus = _rtl92ce_init_mac(hw);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Init MAC failed\n"));
+ err = 1;
+ return err;
+ }
+
+ err = rtl92c_download_fw(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Failed to download FW. Init HW "
+ "without FW now..\n"));
+ err = 1;
+ rtlhal->bfw_ready = false;
+ return err;
+ } else {
+ rtlhal->bfw_ready = true;
+ }
+
+ rtlhal->last_hmeboxnum = 0;
+ rtl92c_phy_mac_config(hw);
+ rtl92c_phy_bb_config(hw);
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+ rtl92c_phy_rf_config(hw);
+ rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+ _rtl92ce_hw_configure(hw);
+ rtl_cam_reset_all_entry(hw);
+ rtl92ce_enable_hw_security_config(hw);
+ ppsc->rfpwr_state = ERFON;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+ _rtl92ce_enable_aspm_back_door(hw);
+ rtlpriv->intf_ops->enable_aspm(hw);
+ if (ppsc->rfpwr_state == ERFON) {
+ rtl92c_phy_set_rfpath_switch(hw, 1);
+ if (iqk_initialized)
+ rtl92c_phy_iq_calibrate(hw, true);
+ else {
+ rtl92c_phy_iq_calibrate(hw, false);
+ iqk_initialized = true;
+ }
+
+ rtl92c_dm_check_txpower_tracking(hw);
+ rtl92c_phy_lc_calibrate(hw);
+ }
+
+ is92c = IS_92C_SERIAL(rtlhal->version);
+ tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+ if (!(tmp_u1b & BIT(0))) {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("PA BIAS path A\n"));
+ }
+
+ if (!(tmp_u1b & BIT(1)) && is92c) {
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0F, 0x05);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("PA BIAS path B\n"));
+ }
+
+ if (!(tmp_u1b & BIT(4))) {
+ tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+ tmp_u1b &= 0x0F;
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+ udelay(10);
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("under 1.5V\n"));
+ }
+ rtl92c_dm_init(hw);
+ rtlpci->being_init_adapter = false;
+ return err;
+}
+
+static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ enum version_8192c version = VERSION_UNKNOWN;
+ u32 value32;
+
+ value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+ if (value32 & TRP_VAUX_EN) {
+ version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C :
+ VERSION_A_CHIP_88C;
+ } else {
+ version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C :
+ VERSION_B_CHIP_88C;
+ }
+
+ switch (version) {
+ case VERSION_B_CHIP_92C:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Chip Version ID: VERSION_B_CHIP_92C.\n"));
+ break;
+ case VERSION_B_CHIP_88C:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Chip Version ID: VERSION_B_CHIP_88C.\n"));
+ break;
+ case VERSION_A_CHIP_92C:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Chip Version ID: VERSION_A_CHIP_92C.\n"));
+ break;
+ case VERSION_A_CHIP_88C:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Chip Version ID: VERSION_A_CHIP_88C.\n"));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Chip Version ID: Unknown. Bug?\n"));
+ break;
+ }
+
+ switch (version & 0x3) {
+ case CHIP_88C:
+ rtlphy->rf_type = RF_1T1R;
+ break;
+ case CHIP_92C:
+ rtlphy->rf_type = RF_2T2R;
+ break;
+ case CHIP_92C_1T2R:
+ rtlphy->rf_type = RF_1T2R;
+ break;
+ default:
+ rtlphy->rf_type = RF_1T1R;
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("ERROR RF_Type is set!!"));
+ break;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+ "RF_2T2R" : "RF_1T1R"));
+
+ return version;
+}
+
+static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+ bt_msr &= 0xfc;
+
+ if (type == NL80211_IFTYPE_UNSPECIFIED ||
+ type == NL80211_IFTYPE_STATION) {
+ _rtl92ce_stop_tx_beacon(hw);
+ _rtl92ce_enable_bcn_sub_func(hw);
+ } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
+ _rtl92ce_resume_tx_beacon(hw);
+ _rtl92ce_disable_bcn_sub_func(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Set HW_VAR_MEDIA_STATUS: "
+ "No such media status(%x).\n", type));
+ }
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= MSR_NOLINK;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to NO LINK!\n"));
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to Ad Hoc!\n"));
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= MSR_INFRA;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to STA!\n"));
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= MSR_AP;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to AP!\n"));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Network type %d not support!\n", type));
+ return 1;
+ break;
+
+ }
+
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+ rtlpriv->cfg->ops->led_control(hw, ledaction);
+ if ((bt_msr & 0xfc) == MSR_AP)
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+ else
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+ return 0;
+}
+
+static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ u8 filterout_non_associated_bssid = false;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ filterout_non_associated_bssid = true;
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_AP:
+ default:
+ break;
+ }
+
+ if (filterout_non_associated_bssid == true) {
+ reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+ (u8 *) (&reg_rcr));
+ _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4));
+ } else if (filterout_non_associated_bssid == false) {
+ reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+ _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0);
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_RCR, (u8 *) (&reg_rcr));
+ }
+}
+
+int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+ if (_rtl92ce_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+ _rtl92ce_set_check_bssid(hw, type);
+ return 0;
+}
+
+void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ u32 u4b_ac_param;
+
+ rtl92c_dm_init_edca_turbo(hw);
+
+ u4b_ac_param = (u32) mac->ac[aci].aifs;
+ u4b_ac_param |=
+ ((u32) mac->ac[aci].cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET;
+ u4b_ac_param |=
+ ((u32) mac->ac[aci].cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET;
+ u4b_ac_param |= (u32) mac->ac[aci].tx_op << AC_PARAM_TXOP_LIMIT_OFFSET;
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG,
+ ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n",
+ aci, u4b_ac_param, mac->ac[aci].aifs, mac->ac[aci].cw_min,
+ mac->ac[aci].cw_max, mac->ac[aci].tx_op));
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param);
+ break;
+ case AC0_BE:
+ rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param);
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param);
+ break;
+ default:
+ RT_ASSERT(false, ("invalid aci: %d !\n", aci));
+ break;
+ }
+}
+
+void rtl92ce_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+ rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+ rtlpci->irq_enabled = true;
+}
+
+void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
+ rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
+ rtlpci->irq_enabled = false;
+}
+
+static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 u1b_tmp;
+
+ rtlpriv->intf_ops->enable_aspm(hw);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0);
+ if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->bfw_ready)
+ rtl92c_firmware_selfreset(hw);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL);
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 |
+ (u1b_tmp << 8));
+ rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);
+ rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);
+ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10);
+}
+
+void rtl92ce_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+ _rtl92ce_set_media_status(hw, opmode);
+ if (rtlpci->driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ _rtl92ce_poweroff_adapter(hw);
+}
+
+void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ /*
+ * *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
+ * rtl_write_dword(rtlpriv, ISR + 4, *p_intb);
+ */
+}
+
+void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval, atim_window;
+
+ bcn_interval = mac->beacon_interval;
+ atim_window = 2; /*FIX MERGE */
+ rtl92ce_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+ rtl_write_byte(rtlpriv, 0x606, 0x30);
+ rtl92ce_enable_interrupt(hw);
+}
+
+void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+ ("beacon_interval:%d\n", bcn_interval));
+ rtl92ce_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl92ce_enable_interrupt(hw);
+}
+
+void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr));
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+ rtl92ce_disable_interrupt(hw);
+ rtl92ce_enable_interrupt(hw);
+}
+
+static u8 _rtl92c_get_chnl_group(u8 chnl)
+{
+ u8 group;
+
+ if (chnl < 3)
+ group = 0;
+ else if (chnl < 9)
+ group = 1;
+ else
+ group = 2;
+ return group;
+}
+
+static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 rf_path, index, tempval;
+ u16 i;
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ if (!autoload_fail) {
+ rtlefuse->
+ eeprom_chnlarea_txpwr_cck[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i];
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 +
+ i];
+ } else {
+ rtlefuse->
+ eeprom_chnlarea_txpwr_cck[rf_path][i] =
+ EEPROM_DEFAULT_TXPOWERLEVEL;
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
+ EEPROM_DEFAULT_TXPOWERLEVEL;
+ }
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!autoload_fail)
+ tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];
+ else
+ tempval = EEPROM_DEFAULT_HT40_2SDIFF;
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] =
+ (tempval & 0xf);
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] =
+ ((tempval & 0xf0) >> 4);
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path,
+ i,
+ rtlefuse->
+ eeprom_chnlarea_txpwr_cck[rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path]
+ [i]));
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 14; i++) {
+ index = _rtl92c_get_chnl_group((u8) i);
+
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index];
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path][index];
+
+ if ((rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] -
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index])
+ > 0) {
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_1s[rf_path]
+ [index] -
+ rtlefuse->
+ eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path]
+ [index];
+ } else {
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0;
+ }
+ }
+
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
+ "[0x%x / 0x%x / 0x%x]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i]));
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!autoload_fail) {
+ rtlefuse->eeprom_pwrlimit_ht40[i] =
+ hwinfo[EEPROM_TXPWR_GROUP + i];
+ rtlefuse->eeprom_pwrlimit_ht20[i] =
+ hwinfo[EEPROM_TXPWR_GROUP + 3 + i];
+ } else {
+ rtlefuse->eeprom_pwrlimit_ht40[i] = 0;
+ rtlefuse->eeprom_pwrlimit_ht20[i] = 0;
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 14; i++) {
+ index = _rtl92c_get_chnl_group((u8) i);
+
+ if (rf_path == RF90_PATH_A) {
+ rtlefuse->pwrgroup_ht20[rf_path][i] =
+ (rtlefuse->eeprom_pwrlimit_ht20[index]
+ & 0xf);
+ rtlefuse->pwrgroup_ht40[rf_path][i] =
+ (rtlefuse->eeprom_pwrlimit_ht40[index]
+ & 0xf);
+ } else if (rf_path == RF90_PATH_B) {
+ rtlefuse->pwrgroup_ht20[rf_path][i] =
+ ((rtlefuse->eeprom_pwrlimit_ht20[index]
+ & 0xf0) >> 4);
+ rtlefuse->pwrgroup_ht40[rf_path][i] =
+ ((rtlefuse->eeprom_pwrlimit_ht40[index]
+ & 0xf0) >> 4);
+ }
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht20[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht20[rf_path][i]));
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht40[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht40[rf_path][i]));
+ }
+ }
+
+ for (i = 0; i < 14; i++) {
+ index = _rtl92c_get_chnl_group((u8) i);
+
+ if (!autoload_fail)
+ tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
+ else
+ tempval = EEPROM_DEFAULT_HT20_DIFF;
+
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF);
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+
+ if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3))
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0;
+
+ if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3))
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0;
+
+ index = _rtl92c_get_chnl_group((u8) i);
+
+ if (!autoload_fail)
+ tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
+ else
+ tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF;
+
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF);
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+ }
+
+ rtlefuse->legacy_ht_txpowerdiff =
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
+
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]));
+
+ if (!autoload_fail)
+ rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
+ else
+ rtlefuse->eeprom_regulatory = 0;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory));
+
+ if (!autoload_fail) {
+ rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
+ rtlefuse->eeprom_tssi[RF90_PATH_B] = hwinfo[EEPROM_TSSI_B];
+ } else {
+ rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
+ rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ rtlefuse->eeprom_tssi[RF90_PATH_A],
+ rtlefuse->eeprom_tssi[RF90_PATH_B]));
+
+ if (!autoload_fail)
+ tempval = hwinfo[EEPROM_THERMAL_METER];
+ else
+ tempval = EEPROM_DEFAULT_THERMALMETER;
+ rtlefuse->eeprom_thermalmeter = (tempval & 0x1f);
+
+ if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail)
+ rtlefuse->b_apk_thermalmeterignore = true;
+
+ rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter));
+}
+
+static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u16 i, usvalue;
+ u8 hwinfo[HWSET_MAX_SIZE];
+ u16 eeprom_id;
+
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy((void *)hwinfo,
+ (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE);
+ } else if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("RTL819X Not boot from eeprom, check it !!"));
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8190_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("EEPROM ID(%#x) is invalid!!\n", eeprom_id));
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ }
+
+ if (rtlefuse->autoload_failflag == true)
+ return;
+
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr)));
+
+ _rtl92ce_read_txpower_info_from_hwpg(hw,
+ rtlefuse->autoload_failflag,
+ hwinfo);
+
+ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+ rtlefuse->b_txpwr_fromeprom = true;
+ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid));
+
+ if (rtlhal->oem_id == RT_CID_DEFAULT) {
+ switch (rtlefuse->eeprom_oemid) {
+ case EEPROM_CID_DEFAULT:
+ if (rtlefuse->eeprom_did == 0x8176) {
+ if ((rtlefuse->eeprom_svid == 0x103C &&
+ rtlefuse->eeprom_smid == 0x1629))
+ rtlhal->oem_id = RT_CID_819x_HP;
+ else
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ break;
+ case EEPROM_CID_TOSHIBA:
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ break;
+ case EEPROM_CID_QMI:
+ rtlhal->oem_id = RT_CID_819x_QMI;
+ break;
+ case EEPROM_CID_WHQL:
+ default:
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ break;
+
+ }
+ }
+
+}
+
+static void _rtl92ce_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ switch (rtlhal->oem_id) {
+ case RT_CID_819x_HP:
+ pcipriv->ledctl.bled_opendrain = true;
+ break;
+ case RT_CID_819x_Lenovo:
+ case RT_CID_DEFAULT:
+ case RT_CID_TOSHIBA:
+ case RT_CID_CCX:
+ case RT_CID_819x_Acer:
+ case RT_CID_WHQL:
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("RT Customized ID: 0x%02X\n", rtlhal->oem_id));
+}
+
+void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_u1b;
+
+ rtlhal->version = _rtl92ce_read_chip_version(hw);
+ if (get_rf_type(rtlphy) == RF_1T1R)
+ rtlpriv->dm.brfpath_rxenable[0] = true;
+ else
+ rtlpriv->dm.brfpath_rxenable[0] =
+ rtlpriv->dm.brfpath_rxenable[1] = true;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("VersionID = 0x%4x\n",
+ rtlhal->version));
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n"));
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n"));
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ _rtl92ce_read_adapter_info(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n"));
+ }
+
+ _rtl92ce_hal_customized_behavior(hw);
+}
+
+void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ u32 ratr_value = (u32) mac->basic_rates;
+ u8 *p_mcsrate = mac->mcs;
+ u8 ratr_index = 0;
+ u8 b_nmode = mac->ht_enable;
+ u8 mimo_ps = 1;
+ u16 shortgi_rate;
+ u32 tmp_ratr_value;
+ u8 b_curtxbw_40mhz = mac->bw_40;
+ u8 b_curshortgi_40mhz = mac->sgi_40;
+ u8 b_curshortgi_20mhz = mac->sgi_20;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ ratr_value |= EF2BYTE((*(u16 *) (p_mcsrate))) << 12;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ if (ratr_value & 0x0000000c)
+ ratr_value &= 0x0000000d;
+ else
+ ratr_value &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ b_nmode = 1;
+ if (mimo_ps == 0) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
+
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+
+ break;
+ }
+
+ ratr_value &= 0x0FFFFFFF;
+
+ if (b_nmode && ((b_curtxbw_40mhz &&
+ b_curshortgi_40mhz) || (!b_curtxbw_40mhz &&
+ b_curshortgi_20mhz))) {
+
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ }
+
+ rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)));
+}
+
+void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u32 ratr_bitmap = (u32) mac->basic_rates;
+ u8 *p_mcsrate = mac->mcs;
+ u8 ratr_index;
+ u8 b_curtxbw_40mhz = mac->bw_40;
+ u8 b_curshortgi_40mhz = mac->sgi_40;
+ u8 b_curshortgi_20mhz = mac->sgi_20;
+ enum wireless_mode wirelessmode = mac->mode;
+ bool b_shortgi = false;
+ u8 rate_mask[5];
+ u8 macid = 0;
+ u8 mimops = 1;
+
+ ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimops == 0) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (b_curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff015;
+ } else {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (b_curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f0f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f0ff000;
+ else
+ ratr_bitmap &= 0x0f0ff015;
+ } else {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f0f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f0ff000;
+ else
+ ratr_bitmap &= 0x0f0ff005;
+ }
+ }
+ }
+
+ if ((b_curtxbw_40mhz && b_curshortgi_40mhz) ||
+ (!b_curtxbw_40mhz && b_curshortgi_20mhz)) {
+
+ if (macid == 0)
+ b_shortgi = true;
+ else if (macid == 1)
+ b_shortgi = false;
+ }
+ break;
+ default:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f0ff0ff;
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ ("ratr_bitmap :%x\n", ratr_bitmap));
+ *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28));
+ rate_mask[4] = macid | (b_shortgi ? 0x20 : 0x00) | 0x80;
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, "
+ "ratr_val:%x, %x:%x:%x:%x:%x\n",
+ ratr_index, ratr_bitmap,
+ rate_mask[0], rate_mask[1],
+ rate_mask[2], rate_mask[3],
+ rate_mask[4]));
+ rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+}
+
+void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *)&mac->slot_time);
+ if (!mac->ht_enable)
+ sifs_timer = 0x0a0a;
+ else
+ sifs_timer = 0x1010;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+ u8 u1tmp;
+ bool b_actuallyset = false;
+ unsigned long flag;
+
+ if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter))
+ return false;
+
+ if (ppsc->b_swrf_processing)
+ return false;
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ cur_rfstate = ppsc->rfpwr_state;
+
+ if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
+ rtlpriv->intf_ops->disable_aspm(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv,
+ REG_MAC_PINMUX_CFG)&~(BIT(3)));
+
+ u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
+ e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF;
+
+ if ((ppsc->b_hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("GPIOChangeRF - HW Radio ON, RF ON\n"));
+
+ e_rfpowerstate_toset = ERFON;
+ ppsc->b_hwradiooff = false;
+ b_actuallyset = true;
+ } else if ((ppsc->b_hwradiooff == false)
+ && (e_rfpowerstate_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("GPIOChangeRF - HW Radio OFF, RF OFF\n"));
+
+ e_rfpowerstate_toset = ERFOFF;
+ ppsc->b_hwradiooff = true;
+ b_actuallyset = true;
+ }
+
+ if (b_actuallyset) {
+ if (e_rfpowerstate_toset == ERFON) {
+ if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
+ rtlpriv->intf_ops->disable_aspm(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+
+ if (e_rfpowerstate_toset == ERFOFF) {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
+ rtlpriv->intf_ops->enable_aspm(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+ }
+
+ } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
+ rtlpriv->intf_ops->enable_aspm(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ } else {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ *valid = 1;
+ return !ppsc->b_hwradiooff;
+
+}
+
+void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 *macaddr = p_macaddr;
+ u32 entry_id = 0;
+ bool is_pairwise = false;
+
+ static u8 cam_const_addr[4][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+ };
+ static u8 cam_const_broad[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n"));
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case "
+ "not process\n"));
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key_index];
+ entry_id = key_index;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ entry_id = key_index;
+ } else {
+ key_index = PAIRWISE_KEYIDX;
+ entry_id = CAM_PAIRWISE_KEY_POSITION;
+ is_pairwise = true;
+ }
+ }
+
+ if (rtlpriv->sec.key_len[key_index] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("delete one entry\n"));
+ rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY length is %d\n",
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY is %x %x\n",
+ rtlpriv->sec.key_buf[0][0],
+ rtlpriv->sec.key_buf[0][1]));
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("add one entry\n"));
+ if (is_pairwise) {
+ RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD,
+ "Pairwiase Key content :",
+ rtlpriv->sec.pairwise_key,
+ rtlpriv->sec.
+ key_len[PAIRWISE_KEYIDX]);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set Pairwiase key\n"));
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.
+ key_buf[key_index]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set group key\n"));
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw,
+ rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf
+ [entry_id]);
+ }
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+
+ }
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
new file mode 100644
index 000000000000..305c819c8c78
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_HW_H__
+#define __RTL92CE_HW_H__
+
+void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+int rtl92ce_hw_init(struct ieee80211_hw *hw);
+void rtl92ce_card_disable(struct ieee80211_hw *hw);
+void rtl92ce_enable_interrupt(struct ieee80211_hw *hw);
+void rtl92ce_disable_interrupt(struct ieee80211_hw *hw);
+int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw);
+void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
+void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
new file mode 100644
index 000000000000..78a0569208ea
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ rtl_write_byte(rtlpriv,
+ REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6));
+ break;
+ case LED_PIN_LED1:
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->b_ledon = true;
+}
+
+void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg &= 0xf0;
+ if (pcipriv->ledctl.bled_opendrain == true)
+ rtl_write_byte(rtlpriv, REG_LEDCFG2,
+ (ledcfg | BIT(1) | BIT(5) | BIT(6)));
+ else
+ rtl_write_byte(rtlpriv, REG_LEDCFG2,
+ (ledcfg | BIT(3) | BIT(5) | BIT(6)));
+ break;
+ case LED_PIN_LED1:
+ ledcfg &= 0x0f;
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3)));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->b_ledon = false;
+}
+
+void rtl92ce_init_sw_leds(struct ieee80211_hw *hw)
+{
+}
+
+void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw)
+{
+}
+
+void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl92ce_sw_led_on(hw, pLed0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl92ce_sw_led_off(hw, pLed0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl92ce_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+ (ledaction == LED_CTL_TX ||
+ ledaction == LED_CTL_RX ||
+ ledaction == LED_CTL_SITE_SURVEY ||
+ ledaction == LED_CTL_LINK ||
+ ledaction == LED_CTL_NO_LINK ||
+ ledaction == LED_CTL_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n",
+ ledaction));
+ _rtl92ce_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
new file mode 100644
index 000000000000..10da3018f4b7
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_LED_H__
+#define __RTL92CE_LED_H__
+
+void rtl92ce_init_sw_leds(struct ieee80211_hw *hw);
+void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw);
+void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
new file mode 100644
index 000000000000..45044117139a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -0,0 +1,2676 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+
+static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset);
+static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data);
+static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset);
+static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data);
+static u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask);
+static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool _rtl92c_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+ u8 configtype);
+static bool _rtl92c_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype);
+static void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
+static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz,
+ enum swchnlcmd_id cmdid, u32 para1,
+ u32 para2, u32 msdelay);
+static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay);
+static u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ long power_indbm);
+static bool _rtl92c_phy_config_rf_external_pa(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+static long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx);
+u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), "
+ "bitmask(%#x)\n", regaddr,
+ bitmask));
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("BBR MASK=0x%x "
+ "Addr[0x%x]=0x%x\n", bitmask,
+ regaddr, originalvalue));
+
+ return returnvalue;
+
+}
+
+void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask,
+ data));
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask,
+ data));
+
+}
+
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), "
+ "rfpath(%#x), bitmask(%#x)\n",
+ regaddr, rfpath, bitmask));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (rtlphy->rf_mode != RF_OP_BY_FW) {
+ original_value = _rtl92c_phy_rf_serial_read(hw,
+ rfpath, regaddr);
+ } else {
+ original_value = _rtl92c_phy_fw_rf_serial_read(hw,
+ rfpath, regaddr);
+ }
+
+ bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ ("regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x), original_value(%#x)\n",
+ regaddr, rfpath, bitmask, original_value));
+
+ return readback_value;
+}
+
+void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, rfpath));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (rtlphy->rf_mode != RF_OP_BY_FW) {
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = _rtl92c_phy_rf_serial_read(hw,
+ rfpath,
+ regaddr);
+ bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ data =
+ ((original_value & (~bitmask)) |
+ (data << bitshift));
+ }
+
+ _rtl92c_phy_rf_serial_write(hw, rfpath, regaddr, data);
+ } else {
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = _rtl92c_phy_fw_rf_serial_read(hw,
+ rfpath,
+ regaddr);
+ bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ data =
+ ((original_value & (~bitmask)) |
+ (data << bitshift));
+ }
+ _rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
+ }
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), "
+ "bitmask(%#x), data(%#x), "
+ "rfpath(%#x)\n", regaddr,
+ bitmask, data, rfpath));
+}
+
+static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+ RT_ASSERT(false, ("deprecated!\n"));
+ return 0;
+}
+
+static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ RT_ASSERT(false, ("deprecated!\n"));
+}
+
+static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 retvalue;
+
+ offset &= 0x3f;
+ newoffset = offset;
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("return all one\n"));
+ return 0xFFFFFFFF;
+ }
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+ if (rfpath == RF90_PATH_A)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+ tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+ (newoffset << 23) | BLSSIREADEDGE;
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSIREADEDGE));
+ mdelay(1);
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(1);
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong | BLSSIREADEDGE);
+ mdelay(1);
+ if (rfpath == RF90_PATH_A)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == RF90_PATH_B)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+ if (rfpi_enable)
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+ BLSSIREADBACKDATA);
+ else
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+ BLSSIREADBACKDATA);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rflssi_readback,
+ retvalue));
+ return retvalue;
+}
+
+static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ u32 data_and_addr;
+ u32 newoffset;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("stop\n"));
+ return;
+ }
+ offset &= 0x3f;
+ newoffset = offset;
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rf3wire_offset,
+ data_and_addr));
+}
+
+static u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+ return i;
+}
+
+static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw)
+{
+ rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
+ rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022);
+ rtl_set_bbreg(hw, RCCK0_AFESETTING, MASKBYTE3, 0x45);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x23);
+ rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, 0x30, 0x1);
+ rtl_set_bbreg(hw, 0xe74, 0x0c000000, 0x2);
+ rtl_set_bbreg(hw, 0xe78, 0x0c000000, 0x2);
+ rtl_set_bbreg(hw, 0xe7c, 0x0c000000, 0x2);
+ rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2);
+ rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2);
+}
+
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool is92c = IS_92C_SERIAL(rtlhal->version);
+ bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw);
+
+ if (is92c)
+ rtl_write_byte(rtlpriv, 0x14, 0x71);
+ return rtstatus;
+}
+
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw)
+{
+ bool rtstatus = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regval;
+ u32 regvaldw;
+ u8 b_reg_hwparafile = 1;
+
+ _rtl92c_phy_init_bb_rf_register_definition(hw);
+ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+ regval | BIT(13) | BIT(0) | BIT(1));
+ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
+ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+ FEN_BB_GLB_RSTn | FEN_BBRSTB);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+ regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0);
+ rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23));
+ if (b_reg_hwparafile == 1)
+ rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
+ return rtstatus;
+}
+
+bool rtl92c_phy_rf_config(struct ieee80211_hw *hw)
+{
+ return rtl92c_phy_rf6052_config(hw);
+}
+
+static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("==>\n"));
+ rtstatus = _rtl92c_phy_config_bb_with_headerfile(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Write BB Reg Fail!!"));
+ return false;
+ }
+ if (rtlphy->rf_type == RF_1T2R) {
+ _rtl92c_phy_bb_config_1t(hw);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Config to 1T!!\n"));
+ }
+ if (rtlefuse->autoload_failflag == false) {
+ rtlphy->pwrgroup_cnt = 0;
+ rtstatus = _rtl92c_phy_config_bb_with_pgheaderfile(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ }
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("BB_PG Reg Fail!!"));
+ return false;
+ }
+ rtstatus = _rtl92c_phy_config_bb_with_headerfile(hw,
+ BASEBAND_CONFIG_AGC_TAB);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("AGC Table Fail\n"));
+ return false;
+ }
+ rtlphy->bcck_high_power = (bool) (rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ 0x200));
+ return true;
+}
+
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptrarray;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Read Rtl819XMACPHY_Array\n"));
+ arraylength = MAC_2T_ARRAYLENGTH;
+ ptrarray = RTL8192CEMAC_2T_ARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Img:RTL8192CEMAC_2T_ARRAY\n"));
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+ return true;
+}
+
+void rtl92c_phy_config_bb_external_pa(struct ieee80211_hw *hw)
+{
+}
+
+static bool _rtl92c_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ int i;
+ u32 *phy_regarray_table;
+ u32 *agctab_array_table;
+ u16 phy_reg_arraylen, agctab_arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (IS_92C_SERIAL(rtlhal->version)) {
+ agctab_arraylen = AGCTAB_2TARRAYLENGTH;
+ agctab_array_table = RTL8192CEAGCTAB_2TARRAY;
+ phy_reg_arraylen = PHY_REG_2TARRAY_LENGTH;
+ phy_regarray_table = RTL8192CEPHY_REG_2TARRAY;
+ } else {
+ agctab_arraylen = AGCTAB_1TARRAYLENGTH;
+ agctab_array_table = RTL8192CEAGCTAB_1TARRAY;
+ phy_reg_arraylen = PHY_REG_1TARRAY_LENGTH;
+ phy_regarray_table = RTL8192CEPHY_REG_1TARRAY;
+ }
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_reg_arraylen; i = i + 2) {
+ if (phy_regarray_table[i] == 0xfe)
+ mdelay(50);
+ else if (phy_regarray_table[i] == 0xfd)
+ mdelay(5);
+ else if (phy_regarray_table[i] == 0xfc)
+ mdelay(1);
+ else if (phy_regarray_table[i] == 0xfb)
+ udelay(50);
+ else if (phy_regarray_table[i] == 0xfa)
+ udelay(5);
+ else if (phy_regarray_table[i] == 0xf9)
+ udelay(1);
+ rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
+ phy_regarray_table[i + 1]);
+ udelay(1);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("The phy_regarray_table[0] is %x"
+ " Rtl819XPHY_REGArray[1] is %x\n",
+ phy_regarray_table[i],
+ phy_regarray_table[i + 1]));
+ }
+ rtl92c_phy_config_bb_external_pa(hw);
+ } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+ for (i = 0; i < agctab_arraylen; i = i + 2) {
+ rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD,
+ agctab_array_table[i + 1]);
+ udelay(1);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("The agctab_array_table[0] is "
+ "%x Rtl819XPHY_REGArray[1] is %x\n",
+ agctab_array_table[i],
+ agctab_array_table[i + 1]));
+ }
+ }
+ return true;
+}
+
+static void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (regaddr == RTXAGC_A_RATE18_06) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][0]));
+ }
+ if (regaddr == RTXAGC_A_RATE54_24) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][1]));
+ }
+ if (regaddr == RTXAGC_A_CCK1_MCS32) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][6]));
+ }
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][7]));
+ }
+ if (regaddr == RTXAGC_A_MCS03_MCS00) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][2]));
+ }
+ if (regaddr == RTXAGC_A_MCS07_MCS04) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][3]));
+ }
+ if (regaddr == RTXAGC_A_MCS11_MCS08) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][4]));
+ }
+ if (regaddr == RTXAGC_A_MCS15_MCS12) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][5]));
+ }
+ if (regaddr == RTXAGC_B_RATE18_06) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
+ data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][8]));
+ }
+ if (regaddr == RTXAGC_B_RATE54_24) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][9]));
+ }
+
+ if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][14]));
+ }
+
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][15]));
+ }
+
+ if (regaddr == RTXAGC_B_MCS03_MCS00) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][10]));
+ }
+
+ if (regaddr == RTXAGC_B_MCS07_MCS04) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][11]));
+ }
+
+ if (regaddr == RTXAGC_B_MCS11_MCS08) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][12]));
+ }
+
+ if (regaddr == RTXAGC_B_MCS15_MCS12) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
+ data;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+ pwrgroup_cnt][13]));
+
+ rtlphy->pwrgroup_cnt++;
+ }
+}
+
+static bool _rtl92c_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int i;
+ u32 *phy_regarray_table_pg;
+ u16 phy_regarray_pg_len;
+
+ phy_regarray_pg_len = PHY_REG_ARRAY_PGLENGTH;
+ phy_regarray_table_pg = RTL8192CEPHY_REG_ARRAY_PG;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
+ if (phy_regarray_table_pg[i] == 0xfe)
+ mdelay(50);
+ else if (phy_regarray_table_pg[i] == 0xfd)
+ mdelay(5);
+ else if (phy_regarray_table_pg[i] == 0xfc)
+ mdelay(1);
+ else if (phy_regarray_table_pg[i] == 0xfb)
+ udelay(50);
+ else if (phy_regarray_table_pg[i] == 0xfa)
+ udelay(5);
+ else if (phy_regarray_table_pg[i] == 0xf9)
+ udelay(1);
+
+ _rtl92c_store_pwrIndex_diffrate_offset(hw,
+ phy_regarray_table_pg[i],
+ phy_regarray_table_pg[i + 1],
+ phy_regarray_table_pg[i + 2]);
+ }
+ } else {
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ ("configtype != BaseBand_Config_PHY_REG\n"));
+ }
+ return true;
+}
+
+static bool _rtl92c_phy_config_rf_external_pa(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ return true;
+}
+
+bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+
+ int i;
+ bool rtstatus = true;
+ u32 *radioa_array_table;
+ u32 *radiob_array_table;
+ u16 radioa_arraylen, radiob_arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (IS_92C_SERIAL(rtlhal->version)) {
+ radioa_arraylen = RADIOA_2TARRAYLENGTH;
+ radioa_array_table = RTL8192CERADIOA_2TARRAY;
+ radiob_arraylen = RADIOB_2TARRAYLENGTH;
+ radiob_array_table = RTL8192CE_RADIOB_2TARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Radio_A:RTL8192CERADIOA_2TARRAY\n"));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Radio_B:RTL8192CE_RADIOB_2TARRAY\n"));
+ } else {
+ radioa_arraylen = RADIOA_1TARRAYLENGTH;
+ radioa_array_table = RTL8192CE_RADIOA_1TARRAY;
+ radiob_arraylen = RADIOB_1TARRAYLENGTH;
+ radiob_array_table = RTL8192CE_RADIOB_1TARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Radio_A:RTL8192CE_RADIOA_1TARRAY\n"));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Radio_B:RTL8192CE_RADIOB_1TARRAY\n"));
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Radio No %x\n", rfpath));
+ rtstatus = true;
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < radioa_arraylen; i = i + 2) {
+ if (radioa_array_table[i] == 0xfe)
+ mdelay(50);
+ else if (radioa_array_table[i] == 0xfd)
+ mdelay(5);
+ else if (radioa_array_table[i] == 0xfc)
+ mdelay(1);
+ else if (radioa_array_table[i] == 0xfb)
+ udelay(50);
+ else if (radioa_array_table[i] == 0xfa)
+ udelay(5);
+ else if (radioa_array_table[i] == 0xf9)
+ udelay(1);
+ else {
+ rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
+ RFREG_OFFSET_MASK,
+ radioa_array_table[i + 1]);
+ udelay(1);
+ }
+ }
+ _rtl92c_phy_config_rf_external_pa(hw, rfpath);
+ break;
+ case RF90_PATH_B:
+ for (i = 0; i < radiob_arraylen; i = i + 2) {
+ if (radiob_array_table[i] == 0xfe) {
+ mdelay(50);
+ } else if (radiob_array_table[i] == 0xfd)
+ mdelay(5);
+ else if (radiob_array_table[i] == 0xfc)
+ mdelay(1);
+ else if (radiob_array_table[i] == 0xfb)
+ udelay(50);
+ else if (radiob_array_table[i] == 0xfa)
+ udelay(5);
+ else if (radiob_array_table[i] == 0xf9)
+ udelay(1);
+ else {
+ rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
+ RFREG_OFFSET_MASK,
+ radiob_array_table[i + 1]);
+ udelay(1);
+ }
+ }
+ break;
+ case RF90_PATH_C:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ case RF90_PATH_D:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ return true;
+}
+
+void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->default_initialgain[0] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[1] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[2] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[3] =
+ (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Default initial gain (c50=0x%x, "
+ "c58=0x%x, c60=0x%x, c68=0x%x\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]));
+
+ rtlphy->framesync = (u8) rtl_get_bbreg(hw,
+ ROFDM0_RXDETECTOR3, MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw,
+ ROFDM0_RXDETECTOR2, MASKDWORD);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync));
+}
+
+static void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+ RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+ RFPGA0_XB_LSSIPARAMETER;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
+ ROFDM0_XARXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
+ ROFDM0_XBRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
+ ROFDM0_XCRXIQIMBANLANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
+ ROFDM0_XDRXIQIMBALANCE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
+ ROFDM0_XATXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
+ ROFDM0_XBTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
+ ROFDM0_XCTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
+ ROFDM0_XDTXIQIMBALANCE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
+ RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
+ RFPGA0_XB_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
+ RFPGA0_XC_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
+ RFPGA0_XD_LSSIREADBACK;
+
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
+ TRANSCEIVEA_HSPI_READBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
+ TRANSCEIVEB_HSPI_READBACK;
+
+}
+
+void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 txpwr_level;
+ long txpwr_dbm;
+
+ txpwr_level = rtlphy->cur_cck_txpwridx;
+ txpwr_dbm = _rtl92c_phy_txpwr_idx_to_dbm(hw,
+ WIRELESS_MODE_B, txpwr_level);
+ txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
+ rtlefuse->legacy_ht_txpowerdiff;
+ if (_rtl92c_phy_txpwr_idx_to_dbm(hw,
+ WIRELESS_MODE_G,
+ txpwr_level) > txpwr_dbm)
+ txpwr_dbm =
+ _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+ txpwr_level);
+ txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+ if (_rtl92c_phy_txpwr_idx_to_dbm(hw,
+ WIRELESS_MODE_N_24G,
+ txpwr_level) > txpwr_dbm)
+ txpwr_dbm =
+ _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+ txpwr_level);
+ *powerlevel = txpwr_dbm;
+}
+
+static void _rtl92c_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+ u8 *cckpowerlevel, u8 *ofdmpowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 index = (channel - 1);
+
+ cckpowerlevel[RF90_PATH_A] =
+ rtlefuse->txpwrlevel_cck[RF90_PATH_A][index];
+ cckpowerlevel[RF90_PATH_B] =
+ rtlefuse->txpwrlevel_cck[RF90_PATH_B][index];
+ if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_1T1R) {
+ ofdmpowerlevel[RF90_PATH_A] =
+ rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index];
+ ofdmpowerlevel[RF90_PATH_B] =
+ rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index];
+ } else if (get_rf_type(rtlphy) == RF_2T2R) {
+ ofdmpowerlevel[RF90_PATH_A] =
+ rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index];
+ ofdmpowerlevel[RF90_PATH_B] =
+ rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index];
+ }
+}
+
+static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw,
+ u8 channel, u8 *cckpowerlevel,
+ u8 *ofdmpowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
+ rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+}
+
+void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 cckpowerlevel[2], ofdmpowerlevel[2];
+
+ if (rtlefuse->b_txpwr_fromeprom == false)
+ return;
+ _rtl92c_get_txpower_index(hw, channel,
+ &cckpowerlevel[0], &ofdmpowerlevel[0]);
+ _rtl92c_ccxpower_index_check(hw,
+ channel, &cckpowerlevel[0],
+ &ofdmpowerlevel[0]);
+ rtl92c_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
+ rtl92c_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel);
+}
+
+bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 idx;
+ u8 rf_path;
+
+ u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
+ WIRELESS_MODE_B,
+ power_indbm);
+ u8 ofdmtxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
+ WIRELESS_MODE_N_24G,
+ power_indbm);
+ if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0)
+ ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff;
+ else
+ ofdmtxpwridx = 0;
+ RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE,
+ ("%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n",
+ power_indbm, ccktxpwridx, ofdmtxpwridx));
+ for (idx = 0; idx < 14; idx++) {
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx;
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] =
+ ofdmtxpwridx;
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] =
+ ofdmtxpwridx;
+ }
+ }
+ rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+ return true;
+}
+
+void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval)
+{
+}
+
+static u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ long power_indbm)
+{
+ u8 txpwridx;
+ long offset;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ offset = -8;
+ break;
+ default:
+ offset = -8;
+ break;
+ }
+
+ if ((power_indbm - offset) > 0)
+ txpwridx = (u8) ((power_indbm - offset) * 2);
+ else
+ txpwridx = 0;
+
+ if (txpwridx > MAX_TXPWR_IDX_NMODE_92S)
+ txpwridx = MAX_TXPWR_IDX_NMODE_92S;
+
+ return txpwridx;
+}
+
+static long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx)
+{
+ long offset;
+ long pwrout_dbm;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ offset = -8;
+ break;
+ default:
+ offset = -8;
+ break;
+ }
+ pwrout_dbm = txpwridx / 2 + offset;
+ return pwrout_dbm;
+}
+
+void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ enum io_type iotype;
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+
+ break;
+ case SCAN_OPT_RESTORE:
+ iotype = IO_CMD_RESUME_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unknown Scan Backup operation.\n"));
+ break;
+ }
+ }
+}
+
+void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ ("Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz"))
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ break;
+
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+
+ reg_prsr_rsc =
+ (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+ rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+ break;
+
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
+ rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+ (mac->cur_40_prime_sc ==
+ HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+ break;
+ }
+ rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
+void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_bw = rtlphy->current_chan_bw;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ rtlphy->set_bwmode_inprogress = true;
+ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw)))
+ rtl92c_phy_set_bw_mode_callback(hw);
+ else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("FALSE driver sleep or unload\n"));
+ rtlphy->set_bwmode_inprogress = false;
+ rtlphy->current_chan_bw = tmp_bw;
+ }
+}
+
+void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ ("switch to channel%d\n", rtlphy->current_channel));
+ if (is_hal_stop(rtlhal))
+ return;
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+ if (!_rtl92c_phy_sw_chnl_step_by_step
+ (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step, &delay)) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else
+ rtlphy->sw_chnl_inprogress = false;
+ break;
+ } while (true);
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
+u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+ RT_ASSERT((rtlphy->current_channel <= 14),
+ ("WIRELESS_MODE_G but channel>14"));
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+ if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl92c_phy_sw_chnl_callback(hw);
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ ("sw_chnl_inprogress false schdule workitem\n"));
+ rtlphy->sw_chnl_inprogress = false;
+ } else {
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ ("sw_chnl_inprogress false driver sleep or"
+ " unload\n"));
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ return 1;
+}
+
+static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ _rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT,
+ CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+ _rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+ postcommoncmdcnt = 0;
+
+ _rtl92c_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ ("illegal channel for Zebra: %d\n", channel));
+
+ _rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ _rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
+ 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl92c_phy_set_txpower_level(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16) currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8) currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+ return true;
+}
+
+bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath)
+{
+ return true;
+}
+
+static u8 _rtl92c_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD,
+ config_pathb ? 0x28160202 : 0x28160502);
+
+ if (config_pathb) {
+ rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22);
+ rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102);
+ rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160202);
+ }
+
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x001028d1);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+ reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+
+ if (!(reg_eac & BIT(27)) &&
+ (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+ u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
+ mdelay(IQK_DELAY_TIME);
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
+ reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
+ reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
+ reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+ if (!(reg_eac & BIT(31)) &&
+ (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+
+ if (!(reg_eac & BIT(30)) &&
+ (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+ bool b_iqk_ok, long result[][8],
+ u8 final_candidate, bool btxonly)
+{
+ u32 oldval_0, x, tx0_a, reg;
+ long y, tx0_c;
+
+ if (final_candidate == 0xFF)
+ return;
+ else if (b_iqk_ok) {
+ oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD) >> 22) & 0x3FF;
+ x = result[final_candidate][0];
+ if ((x & 0x00000200) != 0)
+ x = x | 0xFFFFFC00;
+ tx0_a = (x * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
+ ((x * oldval_0 >> 7) & 0x1));
+ y = result[final_candidate][1];
+ if ((y & 0x00000200) != 0)
+ y = y | 0xFFFFFC00;
+ tx0_c = (y * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+ ((tx0_c & 0x3C0) >> 6));
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
+ (tx0_c & 0x3F));
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
+ ((y * oldval_0 >> 7) & 0x1));
+ if (btxonly)
+ return;
+ reg = result[final_candidate][2];
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+ reg = result[final_candidate][3] & 0x3F;
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+ reg = (result[final_candidate][3] >> 6) & 0xF;
+ rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+ }
+}
+
+static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
+ bool b_iqk_ok, long result[][8],
+ u8 final_candidate, bool btxonly)
+{
+ u32 oldval_1, x, tx1_a, reg;
+ long y, tx1_c;
+
+ if (final_candidate == 0xFF)
+ return;
+ else if (b_iqk_ok) {
+ oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD) >> 22) & 0x3FF;
+ x = result[final_candidate][4];
+ if ((x & 0x00000200) != 0)
+ x = x | 0xFFFFFC00;
+ tx1_a = (x * oldval_1) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x3FF, tx1_a);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(27),
+ ((x * oldval_1 >> 7) & 0x1));
+ y = result[final_candidate][5];
+ if ((y & 0x00000200) != 0)
+ y = y | 0xFFFFFC00;
+ tx1_c = (y * oldval_1) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE, 0xF0000000,
+ ((tx1_c & 0x3C0) >> 6));
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x003F0000,
+ (tx1_c & 0x3F));
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(25),
+ ((y * oldval_1 >> 7) & 0x1));
+ if (btxonly)
+ return;
+ reg = result[final_candidate][6];
+ rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg);
+ reg = result[final_candidate][7] & 0x3F;
+ rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg);
+ reg = (result[final_candidate][7] >> 6) & 0xF;
+ rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0x0000F000, reg);
+ }
+}
+
+static void _rtl92c_phy_save_adda_registers(struct ieee80211_hw *hw,
+ u32 *addareg, u32 *addabackup,
+ u32 registernum)
+{
+ u32 i;
+
+ for (i = 0; i < registernum; i++)
+ addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+
+static void _rtl92c_phy_save_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+ macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+
+static void _rtl92c_phy_reload_adda_registers(struct ieee80211_hw *hw,
+ u32 *addareg, u32 *addabackup,
+ u32 regiesternum)
+{
+ u32 i;
+
+ for (i = 0; i < regiesternum; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
+}
+
+static void _rtl92c_phy_reload_mac_registers(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+ rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+
+static void _rtl92c_phy_path_adda_on(struct ieee80211_hw *hw,
+ u32 *addareg, bool is_patha_on, bool is2t)
+{
+ u32 pathOn;
+ u32 i;
+
+ pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+ if (false == is2t) {
+ pathOn = 0x0bdb25a0;
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+ } else {
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn);
+ }
+
+ for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn);
+}
+
+static void _rtl92c_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+ u32 *macreg, u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ rtl_write_byte(rtlpriv, macreg[0], 0x3F);
+
+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i],
+ (u8) (macbackup[i] & (~BIT(3))));
+ rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+
+static void _rtl92c_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+
+static void _rtl92c_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+ u32 mode;
+
+ mode = pi_mode ? 0x01000100 : 0x01000000;
+ rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+
+static bool _rtl92c_phy_simularity_compare(struct ieee80211_hw *hw,
+ long result[][8], u8 c1, u8 c2)
+{
+ u32 i, j, diff, simularity_bitmap, bound;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 final_candidate[2] = { 0xFF, 0xFF };
+ bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+
+ if (is2t)
+ bound = 8;
+ else
+ bound = 4;
+
+ simularity_bitmap = 0;
+
+ for (i = 0; i < bound; i++) {
+ diff = (result[c1][i] > result[c2][i]) ?
+ (result[c1][i] - result[c2][i]) :
+ (result[c2][i] - result[c1][i]);
+
+ if (diff > MAX_TOLERANCE) {
+ if ((i == 2 || i == 6) && !simularity_bitmap) {
+ if (result[c1][i] + result[c1][i + 1] == 0)
+ final_candidate[(i / 4)] = c2;
+ else if (result[c2][i] + result[c2][i + 1] == 0)
+ final_candidate[(i / 4)] = c1;
+ else
+ simularity_bitmap = simularity_bitmap |
+ (1 << i);
+ } else
+ simularity_bitmap =
+ simularity_bitmap | (1 << i);
+ }
+ }
+
+ if (simularity_bitmap == 0) {
+ for (i = 0; i < (bound / 4); i++) {
+ if (final_candidate[i] != 0xFF) {
+ for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+ result[3][j] =
+ result[final_candidate[i]][j];
+ bresult = false;
+ }
+ }
+ return bresult;
+ } else if (!(simularity_bitmap & 0x0F)) {
+ for (i = 0; i < 4; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else if (!(simularity_bitmap & 0xF0) && is2t) {
+ for (i = 4; i < 8; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else {
+ return false;
+ }
+
+}
+
+static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
+ long result[][8], u8 t, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 i;
+ u8 patha_ok, pathb_ok;
+ u32 adda_reg[IQK_ADDA_REG_NUM] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+
+ u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+ 0x522, 0x550, 0x551, 0x040
+ };
+
+ const u32 retrycount = 2;
+
+ u32 bbvalue;
+
+ if (t == 0) {
+ bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
+
+ _rtl92c_phy_save_adda_registers(hw, adda_reg,
+ rtlphy->adda_backup, 16);
+ _rtl92c_phy_save_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ }
+ _rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t);
+ if (t == 0) {
+ rtlphy->b_rfpi_enable = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ }
+ if (!rtlphy->b_rfpi_enable)
+ _rtl92c_phy_pi_mode_switch(hw, true);
+ if (t == 0) {
+ rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
+ rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
+ rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD);
+ }
+ rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+ if (is2t) {
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
+ }
+ _rtl92c_phy_mac_setting_calibration(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000);
+ if (is2t)
+ rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x00080000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl92c_phy_path_a_iqk(hw, is2t);
+ if (patha_ok == 0x03) {
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else if (i == (retrycount - 1) && patha_ok == 0x01)
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94,
+ MASKDWORD) & 0x3FF0000) >>
+ 16;
+ result[t][1] =
+ (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16;
+
+ }
+
+ if (is2t) {
+ _rtl92c_phy_path_a_standby(hw);
+ _rtl92c_phy_path_adda_on(hw, adda_reg, false, is2t);
+ for (i = 0; i < retrycount; i++) {
+ pathb_ok = _rtl92c_phy_path_b_iqk(hw);
+ if (pathb_ok == 0x03) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4,
+ MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][5] =
+ (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][6] =
+ (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][7] =
+ (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else if (i == (retrycount - 1) && pathb_ok == 0x01) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4,
+ MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ }
+ rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04);
+ rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874);
+ rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+ if (is2t)
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+ if (t != 0) {
+ if (!rtlphy->b_rfpi_enable)
+ _rtl92c_phy_pi_mode_switch(hw, false);
+ _rtl92c_phy_reload_adda_registers(hw, adda_reg,
+ rtlphy->adda_backup, 16);
+ _rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ }
+}
+
+static void _rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+ u8 tmpreg;
+ u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+ if ((tmpreg & 0x70) != 0)
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+ else
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+ if ((tmpreg & 0x70) != 0) {
+ rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
+
+ if (is2t)
+ rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
+ MASK12BITS);
+
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
+ (rf_a_mode & 0x8FFFF) | 0x10000);
+
+ if (is2t)
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+ (rf_b_mode & 0x8FFFF) | 0x10000);
+ }
+ lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000);
+
+ mdelay(100);
+
+ if ((tmpreg & 0x70) != 0) {
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
+
+ if (is2t)
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+ rf_b_mode);
+ } else {
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ }
+}
+
+static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
+ char delta, bool is2t)
+{
+ /* This routine is deliberately dummied out for later fixes */
+#if 0
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ u32 reg_d[PATH_NUM];
+ u32 tmpreg, index, offset, path, i, pathbound = PATH_NUM, apkbound;
+
+ u32 bb_backup[APK_BB_REG_NUM];
+ u32 bb_reg[APK_BB_REG_NUM] = {
+ 0x904, 0xc04, 0x800, 0xc08, 0x874
+ };
+ u32 bb_ap_mode[APK_BB_REG_NUM] = {
+ 0x00000020, 0x00a05430, 0x02040000,
+ 0x000800e4, 0x00204000
+ };
+ u32 bb_normal_ap_mode[APK_BB_REG_NUM] = {
+ 0x00000020, 0x00a05430, 0x02040000,
+ 0x000800e4, 0x22204000
+ };
+
+ u32 afe_backup[APK_AFE_REG_NUM];
+ u32 afe_reg[APK_AFE_REG_NUM] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74, 0xe78,
+ 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c,
+ 0xed0, 0xed4, 0xed8, 0xedc, 0xee0,
+ 0xeec
+ };
+
+ u32 mac_backup[IQK_MAC_REG_NUM];
+ u32 mac_reg[IQK_MAC_REG_NUM] = {
+ 0x522, 0x550, 0x551, 0x040
+ };
+
+ u32 apk_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c},
+ {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e}
+ };
+
+ u32 apk_normal_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c},
+ {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c}
+ };
+
+ u32 apk_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d},
+ {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050}
+ };
+
+ u32 apk_normal_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a},
+ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}
+ };
+
+ u32 afe_on_off[PATH_NUM] = {
+ 0x04db25a4, 0x0b1b25a4
+ };
+
+ u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
+
+ u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 };
+
+ u32 apk_value[PATH_NUM] = { 0x92fc0000, 0x12fc0000 };
+
+ u32 apk_normal_value[PATH_NUM] = { 0x92680000, 0x12680000 };
+
+ const char apk_delta_mapping[APK_BB_REG_NUM][13] = {
+ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0}
+ };
+
+ const u32 apk_normal_setting_value_1[13] = {
+ 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28,
+ 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3,
+ 0x12680000, 0x00880000, 0x00880000
+ };
+
+ const u32 apk_normal_setting_value_2[16] = {
+ 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3,
+ 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025,
+ 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008,
+ 0x00050006
+ };
+
+ const u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
+
+ long bb_offset, delta_v, delta_offset;
+
+ if (!is2t)
+ pathbound = 1;
+
+ for (index = 0; index < PATH_NUM; index++) {
+ apk_offset[index] = apk_normal_offset[index];
+ apk_value[index] = apk_normal_value[index];
+ afe_on_off[index] = 0x6fdb25a4;
+ }
+
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ for (path = 0; path < pathbound; path++) {
+ apk_rf_init_value[path][index] =
+ apk_normal_rf_init_value[path][index];
+ apk_rf_value_0[path][index] =
+ apk_normal_rf_value_0[path][index];
+ }
+ bb_ap_mode[index] = bb_normal_ap_mode[index];
+
+ apkbound = 6;
+ }
+
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0)
+ continue;
+ bb_backup[index] = rtl_get_bbreg(hw, bb_reg[index], MASKDWORD);
+ }
+
+ _rtl92c_phy_save_mac_registers(hw, mac_reg, mac_backup);
+
+ _rtl92c_phy_save_adda_registers(hw, afe_reg, afe_backup, 16);
+
+ for (path = 0; path < pathbound; path++) {
+ if (path == RF90_PATH_A) {
+ offset = 0xb00;
+ for (index = 0; index < 11; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_1
+ [index]);
+
+ offset += 0x04;
+ }
+
+ rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000);
+
+ offset = 0xb68;
+ for (; index < 13; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_1
+ [index]);
+
+ offset += 0x04;
+ }
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000);
+
+ offset = 0xb00;
+ for (index = 0; index < 16; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_2
+ [index]);
+
+ offset += 0x04;
+ }
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
+ } else if (path == RF90_PATH_B) {
+ offset = 0xb70;
+ for (index = 0; index < 10; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_1
+ [index]);
+
+ offset += 0x04;
+ }
+ rtl_set_bbreg(hw, 0xb28, MASKDWORD, 0x12680000);
+ rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000);
+
+ offset = 0xb68;
+ index = 11;
+ for (; index < 13; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_1
+ [index]);
+
+ offset += 0x04;
+ }
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000);
+
+ offset = 0xb60;
+ for (index = 0; index < 16; index++) {
+ rtl_set_bbreg(hw, offset, MASKDWORD,
+ apk_normal_setting_value_2
+ [index]);
+
+ offset += 0x04;
+ }
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
+ }
+
+ reg_d[path] = rtl_get_rfreg(hw, (enum radio_path)path,
+ 0xd, MASKDWORD);
+
+ for (index = 0; index < APK_AFE_REG_NUM; index++)
+ rtl_set_bbreg(hw, afe_reg[index], MASKDWORD,
+ afe_on_off[path]);
+
+ if (path == RF90_PATH_A) {
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0)
+ continue;
+ rtl_set_bbreg(hw, bb_reg[index], MASKDWORD,
+ bb_ap_mode[index]);
+ }
+ }
+
+ _rtl92c_phy_mac_setting_calibration(hw, mac_reg, mac_backup);
+
+ if (path == 0) {
+ rtl_set_rfreg(hw, RF90_PATH_B, 0x0, MASKDWORD, 0x10000);
+ } else {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASKDWORD,
+ 0x10000);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD,
+ 0x1000f);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD,
+ 0x20103);
+ }
+
+ delta_offset = ((delta + 14) / 2);
+ if (delta_offset < 0)
+ delta_offset = 0;
+ else if (delta_offset > 12)
+ delta_offset = 12;
+
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index != 1)
+ continue;
+
+ tmpreg = apk_rf_init_value[path][index];
+
+ if (!rtlefuse->b_apk_thermalmeterignore) {
+ bb_offset = (tmpreg & 0xF0000) >> 16;
+
+ if (!(tmpreg & BIT(15)))
+ bb_offset = -bb_offset;
+
+ delta_v =
+ apk_delta_mapping[index][delta_offset];
+
+ bb_offset += delta_v;
+
+ if (bb_offset < 0) {
+ tmpreg = tmpreg & (~BIT(15));
+ bb_offset = -bb_offset;
+ } else {
+ tmpreg = tmpreg | BIT(15);
+ }
+
+ tmpreg =
+ (tmpreg & 0xFFF0FFFF) | (bb_offset << 16);
+ }
+
+ rtl_set_rfreg(hw, (enum radio_path)path, 0xc,
+ MASKDWORD, 0x8992e);
+ rtl_set_rfreg(hw, (enum radio_path)path, 0x0,
+ MASKDWORD, apk_rf_value_0[path][index]);
+ rtl_set_rfreg(hw, (enum radio_path)path, 0xd,
+ MASKDWORD, tmpreg);
+
+ i = 0;
+ do {
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80000000);
+ rtl_set_bbreg(hw, apk_offset[path],
+ MASKDWORD, apk_value[0]);
+ RTPRINT(rtlpriv, FINIT, INIT_IQK,
+ ("PHY_APCalibrate() offset 0x%x "
+ "value 0x%x\n",
+ apk_offset[path],
+ rtl_get_bbreg(hw, apk_offset[path],
+ MASKDWORD)));
+
+ mdelay(3);
+
+ rtl_set_bbreg(hw, apk_offset[path],
+ MASKDWORD, apk_value[1]);
+ RTPRINT(rtlpriv, FINIT, INIT_IQK,
+ ("PHY_APCalibrate() offset 0x%x "
+ "value 0x%x\n",
+ apk_offset[path],
+ rtl_get_bbreg(hw, apk_offset[path],
+ MASKDWORD)));
+
+ mdelay(20);
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
+
+ if (path == RF90_PATH_A)
+ tmpreg = rtl_get_bbreg(hw, 0xbd8,
+ 0x03E00000);
+ else
+ tmpreg = rtl_get_bbreg(hw, 0xbd8,
+ 0xF8000000);
+
+ RTPRINT(rtlpriv, FINIT, INIT_IQK,
+ ("PHY_APCalibrate() offset "
+ "0xbd8[25:21] %x\n", tmpreg));
+
+ i++;
+
+ } while (tmpreg > apkbound && i < 4);
+
+ apk_result[path][index] = tmpreg;
+ }
+ }
+
+ _rtl92c_phy_reload_mac_registers(hw, mac_reg, mac_backup);
+
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0)
+ continue;
+ rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, bb_backup[index]);
+ }
+
+ _rtl92c_phy_reload_adda_registers(hw, afe_reg, afe_backup, 16);
+
+ for (path = 0; path < pathbound; path++) {
+ rtl_set_rfreg(hw, (enum radio_path)path, 0xd,
+ MASKDWORD, reg_d[path]);
+
+ if (path == RF90_PATH_B) {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD,
+ 0x1000f);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD,
+ 0x20101);
+ }
+
+ if (apk_result[path][1] > 6)
+ apk_result[path][1] = 6;
+ }
+
+ for (path = 0; path < pathbound; path++) {
+ rtl_set_rfreg(hw, (enum radio_path)path, 0x3, MASKDWORD,
+ ((apk_result[path][1] << 15) |
+ (apk_result[path][1] << 10) |
+ (apk_result[path][1] << 5) |
+ apk_result[path][1]));
+
+ if (path == RF90_PATH_A)
+ rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD,
+ ((apk_result[path][1] << 15) |
+ (apk_result[path][1] << 10) |
+ (0x00 << 5) | 0x05));
+ else
+ rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD,
+ ((apk_result[path][1] << 15) |
+ (apk_result[path][1] << 10) |
+ (0x02 << 5) | 0x05));
+
+ rtl_set_rfreg(hw, (enum radio_path)path, 0xe, MASKDWORD,
+ ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) |
+ 0x08));
+
+ }
+
+ rtlphy->b_apk_done = true;
+#endif
+}
+
+static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+ bool bmain, bool is2t)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (is_hal_stop(rtlhal)) {
+ rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01);
+ rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+ }
+ if (is2t) {
+ if (bmain)
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x1);
+ else
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x2);
+ } else {
+ if (bmain)
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2);
+ else
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
+
+ }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ long result[4][8];
+ u8 i, final_candidate;
+ bool b_patha_ok, b_pathb_ok;
+ long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+ reg_ecc, reg_tmp = 0;
+ bool is12simular, is13simular, is23simular;
+ bool b_start_conttx = false, b_singletone = false;
+ u32 iqk_bb_reg[10] = {
+ ROFDM0_XARXIQIMBALANCE,
+ ROFDM0_XBRXIQIMBALANCE,
+ ROFDM0_ECCATHRESHOLD,
+ ROFDM0_AGCRSSITABLE,
+ ROFDM0_XATXIQIMBALANCE,
+ ROFDM0_XBTXIQIMBALANCE,
+ ROFDM0_XCTXIQIMBALANCE,
+ ROFDM0_XCTXAFE,
+ ROFDM0_XDTXAFE,
+ ROFDM0_RXIQEXTANTA
+ };
+
+ if (b_recovery) {
+ _rtl92c_phy_reload_adda_registers(hw,
+ iqk_bb_reg,
+ rtlphy->iqk_bb_backup, 10);
+ return;
+ }
+ if (b_start_conttx || b_singletone)
+ return;
+ for (i = 0; i < 8; i++) {
+ result[0][i] = 0;
+ result[1][i] = 0;
+ result[2][i] = 0;
+ result[3][i] = 0;
+ }
+ final_candidate = 0xff;
+ b_patha_ok = false;
+ b_pathb_ok = false;
+ is12simular = false;
+ is23simular = false;
+ is13simular = false;
+ for (i = 0; i < 3; i++) {
+ if (IS_92C_SERIAL(rtlhal->version))
+ _rtl92c_phy_iq_calibrate(hw, result, i, true);
+ else
+ _rtl92c_phy_iq_calibrate(hw, result, i, false);
+ if (i == 1) {
+ is12simular = _rtl92c_phy_simularity_compare(hw,
+ result, 0,
+ 1);
+ if (is12simular) {
+ final_candidate = 0;
+ break;
+ }
+ }
+ if (i == 2) {
+ is13simular = _rtl92c_phy_simularity_compare(hw,
+ result, 0,
+ 2);
+ if (is13simular) {
+ final_candidate = 0;
+ break;
+ }
+ is23simular = _rtl92c_phy_simularity_compare(hw,
+ result, 1,
+ 2);
+ if (is23simular)
+ final_candidate = 1;
+ else {
+ for (i = 0; i < 8; i++)
+ reg_tmp += result[3][i];
+
+ if (reg_tmp != 0)
+ final_candidate = 3;
+ else
+ final_candidate = 0xFF;
+ }
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ reg_e94 = result[i][0];
+ reg_e9c = result[i][1];
+ reg_ea4 = result[i][2];
+ reg_eac = result[i][3];
+ reg_eb4 = result[i][4];
+ reg_ebc = result[i][5];
+ reg_ec4 = result[i][6];
+ reg_ecc = result[i][7];
+ }
+ if (final_candidate != 0xff) {
+ rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
+ rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
+ reg_ea4 = result[final_candidate][2];
+ reg_eac = result[final_candidate][3];
+ rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
+ rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
+ reg_ec4 = result[final_candidate][6];
+ reg_ecc = result[final_candidate][7];
+ b_patha_ok = b_pathb_ok = true;
+ } else {
+ rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
+ rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
+ }
+ if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+ _rtl92c_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
+ final_candidate,
+ (reg_ea4 == 0));
+ if (IS_92C_SERIAL(rtlhal->version)) {
+ if (reg_eb4 != 0) /*&&(reg_ec4 != 0) */
+ _rtl92c_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok,
+ result,
+ final_candidate,
+ (reg_ec4 == 0));
+ }
+ _rtl92c_phy_save_adda_registers(hw, iqk_bb_reg,
+ rtlphy->iqk_bb_backup, 10);
+}
+
+void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool b_start_conttx = false, b_singletone = false;
+
+ if (b_start_conttx || b_singletone)
+ return;
+ if (IS_92C_SERIAL(rtlhal->version))
+ _rtl92c_phy_lc_calibrate(hw, true);
+ else
+ _rtl92c_phy_lc_calibrate(hw, false);
+}
+
+void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlphy->b_apk_done)
+ return;
+ if (IS_92C_SERIAL(rtlhal->version))
+ _rtl92c_phy_ap_calibrate(hw, delta, true);
+ else
+ _rtl92c_phy_ap_calibrate(hw, delta, false);
+}
+
+void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (IS_92C_SERIAL(rtlhal->version))
+ _rtl92c_phy_set_rfpath_switch(hw, bmain, true);
+ else
+ _rtl92c_phy_set_rfpath_switch(hw, bmain, false);
+}
+
+bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool b_postprocessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ ("-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+ iotype, rtlphy->set_io_inprogress));
+ do {
+ switch (iotype) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ ("[IO CMD] Resume DM after scan.\n"));
+ b_postprocessing = true;
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ ("[IO CMD] Pause DM before scan.\n"));
+ b_postprocessing = true;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ } while (false);
+ if (b_postprocessing && !rtlphy->set_io_inprogress) {
+ rtlphy->set_io_inprogress = true;
+ rtlphy->current_io_type = iotype;
+ } else {
+ return false;
+ }
+ rtl92c_phy_set_io(hw);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, ("<--IO Type(%#x)\n", iotype));
+ return true;
+}
+
+void rtl92c_phy_set_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ ("--->Cmd(%#x), set_io_inprogress(%d)\n",
+ rtlphy->current_io_type, rtlphy->set_io_inprogress));
+ switch (rtlphy->current_io_type) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ dm_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+ rtl92c_dm_write_dig(hw);
+ rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue;
+ dm_digtable.cur_igvalue = 0x17;
+ rtl92c_dm_write_dig(hw);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ rtlphy->set_io_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ ("<---(%#x)\n", rtlphy->current_io_type));
+}
+
+void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ u32 u4b_tmp;
+ u8 delay = 5;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+ while (u4b_tmp != 0 && delay > 0) {
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+ delay--;
+ }
+ if (delay == 0) {
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Switch RF timeout !!!.\n"));
+ return;
+ }
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult = true;
+ u8 i, queue_id;
+ struct rtl8192_tx_ring *ring = NULL;
+
+ ppsc->set_rfpowerstate_inprogress = true;
+ switch (rfpwr_state) {
+ case ERFON:{
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ bool rtstatus;
+ u32 InitializeCount = 0;
+ do {
+ InitializeCount++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic enable\n"));
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while ((rtstatus != true)
+ && (InitializeCount < 10));
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("Set ERFON sleeped:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->
+ last_sleep_jiffies)));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl92ce_phy_set_rf_on(hw);
+ }
+ if (mac->link_state == MAC80211_LINKED) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_LINK);
+ } else {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ }
+ break;
+ }
+ case ERFOFF:{
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0 ||
+ queue_id == BEACON_QUEUE) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("eRf Off/Sleep: %d times "
+ "TcbBusyQueue[%d] "
+ "=%d before doze!\n", (i + 1),
+ queue_id,
+ skb_queue_len(&ring->queue)));
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("\nERFOFF: %d times "
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue)));
+ break;
+ }
+ }
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic disable\n"));
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ } else {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ }
+ break;
+ }
+ case ERFSLEEP:{
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("eRf Off/Sleep: %d times "
+ "TcbBusyQueue[%d] =%d before "
+ "doze!\n", (i + 1), queue_id,
+ skb_queue_len(&ring->queue)));
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("\n ERFSLEEP: %d times "
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue)));
+ break;
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies)));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl92ce_phy_set_rf_sleep(hw);
+ break;
+ }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ bresult = false;
+ break;
+ }
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+ ppsc->set_rfpowerstate_inprogress = false;
+ return bresult;
+}
+
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult = false;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return bresult;
+ bresult = _rtl92ce_phy_set_rf_power_state(hw, rfpwr_state);
+ return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
new file mode 100644
index 000000000000..ca4daee6e9a8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_PHY_H__
+#define __RTL92C_PHY_H__
+
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+#define RT_CANNOT_IO(hw) false
+#define HIGHPOWER_RADIOA_ARRAYLEN 22
+
+#define MAX_TOLERANCE 5
+#define IQK_DELAY_TIME 1
+
+#define APK_BB_REG_NUM 5
+#define APK_AFE_REG_NUM 16
+#define APK_CURVE_REG_NUM 4
+#define PATH_NUM 2
+
+#define LOOP_LIMIT 5
+#define MAX_STALL_TIME 50
+#define AntennaDiversityValue 0x80
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define Reset_Cnt_Limit 3
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_MAC_REG_NUM 4
+
+#define RF90_PATH_MAX 2
+#define CHANNEL_MAX_NUMBER 14
+#define CHANNEL_GROUP_MAX 3
+
+#define CT_OFFSET_MAC_ADDR 0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIF 0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72
+
+#define CT_OFFSET_CHANNEL_PLAH 0x75
+#define CT_OFFSET_THERMAL_METER 0x78
+#define CT_OFFSET_RF_OPTION 0x79
+#define CT_OFFSET_VERSION 0x7E
+#define CT_OFFSET_CUSTOMER_ID 0x7F
+
+#define RTL92C_MAX_PATH_NUM 2
+#define CHANNEL_MAX_NUMBER 14
+#define CHANNEL_GROUP_MAX 3
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+enum hw90_block_e {
+ HW90_BLOCK_MAC = 0,
+ HW90_BLOCK_PHY0 = 1,
+ HW90_BLOCK_PHY1 = 2,
+ HW90_BLOCK_RF = 3,
+ HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+ BASEBAND_CONFIG_PHY_REG = 0,
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+ RA_OFFSET_LEGACY_OFDM1,
+ RA_OFFSET_LEGACY_OFDM2,
+ RA_OFFSET_HT_OFDM1,
+ RA_OFFSET_HT_OFDM2,
+ RA_OFFSET_HT_OFDM3,
+ RA_OFFSET_HT_OFDM4,
+ RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+ ANTENNA_NONE,
+ ANTENNA_D,
+ ANTENNA_C,
+ ANTENNA_CD,
+ ANTENNA_B,
+ ANTENNA_BD,
+ ANTENNA_BC,
+ ANTENNA_BCD,
+ ANTENNA_A,
+ ANTENNA_AD,
+ ANTENNA_AC,
+ ANTENNA_ACD,
+ ANTENNA_AB,
+ ANTENNA_ABD,
+ ANTENNA_ABC,
+ ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+ u32 r_tx_antenna:4;
+ u32 r_ant_l:4;
+ u32 r_ant_non_ht:4;
+ u32 r_ant_ht1:4;
+ u32 r_ant_ht2:4;
+ u32 r_ant_ht_s1:4;
+ u32 r_ant_non_ht_s1:4;
+ u32 ofdm_txsc:2;
+ u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+ u8 r_cckrx_enable_2:2;
+ u8 r_cckrx_enable:2;
+ u8 r_ccktx_enable:4;
+};
+
+struct efuse_contents {
+ u8 mac_addr[ETH_ALEN];
+ u8 cck_tx_power_idx[6];
+ u8 ht40_1s_tx_power_idx[6];
+ u8 ht40_2s_tx_power_idx_diff[3];
+ u8 ht20_tx_power_idx_diff[3];
+ u8 ofdm_tx_power_idx_diff[3];
+ u8 ht40_max_power_offset[3];
+ u8 ht20_max_power_offset[3];
+ u8 channel_plan;
+ u8 thermal_meter;
+ u8 rf_option[5];
+ u8 version;
+ u8 oem_id;
+ u8 regulatory;
+};
+
+struct tx_power_struct {
+ u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_txpowerdiff;
+ u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 pwrgroup_cnt;
+ u32 mcs_original_offset[4][16];
+};
+
+extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask);
+extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data);
+extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask);
+extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask, u32 data);
+extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
+extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
+extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
+extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
+ long *powerlevel);
+extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+ long power_indbm);
+extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation);
+extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
+extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
+ u16 beaconinterval);
+void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
+void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
+ u32 rfpath);
+bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+void rtl92c_phy_config_bb_external_pa(struct ieee80211_hw *hw);
+void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw);
+bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+void rtl92c_phy_set_io(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
new file mode 100644
index 000000000000..875d51465225
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -0,0 +1,2065 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_REG_H__
+#define __RTL92C_REG_H__
+
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define REG_APS_FSMCO 0x0004
+#define REG_SYS_CLKR 0x0008
+#define REG_9346CR 0x000A
+#define REG_EE_VPD 0x000C
+#define REG_AFE_MISC 0x0010
+#define REG_SPS0_CTRL 0x0011
+#define REG_SPS_OCP_CFG 0x0018
+#define REG_RSV_CTRL 0x001C
+#define REG_RF_CTRL 0x001F
+#define REG_LDOA15_CTRL 0x0020
+#define REG_LDOV12D_CTRL 0x0021
+#define REG_LDOHCI12_CTRL 0x0022
+#define REG_LPLDO_CTRL 0x0023
+#define REG_AFE_XTAL_CTRL 0x0024
+#define REG_AFE_PLL_CTRL 0x0028
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define REG_PWR_DATA 0x0038
+#define REG_CAL_TIMER 0x003C
+#define REG_ACLK_MON 0x003E
+#define REG_GPIO_MUXCFG 0x0040
+#define REG_GPIO_IO_SEL 0x0042
+#define REG_MAC_PINMUX_CFG 0x0043
+#define REG_GPIO_PIN_CTRL 0x0044
+#define REG_GPIO_INTM 0x0048
+#define REG_LEDCFG0 0x004C
+#define REG_LEDCFG1 0x004D
+#define REG_LEDCFG2 0x004E
+#define REG_LEDCFG3 0x004F
+#define REG_FSIMR 0x0050
+#define REG_FSISR 0x0054
+
+#define REG_MCUFWDL 0x0080
+
+#define REG_HMEBOX_EXT_0 0x0088
+#define REG_HMEBOX_EXT_1 0x008A
+#define REG_HMEBOX_EXT_2 0x008C
+#define REG_HMEBOX_EXT_3 0x008E
+
+#define REG_BIST_SCAN 0x00D0
+#define REG_BIST_RPT 0x00D4
+#define REG_BIST_ROM_RPT 0x00D8
+#define REG_USB_SIE_INTF 0x00E0
+#define REG_PCIE_MIO_INTF 0x00E4
+#define REG_PCIE_MIO_INTD 0x00E8
+#define REG_HPON_FSM 0x00EC
+#define REG_SYS_CFG 0x00F0
+
+#define REG_CR 0x0100
+#define REG_PBP 0x0104
+#define REG_TRXDMA_CTRL 0x010C
+#define REG_TRXFF_BNDY 0x0114
+#define REG_TRXFF_STATUS 0x0118
+#define REG_RXFF_PTR 0x011C
+#define REG_HIMR 0x0120
+#define REG_HISR 0x0124
+#define REG_HIMRE 0x0128
+#define REG_HISRE 0x012C
+#define REG_CPWM 0x012F
+#define REG_FWIMR 0x0130
+#define REG_FWISR 0x0134
+#define REG_PKTBUF_DBG_CTRL 0x0140
+#define REG_PKTBUF_DBG_DATA_L 0x0144
+#define REG_PKTBUF_DBG_DATA_H 0x0148
+
+#define REG_TC0_CTRL 0x0150
+#define REG_TC1_CTRL 0x0154
+#define REG_TC2_CTRL 0x0158
+#define REG_TC3_CTRL 0x015C
+#define REG_TC4_CTRL 0x0160
+#define REG_TCUNIT_BASE 0x0164
+#define REG_MBIST_START 0x0174
+#define REG_MBIST_DONE 0x0178
+#define REG_MBIST_FAIL 0x017C
+#define REG_C2HEVT_MSG_NORMAL 0x01A0
+#define REG_C2HEVT_MSG_TEST 0x01B8
+#define REG_C2HEVT_CLEAR 0x01BF
+#define REG_MCUTST_1 0x01c0
+#define REG_FMETHR 0x01C8
+#define REG_HMETFR 0x01CC
+#define REG_HMEBOX_0 0x01D0
+#define REG_HMEBOX_1 0x01D4
+#define REG_HMEBOX_2 0x01D8
+#define REG_HMEBOX_3 0x01DC
+
+#define REG_LLT_INIT 0x01E0
+#define REG_BB_ACCEESS_CTRL 0x01E8
+#define REG_BB_ACCESS_DATA 0x01EC
+
+#define REG_RQPN 0x0200
+#define REG_FIFOPAGE 0x0204
+#define REG_TDECTRL 0x0208
+#define REG_TXDMA_OFFSET_CHK 0x020C
+#define REG_TXDMA_STATUS 0x0210
+#define REG_RQPN_NPQ 0x0214
+
+#define REG_RXDMA_AGG_PG_TH 0x0280
+#define REG_RXPKT_NUM 0x0284
+#define REG_RXDMA_STATUS 0x0288
+
+#define REG_PCIE_CTRL_REG 0x0300
+#define REG_INT_MIG 0x0304
+#define REG_BCNQ_DESA 0x0308
+#define REG_HQ_DESA 0x0310
+#define REG_MGQ_DESA 0x0318
+#define REG_VOQ_DESA 0x0320
+#define REG_VIQ_DESA 0x0328
+#define REG_BEQ_DESA 0x0330
+#define REG_BKQ_DESA 0x0338
+#define REG_RX_DESA 0x0340
+#define REG_DBI 0x0348
+#define REG_MDIO 0x0354
+#define REG_DBG_SEL 0x0360
+#define REG_PCIE_HRPWM 0x0361
+#define REG_PCIE_HCPWM 0x0363
+#define REG_UART_CTRL 0x0364
+#define REG_UART_TX_DESA 0x0370
+#define REG_UART_RX_DESA 0x0378
+
+#define REG_HDAQ_DESA_NODEF 0x0000
+#define REG_CMDQ_DESA_NODEF 0x0000
+
+#define REG_VOQ_INFORMATION 0x0400
+#define REG_VIQ_INFORMATION 0x0404
+#define REG_BEQ_INFORMATION 0x0408
+#define REG_BKQ_INFORMATION 0x040C
+#define REG_MGQ_INFORMATION 0x0410
+#define REG_HGQ_INFORMATION 0x0414
+#define REG_BCNQ_INFORMATION 0x0418
+
+#define REG_CPU_MGQ_INFORMATION 0x041C
+#define REG_FWHW_TXQ_CTRL 0x0420
+#define REG_HWSEQ_CTRL 0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY 0x0425
+#define REG_MULTI_BCNQ_EN 0x0426
+#define REG_MULTI_BCNQ_OFFSET 0x0427
+#define REG_SPEC_SIFS 0x0428
+#define REG_RL 0x042A
+#define REG_DARFRC 0x0430
+#define REG_RARFRC 0x0438
+#define REG_RRSR 0x0440
+#define REG_ARFR0 0x0444
+#define REG_ARFR1 0x0448
+#define REG_ARFR2 0x044C
+#define REG_ARFR3 0x0450
+#define REG_AGGLEN_LMT 0x0458
+#define REG_AMPDU_MIN_SPACE 0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D
+#define REG_FAST_EDCA_CTRL 0x0460
+#define REG_RD_RESP_PKT_TH 0x0463
+#define REG_INIRTS_RATE_SEL 0x0480
+#define REG_INIDATA_RATE_SEL 0x0484
+#define REG_POWER_STATUS 0x04A4
+#define REG_POWER_STAGE1 0x04B4
+#define REG_POWER_STAGE2 0x04B8
+#define REG_PKT_LIFE_TIME 0x04C0
+#define REG_STBC_SETTING 0x04C4
+#define REG_PROT_MODE_CTRL 0x04C8
+#define REG_BAR_MODE_CTRL 0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT 0x04CF
+#define REG_NQOS_SEQ 0x04DC
+#define REG_QOS_SEQ 0x04DE
+#define REG_NEED_CPU_HANDLE 0x04E0
+#define REG_PKT_LOSE_RPT 0x04E1
+#define REG_PTCL_ERR_STATUS 0x04E2
+#define REG_DUMMY 0x04FC
+
+#define REG_EDCA_VO_PARAM 0x0500
+#define REG_EDCA_VI_PARAM 0x0504
+#define REG_EDCA_BE_PARAM 0x0508
+#define REG_EDCA_BK_PARAM 0x050C
+#define REG_BCNTCFG 0x0510
+#define REG_PIFS 0x0512
+#define REG_RDG_PIFS 0x0513
+#define REG_SIFS_CTX 0x0514
+#define REG_SIFS_TRX 0x0516
+#define REG_AGGR_BREAK_TIME 0x051A
+#define REG_SLOT 0x051B
+#define REG_TX_PTCL_CTRL 0x0520
+#define REG_TXPAUSE 0x0522
+#define REG_DIS_TXREQ_CLR 0x0523
+#define REG_RD_CTRL 0x0524
+#define REG_TBTT_PROHIBIT 0x0540
+#define REG_RD_NAV_NXT 0x0544
+#define REG_NAV_PROT_LEN 0x0546
+#define REG_BCN_CTRL 0x0550
+#define REG_USTIME_TSF 0x0551
+#define REG_MBID_NUM 0x0552
+#define REG_DUAL_TSF_RST 0x0553
+#define REG_BCN_INTERVAL 0x0554
+#define REG_MBSSID_BCN_SPACE 0x0554
+#define REG_DRVERLYINT 0x0558
+#define REG_BCNDMATIM 0x0559
+#define REG_ATIMWND 0x055A
+#define REG_BCN_MAX_ERR 0x055D
+#define REG_RXTSF_OFFSET_CCK 0x055E
+#define REG_RXTSF_OFFSET_OFDM 0x055F
+#define REG_TSFTR 0x0560
+#define REG_INIT_TSFTR 0x0564
+#define REG_PSTIMER 0x0580
+#define REG_TIMER0 0x0584
+#define REG_TIMER1 0x0588
+#define REG_ACMHWCTRL 0x05C0
+#define REG_ACMRSTCTRL 0x05C1
+#define REG_ACMAVG 0x05C2
+#define REG_VO_ADMTIME 0x05C4
+#define REG_VI_ADMTIME 0x05C6
+#define REG_BE_ADMTIME 0x05C8
+#define REG_EDCA_RANDOM_GEN 0x05CC
+#define REG_SCH_TXCMD 0x05D0
+
+#define REG_APSD_CTRL 0x0600
+#define REG_BWOPMODE 0x0603
+#define REG_TCR 0x0604
+#define REG_RCR 0x0608
+#define REG_RX_PKT_LIMIT 0x060C
+#define REG_RX_DLK_TIME 0x060D
+#define REG_RX_DRVINFO_SZ 0x060F
+
+#define REG_MACID 0x0610
+#define REG_BSSID 0x0618
+#define REG_MAR 0x0620
+#define REG_MBIDCAMCFG 0x0628
+
+#define REG_USTIME_EDCA 0x0638
+#define REG_MAC_SPEC_SIFS 0x063A
+#define REG_RESP_SIFS_CCK 0x063C
+#define REG_RESP_SIFS_OFDM 0x063E
+#define REG_ACKTO 0x0640
+#define REG_CTS2TO 0x0641
+#define REG_EIFS 0x0642
+
+#define REG_NAV_CTRL 0x0650
+#define REG_BACAMCMD 0x0654
+#define REG_BACAMCONTENT 0x0658
+#define REG_LBDLY 0x0660
+#define REG_FWDLY 0x0661
+#define REG_RXERR_RPT 0x0664
+#define REG_WMAC_TRXPTCL_CTL 0x0668
+
+#define REG_CAMCMD 0x0670
+#define REG_CAMWRITE 0x0674
+#define REG_CAMREAD 0x0678
+#define REG_CAMDBG 0x067C
+#define REG_SECCFG 0x0680
+
+#define REG_WOW_CTRL 0x0690
+#define REG_PSSTATUS 0x0691
+#define REG_PS_RX_INFO 0x0692
+#define REG_LPNAV_CTRL 0x0694
+#define REG_WKFMCAM_CMD 0x0698
+#define REG_WKFMCAM_RWD 0x069C
+#define REG_RXFLTMAP0 0x06A0
+#define REG_RXFLTMAP1 0x06A2
+#define REG_RXFLTMAP2 0x06A4
+#define REG_BCN_PSR_RPT 0x06A8
+#define REG_CALB32K_CTRL 0x06AC
+#define REG_PKT_MON_CTRL 0x06B4
+#define REG_BT_COEX_TABLE 0x06C0
+#define REG_WMAC_RESP_TXINFO 0x06D8
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_TEST_USB_TXQS 0xFE48
+#define REG_TEST_SIE_VID 0xFE60
+#define REG_TEST_SIE_PID 0xFE62
+#define REG_TEST_SIE_OPTIONAL 0xFE64
+#define REG_TEST_SIE_CHIRP_K 0xFE65
+#define REG_TEST_SIE_PHY 0xFE66
+#define REG_TEST_SIE_MAC_ADDR 0xFE70
+#define REG_TEST_SIE_STRING 0xFE80
+
+#define REG_NORMAL_SIE_VID 0xFE60
+#define REG_NORMAL_SIE_PID 0xFE62
+#define REG_NORMAL_SIE_OPTIONAL 0xFE64
+#define REG_NORMAL_SIE_EP 0xFE65
+#define REG_NORMAL_SIE_PHY 0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR 0xFE70
+#define REG_NORMAL_SIE_STRING 0xFE80
+
+#define CR9346 REG_9346CR
+#define MSR (REG_CR + 2)
+#define ISR REG_HISR
+#define TSFR REG_TSFTR
+
+#define MACIDR0 REG_MACID
+#define MACIDR4 (REG_MACID + 4)
+
+#define PBP REG_PBP
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+#define UNUSED_REGISTER 0x1BF
+#define DCAM UNUSED_REGISTER
+#define PSR UNUSED_REGISTER
+#define BBADDR UNUSED_REGISTER
+#define PHYDATAR UNUSED_REGISTER
+
+#define INVALID_BBRF_VALUE 0x12345678
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define CMDEEPROM_EN BIT(5)
+#define CMDEEPROM_SEL BIT(4)
+#define CMD9346CR_9356SEL BIT(4)
+#define AUTOLOAD_EEPROM (CMDEEPROM_EN|CMDEEPROM_SEL)
+#define AUTOLOAD_EFUSE CMDEEPROM_EN
+
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_ENBT BIT(5)
+
+#define GPIO_IN REG_GPIO_PIN_CTRL
+#define GPIO_OUT (REG_GPIO_PIN_CTRL+1)
+#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2)
+#define GPIO_MOD (REG_GPIO_PIN_CTRL+3)
+
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_ACKSHORTPMB BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+#define RATE_1M BIT(0)
+#define RATE_2M BIT(1)
+#define RATE_5_5M BIT(2)
+#define RATE_11M BIT(3)
+#define RATE_6M BIT(4)
+#define RATE_9M BIT(5)
+#define RATE_12M BIT(6)
+#define RATE_18M BIT(7)
+#define RATE_24M BIT(8)
+#define RATE_36M BIT(9)
+#define RATE_48M BIT(10)
+#define RATE_54M BIT(11)
+#define RATE_MCS0 BIT(12)
+#define RATE_MCS1 BIT(13)
+#define RATE_MCS2 BIT(14)
+#define RATE_MCS3 BIT(15)
+#define RATE_MCS4 BIT(16)
+#define RATE_MCS5 BIT(17)
+#define RATE_MCS6 BIT(18)
+#define RATE_MCS7 BIT(19)
+#define RATE_MCS8 BIT(20)
+#define RATE_MCS9 BIT(21)
+#define RATE_MCS10 BIT(22)
+#define RATE_MCS11 BIT(23)
+#define RATE_MCS12 BIT(24)
+#define RATE_MCS13 BIT(25)
+#define RATE_MCS14 BIT(26)
+#define RATE_MCS15 BIT(27)
+
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M \
+ | RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
+ RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \
+ RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
+ RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define SCR_USEDK 0x01
+#define SCR_TXSEC_ENABLE 0x02
+#define SCR_RXSEC_ENABLE 0x04
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+#define IMR8190_DISABLED 0x0
+#define IMR_BCNDMAINT6 BIT(31)
+#define IMR_BCNDMAINT5 BIT(30)
+#define IMR_BCNDMAINT4 BIT(29)
+#define IMR_BCNDMAINT3 BIT(28)
+#define IMR_BCNDMAINT2 BIT(27)
+#define IMR_BCNDMAINT1 BIT(26)
+#define IMR_BCNDOK8 BIT(25)
+#define IMR_BCNDOK7 BIT(24)
+#define IMR_BCNDOK6 BIT(23)
+#define IMR_BCNDOK5 BIT(22)
+#define IMR_BCNDOK4 BIT(21)
+#define IMR_BCNDOK3 BIT(20)
+#define IMR_BCNDOK2 BIT(19)
+#define IMR_BCNDOK1 BIT(18)
+#define IMR_TIMEOUT2 BIT(17)
+#define IMR_TIMEOUT1 BIT(16)
+#define IMR_TXFOVW BIT(15)
+#define IMR_PSTIMEOUT BIT(14)
+#define IMR_BCNINT BIT(13)
+#define IMR_RXFOVW BIT(12)
+#define IMR_RDU BIT(11)
+#define IMR_ATIMEND BIT(10)
+#define IMR_BDOK BIT(9)
+#define IMR_HIGHDOK BIT(8)
+#define IMR_TBDOK BIT(7)
+#define IMR_MGNTDOK BIT(6)
+#define IMR_TBDER BIT(5)
+#define IMR_BKDOK BIT(4)
+#define IMR_BEDOK BIT(3)
+#define IMR_VIDOK BIT(2)
+#define IMR_VODOK BIT(1)
+#define IMR_ROK BIT(0)
+
+#define IMR_TXERR BIT(11)
+#define IMR_RXERR BIT(10)
+#define IMR_C2HCMD BIT(9)
+#define IMR_CPWM BIT(8)
+#define IMR_OCPINT BIT(1)
+#define IMR_WLANOFF BIT(0)
+
+#define HWSET_MAX_SIZE 128
+
+#define EEPROM_DEFAULT_TSSI 0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_BOARDTYPE 0x02
+#define EEPROM_DEFAULT_TXPOWER 0x1010
+#define EEPROM_DEFAULT_HT2T_TXPWR 0x10
+
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_THERMALMETER 0x12
+#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22
+#define EEPROM_DEFAULT_HT40_2SDIFF 0x0
+#define EEPROM_DEFAULT_HT20_DIFF 2
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0
+
+#define RF_OPTION1 0x79
+#define RF_OPTION2 0x7A
+#define RF_OPTION3 0x7B
+#define RF_OPTION4 0x7C
+
+#define EEPROM_DEFAULT_PID 0x1234
+#define EEPROM_DEFAULT_VID 0x5678
+#define EEPROM_DEFAULT_CUSTOMERID 0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID 0xCD
+#define EEPROM_DEFAULT_VERSION 0
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_TOSHIBA 0x4
+#define EEPROM_CID_CCX 0x10
+#define EEPROM_CID_QMI 0x0D
+#define EEPROM_CID_WHQL 0xFE
+
+#define RTL8192_EEPROM_ID 0x8129
+
+#define RTL8190_EEPROM_ID 0x8129
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+#define EEPROM_VID 0x0A
+#define EEPROM_DID 0x0C
+#define EEPROM_SVID 0x0E
+#define EEPROM_SMID 0x10
+
+#define EEPROM_MAC_ADDR 0x16
+
+#define EEPROM_CCK_TX_PWR_INX 0x5A
+#define EEPROM_HT40_1S_TX_PWR_INX 0x60
+#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66
+#define EEPROM_HT20_TX_PWR_INX_DIFF 0x69
+#define EEPROM_OFDM_TX_PWR_INX_DIFF 0x6C
+#define EEPROM_HT40_MAX_PWR_OFFSET 0x6F
+#define EEPROM_HT20_MAX_PWR_OFFSET 0x72
+
+#define EEPROM_TSSI_A 0x76
+#define EEPROM_TSSI_B 0x77
+#define EEPROM_THERMAL_METER 0x78
+#define EEPROM_XTAL_K 0x78
+#define EEPROM_RF_OPT1 0x79
+#define EEPROM_RF_OPT2 0x7A
+#define EEPROM_RF_OPT3 0x7B
+#define EEPROM_RF_OPT4 0x7C
+#define EEPROM_CHANNEL_PLAN 0x7D
+#define EEPROM_VERSION 0x7E
+#define EEPROM_CUSTOMER_ID 0x7F
+
+#define EEPROM_PWRDIFF 0x54
+
+#define EEPROM_TXPOWERCCK 0x5A
+#define EEPROM_TXPOWERHT40_1S 0x60
+#define EEPROM_TXPOWERHT40_2SDIFF 0x66
+#define EEPROM_TXPOWERHT20DIFF 0x69
+#define EEPROM_TXPOWER_OFDMDIFF 0x6C
+
+#define EEPROM_TXPWR_GROUP 0x6F
+
+#define EEPROM_TSSI_A 0x76
+#define EEPROM_TSSI_B 0x77
+#define EEPROM_THERMAL_METER 0x78
+
+#define EEPROM_CHANNELPLAN 0x75
+
+#define RF_OPTION1 0x79
+#define RF_OPTION2 0x7A
+#define RF_OPTION3 0x7B
+#define RF_OPTION4 0x7C
+
+#define STOPBECON BIT(6)
+#define STOPHIGHT BIT(5)
+#define STOPMGT BIT(4)
+#define STOPVO BIT(3)
+#define STOPVI BIT(2)
+#define STOPBE BIT(1)
+#define STOPBK BIT(0)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_APP_MIC BIT(30)
+#define RCR_APP_ICV BIT(29)
+#define RCR_APP_PHYST_RXFF BIT(28)
+#define RCR_APP_BA_SSN BIT(27)
+#define RCR_ENMBID BIT(24)
+#define RCR_LSIGEN BIT(23)
+#define RCR_MFBEN BIT(22)
+#define RCR_HTC_LOC_CTRL BIT(14)
+#define RCR_AMF BIT(13)
+#define RCR_ACF BIT(12)
+#define RCR_ADF BIT(11)
+#define RCR_AICV BIT(9)
+#define RCR_ACRC32 BIT(8)
+#define RCR_CBSSID_BCN BIT(7)
+#define RCR_CBSSID_DATA BIT(6)
+#define RCR_CBSSID RCR_CBSSID_DATA
+#define RCR_APWRMGT BIT(5)
+#define RCR_ADD3 BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+#define RSV_CTRL 0x001C
+#define RD_CTRL 0x0524
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_USB_VID 0xFE60
+#define REG_USB_PID 0xFE62
+#define REG_USB_OPTIONAL 0xFE64
+#define REG_USB_CHIRP_K 0xFE65
+#define REG_USB_PHY 0xFE66
+#define REG_USB_MAC_ADDR 0xFE70
+#define REG_USB_HRPWM 0xFE58
+#define REG_USB_HCPWM 0xFE57
+
+#define SW18_FPWM BIT(3)
+
+#define ISO_MD2PP BIT(0)
+#define ISO_UA2USB BIT(1)
+#define ISO_UD2CORE BIT(2)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PD2CORE BIT(4)
+#define ISO_IP2MAC BIT(5)
+#define ISO_DIOP BIT(6)
+#define ISO_DIOE BIT(7)
+#define ISO_EB2CORE BIT(8)
+#define ISO_DIOR BIT(9)
+
+#define PWC_EV25V BIT(14)
+#define PWC_EV12V BIT(15)
+
+#define FEN_BBRSTB BIT(0)
+#define FEN_BB_GLB_RSTn BIT(1)
+#define FEN_USBA BIT(2)
+#define FEN_UPLL BIT(3)
+#define FEN_USBD BIT(4)
+#define FEN_DIO_PCIE BIT(5)
+#define FEN_PCIEA BIT(6)
+#define FEN_PPLL BIT(7)
+#define FEN_PCIED BIT(8)
+#define FEN_DIOE BIT(9)
+#define FEN_CPUEN BIT(10)
+#define FEN_DCORE BIT(11)
+#define FEN_ELDR BIT(12)
+#define FEN_DIO_RF BIT(13)
+#define FEN_HWPDN BIT(14)
+#define FEN_MREGEN BIT(15)
+
+#define PFM_LDALL BIT(0)
+#define PFM_ALDN BIT(1)
+#define PFM_LDKP BIT(2)
+#define PFM_WOWL BIT(3)
+#define EnPDN BIT(4)
+#define PDN_PL BIT(5)
+#define APFM_ONMAC BIT(8)
+#define APFM_OFF BIT(9)
+#define APFM_RSM BIT(10)
+#define AFSM_HSUS BIT(11)
+#define AFSM_PCIE BIT(12)
+#define APDM_MAC BIT(13)
+#define APDM_HOST BIT(14)
+#define APDM_HPDN BIT(15)
+#define RDY_MACON BIT(16)
+#define SUS_HOST BIT(17)
+#define ROP_ALD BIT(20)
+#define ROP_PWR BIT(21)
+#define ROP_SPS BIT(22)
+#define SOP_MRST BIT(25)
+#define SOP_FUSE BIT(26)
+#define SOP_ABG BIT(27)
+#define SOP_AMB BIT(28)
+#define SOP_RCK BIT(29)
+#define SOP_A8M BIT(30)
+#define XOP_BTCK BIT(31)
+
+#define ANAD16V_EN BIT(0)
+#define ANA8M BIT(1)
+#define MACSLP BIT(4)
+#define LOADER_CLK_EN BIT(5)
+#define _80M_SSC_DIS BIT(7)
+#define _80M_SSC_EN_HO BIT(8)
+#define PHY_SSC_RSTB BIT(9)
+#define SEC_CLK_EN BIT(10)
+#define MAC_CLK_EN BIT(11)
+#define SYS_CLK_EN BIT(12)
+#define RING_CLK_EN BIT(13)
+
+#define BOOT_FROM_EEPROM BIT(4)
+#define EEPROM_EN BIT(5)
+
+#define AFE_BGEN BIT(0)
+#define AFE_MBEN BIT(1)
+#define MAC_ID_EN BIT(7)
+
+#define WLOCK_ALL BIT(0)
+#define WLOCK_00 BIT(1)
+#define WLOCK_04 BIT(2)
+#define WLOCK_08 BIT(3)
+#define WLOCK_40 BIT(4)
+#define R_DIS_PRST_0 BIT(5)
+#define R_DIS_PRST_1 BIT(6)
+#define LOCK_ALL_EN BIT(7)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+#define LDA15_STBY BIT(1)
+#define LDA15_OBUF BIT(2)
+#define LDA15_REG_VOS BIT(3)
+#define _LDA15_VOADJ(x) (((x) & 0x7) << 4)
+
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+#define LPLDO_HSM BIT(2)
+#define LPLDO_LSM_DIS BIT(3)
+#define _LDV12_VADJ(x) (((x) & 0xF) << 4)
+
+#define XTAL_EN BIT(0)
+#define XTAL_BSEL BIT(1)
+#define _XTAL_BOSC(x) (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x) (((x) & 0xF) << 4)
+#define XTAL_GATE_USB BIT(8)
+#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE BIT(11)
+#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12)
+#define XTAL_RF_GATE BIT(14)
+#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG BIT(17)
+#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18)
+#define XTAL_BT_GATE BIT(20)
+#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x) (((x) & 0x7) << 23)
+
+#define CKDLY_AFE BIT(26)
+#define CKDLY_USB BIT(27)
+#define CKDLY_DIG BIT(28)
+#define CKDLY_BT BIT(29)
+
+#define APLL_EN BIT(0)
+#define APLL_320_EN BIT(1)
+#define APLL_FREF_SEL BIT(2)
+#define APLL_EDGE_SEL BIT(3)
+#define APLL_WDOGB BIT(4)
+#define APLL_LPFEN BIT(5)
+
+#define APLL_REF_CLK_13MHZ 0x1
+#define APLL_REF_CLK_19_2MHZ 0x2
+#define APLL_REF_CLK_20MHZ 0x3
+#define APLL_REF_CLK_25MHZ 0x4
+#define APLL_REF_CLK_26MHZ 0x5
+#define APLL_REF_CLK_38_4MHZ 0x6
+#define APLL_REF_CLK_40MHZ 0x7
+
+#define APLL_320EN BIT(14)
+#define APLL_80EN BIT(15)
+#define APLL_1MEN BIT(24)
+
+#define ALD_EN BIT(18)
+#define EF_PD BIT(19)
+#define EF_FLAG BIT(31)
+
+#define EF_TRPT BIT(7)
+#define LDOE25_EN BIT(31)
+
+#define RSM_EN BIT(0)
+#define Timer_EN BIT(4)
+
+#define TRSW0EN BIT(2)
+#define TRSW1EN BIT(3)
+#define EROM_EN BIT(4)
+#define EnBT BIT(5)
+#define EnUart BIT(8)
+#define Uart_910 BIT(9)
+#define EnPMAC BIT(10)
+#define SIC_SWRST BIT(11)
+#define EnSIC BIT(12)
+#define SIC_23 BIT(13)
+#define EnHDP BIT(14)
+#define SIC_LBK BIT(15)
+
+#define LED0PL BIT(4)
+#define LED1PL BIT(12)
+#define LED0DIS BIT(7)
+
+#define MCUFWDL_EN BIT(0)
+#define MCUFWDL_RDY BIT(1)
+#define FWDL_ChkSum_rpt BIT(2)
+#define MACINI_RDY BIT(3)
+#define BBINI_RDY BIT(4)
+#define RFINI_RDY BIT(5)
+#define WINTINI_RDY BIT(6)
+#define CPRST BIT(23)
+
+#define XCLK_VLD BIT(0)
+#define ACLK_VLD BIT(1)
+#define UCLK_VLD BIT(2)
+#define PCLK_VLD BIT(3)
+#define PCIRSTB BIT(4)
+#define V15_VLD BIT(5)
+#define TRP_B15V_EN BIT(7)
+#define SIC_IDLE BIT(8)
+#define BD_MAC2 BIT(9)
+#define BD_MAC1 BIT(10)
+#define IC_MACPHY_MODE BIT(11)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23)
+#define TRP_BT_EN BIT(24)
+#define BD_PKG_SEL BIT(25)
+#define BD_HCI_SEL BIT(26)
+#define TYPE_ID BIT(27)
+
+#define CHIP_VER_RTL_MASK 0xF000
+#define CHIP_VER_RTL_SHIFT 12
+
+#define REG_LBMODE (REG_CR + 3)
+
+#define HCI_TXDMA_EN BIT(0)
+#define HCI_RXDMA_EN BIT(1)
+#define TXDMA_EN BIT(2)
+#define RXDMA_EN BIT(3)
+#define PROTOCOL_EN BIT(4)
+#define SCHEDULE_EN BIT(5)
+#define MACTXEN BIT(6)
+#define MACRXEN BIT(7)
+#define ENSWBCN BIT(8)
+#define ENSEC BIT(9)
+
+#define _NETTYPE(x) (((x) & 0x3) << 16)
+#define MASK_NETTYPE 0x30000
+#define NT_NO_LINK 0x0
+#define NT_LINK_AD_HOC 0x1
+#define NT_LINK_AP 0x2
+#define NT_AS_AP 0x3
+
+#define _LBMODE(x) (((x) & 0xF) << 24)
+#define MASK_LBMODE 0xF000000
+#define LOOPBACK_NORMAL 0x0
+#define LOOPBACK_IMMEDIATELY 0xB
+#define LOOPBACK_MAC_DELAY 0x3
+#define LOOPBACK_PHY 0x1
+#define LOOPBACK_DMA 0x7
+
+#define GET_RX_PAGE_SIZE(value) ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4)
+#define _PSRX_MASK 0xF
+#define _PSTX_MASK 0xF0
+#define _PSRX(x) (x)
+#define _PSTX(x) ((x) << 4)
+
+#define PBP_64 0x0
+#define PBP_128 0x1
+#define PBP_256 0x2
+#define PBP_512 0x3
+#define PBP_1024 0x4
+
+#define RXDMA_ARBBW_EN BIT(0)
+#define RXSHFT_EN BIT(1)
+#define RXDMA_AGG_EN BIT(2)
+#define QS_VO_QUEUE BIT(8)
+#define QS_VI_QUEUE BIT(9)
+#define QS_BE_QUEUE BIT(10)
+#define QS_BK_QUEUE BIT(11)
+#define QS_MANAGER_QUEUE BIT(12)
+#define QS_HIGH_QUEUE BIT(13)
+
+#define HQSEL_VOQ BIT(0)
+#define HQSEL_VIQ BIT(1)
+#define HQSEL_BEQ BIT(2)
+#define HQSEL_BKQ BIT(3)
+#define HQSEL_MGTQ BIT(4)
+#define HQSEL_HIQ BIT(5)
+
+#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4)
+
+#define QUEUE_LOW 1
+#define QUEUE_NORMAL 2
+#define QUEUE_HIGH 3
+
+#define _LLT_NO_ACTIVE 0x0
+#define _LLT_WRITE_ACCESS 0x1
+#define _LLT_READ_ACCESS 0x2
+
+#define _LLT_INIT_DATA(x) ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8)
+#define _LLT_OP(x) (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK (BIT(31) | BIT(30))
+#define BB_WRITE_EN BIT(30)
+#define BB_READ_EN BIT(31)
+
+#define _HPQ(x) ((x) & 0xFF)
+#define _LPQ(x) (((x) & 0xFF) << 8)
+#define _PUBQ(x) (((x) & 0xFF) << 16)
+#define _NPQ(x) ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS BIT(24)
+#define LPQ_PUBLIC_DIS BIT(25)
+#define LD_RQPN BIT(31)
+
+#define BCN_VALID BIT(16)
+#define BCN_HEAD(x) (((x) & 0xFF) << 8)
+#define BCN_HEAD_MASK 0xFF00
+
+#define BLK_DESC_NUM_SHIFT 4
+#define BLK_DESC_NUM_MASK 0xF
+
+#define DROP_DATA_EN BIT(9)
+
+#define EN_AMPDU_RTY_NEW BIT(7)
+
+#define _INIRTSMCS_SEL(x) ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x) ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL 0xFFFFF
+
+#define _RRSC_BITMAP(x) ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x) (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED 0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL 0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL 0x2
+#define RRSR_RSC_DUPLICATE_MODE 0x3
+
+#define USE_SHORT_G1 BIT(20)
+
+#define _AGGLMT_MCS0(x) ((x) & 0xF)
+#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define _DARF_RC1(x) ((x) & 0x1F)
+#define _DARF_RC2(x) (((x) & 0x1F) << 8)
+#define _DARF_RC3(x) (((x) & 0x1F) << 16)
+#define _DARF_RC4(x) (((x) & 0x1F) << 24)
+#define _DARF_RC5(x) ((x) & 0x1F)
+#define _DARF_RC6(x) (((x) & 0x1F) << 8)
+#define _DARF_RC7(x) (((x) & 0x1F) << 16)
+#define _DARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x) ((x) & 0x1F)
+#define _RARF_RC2(x) (((x) & 0x1F) << 8)
+#define _RARF_RC3(x) (((x) & 0x1F) << 16)
+#define _RARF_RC4(x) (((x) & 0x1F) << 24)
+#define _RARF_RC5(x) ((x) & 0x1F)
+#define _RARF_RC6(x) (((x) & 0x1F) << 8)
+#define _RARF_RC7(x) (((x) & 0x1F) << 16)
+#define _RARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define _AIFS(x) (x)
+#define _ECW_MAX_MIN(x) ((x) << 8)
+#define _TXOP_LIMIT(x) ((x) << 16)
+
+#define _BCNIFS(x) ((x) & 0xFF)
+#define _BCNECW(x) ((((x) & 0xF)) << 8)
+
+#define _LRL(x) ((x) & 0x3F)
+#define _SRL(x) (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x) ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8);
+
+#define _SIFS_OFDM_CTX(x) ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8);
+
+#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN BIT(11)
+
+#define EN_MBSSID BIT(1)
+#define EN_TXBCN_RPT BIT(2)
+#define EN_BCN_FUNCTION BIT(3)
+
+#define TSFTR_RST BIT(0)
+#define TSFTR1_RST BIT(1)
+
+#define STOP_BCNQ BIT(6)
+
+#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP BIT(5)
+
+#define AcmHw_HwEn BIT(0)
+#define AcmHw_BeqEn BIT(1)
+#define AcmHw_ViqEn BIT(2)
+#define AcmHw_VoqEn BIT(3)
+#define AcmHw_BeqStatus BIT(4)
+#define AcmHw_ViqStatus BIT(5)
+#define AcmHw_VoqStatus BIT(6)
+
+#define APSDOFF BIT(6)
+#define APSDOFF_STATUS BIT(7)
+
+#define BW_20MHZ BIT(2)
+
+#define RATE_BITMAP_ALL 0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1
+
+#define TSFRST BIT(0)
+#define DIS_GCLK BIT(1)
+#define PAD_SEL BIT(2)
+#define PWR_ST BIT(6)
+#define PWRBIT_OW_EN BIT(7)
+#define ACRC BIT(8)
+#define CFENDFORM BIT(9)
+#define ICV BIT(10)
+
+#define AAP BIT(0)
+#define APM BIT(1)
+#define AM BIT(2)
+#define AB BIT(3)
+#define ADD3 BIT(4)
+#define APWRMGT BIT(5)
+#define CBSSID BIT(6)
+#define CBSSID_DATA BIT(6)
+#define CBSSID_BCN BIT(7)
+#define ACRC32 BIT(8)
+#define AICV BIT(9)
+#define ADF BIT(11)
+#define ACF BIT(12)
+#define AMF BIT(13)
+#define HTC_LOC_CTRL BIT(14)
+#define UC_DATA_EN BIT(16)
+#define BM_DATA_EN BIT(17)
+#define MFBEN BIT(22)
+#define LSIGEN BIT(23)
+#define EnMBID BIT(24)
+#define APP_BASSN BIT(27)
+#define APP_PHYSTS BIT(28)
+#define APP_ICV BIT(29)
+#define APP_MIC BIT(30)
+#define APP_FCS BIT(31)
+
+#define _MIN_SPACE(x) ((x) & 0x7)
+#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU 0
+#define RXERR_TYPE_OFDM_FALSE_ALARM 1
+#define RXERR_TYPE_OFDM_MPDU_OK 2
+#define RXERR_TYPE_OFDM_MPDU_FAIL 3
+#define RXERR_TYPE_CCK_PPDU 4
+#define RXERR_TYPE_CCK_FALSE_ALARM 5
+#define RXERR_TYPE_CCK_MPDU_OK 6
+#define RXERR_TYPE_CCK_MPDU_FAIL 7
+#define RXERR_TYPE_HT_PPDU 8
+#define RXERR_TYPE_HT_FALSE_ALARM 9
+#define RXERR_TYPE_HT_MPDU_TOTAL 10
+#define RXERR_TYPE_HT_MPDU_OK 11
+#define RXERR_TYPE_HT_MPDU_FAIL 12
+#define RXERR_TYPE_RX_FULL_DROP 15
+
+#define RXERR_COUNTER_MASK 0xFFFFF
+#define RXERR_RPT_RST BIT(27)
+#define _RXERR_RPT_SEL(type) ((type) << 28)
+
+#define SCR_TxUseDK BIT(0)
+#define SCR_RxUseDK BIT(1)
+#define SCR_TxEncEnable BIT(2)
+#define SCR_RxDecEnable BIT(3)
+#define SCR_SKByA2 BIT(4)
+#define SCR_NoSKMC BIT(5)
+#define SCR_TXBCUSEDK BIT(6)
+#define SCR_RXBCUSEDK BIT(7)
+
+#define USB_IS_HIGH_SPEED 0
+#define USB_IS_FULL_SPEED 1
+#define USB_SPEED_MASK BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK 0xF
+#define USB_NORMAL_SIE_EP_SHIFT 4
+
+#define USB_TEST_EP_MASK 0x30
+#define USB_TEST_EP_SHIFT 4
+
+#define USB_AGG_EN BIT(3)
+
+#define MAC_ADDR_LEN 6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER 255
+
+#define POLLING_LLT_THRESHOLD 20
+#define POLLING_READY_TIMEOUT_COUNT 1000
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG 0x3
+#define EPROM_CMD_LOAD 1
+
+#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
+
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
+
+#define RPMAC_RESET 0x100
+#define RPMAC_TXSTART 0x104
+#define RPMAC_TXLEGACYSIG 0x108
+#define RPMAC_TXHTSIG1 0x10c
+#define RPMAC_TXHTSIG2 0x110
+#define RPMAC_PHYDEBUG 0x114
+#define RPMAC_TXPACKETNUM 0x118
+#define RPMAC_TXIDLE 0x11c
+#define RPMAC_TXMACHEADER0 0x120
+#define RPMAC_TXMACHEADER1 0x124
+#define RPMAC_TXMACHEADER2 0x128
+#define RPMAC_TXMACHEADER3 0x12c
+#define RPMAC_TXMACHEADER4 0x130
+#define RPMAC_TXMACHEADER5 0x134
+#define RPMAC_TXDADATYPE 0x138
+#define RPMAC_TXRANDOMSEED 0x13c
+#define RPMAC_CCKPLCPPREAMBLE 0x140
+#define RPMAC_CCKPLCPHEADER 0x144
+#define RPMAC_CCKCRC16 0x148
+#define RPMAC_OFDMRXCRC32OK 0x170
+#define RPMAC_OFDMRXCRC32Er 0x174
+#define RPMAC_OFDMRXPARITYER 0x178
+#define RPMAC_OFDMRXCRC8ER 0x17c
+#define RPMAC_CCKCRXRC16ER 0x180
+#define RPMAC_CCKCRXRC32ER 0x184
+#define RPMAC_CCKCRXRC32OK 0x188
+#define RPMAC_TXSTATUS 0x18c
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#define RFPGA0_XA_HSSIPARAMETER2 0x824
+#define RFPGA0_XB_HSSIPARAMETER1 0x828
+#define RFPGA0_XB_HSSIPARAMETER2 0x82c
+
+#define RFPGA0_XA_LSSIPARAMETER 0x840
+#define RFPGA0_XB_LSSIPARAMETER 0x844
+
+#define RFPGA0_RFWAKEUPPARAMETER 0x850
+#define RFPGA0_RFSLEEPUPPARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define rFPGA0_XAB_RFPARAMETER 0x878
+#define rFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVEA_HSPI_READBACK 0x8b8
+#define TRANSCEIVEB_HSPI_READBACK 0x8bc
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBALANCE 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBALANCE 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBANLANCE 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBALANCE 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFOANDDAGC 0xc44
+#define ROFDM0_CCADROPTHRESHOLD 0xc48
+#define ROFDM0_ECCATHRESHOLD 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#define ROFDM0_XAAGCCORE2 0xc54
+#define ROFDM0_XBAGCCORE1 0xc58
+#define ROFDM0_XBAGCCORE2 0xc5c
+#define ROFDM0_XCAGCCORE1 0xc60
+#define ROFDM0_XCAGCCORE2 0xc64
+#define ROFDM0_XDAGCCORE1 0xc68
+#define ROFDM0_XDAGCCORE2 0xc6c
+
+#define ROFDM0_AGCPARAMETER1 0xc70
+#define ROFDM0_AGCPARAMETER2 0xc74
+#define ROFDM0_AGCRSSITABLE 0xc78
+#define ROFDM0_HTSTFAGC 0xc7c
+
+#define ROFDM0_XATXIQIMBALANCE 0xc80
+#define ROFDM0_XATXAFE 0xc84
+#define ROFDM0_XBTXIQIMBALANCE 0xc88
+#define ROFDM0_XBTXAFE 0xc8c
+#define ROFDM0_XCTXIQIMBALANCE 0xc90
+#define ROFDM0_XCTXAFE 0xc94
+#define ROFDM0_XDTXIQIMBALANCE 0xc98
+#define ROFDM0_XDTXAFE 0xc9c
+
+#define ROFDM0_RXIQEXTANTA 0xca0
+
+#define ROFDM0_RXHPPARAMETER 0xce0
+#define ROFDM0_TXPSEUDONOISEWGT 0xce4
+#define ROFDM0_FRAMESYNC 0xcf0
+#define ROFDM0_DFSREPORT 0xcf4
+#define ROFDM0_TXCOEFF1 0xca4
+#define ROFDM0_TXCOEFF2 0xca8
+#define ROFDM0_TXCOEFF3 0xcac
+#define ROFDM0_TXCOEFF4 0xcb0
+#define ROFDM0_TXCOEFF5 0xcb4
+#define ROFDM0_TXCOEFF6 0xcb8
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CF0 0xd08
+#define ROFDM1_CSI1 0xd10
+#define ROFDM1_SBD 0xd14
+#define ROFDM1_CSI2 0xd18
+#define ROFDM1_CFOTRACKING 0xd2c
+#define ROFDM1_TRXMESAURE1 0xd34
+#define ROFDM1_INTFDET 0xd3c
+#define ROFDM1_PSEUDONOISESTATEAB 0xd50
+#define ROFDM1_PSEUDONOISESTATECD 0xd54
+#define ROFDM1_RXPSEUDONOISEWGT 0xd58
+
+#define ROFDM_PHYCOUNTER1 0xda0
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORTCFOAB 0xdac
+#define ROFDM_SHORTCFOCD 0xdb0
+#define ROFDM_LONGCFOAB 0xdb4
+#define ROFDM_LONGCFOCD 0xdb8
+#define ROFDM_TAILCF0AB 0xdbc
+#define ROFDM_TAILCF0CD 0xdc0
+#define ROFDM_PWMEASURE1 0xdc4
+#define ROFDM_PWMEASURE2 0xdc8
+#define ROFDM_BWREPORT 0xdcc
+#define ROFDM_AGCREPORT 0xdd0
+#define ROFDM_RXSNR 0xdd4
+#define ROFDM_RXEVMCSI 0xdd8
+#define ROFDM_SIGREPORT 0xddc
+
+#define RTXAGC_A_RATE18_06 0xe00
+#define RTXAGC_A_RATE54_24 0xe04
+#define RTXAGC_A_CCK1_MCS32 0xe08
+#define RTXAGC_A_MCS03_MCS00 0xe10
+#define RTXAGC_A_MCS07_MCS04 0xe14
+#define RTXAGC_A_MCS11_MCS08 0xe18
+#define RTXAGC_A_MCS15_MCS12 0xe1c
+
+#define RTXAGC_B_RATE18_06 0x830
+#define RTXAGC_B_RATE54_24 0x834
+#define RTXAGC_B_CCK1_55_MCS32 0x838
+#define RTXAGC_B_MCS03_MCS00 0x83c
+#define RTXAGC_B_MCS07_MCS04 0x848
+#define RTXAGC_B_MCS11_MCS08 0x84c
+#define RTXAGC_B_MCS15_MCS12 0x868
+#define RTXAGC_B_CCK11_A_CCK2_11 0x86c
+
+#define RZEBRA1_HSSIENABLE 0x0
+#define RZEBRA1_TRXENABLE1 0x1
+#define RZEBRA1_TRXENABLE2 0x2
+#define RZEBRA1_AGC 0x4
+#define RZEBRA1_CHARGEPUMP 0x5
+#define RZEBRA1_CHANNEL 0x7
+
+#define RZEBRA1_TXGAIN 0x8
+#define RZEBRA1_TXLPF 0x9
+#define RZEBRA1_RXLPF 0xb
+#define RZEBRA1_RXHPFCORNER 0xc
+
+#define RGLOBALCTRL 0
+#define RRTL8256_TXLPF 19
+#define RRTL8256_RXLPF 11
+#define RRTL8258_TXLPF 0x11
+#define RRTL8258_RXLPF 0x13
+#define RRTL8258_RSSILPF 0xa
+
+#define RF_AC 0x00
+
+#define RF_IQADJ_G1 0x01
+#define RF_IQADJ_G2 0x02
+#define RF_POW_TRSW 0x05
+
+#define RF_GAIN_RX 0x06
+#define RF_GAIN_TX 0x07
+
+#define RF_TXM_IDAC 0x08
+#define RF_BS_IQGEN 0x0F
+
+#define RF_MODE1 0x10
+#define RF_MODE2 0x11
+
+#define RF_RX_AGC_HP 0x12
+#define RF_TX_AGC 0x13
+#define RF_BIAS 0x14
+#define RF_IPA 0x15
+#define RF_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RRFCHANNEL 0x18
+#define RF_CHNLBW 0x18
+#define RF_TOP 0x19
+
+#define RF_RX_G1 0x1A
+#define RF_RX_G2 0x1B
+
+#define RF_RX_BB2 0x1C
+#define RF_RX_BB1 0x1D
+
+#define RF_RCK1 0x1E
+#define RF_RCK2 0x1F
+
+#define RF_TX_G1 0x20
+#define RF_TX_G2 0x21
+#define RF_TX_G3 0x22
+
+#define RF_TX_BB1 0x23
+#define RF_T_METER 0x24
+
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#define BBBRESETB 0x100
+#define BGLOBALRESETB 0x200
+#define BOFDMTXSTART 0x4
+#define BCCKTXSTART 0x8
+#define BCRC32DEBUG 0x100
+#define BPMACLOOPBACK 0x10
+#define BTXLSIG 0xffffff
+#define BOFDMTXRATE 0xf
+#define BOFDMTXRESERVED 0x10
+#define BOFDMTXLENGTH 0x1ffe0
+#define BOFDMTXPARITY 0x20000
+#define BTXHTSIG1 0xffffff
+#define BTXHTMCSRATE 0x7f
+#define BTXHTBW 0x80
+#define BTXHTLENGTH 0xffff00
+#define BTXHTSIG2 0xffffff
+#define BTXHTSMOOTHING 0x1
+#define BTXHTSOUNDING 0x2
+#define BTXHTRESERVED 0x4
+#define BTXHTAGGREATION 0x8
+#define BTXHTSTBC 0x30
+#define BTXHTADVANCECODING 0x40
+#define BTXHTSHORTGI 0x80
+#define BTXHTNUMBERHT_LT F 0x300
+#define BTXHTCRC8 0x3fc00
+#define BCOUNTERRESET 0x10000
+#define BNUMOFOFDMTX 0xffff
+#define BNUMOFCCKTX 0xffff0000
+#define BTXIDLEINTERVAL 0xffff
+#define BOFDMSERVICE 0xffff0000
+#define BTXMACHEADER 0xffffffff
+#define BTXDATAINIT 0xff
+#define BTXHTMODE 0x100
+#define BTXDATATYPE 0x30000
+#define BTXRANDOMSEED 0xffffffff
+#define BCCKTXPREAMBLE 0x1
+#define BCCKTXSFD 0xffff0000
+#define BCCKTXSIG 0xff
+#define BCCKTXSERVICE 0xff00
+#define BCCKLENGTHEXT 0x8000
+#define BCCKTXLENGHT 0xffff0000
+#define BCCKTXCRC16 0xffff
+#define BCCKTXSTATUS 0x1
+#define BOFDMTXSTATUS 0x2
+#define IS_BB_REG_OFFSET_92S(_Offset) \
+ ((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+#define BRFMOD 0x1
+#define BJAPANMODE 0x2
+#define BCCKTXSC 0x30
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BOFDMRXADCPHASE 0x10000
+#define BOFDMTXDACPHASE 0x40000
+#define BXATXAGC 0x3f
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define BPASTART 0xf0000000
+#define BTRSTART 0x00f00000
+#define BRFSTART 0x0000f000
+#define BBBSTART 0x000000f0
+#define BBBCCKSTART 0x0000000f
+#define BPAEND 0xf
+#define BTREND 0x0f000000
+#define BRFEND 0x000f0000
+#define BCCAMASK 0x000000f0
+#define BR2RCCAMASK 0x00000f00
+#define BHSSI_R2TDELAY 0xf8000000
+#define BHSSI_T2RDELAY 0xf80000
+#define BCONTXHSSI 0x400
+#define BIGFROMCCK 0x200
+#define BAGCADDRESS 0x3f
+#define BRXHPTX 0x7000
+#define BRXHP2RX 0x38000
+#define BRXHPCCKINI 0xc0000
+#define BAGCTXCODE 0xc00000
+#define BAGCRXCODE 0x300000
+
+#define B3WIREDATALENGTH 0x800
+#define B3WIREADDREAALENGTH 0x400
+
+#define B3WIRERFPOWERDOWN 0x1
+#define B5GPAPEPOLARITY 0x40000000
+#define B2GPAPEPOLARITY 0x80000000
+#define BRFSW_TXDEFAULTANT 0x3
+#define BRFSW_TXOPTIONANT 0x30
+#define BRFSW_RXDEFAULTANT 0x300
+#define BRFSW_RXOPTIONANT 0x3000
+#define BRFSI_3WIREDATA 0x1
+#define BRFSI_3WIRECLOCK 0x2
+#define BRFSI_3WIRELOAD 0x4
+#define BRFSI_3WIRERW 0x8
+#define BRFSI_3WIRE 0xf
+
+#define BRFSI_RFENV 0x10
+
+#define BRFSI_TRSW 0x20
+#define BRFSI_TRSWB 0x40
+#define BRFSI_ANTSW 0x100
+#define BRFSI_ANTSWB 0x200
+#define BRFSI_PAPE 0x400
+#define BRFSI_PAPE5G 0x800
+#define BBANDSELECT 0x1
+#define BHTSIG2_GI 0x80
+#define BHTSIG2_SMOOTHING 0x01
+#define BHTSIG2_SOUNDING 0x02
+#define BHTSIG2_AGGREATON 0x08
+#define BHTSIG2_STBC 0x30
+#define BHTSIG2_ADVCODING 0x40
+#define BHTSIG2_NUMOFHTLTF 0x300
+#define BHTSIG2_CRC8 0x3fc
+#define BHTSIG1_MCS 0x7f
+#define BHTSIG1_BANDWIDTH 0x80
+#define BHTSIG1_HTLENGTH 0xffff
+#define BLSIG_RATE 0xf
+#define BLSIG_RESERVED 0x10
+#define BLSIG_LENGTH 0x1fffe
+#define BLSIG_PARITY 0x20
+#define BCCKRXPHASE 0x4
+
+#define BLSSIREADADDRESS 0x7f800000
+#define BLSSIREADEDGE 0x80000000
+
+#define BLSSIREADBACKDATA 0xfffff
+
+#define BLSSIREADOKFLAG 0x1000
+#define BCCKSAMPLERATE 0x8
+#define BREGULATOR0STANDBY 0x1
+#define BREGULATORPLLSTANDBY 0x2
+#define BREGULATOR1STANDBY 0x4
+#define BPLLPOWERUP 0x8
+#define BDPLLPOWERUP 0x10
+#define BDA10POWERUP 0x20
+#define BAD7POWERUP 0x200
+#define BDA6POWERUP 0x2000
+#define BXTALPOWERUP 0x4000
+#define B40MDCLKPOWERUP 0x8000
+#define BDA6DEBUGMODE 0x20000
+#define BDA6SWING 0x380000
+
+#define BADCLKPHASE 0x4000000
+#define B80MCLKDELAY 0x18000000
+#define BAFEWATCHDOGENABLE 0x20000000
+
+#define BXTALCAP01 0xc0000000
+#define BXTALCAP23 0x3
+#define BXTALCAP92X 0x0f000000
+#define BXTALCAP 0x0f000000
+
+#define BINTDIFCLKENABLE 0x400
+#define BEXTSIGCLKENABLE 0x800
+#define BBANDGAP_MBIAS_POWERUP 0x10000
+#define BAD11SH_GAIN 0xc0000
+#define BAD11NPUT_RANGE 0x700000
+#define BAD110P_CURRENT 0x3800000
+#define BLPATH_LOOPBACK 0x4000000
+#define BQPATH_LOOPBACK 0x8000000
+#define BAFE_LOOPBACK 0x10000000
+#define BDA10_SWING 0x7e0
+#define BDA10_REVERSE 0x800
+#define BDA_CLK_SOURCE 0x1000
+#define BDA7INPUT_RANGE 0x6000
+#define BDA7_GAIN 0x38000
+#define BDA7OUTPUT_CM_MODE 0x40000
+#define BDA7INPUT_CM_MODE 0x380000
+#define BDA7CURRENT 0xc00000
+#define BREGULATOR_ADJUST 0x7000000
+#define BAD11POWERUP_ATTX 0x1
+#define BDA10PS_ATTX 0x10
+#define BAD11POWERUP_ATRX 0x100
+#define BDA10PS_ATRX 0x1000
+#define BCCKRX_AGC_FORMAT 0x200
+#define BPSDFFT_SAMPLE_POINT 0xc000
+#define BPSD_AVERAGE_NUM 0x3000
+#define BIQPATH_CONTROL 0xc00
+#define BPSD_FREQ 0x3ff
+#define BPSD_ANTENNA_PATH 0x30
+#define BPSD_IQ_SWITCH 0x40
+#define BPSD_RX_TRIGGER 0x400000
+#define BPSD_TX_TRIGGER 0x80000000
+#define BPSD_SINE_TONE_SCALE 0x7f000000
+#define BPSD_REPORT 0xffff
+
+#define BOFDM_TXSC 0x30000000
+#define BCCK_TXON 0x1
+#define BOFDM_TXON 0x2
+#define BDEBUG_PAGE 0xfff
+#define BDEBUG_ITEM 0xff
+#define BANTL 0x10
+#define BANT_NONHT 0x100
+#define BANT_HT1 0x1000
+#define BANT_HT2 0x10000
+#define BANT_HT1S1 0x100000
+#define BANT_NONHTS1 0x1000000
+
+#define BCCK_BBMODE 0x3
+#define BCCK_TXPOWERSAVING 0x80
+#define BCCK_RXPOWERSAVING 0x40
+
+#define BCCK_SIDEBAND 0x10
+
+#define BCCK_SCRAMBLE 0x8
+#define BCCK_ANTDIVERSITY 0x8000
+#define BCCK_CARRIER_RECOVERY 0x4000
+#define BCCK_TXRATE 0x3000
+#define BCCK_DCCANCEL 0x0800
+#define BCCK_ISICANCEL 0x0400
+#define BCCK_MATCH_FILTER 0x0200
+#define BCCK_EQUALIZER 0x0100
+#define BCCK_PREAMBLE_DETECT 0x800000
+#define BCCK_FAST_FALSECCA 0x400000
+#define BCCK_CH_ESTSTART 0x300000
+#define BCCK_CCA_COUNT 0x080000
+#define BCCK_CS_LIM 0x070000
+#define BCCK_BIST_MODE 0x80000000
+#define BCCK_CCAMASK 0x40000000
+#define BCCK_TX_DAC_PHASE 0x4
+#define BCCK_RX_ADC_PHASE 0x20000000
+#define BCCKR_CP_MODE 0x0100
+#define BCCK_TXDC_OFFSET 0xf0
+#define BCCK_RXDC_OFFSET 0xf
+#define BCCK_CCA_MODE 0xc000
+#define BCCK_FALSECS_LIM 0x3f00
+#define BCCK_CS_RATIO 0xc00000
+#define BCCK_CORGBIT_SEL 0x300000
+#define BCCK_PD_LIM 0x0f0000
+#define BCCK_NEWCCA 0x80000000
+#define BCCK_RXHP_OF_IG 0x8000
+#define BCCK_RXIG 0x7f00
+#define BCCK_LNA_POLARITY 0x800000
+#define BCCK_RX1ST_BAIN 0x7f0000
+#define BCCK_RF_EXTEND 0x20000000
+#define BCCK_RXAGC_SATLEVEL 0x1f000000
+#define BCCK_RXAGC_SATCOUNT 0xe0
+#define bCCKRxRFSettle 0x1f
+#define BCCK_FIXED_RXAGC 0x8000
+#define BCCK_ANTENNA_POLARITY 0x2000
+#define BCCK_TXFILTER_TYPE 0x0c00
+#define BCCK_RXAGC_REPORTTYPE 0x0300
+#define BCCK_RXDAGC_EN 0x80000000
+#define BCCK_RXDAGC_PERIOD 0x20000000
+#define BCCK_RXDAGC_SATLEVEL 0x1f000000
+#define BCCK_TIMING_RECOVERY 0x800000
+#define BCCK_TXC0 0x3f0000
+#define BCCK_TXC1 0x3f000000
+#define BCCK_TXC2 0x3f
+#define BCCK_TXC3 0x3f00
+#define BCCK_TXC4 0x3f0000
+#define BCCK_TXC5 0x3f000000
+#define BCCK_TXC6 0x3f
+#define BCCK_TXC7 0x3f00
+#define BCCK_DEBUGPORT 0xff0000
+#define BCCK_DAC_DEBUG 0x0f000000
+#define BCCK_FALSEALARM_ENABLE 0x8000
+#define BCCK_FALSEALARM_READ 0x4000
+#define BCCK_TRSSI 0x7f
+#define BCCK_RXAGC_REPORT 0xfe
+#define BCCK_RXREPORT_ANTSEL 0x80000000
+#define BCCK_RXREPORT_MFOFF 0x40000000
+#define BCCK_RXREPORT_SQLOSS 0x20000000
+#define BCCK_RXREPORT_PKTLOSS 0x10000000
+#define BCCK_RXREPORT_LOCKEDBIT 0x08000000
+#define BCCK_RXREPORT_RATEERROR 0x04000000
+#define BCCK_RXREPORT_RXRATE 0x03000000
+#define BCCK_RXFA_COUNTER_LOWER 0xff
+#define BCCK_RXFA_COUNTER_UPPER 0xff000000
+#define BCCK_RXHPAGC_START 0xe000
+#define BCCK_RXHPAGC_FINAL 0x1c00
+#define BCCK_RXFALSEALARM_ENABLE 0x8000
+#define BCCK_FACOUNTER_FREEZE 0x4000
+#define BCCK_TXPATH_SEL 0x10000000
+#define BCCK_DEFAULT_RXPATH 0xc000000
+#define BCCK_OPTION_RXPATH 0x3000000
+
+#define BNUM_OFSTF 0x3
+#define BSHIFT_L 0xc0
+#define BGI_TH 0xc
+#define BRXPATH_A 0x1
+#define BRXPATH_B 0x2
+#define BRXPATH_C 0x4
+#define BRXPATH_D 0x8
+#define BTXPATH_A 0x1
+#define BTXPATH_B 0x2
+#define BTXPATH_C 0x4
+#define BTXPATH_D 0x8
+#define BTRSSI_FREQ 0x200
+#define BADC_BACKOFF 0x3000
+#define BDFIR_BACKOFF 0xc000
+#define BTRSSI_LATCH_PHASE 0x10000
+#define BRX_LDC_OFFSET 0xff
+#define BRX_QDC_OFFSET 0xff00
+#define BRX_DFIR_MODE 0x1800000
+#define BRX_DCNF_TYPE 0xe000000
+#define BRXIQIMB_A 0x3ff
+#define BRXIQIMB_B 0xfc00
+#define BRXIQIMB_C 0x3f0000
+#define BRXIQIMB_D 0xffc00000
+#define BDC_DC_NOTCH 0x60000
+#define BRXNB_NOTCH 0x1f000000
+#define BPD_TH 0xf
+#define BPD_TH_OPT2 0xc000
+#define BPWED_TH 0x700
+#define BIFMF_WIN_L 0x800
+#define BPD_OPTION 0x1000
+#define BMF_WIN_L 0xe000
+#define BBW_SEARCH_L 0x30000
+#define BWIN_ENH_L 0xc0000
+#define BBW_TH 0x700000
+#define BED_TH2 0x3800000
+#define BBW_OPTION 0x4000000
+#define BRADIO_TH 0x18000000
+#define BWINDOW_L 0xe0000000
+#define BSBD_OPTION 0x1
+#define BFRAME_TH 0x1c
+#define BFS_OPTION 0x60
+#define BDC_SLOPE_CHECK 0x80
+#define BFGUARD_COUNTER_DC_L 0xe00
+#define BFRAME_WEIGHT_SHORT 0x7000
+#define BSUB_TUNE 0xe00000
+#define BFRAME_DC_LENGTH 0xe000000
+#define BSBD_START_OFFSET 0x30000000
+#define BFRAME_TH_2 0x7
+#define BFRAME_GI2_TH 0x38
+#define BGI2_SYNC_EN 0x40
+#define BSARCH_SHORT_EARLY 0x300
+#define BSARCH_SHORT_LATE 0xc00
+#define BSARCH_GI2_LATE 0x70000
+#define BCFOANTSUM 0x1
+#define BCFOACC 0x2
+#define BCFOSTARTOFFSET 0xc
+#define BCFOLOOPBACK 0x70
+#define BCFOSUMWEIGHT 0x80
+#define BDAGCENABLE 0x10000
+#define BTXIQIMB_A 0x3ff
+#define BTXIQIMB_b 0xfc00
+#define BTXIQIMB_C 0x3f0000
+#define BTXIQIMB_D 0xffc00000
+#define BTXIDCOFFSET 0xff
+#define BTXIQDCOFFSET 0xff00
+#define BTXDFIRMODE 0x10000
+#define BTXPESUDO_NOISEON 0x4000000
+#define BTXPESUDO_NOISE_A 0xff
+#define BTXPESUDO_NOISE_B 0xff00
+#define BTXPESUDO_NOISE_C 0xff0000
+#define BTXPESUDO_NOISE_D 0xff000000
+#define BCCA_DROPOPTION 0x20000
+#define BCCA_DROPTHRES 0xfff00000
+#define BEDCCA_H 0xf
+#define BEDCCA_L 0xf0
+#define BLAMBDA_ED 0x300
+#define BRX_INITIALGAIN 0x7f
+#define BRX_ANTDIV_EN 0x80
+#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00
+#define BRX_HIGHPOWER_FLOW 0x8000
+#define BRX_AGC_FREEZE_THRES 0xc0000
+#define BRX_FREEZESTEP_AGC1 0x300000
+#define BRX_FREEZESTEP_AGC2 0xc00000
+#define BRX_FREEZESTEP_AGC3 0x3000000
+#define BRX_FREEZESTEP_AGC0 0xc000000
+#define BRXRSSI_CMP_EN 0x10000000
+#define BRXQUICK_AGCEN 0x20000000
+#define BRXAGC_FREEZE_THRES_MODE 0x40000000
+#define BRX_OVERFLOW_CHECKTYPE 0x80000000
+#define BRX_AGCSHIFT 0x7f
+#define BTRSW_TRI_ONLY 0x80
+#define BPOWER_THRES 0x300
+#define BRXAGC_EN 0x1
+#define BRXAGC_TOGETHER_EN 0x2
+#define BRXAGC_MIN 0x4
+#define BRXHP_INI 0x7
+#define BRXHP_TRLNA 0x70
+#define BRXHP_RSSI 0x700
+#define BRXHP_BBP1 0x7000
+#define BRXHP_BBP2 0x70000
+#define BRXHP_BBP3 0x700000
+#define BRSSI_H 0x7f0000
+#define BRSSI_GEN 0x7f000000
+#define BRXSETTLE_TRSW 0x7
+#define BRXSETTLE_LNA 0x38
+#define BRXSETTLE_RSSI 0x1c0
+#define BRXSETTLE_BBP 0xe00
+#define BRXSETTLE_RXHP 0x7000
+#define BRXSETTLE_ANTSW_RSSI 0x38000
+#define BRXSETTLE_ANTSW 0xc0000
+#define BRXPROCESS_TIME_DAGC 0x300000
+#define BRXSETTLE_HSSI 0x400000
+#define BRXPROCESS_TIME_BBPPW 0x800000
+#define BRXANTENNA_POWER_SHIFT 0x3000000
+#define BRSSI_TABLE_SELECT 0xc000000
+#define BRXHP_FINAL 0x7000000
+#define BRXHPSETTLE_BBP 0x7
+#define BRXHTSETTLE_HSSI 0x8
+#define BRXHTSETTLE_RXHP 0x70
+#define BRXHTSETTLE_BBPPW 0x80
+#define BRXHTSETTLE_IDLE 0x300
+#define BRXHTSETTLE_RESERVED 0x1c00
+#define BRXHT_RXHP_EN 0x8000
+#define BRXAGC_FREEZE_THRES 0x30000
+#define BRXAGC_TOGETHEREN 0x40000
+#define BRXHTAGC_MIN 0x80000
+#define BRXHTAGC_EN 0x100000
+#define BRXHTDAGC_EN 0x200000
+#define BRXHT_RXHP_BBP 0x1c00000
+#define BRXHT_RXHP_FINAL 0xe0000000
+#define BRXPW_RADIO_TH 0x3
+#define BRXPW_RADIO_EN 0x4
+#define BRXMF_HOLD 0x3800
+#define BRXPD_DELAY_TH1 0x38
+#define BRXPD_DELAY_TH2 0x1c0
+#define BRXPD_DC_COUNT_MAX 0x600
+#define BRXPD_DELAY_TH 0x8000
+#define BRXPROCESS_DELAY 0xf0000
+#define BRXSEARCHRANGE_GI2_EARLY 0x700000
+#define BRXFRAME_FUARD_COUNTER_L 0x3800000
+#define BRXSGI_GUARD_L 0xc000000
+#define BRXSGI_SEARCH_L 0x30000000
+#define BRXSGI_TH 0xc0000000
+#define BDFSCNT0 0xff
+#define BDFSCNT1 0xff00
+#define BDFSFLAG 0xf0000
+#define BMF_WEIGHT_SUM 0x300000
+#define BMINIDX_TH 0x7f000000
+#define BDAFORMAT 0x40000
+#define BTXCH_EMU_ENABLE 0x01000000
+#define BTRSW_ISOLATION_A 0x7f
+#define BTRSW_ISOLATION_B 0x7f00
+#define BTRSW_ISOLATION_C 0x7f0000
+#define BTRSW_ISOLATION_D 0x7f000000
+#define BEXT_LNA_GAIN 0x7c00
+
+#define BSTBC_EN 0x4
+#define BANTENNA_MAPPING 0x10
+#define BNSS 0x20
+#define BCFO_ANTSUM_ID 0x200
+#define BPHY_COUNTER_RESET 0x8000000
+#define BCFO_REPORT_GET 0x4000000
+#define BOFDM_CONTINUE_TX 0x10000000
+#define BOFDM_SINGLE_CARRIER 0x20000000
+#define BOFDM_SINGLE_TONE 0x40000000
+#define BHT_DETECT 0x100
+#define BCFOEN 0x10000
+#define BCFOVALUE 0xfff00000
+#define BSIGTONE_RE 0x3f
+#define BSIGTONE_IM 0x7f00
+#define BCOUNTER_CCA 0xffff
+#define BCOUNTER_PARITYFAIL 0xffff0000
+#define BCOUNTER_RATEILLEGAL 0xffff
+#define BCOUNTER_CRC8FAIL 0xffff0000
+#define BCOUNTER_MCSNOSUPPORT 0xffff
+#define BCOUNTER_FASTSYNC 0xffff
+#define BSHORTCFO 0xfff
+#define BSHORTCFOT_LENGTH 12
+#define BSHORTCFOF_LENGTH 11
+#define BLONGCFO 0x7ff
+#define BLONGCFOT_LENGTH 11
+#define BLONGCFOF_LENGTH 11
+#define BTAILCFO 0x1fff
+#define BTAILCFOT_LENGTH 13
+#define BTAILCFOF_LENGTH 12
+#define BNOISE_EN_PWDB 0xffff
+#define BCC_POWER_DB 0xffff0000
+#define BMOISE_PWDB 0xffff
+#define BPOWERMEAST_LENGTH 10
+#define BPOWERMEASF_LENGTH 3
+#define BRX_HT_BW 0x1
+#define BRXSC 0x6
+#define BRX_HT 0x8
+#define BNB_INTF_DET_ON 0x1
+#define BINTF_WIN_LEN_CFG 0x30
+#define BNB_INTF_TH_CFG 0x1c0
+#define BRFGAIN 0x3f
+#define BTABLESEL 0x40
+#define BTRSW 0x80
+#define BRXSNR_A 0xff
+#define BRXSNR_B 0xff00
+#define BRXSNR_C 0xff0000
+#define BRXSNR_D 0xff000000
+#define BSNR_EVMT_LENGTH 8
+#define BSNR_EVMF_LENGTH 1
+#define BCSI1ST 0xff
+#define BCSI2ND 0xff00
+#define BRXEVM1ST 0xff0000
+#define BRXEVM2ND 0xff000000
+#define BSIGEVM 0xff
+#define BPWDB 0xff00
+#define BSGIEN 0x10000
+
+#define BSFACTOR_QMA1 0xf
+#define BSFACTOR_QMA2 0xf0
+#define BSFACTOR_QMA3 0xf00
+#define BSFACTOR_QMA4 0xf000
+#define BSFACTOR_QMA5 0xf0000
+#define BSFACTOR_QMA6 0xf0000
+#define BSFACTOR_QMA7 0xf00000
+#define BSFACTOR_QMA8 0xf000000
+#define BSFACTOR_QMA9 0xf0000000
+#define BCSI_SCHEME 0x100000
+
+#define BNOISE_LVL_TOP_SET 0x3
+#define BCHSMOOTH 0x4
+#define BCHSMOOTH_CFG1 0x38
+#define BCHSMOOTH_CFG2 0x1c0
+#define BCHSMOOTH_CFG3 0xe00
+#define BCHSMOOTH_CFG4 0x7000
+#define BMRCMODE 0x800000
+#define BTHEVMCFG 0x7000000
+
+#define BLOOP_FIT_TYPE 0x1
+#define BUPD_CFO 0x40
+#define BUPD_CFO_OFFDATA 0x80
+#define BADV_UPD_CFO 0x100
+#define BADV_TIME_CTRL 0x800
+#define BUPD_CLKO 0x1000
+#define BFC 0x6000
+#define BTRACKING_MODE 0x8000
+#define BPHCMP_ENABLE 0x10000
+#define BUPD_CLKO_LTF 0x20000
+#define BCOM_CH_CFO 0x40000
+#define BCSI_ESTI_MODE 0x80000
+#define BADV_UPD_EQZ 0x100000
+#define BUCHCFG 0x7000000
+#define BUPDEQZ 0x8000000
+
+#define BRX_PESUDO_NOISE_ON 0x20000000
+#define BRX_PESUDO_NOISE_A 0xff
+#define BRX_PESUDO_NOISE_B 0xff00
+#define BRX_PESUDO_NOISE_C 0xff0000
+#define BRX_PESUDO_NOISE_D 0xff000000
+#define BRX_PESUDO_NOISESTATE_A 0xffff
+#define BRX_PESUDO_NOISESTATE_B 0xffff0000
+#define BRX_PESUDO_NOISESTATE_C 0xffff
+#define BRX_PESUDO_NOISESTATE_D 0xffff0000
+
+#define BZEBRA1_HSSIENABLE 0x8
+#define BZEBRA1_TRXCONTROL 0xc00
+#define BZEBRA1_TRXGAINSETTING 0x07f
+#define BZEBRA1_RXCOUNTER 0xc00
+#define BZEBRA1_TXCHANGEPUMP 0x38
+#define BZEBRA1_RXCHANGEPUMP 0x7
+#define BZEBRA1_CHANNEL_NUM 0xf80
+#define BZEBRA1_TXLPFBW 0x400
+#define BZEBRA1_RXLPFBW 0x600
+
+#define BRTL8256REG_MODE_CTRL1 0x100
+#define BRTL8256REG_MODE_CTRL0 0x40
+#define BRTL8256REG_TXLPFBW 0x18
+#define BRTL8256REG_RXLPFBW 0x600
+
+#define BRTL8258_TXLPFBW 0xc
+#define BRTL8258_RXLPFBW 0xc00
+#define BRTL8258_RSSILPFBW 0xc0
+
+#define BBYTE0 0x1
+#define BBYTE1 0x2
+#define BBYTE2 0x4
+#define BBYTE3 0x8
+#define BWORD0 0x3
+#define BWORD1 0xc
+#define BWORD 0xf
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+#define MASK12BITS 0xfff
+#define MASKH4BITS 0xf0000000
+#define MASKOFDM_D 0xffc00000
+#define MASKCCK 0x3f3f3f3f
+
+#define MASK4BITS 0x0f
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#define BENABLE 0x1
+#define BDISABLE 0x0
+
+#define LEFT_ANTENNA 0x0
+#define RIGHT_ANTENNA 0x1
+
+#define TCHECK_TXSTATUS 500
+#define TUPDATE_RXCOUNTER 100
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
new file mode 100644
index 000000000000..ffd8e04c4028
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
@@ -0,0 +1,523 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | 0x0400);
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n", bandwidth));
+ break;
+ }
+}
+
+void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 tx_agc[2] = {0, 0}, tmpval;
+ bool turbo_scanoff = false;
+ u8 idx1, idx2;
+ u8 *ptr;
+
+ if (rtlefuse->eeprom_regulatory != 0)
+ turbo_scanoff = true;
+
+ if (mac->act_scanning == true) {
+ tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+ tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+ if (turbo_scanoff) {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = ppowerlevel[idx1] |
+ (ppowerlevel[idx1] << 8) |
+ (ppowerlevel[idx1] << 16) |
+ (ppowerlevel[idx1] << 24);
+ }
+ }
+ } else {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = ppowerlevel[idx1] |
+ (ppowerlevel[idx1] << 8) |
+ (ppowerlevel[idx1] << 16) |
+ (ppowerlevel[idx1] << 24);
+ }
+
+ if (rtlefuse->eeprom_regulatory == 0) {
+ tmpval =
+ (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
+ (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
+ 8);
+ tx_agc[RF90_PATH_A] += tmpval;
+
+ tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
+ (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
+ 24);
+ tx_agc[RF90_PATH_B] += tmpval;
+ }
+ }
+
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ ptr = (u8 *) (&(tx_agc[idx1]));
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if (*ptr > RF6052_MAX_TX_PWR)
+ *ptr = RF6052_MAX_TX_PWR;
+ ptr++;
+ }
+ }
+
+ tmpval = tx_agc[RF90_PATH_A] & 0xff;
+ rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_A_CCK1_MCS32));
+
+ tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+ if (mac->mode == WIRELESS_MODE_B)
+ tmpval = tmpval & 0xff00ffff;
+
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11));
+
+ tmpval = tx_agc[RF90_PATH_B] >> 24;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11));
+
+ tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK1_55_MCS32));
+}
+
+static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw,
+ u8 *ppowerlevel, u8 channel,
+ u32 *ofdmbase, u32 *mcsbase)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 powerBase0, powerBase1;
+ u8 legacy_pwrdiff, ht20_pwrdiff;
+ u8 i, powerlevel[2];
+
+ for (i = 0; i < 2; i++) {
+ powerlevel[i] = ppowerlevel[i];
+ legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];
+ powerBase0 = powerlevel[i] + legacy_pwrdiff;
+
+ powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
+ (powerBase0 << 8) | powerBase0;
+ *(ofdmbase + i) = powerBase0;
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ (" [OFDM power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(ofdmbase + i)));
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
+ ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];
+ powerlevel[i] += ht20_pwrdiff;
+ }
+ powerBase1 = powerlevel[i];
+ powerBase1 = (powerBase1 << 24) |
+ (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
+
+ *(mcsbase + i) = powerBase1;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ (" [MCS power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(mcsbase + i)));
+ }
+}
+
+static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
+ u8 channel, u8 index,
+ u32 *powerBase0,
+ u32 *powerBase1,
+ u32 *p_outwriteval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chnlgroup, pwr_diff_limit[4];
+ u32 writeVal, customer_limit, rf;
+
+ for (rf = 0; rf < 2; rf++) {
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ chnlgroup = 0;
+
+ writeVal =
+ rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
+ (rf ? 8 : 0)]
+ + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("RTK better performance, "
+ "writeVal(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ break;
+ case 1:
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ writeVal = ((index < 2) ? powerBase0[rf] :
+ powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Realtek regulatory, 40MHz, "
+ "writeVal(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ } else {
+ if (rtlphy->pwrgroup_cnt == 1)
+ chnlgroup = 0;
+ if (rtlphy->pwrgroup_cnt >= 3) {
+ if (channel <= 3)
+ chnlgroup = 0;
+ else if (channel >= 4 && channel <= 9)
+ chnlgroup = 1;
+ else if (channel > 9)
+ chnlgroup = 2;
+ if (rtlphy->pwrgroup_cnt == 4)
+ chnlgroup++;
+ }
+
+ writeVal =
+ rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+ [index + (rf ? 8 : 0)] + ((index < 2) ?
+ powerBase0[rf] :
+ powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Realtek regulatory, 20MHz, "
+ "writeVal(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ }
+ break;
+ case 2:
+ writeVal =
+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Better regulatory, "
+ "writeVal(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ break;
+ case 3:
+ chnlgroup = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("customer's limit, 40MHz "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht40[rf][channel -
+ 1]));
+ } else {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("customer's limit, 20MHz "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht20[rf][channel -
+ 1]));
+ }
+ for (i = 0; i < 4; i++) {
+ pwr_diff_limit[i] =
+ (u8) ((rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index +
+ (rf ? 8 : 0)] & (0x7f << (i * 8))) >>
+ (i * 8));
+
+ if (rtlphy->current_chan_bw ==
+ HT_CHANNEL_WIDTH_20_40) {
+ if (pwr_diff_limit[i] >
+ rtlefuse->
+ pwrgroup_ht40[rf][channel - 1])
+ pwr_diff_limit[i] =
+ rtlefuse->pwrgroup_ht40[rf]
+ [channel - 1];
+ } else {
+ if (pwr_diff_limit[i] >
+ rtlefuse->
+ pwrgroup_ht20[rf][channel - 1])
+ pwr_diff_limit[i] =
+ rtlefuse->pwrgroup_ht20[rf]
+ [channel - 1];
+ }
+ }
+
+ customer_limit = (pwr_diff_limit[3] << 24) |
+ (pwr_diff_limit[2] << 16) |
+ (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Customer's limit rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), customer_limit));
+
+ writeVal = customer_limit +
+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Customer, writeVal rf(%c)= 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ break;
+ default:
+ chnlgroup = 0;
+ writeVal =
+ rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+ [index + (rf ? 8 : 0)]
+ + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("RTK better performance, writeVal "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeVal));
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+ writeVal = writeVal - 0x06060606;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TXHIGHPWRLEVEL_BT2)
+ writeVal = writeVal - 0x0c0c0c0c;
+ *(p_outwriteval + rf) = writeVal;
+ }
+}
+
+static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
+ u8 index, u32 *pValue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ u16 regoffset_a[6] = {
+ RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
+ RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+ RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+ };
+ u16 regoffset_b[6] = {
+ RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
+ RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+ RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+ };
+ u8 i, rf, pwr_val[4];
+ u32 writeVal;
+ u16 regoffset;
+
+ for (rf = 0; rf < 2; rf++) {
+ writeVal = pValue[rf];
+ for (i = 0; i < 4; i++) {
+ pwr_val[i] = (u8) ((writeVal & (0x7f <<
+ (i * 8))) >> (i * 8));
+
+ if (pwr_val[i] > RF6052_MAX_TX_PWR)
+ pwr_val[i] = RF6052_MAX_TX_PWR;
+ }
+ writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+ (pwr_val[1] << 8) | pwr_val[0];
+
+ if (rf == 0)
+ regoffset = regoffset_a[index];
+ else
+ regoffset = regoffset_b[index];
+ rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ ("Set 0x%x = %08x\n", regoffset, writeVal));
+
+ if (((get_rf_type(rtlphy) == RF_2T2R) &&
+ (regoffset == RTXAGC_A_MCS15_MCS12 ||
+ regoffset == RTXAGC_B_MCS15_MCS12)) ||
+ ((get_rf_type(rtlphy) != RF_2T2R) &&
+ (regoffset == RTXAGC_A_MCS07_MCS04 ||
+ regoffset == RTXAGC_B_MCS07_MCS04))) {
+
+ writeVal = pwr_val[3];
+ if (regoffset == RTXAGC_A_MCS15_MCS12 ||
+ regoffset == RTXAGC_A_MCS07_MCS04)
+ regoffset = 0xc90;
+ if (regoffset == RTXAGC_B_MCS15_MCS12 ||
+ regoffset == RTXAGC_B_MCS07_MCS04)
+ regoffset = 0xc98;
+
+ for (i = 0; i < 3; i++) {
+ writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
+ rtl_write_byte(rtlpriv, (u32) (regoffset + i),
+ (u8) writeVal);
+ }
+ }
+ }
+}
+
+void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel, u8 channel)
+{
+ u32 writeVal[2], powerBase0[2], powerBase1[2];
+ u8 index;
+
+ rtl92c_phy_get_power_base(hw, ppowerlevel,
+ channel, &powerBase0[0], &powerBase1[0]);
+
+ for (index = 0; index < 6; index++) {
+ _rtl92c_get_txpower_writeval_by_regulatory(hw,
+ channel, index,
+ &powerBase0[0],
+ &powerBase1[0],
+ &writeVal[0]);
+
+ _rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]);
+ }
+}
+
+bool rtl92c_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ return _rtl92c_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 u4_regvalue;
+ u8 rfpath;
+ bool rtstatus;
+ struct bb_reg_def *pphyreg;
+
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+ B3WIREADDREAALENGTH, 0x0);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+ udelay(1);
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+ (enum radio_path) rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+ (enum radio_path) rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl_set_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV, u4_regvalue);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl_set_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16, u4_regvalue);
+ break;
+ }
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Radio[%d] Fail!!", rfpath));
+ return false;
+ }
+
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("<---\n"));
+ return rtstatus;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
new file mode 100644
index 000000000000..d3014f99bb7b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_RF_H__
+#define __RTL92C_RF_H__
+
+#define RF6052_MAX_TX_PWR 0x3F
+#define RF6052_MAX_REG 0x3F
+#define RF6052_MAX_PATH 2
+
+extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel, u8 channel);
+extern bool rtl92c_phy_rf6052_config(struct ieee80211_hw *hw);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
new file mode 100644
index 000000000000..b366e8862929
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -0,0 +1,282 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/vmalloc.h>
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+
+int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtlpriv->dm.b_dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.b_disable_framebursting = 0;;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13);
+
+ rtlpci->receive_config = (RCR_APPFCS |
+ RCR_AMF |
+ RCR_ADF |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_AICV |
+ RCR_ACRC32 |
+ RCR_AB |
+ RCR_AM |
+ RCR_APM |
+ RCR_APP_PHYST_RXFF | RCR_HTC_LOC_CTRL | 0);
+
+ rtlpci->irq_mask[0] =
+ (u32) (IMR_ROK |
+ IMR_VODOK |
+ IMR_VIDOK |
+ IMR_BEDOK |
+ IMR_BKDOK |
+ IMR_MGNTDOK |
+ IMR_HIGHDOK | IMR_BDOK | IMR_RDU | IMR_RXFOVW | 0);
+
+ rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0);
+
+ rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000);
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't alloc buffer for fw.\n"));
+ return 1;
+ }
+
+ return 0;
+}
+
+void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+}
+
+static struct rtl_hal_ops rtl8192ce_hal_ops = {
+ .init_sw_vars = rtl92c_init_sw_vars,
+ .deinit_sw_vars = rtl92c_deinit_sw_vars,
+ .read_eeprom_info = rtl92ce_read_eeprom_info,
+ .interrupt_recognized = rtl92ce_interrupt_recognized,
+ .hw_init = rtl92ce_hw_init,
+ .hw_disable = rtl92ce_card_disable,
+ .enable_interrupt = rtl92ce_enable_interrupt,
+ .disable_interrupt = rtl92ce_disable_interrupt,
+ .set_network_type = rtl92ce_set_network_type,
+ .set_qos = rtl92ce_set_qos,
+ .set_bcn_reg = rtl92ce_set_beacon_related_registers,
+ .set_bcn_intv = rtl92ce_set_beacon_interval,
+ .update_interrupt_mask = rtl92ce_update_interrupt_mask,
+ .get_hw_reg = rtl92ce_get_hw_reg,
+ .set_hw_reg = rtl92ce_set_hw_reg,
+ .update_rate_table = rtl92ce_update_hal_rate_table,
+ .update_rate_mask = rtl92ce_update_hal_rate_mask,
+ .fill_tx_desc = rtl92ce_tx_fill_desc,
+ .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc,
+ .query_rx_desc = rtl92ce_rx_query_desc,
+ .set_channel_access = rtl92ce_update_channel_access_setting,
+ .radio_onoff_checking = rtl92ce_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl92c_phy_set_bw_mode,
+ .switch_channel = rtl92c_phy_sw_chnl,
+ .dm_watchdog = rtl92c_dm_watchdog,
+ .scan_operation_backup = rtl92c_phy_scan_operation_backup,
+ .set_rf_power_state = rtl92c_phy_set_rf_power_state,
+ .led_control = rtl92ce_led_control,
+ .set_desc = rtl92ce_set_desc,
+ .get_desc = rtl92ce_get_desc,
+ .tx_polling = rtl92ce_tx_polling,
+ .enable_hw_sec = rtl92ce_enable_hw_security_config,
+ .set_key = rtl92ce_set_key,
+ .init_sw_leds = rtl92ce_init_sw_leds,
+ .deinit_sw_leds = rtl92ce_deinit_sw_leds,
+ .get_bbreg = rtl92c_phy_query_bb_reg,
+ .set_bbreg = rtl92c_phy_set_bb_reg,
+ .get_rfreg = rtl92c_phy_query_rf_reg,
+ .set_rfreg = rtl92c_phy_set_rf_reg,
+};
+
+static struct rtl_mod_params rtl92ce_mod_params = {
+ .sw_crypto = 0,
+};
+
+static struct rtl_hal_cfg rtl92ce_hal_cfg = {
+ .name = "rtl92c_pci",
+ .fw_name = "rtlwifi/rtl8192cfw.bin",
+ .ops = &rtl8192ce_hal_ops,
+ .mod_params = &rtl92ce_mod_params,
+
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = REG_SYS_CLKR,
+ .maps[MAC_RCR_AM] = AM,
+ .maps[MAC_RCR_AB] = AB,
+ .maps[MAC_RCR_ACRC32] = ACRC32,
+ .maps[MAC_RCR_ACF] = ACF,
+ .maps[MAC_RCR_AAP] = AAP,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = 0,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+ .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+ .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+ .maps[EFUSE_ANA8M] = EFUSE_ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+
+ .maps[RWCAM] = REG_CAMCMD,
+ .maps[WCAMI] = REG_CAMWRITE,
+ .maps[RCAMO] = REG_CAMREAD,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECCFG,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+ .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+ .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,
+ .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BDOK,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8176, rtl92ce_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl92ce_pci_ids);
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin");
+
+module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444);
+MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+
+static struct pci_driver rtl92ce_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl92ce_pci_ids,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+
+#ifdef CONFIG_PM
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+#endif
+
+};
+
+static int __init rtl92ce_module_init(void)
+{
+ int ret;
+
+ ret = pci_register_driver(&rtl92ce_driver);
+ if (ret)
+ RT_ASSERT(false, (": No device found\n"));
+
+ return ret;
+}
+
+static void __exit rtl92ce_module_exit(void)
+{
+ pci_unregister_driver(&rtl92ce_driver);
+}
+
+module_init(rtl92ce_module_init);
+module_exit(rtl92ce_module_exit);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
new file mode 100644
index 000000000000..de1198c38d4e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_SW_H__
+#define __RTL92CE_SW_H__
+
+int rtl92c_init_sw_vars(struct ieee80211_hw *hw);
+void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl92c_init_var_map(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/table.c b/drivers/net/wireless/rtlwifi/rtl8192ce/table.c
new file mode 100644
index 000000000000..ba938b91aa6f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/table.c
@@ -0,0 +1,1224 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+
+
+u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH] = {
+ 0x024, 0x0011800f,
+ 0x028, 0x00ffdb83,
+ 0x800, 0x80040002,
+ 0x804, 0x00000003,
+ 0x808, 0x0000fc00,
+ 0x80c, 0x0000000a,
+ 0x810, 0x10005388,
+ 0x814, 0x020c3d10,
+ 0x818, 0x02200385,
+ 0x81c, 0x00000000,
+ 0x820, 0x01000100,
+ 0x824, 0x00390004,
+ 0x828, 0x01000100,
+ 0x82c, 0x00390004,
+ 0x830, 0x27272727,
+ 0x834, 0x27272727,
+ 0x838, 0x27272727,
+ 0x83c, 0x27272727,
+ 0x840, 0x00010000,
+ 0x844, 0x00010000,
+ 0x848, 0x27272727,
+ 0x84c, 0x27272727,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x569a569a,
+ 0x85c, 0x0c1b25a4,
+ 0x860, 0x66e60230,
+ 0x864, 0x061f0130,
+ 0x868, 0x27272727,
+ 0x86c, 0x2b2b2b27,
+ 0x870, 0x07000700,
+ 0x874, 0x22184000,
+ 0x878, 0x08080808,
+ 0x87c, 0x00000000,
+ 0x880, 0xc0083070,
+ 0x884, 0x000004d5,
+ 0x888, 0x00000000,
+ 0x88c, 0xcc0000c0,
+ 0x890, 0x00000800,
+ 0x894, 0xfffffffe,
+ 0x898, 0x40302010,
+ 0x89c, 0x00706050,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90c, 0x81121313,
+ 0xa00, 0x00d047c8,
+ 0xa04, 0x80ff000c,
+ 0xa08, 0x8c838300,
+ 0xa0c, 0x2e68120f,
+ 0xa10, 0x9500bb78,
+ 0xa14, 0x11144028,
+ 0xa18, 0x00881117,
+ 0xa1c, 0x89140f00,
+ 0xa20, 0x1a1b0000,
+ 0xa24, 0x090e1317,
+ 0xa28, 0x00000204,
+ 0xa2c, 0x00d30000,
+ 0xa70, 0x101fbf00,
+ 0xa74, 0x00000007,
+ 0xc00, 0x48071d40,
+ 0xc04, 0x03a05633,
+ 0xc08, 0x000000e4,
+ 0xc0c, 0x6c6c6c6c,
+ 0xc10, 0x08800000,
+ 0xc14, 0x40000100,
+ 0xc18, 0x08800000,
+ 0xc1c, 0x40000100,
+ 0xc20, 0x00000000,
+ 0xc24, 0x00000000,
+ 0xc28, 0x00000000,
+ 0xc2c, 0x00000000,
+ 0xc30, 0x69e9ac44,
+ 0xc34, 0x469652cf,
+ 0xc38, 0x49795994,
+ 0xc3c, 0x0a97971c,
+ 0xc40, 0x1f7c403f,
+ 0xc44, 0x000100b7,
+ 0xc48, 0xec020107,
+ 0xc4c, 0x007f037f,
+ 0xc50, 0x69543420,
+ 0xc54, 0x43bc0094,
+ 0xc58, 0x69543420,
+ 0xc5c, 0x433c0094,
+ 0xc60, 0x00000000,
+ 0xc64, 0x5116848b,
+ 0xc68, 0x47c00bff,
+ 0xc6c, 0x00000036,
+ 0xc70, 0x2c7f000d,
+ 0xc74, 0x018610db,
+ 0xc78, 0x0000001f,
+ 0xc7c, 0x00b91612,
+ 0xc80, 0x40000100,
+ 0xc84, 0x20f60000,
+ 0xc88, 0x40000100,
+ 0xc8c, 0x20200000,
+ 0xc90, 0x00121820,
+ 0xc94, 0x00000000,
+ 0xc98, 0x00121820,
+ 0xc9c, 0x00007f7f,
+ 0xca0, 0x00000000,
+ 0xca4, 0x00000080,
+ 0xca8, 0x00000000,
+ 0xcac, 0x00000000,
+ 0xcb0, 0x00000000,
+ 0xcb4, 0x00000000,
+ 0xcb8, 0x00000000,
+ 0xcbc, 0x28000000,
+ 0xcc0, 0x00000000,
+ 0xcc4, 0x00000000,
+ 0xcc8, 0x00000000,
+ 0xccc, 0x00000000,
+ 0xcd0, 0x00000000,
+ 0xcd4, 0x00000000,
+ 0xcd8, 0x64b22427,
+ 0xcdc, 0x00766932,
+ 0xce0, 0x00222222,
+ 0xce4, 0x00000000,
+ 0xce8, 0x37644302,
+ 0xcec, 0x2f97d40c,
+ 0xd00, 0x00080740,
+ 0xd04, 0x00020403,
+ 0xd08, 0x0000907f,
+ 0xd0c, 0x20010201,
+ 0xd10, 0xa0633333,
+ 0xd14, 0x3333bc43,
+ 0xd18, 0x7a8f5b6b,
+ 0xd2c, 0xcc979975,
+ 0xd30, 0x00000000,
+ 0xd34, 0x80608000,
+ 0xd38, 0x00000000,
+ 0xd3c, 0x00027293,
+ 0xd40, 0x00000000,
+ 0xd44, 0x00000000,
+ 0xd48, 0x00000000,
+ 0xd4c, 0x00000000,
+ 0xd50, 0x6437140a,
+ 0xd54, 0x00000000,
+ 0xd58, 0x00000000,
+ 0xd5c, 0x30032064,
+ 0xd60, 0x4653de68,
+ 0xd64, 0x04518a3c,
+ 0xd68, 0x00002101,
+ 0xd6c, 0x2a201c16,
+ 0xd70, 0x1812362e,
+ 0xd74, 0x322c2220,
+ 0xd78, 0x000e3c24,
+ 0xe00, 0x2a2a2a2a,
+ 0xe04, 0x2a2a2a2a,
+ 0xe08, 0x03902a2a,
+ 0xe10, 0x2a2a2a2a,
+ 0xe14, 0x2a2a2a2a,
+ 0xe18, 0x2a2a2a2a,
+ 0xe1c, 0x2a2a2a2a,
+ 0xe28, 0x00000000,
+ 0xe30, 0x1000dc1f,
+ 0xe34, 0x10008c1f,
+ 0xe38, 0x02140102,
+ 0xe3c, 0x681604c2,
+ 0xe40, 0x01007c00,
+ 0xe44, 0x01004800,
+ 0xe48, 0xfb000000,
+ 0xe4c, 0x000028d1,
+ 0xe50, 0x1000dc1f,
+ 0xe54, 0x10008c1f,
+ 0xe58, 0x02140102,
+ 0xe5c, 0x28160d05,
+ 0xe60, 0x00000010,
+ 0xe68, 0x001b25a4,
+ 0xe6c, 0x63db25a4,
+ 0xe70, 0x63db25a4,
+ 0xe74, 0x0c1b25a4,
+ 0xe78, 0x0c1b25a4,
+ 0xe7c, 0x0c1b25a4,
+ 0xe80, 0x0c1b25a4,
+ 0xe84, 0x63db25a4,
+ 0xe88, 0x0c1b25a4,
+ 0xe8c, 0x63db25a4,
+ 0xed0, 0x63db25a4,
+ 0xed4, 0x63db25a4,
+ 0xed8, 0x63db25a4,
+ 0xedc, 0x001b25a4,
+ 0xee0, 0x001b25a4,
+ 0xeec, 0x6fdb25a4,
+ 0xf14, 0x00000003,
+ 0xf4c, 0x00000000,
+ 0xf00, 0x00000300,
+};
+
+u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH] = {
+ 0x024, 0x0011800f,
+ 0x028, 0x00ffdb83,
+ 0x800, 0x80040000,
+ 0x804, 0x00000001,
+ 0x808, 0x0000fc00,
+ 0x80c, 0x0000000a,
+ 0x810, 0x10005388,
+ 0x814, 0x020c3d10,
+ 0x818, 0x02200385,
+ 0x81c, 0x00000000,
+ 0x820, 0x01000100,
+ 0x824, 0x00390004,
+ 0x828, 0x00000000,
+ 0x82c, 0x00000000,
+ 0x830, 0x00000000,
+ 0x834, 0x00000000,
+ 0x838, 0x00000000,
+ 0x83c, 0x00000000,
+ 0x840, 0x00010000,
+ 0x844, 0x00000000,
+ 0x848, 0x00000000,
+ 0x84c, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x569a569a,
+ 0x85c, 0x001b25a4,
+ 0x860, 0x66e60230,
+ 0x864, 0x061f0130,
+ 0x868, 0x00000000,
+ 0x86c, 0x32323200,
+ 0x870, 0x07000700,
+ 0x874, 0x22004000,
+ 0x878, 0x00000808,
+ 0x87c, 0x00000000,
+ 0x880, 0xc0083070,
+ 0x884, 0x000004d5,
+ 0x888, 0x00000000,
+ 0x88c, 0xccc000c0,
+ 0x890, 0x00000800,
+ 0x894, 0xfffffffe,
+ 0x898, 0x40302010,
+ 0x89c, 0x00706050,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90c, 0x81121111,
+ 0xa00, 0x00d047c8,
+ 0xa04, 0x80ff000c,
+ 0xa08, 0x8c838300,
+ 0xa0c, 0x2e68120f,
+ 0xa10, 0x9500bb78,
+ 0xa14, 0x11144028,
+ 0xa18, 0x00881117,
+ 0xa1c, 0x89140f00,
+ 0xa20, 0x1a1b0000,
+ 0xa24, 0x090e1317,
+ 0xa28, 0x00000204,
+ 0xa2c, 0x00d30000,
+ 0xa70, 0x101fbf00,
+ 0xa74, 0x00000007,
+ 0xc00, 0x48071d40,
+ 0xc04, 0x03a05611,
+ 0xc08, 0x000000e4,
+ 0xc0c, 0x6c6c6c6c,
+ 0xc10, 0x08800000,
+ 0xc14, 0x40000100,
+ 0xc18, 0x08800000,
+ 0xc1c, 0x40000100,
+ 0xc20, 0x00000000,
+ 0xc24, 0x00000000,
+ 0xc28, 0x00000000,
+ 0xc2c, 0x00000000,
+ 0xc30, 0x69e9ac44,
+ 0xc34, 0x469652cf,
+ 0xc38, 0x49795994,
+ 0xc3c, 0x0a97971c,
+ 0xc40, 0x1f7c403f,
+ 0xc44, 0x000100b7,
+ 0xc48, 0xec020107,
+ 0xc4c, 0x007f037f,
+ 0xc50, 0x69543420,
+ 0xc54, 0x43bc0094,
+ 0xc58, 0x69543420,
+ 0xc5c, 0x433c0094,
+ 0xc60, 0x00000000,
+ 0xc64, 0x5116848b,
+ 0xc68, 0x47c00bff,
+ 0xc6c, 0x00000036,
+ 0xc70, 0x2c7f000d,
+ 0xc74, 0x018610db,
+ 0xc78, 0x0000001f,
+ 0xc7c, 0x00b91612,
+ 0xc80, 0x40000100,
+ 0xc84, 0x20f60000,
+ 0xc88, 0x40000100,
+ 0xc8c, 0x20200000,
+ 0xc90, 0x00121820,
+ 0xc94, 0x00000000,
+ 0xc98, 0x00121820,
+ 0xc9c, 0x00007f7f,
+ 0xca0, 0x00000000,
+ 0xca4, 0x00000080,
+ 0xca8, 0x00000000,
+ 0xcac, 0x00000000,
+ 0xcb0, 0x00000000,
+ 0xcb4, 0x00000000,
+ 0xcb8, 0x00000000,
+ 0xcbc, 0x28000000,
+ 0xcc0, 0x00000000,
+ 0xcc4, 0x00000000,
+ 0xcc8, 0x00000000,
+ 0xccc, 0x00000000,
+ 0xcd0, 0x00000000,
+ 0xcd4, 0x00000000,
+ 0xcd8, 0x64b22427,
+ 0xcdc, 0x00766932,
+ 0xce0, 0x00222222,
+ 0xce4, 0x00000000,
+ 0xce8, 0x37644302,
+ 0xcec, 0x2f97d40c,
+ 0xd00, 0x00080740,
+ 0xd04, 0x00020401,
+ 0xd08, 0x0000907f,
+ 0xd0c, 0x20010201,
+ 0xd10, 0xa0633333,
+ 0xd14, 0x3333bc43,
+ 0xd18, 0x7a8f5b6b,
+ 0xd2c, 0xcc979975,
+ 0xd30, 0x00000000,
+ 0xd34, 0x80608000,
+ 0xd38, 0x00000000,
+ 0xd3c, 0x00027293,
+ 0xd40, 0x00000000,
+ 0xd44, 0x00000000,
+ 0xd48, 0x00000000,
+ 0xd4c, 0x00000000,
+ 0xd50, 0x6437140a,
+ 0xd54, 0x00000000,
+ 0xd58, 0x00000000,
+ 0xd5c, 0x30032064,
+ 0xd60, 0x4653de68,
+ 0xd64, 0x04518a3c,
+ 0xd68, 0x00002101,
+ 0xd6c, 0x2a201c16,
+ 0xd70, 0x1812362e,
+ 0xd74, 0x322c2220,
+ 0xd78, 0x000e3c24,
+ 0xe00, 0x2a2a2a2a,
+ 0xe04, 0x2a2a2a2a,
+ 0xe08, 0x03902a2a,
+ 0xe10, 0x2a2a2a2a,
+ 0xe14, 0x2a2a2a2a,
+ 0xe18, 0x2a2a2a2a,
+ 0xe1c, 0x2a2a2a2a,
+ 0xe28, 0x00000000,
+ 0xe30, 0x1000dc1f,
+ 0xe34, 0x10008c1f,
+ 0xe38, 0x02140102,
+ 0xe3c, 0x681604c2,
+ 0xe40, 0x01007c00,
+ 0xe44, 0x01004800,
+ 0xe48, 0xfb000000,
+ 0xe4c, 0x000028d1,
+ 0xe50, 0x1000dc1f,
+ 0xe54, 0x10008c1f,
+ 0xe58, 0x02140102,
+ 0xe5c, 0x28160d05,
+ 0xe60, 0x00000010,
+ 0xe68, 0x001b25a4,
+ 0xe6c, 0x631b25a0,
+ 0xe70, 0x631b25a0,
+ 0xe74, 0x081b25a0,
+ 0xe78, 0x081b25a0,
+ 0xe7c, 0x081b25a0,
+ 0xe80, 0x081b25a0,
+ 0xe84, 0x631b25a0,
+ 0xe88, 0x081b25a0,
+ 0xe8c, 0x631b25a0,
+ 0xed0, 0x631b25a0,
+ 0xed4, 0x631b25a0,
+ 0xed8, 0x631b25a0,
+ 0xedc, 0x001b25a0,
+ 0xee0, 0x001b25a0,
+ 0xeec, 0x6b1b25a0,
+ 0xf14, 0x00000003,
+ 0xf4c, 0x00000000,
+ 0xf00, 0x00000300,
+};
+
+u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH] = {
+ 0xe00, 0xffffffff, 0x0a0c0c0c,
+ 0xe04, 0xffffffff, 0x02040608,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0x86c, 0xffffff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x0a0c0d0e,
+ 0xe14, 0xffffffff, 0x02040608,
+ 0xe18, 0xffffffff, 0x0a0c0d0e,
+ 0xe1c, 0xffffffff, 0x02040608,
+ 0x830, 0xffffffff, 0x0a0c0c0c,
+ 0x834, 0xffffffff, 0x02040608,
+ 0x838, 0xffffff00, 0x00000000,
+ 0x86c, 0x000000ff, 0x00000000,
+ 0x83c, 0xffffffff, 0x0a0c0d0e,
+ 0x848, 0xffffffff, 0x02040608,
+ 0x84c, 0xffffffff, 0x0a0c0d0e,
+ 0x868, 0xffffffff, 0x02040608,
+ 0xe00, 0xffffffff, 0x00000000,
+ 0xe04, 0xffffffff, 0x00000000,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0x86c, 0xffffff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x00000000,
+ 0xe14, 0xffffffff, 0x00000000,
+ 0xe18, 0xffffffff, 0x00000000,
+ 0xe1c, 0xffffffff, 0x00000000,
+ 0x830, 0xffffffff, 0x00000000,
+ 0x834, 0xffffffff, 0x00000000,
+ 0x838, 0xffffff00, 0x00000000,
+ 0x86c, 0x000000ff, 0x00000000,
+ 0x83c, 0xffffffff, 0x00000000,
+ 0x848, 0xffffffff, 0x00000000,
+ 0x84c, 0xffffffff, 0x00000000,
+ 0x868, 0xffffffff, 0x00000000,
+ 0xe00, 0xffffffff, 0x04040404,
+ 0xe04, 0xffffffff, 0x00020204,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0x86c, 0xffffff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x06060606,
+ 0xe14, 0xffffffff, 0x00020406,
+ 0xe18, 0xffffffff, 0x06060606,
+ 0xe1c, 0xffffffff, 0x00020406,
+ 0x830, 0xffffffff, 0x04040404,
+ 0x834, 0xffffffff, 0x00020204,
+ 0x838, 0xffffff00, 0x00000000,
+ 0x86c, 0x000000ff, 0x00000000,
+ 0x83c, 0xffffffff, 0x06060606,
+ 0x848, 0xffffffff, 0x00020406,
+ 0x84c, 0xffffffff, 0x06060606,
+ 0x868, 0xffffffff, 0x00020406,
+ 0xe00, 0xffffffff, 0x00000000,
+ 0xe04, 0xffffffff, 0x00000000,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0x86c, 0xffffff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x00000000,
+ 0xe14, 0xffffffff, 0x00000000,
+ 0xe18, 0xffffffff, 0x00000000,
+ 0xe1c, 0xffffffff, 0x00000000,
+ 0x830, 0xffffffff, 0x00000000,
+ 0x834, 0xffffffff, 0x00000000,
+ 0x838, 0xffffff00, 0x00000000,
+ 0x86c, 0x000000ff, 0x00000000,
+ 0x83c, 0xffffffff, 0x00000000,
+ 0x848, 0xffffffff, 0x00000000,
+ 0x84c, 0xffffffff, 0x00000000,
+ 0x868, 0xffffffff, 0x00000000,
+};
+
+u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00031284,
+ 0x002, 0x00098000,
+ 0x003, 0x00018c63,
+ 0x004, 0x000210e7,
+ 0x009, 0x0002044f,
+ 0x00a, 0x0001adb0,
+ 0x00b, 0x00054867,
+ 0x00c, 0x0008992e,
+ 0x00d, 0x0000e52c,
+ 0x00e, 0x00039ce7,
+ 0x00f, 0x00000451,
+ 0x019, 0x00000000,
+ 0x01a, 0x00010255,
+ 0x01b, 0x00060a00,
+ 0x01c, 0x000fc378,
+ 0x01d, 0x000a1250,
+ 0x01e, 0x0004445f,
+ 0x01f, 0x00080001,
+ 0x020, 0x0000b614,
+ 0x021, 0x0006c000,
+ 0x022, 0x00000000,
+ 0x023, 0x00001558,
+ 0x024, 0x00000060,
+ 0x025, 0x00000483,
+ 0x026, 0x0004f000,
+ 0x027, 0x000ec7d9,
+ 0x028, 0x000977c0,
+ 0x029, 0x00004783,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00021334,
+ 0x02a, 0x00000000,
+ 0x02b, 0x00000054,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000c,
+ 0x02a, 0x00000002,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000003,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000004,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000005,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00073333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000006,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000007,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000008,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0004b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000009,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000a,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000b,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000c,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000d,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00073333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000e,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00066666,
+ 0x02c, 0x0000001a,
+ 0x02a, 0x000e0000,
+ 0x010, 0x0004000f,
+ 0x011, 0x000e31fc,
+ 0x010, 0x0006000f,
+ 0x011, 0x000ff9f8,
+ 0x010, 0x0002000f,
+ 0x011, 0x000203f9,
+ 0x010, 0x0003000f,
+ 0x011, 0x000ff500,
+ 0x010, 0x00000000,
+ 0x011, 0x00000000,
+ 0x010, 0x0008000f,
+ 0x011, 0x0003f100,
+ 0x010, 0x0009000f,
+ 0x011, 0x00023100,
+ 0x012, 0x00032000,
+ 0x012, 0x00071000,
+ 0x012, 0x000b0000,
+ 0x012, 0x000fc000,
+ 0x013, 0x000287af,
+ 0x013, 0x000244b7,
+ 0x013, 0x000204ab,
+ 0x013, 0x0001c49f,
+ 0x013, 0x00018493,
+ 0x013, 0x00014297,
+ 0x013, 0x00010295,
+ 0x013, 0x0000c298,
+ 0x013, 0x0000819c,
+ 0x013, 0x000040a8,
+ 0x013, 0x0000001c,
+ 0x014, 0x0001944c,
+ 0x014, 0x00059444,
+ 0x014, 0x0009944c,
+ 0x014, 0x000d9444,
+ 0x015, 0x0000f424,
+ 0x015, 0x0004f424,
+ 0x015, 0x0008f424,
+ 0x015, 0x000cf424,
+ 0x016, 0x000e0330,
+ 0x016, 0x000a0330,
+ 0x016, 0x00060330,
+ 0x016, 0x00020330,
+ 0x000, 0x00010159,
+ 0x018, 0x0000f401,
+ 0x0fe, 0x00000000,
+ 0x0fe, 0x00000000,
+ 0x01f, 0x00080003,
+ 0x0fe, 0x00000000,
+ 0x0fe, 0x00000000,
+ 0x01e, 0x00044457,
+ 0x01f, 0x00080000,
+ 0x000, 0x00030159,
+};
+
+u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00031284,
+ 0x002, 0x00098000,
+ 0x003, 0x00018c63,
+ 0x004, 0x000210e7,
+ 0x009, 0x0002044f,
+ 0x00a, 0x0001adb0,
+ 0x00b, 0x00054867,
+ 0x00c, 0x0008992e,
+ 0x00d, 0x0000e52c,
+ 0x00e, 0x00039ce7,
+ 0x00f, 0x00000451,
+ 0x012, 0x00032000,
+ 0x012, 0x00071000,
+ 0x012, 0x000b0000,
+ 0x012, 0x000fc000,
+ 0x013, 0x000287af,
+ 0x013, 0x000244b7,
+ 0x013, 0x000204ab,
+ 0x013, 0x0001c49f,
+ 0x013, 0x00018493,
+ 0x013, 0x00014297,
+ 0x013, 0x00010295,
+ 0x013, 0x0000c298,
+ 0x013, 0x0000819c,
+ 0x013, 0x000040a8,
+ 0x013, 0x0000001c,
+ 0x014, 0x0001944c,
+ 0x014, 0x00059444,
+ 0x014, 0x0009944c,
+ 0x014, 0x000d9444,
+ 0x015, 0x0000f424,
+ 0x015, 0x0004f424,
+ 0x015, 0x0008f424,
+ 0x015, 0x000cf424,
+ 0x016, 0x000e0330,
+ 0x016, 0x000a0330,
+ 0x016, 0x00060330,
+ 0x016, 0x00020330,
+};
+
+u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00031284,
+ 0x002, 0x00098000,
+ 0x003, 0x00018c63,
+ 0x004, 0x000210e7,
+ 0x009, 0x0002044f,
+ 0x00a, 0x0001adb0,
+ 0x00b, 0x00054867,
+ 0x00c, 0x0008992e,
+ 0x00d, 0x0000e52c,
+ 0x00e, 0x00039ce7,
+ 0x00f, 0x00000451,
+ 0x019, 0x00000000,
+ 0x01a, 0x00010255,
+ 0x01b, 0x00060a00,
+ 0x01c, 0x000fc378,
+ 0x01d, 0x000a1250,
+ 0x01e, 0x0004445f,
+ 0x01f, 0x00080001,
+ 0x020, 0x0000b614,
+ 0x021, 0x0006c000,
+ 0x022, 0x00000000,
+ 0x023, 0x00001558,
+ 0x024, 0x00000060,
+ 0x025, 0x00000483,
+ 0x026, 0x0004f000,
+ 0x027, 0x000ec7d9,
+ 0x028, 0x000977c0,
+ 0x029, 0x00004783,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00021334,
+ 0x02a, 0x00000000,
+ 0x02b, 0x00000054,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000c,
+ 0x02a, 0x00000002,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000003,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000004,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000005,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00073333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000006,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000007,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000008,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0004b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000009,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000a,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000b,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000c,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000d,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00073333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000e,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00066666,
+ 0x02c, 0x0000001a,
+ 0x02a, 0x000e0000,
+ 0x010, 0x0004000f,
+ 0x011, 0x000e31fc,
+ 0x010, 0x0006000f,
+ 0x011, 0x000ff9f8,
+ 0x010, 0x0002000f,
+ 0x011, 0x000203f9,
+ 0x010, 0x0003000f,
+ 0x011, 0x000ff500,
+ 0x010, 0x00000000,
+ 0x011, 0x00000000,
+ 0x010, 0x0008000f,
+ 0x011, 0x0003f100,
+ 0x010, 0x0009000f,
+ 0x011, 0x00023100,
+ 0x012, 0x00032000,
+ 0x012, 0x00071000,
+ 0x012, 0x000b0000,
+ 0x012, 0x000fc000,
+ 0x013, 0x000287af,
+ 0x013, 0x000244b7,
+ 0x013, 0x000204ab,
+ 0x013, 0x0001c49f,
+ 0x013, 0x00018493,
+ 0x013, 0x00014297,
+ 0x013, 0x00010295,
+ 0x013, 0x0000c298,
+ 0x013, 0x0000819c,
+ 0x013, 0x000040a8,
+ 0x013, 0x0000001c,
+ 0x014, 0x0001944c,
+ 0x014, 0x00059444,
+ 0x014, 0x0009944c,
+ 0x014, 0x000d9444,
+ 0x015, 0x0000f424,
+ 0x015, 0x0004f424,
+ 0x015, 0x0008f424,
+ 0x015, 0x000cf424,
+ 0x016, 0x000e0330,
+ 0x016, 0x000a0330,
+ 0x016, 0x00060330,
+ 0x016, 0x00020330,
+ 0x000, 0x00010159,
+ 0x018, 0x0000f401,
+ 0x0fe, 0x00000000,
+ 0x0fe, 0x00000000,
+ 0x01f, 0x00080003,
+ 0x0fe, 0x00000000,
+ 0x0fe, 0x00000000,
+ 0x01e, 0x00044457,
+ 0x01f, 0x00080000,
+ 0x000, 0x00030159,
+};
+
+u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH] = {
+ 0x0,
+};
+
+u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH] = {
+ 0x420, 0x00000080,
+ 0x423, 0x00000000,
+ 0x430, 0x00000000,
+ 0x431, 0x00000000,
+ 0x432, 0x00000000,
+ 0x433, 0x00000001,
+ 0x434, 0x00000004,
+ 0x435, 0x00000005,
+ 0x436, 0x00000006,
+ 0x437, 0x00000007,
+ 0x438, 0x00000000,
+ 0x439, 0x00000000,
+ 0x43a, 0x00000000,
+ 0x43b, 0x00000001,
+ 0x43c, 0x00000004,
+ 0x43d, 0x00000005,
+ 0x43e, 0x00000006,
+ 0x43f, 0x00000007,
+ 0x440, 0x0000005d,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000015,
+ 0x445, 0x000000f0,
+ 0x446, 0x0000000f,
+ 0x447, 0x00000000,
+ 0x458, 0x00000041,
+ 0x459, 0x000000a8,
+ 0x45a, 0x00000072,
+ 0x45b, 0x000000b9,
+ 0x460, 0x00000088,
+ 0x461, 0x00000088,
+ 0x462, 0x00000006,
+ 0x463, 0x00000003,
+ 0x4c8, 0x00000004,
+ 0x4c9, 0x00000008,
+ 0x4cc, 0x00000002,
+ 0x4cd, 0x00000028,
+ 0x4ce, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000a2,
+ 0x502, 0x0000002f,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000a3,
+ 0x506, 0x0000005e,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002b,
+ 0x509, 0x000000a4,
+ 0x50a, 0x0000005e,
+ 0x50b, 0x00000000,
+ 0x50c, 0x0000004f,
+ 0x50d, 0x000000a4,
+ 0x50e, 0x00000000,
+ 0x50f, 0x00000000,
+ 0x512, 0x0000001c,
+ 0x514, 0x0000000a,
+ 0x515, 0x00000010,
+ 0x516, 0x0000000a,
+ 0x517, 0x00000010,
+ 0x51a, 0x00000016,
+ 0x524, 0x0000000f,
+ 0x525, 0x0000004f,
+ 0x546, 0x00000020,
+ 0x547, 0x00000000,
+ 0x559, 0x00000002,
+ 0x55a, 0x00000002,
+ 0x55d, 0x000000ff,
+ 0x605, 0x00000030,
+ 0x608, 0x0000000e,
+ 0x609, 0x0000002a,
+ 0x652, 0x00000020,
+ 0x63c, 0x0000000a,
+ 0x63d, 0x0000000a,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70a, 0x00000065,
+ 0x70b, 0x00000087,
+};
+
+u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH] = {
+ 0xc78, 0x7b000001,
+ 0xc78, 0x7b010001,
+ 0xc78, 0x7b020001,
+ 0xc78, 0x7b030001,
+ 0xc78, 0x7b040001,
+ 0xc78, 0x7b050001,
+ 0xc78, 0x7a060001,
+ 0xc78, 0x79070001,
+ 0xc78, 0x78080001,
+ 0xc78, 0x77090001,
+ 0xc78, 0x760a0001,
+ 0xc78, 0x750b0001,
+ 0xc78, 0x740c0001,
+ 0xc78, 0x730d0001,
+ 0xc78, 0x720e0001,
+ 0xc78, 0x710f0001,
+ 0xc78, 0x70100001,
+ 0xc78, 0x6f110001,
+ 0xc78, 0x6e120001,
+ 0xc78, 0x6d130001,
+ 0xc78, 0x6c140001,
+ 0xc78, 0x6b150001,
+ 0xc78, 0x6a160001,
+ 0xc78, 0x69170001,
+ 0xc78, 0x68180001,
+ 0xc78, 0x67190001,
+ 0xc78, 0x661a0001,
+ 0xc78, 0x651b0001,
+ 0xc78, 0x641c0001,
+ 0xc78, 0x631d0001,
+ 0xc78, 0x621e0001,
+ 0xc78, 0x611f0001,
+ 0xc78, 0x60200001,
+ 0xc78, 0x49210001,
+ 0xc78, 0x48220001,
+ 0xc78, 0x47230001,
+ 0xc78, 0x46240001,
+ 0xc78, 0x45250001,
+ 0xc78, 0x44260001,
+ 0xc78, 0x43270001,
+ 0xc78, 0x42280001,
+ 0xc78, 0x41290001,
+ 0xc78, 0x402a0001,
+ 0xc78, 0x262b0001,
+ 0xc78, 0x252c0001,
+ 0xc78, 0x242d0001,
+ 0xc78, 0x232e0001,
+ 0xc78, 0x222f0001,
+ 0xc78, 0x21300001,
+ 0xc78, 0x20310001,
+ 0xc78, 0x06320001,
+ 0xc78, 0x05330001,
+ 0xc78, 0x04340001,
+ 0xc78, 0x03350001,
+ 0xc78, 0x02360001,
+ 0xc78, 0x01370001,
+ 0xc78, 0x00380001,
+ 0xc78, 0x00390001,
+ 0xc78, 0x003a0001,
+ 0xc78, 0x003b0001,
+ 0xc78, 0x003c0001,
+ 0xc78, 0x003d0001,
+ 0xc78, 0x003e0001,
+ 0xc78, 0x003f0001,
+ 0xc78, 0x7b400001,
+ 0xc78, 0x7b410001,
+ 0xc78, 0x7b420001,
+ 0xc78, 0x7b430001,
+ 0xc78, 0x7b440001,
+ 0xc78, 0x7b450001,
+ 0xc78, 0x7a460001,
+ 0xc78, 0x79470001,
+ 0xc78, 0x78480001,
+ 0xc78, 0x77490001,
+ 0xc78, 0x764a0001,
+ 0xc78, 0x754b0001,
+ 0xc78, 0x744c0001,
+ 0xc78, 0x734d0001,
+ 0xc78, 0x724e0001,
+ 0xc78, 0x714f0001,
+ 0xc78, 0x70500001,
+ 0xc78, 0x6f510001,
+ 0xc78, 0x6e520001,
+ 0xc78, 0x6d530001,
+ 0xc78, 0x6c540001,
+ 0xc78, 0x6b550001,
+ 0xc78, 0x6a560001,
+ 0xc78, 0x69570001,
+ 0xc78, 0x68580001,
+ 0xc78, 0x67590001,
+ 0xc78, 0x665a0001,
+ 0xc78, 0x655b0001,
+ 0xc78, 0x645c0001,
+ 0xc78, 0x635d0001,
+ 0xc78, 0x625e0001,
+ 0xc78, 0x615f0001,
+ 0xc78, 0x60600001,
+ 0xc78, 0x49610001,
+ 0xc78, 0x48620001,
+ 0xc78, 0x47630001,
+ 0xc78, 0x46640001,
+ 0xc78, 0x45650001,
+ 0xc78, 0x44660001,
+ 0xc78, 0x43670001,
+ 0xc78, 0x42680001,
+ 0xc78, 0x41690001,
+ 0xc78, 0x406a0001,
+ 0xc78, 0x266b0001,
+ 0xc78, 0x256c0001,
+ 0xc78, 0x246d0001,
+ 0xc78, 0x236e0001,
+ 0xc78, 0x226f0001,
+ 0xc78, 0x21700001,
+ 0xc78, 0x20710001,
+ 0xc78, 0x06720001,
+ 0xc78, 0x05730001,
+ 0xc78, 0x04740001,
+ 0xc78, 0x03750001,
+ 0xc78, 0x02760001,
+ 0xc78, 0x01770001,
+ 0xc78, 0x00780001,
+ 0xc78, 0x00790001,
+ 0xc78, 0x007a0001,
+ 0xc78, 0x007b0001,
+ 0xc78, 0x007c0001,
+ 0xc78, 0x007d0001,
+ 0xc78, 0x007e0001,
+ 0xc78, 0x007f0001,
+ 0xc78, 0x3800001e,
+ 0xc78, 0x3801001e,
+ 0xc78, 0x3802001e,
+ 0xc78, 0x3803001e,
+ 0xc78, 0x3804001e,
+ 0xc78, 0x3805001e,
+ 0xc78, 0x3806001e,
+ 0xc78, 0x3807001e,
+ 0xc78, 0x3808001e,
+ 0xc78, 0x3c09001e,
+ 0xc78, 0x3e0a001e,
+ 0xc78, 0x400b001e,
+ 0xc78, 0x440c001e,
+ 0xc78, 0x480d001e,
+ 0xc78, 0x4c0e001e,
+ 0xc78, 0x500f001e,
+ 0xc78, 0x5210001e,
+ 0xc78, 0x5611001e,
+ 0xc78, 0x5a12001e,
+ 0xc78, 0x5e13001e,
+ 0xc78, 0x6014001e,
+ 0xc78, 0x6015001e,
+ 0xc78, 0x6016001e,
+ 0xc78, 0x6217001e,
+ 0xc78, 0x6218001e,
+ 0xc78, 0x6219001e,
+ 0xc78, 0x621a001e,
+ 0xc78, 0x621b001e,
+ 0xc78, 0x621c001e,
+ 0xc78, 0x621d001e,
+ 0xc78, 0x621e001e,
+ 0xc78, 0x621f001e,
+};
+
+u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH] = {
+ 0xc78, 0x7b000001,
+ 0xc78, 0x7b010001,
+ 0xc78, 0x7b020001,
+ 0xc78, 0x7b030001,
+ 0xc78, 0x7b040001,
+ 0xc78, 0x7b050001,
+ 0xc78, 0x7a060001,
+ 0xc78, 0x79070001,
+ 0xc78, 0x78080001,
+ 0xc78, 0x77090001,
+ 0xc78, 0x760a0001,
+ 0xc78, 0x750b0001,
+ 0xc78, 0x740c0001,
+ 0xc78, 0x730d0001,
+ 0xc78, 0x720e0001,
+ 0xc78, 0x710f0001,
+ 0xc78, 0x70100001,
+ 0xc78, 0x6f110001,
+ 0xc78, 0x6e120001,
+ 0xc78, 0x6d130001,
+ 0xc78, 0x6c140001,
+ 0xc78, 0x6b150001,
+ 0xc78, 0x6a160001,
+ 0xc78, 0x69170001,
+ 0xc78, 0x68180001,
+ 0xc78, 0x67190001,
+ 0xc78, 0x661a0001,
+ 0xc78, 0x651b0001,
+ 0xc78, 0x641c0001,
+ 0xc78, 0x631d0001,
+ 0xc78, 0x621e0001,
+ 0xc78, 0x611f0001,
+ 0xc78, 0x60200001,
+ 0xc78, 0x49210001,
+ 0xc78, 0x48220001,
+ 0xc78, 0x47230001,
+ 0xc78, 0x46240001,
+ 0xc78, 0x45250001,
+ 0xc78, 0x44260001,
+ 0xc78, 0x43270001,
+ 0xc78, 0x42280001,
+ 0xc78, 0x41290001,
+ 0xc78, 0x402a0001,
+ 0xc78, 0x262b0001,
+ 0xc78, 0x252c0001,
+ 0xc78, 0x242d0001,
+ 0xc78, 0x232e0001,
+ 0xc78, 0x222f0001,
+ 0xc78, 0x21300001,
+ 0xc78, 0x20310001,
+ 0xc78, 0x06320001,
+ 0xc78, 0x05330001,
+ 0xc78, 0x04340001,
+ 0xc78, 0x03350001,
+ 0xc78, 0x02360001,
+ 0xc78, 0x01370001,
+ 0xc78, 0x00380001,
+ 0xc78, 0x00390001,
+ 0xc78, 0x003a0001,
+ 0xc78, 0x003b0001,
+ 0xc78, 0x003c0001,
+ 0xc78, 0x003d0001,
+ 0xc78, 0x003e0001,
+ 0xc78, 0x003f0001,
+ 0xc78, 0x7b400001,
+ 0xc78, 0x7b410001,
+ 0xc78, 0x7b420001,
+ 0xc78, 0x7b430001,
+ 0xc78, 0x7b440001,
+ 0xc78, 0x7b450001,
+ 0xc78, 0x7a460001,
+ 0xc78, 0x79470001,
+ 0xc78, 0x78480001,
+ 0xc78, 0x77490001,
+ 0xc78, 0x764a0001,
+ 0xc78, 0x754b0001,
+ 0xc78, 0x744c0001,
+ 0xc78, 0x734d0001,
+ 0xc78, 0x724e0001,
+ 0xc78, 0x714f0001,
+ 0xc78, 0x70500001,
+ 0xc78, 0x6f510001,
+ 0xc78, 0x6e520001,
+ 0xc78, 0x6d530001,
+ 0xc78, 0x6c540001,
+ 0xc78, 0x6b550001,
+ 0xc78, 0x6a560001,
+ 0xc78, 0x69570001,
+ 0xc78, 0x68580001,
+ 0xc78, 0x67590001,
+ 0xc78, 0x665a0001,
+ 0xc78, 0x655b0001,
+ 0xc78, 0x645c0001,
+ 0xc78, 0x635d0001,
+ 0xc78, 0x625e0001,
+ 0xc78, 0x615f0001,
+ 0xc78, 0x60600001,
+ 0xc78, 0x49610001,
+ 0xc78, 0x48620001,
+ 0xc78, 0x47630001,
+ 0xc78, 0x46640001,
+ 0xc78, 0x45650001,
+ 0xc78, 0x44660001,
+ 0xc78, 0x43670001,
+ 0xc78, 0x42680001,
+ 0xc78, 0x41690001,
+ 0xc78, 0x406a0001,
+ 0xc78, 0x266b0001,
+ 0xc78, 0x256c0001,
+ 0xc78, 0x246d0001,
+ 0xc78, 0x236e0001,
+ 0xc78, 0x226f0001,
+ 0xc78, 0x21700001,
+ 0xc78, 0x20710001,
+ 0xc78, 0x06720001,
+ 0xc78, 0x05730001,
+ 0xc78, 0x04740001,
+ 0xc78, 0x03750001,
+ 0xc78, 0x02760001,
+ 0xc78, 0x01770001,
+ 0xc78, 0x00780001,
+ 0xc78, 0x00790001,
+ 0xc78, 0x007a0001,
+ 0xc78, 0x007b0001,
+ 0xc78, 0x007c0001,
+ 0xc78, 0x007d0001,
+ 0xc78, 0x007e0001,
+ 0xc78, 0x007f0001,
+ 0xc78, 0x3800001e,
+ 0xc78, 0x3801001e,
+ 0xc78, 0x3802001e,
+ 0xc78, 0x3803001e,
+ 0xc78, 0x3804001e,
+ 0xc78, 0x3805001e,
+ 0xc78, 0x3806001e,
+ 0xc78, 0x3807001e,
+ 0xc78, 0x3808001e,
+ 0xc78, 0x3c09001e,
+ 0xc78, 0x3e0a001e,
+ 0xc78, 0x400b001e,
+ 0xc78, 0x440c001e,
+ 0xc78, 0x480d001e,
+ 0xc78, 0x4c0e001e,
+ 0xc78, 0x500f001e,
+ 0xc78, 0x5210001e,
+ 0xc78, 0x5611001e,
+ 0xc78, 0x5a12001e,
+ 0xc78, 0x5e13001e,
+ 0xc78, 0x6014001e,
+ 0xc78, 0x6015001e,
+ 0xc78, 0x6016001e,
+ 0xc78, 0x6217001e,
+ 0xc78, 0x6218001e,
+ 0xc78, 0x6219001e,
+ 0xc78, 0x621a001e,
+ 0xc78, 0x621b001e,
+ 0xc78, 0x621c001e,
+ 0xc78, 0x621d001e,
+ 0xc78, 0x621e001e,
+ 0xc78, 0x621f001e,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/table.h b/drivers/net/wireless/rtlwifi/rtl8192ce/table.h
new file mode 100644
index 000000000000..3a6e8b6aeee0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/table.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TABLE__H_
+#define __RTL92CE_TABLE__H_
+
+#include <linux/types.h>
+
+#define PHY_REG_2TARRAY_LENGTH 374
+extern u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH];
+#define PHY_REG_1TARRAY_LENGTH 374
+extern u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH];
+#define PHY_REG_ARRAY_PGLENGTH 192
+extern u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH];
+#define RADIOA_2TARRAYLENGTH 282
+extern u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH];
+#define RADIOB_2TARRAYLENGTH 78
+extern u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH];
+#define RADIOA_1TARRAYLENGTH 282
+extern u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH];
+#define RADIOB_1TARRAYLENGTH 1
+extern u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH];
+#define MAC_2T_ARRAYLENGTH 162
+extern u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH];
+#define AGCTAB_2TARRAYLENGTH 320
+extern u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH];
+#define AGCTAB_1TARRAYLENGTH 320
+extern u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
new file mode 100644
index 000000000000..bf5852f2d634
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -0,0 +1,1031 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+
+static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(u16 fc,
+ unsigned int
+ skb_queue)
+{
+ enum rtl_desc_qsel qsel;
+
+ if (unlikely(ieee80211_is_beacon(fc))) {
+ qsel = QSLT_BEACON;
+ return qsel;
+ }
+
+ if (ieee80211_is_mgmt(fc)) {
+ qsel = QSLT_MGNT;
+ return qsel;
+ }
+
+ switch (skb_queue) {
+ case VO_QUEUE:
+ qsel = QSLT_VO;
+ break;
+ case VI_QUEUE:
+ qsel = QSLT_VI;
+ break;
+ case BE_QUEUE:
+ qsel = QSLT_BE;
+ break;
+ case BK_QUEUE:
+ qsel = QSLT_BK;
+ break;
+ default:
+ qsel = QSLT_BE;
+ RT_ASSERT(false, ("BE queue, skb_queue:%d,"
+ " set qsel = 0x%X\n", skb_queue, QSLT_BE));
+ break;
+ }
+ return qsel;
+}
+
+static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
+{
+ int rate_idx;
+
+ if (first_ampdu) {
+ if (false == isht) {
+ switch (desc_rate) {
+ case DESC92C_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92C_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92C_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92C_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92C_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92C_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92C_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92C_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92C_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92C_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92C_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92C_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ } else {
+ rate_idx = 11;
+ }
+
+ return rate_idx;
+ }
+
+ switch (desc_rate) {
+ case DESC92C_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92C_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92C_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92C_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92C_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92C_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92C_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92C_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92C_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92C_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92C_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92C_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 11;
+ break;
+ }
+ return rate_idx;
+}
+
+static u8 _rtl92c_query_rxpwrpercentage(char antpower)
+{
+ if ((antpower <= -100) || (antpower >= 20))
+ return 0;
+ else if (antpower >= 0)
+ return 100;
+ else
+ return 100 + antpower;
+}
+
+static u8 _rtl92c_evm_db_to_percentage(char value)
+{
+ char ret_val;
+ ret_val = value;
+
+ if (ret_val >= 0)
+ ret_val = 0;
+
+ if (ret_val <= -33)
+ ret_val = -33;
+
+ ret_val = 0 - ret_val;
+ ret_val *= 3;
+
+ if (ret_val == 99)
+ ret_val = 100;
+
+ return ret_val;
+}
+
+static long _rtl92ce_translate_todbm(struct ieee80211_hw *hw,
+ u8 signal_strength_index)
+{
+ long signal_power;
+
+ signal_power = (long)((signal_strength_index + 1) >> 1);
+ signal_power -= 95;
+ return signal_power;
+}
+
+static long _rtl92ce_signal_scale_mapping(struct ieee80211_hw *hw,
+ long currsig)
+{
+ long retsig;
+
+ if (currsig >= 61 && currsig <= 100)
+ retsig = 90 + ((currsig - 60) / 4);
+ else if (currsig >= 41 && currsig <= 60)
+ retsig = 78 + ((currsig - 40) / 2);
+ else if (currsig >= 31 && currsig <= 40)
+ retsig = 66 + (currsig - 30);
+ else if (currsig >= 21 && currsig <= 30)
+ retsig = 54 + (currsig - 20);
+ else if (currsig >= 5 && currsig <= 20)
+ retsig = 42 + (((currsig - 5) * 2) / 3);
+ else if (currsig == 4)
+ retsig = 36;
+ else if (currsig == 3)
+ retsig = 27;
+ else if (currsig == 2)
+ retsig = 18;
+ else if (currsig == 1)
+ retsig = 9;
+ else
+ retsig = currsig;
+
+ return retsig;
+}
+
+static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats,
+ struct rx_desc_92c *pdesc,
+ struct rx_fwinfo_92c *p_drvinfo,
+ bool bpacket_match_bssid,
+ bool bpacket_toself,
+ bool b_packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct phy_sts_cck_8192s_t *cck_buf;
+ s8 rx_pwr_all, rx_pwr[4];
+ u8 rf_rx_num, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi;
+ bool is_cck_rate;
+
+ is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+ pstats->b_packet_matchbssid = bpacket_match_bssid;
+ pstats->b_packet_toself = bpacket_toself;
+ pstats->b_is_cck = is_cck_rate;
+ pstats->b_packet_beacon = b_packet_beacon;
+ pstats->b_is_cck = is_cck_rate;
+ pstats->rx_mimo_signalquality[0] = -1;
+ pstats->rx_mimo_signalquality[1] = -1;
+
+ if (is_cck_rate) {
+ u8 report, cck_highpwr;
+ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
+
+ cck_highpwr = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ BIT(9));
+ if (!cck_highpwr) {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = cck_buf->cck_agc_rpt & 0xc0;
+ report = report >> 6;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x2:
+ rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x1:
+ rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x0:
+ rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+ break;
+ }
+ } else {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = p_drvinfo->cfosho[0] & 0x60;
+ report = report >> 5;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x2:
+ rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x1:
+ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x0:
+ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ }
+ }
+
+ pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (bpacket_match_bssid) {
+ u8 sq;
+ if (pstats->rx_pwdb_all > 40)
+ sq = 100;
+ else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstats->signalquality = sq;
+ pstats->rx_mimo_signalquality[0] = sq;
+ pstats->rx_mimo_signalquality[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.brfpath_rxenable[0] =
+ rtlpriv->dm.brfpath_rxenable[1] = true;
+ for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ if (rtlpriv->dm.brfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] =
+ ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110;
+ rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+ rtlpriv->stats.rx_snr_db[i] =
+ (long)(p_drvinfo->rxsnr[i] / 2);
+
+ if (bpacket_match_bssid)
+ pstats->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+ pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->rxpower = rx_pwr_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 &&
+ pdesc->rxmcs <= DESC92C_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (bpacket_match_bssid) {
+ if (i == 0)
+ pstats->signalquality =
+ (u8) (evm & 0xff);
+ pstats->rx_mimo_signalquality[i] =
+ (u8) (evm & 0xff);
+ }
+ }
+ }
+
+ if (is_cck_rate)
+ pstats->signalstrength =
+ (u8) (_rtl92ce_signal_scale_mapping(hw, pwdb_all));
+ else if (rf_rx_num != 0)
+ pstats->signalstrength =
+ (u8) (_rtl92ce_signal_scale_mapping
+ (hw, total_rssi /= rf_rx_num));
+}
+
+static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 rfpath;
+ u32 last_rssi, tmpval;
+
+ if (pstats->b_packet_toself || pstats->b_packet_beacon) {
+ rtlpriv->stats.rssi_calculate_cnt++;
+
+ if (rtlpriv->stats.ui_rssi.total_num++ >=
+ PHY_RSSI_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_rssi.total_num =
+ PHY_RSSI_SLID_WIN_MAX;
+ last_rssi =
+ rtlpriv->stats.ui_rssi.elements[rtlpriv->
+ stats.ui_rssi.index];
+ rtlpriv->stats.ui_rssi.total_val -= last_rssi;
+ }
+
+ rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
+ rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.
+ index++] =
+ pstats->signalstrength;
+
+ if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
+ rtlpriv->stats.ui_rssi.index = 0;
+
+ tmpval = rtlpriv->stats.ui_rssi.total_val /
+ rtlpriv->stats.ui_rssi.total_num;
+ rtlpriv->stats.signal_strength =
+ _rtl92ce_translate_todbm(hw, (u8) tmpval);
+ pstats->rssi = rtlpriv->stats.signal_strength;
+ }
+
+ if (!pstats->b_is_cck && pstats->b_packet_toself) {
+ for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+ rfpath++) {
+
+ if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath))
+ continue;
+
+ if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ pstats->rx_mimo_signalstrength[rfpath];
+
+ }
+
+ if (pstats->rx_mimo_signalstrength[rfpath] >
+ rtlpriv->stats.rx_rssi_percentage[rfpath]) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.
+ rx_rssi_percentage[rfpath] *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ rtlpriv->stats.rx_rssi_percentage[rfpath] +
+ 1;
+ } else {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.
+ rx_rssi_percentage[rfpath] *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+ }
+
+ }
+ }
+}
+
+static void _rtl92ce_update_rxsignalstatistics(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int weighting;
+
+ if (rtlpriv->stats.recv_signal_power == 0)
+ rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
+
+ if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
+ weighting = 5;
+
+ else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
+ weighting = (-5);
+
+ rtlpriv->stats.recv_signal_power =
+ (rtlpriv->stats.recv_signal_power * 5 +
+ pstats->recvsignalpower + weighting) / 6;
+}
+
+static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undecorated_smoothed_pwdb;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ return;
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ }
+
+ if (pstats->b_packet_toself || pstats->b_packet_beacon) {
+ if (undecorated_smoothed_pwdb < 0)
+ undecorated_smoothed_pwdb = pstats->rx_pwdb_all;
+
+ if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
+ undecorated_smoothed_pwdb =
+ (((undecorated_smoothed_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+
+ undecorated_smoothed_pwdb = undecorated_smoothed_pwdb
+ + 1;
+ } else {
+ undecorated_smoothed_pwdb =
+ (((undecorated_smoothed_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+ }
+
+ rtlpriv->dm.undecorated_smoothed_pwdb =
+ undecorated_smoothed_pwdb;
+ _rtl92ce_update_rxsignalstatistics(hw, pstats);
+ }
+}
+
+static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 last_evm, n_spatialstream, tmpval;
+
+ if (pstats->signalquality != 0) {
+ if (pstats->b_packet_toself || pstats->b_packet_beacon) {
+
+ if (rtlpriv->stats.ui_link_quality.total_num++ >=
+ PHY_LINKQUALITY_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_link_quality.total_num =
+ PHY_LINKQUALITY_SLID_WIN_MAX;
+ last_evm =
+ rtlpriv->stats.
+ ui_link_quality.elements[rtlpriv->
+ stats.ui_link_quality.
+ index];
+ rtlpriv->stats.ui_link_quality.total_val -=
+ last_evm;
+ }
+
+ rtlpriv->stats.ui_link_quality.total_val +=
+ pstats->signalquality;
+ rtlpriv->stats.ui_link_quality.elements[rtlpriv->stats.
+ ui_link_quality.
+ index++] =
+ pstats->signalquality;
+
+ if (rtlpriv->stats.ui_link_quality.index >=
+ PHY_LINKQUALITY_SLID_WIN_MAX)
+ rtlpriv->stats.ui_link_quality.index = 0;
+
+ tmpval = rtlpriv->stats.ui_link_quality.total_val /
+ rtlpriv->stats.ui_link_quality.total_num;
+ rtlpriv->stats.signal_quality = tmpval;
+
+ rtlpriv->stats.last_sigstrength_inpercent = tmpval;
+
+ for (n_spatialstream = 0; n_spatialstream < 2;
+ n_spatialstream++) {
+ if (pstats->
+ rx_mimo_signalquality[n_spatialstream] !=
+ -1) {
+ if (rtlpriv->stats.
+ rx_evm_percentage[n_spatialstream]
+ == 0) {
+ rtlpriv->stats.
+ rx_evm_percentage
+ [n_spatialstream] =
+ pstats->rx_mimo_signalquality
+ [n_spatialstream];
+ }
+
+ rtlpriv->stats.
+ rx_evm_percentage[n_spatialstream] =
+ ((rtlpriv->
+ stats.rx_evm_percentage
+ [n_spatialstream] *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->
+ rx_mimo_signalquality
+ [n_spatialstream] * 1)) /
+ (RX_SMOOTH_FACTOR);
+ }
+ }
+ }
+ } else {
+ ;
+ }
+}
+
+static void _rtl92ce_process_phyinfo(struct ieee80211_hw *hw,
+ u8 *buffer,
+ struct rtl_stats *pcurrent_stats)
+{
+
+ if (!pcurrent_stats->b_packet_matchbssid &&
+ !pcurrent_stats->b_packet_beacon)
+ return;
+
+ _rtl92ce_process_ui_rssi(hw, pcurrent_stats);
+ _rtl92ce_process_pwdb(hw, pcurrent_stats);
+ _rtl92ce_process_ui_link_quality(hw, pcurrent_stats);
+}
+
+static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct rtl_stats *pstats,
+ struct rx_desc_92c *pdesc,
+ struct rx_fwinfo_92c *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ u16 fc, type;
+ bool b_packet_matchbssid, b_packet_toself, b_packet_beacon;
+
+ tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = le16_to_cpu(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(fc);
+ praddr = hdr->addr1;
+ psaddr = hdr->addr2;
+
+ b_packet_matchbssid =
+ ((IEEE80211_FTYPE_CTL != type) &&
+ (!compare_ether_addr(mac->bssid,
+ (fc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3)) &&
+ (!pstats->b_hwerror) && (!pstats->b_crc) && (!pstats->b_icv));
+
+ b_packet_toself = b_packet_matchbssid &&
+ (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+
+ if (ieee80211_is_beacon(fc))
+ b_packet_beacon = true;
+
+ _rtl92ce_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
+ b_packet_matchbssid, b_packet_toself,
+ b_packet_beacon);
+
+ _rtl92ce_process_phyinfo(hw, tmp_buf, pstats);
+}
+
+bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status,
+ u8 *p_desc, struct sk_buff *skb)
+{
+ struct rx_fwinfo_92c *p_drvinfo;
+ struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
+
+ u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+ stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+ RX_DRV_INFO_SIZE_UNIT;
+ stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+ stats->b_icv = (u16) GET_RX_DESC_ICV(pdesc);
+ stats->b_crc = (u16) GET_RX_DESC_CRC32(pdesc);
+ stats->b_hwerror = (stats->b_crc | stats->b_icv);
+ stats->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+ stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+ stats->b_shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+ stats->b_isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+ stats->b_isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+ && (GET_RX_DESC_FAGGR(pdesc) == 1));
+ stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+ stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.channel->band;
+
+ if (GET_RX_DESC_CRC32(pdesc))
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (!GET_RX_DESC_SWDEC(pdesc))
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ if (GET_RX_DESC_BW(pdesc))
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (GET_RX_DESC_RXHT(pdesc))
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ if (stats->decrypted)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ rx_status->rate_idx = _rtl92ce_rate_mapping((bool)
+ GET_RX_DESC_RXHT(pdesc),
+ (u8)
+ GET_RX_DESC_RXMCS(pdesc),
+ (bool)
+ GET_RX_DESC_PAGGR(pdesc));
+
+ rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
+ if (phystatus == true) {
+ p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
+ stats->rx_bufshift);
+
+ _rtl92ce_translate_rx_signal_stuff(hw,
+ skb, stats, pdesc,
+ p_drvinfo);
+ }
+
+ /*rx_status->qual = stats->signal; */
+ rx_status->signal = stats->rssi + 10;
+ /*rx_status->noise = -stats->noise; */
+
+ return true;
+}
+
+void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info, struct sk_buff *skb,
+ unsigned int queue_index)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool b_defaultadapter = true;
+
+ struct ieee80211_sta *sta = ieee80211_find_sta(mac->vif, mac->bssid);
+
+ u8 *pdesc = (u8 *) pdesc_tx;
+ struct rtl_tcb_desc tcb_desc;
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ u16 seq_number;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u8 rate_flag = info->control.rates[0].flags;
+
+ enum rtl_desc_qsel fw_qsel =
+ _rtl92ce_map_hwqueue_to_fwqueue(le16_to_cpu(hdr->frame_control),
+ queue_index);
+
+ bool b_firstseg = ((hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+
+ bool b_lastseg = ((hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+
+ rtl_get_tcb_desc(hw, info, skb, &tcb_desc);
+
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c));
+
+ if (b_firstseg) {
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+ SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate);
+
+ if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble)
+ SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
+
+ if (mac->tids[tid].agg.agg_state == RTL_AGG_ON &&
+ info->flags & IEEE80211_TX_CTL_AMPDU) {
+ SET_TX_DESC_AGG_BREAK(pdesc, 1);
+ SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+ }
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.b_rts_enable &&
+ !tcb_desc.
+ b_cts_enable) ? 1 : 0));
+ SET_TX_DESC_HW_RTS_ENABLE(pdesc,
+ ((tcb_desc.b_rts_enable
+ || tcb_desc.b_cts_enable) ? 1 : 0));
+ SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.b_cts_enable) ? 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.b_rts_stbc) ? 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate);
+ SET_TX_DESC_RTS_BW(pdesc, 0);
+ SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc,
+ ((tcb_desc.rts_rate <= DESC92C_RATE54M) ?
+ (tcb_desc.b_rts_use_shortpreamble ? 1 : 0)
+ : (tcb_desc.b_rts_use_shortgi ? 1 : 0)));
+
+ if (mac->bw_40) {
+ if (tcb_desc.b_packet_bw) {
+ SET_TX_DESC_DATA_BW(pdesc, 1);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+
+ if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
+ }
+ }
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
+
+ if (sta) {
+ u8 ampdu_density = sta->ht_cap.ampdu_density;
+ SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+ }
+
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf =
+ info->control.hw_key;
+
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+
+ }
+ }
+
+ SET_TX_DESC_PKT_ID(pdesc, 0);
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+ SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+ SET_TX_DESC_DISABLE_FB(pdesc, 0);
+ SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0);
+
+ if (ieee80211_is_data_qos(fc)) {
+ if (mac->rdg_en) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ ("Enable RDG function.\n"));
+ SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+ SET_TX_DESC_HTC(pdesc, 1);
+ }
+ }
+ }
+
+ SET_TX_DESC_FIRST_SEG(pdesc, (b_firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (b_lastseg ? 1 : 0));
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
+
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ if (rtlpriv->dm.b_useramask) {
+ SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index);
+ SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id);
+ } else {
+ SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index);
+ SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index);
+ }
+
+ if ((!ieee80211_is_data_qos(fc)) && ppsc->b_leisure_ps &&
+ ppsc->b_fwctrl_lps) {
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ SET_TX_DESC_PKT_ID(pdesc, 8);
+
+ if (!b_defaultadapter)
+ SET_TX_DESC_QOS(pdesc, 1);
+ }
+
+ SET_TX_DESC_MORE_FRAG(pdesc, (b_lastseg ? 0 : 1));
+
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+ is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+ SET_TX_DESC_BMC(pdesc, 1);
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n"));
+}
+
+void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
+ u8 *pdesc, bool b_firstseg,
+ bool b_lastseg, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 fw_queue = QSLT_BEACON;
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+ if (b_firstseg)
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+ SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+ SET_TX_DESC_SEQ(pdesc, 0);
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len));
+
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ SET_TX_DESC_RATE_ID(pdesc, 7);
+ SET_TX_DESC_MACID(pdesc, 0);
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+ SET_TX_DESC_USE_RATE(pdesc, 1);
+
+ if (!ieee80211_is_data_qos(fc)) {
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ SET_TX_DESC_PKT_ID(pdesc, 8);
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C Tx Cmd Content\n",
+ pdesc, TX_DESC_SIZE);
+}
+
+void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d"
+ " not process\n", desc_name));
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d "
+ "not process\n", desc_name));
+ break;
+ }
+ }
+}
+
+u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(p_desc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(p_desc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d "
+ "not process\n", desc_name));
+ break;
+ }
+ } else {
+ struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_DESC_PKT_LEN(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d "
+ "not process\n", desc_name));
+ break;
+ }
+ }
+ return ret;
+}
+
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (hw_queue == BEACON_QUEUE) {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+ } else {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+ BIT(0) << (hw_queue));
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
new file mode 100644
index 000000000000..53d0e0a5af5c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -0,0 +1,714 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TRX_H__
+#define __RTL92CE_TRX_H__
+
+#define TX_DESC_SIZE 64
+#define TX_DESC_AGGR_SUBFRAME_SIZE 32
+
+#define RX_DESC_SIZE 32
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+#define TX_DESC_NEXT_DESC_OFFSET 40
+#define USB_HWDESC_HEADER_LEN 32
+#define CRCLENGTH 4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 5, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 5, 1, __val)
+#define SET_TX_DESC_BK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 6, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 7, 1, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
+
+#define GET_TX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_TX_DESC_AGG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
+#define GET_TX_DESC_AGG_BREAK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
+#define GET_TX_DESC_RDG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
+#define GET_TX_DESC_QUEUE_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_TX_DESC_PIFS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_TX_DESC_RATE_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_TX_DESC_EN_DESC_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_TX_DESC_SEC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
+#define GET_TX_DESC_PKT_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 8)
+
+#define SET_TX_DESC_RTS_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val)
+#define SET_TX_DESC_DATA_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_CCX(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val)
+#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val)
+#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val)
+#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val)
+#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 6)
+#define GET_TX_DESC_DATA_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 6, 6)
+#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 14, 2)
+#define GET_TX_DESC_MORE_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 17, 1)
+#define GET_TX_DESC_RAW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 18, 1)
+#define GET_TX_DESC_CCX(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 19, 1)
+#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 20, 3)
+#define GET_TX_DESC_ANTSEL_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 24, 1)
+#define GET_TX_DESC_ANTSEL_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 25, 1)
+#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 26, 2)
+#define GET_TX_DESC_TX_ANTL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 2)
+#define GET_TX_DESC_TX_ANT_HT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 30, 2)
+
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val)
+#define SET_TX_DESC_PKT_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 4, __val)
+
+#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
+#define GET_TX_DESC_TAIL_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 8)
+#define GET_TX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
+#define GET_TX_DESC_PKT_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 28, 4)
+
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
+#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val)
+#define SET_TX_DESC_QOS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val)
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val)
+#define SET_TX_DESC_PORT_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val)
+#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val)
+#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val)
+#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val)
+#define SET_TX_DESC_RTS_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 5)
+#define GET_TX_DESC_AP_DCFE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 5, 1)
+#define GET_TX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 6, 1)
+#define GET_TX_DESC_HWSEQ_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 7, 1)
+#define GET_TX_DESC_USE_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 8, 1)
+#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 9, 1)
+#define GET_TX_DESC_DISABLE_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 10, 1)
+#define GET_TX_DESC_CTS2SELF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 11, 1)
+#define GET_TX_DESC_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 12, 1)
+#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 13, 1)
+#define GET_TX_DESC_PORT_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 14, 1)
+#define GET_TX_DESC_WAIT_DCTS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 18, 1)
+#define GET_TX_DESC_CTS2AP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 19, 1)
+#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 20, 2)
+#define GET_TX_DESC_TX_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 22, 2)
+#define GET_TX_DESC_DATA_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 24, 1)
+#define GET_TX_DESC_DATA_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 25, 1)
+#define GET_TX_DESC_RTS_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 26, 1)
+#define GET_TX_DESC_RTS_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 27, 1)
+#define GET_TX_DESC_RTS_SC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 28, 2)
+#define GET_TX_DESC_RTS_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 30, 2)
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val)
+#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val)
+#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val)
+
+#define GET_TX_DESC_TX_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 6)
+#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 6, 1)
+#define GET_TX_DESC_CCX_TAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 7, 1)
+#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 8, 5)
+#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 13, 4)
+#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 17, 1)
+#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 18, 6)
+#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 24, 8)
+
+#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val)
+#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val)
+#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val)
+#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val)
+#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val)
+#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val)
+
+#define GET_TX_DESC_TXAGC_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 5)
+#define GET_TX_DESC_TXAGC_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 5, 5)
+#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 10, 1)
+#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 11, 5)
+#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 16, 4)
+#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 20, 4)
+#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 24, 4)
+#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 4, __val)
+#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 20, 4, __val)
+#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val)
+#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 28, 4, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 16, 4)
+#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 20, 4)
+#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 24, 4)
+#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val)
+#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+32, 0, 32)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+36, 0, 32)
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+44, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_RX_DESC_TID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 5, 4)
+#define GET_RX_DESC_HWRSVD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 9, 5)
+#define GET_RX_DESC_PAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_FAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_A2_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 4)
+#define GET_RX_DESC_PAM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+#define GET_RX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 16, 14)
+#define GET_RX_DESC_NEXT_IND(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 30, 1)
+#define GET_RX_DESC_RSVD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 31, 1)
+
+#define GET_RX_DESC_RXMCS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 6)
+#define GET_RX_DESC_RXHT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_DESC_SPLCP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 1)
+#define GET_RX_DESC_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 9, 1)
+#define GET_RX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_DESC_HWPC_ERR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 14, 1)
+#define GET_RX_DESC_HWPC_IND(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 15, 1)
+#define GET_RX_DESC_IV0(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 16, 16)
+
+#define GET_RX_DESC_IV1(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 32)
+#define GET_RX_DESC_TSFL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset((void *)__pdesc, 0, _size); \
+} while (0);
+
+#define RX_HAL_IS_CCK_RATE(_pdesc)\
+ (_pdesc->rxmcs == DESC92C_RATE1M || \
+ _pdesc->rxmcs == DESC92C_RATE2M || \
+ _pdesc->rxmcs == DESC92C_RATE5_5M || \
+ _pdesc->rxmcs == DESC92C_RATE11M)
+
+struct rx_fwinfo_92c {
+ u8 gain_trsw[4];
+ u8 pwdb_all;
+ u8 cfosho[4];
+ u8 cfotail[4];
+ char rxevm[2];
+ char rxsnr[4];
+ u8 pdsnr[2];
+ u8 csi_current[2];
+ u8 csi_target[2];
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+} __packed;
+
+struct tx_desc_92c {
+ u32 pktsize:16;
+ u32 offset:8;
+ u32 bmc:1;
+ u32 htc:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 linip:1;
+ u32 noacm:1;
+ u32 gf:1;
+ u32 own:1;
+
+ u32 macid:5;
+ u32 agg_en:1;
+ u32 bk:1;
+ u32 rdg_en:1;
+ u32 queuesel:5;
+ u32 rd_nav_ext:1;
+ u32 lsig_txop_en:1;
+ u32 pifs:1;
+ u32 rateid:4;
+ u32 nav_usehdr:1;
+ u32 en_descid:1;
+ u32 sectype:2;
+ u32 pktoffset:8;
+
+ u32 rts_rc:6;
+ u32 data_rc:6;
+ u32 rsvd0:2;
+ u32 bar_retryht:2;
+ u32 rsvd1:1;
+ u32 morefrag:1;
+ u32 raw:1;
+ u32 ccx:1;
+ u32 ampdudensity:3;
+ u32 rsvd2:1;
+ u32 ant_sela:1;
+ u32 ant_selb:1;
+ u32 txant_cck:2;
+ u32 txant_l:2;
+ u32 txant_ht:2;
+
+ u32 nextheadpage:8;
+ u32 tailpage:8;
+ u32 seq:12;
+ u32 pktid:4;
+
+ u32 rtsrate:5;
+ u32 apdcfe:1;
+ u32 qos:1;
+ u32 hwseq_enable:1;
+ u32 userrate:1;
+ u32 dis_rtsfb:1;
+ u32 dis_datafb:1;
+ u32 cts2self:1;
+ u32 rts_en:1;
+ u32 hwrts_en:1;
+ u32 portid:1;
+ u32 rsvd3:3;
+ u32 waitdcts:1;
+ u32 cts2ap_en:1;
+ u32 txsc:2;
+ u32 stbc:2;
+ u32 txshort:1;
+ u32 txbw:1;
+ u32 rtsshort:1;
+ u32 rtsbw:1;
+ u32 rtssc:2;
+ u32 rtsstbc:2;
+
+ u32 txrate:6;
+ u32 shortgi:1;
+ u32 ccxt:1;
+ u32 txrate_fb_lmt:5;
+ u32 rtsrate_fb_lmt:4;
+ u32 retrylmt_en:1;
+ u32 txretrylmt:6;
+ u32 usb_txaggnum:8;
+
+ u32 txagca:5;
+ u32 txagcb:5;
+ u32 usemaxlen:1;
+ u32 maxaggnum:5;
+ u32 mcsg1maxlen:4;
+ u32 mcsg2maxlen:4;
+ u32 mcsg3maxlen:4;
+ u32 mcs7sgimaxlen:4;
+
+ u32 txbuffersize:16;
+ u32 mcsg4maxlen:4;
+ u32 mcsg5maxlen:4;
+ u32 mcsg6maxlen:4;
+ u32 mcsg15sgimaxlen:4;
+
+ u32 txbuffaddr;
+ u32 txbufferaddr64;
+ u32 nextdescaddress;
+ u32 nextdescaddress64;
+
+ u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_92c {
+ u32 length:14;
+ u32 crc32:1;
+ u32 icverror:1;
+ u32 drv_infosize:4;
+ u32 security:3;
+ u32 qos:1;
+ u32 shift:2;
+ u32 phystatus:1;
+ u32 swdec:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 eor:1;
+ u32 own:1;
+
+ u32 macid:5;
+ u32 tid:4;
+ u32 hwrsvd:5;
+ u32 paggr:1;
+ u32 faggr:1;
+ u32 a1_fit:4;
+ u32 a2_fit:4;
+ u32 pam:1;
+ u32 pwr:1;
+ u32 moredata:1;
+ u32 morefrag:1;
+ u32 type:2;
+ u32 mc:1;
+ u32 bc:1;
+
+ u32 seq:12;
+ u32 frag:4;
+ u32 nextpktlen:14;
+ u32 nextind:1;
+ u32 rsvd:1;
+
+ u32 rxmcs:6;
+ u32 rxht:1;
+ u32 amsdu:1;
+ u32 splcp:1;
+ u32 bandwidth:1;
+ u32 htc:1;
+ u32 tcpchk_rpt:1;
+ u32 ipcchk_rpt:1;
+ u32 tcpchk_valid:1;
+ u32 hwpcerr:1;
+ u32 hwpcind:1;
+ u32 iv0:16;
+
+ u32 iv1;
+
+ u32 tsfl;
+
+ u32 bufferaddress;
+ u32 bufferaddress64;
+
+} __packed;
+
+void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ u8 *pdesc, struct ieee80211_tx_info *info,
+ struct sk_buff *skb, unsigned int qsel);
+bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue);
+void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
new file mode 100644
index 000000000000..d44d79613d2d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -0,0 +1,1532 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_WIFI_H__
+#define __RTL_WIFI_H__
+
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "debug.h"
+
+#define RF_CHANGE_BY_INIT 0
+#define RF_CHANGE_BY_IPS BIT(28)
+#define RF_CHANGE_BY_PS BIT(29)
+#define RF_CHANGE_BY_HW BIT(30)
+#define RF_CHANGE_BY_SW BIT(31)
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_MAC_REG_NUM 4
+
+#define MAX_KEY_LEN 61
+#define KEY_BUF_SIZE 5
+
+/* QoS related. */
+/*aci: 0x00 Best Effort*/
+/*aci: 0x01 Background*/
+/*aci: 0x10 Video*/
+/*aci: 0x11 Voice*/
+/*Max: define total number.*/
+#define AC0_BE 0
+#define AC1_BK 1
+#define AC2_VI 2
+#define AC3_VO 3
+#define AC_MAX 4
+#define QOS_QUEUE_NUM 4
+#define RTL_MAC80211_NUM_QUEUE 5
+
+#define QBSS_LOAD_SIZE 5
+#define MAX_WMMELE_LENGTH 64
+
+/*slot time for 11g. */
+#define RTL_SLOT_TIME_9 9
+#define RTL_SLOT_TIME_20 20
+
+/*related with tcp/ip. */
+/*if_ehther.h*/
+#define ETH_P_PAE 0x888E /*Port Access Entity (IEEE 802.1X) */
+#define ETH_P_IP 0x0800 /*Internet Protocol packet */
+#define ETH_P_ARP 0x0806 /*Address Resolution packet */
+#define SNAP_SIZE 6
+#define PROTOC_TYPE_SIZE 2
+
+/*related with 802.11 frame*/
+#define MAC80211_3ADDR_LEN 24
+#define MAC80211_4ADDR_LEN 30
+
+enum intf_type {
+ INTF_PCI = 0,
+ INTF_USB = 1,
+};
+
+enum radio_path {
+ RF90_PATH_A = 0,
+ RF90_PATH_B = 1,
+ RF90_PATH_C = 2,
+ RF90_PATH_D = 3,
+};
+
+enum rt_eeprom_type {
+ EEPROM_93C46,
+ EEPROM_93C56,
+ EEPROM_BOOT_EFUSE,
+};
+
+enum rtl_status {
+ RTL_STATUS_INTERFACE_START = 0,
+};
+
+enum hardware_type {
+ HARDWARE_TYPE_RTL8192E,
+ HARDWARE_TYPE_RTL8192U,
+ HARDWARE_TYPE_RTL8192SE,
+ HARDWARE_TYPE_RTL8192SU,
+ HARDWARE_TYPE_RTL8192CE,
+ HARDWARE_TYPE_RTL8192CU,
+ HARDWARE_TYPE_RTL8192DE,
+ HARDWARE_TYPE_RTL8192DU,
+
+ /*keep it last*/
+ HARDWARE_TYPE_NUM
+};
+
+enum scan_operation_backup_opt {
+ SCAN_OPT_BACKUP = 0,
+ SCAN_OPT_RESTORE,
+ SCAN_OPT_MAX
+};
+
+/*RF state.*/
+enum rf_pwrstate {
+ ERFON,
+ ERFSLEEP,
+ ERFOFF
+};
+
+struct bb_reg_def {
+ u32 rfintfs;
+ u32 rfintfi;
+ u32 rfintfo;
+ u32 rfintfe;
+ u32 rf3wire_offset;
+ u32 rflssi_select;
+ u32 rftxgain_stage;
+ u32 rfhssi_para1;
+ u32 rfhssi_para2;
+ u32 rfswitch_control;
+ u32 rfagc_control1;
+ u32 rfagc_control2;
+ u32 rfrxiq_imbalance;
+ u32 rfrx_afe;
+ u32 rftxiq_imbalance;
+ u32 rftx_afe;
+ u32 rflssi_readback;
+ u32 rflssi_readbackpi;
+};
+
+enum io_type {
+ IO_CMD_PAUSE_DM_BY_SCAN = 0,
+ IO_CMD_RESUME_DM_BY_SCAN = 1,
+};
+
+enum hw_variables {
+ HW_VAR_ETHER_ADDR,
+ HW_VAR_MULTICAST_REG,
+ HW_VAR_BASIC_RATE,
+ HW_VAR_BSSID,
+ HW_VAR_MEDIA_STATUS,
+ HW_VAR_SECURITY_CONF,
+ HW_VAR_BEACON_INTERVAL,
+ HW_VAR_ATIM_WINDOW,
+ HW_VAR_LISTEN_INTERVAL,
+ HW_VAR_CS_COUNTER,
+ HW_VAR_DEFAULTKEY0,
+ HW_VAR_DEFAULTKEY1,
+ HW_VAR_DEFAULTKEY2,
+ HW_VAR_DEFAULTKEY3,
+ HW_VAR_SIFS,
+ HW_VAR_DIFS,
+ HW_VAR_EIFS,
+ HW_VAR_SLOT_TIME,
+ HW_VAR_ACK_PREAMBLE,
+ HW_VAR_CW_CONFIG,
+ HW_VAR_CW_VALUES,
+ HW_VAR_RATE_FALLBACK_CONTROL,
+ HW_VAR_CONTENTION_WINDOW,
+ HW_VAR_RETRY_COUNT,
+ HW_VAR_TR_SWITCH,
+ HW_VAR_COMMAND,
+ HW_VAR_WPA_CONFIG,
+ HW_VAR_AMPDU_MIN_SPACE,
+ HW_VAR_SHORTGI_DENSITY,
+ HW_VAR_AMPDU_FACTOR,
+ HW_VAR_MCS_RATE_AVAILABLE,
+ HW_VAR_AC_PARAM,
+ HW_VAR_ACM_CTRL,
+ HW_VAR_DIS_Req_Qsize,
+ HW_VAR_CCX_CHNL_LOAD,
+ HW_VAR_CCX_NOISE_HISTOGRAM,
+ HW_VAR_CCX_CLM_NHM,
+ HW_VAR_TxOPLimit,
+ HW_VAR_TURBO_MODE,
+ HW_VAR_RF_STATE,
+ HW_VAR_RF_OFF_BY_HW,
+ HW_VAR_BUS_SPEED,
+ HW_VAR_SET_DEV_POWER,
+
+ HW_VAR_RCR,
+ HW_VAR_RATR_0,
+ HW_VAR_RRSR,
+ HW_VAR_CPU_RST,
+ HW_VAR_CECHK_BSSID,
+ HW_VAR_LBK_MODE,
+ HW_VAR_AES_11N_FIX,
+ HW_VAR_USB_RX_AGGR,
+ HW_VAR_USER_CONTROL_TURBO_MODE,
+ HW_VAR_RETRY_LIMIT,
+ HW_VAR_INIT_TX_RATE,
+ HW_VAR_TX_RATE_REG,
+ HW_VAR_EFUSE_USAGE,
+ HW_VAR_EFUSE_BYTES,
+ HW_VAR_AUTOLOAD_STATUS,
+ HW_VAR_RF_2R_DISABLE,
+ HW_VAR_SET_RPWM,
+ HW_VAR_H2C_FW_PWRMODE,
+ HW_VAR_H2C_FW_JOINBSSRPT,
+ HW_VAR_FW_PSMODE_STATUS,
+ HW_VAR_1X1_RECV_COMBINE,
+ HW_VAR_STOP_SEND_BEACON,
+ HW_VAR_TSF_TIMER,
+ HW_VAR_IO_CMD,
+
+ HW_VAR_RF_RECOVERY,
+ HW_VAR_H2C_FW_UPDATE_GTK,
+ HW_VAR_WF_MASK,
+ HW_VAR_WF_CRC,
+ HW_VAR_WF_IS_MAC_ADDR,
+ HW_VAR_H2C_FW_OFFLOAD,
+ HW_VAR_RESET_WFCRC,
+
+ HW_VAR_HANDLE_FW_C2H,
+ HW_VAR_DL_FW_RSVD_PAGE,
+ HW_VAR_AID,
+ HW_VAR_HW_SEQ_ENABLE,
+ HW_VAR_CORRECT_TSF,
+ HW_VAR_BCN_VALID,
+ HW_VAR_FWLPS_RF_ON,
+ HW_VAR_DUAL_TSF_RST,
+ HW_VAR_SWITCH_EPHY_WoWLAN,
+ HW_VAR_INT_MIGRATION,
+ HW_VAR_INT_AC,
+ HW_VAR_RF_TIMING,
+
+ HW_VAR_MRC,
+
+ HW_VAR_MGT_FILTER,
+ HW_VAR_CTRL_FILTER,
+ HW_VAR_DATA_FILTER,
+};
+
+enum _RT_MEDIA_STATUS {
+ RT_MEDIA_DISCONNECT = 0,
+ RT_MEDIA_CONNECT = 1
+};
+
+enum rt_oem_id {
+ RT_CID_DEFAULT = 0,
+ RT_CID_8187_ALPHA0 = 1,
+ RT_CID_8187_SERCOMM_PS = 2,
+ RT_CID_8187_HW_LED = 3,
+ RT_CID_8187_NETGEAR = 4,
+ RT_CID_WHQL = 5,
+ RT_CID_819x_CAMEO = 6,
+ RT_CID_819x_RUNTOP = 7,
+ RT_CID_819x_Senao = 8,
+ RT_CID_TOSHIBA = 9,
+ RT_CID_819x_Netcore = 10,
+ RT_CID_Nettronix = 11,
+ RT_CID_DLINK = 12,
+ RT_CID_PRONET = 13,
+ RT_CID_COREGA = 14,
+ RT_CID_819x_ALPHA = 15,
+ RT_CID_819x_Sitecom = 16,
+ RT_CID_CCX = 17,
+ RT_CID_819x_Lenovo = 18,
+ RT_CID_819x_QMI = 19,
+ RT_CID_819x_Edimax_Belkin = 20,
+ RT_CID_819x_Sercomm_Belkin = 21,
+ RT_CID_819x_CAMEO1 = 22,
+ RT_CID_819x_MSI = 23,
+ RT_CID_819x_Acer = 24,
+ RT_CID_819x_HP = 27,
+ RT_CID_819x_CLEVO = 28,
+ RT_CID_819x_Arcadyan_Belkin = 29,
+ RT_CID_819x_SAMSUNG = 30,
+ RT_CID_819x_WNC_COREGA = 31,
+ RT_CID_819x_Foxcoon = 32,
+ RT_CID_819x_DELL = 33,
+};
+
+enum hw_descs {
+ HW_DESC_OWN,
+ HW_DESC_RXOWN,
+ HW_DESC_TX_NEXTDESC_ADDR,
+ HW_DESC_TXBUFF_ADDR,
+ HW_DESC_RXBUFF_ADDR,
+ HW_DESC_RXPKT_LEN,
+ HW_DESC_RXERO,
+};
+
+enum prime_sc {
+ PRIME_CHNL_OFFSET_DONT_CARE = 0,
+ PRIME_CHNL_OFFSET_LOWER = 1,
+ PRIME_CHNL_OFFSET_UPPER = 2,
+};
+
+enum rf_type {
+ RF_1T1R = 0,
+ RF_1T2R = 1,
+ RF_2T2R = 2,
+};
+
+enum ht_channel_width {
+ HT_CHANNEL_WIDTH_20 = 0,
+ HT_CHANNEL_WIDTH_20_40 = 1,
+};
+
+/* Ref: 802.11i sepc D10.0 7.3.2.25.1
+Cipher Suites Encryption Algorithms */
+enum rt_enc_alg {
+ NO_ENCRYPTION = 0,
+ WEP40_ENCRYPTION = 1,
+ TKIP_ENCRYPTION = 2,
+ RSERVED_ENCRYPTION = 3,
+ AESCCMP_ENCRYPTION = 4,
+ WEP104_ENCRYPTION = 5,
+};
+
+enum rtl_hal_state {
+ _HAL_STATE_STOP = 0,
+ _HAL_STATE_START = 1,
+};
+
+enum rtl_var_map {
+ /*reg map */
+ SYS_ISO_CTRL = 0,
+ SYS_FUNC_EN,
+ SYS_CLK,
+ MAC_RCR_AM,
+ MAC_RCR_AB,
+ MAC_RCR_ACRC32,
+ MAC_RCR_ACF,
+ MAC_RCR_AAP,
+
+ /*efuse map */
+ EFUSE_TEST,
+ EFUSE_CTRL,
+ EFUSE_CLK,
+ EFUSE_CLK_CTRL,
+ EFUSE_PWC_EV12V,
+ EFUSE_FEN_ELDR,
+ EFUSE_LOADER_CLK_EN,
+ EFUSE_ANA8M,
+ EFUSE_HWSET_MAX_SIZE,
+
+ /*CAM map */
+ RWCAM,
+ WCAMI,
+ RCAMO,
+ CAMDBG,
+ SECR,
+ SEC_CAM_NONE,
+ SEC_CAM_WEP40,
+ SEC_CAM_TKIP,
+ SEC_CAM_AES,
+ SEC_CAM_WEP104,
+
+ /*IMR map */
+ RTL_IMR_BCNDMAINT6, /*Beacon DMA Interrupt 6 */
+ RTL_IMR_BCNDMAINT5, /*Beacon DMA Interrupt 5 */
+ RTL_IMR_BCNDMAINT4, /*Beacon DMA Interrupt 4 */
+ RTL_IMR_BCNDMAINT3, /*Beacon DMA Interrupt 3 */
+ RTL_IMR_BCNDMAINT2, /*Beacon DMA Interrupt 2 */
+ RTL_IMR_BCNDMAINT1, /*Beacon DMA Interrupt 1 */
+ RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrup 8 */
+ RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrup 7 */
+ RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrup 6 */
+ RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrup 5 */
+ RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrup 4 */
+ RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrup 3 */
+ RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrup 2 */
+ RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrup 1 */
+ RTL_IMR_TIMEOUT2, /*Timeout interrupt 2 */
+ RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */
+ RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */
+ RTL_IMR_PSTIMEOUT, /*Power save time out interrupt */
+ RTL_IMR_BcnInt, /*Beacon DMA Interrupt 0 */
+ RTL_IMR_RXFOVW, /*Receive FIFO Overflow */
+ RTL_IMR_RDU, /*Receive Descriptor Unavailable */
+ RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */
+ RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrup */
+ RTL_IMR_HIGHDOK, /*High Queue DMA OK Interrupt */
+ RTL_IMR_TBDOK, /*Transmit Beacon OK interrup */
+ RTL_IMR_MGNTDOK, /*Management Queue DMA OK Interrupt */
+ RTL_IMR_TBDER, /*For 92C,Transmit Beacon Error Interrupt */
+ RTL_IMR_BKDOK, /*AC_BK DMA OK Interrupt */
+ RTL_IMR_BEDOK, /*AC_BE DMA OK Interrupt */
+ RTL_IMR_VIDOK, /*AC_VI DMA OK Interrupt */
+ RTL_IMR_VODOK, /*AC_VO DMA Interrupt */
+ RTL_IMR_ROK, /*Receive DMA OK Interrupt */
+ RTL_IBSS_INT_MASKS, /*(RTL_IMR_BcnInt|RTL_IMR_TBDOK|RTL_IMR_TBDER)*/
+
+ /*CCK Rates, TxHT = 0 */
+ RTL_RC_CCK_RATE1M,
+ RTL_RC_CCK_RATE2M,
+ RTL_RC_CCK_RATE5_5M,
+ RTL_RC_CCK_RATE11M,
+
+ /*OFDM Rates, TxHT = 0 */
+ RTL_RC_OFDM_RATE6M,
+ RTL_RC_OFDM_RATE9M,
+ RTL_RC_OFDM_RATE12M,
+ RTL_RC_OFDM_RATE18M,
+ RTL_RC_OFDM_RATE24M,
+ RTL_RC_OFDM_RATE36M,
+ RTL_RC_OFDM_RATE48M,
+ RTL_RC_OFDM_RATE54M,
+
+ RTL_RC_HT_RATEMCS7,
+ RTL_RC_HT_RATEMCS15,
+
+ /*keep it last */
+ RTL_VAR_MAP_MAX,
+};
+
+/*Firmware PS mode for control LPS.*/
+enum _fw_ps_mode {
+ FW_PS_ACTIVE_MODE = 0,
+ FW_PS_MIN_MODE = 1,
+ FW_PS_MAX_MODE = 2,
+ FW_PS_DTIM_MODE = 3,
+ FW_PS_VOIP_MODE = 4,
+ FW_PS_UAPSD_WMM_MODE = 5,
+ FW_PS_UAPSD_MODE = 6,
+ FW_PS_IBSS_MODE = 7,
+ FW_PS_WWLAN_MODE = 8,
+ FW_PS_PM_Radio_Off = 9,
+ FW_PS_PM_Card_Disable = 10,
+};
+
+enum rt_psmode {
+ EACTIVE, /*Active/Continuous access. */
+ EMAXPS, /*Max power save mode. */
+ EFASTPS, /*Fast power save mode. */
+ EAUTOPS, /*Auto power save mode. */
+};
+
+/*LED related.*/
+enum led_ctl_mode {
+ LED_CTL_POWER_ON = 1,
+ LED_CTL_LINK = 2,
+ LED_CTL_NO_LINK = 3,
+ LED_CTL_TX = 4,
+ LED_CTL_RX = 5,
+ LED_CTL_SITE_SURVEY = 6,
+ LED_CTL_POWER_OFF = 7,
+ LED_CTL_START_TO_LINK = 8,
+ LED_CTL_START_WPS = 9,
+ LED_CTL_STOP_WPS = 10,
+};
+
+enum rtl_led_pin {
+ LED_PIN_GPIO0,
+ LED_PIN_LED0,
+ LED_PIN_LED1,
+ LED_PIN_LED2
+};
+
+/*QoS related.*/
+/*acm implementation method.*/
+enum acm_method {
+ eAcmWay0_SwAndHw = 0,
+ eAcmWay1_HW = 1,
+ eAcmWay2_SW = 2,
+};
+
+/*aci/aifsn Field.
+Ref: WMM spec 2.2.2: WME Parameter Element, p.12.*/
+union aci_aifsn {
+ u8 char_data;
+
+ struct {
+ u8 aifsn:4;
+ u8 acm:1;
+ u8 aci:2;
+ u8 reserved:1;
+ } f; /* Field */
+};
+
+/*mlme related.*/
+enum wireless_mode {
+ WIRELESS_MODE_UNKNOWN = 0x00,
+ WIRELESS_MODE_A = 0x01,
+ WIRELESS_MODE_B = 0x02,
+ WIRELESS_MODE_G = 0x04,
+ WIRELESS_MODE_AUTO = 0x08,
+ WIRELESS_MODE_N_24G = 0x10,
+ WIRELESS_MODE_N_5G = 0x20
+};
+
+enum ratr_table_mode {
+ RATR_INX_WIRELESS_NGB = 0,
+ RATR_INX_WIRELESS_NG = 1,
+ RATR_INX_WIRELESS_NB = 2,
+ RATR_INX_WIRELESS_N = 3,
+ RATR_INX_WIRELESS_GB = 4,
+ RATR_INX_WIRELESS_G = 5,
+ RATR_INX_WIRELESS_B = 6,
+ RATR_INX_WIRELESS_MC = 7,
+ RATR_INX_WIRELESS_A = 8,
+};
+
+enum rtl_link_state {
+ MAC80211_NOLINK = 0,
+ MAC80211_LINKING = 1,
+ MAC80211_LINKED = 2,
+ MAC80211_LINKED_SCANNING = 3,
+};
+
+enum act_category {
+ ACT_CAT_QOS = 1,
+ ACT_CAT_DLS = 2,
+ ACT_CAT_BA = 3,
+ ACT_CAT_HT = 7,
+ ACT_CAT_WMM = 17,
+};
+
+enum ba_action {
+ ACT_ADDBAREQ = 0,
+ ACT_ADDBARSP = 1,
+ ACT_DELBA = 2,
+};
+
+struct octet_string {
+ u8 *octet;
+ u16 length;
+};
+
+struct rtl_hdr_3addr {
+ __le16 frame_ctl;
+ __le16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ __le16 seq_ctl;
+ u8 payload[0];
+} __packed;
+
+struct rtl_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __packed;
+
+struct rtl_probe_rsp {
+ struct rtl_hdr_3addr header;
+ u32 time_stamp[2];
+ __le16 beacon_interval;
+ __le16 capability;
+ /*SSID, supported rates, FH params, DS params,
+ CF params, IBSS params, TIM (if beacon), RSN */
+ struct rtl_info_element info_element[0];
+} __packed;
+
+/*LED related.*/
+/*ledpin Identify how to implement this SW led.*/
+struct rtl_led {
+ void *hw;
+ enum rtl_led_pin ledpin;
+ bool b_ledon;
+};
+
+struct rtl_led_ctl {
+ bool bled_opendrain;
+ struct rtl_led sw_led0;
+ struct rtl_led sw_led1;
+};
+
+struct rtl_qos_parameters {
+ __le16 cw_min;
+ __le16 cw_max;
+ u8 aifs;
+ u8 flag;
+ __le16 tx_op;
+} __packed;
+
+struct rt_smooth_data {
+ u32 elements[100]; /*array to store values */
+ u32 index; /*index to current array to store */
+ u32 total_num; /*num of valid elements */
+ u32 total_val; /*sum of valid elements */
+};
+
+struct false_alarm_statistics {
+ u32 cnt_parity_fail;
+ u32 cnt_rate_illegal;
+ u32 cnt_crc8_fail;
+ u32 cnt_mcs_fail;
+ u32 cnt_ofdm_fail;
+ u32 cnt_cck_fail;
+ u32 cnt_all;
+};
+
+struct init_gain {
+ u8 xaagccore1;
+ u8 xbagccore1;
+ u8 xcagccore1;
+ u8 xdagccore1;
+ u8 cca;
+
+};
+
+struct wireless_stats {
+ unsigned long txbytesunicast;
+ unsigned long txbytesmulticast;
+ unsigned long txbytesbroadcast;
+ unsigned long rxbytesunicast;
+
+ long rx_snr_db[4];
+ /*Correct smoothed ss in Dbm, only used
+ in driver to report real power now. */
+ long recv_signal_power;
+ long signal_quality;
+ long last_sigstrength_inpercent;
+
+ u32 rssi_calculate_cnt;
+
+ /*Transformed, in dbm. Beautified signal
+ strength for UI, not correct. */
+ long signal_strength;
+
+ u8 rx_rssi_percentage[4];
+ u8 rx_evm_percentage[2];
+
+ struct rt_smooth_data ui_rssi;
+ struct rt_smooth_data ui_link_quality;
+};
+
+struct rate_adaptive {
+ u8 rate_adaptive_disabled;
+ u8 ratr_state;
+ u16 reserve;
+
+ u32 high_rssi_thresh_for_ra;
+ u32 high2low_rssi_thresh_for_ra;
+ u8 low2high_rssi_thresh_for_ra40m;
+ u32 low_rssi_thresh_for_ra40M;
+ u8 low2high_rssi_thresh_for_ra20m;
+ u32 low_rssi_thresh_for_ra20M;
+ u32 upper_rssi_threshold_ratr;
+ u32 middleupper_rssi_threshold_ratr;
+ u32 middle_rssi_threshold_ratr;
+ u32 middlelow_rssi_threshold_ratr;
+ u32 low_rssi_threshold_ratr;
+ u32 ultralow_rssi_threshold_ratr;
+ u32 low_rssi_threshold_ratr_40m;
+ u32 low_rssi_threshold_ratr_20m;
+ u8 ping_rssi_enable;
+ u32 ping_rssi_ratr;
+ u32 ping_rssi_thresh_for_ra;
+ u32 last_ratr;
+ u8 pre_ratr_state;
+};
+
+struct regd_pair_mapping {
+ u16 reg_dmnenum;
+ u16 reg_5ghz_ctl;
+ u16 reg_2ghz_ctl;
+};
+
+struct rtl_regulatory {
+ char alpha2[2];
+ u16 country_code;
+ u16 max_power_level;
+ u32 tp_scale;
+ u16 current_rd;
+ u16 current_rd_ext;
+ int16_t power_limit;
+ struct regd_pair_mapping *regpair;
+};
+
+struct rtl_rfkill {
+ bool rfkill_state; /*0 is off, 1 is on */
+};
+
+struct rtl_phy {
+ struct bb_reg_def phyreg_def[4]; /*Radio A/B/C/D */
+ struct init_gain initgain_backup;
+ enum io_type current_io_type;
+
+ u8 rf_mode;
+ u8 rf_type;
+ u8 current_chan_bw;
+ u8 set_bwmode_inprogress;
+ u8 sw_chnl_inprogress;
+ u8 sw_chnl_stage;
+ u8 sw_chnl_step;
+ u8 current_channel;
+ u8 h2c_box_num;
+ u8 set_io_inprogress;
+
+ /*record for power tracking*/
+ s32 reg_e94;
+ s32 reg_e9c;
+ s32 reg_ea4;
+ s32 reg_eac;
+ s32 reg_eb4;
+ s32 reg_ebc;
+ s32 reg_ec4;
+ s32 reg_ecc;
+ u8 rfpienable;
+ u8 reserve_0;
+ u16 reserve_1;
+ u32 reg_c04, reg_c08, reg_874;
+ u32 adda_backup[16];
+ u32 iqk_mac_backup[IQK_MAC_REG_NUM];
+ u32 iqk_bb_backup[10];
+
+ bool b_rfpi_enable;
+
+ u8 pwrgroup_cnt;
+ u8 bcck_high_power;
+ /* 3 groups of pwr diff by rates*/
+ u32 mcs_txpwrlevel_origoffset[4][16];
+ u8 default_initialgain[4];
+
+ /*the current Tx power level*/
+ u8 cur_cck_txpwridx;
+ u8 cur_ofdm24g_txpwridx;
+
+ u32 rfreg_chnlval[2];
+ bool b_apk_done;
+
+ /*fsync*/
+ u8 framesync;
+ u32 framesync_c34;
+
+ u8 num_total_rfpath;
+};
+
+#define MAX_TID_COUNT 9
+#define RTL_AGG_OFF 0
+#define RTL_AGG_ON 1
+#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2
+#define RTL_AGG_EMPTYING_HW_QUEUE_DELBA 3
+
+struct rtl_ht_agg {
+ u16 txq_id;
+ u16 wait_for_ba;
+ u16 start_idx;
+ u64 bitmap;
+ u32 rate_n_flags;
+ u8 agg_state;
+};
+
+struct rtl_tid_data {
+ u16 seq_number;
+ struct rtl_ht_agg agg;
+};
+
+struct rtl_priv;
+struct rtl_io {
+ struct device *dev;
+
+ /*PCI MEM map */
+ unsigned long pci_mem_end; /*shared mem end */
+ unsigned long pci_mem_start; /*shared mem start */
+
+ /*PCI IO map */
+ unsigned long pci_base_addr; /*device I/O address */
+
+ void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
+ void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val);
+ void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val);
+
+ u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr);
+ u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);
+ u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
+
+};
+
+struct rtl_mac {
+ u8 mac_addr[ETH_ALEN];
+ u8 mac80211_registered;
+ u8 beacon_enabled;
+
+ u32 tx_ss_num;
+ u32 rx_ss_num;
+
+ struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+ struct ieee80211_hw *hw;
+ struct ieee80211_vif *vif;
+ enum nl80211_iftype opmode;
+
+ /*Probe Beacon management */
+ struct rtl_tid_data tids[MAX_TID_COUNT];
+ enum rtl_link_state link_state;
+
+ int n_channels;
+ int n_bitrates;
+
+ /*filters */
+ u32 rx_conf;
+ u16 rx_mgt_filter;
+ u16 rx_ctrl_filter;
+ u16 rx_data_filter;
+
+ bool act_scanning;
+ u8 cnt_after_linked;
+
+ /*RDG*/ bool rdg_en;
+
+ /*AP*/ u8 bssid[6];
+ u8 mcs[16]; /*16 bytes mcs for HT rates.*/
+ u32 basic_rates; /*b/g rates*/
+ u8 ht_enable;
+ u8 sgi_40;
+ u8 sgi_20;
+ u8 bw_40;
+ u8 mode; /*wireless mode*/
+ u8 slot_time;
+ u8 short_preamble;
+ u8 use_cts_protect;
+ u8 cur_40_prime_sc;
+ u8 cur_40_prime_sc_bk;
+ u64 tsf;
+ u8 retry_short;
+ u8 retry_long;
+ u16 assoc_id;
+
+ /*IBSS*/ int beacon_interval;
+
+ /*AMPDU*/ u8 min_space_cfg; /*For Min spacing configurations */
+ u8 max_mss_density;
+ u8 current_ampdu_factor;
+ u8 current_ampdu_density;
+
+ /*QOS & EDCA */
+ struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE];
+ struct rtl_qos_parameters ac[AC_MAX];
+};
+
+struct rtl_hal {
+ struct ieee80211_hw *hw;
+
+ enum intf_type interface;
+ u16 hw_type; /*92c or 92d or 92s and so on */
+ u8 oem_id;
+ u8 version; /*version of chip */
+ u8 state; /*stop 0, start 1 */
+
+ /*firmware */
+ u8 *pfirmware;
+ bool b_h2c_setinprogress;
+ u8 last_hmeboxnum;
+ bool bfw_ready;
+ /*Reserve page start offset except beacon in TxQ. */
+ u8 fw_rsvdpage_startoffset;
+};
+
+struct rtl_security {
+ /*default 0 */
+ bool use_sw_sec;
+
+ bool being_setkey;
+ bool use_defaultkey;
+ /*Encryption Algorithm for Unicast Packet */
+ enum rt_enc_alg pairwise_enc_algorithm;
+ /*Encryption Algorithm for Brocast/Multicast */
+ enum rt_enc_alg group_enc_algorithm;
+
+ /*local Key buffer, indx 0 is for
+ pairwise key 1-4 is for agoup key. */
+ u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN];
+ u8 key_len[KEY_BUF_SIZE];
+
+ /*The pointer of Pairwise Key,
+ it always points to KeyBuf[4] */
+ u8 *pairwise_key;
+};
+
+struct rtl_dm {
+ /*PHY status for DM */
+ long entry_min_undecoratedsmoothed_pwdb;
+ long undecorated_smoothed_pwdb; /*out dm */
+ long entry_max_undecoratedsmoothed_pwdb;
+ bool b_dm_initialgain_enable;
+ bool bdynamic_txpower_enable;
+ bool bcurrent_turbo_edca;
+ bool bis_any_nonbepkts; /*out dm */
+ bool bis_cur_rdlstate;
+ bool btxpower_trackingInit;
+ bool b_disable_framebursting;
+ bool b_cck_inch14;
+ bool btxpower_tracking;
+ bool b_useramask;
+ bool brfpath_rxenable[4];
+
+ u8 thermalvalue_iqk;
+ u8 thermalvalue_lck;
+ u8 thermalvalue;
+ u8 last_dtp_lvl;
+ u8 dynamic_txhighpower_lvl; /*Tx high power level */
+ u8 dm_flag; /*Indicate if each dynamic mechanism's status. */
+ u8 dm_type;
+ u8 txpower_track_control;
+
+ char ofdm_index[2];
+ char cck_index;
+};
+
+#define EFUSE_MAX_LOGICAL_SIZE 128
+
+struct rtl_efuse {
+ bool bautoLoad_ok;
+ bool bootfromefuse;
+ u16 max_physical_size;
+ u8 contents[EFUSE_MAX_LOGICAL_SIZE];
+
+ u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE];
+ u16 efuse_usedbytes;
+ u8 efuse_usedpercentage;
+
+ u8 autoload_failflag;
+
+ short epromtype;
+ u16 eeprom_vid;
+ u16 eeprom_did;
+ u16 eeprom_svid;
+ u16 eeprom_smid;
+ u8 eeprom_oemid;
+ u16 eeprom_channelplan;
+ u8 eeprom_version;
+
+ u8 dev_addr[6];
+
+ bool b_txpwr_fromeprom;
+ u8 eeprom_tssi[2];
+ u8 eeprom_pwrlimit_ht20[3];
+ u8 eeprom_pwrlimit_ht40[3];
+ u8 eeprom_chnlarea_txpwr_cck[2][3];
+ u8 eeprom_chnlarea_txpwr_ht40_1s[2][3];
+ u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][3];
+ u8 txpwrlevel_cck[2][14];
+ u8 txpwrlevel_ht40_1s[2][14]; /*For HT 40MHZ pwr */
+ u8 txpwrlevel_ht40_2s[2][14]; /*For HT 40MHZ pwr */
+
+ /*For power group */
+ u8 pwrgroup_ht20[2][14];
+ u8 pwrgroup_ht40[2][14];
+
+ char txpwr_ht20diff[2][14]; /*HT 20<->40 Pwr diff */
+ u8 txpwr_legacyhtdiff[2][14]; /*For HT<->legacy pwr diff */
+
+ u8 eeprom_regulatory;
+ u8 eeprom_thermalmeter;
+ /*ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */
+ u8 thermalmeter[2];
+
+ u8 legacy_ht_txpowerdiff; /*Legacy to HT rate power diff */
+ bool b_apk_thermalmeterignore;
+};
+
+struct rtl_ps_ctl {
+ bool set_rfpowerstate_inprogress;
+ bool b_in_powersavemode;
+ bool rfchange_inprogress;
+ bool b_swrf_processing;
+ bool b_hwradiooff;
+
+ u32 last_sleep_jiffies;
+ u32 last_awake_jiffies;
+ u32 last_delaylps_stamp_jiffies;
+
+ /*
+ * just for PCIE ASPM
+ * If it supports ASPM, Offset[560h] = 0x40,
+ * otherwise Offset[560h] = 0x00.
+ * */
+ bool b_support_aspm;
+ bool b_support_backdoor;
+
+ /*for LPS */
+ enum rt_psmode dot11_psmode; /*Power save mode configured. */
+ bool b_leisure_ps;
+ bool b_fwctrl_lps;
+ u8 fwctrl_psmode;
+ /*For Fw control LPS mode */
+ u8 b_reg_fwctrl_lps;
+ /*Record Fw PS mode status. */
+ bool b_fw_current_inpsmode;
+ u8 reg_max_lps_awakeintvl;
+ bool report_linked;
+
+ /*for IPS */
+ bool b_inactiveps;
+
+ u32 rfoff_reason;
+
+ /*RF OFF Level */
+ u32 cur_ps_level;
+ u32 reg_rfps_level;
+
+ /*just for PCIE ASPM */
+ u8 const_amdpci_aspm;
+
+ enum rf_pwrstate inactive_pwrstate;
+ enum rf_pwrstate rfpwr_state; /*cur power state */
+};
+
+struct rtl_stats {
+ u32 mac_time[2];
+ s8 rssi;
+ u8 signal;
+ u8 noise;
+ u16 rate; /*in 100 kbps */
+ u8 received_channel;
+ u8 control;
+ u8 mask;
+ u8 freq;
+ u16 len;
+ u64 tsf;
+ u32 beacon_time;
+ u8 nic_type;
+ u16 length;
+ u8 signalquality; /*in 0-100 index. */
+ /*
+ * Real power in dBm for this packet,
+ * no beautification and aggregation.
+ * */
+ s32 recvsignalpower;
+ s8 rxpower; /*in dBm Translate from PWdB */
+ u8 signalstrength; /*in 0-100 index. */
+ u16 b_hwerror:1;
+ u16 b_crc:1;
+ u16 b_icv:1;
+ u16 b_shortpreamble:1;
+ u16 antenna:1;
+ u16 decrypted:1;
+ u16 wakeup:1;
+ u32 timestamp_low;
+ u32 timestamp_high;
+
+ u8 rx_drvinfo_size;
+ u8 rx_bufshift;
+ bool b_isampdu;
+ bool rx_is40Mhzpacket;
+ u32 rx_pwdb_all;
+ u8 rx_mimo_signalstrength[4]; /*in 0~100 index */
+ s8 rx_mimo_signalquality[2];
+ bool b_packet_matchbssid;
+ bool b_is_cck;
+ bool b_packet_toself;
+ bool b_packet_beacon; /*for rssi */
+ char cck_adc_pwdb[4]; /*for rx path selection */
+};
+
+struct rt_link_detect {
+ u32 num_tx_in4period[4];
+ u32 num_rx_in4period[4];
+
+ u32 num_tx_inperiod;
+ u32 num_rx_inperiod;
+
+ bool b_busytraffic;
+ bool b_higher_busytraffic;
+ bool b_higher_busyrxtraffic;
+};
+
+struct rtl_tcb_desc {
+ u8 b_packet_bw:1;
+ u8 b_multicast:1;
+ u8 b_broadcast:1;
+
+ u8 b_rts_stbc:1;
+ u8 b_rts_enable:1;
+ u8 b_cts_enable:1;
+ u8 b_rts_use_shortpreamble:1;
+ u8 b_rts_use_shortgi:1;
+ u8 rts_sc:1;
+ u8 b_rts_bw:1;
+ u8 rts_rate;
+
+ u8 use_shortgi:1;
+ u8 use_shortpreamble:1;
+ u8 use_driver_rate:1;
+ u8 disable_ratefallback:1;
+
+ u8 ratr_index;
+ u8 mac_id;
+ u8 hw_rate;
+};
+
+struct rtl_hal_ops {
+ int (*init_sw_vars) (struct ieee80211_hw *hw);
+ void (*deinit_sw_vars) (struct ieee80211_hw *hw);
+ void (*read_eeprom_info) (struct ieee80211_hw *hw);
+ void (*interrupt_recognized) (struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+ int (*hw_init) (struct ieee80211_hw *hw);
+ void (*hw_disable) (struct ieee80211_hw *hw);
+ void (*enable_interrupt) (struct ieee80211_hw *hw);
+ void (*disable_interrupt) (struct ieee80211_hw *hw);
+ int (*set_network_type) (struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
+ void (*set_bw_mode) (struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+ u8(*switch_channel) (struct ieee80211_hw *hw);
+ void (*set_qos) (struct ieee80211_hw *hw, int aci);
+ void (*set_bcn_reg) (struct ieee80211_hw *hw);
+ void (*set_bcn_intv) (struct ieee80211_hw *hw);
+ void (*update_interrupt_mask) (struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+ void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
+ void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
+ void (*update_rate_table) (struct ieee80211_hw *hw);
+ void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level);
+ void (*fill_tx_desc) (struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info,
+ struct sk_buff *skb, unsigned int queue_index);
+ void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+ bool(*query_rx_desc) (struct ieee80211_hw *hw,
+ struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+ void (*set_channel_access) (struct ieee80211_hw *hw);
+ bool(*radio_onoff_checking) (struct ieee80211_hw *hw, u8 *valid);
+ void (*dm_watchdog) (struct ieee80211_hw *hw);
+ void (*scan_operation_backup) (struct ieee80211_hw *hw, u8 operation);
+ bool(*set_rf_power_state) (struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+ void (*led_control) (struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction);
+ void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+ u32(*get_desc) (u8 *pdesc, bool istx, u8 desc_name);
+ void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue);
+ void (*enable_hw_sec) (struct ieee80211_hw *hw);
+ void (*set_key) (struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+ void (*init_sw_leds) (struct ieee80211_hw *hw);
+ void (*deinit_sw_leds) (struct ieee80211_hw *hw);
+ u32(*get_bbreg) (struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
+ void (*set_bbreg) (struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data);
+ u32(*get_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask);
+ void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
+};
+
+struct rtl_intf_ops {
+ /*com */
+ int (*adapter_start) (struct ieee80211_hw *hw);
+ void (*adapter_stop) (struct ieee80211_hw *hw);
+
+ int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb);
+ int (*reset_trx_ring) (struct ieee80211_hw *hw);
+
+ /*pci */
+ void (*disable_aspm) (struct ieee80211_hw *hw);
+ void (*enable_aspm) (struct ieee80211_hw *hw);
+
+ /*usb */
+};
+
+struct rtl_mod_params {
+ /* default: 0 = using hardware encryption */
+ int sw_crypto;
+};
+
+struct rtl_hal_cfg {
+ char *name;
+ char *fw_name;
+ struct rtl_hal_ops *ops;
+ struct rtl_mod_params *mod_params;
+
+ /*this map used for some registers or vars
+ defined int HAL but used in MAIN */
+ u32 maps[RTL_VAR_MAP_MAX];
+
+};
+
+struct rtl_locks {
+ /* mutex */
+ struct mutex conf_mutex;
+
+ /*spin lock */
+ spinlock_t ips_lock;
+ spinlock_t irq_th_lock;
+ spinlock_t h2c_lock;
+ spinlock_t rf_ps_lock;
+ spinlock_t rf_lock;
+ spinlock_t lps_lock;
+};
+
+struct rtl_works {
+ struct ieee80211_hw *hw;
+
+ /*timer */
+ struct timer_list watchdog_timer;
+
+ /*task */
+ struct tasklet_struct irq_tasklet;
+ struct tasklet_struct irq_prepare_bcn_tasklet;
+
+ /*work queue */
+ struct workqueue_struct *rtl_wq;
+ struct delayed_work watchdog_wq;
+ struct delayed_work ips_nic_off_wq;
+};
+
+struct rtl_debug {
+ u32 dbgp_type[DBGP_TYPE_MAX];
+ u32 global_debuglevel;
+ u64 global_debugcomponents;
+};
+
+struct rtl_priv {
+ struct rtl_locks locks;
+ struct rtl_works works;
+ struct rtl_mac mac80211;
+ struct rtl_hal rtlhal;
+ struct rtl_regulatory regd;
+ struct rtl_rfkill rfkill;
+ struct rtl_io io;
+ struct rtl_phy phy;
+ struct rtl_dm dm;
+ struct rtl_security sec;
+ struct rtl_efuse efuse;
+
+ struct rtl_ps_ctl psc;
+ struct rate_adaptive ra;
+ struct wireless_stats stats;
+ struct rt_link_detect link_info;
+ struct false_alarm_statistics falsealm_cnt;
+
+ struct rtl_rate_priv *rate_priv;
+
+ struct rtl_debug dbg;
+
+ /*
+ *hal_cfg : for diff cards
+ *intf_ops : for diff interrface usb/pcie
+ */
+ struct rtl_hal_cfg *cfg;
+ struct rtl_intf_ops *intf_ops;
+
+ /*this var will be set by set_bit,
+ and was used to indicate status of
+ interface or hardware */
+ unsigned long status;
+
+ /*This must be the last item so
+ that it points to the data allocated
+ beyond this structure like:
+ rtl_pci_priv or rtl_usb_priv */
+ u8 priv[0];
+};
+
+#define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv))
+#define rtl_mac(rtlpriv) (&((rtlpriv)->mac80211))
+#define rtl_hal(rtlpriv) (&((rtlpriv)->rtlhal))
+#define rtl_efuse(rtlpriv) (&((rtlpriv)->efuse))
+#define rtl_psc(rtlpriv) (&((rtlpriv)->psc))
+
+/****************************************
+ mem access macro define start
+ Call endian free function when
+ 1. Read/write packet content.
+ 2. Before write integer to IO.
+ 3. After read integer from IO.
+****************************************/
+/* Convert little data endian to host */
+#define EF1BYTE(_val) \
+ ((u8)(_val))
+#define EF2BYTE(_val) \
+ (le16_to_cpu(_val))
+#define EF4BYTE(_val) \
+ (le32_to_cpu(_val))
+
+/* Read data from memory */
+#define READEF1BYTE(_ptr) \
+ EF1BYTE(*((u8 *)(_ptr)))
+#define READEF2BYTE(_ptr) \
+ EF2BYTE(*((u16 *)(_ptr)))
+#define READEF4BYTE(_ptr) \
+ EF4BYTE(*((u32 *)(_ptr)))
+
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val) \
+ (*((u8 *)(_ptr))) = EF1BYTE(_val)
+#define WRITEEF2BYTE(_ptr, _val) \
+ (*((u16 *)(_ptr))) = EF2BYTE(_val)
+#define WRITEEF4BYTE(_ptr, _val) \
+ (*((u32 *)(_ptr))) = EF4BYTE(_val)
+
+/*Example:
+BIT_LEN_MASK_32(0) => 0x00000000
+BIT_LEN_MASK_32(1) => 0x00000001
+BIT_LEN_MASK_32(2) => 0x00000003
+BIT_LEN_MASK_32(32) => 0xFFFFFFFF*/
+#define BIT_LEN_MASK_32(__bitlen) \
+ (0xFFFFFFFF >> (32 - (__bitlen)))
+#define BIT_LEN_MASK_16(__bitlen) \
+ (0xFFFF >> (16 - (__bitlen)))
+#define BIT_LEN_MASK_8(__bitlen) \
+ (0xFF >> (8 - (__bitlen)))
+
+/*Example:
+BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
+BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000*/
+#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_16(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_8(__bitlen) << (__bitoffset))
+
+/*Description:
+Return 4-byte value in host byte ordering from
+4-byte pointer in little-endian system.*/
+#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \
+ (EF4BYTE(*((u32 *)(__pstart))))
+#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \
+ (EF2BYTE(*((u16 *)(__pstart))))
+#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
+ (EF1BYTE(*((u8 *)(__pstart))))
+
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_32(__bitlen) \
+ )
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_16(__bitlen) \
+ )
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_8(__bitlen) \
+ )
+
+/*Description:
+Mask subfield (continuous bits in little-endian) of 4-byte value
+and return the result in 4-byte value in host byte ordering.*/
+#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \
+ )
+#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \
+ )
+#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \
+ )
+
+/*Description:
+Set subfield of little-endian 4-byte value to specified value. */
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u32 *)(__pstart)) = EF4BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+ );
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u16 *)(__pstart)) = EF2BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+ );
+#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u8 *)(__pstart)) = EF1BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
+ );
+
+/****************************************
+ mem access macro define end
+****************************************/
+
+#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC)
+#define RTL_WATCH_DOG_TIME 2000
+#define MSECS(t) msecs_to_jiffies(t)
+#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA)
+#define 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)
+
+#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */
+#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */
+#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /*PCI D3 mode */
+/*NIC halt, re-initialize hw parameters*/
+#define RT_RF_OFF_LEVL_HALT_NIC BIT(3)
+#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /*FW free, re-download the FW */
+#define RT_RF_OFF_LEVL_FW_32K BIT(5) /*FW in 32k */
+/*Always enable ASPM and Clock Req in initialization.*/
+#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6)
+/*When LPS is on, disable 2R if no packet is received or transmittd.*/
+#define RT_RF_LPS_DISALBE_2R BIT(30)
+#define RT_RF_LPS_LEVEL_ASPM BIT(31) /*LPS with ASPM */
+#define RT_IN_PS_LEVEL(ppsc, _ps_flg) \
+ ((ppsc->cur_ps_level & _ps_flg) ? true : false)
+#define RT_CLEAR_PS_LEVEL(ppsc, _ps_flg) \
+ (ppsc->cur_ps_level &= (~(_ps_flg)))
+#define RT_SET_PS_LEVEL(ppsc, _ps_flg) \
+ (ppsc->cur_ps_level |= _ps_flg)
+
+#define container_of_dwork_rtl(x, y, z) \
+ container_of(container_of(x, struct delayed_work, work), y, z)
+
+#define FILL_OCTET_STRING(_os, _octet, _len) \
+ (_os).octet = (u8 *)(_octet); \
+ (_os).length = (_len);
+
+#define CP_MACADDR(des, src) \
+ ((des)[0] = (src)[0], (des)[1] = (src)[1],\
+ (des)[2] = (src)[2], (des)[3] = (src)[3],\
+ (des)[4] = (src)[4], (des)[5] = (src)[5])
+
+static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return rtlpriv->io.read8_sync(rtlpriv, addr);
+}
+
+static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return rtlpriv->io.read16_sync(rtlpriv, addr);
+}
+
+static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr)
+{
+ return rtlpriv->io.read32_sync(rtlpriv, addr);
+}
+
+static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8)
+{
+ rtlpriv->io.write8_async(rtlpriv, addr, val8);
+}
+
+static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16)
+{
+ rtlpriv->io.write16_async(rtlpriv, addr, val16);
+}
+
+static inline void rtl_write_dword(struct rtl_priv *rtlpriv,
+ u32 addr, u32 val32)
+{
+ rtlpriv->io.write32_async(rtlpriv, addr, val32);
+}
+
+static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask)
+{
+ return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_bbreg(hw,
+ regaddr,
+ bitmask);
+}
+
+static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr,
+ u32 bitmask, u32 data)
+{
+ ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_bbreg(hw,
+ regaddr, bitmask,
+ data);
+
+}
+
+static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask)
+{
+ return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_rfreg(hw,
+ rfpath,
+ regaddr,
+ bitmask);
+}
+
+static inline void rtl_set_rfreg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask, u32 data)
+{
+ ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_rfreg(hw,
+ rfpath, regaddr,
+ bitmask, data);
+}
+
+static inline bool is_hal_stop(struct rtl_hal *rtlhal)
+{
+ return (_HAL_STATE_STOP == rtlhal->state);
+}
+
+static inline void set_hal_start(struct rtl_hal *rtlhal)
+{
+ rtlhal->state = _HAL_STATE_START;
+}
+
+static inline void set_hal_stop(struct rtl_hal *rtlhal)
+{
+ rtlhal->state = _HAL_STATE_STOP;
+}
+
+static inline u8 get_rf_type(struct rtl_phy *rtlphy)
+{
+ return rtlphy->rf_type;
+}
+
+#endif
diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h
index e54b21a4f8b1..efcc3aaca14f 100644
--- a/drivers/net/wireless/wl1251/acx.h
+++ b/drivers/net/wireless/wl1251/acx.h
@@ -1272,10 +1272,10 @@ struct wl1251_acx_tid_cfg {
/* OBSOLETE */
#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
-/* Trace meassge on MBOX #A */
+/* Trace message on MBOX #A */
#define WL1251_ACX_INTR_TRACE_A BIT(7)
-/* Trace meassge on MBOX #B */
+/* Trace message on MBOX #B */
#define WL1251_ACX_INTR_TRACE_B BIT(8)
/* Command processing completion */
diff --git a/drivers/net/wireless/wl1251/boot.c b/drivers/net/wireless/wl1251/boot.c
index 61572dfa1f60..d729daf8e841 100644
--- a/drivers/net/wireless/wl1251/boot.c
+++ b/drivers/net/wireless/wl1251/boot.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/gpio.h>
#include <linux/slab.h>
#include "reg.h"
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c
index 7a8762553cdc..012e1a4016fe 100644
--- a/drivers/net/wireless/wl1251/main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -52,14 +52,14 @@ void wl1251_disable_interrupts(struct wl1251 *wl)
wl->if_ops->disable_irq(wl);
}
-static void wl1251_power_off(struct wl1251 *wl)
+static int wl1251_power_off(struct wl1251 *wl)
{
- wl->set_power(false);
+ return wl->if_ops->power(wl, false);
}
-static void wl1251_power_on(struct wl1251 *wl)
+static int wl1251_power_on(struct wl1251 *wl)
{
- wl->set_power(true);
+ return wl->if_ops->power(wl, true);
}
static int wl1251_fetch_firmware(struct wl1251 *wl)
@@ -152,9 +152,12 @@ static void wl1251_fw_wakeup(struct wl1251 *wl)
static int wl1251_chip_wakeup(struct wl1251 *wl)
{
- int ret = 0;
+ int ret;
+
+ ret = wl1251_power_on(wl);
+ if (ret < 0)
+ return ret;
- wl1251_power_on(wl);
msleep(WL1251_POWER_ON_SLEEP);
wl->if_ops->reset(wl);
diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c
index 74ba9ced5393..d550b5e68d3c 100644
--- a/drivers/net/wireless/wl1251/sdio.c
+++ b/drivers/net/wireless/wl1251/sdio.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/wl12xx.h>
#include <linux/irq.h>
+#include <linux/pm_runtime.h>
#include "wl1251.h"
@@ -42,8 +43,6 @@ struct wl1251_sdio {
u32 elp_val;
};
-static struct wl12xx_platform_data *wl12xx_board_data;
-
static struct sdio_func *wl_to_func(struct wl1251 *wl)
{
struct wl1251_sdio *wl_sdio = wl->if_priv;
@@ -171,8 +170,42 @@ static void wl1251_disable_line_irq(struct wl1251 *wl)
return disable_irq(wl->irq);
}
-static void wl1251_sdio_set_power(bool enable)
+static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
{
+ struct sdio_func *func = wl_to_func(wl);
+ int ret;
+
+ if (enable) {
+ /*
+ * Power is controlled by runtime PM, but we still call board
+ * callback in case it wants to do any additional setup,
+ * for example enabling clock buffer for the module.
+ */
+ if (wl->set_power)
+ wl->set_power(true);
+
+ ret = pm_runtime_get_sync(&func->dev);
+ if (ret < 0)
+ goto out;
+
+ sdio_claim_host(func);
+ sdio_enable_func(func);
+ sdio_release_host(func);
+ } else {
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ ret = pm_runtime_put_sync(&func->dev);
+ if (ret < 0)
+ goto out;
+
+ if (wl->set_power)
+ wl->set_power(false);
+ }
+
+out:
+ return ret;
}
static struct wl1251_if_operations wl1251_sdio_ops = {
@@ -181,30 +214,7 @@ static struct wl1251_if_operations wl1251_sdio_ops = {
.write_elp = wl1251_sdio_write_elp,
.read_elp = wl1251_sdio_read_elp,
.reset = wl1251_sdio_reset,
-};
-
-static int wl1251_platform_probe(struct platform_device *pdev)
-{
- if (pdev->id != -1) {
- wl1251_error("can only handle single device");
- return -ENODEV;
- }
-
- wl12xx_board_data = pdev->dev.platform_data;
- return 0;
-}
-
-/*
- * Dummy platform_driver for passing platform_data to this driver,
- * until we have a way to pass this through SDIO subsystem or
- * some other way.
- */
-static struct platform_driver wl1251_platform_driver = {
- .driver = {
- .name = "wl1251_data",
- .owner = THIS_MODULE,
- },
- .probe = wl1251_platform_probe,
+ .power = wl1251_sdio_set_power,
};
static int wl1251_sdio_probe(struct sdio_func *func,
@@ -214,6 +224,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
struct wl1251 *wl;
struct ieee80211_hw *hw;
struct wl1251_sdio *wl_sdio;
+ const struct wl12xx_platform_data *wl12xx_board_data;
hw = wl1251_alloc_hw();
if (IS_ERR(hw))
@@ -239,9 +250,9 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl_sdio->func = func;
wl->if_priv = wl_sdio;
wl->if_ops = &wl1251_sdio_ops;
- wl->set_power = wl1251_sdio_set_power;
- if (wl12xx_board_data != NULL) {
+ wl12xx_board_data = wl12xx_get_platform_data();
+ if (!IS_ERR(wl12xx_board_data)) {
wl->set_power = wl12xx_board_data->set_power;
wl->irq = wl12xx_board_data->irq;
wl->use_eeprom = wl12xx_board_data->use_eeprom;
@@ -273,6 +284,10 @@ static int wl1251_sdio_probe(struct sdio_func *func,
goto out_free_irq;
sdio_set_drvdata(func, wl);
+
+ /* Tell PM core that we don't need the card to be powered now */
+ pm_runtime_put_noidle(&func->dev);
+
return ret;
out_free_irq:
@@ -294,6 +309,9 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
struct wl1251 *wl = sdio_get_drvdata(func);
struct wl1251_sdio *wl_sdio = wl->if_priv;
+ /* Undo decrement done above in wl1251_probe */
+ pm_runtime_get_noresume(&func->dev);
+
if (wl->irq)
free_irq(wl->irq, wl);
kfree(wl_sdio);
@@ -305,23 +323,37 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
sdio_release_host(func);
}
+static int wl1251_suspend(struct device *dev)
+{
+ /*
+ * Tell MMC/SDIO core it's OK to power down the card
+ * (if it isn't already), but not to remove it completely.
+ */
+ return 0;
+}
+
+static int wl1251_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops wl1251_sdio_pm_ops = {
+ .suspend = wl1251_suspend,
+ .resume = wl1251_resume,
+};
+
static struct sdio_driver wl1251_sdio_driver = {
.name = "wl1251_sdio",
.id_table = wl1251_devices,
.probe = wl1251_sdio_probe,
.remove = __devexit_p(wl1251_sdio_remove),
+ .drv.pm = &wl1251_sdio_pm_ops,
};
static int __init wl1251_sdio_init(void)
{
int err;
- err = platform_driver_register(&wl1251_platform_driver);
- if (err) {
- wl1251_error("failed to register platform driver: %d", err);
- return err;
- }
-
err = sdio_register_driver(&wl1251_sdio_driver);
if (err)
wl1251_error("failed to register sdio driver: %d", err);
@@ -331,7 +363,6 @@ static int __init wl1251_sdio_init(void)
static void __exit wl1251_sdio_exit(void)
{
sdio_unregister_driver(&wl1251_sdio_driver);
- platform_driver_unregister(&wl1251_platform_driver);
wl1251_notice("unloaded");
}
diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c
index 88fa8e69d0d1..ac872b38960f 100644
--- a/drivers/net/wireless/wl1251/spi.c
+++ b/drivers/net/wireless/wl1251/spi.c
@@ -215,12 +215,21 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl)
return disable_irq(wl->irq);
}
+static int wl1251_spi_set_power(struct wl1251 *wl, bool enable)
+{
+ if (wl->set_power)
+ wl->set_power(enable);
+
+ return 0;
+}
+
static const struct wl1251_if_operations wl1251_spi_ops = {
.read = wl1251_spi_read,
.write = wl1251_spi_write,
.reset = wl1251_spi_reset_wake,
.enable_irq = wl1251_spi_enable_irq,
.disable_irq = wl1251_spi_disable_irq,
+ .power = wl1251_spi_set_power,
};
static int __devinit wl1251_spi_probe(struct spi_device *spi)
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index e113d4c1fb35..c0ce2c8b43b8 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -256,6 +256,7 @@ struct wl1251_if_operations {
void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len);
void (*read_elp)(struct wl1251 *wl, int addr, u32 *val);
void (*write_elp)(struct wl1251 *wl, int addr, u32 val);
+ int (*power)(struct wl1251 *wl, bool enable);
void (*reset)(struct wl1251 *wl);
void (*enable_irq)(struct wl1251 *wl);
void (*disable_irq)(struct wl1251 *wl);
@@ -418,7 +419,7 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
#define WL1251_FW_NAME "wl1251-fw.bin"
#define WL1251_NVS_NAME "wl1251-nvs.bin"
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
+#define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */
#define WL1251_PART_DOWN_MEM_START 0x0
#define WL1251_PART_DOWN_MEM_SIZE 0x16800
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index b447559f1db5..0e65bce457d6 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,46 +1,68 @@
-menuconfig WL12XX
+menuconfig WL12XX_MENU
tristate "TI wl12xx driver support"
depends on MAC80211 && EXPERIMENTAL
---help---
- This will enable TI wl12xx driver support. The drivers make
- use of the mac80211 stack.
+ This will enable TI wl12xx driver support for the following chips:
+ wl1271 and wl1273.
+ The drivers make use of the mac80211 stack.
-config WL1271
- tristate "TI wl1271 support"
- depends on WL12XX && GENERIC_HARDIRQS
+config WL12XX
+ tristate "TI wl12xx support"
+ depends on WL12XX_MENU && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
select CRC7
---help---
- This module adds support for wireless adapters based on the
- TI wl1271 chipset.
+ This module adds support for wireless adapters based on TI wl1271 and
+ TI wl1273 chipsets. This module does *not* include support for wl1251.
+ For wl1251 support, use the separate homonymous driver instead.
- If you choose to build a module, it'll be called wl1271. Say N if
+ If you choose to build a module, it will be called wl12xx. Say N if
unsure.
-config WL1271_SPI
- tristate "TI wl1271 SPI support"
- depends on WL1271 && SPI_MASTER
+config WL12XX_HT
+ bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)"
+ depends on WL12XX && EXPERIMENTAL
+ default n
+ ---help---
+ This will enable 802.11 HT support in the wl12xx module.
+
+ That configuration is temporary due to the code incomplete and
+ still in testing process.
+
+config WL12XX_SPI
+ tristate "TI wl12xx SPI support"
+ depends on WL12XX && SPI_MASTER
---help---
This module adds support for the SPI interface of adapters using
- TI wl1271 chipset. Select this if your platform is using
+ TI wl12xx chipsets. Select this if your platform is using
the SPI bus.
- If you choose to build a module, it'll be called wl1251_spi.
+ If you choose to build a module, it'll be called wl12xx_spi.
Say N if unsure.
-config WL1271_SDIO
- tristate "TI wl1271 SDIO support"
- depends on WL1271 && MMC
+config WL12XX_SDIO
+ tristate "TI wl12xx SDIO support"
+ depends on WL12XX && MMC
---help---
This module adds support for the SDIO interface of adapters using
- TI wl1271 chipset. Select this if your platform is using
+ TI wl12xx chipsets. Select this if your platform is using
the SDIO bus.
- If you choose to build a module, it'll be called
- wl1271_sdio. Say N if unsure.
+ If you choose to build a module, it'll be called wl12xx_sdio.
+ Say N if unsure.
+
+config WL12XX_SDIO_TEST
+ tristate "TI wl12xx SDIO testing support"
+ depends on WL12XX && MMC
+ default n
+ ---help---
+ This module adds support for the SDIO bus testing with the
+ TI wl12xx chipsets. You probably don't want this unless you are
+ testing a new hardware platform. Select this if you want to test the
+ SDIO bus which is connected to the wl12xx chip.
config WL12XX_PLATFORM_DATA
bool
- depends on WL1271_SDIO != n
+ depends on WL12XX_SDIO != n || WL1251_SDIO != n
default y
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 3a807444b2af..521c0414e52e 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,12 +1,16 @@
-wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
- wl1271_event.o wl1271_tx.o wl1271_rx.o \
- wl1271_ps.o wl1271_acx.o wl1271_boot.o \
- wl1271_init.o wl1271_debugfs.o wl1271_scan.o
-
-wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
-obj-$(CONFIG_WL1271) += wl1271.o
-obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o
-obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o
+wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
+ boot.o init.o debugfs.o scan.o
+
+wl12xx_spi-objs = spi.o
+wl12xx_sdio-objs = sdio.o
+wl12xx_sdio_test-objs = sdio_test.o
+
+wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o
+obj-$(CONFIG_WL12XX) += wl12xx.o
+obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
+obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
+
+obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
# small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/acx.c
index 618993405262..cc4068d2b4a8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -21,7 +21,7 @@
*
*/
-#include "wl1271_acx.h"
+#include "acx.h"
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -29,10 +29,10 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "wl1271.h"
+#include "wl12xx.h"
#include "wl12xx_80211.h"
-#include "wl1271_reg.h"
-#include "wl1271_ps.h"
+#include "reg.h"
+#include "ps.h"
int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
{
@@ -862,7 +862,7 @@ out:
return ret;
}
-int wl1271_acx_frag_threshold(struct wl1271 *wl)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;
@@ -876,7 +876,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl)
goto out;
}
- acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold);
+ acx->frag_threshold = cpu_to_le16(frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -1041,7 +1041,7 @@ out:
return ret;
}
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
{
struct wl1271_acx_arp_filter *acx;
int ret;
@@ -1057,7 +1057,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;
- if (enable == true)
+ if (enable)
memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
@@ -1226,6 +1226,89 @@ out:
return ret;
}
+int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation)
+{
+ struct wl1271_acx_ht_capabilities *acx;
+ u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Allow HT Operation ? */
+ if (allow_ht_operation) {
+ acx->ht_capabilites =
+ WL1271_ACX_FW_CAP_HT_OPERATION;
+ if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
+ acx->ht_capabilites |=
+ WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
+ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
+ acx->ht_capabilites |=
+ WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
+ if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
+ acx->ht_capabilites |=
+ WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
+
+ /* get data from A-MPDU parameters field */
+ acx->ampdu_max_length = ht_cap->ampdu_factor;
+ acx->ampdu_min_spacing = ht_cap->ampdu_density;
+
+ memcpy(acx->mac_address, mac_address, ETH_ALEN);
+ } else { /* HT operations are not allowed */
+ acx->ht_capabilites = 0;
+ }
+
+ ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx ht capabilities setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_set_ht_information(struct wl1271 *wl,
+ u16 ht_operation_mode)
+{
+ struct wl1271_acx_ht_information *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx ht information setting");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ht_protection =
+ (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
+ acx->rifs_mode = 0;
+ acx->gf_protection = 0;
+ acx->ht_tx_burst_limit = 0;
+ acx->dual_cts_protection = 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx));
+
+ if (ret < 0) {
+ wl1271_warning("acx ht information setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
{
struct wl1271_acx_fw_tsf_information *tsf_info;
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/acx.h
index ebb341d36e8c..7bd8e4db4a71 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -22,11 +22,11 @@
*
*/
-#ifndef __WL1271_ACX_H__
-#define __WL1271_ACX_H__
+#ifndef __ACX_H__
+#define __ACX_H__
-#include "wl1271.h"
-#include "wl1271_cmd.h"
+#include "wl12xx.h"
+#include "cmd.h"
/*************************************************************************
@@ -47,9 +47,9 @@
#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5)
/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */
#define WL1271_ACX_INTR_DATA BIT(6)
-/* Trace meassge on MBOX #A */
+/* Trace message on MBOX #A */
#define WL1271_ACX_INTR_TRACE_A BIT(7)
-/* Trace meassge on MBOX #B */
+/* Trace message on MBOX #B */
#define WL1271_ACX_INTR_TRACE_B BIT(8)
#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
@@ -61,7 +61,8 @@
WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
-#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
+#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
+ WL1271_ACX_INTR_EVENT_A | \
WL1271_ACX_INTR_EVENT_B | \
WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
@@ -867,10 +868,15 @@ struct wl1271_acx_bet_enable {
#define ACX_IPV4_VERSION 4
#define ACX_IPV6_VERSION 6
#define ACX_IPV4_ADDR_SIZE 4
+
+/* bitmap of enabled arp_filter features */
+#define ACX_ARP_FILTER_ARP_FILTERING BIT(0)
+#define ACX_ARP_FILTER_AUTO_ARP BIT(1)
+
struct wl1271_acx_arp_filter {
struct acx_header header;
u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
- u8 enable; /* 1 to enable ARP filtering, 0 to disable */
+ u8 enable; /* bitmap of enabled ARP filtering features */
u8 padding[2];
u8 address[16]; /* The configured device IP address - all ARP
requests directed to this IP address will pass
@@ -964,6 +970,87 @@ struct wl1271_acx_rssi_snr_avg_weights {
u8 snr_data;
};
+/*
+ * ACX_PEER_HT_CAP
+ * Configure HT capabilities - declare the capabilities of the peer
+ * we are connected to.
+ */
+struct wl1271_acx_ht_capabilities {
+ struct acx_header header;
+
+ /*
+ * bit 0 - Allow HT Operation
+ * bit 1 - Allow Greenfield format in TX
+ * bit 2 - Allow Short GI in TX
+ * bit 3 - Allow L-SIG TXOP Protection in TX
+ * bit 4 - Allow HT Control fields in TX.
+ * Note, driver will still leave space for HT control in packets
+ * regardless of the value of this field. FW will be responsible
+ * to drop the HT field from any frame when this Bit set to 0.
+ * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
+ * Exact policy setting for this feature is TBD.
+ * Note, this bit can only be set to 1 if bit 3 is set to 1.
+ */
+ __le32 ht_capabilites;
+
+ /*
+ * Indicates to which peer these capabilities apply.
+ * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance
+ * for all peers.
+ * Only valid for IBSS/DLS operation.
+ */
+ u8 mac_address[ETH_ALEN];
+
+ /*
+ * This the maximum A-MPDU length supported by the AP. The FW may not
+ * exceed this length when sending A-MPDUs
+ */
+ u8 ampdu_max_length;
+
+ /* This is the minimal spacing required when sending A-MPDUs to the AP*/
+ u8 ampdu_min_spacing;
+} __packed;
+
+/* HT Capabilites Fw Bit Mask Mapping */
+#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
+#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
+#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
+#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
+#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
+#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
+
+
+/*
+ * ACX_HT_BSS_OPERATION
+ * Configure HT capabilities - AP rules for behavior in the BSS.
+ */
+struct wl1271_acx_ht_information {
+ struct acx_header header;
+
+ /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */
+ u8 rifs_mode;
+
+ /* Values: 0 - 3 like in spec */
+ u8 ht_protection;
+
+ /* Values: 0 - GF protection not required, 1 - GF protection required */
+ u8 gf_protection;
+
+ /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/
+ u8 ht_tx_burst_limit;
+
+ /*
+ * Values: 0 - Dual CTS protection not required,
+ * 1 - Dual CTS Protection required
+ * Note: When this value is set to 1 FW will protect all TXOP with RTS
+ * frame and will not use CTS-to-self regardless of the value of the
+ * ACX_CTS_PROTECTION information element
+ */
+ u8 dual_cts_protection;
+
+ u8 padding[3];
+} __packed;
+
struct wl1271_acx_fw_tsf_information {
struct acx_header header;
@@ -1079,20 +1166,25 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
-int wl1271_acx_frag_threshold(struct wl1271 *wl);
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address);
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
int wl1271_acx_pm_config(struct wl1271 *wl);
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
s16 thold, u8 hyst);
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
+int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation);
+int wl1271_acx_set_ht_information(struct wl1271 *wl,
+ u16 ht_operation_mode);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/boot.c
index b91021242098..4df04f84d7f1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -21,14 +21,13 @@
*
*/
-#include <linux/gpio.h>
#include <linux/slab.h>
-#include "wl1271_acx.h"
-#include "wl1271_reg.h"
-#include "wl1271_boot.h"
-#include "wl1271_io.h"
-#include "wl1271_event.h"
+#include "acx.h"
+#include "reg.h"
+#include "boot.h"
+#include "io.h"
+#include "event.h"
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
@@ -467,24 +466,24 @@ static void wl1271_boot_hw_version(struct wl1271 *wl)
wl->hw_pg_ver = (s8)fuse;
}
-int wl1271_boot(struct wl1271 *wl)
+/* uploads NVS and firmware */
+int wl1271_load_firmware(struct wl1271 *wl)
{
int ret = 0;
u32 tmp, clk, pause;
- int ref_clock = wl->ref_clock;
wl1271_boot_hw_version(wl);
- if (ref_clock == 0 || ref_clock == 2 || ref_clock == 4)
+ if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4)
/* ref clk: 19.2/38.4/38.4-XTAL */
clk = 0x3;
- else if (ref_clock == 1 || ref_clock == 3)
+ else if (wl->ref_clock == 1 || wl->ref_clock == 3)
/* ref clk: 26/52 */
clk = 0x5;
else
return -EINVAL;
- if (ref_clock != 0) {
+ if (wl->ref_clock != 0) {
u16 val;
/* Set clock type (open drain) */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -529,8 +528,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
- /* 2 */
- clk |= (ref_clock << 1) << 4;
+ clk |= (wl->ref_clock << 1) << 4;
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -574,6 +572,20 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wl1271_load_firmware);
+
+int wl1271_boot(struct wl1271 *wl)
+{
+ int ret;
+
+ /* upload NVS and firmware */
+ ret = wl1271_load_firmware(wl);
+ if (ret)
+ return ret;
+
/* 10.5 start firmware */
ret = wl1271_boot_run_firmware(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/boot.h
index f73b0b15a280..d67dcffa31eb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -24,9 +24,10 @@
#ifndef __BOOT_H__
#define __BOOT_H__
-#include "wl1271.h"
+#include "wl12xx.h"
int wl1271_boot(struct wl1271 *wl);
+int wl1271_load_firmware(struct wl1271 *wl);
#define WL1271_NO_SUBBANDS 8
#define WL1271_NO_POWER_LEVELS 4
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 5d3e8485ea4e..0106628aa5a2 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -29,13 +29,13 @@
#include <linux/ieee80211.h>
#include <linux/slab.h>
-#include "wl1271.h"
-#include "wl1271_reg.h"
-#include "wl1271_io.h"
-#include "wl1271_acx.h"
+#include "wl12xx.h"
+#include "reg.h"
+#include "io.h"
+#include "acx.h"
#include "wl12xx_80211.h"
-#include "wl1271_cmd.h"
-#include "wl1271_event.h"
+#include "cmd.h"
+#include "event.h"
#define WL1271_CMD_FAST_POLL_COUNT 50
@@ -611,6 +611,75 @@ out:
return ret;
}
+struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
+ struct sk_buff *skb)
+{
+ int ret;
+
+ if (!skb)
+ skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
+ if (!skb)
+ goto out;
+
+ wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
+
+ if (wl->band == IEEE80211_BAND_2GHZ)
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ skb->data, skb->len, 0,
+ wl->conf.tx.basic_rate);
+ else
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ skb->data, skb->len, 0,
+ wl->conf.tx.basic_rate_5);
+
+ if (ret < 0)
+ wl1271_error("Unable to set ap probe request template.");
+
+out:
+ return skb;
+}
+
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
+{
+ int ret;
+ struct wl12xx_arp_rsp_template tmpl;
+ struct ieee80211_hdr_3addr *hdr;
+ struct arphdr *arp_hdr;
+
+ memset(&tmpl, 0, sizeof(tmpl));
+
+ /* mac80211 header */
+ hdr = &tmpl.hdr;
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_DATA |
+ IEEE80211_FCTL_TODS);
+ memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
+ memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
+ memset(hdr->addr3, 0xff, ETH_ALEN);
+
+ /* llc layer */
+ memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
+ tmpl.llc_type = htons(ETH_P_ARP);
+
+ /* arp header */
+ arp_hdr = &tmpl.arp_hdr;
+ arp_hdr->ar_hrd = htons(ARPHRD_ETHER);
+ arp_hdr->ar_pro = htons(ETH_P_IP);
+ arp_hdr->ar_hln = ETH_ALEN;
+ arp_hdr->ar_pln = 4;
+ arp_hdr->ar_op = htons(ARPOP_REPLY);
+
+ /* arp payload */
+ memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
+ tmpl.sender_ip = ip_addr;
+
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
+ &tmpl, sizeof(tmpl), 0,
+ wl->basic_rate);
+
+ return ret;
+}
+
int wl1271_build_qos_null_data(struct wl1271 *wl)
{
struct ieee80211_qos_hdr template;
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index a0caf4fc37b1..2a1d9db7ceb8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -22,10 +22,10 @@
*
*/
-#ifndef __WL1271_CMD_H__
-#define __WL1271_CMD_H__
+#ifndef __CMD_H__
+#define __CMD_H__
-#include "wl1271.h"
+#include "wl12xx.h"
struct acx_header;
@@ -49,6 +49,9 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
int wl1271_cmd_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band);
+struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
+ struct sk_buff *skb);
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
@@ -122,6 +125,7 @@ enum cmd_templ {
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
+ CMD_TEMPL_ARP_RSP,
CMD_TEMPL_MAX = 0xff
};
@@ -327,9 +331,6 @@ enum wl1271_channel_tune_bands {
#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
-#define TEST_CMD_P2G_CAL 0x02
-#define TEST_CMD_CHANNEL_TUNE 0x0d
-#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
@@ -375,51 +376,6 @@ struct wl1271_ext_radio_parms_cmd {
u8 padding[3];
} __packed;
-struct wl1271_cmd_cal_channel_tune {
- struct wl1271_cmd_header header;
-
- struct wl1271_cmd_test_header test;
-
- u8 band;
- u8 channel;
-
- __le16 radio_status;
-} __packed;
-
-struct wl1271_cmd_cal_update_ref_point {
- struct wl1271_cmd_header header;
-
- struct wl1271_cmd_test_header test;
-
- __le32 ref_power;
- __le32 ref_detector;
- u8 sub_band;
- u8 padding[3];
-} __packed;
-
-#define MAX_TLV_LENGTH 400
-#define MAX_NVS_VERSION_LENGTH 12
-
-#define WL1271_CAL_P2G_BAND_B_G BIT(0)
-
-struct wl1271_cmd_cal_p2g {
- struct wl1271_cmd_header header;
-
- struct wl1271_cmd_test_header test;
-
- __le16 len;
- u8 buf[MAX_TLV_LENGTH];
- u8 type;
- u8 padding;
-
- __le16 radio_status;
- u8 nvs_version[MAX_NVS_VERSION_LENGTH];
-
- u8 sub_band_mask;
- u8 padding2;
-} __packed;
-
-
/*
* There are three types of disconnections:
*
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/conf.h
index 5f78a6cb1433..a16b3616e430 100644
--- a/drivers/net/wireless/wl12xx/wl1271_conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -21,8 +21,8 @@
*
*/
-#ifndef __WL1271_CONF_H__
-#define __WL1271_CONF_H__
+#ifndef __CONF_H__
+#define __CONF_H__
enum {
CONF_HW_BIT_RATE_1MBPS = BIT(0),
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
new file mode 100644
index 000000000000..ec6077760157
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -0,0 +1,480 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "debugfs.h"
+
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+
+#include "wl12xx.h"
+#include "acx.h"
+#include "ps.h"
+#include "io.h"
+
+/* ms */
+#define WL1271_DEBUGFS_STATS_LIFETIME 1000
+
+/* debugfs macros idea from mac80211 */
+#define DEBUGFS_FORMAT_BUFFER_SIZE 100
+static int wl1271_format_buffer(char __user *userbuf, size_t count,
+ loff_t *ppos, char *fmt, ...)
+{
+ va_list args;
+ char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
+ int res;
+
+ va_start(args, fmt);
+ res = vscnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
+static ssize_t name## _read(struct file *file, char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct wl1271 *wl = file->private_data; \
+ return wl1271_format_buffer(userbuf, count, ppos, \
+ fmt "\n", ##value); \
+} \
+ \
+static const struct file_operations name## _ops = { \
+ .read = name## _read, \
+ .open = wl1271_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define DEBUGFS_ADD(name, parent) \
+ entry = debugfs_create_file(#name, 0400, parent, \
+ wl, &name## _ops); \
+ if (!entry || IS_ERR(entry)) \
+ goto err; \
+
+#define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \
+static ssize_t sub## _ ##name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct wl1271 *wl = file->private_data; \
+ \
+ wl1271_debugfs_update_stats(wl); \
+ \
+ return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \
+ wl->stats.fw_stats->sub.name); \
+} \
+ \
+static const struct file_operations sub## _ ##name## _ops = { \
+ .read = sub## _ ##name## _read, \
+ .open = wl1271_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define DEBUGFS_FWSTATS_ADD(sub, name) \
+ DEBUGFS_ADD(sub## _ ##name, stats)
+
+static void wl1271_debugfs_update_stats(struct wl1271 *wl)
+{
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1271_STATE_ON &&
+ time_after(jiffies, wl->stats.fw_stats_update +
+ msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
+ wl1271_acx_statistics(wl, wl->stats.fw_stats);
+ wl->stats.fw_stats_update = jiffies;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1271_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
+
+DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
+DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
+DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
+DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
+DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
+DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
+DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
+DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
+
+DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
+DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
+DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
+DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
+
+DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
+DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
+DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
+DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
+DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
+DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
+DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
+DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
+DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
+DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
+DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
+DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
+DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
+DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
+DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
+
+DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
+DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
+/* skipping wep.reserved */
+DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
+DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
+DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
+DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
+
+DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
+DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
+/* skipping cont_miss_bcns_spread for now */
+DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
+
+DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
+DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
+
+DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
+DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
+DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
+DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
+
+DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
+DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
+DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
+DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
+DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
+DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
+
+DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
+DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
+DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
+DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
+
+DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
+DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
+
+DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
+DEBUGFS_READONLY_FILE(excessive_retries, "%u",
+ wl->stats.excessive_retries);
+
+static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u32 queue_len;
+ char buf[20];
+ int res;
+
+ queue_len = wl->tx_queue_count;
+
+ res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+static const struct file_operations tx_queue_len_ops = {
+ .read = tx_queue_len_read,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+
+ int res;
+ char buf[10];
+
+ res = scnprintf(buf, sizeof(buf), "%d\n", state);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t gpio_power_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ buf[len] = '\0';
+
+ ret = strict_strtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value in gpio_power");
+ goto out;
+ }
+
+ if (value)
+ wl1271_power_on(wl);
+ else
+ wl1271_power_off(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations gpio_power_ops = {
+ .read = gpio_power_read,
+ .write = gpio_power_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static int wl1271_debugfs_add_files(struct wl1271 *wl)
+{
+ int ret = 0;
+ struct dentry *entry, *stats;
+
+ stats = debugfs_create_dir("fw-statistics", wl->rootdir);
+ if (!stats || IS_ERR(stats)) {
+ entry = stats;
+ goto err;
+ }
+
+ DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
+
+ DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
+ DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
+ DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
+ DEBUGFS_FWSTATS_ADD(rx, dropped);
+ DEBUGFS_FWSTATS_ADD(rx, fcs_err);
+ DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
+ DEBUGFS_FWSTATS_ADD(rx, path_reset);
+ DEBUGFS_FWSTATS_ADD(rx, reset_counter);
+
+ DEBUGFS_FWSTATS_ADD(dma, rx_requested);
+ DEBUGFS_FWSTATS_ADD(dma, rx_errors);
+ DEBUGFS_FWSTATS_ADD(dma, tx_requested);
+ DEBUGFS_FWSTATS_ADD(dma, tx_errors);
+
+ DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
+ DEBUGFS_FWSTATS_ADD(isr, fiqs);
+ DEBUGFS_FWSTATS_ADD(isr, rx_headers);
+ DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
+ DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
+ DEBUGFS_FWSTATS_ADD(isr, irqs);
+ DEBUGFS_FWSTATS_ADD(isr, tx_procs);
+ DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
+ DEBUGFS_FWSTATS_ADD(isr, dma0_done);
+ DEBUGFS_FWSTATS_ADD(isr, dma1_done);
+ DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
+ DEBUGFS_FWSTATS_ADD(isr, commands);
+ DEBUGFS_FWSTATS_ADD(isr, rx_procs);
+ DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
+ DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
+ DEBUGFS_FWSTATS_ADD(isr, pci_pm);
+ DEBUGFS_FWSTATS_ADD(isr, wakeups);
+ DEBUGFS_FWSTATS_ADD(isr, low_rssi);
+
+ DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
+ DEBUGFS_FWSTATS_ADD(wep, default_key_count);
+ /* skipping wep.reserved */
+ DEBUGFS_FWSTATS_ADD(wep, key_not_found);
+ DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
+ DEBUGFS_FWSTATS_ADD(wep, packets);
+ DEBUGFS_FWSTATS_ADD(wep, interrupt);
+
+ DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
+ DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
+ DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
+ DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
+ DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
+ DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
+ DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
+ DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
+ DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
+ /* skipping cont_miss_bcns_spread for now */
+ DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
+
+ DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
+ DEBUGFS_FWSTATS_ADD(mic, calc_failure);
+
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
+ DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
+ DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
+
+ DEBUGFS_FWSTATS_ADD(event, heart_beat);
+ DEBUGFS_FWSTATS_ADD(event, calibration);
+ DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
+ DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
+ DEBUGFS_FWSTATS_ADD(event, rx_pool);
+ DEBUGFS_FWSTATS_ADD(event, oom_late);
+ DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
+ DEBUGFS_FWSTATS_ADD(event, tx_stuck);
+
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
+ DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
+ DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
+
+ DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
+ DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
+ DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+
+ DEBUGFS_ADD(tx_queue_len, wl->rootdir);
+ DEBUGFS_ADD(retry_count, wl->rootdir);
+ DEBUGFS_ADD(excessive_retries, wl->rootdir);
+
+ DEBUGFS_ADD(gpio_power, wl->rootdir);
+
+ entry = debugfs_create_x32("debug_level", 0600, wl->rootdir,
+ &wl12xx_debug_level);
+ if (!entry || IS_ERR(entry))
+ goto err;
+
+ return 0;
+
+err:
+ if (IS_ERR(entry))
+ ret = PTR_ERR(entry);
+ else
+ ret = -ENOMEM;
+
+ return ret;
+}
+
+void wl1271_debugfs_reset(struct wl1271 *wl)
+{
+ if (!wl->rootdir)
+ return;
+
+ memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
+ wl->stats.retry_count = 0;
+ wl->stats.excessive_retries = 0;
+}
+
+int wl1271_debugfs_init(struct wl1271 *wl)
+{
+ int ret;
+
+ wl->rootdir = debugfs_create_dir(KBUILD_MODNAME,
+ wl->hw->wiphy->debugfsdir);
+
+ if (IS_ERR(wl->rootdir)) {
+ ret = PTR_ERR(wl->rootdir);
+ wl->rootdir = NULL;
+ goto err;
+ }
+
+ wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
+ GFP_KERNEL);
+
+ if (!wl->stats.fw_stats) {
+ ret = -ENOMEM;
+ goto err_fw;
+ }
+
+ wl->stats.fw_stats_update = jiffies;
+
+ ret = wl1271_debugfs_add_files(wl);
+
+ if (ret < 0)
+ goto err_file;
+
+ return 0;
+
+err_file:
+ kfree(wl->stats.fw_stats);
+ wl->stats.fw_stats = NULL;
+
+err_fw:
+ debugfs_remove_recursive(wl->rootdir);
+ wl->rootdir = NULL;
+
+err:
+ return ret;
+}
+
+void wl1271_debugfs_exit(struct wl1271 *wl)
+{
+ kfree(wl->stats.fw_stats);
+ wl->stats.fw_stats = NULL;
+
+ debugfs_remove_recursive(wl->rootdir);
+ wl->rootdir = NULL;
+
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h
index 00a45b2669ad..254c5b292cf6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_debugfs.h
+++ b/drivers/net/wireless/wl12xx/debugfs.h
@@ -21,10 +21,10 @@
*
*/
-#ifndef WL1271_DEBUGFS_H
-#define WL1271_DEBUGFS_H
+#ifndef __DEBUGFS_H__
+#define __DEBUGFS_H__
-#include "wl1271.h"
+#include "wl12xx.h"
int wl1271_debugfs_init(struct wl1271 *wl);
void wl1271_debugfs_exit(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/event.c
index 7b3f50382963..f9146f5242fb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -21,12 +21,12 @@
*
*/
-#include "wl1271.h"
-#include "wl1271_reg.h"
-#include "wl1271_io.h"
-#include "wl1271_event.h"
-#include "wl1271_ps.h"
-#include "wl1271_scan.h"
+#include "wl12xx.h"
+#include "reg.h"
+#include "io.h"
+#include "event.h"
+#include "ps.h"
+#include "scan.h"
#include "wl12xx_80211.h"
void wl1271_pspoll_work(struct work_struct *work)
@@ -134,8 +134,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
/* go to extremely low power mode */
wl1271_ps_elp_sleep(wl);
- if (ret < 0)
- break;
break;
case EVENT_EXIT_POWER_SAVE_FAIL:
wl1271_debug(DEBUG_PSM, "PSM exit failed");
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/event.h
index e4751667cf5e..6cce0143adb5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL1271_EVENT_H__
-#define __WL1271_EVENT_H__
+#ifndef __EVENT_H__
+#define __EVENT_H__
/*
* Mbox events
diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/ini.h
index 2313047d4015..c330a2583dfd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ini.h
+++ b/drivers/net/wireless/wl12xx/ini.h
@@ -21,8 +21,8 @@
*
*/
-#ifndef __WL1271_INI_H__
-#define __WL1271_INI_H__
+#ifndef __INI_H__
+#define __INI_H__
#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/init.c
index 8044bba70ee7..785a5304bfc4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -25,11 +25,11 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include "wl1271_init.h"
+#include "init.h"
#include "wl12xx_80211.h"
-#include "wl1271_acx.h"
-#include "wl1271_cmd.h"
-#include "wl1271_reg.h"
+#include "acx.h"
+#include "cmd.h"
+#include "reg.h"
static int wl1271_init_hwenc_config(struct wl1271 *wl)
{
@@ -53,18 +53,16 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
int wl1271_init_templates_config(struct wl1271 *wl)
{
int ret, i;
- size_t size;
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
- sizeof(struct wl12xx_probe_req_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- size = sizeof(struct wl12xx_probe_req_template);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- NULL, size, 0,
+ NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -102,6 +100,13 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
+ sizeof
+ (struct wl12xx_arp_rsp_template),
+ 0, WL1271_RATE_AUTOMATIC);
+ if (ret < 0)
+ return ret;
+
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
WL1271_CMD_TEMPL_MAX_SIZE, i,
@@ -290,7 +295,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl);
+ ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0)
goto out_free_memmap;
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/init.h
index bc26f8c53b91..7762421f8602 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -21,10 +21,10 @@
*
*/
-#ifndef __WL1271_INIT_H__
-#define __WL1271_INIT_H__
+#ifndef __INIT_H__
+#define __INIT_H__
-#include "wl1271.h"
+#include "wl12xx.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_init_templates_config(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/io.c
index c8759acef131..d557f73e7c19 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -26,9 +26,9 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include "wl1271.h"
+#include "wl12xx.h"
#include "wl12xx_80211.h"
-#include "wl1271_io.h"
+#include "io.h"
#define OCP_CMD_LOOP 32
@@ -113,6 +113,7 @@ int wl1271_set_partition(struct wl1271 *wl,
return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_set_partition);
void wl1271_io_reset(struct wl1271 *wl)
{
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/io.h
index c1f92e65ded0..844b32b170bb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -22,10 +22,10 @@
*
*/
-#ifndef __WL1271_IO_H__
-#define __WL1271_IO_H__
+#ifndef __IO_H__
+#define __IO_H__
-#include "wl1271_reg.h"
+#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/main.c
index 48a4b9961ae6..062247ef3ad2 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -31,20 +31,20 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include "wl1271.h"
+#include "wl12xx.h"
#include "wl12xx_80211.h"
-#include "wl1271_reg.h"
-#include "wl1271_io.h"
-#include "wl1271_event.h"
-#include "wl1271_tx.h"
-#include "wl1271_rx.h"
-#include "wl1271_ps.h"
-#include "wl1271_init.h"
-#include "wl1271_debugfs.h"
-#include "wl1271_cmd.h"
-#include "wl1271_boot.h"
-#include "wl1271_testmode.h"
-#include "wl1271_scan.h"
+#include "reg.h"
+#include "io.h"
+#include "event.h"
+#include "tx.h"
+#include "rx.h"
+#include "ps.h"
+#include "init.h"
+#include "debugfs.h"
+#include "cmd.h"
+#include "boot.h"
+#include "testmode.h"
+#include "scan.h"
#define WL1271_BOOT_RETRIES 3
@@ -335,6 +335,28 @@ out:
return NOTIFY_OK;
}
+static int wl1271_reg_notify(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel *ch;
+ int i;
+
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ for (i = 0; i < band->n_channels; i++) {
+ ch = &band->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (ch->flags & IEEE80211_CHAN_RADAR)
+ ch->flags |= IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN;
+
+ }
+
+ return 0;
+}
+
static void wl1271_conf_init(struct wl1271 *wl)
{
@@ -404,7 +426,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl);
+ ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0)
goto out_free_memmap;
@@ -481,9 +503,9 @@ static void wl1271_fw_status(struct wl1271 *wl,
total += cnt;
}
- /* if more blocks are available now, schedule some tx work */
- if (total && !skb_queue_empty(&wl->tx_queue))
- ieee80211_queue_work(wl->hw, &wl->tx_work);
+ /* if more blocks are available now, tx work can be scheduled */
+ if (total)
+ clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
/* update the host-chipset time offset */
getnstimeofday(&ts);
@@ -529,6 +551,15 @@ static void wl1271_irq_work(struct work_struct *work)
intr &= WL1271_INTR_MASK;
+ if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
+ wl1271_error("watchdog interrupt received! "
+ "starting recovery.");
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+
+ /* restarting the chip. ignore any other interrupt. */
+ goto out;
+ }
+
if (intr & WL1271_ACX_INTR_DATA) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
@@ -537,6 +568,16 @@ static void wl1271_irq_work(struct work_struct *work)
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
+ /* Check if any tx blocks were freed */
+ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
+ wl->tx_queue_count) {
+ /*
+ * In order to avoid starvation of the TX path,
+ * call the work function directly.
+ */
+ wl1271_tx_work_locked(wl);
+ }
+
wl1271_rx(wl, wl->fw_status);
}
@@ -850,30 +891,54 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txinfo->control.sta;
unsigned long flags;
+ int q;
- /* peek into the rates configured in the STA entry */
+ /*
+ * peek into the rates configured in the STA entry.
+ * The rates set after connection stage, The first block only BG sets:
+ * the compare is for bit 0-16 of sta_rate_set. The second block add
+ * HT rates in case of HT supported.
+ */
spin_lock_irqsave(&wl->wl_lock, flags);
- if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
+ if (sta &&
+ (sta->supp_rates[conf->channel->band] !=
+ (wl->sta_rate_set & HW_BG_RATES_MASK))) {
wl->sta_rate_set = sta->supp_rates[conf->channel->band];
set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
}
+
+#ifdef CONFIG_WL12XX_HT
+ if (sta &&
+ sta->ht_cap.ht_supported &&
+ ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
+ sta->ht_cap.mcs.rx_mask[0])) {
+ /* Clean MCS bits before setting them */
+ wl->sta_rate_set &= HW_BG_RATES_MASK;
+ wl->sta_rate_set |=
+ (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
+ set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
+ }
+#endif
+ wl->tx_queue_count++;
spin_unlock_irqrestore(&wl->wl_lock, flags);
/* queue the packet */
- skb_queue_tail(&wl->tx_queue, skb);
+ q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+ skb_queue_tail(&wl->tx_queue[q], skb);
/*
* The chip specific setup must run before the first TX packet -
* before that, the tx_work will not be initialized!
*/
- ieee80211_queue_work(wl->hw, &wl->tx_work);
+ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+ if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
spin_lock_irqsave(&wl->wl_lock, flags);
@@ -919,18 +984,19 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct wiphy *wiphy = hw->wiphy;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;
+ bool booted = false;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
vif->type, vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
+ wl1271_debug(DEBUG_MAC80211,
+ "multiple vifs are not supported yet");
ret = -EBUSY;
goto out;
}
- wl->vif = vif;
-
switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
@@ -968,15 +1034,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto irq_disable;
- wl->state = WL1271_STATE_ON;
- wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
-
- /* update hw/fw version info in wiphy struct */
- wiphy->hw_version = wl->chip.id;
- strncpy(wiphy->fw_version, wl->chip.fw_ver,
- sizeof(wiphy->fw_version));
-
- goto out;
+ booted = true;
+ break;
irq_disable:
wl1271_disable_interrupts(wl);
@@ -994,8 +1053,31 @@ power_off:
wl1271_power_off(wl);
}
- wl1271_error("firmware boot failed despite %d retries",
- WL1271_BOOT_RETRIES);
+ if (!booted) {
+ wl1271_error("firmware boot failed despite %d retries",
+ WL1271_BOOT_RETRIES);
+ goto out;
+ }
+
+ wl->vif = vif;
+ wl->state = WL1271_STATE_ON;
+ wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+
+ /* update hw/fw version info in wiphy struct */
+ wiphy->hw_version = wl->chip.id;
+ strncpy(wiphy->fw_version, wl->chip.fw_ver,
+ sizeof(wiphy->fw_version));
+
+ /*
+ * Now we know if 11a is supported (info from the NVS), so disable
+ * 11a channels if not supported
+ */
+ if (!wl->enable_11a)
+ wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
+ wl->enable_11a ? "" : "not ");
+
out:
mutex_unlock(&wl->mutex);
@@ -1025,6 +1107,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
+ wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
}
@@ -1088,10 +1171,16 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
mutex_lock(&wl->mutex);
- WARN_ON(wl->vif != vif);
- __wl1271_op_remove_interface(wl);
- mutex_unlock(&wl->mutex);
+ /*
+ * wl->vif can be null here if someone shuts down the interface
+ * just when hardware recovery has been started.
+ */
+ if (wl->vif) {
+ WARN_ON(wl->vif != vif);
+ __wl1271_op_remove_interface(wl);
+ }
+ mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
}
@@ -1312,8 +1401,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL1271_STATE_OFF))
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
goto out;
+ }
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
@@ -1536,6 +1627,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out_unlock;
@@ -1645,6 +1741,16 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
+ if (wl->state == WL1271_STATE_OFF) {
+ /*
+ * We cannot return -EBUSY here because cfg80211 will expect
+ * a call to ieee80211_scan_completed if we do - in this case
+ * there won't be any call.
+ */
+ ret = -EAGAIN;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
@@ -1659,6 +1765,34 @@ out:
return ret;
}
+static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret = 0;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_frag_threshold(wl, (u16)value);
+ if (ret < 0)
+ wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct wl1271 *wl = hw->priv;
@@ -1666,8 +1800,10 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL1271_STATE_OFF))
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
goto out;
+ }
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
@@ -1685,21 +1821,21 @@ out:
return ret;
}
-static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
+static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
+ int offset)
{
- u8 *ptr = beacon->data +
- offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ u8 *ptr = skb->data + offset;
/* find the location of the ssid in the beacon */
- while (ptr < beacon->data + beacon->len) {
+ while (ptr < skb->data + skb->len) {
if (ptr[0] == WLAN_EID_SSID) {
wl->ssid_len = ptr[1];
memcpy(wl->ssid, ptr+2, wl->ssid_len);
return;
}
- ptr += ptr[1];
+ ptr += (ptr[1] + 2);
}
- wl1271_error("ad-hoc beacon template has no SSID!\n");
+ wl1271_error("No SSID in IEs!\n");
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -1709,6 +1845,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
{
enum wl1271_cmd_ps_mode mode;
struct wl1271 *wl = hw->priv;
+ struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
bool do_join = false;
bool set_assoc = false;
int ret;
@@ -1717,6 +1854,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
@@ -1738,8 +1878,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (beacon) {
struct ieee80211_hdr *hdr;
+ int ieoffset = offsetof(struct ieee80211_mgmt,
+ u.beacon.variable);
+
+ wl1271_ssid_set(wl, beacon, ieoffset);
- wl1271_ssid_set(wl, beacon);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
beacon->data,
beacon->len, 0,
@@ -1819,6 +1962,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
u32 rates;
+ int ieoffset;
wl->aid = bss_conf->aid;
set_assoc = true;
@@ -1847,13 +1991,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
goto out_sleep;
/*
- * The SSID is intentionally set to NULL here - the
- * firmware will set the probe request with a
- * broadcast SSID regardless of what we set in the
- * template.
+ * Get a template for hardware connection maintenance
*/
- ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
- NULL, 0, wl->band);
+ dev_kfree_skb(wl->probereq);
+ wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
+ ieoffset = offsetof(struct ieee80211_mgmt,
+ u.probe_req.variable);
+ wl1271_ssid_set(wl, wl->probereq, ieoffset);
/* enable the connection monitoring feature */
ret = wl1271_acx_conn_monit_params(wl, true);
@@ -1876,6 +2020,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
+ /* free probe-request template */
+ dev_kfree_skb(wl->probereq);
+ wl->probereq = NULL;
+
/* re-enable dynamic ps - just in case */
ieee80211_enable_dyn_ps(wl->vif);
@@ -1891,9 +2039,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* Disable the keep-alive feature */
ret = wl1271_acx_keep_alive_mode(wl, false);
-
if (ret < 0)
goto out_sleep;
+
+ /* restore the bssid filter and go to dummy bssid */
+ wl1271_unjoin(wl);
+ wl1271_dummy_join(wl);
}
}
@@ -1927,14 +2078,61 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ /*
+ * Takes care of: New association with HT enable,
+ * HT information change in beacon.
+ */
+ if (sta &&
+ (changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap true failed %d", ret);
+ goto out_sleep;
+ }
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out_sleep;
+ }
+ }
+ /*
+ * Takes care of: New association without HT,
+ * Disassociation.
+ */
+ else if (sta && (changed & BSS_CHANGED_ASSOC)) {
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap false failed %d", ret);
+ goto out_sleep;
+ }
+ }
+
if (changed & BSS_CHANGED_ARP_FILTER) {
__be32 addr = bss_conf->arp_addr_list[0];
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
- if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
- ret = wl1271_acx_arp_ip_filter(wl, true, addr);
- else
- ret = wl1271_acx_arp_ip_filter(wl, false, addr);
+ if (bss_conf->arp_addr_cnt == 1 &&
+ bss_conf->arp_filter_enabled) {
+ /*
+ * The template should have been configured only upon
+ * association. however, it seems that the correct ip
+ * isn't being set (when sending), so we have to
+ * reconfigure the template upon every ip change.
+ */
+ ret = wl1271_cmd_build_arp_rsp(wl, addr);
+ if (ret < 0) {
+ wl1271_warning("build arp rsp failed: %d", ret);
+ goto out_sleep;
+ }
+
+ ret = wl1271_acx_arp_ip_filter(wl,
+ (ACX_ARP_FILTER_ARP_FILTERING |
+ ACX_ARP_FILTER_AUTO_ARP),
+ addr);
+ } else
+ ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
if (ret < 0)
goto out_sleep;
@@ -1966,6 +2164,11 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
@@ -2009,6 +2212,9 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
@@ -2030,14 +2236,14 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
{
struct wl1271 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
-
+
if (idx != 0)
return -ENOENT;
-
+
survey->channel = conf->channel;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = wl->noise;
-
+
return 0;
}
@@ -2084,37 +2290,34 @@ static struct ieee80211_rate wl1271_rates[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
-/*
- * Can't be const, mac80211 writes to this. The order of the channels here
- * is designed to improve scanning.
- */
+/* can't be const, mac80211 writes to this */
static struct ieee80211_channel wl1271_channels[] = {
{ .hw_value = 1, .center_freq = 2412, .max_power = 25 },
- { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
- { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
- { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
- { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
- { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
- { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
- { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
- { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
- { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+ { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+ { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+ { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+ { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+ { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+ { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
+ { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+ { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+ { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
};
/* mapping to indexes for wl1271_rates */
static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+ 7, /* CONF_HW_RXTX_RATE_MCS7 */
+ 6, /* CONF_HW_RXTX_RATE_MCS6 */
+ 5, /* CONF_HW_RXTX_RATE_MCS5 */
+ 4, /* CONF_HW_RXTX_RATE_MCS4 */
+ 3, /* CONF_HW_RXTX_RATE_MCS3 */
+ 2, /* CONF_HW_RXTX_RATE_MCS2 */
+ 1, /* CONF_HW_RXTX_RATE_MCS1 */
+ 0, /* CONF_HW_RXTX_RATE_MCS0 */
11, /* CONF_HW_RXTX_RATE_54 */
10, /* CONF_HW_RXTX_RATE_48 */
@@ -2134,12 +2337,34 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
0 /* CONF_HW_RXTX_RATE_1 */
};
+/* 11n STA capabilities */
+#define HW_RX_HIGHEST_RATE 72
+
+#ifdef CONFIG_WL12XX_HT
+#define WL12XX_HT_CAP { \
+ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
+ .ht_supported = true, \
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
+ .mcs = { \
+ .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
+ }, \
+}
+#else
+#define WL12XX_HT_CAP { \
+ .ht_supported = false, \
+}
+#endif
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1271_band_2ghz = {
.channels = wl1271_channels,
.n_channels = ARRAY_SIZE(wl1271_channels),
.bitrates = wl1271_rates,
.n_bitrates = ARRAY_SIZE(wl1271_rates),
+ .ht_cap = WL12XX_HT_CAP,
};
/* 5 GHz data rates for WL1273 */
@@ -2170,66 +2395,55 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
-/*
- * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
- * The order of the channels here is designed to improve scanning.
- */
+/* 5 GHz band channels for WL1273 */
static struct ieee80211_channel wl1271_channels_5ghz[] = {
- { .hw_value = 183, .center_freq = 4915},
- { .hw_value = 188, .center_freq = 4940},
+ { .hw_value = 7, .center_freq = 5035},
{ .hw_value = 8, .center_freq = 5040},
- { .hw_value = 34, .center_freq = 5170},
- { .hw_value = 44, .center_freq = 5220},
- { .hw_value = 60, .center_freq = 5300},
- { .hw_value = 112, .center_freq = 5560},
- { .hw_value = 132, .center_freq = 5660},
- { .hw_value = 157, .center_freq = 5785},
- { .hw_value = 184, .center_freq = 4920},
- { .hw_value = 189, .center_freq = 4945},
{ .hw_value = 9, .center_freq = 5045},
- { .hw_value = 36, .center_freq = 5180},
- { .hw_value = 46, .center_freq = 5230},
- { .hw_value = 64, .center_freq = 5320},
- { .hw_value = 116, .center_freq = 5580},
- { .hw_value = 136, .center_freq = 5680},
- { .hw_value = 192, .center_freq = 4960},
{ .hw_value = 11, .center_freq = 5055},
- { .hw_value = 38, .center_freq = 5190},
- { .hw_value = 48, .center_freq = 5240},
- { .hw_value = 100, .center_freq = 5500},
- { .hw_value = 120, .center_freq = 5600},
- { .hw_value = 140, .center_freq = 5700},
- { .hw_value = 185, .center_freq = 4925},
- { .hw_value = 196, .center_freq = 4980},
{ .hw_value = 12, .center_freq = 5060},
- { .hw_value = 40, .center_freq = 5200},
- { .hw_value = 52, .center_freq = 5260},
- { .hw_value = 104, .center_freq = 5520},
- { .hw_value = 124, .center_freq = 5620},
- { .hw_value = 149, .center_freq = 5745},
- { .hw_value = 161, .center_freq = 5805},
- { .hw_value = 187, .center_freq = 4935},
- { .hw_value = 7, .center_freq = 5035},
{ .hw_value = 16, .center_freq = 5080},
+ { .hw_value = 34, .center_freq = 5170},
+ { .hw_value = 36, .center_freq = 5180},
+ { .hw_value = 38, .center_freq = 5190},
+ { .hw_value = 40, .center_freq = 5200},
{ .hw_value = 42, .center_freq = 5210},
+ { .hw_value = 44, .center_freq = 5220},
+ { .hw_value = 46, .center_freq = 5230},
+ { .hw_value = 48, .center_freq = 5240},
+ { .hw_value = 52, .center_freq = 5260},
{ .hw_value = 56, .center_freq = 5280},
+ { .hw_value = 60, .center_freq = 5300},
+ { .hw_value = 64, .center_freq = 5320},
+ { .hw_value = 100, .center_freq = 5500},
+ { .hw_value = 104, .center_freq = 5520},
{ .hw_value = 108, .center_freq = 5540},
+ { .hw_value = 112, .center_freq = 5560},
+ { .hw_value = 116, .center_freq = 5580},
+ { .hw_value = 120, .center_freq = 5600},
+ { .hw_value = 124, .center_freq = 5620},
{ .hw_value = 128, .center_freq = 5640},
+ { .hw_value = 132, .center_freq = 5660},
+ { .hw_value = 136, .center_freq = 5680},
+ { .hw_value = 140, .center_freq = 5700},
+ { .hw_value = 149, .center_freq = 5745},
{ .hw_value = 153, .center_freq = 5765},
+ { .hw_value = 157, .center_freq = 5785},
+ { .hw_value = 161, .center_freq = 5805},
{ .hw_value = 165, .center_freq = 5825},
};
/* mapping to indexes for wl1271_rates_5ghz */
static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+ 7, /* CONF_HW_RXTX_RATE_MCS7 */
+ 6, /* CONF_HW_RXTX_RATE_MCS6 */
+ 5, /* CONF_HW_RXTX_RATE_MCS5 */
+ 4, /* CONF_HW_RXTX_RATE_MCS4 */
+ 3, /* CONF_HW_RXTX_RATE_MCS3 */
+ 2, /* CONF_HW_RXTX_RATE_MCS2 */
+ 1, /* CONF_HW_RXTX_RATE_MCS1 */
+ 0, /* CONF_HW_RXTX_RATE_MCS0 */
7, /* CONF_HW_RXTX_RATE_54 */
6, /* CONF_HW_RXTX_RATE_48 */
@@ -2254,6 +2468,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
.n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
.bitrates = wl1271_rates_5ghz,
.n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
+ .ht_cap = WL12XX_HT_CAP,
};
static const u8 *wl1271_band_rate_to_idx[] = {
@@ -2273,6 +2488,7 @@ static const struct ieee80211_ops wl1271_ops = {
.set_key = wl1271_op_set_key,
.hw_scan = wl1271_op_hw_scan,
.bss_info_changed = wl1271_op_bss_info_changed,
+ .set_frag_threshold = wl1271_op_set_frag_threshold,
.set_rts_threshold = wl1271_op_set_rts_threshold,
.conf_tx = wl1271_op_conf_tx,
.get_tsf = wl1271_op_get_tsf,
@@ -2281,18 +2497,18 @@ static const struct ieee80211_ops wl1271_ops = {
};
-u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
+u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
{
u8 idx;
- BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
+ BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
wl1271_error("Illegal RX rate from HW: %d", rate);
return 0;
}
- idx = wl1271_band_rate_to_idx[wl->band][rate];
+ idx = wl1271_band_rate_to_idx[band][rate];
if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
wl1271_error("Unsupported RX rate from HW: %d", rate);
return 0;
@@ -2401,6 +2617,8 @@ int wl1271_register_hw(struct wl1271 *wl)
wl->mac80211_registered = true;
+ wl1271_debugfs_init(wl);
+
register_netdevice_notifier(&wl1271_dev_notifier);
wl1271_notice("loaded");
@@ -2451,12 +2669,21 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
wl->hw->wiphy->max_scan_ssids = 1;
+ /*
+ * Maximum length of elements in scanning probe request templates
+ * should be the maximum length possible for a template, without
+ * the IEEE80211 header of the template
+ */
+ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
+ sizeof(struct ieee80211_header);
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
wl->hw->queues = 4;
wl->hw->max_rates = 1;
+ wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
+
SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
return 0;
@@ -2495,7 +2722,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->hw = hw;
wl->plat_dev = plat_dev;
- skb_queue_head_init(&wl->tx_queue);
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ skb_queue_head_init(&wl->tx_queue[i]);
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
@@ -2521,6 +2749,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->sg_enabled = true;
wl->hw_pg_ver = -1;
+ memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
@@ -2532,8 +2761,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
/* Apply default driver configuration. */
wl1271_conf_init(wl);
- wl1271_debugfs_init(wl);
-
order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
if (!wl->aggr_buf) {
@@ -2610,6 +2837,11 @@ int wl1271_free_hw(struct wl1271 *wl)
}
EXPORT_SYMBOL_GPL(wl1271_free_hw);
+u32 wl12xx_debug_level;
+EXPORT_SYMBOL_GPL(wl12xx_debug_level);
+module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
+MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/ps.c
index e3c332e2f97c..60a3738eadb0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -21,9 +21,9 @@
*
*/
-#include "wl1271_reg.h"
-#include "wl1271_ps.h"
-#include "wl1271_io.h"
+#include "reg.h"
+#include "ps.h"
+#include "io.h"
#define WL1271_WAKEUP_TIMEOUT 500
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/ps.h
index 6ba7b032736f..8415060f08e5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -21,11 +21,11 @@
*
*/
-#ifndef __WL1271_PS_H__
-#define __WL1271_PS_H__
+#ifndef __PS_H__
+#define __PS_H__
-#include "wl1271.h"
-#include "wl1271_acx.h"
+#include "wl12xx.h"
+#include "acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
u32 rates, bool send);
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/reg.h
index 990960771528..990960771528 100644
--- a/drivers/net/wireless/wl12xx/wl1271_reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/rx.c
index bea133b6e489..682304c30b81 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -23,11 +23,11 @@
#include <linux/gfp.h>
-#include "wl1271.h"
-#include "wl1271_acx.h"
-#include "wl1271_reg.h"
-#include "wl1271_rx.h"
-#include "wl1271_io.h"
+#include "wl12xx.h"
+#include "acx.h"
+#include "reg.h"
+#include "rx.h"
+#include "io.h"
static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
@@ -48,10 +48,24 @@ static void wl1271_rx_status(struct wl1271 *wl,
struct ieee80211_rx_status *status,
u8 beacon)
{
+ enum ieee80211_band desc_band;
+
memset(status, 0, sizeof(struct ieee80211_rx_status));
status->band = wl->band;
- status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
+
+ if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
+ desc_band = IEEE80211_BAND_2GHZ;
+ else
+ desc_band = IEEE80211_BAND_5GHZ;
+
+ status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band);
+
+#ifdef CONFIG_WL12XX_HT
+ /* 11n support */
+ if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
+ status->flag |= RX_FLAG_HT;
+#endif
status->signal = desc->rssi;
@@ -170,10 +184,14 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
while (pkt_offset < buf_size) {
pkt_length = wl1271_rx_get_buf_size(status,
drv_rx_counter);
- if (wl1271_rx_handle_data(wl,
- wl->aggr_buf + pkt_offset,
- pkt_length) < 0)
- break;
+ /*
+ * the handle data call can only fail in memory-outage
+ * conditions, in that case the received frame will just
+ * be dropped.
+ */
+ wl1271_rx_handle_data(wl,
+ wl->aggr_buf + pkt_offset,
+ pkt_length);
wl->rx_counter++;
drv_rx_counter++;
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/rx.h
index 13a232333b13..3abb26fe0364 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL1271_RX_H__
-#define __WL1271_RX_H__
+#ifndef __RX_H__
+#define __RX_H__
#include <linux/bitops.h>
@@ -116,6 +116,6 @@ struct wl1271_rx_descriptor {
} __packed;
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
-u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
+u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/scan.c
index 909bb47995b6..6f897b9d90ca 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -23,10 +23,10 @@
#include <linux/ieee80211.h>
-#include "wl1271.h"
-#include "wl1271_cmd.h"
-#include "wl1271_scan.h"
-#include "wl1271_acx.h"
+#include "wl12xx.h"
+#include "cmd.h"
+#include "scan.h"
+#include "acx.h"
void wl1271_scan_complete_work(struct work_struct *work)
{
@@ -48,14 +48,19 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
- mutex_unlock(&wl->mutex);
-
+ wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, false);
+ /* restore hardware connection monitoring template */
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
+
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
}
+ mutex_unlock(&wl->mutex);
+
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/scan.h
index 6d57127b5e6b..421a750add5a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -21,10 +21,10 @@
*
*/
-#ifndef __WL1271_SCAN_H__
-#define __WL1271_SCAN_H__
+#ifndef __SCAN_H__
+#define __SCAN_H__
-#include "wl1271.h"
+#include "wl12xx.h"
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req);
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 784ef3432641..93cbb8d5aba9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -32,9 +32,9 @@
#include <linux/wl12xx.h>
#include <linux/pm_runtime.h>
-#include "wl1271.h"
+#include "wl12xx.h"
#include "wl12xx_80211.h"
-#include "wl1271_io.h"
+#include "io.h"
#ifndef SDIO_VENDOR_ID_TI
#define SDIO_VENDOR_ID_TI 0x0097
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c
new file mode 100644
index 000000000000..9fcbd3dd8490
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/sdio_test.c
@@ -0,0 +1,520 @@
+/*
+ * SDIO testing driver for wl12xx
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * wl12xx read/write routines taken from the main module
+ *
+ * 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/irq.h>
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/vmalloc.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/gpio.h>
+#include <linux/wl12xx.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+
+#include "wl12xx.h"
+#include "io.h"
+#include "boot.h"
+
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI 0x0097
+#endif
+
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271 0x4076
+#endif
+
+static bool rx, tx;
+
+module_param(rx, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rx, "Perform rx test. Default (0). "
+ "This test continuously reads data from the SDIO device.\n");
+
+module_param(tx, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tx, "Perform tx test. Default (0). "
+ "This test continuously writes data to the SDIO device.\n");
+
+struct wl1271_test {
+ struct wl1271 wl;
+ struct task_struct *test_task;
+};
+
+static const struct sdio_device_id wl1271_devices[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
+ {}
+};
+
+static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
+{
+ return wl->if_priv;
+}
+
+static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
+{
+ return &(wl_to_func(wl)->dev);
+}
+
+static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int ret = 0;
+ struct sdio_func *func = wl_to_func(wl);
+
+ if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+ ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
+ wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
+ addr, ((u8 *)buf)[0]);
+ } else {
+ if (fixed)
+ ret = sdio_readsb(func, buf, addr, len);
+ else
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+
+ wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
+ addr, len);
+ wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
+ }
+
+ if (ret)
+ wl1271_error("sdio read failed (%d)", ret);
+}
+
+static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int ret = 0;
+ struct sdio_func *func = wl_to_func(wl);
+
+ if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+ sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
+ wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
+ addr, ((u8 *)buf)[0]);
+ } else {
+ wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
+ addr, len);
+ wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
+
+ if (fixed)
+ ret = sdio_writesb(func, addr, buf, len);
+ else
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ }
+ if (ret)
+ wl1271_error("sdio write failed (%d)", ret);
+
+}
+
+static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
+{
+ struct sdio_func *func = wl_to_func(wl);
+ int ret;
+
+ /* Let the SDIO stack handle wlan_enable control, so we
+ * keep host claimed while wlan is in use to keep wl1271
+ * alive.
+ */
+ if (enable) {
+ /* Power up the card */
+ ret = pm_runtime_get_sync(&func->dev);
+ if (ret < 0)
+ goto out;
+ sdio_claim_host(func);
+ sdio_enable_func(func);
+ sdio_release_host(func);
+ } else {
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ /* Power down the card */
+ ret = pm_runtime_put_sync(&func->dev);
+ }
+
+out:
+ return ret;
+}
+
+static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
+{
+}
+
+static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
+{
+}
+
+
+static struct wl1271_if_operations sdio_ops = {
+ .read = wl1271_sdio_raw_read,
+ .write = wl1271_sdio_raw_write,
+ .power = wl1271_sdio_set_power,
+ .dev = wl1271_sdio_wl_to_dev,
+ .enable_irq = wl1271_sdio_enable_interrupts,
+ .disable_irq = wl1271_sdio_disable_interrupts,
+};
+
+static void wl1271_fw_wakeup(struct wl1271 *wl)
+{
+ u32 elp_reg;
+
+ elp_reg = ELPCTRL_WAKE_UP;
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+}
+
+static int wl1271_fetch_firmware(struct wl1271 *wl)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
+
+ if (ret < 0) {
+ wl1271_error("could not get firmware: %d", ret);
+ return ret;
+ }
+
+ if (fw->size % 4) {
+ wl1271_error("firmware size is not multiple of 32 bits: %zu",
+ fw->size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ wl->fw_len = fw->size;
+ wl->fw = vmalloc(wl->fw_len);
+
+ if (!wl->fw) {
+ wl1271_error("could not allocate memory for the firmware");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(wl->fw, fw->data, wl->fw_len);
+
+ ret = 0;
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int wl1271_fetch_nvs(struct wl1271 *wl)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
+
+ if (ret < 0) {
+ wl1271_error("could not get nvs file: %d", ret);
+ return ret;
+ }
+
+ wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+
+ if (!wl->nvs) {
+ wl1271_error("could not allocate memory for the nvs file");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl->nvs_len = fw->size;
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int wl1271_chip_wakeup(struct wl1271 *wl)
+{
+ struct wl1271_partition_set partition;
+ int ret;
+
+ msleep(WL1271_PRE_POWER_ON_SLEEP);
+ ret = wl1271_power_on(wl);
+ if (ret)
+ return ret;
+
+ msleep(WL1271_POWER_ON_SLEEP);
+
+ /* We don't need a real memory partition here, because we only want
+ * to use the registers at this point. */
+ memset(&partition, 0, sizeof(partition));
+ partition.reg.start = REGISTERS_BASE;
+ partition.reg.size = REGISTERS_DOWN_SIZE;
+ wl1271_set_partition(wl, &partition);
+
+ /* ELP module wake up */
+ wl1271_fw_wakeup(wl);
+
+ /* whal_FwCtrl_BootSm() */
+
+ /* 0. read chip id from CHIP_ID */
+ wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+
+ /* 1. check if chip id is valid */
+
+ switch (wl->chip.id) {
+ case CHIP_ID_1271_PG10:
+ wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
+ wl->chip.id);
+ break;
+ case CHIP_ID_1271_PG20:
+ wl1271_notice("chip id 0x%x (1271 PG20)",
+ wl->chip.id);
+ break;
+ default:
+ wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static struct wl1271_partition_set part_down = {
+ .mem = {
+ .start = 0x00000000,
+ .size = 0x000177c0
+ },
+ .reg = {
+ .start = REGISTERS_BASE,
+ .size = 0x00008800
+ },
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+};
+
+static int tester(void *data)
+{
+ struct wl1271 *wl = data;
+ struct sdio_func *func = wl_to_func(wl);
+ struct device *pdev = &func->dev;
+ int ret = 0;
+ bool rx_started = 0;
+ bool tx_started = 0;
+ uint8_t *tx_buf, *rx_buf;
+ int test_size = PAGE_SIZE;
+ u32 addr = 0;
+ struct wl1271_partition_set partition;
+
+ /* We assume chip is powered up and firmware fetched */
+
+ memcpy(&partition, &part_down, sizeof(partition));
+ partition.mem.start = addr;
+ wl1271_set_partition(wl, &partition);
+
+ tx_buf = kmalloc(test_size, GFP_KERNEL);
+ rx_buf = kmalloc(test_size, GFP_KERNEL);
+ if (!tx_buf || !rx_buf) {
+ dev_err(pdev,
+ "Could not allocate memory. Test will not run.\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ memset(tx_buf, 0x5a, test_size);
+
+ /* write something in data area so we can read it back */
+ wl1271_write(wl, addr, tx_buf, test_size, false);
+
+ while (!kthread_should_stop()) {
+ if (rx && !rx_started) {
+ dev_info(pdev, "starting rx test\n");
+ rx_started = 1;
+ } else if (!rx && rx_started) {
+ dev_info(pdev, "stopping rx test\n");
+ rx_started = 0;
+ }
+
+ if (tx && !tx_started) {
+ dev_info(pdev, "starting tx test\n");
+ tx_started = 1;
+ } else if (!tx && tx_started) {
+ dev_info(pdev, "stopping tx test\n");
+ tx_started = 0;
+ }
+
+ if (rx_started)
+ wl1271_read(wl, addr, rx_buf, test_size, false);
+
+ if (tx_started)
+ wl1271_write(wl, addr, tx_buf, test_size, false);
+
+ if (!rx_started && !tx_started)
+ msleep(100);
+ }
+
+free:
+ kfree(tx_buf);
+ kfree(rx_buf);
+ return ret;
+}
+
+static int __devinit wl1271_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ const struct wl12xx_platform_data *wlan_data;
+ struct wl1271 *wl;
+ struct wl1271_test *wl_test;
+ int ret = 0;
+
+ /* wl1271 has 2 sdio functions we handle just the wlan part */
+ if (func->num != 0x02)
+ return -ENODEV;
+
+ wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL);
+ if (!wl_test) {
+ dev_err(&func->dev, "Could not allocate memory\n");
+ return -ENOMEM;
+ }
+
+ wl = &wl_test->wl;
+
+ wl->if_priv = func;
+ wl->if_ops = &sdio_ops;
+
+ /* Grab access to FN0 for ELP reg. */
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+
+ wlan_data = wl12xx_get_platform_data();
+ if (IS_ERR(wlan_data)) {
+ ret = PTR_ERR(wlan_data);
+ dev_err(&func->dev, "missing wlan platform data: %d\n", ret);
+ goto out_free;
+ }
+
+ wl->irq = wlan_data->irq;
+ wl->ref_clock = wlan_data->board_ref_clock;
+
+ sdio_set_drvdata(func, wl_test);
+
+
+ /* power up the device */
+ ret = wl1271_chip_wakeup(wl);
+ if (ret) {
+ dev_err(&func->dev, "could not wake up chip\n");
+ goto out_free;
+ }
+
+ if (wl->fw == NULL) {
+ ret = wl1271_fetch_firmware(wl);
+ if (ret < 0) {
+ dev_err(&func->dev, "firmware fetch error\n");
+ goto out_off;
+ }
+ }
+
+ /* fetch NVS */
+ if (wl->nvs == NULL) {
+ ret = wl1271_fetch_nvs(wl);
+ if (ret < 0) {
+ dev_err(&func->dev, "NVS fetch error\n");
+ goto out_off;
+ }
+ }
+
+ ret = wl1271_load_firmware(wl);
+ if (ret < 0) {
+ dev_err(&func->dev, "firmware load error: %d\n", ret);
+ goto out_free;
+ }
+
+ dev_info(&func->dev, "initialized\n");
+
+ /* I/O testing will be done in the tester thread */
+
+ wl_test->test_task = kthread_run(tester, wl, "sdio_tester");
+ if (IS_ERR(wl_test->test_task)) {
+ dev_err(&func->dev, "unable to create kernel thread\n");
+ ret = PTR_ERR(wl_test->test_task);
+ goto out_free;
+ }
+
+ return 0;
+
+out_off:
+ /* power off the chip */
+ wl1271_power_off(wl);
+
+out_free:
+ kfree(wl_test);
+ return ret;
+}
+
+static void __devexit wl1271_remove(struct sdio_func *func)
+{
+ struct wl1271_test *wl_test = sdio_get_drvdata(func);
+
+ /* stop the I/O test thread */
+ kthread_stop(wl_test->test_task);
+
+ /* power off the chip */
+ wl1271_power_off(&wl_test->wl);
+
+ vfree(wl_test->wl.fw);
+ wl_test->wl.fw = NULL;
+ kfree(wl_test->wl.nvs);
+ wl_test->wl.nvs = NULL;
+
+ kfree(wl_test);
+}
+
+static struct sdio_driver wl1271_sdio_driver = {
+ .name = "wl12xx_sdio_test",
+ .id_table = wl1271_devices,
+ .probe = wl1271_probe,
+ .remove = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+ int ret;
+
+ ret = sdio_register_driver(&wl1271_sdio_driver);
+ if (ret < 0)
+ pr_err("failed to register sdio driver: %d\n", ret);
+
+ return ret;
+}
+module_init(wl1271_init);
+
+static void __exit wl1271_exit(void)
+{
+ sdio_unregister_driver(&wl1271_sdio_driver);
+}
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>");
+
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/spi.c
index ef801680773f..46714910f98c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -28,11 +28,11 @@
#include <linux/wl12xx.h>
#include <linux/slab.h>
-#include "wl1271.h"
+#include "wl12xx.h"
#include "wl12xx_80211.h"
-#include "wl1271_io.h"
+#include "io.h"
-#include "wl1271_reg.h"
+#include "reg.h"
#define WSPI_CMD_READ 0x40000000
#define WSPI_CMD_WRITE 0x00000000
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index a3aa84386c88..e64403b6896d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -20,13 +20,13 @@
* 02110-1301 USA
*
*/
-#include "wl1271_testmode.h"
+#include "testmode.h"
#include <linux/slab.h>
#include <net/genetlink.h>
-#include "wl1271.h"
-#include "wl1271_acx.h"
+#include "wl12xx.h"
+#include "acx.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024
@@ -37,6 +37,7 @@ enum wl1271_tm_commands {
WL1271_TM_CMD_CONFIGURE,
WL1271_TM_CMD_NVS_PUSH,
WL1271_TM_CMD_SET_PLT_MODE,
+ WL1271_TM_CMD_RECOVER,
__WL1271_TM_CMD_AFTER_LAST
};
@@ -248,6 +249,15 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
return ret;
}
+static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
+{
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
+
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+
+ return 0;
+}
+
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{
struct wl1271 *wl = hw->priv;
@@ -272,6 +282,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
return wl1271_tm_cmd_nvs_push(wl, tb);
case WL1271_TM_CMD_SET_PLT_MODE:
return wl1271_tm_cmd_set_plt_mode(wl, tb);
+ case WL1271_TM_CMD_RECOVER:
+ return wl1271_tm_cmd_recover(wl, tb);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.h b/drivers/net/wireless/wl12xx/testmode.h
index c196d28f9d9d..8071654259ea 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.h
+++ b/drivers/net/wireless/wl12xx/testmode.h
@@ -21,8 +21,8 @@
*
*/
-#ifndef __WL1271_TESTMODE_H__
-#define __WL1271_TESTMODE_H__
+#ifndef __TESTMODE_H__
+#define __TESTMODE_H__
#include <net/mac80211.h>
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/tx.c
index e3dc13c4d01a..b44c75cd8c1e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -24,23 +24,32 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl1271.h"
-#include "wl1271_io.h"
-#include "wl1271_reg.h"
-#include "wl1271_ps.h"
-#include "wl1271_tx.h"
+#include "wl12xx.h"
+#include "io.h"
+#include "reg.h"
+#include "ps.h"
+#include "tx.h"
-static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
+static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{
- int i;
- for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
- if (wl->tx_frames[i] == NULL) {
- wl->tx_frames[i] = skb;
- wl->tx_frames_cnt++;
- return i;
- }
+ int id;
+
+ id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS);
+ if (id >= ACX_TX_DESCRIPTORS)
+ return -EBUSY;
- return -EBUSY;
+ __set_bit(id, wl->tx_frames_map);
+ wl->tx_frames[id] = skb;
+ wl->tx_frames_cnt++;
+ return id;
+}
+
+static void wl1271_free_tx_id(struct wl1271 *wl, int id)
+{
+ if (__test_and_clear_bit(id, wl->tx_frames_map)) {
+ wl->tx_frames[id] = NULL;
+ wl->tx_frames_cnt--;
+ }
}
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
@@ -52,10 +61,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
int id, ret = -EBUSY;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
- return -EBUSY;
+ return -EAGAIN;
/* allocate free identifier for the packet */
- id = wl1271_tx_id(wl, skb);
+ id = wl1271_alloc_tx_id(wl, skb);
if (id < 0)
return id;
@@ -79,8 +88,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
"tx_allocate: size: %d, blocks: %d, id: %d",
total_len, total_blocks, id);
} else {
- wl->tx_frames[id] = NULL;
- wl->tx_frames_cnt--;
+ wl1271_free_tx_id(wl, id);
}
return ret;
@@ -117,7 +125,6 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* queue (we use same identifiers for tid's and ac's */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = ac;
-
desc->aid = TX_HW_DEFAULT_AID;
desc->reserved = 0;
@@ -201,42 +208,105 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
rate_set >>= 1;
}
+#ifdef CONFIG_WL12XX_HT
+ /* MCS rates indication are on bits 16 - 23 */
+ rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
+
+ for (bit = 0; bit < 8; bit++) {
+ if (rate_set & 0x1)
+ enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
+ rate_set >>= 1;
+ }
+#endif
+
return enabled_rates;
}
-void wl1271_tx_work(struct work_struct *work)
+static void handle_tx_low_watermark(struct wl1271 *wl)
+{
+ unsigned long flags;
+
+ if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
+ wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) {
+ /* firmware buffer has space, restart queues */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_wake_queues(wl->hw);
+ clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ }
+}
+
+static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
+{
+ struct sk_buff *skb = NULL;
+ unsigned long flags;
+
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
+
+out:
+ if (skb) {
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ wl->tx_queue_count--;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ }
+
+ return skb;
+}
+
+static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
+{
+ unsigned long flags;
+ int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+
+ skb_queue_head(&wl->tx_queue[q], skb);
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ wl->tx_queue_count++;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+void wl1271_tx_work_locked(struct wl1271 *wl)
{
- struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
struct sk_buff *skb;
bool woken_up = false;
u32 sta_rates = 0;
- u32 buf_offset;
+ u32 buf_offset = 0;
+ bool sent_packets = false;
int ret;
/* check if the rates supported by the AP have changed */
if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
&wl->flags))) {
unsigned long flags;
+
spin_lock_irqsave(&wl->wl_lock, flags);
sta_rates = wl->sta_rate_set;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
- mutex_lock(&wl->mutex);
-
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
/* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) {
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+ woken_up = true;
+
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
wl1271_acx_rate_policies(wl);
}
- /* Prepare the transfer buffer, by aggregating all
- * available packets */
- buf_offset = 0;
- while ((skb = skb_dequeue(&wl->tx_queue))) {
+ while ((skb = wl1271_skb_dequeue(wl))) {
if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
@@ -245,13 +315,25 @@ void wl1271_tx_work(struct work_struct *work)
}
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
- if (ret == -EBUSY) {
+ if (ret == -EAGAIN) {
+ /*
+ * Aggregation buffer is full.
+ * Flush buffer and try again.
+ */
+ wl1271_skb_queue_head(wl, skb);
+ wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
+ buf_offset, true);
+ sent_packets = true;
+ buf_offset = 0;
+ continue;
+ } else if (ret == -EBUSY) {
/*
- * Either the firmware buffer is full, or the
- * aggregation buffer is.
+ * Firmware buffer is full.
* Queue back last skb, and stop aggregating.
*/
- skb_queue_head(&wl->tx_queue, skb);
+ wl1271_skb_queue_head(wl, skb);
+ /* No work left, avoid scheduling redundant tx work */
+ set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
goto out_ack;
} else if (ret < 0) {
dev_kfree_skb(skb);
@@ -265,14 +347,25 @@ out_ack:
if (buf_offset) {
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
+ sent_packets = true;
+ }
+ if (sent_packets) {
/* interrupt the firmware with the new packets */
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+ handle_tx_low_watermark(wl);
}
out:
if (woken_up)
wl1271_ps_elp_sleep(wl);
+}
+void wl1271_tx_work(struct work_struct *work)
+{
+ struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
+
+ mutex_lock(&wl->mutex);
+ wl1271_tx_work_locked(wl);
mutex_unlock(&wl->mutex);
}
@@ -298,7 +391,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (result->status == TX_SUCCESS) {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK;
- rate = wl1271_rate_to_idx(wl, result->rate_class_index);
+ rate = wl1271_rate_to_idx(result->rate_class_index, wl->band);
retries = result->ack_failures;
} else if (result->status == TX_RETRY_EXCEEDED) {
wl->stats.excessive_retries++;
@@ -335,8 +428,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
- wl->tx_frames[result->id] = NULL;
- wl->tx_frames_cnt--;
+ wl1271_free_tx_id(wl, result->id);
}
/* Called upon reception of a TX complete interrupt */
@@ -375,19 +467,6 @@ void wl1271_tx_complete(struct wl1271 *wl)
wl->tx_results_count++;
}
-
- if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
- skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
- unsigned long flags;
-
- /* firmware buffer has space, restart queues */
- wl1271_debug(DEBUG_TX, "tx_complete: waking queues");
- spin_lock_irqsave(&wl->wl_lock, flags);
- ieee80211_wake_queues(wl->hw);
- clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
- spin_unlock_irqrestore(&wl->wl_lock, flags);
- ieee80211_queue_work(wl->hw, &wl->tx_work);
- }
}
/* caller must hold wl->mutex */
@@ -397,19 +476,27 @@ void wl1271_tx_reset(struct wl1271 *wl)
struct sk_buff *skb;
/* TX failure */
- while ((skb = skb_dequeue(&wl->tx_queue))) {
- wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
- ieee80211_tx_status(wl->hw, skb);
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
+ wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
+ ieee80211_tx_status(wl->hw, skb);
+ }
}
+ wl->tx_queue_count = 0;
+
+ /*
+ * Make sure the driver is at a consistent state, in case this
+ * function is called from a context other than interface removal.
+ */
+ handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] != NULL) {
skb = wl->tx_frames[i];
- wl->tx_frames[i] = NULL;
+ wl1271_free_tx_id(wl, i);
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
}
- wl->tx_frames_cnt = 0;
}
#define WL1271_TX_FLUSH_TIMEOUT 500000
@@ -424,8 +511,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
wl->tx_frames_cnt);
- if ((wl->tx_frames_cnt == 0) &&
- skb_queue_empty(&wl->tx_queue)) {
+ if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) {
mutex_unlock(&wl->mutex);
return;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/tx.h
index d12a129ad11c..903e5dc69b7a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL1271_TX_H__
-#define __WL1271_TX_H__
+#ifndef __TX_H__
+#define __TX_H__
#define TX_HW_BLOCK_SPARE 2
#define TX_HW_BLOCK_SIZE 252
@@ -140,10 +140,11 @@ static inline int wl1271_tx_get_queue(int queue)
}
void wl1271_tx_work(struct work_struct *work);
+void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl);
-u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
+u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c
deleted file mode 100644
index 66c2b90ddfd4..000000000000
--- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * This file is part of wl1271
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * Contact: Luciano Coelho <luciano.coelho@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include "wl1271_debugfs.h"
-
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-
-#include "wl1271.h"
-#include "wl1271_acx.h"
-#include "wl1271_ps.h"
-#include "wl1271_io.h"
-
-/* ms */
-#define WL1271_DEBUGFS_STATS_LIFETIME 1000
-
-/* debugfs macros idea from mac80211 */
-
-#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
-static ssize_t name## _read(struct file *file, char __user *userbuf, \
- size_t count, loff_t *ppos) \
-{ \
- struct wl1271 *wl = file->private_data; \
- char buf[buflen]; \
- int res; \
- \
- res = scnprintf(buf, buflen, fmt "\n", ##value); \
- return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
-} \
- \
-static const struct file_operations name## _ops = { \
- .read = name## _read, \
- .open = wl1271_open_file_generic, \
- .llseek = generic_file_llseek, \
-};
-
-#define DEBUGFS_ADD(name, parent) \
- wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \
- wl, &name## _ops); \
- if (IS_ERR(wl->debugfs.name)) { \
- ret = PTR_ERR(wl->debugfs.name); \
- wl->debugfs.name = NULL; \
- goto out; \
- }
-
-#define DEBUGFS_DEL(name) \
- do { \
- debugfs_remove(wl->debugfs.name); \
- wl->debugfs.name = NULL; \
- } while (0)
-
-#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \
-static ssize_t sub## _ ##name## _read(struct file *file, \
- char __user *userbuf, \
- size_t count, loff_t *ppos) \
-{ \
- struct wl1271 *wl = file->private_data; \
- char buf[buflen]; \
- int res; \
- \
- wl1271_debugfs_update_stats(wl); \
- \
- res = scnprintf(buf, buflen, fmt "\n", \
- wl->stats.fw_stats->sub.name); \
- return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
-} \
- \
-static const struct file_operations sub## _ ##name## _ops = { \
- .read = sub## _ ##name## _read, \
- .open = wl1271_open_file_generic, \
- .llseek = generic_file_llseek, \
-};
-
-#define DEBUGFS_FWSTATS_ADD(sub, name) \
- DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics)
-
-#define DEBUGFS_FWSTATS_DEL(sub, name) \
- DEBUGFS_DEL(sub## _ ##name)
-
-static void wl1271_debugfs_update_stats(struct wl1271 *wl)
-{
- int ret;
-
- mutex_lock(&wl->mutex);
-
- ret = wl1271_ps_elp_wakeup(wl, false);
- if (ret < 0)
- goto out;
-
- if (wl->state == WL1271_STATE_ON &&
- time_after(jiffies, wl->stats.fw_stats_update +
- msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
- wl1271_acx_statistics(wl, wl->stats.fw_stats);
- wl->stats.fw_stats_update = jiffies;
- }
-
- wl1271_ps_elp_sleep(wl);
-
-out:
- mutex_unlock(&wl->mutex);
-}
-
-static int wl1271_open_file_generic(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u");
-DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u");
-DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u");
-DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u");
-/* skipping wep.reserved */
-DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u");
-DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u");
-DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u");
-DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u");
-/* skipping cont_miss_bcns_spread for now */
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u");
-DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u");
-DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u");
-
-DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
- 20, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u");
-
-DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count);
-DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
- wl->stats.excessive_retries);
-
-static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct wl1271 *wl = file->private_data;
- u32 queue_len;
- char buf[20];
- int res;
-
- queue_len = skb_queue_len(&wl->tx_queue);
-
- res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
- return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-
-static const struct file_operations tx_queue_len_ops = {
- .read = tx_queue_len_read,
- .open = wl1271_open_file_generic,
- .llseek = default_llseek,
-};
-
-static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct wl1271 *wl = file->private_data;
- bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
-
- int res;
- char buf[10];
-
- res = scnprintf(buf, sizeof(buf), "%d\n", state);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, res);
-}
-
-static ssize_t gpio_power_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
- unsigned long value;
- int ret;
-
- mutex_lock(&wl->mutex);
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len)) {
- ret = -EFAULT;
- goto out;
- }
- buf[len] = '\0';
-
- ret = strict_strtoul(buf, 0, &value);
- if (ret < 0) {
- wl1271_warning("illegal value in gpio_power");
- goto out;
- }
-
- if (value)
- wl1271_power_on(wl);
- else
- wl1271_power_off(wl);
-
-out:
- mutex_unlock(&wl->mutex);
- return count;
-}
-
-static const struct file_operations gpio_power_ops = {
- .read = gpio_power_read,
- .write = gpio_power_write,
- .open = wl1271_open_file_generic,
- .llseek = default_llseek,
-};
-
-static void wl1271_debugfs_delete_files(struct wl1271 *wl)
-{
- DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
-
- DEBUGFS_FWSTATS_DEL(rx, out_of_mem);
- DEBUGFS_FWSTATS_DEL(rx, hdr_overflow);
- DEBUGFS_FWSTATS_DEL(rx, hw_stuck);
- DEBUGFS_FWSTATS_DEL(rx, dropped);
- DEBUGFS_FWSTATS_DEL(rx, fcs_err);
- DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig);
- DEBUGFS_FWSTATS_DEL(rx, path_reset);
- DEBUGFS_FWSTATS_DEL(rx, reset_counter);
-
- DEBUGFS_FWSTATS_DEL(dma, rx_requested);
- DEBUGFS_FWSTATS_DEL(dma, rx_errors);
- DEBUGFS_FWSTATS_DEL(dma, tx_requested);
- DEBUGFS_FWSTATS_DEL(dma, tx_errors);
-
- DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt);
- DEBUGFS_FWSTATS_DEL(isr, fiqs);
- DEBUGFS_FWSTATS_DEL(isr, rx_headers);
- DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow);
- DEBUGFS_FWSTATS_DEL(isr, rx_rdys);
- DEBUGFS_FWSTATS_DEL(isr, irqs);
- DEBUGFS_FWSTATS_DEL(isr, tx_procs);
- DEBUGFS_FWSTATS_DEL(isr, decrypt_done);
- DEBUGFS_FWSTATS_DEL(isr, dma0_done);
- DEBUGFS_FWSTATS_DEL(isr, dma1_done);
- DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete);
- DEBUGFS_FWSTATS_DEL(isr, commands);
- DEBUGFS_FWSTATS_DEL(isr, rx_procs);
- DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes);
- DEBUGFS_FWSTATS_DEL(isr, host_acknowledges);
- DEBUGFS_FWSTATS_DEL(isr, pci_pm);
- DEBUGFS_FWSTATS_DEL(isr, wakeups);
- DEBUGFS_FWSTATS_DEL(isr, low_rssi);
-
- DEBUGFS_FWSTATS_DEL(wep, addr_key_count);
- DEBUGFS_FWSTATS_DEL(wep, default_key_count);
- /* skipping wep.reserved */
- DEBUGFS_FWSTATS_DEL(wep, key_not_found);
- DEBUGFS_FWSTATS_DEL(wep, decrypt_fail);
- DEBUGFS_FWSTATS_DEL(wep, packets);
- DEBUGFS_FWSTATS_DEL(wep, interrupt);
-
- DEBUGFS_FWSTATS_DEL(pwr, ps_enter);
- DEBUGFS_FWSTATS_DEL(pwr, elp_enter);
- DEBUGFS_FWSTATS_DEL(pwr, missing_bcns);
- DEBUGFS_FWSTATS_DEL(pwr, wake_on_host);
- DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp);
- DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps);
- DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps);
- DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons);
- DEBUGFS_FWSTATS_DEL(pwr, power_save_off);
- DEBUGFS_FWSTATS_DEL(pwr, enable_ps);
- DEBUGFS_FWSTATS_DEL(pwr, disable_ps);
- DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps);
- /* skipping cont_miss_bcns_spread for now */
- DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons);
-
- DEBUGFS_FWSTATS_DEL(mic, rx_pkts);
- DEBUGFS_FWSTATS_DEL(mic, calc_failure);
-
- DEBUGFS_FWSTATS_DEL(aes, encrypt_fail);
- DEBUGFS_FWSTATS_DEL(aes, decrypt_fail);
- DEBUGFS_FWSTATS_DEL(aes, encrypt_packets);
- DEBUGFS_FWSTATS_DEL(aes, decrypt_packets);
- DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt);
- DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt);
-
- DEBUGFS_FWSTATS_DEL(event, heart_beat);
- DEBUGFS_FWSTATS_DEL(event, calibration);
- DEBUGFS_FWSTATS_DEL(event, rx_mismatch);
- DEBUGFS_FWSTATS_DEL(event, rx_mem_empty);
- DEBUGFS_FWSTATS_DEL(event, rx_pool);
- DEBUGFS_FWSTATS_DEL(event, oom_late);
- DEBUGFS_FWSTATS_DEL(event, phy_transmit_error);
- DEBUGFS_FWSTATS_DEL(event, tx_stuck);
-
- DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts);
- DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts);
- DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime);
- DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn);
- DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn);
- DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization);
- DEBUGFS_FWSTATS_DEL(ps, upsd_utilization);
-
- DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop);
- DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
-
- DEBUGFS_DEL(tx_queue_len);
- DEBUGFS_DEL(retry_count);
- DEBUGFS_DEL(excessive_retries);
-
- DEBUGFS_DEL(gpio_power);
-}
-
-static int wl1271_debugfs_add_files(struct wl1271 *wl)
-{
- int ret = 0;
-
- DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
-
- DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
- DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
- DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
- DEBUGFS_FWSTATS_ADD(rx, dropped);
- DEBUGFS_FWSTATS_ADD(rx, fcs_err);
- DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
- DEBUGFS_FWSTATS_ADD(rx, path_reset);
- DEBUGFS_FWSTATS_ADD(rx, reset_counter);
-
- DEBUGFS_FWSTATS_ADD(dma, rx_requested);
- DEBUGFS_FWSTATS_ADD(dma, rx_errors);
- DEBUGFS_FWSTATS_ADD(dma, tx_requested);
- DEBUGFS_FWSTATS_ADD(dma, tx_errors);
-
- DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
- DEBUGFS_FWSTATS_ADD(isr, fiqs);
- DEBUGFS_FWSTATS_ADD(isr, rx_headers);
- DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
- DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
- DEBUGFS_FWSTATS_ADD(isr, irqs);
- DEBUGFS_FWSTATS_ADD(isr, tx_procs);
- DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
- DEBUGFS_FWSTATS_ADD(isr, dma0_done);
- DEBUGFS_FWSTATS_ADD(isr, dma1_done);
- DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
- DEBUGFS_FWSTATS_ADD(isr, commands);
- DEBUGFS_FWSTATS_ADD(isr, rx_procs);
- DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
- DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
- DEBUGFS_FWSTATS_ADD(isr, pci_pm);
- DEBUGFS_FWSTATS_ADD(isr, wakeups);
- DEBUGFS_FWSTATS_ADD(isr, low_rssi);
-
- DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
- DEBUGFS_FWSTATS_ADD(wep, default_key_count);
- /* skipping wep.reserved */
- DEBUGFS_FWSTATS_ADD(wep, key_not_found);
- DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
- DEBUGFS_FWSTATS_ADD(wep, packets);
- DEBUGFS_FWSTATS_ADD(wep, interrupt);
-
- DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
- DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
- DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
- DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
- DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
- DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
- DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
- DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
- DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
- DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
- DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
- DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
- /* skipping cont_miss_bcns_spread for now */
- DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
-
- DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
- DEBUGFS_FWSTATS_ADD(mic, calc_failure);
-
- DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
- DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
- DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
- DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
- DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
- DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
-
- DEBUGFS_FWSTATS_ADD(event, heart_beat);
- DEBUGFS_FWSTATS_ADD(event, calibration);
- DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
- DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
- DEBUGFS_FWSTATS_ADD(event, rx_pool);
- DEBUGFS_FWSTATS_ADD(event, oom_late);
- DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
- DEBUGFS_FWSTATS_ADD(event, tx_stuck);
-
- DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
- DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
- DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
- DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
- DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
- DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
- DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
-
- DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
- DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
- DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
-
- DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
- DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
- DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
-
- DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir);
-
-out:
- if (ret < 0)
- wl1271_debugfs_delete_files(wl);
-
- return ret;
-}
-
-void wl1271_debugfs_reset(struct wl1271 *wl)
-{
- memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
- wl->stats.retry_count = 0;
- wl->stats.excessive_retries = 0;
-}
-
-int wl1271_debugfs_init(struct wl1271 *wl)
-{
- int ret;
-
- wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-
- if (IS_ERR(wl->debugfs.rootdir)) {
- ret = PTR_ERR(wl->debugfs.rootdir);
- wl->debugfs.rootdir = NULL;
- goto err;
- }
-
- wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics",
- wl->debugfs.rootdir);
-
- if (IS_ERR(wl->debugfs.fw_statistics)) {
- ret = PTR_ERR(wl->debugfs.fw_statistics);
- wl->debugfs.fw_statistics = NULL;
- goto err_root;
- }
-
- wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
- GFP_KERNEL);
-
- if (!wl->stats.fw_stats) {
- ret = -ENOMEM;
- goto err_fw;
- }
-
- wl->stats.fw_stats_update = jiffies;
-
- ret = wl1271_debugfs_add_files(wl);
-
- if (ret < 0)
- goto err_file;
-
- return 0;
-
-err_file:
- kfree(wl->stats.fw_stats);
- wl->stats.fw_stats = NULL;
-
-err_fw:
- debugfs_remove(wl->debugfs.fw_statistics);
- wl->debugfs.fw_statistics = NULL;
-
-err_root:
- debugfs_remove(wl->debugfs.rootdir);
- wl->debugfs.rootdir = NULL;
-
-err:
- return ret;
-}
-
-void wl1271_debugfs_exit(struct wl1271 *wl)
-{
- wl1271_debugfs_delete_files(wl);
-
- kfree(wl->stats.fw_stats);
- wl->stats.fw_stats = NULL;
-
- debugfs_remove(wl->debugfs.fw_statistics);
- wl->debugfs.fw_statistics = NULL;
-
- debugfs_remove(wl->debugfs.rootdir);
- wl->debugfs.rootdir = NULL;
-
-}
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 8a4cd763e5a2..9050dd9b62d2 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL1271_H__
-#define __WL1271_H__
+#ifndef __WL12XX_H__
+#define __WL12XX_H__
#include <linux/mutex.h>
#include <linux/completion.h>
@@ -32,8 +32,8 @@
#include <linux/bitops.h>
#include <net/mac80211.h>
-#include "wl1271_conf.h"
-#include "wl1271_ini.h"
+#include "conf.h"
+#include "ini.h"
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -60,31 +60,32 @@ enum {
DEBUG_ALL = ~0,
};
-#define DEBUG_LEVEL (DEBUG_NONE)
+extern u32 wl12xx_debug_level;
#define DEBUG_DUMP_LIMIT 1024
#define wl1271_error(fmt, arg...) \
- printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+ pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
#define wl1271_warning(fmt, arg...) \
- printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+ pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
#define wl1271_notice(fmt, arg...) \
- printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+ pr_info(DRIVER_PREFIX fmt "\n", ##arg)
#define wl1271_info(fmt, arg...) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+ pr_info(DRIVER_PREFIX fmt "\n", ##arg)
#define wl1271_debug(level, fmt, arg...) \
do { \
- if (level & DEBUG_LEVEL) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ if (level & wl12xx_debug_level) \
+ pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
} while (0)
+/* TODO: use pr_debug_hex_dump when it will be available */
#define wl1271_dump(level, prefix, buf, len) \
do { \
- if (level & DEBUG_LEVEL) \
+ if (level & wl12xx_debug_level) \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
DUMP_PREFIX_OFFSET, 16, 1, \
buf, \
@@ -94,7 +95,7 @@ enum {
#define wl1271_dump_ascii(level, prefix, buf, len) \
do { \
- if (level & DEBUG_LEVEL) \
+ if (level & wl12xx_debug_level) \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
DUMP_PREFIX_OFFSET, 16, 1, \
buf, \
@@ -174,108 +175,6 @@ struct wl1271_stats {
unsigned int excessive_retries;
};
-struct wl1271_debugfs {
- struct dentry *rootdir;
- struct dentry *fw_statistics;
-
- struct dentry *tx_internal_desc_overflow;
-
- struct dentry *rx_out_of_mem;
- struct dentry *rx_hdr_overflow;
- struct dentry *rx_hw_stuck;
- struct dentry *rx_dropped;
- struct dentry *rx_fcs_err;
- struct dentry *rx_xfr_hint_trig;
- struct dentry *rx_path_reset;
- struct dentry *rx_reset_counter;
-
- struct dentry *dma_rx_requested;
- struct dentry *dma_rx_errors;
- struct dentry *dma_tx_requested;
- struct dentry *dma_tx_errors;
-
- struct dentry *isr_cmd_cmplt;
- struct dentry *isr_fiqs;
- struct dentry *isr_rx_headers;
- struct dentry *isr_rx_mem_overflow;
- struct dentry *isr_rx_rdys;
- struct dentry *isr_irqs;
- struct dentry *isr_tx_procs;
- struct dentry *isr_decrypt_done;
- struct dentry *isr_dma0_done;
- struct dentry *isr_dma1_done;
- struct dentry *isr_tx_exch_complete;
- struct dentry *isr_commands;
- struct dentry *isr_rx_procs;
- struct dentry *isr_hw_pm_mode_changes;
- struct dentry *isr_host_acknowledges;
- struct dentry *isr_pci_pm;
- struct dentry *isr_wakeups;
- struct dentry *isr_low_rssi;
-
- struct dentry *wep_addr_key_count;
- struct dentry *wep_default_key_count;
- /* skipping wep.reserved */
- struct dentry *wep_key_not_found;
- struct dentry *wep_decrypt_fail;
- struct dentry *wep_packets;
- struct dentry *wep_interrupt;
-
- struct dentry *pwr_ps_enter;
- struct dentry *pwr_elp_enter;
- struct dentry *pwr_missing_bcns;
- struct dentry *pwr_wake_on_host;
- struct dentry *pwr_wake_on_timer_exp;
- struct dentry *pwr_tx_with_ps;
- struct dentry *pwr_tx_without_ps;
- struct dentry *pwr_rcvd_beacons;
- struct dentry *pwr_power_save_off;
- struct dentry *pwr_enable_ps;
- struct dentry *pwr_disable_ps;
- struct dentry *pwr_fix_tsf_ps;
- /* skipping cont_miss_bcns_spread for now */
- struct dentry *pwr_rcvd_awake_beacons;
-
- struct dentry *mic_rx_pkts;
- struct dentry *mic_calc_failure;
-
- struct dentry *aes_encrypt_fail;
- struct dentry *aes_decrypt_fail;
- struct dentry *aes_encrypt_packets;
- struct dentry *aes_decrypt_packets;
- struct dentry *aes_encrypt_interrupt;
- struct dentry *aes_decrypt_interrupt;
-
- struct dentry *event_heart_beat;
- struct dentry *event_calibration;
- struct dentry *event_rx_mismatch;
- struct dentry *event_rx_mem_empty;
- struct dentry *event_rx_pool;
- struct dentry *event_oom_late;
- struct dentry *event_phy_transmit_error;
- struct dentry *event_tx_stuck;
-
- struct dentry *ps_pspoll_timeouts;
- struct dentry *ps_upsd_timeouts;
- struct dentry *ps_upsd_max_sptime;
- struct dentry *ps_upsd_max_apturn;
- struct dentry *ps_pspoll_max_apturn;
- struct dentry *ps_pspoll_utilization;
- struct dentry *ps_upsd_utilization;
-
- struct dentry *rxpipe_rx_prep_beacon_drop;
- struct dentry *rxpipe_descr_host_int_trig_rx_data;
- struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
- struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
- struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
-
- struct dentry *tx_queue_len;
-
- struct dentry *retry_count;
- struct dentry *excessive_retries;
- struct dentry *gpio_power;
-};
-
#define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8
@@ -351,6 +250,7 @@ struct wl1271 {
#define WL1271_FLAG_IDLE_REQUESTED (11)
#define WL1271_FLAG_PSPOLL_FAILURE (12)
#define WL1271_FLAG_STA_STATE_SENT (13)
+#define WL1271_FLAG_FW_TX_BUSY (14)
unsigned long flags;
struct wl1271_partition_set part;
@@ -392,11 +292,13 @@ struct wl1271 {
int session_counter;
/* Frames scheduled for transmission, not handled yet */
- struct sk_buff_head tx_queue;
+ struct sk_buff_head tx_queue[NUM_TX_QUEUES];
+ int tx_queue_count;
struct work_struct tx_work;
/* Pending TX frames */
+ unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
int tx_frames_cnt;
@@ -429,10 +331,18 @@ struct wl1271 {
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
+ /* probe-req template for the current AP */
+ struct sk_buff *probereq;
+
/* Our association ID */
u16 aid;
- /* currently configured rate set */
+ /*
+ * currently configured rate set:
+ * bits 0-15 - 802.11abg rates
+ * bits 16-23 - 802.11n MCS index mask
+ * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
+ */
u32 sta_rate_set;
u32 basic_rate_set;
u32 basic_rate;
@@ -468,7 +378,7 @@ struct wl1271 {
int last_rssi_event;
struct wl1271_stats stats;
- struct wl1271_debugfs debugfs;
+ struct dentry *rootdir;
__le32 buffer_32;
u32 buffer_cmd;
@@ -506,7 +416,11 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
on in case is has been shut down shortly before */
-#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
-#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */
+#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */
+
+/* Macros to handle wl1271.sta_rate_set */
+#define HW_BG_RATES_MASK 0xffff
+#define HW_HT_RATES_OFFSET 16
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 184628027213..be21032f4dc1 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -2,6 +2,7 @@
#define __WL12XX_80211_H__
#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/if_arp.h>
/* RATES */
#define IEEE80211_CCK_RATE_1MB 0x02
@@ -133,11 +134,17 @@ struct wl12xx_qos_null_data_template {
__le16 qos_ctl;
} __packed;
-struct wl12xx_probe_req_template {
- struct ieee80211_header header;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
+struct wl12xx_arp_rsp_template {
+ struct ieee80211_hdr_3addr hdr;
+
+ u8 llc_hdr[sizeof(rfc1042_header)];
+ u16 llc_type;
+
+ struct arphdr arp_hdr;
+ u8 sender_hw[ETH_ALEN];
+ u32 sender_ip;
+ u8 target_hw[ETH_ALEN];
+ u32 target_ip;
} __packed;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index ee82df62e646..3e5befe4d03b 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -192,7 +192,7 @@ static inline void wl3501_switch_page(struct wl3501_card *this, u8 page)
}
/*
- * Get Ethernet MAC addresss.
+ * Get Ethernet MAC address.
*
* WARNING: We switch to FPAGE0 and switc back again.
* Making sure there is no other WL function beening called by ISR.
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 390d77f762c4..415eec401e2e 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -30,6 +30,7 @@ static struct usb_device_id zd1201_table[] = {
{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */
{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */
+ {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
{USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */
{}
};
@@ -1829,7 +1830,7 @@ err_zd:
static void zd1201_disconnect(struct usb_interface *interface)
{
- struct zd1201 *zd=(struct zd1201 *)usb_get_intfdata(interface);
+ struct zd1201 *zd = usb_get_intfdata(interface);
struct hlist_node *node, *node2;
struct zd1201_frag *frag;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 87a95bcfee57..6a9b66051cf7 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -117,6 +117,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
+ /* zd_addr_t is __nocast, so the kmalloc needs an explicit cast */
a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
GFP_KERNEL);
if (!a16) {
@@ -1448,7 +1449,7 @@ int zd_rfwritev_locked(struct zd_chip *chip,
*/
int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
{
- struct zd_ioreq16 ioreqs[] = {
+ const struct zd_ioreq16 ioreqs[] = {
{ CR244, (value >> 16) & 0xff },
{ CR243, (value >> 8) & 0xff },
{ CR242, value & 0xff },
@@ -1475,7 +1476,7 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip,
int zd_chip_set_multicast_hash(struct zd_chip *chip,
struct zd_mc_hash *hash)
{
- struct zd_ioreq32 ioreqs[] = {
+ const struct zd_ioreq32 ioreqs[] = {
{ CR_GROUP_HASH_P1, hash->low },
{ CR_GROUP_HASH_P2, hash->high },
};
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 43307bd42a69..6107304cb94c 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1207,7 +1207,6 @@ static void housekeeping_enable(struct zd_mac *mac)
static void housekeeping_disable(struct zd_mac *mac)
{
dev_dbg_f(zd_mac_dev(mac), "\n");
- cancel_rearming_delayed_workqueue(zd_workqueue,
- &mac->housekeeping.link_led_work);
+ cancel_delayed_work_sync(&mac->housekeeping.link_led_work);
zd_chip_control_leds(&mac->chip, ZD_LED_OFF);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 818e1480ca93..06041cb1c422 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -55,6 +55,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x14ea, 0xab10), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
@@ -92,6 +93,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0xed01), .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/xen-netfront.c b/drivers/net/xen-netfront.c
index 458bb57914a3..546de5749824 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -66,8 +66,8 @@ struct netfront_cb {
#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 NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
+#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
struct netfront_info {
@@ -488,7 +488,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!netif_carrier_ok(dev) ||
(frags > 1 && !xennet_can_sg(dev)) ||
- netif_needs_gso(dev, skb))) {
+ netif_needs_gso(skb, netif_skb_features(skb)))) {
spin_unlock_irq(&np->tx_lock);
goto drop;
}
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 14f0955eca68..cad66ce1640b 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -24,6 +24,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_mdio.h>
+#include <linux/of_net.h>
#include <linux/phy.h>
#define DRIVER_NAME "xilinx_emaclite"
@@ -515,7 +516,7 @@ static void xemaclite_update_address(struct net_local *drvdata,
*/
static int xemaclite_set_mac_address(struct net_device *dev, void *address)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
struct sockaddr *addr = address;
if (netif_running(dev))
@@ -534,7 +535,7 @@ static int xemaclite_set_mac_address(struct net_device *dev, void *address)
*/
static void xemaclite_tx_timeout(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
unsigned long flags;
dev_err(&lp->ndev->dev, "Exceeded transmit timeout of %lu ms\n",
@@ -578,7 +579,7 @@ static void xemaclite_tx_timeout(struct net_device *dev)
*/
static void xemaclite_tx_handler(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
dev->stats.tx_packets++;
if (lp->deferred_skb) {
@@ -605,7 +606,7 @@ static void xemaclite_tx_handler(struct net_device *dev)
*/
static void xemaclite_rx_handler(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
struct sk_buff *skb;
unsigned int align;
u32 len;
@@ -661,7 +662,7 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
{
bool tx_complete = 0;
struct net_device *dev = dev_id;
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
void __iomem *base_addr = lp->base_addr;
u32 tx_status;
@@ -918,7 +919,7 @@ void xemaclite_adjust_link(struct net_device *ndev)
*/
static int xemaclite_open(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
int retval;
/* Just to be safe, stop the device first */
@@ -987,7 +988,7 @@ static int xemaclite_open(struct net_device *dev)
*/
static int xemaclite_close(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
netif_stop_queue(dev);
xemaclite_disable_interrupts(lp);
@@ -1001,21 +1002,6 @@ static int xemaclite_close(struct net_device *dev)
}
/**
- * xemaclite_get_stats - Get the stats for the net_device
- * @dev: Pointer to the network device
- *
- * This function returns the address of the 'net_device_stats' structure for the
- * given network device. This structure holds usage statistics for the network
- * device.
- *
- * Return: Pointer to the net_device_stats structure.
- */
-static struct net_device_stats *xemaclite_get_stats(struct net_device *dev)
-{
- return &dev->stats;
-}
-
-/**
* xemaclite_send - Transmit a frame
* @orig_skb: Pointer to the socket buffer to be transmitted
* @dev: Pointer to the network device
@@ -1031,7 +1017,7 @@ static struct net_device_stats *xemaclite_get_stats(struct net_device *dev)
*/
static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct net_local *lp = netdev_priv(dev);
struct sk_buff *new_skb;
unsigned int len;
unsigned long flags;
@@ -1068,7 +1054,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
static void xemaclite_remove_ndev(struct net_device *ndev)
{
if (ndev) {
- struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+ struct net_local *lp = netdev_priv(ndev);
if (lp->base_addr)
iounmap((void __iomem __force *) (lp->base_addr));
@@ -1245,7 +1231,7 @@ static int __devexit xemaclite_of_remove(struct platform_device *of_dev)
struct device *dev = &of_dev->dev;
struct net_device *ndev = dev_get_drvdata(dev);
- struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+ struct net_local *lp = netdev_priv(ndev);
/* Un-register the mii_bus, if configured */
if (lp->has_mdio) {
@@ -1285,7 +1271,6 @@ static struct net_device_ops xemaclite_netdev_ops = {
.ndo_start_xmit = xemaclite_send,
.ndo_set_mac_address = xemaclite_set_mac_address,
.ndo_tx_timeout = xemaclite_tx_timeout,
- .ndo_get_stats = xemaclite_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = xemaclite_poll_controller,
#endif
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index cd1b3dcd61db..ec47e22fa186 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -744,7 +744,7 @@ static int yellowfin_init_ring(struct net_device *dev)
}
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2);
yp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
@@ -1157,7 +1157,7 @@ static int yellowfin_rx(struct net_device *dev)
for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
entry = yp->dirty_rx % RX_RING_SIZE;
if (yp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2);
if (skb == NULL)
break; /* Better luck next round. */
yp->rx_skbuff[entry] = skb;
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index c3a329204511..ae07b3dfbcc1 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -124,7 +124,7 @@ MODULE_LICENSE("GPL");
#define TX_BUF_SIZE 8192
#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */
-#define TX_TIMEOUT 10
+#define TX_TIMEOUT (HZ/10)
struct znet_private {
int rx_dma, tx_dma;
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
new file mode 100644
index 000000000000..ffedfd492754
--- /dev/null
+++ b/drivers/nfc/Kconfig
@@ -0,0 +1,30 @@
+#
+# Near Field Communication (NFC) devices
+#
+
+menuconfig NFC_DEVICES
+ bool "NFC devices"
+ default n
+ ---help---
+ You'll have to say Y if your computer contains an NFC device that
+ you want to use under Linux.
+
+ You can say N here if you don't have any Near Field Communication
+ devices connected to your computer.
+
+if NFC_DEVICES
+
+config PN544_NFC
+ tristate "PN544 NFC driver"
+ depends on I2C
+ select CRC_CCITT
+ default n
+ ---help---
+ Say yes if you want PN544 Near Field Communication driver.
+ This is for i2c connected version. If unsure, say N here.
+
+ To compile this driver as a module, choose m here. The module will
+ be called pn544.
+
+
+endif # NFC_DEVICES
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
new file mode 100644
index 000000000000..a4efb164ec49
--- /dev/null
+++ b/drivers/nfc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for nfc devices
+#
+
+obj-$(CONFIG_PN544_NFC) += pn544.o
diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c
new file mode 100644
index 000000000000..bae647264dd6
--- /dev/null
+++ b/drivers/nfc/pn544.c
@@ -0,0 +1,891 @@
+/*
+ * Driver for the PN544 NFC chip.
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Jari Vanhala <ext-jari.vanhala@nokia.com>
+ * Contact: Matti Aaltonen <matti.j.aaltonen@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/completion.h>
+#include <linux/crc-ccitt.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nfc/pn544.h>
+#include <linux/poll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serial_core.h> /* for TCGETS */
+#include <linux/slab.h>
+
+#define DRIVER_CARD "PN544 NFC"
+#define DRIVER_DESC "NFC driver for PN544"
+
+static struct i2c_device_id pn544_id_table[] = {
+ { PN544_DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pn544_id_table);
+
+#define HCI_MODE 0
+#define FW_MODE 1
+
+enum pn544_state {
+ PN544_ST_COLD,
+ PN544_ST_FW_READY,
+ PN544_ST_READY,
+};
+
+enum pn544_irq {
+ PN544_NONE,
+ PN544_INT,
+};
+
+struct pn544_info {
+ struct miscdevice miscdev;
+ struct i2c_client *i2c_dev;
+ struct regulator_bulk_data regs[2];
+
+ enum pn544_state state;
+ wait_queue_head_t read_wait;
+ loff_t read_offset;
+ enum pn544_irq read_irq;
+ struct mutex read_mutex; /* Serialize read_irq access */
+ struct mutex mutex; /* Serialize info struct access */
+ u8 *buf;
+ size_t buflen;
+};
+
+static const char reg_vdd_io[] = "Vdd_IO";
+static const char reg_vbat[] = "VBat";
+
+/* sysfs interface */
+static ssize_t pn544_test(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pn544_info *info = dev_get_drvdata(dev);
+ struct i2c_client *client = info->i2c_dev;
+ struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test());
+}
+
+static int pn544_enable(struct pn544_info *info, int mode)
+{
+ struct pn544_nfc_platform_data *pdata;
+ struct i2c_client *client = info->i2c_dev;
+
+ int r;
+
+ r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs);
+ if (r < 0)
+ return r;
+
+ pdata = client->dev.platform_data;
+ info->read_irq = PN544_NONE;
+ if (pdata->enable)
+ pdata->enable(mode);
+
+ if (mode) {
+ info->state = PN544_ST_FW_READY;
+ dev_dbg(&client->dev, "now in FW-mode\n");
+ } else {
+ info->state = PN544_ST_READY;
+ dev_dbg(&client->dev, "now in HCI-mode\n");
+ }
+
+ usleep_range(10000, 15000);
+
+ return 0;
+}
+
+static void pn544_disable(struct pn544_info *info)
+{
+ struct pn544_nfc_platform_data *pdata;
+ struct i2c_client *client = info->i2c_dev;
+
+ pdata = client->dev.platform_data;
+ if (pdata->disable)
+ pdata->disable();
+
+ info->state = PN544_ST_COLD;
+
+ dev_dbg(&client->dev, "Now in OFF-mode\n");
+
+ msleep(PN544_RESETVEN_TIME);
+
+ info->read_irq = PN544_NONE;
+ regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs);
+}
+
+static int check_crc(u8 *buf, int buflen)
+{
+ u8 len;
+ u16 crc;
+
+ len = buf[0] + 1;
+ if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) {
+ pr_err(PN544_DRIVER_NAME
+ ": CRC; corrupt packet len %u (%d)\n", len, buflen);
+ print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+ 16, 2, buf, buflen, false);
+ return -EPERM;
+ }
+ crc = crc_ccitt(0xffff, buf, len - 2);
+ crc = ~crc;
+
+ if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) {
+ pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
+ crc, buf[len-1], buf[len-2]);
+
+ print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+ 16, 2, buf, buflen, false);
+ return -EPERM;
+ }
+ return 0;
+}
+
+static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+ int r;
+
+ if (len < 4 || len != (buf[0] + 1)) {
+ dev_err(&client->dev, "%s: Illegal message length: %d\n",
+ __func__, len);
+ return -EINVAL;
+ }
+
+ if (check_crc(buf, len))
+ return -EINVAL;
+
+ usleep_range(3000, 6000);
+
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "send: %d\n", r);
+
+ if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+ usleep_range(6000, 10000);
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "send2: %d\n", r);
+ }
+
+ if (r != len)
+ return -EREMOTEIO;
+
+ return r;
+}
+
+static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen)
+{
+ int r;
+ u8 len;
+
+ /*
+ * You could read a packet in one go, but then you'd need to read
+ * max size and rest would be 0xff fill, so we do split reads.
+ */
+ r = i2c_master_recv(client, &len, 1);
+ dev_dbg(&client->dev, "recv1: %d\n", r);
+
+ if (r != 1)
+ return -EREMOTEIO;
+
+ if (len < PN544_LLC_HCI_OVERHEAD)
+ len = PN544_LLC_HCI_OVERHEAD;
+ else if (len > (PN544_MSG_MAX_SIZE - 1))
+ len = PN544_MSG_MAX_SIZE - 1;
+
+ if (1 + len > buflen) /* len+(data+crc16) */
+ return -EMSGSIZE;
+
+ buf[0] = len;
+
+ r = i2c_master_recv(client, buf + 1, len);
+ dev_dbg(&client->dev, "recv2: %d\n", r);
+
+ if (r != len)
+ return -EREMOTEIO;
+
+ usleep_range(3000, 6000);
+
+ return r + 1;
+}
+
+static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len)
+{
+ int r;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ if (len < PN544_FW_HEADER_SIZE ||
+ (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len)
+ return -EINVAL;
+
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "fw send: %d\n", r);
+
+ if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+ usleep_range(6000, 10000);
+ r = i2c_master_send(client, buf, len);
+ dev_dbg(&client->dev, "fw send2: %d\n", r);
+ }
+
+ if (r != len)
+ return -EREMOTEIO;
+
+ return r;
+}
+
+static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen)
+{
+ int r, len;
+
+ if (buflen < PN544_FW_HEADER_SIZE)
+ return -EINVAL;
+
+ r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE);
+ dev_dbg(&client->dev, "FW recv1: %d\n", r);
+
+ if (r < 0)
+ return r;
+
+ if (r < PN544_FW_HEADER_SIZE)
+ return -EINVAL;
+
+ len = (buf[1] << 8) + buf[2];
+ if (len == 0) /* just header, no additional data */
+ return r;
+
+ if (len > buflen - PN544_FW_HEADER_SIZE)
+ return -EMSGSIZE;
+
+ r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len);
+ dev_dbg(&client->dev, "fw recv2: %d\n", r);
+
+ if (r != len)
+ return -EINVAL;
+
+ return r + PN544_FW_HEADER_SIZE;
+}
+
+static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id)
+{
+ struct pn544_info *info = dev_id;
+ struct i2c_client *client = info->i2c_dev;
+
+ BUG_ON(!info);
+ BUG_ON(irq != info->i2c_dev->irq);
+
+ dev_dbg(&client->dev, "IRQ\n");
+
+ mutex_lock(&info->read_mutex);
+ info->read_irq = PN544_INT;
+ mutex_unlock(&info->read_mutex);
+
+ wake_up_interruptible(&info->read_wait);
+
+ return IRQ_HANDLED;
+}
+
+static enum pn544_irq pn544_irq_state(struct pn544_info *info)
+{
+ enum pn544_irq irq;
+
+ mutex_lock(&info->read_mutex);
+ irq = info->read_irq;
+ mutex_unlock(&info->read_mutex);
+ /*
+ * XXX: should we check GPIO-line status directly?
+ * return pdata->irq_status() ? PN544_INT : PN544_NONE;
+ */
+
+ return irq;
+}
+
+static ssize_t pn544_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+ enum pn544_irq irq;
+ size_t len;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__,
+ info, count);
+
+ mutex_lock(&info->mutex);
+
+ if (info->state == PN544_ST_COLD) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ irq = pn544_irq_state(info);
+ if (irq == PN544_NONE) {
+ if (file->f_flags & O_NONBLOCK) {
+ r = -EAGAIN;
+ goto out;
+ }
+
+ if (wait_event_interruptible(info->read_wait,
+ (info->read_irq == PN544_INT))) {
+ r = -ERESTARTSYS;
+ goto out;
+ }
+ }
+
+ if (info->state == PN544_ST_FW_READY) {
+ len = min(count, info->buflen);
+
+ mutex_lock(&info->read_mutex);
+ r = pn544_fw_read(info->i2c_dev, info->buf, len);
+ info->read_irq = PN544_NONE;
+ mutex_unlock(&info->read_mutex);
+
+ if (r < 0) {
+ dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r);
+ goto out;
+ }
+
+ print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE,
+ 16, 2, info->buf, r, false);
+
+ *offset += r;
+ if (copy_to_user(buf, info->buf, r)) {
+ r = -EFAULT;
+ goto out;
+ }
+ } else {
+ len = min(count, info->buflen);
+
+ mutex_lock(&info->read_mutex);
+ r = pn544_i2c_read(info->i2c_dev, info->buf, len);
+ info->read_irq = PN544_NONE;
+ mutex_unlock(&info->read_mutex);
+
+ if (r < 0) {
+ dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r);
+ goto out;
+ }
+ print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE,
+ 16, 2, info->buf, r, false);
+
+ *offset += r;
+ if (copy_to_user(buf, info->buf, r)) {
+ r = -EFAULT;
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&info->mutex);
+
+ return r;
+}
+
+static unsigned int pn544_poll(struct file *file, poll_table *wait)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s: info: %p\n", __func__, info);
+
+ mutex_lock(&info->mutex);
+
+ if (info->state == PN544_ST_COLD) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ poll_wait(file, &info->read_wait, wait);
+
+ if (pn544_irq_state(info) == PN544_INT) {
+ r = POLLIN | POLLRDNORM;
+ goto out;
+ }
+out:
+ mutex_unlock(&info->mutex);
+
+ return r;
+}
+
+static ssize_t pn544_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+ ssize_t len;
+ int r;
+
+ dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__,
+ info, count);
+
+ mutex_lock(&info->mutex);
+
+ if (info->state == PN544_ST_COLD) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ /*
+ * XXX: should we detect rset-writes and clean possible
+ * read_irq state
+ */
+ if (info->state == PN544_ST_FW_READY) {
+ size_t fw_len;
+
+ if (count < PN544_FW_HEADER_SIZE) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ len = min(count, info->buflen);
+ if (copy_from_user(info->buf, buf, len)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE,
+ 16, 2, info->buf, len, false);
+
+ fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) +
+ info->buf[2];
+
+ if (len > fw_len) /* 1 msg at a time */
+ len = fw_len;
+
+ r = pn544_fw_write(info->i2c_dev, info->buf, len);
+ } else {
+ if (count < PN544_LLC_MIN_SIZE) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ len = min(count, info->buflen);
+ if (copy_from_user(info->buf, buf, len)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE,
+ 16, 2, info->buf, len, false);
+
+ if (len > (info->buf[0] + 1)) /* 1 msg at a time */
+ len = info->buf[0] + 1;
+
+ r = pn544_i2c_write(info->i2c_dev, info->buf, len);
+ }
+out:
+ mutex_unlock(&info->mutex);
+
+ return r;
+
+}
+
+static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+ struct pn544_nfc_platform_data *pdata;
+ unsigned int val;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd);
+
+ mutex_lock(&info->mutex);
+
+ if (info->state == PN544_ST_COLD) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ pdata = info->i2c_dev->dev.platform_data;
+ switch (cmd) {
+ case PN544_GET_FW_MODE:
+ dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__);
+
+ val = (info->state == PN544_ST_FW_READY);
+ if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ break;
+
+ case PN544_SET_FW_MODE:
+ dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__);
+
+ if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ if (val) {
+ if (info->state == PN544_ST_FW_READY)
+ break;
+
+ pn544_disable(info);
+ r = pn544_enable(info, FW_MODE);
+ if (r < 0)
+ goto out;
+ } else {
+ if (info->state == PN544_ST_READY)
+ break;
+ pn544_disable(info);
+ r = pn544_enable(info, HCI_MODE);
+ if (r < 0)
+ goto out;
+ }
+ file->f_pos = info->read_offset;
+ break;
+
+ case TCGETS:
+ dev_dbg(&client->dev, "%s: TCGETS\n", __func__);
+
+ r = -ENOIOCTLCMD;
+ break;
+
+ default:
+ dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd);
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+out:
+ mutex_unlock(&info->mutex);
+
+ return r;
+}
+
+static int pn544_open(struct inode *inode, struct file *file)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
+ info, info->i2c_dev);
+
+ mutex_lock(&info->mutex);
+
+ /*
+ * Only 1 at a time.
+ * XXX: maybe user (counter) would work better
+ */
+ if (info->state != PN544_ST_COLD) {
+ r = -EBUSY;
+ goto out;
+ }
+
+ file->f_pos = info->read_offset;
+ r = pn544_enable(info, HCI_MODE);
+
+out:
+ mutex_unlock(&info->mutex);
+ return r;
+}
+
+static int pn544_close(struct inode *inode, struct file *file)
+{
+ struct pn544_info *info = container_of(file->private_data,
+ struct pn544_info, miscdev);
+ struct i2c_client *client = info->i2c_dev;
+
+ dev_dbg(&client->dev, "%s: info: %p, client %p\n",
+ __func__, info, info->i2c_dev);
+
+ mutex_lock(&info->mutex);
+ pn544_disable(info);
+ mutex_unlock(&info->mutex);
+
+ return 0;
+}
+
+static const struct file_operations pn544_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = pn544_read,
+ .write = pn544_write,
+ .poll = pn544_poll,
+ .open = pn544_open,
+ .release = pn544_close,
+ .unlocked_ioctl = pn544_ioctl,
+};
+
+#ifdef CONFIG_PM
+static int pn544_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pn544_info *info;
+ int r = 0;
+
+ dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client);
+
+ info = i2c_get_clientdata(client);
+ dev_info(&client->dev, "%s: info: %p, client %p\n", __func__,
+ info, client);
+
+ mutex_lock(&info->mutex);
+
+ switch (info->state) {
+ case PN544_ST_FW_READY:
+ /* Do not suspend while upgrading FW, please! */
+ r = -EPERM;
+ break;
+
+ case PN544_ST_READY:
+ /*
+ * CHECK: Device should be in standby-mode. No way to check?
+ * Allowing low power mode for the regulator is potentially
+ * dangerous if pn544 does not go to suspension.
+ */
+ break;
+
+ case PN544_ST_COLD:
+ break;
+ };
+
+ mutex_unlock(&info->mutex);
+ return r;
+}
+
+static int pn544_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pn544_info *info = i2c_get_clientdata(client);
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
+ info, client);
+
+ mutex_lock(&info->mutex);
+
+ switch (info->state) {
+ case PN544_ST_READY:
+ /*
+ * CHECK: If regulator low power mode is allowed in
+ * pn544_suspend, we should go back to normal mode
+ * here.
+ */
+ break;
+
+ case PN544_ST_COLD:
+ break;
+
+ case PN544_ST_FW_READY:
+ break;
+ };
+
+ mutex_unlock(&info->mutex);
+
+ return r;
+}
+
+static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume);
+#endif
+
+static struct device_attribute pn544_attr =
+ __ATTR(nfc_test, S_IRUGO, pn544_test, NULL);
+
+static int __devinit pn544_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pn544_info *info;
+ struct pn544_nfc_platform_data *pdata;
+ int r = 0;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+ dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
+
+ /* private data allocation */
+ info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&client->dev,
+ "Cannot allocate memory for pn544_info.\n");
+ r = -ENOMEM;
+ goto err_info_alloc;
+ }
+
+ info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER);
+ info->buf = kzalloc(info->buflen, GFP_KERNEL);
+ if (!info->buf) {
+ dev_err(&client->dev,
+ "Cannot allocate memory for pn544_info->buf.\n");
+ r = -ENOMEM;
+ goto err_buf_alloc;
+ }
+
+ info->regs[0].supply = reg_vdd_io;
+ info->regs[1].supply = reg_vbat;
+ r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
+ info->regs);
+ if (r < 0)
+ goto err_kmalloc;
+
+ info->i2c_dev = client;
+ info->state = PN544_ST_COLD;
+ info->read_irq = PN544_NONE;
+ mutex_init(&info->read_mutex);
+ mutex_init(&info->mutex);
+ init_waitqueue_head(&info->read_wait);
+ i2c_set_clientdata(client, info);
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "No platform data\n");
+ r = -EINVAL;
+ goto err_reg;
+ }
+
+ if (!pdata->request_resources) {
+ dev_err(&client->dev, "request_resources() missing\n");
+ r = -EINVAL;
+ goto err_reg;
+ }
+
+ r = pdata->request_resources(client);
+ if (r) {
+ dev_err(&client->dev, "Cannot get platform resources\n");
+ goto err_reg;
+ }
+
+ r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn,
+ IRQF_TRIGGER_RISING, PN544_DRIVER_NAME,
+ info);
+ if (r < 0) {
+ dev_err(&client->dev, "Unable to register IRQ handler\n");
+ goto err_res;
+ }
+
+ /* If we don't have the test we don't need the sysfs file */
+ if (pdata->test) {
+ r = device_create_file(&client->dev, &pn544_attr);
+ if (r) {
+ dev_err(&client->dev,
+ "sysfs registration failed, error %d\n", r);
+ goto err_irq;
+ }
+ }
+
+ info->miscdev.minor = MISC_DYNAMIC_MINOR;
+ info->miscdev.name = PN544_DRIVER_NAME;
+ info->miscdev.fops = &pn544_fops;
+ info->miscdev.parent = &client->dev;
+ r = misc_register(&info->miscdev);
+ if (r < 0) {
+ dev_err(&client->dev, "Device registration failed\n");
+ goto err_sysfs;
+ }
+
+ dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n",
+ __func__, info, pdata, client);
+
+ return 0;
+
+err_sysfs:
+ if (pdata->test)
+ device_remove_file(&client->dev, &pn544_attr);
+err_irq:
+ free_irq(client->irq, info);
+err_res:
+ if (pdata->free_resources)
+ pdata->free_resources();
+err_reg:
+ regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
+err_kmalloc:
+ kfree(info->buf);
+err_buf_alloc:
+ kfree(info);
+err_info_alloc:
+ return r;
+}
+
+static __devexit int pn544_remove(struct i2c_client *client)
+{
+ struct pn544_info *info = i2c_get_clientdata(client);
+ struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ misc_deregister(&info->miscdev);
+ if (pdata->test)
+ device_remove_file(&client->dev, &pn544_attr);
+
+ if (info->state != PN544_ST_COLD) {
+ if (pdata->disable)
+ pdata->disable();
+
+ info->read_irq = PN544_NONE;
+ }
+
+ free_irq(client->irq, info);
+ if (pdata->free_resources)
+ pdata->free_resources();
+
+ regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
+ kfree(info->buf);
+ kfree(info);
+
+ return 0;
+}
+
+static struct i2c_driver pn544_driver = {
+ .driver = {
+ .name = PN544_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &pn544_pm_ops,
+#endif
+ },
+ .probe = pn544_probe,
+ .id_table = pn544_id_table,
+ .remove = __devexit_p(pn544_remove),
+};
+
+static int __init pn544_init(void)
+{
+ int r;
+
+ pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+ r = i2c_add_driver(&pn544_driver);
+ if (r) {
+ pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void __exit pn544_exit(void)
+{
+ i2c_del_driver(&pn544_driver);
+ pr_info(DRIVER_DESC ", Exiting.\n");
+}
+
+module_init(pn544_init);
+module_exit(pn544_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index aa675ebd8eb3..3c6e100a3ad0 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -19,6 +19,10 @@ config OF_FLATTREE
bool
select DTC
+config OF_EARLY_FLATTREE
+ bool
+ select OF_FLATTREE
+
config OF_PROMTREE
bool
@@ -49,6 +53,10 @@ config OF_I2C
help
OpenFirmware I2C accessors
+config OF_NET
+ depends on NETDEVICES
+ def_bool y
+
config OF_SPI
def_tristate SPI
depends on SPI && !SPARC
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 7888155bea08..3ab21a0a4907 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO) += gpio.o
obj-$(CONFIG_OF_I2C) += of_i2c.o
+obj-$(CONFIG_OF_NET) += of_net.o
obj-$(CONFIG_OF_SPI) += of_spi.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 3a1c7e70b192..b4559c58c095 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -12,13 +12,13 @@
(ns) > 0)
static struct of_bus *of_match_bus(struct device_node *np);
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
+static int __of_address_to_resource(struct device_node *dev,
+ const __be32 *addrp, u64 size, unsigned int flags,
struct resource *r);
/* Debug utility */
#ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
+static void of_dump_addr(const char *s, const __be32 *addr, int na)
{
printk(KERN_DEBUG "%s", s);
while (na--)
@@ -26,7 +26,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na)
printk("\n");
}
#else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+static void of_dump_addr(const char *s, const __be32 *addr, int na) { }
#endif
/* Callbacks for bus specific translators */
@@ -36,10 +36,10 @@ struct of_bus {
int (*match)(struct device_node *parent);
void (*count_cells)(struct device_node *child,
int *addrc, int *sizec);
- u64 (*map)(u32 *addr, const u32 *range,
+ u64 (*map)(u32 *addr, const __be32 *range,
int na, int ns, int pna);
int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(const u32 *addr);
+ unsigned int (*get_flags)(const __be32 *addr);
};
/*
@@ -55,7 +55,7 @@ static void of_bus_default_count_cells(struct device_node *dev,
*sizec = of_n_size_cells(dev);
}
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
+static u64 of_bus_default_map(u32 *addr, const __be32 *range,
int na, int ns, int pna)
{
u64 cp, s, da;
@@ -85,7 +85,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na)
return 0;
}
-static unsigned int of_bus_default_get_flags(const u32 *addr)
+static unsigned int of_bus_default_get_flags(const __be32 *addr)
{
return IORESOURCE_MEM;
}
@@ -110,10 +110,10 @@ static void of_bus_pci_count_cells(struct device_node *np,
*sizec = 2;
}
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
+static unsigned int of_bus_pci_get_flags(const __be32 *addr)
{
unsigned int flags = 0;
- u32 w = addr[0];
+ u32 w = be32_to_cpup(addr);
switch((w >> 24) & 0x03) {
case 0x01:
@@ -129,7 +129,8 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr)
return flags;
}
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+static u64 of_bus_pci_map(u32 *addr, const __be32 *range, int na, int ns,
+ int pna)
{
u64 cp, s, da;
unsigned int af, rf;
@@ -160,7 +161,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
return of_bus_default_translate(addr + 1, offset, na - 1);
}
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
const __be32 *prop;
@@ -207,7 +208,7 @@ EXPORT_SYMBOL(of_get_pci_address);
int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r)
{
- const u32 *addrp;
+ const __be32 *addrp;
u64 size;
unsigned int flags;
@@ -237,12 +238,13 @@ static void of_bus_isa_count_cells(struct device_node *child,
*sizec = 1;
}
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+static u64 of_bus_isa_map(u32 *addr, const __be32 *range, int na, int ns,
+ int pna)
{
u64 cp, s, da;
/* Check address type match */
- if ((addr[0] ^ range[0]) & 0x00000001)
+ if ((addr[0] ^ range[0]) & cpu_to_be32(1))
return OF_BAD_ADDR;
/* Read address values, skipping high cell */
@@ -264,10 +266,10 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
return of_bus_default_translate(addr + 1, offset, na - 1);
}
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
+static unsigned int of_bus_isa_get_flags(const __be32 *addr)
{
unsigned int flags = 0;
- u32 w = addr[0];
+ u32 w = be32_to_cpup(addr);
if (w & 1)
flags |= IORESOURCE_IO;
@@ -330,7 +332,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
struct of_bus *pbus, u32 *addr,
int na, int ns, int pna, const char *rprop)
{
- const u32 *ranges;
+ const __be32 *ranges;
unsigned int rlen;
int rone;
u64 offset = OF_BAD_ADDR;
@@ -398,7 +400,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* that can be mapped to a cpu physical address). This is not really specified
* that way, but this is traditionally the way IBM at least do things
*/
-u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
+u64 __of_translate_address(struct device_node *dev, const __be32 *in_addr,
const char *rprop)
{
struct device_node *parent = NULL;
@@ -475,22 +477,22 @@ u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
return result;
}
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
+u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
{
return __of_translate_address(dev, in_addr, "ranges");
}
EXPORT_SYMBOL(of_translate_address);
-u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
+u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
{
return __of_translate_address(dev, in_addr, "dma-ranges");
}
EXPORT_SYMBOL(of_translate_dma_address);
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
unsigned int *flags)
{
- const u32 *prop;
+ const __be32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
@@ -525,8 +527,8 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
}
EXPORT_SYMBOL(of_get_address);
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
+static int __of_address_to_resource(struct device_node *dev,
+ const __be32 *addrp, u64 size, unsigned int flags,
struct resource *r)
{
u64 taddr;
@@ -564,7 +566,7 @@ static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
- const u32 *addrp;
+ const __be32 *addrp;
u64 size;
unsigned int flags;
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c1360e02f921..c787c3d95c60 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -11,10 +11,12 @@
#include <linux/kernel.h>
#include <linux/initrd.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/slab.h>
#ifdef CONFIG_PPC
#include <asm/machdep.h>
@@ -22,104 +24,19 @@
#include <asm/page.h>
-int __initdata dt_root_addr_cells;
-int __initdata dt_root_size_cells;
-
-struct boot_param_header *initial_boot_params;
-
-char *find_flat_dt_string(u32 offset)
+char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
{
- return ((char *)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_strings) + offset;
-}
-
-/**
- * of_scan_flat_dt - scan flattened tree blob and call callback on each.
- * @it: callback function
- * @data: context data pointer
- *
- * This function is used to scan the flattened device-tree, it is
- * used to extract the memory information at boot before we can
- * unflatten the tree
- */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
- const char *uname, int depth,
- void *data),
- void *data)
-{
- unsigned long p = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
- int rc = 0;
- int depth = -1;
-
- do {
- u32 tag = be32_to_cpup((__be32 *)p);
- char *pathp;
-
- p += 4;
- if (tag == OF_DT_END_NODE) {
- depth--;
- continue;
- }
- if (tag == OF_DT_NOP)
- continue;
- if (tag == OF_DT_END)
- break;
- if (tag == OF_DT_PROP) {
- u32 sz = be32_to_cpup((__be32 *)p);
- p += 8;
- if (be32_to_cpu(initial_boot_params->version) < 0x10)
- p = ALIGN(p, sz >= 8 ? 8 : 4);
- p += sz;
- p = ALIGN(p, 4);
- continue;
- }
- if (tag != OF_DT_BEGIN_NODE) {
- pr_err("Invalid tag %x in flat device tree!\n", tag);
- return -EINVAL;
- }
- depth++;
- pathp = (char *)p;
- p = ALIGN(p + strlen(pathp) + 1, 4);
- if ((*pathp) == '/') {
- char *lp, *np;
- for (lp = NULL, np = pathp; *np; np++)
- if ((*np) == '/')
- lp = np+1;
- if (lp != NULL)
- pathp = lp;
- }
- rc = it(p, pathp, depth, data);
- if (rc != 0)
- break;
- } while (1);
-
- return rc;
+ return ((char *)blob) +
+ be32_to_cpu(blob->off_dt_strings) + offset;
}
/**
- * of_get_flat_dt_root - find the root node in the flat blob
+ * of_fdt_get_property - Given a node in the given flat blob, return
+ * the property ptr
*/
-unsigned long __init of_get_flat_dt_root(void)
-{
- unsigned long p = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
-
- while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
- p += 4;
- BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
- p += 4;
- return ALIGN(p + strlen((char *)p) + 1, 4);
-}
-
-/**
- * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
- *
- * This function can be used within scan_flattened_dt callback to get
- * access to properties
- */
-void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size)
+void *of_fdt_get_property(struct boot_param_header *blob,
+ unsigned long node, const char *name,
+ unsigned long *size)
{
unsigned long p = node;
@@ -137,10 +54,10 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
sz = be32_to_cpup((__be32 *)p);
noff = be32_to_cpup((__be32 *)(p + 4));
p += 8;
- if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ if (be32_to_cpu(blob->version) < 0x10)
p = ALIGN(p, sz >= 8 ? 8 : 4);
- nstr = find_flat_dt_string(noff);
+ nstr = of_fdt_get_string(blob, noff);
if (nstr == NULL) {
pr_warning("Can't find property index name !\n");
return NULL;
@@ -156,21 +73,28 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
}
/**
- * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * of_fdt_is_compatible - Return true if given node from the given blob has
+ * compat in its compatible list
+ * @blob: A device tree blob
* @node: node to test
* @compat: compatible string to compare with compatible list.
+ *
+ * On match, returns a non-zero value with smaller values returned for more
+ * specific compatible values.
*/
-int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+int of_fdt_is_compatible(struct boot_param_header *blob,
+ unsigned long node, const char *compat)
{
const char *cp;
- unsigned long cplen, l;
+ unsigned long cplen, l, score = 0;
- cp = of_get_flat_dt_prop(node, "compatible", &cplen);
+ cp = of_fdt_get_property(blob, node, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
+ score++;
if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
- return 1;
+ return score;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
@@ -179,7 +103,28 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
return 0;
}
-static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+/**
+ * of_fdt_match - Return true if node matches a list of compatible values
+ */
+int of_fdt_match(struct boot_param_header *blob, unsigned long node,
+ const char **compat)
+{
+ unsigned int tmp, score = 0;
+
+ if (!compat)
+ return 0;
+
+ while (*compat) {
+ tmp = of_fdt_is_compatible(blob, node, *compat);
+ if (tmp && (score == 0 || (tmp < score)))
+ score = tmp;
+ compat++;
+ }
+
+ return score;
+}
+
+static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
unsigned long align)
{
void *res;
@@ -193,16 +138,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
/**
* unflatten_dt_node - Alloc and populate a device_node from the flat tree
+ * @blob: The parent device tree blob
* @p: pointer to node in flat tree
* @dad: Parent struct device_node
* @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
-unsigned long __init unflatten_dt_node(unsigned long mem,
- unsigned long *p,
- struct device_node *dad,
- struct device_node ***allnextpp,
- unsigned long fpsize)
+unsigned long unflatten_dt_node(struct boot_param_header *blob,
+ unsigned long mem,
+ unsigned long *p,
+ struct device_node *dad,
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
@@ -298,10 +245,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
sz = be32_to_cpup((__be32 *)(*p));
noff = be32_to_cpup((__be32 *)((*p) + 4));
*p += 8;
- if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ if (be32_to_cpu(blob->version) < 0x10)
*p = ALIGN(*p, sz >= 8 ? 8 : 4);
- pname = find_flat_dt_string(noff);
+ pname = of_fdt_get_string(blob, noff);
if (pname == NULL) {
pr_info("Can't find property name in list !\n");
break;
@@ -380,7 +327,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
if (tag == OF_DT_NOP)
*p += 4;
else
- mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
+ mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
+ fpsize);
tag = be32_to_cpup((__be32 *)(*p));
}
if (tag != OF_DT_END_NODE) {
@@ -391,6 +339,211 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
return mem;
}
+/**
+ * __unflatten_device_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens a device-tree, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ * @blob: The blob to expand
+ * @mynodes: The device_node tree created by the call
+ * @dt_alloc: An allocator that provides a virtual address to memory
+ * for the resulting tree
+ */
+void __unflatten_device_tree(struct boot_param_header *blob,
+ struct device_node **mynodes,
+ void * (*dt_alloc)(u64 size, u64 align))
+{
+ unsigned long start, mem, size;
+ struct device_node **allnextp = mynodes;
+
+ pr_debug(" -> unflatten_device_tree()\n");
+
+ if (!blob) {
+ pr_debug("No device tree pointer\n");
+ return;
+ }
+
+ pr_debug("Unflattening device tree:\n");
+ pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
+ pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
+ pr_debug("version: %08x\n", be32_to_cpu(blob->version));
+
+ if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
+ pr_err("Invalid device tree blob header\n");
+ return;
+ }
+
+ /* First pass, scan for size */
+ start = ((unsigned long)blob) +
+ be32_to_cpu(blob->off_dt_struct);
+ size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
+ size = (size | 3) + 1;
+
+ pr_debug(" size is %lx, allocating...\n", size);
+
+ /* Allocate memory for the expanded device tree */
+ mem = (unsigned long)
+ dt_alloc(size + 4, __alignof__(struct device_node));
+
+ ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
+
+ pr_debug(" unflattening %lx...\n", mem);
+
+ /* Second pass, do actual unflattening */
+ start = ((unsigned long)blob) +
+ be32_to_cpu(blob->off_dt_struct);
+ unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
+ if (be32_to_cpup((__be32 *)start) != OF_DT_END)
+ pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
+ if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+ pr_warning("End of tree marker overwritten: %08x\n",
+ be32_to_cpu(((__be32 *)mem)[size / 4]));
+ *allnextp = NULL;
+
+ pr_debug(" <- unflatten_device_tree()\n");
+}
+
+static void *kernel_tree_alloc(u64 size, u64 align)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+
+/**
+ * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ */
+void of_fdt_unflatten_tree(unsigned long *blob,
+ struct device_node **mynodes)
+{
+ struct boot_param_header *device_tree =
+ (struct boot_param_header *)blob;
+ __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
+}
+EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
+
+/* Everything below here references initial_boot_params directly. */
+int __initdata dt_root_addr_cells;
+int __initdata dt_root_size_cells;
+
+struct boot_param_header *initial_boot_params;
+
+#ifdef CONFIG_OF_EARLY_FLATTREE
+
+/**
+ * of_scan_flat_dt - scan flattened tree blob and call callback on each.
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory information at boot before we can
+ * unflatten the tree
+ */
+int __init of_scan_flat_dt(int (*it)(unsigned long node,
+ const char *uname, int depth,
+ void *data),
+ void *data)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+ int rc = 0;
+ int depth = -1;
+
+ do {
+ u32 tag = be32_to_cpup((__be32 *)p);
+ char *pathp;
+
+ p += 4;
+ if (tag == OF_DT_END_NODE) {
+ depth--;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag == OF_DT_END)
+ break;
+ if (tag == OF_DT_PROP) {
+ u32 sz = be32_to_cpup((__be32 *)p);
+ p += 8;
+ if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ p = ALIGN(p, sz >= 8 ? 8 : 4);
+ p += sz;
+ p = ALIGN(p, 4);
+ continue;
+ }
+ if (tag != OF_DT_BEGIN_NODE) {
+ pr_err("Invalid tag %x in flat device tree!\n", tag);
+ return -EINVAL;
+ }
+ depth++;
+ pathp = (char *)p;
+ p = ALIGN(p + strlen(pathp) + 1, 4);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
+ if (rc != 0)
+ break;
+ } while (1);
+
+ return rc;
+}
+
+/**
+ * of_get_flat_dt_root - find the root node in the flat blob
+ */
+unsigned long __init of_get_flat_dt_root(void)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+
+ while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
+ p += 4;
+ BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
+ p += 4;
+ return ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
+/**
+ * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
+ *
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size)
+{
+ return of_fdt_get_property(initial_boot_params, node, name, size);
+}
+
+/**
+ * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ */
+int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+{
+ return of_fdt_is_compatible(initial_boot_params, node, compat);
+}
+
+/**
+ * of_flat_dt_match - Return true if node matches a list of compatible values
+ */
+int __init of_flat_dt_match(unsigned long node, const char **compat)
+{
+ return of_fdt_match(initial_boot_params, node, compat);
+}
+
#ifdef CONFIG_BLK_DEV_INITRD
/**
* early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -539,6 +692,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
return 1;
}
+static void *__init early_device_tree_alloc(u64 size, u64 align)
+{
+ unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
+ return __va(mem);
+}
+
/**
* unflatten_device_tree - create tree of device_nodes from flat blob
*
@@ -549,58 +708,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
*/
void __init unflatten_device_tree(void)
{
- unsigned long start, mem, size;
- struct device_node **allnextp = &allnodes;
-
- pr_debug(" -> unflatten_device_tree()\n");
-
- if (!initial_boot_params) {
- pr_debug("No device tree pointer\n");
- return;
- }
-
- pr_debug("Unflattening device tree:\n");
- pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
- pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
- pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
-
- if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
- pr_err("Invalid device tree blob header\n");
- return;
- }
-
- /* First pass, scan for size */
- start = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
- size = unflatten_dt_node(0, &start, NULL, NULL, 0);
- size = (size | 3) + 1;
-
- pr_debug(" size is %lx, allocating...\n", size);
-
- /* Allocate memory for the expanded device tree */
- mem = early_init_dt_alloc_memory_arch(size + 4,
- __alignof__(struct device_node));
- mem = (unsigned long) __va(mem);
-
- ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
-
- pr_debug(" unflattening %lx...\n", mem);
-
- /* Second pass, do actual unflattening */
- start = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
- unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
- if (be32_to_cpup((__be32 *)start) != OF_DT_END)
- pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
- if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
- pr_warning("End of tree marker overwritten: %08x\n",
- be32_to_cpu(((__be32 *)mem)[size / 4]));
- *allnextp = NULL;
+ __unflatten_device_tree(initial_boot_params, &allnodes,
+ early_device_tree_alloc);
/* Get pointer to OF "/chosen" node for use everywhere */
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");
-
- pr_debug(" <- unflatten_device_tree()\n");
}
+
+#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index c85d3c7421fc..f37fbeb66a44 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -61,7 +61,7 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
info.of_node = of_node_get(node);
info.archdata = &dev_ad;
- request_module("%s", info.type);
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
result = i2c_new_device(adap, &info);
if (result == NULL) {
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 1fce00eb421b..dcd7857784f2 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -52,27 +52,35 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* Loop over the child nodes and register a phy_device for each one */
for_each_child_of_node(np, child) {
- const __be32 *addr;
+ const __be32 *paddr;
+ u32 addr;
int len;
/* A PHY must have a reg property in the range [0-31] */
- addr = of_get_property(child, "reg", &len);
- if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) {
+ paddr = of_get_property(child, "reg", &len);
+ if (!paddr || len < sizeof(*paddr)) {
dev_err(&mdio->dev, "%s has invalid PHY address\n",
child->full_name);
continue;
}
+ addr = be32_to_cpup(paddr);
+ if (addr >= 32) {
+ dev_err(&mdio->dev, "%s PHY address %i is too large\n",
+ child->full_name, addr);
+ continue;
+ }
+
if (mdio->irq) {
- mdio->irq[*addr] = irq_of_parse_and_map(child, 0);
- if (!mdio->irq[*addr])
- mdio->irq[*addr] = PHY_POLL;
+ mdio->irq[addr] = irq_of_parse_and_map(child, 0);
+ if (!mdio->irq[addr])
+ mdio->irq[addr] = PHY_POLL;
}
- phy = get_phy_device(mdio, be32_to_cpup(addr));
+ phy = get_phy_device(mdio, addr);
if (!phy || IS_ERR(phy)) {
dev_err(&mdio->dev, "error probing PHY at address %i\n",
- *addr);
+ addr);
continue;
}
phy_scan_fixups(phy);
@@ -91,7 +99,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
}
dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
- child->name, *addr);
+ child->name, addr);
}
return 0;
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
new file mode 100644
index 000000000000..86f334a2769c
--- /dev/null
+++ b/drivers/of/of_net.c
@@ -0,0 +1,48 @@
+/*
+ * OF helpers for network devices.
+ *
+ * This file is released under the GPLv2
+ *
+ * Initially copied out of arch/powerpc/kernel/prom_parse.c
+ */
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/of_net.h>
+
+/**
+ * Search the device tree for the best MAC address to use. 'mac-address' is
+ * checked first, because that is supposed to contain to "most recent" MAC
+ * address. If that isn't set, then 'local-mac-address' is checked next,
+ * because that is the default address. If that isn't set, then the obsolete
+ * 'address' is checked, just in case we're using an old device tree.
+ *
+ * Note that the 'address' property is supposed to contain a virtual address of
+ * the register set, but some DTS files have redefined that property to be the
+ * MAC address.
+ *
+ * All-zero MAC addresses are rejected, because those could be properties that
+ * exist in the device tree, but were not set by U-Boot. For example, the
+ * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
+ * addresses. Some older U-Boots only initialized 'local-mac-address'. In
+ * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
+ * but is all zeros.
+*/
+const void *of_get_mac_address(struct device_node *np)
+{
+ struct property *pp;
+
+ pp = of_find_property(np, "mac-address", NULL);
+ if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+ return pp->value;
+
+ pp = of_find_property(np, "local-mac-address", NULL);
+ if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+ return pp->value;
+
+ pp = of_find_property(np, "address", NULL);
+ if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
+ return pp->value;
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_mac_address);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 5b4a07f1220e..c01cd1ac7617 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -633,6 +633,9 @@ EXPORT_SYMBOL(of_device_alloc);
* @np: pointer to node to create device for
* @bus_id: name to assign device
* @parent: Linux device model parent device.
+ *
+ * Returns pointer to created platform device, or NULL if a device was not
+ * registered. Unavailable devices will not get registered.
*/
struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
@@ -640,6 +643,9 @@ struct platform_device *of_platform_device_create(struct device_node *np,
{
struct platform_device *dev;
+ if (!of_device_is_available(np))
+ return NULL;
+
dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;
@@ -683,8 +689,9 @@ static int of_platform_bus_create(const struct device_node *bus,
pr_debug(" create child: %s\n", child->full_name);
dev = of_platform_device_create(child, NULL, parent);
if (dev == NULL)
- rc = -ENOMEM;
- else if (!of_match_node(matches, child))
+ continue;
+
+ if (!of_match_node(matches, child))
continue;
if (rc == 0) {
pr_debug(" and sub busses\n");
@@ -733,10 +740,9 @@ int of_platform_bus_probe(struct device_node *root,
if (of_match_node(matches, root)) {
pr_debug(" root match, create all sub devices\n");
dev = of_platform_device_create(root, NULL, parent);
- if (dev == NULL) {
- rc = -ENOMEM;
+ if (dev == NULL)
goto bail;
- }
+
pr_debug(" create all sub busses\n");
rc = of_platform_bus_create(root, matches, &dev->dev);
goto bail;
@@ -748,9 +754,9 @@ int of_platform_bus_probe(struct device_node *root,
pr_debug(" match: %s\n", child->full_name);
dev = of_platform_device_create(child, NULL, parent);
if (dev == NULL)
- rc = -ENOMEM;
- else
- rc = of_platform_bus_create(child, matches, &dev->dev);
+ continue;
+
+ rc = of_platform_bus_create(child, matches, &dev->dev);
if (rc) {
of_node_put(child);
break;
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b7e755f4178a..a3984f4ef192 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -190,7 +190,7 @@ void sync_stop(void)
profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
task_handoff_unregister(&task_free_nb);
mutex_unlock(&buffer_mutex);
- flush_scheduled_work();
+ flush_cpu_work();
/* make sure we don't leak task structs */
process_task_mortuary();
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index f179ac2ea801..59f55441e075 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -111,14 +111,18 @@ void start_cpu_work(void)
void end_cpu_work(void)
{
- int i;
-
work_enabled = 0;
+}
+
+void flush_cpu_work(void)
+{
+ int i;
for_each_online_cpu(i) {
struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i);
- cancel_delayed_work(&b->work);
+ /* these works are per-cpu, no need for flush_sync */
+ flush_delayed_work(&b->work);
}
}
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index 68ea16ab645f..e1d097e250ae 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -25,6 +25,7 @@ void free_cpu_buffers(void);
void start_cpu_work(void);
void end_cpu_work(void);
+void flush_cpu_work(void);
/* CPU buffer is composed of such entries (which are
* also used for context switch notes)
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index dc0ae4d14dff..010725117dbb 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -21,6 +21,7 @@
#include "oprof.h"
static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer);
+static int ctr_running;
static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer)
{
@@ -33,6 +34,9 @@ static void __oprofile_hrtimer_start(void *unused)
{
struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer);
+ if (!ctr_running)
+ return;
+
hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer->function = oprofile_hrtimer_notify;
@@ -42,7 +46,10 @@ static void __oprofile_hrtimer_start(void *unused)
static int oprofile_hrtimer_start(void)
{
+ get_online_cpus();
+ ctr_running = 1;
on_each_cpu(__oprofile_hrtimer_start, NULL, 1);
+ put_online_cpus();
return 0;
}
@@ -50,6 +57,9 @@ static void __oprofile_hrtimer_stop(int cpu)
{
struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu);
+ if (!ctr_running)
+ return;
+
hrtimer_cancel(hrtimer);
}
@@ -57,8 +67,11 @@ static void oprofile_hrtimer_stop(void)
{
int cpu;
+ get_online_cpus();
for_each_online_cpu(cpu)
__oprofile_hrtimer_stop(cpu);
+ ctr_running = 0;
+ put_online_cpus();
}
static int __cpuinit oprofile_cpu_notify(struct notifier_block *self,
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index d9f51485beee..9383063d2b16 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -349,7 +349,6 @@ static struct irq_chip dino_interrupt_type = {
.name = "GSC-PCI",
.unmask = dino_unmask_irq,
.mask = dino_mask_irq,
- .ack = no_ack_irq,
};
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 1211974f55aa..e860038b0b84 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -186,7 +186,6 @@ static struct irq_chip eisa_interrupt_type = {
.name = "EISA",
.unmask = eisa_unmask_irq,
.mask = eisa_mask_irq,
- .ack = no_ack_irq,
};
static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
@@ -340,7 +339,7 @@ static int __init eisa_probe(struct parisc_device *dev)
setup_irq(2, &irq2_action);
for (i = 0; i < 16; i++) {
set_irq_chip_and_handler(i, &eisa_interrupt_type,
- handle_level_irq);
+ handle_simple_irq);
}
EISA_bus = 1;
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index cce00ed81f37..af212c6a6158 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index e605298e3aee..772b1939ac21 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -143,7 +143,6 @@ static struct irq_chip gsc_asic_interrupt_type = {
.name = "GSC-ASIC",
.unmask = gsc_asic_unmask_irq,
.mask = gsc_asic_mask_irq,
- .ack = no_ack_irq,
};
int gsc_assign_irq(struct irq_chip *type, void *data)
@@ -153,7 +152,7 @@ int gsc_assign_irq(struct irq_chip *type, void *data)
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
- set_irq_chip_and_handler(irq, type, handle_level_irq);
+ set_irq_chip_and_handler(irq, type, handle_simple_irq);
set_irq_chip_data(irq, data);
return irq++;
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index a3120a09c43d..0327894bf235 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -669,6 +669,13 @@ printk("\n");
DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
+}
+
+static void iosapic_eoi_irq(unsigned int irq)
+{
+ struct vector_info *vi = get_irq_chip_data(irq);
+
+ iosapic_eoi(vi->eoi_addr, vi->eoi_data);
cpu_eoi_irq(irq);
}
@@ -705,6 +712,7 @@ static struct irq_chip iosapic_interrupt_type = {
.unmask = iosapic_unmask_irq,
.mask = iosapic_mask_irq,
.ack = cpu_ack_irq,
+ .eoi = iosapic_eoi_irq,
#ifdef CONFIG_SMP
.set_affinity = iosapic_set_affinity_irq,
#endif
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 2350e8a86eef..f2f501e5b6a0 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -64,6 +64,7 @@ static unsigned int led_diskio __read_mostly = 1;
static unsigned int led_lanrxtx __read_mostly = 1;
static char lcd_text[32] __read_mostly;
static char lcd_text_default[32] __read_mostly;
+static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */
static struct workqueue_struct *led_wq;
@@ -115,7 +116,7 @@ lcd_info __attribute__((aligned(8))) __read_mostly =
.lcd_width = 16,
.lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD,
.lcd_data_reg_addr = KITTYHAWK_LCD_DATA,
- .min_cmd_delay = 40,
+ .min_cmd_delay = 80,
.reset_cmd1 = 0x80,
.reset_cmd2 = 0xc0,
};
@@ -135,6 +136,9 @@ static int start_task(void)
/* Display the default text now */
if (led_type == LED_HASLCD) lcd_print( lcd_text_default );
+ /* KittyHawk has no LED support on its LCD */
+ if (lcd_no_led_support) return 0;
+
/* Create the work queue and queue the LED task */
led_wq = create_singlethread_workqueue("led_wq");
queue_delayed_work(led_wq, &led_task, 0);
@@ -248,9 +252,13 @@ static int __init led_create_procfs(void)
proc_pdc_root = proc_mkdir("pdc", 0);
if (!proc_pdc_root) return -1;
- ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root,
- &led_proc_fops, (void *)LED_NOLCD); /* LED */
- if (!ent) return -1;
+
+ if (!lcd_no_led_support)
+ {
+ ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root,
+ &led_proc_fops, (void *)LED_NOLCD); /* LED */
+ if (!ent) return -1;
+ }
if (led_type == LED_HASLCD)
{
@@ -692,6 +700,7 @@ int __init led_init(void)
case 0x58B: /* KittyHawk DC2 100 (K200) */
printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
"LED detection skipped.\n", __FILE__, CPU_HVERSION);
+ lcd_no_led_support = 1;
goto found; /* use the preinitialized values of lcd_info */
}
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 0846dafdfff1..28241532c0fd 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -323,7 +323,6 @@ static struct irq_chip superio_interrupt_type = {
.name = SUPERIO,
.unmask = superio_unmask_irq,
.mask = superio_mask_irq,
- .ack = no_ack_irq,
};
#ifdef DEBUG_SUPERIO_INIT
@@ -354,7 +353,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
#endif
for (i = 0; i < 16; i++) {
- set_irq_chip_and_handler(i, &superio_interrupt_type, handle_level_irq);
+ set_irq_chip_and_handler(i, &superio_interrupt_type, handle_simple_irq);
}
/*
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 5b1630e4e9e3..a9523fdc6911 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -45,6 +45,7 @@ config XEN_PCIDEV_FRONTEND
depends on PCI && X86 && XEN
select HOTPLUG
select PCI_XEN
+ select XEN_XENBUS_FRONTEND
default y
help
The PCI device frontend driver allows the kernel to import arbitrary
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index f01e344cf4bd..98e6fdf34d30 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
obj-$(CONFIG_MN10300) += setup-bus.o
obj-$(CONFIG_MICROBLAZE) += setup-bus.o
+obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
#
# ACPI Related PCI FW Functions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 5624db8c9ad0..69546e9213dd 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -64,49 +64,6 @@ void pci_bus_remove_resources(struct pci_bus *bus)
}
}
-/*
- * Find the highest-address bus resource below the cursor "res". If the
- * cursor is NULL, return the highest resource.
- */
-static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
- unsigned int type,
- struct resource *res)
-{
- struct resource *r, *prev = NULL;
- int i;
-
- pci_bus_for_each_resource(bus, r, i) {
- if (!r)
- continue;
-
- if ((r->flags & IORESOURCE_TYPE_BITS) != type)
- continue;
-
- /* If this resource is at or past the cursor, skip it */
- if (res) {
- if (r == res)
- continue;
- if (r->end > res->end)
- continue;
- if (r->end == res->end && r->start > res->start)
- continue;
- }
-
- if (!prev)
- prev = r;
-
- /*
- * A small resource is higher than a large one that ends at
- * the same address.
- */
- if (r->end > prev->end ||
- (r->end == prev->end && r->start > prev->start))
- prev = r;
- }
-
- return prev;
-}
-
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
@@ -132,10 +89,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t),
void *alignf_data)
{
- int ret = -ENOMEM;
+ int i, ret = -ENOMEM;
struct resource *r;
resource_size_t max = -1;
- unsigned int type = res->flags & IORESOURCE_TYPE_BITS;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
@@ -143,9 +99,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
if (!(res->flags & IORESOURCE_MEM_64))
max = PCIBIOS_MAX_MEM_32;
- /* Look for space at highest addresses first */
- r = pci_bus_find_resource_prev(bus, type, NULL);
- for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) {
+ pci_bus_for_each_resource(bus, r, i) {
+ if (!r)
+ continue;
+
/* type_mask must match */
if ((res->flags ^ r->flags) & type_mask)
continue;
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 0157708d474d..09933eb9126b 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -1417,6 +1417,11 @@ int __init enable_drhd_fault_handling(void)
(unsigned long long)drhd->reg_base_addr, ret);
return -1;
}
+
+ /*
+ * Clear any previous faults.
+ */
+ dmar_fault(iommu->irq, iommu);
}
return 0;
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index bab52047baa8..7722108e78df 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -36,7 +36,6 @@
#define _ACPIPHP_H
#include <linux/acpi.h>
-#include <linux/kobject.h>
#include <linux/mutex.h>
#include <linux/pci_hotplug.h>
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 5becbdee4027..2850e64dedae 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -276,6 +276,12 @@ int __init ibmphp_access_ebda (void)
for (;;) {
offset = next_offset;
+
+ /* Make sure what we read is still in the mapped section */
+ if (WARN(offset > (ebda_sz * 1024 - 4),
+ "ibmphp_ebda: next read is beyond ebda_sz\n"))
+ break;
+
next_offset = readw (io_mem + offset); /* offset of next blk */
offset += 2;
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index 2574700db461..5f7226223a62 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -115,7 +115,8 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
static int __init select_detection_mode(void)
{
struct dummy_slot *slot, *tmp;
- pcie_port_service_register(&dummy_driver);
+ if (pcie_port_service_register(&dummy_driver))
+ return PCIEHP_DETECT_ACPI;
pcie_port_service_unregister(&dummy_driver);
list_for_each_entry_safe(slot, tmp, &dummy_slots, list) {
list_del(&slot->list);
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index 2ea9cf1a8d02..b283bbea6d24 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -24,7 +24,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/pci.h>
#include <linux/string.h>
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7c24dcef2989..44b0aeee83e5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -168,8 +168,9 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
u32 mask_bits = desc->masked;
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL;
- mask_bits &= ~1;
- mask_bits |= flag;
+ mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ if (flag)
+ mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
writel(mask_bits, desc->mask_base + offset);
return mask_bits;
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index feff3bee6fe5..65c42f80f23e 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -6,12 +6,6 @@
#ifndef MSI_H
#define MSI_H
-#define PCI_MSIX_ENTRY_SIZE 16
-#define PCI_MSIX_ENTRY_LOWER_ADDR 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR 4
-#define PCI_MSIX_ENTRY_DATA 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
-
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 24e19c594e57..6fe0772e0e7d 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -46,9 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
struct pci_dev *pci_dev = context;
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
+ pci_wakeup_event(pci_dev);
pci_check_pme_status(pci_dev);
pm_runtime_resume(&pci_dev->dev);
- pci_wakeup_event(pci_dev);
if (pci_dev->subordinate)
pci_pme_wakeup_bus(pci_dev->subordinate);
}
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
+ pcie_clear_aspm();
pcie_no_aspm();
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8a6f797de8e5..88246dd46452 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -338,7 +338,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
}
/**
- * __pci_device_probe()
+ * __pci_device_probe - check if a driver wants to claim a specific PCI device
* @drv: driver to call to check if it wants the PCI device
* @pci_dev: PCI device being probed
*
@@ -449,7 +449,8 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
return error;
}
- return pci_restore_state(pci_dev);
+ pci_restore_state(pci_dev);
+ return 0;
}
static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c
index f7b68ca6cc98..775e933c2225 100644
--- a/drivers/pci/pci-stub.c
+++ b/drivers/pci/pci-stub.c
@@ -47,6 +47,10 @@ static int __init pci_stub_init(void)
if (rc)
return rc;
+ /* no ids passed actually */
+ if (ids[0] == '\0')
+ return 0;
+
/* add ids specified in the module parameter */
p = ids;
while ((id = strsep(&p, ","))) {
@@ -54,6 +58,9 @@ static int __init pci_stub_init(void)
subdevice = PCI_ANY_ID, class=0, class_mask=0;
int fields;
+ if (!strlen(id))
+ continue;
+
fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index b5a7d9bfcb24..8ecaac983923 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -705,17 +705,21 @@ void pci_remove_legacy_files(struct pci_bus *b)
#ifdef HAVE_PCI_MMAP
-int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
+ enum pci_mmap_api mmap_api)
{
- unsigned long nr, start, size;
+ unsigned long nr, start, size, pci_start;
+ if (pci_resource_len(pdev, resno) == 0)
+ return 0;
nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
start = vma->vm_pgoff;
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
- if (start < size && size - start >= nr)
+ pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
+ pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0;
+ if (start >= pci_start && start < pci_start + size &&
+ start + nr <= pci_start + size)
return 1;
- WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
- current->comm, start, start+nr, pci_name(pdev), resno, size);
return 0;
}
@@ -745,8 +749,15 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
if (i >= PCI_ROM_RESOURCE)
return -ENODEV;
- if (!pci_mmap_fits(pdev, i, vma))
+ if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) {
+ WARN(1, "process \"%s\" tried to map 0x%08lx bytes "
+ "at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n",
+ current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff,
+ pci_name(pdev), i,
+ (u64)pci_resource_start(pdev, i),
+ (u64)pci_resource_len(pdev, i));
return -EINVAL;
+ }
/* pci_mmap_page_range() expects the same kind of entry as coming
* from /proc/bus/pci/ which is a "user visible" value. If this is
@@ -1138,7 +1149,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
sysfs_bin_attr_init(attr);
attr->size = rom_size;
attr->attr.name = "rom";
- attr->attr.mode = S_IRUSR;
+ attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = pci_read_rom;
attr->write = pci_write_rom;
retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e98c8104297b..b714d787bddd 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -937,14 +937,13 @@ pci_save_state(struct pci_dev *dev)
* pci_restore_state - Restore the saved state of a PCI device
* @dev: - PCI device that we're dealing with
*/
-int
-pci_restore_state(struct pci_dev *dev)
+void pci_restore_state(struct pci_dev *dev)
{
int i;
u32 val;
if (!dev->state_saved)
- return 0;
+ return;
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
@@ -968,8 +967,6 @@ pci_restore_state(struct pci_dev *dev)
pci_restore_iov_state(dev);
dev->state_saved = false;
-
- return 0;
}
static int do_pci_enable_device(struct pci_dev *dev, int bars)
@@ -1007,6 +1004,18 @@ static int __pci_enable_device_flags(struct pci_dev *dev,
int err;
int i, bars = 0;
+ /*
+ * Power state could be unknown at this point, either due to a fresh
+ * boot or a device removal call. So get the current power state
+ * so that things like MSI message writing will behave as expected
+ * (e.g. if the device really is in D0 at enable time).
+ */
+ if (dev->pm_cap) {
+ u16 pmcsr;
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+ }
+
if (atomic_add_return(1, &dev->enable_cnt) > 1)
return 0; /* already enabled */
@@ -1288,22 +1297,6 @@ bool pci_check_pme_status(struct pci_dev *dev)
return ret;
}
-/*
- * Time to wait before the system can be put into a sleep state after reporting
- * a wakeup event signaled by a PCI device.
- */
-#define PCI_WAKEUP_COOLDOWN 100
-
-/**
- * pci_wakeup_event - Report a wakeup event related to a given PCI device.
- * @dev: Device to report the wakeup event for.
- */
-void pci_wakeup_event(struct pci_dev *dev)
-{
- if (device_may_wakeup(&dev->dev))
- pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
-}
-
/**
* pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
* @dev: Device to handle.
@@ -1315,8 +1308,8 @@ void pci_wakeup_event(struct pci_dev *dev)
static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
{
if (pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
return 0;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f5c7c382765f..f69d6e0fda75 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -22,8 +22,13 @@ extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
#endif
extern void pci_cleanup_rom(struct pci_dev *dev);
#ifdef HAVE_PCI_MMAP
+enum pci_mmap_api {
+ PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
+ PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */
+};
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
- struct vm_area_struct *vma);
+ struct vm_area_struct *vmai,
+ enum pci_mmap_api mmap_api);
#endif
int pci_probe_reset_function(struct pci_dev *dev);
@@ -69,6 +74,12 @@ extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+static inline void pci_wakeup_event(struct pci_dev *dev)
+{
+ /* Wait 100 ms before the system can be put into a sleep state. */
+ pm_wakeup_event(&dev->dev, 100);
+}
+
static inline bool pci_is_bridge(struct pci_dev *pci_dev)
{
return !!(pci_dev->subordinate);
@@ -135,14 +146,6 @@ static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
-#ifdef CONFIG_PCIEAER
-void pci_no_aer(void);
-bool pci_aer_available(void);
-#else
-static inline void pci_no_aer(void) { }
-static inline bool pci_aer_available(void) { return false; }
-#endif
-
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 2b2b6508efde..58ad7917553c 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 9656e3060412..80c11d131499 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
#ifdef CONFIG_ACPI_APEI
extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
-extern bool aer_acpi_firmware_first(void);
#else
static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
{
@@ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
return pci_dev->__aer_firmware_first;
return 0;
}
-
-static inline bool aer_acpi_firmware_first(void) { return false; }
#endif
static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 71222814c1ec..3188cd96b338 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -68,7 +68,7 @@ struct pcie_link_state {
struct aspm_latency acceptable[8];
};
-static int aspm_disabled, aspm_force;
+static int aspm_disabled, aspm_force, aspm_clear_state;
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
{
/* Don't enable Clock PM if the link is not Clock PM capable */
if (!link->clkpm_capable && enable)
- return;
+ enable = 0;
/* Need nothing if the specified equals to current state */
if (link->clkpm_enabled == enable)
return;
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
struct pci_dev *child;
int pos;
u32 reg32;
+
+ if (aspm_clear_state)
+ return -EINVAL;
+
/*
* Some functions in a slot might not all be PCIe functions,
* very strange. Disable ASPM for the whole slot
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev);
- if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
+ if (!pci_is_pcie(pdev) || pdev->link_state)
return;
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
return;
+ if (aspm_disabled && !aspm_clear_state)
+ return;
+
/* VIA has a strange chipset, root port is under a bridge */
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
pdev->bus->self)
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link;
- if (aspm_disabled || !pci_is_pcie(pdev) ||
+ if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
!parent || !parent->link_state)
return;
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
__setup("pcie_aspm=", pcie_aspm_disable);
+void pcie_clear_aspm(void)
+{
+ if (!aspm_force)
+ aspm_clear_state = 1;
+}
+
void pcie_no_aspm(void)
{
if (!aspm_force)
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 2f3c90407227..0057344a3fcb 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -26,9 +26,6 @@
#include "../pci.h"
#include "portdrv.h"
-#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
-
/*
* If this switch is set, MSI will not be used for PCIe PME signaling. This
* causes the PCIe port driver to use INTx interrupts only, but it turns out
@@ -74,22 +71,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
}
/**
- * pcie_pme_clear_status - Clear root port PME interrupt status.
- * @dev: PCIe root port or event collector.
- */
-static void pcie_pme_clear_status(struct pci_dev *dev)
-{
- int rtsta_pos;
- u32 rtsta;
-
- rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
-
- pci_read_config_dword(dev, rtsta_pos, &rtsta);
- rtsta |= PCI_EXP_RTSTA_PME;
- pci_write_config_dword(dev, rtsta_pos, rtsta);
-}
-
-/**
* pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#.
* @bus: PCI bus to scan.
*
@@ -103,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
/* Skip PCIe devices in case we started from a root port. */
if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
ret = true;
}
@@ -206,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
/* The device is there, but we have to check its PME status. */
found = pci_check_pme_status(dev);
if (found) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
pci_dev_put(dev);
} else if (devfn) {
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
* Clear PME status of the port. If there are other
* pending PMEs, the status will be set again.
*/
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
spin_unlock_irq(&data->lock);
pcie_pme_handle_request(port, rtsta & 0xffff);
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
port = srv->port;
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
if (ret) {
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
spin_lock_irq(&data->lock);
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
data->noirq = true;
spin_unlock_irq(&data->lock);
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv)
spin_lock_irq(&data->lock);
data->noirq = false;
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
pcie_pme_interrupt_enable(port, true);
spin_unlock_irq(&data->lock);
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 7b5aba0a3291..bd00a01aef14 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -20,9 +20,6 @@
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
-extern bool pcie_ports_disabled;
-extern bool pcie_ports_auto;
-
extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM
@@ -35,6 +32,8 @@ extern void pcie_port_bus_unregister(void);
struct pci_dev;
+extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+
#ifdef CONFIG_PCIE_PME
extern bool pcie_pme_msi_disabled;
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
index 5982b6a63b89..a86b56e5f2f2 100644
--- a/drivers/pci/pcie/portdrv_acpi.c
+++ b/drivers/pci/pcie/portdrv_acpi.c
@@ -33,7 +33,7 @@
*/
int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
{
- acpi_status status;
+ struct acpi_pci_root *root;
acpi_handle handle;
u32 flags;
@@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
if (!handle)
return -EINVAL;
- flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
- | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
- | OSC_PCI_EXPRESS_PME_CONTROL;
-
- if (pci_aer_available()) {
- if (aer_acpi_firmware_first())
- dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
- else
- flags |= OSC_PCI_EXPRESS_AER_CONTROL;
- }
-
- status = acpi_pci_osc_control_set(handle, &flags,
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
- if (ACPI_FAILURE(status)) {
- dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
- status);
+ root = acpi_pci_find_root(handle);
+ if (!root)
return -ENODEV;
- }
- dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags);
+ flags = root->osc_control_set;
*srv_mask = PCIE_PORT_SERVICE_VC;
if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index a9c222d79ebc..5130d0d22390 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev)
int cap_mask;
int err;
+ if (pcie_ports_disabled)
+ return 0;
+
err = pcie_port_platform_notify(dev, &cap_mask);
- if (pcie_ports_auto) {
- if (err) {
- pcie_no_aspm();
- return 0;
- }
- } else {
+ if (!pcie_ports_auto) {
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
| PCIE_PORT_SERVICE_VC;
if (pci_aer_available())
cap_mask |= PCIE_PORT_SERVICE_AER;
+ } else if (err) {
+ return 0;
}
pos = pci_pcie_cap(dev);
@@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev)
int status, capabilities, i, nr_service;
int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
- /* Get and check PCI Express port services */
- capabilities = get_port_device_capability(dev);
- if (!capabilities)
- return -ENODEV;
-
/* Enable PCI Express port device */
status = pci_enable_device(dev);
if (status)
return status;
+
+ /* Get and check PCI Express port services */
+ capabilities = get_port_device_capability(dev);
+ if (!capabilities) {
+ pcie_no_aspm();
+ return 0;
+ }
+
pci_set_master(dev);
/*
* Initialize service irqs. Don't use service devices that
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index f9033e190fb6..e0610bda1dea 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup);
/* global data */
+/**
+ * pcie_clear_root_pme_status - Clear root port PME interrupt status.
+ * @dev: PCIe root port or event collector.
+ */
+void pcie_clear_root_pme_status(struct pci_dev *dev)
+{
+ int rtsta_pos;
+ u32 rtsta;
+
+ rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
+
+ pci_read_config_dword(dev, rtsta_pos, &rtsta);
+ rtsta |= PCI_EXP_RTSTA_PME;
+ pci_write_config_dword(dev, rtsta_pos, rtsta);
+}
+
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
}
#ifdef CONFIG_PM
+static int pcie_port_resume_noirq(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /*
+ * Some BIOSes forget to clear Root PME Status bits after system wakeup
+ * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
+ * bits now just in case (shouldn't hurt).
+ */
+ if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ pcie_clear_root_pme_status(pdev);
+ return 0;
+}
+
static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.suspend = pcie_port_device_suspend,
.resume = pcie_port_device_resume,
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.thaw = pcie_port_device_resume,
.poweroff = pcie_port_device_suspend,
.restore = pcie_port_device_resume,
+ .resume_noirq = pcie_port_resume_noirq,
};
#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void)
{
int retval;
- if (pcie_ports_disabled) {
- pcie_no_aspm();
- return -EACCES;
- }
+ if (pcie_ports_disabled)
+ return pci_register_driver(&pcie_portdriver);
dmi_check_system(pcie_portdrv_dmi_table);
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 297b72c880a1..27911b55c2a5 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -257,7 +256,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
/* Make sure the caller is mapping a real resource for this device */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
- if (pci_mmap_fits(dev, i, vma))
+ if (pci_mmap_fits(dev, i, vma, PCI_MMAP_PROCFS))
break;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f5c63fe9db5c..53a786fd0d40 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2136,6 +2136,24 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB,
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB,
quirk_unhide_mch_dev6);
+#ifdef CONFIG_TILE
+/*
+ * The Tilera TILEmpower platform needs to set the link speed
+ * to 2.5GT(Giga-Transfers)/s (Gen 1). The default link speed
+ * setting is 5GT/s (Gen 2). 0x98 is the Link Control2 PCIe
+ * capability register of the PEX8624 PCIe switch. The switch
+ * supports link speed auto negotiation, but falsely sets
+ * the link speed to 5GT/s.
+ */
+static void __devinit quirk_tile_plx_gen1(struct pci_dev *dev)
+{
+ if (tile_plx_gen1) {
+ pci_write_config_dword(dev, 0x98, 0x1);
+ mdelay(50);
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1);
+#endif /* CONFIG_TILE */
#ifdef CONFIG_PCI_MSI
/* Some chipsets do not support MSI. We cannot easily rely on setting
@@ -2311,6 +2329,9 @@ static void __devinit nvbridge_check_legacy_irq_routing(struct pci_dev *dev)
{
u32 cfg;
+ if (!pci_find_capability(dev, PCI_CAP_ID_HT))
+ return;
+
pci_read_config_dword(dev, 0x74, &cfg);
if (cfg & ((1 << 2) | (1 << 15))) {
@@ -2746,6 +2767,29 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_m
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
#endif /*CONFIG_MMC_RICOH_MMC*/
+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
+#define VTUNCERRMSK_REG 0x1ac
+#define VTD_MSK_SPEC_ERRORS (1 << 31)
+/*
+ * This is a quirk for masking vt-d spec defined errors to platform error
+ * handling logic. With out this, platforms using Intel 7500, 5500 chipsets
+ * (and the derivative chipsets like X58 etc) seem to generate NMI/SMI (based
+ * on the RAS config settings of the platform) when a vt-d fault happens.
+ * The resulting SMI caused the system to hang.
+ *
+ * VT-d spec related errors are already handled by the VT-d OS code, so no
+ * need to report the same error through other channels.
+ */
+static void vtd_mask_spec_errors(struct pci_dev *dev)
+{
+ u32 word;
+
+ pci_read_config_dword(dev, VTUNCERRMSK_REG, &word);
+ pci_write_config_dword(dev, VTUNCERRMSK_REG, word | VTD_MSK_SPEC_ERRORS);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
+#endif
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index a87c4985326e..3a5a6fcc0ead 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -13,7 +13,6 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/msi.h>
-#include <xen/xenbus.h>
#include <xen/interface/io/pciif.h>
#include <asm/xen/pci.h>
#include <linux/interrupt.h>
@@ -576,8 +575,9 @@ static pci_ers_result_t pcifront_common_process(int cmd,
pcidev = pci_get_bus_and_slot(bus, devfn);
if (!pcidev || !pcidev->driver) {
- dev_err(&pcidev->dev,
- "device or driver is NULL\n");
+ dev_err(&pdev->xdev->dev, "device or AER driver is NULL\n");
+ if (pcidev)
+ pci_dev_put(pcidev);
return result;
}
pdrv = pcidev->driver;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index c80a7a6e7698..de886f3dfd39 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -215,7 +215,8 @@ config PCMCIA_PXA2XX
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
- || MACH_VPAC270 || MACH_BALLOON3)
+ || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
+ || MACH_COLIBRI320)
select PCMCIA_SOC_COMMON
help
Say Y here to include support for the PXA2xx PCMCIA controller
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 8d9386a22eb3..29935ea921df 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -50,8 +50,9 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o
sa1100_cs-y += sa1100_generic.o
sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o
sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o
-sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o
+sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o
sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o
+sa1100_cs-$(CONFIG_SA1100_NANOENGINE) += sa1100_nanoengine.o
sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o
sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
@@ -70,6 +71,8 @@ pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o
+pxa2xx-obj-$(CONFIG_MACH_COLIBRI) += pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_COLIBRI320) += pxa2xx_colibri.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h
index 8146e3bee2e8..f558e1adf954 100644
--- a/drivers/pcmcia/m32r_cfc.h
+++ b/drivers/pcmcia/m32r_cfc.h
@@ -9,7 +9,7 @@
#endif
/*
- * M32R PC Card Controler
+ * M32R PC Card Controller
*/
#define M32R_PCC0_BASE 0x00ef7000
#define M32R_PCC1_BASE 0x00ef7020
diff --git a/drivers/pcmcia/m32r_pcc.h b/drivers/pcmcia/m32r_pcc.h
index e4fffe417ba9..f95c58563bc8 100644
--- a/drivers/pcmcia/m32r_pcc.h
+++ b/drivers/pcmcia/m32r_pcc.h
@@ -5,7 +5,7 @@
#define M32R_MAX_PCC 2
/*
- * M32R PC Card Controler
+ * M32R PC Card Controller
*/
#define M32R_PCC0_BASE 0x00ef7000
#define M32R_PCC1_BASE 0x00ef7020
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 99d4f23cb435..0db482771fb5 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1198,7 +1198,7 @@ static int __init m8xx_probe(struct platform_device *ofdev,
out_be32(M8XX_PGCRX(1),
M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
- /* intialize the fixed memory windows */
+ /* initialize the fixed memory windows */
for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 8cbfa067171f..96c72e90b79c 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -725,17 +725,17 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
return 0;
- err_out_free_res2:
+err_out_free_res2:
if (irq_mode == 1)
free_irq(dev->irq, socket);
else
del_timer_sync(&socket->poll_timer);
- err_out_free_res:
+err_out_free_res:
pci_release_regions(dev);
- err_out_disable:
+err_out_disable:
pci_disable_device(dev);
- err_out_free_mem:
+err_out_free_mem:
kfree(socket);
return ret;
}
diff --git a/drivers/pcmcia/pd6729.h b/drivers/pcmcia/pd6729.h
index 41418d394c55..c8e84bdece38 100644
--- a/drivers/pcmcia/pd6729.h
+++ b/drivers/pcmcia/pd6729.h
@@ -15,7 +15,7 @@
struct pd6729_socket {
int number;
int card_irq;
- unsigned long io_base; /* base io address of the socket */
+ unsigned long io_base; /* base io address of the socket */
struct pcmcia_socket socket;
struct timer_list poll_timer;
};
diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c
index dbbdd0063202..453c54c97612 100644
--- a/drivers/pcmcia/pxa2xx_balloon3.c
+++ b/drivers/pcmcia/pxa2xx_balloon3.c
@@ -39,12 +39,10 @@ static struct pcmcia_irqs irqs[] = {
static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
uint16_t ver;
- int ret;
- static void __iomem *fpga_ver;
ver = __raw_readw(BALLOON3_FPGA_VER);
- if (ver > 0x0201)
- pr_warn("The FPGA code, version 0x%04x, is newer than rel-0.3. "
+ if (ver < 0x4f08)
+ pr_warn("The FPGA code, version 0x%04x, is too old. "
"PCMCIA/CF support might be broken in this version!",
ver);
@@ -97,8 +95,9 @@ static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
- __raw_writew((state->flags & SS_RESET) ? BALLOON3_CF_RESET : 0,
- BALLOON3_CF_CONTROL_REG);
+ __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG |
+ ((state->flags & SS_RESET) ?
+ BALLOON3_FPGA_SETnCLR : 0));
return 0;
}
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index ae07b4db8a6e..3755e7c8c715 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
+#include <mach/smemc.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -116,37 +117,49 @@ static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz,
static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock )
{
- MCMEM(sock) = ((pxa2xx_mcxx_setup(speed, clock)
+ uint32_t val;
+
+ val = ((pxa2xx_mcxx_setup(speed, clock)
& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
| ((pxa2xx_mcxx_asst(speed, clock)
& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
| ((pxa2xx_mcxx_hold(speed, clock)
& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+ __raw_writel(val, MCMEM(sock));
+
return 0;
}
static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock )
{
- MCIO(sock) = ((pxa2xx_mcxx_setup(speed, clock)
+ uint32_t val;
+
+ val = ((pxa2xx_mcxx_setup(speed, clock)
& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
| ((pxa2xx_mcxx_asst(speed, clock)
& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
| ((pxa2xx_mcxx_hold(speed, clock)
& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+ __raw_writel(val, MCIO(sock));
+
return 0;
}
static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock )
{
- MCATT(sock) = ((pxa2xx_mcxx_setup(speed, clock)
+ uint32_t val;
+
+ val = ((pxa2xx_mcxx_setup(speed, clock)
& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
| ((pxa2xx_mcxx_asst(speed, clock)
& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
| ((pxa2xx_mcxx_hold(speed, clock)
& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
+ __raw_writel(val, MCATT(sock));
+
return 0;
}
@@ -166,8 +179,8 @@ static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int cl
static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
{
- unsigned int clk = get_memclk_frequency_10khz();
- return pxa2xx_pcmcia_set_mcxx(skt, clk);
+ unsigned long clk = clk_get_rate(skt->clk);
+ return pxa2xx_pcmcia_set_mcxx(skt, clk / 10000);
}
#ifdef CONFIG_CPU_FREQ
@@ -205,19 +218,18 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
static void pxa2xx_configure_sockets(struct device *dev)
{
struct pcmcia_low_level *ops = dev->platform_data;
-
/*
* We have at least one socket, so set MECR:CIT
* (Card Is There)
*/
- MECR |= MECR_CIT;
+ uint32_t mecr = MECR_CIT;
/* Set MECR:NOS (Number Of Sockets) */
if ((ops->first + ops->nr) > 1 ||
machine_is_viper() || machine_is_arcom_zeus())
- MECR |= MECR_NOS;
- else
- MECR &= ~MECR_NOS;
+ mecr |= MECR_NOS;
+
+ __raw_writel(mecr, MECR);
}
static const char *skt_names[] = {
@@ -270,24 +282,41 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
struct pcmcia_low_level *ops;
struct skt_dev_info *sinfo;
struct soc_pcmcia_socket *skt;
+ struct clk *clk;
ops = (struct pcmcia_low_level *)dev->dev.platform_data;
- if (!ops)
+ if (!ops) {
+ ret = -ENODEV;
+ goto err0;
+ }
+
+ if (cpu_is_pxa320() && ops->nr > 1) {
+ dev_err(&dev->dev, "pxa320 supports only one pcmcia slot");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ clk = clk_get(&dev->dev, NULL);
+ if (!clk)
return -ENODEV;
pxa2xx_drv_pcmcia_ops(ops);
sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL);
- if (!sinfo)
+ if (!sinfo) {
+ clk_put(clk);
return -ENOMEM;
+ }
sinfo->nskt = ops->nr;
+ sinfo->clk = clk;
/* Initialize processor specific parameters */
for (i = 0; i < ops->nr; i++) {
skt = &sinfo->skt[i];
skt->nr = ops->first + i;
+ skt->clk = clk;
skt->ops = ops;
skt->socket.owner = ops->owner;
skt->socket.dev.parent = &dev->dev;
@@ -295,18 +324,26 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
ret = pxa2xx_drv_pcmcia_add_one(skt);
if (ret)
- break;
+ goto err1;
}
if (ret) {
while (--i >= 0)
soc_pcmcia_remove_one(&sinfo->skt[i]);
kfree(sinfo);
+ clk_put(clk);
} else {
pxa2xx_configure_sockets(&dev->dev);
dev_set_drvdata(&dev->dev, sinfo);
}
+ return 0;
+
+err1:
+ while (--i >= 0)
+ soc_pcmcia_remove_one(&sinfo->skt[i]);
+ kfree(sinfo);
+err0:
return ret;
}
@@ -320,6 +357,7 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
for (i = 0; i < sinfo->nskt; i++)
soc_pcmcia_remove_one(&sinfo->skt[i]);
+ clk_put(sinfo->clk);
kfree(sinfo);
return 0;
}
diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c
new file mode 100644
index 000000000000..c3f72192af66
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_colibri.c
@@ -0,0 +1,229 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_colibri.c
+ *
+ * Driver for Toradex Colibri PXA270 CF socket
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+#define COLIBRI270_RESET_GPIO 53
+#define COLIBRI270_PPEN_GPIO 107
+#define COLIBRI270_BVD1_GPIO 83
+#define COLIBRI270_BVD2_GPIO 82
+#define COLIBRI270_DETECT_GPIO 84
+#define COLIBRI270_READY_GPIO 1
+
+#define COLIBRI320_RESET_GPIO 77
+#define COLIBRI320_PPEN_GPIO 57
+#define COLIBRI320_BVD1_GPIO 53
+#define COLIBRI320_BVD2_GPIO 79
+#define COLIBRI320_DETECT_GPIO 81
+#define COLIBRI320_READY_GPIO 29
+
+static struct {
+ int reset_gpio;
+ int ppen_gpio;
+ int bvd1_gpio;
+ int bvd2_gpio;
+ int detect_gpio;
+ int ready_gpio;
+} colibri_pcmcia_gpio;
+
+static struct pcmcia_irqs colibri_irqs[] = {
+ {
+ .sock = 0,
+ .str = "PCMCIA CD"
+ },
+};
+
+static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ int ret;
+
+ ret = gpio_request(colibri_pcmcia_gpio.detect_gpio, "DETECT");
+ if (ret)
+ goto err1;
+ ret = gpio_direction_input(colibri_pcmcia_gpio.detect_gpio);
+ if (ret)
+ goto err2;
+
+ ret = gpio_request(colibri_pcmcia_gpio.ready_gpio, "READY");
+ if (ret)
+ goto err2;
+ ret = gpio_direction_input(colibri_pcmcia_gpio.ready_gpio);
+ if (ret)
+ goto err3;
+
+ ret = gpio_request(colibri_pcmcia_gpio.bvd1_gpio, "BVD1");
+ if (ret)
+ goto err3;
+ ret = gpio_direction_input(colibri_pcmcia_gpio.bvd1_gpio);
+ if (ret)
+ goto err4;
+
+ ret = gpio_request(colibri_pcmcia_gpio.bvd2_gpio, "BVD2");
+ if (ret)
+ goto err4;
+ ret = gpio_direction_input(colibri_pcmcia_gpio.bvd2_gpio);
+ if (ret)
+ goto err5;
+
+ ret = gpio_request(colibri_pcmcia_gpio.ppen_gpio, "PPEN");
+ if (ret)
+ goto err5;
+ ret = gpio_direction_output(colibri_pcmcia_gpio.ppen_gpio, 0);
+ if (ret)
+ goto err6;
+
+ ret = gpio_request(colibri_pcmcia_gpio.reset_gpio, "RESET");
+ if (ret)
+ goto err6;
+ ret = gpio_direction_output(colibri_pcmcia_gpio.reset_gpio, 1);
+ if (ret)
+ goto err7;
+
+ colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpio.detect_gpio);
+ skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpio.ready_gpio);
+
+ return soc_pcmcia_request_irqs(skt, colibri_irqs,
+ ARRAY_SIZE(colibri_irqs));
+
+err7:
+ gpio_free(colibri_pcmcia_gpio.detect_gpio);
+err6:
+ gpio_free(colibri_pcmcia_gpio.ready_gpio);
+err5:
+ gpio_free(colibri_pcmcia_gpio.bvd1_gpio);
+err4:
+ gpio_free(colibri_pcmcia_gpio.bvd2_gpio);
+err3:
+ gpio_free(colibri_pcmcia_gpio.reset_gpio);
+err2:
+ gpio_free(colibri_pcmcia_gpio.ppen_gpio);
+err1:
+ return ret;
+}
+
+static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ gpio_free(colibri_pcmcia_gpio.detect_gpio);
+ gpio_free(colibri_pcmcia_gpio.ready_gpio);
+ gpio_free(colibri_pcmcia_gpio.bvd1_gpio);
+ gpio_free(colibri_pcmcia_gpio.bvd2_gpio);
+ gpio_free(colibri_pcmcia_gpio.reset_gpio);
+ gpio_free(colibri_pcmcia_gpio.ppen_gpio);
+}
+
+static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+
+ state->detect = !!gpio_get_value(colibri_pcmcia_gpio.detect_gpio);
+ state->ready = !!gpio_get_value(colibri_pcmcia_gpio.ready_gpio);
+ state->bvd1 = !!gpio_get_value(colibri_pcmcia_gpio.bvd1_gpio);
+ state->bvd2 = !!gpio_get_value(colibri_pcmcia_gpio.bvd2_gpio);
+ state->wrprot = 0;
+ state->vs_3v = 1;
+ state->vs_Xv = 0;
+}
+
+static int
+colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ gpio_set_value(colibri_pcmcia_gpio.ppen_gpio,
+ !(state->Vcc == 33 && state->Vpp < 50));
+ gpio_set_value(colibri_pcmcia_gpio.reset_gpio, state->flags & SS_RESET);
+ return 0;
+}
+
+static void colibri_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void colibri_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+static struct pcmcia_low_level colibri_pcmcia_ops = {
+ .owner = THIS_MODULE,
+
+ .first = 0,
+ .nr = 1,
+
+ .hw_init = colibri_pcmcia_hw_init,
+ .hw_shutdown = colibri_pcmcia_hw_shutdown,
+
+ .socket_state = colibri_pcmcia_socket_state,
+ .configure_socket = colibri_pcmcia_configure_socket,
+
+ .socket_init = colibri_pcmcia_socket_init,
+ .socket_suspend = colibri_pcmcia_socket_suspend,
+};
+
+static struct platform_device *colibri_pcmcia_device;
+
+static int __init colibri_pcmcia_init(void)
+{
+ int ret;
+
+ colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+ if (!colibri_pcmcia_device)
+ return -ENOMEM;
+
+ /* Colibri PXA270 */
+ if (machine_is_colibri()) {
+ colibri_pcmcia_gpio.reset_gpio = COLIBRI270_RESET_GPIO;
+ colibri_pcmcia_gpio.ppen_gpio = COLIBRI270_PPEN_GPIO;
+ colibri_pcmcia_gpio.bvd1_gpio = COLIBRI270_BVD1_GPIO;
+ colibri_pcmcia_gpio.bvd2_gpio = COLIBRI270_BVD2_GPIO;
+ colibri_pcmcia_gpio.detect_gpio = COLIBRI270_DETECT_GPIO;
+ colibri_pcmcia_gpio.ready_gpio = COLIBRI270_READY_GPIO;
+ /* Colibri PXA320 */
+ } else if (machine_is_colibri320()) {
+ colibri_pcmcia_gpio.reset_gpio = COLIBRI320_RESET_GPIO;
+ colibri_pcmcia_gpio.ppen_gpio = COLIBRI320_PPEN_GPIO;
+ colibri_pcmcia_gpio.bvd1_gpio = COLIBRI320_BVD1_GPIO;
+ colibri_pcmcia_gpio.bvd2_gpio = COLIBRI320_BVD2_GPIO;
+ colibri_pcmcia_gpio.detect_gpio = COLIBRI320_DETECT_GPIO;
+ colibri_pcmcia_gpio.ready_gpio = COLIBRI320_READY_GPIO;
+ }
+
+ ret = platform_device_add_data(colibri_pcmcia_device,
+ &colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops));
+
+ if (!ret)
+ ret = platform_device_add(colibri_pcmcia_device);
+
+ if (ret)
+ platform_device_put(colibri_pcmcia_device);
+
+ return ret;
+}
+
+static void __exit colibri_pcmcia_exit(void)
+{
+ platform_device_unregister(colibri_pcmcia_device);
+}
+
+module_init(colibri_pcmcia_init);
+module_exit(colibri_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index 0ea3b29440e6..81af2b3bcc00 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -237,7 +237,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = {
#ifdef CONFIG_SA1100_COLLIE
#include "sa11xx_base.h"
-int __init pcmcia_collie_init(struct device *dev)
+int __devinit pcmcia_collie_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index fd013a1ef47a..f1e882272ab0 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -130,7 +130,7 @@ static struct pcmcia_low_level assabet_pcmcia_ops = {
.socket_suspend = assabet_pcmcia_socket_suspend,
};
-int pcmcia_assabet_init(struct device *dev)
+int __devinit pcmcia_assabet_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 9bf088b17275..30560df8c76b 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -97,7 +97,7 @@ static struct pcmcia_low_level cerf_pcmcia_ops = {
.socket_suspend = cerf_pcmcia_socket_suspend,
};
-int __init pcmcia_cerf_init(struct device *dev)
+int __devinit pcmcia_cerf_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index 945857f8c284..fb9740d3e9a7 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -53,6 +53,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
#if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
pcmcia_h3600_init,
#endif
+#ifdef CONFIG_SA1100_NANOENGINE
+ pcmcia_nanoengine_init,
+#endif
#ifdef CONFIG_SA1100_SHANNON
pcmcia_shannon_init,
#endif
@@ -64,7 +67,7 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
#endif
};
-static int sa11x0_drv_pcmcia_probe(struct platform_device *dev)
+static int __devinit sa11x0_drv_pcmcia_probe(struct platform_device *dev)
{
int i, ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h
index 794f96a35bba..adb08dbc723f 100644
--- a/drivers/pcmcia/sa1100_generic.h
+++ b/drivers/pcmcia/sa1100_generic.h
@@ -13,6 +13,7 @@ extern int pcmcia_freebird_init(struct device *);
extern int pcmcia_gcplus_init(struct device *);
extern int pcmcia_graphicsmaster_init(struct device *);
extern int pcmcia_h3600_init(struct device *);
+extern int pcmcia_nanoengine_init(struct device *);
extern int pcmcia_pangolin_init(struct device *);
extern int pcmcia_pfs168_init(struct device *);
extern int pcmcia_shannon_init(struct device *);
diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c
index 56329ad575a9..edf8f0028898 100644
--- a/drivers/pcmcia/sa1100_h3600.c
+++ b/drivers/pcmcia/sa1100_h3600.c
@@ -219,7 +219,7 @@ struct pcmcia_low_level h3600_pcmcia_ops = {
.socket_suspend = h3600_pcmcia_socket_suspend,
};
-int __init pcmcia_h3600_init(struct device *dev)
+int __devinit pcmcia_h3600_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c
new file mode 100644
index 000000000000..3d2652e2f5ae
--- /dev/null
+++ b/drivers/pcmcia/sa1100_nanoengine.c
@@ -0,0 +1,219 @@
+/*
+ * drivers/pcmcia/sa1100_nanoengine.c
+ *
+ * PCMCIA implementation routines for BSI nanoEngine.
+ *
+ * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine
+ * board you should carefully read this:
+ * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/
+ *
+ * Copyright (C) 2010 Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
+ *
+ * Based on original work for kernel 2.4 by
+ * Miguel Freitas <miguel@cpti.cetuc.puc-rio.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/nanoengine.h>
+
+#include "sa1100_generic.h"
+
+static struct pcmcia_irqs irqs_skt0[] = {
+ /* socket, IRQ, name */
+ { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" },
+};
+
+static struct pcmcia_irqs irqs_skt1[] = {
+ /* socket, IRQ, name */
+ { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" },
+};
+
+struct nanoengine_pins {
+ unsigned input_pins;
+ unsigned output_pins;
+ unsigned clear_outputs;
+ unsigned transition_pins;
+ unsigned pci_irq;
+ struct pcmcia_irqs *pcmcia_irqs;
+ unsigned pcmcia_irqs_size;
+};
+
+static struct nanoengine_pins nano_skts[] = {
+ {
+ .input_pins = GPIO_PC_READY0 | GPIO_PC_CD0,
+ .output_pins = GPIO_PC_RESET0,
+ .clear_outputs = GPIO_PC_RESET0,
+ .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD0,
+ .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY0,
+ .pcmcia_irqs = irqs_skt0,
+ .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt0)
+ }, {
+ .input_pins = GPIO_PC_READY1 | GPIO_PC_CD1,
+ .output_pins = GPIO_PC_RESET1,
+ .clear_outputs = GPIO_PC_RESET1,
+ .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD1,
+ .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY1,
+ .pcmcia_irqs = irqs_skt1,
+ .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt1)
+ }
+};
+
+unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts);
+
+static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return -ENXIO;
+
+ GPDR &= ~nano_skts[i].input_pins;
+ GPDR |= nano_skts[i].output_pins;
+ GPCR = nano_skts[i].clear_outputs;
+ set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH);
+ skt->socket.pci_irq = nano_skts[i].pci_irq;
+
+ return soc_pcmcia_request_irqs(skt,
+ nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+}
+
+/*
+ * Release all resources.
+ */
+static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return;
+
+ soc_pcmcia_free_irqs(skt,
+ nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+}
+
+static int nanoengine_pcmcia_configure_socket(
+ struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+ unsigned reset;
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return -ENXIO;
+
+ switch (i) {
+ case 0:
+ reset = GPIO_PC_RESET0;
+ break;
+ case 1:
+ reset = GPIO_PC_RESET1;
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ if (state->flags & SS_RESET)
+ GPSR = reset;
+ else
+ GPCR = reset;
+
+ return 0;
+}
+
+static void nanoengine_pcmcia_socket_state(
+ struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
+{
+ unsigned long levels = GPLR;
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return;
+
+ memset(state, 0, sizeof(struct pcmcia_state));
+ switch (i) {
+ case 0:
+ state->ready = (levels & GPIO_PC_READY0) ? 1 : 0;
+ state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0;
+ break;
+ case 1:
+ state->ready = (levels & GPIO_PC_READY1) ? 1 : 0;
+ state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0;
+ break;
+ default:
+ return;
+ }
+ state->bvd1 = 1;
+ state->bvd2 = 1;
+ state->wrprot = 0; /* Not available */
+ state->vs_3v = 1; /* Can only apply 3.3V */
+ state->vs_Xv = 0;
+}
+
+/*
+ * Enable card status IRQs on (re-)initialisation. This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return;
+
+ soc_pcmcia_enable_irqs(skt,
+ nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+}
+
+/*
+ * Disable card status IRQs on suspend.
+ */
+static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+ unsigned i = skt->nr;
+
+ if (i >= num_nano_pcmcia_sockets)
+ return;
+
+ soc_pcmcia_disable_irqs(skt,
+ nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+}
+
+static struct pcmcia_low_level nanoengine_pcmcia_ops = {
+ .owner = THIS_MODULE,
+
+ .hw_init = nanoengine_pcmcia_hw_init,
+ .hw_shutdown = nanoengine_pcmcia_hw_shutdown,
+
+ .configure_socket = nanoengine_pcmcia_configure_socket,
+ .socket_state = nanoengine_pcmcia_socket_state,
+ .socket_init = nanoengine_pcmcia_socket_init,
+ .socket_suspend = nanoengine_pcmcia_socket_suspend,
+};
+
+int pcmcia_nanoengine_init(struct device *dev)
+{
+ int ret = -ENODEV;
+
+ if (machine_is_nanoengine())
+ ret = sa11xx_drv_pcmcia_probe(
+ dev, &nanoengine_pcmcia_ops, 0, 2);
+
+ return ret;
+}
+
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index c4d51867a050..7ff1b43540b8 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -113,7 +113,7 @@ static struct pcmcia_low_level shannon_pcmcia_ops = {
.socket_suspend = shannon_pcmcia_socket_suspend,
};
-int __init pcmcia_shannon_init(struct device *dev)
+int __devinit pcmcia_shannon_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index 05bd504e6f18..c998f7aaadbc 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -123,7 +123,7 @@ static struct pcmcia_low_level simpad_pcmcia_ops = {
.socket_suspend = simpad_pcmcia_socket_suspend,
};
-int __init pcmcia_simpad_init(struct device *dev)
+int __devinit pcmcia_simpad_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index 689e3c02edb8..5a9a392eacdf 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -31,20 +31,20 @@
======================================================================*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
+#include <linux/cpufreq.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/timer.h>
#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/spinlock.h>
-#include <linux/cpufreq.h>
+#include <linux/timer.h>
#include <mach/hardware.h>
-#include <asm/io.h>
#include <asm/system.h>
#include "soc_common.h"
@@ -57,18 +57,25 @@ module_param(pc_debug, int, 0644);
void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
int lvl, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
if (pc_debug > lvl) {
- printk(KERN_DEBUG "skt%u: %s: ", skt->nr, func);
va_start(args, fmt);
- vprintk(fmt, args);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
+
va_end(args);
}
}
+EXPORT_SYMBOL(soc_pcmcia_debug);
#endif
-#define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket)
+#define to_soc_pcmcia_socket(x) \
+ container_of(x, struct soc_pcmcia_socket, socket)
static unsigned short
calc_speed(unsigned short *spds, int num, unsigned short dflt)
@@ -85,11 +92,15 @@ calc_speed(unsigned short *spds, int num, unsigned short dflt)
return speed;
}
-void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing)
+void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
+ struct soc_pcmcia_timing *timing)
{
- timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
- timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
- timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
+ timing->io =
+ calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
+ timing->mem =
+ calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
+ timing->attr =
+ calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
}
EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
@@ -131,8 +142,8 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
*
* Convert PCMCIA socket state to our socket configure structure.
*/
-static int
-soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state)
+static int soc_common_pcmcia_config_skt(
+ struct soc_pcmcia_socket *skt, socket_state_t *state)
{
int ret;
@@ -144,7 +155,8 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat
*/
if (skt->irq_state != 1 && state->io_irq) {
skt->irq_state = 1;
- set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING);
+ set_irq_type(skt->socket.pci_irq,
+ IRQ_TYPE_EDGE_FALLING);
} else if (skt->irq_state == 1 && state->io_irq == 0) {
skt->irq_state = 0;
set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
@@ -298,24 +310,24 @@ soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
* of power configuration, reset, &c. We also record the value of
* `state' in order to regurgitate it to the PCMCIA core later.
*/
-static int
-soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+static int soc_common_pcmcia_set_socket(
+ struct pcmcia_socket *sock, socket_state_t *state)
{
struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
- debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
- (state->csc_mask==0)?"<NONE> ":"",
- (state->csc_mask&SS_DETECT)?"DETECT ":"",
- (state->csc_mask&SS_READY)?"READY ":"",
- (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
- (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
- (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
- (state->flags==0)?"<NONE> ":"",
- (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
- (state->flags&SS_IOCARD)?"IOCARD ":"",
- (state->flags&SS_RESET)?"RESET ":"",
- (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
- (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+ debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
+ (state->csc_mask == 0) ? "<NONE> " : "",
+ (state->csc_mask & SS_DETECT) ? "DETECT " : "",
+ (state->csc_mask & SS_READY) ? "READY " : "",
+ (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
+ (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
+ (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
+ (state->flags == 0) ? "<NONE> " : "",
+ (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
+ (state->flags & SS_IOCARD) ? "IOCARD " : "",
+ (state->flags & SS_RESET) ? "RESET " : "",
+ (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
+ (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
state->Vcc, state->Vpp, state->io_irq);
return soc_common_pcmcia_config_skt(skt, state);
@@ -330,8 +342,8 @@ soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
*
* Returns: 0 on success, -1 on error
*/
-static int
-soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
+static int soc_common_pcmcia_set_io_map(
+ struct pcmcia_socket *sock, struct pccard_io_map *map)
{
struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
unsigned short speed = map->speed;
@@ -340,14 +352,14 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
map->map, map->speed, (unsigned long long)map->start,
(unsigned long long)map->stop);
debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
- (map->flags==0)?"<NONE>":"",
- (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
- (map->flags&MAP_16BIT)?"16BIT ":"",
- (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
- (map->flags&MAP_0WS)?"0WS ":"",
- (map->flags&MAP_WRPROT)?"WRPROT ":"",
- (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
- (map->flags&MAP_PREFETCH)?"PREFETCH ":"");
+ (map->flags == 0) ? "<NONE>" : "",
+ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+ (map->flags & MAP_16BIT) ? "16BIT " : "",
+ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+ (map->flags & MAP_0WS) ? "0WS " : "",
+ (map->flags & MAP_WRPROT) ? "WRPROT " : "",
+ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
+ (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
if (map->map >= MAX_IO_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
@@ -384,8 +396,8 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
*
* Returns: 0 on success, -ERRNO on error
*/
-static int
-soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
+static int soc_common_pcmcia_set_mem_map(
+ struct pcmcia_socket *sock, struct pccard_mem_map *map)
{
struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
struct resource *res;
@@ -394,14 +406,14 @@ soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
debug(skt, 2, "map %u speed %u card_start %08x\n",
map->map, map->speed, map->card_start);
debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
- (map->flags==0)?"<NONE>":"",
- (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
- (map->flags&MAP_16BIT)?"16BIT ":"",
- (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
- (map->flags&MAP_0WS)?"0WS ":"",
- (map->flags&MAP_WRPROT)?"WRPROT ":"",
- (map->flags&MAP_ATTRIB)?"ATTRIB ":"",
- (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
+ (map->flags == 0) ? "<NONE>" : "",
+ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+ (map->flags & MAP_16BIT) ? "16BIT " : "",
+ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+ (map->flags & MAP_0WS) ? "0WS " : "",
+ (map->flags & MAP_WRPROT) ? "WRPROT " : "",
+ (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
+ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
if (map->map >= MAX_WIN)
return -EINVAL;
@@ -456,8 +468,8 @@ static struct bittbl conf_bits[] = {
{ SS_OUTPUT_ENA, "SS_OUTPUT_ENA" },
};
-static void
-dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz)
+static void dump_bits(char **p, const char *prefix,
+ unsigned int val, struct bittbl *bits, int sz)
{
char *b = *p;
int i;
@@ -475,13 +487,14 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
*
* Returns: the number of characters added to the buffer
*/
-static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_status(
+ struct device *dev, struct device_attribute *attr, char *buf)
{
struct soc_pcmcia_socket *skt =
container_of(dev, struct soc_pcmcia_socket, socket.dev);
char *p = buf;
- p+=sprintf(p, "slot : %d\n", skt->nr);
+ p += sprintf(p, "slot : %d\n", skt->nr);
dump_bits(&p, "status", skt->status,
status_bits, ARRAY_SIZE(status_bits));
@@ -490,12 +503,12 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch
dump_bits(&p, "cs_flags", skt->cs_state.flags,
conf_bits, ARRAY_SIZE(conf_bits));
- p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
- p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
- p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
+ p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
+ p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
+ p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
skt->socket.pci_irq);
if (skt->ops->show_timing)
- p+=skt->ops->show_timing(skt, p);
+ p += skt->ops->show_timing(skt, p);
return p-buf;
}
@@ -588,7 +601,7 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
mutex_lock(&soc_pcmcia_sockets_lock);
list_for_each_entry(skt, &soc_pcmcia_sockets, node)
- if ( skt->ops->frequency_change )
+ if (skt->ops->frequency_change)
ret += skt->ops->frequency_change(skt, val, freqs);
mutex_unlock(&soc_pcmcia_sockets_lock);
@@ -614,7 +627,8 @@ fs_initcall(soc_pcmcia_cpufreq_register);
static void soc_pcmcia_cpufreq_unregister(void)
{
- cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+ cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
}
module_exit(soc_pcmcia_cpufreq_unregister);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index bbcd5385a221..9daa73615c8b 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -10,6 +10,7 @@
#define _ASM_ARCH_PCMCIA
/* include the world */
+#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
@@ -29,6 +30,7 @@ struct soc_pcmcia_socket {
* Info from low level handler
*/
unsigned int nr;
+ struct clk *clk;
/*
* Core PCMCIA state
@@ -56,6 +58,7 @@ struct soc_pcmcia_socket {
struct skt_dev_info {
int nskt;
+ struct clk *clk;
struct soc_pcmcia_socket skt[0];
};
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index faec777b1ed4..d163bc2e2b9e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -18,12 +18,14 @@ if X86_PLATFORM_DEVICES
config ACER_WMI
tristate "Acer WMI Laptop Extras"
depends on ACPI
- depends on LEDS_CLASS
- depends on NEW_LEDS
+ select LEDS_CLASS
+ select NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
+ depends on INPUT
depends on RFKILL || RFKILL = n
- select ACPI_WMI
+ depends on ACPI_WMI
+ select INPUT_SPARSEKMAP
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
wireless radio and bluetooth control, and on some laptops,
@@ -131,7 +133,7 @@ config TC1100_WMI
depends on !X86_64
depends on EXPERIMENTAL
depends on ACPI
- select ACPI_WMI
+ depends on ACPI_WMI
---help---
This is a driver for the WMI extensions (wireless and bluetooth power
control) of the HP Compaq TC1100 tablet.
@@ -226,6 +228,7 @@ config IDEAPAD_LAPTOP
tristate "Lenovo IdeaPad Laptop Extras"
depends on ACPI
depends on RFKILL
+ select INPUT_SPARSEKMAP
help
This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
@@ -425,7 +428,10 @@ config EEEPC_WMI
depends on INPUT
depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
+ select LEDS_CLASS
+ select NEW_LEDS
---help---
Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
@@ -510,8 +516,8 @@ config TOPSTAR_LAPTOP
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on ACPI
- depends on LEDS_CLASS
- depends on NEW_LEDS
+ select LEDS_CLASS
+ select NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on INPUT
depends on RFKILL || RFKILL = n
@@ -576,6 +582,15 @@ config INTEL_SCU_IPC
some embedded Intel x86 platforms. This is not needed for PC-type
machines.
+config INTEL_SCU_IPC_UTIL
+ tristate "Intel SCU IPC utility driver"
+ depends on INTEL_SCU_IPC
+ default y
+ ---help---
+ The IPC Util driver provides an interface with the SCU enabling
+ low level access for debug work and updating the firmware. Say
+ N unless you will be doing this on an Intel MID platform.
+
config GPIO_INTEL_PMIC
bool "Intel PMIC GPIO support"
depends on INTEL_SCU_IPC && GPIOLIB
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 9950ccc940b5..4ec4ff8f9182 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
+obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c8c65375bfe2..c5c4b8c32eb8 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,9 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/dmi.h>
#include <acpi/acpi_drivers.h>
@@ -48,6 +51,7 @@ MODULE_LICENSE("GPL");
#define ACER_ERR KERN_ERR ACER_LOGPREFIX
#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
+#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
/*
* Magic Number
@@ -82,9 +86,82 @@ MODULE_LICENSE("GPL");
#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
+#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
+
+/*
+ * Acer ACPI event GUIDs
+ */
+#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
+MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
+
+enum acer_wmi_event_ids {
+ WMID_HOTKEY_EVENT = 0x1,
+};
+
+static const struct key_entry acer_wmi_keymap[] = {
+ {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
+ {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
+ {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
+ {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
+ {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
+ {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
+ {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
+ {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */
+ {KE_END, 0}
+};
+
+static struct input_dev *acer_wmi_input_dev;
+
+struct event_return_value {
+ u8 function;
+ u8 key_num;
+ u16 device_state;
+ u32 reserved;
+} __attribute__((packed));
+
+/*
+ * GUID3 Get Device Status device flags
+ */
+#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */
+#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
+#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
+
+struct lm_input_params {
+ u8 function_num; /* Function Number */
+ u16 commun_devices; /* Communication type devices default status */
+ u16 devices; /* Other type devices default status */
+ u8 lm_status; /* Launch Manager Status */
+ u16 reserved;
+} __attribute__((packed));
+
+struct lm_return_value {
+ u8 error_code; /* Error Code */
+ u8 ec_return_value; /* EC Return Value */
+ u16 reserved;
+} __attribute__((packed));
+
+struct wmid3_gds_input_param { /* Get Device Status input parameter */
+ u8 function_num; /* Function Number */
+ u8 hotkey_number; /* Hotkey Number */
+ u16 devices; /* Get Device */
+} __attribute__((packed));
+
+struct wmid3_gds_return_value { /* Get Device Status return value*/
+ u8 error_code; /* Error Code */
+ u8 ec_return_value; /* EC Return Value */
+ u16 devices; /* Current Device Status */
+ u32 reserved;
+} __attribute__((packed));
+
+struct hotkey_function_type_aa {
+ u8 type;
+ u8 length;
+ u16 handle;
+ u16 commun_func_bitmap;
+} __attribute__((packed));
/*
* Interface capability flags
@@ -116,15 +193,19 @@ static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
+static bool ec_raw_mode;
+static bool has_type_aa;
module_param(mailled, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
+module_param(ec_raw_mode, bool, 0444);
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
struct acer_data {
int mailled;
@@ -140,6 +221,7 @@ struct acer_debug {
static struct rfkill *wireless_rfkill;
static struct rfkill *bluetooth_rfkill;
+static struct rfkill *threeg_rfkill;
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
@@ -753,6 +835,28 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
return WMI_execute_u32(method_id, (u32)value, NULL);
}
+static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
+{
+ struct hotkey_function_type_aa *type_aa;
+
+ /* We are looking for OEM-specific Type AAh */
+ if (header->type != 0xAA)
+ return;
+
+ has_type_aa = true;
+ type_aa = (struct hotkey_function_type_aa *) header;
+
+ printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n",
+ type_aa->commun_func_bitmap);
+
+ if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
+ interface->capability |= ACER_CAP_WIRELESS;
+ if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
+ interface->capability |= ACER_CAP_THREEG;
+ if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
+ interface->capability |= ACER_CAP_BLUETOOTH;
+}
+
static acpi_status WMID_set_capabilities(void)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -773,16 +877,17 @@ static acpi_status WMID_set_capabilities(void)
return AE_ERROR;
}
- /* Not sure on the meaning of the relevant bits yet to detect these */
- interface->capability |= ACER_CAP_WIRELESS;
- interface->capability |= ACER_CAP_THREEG;
+ dmi_walk(type_aa_dmi_decode, NULL);
+ if (!has_type_aa) {
+ interface->capability |= ACER_CAP_WIRELESS;
+ interface->capability |= ACER_CAP_THREEG;
+ if (devices & 0x10)
+ interface->capability |= ACER_CAP_BLUETOOTH;
+ }
/* WMID always provides brightness methods */
interface->capability |= ACER_CAP_BRIGHTNESS;
- if (devices & 0x10)
- interface->capability |= ACER_CAP_BLUETOOTH;
-
if (!(devices & 0x20))
max_brightness = 0x9;
@@ -861,7 +966,8 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface
*/
set_u32(mailled, ACER_CAP_MAILLED);
- set_u32(threeg, ACER_CAP_THREEG);
+ if (!has_type_aa)
+ set_u32(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS);
}
@@ -915,7 +1021,7 @@ static int update_bl_status(struct backlight_device *bd)
return 0;
}
-static struct backlight_ops acer_bl_ops = {
+static const struct backlight_ops acer_bl_ops = {
.get_brightness = read_brightness,
.update_status = update_bl_status,
};
@@ -948,6 +1054,79 @@ static void acer_backlight_exit(void)
backlight_device_unregister(acer_backlight_device);
}
+static acpi_status wmid3_get_device_status(u32 *value, u16 device)
+{
+ struct wmid3_gds_return_value return_value;
+ acpi_status status;
+ union acpi_object *obj;
+ struct wmid3_gds_input_param params = {
+ .function_num = 0x1,
+ .hotkey_number = 0x01,
+ .devices = device,
+ };
+ struct acpi_buffer input = {
+ sizeof(struct wmid3_gds_input_param),
+ &params
+ };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = output.pointer;
+
+ if (!obj)
+ return AE_ERROR;
+ else if (obj->type != ACPI_TYPE_BUFFER) {
+ kfree(obj);
+ return AE_ERROR;
+ }
+ if (obj->buffer.length != 8) {
+ printk(ACER_WARNING "Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return AE_ERROR;
+ }
+
+ return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+ kfree(obj);
+
+ if (return_value.error_code || return_value.ec_return_value)
+ printk(ACER_WARNING "Get Device Status failed: "
+ "0x%x - 0x%x\n", return_value.error_code,
+ return_value.ec_return_value);
+ else
+ *value = !!(return_value.devices & device);
+
+ return status;
+}
+
+static acpi_status get_device_status(u32 *value, u32 cap)
+{
+ if (wmi_has_guid(WMID_GUID3)) {
+ u16 device;
+
+ switch (cap) {
+ case ACER_CAP_WIRELESS:
+ device = ACER_WMID3_GDS_WIRELESS;
+ break;
+ case ACER_CAP_BLUETOOTH:
+ device = ACER_WMID3_GDS_BLUETOOTH;
+ break;
+ case ACER_CAP_THREEG:
+ device = ACER_WMID3_GDS_THREEG;
+ break;
+ default:
+ return AE_ERROR;
+ }
+ return wmid3_get_device_status(value, device);
+
+ } else {
+ return get_u32(value, cap);
+ }
+}
+
/*
* Rfkill devices
*/
@@ -968,6 +1147,13 @@ static void acer_rfkill_update(struct work_struct *ignored)
rfkill_set_sw_state(bluetooth_rfkill, !state);
}
+ if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
+ status = wmid3_get_device_status(&state,
+ ACER_WMID3_GDS_THREEG);
+ if (ACPI_SUCCESS(status))
+ rfkill_set_sw_state(threeg_rfkill, !state);
+ }
+
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
}
@@ -991,6 +1177,8 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
{
int err;
struct rfkill *rfkill_dev;
+ u32 state;
+ acpi_status status;
rfkill_dev = rfkill_alloc(name, dev, type,
&acer_rfkill_ops,
@@ -998,6 +1186,10 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
if (!rfkill_dev)
return ERR_PTR(-ENOMEM);
+ status = get_device_status(&state, cap);
+ if (ACPI_SUCCESS(status))
+ rfkill_init_sw_state(rfkill_dev, !state);
+
err = rfkill_register(rfkill_dev);
if (err) {
rfkill_destroy(rfkill_dev);
@@ -1024,6 +1216,19 @@ static int acer_rfkill_init(struct device *dev)
}
}
+ if (has_cap(ACER_CAP_THREEG)) {
+ threeg_rfkill = acer_rfkill_register(dev,
+ RFKILL_TYPE_WWAN, "acer-threeg",
+ ACER_CAP_THREEG);
+ if (IS_ERR(threeg_rfkill)) {
+ rfkill_unregister(wireless_rfkill);
+ rfkill_destroy(wireless_rfkill);
+ rfkill_unregister(bluetooth_rfkill);
+ rfkill_destroy(bluetooth_rfkill);
+ return PTR_ERR(threeg_rfkill);
+ }
+ }
+
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
return 0;
@@ -1040,6 +1245,11 @@ static void acer_rfkill_exit(void)
rfkill_unregister(bluetooth_rfkill);
rfkill_destroy(bluetooth_rfkill);
}
+
+ if (has_cap(ACER_CAP_THREEG)) {
+ rfkill_unregister(threeg_rfkill);
+ rfkill_destroy(threeg_rfkill);
+ }
return;
}
@@ -1050,7 +1260,12 @@ static ssize_t show_bool_threeg(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 result; \
- acpi_status status = get_u32(&result, ACER_CAP_THREEG);
+ acpi_status status;
+ if (wmi_has_guid(WMID_GUID3))
+ status = wmid3_get_device_status(&result,
+ ACER_WMID3_GDS_THREEG);
+ else
+ status = get_u32(&result, ACER_CAP_THREEG);
if (ACPI_SUCCESS(status))
return sprintf(buf, "%u\n", result);
return sprintf(buf, "Read error\n");
@@ -1085,6 +1300,178 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
+static void acer_wmi_notify(u32 value, void *context)
+{
+ struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct event_return_value return_value;
+ acpi_status status;
+
+ status = wmi_get_event_data(value, &response);
+ if (status != AE_OK) {
+ printk(ACER_WARNING "bad event status 0x%x\n", status);
+ return;
+ }
+
+ obj = (union acpi_object *)response.pointer;
+
+ if (!obj)
+ return;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ printk(ACER_WARNING "Unknown response received %d\n",
+ obj->type);
+ kfree(obj);
+ return;
+ }
+ if (obj->buffer.length != 8) {
+ printk(ACER_WARNING "Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return;
+ }
+
+ return_value = *((struct event_return_value *)obj->buffer.pointer);
+ kfree(obj);
+
+ switch (return_value.function) {
+ case WMID_HOTKEY_EVENT:
+ if (!sparse_keymap_report_event(acer_wmi_input_dev,
+ return_value.key_num, 1, true))
+ printk(ACER_WARNING "Unknown key number - 0x%x\n",
+ return_value.key_num);
+ break;
+ default:
+ printk(ACER_WARNING "Unknown function number - %d - %d\n",
+ return_value.function, return_value.key_num);
+ break;
+ }
+}
+
+static acpi_status
+wmid3_set_lm_mode(struct lm_input_params *params,
+ struct lm_return_value *return_value)
+{
+ acpi_status status;
+ union acpi_object *obj;
+
+ struct acpi_buffer input = { sizeof(struct lm_input_params), params };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = output.pointer;
+
+ if (!obj)
+ return AE_ERROR;
+ else if (obj->type != ACPI_TYPE_BUFFER) {
+ kfree(obj);
+ return AE_ERROR;
+ }
+ if (obj->buffer.length != 4) {
+ printk(ACER_WARNING "Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return AE_ERROR;
+ }
+
+ *return_value = *((struct lm_return_value *)obj->buffer.pointer);
+ kfree(obj);
+
+ return status;
+}
+
+static int acer_wmi_enable_ec_raw(void)
+{
+ struct lm_return_value return_value;
+ acpi_status status;
+ struct lm_input_params params = {
+ .function_num = 0x1,
+ .commun_devices = 0xFFFF,
+ .devices = 0xFFFF,
+ .lm_status = 0x00, /* Launch Manager Deactive */
+ };
+
+ status = wmid3_set_lm_mode(&params, &return_value);
+
+ if (return_value.error_code || return_value.ec_return_value)
+ printk(ACER_WARNING "Enabling EC raw mode failed: "
+ "0x%x - 0x%x\n", return_value.error_code,
+ return_value.ec_return_value);
+ else
+ printk(ACER_INFO "Enabled EC raw mode");
+
+ return status;
+}
+
+static int acer_wmi_enable_lm(void)
+{
+ struct lm_return_value return_value;
+ acpi_status status;
+ struct lm_input_params params = {
+ .function_num = 0x1,
+ .commun_devices = 0xFFFF,
+ .devices = 0xFFFF,
+ .lm_status = 0x01, /* Launch Manager Active */
+ };
+
+ status = wmid3_set_lm_mode(&params, &return_value);
+
+ if (return_value.error_code || return_value.ec_return_value)
+ printk(ACER_WARNING "Enabling Launch Manager failed: "
+ "0x%x - 0x%x\n", return_value.error_code,
+ return_value.ec_return_value);
+
+ return status;
+}
+
+static int __init acer_wmi_input_setup(void)
+{
+ acpi_status status;
+ int err;
+
+ acer_wmi_input_dev = input_allocate_device();
+ if (!acer_wmi_input_dev)
+ return -ENOMEM;
+
+ acer_wmi_input_dev->name = "Acer WMI hotkeys";
+ acer_wmi_input_dev->phys = "wmi/input0";
+ acer_wmi_input_dev->id.bustype = BUS_HOST;
+
+ err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
+ if (err)
+ goto err_free_dev;
+
+ status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
+ acer_wmi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ err = -EIO;
+ goto err_free_keymap;
+ }
+
+ err = input_register_device(acer_wmi_input_dev);
+ if (err)
+ goto err_uninstall_notifier;
+
+ return 0;
+
+err_uninstall_notifier:
+ wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
+err_free_keymap:
+ sparse_keymap_free(acer_wmi_input_dev);
+err_free_dev:
+ input_free_device(acer_wmi_input_dev);
+ return err;
+}
+
+static void acer_wmi_input_destroy(void)
+{
+ wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
+ sparse_keymap_free(acer_wmi_input_dev);
+ input_unregister_device(acer_wmi_input_dev);
+}
+
/*
* debugfs functions
*/
@@ -1327,6 +1714,26 @@ static int __init acer_wmi_init(void)
"generic video driver\n");
}
+ if (wmi_has_guid(WMID_GUID3)) {
+ if (ec_raw_mode) {
+ if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
+ printk(ACER_ERR "Cannot enable EC raw mode\n");
+ return -ENODEV;
+ }
+ } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
+ printk(ACER_ERR "Cannot enable Launch Manager mode\n");
+ return -ENODEV;
+ }
+ } else if (ec_raw_mode) {
+ printk(ACER_INFO "No WMID EC raw mode enable method\n");
+ }
+
+ if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
+ err = acer_wmi_input_setup();
+ if (err)
+ return err;
+ }
+
err = platform_driver_register(&acer_platform_driver);
if (err) {
printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1775,17 @@ error_device_add:
error_device_alloc:
platform_driver_unregister(&acer_platform_driver);
error_platform_register:
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
+ acer_wmi_input_destroy();
+
return err;
}
static void __exit acer_wmi_exit(void)
{
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
+ acer_wmi_input_destroy();
+
remove_sysfs(acer_platform_device);
remove_debugfs();
platform_device_unregister(acer_platform_device);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 60a5a5c6b50a..f3aa6a7fdab6 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -81,6 +81,8 @@ MODULE_PARM_DESC(wapf, "WAPF value");
static int wlan_status = 1;
static int bluetooth_status = 1;
+static int wimax_status = -1;
+static int wwan_status = -1;
module_param(wlan_status, int, 0444);
MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
@@ -92,6 +94,16 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1");
+module_param(wimax_status, int, 0444);
+MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
+module_param(wwan_status, int, 0444);
+MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
/*
* Some events we use, same for all Asus
*/
@@ -114,6 +126,8 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
*/
#define WL_RSTS 0x01 /* internal Wifi */
#define BT_RSTS 0x02 /* internal Bluetooth */
+#define WM_RSTS 0x08 /* internal wimax */
+#define WW_RSTS 0x20 /* internal wwan */
/* LED */
#define METHOD_MLED "MLED"
@@ -132,6 +146,11 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
*/
#define METHOD_WLAN "WLED"
#define METHOD_BLUETOOTH "BLED"
+
+/* WWAN and WIMAX */
+#define METHOD_WWAN "GSMC"
+#define METHOD_WIMAX "WMXC"
+
#define METHOD_WL_STATUS "RSTS"
/* Brightness */
@@ -621,7 +640,7 @@ static int update_bl_status(struct backlight_device *bd)
return asus_lcd_set(asus, value);
}
-static struct backlight_ops asusbl_ops = {
+static const struct backlight_ops asusbl_ops = {
.get_brightness = asus_read_brightness,
.update_status = update_bl_status,
};
@@ -883,6 +902,64 @@ static ssize_t store_bluetooth(struct device *dev,
}
/*
+ * Wimax
+ */
+static int asus_wimax_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
+ pr_warning("Error setting wimax status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
+static ssize_t show_wimax(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
+}
+
+static ssize_t store_wimax(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
+}
+
+/*
+ * Wwan
+ */
+static int asus_wwan_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
+ pr_warning("Error setting wwan status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
+static ssize_t show_wwan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
+}
+
+static ssize_t store_wwan(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
+}
+
+/*
* Display
*/
static void asus_set_display(struct asus_laptop *asus, int value)
@@ -1202,6 +1279,8 @@ static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
show_bluetooth, store_bluetooth);
+static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
+static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
@@ -1212,6 +1291,8 @@ static struct attribute *asus_attributes[] = {
&dev_attr_infos.attr,
&dev_attr_wlan.attr,
&dev_attr_bluetooth.attr,
+ &dev_attr_wimax.attr,
+ &dev_attr_wwan.attr,
&dev_attr_display.attr,
&dev_attr_ledd.attr,
&dev_attr_ls_level.attr,
@@ -1239,6 +1320,13 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
} else if (attr == &dev_attr_display.attr) {
supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
+ } else if (attr == &dev_attr_wimax.attr) {
+ supported =
+ !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL);
+
+ } else if (attr == &dev_attr_wwan.attr) {
+ supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL);
+
} else if (attr == &dev_attr_ledd.attr) {
supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
@@ -1397,7 +1485,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
/*
* The HWRS method return informations about the hardware.
- * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth,
+ * 0x40 for WWAN, 0x10 for WIMAX.
* The significance of others is yet to be found.
*/
status =
@@ -1440,6 +1529,12 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
if (wlan_status >= 0)
asus_wlan_set(asus, !!wlan_status);
+ if (wimax_status >= 0)
+ asus_wimax_set(asus, !!wimax_status);
+
+ if (wwan_status >= 0)
+ asus_wwan_set(asus, !!wwan_status);
+
/* Keyboard Backlight is on by default */
if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
asus_kled_set(asus, 1);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index ca05aefd03bf..4633fd8532cc 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1467,7 +1467,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
return 0;
}
-static struct backlight_ops asus_backlight_data = {
+static const struct backlight_ops asus_backlight_data = {
.get_brightness = read_brightness,
.update_status = set_brightness_status,
};
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 341cbfef93ee..911135425224 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -522,18 +522,20 @@ static int cmpc_rfkill_block(void *data, bool blocked)
acpi_status status;
acpi_handle handle;
unsigned long long state;
+ bool is_blocked;
handle = data;
status = cmpc_get_rfkill_wlan(handle, &state);
if (ACPI_FAILURE(status))
return -ENODEV;
- if (blocked)
- state &= ~1;
- else
- state |= 1;
- status = cmpc_set_rfkill_wlan(handle, state);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ /* Check if we really need to call cmpc_set_rfkill_wlan */
+ is_blocked = state & 1 ? false : true;
+ if (is_blocked != blocked) {
+ state = blocked ? 0 : 1;
+ status = cmpc_set_rfkill_wlan(handle, state);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ }
return 0;
}
@@ -653,8 +655,9 @@ static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
code = cmpc_keys_codes[event & 0x0F];
- inputdev = dev_get_drvdata(&dev->dev);;
+ inputdev = dev_get_drvdata(&dev->dev);
input_report_key(inputdev, code, !(event & 0x10));
+ input_sync(inputdev);
}
static void cmpc_keys_idev_init(struct input_dev *inputdev)
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 097083cac413..034572b980c9 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -872,6 +872,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
},
.callback = dmi_check_cb_extra
},
+ {
+ .ident = "KHLB2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
+ DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
+ },
+ .callback = dmi_check_cb_extra
+ },
{ }
};
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index cf8a89a0d8f5..34657f96b5a5 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -546,7 +546,7 @@ out:
return buffer->output[1];
}
-static struct backlight_ops dell_ops = {
+static const struct backlight_ops dell_ops = {
.get_brightness = dell_get_intensity,
.update_status = dell_send_intensity,
};
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index b2edfdcdcb84..49d9ad708f89 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -529,6 +529,15 @@ static void tpd_led_set(struct led_classdev *led_cdev,
queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
}
+static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
+{
+ struct eeepc_laptop *eeepc;
+
+ eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
+
+ return get_acpi(eeepc, CM_ASL_TPD);
+}
+
static int eeepc_led_init(struct eeepc_laptop *eeepc)
{
int rv;
@@ -543,6 +552,8 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc)
eeepc->tpd_led.name = "eeepc::touchpad";
eeepc->tpd_led.brightness_set = tpd_led_set;
+ if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
+ eeepc->tpd_led.brightness_get = tpd_led_get;
eeepc->tpd_led.max_brightness = 1;
rv = led_classdev_register(&eeepc->platform_device->dev,
@@ -1115,7 +1126,7 @@ static int update_bl_status(struct backlight_device *bd)
return set_brightness(bd, bd->props.brightness);
}
-static struct backlight_ops eeepcbl_ops = {
+static const struct backlight_ops eeepcbl_ops = {
.get_brightness = read_brightness,
.update_status = update_bl_status,
};
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 462ceab93f87..4d38f98aa976 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -2,6 +2,7 @@
* Eee PC WMI hotkey driver
*
* Copyright(C) 2010 Intel Corporation.
+ * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
*
* Portions based on wistron_btns.c:
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -34,6 +35,10 @@
#include <linux/input/sparse-keymap.h>
#include <linux/fb.h>
#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/rfkill.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -44,6 +49,8 @@ MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
MODULE_LICENSE("GPL");
+#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
+
#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
@@ -60,6 +67,10 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
#define EEEPC_WMI_METHODID_CFVS 0x53564643
#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
+#define EEEPC_WMI_DEVID_TPDLED 0x00100011
+#define EEEPC_WMI_DEVID_WLAN 0x00010011
+#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013
+#define EEEPC_WMI_DEVID_WWAN3G 0x00010019
static const struct key_entry eeepc_wmi_keymap[] = {
/* Sleep already handled via generic ACPI code */
@@ -83,11 +94,37 @@ struct bios_args {
u32 ctrl_param;
};
+/*
+ * eeepc-wmi/ - debugfs root directory
+ * dev_id - current dev_id
+ * ctrl_param - current ctrl_param
+ * devs - call DEVS(dev_id, ctrl_param) and print result
+ * dsts - call DSTS(dev_id) and print result
+ */
+struct eeepc_wmi_debug {
+ struct dentry *root;
+ u32 dev_id;
+ u32 ctrl_param;
+};
+
struct eeepc_wmi {
struct input_dev *inputdev;
struct backlight_device *backlight_device;
+ struct platform_device *platform_device;
+
+ struct led_classdev tpd_led;
+ int tpd_led_wk;
+ struct workqueue_struct *led_workqueue;
+ struct work_struct tpd_led_work;
+
+ struct rfkill *wlan_rfkill;
+ struct rfkill *bluetooth_rfkill;
+ struct rfkill *wwan3g_rfkill;
+
+ struct eeepc_wmi_debug debug;
};
+/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
static struct platform_device *platform_device;
static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
@@ -101,7 +138,7 @@ static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
eeepc->inputdev->name = "Eee PC WMI hotkeys";
eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
eeepc->inputdev->id.bustype = BUS_HOST;
- eeepc->inputdev->dev.parent = &platform_device->dev;
+ eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
if (err)
@@ -130,7 +167,7 @@ static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
eeepc->inputdev = NULL;
}
-static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
+static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
{
struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -150,8 +187,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
else
tmp = 0;
- if (ctrl_param)
- *ctrl_param = tmp;
+ if (retval)
+ *retval = tmp;
kfree(obj);
@@ -159,7 +196,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
}
-static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
+static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
+ u32 *retval)
{
struct bios_args args = {
.dev_id = dev_id,
@@ -168,34 +206,281 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
acpi_status status;
- status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
- 1, EEEPC_WMI_METHODID_DEVS, &input, NULL);
+ if (!retval) {
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
+ EEEPC_WMI_METHODID_DEVS,
+ &input, NULL);
+ } else {
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ u32 tmp;
+
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
+ EEEPC_WMI_METHODID_DEVS,
+ &input, &output);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = (union acpi_object *)output.pointer;
+ if (obj && obj->type == ACPI_TYPE_INTEGER)
+ tmp = (u32)obj->integer.value;
+ else
+ tmp = 0;
+
+ *retval = tmp;
+
+ kfree(obj);
+ }
return status;
}
+/*
+ * LEDs
+ */
+/*
+ * These functions actually update the LED's, and are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a
+ * potentially bad time, such as a timer interrupt.
+ */
+static void tpd_led_update(struct work_struct *work)
+{
+ int ctrl_param;
+ struct eeepc_wmi *eeepc;
+
+ eeepc = container_of(work, struct eeepc_wmi, tpd_led_work);
+
+ ctrl_param = eeepc->tpd_led_wk;
+ eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL);
+}
+
+static void tpd_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct eeepc_wmi *eeepc;
+
+ eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
+
+ eeepc->tpd_led_wk = !!value;
+ queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
+}
+
+static int read_tpd_state(struct eeepc_wmi *eeepc)
+{
+ u32 retval;
+ acpi_status status;
+
+ status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval);
+
+ if (ACPI_FAILURE(status))
+ return -1;
+ else if (!retval || retval == 0x00060000)
+ /*
+ * if touchpad led is present, DSTS will set some bits,
+ * usually 0x00020000.
+ * 0x00060000 means that the device is not supported
+ */
+ return -ENODEV;
+ else
+ /* Status is stored in the first bit */
+ return retval & 0x1;
+}
+
+static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
+{
+ struct eeepc_wmi *eeepc;
+
+ eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
+
+ return read_tpd_state(eeepc);
+}
+
+static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc)
+{
+ int rv;
+
+ if (read_tpd_state(eeepc) < 0)
+ return 0;
+
+ eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!eeepc->led_workqueue)
+ return -ENOMEM;
+ INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
+
+ eeepc->tpd_led.name = "eeepc::touchpad";
+ eeepc->tpd_led.brightness_set = tpd_led_set;
+ eeepc->tpd_led.brightness_get = tpd_led_get;
+ eeepc->tpd_led.max_brightness = 1;
+
+ rv = led_classdev_register(&eeepc->platform_device->dev,
+ &eeepc->tpd_led);
+ if (rv) {
+ destroy_workqueue(eeepc->led_workqueue);
+ return rv;
+ }
+
+ return 0;
+}
+
+static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
+{
+ if (eeepc->tpd_led.dev)
+ led_classdev_unregister(&eeepc->tpd_led);
+ if (eeepc->led_workqueue)
+ destroy_workqueue(eeepc->led_workqueue);
+}
+
+/*
+ * Rfkill devices
+ */
+static int eeepc_rfkill_set(void *data, bool blocked)
+{
+ int dev_id = (unsigned long)data;
+ u32 ctrl_param = !blocked;
+
+ return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL);
+}
+
+static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
+{
+ int dev_id = (unsigned long)data;
+ u32 retval;
+ acpi_status status;
+
+ status = eeepc_wmi_get_devstate(dev_id, &retval);
+
+ if (ACPI_FAILURE(status))
+ return ;
+
+ rfkill_set_sw_state(rfkill, !(retval & 0x1));
+}
+
+static const struct rfkill_ops eeepc_rfkill_ops = {
+ .set_block = eeepc_rfkill_set,
+ .query = eeepc_rfkill_query,
+};
+
+static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
+ struct rfkill **rfkill,
+ const char *name,
+ enum rfkill_type type, int dev_id)
+{
+ int result;
+ u32 retval;
+ acpi_status status;
+
+ status = eeepc_wmi_get_devstate(dev_id, &retval);
+
+ if (ACPI_FAILURE(status))
+ return -1;
+
+ /* If the device is present, DSTS will always set some bits
+ * 0x00070000 - 1110000000000000000 - device supported
+ * 0x00060000 - 1100000000000000000 - not supported
+ * 0x00020000 - 0100000000000000000 - device supported
+ * 0x00010000 - 0010000000000000000 - not supported / special mode ?
+ */
+ if (!retval || retval == 0x00060000)
+ return -ENODEV;
+
+ *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
+ &eeepc_rfkill_ops, (void *)(long)dev_id);
+
+ if (!*rfkill)
+ return -EINVAL;
+
+ rfkill_init_sw_state(*rfkill, !(retval & 0x1));
+ result = rfkill_register(*rfkill);
+ if (result) {
+ rfkill_destroy(*rfkill);
+ *rfkill = NULL;
+ return result;
+ }
+ return 0;
+}
+
+static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
+{
+ if (eeepc->wlan_rfkill) {
+ rfkill_unregister(eeepc->wlan_rfkill);
+ rfkill_destroy(eeepc->wlan_rfkill);
+ eeepc->wlan_rfkill = NULL;
+ }
+ if (eeepc->bluetooth_rfkill) {
+ rfkill_unregister(eeepc->bluetooth_rfkill);
+ rfkill_destroy(eeepc->bluetooth_rfkill);
+ eeepc->bluetooth_rfkill = NULL;
+ }
+ if (eeepc->wwan3g_rfkill) {
+ rfkill_unregister(eeepc->wwan3g_rfkill);
+ rfkill_destroy(eeepc->wwan3g_rfkill);
+ eeepc->wwan3g_rfkill = NULL;
+ }
+}
+
+static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
+{
+ int result = 0;
+
+ result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
+ "eeepc-wlan", RFKILL_TYPE_WLAN,
+ EEEPC_WMI_DEVID_WLAN);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+ result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
+ "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
+ EEEPC_WMI_DEVID_BLUETOOTH);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+ result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
+ "eeepc-wwan3g", RFKILL_TYPE_WWAN,
+ EEEPC_WMI_DEVID_WWAN3G);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+exit:
+ if (result && result != -ENODEV)
+ eeepc_wmi_rfkill_exit(eeepc);
+
+ if (result == -ENODEV)
+ result = 0;
+
+ return result;
+}
+
+/*
+ * Backlight
+ */
static int read_brightness(struct backlight_device *bd)
{
- static u32 ctrl_param;
+ u32 retval;
acpi_status status;
- status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param);
+ status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
if (ACPI_FAILURE(status))
return -1;
else
- return ctrl_param & 0xFF;
+ return retval & 0xFF;
}
static int update_bl_status(struct backlight_device *bd)
{
- static u32 ctrl_param;
+ u32 ctrl_param;
acpi_status status;
ctrl_param = bd->props.brightness;
- status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param);
+ status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
+ ctrl_param, NULL);
if (ACPI_FAILURE(status))
return -1;
@@ -234,7 +519,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = 15;
bd = backlight_device_register(EEEPC_WMI_FILE,
- &platform_device->dev, eeepc,
+ &eeepc->platform_device->dev, eeepc,
&eeepc_wmi_bl_ops, &props);
if (IS_ERR(bd)) {
pr_err("Could not register backlight device\n");
@@ -298,8 +583,8 @@ static void eeepc_wmi_notify(u32 value, void *context)
kfree(obj);
}
-static int store_cpufv(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int value;
struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
@@ -321,65 +606,240 @@ static int store_cpufv(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
+static struct attribute *platform_attributes[] = {
+ &dev_attr_cpufv.attr,
+ NULL
+};
+
+static struct attribute_group platform_attribute_group = {
+ .attrs = platform_attributes
+};
+
static void eeepc_wmi_sysfs_exit(struct platform_device *device)
{
- device_remove_file(&device->dev, &dev_attr_cpufv);
+ sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
}
static int eeepc_wmi_sysfs_init(struct platform_device *device)
{
- int retval = -ENOMEM;
+ return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
+}
- retval = device_create_file(&device->dev, &dev_attr_cpufv);
- if (retval)
- goto error_sysfs;
+/*
+ * Platform device
+ */
+static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
+{
+ int err;
+ eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
+ if (!eeepc->platform_device)
+ return -ENOMEM;
+ platform_set_drvdata(eeepc->platform_device, eeepc);
+
+ err = platform_device_add(eeepc->platform_device);
+ if (err)
+ goto fail_platform_device;
+
+ err = eeepc_wmi_sysfs_init(eeepc->platform_device);
+ if (err)
+ goto fail_sysfs;
return 0;
-error_sysfs:
- eeepc_wmi_sysfs_exit(platform_device);
- return retval;
+fail_sysfs:
+ platform_device_del(eeepc->platform_device);
+fail_platform_device:
+ platform_device_put(eeepc->platform_device);
+ return err;
}
-static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
+static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
{
+ eeepc_wmi_sysfs_exit(eeepc->platform_device);
+ platform_device_unregister(eeepc->platform_device);
+}
+
+/*
+ * debugfs
+ */
+struct eeepc_wmi_debugfs_node {
struct eeepc_wmi *eeepc;
- int err;
+ char *name;
+ int (*show)(struct seq_file *m, void *data);
+};
+
+static int show_dsts(struct seq_file *m, void *data)
+{
+ struct eeepc_wmi *eeepc = m->private;
acpi_status status;
+ u32 retval = -1;
- eeepc = platform_get_drvdata(device);
+ status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval);
+
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval);
+
+ return 0;
+}
+
+static int show_devs(struct seq_file *m, void *data)
+{
+ struct eeepc_wmi *eeepc = m->private;
+ acpi_status status;
+ u32 retval = -1;
+
+ status = eeepc_wmi_set_devstate(eeepc->debug.dev_id,
+ eeepc->debug.ctrl_param, &retval);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id,
+ eeepc->debug.ctrl_param, retval);
+
+ return 0;
+}
+
+static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = {
+ { NULL, "devs", show_devs },
+ { NULL, "dsts", show_dsts },
+};
+
+static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct eeepc_wmi_debugfs_node *node = inode->i_private;
+
+ return single_open(file, node->show, node->eeepc);
+}
+
+static const struct file_operations eeepc_wmi_debugfs_io_ops = {
+ .owner = THIS_MODULE,
+ .open = eeepc_wmi_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc)
+{
+ debugfs_remove_recursive(eeepc->debug.root);
+}
+
+static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc)
+{
+ struct dentry *dent;
+ int i;
+
+ eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL);
+ if (!eeepc->debug.root) {
+ pr_err("failed to create debugfs directory");
+ goto error_debugfs;
+ }
+
+ dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR,
+ eeepc->debug.root, &eeepc->debug.dev_id);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR,
+ eeepc->debug.root, &eeepc->debug.ctrl_param);
+ if (!dent)
+ goto error_debugfs;
+
+ for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) {
+ struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i];
+
+ node->eeepc = eeepc;
+ dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
+ eeepc->debug.root, node,
+ &eeepc_wmi_debugfs_io_ops);
+ if (!dent) {
+ pr_err("failed to create debug file: %s\n", node->name);
+ goto error_debugfs;
+ }
+ }
+
+ return 0;
+
+error_debugfs:
+ eeepc_wmi_debugfs_exit(eeepc);
+ return -ENOMEM;
+}
+
+/*
+ * WMI Driver
+ */
+static struct platform_device * __init eeepc_wmi_add(void)
+{
+ struct eeepc_wmi *eeepc;
+ acpi_status status;
+ int err;
+
+ eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
+ if (!eeepc)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * Register the platform device first. It is used as a parent for the
+ * sub-devices below.
+ */
+ err = eeepc_wmi_platform_init(eeepc);
+ if (err)
+ goto fail_platform;
err = eeepc_wmi_input_init(eeepc);
if (err)
- goto error_input;
+ goto fail_input;
+
+ err = eeepc_wmi_led_init(eeepc);
+ if (err)
+ goto fail_leds;
+
+ err = eeepc_wmi_rfkill_init(eeepc);
+ if (err)
+ goto fail_rfkill;
if (!acpi_video_backlight_support()) {
err = eeepc_wmi_backlight_init(eeepc);
if (err)
- goto error_backlight;
+ goto fail_backlight;
} else
pr_info("Backlight controlled by ACPI video driver\n");
status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
- eeepc_wmi_notify, eeepc);
+ eeepc_wmi_notify, eeepc);
if (ACPI_FAILURE(status)) {
pr_err("Unable to register notify handler - %d\n",
status);
err = -ENODEV;
- goto error_wmi;
+ goto fail_wmi_handler;
}
- return 0;
+ err = eeepc_wmi_debugfs_init(eeepc);
+ if (err)
+ goto fail_debugfs;
-error_wmi:
+ return eeepc->platform_device;
+
+fail_debugfs:
+ wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
+fail_wmi_handler:
eeepc_wmi_backlight_exit(eeepc);
-error_backlight:
+fail_backlight:
+ eeepc_wmi_rfkill_exit(eeepc);
+fail_rfkill:
+ eeepc_wmi_led_exit(eeepc);
+fail_leds:
eeepc_wmi_input_exit(eeepc);
-error_input:
- return err;
+fail_input:
+ eeepc_wmi_platform_exit(eeepc);
+fail_platform:
+ kfree(eeepc);
+ return ERR_PTR(err);
}
-static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
+static int eeepc_wmi_remove(struct platform_device *device)
{
struct eeepc_wmi *eeepc;
@@ -387,7 +847,12 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device)
wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
eeepc_wmi_backlight_exit(eeepc);
eeepc_wmi_input_exit(eeepc);
+ eeepc_wmi_led_exit(eeepc);
+ eeepc_wmi_rfkill_exit(eeepc);
+ eeepc_wmi_debugfs_exit(eeepc);
+ eeepc_wmi_platform_exit(eeepc);
+ kfree(eeepc);
return 0;
}
@@ -396,13 +861,31 @@ static struct platform_driver platform_driver = {
.name = EEEPC_WMI_FILE,
.owner = THIS_MODULE,
},
- .probe = eeepc_wmi_platform_probe,
- .remove = __devexit_p(eeepc_wmi_platform_remove),
};
+static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
+ void *context, void **retval)
+{
+ pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
+ *(bool *)context = true;
+ return AE_CTRL_TERMINATE;
+}
+
+static int __init eeepc_wmi_check_atkd(void)
+{
+ acpi_status status;
+ bool found = false;
+
+ status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device,
+ &found, NULL);
+
+ if (ACPI_FAILURE(status) || !found)
+ return 0;
+ return -1;
+}
+
static int __init eeepc_wmi_init(void)
{
- struct eeepc_wmi *eeepc;
int err;
if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
@@ -411,58 +894,40 @@ static int __init eeepc_wmi_init(void)
return -ENODEV;
}
- eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
- if (!eeepc)
- return -ENOMEM;
-
- platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
- if (!platform_device) {
- pr_warning("Unable to allocate platform device\n");
- err = -ENOMEM;
- goto fail_platform;
+ if (eeepc_wmi_check_atkd()) {
+ pr_warning("WMI device present, but legacy ATKD device is also "
+ "present and enabled.");
+ pr_warning("You probably booted with acpi_osi=\"Linux\" or "
+ "acpi_osi=\"!Windows 2009\"");
+ pr_warning("Can't load eeepc-wmi, use default acpi_osi "
+ "(preferred) or eeepc-laptop");
+ return -ENODEV;
}
- err = platform_device_add(platform_device);
- if (err) {
- pr_warning("Unable to add platform device\n");
- goto put_dev;
+ platform_device = eeepc_wmi_add();
+ if (IS_ERR(platform_device)) {
+ err = PTR_ERR(platform_device);
+ goto fail_eeepc_wmi;
}
- platform_set_drvdata(platform_device, eeepc);
-
err = platform_driver_register(&platform_driver);
if (err) {
pr_warning("Unable to register platform driver\n");
- goto del_dev;
+ goto fail_platform_driver;
}
- err = eeepc_wmi_sysfs_init(platform_device);
- if (err)
- goto del_sysfs;
-
return 0;
-del_sysfs:
- eeepc_wmi_sysfs_exit(platform_device);
-del_dev:
- platform_device_del(platform_device);
-put_dev:
- platform_device_put(platform_device);
-fail_platform:
- kfree(eeepc);
-
+fail_platform_driver:
+ eeepc_wmi_remove(platform_device);
+fail_eeepc_wmi:
return err;
}
static void __exit eeepc_wmi_exit(void)
{
- struct eeepc_wmi *eeepc;
-
- eeepc_wmi_sysfs_exit(platform_device);
- eeepc = platform_get_drvdata(platform_device);
+ eeepc_wmi_remove(platform_device);
platform_driver_unregister(&platform_driver);
- platform_device_unregister(platform_device);
- kfree(eeepc);
}
module_init(eeepc_wmi_init);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index f44cd2620ff9..95e3b0948e9c 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -437,7 +437,7 @@ static int bl_update_status(struct backlight_device *b)
return ret;
}
-static struct backlight_ops fujitsubl_ops = {
+static const struct backlight_ops fujitsubl_ops = {
.get_brightness = bl_get_brightness,
.update_status = bl_update_status,
};
@@ -689,7 +689,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
if (error)
goto err_free_input_dev;
- result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
+ result = acpi_bus_update_power(fujitsu->acpi_handle, &state);
if (result) {
printk(KERN_ERR "Error reading power state\n");
goto err_unregister_input_dev;
@@ -857,7 +857,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
if (error)
goto err_free_input_dev;
- result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state);
+ result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
if (result) {
printk(KERN_ERR "Error reading power state\n");
goto err_unregister_input_dev;
@@ -1240,7 +1240,7 @@ MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
-static struct pnp_device_id pnp_ids[] = {
+static struct pnp_device_id pnp_ids[] __used = {
{.id = "FUJ02bf"},
{.id = "FUJ02B1"},
{.id = "FUJ02E3"},
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 1dac659b5e0c..9e05af9c41cb 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -172,6 +172,8 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
bios_return = *((struct bios_return *)obj->buffer.pointer);
memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
+
+ kfree(obj);
return 0;
}
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
index 3c2c6b91ecb3..94a114aa8e28 100644
--- a/drivers/platform/x86/ibm_rtl.c
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/sysdev.h>
#include <linux/dmi.h>
+#include <linux/efi.h>
#include <linux/mutex.h>
#include <asm/bios_ebda.h>
@@ -220,32 +221,13 @@ static void rtl_teardown_sysfs(void) {
sysdev_class_unregister(&class_rtl);
}
-static int dmi_check_cb(const struct dmi_system_id *id)
-{
- RTL_DEBUG("found IBM server '%s'\n", id->ident);
- return 0;
-}
-
-#define ibm_dmi_entry(NAME, TYPE) \
-{ \
- .ident = NAME, \
- .matches = { \
- DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
- DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
- }, \
- .callback = dmi_check_cb \
-}
static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
- ibm_dmi_entry("BladeCenter LS21", "7971"),
- ibm_dmi_entry("BladeCenter LS22", "7901"),
- ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
- ibm_dmi_entry("BladeCenter HS22", "7870"),
- ibm_dmi_entry("BladeCenter HS22V", "7871"),
- ibm_dmi_entry("System x3550 M2", "7946"),
- ibm_dmi_entry("System x3650 M2", "7947"),
- ibm_dmi_entry("System x3550 M3", "7944"),
- ibm_dmi_entry("System x3650 M3", "7945"),
+ { \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ }, \
+ },
{ }
};
@@ -257,7 +239,7 @@ static int __init ibm_rtl_init(void) {
if (force)
pr_warning("ibm-rtl: module loaded by force\n");
/* first ensure that we are running on IBM HW */
- else if (!dmi_check_system(ibm_rtl_dmi_table))
+ else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
return -ENODEV;
/* Get the address for the Extended BIOS Data Area */
@@ -302,7 +284,7 @@ static int __init ibm_rtl_init(void) {
RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
rtl_cmd_width, rtl_cmd_type);
addr = ioread32(&rtl_table->cmd_port_address);
- RTL_DEBUG("addr = %#llx\n", addr);
+ RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr);
plen = rtl_cmd_width/sizeof(char);
rtl_cmd_addr = rtl_port_map(addr, plen);
RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 5ff12205aa6b..114d95247cdf 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1,5 +1,5 @@
/*
- * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
+ * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
*
* Copyright © 2010 Intel Corporation
* Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
@@ -27,31 +27,19 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
-#define IDEAPAD_DEV_CAMERA 0
-#define IDEAPAD_DEV_WLAN 1
-#define IDEAPAD_DEV_BLUETOOTH 2
-#define IDEAPAD_DEV_3G 3
-#define IDEAPAD_DEV_KILLSW 4
+#define IDEAPAD_RFKILL_DEV_NUM (3)
struct ideapad_private {
- acpi_handle handle;
- struct rfkill *rfk[5];
-} *ideapad_priv;
-
-static struct {
- char *name;
- int cfgbit;
- int opcode;
- int type;
-} ideapad_rfk_data[] = {
- { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
- { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
- { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
+ struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
+ struct platform_device *platform_device;
+ struct input_dev *inputdev;
};
+static acpi_handle ideapad_handle;
static bool no_bt_rfkill;
module_param(no_bt_rfkill, bool, 0444);
MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
@@ -163,17 +151,17 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
pr_err("timeout in write_ec_cmd\n");
return -1;
}
-/* the above is ACPI helpers */
+/*
+ * camera power
+ */
static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ideapad_private *priv = dev_get_drvdata(dev);
- acpi_handle handle = priv->handle;
unsigned long result;
- if (read_ec_data(handle, 0x1D, &result))
+ if (read_ec_data(ideapad_handle, 0x1D, &result))
return sprintf(buf, "-1\n");
return sprintf(buf, "%lu\n", result);
}
@@ -182,15 +170,13 @@ static ssize_t store_ideapad_cam(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct ideapad_private *priv = dev_get_drvdata(dev);
- acpi_handle handle = priv->handle;
int ret, state;
if (!count)
return 0;
if (sscanf(buf, "%i", &state) != 1)
return -EINVAL;
- ret = write_ec_cmd(handle, 0x1E, state);
+ ret = write_ec_cmd(ideapad_handle, 0x1E, state);
if (ret < 0)
return ret;
return count;
@@ -198,16 +184,27 @@ static ssize_t store_ideapad_cam(struct device *dev,
static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
+/*
+ * Rfkill
+ */
+struct ideapad_rfk_data {
+ char *name;
+ int cfgbit;
+ int opcode;
+ int type;
+};
+
+const struct ideapad_rfk_data ideapad_rfk_data[] = {
+ { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
+};
+
static int ideapad_rfk_set(void *data, bool blocked)
{
- int device = (unsigned long)data;
+ unsigned long opcode = (unsigned long)data;
- if (device == IDEAPAD_DEV_KILLSW)
- return -EINVAL;
-
- return write_ec_cmd(ideapad_priv->handle,
- ideapad_rfk_data[device].opcode,
- !blocked);
+ return write_ec_cmd(ideapad_handle, opcode, !blocked);
}
static struct rfkill_ops ideapad_rfk_ops = {
@@ -217,20 +214,20 @@ static struct rfkill_ops ideapad_rfk_ops = {
static void ideapad_sync_rfk_state(struct acpi_device *adevice)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- acpi_handle handle = priv->handle;
unsigned long hw_blocked;
int i;
- if (read_ec_data(handle, 0x23, &hw_blocked))
+ if (read_ec_data(ideapad_handle, 0x23, &hw_blocked))
return;
hw_blocked = !hw_blocked;
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+ for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
if (priv->rfk[i])
rfkill_set_hw_state(priv->rfk[i], hw_blocked);
}
-static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
+static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
+ int dev)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int ret;
@@ -239,7 +236,7 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
if (no_bt_rfkill &&
(ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
/* Force to enable bluetooth when no_bt_rfkill=1 */
- write_ec_cmd(ideapad_priv->handle,
+ write_ec_cmd(ideapad_handle,
ideapad_rfk_data[dev].opcode, 1);
return 0;
}
@@ -250,7 +247,7 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
if (!priv->rfk[dev])
return -ENOMEM;
- if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+ if (read_ec_data(ideapad_handle, ideapad_rfk_data[dev].opcode-1,
&sw_blocked)) {
rfkill_init_sw_state(priv->rfk[dev], 0);
} else {
@@ -266,7 +263,8 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
return 0;
}
-static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
+static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
+ int dev)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
@@ -277,73 +275,177 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
rfkill_destroy(priv->rfk[dev]);
}
+/*
+ * Platform device
+ */
+static struct attribute *ideapad_attributes[] = {
+ &dev_attr_camera_power.attr,
+ NULL
+};
+
+static struct attribute_group ideapad_attribute_group = {
+ .attrs = ideapad_attributes
+};
+
+static int __devinit ideapad_platform_init(struct ideapad_private *priv)
+{
+ int result;
+
+ priv->platform_device = platform_device_alloc("ideapad", -1);
+ if (!priv->platform_device)
+ return -ENOMEM;
+ platform_set_drvdata(priv->platform_device, priv);
+
+ result = platform_device_add(priv->platform_device);
+ if (result)
+ goto fail_platform_device;
+
+ result = sysfs_create_group(&priv->platform_device->dev.kobj,
+ &ideapad_attribute_group);
+ if (result)
+ goto fail_sysfs;
+ return 0;
+
+fail_sysfs:
+ platform_device_del(priv->platform_device);
+fail_platform_device:
+ platform_device_put(priv->platform_device);
+ return result;
+}
+
+static void ideapad_platform_exit(struct ideapad_private *priv)
+{
+ sysfs_remove_group(&priv->platform_device->dev.kobj,
+ &ideapad_attribute_group);
+ platform_device_unregister(priv->platform_device);
+}
+
+/*
+ * input device
+ */
+static const struct key_entry ideapad_keymap[] = {
+ { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x0D, { KEY_WLAN } },
+ { KE_END, 0 },
+};
+
+static int __devinit ideapad_input_init(struct ideapad_private *priv)
+{
+ struct input_dev *inputdev;
+ int error;
+
+ inputdev = input_allocate_device();
+ if (!inputdev) {
+ pr_info("Unable to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ inputdev->name = "Ideapad extra buttons";
+ inputdev->phys = "ideapad/input0";
+ inputdev->id.bustype = BUS_HOST;
+ inputdev->dev.parent = &priv->platform_device->dev;
+
+ error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
+ if (error) {
+ pr_err("Unable to setup input device keymap\n");
+ goto err_free_dev;
+ }
+
+ error = input_register_device(inputdev);
+ if (error) {
+ pr_err("Unable to register input device\n");
+ goto err_free_keymap;
+ }
+
+ priv->inputdev = inputdev;
+ return 0;
+
+err_free_keymap:
+ sparse_keymap_free(inputdev);
+err_free_dev:
+ input_free_device(inputdev);
+ return error;
+}
+
+static void __devexit ideapad_input_exit(struct ideapad_private *priv)
+{
+ sparse_keymap_free(priv->inputdev);
+ input_unregister_device(priv->inputdev);
+ priv->inputdev = NULL;
+}
+
+static void ideapad_input_report(struct ideapad_private *priv,
+ unsigned long scancode)
+{
+ sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
+}
+
+/*
+ * module init/exit
+ */
static const struct acpi_device_id ideapad_device_ids[] = {
{ "VPC2004", 0},
{ "", 0},
};
MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
-static int ideapad_acpi_add(struct acpi_device *adevice)
+static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
{
- int i, cfg;
- int devs_present[5];
+ int ret, i, cfg;
struct ideapad_private *priv;
if (read_method_int(adevice->handle, "_CFG", &cfg))
return -ENODEV;
- for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
- if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
- devs_present[i] = 1;
- else
- devs_present[i] = 0;
- }
-
- /* The hardware switch is always present */
- devs_present[IDEAPAD_DEV_KILLSW] = 1;
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ dev_set_drvdata(&adevice->dev, priv);
+ ideapad_handle = adevice->handle;
- if (devs_present[IDEAPAD_DEV_CAMERA]) {
- int ret = device_create_file(&adevice->dev, &dev_attr_camera_power);
- if (ret) {
- kfree(priv);
- return ret;
- }
- }
+ ret = ideapad_platform_init(priv);
+ if (ret)
+ goto platform_failed;
- priv->handle = adevice->handle;
- dev_set_drvdata(&adevice->dev, priv);
- ideapad_priv = priv;
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
- if (!devs_present[i])
- continue;
+ ret = ideapad_input_init(priv);
+ if (ret)
+ goto input_failed;
- ideapad_register_rfkill(adevice, i);
+ for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
+ if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+ ideapad_register_rfkill(adevice, i);
+ else
+ priv->rfk[i] = NULL;
}
ideapad_sync_rfk_state(adevice);
+
return 0;
+
+input_failed:
+ ideapad_platform_exit(priv);
+platform_failed:
+ kfree(priv);
+ return ret;
}
-static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
+static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int i;
- device_remove_file(&adevice->dev, &dev_attr_camera_power);
-
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+ for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
ideapad_unregister_rfkill(adevice, i);
-
+ ideapad_input_exit(priv);
+ ideapad_platform_exit(priv);
dev_set_drvdata(&adevice->dev, NULL);
kfree(priv);
+
return 0;
}
static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
{
+ struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
acpi_handle handle = adevice->handle;
unsigned long vpc1, vpc2, vpc_bit;
@@ -357,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
if (test_bit(vpc_bit, &vpc1)) {
if (vpc_bit == 9)
ideapad_sync_rfk_state(adevice);
+ else
+ ideapad_input_report(priv, vpc_bit);
}
}
}
@@ -371,19 +475,14 @@ static struct acpi_driver ideapad_acpi_driver = {
.owner = THIS_MODULE,
};
-
static int __init ideapad_acpi_module_init(void)
{
- acpi_bus_register_driver(&ideapad_acpi_driver);
-
- return 0;
+ return acpi_bus_register_driver(&ideapad_acpi_driver);
}
-
static void __exit ideapad_acpi_module_exit(void)
{
acpi_bus_unregister_driver(&ideapad_acpi_driver);
-
}
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index c44a5e8b8b82..1294a39373ba 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -75,6 +75,7 @@
#include <drm/i915_drm.h>
#include <asm/msr.h>
#include <asm/processor.h>
+#include "intel_ips.h"
#define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
@@ -245,6 +246,7 @@
#define thm_writel(off, val) writel((val), ips->regmap + (off))
static const int IPS_ADJUST_PERIOD = 5000; /* ms */
+static bool late_i915_load = false;
/* For initial average collection */
static const int IPS_SAMPLE_PERIOD = 200; /* ms */
@@ -339,6 +341,9 @@ struct ips_driver {
u64 orig_turbo_ratios;
};
+static bool
+ips_gpu_turbo_enabled(struct ips_driver *ips);
+
/**
* ips_cpu_busy - is CPU busy?
* @ips: IPS driver struct
@@ -517,7 +522,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips)
*/
static bool ips_gpu_busy(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return false;
return ips->gpu_busy();
@@ -532,7 +537,7 @@ static bool ips_gpu_busy(struct ips_driver *ips)
*/
static void ips_gpu_raise(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return;
if (!ips->gpu_raise())
@@ -549,7 +554,7 @@ static void ips_gpu_raise(struct ips_driver *ips)
*/
static void ips_gpu_lower(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return;
if (!ips->gpu_lower())
@@ -1454,6 +1459,31 @@ out_err:
return false;
}
+static bool
+ips_gpu_turbo_enabled(struct ips_driver *ips)
+{
+ if (!ips->gpu_busy && late_i915_load) {
+ if (ips_get_i915_syms(ips)) {
+ dev_info(&ips->dev->dev,
+ "i915 driver attached, reenabling gpu turbo\n");
+ ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS);
+ }
+ }
+
+ return ips->gpu_turbo_enabled;
+}
+
+void
+ips_link_to_i915_driver(void)
+{
+ /* We can't cleanly get at the various ips_driver structs from
+ * this caller (the i915 driver), so just set a flag saying
+ * that it's time to try getting the symbols again.
+ */
+ late_i915_load = true;
+}
+EXPORT_SYMBOL_GPL(ips_link_to_i915_driver);
+
static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
diff --git a/drivers/platform/x86/intel_ips.h b/drivers/platform/x86/intel_ips.h
new file mode 100644
index 000000000000..73299beff5b3
--- /dev/null
+++ b/drivers/platform/x86/intel_ips.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 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".
+ */
+
+void ips_link_to_i915_driver(void);
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index e61db9dfebef..930e62762365 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -244,7 +244,11 @@ static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
generic_handle_irq(pg->irq_base + gpio);
}
}
- desc->chip->eoi(irq);
+
+ if (desc->chip->irq_eoi)
+ desc->chip->irq_eoi(irq_get_irq_data(irq));
+ else
+ dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq);
}
static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 41a9e34899ac..1752ef006d26 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -26,6 +26,7 @@
#include <linux/sfi.h>
#include <asm/mrst.h>
#include <asm/intel_scu_ipc.h>
+#include <asm/mrst.h>
/* IPC defines the following message types */
#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
@@ -496,7 +497,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
"intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
mutex_unlock(&ipclock);
- return -1;
+ return -EIO;
}
mutex_unlock(&ipclock);
return 0;
@@ -641,7 +642,7 @@ update_end:
if (status == IPC_FW_UPDATE_SUCCESS)
return 0;
- return -1;
+ return -EIO;
}
EXPORT_SYMBOL(intel_scu_ipc_fw_update);
@@ -699,6 +700,9 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
iounmap(ipcdev.ipc_base);
return -ENOMEM;
}
+
+ intel_scu_devices_create();
+
return 0;
}
@@ -720,6 +724,7 @@ static void ipc_remove(struct pci_dev *pdev)
iounmap(ipcdev.ipc_base);
iounmap(ipcdev.i2c_base);
ipcdev.pdev = NULL;
+ intel_scu_devices_destroy();
}
static const struct pci_device_id pci_ids[] = {
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
new file mode 100644
index 000000000000..ba3231d0819e
--- /dev/null
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -0,0 +1,133 @@
+/*
+ * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
+ *
+ * (C) Copyright 2008-2010 Intel Corporation
+ * Author: Sreedhara DS (sreedhara.ds@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This driver provides ioctl interfaces to call intel scu ipc driver api
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/intel_scu_ipc.h>
+
+static u32 major;
+
+#define MAX_FW_SIZE 264192
+
+/* ioctl commnds */
+#define INTE_SCU_IPC_REGISTER_READ 0
+#define INTE_SCU_IPC_REGISTER_WRITE 1
+#define INTE_SCU_IPC_REGISTER_UPDATE 2
+#define INTE_SCU_IPC_FW_UPDATE 0xA2
+
+struct scu_ipc_data {
+ u32 count; /* No. of registers */
+ u16 addr[5]; /* Register addresses */
+ u8 data[5]; /* Register data */
+ u8 mask; /* Valid for read-modify-write */
+};
+
+/**
+ * scu_reg_access - implement register access ioctls
+ * @cmd: command we are doing (read/write/update)
+ * @data: kernel copy of ioctl data
+ *
+ * Allow the user to perform register accesses on the SCU via the
+ * kernel interface
+ */
+
+static int scu_reg_access(u32 cmd, struct scu_ipc_data *data)
+{
+ int count = data->count;
+
+ if (count == 0 || count == 3 || count > 4)
+ return -EINVAL;
+
+ switch (cmd) {
+ case INTE_SCU_IPC_REGISTER_READ:
+ return intel_scu_ipc_readv(data->addr, data->data, count);
+ case INTE_SCU_IPC_REGISTER_WRITE:
+ return intel_scu_ipc_writev(data->addr, data->data, count);
+ case INTE_SCU_IPC_REGISTER_UPDATE:
+ return intel_scu_ipc_update_register(data->addr[0],
+ data->data[0], data->mask);
+ default:
+ return -ENOTTY;
+ }
+}
+
+/**
+ * scu_ipc_ioctl - control ioctls for the SCU
+ * @fp: file handle of the SCU device
+ * @cmd: ioctl coce
+ * @arg: pointer to user passed structure
+ *
+ * Support the I/O and firmware flashing interfaces of the SCU
+ */
+static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct scu_ipc_data data;
+ void __user *argp = (void __user *)arg;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ if (cmd == INTE_SCU_IPC_FW_UPDATE) {
+ u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL);
+ if (fwbuf == NULL)
+ return -ENOMEM;
+ if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) {
+ kfree(fwbuf);
+ return -EFAULT;
+ }
+ ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE);
+ kfree(fwbuf);
+ return ret;
+ } else {
+ if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
+ return -EFAULT;
+ ret = scu_reg_access(cmd, &data);
+ if (ret < 0)
+ return ret;
+ if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
+ return -EFAULT;
+ return 0;
+ }
+}
+
+static const struct file_operations scu_ipc_fops = {
+ .unlocked_ioctl = scu_ipc_ioctl,
+};
+
+static int __init ipc_module_init(void)
+{
+ return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
+}
+
+static void __exit ipc_module_exit(void)
+{
+ unregister_chrdev(major, "intel_mid_scu");
+}
+
+module_init(ipc_module_init);
+module_exit(ipc_module_exit);
+
+MODULE_LICENSE("GPL V2");
+MODULE_DESCRIPTION("Utility driver for intel scu ipc");
+MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 42a5469a2459..35278ad7e628 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -43,16 +43,18 @@ MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
#define dprintk(msg...) pr_debug(DRV_PFX msg)
-#define KEYCODE_BASE 0xD0
-#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE
-#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1)
-#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2)
-#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3)
+#define SCANCODE_BASE 0xD0
+#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE
+#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1)
+#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2)
+#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3)
+#define MSI_WMI_MUTE (SCANCODE_BASE + 4)
static struct key_entry msi_wmi_keymap[] = {
{ KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
{ KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
{ KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} },
{ KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
+ { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} },
{ KE_END, 0}
};
static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
@@ -169,7 +171,7 @@ static void msi_wmi_notify(u32 value, void *context)
ktime_t diff;
cur = ktime_get_real();
diff = ktime_sub(cur, last_pressed[key->code -
- KEYCODE_BASE]);
+ SCANCODE_BASE]);
/* Ignore event if the same event happened in a 50 ms
timeframe -> Key press may result in 10-20 GPEs */
if (ktime_to_us(diff) < 1000 * 50) {
@@ -178,7 +180,7 @@ static void msi_wmi_notify(u32 value, void *context)
key->code, ktime_to_us(diff));
return;
}
- last_pressed[key->code - KEYCODE_BASE] = cur;
+ last_pressed[key->code - SCANCODE_BASE] = cur;
if (key->type == KE_KEY &&
/* Brightness is served via acpi video driver */
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f200677851b8..5e83370b0812 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -235,6 +235,7 @@ static int sony_laptop_input_index[] = {
57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
-1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
+ 59, /* 72 SONYPI_EVENT_VENDOR_PRESSED */
};
static int sony_laptop_input_keycode_map[] = {
@@ -297,6 +298,7 @@ static int sony_laptop_input_keycode_map[] = {
KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */
+ KEY_VENDOR, /* 59 SONYPI_EVENT_VENDOR_PRESSED */
};
/* release buttons after a short delay if pressed */
@@ -856,7 +858,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
}
static struct backlight_device *sony_backlight_device;
-static struct backlight_ops sony_backlight_ops = {
+static const struct backlight_ops sony_backlight_ops = {
.update_status = sony_backlight_update_status,
.get_brightness = sony_backlight_get_brightness,
};
@@ -894,10 +896,18 @@ static struct sony_nc_event sony_100_events[] = {
{ 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
{ 0x8C, SONYPI_EVENT_FNKEY_F12 },
{ 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
+ { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
{ 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
{ 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
{ 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
{ 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
+ { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED },
+ { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED },
+ { 0xa5, SONYPI_EVENT_VENDOR_PRESSED },
+ { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED },
+ { 0xa6, SONYPI_EVENT_HELP_PRESSED },
+ { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED },
{ 0, 0 },
};
@@ -1131,7 +1141,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
return err;
}
-static void sony_nc_rfkill_update()
+static void sony_nc_rfkill_update(void)
{
enum sony_nc_rfkill i;
int result;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 2d61186ad5a2..dd599585c6a9 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -589,6 +589,7 @@ static int acpi_evalf(acpi_handle handle,
default:
printk(TPACPI_ERR "acpi_evalf() called "
"with invalid format character '%c'\n", c);
+ va_end(ap);
return 0;
}
}
@@ -6109,7 +6110,7 @@ static void tpacpi_brightness_notify_change(void)
BACKLIGHT_UPDATE_HOTKEY);
}
-static struct backlight_ops ibm_backlight_data = {
+static const struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
};
@@ -6345,7 +6346,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
"as change notification\n");
tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
| TP_ACPI_HKEY_BRGHTUP_MASK
- | TP_ACPI_HKEY_BRGHTDWN_MASK);;
+ | TP_ACPI_HKEY_BRGHTDWN_MASK);
return 0;
}
@@ -7193,7 +7194,7 @@ static struct ibm_struct volume_driver_data = {
* TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
*
* FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
- * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ * boot. Apparently the EC does not initialize it, so unless ACPI DSDT
* does so, its initial value is meaningless (0x07).
*
* For firmware bugs, refer to:
@@ -8497,7 +8498,6 @@ static void ibm_exit(struct ibm_struct *ibm)
ibm->acpi->type,
dispatch_acpi_notify);
ibm->flags.acpi_notify_installed = 0;
- ibm->flags.acpi_notify_installed = 0;
}
if (ibm->flags.proc_created) {
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 06f304f46e02..209cced786c6 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -135,6 +135,7 @@ static const struct key_entry toshiba_acpi_keymap[] __initconst = {
{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x142, { KEY_WLAN } },
{ KE_KEY, 0x143, { KEY_PROG1 } },
+ { KE_KEY, 0x17f, { KEY_FN } },
{ KE_KEY, 0xb05, { KEY_PROG2 } },
{ KE_KEY, 0xb06, { KEY_WWW } },
{ KE_KEY, 0xb07, { KEY_MAIL } },
@@ -840,7 +841,7 @@ static void remove_toshiba_proc_entries(void)
remove_proc_entry("version", toshiba_proc_dir);
}
-static struct backlight_ops toshiba_backlight_data = {
+static const struct backlight_ops toshiba_backlight_data = {
.get_brightness = get_lcd,
.update_status = set_lcd_status,
};
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 104b77c87ef5..05cc79672a8b 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -549,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
struct wmi_block *block;
- acpi_status status;
+ acpi_status status = AE_NOT_EXIST;
+ char tmp[16], guid_input[16];
+ struct list_head *p;
if (!guid || !handler)
return AE_BAD_PARAMETER;
- if (!find_guid(guid, &block))
- return AE_NOT_EXIST;
+ wmi_parse_guid(guid, tmp);
+ wmi_swap_bytes(tmp, guid_input);
- if (block->handler && block->handler != wmi_notify_debug)
- return AE_ALREADY_ACQUIRED;
+ list_for_each(p, &wmi_block_list) {
+ acpi_status wmi_status;
+ block = list_entry(p, struct wmi_block, list);
- block->handler = handler;
- block->handler_data = data;
+ if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
+ if (block->handler &&
+ block->handler != wmi_notify_debug)
+ return AE_ALREADY_ACQUIRED;
- status = wmi_method_enable(block, 1);
+ block->handler = handler;
+ block->handler_data = data;
+
+ wmi_status = wmi_method_enable(block, 1);
+ if ((wmi_status != AE_OK) ||
+ ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
+ status = wmi_status;
+ }
+ }
return status;
}
@@ -577,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
acpi_status wmi_remove_notify_handler(const char *guid)
{
struct wmi_block *block;
- acpi_status status = AE_OK;
+ acpi_status status = AE_NOT_EXIST;
+ char tmp[16], guid_input[16];
+ struct list_head *p;
if (!guid)
return AE_BAD_PARAMETER;
- if (!find_guid(guid, &block))
- return AE_NOT_EXIST;
+ wmi_parse_guid(guid, tmp);
+ wmi_swap_bytes(tmp, guid_input);
- if (!block->handler || block->handler == wmi_notify_debug)
- return AE_NULL_ENTRY;
+ list_for_each(p, &wmi_block_list) {
+ acpi_status wmi_status;
+ block = list_entry(p, struct wmi_block, list);
- if (debug_event) {
- block->handler = wmi_notify_debug;
- } else {
- status = wmi_method_enable(block, 0);
- block->handler = NULL;
- block->handler_data = NULL;
+ if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
+ if (!block->handler ||
+ block->handler == wmi_notify_debug)
+ return AE_NULL_ENTRY;
+
+ if (debug_event) {
+ block->handler = wmi_notify_debug;
+ status = AE_OK;
+ } else {
+ wmi_status = wmi_method_enable(block, 0);
+ block->handler = NULL;
+ block->handler_data = NULL;
+ if ((wmi_status != AE_OK) ||
+ ((wmi_status == AE_OK) &&
+ (status == AE_NOT_EXIST)))
+ status = wmi_status;
+ }
+ }
}
+
return status;
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
@@ -705,22 +734,11 @@ static struct class wmi_class = {
.dev_attrs = wmi_dev_attrs,
};
-static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
- acpi_handle handle)
+static int wmi_create_device(const struct guid_block *gblock,
+ struct wmi_block *wblock, acpi_handle handle)
{
- struct wmi_block *wblock;
- int error;
char guid_string[37];
- wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
- if (!wblock) {
- error = -ENOMEM;
- goto err_out;
- }
-
- wblock->handle = handle;
- wblock->gblock = *gblock;
-
wblock->dev.class = &wmi_class;
wmi_gtoa(gblock->guid, guid_string);
@@ -728,17 +746,7 @@ static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
dev_set_drvdata(&wblock->dev, wblock);
- error = device_register(&wblock->dev);
- if (error)
- goto err_free;
-
- list_add_tail(&wblock->list, &wmi_block_list);
- return wblock;
-
-err_free:
- kfree(wblock);
-err_out:
- return ERR_PTR(error);
+ return device_register(&wblock->dev);
}
static void wmi_free_devices(void)
@@ -747,7 +755,8 @@ static void wmi_free_devices(void)
/* Delete devices for all the GUIDs */
list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
- device_unregister(&wblock->dev);
+ if (wblock->dev.class)
+ device_unregister(&wblock->dev);
}
static bool guid_already_parsed(const char *guid_string)
@@ -755,7 +764,7 @@ static bool guid_already_parsed(const char *guid_string)
struct wmi_block *wblock;
list_for_each_entry(wblock, &wmi_block_list, list)
- if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
+ if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
return true;
return false;
@@ -770,7 +779,6 @@ static acpi_status parse_wdg(acpi_handle handle)
union acpi_object *obj;
const struct guid_block *gblock;
struct wmi_block *wblock;
- char guid_string[37];
acpi_status status;
int retval;
u32 i, total;
@@ -792,28 +800,31 @@ static acpi_status parse_wdg(acpi_handle handle)
total = obj->buffer.length / sizeof(struct guid_block);
for (i = 0; i < total; i++) {
+ if (debug_dump_wdg)
+ wmi_dump_wdg(&gblock[i]);
+
+ wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+ if (!wblock)
+ return AE_NO_MEMORY;
+
+ wblock->handle = handle;
+ wblock->gblock = gblock[i];
+
/*
Some WMI devices, like those for nVidia hooks, have a
duplicate GUID. It's not clear what we should do in this
- case yet, so for now, we'll just ignore the duplicate.
- Anyone who wants to add support for that device can come
- up with a better workaround for the mess then.
+ case yet, so for now, we'll just ignore the duplicate
+ for device creation.
*/
- if (guid_already_parsed(gblock[i].guid) == true) {
- wmi_gtoa(gblock[i].guid, guid_string);
- pr_info("Skipping duplicate GUID %s\n", guid_string);
- continue;
+ if (!guid_already_parsed(gblock[i].guid)) {
+ retval = wmi_create_device(&gblock[i], wblock, handle);
+ if (retval) {
+ wmi_free_devices();
+ goto out_free_pointer;
+ }
}
- if (debug_dump_wdg)
- wmi_dump_wdg(&gblock[i]);
-
- wblock = wmi_create_device(&gblock[i], handle);
- if (IS_ERR(wblock)) {
- retval = PTR_ERR(wblock);
- wmi_free_devices();
- break;
- }
+ list_add_tail(&wblock->list, &wmi_block_list);
if (debug_event) {
wblock->handler = wmi_notify_debug;
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index 8de3775ec242..bfba893cb321 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -2,11 +2,13 @@
# Makefile for the Linux Plug-and-Play Support.
#
-obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
+obj-y := pnp.o
+
+pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
obj-$(CONFIG_PNPACPI) += pnpacpi/
obj-$(CONFIG_PNPBIOS) += pnpbios/
obj-$(CONFIG_ISAPNP) += isapnp/
# pnp_system_init goes after pnpacpi/pnpbios init
-obj-y += system.o
+pnp-y += system.o
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 0f34d962fd3c..cb6ce42f8e77 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -220,10 +220,5 @@ subsys_initcall(pnp_init);
int pnp_debug;
#if defined(CONFIG_PNP_DEBUG_MESSAGES)
-static int __init pnp_debug_setup(char *__unused)
-{
- pnp_debug = 1;
- return 1;
-}
-__setup("pnp.debug", pnp_debug_setup);
+module_param_named(debug, pnp_debug, int, 0644);
#endif
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index d1dbb9df53fa..00e94032531a 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -189,8 +189,11 @@ static int pnp_bus_resume(struct device *dev)
if (!pnp_drv)
return 0;
- if (pnp_dev->protocol->resume)
- pnp_dev->protocol->resume(pnp_dev);
+ if (pnp_dev->protocol->resume) {
+ error = pnp_dev->protocol->resume(pnp_dev);
+ if (error)
+ return error;
+ }
if (pnp_can_write(pnp_dev)) {
error = pnp_start_dev(pnp_dev);
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
index cac18bbfb817..6e607aa33aa3 100644
--- a/drivers/pnp/isapnp/Makefile
+++ b/drivers/pnp/isapnp/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the kernel ISAPNP driver.
#
+obj-y += pnp.o
+pnp-y := core.o compat.o
-isapnp-proc-$(CONFIG_PROC_FS) = proc.o
-
-obj-y := core.o compat.o $(isapnp-proc-y)
+pnp-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index e73ebefdf3e0..315b3112aca8 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -21,7 +21,6 @@
#include <linux/isapnp.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
extern struct pnp_protocol isapnp_protocol;
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
index 905326fcca85..40c93da18252 100644
--- a/drivers/pnp/pnpacpi/Makefile
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -1,5 +1,6 @@
#
# Makefile for the kernel PNPACPI driver.
#
+obj-y += pnp.o
-obj-y := core.o rsparser.o
+pnp-y := core.o rsparser.o
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 2d73dfcecdbb..ca84d5099ce7 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -81,12 +81,19 @@ static int pnpacpi_get_resources(struct pnp_dev *dev)
static int pnpacpi_set_resources(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
struct acpi_buffer buffer;
int ret;
pnp_dbg(&dev->dev, "set resources\n");
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return -ENODEV;
+ }
+
ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
@@ -105,12 +112,18 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
static int pnpacpi_disable_resources(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
int ret;
dev_dbg(&dev->dev, "disable resources\n");
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return 0;
+ }
+
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
ret = 0;
if (acpi_bus_power_manageable(handle))
@@ -124,46 +137,74 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
#ifdef CONFIG_ACPI_SLEEP
static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return false;
+ }
return acpi_bus_can_wakeup(handle);
}
static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
- int power_state;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
+ int error = 0;
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return 0;
+ }
if (device_can_wakeup(&dev->dev)) {
- int rc = acpi_pm_device_sleep_wake(&dev->dev,
+ error = acpi_pm_device_sleep_wake(&dev->dev,
device_may_wakeup(&dev->dev));
+ if (error)
+ return error;
+ }
+
+ if (acpi_bus_power_manageable(handle)) {
+ int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
+
+ if (power_state < 0)
+ power_state = (state.event == PM_EVENT_ON) ?
+ ACPI_STATE_D0 : ACPI_STATE_D3;
- if (rc)
- return rc;
+ /*
+ * acpi_bus_set_power() often fails (keyboard port can't be
+ * powered-down?), and in any case, our return value is ignored
+ * by pnp_bus_suspend(). Hence we don't revert the wakeup
+ * setting if the set_power fails.
+ */
+ error = acpi_bus_set_power(handle, power_state);
}
- power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
- if (power_state < 0)
- power_state = (state.event == PM_EVENT_ON) ?
- ACPI_STATE_D0 : ACPI_STATE_D3;
-
- /* acpi_bus_set_power() often fails (keyboard port can't be
- * powered-down?), and in any case, our return value is ignored
- * by pnp_bus_suspend(). Hence we don't revert the wakeup
- * setting if the set_power fails.
- */
- return acpi_bus_set_power(handle, power_state);
+
+ return error;
}
static int pnpacpi_resume(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ int error = 0;
+
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return -ENODEV;
+ }
if (device_may_wakeup(&dev->dev))
acpi_pm_device_sleep_wake(&dev->dev, false);
- return acpi_bus_set_power(handle, ACPI_STATE_D0);
+
+ if (acpi_bus_power_manageable(handle))
+ error = acpi_bus_set_power(handle, ACPI_STATE_D0);
+
+ return error;
}
#endif
@@ -180,7 +221,7 @@ struct pnp_protocol pnpacpi_protocol = {
};
EXPORT_SYMBOL(pnpacpi_protocol);
-static char *pnpacpi_get_id(struct acpi_device *device)
+static char *__init pnpacpi_get_id(struct acpi_device *device)
{
struct acpi_hardware_id *id;
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
index 3cd3ed760605..240b0ffb83ca 100644
--- a/drivers/pnp/pnpbios/Makefile
+++ b/drivers/pnp/pnpbios/Makefile
@@ -1,7 +1,8 @@
#
# Makefile for the kernel PNPBIOS driver.
#
+obj-y := pnp.o
-pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
+pnp-y := core.o bioscalls.o rsparser.o
-obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
+pnp-$(CONFIG_PNPBIOS_PROC_FS) += proc.o
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 60d83d983a36..61bf5d724139 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -136,6 +136,16 @@ config BATTERY_MAX17040
in handheld and portable equipment. The MAX17040 is configured
to operate with a single lithium cell
+config BATTERY_MAX17042
+ tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
+ depends on I2C
+ help
+ MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17042 is configured
+ to operate with a single lithium cell. MAX8997 and MAX8966 are
+ multi-function devices that include fuel gauages that are compatible
+ with MAX17042.
+
config BATTERY_Z2
tristate "Z2 battery driver"
depends on I2C && MACH_ZIPIT2
@@ -185,4 +195,14 @@ config CHARGER_TWL4030
help
Say Y here to enable support for TWL4030 Battery Charge Interface.
+config CHARGER_GPIO
+ tristate "GPIO charger"
+ depends on GPIOLIB
+ help
+ Say Y to include support for chargers which report their online status
+ through a GPIO pin.
+
+ This driver can be build as a module. If so, the module will be
+ called gpio-charger.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index c75772eb157c..8385bfae8728 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
+obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index 039f41ae217d..548d263b1ad0 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -295,7 +295,7 @@ static struct {
static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -362,7 +362,7 @@ err_psy_reg_bu:
err_psy_reg_main:
/* see comment in collie_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
power_supply_unregister(&collie_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index b3c01c16a164..e534290f3256 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
if (di->rem_capacity > 100)
di->rem_capacity = 100;
- if (di->current_uA >= 100L)
+ if (di->current_uA < -100L)
di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
/ (di->current_uA / 100L);
else
@@ -580,10 +580,8 @@ static int ds2760_battery_remove(struct platform_device *pdev)
{
struct ds2760_device_info *di = platform_get_drvdata(pdev);
- cancel_rearming_delayed_workqueue(di->monitor_wqueue,
- &di->monitor_work);
- cancel_rearming_delayed_workqueue(di->monitor_wqueue,
- &di->set_charged_work);
+ cancel_delayed_work_sync(&di->monitor_work);
+ cancel_delayed_work_sync(&di->set_charged_work);
destroy_workqueue(di->monitor_wqueue);
power_supply_unregister(&di->bat);
kfree(di);
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644
index 000000000000..25b88ac1d44c
--- /dev/null
+++ b/drivers/power/gpio-charger.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Driver for chargers which report their online status through a GPIO pin
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You 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/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+#include <linux/power/gpio-charger.h>
+
+struct gpio_charger {
+ const struct gpio_charger_platform_data *pdata;
+ unsigned int irq;
+
+ struct power_supply charger;
+};
+
+static irqreturn_t gpio_charger_irq(int irq, void *devid)
+{
+ struct power_supply *charger = devid;
+
+ power_supply_changed(charger);
+
+ return IRQ_HANDLED;
+}
+
+static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
+{
+ return container_of(psy, struct gpio_charger, charger);
+}
+
+static int gpio_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
+ const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = gpio_get_value(pdata->gpio);
+ val->intval ^= pdata->gpio_active_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property gpio_charger_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int __devinit gpio_charger_probe(struct platform_device *pdev)
+{
+ const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_charger *gpio_charger;
+ struct power_supply *charger;
+ int ret;
+ int irq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ if (!gpio_is_valid(pdata->gpio)) {
+ dev_err(&pdev->dev, "Invalid gpio pin\n");
+ return -EINVAL;
+ }
+
+ gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+ if (!gpio_charger) {
+ dev_err(&pdev->dev, "Failed to alloc driver structure\n");
+ return -ENOMEM;
+ }
+
+ charger = &gpio_charger->charger;
+
+ charger->name = pdata->name ? pdata->name : "gpio-charger";
+ charger->type = pdata->type;
+ charger->properties = gpio_charger_properties;
+ charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
+ charger->get_property = gpio_charger_get_property;
+ charger->supplied_to = pdata->supplied_to;
+ charger->num_supplicants = pdata->num_supplicants;
+
+ ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
+ goto err_free;
+ }
+ ret = gpio_direction_input(pdata->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
+ goto err_gpio_free;
+ }
+
+ gpio_charger->pdata = pdata;
+
+ ret = power_supply_register(&pdev->dev, charger);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+ ret);
+ goto err_gpio_free;
+ }
+
+ irq = gpio_to_irq(pdata->gpio);
+ if (irq > 0) {
+ ret = request_any_context_irq(irq, gpio_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), charger);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
+ else
+ gpio_charger->irq = irq;
+ }
+
+ platform_set_drvdata(pdev, gpio_charger);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free(pdata->gpio);
+err_free:
+ kfree(gpio_charger);
+ return ret;
+}
+
+static int __devexit gpio_charger_remove(struct platform_device *pdev)
+{
+ struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+ if (gpio_charger->irq)
+ free_irq(gpio_charger->irq, &gpio_charger->charger);
+
+ power_supply_unregister(&gpio_charger->charger);
+
+ gpio_free(gpio_charger->pdata->gpio);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(gpio_charger);
+
+ return 0;
+}
+
+static struct platform_driver gpio_charger_driver = {
+ .probe = gpio_charger_probe,
+ .remove = __devexit_p(gpio_charger_remove),
+ .driver = {
+ .name = "gpio-charger",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_charger_init(void)
+{
+ return platform_driver_register(&gpio_charger_driver);
+}
+module_init(gpio_charger_init);
+
+static void __exit gpio_charger_exit(void)
+{
+ platform_driver_unregister(&gpio_charger_driver);
+}
+module_exit(gpio_charger_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-charger");
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index 2a10cd361181..bce3a01da2f0 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -730,8 +730,7 @@ static __devinit int probe(int irq, struct device *dev)
power_reg_failed_1:
power_supply_unregister(&pbi->batt);
power_reg_failed:
- cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
- &pbi->monitor_battery);
+ cancel_delayed_work_sync(&pbi->monitor_battery);
requestirq_failed:
destroy_workqueue(pbi->monitor_wqueue);
wqueue_failed:
@@ -760,14 +759,13 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
free_irq(pbi->irq, pbi);
- cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
- &pbi->monitor_battery);
+ cancel_delayed_work_sync(&pbi->monitor_battery);
destroy_workqueue(pbi->monitor_wqueue);
power_supply_unregister(&pbi->usb);
power_supply_unregister(&pbi->batt);
- flush_scheduled_work();
+ cancel_work_sync(&pbi->handler);
kfree(pbi);
return 0;
}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 72512185f3e2..2ad9b14a5ce3 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -59,11 +59,61 @@ struct isp1704_charger {
struct notifier_block nb;
struct work_struct work;
- char model[7];
+ /* properties */
+ char model[8];
unsigned present:1;
+ unsigned online:1;
+ unsigned current_max;
+
+ /* temp storage variables */
+ unsigned long event;
+ unsigned max_power;
};
/*
+ * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
+ * chargers).
+ *
+ * REVISIT: The method is defined in Battery Charging Specification and is
+ * applicable to any ULPI transceiver. Nothing isp170x specific here.
+ */
+static inline int isp1704_charger_type(struct isp1704_charger *isp)
+{
+ u8 reg;
+ u8 func_ctrl;
+ u8 otg_ctrl;
+ int type = POWER_SUPPLY_TYPE_USB_DCP;
+
+ func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+ otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+
+ /* disable pulldowns */
+ reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+
+ /* full speed */
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_XCVRSEL_MASK);
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_FULL_SPEED);
+
+ /* Enable strong pull-up on DP (1.5K) and reset */
+ reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+ usleep_range(1000, 2000);
+
+ reg = otg_io_read(isp->otg, ULPI_DEBUG);
+ if ((reg & 3) != 3)
+ type = POWER_SUPPLY_TYPE_USB_CDP;
+
+ /* recover original state */
+ otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
+ otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+
+ return type;
+}
+
+/*
* ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
* is actually a dedicated charger, the following steps need to be taken.
*/
@@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
static inline int isp1704_charger_detect(struct isp1704_charger *isp)
{
unsigned long timeout;
- u8 r;
+ u8 pwr_ctrl;
int ret = 0;
+ pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+
/* set SW control bit in PWR_CTRL register */
otg_io_write(isp->otg, ISP1704_PWR_CTRL,
ISP1704_PWR_CTRL_SWCTRL);
/* enable manual charger detection */
- r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
- otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+ otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+ ISP1704_PWR_CTRL_SWCTRL
+ | ISP1704_PWR_CTRL_DPVSRC_EN);
usleep_range(1000, 2000);
timeout = jiffies + msecs_to_jiffies(300);
@@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
ret = isp1704_charger_verify(isp);
break;
}
- } while (!time_after(jiffies, timeout));
+ } while (!time_after(jiffies, timeout) && isp->online);
+
+ /* recover original state */
+ otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
return ret;
}
@@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
static void isp1704_charger_work(struct work_struct *data)
{
int detect;
+ unsigned long event;
+ unsigned power;
struct isp1704_charger *isp =
container_of(data, struct isp1704_charger, work);
+ static DEFINE_MUTEX(lock);
- /*
- * FIXME Only supporting dedicated chargers even though isp1704 can
- * detect HUB and HOST chargers. If the device has already been
- * enumerated, the detection will break the connection.
- */
- if (isp->otg->state != OTG_STATE_B_IDLE)
- return;
+ event = isp->event;
+ power = isp->max_power;
- /* disable data pullups */
- if (isp->otg->gadget)
- usb_gadget_disconnect(isp->otg->gadget);
+ mutex_lock(&lock);
+
+ switch (event) {
+ case USB_EVENT_VBUS:
+ isp->online = true;
+
+ /* detect charger */
+ detect = isp1704_charger_detect(isp);
+
+ if (detect) {
+ isp->present = detect;
+ isp->psy.type = isp1704_charger_type(isp);
+ }
- /* detect charger */
- detect = isp1704_charger_detect(isp);
- if (detect) {
- isp->present = detect;
- power_supply_changed(&isp->psy);
+ switch (isp->psy.type) {
+ case POWER_SUPPLY_TYPE_USB_DCP:
+ isp->current_max = 1800;
+ break;
+ case POWER_SUPPLY_TYPE_USB_CDP:
+ /*
+ * Only 500mA here or high speed chirp
+ * handshaking may break
+ */
+ isp->current_max = 500;
+ /* FALLTHROUGH */
+ case POWER_SUPPLY_TYPE_USB:
+ default:
+ /* enable data pullups */
+ if (isp->otg->gadget)
+ usb_gadget_connect(isp->otg->gadget);
+ }
+ break;
+ case USB_EVENT_NONE:
+ isp->online = false;
+ isp->current_max = 0;
+ isp->present = 0;
+ isp->current_max = 0;
+ isp->psy.type = POWER_SUPPLY_TYPE_USB;
+
+ /*
+ * Disable data pullups. We need to prevent the controller from
+ * enumerating.
+ *
+ * FIXME: This is here to allow charger detection with Host/HUB
+ * chargers. The pullups may be enabled elsewhere, so this can
+ * not be the final solution.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+ break;
+ case USB_EVENT_ENUMERATED:
+ if (isp->present)
+ isp->current_max = 1800;
+ else
+ isp->current_max = power;
+ break;
+ default:
+ goto out;
}
- /* enable data pullups */
- if (isp->otg->gadget)
- usb_gadget_connect(isp->otg->gadget);
+ power_supply_changed(&isp->psy);
+out:
+ mutex_unlock(&lock);
}
static int isp1704_notifier_call(struct notifier_block *nb,
- unsigned long event, void *unused)
+ unsigned long event, void *power)
{
struct isp1704_charger *isp =
container_of(nb, struct isp1704_charger, nb);
- switch (event) {
- case USB_EVENT_VBUS:
- schedule_work(&isp->work);
- break;
- case USB_EVENT_NONE:
- if (isp->present) {
- isp->present = 0;
- power_supply_changed(&isp->psy);
- }
- break;
- default:
- return NOTIFY_DONE;
- }
+ isp->event = event;
+
+ if (power)
+ isp->max_power = *((unsigned *)power);
+
+ schedule_work(&isp->work);
return NOTIFY_OK;
}
@@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
val->intval = isp->present;
break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = isp->online;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = isp->current_max;
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = isp->model;
break;
@@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
static enum power_supply_property power_props[] = {
POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
};
@@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
if (!isp->otg)
goto fail0;
+ isp->dev = &pdev->dev;
+ platform_set_drvdata(pdev, isp);
+
ret = isp1704_test_ulpi(isp);
if (ret < 0)
goto fail1;
- isp->dev = &pdev->dev;
- platform_set_drvdata(pdev, isp);
-
isp->psy.name = "isp1704";
isp->psy.type = POWER_SUPPLY_TYPE_USB;
isp->psy.properties = power_props;
@@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
dev_info(isp->dev, "registered with product id %s\n", isp->model);
+ /*
+ * Taking over the D+ pullup.
+ *
+ * FIXME: The device will be disconnected if it was already
+ * enumerated. The charger driver should be always loaded before any
+ * gadget is loaded.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+
+ /* Detect charger if VBUS is valid (the cable was already plugged). */
+ ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+ if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+ isp->event = USB_EVENT_VBUS;
+ schedule_work(&isp->work);
+ }
+
return 0;
fail2:
power_supply_unregister(&isp->psy);
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index a8108a73593e..02414db6a94c 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/gpio.h>
@@ -47,6 +48,8 @@ struct jz_battery {
struct power_supply battery;
struct delayed_work work;
+
+ struct mutex lock;
};
static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
@@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
unsigned long val;
long voltage;
+ mutex_lock(&battery->lock);
+
INIT_COMPLETION(battery->read_completion);
enable_irq(battery->irq);
@@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
battery->cell->disable(battery->pdev);
disable_irq(battery->irq);
+ mutex_unlock(&battery->lock);
+
return voltage;
}
@@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
struct jz_battery *jz_battery;
struct power_supply *battery;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform_data supplied\n");
+ return -ENXIO;
+ }
+
jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
if (!jz_battery) {
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
@@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
jz_battery->pdev = pdev;
init_completion(&jz_battery->read_completion);
+ mutex_init(&jz_battery->lock);
INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644
index 000000000000..c5c8805156cb
--- /dev/null
+++ b/drivers/power/max17042_battery.c
@@ -0,0 +1,239 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.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
+ *
+ * This driver is based on max17040_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/power_supply.h>
+#include <linux/power/max17042_battery.h>
+
+enum max17042_register {
+ MAX17042_STATUS = 0x00,
+ MAX17042_VALRT_Th = 0x01,
+ MAX17042_TALRT_Th = 0x02,
+ MAX17042_SALRT_Th = 0x03,
+ MAX17042_AtRate = 0x04,
+ MAX17042_RepCap = 0x05,
+ MAX17042_RepSOC = 0x06,
+ MAX17042_Age = 0x07,
+ MAX17042_TEMP = 0x08,
+ MAX17042_VCELL = 0x09,
+ MAX17042_Current = 0x0A,
+ MAX17042_AvgCurrent = 0x0B,
+ MAX17042_Qresidual = 0x0C,
+ MAX17042_SOC = 0x0D,
+ MAX17042_AvSOC = 0x0E,
+ MAX17042_RemCap = 0x0F,
+ MAX17402_FullCAP = 0x10,
+ MAX17042_TTE = 0x11,
+ MAX17042_V_empty = 0x12,
+
+ MAX17042_RSLOW = 0x14,
+
+ MAX17042_AvgTA = 0x16,
+ MAX17042_Cycles = 0x17,
+ MAX17042_DesignCap = 0x18,
+ MAX17042_AvgVCELL = 0x19,
+ MAX17042_MinMaxTemp = 0x1A,
+ MAX17042_MinMaxVolt = 0x1B,
+ MAX17042_MinMaxCurr = 0x1C,
+ MAX17042_CONFIG = 0x1D,
+ MAX17042_ICHGTerm = 0x1E,
+ MAX17042_AvCap = 0x1F,
+ MAX17042_ManName = 0x20,
+ MAX17042_DevName = 0x21,
+ MAX17042_DevChem = 0x22,
+
+ MAX17042_TempNom = 0x24,
+ MAX17042_TempCold = 0x25,
+ MAX17042_TempHot = 0x26,
+ MAX17042_AIN = 0x27,
+ MAX17042_LearnCFG = 0x28,
+ MAX17042_SHFTCFG = 0x29,
+ MAX17042_RelaxCFG = 0x2A,
+ MAX17042_MiscCFG = 0x2B,
+ MAX17042_TGAIN = 0x2C,
+ MAx17042_TOFF = 0x2D,
+ MAX17042_CGAIN = 0x2E,
+ MAX17042_COFF = 0x2F,
+
+ MAX17042_Q_empty = 0x33,
+ MAX17042_T_empty = 0x34,
+
+ MAX17042_RCOMP0 = 0x38,
+ MAX17042_TempCo = 0x39,
+ MAX17042_Rx = 0x3A,
+ MAX17042_T_empty0 = 0x3B,
+ MAX17042_TaskPeriod = 0x3C,
+ MAX17042_FSTAT = 0x3D,
+
+ MAX17042_SHDNTIMER = 0x3F,
+
+ MAX17042_VFRemCap = 0x4A,
+
+ MAX17042_QH = 0x4D,
+ MAX17042_QL = 0x4E,
+};
+
+struct max17042_chip {
+ struct i2c_client *client;
+ struct power_supply battery;
+ struct max17042_platform_data *pdata;
+};
+
+static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+ int ret = i2c_smbus_write_word_data(client, reg, value);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int max17042_read_reg(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_word_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static enum power_supply_property max17042_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int max17042_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max17042_chip *chip = container_of(psy,
+ struct max17042_chip, battery);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_AvgVCELL) * 83;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_SOC) / 256;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devinit max17042_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct max17042_chip *chip;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EIO;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+ chip->pdata = client->dev.platform_data;
+
+ i2c_set_clientdata(client, chip);
+
+ chip->battery.name = "max17042_battery";
+ chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->battery.get_property = max17042_get_property;
+ chip->battery.properties = max17042_battery_props;
+ chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
+
+ ret = power_supply_register(&client->dev, &chip->battery);
+ if (ret) {
+ dev_err(&client->dev, "failed: power supply register\n");
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return ret;
+ }
+
+ if (!chip->pdata->enable_current_sense) {
+ max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
+ max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
+ max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+ }
+
+ return 0;
+}
+
+static int __devexit max17042_remove(struct i2c_client *client)
+{
+ struct max17042_chip *chip = i2c_get_clientdata(client);
+
+ power_supply_unregister(&chip->battery);
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static const struct i2c_device_id max17042_id[] = {
+ { "max17042", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max17042_id);
+
+static struct i2c_driver max17042_i2c_driver = {
+ .driver = {
+ .name = "max17042",
+ },
+ .probe = max17042_probe,
+ .remove = __devexit_p(max17042_remove),
+ .id_table = max17042_id,
+};
+
+static int __init max17042_init(void)
+{
+ return i2c_add_driver(&max17042_i2c_driver);
+}
+module_init(max17042_init);
+
+static void __exit max17042_exit(void)
+{
+ i2c_del_driver(&max17042_i2c_driver);
+}
+module_exit(max17042_exit);
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5bc1dcf7785e..0b0ff3a936a6 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
return ret;
}
+static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
+{
+ uint8_t ec_byte;
+ union power_supply_propval tech;
+ int ret, mfr;
+
+ ret = olpc_bat_get_tech(&tech);
+ if (ret)
+ return ret;
+
+ ec_byte = BAT_ADDR_MFR_TYPE;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+ if (ret)
+ return ret;
+
+ mfr = ec_byte >> 4;
+
+ switch (tech.intval) {
+ case POWER_SUPPLY_TECHNOLOGY_NiMH:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 3000000*.8;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ case POWER_SUPPLY_TECHNOLOGY_LiFe:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 2800000;
+ break;
+ case 2: /* BYD */
+ val->intval = 3100000;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int olpc_bat_get_charge_now(union power_supply_propval *val)
+{
+ uint8_t soc;
+ union power_supply_propval full;
+ int ret;
+
+ ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
+ if (ret)
+ return ret;
+
+ ret = olpc_bat_get_charge_full_design(&full);
+ if (ret)
+ return ret;
+
+ val->intval = soc * (full.intval / 100);
+ return 0;
+}
+
/*********************************************************************
* Battery properties
*********************************************************************/
@@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
else
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ ret = olpc_bat_get_charge_full_design(val);
+ if (ret)
+ return ret;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ ret = olpc_bat_get_charge_now(val);
+ if (ret)
+ return ret;
+ break;
case POWER_SUPPLY_PROP_TEMP:
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
@@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
}
-static enum power_supply_property olpc_bat_props[] = {
+static enum power_supply_property olpc_xo1_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_MANUFACTURER,
@@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
POWER_SUPPLY_PROP_CHARGE_COUNTER,
};
+/* XO-1.5 does not have ambient temperature property */
+static enum power_supply_property olpc_xo15_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
/* EEPROM reading goes completely around the power_supply API, sadly */
#define EEPROM_START 0x20
@@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
static struct platform_device *bat_pdev;
static struct power_supply olpc_bat = {
- .properties = olpc_bat_props,
- .num_properties = ARRAY_SIZE(olpc_bat_props),
.get_property = olpc_bat_get_property,
.use_for_apm = 1,
};
@@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
goto ac_failed;
olpc_bat.name = bat_pdev->name;
+ if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
+ olpc_bat.properties = olpc_xo15_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
+ } else { /* XO-1 */
+ olpc_bat.properties = olpc_xo1_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
+ }
ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
if (ret)
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 91606bb55318..970f7335d3a7 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto success;
create_triggers_failed:
- device_unregister(psy->dev);
+ device_del(dev);
kobject_set_name_failed:
device_add_failed:
- kfree(dev);
+ put_device(dev);
success:
return rc;
}
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
void power_supply_unregister(struct power_supply *psy)
{
- flush_scheduled_work();
+ cancel_work_sync(&psy->changed_work);
power_supply_remove_triggers(psy);
device_unregister(psy->dev);
}
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index fe16b482e912..4255f2358b13 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -1,5 +1,5 @@
/*
- * iPAQ h1930/h1940/rx1950 battery controler driver
+ * iPAQ h1930/h1940/rx1950 battery controller driver
* Copyright (c) Vasily Khoruzhick
* Based on h1940_battery.c by Arnaud Patard
*
@@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
return volt_val + cur_val * impedance / 1000;
}
+static int charge_finished(struct s3c_adc_bat *bat)
+{
+ return bat->pdata->gpio_inverted ?
+ !gpio_get_value(bat->pdata->gpio_charge_finished) :
+ gpio_get_value(bat->pdata->gpio_charge_finished);
+}
+
static int s3c_adc_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
if (bat->cable_plugged &&
((bat->pdata->gpio_charge_finished < 0) ||
- !gpio_get_value(bat->pdata->gpio_charge_finished))) {
+ !charge_finished(bat))) {
lut = bat->pdata->lut_acin;
lut_size = bat->pdata->lut_acin_cnt;
}
@@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
}
} else {
if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
- is_charged = gpio_get_value(
- main_bat.pdata->gpio_charge_finished);
+ is_charged = charge_finished(&main_bat);
if (is_charged) {
if (bat->pdata->disable_charger)
bat->pdata->disable_charger();
@@ -427,5 +433,5 @@ static void __exit s3c_adc_bat_exit(void)
module_exit(s3c_adc_bat_exit);
MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
-MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controler driver");
+MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index ee04936b2db5..53f0d3524fcd 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -332,7 +332,7 @@ static struct {
static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -422,7 +422,7 @@ err_psy_reg_jacket:
err_psy_reg_main:
/* see comment in tosa_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
power_supply_unregister(&tosa_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index 5071d85ec12d..156559e56fa5 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
#ifdef CONFIG_PM
static int wm97xx_bat_suspend(struct device *dev)
{
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
gpio_free(pdata->charge_gpio);
}
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
power_supply_unregister(&bat_ps);
kfree(prop);
return 0;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index 85064a9f649e..e5ed52d71937 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
struct z2_charger *charger = i2c_get_clientdata(client);
struct z2_battery_info *info = charger->info;
- flush_scheduled_work();
+ cancel_work_sync(&charger->bat_work);
power_supply_unregister(&charger->batt_ps);
kfree(charger->batt_ps.properties);
@@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
#ifdef CONFIG_PM
static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
{
- flush_scheduled_work();
+ struct z2_charger *charger = i2c_get_clientdata(client);
+
+ flush_work_sync(&charger->bat_work);
return 0;
}
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 1afe4e03440f..f0d3376b58ba 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -30,6 +30,17 @@ config PPS_DEBUG
messages to the system log. Select this if you are having a
problem with PPS support and want to see more of what is going on.
+config NTP_PPS
+ bool "PPS kernel consumer support"
+ depends on PPS && !NO_HZ
+ help
+ This option adds support for direct in-kernel time
+ syncronization using an external PPS signal.
+
+ It doesn't work on tickless systems at the moment.
+
source drivers/pps/clients/Kconfig
+source drivers/pps/generators/Kconfig
+
endmenu
diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile
index 98960ddd3188..4483eaadaddd 100644
--- a/drivers/pps/Makefile
+++ b/drivers/pps/Makefile
@@ -3,7 +3,8 @@
#
pps_core-y := pps.o kapi.o sysfs.o
+pps_core-$(CONFIG_NTP_PPS) += kc.o
obj-$(CONFIG_PPS) := pps_core.o
-obj-y += clients/
+obj-y += clients/ generators/
ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
index 4e801bd7254f..8520a7f4dd62 100644
--- a/drivers/pps/clients/Kconfig
+++ b/drivers/pps/clients/Kconfig
@@ -22,4 +22,11 @@ config PPS_CLIENT_LDISC
If you say yes here you get support for a PPS source connected
with the CD (Carrier Detect) pin of your serial port.
+config PPS_CLIENT_PARPORT
+ tristate "Parallel port PPS client"
+ depends on PPS && PARPORT
+ help
+ If you say yes here you get support for a PPS source connected
+ with the interrupt pin of your parallel port.
+
endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
index 812c9b19b430..42517da07049 100644
--- a/drivers/pps/clients/Makefile
+++ b/drivers/pps/clients/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
+obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
ifeq ($(CONFIG_PPS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index e7ef5b8186d0..2728469d3884 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
@@ -31,7 +32,7 @@
* Global variables
*/
-static int source;
+static struct pps_device *pps;
static struct timer_list ktimer;
/*
@@ -40,19 +41,14 @@ static struct timer_list ktimer;
static void pps_ktimer_event(unsigned long ptr)
{
- struct timespec __ts;
- struct pps_ktime ts;
+ struct pps_event_time ts;
/* First of all we get the time stamp... */
- getnstimeofday(&__ts);
+ pps_get_ts(&ts);
- pr_info("PPS event at %lu\n", jiffies);
+ dev_info(pps->dev, "PPS event at %lu\n", jiffies);
- /* ... and translate it to PPS time data struct */
- ts.sec = __ts.tv_sec;
- ts.nsec = __ts.tv_nsec;
-
- pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
+ pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
mod_timer(&ktimer, jiffies + HZ);
}
@@ -61,12 +57,11 @@ static void pps_ktimer_event(unsigned long ptr)
* The echo function
*/
-static void pps_ktimer_echo(int source, int event, void *data)
+static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
{
- pr_info("echo %s %s for source %d\n",
+ dev_info(pps->dev, "echo %s %s\n",
event & PPS_CAPTUREASSERT ? "assert" : "",
- event & PPS_CAPTURECLEAR ? "clear" : "",
- source);
+ event & PPS_CAPTURECLEAR ? "clear" : "");
}
/*
@@ -89,30 +84,27 @@ static struct pps_source_info pps_ktimer_info = {
static void __exit pps_ktimer_exit(void)
{
- del_timer_sync(&ktimer);
- pps_unregister_source(source);
+ dev_info(pps->dev, "ktimer PPS source unregistered\n");
- pr_info("ktimer PPS source unregistered\n");
+ del_timer_sync(&ktimer);
+ pps_unregister_source(pps);
}
static int __init pps_ktimer_init(void)
{
- int ret;
-
- ret = pps_register_source(&pps_ktimer_info,
+ pps = pps_register_source(&pps_ktimer_info,
PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
- if (ret < 0) {
- printk(KERN_ERR "cannot register ktimer source\n");
- return ret;
+ if (pps == NULL) {
+ pr_err("cannot register PPS source\n");
+ return -ENOMEM;
}
- source = ret;
setup_timer(&ktimer, pps_ktimer_event, 0);
mod_timer(&ktimer, jiffies + HZ);
- pr_info("ktimer PPS source registered at %d\n", source);
+ dev_info(pps->dev, "ktimer PPS source registered\n");
- return 0;
+ return 0;
}
module_init(pps_ktimer_init);
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 8e1932d29fd4..79451f2dea6a 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
@@ -27,30 +29,18 @@
#define PPS_TTY_MAGIC 0x0001
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
- struct timespec *ts)
+ struct pps_event_time *ts)
{
- int id = (long)tty->disc_data;
- struct timespec __ts;
- struct pps_ktime pps_ts;
-
- /* First of all we get the time stamp... */
- getnstimeofday(&__ts);
-
- /* Does caller give us a timestamp? */
- if (ts) { /* Yes. Let's use it! */
- pps_ts.sec = ts->tv_sec;
- pps_ts.nsec = ts->tv_nsec;
- } else { /* No. Do it ourself! */
- pps_ts.sec = __ts.tv_sec;
- pps_ts.nsec = __ts.tv_nsec;
- }
+ struct pps_device *pps = (struct pps_device *)tty->disc_data;
+
+ BUG_ON(pps == NULL);
/* Now do the PPS event report */
- pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
- NULL);
+ pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
+ PPS_CAPTURECLEAR, NULL);
- pr_debug("PPS %s at %lu on source #%d\n",
- status ? "assert" : "clear", jiffies, id);
+ dev_dbg(pps->dev, "PPS %s at %lu\n",
+ status ? "assert" : "clear", jiffies);
}
static int (*alias_n_tty_open)(struct tty_struct *tty);
@@ -60,6 +50,7 @@ static int pps_tty_open(struct tty_struct *tty)
struct pps_source_info info;
struct tty_driver *drv = tty->driver;
int index = tty->index + drv->name_base;
+ struct pps_device *pps;
int ret;
info.owner = THIS_MODULE;
@@ -70,34 +61,42 @@ static int pps_tty_open(struct tty_struct *tty)
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
PPS_CANWAIT | PPS_TSFMT_TSPEC;
- ret = pps_register_source(&info, PPS_CAPTUREBOTH | \
+ pps = pps_register_source(&info, PPS_CAPTUREBOTH | \
PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
- if (ret < 0) {
+ if (pps == NULL) {
pr_err("cannot register PPS source \"%s\"\n", info.path);
- return ret;
+ return -ENOMEM;
}
- tty->disc_data = (void *)(long)ret;
+ tty->disc_data = pps;
/* Should open N_TTY ldisc too */
ret = alias_n_tty_open(tty);
- if (ret < 0)
- pps_unregister_source((long)tty->disc_data);
+ if (ret < 0) {
+ pr_err("cannot open tty ldisc \"%s\"\n", info.path);
+ goto err_unregister;
+ }
- pr_info("PPS source #%d \"%s\" added\n", ret, info.path);
+ dev_info(pps->dev, "source \"%s\" added\n", info.path);
return 0;
+
+err_unregister:
+ tty->disc_data = NULL;
+ pps_unregister_source(pps);
+ return ret;
}
static void (*alias_n_tty_close)(struct tty_struct *tty);
static void pps_tty_close(struct tty_struct *tty)
{
- int id = (long)tty->disc_data;
+ struct pps_device *pps = (struct pps_device *)tty->disc_data;
- pps_unregister_source(id);
alias_n_tty_close(tty);
- pr_info("PPS source #%d removed\n", id);
+ tty->disc_data = NULL;
+ dev_info(pps->dev, "removed\n");
+ pps_unregister_source(pps);
}
static struct tty_ldisc_ops pps_ldisc_ops;
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
new file mode 100644
index 000000000000..32221efd9ca9
--- /dev/null
+++ b/drivers/pps/clients/pps_parport.c
@@ -0,0 +1,258 @@
+/*
+ * pps_parport.c -- kernel parallel port PPS client
+ *
+ *
+ * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ */
+
+
+/*
+ * TODO:
+ * implement echo over SEL pin
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irqnr.h>
+#include <linux/time.h>
+#include <linux/parport.h>
+#include <linux/pps_kernel.h>
+
+#define DRVDESC "parallel port PPS client"
+
+/* module parameters */
+
+#define CLEAR_WAIT_MAX 100
+#define CLEAR_WAIT_MAX_ERRORS 5
+
+static unsigned int clear_wait = 100;
+MODULE_PARM_DESC(clear_wait,
+ "Maximum number of port reads when polling for signal clear,"
+ " zero turns clear edge capture off entirely");
+module_param(clear_wait, uint, 0);
+
+
+/* internal per port structure */
+struct pps_client_pp {
+ struct pardevice *pardev; /* parport device */
+ struct pps_device *pps; /* PPS device */
+ unsigned int cw; /* port clear timeout */
+ unsigned int cw_err; /* number of timeouts */
+};
+
+static inline int signal_is_set(struct parport *port)
+{
+ return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0;
+}
+
+/* parport interrupt handler */
+static void parport_irq(void *handle)
+{
+ struct pps_event_time ts_assert, ts_clear;
+ struct pps_client_pp *dev = handle;
+ struct parport *port = dev->pardev->port;
+ unsigned int i;
+ unsigned long flags;
+
+ /* first of all we get the time stamp... */
+ pps_get_ts(&ts_assert);
+
+ if (dev->cw == 0)
+ /* clear edge capture disabled */
+ goto out_assert;
+
+ /* try capture the clear edge */
+
+ /* We have to disable interrupts here. The idea is to prevent
+ * other interrupts on the same processor to introduce random
+ * lags while polling the port. Reading from IO port is known
+ * to take approximately 1us while other interrupt handlers can
+ * take much more potentially.
+ *
+ * Interrupts won't be disabled for a long time because the
+ * number of polls is limited by clear_wait parameter which is
+ * kept rather low. So it should never be an issue.
+ */
+ local_irq_save(flags);
+ /* check the signal (no signal means the pulse is lost this time) */
+ if (!signal_is_set(port)) {
+ local_irq_restore(flags);
+ dev_err(dev->pps->dev, "lost the signal\n");
+ goto out_assert;
+ }
+
+ /* poll the port until the signal is unset */
+ for (i = dev->cw; i; i--)
+ if (!signal_is_set(port)) {
+ pps_get_ts(&ts_clear);
+ local_irq_restore(flags);
+ dev->cw_err = 0;
+ goto out_both;
+ }
+ local_irq_restore(flags);
+
+ /* timeout */
+ dev->cw_err++;
+ if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
+ dev_err(dev->pps->dev, "disabled clear edge capture after %d"
+ " timeouts\n", dev->cw_err);
+ dev->cw = 0;
+ dev->cw_err = 0;
+ }
+
+out_assert:
+ /* fire assert event */
+ pps_event(dev->pps, &ts_assert,
+ PPS_CAPTUREASSERT, NULL);
+ return;
+
+out_both:
+ /* fire assert event */
+ pps_event(dev->pps, &ts_assert,
+ PPS_CAPTUREASSERT, NULL);
+ /* fire clear event */
+ pps_event(dev->pps, &ts_clear,
+ PPS_CAPTURECLEAR, NULL);
+ return;
+}
+
+/* the PPS echo function */
+static void pps_echo(struct pps_device *pps, int event, void *data)
+{
+ dev_info(pps->dev, "echo %s %s\n",
+ event & PPS_CAPTUREASSERT ? "assert" : "",
+ event & PPS_CAPTURECLEAR ? "clear" : "");
+}
+
+static void parport_attach(struct parport *port)
+{
+ struct pps_client_pp *device;
+ struct pps_source_info info = {
+ .name = KBUILD_MODNAME,
+ .path = "",
+ .mode = PPS_CAPTUREBOTH | \
+ PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
+ PPS_ECHOASSERT | PPS_ECHOCLEAR | \
+ PPS_CANWAIT | PPS_TSFMT_TSPEC,
+ .echo = pps_echo,
+ .owner = THIS_MODULE,
+ .dev = NULL
+ };
+
+ device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL);
+ if (!device) {
+ pr_err("memory allocation failed, not attaching\n");
+ return;
+ }
+
+ device->pardev = parport_register_device(port, KBUILD_MODNAME,
+ NULL, NULL, parport_irq, 0, device);
+ if (!device->pardev) {
+ pr_err("couldn't register with %s\n", port->name);
+ goto err_free;
+ }
+
+ if (parport_claim_or_block(device->pardev) < 0) {
+ pr_err("couldn't claim %s\n", port->name);
+ goto err_unregister_dev;
+ }
+
+ device->pps = pps_register_source(&info,
+ PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
+ if (device->pps == NULL) {
+ pr_err("couldn't register PPS source\n");
+ goto err_release_dev;
+ }
+
+ device->cw = clear_wait;
+
+ port->ops->enable_irq(port);
+
+ pr_info("attached to %s\n", port->name);
+
+ return;
+
+err_release_dev:
+ parport_release(device->pardev);
+err_unregister_dev:
+ parport_unregister_device(device->pardev);
+err_free:
+ kfree(device);
+}
+
+static void parport_detach(struct parport *port)
+{
+ struct pardevice *pardev = port->cad;
+ struct pps_client_pp *device;
+
+ /* FIXME: oooh, this is ugly! */
+ if (strcmp(pardev->name, KBUILD_MODNAME))
+ /* not our port */
+ return;
+
+ device = pardev->private;
+
+ port->ops->disable_irq(port);
+ pps_unregister_source(device->pps);
+ parport_release(pardev);
+ parport_unregister_device(pardev);
+ kfree(device);
+}
+
+static struct parport_driver pps_parport_driver = {
+ .name = KBUILD_MODNAME,
+ .attach = parport_attach,
+ .detach = parport_detach,
+};
+
+/* module staff */
+
+static int __init pps_parport_init(void)
+{
+ int ret;
+
+ pr_info(DRVDESC "\n");
+
+ if (clear_wait > CLEAR_WAIT_MAX) {
+ pr_err("clear_wait value should be not greater"
+ " then %d\n", CLEAR_WAIT_MAX);
+ return -EINVAL;
+ }
+
+ ret = parport_register_driver(&pps_parport_driver);
+ if (ret) {
+ pr_err("unable to register with parport\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit pps_parport_exit(void)
+{
+ parport_unregister_driver(&pps_parport_driver);
+}
+
+module_init(pps_parport_init);
+module_exit(pps_parport_exit);
+
+MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
+MODULE_DESCRIPTION(DRVDESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig
new file mode 100644
index 000000000000..f3a73dd77660
--- /dev/null
+++ b/drivers/pps/generators/Kconfig
@@ -0,0 +1,13 @@
+#
+# PPS generators configuration
+#
+
+comment "PPS generators support"
+
+config PPS_GENERATOR_PARPORT
+ tristate "Parallel port PPS signal generator"
+ depends on PARPORT
+ help
+ If you say yes here you get support for a PPS signal generator which
+ utilizes STROBE pin of a parallel port to send PPS signals. It uses
+ parport abstraction layer and hrtimers to precisely control the signal.
diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile
new file mode 100644
index 000000000000..303304a6b8ec
--- /dev/null
+++ b/drivers/pps/generators/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for PPS generators.
+#
+
+obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o
+
+ifeq ($(CONFIG_PPS_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c
new file mode 100644
index 000000000000..5c32f8dacf56
--- /dev/null
+++ b/drivers/pps/generators/pps_gen_parport.c
@@ -0,0 +1,282 @@
+/*
+ * pps_gen_parport.c -- kernel parallel port PPS signal generator
+ *
+ *
+ * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ */
+
+
+/*
+ * TODO:
+ * fix issues when realtime clock is adjusted in a leap
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/parport.h>
+
+#define DRVDESC "parallel port PPS signal generator"
+
+#define SIGNAL 0
+#define NO_SIGNAL PARPORT_CONTROL_STROBE
+
+/* module parameters */
+
+#define SEND_DELAY_MAX 100000
+
+static unsigned int send_delay = 30000;
+MODULE_PARM_DESC(delay,
+ "Delay between setting and dropping the signal (ns)");
+module_param_named(delay, send_delay, uint, 0);
+
+
+#define SAFETY_INTERVAL 3000 /* set the hrtimer earlier for safety (ns) */
+
+/* internal per port structure */
+struct pps_generator_pp {
+ struct pardevice *pardev; /* parport device */
+ struct hrtimer timer;
+ long port_write_time; /* calibrated port write time (ns) */
+};
+
+static struct pps_generator_pp device = {
+ .pardev = NULL,
+};
+
+static int attached;
+
+/* calibrated time between a hrtimer event and the reaction */
+static long hrtimer_error = SAFETY_INTERVAL;
+
+/* the kernel hrtimer event */
+static enum hrtimer_restart hrtimer_event(struct hrtimer *timer)
+{
+ struct timespec expire_time, ts1, ts2, ts3, dts;
+ struct pps_generator_pp *dev;
+ struct parport *port;
+ long lim, delta;
+ unsigned long flags;
+
+ /* We have to disable interrupts here. The idea is to prevent
+ * other interrupts on the same processor to introduce random
+ * lags while polling the clock. getnstimeofday() takes <1us on
+ * most machines while other interrupt handlers can take much
+ * more potentially.
+ *
+ * NB: approx time with blocked interrupts =
+ * send_delay + 3 * SAFETY_INTERVAL
+ */
+ local_irq_save(flags);
+
+ /* first of all we get the time stamp... */
+ getnstimeofday(&ts1);
+ expire_time = ktime_to_timespec(hrtimer_get_softexpires(timer));
+ dev = container_of(timer, struct pps_generator_pp, timer);
+ lim = NSEC_PER_SEC - send_delay - dev->port_write_time;
+
+ /* check if we are late */
+ if (expire_time.tv_sec != ts1.tv_sec || ts1.tv_nsec > lim) {
+ local_irq_restore(flags);
+ pr_err("we are late this time %ld.%09ld\n",
+ ts1.tv_sec, ts1.tv_nsec);
+ goto done;
+ }
+
+ /* busy loop until the time is right for an assert edge */
+ do {
+ getnstimeofday(&ts2);
+ } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
+
+ /* set the signal */
+ port = dev->pardev->port;
+ port->ops->write_control(port, SIGNAL);
+
+ /* busy loop until the time is right for a clear edge */
+ lim = NSEC_PER_SEC - dev->port_write_time;
+ do {
+ getnstimeofday(&ts2);
+ } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
+
+ /* unset the signal */
+ port->ops->write_control(port, NO_SIGNAL);
+
+ getnstimeofday(&ts3);
+
+ local_irq_restore(flags);
+
+ /* update calibrated port write time */
+ dts = timespec_sub(ts3, ts2);
+ dev->port_write_time =
+ (dev->port_write_time + timespec_to_ns(&dts)) >> 1;
+
+done:
+ /* update calibrated hrtimer error */
+ dts = timespec_sub(ts1, expire_time);
+ delta = timespec_to_ns(&dts);
+ /* If the new error value is bigger then the old, use the new
+ * value, if not then slowly move towards the new value. This
+ * way it should be safe in bad conditions and efficient in
+ * good conditions.
+ */
+ if (delta >= hrtimer_error)
+ hrtimer_error = delta;
+ else
+ hrtimer_error = (3 * hrtimer_error + delta) >> 2;
+
+ /* update the hrtimer expire time */
+ hrtimer_set_expires(timer,
+ ktime_set(expire_time.tv_sec + 1,
+ NSEC_PER_SEC - (send_delay +
+ dev->port_write_time + SAFETY_INTERVAL +
+ 2 * hrtimer_error)));
+
+ return HRTIMER_RESTART;
+}
+
+/* calibrate port write time */
+#define PORT_NTESTS_SHIFT 5
+static void calibrate_port(struct pps_generator_pp *dev)
+{
+ struct parport *port = dev->pardev->port;
+ int i;
+ long acc = 0;
+
+ for (i = 0; i < (1 << PORT_NTESTS_SHIFT); i++) {
+ struct timespec a, b;
+ unsigned long irq_flags;
+
+ local_irq_save(irq_flags);
+ getnstimeofday(&a);
+ port->ops->write_control(port, NO_SIGNAL);
+ getnstimeofday(&b);
+ local_irq_restore(irq_flags);
+
+ b = timespec_sub(b, a);
+ acc += timespec_to_ns(&b);
+ }
+
+ dev->port_write_time = acc >> PORT_NTESTS_SHIFT;
+ pr_info("port write takes %ldns\n", dev->port_write_time);
+}
+
+static inline ktime_t next_intr_time(struct pps_generator_pp *dev)
+{
+ struct timespec ts;
+
+ getnstimeofday(&ts);
+
+ return ktime_set(ts.tv_sec +
+ ((ts.tv_nsec > 990 * NSEC_PER_MSEC) ? 1 : 0),
+ NSEC_PER_SEC - (send_delay +
+ dev->port_write_time + 3 * SAFETY_INTERVAL));
+}
+
+static void parport_attach(struct parport *port)
+{
+ if (attached) {
+ /* we already have a port */
+ return;
+ }
+
+ device.pardev = parport_register_device(port, KBUILD_MODNAME,
+ NULL, NULL, NULL, 0, &device);
+ if (!device.pardev) {
+ pr_err("couldn't register with %s\n", port->name);
+ return;
+ }
+
+ if (parport_claim_or_block(device.pardev) < 0) {
+ pr_err("couldn't claim %s\n", port->name);
+ goto err_unregister_dev;
+ }
+
+ pr_info("attached to %s\n", port->name);
+ attached = 1;
+
+ calibrate_port(&device);
+
+ hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ device.timer.function = hrtimer_event;
+#ifdef CONFIG_PREEMPT_RT
+ /* hrtimer interrupt will run in the interrupt context with this */
+ device.timer.irqsafe = 1;
+#endif
+
+ hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS);
+
+ return;
+
+err_unregister_dev:
+ parport_unregister_device(device.pardev);
+}
+
+static void parport_detach(struct parport *port)
+{
+ if (port->cad != device.pardev)
+ return; /* not our port */
+
+ hrtimer_cancel(&device.timer);
+ parport_release(device.pardev);
+ parport_unregister_device(device.pardev);
+}
+
+static struct parport_driver pps_gen_parport_driver = {
+ .name = KBUILD_MODNAME,
+ .attach = parport_attach,
+ .detach = parport_detach,
+};
+
+/* module staff */
+
+static int __init pps_gen_parport_init(void)
+{
+ int ret;
+
+ pr_info(DRVDESC "\n");
+
+ if (send_delay > SEND_DELAY_MAX) {
+ pr_err("delay value should be not greater"
+ " then %d\n", SEND_DELAY_MAX);
+ return -EINVAL;
+ }
+
+ ret = parport_register_driver(&pps_gen_parport_driver);
+ if (ret) {
+ pr_err("unable to register with parport\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit pps_gen_parport_exit(void)
+{
+ parport_unregister_driver(&pps_gen_parport_driver);
+ pr_info("hrtimer avg error is %ldns\n", hrtimer_error);
+}
+
+module_init(pps_gen_parport_init);
+module_exit(pps_gen_parport_exit);
+
+MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
+MODULE_DESCRIPTION(DRVDESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 1aa02db3ff4e..cba1b43f7519 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -19,24 +19,20 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/timex.h>
#include <linux/spinlock.h>
-#include <linux/idr.h>
#include <linux/fs.h>
#include <linux/pps_kernel.h>
#include <linux/slab.h>
-/*
- * Global variables
- */
-
-DEFINE_SPINLOCK(pps_idr_lock);
-DEFINE_IDR(pps_idr);
+#include "kc.h"
/*
* Local functions
@@ -60,60 +56,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
* Exported functions
*/
-/* pps_get_source - find a PPS source
- * @source: the PPS source ID.
- *
- * This function is used to find an already registered PPS source into the
- * system.
- *
- * The function returns NULL if found nothing, otherwise it returns a pointer
- * to the PPS source data struct (the refcounter is incremented by 1).
- */
-
-struct pps_device *pps_get_source(int source)
-{
- struct pps_device *pps;
- unsigned long flags;
-
- spin_lock_irqsave(&pps_idr_lock, flags);
-
- pps = idr_find(&pps_idr, source);
- if (pps != NULL)
- atomic_inc(&pps->usage);
-
- spin_unlock_irqrestore(&pps_idr_lock, flags);
-
- return pps;
-}
-
-/* pps_put_source - free the PPS source data
- * @pps: a pointer to the PPS source.
- *
- * This function is used to free a PPS data struct if its refcount is 0.
- */
-
-void pps_put_source(struct pps_device *pps)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pps_idr_lock, flags);
- BUG_ON(atomic_read(&pps->usage) == 0);
-
- if (!atomic_dec_and_test(&pps->usage)) {
- pps = NULL;
- goto exit;
- }
-
- /* No more reference to the PPS source. We can safely remove the
- * PPS data struct.
- */
- idr_remove(&pps_idr, pps->id);
-
-exit:
- spin_unlock_irqrestore(&pps_idr_lock, flags);
- kfree(pps);
-}
-
/* pps_register_source - add a PPS source in the system
* @info: the PPS info struct
* @default_params: the default PPS parameters of the new source
@@ -122,31 +64,31 @@ exit:
* source is described by info's fields and it will have, as default PPS
* parameters, the ones specified into default_params.
*
- * The function returns, in case of success, the PPS source ID.
+ * The function returns, in case of success, the PPS device. Otherwise NULL.
*/
-int pps_register_source(struct pps_source_info *info, int default_params)
+struct pps_device *pps_register_source(struct pps_source_info *info,
+ int default_params)
{
struct pps_device *pps;
- int id;
int err;
/* Sanity checks */
if ((info->mode & default_params) != default_params) {
- printk(KERN_ERR "pps: %s: unsupported default parameters\n",
+ pr_err("%s: unsupported default parameters\n",
info->name);
err = -EINVAL;
goto pps_register_source_exit;
}
if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
info->echo == NULL) {
- printk(KERN_ERR "pps: %s: echo function is not defined\n",
+ pr_err("%s: echo function is not defined\n",
info->name);
err = -EINVAL;
goto pps_register_source_exit;
}
if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
- printk(KERN_ERR "pps: %s: unspecified time format\n",
+ pr_err("%s: unspecified time format\n",
info->name);
err = -EINVAL;
goto pps_register_source_exit;
@@ -168,94 +110,48 @@ int pps_register_source(struct pps_source_info *info, int default_params)
init_waitqueue_head(&pps->queue);
spin_lock_init(&pps->lock);
- atomic_set(&pps->usage, 1);
-
- /* Get new ID for the new PPS source */
- if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
- err = -ENOMEM;
- goto kfree_pps;
- }
-
- spin_lock_irq(&pps_idr_lock);
-
- /* Now really allocate the PPS source.
- * After idr_get_new() calling the new source will be freely available
- * into the kernel.
- */
- err = idr_get_new(&pps_idr, pps, &id);
- if (err < 0) {
- spin_unlock_irq(&pps_idr_lock);
- goto kfree_pps;
- }
-
- id = id & MAX_ID_MASK;
- if (id >= PPS_MAX_SOURCES) {
- spin_unlock_irq(&pps_idr_lock);
-
- printk(KERN_ERR "pps: %s: too many PPS sources in the system\n",
- info->name);
- err = -EBUSY;
- goto free_idr;
- }
- pps->id = id;
-
- spin_unlock_irq(&pps_idr_lock);
/* Create the char device */
err = pps_register_cdev(pps);
if (err < 0) {
- printk(KERN_ERR "pps: %s: unable to create char device\n",
+ pr_err("%s: unable to create char device\n",
info->name);
- goto free_idr;
+ goto kfree_pps;
}
- pr_info("new PPS source %s at ID %d\n", info->name, id);
+ dev_info(pps->dev, "new PPS source %s\n", info->name);
- return id;
-
-free_idr:
- spin_lock_irq(&pps_idr_lock);
- idr_remove(&pps_idr, id);
- spin_unlock_irq(&pps_idr_lock);
+ return pps;
kfree_pps:
kfree(pps);
pps_register_source_exit:
- printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
+ pr_err("%s: unable to register source\n", info->name);
- return err;
+ return NULL;
}
EXPORT_SYMBOL(pps_register_source);
/* pps_unregister_source - remove a PPS source from the system
- * @source: the PPS source ID
+ * @pps: the PPS source
*
* This function is used to remove a previously registered PPS source from
* the system.
*/
-void pps_unregister_source(int source)
+void pps_unregister_source(struct pps_device *pps)
{
- struct pps_device *pps;
-
- spin_lock_irq(&pps_idr_lock);
- pps = idr_find(&pps_idr, source);
-
- if (!pps) {
- BUG();
- spin_unlock_irq(&pps_idr_lock);
- return;
- }
- spin_unlock_irq(&pps_idr_lock);
-
+ pps_kc_remove(pps);
pps_unregister_cdev(pps);
- pps_put_source(pps);
+
+ /* don't have to kfree(pps) here because it will be done on
+ * device destruction */
}
EXPORT_SYMBOL(pps_unregister_source);
/* pps_event - register a PPS event into the system
- * @source: the PPS source ID
+ * @pps: the PPS device
* @ts: the event timestamp
* @event: the event type
* @data: userdef pointer
@@ -263,78 +159,72 @@ EXPORT_SYMBOL(pps_unregister_source);
* This function is used by each PPS client in order to register a new
* PPS event into the system (it's usually called inside an IRQ handler).
*
- * If an echo function is associated with the PPS source it will be called
+ * If an echo function is associated with the PPS device it will be called
* as:
- * pps->info.echo(source, event, data);
+ * pps->info.echo(pps, event, data);
*/
-
-void pps_event(int source, struct pps_ktime *ts, int event, void *data)
+void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
+ void *data)
{
- struct pps_device *pps;
unsigned long flags;
int captured = 0;
+ struct pps_ktime ts_real;
- if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
- printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
- event, source);
- return;
- }
+ /* check event type */
+ BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
- pps = pps_get_source(source);
- if (!pps)
- return;
+ dev_dbg(pps->dev, "PPS event at %ld.%09ld\n",
+ ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
- pr_debug("PPS event on source %d at %llu.%06u\n",
- pps->id, (unsigned long long) ts->sec, ts->nsec);
+ timespec_to_pps_ktime(&ts_real, ts->ts_real);
spin_lock_irqsave(&pps->lock, flags);
/* Must call the echo function? */
if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
- pps->info.echo(source, event, data);
+ pps->info.echo(pps, event, data);
/* Check the event */
pps->current_mode = pps->params.mode;
- if ((event & PPS_CAPTUREASSERT) &
- (pps->params.mode & PPS_CAPTUREASSERT)) {
+ if (event & pps->params.mode & PPS_CAPTUREASSERT) {
/* We have to add an offset? */
if (pps->params.mode & PPS_OFFSETASSERT)
- pps_add_offset(ts, &pps->params.assert_off_tu);
+ pps_add_offset(&ts_real,
+ &pps->params.assert_off_tu);
/* Save the time stamp */
- pps->assert_tu = *ts;
+ pps->assert_tu = ts_real;
pps->assert_sequence++;
- pr_debug("capture assert seq #%u for source %d\n",
- pps->assert_sequence, source);
+ dev_dbg(pps->dev, "capture assert seq #%u\n",
+ pps->assert_sequence);
captured = ~0;
}
- if ((event & PPS_CAPTURECLEAR) &
- (pps->params.mode & PPS_CAPTURECLEAR)) {
+ if (event & pps->params.mode & PPS_CAPTURECLEAR) {
/* We have to add an offset? */
if (pps->params.mode & PPS_OFFSETCLEAR)
- pps_add_offset(ts, &pps->params.clear_off_tu);
+ pps_add_offset(&ts_real,
+ &pps->params.clear_off_tu);
/* Save the time stamp */
- pps->clear_tu = *ts;
+ pps->clear_tu = ts_real;
pps->clear_sequence++;
- pr_debug("capture clear seq #%u for source %d\n",
- pps->clear_sequence, source);
+ dev_dbg(pps->dev, "capture clear seq #%u\n",
+ pps->clear_sequence);
captured = ~0;
}
- /* Wake up iif captured somthing */
+ pps_kc_event(pps, ts, event);
+
+ /* Wake up if captured something */
if (captured) {
- pps->go = ~0;
- wake_up_interruptible(&pps->queue);
+ pps->last_ev++;
+ wake_up_interruptible_all(&pps->queue);
kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&pps->lock, flags);
-
- /* Now we can release the PPS source for (possible) deregistration */
- pps_put_source(pps);
}
EXPORT_SYMBOL(pps_event);
diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c
new file mode 100644
index 000000000000..079e930b1938
--- /dev/null
+++ b/drivers/pps/kc.c
@@ -0,0 +1,122 @@
+/*
+ * PPS kernel consumer API
+ *
+ * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pps_kernel.h>
+
+#include "kc.h"
+
+/*
+ * Global variables
+ */
+
+/* state variables to bind kernel consumer */
+DEFINE_SPINLOCK(pps_kc_hardpps_lock);
+/* PPS API (RFC 2783): current source and mode for kernel consumer */
+struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */
+int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
+
+/* pps_kc_bind - control PPS kernel consumer binding
+ * @pps: the PPS source
+ * @bind_args: kernel consumer bind parameters
+ *
+ * This function is used to bind or unbind PPS kernel consumer according to
+ * supplied parameters. Should not be called in interrupt context.
+ */
+int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
+{
+ /* Check if another consumer is already bound */
+ spin_lock_irq(&pps_kc_hardpps_lock);
+
+ if (bind_args->edge == 0)
+ if (pps_kc_hardpps_dev == pps) {
+ pps_kc_hardpps_mode = 0;
+ pps_kc_hardpps_dev = NULL;
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+ dev_info(pps->dev, "unbound kernel"
+ " consumer\n");
+ } else {
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+ dev_err(pps->dev, "selected kernel consumer"
+ " is not bound\n");
+ return -EINVAL;
+ }
+ else
+ if (pps_kc_hardpps_dev == NULL ||
+ pps_kc_hardpps_dev == pps) {
+ pps_kc_hardpps_mode = bind_args->edge;
+ pps_kc_hardpps_dev = pps;
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+ dev_info(pps->dev, "bound kernel consumer: "
+ "edge=0x%x\n", bind_args->edge);
+ } else {
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+ dev_err(pps->dev, "another kernel consumer"
+ " is already bound\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* pps_kc_remove - unbind kernel consumer on PPS source removal
+ * @pps: the PPS source
+ *
+ * This function is used to disable kernel consumer on PPS source removal
+ * if this source was bound to PPS kernel consumer. Can be called on any
+ * source safely. Should not be called in interrupt context.
+ */
+void pps_kc_remove(struct pps_device *pps)
+{
+ spin_lock_irq(&pps_kc_hardpps_lock);
+ if (pps == pps_kc_hardpps_dev) {
+ pps_kc_hardpps_mode = 0;
+ pps_kc_hardpps_dev = NULL;
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+ dev_info(pps->dev, "unbound kernel consumer"
+ " on device removal\n");
+ } else
+ spin_unlock_irq(&pps_kc_hardpps_lock);
+}
+
+/* pps_kc_event - call hardpps() on PPS event
+ * @pps: the PPS source
+ * @ts: PPS event timestamp
+ * @event: PPS event edge
+ *
+ * This function calls hardpps() when an event from bound PPS source occurs.
+ */
+void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
+ int event)
+{
+ unsigned long flags;
+
+ /* Pass some events to kernel consumer if activated */
+ spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
+ if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
+ hardpps(&ts->ts_real, &ts->ts_raw);
+ spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
+}
diff --git a/drivers/pps/kc.h b/drivers/pps/kc.h
new file mode 100644
index 000000000000..d296fcd0a175
--- /dev/null
+++ b/drivers/pps/kc.h
@@ -0,0 +1,46 @@
+/*
+ * PPS kernel consumer API header
+ *
+ * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef LINUX_PPS_KC_H
+#define LINUX_PPS_KC_H
+
+#include <linux/errno.h>
+#include <linux/pps_kernel.h>
+
+#ifdef CONFIG_NTP_PPS
+
+extern int pps_kc_bind(struct pps_device *pps,
+ struct pps_bind_args *bind_args);
+extern void pps_kc_remove(struct pps_device *pps);
+extern void pps_kc_event(struct pps_device *pps,
+ struct pps_event_time *ts, int event);
+
+
+#else /* CONFIG_NTP_PPS */
+
+static inline int pps_kc_bind(struct pps_device *pps,
+ struct pps_bind_args *bind_args) { return -EOPNOTSUPP; }
+static inline void pps_kc_remove(struct pps_device *pps) {}
+static inline void pps_kc_event(struct pps_device *pps,
+ struct pps_event_time *ts, int event) {}
+
+#endif /* CONFIG_NTP_PPS */
+
+#endif /* LINUX_PPS_KC_H */
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index ca5183bdad85..2baadd21b7a6 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
@@ -26,9 +27,13 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/idr.h>
+#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/pps_kernel.h>
+#include <linux/slab.h>
+
+#include "kc.h"
/*
* Local variables
@@ -37,6 +42,9 @@
static dev_t pps_devt;
static struct class *pps_class;
+static DEFINE_MUTEX(pps_idr_lock);
+static DEFINE_IDR(pps_idr);
+
/*
* Char device methods
*/
@@ -61,15 +69,13 @@ static long pps_cdev_ioctl(struct file *file,
{
struct pps_device *pps = file->private_data;
struct pps_kparams params;
- struct pps_fdata fdata;
- unsigned long ticks;
void __user *uarg = (void __user *) arg;
int __user *iuarg = (int __user *) arg;
int err;
switch (cmd) {
case PPS_GETPARAMS:
- pr_debug("PPS_GETPARAMS: source %d\n", pps->id);
+ dev_dbg(pps->dev, "PPS_GETPARAMS\n");
spin_lock_irq(&pps->lock);
@@ -85,7 +91,7 @@ static long pps_cdev_ioctl(struct file *file,
break;
case PPS_SETPARAMS:
- pr_debug("PPS_SETPARAMS: source %d\n", pps->id);
+ dev_dbg(pps->dev, "PPS_SETPARAMS\n");
/* Check the capabilities */
if (!capable(CAP_SYS_TIME))
@@ -95,14 +101,14 @@ static long pps_cdev_ioctl(struct file *file,
if (err)
return -EFAULT;
if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
- pr_debug("capture mode unspecified (%x)\n",
+ dev_dbg(pps->dev, "capture mode unspecified (%x)\n",
params.mode);
return -EINVAL;
}
/* Check for supported capabilities */
if ((params.mode & ~pps->info.mode) != 0) {
- pr_debug("unsupported capabilities (%x)\n",
+ dev_dbg(pps->dev, "unsupported capabilities (%x)\n",
params.mode);
return -EINVAL;
}
@@ -115,7 +121,7 @@ static long pps_cdev_ioctl(struct file *file,
/* Restore the read only parameters */
if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
/* section 3.3 of RFC 2783 interpreted */
- pr_debug("time format unspecified (%x)\n",
+ dev_dbg(pps->dev, "time format unspecified (%x)\n",
params.mode);
pps->params.mode |= PPS_TSFMT_TSPEC;
}
@@ -128,7 +134,7 @@ static long pps_cdev_ioctl(struct file *file,
break;
case PPS_GETCAP:
- pr_debug("PPS_GETCAP: source %d\n", pps->id);
+ dev_dbg(pps->dev, "PPS_GETCAP\n");
err = put_user(pps->info.mode, iuarg);
if (err)
@@ -136,20 +142,26 @@ static long pps_cdev_ioctl(struct file *file,
break;
- case PPS_FETCH:
- pr_debug("PPS_FETCH: source %d\n", pps->id);
+ case PPS_FETCH: {
+ struct pps_fdata fdata;
+ unsigned int ev;
+
+ dev_dbg(pps->dev, "PPS_FETCH\n");
err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
if (err)
return -EFAULT;
- pps->go = 0;
+ ev = pps->last_ev;
/* Manage the timeout */
if (fdata.timeout.flags & PPS_TIME_INVALID)
- err = wait_event_interruptible(pps->queue, pps->go);
+ err = wait_event_interruptible(pps->queue,
+ ev != pps->last_ev);
else {
- pr_debug("timeout %lld.%09d\n",
+ unsigned long ticks;
+
+ dev_dbg(pps->dev, "timeout %lld.%09d\n",
(long long) fdata.timeout.sec,
fdata.timeout.nsec);
ticks = fdata.timeout.sec * HZ;
@@ -157,7 +169,9 @@ static long pps_cdev_ioctl(struct file *file,
if (ticks != 0) {
err = wait_event_interruptible_timeout(
- pps->queue, pps->go, ticks);
+ pps->queue,
+ ev != pps->last_ev,
+ ticks);
if (err == 0)
return -ETIMEDOUT;
}
@@ -165,7 +179,7 @@ static long pps_cdev_ioctl(struct file *file,
/* Check for pending signals */
if (err == -ERESTARTSYS) {
- pr_debug("pending signal caught\n");
+ dev_dbg(pps->dev, "pending signal caught\n");
return -EINTR;
}
@@ -185,10 +199,44 @@ static long pps_cdev_ioctl(struct file *file,
return -EFAULT;
break;
+ }
+ case PPS_KC_BIND: {
+ struct pps_bind_args bind_args;
+
+ dev_dbg(pps->dev, "PPS_KC_BIND\n");
+
+ /* Check the capabilities */
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ if (copy_from_user(&bind_args, uarg,
+ sizeof(struct pps_bind_args)))
+ return -EFAULT;
+ /* Check for supported capabilities */
+ if ((bind_args.edge & ~pps->info.mode) != 0) {
+ dev_err(pps->dev, "unsupported capabilities (%x)\n",
+ bind_args.edge);
+ return -EINVAL;
+ }
+
+ /* Validate parameters roughly */
+ if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
+ (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
+ bind_args.consumer != PPS_KC_HARDPPS) {
+ dev_err(pps->dev, "invalid kernel consumer bind"
+ " parameters (%x)\n", bind_args.edge);
+ return -EINVAL;
+ }
+
+ err = pps_kc_bind(pps, &bind_args);
+ if (err < 0)
+ return err;
+
+ break;
+ }
default:
return -ENOTTY;
- break;
}
return 0;
@@ -198,12 +246,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
{
struct pps_device *pps = container_of(inode->i_cdev,
struct pps_device, cdev);
- int found;
-
- found = pps_get_source(pps->id) != 0;
- if (!found)
- return -ENODEV;
-
file->private_data = pps;
return 0;
@@ -211,11 +253,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
static int pps_cdev_release(struct inode *inode, struct file *file)
{
- struct pps_device *pps = file->private_data;
-
- /* Free the PPS source and wake up (possible) deregistration */
- pps_put_source(pps);
-
return 0;
}
@@ -233,25 +270,67 @@ static const struct file_operations pps_cdev_fops = {
.release = pps_cdev_release,
};
+static void pps_device_destruct(struct device *dev)
+{
+ struct pps_device *pps = dev_get_drvdata(dev);
+
+ /* release id here to protect others from using it while it's
+ * still in use */
+ mutex_lock(&pps_idr_lock);
+ idr_remove(&pps_idr, pps->id);
+ mutex_unlock(&pps_idr_lock);
+
+ kfree(dev);
+ kfree(pps);
+}
+
int pps_register_cdev(struct pps_device *pps)
{
int err;
+ dev_t devt;
+
+ mutex_lock(&pps_idr_lock);
+ /* Get new ID for the new PPS source */
+ if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
+ mutex_unlock(&pps_idr_lock);
+ return -ENOMEM;
+ }
+
+ /* Now really allocate the PPS source.
+ * After idr_get_new() calling the new source will be freely available
+ * into the kernel.
+ */
+ err = idr_get_new(&pps_idr, pps, &pps->id);
+ mutex_unlock(&pps_idr_lock);
+
+ if (err < 0)
+ return err;
+
+ pps->id &= MAX_ID_MASK;
+ if (pps->id >= PPS_MAX_SOURCES) {
+ pr_err("%s: too many PPS sources in the system\n",
+ pps->info.name);
+ err = -EBUSY;
+ goto free_idr;
+ }
+
+ devt = MKDEV(MAJOR(pps_devt), pps->id);
- pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
cdev_init(&pps->cdev, &pps_cdev_fops);
pps->cdev.owner = pps->info.owner;
- err = cdev_add(&pps->cdev, pps->devno, 1);
+ err = cdev_add(&pps->cdev, devt, 1);
if (err) {
- printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n",
+ pr_err("%s: failed to add char device %d:%d\n",
pps->info.name, MAJOR(pps_devt), pps->id);
- return err;
+ goto free_idr;
}
- pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL,
+ pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
"pps%d", pps->id);
if (IS_ERR(pps->dev))
goto del_cdev;
- dev_set_drvdata(pps->dev, pps);
+
+ pps->dev->release = pps_device_destruct;
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
MAJOR(pps_devt), pps->id);
@@ -261,12 +340,17 @@ int pps_register_cdev(struct pps_device *pps)
del_cdev:
cdev_del(&pps->cdev);
+free_idr:
+ mutex_lock(&pps_idr_lock);
+ idr_remove(&pps_idr, pps->id);
+ mutex_unlock(&pps_idr_lock);
+
return err;
}
void pps_unregister_cdev(struct pps_device *pps)
{
- device_destroy(pps_class, pps->devno);
+ device_destroy(pps_class, pps->dev->devt);
cdev_del(&pps->cdev);
}
@@ -286,14 +370,14 @@ static int __init pps_init(void)
pps_class = class_create(THIS_MODULE, "pps");
if (!pps_class) {
- printk(KERN_ERR "pps: failed to allocate class\n");
+ pr_err("failed to allocate class\n");
return -ENOMEM;
}
pps_class->dev_attrs = pps_attrs;
err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
if (err < 0) {
- printk(KERN_ERR "pps: failed to allocate char device region\n");
+ pr_err("failed to allocate char device region\n");
goto remove_class;
}
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index ccea15c11c19..50cb1e1b4a12 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_PS3_VUART) += ps3-vuart.o
obj-$(CONFIG_PS3_PS3AV) += ps3av_mod.o
-ps3av_mod-objs += ps3av.o ps3av_cmd.o
+ps3av_mod-y := ps3av.o ps3av_cmd.o
obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 1eb82c4c712e..467e82bd0929 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -46,7 +46,6 @@ static void rio_init_em(struct rio_dev *rdev);
DEFINE_SPINLOCK(rio_global_list_lock);
static int next_destid = 0;
-static int next_switchid = 0;
static int next_net = 0;
static int next_comptag = 1;
@@ -378,12 +377,30 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
struct rio_dev *rdev;
struct rio_switch *rswitch = NULL;
int result, rdid;
+ size_t size;
+ u32 swpinfo = 0;
- rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
+ size = sizeof(struct rio_dev);
+ if (rio_mport_read_config_32(port, destid, hopcount,
+ RIO_PEF_CAR, &result))
+ return NULL;
+
+ if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) {
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_SWP_INFO_CAR, &swpinfo);
+ if (result & RIO_PEF_SWITCH) {
+ size += (RIO_GET_TOTAL_PORTS(swpinfo) *
+ sizeof(rswitch->nextdev[0])) + sizeof(*rswitch);
+ }
+ }
+
+ rdev = kzalloc(size, GFP_KERNEL);
if (!rdev)
return NULL;
rdev->net = net;
+ rdev->pef = result;
+ rdev->swpinfo = swpinfo;
rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
&result);
rdev->did = result >> 16;
@@ -397,8 +414,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR,
&result);
rdev->asm_rev = result >> 16;
- rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
- &rdev->pef);
if (rdev->pef & RIO_PEF_EXT_FEATURES) {
rdev->efptr = result & 0xffff;
rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
@@ -408,11 +423,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
hopcount, RIO_EFB_ERR_MGMNT);
}
- if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) {
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_SWP_INFO_CAR, &rdev->swpinfo);
- }
-
rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
&rdev->src_ops);
rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
@@ -427,6 +437,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rio_mport_write_config_32(port, destid, hopcount,
RIO_COMPONENT_TAG_CSR, next_comptag);
rdev->comp_tag = next_comptag++;
+ } else {
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_COMPONENT_TAG_CSR,
+ &rdev->comp_tag);
}
if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
@@ -437,21 +451,20 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
next_destid++;
} else
rdev->destid = rio_get_device_id(port, destid, hopcount);
- } else
- /* Switch device has an associated destID */
- rdev->destid = RIO_INVALID_DESTID;
+
+ rdev->hopcount = 0xff;
+ } else {
+ /* Switch device has an associated destID which
+ * will be adjusted later
+ */
+ rdev->destid = destid;
+ rdev->hopcount = hopcount;
+ }
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
- rswitch = kzalloc(sizeof(*rswitch) +
- RIO_GET_TOTAL_PORTS(rdev->swpinfo) *
- sizeof(rswitch->nextdev[0]),
- GFP_KERNEL);
- if (!rswitch)
- goto cleanup;
- rswitch->switchid = next_switchid;
- rswitch->hopcount = hopcount;
- rswitch->destid = destid;
+ rswitch = rdev->rswitch;
+ rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
rswitch->port_ok = 0;
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
@@ -462,15 +475,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size);
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
- rdev->rswitch = rswitch;
- rswitch->rdev = rdev;
dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
- rdev->rswitch->switchid);
+ rswitch->switchid);
rio_switch_init(rdev, do_enum);
- if (do_enum && rdev->rswitch->clr_table)
- rdev->rswitch->clr_table(port, destid, hopcount,
- RIO_GLOBAL_TABLE);
+ if (do_enum && rswitch->clr_table)
+ rswitch->clr_table(port, destid, hopcount,
+ RIO_GLOBAL_TABLE);
list_add_tail(&rswitch->node, &rio_switches);
@@ -506,10 +517,9 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
return rdev;
cleanup:
- if (rswitch) {
+ if (rswitch->route_table)
kfree(rswitch->route_table);
- kfree(rswitch);
- }
+
kfree(rdev);
return NULL;
}
@@ -632,8 +642,7 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
/**
* rio_route_add_entry- Add a route entry to a switch routing table
- * @mport: Master port to send transaction
- * @rswitch: Switch device
+ * @rdev: RIO device
* @table: Routing table ID
* @route_destid: Destination ID to be routed
* @route_port: Port number to be routed
@@ -647,31 +656,31 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
* on failure.
*/
static int
-rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
+rio_route_add_entry(struct rio_dev *rdev,
u16 table, u16 route_destid, u8 route_port, int lock)
{
int rc;
if (lock) {
- rc = rio_lock_device(mport, rswitch->destid,
- rswitch->hopcount, 1000);
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
if (rc)
return rc;
}
- rc = rswitch->add_entry(mport, rswitch->destid,
- rswitch->hopcount, table,
- route_destid, route_port);
+ rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
if (lock)
- rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
return rc;
}
/**
* rio_route_get_entry- Read a route entry in a switch routing table
- * @mport: Master port to send transaction
- * @rswitch: Switch device
+ * @rdev: RIO device
* @table: Routing table ID
* @route_destid: Destination ID to be routed
* @route_port: Pointer to read port number into
@@ -685,23 +694,24 @@ rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
* on failure.
*/
static int
-rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
+rio_route_get_entry(struct rio_dev *rdev, u16 table,
u16 route_destid, u8 *route_port, int lock)
{
int rc;
if (lock) {
- rc = rio_lock_device(mport, rswitch->destid,
- rswitch->hopcount, 1000);
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
if (rc)
return rc;
}
- rc = rswitch->get_entry(mport, rswitch->destid,
- rswitch->hopcount, table,
- route_destid, route_port);
+ rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
if (lock)
- rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
return rc;
}
@@ -809,16 +819,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
return -1;
if (rio_is_switch(rdev)) {
- next_switchid++;
sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo);
- rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
+ rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
port->host_deviceid, sw_inport, 0);
rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
for (destid = 0; destid < next_destid; destid++) {
if (destid == port->host_deviceid)
continue;
- rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
+ rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
destid, sw_inport, 0);
rdev->rswitch->route_table[destid] = sw_inport;
}
@@ -850,8 +859,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
"RIO: scanning device on port %d\n",
port_num);
rdev->rswitch->port_ok |= (1 << port_num);
- rio_route_add_entry(port, rdev->rswitch,
- RIO_GLOBAL_TABLE,
+ rio_route_add_entry(rdev, RIO_GLOBAL_TABLE,
RIO_ANY_DESTID(port->sys_size),
port_num, 0);
@@ -865,7 +873,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
destid < next_destid; destid++) {
if (destid == port->host_deviceid)
continue;
- rio_route_add_entry(port, rdev->rswitch,
+ rio_route_add_entry(rdev,
RIO_GLOBAL_TABLE,
destid,
port_num,
@@ -904,7 +912,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
next_destid++;
}
- rdev->rswitch->destid = sw_destid;
+ rdev->destid = sw_destid;
} else
pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
rio_name(rdev), rdev->vid, rdev->did);
@@ -941,7 +949,7 @@ static int rio_enum_complete(struct rio_mport *port)
*/
static int __devinit
rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
- u8 hopcount)
+ u8 hopcount, struct rio_dev *prev, int prev_port)
{
u8 port_num, route_port;
struct rio_dev *rdev;
@@ -951,14 +959,15 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
+ rdev->prev = prev;
+ if (prev && rio_is_switch(prev))
+ prev->rswitch->nextdev[prev_port] = rdev;
} else
return -1;
if (rio_is_switch(rdev)) {
- next_switchid++;
-
/* Associated destid is how we accessed this switch */
- rdev->rswitch->destid = destid;
+ rdev->destid = destid;
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
@@ -981,7 +990,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
for (ndestid = 0;
ndestid < RIO_ANY_DESTID(port->sys_size);
ndestid++) {
- rio_route_get_entry(port, rdev->rswitch,
+ rio_route_get_entry(rdev,
RIO_GLOBAL_TABLE,
ndestid,
&route_port, 0);
@@ -992,8 +1001,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
if (ndestid == RIO_ANY_DESTID(port->sys_size))
continue;
rio_unlock_device(port, destid, hopcount);
- if (rio_disc_peer
- (net, port, ndestid, hopcount + 1) < 0)
+ if (rio_disc_peer(net, port, ndestid,
+ hopcount + 1, rdev, port_num) < 0)
return -1;
}
}
@@ -1069,14 +1078,14 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
*/
static void rio_update_route_tables(struct rio_mport *port)
{
- struct rio_dev *rdev;
+ struct rio_dev *rdev, *swrdev;
struct rio_switch *rswitch;
u8 sport;
u16 destid;
list_for_each_entry(rdev, &rio_devices, global_list) {
- destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid;
+ destid = rdev->destid;
list_for_each_entry(rswitch, &rio_switches, node) {
@@ -1084,14 +1093,16 @@ static void rio_update_route_tables(struct rio_mport *port)
continue;
if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
+ swrdev = sw_to_rio_dev(rswitch);
+
/* Skip if destid ends in empty switch*/
- if (rswitch->destid == destid)
+ if (swrdev->destid == destid)
continue;
- sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo);
+ sport = RIO_GET_PORT_NUM(swrdev->swpinfo);
if (rswitch->add_entry) {
- rio_route_add_entry(port, rswitch,
+ rio_route_add_entry(swrdev,
RIO_GLOBAL_TABLE, destid,
sport, 0);
rswitch->route_table[destid] = sport;
@@ -1203,21 +1214,20 @@ static void rio_build_route_tables(void)
list_for_each_entry(rdev, &rio_devices, global_list)
if (rio_is_switch(rdev)) {
- rio_lock_device(rdev->net->hport, rdev->rswitch->destid,
- rdev->rswitch->hopcount, 1000);
+ rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
for (i = 0;
i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
i++) {
- if (rio_route_get_entry
- (rdev->net->hport, rdev->rswitch,
- RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
+ if (rio_route_get_entry(rdev,
+ RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
continue;
rdev->rswitch->route_table[i] = sport;
}
rio_unlock_device(rdev->net->hport,
- rdev->rswitch->destid,
- rdev->rswitch->hopcount);
+ rdev->destid,
+ rdev->hopcount);
}
}
@@ -1284,7 +1294,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
mport->host_deviceid);
if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
- 0) < 0) {
+ 0, NULL, 0) < 0) {
printk(KERN_INFO
"RIO: master port %d device has failed discovery\n",
mport->id);
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 137ed93ee33f..76b41853a877 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -217,7 +217,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
err = device_create_bin_file(&rdev->dev, &rio_config_attr);
- if (!err && rdev->rswitch) {
+ if (!err && (rdev->pef & RIO_PEF_SWITCH)) {
err = device_create_file(&rdev->dev, &dev_attr_routes);
if (!err && rdev->rswitch->sw_sysfs)
err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
@@ -239,7 +239,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
{
device_remove_bin_file(&rdev->dev, &rio_config_attr);
- if (rdev->rswitch) {
+ if (rdev->pef & RIO_PEF_SWITCH) {
device_remove_file(&rdev->dev, &dev_attr_routes);
if (rdev->rswitch->sw_sysfs)
rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 68cf0c99138a..cc2a3b74d0f0 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -471,16 +471,9 @@ exit:
*/
int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
{
- u8 hopcount = 0xff;
- u16 destid = rdev->destid;
u32 regval;
- if (rdev->rswitch) {
- destid = rdev->rswitch->destid;
- hopcount = rdev->rswitch->hopcount;
- }
-
- rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
&regval);
if (lock)
@@ -488,7 +481,7 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
else
regval &= ~RIO_PORT_N_CTL_LOCKOUT;
- rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
regval);
return 0;
@@ -507,7 +500,7 @@ static int
rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
{
u32 result;
- int p_port, dstid, rc = -EIO;
+ int p_port, rc = -EIO;
struct rio_dev *prev = NULL;
/* Find switch with failed RIO link */
@@ -522,9 +515,7 @@ rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
if (prev == NULL)
goto err_out;
- dstid = (rdev->pef & RIO_PEF_SWITCH) ?
- rdev->rswitch->destid : rdev->destid;
- p_port = prev->rswitch->route_table[dstid];
+ p_port = prev->rswitch->route_table[rdev->destid];
if (p_port != RIO_INVALID_ROUTE) {
pr_debug("RIO: link failed on [%s]-P%d\n",
@@ -567,15 +558,8 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
*/
static int rio_chk_dev_access(struct rio_dev *rdev)
{
- u8 hopcount = 0xff;
- u16 destid = rdev->destid;
-
- if (rdev->rswitch) {
- destid = rdev->rswitch->destid;
- hopcount = rdev->rswitch->hopcount;
- }
-
- return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount);
+ return rio_mport_chk_dev_access(rdev->net->hport,
+ rdev->destid, rdev->hopcount);
}
/**
@@ -588,23 +572,20 @@ static int rio_chk_dev_access(struct rio_dev *rdev)
static int
rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 regval;
int checkcount;
if (lnkresp) {
/* Read from link maintenance response register
* to clear valid bit */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
&regval);
udelay(50);
}
/* Issue Input-status command */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
RIO_MNT_REQ_CMD_IS);
@@ -615,7 +596,7 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
checkcount = 3;
while (checkcount--) {
udelay(50);
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
&regval);
if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
@@ -635,15 +616,12 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
*/
static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum];
u32 regval;
u32 far_ackid, far_linkstat, near_ackid;
if (err_status == 0)
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
&err_status);
@@ -661,7 +639,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
pnum, regval);
far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
&regval);
pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
@@ -679,9 +657,8 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
/* Align near outstanding/outbound ackIDs with
* far inbound.
*/
- rio_mport_write_config_32(mport, destid,
- hopcount, rdev->phys_efptr +
- RIO_PORT_N_ACK_STS_CSR(pnum),
+ rio_write_config_32(rdev,
+ rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
(near_ackid << 24) |
(far_ackid << 8) | far_ackid);
/* Align far outstanding/outbound ackIDs with
@@ -698,7 +675,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
}
rd_err:
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
&err_status);
pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
@@ -710,7 +687,7 @@ rd_err:
RIO_GET_PORT_NUM(nextdev->swpinfo), NULL);
udelay(50);
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
&err_status);
pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
@@ -730,13 +707,10 @@ rd_err:
int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
{
struct rio_dev *rdev;
- struct rio_mport *mport;
- u8 hopcount;
- u16 destid;
u32 err_status, em_perrdet, em_ltlerrdet;
int rc, portnum;
- rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
+ rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
if (rdev == NULL) {
/* Device removed or enumeration error */
pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
@@ -800,17 +774,13 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
return 0;
}
- mport = rdev->net->hport;
- destid = rdev->rswitch->destid;
- hopcount = rdev->rswitch->hopcount;
-
/*
* Process the port-write notification from switch
*/
if (rdev->rswitch->em_handle)
rdev->rswitch->em_handle(rdev, portnum);
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
&err_status);
pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
@@ -840,7 +810,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
rdev->rswitch->port_ok &= ~(1 << portnum);
rio_set_port_lockout(rdev, portnum, 1);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr +
RIO_PORT_N_ACK_STS_CSR(portnum),
RIO_PORT_N_ACK_CLEAR);
@@ -851,28 +821,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
}
}
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
if (em_perrdet) {
pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
portnum, em_perrdet);
/* Clear EM Port N Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
}
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
if (em_ltlerrdet) {
pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
em_ltlerrdet);
/* Clear EM L/T Layer Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
}
/* Clear remaining error bits and Port-Write Pending bit */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
err_status);
@@ -1159,11 +1129,11 @@ int __devinit rio_init_mports(void)
list_for_each_entry(port, &rio_mports, node) {
if (!request_mem_region(port->iores.start,
- port->iores.end - port->iores.start,
+ resource_size(&port->iores),
port->name)) {
printk(KERN_ERR
"RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
- (u64)port->iores.start, (u64)port->iores.end - 1);
+ (u64)port->iores.start, (u64)port->iores.end);
rc = -ENOMEM;
goto out;
}
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
index 0bb871cb5c40..095016a9dec1 100644
--- a/drivers/rapidio/switches/idt_gen2.c
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -209,9 +209,6 @@ idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
static int
idtg2_em_init(struct rio_dev *rdev)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 regval;
int i, tmp;
@@ -220,29 +217,25 @@ idtg2_em_init(struct rio_dev *rdev)
* All standard EM configuration should be performed at upper level.
*/
- pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount);
+ pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
/* Set Port-Write info CSR: PRIO=3 and CRF=1 */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_PW_INFO_CSR, 0x0000e000);
+ rio_write_config_32(rdev, IDT_PW_INFO_CSR, 0x0000e000);
/*
* Configure LT LAYER error reporting.
*/
/* Enable standard (RIO.p8) error reporting */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_LT_ERR_REPORT_EN,
+ rio_write_config_32(rdev, IDT_LT_ERR_REPORT_EN,
REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR |
REM_LTL_ERR_UNSUPTR);
/* Use Port-Writes for LT layer error reporting.
* Enable per-port reset
*/
- rio_mport_read_config_32(mport, destid, hopcount,
- IDT_DEV_CTRL_1, &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_DEV_CTRL_1,
+ rio_read_config_32(rdev, IDT_DEV_CTRL_1, &regval);
+ rio_write_config_32(rdev, IDT_DEV_CTRL_1,
regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH);
/*
@@ -250,45 +243,40 @@ idtg2_em_init(struct rio_dev *rdev)
*/
/* Report all RIO.p8 errors supported by device */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037);
+ rio_write_config_32(rdev, IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037);
/* Configure reporting of implementation specific errors/events */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED);
+ rio_write_config_32(rdev, IDT_PORT_ISERR_REPORT_EN_BC,
+ IDT_PORT_INIT_TX_ACQUIRED);
/* Use Port-Writes for port error reporting and enable error logging */
tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo);
for (i = 0; i < tmp; i++) {
- rio_mport_read_config_32(mport, destid, hopcount,
- IDT_PORT_OPS(i), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev, IDT_PORT_OPS(i), &regval);
+ rio_write_config_32(rdev,
IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW |
IDT_PORT_OPS_PL_ELOG |
IDT_PORT_OPS_LL_ELOG |
IDT_PORT_OPS_LT_ELOG);
}
/* Overwrite error log if full */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR);
+ rio_write_config_32(rdev, IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR);
/*
* Configure LANE error reporting.
*/
/* Disable line error reporting */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_LANE_ERR_REPORT_EN_BC, 0);
+ rio_write_config_32(rdev, IDT_LANE_ERR_REPORT_EN_BC, 0);
/* Use Port-Writes for lane error reporting (when enabled)
* (do per-lane update because lanes may have different configuration)
*/
tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16;
for (i = 0; i < tmp; i++) {
- rio_mport_read_config_32(mport, destid, hopcount,
- IDT_LANE_CTRL(i), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_LANE_CTRL(i), regval | IDT_LANE_CTRL_GENPW);
+ rio_read_config_32(rdev, IDT_LANE_CTRL(i), &regval);
+ rio_write_config_32(rdev, IDT_LANE_CTRL(i),
+ regval | IDT_LANE_CTRL_GENPW);
}
/*
@@ -296,41 +284,32 @@ idtg2_em_init(struct rio_dev *rdev)
*/
/* Disable JTAG and I2C Error capture */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_AUX_PORT_ERR_CAP_EN, 0);
+ rio_write_config_32(rdev, IDT_AUX_PORT_ERR_CAP_EN, 0);
/* Disable JTAG and I2C Error reporting/logging */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_AUX_ERR_REPORT_EN, 0);
+ rio_write_config_32(rdev, IDT_AUX_ERR_REPORT_EN, 0);
/* Disable Port-Write notification from JTAG */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_JTAG_CTRL, 0);
+ rio_write_config_32(rdev, IDT_JTAG_CTRL, 0);
/* Disable Port-Write notification from I2C */
- rio_mport_read_config_32(mport, destid, hopcount,
- IDT_I2C_MCTRL, &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_I2C_MCTRL,
- regval & ~IDT_I2C_MCTRL_GENPW);
+ rio_read_config_32(rdev, IDT_I2C_MCTRL, &regval);
+ rio_write_config_32(rdev, IDT_I2C_MCTRL, regval & ~IDT_I2C_MCTRL_GENPW);
/*
* Configure CFG_BLK error reporting.
*/
/* Disable Configuration Block error capture */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_CFGBLK_ERR_CAPTURE_EN, 0);
+ rio_write_config_32(rdev, IDT_CFGBLK_ERR_CAPTURE_EN, 0);
/* Disable Port-Writes for Configuration Block error reporting */
- rio_mport_read_config_32(mport, destid, hopcount,
- IDT_CFGBLK_ERR_REPORT, &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_CFGBLK_ERR_REPORT,
- regval & ~IDT_CFGBLK_ERR_REPORT_GENPW);
+ rio_read_config_32(rdev, IDT_CFGBLK_ERR_REPORT, &regval);
+ rio_write_config_32(rdev, IDT_CFGBLK_ERR_REPORT,
+ regval & ~IDT_CFGBLK_ERR_REPORT_GENPW);
/* set TVAL = ~50us */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
return 0;
@@ -339,18 +318,15 @@ idtg2_em_init(struct rio_dev *rdev)
static int
idtg2_em_handler(struct rio_dev *rdev, u8 portnum)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 regval, em_perrdet, em_ltlerrdet;
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
if (em_ltlerrdet) {
/* Service Logical/Transport Layer Error(s) */
if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) {
/* Implementation specific error reported */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
IDT_ISLTL_ADDRESS_CAP, &regval);
pr_debug("RIO: %s Implementation Specific LTL errors" \
@@ -358,13 +334,12 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum)
rio_name(rdev), em_ltlerrdet, regval);
/* Clear implementation specific address capture CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
- IDT_ISLTL_ADDRESS_CAP, 0);
+ rio_write_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, 0);
}
}
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
if (em_perrdet) {
/* Service Port-Level Error(s) */
@@ -372,14 +347,14 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum)
/* Implementation Specific port error reported */
/* Get IS errors reported */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
IDT_PORT_ISERR_DET(portnum), &regval);
pr_debug("RIO: %s Implementation Specific Port" \
" errors 0x%x\n", rio_name(rdev), regval);
/* Clear all implementation specific events */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
IDT_PORT_ISERR_DET(portnum), 0);
}
}
@@ -391,14 +366,10 @@ static ssize_t
idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
{
struct rio_dev *rdev = to_rio_dev(dev);
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
ssize_t len = 0;
u32 regval;
- while (!rio_mport_read_config_32(mport, destid, hopcount,
- IDT_ERR_RD, &regval)) {
+ while (!rio_read_config_32(rdev, IDT_ERR_RD, &regval)) {
if (!regval) /* 0 = end of log */
break;
len += snprintf(buf + len, PAGE_SIZE - len,
@@ -445,3 +416,5 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init);
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
index fc9f6374f759..3a971077e7bf 100644
--- a/drivers/rapidio/switches/idtcps.c
+++ b/drivers/rapidio/switches/idtcps.c
@@ -117,10 +117,6 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
-
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
rdev->rswitch->add_entry = idtcps_route_add_entry;
rdev->rswitch->get_entry = idtcps_route_get_entry;
@@ -132,7 +128,7 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
if (do_enum) {
/* set TVAL = ~50us */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
}
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
index b9a389b9f812..3994c00aa01f 100644
--- a/drivers/rapidio/switches/tsi568.c
+++ b/drivers/rapidio/switches/tsi568.c
@@ -113,22 +113,17 @@ tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
static int
tsi568_em_init(struct rio_dev *rdev)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 regval;
int portnum;
- pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
+ pr_debug("TSI568 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
/* Make sure that Port-Writes are disabled (for all ports) */
for (portnum = 0;
portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
- rio_mport_read_config_32(mport, destid, hopcount,
- TSI568_SP_MODE(portnum), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- TSI568_SP_MODE(portnum),
- regval | TSI568_SP_MODE_PW_DIS);
+ rio_read_config_32(rdev, TSI568_SP_MODE(portnum), &regval);
+ rio_write_config_32(rdev, TSI568_SP_MODE(portnum),
+ regval | TSI568_SP_MODE_PW_DIS);
}
return 0;
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
index 2003fb63c404..1a62934bfebc 100644
--- a/drivers/rapidio/switches/tsi57x.c
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -158,48 +158,45 @@ tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
static int
tsi57x_em_init(struct rio_dev *rdev)
{
- struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 regval;
int portnum;
- pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
+ pr_debug("TSI578 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
for (portnum = 0;
portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
/* Make sure that Port-Writes are enabled (for all ports) */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
TSI578_SP_MODE(portnum), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
TSI578_SP_MODE(portnum),
regval & ~TSI578_SP_MODE_PW_DIS);
/* Clear all pending interrupts */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr +
RIO_PORT_N_ERR_STS_CSR(portnum),
&regval);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr +
RIO_PORT_N_ERR_STS_CSR(portnum),
regval & 0x07120214);
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
TSI578_SP_INT_STATUS(portnum), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
TSI578_SP_INT_STATUS(portnum),
regval & 0x000700bd);
/* Enable all interrupts to allow ports to send a port-write */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
TSI578_SP_CTL_INDEP(portnum), &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
TSI578_SP_CTL_INDEP(portnum),
regval | 0x000b0000);
/* Skip next (odd) port if the current port is in x4 mode */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
&regval);
if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
@@ -207,7 +204,7 @@ tsi57x_em_init(struct rio_dev *rdev)
}
/* set TVAL = ~50us */
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8);
return 0;
@@ -217,14 +214,12 @@ static int
tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
{
struct rio_mport *mport = rdev->net->hport;
- u16 destid = rdev->rswitch->destid;
- u8 hopcount = rdev->rswitch->hopcount;
u32 intstat, err_status;
int sendcount, checkcount;
u8 route_port;
u32 regval;
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
&err_status);
@@ -232,15 +227,15 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
(err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
RIO_PORT_N_ERR_STS_PW_INP_ES))) {
/* Remove any queued packets by locking/unlocking port */
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
&regval);
if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
regval | RIO_PORT_N_CTL_LOCKOUT);
udelay(50);
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
regval);
}
@@ -248,7 +243,7 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
/* Read from link maintenance response register to clear
* valid bit
*/
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
&regval);
@@ -257,13 +252,12 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
*/
sendcount = 3;
while (sendcount) {
- rio_mport_write_config_32(mport, destid, hopcount,
+ rio_write_config_32(rdev,
TSI578_SP_CS_TX(portnum), 0x40fc8000);
checkcount = 3;
while (checkcount--) {
udelay(50);
- rio_mport_read_config_32(
- mport, destid, hopcount,
+ rio_read_config_32(rdev,
rdev->phys_efptr +
RIO_PORT_N_MNT_RSP_CSR(portnum),
&regval);
@@ -277,25 +271,23 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
exit_es:
/* Clear implementation specific error status bits */
- rio_mport_read_config_32(mport, destid, hopcount,
- TSI578_SP_INT_STATUS(portnum), &intstat);
+ rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), &intstat);
pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
- destid, hopcount, portnum, intstat);
+ rdev->destid, rdev->hopcount, portnum, intstat);
if (intstat & 0x10000) {
- rio_mport_read_config_32(mport, destid, hopcount,
+ rio_read_config_32(rdev,
TSI578_SP_LUT_PEINF(portnum), &regval);
regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
route_port = rdev->rswitch->route_table[regval];
pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
rio_name(rdev), portnum, regval);
- tsi57x_route_add_entry(mport, destid, hopcount,
+ tsi57x_route_add_entry(mport, rdev->destid, rdev->hopcount,
RIO_GLOBAL_TABLE, regval, route_port);
}
- rio_mport_write_config_32(mport, destid, hopcount,
- TSI578_SP_INT_STATUS(portnum),
- intstat & 0x000700bd);
+ rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum),
+ intstat & 0x000700bd);
return 0;
}
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 2ce2eb71d0f5..dd6308499bd4 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -249,7 +249,7 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
}
static int pm8607_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
uint8_t val, mask;
@@ -263,6 +263,7 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
ret = choose_voltage(rdev, min_uV, max_uV);
if (ret < 0)
return -EINVAL;
+ *selector = ret;
val = (uint8_t)(ret << info->vol_shift);
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index dd30e883d4a7..e1d943619ab8 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -186,13 +186,25 @@ config REGULATOR_PCAP
This driver provides support for the voltage regulators of the
PCAP2 PMIC.
+config REGULATOR_MC13XXX_CORE
+ tristate
+
config REGULATOR_MC13783
tristate "Support regulators on Freescale MC13783 PMIC"
depends on MFD_MC13783
+ select REGULATOR_MC13XXX_CORE
help
Say y here to support the regulators found on the Freescale MC13783
PMIC.
+config REGULATOR_MC13892
+ tristate "Support regulators on Freescale MC13892 PMIC"
+ depends on MFD_MC13XXX
+ select REGULATOR_MC13XXX_CORE
+ help
+ Say y here to support the regulators found on the Freescale MC13892
+ PMIC.
+
config REGULATOR_AB3100
tristate "ST-Ericsson AB3100 Regulator functions"
depends on AB3100_CORE
@@ -250,5 +262,15 @@ config REGULATOR_TPS6586X
help
This driver supports TPS6586X voltage regulator chips.
+config REGULATOR_TPS6524X
+ tristate "TI TPS6524X Power regulators"
+ depends on SPI
+ help
+ This driver supports TPS6524X voltage regulator chips. TPS6524X
+ provides three step-down converters and two general-purpose LDO
+ voltage regulators. This device is interfaced using a customized
+ serial interface currently supported on the sequencer serial
+ port controller.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index bff815736780..0b5e88c2b8d7 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,10 +30,13 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
+obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
+obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index b349266a43de..ed6feaf9398d 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -362,7 +362,8 @@ static int ab3100_get_best_voltage_index(struct regulator_dev *reg,
}
static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct ab3100_regulator *abreg = reg->reg_data;
u8 regval;
@@ -373,6 +374,8 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
if (bestindex < 0)
return bestindex;
+ *selector = bestindex;
+
err = abx500_get_register_interruptible(abreg->dev, 0,
abreg->regreg, &regval);
if (err) {
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index db6b70f20511..d9a052c53aec 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -3,18 +3,13 @@
*
* License Terms: GNU General Public License v2
*
- * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
*
* AB8500 peripheral regulators
*
- * AB8500 supports the following regulators,
- * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT,
- * VAUX1/2/3, VANA
- *
- * for DB8500 cut 1.0 and previous versions of the silicon, all accesses
- * to registers are through the DB8500 SPI. In cut 1.1 onwards, these
- * accesses are through the DB8500 PRCMU I2C
- *
+ * AB8500 supports the following regulators:
+ * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -28,38 +23,37 @@
/**
* struct ab8500_regulator_info - ab8500 regulator information
+ * @dev: device pointer
* @desc: regulator description
- * @ab8500: ab8500 parent
* @regulator_dev: regulator device
* @max_uV: maximum voltage (for variable voltage supplies)
* @min_uV: minimum voltage (for variable voltage supplies)
* @fixed_uV: typical voltage (for fixed voltage supplies)
* @update_bank: bank to control on/off
* @update_reg: register to control on/off
- * @mask: mask to enable/disable regulator
- * @enable: bits to enable the regulator in normal(high power) mode
+ * @update_mask: mask to enable/disable regulator
+ * @update_val_enable: bits to enable the regulator in normal (high power) mode
* @voltage_bank: bank to control regulator voltage
* @voltage_reg: register to control regulator voltage
* @voltage_mask: mask to control regulator voltage
- * @supported_voltages: supported voltage table
+ * @voltages: supported voltage table
* @voltages_len: number of supported voltages for the regulator
*/
struct ab8500_regulator_info {
struct device *dev;
struct regulator_desc desc;
- struct ab8500 *ab8500;
struct regulator_dev *regulator;
int max_uV;
int min_uV;
int fixed_uV;
u8 update_bank;
u8 update_reg;
- u8 mask;
- u8 enable;
+ u8 update_mask;
+ u8 update_val_enable;
u8 voltage_bank;
u8 voltage_reg;
u8 voltage_mask;
- int const *supported_voltages;
+ int const *voltages;
int voltages_len;
};
@@ -83,6 +77,17 @@ static const int ldo_vauxn_voltages[] = {
3300000,
};
+static const int ldo_vaux3_voltages[] = {
+ 1200000,
+ 1500000,
+ 1800000,
+ 2100000,
+ 2500000,
+ 2750000,
+ 2790000,
+ 2910000,
+};
+
static const int ldo_vintcore_voltages[] = {
1200000,
1225000,
@@ -95,57 +100,80 @@ static const int ldo_vintcore_voltages[] = {
static int ab8500_regulator_enable(struct regulator_dev *rdev)
{
- int regulator_id, ret;
+ int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
ret = abx500_mask_and_set_register_interruptible(info->dev,
- info->update_bank, info->update_reg, info->mask, info->enable);
+ info->update_bank, info->update_reg,
+ info->update_mask, info->update_val_enable);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set enable bits for regulator\n");
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, info->update_val_enable);
+
return ret;
}
static int ab8500_regulator_disable(struct regulator_dev *rdev)
{
- int regulator_id, ret;
+ int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
ret = abx500_mask_and_set_register_interruptible(info->dev,
- info->update_bank, info->update_reg, info->mask, 0x0);
+ info->update_bank, info->update_reg,
+ info->update_mask, 0x0);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set disable bits for regulator\n");
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, 0x0);
+
return ret;
}
static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
{
- int regulator_id, ret;
+ int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- u8 value;
+ u8 regval;
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
ret = abx500_get_register_interruptible(info->dev,
- info->update_bank, info->update_reg, &value);
+ info->update_bank, info->update_reg, &regval);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't read 0x%x register\n", info->update_reg);
return ret;
}
- if (value & info->mask)
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, regval);
+
+ if (regval & info->update_mask)
return true;
else
return false;
@@ -153,12 +181,12 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
{
- int regulator_id;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
/* return the uV for the fixed regulators */
if (info->fixed_uV)
@@ -167,33 +195,40 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
if (selector >= info->voltages_len)
return -EINVAL;
- return info->supported_voltages[selector];
+ return info->voltages[selector];
}
static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
{
- int regulator_id, ret;
+ int ret, val;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- u8 value;
+ u8 regval;
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
- ret = abx500_get_register_interruptible(info->dev, info->voltage_bank,
- info->voltage_reg, &value);
+ ret = abx500_get_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg, &regval);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't read voltage reg for regulator\n");
return ret;
}
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
/* vintcore has a different layout */
- value &= info->voltage_mask;
- if (regulator_id == AB8500_LDO_INTCORE)
- ret = info->supported_voltages[value >> 0x3];
+ val = regval & info->voltage_mask;
+ if (info->desc.id == AB8500_LDO_INTCORE)
+ ret = info->voltages[val >> 0x3];
else
- ret = info->supported_voltages[value];
+ ret = info->voltages[val];
return ret;
}
@@ -206,8 +241,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
/* check the supported voltage */
for (i = 0; i < info->voltages_len; i++) {
- if ((info->supported_voltages[i] >= min_uV) &&
- (info->supported_voltages[i] <= max_uV))
+ if ((info->voltages[i] >= min_uV) &&
+ (info->voltages[i] <= max_uV))
return i;
}
@@ -215,14 +250,17 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
}
static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
- int regulator_id, ret;
+ int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
/* get the appropriate voltages within the range */
ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
@@ -232,14 +270,23 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
return ret;
}
+ *selector = ret;
+
/* set the registers for the request */
+ regval = (u8)ret;
ret = abx500_mask_and_set_register_interruptible(info->dev,
- info->voltage_bank, info->voltage_reg,
- info->voltage_mask, (u8)ret);
+ info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
if (ret < 0)
dev_err(rdev_get_dev(rdev),
"couldn't set voltage reg for regulator\n");
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
return ret;
}
@@ -254,17 +301,17 @@ static struct regulator_ops ab8500_regulator_ops = {
static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
{
- int regulator_id;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- regulator_id = rdev_get_id(rdev);
- if (regulator_id >= AB8500_NUM_REGULATORS)
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
+ }
return info->fixed_uV;
}
-static struct regulator_ops ab8500_ldo_fixed_ops = {
+static struct regulator_ops ab8500_regulator_fixed_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
@@ -272,88 +319,197 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
.list_voltage = ab8500_list_voltage,
};
-#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \
- reg_enable, volt_bank, volt_reg, volt_mask, \
- voltages, len_volts) \
-{ \
- .desc = { \
- .name = "LDO-" #_id, \
- .ops = &ab8500_regulator_ops, \
- .type = REGULATOR_VOLTAGE, \
- .id = AB8500_LDO_##_id, \
- .owner = THIS_MODULE, \
- }, \
- .min_uV = (min) * 1000, \
- .max_uV = (max) * 1000, \
- .update_bank = bank, \
- .update_reg = reg, \
- .mask = reg_mask, \
- .enable = reg_enable, \
- .voltage_bank = volt_bank, \
- .voltage_reg = volt_reg, \
- .voltage_mask = volt_mask, \
- .supported_voltages = voltages, \
- .voltages_len = len_volts, \
- .fixed_uV = 0, \
-}
-
-#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \
- reg_mask, reg_enable) \
-{ \
- .desc = { \
- .name = "LDO-" #_id, \
- .ops = &ab8500_ldo_fixed_ops, \
- .type = REGULATOR_VOLTAGE, \
- .id = AB8500_LDO_##_id, \
- .owner = THIS_MODULE, \
- }, \
- .fixed_uV = fixed * 1000, \
- .update_bank = bank, \
- .update_reg = reg, \
- .mask = reg_mask, \
- .enable = reg_enable, \
-}
-
-static struct ab8500_regulator_info ab8500_regulator_info[] = {
+static struct ab8500_regulator_info
+ ab8500_regulator_info[AB8500_NUM_REGULATORS] = {
/*
- * Variable Voltage LDOs
- * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask,
- * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table,
- * num supported volts
+ * Variable Voltage Regulators
+ * name, min mV, max mV,
+ * update bank, reg, mask, enable val
+ * volt bank, reg, mask, table, table length
*/
- AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf,
- ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
- AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf,
- ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
- AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf,
- ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
- AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38,
- ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
+ [AB8500_LDO_AUX1] = {
+ .desc = {
+ .name = "LDO-AUX1",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_AUX1,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ },
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x03,
+ .update_val_enable = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x1f,
+ .voltage_mask = 0x0f,
+ .voltages = ldo_vauxn_voltages,
+ .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages),
+ },
+ [AB8500_LDO_AUX2] = {
+ .desc = {
+ .name = "LDO-AUX2",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_AUX2,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ },
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x0c,
+ .update_val_enable = 0x04,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x20,
+ .voltage_mask = 0x0f,
+ .voltages = ldo_vauxn_voltages,
+ .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages),
+ },
+ [AB8500_LDO_AUX3] = {
+ .desc = {
+ .name = "LDO-AUX3",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_AUX3,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages),
+ },
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .update_bank = 0x04,
+ .update_reg = 0x0a,
+ .update_mask = 0x03,
+ .update_val_enable = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x21,
+ .voltage_mask = 0x07,
+ .voltages = ldo_vaux3_voltages,
+ .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages),
+ },
+ [AB8500_LDO_INTCORE] = {
+ .desc = {
+ .name = "LDO-INTCORE",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_INTCORE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
+ },
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x44,
+ .update_val_enable = 0x04,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x80,
+ .voltage_mask = 0x38,
+ .voltages = ldo_vintcore_voltages,
+ .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages),
+ },
/*
- * Fixed Voltage LDOs
- * name, o/p uV, ctrl bank, ctrl reg, enable, disable
+ * Fixed Voltage Regulators
+ * name, fixed mV,
+ * update bank, reg, mask, enable val
*/
- AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2),
- AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2),
- AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4),
- AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8),
- AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10),
- AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4),
-};
+ [AB8500_LDO_TVOUT] = {
+ .desc = {
+ .name = "LDO-TVOUT",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_TVOUT,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 2000000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x82,
+ .update_val_enable = 0x02,
+ },
+ [AB8500_LDO_AUDIO] = {
+ .desc = {
+ .name = "LDO-AUDIO",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_AUDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 2000000,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x02,
+ .update_val_enable = 0x02,
+ },
+ [AB8500_LDO_ANAMIC1] = {
+ .desc = {
+ .name = "LDO-ANAMIC1",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANAMIC1,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 2050000,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x08,
+ .update_val_enable = 0x08,
+ },
+ [AB8500_LDO_ANAMIC2] = {
+ .desc = {
+ .name = "LDO-ANAMIC2",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANAMIC2,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 2050000,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x10,
+ .update_val_enable = 0x10,
+ },
+ [AB8500_LDO_DMIC] = {
+ .desc = {
+ .name = "LDO-DMIC",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_DMIC,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 1800000,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x04,
+ .update_val_enable = 0x04,
+ },
+ [AB8500_LDO_ANA] = {
+ .desc = {
+ .name = "LDO-ANA",
+ .ops = &ab8500_regulator_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANA,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .fixed_uV = 1200000,
+ .update_bank = 0x04,
+ .update_reg = 0x06,
+ .update_mask = 0x0c,
+ .update_val_enable = 0x04,
+ },
-static inline struct ab8500_regulator_info *find_regulator_info(int id)
-{
- struct ab8500_regulator_info *info;
- int i;
- for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
- info = &ab8500_regulator_info[i];
- if (info->desc.id == id)
- return info;
- }
- return NULL;
-}
+};
static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
{
@@ -366,6 +522,16 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
pdata = dev_get_platdata(ab8500->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "null pdata\n");
+ return -EINVAL;
+ }
+
+ /* make sure the platform data has the correct size */
+ if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) {
+ dev_err(&pdev->dev, "platform configuration error\n");
+ return -EINVAL;
+ }
/* register all regulators */
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
@@ -374,10 +540,22 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
/* assign per-regulator data */
info = &ab8500_regulator_info[i];
info->dev = &pdev->dev;
- info->ab8500 = ab8500;
+ /* fix for hardware before ab8500v2.0 */
+ if (abx500_get_chip_id(info->dev) < 0x20) {
+ if (info->desc.id == AB8500_LDO_AUX3) {
+ info->desc.n_voltages =
+ ARRAY_SIZE(ldo_vauxn_voltages);
+ info->voltages = ldo_vauxn_voltages;
+ info->voltages_len =
+ ARRAY_SIZE(ldo_vauxn_voltages);
+ info->voltage_mask = 0xf;
+ }
+ }
+
+ /* register regulator with framework */
info->regulator = regulator_register(&info->desc, &pdev->dev,
- pdata->regulator[i], info);
+ &pdata->regulator[i], info);
if (IS_ERR(info->regulator)) {
err = PTR_ERR(info->regulator);
dev_err(&pdev->dev, "failed to register regulator %s\n",
@@ -389,6 +567,9 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
}
return err;
}
+
+ dev_vdbg(rdev_get_dev(info->regulator),
+ "%s-probed\n", info->desc.name);
}
return 0;
@@ -401,6 +582,10 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
struct ab8500_regulator_info *info = NULL;
info = &ab8500_regulator_info[i];
+
+ dev_vdbg(rdev_get_dev(info->regulator),
+ "%s-remove\n", info->desc.name);
+
regulator_unregister(info->regulator);
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index f1d10c974cd4..9fa20957847d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -13,8 +13,11 @@
*
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -25,16 +28,30 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/regulator.h>
+
#include "dummy.h"
-#define REGULATOR_VERSION "0.5"
+#define rdev_err(rdev, fmt, ...) \
+ pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_warn(rdev, fmt, ...) \
+ pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_info(rdev, fmt, ...) \
+ pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_dbg(rdev, fmt, ...) \
+ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
-static int has_full_constraints;
+static bool has_full_constraints;
static bool board_wants_dummy_regulator;
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_root;
+#endif
+
/*
* struct regulator_map
*
@@ -71,6 +88,8 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
+static int _regulator_do_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV);
static const char *rdev_get_name(struct regulator_dev *rdev)
{
@@ -111,13 +130,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
BUG_ON(*min_uV > *max_uV);
if (!rdev->constraints) {
- printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev_get_name(rdev));
+ rdev_err(rdev, "no constraints\n");
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
- printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "operation not allowed\n");
return -EPERM;
}
@@ -132,6 +149,27 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
return 0;
}
+/* Make sure we select a voltage that suits the needs of all
+ * regulator consumers
+ */
+static int regulator_check_consumers(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV)
+{
+ struct regulator *regulator;
+
+ list_for_each_entry(regulator, &rdev->consumer_list, list) {
+ if (*max_uV > regulator->max_uV)
+ *max_uV = regulator->max_uV;
+ if (*min_uV < regulator->min_uV)
+ *min_uV = regulator->min_uV;
+ }
+
+ if (*min_uV > *max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
/* current constraint check */
static int regulator_check_current_limit(struct regulator_dev *rdev,
int *min_uA, int *max_uA)
@@ -139,13 +177,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
BUG_ON(*min_uA > *max_uA);
if (!rdev->constraints) {
- printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev_get_name(rdev));
+ rdev_err(rdev, "no constraints\n");
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
- printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "operation not allowed\n");
return -EPERM;
}
@@ -174,18 +210,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
}
if (!rdev->constraints) {
- printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev_get_name(rdev));
+ rdev_err(rdev, "no constraints\n");
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
- printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "operation not allowed\n");
return -EPERM;
}
if (!(rdev->constraints->valid_modes_mask & mode)) {
- printk(KERN_ERR "%s: invalid mode %x for %s\n",
- __func__, mode, rdev_get_name(rdev));
+ rdev_err(rdev, "invalid mode %x\n", mode);
return -EINVAL;
}
return 0;
@@ -195,13 +228,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
static int regulator_check_drms(struct regulator_dev *rdev)
{
if (!rdev->constraints) {
- printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev_get_name(rdev));
+ rdev_err(rdev, "no constraints\n");
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
- printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "operation not allowed\n");
return -EPERM;
}
return 0;
@@ -553,18 +584,21 @@ static void drms_uA_update(struct regulator_dev *rdev)
err = regulator_check_drms(rdev);
if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
- !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode)
+ (!rdev->desc->ops->get_voltage &&
+ !rdev->desc->ops->get_voltage_sel) ||
+ !rdev->desc->ops->set_mode)
return;
/* get output voltage */
- output_uV = rdev->desc->ops->get_voltage(rdev);
+ output_uV = _regulator_get_voltage(rdev);
if (output_uV <= 0)
return;
/* get input voltage */
- if (rdev->supply && rdev->supply->desc->ops->get_voltage)
- input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply);
- else
+ input_uV = 0;
+ if (rdev->supply)
+ input_uV = _regulator_get_voltage(rdev);
+ if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0)
return;
@@ -598,20 +632,17 @@ static int suspend_set_state(struct regulator_dev *rdev,
*/
if (!rstate->enabled && !rstate->disabled) {
if (can_set_state)
- printk(KERN_WARNING "%s: No configuration for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_warn(rdev, "No configuration\n");
return 0;
}
if (rstate->enabled && rstate->disabled) {
- printk(KERN_ERR "%s: invalid configuration for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "invalid configuration\n");
return -EINVAL;
}
if (!can_set_state) {
- printk(KERN_ERR "%s: no way to set suspend state\n",
- __func__);
+ rdev_err(rdev, "no way to set suspend state\n");
return -EINVAL;
}
@@ -620,15 +651,14 @@ static int suspend_set_state(struct regulator_dev *rdev,
else
ret = rdev->desc->ops->set_suspend_disable(rdev);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to enabled/disable\n", __func__);
+ rdev_err(rdev, "failed to enabled/disable\n");
return ret;
}
if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) {
ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to set voltage\n",
- __func__);
+ rdev_err(rdev, "failed to set voltage\n");
return ret;
}
}
@@ -636,7 +666,7 @@ static int suspend_set_state(struct regulator_dev *rdev,
if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) {
ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to set mode\n", __func__);
+ rdev_err(rdev, "failed to set mode\n");
return ret;
}
}
@@ -714,29 +744,27 @@ static void print_constraints(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += sprintf(buf + count, "standby");
- printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf);
+ rdev_info(rdev, "%s\n", buf);
}
static int machine_constraints_voltage(struct regulator_dev *rdev,
struct regulation_constraints *constraints)
{
struct regulator_ops *ops = rdev->desc->ops;
- const char *name = rdev_get_name(rdev);
int ret;
/* do we need to apply the constraint voltage */
if (rdev->constraints->apply_uV &&
- rdev->constraints->min_uV == rdev->constraints->max_uV &&
- ops->set_voltage) {
- ret = ops->set_voltage(rdev,
- rdev->constraints->min_uV, rdev->constraints->max_uV);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
- __func__,
- rdev->constraints->min_uV, name);
- rdev->constraints = NULL;
- return ret;
- }
+ rdev->constraints->min_uV == rdev->constraints->max_uV) {
+ ret = _regulator_do_set_voltage(rdev,
+ rdev->constraints->min_uV,
+ rdev->constraints->max_uV);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to apply %duV constraint\n",
+ rdev->constraints->min_uV);
+ rdev->constraints = NULL;
+ return ret;
+ }
}
/* constrain machine-level voltage specs to fit
@@ -765,8 +793,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
/* else require explicit machine-level constraints */
if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
- pr_err("%s: %s '%s' voltage constraints\n",
- __func__, "invalid", name);
+ rdev_err(rdev, "invalid voltage constraints\n");
return -EINVAL;
}
@@ -787,22 +814,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
/* final: [min_uV..max_uV] valid iff constraints valid */
if (max_uV < min_uV) {
- pr_err("%s: %s '%s' voltage constraints\n",
- __func__, "unsupportable", name);
+ rdev_err(rdev, "unsupportable voltage constraints\n");
return -EINVAL;
}
/* use regulator's subset of machine constraints */
if (constraints->min_uV < min_uV) {
- pr_debug("%s: override '%s' %s, %d -> %d\n",
- __func__, name, "min_uV",
- constraints->min_uV, min_uV);
+ rdev_dbg(rdev, "override min_uV, %d -> %d\n",
+ constraints->min_uV, min_uV);
constraints->min_uV = min_uV;
}
if (constraints->max_uV > max_uV) {
- pr_debug("%s: override '%s' %s, %d -> %d\n",
- __func__, name, "max_uV",
- constraints->max_uV, max_uV);
+ rdev_dbg(rdev, "override max_uV, %d -> %d\n",
+ constraints->max_uV, max_uV);
constraints->max_uV = max_uV;
}
}
@@ -822,26 +846,25 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
* set_mode.
*/
static int set_machine_constraints(struct regulator_dev *rdev,
- struct regulation_constraints *constraints)
+ const struct regulation_constraints *constraints)
{
int ret = 0;
- const char *name;
struct regulator_ops *ops = rdev->desc->ops;
- rdev->constraints = constraints;
-
- name = rdev_get_name(rdev);
+ rdev->constraints = kmemdup(constraints, sizeof(*constraints),
+ GFP_KERNEL);
+ if (!rdev->constraints)
+ return -ENOMEM;
- ret = machine_constraints_voltage(rdev, constraints);
+ ret = machine_constraints_voltage(rdev, rdev->constraints);
if (ret != 0)
goto out;
/* do we need to setup our suspend state */
if (constraints->initial_state) {
- ret = suspend_prepare(rdev, constraints->initial_state);
+ ret = suspend_prepare(rdev, rdev->constraints->initial_state);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to set suspend state for %s\n",
- __func__, name);
+ rdev_err(rdev, "failed to set suspend state\n");
rdev->constraints = NULL;
goto out;
}
@@ -849,17 +872,14 @@ static int set_machine_constraints(struct regulator_dev *rdev,
if (constraints->initial_mode) {
if (!ops->set_mode) {
- printk(KERN_ERR "%s: no set_mode operation for %s\n",
- __func__, name);
+ rdev_err(rdev, "no set_mode operation\n");
ret = -EINVAL;
goto out;
}
- ret = ops->set_mode(rdev, constraints->initial_mode);
+ ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
if (ret < 0) {
- printk(KERN_ERR
- "%s: failed to set initial mode for %s: %d\n",
- __func__, name, ret);
+ rdev_err(rdev, "failed to set initial mode: %d\n", ret);
goto out;
}
}
@@ -867,11 +887,11 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* If the constraints say the regulator should be on at this point
* and we have control then make sure it is enabled.
*/
- if ((constraints->always_on || constraints->boot_on) && ops->enable) {
+ if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
+ ops->enable) {
ret = ops->enable(rdev);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to enable %s\n",
- __func__, name);
+ rdev_err(rdev, "failed to enable\n");
rdev->constraints = NULL;
goto out;
}
@@ -899,9 +919,8 @@ static int set_supply(struct regulator_dev *rdev,
err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
"supply");
if (err) {
- printk(KERN_ERR
- "%s: could not add device link %s err %d\n",
- __func__, supply_rdev->dev.kobj.name, err);
+ rdev_err(rdev, "could not add device link %s err %d\n",
+ supply_rdev->dev.kobj.name, err);
goto out;
}
rdev->supply = supply_rdev;
@@ -911,7 +930,7 @@ out:
}
/**
- * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * set_consumer_device_supply - Bind a regulator to a symbolic supply
* @rdev: regulator source
* @consumer_dev: device the supply applies to
* @consumer_dev_name: dev_name() string for device supply applies to
@@ -957,10 +976,10 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
continue;
dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n",
- dev_name(&node->regulator->dev),
- node->regulator->desc->name,
- supply,
- dev_name(&rdev->dev), rdev_get_name(rdev));
+ dev_name(&node->regulator->dev),
+ node->regulator->desc->name,
+ supply,
+ dev_name(&rdev->dev), rdev_get_name(rdev));
return -EBUSY;
}
@@ -1031,8 +1050,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
regulator->dev_attr.show = device_requested_uA_show;
err = device_create_file(dev, &regulator->dev_attr);
if (err < 0) {
- printk(KERN_WARNING "%s: could not add regulator_dev"
- " load sysfs\n", __func__);
+ rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n");
goto attr_name_err;
}
@@ -1049,10 +1067,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
buf);
if (err) {
- printk(KERN_WARNING
- "%s: could not add device link %s err %d\n",
- __func__, dev->kobj.name, err);
- device_remove_file(dev, &regulator->dev_attr);
+ rdev_warn(rdev, "could not add device link %s err %d\n",
+ dev->kobj.name, err);
goto link_name_err;
}
}
@@ -1089,7 +1105,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
int ret;
if (id == NULL) {
- printk(KERN_ERR "regulator: get() with no identifier\n");
+ pr_err("get() with no identifier\n");
return regulator;
}
@@ -1123,8 +1139,8 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
* substitute in a dummy regulator so consumers can continue.
*/
if (!has_full_constraints) {
- pr_warning("%s supply %s not found, using dummy regulator\n",
- devname, id);
+ pr_warn("%s supply %s not found, using dummy regulator\n",
+ devname, id);
rdev = dummy_regulator_rdev;
goto found;
}
@@ -1268,13 +1284,16 @@ static int _regulator_enable(struct regulator_dev *rdev)
{
int ret, delay;
- /* do we need to enable the supply regulator first */
- if (rdev->supply) {
- ret = _regulator_enable(rdev->supply);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to enable %s: %d\n",
- __func__, rdev_get_name(rdev), ret);
- return ret;
+ if (rdev->use_count == 0) {
+ /* do we need to enable the supply regulator first */
+ if (rdev->supply) {
+ mutex_lock(&rdev->supply->mutex);
+ ret = _regulator_enable(rdev->supply);
+ mutex_unlock(&rdev->supply->mutex);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to enable: %d\n", ret);
+ return ret;
+ }
}
}
@@ -1299,13 +1318,13 @@ static int _regulator_enable(struct regulator_dev *rdev)
if (ret >= 0) {
delay = ret;
} else {
- printk(KERN_WARNING
- "%s: enable_time() failed for %s: %d\n",
- __func__, rdev_get_name(rdev),
- ret);
+ rdev_warn(rdev, "enable_time() failed: %d\n",
+ ret);
delay = 0;
}
+ trace_regulator_enable(rdev_get_name(rdev));
+
/* Allow the regulator to ramp; it would be useful
* to extend this for bulk operations so that the
* regulators can ramp together. */
@@ -1313,14 +1332,19 @@ static int _regulator_enable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (delay >= 1000)
+ trace_regulator_enable_delay(rdev_get_name(rdev));
+
+ if (delay >= 1000) {
mdelay(delay / 1000);
- else if (delay)
+ udelay(delay % 1000);
+ } else if (delay) {
udelay(delay);
+ }
+
+ trace_regulator_enable_complete(rdev_get_name(rdev));
} else if (ret < 0) {
- printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
- __func__, rdev_get_name(rdev), ret);
+ rdev_err(rdev, "is_enabled() failed: %d\n", ret);
return ret;
}
/* Fallthrough on positive return values - already enabled */
@@ -1359,10 +1383,10 @@ static int _regulator_disable(struct regulator_dev *rdev,
struct regulator_dev **supply_rdev_ptr)
{
int ret = 0;
+ *supply_rdev_ptr = NULL;
if (WARN(rdev->use_count <= 0,
- "unbalanced disables for %s\n",
- rdev_get_name(rdev)))
+ "unbalanced disables for %s\n", rdev_get_name(rdev)))
return -EIO;
/* are we the last user and permitted to disable ? */
@@ -1372,13 +1396,16 @@ static int _regulator_disable(struct regulator_dev *rdev,
/* we are last user */
if (_regulator_can_change_status(rdev) &&
rdev->desc->ops->disable) {
+ trace_regulator_disable(rdev_get_name(rdev));
+
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to disable %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "failed to disable\n");
return ret;
}
+ trace_regulator_disable_complete(rdev_get_name(rdev));
+
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
NULL);
}
@@ -1445,8 +1472,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
/* ah well, who wants to live forever... */
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to force disable %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "failed to force disable\n");
return ret;
}
/* notify other consumers that power has been forced off */
@@ -1599,6 +1625,62 @@ int regulator_is_supported_voltage(struct regulator *regulator,
return 0;
}
+static int _regulator_do_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret;
+ unsigned int selector;
+
+ trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
+
+ if (rdev->desc->ops->set_voltage) {
+ ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
+ &selector);
+
+ if (rdev->desc->ops->list_voltage)
+ selector = rdev->desc->ops->list_voltage(rdev,
+ selector);
+ else
+ selector = -1;
+ } else if (rdev->desc->ops->set_voltage_sel) {
+ int best_val = INT_MAX;
+ int i;
+
+ selector = 0;
+
+ /* Find the smallest voltage that falls within the specified
+ * range.
+ */
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ ret = rdev->desc->ops->list_voltage(rdev, i);
+ if (ret < 0)
+ continue;
+
+ if (ret < best_val && ret >= min_uV && ret <= max_uV) {
+ best_val = ret;
+ selector = i;
+ }
+ }
+
+ if (best_val != INT_MAX) {
+ ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
+ selector = best_val;
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ if (ret == 0)
+ _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
+ NULL);
+
+ trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
+
+ return ret;
+}
+
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
@@ -1620,12 +1702,20 @@ int regulator_is_supported_voltage(struct regulator *regulator,
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
- int ret;
+ int ret = 0;
mutex_lock(&rdev->mutex);
+ /* If we're setting the same range as last time the change
+ * should be a noop (some cpufreq implementations use the same
+ * voltage for multiple frequencies, for example).
+ */
+ if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
+ goto out;
+
/* sanity check */
- if (!rdev->desc->ops->set_voltage) {
+ if (!rdev->desc->ops->set_voltage &&
+ !rdev->desc->ops->set_voltage_sel) {
ret = -EINVAL;
goto out;
}
@@ -1636,18 +1726,76 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
goto out;
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
- ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV);
+
+ ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
+ if (ret < 0)
+ goto out;
+
+ ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
out:
- _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
mutex_unlock(&rdev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
+/**
+ * regulator_sync_voltage - re-apply last regulator output voltage
+ * @regulator: regulator source
+ *
+ * Re-apply the last configured voltage. This is intended to be used
+ * where some external control source the consumer is cooperating with
+ * has caused the configured voltage to change.
+ */
+int regulator_sync_voltage(struct regulator *regulator)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret, min_uV, max_uV;
+
+ mutex_lock(&rdev->mutex);
+
+ if (!rdev->desc->ops->set_voltage &&
+ !rdev->desc->ops->set_voltage_sel) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* This is only going to work if we've had a voltage configured. */
+ if (!regulator->min_uV && !regulator->max_uV) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ min_uV = regulator->min_uV;
+ max_uV = regulator->max_uV;
+
+ /* This should be a paranoia check... */
+ ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+ if (ret < 0)
+ goto out;
+
+ ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
+ if (ret < 0)
+ goto out;
+
+ ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+
+out:
+ mutex_unlock(&rdev->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_sync_voltage);
+
static int _regulator_get_voltage(struct regulator_dev *rdev)
{
- /* sanity check */
+ int sel;
+
+ if (rdev->desc->ops->get_voltage_sel) {
+ sel = rdev->desc->ops->get_voltage_sel(rdev);
+ if (sel < 0)
+ return sel;
+ return rdev->desc->ops->list_voltage(rdev, sel);
+ }
if (rdev->desc->ops->get_voltage)
return rdev->desc->ops->get_voltage(rdev);
else
@@ -1874,21 +2022,20 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
goto out;
/* get output voltage */
- output_uV = rdev->desc->ops->get_voltage(rdev);
+ output_uV = _regulator_get_voltage(rdev);
if (output_uV <= 0) {
- printk(KERN_ERR "%s: invalid output voltage found for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "invalid output voltage found\n");
goto out;
}
/* get input voltage */
- if (rdev->supply && rdev->supply->desc->ops->get_voltage)
- input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply);
- else
+ input_uV = 0;
+ if (rdev->supply)
+ input_uV = _regulator_get_voltage(rdev->supply);
+ if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
- printk(KERN_ERR "%s: invalid input voltage found for %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "invalid input voltage found\n");
goto out;
}
@@ -1901,16 +2048,14 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
total_uA_load);
ret = regulator_check_mode(rdev, mode);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to get optimum mode for %s @"
- " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev),
- total_uA_load, input_uV, output_uV);
+ rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
+ total_uA_load, input_uV, output_uV);
goto out;
}
ret = rdev->desc->ops->set_mode(rdev, mode);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
- __func__, mode, rdev_get_name(rdev));
+ rdev_err(rdev, "failed to set optimum mode %x\n", mode);
goto out;
}
ret = mode;
@@ -2041,7 +2186,7 @@ int regulator_bulk_enable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret);
+ pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
for (--i; i >= 0; --i)
regulator_disable(consumers[i].consumer);
@@ -2076,8 +2221,7 @@ int regulator_bulk_disable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply,
- ret);
+ pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
for (--i; i >= 0; --i)
regulator_enable(consumers[i].consumer);
@@ -2160,7 +2304,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
int status = 0;
/* some attributes need specific methods to be displayed */
- if (ops->get_voltage) {
+ if (ops->get_voltage || ops->get_voltage_sel) {
status = device_create_file(dev, &dev_attr_microvolts);
if (status < 0)
return status;
@@ -2201,7 +2345,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
return status;
/* constraints need specific supporting methods */
- if (ops->set_voltage) {
+ if (ops->set_voltage || ops->set_voltage_sel) {
status = device_create_file(dev, &dev_attr_min_microvolts);
if (status < 0)
return status;
@@ -2265,6 +2409,23 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
return status;
}
+static void rdev_init_debugfs(struct regulator_dev *rdev)
+{
+#ifdef CONFIG_DEBUG_FS
+ rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
+ if (IS_ERR(rdev->debugfs) || !rdev->debugfs) {
+ rdev_warn(rdev, "Failed to create debugfs directory\n");
+ rdev->debugfs = NULL;
+ return;
+ }
+
+ debugfs_create_u32("use_count", 0444, rdev->debugfs,
+ &rdev->use_count);
+ debugfs_create_u32("open_count", 0444, rdev->debugfs,
+ &rdev->open_count);
+#endif
+}
+
/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
@@ -2276,7 +2437,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
* Returns 0 on success.
*/
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- struct device *dev, struct regulator_init_data *init_data,
+ struct device *dev, const struct regulator_init_data *init_data,
void *driver_data)
{
static atomic_t regulator_no = ATOMIC_INIT(0);
@@ -2296,6 +2457,22 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (!init_data)
return ERR_PTR(-EINVAL);
+ /* Only one of each should be implemented */
+ WARN_ON(regulator_desc->ops->get_voltage &&
+ regulator_desc->ops->get_voltage_sel);
+ WARN_ON(regulator_desc->ops->set_voltage &&
+ regulator_desc->ops->set_voltage_sel);
+
+ /* If we're using selectors we must implement list_voltage. */
+ if (regulator_desc->ops->get_voltage_sel &&
+ !regulator_desc->ops->list_voltage) {
+ return ERR_PTR(-EINVAL);
+ }
+ if (regulator_desc->ops->set_voltage_sel &&
+ !regulator_desc->ops->list_voltage) {
+ return ERR_PTR(-EINVAL);
+ }
+
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL)
return ERR_PTR(-ENOMEM);
@@ -2346,6 +2523,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (init_data->supply_regulator && init_data->supply_regulator_dev) {
dev_err(dev,
"Supply regulator specified by both name and dev\n");
+ ret = -EINVAL;
goto scrub;
}
@@ -2364,6 +2542,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (!found) {
dev_err(dev, "Failed to find supply %s\n",
init_data->supply_regulator);
+ ret = -ENODEV;
goto scrub;
}
@@ -2391,6 +2570,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
}
list_add(&rdev->list, &regulator_list);
+
+ rdev_init_debugfs(rdev);
out:
mutex_unlock(&regulator_list_mutex);
return rdev;
@@ -2423,12 +2604,16 @@ void regulator_unregister(struct regulator_dev *rdev)
return;
mutex_lock(&regulator_list_mutex);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(rdev->debugfs);
+#endif
WARN_ON(rdev->open_count);
unset_regulator_supplies(rdev);
list_del(&rdev->list);
if (rdev->supply)
sysfs_remove_link(&rdev->dev.kobj, "supply");
device_unregister(&rdev->dev);
+ kfree(rdev->constraints);
mutex_unlock(&regulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_unregister);
@@ -2457,8 +2642,7 @@ int regulator_suspend_prepare(suspend_state_t state)
mutex_unlock(&rdev->mutex);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to prepare %s\n",
- __func__, rdev_get_name(rdev));
+ rdev_err(rdev, "failed to prepare\n");
goto out;
}
}
@@ -2564,10 +2748,16 @@ static int __init regulator_init(void)
{
int ret;
- printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
-
ret = class_register(&regulator_class);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_root = debugfs_create_dir("regulator", NULL);
+ if (IS_ERR(debugfs_root) || !debugfs_root) {
+ pr_warn("regulator: Failed to create debugfs directory\n");
+ debugfs_root = NULL;
+ }
+#endif
+
regulator_dummy_init();
return ret;
@@ -2582,7 +2772,6 @@ static int __init regulator_init_complete(void)
struct regulator_ops *ops;
struct regulation_constraints *c;
int enabled, ret;
- const char *name;
mutex_lock(&regulator_list_mutex);
@@ -2594,8 +2783,6 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops;
c = rdev->constraints;
- name = rdev_get_name(rdev);
-
if (!ops->disable || (c && c->always_on))
continue;
@@ -2616,13 +2803,10 @@ static int __init regulator_init_complete(void)
if (has_full_constraints) {
/* We log since this may kill the system if it
* goes wrong. */
- printk(KERN_INFO "%s: disabling %s\n",
- __func__, name);
+ rdev_info(rdev, "disabling\n");
ret = ops->disable(rdev);
if (ret != 0) {
- printk(KERN_ERR
- "%s: couldn't disable %s: %d\n",
- __func__, name, ret);
+ rdev_err(rdev, "couldn't disable: %d\n", ret);
}
} else {
/* The intention is that in future we will
@@ -2630,9 +2814,7 @@ static int __init regulator_init_complete(void)
* so warn even if we aren't going to do
* anything here.
*/
- printk(KERN_WARNING
- "%s: incomplete constraints, leaving %s on\n",
- __func__, name);
+ rdev_warn(rdev, "incomplete constraints, leaving on\n");
}
unlock:
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index f8c4661a7a81..362e08221085 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -107,7 +107,7 @@ static inline int check_range(struct da903x_regulator_info *info,
/* DA9030/DA9034 common operations */
static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
@@ -119,6 +119,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
}
val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ *selector = val;
val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
@@ -187,7 +188,8 @@ static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector)
/* DA9030 specific operations */
static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da903x_dev = to_da903x_dev(rdev);
@@ -200,6 +202,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
}
val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ *selector = val;
val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
@@ -214,7 +217,8 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
}
static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da903x_dev = to_da903x_dev(rdev);
@@ -234,6 +238,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
val = (min_uV - thresh + info->step_uV - 1) / info->step_uV;
}
+ *selector = val;
val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
@@ -263,7 +268,7 @@ static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
/* DA9034 specific operations */
static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
@@ -276,6 +281,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
}
val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ *selector = val;
val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
@@ -289,7 +295,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
}
static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
struct device *da9034_dev = to_da903x_dev(rdev);
@@ -302,6 +308,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val);
+ *selector = val;
val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index b8cc6389a541..e4b3592e8176 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -58,7 +58,9 @@ out:
return data;
}
-static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV)
+static int isl6271a_set_voltage(struct regulator_dev *dev,
+ int minuV, int maxuV,
+ unsigned *selector)
{
struct isl_pmic *pmic = rdev_get_drvdata(dev);
int vsel, err, data;
@@ -78,6 +80,8 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV)
/* Convert the microvolts to data for the chip */
data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP;
+ *selector = data;
+
mutex_lock(&pmic->mtx);
err = i2c_smbus_write_byte(pmic->client, data);
@@ -169,7 +173,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c,
init_data, pmic);
if (IS_ERR(pmic->rdev[i])) {
dev_err(&i2c->dev, "failed to register %s\n", id->name);
- err = PTR_ERR(pmic->rdev);
+ err = PTR_ERR(pmic->rdev[i]);
goto error;
}
}
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 3bb82b624e19..0f22ef12601c 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -168,7 +168,8 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
}
static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned int *selector)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
@@ -187,6 +188,8 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol)
return -EINVAL;
+ *selector = val;
+
return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
val << LDO_VOL_CONTR_SHIFT(ldo));
@@ -256,7 +259,8 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
}
static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned int *selector)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
@@ -277,6 +281,8 @@ static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol)
return -EINVAL;
+ *selector = val;
+
ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
BUCK_TARGET_VOL_MASK, val);
if (ret)
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index e07062fd0b42..6aa1b506fb5d 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -292,7 +292,8 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
}
static int lp3972_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned int *selector)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3972_LDO1;
@@ -313,6 +314,8 @@ static int lp3972_ldo_set_voltage(struct regulator_dev *dev,
if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol)
return -EINVAL;
+ *selector = val;
+
shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
LP3972_LDO_VOL_MASK(ldo) << shift, val << shift);
@@ -416,7 +419,8 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
}
static int lp3972_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned int *selector)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3972_DCDC1;
@@ -438,6 +442,8 @@ static int lp3972_dcdc_set_voltage(struct regulator_dev *dev,
vol_map[val] > max_vol)
return -EINVAL;
+ *selector = val;
+
ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
LP3972_BUCK_VOL_MASK, val);
if (ret)
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 559cfa271a44..3f49512c5134 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -63,12 +63,12 @@ static int max1586_v3_calc_voltage(struct max1586_data *max1586,
return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
}
-static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned *selector)
{
struct max1586_data *max1586 = rdev_get_drvdata(rdev);
struct i2c_client *client = max1586->client;
unsigned range_uV = max1586->max_uV - max1586->min_uV;
- unsigned selector;
u8 v3_prog;
if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
@@ -76,15 +76,15 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV)
if (min_uV < max1586->min_uV)
min_uV = max1586->min_uV;
- selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL +
+ *selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL +
range_uV - 1) / range_uV;
- if (max1586_v3_calc_voltage(max1586, selector) > max_uV)
+ if (max1586_v3_calc_voltage(max1586, *selector) > max_uV)
return -EINVAL;
dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
- max1586_v3_calc_voltage(max1586, selector) / 1000);
+ max1586_v3_calc_voltage(max1586, *selector) / 1000);
- v3_prog = I2C_V3_SELECT | (u8) selector;
+ v3_prog = I2C_V3_SELECT | (u8) *selector;
return i2c_smbus_write_byte(client, v3_prog);
}
@@ -110,10 +110,10 @@ static int max1586_v6_calc_voltage(unsigned selector)
return voltages_uv[selector];
}
-static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned int *selector)
{
struct i2c_client *client = rdev_get_drvdata(rdev);
- unsigned selector;
u8 v6_prog;
if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
@@ -122,21 +122,21 @@ static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV)
return -EINVAL;
if (min_uV < 1800000)
- selector = 0;
+ *selector = 0;
else if (min_uV < 2500000)
- selector = 1;
+ *selector = 1;
else if (min_uV < 3000000)
- selector = 2;
+ *selector = 2;
else if (min_uV >= 3000000)
- selector = 3;
+ *selector = 3;
- if (max1586_v6_calc_voltage(selector) > max_uV)
+ if (max1586_v6_calc_voltage(*selector) > max_uV)
return -EINVAL;
dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
- max1586_v6_calc_voltage(selector) / 1000);
+ max1586_v6_calc_voltage(*selector) / 1000);
- v6_prog = I2C_V6_SELECT | (u8) selector;
+ v6_prog = I2C_V6_SELECT | (u8) *selector;
return i2c_smbus_write_byte(client, v6_prog);
}
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 6b60a9c0366b..30eb9e54f7ec 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -155,7 +155,7 @@ static int max8649_get_voltage(struct regulator_dev *rdev)
}
static int max8649_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data, mask;
@@ -168,6 +168,7 @@ static int max8649_set_voltage(struct regulator_dev *rdev,
data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1)
/ MAX8649_DCDC_STEP;
mask = MAX8649_VOL_MASK;
+ *selector = data & mask;
return max8649_set_bits(info->i2c, info->vol_reg, mask, data);
}
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index c570e6eb0db2..33f5d9a492ef 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -141,7 +141,8 @@ static int max8660_dcdc_get(struct regulator_dev *rdev)
return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
}
-static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned int *s)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 reg, selector, bits;
@@ -154,6 +155,7 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV)
selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1))
/ MAX8660_DCDC_STEP;
+ *s = selector;
ret = max8660_dcdc_list(rdev, selector);
if (ret < 0 || ret > max_uV)
@@ -196,7 +198,8 @@ static int max8660_ldo5_get(struct regulator_dev *rdev)
return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
}
-static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned int *s)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 selector;
@@ -213,6 +216,8 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV)
if (ret < 0 || ret > max_uV)
return -EINVAL;
+ *s = selector;
+
ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
if (ret)
return ret;
@@ -270,7 +275,8 @@ static int max8660_ldo67_get(struct regulator_dev *rdev)
return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
}
-static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned int *s)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 selector;
@@ -288,6 +294,8 @@ static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV)
if (ret < 0 || ret > max_uV)
return -EINVAL;
+ *s = selector;
+
if (rdev_get_id(rdev) == MAX8660_V6)
return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
else
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 552cad85ae5a..8ae147549c6a 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -55,7 +55,7 @@ static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index)
}
static int max8925_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned int *selector)
{
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data, mask;
@@ -66,6 +66,7 @@ static int max8925_set_voltage(struct regulator_dev *rdev,
return -EINVAL;
}
data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ *selector = data;
data <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 0d5dda4fd911..a8f4ecfb0843 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -133,7 +133,7 @@ static int max8952_get_voltage(struct regulator_dev *rdev)
}
static int max8952_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct max8952_data *max8952 = rdev_get_drvdata(rdev);
s8 vid = -1, i;
@@ -156,6 +156,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev,
if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) {
max8952->vid0 = (vid % 2 == 1);
max8952->vid1 = (((vid >> 1) % 2) == 1);
+ *selector = vid;
gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0);
gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1);
} else
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 5c20756db607..0ec49ca527a8 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -304,7 +304,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev)
}
static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
@@ -331,6 +331,8 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
if (desc->min + desc->step*i > max_vol)
return -EINVAL;
+ *selector = i;
+
ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
@@ -352,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v)
}
static int max8998_set_voltage_buck(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct max8998_platform_data *pdata =
@@ -384,6 +386,8 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
if (desc->min + desc->step*i > max_vol)
return -EINVAL;
+ *selector = i;
+
ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
@@ -420,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
}
}
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
/* no predefine regulator found */
max8998->buck1_idx = (buck1_last_val % 2) + 2;
dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
@@ -447,18 +454,26 @@ buck1_exit:
"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
if (gpio_is_valid(pdata->buck2_set3)) {
- if (max8998->buck2_vol[0] == i) {
- max8998->buck1_idx = 0;
- buck2_gpio_set(pdata->buck2_set3, 0);
- } else {
- max8998->buck1_idx = 1;
- ret = max8998_get_voltage_register(rdev, &reg,
- &shift,
- &mask);
- ret = max8998_write_reg(i2c, reg, i);
- max8998->buck2_vol[1] = i;
- buck2_gpio_set(pdata->buck2_set3, 1);
+
+ /* check if requested voltage */
+ /* value is already defined */
+ for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
+ if (max8998->buck2_vol[j] == i) {
+ max8998->buck2_idx = j;
+ buck2_gpio_set(pdata->buck2_set3, j);
+ goto buck2_exit;
+ }
}
+
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
+ max8998_get_voltage_register(rdev,
+ &reg, &shift, &mask);
+ ret = max8998_write_reg(i2c, reg, i);
+ max8998->buck2_vol[max8998->buck2_idx] = i;
+ buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
+buck2_exit:
dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
gpio_get_value(pdata->buck2_set3));
} else {
@@ -703,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, max8998);
i2c = max8998->iodev->i2c;
+ max8998->buck1_idx = pdata->buck1_default_idx;
+ max8998->buck2_idx = pdata->buck2_default_idx;
+
/* NOTE: */
/* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */
/* will be displayed */
@@ -735,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage1 / 1000))
+ < (pdata->buck1_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
max8998->buck1_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+ if (ret)
+ return ret;
/* Set predefined value for BUCK1 register 2 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage2 / 1000))
+ < (pdata->buck1_voltage2 / 1000))
i++;
max8998->buck1_vol[1] = i;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
- ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
- + ret;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 3 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage3 / 1000))
+ i++;
+
+ max8998->buck1_vol[2] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 4 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage4 / 1000))
+ i++;
+
+ max8998->buck1_vol[3] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
if (ret)
return ret;
@@ -768,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
gpio_direction_output(pdata->buck2_set3,
max8998->buck2_idx & 0x1);
- /* BUCK2 - set preset default voltage value to buck2_vol[0] */
+ /* BUCK2 register 1 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck2_max_voltage / 1000))
+ < (pdata->buck2_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
max8998->buck2_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
if (ret)
return ret;
+ /* BUCK2 register 2 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck2_voltage2 / 1000))
+ i++;
+ printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
+ max8998->buck2_vol[1] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
+ if (ret)
+ return ret;
}
for (i = 0; i < pdata->num_regulators; i++) {
@@ -831,6 +882,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_pmic_id[] = {
+ { "max8998-pmic", TYPE_MAX8998 },
+ { "lp3974-pmic", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_pmic_driver = {
.driver = {
.name = "max8998-pmic",
@@ -838,6 +895,7 @@ static struct platform_driver max8998_pmic_driver = {
},
.probe = max8998_pmic_probe,
.remove = __devexit_p(max8998_pmic_remove),
+ .id_table = max8998_pmic_id,
};
static int __init max8998_pmic_init(void)
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 4597d508a229..3e5d0c3b4e53 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -1,6 +1,7 @@
/*
* Regulator Driver for Freescale MC13783 PMIC
*
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
* Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
*
@@ -17,6 +18,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/err.h>
+#include "mc13xxx.h"
#define MC13783_REG_SWITCHERS5 29
#define MC13783_REG_SWITCHERS5_SW3EN (1 << 20)
@@ -89,154 +91,106 @@
#define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15)
-struct mc13783_regulator {
- struct regulator_desc desc;
- int reg;
- int enable_bit;
- int vsel_reg;
- int vsel_shift;
- int vsel_mask;
- int const *voltages;
-};
-
/* Voltage Values */
-static const int const mc13783_sw3_val[] = {
+static const int mc13783_sw3_val[] = {
5000000, 5000000, 5000000, 5500000,
};
-static const int const mc13783_vaudio_val[] = {
+static const int mc13783_vaudio_val[] = {
2775000,
};
-static const int const mc13783_viohi_val[] = {
+static const int mc13783_viohi_val[] = {
2775000,
};
-static const int const mc13783_violo_val[] = {
+static const int mc13783_violo_val[] = {
1200000, 1300000, 1500000, 1800000,
};
-static const int const mc13783_vdig_val[] = {
+static const int mc13783_vdig_val[] = {
1200000, 1300000, 1500000, 1800000,
};
-static const int const mc13783_vgen_val[] = {
+static const int mc13783_vgen_val[] = {
1200000, 1300000, 1500000, 1800000,
1100000, 2000000, 2775000, 2400000,
};
-static const int const mc13783_vrfdig_val[] = {
+static const int mc13783_vrfdig_val[] = {
1200000, 1500000, 1800000, 1875000,
};
-static const int const mc13783_vrfref_val[] = {
+static const int mc13783_vrfref_val[] = {
2475000, 2600000, 2700000, 2775000,
};
-static const int const mc13783_vrfcp_val[] = {
+static const int mc13783_vrfcp_val[] = {
2700000, 2775000,
};
-static const int const mc13783_vsim_val[] = {
+static const int mc13783_vsim_val[] = {
1800000, 2900000, 3000000,
};
-static const int const mc13783_vesim_val[] = {
+static const int mc13783_vesim_val[] = {
1800000, 2900000,
};
-static const int const mc13783_vcam_val[] = {
+static const int mc13783_vcam_val[] = {
1500000, 1800000, 2500000, 2550000,
2600000, 2750000, 2800000, 3000000,
};
-static const int const mc13783_vrfbg_val[] = {
+static const int mc13783_vrfbg_val[] = {
1250000,
};
-static const int const mc13783_vvib_val[] = {
+static const int mc13783_vvib_val[] = {
1300000, 1800000, 2000000, 3000000,
};
-static const int const mc13783_vmmc_val[] = {
+static const int mc13783_vmmc_val[] = {
1600000, 1800000, 2000000, 2600000,
2700000, 2800000, 2900000, 3000000,
};
-static const int const mc13783_vrf_val[] = {
+static const int mc13783_vrf_val[] = {
1500000, 1875000, 2700000, 2775000,
};
-static const int const mc13783_gpo_val[] = {
+static const int mc13783_gpo_val[] = {
3100000,
};
-static const int const mc13783_pwgtdrv_val[] = {
+static const int mc13783_pwgtdrv_val[] = {
5500000,
};
-static struct regulator_ops mc13783_regulator_ops;
-static struct regulator_ops mc13783_fixed_regulator_ops;
static struct regulator_ops mc13783_gpo_regulator_ops;
-#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \
- [MC13783_ ## prefix ## _ ## _name] = { \
- .desc = { \
- .name = #prefix "_" #_name, \
- .n_voltages = ARRAY_SIZE(_voltages), \
- .ops = &mc13783_regulator_ops, \
- .type = REGULATOR_VOLTAGE, \
- .id = MC13783_ ## prefix ## _ ## _name, \
- .owner = THIS_MODULE, \
- }, \
- .reg = MC13783_REG_ ## _reg, \
- .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
- .vsel_reg = MC13783_REG_ ## _vsel_reg, \
- .vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\
- .vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\
- .voltages = _voltages, \
- }
+#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages) \
+ MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \
+ mc13xxx_regulator_ops)
-#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \
- [MC13783_ ## prefix ## _ ## _name] = { \
- .desc = { \
- .name = #prefix "_" #_name, \
- .n_voltages = ARRAY_SIZE(_voltages), \
- .ops = &mc13783_fixed_regulator_ops, \
- .type = REGULATOR_VOLTAGE, \
- .id = MC13783_ ## prefix ## _ ## _name, \
- .owner = THIS_MODULE, \
- }, \
- .reg = MC13783_REG_ ## _reg, \
- .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
- .voltages = _voltages, \
- }
+#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages) \
+ MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \
+ mc13xxx_fixed_regulator_ops)
-#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \
- [MC13783_ ## prefix ## _ ## _name] = { \
- .desc = { \
- .name = #prefix "_" #_name, \
- .n_voltages = ARRAY_SIZE(_voltages), \
- .ops = &mc13783_gpo_regulator_ops, \
- .type = REGULATOR_VOLTAGE, \
- .id = MC13783_ ## prefix ## _ ## _name, \
- .owner = THIS_MODULE, \
- }, \
- .reg = MC13783_REG_ ## _reg, \
- .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
- .voltages = _voltages, \
- }
+#define MC13783_GPO_DEFINE(prefix, name, reg, voltages) \
+ MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \
+ mc13783_gpo_regulator_ops)
#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \
- MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages)
+ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages)
#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \
- MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages)
+ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages)
-static struct mc13783_regulator mc13783_regulators[] = {
+static struct mc13xxx_regulator mc13783_regulators[] = {
MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val),
- MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
- MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val),
+ MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
+ MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val),
MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \
mc13783_violo_val),
MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \
@@ -255,7 +209,7 @@ static struct mc13783_regulator mc13783_regulators[] = {
mc13783_vesim_val),
MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
mc13783_vcam_val),
- MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val),
+ MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val),
MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vvib_val),
MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \
@@ -266,215 +220,24 @@ static struct mc13783_regulator mc13783_regulators[] = {
mc13783_vmmc_val),
MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vmmc_val),
- MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val),
- MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val),
- MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val),
- MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val),
- MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val),
- MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),
-};
-
-struct mc13783_regulator_priv {
- struct mc13783 *mc13783;
- u32 powermisc_pwgt_state;
- struct regulator_dev *regulators[];
-};
-
-static int mc13783_regulator_enable(struct regulator_dev *rdev)
-{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int ret;
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
- mc13783_regulators[id].enable_bit,
- mc13783_regulators[id].enable_bit);
- mc13783_unlock(priv->mc13783);
-
- return ret;
-}
-
-static int mc13783_regulator_disable(struct regulator_dev *rdev)
-{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int ret;
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
- mc13783_regulators[id].enable_bit, 0);
- mc13783_unlock(priv->mc13783);
-
- return ret;
-}
-
-static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)
-{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
- int ret, id = rdev_get_id(rdev);
- unsigned int val;
-
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
- mc13783_unlock(priv->mc13783);
-
- if (ret)
- return ret;
-
- return (val & mc13783_regulators[id].enable_bit) != 0;
-}
-
-static int mc13783_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int id = rdev_get_id(rdev);
-
- if (selector >= mc13783_regulators[id].desc.n_voltages)
- return -EINVAL;
-
- return mc13783_regulators[id].voltages[selector];
-}
-
-static int mc13783_get_best_voltage_index(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int reg_id = rdev_get_id(rdev);
- int i;
- int bestmatch;
- int bestindex;
-
- /*
- * Locate the minimum voltage fitting the criteria on
- * this regulator. The switchable voltages are not
- * in strict falling order so we need to check them
- * all for the best match.
- */
- bestmatch = INT_MAX;
- bestindex = -1;
- for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) {
- if (mc13783_regulators[reg_id].voltages[i] >= min_uV &&
- mc13783_regulators[reg_id].voltages[i] < bestmatch) {
- bestmatch = mc13783_regulators[reg_id].voltages[i];
- bestindex = i;
- }
- }
-
- if (bestindex < 0 || bestmatch > max_uV) {
- dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
- min_uV, max_uV);
- return -EINVAL;
- }
- return bestindex;
-}
-
-static int mc13783_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
- int value, id = rdev_get_id(rdev);
- int ret;
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
- __func__, id, min_uV, max_uV);
-
- /* Find the best index */
- value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV);
- dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value);
- if (value < 0)
- return value;
-
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg,
- mc13783_regulators[id].vsel_mask,
- value << mc13783_regulators[id].vsel_shift);
- mc13783_unlock(priv->mc13783);
-
- return ret;
-}
-
-static int mc13783_regulator_get_voltage(struct regulator_dev *rdev)
-{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
- int ret, id = rdev_get_id(rdev);
- unsigned int val;
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_read(priv->mc13783,
- mc13783_regulators[id].vsel_reg, &val);
- mc13783_unlock(priv->mc13783);
-
- if (ret)
- return ret;
-
- val = (val & mc13783_regulators[id].vsel_mask)
- >> mc13783_regulators[id].vsel_shift;
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
-
- BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages);
-
- return mc13783_regulators[id].voltages[val];
-}
-
-static struct regulator_ops mc13783_regulator_ops = {
- .enable = mc13783_regulator_enable,
- .disable = mc13783_regulator_disable,
- .is_enabled = mc13783_regulator_is_enabled,
- .list_voltage = mc13783_regulator_list_voltage,
- .set_voltage = mc13783_regulator_set_voltage,
- .get_voltage = mc13783_regulator_get_voltage,
-};
-
-static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int id = rdev_get_id(rdev);
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
- __func__, id, min_uV, max_uV);
-
- if (min_uV >= mc13783_regulators[id].voltages[0] &&
- max_uV <= mc13783_regulators[id].voltages[0])
- return 0;
- else
- return -EINVAL;
-}
-
-static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev)
-{
- int id = rdev_get_id(rdev);
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- return mc13783_regulators[id].voltages[0];
-}
-
-static struct regulator_ops mc13783_fixed_regulator_ops = {
- .enable = mc13783_regulator_enable,
- .disable = mc13783_regulator_disable,
- .is_enabled = mc13783_regulator_is_enabled,
- .list_voltage = mc13783_regulator_list_voltage,
- .set_voltage = mc13783_fixed_regulator_set_voltage,
- .get_voltage = mc13783_fixed_regulator_get_voltage,
+ MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val),
+ MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),
};
-int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
- u32 val)
+static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
+ u32 val)
{
- struct mc13783 *mc13783 = priv->mc13783;
+ struct mc13xxx *mc13783 = priv->mc13xxx;
int ret;
u32 valread;
BUG_ON(val & ~mask);
- ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
+ ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
if (ret)
return ret;
@@ -489,34 +252,36 @@ int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
priv->powermisc_pwgt_state;
- return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+ return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
}
static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
int id = rdev_get_id(rdev);
int ret;
- u32 en_val = mc13783_regulators[id].enable_bit;
+ u32 en_val = mc13xxx_regulators[id].enable_bit;
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
/* Power Gate enable value is 0 */
- if (id == MC13783_REGU_PWGT1SPI ||
- id == MC13783_REGU_PWGT2SPI)
+ if (id == MC13783_REG_PWGT1SPI ||
+ id == MC13783_REG_PWGT2SPI)
en_val = 0;
- mc13783_lock(priv->mc13783);
- ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
en_val);
- mc13783_unlock(priv->mc13783);
+ mc13xxx_unlock(priv->mc13xxx);
return ret;
}
static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
int id = rdev_get_id(rdev);
int ret;
u32 dis_val = 0;
@@ -524,27 +289,28 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
/* Power Gate disable value is 1 */
- if (id == MC13783_REGU_PWGT1SPI ||
- id == MC13783_REGU_PWGT2SPI)
- dis_val = mc13783_regulators[id].enable_bit;
+ if (id == MC13783_REG_PWGT1SPI ||
+ id == MC13783_REG_PWGT2SPI)
+ dis_val = mc13xxx_regulators[id].enable_bit;
- mc13783_lock(priv->mc13783);
- ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
dis_val);
- mc13783_unlock(priv->mc13783);
+ mc13xxx_unlock(priv->mc13xxx);
return ret;
}
static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
{
- struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
int ret, id = rdev_get_id(rdev);
unsigned int val;
- mc13783_lock(priv->mc13783);
- ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
- mc13783_unlock(priv->mc13783);
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
if (ret)
return ret;
@@ -554,22 +320,22 @@ static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
(priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M);
- return (val & mc13783_regulators[id].enable_bit) != 0;
+ return (val & mc13xxx_regulators[id].enable_bit) != 0;
}
static struct regulator_ops mc13783_gpo_regulator_ops = {
.enable = mc13783_gpo_regulator_enable,
.disable = mc13783_gpo_regulator_disable,
.is_enabled = mc13783_gpo_regulator_is_enabled,
- .list_voltage = mc13783_regulator_list_voltage,
- .set_voltage = mc13783_fixed_regulator_set_voltage,
- .get_voltage = mc13783_fixed_regulator_get_voltage,
+ .list_voltage = mc13xxx_regulator_list_voltage,
+ .set_voltage = mc13xxx_fixed_regulator_set_voltage,
+ .get_voltage = mc13xxx_fixed_regulator_get_voltage,
};
static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
{
- struct mc13783_regulator_priv *priv;
- struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_regulator_priv *priv;
+ struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
struct mc13783_regulator_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct mc13783_regulator_init_data *init_data;
@@ -583,7 +349,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->mc13783 = mc13783;
+ priv->mc13xxx_regulators = mc13783_regulators;
+ priv->mc13xxx = mc13783;
for (i = 0; i < pdata->num_regulators; i++) {
init_data = &pdata->regulators[i];
@@ -613,7 +380,7 @@ err:
static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
{
- struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev);
+ struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
struct mc13783_regulator_platform_data *pdata =
dev_get_platdata(&pdev->dev);
int i;
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
new file mode 100644
index 000000000000..1b8f7398a4a8
--- /dev/null
+++ b/drivers/regulator/mc13892-regulator.c
@@ -0,0 +1,635 @@
+/*
+ * Regulator Driver for Freescale MC13892 PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include "mc13xxx.h"
+
+#define MC13892_REVISION 7
+
+#define MC13892_POWERCTL0 13
+#define MC13892_POWERCTL0_USEROFFSPI 3
+#define MC13892_POWERCTL0_VCOINCELLVSEL 20
+#define MC13892_POWERCTL0_VCOINCELLVSEL_M (7<<20)
+#define MC13892_POWERCTL0_VCOINCELLEN (1<<23)
+
+#define MC13892_SWITCHERS0_SWxHI (1<<23)
+
+#define MC13892_SWITCHERS0 24
+#define MC13892_SWITCHERS0_SW1VSEL 0
+#define MC13892_SWITCHERS0_SW1VSEL_M (0x1f<<0)
+#define MC13892_SWITCHERS0_SW1HI (1<<23)
+#define MC13892_SWITCHERS0_SW1EN 0
+
+#define MC13892_SWITCHERS1 25
+#define MC13892_SWITCHERS1_SW2VSEL 0
+#define MC13892_SWITCHERS1_SW2VSEL_M (0x1f<<0)
+#define MC13892_SWITCHERS1_SW2HI (1<<23)
+#define MC13892_SWITCHERS1_SW2EN 0
+
+#define MC13892_SWITCHERS2 26
+#define MC13892_SWITCHERS2_SW3VSEL 0
+#define MC13892_SWITCHERS2_SW3VSEL_M (0x1f<<0)
+#define MC13892_SWITCHERS2_SW3HI (1<<23)
+#define MC13892_SWITCHERS2_SW3EN 0
+
+#define MC13892_SWITCHERS3 27
+#define MC13892_SWITCHERS3_SW4VSEL 0
+#define MC13892_SWITCHERS3_SW4VSEL_M (0x1f<<0)
+#define MC13892_SWITCHERS3_SW4HI (1<<23)
+#define MC13892_SWITCHERS3_SW4EN 0
+
+#define MC13892_SWITCHERS4 28
+#define MC13892_SWITCHERS4_SW1MODE 0
+#define MC13892_SWITCHERS4_SW1MODE_AUTO (8<<0)
+#define MC13892_SWITCHERS4_SW1MODE_M (0xf<<0)
+#define MC13892_SWITCHERS4_SW2MODE 10
+#define MC13892_SWITCHERS4_SW2MODE_AUTO (8<<10)
+#define MC13892_SWITCHERS4_SW2MODE_M (0xf<<10)
+
+#define MC13892_SWITCHERS5 29
+#define MC13892_SWITCHERS5_SW3MODE 0
+#define MC13892_SWITCHERS5_SW3MODE_AUTO (8<<0)
+#define MC13892_SWITCHERS5_SW3MODE_M (0xf<<0)
+#define MC13892_SWITCHERS5_SW4MODE 8
+#define MC13892_SWITCHERS5_SW4MODE_AUTO (8<<8)
+#define MC13892_SWITCHERS5_SW4MODE_M (0xf<<8)
+#define MC13892_SWITCHERS5_SWBSTEN (1<<20)
+
+#define MC13892_REGULATORSETTING0 30
+#define MC13892_REGULATORSETTING0_VGEN1VSEL 0
+#define MC13892_REGULATORSETTING0_VDIGVSEL 4
+#define MC13892_REGULATORSETTING0_VGEN2VSEL 6
+#define MC13892_REGULATORSETTING0_VPLLVSEL 9
+#define MC13892_REGULATORSETTING0_VUSB2VSEL 11
+#define MC13892_REGULATORSETTING0_VGEN3VSEL 14
+#define MC13892_REGULATORSETTING0_VCAMVSEL 16
+
+#define MC13892_REGULATORSETTING0_VGEN1VSEL_M (3<<0)
+#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4)
+#define MC13892_REGULATORSETTING0_VGEN2VSEL_M (7<<6)
+#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9)
+#define MC13892_REGULATORSETTING0_VUSB2VSEL_M (3<<11)
+#define MC13892_REGULATORSETTING0_VGEN3VSEL_M (1<<14)
+#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16)
+
+#define MC13892_REGULATORSETTING1 31
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4
+#define MC13892_REGULATORSETTING1_VSDVSEL 6
+
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M (3<<2)
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M (3<<4)
+#define MC13892_REGULATORSETTING1_VSDVSEL_M (7<<6)
+
+#define MC13892_REGULATORMODE0 32
+#define MC13892_REGULATORMODE0_VGEN1EN (1<<0)
+#define MC13892_REGULATORMODE0_VGEN1STDBY (1<<1)
+#define MC13892_REGULATORMODE0_VGEN1MODE (1<<2)
+#define MC13892_REGULATORMODE0_VIOHIEN (1<<3)
+#define MC13892_REGULATORMODE0_VIOHISTDBY (1<<4)
+#define MC13892_REGULATORMODE0_VIOHIMODE (1<<5)
+#define MC13892_REGULATORMODE0_VDIGEN (1<<9)
+#define MC13892_REGULATORMODE0_VDIGSTDBY (1<<10)
+#define MC13892_REGULATORMODE0_VDIGMODE (1<<11)
+#define MC13892_REGULATORMODE0_VGEN2EN (1<<12)
+#define MC13892_REGULATORMODE0_VGEN2STDBY (1<<13)
+#define MC13892_REGULATORMODE0_VGEN2MODE (1<<14)
+#define MC13892_REGULATORMODE0_VPLLEN (1<<15)
+#define MC13892_REGULATORMODE0_VPLLSTDBY (1<<16)
+#define MC13892_REGULATORMODE0_VPLLMODE (1<<17)
+#define MC13892_REGULATORMODE0_VUSB2EN (1<<18)
+#define MC13892_REGULATORMODE0_VUSB2STDBY (1<<19)
+#define MC13892_REGULATORMODE0_VUSB2MODE (1<<20)
+
+#define MC13892_REGULATORMODE1 33
+#define MC13892_REGULATORMODE1_VGEN3EN (1<<0)
+#define MC13892_REGULATORMODE1_VGEN3STDBY (1<<1)
+#define MC13892_REGULATORMODE1_VGEN3MODE (1<<2)
+#define MC13892_REGULATORMODE1_VCAMEN (1<<6)
+#define MC13892_REGULATORMODE1_VCAMSTDBY (1<<7)
+#define MC13892_REGULATORMODE1_VCAMMODE (1<<8)
+#define MC13892_REGULATORMODE1_VCAMCONFIGEN (1<<9)
+#define MC13892_REGULATORMODE1_VVIDEOEN (1<<12)
+#define MC13892_REGULATORMODE1_VVIDEOSTDBY (1<<13)
+#define MC13892_REGULATORMODE1_VVIDEOMODE (1<<14)
+#define MC13892_REGULATORMODE1_VAUDIOEN (1<<15)
+#define MC13892_REGULATORMODE1_VAUDIOSTDBY (1<<16)
+#define MC13892_REGULATORMODE1_VAUDIOMODE (1<<17)
+#define MC13892_REGULATORMODE1_VSDEN (1<<18)
+#define MC13892_REGULATORMODE1_VSDSTDBY (1<<19)
+#define MC13892_REGULATORMODE1_VSDMODE (1<<20)
+
+#define MC13892_POWERMISC 34
+#define MC13892_POWERMISC_GPO1EN (1<<6)
+#define MC13892_POWERMISC_GPO2EN (1<<8)
+#define MC13892_POWERMISC_GPO3EN (1<<10)
+#define MC13892_POWERMISC_GPO4EN (1<<12)
+#define MC13892_POWERMISC_PWGT1SPIEN (1<<15)
+#define MC13892_POWERMISC_PWGT2SPIEN (1<<16)
+#define MC13892_POWERMISC_GPO4ADINEN (1<<21)
+
+#define MC13892_POWERMISC_PWGTSPI_M (3 << 15)
+
+#define MC13892_USB1 50
+#define MC13892_USB1_VUSBEN (1<<3)
+
+static const int mc13892_vcoincell[] = {
+ 2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
+ 3200000, 3300000,
+};
+
+static const int mc13892_sw1[] = {
+ 600000, 625000, 650000, 675000, 700000, 725000,
+ 750000, 775000, 800000, 825000, 850000, 875000,
+ 900000, 925000, 950000, 975000, 1000000, 1025000,
+ 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+ 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+ 1350000, 1375000
+};
+
+static const int mc13892_sw[] = {
+ 600000, 625000, 650000, 675000, 700000, 725000,
+ 750000, 775000, 800000, 825000, 850000, 875000,
+ 900000, 925000, 950000, 975000, 1000000, 1025000,
+ 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+ 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+ 1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
+ 1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
+ 1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
+ 1800000, 1825000, 1850000, 1875000
+};
+
+static const int mc13892_swbst[] = {
+ 5000000,
+};
+
+static const int mc13892_viohi[] = {
+ 2775000,
+};
+
+static const int mc13892_vpll[] = {
+ 1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vdig[] = {
+ 1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vsd[] = {
+ 1800000, 2000000, 2600000, 2700000,
+ 2800000, 2900000, 3000000, 3150000,
+};
+
+static const int mc13892_vusb2[] = {
+ 2400000, 2600000, 2700000, 2775000,
+};
+
+static const int mc13892_vvideo[] = {
+ 2700000, 2775000, 2500000, 2600000,
+};
+
+static const int mc13892_vaudio[] = {
+ 2300000, 2500000, 2775000, 3000000,
+};
+
+static const int mc13892_vcam[] = {
+ 2500000, 2600000, 2750000, 3000000,
+};
+
+static const int mc13892_vgen1[] = {
+ 1200000, 1500000, 2775000, 3150000,
+};
+
+static const int mc13892_vgen2[] = {
+ 1200000, 1500000, 1600000, 1800000,
+ 2700000, 2800000, 3000000, 3150000,
+};
+
+static const int mc13892_vgen3[] = {
+ 1800000, 2900000,
+};
+
+static const int mc13892_vusb[] = {
+ 3300000,
+};
+
+static const int mc13892_gpo[] = {
+ 2750000,
+};
+
+static const int mc13892_pwgtdrv[] = {
+ 5000000,
+};
+
+static struct regulator_ops mc13892_gpo_regulator_ops;
+/* sw regulators need special care due to the "hi bit" */
+static struct regulator_ops mc13892_sw_regulator_ops;
+
+
+#define MC13892_FIXED_DEFINE(name, reg, voltages) \
+ MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \
+ mc13xxx_fixed_regulator_ops)
+
+#define MC13892_GPO_DEFINE(name, reg, voltages) \
+ MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \
+ mc13892_gpo_regulator_ops)
+
+#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) \
+ MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+ mc13892_sw_regulator_ops)
+
+#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) \
+ MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+ mc13xxx_regulator_ops)
+
+static struct mc13xxx_regulator mc13892_regulators[] = {
+ MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell),
+ MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
+ MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
+ MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
+ MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
+ MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
+ MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
+ MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, \
+ mc13892_vpll),
+ MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \
+ mc13892_vdig),
+ MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, \
+ mc13892_vsd),
+ MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, \
+ mc13892_vusb2),
+ MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, \
+ mc13892_vvideo),
+ MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, \
+ mc13892_vaudio),
+ MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
+ mc13892_vcam),
+ MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, \
+ mc13892_vgen1),
+ MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, \
+ mc13892_vgen2),
+ MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, \
+ mc13892_vgen3),
+ MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
+ MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
+ MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
+ MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
+ MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
+ MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
+ MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
+};
+
+static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
+ u32 val)
+{
+ struct mc13xxx *mc13892 = priv->mc13xxx;
+ int ret;
+ u32 valread;
+
+ BUG_ON(val & ~mask);
+
+ ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
+ if (ret)
+ return ret;
+
+ /* Update the stored state for Power Gates. */
+ priv->powermisc_pwgt_state =
+ (priv->powermisc_pwgt_state & ~mask) | val;
+ priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
+
+ /* Construct the new register value */
+ valread = (valread & ~mask) | val;
+ /* Overwrite the PWGTxEN with the stored version */
+ valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
+ priv->powermisc_pwgt_state;
+
+ return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+}
+
+static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+ u32 en_val = mc13892_regulators[id].enable_bit;
+ u32 mask = mc13892_regulators[id].enable_bit;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ /* Power Gate enable value is 0 */
+ if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
+ en_val = 0;
+
+ if (id == MC13892_GPO4)
+ mask |= MC13892_POWERMISC_GPO4ADINEN;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13892_powermisc_rmw(priv, mask, en_val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+ u32 dis_val = 0;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ /* Power Gate disable value is 1 */
+ if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
+ dis_val = mc13892_regulators[id].enable_bit;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
+ dis_val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ if (ret)
+ return ret;
+
+ /* Power Gates state is stored in powermisc_pwgt_state
+ * where the meaning of bits is negated */
+ val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
+ (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
+
+ return (val & mc13892_regulators[id].enable_bit) != 0;
+}
+
+
+static struct regulator_ops mc13892_gpo_regulator_ops = {
+ .enable = mc13892_gpo_regulator_enable,
+ .disable = mc13892_gpo_regulator_disable,
+ .is_enabled = mc13892_gpo_regulator_is_enabled,
+ .list_voltage = mc13xxx_regulator_list_voltage,
+ .set_voltage = mc13xxx_fixed_regulator_set_voltage,
+ .get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+
+static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val, hi;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx,
+ mc13892_regulators[id].vsel_reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
+ if (ret)
+ return ret;
+
+ hi = val & MC13892_SWITCHERS0_SWxHI;
+ val = (val & mc13892_regulators[id].vsel_mask)
+ >> mc13892_regulators[id].vsel_shift;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+ if (hi)
+ val = (25000 * val) + 1100000;
+ else
+ val = (25000 * val) + 600000;
+
+ return val;
+}
+
+static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int hi, value, val, mask, id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ /* Find the best index */
+ value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
+ dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+ if (value < 0)
+ return value;
+
+ value = mc13892_regulators[id].voltages[value];
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx,
+ mc13892_regulators[id].vsel_reg, &val);
+ if (ret)
+ goto err;
+
+ hi = val & MC13892_SWITCHERS0_SWxHI;
+ if (value > 1375)
+ hi = 1;
+ if (value < 1100)
+ hi = 0;
+
+ if (hi) {
+ value = (value - 1100000) / 25000;
+ value |= MC13892_SWITCHERS0_SWxHI;
+ } else
+ value = (value - 600000) / 25000;
+
+ mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
+ mask, value << mc13892_regulators[id].vsel_shift);
+err:
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static struct regulator_ops mc13892_sw_regulator_ops = {
+ .is_enabled = mc13xxx_sw_regulator_is_enabled,
+ .list_voltage = mc13xxx_regulator_list_voltage,
+ .set_voltage = mc13892_sw_regulator_set_voltage,
+ .get_voltage = mc13892_sw_regulator_get_voltage,
+};
+
+static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ unsigned int en_val = 0;
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+
+ if (mode == REGULATOR_MODE_FAST)
+ en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
+ MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ if (ret)
+ return ret;
+
+ if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
+ return REGULATOR_MODE_FAST;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+
+static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
+{
+ struct mc13xxx_regulator_priv *priv;
+ struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct mc13xxx_regulator_init_data *init_data;
+ int i, ret;
+ u32 val;
+
+ priv = kzalloc(sizeof(*priv) +
+ pdata->num_regulators * sizeof(priv->regulators[0]),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->mc13xxx_regulators = mc13892_regulators;
+ priv->mc13xxx = mc13892;
+
+ mc13xxx_lock(mc13892);
+ ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
+ if (ret)
+ goto err_free;
+
+ /* enable switch auto mode */
+ if ((val & 0x0000FFFF) == 0x45d0) {
+ ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
+ MC13892_SWITCHERS4_SW1MODE_M |
+ MC13892_SWITCHERS4_SW2MODE_M,
+ MC13892_SWITCHERS4_SW1MODE_AUTO |
+ MC13892_SWITCHERS4_SW2MODE_AUTO);
+ if (ret)
+ goto err_free;
+
+ ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
+ MC13892_SWITCHERS5_SW3MODE_M |
+ MC13892_SWITCHERS5_SW4MODE_M,
+ MC13892_SWITCHERS5_SW3MODE_AUTO |
+ MC13892_SWITCHERS5_SW4MODE_AUTO);
+ if (ret)
+ goto err_free;
+ }
+ mc13xxx_unlock(mc13892);
+
+ mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
+ = mc13892_vcam_set_mode;
+ mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
+ = mc13892_vcam_get_mode;
+ for (i = 0; i < pdata->num_regulators; i++) {
+ init_data = &pdata->regulators[i];
+ priv->regulators[i] = regulator_register(
+ &mc13892_regulators[init_data->id].desc,
+ &pdev->dev, init_data->init_data, priv);
+
+ if (IS_ERR(priv->regulators[i])) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ mc13892_regulators[i].desc.name);
+ ret = PTR_ERR(priv->regulators[i]);
+ goto err;
+ }
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+err:
+ while (--i >= 0)
+ regulator_unregister(priv->regulators[i]);
+
+err_free:
+ mc13xxx_unlock(mc13892);
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
+{
+ struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
+ struct mc13xxx_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ int i;
+
+ platform_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < pdata->num_regulators; i++)
+ regulator_unregister(priv->regulators[i]);
+
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver mc13892_regulator_driver = {
+ .driver = {
+ .name = "mc13892-regulator",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(mc13892_regulator_remove),
+ .probe = mc13892_regulator_probe,
+};
+
+static int __init mc13892_regulator_init(void)
+{
+ return platform_driver_register(&mc13892_regulator_driver);
+}
+subsys_initcall(mc13892_regulator_init);
+
+static void __exit mc13892_regulator_exit(void)
+{
+ platform_driver_unregister(&mc13892_regulator_driver);
+}
+module_exit(mc13892_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
+MODULE_ALIAS("platform:mc13892-regulator");
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
new file mode 100644
index 000000000000..f53d31b950d4
--- /dev/null
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -0,0 +1,241 @@
+/*
+ * Regulator Driver for Freescale MC13xxx PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * Based on mc13783 regulator driver :
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file
+ * from freescale
+ */
+
+#include <linux/mfd/mc13xxx.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include "mc13xxx.h"
+
+static int mc13xxx_regulator_enable(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg,
+ mc13xxx_regulators[id].enable_bit,
+ mc13xxx_regulators[id].enable_bit);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static int mc13xxx_regulator_disable(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg,
+ mc13xxx_regulators[id].enable_bit, 0);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ if (ret)
+ return ret;
+
+ return (val & mc13xxx_regulators[id].enable_bit) != 0;
+}
+
+int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int id = rdev_get_id(rdev);
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+
+ if (selector >= mc13xxx_regulators[id].desc.n_voltages)
+ return -EINVAL;
+
+ return mc13xxx_regulators[id].voltages[selector];
+}
+EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
+
+int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int reg_id = rdev_get_id(rdev);
+ int i;
+ int bestmatch;
+ int bestindex;
+
+ /*
+ * Locate the minimum voltage fitting the criteria on
+ * this regulator. The switchable voltages are not
+ * in strict falling order so we need to check them
+ * all for the best match.
+ */
+ bestmatch = INT_MAX;
+ bestindex = -1;
+ for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) {
+ if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV &&
+ mc13xxx_regulators[reg_id].voltages[i] < bestmatch) {
+ bestmatch = mc13xxx_regulators[reg_id].voltages[i];
+ bestindex = i;
+ }
+ }
+
+ if (bestindex < 0 || bestmatch > max_uV) {
+ dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ return bestindex;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index);
+
+static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int value, id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ /* Find the best index */
+ value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
+ dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+ if (value < 0)
+ return value;
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg,
+ mc13xxx_regulators[id].vsel_mask,
+ value << mc13xxx_regulators[id].vsel_shift);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13xxx_lock(priv->mc13xxx);
+ ret = mc13xxx_reg_read(priv->mc13xxx,
+ mc13xxx_regulators[id].vsel_reg, &val);
+ mc13xxx_unlock(priv->mc13xxx);
+
+ if (ret)
+ return ret;
+
+ val = (val & mc13xxx_regulators[id].vsel_mask)
+ >> mc13xxx_regulators[id].vsel_shift;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+ BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages);
+
+ return mc13xxx_regulators[id].voltages[val];
+}
+
+struct regulator_ops mc13xxx_regulator_ops = {
+ .enable = mc13xxx_regulator_enable,
+ .disable = mc13xxx_regulator_disable,
+ .is_enabled = mc13xxx_regulator_is_enabled,
+ .list_voltage = mc13xxx_regulator_list_voltage,
+ .set_voltage = mc13xxx_regulator_set_voltage,
+ .get_voltage = mc13xxx_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops);
+
+int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ if (min_uV >= mc13xxx_regulators[id].voltages[0] &&
+ max_uV <= mc13xxx_regulators[id].voltages[0])
+ return 0;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
+
+int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ return mc13xxx_regulators[id].voltages[0];
+}
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
+
+struct regulator_ops mc13xxx_fixed_regulator_ops = {
+ .enable = mc13xxx_regulator_enable,
+ .disable = mc13xxx_regulator_disable,
+ .is_enabled = mc13xxx_regulator_is_enabled,
+ .list_voltage = mc13xxx_regulator_list_voltage,
+ .set_voltage = mc13xxx_fixed_regulator_set_voltage,
+ .get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
+
+int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ return 1;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC");
+MODULE_ALIAS("mc13xxx-regulator-core");
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
new file mode 100644
index 000000000000..27758267e122
--- /dev/null
+++ b/drivers/regulator/mc13xxx.h
@@ -0,0 +1,101 @@
+/*
+ * mc13xxx.h - regulators for the Freescale mc13xxx PMIC
+ *
+ * Copyright (C) 2010 Yong Shen <yong.shen@linaro.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.
+ */
+
+#ifndef __LINUX_REGULATOR_MC13XXX_H
+#define __LINUX_REGULATOR_MC13XXX_H
+
+#include <linux/regulator/driver.h>
+
+struct mc13xxx_regulator {
+ struct regulator_desc desc;
+ int reg;
+ int enable_bit;
+ int vsel_reg;
+ int vsel_shift;
+ int vsel_mask;
+ int hi_bit;
+ int const *voltages;
+};
+
+struct mc13xxx_regulator_priv {
+ struct mc13xxx *mc13xxx;
+ u32 powermisc_pwgt_state;
+ struct mc13xxx_regulator *mc13xxx_regulators;
+ struct regulator_dev *regulators[];
+};
+
+extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
+extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
+extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV);
+extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned selector);
+extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector);
+extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
+
+extern struct regulator_ops mc13xxx_regulator_ops;
+extern struct regulator_ops mc13xxx_fixed_regulator_ops;
+
+#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \
+ [prefix ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = prefix ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = prefix ## _reg, \
+ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \
+ .vsel_reg = prefix ## _vsel_reg, \
+ .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
+ .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
+ .voltages = _voltages, \
+ }
+
+#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \
+ [prefix ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = prefix ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = prefix ## _reg, \
+ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \
+ .voltages = _voltages, \
+ }
+
+#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \
+ [prefix ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = prefix ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = prefix ## _reg, \
+ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \
+ .voltages = _voltages, \
+ }
+
+#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \
+ MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops)
+#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops) \
+ MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops)
+
+#endif
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 29d0566379ae..31f6e11a7f16 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -151,7 +151,8 @@ static struct pcap_regulator vreg_table[] = {
};
static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
void *pcap = rdev_get_drvdata(rdev);
@@ -170,10 +171,12 @@ static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
i = 0;
uV = vreg->voltage_table[i] * 1000;
- if (min_uV <= uV && uV <= max_uV)
+ if (min_uV <= uV && uV <= max_uV) {
+ *selector = i;
return ezx_pcap_set_bits(pcap, vreg->reg,
(vreg->n_voltages - 1) << vreg->index,
i << vreg->index);
+ }
if (i == 0 && rdev_get_id(rdev) == V1)
i = vreg->n_voltages - 1;
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index c8f41dc05b76..69a11d9dd87f 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -108,7 +108,8 @@ static unsigned int ldo_voltage_value(u8 bits)
}
static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct pcf50633 *pcf;
int regulator_id, millivolts;
@@ -147,6 +148,8 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
return -EINVAL;
}
+ *selector = volt_bits;
+
return pcf50633_reg_write(pcf, regnr, volt_bits);
}
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index cd6d4fc9d74f..60a7ca5409e9 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -321,7 +321,8 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
}
static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
@@ -346,6 +347,8 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
break;
}
+ *selector = vsel;
+
/* write to the register in case we found a match */
if (vsel == tps->info[dcdc]->table_len)
return -EINVAL;
@@ -371,7 +374,7 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
}
static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, ldo = rdev_get_id(dev);
@@ -396,6 +399,8 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
if (vsel == tps->info[ldo]->table_len)
return -EINVAL;
+ *selector = vsel;
+
data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL);
if (data < 0)
return data;
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 020f5878d7ff..064755290599 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -369,7 +369,8 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev)
}
static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, dcdc = rdev_get_id(dev);
@@ -415,6 +416,8 @@ static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev,
if (vsel == tps->info[dcdc]->table_len)
return -EINVAL;
+ *selector = vsel;
+
data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0)
return data;
@@ -450,7 +453,8 @@ static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev)
}
static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, ldo = rdev_get_id(dev);
@@ -483,6 +487,8 @@ static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev,
if (vsel == tps->info[ldo]->table_len)
return -EINVAL;
+ *selector = vsel;
+
data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0)
return data;
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
new file mode 100644
index 000000000000..176a6be5a8ce
--- /dev/null
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -0,0 +1,693 @@
+/*
+ * Regulator driver for TPS6524x PMIC
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define REG_LDO_SET 0x0
+#define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */
+#define LDO_VSEL_MASK 0x0f
+#define LDO2_ILIM_SHIFT 12
+#define LDO2_VSEL_SHIFT 4
+#define LDO1_ILIM_SHIFT 8
+#define LDO1_VSEL_SHIFT 0
+
+#define REG_BLOCK_EN 0x1
+#define BLOCK_MASK 1
+#define BLOCK_LDO1_SHIFT 0
+#define BLOCK_LDO2_SHIFT 1
+#define BLOCK_LCD_SHIFT 2
+#define BLOCK_USB_SHIFT 3
+
+#define REG_DCDC_SET 0x2
+#define DCDC_VDCDC_MASK 0x1f
+#define DCDC_VDCDC1_SHIFT 0
+#define DCDC_VDCDC2_SHIFT 5
+#define DCDC_VDCDC3_SHIFT 10
+
+#define REG_DCDC_EN 0x3
+#define DCDCDCDC_EN_MASK 0x1
+#define DCDCDCDC1_EN_SHIFT 0
+#define DCDCDCDC1_PG_MSK BIT(1)
+#define DCDCDCDC2_EN_SHIFT 2
+#define DCDCDCDC2_PG_MSK BIT(3)
+#define DCDCDCDC3_EN_SHIFT 4
+#define DCDCDCDC3_PG_MSK BIT(5)
+
+#define REG_USB 0x4
+#define USB_ILIM_SHIFT 0
+#define USB_ILIM_MASK 0x3
+#define USB_TSD_SHIFT 2
+#define USB_TSD_MASK 0x3
+#define USB_TWARN_SHIFT 4
+#define USB_TWARN_MASK 0x3
+#define USB_IWARN_SD BIT(6)
+#define USB_FAST_LOOP BIT(7)
+
+#define REG_ALARM 0x5
+#define ALARM_LDO1 BIT(0)
+#define ALARM_DCDC1 BIT(1)
+#define ALARM_DCDC2 BIT(2)
+#define ALARM_DCDC3 BIT(3)
+#define ALARM_LDO2 BIT(4)
+#define ALARM_USB_WARN BIT(5)
+#define ALARM_USB_ALARM BIT(6)
+#define ALARM_LCD BIT(9)
+#define ALARM_TEMP_WARM BIT(10)
+#define ALARM_TEMP_HOT BIT(11)
+#define ALARM_NRST BIT(14)
+#define ALARM_POWERUP BIT(15)
+
+#define REG_INT_ENABLE 0x6
+#define INT_LDO1 BIT(0)
+#define INT_DCDC1 BIT(1)
+#define INT_DCDC2 BIT(2)
+#define INT_DCDC3 BIT(3)
+#define INT_LDO2 BIT(4)
+#define INT_USB_WARN BIT(5)
+#define INT_USB_ALARM BIT(6)
+#define INT_LCD BIT(9)
+#define INT_TEMP_WARM BIT(10)
+#define INT_TEMP_HOT BIT(11)
+#define INT_GLOBAL_EN BIT(15)
+
+#define REG_INT_STATUS 0x7
+#define STATUS_LDO1 BIT(0)
+#define STATUS_DCDC1 BIT(1)
+#define STATUS_DCDC2 BIT(2)
+#define STATUS_DCDC3 BIT(3)
+#define STATUS_LDO2 BIT(4)
+#define STATUS_USB_WARN BIT(5)
+#define STATUS_USB_ALARM BIT(6)
+#define STATUS_LCD BIT(9)
+#define STATUS_TEMP_WARM BIT(10)
+#define STATUS_TEMP_HOT BIT(11)
+
+#define REG_SOFTWARE_RESET 0xb
+#define REG_WRITE_ENABLE 0xd
+#define REG_REV_ID 0xf
+
+#define N_DCDC 3
+#define N_LDO 2
+#define N_SWITCH 2
+#define N_REGULATORS (3 /* DCDC */ + \
+ 2 /* LDO */ + \
+ 2 /* switch */)
+
+#define FIXED_ILIMSEL BIT(0)
+#define FIXED_VOLTAGE BIT(1)
+
+#define CMD_READ(reg) ((reg) << 6)
+#define CMD_WRITE(reg) (BIT(5) | (reg) << 6)
+#define STAT_CLK BIT(3)
+#define STAT_WRITE BIT(2)
+#define STAT_INVALID BIT(1)
+#define STAT_WP BIT(0)
+
+struct field {
+ int reg;
+ int shift;
+ int mask;
+};
+
+struct supply_info {
+ const char *name;
+ int n_voltages;
+ const int *voltages;
+ int fixed_voltage;
+ int n_ilimsels;
+ const int *ilimsels;
+ int fixed_ilimsel;
+ int flags;
+ struct field enable, voltage, ilimsel;
+};
+
+struct tps6524x {
+ struct device *dev;
+ struct spi_device *spi;
+ struct mutex lock;
+ struct regulator_desc desc[N_REGULATORS];
+ struct regulator_dev *rdev[N_REGULATORS];
+};
+
+static int __read_reg(struct tps6524x *hw, int reg)
+{
+ int error = 0;
+ u16 cmd = CMD_READ(reg), in;
+ u8 status;
+ struct spi_message m;
+ struct spi_transfer t[3];
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = &cmd;
+ t[0].len = 2;
+ t[0].bits_per_word = 12;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = &in;
+ t[1].len = 2;
+ t[1].bits_per_word = 16;
+ spi_message_add_tail(&t[1], &m);
+
+ t[2].rx_buf = &status;
+ t[2].len = 1;
+ t[2].bits_per_word = 4;
+ spi_message_add_tail(&t[2], &m);
+
+ error = spi_sync(hw->spi, &m);
+ if (error < 0)
+ return error;
+
+ dev_dbg(hw->dev, "read reg %d, data %x, status %x\n",
+ reg, in, status);
+
+ if (!(status & STAT_CLK) || (status & STAT_WRITE))
+ return -EIO;
+
+ if (status & STAT_INVALID)
+ return -EINVAL;
+
+ return in;
+}
+
+static int read_reg(struct tps6524x *hw, int reg)
+{
+ int ret;
+
+ mutex_lock(&hw->lock);
+ ret = __read_reg(hw, reg);
+ mutex_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int __write_reg(struct tps6524x *hw, int reg, int val)
+{
+ int error = 0;
+ u16 cmd = CMD_WRITE(reg), out = val;
+ u8 status;
+ struct spi_message m;
+ struct spi_transfer t[3];
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = &cmd;
+ t[0].len = 2;
+ t[0].bits_per_word = 12;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = &out;
+ t[1].len = 2;
+ t[1].bits_per_word = 16;
+ spi_message_add_tail(&t[1], &m);
+
+ t[2].rx_buf = &status;
+ t[2].len = 1;
+ t[2].bits_per_word = 4;
+ spi_message_add_tail(&t[2], &m);
+
+ error = spi_sync(hw->spi, &m);
+ if (error < 0)
+ return error;
+
+ dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n",
+ reg, out, status);
+
+ if (!(status & STAT_CLK) || !(status & STAT_WRITE))
+ return -EIO;
+
+ if (status & (STAT_INVALID | STAT_WP))
+ return -EINVAL;
+
+ return error;
+}
+
+static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val)
+{
+ int ret;
+
+ ret = __read_reg(hw, reg);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~mask;
+ ret |= val;
+
+ ret = __write_reg(hw, reg, ret);
+
+ return (ret < 0) ? ret : 0;
+}
+
+static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val)
+{
+ int ret;
+
+ mutex_lock(&hw->lock);
+
+ ret = __write_reg(hw, REG_WRITE_ENABLE, 1);
+ if (ret) {
+ dev_err(hw->dev, "failed to set write enable\n");
+ goto error;
+ }
+
+ ret = __rmw_reg(hw, reg, mask, val);
+ if (ret)
+ dev_err(hw->dev, "failed to rmw register %d\n", reg);
+
+ ret = __write_reg(hw, REG_WRITE_ENABLE, 0);
+ if (ret) {
+ dev_err(hw->dev, "failed to clear write enable\n");
+ goto error;
+ }
+
+error:
+ mutex_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int read_field(struct tps6524x *hw, const struct field *field)
+{
+ int tmp;
+
+ tmp = read_reg(hw, field->reg);
+ if (tmp < 0)
+ return tmp;
+
+ return (tmp >> field->shift) & field->mask;
+}
+
+static int write_field(struct tps6524x *hw, const struct field *field,
+ int val)
+{
+ if (val & ~field->mask)
+ return -EOVERFLOW;
+
+ return rmw_protect(hw, field->reg,
+ field->mask << field->shift,
+ val << field->shift);
+}
+
+static const int dcdc1_voltages[] = {
+ 800000, 825000, 850000, 875000,
+ 900000, 925000, 950000, 975000,
+ 1000000, 1025000, 1050000, 1075000,
+ 1100000, 1125000, 1150000, 1175000,
+ 1200000, 1225000, 1250000, 1275000,
+ 1300000, 1325000, 1350000, 1375000,
+ 1400000, 1425000, 1450000, 1475000,
+ 1500000, 1525000, 1550000, 1575000,
+};
+
+static const int dcdc2_voltages[] = {
+ 1400000, 1450000, 1500000, 1550000,
+ 1600000, 1650000, 1700000, 1750000,
+ 1800000, 1850000, 1900000, 1950000,
+ 2000000, 2050000, 2100000, 2150000,
+ 2200000, 2250000, 2300000, 2350000,
+ 2400000, 2450000, 2500000, 2550000,
+ 2600000, 2650000, 2700000, 2750000,
+ 2800000, 2850000, 2900000, 2950000,
+};
+
+static const int dcdc3_voltages[] = {
+ 2400000, 2450000, 2500000, 2550000, 2600000,
+ 2650000, 2700000, 2750000, 2800000, 2850000,
+ 2900000, 2950000, 3000000, 3050000, 3100000,
+ 3150000, 3200000, 3250000, 3300000, 3350000,
+ 3400000, 3450000, 3500000, 3550000, 3600000,
+};
+
+static const int ldo1_voltages[] = {
+ 4300000, 4350000, 4400000, 4450000,
+ 4500000, 4550000, 4600000, 4650000,
+ 4700000, 4750000, 4800000, 4850000,
+ 4900000, 4950000, 5000000, 5050000,
+};
+
+static const int ldo2_voltages[] = {
+ 1100000, 1150000, 1200000, 1250000,
+ 1300000, 1700000, 1750000, 1800000,
+ 1850000, 1900000, 3150000, 3200000,
+ 3250000, 3300000, 3350000, 3400000,
+};
+
+static const int ldo_ilimsel[] = {
+ 400000, 1500000
+};
+
+static const int usb_ilimsel[] = {
+ 200000, 400000, 800000, 1000000
+};
+
+#define __MK_FIELD(_reg, _mask, _shift) \
+ { .reg = (_reg), .mask = (_mask), .shift = (_shift), }
+
+static const struct supply_info supply_info[N_REGULATORS] = {
+ {
+ .name = "DCDC1",
+ .flags = FIXED_ILIMSEL,
+ .n_voltages = ARRAY_SIZE(dcdc1_voltages),
+ .voltages = dcdc1_voltages,
+ .fixed_ilimsel = 2400000,
+ .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+ DCDCDCDC1_EN_SHIFT),
+ .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+ DCDC_VDCDC1_SHIFT),
+ },
+ {
+ .name = "DCDC2",
+ .flags = FIXED_ILIMSEL,
+ .n_voltages = ARRAY_SIZE(dcdc2_voltages),
+ .voltages = dcdc2_voltages,
+ .fixed_ilimsel = 1200000,
+ .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+ DCDCDCDC2_EN_SHIFT),
+ .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+ DCDC_VDCDC2_SHIFT),
+ },
+ {
+ .name = "DCDC3",
+ .flags = FIXED_ILIMSEL,
+ .n_voltages = ARRAY_SIZE(dcdc3_voltages),
+ .voltages = dcdc3_voltages,
+ .fixed_ilimsel = 1200000,
+ .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+ DCDCDCDC3_EN_SHIFT),
+ .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+ DCDC_VDCDC3_SHIFT),
+ },
+ {
+ .name = "LDO1",
+ .n_voltages = ARRAY_SIZE(ldo1_voltages),
+ .voltages = ldo1_voltages,
+ .n_ilimsels = ARRAY_SIZE(ldo_ilimsel),
+ .ilimsels = ldo_ilimsel,
+ .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+ BLOCK_LDO1_SHIFT),
+ .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+ LDO1_VSEL_SHIFT),
+ .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+ LDO1_ILIM_SHIFT),
+ },
+ {
+ .name = "LDO2",
+ .n_voltages = ARRAY_SIZE(ldo2_voltages),
+ .voltages = ldo2_voltages,
+ .n_ilimsels = ARRAY_SIZE(ldo_ilimsel),
+ .ilimsels = ldo_ilimsel,
+ .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+ BLOCK_LDO2_SHIFT),
+ .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+ LDO2_VSEL_SHIFT),
+ .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+ LDO2_ILIM_SHIFT),
+ },
+ {
+ .name = "USB",
+ .flags = FIXED_VOLTAGE,
+ .fixed_voltage = 5000000,
+ .n_ilimsels = ARRAY_SIZE(usb_ilimsel),
+ .ilimsels = usb_ilimsel,
+ .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+ BLOCK_USB_SHIFT),
+ .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK,
+ USB_ILIM_SHIFT),
+ },
+ {
+ .name = "LCD",
+ .flags = FIXED_VOLTAGE | FIXED_ILIMSEL,
+ .fixed_voltage = 5000000,
+ .fixed_ilimsel = 400000,
+ .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+ BLOCK_LCD_SHIFT),
+ },
+};
+
+static int list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ if (info->flags & FIXED_VOLTAGE)
+ return selector ? -EINVAL : info->fixed_voltage;
+
+ return ((selector < info->n_voltages) ?
+ info->voltages[selector] : -EINVAL);
+}
+
+static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned *selector)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+ unsigned i;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ if (info->flags & FIXED_VOLTAGE)
+ return -EINVAL;
+
+ for (i = 0; i < info->n_voltages; i++)
+ if (min_uV <= info->voltages[i] &&
+ max_uV >= info->voltages[i])
+ break;
+
+ if (i >= info->n_voltages)
+ i = info->n_voltages - 1;
+
+ *selector = info->voltages[i];
+
+ return write_field(hw, &info->voltage, i);
+}
+
+static int get_voltage(struct regulator_dev *rdev)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+ int ret;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ if (info->flags & FIXED_VOLTAGE)
+ return info->fixed_voltage;
+
+ ret = read_field(hw, &info->voltage);
+ if (ret < 0)
+ return ret;
+ if (WARN_ON(ret >= info->n_voltages))
+ return -EIO;
+
+ return info->voltages[ret];
+}
+
+static int set_current_limit(struct regulator_dev *rdev, int min_uA,
+ int max_uA)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+ int i;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ if (info->flags & FIXED_ILIMSEL)
+ return -EINVAL;
+
+ for (i = 0; i < info->n_ilimsels; i++)
+ if (min_uA <= info->ilimsels[i] &&
+ max_uA >= info->ilimsels[i])
+ break;
+
+ if (i >= info->n_ilimsels)
+ return -EINVAL;
+
+ return write_field(hw, &info->ilimsel, i);
+}
+
+static int get_current_limit(struct regulator_dev *rdev)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+ int ret;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ if (info->flags & FIXED_ILIMSEL)
+ return info->fixed_ilimsel;
+
+ ret = read_field(hw, &info->ilimsel);
+ if (ret < 0)
+ return ret;
+ if (WARN_ON(ret >= info->n_ilimsels))
+ return -EIO;
+
+ return info->ilimsels[ret];
+}
+
+static int enable_supply(struct regulator_dev *rdev)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ return write_field(hw, &info->enable, 1);
+}
+
+static int disable_supply(struct regulator_dev *rdev)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ return write_field(hw, &info->enable, 0);
+}
+
+static int is_supply_enabled(struct regulator_dev *rdev)
+{
+ const struct supply_info *info;
+ struct tps6524x *hw;
+
+ hw = rdev_get_drvdata(rdev);
+ info = &supply_info[rdev_get_id(rdev)];
+
+ return read_field(hw, &info->enable);
+}
+
+static struct regulator_ops regulator_ops = {
+ .is_enabled = is_supply_enabled,
+ .enable = enable_supply,
+ .disable = disable_supply,
+ .get_voltage = get_voltage,
+ .set_voltage = set_voltage,
+ .list_voltage = list_voltage,
+ .set_current_limit = set_current_limit,
+ .get_current_limit = get_current_limit,
+};
+
+static int __devexit pmic_remove(struct spi_device *spi)
+{
+ struct tps6524x *hw = spi_get_drvdata(spi);
+ int i;
+
+ if (!hw)
+ return 0;
+ for (i = 0; i < N_REGULATORS; i++) {
+ if (hw->rdev[i])
+ regulator_unregister(hw->rdev[i]);
+ hw->rdev[i] = NULL;
+ }
+ spi_set_drvdata(spi, NULL);
+ kfree(hw);
+ return 0;
+}
+
+static int __devinit pmic_probe(struct spi_device *spi)
+{
+ struct tps6524x *hw;
+ struct device *dev = &spi->dev;
+ const struct supply_info *info = supply_info;
+ struct regulator_init_data *init_data;
+ int ret = 0, i;
+
+ init_data = dev->platform_data;
+ if (!init_data) {
+ dev_err(dev, "could not find regulator platform data\n");
+ return -EINVAL;
+ }
+
+ hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL);
+ if (!hw) {
+ dev_err(dev, "cannot allocate regulator private data\n");
+ return -ENOMEM;
+ }
+ spi_set_drvdata(spi, hw);
+
+ memset(hw, 0, sizeof(struct tps6524x));
+ hw->dev = dev;
+ hw->spi = spi_dev_get(spi);
+ mutex_init(&hw->lock);
+
+ for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
+ hw->desc[i].name = info->name;
+ hw->desc[i].id = i;
+ hw->desc[i].n_voltages = info->n_voltages;
+ hw->desc[i].ops = &regulator_ops;
+ hw->desc[i].type = REGULATOR_VOLTAGE;
+ hw->desc[i].owner = THIS_MODULE;
+
+ if (info->flags & FIXED_VOLTAGE)
+ hw->desc[i].n_voltages = 1;
+
+ hw->rdev[i] = regulator_register(&hw->desc[i], dev,
+ init_data, hw);
+ if (IS_ERR(hw->rdev[i])) {
+ ret = PTR_ERR(hw->rdev[i]);
+ hw->rdev[i] = NULL;
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ pmic_remove(spi);
+ return ret;
+}
+
+static struct spi_driver pmic_driver = {
+ .probe = pmic_probe,
+ .remove = __devexit_p(pmic_remove),
+ .driver = {
+ .name = "tps6524x",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pmic_driver_init(void)
+{
+ return spi_register_driver(&pmic_driver);
+}
+module_init(pmic_driver_init);
+
+static void __exit pmic_driver_exit(void)
+{
+ spi_unregister_driver(&pmic_driver);
+}
+module_exit(pmic_driver_exit);
+
+MODULE_DESCRIPTION("TPS6524X PMIC Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tps6524x");
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 51237fbb1bbb..bb04a75a4c98 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -85,7 +85,8 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
static int __tps6586x_ldo_set_voltage(struct device *parent,
struct tps6586x_regulator *ri,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
int val, uV;
uint8_t mask;
@@ -100,6 +101,8 @@ static int __tps6586x_ldo_set_voltage(struct device *parent,
/* use the first in-range value */
if (min_uV <= uV && uV <= max_uV) {
+ *selector = val;
+
val <<= ri->volt_shift;
mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
@@ -111,12 +114,13 @@ static int __tps6586x_ldo_set_voltage(struct device *parent,
}
static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
- return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
+ return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
+ selector);
}
static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
@@ -140,13 +144,14 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
}
static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps6586x_dev(rdev);
int ret;
- ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
+ ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
+ selector);
if (ret)
return ret;
@@ -231,8 +236,7 @@ static int tps6586x_dvm_voltages[] = {
};
#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
-{ \
+ ereg0, ebit0, ereg1, ebit1) \
.desc = { \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_##_ops, \
@@ -248,18 +252,26 @@ static int tps6586x_dvm_voltages[] = {
.enable_bit[0] = (ebit0), \
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
.enable_bit[1] = (ebit1), \
- .voltages = tps6586x_##vdata##_voltages, \
-}
+ .voltages = tps6586x_##vdata##_voltages,
+
+#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
+ .go_reg = TPS6586X_##goreg, \
+ .go_bit = (gobit),
#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
+{ \
TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, 0, 0)
+ ereg0, ebit0, ereg1, ebit1) \
+}
#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
+{ \
TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, goreg, gobit)
+ ereg0, ebit0, ereg1, ebit1) \
+ TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
+}
static struct tps6586x_regulator tps6586x_regulator[] = {
TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
@@ -267,11 +279,11 @@ static struct tps6586x_regulator tps6586x_regulator[] = {
TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
- TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6),
+ TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
- TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7),
+ TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
- TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1),
+ TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
@@ -290,6 +302,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent,
uint8_t val1, val2;
int ret;
+ if (ri->enable_reg[0] == ri->enable_reg[1] &&
+ ri->enable_bit[0] == ri->enable_bit[1])
+ return 0;
+
ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
if (ret)
return ret;
@@ -298,14 +314,14 @@ static inline int tps6586x_regulator_preinit(struct device *parent,
if (ret)
return ret;
- if (!(val2 & ri->enable_bit[1]))
+ if (!(val2 & (1 << ri->enable_bit[1])))
return 0;
/*
* The regulator is on, but it's enabled with the bit we don't
* want to use, so we switch the enable bits
*/
- if (!(val1 & ri->enable_bit[0])) {
+ if (!(val1 & (1 << ri->enable_bit[0]))) {
ret = tps6586x_set_bits(parent, ri->enable_reg[0],
1 << ri->enable_bit[0]);
if (ret)
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 7e5892efc437..bd332cf1cc3f 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -219,12 +219,12 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
return -EACCES;
status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
- message >> 8, 0x15 /* PB_WORD_MSB */ );
- if (status >= 0)
+ message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB);
+ if (status < 0)
return status;
return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
- message, 0x16 /* PB_WORD_LSB */ );
+ message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
}
/*----------------------------------------------------------------------*/
@@ -329,7 +329,8 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
}
static int
-twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned *selector)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int vsel;
@@ -345,9 +346,11 @@ twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
/* REVISIT for VAUX2, first match may not be best/lowest */
/* use the first in-range value */
- if (min_uV <= uV && uV <= max_uV)
+ if (min_uV <= uV && uV <= max_uV) {
+ *selector = vsel;
return twlreg_write(info, TWL_MODULE_PM_RECEIVER,
VREG_VOLTAGE, vsel);
+ }
}
return -EDOM;
@@ -389,7 +392,8 @@ static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
}
static int
-twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned *selector)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int vsel;
@@ -402,6 +406,7 @@ twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
* mV = 1000mv + 100mv * (vsel - 1)
*/
vsel = (min_uV/1000 - 1000)/100 + 1;
+ *selector = vsel;
return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
}
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index dbfaf5945e48..8b0d2c4bde91 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -302,7 +302,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
}
static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
struct wm831x *wm831x = dcdc->wm831x;
@@ -314,6 +314,8 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
if (vsel < 0)
return vsel;
+ *selector = vsel;
+
/* If this value is already set then do a GPIO update if we can */
if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
return wm831x_buckv_set_dvs(rdev, 0);
@@ -375,14 +377,14 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
}
-static int wm831x_buckv_get_voltage(struct regulator_dev *rdev)
+static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
- return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel);
+ return dcdc->dvs_vsel;
else
- return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel);
+ return dcdc->on_vsel;
}
/* Current limit options */
@@ -424,7 +426,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
static struct regulator_ops wm831x_buckv_ops = {
.set_voltage = wm831x_buckv_set_voltage,
- .get_voltage = wm831x_buckv_get_voltage,
+ .get_voltage_sel = wm831x_buckv_get_voltage_sel,
.list_voltage = wm831x_buckv_list_voltage,
.set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
.set_current_limit = wm831x_buckv_set_current_limit,
@@ -636,7 +638,7 @@ static int wm831x_buckp_list_voltage(struct regulator_dev *rdev,
}
static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, int *selector)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
struct wm831x *wm831x = dcdc->wm831x;
@@ -650,16 +652,20 @@ static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV)
return -EINVAL;
+ *selector = vsel;
+
return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel);
}
static int wm831x_buckp_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
- return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV);
+ return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV,
+ selector);
}
static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
@@ -667,11 +673,12 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+ unsigned selector;
- return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_buckp_get_voltage(struct regulator_dev *rdev)
+static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
struct wm831x *wm831x = dcdc->wm831x;
@@ -682,12 +689,12 @@ static int wm831x_buckp_get_voltage(struct regulator_dev *rdev)
if (val < 0)
return val;
- return wm831x_buckp_list_voltage(rdev, val & WM831X_DC3_ON_VSEL_MASK);
+ return val & WM831X_DC3_ON_VSEL_MASK;
}
static struct regulator_ops wm831x_buckp_ops = {
.set_voltage = wm831x_buckp_set_voltage,
- .get_voltage = wm831x_buckp_get_voltage,
+ .get_voltage_sel = wm831x_buckp_get_voltage_sel,
.list_voltage = wm831x_buckp_list_voltage,
.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 9edf8f692341..c94fc5b7cd5b 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -113,7 +113,8 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
}
static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -133,16 +134,20 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
if (ret < min_uV || ret > max_uV)
return -EINVAL;
+ *selector = vsel;
+
return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel);
}
static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_LDO_ON_CONTROL;
- return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV);
+ return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+ selector);
}
static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
@@ -150,11 +155,12 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+ unsigned int selector;
- return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev)
+static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -167,7 +173,7 @@ static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev)
ret &= WM831X_LDO1_ON_VSEL_MASK;
- return wm831x_gp_ldo_list_voltage(rdev, ret);
+ return ret;
}
static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
@@ -287,7 +293,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
static struct regulator_ops wm831x_gp_ldo_ops = {
.list_voltage = wm831x_gp_ldo_list_voltage,
- .get_voltage = wm831x_gp_ldo_get_voltage,
+ .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel,
.set_voltage = wm831x_gp_ldo_set_voltage,
.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
.get_mode = wm831x_gp_ldo_get_mode,
@@ -413,7 +419,8 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
}
static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -433,16 +440,19 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
if (ret < min_uV || ret > max_uV)
return -EINVAL;
+ *selector = vsel;
+
return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel);
}
static int wm831x_aldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_LDO_ON_CONTROL;
- return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV);
+ return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+ selector);
}
static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
@@ -450,11 +460,12 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+ unsigned int selector;
- return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_aldo_get_voltage(struct regulator_dev *rdev)
+static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -467,7 +478,7 @@ static int wm831x_aldo_get_voltage(struct regulator_dev *rdev)
ret &= WM831X_LDO7_ON_VSEL_MASK;
- return wm831x_aldo_list_voltage(rdev, ret);
+ return ret;
}
static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
@@ -548,7 +559,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
static struct regulator_ops wm831x_aldo_ops = {
.list_voltage = wm831x_aldo_list_voltage,
- .get_voltage = wm831x_aldo_get_voltage,
+ .get_voltage_sel = wm831x_aldo_get_voltage_sel,
.set_voltage = wm831x_aldo_set_voltage,
.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
.get_mode = wm831x_aldo_get_mode,
@@ -666,7 +677,8 @@ static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev,
static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
int reg,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -680,16 +692,20 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
if (ret < min_uV || ret > max_uV)
return -EINVAL;
+ *selector = vsel;
+
return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel);
}
static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV,
+ unsigned *selector)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
- return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV);
+ return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+ selector);
}
static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
@@ -697,11 +713,12 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
+ unsigned selector;
- return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
}
-static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev)
+static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
@@ -714,7 +731,7 @@ static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev)
ret &= WM831X_LDO11_ON_VSEL_MASK;
- return wm831x_alive_ldo_list_voltage(rdev, ret);
+ return ret;
}
static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
@@ -736,7 +753,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
static struct regulator_ops wm831x_alive_ldo_ops = {
.list_voltage = wm831x_alive_ldo_list_voltage,
- .get_voltage = wm831x_alive_ldo_get_voltage,
+ .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel,
.set_voltage = wm831x_alive_ldo_set_voltage,
.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
.get_status = wm831x_alive_ldo_get_status,
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index fe4b8a8a9dfd..1bcb22c44095 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -360,7 +360,7 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV)
+ int max_uV, unsigned *selector)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
int volt_reg, dcdc = rdev_get_id(rdev), mV,
@@ -397,17 +397,18 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
return -EINVAL;
}
+ *selector = mV;
+
/* all DCDCs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
wm8350_reg_write(wm8350, volt_reg, val | mV);
return 0;
}
-static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
+static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
int volt_reg, dcdc = rdev_get_id(rdev);
- u16 val;
switch (dcdc) {
case WM8350_DCDC_1:
@@ -429,8 +430,7 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
}
/* all DCDCs have same mV bits */
- val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
- return wm8350_dcdc_val_to_mvolts(val) * 1000;
+ return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
}
static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
@@ -754,7 +754,7 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
}
static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV)
+ int max_uV, unsigned *selector)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
@@ -797,17 +797,18 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
return -EINVAL;
}
+ *selector = mV;
+
/* all LDOs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
wm8350_reg_write(wm8350, volt_reg, val | mV);
return 0;
}
-static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
+static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
int volt_reg, ldo = rdev_get_id(rdev);
- u16 val;
switch (ldo) {
case WM8350_LDO_1:
@@ -827,8 +828,7 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
}
/* all LDOs have same mV bits */
- val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
- return wm8350_ldo_val_to_mvolts(val) * 1000;
+ return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
}
static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
@@ -1225,7 +1225,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops wm8350_dcdc_ops = {
.set_voltage = wm8350_dcdc_set_voltage,
- .get_voltage = wm8350_dcdc_get_voltage,
+ .get_voltage_sel = wm8350_dcdc_get_voltage_sel,
.list_voltage = wm8350_dcdc_list_voltage,
.enable = wm8350_dcdc_enable,
.disable = wm8350_dcdc_disable,
@@ -1249,7 +1249,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
static struct regulator_ops wm8350_ldo_ops = {
.set_voltage = wm8350_ldo_set_voltage,
- .get_voltage = wm8350_ldo_get_voltage,
+ .get_voltage_sel = wm8350_ldo_get_voltage_sel,
.list_voltage = wm8350_ldo_list_voltage,
.enable = wm8350_ldo_enable,
.disable = wm8350_ldo_disable,
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 924c7eb29ee9..b42d01cef35a 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -67,7 +67,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
}
static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
u16 val;
@@ -93,6 +93,8 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
val += 0xf;
}
+ *selector = val;
+
return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
WM8400_LDO1_VSEL_MASK, val);
}
@@ -156,7 +158,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
}
static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *selector)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
u16 val;
@@ -171,6 +173,8 @@ static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
return -EINVAL;
BUG_ON(850000 + (25000 * val) < min_uV);
+ *selector = val;
+
return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
WM8400_DC1_VSEL_MASK, val);
}
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 03713bc66e4a..35b2958d5106 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -86,7 +86,7 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
return (selector * 100000) + 2400000;
}
-static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev)
+static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int val;
@@ -95,13 +95,11 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev)
if (val < 0)
return val;
- val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
-
- return wm8994_ldo1_list_voltage(rdev, val);
+ return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
}
static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *s)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int selector, v;
@@ -111,6 +109,7 @@ static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
if (v < 0 || v > max_uV)
return -EINVAL;
+ *s = selector;
selector <<= WM8994_LDO1_VSEL_SHIFT;
return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1,
@@ -124,20 +123,29 @@ static struct regulator_ops wm8994_ldo1_ops = {
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo1_list_voltage,
- .get_voltage = wm8994_ldo1_get_voltage,
+ .get_voltage_sel = wm8994_ldo1_get_voltage_sel,
.set_voltage = wm8994_ldo1_set_voltage,
};
static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
if (selector > WM8994_LDO2_MAX_SELECTOR)
return -EINVAL;
- return (selector * 100000) + 900000;
+ switch (ldo->wm8994->type) {
+ case WM8994:
+ return (selector * 100000) + 900000;
+ case WM8958:
+ return (selector * 100000) + 1000000;
+ default:
+ return -EINVAL;
+ }
}
-static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev)
+static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int val;
@@ -146,22 +154,31 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev)
if (val < 0)
return val;
- val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
-
- return wm8994_ldo2_list_voltage(rdev, val);
+ return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
}
static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV, unsigned *s)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int selector, v;
- selector = (min_uV - 900000) / 100000;
+ switch (ldo->wm8994->type) {
+ case WM8994:
+ selector = (min_uV - 900000) / 100000;
+ break;
+ case WM8958:
+ selector = (min_uV - 1000000) / 100000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
v = wm8994_ldo2_list_voltage(rdev, selector);
if (v < 0 || v > max_uV)
return -EINVAL;
+ *s = selector;
selector <<= WM8994_LDO2_VSEL_SHIFT;
return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
@@ -175,7 +192,7 @@ static struct regulator_ops wm8994_ldo2_ops = {
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo2_list_voltage,
- .get_voltage = wm8994_ldo2_get_voltage,
+ .get_voltage_sel = wm8994_ldo2_get_voltage_sel,
.set_voltage = wm8994_ldo2_set_voltage,
};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2883428d5ac8..4941cade319f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -463,6 +463,18 @@ config RTC_DRV_CMOS
This driver can also be built as a module. If so, the module
will be called rtc-cmos.
+config RTC_DRV_VRTC
+ tristate "Virtual RTC for Moorestown platforms"
+ depends on X86_MRST
+ default y if X86_MRST
+
+ help
+ Say "yes" here to get direct support for the real time clock
+ found on Moorestown platforms. The VRTC is a emulated RTC that
+ derives its clock source from a real RTC in the PMIC. The MC146818
+ style programming interface is mostly conserved, but any
+ updates are done via IPC calls to the system controller FW.
+
config RTC_DRV_DS1216
tristate "Dallas DS1216"
depends on SNI_RM
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 4c2832df4697..2afdaf3ff986 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
+obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index e6539cbabb35..9583cbcc6b79 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -16,6 +16,7 @@
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "rtc-core.h"
@@ -152,6 +153,18 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
spin_lock_init(&rtc->irq_task_lock);
init_waitqueue_head(&rtc->irq_queue);
+ /* Init timerqueue */
+ timerqueue_init_head(&rtc->timerqueue);
+ INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
+ /* Init aie timer */
+ rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);
+ /* Init uie timer */
+ rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);
+ /* Init pie timer */
+ hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ rtc->pie_timer.function = rtc_pie_update_irq;
+ rtc->pie_enabled = 0;
+
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
dev_set_name(&rtc->dev, "rtc%d", id);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index a0c816238aa9..90384b9f6b2c 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -14,15 +14,11 @@
#include <linux/rtc.h>
#include <linux/sched.h>
#include <linux/log2.h>
+#include <linux/workqueue.h>
-int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
+static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
-
- err = mutex_lock_interruptible(&rtc->ops_lock);
- if (err)
- return err;
-
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->read_time)
@@ -31,7 +27,18 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm);
}
+ return err;
+}
+
+int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
+{
+ int err;
+ err = mutex_lock_interruptible(&rtc->ops_lock);
+ if (err)
+ return err;
+
+ err = __rtc_read_time(rtc, tm);
mutex_unlock(&rtc->ops_lock);
return err;
}
@@ -106,188 +113,54 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
-static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
-
- if (rtc->ops == NULL)
- err = -ENODEV;
- else if (!rtc->ops->read_alarm)
- err = -EINVAL;
- else {
- memset(alarm, 0, sizeof(struct rtc_wkalrm));
- err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
- }
-
+ alarm->enabled = rtc->aie_timer.enabled;
+ if (alarm->enabled)
+ alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
mutex_unlock(&rtc->ops_lock);
- return err;
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(rtc_read_alarm);
-int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
+ struct rtc_time tm;
+ long now, scheduled;
int err;
- struct rtc_time before, now;
- int first_time = 1;
- unsigned long t_now, t_alm;
- enum { none, day, month, year } missing = none;
- unsigned days;
-
- /* The lower level RTC driver may return -1 in some fields,
- * creating invalid alarm->time values, for reasons like:
- *
- * - The hardware may not be capable of filling them in;
- * many alarms match only on time-of-day fields, not
- * day/month/year calendar data.
- *
- * - Some hardware uses illegal values as "wildcard" match
- * values, which non-Linux firmware (like a BIOS) may try
- * to set up as e.g. "alarm 15 minutes after each hour".
- * Linux uses only oneshot alarms.
- *
- * When we see that here, we deal with it by using values from
- * a current RTC timestamp for any missing (-1) values. The
- * RTC driver prevents "periodic alarm" modes.
- *
- * But this can be racey, because some fields of the RTC timestamp
- * may have wrapped in the interval since we read the RTC alarm,
- * which would lead to us inserting inconsistent values in place
- * of the -1 fields.
- *
- * Reading the alarm and timestamp in the reverse sequence
- * would have the same race condition, and not solve the issue.
- *
- * So, we must first read the RTC timestamp,
- * then read the RTC alarm value,
- * and then read a second RTC timestamp.
- *
- * If any fields of the second timestamp have changed
- * when compared with the first timestamp, then we know
- * our timestamp may be inconsistent with that used by
- * the low-level rtc_read_alarm_internal() function.
- *
- * So, when the two timestamps disagree, we just loop and do
- * the process again to get a fully consistent set of values.
- *
- * This could all instead be done in the lower level driver,
- * but since more than one lower level RTC implementation needs it,
- * then it's probably best best to do it here instead of there..
- */
- /* Get the "before" timestamp */
- err = rtc_read_time(rtc, &before);
- if (err < 0)
+ err = rtc_valid_tm(&alarm->time);
+ if (err)
return err;
- do {
- if (!first_time)
- memcpy(&before, &now, sizeof(struct rtc_time));
- first_time = 0;
-
- /* get the RTC alarm values, which may be incomplete */
- err = rtc_read_alarm_internal(rtc, alarm);
- if (err)
- return err;
- if (!alarm->enabled)
- return 0;
-
- /* full-function RTCs won't have such missing fields */
- if (rtc_valid_tm(&alarm->time) == 0)
- return 0;
-
- /* get the "after" timestamp, to detect wrapped fields */
- err = rtc_read_time(rtc, &now);
- if (err < 0)
- return err;
-
- /* note that tm_sec is a "don't care" value here: */
- } while ( before.tm_min != now.tm_min
- || before.tm_hour != now.tm_hour
- || before.tm_mon != now.tm_mon
- || before.tm_year != now.tm_year);
-
- /* Fill in the missing alarm fields using the timestamp; we
- * know there's at least one since alarm->time is invalid.
- */
- if (alarm->time.tm_sec == -1)
- alarm->time.tm_sec = now.tm_sec;
- if (alarm->time.tm_min == -1)
- alarm->time.tm_min = now.tm_min;
- if (alarm->time.tm_hour == -1)
- alarm->time.tm_hour = now.tm_hour;
-
- /* For simplicity, only support date rollover for now */
- if (alarm->time.tm_mday == -1) {
- alarm->time.tm_mday = now.tm_mday;
- missing = day;
- }
- if (alarm->time.tm_mon == -1) {
- alarm->time.tm_mon = now.tm_mon;
- if (missing == none)
- missing = month;
- }
- if (alarm->time.tm_year == -1) {
- alarm->time.tm_year = now.tm_year;
- if (missing == none)
- missing = year;
- }
-
- /* with luck, no rollover is needed */
- rtc_tm_to_time(&now, &t_now);
- rtc_tm_to_time(&alarm->time, &t_alm);
- if (t_now < t_alm)
- goto done;
-
- switch (missing) {
+ rtc_tm_to_time(&alarm->time, &scheduled);
- /* 24 hour rollover ... if it's now 10am Monday, an alarm that
- * that will trigger at 5am will do so at 5am Tuesday, which
- * could also be in the next month or year. This is a common
- * case, especially for PCs.
- */
- case day:
- dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
- t_alm += 24 * 60 * 60;
- rtc_time_to_tm(t_alm, &alarm->time);
- break;
-
- /* Month rollover ... if it's the 31th, an alarm on the 3rd will
- * be next month. An alarm matching on the 30th, 29th, or 28th
- * may end up in the month after that! Many newer PCs support
- * this type of alarm.
+ /* Make sure we're not setting alarms in the past */
+ err = __rtc_read_time(rtc, &tm);
+ rtc_tm_to_time(&tm, &now);
+ if (scheduled <= now)
+ return -ETIME;
+ /*
+ * XXX - We just checked to make sure the alarm time is not
+ * in the past, but there is still a race window where if
+ * the is alarm set for the next second and the second ticks
+ * over right here, before we set the alarm.
*/
- case month:
- dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
- do {
- if (alarm->time.tm_mon < 11)
- alarm->time.tm_mon++;
- else {
- alarm->time.tm_mon = 0;
- alarm->time.tm_year++;
- }
- days = rtc_month_days(alarm->time.tm_mon,
- alarm->time.tm_year);
- } while (days < alarm->time.tm_mday);
- break;
-
- /* Year rollover ... easy except for leap years! */
- case year:
- dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
- do {
- alarm->time.tm_year++;
- } while (rtc_valid_tm(&alarm->time) != 0);
- break;
-
- default:
- dev_warn(&rtc->dev, "alarm rollover not handled\n");
- }
-done:
- return 0;
+ if (!rtc->ops)
+ err = -ENODEV;
+ else if (!rtc->ops->set_alarm)
+ err = -EINVAL;
+ else
+ err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
+
+ return err;
}
-EXPORT_SYMBOL_GPL(rtc_read_alarm);
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
@@ -300,16 +173,18 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
-
- if (!rtc->ops)
- err = -ENODEV;
- else if (!rtc->ops->set_alarm)
- err = -EINVAL;
- else
- err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
-
+ if (rtc->aie_timer.enabled) {
+ rtc_timer_remove(rtc, &rtc->aie_timer);
+ rtc->aie_timer.enabled = 0;
+ }
+ rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
+ rtc->aie_timer.period = ktime_set(0, 0);
+ if (alarm->enabled) {
+ rtc->aie_timer.enabled = 1;
+ rtc_timer_enqueue(rtc, &rtc->aie_timer);
+ }
mutex_unlock(&rtc->ops_lock);
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(rtc_set_alarm);
@@ -319,6 +194,16 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
if (err)
return err;
+ if (rtc->aie_timer.enabled != enabled) {
+ if (enabled) {
+ rtc->aie_timer.enabled = 1;
+ rtc_timer_enqueue(rtc, &rtc->aie_timer);
+ } else {
+ rtc_timer_remove(rtc, &rtc->aie_timer);
+ rtc->aie_timer.enabled = 0;
+ }
+ }
+
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->alarm_irq_enable)
@@ -337,52 +222,53 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
if (err)
return err;
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
- if (enabled == 0 && rtc->uie_irq_active) {
- mutex_unlock(&rtc->ops_lock);
- return rtc_dev_update_irq_enable_emul(rtc, enabled);
+ /* make sure we're changing state */
+ if (rtc->uie_rtctimer.enabled == enabled)
+ goto out;
+
+ if (enabled) {
+ struct rtc_time tm;
+ ktime_t now, onesec;
+
+ __rtc_read_time(rtc, &tm);
+ onesec = ktime_set(1, 0);
+ now = rtc_tm_to_ktime(tm);
+ rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
+ rtc->uie_rtctimer.period = ktime_set(1, 0);
+ rtc->uie_rtctimer.enabled = 1;
+ rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
+ } else {
+ rtc_timer_remove(rtc, &rtc->uie_rtctimer);
+ rtc->uie_rtctimer.enabled = 0;
}
-#endif
-
- if (!rtc->ops)
- err = -ENODEV;
- else if (!rtc->ops->update_irq_enable)
- err = -EINVAL;
- else
- err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled);
+out:
mutex_unlock(&rtc->ops_lock);
-
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
- /*
- * Enable emulation if the driver did not provide
- * the update_irq_enable function pointer or if returned
- * -EINVAL to signal that it has been configured without
- * interrupts or that are not available at the moment.
- */
- if (err == -EINVAL)
- err = rtc_dev_update_irq_enable_emul(rtc, enabled);
-#endif
return err;
+
}
EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
+
/**
- * rtc_update_irq - report RTC periodic, alarm, and/or update irqs
- * @rtc: the rtc device
- * @num: how many irqs are being reported (usually one)
- * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
- * Context: any
+ * rtc_handle_legacy_irq - AIE, UIE and PIE event hook
+ * @rtc: pointer to the rtc device
+ *
+ * This function is called when an AIE, UIE or PIE mode interrupt
+ * has occured (or been emulated).
+ *
+ * Triggers the registered irq_task function callback.
*/
-void rtc_update_irq(struct rtc_device *rtc,
- unsigned long num, unsigned long events)
+static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
{
unsigned long flags;
+ /* mark one irq of the appropriate mode */
spin_lock_irqsave(&rtc->irq_lock, flags);
- rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
+ rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
spin_unlock_irqrestore(&rtc->irq_lock, flags);
+ /* call the task func */
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task)
rtc->irq_task->func(rtc->irq_task->private_data);
@@ -391,6 +277,69 @@ void rtc_update_irq(struct rtc_device *rtc,
wake_up_interruptible(&rtc->irq_queue);
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
}
+
+
+/**
+ * rtc_aie_update_irq - AIE mode rtctimer hook
+ * @private: pointer to the rtc_device
+ *
+ * This functions is called when the aie_timer expires.
+ */
+void rtc_aie_update_irq(void *private)
+{
+ struct rtc_device *rtc = (struct rtc_device *)private;
+ rtc_handle_legacy_irq(rtc, 1, RTC_AF);
+}
+
+
+/**
+ * rtc_uie_update_irq - UIE mode rtctimer hook
+ * @private: pointer to the rtc_device
+ *
+ * This functions is called when the uie_timer expires.
+ */
+void rtc_uie_update_irq(void *private)
+{
+ struct rtc_device *rtc = (struct rtc_device *)private;
+ rtc_handle_legacy_irq(rtc, 1, RTC_UF);
+}
+
+
+/**
+ * rtc_pie_update_irq - PIE mode hrtimer hook
+ * @timer: pointer to the pie mode hrtimer
+ *
+ * This function is used to emulate PIE mode interrupts
+ * using an hrtimer. This function is called when the periodic
+ * hrtimer expires.
+ */
+enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
+{
+ struct rtc_device *rtc;
+ ktime_t period;
+ int count;
+ rtc = container_of(timer, struct rtc_device, pie_timer);
+
+ period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
+ count = hrtimer_forward_now(timer, period);
+
+ rtc_handle_legacy_irq(rtc, count, RTC_PF);
+
+ return HRTIMER_RESTART;
+}
+
+/**
+ * rtc_update_irq - Triggered when a RTC interrupt occurs.
+ * @rtc: the rtc device
+ * @num: how many irqs are being reported (usually one)
+ * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
+ * Context: any
+ */
+void rtc_update_irq(struct rtc_device *rtc,
+ unsigned long num, unsigned long events)
+{
+ schedule_work(&rtc->irqwork);
+}
EXPORT_SYMBOL_GPL(rtc_update_irq);
static int __rtc_match(struct device *dev, void *data)
@@ -477,18 +426,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
int err = 0;
unsigned long flags;
- if (rtc->ops->irq_set_state == NULL)
- return -ENXIO;
-
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
- spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
- if (err == 0)
- err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
+ if (enabled) {
+ ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
+ hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
+ } else {
+ hrtimer_cancel(&rtc->pie_timer);
+ }
+ rtc->pie_enabled = enabled;
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
return err;
}
@@ -509,21 +460,194 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
int err = 0;
unsigned long flags;
- if (rtc->ops->irq_set_freq == NULL)
- return -ENXIO;
-
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
- spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
-
if (err == 0) {
- err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
- if (err == 0)
- rtc->irq_freq = freq;
+ rtc->irq_freq = freq;
+ if (rtc->pie_enabled) {
+ ktime_t period;
+ hrtimer_cancel(&rtc->pie_timer);
+ period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
+ hrtimer_start(&rtc->pie_timer, period,
+ HRTIMER_MODE_REL);
+ }
}
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
+
+/**
+ * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
+ * @rtc rtc device
+ * @timer timer being added.
+ *
+ * Enqueues a timer onto the rtc devices timerqueue and sets
+ * the next alarm event appropriately.
+ *
+ * Must hold ops_lock for proper serialization of timerqueue
+ */
+void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
+{
+ timerqueue_add(&rtc->timerqueue, &timer->node);
+ if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
+ struct rtc_wkalrm alarm;
+ int err;
+ alarm.time = rtc_ktime_to_tm(timer->node.expires);
+ alarm.enabled = 1;
+ err = __rtc_set_alarm(rtc, &alarm);
+ if (err == -ETIME)
+ schedule_work(&rtc->irqwork);
+ }
+}
+
+/**
+ * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
+ * @rtc rtc device
+ * @timer timer being removed.
+ *
+ * Removes a timer onto the rtc devices timerqueue and sets
+ * the next alarm event appropriately.
+ *
+ * Must hold ops_lock for proper serialization of timerqueue
+ */
+void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
+{
+ struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
+ timerqueue_del(&rtc->timerqueue, &timer->node);
+
+ if (next == &timer->node) {
+ struct rtc_wkalrm alarm;
+ int err;
+ next = timerqueue_getnext(&rtc->timerqueue);
+ if (!next)
+ return;
+ alarm.time = rtc_ktime_to_tm(next->expires);
+ alarm.enabled = 1;
+ err = __rtc_set_alarm(rtc, &alarm);
+ if (err == -ETIME)
+ schedule_work(&rtc->irqwork);
+ }
+}
+
+/**
+ * rtc_timer_do_work - Expires rtc timers
+ * @rtc rtc device
+ * @timer timer being removed.
+ *
+ * Expires rtc timers. Reprograms next alarm event if needed.
+ * Called via worktask.
+ *
+ * Serializes access to timerqueue via ops_lock mutex
+ */
+void rtc_timer_do_work(struct work_struct *work)
+{
+ struct rtc_timer *timer;
+ struct timerqueue_node *next;
+ ktime_t now;
+ struct rtc_time tm;
+
+ struct rtc_device *rtc =
+ container_of(work, struct rtc_device, irqwork);
+
+ mutex_lock(&rtc->ops_lock);
+again:
+ __rtc_read_time(rtc, &tm);
+ now = rtc_tm_to_ktime(tm);
+ while ((next = timerqueue_getnext(&rtc->timerqueue))) {
+ if (next->expires.tv64 > now.tv64)
+ break;
+
+ /* expire timer */
+ timer = container_of(next, struct rtc_timer, node);
+ timerqueue_del(&rtc->timerqueue, &timer->node);
+ timer->enabled = 0;
+ if (timer->task.func)
+ timer->task.func(timer->task.private_data);
+
+ /* Re-add/fwd periodic timers */
+ if (ktime_to_ns(timer->period)) {
+ timer->node.expires = ktime_add(timer->node.expires,
+ timer->period);
+ timer->enabled = 1;
+ timerqueue_add(&rtc->timerqueue, &timer->node);
+ }
+ }
+
+ /* Set next alarm */
+ if (next) {
+ struct rtc_wkalrm alarm;
+ int err;
+ alarm.time = rtc_ktime_to_tm(next->expires);
+ alarm.enabled = 1;
+ err = __rtc_set_alarm(rtc, &alarm);
+ if (err == -ETIME)
+ goto again;
+ }
+
+ mutex_unlock(&rtc->ops_lock);
+}
+
+
+/* rtc_timer_init - Initializes an rtc_timer
+ * @timer: timer to be intiialized
+ * @f: function pointer to be called when timer fires
+ * @data: private data passed to function pointer
+ *
+ * Kernel interface to initializing an rtc_timer.
+ */
+void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
+{
+ timerqueue_init(&timer->node);
+ timer->enabled = 0;
+ timer->task.func = f;
+ timer->task.private_data = data;
+}
+
+/* rtc_timer_start - Sets an rtc_timer to fire in the future
+ * @ rtc: rtc device to be used
+ * @ timer: timer being set
+ * @ expires: time at which to expire the timer
+ * @ period: period that the timer will recur
+ *
+ * Kernel interface to set an rtc_timer
+ */
+int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
+ ktime_t expires, ktime_t period)
+{
+ int ret = 0;
+ mutex_lock(&rtc->ops_lock);
+ if (timer->enabled)
+ rtc_timer_remove(rtc, timer);
+
+ timer->node.expires = expires;
+ timer->period = period;
+
+ timer->enabled = 1;
+ rtc_timer_enqueue(rtc, timer);
+
+ mutex_unlock(&rtc->ops_lock);
+ return ret;
+}
+
+/* rtc_timer_cancel - Stops an rtc_timer
+ * @ rtc: rtc device to be used
+ * @ timer: timer being set
+ *
+ * Kernel interface to cancel an rtc_timer
+ */
+int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
+{
+ int ret = 0;
+ mutex_lock(&rtc->ops_lock);
+ if (timer->enabled)
+ rtc_timer_remove(rtc, timer);
+ timer->enabled = 0;
+ mutex_unlock(&rtc->ops_lock);
+ return ret;
+}
+
+
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 5856167a0c90..c7ff8df347e7 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -36,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
+#include <linux/pm.h>
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <asm-generic/rtc.h>
@@ -687,7 +688,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
#if defined(CONFIG_ATARI)
address_space = 64;
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
- || defined(__sparc__) || defined(__mips__)
+ || defined(__sparc__) || defined(__mips__) \
+ || defined(__powerpc__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -850,7 +852,7 @@ static void __exit cmos_do_remove(struct device *dev)
#ifdef CONFIG_PM
-static int cmos_suspend(struct device *dev, pm_message_t mesg)
+static int cmos_suspend(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
@@ -898,7 +900,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
*/
static inline int cmos_poweroff(struct device *dev)
{
- return cmos_suspend(dev, PMSG_HIBERNATE);
+ return cmos_suspend(dev);
}
static int cmos_resume(struct device *dev)
@@ -945,9 +947,9 @@ static int cmos_resume(struct device *dev)
return 0;
}
+static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
+
#else
-#define cmos_suspend NULL
-#define cmos_resume NULL
static inline int cmos_poweroff(struct device *dev)
{
@@ -1077,7 +1079,7 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
{
- return cmos_suspend(&pnp->dev, mesg);
+ return cmos_suspend(&pnp->dev);
}
static int cmos_pnp_resume(struct pnp_dev *pnp)
@@ -1157,8 +1159,9 @@ static struct platform_driver cmos_platform_driver = {
.shutdown = cmos_platform_shutdown,
.driver = {
.name = (char *) driver_name,
- .suspend = cmos_suspend,
- .resume = cmos_resume,
+#ifdef CONFIG_PM
+ .pm = &cmos_pm_ops,
+#endif
}
};
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 62227cd52410..212b16edafc0 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -46,105 +46,6 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
return err;
}
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
-/*
- * Routine to poll RTC seconds field for change as often as possible,
- * after first RTC_UIE use timer to reduce polling
- */
-static void rtc_uie_task(struct work_struct *work)
-{
- struct rtc_device *rtc =
- container_of(work, struct rtc_device, uie_task);
- struct rtc_time tm;
- int num = 0;
- int err;
-
- err = rtc_read_time(rtc, &tm);
-
- spin_lock_irq(&rtc->irq_lock);
- if (rtc->stop_uie_polling || err) {
- rtc->uie_task_active = 0;
- } else if (rtc->oldsecs != tm.tm_sec) {
- num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
- rtc->oldsecs = tm.tm_sec;
- rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
- rtc->uie_timer_active = 1;
- rtc->uie_task_active = 0;
- add_timer(&rtc->uie_timer);
- } else if (schedule_work(&rtc->uie_task) == 0) {
- rtc->uie_task_active = 0;
- }
- spin_unlock_irq(&rtc->irq_lock);
- if (num)
- rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
-}
-static void rtc_uie_timer(unsigned long data)
-{
- struct rtc_device *rtc = (struct rtc_device *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc->irq_lock, flags);
- rtc->uie_timer_active = 0;
- rtc->uie_task_active = 1;
- if ((schedule_work(&rtc->uie_task) == 0))
- rtc->uie_task_active = 0;
- spin_unlock_irqrestore(&rtc->irq_lock, flags);
-}
-
-static int clear_uie(struct rtc_device *rtc)
-{
- spin_lock_irq(&rtc->irq_lock);
- if (rtc->uie_irq_active) {
- rtc->stop_uie_polling = 1;
- if (rtc->uie_timer_active) {
- spin_unlock_irq(&rtc->irq_lock);
- del_timer_sync(&rtc->uie_timer);
- spin_lock_irq(&rtc->irq_lock);
- rtc->uie_timer_active = 0;
- }
- if (rtc->uie_task_active) {
- spin_unlock_irq(&rtc->irq_lock);
- flush_scheduled_work();
- spin_lock_irq(&rtc->irq_lock);
- }
- rtc->uie_irq_active = 0;
- }
- spin_unlock_irq(&rtc->irq_lock);
- return 0;
-}
-
-static int set_uie(struct rtc_device *rtc)
-{
- struct rtc_time tm;
- int err;
-
- err = rtc_read_time(rtc, &tm);
- if (err)
- return err;
- spin_lock_irq(&rtc->irq_lock);
- if (!rtc->uie_irq_active) {
- rtc->uie_irq_active = 1;
- rtc->stop_uie_polling = 0;
- rtc->oldsecs = tm.tm_sec;
- rtc->uie_task_active = 1;
- if (schedule_work(&rtc->uie_task) == 0)
- rtc->uie_task_active = 0;
- }
- rtc->irq_data = 0;
- spin_unlock_irq(&rtc->irq_lock);
- return 0;
-}
-
-int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
-{
- if (enabled)
- return set_uie(rtc);
- else
- return clear_uie(rtc);
-}
-EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
-
-#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -493,11 +394,6 @@ void rtc_dev_prepare(struct rtc_device *rtc)
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
- INIT_WORK(&rtc->uie_task, rtc_uie_task);
- setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
-#endif
-
cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
}
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 359d1e04626c..f0d638922644 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_SH_SECUREEDGE5410
#include <asm/rtc.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
#define RTC_RESET 0x1000
#define RTC_IODATA 0x0800
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 48da85e97ca4..077af1d7b9e4 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -813,7 +813,7 @@ static int __devexit ds1305_remove(struct spi_device *spi)
if (spi->irq) {
set_bit(FLAG_EXITING, &ds1305->flags);
free_irq(spi->irq, ds1305);
- flush_scheduled_work();
+ cancel_work_sync(&ds1305->work);
}
rtc_device_unregister(ds1305->rtc);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index d827ce570a8c..0d559b6416dd 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -106,9 +106,9 @@ struct ds1307 {
struct i2c_client *client;
struct rtc_device *rtc;
struct work_struct work;
- s32 (*read_block_data)(struct i2c_client *client, u8 command,
+ s32 (*read_block_data)(const struct i2c_client *client, u8 command,
u8 length, u8 *values);
- s32 (*write_block_data)(struct i2c_client *client, u8 command,
+ s32 (*write_block_data)(const struct i2c_client *client, u8 command,
u8 length, const u8 *values);
};
@@ -158,8 +158,8 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id);
#define BLOCK_DATA_MAX_TRIES 10
-static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
- u8 length, u8 *values)
+static s32 ds1307_read_block_data_once(const struct i2c_client *client,
+ u8 command, u8 length, u8 *values)
{
s32 i, data;
@@ -172,7 +172,7 @@ static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
return i;
}
-static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
+static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
u8 length, u8 *values)
{
u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
@@ -198,7 +198,7 @@ static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
return length;
}
-static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
+static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
u8 currvalues[I2C_SMBUS_BLOCK_MAX];
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 1f0007fd4431..47fb6357c346 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -417,7 +417,7 @@ static int __devexit ds1374_remove(struct i2c_client *client)
mutex_unlock(&ds1374->mutex);
free_irq(client->irq, client);
- flush_scheduled_work();
+ cancel_work_sync(&ds1374->work);
}
rtc_device_unregister(ds1374->rtc);
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 57063552d3b7..23a9ee19764c 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -463,7 +463,7 @@ static int __devexit ds3232_remove(struct i2c_client *client)
mutex_unlock(&ds3232->mutex);
free_irq(client->irq, client);
- flush_scheduled_work();
+ cancel_work_sync(&ds3232->work);
}
rtc_device_unregister(ds3232->rtc);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 773851f338b8..075f1708deae 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -117,4 +117,32 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
}
EXPORT_SYMBOL(rtc_tm_to_time);
+/*
+ * Convert rtc_time to ktime
+ */
+ktime_t rtc_tm_to_ktime(struct rtc_time tm)
+{
+ time_t time;
+ rtc_tm_to_time(&tm, &time);
+ return ktime_set(time, 0);
+}
+EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
+
+/*
+ * Convert ktime to rtc_time
+ */
+struct rtc_time rtc_ktime_to_tm(ktime_t kt)
+{
+ struct timespec ts;
+ struct rtc_time ret;
+
+ ts = ktime_to_timespec(kt);
+ /* Round up any ns */
+ if (ts.tv_nsec)
+ ts.tv_sec++;
+ rtc_time_to_tm(ts.tv_sec, &ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 657403ebd54a..0ec3f588a255 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -139,12 +139,13 @@ static int __devinit max6902_probe(struct spi_device *spi)
if (IS_ERR(rtc))
return PTR_ERR(rtc);
+ dev_set_drvdata(&spi->dev, rtc);
return 0;
}
static int __devexit max6902_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = platform_get_drvdata(spi);
+ struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
rtc_device_unregister(rtc);
return 0;
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index f22dee35f330..3f7bc6b9fefa 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
+#include <linux/delay.h>
#define MAX8998_RTC_SEC 0x00
#define MAX8998_RTC_MIN 0x01
@@ -73,6 +74,7 @@ struct max8998_rtc_info {
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
int irq;
+ bool lp3974_bug_workaround;
};
static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
@@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max8998_rtc_info *info = dev_get_drvdata(dev);
u8 data[8];
+ int ret;
max8998_tm_to_data(tm, data);
- return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+ ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+ int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+ int ret;
+ u8 alarm0_conf = 0x77;
+
+ /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
+ if (info->lp3974_bug_workaround)
+ alarm0_conf = 0x57;
+
+ ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
return ret;
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
if (alrm->enabled)
- return max8998_rtc_start_alarm(info);
+ ret = max8998_rtc_start_alarm(info);
- return 0;
+ return ret;
}
static int max8998_rtc_alarm_irq_enable(struct device *dev,
@@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
static int __devinit max8998_rtc_probe(struct platform_device *pdev)
{
struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+ struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
struct max8998_rtc_info *info;
int ret;
@@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
"rtc-alarm0", info);
+
if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->irq, ret);
+ dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
+ if (pdata->rtc_delay) {
+ info->lp3974_bug_workaround = true;
+ dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
+ " RTC updates will be extremely slow.\n");
+ }
+
return 0;
out_rtc:
@@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_rtc_id[] = {
+ { "max8998-rtc", TYPE_MAX8998 },
+ { "lp3974-rtc", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_rtc_driver = {
.driver = {
.name = "max8998-rtc",
@@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
},
.probe = max8998_rtc_probe,
.remove = __devexit_p(max8998_rtc_remove),
+ .id_table = max8998_rtc_id,
};
static int __init max8998_rtc_init(void)
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
new file mode 100644
index 000000000000..bcd0cf63eb16
--- /dev/null
+++ b/drivers/rtc/rtc-mrst.c
@@ -0,0 +1,582 @@
+/*
+ * rtc-mrst.c: Driver for Moorestown virtual RTC
+ *
+ * (C) Copyright 2009 Intel Corporation
+ * Author: Jacob Pan (jacob.jun.pan@intel.com)
+ * Feng Tang (feng.tang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * Note:
+ * VRTC is emulated by system controller firmware, the real HW
+ * RTC is located in the PMIC device. SCU FW shadows PMIC RTC
+ * in a memory mapped IO space that is visible to the host IA
+ * processor.
+ *
+ * This driver is based upon drivers/rtc/rtc-cmos.c
+ */
+
+/*
+ * Note:
+ * * vRTC only supports binary mode and 24H mode
+ * * vRTC only support PIE and AIE, no UIE, and its PIE only happens
+ * at 23:59:59pm everyday, no support for adjustable frequency
+ * * Alarm function is also limited to hr/min/sec.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sfi.h>
+
+#include <asm-generic/rtc.h>
+#include <asm/intel_scu_ipc.h>
+#include <asm/mrst.h>
+#include <asm/mrst-vrtc.h>
+
+struct mrst_rtc {
+ struct rtc_device *rtc;
+ struct device *dev;
+ int irq;
+ struct resource *iomem;
+
+ u8 enabled_wake;
+ u8 suspend_ctrl;
+};
+
+static const char driver_name[] = "rtc_mrst";
+
+#define RTC_IRQMASK (RTC_PF | RTC_AF)
+
+static inline int is_intr(u8 rtc_intr)
+{
+ if (!(rtc_intr & RTC_IRQF))
+ return 0;
+ return rtc_intr & RTC_IRQMASK;
+}
+
+/*
+ * rtc_time's year contains the increment over 1900, but vRTC's YEAR
+ * register can't be programmed to value larger than 0x64, so vRTC
+ * driver chose to use 1960 (1970 is UNIX time start point) as the base,
+ * and does the translation at read/write time.
+ *
+ * Why not just use 1970 as the offset? it's because using 1960 will
+ * make it consistent in leap year setting for both vrtc and low-level
+ * physical rtc devices.
+ */
+static int mrst_read_time(struct device *dev, struct rtc_time *time)
+{
+ unsigned long flags;
+
+ if (rtc_is_updating())
+ mdelay(20);
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ time->tm_sec = vrtc_cmos_read(RTC_SECONDS);
+ time->tm_min = vrtc_cmos_read(RTC_MINUTES);
+ time->tm_hour = vrtc_cmos_read(RTC_HOURS);
+ time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH);
+ time->tm_mon = vrtc_cmos_read(RTC_MONTH);
+ time->tm_year = vrtc_cmos_read(RTC_YEAR);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ /* Adjust for the 1960/1900 */
+ time->tm_year += 60;
+ time->tm_mon--;
+ return RTC_24H;
+}
+
+static int mrst_set_time(struct device *dev, struct rtc_time *time)
+{
+ int ret;
+ unsigned long flags;
+ unsigned char mon, day, hrs, min, sec;
+ unsigned int yrs;
+
+ yrs = time->tm_year;
+ mon = time->tm_mon + 1; /* tm_mon starts at zero */
+ day = time->tm_mday;
+ hrs = time->tm_hour;
+ min = time->tm_min;
+ sec = time->tm_sec;
+
+ if (yrs < 70 || yrs > 138)
+ return -EINVAL;
+ yrs -= 60;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ vrtc_cmos_write(yrs, RTC_YEAR);
+ vrtc_cmos_write(mon, RTC_MONTH);
+ vrtc_cmos_write(day, RTC_DAY_OF_MONTH);
+ vrtc_cmos_write(hrs, RTC_HOURS);
+ vrtc_cmos_write(min, RTC_MINUTES);
+ vrtc_cmos_write(sec, RTC_SECONDS);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
+ return ret;
+}
+
+static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char rtc_control;
+
+ if (mrst->irq <= 0)
+ return -EIO;
+
+ /* Basic alarms only support hour, minute, and seconds fields.
+ * Some also support day and month, for alarms up to a year in
+ * the future.
+ */
+ t->time.tm_mday = -1;
+ t->time.tm_mon = -1;
+ t->time.tm_year = -1;
+
+ /* vRTC only supports binary mode */
+ spin_lock_irq(&rtc_lock);
+ t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM);
+ t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM);
+ t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM);
+
+ rtc_control = vrtc_cmos_read(RTC_CONTROL);
+ spin_unlock_irq(&rtc_lock);
+
+ t->enabled = !!(rtc_control & RTC_AIE);
+ t->pending = 0;
+
+ return 0;
+}
+
+static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control)
+{
+ unsigned char rtc_intr;
+
+ /*
+ * NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
+ * allegedly some older rtcs need that to handle irqs properly
+ */
+ rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS);
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
+ rtc_update_irq(mrst->rtc, 1, rtc_intr);
+}
+
+static void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask)
+{
+ unsigned char rtc_control;
+
+ /*
+ * Flush any pending IRQ status, notably for update irqs,
+ * before we enable new IRQs
+ */
+ rtc_control = vrtc_cmos_read(RTC_CONTROL);
+ mrst_checkintr(mrst, rtc_control);
+
+ rtc_control |= mask;
+ vrtc_cmos_write(rtc_control, RTC_CONTROL);
+
+ mrst_checkintr(mrst, rtc_control);
+}
+
+static void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask)
+{
+ unsigned char rtc_control;
+
+ rtc_control = vrtc_cmos_read(RTC_CONTROL);
+ rtc_control &= ~mask;
+ vrtc_cmos_write(rtc_control, RTC_CONTROL);
+ mrst_checkintr(mrst, rtc_control);
+}
+
+static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char hrs, min, sec;
+ int ret = 0;
+
+ if (!mrst->irq)
+ return -EIO;
+
+ hrs = t->time.tm_hour;
+ min = t->time.tm_min;
+ sec = t->time.tm_sec;
+
+ spin_lock_irq(&rtc_lock);
+ /* Next rtc irq must not be from previous alarm setting */
+ mrst_irq_disable(mrst, RTC_AIE);
+
+ /* Update alarm */
+ vrtc_cmos_write(hrs, RTC_HOURS_ALARM);
+ vrtc_cmos_write(min, RTC_MINUTES_ALARM);
+ vrtc_cmos_write(sec, RTC_SECONDS_ALARM);
+
+ spin_unlock_irq(&rtc_lock);
+
+ ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
+ if (ret)
+ return ret;
+
+ spin_lock_irq(&rtc_lock);
+ if (t->enabled)
+ mrst_irq_enable(mrst, RTC_AIE);
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+}
+
+static int mrst_irq_set_state(struct device *dev, int enabled)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ if (!mrst->irq)
+ return -ENXIO;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ if (enabled)
+ mrst_irq_enable(mrst, RTC_PIE);
+ else
+ mrst_irq_disable(mrst, RTC_PIE);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+}
+
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+
+/* Currently, the vRTC doesn't support UIE ON/OFF */
+static int
+mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ if (!mrst->irq)
+ return -EINVAL;
+ break;
+ default:
+ /* PIE ON/OFF is handled by mrst_irq_set_state() */
+ return -ENOIOCTLCMD;
+ }
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ mrst_irq_disable(mrst, RTC_AIE);
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ mrst_irq_enable(mrst, RTC_AIE);
+ break;
+ }
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+}
+
+#else
+#define mrst_rtc_ioctl NULL
+#endif
+
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+
+static int mrst_procfs(struct device *dev, struct seq_file *seq)
+{
+ unsigned char rtc_control, valid;
+
+ spin_lock_irq(&rtc_lock);
+ rtc_control = vrtc_cmos_read(RTC_CONTROL);
+ valid = vrtc_cmos_read(RTC_VALID);
+ spin_unlock_irq(&rtc_lock);
+
+ return seq_printf(seq,
+ "periodic_IRQ\t: %s\n"
+ "alarm\t\t: %s\n"
+ "BCD\t\t: no\n"
+ "periodic_freq\t: daily (not adjustable)\n",
+ (rtc_control & RTC_PIE) ? "on" : "off",
+ (rtc_control & RTC_AIE) ? "on" : "off");
+}
+
+#else
+#define mrst_procfs NULL
+#endif
+
+static const struct rtc_class_ops mrst_rtc_ops = {
+ .ioctl = mrst_rtc_ioctl,
+ .read_time = mrst_read_time,
+ .set_time = mrst_set_time,
+ .read_alarm = mrst_read_alarm,
+ .set_alarm = mrst_set_alarm,
+ .proc = mrst_procfs,
+ .irq_set_state = mrst_irq_set_state,
+};
+
+static struct mrst_rtc mrst_rtc;
+
+/*
+ * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in
+ * Reg B, so no need for this driver to clear it
+ */
+static irqreturn_t mrst_rtc_irq(int irq, void *p)
+{
+ u8 irqstat;
+
+ spin_lock(&rtc_lock);
+ /* This read will clear all IRQ flags inside Reg C */
+ irqstat = vrtc_cmos_read(RTC_INTR_FLAGS);
+ spin_unlock(&rtc_lock);
+
+ irqstat &= RTC_IRQMASK | RTC_IRQF;
+ if (is_intr(irqstat)) {
+ rtc_update_irq(p, 1, irqstat);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int __init
+vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
+{
+ int retval = 0;
+ unsigned char rtc_control;
+
+ /* There can be only one ... */
+ if (mrst_rtc.dev)
+ return -EBUSY;
+
+ if (!iomem)
+ return -ENODEV;
+
+ iomem = request_mem_region(iomem->start,
+ iomem->end + 1 - iomem->start,
+ driver_name);
+ if (!iomem) {
+ dev_dbg(dev, "i/o mem already in use.\n");
+ return -EBUSY;
+ }
+
+ mrst_rtc.irq = rtc_irq;
+ mrst_rtc.iomem = iomem;
+
+ mrst_rtc.rtc = rtc_device_register(driver_name, dev,
+ &mrst_rtc_ops, THIS_MODULE);
+ if (IS_ERR(mrst_rtc.rtc)) {
+ retval = PTR_ERR(mrst_rtc.rtc);
+ goto cleanup0;
+ }
+
+ mrst_rtc.dev = dev;
+ dev_set_drvdata(dev, &mrst_rtc);
+ rename_region(iomem, dev_name(&mrst_rtc.rtc->dev));
+
+ spin_lock_irq(&rtc_lock);
+ mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE);
+ rtc_control = vrtc_cmos_read(RTC_CONTROL);
+ spin_unlock_irq(&rtc_lock);
+
+ if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))
+ dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n");
+
+ if (rtc_irq) {
+ retval = request_irq(rtc_irq, mrst_rtc_irq,
+ IRQF_DISABLED, dev_name(&mrst_rtc.rtc->dev),
+ mrst_rtc.rtc);
+ if (retval < 0) {
+ dev_dbg(dev, "IRQ %d is already in use, err %d\n",
+ rtc_irq, retval);
+ goto cleanup1;
+ }
+ }
+ dev_dbg(dev, "initialised\n");
+ return 0;
+
+cleanup1:
+ mrst_rtc.dev = NULL;
+ rtc_device_unregister(mrst_rtc.rtc);
+cleanup0:
+ release_region(iomem->start, iomem->end + 1 - iomem->start);
+ dev_err(dev, "rtc-mrst: unable to initialise\n");
+ return retval;
+}
+
+static void rtc_mrst_do_shutdown(void)
+{
+ spin_lock_irq(&rtc_lock);
+ mrst_irq_disable(&mrst_rtc, RTC_IRQMASK);
+ spin_unlock_irq(&rtc_lock);
+}
+
+static void __exit rtc_mrst_do_remove(struct device *dev)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ struct resource *iomem;
+
+ rtc_mrst_do_shutdown();
+
+ if (mrst->irq)
+ free_irq(mrst->irq, mrst->rtc);
+
+ rtc_device_unregister(mrst->rtc);
+ mrst->rtc = NULL;
+
+ iomem = mrst->iomem;
+ release_region(iomem->start, iomem->end + 1 - iomem->start);
+ mrst->iomem = NULL;
+
+ mrst->dev = NULL;
+ dev_set_drvdata(dev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int mrst_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char tmp;
+
+ /* Only the alarm might be a wakeup event source */
+ spin_lock_irq(&rtc_lock);
+ mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL);
+ if (tmp & (RTC_PIE | RTC_AIE)) {
+ unsigned char mask;
+
+ if (device_may_wakeup(dev))
+ mask = RTC_IRQMASK & ~RTC_AIE;
+ else
+ mask = RTC_IRQMASK;
+ tmp &= ~mask;
+ vrtc_cmos_write(tmp, RTC_CONTROL);
+
+ mrst_checkintr(mrst, tmp);
+ }
+ spin_unlock_irq(&rtc_lock);
+
+ if (tmp & RTC_AIE) {
+ mrst->enabled_wake = 1;
+ enable_irq_wake(mrst->irq);
+ }
+
+ dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n",
+ (tmp & RTC_AIE) ? ", alarm may wake" : "",
+ tmp);
+
+ return 0;
+}
+
+/*
+ * We want RTC alarms to wake us from the deep power saving state
+ */
+static inline int mrst_poweroff(struct device *dev)
+{
+ return mrst_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int mrst_resume(struct device *dev)
+{
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char tmp = mrst->suspend_ctrl;
+
+ /* Re-enable any irqs previously active */
+ if (tmp & RTC_IRQMASK) {
+ unsigned char mask;
+
+ if (mrst->enabled_wake) {
+ disable_irq_wake(mrst->irq);
+ mrst->enabled_wake = 0;
+ }
+
+ spin_lock_irq(&rtc_lock);
+ do {
+ vrtc_cmos_write(tmp, RTC_CONTROL);
+
+ mask = vrtc_cmos_read(RTC_INTR_FLAGS);
+ mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
+ if (!is_intr(mask))
+ break;
+
+ rtc_update_irq(mrst->rtc, 1, mask);
+ tmp &= ~RTC_AIE;
+ } while (mask & RTC_AIE);
+ spin_unlock_irq(&rtc_lock);
+ }
+
+ dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp);
+
+ return 0;
+}
+
+#else
+#define mrst_suspend NULL
+#define mrst_resume NULL
+
+static inline int mrst_poweroff(struct device *dev)
+{
+ return -ENOSYS;
+}
+
+#endif
+
+static int __init vrtc_mrst_platform_probe(struct platform_device *pdev)
+{
+ return vrtc_mrst_do_probe(&pdev->dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0),
+ platform_get_irq(pdev, 0));
+}
+
+static int __exit vrtc_mrst_platform_remove(struct platform_device *pdev)
+{
+ rtc_mrst_do_remove(&pdev->dev);
+ return 0;
+}
+
+static void vrtc_mrst_platform_shutdown(struct platform_device *pdev)
+{
+ if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev))
+ return;
+
+ rtc_mrst_do_shutdown();
+}
+
+MODULE_ALIAS("platform:vrtc_mrst");
+
+static struct platform_driver vrtc_mrst_platform_driver = {
+ .probe = vrtc_mrst_platform_probe,
+ .remove = __exit_p(vrtc_mrst_platform_remove),
+ .shutdown = vrtc_mrst_platform_shutdown,
+ .driver = {
+ .name = (char *) driver_name,
+ .suspend = mrst_suspend,
+ .resume = mrst_resume,
+ }
+};
+
+static int __init vrtc_mrst_init(void)
+{
+ return platform_driver_register(&vrtc_mrst_platform_driver);
+}
+
+static void __exit vrtc_mrst_exit(void)
+{
+ platform_driver_unregister(&vrtc_mrst_platform_driver);
+}
+
+module_init(vrtc_mrst_init);
+module_exit(vrtc_mrst_exit);
+
+MODULE_AUTHOR("Jacob Pan; Feng Tang");
+MODULE_DESCRIPTION("Driver for Moorestown virtual RTC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 73377b0d65da..e72b523c79a5 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -429,13 +429,14 @@ fail1:
fail0:
iounmap(rtc_base);
fail:
- release_resource(mem);
+ release_mem_region(mem->start, resource_size(mem));
return -EIO;
}
static int __exit omap_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct resource *mem = dev_get_drvdata(&rtc->dev);
device_init_wakeup(&pdev->dev, 0);
@@ -447,8 +448,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
if (omap_rtc_timer != omap_rtc_alarm)
free_irq(omap_rtc_alarm, rtc);
- release_resource(dev_get_drvdata(&rtc->dev));
rtc_device_unregister(rtc);
+ iounmap(rtc_base);
+ release_mem_region(mem->start, resource_size(mem));
return 0;
}
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 90cf0a6ff23e..dd14e202c2c8 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -207,7 +207,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct rs5c372 *rs5c = i2c_get_clientdata(client);
- unsigned char buf[8];
+ unsigned char buf[7];
int addr;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 1146e3522d3c..af32a62e12a8 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -650,7 +650,7 @@ static int __devexit rx8025_remove(struct i2c_client *client)
mutex_unlock(lock);
free_irq(client->irq, client);
- flush_scheduled_work();
+ cancel_work_sync(&rx8025->work);
}
rx8025_sysfs_unregister(&client->dev);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index e4a44b641702..88ea52b8647a 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -39,10 +39,10 @@
#include <mach/regs-ost.h>
#endif
-#define RTC_DEF_DIVIDER 32768 - 1
+#define RTC_DEF_DIVIDER (32768 - 1)
#define RTC_DEF_TRIM 0
-static unsigned long rtc_freq = 1024;
+static const unsigned long RTC_FREQ = 1024;
static unsigned long timer_freq;
static struct rtc_time rtc_alarm;
static DEFINE_SPINLOCK(sa1100_rtc_lock);
@@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm)
* Calculate the next alarm time given the requested alarm time mask
* and the current time.
*/
-static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+ struct rtc_time *alrm)
{
unsigned long next_time;
unsigned long now_time;
@@ -116,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
rtsr = RTSR;
/* clear interrupt sources */
RTSR = 0;
- RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
+ /* Fix for a nasty initialization problem the in SA11xx RTSR register.
+ * See also the comments in sa1100_rtc_probe(). */
+ if (rtsr & (RTSR_ALE | RTSR_HZE)) {
+ /* This is the original code, before there was the if test
+ * above. This code does not clear interrupts that were not
+ * enabled. */
+ RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
+ } else {
+ /* For some reason, it is possible to enter this routine
+ * without interruptions enabled, it has been tested with
+ * several units (Bug in SA11xx chip?).
+ *
+ * This situation leads to an infinite "loop" of interrupt
+ * routine calling and as a result the processor seems to
+ * lock on its first call to open(). */
+ RTSR = RTSR_AL | RTSR_HZ;
+ }
/* clear alarm interrupt if it has occurred */
if (rtsr & RTSR_AL)
@@ -139,8 +156,58 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int sa1100_irq_set_freq(struct device *dev, int freq)
+{
+ if (freq < 1 || freq > timer_freq) {
+ return -EINVAL;
+ } else {
+ struct rtc_device *rtc = (struct rtc_device *)dev;
+
+ rtc->irq_freq = freq;
+
+ return 0;
+ }
+}
+
static int rtc_timer1_count;
+static int sa1100_irq_set_state(struct device *dev, int enabled)
+{
+ spin_lock_irq(&sa1100_rtc_lock);
+ if (enabled) {
+ struct rtc_device *rtc = (struct rtc_device *)dev;
+
+ OSMR1 = timer_freq / rtc->irq_freq + OSCR;
+ OIER |= OIER_E1;
+ rtc_timer1_count = 1;
+ } else {
+ OIER &= ~OIER_E1;
+ }
+ spin_unlock_irq(&sa1100_rtc_lock);
+
+ return 0;
+}
+
+static inline int sa1100_timer1_retrigger(struct rtc_device *rtc)
+{
+ unsigned long diff;
+ unsigned long period = timer_freq / rtc->irq_freq;
+
+ spin_lock_irq(&sa1100_rtc_lock);
+
+ do {
+ OSMR1 += period;
+ diff = OSMR1 - OSCR;
+ /* If OSCR > OSMR1, diff is a very large number (unsigned
+ * math). This means we have a lost interrupt. */
+ } while (diff > period);
+ OIER |= OIER_E1;
+
+ spin_unlock_irq(&sa1100_rtc_lock);
+
+ return 0;
+}
+
static irqreturn_t timer1_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = to_platform_device(dev_id);
@@ -158,7 +225,11 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
if (rtc_timer1_count == 1)
- rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2)));
+ rtc_timer1_count =
+ (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2)));
+
+ /* retrigger. */
+ sa1100_timer1_retrigger(rtc);
return IRQ_HANDLED;
}
@@ -166,8 +237,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
static int sa1100_rtc_read_callback(struct device *dev, int data)
{
if (data & RTC_PF) {
+ struct rtc_device *rtc = (struct rtc_device *)dev;
+
/* interpolate missed periods and set match for the next */
- unsigned long period = timer_freq / rtc_freq;
+ unsigned long period = timer_freq / rtc->irq_freq;
unsigned long oscr = OSCR;
unsigned long osmr1 = OSMR1;
unsigned long missed = (oscr - osmr1)/period;
@@ -178,7 +251,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data)
* Here we compare (match - OSCR) 8 instead of 0 --
* see comment in pxa_timer_interrupt() for explanation.
*/
- while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) {
+ while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) {
data += 0x100;
OSSR = OSSR_M1; /* clear match on timer 1 */
OSMR1 = osmr1 + period;
@@ -190,25 +263,29 @@ static int sa1100_rtc_read_callback(struct device *dev, int data)
static int sa1100_rtc_open(struct device *dev)
{
int ret;
+ struct rtc_device *rtc = (struct rtc_device *)dev;
ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
- "rtc 1Hz", dev);
+ "rtc 1Hz", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
goto fail_ui;
}
ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED,
- "rtc Alrm", dev);
+ "rtc Alrm", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
goto fail_ai;
}
ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED,
- "rtc timer", dev);
+ "rtc timer", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
goto fail_pi;
}
+ rtc->max_user_freq = RTC_FREQ;
+ sa1100_irq_set_freq(dev, RTC_FREQ);
+
return 0;
fail_pi:
@@ -236,7 +313,7 @@ static void sa1100_rtc_release(struct device *dev)
static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
unsigned long arg)
{
- switch(cmd) {
+ switch (cmd) {
case RTC_AIE_OFF:
spin_lock_irq(&sa1100_rtc_lock);
RTSR &= ~RTSR_ALE;
@@ -257,25 +334,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
RTSR |= RTSR_HZE;
spin_unlock_irq(&sa1100_rtc_lock);
return 0;
- case RTC_PIE_OFF:
- spin_lock_irq(&sa1100_rtc_lock);
- OIER &= ~OIER_E1;
- spin_unlock_irq(&sa1100_rtc_lock);
- return 0;
- case RTC_PIE_ON:
- spin_lock_irq(&sa1100_rtc_lock);
- OSMR1 = timer_freq / rtc_freq + OSCR;
- OIER |= OIER_E1;
- rtc_timer1_count = 1;
- spin_unlock_irq(&sa1100_rtc_lock);
- return 0;
- case RTC_IRQP_READ:
- return put_user(rtc_freq, (unsigned long *)arg);
- case RTC_IRQP_SET:
- if (arg < 1 || arg > timer_freq)
- return -EINVAL;
- rtc_freq = arg;
- return 0;
}
return -ENOIOCTLCMD;
}
@@ -327,12 +385,15 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
{
+ struct rtc_device *rtc = (struct rtc_device *)dev;
+
seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR);
seq_printf(seq, "update_IRQ\t: %s\n",
(RTSR & RTSR_HZE) ? "yes" : "no");
seq_printf(seq, "periodic_IRQ\t: %s\n",
(OIER & OIER_E1) ? "yes" : "no");
- seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq);
+ seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq);
+ seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR);
return 0;
}
@@ -347,6 +408,8 @@ static const struct rtc_class_ops sa1100_rtc_ops = {
.read_alarm = sa1100_rtc_read_alarm,
.set_alarm = sa1100_rtc_set_alarm,
.proc = sa1100_rtc_proc,
+ .irq_set_freq = sa1100_irq_set_freq,
+ .irq_set_state = sa1100_irq_set_state,
};
static int sa1100_rtc_probe(struct platform_device *pdev)
@@ -364,7 +427,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
*/
if (RTTR == 0) {
RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
- dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n");
+ dev_warn(&pdev->dev, "warning: "
+ "initializing default clock divider/trim value\n");
/* The current RTC value probably doesn't make sense either */
RCNR = 0;
}
@@ -372,13 +436,42 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
- THIS_MODULE);
+ THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
platform_set_drvdata(pdev, rtc);
+ /* Set the irq_freq */
+ /*TODO: Find out who is messing with this value after we initialize
+ * it here.*/
+ rtc->irq_freq = RTC_FREQ;
+
+ /* Fix for a nasty initialization problem the in SA11xx RTSR register.
+ * See also the comments in sa1100_rtc_interrupt().
+ *
+ * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an
+ * interrupt pending, even though interrupts were never enabled.
+ * In this case, this bit it must be reset before enabling
+ * interruptions to avoid a nonexistent interrupt to occur.
+ *
+ * In principle, the same problem would apply to bit 0, although it has
+ * never been observed to happen.
+ *
+ * This issue is addressed both here and in sa1100_rtc_interrupt().
+ * If the issue is not addressed here, in the times when the processor
+ * wakes up with the bit set there will be one spurious interrupt.
+ *
+ * The issue is also dealt with in sa1100_rtc_interrupt() to be on the
+ * safe side, once the condition that lead to this strange
+ * initialization is unknown and could in principle happen during
+ * normal processing.
+ *
+ * Notice that clearing bit 1 and 0 is accomplished by writting ONES to
+ * the corresponding bits in RTSR. */
+ RTSR = RTSR_AL | RTSR_HZ;
+
return 0;
}
@@ -386,7 +479,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
- if (rtc)
+ if (rtc)
rtc_device_unregister(rtc);
return 0;
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 5efbd5990ff8..06e41ed93230 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -761,7 +761,7 @@ err_unmap:
clk_put(rtc->clk);
iounmap(rtc->regbase);
err_badmap:
- release_resource(rtc->res);
+ release_mem_region(rtc->res->start, rtc->regsize);
err_badres:
kfree(rtc);
@@ -786,7 +786,7 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
}
iounmap(rtc->regbase);
- release_resource(rtc->res);
+ release_mem_region(rtc->res->start, rtc->regsize);
clk_disable(rtc->clk);
clk_put(rtc->clk);
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 07883197f474..8e477bb1f3f6 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -2,7 +2,8 @@ comment "S/390 block device drivers"
depends on S390 && BLOCK
config BLK_DEV_XPRAM
- tristate "XPRAM disk support"
+ def_tristate m
+ prompt "XPRAM disk support"
depends on S390 && BLOCK
help
Select this option if you want to use your expanded storage on S/390
@@ -12,13 +13,15 @@ config BLK_DEV_XPRAM
xpram. If unsure, say "N".
config DCSSBLK
- tristate "DCSSBLK support"
+ def_tristate m
+ prompt "DCSSBLK support"
depends on S390 && BLOCK
help
Support for dcss block device
config DASD
- tristate "Support for DASD devices"
+ def_tristate y
+ prompt "Support for DASD devices"
depends on CCW && BLOCK
select IOSCHED_DEADLINE
help
@@ -27,28 +30,32 @@ config DASD
natively on a single image or an LPAR.
config DASD_PROFILE
- bool "Profiling support for dasd devices"
+ def_bool y
+ prompt "Profiling support for dasd devices"
depends on DASD
help
Enable this option if you want to see profiling information
in /proc/dasd/statistics.
config DASD_ECKD
- tristate "Support for ECKD Disks"
+ def_tristate y
+ prompt "Support for ECKD Disks"
depends on DASD
help
ECKD devices are the most commonly used devices. You should enable
this option unless you are very sure to have no ECKD device.
config DASD_FBA
- tristate "Support for FBA Disks"
+ def_tristate y
+ prompt "Support for FBA Disks"
depends on DASD
help
Select this option to be able to access FBA devices. It is safe to
say "Y".
config DASD_DIAG
- tristate "Support for DIAG access to Disks"
+ def_tristate y
+ prompt "Support for DIAG access to Disks"
depends on DASD
help
Select this option if you want to use Diagnose250 command to access
@@ -56,7 +63,8 @@ config DASD_DIAG
say "N".
config DASD_EER
- bool "Extended error reporting (EER)"
+ def_bool y
+ prompt "Extended error reporting (EER)"
depends on DASD
help
This driver provides a character device interface to the
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index fb613d70c2cb..794bfd962266 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -11,6 +11,7 @@
#define KMSG_COMPONENT "dasd"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -368,6 +369,11 @@ dasd_state_ready_to_online(struct dasd_device * device)
device->state = DASD_STATE_ONLINE;
if (device->block) {
dasd_schedule_block_bh(device->block);
+ if ((device->features & DASD_FEATURE_USERAW)) {
+ disk = device->block->gdp;
+ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
+ return 0;
+ }
disk = device->block->bdev->bd_disk;
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
while ((part = disk_part_iter_next(&piter)))
@@ -393,7 +399,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
return rc;
}
device->state = DASD_STATE_READY;
- if (device->block) {
+ if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
disk = device->block->bdev->bd_disk;
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
while ((part = disk_part_iter_next(&piter)))
@@ -744,10 +750,6 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength,
char *data;
int size;
- /* Sanity checks */
- BUG_ON(datasize > PAGE_SIZE ||
- (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
-
size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
if (cplength > 0)
size += cplength * sizeof(struct ccw1);
@@ -853,7 +855,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
rc = ccw_device_clear(device->cdev, (long) cqr);
switch (rc) {
case 0: /* termination successful */
- cqr->retries--;
cqr->status = DASD_CQR_CLEAR_PENDING;
cqr->stopclk = get_clock();
cqr->starttime = 0;
@@ -905,6 +906,16 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
return rc;
}
device = (struct dasd_device *) cqr->startdev;
+ if (((cqr->block &&
+ test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) ||
+ test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) &&
+ !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+ DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p "
+ "because of stolen lock", cqr);
+ cqr->status = DASD_CQR_ERROR;
+ cqr->intrc = -EPERM;
+ return -EPERM;
+ }
if (cqr->retries < 0) {
/* internal error 14 - start_IO run out of retries */
sprintf(errorstring, "14 %p", cqr);
@@ -916,6 +927,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
cqr->startclk = get_clock();
cqr->starttime = jiffies;
cqr->retries--;
+ if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
+ cqr->lpm &= device->path_data.opm;
+ if (!cqr->lpm)
+ cqr->lpm = device->path_data.opm;
+ }
if (cqr->cpmode == 1) {
rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
(long) cqr, cqr->lpm);
@@ -928,35 +944,53 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
cqr->status = DASD_CQR_IN_IO;
break;
case -EBUSY:
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: device busy, retry later");
break;
case -ETIMEDOUT:
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: request timeout, retry later");
break;
case -EACCES:
- /* -EACCES indicates that the request used only a
- * subset of the available pathes and all these
- * pathes are gone.
- * Do a retry with all available pathes.
+ /* -EACCES indicates that the request used only a subset of the
+ * available paths and all these paths are gone. If the lpm of
+ * this request was only a subset of the opm (e.g. the ppm) then
+ * we just do a retry with all available paths.
+ * If we already use the full opm, something is amiss, and we
+ * need a full path verification.
*/
- cqr->lpm = LPM_ANYPATH;
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
- "start_IO: selected pathes gone,"
- " retry on all pathes");
+ if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
+ DBF_DEV_EVENT(DBF_WARNING, device,
+ "start_IO: selected paths gone (%x)",
+ cqr->lpm);
+ } else if (cqr->lpm != device->path_data.opm) {
+ cqr->lpm = device->path_data.opm;
+ DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ "start_IO: selected paths gone,"
+ " retry on all paths");
+ } else {
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+ "start_IO: all paths in opm gone,"
+ " do path verification");
+ dasd_generic_last_path_gone(device);
+ device->path_data.opm = 0;
+ device->path_data.ppm = 0;
+ device->path_data.npm = 0;
+ device->path_data.tbvpm =
+ ccw_device_get_path_mask(device->cdev);
+ }
break;
case -ENODEV:
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: -ENODEV device gone, retry");
break;
case -EIO:
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: -EIO device gone, retry");
break;
case -EINVAL:
/* most likely caused in power management context */
- DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: -EINVAL device currently "
"not accessible");
break;
@@ -1076,6 +1110,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
unsigned long long now;
int expires;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++;
if (IS_ERR(irb)) {
switch (PTR_ERR(irb)) {
case -EIO:
@@ -1094,16 +1129,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
}
now = get_clock();
-
- /* check for unsolicited interrupts */
cqr = (struct dasd_ccw_req *) intparm;
- if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
- (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
- ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
- (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
- SCSW_STCTL_ALERT_STATUS))))) {
- if (cqr && cqr->status == DASD_CQR_IN_IO)
- cqr->status = DASD_CQR_QUEUED;
+ /* check for conditions that should be handled immediately */
+ if (!cqr ||
+ !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+ scsw_cstat(&irb->scsw) == 0)) {
if (cqr)
memcpy(&cqr->irb, irb, sizeof(*irb));
device = dasd_device_from_cdev_locked(cdev);
@@ -1114,17 +1144,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
dasd_put_device(device);
return;
}
- device->discipline->dump_sense_dbf(device, irb,
- "unsolicited");
- if ((device->features & DASD_FEATURE_ERPLOG))
- device->discipline->dump_sense(device, cqr,
- irb);
- dasd_device_clear_timer(device);
- device->discipline->handle_unsolicited_interrupt(device,
- irb);
+ device->discipline->dump_sense_dbf(device, irb, "int");
+ if (device->features & DASD_FEATURE_ERPLOG)
+ device->discipline->dump_sense(device, cqr, irb);
+ device->discipline->check_for_device_change(device, cqr, irb);
dasd_put_device(device);
- return;
}
+ if (!cqr)
+ return;
device = (struct dasd_device *) cqr->startdev;
if (!device ||
@@ -1164,25 +1191,19 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
struct dasd_ccw_req, devlist);
}
} else { /* error */
- memcpy(&cqr->irb, irb, sizeof(struct irb));
- /* log sense for every failed I/O to s390 debugfeature */
- dasd_log_sense_dbf(cqr, irb);
- if (device->features & DASD_FEATURE_ERPLOG) {
- dasd_log_sense(cqr, irb);
- }
-
/*
* If we don't want complex ERP for this request, then just
* reset this and retry it in the fastpath
*/
if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
cqr->retries > 0) {
- if (cqr->lpm == LPM_ANYPATH)
+ if (cqr->lpm == device->path_data.opm)
DBF_DEV_EVENT(DBF_DEBUG, device,
"default ERP in fastpath "
"(%i retries left)",
cqr->retries);
- cqr->lpm = LPM_ANYPATH;
+ if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
+ cqr->lpm = device->path_data.opm;
cqr->status = DASD_CQR_QUEUED;
next = cqr;
} else
@@ -1210,13 +1231,13 @@ enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb)
goto out;
if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
device->state != device->target ||
- !device->discipline->handle_unsolicited_interrupt){
+ !device->discipline->check_for_device_change){
dasd_put_device(device);
goto out;
}
-
- dasd_device_clear_timer(device);
- device->discipline->handle_unsolicited_interrupt(device, irb);
+ if (device->discipline->dump_sense_dbf)
+ device->discipline->dump_sense_dbf(device, irb, "uc");
+ device->discipline->check_for_device_change(device, NULL, irb);
dasd_put_device(device);
out:
return UC_TODO_RETRY;
@@ -1366,8 +1387,14 @@ static void __dasd_device_start_head(struct dasd_device *device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
if (cqr->status != DASD_CQR_QUEUED)
return;
- /* when device is stopped, return request to previous layer */
- if (device->stopped) {
+ /* when device is stopped, return request to previous layer
+ * exception: only the disconnect or unresumed bits are set and the
+ * cqr is a path verification request
+ */
+ if (device->stopped &&
+ !(!(device->stopped & ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM))
+ && test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))) {
+ cqr->intrc = -EAGAIN;
cqr->status = DASD_CQR_CLEARED;
dasd_schedule_device_bh(device);
return;
@@ -1383,6 +1410,23 @@ static void __dasd_device_start_head(struct dasd_device *device)
dasd_device_set_timer(device, 50);
}
+static void __dasd_device_check_path_events(struct dasd_device *device)
+{
+ int rc;
+
+ if (device->path_data.tbvpm) {
+ if (device->stopped & ~(DASD_STOPPED_DC_WAIT |
+ DASD_UNRESUMED_PM))
+ return;
+ rc = device->discipline->verify_path(
+ device, device->path_data.tbvpm);
+ if (rc)
+ dasd_device_set_timer(device, 50);
+ else
+ device->path_data.tbvpm = 0;
+ }
+};
+
/*
* Go through all request on the dasd_device request queue,
* terminate them on the cdev if necessary, and return them to the
@@ -1457,6 +1501,7 @@ static void dasd_device_tasklet(struct dasd_device *device)
__dasd_device_check_expire(device);
/* find final requests on ccw queue */
__dasd_device_process_ccw_queue(device, &final_queue);
+ __dasd_device_check_path_events(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
/* Now call the callback function of requests with final status */
__dasd_device_process_final_queue(device, &final_queue);
@@ -1613,7 +1658,12 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
continue;
if (cqr->status != DASD_CQR_FILLED) /* could be failed */
continue;
-
+ if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+ !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = -EPERM;
+ continue;
+ }
/* Non-temporary stop condition will trigger fail fast */
if (device->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
@@ -1621,7 +1671,6 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
cqr->status = DASD_CQR_FAILED;
continue;
}
-
/* Don't try to start requests if device is stopped */
if (interruptible) {
rc = wait_event_interruptible(
@@ -1706,13 +1755,18 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
int rc;
device = cqr->startdev;
+ if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+ !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = -EPERM;
+ return -EIO;
+ }
spin_lock_irq(get_ccwdev_lock(device->cdev));
rc = _dasd_term_running_cqr(device);
if (rc) {
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
}
-
cqr->callback = dasd_wakeup_cb;
cqr->callback_data = DASD_SLEEPON_START_TAG;
cqr->status = DASD_CQR_QUEUED;
@@ -2016,6 +2070,13 @@ static void __dasd_block_start_head(struct dasd_block *block)
list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
if (cqr->status != DASD_CQR_FILLED)
continue;
+ if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) &&
+ !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = -EPERM;
+ dasd_schedule_block_bh(block);
+ continue;
+ }
/* Non-temporary stop condition will trigger fail fast */
if (block->base->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
@@ -2201,8 +2262,20 @@ static void dasd_setup_queue(struct dasd_block *block)
{
int max;
- blk_queue_logical_block_size(block->request_queue, block->bp_block);
- max = block->base->discipline->max_blocks << block->s2b_shift;
+ if (block->base->features & DASD_FEATURE_USERAW) {
+ /*
+ * the max_blocks value for raw_track access is 256
+ * it is higher than the native ECKD value because we
+ * only need one ccw per track
+ * so the max_hw_sectors are
+ * 2048 x 512B = 1024kB = 16 tracks
+ */
+ max = 2048;
+ } else {
+ max = block->base->discipline->max_blocks << block->s2b_shift;
+ }
+ blk_queue_logical_block_size(block->request_queue,
+ block->bp_block);
blk_queue_max_hw_sectors(block->request_queue, max);
blk_queue_max_segments(block->request_queue, -1L);
/* with page sized segments we can translate each segement into
@@ -2588,10 +2661,53 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
return 0;
}
+int dasd_generic_last_path_gone(struct dasd_device *device)
+{
+ struct dasd_ccw_req *cqr;
+
+ dev_warn(&device->cdev->dev, "No operational channel path is left "
+ "for the device\n");
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s", "last path gone");
+ /* First of all call extended error reporting. */
+ dasd_eer_write(device, NULL, DASD_EER_NOPATH);
+
+ if (device->state < DASD_STATE_BASIC)
+ return 0;
+ /* Device is active. We want to keep it. */
+ list_for_each_entry(cqr, &device->ccw_queue, devlist)
+ if ((cqr->status == DASD_CQR_IN_IO) ||
+ (cqr->status == DASD_CQR_CLEAR_PENDING)) {
+ cqr->status = DASD_CQR_QUEUED;
+ cqr->retries++;
+ }
+ dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT);
+ dasd_device_clear_timer(device);
+ dasd_schedule_device_bh(device);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_last_path_gone);
+
+int dasd_generic_path_operational(struct dasd_device *device)
+{
+ dev_info(&device->cdev->dev, "A channel path to the device has become "
+ "operational\n");
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s", "path operational");
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT);
+ if (device->stopped & DASD_UNRESUMED_PM) {
+ dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM);
+ dasd_restore_device(device);
+ return 1;
+ }
+ dasd_schedule_device_bh(device);
+ if (device->block)
+ dasd_schedule_block_bh(device->block);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_path_operational);
+
int dasd_generic_notify(struct ccw_device *cdev, int event)
{
struct dasd_device *device;
- struct dasd_ccw_req *cqr;
int ret;
device = dasd_device_from_cdev_locked(cdev);
@@ -2602,41 +2718,64 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
case CIO_GONE:
case CIO_BOXED:
case CIO_NO_PATH:
- /* First of all call extended error reporting. */
- dasd_eer_write(device, NULL, DASD_EER_NOPATH);
-
- if (device->state < DASD_STATE_BASIC)
- break;
- /* Device is active. We want to keep it. */
- list_for_each_entry(cqr, &device->ccw_queue, devlist)
- if (cqr->status == DASD_CQR_IN_IO) {
- cqr->status = DASD_CQR_QUEUED;
- cqr->retries++;
- }
- dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT);
- dasd_device_clear_timer(device);
- dasd_schedule_device_bh(device);
- ret = 1;
+ device->path_data.opm = 0;
+ device->path_data.ppm = 0;
+ device->path_data.npm = 0;
+ ret = dasd_generic_last_path_gone(device);
break;
case CIO_OPER:
- /* FIXME: add a sanity check. */
- dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT);
- if (device->stopped & DASD_UNRESUMED_PM) {
- dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM);
- dasd_restore_device(device);
- ret = 1;
- break;
- }
- dasd_schedule_device_bh(device);
- if (device->block)
- dasd_schedule_block_bh(device->block);
ret = 1;
+ if (device->path_data.opm)
+ ret = dasd_generic_path_operational(device);
break;
}
dasd_put_device(device);
return ret;
}
+void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
+{
+ int chp;
+ __u8 oldopm, eventlpm;
+ struct dasd_device *device;
+
+ device = dasd_device_from_cdev_locked(cdev);
+ if (IS_ERR(device))
+ return;
+ for (chp = 0; chp < 8; chp++) {
+ eventlpm = 0x80 >> chp;
+ if (path_event[chp] & PE_PATH_GONE) {
+ oldopm = device->path_data.opm;
+ device->path_data.opm &= ~eventlpm;
+ device->path_data.ppm &= ~eventlpm;
+ device->path_data.npm &= ~eventlpm;
+ if (oldopm && !device->path_data.opm)
+ dasd_generic_last_path_gone(device);
+ }
+ if (path_event[chp] & PE_PATH_AVAILABLE) {
+ device->path_data.opm &= ~eventlpm;
+ device->path_data.ppm &= ~eventlpm;
+ device->path_data.npm &= ~eventlpm;
+ device->path_data.tbvpm |= eventlpm;
+ dasd_schedule_device_bh(device);
+ }
+ }
+ dasd_put_device(device);
+}
+EXPORT_SYMBOL_GPL(dasd_generic_path_event);
+
+int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm)
+{
+ if (!device->path_data.opm && lpm) {
+ device->path_data.opm = lpm;
+ dasd_generic_path_operational(device);
+ } else
+ device->path_data.opm |= lpm;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
+
+
int dasd_generic_pm_freeze(struct ccw_device *cdev)
{
struct dasd_ccw_req *cqr, *n;
@@ -2646,6 +2785,10 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
if (IS_ERR(device))
return PTR_ERR(device);
+
+ if (device->discipline->freeze)
+ rc = device->discipline->freeze(device);
+
/* disallow new I/O */
dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
/* clear active requests */
@@ -2682,9 +2825,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
list_splice_tail(&freeze_queue, &device->ccw_queue);
spin_unlock_irq(get_ccwdev_lock(cdev));
- if (device->discipline->freeze)
- rc = device->discipline->freeze(device);
-
dasd_put_device(device);
return rc;
}
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 968c76cf7127..1654a24817be 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -152,9 +152,9 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
opm = ccw_device_get_path_mask(device->cdev);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- //FIXME: start with get_opm ?
if (erp->lpm == 0)
- erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
+ erp->lpm = device->path_data.opm &
+ ~(erp->irb.esw.esw0.sublog.lpum);
else
erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum);
@@ -270,10 +270,11 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
{
erp->function = dasd_3990_erp_action_1;
dasd_3990_erp_alternate_path(erp);
- if (erp->status == DASD_CQR_FAILED) {
+ if (erp->status == DASD_CQR_FAILED &&
+ !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
erp->status = DASD_CQR_FILLED;
erp->retries = 10;
- erp->lpm = LPM_ANYPATH;
+ erp->lpm = erp->startdev->path_data.opm;
erp->function = dasd_3990_erp_action_1_sec;
}
return erp;
@@ -1907,15 +1908,14 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
static void
dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
{
-
if (sense[25] & DASD_SENSE_BIT_3) {
dasd_3990_erp_alternate_path(erp);
- if (erp->status == DASD_CQR_FAILED) {
+ if (erp->status == DASD_CQR_FAILED &&
+ !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
/* reset the lpm and the status to be able to
* try further actions. */
-
- erp->lpm = 0;
+ erp->lpm = erp->startdev->path_data.opm;
erp->status = DASD_CQR_NEED_ERP;
}
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 8d41f3ed38d7..cb6a67bc89ff 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -208,6 +208,8 @@ dasd_feature_list(char *str, char **endp)
features |= DASD_FEATURE_READONLY;
else if (len == 4 && !strncmp(str, "diag", 4))
features |= DASD_FEATURE_USEDIAG;
+ else if (len == 3 && !strncmp(str, "raw", 3))
+ features |= DASD_FEATURE_USERAW;
else if (len == 6 && !strncmp(str, "erplog", 6))
features |= DASD_FEATURE_ERPLOG;
else if (len == 8 && !strncmp(str, "failfast", 8))
@@ -639,6 +641,7 @@ dasd_put_device_wake(struct dasd_device *device)
{
wake_up(&dasd_delete_wq);
}
+EXPORT_SYMBOL_GPL(dasd_put_device_wake);
/*
* Return dasd_device structure associated with cdev.
@@ -856,7 +859,7 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
spin_lock(&dasd_devmap_lock);
/* Changing diag discipline flag is only allowed in offline state. */
rc = count;
- if (!devmap->device) {
+ if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) {
if (val)
devmap->features |= DASD_FEATURE_USEDIAG;
else
@@ -869,6 +872,56 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
+/*
+ * use_raw controls whether the driver should give access to raw eckd data or
+ * operate in standard mode
+ */
+static ssize_t
+dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ int use_raw;
+
+ devmap = dasd_find_busid(dev_name(dev));
+ if (!IS_ERR(devmap))
+ use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0;
+ else
+ use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0;
+ return sprintf(buf, use_raw ? "1\n" : "0\n");
+}
+
+static ssize_t
+dasd_use_raw_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_devmap *devmap;
+ ssize_t rc;
+ unsigned long val;
+
+ devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+
+ if ((strict_strtoul(buf, 10, &val) != 0) || val > 1)
+ return -EINVAL;
+
+ spin_lock(&dasd_devmap_lock);
+ /* Changing diag discipline flag is only allowed in offline state. */
+ rc = count;
+ if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) {
+ if (val)
+ devmap->features |= DASD_FEATURE_USERAW;
+ else
+ devmap->features &= ~DASD_FEATURE_USERAW;
+ } else
+ rc = -EPERM;
+ spin_unlock(&dasd_devmap_lock);
+ return rc;
+}
+
+static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show,
+ dasd_use_raw_store);
+
static ssize_t
dasd_discipline_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1126,6 +1179,103 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
+static ssize_t dasd_reservation_policy_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dasd_devmap *devmap;
+ int rc = 0;
+
+ devmap = dasd_find_busid(dev_name(dev));
+ if (IS_ERR(devmap)) {
+ rc = snprintf(buf, PAGE_SIZE, "ignore\n");
+ } else {
+ spin_lock(&dasd_devmap_lock);
+ if (devmap->features & DASD_FEATURE_FAILONSLCK)
+ rc = snprintf(buf, PAGE_SIZE, "fail\n");
+ else
+ rc = snprintf(buf, PAGE_SIZE, "ignore\n");
+ spin_unlock(&dasd_devmap_lock);
+ }
+ return rc;
+}
+
+static ssize_t dasd_reservation_policy_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_devmap *devmap;
+ int rc;
+
+ devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+ rc = 0;
+ spin_lock(&dasd_devmap_lock);
+ if (sysfs_streq("ignore", buf))
+ devmap->features &= ~DASD_FEATURE_FAILONSLCK;
+ else if (sysfs_streq("fail", buf))
+ devmap->features |= DASD_FEATURE_FAILONSLCK;
+ else
+ rc = -EINVAL;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
+ spin_unlock(&dasd_devmap_lock);
+ if (rc)
+ return rc;
+ else
+ return count;
+}
+
+static DEVICE_ATTR(reservation_policy, 0644,
+ dasd_reservation_policy_show, dasd_reservation_policy_store);
+
+static ssize_t dasd_reservation_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dasd_device *device;
+ int rc = 0;
+
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(device))
+ return snprintf(buf, PAGE_SIZE, "none\n");
+
+ if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags))
+ rc = snprintf(buf, PAGE_SIZE, "reserved\n");
+ else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags))
+ rc = snprintf(buf, PAGE_SIZE, "lost\n");
+ else
+ rc = snprintf(buf, PAGE_SIZE, "none\n");
+ dasd_put_device(device);
+ return rc;
+}
+
+static ssize_t dasd_reservation_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_device *device;
+ int rc = 0;
+
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(device))
+ return -ENODEV;
+ if (sysfs_streq("reset", buf))
+ clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
+ else
+ rc = -EINVAL;
+ dasd_put_device(device);
+
+ if (rc)
+ return rc;
+ else
+ return count;
+}
+
+static DEVICE_ATTR(last_known_reservation_state, 0644,
+ dasd_reservation_state_show, dasd_reservation_state_store);
+
static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
@@ -1134,10 +1284,13 @@ static struct attribute * dasd_attrs[] = {
&dev_attr_vendor.attr,
&dev_attr_uid.attr,
&dev_attr_use_diag.attr,
+ &dev_attr_raw_track_access.attr,
&dev_attr_eer_enabled.attr,
&dev_attr_erplog.attr,
&dev_attr_failfast.attr,
&dev_attr_expires.attr,
+ &dev_attr_reservation_policy.attr,
+ &dev_attr_last_known_reservation_state.attr,
NULL,
};
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 266b34b55403..29143eda9dd9 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -10,6 +10,7 @@
#define KMSG_COMPONENT "dasd"
+#include <linux/kernel_stat.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -238,6 +239,7 @@ static void dasd_ext_handler(unsigned int ext_int_code,
addr_t ip;
int rc;
+ kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++;
switch (ext_int_code >> 24) {
case DASD_DIAG_CODE_31BIT:
ip = (addr_t) param32;
@@ -617,6 +619,7 @@ static struct dasd_discipline dasd_diag_discipline = {
.ebcname = "DIAG",
.max_blocks = DIAG_MAX_BLOCKS,
.check_device = dasd_diag_check_device,
+ .verify_path = dasd_generic_verify_path,
.fill_geometry = dasd_diag_fill_geometry,
.start_IO = dasd_start_diag,
.term_IO = dasd_diag_term_IO,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bf61274af3bb..318672d05563 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -54,6 +54,15 @@
#define ECKD_F7(i) (i->factor7)
#define ECKD_F8(i) (i->factor8)
+/*
+ * raw track access always map to 64k in memory
+ * so it maps to 16 blocks of 4k per track
+ */
+#define DASD_RAW_BLOCK_PER_TRACK 16
+#define DASD_RAW_BLOCKSIZE 4096
+/* 64k are 128 x 512 byte sectors */
+#define DASD_RAW_SECTORS_PER_TRACK 128
+
MODULE_LICENSE("GPL");
static struct dasd_discipline dasd_eckd_discipline;
@@ -90,6 +99,18 @@ static struct {
} *dasd_reserve_req;
static DEFINE_MUTEX(dasd_reserve_mutex);
+/* definitions for the path verification worker */
+struct path_verification_work_data {
+ struct work_struct worker;
+ struct dasd_device *device;
+ struct dasd_ccw_req cqr;
+ struct ccw1 ccw;
+ __u8 rcd_buffer[DASD_ECKD_RCD_DATA_SIZE];
+ int isglobal;
+ __u8 tbvpm;
+};
+static struct path_verification_work_data *path_verification_worker;
+static DEFINE_MUTEX(dasd_path_verification_mutex);
/* initial attempt at a probe function. this can be simplified once
* the other detection code is gone */
@@ -373,6 +394,23 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
data->length = reclen;
data->operation.operation = 0x03;
break;
+ case DASD_ECKD_CCW_WRITE_FULL_TRACK:
+ data->operation.orientation = 0x0;
+ data->operation.operation = 0x3F;
+ data->extended_operation = 0x11;
+ data->length = 0;
+ data->extended_parameter_length = 0x02;
+ if (data->count > 8) {
+ data->extended_parameter[0] = 0xFF;
+ data->extended_parameter[1] = 0xFF;
+ data->extended_parameter[1] <<= (16 - count);
+ } else {
+ data->extended_parameter[0] = 0xFF;
+ data->extended_parameter[0] <<= (8 - count);
+ data->extended_parameter[1] = 0x00;
+ }
+ data->sector = 0xFF;
+ break;
case DASD_ECKD_CCW_WRITE_TRACK_DATA:
data->auxiliary.length_valid = 0x1;
data->length = reclen; /* not tlf, as one might think */
@@ -396,6 +434,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
case DASD_ECKD_CCW_READ_COUNT:
data->operation.operation = 0x06;
break;
+ case DASD_ECKD_CCW_READ_TRACK:
+ data->operation.orientation = 0x1;
+ data->operation.operation = 0x0C;
+ data->extended_parameter_length = 0;
+ data->sector = 0xFF;
+ break;
case DASD_ECKD_CCW_READ_TRACK_DATA:
data->auxiliary.length_valid = 0x1;
data->length = tlf;
@@ -439,10 +483,16 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
ccw->cmd_code = DASD_ECKD_CCW_PFX;
ccw->flags = 0;
- ccw->count = sizeof(*pfxdata);
- ccw->cda = (__u32) __pa(pfxdata);
+ if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) {
+ ccw->count = sizeof(*pfxdata) + 2;
+ ccw->cda = (__u32) __pa(pfxdata);
+ memset(pfxdata, 0, sizeof(*pfxdata) + 2);
+ } else {
+ ccw->count = sizeof(*pfxdata);
+ ccw->cda = (__u32) __pa(pfxdata);
+ memset(pfxdata, 0, sizeof(*pfxdata));
+ }
- memset(pfxdata, 0, sizeof(*pfxdata));
/* prefix data */
if (format > 1) {
DBF_DEV_EVENT(DBF_ERR, basedev,
@@ -476,6 +526,7 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
dedata->mask.perm = 0x1;
dedata->attributes.operation = basepriv->attrib.operation;
break;
+ case DASD_ECKD_CCW_READ_TRACK:
case DASD_ECKD_CCW_READ_TRACK_DATA:
dedata->mask.perm = 0x1;
dedata->attributes.operation = basepriv->attrib.operation;
@@ -502,6 +553,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
dedata->attributes.operation = DASD_BYPASS_CACHE;
rc = check_XRC_on_prefix(pfxdata, basedev);
break;
+ case DASD_ECKD_CCW_WRITE_FULL_TRACK:
+ dedata->mask.perm = 0x03;
+ dedata->attributes.operation = basepriv->attrib.operation;
+ dedata->blk_size = 0;
+ break;
case DASD_ECKD_CCW_WRITE_TRACK_DATA:
dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation;
@@ -755,26 +811,27 @@ static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid)
return -EINVAL;
}
-static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
- void *rcd_buffer,
- struct ciw *ciw, __u8 lpm)
+static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device,
+ struct dasd_ccw_req *cqr,
+ __u8 *rcd_buffer,
+ __u8 lpm)
{
- struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
-
- cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count,
- device);
-
- if (IS_ERR(cqr)) {
- DBF_DEV_EVENT(DBF_WARNING, device, "%s",
- "Could not allocate RCD request");
- return cqr;
- }
+ /*
+ * buffer has to start with EBCDIC "V1.0" to show
+ * support for virtual device SNEQ
+ */
+ rcd_buffer[0] = 0xE5;
+ rcd_buffer[1] = 0xF1;
+ rcd_buffer[2] = 0x4B;
+ rcd_buffer[3] = 0xF0;
ccw = cqr->cpaddr;
- ccw->cmd_code = ciw->cmd;
+ ccw->cmd_code = DASD_ECKD_CCW_RCD;
+ ccw->flags = 0;
ccw->cda = (__u32)(addr_t)rcd_buffer;
- ccw->count = ciw->count;
+ ccw->count = DASD_ECKD_RCD_DATA_SIZE;
+ cqr->magic = DASD_ECKD_MAGIC;
cqr->startdev = device;
cqr->memdev = device;
@@ -784,7 +841,30 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
- return cqr;
+ set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
+}
+
+static int dasd_eckd_read_conf_immediately(struct dasd_device *device,
+ struct dasd_ccw_req *cqr,
+ __u8 *rcd_buffer,
+ __u8 lpm)
+{
+ struct ciw *ciw;
+ int rc;
+ /*
+ * sanity check: scan for RCD command in extended SenseID data
+ * some devices do not support RCD
+ */
+ ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD);
+ if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD)
+ return -EOPNOTSUPP;
+
+ dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm);
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
+ cqr->retries = 5;
+ rc = dasd_sleep_on_immediatly(cqr);
+ return rc;
}
static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
@@ -797,32 +877,29 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
struct dasd_ccw_req *cqr;
/*
- * scan for RCD command in extended SenseID data
+ * sanity check: scan for RCD command in extended SenseID data
+ * some devices do not support RCD
*/
ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD);
- if (!ciw || ciw->cmd == 0) {
+ if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD) {
ret = -EOPNOTSUPP;
goto out_error;
}
- rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+ rcd_buf = kzalloc(DASD_ECKD_RCD_DATA_SIZE, GFP_KERNEL | GFP_DMA);
if (!rcd_buf) {
ret = -ENOMEM;
goto out_error;
}
-
- /*
- * buffer has to start with EBCDIC "V1.0" to show
- * support for virtual device SNEQ
- */
- rcd_buf[0] = 0xE5;
- rcd_buf[1] = 0xF1;
- rcd_buf[2] = 0x4B;
- rcd_buf[3] = 0xF0;
- cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */,
+ 0, /* use rcd_buf as data ara */
+ device);
if (IS_ERR(cqr)) {
- ret = PTR_ERR(cqr);
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+ "Could not allocate RCD request");
+ ret = -ENOMEM;
goto out_error;
}
+ dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buf, lpm);
ret = dasd_sleep_on(cqr);
/*
* on success we update the user input parms
@@ -831,7 +908,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
if (ret)
goto out_error;
- *rcd_buffer_size = ciw->count;
+ *rcd_buffer_size = DASD_ECKD_RCD_DATA_SIZE;
*rcd_buffer = rcd_buf;
return 0;
out_error:
@@ -901,18 +978,18 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
void *conf_data;
int conf_len, conf_data_saved;
int rc;
- __u8 lpm;
+ __u8 lpm, opm;
struct dasd_eckd_private *private;
- struct dasd_eckd_path *path_data;
+ struct dasd_path *path_data;
private = (struct dasd_eckd_private *) device->private;
- path_data = (struct dasd_eckd_path *) &private->path_data;
- path_data->opm = ccw_device_get_path_mask(device->cdev);
+ path_data = &device->path_data;
+ opm = ccw_device_get_path_mask(device->cdev);
lpm = 0x80;
conf_data_saved = 0;
/* get configuration data per operational path */
for (lpm = 0x80; lpm; lpm>>= 1) {
- if (lpm & path_data->opm){
+ if (lpm & opm) {
rc = dasd_eckd_read_conf_lpm(device, &conf_data,
&conf_len, lpm);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
@@ -925,6 +1002,8 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
"No configuration data "
"retrieved");
+ /* no further analysis possible */
+ path_data->opm |= lpm;
continue; /* no error */
}
/* save first valid configuration data */
@@ -948,6 +1027,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
path_data->ppm |= lpm;
break;
}
+ path_data->opm |= lpm;
if (conf_data != private->conf_data)
kfree(conf_data);
}
@@ -955,6 +1035,140 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
return 0;
}
+static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
+{
+ struct dasd_eckd_private *private;
+ int mdc;
+ u32 fcx_max_data;
+
+ private = (struct dasd_eckd_private *) device->private;
+ if (private->fcx_max_data) {
+ mdc = ccw_device_get_mdc(device->cdev, lpm);
+ if ((mdc < 0)) {
+ dev_warn(&device->cdev->dev,
+ "Detecting the maximum data size for zHPF "
+ "requests failed (rc=%d) for a new path %x\n",
+ mdc, lpm);
+ return mdc;
+ }
+ fcx_max_data = mdc * FCX_MAX_DATA_FACTOR;
+ if (fcx_max_data < private->fcx_max_data) {
+ dev_warn(&device->cdev->dev,
+ "The maximum data size for zHPF requests %u "
+ "on a new path %x is below the active maximum "
+ "%u\n", fcx_max_data, lpm,
+ private->fcx_max_data);
+ return -EACCES;
+ }
+ }
+ return 0;
+}
+
+static void do_path_verification_work(struct work_struct *work)
+{
+ struct path_verification_work_data *data;
+ struct dasd_device *device;
+ __u8 lpm, opm, npm, ppm, epm;
+ unsigned long flags;
+ int rc;
+
+ data = container_of(work, struct path_verification_work_data, worker);
+ device = data->device;
+
+ opm = 0;
+ npm = 0;
+ ppm = 0;
+ epm = 0;
+ for (lpm = 0x80; lpm; lpm >>= 1) {
+ if (lpm & data->tbvpm) {
+ memset(data->rcd_buffer, 0, sizeof(data->rcd_buffer));
+ memset(&data->cqr, 0, sizeof(data->cqr));
+ data->cqr.cpaddr = &data->ccw;
+ rc = dasd_eckd_read_conf_immediately(device, &data->cqr,
+ data->rcd_buffer,
+ lpm);
+ if (!rc) {
+ switch (dasd_eckd_path_access(data->rcd_buffer,
+ DASD_ECKD_RCD_DATA_SIZE)) {
+ case 0x02:
+ npm |= lpm;
+ break;
+ case 0x03:
+ ppm |= lpm;
+ break;
+ }
+ opm |= lpm;
+ } else if (rc == -EOPNOTSUPP) {
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "path verification: No configuration "
+ "data retrieved");
+ opm |= lpm;
+ } else if (rc == -EAGAIN) {
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "path verification: device is stopped,"
+ " try again later");
+ epm |= lpm;
+ } else {
+ dev_warn(&device->cdev->dev,
+ "Reading device feature codes failed "
+ "(rc=%d) for new path %x\n", rc, lpm);
+ continue;
+ }
+ if (verify_fcx_max_data(device, lpm)) {
+ opm &= ~lpm;
+ npm &= ~lpm;
+ ppm &= ~lpm;
+ }
+ }
+ }
+ /*
+ * There is a small chance that a path is lost again between
+ * above path verification and the following modification of
+ * the device opm mask. We could avoid that race here by using
+ * yet another path mask, but we rather deal with this unlikely
+ * situation in dasd_start_IO.
+ */
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ if (!device->path_data.opm && opm) {
+ device->path_data.opm = opm;
+ dasd_generic_path_operational(device);
+ } else
+ device->path_data.opm |= opm;
+ device->path_data.npm |= npm;
+ device->path_data.ppm |= ppm;
+ device->path_data.tbvpm |= epm;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+
+ dasd_put_device(device);
+ if (data->isglobal)
+ mutex_unlock(&dasd_path_verification_mutex);
+ else
+ kfree(data);
+}
+
+static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm)
+{
+ struct path_verification_work_data *data;
+
+ data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA);
+ if (!data) {
+ if (mutex_trylock(&dasd_path_verification_mutex)) {
+ data = path_verification_worker;
+ data->isglobal = 1;
+ } else
+ return -ENOMEM;
+ } else {
+ memset(data, 0, sizeof(*data));
+ data->isglobal = 0;
+ }
+ INIT_WORK(&data->worker, do_path_verification_work);
+ dasd_get_device(device);
+ data->device = device;
+ data->tbvpm = lpm;
+ schedule_work(&data->worker);
+ return 0;
+}
+
static int dasd_eckd_read_features(struct dasd_device *device)
{
struct dasd_psf_prssd_data *prssdp;
@@ -1105,6 +1319,37 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
"returned rc=%d", private->uid.ssid, rc);
}
+static u32 get_fcx_max_data(struct dasd_device *device)
+{
+#if defined(CONFIG_64BIT)
+ int tpm, mdc;
+ int fcx_in_css, fcx_in_gneq, fcx_in_features;
+ struct dasd_eckd_private *private;
+
+ if (dasd_nofcx)
+ return 0;
+ /* is transport mode supported? */
+ private = (struct dasd_eckd_private *) device->private;
+ fcx_in_css = css_general_characteristics.fcx;
+ fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
+ fcx_in_features = private->features.feature[40] & 0x80;
+ tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
+
+ if (!tpm)
+ return 0;
+
+ mdc = ccw_device_get_mdc(device->cdev, 0);
+ if (mdc < 0) {
+ dev_warn(&device->cdev->dev, "Detecting the maximum supported"
+ " data size for zHPF requests failed\n");
+ return 0;
+ } else
+ return mdc * FCX_MAX_DATA_FACTOR;
+#else
+ return 0;
+#endif
+}
+
/*
* Check device characteristics.
* If the device is accessible using ECKD discipline, the device is enabled.
@@ -1223,6 +1468,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
else
private->real_cyl = private->rdc_data.no_cyl;
+ private->fcx_max_data = get_fcx_max_data(device);
+
readonly = dasd_device_is_ro(device);
if (readonly)
set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
@@ -1404,6 +1651,13 @@ static int dasd_eckd_end_analysis(struct dasd_block *block)
dasd_sfree_request(init_cqr, device);
}
+ if (device->features & DASD_FEATURE_USERAW) {
+ block->bp_block = DASD_RAW_BLOCKSIZE;
+ blk_per_trk = DASD_RAW_BLOCK_PER_TRACK;
+ block->s2b_shift = 3;
+ goto raw;
+ }
+
if (status == INIT_CQR_UNFORMATTED) {
dev_warn(&device->cdev->dev, "The DASD is not formatted\n");
return -EMEDIUMTYPE;
@@ -1441,6 +1695,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block)
dev_warn(&device->cdev->dev,
"Track 0 has no records following the VTOC\n");
}
+
if (count_area != NULL && count_area->kl == 0) {
/* we found notthing violating our disk layout */
if (dasd_check_blocksize(count_area->dl) == 0)
@@ -1456,6 +1711,8 @@ static int dasd_eckd_end_analysis(struct dasd_block *block)
block->s2b_shift++;
blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
+
+raw:
block->blocks = (private->real_cyl *
private->rdc_data.trk_per_cyl *
blk_per_trk);
@@ -1716,6 +1973,7 @@ static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
if (cqr->block && (cqr->startdev != cqr->block->base)) {
dasd_eckd_reset_ccw_to_base_io(cqr);
cqr->startdev = cqr->block->base;
+ cqr->lpm = cqr->block->base->path_data.opm;
}
};
@@ -1744,9 +2002,9 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
return dasd_default_erp_postaction;
}
-
-static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
- struct irb *irb)
+static void dasd_eckd_check_for_device_change(struct dasd_device *device,
+ struct dasd_ccw_req *cqr,
+ struct irb *irb)
{
char mask;
char *sense = NULL;
@@ -1770,40 +2028,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
/* schedule worker to reload device */
dasd_reload_device(device);
}
-
dasd_generic_handle_state_change(device);
return;
}
- /* summary unit check */
sense = dasd_get_sense(irb);
- if (sense && (sense[7] == 0x0D) &&
+ if (!sense)
+ return;
+
+ /* summary unit check */
+ if ((sense[7] == 0x0D) &&
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
dasd_alias_handle_summary_unit_check(device, irb);
return;
}
/* service information message SIM */
- if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
+ if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) &&
((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
dasd_3990_erp_handle_sim(device, sense);
- dasd_schedule_device_bh(device);
return;
}
- if ((scsw_cc(&irb->scsw) == 1) && !sense &&
- (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
- (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
- (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
- /* fake irb do nothing, they are handled elsewhere */
- dasd_schedule_device_bh(device);
- return;
+ /* loss of device reservation is handled via base devices only
+ * as alias devices may be used with several bases
+ */
+ if (device->block && (sense[7] == 0x3F) &&
+ (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
+ test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
+ if (device->features & DASD_FEATURE_FAILONSLCK)
+ set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
+ clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
+ dev_err(&device->cdev->dev,
+ "The device reservation was lost\n");
}
-
- dasd_schedule_device_bh(device);
- return;
-};
-
+}
static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
struct dasd_device *startdev,
@@ -1984,7 +2243,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
cqr->memdev = startdev;
cqr->block = block;
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
- cqr->lpm = private->path_data.ppm;
+ cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -2161,7 +2420,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
cqr->memdev = startdev;
cqr->block = block;
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
- cqr->lpm = private->path_data.ppm;
+ cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -2326,6 +2585,12 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
struct tidaw *last_tidaw = NULL;
int itcw_op;
size_t itcw_size;
+ u8 tidaw_flags;
+ unsigned int seg_len, part_len, len_to_track_end;
+ unsigned char new_track;
+ sector_t recid, trkid;
+ unsigned int offs;
+ unsigned int count, count_to_trk_end;
basedev = block->base;
private = (struct dasd_eckd_private *) basedev->private;
@@ -2341,12 +2606,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
/* trackbased I/O needs address all memory via TIDAWs,
* not just for 64 bit addresses. This allows us to map
* each segment directly to one tidaw.
+ * In the case of write requests, additional tidaws may
+ * be needed when a segment crosses a track boundary.
*/
trkcount = last_trk - first_trk + 1;
ctidaw = 0;
rq_for_each_segment(bv, req, iter) {
++ctidaw;
}
+ if (rq_data_dir(req) == WRITE)
+ ctidaw += (last_trk - first_trk);
/* Allocate the ccw request. */
itcw_size = itcw_calc_size(0, ctidaw, 0);
@@ -2354,15 +2623,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
if (IS_ERR(cqr))
return cqr;
- cqr->cpmode = 1;
- cqr->startdev = startdev;
- cqr->memdev = startdev;
- cqr->block = block;
- cqr->expires = 100*HZ;
- cqr->buildclk = get_clock();
- cqr->status = DASD_CQR_FILLED;
- cqr->retries = 10;
-
/* transfer length factor: how many bytes to read from the last track */
if (first_trk == last_trk)
tlf = last_offs - first_offs + 1;
@@ -2371,8 +2631,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
tlf *= blksize;
itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0);
+ if (IS_ERR(itcw)) {
+ dasd_sfree_request(cqr, startdev);
+ return ERR_PTR(-EINVAL);
+ }
cqr->cpaddr = itcw_get_tcw(itcw);
-
if (prepare_itcw(itcw, first_trk, last_trk,
cmd, basedev, startdev,
first_offs + 1,
@@ -2385,31 +2648,69 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
dasd_sfree_request(cqr, startdev);
return ERR_PTR(-EAGAIN);
}
-
/*
* A tidaw can address 4k of memory, but must not cross page boundaries
* We can let the block layer handle this by setting
* blk_queue_segment_boundary to page boundaries and
* blk_max_segment_size to page size when setting up the request queue.
+ * For write requests, a TIDAW must not cross track boundaries, because
+ * we have to set the CBC flag on the last tidaw for each track.
*/
- rq_for_each_segment(bv, req, iter) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len);
- if (IS_ERR(last_tidaw))
- return (struct dasd_ccw_req *)last_tidaw;
+ if (rq_data_dir(req) == WRITE) {
+ new_track = 1;
+ recid = first_rec;
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ seg_len = bv->bv_len;
+ while (seg_len) {
+ if (new_track) {
+ trkid = recid;
+ offs = sector_div(trkid, blk_per_trk);
+ count_to_trk_end = blk_per_trk - offs;
+ count = min((last_rec - recid + 1),
+ (sector_t)count_to_trk_end);
+ len_to_track_end = count * blksize;
+ recid += count;
+ new_track = 0;
+ }
+ part_len = min(seg_len, len_to_track_end);
+ seg_len -= part_len;
+ len_to_track_end -= part_len;
+ /* We need to end the tidaw at track end */
+ if (!len_to_track_end) {
+ new_track = 1;
+ tidaw_flags = TIDAW_FLAGS_INSERT_CBC;
+ } else
+ tidaw_flags = 0;
+ last_tidaw = itcw_add_tidaw(itcw, tidaw_flags,
+ dst, part_len);
+ if (IS_ERR(last_tidaw))
+ return ERR_PTR(-EINVAL);
+ dst += part_len;
+ }
+ }
+ } else {
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ last_tidaw = itcw_add_tidaw(itcw, 0x00,
+ dst, bv->bv_len);
+ if (IS_ERR(last_tidaw))
+ return ERR_PTR(-EINVAL);
+ }
}
-
- last_tidaw->flags |= 0x80;
+ last_tidaw->flags |= TIDAW_FLAGS_LAST;
+ last_tidaw->flags &= ~TIDAW_FLAGS_INSERT_CBC;
itcw_finalize(itcw);
if (blk_noretry_request(req) ||
block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ cqr->cpmode = 1;
cqr->startdev = startdev;
cqr->memdev = startdev;
cqr->block = block;
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
- cqr->lpm = private->path_data.ppm;
+ cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -2420,11 +2721,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
struct dasd_block *block,
struct request *req)
{
- int tpm, cmdrtd, cmdwtd;
+ int cmdrtd, cmdwtd;
int use_prefix;
-#if defined(CONFIG_64BIT)
- int fcx_in_css, fcx_in_gneq, fcx_in_features;
-#endif
+ int fcx_multitrack;
struct dasd_eckd_private *private;
struct dasd_device *basedev;
sector_t first_rec, last_rec;
@@ -2432,6 +2731,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
unsigned int first_offs, last_offs;
unsigned int blk_per_trk, blksize;
int cdlspecial;
+ unsigned int data_size;
struct dasd_ccw_req *cqr;
basedev = block->base;
@@ -2450,15 +2750,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
last_offs = sector_div(last_trk, blk_per_trk);
cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk);
- /* is transport mode supported? */
-#if defined(CONFIG_64BIT)
- fcx_in_css = css_general_characteristics.fcx;
- fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
- fcx_in_features = private->features.feature[40] & 0x80;
- tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
-#else
- tpm = 0;
-#endif
+ fcx_multitrack = private->features.feature[40] & 0x20;
+ data_size = blk_rq_bytes(req);
+ /* tpm write request add CBC data on each track boundary */
+ if (rq_data_dir(req) == WRITE)
+ data_size += (last_trk - first_trk) * 4;
/* is read track data and write track data in command mode supported? */
cmdrtd = private->features.feature[9] & 0x20;
@@ -2468,13 +2764,15 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
cqr = NULL;
if (cdlspecial || dasd_page_cache) {
/* do nothing, just fall through to the cmd mode single case */
- } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) {
+ } else if ((data_size <= private->fcx_max_data)
+ && (fcx_multitrack || (first_trk == last_trk))) {
cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req,
first_rec, last_rec,
first_trk, last_trk,
first_offs, last_offs,
blk_per_trk, blksize);
- if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
+ if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) &&
+ (PTR_ERR(cqr) != -ENOMEM))
cqr = NULL;
} else if (use_prefix &&
(((rq_data_dir(req) == READ) && cmdrtd) ||
@@ -2484,7 +2782,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
first_trk, last_trk,
first_offs, last_offs,
blk_per_trk, blksize);
- if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
+ if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) &&
+ (PTR_ERR(cqr) != -ENOMEM))
cqr = NULL;
}
if (!cqr)
@@ -2496,6 +2795,135 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
return cqr;
}
+static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
+ struct dasd_block *block,
+ struct request *req)
+{
+ struct dasd_eckd_private *private;
+ unsigned long *idaws;
+ struct dasd_device *basedev;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ struct req_iterator iter;
+ struct bio_vec *bv;
+ char *dst;
+ unsigned char cmd;
+ unsigned int trkcount;
+ unsigned int seg_len, len_to_track_end;
+ unsigned int first_offs;
+ unsigned int cidaw, cplength, datasize;
+ sector_t first_trk, last_trk;
+ unsigned int pfx_datasize;
+
+ /*
+ * raw track access needs to be mutiple of 64k and on 64k boundary
+ */
+ if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) {
+ cqr = ERR_PTR(-EINVAL);
+ goto out;
+ }
+ if (((blk_rq_pos(req) + blk_rq_sectors(req)) %
+ DASD_RAW_SECTORS_PER_TRACK) != 0) {
+ cqr = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK;
+ last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) /
+ DASD_RAW_SECTORS_PER_TRACK;
+ trkcount = last_trk - first_trk + 1;
+ first_offs = 0;
+ basedev = block->base;
+ private = (struct dasd_eckd_private *) basedev->private;
+
+ if (rq_data_dir(req) == READ)
+ cmd = DASD_ECKD_CCW_READ_TRACK;
+ else if (rq_data_dir(req) == WRITE)
+ cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK;
+ else {
+ cqr = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ /*
+ * Raw track based I/O needs IDAWs for each page,
+ * and not just for 64 bit addresses.
+ */
+ cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK;
+
+ /* 1x prefix + one read/write ccw per track */
+ cplength = 1 + trkcount;
+
+ /*
+ * struct PFX_eckd_data has up to 2 byte as extended parameter
+ * this is needed for write full track and has to be mentioned
+ * seperately
+ * add 8 instead of 2 to keep 8 byte boundary
+ */
+ pfx_datasize = sizeof(struct PFX_eckd_data) + 8;
+
+ datasize = pfx_datasize + cidaw * sizeof(unsigned long long);
+
+ /* Allocate the ccw request. */
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
+ datasize, startdev);
+ if (IS_ERR(cqr))
+ goto out;
+ ccw = cqr->cpaddr;
+
+ if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd,
+ basedev, startdev, 1 /* format */, first_offs + 1,
+ trkcount, 0, 0) == -EAGAIN) {
+ /* Clock not in sync and XRC is enabled.
+ * Try again later.
+ */
+ dasd_sfree_request(cqr, startdev);
+ cqr = ERR_PTR(-EAGAIN);
+ goto out;
+ }
+
+ idaws = (unsigned long *)(cqr->data + pfx_datasize);
+
+ len_to_track_end = 0;
+
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ seg_len = bv->bv_len;
+ if (!len_to_track_end) {
+ ccw[-1].flags |= CCW_FLAG_CC;
+ ccw->cmd_code = cmd;
+ /* maximum 3390 track size */
+ ccw->count = 57326;
+ /* 64k map to one track */
+ len_to_track_end = 65536;
+ ccw->cda = (__u32)(addr_t)idaws;
+ ccw->flags |= CCW_FLAG_IDA;
+ ccw->flags |= CCW_FLAG_SLI;
+ ccw++;
+ }
+ len_to_track_end -= seg_len;
+ idaws = idal_create_words(idaws, dst, seg_len);
+ }
+
+ if (blk_noretry_request(req) ||
+ block->base->features & DASD_FEATURE_FAILFAST)
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ cqr->startdev = startdev;
+ cqr->memdev = startdev;
+ cqr->block = block;
+ cqr->expires = startdev->default_expires * HZ;
+ cqr->lpm = startdev->path_data.ppm;
+ cqr->retries = 256;
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+
+ if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
+ cqr = NULL;
+out:
+ return cqr;
+}
+
+
static int
dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
@@ -2600,7 +3028,10 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
private->count++;
- cqr = dasd_eckd_build_cp(startdev, block, req);
+ if ((base->features & DASD_FEATURE_USERAW))
+ cqr = dasd_raw_build_cp(startdev, block, req);
+ else
+ cqr = dasd_eckd_build_cp(startdev, block, req);
if (IS_ERR(cqr))
private->count--;
spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
@@ -2688,6 +3119,8 @@ dasd_eckd_release(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -2741,6 +3174,8 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -2793,6 +3228,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -2845,6 +3282,7 @@ static int dasd_eckd_snid(struct dasd_device *device,
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
cqr->retries = 5;
cqr->expires = 10 * HZ;
cqr->buildclk = get_clock();
@@ -3279,10 +3717,8 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
{
char *page;
int len, sl, sct, residual;
-
struct tsb *tsb;
- u8 *sense;
-
+ u8 *sense, *rcq;
page = (char *) get_zeroed_page(GFP_ATOMIC);
if (page == NULL) {
@@ -3348,12 +3784,15 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
case 2: /* ts_ddpc */
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc);
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " tsb->tsa.ddpc.rcq: ");
- for (sl = 0; sl < 16; sl++) {
+ for (sl = 0; sl < 2; sl++) {
+ len += sprintf(page + len,
+ KERN_ERR PRINTK_HEADER
+ " tsb->tsa.ddpc.rcq %2d-%2d: ",
+ (8 * sl), ((8 * sl) + 7));
+ rcq = tsb->tsa.ddpc.rcq;
for (sct = 0; sct < 8; sct++) {
len += sprintf(page + len, " %02x",
- tsb->tsa.ddpc.rcq[sl]);
+ rcq[8 * sl + sct]);
}
len += sprintf(page + len, "\n");
}
@@ -3550,6 +3989,7 @@ static struct ccw_driver dasd_eckd_driver = {
.set_offline = dasd_generic_set_offline,
.set_online = dasd_eckd_set_online,
.notify = dasd_generic_notify,
+ .path_event = dasd_generic_path_event,
.freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device,
@@ -3573,10 +4013,11 @@ static struct dasd_discipline dasd_eckd_discipline = {
.owner = THIS_MODULE,
.name = "ECKD",
.ebcname = "ECKD",
- .max_blocks = 240,
+ .max_blocks = 190,
.check_device = dasd_eckd_check_characteristics,
.uncheck_device = dasd_eckd_uncheck_device,
.do_analysis = dasd_eckd_do_analysis,
+ .verify_path = dasd_eckd_verify_path,
.ready_to_online = dasd_eckd_ready_to_online,
.online_to_ready = dasd_eckd_online_to_ready,
.fill_geometry = dasd_eckd_fill_geometry,
@@ -3586,7 +4027,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.format_device = dasd_eckd_format_device,
.erp_action = dasd_eckd_erp_action,
.erp_postaction = dasd_eckd_erp_postaction,
- .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+ .check_for_device_change = dasd_eckd_check_for_device_change,
.build_cp = dasd_eckd_build_alias_cp,
.free_cp = dasd_eckd_free_alias_cp,
.dump_sense = dasd_eckd_dump_sense,
@@ -3609,11 +4050,19 @@ dasd_eckd_init(void)
GFP_KERNEL | GFP_DMA);
if (!dasd_reserve_req)
return -ENOMEM;
+ path_verification_worker = kmalloc(sizeof(*path_verification_worker),
+ GFP_KERNEL | GFP_DMA);
+ if (!path_verification_worker) {
+ kfree(dasd_reserve_req);
+ return -ENOMEM;
+ }
ret = ccw_driver_register(&dasd_eckd_driver);
if (!ret)
wait_for_device_probe();
- else
+ else {
+ kfree(path_verification_worker);
kfree(dasd_reserve_req);
+ }
return ret;
}
@@ -3621,6 +4070,7 @@ static void __exit
dasd_eckd_cleanup(void)
{
ccw_driver_unregister(&dasd_eckd_driver);
+ kfree(path_verification_worker);
kfree(dasd_reserve_req);
}
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 12097c24f2f5..4a688a873a77 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -37,14 +37,17 @@
#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d
#define DASD_ECKD_CCW_READ_KD_MT 0x8e
#define DASD_ECKD_CCW_RELEASE 0x94
+#define DASD_ECKD_CCW_WRITE_FULL_TRACK 0x95
#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
#define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5
#define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6
#define DASD_ECKD_CCW_RESERVE 0xB4
+#define DASD_ECKD_CCW_READ_TRACK 0xDE
#define DASD_ECKD_CCW_PFX 0xE7
#define DASD_ECKD_CCW_PFX_READ 0xEA
#define DASD_ECKD_CCW_RSCK 0xF9
+#define DASD_ECKD_CCW_RCD 0xFA
/*
* Perform Subsystem Function / Sub-Orders
@@ -57,6 +60,11 @@
*/
#define LV_COMPAT_CYL 0xFFFE
+
+#define FCX_MAX_DATA_FACTOR 65536
+#define DASD_ECKD_RCD_DATA_SIZE 256
+
+
/*****************************************************************************
* SECTION: Type Definitions
****************************************************************************/
@@ -331,12 +339,6 @@ struct dasd_gneq {
__u8 reserved2[22];
} __attribute__ ((packed));
-struct dasd_eckd_path {
- __u8 opm;
- __u8 ppm;
- __u8 npm;
-};
-
struct dasd_rssd_features {
char feature[256];
} __attribute__((packed));
@@ -442,7 +444,6 @@ struct dasd_eckd_private {
struct vd_sneq *vdsneq;
struct dasd_gneq *gneq;
- struct dasd_eckd_path path_data;
struct eckd_count count_area[5];
int init_cqr_status;
int uses_cdl;
@@ -455,6 +456,8 @@ struct dasd_eckd_private {
struct alias_pav_group *pavgroup;
struct alias_lcu *lcu;
int count;
+
+ u32 fcx_max_data;
};
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index c71d89dba302..77f778b7b070 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -17,7 +17,6 @@
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include <linux/err.h>
#include <linux/slab.h>
@@ -474,6 +473,7 @@ int dasd_eer_enable(struct dasd_device *device)
cqr->retries = 255;
cqr->expires = 10 * HZ;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_SNSS;
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 7656384a811d..0eafe2e421e7 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -96,7 +96,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_DEBUG, device,
"default ERP called (%i retries left)",
cqr->retries);
- cqr->lpm = LPM_ANYPATH;
+ if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
+ cqr->lpm = device->path_data.opm;
cqr->status = DASD_CQR_FILLED;
} else {
pr_err("%s: default ERP has run out of retries and failed\n",
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index bec5486e0e6d..be89b3a893da 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -73,6 +73,7 @@ static struct ccw_driver dasd_fba_driver = {
.set_offline = dasd_generic_set_offline,
.set_online = dasd_fba_set_online,
.notify = dasd_generic_notify,
+ .path_event = dasd_generic_path_event,
.freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device,
@@ -164,6 +165,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
}
device->default_expires = DASD_EXPIRES;
+ device->path_data.opm = LPM_ANYPATH;
readonly = dasd_device_is_ro(device);
if (readonly)
@@ -231,24 +233,16 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
return NULL;
}
-static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
- struct irb *irb)
+static void dasd_fba_check_for_device_change(struct dasd_device *device,
+ struct dasd_ccw_req *cqr,
+ struct irb *irb)
{
char mask;
/* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
- if ((irb->scsw.cmd.dstat & mask) == mask) {
+ if ((irb->scsw.cmd.dstat & mask) == mask)
dasd_generic_handle_state_change(device);
- return;
- }
-
- /* check for unsolicited interrupts */
- DBF_DEV_EVENT(DBF_WARNING, device, "%s",
- "unsolicited interrupt received");
- device->discipline->dump_sense_dbf(device, irb, "unsolicited");
- dasd_schedule_device_bh(device);
- return;
};
static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
@@ -596,13 +590,14 @@ static struct dasd_discipline dasd_fba_discipline = {
.max_blocks = 96,
.check_device = dasd_fba_check_characteristics,
.do_analysis = dasd_fba_do_analysis,
+ .verify_path = dasd_generic_verify_path,
.fill_geometry = dasd_fba_fill_geometry,
.start_IO = dasd_start_IO,
.term_IO = dasd_term_IO,
.handle_terminated_request = dasd_fba_handle_terminated_request,
.erp_action = dasd_fba_erp_action,
.erp_postaction = dasd_fba_erp_postaction,
- .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
+ .check_for_device_change = dasd_fba_check_for_device_change,
.build_cp = dasd_fba_build_cp,
.free_cp = dasd_fba_free_cp,
.dump_sense = dasd_fba_dump_sense,
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 30a1ca3d08b7..5505bc07e1e7 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -103,7 +103,7 @@ int dasd_scan_partitions(struct dasd_block *block)
struct block_device *bdev;
bdev = bdget_disk(block->gdp, 0);
- if (!bdev || blkdev_get(bdev, FMODE_READ) < 0)
+ if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0)
return -ENODEV;
/*
* See fs/partition/check.c:register_disk,rescan_partitions
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 500678d7116c..df9f6999411d 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -231,6 +231,11 @@ struct dasd_ccw_req {
/* per dasd_ccw_req flags */
#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */
#define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */
+#define DASD_CQR_VERIFY_PATH 2 /* path verification request */
+#define DASD_CQR_ALLOW_SLOCK 3 /* Try this request even when lock was
+ * stolen. Should not be combined with
+ * DASD_CQR_FLAGS_USE_ERP
+ */
/* Signature for error recovery functions. */
typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
@@ -287,6 +292,14 @@ struct dasd_discipline {
int (*do_analysis) (struct dasd_block *);
/*
+ * This function is called, when new paths become available.
+ * Disciplins may use this callback to do necessary setup work,
+ * e.g. verify that new path is compatible with the current
+ * configuration.
+ */
+ int (*verify_path)(struct dasd_device *, __u8);
+
+ /*
* Last things to do when a device is set online, and first things
* when it is set offline.
*/
@@ -325,9 +338,9 @@ struct dasd_discipline {
void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
struct irb *);
void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *);
-
- void (*handle_unsolicited_interrupt) (struct dasd_device *,
- struct irb *);
+ void (*check_for_device_change) (struct dasd_device *,
+ struct dasd_ccw_req *,
+ struct irb *);
/* i/o control functions. */
int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
@@ -362,6 +375,13 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
#define DASD_EER_STATECHANGE 3
#define DASD_EER_PPRCSUSPEND 4
+struct dasd_path {
+ __u8 opm;
+ __u8 tbvpm;
+ __u8 ppm;
+ __u8 npm;
+};
+
struct dasd_device {
/* Block device stuff. */
struct dasd_block *block;
@@ -377,6 +397,7 @@ struct dasd_device {
struct dasd_discipline *discipline;
struct dasd_discipline *base_discipline;
char *private;
+ struct dasd_path path_data;
/* Device state and target state. */
int state, target;
@@ -456,6 +477,9 @@ struct dasd_block {
* confuse this with the user specified
* read-only feature.
*/
+#define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */
+#define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */
+
void dasd_put_device_wake(struct dasd_device *);
@@ -620,10 +644,15 @@ void dasd_generic_remove (struct ccw_device *cdev);
int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
+int dasd_generic_last_path_gone(struct dasd_device *);
+int dasd_generic_path_operational(struct dasd_device *);
+
void dasd_generic_handle_state_change(struct dasd_device *);
int dasd_generic_pm_freeze(struct ccw_device *);
int dasd_generic_restore_device(struct ccw_device *);
enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
+void dasd_generic_path_event(struct ccw_device *, int *);
+int dasd_generic_verify_path(struct dasd_device *, __u8);
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
char *dasd_get_sense(struct irb *);
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 40834f18754c..dcee3c5c8954 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -2,76 +2,85 @@ comment "S/390 character device drivers"
depends on S390
config TN3270
- tristate "Support for locally attached 3270 terminals"
+ def_tristate y
+ prompt "Support for locally attached 3270 terminals"
depends on CCW
help
Include support for IBM 3270 terminals.
config TN3270_TTY
- tristate "Support for tty input/output on 3270 terminals"
+ def_tristate y
+ prompt "Support for tty input/output on 3270 terminals"
depends on TN3270
help
Include support for using an IBM 3270 terminal as a Linux tty.
config TN3270_FS
- tristate "Support for fullscreen applications on 3270 terminals"
+ def_tristate m
+ prompt "Support for fullscreen applications on 3270 terminals"
depends on TN3270
help
Include support for fullscreen applications on an IBM 3270 terminal.
config TN3270_CONSOLE
- bool "Support for console on 3270 terminal"
+ def_bool y
+ prompt "Support for console on 3270 terminal"
depends on TN3270=y && TN3270_TTY=y
help
Include support for using an IBM 3270 terminal as a Linux system
console. Available only if 3270 support is compiled in statically.
config TN3215
- bool "Support for 3215 line mode terminal"
+ def_bool y
+ prompt "Support for 3215 line mode terminal"
depends on CCW
help
Include support for IBM 3215 line-mode terminals.
config TN3215_CONSOLE
- bool "Support for console on 3215 line mode terminal"
+ def_bool y
+ prompt "Support for console on 3215 line mode terminal"
depends on TN3215
help
Include support for using an IBM 3215 line-mode terminal as a
Linux system console.
config CCW_CONSOLE
- bool
- depends on TN3215_CONSOLE || TN3270_CONSOLE
- default y
+ def_bool y if TN3215_CONSOLE || TN3270_CONSOLE
config SCLP_TTY
- bool "Support for SCLP line mode terminal"
+ def_bool y
+ prompt "Support for SCLP line mode terminal"
depends on S390
help
Include support for IBM SCLP line-mode terminals.
config SCLP_CONSOLE
- bool "Support for console on SCLP line mode terminal"
+ def_bool y
+ prompt "Support for console on SCLP line mode terminal"
depends on SCLP_TTY
help
Include support for using an IBM HWC line-mode terminal as the Linux
system console.
config SCLP_VT220_TTY
- bool "Support for SCLP VT220-compatible terminal"
+ def_bool y
+ prompt "Support for SCLP VT220-compatible terminal"
depends on S390
help
Include support for an IBM SCLP VT220-compatible terminal.
config SCLP_VT220_CONSOLE
- bool "Support for console on SCLP VT220-compatible terminal"
+ def_bool y
+ prompt "Support for console on SCLP VT220-compatible terminal"
depends on SCLP_VT220_TTY
help
Include support for using an IBM SCLP VT220-compatible terminal as a
Linux system console.
config SCLP_CPI
- tristate "Control-Program Identification"
+ def_tristate m
+ prompt "Control-Program Identification"
depends on S390
help
This option enables the hardware console interface for system
@@ -83,7 +92,8 @@ config SCLP_CPI
need this feature and intend to run your kernel in LPAR.
config SCLP_ASYNC
- tristate "Support for Call Home via Asynchronous SCLP Records"
+ def_tristate m
+ prompt "Support for Call Home via Asynchronous SCLP Records"
depends on S390
help
This option enables the call home function, which is able to inform
@@ -93,7 +103,8 @@ config SCLP_ASYNC
need this feature and intend to run your kernel in LPAR.
config S390_TAPE
- tristate "S/390 tape device support"
+ def_tristate m
+ prompt "S/390 tape device support"
depends on CCW
help
Select this option if you want to access channel-attached tape
@@ -109,7 +120,8 @@ comment "S/390 tape interface support"
depends on S390_TAPE
config S390_TAPE_BLOCK
- bool "Support for tape block devices"
+ def_bool y
+ prompt "Support for tape block devices"
depends on S390_TAPE && BLOCK
help
Select this option if you want to access your channel-attached tape
@@ -123,7 +135,8 @@ comment "S/390 tape hardware support"
depends on S390_TAPE
config S390_TAPE_34XX
- tristate "Support for 3480/3490 tape hardware"
+ def_tristate m
+ prompt "Support for 3480/3490 tape hardware"
depends on S390_TAPE
help
Select this option if you want to access IBM 3480/3490 magnetic
@@ -131,7 +144,8 @@ config S390_TAPE_34XX
It is safe to say "Y" here.
config S390_TAPE_3590
- tristate "Support for 3590 tape hardware"
+ def_tristate m
+ prompt "Support for 3590 tape hardware"
depends on S390_TAPE
help
Select this option if you want to access IBM 3590 magnetic
@@ -139,7 +153,8 @@ config S390_TAPE_3590
It is safe to say "Y" here.
config VMLOGRDR
- tristate "Support for the z/VM recording system services (VM only)"
+ def_tristate m
+ prompt "Support for the z/VM recording system services (VM only)"
depends on IUCV
help
Select this option if you want to be able to receive records collected
@@ -148,29 +163,31 @@ config VMLOGRDR
This driver depends on the IUCV support driver.
config VMCP
- bool "Support for the z/VM CP interface"
+ def_bool y
+ prompt "Support for the z/VM CP interface"
depends on S390
help
Select this option if you want to be able to interact with the control
program on z/VM
config MONREADER
- tristate "API for reading z/VM monitor service records"
+ def_tristate m
+ prompt "API for reading z/VM monitor service records"
depends on IUCV
help
Character device driver for reading z/VM monitor service records
config MONWRITER
- tristate "API for writing z/VM monitor service records"
+ def_tristate m
+ prompt "API for writing z/VM monitor service records"
depends on S390
- default "m"
help
Character device driver for writing z/VM monitor service records
config S390_VMUR
- tristate "z/VM unit record device driver"
+ def_tristate m
+ prompt "z/VM unit record device driver"
depends on S390
- default "m"
help
Character device driver for z/VM reader, puncher and printer.
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 59ec073724bf..3fb4335d491d 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -9,6 +9,7 @@
* Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu>
*/
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
@@ -361,6 +362,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
int cstat, dstat;
int count;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_C15]++;
raw = dev_get_drvdata(&cdev->dev);
req = (struct raw3215_req *) intparm;
cstat = irb->scsw.cmd.cstat;
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index eb28fb01a38a..f6489eb7e976 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -14,7 +14,6 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <asm/compat.h>
#include <asm/ccwdev.h>
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 2a4c566456e7..96ba2fd1c8ad 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -7,6 +7,7 @@
* Copyright IBM Corp. 2003, 2009
*/
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -329,6 +330,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct raw3270_request *rq;
int rc;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_C70]++;
rp = dev_get_drvdata(&cdev->dev);
if (!rp)
return;
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 35cc4686b99b..b76c61f82485 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -7,6 +7,7 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/spinlock.h>
@@ -18,16 +19,14 @@
#include <linux/suspend.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
-#include <asm/types.h>
#include <asm/s390_ext.h>
+#include <asm/types.h>
+#include <asm/irq.h>
#include "sclp.h"
#define SCLP_HEADER "sclp: "
-/* Structure for register_early_external_interrupt. */
-static ext_int_info_t ext_int_info_hwc;
-
/* Lock to protect internal data consistency. */
static DEFINE_SPINLOCK(sclp_lock);
@@ -402,6 +401,7 @@ static void sclp_interrupt_handler(unsigned int ext_int_code,
u32 finished_sccb;
u32 evbuf_pending;
+ kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++;
spin_lock(&sclp_lock);
finished_sccb = param32 & 0xfffffff8;
evbuf_pending = param32 & 0x3;
@@ -824,6 +824,7 @@ static void sclp_check_handler(unsigned int ext_int_code,
{
u32 finished_sccb;
+ kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++;
finished_sccb = param32 & 0xfffffff8;
/* Is this the interrupt we are waiting for? */
if (finished_sccb == 0)
@@ -866,8 +867,7 @@ sclp_check_interface(void)
spin_lock_irqsave(&sclp_lock, flags);
/* Prepare init mask command */
- rc = register_early_external_interrupt(0x2401, sclp_check_handler,
- &ext_int_info_hwc);
+ rc = register_external_interrupt(0x2401, sclp_check_handler);
if (rc) {
spin_unlock_irqrestore(&sclp_lock, flags);
return rc;
@@ -900,8 +900,7 @@ sclp_check_interface(void)
} else
rc = -EBUSY;
}
- unregister_early_external_interrupt(0x2401, sclp_check_handler,
- &ext_int_info_hwc);
+ unregister_external_interrupt(0x2401, sclp_check_handler);
spin_unlock_irqrestore(&sclp_lock, flags);
return rc;
}
@@ -1064,8 +1063,7 @@ sclp_init(void)
if (rc)
goto fail_init_state_uninitialized;
/* Register interrupt handler */
- rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler,
- &ext_int_info_hwc);
+ rc = register_external_interrupt(0x2401, sclp_interrupt_handler);
if (rc)
goto fail_unregister_reboot_notifier;
sclp_init_state = sclp_init_state_initialized;
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index b497afe061cc..16e232a99fb7 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -33,6 +33,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
int cpu;
struct sys_device *sysdev;
+ s390_adjust_jiffies();
pr_warning("cpu capability changed.\n");
get_online_cpus();
for_each_online_cpu(cpu) {
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index deff2c3361e4..fbe361fcd2c0 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -24,6 +24,8 @@
#include "tape_std.h"
#include "tape_3590.h"
+static struct workqueue_struct *tape_3590_wq;
+
/*
* Pointer to debug area.
*/
@@ -613,7 +615,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
p->device = tape_get_device(device);
p->op = op;
- schedule_work(&p->work);
+ queue_work(tape_3590_wq, &p->work);
return 0;
}
@@ -1629,7 +1631,7 @@ fail_kmalloc:
static void
tape_3590_cleanup_device(struct tape_device *device)
{
- flush_scheduled_work();
+ flush_workqueue(tape_3590_wq);
tape_std_unassign(device);
kfree(device->discdata);
@@ -1733,11 +1735,17 @@ tape_3590_init(void)
#endif
DBF_EVENT(3, "3590 init\n");
+
+ tape_3590_wq = alloc_workqueue("tape_3590", 0, 0);
+ if (!tape_3590_wq)
+ return -ENOMEM;
+
/* Register driver for 3590 tapes. */
rc = ccw_driver_register(&tape_3590_driver);
- if (rc)
+ if (rc) {
+ destroy_workqueue(tape_3590_wq);
DBF_EVENT(3, "3590 init failed\n");
- else
+ } else
DBF_EVENT(3, "3590 registered\n");
return rc;
}
@@ -1746,7 +1754,7 @@ static void
tape_3590_exit(void)
{
ccw_driver_unregister(&tape_3590_driver);
-
+ destroy_workqueue(tape_3590_wq);
debug_unregister(TAPE_DBF_AREA);
}
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index f0fa9ca5cb2c..55d2d0f4eabc 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -264,7 +264,7 @@ cleanup_queue:
void
tapeblock_cleanup_device(struct tape_device *device)
{
- flush_scheduled_work();
+ flush_work_sync(&device->blk_data.requeue_task);
tape_put_device(device);
if (!device->blk_data.disk) {
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 883e2db02bd3..e090a307fdee 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -17,7 +17,6 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/mtio.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <asm/uaccess.h>
diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h
index 707b7f48c232..9e32780c317f 100644
--- a/drivers/s390/char/tape_class.h
+++ b/drivers/s390/char/tape_class.h
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 6c408670e08d..7978a0adeaf3 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -14,6 +14,7 @@
#define KMSG_COMPONENT "tape"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/init.h> // for kernel parameters
#include <linux/kmod.h> // for requesting modules
@@ -209,29 +210,79 @@ tape_state_set(struct tape_device *device, enum tape_state newstate)
wake_up(&device->state_change_wq);
}
+struct tape_med_state_work_data {
+ struct tape_device *device;
+ enum tape_medium_state state;
+ struct work_struct work;
+};
+
+static void
+tape_med_state_work_handler(struct work_struct *work)
+{
+ static char env_state_loaded[] = "MEDIUM_STATE=LOADED";
+ static char env_state_unloaded[] = "MEDIUM_STATE=UNLOADED";
+ struct tape_med_state_work_data *p =
+ container_of(work, struct tape_med_state_work_data, work);
+ struct tape_device *device = p->device;
+ char *envp[] = { NULL, NULL };
+
+ switch (p->state) {
+ case MS_UNLOADED:
+ pr_info("%s: The tape cartridge has been successfully "
+ "unloaded\n", dev_name(&device->cdev->dev));
+ envp[0] = env_state_unloaded;
+ kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+ break;
+ case MS_LOADED:
+ pr_info("%s: A tape cartridge has been mounted\n",
+ dev_name(&device->cdev->dev));
+ envp[0] = env_state_loaded;
+ kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+ break;
+ default:
+ break;
+ }
+ tape_put_device(device);
+ kfree(p);
+}
+
+static void
+tape_med_state_work(struct tape_device *device, enum tape_medium_state state)
+{
+ struct tape_med_state_work_data *p;
+
+ p = kzalloc(sizeof(*p), GFP_ATOMIC);
+ if (p) {
+ INIT_WORK(&p->work, tape_med_state_work_handler);
+ p->device = tape_get_device(device);
+ p->state = state;
+ schedule_work(&p->work);
+ }
+}
+
void
tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
{
- if (device->medium_state == newstate)
+ enum tape_medium_state oldstate;
+
+ oldstate = device->medium_state;
+ if (oldstate == newstate)
return;
+ device->medium_state = newstate;
switch(newstate){
case MS_UNLOADED:
device->tape_generic_status |= GMT_DR_OPEN(~0);
- if (device->medium_state == MS_LOADED)
- pr_info("%s: The tape cartridge has been successfully "
- "unloaded\n", dev_name(&device->cdev->dev));
+ if (oldstate == MS_LOADED)
+ tape_med_state_work(device, MS_UNLOADED);
break;
case MS_LOADED:
device->tape_generic_status &= ~GMT_DR_OPEN(~0);
- if (device->medium_state == MS_UNLOADED)
- pr_info("%s: A tape cartridge has been mounted\n",
- dev_name(&device->cdev->dev));
+ if (oldstate == MS_UNLOADED)
+ tape_med_state_work(device, MS_LOADED);
break;
default:
- // print nothing
break;
}
- device->medium_state = newstate;
wake_up(&device->state_change_wq);
}
@@ -1064,6 +1115,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct tape_request *request;
int rc;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_TAP]++;
device = dev_get_drvdata(&cdev->dev);
if (device == NULL) {
return;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 9f661426e4a1..c837d7419a6a 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -30,7 +30,6 @@
#include <linux/kmod.h>
#include <linux/cdev.h>
#include <linux/device.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
MODULE_AUTHOR
@@ -249,27 +248,25 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
char cp_command[80];
char cp_response[160];
char *onoff, *qid_string;
+ int rc;
- memset(cp_command, 0x00, sizeof(cp_command));
- memset(cp_response, 0x00, sizeof(cp_response));
-
- onoff = ((action == 1) ? "ON" : "OFF");
+ onoff = ((action == 1) ? "ON" : "OFF");
qid_string = ((recording_class_AB == 1) ? " QID * " : "");
- /*
+ /*
* The recording commands needs to be called with option QID
* for guests that have previlege classes A or B.
* Purging has to be done as separate step, because recording
* can't be switched on as long as records are on the queue.
* Doing both at the same time doesn't work.
*/
-
- if (purge) {
+ if (purge && (action == 1)) {
+ memset(cp_command, 0x00, sizeof(cp_command));
+ memset(cp_response, 0x00, sizeof(cp_response));
snprintf(cp_command, sizeof(cp_command),
"RECORDING %s PURGE %s",
logptr->recording_name,
qid_string);
-
cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
}
@@ -279,19 +276,33 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
logptr->recording_name,
onoff,
qid_string);
-
cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
/* The recording command will usually answer with 'Command complete'
* on success, but when the specific service was never connected
* before then there might be an additional informational message
* 'HCPCRC8072I Recording entry not found' before the
- * 'Command complete'. So I use strstr rather then the strncmp.
+ * 'Command complete'. So I use strstr rather then the strncmp.
*/
if (strstr(cp_response,"Command complete"))
- return 0;
+ rc = 0;
else
- return -EIO;
+ rc = -EIO;
+ /*
+ * If we turn recording off, we have to purge any remaining records
+ * afterwards, as a large number of queued records may impact z/VM
+ * performance.
+ */
+ if (purge && (action == 0)) {
+ memset(cp_command, 0x00, sizeof(cp_command));
+ memset(cp_response, 0x00, sizeof(cp_response));
+ snprintf(cp_command, sizeof(cp_command),
+ "RECORDING %s PURGE %s",
+ logptr->recording_name,
+ qid_string);
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
+ }
+ return rc;
}
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index 1de672f21037..caef1757341d 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -11,9 +11,9 @@
#define KMSG_COMPONENT "vmur"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/cdev.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
@@ -303,6 +303,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
{
struct urdev *urd;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_VMR]++;
TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
irb->scsw.cmd.count);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 97b25d68e3e7..2864581d8ecb 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -67,6 +67,27 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
}
/*
+ * Remove references from ccw devices to ccw group device and from
+ * ccw group device to ccw devices.
+ */
+static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev)
+{
+ struct ccw_device *cdev;
+ int i;
+
+ for (i = 0; i < gdev->count; i++) {
+ cdev = gdev->cdev[i];
+ if (!cdev)
+ continue;
+ spin_lock_irq(cdev->ccwlock);
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irq(cdev->ccwlock);
+ gdev->cdev[i] = NULL;
+ put_device(&cdev->dev);
+ }
+}
+
+/*
* Provide an 'ungroup' attribute so the user can remove group devices no
* longer needed or accidentially created. Saves memory :)
*/
@@ -78,6 +99,7 @@ static void ccwgroup_ungroup_callback(struct device *dev)
if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
device_unregister(dev);
+ __ccwgroup_remove_cdev_refs(gdev);
}
mutex_unlock(&gdev->reg_mutex);
}
@@ -116,21 +138,7 @@ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
static void
ccwgroup_release (struct device *dev)
{
- struct ccwgroup_device *gdev;
- int i;
-
- gdev = to_ccwgroupdev(dev);
-
- for (i = 0; i < gdev->count; i++) {
- if (gdev->cdev[i]) {
- spin_lock_irq(gdev->cdev[i]->ccwlock);
- if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
- dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
- spin_unlock_irq(gdev->cdev[i]->ccwlock);
- put_device(&gdev->cdev[i]->dev);
- }
- }
- kfree(gdev);
+ kfree(to_ccwgroupdev(dev));
}
static int
@@ -639,6 +647,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
mutex_lock(&gdev->reg_mutex);
__ccwgroup_remove_symlinks(gdev);
device_unregister(dev);
+ __ccwgroup_remove_cdev_refs(gdev);
mutex_unlock(&gdev->reg_mutex);
put_device(dev);
}
@@ -660,25 +669,6 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
return 0;
}
-static struct ccwgroup_device *
-__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
-{
- struct ccwgroup_device *gdev;
-
- gdev = dev_get_drvdata(&cdev->dev);
- if (gdev) {
- if (get_device(&gdev->dev)) {
- mutex_lock(&gdev->reg_mutex);
- if (device_is_registered(&gdev->dev))
- return gdev;
- mutex_unlock(&gdev->reg_mutex);
- put_device(&gdev->dev);
- }
- return NULL;
- }
- return NULL;
-}
-
/**
* ccwgroup_remove_ccwdev() - remove function for slave devices
* @cdev: ccw device to be removed
@@ -694,13 +684,25 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
/* Ignore offlining errors, device is gone anyway. */
ccw_device_set_offline(cdev);
/* If one of its devices is gone, the whole group is done for. */
- gdev = __ccwgroup_get_gdev_by_cdev(cdev);
- if (gdev) {
+ spin_lock_irq(cdev->ccwlock);
+ gdev = dev_get_drvdata(&cdev->dev);
+ if (!gdev) {
+ spin_unlock_irq(cdev->ccwlock);
+ return;
+ }
+ /* Get ccwgroup device reference for local processing. */
+ get_device(&gdev->dev);
+ spin_unlock_irq(cdev->ccwlock);
+ /* Unregister group device. */
+ mutex_lock(&gdev->reg_mutex);
+ if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev);
- mutex_unlock(&gdev->reg_mutex);
- put_device(&gdev->dev);
+ __ccwgroup_remove_cdev_refs(gdev);
}
+ mutex_unlock(&gdev->reg_mutex);
+ /* Release ccwgroup device reference for local processing. */
+ put_device(&gdev->dev);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 1aaddea673e0..0689fcf23a11 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -695,6 +695,25 @@ out:
return ret;
}
+int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
+ struct channel_path_desc_fmt1 *desc)
+{
+ struct chsc_response_struct *chsc_resp;
+ struct chsc_scpd *scpd_area;
+ int ret;
+
+ spin_lock_irq(&chsc_page_lock);
+ scpd_area = chsc_page;
+ ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area);
+ if (ret)
+ goto out;
+ chsc_resp = (void *)&scpd_area->response;
+ memcpy(desc, &chsc_resp->data, sizeof(*desc));
+out:
+ spin_unlock_irq(&chsc_page_lock);
+ return ret;
+}
+
static void
chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
struct cmg_chars *chars)
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 6693f5e3176f..3f15b2aaeaea 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -35,6 +35,22 @@ struct channel_path_desc {
u8 chpp;
} __attribute__ ((packed));
+struct channel_path_desc_fmt1 {
+ u8 flags;
+ u8 lsn;
+ u8 desc;
+ u8 chpid;
+ u32:24;
+ u8 chpp;
+ u32 unused[3];
+ u16 mdc;
+ u16:13;
+ u8 r:1;
+ u8 s:1;
+ u8 f:1;
+ u32 zeros[2];
+} __attribute__ ((packed));
+
struct channel_path;
struct css_chsc_char {
@@ -92,6 +108,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
int c, int m, void *page);
int chsc_determine_base_channel_path_desc(struct chp_id chpid,
struct channel_path_desc *desc);
+int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
+ struct channel_path_desc_fmt1 *desc);
void chsc_chp_online(struct chp_id chpid);
void chsc_chp_offline(struct chp_id chpid);
int chsc_get_channel_measurement_chars(struct channel_path *chp);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index f4e6cf3aceb8..430f875006f2 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
s390_idle_check(regs, S390_lowcore.int_clock,
S390_lowcore.async_enter_timer);
irq_enter();
- __get_cpu_var(s390_idle).nohz_delay = 1;
+ __this_cpu_write(s390_idle.nohz_delay, 1);
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
/* Serve timer interrupts first. */
clock_comparator_work();
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index a5050e217150..24d8e97355b9 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -618,6 +618,7 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe);
static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
{
struct subchannel_id mchk_schid;
+ struct subchannel *sch;
if (overflow) {
css_schedule_eval_all();
@@ -635,8 +636,15 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
init_subchannel_id(&mchk_schid);
mchk_schid.sch_no = crw0->rsid;
if (crw1)
- mchk_schid.ssid = (crw1->rsid >> 8) & 3;
+ mchk_schid.ssid = (crw1->rsid >> 4) & 3;
+ if (crw0->erc == CRW_ERC_PMOD) {
+ sch = get_subchannel_by_schid(mchk_schid);
+ if (sch) {
+ css_update_ssd_info(sch);
+ put_device(&sch->dev);
+ }
+ }
/*
* Since we are always presented with IPI in the CRW, we have to
* use stsch() to find out if the subchannel in question has come
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 2ff8a22d4257..b7eaff9ca19e 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1455,7 +1455,16 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
break;
case IO_SCH_UNREG_ATTACH:
case IO_SCH_UNREG:
- if (cdev)
+ if (!cdev)
+ break;
+ if (cdev->private->state == DEV_STATE_SENSE_ID) {
+ /*
+ * Note: delayed work triggered by this event
+ * and repeated calls to sch_event are synchronized
+ * by the above check for work_pending(cdev).
+ */
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ } else
ccw_device_set_notoper(cdev);
break;
case IO_SCH_NOP:
@@ -1826,6 +1835,7 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
* available again. Kick re-detection.
*/
cdev->private->flags.resuming = 1;
+ cdev->private->path_new_mask = LPM_ANYPATH;
css_schedule_eval(sch->schid);
spin_unlock_irq(sch->lock);
css_complete_work();
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 6da84543dfe9..651976b54af8 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -687,6 +687,46 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw,
EXPORT_SYMBOL(ccw_device_tm_start_timeout);
/**
+ * ccw_device_get_mdc - accumulate max data count
+ * @cdev: ccw device for which the max data count is accumulated
+ * @mask: mask of paths to use
+ *
+ * Return the number of 64K-bytes blocks all paths at least support
+ * for a transport command. Return values <= 0 indicate failures.
+ */
+int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct channel_path_desc_fmt1 desc;
+ struct chp_id chpid;
+ int mdc = 0, ret, i;
+
+ /* Adjust requested path mask to excluded varied off paths. */
+ if (mask)
+ mask &= sch->lpm;
+ else
+ mask = sch->lpm;
+
+ chp_id_init(&chpid);
+ for (i = 0; i < 8; i++) {
+ if (!(mask & (0x80 >> i)))
+ continue;
+ chpid.id = sch->schib.pmcw.chpid[i];
+ ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc);
+ if (ret)
+ return ret;
+ if (!desc.f)
+ return 0;
+ if (!desc.r)
+ mdc = 1;
+ mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc;
+ }
+
+ return mdc;
+}
+EXPORT_SYMBOL(ccw_device_get_mdc);
+
+/**
* ccw_device_tm_intrg - perform interrogate function
* @cdev: ccw device on which to perform the interrogate function
*
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
index a0ae29564774..358ee16d10a2 100644
--- a/drivers/s390/cio/itcw.c
+++ b/drivers/s390/cio/itcw.c
@@ -93,6 +93,7 @@ EXPORT_SYMBOL(itcw_get_tcw);
size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
{
size_t len;
+ int cross_count;
/* Main data. */
len = sizeof(struct itcw);
@@ -105,12 +106,27 @@ size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
/* TSB */ sizeof(struct tsb) +
/* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw);
}
+
/* Maximum required alignment padding. */
len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7;
- /* Maximum padding for structures that may not cross 4k boundary. */
- if ((max_tidaws > 0) || (intrg_max_tidaws > 0))
- len += max(max_tidaws, intrg_max_tidaws) *
- sizeof(struct tidaw) - 1;
+
+ /* TIDAW lists may not cross a 4k boundary. To cross a
+ * boundary we need to add a TTIC TIDAW. We need to reserve
+ * one additional TIDAW for a TTIC that we may need to add due
+ * to the placement of the data chunk in memory, and a further
+ * TIDAW for each page boundary that the TIDAW list may cross
+ * due to it's own size.
+ */
+ if (max_tidaws) {
+ cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
+ >> PAGE_SHIFT);
+ len += cross_count * sizeof(struct tidaw);
+ }
+ if (intrg_max_tidaws) {
+ cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
+ >> PAGE_SHIFT);
+ len += cross_count * sizeof(struct tidaw);
+ }
return len;
}
EXPORT_SYMBOL(itcw_calc_size);
@@ -165,6 +181,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
void *chunk;
addr_t start;
addr_t end;
+ int cross_count;
/* Check for 2G limit. */
start = (addr_t) buffer;
@@ -177,8 +194,17 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
if (IS_ERR(chunk))
return chunk;
itcw = chunk;
- itcw->max_tidaws = max_tidaws;
- itcw->intrg_max_tidaws = intrg_max_tidaws;
+ /* allow for TTIC tidaws that may be needed to cross a page boundary */
+ cross_count = 0;
+ if (max_tidaws)
+ cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
+ >> PAGE_SHIFT);
+ itcw->max_tidaws = max_tidaws + cross_count;
+ cross_count = 0;
+ if (intrg_max_tidaws)
+ cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
+ >> PAGE_SHIFT);
+ itcw->intrg_max_tidaws = intrg_max_tidaws + cross_count;
/* Main TCW. */
chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
if (IS_ERR(chunk))
@@ -198,7 +224,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
/* Data TIDAL. */
if (max_tidaws > 0) {
chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
- max_tidaws, 16, 1);
+ itcw->max_tidaws, 16, 0);
if (IS_ERR(chunk))
return chunk;
tcw_set_data(itcw->tcw, chunk, 1);
@@ -206,7 +232,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
/* Interrogate data TIDAL. */
if (intrg && (intrg_max_tidaws > 0)) {
chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
- intrg_max_tidaws, 16, 1);
+ itcw->intrg_max_tidaws, 16, 0);
if (IS_ERR(chunk))
return chunk;
tcw_set_data(itcw->intrg_tcw, chunk, 1);
@@ -283,13 +309,29 @@ EXPORT_SYMBOL(itcw_add_dcw);
* the new tidaw on success or -%ENOSPC if the new tidaw would exceed the
* available space.
*
- * Note: the tidaw-list is assumed to be contiguous with no ttics. The
- * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize.
+ * Note: TTIC tidaws are automatically added when needed, so explicitly calling
+ * this interface with the TTIC flag is not supported. The last-tidaw flag
+ * for the last tidaw in the list will be set by itcw_finalize.
*/
struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count)
{
+ struct tidaw *following;
+
if (itcw->num_tidaws >= itcw->max_tidaws)
return ERR_PTR(-ENOSPC);
+ /*
+ * Is the tidaw, which follows the one we are about to fill, on the next
+ * page? Then we have to insert a TTIC tidaw first, that points to the
+ * tidaw on the new page.
+ */
+ following = ((struct tidaw *) tcw_get_data(itcw->tcw))
+ + itcw->num_tidaws + 1;
+ if (itcw->num_tidaws && !((unsigned long) following & ~PAGE_MASK)) {
+ tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++,
+ TIDAW_FLAGS_TTIC, following, 0);
+ if (itcw->num_tidaws >= itcw->max_tidaws)
+ return ERR_PTR(-ENOSPC);
+ }
return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count);
}
EXPORT_SYMBOL(itcw_add_tidaw);
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 0f4ef8769a3d..7bc643f3f5ab 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -91,6 +91,12 @@ enum qdio_irq_states {
#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */
#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */
+/* SIGA flags */
+#define QDIO_SIGA_WRITE 0x00
+#define QDIO_SIGA_READ 0x01
+#define QDIO_SIGA_SYNC 0x02
+#define QDIO_SIGA_QEBSM_FLAG 0x80
+
#ifdef CONFIG_64BIT
static inline int do_sqbs(u64 token, unsigned char state, int queue,
int *start, int *count)
@@ -142,10 +148,9 @@ struct siga_flag {
u8 input:1;
u8 output:1;
u8 sync:1;
- u8 no_sync_ti:1;
- u8 no_sync_out_ti:1;
- u8 no_sync_out_pci:1;
- u8:2;
+ u8 sync_after_ai:1;
+ u8 sync_out_after_pci:1;
+ u8:3;
} __attribute__ ((packed));
struct chsc_ssqd_area {
@@ -202,6 +207,7 @@ struct qdio_dev_perf_stat {
unsigned int inbound_queue_full;
unsigned int outbound_call;
unsigned int outbound_handler;
+ unsigned int outbound_queue_full;
unsigned int fast_requeue;
unsigned int target_full;
unsigned int eqbs;
@@ -245,10 +251,10 @@ struct qdio_input_q {
struct qdio_output_q {
/* PCIs are enabled for the queue */
int pci_out_enabled;
- /* IQDIO: output multiple buffers (enhanced SIGA) */
- int use_enh_siga;
/* timer to check for more outbound work */
struct timer_list timer;
+ /* used SBALs before tasklet schedule */
+ int scan_threshold;
};
/*
@@ -383,12 +389,13 @@ static inline int multicast_outbound(struct qdio_q *q)
(q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)
#define is_qebsm(q) (q->irq_ptr->sch_token != 0)
-#define need_siga_sync_thinint(q) (!q->irq_ptr->siga_flag.no_sync_ti)
-#define need_siga_sync_out_thinint(q) (!q->irq_ptr->siga_flag.no_sync_out_ti)
#define need_siga_in(q) (q->irq_ptr->siga_flag.input)
#define need_siga_out(q) (q->irq_ptr->siga_flag.output)
-#define need_siga_sync(q) (q->irq_ptr->siga_flag.sync)
-#define siga_syncs_out_pci(q) (q->irq_ptr->siga_flag.no_sync_out_pci)
+#define need_siga_sync(q) (unlikely(q->irq_ptr->siga_flag.sync))
+#define need_siga_sync_after_ai(q) \
+ (unlikely(q->irq_ptr->siga_flag.sync_after_ai))
+#define need_siga_sync_out_after_pci(q) \
+ (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci))
#define for_each_input_queue(irq_ptr, q, i) \
for (i = 0, q = irq_ptr->input_qs[0]; \
@@ -423,9 +430,9 @@ struct indicator_t {
extern struct indicator_t *q_indicators;
-static inline int shared_ind(struct qdio_irq *irq_ptr)
+static inline int shared_ind(u32 *dsci)
{
- return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+ return dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
}
/* prototypes for thin interrupt */
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 28868e7471a5..f8b03a636e49 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -151,6 +151,7 @@ static char *qperf_names[] = {
"Inbound queue full",
"Outbound calls",
"Outbound handler",
+ "Outbound queue full",
"Outbound fast_requeue",
"Outbound target_full",
"QEBSM eqbs",
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 5fcfa7f9e9ef..e9fff2b9bce2 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -14,6 +14,7 @@
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/kernel_stat.h>
#include <asm/atomic.h>
#include <asm/debug.h>
#include <asm/qdio.h>
@@ -29,11 +30,12 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\
MODULE_DESCRIPTION("QDIO base support");
MODULE_LICENSE("GPL");
-static inline int do_siga_sync(struct subchannel_id schid,
- unsigned int out_mask, unsigned int in_mask)
+static inline int do_siga_sync(unsigned long schid,
+ unsigned int out_mask, unsigned int in_mask,
+ unsigned int fc)
{
- register unsigned long __fc asm ("0") = 2;
- register struct subchannel_id __schid asm ("1") = schid;
+ register unsigned long __fc asm ("0") = fc;
+ register unsigned long __schid asm ("1") = schid;
register unsigned long out asm ("2") = out_mask;
register unsigned long in asm ("3") = in_mask;
int cc;
@@ -47,10 +49,11 @@ static inline int do_siga_sync(struct subchannel_id schid,
return cc;
}
-static inline int do_siga_input(struct subchannel_id schid, unsigned int mask)
+static inline int do_siga_input(unsigned long schid, unsigned int mask,
+ unsigned int fc)
{
- register unsigned long __fc asm ("0") = 1;
- register struct subchannel_id __schid asm ("1") = schid;
+ register unsigned long __fc asm ("0") = fc;
+ register unsigned long __schid asm ("1") = schid;
register unsigned long __mask asm ("2") = mask;
int cc;
@@ -279,16 +282,20 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr)
static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
unsigned int input)
{
+ unsigned long schid = *((u32 *) &q->irq_ptr->schid);
+ unsigned int fc = QDIO_SIGA_SYNC;
int cc;
- if (!need_siga_sync(q))
- return 0;
-
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
qperf_inc(q, siga_sync);
- cc = do_siga_sync(q->irq_ptr->schid, output, input);
- if (cc)
+ if (is_qebsm(q)) {
+ schid = q->irq_ptr->sch_token;
+ fc |= QDIO_SIGA_QEBSM_FLAG;
+ }
+
+ cc = do_siga_sync(schid, output, input, fc);
+ if (unlikely(cc))
DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc);
return cc;
}
@@ -301,38 +308,22 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
return qdio_siga_sync(q, q->mask, 0);
}
-static inline int qdio_siga_sync_out(struct qdio_q *q)
-{
- return qdio_siga_sync(q, ~0U, 0);
-}
-
-static inline int qdio_siga_sync_all(struct qdio_q *q)
-{
- return qdio_siga_sync(q, ~0U, ~0U);
-}
-
static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
{
- unsigned long schid;
- unsigned int fc = 0;
+ unsigned long schid = *((u32 *) &q->irq_ptr->schid);
+ unsigned int fc = QDIO_SIGA_WRITE;
u64 start_time = 0;
int cc;
- if (q->u.out.use_enh_siga)
- fc = 3;
-
if (is_qebsm(q)) {
schid = q->irq_ptr->sch_token;
- fc |= 0x80;
+ fc |= QDIO_SIGA_QEBSM_FLAG;
}
- else
- schid = *((u32 *)&q->irq_ptr->schid);
-
again:
cc = do_siga_output(schid, q->mask, busy_bit, fc);
/* hipersocket busy condition */
- if (*busy_bit) {
+ if (unlikely(*busy_bit)) {
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
if (!start_time) {
@@ -347,32 +338,41 @@ again:
static inline int qdio_siga_input(struct qdio_q *q)
{
+ unsigned long schid = *((u32 *) &q->irq_ptr->schid);
+ unsigned int fc = QDIO_SIGA_READ;
int cc;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr);
qperf_inc(q, siga_read);
- cc = do_siga_input(q->irq_ptr->schid, q->mask);
- if (cc)
+ if (is_qebsm(q)) {
+ schid = q->irq_ptr->sch_token;
+ fc |= QDIO_SIGA_QEBSM_FLAG;
+ }
+
+ cc = do_siga_input(schid, q->mask, fc);
+ if (unlikely(cc))
DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc);
return cc;
}
-static inline void qdio_sync_after_thinint(struct qdio_q *q)
+#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0)
+#define qdio_siga_sync_all(q) qdio_siga_sync(q, ~0U, ~0U)
+
+static inline void qdio_sync_queues(struct qdio_q *q)
{
- if (pci_out_supported(q)) {
- if (need_siga_sync_thinint(q))
- qdio_siga_sync_all(q);
- else if (need_siga_sync_out_thinint(q))
- qdio_siga_sync_out(q);
- } else
+ /* PCI capable outbound queues will also be scanned so sync them too */
+ if (pci_out_supported(q))
+ qdio_siga_sync_all(q);
+ else
qdio_siga_sync_q(q);
}
int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
unsigned char *state)
{
- qdio_siga_sync_q(q);
+ if (need_siga_sync(q))
+ qdio_siga_sync_q(q);
return get_buf_states(q, bufnr, state, 1, 0);
}
@@ -549,7 +549,8 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
if (!atomic_read(&q->nr_buf_used))
return 1;
- qdio_siga_sync_q(q);
+ if (need_siga_sync(q))
+ qdio_siga_sync_q(q);
get_buf_state(q, q->first_to_check, &state, 0);
if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR)
@@ -644,9 +645,12 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
int count, stop;
unsigned char state;
- if (((queue_type(q) != QDIO_IQDIO_QFMT) && !pci_out_supported(q)) ||
- (queue_type(q) == QDIO_IQDIO_QFMT && multicast_outbound(q)))
- qdio_siga_sync_q(q);
+ if (need_siga_sync(q))
+ if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
+ !pci_out_supported(q)) ||
+ (queue_type(q) == QDIO_IQDIO_QFMT &&
+ multicast_outbound(q)))
+ qdio_siga_sync_q(q);
/*
* Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -818,7 +822,8 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
static void __tiqdio_inbound_processing(struct qdio_q *q)
{
qperf_inc(q, tasklet_inbound);
- qdio_sync_after_thinint(q);
+ if (need_siga_sync(q) && need_siga_sync_after_ai(q))
+ qdio_sync_queues(q);
/*
* The interrupt could be caused by a PCI request. Check the
@@ -898,16 +903,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
tasklet_schedule(&q->tasklet);
}
- if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
+ if (!pci_out_supported(q))
return;
for_each_output_queue(irq_ptr, q, i) {
if (qdio_outbound_q_done(q))
continue;
-
- if (!siga_syncs_out_pci(q))
+ if (need_siga_sync(q) && need_siga_sync_out_after_pci(q))
qdio_siga_sync_q(q);
-
tasklet_schedule(&q->tasklet);
}
}
@@ -970,6 +973,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
return;
}
+ kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++;
if (irq_ptr->perf_stat_enabled)
irq_ptr->perf_stat.qdio_int++;
@@ -1273,7 +1277,6 @@ int qdio_establish(struct qdio_initialize *init_data)
}
qdio_setup_ssqd_info(irq_ptr);
- DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc);
DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
/* qebsm is now setup if available, initialize buffer states */
@@ -1445,52 +1448,38 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
used = atomic_add_return(count, &q->nr_buf_used);
BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q);
+ if (used == QDIO_MAX_BUFFERS_PER_Q)
+ qperf_inc(q, outbound_queue_full);
+
if (callflags & QDIO_FLAG_PCI_OUT) {
q->u.out.pci_out_enabled = 1;
qperf_inc(q, pci_request_int);
- }
- else
+ } else
q->u.out.pci_out_enabled = 0;
if (queue_type(q) == QDIO_IQDIO_QFMT) {
- if (multicast_outbound(q))
+ /* One SIGA-W per buffer required for unicast HiperSockets. */
+ WARN_ON_ONCE(count > 1 && !multicast_outbound(q));
+
+ rc = qdio_kick_outbound_q(q);
+ } else if (need_siga_sync(q)) {
+ rc = qdio_siga_sync_q(q);
+ } else {
+ /* try to fast requeue buffers */
+ get_buf_state(q, prev_buf(bufnr), &state, 0);
+ if (state != SLSB_CU_OUTPUT_PRIMED)
rc = qdio_kick_outbound_q(q);
else
- if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
- (count > 1) &&
- (count <= q->irq_ptr->ssqd_desc.mmwc)) {
- /* exploit enhanced SIGA */
- q->u.out.use_enh_siga = 1;
- rc = qdio_kick_outbound_q(q);
- } else {
- /*
- * One siga-w per buffer required for unicast
- * HiperSockets.
- */
- q->u.out.use_enh_siga = 0;
- while (count--) {
- rc = qdio_kick_outbound_q(q);
- if (rc)
- goto out;
- }
- }
- goto out;
- }
-
- if (need_siga_sync(q)) {
- qdio_siga_sync_q(q);
- goto out;
+ qperf_inc(q, fast_requeue);
}
- /* try to fast requeue buffers */
- get_buf_state(q, prev_buf(bufnr), &state, 0);
- if (state != SLSB_CU_OUTPUT_PRIMED)
- rc = qdio_kick_outbound_q(q);
+ /* in case of SIGA errors we must process the error immediately */
+ if (used >= q->u.out.scan_threshold || rc)
+ tasklet_schedule(&q->tasklet);
else
- qperf_inc(q, fast_requeue);
-
-out:
- tasklet_schedule(&q->tasklet);
+ /* free the SBALs in case of no further traffic */
+ if (!timer_pending(&q->u.out.timer))
+ mod_timer(&q->u.out.timer, jiffies + HZ);
return rc;
}
@@ -1550,7 +1539,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
WARN_ON(queue_irqs_enabled(q));
- if (!shared_ind(q->irq_ptr))
+ if (!shared_ind(q->irq_ptr->dsci))
xchg(q->irq_ptr->dsci, 0);
qdio_stop_polling(q);
@@ -1560,7 +1549,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
* We need to check again to not lose initiative after
* resetting the ACK state.
*/
- if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci)
+ if (!shared_ind(q->irq_ptr->dsci) && *q->irq_ptr->dsci)
goto rescan;
if (!qdio_inbound_q_done(q))
goto rescan;
@@ -1600,12 +1589,14 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
q = irq_ptr->input_qs[nr];
WARN_ON(queue_irqs_enabled(q));
- qdio_sync_after_thinint(q);
-
/*
- * The interrupt could be caused by a PCI request. Check the
- * PCI capable outbound queues.
+ * Cannot rely on automatic sync after interrupt since queues may
+ * also be examined without interrupt.
*/
+ if (need_siga_sync(q))
+ qdio_sync_queues(q);
+
+ /* check the PCI capable outbound queues. */
qdio_check_outbound_after_thinint(q);
if (!qdio_inbound_q_moved(q))
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index a13cf7ec64b2..89107d0938c4 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -178,6 +178,7 @@ static void setup_queues(struct qdio_irq *irq_ptr,
setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
q->is_input_q = 0;
+ q->u.out.scan_threshold = qdio_init->scan_threshold;
setup_storage_lists(q, irq_ptr, output_sbal_array, i);
output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
@@ -196,14 +197,10 @@ static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac)
irq_ptr->siga_flag.output = 1;
if (qdioac & AC1_SIGA_SYNC_NEEDED)
irq_ptr->siga_flag.sync = 1;
- if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT)
- irq_ptr->siga_flag.no_sync_ti = 1;
- if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI)
- irq_ptr->siga_flag.no_sync_out_pci = 1;
-
- if (irq_ptr->siga_flag.no_sync_out_pci &&
- irq_ptr->siga_flag.no_sync_ti)
- irq_ptr->siga_flag.no_sync_out_ti = 1;
+ if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_THININT))
+ irq_ptr->siga_flag.sync_after_ai = 1;
+ if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI))
+ irq_ptr->siga_flag.sync_out_after_pci = 1;
}
static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
@@ -451,7 +448,7 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
char s[80];
snprintf(s, 80, "qdio: %s %s on SC %x using "
- "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n",
+ "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s\n",
dev_name(&cdev->dev),
(irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" :
((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"),
@@ -463,9 +460,8 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
(irq_ptr->siga_flag.input) ? "R" : " ",
(irq_ptr->siga_flag.output) ? "W" : " ",
(irq_ptr->siga_flag.sync) ? "S" : " ",
- (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ",
- (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ",
- (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
+ (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ",
+ (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " ");
printk(KERN_INFO "%s", s);
}
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 752dbee06af5..5c4e741d8221 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -8,6 +8,7 @@
*/
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/kernel_stat.h>
#include <asm/atomic.h>
#include <asm/debug.h>
#include <asm/qdio.h>
@@ -35,22 +36,8 @@ static u8 *tiqdio_alsi;
struct indicator_t *q_indicators;
-static int css_qdio_omit_svs;
-
static u64 last_ai_time;
-static inline unsigned long do_clear_global_summary(void)
-{
- register unsigned long __fn asm("1") = 3;
- register unsigned long __tmp asm("2");
- register unsigned long __time asm("3");
-
- asm volatile(
- " .insn rre,0xb2650000,2,0"
- : "+d" (__fn), "=d" (__tmp), "=d" (__time));
- return __time;
-}
-
/* returns addr for the device state change indicator */
static u32 *get_indicator(void)
{
@@ -83,10 +70,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
struct qdio_q *q;
int i;
- /* No TDD facility? If we must use SIGA-s we can also omit SVS. */
- if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)
- css_qdio_omit_svs = 1;
-
mutex_lock(&tiq_list_lock);
for_each_input_queue(irq_ptr, q, i)
list_add_rcu(&q->entry, &tiq_list);
@@ -112,9 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
}
}
-static inline int shared_ind_used(void)
+static inline u32 shared_ind_set(void)
{
- return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
+ return q_indicators[TIQDIO_SHARED_IND].ind;
}
/**
@@ -124,20 +107,11 @@ static inline int shared_ind_used(void)
*/
static void tiqdio_thinint_handler(void *alsi, void *data)
{
+ u32 si_used = shared_ind_set();
struct qdio_q *q;
last_ai_time = S390_lowcore.int_clock;
-
- /*
- * SVS only when needed: issue SVS to benefit from iqdio interrupt
- * avoidance (SVS clears adapter interrupt suppression overwrite).
- */
- if (!css_qdio_omit_svs)
- do_clear_global_summary();
-
- /* reset local summary indicator */
- if (shared_ind_used())
- xchg(tiqdio_alsi, 0);
+ kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++;
/* protect tiq_list entries, only changed in activate or shutdown */
rcu_read_lock();
@@ -146,7 +120,10 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
list_for_each_entry_rcu(q, &tiq_list, entry) {
/* only process queues from changed sets */
- if (!*q->irq_ptr->dsci)
+ if (unlikely(shared_ind(q->irq_ptr->dsci))) {
+ if (!si_used)
+ continue;
+ } else if (!*q->irq_ptr->dsci)
continue;
if (q->u.in.queue_start_poll) {
@@ -162,7 +139,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
q->irq_ptr->int_parm);
} else {
/* only clear it if the indicator is non-shared */
- if (!shared_ind(q->irq_ptr))
+ if (!shared_ind(q->irq_ptr->dsci))
xchg(q->irq_ptr->dsci, 0);
/*
* Call inbound processing but not directly
@@ -178,13 +155,8 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
* If the shared indicator was used clear it now after all queues
* were processed.
*/
- if (shared_ind_used()) {
+ if (si_used && shared_ind_set())
xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
-
- /* prevent racing */
- if (*tiqdio_alsi)
- xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7);
- }
}
static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
@@ -269,12 +241,6 @@ int qdio_establish_thinint(struct qdio_irq *irq_ptr)
{
if (!is_thinint_irq(irq_ptr))
return 0;
-
- /* Check for aif time delay disablement. If installed,
- * omit SVS even under LPAR
- */
- if (css_general_characteristics.aif_tdd)
- css_qdio_omit_svs = 1;
return set_subchannel_ind(irq_ptr, 0);
}
@@ -292,8 +258,8 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
return;
/* reset adapter interrupt indicators */
- put_indicator(irq_ptr->dsci);
set_subchannel_ind(irq_ptr, 1);
+ put_indicator(irq_ptr->dsci);
}
void __exit tiqdio_unregister_thinints(void)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 8fd8c62455e9..67302b944ab3 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -27,6 +27,7 @@
#define KMSG_COMPONENT "ap"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -154,7 +155,7 @@ static inline int ap_instructions_available(void)
*/
static int ap_interrupts_available(void)
{
- return test_facility(1) && test_facility(2);
+ return test_facility(2) && test_facility(65);
}
/**
@@ -221,6 +222,69 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind)
}
#endif
+static inline struct ap_queue_status __ap_4096_commands_available(ap_qid_t qid,
+ int *support)
+{
+ register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23);
+ register struct ap_queue_status reg1 asm ("1");
+ register unsigned long reg2 asm ("2") = 0UL;
+
+ asm volatile(
+ ".long 0xb2af0000\n"
+ "0: la %1,0\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (reg0), "=d" (reg1), "=d" (reg2)
+ :
+ : "cc");
+
+ if (reg2 & 0x6000000000000000ULL)
+ *support = 1;
+ else
+ *support = 0;
+
+ return reg1;
+}
+
+/**
+ * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA
+ * support.
+ * @qid: The AP queue number
+ *
+ * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not.
+ */
+int ap_4096_commands_available(ap_qid_t qid)
+{
+ struct ap_queue_status status;
+ int i, support = 0;
+ status = __ap_4096_commands_available(qid, &support);
+
+ for (i = 0; i < AP_MAX_RESET; i++) {
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ return support;
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ case AP_RESPONSE_BUSY:
+ break;
+ case AP_RESPONSE_Q_NOT_AVAIL:
+ case AP_RESPONSE_DECONFIGURED:
+ case AP_RESPONSE_CHECKSTOPPED:
+ case AP_RESPONSE_INVALID_ADDRESS:
+ return 0;
+ case AP_RESPONSE_OTHERWISE_CHANGED:
+ break;
+ default:
+ break;
+ }
+ if (i < AP_MAX_RESET - 1) {
+ udelay(5);
+ status = __ap_4096_commands_available(qid, &support);
+ }
+ }
+ return support;
+}
+EXPORT_SYMBOL(ap_4096_commands_available);
+
/**
* ap_queue_enable_interruption(): Enable interruption on an AP.
* @qid: The AP queue number
@@ -1042,6 +1106,7 @@ out:
static void ap_interrupt_handler(void *unused1, void *unused2)
{
+ kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++;
tasklet_schedule(&ap_tasklet);
}
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 4785d07cd447..08b9738285b4 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -196,4 +196,6 @@ void ap_flush_queue(struct ap_device *ap_dev);
int ap_module_init(void);
void ap_module_exit(void);
+int ap_4096_commands_available(ap_qid_t qid);
+
#endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index f5221749d180..8e65447f76b7 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -35,7 +35,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/compat.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
@@ -397,8 +396,15 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
if (copied == 0) {
unsigned int len;
spin_unlock_bh(&zcrypt_device_lock);
- /* len is max 256 / 2 - 120 = 8 */
- len = crt->inputdatalength / 2 - 120;
+ /* len is max 256 / 2 - 120 = 8
+ * For bigger device just assume len of leading
+ * 0s is 8 as stated in the requirements for
+ * ica_rsa_modexpo_crt struct in zcrypt.h.
+ */
+ if (crt->inputdatalength <= 256)
+ len = crt->inputdatalength / 2 - 120;
+ else
+ len = 8;
if (len > sizeof(z1))
return -EFAULT;
z1 = z2 = z3 = 0;
@@ -406,6 +412,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
copy_from_user(&z2, crt->bp_key, len) ||
copy_from_user(&z3, crt->u_mult_inv, len))
return -EFAULT;
+ z1 = z2 = z3 = 0;
copied = 1;
/*
* We have to restart device lookup -
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 8e7ffbf2466c..88ebd114735b 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -109,6 +109,7 @@ struct zcrypt_device {
int request_count; /* # current requests. */
struct ap_message reply; /* Per-device reply structure. */
+ int max_exp_bit_length;
};
struct zcrypt_device *zcrypt_device_alloc(size_t);
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 9c409efa1ecf..2176d00b395e 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -41,7 +41,7 @@
#define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */
#define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */
#define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE
-#define CEX3A_MAX_MOD_SIZE CEX2A_MAX_MOD_SIZE
+#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */
#define CEX2A_SPEED_RATING 970
#define CEX3A_SPEED_RATING 900 /* Fixme: Needs finetuning */
@@ -49,8 +49,10 @@
#define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
-#define CEX3A_MAX_MESSAGE_SIZE CEX2A_MAX_MESSAGE_SIZE
-#define CEX3A_MAX_RESPONSE_SIZE CEX2A_MAX_RESPONSE_SIZE
+#define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus
+ * (max outputdatalength) +
+ * type80_hdr*/
+#define CEX3A_MAX_MESSAGE_SIZE sizeof(struct type50_crb3_msg)
#define CEX2A_CLEANUP_TIME (15*HZ)
#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
@@ -110,7 +112,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
inp = meb1->message + sizeof(meb1->message) - mod_len;
- } else {
+ } else if (mod_len <= 256) {
struct type50_meb2_msg *meb2 = ap_msg->message;
memset(meb2, 0, sizeof(*meb2));
ap_msg->length = sizeof(*meb2);
@@ -120,6 +122,17 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
inp = meb2->message + sizeof(meb2->message) - mod_len;
+ } else {
+ /* mod_len > 256 = 4096 bit RSA Key */
+ struct type50_meb3_msg *meb3 = ap_msg->message;
+ memset(meb3, 0, sizeof(*meb3));
+ ap_msg->length = sizeof(*meb3);
+ meb3->header.msg_type_code = TYPE50_TYPE_CODE;
+ meb3->header.msg_len = sizeof(*meb3);
+ meb3->keyblock_type = TYPE50_MEB3_FMT;
+ mod = meb3->modulus + sizeof(meb3->modulus) - mod_len;
+ exp = meb3->exponent + sizeof(meb3->exponent) - mod_len;
+ inp = meb3->message + sizeof(meb3->message) - mod_len;
}
if (copy_from_user(mod, mex->n_modulus, mod_len) ||
@@ -142,7 +155,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
struct ap_message *ap_msg,
struct ica_rsa_modexpo_crt *crt)
{
- int mod_len, short_len, long_len, long_offset;
+ int mod_len, short_len, long_len, long_offset, limit;
unsigned char *p, *q, *dp, *dq, *u, *inp;
mod_len = crt->inputdatalength;
@@ -152,14 +165,20 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
/*
* CEX2A cannot handle p, dp, or U > 128 bytes.
* If we have one of these, we need to do extra checking.
+ * For CEX3A the limit is 256 bytes.
*/
- if (long_len > 128) {
+ if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)
+ limit = 256;
+ else
+ limit = 128;
+
+ if (long_len > limit) {
/*
* zcrypt_rsa_crt already checked for the leading
* zeroes of np_prime, bp_key and u_mult_inc.
*/
- long_offset = long_len - 128;
- long_len = 128;
+ long_offset = long_len - limit;
+ long_len = limit;
} else
long_offset = 0;
@@ -180,7 +199,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
dq = crb1->dq + sizeof(crb1->dq) - short_len;
u = crb1->u + sizeof(crb1->u) - long_len;
inp = crb1->message + sizeof(crb1->message) - mod_len;
- } else {
+ } else if (long_len <= 128) {
struct type50_crb2_msg *crb2 = ap_msg->message;
memset(crb2, 0, sizeof(*crb2));
ap_msg->length = sizeof(*crb2);
@@ -193,6 +212,20 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
dq = crb2->dq + sizeof(crb2->dq) - short_len;
u = crb2->u + sizeof(crb2->u) - long_len;
inp = crb2->message + sizeof(crb2->message) - mod_len;
+ } else {
+ /* long_len >= 256 */
+ struct type50_crb3_msg *crb3 = ap_msg->message;
+ memset(crb3, 0, sizeof(*crb3));
+ ap_msg->length = sizeof(*crb3);
+ crb3->header.msg_type_code = TYPE50_TYPE_CODE;
+ crb3->header.msg_len = sizeof(*crb3);
+ crb3->keyblock_type = TYPE50_CRB3_FMT;
+ p = crb3->p + sizeof(crb3->p) - long_len;
+ q = crb3->q + sizeof(crb3->q) - short_len;
+ dp = crb3->dp + sizeof(crb3->dp) - long_len;
+ dq = crb3->dq + sizeof(crb3->dq) - short_len;
+ u = crb3->u + sizeof(crb3->u) - long_len;
+ inp = crb3->message + sizeof(crb3->message) - mod_len;
}
if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
@@ -203,7 +236,6 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
copy_from_user(inp, crt->inputdata, mod_len))
return -EFAULT;
-
return 0;
}
@@ -230,7 +262,10 @@ static int convert_type80(struct zcrypt_device *zdev,
zdev->online = 0;
return -EAGAIN; /* repeat the request on a different device. */
}
- BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
+ if (zdev->user_space_type == ZCRYPT_CEX2A)
+ BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
+ else
+ BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
data = reply->message + t80h->len - outputdatalength;
if (copy_to_user(outputdata, data, outputdatalength))
return -EFAULT;
@@ -282,7 +317,10 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
}
t80h = reply->message;
if (t80h->type == TYPE80_RSP_CODE) {
- length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
+ if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A)
+ length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
+ else
+ length = min(CEX3A_MAX_RESPONSE_SIZE, (int) t80h->len);
memcpy(msg->message, reply->message, length);
} else
memcpy(msg->message, reply->message, sizeof error_reply);
@@ -307,7 +345,10 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
int rc;
ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (zdev->user_space_type == ZCRYPT_CEX2A)
+ ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ else
+ ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
@@ -345,7 +386,10 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
int rc;
ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (zdev->user_space_type == ZCRYPT_CEX2A)
+ ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ else
+ ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
@@ -397,6 +441,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
zdev->short_crt = 1;
zdev->speed_rating = CEX2A_SPEED_RATING;
+ zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3A:
zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE);
@@ -404,8 +449,13 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
return -ENOMEM;
zdev->user_space_type = ZCRYPT_CEX3A;
zdev->type_string = "CEX3A";
- zdev->min_mod_size = CEX3A_MIN_MOD_SIZE;
- zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
+ zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
+ zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
+ if (ap_4096_commands_available(ap_dev->qid)) {
+ zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
+ }
zdev->short_crt = 1;
zdev->speed_rating = CEX3A_SPEED_RATING;
break;
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
index 8f69d1dacab8..0350665810cf 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.h
+++ b/drivers/s390/crypto/zcrypt_cex2a.h
@@ -51,8 +51,10 @@ struct type50_hdr {
#define TYPE50_MEB1_FMT 0x0001
#define TYPE50_MEB2_FMT 0x0002
+#define TYPE50_MEB3_FMT 0x0003
#define TYPE50_CRB1_FMT 0x0011
#define TYPE50_CRB2_FMT 0x0012
+#define TYPE50_CRB3_FMT 0x0013
/* Mod-Exp, with a small modulus */
struct type50_meb1_msg {
@@ -74,6 +76,16 @@ struct type50_meb2_msg {
unsigned char message[256];
} __attribute__((packed));
+/* Mod-Exp, with a larger modulus */
+struct type50_meb3_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0003 */
+ unsigned char reserved[6];
+ unsigned char exponent[512];
+ unsigned char modulus[512];
+ unsigned char message[512];
+} __attribute__((packed));
+
/* CRT, with a small modulus */
struct type50_crb1_msg {
struct type50_hdr header;
@@ -100,6 +112,19 @@ struct type50_crb2_msg {
unsigned char message[256];
} __attribute__((packed));
+/* CRT, with a larger modulus */
+struct type50_crb3_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0013 */
+ unsigned char reserved[6];
+ unsigned char p[256];
+ unsigned char q[256];
+ unsigned char dp[256];
+ unsigned char dq[256];
+ unsigned char u[256];
+ unsigned char message[512];
+} __attribute__((packed));
+
/**
* The type 80 response family is associated with a CEX2A card.
*
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 09e934b295a0..1afb69c75fea 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -373,6 +373,7 @@ static int zcrypt_pcica_probe(struct ap_device *ap_dev)
zdev->min_mod_size = PCICA_MIN_MOD_SIZE;
zdev->max_mod_size = PCICA_MAX_MOD_SIZE;
zdev->speed_rating = PCICA_SPEED_RATING;
+ zdev->max_exp_bit_length = PCICA_MAX_MOD_SIZE;
ap_dev->reply = &zdev->reply;
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index 9dec5c77cff4..aa4c050a5694 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -579,6 +579,7 @@ static int zcrypt_pcicc_probe(struct ap_device *ap_dev)
zdev->min_mod_size = PCICC_MIN_MOD_SIZE;
zdev->max_mod_size = PCICC_MAX_MOD_SIZE;
zdev->speed_rating = PCICC_SPEED_RATING;
+ zdev->max_exp_bit_length = PCICC_MAX_MOD_SIZE;
ap_dev->reply = &zdev->reply;
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 510fab4577d4..4f85eb725f4f 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -45,12 +45,12 @@
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
-#define CEX3C_MAX_MOD_SIZE PCIXCC_MAX_MOD_SIZE
+#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
#define PCIXCC_MCL2_SPEED_RATING 7870
#define PCIXCC_MCL3_SPEED_RATING 7870
#define CEX2C_SPEED_RATING 7000
-#define CEX3C_SPEED_RATING 6500 /* FIXME: needs finetuning */
+#define CEX3C_SPEED_RATING 6500
#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
@@ -567,6 +567,15 @@ static int convert_response_ica(struct zcrypt_device *zdev,
case TYPE88_RSP_CODE:
return convert_error(zdev, reply);
case TYPE86_RSP_CODE:
+ if (msg->cprbx.ccp_rtcode &&
+ (msg->cprbx.ccp_rscode == 0x14f) &&
+ (outputdatalength > 256)) {
+ if (zdev->max_exp_bit_length <= 17) {
+ zdev->max_exp_bit_length = 17;
+ return -EAGAIN;
+ } else
+ return -EINVAL;
+ }
if (msg->hdr.reply_code)
return convert_error(zdev, reply);
if (msg->cprbx.cprb_ver_id == 0x02)
@@ -1052,11 +1061,13 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
} else {
zdev->type_string = "PCIXCC_MCL3";
zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
}
break;
case AP_DEVICE_TYPE_CEX2C:
@@ -1065,6 +1076,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->speed_rating = CEX2C_SPEED_RATING;
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3C:
zdev->user_space_type = ZCRYPT_CEX3C;
@@ -1072,6 +1084,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
zdev->speed_rating = CEX3C_SPEED_RATING;
zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
+ zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
break;
default:
goto out_free;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 375aeeaf9ea5..414427d64a8f 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -10,6 +10,7 @@
* Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*/
+#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/err.h>
@@ -25,6 +26,7 @@
#include <asm/kvm_virtio.h>
#include <asm/setup.h>
#include <asm/s390_ext.h>
+#include <asm/irq.h>
#define VIRTIO_SUBCODE_64 0x0D00
@@ -379,6 +381,7 @@ static void kvm_extint_handler(unsigned int ext_int_code,
u16 subcode;
u32 param;
+ kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++;
subcode = ext_int_code >> 16;
if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
return;
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 456b18743397..fa80ba1f0344 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -2,7 +2,8 @@ menu "S/390 network device drivers"
depends on NETDEVICES && S390
config LCS
- tristate "Lan Channel Station Interface"
+ def_tristate m
+ prompt "Lan Channel Station Interface"
depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI)
help
Select this option if you want to use LCS networking on IBM System z.
@@ -12,7 +13,8 @@ config LCS
If you do not know what it is, it's safe to choose Y.
config CTCM
- tristate "CTC and MPC SNA device support"
+ def_tristate m
+ prompt "CTC and MPC SNA device support"
depends on CCW && NETDEVICES
help
Select this option if you want to use channel-to-channel
@@ -26,7 +28,8 @@ config CTCM
If you do not need any channel-to-channel connection, choose N.
config NETIUCV
- tristate "IUCV network device support (VM only)"
+ def_tristate m
+ prompt "IUCV network device support (VM only)"
depends on IUCV && NETDEVICES
help
Select this option if you want to use inter-user communication
@@ -37,14 +40,16 @@ config NETIUCV
The module name is netiucv. If unsure, choose Y.
config SMSGIUCV
- tristate "IUCV special message support (VM only)"
+ def_tristate m
+ prompt "IUCV special message support (VM only)"
depends on IUCV
help
Select this option if you want to be able to receive SMSG messages
from other VM guest systems.
config SMSGIUCV_EVENT
- tristate "Deliver IUCV special messages as uevents (VM only)"
+ def_tristate m
+ prompt "Deliver IUCV special messages as uevents (VM only)"
depends on SMSGIUCV
help
Select this option to deliver CP special messages (SMSGs) as
@@ -54,7 +59,8 @@ config SMSGIUCV_EVENT
To compile as a module, choose M. The module name is "smsgiucv_app".
config CLAW
- tristate "CLAW device support"
+ def_tristate m
+ prompt "CLAW device support"
depends on CCW && NETDEVICES
help
This driver supports channel attached CLAW devices.
@@ -64,7 +70,8 @@ config CLAW
To compile into the kernel, choose Y.
config QETH
- tristate "Gigabit Ethernet device support"
+ def_tristate y
+ prompt "Gigabit Ethernet device support"
depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
help
This driver supports the IBM System z OSA Express adapters
@@ -78,25 +85,25 @@ config QETH
The module name is qeth.
config QETH_L2
- tristate "qeth layer 2 device support"
- depends on QETH
- help
- Select this option to be able to run qeth devices in layer 2 mode.
- To compile as a module, choose M. The module name is qeth_l2.
- If unsure, choose y.
+ def_tristate y
+ prompt "qeth layer 2 device support"
+ depends on QETH
+ help
+ Select this option to be able to run qeth devices in layer 2 mode.
+ To compile as a module, choose M. The module name is qeth_l2.
+ If unsure, choose y.
config QETH_L3
- tristate "qeth layer 3 device support"
- depends on QETH
- help
- Select this option to be able to run qeth devices in layer 3 mode.
- To compile as a module choose M. The module name is qeth_l3.
- If unsure, choose Y.
+ def_tristate y
+ prompt "qeth layer 3 device support"
+ depends on QETH
+ help
+ Select this option to be able to run qeth devices in layer 3 mode.
+ To compile as a module choose M. The module name is qeth_l3.
+ If unsure, choose Y.
config QETH_IPV6
- bool
- depends on (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y')
- default y
+ def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y')
config CCWGROUP
tristate
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 8e4153d740f3..ce3a5c13ce0b 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -63,6 +63,7 @@
#define KMSG_COMPONENT "claw"
+#include <linux/kernel_stat.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include <asm/debug.h>
@@ -640,6 +641,7 @@ claw_irq_handler(struct ccw_device *cdev,
struct claw_env *p_env;
struct chbk *p_ch_r=NULL;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_CLW]++;
CLAW_DBF_TEXT(4, trace, "clawirq");
/* Bypass all 'unsolicited interrupts' */
privptr = dev_get_drvdata(&cdev->dev);
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 2c7d2d9be4d0..4c2845985927 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -24,6 +24,7 @@
#define KMSG_COMPONENT "ctcm"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -1204,6 +1205,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
int cstat;
int dstat;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_CTC]++;
CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
"Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev));
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 0f19d540b655..30b2a820e670 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -26,6 +26,7 @@
#define KMSG_COMPONENT "lcs"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/if.h>
#include <linux/netdevice.h>
@@ -840,7 +841,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
}
/**
- * Emit buffer of a lan comand.
+ * Emit buffer of a lan command.
*/
static void
lcs_lancmd_timeout(unsigned long data)
@@ -1188,7 +1189,8 @@ lcs_remove_mc_addresses(struct lcs_card *card, struct in_device *in4_dev)
spin_lock_irqsave(&card->ipm_lock, flags);
list_for_each(l, &card->ipm_list) {
ipm = list_entry(l, struct lcs_ipm_list, list);
- for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) {
+ for (im4 = rcu_dereference(in4_dev->mc_list);
+ im4 != NULL; im4 = rcu_dereference(im4->next_rcu)) {
lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
if ( (ipm->ipm.ip_addr == im4->multiaddr) &&
(memcmp(buf, &ipm->ipm.mac_addr,
@@ -1233,7 +1235,8 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev)
unsigned long flags;
LCS_DBF_TEXT(4, trace, "setmclst");
- for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
+ for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
+ im4 = rcu_dereference(im4->next_rcu)) {
lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
ipm = lcs_check_addr_entry(card, im4, buf);
if (ipm != NULL)
@@ -1269,10 +1272,10 @@ lcs_register_mc_addresses(void *data)
in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
goto out;
- read_lock(&in4_dev->mc_list_lock);
+ rcu_read_lock();
lcs_remove_mc_addresses(card,in4_dev);
lcs_set_mc_addresses(card, in4_dev);
- read_unlock(&in4_dev->mc_list_lock);
+ rcu_read_unlock();
in_dev_put(in4_dev);
netif_carrier_off(card->dev);
@@ -1396,6 +1399,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
int rc, index;
int cstat, dstat;
+ kstat_cpu(smp_processor_id()).irqs[IOINT_LCS]++;
if (lcs_check_irb_error(cdev, irb))
return;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 6be43eb126b4..f47a714538db 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -440,7 +440,6 @@ struct qeth_qdio_out_q {
* index of buffer to be filled by driver; state EMPTY or PACKING
*/
int next_buf_to_fill;
- int sync_iqdio_error;
/*
* number of buffers that are currently filled (PRIMED)
* -> these buffers are hardware-owned
@@ -695,14 +694,6 @@ struct qeth_mc_mac {
int is_vmac;
};
-struct qeth_skb_data {
- __u32 magic;
- int count;
-};
-
-#define QETH_SKB_MAGIC 0x71657468
-#define QETH_SIGA_CC2_RETRIES 3
-
struct qeth_rx {
int b_count;
int b_index;
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 764267062601..29f848bfc12f 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -877,8 +877,8 @@ out:
return;
}
-static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
- struct qeth_qdio_out_buffer *buf, unsigned int qeth_skip_skb)
+static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf)
{
int i;
struct sk_buff *skb;
@@ -887,13 +887,11 @@ static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
if (buf->buffer->element[0].flags & 0x40)
atomic_dec(&queue->set_pci_flags_count);
- if (!qeth_skip_skb) {
+ skb = skb_dequeue(&buf->skb_list);
+ while (skb) {
+ atomic_dec(&skb->users);
+ dev_kfree_skb_any(skb);
skb = skb_dequeue(&buf->skb_list);
- while (skb) {
- atomic_dec(&skb->users);
- dev_kfree_skb_any(skb);
- skb = skb_dequeue(&buf->skb_list);
- }
}
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) {
if (buf->buffer->element[i].addr && buf->is_header[i])
@@ -909,12 +907,6 @@ static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
}
-static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
- struct qeth_qdio_out_buffer *buf)
-{
- __qeth_clear_output_buffer(queue, buf, 0);
-}
-
void qeth_clear_qdio_buffers(struct qeth_card *card)
{
int i, j;
@@ -2833,7 +2825,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
}
}
- queue->sync_iqdio_error = 0;
queue->card->dev->trans_start = jiffies;
if (queue->card->options.performance_stats) {
queue->card->perf_stats.outbound_do_qdio_cnt++;
@@ -2849,10 +2840,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
queue->card->perf_stats.outbound_do_qdio_time +=
qeth_get_micros() -
queue->card->perf_stats.outbound_do_qdio_start_time;
- if (rc > 0) {
- if (!(rc & QDIO_ERROR_SIGA_BUSY))
- queue->sync_iqdio_error = rc & 3;
- }
+ atomic_add(count, &queue->used_buffers);
if (rc) {
queue->card->stats.tx_errors += count;
/* ignore temporary SIGA errors without busy condition */
@@ -2866,7 +2854,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
qeth_schedule_recovery(queue->card);
return;
}
- atomic_add(count, &queue->used_buffers);
if (queue->card->options.performance_stats)
queue->card->perf_stats.bufs_sent += count;
}
@@ -2916,7 +2903,7 @@ void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue,
{
struct qeth_card *card = (struct qeth_card *)card_ptr;
- if (card->dev)
+ if (card->dev && (card->dev->flags & IFF_UP))
napi_schedule(&card->napi);
}
EXPORT_SYMBOL_GPL(qeth_qdio_start_poll);
@@ -2940,7 +2927,6 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue];
struct qeth_qdio_out_buffer *buffer;
int i;
- unsigned qeth_send_err;
QETH_CARD_TEXT(card, 6, "qdouhdl");
if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
@@ -2956,9 +2942,8 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
}
for (i = first_element; i < (first_element + count); ++i) {
buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
- qeth_send_err = qeth_handle_send_error(card, buffer, qdio_error);
- __qeth_clear_output_buffer(queue, buffer,
- (qeth_send_err == QETH_SEND_ERROR_RETRY) ? 1 : 0);
+ qeth_handle_send_error(card, buffer, qdio_error);
+ qeth_clear_output_buffer(queue, buffer);
}
atomic_sub(count, &queue->used_buffers);
/* check if we need to do something on this outbound queue */
@@ -3183,10 +3168,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
int offset, int hd_len)
{
struct qeth_qdio_out_buffer *buffer;
- struct sk_buff *skb1;
- struct qeth_skb_data *retry_ctrl;
int index;
- int rc;
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
@@ -3205,25 +3187,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
qeth_flush_buffers(queue, index, 1);
- if (queue->sync_iqdio_error == 2) {
- skb1 = skb_dequeue(&buffer->skb_list);
- while (skb1) {
- atomic_dec(&skb1->users);
- skb1 = skb_dequeue(&buffer->skb_list);
- }
- retry_ctrl = (struct qeth_skb_data *) &skb->cb[16];
- if (retry_ctrl->magic != QETH_SKB_MAGIC) {
- retry_ctrl->magic = QETH_SKB_MAGIC;
- retry_ctrl->count = 0;
- }
- if (retry_ctrl->count < QETH_SIGA_CC2_RETRIES) {
- retry_ctrl->count++;
- rc = dev_queue_xmit(skb);
- } else {
- dev_kfree_skb_any(skb);
- QETH_CARD_TEXT(card, 2, "qrdrop");
- }
- }
return 0;
out:
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
@@ -3868,6 +3831,8 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
+ init_data.scan_threshold =
+ (card->info.type == QETH_CARD_TYPE_IQD) ? 8 : 32;
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index e37dd8c4bf4e..07d588867b57 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -333,7 +333,7 @@ struct qeth_arp_query_data {
__u16 request_bits;
__u16 reply_bits;
__u32 no_entries;
- char data;
+ char data; /* only for replies */
} __attribute__((packed));
/* used as parameter for arp_query reply */
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 42fa783a70c8..b5e967cf7e2d 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -372,7 +372,7 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev,
i = simple_strtoul(buf, &tmp, 16);
if ((i == 0) || (i == 1)) {
if (i == card->options.performance_stats)
- goto out;;
+ goto out;
card->options.performance_stats = i;
if (i == 0)
memset(&card->perf_stats, 0,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 847e8797073c..7a7a1b664781 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -849,8 +849,6 @@ static int qeth_l2_open(struct net_device *dev)
card->state = CARD_STATE_UP;
netif_start_queue(dev);
- if (!card->lan_online && netif_carrier_ok(dev))
- netif_carrier_off(dev);
if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
napi_enable(&card->napi);
napi_schedule(&card->napi);
@@ -1013,13 +1011,14 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
dev_warn(&card->gdev->dev,
"The LAN is offline\n");
card->lan_online = 0;
- goto out;
+ goto contin;
}
rc = -ENODEV;
goto out_remove;
} else
card->lan_online = 1;
+contin:
if ((card->info.type == QETH_CARD_TYPE_OSD) ||
(card->info.type == QETH_CARD_TYPE_OSX))
/* configure isolation level */
@@ -1038,7 +1037,10 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove;
}
card->state = CARD_STATE_SOFTSETUP;
- netif_carrier_on(card->dev);
+ if (card->lan_online)
+ netif_carrier_on(card->dev);
+ else
+ netif_carrier_off(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
if (recover_flag == CARD_STATE_RECOVER) {
@@ -1055,7 +1057,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
-out:
mutex_unlock(&card->conf_mutex);
mutex_unlock(&card->discipline_mutex);
return 0;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 74d1401a5d5e..e227e465bfc4 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -30,6 +30,7 @@
#include "qeth_l3.h"
+
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_recover(void *);
static int qeth_l3_stop(struct net_device *);
@@ -455,8 +456,11 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
QETH_CARD_TEXT(card, 2, "sdiplist");
QETH_CARD_HEX(card, 2, &card, sizeof(void *));
- if (card->options.sniffer)
+ if ((card->state != CARD_STATE_UP &&
+ card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) {
return;
+ }
+
spin_lock_irqsave(&card->ip_lock, flags);
tbd_list = card->ip_tbd_list;
card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
@@ -1796,7 +1800,8 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)
char buf[MAX_ADDR_LEN];
QETH_CARD_TEXT(card, 4, "addmc");
- for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
+ for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
+ im4 = rcu_dereference(im4->next_rcu)) {
qeth_l3_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm)
@@ -1828,9 +1833,9 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
in_dev = in_dev_get(netdev);
if (!in_dev)
continue;
- read_lock(&in_dev->mc_list_lock);
+ rcu_read_lock();
qeth_l3_add_mc(card, in_dev);
- read_unlock(&in_dev->mc_list_lock);
+ rcu_read_unlock();
in_dev_put(in_dev);
}
}
@@ -1843,10 +1848,10 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
return;
- read_lock(&in4_dev->mc_list_lock);
+ rcu_read_lock();
qeth_l3_add_mc(card, in4_dev);
qeth_l3_add_vlan_mc(card);
- read_unlock(&in4_dev->mc_list_lock);
+ rcu_read_unlock();
in_dev_put(in4_dev);
}
@@ -2454,22 +2459,46 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
return rc;
}
-static void qeth_l3_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
- struct qeth_arp_query_data *qdata, int entry_size,
- int uentry_size)
+static __u32 get_arp_entry_size(struct qeth_card *card,
+ struct qeth_arp_query_data *qdata,
+ struct qeth_arp_entrytype *type, __u8 strip_entries)
{
- char *entry_ptr;
- char *uentry_ptr;
- int i;
+ __u32 rc;
+ __u8 is_hsi;
- entry_ptr = (char *)&qdata->data;
- uentry_ptr = (char *)(qinfo->udata + qinfo->udata_offset);
- for (i = 0; i < qdata->no_entries; ++i) {
- /* strip off 32 bytes "media specific information" */
- memcpy(uentry_ptr, (entry_ptr + 32), entry_size - 32);
- entry_ptr += entry_size;
- uentry_ptr += uentry_size;
+ is_hsi = qdata->reply_bits == 5;
+ if (type->ip == QETHARP_IP_ADDR_V4) {
+ QETH_CARD_TEXT(card, 4, "arpev4");
+ if (strip_entries) {
+ rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) :
+ sizeof(struct qeth_arp_qi_entry7_short);
+ } else {
+ rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) :
+ sizeof(struct qeth_arp_qi_entry7);
+ }
+ } else if (type->ip == QETHARP_IP_ADDR_V6) {
+ QETH_CARD_TEXT(card, 4, "arpev6");
+ if (strip_entries) {
+ rc = is_hsi ?
+ sizeof(struct qeth_arp_qi_entry5_short_ipv6) :
+ sizeof(struct qeth_arp_qi_entry7_short_ipv6);
+ } else {
+ rc = is_hsi ?
+ sizeof(struct qeth_arp_qi_entry5_ipv6) :
+ sizeof(struct qeth_arp_qi_entry7_ipv6);
+ }
+ } else {
+ QETH_CARD_TEXT(card, 4, "arpinv");
+ rc = 0;
}
+
+ return rc;
+}
+
+static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot)
+{
+ return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) ||
+ (type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6);
}
static int qeth_l3_arp_query_cb(struct qeth_card *card,
@@ -2478,72 +2507,77 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
struct qeth_arp_query_data *qdata;
struct qeth_arp_query_info *qinfo;
- int entry_size;
- int uentry_size;
int i;
+ int e;
+ int entrybytes_done;
+ int stripped_bytes;
+ __u8 do_strip_entries;
- QETH_CARD_TEXT(card, 4, "arpquecb");
+ QETH_CARD_TEXT(card, 3, "arpquecb");
qinfo = (struct qeth_arp_query_info *) reply->param;
cmd = (struct qeth_ipa_cmd *) data;
+ QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version);
if (cmd->hdr.return_code) {
- QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT(card, 4, "arpcberr");
+ QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
return 0;
}
if (cmd->data.setassparms.hdr.return_code) {
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
- QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT(card, 4, "setaperr");
+ QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
return 0;
}
qdata = &cmd->data.setassparms.data.query_arp;
- switch (qdata->reply_bits) {
- case 5:
- uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry5);
- if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
- uentry_size = sizeof(struct qeth_arp_qi_entry5_short);
- break;
- case 7:
- /* fall through to default */
- default:
- /* tr is the same as eth -> entry7 */
- uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry7);
- if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
- uentry_size = sizeof(struct qeth_arp_qi_entry7_short);
- break;
- }
- /* check if there is enough room in userspace */
- if ((qinfo->udata_len - qinfo->udata_offset) <
- qdata->no_entries * uentry_size){
- QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
- cmd->hdr.return_code = -ENOMEM;
- goto out_error;
- }
- QETH_CARD_TEXT_(card, 4, "anore%i",
- cmd->data.setassparms.hdr.number_of_replies);
- QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
- if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) {
- /* strip off "media specific information" */
- qeth_l3_copy_arp_entries_stripped(qinfo, qdata, entry_size,
- uentry_size);
- } else
- /*copy entries to user buffer*/
- memcpy(qinfo->udata + qinfo->udata_offset,
- (char *)&qdata->data, qdata->no_entries*uentry_size);
+ do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0;
+ stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0;
+ entrybytes_done = 0;
+ for (e = 0; e < qdata->no_entries; ++e) {
+ char *cur_entry;
+ __u32 esize;
+ struct qeth_arp_entrytype *etype;
+
+ cur_entry = &qdata->data + entrybytes_done;
+ etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type;
+ if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) {
+ QETH_CARD_TEXT(card, 4, "pmis");
+ QETH_CARD_TEXT_(card, 4, "%i", etype->ip);
+ break;
+ }
+ esize = get_arp_entry_size(card, qdata, etype,
+ do_strip_entries);
+ QETH_CARD_TEXT_(card, 5, "esz%i", esize);
+ if (!esize)
+ break;
+
+ if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
+ QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
+ cmd->hdr.return_code = -ENOMEM;
+ goto out_error;
+ }
- qinfo->no_entries += qdata->no_entries;
- qinfo->udata_offset += (qdata->no_entries*uentry_size);
+ memcpy(qinfo->udata + qinfo->udata_offset,
+ &qdata->data + entrybytes_done + stripped_bytes,
+ esize);
+ entrybytes_done += esize + stripped_bytes;
+ qinfo->udata_offset += esize;
+ ++qinfo->no_entries;
+ }
/* check if all replies received ... */
if (cmd->data.setassparms.hdr.seq_no <
cmd->data.setassparms.hdr.number_of_replies)
return 1;
+ QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries);
memcpy(qinfo->udata, &qinfo->no_entries, 4);
/* keep STRIP_ENTRIES flag so the user program can distinguish
* stripped entries from normal ones */
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;
memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
+ QETH_CARD_TEXT_(card, 4, "rc%i", 0);
return 0;
out_error:
i = 0;
@@ -2566,45 +2600,86 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card,
reply_cb, reply_param);
}
-static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
+static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
+ enum qeth_prot_versions prot,
+ struct qeth_arp_query_info *qinfo)
{
struct qeth_cmd_buffer *iob;
- struct qeth_arp_query_info qinfo = {0, };
+ struct qeth_ipa_cmd *cmd;
int tmp;
int rc;
+ QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
+
+ iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+ IPA_CMD_ASS_ARP_QUERY_INFO,
+ sizeof(struct qeth_arp_query_data) - sizeof(char),
+ prot);
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
+ cmd->data.setassparms.data.query_arp.reply_bits = 0;
+ cmd->data.setassparms.data.query_arp.no_entries = 0;
+ rc = qeth_l3_send_ipa_arp_cmd(card, iob,
+ QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
+ qeth_l3_arp_query_cb, (void *)qinfo);
+ if (rc) {
+ tmp = rc;
+ QETH_DBF_MESSAGE(2,
+ "Error while querying ARP cache on %s: %s "
+ "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
+ qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
+ }
+
+ return rc;
+}
+
+static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
+{
+ struct qeth_arp_query_info qinfo = {0, };
+ int rc;
+
QETH_CARD_TEXT(card, 3, "arpquery");
if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
IPA_ARP_PROCESSING)) {
- return -EOPNOTSUPP;
+ QETH_CARD_TEXT(card, 3, "arpqnsup");
+ rc = -EOPNOTSUPP;
+ goto out;
}
/* get size of userspace buffer and mask_bits -> 6 bytes */
- if (copy_from_user(&qinfo, udata, 6))
- return -EFAULT;
+ if (copy_from_user(&qinfo, udata, 6)) {
+ rc = -EFAULT;
+ goto out;
+ }
qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
- if (!qinfo.udata)
- return -ENOMEM;
+ if (!qinfo.udata) {
+ rc = -ENOMEM;
+ goto out;
+ }
qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
- iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_ARP_QUERY_INFO,
- sizeof(int), QETH_PROT_IPV4);
-
- rc = qeth_l3_send_ipa_arp_cmd(card, iob,
- QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
- qeth_l3_arp_query_cb, (void *)&qinfo);
+ rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo);
if (rc) {
- tmp = rc;
- QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s "
- "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
if (copy_to_user(udata, qinfo.udata, 4))
rc = -EFAULT;
+ goto free_and_out;
} else {
- if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
+#ifdef CONFIG_QETH_IPV6
+ if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
+ /* fails in case of GuestLAN QDIO mode */
+ qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6,
+ &qinfo);
+ }
+#endif
+ if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
+ QETH_CARD_TEXT(card, 4, "qactf");
rc = -EFAULT;
+ goto free_and_out;
+ }
+ QETH_CARD_TEXT_(card, 4, "qacts");
}
+free_and_out:
kfree(qinfo.udata);
+out:
return rc;
}
@@ -2938,6 +3013,7 @@ static void qeth_tso_fill_header(struct qeth_card *card,
/*fix header to TSO values ...*/
hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
+ hdr->hdr.hdr.l3.length = skb->len - sizeof(struct qeth_hdr_tso);
/*set values which are fix for the first approach ...*/
hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
hdr->ext.imb_hdr_no = 1;
@@ -3039,7 +3115,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(new_skb, ETH_HLEN);
}
- if (ipv == 6 && card->vlangrp &&
+ if (ipv != 4 && card->vlangrp &&
vlan_tx_tag_present(new_skb)) {
skb_push(new_skb, VLAN_HLEN);
skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
@@ -3176,8 +3252,6 @@ static int qeth_l3_open(struct net_device *dev)
card->state = CARD_STATE_UP;
netif_start_queue(dev);
- if (!card->lan_online && netif_carrier_ok(dev))
- netif_carrier_off(dev);
if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
napi_enable(&card->napi);
napi_schedule(&card->napi);
@@ -3449,13 +3523,14 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
dev_warn(&card->gdev->dev,
"The LAN is offline\n");
card->lan_online = 0;
- goto out;
+ goto contin;
}
rc = -ENODEV;
goto out_remove;
} else
card->lan_online = 1;
+contin:
rc = qeth_l3_setadapter_parms(card);
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
@@ -3480,10 +3555,13 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove;
}
card->state = CARD_STATE_SOFTSETUP;
- netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
qeth_l3_set_ip_addr_list(card);
+ if (card->lan_online)
+ netif_carrier_on(card->dev);
+ else
+ netif_carrier_off(card->dev);
if (recover_flag == CARD_STATE_RECOVER) {
if (recovery_mode)
qeth_l3_open(card->dev);
@@ -3496,7 +3574,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
-out:
mutex_unlock(&card->conf_mutex);
mutex_unlock(&card->discipline_mutex);
return 0;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 044fb22718d2..51c666fb67a4 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -45,8 +45,8 @@ static char *init_device;
module_param_named(device, init_device, charp, 0400);
MODULE_PARM_DESC(device, "specify initial device");
-static struct kmem_cache *zfcp_cache_hw_align(const char *name,
- unsigned long size)
+static struct kmem_cache * __init zfcp_cache_hw_align(const char *name,
+ unsigned long size)
{
return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL);
}
@@ -311,8 +311,7 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)
if (zfcp_fsf_status_read(adapter->qdio)) {
if (atomic_read(&adapter->stat_miss) >=
adapter->stat_read_buf_num) {
- zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
- NULL);
+ zfcp_erp_adapter_reopen(adapter, 0, "axsref1");
return 1;
}
break;
@@ -459,7 +458,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
zfcp_erp_thread_kill(adapter);
- zfcp_dbf_adapter_unregister(adapter->dbf);
+ zfcp_dbf_adapter_unregister(adapter);
zfcp_qdio_destroy(adapter->qdio);
zfcp_ccw_adapter_put(adapter); /* final put to release */
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 0833c2b51e39..4f7852dd30c7 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -48,7 +48,7 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "ccresu2", NULL);
+ "ccresu2");
zfcp_erp_wait(adapter);
flush_work(&adapter->scan_work);
@@ -182,7 +182,7 @@ static int zfcp_ccw_set_offline(struct ccw_device *cdev)
if (!adapter)
return 0;
- zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1");
zfcp_erp_wait(adapter);
zfcp_ccw_adapter_put(adapter);
@@ -207,24 +207,24 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
dev_warn(&cdev->dev, "The FCP device has been detached\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");
break;
case CIO_NO_PATH:
dev_warn(&cdev->dev,
"The CHPID for the FCP device is offline\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");
break;
case CIO_OPER:
dev_info(&cdev->dev, "The FCP device is operational again\n");
zfcp_erp_set_adapter_status(adapter,
ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "ccnoti4", NULL);
+ "ccnoti4");
break;
case CIO_BOXED:
dev_warn(&cdev->dev, "The FCP device did not respond within "
"the specified time\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5");
break;
}
@@ -243,7 +243,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
if (!adapter)
return;
- zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
+ zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1");
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index d692e229ecba..303dde09d294 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -288,7 +288,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter)
(status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "cfaac_1", NULL);
+ "cfaac_1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
@@ -299,7 +299,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter)
(status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
zfcp_erp_lun_reopen(sdev,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "cfaac_2", NULL);
+ "cfaac_2");
}
}
@@ -317,7 +317,7 @@ static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
/**
* zfcp_cfdc_port_denied - Process "access denied" for port
- * @port: The port where the acces has been denied
+ * @port: The port where the access has been denied
* @qual: The FSF status qualifier for the access denied FSF status
*/
void zfcp_cfdc_port_denied(struct zfcp_port *port,
@@ -426,7 +426,7 @@ int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev,
zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
- zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL);
+ zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6");
return -EACCES;
}
@@ -437,7 +437,7 @@ int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev,
zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
- zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL);
+ zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8");
return -EACCES;
}
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 2cdd6b28ff7f..96d1462e0bf5 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -3,7 +3,7 @@
*
* Debug traces for zfcp.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -22,980 +22,392 @@ module_param(dbfsize, uint, 0400);
MODULE_PARM_DESC(dbfsize,
"number of pages for each debug feature area (default 4)");
-static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len,
- int level, char *from, int from_len)
+static inline unsigned int zfcp_dbf_plen(unsigned int offset)
{
- int offset;
- struct zfcp_dbf_dump *dump = to;
- int room = to_len - sizeof(*dump);
-
- for (offset = 0; offset < from_len; offset += dump->size) {
- memset(to, 0, to_len);
- strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
- dump->total_size = from_len;
- dump->offset = offset;
- dump->size = min(from_len - offset, room);
- memcpy(dump->data, from + offset, dump->size);
- debug_event(dbf, level, dump, dump->size + sizeof(*dump));
- }
+ return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC;
}
-static void zfcp_dbf_tag(char **p, const char *label, const char *tag)
+static inline
+void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
+ u64 req_id)
{
- int i;
-
- *p += sprintf(*p, "%-24s", label);
- for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++)
- *p += sprintf(*p, "%c", tag[i]);
- *p += sprintf(*p, "\n");
-}
+ struct zfcp_dbf_pay *pl = &dbf->pay_buf;
+ u16 offset = 0, rec_length;
-static void zfcp_dbf_outs(char **buf, const char *s1, const char *s2)
-{
- *buf += sprintf(*buf, "%-24s%s\n", s1, s2);
-}
+ spin_lock(&dbf->pay_lock);
+ memset(pl, 0, sizeof(*pl));
+ pl->fsf_req_id = req_id;
+ memcpy(pl->area, area, ZFCP_DBF_TAG_LEN);
-static void zfcp_dbf_out(char **buf, const char *s, const char *format, ...)
-{
- va_list arg;
+ while (offset < length) {
+ rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC,
+ (u16) (length - offset));
+ memcpy(pl->data, data + offset, rec_length);
+ debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length));
- *buf += sprintf(*buf, "%-24s", s);
- va_start(arg, format);
- *buf += vsprintf(*buf, format, arg);
- va_end(arg);
- *buf += sprintf(*buf, "\n");
-}
-
-static void zfcp_dbf_outd(char **p, const char *label, char *buffer,
- int buflen, int offset, int total_size)
-{
- if (!offset)
- *p += sprintf(*p, "%-24s ", label);
- while (buflen--) {
- if (offset > 0) {
- if ((offset % 32) == 0)
- *p += sprintf(*p, "\n%-24c ", ' ');
- else if ((offset % 4) == 0)
- *p += sprintf(*p, " ");
- }
- *p += sprintf(*p, "%02x", *buffer++);
- if (++offset == total_size) {
- *p += sprintf(*p, "\n");
- break;
- }
+ offset += rec_length;
+ pl->counter++;
}
- if (!total_size)
- *p += sprintf(*p, "\n");
-}
-static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view,
- int area, debug_entry_t *entry, char *out_buf)
-{
- struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry);
- struct timespec t;
- char *p = out_buf;
-
- if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) {
- stck_to_timespec(entry->id.stck, &t);
- zfcp_dbf_out(&p, "timestamp", "%011lu:%06lu",
- t.tv_sec, t.tv_nsec);
- zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid);
- } else {
- zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset,
- dump->total_size);
- if ((dump->offset + dump->size) == dump->total_size)
- p += sprintf(p, "\n");
- }
- return p - out_buf;
+ spin_unlock(&dbf->pay_lock);
}
-void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
- struct zfcp_fsf_req *fsf_req,
- struct zfcp_dbf *dbf)
+/**
+ * zfcp_dbf_hba_fsf_res - trace event for fsf responses
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request for which a response was received
+ */
+void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
{
- struct fsf_qtcb *qtcb = fsf_req->qtcb;
- union fsf_prot_status_qual *prot_status_qual =
- &qtcb->prefix.prot_status_qual;
- union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual;
- struct scsi_cmnd *scsi_cmnd;
- struct zfcp_port *port;
- struct zfcp_unit *unit;
- struct zfcp_send_els *send_els;
- struct zfcp_dbf_hba_record *rec = &dbf->hba_buf;
- struct zfcp_dbf_hba_record_response *response = &rec->u.response;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
+ struct fsf_qtcb_header *q_head = &req->qtcb->header;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
-
- response->fsf_command = fsf_req->fsf_command;
- response->fsf_reqid = fsf_req->req_id;
- response->fsf_seqno = fsf_req->seq_no;
- response->fsf_issued = fsf_req->issued;
- response->fsf_prot_status = qtcb->prefix.prot_status;
- response->fsf_status = qtcb->header.fsf_status;
- memcpy(response->fsf_prot_status_qual,
- prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE);
- memcpy(response->fsf_status_qual,
- fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE);
- response->fsf_req_status = fsf_req->status;
- response->sbal_first = fsf_req->qdio_req.sbal_first;
- response->sbal_last = fsf_req->qdio_req.sbal_last;
- response->sbal_response = fsf_req->qdio_req.sbal_response;
- response->pool = fsf_req->pool != NULL;
- response->erp_action = (unsigned long)fsf_req->erp_action;
-
- switch (fsf_req->fsf_command) {
- case FSF_QTCB_FCP_CMND:
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
- break;
- scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
- if (scsi_cmnd) {
- response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
- response->u.fcp.data_dir =
- qtcb->bottom.io.data_direction;
- }
- break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- port = (struct zfcp_port *)fsf_req->data;
- response->u.port.wwpn = port->wwpn;
- response->u.port.d_id = port->d_id;
- response->u.port.port_handle = qtcb->header.port_handle;
- break;
-
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- unit = (struct zfcp_unit *)fsf_req->data;
- port = unit->port;
- response->u.unit.wwpn = port->wwpn;
- response->u.unit.fcp_lun = unit->fcp_lun;
- response->u.unit.port_handle = qtcb->header.port_handle;
- response->u.unit.lun_handle = qtcb->header.lun_handle;
- break;
-
- case FSF_QTCB_SEND_ELS:
- send_els = (struct zfcp_send_els *)fsf_req->data;
- response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id);
- break;
-
- case FSF_QTCB_ABORT_FCP_CMND:
- case FSF_QTCB_SEND_GENERIC:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_EXCHANGE_PORT_DATA:
- case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
- case FSF_QTCB_UPLOAD_CONTROL_FILE:
- break;
- }
-
- debug_event(dbf->hba, level, rec, sizeof(*rec));
- /* have fcp channel microcode fixed to use as little as possible */
- if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) {
- /* adjust length skipping trailing zeros */
- char *buf = (char *)qtcb + qtcb->header.log_start;
- int len = qtcb->header.log_length;
- for (; len && !buf[len - 1]; len--);
- zfcp_dbf_hexdump(dbf->hba, rec, sizeof(*rec), level, buf,
- len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_RES;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+ rec->fsf_seq_no = req->seq_no;
+ rec->u.res.req_issued = req->issued;
+ rec->u.res.prot_status = q_pref->prot_status;
+ rec->u.res.fsf_status = q_head->fsf_status;
+
+ memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
+ FSF_PROT_STATUS_QUAL_SIZE);
+ memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual,
+ FSF_STATUS_QUALIFIER_SIZE);
+
+ if (req->fsf_command != FSF_QTCB_FCP_CMND) {
+ rec->pl_len = q_head->log_length;
+ zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
+ rec->pl_len, "fsf_res", req->req_id);
}
- spin_unlock_irqrestore(&dbf->hba_lock, flags);
-}
-
-void _zfcp_dbf_hba_fsf_unsol(const char *tag, int level, struct zfcp_dbf *dbf,
- struct fsf_status_read_buffer *status_buffer)
-{
- struct zfcp_dbf_hba_record *rec = &dbf->hba_buf;
- unsigned long flags;
-
- spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE);
-
- rec->u.status.failed = atomic_read(&dbf->adapter->stat_miss);
- if (status_buffer != NULL) {
- rec->u.status.status_type = status_buffer->status_type;
- rec->u.status.status_subtype = status_buffer->status_subtype;
- memcpy(&rec->u.status.queue_designator,
- &status_buffer->queue_designator,
- sizeof(struct fsf_queue_designator));
-
- switch (status_buffer->status_type) {
- case FSF_STATUS_READ_SENSE_DATA_AVAIL:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL;
- break;
-
- case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD;
- break;
-
- case FSF_STATUS_READ_LINK_DOWN:
- switch (status_buffer->status_subtype) {
- case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
- case FSF_STATUS_READ_SUB_FDISC_FAILED:
- rec->u.status.payload_size =
- sizeof(struct fsf_link_down_info);
- }
- break;
-
- case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
- rec->u.status.payload_size =
- ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT;
- break;
- }
- memcpy(&rec->u.status.payload,
- &status_buffer->payload, rec->u.status.payload_size);
- }
-
- debug_event(dbf->hba, level, rec, sizeof(*rec));
+ debug_event(dbf->hba, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
/**
- * zfcp_dbf_hba_qdio - trace event for QDIO related failure
- * @qdio: qdio structure affected by this QDIO related event
- * @qdio_error: as passed by qdio module
- * @sbal_index: first buffer with error condition, as passed by qdio module
- * @sbal_count: number of buffers affected, as passed by qdio module
+ * zfcp_dbf_hba_fsf_uss - trace event for an unsolicited status buffer
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request providing the unsolicited status
*/
-void zfcp_dbf_hba_qdio(struct zfcp_dbf *dbf, unsigned int qdio_error,
- int sbal_index, int sbal_count)
+void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)
{
- struct zfcp_dbf_hba_record *r = &dbf->hba_buf;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct fsf_status_read_buffer *srb = req->data;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE);
- r->u.qdio.qdio_error = qdio_error;
- r->u.qdio.sbal_index = sbal_index;
- r->u.qdio.sbal_count = sbal_count;
- debug_event(dbf->hba, 0, r, sizeof(*r));
+ memset(rec, 0, sizeof(*rec));
+
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_USS;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+
+ if (!srb)
+ goto log;
+
+ rec->u.uss.status_type = srb->status_type;
+ rec->u.uss.status_subtype = srb->status_subtype;
+ rec->u.uss.d_id = ntoh24(srb->d_id);
+ rec->u.uss.lun = srb->fcp_lun;
+ memcpy(&rec->u.uss.queue_designator, &srb->queue_designator,
+ sizeof(rec->u.uss.queue_designator));
+
+ /* status read buffer payload length */
+ rec->pl_len = (!srb->length) ? 0 : srb->length -
+ offsetof(struct fsf_status_read_buffer, payload);
+
+ if (rec->pl_len)
+ zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len,
+ "fsf_uss", req->req_id);
+log:
+ debug_event(dbf->hba, 2, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
/**
- * zfcp_dbf_hba_berr - trace event for bit error threshold
- * @dbf: dbf structure affected by this QDIO related event
- * @req: fsf request
+ * zfcp_dbf_hba_bit_err - trace event for bit error conditions
+ * @tag: tag indicating which kind of unsolicited status has been received
+ * @req: request which caused the bit_error condition
*/
-void zfcp_dbf_hba_berr(struct zfcp_dbf *dbf, struct zfcp_fsf_req *req)
+void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req)
{
- struct zfcp_dbf_hba_record *r = &dbf->hba_buf;
+ struct zfcp_dbf *dbf = req->adapter->dbf;
+ struct zfcp_dbf_hba *rec = &dbf->hba_buf;
struct fsf_status_read_buffer *sr_buf = req->data;
- struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
unsigned long flags;
spin_lock_irqsave(&dbf->hba_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE);
- memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload));
- debug_event(dbf->hba, 0, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->hba_lock, flags);
-}
-static void zfcp_dbf_hba_view_response(char **p,
- struct zfcp_dbf_hba_record_response *r)
-{
- struct timespec t;
-
- zfcp_dbf_out(p, "fsf_command", "0x%08x", r->fsf_command);
- zfcp_dbf_out(p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(p, "fsf_seqno", "0x%08x", r->fsf_seqno);
- stck_to_timespec(r->fsf_issued, &t);
- zfcp_dbf_out(p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec);
- zfcp_dbf_out(p, "fsf_prot_status", "0x%08x", r->fsf_prot_status);
- zfcp_dbf_out(p, "fsf_status", "0x%08x", r->fsf_status);
- zfcp_dbf_outd(p, "fsf_prot_status_qual", r->fsf_prot_status_qual,
- FSF_PROT_STATUS_QUAL_SIZE, 0, FSF_PROT_STATUS_QUAL_SIZE);
- zfcp_dbf_outd(p, "fsf_status_qual", r->fsf_status_qual,
- FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE);
- zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status);
- zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first);
- zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last);
- zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response);
- zfcp_dbf_out(p, "pool", "0x%02x", r->pool);
-
- switch (r->fsf_command) {
- case FSF_QTCB_FCP_CMND:
- if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
- break;
- zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
- zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
- *p += sprintf(*p, "\n");
- break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- case FSF_QTCB_CLOSE_PORT:
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.port.wwpn);
- zfcp_dbf_out(p, "d_id", "0x%06x", r->u.port.d_id);
- zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.port.port_handle);
- break;
-
- case FSF_QTCB_OPEN_LUN:
- case FSF_QTCB_CLOSE_LUN:
- zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.unit.wwpn);
- zfcp_dbf_out(p, "fcp_lun", "0x%016Lx", r->u.unit.fcp_lun);
- zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.unit.port_handle);
- zfcp_dbf_out(p, "lun_handle", "0x%08x", r->u.unit.lun_handle);
- break;
-
- case FSF_QTCB_SEND_ELS:
- zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id);
- break;
-
- case FSF_QTCB_ABORT_FCP_CMND:
- case FSF_QTCB_SEND_GENERIC:
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- case FSF_QTCB_EXCHANGE_PORT_DATA:
- case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
- case FSF_QTCB_UPLOAD_CONTROL_FILE:
- break;
- }
-}
-
-static void zfcp_dbf_hba_view_status(char **p,
- struct zfcp_dbf_hba_record_status *r)
-{
- zfcp_dbf_out(p, "failed", "0x%02x", r->failed);
- zfcp_dbf_out(p, "status_type", "0x%08x", r->status_type);
- zfcp_dbf_out(p, "status_subtype", "0x%08x", r->status_subtype);
- zfcp_dbf_outd(p, "queue_designator", (char *)&r->queue_designator,
- sizeof(struct fsf_queue_designator), 0,
- sizeof(struct fsf_queue_designator));
- zfcp_dbf_outd(p, "payload", (char *)&r->payload, r->payload_size, 0,
- r->payload_size);
-}
-
-static void zfcp_dbf_hba_view_qdio(char **p, struct zfcp_dbf_hba_record_qdio *r)
-{
- zfcp_dbf_out(p, "qdio_error", "0x%08x", r->qdio_error);
- zfcp_dbf_out(p, "sbal_index", "0x%02x", r->sbal_index);
- zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count);
-}
+ memset(rec, 0, sizeof(*rec));
-static void zfcp_dbf_hba_view_berr(char **p, struct fsf_bit_error_payload *r)
-{
- zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count);
- zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count);
- zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count);
- zfcp_dbf_out(p, "prim_seq_err", "%d",
- r->primitive_sequence_error_count);
- zfcp_dbf_out(p, "inval_trans_word_err", "%d",
- r->invalid_transmission_word_error_count);
- zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count);
- zfcp_dbf_out(p, "prim_seq_event_to", "%d",
- r->primitive_sequence_event_timeout_count);
- zfcp_dbf_out(p, "elast_buf_overrun_err", "%d",
- r->elastic_buffer_overrun_error_count);
- zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d",
- r->advertised_receive_b2b_credit);
- zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d",
- r->current_receive_b2b_credit);
- zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d",
- r->advertised_transmit_b2b_credit);
- zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d",
- r->current_transmit_b2b_credit);
-}
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_HBA_BIT;
+ rec->fsf_req_id = req->req_id;
+ rec->fsf_req_status = req->status;
+ rec->fsf_cmd = req->fsf_command;
+ memcpy(&rec->u.be, &sr_buf->payload.bit_error,
+ sizeof(struct fsf_bit_error_payload));
-static int zfcp_dbf_hba_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_hba_record *r = (struct zfcp_dbf_hba_record *)in_buf;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- if (isalpha(r->tag2[0]))
- zfcp_dbf_tag(&p, "tag2", r->tag2);
-
- if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_response(&p, &r->u.response);
- else if (strncmp(r->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_status(&p, &r->u.status);
- else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_qdio(&p, &r->u.qdio);
- else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_hba_view_berr(&p, &r->u.berr);
-
- if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0)
- p += sprintf(p, "\n");
- return p - out_buf;
+ debug_event(dbf->hba, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
-static struct debug_view zfcp_dbf_hba_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_hba_view_format,
-};
-
-static const char *zfcp_dbf_rec_tags[] = {
- [ZFCP_REC_DBF_ID_THREAD] = "thread",
- [ZFCP_REC_DBF_ID_TARGET] = "target",
- [ZFCP_REC_DBF_ID_TRIGGER] = "trigger",
- [ZFCP_REC_DBF_ID_ACTION] = "action",
-};
-
-static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view,
- char *buf, const char *_rec)
+static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
+ struct zfcp_adapter *adapter,
+ struct zfcp_port *port,
+ struct scsi_device *sdev)
{
- struct zfcp_dbf_rec_record *r = (struct zfcp_dbf_rec_record *)_rec;
- char *p = buf;
- char hint[ZFCP_DBF_ID_SIZE + 1];
-
- memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE);
- hint[ZFCP_DBF_ID_SIZE] = 0;
- zfcp_dbf_outs(&p, "tag", zfcp_dbf_rec_tags[r->id]);
- zfcp_dbf_outs(&p, "hint", hint);
- switch (r->id) {
- case ZFCP_REC_DBF_ID_THREAD:
- zfcp_dbf_out(&p, "total", "%d", r->u.thread.total);
- zfcp_dbf_out(&p, "ready", "%d", r->u.thread.ready);
- zfcp_dbf_out(&p, "running", "%d", r->u.thread.running);
- break;
- case ZFCP_REC_DBF_ID_TARGET:
- zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.target.ref);
- zfcp_dbf_out(&p, "status", "0x%08x", r->u.target.status);
- zfcp_dbf_out(&p, "erp_count", "%d", r->u.target.erp_count);
- zfcp_dbf_out(&p, "d_id", "0x%06x", r->u.target.d_id);
- zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.target.wwpn);
- zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.target.fcp_lun);
- break;
- case ZFCP_REC_DBF_ID_TRIGGER:
- zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.trigger.ref);
- zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.trigger.action);
- zfcp_dbf_out(&p, "requested", "%d", r->u.trigger.want);
- zfcp_dbf_out(&p, "executed", "%d", r->u.trigger.need);
- zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.trigger.wwpn);
- zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun);
- zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as);
- zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps);
- zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls);
- break;
- case ZFCP_REC_DBF_ID_ACTION:
- zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action);
- zfcp_dbf_out(&p, "fsf_req", "0x%016Lx", r->u.action.fsf_req);
- zfcp_dbf_out(&p, "status", "0x%08Lx", r->u.action.status);
- zfcp_dbf_out(&p, "step", "0x%08Lx", r->u.action.step);
- break;
+ rec->adapter_status = atomic_read(&adapter->status);
+ if (port) {
+ rec->port_status = atomic_read(&port->status);
+ rec->wwpn = port->wwpn;
+ rec->d_id = port->d_id;
+ }
+ if (sdev) {
+ rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
+ rec->lun = zfcp_scsi_dev_lun(sdev);
}
- p += sprintf(p, "\n");
- return p - buf;
}
-static struct debug_view zfcp_dbf_rec_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_rec_view_format,
-};
-
/**
- * zfcp_dbf_rec_thread - trace event related to recovery thread operation
- * @id2: identifier for event
- * @dbf: reference to dbf structure
- * This function assumes that the caller is holding erp_lock.
+ * zfcp_dbf_rec_trig - trace event related to triggered recovery
+ * @tag: identifier for event
+ * @adapter: adapter on which the erp_action should run
+ * @port: remote port involved in the erp_action
+ * @sdev: scsi device involved in the erp_action
+ * @want: wanted erp_action
+ * @need: required erp_action
+ *
+ * The adapter->erp_lock has to be held.
*/
-void zfcp_dbf_rec_thread(char *id2, struct zfcp_dbf *dbf)
+void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter,
+ struct zfcp_port *port, struct scsi_device *sdev,
+ u8 want, u8 need)
{
- struct zfcp_adapter *adapter = dbf->adapter;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
- unsigned long flags = 0;
+ struct zfcp_dbf *dbf = adapter->dbf;
+ struct zfcp_dbf_rec *rec = &dbf->rec_buf;
struct list_head *entry;
- unsigned ready = 0, running = 0, total;
-
- list_for_each(entry, &adapter->erp_ready_head)
- ready++;
- list_for_each(entry, &adapter->erp_running_head)
- running++;
- total = adapter->erp_total_count;
-
- spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_THREAD;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.thread.total = total;
- r->u.thread.ready = ready;
- r->u.thread.running = running;
- debug_event(dbf->rec, 6, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
-
-/**
- * zfcp_dbf_rec_thread - trace event related to recovery thread operation
- * @id2: identifier for event
- * @adapter: adapter
- * This function assumes that the caller does not hold erp_lock.
- */
-void zfcp_dbf_rec_thread_lock(char *id2, struct zfcp_dbf *dbf)
-{
- struct zfcp_adapter *adapter = dbf->adapter;
- unsigned long flags;
-
- read_lock_irqsave(&adapter->erp_lock, flags);
- zfcp_dbf_rec_thread(id2, dbf);
- read_unlock_irqrestore(&adapter->erp_lock, flags);
-}
-
-static void zfcp_dbf_rec_target(char *id2, void *ref, struct zfcp_dbf *dbf,
- atomic_t *status, atomic_t *erp_count, u64 wwpn,
- u32 d_id, u64 fcp_lun)
-{
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_TARGET;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.target.ref = (unsigned long)ref;
- r->u.target.status = atomic_read(status);
- r->u.target.wwpn = wwpn;
- r->u.target.d_id = d_id;
- r->u.target.fcp_lun = fcp_lun;
- r->u.target.erp_count = atomic_read(erp_count);
- debug_event(dbf->rec, 3, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
-
-/**
- * zfcp_dbf_rec_adapter - trace event for adapter state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @dbf: reference to dbf structure
- */
-void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf)
-{
- struct zfcp_adapter *adapter = dbf->adapter;
-
- zfcp_dbf_rec_target(id, ref, dbf, &adapter->status,
- &adapter->erp_counter, 0, 0,
- ZFCP_DBF_INVALID_LUN);
-}
-
-/**
- * zfcp_dbf_rec_port - trace event for port state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @port: port
- */
-void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port)
-{
- struct zfcp_dbf *dbf = port->adapter->dbf;
+ memset(rec, 0, sizeof(*rec));
- zfcp_dbf_rec_target(id, ref, dbf, &port->status,
- &port->erp_counter, port->wwpn, port->d_id,
- ZFCP_DBF_INVALID_LUN);
-}
+ rec->id = ZFCP_DBF_REC_TRIG;
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ zfcp_dbf_set_common(rec, adapter, port, sdev);
-/**
- * zfcp_dbf_rec_lun - trace event for LUN state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @sdev: SCSI device
- */
-void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev)
-{
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- struct zfcp_port *port = zfcp_sdev->port;
- struct zfcp_dbf *dbf = port->adapter->dbf;
+ list_for_each(entry, &adapter->erp_ready_head)
+ rec->u.trig.ready++;
- zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status,
- &zfcp_sdev->erp_counter, port->wwpn, port->d_id,
- zfcp_scsi_dev_lun(sdev));
-}
+ list_for_each(entry, &adapter->erp_running_head)
+ rec->u.trig.running++;
-/**
- * zfcp_dbf_rec_trigger - trace event for triggered error recovery
- * @id2: identifier for error recovery trigger
- * @ref: additional reference (e.g. request)
- * @want: originally requested error recovery action
- * @need: error recovery action actually initiated
- * @action: address of error recovery action struct
- * @adapter: adapter
- * @port: port
- * @sdev: SCSI device
- */
-void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action,
- struct zfcp_adapter *adapter, struct zfcp_port *port,
- struct scsi_device *sdev)
-{
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
- unsigned long flags;
+ rec->u.trig.want = want;
+ rec->u.trig.need = need;
- spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_TRIGGER;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.trigger.ref = (unsigned long)ref;
- r->u.trigger.want = want;
- r->u.trigger.need = need;
- r->u.trigger.action = (unsigned long)action;
- r->u.trigger.as = atomic_read(&adapter->status);
- if (port) {
- r->u.trigger.ps = atomic_read(&port->status);
- r->u.trigger.wwpn = port->wwpn;
- }
- if (sdev)
- r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status);
- r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) :
- ZFCP_DBF_INVALID_LUN;
- debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r));
+ debug_event(dbf->rec, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
+
/**
- * zfcp_dbf_rec_action - trace event showing progress of recovery action
- * @id2: identifier
- * @erp_action: error recovery action struct pointer
+ * zfcp_dbf_rec_run - trace event related to running recovery
+ * @tag: identifier for event
+ * @erp: erp_action running
*/
-void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action)
+void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
{
- struct zfcp_dbf *dbf = erp_action->adapter->dbf;
- struct zfcp_dbf_rec_record *r = &dbf->rec_buf;
+ struct zfcp_dbf *dbf = erp->adapter->dbf;
+ struct zfcp_dbf_rec *rec = &dbf->rec_buf;
unsigned long flags;
spin_lock_irqsave(&dbf->rec_lock, flags);
- memset(r, 0, sizeof(*r));
- r->id = ZFCP_REC_DBF_ID_ACTION;
- memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE);
- r->u.action.action = (unsigned long)erp_action;
- r->u.action.status = erp_action->status;
- r->u.action.step = erp_action->step;
- r->u.action.fsf_req = erp_action->fsf_req_id;
- debug_event(dbf->rec, 5, r, sizeof(*r));
- spin_unlock_irqrestore(&dbf->rec_lock, flags);
-}
+ memset(rec, 0, sizeof(*rec));
-/**
- * zfcp_dbf_san_ct_request - trace event for issued CT request
- * @fsf_req: request containing issued CT data
- * @d_id: destination id where ct request is sent to
- */
-void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id)
-{
- struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct zfcp_dbf *dbf = adapter->dbf;
- struct fc_ct_hdr *hdr = sg_virt(ct->req);
- struct zfcp_dbf_san_record *r = &dbf->san_buf;
- struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req;
- int level = 3;
- unsigned long flags;
+ rec->id = ZFCP_DBF_REC_RUN;
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ zfcp_dbf_set_common(rec, erp->adapter, erp->port, erp->sdev);
- spin_lock_irqsave(&dbf->san_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
- r->fsf_reqid = fsf_req->req_id;
- r->fsf_seqno = fsf_req->seq_no;
- oct->d_id = d_id;
- oct->cmd_req_code = hdr->ct_cmd;
- oct->revision = hdr->ct_rev;
- oct->gs_type = hdr->ct_fs_type;
- oct->gs_subtype = hdr->ct_fs_subtype;
- oct->options = hdr->ct_options;
- oct->max_res_size = hdr->ct_mr_size;
- oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr),
- ZFCP_DBF_SAN_MAX_PAYLOAD);
- debug_event(dbf->san, level, r, sizeof(*r));
- zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct fc_ct_hdr), oct->len);
- spin_unlock_irqrestore(&dbf->san_lock, flags);
-}
+ rec->u.run.fsf_req_id = erp->fsf_req_id;
+ rec->u.run.rec_status = erp->status;
+ rec->u.run.rec_step = erp->step;
+ rec->u.run.rec_action = erp->action;
-/**
- * zfcp_dbf_san_ct_response - trace event for completion of CT request
- * @fsf_req: request containing CT response
- */
-void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
-{
- struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct fc_ct_hdr *hdr = sg_virt(ct->resp);
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_san_record *r = &dbf->san_buf;
- struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp;
- int level = 3;
- unsigned long flags;
+ if (erp->sdev)
+ rec->u.run.rec_count =
+ atomic_read(&sdev_to_zfcp(erp->sdev)->erp_counter);
+ else if (erp->port)
+ rec->u.run.rec_count = atomic_read(&erp->port->erp_counter);
+ else
+ rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter);
- spin_lock_irqsave(&dbf->san_lock, flags);
- memset(r, 0, sizeof(*r));
- strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
- r->fsf_reqid = fsf_req->req_id;
- r->fsf_seqno = fsf_req->seq_no;
- rct->cmd_rsp_code = hdr->ct_cmd;
- rct->revision = hdr->ct_rev;
- rct->reason_code = hdr->ct_reason;
- rct->expl = hdr->ct_explan;
- rct->vendor_unique = hdr->ct_vendor;
- rct->max_res_size = hdr->ct_mr_size;
- rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr),
- ZFCP_DBF_SAN_MAX_PAYLOAD);
- debug_event(dbf->san, level, r, sizeof(*r));
- zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level,
- (void *)hdr + sizeof(struct fc_ct_hdr), rct->len);
- spin_unlock_irqrestore(&dbf->san_lock, flags);
+ debug_event(dbf->rec, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
-static void zfcp_dbf_san_els(const char *tag, int level,
- struct zfcp_fsf_req *fsf_req, u32 d_id,
- void *buffer, int buflen)
+static inline
+void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
+ u64 req_id, u32 d_id)
{
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct zfcp_dbf *dbf = adapter->dbf;
- struct zfcp_dbf_san_record *rec = &dbf->san_buf;
+ struct zfcp_dbf_san *rec = &dbf->san_buf;
+ u16 rec_len;
unsigned long flags;
spin_lock_irqsave(&dbf->san_lock, flags);
memset(rec, 0, sizeof(*rec));
- strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
- rec->fsf_reqid = fsf_req->req_id;
- rec->fsf_seqno = fsf_req->seq_no;
- rec->u.els.d_id = d_id;
- debug_event(dbf->san, level, rec, sizeof(*rec));
- zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level,
- buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD));
+
+ rec->id = id;
+ rec->fsf_req_id = req_id;
+ rec->d_id = d_id;
+ rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD);
+ memcpy(rec->payload, data, rec_len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+
+ debug_event(dbf->san, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->san_lock, flags);
}
/**
- * zfcp_dbf_san_els_request - trace event for issued ELS
- * @fsf_req: request containing issued ELS
+ * zfcp_dbf_san_req - trace event for issued SAN request
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
+ * d_id: destination ID
*/
-void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)
{
- struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
- u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct zfcp_fsf_ct_els *ct_els = fsf->data;
+ u16 length;
- zfcp_dbf_san_els("oels", 2, fsf_req, d_id,
- sg_virt(els->req), els->req->length);
+ length = (u16)(ct_els->req->length + FC_CT_HDR_LEN);
+ zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length,
+ fsf->req_id, d_id);
}
/**
- * zfcp_dbf_san_els_response - trace event for completed ELS
- * @fsf_req: request containing ELS response
+ * zfcp_dbf_san_res - trace event for received SAN request
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
*/
-void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)
{
- struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data;
- u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct zfcp_fsf_ct_els *ct_els = fsf->data;
+ u16 length;
- zfcp_dbf_san_els("rels", 2, fsf_req, d_id,
- sg_virt(els->resp), els->resp->length);
+ length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN);
+ zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length,
+ fsf->req_id, 0);
}
/**
- * zfcp_dbf_san_incoming_els - trace event for incomig ELS
- * @fsf_req: request containing unsolicited status buffer with incoming ELS
+ * zfcp_dbf_san_in_els - trace event for incoming ELS
+ * @tag: indentifier for event
+ * @fsf_req: request containing issued CT data
*/
-void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
{
- struct fsf_status_read_buffer *buf =
- (struct fsf_status_read_buffer *)fsf_req->data;
- int length = (int)buf->length -
- (int)((void *)&buf->payload - (void *)buf);
+ struct zfcp_dbf *dbf = fsf->adapter->dbf;
+ struct fsf_status_read_buffer *srb =
+ (struct fsf_status_read_buffer *) fsf->data;
+ u16 length;
- zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id),
- (void *)buf->payload.data, length);
-}
-
-static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_san_record *r = (struct zfcp_dbf_san_record *)in_buf;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno);
-
- if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req;
- zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id);
- zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code);
- zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision);
- zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type);
- zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype);
- zfcp_dbf_out(&p, "options", "0x%02x", ct->options);
- zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
- } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_ct_response *ct = &r->u.ct_resp;
- zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code);
- zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision);
- zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code);
- zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl);
- zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique);
- zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
- } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
- strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
- strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
- struct zfcp_dbf_san_record_els *els = &r->u.els;
- zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id);
- }
- return p - out_buf;
+ length = (u16)(srb->length -
+ offsetof(struct fsf_status_read_buffer, payload));
+ zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length,
+ fsf->req_id, ntoh24(srb->d_id));
}
-static struct debug_view zfcp_dbf_san_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_san_view_format,
-};
-
-void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
- struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd,
- struct zfcp_fsf_req *fsf_req, unsigned long old_req_id)
+/**
+ * zfcp_dbf_scsi - trace event for scsi commands
+ * @tag: identifier for event
+ * @sc: pointer to struct scsi_cmnd
+ * @fsf: pointer to struct zfcp_fsf_req
+ */
+void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
{
- struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf;
- struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
- unsigned long flags;
+ struct zfcp_adapter *adapter =
+ (struct zfcp_adapter *) sc->device->host->hostdata[0];
+ struct zfcp_dbf *dbf = adapter->dbf;
+ struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;
struct fcp_resp_with_ext *fcp_rsp;
- struct fcp_resp_rsp_info *fcp_rsp_info = NULL;
- char *fcp_sns_info = NULL;
- int offset = 0, buflen = 0;
+ struct fcp_resp_rsp_info *fcp_rsp_info;
+ unsigned long flags;
spin_lock_irqsave(&dbf->scsi_lock, flags);
- do {
- memset(rec, 0, sizeof(*rec));
- if (offset == 0) {
- strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
- strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
- if (scsi_cmnd != NULL) {
- if (scsi_cmnd->device) {
- rec->scsi_id = scsi_cmnd->device->id;
- rec->scsi_lun = scsi_cmnd->device->lun;
- }
- rec->scsi_result = scsi_cmnd->result;
- rec->scsi_cmnd = (unsigned long)scsi_cmnd;
- memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
- min((int)scsi_cmnd->cmd_len,
- ZFCP_DBF_SCSI_OPCODE));
- rec->scsi_retries = scsi_cmnd->retries;
- rec->scsi_allowed = scsi_cmnd->allowed;
- }
- if (fsf_req != NULL) {
- fcp_rsp = (struct fcp_resp_with_ext *)
- &(fsf_req->qtcb->bottom.io.fcp_rsp);
- fcp_rsp_info = (struct fcp_resp_rsp_info *)
- &fcp_rsp[1];
- fcp_sns_info = (char *) &fcp_rsp[1];
- if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
- fcp_sns_info += fcp_rsp->ext.fr_sns_len;
-
- rec->rsp_validity = fcp_rsp->resp.fr_flags;
- rec->rsp_scsi_status = fcp_rsp->resp.fr_status;
- rec->rsp_resid = fcp_rsp->ext.fr_resid;
- if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL)
- rec->rsp_code = fcp_rsp_info->rsp_code;
- if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
- buflen = min(fcp_rsp->ext.fr_sns_len,
- (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
- rec->sns_info_len = buflen;
- memcpy(rec->sns_info, fcp_sns_info,
- min(buflen,
- ZFCP_DBF_SCSI_FCP_SNS_INFO));
- offset += min(buflen,
- ZFCP_DBF_SCSI_FCP_SNS_INFO);
- }
-
- rec->fsf_reqid = fsf_req->req_id;
- rec->fsf_seqno = fsf_req->seq_no;
- rec->fsf_issued = fsf_req->issued;
- }
- rec->old_fsf_reqid = old_req_id;
- } else {
- strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
- dump->total_size = buflen;
- dump->offset = offset;
- dump->size = min(buflen - offset,
- (int)sizeof(struct
- zfcp_dbf_scsi_record) -
- (int)sizeof(struct zfcp_dbf_dump));
- memcpy(dump->data, fcp_sns_info + offset, dump->size);
- offset += dump->size;
- }
- debug_event(dbf->scsi, level, rec, sizeof(*rec));
- } while (offset < buflen);
- spin_unlock_irqrestore(&dbf->scsi_lock, flags);
-}
+ memset(rec, 0, sizeof(*rec));
-static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view,
- char *out_buf, const char *in_buf)
-{
- struct zfcp_dbf_scsi_record *r = (struct zfcp_dbf_scsi_record *)in_buf;
- struct timespec t;
- char *p = out_buf;
-
- if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
- return 0;
-
- zfcp_dbf_tag(&p, "tag", r->tag);
- zfcp_dbf_tag(&p, "tag2", r->tag2);
- zfcp_dbf_out(&p, "scsi_id", "0x%08x", r->scsi_id);
- zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun);
- zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result);
- zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd);
- zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE,
- 0, ZFCP_DBF_SCSI_OPCODE);
- zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries);
- zfcp_dbf_out(&p, "scsi_allowed", "0x%02x", r->scsi_allowed);
- if (strncmp(r->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0)
- zfcp_dbf_out(&p, "old_fsf_reqid", "0x%0Lx", r->old_fsf_reqid);
- zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid);
- zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno);
- stck_to_timespec(r->fsf_issued, &t);
- zfcp_dbf_out(&p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec);
-
- if (strncmp(r->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) {
- zfcp_dbf_out(&p, "fcp_rsp_validity", "0x%02x", r->rsp_validity);
- zfcp_dbf_out(&p, "fcp_rsp_scsi_status", "0x%02x",
- r->rsp_scsi_status);
- zfcp_dbf_out(&p, "fcp_rsp_resid", "0x%08x", r->rsp_resid);
- zfcp_dbf_out(&p, "fcp_rsp_code", "0x%08x", r->rsp_code);
- zfcp_dbf_out(&p, "fcp_sns_info_len", "0x%08x", r->sns_info_len);
- zfcp_dbf_outd(&p, "fcp_sns_info", r->sns_info,
- min((int)r->sns_info_len,
- ZFCP_DBF_SCSI_FCP_SNS_INFO), 0,
- r->sns_info_len);
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->id = ZFCP_DBF_SCSI_CMND;
+ rec->scsi_result = sc->result;
+ rec->scsi_retries = sc->retries;
+ rec->scsi_allowed = sc->allowed;
+ rec->scsi_id = sc->device->id;
+ rec->scsi_lun = sc->device->lun;
+ rec->host_scribble = (unsigned long)sc->host_scribble;
+
+ memcpy(rec->scsi_opcode, sc->cmnd,
+ min((int)sc->cmd_len, ZFCP_DBF_SCSI_OPCODE));
+
+ if (fsf) {
+ rec->fsf_req_id = fsf->req_id;
+ fcp_rsp = (struct fcp_resp_with_ext *)
+ &(fsf->qtcb->bottom.io.fcp_rsp);
+ memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
+ if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
+ fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
+ rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
+ }
+ if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
+ rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE,
+ (u16)ZFCP_DBF_PAY_MAX_REC);
+ zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len,
+ "fcp_sns", fsf->req_id);
+ }
}
- p += sprintf(p, "\n");
- return p - out_buf;
-}
-static struct debug_view zfcp_dbf_scsi_view = {
- .name = "structured",
- .header_proc = zfcp_dbf_view_header,
- .format_proc = zfcp_dbf_scsi_view_format,
-};
+ debug_event(dbf->scsi, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->scsi_lock, flags);
+}
-static debug_info_t *zfcp_dbf_reg(const char *name, int level,
- struct debug_view *view, int size)
+static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size)
{
struct debug_info *d;
- d = debug_register(name, dbfsize, level, size);
+ d = debug_register(name, size, 1, rec_size);
if (!d)
return NULL;
debug_register_view(d, &debug_hex_ascii_view);
- debug_register_view(d, view);
- debug_set_level(d, level);
+ debug_set_level(d, 3);
return d;
}
+static void zfcp_dbf_unregister(struct zfcp_dbf *dbf)
+{
+ if (!dbf)
+ return;
+
+ debug_unregister(dbf->scsi);
+ debug_unregister(dbf->san);
+ debug_unregister(dbf->hba);
+ debug_unregister(dbf->pay);
+ debug_unregister(dbf->rec);
+ kfree(dbf);
+}
+
/**
* zfcp_adapter_debug_register - registers debug feature for an adapter
* @adapter: pointer to adapter for which debug features should be registered
@@ -1003,69 +415,66 @@ static debug_info_t *zfcp_dbf_reg(const char *name, int level,
*/
int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)
{
- char dbf_name[DEBUG_MAX_NAME_LEN];
+ char name[DEBUG_MAX_NAME_LEN];
struct zfcp_dbf *dbf;
dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
if (!dbf)
return -ENOMEM;
- dbf->adapter = adapter;
-
+ spin_lock_init(&dbf->pay_lock);
spin_lock_init(&dbf->hba_lock);
spin_lock_init(&dbf->san_lock);
spin_lock_init(&dbf->scsi_lock);
spin_lock_init(&dbf->rec_lock);
/* debug feature area which records recovery activity */
- sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev));
- dbf->rec = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_rec_view,
- sizeof(struct zfcp_dbf_rec_record));
+ sprintf(name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev));
+ dbf->rec = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_rec));
if (!dbf->rec)
goto err_out;
/* debug feature area which records HBA (FSF and QDIO) conditions */
- sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev));
- dbf->hba = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_hba_view,
- sizeof(struct zfcp_dbf_hba_record));
+ sprintf(name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev));
+ dbf->hba = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_hba));
if (!dbf->hba)
goto err_out;
+ /* debug feature area which records payload info */
+ sprintf(name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev));
+ dbf->pay = zfcp_dbf_reg(name, dbfsize * 2, sizeof(struct zfcp_dbf_pay));
+ if (!dbf->pay)
+ goto err_out;
+
/* debug feature area which records SAN command failures and recovery */
- sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev));
- dbf->san = zfcp_dbf_reg(dbf_name, 6, &zfcp_dbf_san_view,
- sizeof(struct zfcp_dbf_san_record));
+ sprintf(name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev));
+ dbf->san = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_san));
if (!dbf->san)
goto err_out;
/* debug feature area which records SCSI command failures and recovery */
- sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev));
- dbf->scsi = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_scsi_view,
- sizeof(struct zfcp_dbf_scsi_record));
+ sprintf(name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev));
+ dbf->scsi = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_scsi));
if (!dbf->scsi)
goto err_out;
adapter->dbf = dbf;
- return 0;
+ return 0;
err_out:
- zfcp_dbf_adapter_unregister(dbf);
+ zfcp_dbf_unregister(dbf);
return -ENOMEM;
}
/**
* zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
- * @dbf: pointer to dbf for which debug features should be unregistered
+ * @adapter: pointer to adapter for which debug features should be unregistered
*/
-void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf)
+void zfcp_dbf_adapter_unregister(struct zfcp_adapter *adapter)
{
- if (!dbf)
- return;
- debug_unregister(dbf->scsi);
- debug_unregister(dbf->san);
- debug_unregister(dbf->hba);
- debug_unregister(dbf->rec);
- dbf->adapter->dbf = NULL;
- kfree(dbf);
+ struct zfcp_dbf *dbf = adapter->dbf;
+
+ adapter->dbf = NULL;
+ zfcp_dbf_unregister(dbf);
}
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 04081b1b62b4..714f087eb7a9 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -1,22 +1,8 @@
/*
- * This file is part of the zfcp device driver for
- * FCP adapters for IBM System z9 and zSeries.
+ * zfcp device driver
+ * debug feature declarations
*
- * Copyright IBM Corp. 2008, 2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Copyright IBM Corp. 2008, 2010
*/
#ifndef ZFCP_DBF_H
@@ -27,322 +13,350 @@
#include "zfcp_fsf.h"
#include "zfcp_def.h"
-#define ZFCP_DBF_TAG_SIZE 4
-#define ZFCP_DBF_ID_SIZE 7
+#define ZFCP_DBF_TAG_LEN 7
#define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull
-struct zfcp_dbf_dump {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u32 total_size; /* size of total dump data */
- u32 offset; /* how much data has being already dumped */
- u32 size; /* how much data comes with this record */
- u8 data[]; /* dump data */
-} __attribute__ ((packed));
-
-struct zfcp_dbf_rec_record_thread {
- u32 total;
+/**
+ * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action
+ * @ready: number of ready recovery actions
+ * @running: number of running recovery actions
+ * @want: wanted recovery action
+ * @need: needed recovery action
+ */
+struct zfcp_dbf_rec_trigger {
u32 ready;
u32 running;
-};
-
-struct zfcp_dbf_rec_record_target {
- u64 ref;
- u32 status;
- u32 d_id;
- u64 wwpn;
- u64 fcp_lun;
- u32 erp_count;
-};
-
-struct zfcp_dbf_rec_record_trigger {
u8 want;
u8 need;
- u32 as;
- u32 ps;
- u32 ls;
- u64 ref;
- u64 action;
- u64 wwpn;
- u64 fcp_lun;
-};
+} __packed;
-struct zfcp_dbf_rec_record_action {
- u32 status;
- u32 step;
- u64 action;
- u64 fsf_req;
+/**
+ * struct zfcp_dbf_rec_running - trace record for running recovery
+ * @fsf_req_id: request id for fsf requests
+ * @rec_status: status of the fsf request
+ * @rec_step: current step of the recovery action
+ * rec_count: recovery counter
+ */
+struct zfcp_dbf_rec_running {
+ u64 fsf_req_id;
+ u32 rec_status;
+ u16 rec_step;
+ u8 rec_action;
+ u8 rec_count;
+} __packed;
+
+/**
+ * enum zfcp_dbf_rec_id - recovery trace record id
+ * @ZFCP_DBF_REC_TRIG: triggered recovery identifier
+ * @ZFCP_DBF_REC_RUN: running recovery identifier
+ */
+enum zfcp_dbf_rec_id {
+ ZFCP_DBF_REC_TRIG = 1,
+ ZFCP_DBF_REC_RUN = 2,
};
-struct zfcp_dbf_rec_record {
+/**
+ * struct zfcp_dbf_rec - trace record for error recovery actions
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @lun: logical unit number
+ * @wwpn: word wide port number
+ * @d_id: destination ID
+ * @adapter_status: current status of the adapter
+ * @port_status: current status of the port
+ * @lun_status: current status of the lun
+ * @u.trig: structure zfcp_dbf_rec_trigger
+ * @u.run: structure zfcp_dbf_rec_running
+ */
+struct zfcp_dbf_rec {
u8 id;
- char id2[7];
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 lun;
+ u64 wwpn;
+ u32 d_id;
+ u32 adapter_status;
+ u32 port_status;
+ u32 lun_status;
union {
- struct zfcp_dbf_rec_record_action action;
- struct zfcp_dbf_rec_record_thread thread;
- struct zfcp_dbf_rec_record_target target;
- struct zfcp_dbf_rec_record_trigger trigger;
+ struct zfcp_dbf_rec_trigger trig;
+ struct zfcp_dbf_rec_running run;
} u;
-};
+} __packed;
-enum {
- ZFCP_REC_DBF_ID_ACTION,
- ZFCP_REC_DBF_ID_THREAD,
- ZFCP_REC_DBF_ID_TARGET,
- ZFCP_REC_DBF_ID_TRIGGER,
+/**
+ * enum zfcp_dbf_san_id - SAN trace record identifier
+ * @ZFCP_DBF_SAN_REQ: request trace record id
+ * @ZFCP_DBF_SAN_RES: response trace record id
+ * @ZFCP_DBF_SAN_ELS: extended link service record id
+ */
+enum zfcp_dbf_san_id {
+ ZFCP_DBF_SAN_REQ = 1,
+ ZFCP_DBF_SAN_RES = 2,
+ ZFCP_DBF_SAN_ELS = 3,
};
-struct zfcp_dbf_hba_record_response {
- u32 fsf_command;
- u64 fsf_reqid;
- u32 fsf_seqno;
- u64 fsf_issued;
- u32 fsf_prot_status;
+/** struct zfcp_dbf_san - trace record for SAN requests and responses
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @fsf_req_id: request id for fsf requests
+ * @payload: unformatted information related to request/response
+ * @d_id: destination id
+ */
+struct zfcp_dbf_san {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+ u32 d_id;
+#define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32)
+ char payload[ZFCP_DBF_SAN_MAX_PAYLOAD];
+} __packed;
+
+/**
+ * struct zfcp_dbf_hba_res - trace record for hba responses
+ * @req_issued: timestamp when request was issued
+ * @prot_status: protocol status
+ * @prot_status_qual: protocol status qualifier
+ * @fsf_status: fsf status
+ * @fsf_status_qual: fsf status qualifier
+ */
+struct zfcp_dbf_hba_res {
+ u64 req_issued;
+ u32 prot_status;
+ u8 prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
u32 fsf_status;
- u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
- u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
- u32 fsf_req_status;
- u8 sbal_first;
- u8 sbal_last;
- u8 sbal_response;
- u8 pool;
- u64 erp_action;
- union {
- struct {
- u64 cmnd;
- u32 data_dir;
- } fcp;
- struct {
- u64 wwpn;
- u32 d_id;
- u32 port_handle;
- } port;
- struct {
- u64 wwpn;
- u64 fcp_lun;
- u32 port_handle;
- u32 lun_handle;
- } unit;
- struct {
- u32 d_id;
- } els;
- } u;
-} __attribute__ ((packed));
+ u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+} __packed;
-struct zfcp_dbf_hba_record_status {
- u8 failed;
+/**
+ * struct zfcp_dbf_hba_uss - trace record for unsolicited status
+ * @status_type: type of unsolicited status
+ * @status_subtype: subtype of unsolicited status
+ * @d_id: destination ID
+ * @lun: logical unit number
+ * @queue_designator: queue designator
+ */
+struct zfcp_dbf_hba_uss {
u32 status_type;
u32 status_subtype;
- struct fsf_queue_designator
- queue_designator;
- u32 payload_size;
-#define ZFCP_DBF_UNSOL_PAYLOAD 80
-#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32
-#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56
-#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32)
- u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
-} __attribute__ ((packed));
-
-struct zfcp_dbf_hba_record_qdio {
- u32 qdio_error;
- u8 sbal_index;
- u8 sbal_count;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_hba_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u8 tag2[ZFCP_DBF_TAG_SIZE];
- union {
- struct zfcp_dbf_hba_record_response response;
- struct zfcp_dbf_hba_record_status status;
- struct zfcp_dbf_hba_record_qdio qdio;
- struct fsf_bit_error_payload berr;
- } u;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_ct_request {
- u16 cmd_req_code;
- u8 revision;
- u8 gs_type;
- u8 gs_subtype;
- u8 options;
- u16 max_res_size;
- u32 len;
- u32 d_id;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_ct_response {
- u16 cmd_rsp_code;
- u8 revision;
- u8 reason_code;
- u8 expl;
- u8 vendor_unique;
- u16 max_res_size;
- u32 len;
-} __attribute__ ((packed));
-
-struct zfcp_dbf_san_record_els {
u32 d_id;
-} __attribute__ ((packed));
+ u64 lun;
+ u64 queue_designator;
+} __packed;
-struct zfcp_dbf_san_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u64 fsf_reqid;
- u32 fsf_seqno;
+/**
+ * enum zfcp_dbf_hba_id - HBA trace record identifier
+ * @ZFCP_DBF_HBA_RES: response trace record
+ * @ZFCP_DBF_HBA_USS: unsolicited status trace record
+ * @ZFCP_DBF_HBA_BIT: bit error trace record
+ */
+enum zfcp_dbf_hba_id {
+ ZFCP_DBF_HBA_RES = 1,
+ ZFCP_DBF_HBA_USS = 2,
+ ZFCP_DBF_HBA_BIT = 3,
+};
+
+/**
+ * struct zfcp_dbf_hba - common trace record for HBA records
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @fsf_req_id: request id for fsf requests
+ * @fsf_req_status: status of fsf request
+ * @fsf_cmd: fsf command
+ * @fsf_seq_no: fsf sequence number
+ * @pl_len: length of payload stored as zfcp_dbf_pay
+ * @u: record type specific data
+ */
+struct zfcp_dbf_hba {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+ u32 fsf_req_status;
+ u32 fsf_cmd;
+ u32 fsf_seq_no;
+ u16 pl_len;
union {
- struct zfcp_dbf_san_record_ct_request ct_req;
- struct zfcp_dbf_san_record_ct_response ct_resp;
- struct zfcp_dbf_san_record_els els;
+ struct zfcp_dbf_hba_res res;
+ struct zfcp_dbf_hba_uss uss;
+ struct fsf_bit_error_payload be;
} u;
-} __attribute__ ((packed));
+} __packed;
-#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
+/**
+ * enum zfcp_dbf_scsi_id - scsi trace record identifier
+ * @ZFCP_DBF_SCSI_CMND: scsi command trace record
+ */
+enum zfcp_dbf_scsi_id {
+ ZFCP_DBF_SCSI_CMND = 1,
+};
-struct zfcp_dbf_scsi_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u8 tag2[ZFCP_DBF_TAG_SIZE];
+/**
+ * struct zfcp_dbf_scsi - common trace record for SCSI records
+ * @id: unique number of recovery record type
+ * @tag: identifier string specifying the location of initiation
+ * @scsi_id: scsi device id
+ * @scsi_lun: scsi device logical unit number
+ * @scsi_result: scsi result
+ * @scsi_retries: current retry number of scsi request
+ * @scsi_allowed: allowed retries
+ * @fcp_rsp_info: FCP response info
+ * @scsi_opcode: scsi opcode
+ * @fsf_req_id: request id of fsf request
+ * @host_scribble: LLD specific data attached to SCSI request
+ * @pl_len: length of paload stored as zfcp_dbf_pay
+ * @fsf_rsp: response for fsf request
+ */
+struct zfcp_dbf_scsi {
+ u8 id;
+ char tag[ZFCP_DBF_TAG_LEN];
u32 scsi_id;
u32 scsi_lun;
u32 scsi_result;
- u64 scsi_cmnd;
-#define ZFCP_DBF_SCSI_OPCODE 16
- u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
u8 scsi_retries;
u8 scsi_allowed;
- u64 fsf_reqid;
- u32 fsf_seqno;
- u64 fsf_issued;
- u64 old_fsf_reqid;
- u8 rsp_validity;
- u8 rsp_scsi_status;
- u32 rsp_resid;
- u8 rsp_code;
-#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16
-#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256
- u32 sns_info_len;
- u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
-} __attribute__ ((packed));
+ u8 fcp_rsp_info;
+#define ZFCP_DBF_SCSI_OPCODE 16
+ u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
+ u64 fsf_req_id;
+ u64 host_scribble;
+ u16 pl_len;
+ struct fcp_resp_with_ext fcp_rsp;
+} __packed;
+/**
+ * struct zfcp_dbf_pay - trace record for unformatted payload information
+ * @area: area this record is originated from
+ * @counter: ascending record number
+ * @fsf_req_id: request id of fsf request
+ * @data: unformatted data
+ */
+struct zfcp_dbf_pay {
+ u8 counter;
+ char area[ZFCP_DBF_TAG_LEN];
+ u64 fsf_req_id;
+#define ZFCP_DBF_PAY_MAX_REC 0x100
+ char data[ZFCP_DBF_PAY_MAX_REC];
+} __packed;
+
+/**
+ * struct zfcp_dbf - main dbf trace structure
+ * @pay: reference to payload trace area
+ * @rec: reference to recovery trace area
+ * @hba: reference to hba trace area
+ * @san: reference to san trace area
+ * @scsi: reference to scsi trace area
+ * @pay_lock: lock protecting payload trace buffer
+ * @rec_lock: lock protecting recovery trace buffer
+ * @hba_lock: lock protecting hba trace buffer
+ * @san_lock: lock protecting san trace buffer
+ * @scsi_lock: lock protecting scsi trace buffer
+ * @pay_buf: pre-allocated buffer for payload
+ * @rec_buf: pre-allocated buffer for recovery
+ * @hba_buf: pre-allocated buffer for hba
+ * @san_buf: pre-allocated buffer for san
+ * @scsi_buf: pre-allocated buffer for scsi
+ */
struct zfcp_dbf {
+ debug_info_t *pay;
debug_info_t *rec;
debug_info_t *hba;
debug_info_t *san;
debug_info_t *scsi;
+ spinlock_t pay_lock;
spinlock_t rec_lock;
spinlock_t hba_lock;
spinlock_t san_lock;
spinlock_t scsi_lock;
- struct zfcp_dbf_rec_record rec_buf;
- struct zfcp_dbf_hba_record hba_buf;
- struct zfcp_dbf_san_record san_buf;
- struct zfcp_dbf_scsi_record scsi_buf;
- struct zfcp_adapter *adapter;
+ struct zfcp_dbf_pay pay_buf;
+ struct zfcp_dbf_rec rec_buf;
+ struct zfcp_dbf_hba hba_buf;
+ struct zfcp_dbf_san san_buf;
+ struct zfcp_dbf_scsi scsi_buf;
};
static inline
-void zfcp_dbf_hba_fsf_resp(const char *tag2, int level,
- struct zfcp_fsf_req *req, struct zfcp_dbf *dbf)
+void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
{
- if (level <= dbf->hba->level)
- _zfcp_dbf_hba_fsf_response(tag2, level, req, dbf);
+ if (level <= req->adapter->dbf->hba->level)
+ zfcp_dbf_hba_fsf_res(tag, req);
}
/**
* zfcp_dbf_hba_fsf_response - trace event for request completion
- * @fsf_req: request that has been completed
+ * @req: request that has been completed
*/
-static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
+static inline
+void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
{
- struct zfcp_dbf *dbf = req->adapter->dbf;
struct fsf_qtcb *qtcb = req->qtcb;
if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
(qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
- zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
} else if (qtcb->header.fsf_status != FSF_GOOD) {
- zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req);
} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
(req->fsf_command == FSF_QTCB_OPEN_LUN)) {
- zfcp_dbf_hba_fsf_resp("open", 4, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_open", 4, req);
} else if (qtcb->header.log_length) {
- zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_qtcb", 5, req);
} else {
- zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf);
+ zfcp_dbf_hba_fsf_resp("fs_norm", 6, req);
}
- }
-
-/**
- * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer
- * @tag: tag indicating which kind of unsolicited status has been received
- * @dbf: reference to dbf structure
- * @status_buffer: buffer containing payload of unsolicited status
- */
-static inline
-void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf,
- struct fsf_status_read_buffer *buf)
-{
- int level = 2;
-
- if (level <= dbf->hba->level)
- _zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf);
}
static inline
-void zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
- struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
- struct zfcp_fsf_req *req, unsigned long old_id)
+void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd,
+ struct zfcp_fsf_req *req)
{
- if (level <= dbf->scsi->level)
- _zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id);
+ struct zfcp_adapter *adapter = (struct zfcp_adapter *)
+ scmd->device->host->hostdata[0];
+
+ if (level <= adapter->dbf->scsi->level)
+ zfcp_dbf_scsi(tag, scmd, req);
}
/**
* zfcp_dbf_scsi_result - trace event for SCSI command completion
- * @dbf: adapter dbf trace
* @scmd: SCSI command pointer
* @req: FSF request used to issue SCSI command
*/
static inline
-void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
- struct zfcp_fsf_req *req)
+void zfcp_dbf_scsi_result(struct scsi_cmnd *scmd, struct zfcp_fsf_req *req)
{
if (scmd->result != 0)
- zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_err", 3, scmd, req);
else if (scmd->retries > 0)
- zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_ret", 4, scmd, req);
else
- zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0);
+ _zfcp_dbf_scsi("rsl_nor", 6, scmd, req);
}
/**
* zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command
- * @dbf: adapter dbf trace
* @scmd: SCSI command pointer
*/
static inline
-void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd)
+void zfcp_dbf_scsi_fail_send(struct scsi_cmnd *scmd)
{
- zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0);
+ _zfcp_dbf_scsi("rsl_fai", 4, scmd, NULL);
}
/**
* zfcp_dbf_scsi_abort - trace event for SCSI command abort
* @tag: tag indicating success or failure of abort operation
- * @adapter: adapter thas has been used to issue SCSI command to be aborted
* @scmd: SCSI command to be aborted
- * @new_req: request containing abort (might be NULL)
- * @old_id: identifier of request containg SCSI command to be aborted
+ * @fsf_req: request containing abort (might be NULL)
*/
static inline
-void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,
- struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req,
- unsigned long old_id)
+void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd,
+ struct zfcp_fsf_req *fsf_req)
{
- zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id);
+ _zfcp_dbf_scsi(tag, 1, scmd, fsf_req);
}
/**
@@ -352,12 +366,17 @@ void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,
* @flag: indicates type of reset (Target Reset, Logical Unit Reset)
*/
static inline
-void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag)
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
{
- struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device);
+ char tmp_tag[ZFCP_DBF_TAG_LEN];
+
+ if (flag == FCP_TMF_TGT_RESET)
+ memcpy(tmp_tag, "tr_", 3);
+ else
+ memcpy(tmp_tag, "lr_", 3);
- zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
- zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0);
+ memcpy(&tmp_tag[3], tag, 4);
+ _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
}
#endif /* ZFCP_DBF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index d37c7331f244..e003e306f870 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -76,9 +76,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
struct zfcp_adapter *adapter = act->adapter;
list_move(&act->list, &act->adapter->erp_ready_head);
- zfcp_dbf_rec_action("erardy1", act);
+ zfcp_dbf_rec_run("erardy1", act);
wake_up(&adapter->erp_ready_wq);
- zfcp_dbf_rec_thread("erardy2", adapter->dbf);
+ zfcp_dbf_rec_run("erardy2", act);
}
static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
@@ -156,6 +156,8 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
return 0;
+ if (p_status & ZFCP_STATUS_COMMON_NOESC)
+ return need;
if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
/* fall through */
@@ -188,6 +190,9 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&zfcp_sdev->status);
erp_action = &zfcp_sdev->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
+ erp_action->sdev = sdev;
if (!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -200,6 +205,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
zfcp_erp_action_dismiss_port(port);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
erp_action = &port->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+ erp_action->port = port;
if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
@@ -209,6 +216,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
zfcp_erp_action_dismiss_adapter(adapter);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
erp_action = &adapter->erp_action;
+ memset(erp_action, 0, sizeof(struct zfcp_erp_action));
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING))
act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -218,10 +226,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
return NULL;
}
- memset(erp_action, 0, sizeof(struct zfcp_erp_action));
erp_action->adapter = adapter;
- erp_action->port = port;
- erp_action->sdev = sdev;
erp_action->action = need;
erp_action->status = act_status;
@@ -231,10 +236,10 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
struct zfcp_port *port,
struct scsi_device *sdev,
- char *id, void *ref, u32 act_status)
+ char *id, u32 act_status)
{
int retval = 1, need;
- struct zfcp_erp_action *act = NULL;
+ struct zfcp_erp_action *act;
if (!adapter->erp_thread)
return -EIO;
@@ -250,15 +255,14 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
++adapter->erp_total_count;
list_add_tail(&act->list, &adapter->erp_ready_head);
wake_up(&adapter->erp_ready_wq);
- zfcp_dbf_rec_thread("eracte1", adapter->dbf);
retval = 0;
out:
- zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev);
+ zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need);
return retval;
}
static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
- int clear_mask, char *id, void *ref)
+ int clear_mask, char *id)
{
zfcp_erp_adapter_block(adapter, clear_mask);
zfcp_scsi_schedule_rports_block(adapter);
@@ -270,7 +274,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
- adapter, NULL, NULL, id, ref, 0);
+ adapter, NULL, NULL, id, 0);
}
/**
@@ -278,10 +282,8 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
* @adapter: Adapter to reopen.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
- char *id, void *ref)
+void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id)
{
unsigned long flags;
@@ -294,7 +296,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
ZFCP_STATUS_COMMON_ERP_FAILED);
else
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
- NULL, NULL, id, ref, 0);
+ NULL, NULL, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
@@ -303,13 +305,12 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
* @adapter: Adapter to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
- char *id, void *ref)
+ char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
+ zfcp_erp_adapter_reopen(adapter, clear | flags, id);
}
/**
@@ -317,13 +318,11 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
* @port: Port to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
- void *ref)
+void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_port_reopen(port, clear | flags, id, ref);
+ zfcp_erp_port_reopen(port, clear | flags, id);
}
static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
@@ -332,8 +331,8 @@ static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
ZFCP_STATUS_COMMON_UNBLOCKED | clear);
}
-static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
- int clear, char *id, void *ref)
+static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
+ char *id)
{
zfcp_erp_port_block(port, clear);
zfcp_scsi_schedule_rport_block(port);
@@ -342,28 +341,26 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
return;
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
- port->adapter, port, NULL, id, ref, 0);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_forced_reopen - Forced close of port and open again
* @port: Port to force close and to reopen.
+ * @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
- void *ref)
+void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id)
{
unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_port_forced_reopen(port, clear, id, ref);
+ _zfcp_erp_port_forced_reopen(port, clear, id);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
- void *ref)
+static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
zfcp_erp_port_block(port, clear);
zfcp_scsi_schedule_rport_block(port);
@@ -375,24 +372,25 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
- port->adapter, port, NULL, id, ref, 0);
+ port->adapter, port, NULL, id, 0);
}
/**
* zfcp_erp_port_reopen - trigger remote port recovery
* @port: port to recover
* @clear_mask: flags in port status to be cleared
+ * @id: Id for debug trace event.
*
* Returns 0 if recovery has been triggered, < 0 if not.
*/
-int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
+int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)
{
int retval;
unsigned long flags;
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- retval = _zfcp_erp_port_reopen(port, clear, id, ref);
+ retval = _zfcp_erp_port_reopen(port, clear, id);
write_unlock_irqrestore(&adapter->erp_lock, flags);
return retval;
@@ -405,7 +403,7 @@ static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
}
static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
- void *ref, u32 act_status)
+ u32 act_status)
{
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
@@ -416,17 +414,18 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
return;
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
- zfcp_sdev->port, sdev, id, ref, act_status);
+ zfcp_sdev->port, sdev, id, act_status);
}
/**
* zfcp_erp_lun_reopen - initiate reopen of a LUN
* @sdev: SCSI device / LUN to be reopened
* @clear_mask: specifies flags in LUN status to be cleared
+ * @id: Id for debug trace event.
+ *
* Return: 0 on success, < 0 on error
*/
-void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
- void *ref)
+void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id)
{
unsigned long flags;
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
@@ -434,7 +433,7 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
@@ -443,13 +442,11 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
* @sdev: SCSI device / LUN to shut down.
* @clear: Status flags to clear.
* @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id,
- void *ref)
+void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id)
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_lun_reopen(sdev, clear | flags, id, ref);
+ zfcp_erp_lun_reopen(sdev, clear | flags, id);
}
/**
@@ -471,7 +468,7 @@ void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
+ _zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF);
write_unlock_irqrestore(&adapter->erp_lock, flags);
zfcp_erp_wait(adapter);
@@ -485,14 +482,14 @@ static int status_change_set(unsigned long mask, atomic_t *status)
static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
{
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
- zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
+ zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
}
static void zfcp_erp_port_unblock(struct zfcp_port *port)
{
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
- zfcp_dbf_rec_port("erpubl1", NULL, port);
+ zfcp_dbf_rec_run("erpubl1", &port->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
}
@@ -501,14 +498,14 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
- zfcp_dbf_rec_lun("erlubl1", NULL, sdev);
+ zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
}
static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
- zfcp_dbf_rec_action("erator1", erp_action);
+ zfcp_dbf_rec_run("erator1", erp_action);
}
static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
@@ -525,11 +522,11 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
- zfcp_dbf_rec_action("erscf_1", act);
+ zfcp_dbf_rec_run("erscf_1", act);
req->erp_action = NULL;
}
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
- zfcp_dbf_rec_action("erscf_2", act);
+ zfcp_dbf_rec_run("erscf_2", act);
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
act->fsf_req_id = 0;
} else
@@ -580,40 +577,40 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
}
static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
- int clear, char *id, void *ref)
+ int clear, char *id)
{
struct zfcp_port *port;
read_lock(&adapter->port_list_lock);
list_for_each_entry(port, &adapter->port_list, list)
- _zfcp_erp_port_reopen(port, clear, id, ref);
+ _zfcp_erp_port_reopen(port, clear, id);
read_unlock(&adapter->port_list_lock);
}
static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
- char *id, void *ref)
+ char *id)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port)
- _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
}
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
{
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
+ _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
+ _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
- _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersff_3");
break;
case ZFCP_ERP_ACTION_REOPEN_LUN:
- _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0);
+ _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
break;
}
}
@@ -622,13 +619,13 @@ static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
{
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+ _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersfs_2");
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
- _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL);
+ _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
break;
}
}
@@ -647,17 +644,6 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
read_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
-{
- struct zfcp_qdio *qdio = act->adapter->qdio;
-
- if (zfcp_qdio_open(qdio))
- return ZFCP_ERP_FAILED;
- init_waitqueue_head(&qdio->req_q_wq);
- atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
- return ZFCP_ERP_SUCCEEDED;
-}
-
static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
{
struct zfcp_port *port;
@@ -665,7 +651,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
adapter->peer_d_id);
if (IS_ERR(port)) /* error or port already attached */
return;
- _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
+ _zfcp_erp_port_reopen(port, 0, "ereptp1");
}
static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
@@ -688,10 +674,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
}
- zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
wait_event(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head));
- zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
break;
@@ -730,10 +714,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
if (ret)
return ZFCP_ERP_FAILED;
- zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
+ zfcp_dbf_rec_run("erasox1", act);
wait_event(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head));
- zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
+ zfcp_dbf_rec_run("erasox2", act);
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
return ZFCP_ERP_FAILED;
@@ -783,7 +767,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
- if (zfcp_erp_adapter_strategy_open_qdio(act)) {
+ if (zfcp_qdio_open(adapter->qdio)) {
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
&adapter->status);
@@ -1161,7 +1145,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
_zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg1", NULL);
+ "ersscg1");
return ZFCP_ERP_EXIT;
}
break;
@@ -1171,7 +1155,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
_zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg2", NULL);
+ "ersscg2");
return ZFCP_ERP_EXIT;
}
break;
@@ -1181,7 +1165,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
_zfcp_erp_lun_reopen(sdev,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg3", NULL, 0);
+ "ersscg3", 0);
return ZFCP_ERP_EXIT;
}
break;
@@ -1201,7 +1185,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
}
list_del(&erp_action->list);
- zfcp_dbf_rec_action("eractd1", erp_action);
+ zfcp_dbf_rec_run("eractd1", erp_action);
switch (erp_action->action) {
case ZFCP_ERP_ACTION_REOPEN_LUN:
@@ -1308,7 +1292,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
}
if (adapter->erp_total_count == adapter->erp_low_mem_count)
- _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
+ _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");
else {
zfcp_erp_strategy_memwait(erp_action);
retval = ZFCP_ERP_CONTINUES;
@@ -1352,11 +1336,9 @@ static int zfcp_erp_thread(void *data)
unsigned long flags;
for (;;) {
- zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
wait_event_interruptible(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head) ||
kthread_should_stop());
- zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
if (kthread_should_stop())
break;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index bf8f3e514839..6e325284fbe7 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -45,47 +45,33 @@ extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *);
/* zfcp_dbf.c */
extern int zfcp_dbf_adapter_register(struct zfcp_adapter *);
-extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *);
-extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *);
-extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *);
-extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *);
-extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *,
- struct zfcp_adapter *, struct zfcp_port *,
- struct scsi_device *);
-extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *);
-extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *,
- struct zfcp_dbf *);
-extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *,
- struct fsf_status_read_buffer *);
-extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int);
+extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
+extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
+ struct zfcp_port *, struct scsi_device *, u8, u8);
+extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
+extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32);
-extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *);
-extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *);
-extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *,
- struct scsi_cmnd *, struct zfcp_fsf_req *,
- unsigned long);
+extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
+extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);
/* zfcp_erp.c */
extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);
extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32);
-extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *);
-extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *,
- void *);
+extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *);
+extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *);
extern void zfcp_erp_set_port_status(struct zfcp_port *, u32);
extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32);
-extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *);
-extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *);
-extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *,
- void *);
+extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *);
+extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *);
+extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *);
extern void zfcp_erp_set_lun_status(struct scsi_device *, u32);
extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32);
-extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *);
-extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *);
+extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *);
+extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *);
extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *);
extern int zfcp_erp_thread_setup(struct zfcp_adapter *);
extern void zfcp_erp_thread_kill(struct zfcp_adapter *);
@@ -149,6 +135,8 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
extern void zfcp_qdio_siosl(struct zfcp_adapter *);
+extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
+ struct qdio_buffer *);
/* zfcp_scsi.c */
extern struct zfcp_data zfcp_data;
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 86fd905df48b..30cf91a787a3 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -174,7 +174,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
if (!port->d_id)
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcrscn1", NULL);
+ "fcrscn1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
}
@@ -215,7 +215,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if (port->wwpn == wwpn) {
- zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
+ zfcp_erp_port_forced_reopen(port, 0, "fciwwp1");
break;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
@@ -251,7 +251,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
(struct fsf_status_read_buffer *) fsf_req->data;
unsigned int els_type = status_buffer->payload.data[0];
- zfcp_dbf_san_incoming_els(fsf_req);
+ zfcp_dbf_san_in_els("fciels1", fsf_req);
if (els_type == ELS_PLOGI)
zfcp_fc_incoming_plogi(fsf_req);
else if (els_type == ELS_LOGO)
@@ -360,7 +360,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)
ret = zfcp_fc_ns_gid_pn(port);
if (ret) {
/* could not issue gid_pn for some reason */
- zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1");
goto out;
}
@@ -369,7 +369,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)
goto out;
}
- zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
+ zfcp_erp_port_reopen(port, 0, "fcgpn_3");
out:
put_device(&port->dev);
}
@@ -426,7 +426,7 @@ static void zfcp_fc_adisc_handler(void *data)
if (adisc->els.status) {
/* request rejected or timed out */
zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcadh_1", NULL);
+ "fcadh_1");
goto out;
}
@@ -436,7 +436,7 @@ static void zfcp_fc_adisc_handler(void *data)
if ((port->wwpn != adisc_resp->adisc_wwpn) ||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fcadh_2", NULL);
+ "fcadh_2");
goto out;
}
@@ -507,7 +507,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)
/* send of ADISC was not possible */
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
- zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "fcltwk1");
out:
put_device(&port->dev);
@@ -659,7 +659,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
port = zfcp_port_enqueue(adapter, acc->fp_wwpn,
ZFCP_STATUS_COMMON_NOESC, d_id);
if (!IS_ERR(port))
- zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
+ zfcp_erp_port_reopen(port, 0, "fcegpf1");
else if (PTR_ERR(port) != -EEXIST)
ret = PTR_ERR(port);
}
@@ -671,7 +671,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
write_unlock_irqrestore(&adapter->port_list_lock, flags);
list_for_each_entry_safe(port, tmp, &remove_lh, list) {
- zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL);
+ zfcp_erp_port_shutdown(port, 0, "fcegpf2");
zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
}
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index 938d50360166..b464ae01086c 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -270,7 +270,7 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) {
sense = (char *) &fcp_rsp[1];
if (rsp_flags & FCP_RSP_LEN_VAL)
- sense += fcp_rsp->ext.fr_sns_len;
+ sense += fcp_rsp->ext.fr_rsp_len;
sense_len = min(fcp_rsp->ext.fr_sns_len,
(u32) SCSI_SENSE_BUFFERSIZE);
memcpy(scsi->sense_buffer, sense, sense_len);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index beaf0916ceab..60ff9d172c79 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -23,7 +23,7 @@ static void zfcp_fsf_request_timeout_handler(unsigned long data)
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fsrth_1", NULL);
+ "fsrth_1");
}
static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
@@ -65,7 +65,7 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
{
dev_err(&req->adapter->ccw_device->dev, "FCP device not "
"operational because of an unsupported FC class\n");
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
@@ -98,7 +98,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if (port->d_id == d_id) {
- zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
+ zfcp_erp_port_reopen(port, 0, "fssrpc1");
break;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
@@ -211,13 +211,13 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
struct fsf_status_read_buffer *sr_buf = req->data;
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
- zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf);
+ zfcp_dbf_hba_fsf_uss("fssrh_1", req);
mempool_free(sr_buf, adapter->pool.status_read_data);
zfcp_fsf_req_free(req);
return;
}
- zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf);
+ zfcp_dbf_hba_fsf_uss("fssrh_2", req);
switch (sr_buf->status_type) {
case FSF_STATUS_READ_PORT_CLOSED:
@@ -232,7 +232,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
dev_warn(&adapter->ccw_device->dev,
"The error threshold for checksum statistics "
"has been exceeded\n");
- zfcp_dbf_hba_berr(adapter->dbf, req);
+ zfcp_dbf_hba_bit_err("fssrh_3", req);
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
@@ -247,7 +247,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fssrh_2", req);
+ "fssrh_2");
zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
break;
@@ -287,7 +287,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
"The FCP adapter reported a problem "
"that cannot be recovered\n");
zfcp_qdio_siosl(req->adapter);
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1");
break;
}
/* all non-return stats set FSFREQ_ERROR*/
@@ -304,7 +304,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
dev_err(&req->adapter->ccw_device->dev,
"The FCP adapter does not recognize the command 0x%x\n",
req->qtcb->header.fsf_command);
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -335,17 +335,17 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
"QTCB version 0x%x not supported by FCP adapter "
"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
psq->word[0], psq->word[1]);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1");
break;
case FSF_PROT_ERROR_STATE:
case FSF_PROT_SEQ_NUMB_ERROR:
- zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fspse_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_UNSUPP_QTCB_TYPE:
dev_err(&adapter->ccw_device->dev,
"The QTCB type is not supported by the FCP adapter\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3");
break;
case FSF_PROT_HOST_CONNECTION_INITIALIZING:
atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
@@ -355,12 +355,12 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
dev_err(&adapter->ccw_device->dev,
"0x%Lx is an ambiguous request identifier\n",
(unsigned long long)qtcb->bottom.support.req_handle);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4");
break;
case FSF_PROT_LINK_DOWN:
zfcp_fsf_link_down_info_eval(req, &psq->link_down_info);
/* go through reopen to flush pending requests */
- zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fspse_6");
break;
case FSF_PROT_REEST_QUEUE:
/* All ports should be marked as ready to run again */
@@ -369,14 +369,14 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
- "fspse_8", req);
+ "fspse_8");
break;
default:
dev_err(&adapter->ccw_device->dev,
"0x%x is not a valid transfer protocol status\n",
qtcb->prefix.prot_status);
zfcp_qdio_siosl(adapter);
- zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9");
}
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
@@ -482,7 +482,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
dev_err(&adapter->ccw_device->dev,
"Unknown or unsupported arbitrated loop "
"fibre channel topology detected\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1");
return -EIO;
}
@@ -518,7 +518,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
"FCP adapter maximum QTCB size (%d bytes) "
"is too small\n",
bottom->max_qtcb_size);
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1");
return;
}
atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
@@ -532,14 +532,11 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
adapter->hydra_version = 0;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
- &adapter->status);
-
zfcp_fsf_link_down_info_eval(req,
&qtcb->header.fsf_status_qual.link_down_info);
break;
default:
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3");
return;
}
@@ -555,14 +552,14 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
dev_err(&adapter->ccw_device->dev,
"The FCP adapter only supports newer "
"control block versions\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4");
return;
}
if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
dev_err(&adapter->ccw_device->dev,
"The FCP adapter only supports older "
"control block versions\n");
- zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5");
}
}
@@ -703,7 +700,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
del_timer(&req->timer);
/* lookup request again, list might have changed */
zfcp_reqlist_find_rm(adapter->req_list, req_id);
- zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1");
return -EIO;
}
@@ -757,10 +754,11 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
goto out;
failed_req_send:
+ req->data = NULL;
mempool_free(sr_buf, adapter->pool.status_read_data);
failed_buf:
+ zfcp_dbf_hba_fsf_uss("fssr__1", req);
zfcp_fsf_req_free(req);
- zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL);
out:
spin_unlock_irq(&qdio->req_q_lock);
return retval;
@@ -779,14 +777,13 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
case FSF_PORT_HANDLE_NOT_VALID:
if (fsq->word[0] == fsq->word[1]) {
zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0,
- "fsafch1", req);
+ "fsafch1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
break;
case FSF_LUN_HANDLE_NOT_VALID:
if (fsq->word[0] == fsq->word[1]) {
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2",
- req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
break;
@@ -797,14 +794,13 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fsafch4", req);
+ "fsafch4");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -854,7 +850,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
- req->data = zfcp_sdev;
+ req->data = sdev;
req->handler = zfcp_fsf_abort_fcp_command_handler;
req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
req->qtcb->header.port_handle = zfcp_sdev->port->handle;
@@ -885,7 +881,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_GOOD:
- zfcp_dbf_san_ct_response(req);
+ zfcp_dbf_san_res("fsscth1", req);
ct->status = 0;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
@@ -905,7 +901,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");
/* fall through */
case FSF_GENERIC_COMMAND_REJECTED:
case FSF_PAYLOAD_SIZE_MISMATCH:
@@ -1028,7 +1024,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
req->qtcb->header.port_handle = wka_port->handle;
req->data = ct;
- zfcp_dbf_san_ct_request(req, wka_port->d_id);
+ zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
ret = zfcp_fsf_req_send(req);
if (ret)
@@ -1056,7 +1052,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_GOOD:
- zfcp_dbf_san_els_response(req);
+ zfcp_dbf_san_res("fsselh1", req);
send_els->status = 0;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
@@ -1130,7 +1126,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
req->handler = zfcp_fsf_send_els_handler;
req->data = els;
- zfcp_dbf_san_els_request(req);
+ zfcp_dbf_san_req("fssels1", req, d_id);
ret = zfcp_fsf_req_send(req);
if (ret)
@@ -1451,7 +1447,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -1583,7 +1579,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
+ zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1");
}
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
@@ -1641,7 +1637,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
+ zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ACCESS_DENIED:
@@ -1657,7 +1653,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
&sdev_to_zfcp(sdev)->status);
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fscpph2", req);
+ "fscpph2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -1746,7 +1742,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req);
+ zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");
/* fall through */
case FSF_LUN_ALREADY_OPEN:
break;
@@ -1758,8 +1754,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_SHARING_VIOLATION:
@@ -1855,20 +1850,18 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1",
- req);
+ zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_HANDLE_NOT_VALID:
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_BOXED:
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -2005,13 +1998,12 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)
switch (header->fsf_status) {
case FSF_HANDLE_MISMATCH:
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1",
- req);
+ zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_FCPLUN_NOT_VALID:
case FSF_LUN_HANDLE_NOT_VALID:
- zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
@@ -2029,7 +2021,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)
(unsigned long long)zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0,
- "fssfch3", req);
+ "fssfch3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_CMND_LENGTH_NOT_VALID:
@@ -2040,21 +2032,20 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)
(unsigned long long)zfcp_scsi_dev_lun(sdev),
(unsigned long long)zfcp_sdev->port->wwpn);
zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0,
- "fssfch4", req);
+ "fssfch4");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_BOXED:
zfcp_erp_set_port_status(zfcp_sdev->port,
ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_port_reopen(zfcp_sdev->port,
- ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5",
- req);
+ ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "fssfch6", req);
+ "fssfch6");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -2072,8 +2063,6 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)
struct fcp_resp_with_ext *fcp_rsp;
unsigned long flags;
- zfcp_fsf_fcp_handler_common(req);
-
read_lock_irqsave(&req->adapter->abort_lock, flags);
scpnt = req->data;
@@ -2082,6 +2071,8 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)
return;
}
+ zfcp_fsf_fcp_handler_common(req);
+
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
goto skip_fsfstatus;
@@ -2107,7 +2098,7 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)
skip_fsfstatus:
zfcp_fsf_req_trace(req, scpnt);
- zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req);
+ zfcp_dbf_scsi_result(scpnt, req);
scpnt->host_scribble = NULL;
(scpnt->scsi_done) (scpnt);
@@ -2173,12 +2164,13 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
struct fsf_qtcb_bottom_io *io;
+ unsigned long flags;
if (unlikely(!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
- spin_lock(&qdio->req_q_lock);
+ spin_lock_irqsave(&qdio->req_q_lock, flags);
if (atomic_read(&qdio->req_q_free) <= 0) {
atomic_inc(&qdio->req_q_full);
goto out;
@@ -2242,7 +2234,7 @@ failed_scsi_cmnd:
zfcp_fsf_req_free(req);
scsi_cmnd->host_scribble = NULL;
out:
- spin_unlock(&qdio->req_q_lock);
+ spin_unlock_irqrestore(&qdio->req_q_lock, flags);
return retval;
}
@@ -2422,3 +2414,12 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
break;
}
}
+
+struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio,
+ struct qdio_buffer *sbal)
+{
+ struct qdio_buffer_element *sbale = &sbal->element[0];
+ u64 req_id = (unsigned long) sbale->addr;
+
+ return zfcp_reqlist_find(qdio->adapter->req_list, req_id);
+}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index a0554beb4179..8da5ed644c2b 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -41,7 +41,7 @@ static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
+ ZFCP_STATUS_COMMON_ERP_FAILED, id);
}
static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
@@ -74,7 +74,6 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
return;
}
@@ -97,7 +96,6 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
int sbal_idx, sbal_no;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
return;
}
@@ -116,7 +114,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
* put SBALs back to response queue
*/
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
}
static struct qdio_buffer_element *
@@ -236,7 +234,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
if (!ret) {
atomic_inc(&qdio->req_q_full);
/* assume hanging outbound queue, try queue recovery */
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL);
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
}
spin_lock_irq(&qdio->req_q_lock);
@@ -292,6 +290,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->int_parm = (unsigned long) qdio;
id->input_sbal_addr_array = (void **) (qdio->res_q);
id->output_sbal_addr_array = (void **) (qdio->req_q);
+ id->scan_threshold =
+ QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
}
/**
@@ -309,6 +309,7 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
return -ENOMEM;
zfcp_qdio_setup_init_data(&init_data, qdio);
+ init_waitqueue_head(&qdio->req_q_wq);
return qdio_allocate(&init_data);
}
@@ -393,6 +394,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
/* set index of first avalable SBALS / number of available SBALS */
qdio->req_q_idx = 0;
atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
return 0;
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 50286d8707f3..ddb5800823a9 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -30,6 +30,10 @@ module_param_named(dif, enable_dif, bool, 0600);
MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
#endif
+static bool allow_lun_scan = 1;
+module_param(allow_lun_scan, bool, 0600);
+MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs");
+
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
int reason)
{
@@ -68,31 +72,26 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
- struct zfcp_adapter *adapter =
- (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
-
set_host_byte(scpnt, result);
- zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
+ zfcp_dbf_scsi_fail_send(scpnt);
scpnt->scsi_done(scpnt);
}
-static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
- void (*done) (struct scsi_cmnd *))
+static
+int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt)
{
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
- struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
int status, scsi_result, ret;
/* reset the status for this request */
scpnt->result = 0;
scpnt->host_scribble = NULL;
- scpnt->scsi_done = done;
scsi_result = fc_remote_port_chkready(rport);
if (unlikely(scsi_result)) {
scpnt->result = scsi_result;
- zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
+ zfcp_dbf_scsi_fail_send(scpnt);
scpnt->scsi_done(scpnt);
return 0;
}
@@ -135,6 +134,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_port *port;
struct zfcp_unit *unit;
+ int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (!port)
@@ -144,7 +144,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
if (unit)
put_device(&unit->dev);
- if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) {
+ if (!unit && !(allow_lun_scan && npiv)) {
put_device(&port->dev);
return -ENXIO;
}
@@ -159,7 +159,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
spin_lock_init(&zfcp_sdev->latencies.lock);
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
- zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL);
+ zfcp_erp_lun_reopen(sdev, 0, "scsla_1");
zfcp_erp_wait(port->adapter);
return 0;
@@ -183,8 +183,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
old_req = zfcp_reqlist_find(adapter->req_list, old_reqid);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
- zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL,
- old_reqid);
+ zfcp_dbf_scsi_abort("abrt_or", scpnt, NULL);
return FAILED; /* completion could be in progress */
}
old_req->data = NULL;
@@ -199,29 +198,32 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
zfcp_erp_wait(adapter);
ret = fc_block_scsi_eh(scpnt);
- if (ret)
+ if (ret) {
+ zfcp_dbf_scsi_abort("abrt_bl", scpnt, NULL);
return ret;
+ }
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
- zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
- old_reqid);
+ zfcp_dbf_scsi_abort("abrt_ru", scpnt, NULL);
return SUCCESS;
}
}
- if (!abrt_req)
+ if (!abrt_req) {
+ zfcp_dbf_scsi_abort("abrt_ar", scpnt, NULL);
return FAILED;
+ }
wait_for_completion(&abrt_req->completion);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
- dbf_tag = "okay";
+ dbf_tag = "abrt_ok";
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
- dbf_tag = "lte2";
+ dbf_tag = "abrt_nn";
else {
- dbf_tag = "fail";
+ dbf_tag = "abrt_fa";
retval = FAILED;
}
- zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid);
+ zfcp_dbf_scsi_abort(dbf_tag, scpnt, abrt_req);
zfcp_fsf_req_free(abrt_req);
return retval;
}
@@ -281,7 +283,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
int ret;
- zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
+ zfcp_erp_adapter_reopen(adapter, 0, "schrh_1");
zfcp_erp_wait(adapter);
ret = fc_block_scsi_eh(scpnt);
if (ret)
@@ -519,7 +521,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) {
- zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "sctrpi1");
put_device(&port->dev);
}
}
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 2f2c54f4718f..cdc4ff78a7ba 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -105,8 +105,7 @@ static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,
return -EINVAL;
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
- zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2",
- NULL);
+ zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2");
zfcp_erp_wait(port->adapter);
return count;
@@ -148,7 +147,7 @@ static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,
if (sdev) {
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
- "syufai2", NULL);
+ "syufai2");
zfcp_erp_wait(unit->port->adapter);
} else
zfcp_unit_scsi_scan(unit);
@@ -198,7 +197,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "syafai2", NULL);
+ "syafai2");
zfcp_erp_wait(adapter);
out:
zfcp_ccw_adapter_put(adapter);
@@ -256,7 +255,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
put_device(&port->dev);
- zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
+ zfcp_erp_port_shutdown(port, 0, "syprs_1");
zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
out:
zfcp_ccw_adapter_put(adapter);
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c
index 1119c535a667..20796ebc33ce 100644
--- a/drivers/s390/scsi/zfcp_unit.c
+++ b/drivers/s390/scsi/zfcp_unit.c
@@ -142,6 +142,8 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
return -ENOMEM;
}
+ get_device(&port->dev);
+
if (device_register(&unit->dev)) {
put_device(&unit->dev);
return -ENOMEM;
@@ -152,8 +154,6 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
return -EINVAL;
}
- get_device(&port->dev);
-
write_lock_irq(&port->unit_list_lock);
list_add_tail(&unit->list, &port->unit_list);
write_unlock_irq(&port->unit_list_lock);
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index a624f5af4320..e8566224fe4b 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -467,7 +467,7 @@ static int jsflash_init(void)
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "flash-memory");
- if (node != 0 && node != -1) {
+ if (node != 0 && (s32)node != -1) {
if (prom_getproperty(node, "reg",
(char *)&reg0, sizeof(reg0)) == -1) {
printk("jsflash: no \"reg\" property\n");
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index fcf08b3f52c1..b7bd5b0cc7aa 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1765,7 +1765,7 @@ out:
} /* End twa_scsi_eh_reset() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
@@ -1812,6 +1812,8 @@ out:
return retval;
} /* End twa_scsi_queue() */
+static DEF_SCSI_QCMD(twa_scsi_queue)
+
/* This function hands scsi cdb's to the firmware */
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
{
diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
index 6a95d111d207..13e39e1fdfe2 100644
--- a/drivers/scsi/3w-sas.c
+++ b/drivers/scsi/3w-sas.c
@@ -1501,7 +1501,7 @@ out:
} /* End twl_scsi_eh_reset() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
@@ -1536,6 +1536,8 @@ out:
return retval;
} /* End twl_scsi_queue() */
+static DEF_SCSI_QCMD(twl_scsi_queue)
+
/* This function tells the controller to shut down */
static void __twl_shutdown(TW_Device_Extension *tw_dev)
{
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index b1125341f4c8..7fe96ff60c58 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1947,7 +1947,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r
} /* End tw_scsiop_test_unit_ready_complete() */
/* This is the main scsi queue function to handle scsi opcodes */
-static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
unsigned char *command = SCpnt->cmnd;
int request_id = 0;
@@ -2023,6 +2023,8 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
return retval;
} /* End tw_scsi_queue() */
+static DEF_SCSI_QCMD(tw_scsi_queue)
+
/* This function is the interrupt service routine */
static irqreturn_t tw_interrupt(int irq, void *dev_instance)
{
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 89fc1c8af86b..f672491774eb 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -167,7 +167,7 @@ MODULE_LICENSE("GPL");
#include "53c700_d.h"
-STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *);
STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
@@ -1749,8 +1749,8 @@ NCR_700_intr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-STATIC int
-NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
+static int
+NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
@@ -1904,6 +1904,8 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
return 0;
}
+STATIC DEF_SCSI_QCMD(NCR_700_queuecommand)
+
STATIC int
NCR_700_abort(struct scsi_cmnd * SCp)
{
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index fc0b4b81d552..f66c33b9ab41 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2807,7 +2807,7 @@ static int BusLogic_host_reset(struct scsi_cmnd * SCpnt)
Outgoing Mailbox for execution by the associated Host Adapter.
*/
-static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
+static int BusLogic_QueueCommand_lck(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
{
struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata;
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id];
@@ -2994,6 +2994,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
return 0;
}
+static DEF_SCSI_QCMD(BusLogic_QueueCommand)
#if 0
/*
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 73f237a1ed94..649fcb31f26d 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -1319,7 +1319,7 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T Co
*/
static const char *BusLogic_DriverInfo(struct Scsi_Host *);
-static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *));
+static int BusLogic_QueueCommand(struct Scsi_Host *h, struct scsi_cmnd *);
static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
static int BusLogic_SlaveConfigure(struct scsi_device *);
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 5d2f148889ad..9a5629f94f95 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -952,7 +952,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
* Locks: host lock taken by caller
*/
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *instance = cmd->device->host;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -1021,6 +1021,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
/**
* NCR5380_main - NCR state machines
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index bdc468c9e1d9..fd40a32b1f6f 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -313,7 +313,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
#endif
static int NCR5380_abort(Scsi_Cmnd * cmd);
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
char *buffer, char **start, off_t offset, int length, int inout);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 6961f78742ae..c91888a0a23c 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -693,7 +693,7 @@ static void wait_intr(void)
}
#endif
-static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
int i;
@@ -726,6 +726,8 @@ static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(NCR53c406a_queue)
+
static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt)
{
DEB(printk("NCR53c406a_reset called\n"));
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index dbbc601948e5..a391090a17c5 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -416,7 +416,7 @@ static u8 orc_load_firmware(struct orc_host * host)
/* Go back and check they match */
outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */
- bios_addr -= 0x1000; /* Reset the BIOS adddress */
+ bios_addr -= 0x1000; /* Reset the BIOS address */
for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */
i < 0x1000; /* Firmware code size = 4K */
i++, bios_addr++) {
@@ -911,7 +911,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc
* queue the command down to the controller
*/
-static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int inia100_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
{
struct orc_scb *scb;
struct orc_host *host; /* Point to Host adapter control block */
@@ -930,6 +930,8 @@ static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd
return 0;
}
+static DEF_SCSI_QCMD(inia100_queue)
+
/*****************************************************************************
Function name : inia100_abort
Description : Abort a queued command.
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index afc9aeba5edb..060ac4bd5a14 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -91,7 +91,7 @@ void aac_fib_map_free(struct aac_dev *dev)
* aac_fib_setup - setup the fibs
* @dev: Adapter to set up
*
- * Allocate the PCI space for the fibs, map it and then intialise the
+ * Allocate the PCI space for the fibs, map it and then initialise the
* fib area, the unmapped fib data and also the free list
*/
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 29c0ed1cf507..2c93d9496d62 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -248,7 +248,7 @@ static struct aac_driver_ident aac_drivers[] = {
* TODO: unify with aac_scsi_cmd().
*/
-static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int aac_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
@@ -267,6 +267,8 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
return (aac_scsi_cmd(cmd) ? FAILED : 0);
}
+static DEF_SCSI_QCMD(aac_queuecommand)
+
/**
* aac_info - Returns the host adapter name
* @shost: Scsi host to report on
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 0ec3da6f3e12..081c6de92bc5 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -9500,7 +9500,7 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
* in the 'scp' result field.
*/
static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+advansys_queuecommand_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *shost = scp->device->host;
int asc_res, result = 0;
@@ -9525,6 +9525,8 @@ advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
return result;
}
+static DEF_SCSI_QCMD(advansys_queuecommand)
+
static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
{
PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 8eab8587ff21..c5169f01c1cd 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -1056,7 +1056,7 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
* queue a command
*
*/
-static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha152x_queue_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
#if 0
if(*SCpnt->cmnd == REQUEST_SENSE) {
@@ -1070,6 +1070,8 @@ static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
return aha152x_internal_queue(SCpnt, NULL, 0, done);
}
+static DEF_SCSI_QCMD(aha152x_queue)
+
/*
*
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 4f785f254c1f..195823a51aab 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -558,7 +558,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost)
};
}
-static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
unchar ahacmd = CMD_START_SCSI;
unchar direction;
@@ -718,6 +718,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(aha1542_queuecommand)
+
/* Initialize mailboxes */
static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
{
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index 1db538552d56..b871d2b57f93 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -132,7 +132,7 @@ struct ccb { /* Command Control Block 5.3 */
};
static int aha1542_detect(struct scsi_host_template *);
-static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int aha1542_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 0107a4cc3331..d058f1ab82b5 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -331,7 +331,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar direction;
unchar *cmd = (unchar *) SCpnt->cmnd;
@@ -503,6 +503,8 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(aha1740_queuecommand)
+
/* Query the board for its irq_level and irq_type. Nothing else matters
in enhanced mode on an EISA bus. */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 88ad8482ef59..25d066624476 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -573,7 +573,7 @@ ahd_linux_info(struct Scsi_Host *host)
* Queue an SCB to the controller.
*/
static int
-ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahd_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
@@ -588,6 +588,8 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
return rtn;
}
+static DEF_SCSI_QCMD(ahd_linux_queue)
+
static struct scsi_target **
ahd_linux_target_in_softc(struct scsi_target *starget)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index aeea7a61478e..4a359bb307c6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -528,7 +528,7 @@ ahc_linux_info(struct Scsi_Host *host)
* Queue an SCB to the controller.
*/
static int
-ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahc_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device);
@@ -548,6 +548,8 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
return rtn;
}
+static DEF_SCSI_QCMD(ahc_linux_queue)
+
static inline struct scsi_target **
ahc_linux_target_in_softc(struct scsi_target *starget)
{
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index aee73fafccc8..4ff60a08df0f 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -10234,7 +10234,7 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
* Description:
* Queue a SCB to the controller.
*-F*************************************************************************/
-static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+static int aic7xxx_queue_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
@@ -10292,6 +10292,8 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
return (0);
}
+static DEF_SCSI_QCMD(aic7xxx_queue)
+
/*+F*************************************************************************
* Function:
* aic7xxx_bus_device_reset
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq
index 5997e7c3a191..1565be9ebd49 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq
@@ -1178,7 +1178,7 @@ notFound:
/*
* Retrieve an SCB by SCBID first searching the disconnected list falling
* back to DMA'ing the SCB down from the host. This routine assumes that
- * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * ARG_1 is the SCBID of interest and that SINDEX is the position in the
* disconnected list to start the search from. If SINDEX is SCB_LIST_NULL,
* we go directly to the host for the SCB.
*/
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
index 28aaf349c111..40273a747d29 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg_def.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -1689,7 +1689,7 @@
#define PHY_START_CAL 0x01
/*
- * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
+ * HST_PCIX2 Registers, Address Range: (0x00-0xFC)
*/
#define PCIX_REG_BASE_ADR 0xB8040000
@@ -1802,7 +1802,7 @@
#define PCIC_TP_CTRL 0xFC
/*
- * EXSI Registers, Addresss Range: (0x00-0xFC)
+ * EXSI Registers, Address Range: (0x00-0xFC)
*/
#define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index c43698b1cb64..29593275201a 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -867,7 +867,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
* resources they have with this SCB, and then call this one at the
* end of their timeout function. To do this, one should initialize
* the ascb->timer.{function, data, expires} prior to calling the post
- * funcion. The timer is started by the post function.
+ * function. The timer is started by the post function.
*/
void asd_ascb_timedout(unsigned long data)
{
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 74374618010c..390168f62a13 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -797,7 +797,7 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
int j;
/* Start from Page 1 of Mode 0 and 1. */
moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE;
- /* All the fields of page 1 can be intialized to 0. */
+ /* All the fields of page 1 can be initialized to 0. */
for (j = 0; j < LSEQ_PAGE_SIZE; j += 4)
asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0);
}
@@ -938,7 +938,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
asd_write_reg_dword(asd_ha, SCBPRO, 0);
asd_write_reg_dword(asd_ha, CSEQCON, 0);
- /* Intialize CSEQ Mode 11 Interrupt Vectors.
+ /* Initialize CSEQ Mode 11 Interrupt Vectors.
* The addresses are 16 bit wide and in dword units.
* The values of their macros are in byte units.
* Thus we have to divide by 4. */
@@ -961,7 +961,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
for (i = 0; i < 8; i++) {
- /* Intialize Mode n Link m Interrupt Enable. */
+ /* Initialize Mode n Link m Interrupt Enable. */
asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF);
/* Initialize Mode n Request Mailbox. */
asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 05a78e515a24..1cadcd6b7da6 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -85,8 +85,7 @@ static int arcmsr_abort(struct scsi_cmnd *);
static int arcmsr_bus_reset(struct scsi_cmnd *);
static int arcmsr_bios_param(struct scsi_device *sdev,
struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
- void (*done) (struct scsi_cmnd *));
+static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int arcmsr_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void arcmsr_remove(struct pci_dev *pdev);
@@ -1172,9 +1171,8 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
- if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 || pcmd->cmnd[0]|WRITE_12 ){
+ if (pcmd->sc_data_direction == DMA_TO_DEVICE)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
- }
ccb->arc_cdb_size = arccdbsize;
return SUCCESS;
}
@@ -2081,7 +2079,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
}
}
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
void (* done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
@@ -2124,6 +2122,8 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(arcmsr_queue_command)
+
static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 918ccf818757..ec166726b314 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -2511,7 +2511,7 @@ acornscsi_intr(int irq, void *dev_id)
* done - function called on completion, with pointer to command descriptor
* Returns : 0, or < 0 on error.
*/
-int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
+static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
@@ -2561,6 +2561,8 @@ int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
return 0;
}
+DEF_SCSI_QCMD(acornscsi_queuecmd)
+
/*
* Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 9e71ac611146..2b2ce21e227e 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2198,7 +2198,7 @@ no_command:
* Returns: 0 on success, else error.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_queue_command(struct scsi_cmnd *SCpnt,
+static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2240,6 +2240,8 @@ int fas216_queue_command(struct scsi_cmnd *SCpnt,
return result;
}
+DEF_SCSI_QCMD(fas216_queue_command)
+
/**
* fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command
* @SCpnt: Command to wake
@@ -2263,7 +2265,7 @@ static void fas216_internal_done(struct scsi_cmnd *SCpnt)
* Returns: scsi result code.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
+static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2277,7 +2279,7 @@ int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
BUG_ON(info->scsi.irq != NO_IRQ);
info->internal_done = 0;
- fas216_queue_command(SCpnt, fas216_internal_done);
+ fas216_queue_command_lck(SCpnt, fas216_internal_done);
/*
* This wastes time, since we can't return until the command is
@@ -2310,6 +2312,8 @@ int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
return 0;
}
+DEF_SCSI_QCMD(fas216_noqueue_command)
+
/*
* Error handler timeout function. Indicate that we timed out,
* and wake up any error handler process so it can continue.
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index b65f4cf0eec9..f30f8d659dc4 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -331,23 +331,21 @@ extern int fas216_init (struct Scsi_Host *instance);
*/
extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
-/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
* Purpose : queue a command for adapter to process.
- * Params : SCpnt - Command to queue
- * done - done function to call once command is complete
+ * Params : h - host adapter
+ * : SCpnt - Command to queue
* Returns : 0 - success, else error
*/
-extern int fas216_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
-/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
* Purpose : queue a command for adapter to process, and process it to completion.
- * Params : SCpnt - Command to queue
- * done - done function to call once command is complete
+ * Params : h - host adapter
+ * : SCpnt - Command to queue
* Returns : 0 - success, else error
*/
-extern int fas216_noqueue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *);
/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
* Purpose : handle interrupts from the interface to progress a command
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 158ebc3644d8..88b2928b4d3b 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -910,7 +910,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
*
*/
-static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
SETUP_HOSTDATA(cmd->device->host);
Scsi_Cmnd *tmp;
@@ -1022,6 +1022,8 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
/*
* Function : NCR5380_main (void)
*
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index ad7a23aef0ec..3e8658e2f154 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -572,23 +572,6 @@ static void falcon_get_lock(void)
}
-/* This is the wrapper function for NCR5380_queue_command(). It just
- * tries to get the lock on the ST-DMA (see above) and then calls the
- * original function.
- */
-
-#if 0
-int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
-{
- /* falcon_get_lock();
- * ++guenther: moved to NCR5380_queue_command() to prevent
- * race condition, see there for an explanation.
- */
- return NCR5380_queue_command(cmd, done);
-}
-#endif
-
-
int __init atari_scsi_detect(struct scsi_host_template *host)
{
static int called = 0;
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index ab5bdda6903e..76029d570beb 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -605,7 +605,7 @@ handled:
*
* Queue a command to the ATP queue. Called with the host lock held.
*/
-static int atp870u_queuecommand(struct scsi_cmnd * req_p,
+static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
void (*done) (struct scsi_cmnd *))
{
unsigned char c;
@@ -694,6 +694,8 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
return 0;
}
+static DEF_SCSI_QCMD(atp870u_queuecommand)
+
/**
* send_s870 - send a command to the controller
* @host: host
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 75a85aa9e882..79cefbe31367 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -3785,7 +3785,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
dma_addr_t paddr;
io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool,
- GFP_KERNEL, &paddr);
+ GFP_ATOMIC, &paddr);
if (!io_task->cmd_bhs)
return -ENOMEM;
io_task->bhs_pa.u.a64.address = paddr;
@@ -3914,7 +3914,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
io_task->psgl_handle = NULL;
}
} else {
- if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN)
+ if (task->hdr &&
+ ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN))
return;
if (io_task->psgl_handle) {
spin_lock(&phba->mgmt_sgl_lock);
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile
index d2eefd3e3bd5..4ce6f4942327 100644
--- a/drivers/scsi/bfa/Makefile
+++ b/drivers/scsi/bfa/Makefile
@@ -3,6 +3,4 @@ obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o
bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o
bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o
-bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_drv.o bfa_svc.o
-
-ccflags-y := -DBFA_PERF_BUILD
+bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_svc.o
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index ceaac65a91ff..7be6b5a8114b 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -17,7 +17,7 @@
#ifndef __BFA_H__
#define __BFA_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_cs.h"
#include "bfa_plog.h"
#include "bfa_defs_svc.h"
@@ -29,13 +29,12 @@ struct bfa_s;
typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete);
-/**
+/*
* Interrupt message handlers
*/
void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
-void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
-/**
+/*
* Request and response queue related defines
*/
#define BFA_REQQ_NELEMS_MIN (4)
@@ -58,9 +57,9 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
#define bfa_reqq_produce(__bfa, __reqq) do { \
(__bfa)->iocfc.req_cq_pi[__reqq]++; \
(__bfa)->iocfc.req_cq_pi[__reqq] &= \
- ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
- bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \
- (__bfa)->iocfc.req_cq_pi[__reqq]); \
+ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
+ writel((__bfa)->iocfc.req_cq_pi[__reqq], \
+ (__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq]); \
mmiowb(); \
} while (0)
@@ -76,7 +75,7 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
(__index) &= ((__size) - 1); \
} while (0)
-/**
+/*
* Queue element to wait for room in request queue. FIFO order is
* maintained when fullfilling requests.
*/
@@ -86,7 +85,7 @@ struct bfa_reqq_wait_s {
void *cbarg;
};
-/**
+/*
* Circular queue usage assignments
*/
enum {
@@ -113,7 +112,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq])
-/**
+/*
* static inline void
* bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe)
*/
@@ -121,8 +120,8 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
\
struct list_head *waitq = bfa_reqq(__bfa, __reqq); \
\
- bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \
- bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \
+ WARN_ON(((__reqq) >= BFI_IOC_MAX_CQS)); \
+ WARN_ON(!((__wqe)->qresume && (__wqe)->cbarg)); \
\
list_add_tail(&(__wqe)->qe, waitq); \
} while (0)
@@ -130,7 +129,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe)
-/**
+/*
* Generic BFA callback element.
*/
struct bfa_cb_qe_s {
@@ -163,7 +162,7 @@ struct bfa_cb_qe_s {
} while (0)
-/**
+/*
* PCI devices supported by the current BFA
*/
struct bfa_pciid_s {
@@ -173,7 +172,7 @@ struct bfa_pciid_s {
extern char bfa_version[];
-/**
+/*
* BFA memory resources
*/
enum bfa_mem_type {
@@ -202,19 +201,19 @@ struct bfa_meminfo_s {
((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp)
struct bfa_iocfc_regs_s {
- bfa_os_addr_t intr_status;
- bfa_os_addr_t intr_mask;
- bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS];
- bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS];
- bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS];
- bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS];
- bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS];
- bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS];
- bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS];
- bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS];
+ void __iomem *intr_status;
+ void __iomem *intr_mask;
+ void __iomem *cpe_q_pi[BFI_IOC_MAX_CQS];
+ void __iomem *cpe_q_ci[BFI_IOC_MAX_CQS];
+ void __iomem *cpe_q_depth[BFI_IOC_MAX_CQS];
+ void __iomem *cpe_q_ctrl[BFI_IOC_MAX_CQS];
+ void __iomem *rme_q_ci[BFI_IOC_MAX_CQS];
+ void __iomem *rme_q_pi[BFI_IOC_MAX_CQS];
+ void __iomem *rme_q_depth[BFI_IOC_MAX_CQS];
+ void __iomem *rme_q_ctrl[BFI_IOC_MAX_CQS];
};
-/**
+/*
* MSIX vector handlers
*/
#define BFA_MSIX_MAX_VECTORS 22
@@ -224,7 +223,7 @@ struct bfa_msix_s {
bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS];
};
-/**
+/*
* Chip specific interfaces
*/
struct bfa_hwif_s {
@@ -297,7 +296,6 @@ void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad,
struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
-void bfa_iocfc_detach(struct bfa_s *bfa);
void bfa_iocfc_init(struct bfa_s *bfa);
void bfa_iocfc_start(struct bfa_s *bfa);
void bfa_iocfc_stop(struct bfa_s *bfa);
@@ -333,17 +331,14 @@ void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs,
u32 *maxvec);
void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start,
u32 *end);
-void bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi);
void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns);
wwn_t bfa_iocfc_get_pwwn(struct bfa_s *bfa);
wwn_t bfa_iocfc_get_nwwn(struct bfa_s *bfa);
-void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa,
- struct bfa_boot_pbc_s *pbcfg);
int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
struct bfi_pbc_vport_s *pbc_vport);
-/**
+/*
*----------------------------------------------------------------------
* BFA public interfaces
*----------------------------------------------------------------------
@@ -386,19 +381,11 @@ void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg,
void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
-void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod);
-void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog);
void bfa_detach(struct bfa_s *bfa);
-void bfa_init(struct bfa_s *bfa);
-void bfa_start(struct bfa_s *bfa);
-void bfa_stop(struct bfa_s *bfa);
-void bfa_attach_fcs(struct bfa_s *bfa);
void bfa_cb_init(void *bfad, bfa_status_t status);
void bfa_cb_updateq(void *bfad, bfa_status_t status);
bfa_boolean_t bfa_intx(struct bfa_s *bfa);
-void bfa_intx_disable(struct bfa_s *bfa);
-void bfa_intx_enable(struct bfa_s *bfa);
void bfa_isr_enable(struct bfa_s *bfa);
void bfa_isr_disable(struct bfa_s *bfa);
@@ -408,31 +395,14 @@ void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q);
typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status);
void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr);
-void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr);
-void bfa_adapter_get_attr(struct bfa_s *bfa,
- struct bfa_adapter_attr_s *ad_attr);
-u64 bfa_adapter_get_id(struct bfa_s *bfa);
bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
struct bfa_iocfc_intr_attr_s *attr);
void bfa_iocfc_enable(struct bfa_s *bfa);
void bfa_iocfc_disable(struct bfa_s *bfa);
-void bfa_chip_reset(struct bfa_s *bfa);
-void bfa_timer_tick(struct bfa_s *bfa);
#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \
bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
-/*
- * BFA debug API functions
- */
-bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen);
-bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen);
-bfa_status_t bfa_debug_fwcore(struct bfa_s *bfa, void *buf,
- u32 *offset, int *buflen);
-void bfa_debug_fwsave_clear(struct bfa_s *bfa);
-bfa_status_t bfa_fw_stats_get(struct bfa_s *bfa, void *data);
-bfa_status_t bfa_fw_stats_clear(struct bfa_s *bfa);
-
#endif /* __BFA_H__ */
diff --git a/drivers/scsi/bfa/bfa_cb_ioim.h b/drivers/scsi/bfa/bfa_cb_ioim.h
deleted file mode 100644
index a989a94c38da..000000000000
--- a/drivers/scsi/bfa/bfa_cb_ioim.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) 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.
- */
-
-#ifndef __BFA_HCB_IOIM_H__
-#define __BFA_HCB_IOIM_H__
-
-#include "bfa_os_inc.h"
-/*
- * task attribute values in FCP-2 FCP_CMND IU
- */
-#define SIMPLE_Q 0
-#define HEAD_OF_Q 1
-#define ORDERED_Q 2
-#define ACA_Q 4
-#define UNTAGGED 5
-
-static inline lun_t
-bfad_int_to_lun(u32 luno)
-{
- union {
- u16 scsi_lun[4];
- lun_t bfa_lun;
- } lun;
-
- lun.bfa_lun = 0;
- lun.scsi_lun[0] = bfa_os_htons(luno);
-
- return lun.bfa_lun;
-}
-
-/**
- * Get LUN for the I/O request
- */
-#define bfa_cb_ioim_get_lun(__dio) \
- bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
-
-/**
- * Get CDB for the I/O request
- */
-static inline u8 *
-bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return (u8 *) cmnd->cmnd;
-}
-
-/**
- * Get I/O direction (read/write) for the I/O request
- */
-static inline enum fcp_iodir
-bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- enum dma_data_direction dmadir;
-
- dmadir = cmnd->sc_data_direction;
- if (dmadir == DMA_TO_DEVICE)
- return FCP_IODIR_WRITE;
- else if (dmadir == DMA_FROM_DEVICE)
- return FCP_IODIR_READ;
- else
- return FCP_IODIR_NONE;
-}
-
-/**
- * Get IO size in bytes for the I/O request
- */
-static inline u32
-bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return scsi_bufflen(cmnd);
-}
-
-/**
- * Get timeout for the I/O request
- */
-static inline u8
-bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- /*
- * TBD: need a timeout for scsi passthru
- */
- if (cmnd->device->host == NULL)
- return 4;
-
- return 0;
-}
-
-/**
- * Get Command Reference Number for the I/O request. 0 if none.
- */
-static inline u8
-bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
-{
- return 0;
-}
-
-/**
- * Get SAM-3 priority for the I/O request. 0 is default.
- */
-static inline u8
-bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
-{
- return 0;
-}
-
-/**
- * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
- */
-static inline u8
-bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- u8 task_attr = UNTAGGED;
-
- if (cmnd->device->tagged_supported) {
- switch (cmnd->tag) {
- case HEAD_OF_QUEUE_TAG:
- task_attr = HEAD_OF_Q;
- break;
- case ORDERED_QUEUE_TAG:
- task_attr = ORDERED_Q;
- break;
- default:
- task_attr = SIMPLE_Q;
- break;
- }
- }
-
- return task_attr;
-}
-
-/**
- * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
- */
-static inline u8
-bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
-{
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-
- return cmnd->cmd_len;
-}
-
-/**
- * Assign queue to be used for the I/O request. This value depends on whether
- * the driver wants to use the queues via any specific algorithm. Currently,
- * this is not supported.
- */
-#define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE
-
-#endif /* __BFA_HCB_IOIM_H__ */
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index c2fa07f2485d..1cd5c8b0618d 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -15,17 +15,104 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_ctreg.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(HAL, CORE);
-/**
+/*
+ * BFA module list terminated by NULL
+ */
+static struct bfa_module_s *hal_mods[] = {
+ &hal_mod_sgpg,
+ &hal_mod_fcport,
+ &hal_mod_fcxp,
+ &hal_mod_lps,
+ &hal_mod_uf,
+ &hal_mod_rport,
+ &hal_mod_fcpim,
+ NULL
+};
+
+/*
+ * Message handlers for various modules.
+ */
+static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
+ bfa_isr_unhandled, /* NONE */
+ bfa_isr_unhandled, /* BFI_MC_IOC */
+ bfa_isr_unhandled, /* BFI_MC_DIAG */
+ bfa_isr_unhandled, /* BFI_MC_FLASH */
+ bfa_isr_unhandled, /* BFI_MC_CEE */
+ bfa_fcport_isr, /* BFI_MC_FCPORT */
+ bfa_isr_unhandled, /* BFI_MC_IOCFC */
+ bfa_isr_unhandled, /* BFI_MC_LL */
+ bfa_uf_isr, /* BFI_MC_UF */
+ bfa_fcxp_isr, /* BFI_MC_FCXP */
+ bfa_lps_isr, /* BFI_MC_LPS */
+ bfa_rport_isr, /* BFI_MC_RPORT */
+ bfa_itnim_isr, /* BFI_MC_ITNIM */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
+ bfa_ioim_isr, /* BFI_MC_IOIM */
+ bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
+ bfa_tskim_isr, /* BFI_MC_TSKIM */
+ bfa_isr_unhandled, /* BFI_MC_SBOOT */
+ bfa_isr_unhandled, /* BFI_MC_IPFC */
+ bfa_isr_unhandled, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+};
+/*
+ * Message handlers for mailbox command classes
+ */
+static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+ NULL,
+ NULL, /* BFI_MC_IOC */
+ NULL, /* BFI_MC_DIAG */
+ NULL, /* BFI_MC_FLASH */
+ NULL, /* BFI_MC_CEE */
+ NULL, /* BFI_MC_PORT */
+ bfa_iocfc_isr, /* BFI_MC_IOCFC */
+ NULL,
+};
+
+
+
+static void
+bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
+{
+ struct bfa_port_s *port = &bfa->modules.port;
+ u32 dm_len;
+ u8 *dm_kva;
+ u64 dm_pa;
+
+ dm_len = bfa_port_meminfo();
+ dm_kva = bfa_meminfo_dma_virt(mi);
+ dm_pa = bfa_meminfo_dma_phys(mi);
+
+ memset(port, 0, sizeof(struct bfa_port_s));
+ bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod);
+ bfa_port_mem_claim(port, dm_kva, dm_pa);
+
+ bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
+ bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
+}
+
+/*
* BFA IOC FC related definitions
*/
-/**
+/*
* IOC local definitions
*/
#define BFA_IOCFC_TOV 5000 /* msecs */
@@ -54,7 +141,7 @@ enum {
#define DEF_CFG_NUM_SBOOT_TGTS 16
#define DEF_CFG_NUM_SBOOT_LUNS 16
-/**
+/*
* forward declaration for IOC FC functions
*/
static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
@@ -63,22 +150,10 @@ static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
static void bfa_iocfc_reset_cbfn(void *bfa_arg);
static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
-/**
+/*
* BFA Interrupt handling functions
*/
static void
-bfa_msix_errint(struct bfa_s *bfa, u32 intr)
-{
- bfa_ioc_error_isr(&bfa->ioc);
-}
-
-static void
-bfa_msix_lpu(struct bfa_s *bfa)
-{
- bfa_ioc_mbox_isr(&bfa->ioc);
-}
-
-static void
bfa_reqq_resume(struct bfa_s *bfa, int qid)
{
struct list_head *waitq, *qe, *qen;
@@ -86,7 +161,7 @@ bfa_reqq_resume(struct bfa_s *bfa, int qid)
waitq = bfa_reqq(bfa, qid);
list_for_each_safe(qe, qen, waitq) {
- /**
+ /*
* Callback only as long as there is room in request queue
*/
if (bfa_reqq_full(bfa, qid))
@@ -104,24 +179,21 @@ bfa_msix_all(struct bfa_s *bfa, int vec)
bfa_intx(bfa);
}
-/**
- * hal_intr_api
- */
bfa_boolean_t
bfa_intx(struct bfa_s *bfa)
{
u32 intr, qintr;
int queue;
- intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+ intr = readl(bfa->iocfc.bfa_regs.intr_status);
if (!intr)
return BFA_FALSE;
- /**
+ /*
* RME completion queue interrupt
*/
qintr = intr & __HFN_INT_RME_MASK;
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+ writel(qintr, bfa->iocfc.bfa_regs.intr_status);
for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
if (intr & (__HFN_INT_RME_Q0 << queue))
@@ -131,11 +203,11 @@ bfa_intx(struct bfa_s *bfa)
if (!intr)
return BFA_TRUE;
- /**
+ /*
* CPE completion queue interrupt
*/
qintr = intr & __HFN_INT_CPE_MASK;
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+ writel(qintr, bfa->iocfc.bfa_regs.intr_status);
for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
if (intr & (__HFN_INT_CPE_Q0 << queue))
@@ -151,18 +223,6 @@ bfa_intx(struct bfa_s *bfa)
}
void
-bfa_intx_enable(struct bfa_s *bfa)
-{
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, bfa->iocfc.intr_mask);
-}
-
-void
-bfa_intx_disable(struct bfa_s *bfa)
-{
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
-}
-
-void
bfa_isr_enable(struct bfa_s *bfa)
{
u32 intr_unmask;
@@ -188,8 +248,8 @@ bfa_isr_enable(struct bfa_s *bfa)
__HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
__HFN_INT_MBOX_LPU1);
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+ writel(intr_unmask, bfa->iocfc.bfa_regs.intr_status);
+ writel(~intr_unmask, bfa->iocfc.bfa_regs.intr_mask);
bfa->iocfc.intr_mask = ~intr_unmask;
bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
}
@@ -198,7 +258,7 @@ void
bfa_isr_disable(struct bfa_s *bfa)
{
bfa_isr_mode_set(bfa, BFA_FALSE);
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
+ writel(-1L, bfa->iocfc.bfa_regs.intr_mask);
bfa_msix_uninstall(bfa);
}
@@ -211,7 +271,7 @@ bfa_msix_reqq(struct bfa_s *bfa, int qid)
bfa->iocfc.hwif.hw_reqq_ack(bfa, qid);
- /**
+ /*
* Resume any pending requests in the corresponding reqq.
*/
waitq = bfa_reqq(bfa, qid);
@@ -225,7 +285,7 @@ bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
bfa_trc(bfa, m->mhdr.msg_class);
bfa_trc(bfa, m->mhdr.msg_id);
bfa_trc(bfa, m->mhdr.mtag.i2htok);
- bfa_assert(0);
+ WARN_ON(1);
bfa_trc_stop(bfa->trcmod);
}
@@ -236,8 +296,6 @@ bfa_msix_rspq(struct bfa_s *bfa, int qid)
u32 pi, ci;
struct list_head *waitq;
- bfa_trc_fp(bfa, qid);
-
qid &= (BFI_IOC_MAX_CQS - 1);
bfa->iocfc.hwif.hw_rspq_ack(bfa, qid);
@@ -245,28 +303,22 @@ bfa_msix_rspq(struct bfa_s *bfa, int qid)
ci = bfa_rspq_ci(bfa, qid);
pi = bfa_rspq_pi(bfa, qid);
- bfa_trc_fp(bfa, ci);
- bfa_trc_fp(bfa, pi);
-
if (bfa->rme_process) {
while (ci != pi) {
m = bfa_rspq_elem(bfa, qid, ci);
- bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
-
bfa_isrs[m->mhdr.msg_class] (bfa, m);
-
CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems);
}
}
- /**
+ /*
* update CI
*/
bfa_rspq_ci(bfa, qid) = pi;
- bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi);
+ writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]);
mmiowb();
- /**
+ /*
* Resume any pending requests in the corresponding reqq.
*/
waitq = bfa_reqq(bfa, qid);
@@ -279,56 +331,50 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
{
u32 intr, curr_value;
- intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+ intr = readl(bfa->iocfc.bfa_regs.intr_status);
if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
- bfa_msix_lpu(bfa);
+ bfa_ioc_mbox_isr(&bfa->ioc);
intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
__HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT);
if (intr) {
if (intr & __HFN_INT_LL_HALT) {
- /**
+ /*
* If LL_HALT bit is set then FW Init Halt LL Port
* Register needs to be cleared as well so Interrupt
* Status Register will be cleared.
*/
- curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt);
+ curr_value = readl(bfa->ioc.ioc_regs.ll_halt);
curr_value &= ~__FW_INIT_HALT_P;
- bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value);
+ writel(curr_value, bfa->ioc.ioc_regs.ll_halt);
}
if (intr & __HFN_INT_ERR_PSS) {
- /**
+ /*
* ERR_PSS bit needs to be cleared as well in case
* interrups are shared so driver's interrupt handler is
* still called eventhough it is already masked out.
*/
- curr_value = bfa_reg_read(
+ curr_value = readl(
bfa->ioc.ioc_regs.pss_err_status_reg);
curr_value &= __PSS_ERR_STATUS_SET;
- bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg,
- curr_value);
+ writel(curr_value,
+ bfa->ioc.ioc_regs.pss_err_status_reg);
}
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr);
- bfa_msix_errint(bfa, intr);
+ writel(intr, bfa->iocfc.bfa_regs.intr_status);
+ bfa_ioc_error_isr(&bfa->ioc);
}
}
-void
-bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
-{
- bfa_isrs[mc] = isr_func;
-}
-
-/**
+/*
* BFA IOC FC related functions
*/
-/**
- * hal_ioc_pvt BFA IOC private functions
+/*
+ * BFA IOC private functions
*/
static void
@@ -366,7 +412,7 @@ bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
BFA_CACHELINE_SZ);
}
-/**
+/*
* Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
*/
static void
@@ -379,19 +425,19 @@ bfa_iocfc_send_cfg(void *bfa_arg)
struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg;
int i;
- bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
+ WARN_ON(cfg->fwcfg.num_cqs > BFI_IOC_MAX_CQS);
bfa_trc(bfa, cfg->fwcfg.num_cqs);
bfa_iocfc_reset_queues(bfa);
- /**
+ /*
* initialize IOC configuration info
*/
cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
cfg_info->num_cqs = cfg->fwcfg.num_cqs;
bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
- /**
+ /*
* dma map REQ and RSP circular queues and shadow pointers
*/
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
@@ -400,17 +446,17 @@ bfa_iocfc_send_cfg(void *bfa_arg)
bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
iocfc->req_cq_shadow_ci[i].pa);
cfg_info->req_cq_elems[i] =
- bfa_os_htons(cfg->drvcfg.num_reqq_elems);
+ cpu_to_be16(cfg->drvcfg.num_reqq_elems);
bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
iocfc->rsp_cq_ba[i].pa);
bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
iocfc->rsp_cq_shadow_pi[i].pa);
cfg_info->rsp_cq_elems[i] =
- bfa_os_htons(cfg->drvcfg.num_rspq_elems);
+ cpu_to_be16(cfg->drvcfg.num_rspq_elems);
}
- /**
+ /*
* Enable interrupt coalescing if it is driver init path
* and not ioc disable/enable path.
*/
@@ -419,7 +465,7 @@ bfa_iocfc_send_cfg(void *bfa_arg)
iocfc->cfgdone = BFA_FALSE;
- /**
+ /*
* dma map IOC configuration itself
*/
bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
@@ -440,9 +486,9 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
iocfc->bfa = bfa;
iocfc->action = BFA_IOCFC_ACT_NONE;
- bfa_os_assign(iocfc->cfg, *cfg);
+ iocfc->cfg = *cfg;
- /**
+ /*
* Initialize chip specific handlers.
*/
if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) {
@@ -488,8 +534,8 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
* First allocate dma memory for IOC.
*/
bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
- dm_kva += bfa_ioc_meminfo();
- dm_pa += bfa_ioc_meminfo();
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
/*
* Claim DMA-able memory for the request/response queues and for shadow
@@ -503,13 +549,13 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
iocfc->req_cq_ba[i].kva = dm_kva;
iocfc->req_cq_ba[i].pa = dm_pa;
- bfa_os_memset(dm_kva, 0, per_reqq_sz);
+ memset(dm_kva, 0, per_reqq_sz);
dm_kva += per_reqq_sz;
dm_pa += per_reqq_sz;
iocfc->rsp_cq_ba[i].kva = dm_kva;
iocfc->rsp_cq_ba[i].pa = dm_pa;
- bfa_os_memset(dm_kva, 0, per_rspq_sz);
+ memset(dm_kva, 0, per_rspq_sz);
dm_kva += per_rspq_sz;
dm_pa += per_rspq_sz;
}
@@ -552,14 +598,14 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
bfa_meminfo_dma_virt(meminfo) = dm_kva;
bfa_meminfo_dma_phys(meminfo) = dm_pa;
- dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
+ dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
if (dbgsz > 0) {
bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
bfa_meminfo_kva(meminfo) += dbgsz;
}
}
-/**
+/*
* Start BFA submodules.
*/
static void
@@ -573,7 +619,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa)
hal_mods[i]->start(bfa);
}
-/**
+/*
* Disable BFA submodules.
*/
static void
@@ -623,7 +669,7 @@ bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl)
complete(&bfad->disable_comp);
}
-/**
+/*
* Update BFA configuration from firmware configuration.
*/
static void
@@ -634,15 +680,15 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
fwcfg->num_cqs = fwcfg->num_cqs;
- fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
- fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
- fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
- fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
- fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
+ fwcfg->num_ioim_reqs = be16_to_cpu(fwcfg->num_ioim_reqs);
+ fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs);
+ fwcfg->num_fcxp_reqs = be16_to_cpu(fwcfg->num_fcxp_reqs);
+ fwcfg->num_uf_bufs = be16_to_cpu(fwcfg->num_uf_bufs);
+ fwcfg->num_rports = be16_to_cpu(fwcfg->num_rports);
iocfc->cfgdone = BFA_TRUE;
- /**
+ /*
* Configuration is complete - initialize/start submodules
*/
bfa_fcport_init(bfa);
@@ -665,7 +711,7 @@ bfa_iocfc_reset_queues(struct bfa_s *bfa)
}
}
-/**
+/*
* IOC enable request is complete
*/
static void
@@ -684,7 +730,7 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
bfa_iocfc_send_cfg(bfa);
}
-/**
+/*
* IOC disable request is complete
*/
static void
@@ -699,13 +745,13 @@ bfa_iocfc_disable_cbfn(void *bfa_arg)
bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
bfa);
else {
- bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE);
+ WARN_ON(bfa->iocfc.action != BFA_IOCFC_ACT_DISABLE);
bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
bfa);
}
}
-/**
+/*
* Notify sub-modules of hardware failure.
*/
static void
@@ -723,7 +769,7 @@ bfa_iocfc_hbfail_cbfn(void *bfa_arg)
bfa);
}
-/**
+/*
* Actions on chip-reset completion.
*/
static void
@@ -735,11 +781,8 @@ bfa_iocfc_reset_cbfn(void *bfa_arg)
bfa_isr_enable(bfa);
}
-/**
- * hal_ioc_public
- */
-/**
+/*
* Query IOC memory requirement information.
*/
void
@@ -747,14 +790,14 @@ bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
u32 *dm_len)
{
/* dma memory for IOC */
- *dm_len += bfa_ioc_meminfo();
+ *dm_len += BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
bfa_iocfc_fw_cfg_sz(cfg, dm_len);
bfa_iocfc_cqs_sz(cfg, dm_len);
- *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
+ *km_len += (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
}
-/**
+/*
* Query IOC memory requirement information.
*/
void
@@ -772,7 +815,7 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
ioc->trcmod = bfa->trcmod;
bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod);
- /**
+ /*
* Set FC mode for BFA_PCI_DEVICE_ID_CT_FC.
*/
if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC)
@@ -783,23 +826,14 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
bfa_iocfc_mem_claim(bfa, cfg, meminfo);
- bfa_timer_init(&bfa->timer_mod);
+ INIT_LIST_HEAD(&bfa->timer_mod.timer_q);
INIT_LIST_HEAD(&bfa->comp_q);
for (i = 0; i < BFI_IOC_MAX_CQS; i++)
INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
}
-/**
- * Query IOC memory requirement information.
- */
-void
-bfa_iocfc_detach(struct bfa_s *bfa)
-{
- bfa_ioc_detach(&bfa->ioc);
-}
-
-/**
+/*
* Query IOC memory requirement information.
*/
void
@@ -809,7 +843,7 @@ bfa_iocfc_init(struct bfa_s *bfa)
bfa_ioc_enable(&bfa->ioc);
}
-/**
+/*
* IOC start called from bfa_start(). Called to start IOC operations
* at driver instantiation for this instance.
*/
@@ -820,7 +854,7 @@ bfa_iocfc_start(struct bfa_s *bfa)
bfa_iocfc_start_submod(bfa);
}
-/**
+/*
* IOC stop called from bfa_stop(). Called only when driver is unloaded
* for this instance.
*/
@@ -852,23 +886,11 @@ bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m)
iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK);
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
}
void
-bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
-{
- bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
-}
-
-u64
-bfa_adapter_get_id(struct bfa_s *bfa)
-{
- return bfa_ioc_get_adid(&bfa->ioc);
-}
-
-void
bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
{
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
@@ -876,12 +898,12 @@ bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce;
attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ?
- bfa_os_ntohs(iocfc->cfginfo->intr_attr.delay) :
- bfa_os_ntohs(iocfc->cfgrsp->intr_attr.delay);
+ be16_to_cpu(iocfc->cfginfo->intr_attr.delay) :
+ be16_to_cpu(iocfc->cfgrsp->intr_attr.delay);
attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ?
- bfa_os_ntohs(iocfc->cfginfo->intr_attr.latency) :
- bfa_os_ntohs(iocfc->cfgrsp->intr_attr.latency);
+ be16_to_cpu(iocfc->cfginfo->intr_attr.latency) :
+ be16_to_cpu(iocfc->cfgrsp->intr_attr.latency);
attr->config = iocfc->cfg;
}
@@ -893,8 +915,8 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
struct bfi_iocfc_set_intr_req_s *m;
iocfc->cfginfo->intr_attr.coalesce = attr->coalesce;
- iocfc->cfginfo->intr_attr.delay = bfa_os_htons(attr->delay);
- iocfc->cfginfo->intr_attr.latency = bfa_os_htons(attr->latency);
+ iocfc->cfginfo->intr_attr.delay = cpu_to_be16(attr->delay);
+ iocfc->cfginfo->intr_attr.latency = cpu_to_be16(attr->latency);
if (!bfa_iocfc_is_operational(bfa))
return BFA_STATUS_OK;
@@ -924,7 +946,7 @@ bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
}
-/**
+/*
* Enable IOC after it is disabled.
*/
void
@@ -953,7 +975,7 @@ bfa_iocfc_is_operational(struct bfa_s *bfa)
return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
}
-/**
+/*
* Return boot target port wwns -- read from boot information in flash.
*/
void
@@ -976,18 +998,6 @@ bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns)
memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(cfgrsp->bootwwns.wwn));
}
-void
-bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg)
-{
- struct bfa_iocfc_s *iocfc = &bfa->iocfc;
- struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
-
- pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled;
- pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns;
- pbcfg->speed = cfgrsp->pbc_cfg.port_speed;
- memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun));
-}
-
int
bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport)
{
@@ -998,11 +1008,8 @@ bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport)
return cfgrsp->pbc_cfg.nvports;
}
-/**
- * hal_api
- */
-/**
+/*
* Use this function query the memory requirement of the BFA library.
* This function needs to be called before bfa_attach() to get the
* memory required of the BFA layer for a given driver configuration.
@@ -1036,9 +1043,9 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
int i;
u32 km_len = 0, dm_len = 0;
- bfa_assert((cfg != NULL) && (meminfo != NULL));
+ WARN_ON((cfg == NULL) || (meminfo == NULL));
- bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
+ memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
BFA_MEM_TYPE_KVA;
meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
@@ -1055,7 +1062,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
}
-/**
+/*
* Use this function to do attach the driver instance with the BFA
* library. This function will not trigger any HW initialization
* process (which will be done in bfa_init() call)
@@ -1090,9 +1097,9 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa->fcs = BFA_FALSE;
- bfa_assert((cfg != NULL) && (meminfo != NULL));
+ WARN_ON((cfg == NULL) || (meminfo == NULL));
- /**
+ /*
* initialize all memory pointers for iterative allocation
*/
for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
@@ -1109,7 +1116,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_com_port_attach(bfa, meminfo);
}
-/**
+/*
* Use this function to delete a BFA IOC. IOC should be stopped (by
* calling bfa_stop()) before this function call.
*
@@ -1129,79 +1136,7 @@ bfa_detach(struct bfa_s *bfa)
for (i = 0; hal_mods[i]; i++)
hal_mods[i]->detach(bfa);
-
- bfa_iocfc_detach(bfa);
-}
-
-
-void
-bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
-{
- bfa->trcmod = trcmod;
-}
-
-void
-bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
-{
- bfa->plog = plog;
-}
-
-/**
- * Initialize IOC.
- *
- * This function will return immediately, when the IOC initialization is
- * completed, the bfa_cb_init() will be called.
- *
- * @param[in] bfa instance
- *
- * @return void
- *
- * Special Considerations:
- *
- * @note
- * When this function returns, the driver should register the interrupt service
- * routine(s) and enable the device interrupts. If this is not done,
- * bfa_cb_init() will never get called
- */
-void
-bfa_init(struct bfa_s *bfa)
-{
- bfa_iocfc_init(bfa);
-}
-
-/**
- * Use this function initiate the IOC configuration setup. This function
- * will return immediately.
- *
- * @param[in] bfa instance
- *
- * @return None
- */
-void
-bfa_start(struct bfa_s *bfa)
-{
- bfa_iocfc_start(bfa);
-}
-
-/**
- * Use this function quiese the IOC. This function will return immediately,
- * when the IOC is actually stopped, the bfad->comp will be set.
- *
- * @param[in]bfa - pointer to bfa_t.
- *
- * @return None
- *
- * Special Considerations:
- * bfad->comp can be set before or after bfa_stop() returns.
- *
- * @note
- * In case of any failure, we could handle it automatically by doing a
- * reset and then succeed the bfa_stop() call.
- */
-void
-bfa_stop(struct bfa_s *bfa)
-{
- bfa_iocfc_stop(bfa);
+ bfa_ioc_detach(&bfa->ioc);
}
void
@@ -1237,22 +1172,8 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
}
}
-void
-bfa_attach_fcs(struct bfa_s *bfa)
-{
- bfa->fcs = BFA_TRUE;
-}
-/**
- * Periodic timer heart beat from driver
- */
-void
-bfa_timer_tick(struct bfa_s *bfa)
-{
- bfa_timer_beat(&bfa->timer_mod);
-}
-
-/**
+/*
* Return the list of PCI vendor/device id lists supported by this
* BFA instance.
*/
@@ -1270,7 +1191,7 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
*pciids = __pciids;
}
-/**
+/*
* Use this function query the default struct bfa_iocfc_cfg_s value (compiled
* into BFA layer). The OS driver can then turn back and overwrite entries that
* have been configured by the user.
@@ -1321,89 +1242,3 @@ bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg)
cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
cfg->drvcfg.min_cfg = BFA_TRUE;
}
-
-void
-bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
-{
- bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
-}
-
-/**
- * Retrieve firmware trace information on IOC failure.
- */
-bfa_status_t
-bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
-{
- return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
-}
-
-/**
- * Clear the saved firmware trace information of an IOC.
- */
-void
-bfa_debug_fwsave_clear(struct bfa_s *bfa)
-{
- bfa_ioc_debug_fwsave_clear(&bfa->ioc);
-}
-
-/**
- * Fetch firmware trace data.
- *
- * @param[in] bfa BFA instance
- * @param[out] trcdata Firmware trace buffer
- * @param[in,out] trclen Firmware trace buffer len
- *
- * @retval BFA_STATUS_OK Firmware trace is fetched.
- * @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
- */
-bfa_status_t
-bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
-{
- return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
-}
-
-/**
- * Dump firmware memory.
- *
- * @param[in] bfa BFA instance
- * @param[out] buf buffer for dump
- * @param[in,out] offset smem offset to start read
- * @param[in,out] buflen length of buffer
- *
- * @retval BFA_STATUS_OK Firmware memory is dumped.
- * @retval BFA_STATUS_INPROGRESS Firmware memory dump is in progress.
- */
-bfa_status_t
-bfa_debug_fwcore(struct bfa_s *bfa, void *buf, u32 *offset, int *buflen)
-{
- return bfa_ioc_debug_fwcore(&bfa->ioc, buf, offset, buflen);
-}
-/**
- * Reset hw semaphore & usage cnt regs and initialize.
- */
-void
-bfa_chip_reset(struct bfa_s *bfa)
-{
- bfa_ioc_ownership_reset(&bfa->ioc);
- bfa_ioc_pll_init(&bfa->ioc);
-}
-
-/**
- * Fetch firmware statistics data.
- *
- * @param[in] bfa BFA instance
- * @param[out] data Firmware stats buffer
- *
- * @retval BFA_STATUS_OK Firmware trace is fetched.
- */
-bfa_status_t
-bfa_fw_stats_get(struct bfa_s *bfa, void *data)
-{
- return bfa_ioc_fw_stats_get(&bfa->ioc, data);
-}
-
-bfa_status_t
-bfa_fw_stats_clear(struct bfa_s *bfa)
-{
- return bfa_ioc_fw_stats_clear(&bfa->ioc);
-}
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index 7260c74620f8..12bfeed268eb 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -15,16 +15,16 @@
* General Public License for more details.
*/
-/**
+/*
* bfa_cs.h BFA common services
*/
#ifndef __BFA_CS_H__
#define __BFA_CS_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
-/**
+/*
* BFA TRC
*/
@@ -32,12 +32,20 @@
#define BFA_TRC_MAX (4 * 1024)
#endif
+#define BFA_TRC_TS(_trcm) \
+ ({ \
+ struct timeval tv; \
+ \
+ do_gettimeofday(&tv); \
+ (tv.tv_sec*1000000+tv.tv_usec); \
+ })
+
#ifndef BFA_TRC_TS
#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
#endif
struct bfa_trc_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u16 fileno;
u16 line;
#else
@@ -73,7 +81,7 @@ enum {
#define BFA_TRC_MOD_SH 10
#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
-/**
+/*
* Define a new tracing file (module). Module should match one defined above.
*/
#define BFA_TRC_FILE(__mod, __submod) \
@@ -99,13 +107,6 @@ bfa_trc_stop(struct bfa_trc_mod_s *trcm)
trcm->stopped = 1;
}
-#ifdef FWTRC
-extern void dc_flush(void *data);
-#else
-#define dc_flush(data)
-#endif
-
-
static inline void
__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
{
@@ -119,12 +120,10 @@ __bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
trc->line = (u16) line;
trc->data.u64 = data;
trc->timestamp = BFA_TRC_TS(trcm);
- dc_flush(trc);
trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
if (trcm->tail == trcm->head)
trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
- dc_flush(trcm);
}
@@ -141,42 +140,18 @@ __bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
trc->line = (u16) line;
trc->data.u32.u32 = data;
trc->timestamp = BFA_TRC_TS(trcm);
- dc_flush(trc);
trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
if (trcm->tail == trcm->head)
trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
- dc_flush(trcm);
}
-#ifndef BFA_PERF_BUILD
-#define bfa_trc_fp(_trcp, _data) bfa_trc(_trcp, _data)
-#else
-#define bfa_trc_fp(_trcp, _data)
-#endif
-
-/**
- * @ BFA LOG interfaces
- */
-#define bfa_assert(__cond) do { \
- if (!(__cond)) { \
- printk(KERN_ERR "assert(%s) failed at %s:%d\\n", \
- #__cond, __FILE__, __LINE__); \
- } \
-} while (0)
-
#define bfa_sm_fault(__mod, __event) do { \
bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \
printk(KERN_ERR "Assertion failure: %s:%d: %d", \
__FILE__, __LINE__, (__event)); \
} while (0)
-#ifndef BFA_PERF_BUILD
-#define bfa_assert_fp(__cond) bfa_assert(__cond)
-#else
-#define bfa_assert_fp(__cond)
-#endif
-
/* BFA queue definitions */
#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
@@ -199,7 +174,6 @@ __bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
(struct list_head *) (_q); \
bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe));\
- BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
} else { \
*((struct list_head **) (_qe)) = (struct list_head *) NULL;\
} \
@@ -214,7 +188,6 @@ __bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
(struct list_head *) (_q); \
bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\
- BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
} else { \
*((struct list_head **) (_qe)) = (struct list_head *) NULL;\
} \
@@ -236,26 +209,16 @@ bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
return 0;
}
-/*
- * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not
- * consistent across modules)
- */
-#ifndef BFA_PERF_BUILD
-#define BFA_Q_DBG_INIT(_qe) bfa_q_qe_init(_qe)
-#else
-#define BFA_Q_DBG_INIT(_qe)
-#endif
-
#define bfa_q_is_on_q(_q, _qe) \
bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
-/**
+/*
* @ BFA state machine interfaces
*/
typedef void (*bfa_sm_t)(void *sm, int event);
-/**
+/*
* oc - object class eg. bfa_ioc
* st - state, eg. reset
* otype - object type, eg. struct bfa_ioc_s
@@ -269,7 +232,7 @@ typedef void (*bfa_sm_t)(void *sm, int event);
#define bfa_sm_get_state(_sm) ((_sm)->sm)
#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
-/**
+/*
* For converting from state machine function to state encoding.
*/
struct bfa_sm_table_s {
@@ -279,12 +242,12 @@ struct bfa_sm_table_s {
};
#define BFA_SM(_sm) ((bfa_sm_t)(_sm))
-/**
+/*
* State machine with entry actions.
*/
typedef void (*bfa_fsm_t)(void *fsm, int event);
-/**
+/*
* oc - object class eg. bfa_ioc
* st - state, eg. reset
* otype - object type, eg. struct bfa_ioc_s
@@ -314,7 +277,7 @@ bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm)
return smt[i].state;
}
-/**
+/*
* @ Generic wait counter.
*/
@@ -340,7 +303,7 @@ bfa_wc_down(struct bfa_wc_s *wc)
wc->wc_resume(wc->wc_cbarg);
}
-/**
+/*
* Initialize a waiting counter.
*/
static inline void
@@ -352,7 +315,7 @@ bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
bfa_wc_up(wc);
}
-/**
+/*
* Wait for counter to reach zero
*/
static inline void
@@ -361,4 +324,43 @@ bfa_wc_wait(struct bfa_wc_s *wc)
bfa_wc_down(wc);
}
+static inline void
+wwn2str(char *wwn_str, u64 wwn)
+{
+ union {
+ u64 wwn;
+ u8 byte[8];
+ } w;
+
+ w.wwn = wwn;
+ sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
+ w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
+ w.byte[6], w.byte[7]);
+}
+
+static inline void
+fcid2str(char *fcid_str, u32 fcid)
+{
+ union {
+ u32 fcid;
+ u8 byte[4];
+ } f;
+
+ f.fcid = fcid;
+ sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
+}
+
+#define bfa_swap_3b(_x) \
+ ((((_x) & 0xff) << 16) | \
+ ((_x) & 0x00ff00) | \
+ (((_x) & 0xff0000) >> 16))
+
+#ifndef __BIG_ENDIAN
+#define bfa_hton3b(_x) bfa_swap_3b(_x)
+#else
+#define bfa_hton3b(_x) (_x)
+#endif
+
+#define bfa_ntoh3b(_x) bfa_hton3b(_x)
+
#endif /* __BFA_CS_H__ */
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index d49877ff5140..d85f93aea465 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -19,12 +19,12 @@
#define __BFA_DEFS_H__
#include "bfa_fc.h"
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#define BFA_MFG_SERIALNUM_SIZE 11
#define STRSZ(_n) (((_n) + 4) & ~3)
-/**
+/*
* Manufacturing card type
*/
enum {
@@ -45,7 +45,7 @@ enum {
#pragma pack(1)
-/**
+/*
* Check if Mezz card
*/
#define bfa_mfg_is_mezz(type) (( \
@@ -55,7 +55,7 @@ enum {
(type) == BFA_MFG_TYPE_LIGHTNING_P0 || \
(type) == BFA_MFG_TYPE_LIGHTNING))
-/**
+/*
* Check if the card having old wwn/mac handling
*/
#define bfa_mfg_is_old_wwn_mac_model(type) (( \
@@ -78,12 +78,12 @@ do { \
(m)[2] = t & 0xFF; \
} while (0)
-/**
+/*
* VPD data length
*/
#define BFA_MFG_VPD_LEN 512
-/**
+/*
* VPD vendor tag
*/
enum {
@@ -97,7 +97,7 @@ enum {
BFA_MFG_VPD_PCI_BRCD = 0xf8, /* PCI VPD Brocade */
};
-/**
+/*
* All numerical fields are in big-endian format.
*/
struct bfa_mfg_vpd_s {
@@ -112,7 +112,7 @@ struct bfa_mfg_vpd_s {
#pragma pack()
-/**
+/*
* Status return values
*/
enum bfa_status {
@@ -167,11 +167,11 @@ enum bfa_boolean {
#define BFA_STRING_32 32
#define BFA_VERSION_LEN 64
-/**
+/*
* ---------------------- adapter definitions ------------
*/
-/**
+/*
* BFA adapter level attributes.
*/
enum {
@@ -215,7 +215,7 @@ struct bfa_adapter_attr_s {
u8 trunk_capable;
};
-/**
+/*
* ---------------------- IOC definitions ------------
*/
@@ -224,7 +224,7 @@ enum {
BFA_IOC_CHIP_REV_LEN = 8,
};
-/**
+/*
* Driver and firmware versions.
*/
struct bfa_ioc_driver_attr_s {
@@ -236,7 +236,7 @@ struct bfa_ioc_driver_attr_s {
char ob_ver[BFA_VERSION_LEN]; /* openboot version */
};
-/**
+/*
* IOC PCI device attributes
*/
struct bfa_ioc_pci_attr_s {
@@ -249,7 +249,7 @@ struct bfa_ioc_pci_attr_s {
char chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */
};
-/**
+/*
* IOC states
*/
enum bfa_ioc_state {
@@ -267,7 +267,7 @@ enum bfa_ioc_state {
BFA_IOC_ENABLING = 12, /* IOC is being enabled */
};
-/**
+/*
* IOC firmware stats
*/
struct bfa_fw_ioc_stats_s {
@@ -279,7 +279,7 @@ struct bfa_fw_ioc_stats_s {
u32 unknown_reqs;
};
-/**
+/*
* IOC driver stats
*/
struct bfa_ioc_drv_stats_s {
@@ -296,7 +296,7 @@ struct bfa_ioc_drv_stats_s {
u32 enable_replies;
};
-/**
+/*
* IOC statistics
*/
struct bfa_ioc_stats_s {
@@ -310,7 +310,7 @@ enum bfa_ioc_type_e {
BFA_IOC_TYPE_LL = 3,
};
-/**
+/*
* IOC attributes returned in queries
*/
struct bfa_ioc_attr_s {
@@ -323,11 +323,11 @@ struct bfa_ioc_attr_s {
u8 rsvd[7]; /* 64bit align */
};
-/**
+/*
* ---------------------- mfg definitions ------------
*/
-/**
+/*
* Checksum size
*/
#define BFA_MFG_CHKSUM_SIZE 16
@@ -340,7 +340,7 @@ struct bfa_ioc_attr_s {
#pragma pack(1)
-/**
+/*
* All numerical fields are in big-endian format.
*/
struct bfa_mfg_block_s {
@@ -373,11 +373,11 @@ struct bfa_mfg_block_s {
#pragma pack()
-/**
+/*
* ---------------------- pci definitions ------------
*/
-/**
+/*
* PCI device and vendor ID information
*/
enum {
@@ -392,14 +392,14 @@ enum {
((devid) == BFA_PCI_DEVICE_ID_CT || \
(devid) == BFA_PCI_DEVICE_ID_CT_FC)
-/**
+/*
* PCI sub-system device and vendor ID information
*/
enum {
BFA_PCI_FCOE_SSDEVICE_ID = 0x14,
};
-/**
+/*
* Maximum number of device address ranges mapped through different BAR(s)
*/
#define BFA_PCI_ACCESS_RANGES 1
@@ -430,7 +430,7 @@ enum {
#define BOOT_CFG_REV1 1
#define BOOT_CFG_VLAN 1
-/**
+/*
* Boot options setting. Boot options setting determines from where
* to get the boot lun information
*/
@@ -442,16 +442,16 @@ enum bfa_boot_bootopt {
};
#pragma pack(1)
-/**
+/*
* Boot lun information.
*/
struct bfa_boot_bootlun_s {
- wwn_t pwwn; /* port wwn of target */
- lun_t lun; /* 64-bit lun */
+ wwn_t pwwn; /* port wwn of target */
+ struct scsi_lun lun; /* 64-bit lun */
};
#pragma pack()
-/**
+/*
* BOOT boot configuraton
*/
struct bfa_boot_pbc_s {
diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h
index 96905d301828..191d34a58b9c 100644
--- a/drivers/scsi/bfa/bfa_defs_fcs.h
+++ b/drivers/scsi/bfa/bfa_defs_fcs.h
@@ -21,7 +21,7 @@
#include "bfa_fc.h"
#include "bfa_defs_svc.h"
-/**
+/*
* VF states
*/
enum bfa_vf_state {
@@ -35,7 +35,7 @@ enum bfa_vf_state {
BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */
};
-/**
+/*
* VF statistics
*/
struct bfa_vf_stats_s {
@@ -55,7 +55,7 @@ struct bfa_vf_stats_s {
u32 resvd; /* padding for 64 bit alignment */
};
-/**
+/*
* VF attributes returned in queries
*/
struct bfa_vf_attr_s {
@@ -67,7 +67,7 @@ struct bfa_vf_attr_s {
#define BFA_FCS_MAX_LPORTS 256
#define BFA_FCS_FABRIC_IPADDR_SZ 16
-/**
+/*
* symbolic names for base port/virtual port
*/
#define BFA_SYMNAME_MAXLEN 128 /* 128 bytes */
@@ -75,7 +75,7 @@ struct bfa_lport_symname_s {
char symname[BFA_SYMNAME_MAXLEN];
};
-/**
+/*
* Roles of FCS port:
* - FCP IM and FCP TM roles cannot be enabled together for a FCS port
* - Create multiple ports if both IM and TM functions required.
@@ -86,19 +86,19 @@ enum bfa_lport_role {
BFA_LPORT_ROLE_FCP_MAX = BFA_LPORT_ROLE_FCP_IM,
};
-/**
+/*
* FCS port configuration.
*/
struct bfa_lport_cfg_s {
wwn_t pwwn; /* port wwn */
wwn_t nwwn; /* node wwn */
struct bfa_lport_symname_s sym_name; /* vm port symbolic name */
- bfa_boolean_t preboot_vp; /* vport created from PBC */
+ bfa_boolean_t preboot_vp; /* vport created from PBC */
enum bfa_lport_role roles; /* FCS port roles */
u8 tag[16]; /* opaque tag from application */
};
-/**
+/*
* FCS port states
*/
enum bfa_lport_state {
@@ -108,7 +108,7 @@ enum bfa_lport_state {
BFA_LPORT_OFFLINE = 3, /* No login to fabric */
};
-/**
+/*
* FCS port type.
*/
enum bfa_lport_type {
@@ -116,7 +116,7 @@ enum bfa_lport_type {
BFA_LPORT_TYPE_VIRTUAL,
};
-/**
+/*
* FCS port offline reason.
*/
enum bfa_lport_offline_reason {
@@ -128,7 +128,7 @@ enum bfa_lport_offline_reason {
BFA_LPORT_OFFLINE_FAB_LOGOUT,
};
-/**
+/*
* FCS lport info.
*/
struct bfa_lport_info_s {
@@ -150,7 +150,7 @@ struct bfa_lport_info_s {
};
-/**
+/*
* FCS port statistics
*/
struct bfa_lport_stats_s {
@@ -222,7 +222,7 @@ struct bfa_lport_stats_s {
* (max retry of plogi) */
};
-/**
+/*
* BFA port attribute returned in queries
*/
struct bfa_lport_attr_s {
@@ -239,7 +239,7 @@ struct bfa_lport_attr_s {
};
-/**
+/*
* VPORT states
*/
enum bfa_vport_state {
@@ -258,7 +258,7 @@ enum bfa_vport_state {
BFA_FCS_VPORT_MAX_STATE,
};
-/**
+/*
* vport statistics
*/
struct bfa_vport_stats_s {
@@ -296,7 +296,7 @@ struct bfa_vport_stats_s {
u32 rsvd;
};
-/**
+/*
* BFA vport attribute returned in queries
*/
struct bfa_vport_attr_s {
@@ -305,7 +305,7 @@ struct bfa_vport_attr_s {
u32 rsvd;
};
-/**
+/*
* FCS remote port states
*/
enum bfa_rport_state {
@@ -321,7 +321,7 @@ enum bfa_rport_state {
BFA_RPORT_NSDISC = 9, /* re-discover rport */
};
-/**
+/*
* Rport Scsi Function : Initiator/Target.
*/
enum bfa_rport_function {
@@ -329,7 +329,7 @@ enum bfa_rport_function {
BFA_RPORT_TARGET = 0x02, /* SCSI Target */
};
-/**
+/*
* port/node symbolic names for rport
*/
#define BFA_RPORT_SYMNAME_MAXLEN 255
@@ -337,7 +337,7 @@ struct bfa_rport_symname_s {
char symname[BFA_RPORT_SYMNAME_MAXLEN];
};
-/**
+/*
* FCS remote port statistics
*/
struct bfa_rport_stats_s {
@@ -374,7 +374,7 @@ struct bfa_rport_stats_s {
struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */
};
-/**
+/*
* FCS remote port attributes returned in queries
*/
struct bfa_rport_attr_s {
@@ -411,7 +411,7 @@ struct bfa_rport_remote_link_stats_s {
#define BFA_MAX_IO_INDEX 7
#define BFA_NO_IO_INDEX 9
-/**
+/*
* FCS itnim states
*/
enum bfa_itnim_state {
@@ -425,7 +425,7 @@ enum bfa_itnim_state {
BFA_ITNIM_INITIATIOR = 7, /* initiator */
};
-/**
+/*
* FCS remote port statistics
*/
struct bfa_itnim_stats_s {
@@ -443,7 +443,7 @@ struct bfa_itnim_stats_s {
u32 rsvd; /* padding for 64 bit alignment */
};
-/**
+/*
* FCS itnim attributes returned in queries
*/
struct bfa_itnim_attr_s {
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 56226fcf9470..648c84176722 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -27,18 +27,18 @@
#define BFA_IOCFCOE_INTR_DELAY 25
#define BFA_IOCFCOE_INTR_LATENCY 5
-/**
+/*
* Interrupt coalescing configuration.
*/
#pragma pack(1)
struct bfa_iocfc_intr_attr_s {
u8 coalesce; /* enable/disable coalescing */
u8 rsvd[3];
- u16 latency; /* latency in microseconds */
- u16 delay; /* delay in microseconds */
+ __be16 latency; /* latency in microseconds */
+ __be16 delay; /* delay in microseconds */
};
-/**
+/*
* IOC firmware configuraton
*/
struct bfa_iocfc_fwcfg_s {
@@ -71,7 +71,7 @@ struct bfa_iocfc_drvcfg_s {
u32 rsvd;
};
-/**
+/*
* IOC configuration
*/
struct bfa_iocfc_cfg_s {
@@ -79,7 +79,7 @@ struct bfa_iocfc_cfg_s {
struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */
};
-/**
+/*
* IOC firmware IO stats
*/
struct bfa_fw_io_stats_s {
@@ -152,7 +152,7 @@ struct bfa_fw_io_stats_s {
*/
};
-/**
+/*
* IOC port firmware stats
*/
@@ -262,7 +262,7 @@ struct bfa_fw_fcoe_stats_s {
u32 mac_invalids; /* Invalid mac assigned */
};
-/**
+/*
* IOC firmware FCoE port stats
*/
struct bfa_fw_fcoe_port_stats_s {
@@ -270,7 +270,7 @@ struct bfa_fw_fcoe_port_stats_s {
struct bfa_fw_fip_stats_s fip_stats;
};
-/**
+/*
* IOC firmware FC uport stats
*/
struct bfa_fw_fc_uport_stats_s {
@@ -278,7 +278,7 @@ struct bfa_fw_fc_uport_stats_s {
struct bfa_fw_port_lksm_stats_s lksm_stats;
};
-/**
+/*
* IOC firmware FC port stats
*/
union bfa_fw_fc_port_stats_s {
@@ -286,7 +286,7 @@ union bfa_fw_fc_port_stats_s {
struct bfa_fw_fcoe_port_stats_s fcoe_stats;
};
-/**
+/*
* IOC firmware port stats
*/
struct bfa_fw_port_stats_s {
@@ -295,7 +295,7 @@ struct bfa_fw_port_stats_s {
union bfa_fw_fc_port_stats_s fc_port;
};
-/**
+/*
* fcxchg module statistics
*/
struct bfa_fw_fcxchg_stats_s {
@@ -308,7 +308,7 @@ struct bfa_fw_lpsm_stats_s {
u32 cls_tx;
};
-/**
+/*
* Trunk statistics
*/
struct bfa_fw_trunk_stats_s {
@@ -334,7 +334,7 @@ struct bfa_fw_advsm_stats_s {
u32 elp_dropped; /* ELP dropped */
};
-/**
+/*
* IOCFC firmware stats
*/
struct bfa_fw_iocfc_stats_s {
@@ -345,7 +345,7 @@ struct bfa_fw_iocfc_stats_s {
u32 set_intr_reqs; /* set interrupt reqs */
};
-/**
+/*
* IOC attributes returned in queries
*/
struct bfa_iocfc_attr_s {
@@ -353,7 +353,7 @@ struct bfa_iocfc_attr_s {
struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */
};
-/**
+/*
* Eth_sndrcv mod stats
*/
struct bfa_fw_eth_sndrcv_stats_s {
@@ -361,7 +361,7 @@ struct bfa_fw_eth_sndrcv_stats_s {
u32 rsvd; /* 64bit align */
};
-/**
+/*
* CT MAC mod stats
*/
struct bfa_fw_mac_mod_stats_s {
@@ -379,7 +379,7 @@ struct bfa_fw_mac_mod_stats_s {
u32 rsvd; /* 64bit align */
};
-/**
+/*
* CT MOD stats
*/
struct bfa_fw_ct_mod_stats_s {
@@ -391,7 +391,7 @@ struct bfa_fw_ct_mod_stats_s {
u32 rsvd; /* 64bit align */
};
-/**
+/*
* IOC firmware stats
*/
struct bfa_fw_stats_s {
@@ -412,7 +412,7 @@ struct bfa_fw_stats_s {
#define BFA_IOCFC_PATHTOV_MAX 60
#define BFA_IOCFC_QDEPTH_MAX 2000
-/**
+/*
* QoS states
*/
enum bfa_qos_state {
@@ -420,7 +420,7 @@ enum bfa_qos_state {
BFA_QOS_OFFLINE = 2, /* QoS is offline */
};
-/**
+/*
* QoS Priority levels.
*/
enum bfa_qos_priority {
@@ -430,7 +430,7 @@ enum bfa_qos_priority {
BFA_QOS_LOW = 3, /* QoS Priority Level Low */
};
-/**
+/*
* QoS bandwidth allocation for each priority level
*/
enum bfa_qos_bw_alloc {
@@ -439,7 +439,7 @@ enum bfa_qos_bw_alloc {
BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */
};
#pragma pack(1)
-/**
+/*
* QoS attribute returned in QoS Query
*/
struct bfa_qos_attr_s {
@@ -448,7 +448,7 @@ struct bfa_qos_attr_s {
u32 total_bb_cr; /* Total BB Credits */
};
-/**
+/*
* These fields should be displayed only from the CLI.
* There will be a separate BFAL API (get_qos_vc_attr ?)
* to retrieve this.
@@ -471,7 +471,7 @@ struct bfa_qos_vc_attr_s {
* total_vc_count */
};
-/**
+/*
* QoS statistics
*/
struct bfa_qos_stats_s {
@@ -489,7 +489,7 @@ struct bfa_qos_stats_s {
u32 rsvd; /* padding for 64 bit alignment */
};
-/**
+/*
* FCoE statistics
*/
struct bfa_fcoe_stats_s {
@@ -540,7 +540,7 @@ struct bfa_fcoe_stats_s {
u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */
};
-/**
+/*
* QoS or FCoE stats (fcport stats excluding physical FC port stats)
*/
union bfa_fcport_stats_u {
@@ -639,7 +639,7 @@ enum bfa_port_states {
BFA_PORT_ST_MAX_STATE,
};
-/**
+/*
* Port operational type (in sync with SNIA port type).
*/
enum bfa_port_type {
@@ -651,7 +651,7 @@ enum bfa_port_type {
BFA_PORT_TYPE_VPORT = 22, /* NPIV - virtual port */
};
-/**
+/*
* Port topology setting. A port's topology and fabric login status
* determine its operational type.
*/
@@ -662,7 +662,7 @@ enum bfa_port_topology {
BFA_PORT_TOPOLOGY_AUTO = 3, /* auto topology selection */
};
-/**
+/*
* Physical port loopback types.
*/
enum bfa_port_opmode {
@@ -679,7 +679,7 @@ enum bfa_port_opmode {
(_mode == BFA_PORT_OPMODE_LB_SLW) || \
(_mode == BFA_PORT_OPMODE_LB_EXT))
-/**
+/*
* Port link state
*/
enum bfa_port_linkstate {
@@ -687,7 +687,7 @@ enum bfa_port_linkstate {
BFA_PORT_LINKDOWN = 2, /* Physical port/Trunk link down */
};
-/**
+/*
* Port link state reason code
*/
enum bfa_port_linkstate_rsn {
@@ -733,7 +733,7 @@ enum bfa_port_linkstate_rsn {
CEE_ISCSI_PRI_OVERLAP_FCOE_PRI = 43
};
#pragma pack(1)
-/**
+/*
* Physical port configuration
*/
struct bfa_port_cfg_s {
@@ -743,7 +743,7 @@ struct bfa_port_cfg_s {
u8 qos_enabled; /* qos enabled or not */
u8 cfg_hardalpa; /* is hard alpa configured */
u8 hardalpa; /* configured hard alpa */
- u16 maxfrsize; /* maximum frame size */
+ __be16 maxfrsize; /* maximum frame size */
u8 rx_bbcredit; /* receive buffer credits */
u8 tx_bbcredit; /* transmit buffer credits */
u8 ratelimit; /* ratelimit enabled or not */
@@ -753,7 +753,7 @@ struct bfa_port_cfg_s {
};
#pragma pack()
-/**
+/*
* Port attribute values.
*/
struct bfa_port_attr_s {
@@ -800,7 +800,7 @@ struct bfa_port_attr_s {
u8 rsvd1[6];
};
-/**
+/*
* Port FCP mappings.
*/
struct bfa_port_fcpmap_s {
@@ -815,7 +815,7 @@ struct bfa_port_fcpmap_s {
char luid[256];
};
-/**
+/*
* Port RNID info.
*/
struct bfa_port_rnid_s {
@@ -843,12 +843,12 @@ struct bfa_fcport_fcf_s {
u8 fka_disabled; /* FKA is disabled */
u8 maxsz_verified; /* FCoE max size verified */
u8 fc_map[3]; /* FC map */
- u16 vlan; /* FCoE vlan tag/priority */
+ __be16 vlan; /* FCoE vlan tag/priority */
u32 fka_adv_per; /* FIP ka advert. period */
mac_t mac; /* FCF mac */
};
-/**
+/*
* Trunk states for BCU/BFAL
*/
enum bfa_trunk_state {
@@ -857,7 +857,7 @@ enum bfa_trunk_state {
BFA_TRUNK_OFFLINE = 2, /* Trunk is offline */
};
-/**
+/*
* VC attributes for trunked link
*/
struct bfa_trunk_vc_attr_s {
@@ -867,7 +867,7 @@ struct bfa_trunk_vc_attr_s {
u16 vc_credits[8];
};
-/**
+/*
* Link state information
*/
struct bfa_port_link_s {
@@ -959,7 +959,7 @@ struct bfa_rport_hal_stats_s {
u32 rsvd;
};
#pragma pack(1)
-/**
+/*
* Rport's QoS attributes
*/
struct bfa_rport_qos_attr_s {
@@ -987,7 +987,7 @@ struct bfa_itnim_ioprofile_s {
struct bfa_itnim_latency_s io_latency;
};
-/**
+/*
* FC physical port statistics.
*/
struct bfa_port_fc_stats_s {
@@ -1022,7 +1022,7 @@ struct bfa_port_fc_stats_s {
u64 err_enc; /* Encoding err frame_8b10b */
};
-/**
+/*
* Eth Physical Port statistics.
*/
struct bfa_port_eth_stats_s {
@@ -1070,7 +1070,7 @@ struct bfa_port_eth_stats_s {
u64 tx_iscsi_zero_pause; /* Tx iSCSI zero pause */
};
-/**
+/*
* Port statistics.
*/
union bfa_port_stats_u {
diff --git a/drivers/scsi/bfa/bfa_drv.c b/drivers/scsi/bfa/bfa_drv.c
deleted file mode 100644
index 14127646dc54..000000000000
--- a/drivers/scsi/bfa/bfa_drv.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include "bfa_modules.h"
-
-/**
- * BFA module list terminated by NULL
- */
-struct bfa_module_s *hal_mods[] = {
- &hal_mod_sgpg,
- &hal_mod_fcport,
- &hal_mod_fcxp,
- &hal_mod_lps,
- &hal_mod_uf,
- &hal_mod_rport,
- &hal_mod_fcpim,
- NULL
-};
-
-/**
- * Message handlers for various modules.
- */
-bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
- bfa_isr_unhandled, /* NONE */
- bfa_isr_unhandled, /* BFI_MC_IOC */
- bfa_isr_unhandled, /* BFI_MC_DIAG */
- bfa_isr_unhandled, /* BFI_MC_FLASH */
- bfa_isr_unhandled, /* BFI_MC_CEE */
- bfa_fcport_isr, /* BFI_MC_FCPORT */
- bfa_isr_unhandled, /* BFI_MC_IOCFC */
- bfa_isr_unhandled, /* BFI_MC_LL */
- bfa_uf_isr, /* BFI_MC_UF */
- bfa_fcxp_isr, /* BFI_MC_FCXP */
- bfa_lps_isr, /* BFI_MC_LPS */
- bfa_rport_isr, /* BFI_MC_RPORT */
- bfa_itnim_isr, /* BFI_MC_ITNIM */
- bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
- bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
- bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
- bfa_ioim_isr, /* BFI_MC_IOIM */
- bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
- bfa_tskim_isr, /* BFI_MC_TSKIM */
- bfa_isr_unhandled, /* BFI_MC_SBOOT */
- bfa_isr_unhandled, /* BFI_MC_IPFC */
- bfa_isr_unhandled, /* BFI_MC_PORT */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
- bfa_isr_unhandled, /* --------- */
-};
-
-
-/**
- * Message handlers for mailbox command classes
- */
-bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
- NULL,
- NULL, /* BFI_MC_IOC */
- NULL, /* BFI_MC_DIAG */
- NULL, /* BFI_MC_FLASH */
- NULL, /* BFI_MC_CEE */
- NULL, /* BFI_MC_PORT */
- bfa_iocfc_isr, /* BFI_MC_IOCFC */
- NULL,
-};
-
-
-
-void
-bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
-{
- struct bfa_port_s *port = &bfa->modules.port;
- u32 dm_len;
- u8 *dm_kva;
- u64 dm_pa;
-
- dm_len = bfa_port_meminfo();
- dm_kva = bfa_meminfo_dma_virt(mi);
- dm_pa = bfa_meminfo_dma_phys(mi);
-
- memset(port, 0, sizeof(struct bfa_port_s));
- bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod);
- bfa_port_mem_claim(port, dm_kva, dm_pa);
-
- bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
- bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
-}
diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h
index 6eff705564eb..8e764fae8dc9 100644
--- a/drivers/scsi/bfa/bfa_fc.h
+++ b/drivers/scsi/bfa/bfa_fc.h
@@ -18,14 +18,12 @@
#ifndef __BFA_FC_H__
#define __BFA_FC_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
typedef u64 wwn_t;
-typedef u64 lun_t;
#define WWN_NULL (0)
#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */
-#define FC_ALPA_MAX 128
#pragma pack(1)
@@ -40,7 +38,6 @@ struct mac_s { u8 mac[MAC_ADDRLEN]; };
struct scsi_cdb_s {
u8 scsi_cdb[SCSI_MAX_CDBLEN];
};
-#define scsi_cdb_t struct scsi_cdb_s
/* ------------------------------------------------------------
* SCSI status byte values
@@ -63,7 +60,7 @@ struct scsi_cdb_s {
* Fibre Channel Header Structure (FCHS) definition
*/
struct fchs_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 routing:4; /* routing bits */
u32 cat_info:4; /* category info */
#else
@@ -75,34 +72,19 @@ struct fchs_s {
u32 cs_ctl:8; /* class specific control */
u32 s_id:24; /* source identifier */
- u32 type:8; /* data structure type */
+ u32 type:8; /* data structure type */
u32 f_ctl:24; /* initial frame control */
- u8 seq_id; /* sequence identifier */
- u8 df_ctl; /* data field control */
+ u8 seq_id; /* sequence identifier */
+ u8 df_ctl; /* data field control */
u16 seq_cnt; /* sequence count */
- u16 ox_id; /* originator exchange ID */
- u16 rx_id; /* responder exchange ID */
+ __be16 ox_id; /* originator exchange ID */
+ u16 rx_id; /* responder exchange ID */
u32 ro; /* relative offset */
};
-#define FC_SOF_LEN 4
-#define FC_EOF_LEN 4
-#define FC_CRC_LEN 4
-
-/*
- * Fibre Channel BB_E Header Structure
- */
-struct fcbbehs_s {
- u16 ver_rsvd;
- u32 rsvd[2];
- u32 rsvd__sof;
-};
-
-#define FC_SEQ_ID_MAX 256
-
/*
* routing bit definitions
*/
@@ -149,22 +131,6 @@ enum {
};
/*
- * information category for Link Control
- */
-enum {
- FC_CAT_ACK_1 = 0x00,
- FC_CAT_ACK_0_N = 0x01,
- FC_CAT_P_RJT = 0x02,
- FC_CAT_F_RJT = 0x03,
- FC_CAT_P_BSY = 0x04,
- FC_CAT_F_BSY_DATA = 0x05,
- FC_CAT_F_BSY_LINK_CTL = 0x06,
- FC_CAT_F_LCR = 0x07,
- FC_CAT_NTY = 0x08,
- FC_CAT_END = 0x09,
-};
-
-/*
* Type Field Definitions. FC-PH Section 18.5 pg. 165
*/
enum {
@@ -182,10 +148,6 @@ enum {
FC_TYPE_MAX = 256, /* 256 FC-4 types */
};
-struct fc_fc4types_s {
- u8 bits[FC_TYPE_MAX / 8];
-};
-
/*
* Frame Control Definitions. FC-PH Table-45. pg. 168
*/
@@ -288,7 +250,6 @@ enum {
FC_ELS_AUTH = 0x90, /* Authentication. Ref FC-SP */
FC_ELS_RFCN = 0x97, /* Request Fabric Change Notification. Ref
*FC-SP */
-
};
/*
@@ -314,12 +275,12 @@ enum {
* FC-PH-x. Figure-76. pg. 308.
*/
struct fc_plogi_csp_s {
- u8 verhi; /* FC-PH high version */
- u8 verlo; /* FC-PH low version */
- u16 bbcred; /* BB_Credit */
+ u8 verhi; /* FC-PH high version */
+ u8 verlo; /* FC-PH low version */
+ __be16 bbcred; /* BB_Credit */
-#ifdef __BIGENDIAN
- u8 ciro:1, /* continuously increasing RO */
+#ifdef __BIG_ENDIAN
+ u8 ciro:1, /* continuously increasing RO */
rro:1, /* random relative offset */
npiv_supp:1, /* NPIV supported */
port_type:1, /* N_Port/F_port */
@@ -328,7 +289,7 @@ struct fc_plogi_csp_s {
vvl_info:1, /* VVL Info included */
reserved1:1;
- u8 hg_supp:1,
+ u8 hg_supp:1,
query_dbc:1,
security:1,
sync_cap:1,
@@ -337,7 +298,7 @@ struct fc_plogi_csp_s {
cisc:1, /* continuously increasing seq count */
payload:1;
#else
- u8 reserved2:2,
+ u8 reserved2:2,
resolution:1, /* ms/ns ED_TOV resolution */
altbbcred:1, /* alternate BB_Credit */
port_type:1, /* N_Port/F_port */
@@ -345,7 +306,7 @@ struct fc_plogi_csp_s {
rro:1, /* random relative offset */
ciro:1; /* continuously increasing RO */
- u8 payload:1,
+ u8 payload:1,
cisc:1, /* continuously increasing seq count */
dh_dup_supp:1,
r_t_tov:1,
@@ -354,13 +315,10 @@ struct fc_plogi_csp_s {
query_dbc:1,
hg_supp:1;
#endif
-
- u16 rxsz; /* recieve data_field size */
-
- u16 conseq;
- u16 ro_bitmap;
-
- u32 e_d_tov;
+ __be16 rxsz; /* recieve data_field size */
+ __be16 conseq;
+ __be16 ro_bitmap;
+ __be32 e_d_tov;
};
/*
@@ -368,12 +326,11 @@ struct fc_plogi_csp_s {
* FC-PH-x. Figure 78. pg. 318.
*/
struct fc_plogi_clp_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 class_valid:1;
u32 intermix:1; /* class intermix supported if set =1.
- * valid only for class1. Reserved for
- * class2 & class3
- */
+ * valid only for class1. Reserved for
+ * class2 & class3 */
u32 reserved1:2;
u32 sequential:1;
u32 reserved2:3;
@@ -382,12 +339,10 @@ struct fc_plogi_clp_s {
u32 sequential:1;
u32 reserved1:2;
u32 intermix:1; /* class intermix supported if set =1.
- * valid only for class1. Reserved for
- * class2 & class3
- */
+ * valid only for class1. Reserved for
+ * class2 & class3 */
u32 class_valid:1;
#endif
-
u32 reserved3:24;
u32 reserved4:16;
@@ -395,7 +350,7 @@ struct fc_plogi_clp_s {
u32 reserved5:8;
u32 conseq:8;
- u32 e2e_credit:16; /* end to end credit */
+ u32 e2e_credit:16; /* end to end credit */
u32 reserved7:8;
u32 ospx:8;
@@ -409,24 +364,24 @@ struct fc_plogi_clp_s {
* PLOGI els command and reply payload
*/
struct fc_logi_s {
- struct fc_els_cmd_s els_cmd; /* ELS command code */
- struct fc_plogi_csp_s csp; /* common service params */
- wwn_t port_name;
- wwn_t node_name;
- struct fc_plogi_clp_s class1; /* class 1 service parameters */
- struct fc_plogi_clp_s class2; /* class 2 service parameters */
- struct fc_plogi_clp_s class3; /* class 3 service parameters */
- struct fc_plogi_clp_s class4; /* class 4 service parameters */
- u8 vvl[16]; /* vendor version level */
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_plogi_csp_s csp; /* common service params */
+ wwn_t port_name;
+ wwn_t node_name;
+ struct fc_plogi_clp_s class1; /* class 1 service parameters */
+ struct fc_plogi_clp_s class2; /* class 2 service parameters */
+ struct fc_plogi_clp_s class3; /* class 3 service parameters */
+ struct fc_plogi_clp_s class4; /* class 4 service parameters */
+ u8 vvl[16]; /* vendor version level */
};
/*
* LOGO els command payload
*/
struct fc_logo_s {
- struct fc_els_cmd_s els_cmd; /* ELS command code */
- u32 res1:8;
- u32 nport_id:24; /* N_Port identifier of source */
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
wwn_t orig_port_name; /* Port name of the LOGO originator */
};
@@ -435,12 +390,12 @@ struct fc_logo_s {
*/
struct fc_adisc_s {
struct fc_els_cmd_s els_cmd; /* ELS command code */
- u32 res1:8;
- u32 orig_HA:24; /* originator hard address */
- wwn_t orig_port_name; /* originator port name */
- wwn_t orig_node_name; /* originator node name */
- u32 res2:8;
- u32 nport_id:24; /* originator NPortID */
+ u32 res1:8;
+ u32 orig_HA:24; /* originator hard address */
+ wwn_t orig_port_name; /* originator port name */
+ wwn_t orig_node_name; /* originator node name */
+ u32 res2:8;
+ u32 nport_id:24; /* originator NPortID */
};
/*
@@ -466,7 +421,7 @@ struct fc_exch_status_blk_s {
struct fc_res_s {
struct fc_els_cmd_s els_cmd; /* ELS command code */
u32 res1:8;
- u32 nport_id:24; /* N_Port identifier of source */
+ u32 nport_id:24; /* N_Port identifier of source */
u32 oxid:16;
u32 rxid:16;
u8 assoc_hdr[32];
@@ -512,8 +467,8 @@ struct fc_rec_acc_s {
u32 orig_id:24; /* N_Port id of exchange originator */
u32 res2:8;
u32 resp_id:24; /* N_Port id of exchange responder */
- u32 count; /* data transfer count */
- u32 e_stat; /* exchange status */
+ u32 count; /* data transfer count */
+ u32 e_stat; /* exchange status */
};
/*
@@ -533,7 +488,7 @@ struct fc_rsi_s {
*/
struct fc_prli_params_s {
u32 reserved:16;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 reserved1:5;
u32 rec_support:1;
u32 task_retry_id:1;
@@ -575,7 +530,7 @@ enum {
struct fc_prli_params_page_s {
u32 type:8;
u32 codext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 origprocasv:1;
u32 rsppav:1;
u32 imagepair:1;
@@ -611,18 +566,14 @@ struct fc_prli_s {
struct fc_prlo_params_page_s {
u32 type:8;
u32 type_ext:8;
-#ifdef __BIGENDIAN
- u32 opa_valid:1; /* originator process associator
- * valid
- */
+#ifdef __BIG_ENDIAN
+ u32 opa_valid:1; /* originator process associator valid */
u32 rpa_valid:1; /* responder process associator valid */
u32 res1:14;
#else
u32 res1:14;
u32 rpa_valid:1; /* responder process associator valid */
- u32 opa_valid:1; /* originator process associator
- * valid
- */
+ u32 opa_valid:1; /* originator process associator valid */
#endif
u32 orig_process_assc;
u32 resp_process_assc;
@@ -647,18 +598,14 @@ struct fc_prlo_acc_params_page_s {
u32 type:8;
u32 type_ext:8;
-#ifdef __BIGENDIAN
- u32 opa_valid:1; /* originator process associator
- * valid
- */
+#ifdef __BIG_ENDIAN
+ u32 opa_valid:1; /* originator process associator valid */
u32 rpa_valid:1; /* responder process associator valid */
u32 res1:14;
#else
u32 res1:14;
u32 rpa_valid:1; /* responder process associator valid */
- u32 opa_valid:1; /* originator process associator
- * valid
- */
+ u32 opa_valid:1; /* originator process associator valid */
#endif
u32 orig_process_assc;
u32 resp_process_assc;
@@ -715,9 +662,9 @@ enum {
* LS_RJT els reply payload
*/
struct fc_ls_rjt_s {
- struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
u32 res1:8;
- u32 reason_code:8; /* Reason code for reject */
+ u32 reason_code:8; /* Reason code for reject */
u32 reason_code_expl:8; /* Reason code explanation */
u32 vendor_unique:8; /* Vendor specific */
};
@@ -779,12 +726,12 @@ struct fc_rrq_s {
*/
struct fc_ba_acc_s {
u32 seq_id_valid:8; /* set to 0x00 for Abort Exchange */
- u32 seq_id:8; /* invalid for Abort Exchange */
+ u32 seq_id:8; /* invalid for Abort Exchange */
u32 res2:16;
- u32 ox_id:16; /* OX_ID from ABTS frame */
- u32 rx_id:16; /* RX_ID from ABTS frame */
+ u32 ox_id:16; /* OX_ID from ABTS frame */
+ u32 rx_id:16; /* RX_ID from ABTS frame */
u32 low_seq_cnt:16; /* set to 0x0000 for Abort Exchange */
- u32 high_seq_cnt:16;/* set to 0xFFFF for Abort Exchange */
+ u32 high_seq_cnt:16; /* set to 0xFFFF for Abort Exchange */
};
/*
@@ -794,17 +741,17 @@ struct fc_ba_rjt_s {
u32 res1:8; /* Reserved */
u32 reason_code:8; /* reason code for reject */
u32 reason_expl:8; /* reason code explanation */
- u32 vendor_unique:8;/* vendor unique reason code,set to 0 */
+ u32 vendor_unique:8; /* vendor unique reason code,set to 0 */
};
/*
* TPRLO logout parameter page
*/
struct fc_tprlo_params_page_s {
-u32 type:8;
-u32 type_ext:8;
+ u32 type:8;
+ u32 type_ext:8;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 opa_valid:1;
u32 rpa_valid:1;
u32 tpo_nport_valid:1;
@@ -864,16 +811,16 @@ enum fc_rscn_format {
};
struct fc_rscn_event_s {
- u32 format:2;
- u32 qualifier:4;
- u32 resvd:2;
- u32 portid:24;
+ u32 format:2;
+ u32 qualifier:4;
+ u32 resvd:2;
+ u32 portid:24;
};
struct fc_rscn_pl_s {
- u8 command;
- u8 pagelen;
- u16 payldlen;
+ u8 command;
+ u8 pagelen;
+ __be16 payldlen;
struct fc_rscn_event_s event[1];
};
@@ -887,7 +834,6 @@ struct fc_echo_s {
/*
* RNID els command
*/
-
#define RNID_NODEID_DATA_FORMAT_COMMON 0x00
#define RNID_NODEID_DATA_FORMAT_FCP3 0x08
#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF
@@ -920,15 +866,15 @@ struct fc_rnid_cmd_s {
*/
struct fc_rnid_common_id_data_s {
- wwn_t port_name;
+ wwn_t port_name;
wwn_t node_name;
};
struct fc_rnid_general_topology_data_s {
u32 vendor_unique[4];
- u32 asso_type;
+ __be32 asso_type;
u32 phy_port_num;
- u32 num_attached_nodes;
+ __be32 num_attached_nodes;
u32 node_mgmt:8;
u32 ip_version:8;
u32 udp_tcp_port_num:16;
@@ -980,59 +926,17 @@ enum fc_rpsc_op_speed {
RPSC_OP_SPEED_8G = 0x0800,
RPSC_OP_SPEED_16G = 0x0400,
- RPSC_OP_SPEED_NOT_EST = 0x0001, /*! speed not established */
+ RPSC_OP_SPEED_NOT_EST = 0x0001, /* speed not established */
};
struct fc_rpsc_speed_info_s {
- u16 port_speed_cap; /*! see enum fc_rpsc_speed_cap */
- u16 port_op_speed; /*! see enum fc_rpsc_op_speed */
-};
-
-enum link_e2e_beacon_subcmd {
- LINK_E2E_BEACON_ON = 1,
- LINK_E2E_BEACON_OFF = 2
-};
-
-enum beacon_type {
- BEACON_TYPE_NORMAL = 1, /*! Normal Beaconing. Green */
- BEACON_TYPE_WARN = 2, /*! Warning Beaconing. Yellow/Amber */
- BEACON_TYPE_CRITICAL = 3 /*! Critical Beaconing. Red */
-};
-
-struct link_e2e_beacon_param_s {
- u8 beacon_type; /* Beacon Type. See enum beacon_type */
- u8 beacon_frequency;
- /* Beacon frequency. Number of blinks
- * per 10 seconds
- */
- u16 beacon_duration;/* Beacon duration (in Seconds). The
- * command operation should be
- * terminated at the end of this
- * timeout value.
- *
- * Ignored if diag_sub_cmd is
- * LINK_E2E_BEACON_OFF.
- *
- * If 0, beaconing will continue till a
- * BEACON OFF request is received
- */
+ __be16 port_speed_cap; /* see enum fc_rpsc_speed_cap */
+ __be16 port_op_speed; /* see enum fc_rpsc_op_speed */
};
/*
- * Link E2E beacon request/good response format.
- * For LS_RJTs use struct fc_ls_rjt_s
- */
-struct link_e2e_beacon_req_s {
- u32 ls_code; /*! FC_ELS_E2E_LBEACON in requests *
- *or FC_ELS_ACC in good replies */
- u32 ls_sub_cmd; /*! See enum link_e2e_beacon_subcmd */
- struct link_e2e_beacon_param_s beacon_parm;
-};
-
-/**
* If RPSC request is sent to the Domain Controller, the request is for
- * all the ports within that domain (TODO - I don't think FOS implements
- * this...).
+ * all the ports within that domain.
*/
struct fc_rpsc_cmd_s {
struct fc_els_cmd_s els_cmd;
@@ -1049,16 +953,16 @@ struct fc_rpsc_acc_s {
struct fc_rpsc_speed_info_s speed_info[1];
};
-/**
+/*
* If RPSC2 request is sent to the Domain Controller,
*/
#define FC_BRCD_TOKEN 0x42524344
struct fc_rpsc2_cmd_s {
struct fc_els_cmd_s els_cmd;
- u32 token;
+ __be32 token;
u16 resvd;
- u16 num_pids; /* Number of pids in the request */
+ __be16 num_pids; /* Number of pids in the request */
struct {
u32 rsvd1:8;
u32 pid:24; /* port identifier */
@@ -1072,16 +976,17 @@ enum fc_rpsc2_port_type {
RPSC2_PORT_TYPE_NPIV_PORT = 0x5f,
RPSC2_PORT_TYPE_NPORT_TRUNK = 0x6f,
};
+
/*
* RPSC2 portInfo entry structure
*/
struct fc_rpsc2_port_info_s {
- u32 pid; /* PID */
- u16 resvd1;
- u16 index; /* port number / index */
- u8 resvd2;
- u8 type; /* port type N/NL/... */
- u16 speed; /* port Operating Speed */
+ __be32 pid; /* PID */
+ u16 resvd1;
+ __be16 index; /* port number / index */
+ u8 resvd2;
+ u8 type; /* port type N/NL/... */
+ __be16 speed; /* port Operating Speed */
};
/*
@@ -1090,11 +995,11 @@ struct fc_rpsc2_port_info_s {
struct fc_rpsc2_acc_s {
u8 els_cmd;
u8 resvd;
- u16 num_pids; /* Number of pids in the request */
- struct fc_rpsc2_port_info_s port_info[1]; /* port information */
+ __be16 num_pids; /* Number of pids in the request */
+ struct fc_rpsc2_port_info_s port_info[1]; /* port information */
};
-/**
+/*
* bit fields so that multiple classes can be specified
*/
enum fc_cos {
@@ -1110,18 +1015,14 @@ struct fc_symname_s {
u8 symname[FC_SYMNAME_MAX];
};
-struct fc_alpabm_s {
- u8 alpa_bm[FC_ALPA_MAX / 8];
-};
-
/*
* protocol default timeout values
*/
-#define FC_ED_TOV 2
-#define FC_REC_TOV (FC_ED_TOV + 1)
-#define FC_RA_TOV 10
-#define FC_ELS_TOV (2 * FC_RA_TOV)
-#define FC_FCCT_TOV (3 * FC_RA_TOV)
+#define FC_ED_TOV 2
+#define FC_REC_TOV (FC_ED_TOV + 1)
+#define FC_RA_TOV 10
+#define FC_ELS_TOV (2 * FC_RA_TOV)
+#define FC_FCCT_TOV (3 * FC_RA_TOV)
/*
* virtual fabric related defines
@@ -1131,7 +1032,7 @@ struct fc_alpabm_s {
#define FC_VF_ID_MAX 0xEFF
#define FC_VF_ID_CTL 0xFEF /* control VF_ID */
-/**
+/*
* Virtual Fabric Tagging header format
* @caution This is defined only in BIG ENDIAN format.
*/
@@ -1157,50 +1058,34 @@ enum {
};
/*
- * SRR FC-4 LS payload
- */
-struct fc_srr_s {
- u32 ls_cmd;
- u32 ox_id:16; /* ox-id */
- u32 rx_id:16; /* rx-id */
- u32 ro; /* relative offset */
- u32 r_ctl:8; /* R_CTL for I.U. */
- u32 res:24;
-};
-
-
-/*
* FCP_CMND definitions
*/
#define FCP_CMND_CDB_LEN 16
#define FCP_CMND_LUN_LEN 8
struct fcp_cmnd_s {
- lun_t lun; /* 64-bit LU number */
- u8 crn; /* command reference number */
-#ifdef __BIGENDIAN
- u8 resvd:1,
+ struct scsi_lun lun; /* 64-bit LU number */
+ u8 crn; /* command reference number */
+#ifdef __BIG_ENDIAN
+ u8 resvd:1,
priority:4, /* FCP-3: SAM-3 priority */
taskattr:3; /* scsi task attribute */
#else
- u8 taskattr:3, /* scsi task attribute */
+ u8 taskattr:3, /* scsi task attribute */
priority:4, /* FCP-3: SAM-3 priority */
resvd:1;
#endif
- u8 tm_flags; /* task management flags */
-#ifdef __BIGENDIAN
- u8 addl_cdb_len:6, /* additional CDB length words */
+ u8 tm_flags; /* task management flags */
+#ifdef __BIG_ENDIAN
+ u8 addl_cdb_len:6, /* additional CDB length words */
iodir:2; /* read/write FCP_DATA IUs */
#else
- u8 iodir:2, /* read/write FCP_DATA IUs */
+ u8 iodir:2, /* read/write FCP_DATA IUs */
addl_cdb_len:6; /* additional CDB length */
#endif
- scsi_cdb_t cdb;
+ struct scsi_cdb_s cdb;
- /*
- * !!! additional cdb bytes follows here!!!
- */
- u32 fcp_dl; /* bytes to be transferred */
+ __be32 fcp_dl; /* bytes to be transferred */
};
#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN)
@@ -1210,21 +1095,10 @@ struct fcp_cmnd_s {
* struct fcp_cmnd_s .iodir field values
*/
enum fcp_iodir {
- FCP_IODIR_NONE = 0,
+ FCP_IODIR_NONE = 0,
FCP_IODIR_WRITE = 1,
- FCP_IODIR_READ = 2,
- FCP_IODIR_RW = 3,
-};
-
-/*
- * Task attribute field
- */
-enum {
- FCP_TASK_ATTR_SIMPLE = 0,
- FCP_TASK_ATTR_HOQ = 1,
- FCP_TASK_ATTR_ORDERED = 2,
- FCP_TASK_ATTR_ACA = 4,
- FCP_TASK_ATTR_UNTAGGED = 5, /* obsolete in FCP-3 */
+ FCP_IODIR_READ = 2,
+ FCP_IODIR_RW = 3,
};
/*
@@ -1239,58 +1113,40 @@ enum fcp_tm_cmnd {
};
/*
- * FCP_XFER_RDY IU defines
- */
-struct fcp_xfer_rdy_s {
- u32 data_ro;
- u32 burst_len;
- u32 reserved;
-};
-
-/*
* FCP_RSP residue flags
*/
enum fcp_residue {
- FCP_NO_RESIDUE = 0, /* no residue */
- FCP_RESID_OVER = 1, /* more data left that was not sent */
- FCP_RESID_UNDER = 2, /* less data than requested */
-};
-
-enum {
- FCP_RSPINFO_GOOD = 0,
- FCP_RSPINFO_DATALEN_MISMATCH = 1,
- FCP_RSPINFO_CMND_INVALID = 2,
- FCP_RSPINFO_ROLEN_MISMATCH = 3,
- FCP_RSPINFO_TM_NOT_SUPP = 4,
- FCP_RSPINFO_TM_FAILED = 5,
+ FCP_NO_RESIDUE = 0, /* no residue */
+ FCP_RESID_OVER = 1, /* more data left that was not sent */
+ FCP_RESID_UNDER = 2, /* less data than requested */
};
struct fcp_rspinfo_s {
u32 res0:24;
- u32 rsp_code:8; /* response code (as above) */
+ u32 rsp_code:8; /* response code (as above) */
u32 res1;
};
struct fcp_resp_s {
- u32 reserved[2]; /* 2 words reserved */
+ u32 reserved[2]; /* 2 words reserved */
u16 reserved2;
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u8 reserved3:3;
u8 fcp_conf_req:1; /* FCP_CONF is requested */
u8 resid_flags:2; /* underflow/overflow */
- u8 sns_len_valid:1;/* sense len is valid */
- u8 rsp_len_valid:1;/* response len is valid */
+ u8 sns_len_valid:1; /* sense len is valid */
+ u8 rsp_len_valid:1; /* response len is valid */
#else
- u8 rsp_len_valid:1;/* response len is valid */
- u8 sns_len_valid:1;/* sense len is valid */
+ u8 rsp_len_valid:1; /* response len is valid */
+ u8 sns_len_valid:1; /* sense len is valid */
u8 resid_flags:2; /* underflow/overflow */
u8 fcp_conf_req:1; /* FCP_CONF is requested */
u8 reserved3:3;
#endif
- u8 scsi_status; /* one byte SCSI status */
- u32 residue; /* residual data bytes */
- u32 sns_len; /* length od sense info */
- u32 rsp_len; /* length of response info */
+ u8 scsi_status; /* one byte SCSI status */
+ u32 residue; /* residual data bytes */
+ u32 sns_len; /* length od sense info */
+ u32 rsp_len; /* length of response info */
};
#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \
@@ -1300,12 +1156,6 @@ struct fcp_resp_s {
#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1))
#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \
fcp_rsplen(__fcprsp))
-
-struct fcp_cmnd_fr_s {
- struct fchs_s fchs;
- struct fcp_cmnd_s fcp;
-};
-
/*
* CT
*/
@@ -1379,7 +1229,7 @@ enum {
CT_RSN_LOGICAL_BUSY = 0x05,
CT_RSN_PROTO_ERR = 0x07,
CT_RSN_UNABLE_TO_PERF = 0x09,
- CT_RSN_NOT_SUPP = 0x0B,
+ CT_RSN_NOT_SUPP = 0x0B,
CT_RSN_SERVER_NOT_AVBL = 0x0D,
CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E,
CT_RSN_VENDOR_SPECIFIC = 0xFF,
@@ -1419,10 +1269,10 @@ enum {
* defintions for the explanation code for all servers
*/
enum {
- CT_EXP_AUTH_EXCEPTION = 0xF1,
- CT_EXP_DB_FULL = 0xF2,
- CT_EXP_DB_EMPTY = 0xF3,
- CT_EXP_PROCESSING_REQ = 0xF4,
+ CT_EXP_AUTH_EXCEPTION = 0xF1,
+ CT_EXP_DB_FULL = 0xF2,
+ CT_EXP_DB_EMPTY = 0xF3,
+ CT_EXP_PROCESSING_REQ = 0xF4,
CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5,
CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6
};
@@ -1446,7 +1296,7 @@ enum {
GS_RFF_ID = 0x021F, /* Register FC4 Feature */
};
-struct fcgs_id_req_s{
+struct fcgs_id_req_s {
u32 rsvd:8;
u32 dap:24; /* port identifier */
};
@@ -1460,34 +1310,33 @@ struct fcgs_gidpn_req_s {
struct fcgs_gidpn_resp_s {
u32 rsvd:8;
- u32 dap:24; /* port identifier */
+ u32 dap:24; /* port identifier */
};
-/**
+/*
* RFT_ID
*/
struct fcgs_rftid_req_s {
u32 rsvd:8;
u32 dap:24; /* port identifier */
- u32 fc4_type[8]; /* fc4 types */
+ __be32 fc4_type[8]; /* fc4 types */
};
-/**
+/*
* RFF_ID : Register FC4 features.
*/
-
#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02
#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01
struct fcgs_rffid_req_s {
- u32 rsvd:8;
- u32 dap:24; /* port identifier */
- u32 rsvd1:16;
- u32 fc4ftr_bits:8; /* fc4 feature bits */
- u32 fc4_type:8; /* corresponding FC4 Type */
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u32 rsvd1:16;
+ u32 fc4ftr_bits:8; /* fc4 feature bits */
+ u32 fc4_type:8; /* corresponding FC4 Type */
};
-/**
+/*
* GID_FT Request
*/
struct fcgs_gidft_req_s {
@@ -1495,46 +1344,46 @@ struct fcgs_gidft_req_s {
u8 domain_id; /* domain, 0 - all fabric */
u8 area_id; /* area, 0 - whole domain */
u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */
-}; /* GID_FT Request */
+};
-/**
+/*
* GID_FT Response
*/
struct fcgs_gidft_resp_s {
- u8 last:1; /* last port identifier flag */
- u8 reserved:7;
- u32 pid:24; /* port identifier */
-}; /* GID_FT Response */
+ u8 last:1; /* last port identifier flag */
+ u8 reserved:7;
+ u32 pid:24; /* port identifier */
+};
-/**
+/*
* RSPN_ID
*/
struct fcgs_rspnid_req_s {
u32 rsvd:8;
u32 dap:24; /* port identifier */
- u8 spn_len; /* symbolic port name length */
- u8 spn[256]; /* symbolic port name */
+ u8 spn_len; /* symbolic port name length */
+ u8 spn[256]; /* symbolic port name */
};
-/**
+/*
* RPN_ID
*/
struct fcgs_rpnid_req_s {
u32 rsvd:8;
u32 port_id:24;
- wwn_t port_name;
+ wwn_t port_name;
};
-/**
+/*
* RNN_ID
*/
struct fcgs_rnnid_req_s {
u32 rsvd:8;
u32 port_id:24;
- wwn_t node_name;
+ wwn_t node_name;
};
-/**
+/*
* RCS_ID
*/
struct fcgs_rcsid_req_s {
@@ -1543,7 +1392,7 @@ struct fcgs_rcsid_req_s {
u32 cos;
};
-/**
+/*
* RPT_ID
*/
struct fcgs_rptid_req_s {
@@ -1553,7 +1402,7 @@ struct fcgs_rptid_req_s {
u32 rsvd1:24;
};
-/**
+/*
* GA_NXT Request
*/
struct fcgs_ganxt_req_s {
@@ -1561,12 +1410,12 @@ struct fcgs_ganxt_req_s {
u32 port_id:24;
};
-/**
+/*
* GA_NXT Response
*/
struct fcgs_ganxt_rsp_s {
- u32 port_type:8; /* Port Type */
- u32 port_id:24; /* Port Identifier */
+ u32 port_type:8; /* Port Type */
+ u32 port_id:24; /* Port Identifier */
wwn_t port_name; /* Port Name */
u8 spn_len; /* Length of Symbolic Port Name */
char spn[255]; /* Symbolic Port Name */
@@ -1575,19 +1424,14 @@ struct fcgs_ganxt_rsp_s {
char snn[255]; /* Symbolic Node Name */
u8 ipa[8]; /* Initial Process Associator */
u8 ip[16]; /* IP Address */
- u32 cos; /* Class of Service */
- u32 fc4types[8]; /* FC-4 TYPEs */
- wwn_t fabric_port_name;
- /* Fabric Port Name */
- u32 rsvd:8; /* Reserved */
- u32 hard_addr:24; /* Hard Address */
+ u32 cos; /* Class of Service */
+ u32 fc4types[8]; /* FC-4 TYPEs */
+ wwn_t fabric_port_name; /* Fabric Port Name */
+ u32 rsvd:8; /* Reserved */
+ u32 hard_addr:24; /* Hard Address */
};
/*
- * Fabric Config Server
- */
-
-/*
* Command codes for Fabric Configuration Server
*/
enum {
@@ -1598,159 +1442,9 @@ enum {
};
/*
- * Source or Destination Port Tags.
- */
-enum {
- GS_FTRACE_TAG_NPORT_ID = 1,
- GS_FTRACE_TAG_NPORT_NAME = 2,
-};
-
-/*
-* Port Value : Could be a Port id or wwn
- */
-union fcgs_port_val_u {
- u32 nport_id;
- wwn_t nport_wwn;
-};
-
-#define GS_FTRACE_MAX_HOP_COUNT 20
-#define GS_FTRACE_REVISION 1
-
-/*
- * Ftrace Related Structures.
- */
-
-/*
- * STR (Switch Trace) Reject Reason Codes. From FC-SW.
- */
-enum {
- GS_FTRACE_STR_CMD_COMPLETED_SUCC = 0,
- GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH,
- GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH,
- GS_FTRACE_STR_MAX_HOP_CNT_REACHED,
- GS_FTRACE_STR_SRC_PORT_NOT_FOUND,
- GS_FTRACE_STR_DST_PORT_NOT_FOUND,
- GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE,
- GS_FTRACE_STR_NO_ROUTE_BW_PORTS,
- GS_FTRACE_STR_NO_ADDL_EXPLN,
- GS_FTRACE_STR_FABRIC_BUSY,
- GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS,
- GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0,
- GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff,
-};
-
-/*
- * Ftrace Request
- */
-struct fcgs_ftrace_req_s {
- u32 revision;
- u16 src_port_tag; /* Source Port tag */
- u16 src_port_len; /* Source Port len */
- union fcgs_port_val_u src_port_val; /* Source Port value */
- u16 dst_port_tag; /* Destination Port tag */
- u16 dst_port_len; /* Destination Port len */
- union fcgs_port_val_u dst_port_val; /* Destination Port value */
- u32 token;
- u8 vendor_id[8]; /* T10 Vendor Identifier */
- u8 vendor_info[8]; /* Vendor specific Info */
- u32 max_hop_cnt; /* Max Hop Count */
-};
-
-/*
- * Path info structure
- */
-struct fcgs_ftrace_path_info_s {
- wwn_t switch_name; /* Switch WWN */
- u32 domain_id;
- wwn_t ingress_port_name; /* Ingress ports wwn */
- u32 ingress_phys_port_num; /* Ingress ports physical port
- * number
- */
- wwn_t egress_port_name; /* Ingress ports wwn */
- u32 egress_phys_port_num; /* Ingress ports physical port
- * number
- */
-};
-
-/*
- * Ftrace Acc Response
- */
-struct fcgs_ftrace_resp_s {
- u32 revision;
- u32 token;
- u8 vendor_id[8]; /* T10 Vendor Identifier */
- u8 vendor_info[8]; /* Vendor specific Info */
- u32 str_rej_reason_code; /* STR Reject Reason Code */
- u32 num_path_info_entries; /* No. of path info entries */
- /*
- * path info entry/entries.
- */
- struct fcgs_ftrace_path_info_s path_info[1];
-
-};
-
-/*
-* Fabric Config Server : FCPing
- */
-
-/*
- * FC Ping Request
- */
-struct fcgs_fcping_req_s {
- u32 revision;
- u16 port_tag;
- u16 port_len; /* Port len */
- union fcgs_port_val_u port_val; /* Port value */
- u32 token;
-};
-
-/*
- * FC Ping Response
- */
-struct fcgs_fcping_resp_s {
- u32 token;
-};
-
-/*
- * Command codes for zone server query.
- */
-enum {
- ZS_GZME = 0x0124, /* Get zone member extended */
-};
-
-/*
- * ZS GZME request
- */
-#define ZS_GZME_ZNAMELEN 32
-struct zs_gzme_req_s {
- u8 znamelen;
- u8 rsvd[3];
- u8 zname[ZS_GZME_ZNAMELEN];
-};
-
-enum zs_mbr_type {
- ZS_MBR_TYPE_PWWN = 1,
- ZS_MBR_TYPE_DOMPORT = 2,
- ZS_MBR_TYPE_PORTID = 3,
- ZS_MBR_TYPE_NWWN = 4,
-};
-
-struct zs_mbr_wwn_s {
- u8 mbr_type;
- u8 rsvd[3];
- wwn_t wwn;
-};
-
-struct zs_query_resp_s {
- u32 nmbrs; /* number of zone members */
- struct zs_mbr_wwn_s mbr[1];
-};
-
-/*
* GMAL Command ( Get ( interconnect Element) Management Address List)
* To retrieve the IP Address of a Switch.
*/
-
#define CT_GMAL_RESP_PREFIX_TELNET "telnet://"
#define CT_GMAL_RESP_PREFIX_HTTP "http://"
@@ -1764,7 +1458,7 @@ struct fcgs_req_s {
/* Accept Response to GMAL */
struct fcgs_gmal_resp_s {
- u32 ms_len; /* Num of entries */
+ __be32 ms_len; /* Num of entries */
u8 ms_ma[256];
};
@@ -1775,9 +1469,6 @@ struct fcgs_gmal_entry_s {
};
/*
- * FDMI
- */
-/*
* FDMI Command Codes
*/
#define FDMI_GRHL 0x0100
@@ -1856,8 +1547,8 @@ enum fdmi_port_attribute_type {
* FDMI attribute
*/
struct fdmi_attr_s {
- u16 type;
- u16 len;
+ __be16 type;
+ __be16 len;
u8 value[1];
};
@@ -1865,7 +1556,7 @@ struct fdmi_attr_s {
* HBA Attribute Block
*/
struct fdmi_hba_attr_s {
- u32 attr_count; /* # of attributes */
+ __be32 attr_count; /* # of attributes */
struct fdmi_attr_s hba_attr; /* n attributes */
};
@@ -1873,15 +1564,15 @@ struct fdmi_hba_attr_s {
* Registered Port List
*/
struct fdmi_port_list_s {
- u32 num_ports; /* number Of Port Entries */
- wwn_t port_entry; /* one or more */
+ __be32 num_ports; /* number Of Port Entries */
+ wwn_t port_entry; /* one or more */
};
/*
* Port Attribute Block
*/
struct fdmi_port_attr_s {
- u32 attr_count; /* # of attributes */
+ __be32 attr_count; /* # of attributes */
struct fdmi_attr_s port_attr; /* n attributes */
};
@@ -1889,7 +1580,7 @@ struct fdmi_port_attr_s {
* FDMI Register HBA Attributes
*/
struct fdmi_rhba_s {
- wwn_t hba_id; /* HBA Identifier */
+ wwn_t hba_id; /* HBA Identifier */
struct fdmi_port_list_s port_list; /* Registered Port List */
struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */
};
@@ -1898,8 +1589,8 @@ struct fdmi_rhba_s {
* FDMI Register Port
*/
struct fdmi_rprt_s {
- wwn_t hba_id; /* HBA Identifier */
- wwn_t port_name; /* Port wwn */
+ wwn_t hba_id; /* HBA Identifier */
+ wwn_t port_name; /* Port wwn */
struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
};
@@ -1907,7 +1598,7 @@ struct fdmi_rprt_s {
* FDMI Register Port Attributes
*/
struct fdmi_rpa_s {
- wwn_t port_name; /* port wwn */
+ wwn_t port_name; /* port wwn */
struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
};
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index b7d2657ca82a..b7e253451654 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -18,16 +18,16 @@
* fcbuild.c - FC link service frame building and parsing routines
*/
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_fcbuild.h"
/*
* static build functions
*/
static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
static struct fchs_s fc_els_req_tmpl;
static struct fchs_s fc_els_rsp_tmpl;
static struct fchs_s fc_bls_req_tmpl;
@@ -48,7 +48,7 @@ fcbuild_init(void)
fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST;
fc_els_req_tmpl.type = FC_TYPE_ELS;
fc_els_req_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
FCTL_SI_XFER);
fc_els_req_tmpl.rx_id = FC_RXID_ANY;
@@ -59,7 +59,7 @@ fcbuild_init(void)
fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY;
fc_els_rsp_tmpl.type = FC_TYPE_ELS;
fc_els_rsp_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
FCTL_END_SEQ | FCTL_SI_XFER);
fc_els_rsp_tmpl.rx_id = FC_RXID_ANY;
@@ -68,7 +68,7 @@ fcbuild_init(void)
*/
fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK;
fc_bls_req_tmpl.type = FC_TYPE_BLS;
- fc_bls_req_tmpl.f_ctl = bfa_os_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_req_tmpl.f_ctl = bfa_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
fc_bls_req_tmpl.rx_id = FC_RXID_ANY;
/*
@@ -78,7 +78,7 @@ fcbuild_init(void)
fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC;
fc_bls_rsp_tmpl.type = FC_TYPE_BLS;
fc_bls_rsp_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
FCTL_END_SEQ | FCTL_SI_XFER);
fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY;
@@ -94,13 +94,13 @@ fcbuild_init(void)
*/
plogi_tmpl.csp.verhi = FC_PH_VER_PH_3;
plogi_tmpl.csp.verlo = FC_PH_VER_4_3;
- plogi_tmpl.csp.bbcred = bfa_os_htons(0x0004);
+ plogi_tmpl.csp.bbcred = cpu_to_be16(0x0004);
plogi_tmpl.csp.ciro = 0x1;
plogi_tmpl.csp.cisc = 0x0;
plogi_tmpl.csp.altbbcred = 0x0;
- plogi_tmpl.csp.conseq = bfa_os_htons(0x00FF);
- plogi_tmpl.csp.ro_bitmap = bfa_os_htons(0x0002);
- plogi_tmpl.csp.e_d_tov = bfa_os_htonl(2000);
+ plogi_tmpl.csp.conseq = cpu_to_be16(0x00FF);
+ plogi_tmpl.csp.ro_bitmap = cpu_to_be16(0x0002);
+ plogi_tmpl.csp.e_d_tov = cpu_to_be32(2000);
plogi_tmpl.class3.class_valid = 1;
plogi_tmpl.class3.sequential = 1;
@@ -112,7 +112,7 @@ fcbuild_init(void)
*/
prli_tmpl.command = FC_ELS_PRLI;
prli_tmpl.pglen = 0x10;
- prli_tmpl.pagebytes = bfa_os_htons(0x0014);
+ prli_tmpl.pagebytes = cpu_to_be16(0x0014);
prli_tmpl.parampage.type = FC_TYPE_FCP;
prli_tmpl.parampage.imagepair = 1;
prli_tmpl.parampage.servparams.rxrdisab = 1;
@@ -129,7 +129,7 @@ fcbuild_init(void)
fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD;
fcp_fchs_tmpl.type = FC_TYPE_FCP;
fcp_fchs_tmpl.f_ctl =
- bfa_os_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
+ bfa_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
fcp_fchs_tmpl.seq_id = 1;
fcp_fchs_tmpl.rx_id = FC_RXID_ANY;
}
@@ -137,38 +137,38 @@ fcbuild_init(void)
static void
fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id)
{
- bfa_os_memset(fchs, 0, sizeof(struct fchs_s));
+ memset(fchs, 0, sizeof(struct fchs_s));
fchs->routing = FC_RTG_FC4_DEV_DATA;
fchs->cat_info = FC_CAT_UNSOLICIT_CTRL;
fchs->type = FC_TYPE_SERVICES;
fchs->f_ctl =
- bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
FCTL_SI_XFER);
fchs->rx_id = FC_RXID_ANY;
fchs->d_id = (d_id);
fchs->s_id = (s_id);
- fchs->ox_id = bfa_os_htons(ox_id);
+ fchs->ox_id = cpu_to_be16(ox_id);
- /**
+ /*
* @todo no need to set ox_id for request
* no need to set rx_id for response
*/
}
void
-fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
- bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
+ memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
fchs->d_id = (d_id);
fchs->s_id = (s_id);
- fchs->ox_id = bfa_os_htons(ox_id);
+ fchs->ox_id = cpu_to_be16(ox_id);
}
static void
-fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
- bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
+ memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
fchs->d_id = d_id;
fchs->s_id = s_id;
fchs->ox_id = ox_id;
@@ -196,9 +196,9 @@ fc_els_rsp_parse(struct fchs_s *fchs, int len)
}
static void
-fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
- bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
+ memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
fchs->d_id = d_id;
fchs->s_id = s_id;
fchs->ox_id = ox_id;
@@ -206,12 +206,12 @@ fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
static u16
fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id, wwn_t port_name, wwn_t node_name,
+ __be16 ox_id, wwn_t port_name, wwn_t node_name,
u16 pdu_size, u8 els_code)
{
struct fc_logi_s *plogi = (struct fc_logi_s *) (pld);
- bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
plogi->els_cmd.els_code = els_code;
if (els_code == FC_ELS_PLOGI)
@@ -219,10 +219,10 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
else
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- plogi->csp.rxsz = plogi->class3.rxsz = bfa_os_htons(pdu_size);
+ plogi->csp.rxsz = plogi->class3.rxsz = cpu_to_be16(pdu_size);
- bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
- bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
+ memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
+ memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
return sizeof(struct fc_logi_s);
}
@@ -232,15 +232,15 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size,
u8 set_npiv, u8 set_auth, u16 local_bb_credits)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
- u32 *vvl_info;
+ u32 d_id = bfa_hton3b(FC_FABRIC_PORT);
+ __be32 *vvl_info;
- bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
flogi->els_cmd.els_code = FC_ELS_FLOGI;
fc_els_req_build(fchs, d_id, s_id, ox_id);
- flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
flogi->port_name = port_name;
flogi->node_name = node_name;
@@ -253,34 +253,34 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
/* set AUTH capability */
flogi->csp.security = set_auth;
- flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+ flogi->csp.bbcred = cpu_to_be16(local_bb_credits);
/* Set brcd token in VVL */
vvl_info = (u32 *)&flogi->vvl[0];
/* set the flag to indicate the presence of VVL */
flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */
- vvl_info[0] = bfa_os_htonl(FLOGI_VVL_BRCD);
+ vvl_info[0] = cpu_to_be32(FLOGI_VVL_BRCD);
return sizeof(struct fc_logi_s);
}
u16
fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
- u16 ox_id, wwn_t port_name, wwn_t node_name,
+ __be16 ox_id, wwn_t port_name, wwn_t node_name,
u16 pdu_size, u16 local_bb_credits)
{
u32 d_id = 0;
- bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
flogi->els_cmd.els_code = FC_ELS_ACC;
- flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
flogi->port_name = port_name;
flogi->node_name = node_name;
- flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+ flogi->csp.bbcred = cpu_to_be16(local_bb_credits);
return sizeof(struct fc_logi_s);
}
@@ -289,14 +289,14 @@ u16
fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+ u32 d_id = bfa_hton3b(FC_FABRIC_PORT);
- bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
flogi->els_cmd.els_code = FC_ELS_FDISC;
fc_els_req_build(fchs, d_id, s_id, ox_id);
- flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
flogi->port_name = port_name;
flogi->node_name = node_name;
@@ -346,7 +346,7 @@ fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
if (!plogi->class3.class_valid)
return FC_PARSE_FAILURE;
- if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
+ if (be16_to_cpu(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
return FC_PARSE_FAILURE;
return FC_PARSE_OK;
@@ -363,8 +363,8 @@ fc_plogi_parse(struct fchs_s *fchs)
if (plogi->class3.class_valid != 1)
return FC_PARSE_FAILURE;
- if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ)
- || (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ)
+ if ((be16_to_cpu(plogi->class3.rxsz) < FC_MIN_PDUSZ)
+ || (be16_to_cpu(plogi->class3.rxsz) > FC_MAX_PDUSZ)
|| (plogi->class3.rxsz == 0))
return FC_PARSE_FAILURE;
@@ -378,7 +378,7 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+ memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
prli->command = FC_ELS_PRLI;
prli->parampage.servparams.initiator = 1;
@@ -392,12 +392,12 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
u16
fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id, enum bfa_lport_role role)
+ __be16 ox_id, enum bfa_lport_role role)
{
struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+ memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
prli->command = FC_ELS_ACC;
@@ -448,7 +448,7 @@ fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id,
{
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(logo, '\0', sizeof(struct fc_logo_s));
+ memset(logo, '\0', sizeof(struct fc_logo_s));
logo->els_cmd.els_code = FC_ELS_LOGO;
logo->nport_id = (s_id);
logo->orig_port_name = port_name;
@@ -456,12 +456,12 @@ fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id,
return sizeof(struct fc_logo_s);
}
-static u16
+static u16
fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name, u8 els_code)
{
- bfa_os_memset(adisc, '\0', sizeof(struct fc_adisc_s));
+ memset(adisc, '\0', sizeof(struct fc_adisc_s));
adisc->els_cmd.els_code = els_code;
@@ -480,7 +480,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
u16
fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name)
+ u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name)
{
return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
node_name, FC_ELS_ADISC);
@@ -488,7 +488,7 @@ fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
u16
fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
- u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name)
{
return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
@@ -537,7 +537,7 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
if (pdisc->class3.class_valid != 1)
return FC_PARSE_FAILURE;
- if ((bfa_os_ntohs(pdisc->class3.rxsz) <
+ if ((be16_to_cpu(pdisc->class3.rxsz) <
(FC_MIN_PDUSZ - sizeof(struct fchs_s)))
|| (pdisc->class3.rxsz == 0))
return FC_PARSE_FAILURE;
@@ -554,11 +554,11 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
u16
fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
{
- bfa_os_memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
+ memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
fchs->cat_info = FC_CAT_ABTS;
fchs->d_id = (d_id);
fchs->s_id = (s_id);
- fchs->ox_id = bfa_os_htons(ox_id);
+ fchs->ox_id = cpu_to_be16(ox_id);
return sizeof(struct fchs_s);
}
@@ -582,9 +582,9 @@ fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id,
/*
* build rrq payload
*/
- bfa_os_memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
+ memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
rrq->s_id = (s_id);
- rrq->ox_id = bfa_os_htons(rrq_oxid);
+ rrq->ox_id = cpu_to_be16(rrq_oxid);
rrq->rx_id = FC_RXID_ANY;
return sizeof(struct fc_rrq_s);
@@ -592,13 +592,13 @@ fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id,
u16
fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
- u16 ox_id)
+ __be16 ox_id)
{
struct fc_els_cmd_s *acc = pld;
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(acc, 0, sizeof(struct fc_els_cmd_s));
+ memset(acc, 0, sizeof(struct fc_els_cmd_s));
acc->els_code = FC_ELS_ACC;
return sizeof(struct fc_els_cmd_s);
@@ -606,11 +606,11 @@ fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
u16
fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
- u32 s_id, u16 ox_id, u8 reason_code,
+ u32 s_id, __be16 ox_id, u8 reason_code,
u8 reason_code_expl)
{
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
+ memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT;
ls_rjt->reason_code = reason_code;
@@ -622,11 +622,11 @@ fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
u16
fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
- u32 s_id, u16 ox_id, u16 rx_id)
+ u32 s_id, __be16 ox_id, u16 rx_id)
{
fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
+ memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
fchs->rx_id = rx_id;
@@ -638,10 +638,10 @@ fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
u16
fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, u32 d_id,
- u32 s_id, u16 ox_id)
+ u32 s_id, __be16 ox_id)
{
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
+ memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
els_cmd->els_code = FC_ELS_ACC;
return sizeof(struct fc_els_cmd_s);
@@ -656,27 +656,27 @@ fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code)
if (els_code == FC_ELS_PRLO) {
prlo = (struct fc_prlo_s *) (fc_frame + 1);
- num_pages = (bfa_os_ntohs(prlo->payload_len) - 4) / 16;
+ num_pages = (be16_to_cpu(prlo->payload_len) - 4) / 16;
} else {
tprlo = (struct fc_tprlo_s *) (fc_frame + 1);
- num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+ num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16;
}
return num_pages;
}
u16
fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages)
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages)
{
int page;
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(tprlo_acc, 0, (num_pages * 16) + 4);
+ memset(tprlo_acc, 0, (num_pages * 16) + 4);
tprlo_acc->command = FC_ELS_ACC;
tprlo_acc->page_len = 0x10;
- tprlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+ tprlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4);
for (page = 0; page < num_pages; page++) {
tprlo_acc->tprlo_acc_params[page].opa_valid = 0;
@@ -685,21 +685,21 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0;
tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0;
}
- return bfa_os_ntohs(tprlo_acc->payload_len);
+ return be16_to_cpu(tprlo_acc->payload_len);
}
u16
fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id,
- u32 s_id, u16 ox_id, int num_pages)
+ u32 s_id, __be16 ox_id, int num_pages)
{
int page;
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(prlo_acc, 0, (num_pages * 16) + 4);
+ memset(prlo_acc, 0, (num_pages * 16) + 4);
prlo_acc->command = FC_ELS_ACC;
prlo_acc->page_len = 0x10;
- prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+ prlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4);
for (page = 0; page < num_pages; page++) {
prlo_acc->prlo_acc_params[page].opa_valid = 0;
@@ -709,7 +709,7 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id,
prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
}
- return bfa_os_ntohs(prlo_acc->payload_len);
+ return be16_to_cpu(prlo_acc->payload_len);
}
u16
@@ -718,7 +718,7 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
{
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
+ memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
rnid->els_cmd.els_code = FC_ELS_RNID;
rnid->node_id_data_format = data_format;
@@ -728,11 +728,11 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
u16
fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id,
- u32 s_id, u16 ox_id, u32 data_format,
+ u32 s_id, __be16 ox_id, u32 data_format,
struct fc_rnid_common_id_data_s *common_id_data,
struct fc_rnid_general_topology_data_s *gen_topo_data)
{
- bfa_os_memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
+ memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
@@ -745,7 +745,7 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id,
if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
rnid_acc->specific_id_data_length =
sizeof(struct fc_rnid_general_topology_data_s);
- bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data);
+ rnid_acc->gen_topology_data = *gen_topo_data;
return sizeof(struct fc_rnid_acc_s);
} else {
return sizeof(struct fc_rnid_acc_s) -
@@ -760,7 +760,7 @@ fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
{
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
+ memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
rpsc->els_cmd.els_code = FC_ELS_RPSC;
return sizeof(struct fc_rpsc_cmd_s);
@@ -770,16 +770,16 @@ u16
fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id,
u32 s_id, u32 *pid_list, u16 npids)
{
- u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id));
+ u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_hton3b(d_id));
int i = 0;
- fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0);
+ fc_els_req_build(fchs, bfa_hton3b(dctlr_id), s_id, 0);
- bfa_os_memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
+ memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
rpsc2->els_cmd.els_code = FC_ELS_RPSC;
- rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN);
- rpsc2->num_pids = bfa_os_htons(npids);
+ rpsc2->token = cpu_to_be32(FC_BRCD_TOKEN);
+ rpsc2->num_pids = cpu_to_be16(npids);
for (i = 0; i < npids; i++)
rpsc2->pid_list[i].pid = pid_list[i];
@@ -788,30 +788,25 @@ fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id,
u16
fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
struct fc_rpsc_speed_info_s *oper_speed)
{
- bfa_os_memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
+ memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
fc_els_rsp_build(fchs, d_id, s_id, ox_id);
rpsc_acc->command = FC_ELS_ACC;
- rpsc_acc->num_entries = bfa_os_htons(1);
+ rpsc_acc->num_entries = cpu_to_be16(1);
rpsc_acc->speed_info[0].port_speed_cap =
- bfa_os_htons(oper_speed->port_speed_cap);
+ cpu_to_be16(oper_speed->port_speed_cap);
rpsc_acc->speed_info[0].port_op_speed =
- bfa_os_htons(oper_speed->port_op_speed);
+ cpu_to_be16(oper_speed->port_op_speed);
return sizeof(struct fc_rpsc_acc_s);
}
-/*
- * TBD -
- * . get rid of unnecessary memsets
- */
-
u16
fc_logo_rsp_parse(struct fchs_s *fchs, int len)
{
@@ -830,12 +825,12 @@ fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
{
struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
- bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
+ memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
pdisc->els_cmd.els_code = FC_ELS_PDISC;
fc_els_req_build(fchs, d_id, s_id, ox_id);
- pdisc->csp.rxsz = pdisc->class3.rxsz = bfa_os_htons(pdu_size);
+ pdisc->csp.rxsz = pdisc->class3.rxsz = cpu_to_be16(pdu_size);
pdisc->port_name = port_name;
pdisc->node_name = node_name;
@@ -859,7 +854,7 @@ fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
if (!pdisc->class3.class_valid)
return FC_PARSE_NWWN_NOT_EQUAL;
- if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
+ if (be16_to_cpu(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
return FC_PARSE_RXSZ_INVAL;
return FC_PARSE_OK;
@@ -873,10 +868,10 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
int page;
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(prlo, 0, (num_pages * 16) + 4);
+ memset(prlo, 0, (num_pages * 16) + 4);
prlo->command = FC_ELS_PRLO;
prlo->page_len = 0x10;
- prlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+ prlo->payload_len = cpu_to_be16((num_pages * 16) + 4);
for (page = 0; page < num_pages; page++) {
prlo->prlo_params[page].type = FC_TYPE_FCP;
@@ -886,7 +881,7 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
prlo->prlo_params[page].resp_process_assc = 0;
}
- return bfa_os_ntohs(prlo->payload_len);
+ return be16_to_cpu(prlo->payload_len);
}
u16
@@ -901,7 +896,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
if (prlo->command != FC_ELS_ACC)
return FC_PARSE_FAILURE;
- num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
+ num_pages = ((be16_to_cpu(prlo->payload_len)) - 4) / 16;
for (page = 0; page < num_pages; page++) {
if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP)
@@ -931,10 +926,10 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
int page;
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(tprlo, 0, (num_pages * 16) + 4);
+ memset(tprlo, 0, (num_pages * 16) + 4);
tprlo->command = FC_ELS_TPRLO;
tprlo->page_len = 0x10;
- tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+ tprlo->payload_len = cpu_to_be16((num_pages * 16) + 4);
for (page = 0; page < num_pages; page++) {
tprlo->tprlo_params[page].type = FC_TYPE_FCP;
@@ -950,7 +945,7 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
}
}
- return bfa_os_ntohs(tprlo->payload_len);
+ return be16_to_cpu(tprlo->payload_len);
}
u16
@@ -965,7 +960,7 @@ fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
if (tprlo->command != FC_ELS_ACC)
return FC_PARSE_ACC_INVAL;
- num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+ num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16;
for (page = 0; page < num_pages; page++) {
if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
@@ -995,7 +990,7 @@ fc_rrq_rsp_parse(struct fchs_s *fchs, int len)
}
u16
-fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
+fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id,
u32 reason_code, u32 reason_expl)
{
struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1);
@@ -1011,32 +1006,32 @@ fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
static void
fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
{
- bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ memset(cthdr, 0, sizeof(struct ct_hdr_s));
cthdr->rev_id = CT_GS3_REVISION;
cthdr->gs_type = CT_GSTYPE_DIRSERVICE;
cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER;
- cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+ cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
}
static void
fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
{
- bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ memset(cthdr, 0, sizeof(struct ct_hdr_s));
cthdr->rev_id = CT_GS3_REVISION;
cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER;
- cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+ cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
}
static void
fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code,
u8 sub_type)
{
- bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ memset(cthdr, 0, sizeof(struct ct_hdr_s));
cthdr->rev_id = CT_GS3_REVISION;
cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
cthdr->gs_sub_type = sub_type;
- cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+ cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
}
u16
@@ -1045,12 +1040,12 @@ fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_gidpn_req_s *gidpn = (struct fcgs_gidpn_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN);
- bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
+ memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
gidpn->port_name = port_name;
return sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s);
}
@@ -1061,12 +1056,12 @@ fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID);
- bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
+ memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
gpnid->dap = port_id;
return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s);
}
@@ -1077,12 +1072,12 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID);
- bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
+ memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
gnnid->dap = port_id;
return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s);
}
@@ -1090,7 +1085,7 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
u16
fc_ct_rsp_parse(struct ct_hdr_s *cthdr)
{
- if (bfa_os_ntohs(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
+ if (be16_to_cpu(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY)
return FC_PARSE_BUSY;
else
@@ -1104,11 +1099,11 @@ u16
fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr,
u8 set_br_reg, u32 s_id, u16 ox_id)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER);
fc_els_req_build(fchs, d_id, s_id, ox_id);
- bfa_os_memset(scr, 0, sizeof(struct fc_scr_s));
+ memset(scr, 0, sizeof(struct fc_scr_s));
scr->command = FC_ELS_SCR;
scr->reg_func = FC_SCR_REG_FUNC_FULL;
if (set_br_reg)
@@ -1121,7 +1116,7 @@ u16
fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
u32 s_id, u16 ox_id)
{
- u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER);
u16 payldlen;
fc_els_req_build(fchs, d_id, s_id, ox_id);
@@ -1129,7 +1124,7 @@ fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
rscn->pagelen = sizeof(rscn->event[0]);
payldlen = sizeof(u32) + rscn->pagelen;
- rscn->payldlen = bfa_os_htons(payldlen);
+ rscn->payldlen = cpu_to_be16(payldlen);
rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
rscn->event[0].portid = s_id;
@@ -1143,20 +1138,20 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1);
- u32 type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 type_value, d_id = bfa_hton3b(FC_NAME_SERVER);
u8 index;
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
- bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+ memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
rftid->dap = s_id;
/* By default, FCP FC4 Type is registered */
index = FC_TYPE_FCP >> 5;
type_value = 1 << (FC_TYPE_FCP % 32);
- rftid->fc4_type[index] = bfa_os_htonl(type_value);
+ rftid->fc4_type[index] = cpu_to_be32(type_value);
return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
}
@@ -1167,15 +1162,15 @@ fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
- bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+ memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
rftid->dap = s_id;
- bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
+ memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
(bitmap_size < 32 ? bitmap_size : 32));
return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
@@ -1187,12 +1182,12 @@ fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rffid_req_s *rffid = (struct fcgs_rffid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID);
- bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
+ memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
rffid->dap = s_id;
rffid->fc4ftr_bits = fc4_ftrs;
@@ -1209,12 +1204,12 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rspnid_req_s *rspnid =
(struct fcgs_rspnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID);
- bfa_os_memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
+ memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
rspnid->dap = s_id;
rspnid->spn_len = (u8) strlen((char *)name);
@@ -1229,13 +1224,13 @@ fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, u8 fc4_type)
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_gidft_req_s *gidft = (struct fcgs_gidft_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT);
- bfa_os_memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
+ memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
gidft->fc4_type = fc4_type;
gidft->domain_id = 0;
gidft->area_id = 0;
@@ -1249,12 +1244,12 @@ fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rpnid_req_s *rpnid = (struct fcgs_rpnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID);
- bfa_os_memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
+ memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
rpnid->port_id = port_id;
rpnid->port_name = port_name;
@@ -1267,12 +1262,12 @@ fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rnnid_req_s *rnnid = (struct fcgs_rnnid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID);
- bfa_os_memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
+ memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
rnnid->port_id = port_id;
rnnid->node_name = node_name;
@@ -1286,12 +1281,12 @@ fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rcsid_req_s *rcsid =
(struct fcgs_rcsid_req_s *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID);
- bfa_os_memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
+ memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
rcsid->port_id = port_id;
rcsid->cos = cos;
@@ -1304,12 +1299,12 @@ fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_rptid_req_s *rptid = (struct fcgs_rptid_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID);
- bfa_os_memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
+ memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
rptid->port_id = port_id;
rptid->port_type = port_type;
@@ -1321,12 +1316,12 @@ fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
struct fcgs_ganxt_req_s *ganxt = (struct fcgs_ganxt_req_s *)(cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u32 d_id = bfa_hton3b(FC_NAME_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT);
- bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
+ memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
ganxt->port_id = port_id;
return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s);
@@ -1341,7 +1336,7 @@ fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code);
@@ -1356,7 +1351,7 @@ void
fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
{
u8 index;
- u32 *ptr = (u32 *) bit_mask;
+ __be32 *ptr = (__be32 *) bit_mask;
u32 type_value;
/*
@@ -1365,7 +1360,7 @@ fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
index = fc4_type >> 5;
type_value = 1 << (fc4_type % 32);
- ptr[index] = bfa_os_htonl(type_value);
+ ptr[index] = cpu_to_be32(type_value);
}
@@ -1377,13 +1372,13 @@ fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD,
CT_GSSUBTYPE_CFGSERVER);
- bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
+ memset(gmal, 0, sizeof(fcgs_gmal_req_t));
gmal->wwn = wwn;
return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t);
@@ -1397,13 +1392,13 @@ fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
{
struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1);
- u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+ u32 d_id = bfa_hton3b(FC_MGMT_SERVER);
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD,
CT_GSSUBTYPE_CFGSERVER);
- bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
+ memset(gfn, 0, sizeof(fcgs_gfn_req_t));
gfn->wwn = wwn;
return sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t);
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index 73abd02e53cc..ece51ec7620b 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -21,7 +21,7 @@
#ifndef __FCBUILD_H__
#define __FCBUILD_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_fc.h"
#include "bfa_defs_fcs.h"
@@ -138,7 +138,7 @@ u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, u32 s_id,
u16 pdu_size);
u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
- u32 s_id, u16 ox_id,
+ u32 s_id, __be16 ox_id,
wwn_t port_name, wwn_t node_name,
u16 pdu_size,
u16 local_bb_credits);
@@ -186,7 +186,7 @@ u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
u16 pdu_size);
u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
- u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name,
+ u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name,
wwn_t node_name);
enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld,
@@ -196,20 +196,20 @@ enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len,
wwn_t port_name, wwn_t node_name);
u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
wwn_t port_name, wwn_t node_name);
u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt,
- u32 d_id, u32 s_id, u16 ox_id,
+ u32 d_id, u32 s_id, __be16 ox_id,
u8 reason_code, u8 reason_code_expl);
u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
- u32 d_id, u32 s_id, u16 ox_id);
+ u32 d_id, u32 s_id, __be16 ox_id);
u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id,
u32 s_id, u16 ox_id);
enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len);
u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
- u32 s_id, u16 ox_id,
+ u32 s_id, __be16 ox_id,
enum bfa_lport_role role);
u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid,
@@ -218,7 +218,7 @@ u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid,
u16 fc_rnid_acc_build(struct fchs_s *fchs,
struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id,
- u16 ox_id, u32 data_format,
+ __be16 ox_id, u32 data_format,
struct fc_rnid_common_id_data_s *common_id_data,
struct fc_rnid_general_topology_data_s *gen_topo_data);
@@ -228,7 +228,7 @@ u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc,
u32 d_id, u32 s_id, u16 ox_id);
u16 fc_rpsc_acc_build(struct fchs_s *fchs,
struct fc_rpsc_acc_s *rpsc_acc, u32 d_id, u32 s_id,
- u16 ox_id, struct fc_rpsc_speed_info_s *oper_speed);
+ __be16 ox_id, struct fc_rpsc_speed_info_s *oper_speed);
u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id,
u8 fc4_type);
@@ -251,7 +251,7 @@ u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id,
u32 s_id, u16 ox_id, wwn_t port_name);
u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
- u32 s_id, u16 ox_id);
+ u32 s_id, __be16 ox_id);
u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
u16 cmd_code);
@@ -261,7 +261,7 @@ u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn);
void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask);
void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id);
+ __be16 ox_id);
enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len);
@@ -274,15 +274,15 @@ enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name,
wwn_t port_name);
u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
- u32 s_id, u16 ox_id, u16 rx_id);
+ u32 s_id, __be16 ox_id, u16 rx_id);
int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code);
u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages);
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages);
u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
- u32 d_id, u32 s_id, u16 ox_id, int num_pages);
+ u32 d_id, u32 s_id, __be16 ox_id, int num_pages);
u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len);
@@ -304,7 +304,7 @@ u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len);
u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
- u16 ox_id, u32 reason_code, u32 reason_expl);
+ __be16 ox_id, u32 reason_code, u32 reason_expl);
u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
u32 port_id);
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 33c8dd51f474..c0353cdca929 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -15,18 +15,13 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
-#include "bfa_cb_ioim.h"
BFA_TRC_FILE(HAL, FCPIM);
BFA_MODULE(fcpim);
-
-#define bfa_fcpim_add_iostats(__l, __r, __stats) \
- (__l->__stats += __r->__stats)
-
-
-/**
+/*
* BFA ITNIM Related definitions
*/
static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
@@ -37,12 +32,12 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
#define bfa_fcpim_additn(__itnim) \
list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q)
#define bfa_fcpim_delitn(__itnim) do { \
- bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \
+ WARN_ON(!bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \
bfa_itnim_update_del_itn_stats(__itnim); \
list_del(&(__itnim)->qe); \
- bfa_assert(list_empty(&(__itnim)->io_q)); \
- bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \
- bfa_assert(list_empty(&(__itnim)->pending_q)); \
+ WARN_ON(!list_empty(&(__itnim)->io_q)); \
+ WARN_ON(!list_empty(&(__itnim)->io_cleanup_q)); \
+ WARN_ON(!list_empty(&(__itnim)->pending_q)); \
} while (0)
#define bfa_itnim_online_cb(__itnim) do { \
@@ -72,11 +67,9 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
} \
} while (0)
-/**
- * bfa_itnim_sm BFA itnim state machine
+/*
+ * itnim state machine event
*/
-
-
enum bfa_itnim_event {
BFA_ITNIM_SM_CREATE = 1, /* itnim is created */
BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */
@@ -89,7 +82,7 @@ enum bfa_itnim_event {
BFA_ITNIM_SM_QRESUME = 9, /* queue space available */
};
-/**
+/*
* BFA IOIM related definitions
*/
#define bfa_ioim_move_to_comp_q(__ioim) do { \
@@ -107,11 +100,8 @@ enum bfa_itnim_event {
if ((__fcpim)->profile_start) \
(__fcpim)->profile_start(__ioim); \
} while (0)
-/**
- * hal_ioim_sm
- */
-/**
+/*
* IO state machine events
*/
enum bfa_ioim_event {
@@ -136,11 +126,11 @@ enum bfa_ioim_event {
};
-/**
+/*
* BFA TSKIM related definitions
*/
-/**
+/*
* task management completion handling
*/
#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
@@ -165,7 +155,7 @@ enum bfa_tskim_event {
BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */
};
-/**
+/*
* forward declaration for BFA ITNIM functions
*/
static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim);
@@ -183,7 +173,7 @@ static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim);
static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim);
static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim);
-/**
+/*
* forward declaration of ITNIM state machine
*/
static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim,
@@ -217,12 +207,11 @@ static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
enum bfa_itnim_event event);
-/**
+/*
* forward declaration for BFA IOIM functions
*/
static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
-static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim);
-static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim);
static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim);
static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim);
static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete);
@@ -232,8 +221,7 @@ static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
-
-/**
+/*
* forward declaration of BFA IO state machine
*/
static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim,
@@ -260,14 +248,13 @@ static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim,
enum bfa_ioim_event event);
static void bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim,
enum bfa_ioim_event event);
-
-/**
+/*
* forward declaration for BFA TSKIM functions
*/
static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete);
static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim,
- lun_t lun);
+ struct scsi_lun lun);
static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim);
static void bfa_tskim_cleanp_comp(void *tskim_cbarg);
static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim);
@@ -275,8 +262,7 @@ static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim);
static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
-
-/**
+/*
* forward declaration of BFA TSKIM state machine
*/
static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim,
@@ -293,13 +279,12 @@ static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
enum bfa_tskim_event event);
static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
enum bfa_tskim_event event);
-
-/**
- * hal_fcpim_mod BFA FCP Initiator Mode module
+/*
+ * BFA FCP Initiator Mode module
*/
-/**
- * Compute and return memory needed by FCP(im) module.
+/*
+ * Compute and return memory needed by FCP(im) module.
*/
static void
bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
@@ -307,7 +292,7 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
{
bfa_itnim_meminfo(cfg, km_len, dm_len);
- /**
+ /*
* IO memory
*/
if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN)
@@ -320,7 +305,7 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
*dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN;
- /**
+ /*
* task management command memory
*/
if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN)
@@ -357,10 +342,6 @@ bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
static void
bfa_fcpim_detach(struct bfa_s *bfa)
{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- bfa_ioim_detach(fcpim);
- bfa_tskim_detach(fcpim);
}
static void
@@ -387,56 +368,6 @@ bfa_fcpim_iocdisable(struct bfa_s *bfa)
}
void
-bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats,
- struct bfa_itnim_iostats_s *rstats)
-{
- bfa_fcpim_add_iostats(lstats, rstats, total_ios);
- bfa_fcpim_add_iostats(lstats, rstats, qresumes);
- bfa_fcpim_add_iostats(lstats, rstats, no_iotags);
- bfa_fcpim_add_iostats(lstats, rstats, io_aborts);
- bfa_fcpim_add_iostats(lstats, rstats, no_tskims);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted);
- bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts);
- bfa_fcpim_add_iostats(lstats, rstats, iocom_utags);
- bfa_fcpim_add_iostats(lstats, rstats, io_cleanups);
- bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts);
- bfa_fcpim_add_iostats(lstats, rstats, onlines);
- bfa_fcpim_add_iostats(lstats, rstats, offlines);
- bfa_fcpim_add_iostats(lstats, rstats, creates);
- bfa_fcpim_add_iostats(lstats, rstats, deletes);
- bfa_fcpim_add_iostats(lstats, rstats, create_comps);
- bfa_fcpim_add_iostats(lstats, rstats, delete_comps);
- bfa_fcpim_add_iostats(lstats, rstats, sler_events);
- bfa_fcpim_add_iostats(lstats, rstats, fw_create);
- bfa_fcpim_add_iostats(lstats, rstats, fw_delete);
- bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled);
- bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds);
- bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_success);
- bfa_fcpim_add_iostats(lstats, rstats, tm_failures);
- bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps);
- bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes);
- bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups);
- bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps);
- bfa_fcpim_add_iostats(lstats, rstats, io_comps);
- bfa_fcpim_add_iostats(lstats, rstats, input_reqs);
- bfa_fcpim_add_iostats(lstats, rstats, output_reqs);
- bfa_fcpim_add_iostats(lstats, rstats, rd_throughput);
- bfa_fcpim_add_iostats(lstats, rstats, wr_throughput);
-}
-
-void
bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
@@ -454,128 +385,6 @@ bfa_fcpim_path_tov_get(struct bfa_s *bfa)
return fcpim->path_tov / 1000;
}
-bfa_status_t
-bfa_fcpim_port_iostats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *stats,
- u8 lp_tag)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* accumulate IO stats from itnim */
- bfa_os_memset(stats, 0, sizeof(struct bfa_itnim_iostats_s));
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- if (itnim->rport->rport_info.lp_tag != lp_tag)
- continue;
- bfa_fcpim_add_stats(stats, &(itnim->stats));
- }
- return BFA_STATUS_OK;
-}
-bfa_status_t
-bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *modstats)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* accumulate IO stats from itnim */
- bfa_os_memset(modstats, 0, sizeof(struct bfa_itnim_iostats_s));
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_fcpim_add_stats(modstats, &(itnim->stats));
- }
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa,
- struct bfa_fcpim_del_itn_stats_s *modstats)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- *modstats = fcpim->del_itn_stats;
-
- return BFA_STATUS_OK;
-}
-
-
-bfa_status_t
-bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time)
-{
- struct bfa_itnim_s *itnim;
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
-
- /* accumulate IO stats from itnim */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_itnim_clear_stats(itnim);
- }
- fcpim->io_profile = BFA_TRUE;
- fcpim->io_profile_start_time = time;
- fcpim->profile_comp = bfa_ioim_profile_comp;
- fcpim->profile_start = bfa_ioim_profile_start;
-
- return BFA_STATUS_OK;
-}
-bfa_status_t
-bfa_fcpim_profile_off(struct bfa_s *bfa)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- fcpim->io_profile = BFA_FALSE;
- fcpim->io_profile_start_time = 0;
- fcpim->profile_comp = NULL;
- fcpim->profile_start = NULL;
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* clear IO stats from all active itnims */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- if (itnim->rport->rport_info.lp_tag != lp_tag)
- continue;
- bfa_itnim_clear_stats(itnim);
- }
- return BFA_STATUS_OK;
-
-}
-
-bfa_status_t
-bfa_fcpim_clr_modstats(struct bfa_s *bfa)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- struct list_head *qe, *qen;
- struct bfa_itnim_s *itnim;
-
- /* clear IO stats from all active itnims */
- list_for_each_safe(qe, qen, &fcpim->itnim_q) {
- itnim = (struct bfa_itnim_s *) qe;
- bfa_itnim_clear_stats(itnim);
- }
- bfa_os_memset(&fcpim->del_itn_stats, 0,
- sizeof(struct bfa_fcpim_del_itn_stats_s));
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
-
- bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX);
-
- fcpim->q_depth = q_depth;
-}
-
u16
bfa_fcpim_qdepth_get(struct bfa_s *bfa)
{
@@ -584,32 +393,12 @@ bfa_fcpim_qdepth_get(struct bfa_s *bfa)
return fcpim->q_depth;
}
-void
-bfa_fcpim_update_ioredirect(struct bfa_s *bfa)
-{
- bfa_boolean_t ioredirect;
-
- /*
- * IO redirection is turned off when QoS is enabled and vice versa
- */
- ioredirect = bfa_fcport_is_qos_enabled(bfa) ? BFA_FALSE : BFA_TRUE;
-}
-
-void
-bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- fcpim->ioredirect = state;
-}
-
-
-
-/**
+/*
* BFA ITNIM module state machine functions
*/
-/**
- * Beginning/unallocated state - no events expected.
+/*
+ * Beginning/unallocated state - no events expected.
*/
static void
bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -629,8 +418,8 @@ bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/**
- * Beginning state, only online event expected.
+/*
+ * Beginning state, only online event expected.
*/
static void
bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -660,7 +449,7 @@ bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/**
+/*
* Waiting for itnim create response from firmware.
*/
static void
@@ -732,8 +521,8 @@ bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
}
}
-/**
- * Waiting for itnim create response from firmware, a delete is pending.
+/*
+ * Waiting for itnim create response from firmware, a delete is pending.
*/
static void
bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
@@ -760,8 +549,8 @@ bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
}
}
-/**
- * Online state - normal parking state.
+/*
+ * Online state - normal parking state.
*/
static void
bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -802,8 +591,8 @@ bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/**
- * Second level error recovery need.
+/*
+ * Second level error recovery need.
*/
static void
bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -833,8 +622,8 @@ bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/**
- * Going offline. Waiting for active IO cleanup.
+/*
+ * Going offline. Waiting for active IO cleanup.
*/
static void
bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
@@ -870,8 +659,8 @@ bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
}
}
-/**
- * Deleting itnim. Waiting for active IO cleanup.
+/*
+ * Deleting itnim. Waiting for active IO cleanup.
*/
static void
bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
@@ -898,7 +687,7 @@ bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
}
}
-/**
+/*
* Rport offline. Fimrware itnim is being deleted - awaiting f/w response.
*/
static void
@@ -955,8 +744,8 @@ bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
}
}
-/**
- * Offline state.
+/*
+ * Offline state.
*/
static void
bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -987,9 +776,6 @@ bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
}
}
-/**
- * IOC h/w failed state.
- */
static void
bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
enum bfa_itnim_event event)
@@ -1023,8 +809,8 @@ bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
}
}
-/**
- * Itnim is deleted, waiting for firmware response to delete.
+/*
+ * Itnim is deleted, waiting for firmware response to delete.
*/
static void
bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
@@ -1068,8 +854,8 @@ bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
}
}
-/**
- * Initiate cleanup of all IOs on an IOC failure.
+/*
+ * Initiate cleanup of all IOs on an IOC failure.
*/
static void
bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
@@ -1088,7 +874,7 @@ bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
bfa_ioim_iocdisable(ioim);
}
- /**
+ /*
* For IO request in pending queue, we pretend an early timeout.
*/
list_for_each_safe(qe, qen, &itnim->pending_q) {
@@ -1102,8 +888,8 @@ bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
}
}
-/**
- * IO cleanup completion
+/*
+ * IO cleanup completion
*/
static void
bfa_itnim_cleanp_comp(void *itnim_cbarg)
@@ -1114,8 +900,8 @@ bfa_itnim_cleanp_comp(void *itnim_cbarg)
bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP);
}
-/**
- * Initiate cleanup of all IOs.
+/*
+ * Initiate cleanup of all IOs.
*/
static void
bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
@@ -1129,7 +915,7 @@ bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
list_for_each_safe(qe, qen, &itnim->io_q) {
ioim = (struct bfa_ioim_s *) qe;
- /**
+ /*
* Move IO to a cleanup queue from active queue so that a later
* TM will not pickup this IO.
*/
@@ -1176,7 +962,7 @@ __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete)
bfa_cb_itnim_sler(itnim->ditn);
}
-/**
+/*
* Call to resume any I/O requests waiting for room in request queue.
*/
static void
@@ -1187,10 +973,7 @@ bfa_itnim_qresume(void *cbarg)
bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME);
}
-
-
-
-/**
+/*
* bfa_itnim_public
*/
@@ -1210,7 +993,7 @@ void
bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
u32 *dm_len)
{
- /**
+ /*
* ITN memory
*/
*km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s);
@@ -1229,7 +1012,7 @@ bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
fcpim->itnim_arr = itnim;
for (i = 0; i < fcpim->num_itnims; i++, itnim++) {
- bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s));
+ memset(itnim, 0, sizeof(struct bfa_itnim_s));
itnim->bfa = bfa;
itnim->fcpim = fcpim;
itnim->reqq = BFA_REQQ_QOS_LO;
@@ -1264,7 +1047,7 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
itnim->msg_no++;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(itnim->bfa, itnim->reqq);
@@ -1281,7 +1064,7 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
m->msg_no = itnim->msg_no;
bfa_stats(itnim, fw_create);
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(itnim->bfa, itnim->reqq);
@@ -1293,7 +1076,7 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
{
struct bfi_itnim_delete_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(itnim->bfa, itnim->reqq);
@@ -1307,14 +1090,14 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
m->fw_handle = itnim->rport->fw_handle;
bfa_stats(itnim, fw_delete);
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(itnim->bfa, itnim->reqq);
return BFA_TRUE;
}
-/**
+/*
* Cleanup all pending failed inflight requests.
*/
static void
@@ -1329,7 +1112,7 @@ bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov)
}
}
-/**
+/*
* Start all pending IO requests.
*/
static void
@@ -1339,12 +1122,12 @@ bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
bfa_itnim_iotov_stop(itnim);
- /**
+ /*
* Abort all inflight IO requests in the queue
*/
bfa_itnim_delayed_comp(itnim, BFA_FALSE);
- /**
+ /*
* Start all pending IO requests.
*/
while (!list_empty(&itnim->pending_q)) {
@@ -1354,7 +1137,7 @@ bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
}
}
-/**
+/*
* Fail all pending IO requests
*/
static void
@@ -1362,12 +1145,12 @@ bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
{
struct bfa_ioim_s *ioim;
- /**
+ /*
* Fail all inflight IO requests in the queue
*/
bfa_itnim_delayed_comp(itnim, BFA_TRUE);
- /**
+ /*
* Fail any pending IO requests.
*/
while (!list_empty(&itnim->pending_q)) {
@@ -1377,7 +1160,7 @@ bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
}
}
-/**
+/*
* IO TOV timer callback. Fail any pending IO requests.
*/
static void
@@ -1392,7 +1175,7 @@ bfa_itnim_iotov(void *itnim_arg)
bfa_cb_itnim_tov(itnim->ditn);
}
-/**
+/*
* Start IO TOV timer for failing back pending IO requests in offline state.
*/
static void
@@ -1401,13 +1184,13 @@ bfa_itnim_iotov_start(struct bfa_itnim_s *itnim)
if (itnim->fcpim->path_tov > 0) {
itnim->iotov_active = BFA_TRUE;
- bfa_assert(bfa_itnim_hold_io(itnim));
+ WARN_ON(!bfa_itnim_hold_io(itnim));
bfa_timer_start(itnim->bfa, &itnim->timer,
bfa_itnim_iotov, itnim, itnim->fcpim->path_tov);
}
}
-/**
+/*
* Stop IO TOV timer.
*/
static void
@@ -1419,7 +1202,7 @@ bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim)
}
}
-/**
+/*
* Stop IO TOV timer.
*/
static void
@@ -1457,14 +1240,12 @@ bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim)
fcpim->del_itn_stats.del_tm_iocdowns += itnim->stats.tm_iocdowns;
}
-
-
-/**
- * bfa_itnim_public
+/*
+ * bfa_itnim_public
*/
-/**
- * Itnim interrupt processing.
+/*
+ * Itnim interrupt processing.
*/
void
bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
@@ -1481,7 +1262,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
case BFI_ITNIM_I2H_CREATE_RSP:
itnim = BFA_ITNIM_FROM_TAG(fcpim,
msg.create_rsp->bfa_handle);
- bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ WARN_ON(msg.create_rsp->status != BFA_STATUS_OK);
bfa_stats(itnim, create_comps);
bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
break;
@@ -1489,7 +1270,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
case BFI_ITNIM_I2H_DELETE_RSP:
itnim = BFA_ITNIM_FROM_TAG(fcpim,
msg.delete_rsp->bfa_handle);
- bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK);
bfa_stats(itnim, delete_comps);
bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
break;
@@ -1503,14 +1284,12 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
default:
bfa_trc(bfa, m->mhdr.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
-
-
-/**
- * bfa_itnim_api
+/*
+ * bfa_itnim_api
*/
struct bfa_itnim_s *
@@ -1520,7 +1299,7 @@ bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
struct bfa_itnim_s *itnim;
itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag);
- bfa_assert(itnim->rport == rport);
+ WARN_ON(itnim->rport != rport);
itnim->ditn = ditn;
@@ -1552,7 +1331,7 @@ bfa_itnim_offline(struct bfa_itnim_s *itnim)
bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE);
}
-/**
+/*
* Return true if itnim is considered offline for holding off IO request.
* IO is not held if itnim is being deleted.
*/
@@ -1568,54 +1347,26 @@ bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable));
}
-bfa_status_t
-bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
- struct bfa_itnim_ioprofile_s *ioprofile)
-{
- struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa);
- if (!fcpim->io_profile)
- return BFA_STATUS_IOPROFILE_OFF;
-
- itnim->ioprofile.index = BFA_IOBUCKET_MAX;
- itnim->ioprofile.io_profile_start_time =
- bfa_io_profile_start_time(itnim->bfa);
- itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul;
- itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div;
- *ioprofile = itnim->ioprofile;
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
- struct bfa_itnim_iostats_s *stats)
-{
- *stats = itnim->stats;
-}
-
void
bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
{
int j;
- bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats));
- bfa_os_memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile));
+ memset(&itnim->stats, 0, sizeof(itnim->stats));
+ memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile));
for (j = 0; j < BFA_IOBUCKET_MAX; j++)
itnim->ioprofile.io_latency.min[j] = ~0;
}
-/**
+/*
* BFA IO module state machine functions
*/
-/**
- * IO is not started (unallocated).
+/*
+ * IO is not started (unallocated).
*/
static void
bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
{
- bfa_trc_fp(ioim->bfa, ioim->iotag);
- bfa_trc_fp(ioim->bfa, event);
-
switch (event) {
case BFA_IOIM_SM_START:
if (!bfa_itnim_is_online(ioim->itnim)) {
@@ -1635,7 +1386,7 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
if (ioim->nsges > BFI_SGE_INLINE) {
- if (!bfa_ioim_sge_setup(ioim)) {
+ if (!bfa_ioim_sgpg_alloc(ioim)) {
bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc);
return;
}
@@ -1657,12 +1408,12 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_ABORT:
- /**
+ /*
* IO in pending queue can get abort requests. Complete abort
* requests immediately.
*/
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
- bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
+ WARN_ON(!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
__bfa_cb_ioim_abort, ioim);
break;
@@ -1672,8 +1423,8 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * IO is waiting for SG pages.
+/*
+ * IO is waiting for SG pages.
*/
static void
bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
@@ -1719,15 +1470,12 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * IO is active.
+/*
+ * IO is active.
*/
static void
bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
{
- bfa_trc_fp(ioim->bfa, ioim->iotag);
- bfa_trc_fp(ioim->bfa, event);
-
switch (event) {
case BFA_IOIM_SM_COMP_GOOD:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
@@ -1786,8 +1534,8 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_SQRETRY:
- if (bfa_ioim_get_iotag(ioim) != BFA_TRUE) {
- /* max retry completed free IO */
+ if (bfa_ioim_maxretry_reached(ioim)) {
+ /* max retry reached, free IO */
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
bfa_ioim_move_to_comp_q(ioim);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
@@ -1803,18 +1551,16 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
-* IO is retried with new tag.
-*/
+/*
+ * IO is retried with new tag.
+ */
static void
bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
{
- bfa_trc_fp(ioim->bfa, ioim->iotag);
- bfa_trc_fp(ioim->bfa, event);
-
switch (event) {
case BFA_IOIM_SM_FREE:
/* abts and rrq done. Now retry the IO with new tag */
+ bfa_ioim_update_iotag(ioim);
if (!bfa_ioim_send_ioreq(ioim)) {
bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
break;
@@ -1844,7 +1590,7 @@ bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_ABORT:
- /** in this state IO abort is done.
+ /* in this state IO abort is done.
* Waiting for IO tag resource free.
*/
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
@@ -1857,8 +1603,8 @@ bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * IO is being aborted, waiting for completion from firmware.
+/*
+ * IO is being aborted, waiting for completion from firmware.
*/
static void
bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
@@ -1894,7 +1640,7 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_CLEANUP:
- bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ WARN_ON(ioim->iosp->abort_explicit != BFA_TRUE);
ioim->iosp->abort_explicit = BFA_FALSE;
if (bfa_ioim_send_abort(ioim))
@@ -1919,7 +1665,7 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
+/*
* IO is being cleaned up (implicit abort), waiting for completion from
* firmware.
*/
@@ -1937,7 +1683,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_ABORT:
- /**
+ /*
* IO is already being aborted implicitly
*/
ioim->io_cbfn = __bfa_cb_ioim_abort;
@@ -1969,7 +1715,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_CLEANUP:
- /**
+ /*
* IO can be in cleanup state already due to TM command.
* 2nd cleanup request comes from ITN offline event.
*/
@@ -1980,8 +1726,8 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * IO is waiting for room in request CQ
+/*
+ * IO is waiting for room in request CQ
*/
static void
bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
@@ -2024,8 +1770,8 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * Active IO is being aborted, waiting for room in request CQ.
+/*
+ * Active IO is being aborted, waiting for room in request CQ.
*/
static void
bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
@@ -2040,7 +1786,7 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_CLEANUP:
- bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ WARN_ON(ioim->iosp->abort_explicit != BFA_TRUE);
ioim->iosp->abort_explicit = BFA_FALSE;
bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
break;
@@ -2075,8 +1821,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
- * Active IO is being cleaned up, waiting for room in request CQ.
+/*
+ * Active IO is being cleaned up, waiting for room in request CQ.
*/
static void
bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
@@ -2091,8 +1837,8 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
break;
case BFA_IOIM_SM_ABORT:
- /**
- * IO is alraedy being cleaned up implicitly
+ /*
+ * IO is already being cleaned up implicitly
*/
ioim->io_cbfn = __bfa_cb_ioim_abort;
break;
@@ -2125,15 +1871,12 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
+/*
* IO bfa callback is pending.
*/
static void
bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
{
- bfa_trc_fp(ioim->bfa, ioim->iotag);
- bfa_trc_fp(ioim->bfa, event);
-
switch (event) {
case BFA_IOIM_SM_HCB:
bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
@@ -2152,7 +1895,7 @@ bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
+/*
* IO bfa callback is pending. IO resource cannot be freed.
*/
static void
@@ -2185,7 +1928,7 @@ bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
}
-/**
+/*
* IO is completed, waiting resource free from firmware.
*/
static void
@@ -2213,11 +1956,6 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
}
-
-/**
- * hal_ioim_private
- */
-
static void
__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
{
@@ -2247,7 +1985,7 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
if (m->io_status == BFI_IOIM_STS_OK) {
- /**
+ /*
* setup sense information, if present
*/
if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) &&
@@ -2256,15 +1994,15 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
snsinfo = ioim->iosp->snsinfo;
}
- /**
+ /*
* setup residue value correctly for normal completions
*/
if (m->resid_flags == FCP_RESID_UNDER) {
- residue = bfa_os_ntohl(m->residue);
+ residue = be32_to_cpu(m->residue);
bfa_stats(ioim->itnim, iocomp_underrun);
}
if (m->resid_flags == FCP_RESID_OVER) {
- residue = bfa_os_ntohl(m->residue);
+ residue = be32_to_cpu(m->residue);
residue = -residue;
bfa_stats(ioim->itnim, iocomp_overrun);
}
@@ -2323,11 +2061,11 @@ bfa_ioim_sgpg_alloced(void *cbarg)
ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q);
- bfa_ioim_sgpg_setup(ioim);
+ ioim->sgpg = bfa_q_first(&ioim->sgpg_q);
bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
}
-/**
+/*
* Send I/O request to firmware.
*/
static bfa_boolean_t
@@ -2335,15 +2073,18 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
{
struct bfa_itnim_s *itnim = ioim->itnim;
struct bfi_ioim_req_s *m;
- static struct fcp_cmnd_s cmnd_z0 = { 0 };
- struct bfi_sge_s *sge;
+ static struct fcp_cmnd_s cmnd_z0 = { { { 0 } } };
+ struct bfi_sge_s *sge, *sgpge;
u32 pgdlen = 0;
u32 fcp_dl;
u64 addr;
struct scatterlist *sg;
+ struct bfa_sgpg_s *sgpg;
struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
+ u32 i, sge_id, pgcumsz;
+ enum dma_data_direction dmadir;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(ioim->bfa, ioim->reqq);
@@ -2354,27 +2095,66 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
return BFA_FALSE;
}
- /**
+ /*
* build i/o request message next
*/
- m->io_tag = bfa_os_htons(ioim->iotag);
+ m->io_tag = cpu_to_be16(ioim->iotag);
m->rport_hdl = ioim->itnim->rport->fw_handle;
- m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
+ m->io_timeout = 0;
- /**
- * build inline IO SG element here
- */
sge = &m->sges[0];
- if (ioim->nsges) {
- sg = (struct scatterlist *)scsi_sglist(cmnd);
- addr = bfa_os_sgaddr(sg_dma_address(sg));
- sge->sga = *(union bfi_addr_u *) &addr;
- pgdlen = sg_dma_len(sg);
- sge->sg_len = pgdlen;
- sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
+ sgpg = ioim->sgpg;
+ sge_id = 0;
+ sgpge = NULL;
+ pgcumsz = 0;
+ scsi_for_each_sg(cmnd, sg, ioim->nsges, i) {
+ if (i == 0) {
+ /* build inline IO SG element */
+ addr = bfa_sgaddr_le(sg_dma_address(sg));
+ sge->sga = *(union bfi_addr_u *) &addr;
+ pgdlen = sg_dma_len(sg);
+ sge->sg_len = pgdlen;
+ sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
- bfa_sge_to_be(sge);
- sge++;
+ bfa_sge_to_be(sge);
+ sge++;
+ } else {
+ if (sge_id == 0)
+ sgpge = sgpg->sgpg->sges;
+
+ addr = bfa_sgaddr_le(sg_dma_address(sg));
+ sgpge->sga = *(union bfi_addr_u *) &addr;
+ sgpge->sg_len = sg_dma_len(sg);
+ pgcumsz += sgpge->sg_len;
+
+ /* set flags */
+ if (i < (ioim->nsges - 1) &&
+ sge_id < (BFI_SGPG_DATA_SGES - 1))
+ sgpge->flags = BFI_SGE_DATA;
+ else if (i < (ioim->nsges - 1))
+ sgpge->flags = BFI_SGE_DATA_CPL;
+ else
+ sgpge->flags = BFI_SGE_DATA_LAST;
+
+ bfa_sge_to_le(sgpge);
+
+ sgpge++;
+ if (i == (ioim->nsges - 1)) {
+ sgpge->flags = BFI_SGE_PGDLEN;
+ sgpge->sga.a32.addr_lo = 0;
+ sgpge->sga.a32.addr_hi = 0;
+ sgpge->sg_len = pgcumsz;
+ bfa_sge_to_le(sgpge);
+ } else if (++sge_id == BFI_SGPG_DATA_SGES) {
+ sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
+ sgpge->flags = BFI_SGE_LINK;
+ sgpge->sga = sgpg->sgpg_pa;
+ sgpge->sg_len = pgcumsz;
+ bfa_sge_to_le(sgpge);
+ sge_id = 0;
+ pgcumsz = 0;
+ }
+ }
}
if (ioim->nsges > BFI_SGE_INLINE) {
@@ -2387,18 +2167,24 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
sge->flags = BFI_SGE_PGDLEN;
bfa_sge_to_be(sge);
- /**
+ /*
* set up I/O command parameters
*/
- bfa_os_assign(m->cmnd, cmnd_z0);
- m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
- m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
- bfa_os_assign(m->cmnd.cdb,
- *(scsi_cdb_t *)bfa_cb_ioim_get_cdb(ioim->dio));
- fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
- m->cmnd.fcp_dl = bfa_os_htonl(fcp_dl);
-
- /**
+ m->cmnd = cmnd_z0;
+ int_to_scsilun(cmnd->device->lun, &m->cmnd.lun);
+ dmadir = cmnd->sc_data_direction;
+ if (dmadir == DMA_TO_DEVICE)
+ m->cmnd.iodir = FCP_IODIR_WRITE;
+ else if (dmadir == DMA_FROM_DEVICE)
+ m->cmnd.iodir = FCP_IODIR_READ;
+ else
+ m->cmnd.iodir = FCP_IODIR_NONE;
+
+ m->cmnd.cdb = *(struct scsi_cdb_s *) cmnd->cmnd;
+ fcp_dl = scsi_bufflen(cmnd);
+ m->cmnd.fcp_dl = cpu_to_be32(fcp_dl);
+
+ /*
* set up I/O message header
*/
switch (m->cmnd.iodir) {
@@ -2419,47 +2205,28 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
}
if (itnim->seq_rec ||
- (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1)))
+ (scsi_bufflen(cmnd) & (sizeof(u32) - 1)))
bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
-#ifdef IOIM_ADVANCED
- m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio);
- m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
- m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
-
- /**
- * Handle large CDB (>16 bytes).
- */
- m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
- FCP_CMND_CDB_LEN) / sizeof(u32);
- if (m->cmnd.addl_cdb_len) {
- bfa_os_memcpy(&m->cmnd.cdb + 1, (scsi_cdb_t *)
- bfa_cb_ioim_get_cdb(ioim->dio) + 1,
- m->cmnd.addl_cdb_len * sizeof(u32));
- fcp_cmnd_fcpdl(&m->cmnd) =
- bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
- }
-#endif
-
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(ioim->bfa, ioim->reqq);
return BFA_TRUE;
}
-/**
+/*
* Setup any additional SG pages needed.Inline SG element is setup
* at queuing time.
*/
static bfa_boolean_t
-bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
+bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim)
{
u16 nsgpgs;
- bfa_assert(ioim->nsges > BFI_SGE_INLINE);
+ WARN_ON(ioim->nsges <= BFI_SGE_INLINE);
- /**
+ /*
* allocate SG pages needed
*/
nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
@@ -2473,74 +2240,12 @@ bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
}
ioim->nsgpgs = nsgpgs;
- bfa_ioim_sgpg_setup(ioim);
+ ioim->sgpg = bfa_q_first(&ioim->sgpg_q);
return BFA_TRUE;
}
-static void
-bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
-{
- int sgeid, nsges, i;
- struct bfi_sge_s *sge;
- struct bfa_sgpg_s *sgpg;
- u32 pgcumsz;
- u64 addr;
- struct scatterlist *sg;
- struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
-
- sgeid = BFI_SGE_INLINE;
- ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
-
- sg = scsi_sglist(cmnd);
- sg = sg_next(sg);
-
- do {
- sge = sgpg->sgpg->sges;
- nsges = ioim->nsges - sgeid;
- if (nsges > BFI_SGPG_DATA_SGES)
- nsges = BFI_SGPG_DATA_SGES;
-
- pgcumsz = 0;
- for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) {
- addr = bfa_os_sgaddr(sg_dma_address(sg));
- sge->sga = *(union bfi_addr_u *) &addr;
- sge->sg_len = sg_dma_len(sg);
- pgcumsz += sge->sg_len;
-
- /**
- * set flags
- */
- if (i < (nsges - 1))
- sge->flags = BFI_SGE_DATA;
- else if (sgeid < (ioim->nsges - 1))
- sge->flags = BFI_SGE_DATA_CPL;
- else
- sge->flags = BFI_SGE_DATA_LAST;
-
- bfa_sge_to_le(sge);
- }
-
- sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
-
- /**
- * set the link element of each page
- */
- if (sgeid == ioim->nsges) {
- sge->flags = BFI_SGE_PGDLEN;
- sge->sga.a32.addr_lo = 0;
- sge->sga.a32.addr_hi = 0;
- } else {
- sge->flags = BFI_SGE_LINK;
- sge->sga = sgpg->sgpg_pa;
- }
- sge->sg_len = pgcumsz;
-
- bfa_sge_to_le(sge);
- } while (sgeid < ioim->nsges);
-}
-
-/**
+/*
* Send I/O abort request to firmware.
*/
static bfa_boolean_t
@@ -2549,14 +2254,14 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
struct bfi_ioim_abort_req_s *m;
enum bfi_ioim_h2i msgop;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(ioim->bfa, ioim->reqq);
if (!m)
return BFA_FALSE;
- /**
+ /*
* build i/o request message next
*/
if (ioim->iosp->abort_explicit)
@@ -2565,17 +2270,17 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
msgop = BFI_IOIM_H2I_IOCLEANUP_REQ;
bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa));
- m->io_tag = bfa_os_htons(ioim->iotag);
+ m->io_tag = cpu_to_be16(ioim->iotag);
m->abort_tag = ++ioim->abort_tag;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(ioim->bfa, ioim->reqq);
return BFA_TRUE;
}
-/**
+/*
* Call to resume any I/O requests waiting for room in request queue.
*/
static void
@@ -2591,7 +2296,7 @@ bfa_ioim_qresume(void *cbarg)
static void
bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
{
- /**
+ /*
* Move IO from itnim queue to fcpim global queue since itnim will be
* freed.
*/
@@ -2606,7 +2311,7 @@ bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
}
bfa_itnim_iodone(ioim->itnim);
} else
- bfa_tskim_iodone(ioim->iosp->tskim);
+ bfa_wc_down(&ioim->iosp->tskim->wc);
}
static bfa_boolean_t
@@ -2624,13 +2329,10 @@ bfa_ioim_is_abortable(struct bfa_ioim_s *ioim)
return BFA_TRUE;
}
-/**
- * or after the link comes back.
- */
void
bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
{
- /**
+ /*
* If path tov timer expired, failback with PATHTOV status - these
* IO requests are not normally retried by IO stack.
*
@@ -2645,7 +2347,7 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
}
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
- /**
+ /*
* Move IO to fcpim global queue since itnim will be
* freed.
*/
@@ -2654,12 +2356,7 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
}
-
-/**
- * hal_ioim_friend
- */
-
-/**
+/*
* Memory allocation and initialization.
*/
void
@@ -2671,7 +2368,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
u8 *snsinfo;
u32 snsbufsz;
- /**
+ /*
* claim memory first
*/
ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo);
@@ -2682,7 +2379,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
fcpim->ioim_sp_arr = iosp;
bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs);
- /**
+ /*
* Claim DMA memory for per IO sense data.
*/
snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN;
@@ -2694,7 +2391,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
snsinfo = fcpim->snsbase.kva;
bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa);
- /**
+ /*
* Initialize ioim free queues
*/
INIT_LIST_HEAD(&fcpim->ioim_free_q);
@@ -2706,7 +2403,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
/*
* initialize IOIM
*/
- bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s));
+ memset(ioim, 0, sizeof(struct bfa_ioim_s));
ioim->iotag = i;
ioim->bfa = fcpim->bfa;
ioim->fcpim = fcpim;
@@ -2723,14 +2420,6 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
}
}
-/**
- * Driver detach time call.
- */
-void
-bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim)
-{
-}
-
void
bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
{
@@ -2740,17 +2429,17 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
u16 iotag;
enum bfa_ioim_event evt = BFA_IOIM_SM_COMP;
- iotag = bfa_os_ntohs(rsp->io_tag);
+ iotag = be16_to_cpu(rsp->io_tag);
ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
- bfa_assert(ioim->iotag == iotag);
+ WARN_ON(ioim->iotag != iotag);
bfa_trc(ioim->bfa, ioim->iotag);
bfa_trc(ioim->bfa, rsp->io_status);
bfa_trc(ioim->bfa, rsp->reuse_io_tag);
if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active))
- bfa_os_assign(ioim->iosp->comp_rspmsg, *m);
+ ioim->iosp->comp_rspmsg = *m;
switch (rsp->io_status) {
case BFI_IOIM_STS_OK:
@@ -2774,13 +2463,13 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
case BFI_IOIM_STS_PROTO_ERR:
bfa_stats(ioim->itnim, iocom_proto_err);
- bfa_assert(rsp->reuse_io_tag);
+ WARN_ON(!rsp->reuse_io_tag);
evt = BFA_IOIM_SM_COMP;
break;
case BFI_IOIM_STS_SQER_NEEDED:
bfa_stats(ioim->itnim, iocom_sqer_needed);
- bfa_assert(rsp->reuse_io_tag == 0);
+ WARN_ON(rsp->reuse_io_tag != 0);
evt = BFA_IOIM_SM_SQRETRY;
break;
@@ -2809,7 +2498,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
bfa_sm_send_event(ioim, evt);
@@ -2823,43 +2512,16 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
struct bfa_ioim_s *ioim;
u16 iotag;
- iotag = bfa_os_ntohs(rsp->io_tag);
+ iotag = be16_to_cpu(rsp->io_tag);
ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
- bfa_assert(ioim->iotag == iotag);
+ WARN_ON(BFA_IOIM_TAG_2_ID(ioim->iotag) != iotag);
- bfa_trc_fp(ioim->bfa, ioim->iotag);
bfa_ioim_cb_profile_comp(fcpim, ioim);
-
bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
}
-void
-bfa_ioim_profile_start(struct bfa_ioim_s *ioim)
-{
- ioim->start_time = bfa_os_get_clock();
-}
-
-void
-bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
-{
- u32 fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
- u32 index = bfa_ioim_get_index(fcp_dl);
- u64 end_time = bfa_os_get_clock();
- struct bfa_itnim_latency_s *io_lat =
- &(ioim->itnim->ioprofile.io_latency);
- u32 val = (u32)(end_time - ioim->start_time);
-
- bfa_itnim_ioprofile_update(ioim->itnim, index);
-
- io_lat->count[index]++;
- io_lat->min[index] = (io_lat->min[index] < val) ?
- io_lat->min[index] : val;
- io_lat->max[index] = (io_lat->max[index] > val) ?
- io_lat->max[index] : val;
- io_lat->avg[index] += val;
-}
-/**
+/*
* Called by itnim to clean up IO while going offline.
*/
void
@@ -2882,7 +2544,7 @@ bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim)
bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
}
-/**
+/*
* IOC failure handling.
*/
void
@@ -2893,7 +2555,7 @@ bfa_ioim_iocdisable(struct bfa_ioim_s *ioim)
bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL);
}
-/**
+/*
* IO offline TOV popped. Fail the pending IO.
*/
void
@@ -2904,12 +2566,7 @@ bfa_ioim_tov(struct bfa_ioim_s *ioim)
}
-
-/**
- * hal_ioim_api
- */
-
-/**
+/*
* Allocate IOIM resource for initiator mode I/O request.
*/
struct bfa_ioim_s *
@@ -2919,7 +2576,7 @@ bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
struct bfa_ioim_s *ioim;
- /**
+ /*
* alocate IOIM resource
*/
bfa_q_deq(&fcpim->ioim_free_q, &ioim);
@@ -2937,7 +2594,6 @@ bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
fcpim->ios_active++;
list_add_tail(&ioim->qe, &itnim->io_q);
- bfa_trc_fp(ioim->bfa, ioim->iotag);
return ioim;
}
@@ -2947,18 +2603,13 @@ bfa_ioim_free(struct bfa_ioim_s *ioim)
{
struct bfa_fcpim_mod_s *fcpim = ioim->fcpim;
- bfa_trc_fp(ioim->bfa, ioim->iotag);
- bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit));
-
- bfa_assert_fp(list_empty(&ioim->sgpg_q) ||
- (ioim->nsges > BFI_SGE_INLINE));
-
if (ioim->nsgpgs > 0)
bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs);
bfa_stats(ioim->itnim, io_comps);
fcpim->ios_active--;
+ ioim->iotag &= BFA_IOIM_IOTAG_MASK;
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
}
@@ -2966,21 +2617,18 @@ bfa_ioim_free(struct bfa_ioim_s *ioim)
void
bfa_ioim_start(struct bfa_ioim_s *ioim)
{
- bfa_trc_fp(ioim->bfa, ioim->iotag);
-
bfa_ioim_cb_profile_start(ioim->fcpim, ioim);
- /**
+ /*
* Obtain the queue over which this request has to be issued
*/
ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ?
- bfa_cb_ioim_get_reqq(ioim->dio) :
- bfa_itnim_get_reqq(ioim);
+ BFA_FALSE : bfa_itnim_get_reqq(ioim);
bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
}
-/**
+/*
* Driver I/O abort request.
*/
bfa_status_t
@@ -2998,13 +2646,12 @@ bfa_ioim_abort(struct bfa_ioim_s *ioim)
return BFA_STATUS_OK;
}
-
-/**
+/*
* BFA TSKIM state machine functions
*/
-/**
- * Task management command beginning state.
+/*
+ * Task management command beginning state.
*/
static void
bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
@@ -3016,7 +2663,7 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
bfa_sm_set_state(tskim, bfa_tskim_sm_active);
bfa_tskim_gather_ios(tskim);
- /**
+ /*
* If device is offline, do not send TM on wire. Just cleanup
* any pending IO requests and complete TM request.
*/
@@ -3040,10 +2687,9 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-/**
- * brief
- * TM command is active, awaiting completion from firmware to
- * cleanup IO requests in TM scope.
+/*
+ * TM command is active, awaiting completion from firmware to
+ * cleanup IO requests in TM scope.
*/
static void
bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
@@ -3077,9 +2723,9 @@ bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-/**
- * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
- * completion event from firmware.
+/*
+ * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
+ * completion event from firmware.
*/
static void
bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
@@ -3088,7 +2734,7 @@ bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
switch (event) {
case BFA_TSKIM_SM_DONE:
- /**
+ /*
* Ignore and wait for ABORT completion from firmware.
*/
break;
@@ -3121,7 +2767,7 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
break;
case BFA_TSKIM_SM_CLEANUP:
- /**
+ /*
* Ignore, TM command completed on wire.
* Notify TM conmpletion on IO cleanup completion.
*/
@@ -3138,8 +2784,8 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-/**
- * Task management command is waiting for room in request CQ
+/*
+ * Task management command is waiting for room in request CQ
*/
static void
bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
@@ -3153,7 +2799,7 @@ bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
break;
case BFA_TSKIM_SM_CLEANUP:
- /**
+ /*
* No need to send TM on wire since ITN is offline.
*/
bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
@@ -3173,9 +2819,9 @@ bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-/**
- * Task management command is active, awaiting for room in request CQ
- * to send clean up request.
+/*
+ * Task management command is active, awaiting for room in request CQ
+ * to send clean up request.
*/
static void
bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
@@ -3186,11 +2832,9 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
switch (event) {
case BFA_TSKIM_SM_DONE:
bfa_reqq_wcancel(&tskim->reqq_wait);
- /**
- *
+ /*
* Fall through !!!
*/
-
case BFA_TSKIM_SM_QRESUME:
bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
bfa_tskim_send_abort(tskim);
@@ -3208,8 +2852,8 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
}
}
-/**
- * BFA callback is pending
+/*
+ * BFA callback is pending
*/
static void
bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
@@ -3234,12 +2878,6 @@ bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
}
}
-
-
-/**
- * hal_tskim_private
- */
-
static void
__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete)
{
@@ -3269,8 +2907,8 @@ __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete)
BFI_TSKIM_STS_FAILED);
}
-static bfa_boolean_t
-bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
+static bfa_boolean_t
+bfa_tskim_match_scope(struct bfa_tskim_s *tskim, struct scsi_lun lun)
{
switch (tskim->tm_cmnd) {
case FCP_TM_TARGET_RESET:
@@ -3280,46 +2918,50 @@ bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
case FCP_TM_CLEAR_TASK_SET:
case FCP_TM_LUN_RESET:
case FCP_TM_CLEAR_ACA:
- return (tskim->lun == lun);
+ return !memcmp(&tskim->lun, &lun, sizeof(lun));
default:
- bfa_assert(0);
+ WARN_ON(1);
}
return BFA_FALSE;
}
-/**
- * Gather affected IO requests and task management commands.
+/*
+ * Gather affected IO requests and task management commands.
*/
static void
bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
{
struct bfa_itnim_s *itnim = tskim->itnim;
struct bfa_ioim_s *ioim;
- struct list_head *qe, *qen;
+ struct list_head *qe, *qen;
+ struct scsi_cmnd *cmnd;
+ struct scsi_lun scsilun;
INIT_LIST_HEAD(&tskim->io_q);
- /**
+ /*
* Gather any active IO requests first.
*/
list_for_each_safe(qe, qen, &itnim->io_q) {
ioim = (struct bfa_ioim_s *) qe;
- if (bfa_tskim_match_scope
- (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ cmnd = (struct scsi_cmnd *) ioim->dio;
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ if (bfa_tskim_match_scope(tskim, scsilun)) {
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &tskim->io_q);
}
}
- /**
+ /*
* Failback any pending IO requests immediately.
*/
list_for_each_safe(qe, qen, &itnim->pending_q) {
ioim = (struct bfa_ioim_s *) qe;
- if (bfa_tskim_match_scope
- (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ cmnd = (struct scsi_cmnd *) ioim->dio;
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ if (bfa_tskim_match_scope(tskim, scsilun)) {
list_del(&ioim->qe);
list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_ioim_tov(ioim);
@@ -3327,8 +2969,8 @@ bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
}
}
-/**
- * IO cleanup completion
+/*
+ * IO cleanup completion
*/
static void
bfa_tskim_cleanp_comp(void *tskim_cbarg)
@@ -3339,8 +2981,8 @@ bfa_tskim_cleanp_comp(void *tskim_cbarg)
bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE);
}
-/**
- * Gather affected IO requests and task management commands.
+/*
+ * Gather affected IO requests and task management commands.
*/
static void
bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
@@ -3359,8 +3001,8 @@ bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
bfa_wc_wait(&tskim->wc);
}
-/**
- * Send task management request to firmware.
+/*
+ * Send task management request to firmware.
*/
static bfa_boolean_t
bfa_tskim_send(struct bfa_tskim_s *tskim)
@@ -3368,34 +3010,34 @@ bfa_tskim_send(struct bfa_tskim_s *tskim)
struct bfa_itnim_s *itnim = tskim->itnim;
struct bfi_tskim_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(tskim->bfa, itnim->reqq);
if (!m)
return BFA_FALSE;
- /**
+ /*
* build i/o request message next
*/
bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ,
bfa_lpuid(tskim->bfa));
- m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+ m->tsk_tag = cpu_to_be16(tskim->tsk_tag);
m->itn_fhdl = tskim->itnim->rport->fw_handle;
m->t_secs = tskim->tsecs;
m->lun = tskim->lun;
m->tm_flags = tskim->tm_cmnd;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(tskim->bfa, itnim->reqq);
return BFA_TRUE;
}
-/**
- * Send abort request to cleanup an active TM to firmware.
+/*
+ * Send abort request to cleanup an active TM to firmware.
*/
static bfa_boolean_t
bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
@@ -3403,30 +3045,30 @@ bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
struct bfa_itnim_s *itnim = tskim->itnim;
struct bfi_tskim_abortreq_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(tskim->bfa, itnim->reqq);
if (!m)
return BFA_FALSE;
- /**
+ /*
* build i/o request message next
*/
bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ,
bfa_lpuid(tskim->bfa));
- m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+ m->tsk_tag = cpu_to_be16(tskim->tsk_tag);
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(tskim->bfa, itnim->reqq);
return BFA_TRUE;
}
-/**
- * Call to resume task management cmnd waiting for room in request queue.
+/*
+ * Call to resume task management cmnd waiting for room in request queue.
*/
static void
bfa_tskim_qresume(void *cbarg)
@@ -3437,7 +3079,7 @@ bfa_tskim_qresume(void *cbarg)
bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME);
}
-/**
+/*
* Cleanup IOs associated with a task mangement command on IOC failures.
*/
static void
@@ -3452,13 +3094,7 @@ bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim)
}
}
-
-
-/**
- * hal_tskim_friend
- */
-
-/**
+/*
* Notification on completions from related ioim.
*/
void
@@ -3467,7 +3103,7 @@ bfa_tskim_iodone(struct bfa_tskim_s *tskim)
bfa_wc_down(&tskim->wc);
}
-/**
+/*
* Handle IOC h/w failure notification from itnim.
*/
void
@@ -3478,7 +3114,7 @@ bfa_tskim_iocdisable(struct bfa_tskim_s *tskim)
bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL);
}
-/**
+/*
* Cleanup TM command and associated IOs as part of ITNIM offline.
*/
void
@@ -3489,8 +3125,8 @@ bfa_tskim_cleanup(struct bfa_tskim_s *tskim)
bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP);
}
-/**
- * Memory allocation and initialization.
+/*
+ * Memory allocation and initialization.
*/
void
bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
@@ -3507,7 +3143,7 @@ bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
/*
* initialize TSKIM
*/
- bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s));
+ memset(tskim, 0, sizeof(struct bfa_tskim_s));
tskim->tsk_tag = i;
tskim->bfa = fcpim->bfa;
tskim->fcpim = fcpim;
@@ -3523,27 +3159,19 @@ bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
}
void
-bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
-{
- /**
- * @todo
- */
-}
-
-void
bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m;
struct bfa_tskim_s *tskim;
- u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag);
+ u16 tsk_tag = be16_to_cpu(rsp->tsk_tag);
tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag);
- bfa_assert(tskim->tsk_tag == tsk_tag);
+ WARN_ON(tskim->tsk_tag != tsk_tag);
tskim->tsk_status = rsp->tsk_status;
- /**
+ /*
* Firmware sends BFI_TSKIM_STS_ABORTED status for abort
* requests. All other statuses are for normal completions.
*/
@@ -3557,12 +3185,6 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
}
-
-/**
- * hal_tskim_api
- */
-
-
struct bfa_tskim_s *
bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
{
@@ -3580,13 +3202,13 @@ bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
void
bfa_tskim_free(struct bfa_tskim_s *tskim)
{
- bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe));
+ WARN_ON(!bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe));
list_del(&tskim->qe);
list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q);
}
-/**
- * Start a task management command.
+/*
+ * Start a task management command.
*
* @param[in] tskim BFA task management command instance
* @param[in] itnim i-t nexus for the task management command
@@ -3597,7 +3219,8 @@ bfa_tskim_free(struct bfa_tskim_s *tskim)
* @return None.
*/
void
-bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun,
+bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim,
+ struct scsi_lun lun,
enum fcp_tm_cmnd tm_cmnd, u8 tsecs)
{
tskim->itnim = itnim;
diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h
index 3bf343160aac..1e38dade8423 100644
--- a/drivers/scsi/bfa/bfa_fcpim.h
+++ b/drivers/scsi/bfa/bfa_fcpim.h
@@ -41,7 +41,7 @@
(__itnim->ioprofile.iocomps[__index]++)
#define BFA_IOIM_RETRY_TAG_OFFSET 11
-#define BFA_IOIM_RETRY_TAG_MASK 0x07ff /* 2K IOs */
+#define BFA_IOIM_IOTAG_MASK 0x07ff /* 2K IOs */
#define BFA_IOIM_RETRY_MAX 7
/* Buckets are are 512 bytes to 2MB */
@@ -94,17 +94,17 @@ struct bfa_fcpim_mod_s {
struct list_head ioim_resfree_q; /* IOs waiting for f/w */
struct list_head ioim_comp_q; /* IO global comp Q */
struct list_head tskim_free_q;
- u32 ios_active; /* current active IOs */
- u32 delay_comp;
+ u32 ios_active; /* current active IOs */
+ u32 delay_comp;
struct bfa_fcpim_del_itn_stats_s del_itn_stats;
bfa_boolean_t ioredirect;
bfa_boolean_t io_profile;
- u32 io_profile_start_time;
+ u32 io_profile_start_time;
bfa_fcpim_profile_t profile_comp;
bfa_fcpim_profile_t profile_start;
};
-/**
+/*
* BFA IO (initiator mode)
*/
struct bfa_ioim_s {
@@ -114,64 +114,62 @@ struct bfa_ioim_s {
struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
struct bfad_ioim_s *dio; /* driver IO handle */
- u16 iotag; /* FWI IO tag */
- u16 abort_tag; /* unqiue abort request tag */
- u16 nsges; /* number of SG elements */
- u16 nsgpgs; /* number of SG pages */
+ u16 iotag; /* FWI IO tag */
+ u16 abort_tag; /* unqiue abort request tag */
+ u16 nsges; /* number of SG elements */
+ u16 nsgpgs; /* number of SG pages */
struct bfa_sgpg_s *sgpg; /* first SG page */
struct list_head sgpg_q; /* allocated SG pages */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
- struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
- u8 reqq; /* Request queue for I/O */
- u64 start_time; /* IO's Profile start val */
+ struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
+ u8 reqq; /* Request queue for I/O */
+ u64 start_time; /* IO's Profile start val */
};
-
struct bfa_ioim_sp_s {
struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */
u8 *snsinfo; /* sense info for this IO */
- struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
- struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
bfa_boolean_t abort_explicit; /* aborted by OS */
struct bfa_tskim_s *tskim; /* Relevant TM cmd */
};
-/**
+/*
* BFA Task management command (initiator mode)
*/
struct bfa_tskim_s {
struct list_head qe;
bfa_sm_t sm;
- struct bfa_s *bfa; /* BFA module */
+ struct bfa_s *bfa; /* BFA module */
struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
- struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
- bfa_boolean_t notify; /* notify itnim on TM comp */
- lun_t lun; /* lun if applicable */
- enum fcp_tm_cmnd tm_cmnd; /* task management command */
- u16 tsk_tag; /* FWI IO tag */
- u8 tsecs; /* timeout in seconds */
+ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
+ bfa_boolean_t notify; /* notify itnim on TM comp */
+ struct scsi_lun lun; /* lun if applicable */
+ enum fcp_tm_cmnd tm_cmnd; /* task management command */
+ u16 tsk_tag; /* FWI IO tag */
+ u8 tsecs; /* timeout in seconds */
struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
struct list_head io_q; /* queue of affected IOs */
- struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_wc_s wc; /* waiting counter */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
enum bfi_tskim_status tsk_status; /* TM status */
};
-
-/**
+/*
* BFA i-t-n (initiator mode)
*/
struct bfa_itnim_s {
- struct list_head qe; /* queue element */
- bfa_sm_t sm; /* i-t-n im BFA state machine */
- struct bfa_s *bfa; /* bfa instance */
- struct bfa_rport_s *rport; /* bfa rport */
- void *ditn; /* driver i-t-n structure */
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* i-t-n im BFA state machine */
+ struct bfa_s *bfa; /* bfa instance */
+ struct bfa_rport_s *rport; /* bfa rport */
+ void *ditn; /* driver i-t-n structure */
struct bfi_mhdr_s mhdr; /* pre-built mhdr */
- u8 msg_no; /* itnim/rport firmware handle */
- u8 reqq; /* CQ for requests */
+ u8 msg_no; /* itnim/rport firmware handle */
+ u8 reqq; /* CQ for requests */
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
struct list_head pending_q; /* queue of pending IO requests */
struct list_head io_q; /* queue of active IO requests */
@@ -181,19 +179,19 @@ struct bfa_itnim_s {
bfa_boolean_t seq_rec; /* SQER supported */
bfa_boolean_t is_online; /* itnim is ONLINE for IO */
bfa_boolean_t iotov_active; /* IO TOV timer is active */
- struct bfa_wc_s wc; /* waiting counter */
- struct bfa_timer_s timer; /* pending IO TOV */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_timer_s timer; /* pending IO TOV */
struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
struct bfa_itnim_iostats_s stats;
struct bfa_itnim_ioprofile_s ioprofile;
};
-
#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
+#define BFA_IOIM_TAG_2_ID(_iotag) ((_iotag) & BFA_IOIM_IOTAG_MASK)
#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
- (&fcpim->ioim_arr[(_iotag & BFA_IOIM_RETRY_TAG_MASK)])
+ (&fcpim->ioim_arr[(_iotag & BFA_IOIM_IOTAG_MASK)])
#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \
(&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)])
@@ -201,26 +199,26 @@ struct bfa_itnim_s {
(_bfa->modules.fcpim_mod.io_profile_start_time)
#define bfa_fcpim_get_io_profile(_bfa) \
(_bfa->modules.fcpim_mod.io_profile)
+#define bfa_ioim_update_iotag(__ioim) do { \
+ uint16_t k = (__ioim)->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; \
+ k++; (__ioim)->iotag &= BFA_IOIM_IOTAG_MASK; \
+ (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET; \
+} while (0)
static inline bfa_boolean_t
-bfa_ioim_get_iotag(struct bfa_ioim_s *ioim)
+bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim)
{
- u16 k = ioim->iotag;
-
- k >>= BFA_IOIM_RETRY_TAG_OFFSET; k++;
-
- if (k > BFA_IOIM_RETRY_MAX)
+ uint16_t k = ioim->iotag >> BFA_IOIM_RETRY_TAG_OFFSET;
+ if (k < BFA_IOIM_RETRY_MAX)
return BFA_FALSE;
- ioim->iotag &= BFA_IOIM_RETRY_TAG_MASK;
- ioim->iotag |= k<<BFA_IOIM_RETRY_TAG_OFFSET;
return BFA_TRUE;
}
+
/*
* function prototypes
*/
void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim,
struct bfa_meminfo_s *minfo);
-void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim);
void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
void bfa_ioim_good_comp_isr(struct bfa_s *bfa,
struct bfi_msg_s *msg);
@@ -232,7 +230,6 @@ void bfa_ioim_tov(struct bfa_ioim_s *ioim);
void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim,
struct bfa_meminfo_s *minfo);
-void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim);
void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
void bfa_tskim_iodone(struct bfa_tskim_s *tskim);
void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim);
@@ -248,32 +245,14 @@ void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
void bfa_itnim_iodone(struct bfa_itnim_s *itnim);
void bfa_itnim_tskdone(struct bfa_itnim_s *itnim);
bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim);
-void bfa_ioim_profile_comp(struct bfa_ioim_s *ioim);
-void bfa_ioim_profile_start(struct bfa_ioim_s *ioim);
-
/*
* bfa fcpim module API functions
*/
-void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa);
-void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth);
u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
-bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
- struct bfa_itnim_iostats_s *modstats);
-bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa,
- struct bfa_itnim_iostats_s *stats, u8 lp_tag);
-bfa_status_t bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa,
- struct bfa_fcpim_del_itn_stats_s *modstats);
-bfa_status_t bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag);
-void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats,
- struct bfa_itnim_iostats_s *itnim_stats);
-bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
-void bfa_fcpim_set_ioredirect(struct bfa_s *bfa,
- bfa_boolean_t state);
-void bfa_fcpim_update_ioredirect(struct bfa_s *bfa);
-bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time);
-bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa);
+
#define bfa_fcpim_ioredirect_enabled(__bfa) \
(((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect)
@@ -291,48 +270,33 @@ bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa);
* bfa itnim API functions
*/
struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa,
- struct bfa_rport_s *rport, void *itnim);
-void bfa_itnim_delete(struct bfa_itnim_s *itnim);
-void bfa_itnim_online(struct bfa_itnim_s *itnim,
- bfa_boolean_t seq_rec);
-void bfa_itnim_offline(struct bfa_itnim_s *itnim);
-void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
- struct bfa_itnim_iostats_s *stats);
-void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
-bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
- struct bfa_itnim_ioprofile_s *ioprofile);
+ struct bfa_rport_s *rport, void *itnim);
+void bfa_itnim_delete(struct bfa_itnim_s *itnim);
+void bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec);
+void bfa_itnim_offline(struct bfa_itnim_s *itnim);
+void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
+bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_ioprofile_s *ioprofile);
+
#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq)
-/**
- * BFA completion callback for bfa_itnim_online().
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
+/*
+ * BFA completion callback for bfa_itnim_online().
*/
void bfa_cb_itnim_online(void *itnim);
-/**
- * BFA completion callback for bfa_itnim_offline().
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
+/*
+ * BFA completion callback for bfa_itnim_offline().
*/
void bfa_cb_itnim_offline(void *itnim);
void bfa_cb_itnim_tov_begin(void *itnim);
void bfa_cb_itnim_tov(void *itnim);
-/**
- * BFA notification to FCS/driver for second level error recovery.
- *
+/*
+ * BFA notification to FCS/driver for second level error recovery.
* Atleast one I/O request has timedout and target is unresponsive to
* repeated abort requests. Second level error recovery should be initiated
* by starting implicit logout and recovery procedures.
- *
- * @param[in] itnim FCS or driver itnim instance
- *
- * return None
*/
void bfa_cb_itnim_sler(void *itnim);
@@ -349,10 +313,8 @@ void bfa_ioim_start(struct bfa_ioim_s *ioim);
bfa_status_t bfa_ioim_abort(struct bfa_ioim_s *ioim);
void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
bfa_boolean_t iotov);
-
-
-/**
- * I/O completion notification.
+/*
+ * I/O completion notification.
*
* @param[in] dio driver IO structure
* @param[in] io_status IO completion status
@@ -363,39 +325,31 @@ void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
*
* @return None
*/
-void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
- enum bfi_ioim_status io_status,
- u8 scsi_status, int sns_len,
- u8 *sns_info, s32 residue);
+void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status,
+ u8 scsi_status, int sns_len,
+ u8 *sns_info, s32 residue);
-/**
- * I/O good completion notification.
- *
- * @param[in] dio driver IO structure
- *
- * @return None
+/*
+ * I/O good completion notification.
*/
-void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
-/**
- * I/O abort completion notification
- *
- * @param[in] dio driver IO that was aborted
- *
- * @return None
+/*
+ * I/O abort completion notification
*/
-void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
/*
* bfa tskim API functions
*/
-struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
- struct bfad_tskim_s *dtsk);
-void bfa_tskim_free(struct bfa_tskim_s *tskim);
-void bfa_tskim_start(struct bfa_tskim_s *tskim,
- struct bfa_itnim_s *itnim, lun_t lun,
- enum fcp_tm_cmnd tm, u8 t_secs);
-void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
- enum bfi_tskim_status tsk_status);
+struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
+ struct bfad_tskim_s *dtsk);
+void bfa_tskim_free(struct bfa_tskim_s *tskim);
+void bfa_tskim_start(struct bfa_tskim_s *tskim,
+ struct bfa_itnim_s *itnim, struct scsi_lun lun,
+ enum fcp_tm_cmnd tm, u8 t_secs);
+void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status);
#endif /* __BFA_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 9cebbe30a678..f674f9318629 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -15,17 +15,17 @@
* General Public License for more details.
*/
-/**
+/*
* bfa_fcs.c BFA FCS main
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, FCS);
-/**
+/*
* FCS sub-modules
*/
struct bfa_fcs_mod_s {
@@ -43,7 +43,7 @@ static struct bfa_fcs_mod_s fcs_modules[] = {
bfa_fcs_fabric_modexit },
};
-/**
+/*
* fcs_api BFA FCS API
*/
@@ -58,11 +58,11 @@ bfa_fcs_exit_comp(void *fcs_cbarg)
-/**
+/*
* fcs_api BFA FCS API
*/
-/**
+/*
* fcs attach -- called once to initialize data structures at driver attach time
*/
void
@@ -76,7 +76,7 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
fcs->bfad = bfad;
fcs->min_cfg = min_cfg;
- bfa_attach_fcs(bfa);
+ bfa->fcs = BFA_TRUE;
fcbuild_init();
for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
@@ -86,7 +86,7 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
}
}
-/**
+/*
* fcs initialization, called once after bfa initialization is complete
*/
void
@@ -110,16 +110,8 @@ bfa_fcs_init(struct bfa_fcs_s *fcs)
}
}
-/**
- * Start FCS operations.
- */
-void
-bfa_fcs_start(struct bfa_fcs_s *fcs)
-{
- bfa_fcs_fabric_modstart(fcs);
-}
-/**
+/*
* brief
* FCS driver details initialization.
*
@@ -138,23 +130,7 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
bfa_fcs_fabric_psymb_init(&fcs->fabric);
}
-/**
- * brief
- * FCS FDMI Driver Parameter Initialization
- *
- * param[in] fcs FCS instance
- * param[in] fdmi_enable TRUE/FALSE
- *
- * return None
- */
-void
-bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable)
-{
-
- fcs->fdmi_enabled = fdmi_enable;
-
-}
-/**
+/*
* brief
* FCS instance cleanup and exit.
*
@@ -184,19 +160,7 @@ bfa_fcs_exit(struct bfa_fcs_s *fcs)
}
-void
-bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod)
-{
- fcs->trcmod = trcmod;
-}
-
-void
-bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs)
-{
- bfa_wc_down(&fcs->wc);
-}
-
-/**
+/*
* Fabric module implementation.
*/
@@ -232,31 +196,6 @@ static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
u32 rsp_len,
u32 resid_len,
struct fchs_s *rspfchs);
-/**
- * fcs_fabric_sm fabric state machine functions
- */
-
-/**
- * Fabric state machine events
- */
-enum bfa_fcs_fabric_event {
- BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */
- BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */
- BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
- BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
- BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */
- BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */
- BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */
- BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */
- BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */
- BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */
- BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
- BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */
- BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */
- BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
- BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
- BFA_FCS_FABRIC_SM_START = 16, /* from driver */
-};
static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
@@ -270,14 +209,8 @@ static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
-static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
- enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
@@ -286,7 +219,7 @@ static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event);
-/**
+/*
* Beginning state before fabric creation.
*/
static void
@@ -312,7 +245,7 @@ bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Beginning state before fabric creation.
*/
static void
@@ -337,7 +270,7 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_DELETE:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
- bfa_fcs_modexit_comp(fabric->fcs);
+ bfa_wc_down(&fabric->fcs->wc);
break;
default:
@@ -345,7 +278,7 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Link is down, awaiting LINK UP event from port. This is also the
* first state at fabric creation.
*/
@@ -375,7 +308,7 @@ bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* FLOGI is in progress, awaiting FLOGI reply.
*/
static void
@@ -410,7 +343,7 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_LOOPBACK:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_set_opertype(fabric);
break;
@@ -424,12 +357,12 @@ bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_DELETE:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_delete(fabric);
break;
@@ -468,7 +401,7 @@ bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Authentication is in progress, awaiting authentication results.
*/
static void
@@ -481,7 +414,7 @@ bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
switch (event) {
case BFA_FCS_FABRIC_SM_AUTH_FAILED:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
@@ -495,7 +428,7 @@ bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_DELETE:
@@ -508,10 +441,10 @@ bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Authentication failed
*/
-static void
+void
bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
@@ -534,10 +467,10 @@ bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Port is in loopback mode.
*/
-static void
+void
bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
@@ -560,7 +493,7 @@ bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* There is no attached fabric - private loop or NPort-to-NPort topology.
*/
static void
@@ -573,7 +506,7 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
switch (event) {
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_notify_offline(fabric);
break;
@@ -593,10 +526,10 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Fabric is online - normal operating state.
*/
-static void
+void
bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
enum bfa_fcs_fabric_event event)
{
@@ -606,7 +539,7 @@ bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
switch (event) {
case BFA_FCS_FABRIC_SM_LINK_DOWN:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_fabric_notify_offline(fabric);
break;
@@ -617,7 +550,7 @@ bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
case BFA_FCS_FABRIC_SM_AUTH_FAILED:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
- bfa_lps_discard(fabric->lps);
+ bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
@@ -628,7 +561,7 @@ bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* Exchanging virtual fabric parameters.
*/
static void
@@ -652,7 +585,7 @@ bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
}
}
-/**
+/*
* EVFP exchange complete and VFT tagging is enabled.
*/
static void
@@ -663,7 +596,7 @@ bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
bfa_trc(fabric->fcs, event);
}
-/**
+/*
* Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
*/
static void
@@ -677,14 +610,14 @@ bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
bfa_trc(fabric->fcs, event);
wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Port is isolated due to VF_ID mismatch. "
"PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.",
pwwn_ptr, fabric->fcs->port_vfid,
fabric->event_arg.swp_vfid);
}
-/**
+/*
* Fabric is being deleted, awaiting vport delete completions.
*/
static void
@@ -697,7 +630,7 @@ bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
switch (event) {
case BFA_FCS_FABRIC_SM_DELCOMP:
bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
- bfa_fcs_modexit_comp(fabric->fcs);
+ bfa_wc_down(&fabric->fcs->wc);
break;
case BFA_FCS_FABRIC_SM_LINK_UP:
@@ -714,7 +647,7 @@ bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
-/**
+/*
* fcs_fabric_private fabric private functions
*/
@@ -724,11 +657,11 @@ bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
port_cfg->roles = BFA_LPORT_ROLE_FCP_IM;
- port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc);
- port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc);
+ port_cfg->nwwn = fabric->fcs->bfa->ioc.attr->nwwn;
+ port_cfg->pwwn = fabric->fcs->bfa->ioc.attr->pwwn;
}
-/**
+/*
* Port Symbolic Name Creation for base port.
*/
void
@@ -789,7 +722,7 @@ bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
}
-/**
+/*
* bfa lps login completion callback
*/
void
@@ -813,7 +746,7 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
return;
case BFA_STATUS_EPROTOCOL:
- switch (bfa_lps_get_extstatus(fabric->lps)) {
+ switch (fabric->lps->ext_status) {
case BFA_EPROTO_BAD_ACCEPT:
fabric->stats.flogi_acc_err++;
break;
@@ -840,26 +773,26 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
return;
}
- fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps);
+ fabric->bb_credit = fabric->lps->pr_bbcred;
bfa_trc(fabric->fcs, fabric->bb_credit);
- if (!bfa_lps_is_brcd_fabric(fabric->lps))
- fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps);
+ if (!(fabric->lps->brcd_switch))
+ fabric->fabric_name = fabric->lps->pr_nwwn;
/*
* Check port type. It should be 1 = F-port.
*/
- if (bfa_lps_is_fport(fabric->lps)) {
- fabric->bport.pid = bfa_lps_get_pid(fabric->lps);
- fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps);
- fabric->is_auth = bfa_lps_is_authreq(fabric->lps);
+ if (fabric->lps->fport) {
+ fabric->bport.pid = fabric->lps->lp_pid;
+ fabric->is_npiv = fabric->lps->npiv_en;
+ fabric->is_auth = fabric->lps->auth_req;
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
} else {
/*
* Nport-2-Nport direct attached
*/
fabric->bport.port_topo.pn2n.rem_port_wwn =
- bfa_lps_get_peer_pwwn(fabric->lps);
+ fabric->lps->pr_pwwn;
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
}
@@ -867,7 +800,7 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
bfa_trc(fabric->fcs, fabric->is_npiv);
bfa_trc(fabric->fcs, fabric->is_auth);
}
-/**
+/*
* Allocate and send FLOGI.
*/
static void
@@ -897,7 +830,7 @@ bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
bfa_fcs_fabric_set_opertype(fabric);
fabric->stats.fabric_onlines++;
- /**
+ /*
* notify online event to base and then virtual ports
*/
bfa_fcs_lport_online(&fabric->bport);
@@ -917,7 +850,7 @@ bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
bfa_trc(fabric->fcs, fabric->fabric_name);
fabric->stats.fabric_offlines++;
- /**
+ /*
* notify offline event first to vports and then base port.
*/
list_for_each_safe(qe, qen, &fabric->vport_q) {
@@ -939,7 +872,7 @@ bfa_fcs_fabric_delay(void *cbarg)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
}
-/**
+/*
* Delete all vports and wait for vport delete completions.
*/
static void
@@ -965,11 +898,11 @@ bfa_fcs_fabric_delete_comp(void *cbarg)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
}
-/**
+/*
* fcs_fabric_public fabric public functions
*/
-/**
+/*
* Attach time initialization.
*/
void
@@ -978,18 +911,18 @@ bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
struct bfa_fcs_fabric_s *fabric;
fabric = &fcs->fabric;
- bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
+ memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
- /**
+ /*
* Initialize base fabric.
*/
fabric->fcs = fcs;
INIT_LIST_HEAD(&fabric->vport_q);
INIT_LIST_HEAD(&fabric->vf_q);
fabric->lps = bfa_lps_alloc(fcs->bfa);
- bfa_assert(fabric->lps);
+ WARN_ON(!fabric->lps);
- /**
+ /*
* Initialize fabric delete completion handler. Fabric deletion is
* complete when the last vport delete is complete.
*/
@@ -1007,7 +940,7 @@ bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
bfa_trc(fcs, 0);
}
-/**
+/*
* Module cleanup
*/
void
@@ -1017,7 +950,7 @@ bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
bfa_trc(fcs, 0);
- /**
+ /*
* Cleanup base fabric.
*/
fabric = &fcs->fabric;
@@ -1025,7 +958,7 @@ bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
}
-/**
+/*
* Fabric module start -- kick starts FCS actions
*/
void
@@ -1038,33 +971,8 @@ bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
}
-/**
- * Suspend fabric activity as part of driver suspend.
- */
-void
-bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs)
-{
-}
-
-bfa_boolean_t
-bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback);
-}
-
-bfa_boolean_t
-bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_auth_failed);
-}
-enum bfa_port_type
-bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
-{
- return fabric->oper_type;
-}
-
-/**
+/*
* Link up notification from BFA physical port module.
*/
void
@@ -1074,7 +982,7 @@ bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
}
-/**
+/*
* Link down notification from BFA physical port module.
*/
void
@@ -1084,7 +992,7 @@ bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
}
-/**
+/*
* A child vport is being created in the fabric.
*
* Call from vport module at vport creation. A list of base port and vports
@@ -1099,7 +1007,7 @@ void
bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
struct bfa_fcs_vport_s *vport)
{
- /**
+ /*
* - add vport to fabric's vport_q
*/
bfa_trc(fabric->fcs, fabric->vf_id);
@@ -1109,7 +1017,7 @@ bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
bfa_wc_up(&fabric->wc);
}
-/**
+/*
* A child vport is being deleted from fabric.
*
* Vport is being deleted.
@@ -1123,42 +1031,8 @@ bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
bfa_wc_down(&fabric->wc);
}
-/**
- * Base port is deleted.
- */
-void
-bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
-{
- bfa_wc_down(&fabric->wc);
-}
-
-
-/**
- * Check if fabric is online.
- *
- * param[in] fabric - Fabric instance. This can be a base fabric or vf.
- *
- * @return TRUE/FALSE
- */
-int
-bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
-{
- return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
-}
-
-/**
- * brief
- *
- */
-bfa_status_t
-bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs,
- struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
-{
- bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit);
- return BFA_STATUS_OK;
-}
-/**
+/*
* Lookup for a vport withing a fabric given its pwwn
*/
struct bfa_fcs_vport_s *
@@ -1176,18 +1050,6 @@ bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
return NULL;
}
-/**
- * In a given fabric, return the number of lports.
- *
- * param[in] fabric - Fabric instance. This can be a base fabric or vf.
- *
- * @return : 1 or more.
- */
-u16
-bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
-{
- return fabric->num_vports;
-}
/*
* Get OUI of the attached switch.
@@ -1207,14 +1069,14 @@ bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
u8 *tmp;
u16 oui;
- fab_nwwn = bfa_lps_get_peer_nwwn(fabric->lps);
+ fab_nwwn = fabric->lps->pr_nwwn;
tmp = (u8 *)&fab_nwwn;
oui = (tmp[3] << 8) | tmp[4];
return oui;
}
-/**
+/*
* Unsolicited frame receive handling.
*/
void
@@ -1230,29 +1092,29 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
bfa_trc(fabric->fcs, len);
bfa_trc(fabric->fcs, pid);
- /**
+ /*
* Look for our own FLOGI frames being looped back. This means an
* external loopback cable is in place. Our own FLOGI frames are
* sometimes looped back when switch port gets temporarily bypassed.
*/
- if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT)) &&
+ if ((pid == bfa_ntoh3b(FC_FABRIC_PORT)) &&
(els_cmd->els_code == FC_ELS_FLOGI) &&
(flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) {
bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
return;
}
- /**
+ /*
* FLOGI/EVFP exchanges should be consumed by base fabric.
*/
- if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) {
+ if (fchs->d_id == bfa_hton3b(FC_FABRIC_PORT)) {
bfa_trc(fabric->fcs, pid);
bfa_fcs_fabric_process_uf(fabric, fchs, len);
return;
}
if (fabric->bport.pid == pid) {
- /**
+ /*
* All authentication frames should be routed to auth
*/
bfa_trc(fabric->fcs, els_cmd->els_code);
@@ -1266,7 +1128,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
return;
}
- /**
+ /*
* look for a matching local port ID
*/
list_for_each(qe, &fabric->vport_q) {
@@ -1280,7 +1142,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
}
-/**
+/*
* Unsolicited frames to be processed by fabric.
*/
static void
@@ -1304,7 +1166,7 @@ bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
}
}
-/**
+/*
* Process incoming FLOGI
*/
static void
@@ -1329,7 +1191,7 @@ bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
return;
}
- fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred);
+ fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred);
bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
@@ -1351,26 +1213,26 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
struct fchs_s fchs;
fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
- /**
+ /*
* Do not expect this failure -- expect remote node to retry
*/
if (!fcxp)
return;
reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_FABRIC_PORT),
+ bfa_hton3b(FC_FABRIC_PORT),
n2n_port->reply_oxid, pcfg->pwwn,
pcfg->nwwn,
bfa_fcport_get_maxfrsize(bfa),
bfa_fcport_get_rx_bbcredit(bfa));
- bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps),
+ bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->lp_tag,
BFA_FALSE, FC_CLASS_3,
reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric,
FC_MAX_PDUSZ, 0);
}
-/**
+/*
* Flogi Acc completion callback.
*/
static void
@@ -1411,136 +1273,13 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport));
wwn2str(fwwn_ptr,
bfa_fcs_lport_get_fabric_name(&fabric->bport));
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Base port WWN = %s Fabric WWN = %s\n",
pwwn_ptr, fwwn_ptr);
}
}
-/**
- * fcs_vf_api virtual fabrics API
- */
-
-/**
- * Enable VF mode.
- *
- * @param[in] fcs fcs module instance
- * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL
- * to use standard default vf_id of 1.
- *
- * @retval BFA_STATUS_OK vf mode is enabled
- * @retval BFA_STATUS_BUSY Port is active. Port must be disabled
- * before VF mode can be enabled.
- */
-bfa_status_t
-bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id)
-{
- return BFA_STATUS_OK;
-}
-
-/**
- * Disable VF mode.
- *
- * @param[in] fcs fcs module instance
- *
- * @retval BFA_STATUS_OK vf mode is disabled
- * @retval BFA_STATUS_BUSY VFs are present and being used. All
- * VFs must be deleted before disabling
- * VF mode.
- */
-bfa_status_t
-bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs)
-{
- return BFA_STATUS_OK;
-}
-
-/**
- * Create a new VF instance.
- *
- * A new VF is created using the given VF configuration. A VF is identified
- * by VF id. No duplicate VF creation is allowed with the same VF id. Once
- * a VF is created, VF is automatically started after link initialization
- * and EVFP exchange is completed.
- *
- * param[in] vf - FCS vf data structure. Memory is
- * allocated by caller (driver)
- * param[in] fcs - FCS module
- * param[in] vf_cfg - VF configuration
- * param[in] vf_drv - Opaque handle back to the driver's
- * virtual vf structure
- *
- * retval BFA_STATUS_OK VF creation is successful
- * retval BFA_STATUS_FAILED VF creation failed
- * retval BFA_STATUS_EEXIST A VF exists with the given vf_id
- */
-bfa_status_t
-bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id,
- struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
-{
- bfa_trc(fcs, vf_id);
- return BFA_STATUS_OK;
-}
-
-/**
- * Use this function to delete a BFA VF object. VF object should
- * be stopped before this function call.
- *
- * param[in] vf - pointer to bfa_vf_t.
- *
- * retval BFA_STATUS_OK On vf deletion success
- * retval BFA_STATUS_BUSY VF is not in a stopped state
- * retval BFA_STATUS_INPROGRESS VF deletion in in progress
- */
-bfa_status_t
-bfa_fcs_vf_delete(bfa_fcs_vf_t *vf)
-{
- bfa_trc(vf->fcs, vf->vf_id);
- return BFA_STATUS_OK;
-}
-
-
-/**
- * Returns attributes of the given VF.
- *
- * param[in] vf pointer to bfa_vf_t.
- * param[out] vf_attr vf attributes returned
- *
- * return None
- */
-void
-bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr)
-{
- bfa_trc(vf->fcs, vf->vf_id);
-}
-
-/**
- * Return statistics associated with the given vf.
- *
- * param[in] vf pointer to bfa_vf_t.
- * param[out] vf_stats vf statistics returned
- *
- * @return None
- */
-void
-bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats)
-{
- bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s));
-}
-
-/**
- * clear statistics associated with the given vf.
- *
- * param[in] vf pointer to bfa_vf_t.
- *
- * @return None
- */
-void
-bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf)
-{
- bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s));
-}
-
-/**
+/*
* Returns FCS vf structure for a given vf_id.
*
* param[in] vf_id - VF_ID
@@ -1558,81 +1297,7 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
return NULL;
}
-/**
- * Return the list of VFs configured.
- *
- * param[in] fcs fcs module instance
- * param[out] vf_ids returned list of vf_ids
- * param[in,out] nvfs in:size of vf_ids array,
- * out:total elements present,
- * actual elements returned is limited by the size
- *
- * return Driver VF structure
- */
-void
-bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
-{
- bfa_trc(fcs, *nvfs);
-}
-
-/**
- * Return the list of all VFs visible from fabric.
- *
- * param[in] fcs fcs module instance
- * param[out] vf_ids returned list of vf_ids
- * param[in,out] nvfs in:size of vf_ids array,
- * out:total elements present,
- * actual elements returned is limited by the size
- *
- * return Driver VF structure
- */
-void
-bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
-{
- bfa_trc(fcs, *nvfs);
-}
-
-/**
- * Return the list of local logical ports present in the given VF.
- *
- * param[in] vf vf for which logical ports are returned
- * param[out] lpwwn returned logical port wwn list
- * param[in,out] nlports in:size of lpwwn list;
- * out:total elements present,
- * actual elements returned is limited by the size
- */
-void
-bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
-{
- struct list_head *qe;
- struct bfa_fcs_vport_s *vport;
- int i;
- struct bfa_fcs_s *fcs;
-
- if (vf == NULL || lpwwn == NULL || *nlports == 0)
- return;
-
- fcs = vf->fcs;
-
- bfa_trc(fcs, vf->vf_id);
- bfa_trc(fcs, (u32) *nlports);
-
- i = 0;
- lpwwn[i++] = vf->bport.port_cfg.pwwn;
-
- list_for_each(qe, &vf->vport_q) {
- if (i >= *nlports)
- break;
-
- vport = (struct bfa_fcs_vport_s *) qe;
- lpwwn[i++] = vport->lport.port_cfg.pwwn;
- }
-
- bfa_trc(fcs, i);
- *nlports = i;
-}
-
-/**
+/*
* BFA FCS PPORT ( physical port)
*/
static void
@@ -1652,7 +1317,7 @@ bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event)
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
}
@@ -1662,11 +1327,11 @@ bfa_fcs_port_attach(struct bfa_fcs_s *fcs)
bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
}
-/**
+/*
* BFA FCS UF ( Unsolicited Frames)
*/
-/**
+/*
* BFA callback for unsolicited frame receive handler.
*
* @param[in] cbarg callback arg for receive handler
@@ -1683,7 +1348,7 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
struct fc_vft_s *vft;
struct bfa_fcs_fabric_s *fabric;
- /**
+ /*
* check for VFT header
*/
if (fchs->routing == FC_RTG_EXT_HDR &&
@@ -1695,17 +1360,17 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
else
fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
- /**
+ /*
* drop frame if vfid is unknown
*/
if (!fabric) {
- bfa_assert(0);
+ WARN_ON(1);
bfa_stats(fcs, uf.vfid_unknown);
bfa_uf_free(uf);
return;
}
- /**
+ /*
* skip vft header
*/
fchs = (struct fchs_s *) (vft + 1);
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index d75045df1e7e..0fd63168573f 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -27,6 +27,22 @@
#define BFA_FCS_OS_STR_LEN 64
/*
+ * lps_pvt BFA LPS private functions
+ */
+
+enum bfa_lps_event {
+ BFA_LPS_SM_LOGIN = 1, /* login request from user */
+ BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
+ BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
+ BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
+ BFA_LPS_SM_DELETE = 5, /* lps delete from user */
+ BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
+ BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */
+ BFA_LPS_SM_SET_N2N_PID = 8, /* Set assigned PID for n2n */
+};
+
+
+/*
* !!! Only append to the enums defined here to avoid any versioning
* !!! needed between trace utility and driver version
*/
@@ -41,13 +57,12 @@ enum {
struct bfa_fcs_s;
#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg)
-void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
#define BFA_FCS_BRCD_SWITCH_OUI 0x051e
#define N2N_LOCAL_PID 0x010000
#define N2N_REMOTE_PID 0x020000
#define BFA_FCS_RETRY_TIMEOUT 2000
-#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
+#define BFA_FCS_PID_IS_WKA(pid) ((bfa_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
@@ -109,7 +124,7 @@ struct bfa_fcs_lport_loop_s {
struct bfa_fcs_lport_n2n_s {
u32 rsvd;
- u16 reply_oxid; /* ox_id from the req flogi to be
+ __be16 reply_oxid; /* ox_id from the req flogi to be
*used in flogi acc */
wwn_t rem_port_wwn; /* Attached port's wwn */
};
@@ -196,7 +211,7 @@ struct bfa_fcs_fabric_s {
#define bfa_fcs_fabric_is_switched(__f) \
((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
-/**
+/*
* The design calls for a single implementation of base fabric and vf.
*/
#define bfa_fcs_vf_t struct bfa_fcs_fabric_s
@@ -216,7 +231,7 @@ struct bfa_fcs_fabric_s;
#define bfa_fcs_lport_t struct bfa_fcs_lport_s
-/**
+/*
* Symbolic Name related defines
* Total bytes 255.
* Physical Port's symbolic name 128 bytes.
@@ -239,7 +254,7 @@ struct bfa_fcs_fabric_s;
#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48
#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16
-/**
+/*
* Get FC port ID for a logical port.
*/
#define bfa_fcs_lport_get_fcid(_lport) ((_lport)->pid)
@@ -262,7 +277,7 @@ bfa_fcs_lport_get_drvport(struct bfa_fcs_lport_s *port)
#define bfa_fcs_lport_get_fabric_ipaddr(_lport) \
((_lport)->fabric->fabric_ip_addr)
-/**
+/*
* bfa fcs port public functions
*/
@@ -316,8 +331,6 @@ void bfa_fcs_lport_add_rport(struct bfa_fcs_lport_s *port,
struct bfa_fcs_rport_s *rport);
void bfa_fcs_lport_del_rport(struct bfa_fcs_lport_s *port,
struct bfa_fcs_rport_s *rport);
-void bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs);
void bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *vport);
void bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *vport);
void bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *vport);
@@ -342,7 +355,7 @@ struct bfa_fcs_vport_s {
#define bfa_fcs_vport_get_port(vport) \
((struct bfa_fcs_lport_s *)(&vport->port))
-/**
+/*
* bfa fcs vport public functions
*/
bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport,
@@ -359,9 +372,6 @@ bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport);
bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
struct bfa_vport_attr_s *vport_attr);
-void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
- struct bfa_vport_stats_s *vport_stats);
-void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport);
struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs,
u16 vf_id, wwn_t vpwwn);
void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
@@ -393,7 +403,7 @@ struct bfa_fcs_rpf_s {
enum bfa_port_speed rpsc_speed;
/* Current Speed from RPSC. O if RPSC fails */
enum bfa_port_speed assigned_speed;
- /**
+ /*
* Speed assigned by the user. will be used if RPSC is
* not supported by the rport.
*/
@@ -406,7 +416,7 @@ struct bfa_fcs_rport_s {
struct bfad_rport_s *rp_drv; /* driver peer instance */
u32 pid; /* port ID of rport */
u16 maxfrsize; /* maximum frame size */
- u16 reply_oxid; /* OX_ID of inbound requests */
+ __be16 reply_oxid; /* OX_ID of inbound requests */
enum fc_cos fc_cos; /* FC classes of service supp */
bfa_boolean_t cisc; /* CISC capable device */
bfa_boolean_t prlo; /* processing prlo or LOGO */
@@ -434,35 +444,21 @@ bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport)
return rport->bfa_rport;
}
-/**
+/*
* bfa fcs rport API functions
*/
-bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
- struct bfa_fcs_rport_s *rport,
- struct bfad_rport_s *rport_drv);
-bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_attr_s *attr);
-void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_stats_s *stats);
-void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport);
struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port,
wwn_t rpwwn);
struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn(
struct bfa_fcs_lport_s *port, wwn_t rnwwn);
void bfa_fcs_rport_set_del_timeout(u8 rport_tmo);
-void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
- enum bfa_port_speed speed);
void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport,
struct fchs_s *fchs, u16 len);
void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_lport_s *port,
u32 pid);
-void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
struct fc_logi_s *plogi_rsp);
void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port,
@@ -470,10 +466,8 @@ void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port,
struct fc_logi_s *plogi);
void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
struct fc_logi_s *plogi);
-void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
-void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id);
+void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id);
-void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport);
int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport);
@@ -573,7 +567,7 @@ bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim)
return itnim->bfa_itnim;
}
-/**
+/*
* bfa fcs FCP Initiator mode API functions
*/
void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim,
@@ -618,7 +612,7 @@ struct bfa_fcs_fdmi_hba_attr_s {
u8 option_rom_ver[BFA_VERSION_LEN];
u8 fw_version[8];
u8 os_name[256];
- u32 max_ct_pyld;
+ __be32 max_ct_pyld;
};
/*
@@ -626,9 +620,9 @@ struct bfa_fcs_fdmi_hba_attr_s {
*/
struct bfa_fcs_fdmi_port_attr_s {
u8 supp_fc4_types[32]; /* supported FC4 types */
- u32 supp_speed; /* supported speed */
- u32 curr_speed; /* current Speed */
- u32 max_frm_size; /* max frame size */
+ __be32 supp_speed; /* supported speed */
+ __be32 curr_speed; /* current Speed */
+ __be32 max_frm_size; /* max frame size */
u8 os_device_name[256]; /* OS device Name */
u8 host_name[256]; /* host name */
};
@@ -664,6 +658,57 @@ struct bfa_fcs_s {
};
/*
+ * fcs_fabric_sm fabric state machine functions
+ */
+
+/*
+ * Fabric state machine events
+ */
+enum bfa_fcs_fabric_event {
+ BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */
+ BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */
+ BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
+ BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
+ BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */
+ BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */
+ BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */
+ BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */
+ BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */
+ BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */
+ BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
+ BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */
+ BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */
+ BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
+ BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
+ BFA_FCS_FABRIC_SM_START = 16, /* from driver */
+};
+
+/*
+ * fcs_rport_sm FCS rport state machine events
+ */
+
+enum rport_event {
+ RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
+ RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
+ RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
+ RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
+ RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
+ RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
+ RPSM_EVENT_DELETE = 7, /* RPORT delete request */
+ RPSM_EVENT_SCN = 8, /* state change notification */
+ RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */
+ RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
+ RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
+ RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
+ RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
+ RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
+ RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
+ RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */
+ RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */
+ RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */
+};
+
+/*
* bfa fcs API functions
*/
void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa,
@@ -672,29 +717,12 @@ void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa,
void bfa_fcs_init(struct bfa_fcs_s *fcs);
void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
struct bfa_fcs_driver_info_s *driver_info);
-void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable);
void bfa_fcs_exit(struct bfa_fcs_s *fcs);
-void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
-void bfa_fcs_start(struct bfa_fcs_s *fcs);
-/**
+/*
* bfa fcs vf public functions
*/
-bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id);
-bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs);
-bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs,
- u16 vf_id, struct bfa_lport_cfg_s *port_cfg,
- struct bfad_vf_s *vf_drv);
-bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf);
-void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
-void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
-void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr);
-void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf,
- struct bfa_vf_stats_s *vf_stats);
-void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf);
-void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports);
bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id);
-u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
/*
* fabric protected interface functions
@@ -702,38 +730,35 @@ u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
-void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
struct bfa_fcs_vport_s *vport);
void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
struct bfa_fcs_vport_s *vport);
-int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric);
struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup(
struct bfa_fcs_fabric_s *fabric, wwn_t pwwn);
void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs);
void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric,
struct fchs_s *fchs, u16 len);
-bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric);
-bfa_boolean_t bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric);
-enum bfa_port_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric);
-void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric);
-bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf,
- struct bfa_fcs_s *fcs, struct bfa_lport_cfg_s *port_cfg,
- struct bfad_vf_s *vf_drv);
void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
wwn_t fabric_name);
u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
void bfa_fcs_port_attach(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
-/**
+/*
* BFA FCS callback interfaces
*/
-/**
+/*
* fcb Main fcs callbacks
*/
@@ -742,7 +767,7 @@ struct bfad_vf_s;
struct bfad_vport_s;
struct bfad_rport_s;
-/**
+/*
* lport callbacks
*/
struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad,
@@ -754,19 +779,19 @@ void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
struct bfad_vf_s *vf_drv,
struct bfad_vport_s *vp_drv);
-/**
+/*
* vport callbacks
*/
void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s);
-/**
+/*
* rport callbacks
*/
bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad,
struct bfa_fcs_rport_s **rport,
struct bfad_rport_s **rport_drv);
-/**
+/*
* itnim callbacks
*/
void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c
index 569dfefab70d..e7b49f4cb51f 100644
--- a/drivers/scsi/bfa/bfa_fcs_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c
@@ -15,13 +15,13 @@
* General Public License for more details.
*/
-/**
+/*
* fcpim.c - FCP initiator mode i-t nexus state machine
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
#include "bfad_im.h"
BFA_TRC_FILE(FCS, FCPIM);
@@ -38,7 +38,7 @@ static void bfa_fcs_itnim_prli_response(void *fcsarg,
bfa_status_t req_status, u32 rsp_len,
u32 resid_len, struct fchs_s *rsp_fchs);
-/**
+/*
* fcs_itnim_sm FCS itnim state machine events
*/
@@ -84,7 +84,7 @@ static struct bfa_sm_table_s itnim_sm_table[] = {
{BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
};
-/**
+/*
* fcs_itnim_sm FCS itnim state machine
*/
@@ -103,7 +103,7 @@ bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
break;
case BFA_FCS_ITNIM_SM_OFFLINE:
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
@@ -140,7 +140,7 @@ bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -181,7 +181,7 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_fcxp_discard(itnim->fcxp);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
@@ -217,7 +217,7 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
} else {
/* invoke target offline */
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_logo_imp(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
}
break;
@@ -225,7 +225,7 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_timer_stop(&itnim->timer);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_INITIATOR:
@@ -261,7 +261,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
bfa_fcb_itnim_online(itnim->itnim_drv);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) is online for initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
@@ -269,7 +269,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
bfa_itnim_offline(itnim->bfa_itnim);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -301,11 +301,11 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Target (WWN = %s) connectivity lost for "
"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
@@ -330,7 +330,7 @@ bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
switch (event) {
case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -358,7 +358,7 @@ bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
switch (event) {
case BFA_FCS_ITNIM_SM_OFFLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
- bfa_fcs_rport_itnim_ack(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
break;
case BFA_FCS_ITNIM_SM_RSP_ERROR:
@@ -494,11 +494,11 @@ bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
-/**
+/*
* itnim_public FCS ITNIM public interfaces
*/
-/**
+/*
* Called by rport when a new rport is created.
*
* @param[in] rport - remote port.
@@ -536,7 +536,7 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
if (bfa_itnim == NULL) {
bfa_trc(port->fcs, rport->pwwn);
bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
- bfa_assert(0);
+ WARN_ON(1);
return NULL;
}
@@ -554,7 +554,7 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
return itnim;
}
-/**
+/*
* Called by rport to delete the instance of FCPIM.
*
* @param[in] rport - remote port.
@@ -566,7 +566,7 @@ bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
}
-/**
+/*
* Notification from rport that PLOGI is complete to initiate FC-4 session.
*/
void
@@ -586,7 +586,7 @@ bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
}
}
-/**
+/*
* Called by rport to handle a remote device offline.
*/
void
@@ -596,7 +596,7 @@ bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
}
-/**
+/*
* Called by rport when remote port is known to be an initiator from
* PRLI received.
*/
@@ -608,7 +608,7 @@ bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
}
-/**
+/*
* Called by rport to check if the itnim is online.
*/
bfa_status_t
@@ -625,7 +625,7 @@ bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
}
}
-/**
+/*
* BFA completion callback for bfa_itnim_online().
*/
void
@@ -637,7 +637,7 @@ bfa_cb_itnim_online(void *cbarg)
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
}
-/**
+/*
* BFA completion callback for bfa_itnim_offline().
*/
void
@@ -649,7 +649,7 @@ bfa_cb_itnim_offline(void *cb_arg)
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
}
-/**
+/*
* Mark the beginning of PATH TOV handling. IO completion callbacks
* are still pending.
*/
@@ -661,7 +661,7 @@ bfa_cb_itnim_tov_begin(void *cb_arg)
bfa_trc(itnim->fcs, itnim->rport->pwwn);
}
-/**
+/*
* Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
*/
void
@@ -674,7 +674,7 @@ bfa_cb_itnim_tov(void *cb_arg)
itnim_drv->state = ITNIM_STATE_TIMEOUT;
}
-/**
+/*
* BFA notification to FCS/driver for second level error recovery.
*
* Atleast one I/O request has timedout and target is unresponsive to
@@ -688,7 +688,7 @@ bfa_cb_itnim_sler(void *cb_arg)
itnim->stats.sler++;
bfa_trc(itnim->fcs, itnim->rport->pwwn);
- bfa_fcs_rport_logo_imp(itnim->rport);
+ bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
}
struct bfa_fcs_itnim_s *
@@ -700,7 +700,7 @@ bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
if (!rport)
return NULL;
- bfa_assert(rport->itnim != NULL);
+ WARN_ON(rport->itnim == NULL);
return rport->itnim;
}
@@ -729,14 +729,14 @@ bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
{
struct bfa_fcs_itnim_s *itnim = NULL;
- bfa_assert(port != NULL);
+ WARN_ON(port == NULL);
itnim = bfa_fcs_itnim_lookup(port, rpwwn);
if (itnim == NULL)
return BFA_STATUS_NO_FCPIM_NEXUS;
- bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
+ memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
return BFA_STATUS_OK;
}
@@ -746,14 +746,14 @@ bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
{
struct bfa_fcs_itnim_s *itnim = NULL;
- bfa_assert(port != NULL);
+ WARN_ON(port == NULL);
itnim = bfa_fcs_itnim_lookup(port, rpwwn);
if (itnim == NULL)
return BFA_STATUS_NO_FCPIM_NEXUS;
- bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
+ memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
return BFA_STATUS_OK;
}
@@ -778,6 +778,6 @@ bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
}
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index b522bf30247a..43fa986bb586 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -15,21 +15,13 @@
* General Public License for more details.
*/
-/**
- * bfa_fcs_lport.c BFA FCS port
- */
-
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfa_fc.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, PORT);
-/**
- * Forward declarations
- */
-
static void bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port,
struct fchs_s *rx_fchs, u8 reason_code,
u8 reason_code_expl);
@@ -72,7 +64,7 @@ static struct {
bfa_fcs_lport_n2n_offline},
};
-/**
+/*
* fcs_port_sm FCS logical port state machine
*/
@@ -167,7 +159,7 @@ bfa_fcs_lport_sm_online(
bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
break;
@@ -205,7 +197,7 @@ bfa_fcs_lport_sm_offline(
bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
break;
@@ -240,7 +232,7 @@ bfa_fcs_lport_sm_deleting(
}
}
-/**
+/*
* fcs_port_pvt
*/
@@ -272,7 +264,7 @@ bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
FC_MAX_PDUSZ, 0);
}
-/**
+/*
* Process incoming plogi from a remote port.
*/
static void
@@ -303,7 +295,7 @@ bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
return;
}
- /**
+ /*
* Direct Attach P2P mode : verify address assigned by the r-port.
*/
if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
@@ -317,60 +309,62 @@ bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
return;
}
port->pid = rx_fchs->d_id;
+ bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
}
- /**
+ /*
* First, check if we know the device by pwwn.
*/
rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name);
if (rport) {
- /**
+ /*
* Direct Attach P2P mode : handle address assigned by r-port.
*/
if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
(memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
(void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
port->pid = rx_fchs->d_id;
+ bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
rport->pid = rx_fchs->s_id;
}
bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
return;
}
- /**
+ /*
* Next, lookup rport by PID.
*/
rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id);
if (!rport) {
- /**
+ /*
* Inbound PLOGI from a new device.
*/
bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
return;
}
- /**
+ /*
* Rport is known only by PID.
*/
if (rport->pwwn) {
- /**
+ /*
* This is a different device with the same pid. Old device
* disappeared. Send implicit LOGO to old device.
*/
- bfa_assert(rport->pwwn != plogi->port_name);
- bfa_fcs_rport_logo_imp(rport);
+ WARN_ON(rport->pwwn == plogi->port_name);
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
- /**
+ /*
* Inbound PLOGI from a new device (with old PID).
*/
bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
return;
}
- /**
+ /*
* PLOGI crossing each other.
*/
- bfa_assert(rport->pwwn == WWN_NULL);
+ WARN_ON(rport->pwwn != WWN_NULL);
bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
}
@@ -479,12 +473,12 @@ static void
bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
struct fc_rnid_general_topology_data_s *gen_topo_data)
{
- bfa_os_memset(gen_topo_data, 0,
+ memset(gen_topo_data, 0,
sizeof(struct fc_rnid_general_topology_data_s));
- gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
+ gen_topo_data->asso_type = cpu_to_be32(RNID_ASSOCIATED_TYPE_HOST);
gen_topo_data->phy_port_num = 0; /* @todo */
- gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
+ gen_topo_data->num_attached_nodes = cpu_to_be32(1);
}
static void
@@ -499,7 +493,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
__port_action[port->fabric->fab_type].online(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port online: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
@@ -519,37 +513,38 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
__port_action[port->fabric->fab_type].offline(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ if (bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_online) == BFA_TRUE)
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port taken offline: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
list_for_each_safe(qe, qen, &port->rport_q) {
rport = (struct bfa_fcs_rport_s *) qe;
- bfa_fcs_rport_offline(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
}
}
static void
bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port)
{
- bfa_assert(0);
+ WARN_ON(1);
}
static void
bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port)
{
- bfa_assert(0);
+ WARN_ON(1);
}
static void
bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port)
{
- bfa_assert(0);
+ WARN_ON(1);
}
static void
@@ -581,7 +576,7 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
char lpwwn_buf[BFA_STRING_32];
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port deleted: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
@@ -592,34 +587,12 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
port->vport ? port->vport->vport_drv : NULL);
bfa_fcs_vport_delete_comp(port->vport);
} else {
- bfa_fcs_fabric_port_delete_comp(port->fabric);
+ bfa_wc_down(&port->fabric->wc);
}
}
-
-/**
- * fcs_lport_api BFA FCS port API
- */
-/**
- * Module initialization
- */
-void
-bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs)
-{
-
-}
-
-/**
- * Module cleanup
- */
-void
-bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs)
-{
- bfa_fcs_modexit_comp(fcs);
-}
-
-/**
+/*
* Unsolicited frame receive handling.
*/
void
@@ -631,13 +604,14 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
bfa_stats(lport, uf_recvs);
+ bfa_trc(lport->fcs, fchs->type);
if (!bfa_fcs_lport_is_online(lport)) {
bfa_stats(lport, uf_recv_drops);
return;
}
- /**
+ /*
* First, handle ELSs that donot require a login.
*/
/*
@@ -673,7 +647,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
bfa_fcs_lport_abts_acc(lport, fchs);
return;
}
- /**
+ /*
* look for a matching remote port ID
*/
rport = bfa_fcs_lport_get_rport_by_pid(lport, pid);
@@ -686,12 +660,15 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
return;
}
- /**
+ /*
* Only handles ELS frames for now.
*/
if (fchs->type != FC_TYPE_ELS) {
- bfa_trc(lport->fcs, fchs->type);
- bfa_assert(0);
+ bfa_trc(lport->fcs, fchs->s_id);
+ bfa_trc(lport->fcs, fchs->d_id);
+ /* ignore type FC_TYPE_FC_FSS */
+ if (fchs->type != FC_TYPE_FC_FSS)
+ bfa_sm_fault(lport->fcs, fchs->type);
return;
}
@@ -702,20 +679,20 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
}
if (els_cmd->els_code == FC_ELS_LOGO) {
- /**
+ /*
* @todo Handle LOGO frames received.
*/
return;
}
if (els_cmd->els_code == FC_ELS_PRLI) {
- /**
+ /*
* @todo Handle PRLI frames received.
*/
return;
}
- /**
+ /*
* Unhandled ELS frames. Send a LS_RJT.
*/
bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
@@ -723,7 +700,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
}
-/**
+/*
* PID based Lookup for a R-Port in the Port R-Port Queue
*/
struct bfa_fcs_rport_s *
@@ -742,7 +719,7 @@ bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid)
return NULL;
}
-/**
+/*
* PWWN based Lookup for a R-Port in the Port R-Port Queue
*/
struct bfa_fcs_rport_s *
@@ -761,7 +738,7 @@ bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn)
return NULL;
}
-/**
+/*
* NWWN based Lookup for a R-Port in the Port R-Port Queue
*/
struct bfa_fcs_rport_s *
@@ -780,7 +757,7 @@ bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn)
return NULL;
}
-/**
+/*
* Called by rport module when new rports are discovered.
*/
void
@@ -792,7 +769,7 @@ bfa_fcs_lport_add_rport(
port->num_rports++;
}
-/**
+/*
* Called by rport module to when rports are deleted.
*/
void
@@ -800,14 +777,14 @@ bfa_fcs_lport_del_rport(
struct bfa_fcs_lport_s *port,
struct bfa_fcs_rport_s *rport)
{
- bfa_assert(bfa_q_is_on_q(&port->rport_q, rport));
+ WARN_ON(!bfa_q_is_on_q(&port->rport_q, rport));
list_del(&rport->qe);
port->num_rports--;
bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
}
-/**
+/*
* Called by fabric for base port when fabric login is complete.
* Called by vport for virtual ports when FDISC is complete.
*/
@@ -817,7 +794,7 @@ bfa_fcs_lport_online(struct bfa_fcs_lport_s *port)
bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
}
-/**
+/*
* Called by fabric for base port when fabric goes offline.
* Called by vport for virtual ports when virtual port becomes offline.
*/
@@ -827,7 +804,7 @@ bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port)
bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
}
-/**
+/*
* Called by fabric to delete base lport and associated resources.
*
* Called by vport to delete lport and associated resources. Should call
@@ -839,7 +816,7 @@ bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port)
bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
}
-/**
+/*
* Return TRUE if port is online, else return FALSE
*/
bfa_boolean_t
@@ -848,7 +825,7 @@ bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port)
return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online);
}
-/**
+/*
* Attach time initialization of logical ports.
*/
void
@@ -858,14 +835,14 @@ bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs,
lport->fcs = fcs;
lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
lport->vport = vport;
- lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
- bfa_lps_get_tag(lport->fabric->lps);
+ lport->lp_tag = (vport) ? vport->lps->lp_tag :
+ lport->fabric->lps->lp_tag;
INIT_LIST_HEAD(&lport->rport_q);
lport->num_rports = 0;
}
-/**
+/*
* Logical port initialization of base or virtual port.
* Called by fabric for base port or by vport for virtual ports.
*/
@@ -878,7 +855,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad;
char lpwwn_buf[BFA_STRING_32];
- bfa_os_assign(lport->port_cfg, *port_cfg);
+ lport->port_cfg = *port_cfg;
lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport,
lport->port_cfg.roles,
@@ -886,7 +863,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
vport ? vport->vport_drv : NULL);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"New logical port created: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
@@ -894,7 +871,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
}
-/**
+/*
* fcs_lport_api
*/
@@ -911,10 +888,12 @@ bfa_fcs_lport_get_attr(
port_attr->port_cfg = port->port_cfg;
if (port->fabric) {
- port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
- port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
+ port_attr->port_type = port->fabric->oper_type;
+ port_attr->loopback = bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_loopback);
port_attr->authfail =
- bfa_fcs_fabric_is_auth_failed(port->fabric);
+ bfa_sm_cmp_state(port->fabric,
+ bfa_fcs_fabric_sm_auth_failed);
port_attr->fabric_name = bfa_fcs_lport_get_fabric_name(port);
memcpy(port_attr->fabric_ip_addr,
bfa_fcs_lport_get_fabric_ipaddr(port),
@@ -923,10 +902,10 @@ bfa_fcs_lport_get_attr(
if (port->vport != NULL) {
port_attr->port_type = BFA_PORT_TYPE_VPORT;
port_attr->fpma_mac =
- bfa_lps_get_lp_mac(port->vport->lps);
+ port->vport->lps->lp_mac;
} else {
port_attr->fpma_mac =
- bfa_lps_get_lp_mac(port->fabric->lps);
+ port->fabric->lps->lp_mac;
}
} else {
port_attr->port_type = BFA_PORT_TYPE_UNKNOWN;
@@ -934,11 +913,11 @@ bfa_fcs_lport_get_attr(
}
}
-/**
+/*
* bfa_fcs_lport_fab port fab functions
*/
-/**
+/*
* Called by port to initialize fabric services of the base port.
*/
static void
@@ -949,7 +928,7 @@ bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port)
bfa_fcs_lport_ms_init(port);
}
-/**
+/*
* Called by port to notify transition to online state.
*/
static void
@@ -959,7 +938,7 @@ bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port)
bfa_fcs_lport_scn_online(port);
}
-/**
+/*
* Called by port to notify transition to offline state.
*/
static void
@@ -970,11 +949,11 @@ bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port)
bfa_fcs_lport_ms_offline(port);
}
-/**
+/*
* bfa_fcs_lport_n2n functions
*/
-/**
+/*
* Called by fcs/port to initialize N2N topology.
*/
static void
@@ -982,7 +961,7 @@ bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port)
{
}
-/**
+/*
* Called by fcs/port to notify transition to online state.
*/
static void
@@ -1006,7 +985,8 @@ bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
sizeof(wwn_t)) > 0) {
port->pid = N2N_LOCAL_PID;
- /**
+ bfa_lps_set_n2n_pid(port->fabric->lps, N2N_LOCAL_PID);
+ /*
* First, check if we know the device by pwwn.
*/
rport = bfa_fcs_lport_get_rport_by_pwwn(port,
@@ -1015,7 +995,7 @@ bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
bfa_trc(port->fcs, rport->pid);
bfa_trc(port->fcs, rport->pwwn);
rport->pid = N2N_REMOTE_PID;
- bfa_fcs_rport_online(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
return;
}
@@ -1025,17 +1005,17 @@ bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
*/
if (port->num_rports > 0) {
rport = bfa_fcs_lport_get_rport_by_pid(port, 0);
- bfa_assert(rport != NULL);
+ WARN_ON(rport == NULL);
if (rport) {
bfa_trc(port->fcs, rport->pwwn);
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
}
}
bfa_fcs_rport_create(port, N2N_REMOTE_PID);
}
}
-/**
+/*
* Called by fcs/port to notify transition to offline state.
*/
static void
@@ -1094,11 +1074,11 @@ static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr);
-/**
+/*
* fcs_fdmi_sm FCS FDMI state machine
*/
-/**
+/*
* FDMI State Machine events
*/
enum port_fdmi_event {
@@ -1143,7 +1123,7 @@ static void bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
static void bfa_fcs_lport_fdmi_sm_disabled(
struct bfa_fcs_lport_fdmi_s *fdmi,
enum port_fdmi_event event);
-/**
+/*
* Start in offline state - awaiting MS to send start.
*/
static void
@@ -1510,7 +1490,7 @@ bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
bfa_sm_fault(port->fcs, event);
}
}
-/**
+/*
* FDMI is disabled state.
*/
static void
@@ -1525,7 +1505,7 @@ bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi,
/* No op State. It can only be enabled at Driver Init. */
}
-/**
+/*
* RHBA : Register HBA Attributes.
*/
static void
@@ -1549,7 +1529,7 @@ bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
- bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+ memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
FDMI_RHBA);
@@ -1577,6 +1557,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
struct fdmi_attr_s *attr;
u8 *curr_ptr;
u16 len, count;
+ u16 templen;
/*
* get hba attributes
@@ -1584,7 +1565,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);
rhba->hba_id = bfa_fcs_lport_get_pwwn(port);
- rhba->port_list.num_ports = bfa_os_htonl(1);
+ rhba->port_list.num_ports = cpu_to_be32(1);
rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port);
len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);
@@ -1601,204 +1582,165 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
* Node Name
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME);
- attr->len = sizeof(wwn_t);
- memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME);
+ templen = sizeof(wwn_t);
+ memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Manufacturer
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER);
- attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
- memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER);
+ templen = (u16) strlen(fcs_hba_attr->manufacturer);
+ memcpy(attr->value, fcs_hba_attr->manufacturer, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Serial Number
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM);
- attr->len = (u16) strlen(fcs_hba_attr->serial_num);
- memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM);
+ templen = (u16) strlen(fcs_hba_attr->serial_num);
+ memcpy(attr->value, fcs_hba_attr->serial_num, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Model
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL);
- attr->len = (u16) strlen(fcs_hba_attr->model);
- memcpy(attr->value, fcs_hba_attr->model, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL);
+ templen = (u16) strlen(fcs_hba_attr->model);
+ memcpy(attr->value, fcs_hba_attr->model, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Model Desc
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC);
- attr->len = (u16) strlen(fcs_hba_attr->model_desc);
- memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC);
+ templen = (u16) strlen(fcs_hba_attr->model_desc);
+ memcpy(attr->value, fcs_hba_attr->model_desc, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* H/W Version
*/
if (fcs_hba_attr->hw_version[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->hw_version);
- memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION);
+ templen = (u16) strlen(fcs_hba_attr->hw_version);
+ memcpy(attr->value, fcs_hba_attr->hw_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* Driver Version
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->driver_version);
- memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION);
+ templen = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Option Rom Version
*/
if (fcs_hba_attr->option_rom_ver[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
- memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION);
+ templen = (u16) strlen(fcs_hba_attr->option_rom_ver);
+ memcpy(attr->value, fcs_hba_attr->option_rom_ver, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* f/w Version = driver version
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION);
- attr->len = (u16) strlen(fcs_hba_attr->driver_version);
- memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION);
+ templen = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* OS Name
*/
if (fcs_hba_attr->os_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME);
- attr->len = (u16) strlen(fcs_hba_attr->os_name);
- memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME);
+ templen = (u16) strlen(fcs_hba_attr->os_name);
+ memcpy(attr->value, fcs_hba_attr->os_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* MAX_CT_PAYLOAD
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT);
- attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
- memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT);
+ templen = sizeof(fcs_hba_attr->max_ct_pyld);
+ memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, templen);
+ len += templen;
count++;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Update size of payload
*/
- len += ((sizeof(attr->type) +
- sizeof(attr->len)) * count);
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
- rhba->hba_attr_blk.attr_count = bfa_os_htonl(count);
+ rhba->hba_attr_blk.attr_count = cpu_to_be32(count);
return len;
}
@@ -1825,7 +1767,7 @@ bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -1837,7 +1779,7 @@ bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}
-/**
+/*
* RPRT : Register Port
*/
static void
@@ -1861,7 +1803,7 @@ bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
- bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+ memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
FDMI_RPRT);
@@ -1879,7 +1821,7 @@ bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
}
-/**
+/*
* This routine builds Port Attribute Block that used in RPA, RPRT commands.
*/
static u16
@@ -1892,6 +1834,7 @@ bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
u8 *curr_ptr;
u16 len;
u8 count = 0;
+ u16 templen;
/*
* get port attributes
@@ -1909,103 +1852,92 @@ bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
* FC4 Types
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES);
- attr->len = sizeof(fcs_port_attr.supp_fc4_types);
- memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES);
+ templen = sizeof(fcs_port_attr.supp_fc4_types);
+ memcpy(attr->value, fcs_port_attr.supp_fc4_types, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* Supported Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED);
- attr->len = sizeof(fcs_port_attr.supp_speed);
- memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED);
+ templen = sizeof(fcs_port_attr.supp_speed);
+ memcpy(attr->value, &fcs_port_attr.supp_speed, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* current Port Speed
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED);
- attr->len = sizeof(fcs_port_attr.curr_speed);
- memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED);
+ templen = sizeof(fcs_port_attr.curr_speed);
+ memcpy(attr->value, &fcs_port_attr.curr_speed, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* max frame size
*/
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE);
- attr->len = sizeof(fcs_port_attr.max_frm_size);
- memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE);
+ templen = sizeof(fcs_port_attr.max_frm_size);
+ memcpy(attr->value, &fcs_port_attr.max_frm_size, templen);
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
/*
* OS Device Name
*/
if (fcs_port_attr.os_device_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME);
- attr->len = (u16) strlen(fcs_port_attr.os_device_name);
- memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME);
+ templen = (u16) strlen(fcs_port_attr.os_device_name);
+ memcpy(attr->value, fcs_port_attr.os_device_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* Host Name
*/
if (fcs_port_attr.host_name[0] != '\0') {
attr = (struct fdmi_attr_s *) curr_ptr;
- attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME);
- attr->len = (u16) strlen(fcs_port_attr.host_name);
- memcpy(attr->value, fcs_port_attr.host_name, attr->len);
- attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
- *fields need
- *to be 4 byte
- *aligned */
- curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
- len += attr->len;
+ attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME);
+ templen = (u16) strlen(fcs_port_attr.host_name);
+ memcpy(attr->value, fcs_port_attr.host_name, templen);
+ templen = fc_roundup(templen, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
+ len += templen;
++count;
- attr->len =
- bfa_os_htons(attr->len + sizeof(attr->type) +
- sizeof(attr->len));
+ attr->len = cpu_to_be16(templen + sizeof(attr->type) +
+ sizeof(templen));
}
/*
* Update size of payload
*/
- port_attrib->attr_count = bfa_os_htonl(count);
- len += ((sizeof(attr->type) +
- sizeof(attr->len)) * count);
+ port_attrib->attr_count = cpu_to_be32(count);
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
return len;
}
@@ -2050,7 +1982,7 @@ bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -2062,7 +1994,7 @@ bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}
-/**
+/*
* RPA : Register Port Attributes.
*/
static void
@@ -2086,15 +2018,13 @@ bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
fdmi->fcxp = fcxp;
pyld = bfa_fcxp_get_reqbuf(fcxp);
- bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+ memset(pyld, 0, FC_MAX_PDUSZ);
len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
FDMI_RPA);
- attr_len =
- bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi,
- (u8 *) ((struct ct_hdr_s *) pyld
- + 1));
+ attr_len = bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi,
+ (u8 *) ((struct ct_hdr_s *) pyld + 1));
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len + attr_len, &fchs,
@@ -2143,7 +2073,7 @@ bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -2163,14 +2093,14 @@ bfa_fcs_lport_fdmi_timeout(void *arg)
bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}
-void
+static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
struct bfa_fcs_lport_s *port = fdmi->ms->port;
struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
- bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
+ memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc,
hba_attr->manufacturer);
@@ -2204,10 +2134,10 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
sizeof(driver_info->host_os_patch));
}
- hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ);
+ hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ);
}
-void
+static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
@@ -2215,7 +2145,7 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
struct bfa_port_attr_s pport_attr;
- bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
+ memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
/*
* get pport attributes from hal
@@ -2230,17 +2160,17 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
/*
* Supported Speeds
*/
- port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS);
+ port_attr->supp_speed = cpu_to_be32(BFA_FCS_FDMI_SUPORTED_SPEEDS);
/*
* Current Speed
*/
- port_attr->curr_speed = bfa_os_htonl(pport_attr.speed);
+ port_attr->curr_speed = cpu_to_be32(pport_attr.speed);
/*
* Max PDU Size.
*/
- port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ);
+ port_attr->max_frm_size = cpu_to_be32(FC_MAX_PDUSZ);
/*
* OS device Name
@@ -2321,11 +2251,11 @@ static void bfa_fcs_lport_ms_gfn_response(void *fcsarg,
u32 rsp_len,
u32 resid_len,
struct fchs_s *rsp_fchs);
-/**
+/*
* fcs_ms_sm FCS MS state machine
*/
-/**
+/*
* MS State Machine events
*/
enum port_ms_event {
@@ -2360,7 +2290,7 @@ static void bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
enum port_ms_event event);
static void bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms,
enum port_ms_event event);
-/**
+/*
* Start in offline state - awaiting NS to send start.
*/
static void
@@ -2432,7 +2362,7 @@ bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms,
*/
bfa_fcs_lport_fdmi_online(ms);
- /**
+ /*
* if this is a Vport, go to online state.
*/
if (ms->port->vport) {
@@ -2595,7 +2525,7 @@ bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms,
bfa_sm_fault(ms->port->fcs, event);
}
}
-/**
+/*
* ms_pvt MS local functions
*/
@@ -2620,7 +2550,7 @@ bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_lport_get_fcid(port),
- bfa_lps_get_peer_nwwn(port->fabric->lps));
+ port->fabric->lps->pr_nwwn);
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs,
@@ -2657,12 +2587,12 @@ bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);
- num_entries = bfa_os_ntohl(gmal_resp->ms_len);
+ num_entries = be32_to_cpu(gmal_resp->ms_len);
if (num_entries == 0) {
bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
return;
@@ -2795,7 +2725,7 @@ bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
bfa_sm_fault(ms->port->fcs, event);
}
}
-/**
+/*
* ms_pvt MS local functions
*/
@@ -2820,7 +2750,7 @@ bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_lport_get_fcid(port),
- bfa_lps_get_peer_nwwn(port->fabric->lps));
+ port->fabric->lps->pr_nwwn);
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs,
@@ -2853,7 +2783,7 @@ bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
gfn_resp = (wwn_t *)(cthdr + 1);
@@ -2871,7 +2801,7 @@ bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
}
-/**
+/*
* ms_pvt MS local functions
*/
@@ -2896,7 +2826,7 @@ bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
ms->fcxp = fcxp;
len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_MGMT_SERVER),
+ bfa_hton3b(FC_MGMT_SERVER),
bfa_fcs_lport_get_fcid(port), 0,
port->port_cfg.pwwn, port->port_cfg.nwwn,
bfa_fcport_get_maxfrsize(port->fcs->bfa));
@@ -3017,7 +2947,7 @@ bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port)
bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
}
-/**
+/*
* @page ns_sm_info VPORT NS State Machine
*
* @section ns_sm_interactions VPORT NS State Machine Interactions
@@ -3080,11 +3010,11 @@ static void bfa_fcs_lport_ns_process_gidft_pids(
u32 *pid_buf, u32 n_pids);
static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port);
-/**
+/*
* fcs_ns_sm FCS nameserver interface state machine
*/
-/**
+/*
* VPort NS State Machine events
*/
enum vport_ns_event {
@@ -3139,7 +3069,7 @@ static void bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns,
enum vport_ns_event event);
static void bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
enum vport_ns_event event);
-/**
+/*
* Start in offline state - awaiting linkup
*/
static void
@@ -3628,7 +3558,7 @@ bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
-/**
+/*
* ns_pvt Nameserver local functions
*/
@@ -3653,7 +3583,7 @@ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
ns->fcxp = fcxp;
len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_os_hton3b(FC_NAME_SERVER),
+ bfa_hton3b(FC_NAME_SERVER),
bfa_fcs_lport_get_fcid(port), 0,
port->port_cfg.pwwn, port->port_cfg.nwwn,
bfa_fcport_get_maxfrsize(port->fcs->bfa));
@@ -3724,7 +3654,7 @@ bfa_fcs_lport_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
}
-/**
+/*
* Register the symbolic port name.
*/
static void
@@ -3738,7 +3668,7 @@ bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
u8 symbl[256];
u8 *psymbl = &symbl[0];
- bfa_os_memset(symbl, 0, sizeof(symbl));
+ memset(symbl, 0, sizeof(symbl));
bfa_trc(port->fcs, port->port_cfg.pwwn);
@@ -3755,7 +3685,7 @@ bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
* for V-Port, form a Port Symbolic Name
*/
if (port->vport) {
- /**
+ /*
* For Vports, we append the vport's port symbolic name
* to that of the base port.
*/
@@ -3815,7 +3745,7 @@ bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
port->stats.ns_rspnid_accepts++;
@@ -3829,7 +3759,7 @@ bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}
-/**
+/*
* Register FC4-Types
*/
static void
@@ -3887,7 +3817,7 @@ bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
port->stats.ns_rftid_accepts++;
@@ -3901,7 +3831,7 @@ bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}
-/**
+/*
* Register FC4-Features : Should be done after RFT_ID
*/
static void
@@ -3964,7 +3894,7 @@ bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
port->stats.ns_rffid_accepts++;
@@ -3982,7 +3912,7 @@ bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
} else
bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}
-/**
+/*
* Query Fabric for FC4-Types Devices.
*
* TBD : Need to use a local (FCS private) response buffer, since the response
@@ -4058,7 +3988,7 @@ bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
switch (cthdr->cmd_rsp_code) {
@@ -4102,7 +4032,7 @@ bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
}
}
-/**
+/*
* This routine will be called by bfa_timer on timer timeouts.
*
* param[in] port - pointer to bfa_fcs_lport_t.
@@ -4166,7 +4096,7 @@ bfa_fcs_lport_ns_process_gidft_pids(struct bfa_fcs_lport_s *port, u32 *pid_buf,
}
}
-/**
+/*
* fcs_ns_public FCS nameserver public interfaces
*/
@@ -4210,7 +4140,7 @@ bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port)
bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY);
}
-void
+static void
bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port)
{
@@ -4223,11 +4153,11 @@ bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port)
for (ii = 0 ; ii < nwwns; ++ii) {
rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]);
- bfa_assert(rport);
+ WARN_ON(!rport);
}
}
-/**
+/*
* FCS SCN
*/
@@ -4250,11 +4180,11 @@ static void bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
struct fchs_s *rx_fchs);
static void bfa_fcs_lport_scn_timeout(void *arg);
-/**
+/*
* fcs_scm_sm FCS SCN state machine
*/
-/**
+/*
* VPort SCN State Machine events
*/
enum port_scn_event {
@@ -4278,7 +4208,7 @@ static void bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn,
static void bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
enum port_scn_event event);
-/**
+/*
* Starting state - awaiting link up.
*/
static void
@@ -4382,11 +4312,11 @@ bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
-/**
+/*
* fcs_scn_private FCS SCN private functions
*/
-/**
+/*
* This routine will be called to send a SCR command.
*/
static void
@@ -4412,8 +4342,8 @@ bfa_fcs_lport_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
/* Handle VU registrations for Base port only */
if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_lps_is_brcd_fabric(port->fabric->lps),
- port->pid, 0);
+ port->fabric->lps->brcd_switch,
+ port->pid, 0);
} else {
len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
BFA_FALSE,
@@ -4499,7 +4429,7 @@ bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
FC_MAX_PDUSZ, 0);
}
-/**
+/*
* This routine will be called by bfa_timer on timer timeouts.
*
* param[in] vport - pointer to bfa_fcs_lport_t.
@@ -4522,7 +4452,7 @@ bfa_fcs_lport_scn_timeout(void *arg)
-/**
+/*
* fcs_scn_public FCS state change notification public interfaces
*/
@@ -4563,7 +4493,7 @@ bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid)
bfa_trc(port->fcs, rpid);
- /**
+ /*
* If this is an unknown device, then it just came online.
* Otherwise let rport handle the RSCN event.
*/
@@ -4579,7 +4509,7 @@ bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid)
bfa_fcs_rport_scn(rport);
}
-/**
+/*
* rscn format based PID comparison
*/
#define __fc_pid_match(__c0, __c1, __fmt) \
@@ -4624,7 +4554,7 @@ bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port,
int i = 0, j;
num_entries =
- (bfa_os_ntohs(rscn->payldlen) -
+ (be16_to_cpu(rscn->payldlen) -
sizeof(u32)) / sizeof(rscn->event[0]);
bfa_trc(port->fcs, num_entries);
@@ -4686,23 +4616,23 @@ bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port,
default:
- bfa_assert(0);
+ WARN_ON(1);
nsquery = BFA_TRUE;
}
}
- /**
- * If any of area, domain or fabric RSCN is received, do a fresh discovery
- * to find new devices.
+ /*
+ * If any of area, domain or fabric RSCN is received, do a fresh
+ * discovery to find new devices.
*/
if (nsquery)
bfa_fcs_lport_ns_query(port);
}
-/**
+/*
* BFA FCS port
*/
-/**
+/*
* fcs_port_api BFA FCS port API
*/
struct bfa_fcs_lport_s *
@@ -4732,7 +4662,7 @@ bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, int index,
while ((qe != qh) && (i < nrports)) {
rport = (struct bfa_fcs_rport_s *) qe;
- if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
qe = bfa_q_next(qe);
bfa_trc(fcs, (u32) rport->pwwn);
bfa_trc(fcs, rport->pid);
@@ -4780,7 +4710,7 @@ bfa_fcs_lport_get_rports(struct bfa_fcs_lport_s *port,
while ((qe != qh) && (i < *nrports)) {
rport = (struct bfa_fcs_rport_s *) qe;
- if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
qe = bfa_q_next(qe);
bfa_trc(fcs, (u32) rport->pwwn);
bfa_trc(fcs, rport->pid);
@@ -4831,7 +4761,7 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port)
while (qe != qh) {
rport = (struct bfa_fcs_rport_s *) qe;
- if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) ||
+ if ((bfa_ntoh3b(rport->pid) > 0xFFF000) ||
(bfa_fcs_rport_get_state(rport) ==
BFA_RPORT_OFFLINE)) {
qe = bfa_q_next(qe);
@@ -4867,7 +4797,7 @@ bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn)
struct bfa_fcs_vport_s *vport;
bfa_fcs_vf_t *vf;
- bfa_assert(fcs != NULL);
+ WARN_ON(fcs == NULL);
vf = bfa_fcs_vf_lookup(fcs, vf_id);
if (vf == NULL) {
@@ -4913,7 +4843,7 @@ bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port,
port_info->max_vports_supp =
bfa_lps_get_max_vport(port->fcs->bfa);
port_info->num_vports_inuse =
- bfa_fcs_fabric_vport_count(port->fabric);
+ port->fabric->num_vports;
port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP;
port_info->num_rports_inuse = port->num_rports;
} else {
@@ -4943,10 +4873,10 @@ bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port,
void
bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port)
{
- bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s));
+ memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s));
}
-/**
+/*
* FCS virtual port state machine
*/
@@ -4967,11 +4897,11 @@ static void bfa_fcs_vport_timeout(void *vport_arg);
static void bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport);
static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport);
-/**
+/*
* fcs_vport_sm FCS virtual port state machine
*/
-/**
+/*
* VPort State Machine events
*/
enum bfa_fcs_vport_event {
@@ -5024,7 +4954,7 @@ static struct bfa_sm_table_s vport_sm_table[] = {
{BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR}
};
-/**
+/*
* Beginning state.
*/
static void
@@ -5045,7 +4975,7 @@ bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Created state - a start event is required to start up the state machine.
*/
static void
@@ -5057,12 +4987,13 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
switch (event) {
case BFA_FCS_VPORT_SM_START:
- if (bfa_fcs_fabric_is_online(__vport_fabric(vport))
+ if (bfa_sm_cmp_state(__vport_fabric(vport),
+ bfa_fcs_fabric_sm_online)
&& bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) {
bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
bfa_fcs_vport_do_fdisc(vport);
} else {
- /**
+ /*
* Fabric is offline or not NPIV capable, stay in
* offline state.
*/
@@ -5078,7 +5009,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
case BFA_FCS_VPORT_SM_ONLINE:
case BFA_FCS_VPORT_SM_OFFLINE:
- /**
+ /*
* Ignore ONLINE/OFFLINE events from fabric
* till vport is started.
*/
@@ -5089,7 +5020,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Offline state - awaiting ONLINE event from fabric SM.
*/
static void
@@ -5127,7 +5058,7 @@ bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
}
-/**
+/*
* FDISC is sent and awaiting reply from fabric.
*/
static void
@@ -5140,13 +5071,13 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
switch (event) {
case BFA_FCS_VPORT_SM_DELETE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_lport_delete(&vport->lport);
break;
case BFA_FCS_VPORT_SM_OFFLINE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
break;
case BFA_FCS_VPORT_SM_RSP_OK:
@@ -5174,7 +5105,7 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* FDISC attempt failed - a timer is active to retry FDISC.
*/
static void
@@ -5208,7 +5139,7 @@ bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Vport is online (FDISC is complete).
*/
static void
@@ -5226,7 +5157,7 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
case BFA_FCS_VPORT_SM_OFFLINE:
bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
bfa_fcs_lport_offline(&vport->lport);
break;
@@ -5235,7 +5166,7 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Vport is being deleted - awaiting lport delete completion to send
* LOGO to fabric.
*/
@@ -5264,7 +5195,7 @@ bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Error State.
* This state will be set when the Vport Creation fails due
* to errors like Dup WWN. In this state only operation allowed
@@ -5288,7 +5219,7 @@ bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* Lport cleanup is in progress since vport is being deleted. Fabric is
* offline, so no LOGO is needed to complete vport deletion.
*/
@@ -5313,7 +5244,7 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
}
}
-/**
+/*
* LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup
* is done.
*/
@@ -5326,7 +5257,7 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
switch (event) {
case BFA_FCS_VPORT_SM_OFFLINE:
- bfa_lps_discard(vport->lps);
+ bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
/*
* !!! fall through !!!
*/
@@ -5347,10 +5278,10 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
-/**
+/*
* fcs_vport_private FCS virtual port private functions
*/
-/**
+/*
* This routine will be called to send a FDISC command.
*/
static void
@@ -5365,14 +5296,14 @@ bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport)
static void
bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
{
- u8 lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps);
- u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps);
+ u8 lsrjt_rsn = vport->lps->lsrjt_rsn;
+ u8 lsrjt_expl = vport->lps->lsrjt_expl;
bfa_trc(__vport_fcs(vport), lsrjt_rsn);
bfa_trc(__vport_fcs(vport), lsrjt_expl);
/* For certain reason codes, we don't want to retry. */
- switch (bfa_lps_get_lsrjt_expl(vport->lps)) {
+ switch (vport->lps->lsrjt_expl) {
case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */
case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
@@ -5397,7 +5328,7 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
}
}
-/**
+/*
* Called to send a logout to the fabric. Used when a V-Port is
* deleted/stopped.
*/
@@ -5411,7 +5342,7 @@ bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport)
}
-/**
+/*
* This routine will be called by bfa_timer on timer timeouts.
*
* param[in] vport - pointer to bfa_fcs_vport_t.
@@ -5449,11 +5380,11 @@ bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
-/**
+/*
* fcs_vport_public FCS virtual port public interfaces
*/
-/**
+/*
* Online notification from fabric SM.
*/
void
@@ -5463,7 +5394,7 @@ bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport)
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
}
-/**
+/*
* Offline notification from fabric SM.
*/
void
@@ -5473,7 +5404,7 @@ bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport)
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
}
-/**
+/*
* Cleanup notification from fabric SM on link timer expiry.
*/
void
@@ -5481,7 +5412,7 @@ bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport)
{
vport->vport_stats.fab_cleanup++;
}
-/**
+/*
* delete notification from fabric SM. To be invoked from within FCS.
*/
void
@@ -5490,7 +5421,7 @@ bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport)
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
}
-/**
+/*
* Delete completion callback from associated lport
*/
void
@@ -5501,11 +5432,11 @@ bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport)
-/**
+/*
* fcs_vport_api Virtual port API
*/
-/**
+/*
* Use this function to instantiate a new FCS vport object. This
* function will not trigger any HW initialization process (which will be
* done in vport_start() call)
@@ -5536,7 +5467,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL)
return BFA_STATUS_VPORT_EXISTS;
- if (bfa_fcs_fabric_vport_count(&fcs->fabric) ==
+ if (fcs->fabric.num_vports ==
bfa_lps_get_max_vport(fcs->bfa))
return BFA_STATUS_VPORT_MAX;
@@ -5555,7 +5486,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
return BFA_STATUS_OK;
}
-/**
+/*
* Use this function to instantiate a new FCS PBC vport object. This
* function will not trigger any HW initialization process (which will be
* done in vport_start() call)
@@ -5585,7 +5516,7 @@ bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
return rc;
}
-/**
+/*
* Use this function to findout if this is a pbc vport or not.
*
* @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -5603,7 +5534,7 @@ bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport)
}
-/**
+/*
* Use this function initialize the vport.
*
* @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -5618,7 +5549,7 @@ bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport)
return BFA_STATUS_OK;
}
-/**
+/*
* Use this function quiese the vport object. This function will return
* immediately, when the vport is actually stopped, the
* bfa_drv_vport_stop_cb() will be called.
@@ -5635,7 +5566,7 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
return BFA_STATUS_OK;
}
-/**
+/*
* Use this function to delete a vport object. Fabric object should
* be stopped before this function call.
*
@@ -5657,7 +5588,7 @@ bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
return BFA_STATUS_OK;
}
-/**
+/*
* Use this function to get vport's current status info.
*
* param[in] vport pointer to bfa_fcs_vport_t.
@@ -5672,41 +5603,14 @@ bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
if (vport == NULL || attr == NULL)
return;
- bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s));
+ memset(attr, 0, sizeof(struct bfa_vport_attr_s));
bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr);
attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
}
-/**
- * Use this function to get vport's statistics.
- *
- * param[in] vport pointer to bfa_fcs_vport_t.
- * param[out] stats pointer to return vport statistics in
- *
- * return None
- */
-void
-bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
- struct bfa_vport_stats_s *stats)
-{
- *stats = vport->vport_stats;
-}
-/**
- * Use this function to clear vport's statistics.
- *
- * param[in] vport pointer to bfa_fcs_vport_t.
- *
- * return None
- */
-void
-bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport)
-{
- bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
-}
-
-/**
+/*
* Lookup a virtual port. Excludes base port from lookup.
*/
struct bfa_fcs_vport_s *
@@ -5728,7 +5632,7 @@ bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn)
return vport;
}
-/**
+/*
* FDISC Response
*/
void
@@ -5742,9 +5646,9 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
switch (status) {
case BFA_STATUS_OK:
/*
- * Initialiaze the V-Port fields
+ * Initialize the V-Port fields
*/
- __vport_fcid(vport) = bfa_lps_get_pid(vport->lps);
+ __vport_fcid(vport) = vport->lps->lp_pid;
vport->vport_stats.fdisc_accepts++;
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
break;
@@ -5757,7 +5661,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
break;
case BFA_STATUS_EPROTOCOL:
- switch (bfa_lps_get_extstatus(vport->lps)) {
+ switch (vport->lps->ext_status) {
case BFA_EPROTO_BAD_ACCEPT:
vport->vport_stats.fdisc_acc_bad++;
break;
@@ -5784,7 +5688,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
}
}
-/**
+/*
* LOGO response
*/
void
@@ -5794,7 +5698,7 @@ bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg)
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
}
-/**
+/*
* Received clear virtual link
*/
void
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 635f0cd88714..caaee6f06937 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -15,13 +15,13 @@
* General Public License for more details.
*/
-/**
+/*
* rport.c Remote port implementation.
*/
+#include "bfad_drv.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(FCS, RPORT);
@@ -75,30 +75,6 @@ static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport,
static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
struct fchs_s *rx_fchs, u16 len);
static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport);
-/**
- * fcs_rport_sm FCS rport state machine events
- */
-
-enum rport_event {
- RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
- RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
- RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
- RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
- RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
- RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
- RPSM_EVENT_DELETE = 7, /* RPORT delete request */
- RPSM_EVENT_SCN = 8, /* state change notification */
- RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */
- RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
- RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
- RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
- RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
- RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
- RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
- RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */
- RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */
- RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */
-};
static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
enum rport_event event);
@@ -172,7 +148,7 @@ static struct bfa_sm_table_s rport_sm_table[] = {
{BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC},
};
-/**
+/*
* Beginning state.
*/
static void
@@ -210,7 +186,7 @@ bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* PLOGI is being sent.
*/
static void
@@ -262,7 +238,7 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* PLOGI is being sent.
*/
static void
@@ -287,7 +263,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_PLOGI_RCVD:
case RPSM_EVENT_SCN:
- /**
+ /*
* Ignore, SCN is possibly online notification.
*/
break;
@@ -309,7 +285,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_HCB_OFFLINE:
- /**
+ /*
* Ignore BFA callback, on a PLOGI receive we call bfa offline.
*/
break;
@@ -319,7 +295,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* PLOGI is sent.
*/
static void
@@ -380,7 +356,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* PLOGI is sent.
*/
static void
@@ -475,7 +451,7 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* PLOGI is complete. Awaiting BFA rport online callback. FC-4s
* are offline.
*/
@@ -498,28 +474,28 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_LOGO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_LOGO_IMP:
case RPSM_EVENT_ADDRESS_CHANGE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_PLOGI_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
bfa_fcs_rport_send_plogiacc(rport, NULL);
break;
case RPSM_EVENT_DELETE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_SCN:
- /**
+ /*
* @todo
* Ignore SCN - PLOGI just completed, FC-4 login should detect
* device failures.
@@ -531,7 +507,7 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is ONLINE. FC-4s active.
*/
static void
@@ -580,7 +556,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* An SCN event is received in ONLINE state. NS query is being sent
* prior to ADISC authentication with rport. FC-4s are paused.
*/
@@ -604,7 +580,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_SCN:
- /**
+ /*
* ignore SCN, wait for response to query itself
*/
break;
@@ -638,7 +614,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* An SCN event is received in ONLINE state. NS query is sent to rport.
* FC-4s are paused.
*/
@@ -697,7 +673,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* An SCN event is received in ONLINE state. ADISC is being sent for
* authenticating with rport. FC-4s are paused.
*/
@@ -748,7 +724,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* An SCN event is received in ONLINE state. ADISC is to rport.
* FC-4s are paused.
*/
@@ -765,7 +741,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_PLOGI_RCVD:
- /**
+ /*
* Too complex to cleanup FC-4 & rport and then acc to PLOGI.
* At least go offline when a PLOGI is received.
*/
@@ -787,7 +763,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_SCN:
- /**
+ /*
* already processing RSCN
*/
break;
@@ -810,7 +786,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* Rport has sent LOGO. Awaiting FC-4 offline completion callback.
*/
static void
@@ -824,7 +800,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_DELETE:
@@ -841,7 +817,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* LOGO needs to be sent to rport. Awaiting FC-4 offline completion
* callback.
*/
@@ -856,7 +832,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
default:
@@ -864,7 +840,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is going offline. Awaiting FC-4 offline completion callback.
*/
static void
@@ -878,7 +854,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
switch (event) {
case RPSM_EVENT_FC4_OFFLINE:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
- bfa_rport_offline(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE);
break;
case RPSM_EVENT_SCN:
@@ -886,7 +862,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_LOGO_RCVD:
case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_ADDRESS_CHANGE:
- /**
+ /*
* rport is already going offline.
* SCN - ignore and wait till transitioning to offline state
*/
@@ -901,7 +877,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is offline. FC-4s are offline. Awaiting BFA rport offline
* callback.
*/
@@ -945,7 +921,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_SCN:
case RPSM_EVENT_LOGO_RCVD:
case RPSM_EVENT_PRLO_RCVD:
- /**
+ /*
* Ignore, already offline.
*/
break;
@@ -955,7 +931,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is offline. FC-4s are offline. Awaiting BFA rport offline
* callback to send LOGO accept.
*/
@@ -1009,7 +985,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_LOGO_RCVD:
case RPSM_EVENT_PRLO_RCVD:
- /**
+ /*
* Ignore - already processing a LOGO.
*/
break;
@@ -1019,7 +995,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is being deleted. FC-4s are offline.
* Awaiting BFA rport offline
* callback to send LOGO.
@@ -1048,7 +1024,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is being deleted. FC-4s are offline. LOGO is being sent.
*/
static void
@@ -1082,7 +1058,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport is offline. FC-4s are offline. BFA rport is offline.
* Timer active to delete stale rport.
*/
@@ -1142,7 +1118,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
}
}
-/**
+/*
* Rport address has changed. Nameserver discovery request is being sent.
*/
static void
@@ -1199,7 +1175,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Nameserver discovery failed. Waiting for timeout to retry.
*/
static void
@@ -1263,7 +1239,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
}
}
-/**
+/*
* Rport address has changed. Nameserver discovery request is sent.
*/
static void
@@ -1329,13 +1305,13 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
bfa_fcs_rport_send_prlo_acc(rport);
break;
case RPSM_EVENT_SCN:
- /**
+ /*
* ignore, wait for NS query response
*/
break;
case RPSM_EVENT_LOGO_RCVD:
- /**
+ /*
* Not logged-in yet. Accept LOGO.
*/
bfa_fcs_rport_send_logo_acc(rport);
@@ -1354,7 +1330,7 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
-/**
+/*
* fcs_rport_private FCS RPORT provate functions
*/
@@ -1415,7 +1391,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp);
- /**
+ /*
* Check for failure first.
*/
if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) {
@@ -1436,7 +1412,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
return;
}
- /**
+ /*
* PLOGI is complete. Make sure this device is not one of the known
* device with a new FC port address.
*/
@@ -1459,7 +1435,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
twin->stats.plogi_rcvd += rport->stats.plogi_rcvd;
twin->stats.plogi_accs++;
- bfa_fcs_rport_delete(rport);
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
bfa_fcs_rport_update(twin, plogi_rsp);
twin->pid = rsp_fchs->s_id;
@@ -1468,7 +1444,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
}
}
- /**
+ /*
* Normal login path -- no evil twins.
*/
rport->stats.plogi_accs++;
@@ -1621,7 +1597,7 @@ bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
bfa_trc(rport->fcs, rport->pwwn);
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
/* Check if the pid is the same as before. */
@@ -1691,7 +1667,7 @@ bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
bfa_trc(rport->fcs, rport->pwwn);
cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
- cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+ cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
@@ -1722,7 +1698,7 @@ bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
}
}
-/**
+/*
* Called to send a logout to the rport.
*/
static void
@@ -1759,7 +1735,7 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
}
-/**
+/*
* Send ACC for a LOGO received.
*/
static void
@@ -1788,7 +1764,7 @@ bfa_fcs_rport_send_logo_acc(void *rport_cbarg)
FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
}
-/**
+/*
* brief
* This routine will be called by bfa_timer on timer timeouts.
*
@@ -1961,7 +1937,7 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
struct bfa_fcs_rport_s *rport;
struct bfad_rport_s *rport_drv;
- /**
+ /*
* allocate rport
*/
if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv)
@@ -1979,7 +1955,7 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
rport->pid = rpid;
rport->pwwn = pwwn;
- /**
+ /*
* allocate BFA rport
*/
rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport);
@@ -1989,16 +1965,17 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
return NULL;
}
- /**
+ /*
* allocate FC-4s
*/
- bfa_assert(bfa_fcs_lport_is_initiator(port));
+ WARN_ON(!bfa_fcs_lport_is_initiator(port));
if (bfa_fcs_lport_is_initiator(port)) {
rport->itnim = bfa_fcs_itnim_create(rport);
if (!rport->itnim) {
bfa_trc(fcs, rpid);
- bfa_rport_delete(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport,
+ BFA_RPORT_SM_DELETE);
kfree(rport_drv);
return NULL;
}
@@ -2021,7 +1998,7 @@ bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
{
struct bfa_fcs_lport_s *port = rport->port;
- /**
+ /*
* - delete FC-4s
* - delete BFA rport
* - remove from queue of rports
@@ -2032,7 +2009,7 @@ bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
bfa_fcs_rpf_rport_offline(rport);
}
- bfa_rport_delete(rport->bfa_rport);
+ bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_DELETE);
bfa_fcs_lport_del_rport(port, rport);
kfree(rport->rp_drv);
}
@@ -2056,7 +2033,7 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) online for logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
}
@@ -2075,12 +2052,12 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Remote port (WWN = %s) connectivity lost for "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) offlined by "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
@@ -2093,7 +2070,7 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
}
}
-/**
+/*
* Update rport parameters from PLOGI or PLOGI accept.
*/
static void
@@ -2101,14 +2078,14 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
{
bfa_fcs_lport_t *port = rport->port;
- /**
+ /*
* - port name
* - node name
*/
rport->pwwn = plogi->port_name;
rport->nwwn = plogi->node_name;
- /**
+ /*
* - class of service
*/
rport->fc_cos = 0;
@@ -2118,16 +2095,16 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
if (plogi->class2.class_valid)
rport->fc_cos |= FC_CLASS_2;
- /**
+ /*
* - CISC
* - MAX receive frame size
*/
rport->cisc = plogi->csp.cisc;
- rport->maxfrsize = bfa_os_ntohs(plogi->class3.rxsz);
+ rport->maxfrsize = be16_to_cpu(plogi->class3.rxsz);
- bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred));
bfa_trc(port->fcs, port->fabric->bb_credit);
- /**
+ /*
* Direct Attach P2P mode :
* This is to handle a bug (233476) in IBM targets in Direct Attach
* Mode. Basically, in FLOGI Accept the target would have
@@ -2136,19 +2113,19 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
* in PLOGI.
*/
if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
- (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) {
+ (be16_to_cpu(plogi->csp.bbcred) < port->fabric->bb_credit)) {
- bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred));
bfa_trc(port->fcs, port->fabric->bb_credit);
- port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred);
+ port->fabric->bb_credit = be16_to_cpu(plogi->csp.bbcred);
bfa_fcport_set_tx_bbcredit(port->fcs->bfa,
port->fabric->bb_credit);
}
}
-/**
+/*
* Called to handle LOGO received from an existing remote port.
*/
static void
@@ -2164,11 +2141,11 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs)
-/**
+/*
* fcs_rport_public FCS rport public interfaces
*/
-/**
+/*
* Called by bport/vport to create a remote port instance for a discovered
* remote device.
*
@@ -2191,7 +2168,7 @@ bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, u32 rpid)
return rport;
}
-/**
+/*
* Called to create a rport for which only the wwn is known.
*
* @param[in] port - base port
@@ -2211,7 +2188,7 @@ bfa_fcs_rport_create_by_wwn(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC);
return rport;
}
-/**
+/*
* Called by bport in private loop topology to indicate that a
* rport has been discovered and plogi has been completed.
*
@@ -2233,7 +2210,7 @@ bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *fchs,
bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP);
}
-/**
+/*
* Called by bport/vport to handle PLOGI received from a new remote port.
* If an existing rport does a plogi, it will be handled separately.
*/
@@ -2272,7 +2249,7 @@ wwn_compare(wwn_t wwn1, wwn_t wwn2)
return 0;
}
-/**
+/*
* Called by bport/vport to handle PLOGI received from an existing
* remote port.
*/
@@ -2280,7 +2257,7 @@ void
bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
struct fc_logi_s *plogi)
{
- /**
+ /*
* @todo Handle P2P and initiator-initiator.
*/
@@ -2289,7 +2266,7 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
rport->reply_oxid = rx_fchs->ox_id;
bfa_trc(rport->fcs, rport->reply_oxid);
- /**
+ /*
* In Switched fabric topology,
* PLOGI to each other. If our pwwn is smaller, ignore it,
* if it is not a well known address.
@@ -2307,40 +2284,8 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
}
-/**
- * Called by bport/vport to delete a remote port instance.
- *
- * Rport delete is called under the following conditions:
- * - vport is deleted
- * - vf is deleted
- * - explicit request from OS to delete rport
- */
-void
-bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
-}
-
-/**
- * Called by bport/vport to when a target goes offline.
- *
- */
-void
-bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
-}
-/**
- * Called by bport in n2n when a target (attached port) becomes online.
- *
- */
-void
-bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
-}
-/**
+/*
* Called by bport/vport to notify SCN for the remote port
*/
void
@@ -2350,25 +2295,8 @@ bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport)
bfa_sm_send_event(rport, RPSM_EVENT_SCN);
}
-/**
- * Called by fcpim to notify that the ITN cleanup is done.
- */
-void
-bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
-}
-
-/**
- * Called by fcptm to notify that the ITN cleanup is done.
- */
-void
-bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
-}
-/**
+/*
* brief
* This routine BFA callback for bfa_rport_online() call.
*
@@ -2391,7 +2319,7 @@ bfa_cb_rport_online(void *cbarg)
bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE);
}
-/**
+/*
* brief
* This routine BFA callback for bfa_rport_offline() call.
*
@@ -2413,7 +2341,7 @@ bfa_cb_rport_offline(void *cbarg)
bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE);
}
-/**
+/*
* brief
* This routine is a static BFA callback when there is a QoS flow_id
* change notification
@@ -2437,7 +2365,7 @@ bfa_cb_rport_qos_scn_flowid(void *cbarg,
bfa_trc(rport->fcs, rport->pwwn);
}
-/**
+/*
* brief
* This routine is a static BFA callback when there is a QoS priority
* change notification
@@ -2461,16 +2389,7 @@ bfa_cb_rport_qos_scn_prio(void *cbarg,
bfa_trc(rport->fcs, rport->pwwn);
}
-/**
- * Called to process any unsolicted frames from this remote port
- */
-void
-bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport)
-{
- bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
-}
-
-/**
+/*
* Called to process any unsolicted frames from this remote port
*/
void
@@ -2577,7 +2496,7 @@ bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
FC_MAX_PDUSZ, 0);
}
-/**
+/*
* Return state of rport.
*/
int
@@ -2586,7 +2505,8 @@ bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport)
return bfa_sm_to_state(rport_sm_table, rport->sm);
}
-/**
+
+/*
* brief
* Called by the Driver to set rport delete/ageout timeout
*
@@ -2602,7 +2522,7 @@ bfa_fcs_rport_set_del_timeout(u8 rport_tmo)
bfa_fcs_rport_del_timeout = rport_tmo * 1000;
}
void
-bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id)
+bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id)
{
bfa_trc(rport->fcs, rport->pid);
@@ -2613,114 +2533,14 @@ bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id)
-/**
+/*
* Remote port implementation.
*/
-/**
+/*
* fcs_rport_api FCS rport API.
*/
-/**
- * Direct API to add a target by port wwn. This interface is used, for
- * example, by bios when target pwwn is known from boot lun configuration.
- */
-bfa_status_t
-bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
- struct bfa_fcs_rport_s *rport, struct bfad_rport_s *rport_drv)
-{
- bfa_trc(port->fcs, *pwwn);
-
- return BFA_STATUS_OK;
-}
-
-/**
- * Direct API to remove a target and its associated resources. This
- * interface is used, for example, by driver to remove target
- * ports from the target list for a VM.
- */
-bfa_status_t
-bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
-{
-
- struct bfa_fcs_rport_s *rport;
-
- bfa_trc(rport_in->fcs, rport_in->pwwn);
-
- rport = bfa_fcs_lport_get_rport_by_pwwn(rport_in->port, rport_in->pwwn);
- if (rport == NULL) {
- /*
- * TBD Error handling
- */
- bfa_trc(rport_in->fcs, rport_in->pid);
- return BFA_STATUS_UNKNOWN_RWWN;
- }
-
- /*
- * TBD if this remote port is online, send a logo
- */
- return BFA_STATUS_OK;
-
-}
-
-/**
- * Remote device status for display/debug.
- */
-void
-bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_attr_s *rport_attr)
-{
- struct bfa_rport_qos_attr_s qos_attr;
- bfa_fcs_lport_t *port = rport->port;
- bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed;
-
- bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
-
- rport_attr->pid = rport->pid;
- rport_attr->pwwn = rport->pwwn;
- rport_attr->nwwn = rport->nwwn;
- rport_attr->cos_supported = rport->fc_cos;
- rport_attr->df_sz = rport->maxfrsize;
- rport_attr->state = bfa_fcs_rport_get_state(rport);
- rport_attr->fc_cos = rport->fc_cos;
- rport_attr->cisc = rport->cisc;
- rport_attr->scsi_function = rport->scsi_function;
- rport_attr->curr_speed = rport->rpf.rpsc_speed;
- rport_attr->assigned_speed = rport->rpf.assigned_speed;
-
- bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr);
- rport_attr->qos_attr = qos_attr;
-
- rport_attr->trl_enforced = BFA_FALSE;
- if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
- if (rport_speed == BFA_PORT_SPEED_UNKNOWN) {
- /* Use default ratelim speed setting */
- rport_speed =
- bfa_fcport_get_ratelim_speed(rport->fcs->bfa);
- }
-
- if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port))
- rport_attr->trl_enforced = BFA_TRUE;
- }
-}
-
-/**
- * Per remote device statistics.
- */
-void
-bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
- struct bfa_rport_stats_s *stats)
-{
- *stats = rport->stats;
-}
-
-void
-bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
-{
- bfa_os_memset((char *)&rport->stats, 0,
- sizeof(struct bfa_rport_stats_s));
-}
-
struct bfa_fcs_rport_s *
bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
{
@@ -2752,22 +2572,6 @@ bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t rnwwn)
}
/*
- * This API is to set the Rport's speed. Should be used when RPSC is not
- * supported by the rport.
- */
-void
-bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, bfa_port_speed_t speed)
-{
- rport->rpf.assigned_speed = speed;
-
- /* Set this speed in f/w only if the RPSC speed is not available */
- if (rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN)
- bfa_rport_speed(rport->bfa_rport, speed);
-}
-
-
-
-/**
* Remote port features (RPF) implementation.
*/
@@ -2786,7 +2590,7 @@ static void bfa_fcs_rpf_rpsc2_response(void *fcsarg,
static void bfa_fcs_rpf_timeout(void *arg);
-/**
+/*
* fcs_rport_ftrs_sm FCS rport state machine events
*/
@@ -2827,7 +2631,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
case RPFSM_EVENT_RPORT_ONLINE:
/* Send RPSC2 to a Brocade fabric only. */
if ((!BFA_FCS_PID_IS_WKA(rport->pid)) &&
- ((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) ||
+ ((rport->port->fabric->lps->brcd_switch) ||
(bfa_fcs_fabric_get_switch_oui(fabric) ==
BFA_FCS_BRCD_SWITCH_OUI))) {
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
@@ -2981,7 +2785,7 @@ bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_sm_fault(rport->fcs, event);
}
}
-/**
+/*
* Called when Rport is created.
*/
void
@@ -2995,7 +2799,7 @@ bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport)
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit);
}
-/**
+/*
* Called when Rport becomes online
*/
void
@@ -3010,7 +2814,7 @@ bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport)
bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE);
}
-/**
+/*
* Called when Rport becomes offline
*/
void
@@ -3090,16 +2894,16 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp);
if (rpsc2_acc->els_cmd == FC_ELS_ACC) {
rport->stats.rpsc_accs++;
- num_ents = bfa_os_ntohs(rpsc2_acc->num_pids);
+ num_ents = be16_to_cpu(rpsc2_acc->num_pids);
bfa_trc(rport->fcs, num_ents);
if (num_ents > 0) {
- bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid);
+ WARN_ON(rpsc2_acc->port_info[0].pid == rport->pid);
bfa_trc(rport->fcs,
- bfa_os_ntohs(rpsc2_acc->port_info[0].pid));
+ be16_to_cpu(rpsc2_acc->port_info[0].pid));
bfa_trc(rport->fcs,
- bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+ be16_to_cpu(rpsc2_acc->port_info[0].speed));
bfa_trc(rport->fcs,
- bfa_os_ntohs(rpsc2_acc->port_info[0].index));
+ be16_to_cpu(rpsc2_acc->port_info[0].index));
bfa_trc(rport->fcs,
rpsc2_acc->port_info[0].type);
@@ -3109,7 +2913,7 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
}
rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed(
- bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+ be16_to_cpu(rpsc2_acc->port_info[0].speed));
bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP);
}
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index c787d3af0886..977e681ec803 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -15,6 +15,7 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_cbreg.h"
@@ -22,7 +23,7 @@ void
bfa_hwcb_reginit(struct bfa_s *bfa)
{
struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
- bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
if (fn == 0) {
@@ -60,8 +61,8 @@ bfa_hwcb_reqq_ack(struct bfa_s *bfa, int reqq)
static void
bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
{
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
- __HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq));
+ writel(__HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq),
+ bfa->iocfc.bfa_regs.intr_status);
}
void
@@ -72,8 +73,8 @@ bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
static void
bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
{
- bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
- __HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq));
+ writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq),
+ bfa->iocfc.bfa_regs.intr_status);
}
void
@@ -102,7 +103,7 @@ bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
*num_vecs = __HFN_NUMINTS;
}
-/**
+/*
* No special setup required for crossbow -- vector assignments are implicit.
*/
void
@@ -110,7 +111,7 @@ bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
{
int i;
- bfa_assert((nvecs == 1) || (nvecs == __HFN_NUMINTS));
+ WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS));
bfa->msix.nvecs = nvecs;
if (nvecs == 1) {
@@ -129,7 +130,7 @@ bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
bfa->msix.handler[i] = bfa_msix_lpu_err;
}
-/**
+/*
* Crossbow -- dummy, interrupts are masked
*/
void
@@ -142,7 +143,7 @@ bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
{
}
-/**
+/*
* No special enable/disable -- vector assignments are implicit.
*/
void
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index c97ebafec5ea..21018d98a07b 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -15,6 +15,7 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_modules.h"
#include "bfi_ctreg.h"
@@ -31,15 +32,15 @@ static void
bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec)
{
int fn = bfa_ioc_pcifn(&bfa->ioc);
- bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
if (msix)
- bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], vec);
+ writel(vec, kva + __ct_msix_err_vec_reg[fn]);
else
- bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], 0);
+ writel(0, kva + __ct_msix_err_vec_reg[fn]);
}
-/**
+/*
* Dummy interrupt handler for handling spurious interrupt during chip-reinit.
*/
static void
@@ -51,7 +52,7 @@ void
bfa_hwct_reginit(struct bfa_s *bfa)
{
struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
- bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
if (fn == 0) {
@@ -88,8 +89,8 @@ bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq)
{
u32 r32;
- r32 = bfa_reg_read(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
- bfa_reg_write(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq], r32);
+ r32 = readl(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
+ writel(r32, bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
}
void
@@ -97,8 +98,8 @@ bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
{
u32 r32;
- r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
- bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32);
+ r32 = readl(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+ writel(r32, bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
}
void
@@ -110,13 +111,13 @@ bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
*num_vecs = BFA_MSIX_CT_MAX;
}
-/**
+/*
* Setup MSI-X vector for catapult
*/
void
bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs)
{
- bfa_assert((nvecs == 1) || (nvecs == BFA_MSIX_CT_MAX));
+ WARN_ON((nvecs != 1) && (nvecs != BFA_MSIX_CT_MAX));
bfa_trc(bfa, nvecs);
bfa->msix.nvecs = nvecs;
@@ -143,7 +144,7 @@ bfa_hwct_msix_install(struct bfa_s *bfa)
for (; i <= BFA_MSIX_RME_Q3; i++)
bfa->msix.handler[i] = bfa_msix_rspq;
- bfa_assert(i == BFA_MSIX_LPU_ERR);
+ WARN_ON(i != BFA_MSIX_LPU_ERR);
bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err;
}
@@ -156,7 +157,7 @@ bfa_hwct_msix_uninstall(struct bfa_s *bfa)
bfa->msix.handler[i] = bfa_hwct_msix_dummy;
}
-/**
+/*
* Enable MSI-X vectors
*/
void
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 6795b247791a..c1f72c49196f 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -15,21 +15,21 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_ctreg.h"
#include "bfa_defs.h"
#include "bfa_defs_svc.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(CNA, IOC);
-/**
+/*
* IOC local definitions
*/
#define BFA_IOC_TOV 3000 /* msecs */
#define BFA_IOC_HWSEM_TOV 500 /* msecs */
#define BFA_IOC_HB_TOV 500 /* msecs */
-#define BFA_IOC_HWINIT_MAX 2
+#define BFA_IOC_HWINIT_MAX 5
#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV
#define bfa_ioc_timer_start(__ioc) \
@@ -42,14 +42,9 @@ BFA_TRC_FILE(CNA, IOC);
bfa_ioc_hb_check, (__ioc), BFA_IOC_HB_TOV)
#define bfa_hb_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->hb_timer)
-#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
-#define BFA_DBG_FWTRC_LEN \
- (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
- (sizeof(struct bfa_trc_mod_s) - \
- BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
-/**
+/*
* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
*/
@@ -59,21 +54,20 @@ BFA_TRC_FILE(CNA, IOC);
((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
-#define bfa_ioc_notify_hbfail(__ioc) \
- ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
-
-#ifdef BFA_IOC_IS_UEFI
-#define bfa_ioc_is_bios_optrom(__ioc) (0)
-#define bfa_ioc_is_uefi(__ioc) BFA_IOC_IS_UEFI
-#else
-#define bfa_ioc_is_bios_optrom(__ioc) \
- (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
-#define bfa_ioc_is_uefi(__ioc) (0)
-#endif
+#define bfa_ioc_notify_fail(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
+#define bfa_ioc_sync_join(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
+#define bfa_ioc_sync_leave(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))
+#define bfa_ioc_sync_ack(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
+#define bfa_ioc_sync_complete(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
#define bfa_ioc_mbox_cmd_pending(__ioc) \
(!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
- bfa_reg_read((__ioc)->ioc_regs.hfn_mbox_cmd))
+ readl((__ioc)->ioc_regs.hfn_mbox_cmd))
bfa_boolean_t bfa_auto_recover = BFA_TRUE;
@@ -81,31 +75,24 @@ bfa_boolean_t bfa_auto_recover = BFA_TRUE;
* forward declarations
*/
static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
-static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
static void bfa_ioc_timeout(void *ioc);
static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);
static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);
static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);
static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);
-static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc);
-static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc);
static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc);
-static void bfa_ioc_pf_failed(struct bfa_ioc_s *ioc);
+static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc);
+static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc);
static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc);
-/**
- * hal_ioc_sm
- */
-/**
+/*
* IOC state machine definitions/declarations
*/
enum ioc_event {
@@ -116,10 +103,11 @@ enum ioc_event {
IOC_E_ENABLED = 5, /* f/w enabled */
IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */
IOC_E_DISABLED = 7, /* f/w disabled */
- IOC_E_FAILED = 8, /* failure notice by iocpf sm */
- IOC_E_HBFAIL = 9, /* heartbeat failure */
- IOC_E_HWERROR = 10, /* hardware error interrupt */
- IOC_E_TIMEOUT = 11, /* timeout */
+ IOC_E_INITFAILED = 8, /* failure notice by iocpf sm */
+ IOC_E_PFFAILED = 9, /* failure notice by iocpf sm */
+ IOC_E_HBFAIL = 10, /* heartbeat failure */
+ IOC_E_HWERROR = 11, /* hardware error interrupt */
+ IOC_E_TIMEOUT = 12, /* timeout */
};
bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event);
@@ -127,7 +115,7 @@ bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
@@ -138,13 +126,13 @@ static struct bfa_sm_table_s ioc_sm_table[] = {
{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},
{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
- {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},
{BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
};
-/**
+/*
* IOCPF state machine definitions/declarations
*/
@@ -165,16 +153,10 @@ static struct bfa_sm_table_s ioc_sm_table[] = {
/*
* Forward declareations for iocpf state machine
*/
-static void bfa_iocpf_enable(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_disable(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_fail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_initfail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc);
-static void bfa_iocpf_stop(struct bfa_ioc_s *ioc);
static void bfa_iocpf_timeout(void *ioc_arg);
static void bfa_iocpf_sem_timeout(void *ioc_arg);
-/**
+/*
* IOCPF state machine events
*/
enum iocpf_event {
@@ -191,7 +173,7 @@ enum iocpf_event {
IOCPF_E_TIMEOUT = 11, /* f/w response timeout */
};
-/**
+/*
* IOCPF states
*/
enum bfa_iocpf_state {
@@ -213,9 +195,14 @@ bfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf_s,
+ enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf_s, enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf_s, enum iocpf_event);
+bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf_s,
+ enum iocpf_event);
bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event);
static struct bfa_sm_table_s iocpf_sm_table[] = {
@@ -226,17 +213,20 @@ static struct bfa_sm_table_s iocpf_sm_table[] = {
{BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},
{BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},
{BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},
+ {BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},
{BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},
+ {BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},
{BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},
{BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},
+ {BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},
{BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
};
-/**
+/*
* IOC State Machine
*/
-/**
+/*
* Beginning state. IOC uninit state.
*/
@@ -245,7 +235,7 @@ bfa_ioc_sm_uninit_entry(struct bfa_ioc_s *ioc)
{
}
-/**
+/*
* IOC is in uninit state.
*/
static void
@@ -262,7 +252,7 @@ bfa_ioc_sm_uninit(struct bfa_ioc_s *ioc, enum ioc_event event)
bfa_sm_fault(ioc, event);
}
}
-/**
+/*
* Reset entry actions -- initialize state machine
*/
static void
@@ -271,7 +261,7 @@ bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)
bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);
}
-/**
+/*
* IOC is in reset state.
*/
static void
@@ -301,10 +291,10 @@ bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event)
static void
bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
{
- bfa_iocpf_enable(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
}
-/**
+/*
* Host IOC function is being enabled, awaiting response from firmware.
* Semaphore is acquired.
*/
@@ -318,13 +308,13 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
break;
- case IOC_E_FAILED:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- break;
-
+ case IOC_E_PFFAILED:
+ /* !!! fall through !!! */
case IOC_E_HWERROR:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- bfa_iocpf_initfail(ioc);
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
break;
case IOC_E_DISABLE:
@@ -333,7 +323,7 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
case IOC_E_ENABLE:
@@ -352,7 +342,7 @@ bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)
bfa_ioc_send_getattr(ioc);
}
-/**
+/*
* IOC configuration in progress. Timer is active.
*/
static void
@@ -367,18 +357,16 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)
bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
break;
- case IOC_E_FAILED:
- bfa_ioc_timer_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
break;
-
+ case IOC_E_PFFAILED:
case IOC_E_HWERROR:
bfa_ioc_timer_stop(ioc);
- /* fall through */
-
+ /* !!! fall through !!! */
case IOC_E_TIMEOUT:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
- bfa_iocpf_getattrfail(ioc);
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
break;
case IOC_E_DISABLE:
@@ -402,7 +390,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
bfa_ioc_hb_monitor(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC enabled\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
}
static void
@@ -415,22 +403,24 @@ bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event)
break;
case IOC_E_DISABLE:
- bfa_ioc_hb_stop(ioc);
+ bfa_hb_timer_stop(ioc);
bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
- case IOC_E_FAILED:
- bfa_ioc_hb_stop(ioc);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
- break;
-
+ case IOC_E_PFFAILED:
case IOC_E_HWERROR:
- bfa_ioc_hb_stop(ioc);
+ bfa_hb_timer_stop(ioc);
/* !!! fall through !!! */
-
case IOC_E_HBFAIL:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
- bfa_iocpf_fail(ioc);
+ bfa_ioc_fail_notify(ioc);
+
+ if (ioc->iocpf.auto_recover)
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ else
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
break;
default:
@@ -443,11 +433,11 @@ static void
bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
{
struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
- bfa_iocpf_disable(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n");
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");
}
-/**
+/*
* IOC is being disabled
*/
static void
@@ -466,7 +456,7 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
* after iocpf sm completes failure processing and
* moves to disabled state.
*/
- bfa_iocpf_fail(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
break;
default:
@@ -474,7 +464,7 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
}
}
-/**
+/*
* IOC disable completion entry.
*/
static void
@@ -499,7 +489,7 @@ bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
default:
@@ -509,16 +499,16 @@ bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)
static void
-bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
+bfa_ioc_sm_fail_retry_entry(struct bfa_ioc_s *ioc)
{
- ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_trc(ioc, 0);
}
-/**
- * Hardware initialization failed.
+/*
+ * Hardware initialization retry.
*/
static void
-bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event)
{
bfa_trc(ioc, event);
@@ -527,11 +517,21 @@ bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
break;
- case IOC_E_FAILED:
- /**
- * Initialization failure during iocpf init retry.
+ case IOC_E_PFFAILED:
+ case IOC_E_HWERROR:
+ /*
+ * Initialization retry failed.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ if (event != IOC_E_PFFAILED)
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
+ break;
+
+ case IOC_E_INITFAILED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+ break;
+
+ case IOC_E_ENABLE:
break;
case IOC_E_DISABLE:
@@ -540,7 +540,7 @@ bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
case IOC_E_DETACH:
bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
- bfa_iocpf_stop(ioc);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
break;
default:
@@ -552,24 +552,10 @@ bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
static void
bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc)
{
- struct list_head *qe;
- struct bfa_ioc_hbfail_notify_s *notify;
- struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
-
- /**
- * Notify driver and common modules registered for notification.
- */
- ioc->cbfn->hbfail_cbfn(ioc->bfa);
- list_for_each(qe, &ioc->hb_notify_q) {
- notify = (struct bfa_ioc_hbfail_notify_s *) qe;
- notify->cbfn(notify->cbarg);
- }
-
- BFA_LOG(KERN_CRIT, bfad, log_level,
- "Heart Beat of IOC has failed\n");
+ bfa_trc(ioc, 0);
}
-/**
+/*
* IOC failure.
*/
static void
@@ -579,23 +565,19 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)
switch (event) {
- case IOC_E_FAILED:
- /**
- * Initialization failure during iocpf recovery.
- * !!! Fall through !!!
- */
case IOC_E_ENABLE:
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
break;
- case IOC_E_ENABLED:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
- break;
-
case IOC_E_DISABLE:
bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
+ break;
+
case IOC_E_HWERROR:
/*
* HB failure notification, ignore.
@@ -606,14 +588,11 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)
}
}
-
-
-/**
+/*
* IOCPF State Machine
*/
-
-/**
+/*
* Reset entry actions -- initialize state machine
*/
static void
@@ -623,7 +602,7 @@ bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf)
iocpf->auto_recover = bfa_auto_recover;
}
-/**
+/*
* Beginning state. IOC is in reset state.
*/
static void
@@ -646,7 +625,7 @@ bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-/**
+/*
* Semaphore should be acquired for version check.
*/
static void
@@ -655,7 +634,7 @@ bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf)
bfa_ioc_hw_sem_get(iocpf->ioc);
}
-/**
+/*
* Awaiting h/w semaphore to continue with version check.
*/
static void
@@ -668,22 +647,29 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_SEMLOCKED:
if (bfa_ioc_firmware_lock(ioc)) {
- iocpf->retry_count = 0;
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ if (bfa_ioc_sync_complete(ioc)) {
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ bfa_ioc_firmware_unlock(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_sem_timer_start(ioc);
+ }
} else {
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);
}
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_sem_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
- bfa_ioc_pf_disabled(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLED);
break;
case IOCPF_E_STOP:
- bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_sem_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
@@ -692,7 +678,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-/**
+/*
* Notify enable completion callback.
*/
static void
@@ -708,7 +694,7 @@ bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf)
bfa_iocpf_timer_start(iocpf->ioc);
}
-/**
+/*
* Awaiting firmware version match.
*/
static void
@@ -726,7 +712,7 @@ bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
case IOCPF_E_DISABLE:
bfa_iocpf_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
- bfa_ioc_pf_disabled(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLED);
break;
case IOCPF_E_STOP:
@@ -739,7 +725,7 @@ bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-/**
+/*
* Request for semaphore.
*/
static void
@@ -748,7 +734,7 @@ bfa_iocpf_sm_semwait_entry(struct bfa_iocpf_s *iocpf)
bfa_ioc_hw_sem_get(iocpf->ioc);
}
-/**
+/*
* Awaiting semaphore for h/w initialzation.
*/
static void
@@ -760,13 +746,18 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_SEMLOCKED:
- iocpf->retry_count = 0;
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ if (bfa_ioc_sync_complete(ioc)) {
+ bfa_ioc_sync_join(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ } else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_sem_timer_start(ioc);
+ }
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_get_cancel(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
default:
@@ -774,15 +765,14 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-
static void
bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf)
{
bfa_iocpf_timer_start(iocpf->ioc);
- bfa_ioc_reset(iocpf->ioc, BFA_FALSE);
+ bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE);
}
-/**
+/*
* Hardware is being initialized. Interrupts are enabled.
* Holding hardware semaphore lock.
*/
@@ -806,23 +796,16 @@ bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
*/
case IOCPF_E_TIMEOUT:
- iocpf->retry_count++;
- if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) {
- bfa_iocpf_timer_start(ioc);
- bfa_ioc_reset(ioc, BFA_TRUE);
- break;
- }
-
- bfa_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
if (event == IOCPF_E_TIMEOUT)
- bfa_ioc_pf_failed(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_DISABLE:
- bfa_ioc_hw_sem_release(ioc);
bfa_iocpf_timer_stop(ioc);
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
@@ -831,7 +814,6 @@ bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-
static void
bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf)
{
@@ -839,7 +821,7 @@ bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf)
bfa_ioc_send_enable(iocpf->ioc);
}
-/**
+/*
* Host IOC function is being enabled, awaiting response from firmware.
* Semaphore is acquired.
*/
@@ -853,7 +835,7 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_FWRSP_ENABLE:
bfa_iocpf_timer_stop(ioc);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);
break;
@@ -864,24 +846,15 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
*/
case IOCPF_E_TIMEOUT:
- iocpf->retry_count++;
- if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) {
- bfa_reg_write(ioc->ioc_regs.ioc_fwstate,
- BFI_IOC_UNINIT);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
- break;
- }
-
- bfa_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
if (event == IOCPF_E_TIMEOUT)
- bfa_ioc_pf_failed(ioc);
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_DISABLE:
bfa_iocpf_timer_stop(ioc);
- bfa_ioc_hw_sem_release(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
break;
@@ -894,12 +867,10 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-
-
static void
bfa_iocpf_sm_ready_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_ioc_pf_enabled(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_ENABLED);
}
static void
@@ -915,20 +886,21 @@ bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
break;
case IOCPF_E_GETATTRFAIL:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
case IOCPF_E_FAIL:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
break;
case IOCPF_E_FWREADY:
- if (bfa_ioc_is_operational(ioc))
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
- else
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
-
- bfa_ioc_pf_failed(ioc);
+ if (bfa_ioc_is_operational(ioc)) {
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
+ } else {
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
+ }
break;
default:
@@ -936,7 +908,6 @@ bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-
static void
bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf)
{
@@ -944,7 +915,7 @@ bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf)
bfa_ioc_send_disable(iocpf->ioc);
}
-/**
+/*
* IOC is being disabled
*/
static void
@@ -958,7 +929,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
case IOCPF_E_FWRSP_DISABLE:
case IOCPF_E_FWREADY:
bfa_iocpf_timer_stop(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
case IOCPF_E_FAIL:
@@ -968,8 +939,8 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
*/
case IOCPF_E_TIMEOUT:
- bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
case IOCPF_E_FWRSP_ENABLE:
@@ -980,13 +951,44 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
-/**
+static void
+bfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf_s *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/*
+ * IOC hb ack request is being removed.
+ */
+static void
+bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ break;
+
+ case IOCPF_E_FAIL:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/*
* IOC disable completion entry.
*/
static void
bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_ioc_pf_disabled(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED);
}
static void
@@ -998,6 +1000,7 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_ENABLE:
+ iocpf->retry_count = 0;
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
break;
@@ -1011,14 +1014,67 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
+static void
+bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf)
+{
+ bfa_ioc_hw_sem_get(iocpf->ioc);
+}
+
+/*
+ * Hardware initialization failed.
+ */
+static void
+bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ bfa_ioc_notify_fail(ioc);
+ bfa_ioc_sync_ack(ioc);
+ iocpf->retry_count++;
+ if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
+ break;
+
+ case IOCPF_E_DISABLE:
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
+ break;
+
+ case IOCPF_E_STOP:
+ bfa_sem_timer_stop(ioc);
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
+ break;
+
+ case IOCPF_E_FAIL:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
static void
bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf)
{
- bfa_iocpf_timer_start(iocpf->ioc);
+ bfa_fsm_send_event(iocpf->ioc, IOC_E_INITFAILED);
}
-/**
+/*
* Hardware initialization failed.
*/
static void
@@ -1030,68 +1086,67 @@ bfa_iocpf_sm_initfail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_DISABLE:
- bfa_iocpf_timer_stop(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
case IOCPF_E_STOP:
- bfa_iocpf_timer_stop(ioc);
bfa_ioc_firmware_unlock(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
break;
- case IOCPF_E_TIMEOUT:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
- break;
-
default:
bfa_sm_fault(ioc, event);
}
}
-
static void
-bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
+bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf)
{
- /**
+ /*
* Mark IOC as failed in hardware and stop firmware.
*/
bfa_ioc_lpu_stop(iocpf->ioc);
- bfa_reg_write(iocpf->ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
- /**
- * Notify other functions on HB failure.
- */
- bfa_ioc_notify_hbfail(iocpf->ioc);
-
- /**
+ /*
* Flush any queued up mailbox requests.
*/
bfa_ioc_mbox_hbfail(iocpf->ioc);
- if (iocpf->auto_recover)
- bfa_iocpf_recovery_timer_start(iocpf->ioc);
+ bfa_ioc_hw_sem_get(iocpf->ioc);
}
-/**
- * IOC is in failed state.
- */
static void
-bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
{
struct bfa_ioc_s *ioc = iocpf->ioc;
bfa_trc(ioc, event);
switch (event) {
+ case IOCPF_E_SEMLOCKED:
+ iocpf->retry_count = 0;
+ bfa_ioc_sync_ack(ioc);
+ bfa_ioc_notify_fail(ioc);
+ if (!iocpf->auto_recover) {
+ bfa_ioc_sync_leave(ioc);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ } else {
+ if (bfa_ioc_sync_complete(ioc))
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
+ else {
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ }
+ }
+ break;
+
case IOCPF_E_DISABLE:
- if (iocpf->auto_recover)
- bfa_iocpf_timer_stop(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ bfa_sem_timer_stop(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
- case IOCPF_E_TIMEOUT:
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
+ case IOCPF_E_FAIL:
break;
default:
@@ -1099,10 +1154,33 @@ bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
}
}
+static void
+bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
+{
+}
+
+/*
+ * IOC is in failed state.
+ */
+static void
+bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
+{
+ struct bfa_ioc_s *ioc = iocpf->ioc;
+
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOCPF_E_DISABLE:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
+ break;
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
-/**
- * hal_ioc_pvt BFA IOC private functions
+/*
+ * BFA IOC private functions
*/
static void
@@ -1113,7 +1191,7 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
ioc->cbfn->disable_cbfn(ioc->bfa);
- /**
+ /*
* Notify common modules registered for notification.
*/
list_for_each(qe, &ioc->hb_notify_q) {
@@ -1123,43 +1201,37 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
}
bfa_boolean_t
-bfa_ioc_sem_get(bfa_os_addr_t sem_reg)
+bfa_ioc_sem_get(void __iomem *sem_reg)
{
u32 r32;
int cnt = 0;
#define BFA_SEM_SPINCNT 3000
- r32 = bfa_reg_read(sem_reg);
+ r32 = readl(sem_reg);
while (r32 && (cnt < BFA_SEM_SPINCNT)) {
cnt++;
- bfa_os_udelay(2);
- r32 = bfa_reg_read(sem_reg);
+ udelay(2);
+ r32 = readl(sem_reg);
}
if (r32 == 0)
return BFA_TRUE;
- bfa_assert(cnt < BFA_SEM_SPINCNT);
+ WARN_ON(cnt >= BFA_SEM_SPINCNT);
return BFA_FALSE;
}
-void
-bfa_ioc_sem_release(bfa_os_addr_t sem_reg)
-{
- bfa_reg_write(sem_reg, 1);
-}
-
static void
bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
{
u32 r32;
- /**
+ /*
* First read to the semaphore register will return 0, subsequent reads
* will return 1. Semaphore is released by writing 1 to the register
*/
- r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+ r32 = readl(ioc->ioc_regs.ioc_sem_reg);
if (r32 == 0) {
bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
return;
@@ -1168,19 +1240,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
bfa_sem_timer_start(ioc);
}
-void
-bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
-{
- bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1);
-}
-
-static void
-bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
-{
- bfa_sem_timer_stop(ioc);
-}
-
-/**
+/*
* Initialize LPU local memory (aka secondary memory / SRAM)
*/
static void
@@ -1190,7 +1250,7 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
int i;
#define PSS_LMEM_INIT_TIME 10000
- pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
pss_ctl &= ~__PSS_LMEM_RESET;
pss_ctl |= __PSS_LMEM_INIT_EN;
@@ -1198,26 +1258,26 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
* i2c workaround 12.5khz clock
*/
pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
- bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
- /**
+ /*
* wait for memory initialization to be complete
*/
i = 0;
do {
- pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
i++;
} while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
- /**
+ /*
* If memory initialization is not successful, IOC timeout will catch
* such failures.
*/
- bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE);
+ WARN_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));
bfa_trc(ioc, pss_ctl);
pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
- bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
}
static void
@@ -1225,13 +1285,13 @@ bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)
{
u32 pss_ctl;
- /**
+ /*
* Take processor out of reset.
*/
- pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
pss_ctl &= ~__PSS_LPU0_RESET;
- bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
}
static void
@@ -1239,16 +1299,16 @@ bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)
{
u32 pss_ctl;
- /**
+ /*
* Put processors in reset.
*/
- pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
- bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
}
-/**
+/*
* Get driver and firmware versions.
*/
void
@@ -1259,9 +1319,9 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
int i;
u32 *fwsig = (u32 *) fwhdr;
- pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
+ pgoff = PSS_SMEM_PGOFF(loff);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
i++) {
@@ -1271,7 +1331,7 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
}
}
-/**
+/*
* Returns TRUE if same.
*/
bfa_boolean_t
@@ -1296,7 +1356,7 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
return BFA_TRUE;
}
-/**
+/*
* Return true if current running version is valid. Firmware signature and
* execution context (driver/bios) must match.
*/
@@ -1305,12 +1365,6 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
{
struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr;
- /**
- * If bios/efi boot (flash based) -- return true
- */
- if (bfa_ioc_is_bios_optrom(ioc))
- return BFA_TRUE;
-
bfa_ioc_fwver_get(ioc, &fwhdr);
drv_fwhdr = (struct bfi_ioc_image_hdr_s *)
bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
@@ -1321,7 +1375,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
return BFA_FALSE;
}
- if (bfa_os_swap32(fwhdr.param) != boot_env) {
+ if (swab32(fwhdr.param) != boot_env) {
bfa_trc(ioc, fwhdr.param);
bfa_trc(ioc, boot_env);
return BFA_FALSE;
@@ -1330,7 +1384,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
return bfa_ioc_fwver_cmp(ioc, &fwhdr);
}
-/**
+/*
* Conditionally flush any pending message from firmware at start.
*/
static void
@@ -1338,12 +1392,11 @@ bfa_ioc_msgflush(struct bfa_ioc_s *ioc)
{
u32 r32;
- r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+ r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
if (r32)
- bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+ writel(1, ioc->ioc_regs.lpu_mbox_cmd);
}
-
static void
bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
{
@@ -1352,7 +1405,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
u32 boot_type;
u32 boot_env;
- ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+ ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
if (force)
ioc_fwstate = BFI_IOC_UNINIT;
@@ -1362,23 +1415,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
boot_type = BFI_BOOT_TYPE_NORMAL;
boot_env = BFI_BOOT_LOADER_OS;
- /**
- * Flash based firmware boot BIOS env.
- */
- if (bfa_ioc_is_bios_optrom(ioc)) {
- boot_type = BFI_BOOT_TYPE_FLASH;
- boot_env = BFI_BOOT_LOADER_BIOS;
- }
-
- /**
- * Flash based firmware boot UEFI env.
- */
- if (bfa_ioc_is_uefi(ioc)) {
- boot_type = BFI_BOOT_TYPE_FLASH;
- boot_env = BFI_BOOT_LOADER_UEFI;
- }
-
- /**
+ /*
* check if firmware is valid
*/
fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
@@ -1389,7 +1426,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
return;
}
- /**
+ /*
* If hardware initialization is in progress (initialized by other IOC),
* just wait for an initialization completion interrupt.
*/
@@ -1398,7 +1435,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
return;
}
- /**
+ /*
* If IOC function is disabled and firmware version is same,
* just re-enable IOC.
*
@@ -1406,10 +1443,9 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
* convergence, IOC will be in operational state when 2nd driver
* is loaded.
*/
- if (ioc_fwstate == BFI_IOC_DISABLED ||
- (!bfa_ioc_is_bios_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
+ if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
- /**
+ /*
* When using MSI-X any pending firmware ready event should
* be flushed. Otherwise MSI-X interrupts are not delivered.
*/
@@ -1419,7 +1455,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
return;
}
- /**
+ /*
* Initialize the h/w for any other states.
*/
bfa_ioc_boot(ioc, boot_type, boot_env);
@@ -1443,36 +1479,36 @@ bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)
bfa_trc(ioc, msgp[0]);
bfa_trc(ioc, len);
- bfa_assert(len <= BFI_IOC_MSGLEN_MAX);
+ WARN_ON(len > BFI_IOC_MSGLEN_MAX);
/*
* first write msg to mailbox registers
*/
for (i = 0; i < len / sizeof(u32); i++)
- bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32),
- bfa_os_wtole(msgp[i]));
+ writel(cpu_to_le32(msgp[i]),
+ ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
- bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0);
+ writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
/*
* write 1 to mailbox CMD to trigger LPU event
*/
- bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1);
- (void) bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ writel(1, ioc->ioc_regs.hfn_mbox_cmd);
+ (void) readl(ioc->ioc_regs.hfn_mbox_cmd);
}
static void
bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
{
struct bfi_ioc_ctrl_req_s enable_req;
- struct bfa_timeval_s tv;
+ struct timeval tv;
bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
bfa_ioc_portid(ioc));
enable_req.ioc_class = ioc->ioc_mc;
- bfa_os_gettimeofday(&tv);
- enable_req.tv_sec = bfa_os_ntohl(tv.tv_sec);
+ do_gettimeofday(&tv);
+ enable_req.tv_sec = be32_to_cpu(tv.tv_sec);
bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
}
@@ -1503,9 +1539,8 @@ bfa_ioc_hb_check(void *cbarg)
struct bfa_ioc_s *ioc = cbarg;
u32 hb_count;
- hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ hb_count = readl(ioc->ioc_regs.heartbeat);
if (ioc->hb_count == hb_count) {
- printk(KERN_CRIT "Firmware heartbeat failure at %d", hb_count);
bfa_ioc_recover(ioc);
return;
} else {
@@ -1519,18 +1554,11 @@ bfa_ioc_hb_check(void *cbarg)
static void
bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
{
- ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
bfa_hb_timer_start(ioc);
}
-static void
-bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
-{
- bfa_hb_timer_stop(ioc);
-}
-
-
-/**
+/*
* Initiate a full firmware download.
*/
static void
@@ -1543,7 +1571,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
u32 chunkno = 0;
u32 i;
- /**
+ /*
* Initialize LMEM first before code download
*/
bfa_ioc_lmem_init(ioc);
@@ -1551,10 +1579,10 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
bfa_trc(ioc, bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)));
fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
- pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
+ pgoff = PSS_SMEM_PGOFF(loff);
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
@@ -1564,7 +1592,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
}
- /**
+ /*
* write smem
*/
bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
@@ -1572,36 +1600,30 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
loff += sizeof(u32);
- /**
+ /*
* handle page offset wrap around
*/
loff = PSS_SMEM_PGOFF(loff);
if (loff == 0) {
pgnum++;
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
- pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
- bfa_ioc_smem_pgnum(ioc, 0));
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* Set boot type and boot param at the end.
*/
bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF,
- bfa_os_swap32(boot_type));
+ swab32(boot_type));
bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_LOADER_OFF,
- bfa_os_swap32(boot_env));
+ swab32(boot_env));
}
-static void
-bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
-{
- bfa_ioc_hwinit(ioc, force);
-}
-/**
+/*
* Update BFA configuration from firmware configuration.
*/
static void
@@ -1609,14 +1631,14 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
{
struct bfi_ioc_attr_s *attr = ioc->attr;
- attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
- attr->card_type = bfa_os_ntohl(attr->card_type);
- attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
+ attr->adapter_prop = be32_to_cpu(attr->adapter_prop);
+ attr->card_type = be32_to_cpu(attr->card_type);
+ attr->maxfrsize = be16_to_cpu(attr->maxfrsize);
bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
}
-/**
+/*
* Attach time initialization of mbox logic.
*/
static void
@@ -1632,7 +1654,7 @@ bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)
}
}
-/**
+/*
* Mbox poll timer -- restarts any pending mailbox requests.
*/
static void
@@ -1642,27 +1664,27 @@ bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)
struct bfa_mbox_cmd_s *cmd;
u32 stat;
- /**
+ /*
* If no command pending, do nothing
*/
if (list_empty(&mod->cmd_q))
return;
- /**
+ /*
* If previous command is not yet fetched by firmware, do nothing
*/
- stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
if (stat)
return;
- /**
+ /*
* Enqueue command to firmware.
*/
bfa_q_deq(&mod->cmd_q, &cmd);
bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
}
-/**
+/*
* Cleanup any pending requests.
*/
static void
@@ -1675,7 +1697,7 @@ bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
bfa_q_deq(&mod->cmd_q, &cmd);
}
-/**
+/*
* Read data from SMEM to host through PCI memmap
*
* @param[in] ioc memory for IOC
@@ -1686,12 +1708,13 @@ bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
static bfa_status_t
bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
{
- u32 pgnum, loff, r32;
+ u32 pgnum, loff;
+ __be32 r32;
int i, len;
u32 *buf = tbuf;
- pgnum = bfa_ioc_smem_pgnum(ioc, soff);
- loff = bfa_ioc_smem_pgoff(ioc, soff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
+ loff = PSS_SMEM_PGOFF(soff);
bfa_trc(ioc, pgnum);
bfa_trc(ioc, loff);
bfa_trc(ioc, sz);
@@ -1704,36 +1727,36 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
return BFA_STATUS_FAILED;
}
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
len = sz/sizeof(u32);
bfa_trc(ioc, len);
for (i = 0; i < len; i++) {
r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
- buf[i] = bfa_os_ntohl(r32);
+ buf[i] = be32_to_cpu(r32);
loff += sizeof(u32);
- /**
+ /*
* handle page offset wrap around
*/
loff = PSS_SMEM_PGOFF(loff);
if (loff == 0) {
pgnum++;
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
- bfa_ioc_smem_pgnum(ioc, 0));
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
bfa_trc(ioc, pgnum);
return BFA_STATUS_OK;
}
-/**
+/*
* Clear SMEM data from host through PCI memmap
*
* @param[in] ioc memory for IOC
@@ -1746,8 +1769,8 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
int i, len;
u32 pgnum, loff;
- pgnum = bfa_ioc_smem_pgnum(ioc, soff);
- loff = bfa_ioc_smem_pgoff(ioc, soff);
+ pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
+ loff = PSS_SMEM_PGOFF(soff);
bfa_trc(ioc, pgnum);
bfa_trc(ioc, loff);
bfa_trc(ioc, sz);
@@ -1760,7 +1783,7 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
return BFA_STATUS_FAILED;
}
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
len = sz/sizeof(u32); /* len in words */
bfa_trc(ioc, len);
@@ -1768,66 +1791,62 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, 0);
loff += sizeof(u32);
- /**
+ /*
* handle page offset wrap around
*/
loff = PSS_SMEM_PGOFF(loff);
if (loff == 0) {
pgnum++;
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
}
}
- bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
- bfa_ioc_smem_pgnum(ioc, 0));
+ writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
+ ioc->ioc_regs.host_page_num_fn);
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
bfa_trc(ioc, pgnum);
return BFA_STATUS_OK;
}
-/**
- * hal iocpf to ioc interface
- */
static void
-bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc)
+bfa_ioc_fail_notify(struct bfa_ioc_s *ioc)
{
- bfa_fsm_send_event(ioc, IOC_E_ENABLED);
-}
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+ struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
-static void
-bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(ioc, IOC_E_DISABLED);
-}
+ /*
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *) qe;
+ notify->cbfn(notify->cbarg);
+ }
+
+ bfa_ioc_debug_save_ftrc(ioc);
+
+ BFA_LOG(KERN_CRIT, bfad, bfa_log_level,
+ "Heart Beat of IOC has failed\n");
-static void
-bfa_ioc_pf_failed(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(ioc, IOC_E_FAILED);
}
static void
bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)
{
struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
- /**
+ /*
* Provide enable completion callback.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Running firmware version is incompatible "
"with the driver version\n");
}
-
-
-/**
- * hal_ioc_public
- */
-
bfa_status_t
bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
{
@@ -1843,48 +1862,48 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
/*
* release semaphore.
*/
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_init_sem_reg);
return BFA_STATUS_OK;
}
-/**
+/*
* Interface used by diag module to do firmware boot with memory test
* as the entry vector.
*/
void
bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env)
{
- bfa_os_addr_t rb;
+ void __iomem *rb;
bfa_ioc_stats(ioc, ioc_boots);
if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
return;
- /**
+ /*
* Initialize IOC state of all functions on a chip reset.
*/
rb = ioc->pcidev.pci_bar_kva;
if (boot_type == BFI_BOOT_TYPE_MEMTEST) {
- bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST);
- bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST);
+ writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
} else {
- bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING);
- bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
+ writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
}
bfa_ioc_msgflush(ioc);
bfa_ioc_download_fw(ioc, boot_type, boot_env);
- /**
+ /*
* Enable interrupts just before starting LPU
*/
ioc->cbfn->reset_cbfn(ioc->bfa);
bfa_ioc_lpu_start(ioc);
}
-/**
+/*
* Enable/disable IOC failure auto recovery.
*/
void
@@ -1904,7 +1923,7 @@ bfa_ioc_is_operational(struct bfa_ioc_s *ioc)
bfa_boolean_t
bfa_ioc_is_initialized(struct bfa_ioc_s *ioc)
{
- u32 r32 = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+ u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
return ((r32 != BFI_IOC_UNINIT) &&
(r32 != BFI_IOC_INITING) &&
@@ -1914,25 +1933,25 @@ bfa_ioc_is_initialized(struct bfa_ioc_s *ioc)
void
bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
{
- u32 *msgp = mbmsg;
+ __be32 *msgp = mbmsg;
u32 r32;
int i;
- /**
+ /*
* read the MBOX msg
*/
for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
i++) {
- r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox +
+ r32 = readl(ioc->ioc_regs.lpu_mbox +
i * sizeof(u32));
- msgp[i] = bfa_os_htonl(r32);
+ msgp[i] = cpu_to_be32(r32);
}
- /**
+ /*
* turn off mailbox interrupt by clearing mailbox status
*/
- bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
- bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+ writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+ readl(ioc->ioc_regs.lpu_mbox_cmd);
}
void
@@ -1967,11 +1986,11 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)
default:
bfa_trc(ioc, msg->mh.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
-/**
+/*
* IOC attach time initialization and setup.
*
* @param[in] ioc memory for IOC
@@ -1996,7 +2015,7 @@ bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,
bfa_fsm_send_event(ioc, IOC_E_RESET);
}
-/**
+/*
* Driver detach time IOC cleanup.
*/
void
@@ -2005,7 +2024,7 @@ bfa_ioc_detach(struct bfa_ioc_s *ioc)
bfa_fsm_send_event(ioc, IOC_E_DETACH);
}
-/**
+/*
* Setup IOC PCI properties.
*
* @param[in] pcidev PCI device information for this IOC
@@ -2019,7 +2038,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id);
ioc->cna = ioc->ctdev && !ioc->fcmode;
- /**
+ /*
* Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c
*/
if (ioc->ctdev)
@@ -2031,7 +2050,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
bfa_ioc_reg_init(ioc);
}
-/**
+/*
* Initialize IOC dma memory
*
* @param[in] dm_kva kernel virtual address of IOC dma memory
@@ -2040,7 +2059,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
void
bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)
{
- /**
+ /*
* dma memory for firmware attribute
*/
ioc->attr_dma.kva = dm_kva;
@@ -2048,15 +2067,6 @@ bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)
ioc->attr = (struct bfi_ioc_attr_s *) dm_kva;
}
-/**
- * Return size of dma memory required.
- */
-u32
-bfa_ioc_meminfo(void)
-{
- return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
-}
-
void
bfa_ioc_enable(struct bfa_ioc_s *ioc)
{
@@ -2073,20 +2083,8 @@ bfa_ioc_disable(struct bfa_ioc_s *ioc)
bfa_fsm_send_event(ioc, IOC_E_DISABLE);
}
-/**
- * Returns memory required for saving firmware trace in case of crash.
- * Driver must call this interface to allocate memory required for
- * automatic saving of firmware trace. Driver should call
- * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
- * trace memory.
- */
-int
-bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
-{
- return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
-}
-/**
+/*
* Initialize memory for saving firmware trace. Driver must initialize
* trace memory before call bfa_ioc_enable().
*/
@@ -2094,22 +2092,10 @@ void
bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
{
ioc->dbg_fwsave = dbg_fwsave;
- ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->iocpf.auto_recover);
+ ioc->dbg_fwsave_len = (ioc->iocpf.auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
}
-u32
-bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr)
-{
- return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
-}
-
-u32
-bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
-{
- return PSS_SMEM_PGOFF(fmaddr);
-}
-
-/**
+/*
* Register mailbox message handler functions
*
* @param[in] ioc IOC instance
@@ -2125,7 +2111,7 @@ bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
mod->mbhdlr[mc].cbfn = mcfuncs[mc];
}
-/**
+/*
* Register mailbox message handler function, to be called by common modules
*/
void
@@ -2138,7 +2124,7 @@ bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
mod->mbhdlr[mc].cbarg = cbarg;
}
-/**
+/*
* Queue a mailbox command request to firmware. Waits if mailbox is busy.
* Responsibility of caller to serialize
*
@@ -2151,7 +2137,7 @@ bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
u32 stat;
- /**
+ /*
* If a previous command is pending, queue new command
*/
if (!list_empty(&mod->cmd_q)) {
@@ -2159,22 +2145,22 @@ bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
return;
}
- /**
+ /*
* If mailbox is busy, queue command for poll timer
*/
- stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
if (stat) {
list_add_tail(&cmd->qe, &mod->cmd_q);
return;
}
- /**
+ /*
* mailbox is free -- queue command to firmware
*/
bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
}
-/**
+/*
* Handle mailbox interrupts
*/
void
@@ -2186,7 +2172,7 @@ bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
bfa_ioc_msgget(ioc, &m);
- /**
+ /*
* Treat IOC message class as special.
*/
mc = m.mh.msg_class;
@@ -2214,7 +2200,7 @@ bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
ioc->port_id = bfa_ioc_pcifn(ioc);
}
-/**
+/*
* return true if IOC is disabled
*/
bfa_boolean_t
@@ -2224,7 +2210,7 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
}
-/**
+/*
* return true if IOC firmware is different.
*/
bfa_boolean_t
@@ -2243,7 +2229,7 @@ bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
((__sm) == BFI_IOC_FAIL) || \
((__sm) == BFI_IOC_CFG_DISABLED))
-/**
+/*
* Check if adapter is disabled -- both IOCs should be in a disabled
* state.
*/
@@ -2251,17 +2237,17 @@ bfa_boolean_t
bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
{
u32 ioc_state;
- bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
return BFA_FALSE;
- ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG);
+ ioc_state = readl(rb + BFA_IOC0_STATE_REG);
if (!bfa_ioc_state_disabled(ioc_state))
return BFA_FALSE;
if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) {
- ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG);
+ ioc_state = readl(rb + BFA_IOC1_STATE_REG);
if (!bfa_ioc_state_disabled(ioc_state))
return BFA_FALSE;
}
@@ -2269,15 +2255,14 @@ bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
return BFA_TRUE;
}
-/**
- * Add to IOC heartbeat failure notification queue. To be used by common
- * modules such as cee, port, diag.
+/*
+ * Reset IOC fwstate registers.
*/
void
-bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
- struct bfa_ioc_hbfail_notify_s *notify)
+bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
{
- list_add_tail(&notify->qe, &ioc->hb_notify_q);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
}
#define BFA_MFG_NAME "Brocade"
@@ -2293,7 +2278,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
- bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+ memcpy(&ad_attr->vpd, &ioc_attr->vpd,
sizeof(struct bfa_mfg_vpd_s));
ad_attr->nports = bfa_ioc_get_nports(ioc);
@@ -2311,7 +2296,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
else
ad_attr->prototype = 0;
- ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+ ad_attr->pwwn = ioc->attr->pwwn;
ad_attr->mac = bfa_ioc_get_mac(ioc);
ad_attr->pcie_gen = ioc_attr->pcie_gen;
@@ -2322,7 +2307,8 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
ad_attr->cna_capable = ioc->cna;
- ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna;
+ ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna &&
+ !ad_attr->is_mezz;
}
enum bfa_ioc_type_e
@@ -2335,7 +2321,7 @@ bfa_ioc_get_type(struct bfa_ioc_s *ioc)
else if (ioc->ioc_mc == BFI_MC_LL)
return BFA_IOC_TYPE_LL;
else {
- bfa_assert(ioc->ioc_mc == BFI_MC_LL);
+ WARN_ON(ioc->ioc_mc != BFI_MC_LL);
return BFA_IOC_TYPE_LL;
}
}
@@ -2343,8 +2329,8 @@ bfa_ioc_get_type(struct bfa_ioc_s *ioc)
void
bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)
{
- bfa_os_memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
- bfa_os_memcpy((void *)serial_num,
+ memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+ memcpy((void *)serial_num,
(void *)ioc->attr->brcd_serialnum,
BFA_ADAPTER_SERIAL_NUM_LEN);
}
@@ -2352,16 +2338,16 @@ bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)
void
bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver)
{
- bfa_os_memset((void *)fw_ver, 0, BFA_VERSION_LEN);
- bfa_os_memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+ memset((void *)fw_ver, 0, BFA_VERSION_LEN);
+ memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
}
void
bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)
{
- bfa_assert(chip_rev);
+ WARN_ON(!chip_rev);
- bfa_os_memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+ memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
chip_rev[0] = 'R';
chip_rev[1] = 'e';
@@ -2374,16 +2360,16 @@ bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)
void
bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver)
{
- bfa_os_memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
- bfa_os_memcpy(optrom_ver, ioc->attr->optrom_version,
+ memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
+ memcpy(optrom_ver, ioc->attr->optrom_version,
BFA_VERSION_LEN);
}
void
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
{
- bfa_os_memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
- bfa_os_memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+ memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+ memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
}
void
@@ -2391,15 +2377,15 @@ bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)
{
struct bfi_ioc_attr_s *ioc_attr;
- bfa_assert(model);
- bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+ WARN_ON(!model);
+ memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
ioc_attr = ioc->attr;
- /**
+ /*
* model name
*/
- bfa_os_snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+ snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
BFA_MFG_NAME, ioc_attr->card_type);
}
@@ -2446,7 +2432,7 @@ bfa_ioc_get_state(struct bfa_ioc_s *ioc)
void
bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
{
- bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
+ memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
ioc_attr->state = bfa_ioc_get_state(ioc);
ioc_attr->port_id = ioc->port_id;
@@ -2460,27 +2446,6 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
}
-/**
- * hal_wwn_public
- */
-wwn_t
-bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->pwwn;
-}
-
-wwn_t
-bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->nwwn;
-}
-
-u64
-bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_pwwn;
-}
-
mac_t
bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
{
@@ -2493,18 +2458,6 @@ bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
return ioc->attr->mac;
}
-wwn_t
-bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_pwwn;
-}
-
-wwn_t
-bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc)
-{
- return ioc->attr->mfg_nwwn;
-}
-
mac_t
bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
{
@@ -2526,7 +2479,7 @@ bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id);
}
-/**
+/*
* Retrieve saved firmware trace from a prior IOC failure.
*/
bfa_status_t
@@ -2541,21 +2494,13 @@ bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
if (tlen > ioc->dbg_fwsave_len)
tlen = ioc->dbg_fwsave_len;
- bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen);
+ memcpy(trcdata, ioc->dbg_fwsave, tlen);
*trclen = tlen;
return BFA_STATUS_OK;
}
-/**
- * Clear saved firmware trace
- */
-void
-bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc)
-{
- ioc->dbg_fwsave_once = BFA_TRUE;
-}
-/**
+/*
* Retrieve saved firmware trace from a prior IOC failure.
*/
bfa_status_t
@@ -2595,7 +2540,7 @@ bfa_ioc_fwsync(struct bfa_ioc_s *ioc)
bfa_ioc_send_fwsync(ioc);
- /**
+ /*
* After sending a fw sync mbox command wait for it to
* take effect. We will not wait for a response because
* 1. fw_sync mbox cmd doesn't have a response.
@@ -2610,7 +2555,7 @@ bfa_ioc_fwsync(struct bfa_ioc_s *ioc)
fwsync_iter--;
}
-/**
+/*
* Dump firmware smem
*/
bfa_status_t
@@ -2630,7 +2575,7 @@ bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
loff = *offset;
dlen = *buflen;
- /**
+ /*
* First smem read, sync smem before proceeding
* No need to sync before reading every chunk.
*/
@@ -2657,7 +2602,7 @@ bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
return status;
}
-/**
+/*
* Firmware statistics
*/
bfa_status_t
@@ -2702,31 +2647,29 @@ bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc)
return status;
}
-/**
+/*
* Save firmware trace if configured.
*/
static void
-bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
+bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc)
{
int tlen;
- if (ioc->dbg_fwsave_len) {
- tlen = ioc->dbg_fwsave_len;
- bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ if (ioc->dbg_fwsave_once) {
+ ioc->dbg_fwsave_once = BFA_FALSE;
+ if (ioc->dbg_fwsave_len) {
+ tlen = ioc->dbg_fwsave_len;
+ bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ }
}
}
-/**
+/*
* Firmware failure detected. Start recovery actions.
*/
static void
bfa_ioc_recover(struct bfa_ioc_s *ioc)
{
- if (ioc->dbg_fwsave_once) {
- ioc->dbg_fwsave_once = BFA_FALSE;
- bfa_ioc_debug_save(ioc);
- }
-
bfa_ioc_stats(ioc, ioc_hbfails);
bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
}
@@ -2738,46 +2681,9 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
return;
}
-/**
- * hal_iocpf_pvt BFA IOC PF private functions
+/*
+ * BFA IOC PF private functions
*/
-
-static void
-bfa_iocpf_enable(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
-}
-
-static void
-bfa_iocpf_disable(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
-}
-
-static void
-bfa_iocpf_fail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
-}
-
-static void
-bfa_iocpf_initfail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
-}
-
-static void
-bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
-}
-
-static void
-bfa_iocpf_stop(struct bfa_ioc_s *ioc)
-{
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
-}
-
static void
bfa_iocpf_timeout(void *ioc_arg)
{
@@ -2795,16 +2701,10 @@ bfa_iocpf_sem_timeout(void *ioc_arg)
bfa_ioc_hw_sem_get(ioc);
}
-/**
+/*
* bfa timer function
*/
void
-bfa_timer_init(struct bfa_timer_mod_s *mod)
-{
- INIT_LIST_HEAD(&mod->timer_q);
-}
-
-void
bfa_timer_beat(struct bfa_timer_mod_s *mod)
{
struct list_head *qh = &mod->timer_q;
@@ -2840,7 +2740,7 @@ bfa_timer_beat(struct bfa_timer_mod_s *mod)
}
}
-/**
+/*
* Should be called with lock protection
*/
void
@@ -2848,8 +2748,8 @@ bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
void (*timercb) (void *), void *arg, unsigned int timeout)
{
- bfa_assert(timercb != NULL);
- bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
+ WARN_ON(timercb == NULL);
+ WARN_ON(bfa_q_is_on_q(&mod->timer_q, timer));
timer->timeout = timeout;
timer->timercb = timercb;
@@ -2858,13 +2758,13 @@ bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
list_add_tail(&timer->qe, &mod->timer_q);
}
-/**
+/*
* Should be called with lock protection
*/
void
bfa_timer_stop(struct bfa_timer_s *timer)
{
- bfa_assert(!list_empty(&timer->qe));
+ WARN_ON(list_empty(&timer->qe));
list_del(&timer->qe);
}
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 288c5801aace..ec9cf08b0e7f 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -18,42 +18,46 @@
#ifndef __BFA_IOC_H__
#define __BFA_IOC_H__
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_cs.h"
#include "bfi.h"
-/**
+#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
+#define BFA_DBG_FWTRC_LEN \
+ (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
+ (sizeof(struct bfa_trc_mod_s) - \
+ BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
+/*
* BFA timer declarations
*/
typedef void (*bfa_timer_cbfn_t)(void *);
-/**
+/*
* BFA timer data structure
*/
struct bfa_timer_s {
struct list_head qe;
bfa_timer_cbfn_t timercb;
void *arg;
- int timeout; /**< in millisecs. */
+ int timeout; /* in millisecs */
};
-/**
+/*
* Timer module structure
*/
struct bfa_timer_mod_s {
struct list_head timer_q;
};
-#define BFA_TIMER_FREQ 200 /**< specified in millisecs */
+#define BFA_TIMER_FREQ 200 /* specified in millisecs */
void bfa_timer_beat(struct bfa_timer_mod_s *mod);
-void bfa_timer_init(struct bfa_timer_mod_s *mod);
void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
bfa_timer_cbfn_t timercb, void *arg,
unsigned int timeout);
void bfa_timer_stop(struct bfa_timer_s *timer);
-/**
+/*
* Generic Scatter Gather Element used by driver
*/
struct bfa_sge_s {
@@ -62,15 +66,15 @@ struct bfa_sge_s {
};
#define bfa_sge_word_swap(__sge) do { \
- ((u32 *)(__sge))[0] = bfa_os_swap32(((u32 *)(__sge))[0]); \
- ((u32 *)(__sge))[1] = bfa_os_swap32(((u32 *)(__sge))[1]); \
- ((u32 *)(__sge))[2] = bfa_os_swap32(((u32 *)(__sge))[2]); \
+ ((u32 *)(__sge))[0] = swab32(((u32 *)(__sge))[0]); \
+ ((u32 *)(__sge))[1] = swab32(((u32 *)(__sge))[1]); \
+ ((u32 *)(__sge))[2] = swab32(((u32 *)(__sge))[2]); \
} while (0)
#define bfa_swap_words(_x) ( \
((_x) << 32) | ((_x) >> 32))
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
#define bfa_sge_to_be(_x)
#define bfa_sge_to_le(_x) bfa_sge_word_swap(_x)
#define bfa_sgaddr_le(_x) bfa_swap_words(_x)
@@ -80,17 +84,17 @@ struct bfa_sge_s {
#define bfa_sgaddr_le(_x) (_x)
#endif
-/**
+/*
* PCI device information required by IOC
*/
struct bfa_pcidev_s {
int pci_slot;
u8 pci_func;
- u16 device_id;
- bfa_os_addr_t pci_bar_kva;
+ u16 device_id;
+ void __iomem *pci_bar_kva;
};
-/**
+/*
* Structure used to remember the DMA-able memory block's KVA and Physical
* Address
*/
@@ -102,7 +106,7 @@ struct bfa_dma_s {
#define BFA_DMA_ALIGN_SZ 256
#define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
-/**
+/*
* smem size for Crossbow and Catapult
*/
#define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */
@@ -115,8 +119,8 @@ struct bfa_dma_s {
static inline void
__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
{
- dma_addr->a32.addr_lo = (u32) pa;
- dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa));
+ dma_addr->a32.addr_lo = (__be32) pa;
+ dma_addr->a32.addr_hi = (__be32) (pa >> 32);
}
@@ -125,40 +129,41 @@ __bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
static inline void
__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
{
- dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa);
- dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa));
+ dma_addr->a32.addr_lo = cpu_to_be32(pa);
+ dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32);
}
struct bfa_ioc_regs_s {
- bfa_os_addr_t hfn_mbox_cmd;
- bfa_os_addr_t hfn_mbox;
- bfa_os_addr_t lpu_mbox_cmd;
- bfa_os_addr_t lpu_mbox;
- bfa_os_addr_t pss_ctl_reg;
- bfa_os_addr_t pss_err_status_reg;
- bfa_os_addr_t app_pll_fast_ctl_reg;
- bfa_os_addr_t app_pll_slow_ctl_reg;
- bfa_os_addr_t ioc_sem_reg;
- bfa_os_addr_t ioc_usage_sem_reg;
- bfa_os_addr_t ioc_init_sem_reg;
- bfa_os_addr_t ioc_usage_reg;
- bfa_os_addr_t host_page_num_fn;
- bfa_os_addr_t heartbeat;
- bfa_os_addr_t ioc_fwstate;
- bfa_os_addr_t ll_halt;
- bfa_os_addr_t err_set;
- bfa_os_addr_t shirq_isr_next;
- bfa_os_addr_t shirq_msk_next;
- bfa_os_addr_t smem_page_start;
+ void __iomem *hfn_mbox_cmd;
+ void __iomem *hfn_mbox;
+ void __iomem *lpu_mbox_cmd;
+ void __iomem *lpu_mbox;
+ void __iomem *pss_ctl_reg;
+ void __iomem *pss_err_status_reg;
+ void __iomem *app_pll_fast_ctl_reg;
+ void __iomem *app_pll_slow_ctl_reg;
+ void __iomem *ioc_sem_reg;
+ void __iomem *ioc_usage_sem_reg;
+ void __iomem *ioc_init_sem_reg;
+ void __iomem *ioc_usage_reg;
+ void __iomem *host_page_num_fn;
+ void __iomem *heartbeat;
+ void __iomem *ioc_fwstate;
+ void __iomem *alt_ioc_fwstate;
+ void __iomem *ll_halt;
+ void __iomem *alt_ll_halt;
+ void __iomem *err_set;
+ void __iomem *ioc_fail_sync;
+ void __iomem *shirq_isr_next;
+ void __iomem *shirq_msk_next;
+ void __iomem *smem_page_start;
u32 smem_pg0;
};
-#define bfa_reg_read(_raddr) bfa_os_reg_read(_raddr)
-#define bfa_reg_write(_raddr, _val) bfa_os_reg_write(_raddr, _val)
-#define bfa_mem_read(_raddr, _off) bfa_os_mem_read(_raddr, _off)
+#define bfa_mem_read(_raddr, _off) swab32(readl(((_raddr) + (_off))))
#define bfa_mem_write(_raddr, _off, _val) \
- bfa_os_mem_write(_raddr, _off, _val)
-/**
+ writel(swab32((_val)), ((_raddr) + (_off)))
+/*
* IOC Mailbox structures
*/
struct bfa_mbox_cmd_s {
@@ -166,7 +171,7 @@ struct bfa_mbox_cmd_s {
u32 msg[BFI_IOC_MSGSZ];
};
-/**
+/*
* IOC mailbox module
*/
typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m);
@@ -179,7 +184,7 @@ struct bfa_ioc_mbox_mod_s {
} mbhdlr[BFI_MC_MAX];
};
-/**
+/*
* IOC callback function interfaces
*/
typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
@@ -193,7 +198,7 @@ struct bfa_ioc_cbfn_s {
bfa_ioc_reset_cbfn_t reset_cbfn;
};
-/**
+/*
* Heartbeat failure notification queue element.
*/
struct bfa_ioc_hbfail_notify_s {
@@ -202,7 +207,7 @@ struct bfa_ioc_hbfail_notify_s {
void *cbarg;
};
-/**
+/*
* Initialize a heartbeat failure notification structure
*/
#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \
@@ -249,15 +254,19 @@ struct bfa_ioc_s {
};
struct bfa_ioc_hwif_s {
- bfa_status_t (*ioc_pll_init) (bfa_os_addr_t rb, bfa_boolean_t fcmode);
+ bfa_status_t (*ioc_pll_init) (void __iomem *rb, bfa_boolean_t fcmode);
bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc);
void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc);
void (*ioc_reg_init) (struct bfa_ioc_s *ioc);
void (*ioc_map_port) (struct bfa_ioc_s *ioc);
void (*ioc_isr_mode_set) (struct bfa_ioc_s *ioc,
bfa_boolean_t msix);
- void (*ioc_notify_hbfail) (struct bfa_ioc_s *ioc);
+ void (*ioc_notify_fail) (struct bfa_ioc_s *ioc);
void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_join) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_leave) (struct bfa_ioc_s *ioc);
+ void (*ioc_sync_ack) (struct bfa_ioc_s *ioc);
+ bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc);
};
#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
@@ -267,7 +276,7 @@ struct bfa_ioc_hwif_s {
#define bfa_ioc_fetch_stats(__ioc, __stats) \
(((__stats)->drv_stats) = (__ioc)->stats)
#define bfa_ioc_clr_stats(__ioc) \
- bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
+ memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
#define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize)
#define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit)
#define bfa_ioc_speed_sup(__ioc) \
@@ -287,7 +296,7 @@ struct bfa_ioc_hwif_s {
#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
-/**
+/*
* IOC mailbox interface
*/
void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd);
@@ -299,7 +308,7 @@ void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg);
void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
-/**
+/*
* IOC interfaces
*/
@@ -308,9 +317,9 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
(__ioc)->fcmode))
bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
-bfa_status_t bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode);
-bfa_boolean_t bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb);
-bfa_status_t bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode);
+bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode);
+bfa_boolean_t bfa_ioc_ct_pll_init_complete(void __iomem *rb);
+bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode);
#define bfa_ioc_isr_mode_set(__ioc, __msix) \
((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
@@ -327,7 +336,6 @@ void bfa_ioc_auto_recover(bfa_boolean_t auto_recover);
void bfa_ioc_detach(struct bfa_ioc_s *ioc);
void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
enum bfi_mclass mc);
-u32 bfa_ioc_meminfo(void);
void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa);
void bfa_ioc_enable(struct bfa_ioc_s *ioc);
void bfa_ioc_disable(struct bfa_ioc_s *ioc);
@@ -342,6 +350,7 @@ bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
+void bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc);
enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc);
void bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num);
void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver);
@@ -355,24 +364,16 @@ enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc);
void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
struct bfa_adapter_attr_s *ad_attr);
-int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
int *trclen);
-void bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc);
bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
int *trclen);
bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
u32 *offset, int *buflen);
-u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
-u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr);
void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
-void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
- struct bfa_ioc_hbfail_notify_s *notify);
-bfa_boolean_t bfa_ioc_sem_get(bfa_os_addr_t sem_reg);
-void bfa_ioc_sem_release(bfa_os_addr_t sem_reg);
-void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg);
void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
struct bfi_ioc_image_hdr_s *fwhdr);
bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
@@ -383,13 +384,8 @@ bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc);
/*
* bfa mfg wwn API functions
*/
-wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc);
mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc);
-u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
/*
* F/W Image Size & Chunk
@@ -423,7 +419,7 @@ bfa_cb_image_get_chunk(int type, u32 off)
return bfi_image_ct_cna_get_chunk(off); break;
case BFI_IMAGE_CB_FC:
return bfi_image_cb_fc_get_chunk(off); break;
- default: return 0;
+ default: return NULL;
}
}
@@ -441,7 +437,7 @@ bfa_cb_image_get_size(int type)
}
}
-/**
+/*
* CNA TRCMOD declaration
*/
/*
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index d7ac864d8539..e4a0713185b6 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -15,6 +15,7 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_cbreg.h"
#include "bfa_defs.h"
@@ -29,12 +30,16 @@ static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
-static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc);
+static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_cb;
+static struct bfa_ioc_hwif_s hwif_cb;
-/**
+/*
* Called from bfa_ioc_attach() to map asic specific calls.
*/
void
@@ -46,18 +51,37 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
- hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail;
+ hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail;
hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
+ hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join;
+ hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave;
+ hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack;
+ hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete;
ioc->ioc_hwif = &hwif_cb;
}
-/**
+/*
* Return true if firmware of current driver matches the running firmware.
*/
static bfa_boolean_t
bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
{
+ struct bfi_ioc_image_hdr_s fwhdr;
+ uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ if (fwstate == BFI_IOC_UNINIT)
+ return BFA_TRUE;
+
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+
+ if (swab32(fwhdr.exec) == BFI_BOOT_TYPE_NORMAL)
+ return BFA_TRUE;
+
+ bfa_trc(ioc, fwstate);
+ bfa_trc(ioc, fwhdr.exec);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+
return BFA_TRUE;
}
@@ -66,17 +90,17 @@ bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc)
{
}
-/**
+/*
* Notify other functions on HB failure.
*/
static void
-bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc)
+bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc)
{
- bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
- bfa_reg_read(ioc->ioc_regs.err_set);
+ writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+ readl(ioc->ioc_regs.err_set);
}
-/**
+/*
* Host to LPU mailbox message addresses
*/
static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
@@ -84,7 +108,7 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
{ HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }
};
-/**
+/*
* Host <-> LPU mailbox command/status registers
*/
static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
@@ -96,7 +120,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
static void
bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
{
- bfa_os_addr_t rb;
+ void __iomem *rb;
int pcifn = bfa_ioc_pcifn(ioc);
rb = bfa_ioc_bar0(ioc);
@@ -108,12 +132,14 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.alt_ioc_fwstate = (rb + BFA_IOC0_STATE_REG);
}
- /**
+ /*
* Host <-> LPU mailbox command/status registers
*/
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn;
@@ -133,7 +159,7 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
- /**
+ /*
* sram memory access
*/
ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
@@ -145,14 +171,14 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
}
-/**
+/*
* Initialize IOC to port mapping.
*/
static void
bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
{
- /**
+ /*
* For crossbow, port id is same as pci function.
*/
ioc->port_id = bfa_ioc_pcifn(ioc);
@@ -160,7 +186,7 @@ bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
bfa_trc(ioc, ioc->port_id);
}
-/**
+/*
* Set interrupt mode for a function: INTX or MSIX
*/
static void
@@ -168,7 +194,7 @@ bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
{
}
-/**
+/*
* Cleanup hw semaphore and usecnt registers
*/
static void
@@ -180,14 +206,75 @@ bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc)
* before we clear it. If it is not locked, writing 1
* will lock it instead of clearing it.
*/
- bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
- bfa_ioc_hw_sem_release(ioc);
+ readl(ioc->ioc_regs.ioc_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+}
+
+/*
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc)
+{
+}
+
+static void
+bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc)
+{
+}
+
+static void
+bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc)
+{
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
}
+static bfa_boolean_t
+bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc)
+{
+ uint32_t fwstate, alt_fwstate;
+ fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+ /*
+ * At this point, this IOC is hoding the hw sem in the
+ * start path (fwcheck) OR in the disable/enable path
+ * OR to check if the other IOC has acknowledged failure.
+ *
+ * So, this IOC can be in UNINIT, INITING, DISABLED, FAIL
+ * or in MEMTEST states. In a normal scenario, this IOC
+ * can not be in OP state when this function is called.
+ *
+ * However, this IOC could still be in OP state when
+ * the OS driver is starting up, if the OptROM code has
+ * left it in that state.
+ *
+ * If we had marked this IOC's fwstate as BFI_IOC_FAIL
+ * in the failure case and now, if the fwstate is not
+ * BFI_IOC_FAIL it implies that the other PCI fn have
+ * reinitialized the ASIC or this IOC got disabled, so
+ * return TRUE.
+ */
+ if (fwstate == BFI_IOC_UNINIT ||
+ fwstate == BFI_IOC_INITING ||
+ fwstate == BFI_IOC_DISABLED ||
+ fwstate == BFI_IOC_MEMTEST ||
+ fwstate == BFI_IOC_OP)
+ return BFA_TRUE;
+ else {
+ alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate);
+ if (alt_fwstate == BFI_IOC_FAIL ||
+ alt_fwstate == BFI_IOC_DISABLED ||
+ alt_fwstate == BFI_IOC_UNINIT ||
+ alt_fwstate == BFI_IOC_INITING ||
+ alt_fwstate == BFI_IOC_MEMTEST)
+ return BFA_TRUE;
+ else
+ return BFA_FALSE;
+ }
+}
bfa_status_t
-bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
+bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode)
{
u32 pll_sclk, pll_fclk;
@@ -199,38 +286,32 @@ bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
__APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) |
__APP_PLL_400_JITLMT0_1(3U) |
__APP_PLL_400_CNTLMT0_1(3U);
- bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
- bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
- bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
- bfa_reg_write(rb + APP_PLL_212_CTL_REG,
- __APP_PLL_212_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_212_CTL_REG,
- __APP_PLL_212_BYPASS |
- __APP_PLL_212_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_400_CTL_REG,
- __APP_PLL_400_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_400_CTL_REG,
- __APP_PLL_400_BYPASS |
- __APP_PLL_400_LOGIC_SOFT_RESET);
- bfa_os_udelay(2);
- bfa_reg_write(rb + APP_PLL_212_CTL_REG,
- __APP_PLL_212_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_400_CTL_REG,
- __APP_PLL_400_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_212_CTL_REG,
- pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_400_CTL_REG,
- pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET);
- bfa_os_udelay(2000);
- bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + APP_PLL_212_CTL_REG), pll_sclk);
- bfa_reg_write((rb + APP_PLL_400_CTL_REG), pll_fclk);
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG);
+ writel(__APP_PLL_212_BYPASS | __APP_PLL_212_LOGIC_SOFT_RESET,
+ rb + APP_PLL_212_CTL_REG);
+ writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG);
+ writel(__APP_PLL_400_BYPASS | __APP_PLL_400_LOGIC_SOFT_RESET,
+ rb + APP_PLL_400_CTL_REG);
+ udelay(2);
+ writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG);
+ writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG);
+ writel(pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET,
+ rb + APP_PLL_212_CTL_REG);
+ writel(pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET,
+ rb + APP_PLL_400_CTL_REG);
+ udelay(2000);
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(pll_sclk, (rb + APP_PLL_212_CTL_REG));
+ writel(pll_fclk, (rb + APP_PLL_400_CTL_REG));
return BFA_STATUS_OK;
}
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index f21b82c5f64c..008d129ddfcd 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -15,12 +15,22 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_ioc.h"
#include "bfi_ctreg.h"
#include "bfa_defs.h"
BFA_TRC_FILE(CNA, IOC_CT);
+#define bfa_ioc_ct_sync_pos(__ioc) \
+ ((uint32_t) (1 << bfa_ioc_pcifn(__ioc)))
+#define BFA_IOC_SYNC_REQD_SH 16
+#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
+#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
+#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
+#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
+ (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
+
/*
* forward declarations
*/
@@ -29,12 +39,16 @@ static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
-static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc);
+static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_ct;
+static struct bfa_ioc_hwif_s hwif_ct;
-/**
+/*
* Called from bfa_ioc_attach() to map asic specific calls.
*/
void
@@ -46,13 +60,17 @@ bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
- hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+ hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+ hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
+ hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
+ hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
+ hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete;
ioc->ioc_hwif = &hwif_ct;
}
-/**
+/*
* Return true if firmware of current driver matches the running firmware.
*/
static bfa_boolean_t
@@ -62,13 +80,13 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
u32 usecnt;
struct bfi_ioc_image_hdr_s fwhdr;
- /**
+ /*
* Firmware match check is relevant only for CNA.
*/
if (!ioc->cna)
return BFA_TRUE;
- /**
+ /*
* If bios boot (flash based) -- do not increment usage count
*/
if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
@@ -76,42 +94,43 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
return BFA_TRUE;
bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+ usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
- /**
+ /*
* If usage count is 0, always return TRUE.
*/
if (usecnt == 0) {
- bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_fail_sync);
bfa_trc(ioc, usecnt);
return BFA_TRUE;
}
- ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+ ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
bfa_trc(ioc, ioc_fwstate);
- /**
+ /*
* Use count cannot be non-zero and chip in uninitialized state.
*/
- bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
+ WARN_ON(ioc_fwstate == BFI_IOC_UNINIT);
- /**
+ /*
* Check if another driver with a different firmware is active
*/
bfa_ioc_fwver_get(ioc, &fwhdr);
if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
bfa_trc(ioc, usecnt);
return BFA_FALSE;
}
- /**
+ /*
* Same firmware version. Increment the reference count.
*/
usecnt++;
- bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
bfa_trc(ioc, usecnt);
return BFA_TRUE;
}
@@ -121,50 +140,52 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
{
u32 usecnt;
- /**
+ /*
* Firmware lock is relevant only for CNA.
*/
if (!ioc->cna)
return;
- /**
+ /*
* If bios boot (flash based) -- do not decrement usage count
*/
if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
BFA_IOC_FWIMG_MINSZ)
return;
- /**
+ /*
* decrement usage count
*/
bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
- bfa_assert(usecnt > 0);
+ usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+ WARN_ON(usecnt <= 0);
usecnt--;
- bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+ writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
bfa_trc(ioc, usecnt);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
}
-/**
+/*
* Notify other functions on HB failure.
*/
static void
-bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc)
+bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc)
{
if (ioc->cna) {
- bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
/* Wait for halt to take effect */
- bfa_reg_read(ioc->ioc_regs.ll_halt);
+ readl(ioc->ioc_regs.ll_halt);
+ readl(ioc->ioc_regs.alt_ll_halt);
} else {
- bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
- bfa_reg_read(ioc->ioc_regs.err_set);
+ writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+ readl(ioc->ioc_regs.err_set);
}
}
-/**
+/*
* Host to LPU mailbox message addresses
*/
static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
@@ -174,7 +195,7 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
{ HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
};
-/**
+/*
* Host <-> LPU mailbox command/status registers - port 0
*/
static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
@@ -184,7 +205,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
{ HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
};
-/**
+/*
* Host <-> LPU mailbox command/status registers - port 1
*/
static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
@@ -197,7 +218,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
static void
bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
{
- bfa_os_addr_t rb;
+ void __iomem *rb;
int pcifn = bfa_ioc_pcifn(ioc);
rb = bfa_ioc_bar0(ioc);
@@ -209,15 +230,19 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
}
/*
@@ -235,8 +260,9 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+ ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC);
- /**
+ /*
* sram memory access
*/
ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
@@ -248,7 +274,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
}
-/**
+/*
* Initialize IOC to port mapping.
*/
@@ -256,13 +282,13 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
static void
bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
{
- bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
u32 r32;
- /**
+ /*
* For catapult, base port id on personality register and IOC type
*/
- r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ r32 = readl(rb + FNC_PERS_REG);
r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
@@ -270,22 +296,22 @@ bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
bfa_trc(ioc, ioc->port_id);
}
-/**
+/*
* Set interrupt mode for a function: INTX or MSIX
*/
static void
bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
{
- bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
u32 r32, mode;
- r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ r32 = readl(rb + FNC_PERS_REG);
bfa_trc(ioc, r32);
mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
__F0_INTX_STATUS;
- /**
+ /*
* If already in desired mode, do not change anything
*/
if (!msix && mode)
@@ -300,10 +326,10 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
bfa_trc(ioc, r32);
- bfa_reg_write(rb + FNC_PERS_REG, r32);
+ writel(r32, rb + FNC_PERS_REG);
}
-/**
+/*
* Cleanup hw semaphore and usecnt registers
*/
static void
@@ -312,8 +338,8 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
if (ioc->cna) {
bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0);
- bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_usage_reg);
+ writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
}
/*
@@ -321,27 +347,97 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
* before we clear it. If it is not locked, writing 1
* will lock it instead of clearing it.
*/
- bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
- bfa_ioc_hw_sem_release(ioc);
+ readl(ioc->ioc_regs.ioc_sem_reg);
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
}
+/*
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
+ writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
+ bfa_ioc_ct_sync_pos(ioc);
+
+ writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+
+ writel((r32 | bfa_ioc_ct_sync_pos(ioc)),
+ ioc->ioc_regs.ioc_fail_sync);
+}
+
+static bfa_boolean_t
+bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc)
+{
+ uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+ uint32_t sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
+ uint32_t tmp_ackd;
+
+ if (sync_ackd == 0)
+ return BFA_TRUE;
+
+ /*
+ * The check below is to see whether any other PCI fn
+ * has reinitialized the ASIC (reset sync_ackd bits)
+ * and failed again while this IOC was waiting for hw
+ * semaphore (in bfa_iocpf_sm_semwait()).
+ */
+ tmp_ackd = sync_ackd;
+ if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) &&
+ !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
+ sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
+
+ if (sync_reqd == sync_ackd) {
+ writel(bfa_ioc_ct_clear_sync_ackd(r32),
+ ioc->ioc_regs.ioc_fail_sync);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
+ return BFA_TRUE;
+ }
+
+ /*
+ * If another PCI fn reinitialized and failed again while
+ * this IOC was waiting for hw sem, the sync_ackd bit for
+ * this IOC need to be set again to allow reinitialization.
+ */
+ if (tmp_ackd != sync_ackd)
+ writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
+
+ return BFA_FALSE;
+}
/*
* Check the firmware state to know if pll_init has been completed already
*/
bfa_boolean_t
-bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb)
+bfa_ioc_ct_pll_init_complete(void __iomem *rb)
{
- if ((bfa_reg_read(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) ||
- (bfa_reg_read(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP))
+ if ((readl(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) ||
+ (readl(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP))
return BFA_TRUE;
return BFA_FALSE;
}
bfa_status_t
-bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
+bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode)
{
u32 pll_sclk, pll_fclk, r32;
@@ -354,56 +450,51 @@ bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
__APP_PLL_425_JITLMT0_1(3U) |
__APP_PLL_425_CNTLMT0_1(1U);
if (fcmode) {
- bfa_reg_write((rb + OP_MODE), 0);
- bfa_reg_write((rb + ETH_MAC_SER_REG),
- __APP_EMS_CMLCKSEL |
- __APP_EMS_REFCKBUFEN2 |
- __APP_EMS_CHANNEL_SEL);
+ writel(0, (rb + OP_MODE));
+ writel(__APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 |
+ __APP_EMS_CHANNEL_SEL, (rb + ETH_MAC_SER_REG));
} else {
- bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
- bfa_reg_write((rb + ETH_MAC_SER_REG),
- __APP_EMS_REFCKBUFEN1);
+ writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
+ writel(__APP_EMS_REFCKBUFEN1, (rb + ETH_MAC_SER_REG));
}
- bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
- bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
- bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
- bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
- __APP_PLL_312_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
- __APP_PLL_425_LOGIC_SOFT_RESET);
- bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
- __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE);
- bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
- __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE);
- bfa_reg_read(rb + HOSTFN0_INT_MSK);
- bfa_os_udelay(2000);
- bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
- bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
- bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
- __APP_PLL_312_ENABLE);
- bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
- __APP_PLL_425_ENABLE);
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET,
+ rb + APP_PLL_312_CTL_REG);
+ writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET,
+ rb + APP_PLL_425_CTL_REG);
+ writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
+ rb + APP_PLL_312_CTL_REG);
+ writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
+ rb + APP_PLL_425_CTL_REG);
+ readl(rb + HOSTFN0_INT_MSK);
+ udelay(2000);
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(pll_sclk | __APP_PLL_312_ENABLE, rb + APP_PLL_312_CTL_REG);
+ writel(pll_fclk | __APP_PLL_425_ENABLE, rb + APP_PLL_425_CTL_REG);
if (!fcmode) {
- bfa_reg_write((rb + PMM_1T_RESET_REG_P0), __PMM_1T_RESET_P);
- bfa_reg_write((rb + PMM_1T_RESET_REG_P1), __PMM_1T_RESET_P);
+ writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
+ writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
}
- r32 = bfa_reg_read((rb + PSS_CTL_REG));
+ r32 = readl((rb + PSS_CTL_REG));
r32 &= ~__PSS_LMEM_RESET;
- bfa_reg_write((rb + PSS_CTL_REG), r32);
- bfa_os_udelay(1000);
+ writel(r32, (rb + PSS_CTL_REG));
+ udelay(1000);
if (!fcmode) {
- bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0);
- bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0);
+ writel(0, (rb + PMM_1T_RESET_REG_P0));
+ writel(0, (rb + PMM_1T_RESET_REG_P1));
}
- bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
- bfa_os_udelay(1000);
- r32 = bfa_reg_read((rb + MBIST_STAT_REG));
- bfa_reg_write((rb + MBIST_CTL_REG), 0);
+ writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+ udelay(1000);
+ r32 = readl((rb + MBIST_STAT_REG));
+ writel(0, (rb + MBIST_CTL_REG));
return BFA_STATUS_OK;
}
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index 2cd527338677..ab79ff6fdeea 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -15,7 +15,7 @@
* General Public License for more details.
*/
-/**
+/*
* bfa_modules.h BFA modules
*/
@@ -52,7 +52,7 @@ enum {
};
-/**
+/*
* Macro to define a new BFA module
*/
#define BFA_MODULE(__mod) \
@@ -80,7 +80,7 @@ enum {
#define BFA_CACHELINE_SZ (256)
-/**
+/*
* Structure used to interact between different BFA sub modules
*
* Each sub module needs to implement only the entry points relevant to it (and
@@ -99,7 +99,6 @@ struct bfa_module_s {
void (*iocdisable) (struct bfa_s *bfa);
};
-extern struct bfa_module_s *hal_mods[];
struct bfa_s {
void *bfad; /* BFA driver instance */
@@ -116,8 +115,6 @@ struct bfa_s {
struct bfa_msix_s msix;
};
-extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX];
-extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[];
extern bfa_boolean_t bfa_auto_recover;
extern struct bfa_module_s hal_mod_sgpg;
extern struct bfa_module_s hal_mod_fcport;
diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h
deleted file mode 100644
index 788a250ffb8a..000000000000
--- a/drivers/scsi/bfa/bfa_os_inc.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) 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.
- */
-
-/**
- * Contains declarations all OS Specific files needed for BFA layer
- */
-
-#ifndef __BFA_OS_INC_H__
-#define __BFA_OS_INC_H__
-
-#include <linux/types.h>
-#include <linux/version.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/idr.h>
-#include <linux/interrupt.h>
-#include <linux/cdev.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/vmalloc.h>
-#include <linux/workqueue.h>
-#include <linux/bitops.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_transport_fc.h>
-#include <scsi/scsi_transport.h>
-
-#ifdef __BIG_ENDIAN
-#define __BIGENDIAN
-#endif
-
-static inline u64 bfa_os_get_clock(void)
-{
- return jiffies;
-}
-
-static inline u64 bfa_os_get_log_time(void)
-{
- u64 system_time = 0;
- struct timeval tv;
- do_gettimeofday(&tv);
-
- /* We are interested in seconds only. */
- system_time = tv.tv_sec;
- return system_time;
-}
-
-#define bfa_io_lat_clock_res_div HZ
-#define bfa_io_lat_clock_res_mul 1000
-
-#define BFA_ASSERT(p) do { \
- if (!(p)) { \
- printk(KERN_ERR "assert(%s) failed at %s:%d\n", \
- #p, __FILE__, __LINE__); \
- } \
-} while (0)
-
-#define BFA_LOG(level, bfad, mask, fmt, arg...) \
-do { \
- if (((mask) == 4) || (level[1] <= '4')) \
- dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \
-} while (0)
-
-#define bfa_swap_3b(_x) \
- ((((_x) & 0xff) << 16) | \
- ((_x) & 0x00ff00) | \
- (((_x) & 0xff0000) >> 16))
-
-#define bfa_swap_8b(_x) \
- ((((_x) & 0xff00000000000000ull) >> 56) \
- | (((_x) & 0x00ff000000000000ull) >> 40) \
- | (((_x) & 0x0000ff0000000000ull) >> 24) \
- | (((_x) & 0x000000ff00000000ull) >> 8) \
- | (((_x) & 0x00000000ff000000ull) << 8) \
- | (((_x) & 0x0000000000ff0000ull) << 24) \
- | (((_x) & 0x000000000000ff00ull) << 40) \
- | (((_x) & 0x00000000000000ffull) << 56))
-
-#define bfa_os_swap32(_x) \
- ((((_x) & 0xff) << 24) | \
- (((_x) & 0x0000ff00) << 8) | \
- (((_x) & 0x00ff0000) >> 8) | \
- (((_x) & 0xff000000) >> 24))
-
-#define bfa_os_swap_sgaddr(_x) ((u64)( \
- (((u64)(_x) & (u64)0x00000000000000ffull) << 32) | \
- (((u64)(_x) & (u64)0x000000000000ff00ull) << 32) | \
- (((u64)(_x) & (u64)0x0000000000ff0000ull) << 32) | \
- (((u64)(_x) & (u64)0x00000000ff000000ull) << 32) | \
- (((u64)(_x) & (u64)0x000000ff00000000ull) >> 32) | \
- (((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32) | \
- (((u64)(_x) & (u64)0x00ff000000000000ull) >> 32) | \
- (((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
-
-#ifndef __BIGENDIAN
-#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
- (((_x) & 0x00ff) << 8)))
-#define bfa_os_htonl(_x) bfa_os_swap32(_x)
-#define bfa_os_htonll(_x) bfa_swap_8b(_x)
-#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
-#define bfa_os_wtole(_x) (_x)
-#define bfa_os_sgaddr(_x) (_x)
-
-#else
-
-#define bfa_os_htons(_x) (_x)
-#define bfa_os_htonl(_x) (_x)
-#define bfa_os_hton3b(_x) (_x)
-#define bfa_os_htonll(_x) (_x)
-#define bfa_os_wtole(_x) bfa_os_swap32(_x)
-#define bfa_os_sgaddr(_x) bfa_os_swap_sgaddr(_x)
-
-#endif
-
-#define bfa_os_ntohs(_x) bfa_os_htons(_x)
-#define bfa_os_ntohl(_x) bfa_os_htonl(_x)
-#define bfa_os_ntohll(_x) bfa_os_htonll(_x)
-#define bfa_os_ntoh3b(_x) bfa_os_hton3b(_x)
-
-#define bfa_os_u32(__pa64) ((__pa64) >> 32)
-
-#define bfa_os_memset memset
-#define bfa_os_memcpy memcpy
-#define bfa_os_udelay udelay
-#define bfa_os_vsprintf vsprintf
-#define bfa_os_snprintf snprintf
-
-#define bfa_os_assign(__t, __s) __t = __s
-#define bfa_os_addr_t void __iomem *
-
-#define bfa_os_reg_read(_raddr) readl(_raddr)
-#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))
-#define bfa_os_mem_read(_raddr, _off) \
- bfa_os_swap32(readl(((_raddr) + (_off))))
-#define bfa_os_mem_write(_raddr, _off, _val) \
- writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))
-
-#define BFA_TRC_TS(_trcm) \
- ({ \
- struct timeval tv; \
- \
- do_gettimeofday(&tv); \
- (tv.tv_sec*1000000+tv.tv_usec); \
- })
-
-#define boolean_t int
-
-/**
- * For current time stamp, OS API will fill-in
- */
-struct bfa_timeval_s {
- u32 tv_sec; /* seconds */
- u32 tv_usec; /* microseconds */
-};
-
-static inline void
-bfa_os_gettimeofday(struct bfa_timeval_s *tv)
-{
- struct timeval tmp_tv;
-
- do_gettimeofday(&tmp_tv);
- tv->tv_sec = (u32) tmp_tv.tv_sec;
- tv->tv_usec = (u32) tmp_tv.tv_usec;
-}
-
-static inline void
-wwn2str(char *wwn_str, u64 wwn)
-{
- union {
- u64 wwn;
- u8 byte[8];
- } w;
-
- w.wwn = wwn;
- sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
- w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
- w.byte[6], w.byte[7]);
-}
-
-static inline void
-fcid2str(char *fcid_str, u32 fcid)
-{
- union {
- u32 fcid;
- u8 byte[4];
- } f;
-
- f.fcid = fcid;
- sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
-}
-
-#endif /* __BFA_OS_INC_H__ */
diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h
index 501f0ed35cf0..1c9baa68339b 100644
--- a/drivers/scsi/bfa/bfa_plog.h
+++ b/drivers/scsi/bfa/bfa_plog.h
@@ -151,9 +151,5 @@ void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
enum bfa_plog_eid event, u16 misc,
struct fchs_s *fchdr, u32 pld_w0);
-void bfa_plog_clear(struct bfa_plog_s *plog);
-void bfa_plog_enable(struct bfa_plog_s *plog);
-void bfa_plog_disable(struct bfa_plog_s *plog);
-bfa_boolean_t bfa_plog_get_setting(struct bfa_plog_s *plog);
#endif /* __BFA_PORTLOG_H__ */
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index b6d170a13bea..3f8e9d6066ec 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -15,6 +15,7 @@
* General Public License for more details.
*/
+#include "bfad_drv.h"
#include "bfa_defs_svc.h"
#include "bfa_port.h"
#include "bfi.h"
@@ -29,24 +30,24 @@ static void
bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats)
{
u32 *dip = (u32 *) stats;
- u32 t0, t1;
+ __be32 t0, t1;
int i;
for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32);
i += 2) {
t0 = dip[i];
t1 = dip[i + 1];
-#ifdef __BIGENDIAN
- dip[i] = bfa_os_ntohl(t0);
- dip[i + 1] = bfa_os_ntohl(t1);
+#ifdef __BIG_ENDIAN
+ dip[i] = be32_to_cpu(t0);
+ dip[i + 1] = be32_to_cpu(t1);
#else
- dip[i] = bfa_os_ntohl(t1);
- dip[i + 1] = bfa_os_ntohl(t0);
+ dip[i] = be32_to_cpu(t1);
+ dip[i + 1] = be32_to_cpu(t0);
#endif
}
}
-/**
+/*
* bfa_port_enable_isr()
*
*
@@ -63,7 +64,7 @@ bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status)
port->endis_cbfn(port->endis_cbarg, status);
}
-/**
+/*
* bfa_port_disable_isr()
*
*
@@ -80,7 +81,7 @@ bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status)
port->endis_cbfn(port->endis_cbarg, status);
}
-/**
+/*
* bfa_port_get_stats_isr()
*
*
@@ -96,13 +97,13 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
port->stats_busy = BFA_FALSE;
if (status == BFA_STATUS_OK) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
memcpy(port->stats, port->stats_dma.kva,
sizeof(union bfa_port_stats_u));
bfa_port_stats_swap(port, port->stats);
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time;
}
@@ -112,7 +113,7 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
}
}
-/**
+/*
* bfa_port_clear_stats_isr()
*
*
@@ -124,15 +125,15 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
static void
bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
{
- struct bfa_timeval_s tv;
+ struct timeval tv;
port->stats_status = status;
port->stats_busy = BFA_FALSE;
- /**
+ /*
* re-initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats_reset_time = tv.tv_sec;
if (port->stats_cbfn) {
@@ -141,7 +142,7 @@ bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
}
}
-/**
+/*
* bfa_port_isr()
*
*
@@ -185,11 +186,11 @@ bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m)
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
}
-/**
+/*
* bfa_port_meminfo()
*
*
@@ -203,7 +204,7 @@ bfa_port_meminfo(void)
return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ);
}
-/**
+/*
* bfa_port_mem_claim()
*
*
@@ -220,7 +221,7 @@ bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa)
port->stats_dma.pa = dma_pa;
}
-/**
+/*
* bfa_port_enable()
*
* Send the Port enable request to the f/w
@@ -264,7 +265,7 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
return BFA_STATUS_OK;
}
-/**
+/*
* bfa_port_disable()
*
* Send the Port disable request to the f/w
@@ -308,7 +309,7 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
return BFA_STATUS_OK;
}
-/**
+/*
* bfa_port_get_stats()
*
* Send the request to the f/w to fetch Port statistics.
@@ -348,7 +349,7 @@ bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats,
return BFA_STATUS_OK;
}
-/**
+/*
* bfa_port_clear_stats()
*
*
@@ -385,7 +386,7 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn,
return BFA_STATUS_OK;
}
-/**
+/*
* bfa_port_hbfail()
*
*
@@ -415,7 +416,7 @@ bfa_port_hbfail(void *arg)
}
}
-/**
+/*
* bfa_port_attach()
*
*
@@ -432,9 +433,9 @@ void
bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
void *dev, struct bfa_trc_mod_s *trcmod)
{
- struct bfa_timeval_s tv;
+ struct timeval tv;
- bfa_assert(port);
+ WARN_ON(!port);
port->dev = dev;
port->ioc = ioc;
@@ -447,27 +448,13 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
- bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
+ list_add_tail(&port->hbfail.qe, &port->ioc->hb_notify_q);
- /**
+ /*
* initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
port->stats_reset_time = tv.tv_sec;
bfa_trc(port, 0);
}
-
-/**
- * bfa_port_detach()
- *
- *
- * @param[in] port - Pointer to the Port module data structure
- *
- * @return void
- */
-void
-bfa_port_detach(struct bfa_port_s *port)
-{
- bfa_trc(port, 0);
-}
diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h
index dbce9dfd056b..c4ee9db6b470 100644
--- a/drivers/scsi/bfa/bfa_port.h
+++ b/drivers/scsi/bfa/bfa_port.h
@@ -48,7 +48,6 @@ struct bfa_port_s {
void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
void *dev, struct bfa_trc_mod_s *trcmod);
-void bfa_port_detach(struct bfa_port_s *port);
void bfa_port_hbfail(void *arg);
bfa_status_t bfa_port_get_stats(struct bfa_port_s *port,
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index aa1dc749b281..1d34921f88bf 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -15,11 +15,10 @@
* General Public License for more details.
*/
-#include "bfa_os_inc.h"
+#include "bfad_drv.h"
#include "bfa_plog.h"
#include "bfa_cs.h"
#include "bfa_modules.h"
-#include "bfad_drv.h"
BFA_TRC_FILE(HAL, FCXP);
BFA_MODULE(fcxp);
@@ -29,7 +28,7 @@ BFA_MODULE(fcport);
BFA_MODULE(rport);
BFA_MODULE(uf);
-/**
+/*
* LPS related definitions
*/
#define BFA_LPS_MIN_LPORTS (1)
@@ -41,21 +40,8 @@ BFA_MODULE(uf);
#define BFA_LPS_MAX_VPORTS_SUPP_CB 255
#define BFA_LPS_MAX_VPORTS_SUPP_CT 190
-/**
- * lps_pvt BFA LPS private functions
- */
-
-enum bfa_lps_event {
- BFA_LPS_SM_LOGIN = 1, /* login request from user */
- BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
- BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
- BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
- BFA_LPS_SM_DELETE = 5, /* lps delete from user */
- BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
- BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */
-};
-/**
+/*
* FC PORT related definitions
*/
/*
@@ -66,8 +52,7 @@ enum bfa_lps_event {
((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \
(bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
-
-/**
+/*
* BFA port state machine events
*/
enum bfa_fcport_sm_event {
@@ -82,7 +67,7 @@ enum bfa_fcport_sm_event {
BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */
};
-/**
+/*
* BFA port link notification state machine events
*/
@@ -92,7 +77,7 @@ enum bfa_fcport_ln_sm_event {
BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */
};
-/**
+/*
* RPORT related definitions
*/
#define bfa_rport_offline_cb(__rp) do { \
@@ -113,20 +98,7 @@ enum bfa_fcport_ln_sm_event {
} \
} while (0)
-
-enum bfa_rport_event {
- BFA_RPORT_SM_CREATE = 1, /* rport create event */
- BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
- BFA_RPORT_SM_ONLINE = 3, /* rport is online */
- BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
- BFA_RPORT_SM_FWRSP = 5, /* firmware response */
- BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
- BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
- BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
- BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
-};
-
-/**
+/*
* forward declarations FCXP related functions
*/
static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
@@ -138,7 +110,7 @@ static void bfa_fcxp_qresume(void *cbarg);
static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp,
struct bfi_fcxp_send_req_s *send_req);
-/**
+/*
* forward declarations for LPS functions
*/
static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
@@ -159,11 +131,12 @@ static void bfa_lps_reqq_resume(void *lps_arg);
static void bfa_lps_free(struct bfa_lps_s *lps);
static void bfa_lps_send_login(struct bfa_lps_s *lps);
static void bfa_lps_send_logout(struct bfa_lps_s *lps);
+static void bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps);
static void bfa_lps_login_comp(struct bfa_lps_s *lps);
static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
static void bfa_lps_cvl_event(struct bfa_lps_s *lps);
-/**
+/*
* forward declaration for LPS state machine
*/
static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
@@ -171,11 +144,13 @@ static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event
event);
static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event
event);
-/**
+/*
* forward declaration for FC Port functions
*/
static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport);
@@ -193,7 +168,7 @@ static void bfa_fcport_stats_get_timeout(void *cbarg);
static void bfa_fcport_stats_clr_timeout(void *cbarg);
static void bfa_trunk_iocdisable(struct bfa_s *bfa);
-/**
+/*
* forward declaration for FC PORT state machine
*/
static void bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
@@ -252,7 +227,7 @@ static struct bfa_sm_table_s hal_port_sm_table[] = {
};
-/**
+/*
* forward declaration for RPORT related functions
*/
static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
@@ -265,7 +240,7 @@ static void __bfa_cb_rport_online(void *cbarg,
static void __bfa_cb_rport_offline(void *cbarg,
bfa_boolean_t complete);
-/**
+/*
* forward declaration for RPORT state machine
*/
static void bfa_rport_sm_uninit(struct bfa_rport_s *rp,
@@ -295,7 +270,7 @@ static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp,
static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp,
enum bfa_rport_event event);
-/**
+/*
* PLOG related definitions
*/
static int
@@ -312,6 +287,18 @@ plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec)
return 0;
}
+static u64
+bfa_get_log_time(void)
+{
+ u64 system_time = 0;
+ struct timeval tv;
+ do_gettimeofday(&tv);
+
+ /* We are interested in seconds only. */
+ system_time = tv.tv_sec;
+ return system_time;
+}
+
static void
bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
{
@@ -322,7 +309,7 @@ bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
return;
if (plkd_validate_logrec(pl_rec)) {
- bfa_assert(0);
+ WARN_ON(1);
return;
}
@@ -330,9 +317,9 @@ bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
pl_recp = &(plog->plog_recs[tail]);
- bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
+ memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
- pl_recp->tv = bfa_os_get_log_time();
+ pl_recp->tv = bfa_get_log_time();
BFA_PL_LOG_REC_INCR(plog->tail);
if (plog->head == plog->tail)
@@ -342,9 +329,9 @@ bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
void
bfa_plog_init(struct bfa_plog_s *plog)
{
- bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s));
+ memset((char *)plog, 0, sizeof(struct bfa_plog_s));
- bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
+ memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
plog->head = plog->tail = 0;
plog->plog_enabled = 1;
}
@@ -357,7 +344,7 @@ bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
struct bfa_plog_rec_s lp;
if (plog->plog_enabled) {
- bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
lp.mid = mid;
lp.eid = event;
lp.log_type = BFA_PL_LOG_TYPE_STRING;
@@ -381,15 +368,14 @@ bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
num_ints = BFA_PL_INT_LOG_SZ;
if (plog->plog_enabled) {
- bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
lp.mid = mid;
lp.eid = event;
lp.log_type = BFA_PL_LOG_TYPE_INT;
lp.misc = misc;
for (i = 0; i < num_ints; i++)
- bfa_os_assign(lp.log_entry.int_log[i],
- intarr[i]);
+ lp.log_entry.int_log[i] = intarr[i];
lp.log_num_ints = (u8) num_ints;
@@ -407,7 +393,7 @@ bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
u32 ints[BFA_PL_INT_LOG_SZ];
if (plog->plog_enabled) {
- bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
ints[0] = tmp_int[0];
ints[1] = tmp_int[1];
@@ -427,7 +413,7 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
u32 ints[BFA_PL_INT_LOG_SZ];
if (plog->plog_enabled) {
- bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
ints[0] = tmp_int[0];
ints[1] = tmp_int[1];
@@ -438,31 +424,8 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
}
}
-void
-bfa_plog_clear(struct bfa_plog_s *plog)
-{
- plog->head = plog->tail = 0;
-}
-void
-bfa_plog_enable(struct bfa_plog_s *plog)
-{
- plog->plog_enabled = 1;
-}
-
-void
-bfa_plog_disable(struct bfa_plog_s *plog)
-{
- plog->plog_enabled = 0;
-}
-
-bfa_boolean_t
-bfa_plog_get_setting(struct bfa_plog_s *plog)
-{
- return (bfa_boolean_t)plog->plog_enabled;
-}
-
-/**
+/*
* fcxp_pvt BFA FCXP private functions
*/
@@ -485,7 +448,7 @@ claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
mod->req_pld_list_pa = dm_pa;
dm_kva += buf_pool_sz;
dm_pa += buf_pool_sz;
- bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz);
+ memset(mod->req_pld_list_kva, 0, buf_pool_sz);
/*
* Initialize the fcxp rsp payload list
@@ -495,7 +458,7 @@ claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
mod->rsp_pld_list_pa = dm_pa;
dm_kva += buf_pool_sz;
dm_pa += buf_pool_sz;
- bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
+ memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
bfa_meminfo_dma_virt(mi) = dm_kva;
bfa_meminfo_dma_phys(mi) = dm_pa;
@@ -508,7 +471,7 @@ claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
struct bfa_fcxp_s *fcxp;
fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi);
- bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
+ memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
INIT_LIST_HEAD(&mod->fcxp_free_q);
INIT_LIST_HEAD(&mod->fcxp_active_q);
@@ -559,11 +522,11 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
{
struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
- bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
+ memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
mod->bfa = bfa;
mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;
- /**
+ /*
* Initialize FCXP request and response payload sizes.
*/
mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
@@ -638,15 +601,15 @@ bfa_fcxp_init_reqrsp(struct bfa_fcxp_s *fcxp,
bfa_fcxp_get_sglen_t sglen_cbfn)
{
- bfa_assert(bfa != NULL);
+ WARN_ON(bfa == NULL);
bfa_trc(bfa, fcxp->fcxp_tag);
if (n_sgles == 0) {
*use_ibuf = 1;
} else {
- bfa_assert(*sga_cbfn != NULL);
- bfa_assert(*sglen_cbfn != NULL);
+ WARN_ON(*sga_cbfn == NULL);
+ WARN_ON(*sglen_cbfn == NULL);
*use_ibuf = 0;
*r_sga_cbfn = sga_cbfn;
@@ -658,7 +621,7 @@ bfa_fcxp_init_reqrsp(struct bfa_fcxp_s *fcxp,
* alloc required sgpgs
*/
if (n_sgles > BFI_SGE_INLINE)
- bfa_assert(0);
+ WARN_ON(1);
}
}
@@ -672,7 +635,7 @@ bfa_fcxp_init(struct bfa_fcxp_s *fcxp,
bfa_fcxp_get_sglen_t rsp_sglen_cbfn)
{
- bfa_assert(bfa != NULL);
+ WARN_ON(bfa == NULL);
bfa_trc(bfa, fcxp->fcxp_tag);
@@ -709,7 +672,7 @@ bfa_fcxp_put(struct bfa_fcxp_s *fcxp)
return;
}
- bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
+ WARN_ON(!bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
list_del(&fcxp->qe);
list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
}
@@ -741,24 +704,24 @@ hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
{
struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
struct bfa_fcxp_s *fcxp;
- u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag);
+ u16 fcxp_tag = be16_to_cpu(fcxp_rsp->fcxp_tag);
bfa_trc(bfa, fcxp_tag);
- fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len);
+ fcxp_rsp->rsp_len = be32_to_cpu(fcxp_rsp->rsp_len);
- /**
+ /*
* @todo f/w should not set residue to non-0 when everything
* is received.
*/
if (fcxp_rsp->req_status == BFA_STATUS_OK)
fcxp_rsp->residue_len = 0;
else
- fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len);
+ fcxp_rsp->residue_len = be32_to_cpu(fcxp_rsp->residue_len);
fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);
- bfa_assert(fcxp->send_cbfn != NULL);
+ WARN_ON(fcxp->send_cbfn == NULL);
hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp);
@@ -856,7 +819,7 @@ hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
}
}
-/**
+/*
* Handler to resume sending fcxp when space in available in cpe queue.
*/
static void
@@ -871,7 +834,7 @@ bfa_fcxp_qresume(void *cbarg)
bfa_fcxp_queue(fcxp, send_req);
}
-/**
+/*
* Queue fcxp send request to foimrware.
*/
static void
@@ -885,26 +848,26 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
bfa_lpuid(bfa));
- send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag);
+ send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag);
if (rport) {
send_req->rport_fw_hndl = rport->fw_handle;
- send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz);
+ send_req->max_frmsz = cpu_to_be16(rport->rport_info.max_frmsz);
if (send_req->max_frmsz == 0)
- send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
} else {
send_req->rport_fw_hndl = 0;
- send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
}
- send_req->vf_id = bfa_os_htons(reqi->vf_id);
+ send_req->vf_id = cpu_to_be16(reqi->vf_id);
send_req->lp_tag = reqi->lp_tag;
send_req->class = reqi->class;
send_req->rsp_timeout = rspi->rsp_timeout;
send_req->cts = reqi->cts;
send_req->fchs = reqi->fchs;
- send_req->req_len = bfa_os_htonl(reqi->req_tot_len);
- send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen);
+ send_req->req_len = cpu_to_be32(reqi->req_tot_len);
+ send_req->rsp_maxlen = cpu_to_be32(rspi->rsp_maxlen);
/*
* setup req sgles
@@ -914,13 +877,13 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
BFA_FCXP_REQ_PLD_PA(fcxp));
} else {
if (fcxp->nreq_sgles > 0) {
- bfa_assert(fcxp->nreq_sgles == 1);
+ WARN_ON(fcxp->nreq_sgles != 1);
hal_fcxp_set_local_sges(send_req->req_sge,
reqi->req_tot_len,
fcxp->req_sga_cbfn(fcxp->caller,
0));
} else {
- bfa_assert(reqi->req_tot_len == 0);
+ WARN_ON(reqi->req_tot_len != 0);
hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
}
}
@@ -929,20 +892,20 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
* setup rsp sgles
*/
if (fcxp->use_irspbuf == 1) {
- bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ);
+ WARN_ON(rspi->rsp_maxlen > BFA_FCXP_MAX_LBUF_SZ);
hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen,
BFA_FCXP_RSP_PLD_PA(fcxp));
} else {
if (fcxp->nrsp_sgles > 0) {
- bfa_assert(fcxp->nrsp_sgles == 1);
+ WARN_ON(fcxp->nrsp_sgles != 1);
hal_fcxp_set_local_sges(send_req->rsp_sge,
rspi->rsp_maxlen,
fcxp->rsp_sga_cbfn(fcxp->caller,
0));
} else {
- bfa_assert(rspi->rsp_maxlen == 0);
+ WARN_ON(rspi->rsp_maxlen != 0);
hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
}
}
@@ -955,11 +918,7 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
}
-/**
- * hal_fcxp_api BFA FCXP API
- */
-
-/**
+/*
* Allocate an FCXP instance to send a response or to send a request
* that has a response. Request/response buffers are allocated by caller.
*
@@ -991,7 +950,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
{
struct bfa_fcxp_s *fcxp = NULL;
- bfa_assert(bfa != NULL);
+ WARN_ON(bfa == NULL);
fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
if (fcxp == NULL)
@@ -1005,7 +964,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
return fcxp;
}
-/**
+/*
* Get the internal request buffer pointer
*
* @param[in] fcxp BFA fcxp pointer
@@ -1018,7 +977,7 @@ bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp)
struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
void *reqbuf;
- bfa_assert(fcxp->use_ireqbuf == 1);
+ WARN_ON(fcxp->use_ireqbuf != 1);
reqbuf = ((u8 *)mod->req_pld_list_kva) +
fcxp->fcxp_tag * mod->req_pld_sz;
return reqbuf;
@@ -1032,7 +991,7 @@ bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp)
return mod->req_pld_sz;
}
-/**
+/*
* Get the internal response buffer pointer
*
* @param[in] fcxp BFA fcxp pointer
@@ -1045,15 +1004,15 @@ bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
void *rspbuf;
- bfa_assert(fcxp->use_irspbuf == 1);
+ WARN_ON(fcxp->use_irspbuf != 1);
rspbuf = ((u8 *)mod->rsp_pld_list_kva) +
fcxp->fcxp_tag * mod->rsp_pld_sz;
return rspbuf;
}
-/**
- * Free the BFA FCXP
+/*
+ * Free the BFA FCXP
*
* @param[in] fcxp BFA fcxp pointer
*
@@ -1064,12 +1023,12 @@ bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
{
struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
- bfa_assert(fcxp != NULL);
+ WARN_ON(fcxp == NULL);
bfa_trc(mod->bfa, fcxp->fcxp_tag);
bfa_fcxp_put(fcxp);
}
-/**
+/*
* Send a FCXP request
*
* @param[in] fcxp BFA fcxp pointer
@@ -1103,7 +1062,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
bfa_trc(bfa, fcxp->fcxp_tag);
- /**
+ /*
* setup request/response info
*/
reqi->bfa_rport = rport;
@@ -1118,7 +1077,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
fcxp->send_cbarg = cbarg;
- /**
+ /*
* If no room in CPE queue, wait for space in request queue
*/
send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
@@ -1132,7 +1091,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
bfa_fcxp_queue(fcxp, send_req);
}
-/**
+/*
* Abort a BFA FCXP
*
* @param[in] fcxp BFA fcxp pointer
@@ -1143,7 +1102,7 @@ bfa_status_t
bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
{
bfa_trc(fcxp->fcxp_mod->bfa, fcxp->fcxp_tag);
- bfa_assert(0);
+ WARN_ON(1);
return BFA_STATUS_OK;
}
@@ -1158,7 +1117,7 @@ bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
{
struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
- bfa_assert(list_empty(&mod->fcxp_free_q));
+ WARN_ON(!list_empty(&mod->fcxp_free_q));
wqe->alloc_cbfn = alloc_cbfn;
wqe->alloc_cbarg = alloc_cbarg;
@@ -1179,14 +1138,14 @@ bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
{
struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
- bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe));
+ WARN_ON(!bfa_q_is_on_q(&mod->wait_q, wqe));
list_del(&wqe->qe);
}
void
bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
{
- /**
+ /*
* If waiting for room in request queue, cancel reqq wait
* and free fcxp.
*/
@@ -1200,12 +1159,6 @@ bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
fcxp->send_cbfn = bfa_fcxp_null_comp;
}
-
-
-/**
- * hal_fcxp_public BFA FCXP public functions
- */
-
void
bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
{
@@ -1216,7 +1169,7 @@ bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
default:
bfa_trc(bfa, msg->mhdr.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
@@ -1229,11 +1182,11 @@ bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
}
-/**
+/*
* BFA LPS state machine functions
*/
-/**
+/*
* Init state -- no login
*/
static void
@@ -1285,7 +1238,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
}
}
-/**
+/*
* login is in progress -- awaiting response from firmware
*/
static void
@@ -1304,6 +1257,12 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
else
bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
BFA_PL_EID_LOGIN, 0, "FLOGI Accept");
+ /* If N2N, send the assigned PID to FW */
+ bfa_trc(lps->bfa, lps->fport);
+ bfa_trc(lps->bfa, lps->lp_pid);
+
+ if (!lps->fport && lps->lp_pid)
+ bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
} else {
bfa_sm_set_state(lps, bfa_lps_sm_init);
if (lps->fdisc)
@@ -1322,12 +1281,17 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
bfa_sm_set_state(lps, bfa_lps_sm_init);
break;
+ case BFA_LPS_SM_SET_N2N_PID:
+ bfa_trc(lps->bfa, lps->fport);
+ bfa_trc(lps->bfa, lps->lp_pid);
+ break;
+
default:
bfa_sm_fault(lps->bfa, event);
}
}
-/**
+/*
* login pending - awaiting space in request queue
*/
static void
@@ -1359,7 +1323,7 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
}
}
-/**
+/*
* login complete
*/
static void
@@ -1390,6 +1354,14 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
break;
+ case BFA_LPS_SM_SET_N2N_PID:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_online_n2n_pid_wait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else
+ bfa_lps_send_set_n2n_pid(lps);
+ break;
+
case BFA_LPS_SM_OFFLINE:
case BFA_LPS_SM_DELETE:
bfa_sm_set_state(lps, bfa_lps_sm_init);
@@ -1400,7 +1372,49 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
}
}
-/**
+/*
+ * login complete
+ */
+static void
+bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_online);
+ bfa_lps_send_set_n2n_pid(lps);
+ break;
+
+ case BFA_LPS_SM_LOGOUT:
+ bfa_sm_set_state(lps, bfa_lps_sm_logowait);
+ bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+ BFA_PL_EID_LOGO, 0, "Logout");
+ break;
+
+ case BFA_LPS_SM_RX_CVL:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+
+ /* Let the vport module know about this event */
+ bfa_lps_cvl_event(lps);
+ bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
+ BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ case BFA_LPS_SM_DELETE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+ break;
+
+ default:
+ bfa_sm_fault(lps->bfa, event);
+ }
+}
+
+/*
* logout in progress - awaiting firmware response
*/
static void
@@ -1424,7 +1438,7 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
}
}
-/**
+/*
* logout pending -- awaiting space in request queue
*/
static void
@@ -1451,11 +1465,11 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
-/**
+/*
* lps_pvt BFA LPS private functions
*/
-/**
+/*
* return memory requirement
*/
static void
@@ -1468,7 +1482,7 @@ bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
*ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS;
}
-/**
+/*
* bfa module attach at initialization time
*/
static void
@@ -1479,7 +1493,7 @@ bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_lps_s *lps;
int i;
- bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s));
+ memset(mod, 0, sizeof(struct bfa_lps_mod_s));
mod->num_lps = BFA_LPS_MAX_LPORTS;
if (cfg->drvcfg.min_cfg)
mod->num_lps = BFA_LPS_MIN_LPORTS;
@@ -1516,7 +1530,7 @@ bfa_lps_stop(struct bfa_s *bfa)
{
}
-/**
+/*
* IOC in disabled state -- consider all lps offline
*/
static void
@@ -1532,7 +1546,7 @@ bfa_lps_iocdisable(struct bfa_s *bfa)
}
}
-/**
+/*
* Firmware login response
*/
static void
@@ -1541,16 +1555,17 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
struct bfa_lps_s *lps;
- bfa_assert(rsp->lp_tag < mod->num_lps);
+ WARN_ON(rsp->lp_tag >= mod->num_lps);
lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
lps->status = rsp->status;
switch (rsp->status) {
case BFA_STATUS_OK:
lps->fport = rsp->f_port;
+ if (lps->fport)
+ lps->lp_pid = rsp->lp_pid;
lps->npiv_en = rsp->npiv_en;
- lps->lp_pid = rsp->lp_pid;
- lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit);
+ lps->pr_bbcred = be16_to_cpu(rsp->bb_credit);
lps->pr_pwwn = rsp->port_name;
lps->pr_nwwn = rsp->node_name;
lps->auth_req = rsp->auth_req;
@@ -1579,7 +1594,7 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
}
-/**
+/*
* Firmware logout response
*/
static void
@@ -1588,13 +1603,13 @@ bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
struct bfa_lps_s *lps;
- bfa_assert(rsp->lp_tag < mod->num_lps);
+ WARN_ON(rsp->lp_tag >= mod->num_lps);
lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
}
-/**
+/*
* Firmware received a Clear virtual link request (for FCoE)
*/
static void
@@ -1608,7 +1623,7 @@ bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl)
bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL);
}
-/**
+/*
* Space is available in request queue, resume queueing request to firmware.
*/
static void
@@ -1619,7 +1634,7 @@ bfa_lps_reqq_resume(void *lps_arg)
bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
}
-/**
+/*
* lps is freed -- triggered by vport delete
*/
static void
@@ -1632,7 +1647,7 @@ bfa_lps_free(struct bfa_lps_s *lps)
list_add_tail(&lps->qe, &mod->lps_free_q);
}
-/**
+/*
* send login request to firmware
*/
static void
@@ -1641,14 +1656,14 @@ bfa_lps_send_login(struct bfa_lps_s *lps)
struct bfi_lps_login_req_s *m;
m = bfa_reqq_next(lps->bfa, lps->reqq);
- bfa_assert(m);
+ WARN_ON(!m);
bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ,
bfa_lpuid(lps->bfa));
m->lp_tag = lps->lp_tag;
m->alpa = lps->alpa;
- m->pdu_size = bfa_os_htons(lps->pdusz);
+ m->pdu_size = cpu_to_be16(lps->pdusz);
m->pwwn = lps->pwwn;
m->nwwn = lps->nwwn;
m->fdisc = lps->fdisc;
@@ -1657,7 +1672,7 @@ bfa_lps_send_login(struct bfa_lps_s *lps)
bfa_reqq_produce(lps->bfa, lps->reqq);
}
-/**
+/*
* send logout request to firmware
*/
static void
@@ -1666,7 +1681,7 @@ bfa_lps_send_logout(struct bfa_lps_s *lps)
struct bfi_lps_logout_req_s *m;
m = bfa_reqq_next(lps->bfa, lps->reqq);
- bfa_assert(m);
+ WARN_ON(!m);
bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ,
bfa_lpuid(lps->bfa));
@@ -1676,7 +1691,26 @@ bfa_lps_send_logout(struct bfa_lps_s *lps)
bfa_reqq_produce(lps->bfa, lps->reqq);
}
-/**
+/*
+ * send n2n pid set request to firmware
+ */
+static void
+bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_n2n_pid_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ WARN_ON(!m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->lp_pid = lps->lp_pid;
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
+/*
* Indirect login completion handler for non-fcs
*/
static void
@@ -1693,7 +1727,7 @@ bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
}
-/**
+/*
* Login completion handler -- direct call for fcs, queue for others
*/
static void
@@ -1711,7 +1745,7 @@ bfa_lps_login_comp(struct bfa_lps_s *lps)
bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
}
-/**
+/*
* Indirect logout completion handler for non-fcs
*/
static void
@@ -1726,7 +1760,7 @@ bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
}
-/**
+/*
* Logout completion handler -- direct call for fcs, queue for others
*/
static void
@@ -1741,7 +1775,7 @@ bfa_lps_logout_comp(struct bfa_lps_s *lps)
bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
}
-/**
+/*
* Clear virtual link completion handler for non-fcs
*/
static void
@@ -1757,7 +1791,7 @@ bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete)
bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
}
-/**
+/*
* Received Clear virtual link event --direct call for fcs,
* queue for others
*/
@@ -1777,7 +1811,7 @@ bfa_lps_cvl_event(struct bfa_lps_s *lps)
-/**
+/*
* lps_public BFA LPS public functions
*/
@@ -1790,7 +1824,7 @@ bfa_lps_get_max_vport(struct bfa_s *bfa)
return BFA_LPS_MAX_VPORTS_SUPP_CB;
}
-/**
+/*
* Allocate a lport srvice tag.
*/
struct bfa_lps_s *
@@ -1810,7 +1844,7 @@ bfa_lps_alloc(struct bfa_s *bfa)
return lps;
}
-/**
+/*
* Free lport service tag. This can be called anytime after an alloc.
* No need to wait for any pending login/logout completions.
*/
@@ -1820,7 +1854,7 @@ bfa_lps_delete(struct bfa_lps_s *lps)
bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
}
-/**
+/*
* Initiate a lport login.
*/
void
@@ -1837,7 +1871,7 @@ bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
}
-/**
+/*
* Initiate a lport fdisc login.
*/
void
@@ -1854,16 +1888,8 @@ bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
}
-/**
- * Initiate a lport logout (flogi).
- */
-void
-bfa_lps_flogo(struct bfa_lps_s *lps)
-{
- bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
-}
-/**
+/*
* Initiate a lport FDSIC logout.
*/
void
@@ -1872,26 +1898,8 @@ bfa_lps_fdisclogo(struct bfa_lps_s *lps)
bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
}
-/**
- * Discard a pending login request -- should be called only for
- * link down handling.
- */
-void
-bfa_lps_discard(struct bfa_lps_s *lps)
-{
- bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
-}
-/**
- * Return lport services tag
- */
-u8
-bfa_lps_get_tag(struct bfa_lps_s *lps)
-{
- return lps->lp_tag;
-}
-
-/**
+/*
* Return lport services tag given the pid
*/
u8
@@ -1910,57 +1918,8 @@ bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid)
return 0;
}
-/**
- * return if fabric login indicates support for NPIV
- */
-bfa_boolean_t
-bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
-{
- return lps->npiv_en;
-}
-
-/**
- * Return TRUE if attached to F-Port, else return FALSE
- */
-bfa_boolean_t
-bfa_lps_is_fport(struct bfa_lps_s *lps)
-{
- return lps->fport;
-}
-
-/**
- * Return TRUE if attached to a Brocade Fabric
- */
-bfa_boolean_t
-bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
-{
- return lps->brcd_switch;
-}
-/**
- * return TRUE if authentication is required
- */
-bfa_boolean_t
-bfa_lps_is_authreq(struct bfa_lps_s *lps)
-{
- return lps->auth_req;
-}
-
-bfa_eproto_status_t
-bfa_lps_get_extstatus(struct bfa_lps_s *lps)
-{
- return lps->ext_status;
-}
-
-/**
- * return port id assigned to the lport
- */
-u32
-bfa_lps_get_pid(struct bfa_lps_s *lps)
-{
- return lps->lp_pid;
-}
-/**
+/*
* return port id assigned to the base lport
*/
u32
@@ -1971,61 +1930,20 @@ bfa_lps_get_base_pid(struct bfa_s *bfa)
return BFA_LPS_FROM_TAG(mod, 0)->lp_pid;
}
-/**
- * Return bb_credit assigned in FLOGI response
- */
-u16
-bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
-{
- return lps->pr_bbcred;
-}
-
-/**
- * Return peer port name
- */
-wwn_t
-bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
-{
- return lps->pr_pwwn;
-}
-
-/**
- * Return peer node name
- */
-wwn_t
-bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
-{
- return lps->pr_nwwn;
-}
-
-/**
- * return reason code if login request is rejected
- */
-u8
-bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
-{
- return lps->lsrjt_rsn;
-}
-
-/**
- * return explanation code if login request is rejected
+/*
+ * Set PID in case of n2n (which is assigned during PLOGI)
*/
-u8
-bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
+void
+bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid)
{
- return lps->lsrjt_expl;
-}
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, n2n_pid);
-/**
- * Return fpma/spma MAC for lport
- */
-mac_t
-bfa_lps_get_lp_mac(struct bfa_lps_s *lps)
-{
- return lps->lp_mac;
+ lps->lp_pid = n2n_pid;
+ bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
}
-/**
+/*
* LPS firmware message class handler.
*/
void
@@ -2051,11 +1969,11 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
default:
bfa_trc(bfa, m->mhdr.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
-/**
+/*
* FC PORT state machine functions
*/
static void
@@ -2066,9 +1984,11 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
switch (event) {
case BFA_FCPORT_SM_START:
- /**
+ /*
* Start event after IOC is configured and BFA is started.
*/
+ fcport->use_flash_cfg = BFA_TRUE;
+
if (bfa_fcport_send_enable(fcport)) {
bfa_trc(fcport->bfa, BFA_TRUE);
bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
@@ -2080,7 +2000,7 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
break;
case BFA_FCPORT_SM_ENABLE:
- /**
+ /*
* Port is persistently configured to be in enabled state. Do
* not change state. Port enabling is done when START event is
* received.
@@ -2088,7 +2008,7 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
break;
case BFA_FCPORT_SM_DISABLE:
- /**
+ /*
* If a port is persistently configured to be disabled, the
* first event will a port disable request.
*/
@@ -2124,13 +2044,13 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
break;
case BFA_FCPORT_SM_ENABLE:
- /**
+ /*
* Already enable is in progress.
*/
break;
case BFA_FCPORT_SM_DISABLE:
- /**
+ /*
* Just send disable request to firmware when room becomes
* available in request queue.
*/
@@ -2139,13 +2059,13 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
case BFA_FCPORT_SM_LINKUP:
case BFA_FCPORT_SM_LINKDOWN:
- /**
+ /*
* Possible to get link events when doing back-to-back
* enable/disables.
*/
@@ -2179,12 +2099,12 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
bfa_fcport_update_linkinfo(fcport);
bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);
- bfa_assert(fcport->event_cbfn);
+ WARN_ON(!fcport->event_cbfn);
bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
break;
case BFA_FCPORT_SM_ENABLE:
- /**
+ /*
* Already being enabled.
*/
break;
@@ -2199,7 +2119,7 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
@@ -2230,7 +2150,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
case BFA_FCPORT_SM_LINKUP:
bfa_fcport_update_linkinfo(fcport);
bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);
- bfa_assert(fcport->event_cbfn);
+ WARN_ON(!fcport->event_cbfn);
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
@@ -2252,18 +2172,18 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port online: WWN = %s\n", pwwn_buf);
break;
case BFA_FCPORT_SM_LINKDOWN:
- /**
+ /*
* Possible to get link down event.
*/
break;
case BFA_FCPORT_SM_ENABLE:
- /**
+ /*
* Already enabled.
*/
break;
@@ -2278,7 +2198,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
@@ -2306,7 +2226,7 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
switch (event) {
case BFA_FCPORT_SM_ENABLE:
- /**
+ /*
* Already enabled.
*/
break;
@@ -2323,9 +2243,9 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
@@ -2337,10 +2257,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
@@ -2350,10 +2270,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
bfa_fcport_reset_linkinfo(fcport);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
@@ -2364,10 +2284,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
@@ -2399,14 +2319,14 @@ bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
break;
case BFA_FCPORT_SM_DISABLE:
- /**
+ /*
* Already being disabled.
*/
break;
case BFA_FCPORT_SM_LINKUP:
case BFA_FCPORT_SM_LINKDOWN:
- /**
+ /*
* Possible to get link events when doing back-to-back
* enable/disables.
*/
@@ -2453,7 +2373,7 @@ bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport,
case BFA_FCPORT_SM_LINKUP:
case BFA_FCPORT_SM_LINKDOWN:
- /**
+ /*
* Possible to get link events when doing back-to-back
* enable/disables.
*/
@@ -2483,7 +2403,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
break;
case BFA_FCPORT_SM_DISABLE:
- /**
+ /*
* Already being disabled.
*/
break;
@@ -2498,7 +2418,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
@@ -2508,7 +2428,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
case BFA_FCPORT_SM_LINKUP:
case BFA_FCPORT_SM_LINKDOWN:
- /**
+ /*
* Possible to get link events when doing back-to-back
* enable/disables.
*/
@@ -2533,7 +2453,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
switch (event) {
case BFA_FCPORT_SM_START:
- /**
+ /*
* Ignore start event for a port that is disabled.
*/
break;
@@ -2552,12 +2472,12 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
case BFA_FCPORT_SM_DISABLE:
- /**
+ /*
* Already disabled.
*/
break;
@@ -2587,14 +2507,14 @@ bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
break;
default:
- /**
+ /*
* Ignore all other events.
*/
;
}
}
-/**
+/*
* Port is enabled. IOC is down/failed.
*/
static void
@@ -2613,14 +2533,14 @@ bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
break;
default:
- /**
+ /*
* Ignore all events.
*/
;
}
}
-/**
+/*
* Port is disabled. IOC is down/failed.
*/
static void
@@ -2639,14 +2559,14 @@ bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
break;
default:
- /**
+ /*
* Ignore all events.
*/
;
}
}
-/**
+/*
* Link state is down
*/
static void
@@ -2666,7 +2586,7 @@ bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is waiting for down notification
*/
static void
@@ -2689,7 +2609,7 @@ bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is waiting for down notification and there is a pending up
*/
static void
@@ -2713,7 +2633,7 @@ bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is up
*/
static void
@@ -2733,7 +2653,7 @@ bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is waiting for up notification
*/
static void
@@ -2756,7 +2676,7 @@ bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is waiting for up notification and there is a pending down
*/
static void
@@ -2780,7 +2700,7 @@ bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln,
}
}
-/**
+/*
* Link state is waiting for up notification and there are pending down and up
*/
static void
@@ -2804,12 +2724,6 @@ bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln,
}
}
-
-
-/**
- * hal_port_private
- */
-
static void
__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete)
{
@@ -2821,7 +2735,7 @@ __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete)
bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION);
}
-/**
+/*
* Send SCN notification to upper layers.
* trunk - false if caller is fcport to ignore fcport event in trunked mode
*/
@@ -2840,7 +2754,7 @@ bfa_fcport_scn(struct bfa_fcport_s *fcport, enum bfa_port_linkstate event,
bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKDOWN);
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
}
}
@@ -2897,7 +2811,7 @@ bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo)
bfa_meminfo_dma_phys(meminfo) = dm_pa;
}
-/**
+/*
* Memory initialization.
*/
static void
@@ -2907,9 +2821,9 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
struct bfa_port_cfg_s *port_cfg = &fcport->cfg;
struct bfa_fcport_ln_s *ln = &fcport->ln;
- struct bfa_timeval_s tv;
+ struct timeval tv;
- bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s));
+ memset(fcport, 0, sizeof(struct bfa_fcport_s));
fcport->bfa = bfa;
ln->fcport = fcport;
@@ -2918,13 +2832,13 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_sm_set_state(fcport, bfa_fcport_sm_uninit);
bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
- /**
+ /*
* initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_reset_time = tv.tv_sec;
- /**
+ /*
* initialize and set default configuration
*/
port_cfg->topology = BFA_PORT_TOPOLOGY_P2P;
@@ -2942,7 +2856,7 @@ bfa_fcport_detach(struct bfa_s *bfa)
{
}
-/**
+/*
* Called when IOC is ready.
*/
static void
@@ -2951,7 +2865,7 @@ bfa_fcport_start(struct bfa_s *bfa)
bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START);
}
-/**
+/*
* Called before IOC is stopped.
*/
static void
@@ -2961,7 +2875,7 @@ bfa_fcport_stop(struct bfa_s *bfa)
bfa_trunk_iocdisable(bfa);
}
-/**
+/*
* Called when IOC failure is detected.
*/
static void
@@ -2986,18 +2900,17 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport)
fcport->myalpa = 0;
/* QoS Details */
- bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr);
- bfa_os_assign(fcport->qos_vc_attr,
- pevent->link_state.vc_fcf.qos_vc_attr);
+ fcport->qos_attr = pevent->link_state.qos_attr;
+ fcport->qos_vc_attr = pevent->link_state.vc_fcf.qos_vc_attr;
- /**
+ /*
* update trunk state if applicable
*/
if (!fcport->cfg.trunked)
trunk->attr.state = BFA_TRUNK_DISABLED;
/* update FCoE specific */
- fcport->fcoe_vlan = bfa_os_ntohs(pevent->link_state.vc_fcf.fcf.vlan);
+ fcport->fcoe_vlan = be16_to_cpu(pevent->link_state.vc_fcf.fcf.vlan);
bfa_trc(fcport->bfa, fcport->speed);
bfa_trc(fcport->bfa, fcport->topology);
@@ -3010,7 +2923,7 @@ bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport)
fcport->topology = BFA_PORT_TOPOLOGY_NONE;
}
-/**
+/*
* Send port enable message to firmware.
*/
static bfa_boolean_t
@@ -3018,13 +2931,13 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
{
struct bfi_fcport_enable_req_s *m;
- /**
+ /*
* Increment message tag before queue check, so that responses to old
* requests are discarded.
*/
fcport->msgtag++;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3040,19 +2953,20 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
m->pwwn = fcport->pwwn;
m->port_cfg = fcport->cfg;
m->msgtag = fcport->msgtag;
- m->port_cfg.maxfrsize = bfa_os_htons(fcport->cfg.maxfrsize);
+ m->port_cfg.maxfrsize = cpu_to_be16(fcport->cfg.maxfrsize);
+ m->use_flash_cfg = fcport->use_flash_cfg;
bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi);
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
return BFA_TRUE;
}
-/**
+/*
* Send port disable message to firmware.
*/
static bfa_boolean_t
@@ -3060,13 +2974,13 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
{
struct bfi_fcport_req_s *m;
- /**
+ /*
* Increment message tag before queue check, so that responses to old
* requests are discarded.
*/
fcport->msgtag++;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3080,7 +2994,7 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
bfa_lpuid(fcport->bfa));
m->msgtag = fcport->msgtag;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3091,8 +3005,8 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
static void
bfa_fcport_set_wwns(struct bfa_fcport_s *fcport)
{
- fcport->pwwn = bfa_ioc_get_pwwn(&fcport->bfa->ioc);
- fcport->nwwn = bfa_ioc_get_nwwn(&fcport->bfa->ioc);
+ fcport->pwwn = fcport->bfa->ioc.attr->pwwn;
+ fcport->nwwn = fcport->bfa->ioc.attr->nwwn;
bfa_trc(fcport->bfa, fcport->pwwn);
bfa_trc(fcport->bfa, fcport->nwwn);
@@ -3105,7 +3019,7 @@ bfa_fcport_send_txcredit(void *port_cbarg)
struct bfa_fcport_s *fcport = port_cbarg;
struct bfi_fcport_set_svc_params_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3116,9 +3030,9 @@ bfa_fcport_send_txcredit(void *port_cbarg)
bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ,
bfa_lpuid(fcport->bfa));
- m->tx_bbcredit = bfa_os_htons((u16)fcport->cfg.tx_bbcredit);
+ m->tx_bbcredit = cpu_to_be16((u16)fcport->cfg.tx_bbcredit);
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3129,12 +3043,12 @@ bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d,
struct bfa_qos_stats_s *s)
{
u32 *dip = (u32 *) d;
- u32 *sip = (u32 *) s;
+ __be32 *sip = (__be32 *) s;
int i;
/* Now swap the 32 bit fields */
for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i)
- dip[i] = bfa_os_ntohl(sip[i]);
+ dip[i] = be32_to_cpu(sip[i]);
}
static void
@@ -3142,17 +3056,17 @@ bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
struct bfa_fcoe_stats_s *s)
{
u32 *dip = (u32 *) d;
- u32 *sip = (u32 *) s;
+ __be32 *sip = (__be32 *) s;
int i;
for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32));
i = i + 2) {
-#ifdef __BIGENDIAN
- dip[i] = bfa_os_ntohl(sip[i]);
- dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
+#ifdef __BIG_ENDIAN
+ dip[i] = be32_to_cpu(sip[i]);
+ dip[i + 1] = be32_to_cpu(sip[i + 1]);
#else
- dip[i] = bfa_os_ntohl(sip[i + 1]);
- dip[i + 1] = bfa_os_ntohl(sip[i]);
+ dip[i] = be32_to_cpu(sip[i + 1]);
+ dip[i + 1] = be32_to_cpu(sip[i]);
#endif
}
}
@@ -3164,7 +3078,7 @@ __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
if (complete) {
if (fcport->stats_status == BFA_STATUS_OK) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
/* Swap FC QoS or FCoE stats */
if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
@@ -3176,7 +3090,7 @@ __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
&fcport->stats_ret->fcoe,
&fcport->stats->fcoe);
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_ret->fcoe.secs_reset =
tv.tv_sec - fcport->stats_reset_time;
}
@@ -3223,7 +3137,7 @@ bfa_fcport_send_stats_get(void *cbarg)
}
fcport->stats_qfull = BFA_FALSE;
- bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+ memset(msg, 0, sizeof(struct bfi_fcport_req_s));
bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ,
bfa_lpuid(fcport->bfa));
bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3235,12 +3149,12 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
struct bfa_fcport_s *fcport = cbarg;
if (complete) {
- struct bfa_timeval_s tv;
+ struct timeval tv;
- /**
+ /*
* re-initialize time stamp for stats reset
*/
- bfa_os_gettimeofday(&tv);
+ do_gettimeofday(&tv);
fcport->stats_reset_time = tv.tv_sec;
fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
@@ -3285,13 +3199,13 @@ bfa_fcport_send_stats_clear(void *cbarg)
}
fcport->stats_qfull = BFA_FALSE;
- bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+ memset(msg, 0, sizeof(struct bfi_fcport_req_s));
bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ,
bfa_lpuid(fcport->bfa));
bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
}
-/**
+/*
* Handle trunk SCN event from firmware.
*/
static void
@@ -3305,14 +3219,14 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
int link_bm = 0;
bfa_trc(fcport->bfa, fcport->cfg.trunked);
- bfa_assert(scn->trunk_state == BFA_TRUNK_ONLINE ||
- scn->trunk_state == BFA_TRUNK_OFFLINE);
+ WARN_ON(scn->trunk_state != BFA_TRUNK_ONLINE &&
+ scn->trunk_state != BFA_TRUNK_OFFLINE);
bfa_trc(fcport->bfa, trunk->attr.state);
bfa_trc(fcport->bfa, scn->trunk_state);
bfa_trc(fcport->bfa, scn->trunk_speed);
- /**
+ /*
* Save off new state for trunk attribute query
*/
state_prev = trunk->attr.state;
@@ -3327,7 +3241,7 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
lattr->trunk_wwn = tlink->trunk_wwn;
lattr->fctl = tlink->fctl;
lattr->speed = tlink->speed;
- lattr->deskew = bfa_os_ntohl(tlink->deskew);
+ lattr->deskew = be32_to_cpu(tlink->deskew);
if (tlink->state == BFA_TRUNK_LINK_STATE_UP) {
fcport->speed = tlink->speed;
@@ -3360,7 +3274,7 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
BFA_PL_EID_TRUNK_SCN, 0, "Trunk down");
}
- /**
+ /*
* Notify upper layers if trunk state changed.
*/
if ((state_prev != trunk->attr.state) ||
@@ -3376,7 +3290,7 @@ bfa_trunk_iocdisable(struct bfa_s *bfa)
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
int i = 0;
- /**
+ /*
* In trunked mode, notify upper layers that link is down
*/
if (fcport->cfg.trunked) {
@@ -3398,13 +3312,7 @@ bfa_trunk_iocdisable(struct bfa_s *bfa)
}
}
-
-
-/**
- * hal_port_public
- */
-
-/**
+/*
* Called to initialize port attributes
*/
void
@@ -3412,7 +3320,7 @@ bfa_fcport_init(struct bfa_s *bfa)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- /**
+ /*
* Initialize port attributes from IOC hardware data.
*/
bfa_fcport_set_wwns(fcport);
@@ -3421,12 +3329,12 @@ bfa_fcport_init(struct bfa_s *bfa)
fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
- bfa_assert(fcport->cfg.maxfrsize);
- bfa_assert(fcport->cfg.rx_bbcredit);
- bfa_assert(fcport->speed_sup);
+ WARN_ON(!fcport->cfg.maxfrsize);
+ WARN_ON(!fcport->cfg.rx_bbcredit);
+ WARN_ON(!fcport->speed_sup);
}
-/**
+/*
* Firmware message handler.
*/
void
@@ -3443,8 +3351,28 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
switch (msg->mhdr.msg_id) {
case BFI_FCPORT_I2H_ENABLE_RSP:
- if (fcport->msgtag == i2hmsg.penable_rsp->msgtag)
+ if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) {
+
+ if (fcport->use_flash_cfg) {
+ fcport->cfg = i2hmsg.penable_rsp->port_cfg;
+ fcport->cfg.maxfrsize =
+ cpu_to_be16(fcport->cfg.maxfrsize);
+ fcport->cfg.path_tov =
+ cpu_to_be16(fcport->cfg.path_tov);
+ fcport->cfg.q_depth =
+ cpu_to_be16(fcport->cfg.q_depth);
+
+ if (fcport->cfg.trunked)
+ fcport->trunk.attr.state =
+ BFA_TRUNK_OFFLINE;
+ else
+ fcport->trunk.attr.state =
+ BFA_TRUNK_DISABLED;
+ fcport->use_flash_cfg = BFA_FALSE;
+ }
+
bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
+ }
break;
case BFI_FCPORT_I2H_DISABLE_RSP:
@@ -3500,18 +3428,12 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
break;
}
}
-
-
-/**
- * hal_port_api
- */
-
-/**
+/*
* Registered callback for port events.
*/
void
@@ -3552,7 +3474,7 @@ bfa_fcport_disable(struct bfa_s *bfa)
return BFA_STATUS_OK;
}
-/**
+/*
* Configure port speed.
*/
bfa_status_t
@@ -3574,7 +3496,7 @@ bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed)
return BFA_STATUS_OK;
}
-/**
+/*
* Get current speed.
*/
enum bfa_port_speed
@@ -3585,7 +3507,7 @@ bfa_fcport_get_speed(struct bfa_s *bfa)
return fcport->speed;
}
-/**
+/*
* Configure port topology.
*/
bfa_status_t
@@ -3610,7 +3532,7 @@ bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topology)
return BFA_STATUS_OK;
}
-/**
+/*
* Get current topology.
*/
enum bfa_port_topology
@@ -3710,7 +3632,7 @@ bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
bfa_fcport_send_txcredit(fcport);
}
-/**
+/*
* Get port attributes.
*/
@@ -3729,15 +3651,15 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- bfa_os_memset(attr, 0, sizeof(struct bfa_port_attr_s));
+ memset(attr, 0, sizeof(struct bfa_port_attr_s));
attr->nwwn = fcport->nwwn;
attr->pwwn = fcport->pwwn;
- attr->factorypwwn = bfa_ioc_get_mfg_pwwn(&bfa->ioc);
- attr->factorynwwn = bfa_ioc_get_mfg_nwwn(&bfa->ioc);
+ attr->factorypwwn = bfa->ioc.attr->mfg_pwwn;
+ attr->factorynwwn = bfa->ioc.attr->mfg_nwwn;
- bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg,
+ memcpy(&attr->pport_cfg, &fcport->cfg,
sizeof(struct bfa_port_cfg_s));
/* speed attributes */
attr->pport_cfg.speed = fcport->cfg.speed;
@@ -3753,7 +3675,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
/* beacon attributes */
attr->beacon = fcport->beacon;
attr->link_e2e_beacon = fcport->link_e2e_beacon;
- attr->plog_enabled = bfa_plog_get_setting(fcport->bfa->plog);
+ attr->plog_enabled = (bfa_boolean_t)fcport->bfa->plog->plog_enabled;
attr->io_profile = bfa_fcpim_get_io_profile(fcport->bfa);
attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
@@ -3770,7 +3692,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
#define BFA_FCPORT_STATS_TOV 1000
-/**
+/*
* Fetch port statistics (FCQoS or FCoE).
*/
bfa_status_t
@@ -3796,7 +3718,7 @@ bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
return BFA_STATUS_OK;
}
-/**
+/*
* Reset port statistics (FCQoS or FCoE).
*/
bfa_status_t
@@ -3820,91 +3742,8 @@ bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
return BFA_STATUS_OK;
}
-/**
- * Fetch FCQoS port statistics
- */
-bfa_status_t
-bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FC mode */
- bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
-}
-
-/**
- * Reset FCoE port statistics
- */
-bfa_status_t
-bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FC mode */
- bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
-}
-
-/**
- * Fetch FCQoS port statistics
- */
-bfa_status_t
-bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FCoE mode */
- bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
-}
-/**
- * Reset FCoE port statistics
- */
-bfa_status_t
-bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
-{
- /* Meaningful only for FCoE mode */
- bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc));
-
- return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
-}
-
-void
-bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- qos_attr->state = fcport->qos_attr.state;
- qos_attr->total_bb_cr = bfa_os_ntohl(fcport->qos_attr.total_bb_cr);
-}
-
-void
-bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
- struct bfa_qos_vc_attr_s *qos_vc_attr)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
- u32 i = 0;
-
- qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
- qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit);
- qos_vc_attr->elp_opmode_flags =
- bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags);
-
- /* Individual VC info */
- while (i < qos_vc_attr->total_vc_count) {
- qos_vc_attr->vc_info[i].vc_credit =
- bfa_vc_attr->vc_info[i].vc_credit;
- qos_vc_attr->vc_info[i].borrow_credit =
- bfa_vc_attr->vc_info[i].borrow_credit;
- qos_vc_attr->vc_info[i].priority =
- bfa_vc_attr->vc_info[i].priority;
- ++i;
- }
-}
-
-/**
+/*
* Fetch port attributes.
*/
bfa_boolean_t
@@ -3926,61 +3765,7 @@ bfa_fcport_is_ratelim(struct bfa_s *bfa)
}
-void
-bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa);
-
- bfa_trc(bfa, on_off);
- bfa_trc(bfa, fcport->cfg.qos_enabled);
-
- bfa_trc(bfa, ioc_type);
-
- if (ioc_type == BFA_IOC_TYPE_FC) {
- fcport->cfg.qos_enabled = on_off;
- /**
- * Notify fcpim of the change in QoS state
- */
- bfa_fcpim_update_ioredirect(bfa);
- }
-}
-
-void
-bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, on_off);
- bfa_trc(bfa, fcport->cfg.ratelimit);
-
- fcport->cfg.ratelimit = on_off;
- if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN)
- fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS;
-}
-
-/**
- * Configure default minimum ratelim speed
- */
-bfa_status_t
-bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_port_speed speed)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, speed);
-
- /* Auto and speeds greater than the supported speed, are invalid */
- if ((speed == BFA_PORT_SPEED_AUTO) || (speed > fcport->speed_sup)) {
- bfa_trc(bfa, fcport->speed_sup);
- return BFA_STATUS_UNSUPP_SPEED;
- }
-
- fcport->cfg.trl_def_speed = speed;
-
- return BFA_STATUS_OK;
-}
-
-/**
+/*
* Get default minimum ratelim speed
*/
enum bfa_port_speed
@@ -3992,32 +3777,6 @@ bfa_fcport_get_ratelim_speed(struct bfa_s *bfa)
return fcport->cfg.trl_def_speed;
}
-void
-bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, status);
- bfa_trc(bfa, fcport->diag_busy);
-
- fcport->diag_busy = status;
-}
-
-void
-bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
- bfa_boolean_t link_e2e_beacon)
-{
- struct bfa_s *bfa = dev;
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- bfa_trc(bfa, beacon);
- bfa_trc(bfa, link_e2e_beacon);
- bfa_trc(bfa, fcport->beacon);
- bfa_trc(bfa, fcport->link_e2e_beacon);
-
- fcport->beacon = beacon;
- fcport->link_e2e_beacon = link_e2e_beacon;
-}
bfa_boolean_t
bfa_fcport_is_linkup(struct bfa_s *bfa)
@@ -4038,67 +3797,10 @@ bfa_fcport_is_qos_enabled(struct bfa_s *bfa)
return fcport->cfg.qos_enabled;
}
-bfa_status_t
-bfa_trunk_get_attr(struct bfa_s *bfa, struct bfa_trunk_attr_s *attr)
-
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, fcport->cfg.trunked);
- bfa_trc(bfa, trunk->attr.state);
- *attr = trunk->attr;
- attr->port_id = bfa_lps_get_base_pid(bfa);
-
- return BFA_STATUS_OK;
-}
-
-void
-bfa_trunk_enable_cfg(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 1);
- trunk->attr.state = BFA_TRUNK_OFFLINE;
- fcport->cfg.trunked = BFA_TRUE;
-}
-
-bfa_status_t
-bfa_trunk_enable(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 1);
-
- trunk->attr.state = BFA_TRUNK_OFFLINE;
- bfa_fcport_disable(bfa);
- fcport->cfg.trunked = BFA_TRUE;
- bfa_fcport_enable(bfa);
-
- return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_trunk_disable(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
- struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
-
- bfa_trc(bfa, 0);
- trunk->attr.state = BFA_TRUNK_DISABLED;
- bfa_fcport_disable(bfa);
- fcport->cfg.trunked = BFA_FALSE;
- bfa_fcport_enable(bfa);
- return BFA_STATUS_OK;
-}
-
-
-/**
+/*
* Rport State machine functions
*/
-/**
+/*
* Beginning state, only online event expected.
*/
static void
@@ -4151,7 +3853,7 @@ bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Waiting for rport create response from firmware.
*/
static void
@@ -4188,7 +3890,7 @@ bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Request queue is full, awaiting queue resume to send create request.
*/
static void
@@ -4229,7 +3931,7 @@ bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Online state - normal parking state.
*/
static void
@@ -4275,9 +3977,9 @@ bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority);
qos_scn->old_qos_attr.qos_flow_id =
- bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id);
+ be32_to_cpu(qos_scn->old_qos_attr.qos_flow_id);
qos_scn->new_qos_attr.qos_flow_id =
- bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id);
+ be32_to_cpu(qos_scn->new_qos_attr.qos_flow_id);
if (qos_scn->old_qos_attr.qos_flow_id !=
qos_scn->new_qos_attr.qos_flow_id)
@@ -4297,7 +3999,7 @@ bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Firmware rport is being deleted - awaiting f/w response.
*/
static void
@@ -4360,7 +4062,7 @@ bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Offline state.
*/
static void
@@ -4395,7 +4097,7 @@ bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Rport is deleted, waiting for firmware response to delete.
*/
static void
@@ -4447,7 +4149,7 @@ bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
}
}
-/**
+/*
* Waiting for rport create response from firmware. A delete is pending.
*/
static void
@@ -4478,7 +4180,7 @@ bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
}
}
-/**
+/*
* Waiting for rport create response from firmware. Rport offline is pending.
*/
static void
@@ -4513,7 +4215,7 @@ bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
}
}
-/**
+/*
* IOC h/w failed.
*/
static void
@@ -4553,7 +4255,7 @@ bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
-/**
+/*
* bfa_rport_private BFA rport private functions
*/
@@ -4608,16 +4310,16 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
mod->rps_list = rp;
mod->num_rports = cfg->fwcfg.num_rports;
- bfa_assert(mod->num_rports &&
- !(mod->num_rports & (mod->num_rports - 1)));
+ WARN_ON(!mod->num_rports ||
+ (mod->num_rports & (mod->num_rports - 1)));
for (i = 0; i < mod->num_rports; i++, rp++) {
- bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s));
+ memset(rp, 0, sizeof(struct bfa_rport_s));
rp->bfa = bfa;
rp->rport_tag = i;
bfa_sm_set_state(rp, bfa_rport_sm_uninit);
- /**
+ /*
* - is unused
*/
if (i)
@@ -4626,7 +4328,7 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp);
}
- /**
+ /*
* consume memory
*/
bfa_meminfo_kva(meminfo) = (u8 *) rp;
@@ -4677,7 +4379,7 @@ bfa_rport_free(struct bfa_rport_s *rport)
{
struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa);
- bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport));
+ WARN_ON(!bfa_q_is_on_q(&mod->rp_active_q, rport));
list_del(&rport->qe);
list_add_tail(&rport->qe, &mod->rp_free_q);
}
@@ -4687,7 +4389,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
{
struct bfi_rport_create_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4699,7 +4401,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ,
bfa_lpuid(rp->bfa));
m->bfa_handle = rp->rport_tag;
- m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz);
+ m->max_frmsz = cpu_to_be16(rp->rport_info.max_frmsz);
m->pid = rp->rport_info.pid;
m->lp_tag = rp->rport_info.lp_tag;
m->local_pid = rp->rport_info.local_pid;
@@ -4708,7 +4410,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
m->vf_id = rp->rport_info.vf_id;
m->cisc = rp->rport_info.cisc;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4720,7 +4422,7 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
{
struct bfi_rport_delete_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4733,7 +4435,7 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
bfa_lpuid(rp->bfa));
m->fw_handle = rp->fw_handle;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4745,7 +4447,7 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
{
struct bfa_rport_speed_req_s *m;
- /**
+ /*
* check for room in queue to send request now
*/
m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4759,7 +4461,7 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
m->fw_handle = rp->fw_handle;
m->speed = (u8)rp->rport_info.speed;
- /**
+ /*
* queue I/O message to firmware
*/
bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4768,11 +4470,11 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
-/**
+/*
* bfa_rport_public
*/
-/**
+/*
* Rport interrupt processing.
*/
void
@@ -4790,13 +4492,13 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle);
rp->fw_handle = msg.create_rsp->fw_handle;
rp->qos_attr = msg.create_rsp->qos_attr;
- bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ WARN_ON(msg.create_rsp->status != BFA_STATUS_OK);
bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
break;
case BFI_RPORT_I2H_DELETE_RSP:
rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle);
- bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK);
bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
break;
@@ -4808,13 +4510,13 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
default:
bfa_trc(bfa, m->mhdr.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
-/**
+/*
* bfa_rport_api
*/
@@ -4830,26 +4532,20 @@ bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
rp->bfa = bfa;
rp->rport_drv = rport_drv;
- bfa_rport_clear_stats(rp);
+ memset(&rp->stats, 0, sizeof(rp->stats));
- bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
+ WARN_ON(!bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
return rp;
}
void
-bfa_rport_delete(struct bfa_rport_s *rport)
-{
- bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE);
-}
-
-void
bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
{
- bfa_assert(rport_info->max_frmsz != 0);
+ WARN_ON(rport_info->max_frmsz == 0);
- /**
+ /*
* Some JBODs are seen to be not setting PDU size correctly in PLOGI
* responses. Default to minimum size.
*/
@@ -4858,54 +4554,26 @@ bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
rport_info->max_frmsz = FC_MIN_PDUSZ;
}
- bfa_os_assign(rport->rport_info, *rport_info);
+ rport->rport_info = *rport_info;
bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
}
void
-bfa_rport_offline(struct bfa_rport_s *rport)
-{
- bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE);
-}
-
-void
bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed)
{
- bfa_assert(speed != 0);
- bfa_assert(speed != BFA_PORT_SPEED_AUTO);
+ WARN_ON(speed == 0);
+ WARN_ON(speed == BFA_PORT_SPEED_AUTO);
rport->rport_info.speed = speed;
bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
}
-void
-bfa_rport_get_stats(struct bfa_rport_s *rport,
- struct bfa_rport_hal_stats_s *stats)
-{
- *stats = rport->stats;
-}
-void
-bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
- struct bfa_rport_qos_attr_s *qos_attr)
-{
- qos_attr->qos_priority = rport->qos_attr.qos_priority;
- qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id);
-
-}
-
-void
-bfa_rport_clear_stats(struct bfa_rport_s *rport)
-{
- bfa_os_memset(&rport->stats, 0, sizeof(rport->stats));
-}
-
-
-/**
+/*
* SGPG related functions
*/
-/**
+/*
* Compute and return memory needed by FCP(im) module.
*/
static void
@@ -4954,11 +4622,11 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
sgpg_pa.pa = mod->sgpg_arr_pa;
mod->free_sgpgs = mod->num_sgpgs;
- bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
+ WARN_ON(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1));
for (i = 0; i < mod->num_sgpgs; i++) {
- bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
- bfa_os_memset(sgpg, 0, sizeof(*sgpg));
+ memset(hsgpg, 0, sizeof(*hsgpg));
+ memset(sgpg, 0, sizeof(*sgpg));
hsgpg->sgpg = sgpg;
sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa);
@@ -4995,12 +4663,6 @@ bfa_sgpg_iocdisable(struct bfa_s *bfa)
{
}
-
-
-/**
- * hal_sgpg_public BFA SGPG public functions
- */
-
bfa_status_t
bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
{
@@ -5008,14 +4670,12 @@ bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
struct bfa_sgpg_s *hsgpg;
int i;
- bfa_trc_fp(bfa, nsgpgs);
-
if (mod->free_sgpgs < nsgpgs)
return BFA_STATUS_ENOMEM;
for (i = 0; i < nsgpgs; i++) {
bfa_q_deq(&mod->sgpg_q, &hsgpg);
- bfa_assert(hsgpg);
+ WARN_ON(!hsgpg);
list_add_tail(&hsgpg->qe, sgpg_q);
}
@@ -5029,17 +4689,15 @@ bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
struct bfa_sgpg_wqe_s *wqe;
- bfa_trc_fp(bfa, nsgpg);
-
mod->free_sgpgs += nsgpg;
- bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
+ WARN_ON(mod->free_sgpgs > mod->num_sgpgs);
list_splice_tail_init(sgpg_q, &mod->sgpg_q);
if (list_empty(&mod->sgpg_wait_q))
return;
- /**
+ /*
* satisfy as many waiting requests as possible
*/
do {
@@ -5062,19 +4720,19 @@ bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
{
struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
- bfa_assert(nsgpg > 0);
- bfa_assert(nsgpg > mod->free_sgpgs);
+ WARN_ON(nsgpg <= 0);
+ WARN_ON(nsgpg <= mod->free_sgpgs);
wqe->nsgpg_total = wqe->nsgpg = nsgpg;
- /**
+ /*
* allocate any left to this one first
*/
if (mod->free_sgpgs) {
- /**
+ /*
* no one else is waiting for SGPG
*/
- bfa_assert(list_empty(&mod->sgpg_wait_q));
+ WARN_ON(!list_empty(&mod->sgpg_wait_q));
list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
wqe->nsgpg -= mod->free_sgpgs;
mod->free_sgpgs = 0;
@@ -5088,7 +4746,7 @@ bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
{
struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
- bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
+ WARN_ON(!bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
list_del(&wqe->qe);
if (wqe->nsgpg_total != wqe->nsgpg)
@@ -5105,7 +4763,7 @@ bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
wqe->cbarg = cbarg;
}
-/**
+/*
* UF related functions
*/
/*
@@ -5136,7 +4794,7 @@ claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz;
bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz;
- bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
+ memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
}
static void
@@ -5153,11 +4811,11 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs;
i++, uf_bp_msg++) {
- bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
+ memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
uf_bp_msg->buf_tag = i;
buf_len = sizeof(struct bfa_uf_buf_s);
- uf_bp_msg->buf_len = bfa_os_htons(buf_len);
+ uf_bp_msg->buf_len = cpu_to_be16(buf_len);
bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST,
bfa_lpuid(ufm->bfa));
@@ -5173,7 +4831,7 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
bfa_sge_to_be(&sge[1]);
}
- /**
+ /*
* advance pointer beyond consumed memory
*/
bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg;
@@ -5194,7 +4852,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
* Initialize UFs and queue it in UF free queue
*/
for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) {
- bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s));
+ memset(uf, 0, sizeof(struct bfa_uf_s));
uf->bfa = ufm->bfa;
uf->uf_tag = i;
uf->pb_len = sizeof(struct bfa_uf_buf_s);
@@ -5203,7 +4861,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
list_add_tail(&uf->qe, &ufm->uf_free_q);
}
- /**
+ /*
* advance memory pointer
*/
bfa_meminfo_kva(mi) = (u8 *) uf;
@@ -5241,7 +4899,7 @@ bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
{
struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
- bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
+ memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
ufm->bfa = bfa;
ufm->num_ufs = cfg->fwcfg.num_uf_bufs;
INIT_LIST_HEAD(&ufm->uf_free_q);
@@ -5279,7 +4937,7 @@ bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf)
if (!uf_post_msg)
return BFA_STATUS_FAILED;
- bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
+ memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
sizeof(struct bfi_uf_buf_post_s));
bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP);
@@ -5310,8 +4968,8 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
u8 *buf = &uf_buf->d[0];
struct fchs_s *fchs;
- m->frm_len = bfa_os_ntohs(m->frm_len);
- m->xfr_len = bfa_os_ntohs(m->xfr_len);
+ m->frm_len = be16_to_cpu(m->frm_len);
+ m->xfr_len = be16_to_cpu(m->xfr_len);
fchs = (struct fchs_s *)uf_buf;
@@ -5320,7 +4978,7 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
uf->data_ptr = buf;
uf->data_len = m->xfr_len;
- bfa_assert(uf->data_len >= sizeof(struct fchs_s));
+ WARN_ON(uf->data_len < sizeof(struct fchs_s));
if (uf->data_len == sizeof(struct fchs_s)) {
bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX,
@@ -5363,13 +5021,7 @@ bfa_uf_start(struct bfa_s *bfa)
bfa_uf_post_all(BFA_UF_MOD(bfa));
}
-
-
-/**
- * hal_uf_api
- */
-
-/**
+/*
* Register handler for all unsolicted recieve frames.
*
* @param[in] bfa BFA instance
@@ -5385,7 +5037,7 @@ bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg)
ufm->cbarg = cbarg;
}
-/**
+/*
* Free an unsolicited frame back to BFA.
*
* @param[in] uf unsolicited frame to be freed
@@ -5401,7 +5053,7 @@ bfa_uf_free(struct bfa_uf_s *uf)
-/**
+/*
* uf_pub BFA uf module public functions
*/
void
@@ -5416,7 +5068,7 @@ bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
default:
bfa_trc(bfa, msg->mhdr.msg_id);
- bfa_assert(0);
+ WARN_ON(1);
}
}
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index 9921dad0d039..331ad992a581 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -22,12 +22,12 @@
#include "bfi_ms.h"
-/**
+/*
* Scatter-gather DMA related defines
*/
#define BFA_SGPG_MIN (16)
-/**
+/*
* Alignment macro for SG page allocation
*/
#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \
@@ -48,7 +48,7 @@ struct bfa_sgpg_s {
union bfi_addr_u sgpg_pa; /* pa of SG page */
};
-/**
+/*
* Given number of SG elements, BFA_SGPG_NPAGE() returns the number of
* SG pages required.
*/
@@ -75,7 +75,7 @@ void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpgs);
void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe);
-/**
+/*
* FCXP related defines
*/
#define BFA_FCXP_MIN (1)
@@ -115,12 +115,12 @@ typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp);
-/**
+/*
* Information needed for a FCXP request
*/
struct bfa_fcxp_req_info_s {
struct bfa_rport_s *bfa_rport;
- /** Pointer to the bfa rport that was
+ /* Pointer to the bfa rport that was
* returned from bfa_rport_create().
* This could be left NULL for WKA or
* for FCXP interactions before the
@@ -137,11 +137,10 @@ struct bfa_fcxp_req_info_s {
struct bfa_fcxp_rsp_info_s {
struct fchs_s rsp_fchs;
- /** !< Response frame's FC header will
+ /* Response frame's FC header will
* be sent back in this field */
u8 rsp_timeout;
- /** !< timeout in seconds, 0-no response
- */
+ /* timeout in seconds, 0-no response */
u8 rsvd2[3];
u32 rsp_maxlen; /* max response length expected */
};
@@ -218,9 +217,21 @@ struct bfa_fcxp_wqe_s {
void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
-/**
+/*
* RPORT related defines
*/
+enum bfa_rport_event {
+ BFA_RPORT_SM_CREATE = 1, /* rport create event */
+ BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
+ BFA_RPORT_SM_ONLINE = 3, /* rport is online */
+ BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
+ BFA_RPORT_SM_FWRSP = 5, /* firmware response */
+ BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
+ BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
+ BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
+ BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
+};
+
#define BFA_RPORT_MIN 4
struct bfa_rport_mod_s {
@@ -232,7 +243,7 @@ struct bfa_rport_mod_s {
#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod)
-/**
+/*
* Convert rport tag to RPORT
*/
#define BFA_RPORT_FROM_TAG(__bfa, _tag) \
@@ -244,7 +255,7 @@ struct bfa_rport_mod_s {
*/
void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
-/**
+/*
* BFA rport information.
*/
struct bfa_rport_info_s {
@@ -259,7 +270,7 @@ struct bfa_rport_info_s {
enum bfa_port_speed speed; /* Rport's current speed */
};
-/**
+/*
* BFA rport data structure
*/
struct bfa_rport_s {
@@ -282,7 +293,7 @@ struct bfa_rport_s {
#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class)
-/**
+/*
* UF - unsolicited receive related defines
*/
@@ -305,7 +316,7 @@ struct bfa_uf_s {
struct bfa_sge_s sges[BFI_SGE_INLINE_MAX];
};
-/**
+/*
* Callback prototype for unsolicited frame receive handler.
*
* @param[in] cbarg callback arg for receive handler
@@ -338,7 +349,7 @@ void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
#define BFA_UF_BUFSZ (2 * 1024 + 256)
-/**
+/*
* @todo private
*/
struct bfa_uf_buf_s {
@@ -346,7 +357,7 @@ struct bfa_uf_buf_s {
};
-/**
+/*
* LPS - bfa lport login/logout service interface
*/
struct bfa_lps_s {
@@ -397,14 +408,14 @@ struct bfa_lps_mod_s {
void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
-/**
+/*
* FCPORT related defines
*/
#define BFA_FCPORT(_bfa) (&((_bfa)->modules.port))
typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status);
-/**
+/*
* Link notification data structure
*/
struct bfa_fcport_ln_s {
@@ -418,7 +429,7 @@ struct bfa_fcport_trunk_s {
struct bfa_trunk_attr_s attr;
};
-/**
+/*
* BFA FC port data structure
*/
struct bfa_fcport_s {
@@ -433,6 +444,7 @@ struct bfa_fcport_s {
u8 myalpa; /* my ALPA in LOOP topology */
u8 rsvd[3];
struct bfa_port_cfg_s cfg; /* current port configuration */
+ bfa_boolean_t use_flash_cfg; /* get port cfg from flash */
struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
struct bfa_reqq_wait_s reqq_wait;
@@ -501,30 +513,9 @@ void bfa_fcport_event_register(struct bfa_s *bfa,
void (*event_cbfn) (void *cbarg,
enum bfa_port_linkstate event), void *event_cbarg);
bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa);
-void bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
-void bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
-bfa_status_t bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa,
- enum bfa_port_speed speed);
enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa);
void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
-void bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status);
-void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
- bfa_boolean_t link_e2e_beacon);
-void bfa_fcport_qos_get_attr(struct bfa_s *bfa,
- struct bfa_qos_attr_s *qos_attr);
-void bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
- struct bfa_qos_vc_attr_s *qos_vc_attr);
-bfa_status_t bfa_fcport_get_qos_stats(struct bfa_s *bfa,
- union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
- void *cbarg);
-bfa_status_t bfa_fcport_get_fcoe_stats(struct bfa_s *bfa,
- union bfa_fcport_stats_u *stats,
- bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
- void *cbarg);
bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa);
bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa);
bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
@@ -538,14 +529,9 @@ bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
* bfa rport API functions
*/
struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv);
-void bfa_rport_delete(struct bfa_rport_s *rport);
void bfa_rport_online(struct bfa_rport_s *rport,
struct bfa_rport_info_s *rport_info);
-void bfa_rport_offline(struct bfa_rport_s *rport);
void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed);
-void bfa_rport_get_stats(struct bfa_rport_s *rport,
- struct bfa_rport_hal_stats_s *stats);
-void bfa_rport_clear_stats(struct bfa_rport_s *rport);
void bfa_cb_rport_online(void *rport);
void bfa_cb_rport_offline(void *rport);
void bfa_cb_rport_qos_scn_flowid(void *rport,
@@ -554,8 +540,6 @@ void bfa_cb_rport_qos_scn_flowid(void *rport,
void bfa_cb_rport_qos_scn_prio(void *rport,
struct bfa_rport_qos_attr_s old_qos_attr,
struct bfa_rport_qos_attr_s new_qos_attr);
-void bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
- struct bfa_rport_qos_attr_s *qos_attr);
/*
* bfa fcxp API functions
@@ -613,45 +597,25 @@ void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv,
void *cbarg);
void bfa_uf_free(struct bfa_uf_s *uf);
-/**
+/*
* bfa lport service api
*/
u32 bfa_lps_get_max_vport(struct bfa_s *bfa);
struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa);
void bfa_lps_delete(struct bfa_lps_s *lps);
-void bfa_lps_discard(struct bfa_lps_s *lps);
void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa,
u16 pdusz, wwn_t pwwn, wwn_t nwwn,
bfa_boolean_t auth_en);
void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz,
wwn_t pwwn, wwn_t nwwn);
-void bfa_lps_flogo(struct bfa_lps_s *lps);
void bfa_lps_fdisclogo(struct bfa_lps_s *lps);
-u8 bfa_lps_get_tag(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps);
-bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps);
-bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps);
-u32 bfa_lps_get_pid(struct bfa_lps_s *lps);
+void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, u32 n2n_pid);
u32 bfa_lps_get_base_pid(struct bfa_s *bfa);
u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid);
-u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps);
-wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps);
-wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps);
-u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps);
-u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps);
-mac_t bfa_lps_get_lp_mac(struct bfa_lps_s *lps);
void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
void bfa_cb_lps_cvl_event(void *bfad, void *uarg);
-void bfa_trunk_enable_cfg(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_enable(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_disable(struct bfa_s *bfa);
-bfa_status_t bfa_trunk_get_attr(struct bfa_s *bfa,
- struct bfa_trunk_attr_s *attr);
-
#endif /* __BFA_SVC_H__ */
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 4d8784e06e14..44524cf55d33 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -15,7 +15,7 @@
* General Public License for more details.
*/
-/**
+/*
* bfad.c Linux driver PCI interface module.
*/
#include <linux/module.h>
@@ -32,7 +32,6 @@
#include "bfad_drv.h"
#include "bfad_im.h"
#include "bfa_fcs.h"
-#include "bfa_os_inc.h"
#include "bfa_defs.h"
#include "bfa.h"
@@ -50,7 +49,7 @@ int reqq_size, rspq_size, num_sgpgs;
int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
int bfa_io_max_sge = BFAD_IO_MAX_SGE;
-int log_level = 3; /* WARNING log level */
+int bfa_log_level = 3; /* WARNING log level */
int ioc_auto_recover = BFA_TRUE;
int bfa_linkup_delay = -1;
int fdmi_enable = BFA_TRUE;
@@ -61,12 +60,12 @@ int msix_disable_cb = 0, msix_disable_ct = 0;
u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size;
u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc;
-const char *msix_name_ct[] = {
+static const char *msix_name_ct[] = {
"cpe0", "cpe1", "cpe2", "cpe3",
"rme0", "rme1", "rme2", "rme3",
"ctrl" };
-const char *msix_name_cb[] = {
+static const char *msix_name_cb[] = {
"cpe0", "cpe1", "cpe2", "cpe3",
"rme0", "rme1", "rme2", "rme3",
"eemc", "elpu0", "elpu1", "epss", "mlpu" };
@@ -108,8 +107,8 @@ module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]");
module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
-module_param(log_level, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(log_level, "Driver log level, default=3, "
+module_param(bfa_log_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, "
"Range[Critical:1|Error:2|Warning:3|Info:4]");
module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, "
@@ -151,7 +150,7 @@ bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event);
static void
bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event);
-/**
+/*
* Beginning state for the driver instance, awaiting the pci_probe event
*/
static void
@@ -181,7 +180,7 @@ bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event)
}
}
-/**
+/*
* Driver Instance is created, awaiting event INIT to initialize the bfad
*/
static void
@@ -206,7 +205,7 @@ bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event)
}
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_init(&bfad->bfa);
+ bfa_iocfc_init(&bfad->bfa);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
/* Set up interrupt handler for each vectors */
@@ -364,7 +363,7 @@ bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event)
}
}
-/**
+/*
* BFA callbacks
*/
void
@@ -376,7 +375,7 @@ bfad_hcb_comp(void *arg, bfa_status_t status)
complete(&fcomp->comp);
}
-/**
+/*
* bfa_init callback
*/
void
@@ -401,7 +400,7 @@ bfa_cb_init(void *drv, bfa_status_t init_status)
complete(&bfad->comp);
}
-/**
+/*
* BFA_FCS callbacks
*/
struct bfad_port_s *
@@ -457,7 +456,7 @@ bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
}
}
-/**
+/*
* FCS RPORT alloc callback, after successful PLOGI by FCS
*/
bfa_status_t
@@ -478,7 +477,7 @@ ext:
return rc;
}
-/**
+/*
* FCS PBC VPORT Create
*/
void
@@ -533,7 +532,7 @@ bfad_hal_mem_release(struct bfad_s *bfad)
(dma_addr_t) meminfo_elem->dma);
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
break;
}
}
@@ -663,7 +662,7 @@ ext:
return rc;
}
-/**
+/*
* Create a vport under a vf.
*/
bfa_status_t
@@ -716,30 +715,6 @@ ext:
return rc;
}
-/**
- * Create a vf and its base vport implicitely.
- */
-bfa_status_t
-bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
- struct bfa_lport_cfg_s *port_cfg)
-{
- struct bfad_vf_s *vf;
- int rc = BFA_STATUS_OK;
-
- vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL);
- if (!vf) {
- rc = BFA_STATUS_FAILED;
- goto ext;
- }
-
- rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg,
- vf);
- if (rc != BFA_STATUS_OK)
- kfree(vf);
-ext:
- return rc;
-}
-
void
bfad_bfa_tmo(unsigned long data)
{
@@ -749,7 +724,7 @@ bfad_bfa_tmo(unsigned long data)
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_timer_tick(&bfad->bfa);
+ bfa_timer_beat(&bfad->bfa.timer_mod);
bfa_comp_deq(&bfad->bfa, &doneq);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -885,20 +860,6 @@ bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
pci_set_drvdata(pdev, NULL);
}
-void
-bfad_fcs_port_cfg(struct bfad_s *bfad)
-{
- struct bfa_lport_cfg_s port_cfg;
- struct bfa_port_attr_s attr;
- char symname[BFA_SYMNAME_MAXLEN];
-
- sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no);
- memcpy(port_cfg.sym_name.symname, symname, strlen(symname));
- bfa_fcport_get_attr(&bfad->bfa, &attr);
- port_cfg.nwwn = attr.nwwn;
- port_cfg.pwwn = attr.pwwn;
-}
-
bfa_status_t
bfad_drv_init(struct bfad_s *bfad)
{
@@ -920,8 +881,8 @@ bfad_drv_init(struct bfad_s *bfad)
goto out_hal_mem_alloc_failure;
}
- bfa_init_trc(&bfad->bfa, bfad->trcmod);
- bfa_init_plog(&bfad->bfa, &bfad->plog_buf);
+ bfad->bfa.trcmod = bfad->trcmod;
+ bfad->bfa.plog = &bfad->plog_buf;
bfa_plog_init(&bfad->plog_buf);
bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
0, "Driver Attach");
@@ -931,9 +892,9 @@ bfad_drv_init(struct bfad_s *bfad)
/* FCS INIT */
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod);
+ bfad->bfa_fcs.trcmod = bfad->trcmod;
bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
- bfa_fcs_set_fdmi_param(&bfad->bfa_fcs, fdmi_enable);
+ bfad->bfa_fcs.fdmi_enabled = fdmi_enable;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
@@ -951,7 +912,7 @@ bfad_drv_uninit(struct bfad_s *bfad)
spin_lock_irqsave(&bfad->bfad_lock, flags);
init_completion(&bfad->comp);
- bfa_stop(&bfad->bfa);
+ bfa_iocfc_stop(&bfad->bfa);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
wait_for_completion(&bfad->comp);
@@ -970,8 +931,8 @@ bfad_drv_start(struct bfad_s *bfad)
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_start(&bfad->bfa);
- bfa_fcs_start(&bfad->bfa_fcs);
+ bfa_iocfc_start(&bfad->bfa);
+ bfa_fcs_fabric_modstart(&bfad->bfa_fcs);
bfad->bfad_flags |= BFAD_HAL_START_DONE;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -1001,7 +962,7 @@ bfad_stop(struct bfad_s *bfad)
spin_lock_irqsave(&bfad->bfad_lock, flags);
init_completion(&bfad->comp);
- bfa_stop(&bfad->bfa);
+ bfa_iocfc_stop(&bfad->bfa);
bfad->bfad_flags &= ~BFAD_HAL_START_DONE;
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
wait_for_completion(&bfad->comp);
@@ -1089,9 +1050,6 @@ bfad_start_ops(struct bfad_s *bfad) {
bfa_fcs_init(&bfad->bfa_fcs);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
- /* PPORT FCS config */
- bfad_fcs_port_cfg(bfad);
-
retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM);
if (retval != BFA_STATUS_OK) {
if (bfa_sm_cmp_state(bfad, bfad_sm_initializing))
@@ -1143,17 +1101,17 @@ bfad_start_ops(struct bfad_s *bfad) {
/*
* If bfa_linkup_delay is set to -1 default; try to retrive the
- * value using the bfad_os_get_linkup_delay(); else use the
+ * value using the bfad_get_linkup_delay(); else use the
* passed in module param value as the bfa_linkup_delay.
*/
if (bfa_linkup_delay < 0) {
- bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
- bfad_os_rport_online_wait(bfad);
+ bfa_linkup_delay = bfad_get_linkup_delay(bfad);
+ bfad_rport_online_wait(bfad);
bfa_linkup_delay = -1;
} else
- bfad_os_rport_online_wait(bfad);
+ bfad_rport_online_wait(bfad);
- BFA_LOG(KERN_INFO, bfad, log_level, "bfa device claimed\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n");
return BFA_STATUS_OK;
}
@@ -1181,7 +1139,7 @@ bfad_worker(void *ptr)
return 0;
}
-/**
+/*
* BFA driver interrupt functions
*/
irqreturn_t
@@ -1208,7 +1166,6 @@ bfad_intx(int irq, void *dev_id)
spin_lock_irqsave(&bfad->bfad_lock, flags);
bfa_comp_free(&bfad->bfa, &doneq);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
- bfa_trc_fp(bfad, irq);
}
return IRQ_HANDLED;
@@ -1240,7 +1197,7 @@ bfad_msix(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/**
+/*
* Initialize the MSIX entry table.
*/
static void
@@ -1293,7 +1250,7 @@ bfad_install_msix_handler(struct bfad_s *bfad)
return 0;
}
-/**
+/*
* Setup MSIX based interrupt.
*/
int
@@ -1374,7 +1331,7 @@ bfad_remove_intr(struct bfad_s *bfad)
}
}
-/**
+/*
* PCI probe entry.
*/
int
@@ -1460,7 +1417,7 @@ out:
return error;
}
-/**
+/*
* PCI remove entry.
*/
void
@@ -1541,7 +1498,7 @@ static struct pci_driver bfad_pci_driver = {
.remove = __devexit_p(bfad_pci_remove),
};
-/**
+/*
* Driver module init.
*/
static int __init
@@ -1565,7 +1522,7 @@ bfad_init(void)
if (strcmp(FCPI_NAME, " fcpim") == 0)
supported_fc4s |= BFA_LPORT_ROLE_FCP_IM;
- bfa_ioc_auto_recover(ioc_auto_recover);
+ bfa_auto_recover = ioc_auto_recover;
bfa_fcs_rport_set_del_timeout(rport_del_timeout);
error = pci_register_driver(&bfad_pci_driver);
@@ -1581,7 +1538,7 @@ ext:
return error;
}
-/**
+/*
* Driver module exit.
*/
static void __exit
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index d8843720eac1..a94ea4235433 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -15,17 +15,17 @@
* General Public License for more details.
*/
-/**
+/*
* bfa_attr.c Linux driver configuration interface module.
*/
#include "bfad_drv.h"
#include "bfad_im.h"
-/**
+/*
* FC transport template entry, get SCSI target port ID.
*/
-void
+static void
bfad_im_get_starget_port_id(struct scsi_target *starget)
{
struct Scsi_Host *shost;
@@ -40,7 +40,7 @@ bfad_im_get_starget_port_id(struct scsi_target *starget)
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
@@ -48,10 +48,10 @@ bfad_im_get_starget_port_id(struct scsi_target *starget)
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
-/**
+/*
* FC transport template entry, get SCSI target nwwn.
*/
-void
+static void
bfad_im_get_starget_node_name(struct scsi_target *starget)
{
struct Scsi_Host *shost;
@@ -66,18 +66,18 @@ bfad_im_get_starget_node_name(struct scsi_target *starget)
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim);
- fc_starget_node_name(starget) = bfa_os_htonll(node_name);
+ fc_starget_node_name(starget) = cpu_to_be64(node_name);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
-/**
+/*
* FC transport template entry, get SCSI target pwwn.
*/
-void
+static void
bfad_im_get_starget_port_name(struct scsi_target *starget)
{
struct Scsi_Host *shost;
@@ -92,18 +92,18 @@ bfad_im_get_starget_port_name(struct scsi_target *starget)
bfad = im_port->bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- itnim = bfad_os_get_itnim(im_port, starget->id);
+ itnim = bfad_get_itnim(im_port, starget->id);
if (itnim)
port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
- fc_starget_port_name(starget) = bfa_os_htonll(port_name);
+ fc_starget_port_name(starget) = cpu_to_be64(port_name);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
-/**
+/*
* FC transport template entry, get SCSI host port ID.
*/
-void
+static void
bfad_im_get_host_port_id(struct Scsi_Host *shost)
{
struct bfad_im_port_s *im_port =
@@ -111,10 +111,10 @@ bfad_im_get_host_port_id(struct Scsi_Host *shost)
struct bfad_port_s *port = im_port->port;
fc_host_port_id(shost) =
- bfa_os_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port));
+ bfa_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port));
}
-/**
+/*
* FC transport template entry, get SCSI host port type.
*/
static void
@@ -146,7 +146,7 @@ bfad_im_get_host_port_type(struct Scsi_Host *shost)
}
}
-/**
+/*
* FC transport template entry, get SCSI host port state.
*/
static void
@@ -183,7 +183,7 @@ bfad_im_get_host_port_state(struct Scsi_Host *shost)
}
}
-/**
+/*
* FC transport template entry, get SCSI host active fc4s.
*/
static void
@@ -202,7 +202,7 @@ bfad_im_get_host_active_fc4s(struct Scsi_Host *shost)
fc_host_active_fc4s(shost)[7] = 1;
}
-/**
+/*
* FC transport template entry, get SCSI host link speed.
*/
static void
@@ -236,7 +236,7 @@ bfad_im_get_host_speed(struct Scsi_Host *shost)
}
}
-/**
+/*
* FC transport template entry, get SCSI host port type.
*/
static void
@@ -249,11 +249,11 @@ bfad_im_get_host_fabric_name(struct Scsi_Host *shost)
fabric_nwwn = bfa_fcs_lport_get_fabric_name(port->fcs_port);
- fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn);
+ fc_host_fabric_name(shost) = cpu_to_be64(fabric_nwwn);
}
-/**
+/*
* FC transport template entry, get BFAD statistics.
*/
static struct fc_host_statistics *
@@ -304,7 +304,7 @@ bfad_im_get_stats(struct Scsi_Host *shost)
return hstats;
}
-/**
+/*
* FC transport template entry, reset BFAD statistics.
*/
static void
@@ -331,7 +331,7 @@ bfad_im_reset_stats(struct Scsi_Host *shost)
return;
}
-/**
+/*
* FC transport template entry, get rport loss timeout.
*/
static void
@@ -347,7 +347,7 @@ bfad_im_get_rport_loss_tmo(struct fc_rport *rport)
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
-/**
+/*
* FC transport template entry, set rport loss timeout.
*/
static void
@@ -487,7 +487,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
wait_for_completion(vport->comp_del);
free_scsi_host:
- bfad_os_scsi_host_free(bfad, im_port);
+ bfad_scsi_host_free(bfad, im_port);
kfree(vport);
@@ -633,7 +633,7 @@ struct fc_function_template bfad_im_vport_fc_function_template = {
.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
};
-/**
+/*
* Scsi_Host_attrs SCSI host attributes
*/
static ssize_t
@@ -733,7 +733,7 @@ bfad_im_node_name_show(struct device *dev, struct device_attribute *attr,
u64 nwwn;
nwwn = bfa_fcs_lport_get_nwwn(port->fcs_port);
- return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn));
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n", cpu_to_be64(nwwn));
}
static ssize_t
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 69ed1c4a903e..c66e32eced7b 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -90,7 +90,7 @@ bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
spin_lock_irqsave(&bfad->bfad_lock, flags);
- rc = bfa_debug_fwtrc(&bfad->bfa,
+ rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
fw_debug->debug_buffer,
&fw_debug->buffer_len);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -134,7 +134,7 @@ bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
spin_lock_irqsave(&bfad->bfad_lock, flags);
- rc = bfa_debug_fwsave(&bfad->bfa,
+ rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
fw_debug->debug_buffer,
&fw_debug->buffer_len);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -208,7 +208,7 @@ bfad_debugfs_read(struct file *file, char __user *buf,
if (!debug || !debug->debug_buffer)
return 0;
- return memory_read_from_buffer(buf, nbytes, pos,
+ return simple_read_from_buffer(buf, nbytes, pos,
debug->debug_buffer, debug->buffer_len);
}
@@ -254,7 +254,7 @@ bfad_debugfs_read_regrd(struct file *file, char __user *buf,
if (!bfad->regdata)
return 0;
- rc = memory_read_from_buffer(buf, nbytes, pos,
+ rc = simple_read_from_buffer(buf, nbytes, pos,
bfad->regdata, bfad->reglen);
if ((*pos + nbytes) >= bfad->reglen) {
@@ -279,15 +279,31 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
u32 *regbuf;
void __iomem *rb, *reg_addr;
unsigned long flags;
+ void *kern_buf;
- rc = sscanf(buf, "%x:%x", &addr, &len);
+ kern_buf = kzalloc(nbytes, GFP_KERNEL);
+
+ if (!kern_buf) {
+ printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
+ kfree(kern_buf);
+ return -ENOMEM;
+ }
+
+ rc = sscanf(kern_buf, "%x:%x", &addr, &len);
if (rc < 2) {
printk(KERN_INFO
"bfad[%d]: %s failed to read user buf\n",
bfad->inst_no, __func__);
+ kfree(kern_buf);
return -EINVAL;
}
+ kfree(kern_buf);
kfree(bfad->regdata);
bfad->regdata = NULL;
bfad->reglen = 0;
@@ -318,7 +334,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
regbuf = (u32 *)bfad->regdata;
spin_lock_irqsave(&bfad->bfad_lock, flags);
for (i = 0; i < len; i++) {
- *regbuf = bfa_reg_read(reg_addr);
+ *regbuf = readl(reg_addr);
regbuf++;
reg_addr += sizeof(u32);
}
@@ -339,14 +355,30 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
int addr, val, rc;
void __iomem *reg_addr;
unsigned long flags;
+ void *kern_buf;
+
+ kern_buf = kzalloc(nbytes, GFP_KERNEL);
+
+ if (!kern_buf) {
+ printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
+ kfree(kern_buf);
+ return -ENOMEM;
+ }
- rc = sscanf(buf, "%x:%x", &addr, &val);
+ rc = sscanf(kern_buf, "%x:%x", &addr, &val);
if (rc < 2) {
printk(KERN_INFO
"bfad[%d]: %s failed to read user buf\n",
bfad->inst_no, __func__);
+ kfree(kern_buf);
return -EINVAL;
}
+ kfree(kern_buf);
addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */
@@ -359,9 +391,9 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
return -EINVAL;
}
- reg_addr = (u32 *) ((u8 *) bfa_ioc_bar0(ioc) + addr);
+ reg_addr = (bfa_ioc_bar0(ioc)) + addr;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- bfa_reg_write(reg_addr, val);
+ writel(val, reg_addr);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
return nbytes;
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 98420bbb4f3f..7f9ea90254cd 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -15,18 +15,34 @@
* General Public License for more details.
*/
-/**
+/*
* Contains base driver definitions.
*/
-/**
+/*
* bfa_drv.h Linux driver data structures.
*/
#ifndef __BFAD_DRV_H__
#define __BFAD_DRV_H__
-#include "bfa_os_inc.h"
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
#include "bfa_modules.h"
#include "bfa_fcs.h"
@@ -39,7 +55,7 @@
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "2.3.2.0"
+#define BFAD_DRIVER_VERSION "2.3.2.3"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
@@ -263,28 +279,21 @@ struct bfad_hal_comp {
*/
#define nextLowerInt(x) \
do { \
- int i; \
+ int __i; \
(*x)--; \
- for (i = 1; i < (sizeof(int)*8); i <<= 1) \
- (*x) = (*x) | (*x) >> i; \
+ for (__i = 1; __i < (sizeof(int)*8); __i <<= 1) \
+ (*x) = (*x) | (*x) >> __i; \
(*x)++; \
(*x) = (*x) >> 1; \
} while (0)
-#define list_remove_head(list, entry, type, member) \
-do { \
- entry = NULL; \
- if (!list_empty(list)) { \
- entry = list_entry((list)->next, type, member); \
- list_del_init(&entry->member); \
- } \
+#define BFA_LOG(level, bfad, mask, fmt, arg...) \
+do { \
+ if (((mask) == 4) || (level[1] <= '4')) \
+ dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \
} while (0)
-#define list_get_first(list, type, member) \
-((list_empty(list)) ? NULL : \
- list_entry((list)->next, type, member))
-
bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
struct bfa_lport_cfg_s *port_cfg,
struct device *dev);
@@ -309,7 +318,6 @@ void bfad_bfa_tmo(unsigned long data);
void bfad_init_timer(struct bfad_s *bfad);
int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad);
void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad);
-void bfad_fcs_port_cfg(struct bfad_s *bfad);
void bfad_drv_uninit(struct bfad_s *bfad);
int bfad_worker(void *ptr);
void bfad_debugfs_init(struct bfad_port_s *port);
@@ -317,8 +325,8 @@ void bfad_debugfs_exit(struct bfad_port_s *port);
void bfad_pci_remove(struct pci_dev *pdev);
int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
-void bfad_os_rport_online_wait(struct bfad_s *bfad);
-int bfad_os_get_linkup_delay(struct bfad_s *bfad);
+void bfad_rport_online_wait(struct bfad_s *bfad);
+int bfad_get_linkup_delay(struct bfad_s *bfad);
int bfad_install_msix_handler(struct bfad_s *bfad);
extern struct idr bfad_im_port_index;
@@ -338,7 +346,7 @@ extern int num_sgpgs;
extern int rport_del_timeout;
extern int bfa_lun_queue_depth;
extern int bfa_io_max_sge;
-extern int log_level;
+extern int bfa_log_level;
extern int ioc_auto_recover;
extern int bfa_linkup_delay;
extern int msix_disable_cb;
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index d950ee44016e..c2b36179e8e8 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -15,13 +15,12 @@
* General Public License for more details.
*/
-/**
+/*
* bfad_im.c Linux driver IM module.
*/
#include "bfad_drv.h"
#include "bfad_im.h"
-#include "bfa_cb_ioim.h"
#include "bfa_fcs.h"
BFA_TRC_FILE(LDRV, IM);
@@ -30,8 +29,7 @@ DEFINE_IDR(bfad_im_port_index);
struct scsi_transport_template *bfad_im_scsi_transport_template;
struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
static void bfad_im_itnim_work_handler(struct work_struct *work);
-static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
- void (*done)(struct scsi_cmnd *));
+static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd);
static int bfad_im_slave_alloc(struct scsi_device *sdev);
static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port,
struct bfad_itnim_s *itnim);
@@ -94,10 +92,10 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
if (!cmnd->result && itnim &&
(bfa_lun_queue_depth > cmnd->device->queue_depth)) {
/* Queue depth adjustment for good status completion */
- bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ bfad_ramp_up_qdepth(itnim, cmnd->device);
} else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) {
/* qfull handling */
- bfad_os_handle_qfull(itnim, cmnd->device);
+ bfad_handle_qfull(itnim, cmnd->device);
}
}
@@ -125,7 +123,7 @@ bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio)
if (itnim_data) {
itnim = itnim_data->itnim;
if (itnim)
- bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ bfad_ramp_up_qdepth(itnim, cmnd->device);
}
}
@@ -164,10 +162,10 @@ bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
wake_up(wq);
}
-/**
+/*
* Scsi_Host_template SCSI host template
*/
-/**
+/*
* Scsi_Host template entry, returns BFAD PCI info.
*/
static const char *
@@ -184,7 +182,7 @@ bfad_im_info(struct Scsi_Host *shost)
bfa_get_adapter_model(bfa, model);
memset(bfa_buf, 0, sizeof(bfa_buf));
- if (ioc->ctdev)
+ if (ioc->ctdev && !ioc->fcmode)
snprintf(bfa_buf, sizeof(bfa_buf),
"Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s",
model, bfad->pci_name, BFAD_DRIVER_VERSION);
@@ -196,7 +194,7 @@ bfad_im_info(struct Scsi_Host *shost)
return bfa_buf;
}
-/**
+/*
* Scsi_Host template entry, aborts the specified SCSI command.
*
* Returns: SUCCESS or FAILED.
@@ -226,7 +224,8 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd)
}
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ "scsi%d: abort cmnd %p iotag %x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
(void) bfa_ioim_abort(hal_io);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -242,7 +241,7 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd)
cmnd->scsi_done(cmnd);
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"scsi%d: complete abort 0x%p iotag 0x%x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
return SUCCESS;
@@ -258,10 +257,11 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
struct bfa_tskim_s *tskim;
struct bfa_itnim_s *bfa_itnim;
bfa_status_t rc = BFA_STATUS_OK;
+ struct scsi_lun scsilun;
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset, fail to allocate tskim\n");
rc = BFA_STATUS_FAILED;
goto out;
@@ -274,13 +274,14 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
cmnd->host_scribble = NULL;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
- bfa_tskim_start(tskim, bfa_itnim, (lun_t)0,
+ memset(&scsilun, 0, sizeof(scsilun));
+ bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
out:
return rc;
}
-/**
+/*
* Scsi_Host template entry, resets a LUN and abort its all commands.
*
* Returns: SUCCESS or FAILED.
@@ -301,6 +302,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
int rc = SUCCESS;
unsigned long flags;
enum bfi_tskim_status task_status;
+ struct scsi_lun scsilun;
spin_lock_irqsave(&bfad->bfad_lock, flags);
itnim = itnim_data->itnim;
@@ -312,14 +314,14 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset, fail to allocate tskim");
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
rc = FAILED;
goto out;
}
- /**
+ /*
* Set host_scribble to NULL to avoid aborting a task command
* if happens.
*/
@@ -327,8 +329,8 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
cmnd->SCp.ptr = (char *)&wq;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
- bfa_tskim_start(tskim, bfa_itnim,
- bfad_int_to_lun(cmnd->device->lun),
+ int_to_scsilun(cmnd->device->lun, &scsilun);
+ bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -337,7 +339,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset failure, status: %d\n", task_status);
rc = FAILED;
}
@@ -346,7 +348,7 @@ out:
return rc;
}
-/**
+/*
* Scsi_Host template entry, resets the bus and abort all commands.
*/
static int
@@ -364,7 +366,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
spin_lock_irqsave(&bfad->bfad_lock, flags);
for (i = 0; i < MAX_FCP_TARGET; i++) {
- itnim = bfad_os_get_itnim(im_port, i);
+ itnim = bfad_get_itnim(im_port, i);
if (itnim) {
cmnd->SCp.ptr = (char *)&wq;
rc = bfad_im_target_reset_send(bfad, cmnd, itnim);
@@ -381,7 +383,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset failure,"
" status: %d\n", task_status);
err_cnt++;
@@ -396,7 +398,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
return SUCCESS;
}
-/**
+/*
* Scsi_Host template entry slave_destroy.
*/
static void
@@ -406,11 +408,11 @@ bfad_im_slave_destroy(struct scsi_device *sdev)
return;
}
-/**
+/*
* BFA FCS itnim callbacks
*/
-/**
+/*
* BFA FCS itnim alloc callback, after successful PRLI
* Context: Interrupt
*/
@@ -433,7 +435,7 @@ bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
bfad->bfad_flags |= BFAD_RPORT_ONLINE;
}
-/**
+/*
* BFA FCS itnim free callback.
* Context: Interrupt. bfad_lock is held
*/
@@ -447,7 +449,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
struct bfad_im_s *im = itnim_drv->im;
/* online to free state transtion should not happen */
- bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE);
+ WARN_ON(itnim_drv->state == ITNIM_STATE_ONLINE);
itnim_drv->queue_work = 1;
/* offline request is not yet done, use the same request to free */
@@ -461,7 +463,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM FREE scsi%d: FCID: %s WWPN: %s\n",
port->im_port->shost->host_no,
fcid_str, wwpn_str);
@@ -471,7 +473,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
queue_work(im->drv_workq, &itnim_drv->itnim_work);
}
-/**
+/*
* BFA FCS itnim online callback.
* Context: Interrupt. bfad_lock is held
*/
@@ -492,7 +494,7 @@ bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv)
queue_work(im->drv_workq, &itnim_drv->itnim_work);
}
-/**
+/*
* BFA FCS itnim offline callback.
* Context: Interrupt. bfad_lock is held
*/
@@ -519,7 +521,7 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv)
queue_work(im->drv_workq, &itnim_drv->itnim_work);
}
-/**
+/*
* Allocate a Scsi_Host for a port.
*/
int
@@ -545,7 +547,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
mutex_unlock(&bfad_mutex);
- im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
+ im_port->shost = bfad_scsi_host_alloc(im_port, bfad);
if (!im_port->shost) {
error = 1;
goto out_free_idr;
@@ -571,7 +573,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
}
/* setup host fixed attribute if the lk supports */
- bfad_os_fc_host_init(im_port);
+ bfad_fc_host_init(im_port);
return 0;
@@ -590,7 +592,7 @@ void
bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
{
bfa_trc(bfad, bfad->inst_no);
- BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n",
im_port->shost->host_no);
fc_remove_host(im_port->shost);
@@ -662,7 +664,7 @@ bfad_im_port_clean(struct bfad_im_port_s *im_port)
}
/* the itnim_mapped_list must be empty at this time */
- bfa_assert(list_empty(&im_port->itnim_mapped_list));
+ WARN_ON(!list_empty(&im_port->itnim_mapped_list));
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
@@ -682,7 +684,7 @@ bfad_im_probe(struct bfad_s *bfad)
bfad->im = im;
im->bfad = bfad;
- if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) {
+ if (bfad_thread_workq(bfad) != BFA_STATUS_OK) {
kfree(im);
rc = BFA_STATUS_FAILED;
}
@@ -695,14 +697,14 @@ void
bfad_im_probe_undo(struct bfad_s *bfad)
{
if (bfad->im) {
- bfad_os_destroy_workq(bfad->im);
+ bfad_destroy_workq(bfad->im);
kfree(bfad->im);
bfad->im = NULL;
}
}
struct Scsi_Host *
-bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
+bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
{
struct scsi_host_template *sht;
@@ -717,7 +719,7 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
}
void
-bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+bfad_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
{
if (!(im_port->flags & BFAD_PORT_DELETE))
flush_workqueue(bfad->im->drv_workq);
@@ -727,7 +729,7 @@ bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
}
void
-bfad_os_destroy_workq(struct bfad_im_s *im)
+bfad_destroy_workq(struct bfad_im_s *im)
{
if (im && im->drv_workq) {
flush_workqueue(im->drv_workq);
@@ -737,7 +739,7 @@ bfad_os_destroy_workq(struct bfad_im_s *im)
}
bfa_status_t
-bfad_os_thread_workq(struct bfad_s *bfad)
+bfad_thread_workq(struct bfad_s *bfad)
{
struct bfad_im_s *im = bfad->im;
@@ -751,7 +753,7 @@ bfad_os_thread_workq(struct bfad_s *bfad)
return BFA_STATUS_OK;
}
-/**
+/*
* Scsi_Host template entry.
*
* Description:
@@ -841,7 +843,7 @@ bfad_im_module_exit(void)
}
void
-bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
{
struct scsi_device *tmp_sdev;
@@ -869,7 +871,7 @@ bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
}
void
-bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
{
struct scsi_device *tmp_sdev;
@@ -883,7 +885,7 @@ bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
}
struct bfad_itnim_s *
-bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
+bfad_get_itnim(struct bfad_im_port_s *im_port, int id)
{
struct bfad_itnim_s *itnim = NULL;
@@ -896,7 +898,7 @@ bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
return NULL;
}
-/**
+/*
* Scsi_Host template entry slave_alloc
*/
static int
@@ -915,12 +917,16 @@ bfad_im_slave_alloc(struct scsi_device *sdev)
static u32
bfad_im_supported_speeds(struct bfa_s *bfa)
{
- struct bfa_ioc_attr_s ioc_attr;
+ struct bfa_ioc_attr_s *ioc_attr;
u32 supported_speed = 0;
- bfa_get_attr(bfa, &ioc_attr);
- if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
- if (ioc_attr.adapter_attr.is_mezz) {
+ ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL);
+ if (!ioc_attr)
+ return 0;
+
+ bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
+ if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
+ if (ioc_attr->adapter_attr.is_mezz) {
supported_speed |= FC_PORTSPEED_8GBIT |
FC_PORTSPEED_4GBIT |
FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
@@ -929,29 +935,29 @@ bfad_im_supported_speeds(struct bfa_s *bfa)
FC_PORTSPEED_4GBIT |
FC_PORTSPEED_2GBIT;
}
- } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) {
+ } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) {
supported_speed |= FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
FC_PORTSPEED_1GBIT;
- } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) {
+ } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) {
supported_speed |= FC_PORTSPEED_10GBIT;
}
+ kfree(ioc_attr);
return supported_speed;
}
void
-bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
+bfad_fc_host_init(struct bfad_im_port_s *im_port)
{
struct Scsi_Host *host = im_port->shost;
struct bfad_s *bfad = im_port->bfad;
struct bfad_port_s *port = im_port->port;
- struct bfa_port_attr_s pattr;
- struct bfa_lport_attr_s port_attr;
char symname[BFA_SYMNAME_MAXLEN];
+ struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
fc_host_node_name(host) =
- bfa_os_htonll((bfa_fcs_lport_get_nwwn(port->fcs_port)));
+ cpu_to_be64((bfa_fcs_lport_get_nwwn(port->fcs_port)));
fc_host_port_name(host) =
- bfa_os_htonll((bfa_fcs_lport_get_pwwn(port->fcs_port)));
+ cpu_to_be64((bfa_fcs_lport_get_pwwn(port->fcs_port)));
fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
fc_host_supported_classes(host) = FC_COS_CLASS3;
@@ -964,15 +970,12 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
/* For fibre channel services type 0x20 */
fc_host_supported_fc4s(host)[7] = 1;
- bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
- strncpy(symname, port_attr.port_cfg.sym_name.symname,
+ strncpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname,
BFA_SYMNAME_MAXLEN);
sprintf(fc_host_symbolic_name(host), "%s", symname);
fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa);
-
- bfa_fcport_get_attr(&bfad->bfa, &pattr);
- fc_host_maxframe_size(host) = pattr.pport_cfg.maxfrsize;
+ fc_host_maxframe_size(host) = fcport->cfg.maxfrsize;
}
static void
@@ -983,11 +986,11 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
struct bfad_itnim_data_s *itnim_data;
rport_ids.node_name =
- bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
+ cpu_to_be64(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
rport_ids.port_name =
- bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+ cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
rport_ids.port_id =
- bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
+ bfa_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
itnim->fc_rport = fc_rport =
@@ -1015,7 +1018,7 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
return;
}
-/**
+/*
* Work queue handler using FC transport service
* Context: kernel
*/
@@ -1048,7 +1051,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
fcid2str(fcid_str, fcid);
list_add_tail(&itnim->list_entry,
&im_port->itnim_mapped_list);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM ONLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
@@ -1081,7 +1084,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
list_del(&itnim->list_entry);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM OFFLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
@@ -1108,18 +1111,18 @@ bfad_im_itnim_work_handler(struct work_struct *work)
kfree(itnim);
break;
default:
- bfa_assert(0);
+ WARN_ON(1);
break;
}
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
}
-/**
+/*
* Scsi_Host template entry, queue a SCSI command to the BFAD.
*/
static int
-bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
struct bfad_im_port_s *im_port =
(struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
@@ -1171,7 +1174,6 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
}
cmnd->host_scribble = (char *)hal_io;
- bfa_trc_fp(bfad, hal_io->iotag);
bfa_ioim_start(hal_io);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -1186,8 +1188,10 @@ out_fail_cmd:
return 0;
}
+static DEF_SCSI_QCMD(bfad_im_queuecommand)
+
void
-bfad_os_rport_online_wait(struct bfad_s *bfad)
+bfad_rport_online_wait(struct bfad_s *bfad)
{
int i;
int rport_delay = 10;
@@ -1215,7 +1219,7 @@ bfad_os_rport_online_wait(struct bfad_s *bfad)
}
int
-bfad_os_get_linkup_delay(struct bfad_s *bfad)
+bfad_get_linkup_delay(struct bfad_s *bfad)
{
u8 nwwns = 0;
wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX];
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index b038c0e08921..bfee63b16fa9 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -117,17 +117,17 @@ struct bfad_im_s {
char drv_workq_name[KOBJ_NAME_LEN];
};
-struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port,
+struct Scsi_Host *bfad_scsi_host_alloc(struct bfad_im_port_s *im_port,
struct bfad_s *);
-bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad);
-void bfad_os_destroy_workq(struct bfad_im_s *im);
-void bfad_os_fc_host_init(struct bfad_im_port_s *im_port);
-void bfad_os_scsi_host_free(struct bfad_s *bfad,
+bfa_status_t bfad_thread_workq(struct bfad_s *bfad);
+void bfad_destroy_workq(struct bfad_im_s *im);
+void bfad_fc_host_init(struct bfad_im_port_s *im_port);
+void bfad_scsi_host_free(struct bfad_s *bfad,
struct bfad_im_port_s *im_port);
-void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim,
+void bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim,
struct scsi_device *sdev);
-void bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
-struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id);
+void bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
+struct bfad_itnim_s *bfad_get_itnim(struct bfad_im_port_s *im_port, int id);
extern struct scsi_host_template bfad_im_scsi_host_template;
extern struct scsi_host_template bfad_im_vport_template;
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index 85f2224a5733..72b69a0c3b51 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -23,7 +23,7 @@
#pragma pack(1)
-/**
+/*
* BFI FW image type
*/
#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */
@@ -35,7 +35,7 @@ enum {
BFI_IMAGE_MAX,
};
-/**
+/*
* Msg header common to all msgs
*/
struct bfi_mhdr_s {
@@ -68,7 +68,7 @@ struct bfi_mhdr_s {
#define BFI_I2H_OPCODE_BASE 128
#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE)
-/**
+/*
****************************************************************************
*
* Scatter Gather Element and Page definition
@@ -79,7 +79,7 @@ struct bfi_mhdr_s {
#define BFI_SGE_INLINE 1
#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1)
-/**
+/*
* SG Flags
*/
enum {
@@ -90,21 +90,21 @@ enum {
BFI_SGE_PGDLEN = 2, /* cumulative data length for page */
};
-/**
+/*
* DMA addresses
*/
union bfi_addr_u {
struct {
- u32 addr_lo;
- u32 addr_hi;
+ __be32 addr_lo;
+ __be32 addr_hi;
} a32;
};
-/**
+/*
* Scatter Gather Element
*/
struct bfi_sge_s {
-#ifdef __BIGENDIAN
+#ifdef __BIG_ENDIAN
u32 flags:2,
rsvd:2,
sg_len:28;
@@ -116,7 +116,7 @@ struct bfi_sge_s {
union bfi_addr_u sga;
};
-/**
+/*
* Scatter Gather Page
*/
#define BFI_SGPG_DATA_SGES 7
@@ -139,7 +139,7 @@ struct bfi_msg_s {
u32 pl[BFI_LMSG_PL_WSZ];
};
-/**
+/*
* Mailbox message structure
*/
#define BFI_MBMSG_SZ 7
@@ -148,7 +148,7 @@ struct bfi_mbmsg_s {
u32 pl[BFI_MBMSG_SZ];
};
-/**
+/*
* Message Classes
*/
enum bfi_mclass {
@@ -186,7 +186,7 @@ enum bfi_mclass {
#define BFI_BOOT_LOADER_BIOS 1
#define BFI_BOOT_LOADER_UEFI 2
-/**
+/*
*----------------------------------------------------------------------
* IOC
*----------------------------------------------------------------------
@@ -208,7 +208,7 @@ enum bfi_ioc_i2h_msgs {
BFI_IOC_I2H_HBEAT = BFA_I2HM(5),
};
-/**
+/*
* BFI_IOC_H2I_GETATTR_REQ message
*/
struct bfi_ioc_getattr_req_s {
@@ -242,7 +242,7 @@ struct bfi_ioc_attr_s {
u32 card_type; /* card type */
};
-/**
+/*
* BFI_IOC_I2H_GETATTR_REPLY message
*/
struct bfi_ioc_getattr_reply_s {
@@ -251,19 +251,19 @@ struct bfi_ioc_getattr_reply_s {
u8 rsvd[3];
};
-/**
+/*
* Firmware memory page offsets
*/
#define BFI_IOC_SMEM_PG0_CB (0x40)
#define BFI_IOC_SMEM_PG0_CT (0x180)
-/**
+/*
* Firmware statistic offset
*/
#define BFI_IOC_FWSTATS_OFF (0x6B40)
#define BFI_IOC_FWSTATS_SZ (4096)
-/**
+/*
* Firmware trace offset
*/
#define BFI_IOC_TRC_OFF (0x4b00)
@@ -280,7 +280,7 @@ struct bfi_ioc_image_hdr_s {
u32 md5sum[BFI_IOC_MD5SUM_SZ];
};
-/**
+/*
* BFI_IOC_I2H_READY_EVENT message
*/
struct bfi_ioc_rdy_event_s {
@@ -294,7 +294,7 @@ struct bfi_ioc_hbeat_s {
u32 hb_count; /* current heart beat count */
};
-/**
+/*
* IOC hardware/firmware state
*/
enum bfi_ioc_state {
@@ -340,7 +340,7 @@ enum {
((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
BFI_ADAPTER_UNSUPP))
-/**
+/*
* BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
*/
struct bfi_ioc_ctrl_req_s {
@@ -352,7 +352,7 @@ struct bfi_ioc_ctrl_req_s {
#define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s;
#define bfi_ioc_disable_req_t struct bfi_ioc_ctrl_req_s;
-/**
+/*
* BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
*/
struct bfi_ioc_ctrl_reply_s {
@@ -364,7 +364,7 @@ struct bfi_ioc_ctrl_reply_s {
#define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s;
#define BFI_IOC_MSGSZ 8
-/**
+/*
* H2I Messages
*/
union bfi_ioc_h2i_msg_u {
@@ -375,7 +375,7 @@ union bfi_ioc_h2i_msg_u {
u32 mboxmsg[BFI_IOC_MSGSZ];
};
-/**
+/*
* I2H Messages
*/
union bfi_ioc_i2h_msg_u {
@@ -385,7 +385,7 @@ union bfi_ioc_i2h_msg_u {
};
-/**
+/*
*----------------------------------------------------------------------
* PBC
*----------------------------------------------------------------------
@@ -394,15 +394,15 @@ union bfi_ioc_i2h_msg_u {
#define BFI_PBC_MAX_BLUNS 8
#define BFI_PBC_MAX_VPORTS 16
-/**
+/*
* PBC boot lun configuration
*/
struct bfi_pbc_blun_s {
wwn_t tgt_pwwn;
- lun_t tgt_lun;
+ struct scsi_lun tgt_lun;
};
-/**
+/*
* PBC virtual port configuration
*/
struct bfi_pbc_vport_s {
@@ -410,7 +410,7 @@ struct bfi_pbc_vport_s {
wwn_t vp_nwwn;
};
-/**
+/*
* BFI pre-boot configuration information
*/
struct bfi_pbc_s {
@@ -427,7 +427,7 @@ struct bfi_pbc_s {
struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS];
};
-/**
+/*
*----------------------------------------------------------------------
* MSGQ
*----------------------------------------------------------------------
@@ -531,7 +531,7 @@ enum bfi_port_i2h {
BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
};
-/**
+/*
* Generic REQ type
*/
struct bfi_port_generic_req_s {
@@ -540,7 +540,7 @@ struct bfi_port_generic_req_s {
u32 rsvd;
};
-/**
+/*
* Generic RSP type
*/
struct bfi_port_generic_rsp_s {
@@ -550,7 +550,7 @@ struct bfi_port_generic_rsp_s {
u32 msgtag; /* msgtag for reply */
};
-/**
+/*
* BFI_PORT_H2I_GET_STATS_REQ
*/
struct bfi_port_get_stats_req_s {
diff --git a/drivers/scsi/bfa/bfi_cbreg.h b/drivers/scsi/bfa/bfi_cbreg.h
index 6f03ed382c69..39ad42b66b5b 100644
--- a/drivers/scsi/bfa/bfi_cbreg.h
+++ b/drivers/scsi/bfa/bfi_cbreg.h
@@ -208,6 +208,7 @@
#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
#define CPE_Q_DEPTH(__n) \
(CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH))
diff --git a/drivers/scsi/bfa/bfi_ctreg.h b/drivers/scsi/bfa/bfi_ctreg.h
index 62b86a4b0e4b..fc4ce4a5a183 100644
--- a/drivers/scsi/bfa/bfi_ctreg.h
+++ b/drivers/scsi/bfa/bfi_ctreg.h
@@ -522,6 +522,7 @@ enum {
#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
#define CPE_DEPTH_Q(__n) \
(CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
@@ -539,22 +540,30 @@ enum {
(RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
#define RME_CI_PTR_Q(__n) \
(RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
-#define HQM_QSET_RXQ_DRBL_P0(__n) (HQM_QSET0_RXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
-#define HQM_QSET_TXQ_DRBL_P0(__n) (HQM_QSET0_TXQ_DRBL_P0 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
-#define HQM_QSET_IB_DRBL_1_P0(__n) (HQM_QSET0_IB_DRBL_1_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
-#define HQM_QSET_IB_DRBL_2_P0(__n) (HQM_QSET0_IB_DRBL_2_P0 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
-#define HQM_QSET_RXQ_DRBL_P1(__n) (HQM_QSET0_RXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
-#define HQM_QSET_TXQ_DRBL_P1(__n) (HQM_QSET0_TXQ_DRBL_P1 + (__n) \
- * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
-#define HQM_QSET_IB_DRBL_1_P1(__n) (HQM_QSET0_IB_DRBL_1_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
-#define HQM_QSET_IB_DRBL_2_P1(__n) (HQM_QSET0_IB_DRBL_2_P1 + (__n) \
- * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+ (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+ (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+ (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+ (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+ (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+ (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \
+ (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+ (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+ (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \
+ (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index 69ac85f9e938..19e888a57555 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -41,16 +41,16 @@ struct bfi_iocfc_cfg_s {
u16 rsvd_1;
u32 endian_sig; /* endian signature of host */
- /**
+ /*
* Request and response circular queue base addresses, size and
* shadow index pointers.
*/
union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS];
union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS];
- u16 req_cq_elems[BFI_IOC_MAX_CQS];
+ __be16 req_cq_elems[BFI_IOC_MAX_CQS];
union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS];
union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS];
- u16 rsp_cq_elems[BFI_IOC_MAX_CQS];
+ __be16 rsp_cq_elems[BFI_IOC_MAX_CQS];
union bfi_addr_u stats_addr; /* DMA-able address for stats */
union bfi_addr_u cfgrsp_addr; /* config response dma address */
@@ -58,7 +58,7 @@ struct bfi_iocfc_cfg_s {
struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */
};
-/**
+/*
* Boot target wwn information for this port. This contains either the stored
* or discovered boot target port wwns for the port.
*/
@@ -75,7 +75,7 @@ struct bfi_iocfc_cfgrsp_s {
struct bfi_pbc_s pbc_cfg;
};
-/**
+/*
* BFI_IOCFC_H2I_CFG_REQ message
*/
struct bfi_iocfc_cfg_req_s {
@@ -84,7 +84,7 @@ struct bfi_iocfc_cfg_req_s {
};
-/**
+/*
* BFI_IOCFC_I2H_CFG_REPLY message
*/
struct bfi_iocfc_cfg_reply_s {
@@ -95,19 +95,19 @@ struct bfi_iocfc_cfg_reply_s {
};
-/**
+/*
* BFI_IOCFC_H2I_SET_INTR_REQ message
*/
struct bfi_iocfc_set_intr_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u8 coalesce; /* enable intr coalescing */
u8 rsvd[3];
- u16 delay; /* delay timer 0..1125us */
- u16 latency; /* latency timer 0..225us */
+ __be16 delay; /* delay timer 0..1125us */
+ __be16 latency; /* latency timer 0..225us */
};
-/**
+/*
* BFI_IOCFC_H2I_UPDATEQ_REQ message
*/
struct bfi_iocfc_updateq_req_s {
@@ -119,7 +119,7 @@ struct bfi_iocfc_updateq_req_s {
};
-/**
+/*
* BFI_IOCFC_I2H_UPDATEQ_RSP message
*/
struct bfi_iocfc_updateq_rsp_s {
@@ -129,7 +129,7 @@ struct bfi_iocfc_updateq_rsp_s {
};
-/**
+/*
* H2I Messages
*/
union bfi_iocfc_h2i_msg_u {
@@ -140,7 +140,7 @@ union bfi_iocfc_h2i_msg_u {
};
-/**
+/*
* I2H Messages
*/
union bfi_iocfc_i2h_msg_u {
@@ -173,7 +173,7 @@ enum bfi_fcport_i2h {
};
-/**
+/*
* Generic REQ type
*/
struct bfi_fcport_req_s {
@@ -181,17 +181,18 @@ struct bfi_fcport_req_s {
u32 msgtag; /* msgtag for reply */
};
-/**
+/*
* Generic RSP type
*/
struct bfi_fcport_rsp_s {
struct bfi_mhdr_s mh; /* common msg header */
u8 status; /* port enable status */
u8 rsvd[3];
- u32 msgtag; /* msgtag for reply */
+ struct bfa_port_cfg_s port_cfg;/* port configuration */
+ u32 msgtag; /* msgtag for reply */
};
-/**
+/*
* BFI_FCPORT_H2I_ENABLE_REQ
*/
struct bfi_fcport_enable_req_s {
@@ -202,19 +203,20 @@ struct bfi_fcport_enable_req_s {
struct bfa_port_cfg_s port_cfg; /* port configuration */
union bfi_addr_u stats_dma_addr; /* DMA address for stats */
u32 msgtag; /* msgtag for reply */
- u32 rsvd2;
+ u8 use_flash_cfg; /* get prot cfg from flash */
+ u8 rsvd2[3];
};
-/**
+/*
* BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ
*/
struct bfi_fcport_set_svc_params_req_s {
struct bfi_mhdr_s mh; /* msg header */
- u16 tx_bbcredit; /* Tx credits */
+ __be16 tx_bbcredit; /* Tx credits */
u16 rsvd;
};
-/**
+/*
* BFI_FCPORT_I2H_EVENT
*/
struct bfi_fcport_event_s {
@@ -222,7 +224,7 @@ struct bfi_fcport_event_s {
struct bfa_port_link_s link_state;
};
-/**
+/*
* BFI_FCPORT_I2H_TRUNK_SCN
*/
struct bfi_fcport_trunk_link_s {
@@ -231,7 +233,7 @@ struct bfi_fcport_trunk_link_s {
u8 state; /* bfa_trunk_link_state_t */
u8 speed; /* bfa_port_speed_t */
u8 rsvd;
- u32 deskew;
+ __be32 deskew;
};
#define BFI_FCPORT_MAX_LINKS 2
@@ -243,7 +245,7 @@ struct bfi_fcport_trunk_scn_s {
struct bfi_fcport_trunk_link_s tlink[BFI_FCPORT_MAX_LINKS];
};
-/**
+/*
* fcport H2I message
*/
union bfi_fcport_h2i_msg_u {
@@ -255,7 +257,7 @@ union bfi_fcport_h2i_msg_u {
struct bfi_fcport_req_s *pstatsclear;
};
-/**
+/*
* fcport I2H message
*/
union bfi_fcport_i2h_msg_u {
@@ -279,36 +281,36 @@ enum bfi_fcxp_i2h {
#define BFA_FCXP_MAX_SGES 2
-/**
+/*
* FCXP send request structure
*/
struct bfi_fcxp_send_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 fcxp_tag; /* driver request tag */
- u16 max_frmsz; /* max send frame size */
- u16 vf_id; /* vsan tag if applicable */
+ __be16 fcxp_tag; /* driver request tag */
+ __be16 max_frmsz; /* max send frame size */
+ __be16 vf_id; /* vsan tag if applicable */
u16 rport_fw_hndl; /* FW Handle for the remote port */
u8 class; /* FC class used for req/rsp */
u8 rsp_timeout; /* timeout in secs, 0-no response */
u8 cts; /* continue sequence */
u8 lp_tag; /* lport tag */
struct fchs_s fchs; /* request FC header structure */
- u32 req_len; /* request payload length */
- u32 rsp_maxlen; /* max response length expected */
+ __be32 req_len; /* request payload length */
+ __be32 rsp_maxlen; /* max response length expected */
struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */
struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */
};
-/**
+/*
* FCXP send response structure
*/
struct bfi_fcxp_send_rsp_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 fcxp_tag; /* send request tag */
+ __be16 fcxp_tag; /* send request tag */
u8 req_status; /* request status */
u8 rsvd;
- u32 rsp_len; /* actual response length */
- u32 residue_len; /* residual response length */
+ __be32 rsp_len; /* actual response length */
+ __be32 residue_len; /* residual response length */
struct fchs_s fchs; /* response FC header structure */
};
@@ -325,7 +327,7 @@ enum bfi_uf_i2h {
struct bfi_uf_buf_post_s {
struct bfi_mhdr_s mh; /* Common msg header */
u16 buf_tag; /* buffer tag */
- u16 buf_len; /* total buffer length */
+ __be16 buf_len; /* total buffer length */
struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */
};
@@ -340,6 +342,7 @@ struct bfi_uf_frm_rcvd_s {
enum bfi_lps_h2i_msgs {
BFI_LPS_H2I_LOGIN_REQ = 1,
BFI_LPS_H2I_LOGOUT_REQ = 2,
+ BFI_LPS_H2I_N2N_PID_REQ = 3,
};
enum bfi_lps_i2h_msgs {
@@ -352,7 +355,7 @@ struct bfi_lps_login_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u8 lp_tag;
u8 alpa;
- u16 pdu_size;
+ __be16 pdu_size;
wwn_t pwwn;
wwn_t nwwn;
u8 fdisc;
@@ -368,7 +371,7 @@ struct bfi_lps_login_rsp_s {
u8 lsrjt_expl;
wwn_t port_name;
wwn_t node_name;
- u16 bb_credit;
+ __be16 bb_credit;
u8 f_port;
u8 npiv_en;
u32 lp_pid:24;
@@ -399,10 +402,17 @@ struct bfi_lps_cvl_event_s {
u8 rsvd[3];
};
+struct bfi_lps_n2n_pid_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u32 lp_pid:24;
+};
+
union bfi_lps_h2i_msg_u {
struct bfi_mhdr_s *msg;
struct bfi_lps_login_req_s *login_req;
struct bfi_lps_logout_req_s *logout_req;
+ struct bfi_lps_n2n_pid_req_s *n2n_pid_req;
};
union bfi_lps_i2h_msg_u {
@@ -427,7 +437,7 @@ enum bfi_rport_i2h_msgs {
struct bfi_rport_create_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u16 bfa_handle; /* host rport handle */
- u16 max_frmsz; /* max rcv pdu size */
+ __be16 max_frmsz; /* max rcv pdu size */
u32 pid:24, /* remote port ID */
lp_tag:8; /* local port tag */
u32 local_pid:24, /* local port ID */
@@ -565,14 +575,14 @@ enum bfi_ioim_i2h {
BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2), /* ABORT rsp */
};
-/**
+/*
* IO command DIF info
*/
struct bfi_ioim_dif_s {
u32 dif_info[4];
};
-/**
+/*
* FCP IO messages overview
*
* @note
@@ -583,11 +593,11 @@ struct bfi_ioim_dif_s {
*/
struct bfi_ioim_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 io_tag; /* I/O tag */
+ __be16 io_tag; /* I/O tag */
u16 rport_hdl; /* itnim/rport firmware handle */
struct fcp_cmnd_s cmnd; /* IO request info */
- /**
+ /*
* SG elements array within the IO request must be double word
* aligned. This aligment is required to optimize SGM setup for the IO.
*/
@@ -598,7 +608,7 @@ struct bfi_ioim_req_s {
struct bfi_ioim_dif_s dif;
};
-/**
+/*
* This table shows various IO status codes from firmware and their
* meaning. Host driver can use these status codes to further process
* IO completions.
@@ -684,12 +694,12 @@ enum bfi_ioim_status {
};
#define BFI_IOIM_SNSLEN (256)
-/**
+/*
* I/O response message
*/
struct bfi_ioim_rsp_s {
struct bfi_mhdr_s mh; /* common msg header */
- u16 io_tag; /* completed IO tag */
+ __be16 io_tag; /* completed IO tag */
u16 bfa_rport_hndl; /* releated rport handle */
u8 io_status; /* IO completion status */
u8 reuse_io_tag; /* IO tag can be reused */
@@ -698,13 +708,13 @@ struct bfi_ioim_rsp_s {
u8 sns_len; /* scsi sense length */
u8 resid_flags; /* IO residue flags */
u8 rsvd_a;
- u32 residue; /* IO residual length in bytes */
+ __be32 residue; /* IO residual length in bytes */
u32 rsvd_b[3];
};
struct bfi_ioim_abort_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 io_tag; /* I/O tag */
+ __be16 io_tag; /* I/O tag */
u16 abort_tag; /* unique request tag */
};
@@ -723,9 +733,9 @@ enum bfi_tskim_i2h {
struct bfi_tskim_req_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task management tag */
+ __be16 tsk_tag; /* task management tag */
u16 itn_fhdl; /* itn firmware handle */
- lun_t lun; /* LU number */
+ struct scsi_lun lun; /* LU number */
u8 tm_flags; /* see enum fcp_tm_cmnd */
u8 t_secs; /* Timeout value in seconds */
u8 rsvd[2];
@@ -733,7 +743,7 @@ struct bfi_tskim_req_s {
struct bfi_tskim_abortreq_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task management tag */
+ __be16 tsk_tag; /* task management tag */
u16 rsvd;
};
@@ -746,7 +756,7 @@ enum bfi_tskim_status {
BFI_TSKIM_STS_NOT_SUPP = 4,
BFI_TSKIM_STS_FAILED = 5,
- /**
+ /*
* Defined by BFA
*/
BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */
@@ -755,7 +765,7 @@ enum bfi_tskim_status {
struct bfi_tskim_rsp_s {
struct bfi_mhdr_s mh; /* Common msg header */
- u16 tsk_tag; /* task mgmt cmnd tag */
+ __be16 tsk_tag; /* task mgmt cmnd tag */
u8 tsk_status; /* @ref bfi_tskim_status */
u8 rsvd;
};
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 1b6f86b2482d..30e6bdbd65af 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,12 +1,13 @@
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef __57XX_ISCSI_CONSTANTS_H_
#define __57XX_ISCSI_CONSTANTS_H_
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index 36af1afef9b6..dad6c8a34317 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,12 +1,13 @@
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef __57XX_ISCSI_HSI_LINUX_LE__
#define __57XX_ISCSI_HSI_LINUX_LE__
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index a44b1b33fa18..e1ca5fe7e6bb 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef _BNX2I_H_
@@ -649,6 +650,7 @@ enum {
EP_STATE_OFLD_FAILED = 0x8000000,
EP_STATE_CONNECT_FAILED = 0x10000000,
EP_STATE_DISCONN_TIMEDOUT = 0x20000000,
+ EP_STATE_OFLD_FAILED_CID_BUSY = 0x80000000,
};
/**
@@ -717,14 +719,11 @@ extern struct device_attribute *bnx2i_dev_attributes[];
* Function Prototypes
*/
extern void bnx2i_identify_device(struct bnx2i_hba *hba);
-extern void bnx2i_register_device(struct bnx2i_hba *hba);
extern void bnx2i_ulp_init(struct cnic_dev *dev);
extern void bnx2i_ulp_exit(struct cnic_dev *dev);
extern void bnx2i_start(void *handle);
extern void bnx2i_stop(void *handle);
-extern void bnx2i_reg_dev_all(void);
-extern void bnx2i_unreg_dev_all(void);
extern struct bnx2i_hba *get_adapter_list_head(void);
struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
@@ -761,11 +760,11 @@ extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba,
struct bnx2i_cmd *cmd);
-extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep);
-extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
-extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+extern int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
+extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
+extern int bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep);
extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 8d9dbb33972f..96505e3ab986 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/gfp.h>
@@ -385,6 +386,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
struct bnx2i_cmd *bnx2i_cmd;
struct bnx2i_tmf_request *tmfabort_wqe;
u32 dword;
+ u32 scsi_lun[2];
bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
@@ -426,7 +428,10 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
default:
tmfabort_wqe->ref_itt = RESERVED_ITT;
}
- memcpy(tmfabort_wqe->lun, tmfabort_hdr->lun, sizeof(struct scsi_lun));
+ memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun));
+ tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
+ tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
+
tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
@@ -697,10 +702,11 @@ void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
* iscsi connection context clean-up process
*/
-void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_destroy conn_cleanup;
+ int rc = -EINVAL;
memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
@@ -717,7 +723,9 @@ void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+
+ return rc;
}
@@ -728,8 +736,8 @@ void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
*
* 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_offload1 ofld_req1;
@@ -737,6 +745,7 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
@@ -774,7 +783,9 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
ofld_req2.num_additional_wqes = 0;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
@@ -785,8 +796,8 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
*
* 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[5];
struct iscsi_kwqe_conn_offload1 ofld_req1;
@@ -795,6 +806,7 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
@@ -840,7 +852,9 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
num_kwqes += 1;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
/**
@@ -851,12 +865,16 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
*
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
+ int rc;
+
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
- bnx2i_5771x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_5771x_send_conn_ofld_req(hba, ep);
else
- bnx2i_570x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_570x_send_conn_ofld_req(hba, ep);
+
+ return rc;
}
@@ -1513,7 +1531,7 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
task = iscsi_itt_to_task(conn,
nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
if (task)
- iscsi_put_task(task);
+ __iscsi_put_task(task);
spin_unlock(&session->lock);
}
@@ -1549,11 +1567,9 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
struct iscsi_task *task;
struct bnx2i_nop_in_msg *nop_in;
struct iscsi_nopin *hdr;
- u32 itt;
int tgt_async_nop = 0;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX;
spin_lock(&session->lock);
hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
@@ -1563,7 +1579,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
hdr->ttt = cpu_to_be32(nop_in->ttt);
- if (itt == (u16) RESERVED_ITT) {
+ if (nop_in->itt == (u16) RESERVED_ITT) {
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
hdr->itt = RESERVED_ITT;
tgt_async_nop = 1;
@@ -1571,7 +1587,8 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
}
/* this is a response to one of our nop-outs */
- task = iscsi_itt_to_task(conn, itt);
+ task = iscsi_itt_to_task(conn,
+ (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX));
if (task) {
hdr->flags = ISCSI_FLAG_CMD_FINAL;
hdr->itt = task->hdr->itt;
@@ -1721,9 +1738,18 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
break;
- if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx)))
+ if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) {
+ if (nopin->op_code == ISCSI_OP_NOOP_IN &&
+ nopin->itt == (u16) RESERVED_ITT) {
+ printk(KERN_ALERT "bnx2i: Unsolicited "
+ "NOP-In detected for suspended "
+ "connection dev=%s!\n",
+ bnx2i_conn->hba->netdev->name);
+ bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+ goto cqe_out;
+ }
break;
-
+ }
tgt_async_msg = 0;
switch (nopin->op_code) {
@@ -1770,10 +1796,9 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
nopin->op_code);
}
-
if (!tgt_async_msg)
bnx2i_conn->ep->num_active_cmds--;
-
+cqe_out:
/* clear out in production version only, till beta keep opcode
* field intact, will be helpful in debugging (context dump)
* nopin->op_code = 0;
@@ -2154,11 +2179,24 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
}
if (ofld_kcqe->completion_status) {
+ ep->state = EP_STATE_OFLD_FAILED;
if (ofld_kcqe->completion_status ==
ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
- printk(KERN_ALERT "bnx2i: unable to allocate"
- " iSCSI context resources\n");
- ep->state = EP_STATE_OFLD_FAILED;
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable "
+ "to allocate iSCSI context resources\n",
+ hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE)
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "opcode\n", hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
+ /* error status code valid only for 5771x chipset */
+ ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
+ else
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "error code %d\n", hba->netdev->name,
+ ofld_kcqe->completion_status);
} else {
ep->state = EP_STATE_OFLD_COMPL;
cid_addr = ofld_kcqe->iscsi_conn_context_id;
@@ -2339,26 +2377,32 @@ static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
{
struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+ u32 old_state = ep->state;
ep->state = EP_STATE_TCP_RST_RCVD;
- if (ep->conn)
- bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+ if (old_state == EP_STATE_DISCONN_START)
+ wake_up_interruptible(&ep->ofld_wait);
+ else
+ if (ep->conn)
+ bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
}
-static void bnx2i_send_nl_mesg(struct cnic_dev *dev, u32 msg_type,
+static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
char *buf, u16 buflen)
{
- struct bnx2i_hba *hba;
+ struct bnx2i_hba *hba = context;
+ int rc;
- hba = bnx2i_find_hba_for_cnic(dev);
if (!hba)
- return;
+ return -ENODEV;
- if (iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
- msg_type, buf, buflen))
+ rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
+ msg_type, buf, buflen);
+ if (rc)
printk(KERN_ALERT "bnx2i: private nl message send error\n");
+ return rc;
}
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 50c2aa3b8eb1..72a7b2d4a439 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include "bnx2i.h"
@@ -17,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.1.3"
-#define DRV_MODULE_RELDATE "Aug 10, 2010"
+#define DRV_MODULE_VERSION "2.6.2.2"
+#define DRV_MODULE_RELDATE "Nov 23, 2010"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -65,8 +66,6 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size");
u64 iscsi_error_mask = 0x00;
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ;
-
/**
* bnx2i_identify_device - identifies NetXtreme II device type
@@ -211,13 +210,24 @@ void bnx2i_stop(void *handle)
{
struct bnx2i_hba *hba = handle;
int conns_active;
+ int wait_delay = 1 * HZ;
/* check if cleanup happened in GOING_DOWN context */
- if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
- &hba->adapter_state))
+ if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN,
+ &hba->adapter_state)) {
iscsi_host_for_each_session(hba->shost,
bnx2i_drop_session);
-
+ wait_delay = hba->hba_shutdown_tmo;
+ }
+ /* Wait for inflight offload connection tasks to complete before
+ * proceeding. Forcefully terminate all connection recovery in
+ * progress at the earliest, either in bind(), send_pdu(LOGIN),
+ * or conn_start()
+ */
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (list_empty(&hba->ep_ofld_list) &&
+ list_empty(&hba->ep_destroy_list)),
+ 10 * HZ);
/* Wait for all endpoints to be torn down, Chip will be reset once
* control returns to network driver. So it is required to cleanup and
* release all connection resources before returning from this routine.
@@ -226,7 +236,7 @@ void bnx2i_stop(void *handle)
conns_active = hba->ofld_conns_active;
wait_event_interruptible_timeout(hba->eh_wait,
(hba->ofld_conns_active != conns_active),
- hba->hba_shutdown_tmo);
+ wait_delay);
if (hba->ofld_conns_active == conns_active)
break;
}
@@ -235,88 +245,10 @@ void bnx2i_stop(void *handle)
/* This flag should be cleared last so that ep_disconnect() gracefully
* cleans up connection context
*/
+ clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
}
-/**
- * bnx2i_register_device - register bnx2i adapter instance with the cnic driver
- * @hba: Adapter instance to register
- *
- * registers bnx2i adapter instance with the cnic driver while holding the
- * adapter structure lock
- */
-void bnx2i_register_device(struct bnx2i_hba *hba)
-{
- int rc;
-
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
- test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- return;
- }
-
- rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
-
- if (!rc)
- set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-
-/**
- * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver
- *
- * registers all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_reg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_register_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
-
-/**
- * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver
- * @hba: Adapter instance to unregister
- *
- * registers bnx2i adapter instance with the cnic driver while holding
- * the adapter structure lock
- */
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
-{
- if (hba->ofld_conns_active ||
- !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) ||
- test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state))
- return;
-
- hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
-
- /* ep_disconnect could come before NETDEV_DOWN, driver won't
- * see NETDEV_DOWN as it already unregistered itself.
- */
- hba->adapter_state = 0;
- clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-/**
- * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver
- *
- * unregisters all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_unreg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_unreg_one_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
/**
* bnx2i_init_one - initialize an adapter instance and allocate memory resources
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fb50efbce087..f0dce26593eb 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2010 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -10,6 +10,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/slab.h>
@@ -411,7 +412,9 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep)
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->hba->ofld_conns_active--;
- bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+ if (bnx2i_ep->ep_iscsi_cid != (u16) -1)
+ bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+
if (bnx2i_ep->conn) {
bnx2i_ep->conn->ep = NULL;
bnx2i_ep->conn = NULL;
@@ -1383,6 +1386,12 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
return -EINVAL;
+ /*
+ * Forcefully terminate all in progress connection recovery at the
+ * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
+ */
+ if (bnx2i_adapter_ready(hba))
+ return -EIO;
bnx2i_ep = ep->dd_data;
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
@@ -1404,7 +1413,6 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
hba->netdev->name);
return -EEXIST;
}
-
bnx2i_ep->conn = bnx2i_conn;
bnx2i_conn->ep = bnx2i_ep;
bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
@@ -1461,21 +1469,28 @@ static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
struct bnx2i_conn *bnx2i_conn = conn->dd_data;
int len = 0;
+ if (!(bnx2i_conn && bnx2i_conn->ep && bnx2i_conn->ep->hba))
+ goto out;
+
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- if (bnx2i_conn->ep)
+ mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
+ if (bnx2i_conn->ep->cm_sk)
len = sprintf(buf, "%hu\n",
bnx2i_conn->ep->cm_sk->dst_port);
+ mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- if (bnx2i_conn->ep)
+ mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
+ if (bnx2i_conn->ep->cm_sk)
len = sprintf(buf, "%pI4\n",
&bnx2i_conn->ep->cm_sk->dst_ip);
+ mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
-
+out:
return len;
}
@@ -1599,8 +1614,6 @@ static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
struct bnx2i_hba *hba;
struct cnic_dev *cnic = NULL;
- bnx2i_reg_dev_all();
-
hba = get_adapter_list_head();
if (hba && hba->cnic)
cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
@@ -1640,18 +1653,26 @@ no_nx2_route:
static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep)
{
- if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+ if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
hba->cnic->cm_destroy(ep->cm_sk);
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
- ep->state = EP_STATE_DISCONN_COMPL;
-
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
ep->state == EP_STATE_DISCONN_TIMEDOUT) {
- printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump,"
- " NW/PCIe trace, driver msgs to developers"
- " for analysis\n");
- return 1;
+ if (ep->conn && ep->conn->cls_conn &&
+ ep->conn->cls_conn->dd_data) {
+ struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
+
+ /* Must suspend all rx queue activity for this ep */
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ }
+ /* CONN_DISCONNECT timeout may or may not be an issue depending
+ * on what transcribed in TCP layer, different targets behave
+ * differently
+ */
+ printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, "
+ "please submit GRC Dump, NW/PCIe trace, "
+ "driver msgs to developers for analysis\n",
+ hba->netdev->name);
}
ep->state = EP_STATE_CLEANUP_START;
@@ -1664,7 +1685,9 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
bnx2i_ep_destroy_list_add(hba, ep);
/* destroy iSCSI context, wait for it to complete */
- bnx2i_send_conn_destroy(hba, ep);
+ if (bnx2i_send_conn_destroy(hba, ep))
+ ep->state = EP_STATE_CLEANUP_CMPL;
+
wait_event_interruptible(ep->ofld_wait,
(ep->state != EP_STATE_CLEANUP_START));
@@ -1711,8 +1734,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
if (shost) {
/* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
- /* Register the device with cnic if not already done so */
- bnx2i_register_device(hba);
} else
/*
* check if the given destination can be reached through
@@ -1720,13 +1741,17 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
*/
hba = bnx2i_check_route(dst_addr);
- if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
+ if (!hba) {
rc = -EINVAL;
goto nohba;
}
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) {
+ rc = -EPERM;
+ goto check_busy;
+ }
cnic = hba->cnic;
- mutex_lock(&hba->net_dev_lock);
ep = bnx2i_alloc_ep(hba);
if (!ep) {
rc = -ENOMEM;
@@ -1734,23 +1759,21 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
}
bnx2i_ep = ep->dd_data;
- if (bnx2i_adapter_ready(hba)) {
- rc = -EPERM;
- goto net_if_down;
- }
-
bnx2i_ep->num_active_cmds = 0;
iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
if (iscsi_cid == -1) {
- printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n");
+ printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate "
+ "iscsi cid\n", hba->netdev->name);
rc = -ENOMEM;
- goto iscsi_cid_err;
+ bnx2i_free_ep(ep);
+ goto check_busy;
}
bnx2i_ep->hba_age = hba->age;
rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
if (rc != 0) {
- printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n");
+ printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error"
+ "\n", hba->netdev->name);
rc = -ENOMEM;
goto qp_resc_err;
}
@@ -1765,7 +1788,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
add_timer(&bnx2i_ep->ofld_timer);
- bnx2i_send_conn_ofld_req(hba, bnx2i_ep);
+ if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) {
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
+ printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe"
+ "\n", hba->netdev->name);
+ bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
+ goto conn_failed;
+ }
/* Wait for CNIC hardware to setup conn context and return 'cid' */
wait_event_interruptible(bnx2i_ep->ofld_wait,
@@ -1778,7 +1812,12 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
- rc = -ENOSPC;
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
goto conn_failed;
}
@@ -1786,7 +1825,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
if (rc) {
rc = -EINVAL;
- goto conn_failed;
+ /* Need to terminate and cleanup the connection */
+ goto release_ep;
}
bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
@@ -1830,15 +1870,12 @@ release_ep:
return ERR_PTR(rc);
}
conn_failed:
-net_if_down:
-iscsi_cid_err:
bnx2i_free_qp_resc(hba, bnx2i_ep);
qp_resc_err:
bnx2i_free_ep(ep);
check_busy:
mutex_unlock(&hba->net_dev_lock);
nohba:
- bnx2i_unreg_dev_all();
return ERR_PTR(rc);
}
@@ -1898,12 +1935,13 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
cnic_dev_10g = 1;
switch (bnx2i_ep->state) {
- case EP_STATE_CONNECT_START:
+ case EP_STATE_CONNECT_FAILED:
case EP_STATE_CLEANUP_FAILED:
case EP_STATE_OFLD_FAILED:
case EP_STATE_DISCONN_TIMEDOUT:
ret = 0;
break;
+ case EP_STATE_CONNECT_START:
case EP_STATE_CONNECT_COMPL:
case EP_STATE_ULP_UPDATE_START:
case EP_STATE_ULP_UPDATE_COMPL:
@@ -1914,13 +1952,10 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
ret = 1;
break;
case EP_STATE_TCP_RST_RCVD:
- ret = 0;
- break;
- case EP_STATE_CONNECT_FAILED:
if (cnic_dev_10g)
- ret = 1;
- else
ret = 0;
+ else
+ ret = 1;
break;
default:
ret = 0;
@@ -1953,7 +1988,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
if (!cnic)
return 0;
- if (bnx2i_ep->state == EP_STATE_IDLE)
+ if (bnx2i_ep->state == EP_STATE_IDLE ||
+ bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
return 0;
if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
@@ -1979,9 +2015,10 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
if (session->state == ISCSI_STATE_LOGGING_OUT) {
if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
/* Logout sent, but no resp */
- printk(KERN_ALERT "bnx2i - WARNING "
- "logout response was not "
- "received!\n");
+ printk(KERN_ALERT "bnx2i (%s): WARNING"
+ " logout response was not "
+ "received!\n",
+ bnx2i_ep->hba->netdev->name);
} else if (bnx2i_ep->state ==
EP_STATE_LOGOUT_RESP_RCVD)
close = 1;
@@ -1999,9 +2036,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
else
close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
- /* No longer allow CFC delete if cm_close/abort fails the request */
if (close_ret)
- printk(KERN_ALERT "bnx2i: %s close/abort(%d) returned %d\n",
+ printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n",
bnx2i_ep->hba->netdev->name, close, close_ret);
else
/* wait for option-2 conn teardown */
@@ -2015,7 +2051,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
destroy_conn:
bnx2i_ep_active_list_del(hba, bnx2i_ep);
if (bnx2i_tear_down_conn(hba, bnx2i_ep))
- ret = -EINVAL;
+ return -EINVAL;
out:
bnx2i_ep->state = EP_STATE_IDLE;
return ret;
@@ -2054,14 +2090,17 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
mutex_lock(&hba->net_dev_lock);
- if (bnx2i_ep->state == EP_STATE_IDLE)
- goto return_bnx2i_ep;
+ if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
+ goto out;
- if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+ if (bnx2i_ep->state == EP_STATE_IDLE)
goto free_resc;
- if (bnx2i_ep->hba_age != hba->age)
+ if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
+ (bnx2i_ep->hba_age != hba->age)) {
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
goto free_resc;
+ }
/* Do all chip cleanup here */
if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
@@ -2070,14 +2109,13 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
}
free_resc:
bnx2i_free_qp_resc(hba, bnx2i_ep);
-return_bnx2i_ep:
+
if (bnx2i_conn)
bnx2i_conn->ep = NULL;
bnx2i_free_ep(ep);
+out:
mutex_unlock(&hba->net_dev_lock);
- if (!hba->ofld_conns_active)
- bnx2i_unreg_dev_all();
wake_up_interruptible(&hba->eh_wait);
}
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index 96426b751eb2..9174196d9033 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,12 +1,13 @@
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2009 Broadcom Corporation
+ * Copyright (c) 2004 - 2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include "bnx2i.h"
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 99f2b8c5dd63..8c04fada710b 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -692,6 +692,9 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb)
&csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port),
atid, tid, status, csk, csk->state, csk->flags);
+ if (status == CPL_ERR_RTX_NEG_ADVICE)
+ goto rel_skb;
+
if (status && status != CPL_ERR_TCAM_FULL &&
status != CPL_ERR_CONN_EXIST &&
status != CPL_ERR_ARP_MISS)
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index be5661707dfa..d2ad3d676724 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -825,7 +825,7 @@ unsigned int cxgbi_sock_select_mss(struct cxgbi_sock *csk, unsigned int pmtu)
unsigned int idx;
struct dst_entry *dst = csk->dst;
- csk->advmss = dst_metric(dst, RTAX_ADVMSS);
+ csk->advmss = dst_metric_advmss(dst);
if (csk->advmss > pmtu - 40)
csk->advmss = pmtu - 40;
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 54f50b07dac7..b0f8523e665f 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1080,7 +1080,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
* and is expected to be held on return.
*
**/
-static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
@@ -1154,6 +1154,7 @@ complete:
return 0;
}
+static DEF_SCSI_QCMD(dc395x_queue_command)
/*
* Return the disk geometry for the given SCSI device.
@@ -3795,7 +3796,7 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
* adapter_add_device - Adds the device instance to the adaptor instance.
*
* @acb: The adapter device to be updated
- * @dcb: A newly created and intialised device instance to add.
+ * @dcb: A newly created and initialised device instance to add.
**/
static void adapter_add_device(struct AdapterCtlBlk *acb,
struct DeviceCtlBlk *dcb)
@@ -4497,7 +4498,7 @@ static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb)
* init_adapter - Grab the resource for the card, setup the adapter
* information, set the card into a known state, create the various
* tables etc etc. This basically gets all adapter information all up
- * to date, intialised and gets the chip in sync with it.
+ * to date, initialised and gets the chip in sync with it.
*
* @host: This hosts adapter structure
* @io_port: The base I/O port
@@ -4788,7 +4789,7 @@ static void banner_display(void)
* that it finds in the system. The pci_dev strcuture indicates which
* instance we are being called from.
*
- * @dev: The PCI device to intialize.
+ * @dev: The PCI device to initialize.
* @id: Looks like a pointer to the entry in our pci device table
* that was actually matched by the PCI subsystem.
*
@@ -4859,7 +4860,7 @@ fail:
* dc395x_remove_one - Called to remove a single instance of the
* adapter.
*
- * @dev: The PCI device to intialize.
+ * @dev: The PCI device to initialize.
**/
static void __devexit dc395x_remove_one(struct pci_dev *dev)
{
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 6fae3d285ae7..b837c5b3c8f9 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -442,12 +442,19 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
sdev = q->queuedata;
if (sdev && sdev->scsi_dh_data)
scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (!scsi_dh || !get_device(&sdev->sdev_gendev))
+ if (!scsi_dh || !get_device(&sdev->sdev_gendev) ||
+ sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
err = SCSI_DH_NOSYS;
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ err = SCSI_DH_DEV_OFFLINED;
spin_unlock_irqrestore(q->queue_lock, flags);
- if (err)
+ if (err) {
+ if (fn)
+ fn(data, err);
return err;
+ }
if (scsi_dh->activate)
err = scsi_dh->activate(sdev, fn, data);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index b9bcfa4c7d26..5be3ae15cb71 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -773,6 +773,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"ENGENIO", "INF-01-00"},
{"STK", "FLEXLINE 380"},
{"SUN", "CSM100_R_FC"},
+ {"SUN", "STK6580_6780"},
+ {"SUN", "SUN_6180"},
{NULL, NULL},
};
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 23dec0063385..cffcb108ac96 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -423,7 +423,7 @@ static int adpt_slave_configure(struct scsi_device * device)
return 0;
}
-static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
{
adpt_hba* pHba = NULL;
struct adpt_device* pDev = NULL; /* dpt per device information */
@@ -491,6 +491,8 @@ static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
return adpt_scsi_to_i2o(pHba, cmd, pDev);
}
+static DEF_SCSI_QCMD(adpt_queue)
+
static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev,
sector_t capacity, int geom[])
{
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 337746d46043..beded716f93f 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -29,7 +29,7 @@
*/
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_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd);
static int adpt_abort(struct scsi_cmnd * cmd);
static int adpt_reset(struct scsi_cmnd* cmd);
static int adpt_release(struct Scsi_Host *host);
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 0b205f8c7326..cdc621204b66 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -36,7 +36,7 @@ static int dtc_abort(Scsi_Cmnd *);
static int dtc_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int dtc_detect(struct scsi_host_template *);
-static int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int dtc_bus_reset(Scsi_Cmnd *);
#ifndef CMD_PER_LUN
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index d1c31378f6da..53925ac178fd 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -505,8 +505,7 @@
static int eata2x_detect(struct scsi_host_template *);
static int eata2x_release(struct Scsi_Host *);
-static int eata2x_queuecommand(struct scsi_cmnd *,
- void (*done) (struct scsi_cmnd *));
+static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int eata2x_eh_abort(struct scsi_cmnd *);
static int eata2x_eh_host_reset(struct scsi_cmnd *);
static int eata2x_bios_param(struct scsi_device *, struct block_device *,
@@ -1758,7 +1757,7 @@ static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha)
}
-static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
+static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct Scsi_Host *shost = SCpnt->device->host;
@@ -1843,6 +1842,8 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
return 0;
}
+static DEF_SCSI_QCMD(eata2x_queuecommand)
+
static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
{
struct Scsi_Host *shost = SCarg->device->host;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 60886c19065e..4a9641e69f54 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -335,7 +335,7 @@ static inline unsigned int eata_pio_send_command(unsigned long base, unsigned ch
return 0;
}
-static int eata_pio_queue(struct scsi_cmnd *cmd,
+static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
unsigned int x, y;
@@ -438,6 +438,8 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(eata_pio_queue)
+
static int eata_pio_abort(struct scsi_cmnd *cmd)
{
unsigned int loop = 100;
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index e2bc779f86c1..57558523c1b8 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -916,7 +916,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
scsi_track_queue_full(dev, lp->num_tagged - 1);
}
-static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct scsi_device *dev = cmd->device;
struct esp *esp = shost_priv(dev->host);
@@ -941,6 +941,8 @@ static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
return 0;
}
+static DEF_SCSI_QCMD(esp_queuecommand)
+
static int esp_check_gross_error(struct esp *esp)
{
if (esp->sreg & ESP_STAT_SPAM) {
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 844d618b84bd..9f9600b67001 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -117,7 +117,7 @@ static void fcoe_recv_frame(struct sk_buff *skb);
static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
-module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR);
+module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_FABRIC, S_IWUSR);
__MODULE_PARM_TYPE(create, "string");
MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
module_param_call(create_vn2vn, fcoe_create, NULL,
@@ -854,7 +854,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Cleanup the fc_lport */
fc_lport_destroy(lport);
- fc_fcp_destroy(lport);
/* Stop the transmit retry timer */
del_timer_sync(&port->timer);
@@ -876,6 +875,9 @@ static void fcoe_if_destroy(struct fc_lport *lport)
fc_remove_host(lport->host);
scsi_remove_host(lport->host);
+ /* Destroy lport scsi_priv */
+ fc_fcp_destroy(lport);
+
/* There are no more rports or I/O, free the EM */
fc_exch_mgr_free(lport);
@@ -1243,7 +1245,6 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
struct fcoe_interface *fcoe;
struct fc_frame_header *fh;
struct fcoe_percpu_s *fps;
- struct fcoe_port *port;
struct ethhdr *eh;
unsigned int cpu;
@@ -1262,16 +1263,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
skb_tail_pointer(skb), skb_end_pointer(skb),
skb->csum, skb->dev ? skb->dev->name : "<NULL>");
- /* check for mac addresses */
eh = eth_hdr(skb);
- port = lport_priv(lport);
- if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
- compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
- compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
- FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
- eh->h_dest);
- goto err;
- }
if (is_fip_mode(&fcoe->ctlr) &&
compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
@@ -1291,6 +1283,12 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
fh = (struct fc_frame_header *) skb_transport_header(skb);
+ if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) {
+ FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n",
+ eh->h_dest);
+ goto err;
+ }
+
fr = fcoe_dev_from_skb(skb);
fr->fr_dev = lport;
fr->ptype = ptype;
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index aa503d83092a..625c6be25396 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -54,6 +54,7 @@ MODULE_LICENSE("GPL v2");
static void fcoe_ctlr_timeout(unsigned long);
static void fcoe_ctlr_timer_work(struct work_struct *);
static void fcoe_ctlr_recv_work(struct work_struct *);
+static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *);
static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
@@ -176,6 +177,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
fip->mode = mode;
INIT_LIST_HEAD(&fip->fcfs);
mutex_init(&fip->ctlr_mutex);
+ spin_lock_init(&fip->ctlr_lock);
fip->flogi_oxid = FC_XID_UNKNOWN;
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
@@ -231,6 +233,49 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
EXPORT_SYMBOL(fcoe_ctlr_destroy);
/**
+ * fcoe_ctlr_announce() - announce new FCF selection
+ * @fip: The FCoE controller
+ *
+ * Also sets the destination MAC for FCoE and control packets
+ *
+ * Called with neither ctlr_mutex nor ctlr_lock held.
+ */
+static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *sel;
+ struct fcoe_fcf *fcf;
+
+ mutex_lock(&fip->ctlr_mutex);
+ spin_lock_bh(&fip->ctlr_lock);
+
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = NULL;
+ list_for_each_entry(fcf, &fip->fcfs, list)
+ fcf->flogi_sent = 0;
+
+ spin_unlock_bh(&fip->ctlr_lock);
+ sel = fip->sel_fcf;
+
+ if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr))
+ goto unlock;
+ if (!is_zero_ether_addr(fip->dest_addr)) {
+ printk(KERN_NOTICE "libfcoe: host%d: "
+ "FIP Fibre-Channel Forwarder MAC %pM deselected\n",
+ fip->lp->host->host_no, fip->dest_addr);
+ memset(fip->dest_addr, 0, ETH_ALEN);
+ }
+ if (sel) {
+ printk(KERN_INFO "libfcoe: host%d: FIP selected "
+ "Fibre-Channel Forwarder MAC %pM\n",
+ fip->lp->host->host_no, sel->fcf_mac);
+ memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+ fip->map_dest = 0;
+ }
+unlock:
+ mutex_unlock(&fip->ctlr_mutex);
+}
+
+/**
* fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port
* @fip: The FCoE controller to get the maximum FCoE size from
*
@@ -564,6 +609,9 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
* The caller must check that the length is a multiple of 4.
* The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
* The the skb must also be an fc_frame.
+ *
+ * This is called from the lower-level driver with spinlocks held,
+ * so we must not take a mutex here.
*/
int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
struct sk_buff *skb)
@@ -601,7 +649,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
switch (op) {
case ELS_FLOGI:
op = FIP_DT_FLOGI;
- break;
+ if (fip->mode == FIP_MODE_VN2VN)
+ break;
+ spin_lock_bh(&fip->ctlr_lock);
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = skb;
+ fip->flogi_req_send = 1;
+ spin_unlock_bh(&fip->ctlr_lock);
+ schedule_work(&fip->timer_work);
+ return -EINPROGRESS;
case ELS_FDISC:
if (ntoh24(fh->fh_s_id))
return 0;
@@ -922,11 +978,9 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
}
mtu_valid = fcoe_ctlr_mtu_valid(fcf);
fcf->time = jiffies;
- if (!found) {
- LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
- "map %x val %d\n",
- fcf->fabric_name, fcf->fc_map, mtu_valid);
- }
+ if (!found)
+ LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n",
+ fcf->fabric_name, fcf->fcf_mac);
/*
* If this advertisement is not solicited and our max receive size
@@ -945,6 +999,17 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
fcoe_ctlr_solicit(fip, NULL);
/*
+ * Put this FCF at the head of the list for priority among equals.
+ * This helps in the case of an NPV switch which insists we use
+ * the FCF that answers multicast solicitations, not the others that
+ * are sending periodic multicast advertisements.
+ */
+ if (mtu_valid) {
+ list_del(&fcf->list);
+ list_add(&fcf->list, &fip->fcfs);
+ }
+
+ /*
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
*/
@@ -1061,18 +1126,24 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
els_op = *(u8 *)(fh + 1);
if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
- sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
- fip->mode != FIP_MODE_VN2VN) {
- if (!is_valid_ether_addr(granted_mac)) {
- LIBFCOE_FIP_DBG(fip,
- "Invalid MAC address %pM in FIP ELS\n",
- granted_mac);
- goto drop;
- }
- memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
+ sub == FIP_SC_REP && fip->mode != FIP_MODE_VN2VN) {
+ if (els_op == ELS_LS_ACC) {
+ if (!is_valid_ether_addr(granted_mac)) {
+ LIBFCOE_FIP_DBG(fip,
+ "Invalid MAC address %pM in FIP ELS\n",
+ granted_mac);
+ goto drop;
+ }
+ memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
- if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
- fip->flogi_oxid = FC_XID_UNKNOWN;
+ if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
+ fip->flogi_oxid = FC_XID_UNKNOWN;
+ if (els_dtype == FIP_DT_FLOGI)
+ fcoe_ctlr_announce(fip);
+ }
+ } else if (els_dtype == FIP_DT_FLOGI &&
+ !fcoe_ctlr_flogi_retry(fip))
+ goto drop; /* retrying FLOGI so drop reject */
}
if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
@@ -1326,20 +1397,39 @@ drop:
* fcoe_ctlr_select() - Select the best FCF (if possible)
* @fip: The FCoE controller
*
+ * Returns the selected FCF, or NULL if none are usable.
+ *
* If there are conflicting advertisements, no FCF can be chosen.
*
+ * If there is already a selected FCF, this will choose a better one or
+ * an equivalent one that hasn't already been sent a FLOGI.
+ *
* Called with lock held.
*/
-static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
+static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
- struct fcoe_fcf *best = NULL;
+ struct fcoe_fcf *best = fip->sel_fcf;
+ struct fcoe_fcf *first;
+
+ first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list);
list_for_each_entry(fcf, &fip->fcfs, list) {
- LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
- "VFID %d map %x val %d\n",
- fcf->fabric_name, fcf->vfid,
- fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
+ LIBFCOE_FIP_DBG(fip, "consider FCF fab %16.16llx "
+ "VFID %d mac %pM map %x val %d "
+ "sent %u pri %u\n",
+ fcf->fabric_name, fcf->vfid, fcf->fcf_mac,
+ fcf->fc_map, fcoe_ctlr_mtu_valid(fcf),
+ fcf->flogi_sent, fcf->pri);
+ if (fcf->fabric_name != first->fabric_name ||
+ fcf->vfid != first->vfid ||
+ fcf->fc_map != first->fc_map) {
+ LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
+ "or FC-MAP\n");
+ return NULL;
+ }
+ if (fcf->flogi_sent)
+ continue;
if (!fcoe_ctlr_fcf_usable(fcf)) {
LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
"map %x %svalid %savailable\n",
@@ -1349,21 +1439,131 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
"" : "un");
continue;
}
- if (!best) {
- best = fcf;
- continue;
- }
- if (fcf->fabric_name != best->fabric_name ||
- fcf->vfid != best->vfid ||
- fcf->fc_map != best->fc_map) {
- LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
- "or FC-MAP\n");
- return;
- }
- if (fcf->pri < best->pri)
+ if (!best || fcf->pri < best->pri || best->flogi_sent)
best = fcf;
}
fip->sel_fcf = best;
+ if (best) {
+ LIBFCOE_FIP_DBG(fip, "using FCF mac %pM\n", best->fcf_mac);
+ fip->port_ka_time = jiffies +
+ msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ fip->ctlr_ka_time = jiffies + best->fka_period;
+ if (time_before(fip->ctlr_ka_time, fip->timer.expires))
+ mod_timer(&fip->timer, fip->ctlr_ka_time);
+ }
+ return best;
+}
+
+/**
+ * fcoe_ctlr_flogi_send_locked() - send FIP-encapsulated FLOGI to current FCF
+ * @fip: The FCoE controller
+ *
+ * Returns non-zero error if it could not be sent.
+ *
+ * Called with ctlr_mutex and ctlr_lock held.
+ * Caller must verify that fip->sel_fcf is not NULL.
+ */
+static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
+{
+ struct sk_buff *skb;
+ struct sk_buff *skb_orig;
+ struct fc_frame_header *fh;
+ int error;
+
+ skb_orig = fip->flogi_req;
+ if (!skb_orig)
+ return -EINVAL;
+
+ /*
+ * Clone and send the FLOGI request. If clone fails, use original.
+ */
+ skb = skb_clone(skb_orig, GFP_ATOMIC);
+ if (!skb) {
+ skb = skb_orig;
+ fip->flogi_req = NULL;
+ }
+ fh = (struct fc_frame_header *)skb->data;
+ error = fcoe_ctlr_encaps(fip, fip->lp, FIP_DT_FLOGI, skb,
+ ntoh24(fh->fh_d_id));
+ if (error) {
+ kfree_skb(skb);
+ return error;
+ }
+ fip->send(fip, skb);
+ fip->sel_fcf->flogi_sent = 1;
+ return 0;
+}
+
+/**
+ * fcoe_ctlr_flogi_retry() - resend FLOGI request to a new FCF if possible
+ * @fip: The FCoE controller
+ *
+ * Returns non-zero error code if there's no FLOGI request to retry or
+ * no alternate FCF available.
+ */
+static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *fcf;
+ int error;
+
+ mutex_lock(&fip->ctlr_mutex);
+ spin_lock_bh(&fip->ctlr_lock);
+ LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
+ fcf = fcoe_ctlr_select(fip);
+ if (!fcf || fcf->flogi_sent) {
+ kfree_skb(fip->flogi_req);
+ fip->flogi_req = NULL;
+ error = -ENOENT;
+ } else {
+ fcoe_ctlr_solicit(fip, NULL);
+ error = fcoe_ctlr_flogi_send_locked(fip);
+ }
+ spin_unlock_bh(&fip->ctlr_lock);
+ mutex_unlock(&fip->ctlr_mutex);
+ return error;
+}
+
+
+/**
+ * fcoe_ctlr_flogi_send() - Handle sending of FIP FLOGI.
+ * @fip: The FCoE controller that timed out
+ *
+ * Done here because fcoe_ctlr_els_send() can't get mutex.
+ *
+ * Called with ctlr_mutex held. The caller must not hold ctlr_lock.
+ */
+static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
+{
+ struct fcoe_fcf *fcf;
+
+ spin_lock_bh(&fip->ctlr_lock);
+ fcf = fip->sel_fcf;
+ if (!fcf || !fip->flogi_req_send)
+ goto unlock;
+
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI\n");
+
+ /*
+ * If this FLOGI is being sent due to a timeout retry
+ * to the same FCF as before, select a different FCF if possible.
+ */
+ if (fcf->flogi_sent) {
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI - reselect\n");
+ fcf = fcoe_ctlr_select(fip);
+ if (!fcf || fcf->flogi_sent) {
+ LIBFCOE_FIP_DBG(fip, "sending FLOGI - clearing\n");
+ list_for_each_entry(fcf, &fip->fcfs, list)
+ fcf->flogi_sent = 0;
+ fcf = fcoe_ctlr_select(fip);
+ }
+ }
+ if (fcf) {
+ fcoe_ctlr_flogi_send_locked(fip);
+ fip->flogi_req_send = 0;
+ } else /* XXX */
+ LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
+unlock:
+ spin_unlock_bh(&fip->ctlr_lock);
}
/**
@@ -1411,34 +1611,16 @@ static void fcoe_ctlr_timer_work(struct work_struct *work)
sel = fip->sel_fcf;
if (!sel && fip->sel_time) {
if (time_after_eq(jiffies, fip->sel_time)) {
- fcoe_ctlr_select(fip);
- sel = fip->sel_fcf;
+ sel = fcoe_ctlr_select(fip);
fip->sel_time = 0;
} else if (time_after(next_timer, fip->sel_time))
next_timer = fip->sel_time;
}
- if (sel != fcf) {
- fcf = sel; /* the old FCF may have been freed */
- if (sel) {
- printk(KERN_INFO "libfcoe: host%d: FIP selected "
- "Fibre-Channel Forwarder MAC %pM\n",
- fip->lp->host->host_no, sel->fcf_mac);
- memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
- fip->map_dest = 0;
- fip->port_ka_time = jiffies +
- msecs_to_jiffies(FIP_VN_KA_PERIOD);
- fip->ctlr_ka_time = jiffies + sel->fka_period;
- if (time_after(next_timer, fip->ctlr_ka_time))
- next_timer = fip->ctlr_ka_time;
- } else {
- printk(KERN_NOTICE "libfcoe: host%d: "
- "FIP Fibre-Channel Forwarder timed out. "
- "Starting FCF discovery.\n",
- fip->lp->host->host_no);
- reset = 1;
- }
- }
+ if (sel && fip->flogi_req_send)
+ fcoe_ctlr_flogi_send(fip);
+ else if (!sel && fcf)
+ reset = 1;
if (sel && !sel->fd_flags) {
if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
@@ -2296,7 +2478,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
struct fip_header *fiph;
enum fip_vn2vn_subcode sub;
- union {
+ struct {
struct fc_rport_priv rdata;
struct fcoe_rport frport;
} buf;
@@ -2475,7 +2657,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
case FIP_ST_LINK_WAIT:
goto unlock;
default:
- WARN(1, "unexpected state %d", fip->state);
+ WARN(1, "unexpected state %d\n", fip->state);
goto unlock;
}
mod_timer(&fip->timer, next_time);
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 2ad95aa8f585..a2c6135d337e 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -1072,7 +1072,7 @@ static int fd_mcs_release(struct Scsi_Host *shpnt)
return 0;
}
-static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *shpnt = SCpnt->device->host;
@@ -1122,6 +1122,8 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(fd_mcs_queue)
+
#if DEBUG_ABORT || DEBUG_RESET
static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
{
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index e296bcc57d5c..69b7aa54f43f 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1419,7 +1419,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
+static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
if (in_command) {
@@ -1469,6 +1469,8 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
return 0;
}
+static DEF_SCSI_QCMD(fdomain_16x0_queue)
+
#if DEBUG_ABORT
static void print_info(struct scsi_cmnd *SCpnt)
{
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index cbb20b13b228..92f185081e62 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -246,7 +246,7 @@ void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *);
void fnic_update_mac(struct fc_lport *, u8 *new);
void fnic_update_mac_locked(struct fnic *, u8 *new);
-int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
int fnic_abort_cmd(struct scsi_cmnd *);
int fnic_device_reset(struct scsi_cmnd *);
int fnic_host_reset(struct scsi_cmnd *);
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 198cbab3e894..22d02404d15f 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -349,7 +349,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
* Routine to send a scsi cdb
* Called with host_lock held and interrupts disabled.
*/
-int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
struct fc_lport *lp;
struct fc_rport *rport;
@@ -457,6 +457,8 @@ out:
return ret;
}
+DEF_SCSI_QCMD(fnic_queuecommand)
+
/*
* fnic_fcpio_fw_reset_cmpl_handler
* Routine to handle fw reset completion
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index 921764c9ab24..1bcdb7beb77b 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -46,7 +46,7 @@
static int generic_NCR5380_abort(Scsi_Cmnd *);
static int generic_NCR5380_detect(struct scsi_host_template *);
static int generic_NCR5380_release_resources(struct Scsi_Host *);
-static int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int generic_NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
static const char* generic_NCR5380_info(struct Scsi_Host *);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 5a3f93101017..3242bcabad97 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -185,7 +185,7 @@ static long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg);
static void gdth_flush(gdth_ha_str *ha);
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+static int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
struct gdth_cmndinfo *cmndinfo);
static void gdth_scsi_done(struct scsi_cmnd *scp);
@@ -4004,7 +4004,7 @@ static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,se
}
-static int gdth_queuecommand(struct scsi_cmnd *scp,
+static int gdth_queuecommand_lck(struct scsi_cmnd *scp,
void (*done)(struct scsi_cmnd *))
{
gdth_ha_str *ha = shost_priv(scp->device->host);
@@ -4022,6 +4022,8 @@ static int gdth_queuecommand(struct scsi_cmnd *scp,
return __gdth_queuecommand(ha, scp, cmndinfo);
}
+static DEF_SCSI_QCMD(gdth_queuecommand)
+
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
struct gdth_cmndinfo *cmndinfo)
{
@@ -4177,6 +4179,14 @@ static int ioc_general(void __user *arg, char *cmnd)
ha = gdth_find_ha(gen.ionode);
if (!ha)
return -EFAULT;
+
+ if (gen.data_len > INT_MAX)
+ return -EINVAL;
+ if (gen.sense_len > INT_MAX)
+ return -EINVAL;
+ if (gen.data_len + gen.sense_len > INT_MAX)
+ return -EINVAL;
+
if (gen.data_len + gen.sense_len != 0) {
if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len,
FALSE, &paddr)))
@@ -4263,8 +4273,10 @@ static int ioc_general(void __user *arg, char *cmnd)
}
rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, &gen.info);
- if (rval < 0)
+ if (rval < 0) {
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return rval;
+ }
gen.status = rval;
if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf,
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 0572b9bf4bd6..652754319a4b 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -365,8 +365,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len = 0;
begin = pos;
}
- if (pos > offset + length)
+ if (pos > offset + length) {
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
goto stop_output;
+ }
}
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
@@ -450,8 +452,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len = 0;
begin = pos;
}
- if (pos > offset + length)
+ if (pos > offset + length) {
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
goto stop_output;
+ }
} while (drv_no != -1);
if (is_mirr) {
@@ -472,8 +476,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len = 0;
begin = pos;
}
- if (pos > offset + length)
+ if (pos > offset + length) {
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
goto stop_output;
+ }
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
@@ -542,8 +548,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len = 0;
begin = pos;
}
- if (pos > offset + length)
+ if (pos > offset + length) {
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
goto stop_output;
+ }
}
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c5d0606ad097..12deffccb8da 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -31,7 +31,6 @@
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <linux/blktrace_api.h>
#include <linux/uaccess.h>
@@ -91,11 +90,7 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
-#define PCI_DEVICE_ID_HP_CISSF 0x333f
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
- {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
- {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -114,8 +109,6 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324a103C, "Smart Array P712m", &SA5_access},
{0x324b103C, "Smart Array P711m", &SA5_access},
- {0x3233103C, "StorageWorks P1210m", &SA5_access},
- {0x333F103C, "StorageWorks P1210m", &SA5_access},
{0x3250103C, "Smart Array", &SA5_access},
{0x3250113C, "Smart Array", &SA5_access},
{0x3250123C, "Smart Array", &SA5_access},
@@ -143,8 +136,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
int cmd_type);
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *));
+static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
static int hpsa_scan_finished(struct Scsi_Host *sh,
unsigned long elapsed_time);
@@ -649,11 +641,6 @@ static void fixup_botched_add(struct ctlr_info *h,
static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
struct hpsa_scsi_dev_t *dev2)
{
- if ((is_logical_dev_addr_mode(dev1->scsi3addr) ||
- (dev1->lun != -1 && dev2->lun != -1)) &&
- dev1->devtype != 0x0C)
- return (memcmp(dev1, dev2, sizeof(*dev1)) == 0);
-
/* we compare everything except lun and target as these
* are not yet assigned. Compare parts likely
* to differ first
@@ -668,12 +655,8 @@ static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
return 0;
if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
return 0;
- if (memcmp(dev1->revision, dev2->revision, sizeof(dev1->revision)) != 0)
- return 0;
if (dev1->devtype != dev2->devtype)
return 0;
- if (dev1->raid_level != dev2->raid_level)
- return 0;
if (dev1->bus != dev2->bus)
return 0;
return 1;
@@ -1485,8 +1468,6 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->vendor));
memcpy(this_device->model, &inq_buff[16],
sizeof(this_device->model));
- memcpy(this_device->revision, &inq_buff[32],
- sizeof(this_device->revision));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
hpsa_get_device_id(h, scsi3addr, this_device->device_id,
@@ -1926,7 +1907,7 @@ sglist_finished:
}
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ctlr_info *h;
@@ -2020,6 +2001,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+
static void hpsa_scan_start(struct Scsi_Host *sh)
{
struct ctlr_info *h = shost_to_hba(sh);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index a203ef65cb50..19586e189f0f 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -45,7 +45,6 @@ struct hpsa_scsi_dev_t {
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
- unsigned char revision[4]; /* bytes 32-35 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
};
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 0729f150b33a..10b65556937b 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -751,7 +751,7 @@ static void hptiop_post_req_mv(struct hptiop_hba *hba,
MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
}
-static int hptiop_queuecommand(struct scsi_cmnd *scp,
+static int hptiop_queuecommand_lck(struct scsi_cmnd *scp,
void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = scp->device->host;
@@ -819,6 +819,8 @@ cmd_done:
return 0;
}
+static DEF_SCSI_QCMD(hptiop_queuecommand)
+
static const char *hptiop_info(struct Scsi_Host *host)
{
return driver_name_long;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 9a4b69d4f4eb..67fc8ffd52e6 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -39,7 +39,7 @@
#include <scsi/scsi_host.h>
/* Common forward declarations for all Linux-versions: */
-static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *);
static int ibmmca_abort (Scsi_Cmnd *);
static int ibmmca_host_reset (Scsi_Cmnd *);
static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
@@ -1691,7 +1691,7 @@ static int __devexit ibmmca_remove(struct device *dev)
}
/* The following routine is the SCSI command queue for the midlevel driver */
-static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
unsigned int ldn;
unsigned int scsi_cmd;
@@ -1996,6 +1996,8 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(ibmmca_queuecommand)
+
static int __ibmmca_abort(Scsi_Cmnd * cmd)
{
/* Abort does not work, as the adapter never generates an interrupt on
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 00d08b25425f..b7650613b8c2 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -1606,7 +1606,7 @@ static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost)
* Returns:
* 0 on success / other on failure
**/
-static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done) (struct scsi_cmnd *))
{
struct ibmvfc_host *vhost = shost_priv(cmnd->device->host);
@@ -1672,6 +1672,8 @@ static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
return 0;
}
+static DEF_SCSI_QCMD(ibmvfc_queuecommand)
+
/**
* ibmvfc_sync_completion - Signal that a synchronous command has completed
* @evt: ibmvfc event struct
@@ -2491,23 +2493,23 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport)
}
static const struct ibmvfc_async_desc ae_desc [] = {
- { IBMVFC_AE_ELS_PLOGI, "PLOGI", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_ELS_LOGO, "LOGO", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_ELS_PRLO, "PRLO", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_NPORT, "N-Port SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_GROUP, "Group SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 },
- { IBMVFC_AE_SCN_DOMAIN, "Domain SCN", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_SCN_FABRIC, "Fabric SCN", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_UP, "Link Up", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_DOWN, "Link Down", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_LINK_DEAD, "Link Dead", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_HALT, "Halt", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_RESUME, "Resume", IBMVFC_DEFAULT_LOG_LEVEL },
- { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed", IBMVFC_DEFAULT_LOG_LEVEL },
+ { "PLOGI", IBMVFC_AE_ELS_PLOGI, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "LOGO", IBMVFC_AE_ELS_LOGO, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "PRLO", IBMVFC_AE_ELS_PRLO, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "N-Port SCN", IBMVFC_AE_SCN_NPORT, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "Group SCN", IBMVFC_AE_SCN_GROUP, IBMVFC_DEFAULT_LOG_LEVEL + 1 },
+ { "Domain SCN", IBMVFC_AE_SCN_DOMAIN, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Fabric SCN", IBMVFC_AE_SCN_FABRIC, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Up", IBMVFC_AE_LINK_UP, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Down", IBMVFC_AE_LINK_DOWN, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Link Dead", IBMVFC_AE_LINK_DEAD, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Halt", IBMVFC_AE_HALT, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Resume", IBMVFC_AE_RESUME, IBMVFC_DEFAULT_LOG_LEVEL },
+ { "Adapter Failed", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL },
};
static const struct ibmvfc_async_desc unknown_ae = {
- 0, "Unknown async", IBMVFC_DEFAULT_LOG_LEVEL
+ "Unknown async", 0, IBMVFC_DEFAULT_LOG_LEVEL
};
/**
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index ef663e7c9bbc..834c37fc7ce9 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -542,8 +542,8 @@ enum ibmvfc_async_event {
};
struct ibmvfc_async_desc {
- enum ibmvfc_async_event ae;
const char *desc;
+ enum ibmvfc_async_event ae;
int log_level;
};
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 67f78a470f5f..041958453e2a 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -713,7 +713,7 @@ static inline u16 lun_from_dev(struct scsi_device *dev)
* @cmd: struct scsi_cmnd to be executed
* @done: Callback function to be called when cmd is completed
*/
-static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done) (struct scsi_cmnd *))
{
struct srp_cmd *srp_cmd;
@@ -766,6 +766,8 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
}
+static DEF_SCSI_QCMD(ibmvscsi_queuecommand)
+
/* ------------------------------------------------------------
* Routines for driver initialization
*/
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 4734ab0b3ff6..99aa0e5699bc 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -926,7 +926,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
return 0;
}
-static int imm_queuecommand(struct scsi_cmnd *cmd,
+static int imm_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
imm_struct *dev = imm_dev(cmd->device->host);
@@ -949,6 +949,8 @@ static int imm_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(imm_queuecommand)
+
/*
* Apparently the disk->capacity attribute is off by 1 sector
* for all disk drives. We add the one here, but it should really
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 52bdc6df6b92..6568aab745a0 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -334,7 +334,7 @@ static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
static void in2000_execute(struct Scsi_Host *instance);
-static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
struct Scsi_Host *instance;
struct IN2000_hostdata *hostdata;
@@ -431,6 +431,8 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(in2000_queuecommand)
+
/*
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index 0fb8b06b8392..5821e1fbce08 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -396,7 +396,7 @@ struct IN2000_hostdata {
flags)
static int in2000_detect(struct scsi_host_template *) in2000__INIT;
-static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int in2000_abort(Scsi_Cmnd *);
static void in2000_setup(char *, int *) in2000__INIT;
static int in2000_biosparam(struct scsi_device *, struct block_device *,
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 108797761b95..9627d062e16b 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2639,7 +2639,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
* will cause the mid layer to call us again later with the command)
*/
-static int i91u_queuecommand(struct scsi_cmnd *cmd,
+static int i91u_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
@@ -2656,6 +2656,8 @@ static int i91u_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(i91u_queuecommand)
+
/**
* i91u_bus_reset - reset the SCSI bus
* @cmnd: Command block we want to trigger the reset for
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index df9a12c8b373..9c5c8be72231 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -146,7 +146,7 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
}
},
{ /* CRoC */
- .mailbox = 0x00040,
+ .mailbox = 0x00044,
.cache_line_size = 0x20,
{
.set_interrupt_mask_reg = 0x00010,
@@ -1048,6 +1048,8 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
sizeof(res->res_path));
res->bus = 0;
+ memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
+ sizeof(res->dev_lun.scsi_lun));
res->lun = scsilun_to_int(&res->dev_lun);
if (res->type == IPR_RES_TYPE_GENERIC_SCSI) {
@@ -1063,9 +1065,6 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
ioa_cfg->max_devs_supported);
set_bit(res->target, ioa_cfg->target_ids);
}
-
- memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
- sizeof(res->dev_lun.scsi_lun));
} else if (res->type == IPR_RES_TYPE_IOAFP) {
res->bus = IPR_IOAFP_VIRTUAL_BUS;
res->target = 0;
@@ -1116,7 +1115,7 @@ static int ipr_is_same_device(struct ipr_resource_entry *res,
if (res->ioa_cfg->sis64) {
if (!memcmp(&res->dev_id, &cfgtew->u.cfgte64->dev_id,
sizeof(cfgtew->u.cfgte64->dev_id)) &&
- !memcmp(&res->lun, &cfgtew->u.cfgte64->lun,
+ !memcmp(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun,
sizeof(cfgtew->u.cfgte64->lun))) {
return 1;
}
@@ -2901,6 +2900,12 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
return;
}
+ if (ioa_cfg->sis64) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ ssleep(IPR_DUMP_DELAY_SECONDS);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
+
start_addr = readl(ioa_cfg->ioa_mailbox);
if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) {
@@ -5709,7 +5714,7 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
* SCSI_MLQUEUE_DEVICE_BUSY if device is busy
* SCSI_MLQUEUE_HOST_BUSY if host is busy
**/
-static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
+static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
void (*done) (struct scsi_cmnd *))
{
struct ipr_ioa_cfg *ioa_cfg;
@@ -5743,7 +5748,7 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
}
if (ipr_is_gata(res) && res->sata_port)
- return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+ return ata_sas_queuecmd(scsi_cmd, res->sata_port->ap);
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
@@ -5792,6 +5797,8 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
return 0;
}
+static DEF_SCSI_QCMD(ipr_queuecommand)
+
/**
* ipr_ioctl - IOCTL handler
* @sdev: scsi device struct
@@ -7471,6 +7478,29 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
}
/**
+ * ipr_reset_get_unit_check_job - Call to get the unit check buffer.
+ * @ipr_cmd: ipr command struct
+ *
+ * Description: This function will call to get the unit check buffer.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+ ENTER;
+ ioa_cfg->ioa_unit_checked = 0;
+ ipr_get_unit_check_buffer(ioa_cfg);
+ ipr_cmd->job_step = ipr_reset_alert;
+ ipr_reset_start_timer(ipr_cmd, 0);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
+/**
* ipr_reset_restore_cfg_space - Restore PCI config space.
* @ipr_cmd: ipr command struct
*
@@ -7485,16 +7515,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
volatile u32 int_reg;
- int rc;
ENTER;
ioa_cfg->pdev->state_saved = true;
- rc = pci_restore_state(ioa_cfg->pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
- return IPR_RC_JOB_CONTINUE;
- }
+ pci_restore_state(ioa_cfg->pdev);
if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
@@ -7510,11 +7534,17 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
}
if (ioa_cfg->ioa_unit_checked) {
- ioa_cfg->ioa_unit_checked = 0;
- ipr_get_unit_check_buffer(ioa_cfg);
- ipr_cmd->job_step = ipr_reset_alert;
- ipr_reset_start_timer(ipr_cmd, 0);
- return IPR_RC_JOB_RETURN;
+ if (ioa_cfg->sis64) {
+ ipr_cmd->job_step = ipr_reset_get_unit_check_job;
+ ipr_reset_start_timer(ipr_cmd, IPR_DUMP_DELAY_TIMEOUT);
+ return IPR_RC_JOB_RETURN;
+ } else {
+ ioa_cfg->ioa_unit_checked = 0;
+ ipr_get_unit_check_buffer(ioa_cfg);
+ ipr_cmd->job_step = ipr_reset_alert;
+ ipr_reset_start_timer(ipr_cmd, 0);
+ return IPR_RC_JOB_RETURN;
+ }
}
if (ioa_cfg->in_ioa_bringdown) {
@@ -9025,6 +9055,8 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B2, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index aa8bb2f2c6ee..13f425fb8851 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -82,6 +82,7 @@
#define IPR_SUBS_DEV_ID_57B4 0x033B
#define IPR_SUBS_DEV_ID_57B2 0x035F
+#define IPR_SUBS_DEV_ID_57C4 0x0354
#define IPR_SUBS_DEV_ID_57C6 0x0357
#define IPR_SUBS_DEV_ID_57CC 0x035C
@@ -217,6 +218,8 @@
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
#define IPR_DUMP_TIMEOUT (15 * HZ)
+#define IPR_DUMP_DELAY_SECONDS 4
+#define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ)
/*
* SCSI Literals
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index f83a116955f2..b2511acd39bd 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -232,7 +232,7 @@ static int ips_detect(struct scsi_host_template *);
static int ips_release(struct Scsi_Host *);
static int ips_eh_abort(struct scsi_cmnd *);
static int ips_eh_reset(struct scsi_cmnd *);
-static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
+static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
static const char *ips_info(struct Scsi_Host *);
static irqreturn_t do_ipsintr(int, void *);
static int ips_hainit(ips_ha_t *);
@@ -1046,7 +1046,7 @@ static int ips_eh_reset(struct scsi_cmnd *SC)
/* Linux obtains io_request_lock before calling this function */
/* */
/****************************************************************************/
-static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
+static int ips_queue_lck(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
{
ips_ha_t *ha;
ips_passthru_t *pt;
@@ -1137,6 +1137,8 @@ static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
return (0);
}
+static DEF_SCSI_QCMD(ips_queue)
+
/****************************************************************************/
/* */
/* Routine Name: ips_biosparam */
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 32f67c4b03fc..911b2736cafa 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -684,10 +684,9 @@ void fc_disc_stop(struct fc_lport *lport)
{
struct fc_disc *disc = &lport->disc;
- if (disc) {
+ if (disc->pending)
cancel_delayed_work_sync(&disc->disc_work);
- fc_disc_stop_rports(disc);
- }
+ fc_disc_stop_rports(disc);
}
/**
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index ec2a1aec2350..d21367d3305f 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -67,6 +67,11 @@ struct workqueue_struct *fc_exch_workqueue;
struct fc_exch_pool {
u16 next_index;
u16 total_exches;
+
+ /* two cache of free slot in exch array */
+ u16 left;
+ u16 right;
+
spinlock_t lock;
struct list_head ex_list;
};
@@ -108,7 +113,6 @@ struct fc_exch_mgr {
atomic_t non_bls_resp;
} stats;
};
-#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
/**
* struct fc_exch_mgr_anchor - primary structure for list of EMs
@@ -397,13 +401,23 @@ static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index,
static void fc_exch_delete(struct fc_exch *ep)
{
struct fc_exch_pool *pool;
+ u16 index;
pool = ep->pool;
spin_lock_bh(&pool->lock);
WARN_ON(pool->total_exches <= 0);
pool->total_exches--;
- fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order,
- NULL);
+
+ /* update cache of free slot */
+ index = (ep->xid - ep->em->min_xid) >> fc_cpu_order;
+ if (pool->left == FC_XID_UNKNOWN)
+ pool->left = index;
+ else if (pool->right == FC_XID_UNKNOWN)
+ pool->right = index;
+ else
+ pool->next_index = index;
+
+ fc_exch_ptr_set(pool, index, NULL);
list_del(&ep->ex_list);
spin_unlock_bh(&pool->lock);
fc_exch_release(ep); /* drop hold for exch in mp */
@@ -636,10 +650,13 @@ static void fc_exch_timeout(struct work_struct *work)
if (e_stat & ESB_ST_ABNORMAL)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
- if (!rc)
- fc_exch_delete(ep);
if (resp)
resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg);
+ if (!rc) {
+ /* delete the exchange if it's already being aborted */
+ fc_exch_delete(ep);
+ return;
+ }
fc_seq_exch_abort(sp, 2 * ep->r_a_tov);
goto done;
}
@@ -679,6 +696,19 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
pool = per_cpu_ptr(mp->pool, cpu);
spin_lock_bh(&pool->lock);
put_cpu();
+
+ /* peek cache of free slot */
+ if (pool->left != FC_XID_UNKNOWN) {
+ index = pool->left;
+ pool->left = FC_XID_UNKNOWN;
+ goto hit;
+ }
+ if (pool->right != FC_XID_UNKNOWN) {
+ index = pool->right;
+ pool->right = FC_XID_UNKNOWN;
+ goto hit;
+ }
+
index = pool->next_index;
/* allocate new exch from pool */
while (fc_exch_ptr_get(pool, index)) {
@@ -687,7 +717,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
goto err;
}
pool->next_index = index == mp->pool_max_index ? 0 : index + 1;
-
+hit:
fc_exch_hold(ep); /* hold for exch in mp */
spin_lock_init(&ep->ex_lock);
/*
@@ -1247,7 +1277,7 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
list_for_each_entry(ema, &lport->ema_list, ema_list)
if ((!ema->match || ema->match(fp)) &&
- fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE)
+ fc_seq_lookup_recip(lport, ema->mp, fp) == FC_RJT_NONE)
break;
return fr_seq(fp);
}
@@ -1343,7 +1373,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
}
if (ep->esb_stat & ESB_ST_COMPLETE) {
atomic_inc(&mp->stats.xid_not_found);
- goto out;
+ goto rel;
}
if (ep->rxid == FC_XID_UNKNOWN)
ep->rxid = ntohs(fh->fh_rx_id);
@@ -2181,6 +2211,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport,
goto free_mempool;
for_each_possible_cpu(cpu) {
pool = per_cpu_ptr(mp->pool, cpu);
+ pool->left = FC_XID_UNKNOWN;
+ pool->right = FC_XID_UNKNOWN;
spin_lock_init(&pool->lock);
INIT_LIST_HEAD(&pool->ex_list);
}
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index c797f6b48f05..5962d1a5a674 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -57,9 +57,11 @@ struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_READ (1 << 1)
#define FC_SRB_WRITE (1 << 0)
+/* constant added to e_d_tov timeout to get rec_tov value */
+#define REC_TOV_CONST 1
+
/*
- * The SCp.ptr should be tested and set under the host lock. NULL indicates
- * that the command has been retruned to the scsi layer.
+ * The SCp.ptr should be tested and set under the scsi_pkt_queue lock
*/
#define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr)
#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in)
@@ -97,7 +99,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
-static void fc_fcp_recovery(struct fc_fcp_pkt *);
+static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code);
static void fc_fcp_timeout(unsigned long);
static void fc_fcp_rec(struct fc_fcp_pkt *);
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
@@ -121,14 +123,13 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
#define FC_DATA_UNDRUN 7
#define FC_ERROR 8
#define FC_HRD_ERROR 9
-#define FC_CMD_RECOVERY 10
+#define FC_CRC_ERROR 10
+#define FC_TIMED_OUT 11
/*
* Error recovery timeout values.
*/
-#define FC_SCSI_ER_TIMEOUT (10 * HZ)
#define FC_SCSI_TM_TOV (10 * HZ)
-#define FC_SCSI_REC_TOV (2 * HZ)
#define FC_HOST_RESET_TIMEOUT (30 * HZ)
#define FC_CAN_QUEUE_PERIOD (60 * HZ)
@@ -439,6 +440,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
void *buf;
struct scatterlist *sg;
u32 nents;
+ u8 host_bcode = FC_COMPLETE;
fh = fc_frame_header_get(fp);
offset = ntohl(fh->fh_parm_offset);
@@ -447,13 +449,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
buf = fc_frame_payload_get(fp, 0);
/*
- * if this I/O is ddped then clear it
- * and initiate recovery since data
- * frames are expected to be placed
- * directly in that case.
+ * if this I/O is ddped then clear it and initiate recovery since data
+ * frames are expected to be placed directly in that case.
+ *
+ * Indicate error to scsi-ml because something went wrong with the
+ * ddp handling to get us here.
*/
if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
fc_fcp_ddp_done(fsp);
+ FC_FCP_DBG(fsp, "DDP I/O in fc_fcp_recv_data set ERROR\n");
+ host_bcode = FC_ERROR;
goto err;
}
if (offset + len > fsp->data_len) {
@@ -463,6 +468,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
goto crc_err;
FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
"data_len %x\n", len, offset, fsp->data_len);
+
+ /* Data is corrupted indicate scsi-ml should retry */
+ host_bcode = FC_DATA_OVRRUN;
goto err;
}
if (offset != fsp->xfer_len)
@@ -499,8 +507,10 @@ crc_err:
* If so, we need to retry the entire operation.
* Otherwise, ignore it.
*/
- if (fsp->state & FC_SRB_DISCONTIG)
+ if (fsp->state & FC_SRB_DISCONTIG) {
+ host_bcode = FC_CRC_ERROR;
goto err;
+ }
return;
}
}
@@ -518,7 +528,7 @@ crc_err:
fc_fcp_complete_locked(fsp);
return;
err:
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, host_bcode);
}
/**
@@ -963,7 +973,13 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
}
lport->tt.exch_done(seq);
}
- fc_io_compl(fsp);
+ /*
+ * Some resets driven by SCSI are not I/Os and do not have
+ * SCSI commands associated with the requests. We should not
+ * call I/O completion if we do not have a SCSI command.
+ */
+ if (fsp->cmd)
+ fc_io_compl(fsp);
}
/**
@@ -1074,6 +1090,21 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
}
/**
+ * get_fsp_rec_tov() - Helper function to get REC_TOV
+ * @fsp: the FCP packet
+ */
+static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp)
+{
+ struct fc_rport *rport;
+ struct fc_rport_libfc_priv *rpriv;
+
+ rport = fsp->rport;
+ rpriv = rport->dd_data;
+
+ return rpriv->e_d_tov + REC_TOV_CONST;
+}
+
+/**
* fc_fcp_cmd_send() - Send a FCP command
* @lport: The local port to send the command on
* @fsp: The FCP packet the command is on
@@ -1090,6 +1121,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
struct fc_rport_libfc_priv *rpriv;
const size_t len = sizeof(fsp->cdb_cmd);
int rc = 0;
+ unsigned int rec_tov;
if (fc_fcp_lock_pkt(fsp))
return 0;
@@ -1120,10 +1152,13 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
fsp->seq_ptr = seq;
fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */
+ rec_tov = get_fsp_rec_tov(fsp);
+
setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp);
- fc_fcp_timer_set(fsp,
- (fsp->tgt_flags & FC_RP_FLAGS_REC_SUPPORTED) ?
- FC_SCSI_REC_TOV : FC_SCSI_ER_TIMEOUT);
+
+ if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
+ fc_fcp_timer_set(fsp, rec_tov);
+
unlock:
fc_fcp_unlock_pkt(fsp);
return rc;
@@ -1198,13 +1233,16 @@ static void fc_lun_reset_send(unsigned long data)
{
struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
struct fc_lport *lport = fsp->lp;
+ unsigned int rec_tov;
+
if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) {
if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY)
return;
if (fc_fcp_lock_pkt(fsp))
return;
+ rec_tov = get_fsp_rec_tov(fsp);
setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp);
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, rec_tov);
fc_fcp_unlock_pkt(fsp);
}
}
@@ -1212,7 +1250,7 @@ static void fc_lun_reset_send(unsigned long data)
/**
* fc_lun_reset() - Send a LUN RESET command to a device
* and wait for the reply
- * @lport: The local port to sent the comand on
+ * @lport: The local port to sent the command on
* @fsp: The FCP packet that identifies the LUN to be reset
* @id: The SCSI command ID
* @lun: The LUN ID to be reset
@@ -1283,27 +1321,27 @@ static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg)
*
* scsi-eh will escalate for when either happens.
*/
- return;
+ goto out;
}
if (fc_fcp_lock_pkt(fsp))
- return;
+ goto out;
/*
* raced with eh timeout handler.
*/
- if (!fsp->seq_ptr || !fsp->wait_for_comp) {
- spin_unlock_bh(&fsp->scsi_pkt_lock);
- return;
- }
+ if (!fsp->seq_ptr || !fsp->wait_for_comp)
+ goto out_unlock;
fh = fc_frame_header_get(fp);
if (fh->fh_type != FC_TYPE_BLS)
fc_fcp_resp(fsp, fp);
fsp->seq_ptr = NULL;
fsp->lp->tt.exch_done(seq);
- fc_frame_free(fp);
+out_unlock:
fc_fcp_unlock_pkt(fsp);
+out:
+ fc_frame_free(fp);
}
/**
@@ -1342,13 +1380,10 @@ static void fc_fcp_timeout(unsigned long data)
if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
fc_fcp_rec(fsp);
- else if (time_after_eq(fsp->last_pkt_time + (FC_SCSI_ER_TIMEOUT / 2),
- jiffies))
- fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT);
else if (fsp->state & FC_SRB_RCV_STATUS)
fc_fcp_complete_locked(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
unlock:
fc_fcp_unlock_pkt(fsp);
@@ -1374,6 +1409,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
fc_fcp_complete_locked(fsp);
return;
}
+
fp = fc_fcp_frame_alloc(lport, sizeof(struct fc_els_rec));
if (!fp)
goto retry;
@@ -1384,15 +1420,15 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
FC_FCTL_REQ, 0);
if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
fc_fcp_rec_resp, fsp,
- jiffies_to_msecs(FC_SCSI_REC_TOV))) {
+ 2 * lport->r_a_tov)) {
fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */
return;
}
retry:
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
}
/**
@@ -1446,7 +1482,6 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
* making progress.
*/
rpriv->flags &= ~FC_RP_FLAGS_REC_SUPPORTED;
- fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT);
break;
case ELS_RJT_LOGIC:
case ELS_RJT_UNAB:
@@ -1461,7 +1496,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
fc_fcp_retry_cmd(fsp);
break;
}
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
} else if (opcode == ELS_LS_ACC) {
@@ -1499,12 +1534,12 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
}
fc_fcp_srr(fsp, r_ctl, offset);
} else if (e_stat & ESB_ST_SEQ_INIT) {
-
+ unsigned int rec_tov = get_fsp_rec_tov(fsp);
/*
* The remote port has the initiative, so just
* keep waiting for it to complete.
*/
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ fc_fcp_timer_set(fsp, rec_tov);
} else {
/*
@@ -1576,7 +1611,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
fc_fcp_unlock_pkt(fsp);
@@ -1588,9 +1623,9 @@ out:
* fc_fcp_recovery() - Handler for fcp_pkt recovery
* @fsp: The FCP pkt that needs to be aborted
*/
-static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)
+static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code)
{
- fsp->status_code = FC_CMD_RECOVERY;
+ fsp->status_code = code;
fsp->cdb_status = 0;
fsp->io_status = 0;
/*
@@ -1617,6 +1652,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
struct fcp_srr *srr;
struct fc_frame *fp;
u8 cdb_op;
+ unsigned int rec_tov;
rport = fsp->rport;
rpriv = rport->dd_data;
@@ -1641,8 +1677,9 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
rpriv->local_port->port_id, FC_TYPE_FCP,
FC_FCTL_REQ, 0);
+ rec_tov = get_fsp_rec_tov(fsp);
seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
+ fsp, jiffies_to_msecs(rec_tov));
if (!seq)
goto retry;
@@ -1666,6 +1703,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
struct fc_fcp_pkt *fsp = arg;
struct fc_frame_header *fh;
+ unsigned int rec_tov;
if (IS_ERR(fp)) {
fc_fcp_srr_error(fsp, fp);
@@ -1692,11 +1730,12 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
switch (fc_frame_payload_op(fp)) {
case ELS_LS_ACC:
fsp->recov_retry = 0;
- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
+ rec_tov = get_fsp_rec_tov(fsp);
+ fc_fcp_timer_set(fsp, rec_tov);
break;
case ELS_LS_RJT:
default:
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_ERROR);
break;
}
fc_fcp_unlock_pkt(fsp);
@@ -1722,7 +1761,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp);
else
- fc_fcp_recovery(fsp);
+ fc_fcp_recovery(fsp, FC_TIMED_OUT);
break;
case -FC_EX_CLOSED: /* e.g., link failure */
/* fall through */
@@ -1754,7 +1793,7 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport)
* This is the i/o strategy routine, called by the SCSI layer. This routine
* is called with the host_lock held.
*/
-int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
+static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
{
struct fc_lport *lport;
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
@@ -1821,19 +1860,17 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
fsp->req_flags = FC_SRB_READ;
stats->InputRequests++;
- stats->InputMegabytes = fsp->data_len;
+ stats->InputBytes += fsp->data_len;
} else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
fsp->req_flags = FC_SRB_WRITE;
stats->OutputRequests++;
- stats->OutputMegabytes = fsp->data_len;
+ stats->OutputBytes += fsp->data_len;
} else {
fsp->req_flags = 0;
stats->ControlRequests++;
}
put_cpu();
- fsp->tgt_flags = rpriv->flags;
-
init_timer(&fsp->timer);
fsp->timer.data = (unsigned long)fsp;
@@ -1852,6 +1889,8 @@ out:
spin_lock_irq(lport->host->host_lock);
return rc;
}
+
+DEF_SCSI_QCMD(fc_queuecommand)
EXPORT_SYMBOL(fc_queuecommand);
/**
@@ -1880,8 +1919,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
lport = fsp->lp;
si = fc_get_scsi_internal(lport);
- if (!fsp->cmd)
- return;
/*
* if can_queue ramp down is done then try can_queue ramp up
@@ -1891,11 +1928,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
fc_fcp_can_queue_ramp_up(lport);
sc_cmd = fsp->cmd;
- fsp->cmd = NULL;
-
- if (!sc_cmd->SCp.ptr)
- return;
-
CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status;
switch (fsp->status_code) {
case FC_COMPLETE:
@@ -1952,18 +1984,29 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
break;
case FC_CMD_ABORTED:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
- "due to FC_CMD_ABORTED\n");
+ "due to FC_CMD_ABORTED\n");
sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
break;
- case FC_CMD_RECOVERY:
- sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
- break;
case FC_CMD_RESET:
+ FC_FCP_DBG(fsp, "Returning DID_RESET to scsi-ml "
+ "due to FC_CMD_RESET\n");
sc_cmd->result = (DID_RESET << 16);
break;
case FC_HRD_ERROR:
+ FC_FCP_DBG(fsp, "Returning DID_NO_CONNECT to scsi-ml "
+ "due to FC_HRD_ERROR\n");
sc_cmd->result = (DID_NO_CONNECT << 16);
break;
+ case FC_CRC_ERROR:
+ FC_FCP_DBG(fsp, "Returning DID_PARITY to scsi-ml "
+ "due to FC_CRC_ERROR\n");
+ sc_cmd->result = (DID_PARITY << 16);
+ break;
+ case FC_TIMED_OUT:
+ FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml "
+ "due to FC_TIMED_OUT\n");
+ sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
+ break;
default:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
"due to unknown error\n");
@@ -1971,15 +2014,13 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
break;
}
- if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) {
- sc_cmd->result = (DID_REQUEUE << 16);
- FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
- }
+ if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE)
+ sc_cmd->result = (DID_TRANSPORT_DISRUPTED << 16);
spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list);
- spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->SCp.ptr = NULL;
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->scsi_done(sc_cmd);
/* release ref from initial allocation in queue command */
@@ -1997,6 +2038,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
{
struct fc_fcp_pkt *fsp;
struct fc_lport *lport;
+ struct fc_fcp_internal *si;
int rc = FAILED;
unsigned long flags;
@@ -2006,16 +2048,17 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
else if (!lport->link_up)
return rc;
- spin_lock_irqsave(lport->host->host_lock, flags);
+ si = fc_get_scsi_internal(lport);
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
fsp = CMD_SP(sc_cmd);
if (!fsp) {
/* command completed while scsi eh was setting up */
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
return SUCCESS;
}
/* grab a ref so the fsp and sc_cmd cannot be relased from under us */
fc_fcp_pkt_hold(fsp);
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
if (fc_fcp_lock_pkt(fsp)) {
/* completed while we were waiting for timer to be deleted */
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index 16d2162dda1f..eea0c3541b71 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -66,9 +66,21 @@ extern unsigned int fc_debug_logging;
#define FC_FCP_DBG(pkt, fmt, args...) \
FC_CHECK_LOGGING(FC_FCP_LOGGING, \
- printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \
+ { \
+ if ((pkt)->seq_ptr) { \
+ struct fc_exch *_ep = NULL; \
+ _ep = fc_seq_exch((pkt)->seq_ptr); \
+ printk(KERN_INFO "host%u: fcp: %6.6x: " \
+ "xid %04x-%04x: " fmt, \
(pkt)->lp->host->host_no, \
- pkt->rport->port_id, ##args))
+ (pkt)->rport->port_id, \
+ (_ep)->oxid, (_ep)->rxid, ##args); \
+ } else { \
+ printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \
+ (pkt)->lp->host->host_no, \
+ (pkt)->rport->port_id, ##args); \
+ } \
+ })
#define FC_EXCH_DBG(exch, fmt, args...) \
FC_CHECK_LOGGING(FC_EXCH_LOGGING, \
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index d9b6e11b0e88..c5a10f94f845 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -288,6 +288,8 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
struct fc_lport *lport = shost_priv(shost);
struct timespec v0, v1;
unsigned int cpu;
+ u64 fcp_in_bytes = 0;
+ u64 fcp_out_bytes = 0;
fcoe_stats = &lport->host_stats;
memset(fcoe_stats, 0, sizeof(struct fc_host_statistics));
@@ -310,10 +312,12 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
fcoe_stats->fcp_input_requests += stats->InputRequests;
fcoe_stats->fcp_output_requests += stats->OutputRequests;
fcoe_stats->fcp_control_requests += stats->ControlRequests;
- fcoe_stats->fcp_input_megabytes += stats->InputMegabytes;
- fcoe_stats->fcp_output_megabytes += stats->OutputMegabytes;
+ fcp_in_bytes += stats->InputBytes;
+ fcp_out_bytes += stats->OutputBytes;
fcoe_stats->link_failure_count += stats->LinkFailureCount;
}
+ fcoe_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);
+ fcoe_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);
fcoe_stats->lip_count = -1;
fcoe_stats->nos_count = -1;
fcoe_stats->loss_of_sync_count = -1;
@@ -1447,13 +1451,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
}
did = fc_frame_did(fp);
-
- if (!did) {
- FC_LPORT_DBG(lport, "Bad FLOGI response\n");
- goto out;
- }
-
- if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
+ if (fc_frame_payload_op(fp) == ELS_LS_ACC && did) {
flp = fc_frame_payload_get(fp, sizeof(*flp));
if (flp) {
mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1492,8 +1490,10 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
fc_lport_enter_dns(lport);
}
}
- } else
+ } else {
+ FC_LPORT_DBG(lport, "FLOGI RJT or bad response\n");
fc_lport_error(lport, fp);
+ }
out:
fc_frame_free(fp);
@@ -1707,8 +1707,10 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
info->sg = job->reply_payload.sg_list;
if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
- NULL, info, tov))
+ NULL, info, tov)) {
+ kfree(info);
return -ECOMM;
+ }
return 0;
}
@@ -1766,8 +1768,10 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
info->sg = job->reply_payload.sg_list;
if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp,
- NULL, info, tov))
+ NULL, info, tov)) {
+ kfree(info);
return -ECOMM;
+ }
return 0;
}
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index b9f2286fe0cb..a7175adab32d 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -196,9 +196,9 @@ static const char *fc_rport_state(struct fc_rport_priv *rdata)
void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
{
if (timeout)
- rport->dev_loss_tmo = timeout + 5;
+ rport->dev_loss_tmo = timeout;
else
- rport->dev_loss_tmo = 30;
+ rport->dev_loss_tmo = 1;
}
EXPORT_SYMBOL(fc_set_rport_loss_tmo);
@@ -652,7 +652,7 @@ void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
- return;
+ goto put;
mutex_lock(&rdata->rp_mutex);
@@ -689,6 +689,7 @@ out:
fc_frame_free(fp);
err:
mutex_unlock(&rdata->rp_mutex);
+put:
kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
return;
bad:
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 633e09036357..da8b61543ee4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -505,6 +505,7 @@ static void iscsi_free_task(struct iscsi_task *task)
struct iscsi_conn *conn = task->conn;
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = task->sc;
+ int oldstate = task->state;
ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
task->itt, task->state, task->sc);
@@ -525,10 +526,10 @@ static void iscsi_free_task(struct iscsi_task *task)
/* SCSI eh reuses commands to verify us */
sc->SCp.ptr = NULL;
/*
- * queue command may call this to free the task, but
- * not have setup the sc callback
+ * queue command may call this to free the task, so
+ * it will decide how to return sc to scsi-ml.
*/
- if (sc->scsi_done)
+ if (oldstate != ISCSI_TASK_REQUEUE_SCSIQ)
sc->scsi_done(sc);
}
}
@@ -539,11 +540,12 @@ void __iscsi_get_task(struct iscsi_task *task)
}
EXPORT_SYMBOL_GPL(__iscsi_get_task);
-static void __iscsi_put_task(struct iscsi_task *task)
+void __iscsi_put_task(struct iscsi_task *task)
{
if (atomic_dec_and_test(&task->refcount))
iscsi_free_task(task);
}
+EXPORT_SYMBOL_GPL(__iscsi_put_task);
void iscsi_put_task(struct iscsi_task *task)
{
@@ -571,7 +573,8 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
task->itt, task->state, task->sc);
if (task->state == ISCSI_TASK_COMPLETED ||
task->state == ISCSI_TASK_ABRT_TMF ||
- task->state == ISCSI_TASK_ABRT_SESS_RECOV)
+ task->state == ISCSI_TASK_ABRT_SESS_RECOV ||
+ task->state == ISCSI_TASK_REQUEUE_SCSIQ)
return;
WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
task->state = state;
@@ -1335,17 +1338,16 @@ void iscsi_session_failure(struct iscsi_session *session,
{
struct iscsi_conn *conn;
struct device *dev;
- unsigned long flags;
- spin_lock_irqsave(&session->lock, flags);
+ spin_lock_bh(&session->lock);
conn = session->leadconn;
if (session->state == ISCSI_STATE_TERMINATE || !conn) {
- spin_unlock_irqrestore(&session->lock, flags);
+ spin_unlock_bh(&session->lock);
return;
}
dev = get_device(&conn->cls_conn->dev);
- spin_unlock_irqrestore(&session->lock, flags);
+ spin_unlock_bh(&session->lock);
if (!dev)
return;
/*
@@ -1364,17 +1366,16 @@ EXPORT_SYMBOL_GPL(iscsi_session_failure);
void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
{
struct iscsi_session *session = conn->session;
- unsigned long flags;
- spin_lock_irqsave(&session->lock, flags);
+ spin_lock_bh(&session->lock);
if (session->state == ISCSI_STATE_FAILED) {
- spin_unlock_irqrestore(&session->lock, flags);
+ spin_unlock_bh(&session->lock);
return;
}
if (conn->stop_stage == 0)
session->state = ISCSI_STATE_FAILED;
- spin_unlock_irqrestore(&session->lock, flags);
+ spin_unlock_bh(&session->lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1599,27 +1600,23 @@ enum {
FAILURE_SESSION_NOT_READY,
};
-int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
{
struct iscsi_cls_session *cls_session;
- struct Scsi_Host *host;
struct iscsi_host *ihost;
int reason = 0;
struct iscsi_session *session;
struct iscsi_conn *conn;
struct iscsi_task *task = NULL;
- sc->scsi_done = done;
sc->result = 0;
sc->SCp.ptr = NULL;
- host = sc->device->host;
ihost = shost_priv(host);
- spin_unlock(host->host_lock);
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock(&session->lock);
+ spin_lock_bh(&session->lock);
reason = iscsi_session_chkready(cls_session);
if (reason) {
@@ -1705,25 +1702,21 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
}
session->queued_cmdsn++;
- spin_unlock(&session->lock);
- spin_lock(host->host_lock);
+ spin_unlock_bh(&session->lock);
return 0;
prepd_reject:
- sc->scsi_done = NULL;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+ iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
reject:
- spin_unlock(&session->lock);
+ spin_unlock_bh(&session->lock);
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
sc->cmnd[0], reason);
- spin_lock(host->host_lock);
return SCSI_MLQUEUE_TARGET_BUSY;
prepd_fault:
- sc->scsi_done = NULL;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+ iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
fault:
- spin_unlock(&session->lock);
+ spin_unlock_bh(&session->lock);
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
sc->cmnd[0], reason);
if (!scsi_bidi_cmnd(sc))
@@ -1732,8 +1725,7 @@ fault:
scsi_out(sc)->resid = scsi_out(sc)->length;
scsi_in(sc)->resid = scsi_in(sc)->length;
}
- done(sc);
- spin_lock(host->host_lock);
+ sc->scsi_done(sc);
return 0;
}
EXPORT_SYMBOL_GPL(iscsi_queuecommand);
@@ -1793,9 +1785,9 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
NULL, 0);
if (!task) {
spin_unlock_bh(&session->lock);
+ iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
spin_lock_bh(&session->lock);
- ISCSI_DBG_EH(session, "tmf exec failure\n");
return -EPERM;
}
conn->tmfcmd_pdus_cnt++;
@@ -2200,7 +2192,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto success_unlocked;
case TMF_TIMEDOUT:
spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
case TMF_NOT_FOUND:
if (!sc->SCp.ptr) {
@@ -2287,7 +2279,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
break;
case TMF_TIMEDOUT:
spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
conn->tmf_state = TMF_INITIAL;
@@ -2368,7 +2360,7 @@ failed:
* we drop the lock here but the leadconn cannot be destoyed while
* we are in the scsi eh
*/
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
ISCSI_DBG_EH(session, "wait for relogin\n");
wait_event_interruptible(conn->ehwait,
@@ -2450,7 +2442,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
break;
case TMF_TIMEDOUT:
spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
conn->tmf_state = TMF_INITIAL;
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index fe8b74c706d2..5257fdfe699a 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -28,6 +28,17 @@
#include <scsi/scsi_transport_sas.h>
#include "../scsi_sas_internal.h"
+static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy)
+{
+ struct sas_ha_struct *sas_ha = phy->ha;
+
+ if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports &&
+ memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0))
+ return false;
+ return true;
+}
+
/**
* sas_form_port -- add this phy to a port
* @phy: the phy of interest
@@ -45,8 +56,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
unsigned long flags;
if (port) {
- if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
- SAS_ADDR_SIZE) != 0)
+ if (!phy_is_wideport_member(port, phy))
sas_deform_port(phy);
else {
SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
@@ -62,9 +72,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
port = sas_ha->sas_port[i];
spin_lock(&port->phy_list_lock);
if (*(u64 *) port->sas_addr &&
- memcmp(port->attached_sas_addr,
- phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
- port->num_phys > 0) {
+ phy_is_wideport_member(port, phy) && port->num_phys > 0) {
/* wide port */
SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
port->id);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 55f09e92ab59..5815cbeb27a6 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -189,7 +189,7 @@ int sas_queue_up(struct sas_task *task)
* Note: XXX: Remove the host unlock/lock pair when SCSI Core can
* call us without holding an IRQ spinlock...
*/
-int sas_queuecommand(struct scsi_cmnd *cmd,
+static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
void (*scsi_done)(struct scsi_cmnd *))
__releases(host->host_lock)
__acquires(dev->sata_dev.ap->lock)
@@ -211,8 +211,7 @@ int sas_queuecommand(struct scsi_cmnd *cmd,
unsigned long flags;
spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
- res = ata_sas_queuecmd(cmd, scsi_done,
- dev->sata_dev.ap);
+ res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
goto out;
}
@@ -254,6 +253,8 @@ out:
return res;
}
+DEF_SCSI_QCMD(sas_queuecommand)
+
static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
{
struct sas_task *task = TO_SAS_TASK(cmd);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index a50aa03b8ac1..746dd3d7a092 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -202,9 +202,12 @@ struct lpfc_stats {
uint32_t elsRcvPRLO;
uint32_t elsRcvPRLI;
uint32_t elsRcvLIRR;
+ uint32_t elsRcvRLS;
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
uint32_t elsRcvRRQ;
+ uint32_t elsRcvRTV;
+ uint32_t elsRcvECHO;
uint32_t elsXmitFLOGI;
uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
@@ -461,12 +464,29 @@ struct unsol_rcv_ct_ctx {
#define UNSOL_VALID 0x00000001
};
+#define LPFC_USER_LINK_SPEED_AUTO 0 /* auto select (default)*/
+#define LPFC_USER_LINK_SPEED_1G 1 /* 1 Gigabaud */
+#define LPFC_USER_LINK_SPEED_2G 2 /* 2 Gigabaud */
+#define LPFC_USER_LINK_SPEED_4G 4 /* 4 Gigabaud */
+#define LPFC_USER_LINK_SPEED_8G 8 /* 8 Gigabaud */
+#define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */
+#define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */
+#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_16G
+#define LPFC_USER_LINK_SPEED_BITMAP ((1 << LPFC_USER_LINK_SPEED_16G) | \
+ (1 << LPFC_USER_LINK_SPEED_10G) | \
+ (1 << LPFC_USER_LINK_SPEED_8G) | \
+ (1 << LPFC_USER_LINK_SPEED_4G) | \
+ (1 << LPFC_USER_LINK_SPEED_2G) | \
+ (1 << LPFC_USER_LINK_SPEED_1G) | \
+ (1 << LPFC_USER_LINK_SPEED_AUTO))
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16"
+
struct lpfc_hba {
/* SCSI interface function jump table entries */
int (*lpfc_new_scsi_buf)
(struct lpfc_vport *, int);
struct lpfc_scsi_buf * (*lpfc_get_scsi_buf)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, struct lpfc_nodelist *);
int (*lpfc_scsi_prep_dma_buf)
(struct lpfc_hba *, struct lpfc_scsi_buf *);
void (*lpfc_scsi_unprep_dma_buf)
@@ -542,16 +562,19 @@ struct lpfc_hba {
uint32_t hba_flag; /* hba generic flags */
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */
#define DEFER_ERATT 0x2 /* Deferred error attention in progress */
-#define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */
+#define HBA_FCOE_MODE 0x4 /* HBA function in FCoE Mode */
#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/
#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
#define FCP_XRI_ABORT_EVENT 0x20
#define ELS_XRI_ABORT_EVENT 0x40
#define ASYNC_EVENT 0x80
#define LINK_DISABLED 0x100 /* Link disabled by user */
-#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
-#define HBA_FIP_SUPPORT 0x400 /* FIP support in HBA */
-#define HBA_AER_ENABLED 0x800 /* AER enabled with HBA */
+#define FCF_TS_INPROG 0x200 /* FCF table scan in progress */
+#define FCF_RR_INPROG 0x400 /* FCF roundrobin flogi in progress */
+#define HBA_FIP_SUPPORT 0x800 /* FIP support in HBA */
+#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */
+#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */
+#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
struct lpfc_dmabuf slim2p;
@@ -573,6 +596,7 @@ struct lpfc_hba {
/* These fields used to be binfo */
uint32_t fc_pref_DID; /* preferred D_ID */
uint8_t fc_pref_ALPA; /* preferred AL_PA */
+ uint32_t fc_edtovResol; /* E_D_TOV timer resolution */
uint32_t fc_edtov; /* E_D_TOV timer value */
uint32_t fc_arbtov; /* ARB_TOV timer value */
uint32_t fc_ratov; /* R_A_TOV timer value */
@@ -600,6 +624,7 @@ struct lpfc_hba {
/* HBA Config Parameters */
uint32_t cfg_ack0;
uint32_t cfg_enable_npiv;
+ uint32_t cfg_enable_rrq;
uint32_t cfg_topology;
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
@@ -710,6 +735,7 @@ struct lpfc_hba {
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
+ struct list_head active_rrq_list;
spinlock_t hbalock;
/* pci_mem_pools */
@@ -722,6 +748,7 @@ struct lpfc_hba {
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
+ mempool_t *rrq_pool;
struct fc_host_statistics link_stats;
enum intr_type_t intr_type;
@@ -778,6 +805,7 @@ struct lpfc_hba {
unsigned long skipped_hb;
struct timer_list hb_tmofunc;
uint8_t hb_outstanding;
+ struct timer_list rrq_tmr;
enum hba_temp_state over_temp_state;
/* ndlp reference management */
spinlock_t ndlp_lock;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f681eea57730..3512abb8a587 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -52,10 +52,6 @@
#define LPFC_MIN_DEVLOSS_TMO 1
#define LPFC_MAX_DEVLOSS_TMO 255
-#define LPFC_MAX_LINK_SPEED 8
-#define LPFC_LINK_SPEED_BITMAP 0x00000117
-#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
-
/**
* lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
* @incr: integer to convert.
@@ -463,7 +459,7 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
len += snprintf(buf + len, PAGE_SIZE-len,
" Menlo Maint Mode\n");
- else if (phba->fc_topology == TOPOLOGY_LOOP) {
+ else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (vport->fc_flag & FC_PUBLIC_LOOP)
len += snprintf(buf + len, PAGE_SIZE-len,
" Public Loop\n");
@@ -1339,7 +1335,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
}
/**
- * lpfc_param_init - Intializes a cfg attribute
+ * lpfc_param_init - Initializes a cfg attribute
*
* Description:
* Macro that given an attr e.g. hba_queue_depth expands
@@ -1981,6 +1977,13 @@ lpfc_param_show(enable_npiv);
lpfc_param_init(enable_npiv, 1, 0, 1);
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
+int lpfc_enable_rrq;
+module_param(lpfc_enable_rrq, int, 0);
+MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
+lpfc_param_show(enable_rrq);
+lpfc_param_init(enable_rrq, 0, 0, 1);
+static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL);
+
/*
# lpfc_suppress_link_up: Bring link up at initialization
# 0x0 = bring link up (issue MBX_INIT_LINK)
@@ -2837,14 +2840,8 @@ static struct bin_attribute sysfs_drvr_stat_data_attr = {
/*
# lpfc_link_speed: Link speed selection for initializing the Fibre Channel
# connection.
-# 0 = auto select (default)
-# 1 = 1 Gigabaud
-# 2 = 2 Gigabaud
-# 4 = 4 Gigabaud
-# 8 = 8 Gigabaud
-# Value range is [0,8]. Default value is 0.
+# Value range is [0,16]. Default value is 0.
*/
-
/**
* lpfc_link_speed_set - Set the adapters link speed
* @phba: lpfc_hba pointer.
@@ -2869,7 +2866,7 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- int val = 0;
+ int val = LPFC_USER_LINK_SPEED_AUTO;
int nolip = 0;
const char *val_buf = buf;
int err;
@@ -2885,15 +2882,20 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
if (sscanf(val_buf, "%i", &val) != 1)
return -EINVAL;
- if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
- ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
- ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
- ((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
- ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
+ if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb))) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2879 lpfc_link_speed attribute cannot be set "
+ "to %d. Speed is not supported by this port.\n",
+ val);
return -EINVAL;
-
- if ((val >= 0 && val <= 8)
- && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+ }
+ if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
+ (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
prev_val = phba->cfg_link_speed;
phba->cfg_link_speed = val;
if (nolip)
@@ -2906,11 +2908,9 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
} else
return strlen(buf);
}
-
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0469 lpfc_link_speed attribute cannot be set to %d, "
- "allowed range is [0, 8]\n",
- phba->brd_no, val);
+ "0469 lpfc_link_speed attribute cannot be set to %d, "
+ "allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val);
return -EINVAL;
}
@@ -2938,8 +2938,8 @@ lpfc_param_show(link_speed)
static int
lpfc_link_speed_init(struct lpfc_hba *phba, int val)
{
- if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
- && (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+ if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
+ (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
phba->cfg_link_speed = val;
return 0;
}
@@ -2947,12 +2947,12 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val)
"0405 lpfc_link_speed attribute cannot "
"be set to %d, allowed values are "
"["LPFC_LINK_SPEED_STRING"]\n", val);
- phba->cfg_link_speed = 0;
+ phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
return -EINVAL;
}
static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
- lpfc_link_speed_show, lpfc_link_speed_store);
+ lpfc_link_speed_show, lpfc_link_speed_store);
/*
# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER)
@@ -3305,12 +3305,12 @@ LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX,
LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
/*
-# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
+# lpfc_enable_hba_heartbeat: Disable HBA heartbeat timer..
# 0 = HBA Heartbeat disabled
# 1 = HBA Heartbeat enabled (default)
# Value range is [0,1]. Default value is 1.
*/
-LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
+LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat.");
/*
# lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF)
@@ -3401,6 +3401,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
+ &dev_attr_lpfc_enable_rrq,
&dev_attr_nport_evt_cnt,
&dev_attr_board_mode,
&dev_attr_max_vpi,
@@ -3789,12 +3790,16 @@ sysfs_mbox_read(struct file *filp, struct kobject *kobj,
break;
case MBX_SECURITY_MGMT:
case MBX_AUTH_PORT:
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+ printk(KERN_WARNING "mbox_read:Command 0x%x "
+ "is not permitted\n", pmb->mbxCommand);
+ sysfs_mbox_idle(phba);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
+ }
break;
case MBX_READ_SPARM64:
- case MBX_READ_LA:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_REG_LOGIN:
case MBX_REG_LOGIN64:
case MBX_CONFIG_PORT:
@@ -3984,7 +3989,7 @@ lpfc_get_host_port_type(struct Scsi_Host *shost)
if (vport->port_type == LPFC_NPIV_PORT) {
fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
} else if (lpfc_is_link_up(phba)) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (vport->fc_flag & FC_PUBLIC_LOOP)
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
else
@@ -4053,23 +4058,26 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
if (lpfc_is_link_up(phba)) {
switch(phba->fc_linkspeed) {
- case LA_1GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+ case LPFC_LINK_SPEED_1GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
break;
- case LA_2GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
+ case LPFC_LINK_SPEED_4GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
break;
- case LA_4GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
+ case LPFC_LINK_SPEED_8GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
break;
- case LA_8GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+ case LPFC_LINK_SPEED_10GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
break;
- case LA_10GHZ_LINK:
- fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
+ case LPFC_LINK_SPEED_16GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_16GBIT;
break;
- default:
- fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ default:
+ fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break;
}
} else
@@ -4092,7 +4100,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
spin_lock_irq(shost->host_lock);
if ((vport->fc_flag & FC_FABRIC) ||
- ((phba->fc_topology == TOPOLOGY_LOOP) &&
+ ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
(vport->fc_flag & FC_PUBLIC_LOOP)))
node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
else
@@ -4203,11 +4211,11 @@ lpfc_get_stats(struct Scsi_Host *shost)
hs->invalid_crc_count -= lso->invalid_crc_count;
hs->error_frames -= lso->error_frames;
- if (phba->hba_flag & HBA_FCOE_SUPPORT) {
+ if (phba->hba_flag & HBA_FCOE_MODE) {
hs->lip_count = -1;
hs->nos_count = (phba->link_events >> 1);
hs->nos_count -= lso->link_events;
- } else if (phba->fc_topology == TOPOLOGY_LOOP) {
+ } else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
hs->lip_count -= lso->link_events;
hs->nos_count = -1;
@@ -4298,7 +4306,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
lso->error_frames = pmb->un.varRdLnk.crcCnt;
- if (phba->hba_flag & HBA_FCOE_SUPPORT)
+ if (phba->hba_flag & HBA_FCOE_MODE)
lso->link_events = (phba->link_events >> 1);
else
lso->link_events = (phba->fc_eventTag >> 1);
@@ -4610,6 +4618,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
+ lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index f5d60b55f53a..0dd43bb91618 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -162,7 +162,6 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocbq,
struct lpfc_iocbq *rspiocbq)
{
- unsigned long iflags;
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
@@ -173,9 +172,10 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
int rc = 0;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context2;
if (!dd_data) {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
return;
}
@@ -183,17 +183,9 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
job = iocb->set_job;
job->dd_data = NULL; /* so timeout handler does not reply */
- spin_lock_irqsave(&phba->hbalock, iflags);
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
- spin_unlock_irqrestore(&phba->hbalock, iflags);
-
bmp = iocb->bmp;
- rspiocbq = iocb->rspiocbq;
rsp = &rspiocbq->iocb;
- ndlp = iocb->ndlp;
+ ndlp = cmdiocbq->context1;
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -220,7 +212,6 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
rsp->un.genreq64.bdl.bdeSize;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
kfree(bmp);
@@ -247,9 +238,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
struct ulp_bde64 *bpl = NULL;
uint32_t timeout;
struct lpfc_iocbq *cmdiocbq = NULL;
- struct lpfc_iocbq *rspiocbq = NULL;
IOCB_t *cmd;
- IOCB_t *rsp;
struct lpfc_dmabuf *bmp = NULL;
int request_nseg;
int reply_nseg;
@@ -296,17 +285,10 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
}
cmd = &cmdiocbq->iocb;
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- rc = -ENOMEM;
- goto free_cmdiocbq;
- }
-
- rsp = &rspiocbq->iocb;
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
- goto free_rspiocbq;
+ goto free_cmdiocbq;
}
INIT_LIST_HEAD(&bmp->list);
@@ -358,14 +340,12 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
cmd->ulpTimeout = timeout;
cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
- cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->context1 = ndlp;
+ cmdiocbq->context2 = dd_data;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.rspiocbq = rspiocbq;
dd_data->context_un.iocb.set_job = job;
dd_data->context_un.iocb.bmp = bmp;
- dd_data->context_un.iocb.ndlp = ndlp;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
creg_val = readl(phba->HCregaddr);
@@ -391,8 +371,6 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
free_bmp:
@@ -1220,7 +1198,7 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
int rc = 0;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context2;
/* normal completion and timeout crossed paths, already done */
if (!dd_data) {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
@@ -1369,8 +1347,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
ctiocb->context3 = bmp;
ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
- ctiocb->context1 = dd_data;
- ctiocb->context2 = NULL;
+ ctiocb->context2 = dd_data;
+ ctiocb->context1 = ndlp;
dd_data->type = TYPE_IOCB;
dd_data->context_un.iocb.cmdiocbq = ctiocb;
dd_data->context_un.iocb.rspiocbq = NULL;
@@ -1641,7 +1619,7 @@ job_error:
* This function obtains a remote port login id so the diag loopback test
* can send and receive its own unsolicited CT command.
**/
-static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi)
+static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
{
LPFC_MBOXQ_t *mbox;
struct lpfc_dmabuf *dmabuff;
@@ -1651,10 +1629,14 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi)
if (!mbox)
return -ENOMEM;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ *rpi = lpfc_sli4_alloc_rpi(phba);
status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
- (uint8_t *)&phba->pport->fc_sparam, mbox, 0);
+ (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi);
if (status) {
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, *rpi);
return -ENOMEM;
}
@@ -1668,6 +1650,8 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi)
kfree(dmabuff);
if (status != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, *rpi);
return -ENODEV;
}
@@ -1704,8 +1688,9 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
mempool_free(mbox, phba->mbox_mem_pool);
return -EIO;
}
-
mempool_free(mbox, phba->mbox_mem_pool);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, rpi);
return 0;
}
@@ -2102,7 +2087,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
uint32_t size;
uint32_t full_size;
size_t segment_len = 0, segment_offset = 0, current_offset = 0;
- uint16_t rpi;
+ uint16_t rpi = 0;
struct lpfc_iocbq *cmdiocbq, *rspiocbq;
IOCB_t *cmd, *rsp;
struct lpfc_sli_ct_request *ctreq;
@@ -2162,7 +2147,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
goto loopback_test_exit;
}
- if (size >= BUF_SZ_4K) {
+ if (full_size >= BUF_SZ_4K) {
/*
* Allocate memory for ioctl data. If buffer is bigger than 64k,
* then we allocate 64k and re-use that buffer over and over to
@@ -2171,7 +2156,7 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
* problem with GET_FCPTARGETMAPPING...
*/
if (size <= (64 * 1024))
- total_mem = size;
+ total_mem = full_size;
else
total_mem = 64 * 1024;
} else
@@ -2189,7 +2174,6 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
sg_copy_to_buffer(job->request_payload.sg_list,
job->request_payload.sg_cnt,
ptr, size);
-
rc = lpfcdiag_loop_self_reg(phba, &rpi);
if (rc)
goto loopback_test_exit;
@@ -2601,12 +2585,11 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
phba->wait_4_mlo_maint_flg = 1;
} else if (mb->un.varWords[0] == SETVAR_MLORST) {
phba->link_flag &= ~LS_LOOPBACK_MODE;
- phba->fc_topology = TOPOLOGY_PT_PT;
+ phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
}
break;
case MBX_READ_SPARM64:
- case MBX_READ_LA:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_REG_LOGIN:
case MBX_REG_LOGIN64:
case MBX_CONFIG_PORT:
@@ -3142,12 +3125,12 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
job = menlo->set_job;
job->dd_data = NULL; /* so timeout handler does not reply */
- spin_lock_irqsave(&phba->hbalock, flags);
+ spin_lock(&phba->hbalock);
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
if (cmdiocbq->context2 && rspiocbq)
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
&rspiocbq->iocb, sizeof(IOCB_t));
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock(&phba->hbalock);
bmp = menlo->bmp;
rspiocbq = menlo->rspiocbq;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 03f4ddc18572..17fde522c84a 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -31,7 +31,7 @@ void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *);
+int lpfc_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_issue_clear_la(struct lpfc_hba *, struct lpfc_vport *);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -40,10 +40,12 @@ int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
- LPFC_MBOXQ_t *, uint32_t);
+ LPFC_MBOXQ_t *, uint16_t);
void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_sli4_unreg_all_rpis(struct lpfc_vport *);
+
void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
struct lpfc_nodelist *);
@@ -62,7 +64,7 @@ void lpfc_cleanup_pending_mbox(struct lpfc_vport *);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
void lpfc_port_link_failure(struct lpfc_vport *);
-void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);
@@ -119,6 +121,7 @@ void lpfc_end_rscn(struct lpfc_vport *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *);
+void lpfc_issue_init_vfi(struct lpfc_vport *);
int lpfc_initial_fdisc(struct lpfc_vport *);
int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
@@ -229,6 +232,7 @@ void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
int lpfc_mem_alloc(struct lpfc_hba *, int align);
void lpfc_mem_free(struct lpfc_hba *);
@@ -271,6 +275,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
void lpfc_sli_bemem_bcopy(void *, void *, uint32_t);
void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
+void lpfc_sli_hba_iocb_abort(struct lpfc_hba *);
void lpfc_sli_flush_fcp_rings(struct lpfc_hba *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *);
@@ -411,5 +416,13 @@ struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
uint32_t lpfc_drain_txq(struct lpfc_hba *);
-
-
+void lpfc_clr_rrq_active(struct lpfc_hba *, uint16_t, struct lpfc_node_rrq *);
+int lpfc_test_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, uint16_t);
+void lpfc_handle_rrq_active(struct lpfc_hba *);
+int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
+int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
+ uint16_t, uint16_t, uint16_t);
+void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
+void lpfc_cleanup_vports_rrqs(struct lpfc_vport *);
+struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
+ uint32_t);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 463b74902ac4..c004fa9a681e 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -48,14 +48,14 @@
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
- * incapable of reporting */
-#define HBA_PORTSPEED_1GBIT 1 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 2 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 8 /* 4 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 16 /* 8 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 4 /* 10 GBit/sec */
-#define HBA_PORTSPEED_NOT_NEGOTIATED 5 /* Speed not established */
+/* FDMI Port Speed definitions */
+#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
+#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
+#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
+#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
+#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
+#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
+#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
#define FOURBYTES 4
@@ -1593,8 +1593,10 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
ae->un.SupportSpeed = 0;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
+ ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
if (phba->lmt & LMT_8Gb)
ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
if (phba->lmt & LMT_4Gb)
@@ -1612,24 +1614,26 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
switch(phba->fc_linkspeed) {
- case LA_1GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
break;
- case LA_2GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
break;
- case LA_4GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
break;
- case LA_8GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
break;
- case LA_10GHZ_LINK:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
break;
- default:
- ae->un.PortSpeed =
- HBA_PORTSPEED_UNKNOWN;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
+ break;
+ default:
+ ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
break;
}
pab->ab.EntryCnt++;
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 7cae69de36f7..1d84b63fccad 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -68,6 +68,12 @@ struct lpfc_fast_path_event {
} un;
};
+#define LPFC_SLI4_MAX_XRI 1024 /* Used to make the ndlp's xri_bitmap */
+#define XRI_BITMAP_ULONGS (LPFC_SLI4_MAX_XRI / BITS_PER_LONG)
+struct lpfc_node_rrqs {
+ unsigned long xri_bitmap[XRI_BITMAP_ULONGS];
+};
+
struct lpfc_nodelist {
struct list_head nlp_listp;
struct lpfc_name nlp_portname;
@@ -110,8 +116,19 @@ struct lpfc_nodelist {
atomic_t cmd_pending;
uint32_t cmd_qdepth;
unsigned long last_change_time;
+ struct lpfc_node_rrqs active_rrqs;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
};
+struct lpfc_node_rrq {
+ struct list_head list;
+ uint16_t xritag;
+ uint16_t send_rrq;
+ uint16_t rxid;
+ uint32_t nlp_DID; /* FC D_ID of entry */
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ unsigned long rrq_stop_time;
+};
/* Defines for nlp_flag (uint32) */
#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
@@ -136,7 +153,7 @@ struct lpfc_nodelist {
#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
#define NLP_SC_REQ 0x20000000 /* Target requires authentication */
-#define NLP_RPI_VALID 0x80000000 /* nlp_rpi is valid */
+#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */
/* ndlp usage management macros */
#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index e6ca12f6c6cb..c62d567cc845 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -177,15 +177,18 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
(elscmd == ELS_CMD_LOGO)))
switch (elscmd) {
case ELS_CMD_FLOGI:
- elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+ elsiocb->iocb_flag |=
+ ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
& LPFC_FIP_ELS_ID_MASK);
break;
case ELS_CMD_FDISC:
- elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
+ elsiocb->iocb_flag |=
+ ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
& LPFC_FIP_ELS_ID_MASK);
break;
case ELS_CMD_LOGO:
- elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
+ elsiocb->iocb_flag |=
+ ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
& LPFC_FIP_ELS_ID_MASK);
break;
}
@@ -372,7 +375,8 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
err = 4;
goto fail;
}
- rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0);
+ rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ ndlp->nlp_rpi);
if (rc) {
err = 5;
goto fail_free_mbox;
@@ -517,18 +521,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
+ phba->fc_edtovResol = sp->cmn.edtovResolution;
phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
- } else {
- /*
- * If we are a N-port connected to a Fabric, fixup sparam's so
- * logins to devices on remote loops work.
- */
- vport->fc_sparam.cmn.altBbCredit = 1;
}
vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
@@ -585,6 +584,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_unreg_rpi(vport, np);
}
lpfc_cleanup_pending_mbox(vport);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
+
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
@@ -800,7 +803,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (irsp->ulpStatus) {
/*
- * In case of FIP mode, perform round robin FCF failover
+ * In case of FIP mode, perform roundrobin FCF failover
* due to new FCF discovery
*/
if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
@@ -808,48 +811,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
(irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
(irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
- "2611 FLOGI failed on registered "
- "FCF record fcf_index(%d), status: "
- "x%x/x%x, tmo:x%x, trying to perform "
- "round robin failover\n",
+ "2611 FLOGI failed on FCF (x%x), "
+ "status:x%x/x%x, tmo:x%x, perform "
+ "roundrobin FCF failover\n",
phba->fcf.current_rec.fcf_indx,
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout);
fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
- if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
- /*
- * Exhausted the eligible FCF record list,
- * fail through to retry FLOGI on current
- * FCF record.
- */
- lpfc_printf_log(phba, KERN_WARNING,
- LOG_FIP | LOG_ELS,
- "2760 Completed one round "
- "of FLOGI FCF round robin "
- "failover list, retry FLOGI "
- "on currently registered "
- "FCF index:%d\n",
- phba->fcf.current_rec.fcf_indx);
- } else {
- lpfc_printf_log(phba, KERN_INFO,
- LOG_FIP | LOG_ELS,
- "2794 FLOGI FCF round robin "
- "failover to FCF index x%x\n",
- fcf_index);
- rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
- fcf_index);
- if (rc)
- lpfc_printf_log(phba, KERN_WARNING,
- LOG_FIP | LOG_ELS,
- "2761 FLOGI round "
- "robin FCF failover "
- "read FCF failed "
- "rc:x%x, fcf_index:"
- "%d\n", rc,
- phba->fcf.current_rec.fcf_indx);
- else
- goto out;
- }
+ rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
+ if (rc)
+ goto out;
}
/* FLOGI failure */
@@ -862,6 +833,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
+ /* FLOGI failure */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout);
+
/* FLOGI failed, so there is no fabric */
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
@@ -873,13 +850,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
if (phba->alpa_map[0] == 0) {
vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (!(vport->fc_flag & FC_VFI_REGISTERED) ||
+ (vport->fc_prevDID != vport->fc_myDID))) {
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_sli4_unreg_all_rpis(vport);
+ lpfc_issue_reg_vfi(vport);
+ lpfc_nlp_put(ndlp);
+ goto out;
+ }
}
-
- /* FLOGI failure */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
- irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->ulpTimeout);
goto flogifail;
}
spin_lock_irq(shost->host_lock);
@@ -909,7 +889,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
+ else if (!(phba->hba_flag & HBA_FCOE_MODE))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
else {
lpfc_printf_vlog(vport, KERN_ERR,
@@ -939,6 +919,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_nlp_put(ndlp);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
spin_unlock_irq(&phba->hbalock);
goto out;
}
@@ -947,13 +928,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (phba->hba_flag & HBA_FIP_SUPPORT)
lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
LOG_ELS,
- "2769 FLOGI successful on FCF "
- "record: current_fcf_index:"
- "x%x, terminate FCF round "
- "robin failover process\n",
+ "2769 FLOGI to FCF (x%x) "
+ "completed successfully\n",
phba->fcf.current_rec.fcf_indx);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
spin_unlock_irq(&phba->hbalock);
goto out;
}
@@ -1044,7 +1024,9 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
- if (phba->sli_rev == LPFC_SLI_REV4) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)) {
elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1);
elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1);
/* FLOGI needs to be 3 for WQE FCFI */
@@ -1057,7 +1039,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
icmd->ulpCt_l = 0;
}
- if (phba->fc_topology != TOPOLOGY_LOOP) {
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
}
@@ -1175,12 +1157,13 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
return 0;
}
- if (lpfc_issue_els_flogi(vport, ndlp, 0))
+ if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
/* This decrement of reference count to node shall kick off
* the release of the node.
*/
lpfc_nlp_put(ndlp);
-
+ return 0;
+ }
return 1;
}
@@ -1310,6 +1293,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
uint32_t rc, keepDID = 0;
int put_node;
int put_rport;
+ struct lpfc_node_rrqs rrq;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
@@ -1327,6 +1311,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
return ndlp;
+ memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
if (!new_ndlp) {
rc = memcmp(&ndlp->nlp_portname, name,
@@ -1347,12 +1332,25 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (!new_ndlp)
return ndlp;
keepDID = new_ndlp->nlp_DID;
- } else
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ } else {
keepDID = new_ndlp->nlp_DID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ }
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(new_ndlp->active_rrqs.xri_bitmap,
+ &ndlp->active_rrqs.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
@@ -1391,12 +1389,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
/* Two ndlps cannot have the same did on the nodelist */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_drop_node(vport, ndlp);
}
else {
lpfc_unreg_rpi(vport, ndlp);
/* Two ndlps cannot have the same did */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
/* Since we are swapping the ndlp passed in with the new one
* and the did has already been swapped, copy over the
@@ -1457,6 +1463,73 @@ lpfc_end_rscn(struct lpfc_vport *vport)
}
/**
+ * lpfc_cmpl_els_rrq - Completion handled for els RRQs.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @rspiocb: pointer to lpfc response iocb data structure.
+ *
+ * This routine will call the clear rrq function to free the rrq and
+ * clear the xri's bit in the ndlp's xri_bitmap. If the ndlp does not
+ * exist then the clear_rrq is still called because the rrq needs to
+ * be freed.
+ **/
+
+static void
+lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_node_rrq *rrq;
+
+ /* we pass cmdiocb to state machine which needs rspiocb as well */
+ rrq = cmdiocb->context_un.rrq;
+ cmdiocb->context_un.rsp_iocb = rspiocb;
+
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "RRQ cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
+ ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2882 RRQ 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;
+ }
+
+ /* rrq completes to NPort <nlp_DID> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2880 RRQ 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, rrq->xritag, rrq->rxid);
+
+ if (irsp->ulpStatus) {
+ /* Check for retry */
+ /* RRQ failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2881 RRQ failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
+ }
+out:
+ if (rrq)
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ lpfc_els_free_iocb(phba, cmdiocb);
+ return;
+}
+/**
* lpfc_cmpl_els_plogi - Completion callback function for plogi
* @phba: pointer to lpfc hba data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
@@ -1645,6 +1718,13 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
+ /*
+ * If we are a N-port connected to a Fabric, fix-up paramm's so logins
+ * to device on remote loops work.
+ */
+ if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP))
+ sp->cmn.altBbCredit = 1;
+
if (sp->cmn.fcphLow < FC_PH_4_3)
sp->cmn.fcphLow = FC_PH_4_3;
@@ -2744,7 +2824,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (cmd == ELS_CMD_FLOGI) {
if (PCI_DEVICE_ID_HORNET ==
phba->pcidev->device) {
- phba->fc_topology = TOPOLOGY_LOOP;
+ phba->fc_topology = LPFC_TOPOLOGY_LOOP;
phba->pport->fc_myDID = 0;
phba->alpa_map[0] = 0;
phba->alpa_map[1] = 0;
@@ -2899,7 +2979,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
retry = 1;
if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
- (phba->fc_topology != TOPOLOGY_LOOP) &&
+ (phba->fc_topology != LPFC_TOPOLOGY_LOOP) &&
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
retry = 1;
@@ -3241,14 +3321,6 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
- /*
- * This routine is used to register and unregister in previous SLI
- * modes.
- */
- if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
- (phba->sli_rev == LPFC_SLI_REV4))
- lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
-
pmb->context1 = NULL;
pmb->context2 = NULL;
@@ -3926,6 +3998,105 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
}
/**
+ * lpfc_els_clear_rrq - Clear the rq that this rrq describes.
+ * @vport: pointer to a virtual N_Port data structure.
+ * @iocb: pointer to the lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return
+ **/
+static void
+lpfc_els_clear_rrq(struct lpfc_vport *vport,
+ struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ uint8_t *pcmd;
+ struct RRQ *rrq;
+ uint16_t rxid;
+ struct lpfc_node_rrq *prrq;
+
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt);
+ pcmd += sizeof(uint32_t);
+ rrq = (struct RRQ *)pcmd;
+ rxid = bf_get(rrq_oxid, rrq);
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x"
+ " x%x x%x\n",
+ bf_get(rrq_did, rrq),
+ bf_get(rrq_oxid, rrq),
+ rxid,
+ iocb->iotag, iocb->iocb.ulpContext);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Clear RRQ: did:x%x flg:x%x exchg:x%.08x",
+ ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg);
+ prrq = lpfc_get_active_rrq(vport, rxid, ndlp->nlp_DID);
+ if (prrq)
+ lpfc_clr_rrq_active(phba, rxid, prrq);
+ return;
+}
+
+/**
+ * lpfc_els_rsp_echo_acc - Issue echo acc response
+ * @vport: pointer to a virtual N_Port data structure.
+ * @data: pointer to echo data to return in the accept.
+ * @oldiocb: pointer to the original lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return code
+ * 0 - Successfully issued acc echo response
+ * 1 - Failed to issue acc echo response
+ **/
+static int
+lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_sli *psli;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int rc;
+
+ psli = &phba->sli;
+ cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len;
+
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+ if (!elsiocb)
+ return 1;
+
+ elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri */
+ /* Xmit ECHO ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2876 Xmit ECHO 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);
+ memcpy(pcmd, data, cmdsize - sizeof(uint32_t));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC ECHO: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ phba->fc_stat.elsXmitACC++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ lpfc_nlp_put(ndlp);
+ elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
+ * it could be freed */
+
+ rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+ if (rc == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+/**
* lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport
* @vport: pointer to a host virtual N_Port data structure.
*
@@ -4561,7 +4732,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
lpfc_set_disctmo(vport);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* We should never receive a FLOGI in loop mode, ignore it */
did = icmd->un.elsreq64.remoteID;
@@ -4684,6 +4855,30 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
}
/**
+ * lpfc_els_rcv_echo - Process an unsolicited echo iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return code
+ * 0 - Successfully processed echo iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ uint8_t *pcmd;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+
+ /* skip over first word of echo command to find echo data */
+ pcmd += sizeof(uint32_t);
+
+ lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp);
+ return 0;
+}
+
+/**
* lpfc_els_rcv_lirr - Process an unsolicited lirr iocb
* @vport: pointer to a host virtual N_Port data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
@@ -4732,6 +4927,91 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp)
{
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_els_clear_rrq(vport, cmdiocb, ndlp);
+}
+
+/**
+ * lpfc_els_rsp_rls_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
+ * @phba: pointer to lpfc hba data structure.
+ * @pmb: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine is the completion callback function for the MBX_READ_LNK_STAT
+ * mailbox command. This callback function is to actually send the Accept
+ * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It
+ * collects the link statistics from the completion of the MBX_READ_LNK_STAT
+ * mailbox command, constructs the RPS response with the link statistics
+ * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC
+ * response to the RPS.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ **/
+static void
+lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb;
+ IOCB_t *icmd;
+ struct RLS_RSP *rls_rsp;
+ uint8_t *pcmd;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_nodelist *ndlp;
+ uint16_t xri;
+ uint32_t cmdsize;
+
+ mb = &pmb->u.mb;
+
+ ndlp = (struct lpfc_nodelist *) pmb->context2;
+ xri = (uint16_t) ((unsigned long)(pmb->context1));
+ pmb->context1 = NULL;
+ pmb->context2 = NULL;
+
+ if (mb->mbxStatus) {
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return;
+ }
+
+ cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+
+ /* Decrement the ndlp reference count from previous mbox command */
+ lpfc_nlp_put(ndlp);
+
+ if (!elsiocb)
+ return;
+
+ icmd = &elsiocb->iocb;
+ icmd->ulpContext = xri;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+ pcmd += sizeof(uint32_t); /* Skip past command */
+ rls_rsp = (struct RLS_RSP *)pcmd;
+
+ rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+ rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+ rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+ rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+ rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+ rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
+
+ /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ "2874 Xmit ELS RLS 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, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+ lpfc_els_free_iocb(phba, elsiocb);
}
/**
@@ -4797,7 +5077,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
pcmd += sizeof(uint32_t); /* Skip past command */
rps_rsp = (RPS_RSP *)pcmd;
- if (phba->fc_topology != TOPOLOGY_LOOP)
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
status = 0x10;
else
status = 0x8;
@@ -4827,7 +5107,155 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
/**
- * lpfc_els_rcv_rps - Process an unsolicited rps iocb
+ * lpfc_els_rcv_rls - Process an unsolicited rls iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes Read Port Status (RPL) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command
+ * for reading the HBA link statistics. It is for the callback function,
+ * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command
+ * to actually sending out RPL Accept (ACC) response.
+ *
+ * Return codes
+ * 0 - Successfully processed rls iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ struct lpfc_dmabuf *pcmd;
+ struct ls_rjt stat;
+
+ if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+ /* reject the unsolicited RPS request and done with it */
+ goto reject_out;
+
+ pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+ if (mbox) {
+ lpfc_read_lnk_stat(phba, mbox);
+ mbox->context1 =
+ (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+ mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
+ if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+ != MBX_NOT_FINISHED)
+ /* Mbox completion will send ELS Response */
+ return 0;
+ /* Decrement reference count used for the failed mbox
+ * command.
+ */
+ lpfc_nlp_put(ndlp);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+reject_out:
+ /* issue rejection response */
+ stat.un.b.lsRjtRsvd0 = 0;
+ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+ stat.un.b.vendorUnique = 0;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+ return 0;
+}
+
+/**
+ * lpfc_els_rcv_rtv - Process an unsolicited rtv iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes Read Timout Value (RTV) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout
+ * Value (RTV) unsolicited IOCB event.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ * Return codes
+ * 0 - Successfully processed rtv iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct ls_rjt stat;
+ struct RTV_RSP *rtv_rsp;
+ uint8_t *pcmd;
+ struct lpfc_iocbq *elsiocb;
+ uint32_t cmdsize;
+
+
+ if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+ /* reject the unsolicited RPS request and done with it */
+ goto reject_out;
+
+ cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+
+ if (!elsiocb)
+ return 1;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+ pcmd += sizeof(uint32_t); /* Skip past command */
+
+ /* use the command's xri in the response */
+ elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;
+
+ rtv_rsp = (struct RTV_RSP *)pcmd;
+
+ /* populate RTV payload */
+ rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */
+ rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov);
+ bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0);
+ bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */
+ rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov);
+
+ /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ "2875 Xmit ELS RTV ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, "
+ "Data: x%x x%x x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi,
+ rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ phba->fc_stat.elsXmitACC++;
+ if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 0;
+
+reject_out:
+ /* issue rejection response */
+ stat.un.b.lsRjtRsvd0 = 0;
+ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+ stat.un.b.vendorUnique = 0;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+ return 0;
+}
+
+/* lpfc_els_rcv_rps - Process an unsolicited rps iocb
* @vport: pointer to a host virtual N_Port data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
* @ndlp: pointer to a node-list data structure.
@@ -4903,6 +5331,97 @@ reject_out:
return 0;
}
+/* lpfc_issue_els_rrq - Process an unsolicited rps iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: pointer to a node-list data structure.
+ * @did: DID of the target.
+ * @rrq: Pointer to the rrq struct.
+ *
+ * Build a ELS RRQ command and send it to the target. If the issue_iocb is
+ * Successful the the completion handler will clear the RRQ.
+ *
+ * Return codes
+ * 0 - Successfully sent rrq els iocb.
+ * 1 - Failed to send rrq els iocb.
+ **/
+static int
+lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct RRQ *els_rrq;
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int ret;
+
+
+ if (ndlp != rrq->ndlp)
+ ndlp = rrq->ndlp;
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 1;
+
+ /* If ndlp is not NULL, we will bump the reference count on it */
+ cmdsize = (sizeof(uint32_t) + sizeof(struct RRQ));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, did,
+ ELS_CMD_RRQ);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+ /* For RRQ request, remainder of payload is Exchange IDs */
+ *((uint32_t *) (pcmd)) = ELS_CMD_RRQ;
+ pcmd += sizeof(uint32_t);
+ els_rrq = (struct RRQ *) pcmd;
+
+ bf_set(rrq_oxid, els_rrq, rrq->xritag);
+ bf_set(rrq_rxid, els_rrq, rrq->rxid);
+ bf_set(rrq_did, els_rrq, vport->fc_myDID);
+ els_rrq->rrq = cpu_to_be32(els_rrq->rrq);
+ els_rrq->rrq_exchg = cpu_to_be32(els_rrq->rrq_exchg);
+
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue RRQ: did:x%x",
+ did, rrq->xritag, rrq->rxid);
+ elsiocb->context_un.rrq = rrq;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq;
+ ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * lpfc_send_rrq - Sends ELS RRQ if needed.
+ * @phba: pointer to lpfc hba data structure.
+ * @rrq: pointer to the active rrq.
+ *
+ * This routine will call the lpfc_issue_els_rrq if the rrq is
+ * still active for the xri. If this function returns a failure then
+ * the caller needs to clean up the RRQ by calling lpfc_clr_active_rrq.
+ *
+ * Returns 0 Success.
+ * 1 Failure.
+ **/
+int
+lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport,
+ rrq->nlp_DID);
+ if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag))
+ return lpfc_issue_els_rrq(rrq->vport, ndlp,
+ rrq->nlp_DID, rrq);
+ else
+ return 1;
+}
+
/**
* lpfc_els_rsp_rpl_acc - Issue an accept rpl els command
* @vport: pointer to a host virtual N_Port data structure.
@@ -5017,7 +5536,6 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
rpl = (RPL *) (lp + 1);
-
maxsize = be32_to_cpu(rpl->maxsize);
/* We support only one port */
@@ -5192,7 +5710,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
sizeof(struct lpfc_name)))) {
/* This port has switched fabrics. FLOGI is required */
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
} else {
/* FAN verified - skip FLOGI */
vport->fc_myDID = vport->fc_prevDID;
@@ -5836,6 +6354,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RLS:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RLS: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvRLS++;
+ lpfc_els_rcv_rls(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
case ELS_CMD_RPS:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV RPS: did:x%x/ste:x%x flg:x%x",
@@ -5866,6 +6394,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RTV:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RTV: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+ phba->fc_stat.elsRcvRTV++;
+ lpfc_els_rcv_rtv(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
case ELS_CMD_RRQ:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV RRQ: did:x%x/ste:x%x flg:x%x",
@@ -5876,13 +6413,23 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_ECHO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ECHO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvECHO++;
+ lpfc_els_rcv_echo(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
cmd, did, vport->port_state);
/* Unsupported ELS command, reject */
- rjt_err = LSRJT_INVALID_CMD;
+ rjt_err = LSRJT_CMD_UNSUPPORTED;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -6054,7 +6601,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
if (!ndlp) {
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
@@ -6067,7 +6614,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
} else if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
@@ -6089,18 +6636,31 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
}
if (vport->cfg_fdmi_on) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp_fdmi) {
+ ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+ GFP_KERNEL);
+ if (ndlp_fdmi) {
+ lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+ ndlp_fdmi->nlp_type |= NLP_FABRIC;
+ } else
+ return;
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
+ ndlp_fdmi = lpfc_enable_node(vport,
+ ndlp_fdmi,
+ NLP_STE_NPR_NODE);
+
if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
- 0);
+ NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
}
}
- return;
}
/**
@@ -6170,13 +6730,15 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
default:
/* Try to recover from this error */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
spin_unlock_irq(shost->host_lock);
if (vport->port_type == LPFC_PHYSICAL_PORT
&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
else
lpfc_initial_fdisc(vport);
break;
@@ -6413,7 +6975,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
vport->fc_flag |= FC_FABRIC;
- if (vport->phba->fc_topology == TOPOLOGY_LOOP)
+ if (vport->phba->fc_topology == LPFC_TOPOLOGY_LOOP)
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
@@ -6437,6 +6999,10 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_unreg_rpi(vport, np);
}
lpfc_cleanup_pending_mbox(vport);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
+
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
@@ -6452,7 +7018,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* to update the MAC address.
*/
lpfc_register_new_vport(phba, vport, ndlp);
- return ;
+ goto out;
}
if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
@@ -6519,7 +7085,9 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
- if (phba->sli_rev == LPFC_SLI_REV4) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)) {
/* FDISC needs to be 1 for WQE VPI */
elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1;
elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ;
@@ -7026,8 +7594,11 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+ uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
+ struct lpfc_nodelist *ndlp;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
@@ -7036,11 +7607,14 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
&phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
if (sglq_entry->sli4_xritag == xri) {
list_del(&sglq_entry->list);
+ ndlp = sglq_entry->ndlp;
+ sglq_entry->ndlp = NULL;
list_add_tail(&sglq_entry->list,
&phba->sli4_hba.lpfc_sgl_list);
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index a345dde16c86..bb015960dbc9 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -20,6 +20,7 @@
*******************************************************************/
#include <linux/blkdev.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/kthread.h>
@@ -63,6 +64,7 @@ static uint8_t lpfcAlpaArray[] = {
static void lpfc_disc_timeout_handler(struct lpfc_vport *);
static void lpfc_disc_flush_list(struct lpfc_vport *vport);
static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
+static int lpfc_fcf_inuse(struct lpfc_hba *);
void
lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -160,11 +162,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
return;
}
-/*
- * This function is called from the worker thread when dev_loss_tmo
- * expire.
- */
-static void
+/**
+ * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
+ * @ndlp: Pointer to remote node object.
+ *
+ * This function is called from the worker thread when devloss timeout timer
+ * expires. For SLI4 host, this routine shall return 1 when at lease one
+ * remote node, including this @ndlp, is still in use of FCF; otherwise, this
+ * routine shall return 0 when there is no remote node is still in use of FCF
+ * when devloss timeout happened to this @ndlp.
+ **/
+static int
lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
{
struct lpfc_rport_data *rdata;
@@ -175,17 +183,21 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
int put_node;
int put_rport;
int warn_on = 0;
+ int fcf_inuse = 0;
rport = ndlp->rport;
if (!rport)
- return;
+ return fcf_inuse;
rdata = rport->dd_data;
name = (uint8_t *) &ndlp->nlp_portname;
vport = ndlp->vport;
phba = vport->phba;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ fcf_inuse = lpfc_fcf_inuse(phba);
+
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
"rport devlosstmo:did:x%x type:x%x id:x%x",
ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
@@ -209,7 +221,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_nlp_put(ndlp);
if (put_rport)
put_device(&rport->dev);
- return;
+ return fcf_inuse;
}
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
@@ -220,7 +232,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID);
- return;
+ return fcf_inuse;
}
if (ndlp->nlp_type & NLP_FABRIC) {
@@ -233,7 +245,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_nlp_put(ndlp);
if (put_rport)
put_device(&rport->dev);
- return;
+ return fcf_inuse;
}
if (ndlp->nlp_sid != NLP_NO_SID) {
@@ -280,6 +292,74 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
(ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ return fcf_inuse;
+}
+
+/**
+ * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler
+ * @phba: Pointer to hba context object.
+ * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler.
+ * @nlp_did: remote node identifer with devloss timeout.
+ *
+ * This function is called from the worker thread after invoking devloss
+ * timeout handler and releasing the reference count for the ndlp with
+ * which the devloss timeout was handled for SLI4 host. For the devloss
+ * timeout of the last remote node which had been in use of FCF, when this
+ * routine is invoked, it shall be guaranteed that none of the remote are
+ * in-use of FCF. When devloss timeout to the last remote using the FCF,
+ * if the FIP engine is neither in FCF table scan process nor roundrobin
+ * failover process, the in-use FCF shall be unregistered. If the FIP
+ * engine is in FCF discovery process, the devloss timeout state shall
+ * be set for either the FCF table scan process or roundrobin failover
+ * process to unregister the in-use FCF.
+ **/
+static void
+lpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse,
+ uint32_t nlp_did)
+{
+ /* If devloss timeout happened to a remote node when FCF had no
+ * longer been in-use, do nothing.
+ */
+ if (!fcf_inuse)
+ return;
+
+ if ((phba->hba_flag & HBA_FIP_SUPPORT) && !lpfc_fcf_inuse(phba)) {
+ spin_lock_irq(&phba->hbalock);
+ if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
+ if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
+ phba->hba_flag |= HBA_DEVLOSS_TMO;
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2847 Last remote node (x%x) using "
+ "FCF devloss tmo\n", nlp_did);
+ }
+ if (phba->fcf.fcf_flag & FCF_REDISC_PROG) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2868 Devloss tmo to FCF rediscovery "
+ "in progress\n");
+ return;
+ }
+ if (!(phba->hba_flag & (FCF_TS_INPROG | FCF_RR_INPROG))) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2869 Devloss tmo to idle FIP engine, "
+ "unreg in-use FCF and rescan.\n");
+ /* Unregister in-use FCF and rescan */
+ lpfc_unregister_fcf_rescan(phba);
+ return;
+ }
+ spin_unlock_irq(&phba->hbalock);
+ if (phba->hba_flag & FCF_TS_INPROG)
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2870 FCF table scan in progress\n");
+ if (phba->hba_flag & FCF_RR_INPROG)
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2871 FLOGI roundrobin FCF failover "
+ "in progress\n");
+ }
lpfc_unregister_unused_fcf(phba);
}
@@ -408,6 +488,8 @@ lpfc_work_list_done(struct lpfc_hba *phba)
struct lpfc_work_evt *evtp = NULL;
struct lpfc_nodelist *ndlp;
int free_evt;
+ int fcf_inuse;
+ uint32_t nlp_did;
spin_lock_irq(&phba->hbalock);
while (!list_empty(&phba->work_list)) {
@@ -427,12 +509,17 @@ lpfc_work_list_done(struct lpfc_hba *phba)
break;
case LPFC_EVT_DEV_LOSS:
ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
- lpfc_dev_loss_tmo_handler(ndlp);
+ fcf_inuse = lpfc_dev_loss_tmo_handler(ndlp);
free_evt = 0;
/* decrement the node reference count held for
* this queued work
*/
+ nlp_did = ndlp->nlp_DID;
lpfc_nlp_put(ndlp);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_post_dev_loss_tmo_handler(phba,
+ fcf_inuse,
+ nlp_did);
break;
case LPFC_EVT_ONLINE:
if (phba->link_state < LPFC_LINK_DOWN)
@@ -520,6 +607,8 @@ lpfc_work_done(struct lpfc_hba *phba)
/* Process SLI4 events */
if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+ if (phba->hba_flag & HBA_RRQ_ACTIVE)
+ lpfc_handle_rrq_active(phba);
if (phba->hba_flag & FCP_XRI_ABORT_EVENT)
lpfc_sli4_fcp_xri_abort_event_proc(phba);
if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
@@ -707,6 +796,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
: NLP_EVT_DEVICE_RECOVERY);
}
if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
@@ -877,6 +968,7 @@ lpfc_linkup(struct lpfc_hba *phba)
struct lpfc_vport **vports;
int i;
+ lpfc_cleanup_wt_rrqs(phba);
phba->link_state = LPFC_LINK_UP;
/* Unblock fabric iocbs if they are blocked */
@@ -975,7 +1067,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mempool_free(pmb, phba->mbox_mem_pool);
- if (phba->fc_topology == TOPOLOGY_LOOP &&
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
vport->fc_flag & FC_PUBLIC_LOOP &&
!(vport->fc_flag & FC_LBIT)) {
/* Need to wait for FAN - use discovery timer
@@ -989,9 +1081,8 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI) {
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
- }
return;
out:
@@ -1021,8 +1112,7 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
"2017 REG_FCFI mbxStatus error x%x "
"HBA state x%x\n",
mboxq->u.mb.mbxStatus, vport->port_state);
- mempool_free(mboxq, phba->mbox_mem_pool);
- return;
+ goto fail_out;
}
/* Start FCoE discovery by sending a FLOGI. */
@@ -1031,20 +1121,30 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= FCF_REGISTERED;
spin_unlock_irq(&phba->hbalock);
+
/* If there is a pending FCoE event, restart FCF table scan. */
- if (lpfc_check_pending_fcoe_event(phba, 1)) {
- mempool_free(mboxq, phba->mbox_mem_pool);
- return;
- }
+ if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
+ goto fail_out;
+
+ /* Mark successful completion of FCF table scan */
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~FCF_TS_INPROG;
+ if (vport->port_state != LPFC_FLOGI) {
+ phba->hba_flag |= FCF_RR_INPROG;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_issue_init_vfi(vport);
+ goto out;
+ }
spin_unlock_irq(&phba->hbalock);
- if (vport->port_state != LPFC_FLOGI)
- lpfc_initial_flogi(vport);
+ goto out;
+fail_out:
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag &= ~FCF_RR_INPROG;
+ spin_unlock_irq(&phba->hbalock);
+out:
mempool_free(mboxq, phba->mbox_mem_pool);
- return;
}
/**
@@ -1241,10 +1341,9 @@ lpfc_register_fcf(struct lpfc_hba *phba)
int rc;
spin_lock_irq(&phba->hbalock);
-
/* If the FCF is not availabe do nothing. */
if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -1252,19 +1351,22 @@ lpfc_register_fcf(struct lpfc_hba *phba)
/* The FCF is already registered, start discovery */
if (phba->fcf.fcf_flag & FCF_REGISTERED) {
phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~FCF_TS_INPROG;
+ if (phba->pport->port_state != LPFC_FLOGI) {
+ phba->hba_flag |= FCF_RR_INPROG;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_issue_init_vfi(phba->pport);
+ return;
+ }
spin_unlock_irq(&phba->hbalock);
- if (phba->pport->port_state != LPFC_FLOGI)
- lpfc_initial_flogi(phba->pport);
return;
}
spin_unlock_irq(&phba->hbalock);
- fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
+ fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!fcf_mbxq) {
spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -1275,7 +1377,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
spin_unlock_irq(&phba->hbalock);
mempool_free(fcf_mbxq, phba->mbox_mem_pool);
}
@@ -1493,7 +1595,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* FCF discovery, no need to restart FCF discovery.
*/
if ((phba->link_state >= LPFC_LINK_UP) &&
- (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
+ (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
return 0;
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
@@ -1517,14 +1619,14 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
} else {
/*
- * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
+ * Do not continue FCF discovery and clear FCF_TS_INPROG
* flag
*/
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2833 Stop FCF discovery process due to link "
"state change (x%x)\n", phba->link_state);
spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
spin_unlock_irq(&phba->hbalock);
}
@@ -1729,6 +1831,65 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
}
/**
+ * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf
+ * @vport: Pointer to vport object.
+ * @fcf_index: index to next fcf.
+ *
+ * This function processing the roundrobin fcf failover to next fcf index.
+ * When this function is invoked, there will be a current fcf registered
+ * for flogi.
+ * Return: 0 for continue retrying flogi on currently registered fcf;
+ * 1 for stop flogi on currently registered fcf;
+ */
+int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index)
+{
+ struct lpfc_hba *phba = vport->phba;
+ int rc;
+
+ if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
+ spin_lock_irq(&phba->hbalock);
+ if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2872 Devloss tmo with no eligible "
+ "FCF, unregister in-use FCF (x%x) "
+ "and rescan FCF table\n",
+ phba->fcf.current_rec.fcf_indx);
+ lpfc_unregister_fcf_rescan(phba);
+ goto stop_flogi_current_fcf;
+ }
+ /* Mark the end to FLOGI roundrobin failover */
+ phba->hba_flag &= ~FCF_RR_INPROG;
+ /* Allow action to new fcf asynchronous event */
+ phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2865 No FCF available, stop roundrobin FCF "
+ "failover and change port state:x%x/x%x\n",
+ phba->pport->port_state, LPFC_VPORT_UNKNOWN);
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
+ goto stop_flogi_current_fcf;
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS,
+ "2794 Try FLOGI roundrobin FCF failover to "
+ "(x%x)\n", fcf_index);
+ rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index);
+ if (rc)
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
+ "2761 FLOGI roundrobin FCF failover "
+ "failed (rc:x%x) to read FCF (x%x)\n",
+ rc, phba->fcf.current_rec.fcf_indx);
+ else
+ goto stop_flogi_current_fcf;
+ }
+ return 0;
+
+stop_flogi_current_fcf:
+ lpfc_can_disctmo(vport);
+ return 1;
+}
+
+/**
* lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
@@ -1756,7 +1917,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
int rc;
/* If there is pending FCoE event restart FCF table scan */
- if (lpfc_check_pending_fcoe_event(phba, 0)) {
+ if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) {
lpfc_sli4_mbox_cmd_free(phba, mboxq);
return;
}
@@ -1765,12 +1926,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
&next_fcf_index);
if (!new_fcf_record) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
"2765 Mailbox command READ_FCF_RECORD "
"failed to retrieve a FCF record.\n");
/* Let next new FCF event trigger fast failover */
spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~FCF_TS_INPROG;
spin_unlock_irq(&phba->hbalock);
lpfc_sli4_mbox_cmd_free(phba, mboxq);
return;
@@ -1787,13 +1948,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
/*
* If the fcf record does not match with connect list entries
* read the next entry; otherwise, this is an eligible FCF
- * record for round robin FCF failover.
+ * record for roundrobin FCF failover.
*/
if (!rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2781 FCF record (x%x) failed FCF "
- "connection list check, fcf_avail:x%x, "
- "fcf_valid:x%x\n",
+ "2781 FCF (x%x) failed connection "
+ "list check: (x%x/x%x)\n",
bf_get(lpfc_fcf_record_fcf_index,
new_fcf_record),
bf_get(lpfc_fcf_record_fcf_avail,
@@ -1803,6 +1963,16 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+ if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) !=
+ phba->fcf.current_rec.fcf_indx) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+ "2862 FCF (x%x) matches property "
+ "of in-use FCF (x%x)\n",
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record),
+ phba->fcf.current_rec.fcf_indx);
+ goto read_next_fcf;
+ }
/*
* In case the current in-use FCF record becomes
* invalid/unavailable during FCF discovery that
@@ -1813,9 +1983,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"2835 Invalid in-use FCF "
- "record (x%x) reported, "
- "entering fast FCF failover "
- "mode scanning.\n",
+ "(x%x), enter FCF failover "
+ "table scan.\n",
phba->fcf.current_rec.fcf_indx);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= FCF_REDISC_FOV;
@@ -1844,22 +2013,29 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (phba->fcf.fcf_flag & FCF_IN_USE) {
if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
new_fcf_record, vlan_id)) {
- phba->fcf.fcf_flag |= FCF_AVAILABLE;
- if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
- /* Stop FCF redisc wait timer if pending */
- __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
- else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
- /* If in fast failover, mark it's completed */
- phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
- spin_unlock_irq(&phba->hbalock);
- lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2836 The new FCF record (x%x) "
- "matches the in-use FCF record "
- "(x%x)\n",
- phba->fcf.current_rec.fcf_indx,
+ if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
+ phba->fcf.current_rec.fcf_indx) {
+ phba->fcf.fcf_flag |= FCF_AVAILABLE;
+ if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
+ /* Stop FCF redisc wait timer */
+ __lpfc_sli4_stop_fcf_redisc_wait_timer(
+ phba);
+ else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
+ /* Fast failover, mark completed */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2836 New FCF matches in-use "
+ "FCF (x%x)\n",
+ phba->fcf.current_rec.fcf_indx);
+ goto out;
+ } else
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+ "2863 New FCF (x%x) matches "
+ "property of in-use FCF (x%x)\n",
bf_get(lpfc_fcf_record_fcf_index,
- new_fcf_record));
- goto out;
+ new_fcf_record),
+ phba->fcf.current_rec.fcf_indx);
}
/*
* Read next FCF record from HBA searching for the matching
@@ -1953,8 +2129,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (fcf_rec) {
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2840 Update current FCF record "
- "with initial FCF record (x%x)\n",
+ "2840 Update initial FCF candidate "
+ "with FCF (x%x)\n",
bf_get(lpfc_fcf_record_fcf_index,
new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
@@ -1984,20 +2160,28 @@ read_next_fcf:
*/
if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2782 No suitable FCF record "
- "found during this round of "
- "post FCF rediscovery scan: "
- "fcf_evt_tag:x%x, fcf_index: "
- "x%x\n",
+ "2782 No suitable FCF found: "
+ "(x%x/x%x)\n",
phba->fcoe_eventtag_at_fcf_scan,
bf_get(lpfc_fcf_record_fcf_index,
new_fcf_record));
+ spin_lock_irq(&phba->hbalock);
+ if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+ phba->hba_flag &= ~FCF_TS_INPROG;
+ spin_unlock_irq(&phba->hbalock);
+ /* Unregister in-use FCF and rescan */
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_FIP,
+ "2864 On devloss tmo "
+ "unreg in-use FCF and "
+ "rescan FCF table\n");
+ lpfc_unregister_fcf_rescan(phba);
+ return;
+ }
/*
- * Let next new FCF event trigger fast
- * failover
+ * Let next new FCF event trigger fast failover
*/
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~FCF_TS_INPROG;
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -2015,9 +2199,8 @@ read_next_fcf:
/* Replace in-use record with the new record */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2842 Replace the current in-use "
- "FCF record (x%x) with failover FCF "
- "record (x%x)\n",
+ "2842 Replace in-use FCF (x%x) "
+ "with failover FCF (x%x)\n",
phba->fcf.current_rec.fcf_indx,
phba->fcf.failover_rec.fcf_indx);
memcpy(&phba->fcf.current_rec,
@@ -2029,15 +2212,8 @@ read_next_fcf:
* FCF failover.
*/
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &=
- ~(FCF_REDISC_FOV | FCF_REDISC_RRU);
+ phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
spin_unlock_irq(&phba->hbalock);
- /*
- * Set up the initial registered FCF index for FLOGI
- * round robin FCF failover.
- */
- phba->fcf.fcf_rr_init_indx =
- phba->fcf.failover_rec.fcf_indx;
/* Register to the new FCF record */
lpfc_register_fcf(phba);
} else {
@@ -2069,28 +2245,6 @@ read_next_fcf:
LPFC_FCOE_FCF_GET_FIRST);
return;
}
-
- /*
- * Otherwise, initial scan or post linkdown rescan,
- * register with the best FCF record found so far
- * through the FCF scanning process.
- */
-
- /*
- * Mark the initial FCF discovery completed and
- * the start of the first round of the roundrobin
- * FCF failover.
- */
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &=
- ~(FCF_INIT_DISC | FCF_REDISC_RRU);
- spin_unlock_irq(&phba->hbalock);
- /*
- * Set up the initial registered FCF index for FLOGI
- * round robin FCF failover
- */
- phba->fcf.fcf_rr_init_indx =
- phba->fcf.current_rec.fcf_indx;
/* Register to the new FCF record */
lpfc_register_fcf(phba);
}
@@ -2106,11 +2260,11 @@ out:
}
/**
- * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf round robin read_fcf mbox cmpl hdler
+ * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
*
- * This is the callback function for FLOGI failure round robin FCF failover
+ * This is the callback function for FLOGI failure roundrobin FCF failover
* read FCF record mailbox command from the eligible FCF record bmask for
* performing the failover. If the FCF read back is not valid/available, it
* fails through to retrying FLOGI to the currently registered FCF again.
@@ -2125,17 +2279,18 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
struct fcf_record *new_fcf_record;
uint32_t boot_flag, addr_mode;
- uint16_t next_fcf_index;
+ uint16_t next_fcf_index, fcf_index;
uint16_t current_fcf_index;
uint16_t vlan_id;
+ int rc;
- /* If link state is not up, stop the round robin failover process */
+ /* If link state is not up, stop the roundrobin failover process */
if (phba->link_state < LPFC_LINK_UP) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ phba->hba_flag &= ~FCF_RR_INPROG;
spin_unlock_irq(&phba->hbalock);
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
- return;
+ goto out;
}
/* Parse the FCF record from the non-embedded mailbox command */
@@ -2145,23 +2300,47 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"2766 Mailbox command READ_FCF_RECORD "
"failed to retrieve a FCF record.\n");
- goto out;
+ goto error_out;
}
/* Get the needed parameters from FCF record */
- lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
- &addr_mode, &vlan_id);
+ rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
+ &addr_mode, &vlan_id);
/* Log the FCF record information if turned on */
lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
next_fcf_index);
+ fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+ if (!rc) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2848 Remove ineligible FCF (x%x) from "
+ "from roundrobin bmask\n", fcf_index);
+ /* Clear roundrobin bmask bit for ineligible FCF */
+ lpfc_sli4_fcf_rr_index_clear(phba, fcf_index);
+ /* Perform next round of roundrobin FCF failover */
+ fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
+ rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index);
+ if (rc)
+ goto out;
+ goto error_out;
+ }
+
+ if (fcf_index == phba->fcf.current_rec.fcf_indx) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2760 Perform FLOGI roundrobin FCF failover: "
+ "FCF (x%x) back to FCF (x%x)\n",
+ phba->fcf.current_rec.fcf_indx, fcf_index);
+ /* Wait 500 ms before retrying FLOGI to current FCF */
+ msleep(500);
+ lpfc_issue_init_vfi(phba->pport);
+ goto out;
+ }
+
/* Upload new FCF record to the failover FCF record */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2834 Update the current FCF record (x%x) "
- "with the next FCF record (x%x)\n",
- phba->fcf.failover_rec.fcf_indx,
- bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
+ "2834 Update current FCF (x%x) with new FCF (x%x)\n",
+ phba->fcf.failover_rec.fcf_indx, fcf_index);
spin_lock_irq(&phba->hbalock);
__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
new_fcf_record, addr_mode, vlan_id,
@@ -2178,14 +2357,13 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
sizeof(struct lpfc_fcf_rec));
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2783 FLOGI round robin FCF failover from FCF "
- "(x%x) to FCF (x%x).\n",
- current_fcf_index,
- bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
+ "2783 Perform FLOGI roundrobin FCF failover: FCF "
+ "(x%x) to FCF (x%x)\n", current_fcf_index, fcf_index);
+error_out:
+ lpfc_register_fcf(phba);
out:
lpfc_sli4_mbox_cmd_free(phba, mboxq);
- lpfc_register_fcf(phba);
}
/**
@@ -2194,10 +2372,10 @@ out:
* @mboxq: pointer to mailbox object.
*
* This is the callback function of read FCF record mailbox command for
- * updating the eligible FCF bmask for FLOGI failure round robin FCF
+ * updating the eligible FCF bmask for FLOGI failure roundrobin FCF
* failover when a new FCF event happened. If the FCF read back is
* valid/available and it passes the connection list check, it updates
- * the bmask for the eligible FCF record for round robin failover.
+ * the bmask for the eligible FCF record for roundrobin failover.
*/
void
lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
@@ -2246,6 +2424,63 @@ out:
}
/**
+ * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox data structure.
+ *
+ * This function handles completion of init vfi mailbox command.
+ */
+void
+lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+ struct lpfc_vport *vport = mboxq->vport;
+
+ if (mboxq->u.mb.mbxStatus && (mboxq->u.mb.mbxStatus != 0x4002)) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX,
+ "2891 Init VFI mailbox failed 0x%x\n",
+ mboxq->u.mb.mbxStatus);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ return;
+ }
+ lpfc_initial_flogi(vport);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return;
+}
+
+/**
+ * lpfc_issue_init_vfi - Issue init_vfi mailbox command.
+ * @vport: pointer to lpfc_vport data structure.
+ *
+ * This function issue a init_vfi mailbox command to initialize the VFI and
+ * VPI for the physical port.
+ */
+void
+lpfc_issue_init_vfi(struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *mboxq;
+ int rc;
+ struct lpfc_hba *phba = vport->phba;
+
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2892 Failed to allocate "
+ "init_vfi mailbox\n");
+ return;
+ }
+ lpfc_init_vfi(mboxq, vport);
+ mboxq->mbox_cmpl = lpfc_init_vfi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2893 Failed to issue init_vfi mailbox\n");
+ mempool_free(mboxq, vport->phba->mbox_mem_pool);
+ }
+}
+
+/**
* lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox data structure.
@@ -2352,7 +2587,7 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
FC_VPORT_FAILED);
continue;
}
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_vport_set_state(vports[i],
FC_VPORT_LINKDOWN);
continue;
@@ -2388,7 +2623,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
"2018 REG_VFI mbxStatus error x%x "
"HBA state x%x\n",
mboxq->u.mb.mbxStatus, vport->port_state);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
/* Start discovery */
@@ -2406,8 +2641,18 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_unlock_irq(shost->host_lock);
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
- lpfc_start_fdiscs(phba);
- lpfc_do_scr_ns_plogi(phba, vport);
+ /* For private loop just start discovery and we are done. */
+ if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
+ (phba->alpa_map[0] == 0) &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP)) {
+ /* Use loop map to make discovery list */
+ lpfc_disc_list_loopmap(vport);
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ } else {
+ lpfc_start_fdiscs(phba);
+ lpfc_do_scr_ns_plogi(phba, vport);
+ }
}
fail_free_mem:
@@ -2468,7 +2713,7 @@ out:
}
static void
-lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
+lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
{
struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
@@ -2478,31 +2723,24 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
struct fcf_record *fcf_record;
spin_lock_irq(&phba->hbalock);
- switch (la->UlnkSpeed) {
- case LA_1GHZ_LINK:
- phba->fc_linkspeed = LA_1GHZ_LINK;
- break;
- case LA_2GHZ_LINK:
- phba->fc_linkspeed = LA_2GHZ_LINK;
- break;
- case LA_4GHZ_LINK:
- phba->fc_linkspeed = LA_4GHZ_LINK;
- break;
- case LA_8GHZ_LINK:
- phba->fc_linkspeed = LA_8GHZ_LINK;
- break;
- case LA_10GHZ_LINK:
- phba->fc_linkspeed = LA_10GHZ_LINK;
+ switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+ case LPFC_LINK_SPEED_1GHZ:
+ case LPFC_LINK_SPEED_2GHZ:
+ case LPFC_LINK_SPEED_4GHZ:
+ case LPFC_LINK_SPEED_8GHZ:
+ case LPFC_LINK_SPEED_10GHZ:
+ case LPFC_LINK_SPEED_16GHZ:
+ phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
break;
default:
- phba->fc_linkspeed = LA_UNKNW_LINK;
+ phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
break;
}
- phba->fc_topology = la->topology;
+ phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la);
phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
/* if npiv is enabled and this adapter supports npiv log
@@ -2513,11 +2751,11 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
"1309 Link Up Event npiv not supported in loop "
"topology\n");
/* Get Loop Map information */
- if (la->il)
+ if (bf_get(lpfc_mbx_read_top_il, la))
vport->fc_flag |= FC_LBIT;
- vport->fc_myDID = la->granted_AL_PA;
- i = la->un.lilpBde64.tus.f.bdeSize;
+ vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
+ i = la->lilpBde64.tus.f.bdeSize;
if (i == 0) {
phba->alpa_map[0] = 0;
@@ -2588,7 +2826,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
goto out;
}
- if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!cfglink_mbox)
goto out;
@@ -2614,7 +2852,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
if (unlikely(!fcf_record)) {
lpfc_printf_log(phba, KERN_ERR,
LOG_MBOX | LOG_SLI,
- "2554 Could not allocate memmory for "
+ "2554 Could not allocate memory for "
"fcf record\n");
rc = -ENODEV;
goto out;
@@ -2639,7 +2877,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
* and get the FCF Table.
*/
spin_lock_irq(&phba->hbalock);
- if (phba->hba_flag & FCF_DISC_INPROGRESS) {
+ if (phba->hba_flag & FCF_TS_INPROG) {
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -2698,17 +2936,17 @@ lpfc_mbx_issue_link_down(struct lpfc_hba *phba)
/*
- * This routine handles processing a READ_LA mailbox
+ * This routine handles processing a READ_TOPOLOGY mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- READ_LA_VAR *la;
+ struct lpfc_mbx_read_top *la;
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
@@ -2721,15 +2959,15 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
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;
+ goto lpfc_mbx_cmpl_read_topology_free_mbuf;
}
- la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+ la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
memcpy(&phba->alpa_map[0], mp->virt, 128);
spin_lock_irq(shost->host_lock);
- if (la->pb)
+ if (bf_get(lpfc_mbx_read_top_pb, la))
vport->fc_flag |= FC_BYPASSED_MODE;
else
vport->fc_flag &= ~FC_BYPASSED_MODE;
@@ -2738,41 +2976,48 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if ((phba->fc_eventTag < la->eventTag) ||
(phba->fc_eventTag == la->eventTag)) {
phba->fc_stat.LinkMultiEvent++;
- if (la->attType == AT_LINK_UP)
+ if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)
if (phba->fc_eventTag != 0)
lpfc_linkdown(phba);
}
phba->fc_eventTag = la->eventTag;
spin_lock_irq(&phba->hbalock);
- if (la->mm)
+ if (bf_get(lpfc_mbx_read_top_mm, la))
phba->sli.sli_flag |= LPFC_MENLO_MAINT;
else
phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
spin_unlock_irq(&phba->hbalock);
phba->link_events++;
- if (la->attType == AT_LINK_UP && (!la->mm)) {
+ if ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) &&
+ (!bf_get(lpfc_mbx_read_top_mm, la))) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"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,
+ bf_get(lpfc_mbx_read_top_alpa_granted,
+ la),
+ bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0]);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1303 Link Up Event x%x received "
"Data: x%x x%x x%x x%x x%x x%x %d\n",
la->eventTag, phba->fc_eventTag,
- la->granted_AL_PA, la->UlnkSpeed,
+ bf_get(lpfc_mbx_read_top_alpa_granted,
+ la),
+ bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0],
- la->mm, la->fa,
+ bf_get(lpfc_mbx_read_top_mm, la),
+ bf_get(lpfc_mbx_read_top_fa, la),
phba->wait_4_mlo_maint_flg);
}
lpfc_mbx_process_link_up(phba, la);
- } else if (la->attType == AT_LINK_DOWN) {
+ } else if (bf_get(lpfc_mbx_read_top_att_type, la) ==
+ LPFC_ATT_LINK_DOWN) {
phba->fc_stat.LinkDown++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -2788,11 +3033,13 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
"Data: x%x x%x x%x x%x x%x\n",
la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag,
- la->mm, la->fa);
+ bf_get(lpfc_mbx_read_top_mm, la),
+ bf_get(lpfc_mbx_read_top_fa, la));
}
lpfc_mbx_issue_link_down(phba);
}
- if (la->mm && la->attType == AT_LINK_UP) {
+ if ((bf_get(lpfc_mbx_read_top_mm, la)) &&
+ (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)) {
if (phba->link_state != LPFC_LINK_DOWN) {
phba->fc_stat.LinkDown++;
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -2820,14 +3067,15 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
}
- if (la->fa) {
- if (la->mm)
+ if (bf_get(lpfc_mbx_read_top_fa, la)) {
+ if (bf_get(lpfc_mbx_read_top_mm, la))
lpfc_issue_clear_la(phba, vport);
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
- "1311 fa %d\n", la->fa);
+ "1311 fa %d\n",
+ bf_get(lpfc_mbx_read_top_fa, la));
}
-lpfc_mbx_cmpl_read_la_free_mbuf:
+lpfc_mbx_cmpl_read_topology_free_mbuf:
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
@@ -2854,8 +3102,8 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
- if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
- ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+ if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
+ ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
/* We rcvd a rscn after issuing this
* mbox reg login, we may have cycled
* back through the state and be
@@ -2867,10 +3115,6 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
spin_unlock_irq(shost->host_lock);
- if (phba->sli_rev == LPFC_SLI_REV4)
- lpfc_sli4_free_rpi(phba,
- pmb->u.mb.un.varRegLogin.rpi);
-
} else
/* Good status, call state machine */
lpfc_disc_state_machine(vport, ndlp, pmb,
@@ -2916,6 +3160,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_unlock_irq(shost->host_lock);
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_cleanup_vports_rrqs(vport);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
@@ -3157,7 +3402,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
@@ -3179,7 +3424,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -3237,7 +3482,7 @@ out:
/* If no other thread is using the ndlp, free it */
lpfc_nlp_not_used(ndlp);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/*
* RegLogin failed, use loop map to make discovery
* list
@@ -3253,7 +3498,7 @@ out:
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -3586,6 +3831,8 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
NLP_INT_NODE_ACT(ndlp);
atomic_set(&ndlp->cmd_pending, 0);
ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
}
struct lpfc_nodelist *
@@ -3799,7 +4046,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
* by firmware with a no rpi error.
*/
psli = &phba->sli;
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
/* Now process each ring */
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
@@ -3847,7 +4094,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
LPFC_MBOXQ_t *mbox;
int rc;
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox) {
lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
@@ -3859,8 +4106,9 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
}
lpfc_no_rpi(phba, ndlp);
- ndlp->nlp_rpi = 0;
- ndlp->nlp_flag &= ~NLP_RPI_VALID;
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ ndlp->nlp_rpi = 0;
+ ndlp->nlp_flag &= ~NLP_RPI_REGISTERED;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
return 1;
}
@@ -3883,11 +4131,16 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
int i;
vports = lpfc_create_vport_work_array(phba);
+ if (!vports) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2884 Vport array allocation failed \n");
+ return;
+ }
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
- if (ndlp->nlp_flag & NLP_RPI_VALID) {
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
/* The mempool_alloc might sleep */
spin_unlock_irq(shost->host_lock);
lpfc_unreg_rpi(vports[i], ndlp);
@@ -3906,6 +4159,11 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
LPFC_MBOXQ_t *mbox;
int rc;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ lpfc_sli4_unreg_all_rpis(vport);
+ return;
+ }
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox) {
lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
@@ -3992,6 +4250,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
}
spin_lock_irq(&phba->hbalock);
+ /* Cleanup REG_LOGIN completions which are not yet processed */
+ list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
+ if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) ||
+ (ndlp != (struct lpfc_nodelist *) mb->context2))
+ continue;
+
+ mb->context2 = NULL;
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ }
+
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -4001,9 +4269,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
kfree(mp);
}
list_del(&mb->list);
- if (phba->sli_rev == LPFC_SLI_REV4)
- lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
mempool_free(mb, phba->mbox_mem_pool);
/* We shall not invoke the lpfc_nlp_put to decrement
* the ndlp reference count as we are in the process
@@ -4045,15 +4310,15 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
- !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
- !(ndlp->nlp_flag & NLP_RPI_VALID)) {
+ !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
+ !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
*/
if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
!= NULL) {
rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID,
- (uint8_t *) &vport->fc_sparam, mbox, 0);
+ (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi);
if (rc) {
mempool_free(mbox, phba->mbox_mem_pool);
}
@@ -4245,7 +4510,7 @@ lpfc_disc_list_loopmap(struct lpfc_vport *vport)
if (!lpfc_is_link_up(phba))
return;
- if (phba->fc_topology != TOPOLOGY_LOOP)
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
return;
/* Check for loop map present or not */
@@ -4597,7 +4862,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
}
}
if (vport->port_state != LPFC_FLOGI) {
- lpfc_initial_flogi(vport);
+ if (phba->sli_rev <= LPFC_SLI_REV3)
+ lpfc_initial_flogi(vport);
+ else
+ lpfc_issue_init_vfi(vport);
return;
}
break;
@@ -4788,7 +5056,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
pmb->context2 = NULL;
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -4912,6 +5180,8 @@ lpfc_nlp_release(struct kref *kref)
spin_lock_irqsave(&phba->ndlp_lock, flags);
NLP_CLR_NODE_ACT(ndlp);
spin_unlock_irqrestore(&phba->ndlp_lock, flags);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
/* free ndlp memory for final ndlp release */
if (NLP_CHK_FREE_REQ(ndlp)) {
@@ -5063,6 +5333,10 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
vports = lpfc_create_vport_work_array(phba);
+ /* If driver cannot allocate memory, indicate fcf is in use */
+ if (!vports)
+ return 1;
+
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock);
@@ -5078,7 +5352,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
"logged in\n",
ndlp->nlp_rpi, ndlp->nlp_DID,
ndlp->nlp_flag);
- if (ndlp->nlp_flag & NLP_RPI_VALID)
+ if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
ret = 1;
}
}
@@ -5170,6 +5444,8 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
if (ndlp)
lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
lpfc_cleanup_pending_mbox(vports[i]);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vports[i]);
lpfc_mbx_unreg_vpi(vports[i]);
shost = lpfc_shost_from_vport(vports[i]);
spin_lock_irq(shost->host_lock);
@@ -5357,7 +5633,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
* registered, do nothing.
*/
spin_lock_irq(&phba->hbalock);
- if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
+ if (!(phba->hba_flag & HBA_FCOE_MODE) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
!(phba->hba_flag & HBA_FIP_SUPPORT) ||
(phba->fcf.fcf_flag & FCF_DISCOVERY) ||
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index a631647051d9..96ed3ba6ba95 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -861,6 +861,65 @@ typedef struct _RPS_RSP { /* Structure is in Big Endian format */
uint32_t crcCnt;
} RPS_RSP;
+struct RLS { /* Structure is in Big Endian format */
+ uint32_t rls;
+#define rls_rsvd_SHIFT 24
+#define rls_rsvd_MASK 0x000000ff
+#define rls_rsvd_WORD rls
+#define rls_did_SHIFT 0
+#define rls_did_MASK 0x00ffffff
+#define rls_did_WORD rls
+};
+
+struct RLS_RSP { /* Structure is in Big Endian format */
+ uint32_t linkFailureCnt;
+ uint32_t lossSyncCnt;
+ uint32_t lossSignalCnt;
+ uint32_t primSeqErrCnt;
+ uint32_t invalidXmitWord;
+ uint32_t crcCnt;
+};
+
+struct RRQ { /* Structure is in Big Endian format */
+ uint32_t rrq;
+#define rrq_rsvd_SHIFT 24
+#define rrq_rsvd_MASK 0x000000ff
+#define rrq_rsvd_WORD rrq
+#define rrq_did_SHIFT 0
+#define rrq_did_MASK 0x00ffffff
+#define rrq_did_WORD rrq
+ uint32_t rrq_exchg;
+#define rrq_oxid_SHIFT 16
+#define rrq_oxid_MASK 0xffff
+#define rrq_oxid_WORD rrq_exchg
+#define rrq_rxid_SHIFT 0
+#define rrq_rxid_MASK 0xffff
+#define rrq_rxid_WORD rrq_exchg
+};
+
+
+struct RTV_RSP { /* Structure is in Big Endian format */
+ uint32_t ratov;
+ uint32_t edtov;
+ uint32_t qtov;
+#define qtov_rsvd0_SHIFT 28
+#define qtov_rsvd0_MASK 0x0000000f
+#define qtov_rsvd0_WORD qtov /* reserved */
+#define qtov_edtovres_SHIFT 27
+#define qtov_edtovres_MASK 0x00000001
+#define qtov_edtovres_WORD qtov /* E_D_TOV Resolution */
+#define qtov__rsvd1_SHIFT 19
+#define qtov_rsvd1_MASK 0x0000003f
+#define qtov_rsvd1_WORD qtov /* reserved */
+#define qtov_rttov_SHIFT 18
+#define qtov_rttov_MASK 0x00000001
+#define qtov_rttov_WORD qtov /* R_T_TOV value */
+#define qtov_rsvd2_SHIFT 0
+#define qtov_rsvd2_MASK 0x0003ffff
+#define qtov_rsvd2_WORD qtov /* reserved */
+};
+
+
typedef struct _RPL { /* Structure is in Big Endian format */
uint32_t maxsize;
uint32_t index;
@@ -1131,7 +1190,10 @@ typedef struct {
#define PCI_VENDOR_ID_EMULEX 0x10df
#define PCI_DEVICE_ID_FIREFLY 0x1ae5
#define PCI_DEVICE_ID_PROTEUS_VF 0xe100
+#define PCI_DEVICE_ID_BALIUS 0xe131
#define PCI_DEVICE_ID_PROTEUS_PF 0xe180
+#define PCI_DEVICE_ID_LANCER_FC 0xe200
+#define PCI_DEVICE_ID_LANCER_FCOE 0xe260
#define PCI_DEVICE_ID_SAT_SMB 0xf011
#define PCI_DEVICE_ID_SAT_MID 0xf015
#define PCI_DEVICE_ID_RFLY 0xf095
@@ -1148,6 +1210,7 @@ typedef struct {
#define PCI_DEVICE_ID_SAT 0xf100
#define PCI_DEVICE_ID_SAT_SCSP 0xf111
#define PCI_DEVICE_ID_SAT_DCSP 0xf112
+#define PCI_DEVICE_ID_FALCON 0xf180
#define PCI_DEVICE_ID_SUPERFLY 0xf700
#define PCI_DEVICE_ID_DRAGONFLY 0xf800
#define PCI_DEVICE_ID_CENTAUR 0xf900
@@ -1169,8 +1232,6 @@ typedef struct {
#define PCI_VENDOR_ID_SERVERENGINE 0x19a2
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
#define PCI_DEVICE_ID_TOMCAT 0x0714
-#define PCI_DEVICE_ID_FALCON 0xf180
-#define PCI_DEVICE_ID_BALIUS 0xe131
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
@@ -1327,7 +1388,6 @@ typedef struct { /* FireFly BIU registers */
#define MBX_READ_LNK_STAT 0x12
#define MBX_REG_LOGIN 0x13
#define MBX_UNREG_LOGIN 0x14
-#define MBX_READ_LA 0x15
#define MBX_CLEAR_LA 0x16
#define MBX_DUMP_MEMORY 0x17
#define MBX_DUMP_CONTEXT 0x18
@@ -1361,7 +1421,7 @@ typedef struct { /* FireFly BIU registers */
#define MBX_READ_SPARM64 0x8D
#define MBX_READ_RPI64 0x8F
#define MBX_REG_LOGIN64 0x93
-#define MBX_READ_LA64 0x95
+#define MBX_READ_TOPOLOGY 0x95
#define MBX_REG_VPI 0x96
#define MBX_UNREG_VPI 0x97
@@ -1782,12 +1842,13 @@ typedef struct {
#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */
uint32_t link_speed;
-#define LINK_SPEED_AUTO 0 /* Auto selection */
-#define LINK_SPEED_1G 1 /* 1 Gigabaud */
-#define LINK_SPEED_2G 2 /* 2 Gigabaud */
-#define LINK_SPEED_4G 4 /* 4 Gigabaud */
-#define LINK_SPEED_8G 8 /* 8 Gigabaud */
-#define LINK_SPEED_10G 16 /* 10 Gigabaud */
+#define LINK_SPEED_AUTO 0x0 /* Auto selection */
+#define LINK_SPEED_1G 0x1 /* 1 Gigabaud */
+#define LINK_SPEED_2G 0x2 /* 2 Gigabaud */
+#define LINK_SPEED_4G 0x4 /* 4 Gigabaud */
+#define LINK_SPEED_8G 0x8 /* 8 Gigabaud */
+#define LINK_SPEED_10G 0x10 /* 10 Gigabaud */
+#define LINK_SPEED_16G 0x11 /* 16 Gigabaud */
} INIT_LINK_VAR;
@@ -1958,6 +2019,7 @@ typedef struct {
#define LMT_4Gb 0x040
#define LMT_8Gb 0x080
#define LMT_10Gb 0x100
+#define LMT_16Gb 0x200
uint32_t rsvd2;
uint32_t rsvd3;
uint32_t max_xri;
@@ -2353,100 +2415,93 @@ typedef struct {
#endif
} UNREG_D_ID_VAR;
-/* Structure for MB Command READ_LA (21) */
-/* Structure for MB Command READ_LA64 (0x95) */
-
-typedef struct {
+/* Structure for MB Command READ_TOPOLOGY (0x95) */
+struct lpfc_mbx_read_top {
uint32_t eventTag; /* Event tag */
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t rsvd1:19;
- uint32_t fa:1;
- uint32_t mm:1; /* Menlo Maintenance mode enabled */
- uint32_t rx:1;
- uint32_t pb:1;
- uint32_t il:1;
- uint32_t attType:8;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t attType:8;
- uint32_t il:1;
- uint32_t pb:1;
- uint32_t rx:1;
- uint32_t mm:1;
- uint32_t fa:1;
- uint32_t rsvd1:19;
-#endif
-
-#define AT_RESERVED 0x00 /* Reserved - attType */
-#define AT_LINK_UP 0x01 /* Link is up */
-#define AT_LINK_DOWN 0x02 /* Link is down */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint8_t granted_AL_PA;
- uint8_t lipAlPs;
- uint8_t lipType;
- uint8_t topology;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint8_t topology;
- uint8_t lipType;
- uint8_t lipAlPs;
- uint8_t granted_AL_PA;
-#endif
-
-#define TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */
-#define TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */
-#define TOPOLOGY_LNK_MENLO_MAINTENANCE 0x05 /* maint mode zephtr to menlo */
-
- union {
- struct ulp_bde lilpBde; /* This BDE points to a 128 byte buffer
- to */
- /* store the LILP AL_PA position map into */
- struct ulp_bde64 lilpBde64;
- } un;
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t Dlu:1;
- uint32_t Dtf:1;
- uint32_t Drsvd2:14;
- uint32_t DlnkSpeed:8;
- uint32_t DnlPort:4;
- uint32_t Dtx:2;
- uint32_t Drx:2;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t Drx:2;
- uint32_t Dtx:2;
- uint32_t DnlPort:4;
- uint32_t DlnkSpeed:8;
- uint32_t Drsvd2:14;
- uint32_t Dtf:1;
- uint32_t Dlu:1;
-#endif
-
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t Ulu:1;
- uint32_t Utf:1;
- uint32_t Ursvd2:14;
- uint32_t UlnkSpeed:8;
- uint32_t UnlPort:4;
- uint32_t Utx:2;
- uint32_t Urx:2;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t Urx:2;
- uint32_t Utx:2;
- uint32_t UnlPort:4;
- uint32_t UlnkSpeed:8;
- uint32_t Ursvd2:14;
- uint32_t Utf:1;
- uint32_t Ulu:1;
-#endif
-
-#define LA_UNKNW_LINK 0x0 /* lnkSpeed */
-#define LA_1GHZ_LINK 0x04 /* lnkSpeed */
-#define LA_2GHZ_LINK 0x08 /* lnkSpeed */
-#define LA_4GHZ_LINK 0x10 /* lnkSpeed */
-#define LA_8GHZ_LINK 0x20 /* lnkSpeed */
-#define LA_10GHZ_LINK 0x40 /* lnkSpeed */
-
-} READ_LA_VAR;
+ uint32_t word2;
+#define lpfc_mbx_read_top_fa_SHIFT 12
+#define lpfc_mbx_read_top_fa_MASK 0x00000001
+#define lpfc_mbx_read_top_fa_WORD word2
+#define lpfc_mbx_read_top_mm_SHIFT 11
+#define lpfc_mbx_read_top_mm_MASK 0x00000001
+#define lpfc_mbx_read_top_mm_WORD word2
+#define lpfc_mbx_read_top_pb_SHIFT 9
+#define lpfc_mbx_read_top_pb_MASK 0X00000001
+#define lpfc_mbx_read_top_pb_WORD word2
+#define lpfc_mbx_read_top_il_SHIFT 8
+#define lpfc_mbx_read_top_il_MASK 0x00000001
+#define lpfc_mbx_read_top_il_WORD word2
+#define lpfc_mbx_read_top_att_type_SHIFT 0
+#define lpfc_mbx_read_top_att_type_MASK 0x000000FF
+#define lpfc_mbx_read_top_att_type_WORD word2
+#define LPFC_ATT_RESERVED 0x00 /* Reserved - attType */
+#define LPFC_ATT_LINK_UP 0x01 /* Link is up */
+#define LPFC_ATT_LINK_DOWN 0x02 /* Link is down */
+ uint32_t word3;
+#define lpfc_mbx_read_top_alpa_granted_SHIFT 24
+#define lpfc_mbx_read_top_alpa_granted_MASK 0x000000FF
+#define lpfc_mbx_read_top_alpa_granted_WORD word3
+#define lpfc_mbx_read_top_lip_alps_SHIFT 16
+#define lpfc_mbx_read_top_lip_alps_MASK 0x000000FF
+#define lpfc_mbx_read_top_lip_alps_WORD word3
+#define lpfc_mbx_read_top_lip_type_SHIFT 8
+#define lpfc_mbx_read_top_lip_type_MASK 0x000000FF
+#define lpfc_mbx_read_top_lip_type_WORD word3
+#define lpfc_mbx_read_top_topology_SHIFT 0
+#define lpfc_mbx_read_top_topology_MASK 0x000000FF
+#define lpfc_mbx_read_top_topology_WORD word3
+#define LPFC_TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */
+#define LPFC_TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */
+#define LPFC_TOPOLOGY_MM 0x05 /* maint mode zephtr to menlo */
+ /* store the LILP AL_PA position map into */
+ struct ulp_bde64 lilpBde64;
+#define LPFC_ALPA_MAP_SIZE 128
+ uint32_t word7;
+#define lpfc_mbx_read_top_ld_lu_SHIFT 31
+#define lpfc_mbx_read_top_ld_lu_MASK 0x00000001
+#define lpfc_mbx_read_top_ld_lu_WORD word7
+#define lpfc_mbx_read_top_ld_tf_SHIFT 30
+#define lpfc_mbx_read_top_ld_tf_MASK 0x00000001
+#define lpfc_mbx_read_top_ld_tf_WORD word7
+#define lpfc_mbx_read_top_ld_link_spd_SHIFT 8
+#define lpfc_mbx_read_top_ld_link_spd_MASK 0x000000FF
+#define lpfc_mbx_read_top_ld_link_spd_WORD word7
+#define lpfc_mbx_read_top_ld_nl_port_SHIFT 4
+#define lpfc_mbx_read_top_ld_nl_port_MASK 0x0000000F
+#define lpfc_mbx_read_top_ld_nl_port_WORD word7
+#define lpfc_mbx_read_top_ld_tx_SHIFT 2
+#define lpfc_mbx_read_top_ld_tx_MASK 0x00000003
+#define lpfc_mbx_read_top_ld_tx_WORD word7
+#define lpfc_mbx_read_top_ld_rx_SHIFT 0
+#define lpfc_mbx_read_top_ld_rx_MASK 0x00000003
+#define lpfc_mbx_read_top_ld_rx_WORD word7
+ uint32_t word8;
+#define lpfc_mbx_read_top_lu_SHIFT 31
+#define lpfc_mbx_read_top_lu_MASK 0x00000001
+#define lpfc_mbx_read_top_lu_WORD word8
+#define lpfc_mbx_read_top_tf_SHIFT 30
+#define lpfc_mbx_read_top_tf_MASK 0x00000001
+#define lpfc_mbx_read_top_tf_WORD word8
+#define lpfc_mbx_read_top_link_spd_SHIFT 8
+#define lpfc_mbx_read_top_link_spd_MASK 0x000000FF
+#define lpfc_mbx_read_top_link_spd_WORD word8
+#define lpfc_mbx_read_top_nl_port_SHIFT 4
+#define lpfc_mbx_read_top_nl_port_MASK 0x0000000F
+#define lpfc_mbx_read_top_nl_port_WORD word8
+#define lpfc_mbx_read_top_tx_SHIFT 2
+#define lpfc_mbx_read_top_tx_MASK 0x00000003
+#define lpfc_mbx_read_top_tx_WORD word8
+#define lpfc_mbx_read_top_rx_SHIFT 0
+#define lpfc_mbx_read_top_rx_MASK 0x00000003
+#define lpfc_mbx_read_top_rx_WORD word8
+#define LPFC_LINK_SPEED_UNKNOWN 0x0
+#define LPFC_LINK_SPEED_1GHZ 0x04
+#define LPFC_LINK_SPEED_2GHZ 0x08
+#define LPFC_LINK_SPEED_4GHZ 0x10
+#define LPFC_LINK_SPEED_8GHZ 0x20
+#define LPFC_LINK_SPEED_10GHZ 0x40
+#define LPFC_LINK_SPEED_16GHZ 0x80
+};
/* Structure for MB Command CLEAR_LA (22) */
@@ -2975,7 +3030,6 @@ typedef union {
READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */
UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */
- READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */
DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
@@ -2985,6 +3039,7 @@ typedef union {
struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */
struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/
CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ struct lpfc_mbx_read_top varReadTop; /* cmd = 0x95 (READ_TOPOLOGY) */
REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */
UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */
ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index bbdcf96800f6..94c1aa1136de 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -64,29 +64,39 @@ struct lpfc_sli_intf {
#define lpfc_sli_intf_valid_MASK 0x00000007
#define lpfc_sli_intf_valid_WORD word0
#define LPFC_SLI_INTF_VALID 6
-#define lpfc_sli_intf_featurelevel2_SHIFT 24
-#define lpfc_sli_intf_featurelevel2_MASK 0x0000001F
-#define lpfc_sli_intf_featurelevel2_WORD word0
-#define lpfc_sli_intf_featurelevel1_SHIFT 16
-#define lpfc_sli_intf_featurelevel1_MASK 0x000000FF
-#define lpfc_sli_intf_featurelevel1_WORD word0
-#define LPFC_SLI_INTF_FEATURELEVEL1_1 1
-#define LPFC_SLI_INTF_FEATURELEVEL1_2 2
+#define lpfc_sli_intf_sli_hint2_SHIFT 24
+#define lpfc_sli_intf_sli_hint2_MASK 0x0000001F
+#define lpfc_sli_intf_sli_hint2_WORD word0
+#define LPFC_SLI_INTF_SLI_HINT2_NONE 0
+#define lpfc_sli_intf_sli_hint1_SHIFT 16
+#define lpfc_sli_intf_sli_hint1_MASK 0x000000FF
+#define lpfc_sli_intf_sli_hint1_WORD word0
+#define LPFC_SLI_INTF_SLI_HINT1_NONE 0
+#define LPFC_SLI_INTF_SLI_HINT1_1 1
+#define LPFC_SLI_INTF_SLI_HINT1_2 2
+#define lpfc_sli_intf_if_type_SHIFT 12
+#define lpfc_sli_intf_if_type_MASK 0x0000000F
+#define lpfc_sli_intf_if_type_WORD word0
+#define LPFC_SLI_INTF_IF_TYPE_0 0
+#define LPFC_SLI_INTF_IF_TYPE_1 1
+#define LPFC_SLI_INTF_IF_TYPE_2 2
#define lpfc_sli_intf_sli_family_SHIFT 8
-#define lpfc_sli_intf_sli_family_MASK 0x000000FF
+#define lpfc_sli_intf_sli_family_MASK 0x0000000F
#define lpfc_sli_intf_sli_family_WORD word0
-#define LPFC_SLI_INTF_FAMILY_BE2 0
-#define LPFC_SLI_INTF_FAMILY_BE3 1
+#define LPFC_SLI_INTF_FAMILY_BE2 0x0
+#define LPFC_SLI_INTF_FAMILY_BE3 0x1
+#define LPFC_SLI_INTF_FAMILY_LNCR_A0 0xa
+#define LPFC_SLI_INTF_FAMILY_LNCR_B0 0xb
#define lpfc_sli_intf_slirev_SHIFT 4
#define lpfc_sli_intf_slirev_MASK 0x0000000F
#define lpfc_sli_intf_slirev_WORD word0
#define LPFC_SLI_INTF_REV_SLI3 3
#define LPFC_SLI_INTF_REV_SLI4 4
-#define lpfc_sli_intf_if_type_SHIFT 0
-#define lpfc_sli_intf_if_type_MASK 0x00000007
-#define lpfc_sli_intf_if_type_WORD word0
-#define LPFC_SLI_INTF_IF_TYPE_0 0
-#define LPFC_SLI_INTF_IF_TYPE_1 1
+#define lpfc_sli_intf_func_type_SHIFT 0
+#define lpfc_sli_intf_func_type_MASK 0x00000001
+#define lpfc_sli_intf_func_type_WORD word0
+#define LPFC_SLI_INTF_IF_TYPE_PHYS 0
+#define LPFC_SLI_INTF_IF_TYPE_VIRT 1
};
#define LPFC_SLI4_MBX_EMBED true
@@ -424,79 +434,6 @@ struct lpfc_rcqe {
#define FCOE_SOFn3 0x36
};
-struct lpfc_wqe_generic{
- struct ulp_bde64 bde;
- uint32_t word3;
- uint32_t word4;
- uint32_t word5;
- uint32_t word6;
-#define lpfc_wqe_gen_context_SHIFT 16
-#define lpfc_wqe_gen_context_MASK 0x0000FFFF
-#define lpfc_wqe_gen_context_WORD word6
-#define lpfc_wqe_gen_xri_SHIFT 0
-#define lpfc_wqe_gen_xri_MASK 0x0000FFFF
-#define lpfc_wqe_gen_xri_WORD word6
- uint32_t word7;
-#define lpfc_wqe_gen_lnk_SHIFT 23
-#define lpfc_wqe_gen_lnk_MASK 0x00000001
-#define lpfc_wqe_gen_lnk_WORD word7
-#define lpfc_wqe_gen_erp_SHIFT 22
-#define lpfc_wqe_gen_erp_MASK 0x00000001
-#define lpfc_wqe_gen_erp_WORD word7
-#define lpfc_wqe_gen_pu_SHIFT 20
-#define lpfc_wqe_gen_pu_MASK 0x00000003
-#define lpfc_wqe_gen_pu_WORD word7
-#define lpfc_wqe_gen_class_SHIFT 16
-#define lpfc_wqe_gen_class_MASK 0x00000007
-#define lpfc_wqe_gen_class_WORD word7
-#define lpfc_wqe_gen_command_SHIFT 8
-#define lpfc_wqe_gen_command_MASK 0x000000FF
-#define lpfc_wqe_gen_command_WORD word7
-#define lpfc_wqe_gen_status_SHIFT 4
-#define lpfc_wqe_gen_status_MASK 0x0000000F
-#define lpfc_wqe_gen_status_WORD word7
-#define lpfc_wqe_gen_ct_SHIFT 2
-#define lpfc_wqe_gen_ct_MASK 0x00000003
-#define lpfc_wqe_gen_ct_WORD word7
- uint32_t abort_tag;
- uint32_t word9;
-#define lpfc_wqe_gen_request_tag_SHIFT 0
-#define lpfc_wqe_gen_request_tag_MASK 0x0000FFFF
-#define lpfc_wqe_gen_request_tag_WORD word9
- uint32_t word10;
-#define lpfc_wqe_gen_ccp_SHIFT 24
-#define lpfc_wqe_gen_ccp_MASK 0x000000FF
-#define lpfc_wqe_gen_ccp_WORD word10
-#define lpfc_wqe_gen_ccpe_SHIFT 23
-#define lpfc_wqe_gen_ccpe_MASK 0x00000001
-#define lpfc_wqe_gen_ccpe_WORD word10
-#define lpfc_wqe_gen_pv_SHIFT 19
-#define lpfc_wqe_gen_pv_MASK 0x00000001
-#define lpfc_wqe_gen_pv_WORD word10
-#define lpfc_wqe_gen_pri_SHIFT 16
-#define lpfc_wqe_gen_pri_MASK 0x00000007
-#define lpfc_wqe_gen_pri_WORD word10
- uint32_t word11;
-#define lpfc_wqe_gen_cq_id_SHIFT 16
-#define lpfc_wqe_gen_cq_id_MASK 0x0000FFFF
-#define lpfc_wqe_gen_cq_id_WORD word11
-#define LPFC_WQE_CQ_ID_DEFAULT 0xffff
-#define lpfc_wqe_gen_wqec_SHIFT 7
-#define lpfc_wqe_gen_wqec_MASK 0x00000001
-#define lpfc_wqe_gen_wqec_WORD word11
-#define ELS_ID_FLOGI 3
-#define ELS_ID_FDISC 2
-#define ELS_ID_LOGO 1
-#define ELS_ID_DEFAULT 0
-#define lpfc_wqe_gen_els_id_SHIFT 4
-#define lpfc_wqe_gen_els_id_MASK 0x00000003
-#define lpfc_wqe_gen_els_id_WORD word11
-#define lpfc_wqe_gen_cmd_type_SHIFT 0
-#define lpfc_wqe_gen_cmd_type_MASK 0x0000000F
-#define lpfc_wqe_gen_cmd_type_WORD word11
- uint32_t payload[4];
-};
-
struct lpfc_rqe {
uint32_t address_hi;
uint32_t address_lo;
@@ -523,35 +460,40 @@ struct lpfc_register {
uint32_t word0;
};
+/* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */
#define LPFC_UERR_STATUS_HI 0x00A4
#define LPFC_UERR_STATUS_LO 0x00A0
#define LPFC_UE_MASK_HI 0x00AC
#define LPFC_UE_MASK_LO 0x00A8
+
+/* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */
#define LPFC_SLI_INTF 0x0058
-/* BAR0 Registers */
-#define LPFC_HST_STATE 0x00AC
-#define lpfc_hst_state_perr_SHIFT 31
-#define lpfc_hst_state_perr_MASK 0x1
-#define lpfc_hst_state_perr_WORD word0
-#define lpfc_hst_state_sfi_SHIFT 30
-#define lpfc_hst_state_sfi_MASK 0x1
-#define lpfc_hst_state_sfi_WORD word0
-#define lpfc_hst_state_nip_SHIFT 29
-#define lpfc_hst_state_nip_MASK 0x1
-#define lpfc_hst_state_nip_WORD word0
-#define lpfc_hst_state_ipc_SHIFT 28
-#define lpfc_hst_state_ipc_MASK 0x1
-#define lpfc_hst_state_ipc_WORD word0
-#define lpfc_hst_state_xrom_SHIFT 27
-#define lpfc_hst_state_xrom_MASK 0x1
-#define lpfc_hst_state_xrom_WORD word0
-#define lpfc_hst_state_dl_SHIFT 26
-#define lpfc_hst_state_dl_MASK 0x1
-#define lpfc_hst_state_dl_WORD word0
-#define lpfc_hst_state_port_status_SHIFT 0
-#define lpfc_hst_state_port_status_MASK 0xFFFF
-#define lpfc_hst_state_port_status_WORD word0
+#define LPFC_SLIPORT_IF2_SMPHR 0x0400
+#define lpfc_port_smphr_perr_SHIFT 31
+#define lpfc_port_smphr_perr_MASK 0x1
+#define lpfc_port_smphr_perr_WORD word0
+#define lpfc_port_smphr_sfi_SHIFT 30
+#define lpfc_port_smphr_sfi_MASK 0x1
+#define lpfc_port_smphr_sfi_WORD word0
+#define lpfc_port_smphr_nip_SHIFT 29
+#define lpfc_port_smphr_nip_MASK 0x1
+#define lpfc_port_smphr_nip_WORD word0
+#define lpfc_port_smphr_ipc_SHIFT 28
+#define lpfc_port_smphr_ipc_MASK 0x1
+#define lpfc_port_smphr_ipc_WORD word0
+#define lpfc_port_smphr_scr1_SHIFT 27
+#define lpfc_port_smphr_scr1_MASK 0x1
+#define lpfc_port_smphr_scr1_WORD word0
+#define lpfc_port_smphr_scr2_SHIFT 26
+#define lpfc_port_smphr_scr2_MASK 0x1
+#define lpfc_port_smphr_scr2_WORD word0
+#define lpfc_port_smphr_host_scratch_SHIFT 16
+#define lpfc_port_smphr_host_scratch_MASK 0xFF
+#define lpfc_port_smphr_host_scratch_WORD word0
+#define lpfc_port_smphr_port_status_SHIFT 0
+#define lpfc_port_smphr_port_status_MASK 0xFFFF
+#define lpfc_port_smphr_port_status_WORD word0
#define LPFC_POST_STAGE_POWER_ON_RESET 0x0000
#define LPFC_POST_STAGE_AWAITING_HOST_RDY 0x0001
@@ -584,10 +526,46 @@ struct lpfc_register {
#define LPFC_POST_STAGE_RC_DONE 0x0B07
#define LPFC_POST_STAGE_REBOOT_SYSTEM 0x0B08
#define LPFC_POST_STAGE_MAC_ADDRESS 0x0C00
-#define LPFC_POST_STAGE_ARMFW_READY 0xC000
-#define LPFC_POST_STAGE_ARMFW_UE 0xF000
+#define LPFC_POST_STAGE_PORT_READY 0xC000
+#define LPFC_POST_STAGE_PORT_UE 0xF000
+
+#define LPFC_SLIPORT_STATUS 0x0404
+#define lpfc_sliport_status_err_SHIFT 31
+#define lpfc_sliport_status_err_MASK 0x1
+#define lpfc_sliport_status_err_WORD word0
+#define lpfc_sliport_status_end_SHIFT 30
+#define lpfc_sliport_status_end_MASK 0x1
+#define lpfc_sliport_status_end_WORD word0
+#define lpfc_sliport_status_oti_SHIFT 29
+#define lpfc_sliport_status_oti_MASK 0x1
+#define lpfc_sliport_status_oti_WORD word0
+#define lpfc_sliport_status_rn_SHIFT 24
+#define lpfc_sliport_status_rn_MASK 0x1
+#define lpfc_sliport_status_rn_WORD word0
+#define lpfc_sliport_status_rdy_SHIFT 23
+#define lpfc_sliport_status_rdy_MASK 0x1
+#define lpfc_sliport_status_rdy_WORD word0
+#define MAX_IF_TYPE_2_RESETS 1000
+
+#define LPFC_SLIPORT_CNTRL 0x0408
+#define lpfc_sliport_ctrl_end_SHIFT 30
+#define lpfc_sliport_ctrl_end_MASK 0x1
+#define lpfc_sliport_ctrl_end_WORD word0
+#define LPFC_SLIPORT_LITTLE_ENDIAN 0
+#define LPFC_SLIPORT_BIG_ENDIAN 1
+#define lpfc_sliport_ctrl_ip_SHIFT 27
+#define lpfc_sliport_ctrl_ip_MASK 0x1
+#define lpfc_sliport_ctrl_ip_WORD word0
+#define LPFC_SLIPORT_INIT_PORT 1
+
+#define LPFC_SLIPORT_ERR_1 0x040C
+#define LPFC_SLIPORT_ERR_2 0x0410
+
+/* The following Registers apply to SLI4 if_type 0 UCNAs. They typically
+ * reside in BAR 2.
+ */
+#define LPFC_SLIPORT_IF0_SMPHR 0x00AC
-/* BAR1 Registers */
#define LPFC_IMR_MASK_ALL 0xFFFFFFFF
#define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF
@@ -642,14 +620,21 @@ struct lpfc_register {
#define LPFC_SLI4_INTR30 BIT30
#define LPFC_SLI4_INTR31 BIT31
-/* BAR2 Registers */
+/*
+ * The Doorbell registers defined here exist in different BAR
+ * register sets depending on the UCNA Port's reported if_type
+ * value. For UCNA ports running SLI4 and if_type 0, they reside in
+ * BAR4. For UCNA ports running SLI4 and if_type 2, they reside in
+ * BAR0. The offsets are the same so the driver must account for
+ * any base address difference.
+ */
#define LPFC_RQ_DOORBELL 0x00A0
#define lpfc_rq_doorbell_num_posted_SHIFT 16
#define lpfc_rq_doorbell_num_posted_MASK 0x3FFF
#define lpfc_rq_doorbell_num_posted_WORD word0
#define LPFC_RQ_POST_BATCH 8 /* RQEs to post at one time */
#define lpfc_rq_doorbell_id_SHIFT 0
-#define lpfc_rq_doorbell_id_MASK 0x03FF
+#define lpfc_rq_doorbell_id_MASK 0xFFFF
#define lpfc_rq_doorbell_id_WORD word0
#define LPFC_WQ_DOORBELL 0x0040
@@ -664,6 +649,11 @@ struct lpfc_register {
#define lpfc_wq_doorbell_id_WORD word0
#define LPFC_EQCQ_DOORBELL 0x0120
+#define lpfc_eqcq_doorbell_se_SHIFT 31
+#define lpfc_eqcq_doorbell_se_MASK 0x0001
+#define lpfc_eqcq_doorbell_se_WORD word0
+#define LPFC_EQCQ_SOLICIT_ENABLE_OFF 0
+#define LPFC_EQCQ_SOLICIT_ENABLE_ON 1
#define lpfc_eqcq_doorbell_arm_SHIFT 29
#define lpfc_eqcq_doorbell_arm_MASK 0x0001
#define lpfc_eqcq_doorbell_arm_WORD word0
@@ -701,7 +691,7 @@ struct lpfc_register {
#define lpfc_mq_doorbell_num_posted_MASK 0x3FFF
#define lpfc_mq_doorbell_num_posted_WORD word0
#define lpfc_mq_doorbell_id_SHIFT 0
-#define lpfc_mq_doorbell_id_MASK 0x03FF
+#define lpfc_mq_doorbell_id_MASK 0xFFFF
#define lpfc_mq_doorbell_id_WORD word0
struct lpfc_sli4_cfg_mhdr {
@@ -1121,12 +1111,18 @@ struct lpfc_mbx_mq_create_ext {
#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK
#define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001
#define lpfc_mbx_mq_create_ext_async_evt_link_WORD async_evt_bmap
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT LPFC_TRAILER_CODE_FCOE
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK 0x00000001
-#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fip_SHIFT LPFC_TRAILER_CODE_FCOE
+#define lpfc_mbx_mq_create_ext_async_evt_fip_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fip_WORD async_evt_bmap
#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT LPFC_TRAILER_CODE_GRP5
#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK 0x00000001
#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fc_SHIFT LPFC_TRAILER_CODE_FC
+#define lpfc_mbx_mq_create_ext_async_evt_fc_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fc_WORD async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_sli_SHIFT LPFC_TRAILER_CODE_SLI
+#define lpfc_mbx_mq_create_ext_async_evt_sli_MASK 0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_sli_WORD async_evt_bmap
struct mq_context context;
struct dma_address page[LPFC_MAX_MQ_PAGE];
} request;
@@ -1380,7 +1376,7 @@ struct lpfc_mbx_query_fw_cfg {
#define lpfc_function_mode_dal_WORD function_mode
#define lpfc_function_mode_lro_SHIFT 9
#define lpfc_function_mode_lro_MASK 0x00000001
-#define lpfc_function_mode_lro_WORD function_mode9
+#define lpfc_function_mode_lro_WORD function_mode
#define lpfc_function_mode_flex10_SHIFT 10
#define lpfc_function_mode_flex10_MASK 0x00000001
#define lpfc_function_mode_flex10_WORD function_mode
@@ -1431,10 +1427,16 @@ struct lpfc_mbx_init_vfi {
#define lpfc_init_vfi_vf_SHIFT 29
#define lpfc_init_vfi_vf_MASK 0x00000001
#define lpfc_init_vfi_vf_WORD word1
+#define lpfc_init_vfi_vp_SHIFT 28
+#define lpfc_init_vfi_vp_MASK 0x00000001
+#define lpfc_init_vfi_vp_WORD word1
#define lpfc_init_vfi_vfi_SHIFT 0
#define lpfc_init_vfi_vfi_MASK 0x0000FFFF
#define lpfc_init_vfi_vfi_WORD word1
uint32_t word2;
+#define lpfc_init_vfi_vpi_SHIFT 16
+#define lpfc_init_vfi_vpi_MASK 0x0000FFFF
+#define lpfc_init_vfi_vpi_WORD word2
#define lpfc_init_vfi_fcfi_SHIFT 0
#define lpfc_init_vfi_fcfi_MASK 0x0000FFFF
#define lpfc_init_vfi_fcfi_WORD word2
@@ -2142,6 +2144,8 @@ struct lpfc_mcqe {
#define LPFC_TRAILER_CODE_FCOE 0x2
#define LPFC_TRAILER_CODE_DCBX 0x3
#define LPFC_TRAILER_CODE_GRP5 0x5
+#define LPFC_TRAILER_CODE_FC 0x10
+#define LPFC_TRAILER_CODE_SLI 0x11
};
struct lpfc_acqe_link {
@@ -2167,11 +2171,12 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_STATUS_UP 0x1
#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN 0x2
#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP 0x3
-#define lpfc_acqe_link_physical_SHIFT 0
-#define lpfc_acqe_link_physical_MASK 0x000000FF
-#define lpfc_acqe_link_physical_WORD word0
-#define LPFC_ASYNC_LINK_PORT_A 0x0
-#define LPFC_ASYNC_LINK_PORT_B 0x1
+#define lpfc_acqe_link_type_SHIFT 6
+#define lpfc_acqe_link_type_MASK 0x00000003
+#define lpfc_acqe_link_type_WORD word0
+#define lpfc_acqe_link_number_SHIFT 0
+#define lpfc_acqe_link_number_MASK 0x0000003F
+#define lpfc_acqe_link_number_WORD word0
uint32_t word1;
#define lpfc_acqe_link_fault_SHIFT 0
#define lpfc_acqe_link_fault_MASK 0x000000FF
@@ -2179,29 +2184,31 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_FAULT_NONE 0x0
#define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1
#define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2
-#define lpfc_acqe_qos_link_speed_SHIFT 16
-#define lpfc_acqe_qos_link_speed_MASK 0x0000FFFF
-#define lpfc_acqe_qos_link_speed_WORD word1
+#define lpfc_acqe_logical_link_speed_SHIFT 16
+#define lpfc_acqe_logical_link_speed_MASK 0x0000FFFF
+#define lpfc_acqe_logical_link_speed_WORD word1
uint32_t event_tag;
uint32_t trailer;
+#define LPFC_LINK_EVENT_TYPE_PHYSICAL 0x0
+#define LPFC_LINK_EVENT_TYPE_VIRTUAL 0x1
};
-struct lpfc_acqe_fcoe {
+struct lpfc_acqe_fip {
uint32_t index;
uint32_t word1;
-#define lpfc_acqe_fcoe_fcf_count_SHIFT 0
-#define lpfc_acqe_fcoe_fcf_count_MASK 0x0000FFFF
-#define lpfc_acqe_fcoe_fcf_count_WORD word1
-#define lpfc_acqe_fcoe_event_type_SHIFT 16
-#define lpfc_acqe_fcoe_event_type_MASK 0x0000FFFF
-#define lpfc_acqe_fcoe_event_type_WORD word1
-#define LPFC_FCOE_EVENT_TYPE_NEW_FCF 0x1
-#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2
-#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3
-#define LPFC_FCOE_EVENT_TYPE_CVL 0x4
-#define LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD 0x5
+#define lpfc_acqe_fip_fcf_count_SHIFT 0
+#define lpfc_acqe_fip_fcf_count_MASK 0x0000FFFF
+#define lpfc_acqe_fip_fcf_count_WORD word1
+#define lpfc_acqe_fip_event_type_SHIFT 16
+#define lpfc_acqe_fip_event_type_MASK 0x0000FFFF
+#define lpfc_acqe_fip_event_type_WORD word1
uint32_t event_tag;
uint32_t trailer;
+#define LPFC_FIP_EVENT_TYPE_NEW_FCF 0x1
+#define LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL 0x2
+#define LPFC_FIP_EVENT_TYPE_FCF_DEAD 0x3
+#define LPFC_FIP_EVENT_TYPE_CVL 0x4
+#define LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD 0x5
};
struct lpfc_acqe_dcbx {
@@ -2213,9 +2220,12 @@ struct lpfc_acqe_dcbx {
struct lpfc_acqe_grp5 {
uint32_t word0;
-#define lpfc_acqe_grp5_pport_SHIFT 0
-#define lpfc_acqe_grp5_pport_MASK 0x000000FF
-#define lpfc_acqe_grp5_pport_WORD word0
+#define lpfc_acqe_grp5_type_SHIFT 6
+#define lpfc_acqe_grp5_type_MASK 0x00000003
+#define lpfc_acqe_grp5_type_WORD word0
+#define lpfc_acqe_grp5_number_SHIFT 0
+#define lpfc_acqe_grp5_number_MASK 0x0000003F
+#define lpfc_acqe_grp5_number_WORD word0
uint32_t word1;
#define lpfc_acqe_grp5_llink_spd_SHIFT 16
#define lpfc_acqe_grp5_llink_spd_MASK 0x0000FFFF
@@ -2224,6 +2234,68 @@ struct lpfc_acqe_grp5 {
uint32_t trailer;
};
+struct lpfc_acqe_fc_la {
+ uint32_t word0;
+#define lpfc_acqe_fc_la_speed_SHIFT 24
+#define lpfc_acqe_fc_la_speed_MASK 0x000000FF
+#define lpfc_acqe_fc_la_speed_WORD word0
+#define LPFC_FC_LA_SPEED_UNKOWN 0x0
+#define LPFC_FC_LA_SPEED_1G 0x1
+#define LPFC_FC_LA_SPEED_2G 0x2
+#define LPFC_FC_LA_SPEED_4G 0x4
+#define LPFC_FC_LA_SPEED_8G 0x8
+#define LPFC_FC_LA_SPEED_10G 0xA
+#define LPFC_FC_LA_SPEED_16G 0x10
+#define lpfc_acqe_fc_la_topology_SHIFT 16
+#define lpfc_acqe_fc_la_topology_MASK 0x000000FF
+#define lpfc_acqe_fc_la_topology_WORD word0
+#define LPFC_FC_LA_TOP_UNKOWN 0x0
+#define LPFC_FC_LA_TOP_P2P 0x1
+#define LPFC_FC_LA_TOP_FCAL 0x2
+#define LPFC_FC_LA_TOP_INTERNAL_LOOP 0x3
+#define LPFC_FC_LA_TOP_SERDES_LOOP 0x4
+#define lpfc_acqe_fc_la_att_type_SHIFT 8
+#define lpfc_acqe_fc_la_att_type_MASK 0x000000FF
+#define lpfc_acqe_fc_la_att_type_WORD word0
+#define LPFC_FC_LA_TYPE_LINK_UP 0x1
+#define LPFC_FC_LA_TYPE_LINK_DOWN 0x2
+#define LPFC_FC_LA_TYPE_NO_HARD_ALPA 0x3
+#define lpfc_acqe_fc_la_port_type_SHIFT 6
+#define lpfc_acqe_fc_la_port_type_MASK 0x00000003
+#define lpfc_acqe_fc_la_port_type_WORD word0
+#define LPFC_LINK_TYPE_ETHERNET 0x0
+#define LPFC_LINK_TYPE_FC 0x1
+#define lpfc_acqe_fc_la_port_number_SHIFT 0
+#define lpfc_acqe_fc_la_port_number_MASK 0x0000003F
+#define lpfc_acqe_fc_la_port_number_WORD word0
+ uint32_t word1;
+#define lpfc_acqe_fc_la_llink_spd_SHIFT 16
+#define lpfc_acqe_fc_la_llink_spd_MASK 0x0000FFFF
+#define lpfc_acqe_fc_la_llink_spd_WORD word1
+#define lpfc_acqe_fc_la_fault_SHIFT 0
+#define lpfc_acqe_fc_la_fault_MASK 0x000000FF
+#define lpfc_acqe_fc_la_fault_WORD word1
+#define LPFC_FC_LA_FAULT_NONE 0x0
+#define LPFC_FC_LA_FAULT_LOCAL 0x1
+#define LPFC_FC_LA_FAULT_REMOTE 0x2
+ uint32_t event_tag;
+ uint32_t trailer;
+#define LPFC_FC_LA_EVENT_TYPE_FC_LINK 0x1
+#define LPFC_FC_LA_EVENT_TYPE_SHARED_LINK 0x2
+};
+
+struct lpfc_acqe_sli {
+ uint32_t event_data1;
+ uint32_t event_data2;
+ uint32_t reserved;
+ uint32_t trailer;
+#define LPFC_SLI_EVENT_TYPE_PORT_ERROR 0x1
+#define LPFC_SLI_EVENT_TYPE_OVER_TEMP 0x2
+#define LPFC_SLI_EVENT_TYPE_NORM_TEMP 0x3
+#define LPFC_SLI_EVENT_TYPE_NVLOG_POST 0x4
+#define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5
+};
+
/*
* Define the bootstrap mailbox (bmbx) region used to communicate
* mailbox command between the host and port. The mailbox consists
@@ -2279,9 +2351,36 @@ struct wqe_common {
#define wqe_reqtag_MASK 0x0000FFFF
#define wqe_reqtag_WORD word9
#define wqe_rcvoxid_SHIFT 16
-#define wqe_rcvoxid_MASK 0x0000FFFF
-#define wqe_rcvoxid_WORD word9
+#define wqe_rcvoxid_MASK 0x0000FFFF
+#define wqe_rcvoxid_WORD word9
uint32_t word10;
+#define wqe_ebde_cnt_SHIFT 0
+#define wqe_ebde_cnt_MASK 0x0000000f
+#define wqe_ebde_cnt_WORD word10
+#define wqe_lenloc_SHIFT 7
+#define wqe_lenloc_MASK 0x00000003
+#define wqe_lenloc_WORD word10
+#define LPFC_WQE_LENLOC_NONE 0
+#define LPFC_WQE_LENLOC_WORD3 1
+#define LPFC_WQE_LENLOC_WORD12 2
+#define LPFC_WQE_LENLOC_WORD4 3
+#define wqe_qosd_SHIFT 9
+#define wqe_qosd_MASK 0x00000001
+#define wqe_qosd_WORD word10
+#define wqe_xbl_SHIFT 11
+#define wqe_xbl_MASK 0x00000001
+#define wqe_xbl_WORD word10
+#define wqe_iod_SHIFT 13
+#define wqe_iod_MASK 0x00000001
+#define wqe_iod_WORD word10
+#define LPFC_WQE_IOD_WRITE 0
+#define LPFC_WQE_IOD_READ 1
+#define wqe_dbde_SHIFT 14
+#define wqe_dbde_MASK 0x00000001
+#define wqe_dbde_WORD word10
+#define wqe_wqes_SHIFT 15
+#define wqe_wqes_MASK 0x00000001
+#define wqe_wqes_WORD word10
#define wqe_pri_SHIFT 16
#define wqe_pri_MASK 0x00000007
#define wqe_pri_WORD word10
@@ -2295,18 +2394,26 @@ struct wqe_common {
#define wqe_ccpe_MASK 0x00000001
#define wqe_ccpe_WORD word10
#define wqe_ccp_SHIFT 24
-#define wqe_ccp_MASK 0x000000ff
-#define wqe_ccp_WORD word10
+#define wqe_ccp_MASK 0x000000ff
+#define wqe_ccp_WORD word10
uint32_t word11;
-#define wqe_cmd_type_SHIFT 0
-#define wqe_cmd_type_MASK 0x0000000f
-#define wqe_cmd_type_WORD word11
-#define wqe_wqec_SHIFT 7
-#define wqe_wqec_MASK 0x00000001
-#define wqe_wqec_WORD word11
-#define wqe_cqid_SHIFT 16
-#define wqe_cqid_MASK 0x0000ffff
-#define wqe_cqid_WORD word11
+#define wqe_cmd_type_SHIFT 0
+#define wqe_cmd_type_MASK 0x0000000f
+#define wqe_cmd_type_WORD word11
+#define wqe_els_id_SHIFT 4
+#define wqe_els_id_MASK 0x00000003
+#define wqe_els_id_WORD word11
+#define LPFC_ELS_ID_FLOGI 3
+#define LPFC_ELS_ID_FDISC 2
+#define LPFC_ELS_ID_LOGO 1
+#define LPFC_ELS_ID_DEFAULT 0
+#define wqe_wqec_SHIFT 7
+#define wqe_wqec_MASK 0x00000001
+#define wqe_wqec_WORD word11
+#define wqe_cqid_SHIFT 16
+#define wqe_cqid_MASK 0x0000ffff
+#define wqe_cqid_WORD word11
+#define LPFC_WQE_CQ_ID_DEFAULT 0xffff
};
struct wqe_did {
@@ -2325,6 +2432,15 @@ struct wqe_did {
#define wqe_xmit_bls_xo_WORD word5
};
+struct lpfc_wqe_generic{
+ struct ulp_bde64 bde;
+ uint32_t word3;
+ uint32_t word4;
+ uint32_t word5;
+ struct wqe_common wqe_com;
+ uint32_t payload[4];
+};
+
struct els_request64_wqe {
struct ulp_bde64 bde;
uint32_t payload_len;
@@ -2356,9 +2472,9 @@ struct els_request64_wqe {
struct xmit_els_rsp64_wqe {
struct ulp_bde64 bde;
- uint32_t rsvd3;
+ uint32_t response_payload_len;
uint32_t rsvd4;
- struct wqe_did wqe_dest;
+ struct wqe_did wqe_dest;
struct wqe_common wqe_com; /* words 6-11 */
uint32_t rsvd_12_15[4];
};
@@ -2427,17 +2543,16 @@ struct wqe_rctl_dfctl {
struct xmit_seq64_wqe {
struct ulp_bde64 bde;
- uint32_t paylaod_offset;
+ uint32_t rsvd3;
uint32_t relative_offset;
struct wqe_rctl_dfctl wge_ctl;
struct wqe_common wqe_com; /* words 6-11 */
- /* Note: word10 different REVISIT */
uint32_t xmit_len;
uint32_t rsvd_12_15[3];
};
struct xmit_bcast64_wqe {
struct ulp_bde64 bde;
- uint32_t paylaod_len;
+ uint32_t seq_payload_len;
uint32_t rsvd4;
struct wqe_rctl_dfctl wge_ctl; /* word 5 */
struct wqe_common wqe_com; /* words 6-11 */
@@ -2446,8 +2561,8 @@ struct xmit_bcast64_wqe {
struct gen_req64_wqe {
struct ulp_bde64 bde;
- uint32_t command_len;
- uint32_t payload_len;
+ uint32_t request_payload_len;
+ uint32_t relative_offset;
struct wqe_rctl_dfctl wge_ctl; /* word 5 */
struct wqe_common wqe_com; /* words 6-11 */
uint32_t rsvd_12_15[4];
@@ -2480,7 +2595,7 @@ struct abort_cmd_wqe {
struct fcp_iwrite64_wqe {
struct ulp_bde64 bde;
- uint32_t payload_len;
+ uint32_t payload_offset_len;
uint32_t total_xfer_len;
uint32_t initial_xfer_len;
struct wqe_common wqe_com; /* words 6-11 */
@@ -2489,7 +2604,7 @@ struct fcp_iwrite64_wqe {
struct fcp_iread64_wqe {
struct ulp_bde64 bde;
- uint32_t payload_len; /* word 3 */
+ uint32_t payload_offset_len; /* word 3 */
uint32_t total_xfer_len; /* word 4 */
uint32_t rsrvd5; /* word 5 */
struct wqe_common wqe_com; /* words 6-11 */
@@ -2497,10 +2612,12 @@ struct fcp_iread64_wqe {
};
struct fcp_icmnd64_wqe {
- struct ulp_bde64 bde; /* words 0-2 */
- uint32_t rsrvd[3]; /* words 3-5 */
+ struct ulp_bde64 bde; /* words 0-2 */
+ uint32_t rsrvd3; /* word 3 */
+ uint32_t rsrvd4; /* word 4 */
+ uint32_t rsrvd5; /* word 5 */
struct wqe_common wqe_com; /* words 6-11 */
- uint32_t rsvd_12_15[4]; /* word 12-15 */
+ uint32_t rsvd_12_15[4]; /* word 12-15 */
};
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 295c7ddb36c1..6d0b36aa3389 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -446,23 +446,25 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/* Get the default values for Model Name and Description */
lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
- if ((phba->cfg_link_speed > LINK_SPEED_10G)
- || ((phba->cfg_link_speed == LINK_SPEED_1G)
+ if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_16G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G)
&& !(phba->lmt & LMT_1Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_2G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G)
&& !(phba->lmt & LMT_2Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_4G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G)
&& !(phba->lmt & LMT_4Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_8G)
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G)
&& !(phba->lmt & LMT_8Gb))
- || ((phba->cfg_link_speed == LINK_SPEED_10G)
- && !(phba->lmt & LMT_10Gb))) {
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G)
+ && !(phba->lmt & LMT_10Gb))
+ || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G)
+ && !(phba->lmt & LMT_16Gb))) {
/* Reset link speed to auto */
lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
"1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
phba->cfg_link_speed);
- phba->cfg_link_speed = LINK_SPEED_AUTO;
+ phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
}
phba->link_state = LPFC_LINK_DOWN;
@@ -648,22 +650,23 @@ lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
mb = &pmb->u.mb;
pmb->vport = vport;
- lpfc_init_link(phba, pmb, phba->cfg_topology,
- phba->cfg_link_speed);
+ lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
rc = lpfc_sli_issue_mbox(phba, pmb, flag);
- if (rc != MBX_SUCCESS) {
+ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0498 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
- /* Clear all interrupt enable conditions */
- writel(0, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- /* Clear all pending interrupts */
- writel(0xffffffff, phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
+ if (phba->sli_rev <= LPFC_SLI_REV3) {
+ /* Clear all interrupt enable conditions */
+ writel(0, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ /* Clear all pending interrupts */
+ writel(0xffffffff, phba->HAregaddr);
+ readl(phba->HAregaddr); /* flush */
+ }
phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY || flag == MBX_POLL)
mempool_free(pmb, phba->mbox_mem_pool);
@@ -813,6 +816,7 @@ lpfc_hba_down_post_s3(struct lpfc_hba *phba)
return 0;
}
+
/**
* lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset
* @phba: pointer to lpfc HBA data structure.
@@ -926,6 +930,35 @@ lpfc_hb_timeout(unsigned long ptr)
}
/**
+ * lpfc_rrq_timeout - The RRQ-timer timeout handler
+ * @ptr: unsigned long holds the pointer to lpfc hba data structure.
+ *
+ * This is the RRQ-timer timeout handler registered to the lpfc driver. When
+ * this timer fires, a RRQ timeout event shall be posted to the lpfc driver
+ * work-port-events bitmap and the worker thread is notified. This timeout
+ * event will be used by the worker thread to invoke the actual timeout
+ * handler routine, lpfc_rrq_handler. Any periodical operations will
+ * be performed in the timeout handler and the RRQ timeout event bit shall
+ * be cleared by the worker thread after it has taken the event bitmap out.
+ **/
+static void
+lpfc_rrq_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba;
+ uint32_t tmo_posted;
+ unsigned long iflag;
+
+ phba = (struct lpfc_hba *)ptr;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ tmo_posted = phba->hba_flag & HBA_RRQ_ACTIVE;
+ if (!tmo_posted)
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+}
+
+/**
* lpfc_hb_mbox_cmpl - The lpfc heart-beat mailbox command callback function
* @phba: pointer to lpfc hba data structure.
* @pmboxq: pointer to the driver internal queue element for mailbox command.
@@ -1373,6 +1406,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
struct lpfc_vport *vport = phba->pport;
uint32_t event_data;
struct Scsi_Host *shost;
+ uint32_t if_type;
+ struct lpfc_register portstat_reg;
/* If the pci channel is offline, ignore possible errors, since
* we cannot communicate with the pci card anyway.
@@ -1389,17 +1424,49 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
/* For now, the actual action for SLI4 device handling is not
* specified yet, just treated it as adaptor hardware failure
*/
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0143 SLI4 Adapter Hardware Error Data: x%x x%x\n",
- phba->work_status[0], phba->work_status[1]);
-
event_data = FC_REG_DUMP_EVENT;
shost = lpfc_shost_from_vport(vport);
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(event_data), (char *) &event_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
- lpfc_sli4_offline_eratt(phba);
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ lpfc_sli4_offline_eratt(phba);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ portstat_reg.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+
+ if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) {
+ /* TODO: Register for Overtemp async events. */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2889 Port Overtemperature event, "
+ "taking port\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->over_temp_state = HBA_OVER_TEMP;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_offline_eratt(phba);
+ return;
+ }
+ if (bf_get(lpfc_sliport_status_rn, &portstat_reg)) {
+ /*
+ * TODO: Attempt port recovery via a port reset.
+ * When fully implemented, the driver should
+ * attempt to recover the port here and return.
+ * For now, log an error and take the port offline.
+ */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2887 Port Error: Attempting "
+ "Port Recovery\n");
+ }
+ lpfc_sli4_offline_eratt(phba);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
+ }
}
/**
@@ -1458,8 +1525,8 @@ lpfc_handle_latt(struct lpfc_hba *phba)
lpfc_els_flush_all_cmd(phba);
psli->slistat.link_event++;
- lpfc_read_la(phba, pmb, mp);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = vport;
/* Block ELS IOCBs until we have processed this mbox command */
phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
@@ -1852,6 +1919,14 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
"Fibre Channel Adapter"};
break;
+ case PCI_DEVICE_ID_LANCER_FC:
+ oneConnect = 1;
+ m = (typeof(m)){"Undefined", "PCIe", "Fibre Channel Adapter"};
+ break;
+ case PCI_DEVICE_ID_LANCER_FCOE:
+ oneConnect = 1;
+ m = (typeof(m)){"Undefined", "PCIe", "FCoE"};
+ break;
default:
m = (typeof(m)){"Unknown", "", ""};
break;
@@ -2234,10 +2309,9 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
void
__lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
{
- /* Clear pending FCF rediscovery wait and failover in progress flags */
- phba->fcf.fcf_flag &= ~(FCF_REDISC_PEND |
- FCF_DEAD_DISC |
- FCF_ACVL_DISC);
+ /* Clear pending FCF rediscovery wait flag */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
+
/* Now, try to stop the timer */
del_timer(&phba->fcf.redisc_wait);
}
@@ -2261,6 +2335,8 @@ lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
return;
}
__lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
+ /* Clear failover in progress flags */
+ phba->fcf.fcf_flag &= ~(FCF_DEAD_DISC | FCF_ACVL_DISC);
spin_unlock_irq(&phba->hbalock);
}
@@ -2935,70 +3011,12 @@ lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr)
phba->fcf.fcf_flag |= FCF_REDISC_EVT;
spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2776 FCF rediscover wait timer expired, post "
- "a worker thread event for FCF table scan\n");
+ "2776 FCF rediscover quiescent timer expired\n");
/* wake up worker thread */
lpfc_worker_wake_up(phba);
}
/**
- * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support
- * @phba: pointer to lpfc hba data structure.
- *
- * This function uses the QUERY_FW_CFG mailbox command to determine if the
- * firmware loaded supports FCoE. A return of zero indicates that the mailbox
- * was successful and the firmware supports FCoE. Any other return indicates
- * a error. It is assumed that this function will be called before interrupts
- * are enabled.
- **/
-static int
-lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba)
-{
- int rc = 0;
- LPFC_MBOXQ_t *mboxq;
- struct lpfc_mbx_query_fw_cfg *query_fw_cfg;
- uint32_t length;
- uint32_t shdr_status, shdr_add_status;
-
- mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2621 Failed to allocate mbox for "
- "query firmware config cmd\n");
- return -ENOMEM;
- }
- query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg;
- length = (sizeof(struct lpfc_mbx_query_fw_cfg) -
- sizeof(struct lpfc_sli4_cfg_mhdr));
- lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
- LPFC_MBOX_OPCODE_QUERY_FW_CFG,
- length, LPFC_SLI4_MBX_EMBED);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- /* The IOCTL status is embedded in the mailbox subheader. */
- shdr_status = bf_get(lpfc_mbox_hdr_status,
- &query_fw_cfg->header.cfg_shdr.response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
- &query_fw_cfg->header.cfg_shdr.response);
- if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2622 Query Firmware Config failed "
- "mbx status x%x, status x%x add_status x%x\n",
- rc, shdr_status, shdr_add_status);
- return -EINVAL;
- }
- if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2623 FCoE Function not supported by firmware. "
- "Function mode = %08x\n",
- query_fw_cfg->function_mode);
- return -EINVAL;
- }
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- return 0;
-}
-
-/**
* lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async link completion queue entry.
@@ -3050,20 +3068,20 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
switch (bf_get(lpfc_acqe_link_status, acqe_link)) {
case LPFC_ASYNC_LINK_STATUS_DOWN:
case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN:
- att_type = AT_LINK_DOWN;
+ att_type = LPFC_ATT_LINK_DOWN;
break;
case LPFC_ASYNC_LINK_STATUS_UP:
/* Ignore physical link up events - wait for logical link up */
- att_type = AT_RESERVED;
+ att_type = LPFC_ATT_RESERVED;
break;
case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP:
- att_type = AT_LINK_UP;
+ att_type = LPFC_ATT_LINK_UP;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0399 Invalid link attention type: x%x\n",
bf_get(lpfc_acqe_link_status, acqe_link));
- att_type = AT_RESERVED;
+ att_type = LPFC_ATT_RESERVED;
break;
}
return att_type;
@@ -3087,36 +3105,32 @@ lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
case LPFC_ASYNC_LINK_SPEED_ZERO:
- link_speed = LA_UNKNW_LINK;
- break;
case LPFC_ASYNC_LINK_SPEED_10MBPS:
- link_speed = LA_UNKNW_LINK;
- break;
case LPFC_ASYNC_LINK_SPEED_100MBPS:
- link_speed = LA_UNKNW_LINK;
+ link_speed = LPFC_LINK_SPEED_UNKNOWN;
break;
case LPFC_ASYNC_LINK_SPEED_1GBPS:
- link_speed = LA_1GHZ_LINK;
+ link_speed = LPFC_LINK_SPEED_1GHZ;
break;
case LPFC_ASYNC_LINK_SPEED_10GBPS:
- link_speed = LA_10GHZ_LINK;
+ link_speed = LPFC_LINK_SPEED_10GHZ;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0483 Invalid link-attention link speed: x%x\n",
bf_get(lpfc_acqe_link_speed, acqe_link));
- link_speed = LA_UNKNW_LINK;
+ link_speed = LPFC_LINK_SPEED_UNKNOWN;
break;
}
return link_speed;
}
/**
- * lpfc_sli4_async_link_evt - Process the asynchronous link event
+ * lpfc_sli4_async_link_evt - Process the asynchronous FCoE link event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async link completion queue entry.
*
- * This routine is to handle the SLI4 asynchronous link event.
+ * This routine is to handle the SLI4 asynchronous FCoE link event.
**/
static void
lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
@@ -3125,11 +3139,12 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
struct lpfc_dmabuf *mp;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
- READ_LA_VAR *la;
+ struct lpfc_mbx_read_top *la;
uint8_t att_type;
+ int rc;
att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
- if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
+ if (att_type != LPFC_ATT_LINK_DOWN && att_type != LPFC_ATT_LINK_UP)
return;
phba->fcoe_eventtag = acqe_link->event_tag;
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -3160,45 +3175,168 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
/* Update link event statistics */
phba->sli.slistat.link_event++;
- /* Create pseudo lpfc_handle_latt mailbox command from link ACQE */
- lpfc_read_la(phba, pmb, mp);
+ /* Create lpfc_handle_latt mailbox command from link ACQE */
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = phba->pport;
+ /* Keep the link status for extra SLI4 state machine reference */
+ phba->sli4_hba.link_state.speed =
+ bf_get(lpfc_acqe_link_speed, acqe_link);
+ phba->sli4_hba.link_state.duplex =
+ bf_get(lpfc_acqe_link_duplex, acqe_link);
+ phba->sli4_hba.link_state.status =
+ bf_get(lpfc_acqe_link_status, acqe_link);
+ phba->sli4_hba.link_state.type =
+ bf_get(lpfc_acqe_link_type, acqe_link);
+ phba->sli4_hba.link_state.number =
+ bf_get(lpfc_acqe_link_number, acqe_link);
+ phba->sli4_hba.link_state.fault =
+ bf_get(lpfc_acqe_link_fault, acqe_link);
+ phba->sli4_hba.link_state.logical_speed =
+ bf_get(lpfc_acqe_logical_link_speed, acqe_link);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2900 Async FCoE Link event - Speed:%dGBit duplex:x%x "
+ "LA Type:x%x Port Type:%d Port Number:%d Logical "
+ "speed:%dMbps Fault:%d\n",
+ phba->sli4_hba.link_state.speed,
+ phba->sli4_hba.link_state.topology,
+ phba->sli4_hba.link_state.status,
+ phba->sli4_hba.link_state.type,
+ phba->sli4_hba.link_state.number,
+ phba->sli4_hba.link_state.logical_speed * 10,
+ phba->sli4_hba.link_state.fault);
+ /*
+ * For FC Mode: issue the READ_TOPOLOGY mailbox command to fetch
+ * topology info. Note: Optional for non FC-AL ports.
+ */
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_dmabuf;
+ return;
+ }
+ /*
+ * For FCoE Mode: fill in all the topology information we need and call
+ * the READ_TOPOLOGY completion routine to continue without actually
+ * sending the READ_TOPOLOGY mailbox command to the port.
+ */
/* Parse and translate status field */
mb = &pmb->u.mb;
mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link);
/* Parse and translate link attention fields */
- la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+ la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
la->eventTag = acqe_link->event_tag;
- la->attType = att_type;
- la->UlnkSpeed = lpfc_sli4_parse_latt_link_speed(phba, acqe_link);
+ bf_set(lpfc_mbx_read_top_att_type, la, att_type);
+ bf_set(lpfc_mbx_read_top_link_spd, la,
+ lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
/* Fake the the following irrelvant fields */
- la->topology = TOPOLOGY_PT_PT;
- la->granted_AL_PA = 0;
- la->il = 0;
- la->pb = 0;
- la->fa = 0;
- la->mm = 0;
+ bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
+ bf_set(lpfc_mbx_read_top_alpa_granted, la, 0);
+ bf_set(lpfc_mbx_read_top_il, la, 0);
+ bf_set(lpfc_mbx_read_top_pb, la, 0);
+ bf_set(lpfc_mbx_read_top_fa, la, 0);
+ bf_set(lpfc_mbx_read_top_mm, la, 0);
+
+ /* Invoke the lpfc_handle_latt mailbox command callback function */
+ lpfc_mbx_cmpl_read_topology(phba, pmb);
+
+ return;
+out_free_dmabuf:
+ kfree(mp);
+out_free_pmb:
+ mempool_free(pmb, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_async_fc_evt - Process the asynchronous FC link event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_fc: pointer to the async fc completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous FC event. It will simply log
+ * that the event was received and then issue a read_topology mailbox command so
+ * that the rest of the driver will treat it the same as SLI3.
+ **/
+static void
+lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
+{
+ struct lpfc_dmabuf *mp;
+ LPFC_MBOXQ_t *pmb;
+ int rc;
+
+ if (bf_get(lpfc_trailer_type, acqe_fc) !=
+ LPFC_FC_LA_EVENT_TYPE_FC_LINK) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2895 Non FC link Event detected.(%d)\n",
+ bf_get(lpfc_trailer_type, acqe_fc));
+ return;
+ }
/* Keep the link status for extra SLI4 state machine reference */
phba->sli4_hba.link_state.speed =
- bf_get(lpfc_acqe_link_speed, acqe_link);
- phba->sli4_hba.link_state.duplex =
- bf_get(lpfc_acqe_link_duplex, acqe_link);
+ bf_get(lpfc_acqe_fc_la_speed, acqe_fc);
+ phba->sli4_hba.link_state.duplex = LPFC_ASYNC_LINK_DUPLEX_FULL;
+ phba->sli4_hba.link_state.topology =
+ bf_get(lpfc_acqe_fc_la_topology, acqe_fc);
phba->sli4_hba.link_state.status =
- bf_get(lpfc_acqe_link_status, acqe_link);
- phba->sli4_hba.link_state.physical =
- bf_get(lpfc_acqe_link_physical, acqe_link);
+ bf_get(lpfc_acqe_fc_la_att_type, acqe_fc);
+ phba->sli4_hba.link_state.type =
+ bf_get(lpfc_acqe_fc_la_port_type, acqe_fc);
+ phba->sli4_hba.link_state.number =
+ bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
phba->sli4_hba.link_state.fault =
- bf_get(lpfc_acqe_link_fault, acqe_link);
+ bf_get(lpfc_acqe_link_fault, acqe_fc);
phba->sli4_hba.link_state.logical_speed =
- bf_get(lpfc_acqe_qos_link_speed, acqe_link);
+ bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2896 Async FC event - Speed:%dGBaud Topology:x%x "
+ "LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
+ "%dMbps Fault:%d\n",
+ phba->sli4_hba.link_state.speed,
+ phba->sli4_hba.link_state.topology,
+ phba->sli4_hba.link_state.status,
+ phba->sli4_hba.link_state.type,
+ phba->sli4_hba.link_state.number,
+ phba->sli4_hba.link_state.logical_speed * 10,
+ phba->sli4_hba.link_state.fault);
+ pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2897 The mboxq allocation failed\n");
+ return;
+ }
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!mp) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2898 The lpfc_dmabuf allocation failed\n");
+ goto out_free_pmb;
+ }
+ mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+ if (!mp->virt) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2899 The mbuf allocation failed\n");
+ goto out_free_dmabuf;
+ }
- /* Invoke the lpfc_handle_latt mailbox command callback function */
- lpfc_mbx_cmpl_read_la(phba, pmb);
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_all_cmd(phba);
+ /* Block ELS IOCBs until we have done process link event */
+ phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
+
+ /* Update link event statistics */
+ phba->sli.slistat.link_event++;
+
+ /* Create lpfc_handle_latt mailbox command from link ACQE */
+ lpfc_read_topology(phba, pmb, mp);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
+ pmb->vport = phba->pport;
+
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_dmabuf;
return;
out_free_dmabuf:
@@ -3208,6 +3346,24 @@ out_free_pmb:
}
/**
+ * lpfc_sli4_async_sli_evt - Process the asynchronous SLI link event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_fc: pointer to the async SLI completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous SLI events.
+ **/
+static void
+lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
+{
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+ "x%08x SLI Event Type:%d",
+ acqe_sli->event_data1, acqe_sli->event_data2,
+ bf_get(lpfc_trailer_type, acqe_sli));
+ return;
+}
+
+/**
* lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport
* @vport: pointer to vport data structure.
*
@@ -3246,10 +3402,12 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
if (!ndlp)
return 0;
}
- if (phba->pport->port_state < LPFC_FLOGI)
+ if ((phba->pport->port_state < LPFC_FLOGI) &&
+ (phba->pport->port_state != LPFC_VPORT_FAILED))
return NULL;
/* If virtual link is not yet instantiated ignore CVL */
- if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC))
+ if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC)
+ && (vport->port_state != LPFC_VPORT_FAILED))
return NULL;
shost = lpfc_shost_from_vport(vport);
if (!shost)
@@ -3284,17 +3442,17 @@ lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
}
/**
- * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
+ * lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async fcoe completion queue entry.
*
* This routine is to handle the SLI4 asynchronous fcoe event.
**/
static void
-lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
- struct lpfc_acqe_fcoe *acqe_fcoe)
+lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
+ struct lpfc_acqe_fip *acqe_fip)
{
- uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
+ uint8_t event_type = bf_get(lpfc_trailer_type, acqe_fip);
int rc;
struct lpfc_vport *vport;
struct lpfc_nodelist *ndlp;
@@ -3303,43 +3461,42 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
struct lpfc_vport **vports;
int i;
- phba->fc_eventTag = acqe_fcoe->event_tag;
- phba->fcoe_eventtag = acqe_fcoe->event_tag;
+ phba->fc_eventTag = acqe_fip->event_tag;
+ phba->fcoe_eventtag = acqe_fip->event_tag;
switch (event_type) {
- case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
- case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
- if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
+ case LPFC_FIP_EVENT_TYPE_NEW_FCF:
+ case LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD:
+ if (event_type == LPFC_FIP_EVENT_TYPE_NEW_FCF)
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
LOG_DISCOVERY,
- "2546 New FCF found event: "
- "evt_tag:x%x, fcf_index:x%x\n",
- acqe_fcoe->event_tag,
- acqe_fcoe->index);
+ "2546 New FCF event, evt_tag:x%x, "
+ "index:x%x\n",
+ acqe_fip->event_tag,
+ acqe_fip->index);
else
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
LOG_DISCOVERY,
- "2788 FCF parameter modified event: "
- "evt_tag:x%x, fcf_index:x%x\n",
- acqe_fcoe->event_tag,
- acqe_fcoe->index);
+ "2788 FCF param modified event, "
+ "evt_tag:x%x, index:x%x\n",
+ acqe_fip->event_tag,
+ acqe_fip->index);
if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
/*
* During period of FCF discovery, read the FCF
* table record indexed by the event to update
- * FCF round robin failover eligible FCF bmask.
+ * FCF roundrobin failover eligible FCF bmask.
*/
lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
LOG_DISCOVERY,
- "2779 Read new FCF record with "
- "fcf_index:x%x for updating FCF "
- "round robin failover bmask\n",
- acqe_fcoe->index);
- rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
+ "2779 Read FCF (x%x) for updating "
+ "roundrobin FCF failover bmask\n",
+ acqe_fip->index);
+ rc = lpfc_sli4_read_fcf_rec(phba, acqe_fip->index);
}
/* If the FCF discovery is in progress, do nothing. */
spin_lock_irq(&phba->hbalock);
- if (phba->hba_flag & FCF_DISC_INPROGRESS) {
+ if (phba->hba_flag & FCF_TS_INPROG) {
spin_unlock_irq(&phba->hbalock);
break;
}
@@ -3358,29 +3515,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
/* Otherwise, scan the entire FCF table and re-discover SAN */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
- "2770 Start FCF table scan due to new FCF "
- "event: evt_tag:x%x, fcf_index:x%x\n",
- acqe_fcoe->event_tag, acqe_fcoe->index);
+ "2770 Start FCF table scan per async FCF "
+ "event, evt_tag:x%x, index:x%x\n",
+ acqe_fip->event_tag, acqe_fip->index);
rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
LPFC_FCOE_FCF_GET_FIRST);
if (rc)
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
"2547 Issue FCF scan read FCF mailbox "
- "command failed 0x%x\n", rc);
+ "command failed (x%x)\n", rc);
break;
- case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
+ case LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2548 FCF Table full count 0x%x tag 0x%x\n",
- bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
- acqe_fcoe->event_tag);
+ bf_get(lpfc_acqe_fip_fcf_count, acqe_fip),
+ acqe_fip->event_tag);
break;
- case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
+ case LPFC_FIP_EVENT_TYPE_FCF_DEAD:
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
- "2549 FCF disconnected from network index 0x%x"
- " tag 0x%x\n", acqe_fcoe->index,
- acqe_fcoe->event_tag);
+ "2549 FCF (x%x) disconnected from network, "
+ "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag);
/*
* If we are in the middle of FCF failover process, clear
* the corresponding FCF bit in the roundrobin bitmap.
@@ -3389,13 +3545,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
spin_unlock_irq(&phba->hbalock);
/* Update FLOGI FCF failover eligible FCF bmask */
- lpfc_sli4_fcf_rr_index_clear(phba, acqe_fcoe->index);
+ lpfc_sli4_fcf_rr_index_clear(phba, acqe_fip->index);
break;
}
spin_unlock_irq(&phba->hbalock);
/* If the event is not for currently used fcf do nothing */
- if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index)
+ if (phba->fcf.current_rec.fcf_indx != acqe_fip->index)
break;
/*
@@ -3412,7 +3568,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2771 Start FCF fast failover process due to "
"FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
- "\n", acqe_fcoe->event_tag, acqe_fcoe->index);
+ "\n", acqe_fip->event_tag, acqe_fip->index);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
@@ -3439,12 +3595,12 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
lpfc_sli4_perform_all_vport_cvl(phba);
}
break;
- case LPFC_FCOE_EVENT_TYPE_CVL:
+ case LPFC_FIP_EVENT_TYPE_CVL:
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
"2718 Clear Virtual Link Received for VPI 0x%x"
- " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
+ " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
vport = lpfc_find_vport_by_vpid(phba,
- acqe_fcoe->index - phba->vpi_base);
+ acqe_fip->index - phba->vpi_base);
ndlp = lpfc_sli4_perform_vport_cvl(vport);
if (!ndlp)
break;
@@ -3494,9 +3650,8 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
LOG_DISCOVERY,
- "2773 Start FCF fast failover due "
- "to CVL event: evt_tag:x%x\n",
- acqe_fcoe->event_tag);
+ "2773 Start FCF failover per CVL, "
+ "evt_tag:x%x\n", acqe_fip->event_tag);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
@@ -3524,7 +3679,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
default:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0288 Unknown FCoE event type 0x%x event tag "
- "0x%x\n", event_type, acqe_fcoe->event_tag);
+ "0x%x\n", event_type, acqe_fip->event_tag);
break;
}
}
@@ -3601,8 +3756,7 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
&cq_event->cqe.acqe_link);
break;
case LPFC_TRAILER_CODE_FCOE:
- lpfc_sli4_async_fcoe_evt(phba,
- &cq_event->cqe.acqe_fcoe);
+ lpfc_sli4_async_fip_evt(phba, &cq_event->cqe.acqe_fip);
break;
case LPFC_TRAILER_CODE_DCBX:
lpfc_sli4_async_dcbx_evt(phba,
@@ -3612,6 +3766,12 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
lpfc_sli4_async_grp5_evt(phba,
&cq_event->cqe.acqe_grp5);
break;
+ case LPFC_TRAILER_CODE_FC:
+ lpfc_sli4_async_fc_evt(phba, &cq_event->cqe.acqe_fc);
+ break;
+ case LPFC_TRAILER_CODE_SLI:
+ lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli);
+ break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"1804 Invalid asynchrous event code: "
@@ -3646,8 +3806,7 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba)
/* Scan FCF table from the first entry to re-discover SAN */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
- "2777 Start FCF table scan after FCF "
- "rediscovery quiescent period over\n");
+ "2777 Start post-quiescent FCF table scan\n");
rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
if (rc)
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
@@ -3951,7 +4110,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
int rc, i, hbq_count, buf_size, dma_buf_size, max_buf_size;
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
struct lpfc_mqe *mqe;
- int longs;
+ int longs, sli_family;
/* Before proceed, wait for POST done and device ready */
rc = lpfc_sli4_post_status_check(phba);
@@ -3966,6 +4125,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
init_timer(&phba->hb_tmofunc);
phba->hb_tmofunc.function = lpfc_hb_timeout;
phba->hb_tmofunc.data = (unsigned long)phba;
+ init_timer(&phba->rrq_tmr);
+ phba->rrq_tmr.function = lpfc_rrq_timeout;
+ phba->rrq_tmr.data = (unsigned long)phba;
psli = &phba->sli;
/* MBOX heartbeat timer */
@@ -4013,12 +4175,22 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
*/
buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)));
- /* Feature Level 1 hardware is limited to 2 pages */
- if ((bf_get(lpfc_sli_intf_featurelevel1, &phba->sli4_hba.sli_intf) ==
- LPFC_SLI_INTF_FEATURELEVEL1_1))
- max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE;
- else
- max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
+
+ sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf);
+ max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
+ switch (sli_family) {
+ case LPFC_SLI_INTF_FAMILY_BE2:
+ case LPFC_SLI_INTF_FAMILY_BE3:
+ /* There is a single hint for BE - 2 pages per BPL. */
+ if (bf_get(lpfc_sli_intf_sli_hint1, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_SLI_HINT1_1)
+ max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE;
+ break;
+ case LPFC_SLI_INTF_FAMILY_LNCR_A0:
+ case LPFC_SLI_INTF_FAMILY_LNCR_B0:
+ default:
+ break;
+ }
for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
dma_buf_size < max_buf_size && buf_size > dma_buf_size;
dma_buf_size = dma_buf_size << 1)
@@ -4073,6 +4245,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (rc)
return -ENOMEM;
+ /* IF Type 2 ports get initialized now. */
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_2) {
+ rc = lpfc_pci_function_reset(phba);
+ if (unlikely(rc))
+ return -ENODEV;
+ }
+
/* Create the bootstrap mailbox command */
rc = lpfc_create_bootstrap_mbox(phba);
if (unlikely(rc))
@@ -4083,19 +4263,18 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (unlikely(rc))
goto out_free_bsmbx;
- rc = lpfc_sli4_fw_cfg_check(phba);
- if (unlikely(rc))
- goto out_free_bsmbx;
-
/* Set up the hba's configuration parameters. */
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
- /* Perform a function reset */
- rc = lpfc_pci_function_reset(phba);
- if (unlikely(rc))
- goto out_free_bsmbx;
+ /* IF Type 0 ports get initialized now. */
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0) {
+ rc = lpfc_pci_function_reset(phba);
+ if (unlikely(rc))
+ goto out_free_bsmbx;
+ }
mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL);
@@ -4165,7 +4344,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
goto out_free_active_sgl;
}
- /* Allocate eligible FCF bmask memory for FCF round robin failover */
+ /* Allocate eligible FCF bmask memory for FCF roundrobin failover */
longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG;
phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long),
GFP_KERNEL);
@@ -5193,97 +5372,183 @@ lpfc_sli_pci_mem_unset(struct lpfc_hba *phba)
int
lpfc_sli4_post_status_check(struct lpfc_hba *phba)
{
- struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg;
- int i, port_error = -ENODEV;
+ struct lpfc_register portsmphr_reg, uerrlo_reg, uerrhi_reg;
+ struct lpfc_register reg_data;
+ int i, port_error = 0;
+ uint32_t if_type;
- if (!phba->sli4_hba.STAregaddr)
+ if (!phba->sli4_hba.PSMPHRregaddr)
return -ENODEV;
/* Wait up to 30 seconds for the SLI Port POST done and ready */
for (i = 0; i < 3000; i++) {
- sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
- /* Encounter fatal POST error, break out */
- if (bf_get(lpfc_hst_state_perr, &sta_reg)) {
+ portsmphr_reg.word0 = readl(phba->sli4_hba.PSMPHRregaddr);
+ if (bf_get(lpfc_port_smphr_perr, &portsmphr_reg)) {
+ /* Port has a fatal POST error, break out */
port_error = -ENODEV;
break;
}
- if (LPFC_POST_STAGE_ARMFW_READY ==
- bf_get(lpfc_hst_state_port_status, &sta_reg)) {
- port_error = 0;
+ if (LPFC_POST_STAGE_PORT_READY ==
+ bf_get(lpfc_port_smphr_port_status, &portsmphr_reg))
break;
- }
msleep(10);
}
- if (port_error)
+ /*
+ * If there was a port error during POST, then don't proceed with
+ * other register reads as the data may not be valid. Just exit.
+ */
+ if (port_error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1408 Failure HBA POST Status: sta_reg=0x%x, "
- "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, "
- "dl=x%x, pstatus=x%x\n", sta_reg.word0,
- bf_get(lpfc_hst_state_perr, &sta_reg),
- bf_get(lpfc_hst_state_sfi, &sta_reg),
- bf_get(lpfc_hst_state_nip, &sta_reg),
- bf_get(lpfc_hst_state_ipc, &sta_reg),
- bf_get(lpfc_hst_state_xrom, &sta_reg),
- bf_get(lpfc_hst_state_dl, &sta_reg),
- bf_get(lpfc_hst_state_port_status, &sta_reg));
-
- /* Log device information */
- phba->sli4_hba.sli_intf.word0 = readl(phba->sli4_hba.SLIINTFregaddr);
- if (bf_get(lpfc_sli_intf_valid,
- &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_VALID) {
+ "1408 Port Failed POST - portsmphr=0x%x, "
+ "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, "
+ "scr2=x%x, hscratch=x%x, pstatus=x%x\n",
+ portsmphr_reg.word0,
+ bf_get(lpfc_port_smphr_perr, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_sfi, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_nip, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_ipc, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_scr1, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_scr2, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_host_scratch, &portsmphr_reg),
+ bf_get(lpfc_port_smphr_port_status, &portsmphr_reg));
+ } else {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
- "FeatureL1=0x%x, FeatureL2=0x%x\n",
+ "2534 Device Info: SLIFamily=0x%x, "
+ "SLIRev=0x%x, IFType=0x%x, SLIHint_1=0x%x, "
+ "SLIHint_2=0x%x, FT=0x%x\n",
bf_get(lpfc_sli_intf_sli_family,
&phba->sli4_hba.sli_intf),
bf_get(lpfc_sli_intf_slirev,
&phba->sli4_hba.sli_intf),
- bf_get(lpfc_sli_intf_featurelevel1,
+ bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_sli_hint1,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_sli_hint2,
&phba->sli4_hba.sli_intf),
- bf_get(lpfc_sli_intf_featurelevel2,
+ bf_get(lpfc_sli_intf_func_type,
&phba->sli4_hba.sli_intf));
+ /*
+ * Check for other Port errors during the initialization
+ * process. Fail the load if the port did not come up
+ * correctly.
+ */
+ if_type = bf_get(lpfc_sli_intf_if_type,
+ &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ phba->sli4_hba.ue_mask_lo =
+ readl(phba->sli4_hba.u.if_type0.UEMASKLOregaddr);
+ phba->sli4_hba.ue_mask_hi =
+ readl(phba->sli4_hba.u.if_type0.UEMASKHIregaddr);
+ uerrlo_reg.word0 =
+ readl(phba->sli4_hba.u.if_type0.UERRLOregaddr);
+ uerrhi_reg.word0 =
+ readl(phba->sli4_hba.u.if_type0.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) ||
+ (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1422 Unrecoverable Error "
+ "Detected during POST "
+ "uerr_lo_reg=0x%x, "
+ "uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, "
+ "ue_mask_hi_reg=0x%x\n",
+ uerrlo_reg.word0,
+ uerrhi_reg.word0,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
+ port_error = -ENODEV;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ /* Final checks. The port status should be clean. */
+ reg_data.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+ if (bf_get(lpfc_sliport_status_err, &reg_data)) {
+ phba->work_status[0] =
+ readl(phba->sli4_hba.u.if_type2.
+ ERR1regaddr);
+ phba->work_status[1] =
+ readl(phba->sli4_hba.u.if_type2.
+ ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2888 Port Error Detected "
+ "during POST: "
+ "port status reg 0x%x, "
+ "port_smphr reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ reg_data.word0,
+ portsmphr_reg.word0,
+ phba->work_status[0],
+ phba->work_status[1]);
+ port_error = -ENODEV;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
+ }
}
- phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr);
- phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr);
- /* With uncoverable error, log the error message and return error */
- uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
- uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
- if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) ||
- (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1422 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
- uerrlo_reg.word0, uerrhi_reg.word0,
- phba->sli4_hba.ue_mask_lo,
- phba->sli4_hba.ue_mask_hi);
- return -ENODEV;
- }
-
return port_error;
}
/**
* lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map.
* @phba: pointer to lpfc hba data structure.
+ * @if_type: The SLI4 interface type getting configured.
*
* This routine is invoked to set up SLI4 BAR0 PCI config space register
* memory map.
**/
static void
-lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
-{
- phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UERR_STATUS_LO;
- phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UERR_STATUS_HI;
- phba->sli4_hba.UEMASKLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UE_MASK_LO;
- phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_UE_MASK_HI;
- phba->sli4_hba.SLIINTFregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_SLI_INTF;
+lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
+{
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ phba->sli4_hba.u.if_type0.UERRLOregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_LO;
+ phba->sli4_hba.u.if_type0.UERRHIregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_HI;
+ phba->sli4_hba.u.if_type0.UEMASKLOregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_LO;
+ phba->sli4_hba.u.if_type0.UEMASKHIregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_HI;
+ phba->sli4_hba.SLIINTFregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ phba->sli4_hba.u.if_type2.ERR1regaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+ phba->sli4_hba.u.if_type2.ERR2regaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+ phba->sli4_hba.u.if_type2.CTRLregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+ phba->sli4_hba.u.if_type2.STATUSregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+ phba->sli4_hba.SLIINTFregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
+ phba->sli4_hba.PSMPHRregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+ phba->sli4_hba.RQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
+ phba->sli4_hba.WQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_WQ_DOORBELL;
+ phba->sli4_hba.EQCQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
+ phba->sli4_hba.MQDBregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL;
+ phba->sli4_hba.BMBXregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ dev_printk(KERN_ERR, &phba->pcidev->dev,
+ "FATAL - unsupported SLI4 interface type - %d\n",
+ if_type);
+ break;
+ }
}
/**
@@ -5296,16 +5561,14 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
static void
lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
{
-
- phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_STATE;
+ phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_SLIPORT_IF0_SMPHR;
phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISR0;
+ LPFC_HST_ISR0;
phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_IMR0;
+ LPFC_HST_IMR0;
phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISCR0;
- return;
+ LPFC_HST_ISCR0;
}
/**
@@ -5545,11 +5808,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
}
/**
- * lpfc_dev_endian_order_setup - Notify the port of the host's endian order.
+ * lpfc_setup_endian_order - Write endian order to an SLI4 if_type 0 port.
* @phba: pointer to lpfc hba data structure.
*
- * This routine is invoked to setup the host-side endian order to the
- * HBA consistent with the SLI-4 interface spec.
+ * This routine is invoked to setup the port-side endian order when
+ * the port if_type is 0. This routine has no function for other
+ * if_types.
*
* Return codes
* 0 - successful
@@ -5560,34 +5824,44 @@ static int
lpfc_setup_endian_order(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq;
- uint32_t rc = 0;
+ uint32_t if_type, rc = 0;
uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0,
HOST_ENDIAN_HIGH_WORD1};
- mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0492 Unable to allocate memory for issuing "
- "SLI_CONFIG_SPECIAL mailbox command\n");
- return -ENOMEM;
- }
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0492 Unable to allocate memory for "
+ "issuing SLI_CONFIG_SPECIAL mailbox "
+ "command\n");
+ return -ENOMEM;
+ }
- /*
- * The SLI4_CONFIG_SPECIAL mailbox command requires the first two
- * words to contain special data values and no other data.
- */
- memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
- memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0493 SLI_CONFIG_SPECIAL mailbox failed with "
- "status x%x\n",
- rc);
- rc = -EIO;
+ /*
+ * The SLI4_CONFIG_SPECIAL mailbox command requires the first
+ * two words to contain special data values and no other data.
+ */
+ memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+ memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0493 SLI_CONFIG_SPECIAL mailbox "
+ "failed with status x%x\n",
+ rc);
+ rc = -EIO;
+ }
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
}
-
- mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
}
@@ -6419,36 +6693,124 @@ int
lpfc_pci_function_reset(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq;
- uint32_t rc = 0;
+ uint32_t rc = 0, if_type;
uint32_t shdr_status, shdr_add_status;
+ uint32_t rdy_chk, num_resets = 0, reset_again = 0;
union lpfc_sli4_cfg_shdr *shdr;
+ struct lpfc_register reg_data;
- mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0494 Unable to allocate memory for issuing "
- "SLI_FUNCTION_RESET mailbox command\n");
- return -ENOMEM;
- }
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0494 Unable to allocate memory for "
+ "issuing SLI_FUNCTION_RESET mailbox "
+ "command\n");
+ return -ENOMEM;
+ }
- /* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */
- lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
- LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
- LPFC_SLI4_MBX_EMBED);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- shdr = (union lpfc_sli4_cfg_shdr *)
- &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
- shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
- shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
- if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
- if (shdr_status || shdr_add_status || rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0495 SLI_FUNCTION_RESET mailbox failed with "
- "status x%x add_status x%x, mbx status x%x\n",
- shdr_status, shdr_add_status, rc);
- rc = -ENXIO;
+ /* Setup PCI function reset mailbox-ioctl command */
+ lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
+ LPFC_SLI4_MBX_EMBED);
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ shdr = (union lpfc_sli4_cfg_shdr *)
+ &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+ shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+ shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+ &shdr->response);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (shdr_status || shdr_add_status || rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0495 SLI_FUNCTION_RESET mailbox "
+ "failed with status x%x add_status x%x,"
+ " mbx status x%x\n",
+ shdr_status, shdr_add_status, rc);
+ rc = -ENXIO;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ for (num_resets = 0;
+ num_resets < MAX_IF_TYPE_2_RESETS;
+ num_resets++) {
+ reg_data.word0 = 0;
+ bf_set(lpfc_sliport_ctrl_end, &reg_data,
+ LPFC_SLIPORT_LITTLE_ENDIAN);
+ bf_set(lpfc_sliport_ctrl_ip, &reg_data,
+ LPFC_SLIPORT_INIT_PORT);
+ writel(reg_data.word0, phba->sli4_hba.u.if_type2.
+ CTRLregaddr);
+
+ /*
+ * Poll the Port Status Register and wait for RDY for
+ * up to 10 seconds. If the port doesn't respond, treat
+ * it as an error. If the port responds with RN, start
+ * the loop again.
+ */
+ for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) {
+ reg_data.word0 =
+ readl(phba->sli4_hba.u.if_type2.
+ STATUSregaddr);
+ if (bf_get(lpfc_sliport_status_rdy, &reg_data))
+ break;
+ if (bf_get(lpfc_sliport_status_rn, &reg_data)) {
+ reset_again++;
+ break;
+ }
+ msleep(10);
+ }
+
+ /*
+ * If the port responds to the init request with
+ * reset needed, delay for a bit and restart the loop.
+ */
+ if (reset_again) {
+ msleep(10);
+ reset_again = 0;
+ continue;
+ }
+
+ /* Detect any port errors. */
+ reg_data.word0 = readl(phba->sli4_hba.u.if_type2.
+ STATUSregaddr);
+ if ((bf_get(lpfc_sliport_status_err, &reg_data)) ||
+ (rdy_chk >= 1000)) {
+ phba->work_status[0] = readl(
+ phba->sli4_hba.u.if_type2.ERR1regaddr);
+ phba->work_status[1] = readl(
+ phba->sli4_hba.u.if_type2.ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2890 Port Error Detected "
+ "during Port Reset: "
+ "port status reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ reg_data.word0,
+ phba->work_status[0],
+ phba->work_status[1]);
+ rc = -ENODEV;
+ }
+
+ /*
+ * Terminate the outer loop provided the Port indicated
+ * ready within 10 seconds.
+ */
+ if (rdy_chk < 1000)
+ break;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ break;
}
+
+ /* Catch the not-ready port failure after a port reset. */
+ if (num_resets >= MAX_IF_TYPE_2_RESETS)
+ rc = -ENODEV;
+
return rc;
}
@@ -6539,6 +6901,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
struct pci_dev *pdev;
unsigned long bar0map_len, bar1map_len, bar2map_len;
int error = -ENODEV;
+ uint32_t if_type;
/* Obtain PCI device reference */
if (!phba->pcidev)
@@ -6555,61 +6918,105 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
}
}
- /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
- * number of bytes required by each mapping. They are actually
- * mapping to the PCI BAR regions 0 or 1, 2, and 4 by the SLI4 device.
+ /*
+ * The BARs and register set definitions and offset locations are
+ * dependent on the if_type.
+ */
+ if (pci_read_config_dword(pdev, LPFC_SLI_INTF,
+ &phba->sli4_hba.sli_intf.word0)) {
+ return error;
+ }
+
+ /* There is no SLI3 failback for SLI4 devices. */
+ if (bf_get(lpfc_sli_intf_valid, &phba->sli4_hba.sli_intf) !=
+ LPFC_SLI_INTF_VALID) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2894 SLI_INTF reg contents invalid "
+ "sli_intf reg 0x%x\n",
+ phba->sli4_hba.sli_intf.word0);
+ return error;
+ }
+
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ /*
+ * Get the bus address of SLI4 device Bar regions and the
+ * number of bytes required by each mapping. The mapping of the
+ * particular PCI BARs regions is dependent on the type of
+ * SLI4 device.
*/
if (pci_resource_start(pdev, 0)) {
phba->pci_bar0_map = pci_resource_start(pdev, 0);
bar0map_len = pci_resource_len(pdev, 0);
+
+ /*
+ * Map SLI4 PCI Config Space Register base to a kernel virtual
+ * addr
+ */
+ phba->sli4_hba.conf_regs_memmap_p =
+ ioremap(phba->pci_bar0_map, bar0map_len);
+ if (!phba->sli4_hba.conf_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "ioremap failed for SLI4 PCI config "
+ "registers.\n");
+ goto out;
+ }
+ /* Set up BAR0 PCI config space register memory map */
+ lpfc_sli4_bar0_register_memmap(phba, if_type);
} else {
phba->pci_bar0_map = pci_resource_start(pdev, 1);
bar0map_len = pci_resource_len(pdev, 1);
- }
- phba->pci_bar1_map = pci_resource_start(pdev, 2);
- bar1map_len = pci_resource_len(pdev, 2);
-
- phba->pci_bar2_map = pci_resource_start(pdev, 4);
- bar2map_len = pci_resource_len(pdev, 4);
-
- /* Map SLI4 PCI Config Space Register base to a kernel virtual addr */
- phba->sli4_hba.conf_regs_memmap_p =
+ if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "FATAL - No BAR0 mapping for SLI4, if_type 2\n");
+ goto out;
+ }
+ phba->sli4_hba.conf_regs_memmap_p =
ioremap(phba->pci_bar0_map, bar0map_len);
- if (!phba->sli4_hba.conf_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
- "ioremap failed for SLI4 PCI config registers.\n");
- goto out;
+ if (!phba->sli4_hba.conf_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "ioremap failed for SLI4 PCI config "
+ "registers.\n");
+ goto out;
+ }
+ lpfc_sli4_bar0_register_memmap(phba, if_type);
}
- /* Map SLI4 HBA Control Register base to a kernel virtual address. */
- phba->sli4_hba.ctrl_regs_memmap_p =
+ if (pci_resource_start(pdev, 2)) {
+ /*
+ * Map SLI4 if type 0 HBA Control Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar1_map = pci_resource_start(pdev, 2);
+ bar1map_len = pci_resource_len(pdev, 2);
+ phba->sli4_hba.ctrl_regs_memmap_p =
ioremap(phba->pci_bar1_map, bar1map_len);
- if (!phba->sli4_hba.ctrl_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
+ if (!phba->sli4_hba.ctrl_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
"ioremap failed for SLI4 HBA control registers.\n");
- goto out_iounmap_conf;
+ goto out_iounmap_conf;
+ }
+ lpfc_sli4_bar1_register_memmap(phba);
}
- /* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */
- phba->sli4_hba.drbl_regs_memmap_p =
+ if (pci_resource_start(pdev, 4)) {
+ /*
+ * Map SLI4 if type 0 HBA Doorbell Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar2_map = pci_resource_start(pdev, 4);
+ bar2map_len = pci_resource_len(pdev, 4);
+ phba->sli4_hba.drbl_regs_memmap_p =
ioremap(phba->pci_bar2_map, bar2map_len);
- if (!phba->sli4_hba.drbl_regs_memmap_p) {
- dev_printk(KERN_ERR, &pdev->dev,
+ if (!phba->sli4_hba.drbl_regs_memmap_p) {
+ dev_printk(KERN_ERR, &pdev->dev,
"ioremap failed for SLI4 HBA doorbell registers.\n");
- goto out_iounmap_ctrl;
+ goto out_iounmap_ctrl;
+ }
+ error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
+ if (error)
+ goto out_iounmap_all;
}
- /* Set up BAR0 PCI config space register memory map */
- lpfc_sli4_bar0_register_memmap(phba);
-
- /* Set up BAR1 register memory map */
- lpfc_sli4_bar1_register_memmap(phba);
-
- /* Set up BAR2 register memory map */
- error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
- if (error)
- goto out_iounmap_all;
-
return 0;
out_iounmap_all:
@@ -7271,6 +7678,51 @@ lpfc_sli4_unset_hba(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_xri_exchange_busy_wait - Wait for device XRI exchange busy
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI4 code path to wait for completion
+ * of device's XRIs exchange busy. It will check the XRI exchange busy
+ * on outstanding FCP and ELS I/Os every 10ms for up to 10 seconds; after
+ * that, it will check the XRI exchange busy on outstanding FCP and ELS
+ * I/Os every 30 seconds, log error message, and wait forever. Only when
+ * all XRI exchange busy complete, the driver unload shall proceed with
+ * invoking the function reset ioctl mailbox command to the CNA and the
+ * the rest of the driver unload resource release.
+ **/
+static void
+lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba)
+{
+ int wait_time = 0;
+ int fcp_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+ int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+
+ while (!fcp_xri_cmpl || !els_xri_cmpl) {
+ if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) {
+ if (!fcp_xri_cmpl)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2877 FCP XRI exchange busy "
+ "wait time: %d seconds.\n",
+ wait_time/1000);
+ if (!els_xri_cmpl)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2878 ELS XRI exchange busy "
+ "wait time: %d seconds.\n",
+ wait_time/1000);
+ msleep(LPFC_XRI_EXCH_BUSY_WAIT_T2);
+ wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T2;
+ } else {
+ msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1);
+ wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T1;
+ }
+ fcp_xri_cmpl =
+ list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+ els_xri_cmpl =
+ list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+ }
+}
+
+/**
* lpfc_sli4_hba_unset - Unset the fcoe hba
* @phba: Pointer to HBA context object.
*
@@ -7315,6 +7767,12 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
spin_unlock_irq(&phba->hbalock);
}
+ /* Abort all iocbs associated with the hba */
+ lpfc_sli_hba_iocb_abort(phba);
+
+ /* Wait for completion of device XRI exchange busy */
+ lpfc_sli4_xri_exchange_busy_wait(phba);
+
/* Disable PCI subsystem interrupt */
lpfc_sli4_disable_intr(phba);
@@ -7613,7 +8071,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
* the HBA.
*/
- /* HBA interrupt will be diabled after this call */
+ /* HBA interrupt will be disabled after this call */
lpfc_sli_hba_down(phba);
/* Stop kthread signal shall trigger work_done one more time */
kthread_stop(phba->worker_thread);
@@ -8101,6 +8559,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_unset_driver_resource_s4;
}
+ INIT_LIST_HEAD(&phba->active_rrq_list);
+
/* Set up common device driver resources */
error = lpfc_setup_driver_resource_phase2(phba);
if (error) {
@@ -8170,7 +8630,11 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
"0451 Configure interrupt mode (%d) "
"failed active interrupt test.\n",
intr_mode);
- /* Unset the preivous SLI-4 HBA setup */
+ /* Unset the previous SLI-4 HBA setup. */
+ /*
+ * TODO: Is this operation compatible with IF TYPE 2
+ * devices? All port state is deleted and cleared.
+ */
lpfc_sli4_unset_hba(phba);
/* Try next level of interrupt mode */
cfg_mode = --intr_mode;
@@ -8942,6 +9406,10 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index bb59e9273126..e3b790e59156 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -33,7 +33,7 @@
#define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */
#define LOG_LIBDFC 0x00002000 /* Libdfc events */
#define LOG_VPORT 0x00004000 /* NPIV events */
-#define LOF_SECURITY 0x00008000 /* Security events */
+#define LOG_SECURITY 0x00008000 /* Security events */
#define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */
#define LOG_FIP 0x00020000 /* FIP events */
#define LOG_ALL_MSG 0xffffffff /* LOG all messages */
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 0dfa310cd609..23403c650207 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -263,18 +263,19 @@ lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
}
/**
- * lpfc_read_la - Prepare a mailbox command for reading HBA link attention
+ * lpfc_read_topology - Prepare a mailbox command for reading HBA topology
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
* @mp: DMA buffer memory for reading the link attention information into.
*
- * The read link attention mailbox command is issued to read the Link Event
- * Attention information indicated by the HBA port when the Link Event bit
- * of the Host Attention (HSTATT) register is set to 1. A Link Event
+ * The read topology mailbox command is issued to read the link topology
+ * information indicated by the HBA port when the Link Event bit of the Host
+ * Attention (HSTATT) register is set to 1 (For SLI-3) or when an FC Link
+ * Attention ACQE is received from the port (For SLI-4). A Link Event
* Attention occurs based on an exception detected at the Fibre Channel link
* interface.
*
- * This routine prepares the mailbox command for reading HBA link attention
+ * This routine prepares the mailbox command for reading HBA link topology
* information. A DMA memory has been set aside and address passed to the
* HBA through @mp for the HBA to DMA link attention information into the
* memory as part of the execution of the mailbox command.
@@ -283,7 +284,8 @@ lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
* 0 - Success (currently always return 0)
**/
int
-lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
+lpfc_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
+ struct lpfc_dmabuf *mp)
{
MAILBOX_t *mb;
struct lpfc_sli *psli;
@@ -293,15 +295,15 @@ lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
INIT_LIST_HEAD(&mp->list);
- mb->mbxCommand = MBX_READ_LA64;
- mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
- mb->un.varReadLA.un.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
- mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(mp->phys);
+ mb->mbxCommand = MBX_READ_TOPOLOGY;
+ mb->un.varReadTop.lilpBde64.tus.f.bdeSize = LPFC_ALPA_MAP_SIZE;
+ mb->un.varReadTop.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
+ mb->un.varReadTop.lilpBde64.addrLow = putPaddrLow(mp->phys);
/* Save address for later completion and set the owner to host so that
* the FW knows this mailbox is available for processing.
*/
- pmb->context1 = (uint8_t *) mp;
+ pmb->context1 = (uint8_t *)mp;
mb->mbxOwner = OWN_HOST;
return (0);
}
@@ -516,18 +518,33 @@ lpfc_init_link(struct lpfc_hba * phba,
vpd = &phba->vpd;
if (vpd->rev.feaLevelHigh >= 0x02){
switch(linkspeed){
- case LINK_SPEED_1G:
- case LINK_SPEED_2G:
- case LINK_SPEED_4G:
- case LINK_SPEED_8G:
- mb->un.varInitLnk.link_flags |=
- FLAGS_LINK_SPEED;
- mb->un.varInitLnk.link_speed = linkspeed;
+ case LPFC_USER_LINK_SPEED_1G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_1G;
+ break;
+ case LPFC_USER_LINK_SPEED_2G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_2G;
+ break;
+ case LPFC_USER_LINK_SPEED_4G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_4G;
+ break;
+ case LPFC_USER_LINK_SPEED_8G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_8G;
+ break;
+ case LPFC_USER_LINK_SPEED_10G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_10G;
break;
- case LINK_SPEED_AUTO:
- default:
- mb->un.varInitLnk.link_speed =
- LINK_SPEED_AUTO;
+ case LPFC_USER_LINK_SPEED_16G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_16G;
+ break;
+ case LPFC_USER_LINK_SPEED_AUTO:
+ default:
+ mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
break;
}
@@ -693,7 +710,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
* @did: remote port identifier.
* @param: pointer to memory holding the server parameters.
* @pmb: pointer to the driver internal queue element for mailbox command.
- * @flag: action flag to be passed back for the complete function.
+ * @rpi: the rpi to use in the registration (usually only used for SLI4.
*
* The registration login mailbox command is used to register an N_Port or
* F_Port login. This registration allows the HBA to cache the remote N_Port
@@ -712,7 +729,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
**/
int
lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
- uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
+ uint8_t *param, LPFC_MBOXQ_t *pmb, uint16_t rpi)
{
MAILBOX_t *mb = &pmb->u.mb;
uint8_t *sparam;
@@ -722,17 +739,13 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
mb->un.varRegLogin.rpi = 0;
if (phba->sli_rev == LPFC_SLI_REV4) {
- mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba);
+ mb->un.varRegLogin.rpi = rpi;
if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
return 1;
}
-
mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
mb->un.varRegLogin.did = did;
- mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */
-
mb->mbxOwner = OWN_HOST;
-
/* Get a buffer to hold NPorts Service Parameters */
mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
if (mp)
@@ -743,7 +756,7 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
/* REG_LOGIN: no buffers */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
- "flag x%x\n", vpi, did, flag);
+ "rpi x%x\n", vpi, did, rpi);
return (1);
}
INIT_LIST_HEAD(&mp->list);
@@ -797,6 +810,34 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
}
/**
+ * lpfc_sli4_unreg_all_rpis - unregister all RPIs for a vport on SLI4 HBA.
+ * @vport: pointer to a vport object.
+ *
+ * This routine sends mailbox command to unregister all active RPIs for
+ * a vport.
+ **/
+void
+lpfc_sli4_unreg_all_rpis(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_login(phba, vport->vpi,
+ vport->vpi + phba->vpi_base, mbox);
+ mbox->u.mb.un.varUnregLogin.rsvd1 = 0x4000 ;
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->context1 = NULL;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+}
+
+/**
* lpfc_reg_vpi - Prepare a mailbox command for registering vport identifier
* @phba: pointer to lpfc hba data structure.
* @vpi: virtual N_Port identifier.
@@ -1890,11 +1931,14 @@ lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
struct lpfc_mbx_init_vfi *init_vfi;
memset(mbox, 0, sizeof(*mbox));
+ mbox->vport = vport;
init_vfi = &mbox->u.mqe.un.init_vfi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI);
bf_set(lpfc_init_vfi_vr, init_vfi, 1);
bf_set(lpfc_init_vfi_vt, init_vfi, 1);
+ bf_set(lpfc_init_vfi_vp, init_vfi, 1);
bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base);
+ bf_set(lpfc_init_vpi_vpi, init_vfi, vport->vpi + vport->phba->vpi_base);
bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi);
}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 8f879e477e9d..cbb48ee8b0bb 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -113,11 +113,16 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
goto fail_free_mbox_pool;
if (phba->sli_rev == LPFC_SLI_REV4) {
+ phba->rrq_pool =
+ mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+ sizeof(struct lpfc_node_rrq));
+ if (!phba->rrq_pool)
+ goto fail_free_nlp_mem_pool;
phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
phba->pcidev,
LPFC_HDR_BUF_SIZE, align, 0);
if (!phba->lpfc_hrb_pool)
- goto fail_free_nlp_mem_pool;
+ goto fail_free_rrq_mem_pool;
phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
phba->pcidev,
@@ -147,6 +152,9 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
+ fail_free_rrq_mem_pool:
+ mempool_destroy(phba->rrq_pool);
+ phba->rrq_pool = NULL;
fail_free_nlp_mem_pool:
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bccc9c66fa37..d85a7423a694 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -386,7 +386,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
goto out;
rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
- (uint8_t *) sp, mbox, 0);
+ (uint8_t *) sp, mbox, ndlp->nlp_rpi);
if (rc) {
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
@@ -632,7 +632,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- if (!(ndlp->nlp_flag & NLP_RPI_VALID)) {
+ if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
return 0;
}
@@ -968,7 +968,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
lpfc_unreg_rpi(vport, ndlp);
if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
- (uint8_t *) sp, mbox, 0) == 0) {
+ (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
@@ -1338,12 +1338,6 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
- if (phba->sli_rev == LPFC_SLI_REV4) {
- spin_unlock_irq(&phba->hbalock);
- lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
- spin_lock_irq(&phba->hbalock);
- }
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1426,7 +1420,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
}
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
/* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) {
@@ -2027,7 +2021,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
if (!mb->mbxStatus) {
ndlp->nlp_rpi = mb->un.varWords[0];
- ndlp->nlp_flag |= NLP_RPI_VALID;
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
} else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
lpfc_drop_node(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 3a658953486c..c97751c95d77 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -169,6 +169,7 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
spin_lock_irqsave(shost->host_lock, flags);
if (!vport->stat_data_enabled ||
vport->stat_data_blocked ||
+ !pnode ||
!pnode->lat_data ||
(phba->bucket_type == LPFC_NO_BUCKET)) {
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -620,10 +621,13 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+ uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
struct lpfc_scsi_buf *psb, *next_psb;
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
+ struct lpfc_nodelist *ndlp;
+ int rrq_empty = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
@@ -636,8 +640,14 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb->status = IOSTAT_SUCCESS;
spin_unlock(
&phba->sli4_hba.abts_scsi_buf_list_lock);
+ ndlp = psb->rdata->pnode;
+ rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (ndlp)
+ lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
lpfc_release_scsi_buf_s4(phba, psb);
+ if (rrq_empty)
+ lpfc_worker_wake_up(phba);
return;
}
}
@@ -913,7 +923,7 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
}
/**
- * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
* @phba: The HBA for which this call is being executed.
*
* This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
@@ -924,7 +934,7 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
* Pointer to lpfc_scsi_buf - Success
**/
static struct lpfc_scsi_buf*
-lpfc_get_scsi_buf(struct lpfc_hba * phba)
+lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf * lpfc_cmd = NULL;
struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
@@ -940,6 +950,67 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
return lpfc_cmd;
}
+/**
+ * lpfc_get_scsi_buf_s4 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
+ *
+ * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
+ * and returns to caller.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_scsi_buf - Success
+ **/
+static struct lpfc_scsi_buf*
+lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_scsi_buf *lpfc_cmd = NULL;
+ struct lpfc_scsi_buf *start_lpfc_cmd = NULL;
+ struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+ unsigned long iflag = 0;
+ int found = 0;
+
+ spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+ list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+ while (!found && lpfc_cmd) {
+ if (lpfc_test_rrq_active(phba, ndlp,
+ lpfc_cmd->cur_iocbq.sli4_xritag)) {
+ lpfc_release_scsi_buf_s4(phba, lpfc_cmd);
+ spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+ list_remove_head(scsi_buf_list, lpfc_cmd,
+ struct lpfc_scsi_buf, list);
+ spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
+ iflag);
+ if (lpfc_cmd == start_lpfc_cmd) {
+ lpfc_cmd = NULL;
+ break;
+ } else
+ continue;
+ }
+ found = 1;
+ lpfc_cmd->seg_cnt = 0;
+ lpfc_cmd->nonsg_phys = 0;
+ lpfc_cmd->prot_seg_cnt = 0;
+ }
+ return lpfc_cmd;
+}
+/**
+ * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
+ *
+ * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
+ * and returns to caller.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_scsi_buf - Success
+ **/
+static struct lpfc_scsi_buf*
+lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ return phba->lpfc_get_scsi_buf(phba, ndlp);
+}
/**
* lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list
@@ -2040,6 +2111,9 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode;
unsigned long flags;
+ if (!pnode || !NLP_CHK_NODE_ACT(pnode))
+ return;
+
/* If there is queuefull or busy condition send a scsi event */
if ((cmnd->result == SAM_STAT_TASK_SET_FULL) ||
(cmnd->result == SAM_STAT_BUSY)) {
@@ -2740,18 +2814,19 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf;
phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd;
- phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
switch (dev_grp) {
case LPFC_PCI_DEV_LP:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
+ phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3;
break;
case LPFC_PCI_DEV_OC:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
+ phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4;
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -2760,7 +2835,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
return -ENODEV;
break;
}
- phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
return 0;
@@ -2895,7 +2969,7 @@ void lpfc_poll_timeout(unsigned long ptr)
* SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily.
**/
static int
-lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
@@ -2936,7 +3010,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
- lpfc_cmd = lpfc_get_scsi_buf(phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
if (lpfc_cmd == NULL) {
lpfc_rampdown_queue_depth(phba);
@@ -3056,6 +3130,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(lpfc_queuecommand)
+
/**
* lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
* @cmnd: Pointer to scsi_cmnd data structure.
@@ -3226,13 +3302,14 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
struct lpfc_scsi_buf *lpfc_cmd;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
+ struct lpfc_nodelist *pnode = rdata->pnode;
int ret;
int status;
- if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode))
+ if (!pnode || !NLP_CHK_NODE_ACT(pnode))
return FAILED;
- lpfc_cmd = lpfc_get_scsi_buf(phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode);
if (lpfc_cmd == NULL)
return FAILED;
lpfc_cmd->timeout = 60;
@@ -3256,7 +3333,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
"0702 Issue %s to TGT %d LUN %d "
"rpi x%x nlp_flag x%x\n",
lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id,
- rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
+ pnode->nlp_rpi, pnode->nlp_flag);
status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
iocbq, iocbqrsp, lpfc_cmd->timeout);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 0d1e187b005d..a359d2b873ce 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -95,7 +95,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
return -ENOMEM;
/* set consumption flag every once in a while */
if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
- bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1);
+ bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
@@ -513,8 +513,344 @@ __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
}
/**
+ * __lpfc_set_rrq_active - set RRQ active bit in the ndlp's xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: nodelist pointer for this target.
+ * @xritag: xri used in this exchange.
+ * @rxid: Remote Exchange ID.
+ * @send_rrq: Flag used to determine if we should send rrq els cmd.
+ *
+ * This function is called with hbalock held.
+ * The active bit is set in the ndlp's active rrq xri_bitmap. Allocates an
+ * rrq struct and adds it to the active_rrq_list.
+ *
+ * returns 0 for rrq slot for this xri
+ * < 0 Were not able to get rrq mem or invalid parameter.
+ **/
+static int
+__lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
+{
+ uint16_t adj_xri;
+ struct lpfc_node_rrq *rrq;
+ int empty;
+
+ /*
+ * set the active bit even if there is no mem available.
+ */
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (!ndlp)
+ return -EINVAL;
+ if (test_and_set_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+ return -EINVAL;
+ rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
+ if (rrq) {
+ rrq->send_rrq = send_rrq;
+ rrq->xritag = xritag;
+ rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
+ rrq->ndlp = ndlp;
+ rrq->nlp_DID = ndlp->nlp_DID;
+ rrq->vport = ndlp->vport;
+ rrq->rxid = rxid;
+ empty = list_empty(&phba->active_rrq_list);
+ if (phba->cfg_enable_rrq && send_rrq)
+ /*
+ * We need the xri before we can add this to the
+ * phba active rrq list.
+ */
+ rrq->send_rrq = send_rrq;
+ else
+ rrq->send_rrq = 0;
+ list_add_tail(&rrq->list, &phba->active_rrq_list);
+ if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) {
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ if (empty)
+ lpfc_worker_wake_up(phba);
+ }
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+/**
+ * __lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @xritag: xri used in this exchange.
+ * @rrq: The RRQ to be cleared.
+ *
+ * This function is called with hbalock held. This function
+ **/
+static void
+__lpfc_clr_rrq_active(struct lpfc_hba *phba,
+ uint16_t xritag,
+ struct lpfc_node_rrq *rrq)
+{
+ uint16_t adj_xri;
+ struct lpfc_nodelist *ndlp;
+
+ ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID);
+
+ /* The target DID could have been swapped (cable swap)
+ * we should use the ndlp from the findnode if it is
+ * available.
+ */
+ if (!ndlp)
+ ndlp = rrq->ndlp;
+
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (test_and_clear_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) {
+ rrq->send_rrq = 0;
+ rrq->xritag = 0;
+ rrq->rrq_stop_time = 0;
+ }
+ mempool_free(rrq, phba->rrq_pool);
+}
+
+/**
+ * lpfc_handle_rrq_active - Checks if RRQ has waithed RATOV.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with hbalock held. This function
+ * Checks if stop_time (ratov from setting rrq active) has
+ * been reached, if it has and the send_rrq flag is set then
+ * it will call lpfc_send_rrq. If the send_rrq flag is not set
+ * then it will just call the routine to clear the rrq and
+ * free the rrq resource.
+ * The timer is set to the next rrq that is going to expire before
+ * leaving the routine.
+ *
+ **/
+void
+lpfc_handle_rrq_active(struct lpfc_hba *phba)
+{
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long next_time;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ next_time = jiffies + HZ * (phba->fc_ratov + 1);
+ list_for_each_entry_safe(rrq, nextrrq,
+ &phba->active_rrq_list, list) {
+ if (time_after(jiffies, rrq->rrq_stop_time)) {
+ list_del(&rrq->list);
+ if (!rrq->send_rrq)
+ /* this call will free the rrq */
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ else {
+ /* if we send the rrq then the completion handler
+ * will clear the bit in the xribitmap.
+ */
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (lpfc_send_rrq(phba, rrq)) {
+ lpfc_clr_rrq_active(phba, rrq->xritag,
+ rrq);
+ }
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ }
+ } else if (time_before(rrq->rrq_stop_time, next_time))
+ next_time = rrq->rrq_stop_time;
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (!list_empty(&phba->active_rrq_list))
+ mod_timer(&phba->rrq_tmr, next_time);
+}
+
+/**
+ * lpfc_get_active_rrq - Get the active RRQ for this exchange.
+ * @vport: Pointer to vport context object.
+ * @xri: The xri used in the exchange.
+ * @did: The targets DID for this exchange.
+ *
+ * returns NULL = rrq not found in the phba->active_rrq_list.
+ * rrq = rrq for this xri and target.
+ **/
+struct lpfc_node_rrq *
+lpfc_get_active_rrq(struct lpfc_vport *vport, uint16_t xri, uint32_t did)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return NULL;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ if (rrq->vport == vport && rrq->xritag == xri &&
+ rrq->nlp_DID == did){
+ list_del(&rrq->list);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return rrq;
+ }
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return NULL;
+}
+
+/**
+ * lpfc_cleanup_vports_rrqs - Remove and clear the active RRQ for this vport.
+ * @vport: Pointer to vport context object.
+ *
+ * Remove all active RRQs for this vport from the phba->active_rrq_list and
+ * clear the rrq.
+ **/
+void
+lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport)
+
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ if (rrq->vport == vport) {
+ list_del(&rrq->list);
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ }
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+/**
+ * lpfc_cleanup_wt_rrqs - Remove all rrq's from the active list.
+ * @phba: Pointer to HBA context object.
+ *
+ * Remove all rrqs from the phba->active_rrq_list and free them by
+ * calling __lpfc_clr_active_rrq
+ *
+ **/
+void
+lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
+{
+ struct lpfc_node_rrq *rrq;
+ struct lpfc_node_rrq *nextrrq;
+ unsigned long next_time;
+ unsigned long iflags;
+
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ return;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ next_time = jiffies + HZ * (phba->fc_ratov * 2);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ list_del(&rrq->list);
+ __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (!list_empty(&phba->active_rrq_list))
+ mod_timer(&phba->rrq_tmr, next_time);
+}
+
+
+/**
+ * __lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: Targets nodelist pointer for this exchange.
+ * @xritag the xri in the bitmap to test.
+ *
+ * This function is called with hbalock held. This function
+ * returns 0 = rrq not active for this xri
+ * 1 = rrq is valid for this xri.
+ **/
+static int
+__lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag)
+{
+ uint16_t adj_xri;
+
+ adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+ if (!ndlp)
+ return 0;
+ if (test_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * lpfc_set_rrq_active - set RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: nodelist pointer for this target.
+ * @xritag: xri used in this exchange.
+ * @rxid: Remote Exchange ID.
+ * @send_rrq: Flag used to determine if we should send rrq els cmd.
+ *
+ * This function takes the hbalock.
+ * The active bit is always set in the active rrq xri_bitmap even
+ * if there is no slot avaiable for the other rrq information.
+ *
+ * returns 0 rrq actived for this xri
+ * < 0 No memory or invalid ndlp.
+ **/
+int
+lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
+{
+ int ret;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ret = __lpfc_set_rrq_active(phba, ndlp, xritag, rxid, send_rrq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return ret;
+}
+
+/**
+ * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @xritag: xri used in this exchange.
+ * @rrq: The RRQ to be cleared.
+ *
+ * This function is takes the hbalock.
+ **/
+void
+lpfc_clr_rrq_active(struct lpfc_hba *phba,
+ uint16_t xritag,
+ struct lpfc_node_rrq *rrq)
+{
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_clr_rrq_active(phba, xritag, rrq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return;
+}
+
+
+
+/**
+ * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
+ * @phba: Pointer to HBA context object.
+ * @ndlp: Targets nodelist pointer for this exchange.
+ * @xritag the xri in the bitmap to test.
+ *
+ * This function takes the hbalock.
+ * returns 0 = rrq not active for this xri
+ * 1 = rrq is valid for this xri.
+ **/
+int
+lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ uint16_t xritag)
+{
+ int ret;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ret = __lpfc_test_rrq_active(phba, ndlp, xritag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return ret;
+}
+
+/**
* __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
* @phba: Pointer to HBA context object.
+ * @piocb: Pointer to the iocbq.
*
* This function is called with hbalock held. This function
* Gets a new driver sglq object from the sglq list. If the
@@ -522,17 +858,51 @@ __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
* allocated sglq object else it returns NULL.
**/
static struct lpfc_sglq *
-__lpfc_sli_get_sglq(struct lpfc_hba *phba)
+__lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
{
struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
struct lpfc_sglq *sglq = NULL;
+ struct lpfc_sglq *start_sglq = NULL;
uint16_t adj_xri;
+ struct lpfc_scsi_buf *lpfc_cmd;
+ struct lpfc_nodelist *ndlp;
+ int found = 0;
+
+ if (piocbq->iocb_flag & LPFC_IO_FCP) {
+ lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1;
+ ndlp = lpfc_cmd->rdata->pnode;
+ } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) &&
+ !(piocbq->iocb_flag & LPFC_IO_LIBDFC))
+ ndlp = piocbq->context_un.ndlp;
+ else
+ ndlp = piocbq->context1;
+
list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
- if (!sglq)
- return NULL;
- adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
- phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
- sglq->state = SGL_ALLOCATED;
+ start_sglq = sglq;
+ while (!found) {
+ if (!sglq)
+ return NULL;
+ adj_xri = sglq->sli4_xritag -
+ phba->sli4_hba.max_cfg_param.xri_base;
+ if (__lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
+ /* This xri has an rrq outstanding for this DID.
+ * put it back in the list and get another xri.
+ */
+ list_add_tail(&sglq->list, lpfc_sgl_list);
+ sglq = NULL;
+ list_remove_head(lpfc_sgl_list, sglq,
+ struct lpfc_sglq, list);
+ if (sglq == start_sglq) {
+ sglq = NULL;
+ break;
+ } else
+ continue;
+ }
+ sglq->ndlp = ndlp;
+ found = 1;
+ phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+ sglq->state = SGL_ALLOCATED;
+ }
return sglq;
}
@@ -598,6 +968,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
&phba->sli4_hba.abts_sgl_list_lock, iflag);
} else {
sglq->state = SGL_FREED;
+ sglq->ndlp = NULL;
list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
/* Check if TXQ queue needs to be serviced */
@@ -1634,7 +2005,6 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
case MBX_READ_LNK_STAT:
case MBX_REG_LOGIN:
case MBX_UNREG_LOGIN:
- case MBX_READ_LA:
case MBX_CLEAR_LA:
case MBX_DUMP_MEMORY:
case MBX_DUMP_CONTEXT:
@@ -1656,7 +2026,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
case MBX_READ_SPARM64:
case MBX_READ_RPI64:
case MBX_REG_LOGIN64:
- case MBX_READ_LA64:
+ case MBX_READ_TOPOLOGY:
case MBX_WRITE_WWN:
case MBX_SET_DEBUG:
case MBX_LOAD_EXP_ROM:
@@ -1735,6 +2105,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_vport *vport = pmb->vport;
struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
uint16_t rpi, vpi;
int rc;
@@ -1745,10 +2116,6 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
kfree(mp);
}
- if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
- (phba->sli_rev == LPFC_SLI_REV4))
- lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
-
/*
* If a REG_LOGIN succeeded after node is destroyed or node
* is in re-discovery driver need to cleanup the RPI.
@@ -1765,16 +2132,14 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
return;
}
- /* Unreg VPI, if the REG_VPI succeed after VLink failure */
if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) &&
!(phba->pport->load_flag & FC_UNLOADING) &&
!pmb->u.mb.mbxStatus) {
- lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb);
- pmb->vport = vport;
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc != MBX_NOT_FINISHED)
- return;
+ shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->vpi_state |= LPFC_VPI_REGISTERED;
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
}
if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
@@ -3483,12 +3848,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
phba->pport->fc_myDID = 0;
phba->pport->fc_prevDID = 0;
- /* Turn off parity checking and serr during the physical reset */
- pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
- pci_write_config_word(phba->pcidev, PCI_COMMAND,
- (cfg_value &
- ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
-
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~(LPFC_PROCESS_LA);
phba->fcf.fcf_flag = 0;
@@ -3508,9 +3867,18 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
/* Now physically reset the device */
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0389 Performing PCI function reset!\n");
+
+ /* Turn off parity checking and serr during the physical reset */
+ pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+ pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value &
+ ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
/* Perform FCoE PCI function reset */
lpfc_pci_function_reset(phba);
+ /* Restore PCI cmd register */
+ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
+
return 0;
}
@@ -4317,6 +4685,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
struct lpfc_vport *vport = phba->pport;
struct lpfc_dmabuf *mp;
+ /*
+ * TODO: Why does this routine execute these task in a different
+ * order from probe?
+ */
/* Perform a PCI function reset to start from clean */
rc = lpfc_pci_function_reset(phba);
if (unlikely(rc))
@@ -4357,13 +4729,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
}
rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
- if (unlikely(rc))
- goto out_free_vpd;
-
+ if (unlikely(rc)) {
+ kfree(vpd);
+ goto out_free_mbox;
+ }
mqe = &mboxq->u.mqe;
phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
- phba->hba_flag |= HBA_FCOE_SUPPORT;
+ phba->hba_flag |= HBA_FCOE_MODE;
+ else
+ phba->hba_flag &= ~HBA_FCOE_MODE;
if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
LPFC_DCBX_CEE_MODE)
@@ -4372,13 +4747,14 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
phba->hba_flag &= ~HBA_FIP_SUPPORT;
if (phba->sli_rev != LPFC_SLI_REV4 ||
- !(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+ !(phba->hba_flag & HBA_FCOE_MODE)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"0376 READ_REV Error. SLI Level %d "
"FCoE enabled %d\n",
- phba->sli_rev, phba->hba_flag & HBA_FCOE_SUPPORT);
+ phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE);
rc = -EIO;
- goto out_free_vpd;
+ kfree(vpd);
+ goto out_free_mbox;
}
/*
* Evaluate the read rev and vpd data. Populate the driver
@@ -4392,6 +4768,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"Using defaults.\n", rc);
rc = 0;
}
+ kfree(vpd);
/* Save information as VPD data */
phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
@@ -4428,7 +4805,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
if (unlikely(rc)) {
rc = -EIO;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/*
@@ -4476,7 +4853,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
if (rc) {
phba->link_state = LPFC_HBA_ERROR;
rc = -ENOMEM;
- goto out_free_vpd;
+ goto out_free_mbox;
}
mboxq->vport = vport;
@@ -4501,7 +4878,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
rc, bf_get(lpfc_mqe_status, mqe));
phba->link_state = LPFC_HBA_ERROR;
rc = -EIO;
- goto out_free_vpd;
+ goto out_free_mbox;
}
if (phba->cfg_soft_wwnn)
@@ -4526,7 +4903,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"0582 Error %d during sgl post operation\n",
rc);
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Register SCSI SGL pool to the device */
@@ -4538,7 +4915,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
/* Some Scsi buffers were moved to the abort scsi list */
/* A pci function reset will repost them */
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Post the rpi header region to the device. */
@@ -4548,7 +4925,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"0393 Error %d during rpi post operation\n",
rc);
rc = -ENODEV;
- goto out_free_vpd;
+ goto out_free_mbox;
}
/* Set up all the queues to the device */
@@ -4608,33 +4985,33 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
}
}
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ /*
+ * The FC Port needs to register FCFI (index 0)
+ */
+ lpfc_reg_fcfi(phba, mboxq);
+ mboxq->vport = phba->pport;
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ if (rc == MBX_SUCCESS)
+ rc = 0;
+ else
+ goto out_unset_queue;
+ }
/*
* The port is ready, set the host's link state to LINK_DOWN
* in preparation for link interrupts.
*/
- lpfc_init_link(phba, mboxq, phba->cfg_topology, phba->cfg_link_speed);
- mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- lpfc_set_loopback_flag(phba);
- /* Change driver state to LPFC_LINK_DOWN right before init link */
spin_lock_irq(&phba->hbalock);
phba->link_state = LPFC_LINK_DOWN;
spin_unlock_irq(&phba->hbalock);
- rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
- if (unlikely(rc != MBX_NOT_FINISHED)) {
- kfree(vpd);
- return 0;
- } else
- rc = -EIO;
-
+ rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
+out_unset_queue:
/* Unset all the queues set up in this routine when error out */
if (rc)
lpfc_sli4_queue_unset(phba);
-
out_stop_timers:
if (rc)
lpfc_stop_hba_timers(phba);
-out_free_vpd:
- kfree(vpd);
out_free_mbox:
mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
@@ -5863,6 +6240,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
IOCB_t *icmd;
int numBdes = 0;
int i = 0;
+ uint32_t offset = 0; /* accumulated offset in the sg request list */
+ int inbound = 0; /* number of sg reply entries inbound from firmware */
if (!piocbq || !sglq)
return xritag;
@@ -5897,6 +6276,20 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
*/
bde.tus.w = le32_to_cpu(bpl->tus.w);
sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize);
+ /* The offsets in the sgl need to be accumulated
+ * separately for the request and reply lists.
+ * The request is always first, the reply follows.
+ */
+ if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) {
+ /* add up the reply sg entries */
+ if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I)
+ inbound++;
+ /* first inbound? reset the offset */
+ if (inbound == 1)
+ offset = 0;
+ bf_set(lpfc_sli4_sge_offset, sgl, offset);
+ offset += bde.tus.f.bdeSize;
+ }
bpl++;
sgl++;
}
@@ -5921,7 +6314,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
* lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
* @phba: Pointer to HBA context object.
*
- * This routine performs a round robin SCSI command to SLI4 FCP WQ index
+ * This routine performs a roundrobin SCSI command to SLI4 FCP WQ index
* distribution. This is called by __lpfc_sli_issue_iocb_s4() with the hbalock
* held.
*
@@ -5965,7 +6358,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
uint16_t abrt_iotag;
struct lpfc_iocbq *abrtiocbq;
struct ulp_bde64 *bpl = NULL;
- uint32_t els_id = ELS_ID_DEFAULT;
+ uint32_t els_id = LPFC_ELS_ID_DEFAULT;
int numBdes, i;
struct ulp_bde64 bde;
@@ -5982,7 +6375,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
abort_tag = (uint32_t) iocbq->iotag;
xritag = iocbq->sli4_xritag;
- wqe->words[7] = 0; /* The ct field has moved so reset */
+ wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */
/* words0-2 bpl convert bde */
if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
@@ -6028,114 +6421,129 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(els_req64_vf, &wqe->els_req, 0);
/* And a VFID for word 12 */
bf_set(els_req64_vfid, &wqe->els_req, 0);
- /*
- * Set ct field to 3, indicates that the context_tag field
- * contains the FCFI and remote N_Port_ID is
- * in word 5.
- */
-
ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
- bf_set(lpfc_wqe_gen_context, &wqe->generic,
- iocbq->iocb.ulpContext);
-
- bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct);
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+ bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
+ iocbq->iocb.ulpContext);
+ bf_set(wqe_ct, &wqe->els_req.wqe_com, ct);
+ bf_set(wqe_pu, &wqe->els_req.wqe_com, 0);
/* CCP CCPE PV PRI in word10 were set in the memcpy */
-
if (command_type == ELS_COMMAND_FIP) {
els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)
>> LPFC_FIP_ELS_ID_SHIFT);
}
- bf_set(lpfc_wqe_gen_els_id, &wqe->generic, els_id);
-
+ bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
+ bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ);
+ bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
+ bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
break;
case CMD_XMIT_SEQUENCE64_CX:
- bf_set(lpfc_wqe_gen_context, &wqe->generic,
- iocbq->iocb.un.ulpWord[3]);
- wqe->generic.word3 = 0;
- bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+ bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,
+ iocbq->iocb.un.ulpWord[3]);
+ bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com,
+ iocbq->iocb.ulpContext);
/* The entire sequence is transmitted for this IOCB */
xmit_len = total_len;
cmnd = CMD_XMIT_SEQUENCE64_CR;
case CMD_XMIT_SEQUENCE64_CR:
- /* word3 iocb=io_tag32 wqe=payload_offset */
- /* payload offset used for multilpe outstanding
- * sequences on the same exchange
- */
- wqe->words[3] = 0;
+ /* word3 iocb=io_tag32 wqe=reserved */
+ wqe->xmit_sequence.rsvd3 = 0;
/* word4 relative_offset memcpy */
/* word5 r_ctl/df_ctl memcpy */
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+ bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0);
+ bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com,
+ LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com,
+ LPFC_WQE_LENLOC_WORD12);
+ bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
wqe->xmit_sequence.xmit_len = xmit_len;
command_type = OTHER_COMMAND;
break;
case CMD_XMIT_BCAST64_CN:
- /* word3 iocb=iotag32 wqe=payload_len */
- wqe->words[3] = 0; /* no definition for this in wqe */
+ /* word3 iocb=iotag32 wqe=seq_payload_len */
+ wqe->xmit_bcast64.seq_payload_len = xmit_len;
/* word4 iocb=rsvd wqe=rsvd */
/* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */
/* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */
- bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+ bf_set(wqe_ct, &wqe->xmit_bcast64.wqe_com,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+ bf_set(wqe_dbde, &wqe->xmit_bcast64.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->xmit_bcast64.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,
+ LPFC_WQE_LENLOC_WORD3);
+ bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0);
break;
case CMD_FCP_IWRITE64_CR:
command_type = FCP_COMMAND_DATA_OUT;
- /* The struct for wqe fcp_iwrite has 3 fields that are somewhat
- * confusing.
- * word3 is payload_len: byte offset to the sgl entry for the
- * fcp_command.
- * word4 is total xfer len, same as the IOCB->ulpParameter.
- * word5 is initial xfer len 0 = wait for xfer-ready
- */
-
- /* Always wait for xfer-ready before sending data */
- wqe->fcp_iwrite.initial_xfer_len = 0;
- /* word 4 (xfer length) should have been set on the memcpy */
-
- /* allow write to fall through to read */
+ /* word3 iocb=iotag wqe=payload_offset_len */
+ /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
+ wqe->fcp_iwrite.payload_offset_len =
+ xmit_len + sizeof(struct fcp_rsp);
+ /* word4 iocb=parameter wqe=total_xfer_length memcpy */
+ /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */
+ bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com,
+ iocbq->iocb.ulpFCP2Rcvy);
+ bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS);
+ /* Always open the exchange */
+ bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0);
+ bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
+ LPFC_WQE_LENLOC_WORD4);
+ bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
+ bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
+ break;
case CMD_FCP_IREAD64_CR:
- /* FCP_CMD is always the 1st sgl entry */
- wqe->fcp_iread.payload_len =
+ /* word3 iocb=iotag wqe=payload_offset_len */
+ /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
+ wqe->fcp_iread.payload_offset_len =
xmit_len + sizeof(struct fcp_rsp);
-
- /* word 4 (xfer length) should have been set on the memcpy */
-
- bf_set(lpfc_wqe_gen_erp, &wqe->generic,
- iocbq->iocb.ulpFCP2Rcvy);
- bf_set(lpfc_wqe_gen_lnk, &wqe->generic, iocbq->iocb.ulpXS);
- /* The XC bit and the XS bit are similar. The driver never
- * tracked whether or not the exchange was previouslly open.
- * XC = Exchange create, 0 is create. 1 is already open.
- * XS = link cmd: 1 do not close the exchange after command.
- * XS = 0 close exchange when command completes.
- * The only time we would not set the XC bit is when the XS bit
- * is set and we are sending our 2nd or greater command on
- * this exchange.
- */
+ /* word4 iocb=parameter wqe=total_xfer_length memcpy */
+ /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */
+ bf_set(wqe_erp, &wqe->fcp_iread.wqe_com,
+ iocbq->iocb.ulpFCP2Rcvy);
+ bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS);
/* Always open the exchange */
bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
-
- wqe->words[10] &= 0xffff0000; /* zero out ebde count */
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
- break;
+ bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
+ bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
+ LPFC_WQE_LENLOC_WORD4);
+ bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
+ bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
+ break;
case CMD_FCP_ICMND64_CR:
+ /* word3 iocb=IO_TAG wqe=reserved */
+ wqe->fcp_icmd.rsrvd3 = 0;
+ bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0);
/* Always open the exchange */
- bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
-
- wqe->words[4] = 0;
- wqe->words[10] &= 0xffff0000; /* zero out ebde count */
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+ bf_set(wqe_xc, &wqe->fcp_icmd.wqe_com, 0);
+ bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
+ LPFC_WQE_LENLOC_NONE);
+ bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
break;
case CMD_GEN_REQUEST64_CR:
- /* word3 command length is described as byte offset to the
- * rsp_data. Would always be 16, sizeof(struct sli4_sge)
- * sgl[0] = cmnd
- * sgl[1] = rsp.
- *
+ /* For this command calculate the xmit length of the
+ * request bde.
*/
- wqe->gen_req.command_len = xmit_len;
- /* Word4 parameter copied in the memcpy */
- /* Word5 [rctl, type, df_ctl, la] copied in memcpy */
+ xmit_len = 0;
+ numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
+ sizeof(struct ulp_bde64);
+ for (i = 0; i < numBdes; i++) {
+ if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64)
+ break;
+ bde.tus.w = le32_to_cpu(bpl[i].tus.w);
+ xmit_len += bde.tus.f.bdeSize;
+ }
+ /* word3 iocb=IO_TAG wqe=request_payload_len */
+ wqe->gen_req.request_payload_len = xmit_len;
+ /* word4 iocb=parameter wqe=relative_offset memcpy */
+ /* word5 [rctl, type, df_ctl, la] copied in memcpy */
/* word6 context tag copied in memcpy */
if (iocbq->iocb.ulpCt_h || iocbq->iocb.ulpCt_l) {
ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
@@ -6144,31 +6552,39 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
ct, iocbq->iocb.ulpCommand);
return IOCB_ERROR;
}
- bf_set(lpfc_wqe_gen_ct, &wqe->generic, 0);
- bf_set(wqe_tmo, &wqe->gen_req.wqe_com,
- iocbq->iocb.ulpTimeout);
-
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+ bf_set(wqe_ct, &wqe->gen_req.wqe_com, 0);
+ bf_set(wqe_tmo, &wqe->gen_req.wqe_com, iocbq->iocb.ulpTimeout);
+ bf_set(wqe_pu, &wqe->gen_req.wqe_com, iocbq->iocb.ulpPU);
+ bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ);
+ bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
+ bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
command_type = OTHER_COMMAND;
break;
case CMD_XMIT_ELS_RSP64_CX:
/* words0-2 BDE memcpy */
- /* word3 iocb=iotag32 wqe=rsvd */
- wqe->words[3] = 0;
+ /* word3 iocb=iotag32 wqe=response_payload_len */
+ wqe->xmit_els_rsp.response_payload_len = xmit_len;
/* word4 iocb=did wge=rsvd. */
- wqe->words[4] = 0;
+ wqe->xmit_els_rsp.rsvd4 = 0;
/* word5 iocb=rsvd wge=did */
bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
iocbq->iocb.un.elsreq64.remoteID);
-
- bf_set(lpfc_wqe_gen_ct, &wqe->generic,
- ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
-
- bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
- bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+ bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com,
+ ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+ bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
+ bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
+ iocbq->iocb.ulpContext);
if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
- bf_set(lpfc_wqe_gen_context, &wqe->generic,
+ bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
iocbq->vport->vpi + phba->vpi_base);
+ bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com,
+ LPFC_WQE_LENLOC_WORD3);
+ bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0);
command_type = OTHER_COMMAND;
break;
case CMD_CLOSE_XRI_CN:
@@ -6193,15 +6609,19 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
else
bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
- wqe->words[5] = 0;
- bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+ /* word5 iocb=CONTEXT_TAG|IO_TAG wqe=reserved */
+ wqe->abort_cmd.rsrvd5 = 0;
+ bf_set(wqe_ct, &wqe->abort_cmd.wqe_com,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
abort_tag = iocbq->iocb.un.acxri.abortIoTag;
/*
* The abort handler will send us CMD_ABORT_XRI_CN or
* CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
*/
- bf_set(lpfc_wqe_gen_command, &wqe->generic, CMD_ABORT_XRI_CX);
+ bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
+ bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com,
+ LPFC_WQE_LENLOC_NONE);
cmnd = CMD_ABORT_XRI_CX;
command_type = OTHER_COMMAND;
xritag = 0;
@@ -6235,18 +6655,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
iocbq->iocb.ulpContext);
+ bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1);
+ bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com,
+ LPFC_WQE_LENLOC_NONE);
/* Overwrite the pre-set comnd type with OTHER_COMMAND */
command_type = OTHER_COMMAND;
break;
case CMD_XRI_ABORTED_CX:
case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
- /* words0-2 are all 0's no bde */
- /* word3 and word4 are rsvrd */
- wqe->words[3] = 0;
- wqe->words[4] = 0;
- /* word5 iocb=rsvd wge=did */
- /* There is no remote port id in the IOCB? */
- /* Let this fall through and fail */
case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */
case CMD_FCP_TRSP64_CX: /* Target mode rcv */
@@ -6257,16 +6673,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
iocbq->iocb.ulpCommand);
return IOCB_ERROR;
break;
-
}
- bf_set(lpfc_wqe_gen_xri, &wqe->generic, xritag);
- bf_set(lpfc_wqe_gen_request_tag, &wqe->generic, iocbq->iotag);
- wqe->generic.abort_tag = abort_tag;
- bf_set(lpfc_wqe_gen_cmd_type, &wqe->generic, command_type);
- bf_set(lpfc_wqe_gen_command, &wqe->generic, cmnd);
- bf_set(lpfc_wqe_gen_class, &wqe->generic, iocbq->iocb.ulpClass);
- bf_set(lpfc_wqe_gen_cq_id, &wqe->generic, LPFC_WQE_CQ_ID_DEFAULT);
-
+ bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
+ bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag);
+ wqe->generic.wqe_com.abort_tag = abort_tag;
+ bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type);
+ bf_set(wqe_cmnd, &wqe->generic.wqe_com, cmnd);
+ bf_set(wqe_class, &wqe->generic.wqe_com, iocbq->iocb.ulpClass);
+ bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
return 0;
}
@@ -6306,7 +6720,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_BUSY;
}
} else {
- sglq = __lpfc_sli_get_sglq(phba);
+ sglq = __lpfc_sli_get_sglq(phba, piocb);
if (!sglq) {
if (!(flag & SLI_IOCB_RET_IOCB)) {
__lpfc_sli_ringtx_put(phba,
@@ -7257,25 +7671,26 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
/**
- * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb
* @phba: Pointer to HBA context object.
* @pring: Pointer to driver SLI ring object.
* @cmdiocb: Pointer to driver command iocb object.
*
- * This function issues an abort iocb for the provided command
- * iocb. This function is called with hbalock held.
- * The function returns 0 when it fails due to memory allocation
- * failure or when the command iocb is an abort request.
+ * This function issues an abort iocb for the provided command iocb down to
+ * the port. Other than the case the outstanding command iocb is an abort
+ * request, this function issues abort out unconditionally. This function is
+ * called with hbalock held. The function returns 0 when it fails due to
+ * memory allocation failure or when the command iocb is an abort request.
**/
-int
-lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+static int
+lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *cmdiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
- int retval = IOCB_ERROR;
+ int retval;
/*
* There are certain command types we don't want to abort. And we
@@ -7288,18 +7703,6 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
(cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
return 0;
- /* If we're unloading, don't abort iocb on the ELS ring, but change the
- * callback so that nothing happens when it finishes.
- */
- if ((vport->load_flag & FC_UNLOADING) &&
- (pring->ringno == LPFC_ELS_RING)) {
- if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
- cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
- else
- cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
- goto abort_iotag_exit;
- }
-
/* issue ABTS for this IOCB based on iotag */
abtsiocbp = __lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
@@ -7344,6 +7747,63 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (retval)
__lpfc_sli_release_iocbq(phba, abtsiocbp);
+
+ /*
+ * Caller to this routine should check for IOCB_ERROR
+ * and handle it properly. This routine no longer removes
+ * iocb off txcmplq and call compl in case of IOCB_ERROR.
+ */
+ return retval;
+}
+
+/**
+ * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ *
+ * This function issues an abort iocb for the provided command iocb. In case
+ * of unloading, the abort iocb will not be issued to commands on the ELS
+ * ring. Instead, the callback function shall be changed to those commands
+ * so that nothing happens when them finishes. This function is called with
+ * hbalock held. The function returns 0 when the command iocb is an abort
+ * request.
+ **/
+int
+lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *cmdiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ int retval = IOCB_ERROR;
+ IOCB_t *icmd = NULL;
+
+ /*
+ * There are certain command types we don't want to abort. And we
+ * don't want to abort commands that are already in the process of
+ * being aborted.
+ */
+ icmd = &cmdiocb->iocb;
+ if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+ icmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+ (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
+ return 0;
+
+ /*
+ * If we're unloading, don't abort iocb on the ELS ring, but change
+ * the callback so that nothing happens when it finishes.
+ */
+ if ((vport->load_flag & FC_UNLOADING) &&
+ (pring->ringno == LPFC_ELS_RING)) {
+ if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
+ cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
+ else
+ cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
+ goto abort_iotag_exit;
+ }
+
+ /* Now, we try to issue the abort to the cmdiocb out */
+ retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb);
+
abort_iotag_exit:
/*
* Caller to this routine should check for IOCB_ERROR
@@ -7354,6 +7814,62 @@ abort_iotag_exit:
}
/**
+ * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function aborts all iocbs in the given ring and frees all the iocb
+ * objects in txq. This function issues abort iocbs unconditionally for all
+ * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed
+ * to complete before the return of this function. The caller is not required
+ * to hold any locks.
+ **/
+static void
+lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *iocb, *next_iocb;
+
+ if (pring->ringno == LPFC_ELS_RING)
+ lpfc_fabric_abort_hba(phba);
+
+ spin_lock_irq(&phba->hbalock);
+
+ /* Take off all the iocbs on txq for cancelling */
+ list_splice_init(&pring->txq, &completions);
+ pring->txq_cnt = 0;
+
+ /* Next issue ABTS for everything on the txcmplq */
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+ lpfc_sli_abort_iotag_issue(phba, pring, iocb);
+
+ spin_unlock_irq(&phba->hbalock);
+
+ /* Cancel all the IOCBs from the completions list */
+ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+}
+
+/**
+ * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine will abort all pending and outstanding iocbs to an HBA.
+ **/
+void
+lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+ int i;
+
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ lpfc_sli_iocb_ring_abort(phba, pring);
+ }
+}
+
+/**
* lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN
* @iocbq: Pointer to driver iocb object.
* @vport: Pointer to driver virtual port object.
@@ -7917,29 +8433,66 @@ static int
lpfc_sli4_eratt_read(struct lpfc_hba *phba)
{
uint32_t uerr_sta_hi, uerr_sta_lo;
+ uint32_t if_type, portsmphr;
+ struct lpfc_register portstat_reg;
- /* For now, use the SLI4 device internal unrecoverable error
+ /*
+ * For now, use the SLI4 device internal unrecoverable error
* registers for error attention. This can be changed later.
*/
- uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
- uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
- if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
- (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
+ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ uerr_sta_lo = readl(phba->sli4_hba.u.if_type0.UERRLOregaddr);
+ uerr_sta_hi = readl(phba->sli4_hba.u.if_type0.UERRHIregaddr);
+ if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) ||
+ (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1423 HBA Unrecoverable error: "
+ "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+ "ue_mask_lo_reg=0x%x, "
+ "ue_mask_hi_reg=0x%x\n",
+ uerr_sta_lo, uerr_sta_hi,
+ phba->sli4_hba.ue_mask_lo,
+ phba->sli4_hba.ue_mask_hi);
+ phba->work_status[0] = uerr_sta_lo;
+ phba->work_status[1] = uerr_sta_hi;
+ phba->work_ha |= HA_ERATT;
+ phba->hba_flag |= HBA_ERATT_HANDLED;
+ return 1;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ portstat_reg.word0 =
+ readl(phba->sli4_hba.u.if_type2.STATUSregaddr);
+ portsmphr = readl(phba->sli4_hba.PSMPHRregaddr);
+ if (bf_get(lpfc_sliport_status_err, &portstat_reg)) {
+ phba->work_status[0] =
+ readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
+ phba->work_status[1] =
+ readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2885 Port Error Detected: "
+ "port status reg 0x%x, "
+ "port smphr reg 0x%x, "
+ "error 1=0x%x, error 2=0x%x\n",
+ portstat_reg.word0,
+ portsmphr,
+ phba->work_status[0],
+ phba->work_status[1]);
+ phba->work_ha |= HA_ERATT;
+ phba->hba_flag |= HBA_ERATT_HANDLED;
+ return 1;
+ }
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1423 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n",
- uerr_sta_lo, uerr_sta_hi,
- phba->sli4_hba.ue_mask_lo,
- phba->sli4_hba.ue_mask_hi);
- phba->work_status[0] = uerr_sta_lo;
- phba->work_status[1] = uerr_sta_hi;
- /* Set the driver HA work bitmap */
- phba->work_ha |= HA_ERATT;
- /* Indicate polling handles this ERATT */
- phba->hba_flag |= HBA_ERATT_HANDLED;
+ "2886 HBA Error Attention on unsupported "
+ "if type %d.", if_type);
return 1;
}
+
return 0;
}
@@ -7994,7 +8547,7 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba)
ha_copy = lpfc_sli_eratt_read(phba);
break;
case LPFC_SLI_REV4:
- /* Read devcie Uncoverable Error (UERR) registers */
+ /* Read device Uncoverable Error (UERR) registers */
ha_copy = lpfc_sli4_eratt_read(phba);
break;
default:
@@ -9619,7 +10172,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id)
* lpfc_sli4_queue_free - free a queue structure and associated memory
* @queue: The queue structure to free.
*
- * This function frees a queue structure and the DMAable memeory used for
+ * This function frees a queue structure and the DMAable memory used for
* the host resident queue. This function must be called after destroying the
* queue on the HBA.
**/
@@ -10039,16 +10592,20 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
length, LPFC_SLI4_MBX_EMBED);
mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
- bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,
- mq->page_count);
- bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request,
- 1);
- bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste,
+ bf_set(lpfc_mbx_mq_create_ext_num_pages,
+ &mq_create_ext->u.request, mq->page_count);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_link,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_fip,
&mq_create_ext->u.request, 1);
bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
&mq_create_ext->u.request, 1);
- bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
- cq->queue_id);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_fc,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mbx_mq_create_ext_async_evt_sli,
+ &mq_create_ext->u.request, 1);
+ bf_set(lpfc_mq_context_cq_id,
+ &mq_create_ext->u.request.context, cq->queue_id);
bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
switch (mq->entry_count) {
default:
@@ -11021,7 +11578,8 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
static int
lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
{
- char *rctl_names[] = FC_RCTL_NAMES_INIT;
+ /* make rctl_names static to save stack space */
+ static char *rctl_names[] = FC_RCTL_NAMES_INIT;
char *type_names[] = FC_TYPE_NAMES_INIT;
struct fc_vft_header *fc_vft_hdr;
@@ -11422,6 +11980,10 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
"SID:x%x\n", oxid, sid);
return;
}
+ if (rxid >= phba->sli4_hba.max_cfg_param.xri_base
+ && rxid <= (phba->sli4_hba.max_cfg_param.max_xri
+ + phba->sli4_hba.max_cfg_param.xri_base))
+ lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0);
/* Allocate buffer for acc iocb */
ctiocb = lpfc_sli_get_iocbq(phba);
@@ -11444,6 +12006,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
+ ctiocb->context1 = ndlp;
ctiocb->iocb_cmpl = NULL;
ctiocb->vport = phba->pport;
@@ -12013,42 +12576,37 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
/**
* lpfc_sli4_init_vpi - Initialize a vpi with the port
- * @phba: pointer to lpfc hba data structure.
- * @vpi: vpi value to activate with the port.
+ * @vport: Pointer to the vport for which the vpi is being initialized
*
- * This routine is invoked to activate a vpi with the
- * port when the host intends to use vports with a
- * nonzero vpi.
+ * This routine is invoked to activate a vpi with the port.
*
* Returns:
* 0 success
* -Evalue otherwise
**/
int
-lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
+lpfc_sli4_init_vpi(struct lpfc_vport *vport)
{
LPFC_MBOXQ_t *mboxq;
int rc = 0;
int retval = MBX_SUCCESS;
uint32_t mbox_tmo;
-
- if (vpi == 0)
- return -EINVAL;
+ struct lpfc_hba *phba = vport->phba;
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq)
return -ENOMEM;
- lpfc_init_vpi(phba, mboxq, vpi);
+ lpfc_init_vpi(phba, mboxq, vport->vpi);
mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
"2022 INIT VPI Mailbox failed "
"status %d, mbxStatus x%x\n", rc,
bf_get(lpfc_mqe_status, &mboxq->u.mqe));
retval = -EIO;
}
if (rc != MBX_TIMEOUT)
- mempool_free(mboxq, phba->mbox_mem_pool);
+ mempool_free(mboxq, vport->phba->mbox_mem_pool);
return retval;
}
@@ -12242,13 +12800,15 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
/* Issue the mailbox command asynchronously */
mboxq->vport = phba->pport;
mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec;
+
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= FCF_TS_INPROG;
+ spin_unlock_irq(&phba->hbalock);
+
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED)
error = -EIO;
else {
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag |= FCF_DISC_INPROGRESS;
- spin_unlock_irq(&phba->hbalock);
/* Reset eligible FCF count for new scan */
if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
phba->fcf.eligible_fcf_cnt = 0;
@@ -12258,21 +12818,21 @@ fail_fcf_scan:
if (error) {
if (mboxq)
lpfc_sli4_mbox_cmd_free(phba, mboxq);
- /* FCF scan failed, clear FCF_DISC_INPROGRESS flag */
+ /* FCF scan failed, clear FCF_TS_INPROG flag */
spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->hba_flag &= ~FCF_TS_INPROG;
spin_unlock_irq(&phba->hbalock);
}
return error;
}
/**
- * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for round robin fcf.
+ * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for roundrobin fcf.
* @phba: pointer to lpfc hba data structure.
* @fcf_index: FCF table entry offset.
*
* This routine is invoked to read an FCF record indicated by @fcf_index
- * and to use it for FLOGI round robin FCF failover.
+ * and to use it for FLOGI roundrobin FCF failover.
*
* Return 0 if the mailbox command is submitted sucessfully, none 0
* otherwise.
@@ -12318,7 +12878,7 @@ fail_fcf_read:
* @fcf_index: FCF table entry offset.
*
* This routine is invoked to read an FCF record indicated by @fcf_index to
- * determine whether it's eligible for FLOGI round robin failover list.
+ * determine whether it's eligible for FLOGI roundrobin failover list.
*
* Return 0 if the mailbox command is submitted sucessfully, none 0
* otherwise.
@@ -12364,7 +12924,7 @@ fail_fcf_read:
*
* This routine is to get the next eligible FCF record index in a round
* robin fashion. If the next eligible FCF record index equals to the
- * initial round robin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
+ * initial roundrobin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
* shall be returned, otherwise, the next eligible FCF record's index
* shall be returned.
**/
@@ -12392,28 +12952,10 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
return LPFC_FCOE_FCF_NEXT_NONE;
}
- /* Check roundrobin failover index bmask stop condition */
- if (next_fcf_index == phba->fcf.fcf_rr_init_indx) {
- if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2847 Round robin failover FCF index "
- "search hit stop condition:x%x\n",
- next_fcf_index);
- return LPFC_FCOE_FCF_NEXT_NONE;
- }
- /* The roundrobin failover index bmask updated, start over */
- lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2848 Round robin failover FCF index bmask "
- "updated, start over\n");
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_REDISC_RRU;
- spin_unlock_irq(&phba->hbalock);
- return phba->fcf.fcf_rr_init_indx;
- }
-
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2845 Get next round robin failover "
- "FCF index x%x\n", next_fcf_index);
+ "2845 Get next roundrobin failover FCF (x%x)\n",
+ next_fcf_index);
+
return next_fcf_index;
}
@@ -12422,7 +12964,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
* @phba: pointer to lpfc hba data structure.
*
* This routine sets the FCF record index in to the eligible bmask for
- * round robin failover search. It checks to make sure that the index
+ * roundrobin failover search. It checks to make sure that the index
* does not go beyond the range of the driver allocated bmask dimension
* before setting the bit.
*
@@ -12434,22 +12976,16 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
{
if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
- "2610 HBA FCF index reached driver's "
- "book keeping dimension: fcf_index:%d, "
- "driver_bmask_max:%d\n",
+ "2610 FCF (x%x) reached driver's book "
+ "keeping dimension:x%x\n",
fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
return -EINVAL;
}
/* Set the eligible FCF record index bmask */
set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
- /* Set the roundrobin index bmask updated */
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag |= FCF_REDISC_RRU;
- spin_unlock_irq(&phba->hbalock);
-
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2790 Set FCF index x%x to round robin failover "
+ "2790 Set FCF (x%x) to roundrobin FCF failover "
"bmask\n", fcf_index);
return 0;
@@ -12460,7 +12996,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
* @phba: pointer to lpfc hba data structure.
*
* This routine clears the FCF record index from the eligible bmask for
- * round robin failover search. It checks to make sure that the index
+ * roundrobin failover search. It checks to make sure that the index
* does not go beyond the range of the driver allocated bmask dimension
* before clearing the bit.
**/
@@ -12469,9 +13005,8 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
{
if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
- "2762 HBA FCF index goes beyond driver's "
- "book keeping dimension: fcf_index:%d, "
- "driver_bmask_max:%d\n",
+ "2762 FCF (x%x) reached driver's book "
+ "keeping dimension:x%x\n",
fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
return;
}
@@ -12479,7 +13014,7 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2791 Clear FCF index x%x from round robin failover "
+ "2791 Clear FCF (x%x) from roundrobin failover "
"bmask\n", fcf_index);
}
@@ -12530,8 +13065,7 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
}
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
- "2775 Start FCF rediscovery quiescent period "
- "wait timer before scaning FCF table\n");
+ "2775 Start FCF rediscover quiescent timer\n");
/*
* Start FCF rediscovery wait timer for pending FCF
* before rescan FCF record table.
@@ -12762,6 +13296,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
struct lpfc_nodelist *act_mbx_ndlp = NULL;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
LIST_HEAD(mbox_cmd_list);
+ uint8_t restart_loop;
/* Clean up internally queued mailbox commands with the vport */
spin_lock_irq(&phba->hbalock);
@@ -12790,15 +13325,44 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
}
}
+ /* Cleanup any mailbox completions which are not yet processed */
+ do {
+ restart_loop = 0;
+ list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
+ /*
+ * If this mailox is already processed or it is
+ * for another vport ignore it.
+ */
+ if ((mb->vport != vport) ||
+ (mb->mbox_flag & LPFC_MBX_IMED_UNREG))
+ continue;
+
+ if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
+ (mb->u.mb.mbxCommand != MBX_REG_VPI))
+ continue;
+
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ ndlp = (struct lpfc_nodelist *)mb->context2;
+ /* Unregister the RPI when mailbox complete */
+ mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+ restart_loop = 1;
+ spin_unlock_irq(&phba->hbalock);
+ spin_lock(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock(shost->host_lock);
+ spin_lock_irq(&phba->hbalock);
+ break;
+ }
+ }
+ } while (restart_loop);
+
spin_unlock_irq(&phba->hbalock);
/* Release the cleaned-up mailbox commands */
while (!list_empty(&mbox_cmd_list)) {
list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list);
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
- if (phba->sli_rev == LPFC_SLI_REV4)
- __lpfc_sli4_free_rpi(phba,
- mb->u.mb.un.varRegLogin.rpi);
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -12856,12 +13420,13 @@ lpfc_drain_txq(struct lpfc_hba *phba)
while (pring->txq_cnt) {
spin_lock_irqsave(&phba->hbalock, iflags);
- sglq = __lpfc_sli_get_sglq(phba);
+ piocbq = lpfc_sli_ringtx_get(phba, pring);
+ sglq = __lpfc_sli_get_sglq(phba, piocbq);
if (!sglq) {
+ __lpfc_sli_ringtx_put(phba, pring, piocbq);
spin_unlock_irqrestore(&phba->hbalock, iflags);
break;
} else {
- piocbq = lpfc_sli_ringtx_get(phba, pring);
if (!piocbq) {
/* The txq_cnt out of sync. This should
* never happen
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index cd56d6cce6c3..453577c21c14 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -34,9 +34,11 @@ struct lpfc_cq_event {
union {
struct lpfc_mcqe mcqe_cmpl;
struct lpfc_acqe_link acqe_link;
- struct lpfc_acqe_fcoe acqe_fcoe;
+ struct lpfc_acqe_fip acqe_fip;
struct lpfc_acqe_dcbx acqe_dcbx;
struct lpfc_acqe_grp5 acqe_grp5;
+ struct lpfc_acqe_fc_la acqe_fc;
+ struct lpfc_acqe_sli acqe_sli;
struct lpfc_rcqe rcqe_cmpl;
struct sli4_wcqe_xri_aborted wcqe_axri;
struct lpfc_wcqe_complete wcqe_cmpl;
@@ -82,6 +84,7 @@ struct lpfc_iocbq {
struct lpfc_iocbq *rsp_iocb;
struct lpfcMboxq *mbox;
struct lpfc_nodelist *ndlp;
+ struct lpfc_node_rrq *rrq;
} context_un;
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index a0ca572ec28b..c7217d579e0f 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -19,10 +19,16 @@
*******************************************************************/
#define LPFC_ACTIVE_MBOX_WAIT_CNT 100
+#define LPFC_XRI_EXCH_BUSY_WAIT_TMO 10000
+#define LPFC_XRI_EXCH_BUSY_WAIT_T1 10
+#define LPFC_XRI_EXCH_BUSY_WAIT_T2 30000
#define LPFC_RELEASE_NOTIFICATION_INTERVAL 32
#define LPFC_GET_QE_REL_INT 32
#define LPFC_RPI_LOW_WATER_MARK 10
+#define LPFC_UNREG_FCF 1
+#define LPFC_SKIP_UNREG_FCF 0
+
/* Amount of time in seconds for waiting FCF rediscovery to complete */
#define LPFC_FCF_REDISCOVER_WAIT_TMO 2000 /* msec */
@@ -131,9 +137,11 @@ struct lpfc_sli4_link {
uint8_t speed;
uint8_t duplex;
uint8_t status;
- uint8_t physical;
+ uint8_t type;
+ uint8_t number;
uint8_t fault;
uint16_t logical_speed;
+ uint16_t topology;
};
struct lpfc_fcf_rec {
@@ -163,9 +171,8 @@ struct lpfc_fcf {
#define FCF_REDISC_PEND 0x80 /* FCF rediscovery pending */
#define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */
#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
-#define FCF_REDISC_RRU 0x400 /* Roundrobin bitmap updated */
+#define FCF_REDISC_PROG (FCF_REDISC_PEND | FCF_REDISC_EVT)
uint32_t addr_mode;
- uint16_t fcf_rr_init_indx;
uint32_t eligible_fcf_cnt;
struct lpfc_fcf_rec current_rec;
struct lpfc_fcf_rec failover_rec;
@@ -362,23 +369,39 @@ struct lpfc_sli4_hba {
PCI BAR1, control registers */
void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
PCI BAR2, doorbell registers */
- /* BAR0 PCI config space register memory map */
- void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */
- void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
- void __iomem *UEMASKLOregaddr; /* Address to UE_MASK_LO register */
- void __iomem *UEMASKHIregaddr; /* Address to UE_MASK_HI register */
- void __iomem *SLIINTFregaddr; /* Address to SLI_INTF register */
- /* BAR1 FCoE function CSR register memory map */
- void __iomem *STAregaddr; /* Address to HST_STATE register */
- void __iomem *ISRregaddr; /* Address to HST_ISR register */
- void __iomem *IMRregaddr; /* Address to HST_IMR register */
- void __iomem *ISCRregaddr; /* Address to HST_ISCR register */
- /* BAR2 VF-0 doorbell register memory map */
- void __iomem *RQDBregaddr; /* Address to RQ_DOORBELL register */
- void __iomem *WQDBregaddr; /* Address to WQ_DOORBELL register */
- void __iomem *EQCQDBregaddr; /* Address to EQCQ_DOORBELL register */
- void __iomem *MQDBregaddr; /* Address to MQ_DOORBELL register */
- void __iomem *BMBXregaddr; /* Address to BootStrap MBX register */
+ union {
+ struct {
+ /* IF Type 0, BAR 0 PCI cfg space reg mem map */
+ void __iomem *UERRLOregaddr;
+ void __iomem *UERRHIregaddr;
+ void __iomem *UEMASKLOregaddr;
+ void __iomem *UEMASKHIregaddr;
+ } if_type0;
+ struct {
+ /* IF Type 2, BAR 0 PCI cfg space reg mem map. */
+ void __iomem *STATUSregaddr;
+ void __iomem *CTRLregaddr;
+ void __iomem *ERR1regaddr;
+ void __iomem *ERR2regaddr;
+ } if_type2;
+ } u;
+
+ /* IF type 0, BAR1 and if type 2, Bar 0 CSR register memory map */
+ void __iomem *PSMPHRregaddr;
+
+ /* Well-known SLI INTF register memory map. */
+ void __iomem *SLIINTFregaddr;
+
+ /* IF type 0, BAR 1 function CSR register memory map */
+ void __iomem *ISRregaddr; /* HST_ISR register */
+ void __iomem *IMRregaddr; /* HST_IMR register */
+ void __iomem *ISCRregaddr; /* HST_ISCR register */
+ /* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */
+ void __iomem *RQDBregaddr; /* RQ_DOORBELL register */
+ void __iomem *WQDBregaddr; /* WQ_DOORBELL register */
+ void __iomem *EQCQDBregaddr; /* EQCQ_DOORBELL register */
+ void __iomem *MQDBregaddr; /* MQ_DOORBELL register */
+ void __iomem *BMBXregaddr; /* BootStrap MBX register */
uint32_t ue_mask_lo;
uint32_t ue_mask_hi;
@@ -461,6 +484,7 @@ struct lpfc_sglq {
struct list_head clist;
enum lpfc_sge_type buff_type; /* is this a scsi sgl */
enum lpfc_sgl_state state;
+ struct lpfc_nodelist *ndlp; /* ndlp associated with IO */
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct sli4_sge *sgl; /* pre-assigned SGL */
@@ -527,7 +551,6 @@ int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
-void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
@@ -543,7 +566,7 @@ int lpfc_sli4_brdreset(struct lpfc_hba *);
int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *);
void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
-int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_init_vpi(struct lpfc_vport *);
uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index f93120e4c796..386cf92de492 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.17"
+#define LPFC_DRIVER_VERSION "8.3.20"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index a5281ce893d0..6b8d2952e32f 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -395,8 +395,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
* by the port.
*/
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- (pport->fc_flag & FC_VFI_REGISTERED)) {
- rc = lpfc_sli4_init_vpi(phba, vpi);
+ (pport->fc_flag & FC_VFI_REGISTERED)) {
+ rc = lpfc_sli4_init_vpi(vport);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1838 Failed to INIT_VPI on vpi %d "
@@ -418,7 +418,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
if ((phba->link_state < LPFC_LINK_UP) ||
(pport->port_state < LPFC_FABRIC_CFG_LINK) ||
- (phba->fc_topology == TOPOLOGY_LOOP)) {
+ (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
goto out;
@@ -514,7 +514,7 @@ enable_vport(struct fc_vport *fc_vport)
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if ((phba->link_state < LPFC_LINK_UP) ||
- (phba->fc_topology == TOPOLOGY_LOOP)) {
+ (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
return VPORT_OK;
}
@@ -665,7 +665,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
phba->link_state >= LPFC_LINK_UP &&
- phba->fc_topology != TOPOLOGY_LOOP) {
+ phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
if (vport->cfg_enable_da_id) {
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 3ddb4dc62d5d..6c42dff0f4d3 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -66,7 +66,7 @@ static void cmd_done(struct fsc_state *, int result);
static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
-static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mac53c94_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct fsc_state *state;
@@ -99,6 +99,8 @@ static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *
return 0;
}
+static DEF_SCSI_QCMD(mac53c94_queue)
+
static int mac53c94_host_reset(struct scsi_cmnd *cmd)
{
struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 7ceb5cf12c6b..9aa048525eb2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -366,7 +366,7 @@ mega_runpendq(adapter_t *adapter)
* The command queuing entry point for the mid-layer.
*/
static int
-megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
+megaraid_queue_lck(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
{
adapter_t *adapter;
scb_t *scb;
@@ -409,6 +409,8 @@ megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
return busy;
}
+static DEF_SCSI_QCMD(megaraid_queue)
+
/**
* mega_allocate_scb()
* @adapter - pointer to our soft state
@@ -4456,7 +4458,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scb->idx = CMDID_INT_CMDS;
- megaraid_queue(scmd, mega_internal_done);
+ megaraid_queue_lck(scmd, mega_internal_done);
wait_for_completion(&adapter->int_waitq);
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 2b4a048cadf1..853411911b2e 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -13,7 +13,7 @@
*/
/*
- * Comand coalescing - This feature allows the driver to be able to combine
+ * Command coalescing - This feature allows the driver to be able to combine
* two or more commands and issue as one command in order to boost I/O
* performance. Useful if the nature of the I/O is sequential. It is not very
* useful for random natured I/Os.
@@ -987,7 +987,7 @@ static int mega_query_adapter(adapter_t *);
static int issue_scb(adapter_t *, scb_t *);
static int mega_setup_mailbox(adapter_t *);
-static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *);
static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
static void __mega_runpendq(adapter_t *);
static int issue_scb_block(adapter_t *, u_char *);
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
index f469915b97c3..5826ed509e3e 100644
--- a/drivers/scsi/megaraid/Makefile
+++ b/drivers/scsi/megaraid/Makefile
@@ -1,3 +1,5 @@
obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
+megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
+ megaraid_sas_fp.o
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index a7810a106b37..5708cb27d078 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -113,8 +113,7 @@ static int megaraid_mbox_fire_sync_cmd(adapter_t *);
static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
static void megaraid_mbox_setup_device_map(adapter_t *);
-static int megaraid_queue_command(struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
+static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
@@ -1484,7 +1483,7 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
* Queue entry point for mailbox based controllers.
*/
static int
-megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+megaraid_queue_command_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
adapter_t *adapter;
scb_t *scb;
@@ -1513,6 +1512,8 @@ megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
return if_busy;
}
+static DEF_SCSI_QCMD(megaraid_queue_command)
+
/**
* megaraid_mbox_build_cmd - transform the mid-layer scsi commands
* @adapter : controller's soft state
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index a7008c0c24f9..25506c777381 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -224,7 +224,7 @@ mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd,
{
int err;
- /* inconsistant: mraid_mm_compat_ioctl doesn't take the BKL */
+ /* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */
mutex_lock(&mraid_mm_mutex);
err = mraid_mm_ioctl(filep, cmd, arg);
mutex_unlock(&mraid_mm_mutex);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 16a4f68a34b0..1b5e375732c0 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1,15 +1,30 @@
/*
+ * Linux MegaRAID driver for SAS based RAID controllers
*
- * Linux MegaRAID driver for SAS based RAID controllers
+ * Copyright (c) 2009-2011 LSI Corporation.
*
- * Copyright (c) 2003-2005 LSI 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 free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * FILE : megaraid_sas.h
+ * You 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
+ *
+ * FILE: megaraid_sas.h
+ *
+ * Authors: LSI Corporation
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
*/
#ifndef LSI_MEGARAID_SAS_H
@@ -18,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.04.17.1-rc1"
-#define MEGASAS_RELDATE "Oct. 29, 2009"
-#define MEGASAS_EXT_VERSION "Thu. Oct. 29, 11:41:51 PST 2009"
+#define MEGASAS_VERSION "00.00.05.29-rc1"
+#define MEGASAS_RELDATE "Dec. 7, 2010"
+#define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010"
/*
* Device IDs
@@ -32,6 +47,7 @@
#define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079
#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
+#define PCI_DEVICE_ID_LSI_FUSION 0x005b
/*
* =====================================
@@ -421,7 +437,6 @@ struct megasas_ctrl_prop {
* Add properties that can be controlled by
* a bit in the following structure.
*/
-
struct {
u32 copyBackDisabled : 1;
u32 SMARTerEnabled : 1;
@@ -701,11 +716,13 @@ struct megasas_ctrl_info {
#define MEGASAS_DEFAULT_INIT_ID -1
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_DEFAULT_CMD_PER_LUN 128
#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
MEGASAS_MAX_DEV_PER_CHANNEL)
+#define MEGASAS_MAX_SECTORS (2*1024)
#define MEGASAS_DBG_LVL 1
#define MEGASAS_FW_BUSY 1
@@ -768,7 +785,10 @@ struct megasas_ctrl_info {
*/
struct megasas_register_set {
- u32 reserved_0[4]; /*0000h*/
+ u32 doorbell; /*0000h*/
+ u32 fusion_seq_offset; /*0004h*/
+ u32 fusion_host_diag; /*0008h*/
+ u32 reserved_01; /*000Ch*/
u32 inbound_msg_0; /*0010h*/
u32 inbound_msg_1; /*0014h*/
@@ -788,15 +808,18 @@ struct megasas_register_set {
u32 inbound_queue_port; /*0040h*/
u32 outbound_queue_port; /*0044h*/
- u32 reserved_2[22]; /*0048h*/
+ u32 reserved_2[9]; /*0048h*/
+ u32 reply_post_host_index; /*006Ch*/
+ u32 reserved_2_2[12]; /*0070h*/
u32 outbound_doorbell_clear; /*00A0h*/
u32 reserved_3[3]; /*00A4h*/
u32 outbound_scratch_pad ; /*00B0h*/
+ u32 outbound_scratch_pad_2; /*00B4h*/
- u32 reserved_4[3]; /*00B4h*/
+ u32 reserved_4[2]; /*00B8h*/
u32 inbound_low_queue_port ; /*00C0h*/
@@ -1271,6 +1294,9 @@ struct megasas_instance {
u16 max_num_sge;
u16 max_fw_cmds;
+ /* For Fusion its num IOCTL cmds, for others MFI based its
+ max_fw_cmds */
+ u16 max_mfi_cmds;
u32 max_sectors_per_req;
struct megasas_aen_event *ev;
@@ -1319,6 +1345,16 @@ struct megasas_instance {
struct timer_list io_completion_timer;
struct list_head internal_reset_pending_q;
+
+ /* Ptr to hba specfic information */
+ void *ctrl_context;
+ u8 msi_flag;
+ struct msix_entry msixentry;
+ u64 map_id;
+ struct megasas_cmd *map_update_cmd;
+ unsigned long bar;
+ long reset_flags;
+ struct mutex reset_mutex;
};
enum {
@@ -1344,6 +1380,13 @@ struct megasas_instance_template {
struct megasas_register_set __iomem *);
int (*check_reset)(struct megasas_instance *, \
struct megasas_register_set __iomem *);
+ irqreturn_t (*service_isr)(int irq, void *devp);
+ void (*tasklet)(unsigned long);
+ u32 (*init_adapter)(struct megasas_instance *);
+ u32 (*build_and_issue_cmd) (struct megasas_instance *,
+ struct scsi_cmnd *);
+ void (*issue_dcmd) (struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
};
#define MEGASAS_IS_LOGICAL(scp) \
@@ -1370,7 +1413,13 @@ struct megasas_cmd {
struct list_head list;
struct scsi_cmnd *scmd;
struct megasas_instance *instance;
- u32 frame_count;
+ union {
+ struct {
+ u16 smid;
+ u16 resvd;
+ } context;
+ u32 frame_count;
+ };
};
#define MAX_MGMT_ADAPTERS 1024
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index d3c9cdee292b..5d6d07bd1cd0 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1,27 +1,34 @@
/*
+ * Linux MegaRAID driver for SAS based RAID controllers
*
- * Linux MegaRAID driver for SAS based RAID controllers
+ * Copyright (c) 2009-2011 LSI Corporation.
*
- * Copyright (c) 2003-2005 LSI 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 free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * FILE : megaraid_sas.c
- * Version : v00.00.04.17.1-rc1
+ * You 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
*
- * Authors:
- * (email-id : megaraidlinux@lsi.com)
- * Sreenivas Bagalkote
- * Sumant Patro
- * Bo Yang
+ * FILE: megaraid_sas_base.c
+ * Version : v00.00.05.29-rc1
*
- * List of supported controllers
+ * Authors: LSI Corporation
+ * Sreenivas Bagalkote
+ * Sumant Patro
+ * Bo Yang
*
- * OEM Product Name VID DID SSVID SSID
- * --- ------------ --- --- ---- ----
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
*/
#include <linux/kernel.h>
@@ -46,6 +53,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
/*
@@ -56,12 +64,25 @@ module_param_named(poll_mode_io, poll_mode_io, int, 0);
MODULE_PARM_DESC(poll_mode_io,
"Complete cmds from IO path, (default=0)");
+/*
+ * Number of sectors per IO command
+ * Will be set in megasas_init_mfi if user does not provide
+ */
+static unsigned int max_sectors;
+module_param_named(max_sectors, max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+ "Maximum number of sectors per IO command");
+
+static int msix_disable;
+module_param(msix_disable, int, S_IRUGO);
+MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux@lsi.com");
MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
-static int megasas_transition_to_ready(struct megasas_instance *instance);
+int megasas_transition_to_ready(struct megasas_instance *instance);
static int megasas_get_pd_list(struct megasas_instance *instance);
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
@@ -89,6 +110,8 @@ static struct pci_device_id megasas_pci_table[] = {
/* xscale IOP, vega */
{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
/* xscale IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
+ /* Fusion */
{}
};
@@ -102,22 +125,55 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
static int megasas_poll_wait_aen;
static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
static u32 support_poll_for_event;
-static u32 megasas_dbg_lvl;
+u32 megasas_dbg_lvl;
+static u32 support_device_change;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
-static void
+void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
+static irqreturn_t megasas_isr(int irq, void *devp);
+static u32
+megasas_init_adapter_mfi(struct megasas_instance *instance);
+u32
+megasas_build_and_issue_cmd(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd);
+static void megasas_complete_cmd_dpc(unsigned long instance_addr);
+void
+megasas_release_fusion(struct megasas_instance *instance);
+int
+megasas_ioc_init_fusion(struct megasas_instance *instance);
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance);
+u8
+megasas_get_map_info(struct megasas_instance *instance);
+int
+megasas_sync_map_info(struct megasas_instance *instance);
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+void megasas_reset_reply_desc(struct megasas_instance *instance);
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+int megasas_reset_fusion(struct Scsi_Host *shost);
+void megasas_fusion_ocr_wq(struct work_struct *work);
+
+void
+megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
+}
+
/**
* megasas_get_cmd - Get a command from the free pool
* @instance: Adapter soft state
*
* Returns a free command from the pool
*/
-static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+struct megasas_cmd *megasas_get_cmd(struct megasas_instance
*instance)
{
unsigned long flags;
@@ -142,7 +198,7 @@ static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
* @instance: Adapter soft state
* @cmd: Command packet to be returned to free command pool
*/
-static inline void
+inline void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
unsigned long flags;
@@ -150,6 +206,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
spin_lock_irqsave(&instance->cmd_pool_lock, flags);
cmd->scmd = NULL;
+ cmd->frame_count = 0;
list_add_tail(&cmd->list, &instance->cmd_pool);
spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
@@ -157,7 +214,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
/**
-* The following functions are defined for xscale
+* The following functions are defined for xscale
* (deviceid : 1064R, PERC5) controllers
*/
@@ -200,7 +257,7 @@ megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
* megasas_clear_interrupt_xscale - Check & clear interrupt
* @regs: MFI register set
*/
-static int
+static int
megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
{
u32 status;
@@ -233,7 +290,7 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
* @frame_count : Number of frames for the command
* @regs : MFI register set
*/
-static inline void
+static inline void
megasas_fire_cmd_xscale(struct megasas_instance *instance,
dma_addr_t frame_phys_addr,
u32 frame_count,
@@ -313,15 +370,20 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
.adp_reset = megasas_adp_reset_xscale,
.check_reset = megasas_check_reset_xscale,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
-* This is the end of set of functions & definitions specific
+* This is the end of set of functions & definitions specific
* to xscale (deviceid : 1064R, PERC5) controllers
*/
/**
-* The following functions are defined for ppc (deviceid : 0x60)
+* The following functions are defined for ppc (deviceid : 0x60)
* controllers
*/
@@ -333,7 +395,7 @@ static inline void
megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
{
writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
-
+
writel(~0x80000000, &(regs)->outbound_intr_mask);
/* Dummy readl to force pci flush */
@@ -367,7 +429,7 @@ megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs)
* megasas_clear_interrupt_ppc - Check & clear interrupt
* @regs: MFI register set
*/
-static int
+static int
megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
{
u32 status;
@@ -396,7 +458,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
* @frame_count : Number of frames for the command
* @regs : MFI register set
*/
-static inline void
+static inline void
megasas_fire_cmd_ppc(struct megasas_instance *instance,
dma_addr_t frame_phys_addr,
u32 frame_count,
@@ -404,7 +466,7 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance,
{
unsigned long flags;
spin_lock_irqsave(&instance->hba_lock, flags);
- writel((frame_phys_addr | (frame_count<<1))|1,
+ writel((frame_phys_addr | (frame_count<<1))|1,
&(regs)->inbound_queue_port);
spin_unlock_irqrestore(&instance->hba_lock, flags);
}
@@ -431,7 +493,7 @@ megasas_check_reset_ppc(struct megasas_instance *instance,
return 0;
}
static struct megasas_instance_template megasas_instance_template_ppc = {
-
+
.fire_cmd = megasas_fire_cmd_ppc,
.enable_intr = megasas_enable_intr_ppc,
.disable_intr = megasas_disable_intr_ppc,
@@ -439,6 +501,11 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
.adp_reset = megasas_adp_reset_ppc,
.check_reset = megasas_check_reset_ppc,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
@@ -560,6 +627,11 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
.read_fw_status_reg = megasas_read_fw_status_reg_skinny,
.adp_reset = megasas_adp_reset_skinny,
.check_reset = megasas_check_reset_skinny,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
@@ -718,6 +790,10 @@ static int
megasas_check_reset_gen2(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
+ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ return 1;
+ }
+
return 0;
}
@@ -730,6 +806,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
.read_fw_status_reg = megasas_read_fw_status_reg_gen2,
.adp_reset = megasas_adp_reset_gen2,
.check_reset = megasas_check_reset_gen2,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+ .init_adapter = megasas_init_adapter_mfi,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd,
+ .issue_dcmd = megasas_issue_dcmd,
};
/**
@@ -737,18 +818,21 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
* specific to gen2 (deviceid : 0x78, 0x79) controllers
*/
+/*
+ * Template added for TB (Fusion)
+ */
+extern struct megasas_instance_template megasas_instance_template_fusion;
+
/**
* megasas_issue_polled - Issues a polling command
* @instance: Adapter soft state
- * @cmd: Command packet to be issued
+ * @cmd: Command packet to be issued
*
* For polling, MFI requires the cmd_status to be set to 0xFF before posting.
*/
-static int
+int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
- int i;
- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
@@ -758,21 +842,12 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Issue the frame using inbound queue port
*/
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
/*
* Wait for cmd_status to change
*/
- for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
- rmb();
- msleep(1);
- }
-
- if (frame_hdr->cmd_status == 0xff)
- return -ETIME;
-
- return 0;
+ return wait_and_poll(instance, cmd);
}
/**
@@ -790,8 +865,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
{
cmd->cmd_status = ENODATA;
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
@@ -835,8 +909,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 1;
cmd->cmd_status = 0xFF;
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
/*
* Wait for this cmd to complete
@@ -930,6 +1003,7 @@ megasas_make_sgl_skinny(struct megasas_instance *instance,
mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
mfi_sgl->sge_skinny[i].phys_addr =
sg_dma_address(os_sgl);
+ mfi_sgl->sge_skinny[i].flag = 0;
}
}
return sge_count;
@@ -1227,11 +1301,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/**
* megasas_is_ldio - Checks if the cmd is for logical drive
* @scmd: SCSI command
- *
+ *
* Called by megasas_queue_command to find out if the command to be queued
- * is a logical drive command
+ * is a logical drive command
*/
-static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
+inline int megasas_is_ldio(struct scsi_cmnd *cmd)
{
if (!MEGASAS_IS_LOGICAL(cmd))
return 0;
@@ -1313,16 +1387,59 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
}
+u32
+megasas_build_and_issue_cmd(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd *cmd;
+ u32 frame_count;
+
+ cmd = megasas_get_cmd(instance);
+ if (!cmd)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ /*
+ * Logical drive command
+ */
+ if (megasas_is_ldio(scmd))
+ frame_count = megasas_build_ldio(instance, scmd, cmd);
+ else
+ frame_count = megasas_build_dcdb(instance, scmd, cmd);
+
+ if (!frame_count)
+ goto out_return_cmd;
+
+ cmd->scmd = scmd;
+ scmd->SCp.ptr = (char *)cmd;
+
+ /*
+ * Issue the command to the FW
+ */
+ atomic_inc(&instance->fw_outstanding);
+
+ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+ cmd->frame_count-1, instance->reg_set);
+ /*
+ * Check if we have pend cmds to be completed
+ */
+ if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+ tasklet_schedule(&instance->isr_tasklet);
+
+ return 0;
+out_return_cmd:
+ megasas_return_cmd(instance, cmd);
+ return 1;
+}
+
+
/**
* megasas_queue_command - Queue entry point
* @scmd: SCSI command to be queued
* @done: Callback entry point
*/
static int
-megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
{
- u32 frame_count;
- struct megasas_cmd *cmd;
struct megasas_instance *instance;
unsigned long flags;
@@ -1361,47 +1478,20 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
break;
}
- cmd = megasas_get_cmd(instance);
- if (!cmd)
+ if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
+ printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n");
return SCSI_MLQUEUE_HOST_BUSY;
-
- /*
- * Logical drive command
- */
- if (megasas_is_ldio(scmd))
- frame_count = megasas_build_ldio(instance, scmd, cmd);
- else
- frame_count = megasas_build_dcdb(instance, scmd, cmd);
-
- if (!frame_count)
- goto out_return_cmd;
-
- cmd->scmd = scmd;
- scmd->SCp.ptr = (char *)cmd;
-
- /*
- * Issue the command to the FW
- */
- atomic_inc(&instance->fw_outstanding);
-
- instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
- cmd->frame_count-1, instance->reg_set);
- /*
- * Check if we have pend cmds to be completed
- */
- if (poll_mode_io && atomic_read(&instance->fw_outstanding))
- tasklet_schedule(&instance->isr_tasklet);
-
+ }
return 0;
- out_return_cmd:
- megasas_return_cmd(instance, cmd);
out_done:
done(scmd);
return 0;
}
+static DEF_SCSI_QCMD(megasas_queue_command)
+
static struct megasas_instance *megasas_lookup_instance(u16 host_no)
{
int i;
@@ -1475,15 +1565,44 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
return 0;
}
-static void megaraid_sas_kill_hba(struct megasas_instance *instance)
+void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- writel(MFI_STOP_ADP,
- &instance->reg_set->reserved_0[0]);
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) {
+ writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
} else {
- writel(MFI_STOP_ADP,
- &instance->reg_set->inbound_doorbell);
+ writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
+ }
+}
+
+ /**
+ * megasas_check_and_restore_queue_depth - Check if queue depth needs to be
+ * restored to max value
+ * @instance: Adapter soft state
+ *
+ */
+void
+megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
+{
+ unsigned long flags;
+ if (instance->flag & MEGASAS_FW_BUSY
+ && time_after(jiffies, instance->last_time + 5 * HZ)
+ && atomic_read(&instance->fw_outstanding) < 17) {
+
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ instance->flag &= ~MEGASAS_FW_BUSY;
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
+
+ spin_unlock_irqrestore(instance->host->host_lock, flags);
}
}
@@ -1537,24 +1656,29 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
/*
* Check if we can restore can_queue
*/
- if (instance->flag & MEGASAS_FW_BUSY
- && time_after(jiffies, instance->last_time + 5 * HZ)
- && atomic_read(&instance->fw_outstanding) < 17) {
+ megasas_check_and_restore_queue_depth(instance);
+}
- spin_lock_irqsave(instance->host->host_lock, flags);
- instance->flag &= ~MEGASAS_FW_BUSY;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
- } else
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+static void
+megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
- spin_unlock_irqrestore(instance->host->host_lock, flags);
+static void
+process_fw_state_change_wq(struct work_struct *work);
+
+void megasas_do_ocr(struct megasas_instance *instance)
+{
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+ (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
+ *instance->consumer = MEGASAS_ADPRESET_INPROG_SIGN;
}
+ instance->instancet->disable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->issuepend_done = 0;
+
+ atomic_set(&instance->fw_outstanding, 0);
+ megasas_internal_reset_defer_cmds(instance);
+ process_fw_state_change_wq(&instance->work_init);
}
/**
@@ -1574,6 +1698,8 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
unsigned long flags;
struct list_head clist_local;
struct megasas_cmd *reset_cmd;
+ u32 fw_state;
+ u8 kill_adapter_flag;
spin_lock_irqsave(&instance->hba_lock, flags);
adprecovery = instance->adprecovery;
@@ -1659,7 +1785,45 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
msleep(1000);
}
- if (atomic_read(&instance->fw_outstanding)) {
+ i = 0;
+ kill_adapter_flag = 0;
+ do {
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if ((fw_state == MFI_STATE_FAULT) &&
+ (instance->disableOnlineCtrlReset == 0)) {
+ if (i == 3) {
+ kill_adapter_flag = 2;
+ break;
+ }
+ megasas_do_ocr(instance);
+ kill_adapter_flag = 1;
+
+ /* wait for 1 secs to let FW finish the pending cmds */
+ msleep(1000);
+ }
+ i++;
+ } while (i <= 3);
+
+ if (atomic_read(&instance->fw_outstanding) &&
+ !kill_adapter_flag) {
+ if (instance->disableOnlineCtrlReset == 0) {
+
+ megasas_do_ocr(instance);
+
+ /* wait for 5 secs to let FW finish the pending cmds */
+ for (i = 0; i < wait_time; i++) {
+ int outstanding =
+ atomic_read(&instance->fw_outstanding);
+ if (!outstanding)
+ return SUCCESS;
+ msleep(1000);
+ }
+ }
+ }
+
+ if (atomic_read(&instance->fw_outstanding) ||
+ (kill_adapter_flag == 2)) {
printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
/*
* Send signal to FW to stop processing any pending cmds.
@@ -1670,7 +1834,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
writel(MFI_STOP_ADP,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else {
writel(MFI_STOP_ADP,
&instance->reg_set->inbound_doorbell);
@@ -1774,11 +1938,16 @@ static int megasas_reset_device(struct scsi_cmnd *scmd)
static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
{
int ret;
+ struct megasas_instance *instance;
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
/*
* First wait for all commands to complete
*/
- ret = megasas_generic_reset(scmd);
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ ret = megasas_reset_fusion(scmd->device->host);
+ else
+ ret = megasas_generic_reset(scmd);
return ret;
}
@@ -1921,8 +2090,8 @@ megasas_complete_int_cmd(struct megasas_instance *instance,
* @instance: Adapter soft state
* @cmd: Cmd that was issued to abort another cmd
*
- * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
- * after it issues an abort on a previously issued command. This function
+ * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
+ * after it issues an abort on a previously issued command. This function
* wakes up all functions waiting on the same wait queue.
*/
static void
@@ -1942,19 +2111,20 @@ megasas_complete_abort(struct megasas_instance *instance,
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
* @cmd: Command to be completed
- * @alt_status: If non-zero, use this value as status to
+ * @alt_status: If non-zero, use this value as status to
* SCSI mid-layer instead of the value returned
* by the FW. This should be used if caller wants
* an alternate status (as in the case of aborted
* commands)
*/
-static void
+void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status)
{
int exception = 0;
struct megasas_header *hdr = &cmd->frame->hdr;
unsigned long flags;
+ struct fusion_context *fusion = instance->ctrl_context;
/* flag for the retry reset */
cmd->retry_for_fw_reset = 0;
@@ -2047,6 +2217,37 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_DCMD:
+ /* Check for LD map update */
+ if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
+ (cmd->frame->dcmd.mbox.b[1] == 1)) {
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ if (cmd->frame->hdr.cmd_status != 0) {
+ if (cmd->frame->hdr.cmd_status !=
+ MFI_STAT_NOT_FOUND)
+ printk(KERN_WARNING "megasas: map sync"
+ "failed, status = 0x%x.\n",
+ cmd->frame->hdr.cmd_status);
+ else {
+ megasas_return_cmd(instance, cmd);
+ spin_unlock_irqrestore(
+ instance->host->host_lock,
+ flags);
+ break;
+ }
+ } else
+ instance->map_id++;
+ megasas_return_cmd(instance, cmd);
+ if (MR_ValidateMapInfo(
+ fusion->ld_map[(instance->map_id & 1)],
+ fusion->load_balance_info))
+ fusion->fast_path_io = 1;
+ else
+ fusion->fast_path_io = 0;
+ megasas_sync_map_info(instance);
+ spin_unlock_irqrestore(instance->host->host_lock,
+ flags);
+ break;
+ }
if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
spin_lock_irqsave(&poll_aen_lock, flags);
@@ -2385,7 +2586,7 @@ static irqreturn_t megasas_isr(int irq, void *devp)
* states, driver must take steps to bring it to ready state. Otherwise, it
* has to wait for the ready state.
*/
-static int
+int
megasas_transition_to_ready(struct megasas_instance* instance)
{
int i;
@@ -2397,8 +2598,8 @@ megasas_transition_to_ready(struct megasas_instance* instance)
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
if (fw_state != MFI_STATE_READY)
- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
- " state\n");
+ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ " state\n");
while (fw_state != MFI_STATE_READY) {
@@ -2419,11 +2620,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
-
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION)) {
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else {
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
@@ -2436,11 +2638,13 @@ megasas_transition_to_ready(struct megasas_instance* instance)
case MFI_STATE_BOOT_MESSAGE_PENDING:
if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION)) {
writel(MFI_INIT_HOTPLUG,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
} else
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
@@ -2457,9 +2661,23 @@ megasas_transition_to_ready(struct megasas_instance* instance)
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device
+ == PCI_DEVICE_ID_LSI_FUSION)) {
writel(MFI_RESET_FLAGS,
- &instance->reg_set->reserved_0[0]);
+ &instance->reg_set->doorbell);
+ if (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_FUSION) {
+ for (i = 0; i < (10 * 1000); i += 20) {
+ if (readl(
+ &instance->
+ reg_set->
+ doorbell) & 1)
+ msleep(20);
+ else
+ break;
+ }
+ }
} else
writel(MFI_RESET_FLAGS,
&instance->reg_set->inbound_doorbell);
@@ -2511,7 +2729,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
* The cur_state should not last for more than max_wait secs
*/
for (i = 0; i < (max_wait * 1000); i++) {
- fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
MFI_STATE_MASK ;
curr_abs_state =
instance->instancet->read_fw_status_reg(instance->reg_set);
@@ -2531,7 +2749,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
return -ENODEV;
}
}
- printk(KERN_INFO "megasas: FW now in Ready state\n");
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
return 0;
}
@@ -2543,7 +2761,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
static void megasas_teardown_frame_pool(struct megasas_instance *instance)
{
int i;
- u32 max_cmd = instance->max_fw_cmds;
+ u32 max_cmd = instance->max_mfi_cmds;
struct megasas_cmd *cmd;
if (!instance->frame_dma_pool)
@@ -2594,7 +2812,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
u32 frame_count;
struct megasas_cmd *cmd;
- max_cmd = instance->max_fw_cmds;
+ max_cmd = instance->max_mfi_cmds;
/*
* Size of our frame is 64 bytes for MFI frame, followed by max SG
@@ -2669,6 +2887,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
return -ENOMEM;
}
+ memset(cmd->frame, 0, total_sz);
cmd->frame->io.context = cmd->index;
cmd->frame->io.pad_0 = 0;
}
@@ -2680,14 +2899,15 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
* megasas_free_cmds - Free all the cmds in the free cmd pool
* @instance: Adapter soft state
*/
-static void megasas_free_cmds(struct megasas_instance *instance)
+void megasas_free_cmds(struct megasas_instance *instance)
{
int i;
/* First free the MFI frame pool */
megasas_teardown_frame_pool(instance);
/* Free all the commands in the cmd_list */
- for (i = 0; i < instance->max_fw_cmds; i++)
+ for (i = 0; i < instance->max_mfi_cmds; i++)
+
kfree(instance->cmd_list[i]);
/* Free the cmd_list buffer itself */
@@ -2715,14 +2935,14 @@ static void megasas_free_cmds(struct megasas_instance *instance)
* This array is used only to look up the megasas_cmd given the context. The
* free commands themselves are maintained in a linked list called cmd_pool.
*/
-static int megasas_alloc_cmds(struct megasas_instance *instance)
+int megasas_alloc_cmds(struct megasas_instance *instance)
{
int i;
int j;
u32 max_cmd;
struct megasas_cmd *cmd;
- max_cmd = instance->max_fw_cmds;
+ max_cmd = instance->max_mfi_cmds;
/*
* instance->cmd_list is an array of struct megasas_cmd pointers.
@@ -2736,6 +2956,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
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),
@@ -3130,76 +3351,15 @@ megasas_io_completion_timer(unsigned long instance_addr)
jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
}
-/**
- * megasas_init_mfi - Initializes the FW
- * @instance: Adapter soft state
- *
- * This is the main function for initializing MFI firmware.
- */
-static int megasas_init_mfi(struct megasas_instance *instance)
+static u32
+megasas_init_adapter_mfi(struct megasas_instance *instance)
{
+ struct megasas_register_set __iomem *reg_set;
u32 context_sz;
u32 reply_q_sz;
- u32 max_sectors_1;
- u32 max_sectors_2;
- u32 tmp_sectors;
- struct megasas_register_set __iomem *reg_set;
- struct megasas_ctrl_info *ctrl_info;
- /*
- * Map the message registers
- */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
- instance->base_addr = pci_resource_start(instance->pdev, 1);
- } else {
- instance->base_addr = pci_resource_start(instance->pdev, 0);
- }
-
- if (pci_request_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM),
- "megasas: LSI")) {
- printk(KERN_DEBUG "megasas: IO memory region busy!\n");
- return -EBUSY;
- }
-
- instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
-
- if (!instance->reg_set) {
- printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
- goto fail_ioremap;
- }
reg_set = instance->reg_set;
- switch(instance->pdev->device)
- {
- case PCI_DEVICE_ID_LSI_SAS1078R:
- case PCI_DEVICE_ID_LSI_SAS1078DE:
- instance->instancet = &megasas_instance_template_ppc;
- break;
- case PCI_DEVICE_ID_LSI_SAS1078GEN2:
- case PCI_DEVICE_ID_LSI_SAS0079GEN2:
- instance->instancet = &megasas_instance_template_gen2;
- break;
- case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
- case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
- instance->instancet = &megasas_instance_template_skinny;
- break;
- case PCI_DEVICE_ID_LSI_SAS1064R:
- case PCI_DEVICE_ID_DELL_PERC5:
- default:
- instance->instancet = &megasas_instance_template_xscale;
- break;
- }
-
- /*
- * We expect the FW state to be READY
- */
- if (megasas_transition_to_ready(instance))
- goto fail_ready_state;
-
/*
* Get various operational parameters from status register
*/
@@ -3210,7 +3370,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* does not exceed max cmds that the FW can support
*/
instance->max_fw_cmds = instance->max_fw_cmds-1;
- instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
+ instance->max_mfi_cmds = instance->max_fw_cmds;
+ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
0x10;
/*
* Create a pool of commands
@@ -3253,6 +3414,90 @@ static int megasas_init_mfi(struct megasas_instance *instance)
if (instance->fw_support_ieee)
instance->flag_ieee = 1;
+ return 0;
+
+fail_fw_init:
+
+ pci_free_consistent(instance->pdev, reply_q_sz,
+ instance->reply_queue, instance->reply_queue_h);
+fail_reply_queue:
+ megasas_free_cmds(instance);
+
+fail_alloc_cmds:
+ iounmap(instance->reg_set);
+ return 1;
+}
+
+/**
+ * megasas_init_fw - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * This is the main function for initializing firmware
+ */
+
+static int megasas_init_fw(struct megasas_instance *instance)
+{
+ u32 max_sectors_1;
+ u32 max_sectors_2;
+ u32 tmp_sectors;
+ struct megasas_register_set __iomem *reg_set;
+ struct megasas_ctrl_info *ctrl_info;
+ unsigned long bar_list;
+
+ /* Find first memory bar */
+ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
+ instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
+ instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
+ if (pci_request_selected_regions(instance->pdev, instance->bar,
+ "megasas: LSI")) {
+ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+ return -EBUSY;
+ }
+
+ instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+
+ if (!instance->reg_set) {
+ printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
+ goto fail_ioremap;
+ }
+
+ reg_set = instance->reg_set;
+
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ instance->instancet = &megasas_instance_template_fusion;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1078R:
+ case PCI_DEVICE_ID_LSI_SAS1078DE:
+ instance->instancet = &megasas_instance_template_ppc;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+ case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+ instance->instancet = &megasas_instance_template_gen2;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+ instance->instancet = &megasas_instance_template_skinny;
+ break;
+ case PCI_DEVICE_ID_LSI_SAS1064R:
+ case PCI_DEVICE_ID_DELL_PERC5:
+ default:
+ instance->instancet = &megasas_instance_template_xscale;
+ break;
+ }
+
+ /*
+ * We expect the FW state to be READY
+ */
+ if (megasas_transition_to_ready(instance))
+ goto fail_ready_state;
+
+ /* Get operational params, sge flags, send init cmd to controller */
+ if (instance->instancet->init_adapter(instance))
+ return -ENODEV;
+
+ printk(KERN_ERR "megasas: INIT adapter done\n");
+
/** for passthrough
* the following function will get the PD LIST.
*/
@@ -3308,20 +3553,11 @@ static int megasas_init_mfi(struct megasas_instance *instance)
MEGASAS_COMPLETION_TIMER_INTERVAL);
return 0;
- fail_fw_init:
-
- pci_free_consistent(instance->pdev, reply_q_sz,
- instance->reply_queue, instance->reply_queue_h);
- fail_reply_queue:
- megasas_free_cmds(instance);
-
- fail_alloc_cmds:
- fail_ready_state:
+fail_ready_state:
iounmap(instance->reg_set);
fail_ioremap:
- pci_release_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM));
+ pci_release_selected_regions(instance->pdev, instance->bar);
return -EINVAL;
}
@@ -3332,17 +3568,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
*/
static void megasas_release_mfi(struct megasas_instance *instance)
{
- u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
+ u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
- pci_free_consistent(instance->pdev, reply_q_sz,
+ if (instance->reply_queue)
+ pci_free_consistent(instance->pdev, reply_q_sz,
instance->reply_queue, instance->reply_queue_h);
megasas_free_cmds(instance);
iounmap(instance->reg_set);
- pci_release_selected_regions(instance->pdev,
- pci_select_bars(instance->pdev, IORESOURCE_MEM));
+ pci_release_selected_regions(instance->pdev, instance->bar);
}
/**
@@ -3529,8 +3765,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
/*
* Issue the aen registration frame
*/
- instance->instancet->fire_cmd(instance,
- cmd->frame_phys_addr, 0, instance->reg_set);
+ instance->instancet->issue_dcmd(instance, cmd);
return 0;
}
@@ -3585,13 +3820,40 @@ static int megasas_io_attach(struct megasas_instance *instance)
instance->max_fw_cmds - MEGASAS_INT_CMDS;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
+ /*
+ * Check if the module parameter value for max_sectors can be used
+ */
+ if (max_sectors && max_sectors < instance->max_sectors_per_req)
+ instance->max_sectors_per_req = max_sectors;
+ else {
+ if (max_sectors) {
+ if (((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
+ (max_sectors <= MEGASAS_MAX_SECTORS)) {
+ instance->max_sectors_per_req = max_sectors;
+ } else {
+ printk(KERN_INFO "megasas: max_sectors should be > 0"
+ "and <= %d (or < 1MB for GEN2 controller)\n",
+ instance->max_sectors_per_req);
+ }
+ }
+ }
+
host->max_sectors = instance->max_sectors_per_req;
- host->cmd_per_lun = 128;
+ host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
host->max_channel = MEGASAS_MAX_CHANNELS - 1;
host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
host->max_lun = MEGASAS_MAX_LUN;
host->max_cmd_len = 16;
+ /* Fusion only supports host reset */
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
+ host->hostt->eh_device_reset_handler = NULL;
+ host->hostt->eh_bus_reset_handler = NULL;
+ }
+
/*
* Notify the mid-layer about the new controller
*/
@@ -3632,7 +3894,7 @@ fail_set_dma_mask:
/**
* megasas_probe_one - PCI hotplug entry point
* @pdev: PCI device structure
- * @id: PCI ids of supported hotplugged adapter
+ * @id: PCI ids of supported hotplugged adapter
*/
static int __devinit
megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -3676,20 +3938,45 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance = (struct megasas_instance *)host->hostdata;
memset(instance, 0, sizeof(*instance));
atomic_set( &instance->fw_reset_no_pci_access, 0 );
+ instance->pdev = pdev;
- instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
- &instance->producer_h);
- instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
- &instance->consumer_h);
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ {
+ struct fusion_context *fusion;
+
+ instance->ctrl_context =
+ kzalloc(sizeof(struct fusion_context), GFP_KERNEL);
+ if (!instance->ctrl_context) {
+ printk(KERN_DEBUG "megasas: Failed to allocate "
+ "memory for Fusion context info\n");
+ goto fail_alloc_dma_buf;
+ }
+ fusion = instance->ctrl_context;
+ INIT_LIST_HEAD(&fusion->cmd_pool);
+ spin_lock_init(&fusion->cmd_pool_lock);
+ }
+ break;
+ default: /* For all other supported controllers */
+
+ instance->producer =
+ pci_alloc_consistent(pdev, sizeof(u32),
+ &instance->producer_h);
+ instance->consumer =
+ pci_alloc_consistent(pdev, sizeof(u32),
+ &instance->consumer_h);
+
+ if (!instance->producer || !instance->consumer) {
+ printk(KERN_DEBUG "megasas: Failed to allocate"
+ "memory for producer, consumer\n");
+ goto fail_alloc_dma_buf;
+ }
- if (!instance->producer || !instance->consumer) {
- printk(KERN_DEBUG "megasas: Failed to allocate memory for "
- "producer, consumer\n");
- goto fail_alloc_dma_buf;
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ break;
}
- *instance->producer = 0;
- *instance->consumer = 0;
megasas_poll_wait_aen = 0;
instance->flag_ieee = 0;
instance->ev = NULL;
@@ -3725,11 +4012,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&poll_aen_lock);
mutex_init(&instance->aen_mutex);
+ mutex_init(&instance->reset_mutex);
/*
* Initialize PCI related and misc parameters
*/
- instance->pdev = pdev;
instance->host = host;
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
@@ -3747,18 +4034,31 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->last_time = 0;
instance->disableOnlineCtrlReset = 1;
- INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
+ else
+ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
/*
* Initialize MFI Firmware
*/
- if (megasas_init_mfi(instance))
+ if (megasas_init_fw(instance))
goto fail_init_mfi;
+ /* Try to enable MSI-X */
+ if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_VERDE_ZCR) &&
+ !msix_disable && !pci_enable_msix(instance->pdev,
+ &instance->msixentry, 1))
+ instance->msi_flag = 1;
+
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
goto fail_irq;
}
@@ -3803,9 +4103,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, NULL);
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
-
- megasas_release_mfi(instance);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
fail_irq:
fail_init_mfi:
@@ -3815,9 +4116,13 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->evt_detail,
instance->evt_detail_h);
- if (instance->producer)
+ if (instance->producer) {
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
+ megasas_release_mfi(instance);
+ } else {
+ megasas_release_fusion(instance);
+ }
if (instance->consumer)
pci_free_consistent(pdev, sizeof(u32), instance->consumer,
instance->consumer_h);
@@ -3889,7 +4194,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
-
+ if (instance->map_update_cmd)
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->map_update_cmd);
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -3945,7 +4252,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
pci_set_drvdata(instance->pdev, instance);
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
pci_save_state(pdev);
pci_disable_device(pdev);
@@ -3991,9 +4301,6 @@ megasas_resume(struct pci_dev *pdev)
* Initialize MFI Firmware
*/
- *instance->producer = 0;
- *instance->consumer = 0;
-
atomic_set(&instance->fw_outstanding, 0);
/*
@@ -4002,17 +4309,40 @@ megasas_resume(struct pci_dev *pdev)
if (megasas_transition_to_ready(instance))
goto fail_ready_state;
- if (megasas_issue_init_mfi(instance))
- goto fail_init_mfi;
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ {
+ megasas_reset_reply_desc(instance);
+ if (megasas_ioc_init_fusion(instance)) {
+ megasas_free_cmds(instance);
+ megasas_free_cmds_fusion(instance);
+ goto fail_init_mfi;
+ }
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+ }
+ break;
+ default:
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ if (megasas_issue_init_mfi(instance))
+ goto fail_init_mfi;
+ break;
+ }
- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
- (unsigned long)instance);
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
+
+ /* Now re-enable MSI-X */
+ if (instance->msi_flag)
+ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
- "megasas", instance)) {
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
printk(KERN_ERR "megasas: Failed to register IRQ\n");
goto fail_irq;
}
@@ -4070,10 +4400,12 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
int i;
struct Scsi_Host *host;
struct megasas_instance *instance;
+ struct fusion_context *fusion;
instance = pci_get_drvdata(pdev);
instance->unload = 1;
host = instance->host;
+ fusion = instance->ctrl_context;
if (poll_mode_io)
del_timer_sync(&instance->io_completion_timer);
@@ -4110,18 +4442,37 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
instance->instancet->disable_intr(instance->reg_set);
- free_irq(instance->pdev->irq, instance);
-
- megasas_release_mfi(instance);
-
- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
- instance->evt_detail, instance->evt_detail_h);
-
- pci_free_consistent(pdev, sizeof(u32), instance->producer,
- instance->producer_h);
-
- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
- instance->consumer_h);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
+
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ megasas_release_fusion(instance);
+ for (i = 0; i < 2 ; i++)
+ if (fusion->ld_map[i])
+ dma_free_coherent(&instance->pdev->dev,
+ fusion->map_sz,
+ fusion->ld_map[i],
+ fusion->
+ ld_map_phys[i]);
+ kfree(instance->ctrl_context);
+ break;
+ default:
+ megasas_release_mfi(instance);
+ pci_free_consistent(pdev,
+ sizeof(struct megasas_evt_detail),
+ instance->evt_detail,
+ instance->evt_detail_h);
+ pci_free_consistent(pdev, sizeof(u32),
+ instance->producer,
+ instance->producer_h);
+ pci_free_consistent(pdev, sizeof(u32),
+ instance->consumer,
+ instance->consumer_h);
+ break;
+ }
scsi_host_put(host);
@@ -4658,6 +5009,15 @@ megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
megasas_sysfs_show_support_poll_for_event, NULL);
+ static ssize_t
+megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_device_change);
+}
+
+static DRIVER_ATTR(support_device_change, S_IRUGO,
+ megasas_sysfs_show_support_device_change, NULL);
+
static ssize_t
megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
{
@@ -4876,6 +5236,7 @@ megasas_aen_polling(struct work_struct *work)
break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
+ case MR_EVT_LD_STATE_CHANGE:
doscan = 1;
break;
default:
@@ -4978,6 +5339,7 @@ static int __init megasas_init(void)
MEGASAS_EXT_VERSION);
support_poll_for_event = 2;
+ support_device_change = 1;
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
@@ -5026,8 +5388,17 @@ static int __init megasas_init(void)
if (rval)
goto err_dcf_poll_mode_io;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_device_change);
+ if (rval)
+ goto err_dcf_support_device_change;
+
return rval;
+err_dcf_support_device_change:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_poll_mode_io);
+
err_dcf_poll_mode_io:
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
@@ -5045,7 +5416,7 @@ err_dcf_attr_ver:
pci_unregister_driver(&megasas_pci_driver);
err_pcidrv:
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
- return rval;
+ return rval;
}
/**
@@ -5058,6 +5429,10 @@ static void __exit megasas_exit(void)
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_device_change);
+ driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
new file mode 100644
index 000000000000..53fa96ae2b3e
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -0,0 +1,516 @@
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI 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
+ *
+ * FILE: megaraid_sas_fp.c
+ *
+ * Authors: LSI Corporation
+ * Sumant Patro
+ * Varad Talamacki
+ * Manoj Jose
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/compat.h>
+#include <linux/blkdev.h>
+#include <linux/poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include <asm/div64.h>
+
+#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
+#define MR_LD_STATE_OPTIMAL 3
+#define FALSE 0
+#define TRUE 1
+
+/* Prototypes */
+void
+mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+
+u32 mega_mod64(u64 dividend, u32 divisor)
+{
+ u64 d;
+ u32 remainder;
+
+ if (!divisor)
+ printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
+ d = dividend;
+ remainder = do_div(d, divisor);
+ return remainder;
+}
+
+/**
+ * @param dividend : Dividend
+ * @param divisor : Divisor
+ *
+ * @return quotient
+ **/
+u64 mega_div64_32(uint64_t dividend, uint32_t divisor)
+{
+ u32 remainder;
+ u64 d;
+
+ if (!divisor)
+ printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");
+
+ d = dividend;
+ remainder = do_div(d, divisor);
+
+ return d;
+}
+
+struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return &map->raidMap.ldSpanMap[ld].ldRaid;
+}
+
+static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,
+ struct MR_FW_RAID_MAP_ALL
+ *map)
+{
+ return &map->raidMap.ldSpanMap[ld].spanBlock[0];
+}
+
+static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
+}
+
+static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.arMapInfo[ar].pd[arm];
+}
+
+static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
+}
+
+static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.devHndlInfo[pd].curDevHdl;
+}
+
+u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
+}
+
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
+{
+ return map->raidMap.ldTgtIdToLd[ldTgtId];
+}
+
+static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
+}
+
+/*
+ * This function will validate Map info data provided by FW
+ */
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo)
+{
+ struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
+
+ if (pFwRaidMap->totalSize !=
+ (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) {
+ printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
+ (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
+ sizeof(struct MR_LD_SPAN_MAP)) +
+ (sizeof(struct MR_LD_SPAN_MAP) *
+ pFwRaidMap->ldCount)));
+ printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
+ ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
+ pFwRaidMap->totalSize);
+ return 0;
+ }
+
+ mr_update_load_balance_params(map, lbInfo);
+
+ return 1;
+}
+
+u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
+ struct MR_FW_RAID_MAP_ALL *map, int *div_error)
+{
+ struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
+ struct MR_QUAD_ELEMENT *quad;
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u32 span, j;
+
+ for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
+
+ for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
+ quad = &pSpanBlock->block_span_info.quad[j];
+
+ if (quad->diff == 0) {
+ *div_error = 1;
+ return span;
+ }
+ if (quad->logStart <= row && row <= quad->logEnd &&
+ (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
+ if (span_blk != NULL) {
+ u64 blk, debugBlk;
+ blk =
+ mega_div64_32(
+ (row-quad->logStart),
+ quad->diff);
+ debugBlk = blk;
+
+ blk = (blk + quad->offsetInSpan) <<
+ raid->stripeShift;
+ *span_blk = blk;
+ }
+ return span;
+ }
+ }
+ }
+ return span;
+}
+
+/*
+******************************************************************************
+*
+* This routine calculates the arm, span and block for the specified stripe and
+* reference in stripe.
+*
+* Inputs :
+*
+* ld - Logical drive number
+* stripRow - Stripe number
+* stripRef - Reference in stripe
+*
+* Outputs :
+*
+* span - Span number
+* block - Absolute Block number in the physical disk
+*/
+u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
+ u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u32 pd, arRef;
+ u8 physArm, span;
+ u64 row;
+ u8 retval = TRUE;
+ int error_code = 0;
+
+ row = mega_div64_32(stripRow, raid->rowDataSize);
+
+ if (raid->level == 6) {
+ /* logical arm within row */
+ u32 logArm = mega_mod64(stripRow, raid->rowDataSize);
+ u32 rowMod, armQ, arm;
+
+ if (raid->rowSize == 0)
+ return FALSE;
+ /* get logical row mod */
+ rowMod = mega_mod64(row, raid->rowSize);
+ armQ = raid->rowSize-1-rowMod; /* index of Q drive */
+ arm = armQ+1+logArm; /* data always logically follows Q */
+ if (arm >= raid->rowSize) /* handle wrap condition */
+ arm -= raid->rowSize;
+ physArm = (u8)arm;
+ } else {
+ if (raid->modFactor == 0)
+ return FALSE;
+ physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow,
+ raid->modFactor),
+ map);
+ }
+
+ if (raid->spanDepth == 1) {
+ span = 0;
+ *pdBlock = row << raid->stripeShift;
+ } else {
+ span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
+ if (error_code == 1)
+ return FALSE;
+ }
+
+ /* Get the array on which this span is present */
+ arRef = MR_LdSpanArrayGet(ld, span, map);
+ pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
+
+ if (pd != MR_PD_INVALID)
+ /* Get dev handle from Pd. */
+ *pDevHandle = MR_PdDevHandleGet(pd, map);
+ else {
+ *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
+ if (raid->level >= 5)
+ pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
+ else if (raid->level == 1) {
+ /* Get alternate Pd. */
+ pd = MR_ArPdGet(arRef, physArm + 1, map);
+ if (pd != MR_PD_INVALID)
+ /* Get dev handle from Pd */
+ *pDevHandle = MR_PdDevHandleGet(pd, map);
+ }
+ retval = FALSE;
+ }
+
+ *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
+ pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
+ physArm;
+ return retval;
+}
+
+/*
+******************************************************************************
+*
+* MR_BuildRaidContext function
+*
+* This function will initiate command processing. The start/end row and strip
+* information is calculated then the lock is acquired.
+* This function will return 0 if region lock was acquired OR return num strips
+*/
+u8
+MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid;
+ u32 ld, stripSize, stripe_mask;
+ u64 endLba, endStrip, endRow, start_row, start_strip;
+ u64 regStart;
+ u32 regSize;
+ u8 num_strips, numRows;
+ u16 ref_in_start_stripe, ref_in_end_stripe;
+ u64 ldStartBlock;
+ u32 numBlocks, ldTgtId;
+ u8 isRead;
+ u8 retval = 0;
+
+ ldStartBlock = io_info->ldStartBlock;
+ numBlocks = io_info->numBlocks;
+ ldTgtId = io_info->ldTgtId;
+ isRead = io_info->isRead;
+
+ ld = MR_TargetIdToLdGet(ldTgtId, map);
+ raid = MR_LdRaidGet(ld, map);
+
+ stripSize = 1 << raid->stripeShift;
+ stripe_mask = stripSize-1;
+ /*
+ * calculate starting row and stripe, and number of strips and rows
+ */
+ start_strip = ldStartBlock >> raid->stripeShift;
+ ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);
+ endLba = ldStartBlock + numBlocks - 1;
+ ref_in_end_stripe = (u16)(endLba & stripe_mask);
+ endStrip = endLba >> raid->stripeShift;
+ num_strips = (u8)(endStrip - start_strip + 1); /* End strip */
+ if (raid->rowDataSize == 0)
+ return FALSE;
+ start_row = mega_div64_32(start_strip, raid->rowDataSize);
+ endRow = mega_div64_32(endStrip, raid->rowDataSize);
+ numRows = (u8)(endRow - start_row + 1);
+
+ /*
+ * calculate region info.
+ */
+
+ /* assume region is at the start of the first row */
+ regStart = start_row << raid->stripeShift;
+ /* assume this IO needs the full row - we'll adjust if not true */
+ regSize = stripSize;
+
+ /* If IO spans more than 1 strip, fp is not possible
+ FP is not possible for writes on non-0 raid levels
+ FP is not possible if LD is not capable */
+ if (num_strips > 1 || (!isRead && raid->level != 0) ||
+ !raid->capability.fpCapable) {
+ io_info->fpOkForIo = FALSE;
+ } else {
+ io_info->fpOkForIo = TRUE;
+ }
+
+ if (numRows == 1) {
+ /* single-strip IOs can always lock only the data needed */
+ if (num_strips == 1) {
+ regStart += ref_in_start_stripe;
+ regSize = numBlocks;
+ }
+ /* multi-strip IOs always need to full stripe locked */
+ } else {
+ if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
+ /* If the start strip is the last in the start row */
+ regStart += ref_in_start_stripe;
+ regSize = stripSize - ref_in_start_stripe;
+ /* initialize count to sectors from startref to end
+ of strip */
+ }
+
+ if (numRows > 2)
+ /* Add complete rows in the middle of the transfer */
+ regSize += (numRows-2) << raid->stripeShift;
+
+ /* if IO ends within first strip of last row */
+ if (endStrip == endRow*raid->rowDataSize)
+ regSize += ref_in_end_stripe+1;
+ else
+ regSize += stripSize;
+ }
+
+ pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
+ pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ :
+ raid->regTypeReqOnWrite;
+ pRAID_Context->VirtualDiskTgtId = raid->targetId;
+ pRAID_Context->regLockRowLBA = regStart;
+ pRAID_Context->regLockLength = regSize;
+ pRAID_Context->configSeqNum = raid->seqNum;
+
+ /*Get Phy Params only if FP capable, or else leave it to MR firmware
+ to do the calculation.*/
+ if (io_info->fpOkForIo) {
+ retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe,
+ &io_info->pdBlock,
+ &io_info->devHandle, pRAID_Context,
+ map);
+ /* If IO on an invalid Pd, then FP i snot possible */
+ if (io_info->devHandle == MR_PD_INVALID)
+ io_info->fpOkForIo = FALSE;
+ return retval;
+ } else if (isRead) {
+ uint stripIdx;
+ for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
+ if (!MR_GetPhyParams(ld, start_strip + stripIdx,
+ ref_in_start_stripe,
+ &io_info->pdBlock,
+ &io_info->devHandle,
+ pRAID_Context, map))
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
+void
+mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo)
+{
+ int ldCount;
+ u16 ld;
+ struct MR_LD_RAID *raid;
+
+ for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
+ ld = MR_TargetIdToLdGet(ldCount, map);
+ if (ld >= MAX_LOGICAL_DRIVES) {
+ lbInfo[ldCount].loadBalanceFlag = 0;
+ continue;
+ }
+
+ raid = MR_LdRaidGet(ld, map);
+
+ /* Two drive Optimal RAID 1 */
+ if ((raid->level == 1) && (raid->rowSize == 2) &&
+ (raid->spanDepth == 1) && raid->ldState ==
+ MR_LD_STATE_OPTIMAL) {
+ u32 pd, arRef;
+
+ lbInfo[ldCount].loadBalanceFlag = 1;
+
+ /* Get the array on which this span is present */
+ arRef = MR_LdSpanArrayGet(ld, 0, map);
+
+ /* Get the Pd */
+ pd = MR_ArPdGet(arRef, 0, map);
+ /* Get dev handle from Pd */
+ lbInfo[ldCount].raid1DevHandle[0] =
+ MR_PdDevHandleGet(pd, map);
+ /* Get the Pd */
+ pd = MR_ArPdGet(arRef, 1, map);
+
+ /* Get the dev handle from Pd */
+ lbInfo[ldCount].raid1DevHandle[1] =
+ MR_PdDevHandleGet(pd, map);
+ } else
+ lbInfo[ldCount].loadBalanceFlag = 0;
+ }
+}
+
+u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block,
+ u32 count)
+{
+ u16 pend0, pend1;
+ u64 diff0, diff1;
+ u8 bestArm;
+
+ /* get the pending cmds for the data and mirror arms */
+ pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
+ pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
+
+ /* Determine the disk whose head is nearer to the req. block */
+ diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
+ diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
+ bestArm = (diff0 <= diff1 ? 0 : 1);
+
+ if ((bestArm == arm && pend0 > pend1 + 16) ||
+ (bestArm != arm && pend1 > pend0 + 16))
+ bestArm ^= 1;
+
+ /* Update the last accessed block on the correct pd */
+ lbInfo->last_accessed_block[bestArm] = block + count - 1;
+
+ return bestArm;
+}
+
+u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
+ struct IO_REQUEST_INFO *io_info)
+{
+ u8 arm, old_arm;
+ u16 devHandle;
+
+ old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
+
+ /* get best new arm */
+ arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock,
+ io_info->numBlocks);
+ devHandle = lbInfo->raid1DevHandle[arm];
+ atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
+
+ return devHandle;
+}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
new file mode 100644
index 000000000000..c1e09d5a6196
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -0,0 +1,2248 @@
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI 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
+ *
+ * FILE: megaraid_sas_fusion.c
+ *
+ * Authors: LSI Corporation
+ * Sumant Patro
+ * Adam Radford <linuxraid@lsi.com>
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/compat.h>
+#include <linux/blkdev.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include "megaraid_sas.h"
+
+extern void megasas_free_cmds(struct megasas_instance *instance);
+extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+ *instance);
+extern void
+megasas_complete_cmd(struct megasas_instance *instance,
+ struct megasas_cmd *cmd, u8 alt_status);
+int megasas_is_ldio(struct scsi_cmnd *cmd);
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+
+void
+megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
+int megasas_alloc_cmds(struct megasas_instance *instance);
+int
+megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs);
+int
+megasas_issue_polled(struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
+
+u8
+MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT *pRAID_Context,
+ struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+
+u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
+ struct IO_REQUEST_INFO *in_info);
+int megasas_transition_to_ready(struct megasas_instance *instance);
+void megaraid_sas_kill_hba(struct megasas_instance *instance);
+
+extern u32 megasas_dbg_lvl;
+
+/**
+ * megasas_enable_intr_fusion - Enables interrupts
+ * @regs: MFI register set
+ */
+void
+megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr_fusion - Disables interrupt
+ * @regs: MFI register set
+ */
+void
+megasas_disable_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ u32 status;
+
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ status = readl(&regs->outbound_intr_mask);
+}
+
+int
+megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs)
+{
+ u32 status;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(&regs->outbound_intr_status);
+
+ if (status & 1) {
+ writel(status, &regs->outbound_intr_status);
+ readl(&regs->outbound_intr_status);
+ return 1;
+ }
+ if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
+ return 0;
+
+ /*
+ * dummy read to flush PCI
+ */
+ readl(&regs->outbound_intr_status);
+
+ return 1;
+}
+
+/**
+ * megasas_get_cmd_fusion - Get a command from the free pool
+ * @instance: Adapter soft state
+ *
+ * Returns a free command from the pool
+ */
+struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
+ *instance)
+{
+ unsigned long flags;
+ struct fusion_context *fusion =
+ (struct fusion_context *)instance->ctrl_context;
+ struct megasas_cmd_fusion *cmd = NULL;
+
+ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
+
+ if (!list_empty(&fusion->cmd_pool)) {
+ cmd = list_entry((&fusion->cmd_pool)->next,
+ struct megasas_cmd_fusion, list);
+ list_del_init(&cmd->list);
+ } else {
+ printk(KERN_ERR "megasas: Command pool (fusion) empty!\n");
+ }
+
+ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
+ return cmd;
+}
+
+/**
+ * megasas_return_cmd_fusion - Return a cmd to free command pool
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be returned to free command pool
+ */
+static inline void
+megasas_return_cmd_fusion(struct megasas_instance *instance,
+ struct megasas_cmd_fusion *cmd)
+{
+ unsigned long flags;
+ struct fusion_context *fusion =
+ (struct fusion_context *)instance->ctrl_context;
+
+ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
+
+ cmd->scmd = NULL;
+ cmd->sync_cmd_idx = (u32)ULONG_MAX;
+ list_add_tail(&cmd->list, &fusion->cmd_pool);
+
+ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
+}
+
+/**
+ * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool
+ * @instance: Adapter soft state
+ */
+static void megasas_teardown_frame_pool_fusion(
+ struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ u16 max_cmd = instance->max_fw_cmds;
+
+ struct megasas_cmd_fusion *cmd;
+
+ if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
+ printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, "
+ "sense pool : %p\n", fusion->sg_dma_pool,
+ fusion->sense_dma_pool);
+ return;
+ }
+
+ /*
+ * Return all frames to pool
+ */
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = fusion->cmd_list[i];
+
+ if (cmd->sg_frame)
+ pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
+ cmd->sg_frame_phys_addr);
+
+ if (cmd->sense)
+ pci_pool_free(fusion->sense_dma_pool, cmd->sense,
+ cmd->sense_phys_addr);
+ }
+
+ /*
+ * Now destroy the pool itself
+ */
+ pci_pool_destroy(fusion->sg_dma_pool);
+ pci_pool_destroy(fusion->sense_dma_pool);
+
+ fusion->sg_dma_pool = NULL;
+ fusion->sense_dma_pool = NULL;
+}
+
+/**
+ * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
+ * @instance: Adapter soft state
+ */
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ u32 max_cmds, req_sz, reply_sz, io_frames_sz;
+
+
+ req_sz = fusion->request_alloc_sz;
+ reply_sz = fusion->reply_alloc_sz;
+ io_frames_sz = fusion->io_frames_alloc_sz;
+
+ max_cmds = instance->max_fw_cmds;
+
+ /* Free descriptors and request Frames memory */
+ if (fusion->req_frames_desc)
+ dma_free_coherent(&instance->pdev->dev, req_sz,
+ fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+
+ if (fusion->reply_frames_desc) {
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+ }
+
+ if (fusion->io_request_frames) {
+ pci_pool_free(fusion->io_request_frames_pool,
+ fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ pci_pool_destroy(fusion->io_request_frames_pool);
+ }
+
+ /* Free the Fusion frame pool */
+ megasas_teardown_frame_pool_fusion(instance);
+
+ /* Free all the commands in the cmd_list */
+ for (i = 0; i < max_cmds; i++)
+ kfree(fusion->cmd_list[i]);
+
+ /* Free the cmd_list buffer itself */
+ kfree(fusion->cmd_list);
+ fusion->cmd_list = NULL;
+
+ INIT_LIST_HEAD(&fusion->cmd_pool);
+}
+
+/**
+ * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames
+ * @instance: Adapter soft state
+ *
+ */
+static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+{
+ int i;
+ u32 max_cmd;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ u32 total_sz_chain_frame;
+
+ fusion = instance->ctrl_context;
+ max_cmd = instance->max_fw_cmds;
+
+ total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME;
+
+ /*
+ * Use DMA pool facility provided by PCI layer
+ */
+
+ fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion",
+ instance->pdev,
+ total_sz_chain_frame, 4,
+ 0);
+ if (!fusion->sg_dma_pool) {
+ printk(KERN_DEBUG "megasas: failed to setup request pool "
+ "fusion\n");
+ return -ENOMEM;
+ }
+ fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion",
+ instance->pdev,
+ SCSI_SENSE_BUFFERSIZE, 64, 0);
+
+ if (!fusion->sense_dma_pool) {
+ printk(KERN_DEBUG "megasas: failed to setup sense pool "
+ "fusion\n");
+ pci_pool_destroy(fusion->sg_dma_pool);
+ fusion->sg_dma_pool = NULL;
+ return -ENOMEM;
+ }
+
+ /*
+ * Allocate and attach a frame to each of the commands in cmd_list
+ */
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = fusion->cmd_list[i];
+
+ cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
+ GFP_KERNEL,
+ &cmd->sg_frame_phys_addr);
+
+ cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
+ GFP_KERNEL, &cmd->sense_phys_addr);
+ /*
+ * megasas_teardown_frame_pool_fusion() takes care of freeing
+ * whatever has been allocated
+ */
+ if (!cmd->sg_frame || !cmd->sense) {
+ printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n");
+ megasas_teardown_frame_pool_fusion(instance);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * megasas_alloc_cmds_fusion - Allocates the command packets
+ * @instance: Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+ int i, j;
+ u32 max_cmd, io_frames_sz;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+ u32 offset;
+ dma_addr_t io_req_base_phys;
+ u8 *io_req_base;
+
+ fusion = instance->ctrl_context;
+
+ max_cmd = instance->max_fw_cmds;
+
+ fusion->req_frames_desc =
+ dma_alloc_coherent(&instance->pdev->dev,
+ fusion->request_alloc_sz,
+ &fusion->req_frames_desc_phys, GFP_KERNEL);
+
+ if (!fusion->req_frames_desc) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "request_frames\n");
+ goto fail_req_desc;
+ }
+
+ fusion->reply_frames_desc_pool =
+ pci_pool_create("reply_frames pool", instance->pdev,
+ fusion->reply_alloc_sz, 16, 0);
+
+ if (!fusion->reply_frames_desc_pool) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "reply_frame pool\n");
+ goto fail_reply_desc;
+ }
+
+ fusion->reply_frames_desc =
+ pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
+ &fusion->reply_frames_desc_phys);
+ if (!fusion->reply_frames_desc) {
+ printk(KERN_ERR "megasas; Could not allocate memory for "
+ "reply_frame pool\n");
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+ goto fail_reply_desc;
+ }
+
+ reply_desc = fusion->reply_frames_desc;
+ for (i = 0; i < fusion->reply_q_depth; i++, reply_desc++)
+ reply_desc->Words = ULLONG_MAX;
+
+ io_frames_sz = fusion->io_frames_alloc_sz;
+
+ fusion->io_request_frames_pool =
+ pci_pool_create("io_request_frames pool", instance->pdev,
+ fusion->io_frames_alloc_sz, 16, 0);
+
+ if (!fusion->io_request_frames_pool) {
+ printk(KERN_ERR "megasas: Could not allocate memory for "
+ "io_request_frame pool\n");
+ goto fail_io_frames;
+ }
+
+ fusion->io_request_frames =
+ pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
+ &fusion->io_request_frames_phys);
+ if (!fusion->io_request_frames) {
+ printk(KERN_ERR "megasas: Could not allocate memory for "
+ "io_request_frames frames\n");
+ pci_pool_destroy(fusion->io_request_frames_pool);
+ goto fail_io_frames;
+ }
+
+ /*
+ * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *)
+ *max_cmd, GFP_KERNEL);
+
+ if (!fusion->cmd_list) {
+ printk(KERN_DEBUG "megasas: out of memory. Could not alloc "
+ "memory for cmd_list_fusion\n");
+ goto fail_cmd_list;
+ }
+
+ memset(fusion->cmd_list, 0, sizeof(struct megasas_cmd_fusion *)
+ *max_cmd);
+
+ max_cmd = instance->max_fw_cmds;
+ for (i = 0; i < max_cmd; i++) {
+ fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
+ GFP_KERNEL);
+ if (!fusion->cmd_list[i]) {
+ printk(KERN_ERR "Could not alloc cmd list fusion\n");
+
+ for (j = 0; j < i; j++)
+ kfree(fusion->cmd_list[j]);
+
+ kfree(fusion->cmd_list);
+ fusion->cmd_list = NULL;
+ goto fail_cmd_list;
+ }
+ }
+
+ /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
+ io_req_base = fusion->io_request_frames +
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ io_req_base_phys = fusion->io_request_frames_phys +
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+
+ /*
+ * Add all the commands to command pool (fusion->cmd_pool)
+ */
+
+ /* SMID 0 is reserved. Set SMID/index from 1 */
+ for (i = 0; i < max_cmd; i++) {
+ cmd = fusion->cmd_list[i];
+ offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
+ memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
+ cmd->index = i + 1;
+ cmd->scmd = NULL;
+ cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */
+ cmd->instance = instance;
+ cmd->io_request =
+ (struct MPI2_RAID_SCSI_IO_REQUEST *)
+ (io_req_base + offset);
+ memset(cmd->io_request, 0,
+ sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
+ cmd->io_request_phys_addr = io_req_base_phys + offset;
+
+ list_add_tail(&cmd->list, &fusion->cmd_pool);
+ }
+
+ /*
+ * Create a frame pool and assign one frame to each cmd
+ */
+ if (megasas_create_frame_pool_fusion(instance)) {
+ printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
+ megasas_free_cmds_fusion(instance);
+ goto fail_req_desc;
+ }
+
+ return 0;
+
+fail_cmd_list:
+ pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ pci_pool_destroy(fusion->io_request_frames_pool);
+fail_io_frames:
+ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc,
+ fusion->reply_frames_desc_phys);
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+fail_reply_desc:
+ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
+ fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+fail_req_desc:
+ return -ENOMEM;
+}
+
+/**
+ * wait_and_poll - Issues a polling command
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be issued
+ *
+ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
+ */
+int
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ int i;
+ struct megasas_header *frame_hdr = &cmd->frame->hdr;
+
+ u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+
+ /*
+ * Wait for cmd_status to change
+ */
+ for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
+ rmb();
+ msleep(20);
+ }
+
+ if (frame_hdr->cmd_status == 0xff)
+ return -ETIME;
+
+ return 0;
+}
+
+/**
+ * megasas_ioc_init_fusion - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * Issues the IOC Init cmd
+ */
+int
+megasas_ioc_init_fusion(struct megasas_instance *instance)
+{
+ struct megasas_init_frame *init_frame;
+ struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+ dma_addr_t ioc_init_handle;
+ u32 context;
+ struct megasas_cmd *cmd;
+ u8 ret;
+ struct fusion_context *fusion;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ int i;
+ struct megasas_header *frame_hdr;
+
+ fusion = instance->ctrl_context;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_ERR "Could not allocate cmd for INIT Frame\n");
+ ret = 1;
+ goto fail_get_cmd;
+ }
+
+ IOCInitMessage =
+ dma_alloc_coherent(&instance->pdev->dev,
+ sizeof(struct MPI2_IOC_INIT_REQUEST),
+ &ioc_init_handle, GFP_KERNEL);
+
+ if (!IOCInitMessage) {
+ printk(KERN_ERR "Could not allocate memory for "
+ "IOCInitMessage\n");
+ ret = 1;
+ goto fail_fw_init;
+ }
+
+ memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST));
+
+ IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT;
+ IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+ IOCInitMessage->MsgVersion = MPI2_VERSION;
+ IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION;
+ IOCInitMessage->SystemRequestFrameSize =
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
+
+ IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth;
+ IOCInitMessage->ReplyDescriptorPostQueueAddress =
+ fusion->reply_frames_desc_phys;
+ IOCInitMessage->SystemRequestFrameBaseAddress =
+ fusion->io_request_frames_phys;
+
+ init_frame = (struct megasas_init_frame *)cmd->frame;
+ memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+
+ frame_hdr = &cmd->frame->hdr;
+ context = init_frame->context;
+ init_frame->context = context;
+
+ frame_hdr->cmd_status = 0xFF;
+ frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+ init_frame->cmd = MFI_CMD_INIT;
+ init_frame->cmd_status = 0xFF;
+
+ init_frame->queue_info_new_phys_addr_lo = ioc_init_handle;
+ init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
+
+ req_desc =
+ (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
+
+ req_desc->Words = cmd->frame_phys_addr;
+ req_desc->MFAIo.RequestFlags =
+ (MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+
+ /*
+ * disable the intr before firing the init frame
+ */
+ instance->instancet->disable_intr(instance->reg_set);
+
+ for (i = 0; i < (10 * 1000); i += 20) {
+ if (readl(&instance->reg_set->doorbell) & 1)
+ msleep(20);
+ else
+ break;
+ }
+
+ instance->instancet->fire_cmd(instance, req_desc->u.low,
+ req_desc->u.high, instance->reg_set);
+
+ wait_and_poll(instance, cmd);
+
+ frame_hdr = &cmd->frame->hdr;
+ if (frame_hdr->cmd_status != 0) {
+ ret = 1;
+ goto fail_fw_init;
+ }
+ printk(KERN_ERR "megasas:IOC Init cmd success\n");
+
+ ret = 0;
+
+fail_fw_init:
+ megasas_return_cmd(instance, cmd);
+ if (IOCInitMessage)
+ dma_free_coherent(&instance->pdev->dev,
+ sizeof(struct MPI2_IOC_INIT_REQUEST),
+ IOCInitMessage, ioc_init_handle);
+fail_get_cmd:
+ return ret;
+}
+
+/*
+ * megasas_return_cmd_for_smid - Returns a cmd_fusion for a SMID
+ * @instance: Adapter soft state
+ *
+ */
+void
+megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid)
+{
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+
+ fusion = instance->ctrl_context;
+ cmd = fusion->cmd_list[smid - 1];
+ megasas_return_cmd_fusion(instance, cmd);
+}
+
+/*
+ * megasas_get_ld_map_info - Returns FW's ld_map structure
+ * @instance: Adapter soft state
+ * @pend: Pend the command or not
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_ld_map_info(struct megasas_instance *instance)
+{
+ int ret = 0;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_FW_RAID_MAP_ALL *ci;
+ dma_addr_t ci_h = 0;
+ u32 size_map_info;
+ struct fusion_context *fusion;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n");
+ return -ENOMEM;
+ }
+
+ fusion = instance->ctrl_context;
+
+ if (!fusion) {
+ megasas_return_cmd(instance, cmd);
+ return 1;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ ci = fusion->ld_map[(instance->map_id & 1)];
+ ci_h = fusion->ld_map_phys[(instance->map_id & 1)];
+
+ if (!ci) {
+ printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n");
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ memset(ci, 0, sizeof(*ci));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = size_map_info;
+ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = size_map_info;
+
+ if (!megasas_issue_polled(instance, cmd))
+ ret = 0;
+ else {
+ printk(KERN_ERR "megasas: Get LD Map Info Failed\n");
+ ret = -1;
+ }
+
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+
+u8
+megasas_get_map_info(struct megasas_instance *instance)
+{
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ fusion->fast_path_io = 0;
+ if (!megasas_get_ld_map_info(instance)) {
+ if (MR_ValidateMapInfo(fusion->ld_map[(instance->map_id & 1)],
+ fusion->load_balance_info)) {
+ fusion->fast_path_io = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * megasas_sync_map_info - Returns FW's ld_map structure
+ * @instance: Adapter soft state
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+int
+megasas_sync_map_info(struct megasas_instance *instance)
+{
+ int ret = 0, i;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ u32 size_sync_info, num_lds;
+ struct fusion_context *fusion;
+ struct MR_LD_TARGET_SYNC *ci = NULL;
+ struct MR_FW_RAID_MAP_ALL *map;
+ struct MR_LD_RAID *raid;
+ struct MR_LD_TARGET_SYNC *ld_sync;
+ dma_addr_t ci_h = 0;
+ u32 size_map_info;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: Failed to get cmd for sync"
+ "info.\n");
+ return -ENOMEM;
+ }
+
+ fusion = instance->ctrl_context;
+
+ if (!fusion) {
+ megasas_return_cmd(instance, cmd);
+ return 1;
+ }
+
+ map = fusion->ld_map[instance->map_id & 1];
+
+ num_lds = map->raidMap.ldCount;
+
+ dcmd = &cmd->frame->dcmd;
+
+ size_sync_info = sizeof(struct MR_LD_TARGET_SYNC) *num_lds;
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ ci = (struct MR_LD_TARGET_SYNC *)
+ fusion->ld_map[(instance->map_id - 1) & 1];
+ memset(ci, 0, sizeof(struct MR_FW_RAID_MAP_ALL));
+
+ ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1];
+
+ ld_sync = (struct MR_LD_TARGET_SYNC *)ci;
+
+ for (i = 0; i < num_lds; i++, ld_sync++) {
+ raid = MR_LdRaidGet(i, map);
+ ld_sync->targetId = MR_GetLDTgtId(i, map);
+ ld_sync->seqNum = raid->seqNum;
+ }
+
+ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_WRITE;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = size_map_info;
+ dcmd->mbox.b[0] = num_lds;
+ dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG;
+ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = size_map_info;
+
+ instance->map_update_cmd = cmd;
+
+ instance->instancet->issue_dcmd(instance, cmd);
+
+ return ret;
+}
+
+/**
+ * megasas_init_adapter_fusion - Initializes the FW
+ * @instance: Adapter soft state
+ *
+ * This is the main function for initializing firmware.
+ */
+u32
+megasas_init_adapter_fusion(struct megasas_instance *instance)
+{
+ struct megasas_register_set __iomem *reg_set;
+ struct fusion_context *fusion;
+ u32 max_cmd;
+ int i = 0;
+
+ fusion = instance->ctrl_context;
+
+ reg_set = instance->reg_set;
+
+ /*
+ * Get various operational parameters from status register
+ */
+ instance->max_fw_cmds =
+ instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
+ /* Only internal cmds (DCMD) need to have MFI frames */
+ instance->max_mfi_cmds = MEGASAS_INT_CMDS;
+
+ max_cmd = instance->max_fw_cmds;
+
+ fusion->reply_q_depth = ((max_cmd + 1 + 15)/16)*16;
+
+ fusion->request_alloc_sz =
+ sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
+ fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
+ *(fusion->reply_q_depth);
+ fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
+ (max_cmd + 1)); /* Extra 1 for SMID 0 */
+
+ fusion->max_sge_in_main_msg =
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
+
+ fusion->max_sge_in_chain =
+ MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION);
+
+ instance->max_num_sge = fusion->max_sge_in_main_msg +
+ fusion->max_sge_in_chain - 2;
+
+ /* Used for pass thru MFI frame (DCMD) */
+ fusion->chain_offset_mfi_pthru =
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16;
+
+ fusion->chain_offset_io_request =
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
+ sizeof(union MPI2_SGE_IO_UNION))/16;
+
+ fusion->last_reply_idx = 0;
+
+ /*
+ * Allocate memory for descriptors
+ * Create a pool of commands
+ */
+ if (megasas_alloc_cmds(instance))
+ goto fail_alloc_mfi_cmds;
+ if (megasas_alloc_cmds_fusion(instance))
+ goto fail_alloc_cmds;
+
+ if (megasas_ioc_init_fusion(instance))
+ goto fail_ioc_init;
+
+ instance->flag_ieee = 1;
+
+ fusion->map_sz = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
+
+ fusion->fast_path_io = 0;
+
+ for (i = 0; i < 2; i++) {
+ fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev,
+ fusion->map_sz,
+ &fusion->ld_map_phys[i],
+ GFP_KERNEL);
+ if (!fusion->ld_map[i]) {
+ printk(KERN_ERR "megasas: Could not allocate memory "
+ "for map info\n");
+ goto fail_map_info;
+ }
+ }
+
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+
+ return 0;
+
+fail_alloc_cmds:
+fail_alloc_mfi_cmds:
+fail_map_info:
+ if (i == 1)
+ dma_free_coherent(&instance->pdev->dev, fusion->map_sz,
+ fusion->ld_map[0], fusion->ld_map_phys[0]);
+fail_ioc_init:
+ return 1;
+}
+
+/**
+ * megasas_fire_cmd_fusion - Sends command to the FW
+ * @frame_phys_addr : Physical address of cmd
+ * @frame_count : Number of frames for the command
+ * @regs : MFI register set
+ */
+void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+ dma_addr_t req_desc_lo,
+ u32 req_desc_hi,
+ struct megasas_register_set __iomem *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&instance->hba_lock, flags);
+
+ writel(req_desc_lo,
+ &(regs)->inbound_low_queue_port);
+ writel(req_desc_hi, &(regs)->inbound_high_queue_port);
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+}
+
+/**
+ * map_cmd_status - Maps FW cmd status to OS cmd status
+ * @cmd : Pointer to cmd
+ * @status : status of cmd returned by FW
+ * @ext_status : ext status of cmd returned by FW
+ */
+
+void
+map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
+{
+
+ switch (status) {
+
+ case MFI_STAT_OK:
+ cmd->scmd->result = DID_OK << 16;
+ break;
+
+ case MFI_STAT_SCSI_IO_FAILED:
+ case MFI_STAT_LD_INIT_IN_PROGRESS:
+ cmd->scmd->result = (DID_ERROR << 16) | ext_status;
+ break;
+
+ case MFI_STAT_SCSI_DONE_WITH_ERROR:
+
+ cmd->scmd->result = (DID_OK << 16) | ext_status;
+ if (ext_status == SAM_STAT_CHECK_CONDITION) {
+ memset(cmd->scmd->sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
+ memcpy(cmd->scmd->sense_buffer, cmd->sense,
+ SCSI_SENSE_BUFFERSIZE);
+ cmd->scmd->result |= DRIVER_SENSE << 24;
+ }
+ break;
+
+ case MFI_STAT_LD_OFFLINE:
+ case MFI_STAT_DEVICE_NOT_FOUND:
+ cmd->scmd->result = DID_BAD_TARGET << 16;
+ break;
+
+ default:
+ printk(KERN_DEBUG "megasas: FW status %#x\n", status);
+ cmd->scmd->result = DID_ERROR << 16;
+ break;
+ }
+}
+
+/**
+ * megasas_make_sgl_fusion - Prepares 32-bit SGL
+ * @instance: Adapter soft state
+ * @scp: SCSI command from the mid-layer
+ * @sgl_ptr: SGL to be filled in
+ * @cmd: cmd we are working on
+ *
+ * If successful, this function returns the number of SG elements.
+ */
+static int
+megasas_make_sgl_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
+ struct megasas_cmd_fusion *cmd)
+{
+ int i, sg_processed;
+ int sge_count, sge_idx;
+ struct scatterlist *os_sgl;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ cmd->io_request->ChainOffset = 0;
+
+ sge_count = scsi_dma_map(scp);
+
+ BUG_ON(sge_count < 0);
+
+ if (sge_count > instance->max_num_sge || !sge_count)
+ return sge_count;
+
+ if (sge_count > fusion->max_sge_in_main_msg) {
+ /* One element to store the chain info */
+ sge_idx = fusion->max_sge_in_main_msg - 1;
+ } else
+ sge_idx = sge_count;
+
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ sgl_ptr->Length = sg_dma_len(os_sgl);
+ sgl_ptr->Address = sg_dma_address(os_sgl);
+ sgl_ptr->Flags = 0;
+ sgl_ptr++;
+
+ sg_processed = i + 1;
+
+ if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) &&
+ (sge_count > fusion->max_sge_in_main_msg)) {
+
+ struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
+ cmd->io_request->ChainOffset =
+ fusion->chain_offset_io_request;
+ sg_chain = sgl_ptr;
+ /* Prepare chain element */
+ sg_chain->NextChainOffset = 0;
+ sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
+ sg_chain->Length = (sizeof(union MPI2_SGE_IO_UNION)
+ *(sge_count - sg_processed));
+ sg_chain->Address = cmd->sg_frame_phys_addr;
+
+ sgl_ptr =
+ (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
+ }
+ }
+
+ return sge_count;
+}
+
+/**
+ * megasas_set_pd_lba - Sets PD LBA
+ * @cdb: CDB
+ * @cdb_len: cdb length
+ * @start_blk: Start block of IO
+ *
+ * Used to set the PD LBA in CDB for FP IOs
+ */
+void
+megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
+ struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp,
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr, u32 ref_tag)
+{
+ struct MR_LD_RAID *raid;
+ u32 ld;
+ u64 start_blk = io_info->pdBlock;
+ u8 *cdb = io_request->CDB.CDB32;
+ u32 num_blocks = io_info->numBlocks;
+ u8 opcode, flagvals, groupnum, control;
+
+ /* Check if T10 PI (DIF) is enabled for this LD */
+ ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
+ raid = MR_LdRaidGet(ld, local_map_ptr);
+ if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
+ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
+ cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD;
+ cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN;
+
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32;
+ else
+ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32;
+ cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL;
+
+ /* LBA */
+ cdb[12] = (u8)((start_blk >> 56) & 0xff);
+ cdb[13] = (u8)((start_blk >> 48) & 0xff);
+ cdb[14] = (u8)((start_blk >> 40) & 0xff);
+ cdb[15] = (u8)((start_blk >> 32) & 0xff);
+ cdb[16] = (u8)((start_blk >> 24) & 0xff);
+ cdb[17] = (u8)((start_blk >> 16) & 0xff);
+ cdb[18] = (u8)((start_blk >> 8) & 0xff);
+ cdb[19] = (u8)(start_blk & 0xff);
+
+ /* Logical block reference tag */
+ io_request->CDB.EEDP32.PrimaryReferenceTag =
+ cpu_to_be32(ref_tag);
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
+
+ io_request->DataLength = num_blocks * 512;
+ io_request->IoFlags = 32; /* Specify 32-byte cdb */
+
+ /* Transfer length */
+ cdb[28] = (u8)((num_blocks >> 24) & 0xff);
+ cdb[29] = (u8)((num_blocks >> 16) & 0xff);
+ cdb[30] = (u8)((num_blocks >> 8) & 0xff);
+ cdb[31] = (u8)(num_blocks & 0xff);
+
+ /* set SCSI IO EEDPFlags */
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) {
+ io_request->EEDPFlags =
+ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+ } else {
+ io_request->EEDPFlags =
+ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+ }
+ io_request->Control |= (0x4 << 26);
+ io_request->EEDPBlockSize = MEGASAS_EEDPBLOCKSIZE;
+ } else {
+ /* Some drives don't support 16/12 byte CDB's, convert to 10 */
+ if (((cdb_len == 12) || (cdb_len == 16)) &&
+ (start_blk <= 0xffffffff)) {
+ if (cdb_len == 16) {
+ opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
+ flagvals = cdb[1];
+ groupnum = cdb[14];
+ control = cdb[15];
+ } else {
+ opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
+ flagvals = cdb[1];
+ groupnum = cdb[10];
+ control = cdb[11];
+ }
+
+ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
+
+ cdb[0] = opcode;
+ cdb[1] = flagvals;
+ cdb[6] = groupnum;
+ cdb[9] = control;
+
+ /* Transfer length */
+ cdb[8] = (u8)(num_blocks & 0xff);
+ cdb[7] = (u8)((num_blocks >> 8) & 0xff);
+
+ cdb_len = 10;
+ }
+
+ /* Normal case, just load LBA here */
+ switch (cdb_len) {
+ case 6:
+ {
+ u8 val = cdb[1] & 0xE0;
+ cdb[3] = (u8)(start_blk & 0xff);
+ cdb[2] = (u8)((start_blk >> 8) & 0xff);
+ cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f);
+ break;
+ }
+ case 10:
+ cdb[5] = (u8)(start_blk & 0xff);
+ cdb[4] = (u8)((start_blk >> 8) & 0xff);
+ cdb[3] = (u8)((start_blk >> 16) & 0xff);
+ cdb[2] = (u8)((start_blk >> 24) & 0xff);
+ break;
+ case 12:
+ cdb[5] = (u8)(start_blk & 0xff);
+ cdb[4] = (u8)((start_blk >> 8) & 0xff);
+ cdb[3] = (u8)((start_blk >> 16) & 0xff);
+ cdb[2] = (u8)((start_blk >> 24) & 0xff);
+ break;
+ case 16:
+ cdb[9] = (u8)(start_blk & 0xff);
+ cdb[8] = (u8)((start_blk >> 8) & 0xff);
+ cdb[7] = (u8)((start_blk >> 16) & 0xff);
+ cdb[6] = (u8)((start_blk >> 24) & 0xff);
+ cdb[5] = (u8)((start_blk >> 32) & 0xff);
+ cdb[4] = (u8)((start_blk >> 40) & 0xff);
+ cdb[3] = (u8)((start_blk >> 48) & 0xff);
+ cdb[2] = (u8)((start_blk >> 56) & 0xff);
+ break;
+ }
+ }
+}
+
+/**
+ * megasas_build_ldio_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Prepares the io_request and chain elements (sg_frame) for IO
+ * The IO can be for PD (Fast Path) or LD
+ */
+void
+megasas_build_ldio_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct megasas_cmd_fusion *cmd)
+{
+ u8 fp_possible;
+ u32 start_lba_lo, start_lba_hi, device_id;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct IO_REQUEST_INFO io_info;
+ struct fusion_context *fusion;
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
+
+ device_id = MEGASAS_DEV_INDEX(instance, scp);
+
+ fusion = instance->ctrl_context;
+
+ io_request = cmd->io_request;
+ io_request->RaidContext.VirtualDiskTgtId = device_id;
+ io_request->RaidContext.status = 0;
+ io_request->RaidContext.exStatus = 0;
+
+ req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
+
+ start_lba_lo = 0;
+ start_lba_hi = 0;
+ fp_possible = 0;
+
+ /*
+ * 6-byte READ(0x08) or WRITE(0x0A) cdb
+ */
+ if (scp->cmd_len == 6) {
+ io_request->DataLength = (u32) scp->cmnd[4];
+ start_lba_lo = ((u32) scp->cmnd[1] << 16) |
+ ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
+
+ start_lba_lo &= 0x1FFFFF;
+ }
+
+ /*
+ * 10-byte READ(0x28) or WRITE(0x2A) cdb
+ */
+ else if (scp->cmd_len == 10) {
+ io_request->DataLength = (u32) scp->cmnd[8] |
+ ((u32) scp->cmnd[7] << 8);
+ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ /*
+ * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+ */
+ else if (scp->cmd_len == 12) {
+ io_request->DataLength = ((u32) scp->cmnd[6] << 24) |
+ ((u32) scp->cmnd[7] << 16) |
+ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ /*
+ * 16-byte READ(0x88) or WRITE(0x8A) cdb
+ */
+ else if (scp->cmd_len == 16) {
+ io_request->DataLength = ((u32) scp->cmnd[10] << 24) |
+ ((u32) scp->cmnd[11] << 16) |
+ ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
+ start_lba_lo = ((u32) scp->cmnd[6] << 24) |
+ ((u32) scp->cmnd[7] << 16) |
+ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+
+ start_lba_hi = ((u32) scp->cmnd[2] << 24) |
+ ((u32) scp->cmnd[3] << 16) |
+ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+ }
+
+ memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
+ io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
+ io_info.numBlocks = io_request->DataLength;
+ io_info.ldTgtId = device_id;
+
+ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ io_info.isRead = 1;
+
+ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
+
+ if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >=
+ MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io)) {
+ io_request->RaidContext.regLockFlags = 0;
+ fp_possible = 0;
+ } else {
+ if (MR_BuildRaidContext(&io_info, &io_request->RaidContext,
+ local_map_ptr))
+ fp_possible = io_info.fpOkForIo;
+ }
+
+ if (fp_possible) {
+ megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
+ local_map_ptr, start_lba_lo);
+ io_request->DataLength = scsi_bufflen(scp);
+ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
+ (io_info.isRead)) {
+ io_info.devHandle =
+ get_updated_dev_handle(
+ &fusion->load_balance_info[device_id],
+ &io_info);
+ scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG;
+ } else
+ scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
+ cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
+ io_request->DevHandle = io_info.devHandle;
+ } else {
+ io_request->RaidContext.timeoutValue =
+ local_map_ptr->raidMap.fpPdIoTimeoutSec;
+ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ io_request->DevHandle = device_id;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
+ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ } /* Not FP */
+}
+
+/**
+ * megasas_build_dcdb_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Prepares the io_request frame for non-io cmds
+ */
+static void
+megasas_build_dcdb_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd,
+ struct megasas_cmd_fusion *cmd)
+{
+ u32 device_id;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ u16 pd_index = 0;
+ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ io_request = cmd->io_request;
+ device_id = MEGASAS_DEV_INDEX(instance, scmd);
+ pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
+ +scmd->device->id;
+ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
+
+ /* Check if this is a system PD I/O */
+ if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
+ (instance->pd_list[pd_index].driveType == TYPE_DISK)) {
+ io_request->Function = 0;
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ io_request->RaidContext.timeoutValue =
+ local_map_ptr->raidMap.fpPdIoTimeoutSec;
+ io_request->RaidContext.regLockFlags = 0;
+ io_request->RaidContext.regLockRowLBA = 0;
+ io_request->RaidContext.regLockLength = 0;
+ io_request->RaidContext.RAIDFlags =
+ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD <<
+ MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ } else {
+ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ io_request->DevHandle = device_id;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ }
+ io_request->RaidContext.VirtualDiskTgtId = device_id;
+ io_request->LUN[0] = scmd->device->lun;
+ io_request->DataLength = scsi_bufflen(scmd);
+}
+
+/**
+ * megasas_build_io_fusion - Prepares IOs to devices
+ * @instance: Adapter soft state
+ * @scp: SCSI command
+ * @cmd: Command to be prepared
+ *
+ * Invokes helper functions to prepare request frames
+ * and sets flags appropriate for IO/Non-IO cmd
+ */
+int
+megasas_build_io_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scp,
+ struct megasas_cmd_fusion *cmd)
+{
+ u32 device_id, sge_count;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
+
+ device_id = MEGASAS_DEV_INDEX(instance, scp);
+
+ /* Zero out some fields so they don't get reused */
+ io_request->LUN[0] = 0;
+ io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
+ io_request->EEDPFlags = 0;
+ io_request->Control = 0;
+ io_request->EEDPBlockSize = 0;
+ io_request->IoFlags = 0;
+ io_request->RaidContext.RAIDFlags = 0;
+
+ memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
+ /*
+ * Just the CDB length,rest of the Flags are zero
+ * This will be modified for FP in build_ldio_fusion
+ */
+ io_request->IoFlags = scp->cmd_len;
+
+ if (megasas_is_ldio(scp))
+ megasas_build_ldio_fusion(instance, scp, cmd);
+ else
+ megasas_build_dcdb_fusion(instance, scp, cmd);
+
+ /*
+ * Construct SGL
+ */
+
+ sge_count =
+ megasas_make_sgl_fusion(instance, scp,
+ (struct MPI25_IEEE_SGE_CHAIN64 *)
+ &io_request->SGL, cmd);
+
+ if (sge_count > instance->max_num_sge) {
+ printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds "
+ "max (0x%x) allowed\n", sge_count,
+ instance->max_num_sge);
+ return 1;
+ }
+
+ io_request->RaidContext.numSGE = sge_count;
+
+ io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+
+ if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+ io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;
+ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
+
+ io_request->SGLOffset0 =
+ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4;
+
+ io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
+ io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
+
+ cmd->scmd = scp;
+ scp->SCp.ptr = (char *)cmd;
+
+ return 0;
+}
+
+union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
+{
+ u8 *p;
+ struct fusion_context *fusion;
+
+ if (index >= instance->max_fw_cmds) {
+ printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
+ "descriptor\n", index);
+ return NULL;
+ }
+ fusion = instance->ctrl_context;
+ p = fusion->req_frames_desc
+ +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
+
+ return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
+}
+
+/**
+ * megasas_build_and_issue_cmd_fusion -Main routine for building and
+ * issuing non IOCTL cmd
+ * @instance: Adapter soft state
+ * @scmd: pointer to scsi cmd from OS
+ */
+static u32
+megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd_fusion *cmd;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u32 index;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ cmd = megasas_get_cmd_fusion(instance);
+ if (!cmd)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ index = cmd->index;
+
+ req_desc = megasas_get_request_descriptor(instance, index-1);
+ if (!req_desc)
+ return 1;
+
+ req_desc->Words = 0;
+ cmd->request_desc = req_desc;
+ cmd->request_desc->Words = 0;
+
+ if (megasas_build_io_fusion(instance, scmd, cmd)) {
+ megasas_return_cmd_fusion(instance, cmd);
+ printk(KERN_ERR "megasas: Error building command.\n");
+ cmd->request_desc = NULL;
+ return 1;
+ }
+
+ req_desc = cmd->request_desc;
+ req_desc->SCSIIO.SMID = index;
+
+ if (cmd->io_request->ChainOffset != 0 &&
+ cmd->io_request->ChainOffset != 0xF)
+ printk(KERN_ERR "megasas: The chain offset value is not "
+ "correct : %x\n", cmd->io_request->ChainOffset);
+
+ /*
+ * Issue the command to the FW
+ */
+ atomic_inc(&instance->fw_outstanding);
+
+ instance->instancet->fire_cmd(instance,
+ req_desc->u.low, req_desc->u.high,
+ instance->reg_set);
+
+ return 0;
+}
+
+/**
+ * complete_cmd_fusion - Completes command
+ * @instance: Adapter soft state
+ * Completes all commands that is in reply descriptor queue
+ */
+int
+complete_cmd_fusion(struct megasas_instance *instance)
+{
+ union MPI2_REPLY_DESCRIPTORS_UNION *desc;
+ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
+ struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+ struct megasas_cmd_fusion *cmd_fusion;
+ u16 smid, num_completed;
+ u8 reply_descript_type, arm;
+ u32 status, extStatus, device_id;
+ union desc_value d_val;
+ struct LD_LOAD_BALANCE_INFO *lbinfo;
+
+ fusion = instance->ctrl_context;
+
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ return IRQ_HANDLED;
+
+ desc = fusion->reply_frames_desc;
+ desc += fusion->last_reply_idx;
+
+ reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
+
+ d_val.word = desc->Words;
+
+ reply_descript_type = reply_desc->ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ return IRQ_NONE;
+
+ d_val.word = desc->Words;
+
+ num_completed = 0;
+
+ while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) {
+ smid = reply_desc->SMID;
+
+ cmd_fusion = fusion->cmd_list[smid - 1];
+
+ scsi_io_req =
+ (struct MPI2_RAID_SCSI_IO_REQUEST *)
+ cmd_fusion->io_request;
+
+ if (cmd_fusion->scmd)
+ cmd_fusion->scmd->SCp.ptr = NULL;
+
+ status = scsi_io_req->RaidContext.status;
+ extStatus = scsi_io_req->RaidContext.exStatus;
+
+ switch (scsi_io_req->Function) {
+ case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
+ /* Update load balancing info */
+ device_id = MEGASAS_DEV_INDEX(instance,
+ cmd_fusion->scmd);
+ lbinfo = &fusion->load_balance_info[device_id];
+ if (cmd_fusion->scmd->SCp.Status &
+ MEGASAS_LOAD_BALANCE_FLAG) {
+ arm = lbinfo->raid1DevHandle[0] ==
+ cmd_fusion->io_request->DevHandle ? 0 :
+ 1;
+ atomic_dec(&lbinfo->scsi_pending_cmds[arm]);
+ cmd_fusion->scmd->SCp.Status &=
+ ~MEGASAS_LOAD_BALANCE_FLAG;
+ }
+ if (reply_descript_type ==
+ MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
+ if (megasas_dbg_lvl == 5)
+ printk(KERN_ERR "\nmegasas: FAST Path "
+ "IO Success\n");
+ }
+ /* Fall thru and complete IO */
+ case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
+ /* Map the FW Cmd Status */
+ map_cmd_status(cmd_fusion, status, extStatus);
+ scsi_dma_unmap(cmd_fusion->scmd);
+ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
+ scsi_io_req->RaidContext.status = 0;
+ scsi_io_req->RaidContext.exStatus = 0;
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ atomic_dec(&instance->fw_outstanding);
+
+ break;
+ case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
+ cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+ megasas_complete_cmd(instance, cmd_mfi, DID_OK);
+ cmd_fusion->flags = 0;
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+
+ break;
+ }
+
+ fusion->last_reply_idx++;
+ if (fusion->last_reply_idx >= fusion->reply_q_depth)
+ fusion->last_reply_idx = 0;
+
+ desc->Words = ULLONG_MAX;
+ num_completed++;
+
+ /* Get the next reply descriptor */
+ if (!fusion->last_reply_idx)
+ desc = fusion->reply_frames_desc;
+ else
+ desc++;
+
+ reply_desc =
+ (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
+
+ d_val.word = desc->Words;
+
+ reply_descript_type = reply_desc->ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ break;
+ }
+
+ if (!num_completed)
+ return IRQ_NONE;
+
+ wmb();
+ writel(fusion->last_reply_idx,
+ &instance->reg_set->reply_post_host_index);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * megasas_complete_cmd_dpc_fusion - Completes command
+ * @instance: Adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+void
+megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
+{
+ struct megasas_instance *instance =
+ (struct megasas_instance *)instance_addr;
+ unsigned long flags;
+
+ /* If we have already declared adapter dead, donot complete cmds */
+ spin_lock_irqsave(&instance->hba_lock, flags);
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+ spin_lock_irqsave(&instance->completion_lock, flags);
+ complete_cmd_fusion(instance);
+ spin_unlock_irqrestore(&instance->completion_lock, flags);
+}
+
+/**
+ * megasas_isr_fusion - isr entry point
+ */
+irqreturn_t megasas_isr_fusion(int irq, void *devp)
+{
+ struct megasas_instance *instance = (struct megasas_instance *)devp;
+ u32 mfiStatus, fw_state;
+
+ if (!instance->msi_flag) {
+ mfiStatus = instance->instancet->clear_intr(instance->reg_set);
+ if (!mfiStatus)
+ return IRQ_NONE;
+ }
+
+ /* If we are resetting, bail */
+ if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+ return IRQ_HANDLED;
+
+ if (!complete_cmd_fusion(instance)) {
+ /* If we didn't complete any commands, check for FW fault */
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state == MFI_STATE_FAULT)
+ schedule_work(&instance->work_init);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru
+ * @instance: Adapter soft state
+ * mfi_cmd: megasas_cmd pointer
+ *
+ */
+u8
+build_mpt_mfi_pass_thru(struct megasas_instance *instance,
+ struct megasas_cmd *mfi_cmd)
+{
+ struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_req;
+ struct megasas_cmd_fusion *cmd;
+ struct fusion_context *fusion;
+ struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr;
+
+ cmd = megasas_get_cmd_fusion(instance);
+ if (!cmd)
+ return 1;
+
+ /* Save the smid. To be used for returning the cmd */
+ mfi_cmd->context.smid = cmd->index;
+
+ cmd->sync_cmd_idx = mfi_cmd->index;
+
+ /*
+ * For cmds where the flag is set, store the flag and check
+ * on completion. For cmds with this flag, don't call
+ * megasas_complete_cmd
+ */
+
+ if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
+ cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+ fusion = instance->ctrl_context;
+ io_req = cmd->io_request;
+ mpi25_ieee_chain =
+ (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
+
+ io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
+ io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST,
+ SGL) / 4;
+ io_req->ChainOffset = fusion->chain_offset_mfi_pthru;
+
+ mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
+
+ mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
+
+ mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME;
+
+ return 0;
+}
+
+/**
+ * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd
+ * @instance: Adapter soft state
+ * @cmd: mfi cmd to build
+ *
+ */
+union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u16 index;
+
+ if (build_mpt_mfi_pass_thru(instance, cmd)) {
+ printk(KERN_ERR "Couldn't build MFI pass thru cmd\n");
+ return NULL;
+ }
+
+ index = cmd->context.smid;
+
+ req_desc = megasas_get_request_descriptor(instance, index - 1);
+
+ if (!req_desc)
+ return NULL;
+
+ req_desc->Words = 0;
+ req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+
+ req_desc->SCSIIO.SMID = index;
+
+ return req_desc;
+}
+
+/**
+ * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd
+ * @instance: Adapter soft state
+ * @cmd: mfi cmd pointer
+ *
+ */
+void
+megasas_issue_dcmd_fusion(struct megasas_instance *instance,
+ struct megasas_cmd *cmd)
+{
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ union desc_value d_val;
+
+ req_desc = build_mpt_cmd(instance, cmd);
+ if (!req_desc) {
+ printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n");
+ return;
+ }
+ d_val.word = req_desc->Words;
+
+ instance->instancet->fire_cmd(instance, req_desc->u.low,
+ req_desc->u.high, instance->reg_set);
+}
+
+/**
+ * megasas_release_fusion - Reverses the FW initialization
+ * @intance: Adapter soft state
+ */
+void
+megasas_release_fusion(struct megasas_instance *instance)
+{
+ megasas_free_cmds(instance);
+ megasas_free_cmds_fusion(instance);
+
+ iounmap(instance->reg_set);
+
+ pci_release_selected_regions(instance->pdev, instance->bar);
+}
+
+/**
+ * megasas_read_fw_status_reg_fusion - returns the current FW status value
+ * @regs: MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_fusion(struct megasas_register_set __iomem *regs)
+{
+ return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_adp_reset_fusion - For controller reset
+ * @regs: MFI register set
+ */
+static int
+megasas_adp_reset_fusion(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+{
+ return 0;
+}
+
+/**
+ * megasas_check_reset_fusion - For controller reset check
+ * @regs: MFI register set
+ */
+static int
+megasas_check_reset_fusion(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+{
+ return 0;
+}
+
+/* This function waits for outstanding commands on fusion to complete */
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
+{
+ int i, outstanding, retval = 0;
+ u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME;
+
+ for (i = 0; i < wait_time; i++) {
+ /* Check if firmware is in fault state */
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state == MFI_STATE_FAULT) {
+ printk(KERN_WARNING "megasas: Found FW in FAULT state,"
+ " will reset adapter.\n");
+ retval = 1;
+ goto out;
+ }
+
+ outstanding = atomic_read(&instance->fw_outstanding);
+ if (!outstanding)
+ goto out;
+
+ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+ printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
+ "commands to complete\n", i, outstanding);
+ megasas_complete_cmd_dpc_fusion(
+ (unsigned long)instance);
+ }
+ msleep(1000);
+ }
+
+ if (atomic_read(&instance->fw_outstanding)) {
+ printk("megaraid_sas: pending commands remain after waiting, "
+ "will reset adapter.\n");
+ retval = 1;
+ }
+out:
+ return retval;
+}
+
+void megasas_reset_reply_desc(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+ fusion = instance->ctrl_context;
+ fusion->last_reply_idx = 0;
+ reply_desc = fusion->reply_frames_desc;
+ for (i = 0 ; i < fusion->reply_q_depth; i++, reply_desc++)
+ reply_desc->Words = ULLONG_MAX;
+}
+
+/* Core fusion reset function */
+int megasas_reset_fusion(struct Scsi_Host *shost)
+{
+ int retval = SUCCESS, i, j, retry = 0;
+ struct megasas_instance *instance;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ u32 host_diag, abs_state;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+ fusion = instance->ctrl_context;
+
+ mutex_lock(&instance->reset_mutex);
+ set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->instancet->disable_intr(instance->reg_set);
+ msleep(1000);
+
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
+ "returning FAILED.\n");
+ retval = FAILED;
+ goto out;
+ }
+
+ /* First try waiting for commands to complete */
+ if (megasas_wait_for_outstanding_fusion(instance)) {
+ printk(KERN_WARNING "megaraid_sas: resetting fusion "
+ "adapter.\n");
+ /* Now return commands back to the OS */
+ for (i = 0 ; i < instance->max_fw_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd) {
+ scsi_dma_unmap(cmd_fusion->scmd);
+ cmd_fusion->scmd->result = (DID_RESET << 16);
+ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ atomic_dec(&instance->fw_outstanding);
+ }
+ }
+
+ if (instance->disableOnlineCtrlReset == 1) {
+ /* Reset not supported, kill adapter */
+ printk(KERN_WARNING "megaraid_sas: Reset not supported"
+ ", killing adapter.\n");
+ megaraid_sas_kill_hba(instance);
+ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+ retval = FAILED;
+ goto out;
+ }
+
+ /* Now try to reset the chip */
+ for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_1ST_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_2ND_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_3RD_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_4TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_5TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_6TH_KEY_VALUE,
+ &instance->reg_set->fusion_seq_offset);
+
+ /* Check that the diag write enable (DRWE) bit is on */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
+ msleep(100);
+ host_diag =
+ readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 100) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "Host diag unlock failed!\n");
+ break;
+ }
+ }
+ if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
+ continue;
+
+ /* Send chip reset command */
+ writel(host_diag | HOST_DIAG_RESET_ADAPTER,
+ &instance->reg_set->fusion_host_diag);
+ msleep(3000);
+
+ /* Make sure reset adapter bit is cleared */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (host_diag & HOST_DIAG_RESET_ADAPTER) {
+ msleep(100);
+ host_diag =
+ readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 1000) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "Diag reset adapter never "
+ "cleared!\n");
+ break;
+ }
+ }
+ if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ continue;
+
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+ instance->reg_set);
+ retry = 0;
+
+ while ((abs_state <= MFI_STATE_FW_INIT) &&
+ (retry++ < 1000)) {
+ msleep(100);
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+ instance->reg_set);
+ }
+ if (abs_state <= MFI_STATE_FW_INIT) {
+ printk(KERN_WARNING "megaraid_sas: firmware "
+ "state < MFI_STATE_FW_INIT, state = "
+ "0x%x\n", abs_state);
+ continue;
+ }
+
+ /* Wait for FW to become ready */
+ if (megasas_transition_to_ready(instance)) {
+ printk(KERN_WARNING "megaraid_sas: Failed to "
+ "transition controller to ready.\n");
+ continue;
+ }
+
+ megasas_reset_reply_desc(instance);
+ if (megasas_ioc_init_fusion(instance)) {
+ printk(KERN_WARNING "megaraid_sas: "
+ "megasas_ioc_init_fusion() failed!\n");
+ continue;
+ }
+
+ instance->instancet->enable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
+ /* Re-fire management commands */
+ for (j = 0 ; j < instance->max_fw_cmds; j++) {
+ cmd_fusion = fusion->cmd_list[j];
+ if (cmd_fusion->sync_cmd_idx !=
+ (u32)ULONG_MAX) {
+ cmd_mfi =
+ instance->
+ cmd_list[cmd_fusion->sync_cmd_idx];
+ if (cmd_mfi->frame->dcmd.opcode ==
+ MR_DCMD_LD_MAP_GET_INFO) {
+ megasas_return_cmd(instance,
+ cmd_mfi);
+ megasas_return_cmd_fusion(
+ instance, cmd_fusion);
+ } else {
+ req_desc =
+ megasas_get_request_descriptor(
+ instance,
+ cmd_mfi->context.smid
+ -1);
+ if (!req_desc)
+ printk(KERN_WARNING
+ "req_desc NULL"
+ "\n");
+ else {
+ instance->instancet->
+ fire_cmd(instance,
+ req_desc->
+ u.low,
+ req_desc->
+ u.high,
+ instance->
+ reg_set);
+ }
+ }
+ }
+ }
+
+ /* Reset load balance info */
+ memset(fusion->load_balance_info, 0,
+ sizeof(struct LD_LOAD_BALANCE_INFO)
+ *MAX_LOGICAL_DRIVES);
+
+ if (!megasas_get_map_info(instance))
+ megasas_sync_map_info(instance);
+
+ /* Adapter reset completed successfully */
+ printk(KERN_WARNING "megaraid_sas: Reset "
+ "successful.\n");
+ retval = SUCCESS;
+ goto out;
+ }
+ /* Reset failed, kill the adapter */
+ printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
+ "adapter.\n");
+ megaraid_sas_kill_hba(instance);
+ retval = FAILED;
+ } else {
+ instance->instancet->enable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ }
+out:
+ clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+ mutex_unlock(&instance->reset_mutex);
+ return retval;
+}
+
+/* Fusion OCR work queue */
+void megasas_fusion_ocr_wq(struct work_struct *work)
+{
+ struct megasas_instance *instance =
+ container_of(work, struct megasas_instance, work_init);
+
+ megasas_reset_fusion(instance->host);
+}
+
+struct megasas_instance_template megasas_instance_template_fusion = {
+ .fire_cmd = megasas_fire_cmd_fusion,
+ .enable_intr = megasas_enable_intr_fusion,
+ .disable_intr = megasas_disable_intr_fusion,
+ .clear_intr = megasas_clear_intr_fusion,
+ .read_fw_status_reg = megasas_read_fw_status_reg_fusion,
+ .adp_reset = megasas_adp_reset_fusion,
+ .check_reset = megasas_check_reset_fusion,
+ .service_isr = megasas_isr_fusion,
+ .tasklet = megasas_complete_cmd_dpc_fusion,
+ .init_adapter = megasas_init_adapter_fusion,
+ .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion,
+ .issue_dcmd = megasas_issue_dcmd_fusion,
+};
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
new file mode 100644
index 000000000000..82b577a72c8b
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -0,0 +1,695 @@
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2009-2011 LSI 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
+ *
+ * FILE: megaraid_sas_fusion.h
+ *
+ * Authors: LSI Corporation
+ * Manoj Jose
+ * Sumant Patro
+ *
+ * Send feedback to: <megaraidlinux@lsi.com>
+ *
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: Linuxraid
+ */
+
+#ifndef _MEGARAID_SAS_FUSION_H_
+#define _MEGARAID_SAS_FUSION_H_
+
+/* Fusion defines */
+#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
+#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009)
+#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256
+#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
+#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1
+#define MEGASAS_LOAD_BALANCE_FLAG 0x1
+#define MEGASAS_DCMD_MBOX_PEND_FLAG 0x1
+#define HOST_DIAG_WRITE_ENABLE 0x80
+#define HOST_DIAG_RESET_ADAPTER 0x4
+#define MEGASAS_FUSION_MAX_RESET_TRIES 3
+
+/* T10 PI defines */
+#define MR_PROT_INFO_TYPE_CONTROLLER 0x8
+#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f
+#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9
+#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB
+#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18
+#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20
+#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60
+#define MEGASAS_EEDPBLOCKSIZE 512
+
+/*
+ * Raid context flags
+ */
+
+#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4
+#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30
+enum MR_RAID_FLAGS_IO_SUB_TYPE {
+ MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0,
+ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1,
+};
+
+/*
+ * Request descriptor types
+ */
+#define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7
+#define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1
+
+#define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1
+
+#define MEGASAS_FP_CMD_LEN 16
+#define MEGASAS_FUSION_IN_RESET 0
+
+/*
+ * Raid Context structure which describes MegaRAID specific IO Paramenters
+ * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames
+ */
+
+struct RAID_CONTEXT {
+ u16 resvd0;
+ u16 timeoutValue;
+ u8 regLockFlags;
+ u8 resvd1;
+ u16 VirtualDiskTgtId;
+ u64 regLockRowLBA;
+ u32 regLockLength;
+ u16 nextLMId;
+ u8 exStatus;
+ u8 status;
+ u8 RAIDFlags;
+ u8 numSGE;
+ u16 configSeqNum;
+ u8 spanArm;
+ u8 resvd2[3];
+};
+
+#define RAID_CTX_SPANARM_ARM_SHIFT (0)
+#define RAID_CTX_SPANARM_ARM_MASK (0x1f)
+
+#define RAID_CTX_SPANARM_SPAN_SHIFT (5)
+#define RAID_CTX_SPANARM_SPAN_MASK (0xE0)
+
+/*
+ * define region lock types
+ */
+enum REGION_TYPE {
+ REGION_TYPE_UNUSED = 0,
+ REGION_TYPE_SHARED_READ = 1,
+ REGION_TYPE_SHARED_WRITE = 2,
+ REGION_TYPE_EXCLUSIVE = 3,
+};
+
+/* MPI2 defines */
+#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
+#define MPI2_WHOINIT_HOST_DRIVER (0x04)
+#define MPI2_VERSION_MAJOR (0x02)
+#define MPI2_VERSION_MINOR (0x00)
+#define MPI2_VERSION_MAJOR_MASK (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT (8)
+#define MPI2_VERSION_MINOR_MASK (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT (0)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI2_VERSION_MINOR)
+#define MPI2_HEADER_VERSION_UNIT (0x10)
+#define MPI2_HEADER_VERSION_DEV (0x00)
+#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
+#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
+#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
+#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \
+ MPI2_HEADER_VERSION_DEV)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
+#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
+#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
+#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
+#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0)
+#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004)
+#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF)
+#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4)
+#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB)
+#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2)
+#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7)
+#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD)
+
+struct MPI25_IEEE_SGE_CHAIN64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 NextChainOffset;
+ u8 Flags;
+};
+
+struct MPI2_SGE_SIMPLE_UNION {
+ u32 FlagsLength;
+ union {
+ u32 Address32;
+ u64 Address64;
+ } u;
+};
+
+struct MPI2_SCSI_IO_CDB_EEDP32 {
+ u8 CDB[20]; /* 0x00 */
+ u32 PrimaryReferenceTag; /* 0x14 */
+ u16 PrimaryApplicationTag; /* 0x18 */
+ u16 PrimaryApplicationTagMask; /* 0x1A */
+ u32 TransferLength; /* 0x1C */
+};
+
+struct MPI2_SGE_CHAIN_UNION {
+ u16 Length;
+ u8 NextChainOffset;
+ u8 Flags;
+ union {
+ u32 Address32;
+ u64 Address64;
+ } u;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE32 {
+ u32 Address;
+ u32 FlagsLength;
+};
+
+struct MPI2_IEEE_SGE_CHAIN32 {
+ u32 Address;
+ u32 FlagsLength;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 Reserved2;
+ u8 Flags;
+};
+
+struct MPI2_IEEE_SGE_CHAIN64 {
+ u64 Address;
+ u32 Length;
+ u16 Reserved1;
+ u8 Reserved2;
+ u8 Flags;
+};
+
+union MPI2_IEEE_SGE_SIMPLE_UNION {
+ struct MPI2_IEEE_SGE_SIMPLE32 Simple32;
+ struct MPI2_IEEE_SGE_SIMPLE64 Simple64;
+};
+
+union MPI2_IEEE_SGE_CHAIN_UNION {
+ struct MPI2_IEEE_SGE_CHAIN32 Chain32;
+ struct MPI2_IEEE_SGE_CHAIN64 Chain64;
+};
+
+union MPI2_SGE_IO_UNION {
+ struct MPI2_SGE_SIMPLE_UNION MpiSimple;
+ struct MPI2_SGE_CHAIN_UNION MpiChain;
+ union MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
+ union MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
+};
+
+union MPI2_SCSI_IO_CDB_UNION {
+ u8 CDB32[32];
+ struct MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+ struct MPI2_SGE_SIMPLE_UNION SGE;
+};
+
+/*
+ * RAID SCSI IO Request Message
+ * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
+ */
+struct MPI2_RAID_SCSI_IO_REQUEST {
+ u16 DevHandle; /* 0x00 */
+ u8 ChainOffset; /* 0x02 */
+ u8 Function; /* 0x03 */
+ u16 Reserved1; /* 0x04 */
+ u8 Reserved2; /* 0x06 */
+ u8 MsgFlags; /* 0x07 */
+ u8 VP_ID; /* 0x08 */
+ u8 VF_ID; /* 0x09 */
+ u16 Reserved3; /* 0x0A */
+ u32 SenseBufferLowAddress; /* 0x0C */
+ u16 SGLFlags; /* 0x10 */
+ u8 SenseBufferLength; /* 0x12 */
+ u8 Reserved4; /* 0x13 */
+ u8 SGLOffset0; /* 0x14 */
+ u8 SGLOffset1; /* 0x15 */
+ u8 SGLOffset2; /* 0x16 */
+ u8 SGLOffset3; /* 0x17 */
+ u32 SkipCount; /* 0x18 */
+ u32 DataLength; /* 0x1C */
+ u32 BidirectionalDataLength; /* 0x20 */
+ u16 IoFlags; /* 0x24 */
+ u16 EEDPFlags; /* 0x26 */
+ u32 EEDPBlockSize; /* 0x28 */
+ u32 SecondaryReferenceTag; /* 0x2C */
+ u16 SecondaryApplicationTag; /* 0x30 */
+ u16 ApplicationTagTranslationMask; /* 0x32 */
+ u8 LUN[8]; /* 0x34 */
+ u32 Control; /* 0x3C */
+ union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+ struct RAID_CONTEXT RaidContext; /* 0x60 */
+ union MPI2_SGE_IO_UNION SGL; /* 0x80 */
+};
+
+/*
+ * MPT RAID MFA IO Descriptor.
+ */
+struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR {
+ u32 RequestFlags:8;
+ u32 MessageAddress1:24; /* bits 31:8*/
+ u32 MessageAddress2; /* bits 61:32 */
+};
+
+/* Default Request Descriptor */
+struct MPI2_DEFAULT_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 DescriptorTypeDependent; /* 0x06 */
+};
+
+/* High Priority Request Descriptor */
+struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 Reserved1; /* 0x06 */
+};
+
+/* SCSI IO Request Descriptor */
+struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 DevHandle; /* 0x06 */
+};
+
+/* SCSI Target Request Descriptor */
+struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* RAID Accelerator Request Descriptor */
+struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
+ u8 RequestFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 LMID; /* 0x04 */
+ u16 Reserved; /* 0x06 */
+};
+
+/* union of Request Descriptors */
+union MEGASAS_REQUEST_DESCRIPTOR_UNION {
+ struct MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
+ struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
+ struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
+ struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
+ struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
+ struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo;
+ union {
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+ u64 Words;
+ };
+};
+
+/* Default Reply Descriptor */
+struct MPI2_DEFAULT_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 DescriptorTypeDependent1; /* 0x02 */
+ u32 DescriptorTypeDependent2; /* 0x04 */
+};
+
+/* Address Reply Descriptor */
+struct MPI2_ADDRESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u32 ReplyFrameAddress; /* 0x04 */
+};
+
+/* SCSI IO Success Reply Descriptor */
+struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u16 TaskTag; /* 0x04 */
+ u16 Reserved1; /* 0x06 */
+};
+
+/* TargetAssist Success Reply Descriptor */
+struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u8 SequenceNumber; /* 0x04 */
+ u8 Reserved1; /* 0x05 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* Target Command Buffer Reply Descriptor */
+struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u8 VP_ID; /* 0x02 */
+ u8 Flags; /* 0x03 */
+ u16 InitiatorDevHandle; /* 0x04 */
+ u16 IoIndex; /* 0x06 */
+};
+
+/* RAID Accelerator Success Reply Descriptor */
+struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
+ u8 ReplyFlags; /* 0x00 */
+ u8 MSIxIndex; /* 0x01 */
+ u16 SMID; /* 0x02 */
+ u32 Reserved; /* 0x04 */
+};
+
+/* union of Reply Descriptors */
+union MPI2_REPLY_DESCRIPTORS_UNION {
+ struct MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
+ struct MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
+ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
+ struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
+ struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+ struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
+ RAIDAcceleratorSuccess;
+ u64 Words;
+};
+
+/* IOCInit Request message */
+struct MPI2_IOC_INIT_REQUEST {
+ u8 WhoInit; /* 0x00 */
+ u8 Reserved1; /* 0x01 */
+ u8 ChainOffset; /* 0x02 */
+ u8 Function; /* 0x03 */
+ u16 Reserved2; /* 0x04 */
+ u8 Reserved3; /* 0x06 */
+ u8 MsgFlags; /* 0x07 */
+ u8 VP_ID; /* 0x08 */
+ u8 VF_ID; /* 0x09 */
+ u16 Reserved4; /* 0x0A */
+ u16 MsgVersion; /* 0x0C */
+ u16 HeaderVersion; /* 0x0E */
+ u32 Reserved5; /* 0x10 */
+ u16 Reserved6; /* 0x14 */
+ u8 Reserved7; /* 0x16 */
+ u8 HostMSIxVectors; /* 0x17 */
+ u16 Reserved8; /* 0x18 */
+ u16 SystemRequestFrameSize; /* 0x1A */
+ u16 ReplyDescriptorPostQueueDepth; /* 0x1C */
+ u16 ReplyFreeQueueDepth; /* 0x1E */
+ u32 SenseBufferAddressHigh; /* 0x20 */
+ u32 SystemReplyAddressHigh; /* 0x24 */
+ u64 SystemRequestFrameBaseAddress; /* 0x28 */
+ u64 ReplyDescriptorPostQueueAddress;/* 0x30 */
+ u64 ReplyFreeQueueAddress; /* 0x38 */
+ u64 TimeStamp; /* 0x40 */
+};
+
+/* mrpriv defines */
+#define MR_PD_INVALID 0xFFFF
+#define MAX_SPAN_DEPTH 8
+#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH)
+#define MAX_ROW_SIZE 32
+#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE)
+#define MAX_LOGICAL_DRIVES 64
+#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES)
+#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES)
+#define MAX_ARRAYS 128
+#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS)
+#define MAX_PHYSICAL_DEVICES 256
+#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
+#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+
+struct MR_DEV_HANDLE_INFO {
+ u16 curDevHdl;
+ u8 validHandles;
+ u8 reserved;
+ u16 devHandle[2];
+};
+
+struct MR_ARRAY_INFO {
+ u16 pd[MAX_RAIDMAP_ROW_SIZE];
+};
+
+struct MR_QUAD_ELEMENT {
+ u64 logStart;
+ u64 logEnd;
+ u64 offsetInSpan;
+ u32 diff;
+ u32 reserved1;
+};
+
+struct MR_SPAN_INFO {
+ u32 noElements;
+ u32 reserved1;
+ struct MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH];
+};
+
+struct MR_LD_SPAN {
+ u64 startBlk;
+ u64 numBlks;
+ u16 arrayRef;
+ u8 reserved[6];
+};
+
+struct MR_SPAN_BLOCK_INFO {
+ u64 num_rows;
+ struct MR_LD_SPAN span;
+ struct MR_SPAN_INFO block_span_info;
+};
+
+struct MR_LD_RAID {
+ struct {
+ u32 fpCapable:1;
+ u32 reserved5:3;
+ u32 ldPiMode:4;
+ u32 pdPiMode:4;
+ u32 encryptionType:8;
+ u32 fpWriteCapable:1;
+ u32 fpReadCapable:1;
+ u32 fpWriteAcrossStripe:1;
+ u32 fpReadAcrossStripe:1;
+ u32 reserved4:8;
+ } capability;
+ u32 reserved6;
+ u64 size;
+ u8 spanDepth;
+ u8 level;
+ u8 stripeShift;
+ u8 rowSize;
+ u8 rowDataSize;
+ u8 writeMode;
+ u8 PRL;
+ u8 SRL;
+ u16 targetId;
+ u8 ldState;
+ u8 regTypeReqOnWrite;
+ u8 modFactor;
+ u8 reserved2[1];
+ u16 seqNum;
+
+ struct {
+ u32 ldSyncRequired:1;
+ u32 reserved:31;
+ } flags;
+
+ u8 reserved3[0x5C];
+};
+
+struct MR_LD_SPAN_MAP {
+ struct MR_LD_RAID ldRaid;
+ u8 dataArmMap[MAX_RAIDMAP_ROW_SIZE];
+ struct MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH];
+};
+
+struct MR_FW_RAID_MAP {
+ u32 totalSize;
+ union {
+ struct {
+ u32 maxLd;
+ u32 maxSpanDepth;
+ u32 maxRowSize;
+ u32 maxPdCount;
+ u32 maxArrays;
+ } validationInfo;
+ u32 version[5];
+ u32 reserved1[5];
+ };
+
+ u32 ldCount;
+ u32 Reserved1;
+ u8 ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+
+ MAX_RAIDMAP_VIEWS];
+ u8 fpPdIoTimeoutSec;
+ u8 reserved2[7];
+ struct MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS];
+ struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES];
+ struct MR_LD_SPAN_MAP ldSpanMap[1];
+};
+
+struct IO_REQUEST_INFO {
+ u64 ldStartBlock;
+ u32 numBlocks;
+ u16 ldTgtId;
+ u8 isRead;
+ u16 devHandle;
+ u64 pdBlock;
+ u8 fpOkForIo;
+};
+
+struct MR_LD_TARGET_SYNC {
+ u8 targetId;
+ u8 reserved;
+ u16 seqNum;
+};
+
+#define IEEE_SGE_FLAGS_ADDR_MASK (0x03)
+#define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
+#define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
+#define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
+#define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
+#define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
+#define IEEE_SGE_FLAGS_END_OF_LIST (0x40)
+
+struct megasas_register_set;
+struct megasas_instance;
+
+union desc_word {
+ u64 word;
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+};
+
+struct megasas_cmd_fusion {
+ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+ dma_addr_t io_request_phys_addr;
+
+ union MPI2_SGE_IO_UNION *sg_frame;
+ dma_addr_t sg_frame_phys_addr;
+
+ u8 *sense;
+ dma_addr_t sense_phys_addr;
+
+ struct list_head list;
+ struct scsi_cmnd *scmd;
+ struct megasas_instance *instance;
+
+ u8 retry_for_fw_reset;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *request_desc;
+
+ /*
+ * Context for a MFI frame.
+ * Used to get the mfi cmd from list when a MFI cmd is completed
+ */
+ u32 sync_cmd_idx;
+ u32 index;
+ u8 flags;
+};
+
+struct LD_LOAD_BALANCE_INFO {
+ u8 loadBalanceFlag;
+ u8 reserved1;
+ u16 raid1DevHandle[2];
+ atomic_t scsi_pending_cmds[2];
+ u64 last_accessed_block[2];
+};
+
+struct MR_FW_RAID_MAP_ALL {
+ struct MR_FW_RAID_MAP raidMap;
+ struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1];
+} __attribute__ ((packed));
+
+struct fusion_context {
+ struct megasas_cmd_fusion **cmd_list;
+ struct list_head cmd_pool;
+
+ spinlock_t cmd_pool_lock;
+
+ dma_addr_t req_frames_desc_phys;
+ u8 *req_frames_desc;
+
+ struct dma_pool *io_request_frames_pool;
+ dma_addr_t io_request_frames_phys;
+ u8 *io_request_frames;
+
+ struct dma_pool *sg_dma_pool;
+ struct dma_pool *sense_dma_pool;
+
+ dma_addr_t reply_frames_desc_phys;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+ struct dma_pool *reply_frames_desc_pool;
+
+ u16 last_reply_idx;
+
+ u32 reply_q_depth;
+ u32 request_alloc_sz;
+ u32 reply_alloc_sz;
+ u32 io_frames_alloc_sz;
+
+ u16 max_sge_in_main_msg;
+ u16 max_sge_in_chain;
+
+ u8 chain_offset_io_request;
+ u8 chain_offset_mfi_pthru;
+
+ struct MR_FW_RAID_MAP_ALL *ld_map[2];
+ dma_addr_t ld_map_phys[2];
+
+ u32 map_sz;
+ u8 fast_path_io;
+ struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES];
+};
+
+union desc_value {
+ u64 word;
+ struct {
+ u32 low;
+ u32 high;
+ } u;
+};
+
+#endif /* _MEGARAID_SAS_FUSION_H_ */
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 1f784fde2510..197aa1b3f0f3 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1627,7 +1627,7 @@ static void cmd_complete(struct mesh_state *ms)
* Called by midlayer with host locked to queue a new
* request
*/
-static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mesh_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct mesh_state *ms;
@@ -1648,6 +1648,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(mesh_queue)
+
/*
* Called to handle interrupts, either call by the interrupt
* handler (do_mesh_interrupt) or by other functions in
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 4b1c2f0350f9..8be75e65f763 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.15
+ * mpi2.h Version: 02.00.16
*
* Version History
* ---------------
@@ -61,6 +61,8 @@
* Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
* Added defines for product-specific range of message
* function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
* --------------------------------------------------------------------------
*/
@@ -86,7 +88,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0F)
+#define MPI2_HEADER_VERSION_UNIT (0x10)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -929,6 +931,9 @@ typedef struct _MPI2_MPI_SGE_UNION
#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00)
#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04)
+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
/* Address Size */
#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index e3728d736d85..d76a65847603 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.14
+ * mpi2_cnfg.h Version: 02.00.15
*
* Version History
* ---------------
@@ -121,6 +121,10 @@
* Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
* Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
* Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
* --------------------------------------------------------------------------
*/
@@ -333,7 +337,7 @@ typedef struct _MPI2_CONFIG_REQUEST
#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Config Reply Message */
@@ -379,6 +383,8 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
+
#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
@@ -390,6 +396,8 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
+
+
/* Manufacturing Page 0 */
typedef struct _MPI2_CONFIG_PAGE_MAN_0
@@ -729,6 +737,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
/* IO Unit Page 1 Flags defines */
#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
@@ -1347,6 +1356,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000)
#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000)
#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080)
#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
@@ -1469,11 +1479,15 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03)
#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04)
#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06)
#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
+
+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
@@ -1545,6 +1559,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
@@ -1571,6 +1586,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
index bd6c92b5fae5..b1e88f26b748 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
@@ -291,6 +291,7 @@ mpi2_raid.h
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
mpi2_sas.h
@@ -301,6 +302,7 @@ mpi2_sas.h
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
* --------------------------------------------------------------------------
mpi2_targ.h
@@ -324,6 +326,7 @@ mpi2_tool.h
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
* --------------------------------------------------------------------------
mpi2_type.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index c4c99dfcb820..20e6b8869341 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -6,7 +6,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.09
+ * mpi2_init.h Version: 02.00.10
*
* Version History
* ---------------
@@ -32,6 +32,7 @@
* Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
* Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
* 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
* --------------------------------------------------------------------------
*/
@@ -98,7 +99,13 @@ typedef struct _MPI2_SCSI_IO_REQUEST
U8 LUN[8]; /* 0x34 */
U32 Control; /* 0x3C */
MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+
+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
MPI2_SGE_IO_UNION SGL; /* 0x60 */
+
} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index 495bedc4d1f7..761cbdb8a033 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.14
+ * mpi2_ioc.h Version: 02.00.15
*
* Version History
* ---------------
@@ -101,6 +101,8 @@
* 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
* Added PowerManagementControl Request structures and
* defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
* --------------------------------------------------------------------------
*/
@@ -456,7 +458,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_STATE_CHANGE (0x0002)
#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005)
#define MPI2_EVENT_EVENT_CHANGE (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL (0x000E)
+#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */
#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F)
#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014)
#define MPI2_EVENT_SAS_DISCOVERY (0x0016)
@@ -517,6 +519,7 @@ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
MPI2_POINTER pMpi2EventDataHardResetReceived_t;
/* Task Set Full Event data */
+/* this event is obsolete */
typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
{
@@ -831,6 +834,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
index 5160c33d2a00..bd61a7b60a2b 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2010 LSI Corporation.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.04
+ * mpi2_raid.h Version: 02.00.05
*
* Version History
* ---------------
@@ -22,6 +22,7 @@
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
*/
@@ -260,6 +261,7 @@ typedef struct _MPI2_RAID_VOL_INDICATOR
#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
/* RAID Action Reply ActionData union */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
index 2d8aeed51392..608f6d6e6fca 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2010 LSI Corporation.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2.h Version: 02.00.03
+ * mpi2_sas.h Version: 02.00.04
*
* Version History
* ---------------
@@ -20,6 +20,7 @@
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
* --------------------------------------------------------------------------
*/
@@ -110,7 +111,7 @@ typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
/* values for PassthroughFlags field */
#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SMP Passthrough Reply Message */
@@ -174,7 +175,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SATA Passthrough Reply Message */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 686b09b81219..5c6e3a67bb94 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -6,7 +6,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.04
+ * mpi2_tool.h Version: 02.00.05
*
* Version History
* ---------------
@@ -22,6 +22,7 @@
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
* --------------------------------------------------------------------------
*/
@@ -37,6 +38,7 @@
/* defines for the Tools */
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02)
#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
@@ -102,8 +104,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST
* Toolbox Memory Move request
****************************************************************************/
-typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
-{
+typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST {
U8 Tool; /* 0x00 */
U8 Reserved1; /* 0x01 */
U8 ChainOffset; /* 0x02 */
@@ -120,6 +121,44 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
/****************************************************************************
+* Toolbox Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 Flags; /* 0x10 */
+ U32 DataLength; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+Mpi2ToolboxDiagDataUploadRequest_t,
+MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER {
+ U32 DiagDataLength; /* 00h */
+ U8 FormatCode; /* 04h */
+ U8 Reserved1; /* 05h */
+ U16 Reserved2; /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
+/****************************************************************************
* Toolbox ISTWI Read Write Tool
****************************************************************************/
@@ -162,7 +201,7 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {
#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox ISTWI Read Write Tool reply message */
@@ -248,7 +287,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
Mpi2ToolboxDiagnosticCliRequest_t,
MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox Diagnostic CLI Tool reply message */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 12faf64f91b0..b2a817055b8b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -65,7 +65,6 @@
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */
static int max_queue_depth = -1;
module_param(max_queue_depth, int, 0);
@@ -79,6 +78,10 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+static int missing_delay[2] = {-1, -1};
+module_param_array(missing_delay, int, NULL, 0);
+MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
+
/* diag_buffer_enable is bitwise
* bit 0 set = TRACE
* bit 1 set = SNAPSHOT
@@ -515,9 +518,6 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_EVENT_CHANGE:
desc = "Event Change";
break;
- case MPI2_EVENT_TASK_SET_FULL:
- desc = "Task Set Full";
- break;
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
desc = "Device Status Change";
break;
@@ -758,7 +758,7 @@ _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
if (smid < ioc->internal_smid) {
i = smid - ioc->hi_priority_smid;
cb_idx = ioc->hpr_lookup[i].cb_idx;
- } else {
+ } else if (smid <= ioc->hba_queue_depth) {
i = smid - ioc->internal_smid;
cb_idx = ioc->internal_lookup[i].cb_idx;
}
@@ -848,6 +848,7 @@ _base_interrupt(int irq, void *bus_id)
return IRQ_NONE;
completed_cmds = 0;
+ cb_idx = 0xFF;
do {
rd.word = rpf->Words;
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
@@ -860,6 +861,9 @@ _base_interrupt(int irq, void *bus_id)
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu
(rpf->AddressReply.ReplyFrameAddress);
+ if (reply > ioc->reply_dma_max_address ||
+ reply < ioc->reply_dma_min_address)
+ reply = 0;
} else if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
goto next;
@@ -1489,6 +1493,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
unsigned long flags;
int i;
+ struct chain_tracker *chain_req, *next;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
if (smid >= ioc->hi_priority_smid) {
@@ -1511,6 +1516,14 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
/* scsiio queue */
i = smid - 1;
+ if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
+ list_for_each_entry_safe(chain_req, next,
+ &ioc->scsi_lookup[i].chain_list, tracker_list) {
+ list_del_init(&chain_req->tracker_list);
+ list_add_tail(&chain_req->tracker_list,
+ &ioc->free_chain_list);
+ }
+ }
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].scmd = NULL;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
@@ -1819,6 +1832,97 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
}
/**
+ * _base_update_missing_delay - change the missing delay timers
+ * @ioc: per adapter object
+ * @device_missing_delay: amount of time till device is reported missing
+ * @io_missing_delay: interval IO is returned when there is a missing device
+ *
+ * Return nothing.
+ *
+ * Passed on the command line, this function will modify the device missing
+ * delay, as well as the io missing delay. This should be called at driver
+ * load time.
+ */
+static void
+_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
+ u16 device_missing_delay, u8 io_missing_delay)
+{
+ u16 dmd, dmd_new, dmd_orignal;
+ u8 io_missing_delay_original;
+ u16 sz;
+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2ConfigReply_t mpi_reply;
+ u8 num_phys = 0;
+ u16 ioc_status;
+
+ mpt2sas_config_get_number_hba_phys(ioc, &num_phys);
+ if (!num_phys)
+ return;
+
+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys *
+ sizeof(Mpi2SasIOUnit1PhyData_t));
+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg1) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+ sas_iounit_pg1, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+
+ /* device missing delay */
+ dmd = sas_iounit_pg1->ReportDeviceMissingDelay;
+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
+ dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
+ else
+ dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+ dmd_orignal = dmd;
+ if (device_missing_delay > 0x7F) {
+ dmd = (device_missing_delay > 0x7F0) ? 0x7F0 :
+ device_missing_delay;
+ dmd = dmd / 16;
+ dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16;
+ } else
+ dmd = device_missing_delay;
+ sas_iounit_pg1->ReportDeviceMissingDelay = dmd;
+
+ /* io missing delay */
+ io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay;
+ sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay;
+
+ if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
+ sz)) {
+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
+ dmd_new = (dmd &
+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
+ else
+ dmd_new =
+ dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+ printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), "
+ "new(%d)\n", ioc->name, dmd_orignal, dmd_new);
+ printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), "
+ "new(%d)\n", ioc->name, io_missing_delay_original,
+ io_missing_delay);
+ ioc->device_missing_delay = dmd_new;
+ ioc->io_missing_delay = io_missing_delay;
+ }
+
+out:
+ kfree(sas_iounit_pg1);
+}
+
+/**
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
*
@@ -1855,6 +1959,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+
}
/**
@@ -1868,6 +1973,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
static void
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
{
+ int i;
+
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1932,6 +2039,20 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
}
kfree(ioc->hpr_lookup);
kfree(ioc->internal_lookup);
+ if (ioc->chain_lookup) {
+ for (i = 0; i < ioc->chain_depth; i++) {
+ if (ioc->chain_lookup[i].chain_buffer)
+ pci_pool_free(ioc->chain_dma_pool,
+ ioc->chain_lookup[i].chain_buffer,
+ ioc->chain_lookup[i].chain_buffer_dma);
+ }
+ if (ioc->chain_dma_pool)
+ pci_pool_destroy(ioc->chain_dma_pool);
+ }
+ if (ioc->chain_lookup) {
+ free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
+ ioc->chain_lookup = NULL;
+ }
}
@@ -1953,6 +2074,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u32 sz, total_sz;
u32 retry_sz;
u16 max_request_credit;
+ int i;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
@@ -1970,14 +2092,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
/* command line tunables for max controller queue depth */
- if (max_queue_depth != -1) {
+ if (max_queue_depth != -1)
max_request_credit = (max_queue_depth < facts->RequestCredit)
? max_queue_depth : facts->RequestCredit;
- } else {
- max_request_credit = (facts->RequestCredit >
- MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
- facts->RequestCredit;
- }
+ else
+ max_request_credit = facts->RequestCredit;
ioc->hba_queue_depth = max_request_credit;
ioc->hi_priority_depth = facts->HighPriorityCredit;
@@ -2083,7 +2202,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
* "frame for smid=0
*/
ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
- sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+ sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);
/* hi-priority queue */
sz += (ioc->hi_priority_depth * ioc->request_sz);
@@ -2124,19 +2243,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
ioc->request_sz);
- ioc->chain = ioc->internal + (ioc->internal_depth *
- ioc->request_sz);
- ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *
- ioc->request_sz);
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
ioc->request, ioc->hba_queue_depth, ioc->request_sz,
(ioc->hba_queue_depth * ioc->request_sz)/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
- ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
- ioc->request_sz))/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
ioc->name, (unsigned long long) ioc->request_dma));
total_sz += sz;
@@ -2155,6 +2266,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
"depth(%d)\n", ioc->name, ioc->request,
ioc->scsiio_depth));
+ /* loop till the allocation succeeds */
+ do {
+ sz = ioc->chain_depth * sizeof(struct chain_tracker);
+ ioc->chain_pages = get_order(sz);
+ ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
+ GFP_KERNEL, ioc->chain_pages);
+ if (ioc->chain_lookup == NULL)
+ ioc->chain_depth -= 100;
+ } while (ioc->chain_lookup == NULL);
+ ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
+ ioc->request_sz, 16, 0);
+ if (!ioc->chain_dma_pool) {
+ printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create "
+ "failed\n", ioc->name);
+ goto out;
+ }
+ for (i = 0; i < ioc->chain_depth; i++) {
+ ioc->chain_lookup[i].chain_buffer = pci_pool_alloc(
+ ioc->chain_dma_pool , GFP_KERNEL,
+ &ioc->chain_lookup[i].chain_buffer_dma);
+ if (!ioc->chain_lookup[i].chain_buffer) {
+ ioc->chain_depth = i;
+ goto chain_done;
+ }
+ total_sz += ioc->request_sz;
+ }
+chain_done:
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth"
+ "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
+ ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
+ ioc->request_sz))/1024));
+
/* initialize hi-priority queue smid's */
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
sizeof(struct request_tracker), GFP_KERNEL);
@@ -2221,6 +2364,8 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->name);
goto out;
}
+ ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
+ ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
@@ -2302,7 +2447,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
return 0;
out:
- _base_release_memory_pools(ioc);
return -ENOMEM;
}
@@ -3485,6 +3629,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
INIT_LIST_HEAD(&ioc->free_list);
smid = 1;
for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
+ INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].smid = smid;
ioc->scsi_lookup[i].scmd = NULL;
@@ -3511,6 +3656,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
list_add_tail(&ioc->internal_lookup[i].tracker_list,
&ioc->internal_free_list);
}
+
+ /* chain pool */
+ INIT_LIST_HEAD(&ioc->free_chain_list);
+ for (i = 0; i < ioc->chain_depth; i++)
+ list_add_tail(&ioc->chain_lookup[i].tracker_list,
+ &ioc->free_chain_list);
+
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
/* initialize Reply Free Queue */
@@ -3708,12 +3860,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
_base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
_base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
- _base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
+ if (missing_delay[0] != -1 && missing_delay[1] != -1)
+ _base_update_missing_delay(ioc, missing_delay[0],
+ missing_delay[1]);
+
mpt2sas_base_start_watchdog(ioc);
return 0;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 0b15a8bdebfc..283568c6fb04 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "06.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 06
+#define MPT2SAS_DRIVER_VERSION "07.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 07
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -419,6 +419,18 @@ enum reset_type {
};
/**
+ * struct chain_tracker - firmware chain tracker
+ * @chain_buffer: chain buffer
+ * @chain_buffer_dma: physical address
+ * @tracker_list: list of free request (ioc->free_chain_list)
+ */
+struct chain_tracker {
+ void *chain_buffer;
+ dma_addr_t chain_buffer_dma;
+ struct list_head tracker_list;
+};
+
+/**
* struct request_tracker - firmware request tracker
* @smid: system message id
* @scmd: scsi request pointer
@@ -430,6 +442,7 @@ struct request_tracker {
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
+ struct list_head chain_list;
struct list_head tracker_list;
};
@@ -704,8 +717,10 @@ struct MPT2SAS_ADAPTER {
wait_queue_head_t reset_wq;
/* chain */
- u8 *chain;
- dma_addr_t chain_dma;
+ struct chain_tracker *chain_lookup;
+ struct list_head free_chain_list;
+ struct dma_pool *chain_dma_pool;
+ ulong chain_pages;
u16 max_sges_in_main_message;
u16 max_sges_in_chain_message;
u16 chains_needed_per_io;
@@ -737,6 +752,8 @@ struct MPT2SAS_ADAPTER {
u16 reply_sz;
u8 *reply;
dma_addr_t reply_dma;
+ u32 reply_dma_max_address;
+ u32 reply_dma_min_address;
struct dma_pool *reply_dma_pool;
/* reply free queue */
@@ -832,6 +849,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
ulong timeout, struct scsi_cmnd *scmd);
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
+void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 40cb8aeb21b1..e92b77af5484 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -81,6 +81,7 @@ enum block_state {
BLOCKING,
};
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_sas_device_find_by_handle - sas device search
* @ioc: per adapter object
@@ -107,7 +108,6 @@ _ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
return r;
}
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_display_some_debug - debug routine
* @ioc: per adapter object
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 16e99b686354..eda347c57979 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -931,31 +931,32 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
}
/**
- * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
+ * _scsih_get_chain_buffer_tracker - obtain chain tracker
* @ioc: per adapter object
- * @smid: system request message index
+ * @smid: smid associated to an IO request
*
- * Returns phys pointer to chain buffer.
+ * Returns chain tracker(from ioc->free_chain_list)
*/
-static dma_addr_t
-_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+static struct chain_tracker *
+_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
- ioc->chains_needed_per_io));
-}
+ struct chain_tracker *chain_req;
+ unsigned long flags;
-/**
- * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns virt pointer to chain buffer.
- */
-static void *
-_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
- ioc->chains_needed_per_io)));
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->free_chain_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ printk(MPT2SAS_WARN_FMT "chain buffers not available\n",
+ ioc->name);
+ return NULL;
+ }
+ chain_req = list_entry(ioc->free_chain_list.next,
+ struct chain_tracker, tracker_list);
+ list_del_init(&chain_req->tracker_list);
+ list_add_tail(&chain_req->tracker_list,
+ &ioc->scsi_lookup[smid - 1].chain_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return chain_req;
}
/**
@@ -986,6 +987,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
u32 sgl_flags;
u32 sgl_flags_last_element;
u32 sgl_flags_end_buffer;
+ struct chain_tracker *chain_req;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
@@ -1033,8 +1035,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
/* initializing the chain flags and pointers */
chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
- chain = _scsih_get_chain_buffer(ioc, smid);
- chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
+ chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
do {
sges_in_segment = (sges_left <=
ioc->max_sges_in_chain_message) ? sges_left :
@@ -1070,8 +1075,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
sges_in_segment--;
}
- chain_dma += ioc->request_sz;
- chain += ioc->request_sz;
+ chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
} while (1);
@@ -1094,28 +1102,24 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
}
/**
- * _scsih_change_queue_depth - setting device queue depth
+ * _scsih_adjust_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
- * @reason: calling context
*
- * Returns queue depth.
+ *
+ * Returns nothing
*/
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+static void
+_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
- int tag_type;
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct MPT2SAS_TARGET *sas_target_priv_data;
struct _sas_device *sas_device;
unsigned long flags;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
max_depth = shost->can_queue;
/* limit max device queue for SATA to 32 */
@@ -1141,8 +1145,27 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
max_depth = 1;
if (qdepth > max_depth)
qdepth = max_depth;
- tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
- scsi_adjust_queue_depth(sdev, tag_type, qdepth);
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+}
+
+/**
+ * _scsih_change_queue_depth - setting device queue depth
+ * @sdev: scsi device struct
+ * @qdepth: requested queue depth
+ * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
+ * (see include/scsi/scsi_host.h for definition)
+ *
+ * Returns queue depth.
+ */
+static int
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+{
+ if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
+ _scsih_adjust_queue_depth(sdev, qdepth);
+ else if (reason == SCSI_QDEPTH_QFULL)
+ scsi_track_queue_full(sdev, qdepth);
+ else
+ return -EOPNOTSUPP;
if (sdev->inquiry_len > 7)
sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
@@ -2251,13 +2274,13 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
struct scsi_target *starget = scmd->device->sdev_target;
- starget_printk(KERN_INFO, starget, "attempting target reset! "
+ starget_printk(KERN_INFO, starget, "attempting device reset! "
"scmd(%p)\n", scmd);
_scsih_tm_display_info(ioc, scmd);
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "target been deleted! "
+ starget_printk(KERN_INFO, starget, "device been deleted! "
"scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
@@ -2576,9 +2599,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
&sas_expander->sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+ SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+ SAS_FANOUT_EXPANDER_DEVICE) {
spin_lock_irqsave(&ioc->sas_node_lock, flags);
expander_sibling =
@@ -2715,9 +2738,10 @@ static u8
_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u8 msix_index, u32 reply)
{
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2SasIoUnitControlReply_t *mpi_reply =
mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
+#endif
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"sc_complete:handle(0x%04x), (open) "
"smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -3315,7 +3339,7 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
* SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
*/
static int
-_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
{
struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -3441,6 +3465,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
return SCSI_MLQUEUE_HOST_BUSY;
}
+static DEF_SCSI_QCMD(_scsih_qcmd)
+
/**
* _scsih_normalize_sense - normalize descriptor and fixed format sense data
* @sense_buffer: sense data returned by target
@@ -3961,6 +3987,7 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
u16 attached_handle;
+ u8 link_rate;
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"updating handles for sas_host(0x%016llx)\n",
@@ -3982,15 +4009,17 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
goto out;
for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
if (i == 0)
ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
PhyData[0].ControllerDevHandle);
ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
AttachedDevHandle);
+ if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
+ link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
- attached_handle, i, sas_iounit_pg0->PhyData[i].
- NegotiatedLinkRate >> 4);
+ attached_handle, i, link_rate);
}
out:
kfree(sas_iounit_pg0);
@@ -4334,14 +4363,14 @@ _scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
/**
- * _scsih_expander_remove - removing expander object
+ * mpt2sas_expander_remove - removing expander object
* @ioc: per adapter object
* @sas_address: expander sas_address
*
* Return nothing.
*/
-static void
-_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+void
+mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct _sas_node *sas_expander;
unsigned long flags;
@@ -4352,6 +4381,11 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
+ if (!sas_expander) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ return;
+ }
+ list_del(&sas_expander->list);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_expander_node_remove(ioc, sas_expander);
}
@@ -4641,6 +4675,33 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
sas_device_backup.sas_address));
}
+/**
+ * mpt2sas_device_remove - removing device object
+ * @ioc: per adapter object
+ * @sas_address: expander sas_address
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+{
+ struct _sas_device *sas_device;
+ unsigned long flags;
+
+ if (ioc->shost_recovery)
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_address);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_remove_device(ioc, sas_device);
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
@@ -4735,7 +4796,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
int i;
u16 parent_handle, handle;
u16 reason_code;
- u8 phy_number;
+ u8 phy_number, max_phys;
struct _sas_node *sas_expander;
struct _sas_device *sas_device;
u64 sas_address;
@@ -4773,11 +4834,13 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
parent_handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (sas_expander)
+ if (sas_expander) {
sas_address = sas_expander->sas_address;
- else if (parent_handle < ioc->sas_hba.num_phys)
+ max_phys = sas_expander->num_phys;
+ } else if (parent_handle < ioc->sas_hba.num_phys) {
sas_address = ioc->sas_hba.sas_address;
- else
+ max_phys = ioc->sas_hba.num_phys;
+ } else
return;
/* handle siblings events */
@@ -4791,6 +4854,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
ioc->pci_error_recovery)
return;
phy_number = event_data->StartPhyNum + i;
+ if (phy_number >= max_phys)
+ continue;
reason_code = event_data->PHY[i].PhyStatus &
MPI2_EVENT_SAS_TOPO_RC_MASK;
if ((event_data->PHY[i].PhyStatus &
@@ -4842,7 +4907,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
/* handle expander removal */
if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
sas_expander)
- _scsih_expander_remove(ioc, sas_address);
+ mpt2sas_expander_remove(ioc, sas_address);
}
@@ -5771,90 +5836,6 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
}
/**
- * _scsih_task_set_full - handle task set full
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Throttle back qdepth.
- */
-static void
-_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
- *fw_event)
-{
- unsigned long flags;
- struct _sas_device *sas_device;
- static struct _raid_device *raid_device;
- struct scsi_device *sdev;
- int depth;
- u16 current_depth;
- u16 handle;
- int id, channel;
- u64 sas_address;
- Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
-
- current_depth = le16_to_cpu(event_data->CurrentDepth);
- handle = le16_to_cpu(event_data->DevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- id = sas_device->id;
- channel = sas_device->channel;
- sas_address = sas_device->sas_address;
-
- /* if hidden raid component, then change to volume characteristics */
- if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(
- ioc, sas_device->volume_handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (raid_device) {
- id = raid_device->id;
- channel = raid_device->channel;
- handle = raid_device->handle;
- sas_address = raid_device->wwid;
- }
- }
-
- if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
- starget_printk(KERN_INFO, sas_device->starget, "task set "
- "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
- handle, (unsigned long long)sas_address, current_depth);
-
- shost_for_each_device(sdev, ioc->shost) {
- if (sdev->id == id && sdev->channel == channel) {
- if (current_depth > sdev->queue_depth) {
- if (ioc->logging_level &
- MPT_DEBUG_TASK_SET_FULL)
- sdev_printk(KERN_INFO, sdev, "strange "
- "observation, the queue depth is"
- " (%d) meanwhile fw queue depth "
- "is (%d)\n", sdev->queue_depth,
- current_depth);
- continue;
- }
- depth = scsi_track_queue_full(sdev,
- current_depth - 1);
- if (depth > 0)
- sdev_printk(KERN_INFO, sdev, "Queue depth "
- "reduced to (%d)\n", depth);
- else if (depth < 0)
- sdev_printk(KERN_INFO, sdev, "Tagged Command "
- "Queueing is being disabled\n");
- else if (depth == 0)
- if (ioc->logging_level &
- MPT_DEBUG_TASK_SET_FULL)
- sdev_printk(KERN_INFO, sdev,
- "Queue depth not changed yet\n");
- }
- }
-}
-
-/**
* _scsih_prep_device_scan - initialize parameters prior to device scan
* @ioc: per adapter object
*
@@ -6217,7 +6198,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
sas_expander->responding = 0;
continue;
}
- _scsih_expander_remove(ioc, sas_expander->sas_address);
+ mpt2sas_expander_remove(ioc, sas_expander->sas_address);
goto retry_expander_search;
}
}
@@ -6341,9 +6322,6 @@ _firmware_event_work(struct work_struct *work)
case MPI2_EVENT_IR_OPERATION_STATUS:
_scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
- case MPI2_EVENT_TASK_SET_FULL:
- _scsih_task_set_full(ioc, fw_event);
- break;
}
_scsih_fw_event_free(ioc, fw_event);
}
@@ -6413,7 +6391,6 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_SAS_DISCOVERY:
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_PHYSICAL_DISK:
- case MPI2_EVENT_TASK_SET_FULL:
break;
default: /* ignore the rest */
@@ -6488,56 +6465,23 @@ static void
_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
struct _sas_node *sas_expander)
{
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
- unsigned long flags;
-
- if (!sas_expander)
- return;
+ struct _sas_port *mpt2sas_port, *next;
/* remove sibling ports attached to this expander */
- retry_device_search:
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device =
- mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- continue;
- _scsih_remove_device(ioc, sas_device);
- if (ioc->shost_recovery)
- return;
- goto retry_device_search;
- }
- }
-
- retry_expander_search:
- list_for_each_entry(mpt2sas_port,
+ list_for_each_entry_safe(mpt2sas_port, next,
&sas_expander->sas_port_list, port_list) {
-
+ if (ioc->shost_recovery)
+ return;
if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+ SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
+ else if (mpt2sas_port->remote_identify.device_type ==
+ SAS_EDGE_EXPANDER_DEVICE ||
mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(
- ioc, mpt2sas_port->remote_identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!expander_sibling)
- continue;
- _scsih_expander_remove(ioc,
- expander_sibling->sas_address);
- if (ioc->shost_recovery)
- return;
- goto retry_expander_search;
- }
+ SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
}
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
@@ -6548,7 +6492,6 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
sas_expander->handle, (unsigned long long)
sas_expander->sas_address);
- list_del(&sas_expander->list);
kfree(sas_expander->phy);
kfree(sas_expander);
}
@@ -6666,9 +6609,7 @@ _scsih_remove(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
+ struct _sas_port *mpt2sas_port, *next_port;
struct _raid_device *raid_device, *next;
struct MPT2SAS_TARGET *sas_target_priv_data;
struct workqueue_struct *wq;
@@ -6700,28 +6641,18 @@ _scsih_remove(struct pci_dev *pdev)
}
/* free ports attached to the sas_host */
- retry_again:
- list_for_each_entry(mpt2sas_port,
+ list_for_each_entry_safe(mpt2sas_port, next_port,
&ioc->sas_hba.sas_port_list, port_list) {
if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE) {
- sas_device =
- mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- goto retry_again;
- }
- } else {
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc,
+ mpt2sas_port->remote_identify.sas_address);
+ else if (mpt2sas_port->remote_identify.device_type ==
+ SAS_EDGE_EXPANDER_DEVICE ||
+ mpt2sas_port->remote_identify.device_type ==
+ SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc,
mpt2sas_port->remote_identify.sas_address);
- if (expander_sibling) {
- _scsih_expander_remove(ioc,
- expander_sibling->sas_address);
- goto retry_again;
- }
- }
}
/* free phys attached to the sas_host */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index b55c6dc07470..cb1cdecbe0f8 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -465,62 +465,149 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
return rc;
}
+/**
+ * _transport_delete_port - helper function to removing a port
+ * @ioc: per adapter object
+ * @mpt2sas_port: mpt2sas per port object
+ *
+ * Returns nothing.
+ */
+static void
+_transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_port *mpt2sas_port)
+{
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
+ enum sas_device_type device_type =
+ mpt2sas_port->remote_identify.device_type;
+
+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
+ "remove: sas_addr(0x%016llx)\n",
+ (unsigned long long) sas_address);
+
+ ioc->logging_level |= MPT_DEBUG_TRANSPORT;
+ if (device_type == SAS_END_DEVICE)
+ mpt2sas_device_remove(ioc, sas_address);
+ else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
+ device_type == SAS_FANOUT_EXPANDER_DEVICE)
+ mpt2sas_expander_remove(ioc, sas_address);
+ ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
+}
/**
- * _transport_delete_duplicate_port - (see below description)
+ * _transport_delete_phy - helper function to removing single phy from port
* @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @sas_address: sas address of device being added
- * @phy_num: phy number
+ * @mpt2sas_port: mpt2sas per port object
+ * @mpt2sas_phy: mpt2sas per phy object
*
- * This function is called when attempting to add a new port that is claiming
- * the same phy resources already in use by another port. If we don't release
- * the claimed phy resources, the sas transport layer will hang from the BUG
- * in sas_port_add_phy.
+ * Returns nothing.
+ */
+static void
+_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy)
+{
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
+
+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
+ "remove: sas_addr(0x%016llx), phy(%d)\n",
+ (unsigned long long) sas_address, mpt2sas_phy->phy_id);
+
+ list_del(&mpt2sas_phy->port_siblings);
+ mpt2sas_port->num_phys--;
+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
+ mpt2sas_phy->phy_belongs_to_port = 0;
+}
+
+/**
+ * _transport_add_phy - helper function to adding single phy to port
+ * @ioc: per adapter object
+ * @mpt2sas_port: mpt2sas per port object
+ * @mpt2sas_phy: mpt2sas per phy object
*
- * The reason we would hit this issue is becuase someone is changing the
- * sas address of a device on the fly, meanwhile controller firmware sends
- * EVENTs out of order when removing the previous instance of the device.
+ * Returns nothing.
*/
static void
-_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_node, u64 sas_address, int phy_num)
+_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port,
+ struct _sas_phy *mpt2sas_phy)
{
- struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate;
- struct _sas_phy *mpt2sas_phy;
+ u64 sas_address = mpt2sas_port->remote_identify.sas_address;
- printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), "
- "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address,
- phy_num);
+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
+ "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)
+ sas_address, mpt2sas_phy->phy_id);
- mpt2sas_port_duplicate = NULL;
- list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) {
- dev_printk(KERN_ERR, &mpt2sas_port->port->dev,
- "existing device at sas_addr(0x%016llx), num_phys(%d)\n",
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_port->num_phys);
- list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
+ list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list);
+ mpt2sas_port->num_phys++;
+ sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy);
+ mpt2sas_phy->phy_belongs_to_port = 1;
+}
+
+/**
+ * _transport_add_phy_to_an_existing_port - adding new phy to existing port
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @mpt2sas_phy: mpt2sas per phy object
+ * @sas_address: sas address of device/expander were phy needs to be added to
+ *
+ * Returns nothing.
+ */
+static void
+_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
+struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address)
+{
+ struct _sas_port *mpt2sas_port;
+ struct _sas_phy *phy_srch;
+
+ if (mpt2sas_phy->phy_belongs_to_port == 1)
+ return;
+
+ list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list,
+ port_list) {
+ if (mpt2sas_port->remote_identify.sas_address !=
+ sas_address)
+ continue;
+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
port_siblings) {
- dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev,
- "phy_number(%d)\n", mpt2sas_phy->phy_id);
- if (mpt2sas_phy->phy_id == phy_num)
- mpt2sas_port_duplicate = mpt2sas_port;
+ if (phy_srch == mpt2sas_phy)
+ return;
}
+ _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy);
+ return;
}
- if (!mpt2sas_port_duplicate)
+}
+
+/**
+ * _transport_del_phy_from_an_existing_port - delete phy from existing port
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @mpt2sas_phy: mpt2sas per phy object
+ *
+ * Returns nothing.
+ */
+static void
+_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy)
+{
+ struct _sas_port *mpt2sas_port, *next;
+ struct _sas_phy *phy_srch;
+
+ if (mpt2sas_phy->phy_belongs_to_port == 0)
return;
- dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev,
- "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n",
- (unsigned long long)
- mpt2sas_port_duplicate->remote_identify.sas_address, phy_num);
- ioc->logging_level |= MPT_DEBUG_TRANSPORT;
- mpt2sas_transport_port_remove(ioc,
- mpt2sas_port_duplicate->remote_identify.sas_address,
- sas_node->sas_address);
- ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
+ port_list) {
+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
+ port_siblings) {
+ if (phy_srch != mpt2sas_phy)
+ continue;
+ if (mpt2sas_port->num_phys == 1)
+ _transport_delete_port(ioc, mpt2sas_port);
+ else
+ _transport_delete_phy(ioc, mpt2sas_port,
+ mpt2sas_phy);
+ return;
+ }
+ }
}
/**
@@ -537,11 +624,13 @@ _transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,
{
int i;
- for (i = 0; i < sas_node->num_phys; i++)
- if (sas_node->phy[i].remote_identify.sas_address == sas_address)
- if (sas_node->phy[i].phy_belongs_to_port)
- _transport_delete_duplicate_port(ioc, sas_node,
- sas_address, i);
+ for (i = 0; i < sas_node->num_phys; i++) {
+ if (sas_node->phy[i].remote_identify.sas_address != sas_address)
+ continue;
+ if (sas_node->phy[i].phy_belongs_to_port == 1)
+ _transport_del_phy_from_an_existing_port(ioc, sas_node,
+ &sas_node->phy[i]);
+ }
}
/**
@@ -905,10 +994,12 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
mpt2sas_phy = &sas_node->phy[phy_number];
mpt2sas_phy->attached_handle = handle;
- if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
_transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
- else
+ _transport_add_phy_to_an_existing_port(ioc, sas_node,
+ mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
+ } else
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
sas_identify));
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index d013a2aa2fd5..46cc3825638d 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8029,7 +8029,7 @@ static int ncr53c8xx_slave_configure(struct scsi_device *device)
return 0;
}
-static int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+static int ncr53c8xx_queue_command_lck (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
unsigned long flags;
@@ -8068,6 +8068,8 @@ printk("ncr53c8xx : command successfully queued\n");
return sts;
}
+static DEF_SCSI_QCMD(ncr53c8xx_queue_command)
+
irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 4c1e54545200..6b8b021400f8 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -196,8 +196,7 @@ static void __exit exit_nsp32 (void);
static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);
static int nsp32_detect (struct pci_dev *pdev);
-static int nsp32_queuecommand(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static const char *nsp32_info (struct Scsi_Host *);
static int nsp32_release (struct Scsi_Host *);
@@ -909,7 +908,7 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
return TRUE;
}
-static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
nsp32_target *target;
@@ -1050,6 +1049,8 @@ static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
return 0;
}
+static DEF_SCSI_QCMD(nsp32_queuecommand)
+
/* initialize asic */
static int nsp32hw_init(nsp32_hw_data *data)
{
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index e88bbdde49c5..b37c8a3c1bb0 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -452,10 +452,6 @@ void osd_end_request(struct osd_request *or)
{
struct request *rq = or->request;
- _osd_free_seg(or, &or->set_attr);
- _osd_free_seg(or, &or->enc_get_attr);
- _osd_free_seg(or, &or->get_attr);
-
if (rq) {
if (rq->next_rq) {
_put_request(rq->next_rq);
@@ -464,6 +460,12 @@ void osd_end_request(struct osd_request *or)
_put_request(rq);
}
+
+ _osd_free_seg(or, &or->get_attr);
+ _osd_free_seg(or, &or->enc_get_attr);
+ _osd_free_seg(or, &or->set_attr);
+ _osd_free_seg(or, &or->cdb_cont);
+
_osd_request_free(or);
}
EXPORT_SYMBOL(osd_end_request);
@@ -547,6 +549,12 @@ static int _osd_realloc_seg(struct osd_request *or,
return 0;
}
+static int _alloc_cdb_cont(struct osd_request *or, unsigned total_bytes)
+{
+ OSD_DEBUG("total_bytes=%d\n", total_bytes);
+ return _osd_realloc_seg(or, &or->cdb_cont, total_bytes);
+}
+
static int _alloc_set_attr_list(struct osd_request *or,
const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
{
@@ -885,6 +893,199 @@ int osd_req_read_kern(struct osd_request *or,
}
EXPORT_SYMBOL(osd_req_read_kern);
+static int _add_sg_continuation_descriptor(struct osd_request *or,
+ const struct osd_sg_entry *sglist, unsigned numentries, u64 *len)
+{
+ struct osd_sg_continuation_descriptor *oscd;
+ u32 oscd_size;
+ unsigned i;
+ int ret;
+
+ oscd_size = sizeof(*oscd) + numentries * sizeof(oscd->entries[0]);
+
+ if (!or->cdb_cont.total_bytes) {
+ /* First time, jump over the header, we will write to:
+ * cdb_cont.buff + cdb_cont.total_bytes
+ */
+ or->cdb_cont.total_bytes =
+ sizeof(struct osd_continuation_segment_header);
+ }
+
+ ret = _alloc_cdb_cont(or, or->cdb_cont.total_bytes + oscd_size);
+ if (unlikely(ret))
+ return ret;
+
+ oscd = or->cdb_cont.buff + or->cdb_cont.total_bytes;
+ oscd->hdr.type = cpu_to_be16(SCATTER_GATHER_LIST);
+ oscd->hdr.pad_length = 0;
+ oscd->hdr.length = cpu_to_be32(oscd_size - sizeof(*oscd));
+
+ *len = 0;
+ /* copy the sg entries and convert to network byte order */
+ for (i = 0; i < numentries; i++) {
+ oscd->entries[i].offset = cpu_to_be64(sglist[i].offset);
+ oscd->entries[i].len = cpu_to_be64(sglist[i].len);
+ *len += sglist[i].len;
+ }
+
+ or->cdb_cont.total_bytes += oscd_size;
+ OSD_DEBUG("total_bytes=%d oscd_size=%d numentries=%d\n",
+ or->cdb_cont.total_bytes, oscd_size, numentries);
+ return 0;
+}
+
+static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key)
+{
+ struct request_queue *req_q = osd_request_queue(or->osd_dev);
+ struct bio *bio;
+ struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+ struct osd_continuation_segment_header *cont_seg_hdr;
+
+ if (!or->cdb_cont.total_bytes)
+ return 0;
+
+ cont_seg_hdr = or->cdb_cont.buff;
+ cont_seg_hdr->format = CDB_CONTINUATION_FORMAT_V2;
+ cont_seg_hdr->service_action = cdbh->varlen_cdb.service_action;
+
+ /* create a bio for continuation segment */
+ bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes,
+ GFP_KERNEL);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ bio->bi_rw |= REQ_WRITE;
+
+ /* integrity check the continuation before the bio is linked
+ * with the other data segments since the continuation
+ * integrity is separate from the other data segments.
+ */
+ osd_sec_sign_data(cont_seg_hdr->integrity_check, bio, cap_key);
+
+ cdbh->v2.cdb_continuation_length = cpu_to_be32(or->cdb_cont.total_bytes);
+
+ /* we can't use _req_append_segment, because we need to link in the
+ * continuation bio to the head of the bio list - the
+ * continuation segment (if it exists) is always the first segment in
+ * the out data buffer.
+ */
+ bio->bi_next = or->out.bio;
+ or->out.bio = bio;
+ or->out.total_bytes += or->cdb_cont.total_bytes;
+
+ return 0;
+}
+
+/* osd_req_write_sg: Takes a @bio that points to the data out buffer and an
+ * @sglist that has the scatter gather entries. Scatter-gather enables a write
+ * of multiple none-contiguous areas of an object, in a single call. The extents
+ * may overlap and/or be in any order. The only constrain is that:
+ * total_bytes(sglist) >= total_bytes(bio)
+ */
+int osd_req_write_sg(struct osd_request *or,
+ const struct osd_obj_id *obj, struct bio *bio,
+ const struct osd_sg_entry *sglist, unsigned numentries)
+{
+ u64 len;
+ int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
+
+ if (ret)
+ return ret;
+ osd_req_write(or, obj, 0, bio, len);
+
+ return 0;
+}
+EXPORT_SYMBOL(osd_req_write_sg);
+
+/* osd_req_read_sg: Read multiple extents of an object into @bio
+ * See osd_req_write_sg
+ */
+int osd_req_read_sg(struct osd_request *or,
+ const struct osd_obj_id *obj, struct bio *bio,
+ const struct osd_sg_entry *sglist, unsigned numentries)
+{
+ u64 len;
+ int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
+
+ if (ret)
+ return ret;
+ osd_req_read(or, obj, 0, bio, len);
+
+ return 0;
+}
+EXPORT_SYMBOL(osd_req_read_sg);
+
+/* SG-list write/read Kern API
+ *
+ * osd_req_{write,read}_sg_kern takes an array of @buff pointers and an array
+ * of sg_entries. @numentries indicates how many pointers and sg_entries there
+ * are. By requiring an array of buff pointers. This allows a caller to do a
+ * single write/read and scatter into multiple buffers.
+ * NOTE: Each buffer + len should not cross a page boundary.
+ */
+static struct bio *_create_sg_bios(struct osd_request *or,
+ void **buff, const struct osd_sg_entry *sglist, unsigned numentries)
+{
+ struct request_queue *q = osd_request_queue(or->osd_dev);
+ struct bio *bio;
+ unsigned i;
+
+ bio = bio_kmalloc(GFP_KERNEL, numentries);
+ if (unlikely(!bio)) {
+ OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < numentries; i++) {
+ unsigned offset = offset_in_page(buff[i]);
+ struct page *page = virt_to_page(buff[i]);
+ unsigned len = sglist[i].len;
+ unsigned added_len;
+
+ BUG_ON(offset + len > PAGE_SIZE);
+ added_len = bio_add_pc_page(q, bio, page, len, offset);
+ if (unlikely(len != added_len)) {
+ OSD_DEBUG("bio_add_pc_page len(%d) != added_len(%d)\n",
+ len, added_len);
+ bio_put(bio);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ return bio;
+}
+
+int osd_req_write_sg_kern(struct osd_request *or,
+ const struct osd_obj_id *obj, void **buff,
+ const struct osd_sg_entry *sglist, unsigned numentries)
+{
+ struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ bio->bi_rw |= REQ_WRITE;
+ osd_req_write_sg(or, obj, bio, sglist, numentries);
+
+ return 0;
+}
+EXPORT_SYMBOL(osd_req_write_sg_kern);
+
+int osd_req_read_sg_kern(struct osd_request *or,
+ const struct osd_obj_id *obj, void **buff,
+ const struct osd_sg_entry *sglist, unsigned numentries)
+{
+ struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
+
+ osd_req_read_sg(or, obj, bio, sglist, numentries);
+
+ return 0;
+}
+EXPORT_SYMBOL(osd_req_read_sg_kern);
+
+
+
void osd_req_get_attributes(struct osd_request *or,
const struct osd_obj_id *obj)
{
@@ -1218,17 +1419,18 @@ int osd_req_add_get_attr_page(struct osd_request *or,
or->get_attr.buff = attar_page;
or->get_attr.total_bytes = max_page_len;
- or->set_attr.buff = set_one_attr->val_ptr;
- or->set_attr.total_bytes = set_one_attr->len;
-
cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
- /* ocdb->attrs_page.get_attr_offset; */
+
+ if (!set_one_attr || !set_one_attr->attr_page)
+ return 0; /* The set is optional */
+
+ or->set_attr.buff = set_one_attr->val_ptr;
+ or->set_attr.total_bytes = set_one_attr->len;
cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
- /* ocdb->attrs_page.set_attr_offset; */
return 0;
}
EXPORT_SYMBOL(osd_req_add_get_attr_page);
@@ -1248,11 +1450,14 @@ static int _osd_req_finalize_attr_page(struct osd_request *or)
if (ret)
return ret;
+ if (or->set_attr.total_bytes == 0)
+ return 0;
+
/* set one value */
cdbh->attrs_page.set_attr_offset =
osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
- ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
+ ret = _req_append_segment(or, out_padding, &or->set_attr, NULL,
&or->out);
return ret;
}
@@ -1276,7 +1481,8 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1,
}
static int _osd_req_finalize_data_integrity(struct osd_request *or,
- bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
+ bool has_in, bool has_out, struct bio *out_data_bio, u64 out_data_bytes,
+ const u8 *cap_key)
{
struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
int ret;
@@ -1307,7 +1513,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
or->out.last_seg = NULL;
/* they are now all chained to request sign them all together */
- osd_sec_sign_data(&or->out_data_integ, or->out.req->bio,
+ osd_sec_sign_data(&or->out_data_integ, out_data_bio,
cap_key);
}
@@ -1403,6 +1609,8 @@ int osd_finalize_request(struct osd_request *or,
{
struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
bool has_in, has_out;
+ /* Save for data_integrity without the cdb_continuation */
+ struct bio *out_data_bio = or->out.bio;
u64 out_data_bytes = or->out.total_bytes;
int ret;
@@ -1418,9 +1626,14 @@ int osd_finalize_request(struct osd_request *or,
osd_set_caps(&or->cdb, cap);
has_in = or->in.bio || or->get_attr.total_bytes;
- has_out = or->out.bio || or->set_attr.total_bytes ||
- or->enc_get_attr.total_bytes;
+ has_out = or->out.bio || or->cdb_cont.total_bytes ||
+ or->set_attr.total_bytes || or->enc_get_attr.total_bytes;
+ ret = _osd_req_finalize_cdb_cont(or, cap_key);
+ if (ret) {
+ OSD_DEBUG("_osd_req_finalize_cdb_cont failed\n");
+ return ret;
+ }
ret = _init_blk_request(or, has_in, has_out);
if (ret) {
OSD_DEBUG("_init_blk_request failed\n");
@@ -1458,7 +1671,8 @@ int osd_finalize_request(struct osd_request *or,
}
ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
- out_data_bytes, cap_key);
+ out_data_bio, out_data_bytes,
+ cap_key);
if (ret)
return ret;
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index 8dc5b1a5f5da..a04281cace2e 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -118,7 +118,7 @@ static int pas16_abort(Scsi_Cmnd *);
static int pas16_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int pas16_detect(struct scsi_host_template *);
-static int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int pas16_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int pas16_bus_reset(Scsi_Cmnd *);
#ifndef CMD_PER_LUN
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 9326c2c14880..be3f33d31a99 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -184,7 +184,7 @@ static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
SCpnt->scsi_done(SCpnt);
}
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
#ifdef NSP_DEBUG
@@ -264,6 +264,8 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
return 0;
}
+static DEF_SCSI_QCMD(nsp_queuecommand)
+
/*
* setup PIO FIFO transfer mode and enable/disable to data out
*/
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index d68c9f267c5e..7fc9a9d0a448 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -299,8 +299,7 @@ static int nsp_proc_info (
off_t offset,
int length,
int inout);
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
- void (* done)(struct scsi_cmnd *SCpnt));
+static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
/* Error handler */
/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 0ae27cb5cd6f..8552296edaa1 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -547,7 +547,7 @@ SYM53C500_info(struct Scsi_Host *SChost)
}
static int
-SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+SYM53C500_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
int i;
int port_base = SCpnt->device->host->io_port;
@@ -583,6 +583,8 @@ SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(SYM53C500_queue)
+
static int
SYM53C500_host_reset(struct scsi_cmnd *SCpnt)
{
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index f8c86b28f03f..b95285f3383f 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -603,7 +603,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
#endif
intx:
- /* intialize the INT-X interrupt */
+ /* initialize the INT-X interrupt */
rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME,
SHOST_TO_SAS_HA(pm8001_ha->shost));
return rc;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 8e38ca8cd101..7f064f9ca828 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -50,7 +50,6 @@
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <scsi/libsas.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 4b8765785aeb..321cf3ae8630 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -62,6 +62,7 @@
static unsigned int pmcraid_debug_log;
static unsigned int pmcraid_disable_aen;
static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST;
+static unsigned int pmcraid_enable_msix;
/*
* Data structures to support multiple adapters by the LLD.
@@ -1594,10 +1595,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
cfg_entry = &ccn_hcam->cfg_entry;
fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
- pmcraid_info
- ("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n",
+ pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \
+ res: %x:%x:%x:%x\n",
pinstance->ccn.hcam->ilid,
pinstance->ccn.hcam->op_code,
+ ((pinstance->ccn.hcam->timestamp1) |
+ ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)),
pinstance->ccn.hcam->notification_type,
pinstance->ccn.hcam->notification_lost,
pinstance->ccn.hcam->flags,
@@ -1850,6 +1853,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd)
* none
*/
static void pmcraid_initiate_reset(struct pmcraid_instance *);
+static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd);
static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
{
@@ -1881,6 +1885,10 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
lock_flags);
return;
}
+ if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) {
+ pinstance->timestamp_error = 1;
+ pmcraid_set_timestamp(cmd);
+ }
} else {
dev_info(&pinstance->pdev->dev,
"Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc);
@@ -2220,12 +2228,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
/* Once either bist or pci reset is done, restore PCI config
* space. If this fails, proceed with hard reset again
*/
- if (pci_restore_state(pinstance->pdev)) {
- pmcraid_info("config-space error resetting again\n");
- pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
- pmcraid_reset_alert(cmd);
- break;
- }
+ pci_restore_state(pinstance->pdev);
/* fail all pending commands */
pmcraid_fail_outstanding_cmds(pinstance);
@@ -3363,7 +3366,7 @@ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
sg_size = buflen;
for (i = 0; i < num_elem; i++) {
- page = alloc_pages(GFP_KERNEL|GFP_DMA, order);
+ page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order);
if (!page) {
for (j = i - 1; j >= 0; j--)
__free_pages(sg_page(&scatterlist[j]), order);
@@ -3471,7 +3474,7 @@ static int pmcraid_copy_sglist(
* SCSI_MLQUEUE_DEVICE_BUSY if device is busy
* SCSI_MLQUEUE_HOST_BUSY if host is busy
*/
-static int pmcraid_queuecommand(
+static int pmcraid_queuecommand_lck(
struct scsi_cmnd *scsi_cmd,
void (*done) (struct scsi_cmnd *)
)
@@ -3577,6 +3580,8 @@ static int pmcraid_queuecommand(
return rc;
}
+static DEF_SCSI_QCMD(pmcraid_queuecommand)
+
/**
* pmcraid_open -char node "open" entry, allowed only users with admin access
*/
@@ -3739,6 +3744,7 @@ static long pmcraid_ioctl_passthrough(
unsigned long request_buffer;
unsigned long request_offset;
unsigned long lock_flags;
+ void *ioasa;
u32 ioasc;
int request_size;
int buffer_size;
@@ -3780,6 +3786,11 @@ static long pmcraid_ioctl_passthrough(
rc = __copy_from_user(buffer,
(struct pmcraid_passthrough_ioctl_buffer *) arg,
sizeof(struct pmcraid_passthrough_ioctl_buffer));
+
+ ioasa =
+ (void *)(arg +
+ offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
+
if (rc) {
pmcraid_err("ioctl: can't copy passthrough buffer\n");
rc = -EFAULT;
@@ -3947,22 +3958,14 @@ static long pmcraid_ioctl_passthrough(
}
out_handle_response:
- /* If the command failed for any reason, copy entire IOASA buffer and
- * return IOCTL success. If copying IOASA to user-buffer fails, return
+ /* copy entire IOASA buffer and return IOCTL success.
+ * If copying IOASA to user-buffer fails, return
* EFAULT
*/
- if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) {
- void *ioasa =
- (void *)(arg +
- offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
-
- pmcraid_info("command failed with %x\n",
- le32_to_cpu(cmd->ioa_cb->ioasa.ioasc));
- if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa,
- sizeof(struct pmcraid_ioasa))) {
- pmcraid_err("failed to copy ioasa buffer to user\n");
- rc = -EFAULT;
- }
+ if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa,
+ sizeof(struct pmcraid_ioasa))) {
+ pmcraid_err("failed to copy ioasa buffer to user\n");
+ rc = -EFAULT;
}
/* If the data transfer was from device, copy the data onto user
@@ -4684,7 +4687,8 @@ pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance)
int rc;
struct pci_dev *pdev = pinstance->pdev;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ if ((pmcraid_enable_msix) &&
+ (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) {
int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
int i;
@@ -5147,6 +5151,16 @@ static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
pinstance->inq_data = NULL;
pinstance->inq_data_baddr = 0;
}
+
+ if (pinstance->timestamp_data != NULL) {
+ pci_free_consistent(pinstance->pdev,
+ sizeof(struct pmcraid_timestamp_data),
+ pinstance->timestamp_data,
+ pinstance->timestamp_data_baddr);
+
+ pinstance->timestamp_data = NULL;
+ pinstance->timestamp_data_baddr = 0;
+ }
}
/**
@@ -5205,6 +5219,20 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
return -ENOMEM;
}
+ /* allocate DMAable memory for set timestamp data buffer */
+ pinstance->timestamp_data = pci_alloc_consistent(
+ pinstance->pdev,
+ sizeof(struct pmcraid_timestamp_data),
+ &pinstance->timestamp_data_baddr);
+
+ if (pinstance->timestamp_data == NULL) {
+ pmcraid_err("couldn't allocate DMA memory for \
+ set time_stamp \n");
+ pmcraid_release_buffers(pinstance);
+ return -ENOMEM;
+ }
+
+
/* Initialize all the command blocks and add them to free pool. No
* need to lock (free_pool_lock) as this is done in initialization
* itself
@@ -5610,6 +5638,68 @@ static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd)
}
/**
+ * pmcraid_set_timestamp - set the timestamp to IOAFP
+ *
+ * @cmd: pointer to pmcraid_cmd structure
+ *
+ * Return Value
+ * 0 for success or non-zero for failure cases
+ */
+static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
+ __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN);
+ struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+
+ struct timeval tv;
+ __le64 timestamp;
+
+ do_gettimeofday(&tv);
+ timestamp = tv.tv_sec * 1000;
+
+ pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp);
+ pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8);
+ pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16);
+ pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24);
+ pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32);
+ pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40);
+
+ pmcraid_reinit_cmdblk(cmd);
+ ioarcb->request_type = REQ_TYPE_SCSI;
+ ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
+ ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP;
+ ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION;
+ memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len));
+
+ ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) +
+ offsetof(struct pmcraid_ioarcb,
+ add_data.u.ioadl[0]));
+ ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc));
+ ioarcb->ioarcb_bus_addr &= ~(0x1FULL);
+
+ ioarcb->request_flags0 |= NO_LINK_DESCS;
+ ioarcb->request_flags0 |= TRANSFER_DIR_WRITE;
+ ioarcb->data_transfer_length =
+ cpu_to_le32(sizeof(struct pmcraid_timestamp_data));
+ ioadl = &(ioarcb->add_data.u.ioadl[0]);
+ ioadl->flags = IOADL_FLAGS_LAST_DESC;
+ ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr);
+ ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data));
+
+ if (!pinstance->timestamp_error) {
+ pinstance->timestamp_error = 0;
+ pmcraid_send_cmd(cmd, pmcraid_set_supported_devs,
+ PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+ } else {
+ pmcraid_send_cmd(cmd, pmcraid_return_cmd,
+ PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+ return;
+ }
+}
+
+
+/**
* pmcraid_init_res_table - Initialize the resource table
* @cmd: pointer to pmcraid command struct
*
@@ -5720,7 +5810,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
/* release the resource list lock */
spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags);
- pmcraid_set_supported_devs(cmd);
+ pmcraid_set_timestamp(cmd);
}
/**
@@ -6054,10 +6144,10 @@ out_init:
static void __exit pmcraid_exit(void)
{
pmcraid_netlink_release();
- class_destroy(pmcraid_class);
unregister_chrdev_region(MKDEV(pmcraid_major, 0),
PMCRAID_MAX_ADAPTERS);
pci_unregister_driver(&pmcraid_driver);
+ class_destroy(pmcraid_class);
}
module_init(pmcraid_init);
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 6cfa0145a1d7..4db210d93947 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -42,7 +42,7 @@
*/
#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
#define PMCRAID_DEVFILE "pmcsas"
-#define PMCRAID_DRIVER_VERSION "2.0.2"
+#define PMCRAID_DRIVER_VERSION "1.0.3"
#define PMCRAID_DRIVER_DATE __DATE__
#define PMCRAID_FW_VERSION_1 0x002
@@ -184,6 +184,7 @@
#define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000
#define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000
#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000
+#define PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC 0x06908B00
#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000
/* Driver defined IOASCs */
@@ -332,11 +333,9 @@ struct pmcraid_config_table_entry {
__u8 lun[PMCRAID_LUN_LEN];
} __attribute__((packed, aligned(4)));
-/* extended configuration table sizes are of 64 bytes in size */
-#define PMCRAID_CFGTE_EXT_SIZE 32
+/* extended configuration table sizes are also of 32 bytes in size */
struct pmcraid_config_table_entry_ext {
struct pmcraid_config_table_entry cfgte;
- __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE];
};
/* resource types (config_table_entry.resource_type values) */
@@ -561,6 +560,17 @@ struct pmcraid_inquiry_data {
__u8 reserved3[16];
};
+#define PMCRAID_TIMESTAMP_LEN 12
+#define PMCRAID_REQ_TM_STR_LEN 6
+#define PMCRAID_SCSI_SET_TIMESTAMP 0xA4
+#define PMCRAID_SCSI_SERVICE_ACTION 0x0F
+
+struct pmcraid_timestamp_data {
+ __u8 reserved1[4];
+ __u8 timestamp[PMCRAID_REQ_TM_STR_LEN]; /* current time value */
+ __u8 reserved2[2];
+};
+
/* pmcraid_cmd - LLD representation of SCSI command */
struct pmcraid_cmd {
@@ -568,7 +578,6 @@ struct pmcraid_cmd {
struct pmcraid_control_block *ioa_cb;
dma_addr_t ioa_cb_bus_addr;
dma_addr_t dma_handle;
- u8 *sense_buffer;
/* pointer to mid layer structure of SCSI commands */
struct scsi_cmnd *scsi_cmd;
@@ -705,6 +714,9 @@ struct pmcraid_instance {
struct pmcraid_inquiry_data *inq_data;
dma_addr_t inq_data_baddr;
+ struct pmcraid_timestamp_data *timestamp_data;
+ dma_addr_t timestamp_data_baddr;
+
/* size of configuration table entry, varies based on the firmware */
u32 config_table_entry_size;
@@ -791,6 +803,7 @@ struct pmcraid_instance {
#define SHUTDOWN_NONE 0x0
#define SHUTDOWN_NORMAL 0x1
#define SHUTDOWN_ABBREV 0x2
+ u32 timestamp_error:1; /* indicate set timestamp for out of sync */
};
@@ -1056,10 +1069,10 @@ struct pmcraid_passthrough_ioctl_buffer {
#define PMCRAID_PASSTHROUGH_IOCTL 'F'
#define DRV_IOCTL(n, size) \
- _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size))
+ _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size))
#define FMW_IOCTL(n, size) \
- _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size))
+ _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size))
/*
* _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd.
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 7bc2d796e403..d164c9639361 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -798,7 +798,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
return 0;
}
-static int ppa_queuecommand(struct scsi_cmnd *cmd,
+static int ppa_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *))
{
ppa_struct *dev = ppa_dev(cmd->device->host);
@@ -821,6 +821,8 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(ppa_queuecommand)
+
/*
* Apparently the disk->capacity attribute is off by 1 sector
* for all disk drives. We add the one here, but it should really
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index 92ffbb510498..cd178b9e40cd 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -211,7 +211,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev,
return 0;
}
-static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct ps3rom_private *priv = shost_priv(cmd->device->host);
@@ -260,6 +260,8 @@ static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(ps3rom_queuecommand)
+
static int decode_lv1_status(u64 status, unsigned char *sense_key,
unsigned char *asc, unsigned char *ascq)
{
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index b8166ecfd0e3..5dec684bf010 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -727,7 +727,7 @@ qla1280_info(struct Scsi_Host *host)
* context which is a big NO! NO!.
**************************************************************************/
static int
-qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+qla1280_queuecommand_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
@@ -756,6 +756,8 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
return status;
}
+static DEF_SCSI_QCMD(qla1280_queuecommand)
+
enum action {
ABORT_COMMAND,
DEVICE_RESET,
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 2ff4342ae362..44578b56ad0a 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1309,6 +1309,31 @@ qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+qla2x00_thermal_temp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int rval = QLA_FUNCTION_FAILED;
+ uint16_t temp, frac;
+
+ if (!vha->hw->flags.thermal_supported)
+ return snprintf(buf, PAGE_SIZE, "\n");
+
+ temp = frac = 0;
+ if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+ test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): isp reset in progress.\n",
+ __func__, vha->host_no));
+ else if (!vha->hw->flags.eeh_busy)
+ rval = qla2x00_get_thermal_temp(vha, &temp, &frac);
+ if (rval != QLA_SUCCESS)
+ temp = frac = 0;
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d\n", temp, frac);
+}
+
+static ssize_t
qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1366,6 +1391,7 @@ static DEVICE_ATTR(vn_port_mac_address, S_IRUGO,
qla2x00_vn_port_mac_address_show, NULL);
static DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL);
static DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL);
+static DEVICE_ATTR(thermal_temp, S_IRUGO, qla2x00_thermal_temp_show, NULL);
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1394,6 +1420,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_fabric_param,
&dev_attr_fw_state,
&dev_attr_optrom_gold_fw_version,
+ &dev_attr_thermal_temp,
NULL,
};
@@ -1538,6 +1565,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
if (!fcport)
return;
+ /* Now that the rport has been deleted, set the fcport state to
+ FCS_DEVICE_DEAD */
+ atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+
/*
* Transport has effectively 'deleted' the rport, clear
* all local references.
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index fdfbf83a6330..903b0586ded3 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -103,7 +103,7 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
bsg_job->reply->reply_payload_rcv_len = 0;
- if (!IS_QLA24XX_TYPE(ha) || !IS_QLA25XX(ha)) {
+ if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))) {
ret = -EINVAL;
goto exit_fcp_prio_cfg;
}
@@ -753,7 +753,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
command_sent = INT_DEF_LB_LOOPBACK_CMD;
rval = qla2x00_loopback_test(vha, &elreq, response);
- if (new_config[1]) {
+ if (new_config[0]) {
/* Revert back to original port config
* Also clear internal loopback
*/
@@ -1307,6 +1307,125 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
}
static int
+qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
+ uint8_t is_update)
+{
+ uint32_t start = 0;
+ int valid = 0;
+
+ bsg_job->reply->reply_payload_rcv_len = 0;
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ return -EINVAL;
+
+ start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+ if (start > ha->optrom_size)
+ return -EINVAL;
+
+ if (ha->optrom_state != QLA_SWAITING)
+ return -EBUSY;
+
+ ha->optrom_region_start = start;
+
+ if (is_update) {
+ if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+ valid = 1;
+ else if (start == (ha->flt_region_boot * 4) ||
+ start == (ha->flt_region_fw * 4))
+ valid = 1;
+ else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
+ IS_QLA8XXX_TYPE(ha))
+ valid = 1;
+ if (!valid) {
+ qla_printk(KERN_WARNING, ha,
+ "Invalid start region 0x%x/0x%x.\n",
+ start, bsg_job->request_payload.payload_len);
+ return -EINVAL;
+ }
+
+ ha->optrom_region_size = start +
+ bsg_job->request_payload.payload_len > ha->optrom_size ?
+ ha->optrom_size - start :
+ bsg_job->request_payload.payload_len;
+ ha->optrom_state = QLA_SWRITING;
+ } else {
+ ha->optrom_region_size = start +
+ bsg_job->reply_payload.payload_len > ha->optrom_size ?
+ ha->optrom_size - start :
+ bsg_job->reply_payload.payload_len;
+ ha->optrom_state = QLA_SREADING;
+ }
+
+ ha->optrom_buffer = vmalloc(ha->optrom_region_size);
+ if (!ha->optrom_buffer) {
+ qla_printk(KERN_WARNING, ha,
+ "Read: Unable to allocate memory for optrom retrieval "
+ "(%x).\n", ha->optrom_region_size);
+
+ ha->optrom_state = QLA_SWAITING;
+ return -ENOMEM;
+ }
+
+ memset(ha->optrom_buffer, 0, ha->optrom_region_size);
+ return 0;
+}
+
+static int
+qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = 0;
+
+ rval = qla2x00_optrom_setup(bsg_job, ha, 0);
+ if (rval)
+ return rval;
+
+ ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,
+ ha->optrom_region_size);
+
+ bsg_job->reply->reply_payload_rcv_len = ha->optrom_region_size;
+ bsg_job->reply->result = DID_OK;
+ vfree(ha->optrom_buffer);
+ ha->optrom_buffer = NULL;
+ ha->optrom_state = QLA_SWAITING;
+ bsg_job->job_done(bsg_job);
+ return rval;
+}
+
+static int
+qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = 0;
+
+ rval = qla2x00_optrom_setup(bsg_job, ha, 1);
+ if (rval)
+ return rval;
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
+ ha->optrom_region_size);
+
+ ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
+
+ bsg_job->reply->result = DID_OK;
+ vfree(ha->optrom_buffer);
+ ha->optrom_buffer = NULL;
+ ha->optrom_state = QLA_SWAITING;
+ bsg_job->job_done(bsg_job);
+ return rval;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -1328,6 +1447,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_FCP_PRIO_CFG_CMD:
return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);
+ case QL_VND_READ_FLASH:
+ return qla2x00_read_optrom(bsg_job);
+
+ case QL_VND_UPDATE_FLASH:
+ return qla2x00_update_optrom(bsg_job);
+
default:
bsg_job->reply->result = (DID_ERROR << 16);
bsg_job->job_done(bsg_job);
@@ -1387,6 +1512,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
if (((sp_bsg->type == SRB_CT_CMD) ||
(sp_bsg->type == SRB_ELS_CMD_HST))
&& (sp_bsg->u.bsg_job == bsg_job)) {
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
DEBUG2(qla_printk(KERN_INFO, ha,
"scsi(%ld): mbx "
@@ -1402,6 +1528,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
bsg_job->req->errors =
bsg_job->reply->result = 0;
}
+ spin_lock_irqsave(&ha->hardware_lock, flags);
goto done;
}
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index cc7c52f87a11..074a999c7017 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -14,6 +14,8 @@
#define QL_VND_A84_MGMT_CMD 0x04
#define QL_VND_IIDMA 0x05
#define QL_VND_FCP_PRIO_CFG_CMD 0x06
+#define QL_VND_READ_FLASH 0x07
+#define QL_VND_UPDATE_FLASH 0x08
/* BSG definations for interpreting CommandSent field */
#define INT_DEF_LB_LOOPBACK_CMD 0
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e1d3ad40a946..ccfc8e78be21 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1700,9 +1700,7 @@ typedef struct fc_port {
atomic_t state;
uint32_t flags;
- int port_login_retry_count;
int login_retry;
- atomic_t port_down_timer;
struct fc_rport *rport, *drport;
u32 supported_classes;
@@ -2411,7 +2409,6 @@ struct qla_hw_data {
uint32_t enable_target_reset :1;
uint32_t enable_lip_full_login :1;
uint32_t enable_led_scheme :1;
- uint32_t inta_enabled :1;
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
@@ -2428,6 +2425,9 @@ struct qla_hw_data {
uint32_t disable_msix_handshake :1;
uint32_t fcp_prio_enabled :1;
uint32_t fw_hung :1;
+ uint32_t quiesce_owner:1;
+ uint32_t thermal_supported:1;
+ /* 26 bits */
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2866,6 +2866,7 @@ typedef struct scsi_qla_host {
#define ISP_UNRECOVERABLE 17
#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
+#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index c33dec827e1e..89e900adb679 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -36,6 +36,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
+extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
extern int qla2x00_loop_resync(scsi_qla_host_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
@@ -45,12 +46,15 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
+extern void qla82xx_quiescent_state_cleanup(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
+extern int qla2x00_get_thermal_temp(scsi_qla_host_t *, uint16_t *, uint16_t *);
+
extern void qla84xx_put_chip(struct scsi_qla_host *);
extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
@@ -68,6 +72,7 @@ extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *,
extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
struct srb_iocb *);
extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *);
+extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
extern fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -90,8 +95,8 @@ extern int ql2xfwloadbin;
extern int ql2xetsenable;
extern int ql2xshiftctondsd;
extern int ql2xdbwr;
-extern int ql2xdontresethba;
extern int ql2xasynctmfenable;
+extern int ql2xgffidenable;
extern int ql2xenabledif;
extern int ql2xenablehba_err_chk;
extern int ql2xtargetreset;
@@ -548,9 +553,11 @@ extern void qla82xx_rom_unlock(struct qla_hw_data *);
/* ISP 8021 IDC */
extern void qla82xx_clear_drv_active(struct qla_hw_data *);
+extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t);
extern int qla82xx_idc_lock(struct qla_hw_data *);
extern void qla82xx_idc_unlock(struct qla_hw_data *);
extern int qla82xx_device_state_handler(scsi_qla_host_t *);
+extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
size_t, char *);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 3cafbef40737..f948e1a73aec 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -71,7 +71,7 @@ qla2x00_ctx_sp_free(srb_t *sp)
struct srb_iocb *iocb = ctx->u.iocb_cmd;
struct scsi_qla_host *vha = sp->fcport->vha;
- del_timer_sync(&iocb->timer);
+ del_timer(&iocb->timer);
kfree(iocb);
kfree(ctx);
mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
@@ -498,6 +498,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
vha->flags.reset_active = 0;
ha->flags.pci_channel_io_perm_failure = 0;
ha->flags.eeh_busy = 0;
+ ha->flags.thermal_supported = 1;
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
atomic_set(&vha->loop_state, LOOP_DOWN);
vha->device_flags = DFLG_NO_CABLE;
@@ -1344,6 +1345,13 @@ cont_alloc:
qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
"firmware dump!!!\n", dump_size / 1024);
+ if (ha->fce) {
+ dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
+ ha->fce_dma);
+ ha->fce = NULL;
+ ha->fce_dma = 0;
+ }
+
if (ha->eft) {
dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
ha->eft_dma);
@@ -1818,14 +1826,14 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
qla2x00_init_response_q_entries(rsp);
}
- spin_lock_irqsave(&ha->vport_slock, flags);
+ spin_lock(&ha->vport_slock);
/* Clear RSCN queue. */
list_for_each_entry(vp, &ha->vp_list, list) {
vp->rscn_in_ptr = 0;
vp->rscn_out_ptr = 0;
}
- spin_unlock_irqrestore(&ha->vport_slock, flags);
+ spin_unlock(&ha->vport_slock);
ha->isp_ops->config_rings(vha);
@@ -2016,6 +2024,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
&loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
if (rval != QLA_SUCCESS) {
if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
+ IS_QLA8XXX_TYPE(ha) ||
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
__func__, vha->host_no));
@@ -2916,21 +2925,14 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
- struct qla_hw_data *ha = vha->hw;
-
fcport->vha = vha;
fcport->login_retry = 0;
- fcport->port_login_retry_count = ha->port_down_retry_count *
- PORT_RETRY_TIME;
- atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
- PORT_RETRY_TIME);
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
qla2x00_iidma_fcport(vha, fcport);
-
- atomic_set(&fcport->state, FCS_ONLINE);
-
+ qla24xx_update_fcport_fcp_prio(vha, fcport);
qla2x00_reg_remote_port(vha, fcport);
+ atomic_set(&fcport->state, FCS_ONLINE);
}
/*
@@ -3292,8 +3294,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
continue;
/* Bypass ports whose FCP-4 type is not FCP_SCSI */
- if (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
- new_fcport->fc4_type != FC4_TYPE_UNKNOWN)
+ if (ql2xgffidenable &&
+ (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
+ new_fcport->fc4_type != FC4_TYPE_UNKNOWN))
continue;
/* Locate matching device in database. */
@@ -3844,6 +3847,37 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
return (rval);
}
+/*
+* qla2x00_perform_loop_resync
+* Description: This function will set the appropriate flags and call
+* qla2x00_loop_resync. If successful loop will be resynced
+* Arguments : scsi_qla_host_t pointer
+* returm : Success or Failure
+*/
+
+int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
+{
+ int32_t rval = 0;
+
+ if (!test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) {
+ /*Configure the flags so that resync happens properly*/
+ atomic_set(&ha->loop_down_timer, 0);
+ if (!(ha->device_flags & DFLG_NO_CABLE)) {
+ atomic_set(&ha->loop_state, LOOP_UP);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+
+ rval = qla2x00_loop_resync(ha);
+ } else
+ atomic_set(&ha->loop_state, LOOP_DEAD);
+
+ clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
+ }
+
+ return rval;
+}
+
void
qla2x00_update_fcports(scsi_qla_host_t *base_vha)
{
@@ -3857,7 +3891,7 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
list_for_each_entry(vha, &base_vha->hw->vp_list, list) {
atomic_inc(&vha->vref_count);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport && fcport->drport &&
+ if (fcport->drport &&
atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
spin_unlock_irqrestore(&ha->vport_slock, flags);
@@ -3871,11 +3905,43 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
spin_unlock_irqrestore(&ha->vport_slock, flags);
}
+/*
+* qla82xx_quiescent_state_cleanup
+* Description: This function will block the new I/Os
+* Its not aborting any I/Os as context
+* is not destroyed during quiescence
+* Arguments: scsi_qla_host_t
+* return : void
+*/
+void
+qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct scsi_qla_host *vp;
+
+ qla_printk(KERN_INFO, ha,
+ "Performing ISP error recovery - ha= %p.\n", ha);
+
+ atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+ if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ qla2x00_mark_all_devices_lost(vha, 0);
+ list_for_each_entry(vp, &ha->vp_list, list)
+ qla2x00_mark_all_devices_lost(vha, 0);
+ } else {
+ if (!atomic_read(&vha->loop_down_timer))
+ atomic_set(&vha->loop_down_timer,
+ LOOP_DOWN_TIME);
+ }
+ /* Wait for pending cmds to complete */
+ qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST);
+}
+
void
qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
+ struct scsi_qla_host *vp;
unsigned long flags;
vha->flags.online = 0;
@@ -3896,7 +3962,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
qla2x00_mark_all_devices_lost(vha, 0);
spin_lock_irqsave(&ha->vport_slock, flags);
- list_for_each_entry(vp, &base_vha->hw->vp_list, list) {
+ list_for_each_entry(vp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);
@@ -5410,7 +5476,7 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
* the tag (priority) value is returned.
*
* Input:
- * ha = adapter block po
+ * vha = scsi host structure pointer.
* fcport = port structure pointer.
*
* Return:
@@ -5504,7 +5570,7 @@ qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
* Activates fcp priority for the logged in fc port
*
* Input:
- * ha = adapter block pointer.
+ * vha = scsi host structure pointer.
* fcp = port structure pointer.
*
* Return:
@@ -5514,25 +5580,24 @@ qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
* Kernel context.
*/
int
-qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport)
+qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
{
int ret;
uint8_t priority;
uint16_t mb[5];
- if (atomic_read(&fcport->state) == FCS_UNCONFIGURED ||
- fcport->port_type != FCT_TARGET ||
- fcport->loop_id == FC_NO_LOOP_ID)
+ if (fcport->port_type != FCT_TARGET ||
+ fcport->loop_id == FC_NO_LOOP_ID)
return QLA_FUNCTION_FAILED;
- priority = qla24xx_get_fcp_prio(ha, fcport);
- ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb);
+ priority = qla24xx_get_fcp_prio(vha, fcport);
+ ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb);
if (ret == QLA_SUCCESS)
fcport->fcp_prio = priority;
else
DEBUG2(printk(KERN_WARNING
"scsi(%ld): Unable to activate fcp priority, "
- " ret=0x%x\n", ha->host_no, ret));
+ " ret=0x%x\n", vha->host_no, ret));
return ret;
}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 579f02854665..4c1ba6263eb3 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -992,8 +992,8 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
ha = vha->hw;
DEBUG18(printk(KERN_DEBUG
- "%s(%ld): Executing cmd sp %p, pid=%ld, prot_op=%u.\n", __func__,
- vha->host_no, sp, cmd->serial_number, scsi_get_prot_op(sp->cmd)));
+ "%s(%ld): Executing cmd sp %p, prot_op=%u.\n", __func__,
+ vha->host_no, sp, scsi_get_prot_op(sp->cmd)));
cmd_pkt->vp_index = sp->fcport->vp_idx;
@@ -1061,6 +1061,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
fcp_cmnd->additional_cdb_len |= 2;
int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
+ host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun));
memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e0e43d9e7ed1..d17ed9a94a0c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -321,6 +321,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+ struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
uint32_t rscn_entry, host_pid;
uint8_t rscn_queue_index;
unsigned long flags;
@@ -498,6 +499,7 @@ skip_rio:
case MBA_LOOP_DOWN: /* Loop Down Event */
mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
+ mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
"(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
mbx));
@@ -1240,12 +1242,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
case LSC_SCODE_NPORT_USED:
data[0] = MBS_LOOP_ID_USED;
break;
- case LSC_SCODE_CMD_FAILED:
- if ((iop[1] & 0xff) == 0x05) {
- data[0] = MBS_NOT_LOGGED_IN;
- break;
- }
- /* Fall through. */
default:
data[0] = MBS_COMMAND_ERROR;
break;
@@ -1431,9 +1427,8 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
rsp->status_srb = sp;
DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
- "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
- cp->device->channel, cp->device->id, cp->device->lun, cp,
- cp->serial_number));
+ "cmd=%p\n", __func__, sp->fcport->vha->host_no,
+ cp->device->channel, cp->device->id, cp->device->lun, cp));
if (sense_len)
DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
}
@@ -1757,6 +1752,8 @@ check_scsi_status:
case CS_INCOMPLETE:
case CS_PORT_UNAVAILABLE:
case CS_TIMEOUT:
+ case CS_RESET:
+
/*
* We are going to have the fc class block the rport
* while we try to recover so instruct the mid layer
@@ -1781,10 +1778,6 @@ check_scsi_status:
qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
break;
- case CS_RESET:
- cp->result = DID_TRANSPORT_DISRUPTED << 16;
- break;
-
case CS_ABORTED:
cp->result = DID_RESET << 16;
break;
@@ -1801,10 +1794,10 @@ out:
if (logit)
DEBUG2(qla_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) "
- "oxid=0x%x ser=0x%lx cdb=%02x%02x%02x len=0x%x "
+ "oxid=0x%x cdb=%02x%02x%02x len=0x%x "
"rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no,
cp->device->id, cp->device->lun, comp_status, scsi_status,
- cp->result, ox_id, cp->serial_number, cp->cmnd[0],
+ cp->result, ox_id, cp->cmnd[0],
cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len,
resid_len, fw_resid_len));
@@ -2500,14 +2493,15 @@ skip_msix:
skip_msi:
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
- IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
+ ha->flags.msi_enabled ? 0 : IRQF_SHARED,
+ QLA2XXX_DRIVER_NAME, rsp);
if (ret) {
qla_printk(KERN_WARNING, ha,
"Failed to reserve interrupt %d already in use.\n",
ha->pdev->irq);
goto fail;
}
- ha->flags.inta_enabled = 1;
+
clear_risc_ints:
/*
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index effd8a1403d9..e473e9fb363c 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4125,7 +4125,7 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
return QLA_FUNCTION_FAILED;
DEBUG11(printk(KERN_INFO
- "%s(%ld): entered.\n", __func__, ha->host_no));
+ "%s(%ld): entered.\n", __func__, vha->host_no));
mcp->mb[0] = MBC_PORT_PARAMS;
mcp->mb[1] = loop_id;
@@ -4160,6 +4160,71 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
}
int
+qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, ha->host_no));
+
+ /* High bits. */
+ mcp->mb[0] = MBC_READ_SFP;
+ mcp->mb[1] = 0x98;
+ mcp->mb[2] = 0;
+ mcp->mb[3] = 0;
+ mcp->mb[6] = 0;
+ mcp->mb[7] = 0;
+ mcp->mb[8] = 1;
+ mcp->mb[9] = 0x01;
+ mcp->mb[10] = BIT_13|BIT_0;
+ mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ ha->flags.thermal_supported = 0;
+ goto fail;
+ }
+ *temp = mcp->mb[1] & 0xFF;
+
+ /* Low bits. */
+ mcp->mb[0] = MBC_READ_SFP;
+ mcp->mb[1] = 0x98;
+ mcp->mb[2] = 0;
+ mcp->mb[3] = 0;
+ mcp->mb[6] = 0;
+ mcp->mb[7] = 0;
+ mcp->mb[8] = 1;
+ mcp->mb[9] = 0x10;
+ mcp->mb[10] = BIT_13|BIT_0;
+ mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ ha->flags.thermal_supported = 0;
+ goto fail;
+ }
+ *frac = ((mcp->mb[1] & 0xFF) >> 6) * 25;
+
+ if (rval == QLA_SUCCESS)
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): done.\n", __func__, ha->host_no));
+fail:
+ return rval;
+}
+
+int
qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
{
int rval;
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 8d9edfb39803..fdb96a3584a5 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1079,11 +1079,55 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
/* Halt all the indiviual PEGs and other blocks of the ISP */
qla82xx_rom_lock(ha);
+
+ /* mask all niu interrupts */
+ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
+ /* disable xge rx/tx */
+ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
+ /* disable xg1 rx/tx */
+ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
+
+ /* halt sre */
+ val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
+ qla82xx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));
+
+ /* halt epg */
+ qla82xx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);
+
+ /* halt timers */
+ qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
+ qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
+ qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
+ qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
+ qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
+
+ /* halt pegs */
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
+
+ /* big hammer */
+ msleep(1000);
if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
/* don't reset CAM block on reset */
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
else
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+
+ /* reset ms */
+ val = qla82xx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val |= (1 << 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+ msleep(20);
+
+ /* unreset ms */
+ val = qla82xx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val &= ~(1 << 1);
+ qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+ msleep(20);
+
qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
/* Read the signature value from the flash.
@@ -1210,25 +1254,6 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
}
static int
-qla82xx_check_for_bad_spd(struct qla_hw_data *ha)
-{
- u32 val = 0;
- val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS);
- val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
- if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
- qla_printk(KERN_INFO, ha,
- "Memory DIMM SPD not programmed. "
- " Assumed valid.\n");
- return 1;
- } else if (val) {
- qla_printk(KERN_INFO, ha,
- "Memory DIMM type incorrect.Info:%08X.\n", val);
- return 2;
- }
- return 0;
-}
-
-static int
qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
u64 off, void *data, int size)
{
@@ -1293,11 +1318,6 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
word[startword+1] |= tmpw >> (sz[0] * 8);
}
- /*
- * don't lock here - write_wx gets the lock if each time
- * write_lock_irqsave(&adapter->adapter_lock, flags);
- * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
- */
for (i = 0; i < loop; i++) {
temp = off8 + (i << shift_amount);
qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
@@ -1399,12 +1419,6 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
off0[1] = 0;
sz[1] = size - sz[0];
- /*
- * don't lock here - write_wx gets the lock if each time
- * write_lock_irqsave(&adapter->adapter_lock, flags);
- * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
- */
-
for (i = 0; i < loop; i++) {
temp = off8 + (i << shift_amount);
qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
@@ -1437,11 +1451,6 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
}
}
- /*
- * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- * write_unlock_irqrestore(&adapter->adapter_lock, flags);
- */
-
if (j >= MAX_CTL_CHECK)
return -1;
@@ -1872,7 +1881,6 @@ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
qla_printk(KERN_INFO, ha,
"Cmd Peg initialization failed: 0x%x.\n", val);
- qla82xx_check_for_bad_spd(ha);
val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
read_lock(&ha->hw_lock);
qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
@@ -2343,6 +2351,17 @@ qla82xx_set_qsnt_ready(struct qla_hw_data *ha)
qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
}
+void
+qla82xx_clear_qsnt_ready(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t qsnt_state;
+
+ qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
+ qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
+}
+
static int
qla82xx_load_fw(scsi_qla_host_t *vha)
{
@@ -2542,7 +2561,7 @@ qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- cur_seg++;
+ cur_seg = sg_next(cur_seg);
avail_dsds--;
}
}
@@ -2749,6 +2768,7 @@ sufficient_dsds:
goto queuing_error_fcp_cmnd;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+ host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
/* build FCP_CMND IU */
memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
@@ -3260,6 +3280,104 @@ dev_ready:
return QLA_SUCCESS;
}
+/*
+* qla82xx_need_qsnt_handler
+* Code to start quiescence sequence
+*
+* Note:
+* IDC lock must be held upon entry
+*
+* Return: void
+*/
+
+static void
+qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t dev_state, drv_state, drv_active;
+ unsigned long reset_timeout;
+
+ if (vha->flags.online) {
+ /*Block any further I/O and wait for pending cmnds to complete*/
+ qla82xx_quiescent_state_cleanup(vha);
+ }
+
+ /* Set the quiescence ready bit */
+ qla82xx_set_qsnt_ready(ha);
+
+ /*wait for 30 secs for other functions to ack */
+ reset_timeout = jiffies + (30 * HZ);
+
+ drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+ /* Its 2 that is written when qsnt is acked, moving one bit */
+ drv_active = drv_active << 0x01;
+
+ while (drv_state != drv_active) {
+
+ if (time_after_eq(jiffies, reset_timeout)) {
+ /* quiescence timeout, other functions didn't ack
+ * changing the state to DEV_READY
+ */
+ qla_printk(KERN_INFO, ha,
+ "%s: QUIESCENT TIMEOUT\n", QLA2XXX_DRIVER_NAME);
+ qla_printk(KERN_INFO, ha,
+ "DRV_ACTIVE:%d DRV_STATE:%d\n", drv_active,
+ drv_state);
+ qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_READY);
+ qla_printk(KERN_INFO, ha,
+ "HW State: DEV_READY\n");
+ qla82xx_idc_unlock(ha);
+ qla2x00_perform_loop_resync(vha);
+ qla82xx_idc_lock(ha);
+
+ qla82xx_clear_qsnt_ready(vha);
+ return;
+ }
+
+ qla82xx_idc_unlock(ha);
+ msleep(1000);
+ qla82xx_idc_lock(ha);
+
+ drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+ drv_active = drv_active << 0x01;
+ }
+ dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ /* everyone acked so set the state to DEV_QUIESCENCE */
+ if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
+ qla_printk(KERN_INFO, ha, "HW State: DEV_QUIESCENT\n");
+ qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
+ }
+}
+
+/*
+* qla82xx_wait_for_state_change
+* Wait for device state to change from given current state
+*
+* Note:
+* IDC lock must not be held upon entry
+*
+* Return:
+* Changed device state.
+*/
+uint32_t
+qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t dev_state;
+
+ do {
+ msleep(1000);
+ qla82xx_idc_lock(ha);
+ dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ qla82xx_idc_unlock(ha);
+ } while (dev_state == curr_state);
+
+ return dev_state;
+}
+
static void
qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
{
@@ -3438,15 +3556,28 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
qla82xx_idc_lock(ha);
break;
case QLA82XX_DEV_NEED_RESET:
- if (!ql2xdontresethba)
- qla82xx_need_reset_handler(vha);
+ qla82xx_need_reset_handler(vha);
break;
case QLA82XX_DEV_NEED_QUIESCENT:
- qla82xx_set_qsnt_ready(ha);
+ qla82xx_need_qsnt_handler(vha);
+ /* Reset timeout value after quiescence handler */
+ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
+ * HZ);
+ break;
case QLA82XX_DEV_QUIESCENT:
+ /* Owner will exit and other will wait for the state
+ * to get changed
+ */
+ if (ha->flags.quiesce_owner)
+ goto exit;
+
qla82xx_idc_unlock(ha);
msleep(1000);
qla82xx_idc_lock(ha);
+
+ /* Reset timeout value after quiescence handler */
+ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
+ * HZ);
break;
case QLA82XX_DEV_FAILED:
qla82xx_dev_failed_handler(vha);
@@ -3489,6 +3620,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
&ha->mbx_cmd_flags))
complete(&ha->mbx_intr_comp);
}
+ } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
+ !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
+ DEBUG(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) %s - detected quiescence needed\n",
+ vha->host_no, __func__));
+ set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
} else {
qla82xx_check_fw_alive(vha);
}
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index 51ec0c5380e8..ed5883f1778a 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -523,8 +523,6 @@
# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000)
# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg))
-#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000
-#define QLA82XX_BOOT_LOADER_MN_ISSUE 0xff00ffff
#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24))
#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8))
#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac))
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 800ea9269752..c194c23ca1fb 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -37,12 +37,12 @@ static struct kmem_cache *srb_cachep;
static struct kmem_cache *ctx_cachep;
int ql2xlogintimeout = 20;
-module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
+module_param(ql2xlogintimeout, int, S_IRUGO);
MODULE_PARM_DESC(ql2xlogintimeout,
"Login timeout value in seconds.");
int qlport_down_retry;
-module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
+module_param(qlport_down_retry, int, S_IRUGO);
MODULE_PARM_DESC(qlport_down_retry,
"Maximum number of command retries to a port that returns "
"a PORT-DOWN status.");
@@ -55,12 +55,12 @@ MODULE_PARM_DESC(ql2xplogiabsentdevice,
"Default is 0 - no PLOGI. 1 - perfom PLOGI.");
int ql2xloginretrycount = 0;
-module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
+module_param(ql2xloginretrycount, int, S_IRUGO);
MODULE_PARM_DESC(ql2xloginretrycount,
"Specify an alternate value for the NVRAM login retry count.");
int ql2xallocfwdump = 1;
-module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);
+module_param(ql2xallocfwdump, int, S_IRUGO);
MODULE_PARM_DESC(ql2xallocfwdump,
"Option to enable allocation of memory for a firmware dump "
"during HBA initialization. Memory allocation requirements "
@@ -73,7 +73,7 @@ MODULE_PARM_DESC(ql2xextended_error_logging,
"Default is 0 - no logging. 1 - log errors.");
int ql2xshiftctondsd = 6;
-module_param(ql2xshiftctondsd, int, S_IRUGO|S_IRUSR);
+module_param(ql2xshiftctondsd, int, S_IRUGO);
MODULE_PARM_DESC(ql2xshiftctondsd,
"Set to control shifting of command type processing "
"based on total number of SG elements.");
@@ -81,7 +81,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
static void qla2x00_free_device(scsi_qla_host_t *);
int ql2xfdmienable=1;
-module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
+module_param(ql2xfdmienable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registrations. "
"0 - no FDMI. Default is 1 - perform FDMI.");
@@ -106,27 +106,27 @@ MODULE_PARM_DESC(ql2xenablehba_err_chk,
" Default is 0 - Error isolation disabled, 1 - Enable it");
int ql2xiidmaenable=1;
-module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
+module_param(ql2xiidmaenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xiidmaenable,
"Enables iIDMA settings "
"Default is 1 - perform iIDMA. 0 - no iIDMA.");
int ql2xmaxqueues = 1;
-module_param(ql2xmaxqueues, int, S_IRUGO|S_IRUSR);
+module_param(ql2xmaxqueues, int, S_IRUGO);
MODULE_PARM_DESC(ql2xmaxqueues,
"Enables MQ settings "
"Default is 1 for single queue. Set it to number "
"of queues in MQ mode.");
int ql2xmultique_tag;
-module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR);
+module_param(ql2xmultique_tag, int, S_IRUGO);
MODULE_PARM_DESC(ql2xmultique_tag,
"Enables CPU affinity settings for the driver "
"Default is 0 for no affinity of request and response IO. "
"Set it to 1 to turn on the cpu affinity.");
int ql2xfwloadbin;
-module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
+module_param(ql2xfwloadbin, int, S_IRUGO);
MODULE_PARM_DESC(ql2xfwloadbin,
"Option to specify location from which to load ISP firmware:\n"
" 2 -- load firmware via the request_firmware() (hotplug)\n"
@@ -135,34 +135,32 @@ MODULE_PARM_DESC(ql2xfwloadbin,
" 0 -- use default semantics.\n");
int ql2xetsenable;
-module_param(ql2xetsenable, int, S_IRUGO|S_IRUSR);
+module_param(ql2xetsenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xetsenable,
"Enables firmware ETS burst."
"Default is 0 - skip ETS enablement.");
int ql2xdbwr = 1;
-module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
+module_param(ql2xdbwr, int, S_IRUGO);
MODULE_PARM_DESC(ql2xdbwr,
"Option to specify scheme for request queue posting\n"
" 0 -- Regular doorbell.\n"
" 1 -- CAMRAM doorbell (faster).\n");
-int ql2xdontresethba;
-module_param(ql2xdontresethba, int, S_IRUGO|S_IRUSR);
-MODULE_PARM_DESC(ql2xdontresethba,
- "Option to specify reset behaviour\n"
- " 0 (Default) -- Reset on failure.\n"
- " 1 -- Do not reset on failure.\n");
-
int ql2xtargetreset = 1;
-module_param(ql2xtargetreset, int, S_IRUGO|S_IRUSR);
+module_param(ql2xtargetreset, int, S_IRUGO);
MODULE_PARM_DESC(ql2xtargetreset,
"Enable target reset."
"Default is 1 - use hw defaults.");
+int ql2xgffidenable;
+module_param(ql2xgffidenable, int, S_IRUGO);
+MODULE_PARM_DESC(ql2xgffidenable,
+ "Enables GFF_ID checks of port type. "
+ "Default is 0 - Do not use GFF_ID information.");
int ql2xasynctmfenable;
-module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR);
+module_param(ql2xasynctmfenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xasynctmfenable,
"Enables issue of TM IOCBs asynchronously via IOCB mechanism"
"Default is 0 - Issue TM IOCBs via mailbox mechanism.");
@@ -174,8 +172,7 @@ static int qla2xxx_slave_alloc(struct scsi_device *);
static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
static void qla2xxx_scan_start(struct Scsi_Host *);
static void qla2xxx_slave_destroy(struct scsi_device *);
-static int qla2xxx_queuecommand(struct scsi_cmnd *cmd,
- void (*fn)(struct scsi_cmnd *));
+static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int qla2xxx_eh_abort(struct scsi_cmnd *);
static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
@@ -255,6 +252,7 @@ static void qla2x00_rst_aen(scsi_qla_host_t *);
static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t,
struct req_que **, struct rsp_que **);
+static void qla2x00_free_fw_dump(struct qla_hw_data *);
static void qla2x00_mem_free(struct qla_hw_data *);
static void qla2x00_sp_free_dma(srb_t *);
@@ -529,7 +527,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
}
static int
-qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -539,6 +537,7 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
srb_t *sp;
int rval;
+ spin_unlock_irq(vha->host->host_lock);
if (ha->flags.eeh_busy) {
if (ha->flags.pci_channel_io_perm_failure)
cmd->result = DID_NO_CONNECT << 16;
@@ -553,10 +552,6 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
goto qc24_fail_command;
}
- /* Close window on fcport/rport state-transitioning. */
- if (fcport->drport)
- goto qc24_target_busy;
-
if (!vha->flags.difdix_supported &&
scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
DEBUG2(qla_printk(KERN_ERR, ha,
@@ -567,15 +562,14 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
}
if (atomic_read(&fcport->state) != FCS_ONLINE) {
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+ atomic_read(&fcport->state) == FCS_DEVICE_LOST ||
+ atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
goto qc24_target_busy;
}
- spin_unlock_irq(vha->host->host_lock);
-
sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done);
if (!sp)
goto qc24_host_busy_lock;
@@ -597,14 +591,18 @@ qc24_host_busy_lock:
return SCSI_MLQUEUE_HOST_BUSY;
qc24_target_busy:
+ spin_lock_irq(vha->host->host_lock);
return SCSI_MLQUEUE_TARGET_BUSY;
qc24_fail_command:
+ spin_lock_irq(vha->host->host_lock);
done(cmd);
return 0;
}
+static DEF_SCSI_QCMD(qla2xxx_queuecommand)
+
/*
* qla2x00_eh_wait_on_command
@@ -824,81 +822,58 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
srb_t *sp;
- int ret, i;
+ int ret = SUCCESS;
unsigned int id, lun;
- unsigned long serial;
unsigned long flags;
int wait = 0;
struct qla_hw_data *ha = vha->hw;
- struct req_que *req = vha->req;
- srb_t *spt;
- int got_ref = 0;
fc_block_scsi_eh(cmd);
if (!CMD_SP(cmd))
return SUCCESS;
- ret = SUCCESS;
-
id = cmd->device->id;
lun = cmd->device->lun;
- serial = cmd->serial_number;
- spt = (srb_t *) CMD_SP(cmd);
- if (!spt)
- return SUCCESS;
- /* Check active list for command command. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
- sp = req->outstanding_cmds[i];
-
- if (sp == NULL)
- continue;
- if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) &&
- !IS_PROT_IO(sp))
- continue;
- if (sp->cmd != cmd)
- continue;
+ sp = (srb_t *) CMD_SP(cmd);
+ if (!sp) {
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return SUCCESS;
+ }
- DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
- " pid=%ld.\n", __func__, vha->host_no, sp, serial));
+ DEBUG2(printk("%s(%ld): aborting sp %p from RISC.",
+ __func__, vha->host_no, sp));
- /* Get a reference to the sp and drop the lock.*/
- sp_get(sp);
- got_ref++;
+ /* Get a reference to the sp and drop the lock.*/
+ sp_get(sp);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (ha->isp_ops->abort_command(sp)) {
- DEBUG2(printk("%s(%ld): abort_command "
- "mbx failed.\n", __func__, vha->host_no));
- ret = FAILED;
- } else {
- DEBUG3(printk("%s(%ld): abort_command "
- "mbx success.\n", __func__, vha->host_no));
- wait = 1;
- }
- spin_lock_irqsave(&ha->hardware_lock, flags);
- break;
- }
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ DEBUG2(printk("%s(%ld): abort_command "
+ "mbx failed.\n", __func__, vha->host_no));
+ ret = FAILED;
+ } else {
+ DEBUG3(printk("%s(%ld): abort_command "
+ "mbx success.\n", __func__, vha->host_no));
+ wait = 1;
+ }
+ qla2x00_sp_compl(ha, sp);
/* Wait for the command to be returned. */
if (wait) {
if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
- "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
- "%x.\n", vha->host_no, id, lun, serial, ret);
+ "scsi(%ld:%d:%d): Abort handler timed out -- %x.\n",
+ vha->host_no, id, lun, ret);
ret = FAILED;
}
}
- if (got_ref)
- qla2x00_sp_compl(ha, sp);
-
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
- vha->host_no, id, lun, wait, serial, ret);
+ "scsi(%ld:%d:%d): Abort command issued -- %d %x.\n",
+ vha->host_no, id, lun, wait, ret);
return ret;
}
@@ -1043,13 +1018,11 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
unsigned int id, lun;
- unsigned long serial;
fc_block_scsi_eh(cmd);
id = cmd->device->id;
lun = cmd->device->lun;
- serial = cmd->serial_number;
if (!fcport)
return ret;
@@ -1104,14 +1077,12 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
struct qla_hw_data *ha = vha->hw;
int ret = FAILED;
unsigned int id, lun;
- unsigned long serial;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
fc_block_scsi_eh(cmd);
id = cmd->device->id;
lun = cmd->device->lun;
- serial = cmd->serial_number;
if (!fcport)
return ret;
@@ -1974,6 +1945,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->bars = bars;
ha->mem_only = mem_only;
spin_lock_init(&ha->hardware_lock);
+ spin_lock_init(&ha->vport_slock);
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
@@ -2085,6 +2057,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_82XX;
+ ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
ha->isp_ops = &qla82xx_isp_ops;
ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
@@ -2342,6 +2315,42 @@ probe_out:
}
static void
+qla2x00_shutdown(struct pci_dev *pdev)
+{
+ scsi_qla_host_t *vha;
+ struct qla_hw_data *ha;
+
+ vha = pci_get_drvdata(pdev);
+ ha = vha->hw;
+
+ /* Turn-off FCE trace */
+ if (ha->flags.fce_enabled) {
+ qla2x00_disable_fce_trace(vha, NULL, NULL);
+ ha->flags.fce_enabled = 0;
+ }
+
+ /* Turn-off EFT trace */
+ if (ha->eft)
+ qla2x00_disable_eft_trace(vha);
+
+ /* Stop currently executing firmware. */
+ qla2x00_try_to_stop_firmware(vha);
+
+ /* Turn adapter off line */
+ vha->flags.online = 0;
+
+ /* turn-off interrupts on the card */
+ if (ha->interrupts_on) {
+ vha->flags.init_done = 0;
+ ha->isp_ops->disable_intrs(ha);
+ }
+
+ qla2x00_free_irqs(vha);
+
+ qla2x00_free_fw_dump(ha);
+}
+
+static void
qla2x00_remove_one(struct pci_dev *pdev)
{
scsi_qla_host_t *base_vha, *vha;
@@ -2355,7 +2364,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
list_for_each_entry(vha, &ha->vp_list, list) {
atomic_inc(&vha->vref_count);
- if (vha && vha->fc_vport) {
+ if (vha->fc_vport) {
spin_unlock_irqrestore(&ha->vport_slock, flags);
fc_vport_terminate(vha->fc_vport);
@@ -2597,12 +2606,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
if (atomic_read(&fcport->state) == FCS_ONLINE) {
+ atomic_set(&fcport->state, FCS_DEVICE_LOST);
if (defer)
qla2x00_schedule_rport_del(vha, fcport, defer);
else if (vha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(vha, fcport, defer);
}
- atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
}
@@ -2830,28 +2839,48 @@ fail:
}
/*
-* qla2x00_mem_free
-* Frees all adapter allocated memory.
+* qla2x00_free_fw_dump
+* Frees fw dump stuff.
*
* Input:
-* ha = adapter block pointer.
+* ha = adapter block pointer.
*/
static void
-qla2x00_mem_free(struct qla_hw_data *ha)
+qla2x00_free_fw_dump(struct qla_hw_data *ha)
{
- if (ha->srb_mempool)
- mempool_destroy(ha->srb_mempool);
-
if (ha->fce)
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
- ha->fce_dma);
+ ha->fce_dma);
if (ha->fw_dump) {
if (ha->eft)
dma_free_coherent(&ha->pdev->dev,
- ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+ ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
vfree(ha->fw_dump);
}
+ ha->fce = NULL;
+ ha->fce_dma = 0;
+ ha->eft = NULL;
+ ha->eft_dma = 0;
+ ha->fw_dump = NULL;
+ ha->fw_dumped = 0;
+ ha->fw_dump_reading = 0;
+}
+
+/*
+* qla2x00_mem_free
+* Frees all adapter allocated memory.
+*
+* Input:
+* ha = adapter block pointer.
+*/
+static void
+qla2x00_mem_free(struct qla_hw_data *ha)
+{
+ qla2x00_free_fw_dump(ha);
+
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
if (ha->dcbx_tlv)
dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
@@ -2925,8 +2954,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->srb_mempool = NULL;
ha->ctx_mempool = NULL;
- ha->eft = NULL;
- ha->eft_dma = 0;
ha->sns_cmd = NULL;
ha->sns_cmd_dma = 0;
ha->ct_sns = NULL;
@@ -2946,10 +2973,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->gid_list = NULL;
ha->gid_list_dma = 0;
-
- ha->fw_dump = NULL;
- ha->fw_dumped = 0;
- ha->fw_dump_reading = 0;
}
struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -3356,6 +3379,21 @@ qla2x00_do_dpc(void *data)
clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
}
+ if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
+ DEBUG(printk(KERN_INFO "scsi(%ld): dpc: sched "
+ "qla2x00_quiesce_needed ha = %p\n",
+ base_vha->host_no, ha));
+ qla82xx_device_state_handler(base_vha);
+ clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
+ if (!ha->flags.quiesce_owner) {
+ qla2x00_perform_loop_resync(base_vha);
+
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_qsnt_ready(base_vha);
+ qla82xx_idc_unlock(ha);
+ }
+ }
+
if (test_and_clear_bit(RESET_MARKER_NEEDED,
&base_vha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
@@ -3547,11 +3585,9 @@ void
qla2x00_timer(scsi_qla_host_t *vha)
{
unsigned long cpu_flags = 0;
- fc_port_t *fcport;
int start_dpc = 0;
int index;
srb_t *sp;
- int t;
uint16_t w;
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
@@ -3561,40 +3597,15 @@ qla2x00_timer(scsi_qla_host_t *vha)
return;
}
- if (IS_QLA82XX(ha))
- qla82xx_watchdog(vha);
-
/* Hardware read to raise pending EEH errors during mailbox waits. */
if (!pci_channel_offline(ha->pdev))
pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
- /*
- * Ports - Port down timer.
- *
- * Whenever, a port is in the LOST state we start decrementing its port
- * down timer every second until it reaches zero. Once it reaches zero
- * the port it marked DEAD.
- */
- t = 0;
- list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
-
- if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
-
- if (atomic_read(&fcport->port_down_timer) == 0)
- continue;
-
- if (atomic_dec_and_test(&fcport->port_down_timer) != 0)
- atomic_set(&fcport->state, FCS_DEVICE_DEAD);
-
- DEBUG(printk("scsi(%ld): fcport-%d - port retry count: "
- "%d remaining\n",
- vha->host_no,
- t, atomic_read(&fcport->port_down_timer)));
- }
- t++;
- } /* End of for fcport */
+ if (IS_QLA82XX(ha)) {
+ if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags))
+ start_dpc++;
+ qla82xx_watchdog(vha);
+ }
/* Loop down handler. */
if (atomic_read(&vha->loop_down_timer) > 0 &&
@@ -4079,6 +4090,7 @@ static struct pci_driver qla2xxx_pci_driver = {
.id_table = qla2xxx_pci_tbl,
.probe = qla2x00_probe_one,
.remove = qla2x00_remove_one,
+ .shutdown = qla2x00_shutdown,
.err_handler = &qla2xxx_err_handler,
};
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 76de9574b385..22070621206c 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -669,6 +669,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
def = 1;
else if (IS_QLA81XX(ha))
def = 2;
+
+ /* Assign FCP prio region since older adapters may not have FLT, or
+ FCP prio region in it's FLT.
+ */
+ ha->flt_region_fcp_prio = ha->flags.port0 ?
+ fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
+
ha->flt_region_flt = flt_addr;
wptr = (uint16_t *)req->ring;
flt = (struct qla_flt_header *)req->ring;
@@ -696,10 +703,6 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
goto no_flash_data;
}
- /* Assign FCP prio region since older FLT's may not have it */
- ha->flt_region_fcp_prio = ha->flags.port0 ?
- fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
-
loc = locations[1];
cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
for ( ; cnt; cnt--, region++) {
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 8edbccb3232d..cf0075a2d0c2 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.04-k0"
+#define QLA2XXX_VERSION "8.03.05-k0"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 4
+#define QLA_DRIVER_PATCH_VER 5
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index cbceb0ebabf7..af62c3cf8752 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -30,3 +30,104 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
printk(KERN_INFO "\n");
}
+void qla4xxx_dump_registers(struct scsi_qla_host *ha)
+{
+ uint8_t i;
+
+ if (is_qla8022(ha)) {
+ for (i = 1; i < MBOX_REG_COUNT; i++)
+ printk(KERN_INFO "mailbox[%d] = 0x%08X\n",
+ i, readl(&ha->qla4_8xxx_reg->mailbox_in[i]));
+ return;
+ }
+
+ for (i = 0; i < MBOX_REG_COUNT; i++) {
+ printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
+ readw(&ha->reg->mailbox[i]));
+ }
+
+ printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_address),
+ readw(&ha->reg->flash_address));
+ printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_data),
+ readw(&ha->reg->flash_data));
+ printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, ctrl_status),
+ readw(&ha->reg->ctrl_status));
+
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
+ readw(&ha->reg->u1.isp4010.nvram));
+ } else if (is_qla4022(ha) | is_qla4032(ha)) {
+ printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4022.intr_mask),
+ readw(&ha->reg->u1.isp4022.intr_mask));
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
+ readw(&ha->reg->u1.isp4022.nvram));
+ printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4022.semaphore),
+ readw(&ha->reg->u1.isp4022.semaphore));
+ }
+ printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, req_q_in),
+ readw(&ha->reg->req_q_in));
+ printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, rsp_q_out),
+ readw(&ha->reg->rsp_q_out));
+
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.ext_hw_conf),
+ readw(&ha->reg->u2.isp4010.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_ctrl),
+ readw(&ha->reg->u2.isp4010.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_status),
+ readw(&ha->reg->u2.isp4010.port_status));
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.req_q_out),
+ readw(&ha->reg->u2.isp4010.req_q_out));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
+ readw(&ha->reg->u2.isp4010.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
+ readw(&ha->reg->u2.isp4010.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", (uint8_t)
+ offsetof(struct isp_reg, u2.isp4010.port_err_status),
+ readw(&ha->reg->u2.isp4010.port_err_status));
+ } else if (is_qla4022(ha) | is_qla4032(ha)) {
+ printk(KERN_INFO "Page 0 Registers:\n");
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", (uint8_t)
+ offsetof(struct isp_reg, u2.isp4022.p0.ext_hw_conf),
+ readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", (uint8_t)
+ offsetof(struct isp_reg, u2.isp4022.p0.port_ctrl),
+ readw(&ha->reg->u2.isp4022.p0.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n", (uint8_t)
+ offsetof(struct isp_reg, u2.isp4022.p0.port_status),
+ readw(&ha->reg->u2.isp4022.p0.port_status));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_out),
+ readw(&ha->reg->u2.isp4022.p0.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
+ readw(&ha->reg->u2.isp4022.p0.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", (uint8_t)
+ offsetof(struct isp_reg, u2.isp4022.p0.port_err_status),
+ readw(&ha->reg->u2.isp4022.p0.port_err_status));
+ printk(KERN_INFO "Page 1 Registers:\n");
+ writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p1.req_q_out),
+ readw(&ha->reg->u2.isp4022.p1.req_q_out));
+ writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ }
+}
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
index d861c3b411c8..abd83602cdda 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.h
+++ b/drivers/scsi/qla4xxx/ql4_dbg.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 9dc0a6616edd..2fc0045b1a52 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/aer.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
@@ -36,24 +37,6 @@
#include "ql4_dbg.h"
#include "ql4_nx.h"
-#if defined(CONFIG_PCIEAER)
-#include <linux/aer.h>
-#else
-/* AER releated */
-static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
-{
- return -EINVAL;
-}
-static inline int pci_disable_pcie_error_reporting(struct pci_dev *dev)
-{
- return -EINVAL;
-}
-static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
-{
- return -EINVAL;
-}
-#endif
-
#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
#endif
@@ -179,6 +162,7 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
#define IOCB_TOV_MARGIN 10
#define RELOGIN_TOV 18
#define ISNS_DEREG_TOV 5
+#define HBA_ONLINE_TOV 30
#define MAX_RESET_HA_RETRIES 2
@@ -191,7 +175,7 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
struct srb {
struct list_head list; /* (8) */
struct scsi_qla_host *ha; /* HA the SP is queued on */
- struct ddb_entry *ddb;
+ struct ddb_entry *ddb;
uint16_t flags; /* (1) Status flags. */
#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
@@ -207,7 +191,6 @@ struct srb {
struct scsi_cmnd *cmd; /* (4) SCSI command block */
dma_addr_t dma_handle; /* (4) for unmap of single transfers */
struct kref srb_ref; /* reference count for this srb */
- uint32_t fw_ddb_index;
uint8_t err_id; /* error id */
#define SRB_ERR_PORT 1 /* Request failed because "port down" */
#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 0336c6db8cb3..c1985792f034 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -416,6 +416,8 @@ struct qla_flt_region {
#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
+#define MBOX_ASTS_TXSCVR_INSERTED 0x8130
+#define MBOX_ASTS_TXSCVR_REMOVED 0x8131
#define ISNS_EVENT_DATA_RECEIVED 0x0000
#define ISNS_EVENT_CONNECTION_OPENED 0x0001
@@ -446,6 +448,7 @@ struct addr_ctrl_blk {
#define FWOPT_SESSION_MODE 0x0040
#define FWOPT_INITIATOR_MODE 0x0020
#define FWOPT_TARGET_MODE 0x0010
+#define FWOPT_ENABLE_CRBDB 0x8000
uint16_t exec_throttle; /* 04-05 */
uint8_t zio_count; /* 06 */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 95a26fb1626c..8fad99b7eef4 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -94,6 +94,7 @@ void qla4xxx_process_response_queue(struct scsi_qla_host *ha);
void qla4xxx_wake_dpc(struct scsi_qla_host *ha);
void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha);
void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha);
+void qla4xxx_dump_registers(struct scsi_qla_host *ha);
void qla4_8xxx_pci_config(struct scsi_qla_host *);
int qla4_8xxx_iospace_config(struct scsi_qla_host *ha);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 4c9be77ee70b..1629c48c35ef 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -1207,8 +1207,8 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
break;
DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot "
- "firmware to complete... ctrl_sts=0x%x\n",
- ha->host_no, __func__, ctrl_status));
+ "firmware to complete... ctrl_sts=0x%x, remaining=%ld\n",
+ ha->host_no, __func__, ctrl_status, max_wait_time));
msleep_interruptible(250);
} while (!time_after_eq(jiffies, max_wait_time));
@@ -1459,6 +1459,12 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
exit_init_online:
set_bit(AF_ONLINE, &ha->flags);
exit_init_hba:
+ if (is_qla8022(ha) && (status == QLA_ERROR)) {
+ /* Since interrupts are registered in start_firmware for
+ * 82xx, release them here if initialize_adapter fails */
+ qla4xxx_free_irqs(ha);
+ }
+
DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
return status;
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
index 9471ac755000..62f90bdec5d5 100644
--- a/drivers/scsi/qla4xxx/ql4_inline.h
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 4ef9ba112ee8..75fcd82a8fca 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -202,19 +202,11 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha)
{
uint32_t dbval = 0;
- unsigned long wtime;
dbval = 0x14 | (ha->func_num << 5);
dbval = dbval | (0 << 8) | (ha->request_in << 16);
- writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
- wmb();
- wtime = jiffies + (2 * HZ);
- while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval &&
- !time_after_eq(jiffies, wtime)) {
- writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
- wmb();
- }
+ qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, ha->request_in);
}
/**
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 2a1ab63f3eb0..6ffbe9727dff 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -72,7 +72,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
{
struct srb *srb = ha->status_srb;
struct scsi_cmnd *cmd;
- uint8_t sense_len;
+ uint16_t sense_len;
if (srb == NULL)
return;
@@ -487,6 +487,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
case MBOX_ASTS_SYSTEM_ERROR:
/* Log Mailbox registers */
ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
+ qla4xxx_dump_registers(ha);
+
if (ql4xdontresethba) {
DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
ha->host_no, __func__));
@@ -552,7 +554,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
/* mbox_sts[2] = Old ACB state
* mbox_sts[3] = new ACB state */
if ((mbox_sts[3] == ACB_STATE_VALID) &&
- (mbox_sts[2] == ACB_STATE_TENTATIVE))
+ ((mbox_sts[2] == ACB_STATE_TENTATIVE) ||
+ (mbox_sts[2] == ACB_STATE_ACQUIRING)))
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
(mbox_sts[2] == ACB_STATE_VALID))
@@ -621,6 +624,18 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
}
break;
+ case MBOX_ASTS_TXSCVR_INSERTED:
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: AEN %04x Transceiver"
+ " inserted\n", ha->host_no, mbox_sts[0]));
+ break;
+
+ case MBOX_ASTS_TXSCVR_REMOVED:
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: AEN %04x Transceiver"
+ " removed\n", ha->host_no, mbox_sts[0]));
+ break;
+
default:
DEBUG2(printk(KERN_WARNING
"scsi%ld: AEN %04x UNKNOWN\n",
@@ -1063,7 +1078,7 @@ try_msi:
ret = pci_enable_msi(ha->pdev);
if (!ret) {
ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler,
- IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ 0, DRIVER_NAME, ha);
if (!ret) {
DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
set_bit(AF_MSI_ENABLED, &ha->flags);
@@ -1081,7 +1096,7 @@ try_msi:
try_intx:
/* Trying INTx */
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
- IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ IRQF_SHARED, DRIVER_NAME, ha);
if (!ret) {
DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n"));
set_bit(AF_INTx_ENABLED, &ha->flags);
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 90021704d8ca..f65626aec7c1 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -81,23 +81,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (is_qla8022(ha)) {
- intr_status = readl(&ha->qla4_8xxx_reg->host_int);
- if (intr_status & ISRX_82XX_RISC_INT) {
- /* Service existing interrupt */
- DEBUG2(printk("scsi%ld: %s: "
- "servicing existing interrupt\n",
- ha->host_no, __func__));
- intr_status = readl(&ha->qla4_8xxx_reg->host_status);
- ha->isp_ops->interrupt_service_routine(ha, intr_status);
- clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
- if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
- test_bit(AF_INTx_ENABLED, &ha->flags))
- qla4_8xxx_wr_32(ha,
- ha->nx_legacy_intr.tgt_mask_reg,
- 0xfbff);
- }
- } else {
+ if (!is_qla8022(ha)) {
intr_status = readl(&ha->reg->ctrl_status);
if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
/* Service existing interrupt */
@@ -299,6 +283,10 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
{
memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
+
+ if (is_qla8022(ha))
+ qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, 0);
+
mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
mbox_cmd[1] = 0;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
@@ -472,6 +460,11 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
init_fw_cb->fw_options |=
__constant_cpu_to_le16(FWOPT_SESSION_MODE |
FWOPT_INITIATOR_MODE);
+
+ if (is_qla8022(ha))
+ init_fw_cb->fw_options |=
+ __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB);
+
init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)
@@ -592,7 +585,7 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
}
ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
- ha->host_no, mbox_cmd[2]);
+ ha->host_no, mbox_sts[2]);
return QLA_SUCCESS;
}
@@ -925,7 +918,7 @@ int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
return status;
mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
- mbox_cmd[1] = srb->fw_ddb_index;
+ mbox_cmd[1] = srb->ddb->fw_ddb_index;
mbox_cmd[2] = index;
/* Immediate Command Enable */
mbox_cmd[5] = 0x01;
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index f0d0fbf88aa2..b4b859b2d47e 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
index 7a8fc66a760d..b3831bd29479 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.h
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 449256f2c5f8..3d5ef2df4134 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2009 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -839,8 +839,11 @@ qla4_8xxx_rom_lock(struct scsi_qla_host *ha)
done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
if (done == 1)
break;
- if (timeout >= qla4_8xxx_rom_lock_timeout)
+ if (timeout >= qla4_8xxx_rom_lock_timeout) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: Failed to acquire rom lock", __func__);
return -1;
+ }
timeout++;
@@ -939,12 +942,55 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
/* Halt all the indiviual PEGs and other blocks of the ISP */
qla4_8xxx_rom_lock(ha);
+
+ /* mask all niu interrupts */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
+ /* disable xge rx/tx */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
+ /* disable xg1 rx/tx */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
+
+ /* halt sre */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));
+
+ /* halt epg */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);
+
+ /* halt timers */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
+
+ /* halt pegs */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
+
+ /* big hammer */
+ msleep(1000);
if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
/* don't reset CAM block on reset */
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
else
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+ /* reset ms */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val |= (1 << 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+
+ msleep(20);
+ /* unreset ms */
+ val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
+ val &= ~(1 << 1);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
+ msleep(20);
+
qla4_8xxx_rom_unlock(ha);
/* Read the signature value from the flash.
@@ -1078,32 +1124,17 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
return 0;
}
-static int qla4_8xxx_check_for_bad_spd(struct scsi_qla_host *ha)
-{
- u32 val = 0;
- val = qla4_8xxx_rd_32(ha, BOOT_LOADER_DIMM_STATUS) ;
- val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
- if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
- printk("Memory DIMM SPD not programmed. Assumed valid.\n");
- return 1;
- } else if (val) {
- printk("Memory DIMM type incorrect. Info:%08X.\n", val);
- return 2;
- }
- return 0;
-}
-
static int
qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
{
- int i;
+ int i, rval = 0;
long size = 0;
long flashaddr, memaddr;
u64 data;
u32 high, low;
flashaddr = memaddr = ha->hw.flt_region_bootload;
- size = (image_start - flashaddr)/8;
+ size = (image_start - flashaddr) / 8;
DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n",
ha->host_no, __func__, flashaddr, image_start));
@@ -1112,14 +1143,18 @@ qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
(qla4_8xxx_rom_fast_read(ha, flashaddr + 4,
(int *)&high))) {
- return -1;
+ rval = -1;
+ goto exit_load_from_flash;
}
data = ((u64)high << 32) | low ;
- qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+ rval = qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+ if (rval)
+ goto exit_load_from_flash;
+
flashaddr += 8;
memaddr += 8;
- if (i%0x1000 == 0)
+ if (i % 0x1000 == 0)
msleep(1);
}
@@ -1131,7 +1166,8 @@ qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
read_unlock(&ha->hw_lock);
- return 0;
+exit_load_from_flash:
+ return rval;
}
static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start)
@@ -1377,8 +1413,6 @@ static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
} while (--retries);
- qla4_8xxx_check_for_bad_spd(ha);
-
if (!retries) {
pegtune_val = qla4_8xxx_rd_32(ha,
QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
@@ -1540,14 +1574,31 @@ qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
ql4_printk(KERN_INFO, ha,
"FW: Attempting to load firmware from flash...\n");
rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw);
- if (rval == QLA_SUCCESS)
- return rval;
- ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash FAILED...\n");
+ if (rval != QLA_SUCCESS) {
+ ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash"
+ " FAILED...\n");
+ return rval;
+ }
return rval;
}
+static void qla4_8xxx_rom_lock_recovery(struct scsi_qla_host *ha)
+{
+ if (qla4_8xxx_rom_lock(ha)) {
+ /* Someone else is holding the lock. */
+ dev_info(&ha->pdev->dev, "Resetting rom_lock\n");
+ }
+
+ /*
+ * Either we got the lock, or someone
+ * else died while holding it.
+ * In either case, unlock.
+ */
+ qla4_8xxx_rom_unlock(ha);
+}
+
/**
* qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw
* @ha: pointer to adapter structure
@@ -1557,11 +1608,12 @@ qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
static int
qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
{
- int rval, i, timeout;
+ int rval = QLA_ERROR;
+ int i, timeout;
uint32_t old_count, count;
+ int need_reset = 0, peg_stuck = 1;
- if (qla4_8xxx_need_reset(ha))
- goto dev_initialize;
+ need_reset = qla4_8xxx_need_reset(ha);
old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
@@ -1570,12 +1622,30 @@ qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
if (timeout) {
qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
QLA82XX_DEV_FAILED);
- return QLA_ERROR;
+ return rval;
}
count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
if (count != old_count)
+ peg_stuck = 0;
+ }
+
+ if (need_reset) {
+ /* We are trying to perform a recovery here. */
+ if (peg_stuck)
+ qla4_8xxx_rom_lock_recovery(ha);
+ goto dev_initialize;
+ } else {
+ /* Start of day for this ha context. */
+ if (peg_stuck) {
+ /* Either we are the first or recovery in progress. */
+ qla4_8xxx_rom_lock_recovery(ha);
+ goto dev_initialize;
+ } else {
+ /* Firmware already running. */
+ rval = QLA_SUCCESS;
goto dev_ready;
+ }
}
dev_initialize:
@@ -1601,7 +1671,7 @@ dev_ready:
ql4_printk(KERN_INFO, ha, "HW State: READY\n");
qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
- return QLA_SUCCESS;
+ return rval;
}
/**
@@ -1764,20 +1834,9 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
int retval;
retval = qla4_8xxx_device_state_handler(ha);
- if (retval == QLA_SUCCESS &&
- !test_bit(AF_INIT_DONE, &ha->flags)) {
+ if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags))
retval = qla4xxx_request_irqs(ha);
- if (retval != QLA_SUCCESS) {
- ql4_printk(KERN_WARNING, ha,
- "Failed to reserve interrupt %d already in use.\n",
- ha->pdev->irq);
- } else {
- set_bit(AF_IRQ_ATTACHED, &ha->flags);
- ha->host->irq = ha->pdev->irq;
- ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
- __func__, ha->pdev->irq);
- }
- }
+
return retval;
}
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index 931ad3f1e918..35376a1c3f1b 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -1,8 +1,8 @@
/*
- * QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2010 QLogic Corporation
*
- * See LICENSE.qla2xxx for copyright and licensing details.
+ * See LICENSE.qla4xxx for copyright and licensing details.
*/
#ifndef __QLA_NX_H
#define __QLA_NX_H
@@ -24,7 +24,6 @@
#define CRB_CMDPEG_STATE QLA82XX_REG(0x50)
#define CRB_RCVPEG_STATE QLA82XX_REG(0x13c)
-#define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54)
#define CRB_DMA_SHIFT QLA82XX_REG(0xcc)
#define QLA82XX_HW_H0_CH_HUB_ADR 0x05
@@ -529,12 +528,12 @@
# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000)
# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg))
-#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000
-#define QLA82XX_BOOT_LOADER_MN_ISSUE 0xff00ffff
#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24))
#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8))
#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac))
#define QLA82XX_PEG_ALIVE_COUNTER (QLA82XX_CAM_RAM(0xb0))
+#define QLA82XX_CAM_RAM_DB1 (QLA82XX_CAM_RAM(0x1b0))
+#define QLA82XX_CAM_RAM_DB2 (QLA82XX_CAM_RAM(0x1b4))
#define HALT_STATUS_UNRECOVERABLE 0x80000000
#define HALT_STATUS_RECOVERABLE 0x40000000
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 370d40ff1529..3fc1d256636f 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -79,8 +79,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
/*
* SCSI host template entry points
*/
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
- void (*done) (struct scsi_cmnd *));
+static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
@@ -167,8 +166,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
"of (%d) secs exhausted, marking device DEAD.\n",
ha->host_no, __func__, ddb_entry->fw_ddb_index,
QL4_SESS_RECOVERY_TMO));
-
- qla4xxx_wake_dpc(ha);
}
}
@@ -466,7 +463,7 @@ void qla4xxx_srb_compl(struct kref *ref)
* completion handling). Unfortunely, it sometimes calls the scheduler
* in interrupt context which is a big NO! NO!.
**/
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
@@ -540,6 +537,8 @@ qc_fail_command:
return 0;
}
+static DEF_SCSI_QCMD(qla4xxx_queuecommand)
+
/**
* qla4xxx_mem_free - frees memory allocated to adapter
* @ha: Pointer to host adapter structure.
@@ -573,10 +572,6 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
if (ha->nx_pcibase)
iounmap(
(struct device_reg_82xx __iomem *)ha->nx_pcibase);
-
- if (ha->nx_db_wr_ptr)
- iounmap(
- (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr);
} else if (ha->reg)
iounmap(ha->reg);
pci_release_regions(ha->pdev);
@@ -692,7 +687,9 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
qla4xxx_wake_dpc(ha);
qla4xxx_mailbox_premature_completion(ha);
}
- }
+ } else
+ ha->seconds_since_last_heartbeat = 0;
+
ha->fw_heartbeat_counter = fw_heartbeat_counter;
}
@@ -709,18 +706,22 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
/* don't poll if reset is going on */
- if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags)) {
+ if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags))) {
if (dev_state == QLA82XX_DEV_NEED_RESET &&
!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
- printk("scsi%ld: %s: HW State: NEED RESET!\n",
- ha->host_no, __func__);
- set_bit(DPC_RESET_HA, &ha->dpc_flags);
- qla4xxx_wake_dpc(ha);
- qla4xxx_mailbox_premature_completion(ha);
+ if (!ql4xdontresethba) {
+ ql4_printk(KERN_INFO, ha, "%s: HW State: "
+ "NEED RESET!\n", __func__);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ qla4xxx_wake_dpc(ha);
+ qla4xxx_mailbox_premature_completion(ha);
+ }
} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
!test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
- printk("scsi%ld: %s: HW State: NEED QUIES!\n",
- ha->host_no, __func__);
+ ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
+ __func__);
set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
qla4xxx_wake_dpc(ha);
} else {
@@ -885,7 +886,13 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
/* Find a command that hasn't completed. */
for (index = 0; index < ha->host->can_queue; index++) {
cmd = scsi_host_find_tag(ha->host, index);
- if (cmd != NULL)
+ /*
+ * We cannot just check if the index is valid,
+ * becase if we are run from the scsi eh, then
+ * the scsi/block layer is going to prevent
+ * the tag from being released.
+ */
+ if (cmd != NULL && CMD_SP(cmd))
break;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -937,11 +944,14 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha)
{
uint32_t max_wait_time;
unsigned long flags = 0;
- int status = QLA_ERROR;
+ int status;
uint32_t ctrl_status;
- qla4xxx_hw_reset(ha);
+ status = qla4xxx_hw_reset(ha);
+ if (status != QLA_SUCCESS)
+ return status;
+ status = QLA_ERROR;
/* Wait until the Network Reset Intr bit is cleared */
max_wait_time = RESET_INTR_TOV;
do {
@@ -1101,7 +1111,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
ha->host_no, __func__));
status = ha->isp_ops->reset_firmware(ha);
if (status == QLA_SUCCESS) {
- qla4xxx_cmd_wait(ha);
+ if (!test_bit(AF_FW_RECOVERY, &ha->flags))
+ qla4xxx_cmd_wait(ha);
ha->isp_ops->disable_intrs(ha);
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
@@ -1118,7 +1129,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
* or if stop_firmware fails for ISP-82xx.
* This is the default case for ISP-4xxx */
if (!is_qla8022(ha) || reset_chip) {
- qla4xxx_cmd_wait(ha);
+ if (!test_bit(AF_FW_RECOVERY, &ha->flags))
+ qla4xxx_cmd_wait(ha);
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -1471,24 +1483,10 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */
db_len = pci_resource_len(pdev, 4);
- /* mapping of doorbell write pointer */
- ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base +
- (ha->pdev->devfn << 12), 4);
- if (!ha->nx_db_wr_ptr) {
- printk(KERN_ERR
- "cannot remap MMIO doorbell-write (%s), aborting\n",
- pci_name(pdev));
- goto iospace_error_exit;
- }
- /* mapping of doorbell read pointer */
- ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) +
- (ha->pdev->devfn * 8);
- if (!ha->nx_db_rd_ptr)
- printk(KERN_ERR
- "cannot remap MMIO doorbell-read (%s), aborting\n",
- pci_name(pdev));
- return 0;
+ ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
+ QLA82XX_CAM_RAM_DB2);
+ return 0;
iospace_error_exit:
return -ENOMEM;
}
@@ -1727,6 +1725,14 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
if (!test_bit(AF_ONLINE, &ha->flags)) {
ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
+ if (is_qla8022(ha) && ql4xdontresethba) {
+ /* Put the device in failed state. */
+ DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_FAILED);
+ qla4_8xxx_idc_unlock(ha);
+ }
ret = -ENODEV;
goto probe_failed;
}
@@ -1960,13 +1966,11 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
{
unsigned long wait_online;
- wait_online = jiffies + (30 * HZ);
+ wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
while (time_before(jiffies, wait_online)) {
if (adapter_up(ha))
return QLA_SUCCESS;
- else if (ha->retry_reset_ha_cnt == 0)
- return QLA_ERROR;
msleep(2000);
}
@@ -2021,6 +2025,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned int id = cmd->device->id;
unsigned int lun = cmd->device->lun;
unsigned long serial = cmd->serial_number;
+ unsigned long flags;
struct srb *srb = NULL;
int ret = SUCCESS;
int wait = 0;
@@ -2029,12 +2034,14 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
"scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
ha->host_no, id, lun, cmd, serial);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
srb = (struct srb *) CMD_SP(cmd);
-
- if (!srb)
+ if (!srb) {
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return SUCCESS;
-
+ }
kref_get(&srb->srb_ref);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
@@ -2267,6 +2274,8 @@ qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
qla4xxx_mailbox_premature_completion(ha);
qla4xxx_free_irqs(ha);
pci_disable_device(pdev);
+ /* Return back all IOs */
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
set_bit(AF_EEH_BUSY, &ha->flags);
@@ -2290,17 +2299,13 @@ qla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
if (!is_aer_supported(ha))
return PCI_ERS_RESULT_NONE;
- if (test_bit(AF_FW_RECOVERY, &ha->flags)) {
- ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: firmware hang -- "
- "mmio_enabled\n", ha->host_no, __func__);
- return PCI_ERS_RESULT_NEED_RESET;
- } else
- return PCI_ERS_RESULT_RECOVERED;
+ return PCI_ERS_RESULT_RECOVERED;
}
-uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
+static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
{
uint32_t rval = QLA_ERROR;
+ uint32_t ret = 0;
int fn;
struct pci_dev *other_pdev = NULL;
@@ -2312,7 +2317,6 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
clear_bit(AF_ONLINE, &ha->flags);
qla4xxx_mark_all_devices_missing(ha);
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
- qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
}
fn = PCI_FUNC(ha->pdev->devfn);
@@ -2375,7 +2379,16 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
/* Clear driver state register */
qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
qla4_8xxx_set_drv_active(ha);
- ha->isp_ops->enable_intrs(ha);
+ ret = qla4xxx_request_irqs(ha);
+ if (ret) {
+ ql4_printk(KERN_WARNING, ha, "Failed to "
+ "reserve interrupt %d already in use.\n",
+ ha->pdev->irq);
+ rval = QLA_ERROR;
+ } else {
+ ha->isp_ops->enable_intrs(ha);
+ rval = QLA_SUCCESS;
+ }
}
qla4_8xxx_idc_unlock(ha);
} else {
@@ -2387,8 +2400,18 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
clear_bit(AF_FW_RECOVERY, &ha->flags);
rval = qla4xxx_initialize_adapter(ha,
PRESERVE_DDB_LIST);
- if (rval == QLA_SUCCESS)
- ha->isp_ops->enable_intrs(ha);
+ if (rval == QLA_SUCCESS) {
+ ret = qla4xxx_request_irqs(ha);
+ if (ret) {
+ ql4_printk(KERN_WARNING, ha, "Failed to"
+ " reserve interrupt %d already in"
+ " use.\n", ha->pdev->irq);
+ rval = QLA_ERROR;
+ } else {
+ ha->isp_ops->enable_intrs(ha);
+ rval = QLA_SUCCESS;
+ }
+ }
qla4_8xxx_idc_lock(ha);
qla4_8xxx_set_drv_active(ha);
qla4_8xxx_idc_unlock(ha);
@@ -2430,12 +2453,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev)
goto exit_slot_reset;
}
- ret = qla4xxx_request_irqs(ha);
- if (ret) {
- ql4_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d"
- " already in use.\n", pdev->irq);
- goto exit_slot_reset;
- }
+ ha->isp_ops->disable_intrs(ha);
if (is_qla8022(ha)) {
if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index a77b973f2cbc..8475b308e01b 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -1,8 +1,8 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2006 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k3"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k5"
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 1ad51552d6b1..c3a9151ca823 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -439,7 +439,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
* Queued command
*/
-int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
+static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *))
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
@@ -459,6 +459,8 @@ int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+DEF_SCSI_QCMD(qlogicfas408_queuecommand)
+
/*
* Return bios parameters
*/
diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h
index 260626427a32..2f6c0a166200 100644
--- a/drivers/scsi/qlogicfas408.h
+++ b/drivers/scsi/qlogicfas408.h
@@ -103,8 +103,7 @@ struct qlogicfas408_priv {
#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
-int qlogicfas408_queuecommand(struct scsi_cmnd * cmd,
- void (*done) (struct scsi_cmnd *));
+int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd);
int qlogicfas408_biosparam(struct scsi_device * disk,
struct block_device *dev,
sector_t capacity, int ip[]);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index f8c561cf751e..664c9572d0c9 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1003,7 +1003,7 @@ static int qlogicpti_slave_configure(struct scsi_device *sdev)
*
* "This code must fly." -davem
*/
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
+static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = Cmnd->device->host;
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
@@ -1052,6 +1052,8 @@ toss_command:
return 1;
}
+static DEF_SCSI_QCMD(qlogicpti_queuecommand)
+
static int qlogicpti_return_status(struct Status_Entry *sts, int id)
{
int host_status = DID_ERROR;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 348fba0a8976..2aeb2e9c4d3b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -634,12 +634,13 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
* Description: a serial number identifies a request for error recovery
* and debugging purposes. Protected by the Host_Lock of host.
*/
-static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
cmd->serial_number = host->cmd_serial_number++;
if (cmd->serial_number == 0)
cmd->serial_number = host->cmd_serial_number++;
}
+EXPORT_SYMBOL(scsi_cmd_get_serial);
/**
* scsi_dispatch_command - Dispatch a command to the low-level driver.
@@ -651,7 +652,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
- unsigned long flags = 0;
unsigned long timeout;
int rtn = 0;
@@ -737,23 +737,15 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
goto out;
}
- spin_lock_irqsave(host->host_lock, flags);
- /*
- * AK: unlikely race here: for some reason the timer could
- * expire before the serial number is set up below.
- *
- * TODO: kill serial or move to blk layer
- */
- scsi_cmd_get_serial(host, cmd);
-
if (unlikely(host->shost_state == SHOST_DEL)) {
cmd->result = (DID_NO_CONNECT << 16);
scsi_done(cmd);
} else {
trace_scsi_dispatch_cmd_start(cmd);
- rtn = host->hostt->queuecommand(cmd, scsi_done);
+ cmd->scsi_done = scsi_done;
+ rtn = host->hostt->queuecommand(host, cmd);
}
- spin_unlock_irqrestore(host->host_lock, flags);
+
if (rtn) {
trace_scsi_dispatch_cmd_error(cmd, rtn);
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2c36bae3bd4b..7b310934efed 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1805,6 +1805,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
devip->sense_buff[5] = (ret >> 8) & 0xff;
devip->sense_buff[6] = ret & 0xff;
}
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
return check_condition_result;
}
@@ -3538,7 +3539,7 @@ static void sdebug_remove_adapter(void)
}
static
-int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
+int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
int len, k;
@@ -3884,6 +3885,8 @@ write:
(delay_override ? 0 : scsi_debug_delay));
}
+static DEF_SCSI_QCMD(scsi_debug_queuecommand)
+
static struct scsi_host_template sdebug_driver_template = {
.proc_info = scsi_debug_proc_info,
.proc_name = sdebug_proc_name,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1de30eb83bb0..45c75649b9e0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -320,19 +320,11 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
"changed. The Linux SCSI layer does not "
"automatically adjust these parameters.\n");
- if (scmd->request->cmd_flags & REQ_HARDBARRIER)
- /*
- * barrier requests should always retry on UA
- * otherwise block will get a spurious error
- */
- return NEEDS_RETRY;
- else
- /*
- * for normal (non barrier) commands, pass the
- * UA upwards for a determination in the
- * completion functions
- */
- return SUCCESS;
+ /*
+ * Pass the UA upwards for a determination in the completion
+ * functions.
+ */
+ return SUCCESS;
/* these three are not supported */
case COPY_ABORTED:
@@ -623,7 +615,7 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
return rtn;
}
-static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
{
if (!scmd->device->host->hostt->eh_abort_handler)
return FAILED;
@@ -631,31 +623,9 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
return scmd->device->host->hostt->eh_abort_handler(scmd);
}
-/**
- * scsi_try_to_abort_cmd - Ask host to abort a running command.
- * @scmd: SCSI cmd to abort from Lower Level.
- *
- * Notes:
- * This function will not return until the user's completion function
- * has been called. there is no timeout on this operation. if the
- * author of the low-level driver wishes this operation to be timed,
- * they can provide this facility themselves. helper functions in
- * scsi_error.c can be supplied to make this easier to do.
- */
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
-{
- /*
- * scsi_done was called just after the command timed out and before
- * we had a chance to process it. (db)
- */
- if (scmd->serial_number == 0)
- return SUCCESS;
- return __scsi_try_to_abort_cmd(scmd);
-}
-
static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
{
- if (__scsi_try_to_abort_cmd(scmd) != SUCCESS)
+ if (scsi_try_to_abort_cmd(scmd) != SUCCESS)
if (scsi_try_bus_device_reset(scmd) != SUCCESS)
if (scsi_try_target_reset(scmd) != SUCCESS)
if (scsi_try_bus_reset(scmd) != SUCCESS)
@@ -781,17 +751,15 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
struct Scsi_Host *shost = sdev->host;
DECLARE_COMPLETION_ONSTACK(done);
unsigned long timeleft;
- unsigned long flags;
struct scsi_eh_save ses;
int rtn;
scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
shost->eh_action = &done;
- spin_lock_irqsave(shost->host_lock, flags);
scsi_log_send(scmd);
- shost->hostt->queuecommand(scmd, scsi_eh_done);
- spin_unlock_irqrestore(shost->host_lock, flags);
+ scmd->scsi_done = scsi_eh_done;
+ shost->hostt->queuecommand(shost, scmd);
timeleft = wait_for_completion_timeout(&done, timeout);
@@ -1156,51 +1124,40 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
struct list_head *work_q,
struct list_head *done_q)
{
- struct scsi_cmnd *scmd, *tgtr_scmd, *next;
- unsigned int id = 0;
- int rtn;
+ LIST_HEAD(tmp_list);
- do {
- tgtr_scmd = NULL;
- list_for_each_entry(scmd, work_q, eh_entry) {
- if (id == scmd_id(scmd)) {
- tgtr_scmd = scmd;
- break;
- }
- }
- if (!tgtr_scmd) {
- /* not one exactly equal; find the next highest */
- list_for_each_entry(scmd, work_q, eh_entry) {
- if (scmd_id(scmd) > id &&
- (!tgtr_scmd ||
- scmd_id(tgtr_scmd) > scmd_id(scmd)))
- tgtr_scmd = scmd;
- }
- }
- if (!tgtr_scmd)
- /* no more commands, that's it */
- break;
+ list_splice_init(work_q, &tmp_list);
+
+ while (!list_empty(&tmp_list)) {
+ struct scsi_cmnd *next, *scmd;
+ int rtn;
+ unsigned int id;
+
+ scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry);
+ id = scmd_id(scmd);
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
"to target %d\n",
current->comm, id));
- rtn = scsi_try_target_reset(tgtr_scmd);
- if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
- list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
- if (id == scmd_id(scmd))
- if (!scsi_device_online(scmd->device) ||
- rtn == FAST_IO_FAIL ||
- !scsi_eh_tur(tgtr_scmd))
- scsi_eh_finish_cmd(scmd,
- done_q);
- }
- } else
+ rtn = scsi_try_target_reset(scmd);
+ if (rtn != SUCCESS && rtn != FAST_IO_FAIL)
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Target reset"
" failed target: "
"%d\n",
current->comm, id));
- id++;
- } while(id != 0);
+ list_for_each_entry_safe(scmd, next, &tmp_list, eh_entry) {
+ if (scmd_id(scmd) != id)
+ continue;
+
+ if ((rtn == SUCCESS || rtn == FAST_IO_FAIL)
+ && (!scsi_device_online(scmd->device) ||
+ rtn == FAST_IO_FAIL || !scsi_eh_tur(scmd)))
+ scsi_eh_finish_cmd(scmd, done_q);
+ else
+ /* push back on work queue for further processing */
+ list_move(&scmd->eh_entry, work_q);
+ }
+ }
return list_empty(work_q);
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 8041fe1ab179..9045c52abd25 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1278,11 +1278,10 @@ static inline int scsi_target_queue_ready(struct Scsi_Host *shost,
}
if (scsi_target_is_busy(starget)) {
- if (list_empty(&sdev->starved_entry)) {
+ if (list_empty(&sdev->starved_entry))
list_add_tail(&sdev->starved_entry,
&shost->starved_list);
- return 0;
- }
+ return 0;
}
/* We're OK to process the command, so we can't be starved */
@@ -1403,11 +1402,6 @@ static void scsi_softirq_done(struct request *rq)
INIT_LIST_HEAD(&cmd->eh_entry);
- /*
- * Set the serial numbers back to zero
- */
- cmd->serial_number = 0;
-
atomic_inc(&cmd->device->iodone_cnt);
if (cmd->result)
atomic_inc(&cmd->device->ioerr_cnt);
@@ -1642,9 +1636,8 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
- /* New queue, no concurrency on queue_flags */
if (!shost->use_clustering)
- queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
+ q->limits.cluster = 0;
/*
* set a reasonable default alignment on word boundaries: the
@@ -1984,8 +1977,7 @@ EXPORT_SYMBOL(scsi_mode_sense);
* in.
*
* Returns zero if unsuccessful or an error if TUR failed. For
- * removable media, a return of NOT_READY or UNIT_ATTENTION is
- * translated to success, with the ->changed flag updated.
+ * removable media, UNIT_ATTENTION sets ->changed flag.
**/
int
scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
@@ -2012,16 +2004,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
} while (scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION && --retries);
- if (!sshdr)
- /* could not allocate sense buffer, so can't process it */
- return result;
-
- if (sdev->removable && scsi_sense_valid(sshdr) &&
- (sshdr->sense_key == UNIT_ATTENTION ||
- sshdr->sense_key == NOT_READY)) {
- sdev->changed = 1;
- result = 0;
- }
if (!sshdr_external)
kfree(sshdr);
return result;
@@ -2438,7 +2420,8 @@ scsi_internal_device_unblock(struct scsi_device *sdev)
sdev->sdev_state = SDEV_RUNNING;
else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
sdev->sdev_state = SDEV_CREATED;
- else
+ else if (sdev->sdev_state != SDEV_CANCEL &&
+ sdev->sdev_state != SDEV_OFFLINE)
return -EINVAL;
spin_lock_irqsave(q->queue_lock, flags);
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index d53e6503c6d5..a2ed201885ae 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(scsi_nl_remove_driver);
/**
- * scsi_netlink_init - Called by SCSI subsystem to intialize
+ * scsi_netlink_init - Called by SCSI subsystem to initialize
* the SCSI transport netlink interface
*
**/
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 20ad59dff730..490ce213204e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -864,13 +864,15 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
error = device_add(&sdev->sdev_gendev);
if (error) {
- printk(KERN_INFO "error 1\n");
+ sdev_printk(KERN_INFO, sdev,
+ "failed to add device: %d\n", error);
return error;
}
device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
if (error) {
- printk(KERN_INFO "error 2\n");
+ sdev_printk(KERN_INFO, sdev,
+ "failed to add class device: %d\n", error);
device_del(&sdev->sdev_gendev);
return error;
}
@@ -964,10 +966,11 @@ static void __scsi_remove_target(struct scsi_target *starget)
list_for_each_entry(sdev, &shost->__devices, siblings) {
if (sdev->channel != starget->channel ||
sdev->id != starget->id ||
- sdev->sdev_state == SDEV_DEL)
+ scsi_device_get(sdev))
continue;
spin_unlock_irqrestore(shost->host_lock, flags);
scsi_remove_device(sdev);
+ scsi_device_put(sdev);
spin_lock_irqsave(shost->host_lock, flags);
goto restart;
}
@@ -992,16 +995,14 @@ static int __remove_child (struct device * dev, void * data)
*/
void scsi_remove_target(struct device *dev)
{
- struct device *rdev;
-
if (scsi_is_target_device(dev)) {
__scsi_remove_target(to_scsi_target(dev));
return;
}
- rdev = get_device(dev);
+ get_device(dev);
device_for_each_child(dev, NULL, __remove_child);
- put_device(rdev);
+ put_device(dev);
}
EXPORT_SYMBOL(scsi_remove_target);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 332387a6bc25..f905ecb5704d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -2200,3 +2200,4 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
MODULE_DESCRIPTION("iSCSI Transport Interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 57d1e3e1bd44..e56730214c05 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -46,7 +46,6 @@
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
#include <linux/async.h>
@@ -259,6 +258,28 @@ sd_show_protection_type(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+sd_show_protection_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+ struct scsi_device *sdp = sdkp->device;
+ unsigned int dif, dix;
+
+ dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
+ dix = scsi_host_dix_capable(sdp->host, sdkp->protection_type);
+
+ if (!dix && scsi_host_dix_capable(sdp->host, SD_DIF_TYPE0_PROTECTION)) {
+ dif = 0;
+ dix = 1;
+ }
+
+ if (!dif && !dix)
+ return snprintf(buf, 20, "none\n");
+
+ return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif);
+}
+
+static ssize_t
sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -285,6 +306,7 @@ static struct device_attribute sd_disk_attrs[] = {
__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
sd_store_manage_start_stop),
__ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL),
+ __ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
__ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
__ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
__ATTR_NULL,
@@ -561,7 +583,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
* quietly refuse to do anything to a changed disc until
* the changed bit has been reset
*/
- /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+ /* printk("SCSI disk has been changed or is not present. Prohibiting further I/O.\n"); */
goto out;
}
@@ -968,30 +990,51 @@ out:
static void set_media_not_present(struct scsi_disk *sdkp)
{
- sdkp->media_present = 0;
- sdkp->capacity = 0;
- sdkp->device->changed = 1;
+ if (sdkp->media_present)
+ sdkp->device->changed = 1;
+
+ if (sdkp->device->removable) {
+ sdkp->media_present = 0;
+ sdkp->capacity = 0;
+ }
+}
+
+static int media_not_present(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
+{
+ if (!scsi_sense_valid(sshdr))
+ return 0;
+
+ /* not invoked for commands that could return deferred errors */
+ switch (sshdr->sense_key) {
+ case UNIT_ATTENTION:
+ case NOT_READY:
+ /* medium not present */
+ if (sshdr->asc == 0x3A) {
+ set_media_not_present(sdkp);
+ return 1;
+ }
+ }
+ return 0;
}
/**
- * sd_media_changed - check if our medium changed
- * @disk: kernel device descriptor
+ * sd_check_events - check media events
+ * @disk: kernel device descriptor
+ * @clearing: disk events currently being cleared
*
- * Returns 0 if not applicable or no change; 1 if change
+ * Returns mask of DISK_EVENT_*.
*
* Note: this function is invoked from the block subsystem.
**/
-static int sd_media_changed(struct gendisk *disk)
+static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
struct scsi_sense_hdr *sshdr = NULL;
int retval;
- SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
-
- if (!sdp->removable)
- return 0;
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n"));
/*
* If the device is offline, don't send any commands - just pretend as
@@ -1001,7 +1044,6 @@ static int sd_media_changed(struct gendisk *disk)
*/
if (!scsi_device_online(sdp)) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
@@ -1022,34 +1064,32 @@ static int sd_media_changed(struct gendisk *disk)
sshdr);
}
- /*
- * Unable to test, unit probably not ready. This usually
- * means there is no disc in the drive. Mark as changed,
- * and we will figure it out later once the drive is
- * available again.
- */
- if (retval || (scsi_sense_valid(sshdr) &&
- /* 0x3a is medium not present */
- sshdr->asc == 0x3a)) {
+ /* failed to execute TUR, assume media not present */
+ if (host_byte(retval)) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
+ if (media_not_present(sdkp, sshdr))
+ goto out;
+
/*
* For removable scsi disk we have to recognise the presence
- * of a disk in the drive. This is kept in the struct scsi_disk
- * struct and tested at open ! Daniel Roche (dan@lectra.fr)
+ * of a disk in the drive.
*/
+ if (!sdkp->media_present)
+ sdp->changed = 1;
sdkp->media_present = 1;
-
- retval = sdp->changed;
- sdp->changed = 0;
out:
- if (retval != sdkp->previous_state)
- sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
- sdkp->previous_state = retval;
+ /*
+ * sdp->changed is set under the following conditions:
+ *
+ * Medium present state has changed in either direction.
+ * Device has indicated UNIT_ATTENTION.
+ */
kfree(sshdr);
+ retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
+ sdp->changed = 0;
return retval;
}
@@ -1142,7 +1182,7 @@ static const struct block_device_operations sd_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
#endif
- .media_changed = sd_media_changed,
+ .check_events = sd_check_events,
.revalidate_disk = sd_revalidate_disk,
.unlock_native_capacity = sd_unlock_native_capacity,
};
@@ -1153,6 +1193,12 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
u64 bad_lba;
int info_valid;
+ /*
+ * resid is optional but mostly filled in. When it's unused,
+ * its value is zero, so we assume the whole buffer transferred
+ */
+ unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
+ unsigned int good_bytes;
if (scmd->request->cmd_type != REQ_TYPE_FS)
return 0;
@@ -1186,7 +1232,8 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
/* This computation should always be done in terms of
* the resolution of the device's medium.
*/
- return (bad_lba - start_lba) * scmd->device->sector_size;
+ good_bytes = (bad_lba - start_lba) * scmd->device->sector_size;
+ return min(good_bytes, transferred);
}
/**
@@ -1278,23 +1325,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
return good_bytes;
}
-static int media_not_present(struct scsi_disk *sdkp,
- struct scsi_sense_hdr *sshdr)
-{
-
- if (!scsi_sense_valid(sshdr))
- return 0;
- /* not invoked for commands that could return deferred errors */
- if (sshdr->sense_key != NOT_READY &&
- sshdr->sense_key != UNIT_ATTENTION)
- return 0;
- if (sshdr->asc != 0x3A) /* medium not present */
- return 0;
-
- set_media_not_present(sdkp);
- return 1;
-}
-
/*
* spinup disk - called only in sd_revalidate_disk()
*/
@@ -1469,7 +1499,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
*/
if (sdp->removable &&
sense_valid && sshdr->sense_key == NOT_READY)
- sdp->changed = 1;
+ set_media_not_present(sdkp);
/*
* We used to set media_present to 0 here to indicate no media
@@ -1880,10 +1910,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
int old_rcd = sdkp->RCD;
int old_dpofua = sdkp->DPOFUA;
- if (sdp->skip_ms_page_8)
- goto defaults;
-
- if (sdp->type == TYPE_RBC) {
+ if (sdp->skip_ms_page_8) {
+ if (sdp->type == TYPE_RBC)
+ goto defaults;
+ else {
+ modepage = 0x3F;
+ dbd = 0;
+ }
+ } else if (sdp->type == TYPE_RBC) {
modepage = 6;
dbd = 8;
} else {
@@ -1911,13 +1945,11 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
*/
if (len < 3)
goto bad_sense;
- if (len > 20)
- len = 20;
-
- /* Take headers and block descriptors into account */
- len += data.header_length + data.block_descriptor_length;
- if (len > SD_BUF_SIZE)
- goto bad_sense;
+ else if (len > SD_BUF_SIZE) {
+ sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
+ "data from %d to %d bytes\n", len, SD_BUF_SIZE);
+ len = SD_BUF_SIZE;
+ }
/* Get the data */
res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
@@ -1925,16 +1957,45 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
if (scsi_status_is_good(res)) {
int offset = data.header_length + data.block_descriptor_length;
- if (offset >= SD_BUF_SIZE - 2) {
- sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
- goto defaults;
+ while (offset < len) {
+ u8 page_code = buffer[offset] & 0x3F;
+ u8 spf = buffer[offset] & 0x40;
+
+ if (page_code == 8 || page_code == 6) {
+ /* We're interested only in the first 3 bytes.
+ */
+ if (len - offset <= 2) {
+ sd_printk(KERN_ERR, sdkp, "Incomplete "
+ "mode parameter data\n");
+ goto defaults;
+ } else {
+ modepage = page_code;
+ goto Page_found;
+ }
+ } else {
+ /* Go to the next page */
+ if (spf && len - offset > 3)
+ offset += 4 + (buffer[offset+2] << 8) +
+ buffer[offset+3];
+ else if (!spf && len - offset > 1)
+ offset += 2 + buffer[offset+1];
+ else {
+ sd_printk(KERN_ERR, sdkp, "Incomplete "
+ "mode parameter data\n");
+ goto defaults;
+ }
+ }
}
- if ((buffer[offset] & 0x3f) != modepage) {
+ if (modepage == 0x3F) {
+ sd_printk(KERN_ERR, sdkp, "No Caching mode page "
+ "present\n");
+ goto defaults;
+ } else if ((buffer[offset] & 0x3f) != modepage) {
sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
goto defaults;
}
-
+ Page_found:
if (modepage == 8) {
sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);
@@ -2324,8 +2385,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
gd->driverfs_dev = &sdp->sdev_gendev;
gd->flags = GENHD_FL_EXT_DEVT;
- if (sdp->removable)
+ if (sdp->removable) {
gd->flags |= GENHD_FL_REMOVABLE;
+ gd->events |= DISK_EVENT_MEDIA_CHANGE;
+ }
add_disk(gd);
sd_dif_config_host(sdkp);
@@ -2407,7 +2470,6 @@ static int sd_probe(struct device *dev)
sdkp->disk = gd;
sdkp->index = index;
atomic_set(&sdkp->openers, 0);
- sdkp->previous_state = 1;
if (!sdp->request_queue->rq_timeout) {
if (sdp->type != TYPE_MOD)
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 55488faf0815..c9d8f6ca49e2 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -55,7 +55,6 @@ struct scsi_disk {
u8 media_present;
u8 write_prot;
u8 protection_type;/* Data Integrity Field */
- unsigned previous_state : 1;
unsigned ATO : 1; /* state of disk ATO bit */
unsigned WCE : 1; /* state of disk WCE bit */
unsigned RCD : 1; /* state of disk RCD bit, unused */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index d7b383c96d5d..aefadc6a1607 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -104,14 +104,15 @@ static void sr_release(struct cdrom_device_info *);
static void get_sectorsize(struct scsi_cd *);
static void get_capabilities(struct scsi_cd *);
-static int sr_media_change(struct cdrom_device_info *, int);
+static unsigned int sr_check_events(struct cdrom_device_info *cdi,
+ unsigned int clearing, int slot);
static int sr_packet(struct cdrom_device_info *, struct packet_command *);
static struct cdrom_device_ops sr_dops = {
.open = sr_open,
.release = sr_release,
.drive_status = sr_drive_status,
- .media_changed = sr_media_change,
+ .check_events = sr_check_events,
.tray_move = sr_tray_move,
.lock_door = sr_lock_door,
.select_speed = sr_select_speed,
@@ -165,90 +166,92 @@ static void scsi_cd_put(struct scsi_cd *cd)
mutex_unlock(&sr_ref_mutex);
}
-/* identical to scsi_test_unit_ready except that it doesn't
- * eat the NOT_READY returns for removable media */
-int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr)
+static unsigned int sr_get_events(struct scsi_device *sdev)
{
- int retries = MAX_RETRIES;
- int the_result;
- u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+ u8 buf[8];
+ u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION,
+ 1, /* polled */
+ 0, 0, /* reserved */
+ 1 << 4, /* notification class: media */
+ 0, 0, /* reserved */
+ 0, sizeof(buf), /* allocation length */
+ 0, /* control */
+ };
+ struct event_header *eh = (void *)buf;
+ struct media_event_desc *med = (void *)(buf + 4);
+ struct scsi_sense_hdr sshdr;
+ int result;
- /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION
- * conditions are gone, or a timeout happens
- */
- do {
- the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL,
- 0, sshdr, SR_TIMEOUT,
- retries--, NULL);
- if (scsi_sense_valid(sshdr) &&
- sshdr->sense_key == UNIT_ATTENTION)
- sdev->changed = 1;
-
- } while (retries > 0 &&
- (!scsi_status_is_good(the_result) ||
- (scsi_sense_valid(sshdr) &&
- sshdr->sense_key == UNIT_ATTENTION)));
- return the_result;
+ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf),
+ &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL);
+ if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION)
+ return DISK_EVENT_MEDIA_CHANGE;
+
+ if (result || be16_to_cpu(eh->data_len) < sizeof(*med))
+ return 0;
+
+ if (eh->nea || eh->notification_class != 0x4)
+ return 0;
+
+ if (med->media_event_code == 1)
+ return DISK_EVENT_EJECT_REQUEST;
+ else if (med->media_event_code == 2)
+ return DISK_EVENT_MEDIA_CHANGE;
+ return 0;
}
/*
- * This function checks to see if the media has been changed in the
- * CDROM drive. It is possible that we have already sensed a change,
- * or the drive may have sensed one and not yet reported it. We must
- * be ready for either case. This function always reports the current
- * value of the changed bit. If flag is 0, then the changed bit is reset.
- * This function could be done as an ioctl, but we would need to have
- * an inode for that to work, and we do not always have one.
+ * This function checks to see if the media has been changed or eject
+ * button has been pressed. It is possible that we have already
+ * sensed a change, or the drive may have sensed one and not yet
+ * reported it. The past events are accumulated in sdev->changed and
+ * returned together with the current state.
*/
-
-static int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static unsigned int sr_check_events(struct cdrom_device_info *cdi,
+ unsigned int clearing, int slot)
{
struct scsi_cd *cd = cdi->handle;
- int retval;
- struct scsi_sense_hdr *sshdr;
+ bool last_present;
+ struct scsi_sense_hdr sshdr;
+ unsigned int events;
+ int ret;
- if (CDSL_CURRENT != slot) {
- /* no changer support */
- return -EINVAL;
- }
+ /* no changer support */
+ if (CDSL_CURRENT != slot)
+ return 0;
- sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
- retval = sr_test_unit_ready(cd->device, sshdr);
- if (retval || (scsi_sense_valid(sshdr) &&
- /* 0x3a is medium not present */
- sshdr->asc == 0x3a)) {
- /* Media not present or unable to test, unit probably not
- * ready. This usually means there is no disc in the drive.
- * Mark as changed, and we will figure it out later once
- * the drive is available again.
- */
- cd->device->changed = 1;
- /* This will force a flush, if called from check_disk_change */
- retval = 1;
- goto out;
- };
+ events = sr_get_events(cd->device);
+ /*
+ * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE
+ * is being cleared. Note that there are devices which hang
+ * if asked to execute TUR repeatedly.
+ */
+ if (!(clearing & DISK_EVENT_MEDIA_CHANGE))
+ goto skip_tur;
+
+ /* let's see whether the media is there with TUR */
+ last_present = cd->media_present;
+ ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
+
+ /*
+ * Media is considered to be present if TUR succeeds or fails with
+ * sense data indicating something other than media-not-present
+ * (ASC 0x3a).
+ */
+ cd->media_present = scsi_status_is_good(ret) ||
+ (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a);
- retval = cd->device->changed;
- cd->device->changed = 0;
- /* If the disk changed, the capacity will now be different,
- * so we force a re-read of this information */
- if (retval) {
- /* check multisession offset etc */
- sr_cd_check(cdi);
- get_sectorsize(cd);
+ if (last_present != cd->media_present)
+ events |= DISK_EVENT_MEDIA_CHANGE;
+skip_tur:
+ if (cd->device->changed) {
+ events |= DISK_EVENT_MEDIA_CHANGE;
+ cd->device->changed = 0;
}
-out:
- /* Notify userspace, that media has changed. */
- if (retval != cd->previous_state)
- sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
- GFP_KERNEL);
- cd->previous_state = retval;
- kfree(sshdr);
-
- return retval;
+ return events;
}
-
+
/*
* sr_done is the interrupt routine for the device driver.
*
@@ -533,10 +536,25 @@ out:
return ret;
}
-static int sr_block_media_changed(struct gendisk *disk)
+static unsigned int sr_block_check_events(struct gendisk *disk,
+ unsigned int clearing)
{
struct scsi_cd *cd = scsi_cd(disk);
- return cdrom_media_changed(&cd->cdi);
+ return cdrom_check_events(&cd->cdi, clearing);
+}
+
+static int sr_block_revalidate_disk(struct gendisk *disk)
+{
+ struct scsi_cd *cd = scsi_cd(disk);
+ struct scsi_sense_hdr sshdr;
+
+ /* if the unit is not ready, nothing more to do */
+ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
+ return 0;
+
+ sr_cd_check(&cd->cdi);
+ get_sectorsize(cd);
+ return 0;
}
static const struct block_device_operations sr_bdops =
@@ -545,7 +563,8 @@ static const struct block_device_operations sr_bdops =
.open = sr_block_open,
.release = sr_block_release,
.ioctl = sr_block_ioctl,
- .media_changed = sr_block_media_changed,
+ .check_events = sr_block_check_events,
+ .revalidate_disk = sr_block_revalidate_disk,
/*
* No compat_ioctl for now because sr_block_ioctl never
* seems to pass arbitary ioctls down to host drivers.
@@ -618,6 +637,7 @@ static int sr_probe(struct device *dev)
sprintf(disk->disk_name, "sr%d", minor);
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
+ disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
@@ -627,7 +647,7 @@ static int sr_probe(struct device *dev)
cd->disk = disk;
cd->capacity = 0x1fffff;
cd->device->changed = 1; /* force recheck CD type */
- cd->previous_state = 1;
+ cd->media_present = 1;
cd->use = 1;
cd->readcd_known = 0;
cd->readcd_cdda = 0;
@@ -780,7 +800,7 @@ static void get_capabilities(struct scsi_cd *cd)
}
/* eat unit attentions */
- sr_test_unit_ready(cd->device, &sshdr);
+ scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
/* ask for mode page 0x2a */
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index 1e144dfdbd4b..e036f1dc83c8 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -40,7 +40,7 @@ typedef struct scsi_cd {
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
unsigned readcd_cdda:1; /* reading audio data using READ_CD */
- unsigned previous_state:1; /* media has changed */
+ unsigned media_present:1; /* media is present */
struct cdrom_device_info cdi;
/* We hold gendisk and scsi_device references on probe and use
* the refs on this kref to decide when to release them */
@@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed);
int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
int sr_is_xa(Scsi_CD *);
-int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr);
/* sr_vendor.c */
void sr_vendor_init(Scsi_CD *);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index cbb38c5197fa..8be30554119b 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -307,7 +307,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
/* we have no changer support */
return -EINVAL;
}
- if (0 == sr_test_unit_ready(cd->device, &sshdr))
+ if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
return CDS_DISC_OK;
/* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */
@@ -325,6 +325,15 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
}
/*
+ * SK/ASC/ASCQ of 2/4/2 means "initialization required"
+ * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close
+ * the tray, which resolves the initialization requirement.
+ */
+ if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY
+ && sshdr.asc == 0x04 && sshdr.ascq == 0x02)
+ return CDS_TRAY_OPEN;
+
+ /*
* 0x04 is format in progress .. but there must be a disc present!
*/
if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 5b7388f1c835..1871b8ae83ae 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20100829";
+static const char *verstr = "20101219";
#include <linux/module.h>
@@ -3729,9 +3729,11 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
b_size = PAGE_SIZE << order;
} else {
for (b_size = PAGE_SIZE, order = 0;
- order < ST_MAX_ORDER && b_size < new_size;
+ order < ST_MAX_ORDER &&
+ max_segs * (PAGE_SIZE << order) < new_size;
order++, b_size *= 2)
; /* empty */
+ STbuffer->reserved_page_order = order;
}
if (max_segs * (PAGE_SIZE << order) < new_size) {
if (order == ST_MAX_ORDER)
@@ -3758,7 +3760,6 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
segs++;
}
STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
- STbuffer->reserved_page_order = order;
return 1;
}
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 9c73dbda3bbb..606215e54b88 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -572,7 +572,7 @@ stex_slave_destroy(struct scsi_device *sdev)
}
static int
-stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct st_hba *hba;
struct Scsi_Host *host;
@@ -698,6 +698,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(stex_queuecommand)
+
static void stex_scsi_done(struct st_ccb *ccb)
{
struct scsi_cmnd *cmd = ccb->cmd;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 713620ed70d9..4f0e5485ffde 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -908,7 +908,7 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags)
*/
/* Only make static if a wrapper function is used */
-static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
SETUP_HOSTDATA(cmd->device->host);
@@ -1019,6 +1019,8 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
/*
* Function : NCR5380_main (void)
*
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index b29a9d661ca4..bcefd8458e65 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -51,8 +51,7 @@ static int sun3scsi_abort(struct scsi_cmnd *);
static int sun3scsi_detect (struct scsi_host_template *);
static const char *sun3scsi_info (struct Scsi_Host *);
static int sun3scsi_bus_reset(struct scsi_cmnd *);
-static int sun3scsi_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int sun3scsi_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int sun3scsi_release (struct Scsi_Host *);
#ifndef CMD_PER_LUN
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index e5c369bb568f..190107ae120b 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -734,7 +734,7 @@ const char *sym53c416_info(struct Scsi_Host *SChost)
return info;
}
-int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int sym53c416_queuecommand_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
int base;
unsigned long flags = 0;
@@ -761,6 +761,8 @@ int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
return 0;
}
+DEF_SCSI_QCMD(sym53c416_queuecommand)
+
static int sym53c416_host_reset(Scsi_Cmnd *SCpnt)
{
int base;
diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
index 77860d0748ff..387de5d80a70 100644
--- a/drivers/scsi/sym53c416.h
+++ b/drivers/scsi/sym53c416.h
@@ -25,7 +25,7 @@
static int sym53c416_detect(struct scsi_host_template *);
static const char *sym53c416_info(struct Scsi_Host *);
static int sym53c416_release(struct Scsi_Host *);
-static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int sym53c416_host_reset(Scsi_Cmnd *);
static int sym53c416_bios_param(struct scsi_device *, struct block_device *,
sector_t, int *);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 8b955b534a36..b4543f575f46 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -505,7 +505,7 @@ void sym_log_bus_error(struct Scsi_Host *shost)
* queuecommand method. Entered with the host adapter lock held and
* interrupts disabled.
*/
-static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
+static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
@@ -536,6 +536,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(sym53c8xx_queue_command)
+
/*
* Linux entry point of the interrupt handler.
*/
@@ -1864,7 +1866,7 @@ static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev)
*
* This routine is similar to sym_set_workarounds(), except
* that, at this point, we already know that the device was
- * successfully intialized at least once before, and so most
+ * successfully initialized at least once before, and so most
* of the steps taken there are un-needed here.
*/
static void sym2_reset_workarounds(struct pci_dev *pdev)
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 76a069b7ac0b..ada1115079c9 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -96,8 +96,7 @@ static int t128_abort(struct scsi_cmnd *);
static int t128_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int t128_detect(struct scsi_host_template *);
-static int t128_queue_command(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int t128_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
static int t128_bus_reset(struct scsi_cmnd *);
#ifndef CMD_PER_LUN
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 27866b0adfeb..a124a28f2ccb 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -1883,7 +1883,7 @@ dc390_ScsiRstDetect( struct dc390_acb* pACB )
return;
}
-static int DC390_queuecommand(struct scsi_cmnd *cmd,
+static int DC390_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmd->device;
@@ -1944,6 +1944,8 @@ static int DC390_queuecommand(struct scsi_cmnd *cmd,
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+static DEF_SCSI_QCMD(DC390_queuecommand)
+
static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
{
struct pci_dev *pdev;
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 5d9fdeeb2315..edfc5da8be4c 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -433,7 +433,7 @@
static int u14_34f_detect(struct scsi_host_template *);
static int u14_34f_release(struct Scsi_Host *);
-static int u14_34f_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+static int u14_34f_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int u14_34f_eh_abort(struct scsi_cmnd *);
static int u14_34f_eh_host_reset(struct scsi_cmnd *);
static int u14_34f_bios_param(struct scsi_device *, struct block_device *,
@@ -1248,7 +1248,7 @@ static void scsi_to_dev_dir(unsigned int i, unsigned int j) {
}
-static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
+static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
unsigned int i, j, k;
struct mscp *cpp;
@@ -1329,6 +1329,8 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
return 0;
}
+static DEF_SCSI_QCMD(u14_34f_queuecommand)
+
static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
unsigned int i, j;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 27aa40f3980e..0571ef9639cb 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -700,7 +700,7 @@ static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
mscp->transfer_data_length = transfer_length;
}
-static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+static int ultrastor_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct mscp *my_mscp;
@@ -825,6 +825,8 @@ retry:
return 0;
}
+static DEF_SCSI_QCMD(ultrastor_queuecommand)
+
/* This code must deal with 2 cases:
1. The command has not been written to the OGM. In this case, set
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index a692905f95f7..165c18b5cf5f 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -15,8 +15,7 @@
static int ultrastor_detect(struct scsi_host_template *);
static const char *ultrastor_info(struct Scsi_Host *shpnt);
-static int ultrastor_queuecommand(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+static int ultrastor_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static int ultrastor_abort(struct scsi_cmnd *);
static int ultrastor_host_reset(struct scsi_cmnd *);
static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 26894459c37f..a18996d24466 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -690,7 +690,7 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
return 0;
}
-static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
struct pvscsi_adapter *adapter = shost_priv(host);
@@ -719,6 +719,8 @@ static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(pvscsi_queue)
+
static int pvscsi_abort(struct scsi_cmnd *cmd)
{
struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index b701bf2cc187..5f697e0bd009 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -371,8 +371,8 @@ calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast,
msg[1] = offset;
}
-int
-wd33c93_queuecommand(struct scsi_cmnd *cmd,
+static int
+wd33c93_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct WD33C93_hostdata *hostdata;
@@ -468,6 +468,8 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
return 0;
}
+DEF_SCSI_QCMD(wd33c93_queuecommand)
+
/*
* This routine attempts to start a scsi command. If the host_card is
* already connected, we give up immediately. Otherwise, look through
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 1ed5f3bf388e..3b463d7304dc 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -343,8 +343,7 @@ struct WD33C93_hostdata {
void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs,
dma_setup_t setup, dma_stop_t stop, int clock_freq);
int wd33c93_abort (struct scsi_cmnd *cmd);
-int wd33c93_queuecommand (struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *));
+int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd);
void wd33c93_intr (struct Scsi_Host *instance);
int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
int wd33c93_host_reset (struct scsi_cmnd *);
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 333580bf37c5..db451ae0a368 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1082,7 +1082,7 @@ static irqreturn_t wd7000_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
Scb *scb;
@@ -1139,6 +1139,8 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
return 0;
}
+static DEF_SCSI_QCMD(wd7000_queuecommand)
+
static int wd7000_diagnostics(Adapter * host, int code)
{
static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 4d8e14b7aa93..b25e6e490530 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -454,21 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset);
}
+/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
+static inline void dwapb_save_out_value(struct uart_port *p, int offset,
+ int value)
+{
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
+
+ if (offset == UART_LCR)
+ up->lcr = value;
+}
+
+/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
+static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
+{
+ if (offset == UART_TX || offset == UART_IER)
+ p->serial_in(p, UART_IER);
+}
+
static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
- /* Save the LCR value so it can be re-written when a
- * Busy Detect interrupt occurs. */
- if (save_offset == UART_LCR) {
- struct uart_8250_port *up = (struct uart_8250_port *)p;
- up->lcr = value;
- }
+ dwapb_save_out_value(p, save_offset, value);
writeb(value, p->membase + offset);
- /* Read the IER to ensure any interrupt is cleared before
- * returning from ISR. */
- if (save_offset == UART_TX || save_offset == UART_IER)
- value = p->serial_in(p, UART_IER);
+ dwapb_check_clear_ier(p, save_offset);
+}
+
+static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
+{
+ int save_offset = offset;
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ dwapb_save_out_value(p, save_offset, value);
+ writel(value, p->membase + offset);
+ dwapb_check_clear_ier(p, save_offset);
}
static unsigned int io_serial_in(struct uart_port *p, int offset)
@@ -485,7 +504,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
static void set_io_from_upio(struct uart_port *p)
{
- struct uart_8250_port *up = (struct uart_8250_port *)p;
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
switch (p->iotype) {
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
@@ -518,6 +538,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = dwapb_serial_out;
break;
+ case UPIO_DWAPB32:
+ p->serial_in = mem32_serial_in;
+ p->serial_out = dwapb32_serial_out;
+ break;
+
default:
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
@@ -536,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
case UPIO_MEM32:
case UPIO_AU:
case UPIO_DWAPB:
+ case UPIO_DWAPB32:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
@@ -653,13 +679,13 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
{
if (p->capabilities & UART_CAP_SLEEP) {
if (p->capabilities & UART_CAP_EFR) {
- serial_outp(p, UART_LCR, 0xBF);
+ serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(p, UART_EFR, UART_EFR_ECB);
serial_outp(p, UART_LCR, 0);
}
serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
if (p->capabilities & UART_CAP_EFR) {
- serial_outp(p, UART_LCR, 0xBF);
+ serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(p, UART_EFR, 0);
serial_outp(p, UART_LCR, 0);
}
@@ -752,7 +778,7 @@ static int size_fifo(struct uart_8250_port *up)
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_MCR, UART_MCR_LOOP);
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
old_dl = serial_dl_read(up);
serial_dl_write(up, 0x0001);
serial_outp(up, UART_LCR, 0x03);
@@ -764,7 +790,7 @@ static int size_fifo(struct uart_8250_port *up)
serial_inp(up, UART_RX);
serial_outp(up, UART_FCR, old_fcr);
serial_outp(up, UART_MCR, old_mcr);
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_dl_write(up, old_dl);
serial_outp(up, UART_LCR, old_lcr);
@@ -782,7 +808,7 @@ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
unsigned int id;
old_lcr = serial_inp(p, UART_LCR);
- serial_outp(p, UART_LCR, UART_LCR_DLAB);
+ serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A);
old_dll = serial_inp(p, UART_DLL);
old_dlm = serial_inp(p, UART_DLM);
@@ -836,7 +862,7 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
* recommended for new designs).
*/
up->acr = 0;
- serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, UART_EFR_ECB);
serial_out(up, UART_LCR, 0x00);
id1 = serial_icr_read(up, UART_ID1);
@@ -945,7 +971,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* Check for presence of the EFR when DLAB is set.
* Only ST16C650V1 UARTs pass this test.
*/
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
if (serial_in(up, UART_EFR) == 0) {
serial_outp(up, UART_EFR, 0xA8);
if (serial_in(up, UART_EFR) != 0) {
@@ -963,7 +989,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* Maybe it requires 0xbf to be written to the LCR.
* (other ST16C650V2 UARTs, TI16C752A, etc)
*/
- serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
DEBUG_AUTOCONF("EFRv2 ");
autoconfig_has_efr(up);
@@ -1024,7 +1050,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
status1 = serial_in(up, UART_IIR) >> 5;
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
status2 = serial_in(up, UART_IIR) >> 5;
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -1183,7 +1209,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
* We also initialise the EFR (if any) to zero for later. The
* EFR occupies the same register location as the FCR and IIR.
*/
- serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, 0);
serial_outp(up, UART_LCR, 0);
@@ -1319,7 +1345,8 @@ static inline void __stop_tx(struct uart_8250_port *p)
static void serial8250_stop_tx(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
__stop_tx(up);
@@ -1336,7 +1363,8 @@ static void transmit_chars(struct uart_8250_port *up);
static void serial8250_start_tx(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
@@ -1364,7 +1392,8 @@ static void serial8250_start_tx(struct uart_port *port)
static void serial8250_stop_rx(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
@@ -1373,7 +1402,8 @@ static void serial8250_stop_rx(struct uart_port *port)
static void serial8250_enable_ms(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1581,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
handled = 1;
end = NULL;
- } else if (up->port.iotype == UPIO_DWAPB &&
+ } else if ((up->port.iotype == UPIO_DWAPB ||
+ up->port.iotype == UPIO_DWAPB32) &&
(iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* The DesignWare APB UART has an Busy Detect (0x07)
* interrupt meaning an LCR write attempt occured while the
@@ -1781,7 +1812,8 @@ static void serial8250_backup_timeout(unsigned long data)
static unsigned int serial8250_tx_empty(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned long flags;
unsigned int lsr;
@@ -1795,7 +1827,8 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned int status;
unsigned int ret;
@@ -1815,7 +1848,8 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned char mcr = 0;
if (mctrl & TIOCM_RTS)
@@ -1836,7 +1870,8 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
@@ -1890,7 +1925,8 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
static int serial8250_get_poll_char(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned char lsr = serial_inp(up, UART_LSR);
if (!(lsr & UART_LSR_DR))
@@ -1904,7 +1940,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
unsigned char c)
{
unsigned int ier;
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
/*
* First save the IER then disable the interrupts
@@ -1938,11 +1975,14 @@ static void serial8250_put_poll_char(struct uart_port *port,
static int serial8250_startup(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned long flags;
unsigned char lsr, iir;
int retval;
+ up->port.fifosize = uart_config[up->port.type].fifo_size;
+ up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
up->capabilities = uart_config[up->port.type].flags;
up->mcr = 0;
@@ -1952,7 +1992,7 @@ static int serial8250_startup(struct uart_port *port)
if (up->port.type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
- serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, UART_EFR_ECB);
serial_outp(up, UART_IER, 0);
serial_outp(up, UART_LCR, 0);
@@ -2002,7 +2042,7 @@ static int serial8250_startup(struct uart_port *port)
if (up->port.type == PORT_16850) {
unsigned char fctr;
- serial_outp(up, UART_LCR, 0xbf);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
@@ -2166,7 +2206,8 @@ dont_test_tx_en:
static void serial8250_shutdown(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned long flags;
/*
@@ -2235,7 +2276,8 @@ void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
@@ -2363,7 +2405,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CRTSCTS)
efr |= UART_EFR_CTS;
- serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, efr);
}
@@ -2435,7 +2477,8 @@ serial8250_set_ldisc(struct uart_port *port, int new)
void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_8250_port *p = (struct uart_8250_port *)port;
+ struct uart_8250_port *p =
+ container_of(port, struct uart_8250_port, port);
serial8250_set_sleep(p, state != 0);
}
@@ -2476,6 +2519,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32:
case UPIO_MEM:
case UPIO_DWAPB:
+ case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@@ -2513,6 +2557,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_MEM32:
case UPIO_MEM:
case UPIO_DWAPB:
+ case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@@ -2566,7 +2611,8 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
static void serial8250_release_port(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
serial8250_release_std_resource(up);
if (up->port.type == PORT_RSA)
@@ -2575,7 +2621,8 @@ static void serial8250_release_port(struct uart_port *port)
static int serial8250_request_port(struct uart_port *port)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
int ret = 0;
ret = serial8250_request_std_resource(up);
@@ -2590,7 +2637,8 @@ static int serial8250_request_port(struct uart_port *port)
static void serial8250_config_port(struct uart_port *port, int flags)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
int probeflags = PROBE_ANY;
int ret;
@@ -2771,7 +2819,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
static void serial8250_console_putchar(struct uart_port *port, int ch)
{
- struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
wait_for_xmitr(up, UART_LSR_THRE);
serial_out(up, UART_TX, ch);
@@ -2872,7 +2921,7 @@ static struct console serial8250_console = {
.device = uart_console_device,
.setup = serial8250_console_setup,
.early_setup = serial8250_console_early_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &serial8250_reg,
};
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 53be4d35a0aa..8b8930f700b5 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -957,6 +957,22 @@ pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
+static int
+ce4100_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_port *port, int idx)
+{
+ int ret;
+
+ ret = setup_port(priv, port, 0, 0, board->reg_shift);
+ port->iotype = UPIO_MEM32;
+ port->type = PORT_XSCALE;
+ port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+ port->regshift = 2;
+
+ return ret;
+}
+
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
@@ -981,6 +997,7 @@ static int skip_tx_en_setup(struct serial_private *priv,
#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
#define PCI_DEVICE_ID_TITAN_200I 0x8028
#define PCI_DEVICE_ID_TITAN_400I 0x8048
@@ -1072,6 +1089,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = skip_tx_en_setup,
},
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CE4100_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = ce4100_serial_setup,
+ },
/*
* ITE
*/
@@ -1592,6 +1616,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_2_3906250,
pbn_ADDIDATA_PCIe_4_3906250,
pbn_ADDIDATA_PCIe_8_3906250,
+ pbn_ce4100_1_115200,
};
/*
@@ -2281,10 +2306,18 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.uart_offset = 0x200,
.first_offset = 0x1000,
},
+ [pbn_ce4100_1_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .reg_shift = 2,
+ },
};
static const struct pci_device_id softmodem_blacklist[] = {
{ PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+ { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+ { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
};
/*
@@ -2863,6 +2896,9 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
0, 0,
pbn_b0_4_1152000 },
+ { PCI_VENDOR_ID_OXSEMI, 0x9505,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
/*
* The below card is a little controversial since it is the
@@ -3760,6 +3796,11 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
0xA000, 0x3004,
0, 0, pbn_b0_bt_4_115200 },
+ /* Intel CE4100 */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ce4100_1_115200 },
+
/*
* These entries match devices with class COMMUNICATION_SERIAL,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index aff9dcd051c6..c1df7676a73d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -776,24 +776,7 @@ config BFIN_UART0_CTSRTS
bool "Enable UART0 hardware flow control"
depends on SERIAL_BFIN_UART0
help
- Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
- signal.
-
-config UART0_CTS_PIN
- int "UART0 CTS pin"
- depends on BFIN_UART0_CTSRTS && !BF548
- default 23
- help
- The default pin is GPIO_GP7.
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
-
-config UART0_RTS_PIN
- int "UART0 RTS pin"
- depends on BFIN_UART0_CTSRTS && !BF548
- default 22
- help
- The default pin is GPIO_GP6.
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
+ Enable hardware flow control in the driver.
config SERIAL_BFIN_UART1
bool "Enable UART1"
@@ -805,22 +788,7 @@ config BFIN_UART1_CTSRTS
bool "Enable UART1 hardware flow control"
depends on SERIAL_BFIN_UART1
help
- Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
- signal.
-
-config UART1_CTS_PIN
- int "UART1 CTS pin"
- depends on BFIN_UART1_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
-
-config UART1_RTS_PIN
- int "UART1 RTS pin"
- depends on BFIN_UART1_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
+ Enable hardware flow control in the driver.
config SERIAL_BFIN_UART2
bool "Enable UART2"
@@ -832,22 +800,7 @@ config BFIN_UART2_CTSRTS
bool "Enable UART2 hardware flow control"
depends on SERIAL_BFIN_UART2
help
- Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
- signal.
-
-config UART2_CTS_PIN
- int "UART2 CTS pin"
- depends on BFIN_UART2_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
-
-config UART2_RTS_PIN
- int "UART2 RTS pin"
- depends on BFIN_UART2_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
+ Enable hardware flow control in the driver.
config SERIAL_BFIN_UART3
bool "Enable UART3"
@@ -859,22 +812,7 @@ config BFIN_UART3_CTSRTS
bool "Enable UART3 hardware flow control"
depends on SERIAL_BFIN_UART3
help
- Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
- signal.
-
-config UART3_CTS_PIN
- int "UART3 CTS pin"
- depends on BFIN_UART3_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
-
-config UART3_RTS_PIN
- int "UART3 RTS pin"
- depends on BFIN_UART3_CTSRTS && !BF548
- default -1
- help
- Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map.
+ Enable hardware flow control in the driver.
config SERIAL_IMX
bool "IMX serial port support"
@@ -1381,6 +1319,16 @@ config SERIAL_MSM_CONSOLE
depends on SERIAL_MSM=y
select SERIAL_CORE_CONSOLE
+config SERIAL_VT8500
+ bool "VIA VT8500 on-chip serial port support"
+ depends on ARM && ARCH_VT8500
+ select SERIAL_CORE
+
+config SERIAL_VT8500_CONSOLE
+ bool "VIA VT8500 serial console support"
+ depends on SERIAL_VT8500=y
+ select SERIAL_CORE_CONSOLE
+
config SERIAL_NETX
tristate "NetX serial port support"
depends on ARM && ARCH_NETX
@@ -1402,7 +1350,7 @@ config SERIAL_NETX_CONSOLE
config SERIAL_OF_PLATFORM
tristate "Serial port on Open Firmware platform bus"
- depends on PPC_OF || MICROBLAZE
+ depends on OF
depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
help
If you have a PowerPC based system that has serial ports
@@ -1632,4 +1580,19 @@ config SERIAL_ALTERA_UART_CONSOLE
help
Enable a Altera UART port to be the system console.
+config SERIAL_IFX6X60
+ tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
+ depends on GPIOLIB && SPI && EXPERIMENTAL
+ help
+ Support for the IFX6x60 modem devices on Intel MID platforms.
+
+config SERIAL_PCH_UART
+ tristate "Intel EG20T PCH UART"
+ depends on PCI && DMADEVICES
+ select SERIAL_CORE
+ select PCH_DMA
+ help
+ This driver is for PCH(Platform controller Hub) UART of Intel EG20T
+ which is an IOH(Input/Output Hub) for x86 embedded processor.
+ Enabling PCH_DMA, this PCH UART works as DMA mode.
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index c5705765454f..8ea92e9c73b0 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -80,12 +80,15 @@ obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
-obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
+obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 6ca7a44f29c2..e76d7d000128 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -7,6 +7,7 @@
*
* Copyright 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd.
+ * Copyright (C) 2010 ST-Ericsson SA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,6 +49,9 @@
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -63,21 +67,6 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct uart_amba_port {
- struct uart_port port;
- struct clk *clk;
- unsigned int im; /* interrupt mask */
- unsigned int old_status;
- unsigned int ifls; /* vendor-specific */
- unsigned int lcrh_tx; /* vendor-specific */
- unsigned int lcrh_rx; /* vendor-specific */
- bool oversampling; /* vendor-specific */
- bool autorts;
-};
-
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
@@ -85,6 +74,7 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
+ bool dma_threshold;
};
static struct vendor_data vendor_arm = {
@@ -93,6 +83,7 @@ static struct vendor_data vendor_arm = {
.lcrh_tx = UART011_LCRH,
.lcrh_rx = UART011_LCRH,
.oversampling = false,
+ .dma_threshold = false,
};
static struct vendor_data vendor_st = {
@@ -101,22 +92,535 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
+ .dma_threshold = true,
+};
+
+/* Deals with DMA transactions */
+struct pl011_dmatx_data {
+ struct dma_chan *chan;
+ struct scatterlist sg;
+ char *buf;
+ bool queued;
};
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+ struct uart_port port;
+ struct clk *clk;
+ const struct vendor_data *vendor;
+ unsigned int dmacr; /* dma control reg */
+ unsigned int im; /* interrupt mask */
+ unsigned int old_status;
+ unsigned int fifosize; /* vendor-specific */
+ unsigned int lcrh_tx; /* vendor-specific */
+ unsigned int lcrh_rx; /* vendor-specific */
+ bool autorts;
+ char type[12];
+#ifdef CONFIG_DMA_ENGINE
+ /* DMA stuff */
+ bool using_dma;
+ struct pl011_dmatx_data dmatx;
+#endif
+};
+
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+
+#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+
+static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
+{
+ /* DMA is the sole user of the platform data right now */
+ struct amba_pl011_data *plat = uap->port.dev->platform_data;
+ struct dma_slave_config tx_conf = {
+ .dst_addr = uap->port.mapbase + UART01x_DR,
+ .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+ .direction = DMA_TO_DEVICE,
+ .dst_maxburst = uap->fifosize >> 1,
+ };
+ struct dma_chan *chan;
+ dma_cap_mask_t mask;
+
+ /* We need platform data */
+ if (!plat || !plat->dma_filter) {
+ dev_info(uap->port.dev, "no DMA platform data\n");
+ return;
+ }
+
+ /* Try to acquire a generic DMA engine slave channel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
+ if (!chan) {
+ dev_err(uap->port.dev, "no TX DMA channel!\n");
+ return;
+ }
+
+ dmaengine_slave_config(chan, &tx_conf);
+ uap->dmatx.chan = chan;
+
+ dev_info(uap->port.dev, "DMA channel TX %s\n",
+ dma_chan_name(uap->dmatx.chan));
+}
+
+#ifndef MODULE
+/*
+ * Stack up the UARTs and let the above initcall be done at device
+ * initcall time, because the serial driver is called as an arch
+ * initcall, and at this time the DMA subsystem is not yet registered.
+ * At this point the driver will switch over to using DMA where desired.
+ */
+struct dma_uap {
+ struct list_head node;
+ struct uart_amba_port *uap;
+};
+
+static LIST_HEAD(pl011_dma_uarts);
+
+static int __init pl011_dma_initcall(void)
+{
+ struct list_head *node, *tmp;
+
+ list_for_each_safe(node, tmp, &pl011_dma_uarts) {
+ struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
+ pl011_dma_probe_initcall(dmau->uap);
+ list_del(node);
+ kfree(dmau);
+ }
+ return 0;
+}
+
+device_initcall(pl011_dma_initcall);
+
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+ struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
+ if (dmau) {
+ dmau->uap = uap;
+ list_add_tail(&dmau->node, &pl011_dma_uarts);
+ }
+}
+#else
+static void pl011_dma_probe(struct uart_amba_port *uap)
+{
+ pl011_dma_probe_initcall(uap);
+}
+#endif
+
+static void pl011_dma_remove(struct uart_amba_port *uap)
+{
+ /* TODO: remove the initcall if it has not yet executed */
+ if (uap->dmatx.chan)
+ dma_release_channel(uap->dmatx.chan);
+}
+
+
+/* Forward declare this for the refill routine */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap);
+
+/*
+ * The current DMA TX buffer has been sent.
+ * Try to queue up another DMA buffer.
+ */
+static void pl011_dma_tx_callback(void *data)
+{
+ struct uart_amba_port *uap = data;
+ struct pl011_dmatx_data *dmatx = &uap->dmatx;
+ unsigned long flags;
+ u16 dmacr;
+
+ spin_lock_irqsave(&uap->port.lock, flags);
+ if (uap->dmatx.queued)
+ dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
+ DMA_TO_DEVICE);
+
+ dmacr = uap->dmacr;
+ uap->dmacr = dmacr & ~UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+ /*
+ * If TX DMA was disabled, it means that we've stopped the DMA for
+ * some reason (eg, XOFF received, or we want to send an X-char.)
+ *
+ * Note: we need to be careful here of a potential race between DMA
+ * and the rest of the driver - if the driver disables TX DMA while
+ * a TX buffer completing, we must update the tx queued status to
+ * get further refills (hence we check dmacr).
+ */
+ if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
+ uart_circ_empty(&uap->port.state->xmit)) {
+ uap->dmatx.queued = false;
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+ return;
+ }
+
+ if (pl011_dma_tx_refill(uap) <= 0) {
+ /*
+ * We didn't queue a DMA buffer for some reason, but we
+ * have data pending to be sent. Re-enable the TX IRQ.
+ */
+ uap->im |= UART011_TXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+/*
+ * Try to refill the TX DMA buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ * 1 if we queued up a TX DMA buffer.
+ * 0 if we didn't want to handle this by DMA
+ * <0 on error
+ */
+static int pl011_dma_tx_refill(struct uart_amba_port *uap)
+{
+ struct pl011_dmatx_data *dmatx = &uap->dmatx;
+ struct dma_chan *chan = dmatx->chan;
+ struct dma_device *dma_dev = chan->device;
+ struct dma_async_tx_descriptor *desc;
+ struct circ_buf *xmit = &uap->port.state->xmit;
+ unsigned int count;
+
+ /*
+ * Try to avoid the overhead involved in using DMA if the
+ * transaction fits in the first half of the FIFO, by using
+ * the standard interrupt handling. This ensures that we
+ * issue a uart_write_wakeup() at the appropriate time.
+ */
+ count = uart_circ_chars_pending(xmit);
+ if (count < (uap->fifosize >> 1)) {
+ uap->dmatx.queued = false;
+ return 0;
+ }
+
+ /*
+ * Bodge: don't send the last character by DMA, as this
+ * will prevent XON from notifying us to restart DMA.
+ */
+ count -= 1;
+
+ /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
+ if (count > PL011_DMA_BUFFER_SIZE)
+ count = PL011_DMA_BUFFER_SIZE;
+
+ if (xmit->tail < xmit->head)
+ memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
+ else {
+ size_t first = UART_XMIT_SIZE - xmit->tail;
+ size_t second = xmit->head;
+
+ memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
+ if (second)
+ memcpy(&dmatx->buf[first], &xmit->buf[0], second);
+ }
+
+ dmatx->sg.length = count;
+
+ if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
+ uap->dmatx.queued = false;
+ dev_dbg(uap->port.dev, "unable to map TX DMA\n");
+ return -EBUSY;
+ }
+
+ desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
+ uap->dmatx.queued = false;
+ /*
+ * If DMA cannot be used right now, we complete this
+ * transaction via IRQ and let the TTY layer retry.
+ */
+ dev_dbg(uap->port.dev, "TX DMA busy\n");
+ return -EBUSY;
+ }
+
+ /* Some data to go along to the callback */
+ desc->callback = pl011_dma_tx_callback;
+ desc->callback_param = uap;
+
+ /* All errors should happen at prepare time */
+ dmaengine_submit(desc);
+
+ /* Fire the DMA transaction */
+ dma_dev->device_issue_pending(chan);
+
+ uap->dmacr |= UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->dmatx.queued = true;
+
+ /*
+ * Now we know that DMA will fire, so advance the ring buffer
+ * with the stuff we just dispatched.
+ */
+ xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+ uap->port.icount.tx += count;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&uap->port);
+
+ return 1;
+}
+
+/*
+ * We received a transmit interrupt without a pending X-char but with
+ * pending characters.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ * false if we want to use PIO to transmit
+ * true if we queued a DMA buffer
+ */
+static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+ if (!uap->using_dma)
+ return false;
+
+ /*
+ * If we already have a TX buffer queued, but received a
+ * TX interrupt, it will be because we've just sent an X-char.
+ * Ensure the TX DMA is enabled and the TX IRQ is disabled.
+ */
+ if (uap->dmatx.queued) {
+ uap->dmacr |= UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->im &= ~UART011_TXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ return true;
+ }
+
+ /*
+ * We don't have a TX buffer queued, so try to queue one.
+ * If we succesfully queued a buffer, mask the TX IRQ.
+ */
+ if (pl011_dma_tx_refill(uap) > 0) {
+ uap->im &= ~UART011_TXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Stop the DMA transmit (eg, due to received XOFF).
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+ if (uap->dmatx.queued) {
+ uap->dmacr &= ~UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ }
+}
+
+/*
+ * Try to start a DMA transmit, or in the case of an XON/OFF
+ * character queued for send, try to get that character out ASAP.
+ * Locking: called with port lock held and IRQs disabled.
+ * Returns:
+ * false if we want the TX IRQ to be enabled
+ * true if we have a buffer queued
+ */
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+ u16 dmacr;
+
+ if (!uap->using_dma)
+ return false;
+
+ if (!uap->port.x_char) {
+ /* no X-char, try to push chars out in DMA mode */
+ bool ret = true;
+
+ if (!uap->dmatx.queued) {
+ if (pl011_dma_tx_refill(uap) > 0) {
+ uap->im &= ~UART011_TXIM;
+ ret = true;
+ } else {
+ uap->im |= UART011_TXIM;
+ ret = false;
+ }
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ } else if (!(uap->dmacr & UART011_TXDMAE)) {
+ uap->dmacr |= UART011_TXDMAE;
+ writew(uap->dmacr,
+ uap->port.membase + UART011_DMACR);
+ }
+ return ret;
+ }
+
+ /*
+ * We have an X-char to send. Disable DMA to prevent it loading
+ * the TX fifo, and then see if we can stuff it into the FIFO.
+ */
+ dmacr = uap->dmacr;
+ uap->dmacr &= ~UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+ if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+ /*
+ * No space in the FIFO, so enable the transmit interrupt
+ * so we know when there is space. Note that once we've
+ * loaded the character, we should just re-enable DMA.
+ */
+ return false;
+ }
+
+ writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+ uap->port.icount.tx++;
+ uap->port.x_char = 0;
+
+ /* Success - restore the DMA state */
+ uap->dmacr = dmacr;
+ writew(dmacr, uap->port.membase + UART011_DMACR);
+
+ return true;
+}
+
+/*
+ * Flush the transmit buffer.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static void pl011_dma_flush_buffer(struct uart_port *port)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+ if (!uap->using_dma)
+ return;
+
+ /* Avoid deadlock with the DMA engine callback */
+ spin_unlock(&uap->port.lock);
+ dmaengine_terminate_all(uap->dmatx.chan);
+ spin_lock(&uap->port.lock);
+ if (uap->dmatx.queued) {
+ dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+ DMA_TO_DEVICE);
+ uap->dmatx.queued = false;
+ uap->dmacr &= ~UART011_TXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ }
+}
+
+
+static void pl011_dma_startup(struct uart_amba_port *uap)
+{
+ if (!uap->dmatx.chan)
+ return;
+
+ uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!uap->dmatx.buf) {
+ dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
+ uap->port.fifosize = uap->fifosize;
+ return;
+ }
+
+ sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
+
+ /* The DMA buffer is now the FIFO the TTY subsystem can use */
+ uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
+ uap->using_dma = true;
+
+ /* Turn on DMA error (RX/TX will be enabled on demand) */
+ uap->dmacr |= UART011_DMAONERR;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+
+ /*
+ * ST Micro variants has some specific dma burst threshold
+ * compensation. Set this to 16 bytes, so burst will only
+ * be issued above/below 16 bytes.
+ */
+ if (uap->vendor->dma_threshold)
+ writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
+ uap->port.membase + ST_UART011_DMAWM);
+}
+
+static void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+ if (!uap->using_dma)
+ return;
+
+ /* Disable RX and TX DMA */
+ while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+ barrier();
+
+ spin_lock_irq(&uap->port.lock);
+ uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ spin_unlock_irq(&uap->port.lock);
+
+ /* In theory, this should already be done by pl011_dma_flush_buffer */
+ dmaengine_terminate_all(uap->dmatx.chan);
+ if (uap->dmatx.queued) {
+ dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+ DMA_TO_DEVICE);
+ uap->dmatx.queued = false;
+ }
+
+ kfree(uap->dmatx.buf);
+
+ uap->using_dma = false;
+}
+
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_remove(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_startup(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
+{
+ return false;
+}
+
+static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
+{
+ return false;
+}
+
+#define pl011_dma_flush_buffer NULL
+#endif
+
+
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im &= ~UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
+ pl011_dma_tx_stop(uap);
}
static void pl011_start_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
- uap->im |= UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
+ if (!pl011_dma_tx_start(uap)) {
+ uap->im |= UART011_TXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
}
static void pl011_stop_rx(struct uart_port *port)
@@ -203,7 +707,11 @@ static void pl011_tx_chars(struct uart_amba_port *uap)
return;
}
- count = uap->port.fifosize >> 1;
+ /* If we are using DMA mode, try to send some characters. */
+ if (pl011_dma_tx_irq(uap))
+ return;
+
+ count = uap->fifosize >> 1;
do {
writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -246,10 +754,11 @@ static void pl011_modem_status(struct uart_amba_port *uap)
static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
+ unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
- spin_lock(&uap->port.lock);
+ spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS);
if (status) {
@@ -274,7 +783,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
handled = 1;
}
- spin_unlock(&uap->port.lock);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
return IRQ_RETVAL(handled);
}
@@ -396,7 +905,7 @@ static int pl011_startup(struct uart_port *port)
if (retval)
goto clk_dis;
- writew(uap->ifls, uap->port.membase + UART011_IFLS);
+ writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
/*
* Provoke TX FIFO interrupt into asserting.
@@ -423,11 +932,18 @@ static int pl011_startup(struct uart_port *port)
cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR);
+ /* Clear pending error interrupts */
+ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
+ uap->port.membase + UART011_ICR);
+
/*
* initialise the old status of the modem signals
*/
uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ /* Startup DMA */
+ pl011_dma_startup(uap);
+
/*
* Finally, enable interrupts
*/
@@ -467,6 +983,8 @@ static void pl011_shutdown(struct uart_port *port)
writew(0xffff, uap->port.membase + UART011_ICR);
spin_unlock_irq(&uap->port.lock);
+ pl011_dma_shutdown(uap);
+
/*
* Free the interrupt
*/
@@ -498,13 +1016,18 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int lcr_h, old_cr;
unsigned long flags;
- unsigned int baud, quot;
+ unsigned int baud, quot, clkdiv;
+
+ if (uap->vendor->oversampling)
+ clkdiv = 8;
+ else
+ clkdiv = 16;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0,
- port->uartclk/(uap->oversampling ? 8 : 16));
+ port->uartclk / clkdiv);
if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
@@ -532,7 +1055,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
}
- if (port->fifosize > 1)
+ if (uap->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
spin_lock_irqsave(&port->lock, flags);
@@ -588,8 +1111,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
uap->autorts = false;
}
- if (uap->oversampling) {
- if (baud > port->uartclk/16)
+ if (uap->vendor->oversampling) {
+ if (baud > port->uartclk / 16)
old_cr |= ST_UART011_CR_OVSFACT;
else
old_cr &= ~ST_UART011_CR_OVSFACT;
@@ -622,7 +1145,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
static const char *pl011_type(struct uart_port *port)
{
- return port->type == PORT_AMBA ? "AMBA/PL011" : NULL;
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ return uap->port.type == PORT_AMBA ? uap->type : NULL;
}
/*
@@ -679,6 +1203,7 @@ static struct uart_ops amba_pl011_pops = {
.break_ctl = pl011_break_ctl,
.startup = pl011_startup,
.shutdown = pl011_shutdown,
+ .flush_buffer = pl011_dma_flush_buffer,
.set_termios = pl011_set_termios,
.type = pl011_type,
.release_port = pl010_release_port,
@@ -761,7 +1286,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
- if (uap->oversampling) {
+ if (uap->vendor->oversampling) {
if (readw(uap->port.membase + UART011_CR)
& ST_UART011_CR_OVSFACT)
*baud *= 2;
@@ -858,19 +1383,22 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
goto unmap;
}
- uap->ifls = vendor->ifls;
+ uap->vendor = vendor;
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
- uap->oversampling = vendor->oversampling;
+ uap->fifosize = vendor->fifosize;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
uap->port.iotype = UPIO_MEM;
uap->port.irq = dev->irq[0];
- uap->port.fifosize = vendor->fifosize;
+ uap->port.fifosize = uap->fifosize;
uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = i;
+ pl011_dma_probe(uap);
+
+ snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
amba_ports[i] = uap;
@@ -879,6 +1407,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
if (ret) {
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
+ pl011_dma_remove(uap);
clk_put(uap->clk);
unmap:
iounmap(base);
@@ -902,6 +1431,7 @@ static int pl011_remove(struct amba_device *dev)
if (amba_ports[i] == uap)
amba_ports[i] = NULL;
+ pl011_dma_remove(uap);
iounmap(uap->port.membase);
clk_put(uap->clk);
kfree(uap);
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
index cc01c650a144..095a5d562618 100644
--- a/drivers/serial/apbuart.c
+++ b/drivers/serial/apbuart.c
@@ -26,6 +26,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/serial_core.h>
@@ -520,11 +521,12 @@ static struct console grlib_apbuart_console = {
};
-static void grlib_apbuart_configure(void);
+static int grlib_apbuart_configure(void);
static int __init apbuart_console_init(void)
{
- grlib_apbuart_configure();
+ if (grlib_apbuart_configure())
+ return -ENODEV;
register_console(&grlib_apbuart_console);
return 0;
}
@@ -573,13 +575,15 @@ static int __devinit apbuart_probe(struct platform_device *op,
printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
(unsigned long long) port->mapbase, port->irq);
return 0;
-
}
static struct of_device_id __initdata apbuart_match[] = {
{
.name = "GAISLER_APBUART",
},
+ {
+ .name = "01_00c",
+ },
{},
};
@@ -593,54 +597,49 @@ static struct of_platform_driver grlib_apbuart_of_driver = {
};
-static void grlib_apbuart_configure(void)
+static int grlib_apbuart_configure(void)
{
- static int enum_done;
struct device_node *np, *rp;
- struct uart_port *port = NULL;
const u32 *prop;
- int freq_khz;
- int v = 0, d = 0;
- unsigned int addr;
- int irq, line;
- struct amba_prom_registers *regs;
-
- if (enum_done)
- return;
+ int freq_khz, line = 0;
/* Get bus frequency */
rp = of_find_node_by_path("/");
+ if (!rp)
+ return -ENODEV;
rp = of_get_next_child(rp, NULL);
+ if (!rp)
+ return -ENODEV;
prop = of_get_property(rp, "clock-frequency", NULL);
+ if (!prop)
+ return -ENODEV;
freq_khz = *prop;
- line = 0;
for_each_matching_node(np, apbuart_match) {
+ const int *irqs, *ampopts;
+ const struct amba_prom_registers *regs;
+ struct uart_port *port;
+ unsigned long addr;
- int *vendor = (int *) of_get_property(np, "vendor", NULL);
- int *device = (int *) of_get_property(np, "device", NULL);
- int *irqs = (int *) of_get_property(np, "interrupts", NULL);
- regs = (struct amba_prom_registers *)
- of_get_property(np, "reg", NULL);
+ ampopts = of_get_property(np, "ampopts", NULL);
+ if (ampopts && (*ampopts == 0))
+ continue; /* Ignore if used by another OS instance */
- if (vendor)
- v = *vendor;
- if (device)
- d = *device;
+ irqs = of_get_property(np, "interrupts", NULL);
+ regs = of_get_property(np, "reg", NULL);
if (!irqs || !regs)
- return;
+ continue;
grlib_apbuart_nodes[line] = np;
addr = regs->phys_addr;
- irq = *irqs;
port = &grlib_apbuart_ports[line];
port->mapbase = addr;
port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
- port->irq = irq;
+ port->irq = *irqs;
port->iotype = UPIO_MEM;
port->ops = &grlib_apbuart_ops;
port->flags = UPF_BOOT_AUTOCONF;
@@ -652,12 +651,10 @@ static void grlib_apbuart_configure(void)
/* We support maximum UART_NR uarts ... */
if (line == UART_NR)
break;
-
}
- enum_done = 1;
-
grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+ return line ? 0 : -ENODEV;
}
static int __init grlib_apbuart_init(void)
@@ -665,7 +662,9 @@ static int __init grlib_apbuart_init(void)
int ret;
/* Find all APBUARTS in device the tree and initialize their ports */
- grlib_apbuart_configure();
+ ret = grlib_apbuart_configure();
+ if (ret)
+ return ret;
printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3892666b5fbd..2a1d52fb4936 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1732,6 +1732,11 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
+ UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
+ }
+
return 0;
err_add_port:
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index a9eff2b18eab..e381b895b04d 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1,7 +1,7 @@
/*
* Blackfin On-Chip Serial Driver
*
- * Copyright 2006-2008 Analog Devices Inc.
+ * Copyright 2006-2010 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -12,6 +12,9 @@
#define SUPPORT_SYSRQ
#endif
+#define DRIVER_NAME "bfin-uart"
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/gfp.h>
@@ -23,22 +26,20 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
-
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
- defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+#include <linux/gpio.h>
+#include <linux/irq.h>
#include <linux/kgdb.h>
-#include <asm/irq_regs.h>
-#endif
-
-#include <asm/gpio.h>
-#include <mach/bfin_serial_5xx.h>
-
-#ifdef CONFIG_SERIAL_BFIN_DMA
+#include <linux/slab.h>
#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/irq.h>
+
+#include <asm/portmux.h>
#include <asm/cacheflush.h>
-#endif
+#include <asm/dma.h>
+
+#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase)
+#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr)
+#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
+#include <asm/bfin_serial.h>
#ifdef CONFIG_SERIAL_BFIN_MODULE
# undef CONFIG_EARLY_PRINTK
@@ -49,12 +50,11 @@
#endif
/* UART name and device definitions */
-#define BFIN_SERIAL_NAME "ttyBF"
+#define BFIN_SERIAL_DEV_NAME "ttyBF"
#define BFIN_SERIAL_MAJOR 204
#define BFIN_SERIAL_MINOR 64
-static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
-static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS];
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
@@ -360,7 +360,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx++;
- SSYNC();
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -688,6 +687,13 @@ static int bfin_serial_startup(struct uart_port *port)
# ifdef CONFIG_BF54x
{
+ /*
+ * UART2 and UART3 on BF548 share interrupt PINs and DMA
+ * controllers with SPORT2 and SPORT3. UART rx and tx
+ * interrupts are generated in PIO mode only when configure
+ * their peripheral mapping registers properly, which means
+ * request corresponding DMA channels in PIO mode as well.
+ */
unsigned uart_dma_ch_rx, uart_dma_ch_tx;
switch (uart->port.irq) {
@@ -734,21 +740,19 @@ static int bfin_serial_startup(struct uart_port *port)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
uart->cts_pin = -1;
- pr_info("Unable to attach BlackFin UART CTS interrupt.\
- So, disable it.\n");
+ pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
}
}
if (uart->rts_pin >= 0) {
- gpio_request(uart->rts_pin, DRIVER_NAME);
gpio_direction_output(uart->rts_pin, 0);
}
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- if (request_irq(uart->status_irq,
+ if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
bfin_serial_mctrl_cts_int,
IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
- pr_info("Unable to attach BlackFin UART Modem \
- Status interrupt.\n");
+ uart->cts_pin = -1;
+ pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
}
/* CTS RTS PINs are negative assertive. */
@@ -793,11 +797,9 @@ static void bfin_serial_shutdown(struct uart_port *port)
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0)
free_irq(gpio_to_irq(uart->cts_pin), uart);
- if (uart->rts_pin >= 0)
- gpio_free(uart->rts_pin);
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- if (UART_GET_IER(uart) & EDSSI)
+ if (uart->cts_pin >= 0)
free_irq(uart->status_irq, uart);
#endif
}
@@ -846,6 +848,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CMSPAR)
lcr |= STP;
+ spin_lock_irqsave(&uart->port.lock, flags);
+
port->read_status_mask = OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= (FE | PE);
@@ -875,8 +879,6 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_line != N_IRDA)
quot -= ANOMALY_05000230;
- spin_lock_irqsave(&uart->port.lock, flags);
-
UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
/* Disable UART */
@@ -959,33 +961,33 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
*/
static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
{
- int line = port->line;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
unsigned short val;
switch (ld) {
case N_IRDA:
- val = UART_GET_GCTL(&bfin_serial_ports[line]);
+ val = UART_GET_GCTL(uart);
val |= (IREN | RPOLC);
- UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ UART_PUT_GCTL(uart, val);
break;
default:
- val = UART_GET_GCTL(&bfin_serial_ports[line]);
+ val = UART_GET_GCTL(uart);
val &= ~(IREN | RPOLC);
- UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ UART_PUT_GCTL(uart, val);
}
}
static void bfin_serial_reset_irda(struct uart_port *port)
{
- int line = port->line;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
unsigned short val;
- val = UART_GET_GCTL(&bfin_serial_ports[line]);
+ val = UART_GET_GCTL(uart);
val &= ~(IREN | RPOLC);
- UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ UART_PUT_GCTL(uart, val);
SSYNC();
val |= (IREN | RPOLC);
- UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ UART_PUT_GCTL(uart, val);
SSYNC();
}
@@ -1067,85 +1069,6 @@ static struct uart_ops bfin_serial_pops = {
#endif
};
-static void __init bfin_serial_hw_init(void)
-{
-#ifdef CONFIG_SERIAL_BFIN_UART0
- peripheral_request(P_UART0_TX, DRIVER_NAME);
- peripheral_request(P_UART0_RX, DRIVER_NAME);
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_UART1
- peripheral_request(P_UART1_TX, DRIVER_NAME);
- peripheral_request(P_UART1_RX, DRIVER_NAME);
-
-# if defined(CONFIG_BFIN_UART1_CTSRTS) && defined(CONFIG_BF54x)
- peripheral_request(P_UART1_RTS, DRIVER_NAME);
- peripheral_request(P_UART1_CTS, DRIVER_NAME);
-# endif
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_UART2
- peripheral_request(P_UART2_TX, DRIVER_NAME);
- peripheral_request(P_UART2_RX, DRIVER_NAME);
-#endif
-
-#ifdef CONFIG_SERIAL_BFIN_UART3
- peripheral_request(P_UART3_TX, DRIVER_NAME);
- peripheral_request(P_UART3_RX, DRIVER_NAME);
-
-# if defined(CONFIG_BFIN_UART3_CTSRTS) && defined(CONFIG_BF54x)
- peripheral_request(P_UART3_RTS, DRIVER_NAME);
- peripheral_request(P_UART3_CTS, DRIVER_NAME);
-# endif
-#endif
-}
-
-static void __init bfin_serial_init_ports(void)
-{
- static int first = 1;
- int i;
-
- if (!first)
- return;
- first = 0;
-
- bfin_serial_hw_init();
-
- for (i = 0; i < nr_active_ports; i++) {
- spin_lock_init(&bfin_serial_ports[i].port.lock);
- bfin_serial_ports[i].port.uartclk = get_sclk();
- bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE;
- bfin_serial_ports[i].port.ops = &bfin_serial_pops;
- bfin_serial_ports[i].port.line = i;
- bfin_serial_ports[i].port.iotype = UPIO_MEM;
- bfin_serial_ports[i].port.membase =
- (void __iomem *)bfin_serial_resource[i].uart_base_addr;
- bfin_serial_ports[i].port.mapbase =
- bfin_serial_resource[i].uart_base_addr;
- bfin_serial_ports[i].port.irq =
- bfin_serial_resource[i].uart_irq;
- bfin_serial_ports[i].status_irq =
- bfin_serial_resource[i].uart_status_irq;
- bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF;
-#ifdef CONFIG_SERIAL_BFIN_DMA
- bfin_serial_ports[i].tx_done = 1;
- bfin_serial_ports[i].tx_count = 0;
- bfin_serial_ports[i].tx_dma_channel =
- bfin_serial_resource[i].uart_tx_dma_channel;
- bfin_serial_ports[i].rx_dma_channel =
- bfin_serial_resource[i].uart_rx_dma_channel;
- init_timer(&(bfin_serial_ports[i].rx_dma_timer));
-#endif
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
- bfin_serial_ports[i].cts_pin =
- bfin_serial_resource[i].uart_cts_pin;
- bfin_serial_ports[i].rts_pin =
- bfin_serial_resource[i].uart_rts_pin;
-#endif
- }
-}
-
#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
/*
* If the port was already initialised (eg, by a boot loader),
@@ -1193,6 +1116,34 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
static struct uart_driver bfin_serial_reg;
+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);
+}
+
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+ defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#define CLASS_BFIN_CONSOLE "bfin-console"
+/*
+ * 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];
+ unsigned long flags;
+
+ 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 int __init
bfin_serial_console_setup(struct console *co, char *options)
{
@@ -1212,9 +1163,12 @@ bfin_serial_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index == -1 || co->index >= nr_active_ports)
- co->index = 0;
- uart = &bfin_serial_ports[co->index];
+ if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS)
+ return -ENODEV;
+
+ uart = bfin_serial_ports[co->index];
+ if (!uart)
+ return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1223,36 +1177,9 @@ bfin_serial_console_setup(struct console *co, char *options)
return uart_set_options(&uart->port, co, baud, parity, bits, flow);
}
-#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];
- unsigned long flags;
-
- 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 console bfin_serial_console = {
- .name = BFIN_SERIAL_NAME,
+ .name = BFIN_SERIAL_DEV_NAME,
.write = bfin_serial_console_write,
.device = uart_console_device,
.setup = bfin_serial_console_setup,
@@ -1260,44 +1187,30 @@ static struct console bfin_serial_console = {
.index = -1,
.data = &bfin_serial_reg,
};
-
-static int __init bfin_serial_rs_console_init(void)
-{
- bfin_serial_init_ports();
- register_console(&bfin_serial_console);
-
- return 0;
-}
-console_initcall(bfin_serial_rs_console_init);
-
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE NULL
#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+#ifdef CONFIG_EARLY_PRINTK
+static struct bfin_serial_port bfin_earlyprintk_port;
+#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk"
-#ifdef CONFIG_EARLY_PRINTK
-static __init void early_serial_putc(struct uart_port *port, int ch)
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count)
{
- 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);
-}
+ unsigned long flags;
-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;
+ if (bfin_earlyprintk_port.port.line != co->index)
+ return;
- for (i = 0; i < n; i++, s++) {
- if (*s == '\n')
- early_serial_putc(&uart->port, '\r');
- early_serial_putc(&uart->port, *s);
- }
+ spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags);
+ uart_console_write(&bfin_earlyprintk_port.port, s, count,
+ bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags);
}
/*
@@ -1308,105 +1221,204 @@ static __init void early_serial_write(struct console *con, const char *s,
*/
static struct __initdata console bfin_early_serial_console = {
.name = "early_BFuart",
- .write = early_serial_write,
+ .write = bfin_earlyprintk_console_write,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.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_active_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_EARLY_PRINTK */
+#endif
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
- .driver_name = "bfin-uart",
- .dev_name = BFIN_SERIAL_NAME,
+ .driver_name = DRIVER_NAME,
+ .dev_name = BFIN_SERIAL_DEV_NAME,
.major = BFIN_SERIAL_MAJOR,
.minor = BFIN_SERIAL_MINOR,
.nr = BFIN_UART_NR_PORTS,
.cons = BFIN_SERIAL_CONSOLE,
};
-static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
+static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state)
{
- int i;
+ struct bfin_serial_port *uart = platform_get_drvdata(pdev);
- for (i = 0; i < nr_active_ports; i++) {
- if (bfin_serial_ports[i].port.dev != &dev->dev)
- continue;
- uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
- }
+ return uart_suspend_port(&bfin_serial_reg, &uart->port);
+}
- return 0;
+static int bfin_serial_resume(struct platform_device *pdev)
+{
+ struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+ return uart_resume_port(&bfin_serial_reg, &uart->port);
}
-static int bfin_serial_resume(struct platform_device *dev)
+static int bfin_serial_probe(struct platform_device *pdev)
{
- int i;
+ struct resource *res;
+ struct bfin_serial_port *uart = NULL;
+ int ret = 0;
- for (i = 0; i < nr_active_ports; i++) {
- if (bfin_serial_ports[i].port.dev != &dev->dev)
- continue;
- uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+ dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n");
+ return -ENOENT;
}
- return 0;
-}
+ if (bfin_serial_ports[pdev->id] == NULL) {
-static int bfin_serial_probe(struct platform_device *dev)
-{
- struct resource *res = dev->resource;
- int i;
+ uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+ if (!uart) {
+ dev_err(&pdev->dev,
+ "fail to malloc bfin_serial_port\n");
+ return -ENOMEM;
+ }
+ bfin_serial_ports[pdev->id] = uart;
- for (i = 0; i < dev->num_resources; i++, res++)
- if (res->flags & IORESOURCE_MEM)
- break;
+#ifdef CONFIG_EARLY_PRINTK
+ if (!(bfin_earlyprintk_port.port.membase
+ && bfin_earlyprintk_port.port.line == pdev->id)) {
+ /*
+ * If the peripheral PINs of current port is allocated
+ * in earlyprintk probe stage, don't do it again.
+ */
+#endif
+ ret = peripheral_request_list(
+ (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fail to request bfin serial peripherals\n");
+ goto out_error_free_mem;
+ }
+#ifdef CONFIG_EARLY_PRINTK
+ }
+#endif
+
+ spin_lock_init(&uart->port.lock);
+ uart->port.uartclk = get_sclk();
+ uart->port.fifosize = BFIN_UART_TX_FIFO_SIZE;
+ uart->port.ops = &bfin_serial_pops;
+ uart->port.line = pdev->id;
+ uart->port.iotype = UPIO_MEM;
+ uart->port.flags = UPF_BOOT_AUTOCONF;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ ret = -ENOENT;
+ goto out_error_free_peripherals;
+ }
- if (i < dev->num_resources) {
- for (i = 0; i < nr_active_ports; i++, res++) {
- if (bfin_serial_ports[i].port.mapbase != res->start)
- continue;
- bfin_serial_ports[i].port.dev = &dev->dev;
- uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ uart->port.membase = ioremap(res->start,
+ res->end - res->start);
+ if (!uart->port.membase) {
+ dev_err(&pdev->dev, "Cannot map uart IO\n");
+ ret = -ENXIO;
+ goto out_error_free_peripherals;
}
+ uart->port.mapbase = res->start;
+
+ uart->port.irq = platform_get_irq(pdev, 0);
+ if (uart->port.irq < 0) {
+ dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+
+ uart->status_irq = platform_get_irq(pdev, 1);
+ if (uart->status_irq < 0) {
+ dev_err(&pdev->dev, "No uart status IRQ specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ uart->tx_done = 1;
+ uart->tx_count = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No uart TX DMA channel specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+ uart->tx_dma_channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No uart RX DMA channel specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+ uart->rx_dma_channel = res->start;
+
+ init_timer(&(uart->rx_dma_timer));
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+ defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL)
+ uart->cts_pin = -1;
+ else
+ uart->cts_pin = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ if (res == NULL)
+ uart->rts_pin = -1;
+ else
+ uart->rts_pin = res->start;
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
+ if (uart->rts_pin >= 0)
+ gpio_request(uart->rts_pin, DRIVER_NAME);
+# endif
+#endif
}
- return 0;
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+ if (!is_early_platform_device(pdev)) {
+#endif
+ uart = bfin_serial_ports[pdev->id];
+ uart->port.dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, uart);
+ ret = uart_add_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+ }
+#endif
+
+ if (!ret)
+ return 0;
+
+ if (uart) {
+out_error_unmap:
+ iounmap(uart->port.membase);
+out_error_free_peripherals:
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+ kfree(uart);
+ bfin_serial_ports[pdev->id] = NULL;
+ }
+
+ return ret;
}
-static int bfin_serial_remove(struct platform_device *dev)
+static int __devexit bfin_serial_remove(struct platform_device *pdev)
{
- int i;
-
- for (i = 0; i < nr_active_ports; i++) {
- if (bfin_serial_ports[i].port.dev != &dev->dev)
- continue;
- uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
- bfin_serial_ports[i].port.dev = NULL;
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS)
- gpio_free(bfin_serial_ports[i].cts_pin);
- gpio_free(bfin_serial_ports[i].rts_pin);
+ struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ if (uart) {
+ uart_remove_one_port(&bfin_serial_reg, &uart->port);
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (uart->rts_pin >= 0)
+ gpio_free(uart->rts_pin);
#endif
+ iounmap(uart->port.membase);
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+ kfree(uart);
+ bfin_serial_ports[pdev->id] = NULL;
}
return 0;
@@ -1414,31 +1426,160 @@ static int bfin_serial_remove(struct platform_device *dev)
static struct platform_driver bfin_serial_driver = {
.probe = bfin_serial_probe,
- .remove = bfin_serial_remove,
+ .remove = __devexit_p(bfin_serial_remove),
.suspend = bfin_serial_suspend,
.resume = bfin_serial_resume,
.driver = {
- .name = "bfin-uart",
+ .name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
-static int __init bfin_serial_init(void)
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
+static __initdata struct early_platform_driver early_bfin_serial_driver = {
+ .class_str = CLASS_BFIN_CONSOLE,
+ .pdrv = &bfin_serial_driver,
+ .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init bfin_serial_rs_console_init(void)
{
+ early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME);
+
+ early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0);
+
+ register_console(&bfin_serial_console);
+
+ return 0;
+}
+console_initcall(bfin_serial_rs_console_init);
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK
+/*
+ * Memory can't be allocated dynamically during earlyprink init stage.
+ * So, do individual probe for earlyprink with a static uart port variable.
+ */
+static int bfin_earlyprintk_probe(struct platform_device *pdev)
+{
+ struct resource *res;
int ret;
- pr_info("Serial: Blackfin serial driver\n");
+ if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) {
+ dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n");
+ return -ENOENT;
+ }
+
+ ret = peripheral_request_list(
+ (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fail to request bfin serial peripherals\n");
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ ret = -ENOENT;
+ goto out_error_free_peripherals;
+ }
+
+ bfin_earlyprintk_port.port.membase = ioremap(res->start,
+ res->end - res->start);
+ if (!bfin_earlyprintk_port.port.membase) {
+ dev_err(&pdev->dev, "Cannot map uart IO\n");
+ ret = -ENXIO;
+ goto out_error_free_peripherals;
+ }
+ bfin_earlyprintk_port.port.mapbase = res->start;
+ bfin_earlyprintk_port.port.line = pdev->id;
+ bfin_earlyprintk_port.port.uartclk = get_sclk();
+ bfin_earlyprintk_port.port.fifosize = BFIN_UART_TX_FIFO_SIZE;
+ spin_lock_init(&bfin_earlyprintk_port.port.lock);
+
+ return 0;
+
+out_error_free_peripherals:
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+
+ return ret;
+}
+
+static struct platform_driver bfin_earlyprintk_driver = {
+ .probe = bfin_earlyprintk_probe,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
+ .class_str = CLASS_BFIN_EARLYPRINTK,
+ .pdrv = &bfin_earlyprintk_driver,
+ .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag)
+{
+ struct ktermios t;
+ char port_name[20];
+
+ if (port < 0 || port >= BFIN_UART_NR_PORTS)
+ return NULL;
- bfin_serial_init_ports();
+ /*
+ * Only probe resource of the given port in earlyprintk boot arg.
+ * The expected port id should be indicated in port name string.
+ */
+ snprintf(port_name, 20, DRIVER_NAME ".%d", port);
+ early_platform_driver_register(&early_bfin_earlyprintk_driver,
+ port_name);
+ early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0);
+
+ if (!bfin_earlyprintk_port.port.membase)
+ return NULL;
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+ /*
+ * If we are using early serial, don't let the normal console rewind
+ * log buffer, since that causes things to be printed multiple times
+ */
+ bfin_serial_console.flags &= ~CON_PRINTBUFFER;
+#endif
+
+ bfin_early_serial_console.index = 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(&bfin_earlyprintk_port.port, &t, &t);
+
+ return &bfin_early_serial_console;
+}
+#endif /* CONFIG_EARLY_PRINTK */
+
+static int __init bfin_serial_init(void)
+{
+ int ret;
+
+ pr_info("Blackfin serial driver\n");
ret = uart_register_driver(&bfin_serial_reg);
- if (ret == 0) {
- ret = platform_driver_register(&bfin_serial_driver);
- if (ret) {
- pr_debug("uart register failed\n");
- uart_unregister_driver(&bfin_serial_reg);
- }
+ if (ret) {
+ pr_err("failed to register %s:%d\n",
+ bfin_serial_reg.driver_name, ret);
+ }
+
+ ret = platform_driver_register(&bfin_serial_driver);
+ if (ret) {
+ pr_err("fail to register bfin uart\n");
+ uart_unregister_driver(&bfin_serial_reg);
}
+
return ret;
}
@@ -1452,7 +1593,7 @@ static void __exit bfin_serial_exit(void)
module_init(bfin_serial_init);
module_exit(bfin_serial_exit);
-MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
+MODULE_AUTHOR("Sonic Zhang, Aubrey Li");
MODULE_DESCRIPTION("Blackfin generic serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 7274b527a3c1..b754dcf0fda5 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -76,18 +76,12 @@ struct uart_cpm_port {
unsigned char *tx_buf;
unsigned char *rx_buf;
u32 flags;
- void (*set_lineif)(struct uart_cpm_port *);
struct clk *clk;
u8 brg;
uint dp_addr;
void *mem_addr;
dma_addr_t dma_addr;
u32 mem_size;
- /* helpers */
- int baud;
- int bits;
- /* Keep track of 'odd' SMC2 wirings */
- int is_portb;
/* wait on close if needed */
int wait_closing;
/* value to combine with opcode to form cpm command */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index f2b8adcc6c92..8692ff98fc07 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -72,6 +72,8 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
+#define HW_BUF_SPD_THRESHOLD 9600
+
/*
* Check, if transmit buffers are processed
*/
@@ -503,6 +505,11 @@ static void cpm_uart_set_termios(struct uart_port *port,
pr_debug("CPM uart[%d]:set_termios\n", port->line);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+ if (baud <= HW_BUF_SPD_THRESHOLD ||
+ (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
+ pinfo->rx_fifosize = 1;
+ else
+ pinfo->rx_fifosize = RX_BUF_SIZE;
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
@@ -594,6 +601,17 @@ static void cpm_uart_set_termios(struct uart_port *port,
*/
bits++;
if (IS_SMC(pinfo)) {
+ /*
+ * MRBLR can be changed while an SMC/SCC is operating only
+ * if it is done in a single bus cycle with one 16-bit move
+ * (not two 8-bit bus cycles back-to-back). This occurs when
+ * the cp shifts control to the next RxBD, so the change does
+ * not take effect immediately. To guarantee the exact RxBD
+ * on which the change occurs, change MRBLR only while the
+ * SMC/SCC receiver is disabled.
+ */
+ out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+
/* Set the mode register. We want to keep a copy of the
* enables, because we want to put them back if they were
* present.
@@ -604,6 +622,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
SMCMR_SM_UART | prev_mode);
} else {
+ out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index c856905bb3bd..bcc31f2140ac 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -18,7 +18,6 @@ static char *serial_version = "$Revision: 1.25 $";
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
@@ -1411,11 +1410,12 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
#endif
- info->rs485.flags = r->flags;
- if (r->delay_rts_before_send >= 1000)
+ info->rs485 = *r;
+
+ /* Maximum delay before RTS equal to 1000 */
+ if (info->rs485.delay_rts_before_send >= 1000)
info->rs485.delay_rts_before_send = 1000;
- else
- info->rs485.delay_rts_before_send = r->delay_rts_before_send;
+
/* printk("rts: on send = %i, after = %i, enabled = %i",
info->rs485.rts_on_send,
info->rs485.rts_after_sent,
@@ -3234,9 +3234,9 @@ rs_write(struct tty_struct *tty,
e100_disable_rx(info);
e100_enable_rx_irq(info);
#endif
-
- if (info->rs485.delay_rts_before_send > 0)
- msleep(info->rs485.delay_rts_before_send);
+ if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
+ (info->rs485.delay_rts_before_send > 0))
+ msleep(info->rs485.delay_rts_before_send);
}
#endif /* CONFIG_ETRAX_RS485 */
@@ -3694,6 +3694,11 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
rs485data.flags = 0;
+ if (rs485data.delay_rts_before_send != 0)
+ rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
+ else
+ rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+
if (rs485ctrl.enabled)
rs485data.flags |= SER_RS485_ENABLED;
else
@@ -3731,7 +3736,7 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
/* This is the ioctl to get RS485 data from user-space */
if (copy_to_user((struct serial_rs485 *) arg,
rs485data,
- sizeof(serial_rs485)))
+ sizeof(struct serial_rs485)))
return -EFAULT;
break;
}
@@ -4527,6 +4532,7 @@ static int __init rs_init(void)
/* Set sane defaults */
info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
+ info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
info->rs485.delay_rts_before_send = 0;
info->rs485.flags &= ~(SER_RS485_ENABLED);
#endif
diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
new file mode 100644
index 000000000000..ab93763862d5
--- /dev/null
+++ b/drivers/serial/ifx6x60.c
@@ -0,0 +1,1406 @@
+/****************************************************************************
+ *
+ * Driver for the IFX 6x60 spi modem.
+ *
+ * Copyright (C) 2008 Option International
+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
+ * Denis Joseph Barrow <d.barow@option.com>
+ * Jan Dumon <j.dumon@option.com>
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Russ Gorby <richardx.r.gorby@intel.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 Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ * Driver modified by Intel from Option gtm501l_spi.c
+ *
+ * Notes
+ * o The driver currently assumes a single device only. If you need to
+ * change this then look for saved_ifx_dev and add a device lookup
+ * o The driver is intended to be big-endian safe but has never been
+ * tested that way (no suitable hardware). There are a couple of FIXME
+ * notes by areas that may need addressing
+ * o Some of the GPIO naming/setup assumptions may need revisiting if
+ * you need to use this driver for another platform.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/tty.h>
+#include <linux/kfifo.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rfkill.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/dmapool.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/ifx_modem.h>
+#include <linux/delay.h>
+
+#include "ifx6x60.h"
+
+#define IFX_SPI_MORE_MASK 0x10
+#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */
+#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */
+#define IFX_SPI_TTY_ID 0
+#define IFX_SPI_TIMEOUT_SEC 2
+#define IFX_SPI_HEADER_0 (-1)
+#define IFX_SPI_HEADER_F (-2)
+
+/* forward reference */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+
+/* local variables */
+static int spi_b16 = 1; /* 8 or 16 bit word length */
+static struct tty_driver *tty_drv;
+static struct ifx_spi_device *saved_ifx_dev;
+static struct lock_class_key ifx_spi_key;
+
+/* GPIO/GPE settings */
+
+/**
+ * mrdy_set_high - set MRDY GPIO
+ * @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_high(struct ifx_spi_device *ifx)
+{
+ gpio_set_value(ifx->gpio.mrdy, 1);
+}
+
+/**
+ * mrdy_set_low - clear MRDY GPIO
+ * @ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_low(struct ifx_spi_device *ifx)
+{
+ gpio_set_value(ifx->gpio.mrdy, 0);
+}
+
+/**
+ * ifx_spi_power_state_set
+ * @ifx_dev: our SPI device
+ * @val: bits to set
+ *
+ * Set bit in power status and signal power system if status becomes non-0
+ */
+static void
+ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+ /*
+ * if power status is already non-0, just update, else
+ * tell power system
+ */
+ if (!ifx_dev->power_status)
+ pm_runtime_get(&ifx_dev->spi_dev->dev);
+ ifx_dev->power_status |= val;
+
+ spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ * ifx_spi_power_state_clear - clear power bit
+ * @ifx_dev: our SPI device
+ * @val: bits to clear
+ *
+ * clear bit in power status and signal power system if status becomes 0
+ */
+static void
+ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+ if (ifx_dev->power_status) {
+ ifx_dev->power_status &= ~val;
+ if (!ifx_dev->power_status)
+ pm_runtime_put(&ifx_dev->spi_dev->dev);
+ }
+
+ spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ * swap_buf
+ * @buf: our buffer
+ * @len : number of bytes (not words) in the buffer
+ * @end: end of buffer
+ *
+ * Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf(u16 *buf, int len, void *end)
+{
+ int n;
+
+ len = ((len + 1) >> 1);
+ if ((void *)&buf[len] > end) {
+ pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
+ &buf[len], end);
+ return;
+ }
+ for (n = 0; n < len; n++) {
+ *buf = cpu_to_be16(*buf);
+ buf++;
+ }
+}
+
+/**
+ * mrdy_assert - assert MRDY line
+ * @ifx_dev: our SPI device
+ *
+ * Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
+ * now.
+ *
+ * FIXME: Can SRDY even go high as we are running this code ?
+ */
+static void mrdy_assert(struct ifx_spi_device *ifx_dev)
+{
+ int val = gpio_get_value(ifx_dev->gpio.srdy);
+ if (!val) {
+ if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
+ &ifx_dev->flags)) {
+ ifx_dev->spi_timer.expires =
+ jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
+ add_timer(&ifx_dev->spi_timer);
+
+ }
+ }
+ ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
+ mrdy_set_high(ifx_dev);
+}
+
+/**
+ * ifx_spi_hangup - hang up an IFX device
+ * @ifx_dev: our SPI device
+ *
+ * Hang up the tty attached to the IFX device if one is currently
+ * open. If not take no action
+ */
+static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
+{
+ struct tty_port *pport = &ifx_dev->tty_port;
+ struct tty_struct *tty = tty_port_tty_get(pport);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
+}
+
+/**
+ * ifx_spi_timeout - SPI timeout
+ * @arg: our SPI device
+ *
+ * The SPI has timed out: hang up the tty. Users will then see a hangup
+ * and error events.
+ */
+static void ifx_spi_timeout(unsigned long arg)
+{
+ struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
+
+ dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
+ ifx_spi_ttyhangup(ifx_dev);
+ mrdy_set_low(ifx_dev);
+ clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+}
+
+/* char/tty operations */
+
+/**
+ * ifx_spi_tiocmget - get modem lines
+ * @tty: our tty device
+ * @filp: file handle issuing the request
+ *
+ * Map the signal state into Linux modem flags and report the value
+ * in Linux terms
+ */
+static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+ unsigned int value;
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+ value =
+ (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
+ (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
+ (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
+ (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
+ (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
+ (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
+ return value;
+}
+
+/**
+ * ifx_spi_tiocmset - set modem bits
+ * @tty: the tty structure
+ * @filp: file handle issuing the request
+ * @set: bits to set
+ * @clear: bits to clear
+ *
+ * The IFX6x60 only supports DTR and RTS. Set them accordingly
+ * and flag that an update to the modem is needed.
+ *
+ * FIXME: do we need to kick the tranfers when we do this ?
+ */
+static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
+ unsigned int set, unsigned int clear)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+ if (set & TIOCM_RTS)
+ set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+ if (set & TIOCM_DTR)
+ set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+ if (clear & TIOCM_RTS)
+ clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+ if (clear & TIOCM_DTR)
+ clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+
+ set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
+ return 0;
+}
+
+/**
+ * ifx_spi_open - called on tty open
+ * @tty: our tty device
+ * @filp: file handle being associated with the tty
+ *
+ * Open the tty interface. We let the tty_port layer do all the work
+ * for us.
+ *
+ * FIXME: Remove single device assumption and saved_ifx_dev
+ */
+static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
+{
+ return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
+}
+
+/**
+ * ifx_spi_close - called when our tty closes
+ * @tty: the tty being closed
+ * @filp: the file handle being closed
+ *
+ * Perform the close of the tty. We use the tty_port layer to do all
+ * our hard work.
+ */
+static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+ tty_port_close(&ifx_dev->tty_port, tty, filp);
+ /* FIXME: should we do an ifx_spi_reset here ? */
+}
+
+/**
+ * ifx_decode_spi_header - decode received header
+ * @buffer: the received data
+ * @length: decoded length
+ * @more: decoded more flag
+ * @received_cts: status of cts we received
+ *
+ * Note how received_cts is handled -- if header is all F it is left
+ * the same as it was, if header is all 0 it is set to 0 otherwise it is
+ * taken from the incoming header.
+ *
+ * FIXME: endianness
+ */
+static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
+ unsigned char *more, unsigned char *received_cts)
+{
+ u16 h1;
+ u16 h2;
+ u16 *in_buffer = (u16 *)buffer;
+
+ h1 = *in_buffer;
+ h2 = *(in_buffer+1);
+
+ if (h1 == 0 && h2 == 0) {
+ *received_cts = 0;
+ return IFX_SPI_HEADER_0;
+ } else if (h1 == 0xffff && h2 == 0xffff) {
+ /* spi_slave_cts remains as it was */
+ return IFX_SPI_HEADER_F;
+ }
+
+ *length = h1 & 0xfff; /* upper bits of byte are flags */
+ *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
+ *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
+ return 0;
+}
+
+/**
+ * ifx_setup_spi_header - set header fields
+ * @txbuffer: pointer to start of SPI buffer
+ * @tx_count: bytes
+ * @more: indicate if more to follow
+ *
+ * Format up an SPI header for a transfer
+ *
+ * FIXME: endianness?
+ */
+static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
+ unsigned char more)
+{
+ *(u16 *)(txbuffer) = tx_count;
+ *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
+ txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
+}
+
+/**
+ * ifx_spi_wakeup_serial - SPI space made
+ * @port_data: our SPI device
+ *
+ * We have emptied the FIFO enough that we want to get more data
+ * queued into it. Poke the line discipline via tty_wakeup so that
+ * it will feed us more bits
+ */
+static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
+{
+ struct tty_struct *tty;
+
+ tty = tty_port_tty_get(&ifx_dev->tty_port);
+ if (!tty)
+ return;
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+}
+
+/**
+ * ifx_spi_prepare_tx_buffer - prepare transmit frame
+ * @ifx_dev: our SPI device
+ *
+ * The transmit buffr needs a header and various other bits of
+ * information followed by as much data as we can pull from the FIFO
+ * and transfer. This function formats up a suitable buffer in the
+ * ifx_dev->tx_buffer
+ *
+ * FIXME: performance - should we wake the tty when the queue is half
+ * empty ?
+ */
+static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
+{
+ int temp_count;
+ int queue_length;
+ int tx_count;
+ unsigned char *tx_buffer;
+
+ tx_buffer = ifx_dev->tx_buffer;
+ memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
+
+ /* make room for required SPI header */
+ tx_buffer += IFX_SPI_HEADER_OVERHEAD;
+ tx_count = IFX_SPI_HEADER_OVERHEAD;
+
+ /* clear to signal no more data if this turns out to be the
+ * last buffer sent in a sequence */
+ ifx_dev->spi_more = 0;
+
+ /* if modem cts is set, just send empty buffer */
+ if (!ifx_dev->spi_slave_cts) {
+ /* see if there's tx data */
+ queue_length = kfifo_len(&ifx_dev->tx_fifo);
+ if (queue_length != 0) {
+ /* data to mux -- see if there's room for it */
+ temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
+ temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
+ tx_buffer, temp_count,
+ &ifx_dev->fifo_lock);
+
+ /* update buffer pointer and data count in message */
+ tx_buffer += temp_count;
+ tx_count += temp_count;
+ if (temp_count == queue_length)
+ /* poke port to get more data */
+ ifx_spi_wakeup_serial(ifx_dev);
+ else /* more data in port, use next SPI message */
+ ifx_dev->spi_more = 1;
+ }
+ }
+ /* have data and info for header -- set up SPI header in buffer */
+ /* spi header needs payload size, not entire buffer size */
+ ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
+ tx_count-IFX_SPI_HEADER_OVERHEAD,
+ ifx_dev->spi_more);
+ /* swap actual data in the buffer */
+ swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+ &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
+ return tx_count;
+}
+
+/**
+ * ifx_spi_write - line discipline write
+ * @tty: our tty device
+ * @buf: pointer to buffer to write (kernel space)
+ * @count: size of buffer
+ *
+ * Write the characters we have been given into the FIFO. If the device
+ * is not active then activate it, when the SRDY line is asserted back
+ * this will commence I/O
+ */
+static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+ unsigned char *tmp_buf = (unsigned char *)buf;
+ int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
+ &ifx_dev->fifo_lock);
+ mrdy_assert(ifx_dev);
+ return tx_count;
+}
+
+/**
+ * ifx_spi_chars_in_buffer - line discipline helper
+ * @tty: our tty device
+ *
+ * Report how much data we can accept before we drop bytes. As we use
+ * a simple FIFO this is nice and easy.
+ */
+static int ifx_spi_write_room(struct tty_struct *tty)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+ return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ * ifx_spi_chars_in_buffer - line discipline helper
+ * @tty: our tty device
+ *
+ * Report how many characters we have buffered. In our case this is the
+ * number of bytes sitting in our transmit FIFO.
+ */
+static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+ return kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ * ifx_port_hangup
+ * @port: our tty port
+ *
+ * tty port hang up. Called when tty_hangup processing is invoked either
+ * by loss of carrier, or by software (eg vhangup). Serialized against
+ * activate/shutdown by the tty layer.
+ */
+static void ifx_spi_hangup(struct tty_struct *tty)
+{
+ struct ifx_spi_device *ifx_dev = tty->driver_data;
+ tty_port_hangup(&ifx_dev->tty_port);
+}
+
+/**
+ * ifx_port_activate
+ * @port: our tty port
+ *
+ * tty port activate method - called for first open. Serialized
+ * with hangup and shutdown by the tty layer.
+ */
+static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct ifx_spi_device *ifx_dev =
+ container_of(port, struct ifx_spi_device, tty_port);
+
+ /* clear any old data; can't do this in 'close' */
+ kfifo_reset(&ifx_dev->tx_fifo);
+
+ /* put port data into this tty */
+ tty->driver_data = ifx_dev;
+
+ /* allows flip string push from int context */
+ tty->low_latency = 1;
+
+ return 0;
+}
+
+/**
+ * ifx_port_shutdown
+ * @port: our tty port
+ *
+ * tty port shutdown method - called for last port close. Serialized
+ * with hangup and activate by the tty layer.
+ */
+static void ifx_port_shutdown(struct tty_port *port)
+{
+ struct ifx_spi_device *ifx_dev =
+ container_of(port, struct ifx_spi_device, tty_port);
+
+ mrdy_set_low(ifx_dev);
+ clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+ tasklet_kill(&ifx_dev->io_work_tasklet);
+}
+
+static const struct tty_port_operations ifx_tty_port_ops = {
+ .activate = ifx_port_activate,
+ .shutdown = ifx_port_shutdown,
+};
+
+static const struct tty_operations ifx_spi_serial_ops = {
+ .open = ifx_spi_open,
+ .close = ifx_spi_close,
+ .write = ifx_spi_write,
+ .hangup = ifx_spi_hangup,
+ .write_room = ifx_spi_write_room,
+ .chars_in_buffer = ifx_spi_chars_in_buffer,
+ .tiocmget = ifx_spi_tiocmget,
+ .tiocmset = ifx_spi_tiocmset,
+};
+
+/**
+ * ifx_spi_insert_fip_string - queue received data
+ * @ifx_ser: our SPI device
+ * @chars: buffer we have received
+ * @size: number of chars reeived
+ *
+ * Queue bytes to the tty assuming the tty side is currently open. If
+ * not the discard the data.
+ */
+static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
+ unsigned char *chars, size_t size)
+{
+ struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
+ if (!tty)
+ return;
+ tty_insert_flip_string(tty, chars, size);
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
+
+/**
+ * ifx_spi_complete - SPI transfer completed
+ * @ctx: our SPI device
+ *
+ * An SPI transfer has completed. Process any received data and kick off
+ * any further transmits we can commence.
+ */
+static void ifx_spi_complete(void *ctx)
+{
+ struct ifx_spi_device *ifx_dev = ctx;
+ struct tty_struct *tty;
+ struct tty_ldisc *ldisc = NULL;
+ int length;
+ int actual_length;
+ unsigned char more;
+ unsigned char cts;
+ int local_write_pending = 0;
+ int queue_length;
+ int srdy;
+ int decode_result;
+
+ mrdy_set_low(ifx_dev);
+
+ if (!ifx_dev->spi_msg.status) {
+ /* check header validity, get comm flags */
+ swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+ &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
+ decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
+ &length, &more, &cts);
+ if (decode_result == IFX_SPI_HEADER_0) {
+ dev_dbg(&ifx_dev->spi_dev->dev,
+ "ignore input: invalid header 0");
+ ifx_dev->spi_slave_cts = 0;
+ goto complete_exit;
+ } else if (decode_result == IFX_SPI_HEADER_F) {
+ dev_dbg(&ifx_dev->spi_dev->dev,
+ "ignore input: invalid header F");
+ goto complete_exit;
+ }
+
+ ifx_dev->spi_slave_cts = cts;
+
+ actual_length = min((unsigned int)length,
+ ifx_dev->spi_msg.actual_length);
+ swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+ actual_length,
+ &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
+ ifx_spi_insert_flip_string(
+ ifx_dev,
+ ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
+ (size_t)actual_length);
+ } else {
+ dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
+ ifx_dev->spi_msg.status);
+ }
+
+complete_exit:
+ if (ifx_dev->write_pending) {
+ ifx_dev->write_pending = 0;
+ local_write_pending = 1;
+ }
+
+ clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
+
+ queue_length = kfifo_len(&ifx_dev->tx_fifo);
+ srdy = gpio_get_value(ifx_dev->gpio.srdy);
+ if (!srdy)
+ ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
+
+ /* schedule output if there is more to do */
+ if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
+ tasklet_schedule(&ifx_dev->io_work_tasklet);
+ else {
+ if (more || ifx_dev->spi_more || queue_length > 0 ||
+ local_write_pending) {
+ if (ifx_dev->spi_slave_cts) {
+ if (more)
+ mrdy_assert(ifx_dev);
+ } else
+ mrdy_assert(ifx_dev);
+ } else {
+ /*
+ * poke line discipline driver if any for more data
+ * may or may not get more data to write
+ * for now, say not busy
+ */
+ ifx_spi_power_state_clear(ifx_dev,
+ IFX_SPI_POWER_DATA_PENDING);
+ tty = tty_port_tty_get(&ifx_dev->tty_port);
+ if (tty) {
+ ldisc = tty_ldisc_ref(tty);
+ if (ldisc) {
+ ldisc->ops->write_wakeup(tty);
+ tty_ldisc_deref(ldisc);
+ }
+ tty_kref_put(tty);
+ }
+ }
+ }
+}
+
+/**
+ * ifx_spio_io - I/O tasklet
+ * @data: our SPI device
+ *
+ * Queue data for transmission if possible and then kick off the
+ * transfer.
+ */
+static void ifx_spi_io(unsigned long data)
+{
+ int retval;
+ struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
+
+ if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+ if (ifx_dev->gpio.unack_srdy_int_nb > 0)
+ ifx_dev->gpio.unack_srdy_int_nb--;
+
+ ifx_spi_prepare_tx_buffer(ifx_dev);
+
+ spi_message_init(&ifx_dev->spi_msg);
+ INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
+
+ ifx_dev->spi_msg.context = ifx_dev;
+ ifx_dev->spi_msg.complete = ifx_spi_complete;
+
+ /* set up our spi transfer */
+ /* note len is BYTES, not transfers */
+ ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
+ ifx_dev->spi_xfer.cs_change = 0;
+ ifx_dev->spi_xfer.speed_hz = 12500000;
+ /* ifx_dev->spi_xfer.speed_hz = 390625; */
+ ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
+
+ ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
+ ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
+
+ /*
+ * setup dma pointers
+ */
+ if (ifx_dev->is_6160) {
+ ifx_dev->spi_msg.is_dma_mapped = 1;
+ ifx_dev->tx_dma = ifx_dev->tx_bus;
+ ifx_dev->rx_dma = ifx_dev->rx_bus;
+ ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
+ ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
+ } else {
+ ifx_dev->spi_msg.is_dma_mapped = 0;
+ ifx_dev->tx_dma = (dma_addr_t)0;
+ ifx_dev->rx_dma = (dma_addr_t)0;
+ ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
+ ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
+ }
+
+ spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
+
+ /* Assert MRDY. This may have already been done by the write
+ * routine.
+ */
+ mrdy_assert(ifx_dev);
+
+ retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
+ if (retval) {
+ clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
+ &ifx_dev->flags);
+ tasklet_schedule(&ifx_dev->io_work_tasklet);
+ return;
+ }
+ } else
+ ifx_dev->write_pending = 1;
+}
+
+/**
+ * ifx_spi_free_port - free up the tty side
+ * @ifx_dev: IFX device going away
+ *
+ * Unregister and free up a port when the device goes away
+ */
+static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
+{
+ if (ifx_dev->tty_dev)
+ tty_unregister_device(tty_drv, ifx_dev->minor);
+ kfifo_free(&ifx_dev->tx_fifo);
+}
+
+/**
+ * ifx_spi_create_port - create a new port
+ * @ifx_dev: our spi device
+ *
+ * Allocate and initialise the tty port that goes with this interface
+ * and add it to the tty layer so that it can be opened.
+ */
+static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
+{
+ int ret = 0;
+ struct tty_port *pport = &ifx_dev->tty_port;
+
+ spin_lock_init(&ifx_dev->fifo_lock);
+ lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
+ &ifx_spi_key, 0);
+
+ if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ pport->ops = &ifx_tty_port_ops;
+ tty_port_init(pport);
+ ifx_dev->minor = IFX_SPI_TTY_ID;
+ ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
+ &ifx_dev->spi_dev->dev);
+ if (IS_ERR(ifx_dev->tty_dev)) {
+ dev_dbg(&ifx_dev->spi_dev->dev,
+ "%s: registering tty device failed", __func__);
+ ret = PTR_ERR(ifx_dev->tty_dev);
+ goto error_ret;
+ }
+ return 0;
+
+error_ret:
+ ifx_spi_free_port(ifx_dev);
+ return ret;
+}
+
+/**
+ * ifx_spi_handle_srdy - handle SRDY
+ * @ifx_dev: device asserting SRDY
+ *
+ * Check our device state and see what we need to kick off when SRDY
+ * is asserted. This usually means killing the timer and firing off the
+ * I/O processing.
+ */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
+{
+ if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
+ del_timer_sync(&ifx_dev->spi_timer);
+ clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+ }
+
+ ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
+
+ if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
+ tasklet_schedule(&ifx_dev->io_work_tasklet);
+ else
+ set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+}
+
+/**
+ * ifx_spi_srdy_interrupt - SRDY asserted
+ * @irq: our IRQ number
+ * @dev: our ifx device
+ *
+ * The modem asserted SRDY. Handle the srdy event
+ */
+static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
+{
+ struct ifx_spi_device *ifx_dev = dev;
+ ifx_dev->gpio.unack_srdy_int_nb++;
+ ifx_spi_handle_srdy(ifx_dev);
+ return IRQ_HANDLED;
+}
+
+/**
+ * ifx_spi_reset_interrupt - Modem has changed reset state
+ * @irq: interrupt number
+ * @dev: our device pointer
+ *
+ * The modem has either entered or left reset state. Check the GPIO
+ * line to see which.
+ *
+ * FIXME: review locking on MR_INPROGRESS versus
+ * parallel unsolicited reset/solicited reset
+ */
+static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
+{
+ struct ifx_spi_device *ifx_dev = dev;
+ int val = gpio_get_value(ifx_dev->gpio.reset_out);
+ int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
+
+ if (val == 0) {
+ /* entered reset */
+ set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+ if (!solreset) {
+ /* unsolicited reset */
+ ifx_spi_ttyhangup(ifx_dev);
+ }
+ } else {
+ /* exited reset */
+ clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+ if (solreset) {
+ set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
+ wake_up(&ifx_dev->mdm_reset_wait);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * ifx_spi_free_device - free device
+ * @ifx_dev: device to free
+ *
+ * Free the IFX device
+ */
+static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
+{
+ ifx_spi_free_port(ifx_dev);
+ dma_free_coherent(&ifx_dev->spi_dev->dev,
+ IFX_SPI_TRANSFER_SIZE,
+ ifx_dev->tx_buffer,
+ ifx_dev->tx_bus);
+ dma_free_coherent(&ifx_dev->spi_dev->dev,
+ IFX_SPI_TRANSFER_SIZE,
+ ifx_dev->rx_buffer,
+ ifx_dev->rx_bus);
+}
+
+/**
+ * ifx_spi_reset - reset modem
+ * @ifx_dev: modem to reset
+ *
+ * Perform a reset on the modem
+ */
+static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
+{
+ int ret;
+ /*
+ * set up modem power, reset
+ *
+ * delays are required on some platforms for the modem
+ * to reset properly
+ */
+ set_bit(MR_START, &ifx_dev->mdm_reset_state);
+ gpio_set_value(ifx_dev->gpio.po, 0);
+ gpio_set_value(ifx_dev->gpio.reset, 0);
+ msleep(25);
+ gpio_set_value(ifx_dev->gpio.reset, 1);
+ msleep(1);
+ gpio_set_value(ifx_dev->gpio.po, 1);
+ msleep(1);
+ gpio_set_value(ifx_dev->gpio.po, 0);
+ ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
+ test_bit(MR_COMPLETE,
+ &ifx_dev->mdm_reset_state),
+ IFX_RESET_TIMEOUT);
+ if (!ret)
+ dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
+ ifx_dev->mdm_reset_state);
+
+ ifx_dev->mdm_reset_state = 0;
+ return ret;
+}
+
+/**
+ * ifx_spi_spi_probe - probe callback
+ * @spi: our possible matching SPI device
+ *
+ * Probe for a 6x60 modem on SPI bus. Perform any needed device and
+ * GPIO setup.
+ *
+ * FIXME:
+ * - Support for multiple devices
+ * - Split out MID specific GPIO handling eventually
+ */
+
+static int ifx_spi_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ int srdy;
+ struct ifx_modem_platform_data *pl_data = NULL;
+ struct ifx_spi_device *ifx_dev;
+
+ if (saved_ifx_dev) {
+ dev_dbg(&spi->dev, "ignoring subsequent detection");
+ return -ENODEV;
+ }
+
+ /* initialize structure to hold our device variables */
+ ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
+ if (!ifx_dev) {
+ dev_err(&spi->dev, "spi device allocation failed");
+ return -ENOMEM;
+ }
+ saved_ifx_dev = ifx_dev;
+ ifx_dev->spi_dev = spi;
+ clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+ spin_lock_init(&ifx_dev->write_lock);
+ spin_lock_init(&ifx_dev->power_lock);
+ ifx_dev->power_status = 0;
+ init_timer(&ifx_dev->spi_timer);
+ ifx_dev->spi_timer.function = ifx_spi_timeout;
+ ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
+ ifx_dev->is_6160 = pl_data->is_6160;
+
+ /* ensure SPI protocol flags are initialized to enable transfer */
+ ifx_dev->spi_more = 0;
+ ifx_dev->spi_slave_cts = 0;
+
+ /*initialize transfer and dma buffers */
+ ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+ IFX_SPI_TRANSFER_SIZE,
+ &ifx_dev->tx_bus,
+ GFP_KERNEL);
+ if (!ifx_dev->tx_buffer) {
+ dev_err(&spi->dev, "DMA-TX buffer allocation failed");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+ IFX_SPI_TRANSFER_SIZE,
+ &ifx_dev->rx_bus,
+ GFP_KERNEL);
+ if (!ifx_dev->rx_buffer) {
+ dev_err(&spi->dev, "DMA-RX buffer allocation failed");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ /* initialize waitq for modem reset */
+ init_waitqueue_head(&ifx_dev->mdm_reset_wait);
+
+ spi_set_drvdata(spi, ifx_dev);
+ tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
+ (unsigned long)ifx_dev);
+
+ set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
+
+ /* create our tty port */
+ ret = ifx_spi_create_port(ifx_dev);
+ if (ret != 0) {
+ dev_err(&spi->dev, "create default tty port failed");
+ goto error_ret;
+ }
+
+ pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+ if (pl_data) {
+ ifx_dev->gpio.reset = pl_data->rst_pmu;
+ ifx_dev->gpio.po = pl_data->pwr_on;
+ ifx_dev->gpio.mrdy = pl_data->mrdy;
+ ifx_dev->gpio.srdy = pl_data->srdy;
+ ifx_dev->gpio.reset_out = pl_data->rst_out;
+ } else {
+ dev_err(&spi->dev, "missing platform data!");
+ ret = -ENODEV;
+ goto error_ret;
+ }
+
+ dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
+ ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
+ ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
+
+ /* Configure gpios */
+ ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
+ if (ret < 0) {
+ dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
+ ifx_dev->gpio.reset);
+ goto error_ret;
+ }
+ ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
+ ret += gpio_export(ifx_dev->gpio.reset, 1);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
+ ifx_dev->gpio.reset);
+ ret = -EBUSY;
+ goto error_ret2;
+ }
+
+ ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
+ ret += gpio_direction_output(ifx_dev->gpio.po, 0);
+ ret += gpio_export(ifx_dev->gpio.po, 1);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
+ ifx_dev->gpio.po);
+ ret = -EBUSY;
+ goto error_ret3;
+ }
+
+ ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
+ if (ret < 0) {
+ dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
+ ifx_dev->gpio.mrdy);
+ goto error_ret3;
+ }
+ ret += gpio_export(ifx_dev->gpio.mrdy, 1);
+ ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
+ ifx_dev->gpio.mrdy);
+ ret = -EBUSY;
+ goto error_ret4;
+ }
+
+ ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
+ if (ret < 0) {
+ dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
+ ifx_dev->gpio.srdy);
+ ret = -EBUSY;
+ goto error_ret4;
+ }
+ ret += gpio_export(ifx_dev->gpio.srdy, 1);
+ ret += gpio_direction_input(ifx_dev->gpio.srdy);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
+ ifx_dev->gpio.srdy);
+ ret = -EBUSY;
+ goto error_ret5;
+ }
+
+ ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
+ if (ret < 0) {
+ dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
+ ifx_dev->gpio.reset_out);
+ goto error_ret5;
+ }
+ ret += gpio_export(ifx_dev->gpio.reset_out, 1);
+ ret += gpio_direction_input(ifx_dev->gpio.reset_out);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
+ ifx_dev->gpio.reset_out);
+ ret = -EBUSY;
+ goto error_ret6;
+ }
+
+ ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
+ ifx_spi_reset_interrupt,
+ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
+ (void *)ifx_dev);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to get irq %x\n",
+ gpio_to_irq(ifx_dev->gpio.reset_out));
+ goto error_ret6;
+ }
+
+ ret = ifx_spi_reset(ifx_dev);
+
+ ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
+ ifx_spi_srdy_interrupt,
+ IRQF_TRIGGER_RISING, DRVNAME,
+ (void *)ifx_dev);
+ if (ret) {
+ dev_err(&spi->dev, "Unable to get irq %x",
+ gpio_to_irq(ifx_dev->gpio.srdy));
+ goto error_ret7;
+ }
+
+ /* set pm runtime power state and register with power system */
+ pm_runtime_set_active(&spi->dev);
+ pm_runtime_enable(&spi->dev);
+
+ /* handle case that modem is already signaling SRDY */
+ /* no outgoing tty open at this point, this just satisfies the
+ * modem's read and should reset communication properly
+ */
+ srdy = gpio_get_value(ifx_dev->gpio.srdy);
+
+ if (srdy) {
+ mrdy_assert(ifx_dev);
+ ifx_spi_handle_srdy(ifx_dev);
+ } else
+ mrdy_set_low(ifx_dev);
+ return 0;
+
+error_ret7:
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+error_ret6:
+ gpio_free(ifx_dev->gpio.srdy);
+error_ret5:
+ gpio_free(ifx_dev->gpio.mrdy);
+error_ret4:
+ gpio_free(ifx_dev->gpio.reset);
+error_ret3:
+ gpio_free(ifx_dev->gpio.po);
+error_ret2:
+ gpio_free(ifx_dev->gpio.reset_out);
+error_ret:
+ ifx_spi_free_device(ifx_dev);
+ saved_ifx_dev = NULL;
+ return ret;
+}
+
+/**
+ * ifx_spi_spi_remove - SPI device was removed
+ * @spi: SPI device
+ *
+ * FIXME: We should be shutting the device down here not in
+ * the module unload path.
+ */
+
+static int ifx_spi_spi_remove(struct spi_device *spi)
+{
+ struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+ /* stop activity */
+ tasklet_kill(&ifx_dev->io_work_tasklet);
+ /* free irq */
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+
+ gpio_free(ifx_dev->gpio.srdy);
+ gpio_free(ifx_dev->gpio.mrdy);
+ gpio_free(ifx_dev->gpio.reset);
+ gpio_free(ifx_dev->gpio.po);
+ gpio_free(ifx_dev->gpio.reset_out);
+
+ /* free allocations */
+ ifx_spi_free_device(ifx_dev);
+
+ saved_ifx_dev = NULL;
+ return 0;
+}
+
+/**
+ * ifx_spi_spi_shutdown - called on SPI shutdown
+ * @spi: SPI device
+ *
+ * No action needs to be taken here
+ */
+
+static void ifx_spi_spi_shutdown(struct spi_device *spi)
+{
+}
+
+/*
+ * various suspends and resumes have nothing to do
+ * no hardware to save state for
+ */
+
+/**
+ * ifx_spi_spi_suspend - suspend SPI on system suspend
+ * @dev: device being suspended
+ *
+ * Suspend the SPI side. No action needed on Intel MID platforms, may
+ * need extending for other systems.
+ */
+static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_spi_resume - resume SPI side on system resume
+ * @dev: device being suspended
+ *
+ * Suspend the SPI side. No action needed on Intel MID platforms, may
+ * need extending for other systems.
+ */
+static int ifx_spi_spi_resume(struct spi_device *spi)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_pm_suspend - suspend modem on system suspend
+ * @dev: device being suspended
+ *
+ * Suspend the modem. No action needed on Intel MID platforms, may
+ * need extending for other systems.
+ */
+static int ifx_spi_pm_suspend(struct device *dev)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_pm_resume - resume modem on system resume
+ * @dev: device being suspended
+ *
+ * Allow the modem to resume. No action needed.
+ *
+ * FIXME: do we need to reset anything here ?
+ */
+static int ifx_spi_pm_resume(struct device *dev)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_pm_runtime_resume - suspend modem
+ * @dev: device being suspended
+ *
+ * Allow the modem to resume. No action needed.
+ */
+static int ifx_spi_pm_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_pm_runtime_suspend - suspend modem
+ * @dev: device being suspended
+ *
+ * Allow the modem to suspend and thus suspend to continue up the
+ * device tree.
+ */
+static int ifx_spi_pm_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+/**
+ * ifx_spi_pm_runtime_idle - check if modem idle
+ * @dev: our device
+ *
+ * Check conditions and queue runtime suspend if idle.
+ */
+static int ifx_spi_pm_runtime_idle(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+ if (!ifx_dev->power_status)
+ pm_runtime_suspend(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ifx_spi_pm = {
+ .resume = ifx_spi_pm_resume,
+ .suspend = ifx_spi_pm_suspend,
+ .runtime_resume = ifx_spi_pm_runtime_resume,
+ .runtime_suspend = ifx_spi_pm_runtime_suspend,
+ .runtime_idle = ifx_spi_pm_runtime_idle
+};
+
+static const struct spi_device_id ifx_id_table[] = {
+ {"ifx6160", 0},
+ {"ifx6260", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ifx_id_table);
+
+/* spi operations */
+static const struct spi_driver ifx_spi_driver_6160 = {
+ .driver = {
+ .name = "ifx6160",
+ .bus = &spi_bus_type,
+ .pm = &ifx_spi_pm,
+ .owner = THIS_MODULE},
+ .probe = ifx_spi_spi_probe,
+ .shutdown = ifx_spi_spi_shutdown,
+ .remove = __devexit_p(ifx_spi_spi_remove),
+ .suspend = ifx_spi_spi_suspend,
+ .resume = ifx_spi_spi_resume,
+ .id_table = ifx_id_table
+};
+
+/**
+ * ifx_spi_exit - module exit
+ *
+ * Unload the module.
+ */
+
+static void __exit ifx_spi_exit(void)
+{
+ /* unregister */
+ tty_unregister_driver(tty_drv);
+ spi_unregister_driver((void *)&ifx_spi_driver_6160);
+}
+
+/**
+ * ifx_spi_init - module entry point
+ *
+ * Initialise the SPI and tty interfaces for the IFX SPI driver
+ * We need to initialize upper-edge spi driver after the tty
+ * driver because otherwise the spi probe will race
+ */
+
+static int __init ifx_spi_init(void)
+{
+ int result;
+
+ tty_drv = alloc_tty_driver(1);
+ if (!tty_drv) {
+ pr_err("%s: alloc_tty_driver failed", DRVNAME);
+ return -ENOMEM;
+ }
+
+ tty_drv->magic = TTY_DRIVER_MAGIC;
+ tty_drv->owner = THIS_MODULE;
+ tty_drv->driver_name = DRVNAME;
+ tty_drv->name = TTYNAME;
+ tty_drv->minor_start = IFX_SPI_TTY_ID;
+ tty_drv->num = 1;
+ 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_set_operations(tty_drv, &ifx_spi_serial_ops);
+
+ result = tty_register_driver(tty_drv);
+ if (result) {
+ pr_err("%s: tty_register_driver failed(%d)",
+ DRVNAME, result);
+ put_tty_driver(tty_drv);
+ return result;
+ }
+
+ result = spi_register_driver((void *)&ifx_spi_driver_6160);
+ if (result) {
+ pr_err("%s: spi_register_driver failed(%d)",
+ DRVNAME, result);
+ tty_unregister_driver(tty_drv);
+ }
+ return result;
+}
+
+module_init(ifx_spi_init);
+module_exit(ifx_spi_exit);
+
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("IFX6x60 spi driver");
+MODULE_LICENSE("GPL");
+MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
new file mode 100644
index 000000000000..deb7b8d977dc
--- /dev/null
+++ b/drivers/serial/ifx6x60.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+ *
+ * Driver for the IFX spi modem.
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Jim Stanley <jim.stanley@intel.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 Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ *
+ *
+ *****************************************************************************/
+#ifndef _IFX6X60_H
+#define _IFX6X60_H
+
+#define DRVNAME "ifx6x60"
+#define TTYNAME "ttyIFX"
+
+/* #define IFX_THROTTLE_CODE */
+
+#define IFX_SPI_MAX_MINORS 1
+#define IFX_SPI_TRANSFER_SIZE 2048
+#define IFX_SPI_FIFO_SIZE 4096
+
+#define IFX_SPI_HEADER_OVERHEAD 4
+#define IFX_RESET_TIMEOUT msecs_to_jiffies(50)
+
+/* device flags bitfield definitions */
+#define IFX_SPI_STATE_PRESENT 0
+#define IFX_SPI_STATE_IO_IN_PROGRESS 1
+#define IFX_SPI_STATE_IO_READY 2
+#define IFX_SPI_STATE_TIMER_PENDING 3
+
+/* flow control bitfields */
+#define IFX_SPI_DCD 0
+#define IFX_SPI_CTS 1
+#define IFX_SPI_DSR 2
+#define IFX_SPI_RI 3
+#define IFX_SPI_DTR 4
+#define IFX_SPI_RTS 5
+#define IFX_SPI_TX_FC 6
+#define IFX_SPI_RX_FC 7
+#define IFX_SPI_UPDATE 8
+
+#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \
+ IFX_SPI_HEADER_OVERHEAD)
+
+#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING
+#define IFX_SPI_GPIO_TARGET 0
+#define IFX_SPI_GPIO0 0x105
+
+#define IFX_SPI_STATUS_TIMEOUT (2000*HZ)
+
+/* values for bits in power status byte */
+#define IFX_SPI_POWER_DATA_PENDING 1
+#define IFX_SPI_POWER_SRDY 2
+
+struct ifx_spi_device {
+ /* Our SPI device */
+ struct spi_device *spi_dev;
+
+ /* Port specific data */
+ struct kfifo tx_fifo;
+ spinlock_t fifo_lock;
+ unsigned long signal_state;
+
+ /* TTY Layer logic */
+ struct tty_port tty_port;
+ struct device *tty_dev;
+ int minor;
+
+ /* Low level I/O work */
+ struct tasklet_struct io_work_tasklet;
+ unsigned long flags;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+
+ int is_6160; /* Modem type */
+
+ spinlock_t write_lock;
+ int write_pending;
+ spinlock_t power_lock;
+ unsigned char power_status;
+
+ unsigned char *rx_buffer;
+ unsigned char *tx_buffer;
+ dma_addr_t rx_bus;
+ dma_addr_t tx_bus;
+ unsigned char spi_more;
+ unsigned char spi_slave_cts;
+
+ struct timer_list spi_timer;
+
+ struct spi_message spi_msg;
+ struct spi_transfer spi_xfer;
+
+ struct {
+ /* gpio lines */
+ unsigned short srdy; /* slave-ready gpio */
+ unsigned short mrdy; /* master-ready gpio */
+ unsigned short reset; /* modem-reset gpio */
+ unsigned short po; /* modem-on gpio */
+ unsigned short reset_out; /* modem-in-reset gpio */
+ /* state/stats */
+ int unack_srdy_int_nb;
+ } gpio;
+
+ /* modem reset */
+ unsigned long mdm_reset_state;
+#define MR_START 0
+#define MR_INPROGRESS 1
+#define MR_COMPLETE 2
+ wait_queue_head_t mdm_reset_wait;
+};
+
+#endif /* _IFX6X60_H */
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index d4b711c9a416..25a8bc565f40 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -18,6 +18,7 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
+#include <linux/input.h>
#define MAX_CONFIG_LEN 40
@@ -37,6 +38,62 @@ static struct tty_driver *kgdb_tty_driver;
static int kgdb_tty_line;
#ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ input_reset_device(dev);
+
+ /* Retrun an error - we do not want to bind, just to reset */
+ return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+ /* We do not expect anyone to actually bind to us */
+ BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
+ { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+ .connect = kgdboc_reset_connect,
+ .disconnect = kgdboc_reset_disconnect,
+ .name = "kgdboc_reset",
+ .id_table = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+ /*
+ * We need to take a mutex to prevent several instances of
+ * this work running on different CPUs so they don't try
+ * to register again already registered handler.
+ */
+ mutex_lock(&kgdboc_reset_mutex);
+
+ if (input_register_handler(&kgdboc_reset_handler) == 0)
+ input_unregister_handler(&kgdboc_reset_handler);
+
+ mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+ if (likely(system_state == SYSTEM_RUNNING))
+ schedule_work(&kgdboc_restore_input_work);
+}
+
static int kgdboc_register_kbd(char **cptr)
{
if (strncmp(*cptr, "kbd", 3) == 0) {
@@ -64,10 +121,12 @@ static void kgdboc_unregister_kbd(void)
i--;
}
}
+ flush_work_sync(&kgdboc_restore_input_work);
}
#else /* ! CONFIG_KDB_KEYBOARD */
#define kgdboc_register_kbd(x) 0
#define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
#endif /* ! CONFIG_KDB_KEYBOARD */
static int kgdboc_option_setup(char *opt)
@@ -231,6 +290,7 @@ static void kgdboc_post_exp_handler(void)
dbg_restore_graphics = 0;
con_debug_leave();
}
+ kgdboc_restore_input();
}
static struct kgdb_io kgdboc_io_ops = {
diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c
index 5fc699e929dc..d40010a22ecd 100644
--- a/drivers/serial/mfd.c
+++ b/drivers/serial/mfd.c
@@ -900,8 +900,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
- u32 mul = 0x3600;
- u32 ps = 0x10;
+ u32 ps, mul;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -943,31 +942,24 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
quot = 1;
+ ps = 0x10;
+ mul = 0x3600;
switch (baud) {
case 3500000:
mul = 0x3345;
ps = 0xC;
break;
- case 3000000:
- mul = 0x2EE0;
- break;
- case 2500000:
- mul = 0x2710;
- break;
- case 2000000:
- mul = 0x1F40;
- break;
case 1843200:
mul = 0x2400;
break;
+ case 3000000:
+ case 2500000:
+ case 2000000:
case 1500000:
- mul = 0x1770;
- break;
case 1000000:
- mul = 0xFA0;
- break;
case 500000:
- mul = 0x7D0;
+ /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
+ mul = baud / 500000 * 0x9C4;
break;
default:
/* Use uart_get_divisor to get quot for other baud rates */
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index c4399e23565a..126ec7f568ec 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -838,7 +838,11 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
static const char *
mpc52xx_uart_type(struct uart_port *port)
{
- return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
+ /*
+ * We keep using PORT_MPC52xx for historic reasons although it applies
+ * for MPC512x, too, but print "MPC5xxx" to not irritate users
+ */
+ return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
}
static void
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index f8c816e7725d..8e43a7b69e64 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -686,7 +686,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
msm_port = UART_TO_MSM(port);
msm_port->clk = clk_get(&pdev->dev, "uart_clk");
- if (unlikely(IS_ERR(msm_port->clk)))
+ if (IS_ERR(msm_port->clk))
return PTR_ERR(msm_port->clk);
port->uartclk = clk_get_rate(msm_port->clk);
printk(KERN_INFO "uartclk = %d\n", port->uartclk);
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 17849dcb9adc..5c7abe4c94dd 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -15,6 +15,7 @@
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
index 14365f72b664..7f2f01058789 100644
--- a/drivers/serial/omap-serial.c
+++ b/drivers/serial/omap-serial.c
@@ -570,7 +570,7 @@ serial_omap_configure_xonxoff
unsigned char efr = 0;
up->lcr = serial_in(up, UART_LCR);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
up->efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
@@ -598,7 +598,7 @@ serial_omap_configure_xonxoff
efr |= OMAP_UART_SW_RX;
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
up->mcr = serial_in(up, UART_MCR);
@@ -612,14 +612,14 @@ serial_omap_configure_xonxoff
up->mcr |= UART_MCR_XONANY;
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
/* Enable special char function UARTi.EFR_REG[5] and
* load the new software flow control mode IXON or IXOFF
* and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
*/
serial_out(up, UART_EFR, efr | UART_EFR_SCD);
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
serial_out(up, UART_LCR, up->lcr);
@@ -724,22 +724,22 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
* baud clock is not running
* DLL_REG and DLH_REG set to 0.
*/
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_DLL, 0);
serial_out(up, UART_DLM, 0);
serial_out(up, UART_LCR, 0);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
up->efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
up->mcr = serial_in(up, UART_MCR);
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
/* FIFO ENABLE, DMA MODE */
serial_out(up, UART_FCR, up->fcr);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
if (up->use_dma) {
serial_out(up, UART_TI752_TLR, 0);
@@ -748,52 +748,52 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
}
serial_out(up, UART_EFR, up->efr);
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr);
/* Protocol, Baud Rate, and Interrupt Settings */
- serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
up->efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
serial_out(up, UART_IER, 0);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
serial_out(up, UART_LCR, 0);
serial_out(up, UART_IER, up->ier);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, cval);
if (baud > 230400 && baud != 3000000)
- serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
+ serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE);
else
- serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
+ serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
/* Hardware Flow Control Configuration */
if (termios->c_cflag & CRTSCTS) {
efr |= (UART_EFR_CTS | UART_EFR_RTS);
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
up->mcr = serial_in(up, UART_MCR);
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
up->efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
- serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
serial_out(up, UART_LCR, cval);
}
@@ -815,13 +815,13 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
unsigned char efr;
dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
- serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
/* Enable module level wake up */
@@ -866,12 +866,6 @@ serial_omap_type(struct uart_port *port)
return up->name;
}
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
-static struct uart_omap_port *serial_omap_console_ports[4];
-
-static struct uart_driver serial_omap_reg;
-
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static inline void wait_for_xmitr(struct uart_omap_port *up)
@@ -905,6 +899,34 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
}
}
+#ifdef CONFIG_CONSOLE_POLL
+
+static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ wait_for_xmitr(up);
+ serial_out(up, UART_TX, ch);
+}
+
+static int serial_omap_poll_get_char(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned int status = serial_in(up, UART_LSR);
+
+ if (!(status & UART_LSR_DR))
+ return NO_POLL_CHAR;
+
+ return serial_in(up, UART_RX);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
static void serial_omap_console_putchar(struct uart_port *port, int ch)
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
@@ -1022,6 +1044,10 @@ static struct uart_ops serial_omap_pops = {
.request_port = serial_omap_request_port,
.config_port = serial_omap_config_port,
.verify_port = serial_omap_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_put_char = serial_omap_poll_put_char,
+ .poll_get_char = serial_omap_poll_get_char,
+#endif
};
static struct uart_driver serial_omap_reg = {
diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c
new file mode 100644
index 000000000000..70a61458ec42
--- /dev/null
+++ b/drivers/serial/pch_uart.c
@@ -0,0 +1,1451 @@
+/*
+ *Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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; version 2 of the License.
+ *
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *GNU General Public License for more details.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/dmaengine.h>
+#include <linux/pch_dma.h>
+
+enum {
+ PCH_UART_HANDLED_RX_INT_SHIFT,
+ PCH_UART_HANDLED_TX_INT_SHIFT,
+ PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
+ PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
+ PCH_UART_HANDLED_MS_INT_SHIFT,
+};
+
+enum {
+ PCH_UART_8LINE,
+ PCH_UART_2LINE,
+};
+
+#define PCH_UART_DRIVER_DEVICE "ttyPCH"
+
+#define PCH_UART_NR_GE_256FIFO 1
+#define PCH_UART_NR_GE_64FIFO 3
+#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
+#define PCH_UART_NR PCH_UART_NR_GE
+
+#define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_ERR_INT (1<<((\
+ PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_TRG_INT (1<<((\
+ PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+
+#define PCH_UART_RBR 0x00
+#define PCH_UART_THR 0x00
+
+#define PCH_UART_IER_MASK (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
+ PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
+#define PCH_UART_IER_ERBFI 0x00000001
+#define PCH_UART_IER_ETBEI 0x00000002
+#define PCH_UART_IER_ELSI 0x00000004
+#define PCH_UART_IER_EDSSI 0x00000008
+
+#define PCH_UART_IIR_IP 0x00000001
+#define PCH_UART_IIR_IID 0x00000006
+#define PCH_UART_IIR_MSI 0x00000000
+#define PCH_UART_IIR_TRI 0x00000002
+#define PCH_UART_IIR_RRI 0x00000004
+#define PCH_UART_IIR_REI 0x00000006
+#define PCH_UART_IIR_TOI 0x00000008
+#define PCH_UART_IIR_FIFO256 0x00000020
+#define PCH_UART_IIR_FIFO64 PCH_UART_IIR_FIFO256
+#define PCH_UART_IIR_FE 0x000000C0
+
+#define PCH_UART_FCR_FIFOE 0x00000001
+#define PCH_UART_FCR_RFR 0x00000002
+#define PCH_UART_FCR_TFR 0x00000004
+#define PCH_UART_FCR_DMS 0x00000008
+#define PCH_UART_FCR_FIFO256 0x00000020
+#define PCH_UART_FCR_RFTL 0x000000C0
+
+#define PCH_UART_FCR_RFTL1 0x00000000
+#define PCH_UART_FCR_RFTL64 0x00000040
+#define PCH_UART_FCR_RFTL128 0x00000080
+#define PCH_UART_FCR_RFTL224 0x000000C0
+#define PCH_UART_FCR_RFTL16 PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL32 PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL56 PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL4 PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL8 PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL14 PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL_SHIFT 6
+
+#define PCH_UART_LCR_WLS 0x00000003
+#define PCH_UART_LCR_STB 0x00000004
+#define PCH_UART_LCR_PEN 0x00000008
+#define PCH_UART_LCR_EPS 0x00000010
+#define PCH_UART_LCR_SP 0x00000020
+#define PCH_UART_LCR_SB 0x00000040
+#define PCH_UART_LCR_DLAB 0x00000080
+#define PCH_UART_LCR_NP 0x00000000
+#define PCH_UART_LCR_OP PCH_UART_LCR_PEN
+#define PCH_UART_LCR_EP (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
+#define PCH_UART_LCR_1P (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
+#define PCH_UART_LCR_0P (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
+ PCH_UART_LCR_SP)
+
+#define PCH_UART_LCR_5BIT 0x00000000
+#define PCH_UART_LCR_6BIT 0x00000001
+#define PCH_UART_LCR_7BIT 0x00000002
+#define PCH_UART_LCR_8BIT 0x00000003
+
+#define PCH_UART_MCR_DTR 0x00000001
+#define PCH_UART_MCR_RTS 0x00000002
+#define PCH_UART_MCR_OUT 0x0000000C
+#define PCH_UART_MCR_LOOP 0x00000010
+#define PCH_UART_MCR_AFE 0x00000020
+
+#define PCH_UART_LSR_DR 0x00000001
+#define PCH_UART_LSR_ERR (1<<7)
+
+#define PCH_UART_MSR_DCTS 0x00000001
+#define PCH_UART_MSR_DDSR 0x00000002
+#define PCH_UART_MSR_TERI 0x00000004
+#define PCH_UART_MSR_DDCD 0x00000008
+#define PCH_UART_MSR_CTS 0x00000010
+#define PCH_UART_MSR_DSR 0x00000020
+#define PCH_UART_MSR_RI 0x00000040
+#define PCH_UART_MSR_DCD 0x00000080
+#define PCH_UART_MSR_DELTA (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
+ PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
+
+#define PCH_UART_DLL 0x00
+#define PCH_UART_DLM 0x01
+
+#define DIV_ROUND(a, b) (((a) + ((b)/2)) / (b))
+
+#define PCH_UART_IID_RLS (PCH_UART_IIR_REI)
+#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)
+#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
+#define PCH_UART_IID_THRE (PCH_UART_IIR_TRI)
+#define PCH_UART_IID_MS (PCH_UART_IIR_MSI)
+
+#define PCH_UART_HAL_PARITY_NONE (PCH_UART_LCR_NP)
+#define PCH_UART_HAL_PARITY_ODD (PCH_UART_LCR_OP)
+#define PCH_UART_HAL_PARITY_EVEN (PCH_UART_LCR_EP)
+#define PCH_UART_HAL_PARITY_FIX1 (PCH_UART_LCR_1P)
+#define PCH_UART_HAL_PARITY_FIX0 (PCH_UART_LCR_0P)
+#define PCH_UART_HAL_5BIT (PCH_UART_LCR_5BIT)
+#define PCH_UART_HAL_6BIT (PCH_UART_LCR_6BIT)
+#define PCH_UART_HAL_7BIT (PCH_UART_LCR_7BIT)
+#define PCH_UART_HAL_8BIT (PCH_UART_LCR_8BIT)
+#define PCH_UART_HAL_STB1 0
+#define PCH_UART_HAL_STB2 (PCH_UART_LCR_STB)
+
+#define PCH_UART_HAL_CLR_TX_FIFO (PCH_UART_FCR_TFR)
+#define PCH_UART_HAL_CLR_RX_FIFO (PCH_UART_FCR_RFR)
+#define PCH_UART_HAL_CLR_ALL_FIFO (PCH_UART_HAL_CLR_TX_FIFO | \
+ PCH_UART_HAL_CLR_RX_FIFO)
+
+#define PCH_UART_HAL_DMA_MODE0 0
+#define PCH_UART_HAL_FIFO_DIS 0
+#define PCH_UART_HAL_FIFO16 (PCH_UART_FCR_FIFOE)
+#define PCH_UART_HAL_FIFO256 (PCH_UART_FCR_FIFOE | \
+ PCH_UART_FCR_FIFO256)
+#define PCH_UART_HAL_FIFO64 (PCH_UART_HAL_FIFO256)
+#define PCH_UART_HAL_TRIGGER1 (PCH_UART_FCR_RFTL1)
+#define PCH_UART_HAL_TRIGGER64 (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER128 (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER224 (PCH_UART_FCR_RFTL224)
+#define PCH_UART_HAL_TRIGGER16 (PCH_UART_FCR_RFTL16)
+#define PCH_UART_HAL_TRIGGER32 (PCH_UART_FCR_RFTL32)
+#define PCH_UART_HAL_TRIGGER56 (PCH_UART_FCR_RFTL56)
+#define PCH_UART_HAL_TRIGGER4 (PCH_UART_FCR_RFTL4)
+#define PCH_UART_HAL_TRIGGER8 (PCH_UART_FCR_RFTL8)
+#define PCH_UART_HAL_TRIGGER14 (PCH_UART_FCR_RFTL14)
+#define PCH_UART_HAL_TRIGGER_L (PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER_M (PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER_H (PCH_UART_FCR_RFTL224)
+
+#define PCH_UART_HAL_RX_INT (PCH_UART_IER_ERBFI)
+#define PCH_UART_HAL_TX_INT (PCH_UART_IER_ETBEI)
+#define PCH_UART_HAL_RX_ERR_INT (PCH_UART_IER_ELSI)
+#define PCH_UART_HAL_MS_INT (PCH_UART_IER_EDSSI)
+#define PCH_UART_HAL_ALL_INT (PCH_UART_IER_MASK)
+
+#define PCH_UART_HAL_DTR (PCH_UART_MCR_DTR)
+#define PCH_UART_HAL_RTS (PCH_UART_MCR_RTS)
+#define PCH_UART_HAL_OUT (PCH_UART_MCR_OUT)
+#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP)
+#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE)
+
+struct pch_uart_buffer {
+ unsigned char *buf;
+ int size;
+};
+
+struct eg20t_port {
+ struct uart_port port;
+ int port_type;
+ void __iomem *membase;
+ resource_size_t mapbase;
+ unsigned int iobase;
+ struct pci_dev *pdev;
+ int fifo_size;
+ int base_baud;
+ int start_tx;
+ int start_rx;
+ int tx_empty;
+ int int_dis_flag;
+ int trigger;
+ int trigger_level;
+ struct pch_uart_buffer rxbuf;
+ unsigned int dmsr;
+ unsigned int fcr;
+ unsigned int use_dma;
+ unsigned int use_dma_flag;
+ struct dma_async_tx_descriptor *desc_tx;
+ struct dma_async_tx_descriptor *desc_rx;
+ struct pch_dma_slave param_tx;
+ struct pch_dma_slave param_rx;
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ struct scatterlist sg_tx;
+ struct scatterlist sg_rx;
+ int tx_dma_use;
+ void *rx_buf_virt;
+ dma_addr_t rx_buf_dma;
+};
+
+static unsigned int default_baud = 9600;
+static const int trigger_level_256[4] = { 1, 64, 128, 224 };
+static const int trigger_level_64[4] = { 1, 16, 32, 56 };
+static const int trigger_level_16[4] = { 1, 4, 8, 14 };
+static const int trigger_level_1[4] = { 1, 1, 1, 1 };
+
+static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
+ int base_baud)
+{
+ struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+ priv->trigger_level = 1;
+ priv->fcr = 0;
+}
+
+static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+{
+ unsigned int msr = ioread8(base + UART_MSR);
+ priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+
+ return msr;
+}
+
+static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
+ unsigned int flag)
+{
+ u8 ier = ioread8(priv->membase + UART_IER);
+ ier |= flag & PCH_UART_IER_MASK;
+ iowrite8(ier, priv->membase + UART_IER);
+}
+
+static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
+ unsigned int flag)
+{
+ u8 ier = ioread8(priv->membase + UART_IER);
+ ier &= ~(flag & PCH_UART_IER_MASK);
+ iowrite8(ier, priv->membase + UART_IER);
+}
+
+static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+ unsigned int parity, unsigned int bits,
+ unsigned int stb)
+{
+ unsigned int dll, dlm, lcr;
+ int div;
+
+ div = DIV_ROUND(priv->base_baud / 16, baud);
+ if (div < 0 || USHRT_MAX <= div) {
+ pr_err("Invalid Baud(div=0x%x)\n", div);
+ return -EINVAL;
+ }
+
+ dll = (unsigned int)div & 0x00FFU;
+ dlm = ((unsigned int)div >> 8) & 0x00FFU;
+
+ if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
+ pr_err("Invalid parity(0x%x)\n", parity);
+ return -EINVAL;
+ }
+
+ if (bits & ~PCH_UART_LCR_WLS) {
+ pr_err("Invalid bits(0x%x)\n", bits);
+ return -EINVAL;
+ }
+
+ if (stb & ~PCH_UART_LCR_STB) {
+ pr_err("Invalid STB(0x%x)\n", stb);
+ return -EINVAL;
+ }
+
+ lcr = parity;
+ lcr |= bits;
+ lcr |= stb;
+
+ pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+ __func__, baud, div, lcr, jiffies);
+ iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+ iowrite8(dll, priv->membase + PCH_UART_DLL);
+ iowrite8(dlm, priv->membase + PCH_UART_DLM);
+ iowrite8(lcr, priv->membase + UART_LCR);
+
+ return 0;
+}
+
+static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
+ unsigned int flag)
+{
+ if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
+ pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
+ return -EINVAL;
+ }
+
+ iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
+ iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
+ priv->membase + UART_FCR);
+ iowrite8(priv->fcr, priv->membase + UART_FCR);
+
+ return 0;
+}
+
+static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
+ unsigned int dmamode,
+ unsigned int fifo_size, unsigned int trigger)
+{
+ u8 fcr;
+
+ if (dmamode & ~PCH_UART_FCR_DMS) {
+ pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
+ return -EINVAL;
+ }
+
+ if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
+ pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
+ return -EINVAL;
+ }
+
+ if (trigger & ~PCH_UART_FCR_RFTL) {
+ pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
+ return -EINVAL;
+ }
+
+ switch (priv->fifo_size) {
+ case 256:
+ priv->trigger_level =
+ trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+ break;
+ case 64:
+ priv->trigger_level =
+ trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+ break;
+ case 16:
+ priv->trigger_level =
+ trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+ break;
+ default:
+ priv->trigger_level =
+ trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+ break;
+ }
+ fcr =
+ dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
+ iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
+ iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
+ priv->membase + UART_FCR);
+ iowrite8(fcr, priv->membase + UART_FCR);
+ priv->fcr = fcr;
+
+ return 0;
+}
+
+static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
+{
+ priv->dmsr = 0;
+ return get_msr(priv, priv->membase);
+}
+
+static int pch_uart_hal_write(struct eg20t_port *priv,
+ const unsigned char *buf, int tx_size)
+{
+ int i;
+ unsigned int thr;
+
+ for (i = 0; i < tx_size;) {
+ thr = buf[i++];
+ iowrite8(thr, priv->membase + PCH_UART_THR);
+ }
+ return i;
+}
+
+static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
+ int rx_size)
+{
+ int i;
+ u8 rbr, lsr;
+
+ lsr = ioread8(priv->membase + UART_LSR);
+ for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
+ i < rx_size && lsr & UART_LSR_DR;
+ lsr = ioread8(priv->membase + UART_LSR)) {
+ rbr = ioread8(priv->membase + PCH_UART_RBR);
+ buf[i++] = rbr;
+ }
+ return i;
+}
+
+static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+{
+ unsigned int iir;
+ int ret;
+
+ iir = ioread8(priv->membase + UART_IIR);
+ ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
+ return ret;
+}
+
+static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
+{
+ return ioread8(priv->membase + UART_LSR);
+}
+
+static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
+{
+ unsigned int lcr;
+
+ lcr = ioread8(priv->membase + UART_LCR);
+ if (on)
+ lcr |= PCH_UART_LCR_SB;
+ else
+ lcr &= ~PCH_UART_LCR_SB;
+
+ iowrite8(lcr, priv->membase + UART_LCR);
+}
+
+static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
+ int size)
+{
+ struct uart_port *port;
+ struct tty_struct *tty;
+
+ port = &priv->port;
+ tty = tty_port_tty_get(&port->state->port);
+ if (!tty) {
+ pr_debug("%s:tty is busy now", __func__);
+ return -EBUSY;
+ }
+
+ tty_insert_flip_string(tty, buf, size);
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+
+ return 0;
+}
+
+static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
+{
+ int ret;
+ struct uart_port *port = &priv->port;
+
+ if (port->x_char) {
+ pr_debug("%s:X character send %02x (%lu)\n", __func__,
+ port->x_char, jiffies);
+ buf[0] = port->x_char;
+ port->x_char = 0;
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int dma_push_rx(struct eg20t_port *priv, int size)
+{
+ struct tty_struct *tty;
+ int room;
+ struct uart_port *port = &priv->port;
+
+ port = &priv->port;
+ tty = tty_port_tty_get(&port->state->port);
+ if (!tty) {
+ pr_debug("%s:tty is busy now", __func__);
+ return 0;
+ }
+
+ room = tty_buffer_request_room(tty, size);
+
+ if (room < size)
+ dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+ size - room);
+ if (!room)
+ return room;
+
+ tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
+
+ port->icount.rx += room;
+ tty_kref_put(tty);
+
+ return room;
+}
+
+static void pch_free_dma(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ priv = container_of(port, struct eg20t_port, port);
+
+ if (priv->chan_tx) {
+ dma_release_channel(priv->chan_tx);
+ priv->chan_tx = NULL;
+ }
+ if (priv->chan_rx) {
+ dma_release_channel(priv->chan_rx);
+ priv->chan_rx = NULL;
+ }
+ if (sg_dma_address(&priv->sg_rx))
+ dma_free_coherent(port->dev, port->fifosize,
+ sg_virt(&priv->sg_rx),
+ sg_dma_address(&priv->sg_rx));
+
+ return;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct pch_dma_slave *param = slave;
+
+ if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
+ chan->device->dev)) {
+ chan->private = param;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void pch_request_dma(struct uart_port *port)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ struct pci_dev *dma_dev;
+ struct pch_dma_slave *param;
+ struct eg20t_port *priv =
+ container_of(port, struct eg20t_port, port);
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+ information */
+ /* Set Tx DMA */
+ param = &priv->param_tx;
+ param->dma_dev = &dma_dev->dev;
+ param->chan_id = priv->port.line;
+ param->tx_reg = port->mapbase + UART_TX;
+ chan = dma_request_channel(mask, filter, param);
+ if (!chan) {
+ pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
+ return;
+ }
+ priv->chan_tx = chan;
+
+ /* Set Rx DMA */
+ param = &priv->param_rx;
+ param->dma_dev = &dma_dev->dev;
+ param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
+ param->rx_reg = port->mapbase + UART_RX;
+ chan = dma_request_channel(mask, filter, param);
+ if (!chan) {
+ pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
+ dma_release_channel(priv->chan_tx);
+ return;
+ }
+
+ /* Get Consistent memory for DMA */
+ priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
+ &priv->rx_buf_dma, GFP_KERNEL);
+ priv->chan_rx = chan;
+}
+
+static void pch_dma_rx_complete(void *arg)
+{
+ struct eg20t_port *priv = arg;
+ struct uart_port *port = &priv->port;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+ if (!tty) {
+ pr_debug("%s:tty is busy now", __func__);
+ return;
+ }
+
+ if (dma_push_rx(priv, priv->trigger_level))
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+}
+
+static void pch_dma_tx_complete(void *arg)
+{
+ struct eg20t_port *priv = arg;
+ struct uart_port *port = &priv->port;
+ struct circ_buf *xmit = &port->state->xmit;
+
+ xmit->tail += sg_dma_len(&priv->sg_tx);
+ xmit->tail &= UART_XMIT_SIZE - 1;
+ port->icount.tx += sg_dma_len(&priv->sg_tx);
+
+ async_tx_ack(priv->desc_tx);
+ priv->tx_dma_use = 0;
+}
+
+static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
+{
+ int count = 0;
+ struct uart_port *port = &priv->port;
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
+ goto pop_tx_end;
+
+ do {
+ int cnt_to_end =
+ CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ int sz = min(size - count, cnt_to_end);
+ memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
+ xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
+ count += sz;
+ } while (!uart_circ_empty(xmit) && count < size);
+
+pop_tx_end:
+ pr_debug("%d characters. Remained %d characters. (%lu)\n",
+ count, size - count, jiffies);
+
+ return count;
+}
+
+static int handle_rx_to(struct eg20t_port *priv)
+{
+ struct pch_uart_buffer *buf;
+ int rx_size;
+ int ret;
+ if (!priv->start_rx) {
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+ return 0;
+ }
+ buf = &priv->rxbuf;
+ do {
+ rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
+ ret = push_rx(priv, buf->buf, rx_size);
+ if (ret)
+ return 0;
+ } while (rx_size == buf->size);
+
+ return PCH_UART_HANDLED_RX_INT;
+}
+
+static int handle_rx(struct eg20t_port *priv)
+{
+ return handle_rx_to(priv);
+}
+
+static int dma_handle_rx(struct eg20t_port *priv)
+{
+ struct uart_port *port = &priv->port;
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sg;
+
+ priv = container_of(port, struct eg20t_port, port);
+ sg = &priv->sg_rx;
+
+ sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
+
+ sg_dma_len(sg) = priv->fifo_size;
+
+ sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
+ sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
+ ~PAGE_MASK);
+
+ sg_dma_address(sg) = priv->rx_buf_dma;
+
+ desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+ sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT);
+ if (!desc)
+ return 0;
+
+ priv->desc_rx = desc;
+ desc->callback = pch_dma_rx_complete;
+ desc->callback_param = priv;
+ desc->tx_submit(desc);
+ dma_async_issue_pending(priv->chan_rx);
+
+ return PCH_UART_HANDLED_RX_INT;
+}
+
+static unsigned int handle_tx(struct eg20t_port *priv)
+{
+ struct uart_port *port = &priv->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ int ret;
+ int fifo_size;
+ int tx_size;
+ int size;
+ int tx_empty;
+
+ if (!priv->start_tx) {
+ pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ priv->tx_empty = 1;
+ return 0;
+ }
+
+ fifo_size = max(priv->fifo_size, 1);
+ tx_empty = 1;
+ if (pop_tx_x(priv, xmit->buf)) {
+ pch_uart_hal_write(priv, xmit->buf, 1);
+ port->icount.tx++;
+ tx_empty = 0;
+ fifo_size--;
+ }
+ size = min(xmit->head - xmit->tail, fifo_size);
+ tx_size = pop_tx(priv, xmit->buf, size);
+ if (tx_size > 0) {
+ ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
+ port->icount.tx += ret;
+ tx_empty = 0;
+ }
+
+ priv->tx_empty = tx_empty;
+
+ if (tx_empty)
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+ return PCH_UART_HANDLED_TX_INT;
+}
+
+static unsigned int dma_handle_tx(struct eg20t_port *priv)
+{
+ struct uart_port *port = &priv->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct scatterlist *sg = &priv->sg_tx;
+ int nent;
+ int fifo_size;
+ int tx_empty;
+ struct dma_async_tx_descriptor *desc;
+
+ if (!priv->start_tx) {
+ pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+ priv->tx_empty = 1;
+ return 0;
+ }
+
+ fifo_size = max(priv->fifo_size, 1);
+ tx_empty = 1;
+ if (pop_tx_x(priv, xmit->buf)) {
+ pch_uart_hal_write(priv, xmit->buf, 1);
+ port->icount.tx++;
+ tx_empty = 0;
+ fifo_size--;
+ }
+
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+ priv->tx_dma_use = 1;
+
+ sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
+
+ sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
+ UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
+
+ nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
+ if (!nent) {
+ pr_err("%s:dma_map_sg Failed\n", __func__);
+ return 0;
+ }
+
+ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+ sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+ sg->offset;
+ sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
+ UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE));
+
+ desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+ sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ pr_err("%s:device_prep_slave_sg Failed\n", __func__);
+ return 0;
+ }
+
+ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+ priv->desc_tx = desc;
+ desc->callback = pch_dma_tx_complete;
+ desc->callback_param = priv;
+
+ desc->tx_submit(desc);
+
+ dma_async_issue_pending(priv->chan_tx);
+
+ return PCH_UART_HANDLED_TX_INT;
+}
+
+static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
+{
+ u8 fcr = ioread8(priv->membase + UART_FCR);
+
+ /* Reset FIFO */
+ fcr |= UART_FCR_CLEAR_RCVR;
+ iowrite8(fcr, priv->membase + UART_FCR);
+
+ if (lsr & PCH_UART_LSR_ERR)
+ dev_err(&priv->pdev->dev, "Error data in FIFO\n");
+
+ if (lsr & UART_LSR_FE)
+ dev_err(&priv->pdev->dev, "Framing Error\n");
+
+ if (lsr & UART_LSR_PE)
+ dev_err(&priv->pdev->dev, "Parity Error\n");
+
+ if (lsr & UART_LSR_OE)
+ dev_err(&priv->pdev->dev, "Overrun Error\n");
+}
+
+static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
+{
+ struct eg20t_port *priv = dev_id;
+ unsigned int handled;
+ u8 lsr;
+ int ret = 0;
+ unsigned int iid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->port.lock, flags);
+ handled = 0;
+ while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+ switch (iid) {
+ case PCH_UART_IID_RLS: /* Receiver Line Status */
+ lsr = pch_uart_hal_get_line_status(priv);
+ if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
+ UART_LSR_PE | UART_LSR_OE)) {
+ pch_uart_err_ir(priv, lsr);
+ ret = PCH_UART_HANDLED_RX_ERR_INT;
+ }
+ break;
+ case PCH_UART_IID_RDR: /* Received Data Ready */
+ if (priv->use_dma)
+ ret = dma_handle_rx(priv);
+ else
+ ret = handle_rx(priv);
+ break;
+ case PCH_UART_IID_RDR_TO: /* Received Data Ready
+ (FIFO Timeout) */
+ ret = handle_rx_to(priv);
+ break;
+ case PCH_UART_IID_THRE: /* Transmitter Holding Register
+ Empty */
+ if (priv->use_dma)
+ ret = dma_handle_tx(priv);
+ else
+ ret = handle_tx(priv);
+ break;
+ case PCH_UART_IID_MS: /* Modem Status */
+ ret = PCH_UART_HANDLED_MS_INT;
+ break;
+ default: /* Never junp to this label */
+ pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
+ ret = -1;
+ break;
+ }
+ handled |= (unsigned int)ret;
+ }
+ if (handled == 0 && iid <= 1) {
+ if (priv->int_dis_flag)
+ priv->int_dis_flag = 0;
+ }
+
+ spin_unlock_irqrestore(&priv->port.lock, flags);
+ return IRQ_RETVAL(handled);
+}
+
+/* This function tests whether the transmitter fifo and shifter for the port
+ described by 'port' is empty. */
+static unsigned int pch_uart_tx_empty(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ int ret;
+ priv = container_of(port, struct eg20t_port, port);
+ if (priv->tx_empty)
+ ret = TIOCSER_TEMT;
+ else
+ ret = 0;
+
+ return ret;
+}
+
+/* Returns the current state of modem control inputs. */
+static unsigned int pch_uart_get_mctrl(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ u8 modem;
+ unsigned int ret = 0;
+
+ priv = container_of(port, struct eg20t_port, port);
+ modem = pch_uart_hal_get_modem(priv);
+
+ if (modem & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+
+ if (modem & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+
+ if (modem & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+
+ if (modem & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+
+ return ret;
+}
+
+static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ u32 mcr = 0;
+ unsigned int dat;
+ struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
+
+ if (mctrl & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (mctrl & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (mctrl & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ if (mctrl) {
+ dat = pch_uart_get_mctrl(port);
+ dat |= mcr;
+ iowrite8(dat, priv->membase + UART_MCR);
+ }
+}
+
+static void pch_uart_stop_tx(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ priv = container_of(port, struct eg20t_port, port);
+ priv->start_tx = 0;
+ priv->tx_dma_use = 0;
+}
+
+static void pch_uart_start_tx(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+
+ priv = container_of(port, struct eg20t_port, port);
+
+ if (priv->use_dma)
+ if (priv->tx_dma_use)
+ return;
+
+ priv->start_tx = 1;
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+}
+
+static void pch_uart_stop_rx(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ priv = container_of(port, struct eg20t_port, port);
+ priv->start_rx = 0;
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+ priv->int_dis_flag = 1;
+}
+
+/* Enable the modem status interrupts. */
+static void pch_uart_enable_ms(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ priv = container_of(port, struct eg20t_port, port);
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
+}
+
+/* Control the transmission of a break signal. */
+static void pch_uart_break_ctl(struct uart_port *port, int ctl)
+{
+ struct eg20t_port *priv;
+ unsigned long flags;
+
+ priv = container_of(port, struct eg20t_port, port);
+ spin_lock_irqsave(&port->lock, flags);
+ pch_uart_hal_set_break(priv, ctl);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Grab any interrupt resources and initialise any low level driver state. */
+static int pch_uart_startup(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ int ret;
+ int fifo_size;
+ int trigger_level;
+
+ priv = container_of(port, struct eg20t_port, port);
+ priv->tx_empty = 1;
+ port->uartclk = priv->base_baud;
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+ ret = pch_uart_hal_set_line(priv, default_baud,
+ PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
+ PCH_UART_HAL_STB1);
+ if (ret)
+ return ret;
+
+ switch (priv->fifo_size) {
+ case 256:
+ fifo_size = PCH_UART_HAL_FIFO256;
+ break;
+ case 64:
+ fifo_size = PCH_UART_HAL_FIFO64;
+ break;
+ case 16:
+ fifo_size = PCH_UART_HAL_FIFO16;
+ case 1:
+ default:
+ fifo_size = PCH_UART_HAL_FIFO_DIS;
+ break;
+ }
+
+ switch (priv->trigger) {
+ case PCH_UART_HAL_TRIGGER1:
+ trigger_level = 1;
+ break;
+ case PCH_UART_HAL_TRIGGER_L:
+ trigger_level = priv->fifo_size / 4;
+ break;
+ case PCH_UART_HAL_TRIGGER_M:
+ trigger_level = priv->fifo_size / 2;
+ break;
+ case PCH_UART_HAL_TRIGGER_H:
+ default:
+ trigger_level = priv->fifo_size - (priv->fifo_size / 8);
+ break;
+ }
+
+ priv->trigger_level = trigger_level;
+ ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+ fifo_size, priv->trigger);
+ if (ret < 0)
+ return ret;
+
+ ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, priv);
+ if (ret < 0)
+ return ret;
+
+ if (priv->use_dma)
+ pch_request_dma(port);
+
+ priv->start_rx = 1;
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
+ uart_update_timeout(port, CS8, default_baud);
+
+ return 0;
+}
+
+static void pch_uart_shutdown(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ int ret;
+
+ priv = container_of(port, struct eg20t_port, port);
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+ pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
+ ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+ PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
+ if (ret)
+ pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
+
+ if (priv->use_dma_flag)
+ pch_free_dma(port);
+
+ free_irq(priv->port.irq, priv);
+}
+
+/* Change the port parameters, including word length, parity, stop
+ *bits. Update read_status_mask and ignore_status_mask to indicate
+ *the types of events we are interested in receiving. */
+static void pch_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ int baud;
+ int rtn;
+ unsigned int parity, bits, stb;
+ struct eg20t_port *priv;
+ unsigned long flags;
+
+ priv = container_of(port, struct eg20t_port, port);
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ bits = PCH_UART_HAL_5BIT;
+ break;
+ case CS6:
+ bits = PCH_UART_HAL_6BIT;
+ break;
+ case CS7:
+ bits = PCH_UART_HAL_7BIT;
+ break;
+ default: /* CS8 */
+ bits = PCH_UART_HAL_8BIT;
+ break;
+ }
+ if (termios->c_cflag & CSTOPB)
+ stb = PCH_UART_HAL_STB2;
+ else
+ stb = PCH_UART_HAL_STB1;
+
+ if (termios->c_cflag & PARENB) {
+ if (!(termios->c_cflag & PARODD))
+ parity = PCH_UART_HAL_PARITY_ODD;
+ else
+ parity = PCH_UART_HAL_PARITY_EVEN;
+
+ } else {
+ parity = PCH_UART_HAL_PARITY_NONE;
+ }
+ termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+ rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
+ if (rtn)
+ goto out;
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+out:
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pch_uart_type(struct uart_port *port)
+{
+ return KBUILD_MODNAME;
+}
+
+static void pch_uart_release_port(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+
+ priv = container_of(port, struct eg20t_port, port);
+ pci_iounmap(priv->pdev, priv->membase);
+ pci_release_regions(priv->pdev);
+}
+
+static int pch_uart_request_port(struct uart_port *port)
+{
+ struct eg20t_port *priv;
+ int ret;
+ void __iomem *membase;
+
+ priv = container_of(port, struct eg20t_port, port);
+ ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
+ if (ret < 0)
+ return -EBUSY;
+
+ membase = pci_iomap(priv->pdev, 1, 0);
+ if (!membase) {
+ pci_release_regions(priv->pdev);
+ return -EBUSY;
+ }
+ priv->membase = port->membase = membase;
+
+ return 0;
+}
+
+static void pch_uart_config_port(struct uart_port *port, int type)
+{
+ struct eg20t_port *priv;
+
+ priv = container_of(port, struct eg20t_port, port);
+ if (type & UART_CONFIG_TYPE) {
+ port->type = priv->port_type;
+ pch_uart_request_port(port);
+ }
+}
+
+static int pch_uart_verify_port(struct uart_port *port,
+ struct serial_struct *serinfo)
+{
+ struct eg20t_port *priv;
+
+ priv = container_of(port, struct eg20t_port, port);
+ if (serinfo->flags & UPF_LOW_LATENCY) {
+ pr_info("PCH UART : Use PIO Mode (without DMA)\n");
+ priv->use_dma = 0;
+ serinfo->flags &= ~UPF_LOW_LATENCY;
+ } else {
+#ifndef CONFIG_PCH_DMA
+ pr_err("%s : PCH DMA is not Loaded.\n", __func__);
+ return -EOPNOTSUPP;
+#endif
+ priv->use_dma = 1;
+ priv->use_dma_flag = 1;
+ pr_info("PCH UART : Use DMA Mode\n");
+ }
+
+ return 0;
+}
+
+static struct uart_ops pch_uart_ops = {
+ .tx_empty = pch_uart_tx_empty,
+ .set_mctrl = pch_uart_set_mctrl,
+ .get_mctrl = pch_uart_get_mctrl,
+ .stop_tx = pch_uart_stop_tx,
+ .start_tx = pch_uart_start_tx,
+ .stop_rx = pch_uart_stop_rx,
+ .enable_ms = pch_uart_enable_ms,
+ .break_ctl = pch_uart_break_ctl,
+ .startup = pch_uart_startup,
+ .shutdown = pch_uart_shutdown,
+ .set_termios = pch_uart_set_termios,
+/* .pm = pch_uart_pm, Not supported yet */
+/* .set_wake = pch_uart_set_wake, Not supported yet */
+ .type = pch_uart_type,
+ .release_port = pch_uart_release_port,
+ .request_port = pch_uart_request_port,
+ .config_port = pch_uart_config_port,
+ .verify_port = pch_uart_verify_port
+};
+
+static struct uart_driver pch_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = KBUILD_MODNAME,
+ .dev_name = PCH_UART_DRIVER_DEVICE,
+ .major = 0,
+ .minor = 0,
+ .nr = PCH_UART_NR,
+};
+
+static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
+ int port_type)
+{
+ struct eg20t_port *priv;
+ int ret;
+ unsigned int iobase;
+ unsigned int mapbase;
+ unsigned char *rxbuf;
+ int fifosize, base_baud;
+ static int num;
+
+ priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
+ if (priv == NULL)
+ goto init_port_alloc_err;
+
+ rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!rxbuf)
+ goto init_port_free_txbuf;
+
+ switch (port_type) {
+ case PORT_UNKNOWN:
+ fifosize = 256; /* UART0 */
+ base_baud = 1843200; /* 1.8432MHz */
+ break;
+ case PORT_8250:
+ fifosize = 64; /* UART1~3 */
+ base_baud = 1843200; /* 1.8432MHz */
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
+ goto init_port_hal_free;
+ }
+
+ iobase = pci_resource_start(pdev, 0);
+ mapbase = pci_resource_start(pdev, 1);
+ priv->mapbase = mapbase;
+ priv->iobase = iobase;
+ priv->pdev = pdev;
+ priv->tx_empty = 1;
+ priv->rxbuf.buf = rxbuf;
+ priv->rxbuf.size = PAGE_SIZE;
+
+ priv->fifo_size = fifosize;
+ priv->base_baud = base_baud;
+ priv->port_type = PORT_MAX_8250 + port_type + 1;
+ priv->port.dev = &pdev->dev;
+ priv->port.iobase = iobase;
+ priv->port.membase = NULL;
+ priv->port.mapbase = mapbase;
+ priv->port.irq = pdev->irq;
+ priv->port.iotype = UPIO_PORT;
+ priv->port.ops = &pch_uart_ops;
+ priv->port.flags = UPF_BOOT_AUTOCONF;
+ priv->port.fifosize = fifosize;
+ priv->port.line = num++;
+ priv->trigger = PCH_UART_HAL_TRIGGER_M;
+
+ pci_set_drvdata(pdev, priv);
+ pch_uart_hal_request(pdev, fifosize, base_baud);
+ ret = uart_add_one_port(&pch_uart_driver, &priv->port);
+ if (ret < 0)
+ goto init_port_hal_free;
+
+ return priv;
+
+init_port_hal_free:
+ free_page((unsigned long)rxbuf);
+init_port_free_txbuf:
+ kfree(priv);
+init_port_alloc_err:
+
+ return NULL;
+}
+
+static void pch_uart_exit_port(struct eg20t_port *priv)
+{
+ uart_remove_one_port(&pch_uart_driver, &priv->port);
+ pci_set_drvdata(priv->pdev, NULL);
+ free_page((unsigned long)priv->rxbuf.buf);
+}
+
+static void pch_uart_pci_remove(struct pci_dev *pdev)
+{
+ struct eg20t_port *priv;
+
+ priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+ pch_uart_exit_port(priv);
+ pci_disable_device(pdev);
+ kfree(priv);
+ return;
+}
+#ifdef CONFIG_PM
+static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+ uart_suspend_port(&pch_uart_driver, &priv->port);
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int pch_uart_pci_resume(struct pci_dev *pdev)
+{
+ struct eg20t_port *priv = pci_get_drvdata(pdev);
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
+ return ret;
+ }
+
+ uart_resume_port(&pch_uart_driver, &priv->port);
+
+ return 0;
+}
+#else
+#define pch_uart_pci_suspend NULL
+#define pch_uart_pci_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
+ .driver_data = PCH_UART_8LINE},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
+ .driver_data = PCH_UART_2LINE},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
+ .driver_data = PCH_UART_2LINE},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
+ .driver_data = PCH_UART_2LINE},
+ {0,},
+};
+
+static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret;
+ struct eg20t_port *priv;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto probe_error;
+
+ priv = pch_uart_init_port(pdev, id->driver_data);
+ if (!priv) {
+ ret = -EBUSY;
+ goto probe_disable_device;
+ }
+ pci_set_drvdata(pdev, priv);
+
+ return ret;
+
+probe_disable_device:
+ pci_disable_device(pdev);
+probe_error:
+ return ret;
+}
+
+static struct pci_driver pch_uart_pci_driver = {
+ .name = "pch_uart",
+ .id_table = pch_uart_pci_id,
+ .probe = pch_uart_pci_probe,
+ .remove = __devexit_p(pch_uart_pci_remove),
+ .suspend = pch_uart_pci_suspend,
+ .resume = pch_uart_pci_resume,
+};
+
+static int __init pch_uart_module_init(void)
+{
+ int ret;
+
+ /* register as UART driver */
+ ret = uart_register_driver(&pch_uart_driver);
+ if (ret < 0)
+ return ret;
+
+ /* register as PCI driver */
+ ret = pci_register_driver(&pch_uart_pci_driver);
+ if (ret < 0)
+ uart_unregister_driver(&pch_uart_driver);
+
+ return ret;
+}
+module_init(pch_uart_module_init);
+
+static void __exit pch_uart_module_exit(void)
+{
+ pci_unregister_driver(&pch_uart_pci_driver);
+ uart_unregister_driver(&pch_uart_driver);
+}
+module_exit(pch_uart_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
+module_param(default_baud, uint, S_IRUGO);
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 7ac2bf5167cd..2335edafe903 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -883,10 +883,10 @@ static struct uart_ops s3c24xx_serial_ops = {
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
- .dev_name = "s3c2410_serial",
+ .driver_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
- .driver_name = S3C24XX_SERIAL_NAME,
+ .dev_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c4ea14670d44..460a72d91bb7 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -29,7 +29,6 @@
#include <linux/console.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
#include <linux/serial_core.h>
@@ -1986,7 +1985,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (device_may_wakeup(tty_dev)) {
- enable_irq_wake(uport->irq);
+ if (!enable_irq_wake(uport->irq))
+ uport->irq_wake = 1;
put_device(tty_dev);
mutex_unlock(&port->mutex);
return 0;
@@ -2052,7 +2052,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) {
- disable_irq_wake(uport->irq);
+ if (uport->irq_wake) {
+ disable_irq_wake(uport->irq);
+ uport->irq_wake = 0;
+ }
mutex_unlock(&port->mutex);
return 0;
}
@@ -2135,6 +2138,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_AU:
case UPIO_TSI:
case UPIO_DWAPB:
+ case UPIO_DWAPB32:
snprintf(address, sizeof(address),
"MMIO 0x%llx", (unsigned long long)port->mapbase);
break;
@@ -2555,6 +2559,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
case UPIO_AU:
case UPIO_TSI:
case UPIO_DWAPB:
+ case UPIO_DWAPB32:
return (port1->mapbase == port2->mapbase);
}
return 0;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index c291b3add1d2..92c91c83edde 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -3,7 +3,7 @@
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
- * Copyright (C) 2002 - 2008 Paul Mundt
+ * Copyright (C) 2002 - 2011 Paul Mundt
* Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
@@ -81,14 +81,22 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
+ /* SCSCR initialization */
+ unsigned int scscr;
+
+ /* SCBRR calculation algo */
+ unsigned int scbrr_algo_id;
+
/* Interface clock */
struct clk *iclk;
/* Function clock */
struct clk *fclk;
struct list_head node;
+
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
+
#ifdef CONFIG_SERIAL_SH_SCI_DMA
struct device *dma_dev;
unsigned int slave_tx;
@@ -415,9 +423,9 @@ static void sci_transmit_chars(struct uart_port *port)
if (!(status & SCxSR_TDxE(port))) {
ctrl = sci_in(port, SCSCR);
if (uart_circ_empty(xmit))
- ctrl &= ~SCI_CTRL_FLAGS_TIE;
+ ctrl &= ~SCSCR_TIE;
else
- ctrl |= SCI_CTRL_FLAGS_TIE;
+ ctrl |= SCSCR_TIE;
sci_out(port, SCSCR, ctrl);
return;
}
@@ -459,7 +467,7 @@ static void sci_transmit_chars(struct uart_port *port)
sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
}
- ctrl |= SCI_CTRL_FLAGS_TIE;
+ ctrl |= SCSCR_TIE;
sci_out(port, SCSCR, ctrl);
}
}
@@ -708,7 +716,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
disable_irq_nosync(irq);
scr |= 0x4000;
} else {
- scr &= ~SCI_CTRL_FLAGS_RIE;
+ scr &= ~SCSCR_RIE;
}
sci_out(port, SCSCR, scr);
/* Clear current interrupt */
@@ -777,6 +785,18 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
return IRQ_HANDLED;
}
+static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+{
+ /*
+ * Not all ports (such as SCIFA) will support REIE. Rather than
+ * special-casing the port type, we check the port initialization
+ * IRQ enable mask to see whether the IRQ is desired at all. If
+ * it's unset, it's logically inferred that there's no point in
+ * testing for it.
+ */
+ return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE);
+}
+
static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
unsigned short ssr_status, scr_status, err_enabled;
@@ -786,22 +806,25 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ssr_status = sci_in(port, SCxSR);
scr_status = sci_in(port, SCSCR);
- err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
+ err_enabled = scr_status & port_rx_irq_mask(port);
/* Tx Interrupt */
- if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) &&
+ if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
!s->chan_tx)
ret = sci_tx_interrupt(irq, ptr);
+
/*
* Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
* DR flags
*/
if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
- (scr_status & SCI_CTRL_FLAGS_RIE))
+ (scr_status & SCSCR_RIE))
ret = sci_rx_interrupt(irq, ptr);
+
/* Error Interrupt */
if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
ret = sci_er_interrupt(irq, ptr);
+
/* Break Interrupt */
if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
@@ -951,7 +974,7 @@ static void sci_dma_tx_complete(void *arg)
schedule_work(&s->work_tx);
} else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 ctrl = sci_in(port, SCSCR);
- sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
+ sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
}
spin_unlock_irqrestore(&port->lock, flags);
@@ -1214,14 +1237,16 @@ static void sci_start_tx(struct uart_port *port)
if (new != scr)
sci_out(port, SCSCR, new);
}
+
if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
s->cookie_tx < 0)
schedule_work(&s->work_tx);
#endif
+
if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
- sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
+ sci_out(port, SCSCR, ctrl | SCSCR_TIE);
}
}
@@ -1231,20 +1256,24 @@ static void sci_stop_tx(struct uart_port *port)
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
+
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x8000;
- ctrl &= ~SCI_CTRL_FLAGS_TIE;
+
+ ctrl &= ~SCSCR_TIE;
+
sci_out(port, SCSCR, ctrl);
}
static void sci_start_rx(struct uart_port *port)
{
- unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
+ unsigned short ctrl;
+
+ ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port);
- /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
- ctrl |= sci_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x4000;
+
sci_out(port, SCSCR, ctrl);
}
@@ -1252,11 +1281,13 @@ static void sci_stop_rx(struct uart_port *port)
{
unsigned short ctrl;
- /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
+
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x4000;
- ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
+
+ ctrl &= ~port_rx_irq_mask(port);
+
sci_out(port, SCSCR, ctrl);
}
@@ -1296,7 +1327,7 @@ static void rx_timer_fn(unsigned long arg)
scr &= ~0x4000;
enable_irq(s->irqs[1]);
}
- sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
+ sci_out(port, SCSCR, scr | SCSCR_RIE);
dev_dbg(port->dev, "DMA Rx timed out\n");
schedule_work(&s->work_rx);
}
@@ -1442,12 +1473,31 @@ static void sci_shutdown(struct uart_port *port)
s->disable(port);
}
+static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
+ unsigned long freq)
+{
+ switch (algo_id) {
+ case SCBRR_ALGO_1:
+ return ((freq + 16 * bps) / (16 * bps) - 1);
+ case SCBRR_ALGO_2:
+ return ((freq + 16 * bps) / (32 * bps) - 1);
+ case SCBRR_ALGO_3:
+ return (((freq * 2) + 16 * bps) / (16 * bps) - 1);
+ case SCBRR_ALGO_4:
+ return (((freq * 2) + 16 * bps) / (32 * bps) - 1);
+ case SCBRR_ALGO_5:
+ return (((freq * 1000 / 32) / bps) - 1);
+ }
+
+ /* Warn, but use a safe default */
+ WARN_ON(1);
+ return ((freq + 16 * bps) / (32 * bps) - 1);
+}
+
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
struct sci_port *s = to_sci_port(port);
-#endif
unsigned int status, baud, smr_val, max_baud;
int t = -1;
u16 scfcr = 0;
@@ -1464,7 +1514,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
if (likely(baud && port->uartclk))
- t = SCBRR_VALUE(baud, port->uartclk);
+ t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk);
do {
status = sci_in(port, SCxSR);
@@ -1490,7 +1540,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_out(port, SCSMR, smr_val);
dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
- SCSCR_INIT(port));
+ s->scscr);
if (t > 0) {
if (t >= 256) {
@@ -1506,7 +1556,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_init_pins(port, termios->c_cflag);
sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
- sci_out(port, SCSCR, SCSCR_INIT(port));
+ sci_out(port, SCSCR, s->scscr);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -1679,9 +1729,11 @@ static int __devinit sci_init_single(struct platform_device *dev,
port->mapbase = p->mapbase;
port->membase = p->membase;
- port->irq = p->irqs[SCIx_TXI_IRQ];
- port->flags = p->flags;
- sci_port->type = port->type = p->type;
+ port->irq = p->irqs[SCIx_TXI_IRQ];
+ port->flags = p->flags;
+ sci_port->type = port->type = p->type;
+ sci_port->scscr = p->scscr;
+ sci_port->scbrr_algo_id = p->scbrr_algo_id;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
sci_port->dma_dev = p->dma_dev;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index d2352ac437c5..b223d6cbf33a 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -15,26 +15,17 @@
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 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCIF0 0xA4400000
# define SCIF2 0xA4410000
-# define SCSMR_Ir 0xA44A0000
-# define IRDA_SCIF SCIF0
# define SCPCR 0xA4000116
# define SCPDR 0xA4000136
-
-/* Set the clock source,
- * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
- * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
- */
-# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372)
-# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define PORT_PTCR 0xA405011EUL
# define PORT_PVCR 0xA4050122UL
# define SCIF_ORER 0x0200 /* overrun error bit */
@@ -42,7 +33,6 @@
# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
@@ -52,39 +42,31 @@
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
- 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
- 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define PACR 0xa4050100
# define PBCR 0xa4050102
-# define SCSCR_INIT(port) 0x3B
#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
# define SCSPTR2 0xffe20010 /* 16 bit SCIF */
# define SCSPTR3 0xffe30010 /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
# define PADR 0xA4050120
# define PSDR 0xA405013e
# define PWDR 0xA4050166
# define PSCR 0xA405011E
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */
# define SCSPTR0 SCPDR0
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
# define SCSPTR0 0xa4050160
# define SCSPTR1 0xa405013e
@@ -93,62 +75,38 @@
# define SCSPTR4 0xa4050128
# define SCSPTR5 0xa4050128
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \
- 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
- 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
-# define SCIF_BASE_ADDR 0x01030000
-# define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
# define SCIF_PTR2_OFFS 0x0000020
-# define SCIF_LSR2_OFFS 0x0000024
# define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
-# define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#elif defined(CONFIG_H8S2678)
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
# define SCSPTR0 0xfe4b0020
# define SCSPTR1 0xfe4b0020
# define SCSPTR2 0xfe4b0020
# define SCIF_ORER 0x0001
-# define SCSCR_INIT(port) 0x38
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
# define SCSPTR0 0xff923020 /* 16 bit SCIF */
# define SCSPTR1 0xff924020 /* 16 bit SCIF */
# define SCSPTR2 0xff925020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-
-#if defined(CONFIG_SH_SH2007)
-/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
-# define SCSCR_INIT(port) 0x38
-#else
-/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
-# define SCSCR_INIT(port) 0x3a
-#endif
-
#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
defined(CONFIG_CPU_SUBTYPE_SH7786)
# define SCSPTR0 0xffea0024 /* 16 bit SCIF */
@@ -158,7 +116,6 @@
# define SCSPTR4 0xffee0024 /* 16 bit SCIF */
# define SCSPTR5 0xffef0024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
defined(CONFIG_CPU_SUBTYPE_SH7203) || \
defined(CONFIG_CPU_SUBTYPE_SH7206) || \
@@ -173,52 +130,21 @@
# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
# endif
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
# define SCSPTR0 0xffc30020 /* 16 bit SCIF */
# define SCSPTR1 0xffc40020 /* 16 bit SCIF */
# define SCSPTR2 0xffc50020 /* 16 bit SCIF */
# define SCSPTR3 0xffc60020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#else
# error CPU subtype not defined
#endif
-/* SCSCR */
-#define SCI_CTRL_FLAGS_TIE 0x80 /* all */
-#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
-#define SCI_CTRL_FLAGS_TE 0x20 /* all */
-#define SCI_CTRL_FLAGS_RE 0x10 /* all */
-#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
- defined(CONFIG_CPU_SUBTYPE_SH7091) || \
- defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
- defined(CONFIG_CPU_SUBTYPE_SH7722) || \
- defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
- defined(CONFIG_CPU_SUBTYPE_SH7751) || \
- defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
- defined(CONFIG_CPU_SUBTYPE_SH7763) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785) || \
- defined(CONFIG_CPU_SUBTYPE_SH7786) || \
- defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8)
-#else
-#define SCI_CTRL_FLAGS_REIE 0
-#endif
-/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/* SCI_CTRL_FLAGS_CKE1 0x02 * all */
-/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
-
/* SCxSR SCI */
#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
@@ -244,6 +170,7 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372)
@@ -280,6 +207,7 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372)
@@ -297,23 +225,11 @@
/* SCFCR */
#define SCFCR_RFRST 0x0002
#define SCFCR_TFRST 0x0004
-#define SCFCR_TCRST 0x4000
#define SCFCR_MCE 0x0008
#define SCI_MAJOR 204
#define SCI_MINOR_START 8
-/* Generic serial flags */
-#define SCI_RX_THROTTLE 0x0000001
-
-#define SCI_MAGIC 0xbabeface
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define SCI_EVENT_WRITE_WAKEUP 0
-
#define SCI_IN(size, offset) \
if ((size) == 8) { \
return ioread8(port->membase + (offset)); \
@@ -378,6 +294,7 @@
}
#if defined(CONFIG_CPU_SH3) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372)
@@ -391,6 +308,7 @@
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377)
#define SCIF_FNS(name, scif_offset, scif_size) \
@@ -433,14 +351,13 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c, 8)
-SCIF_FNS(SCFER, 0x10, 16)
SCIF_FNS(SCxSR, 0x14, 16)
SCIF_FNS(SCFCR, 0x18, 16)
SCIF_FNS(SCFDR, 0x1c, 16)
@@ -470,8 +387,6 @@ SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8)
SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16)
SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8)
SCIx_FNS(SCSPTR, 0, 0, 0, 0)
-SCIF_FNS(SCTDSR, 0x0c, 8)
-SCIF_FNS(SCFER, 0x10, 16)
SCIF_FNS(SCFCR, 0x18, 16)
SCIF_FNS(SCFDR, 0x1c, 16)
SCIF_FNS(SCLSR, 0x24, 16)
@@ -497,7 +412,6 @@ SCIF_FNS(SCLSR, 0, 0, 0x28, 16)
#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
SCIF_FNS(SCFDR, 0, 0, 0x1C, 16)
SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16)
-SCIF_FNS(SCLSR2, 0, 0, 0x24, 16)
SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16)
SCIF_FNS(SCSPTR, 0, 0, 0x24, 16)
@@ -591,63 +505,3 @@ static inline int sci_rxd_in(struct uart_port *port)
return 1;
}
#endif
-
-/*
- * Values for the BitRate Register (SCBRR)
- *
- * The values are actually divisors for a frequency which can
- * be internal to the SH3 (14.7456MHz) or derived from an external
- * clock source. This driver assumes the internal clock is used;
- * to support using an external clock source, config options or
- * possibly command-line options would need to be added.
- *
- * Also, to support speeds below 2400 (why?) the lower 2 bits of
- * the SCSMR register would also need to be set to non-zero values.
- *
- * -- Greg Banks 27Feb2000
- *
- * Answer: The SCBRR register is only eight bits, and the value in
- * it gets larger with lower baud rates. At around 2400 (depending on
- * the peripherial module clock) you run out of bits. However the
- * lower two bits of SCSMR allow the module clock to be divided down,
- * scaling the value which is needed in SCBRR.
- *
- * -- Stuart Menefy - 23 May 2000
- *
- * I meant, why would anyone bother with bitrates below 2400.
- *
- * -- Greg Banks - 7Jul2000
- *
- * You "speedist"! How will I use my 110bps ASR-33 teletype with paper
- * tape reader as a console!
- *
- * -- Mitch Davis - 15 Jul 2000
- */
-
-#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785) || \
- defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
- !defined(CONFIG_SH_SH2007)
-#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
- defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372)
-#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
- defined(CONFIG_CPU_SUBTYPE_SH7724)
-static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
-{
- if (port->type == PORT_SCIF)
- return (clk+16*bps)/(32*bps)-1;
- else
- return ((clk*2)+16*bps)/(16*bps)-1;
-}
-#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
-#else /* Generic SH */
-#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
-#endif
diff --git a/drivers/serial/vt8500_serial.c b/drivers/serial/vt8500_serial.c
new file mode 100644
index 000000000000..322bf56c0d89
--- /dev/null
+++ b/drivers/serial/vt8500_serial.c
@@ -0,0 +1,648 @@
+/*
+ * drivers/serial/vt8500_serial.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on msm_serial.c, which is:
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/*
+ * UART Register offsets
+ */
+
+#define VT8500_URTDR 0x0000 /* Transmit data */
+#define VT8500_URRDR 0x0004 /* Receive data */
+#define VT8500_URDIV 0x0008 /* Clock/Baud rate divisor */
+#define VT8500_URLCR 0x000C /* Line control */
+#define VT8500_URICR 0x0010 /* IrDA control */
+#define VT8500_URIER 0x0014 /* Interrupt enable */
+#define VT8500_URISR 0x0018 /* Interrupt status */
+#define VT8500_URUSR 0x001c /* UART status */
+#define VT8500_URFCR 0x0020 /* FIFO control */
+#define VT8500_URFIDX 0x0024 /* FIFO index */
+#define VT8500_URBKR 0x0028 /* Break signal count */
+#define VT8500_URTOD 0x002c /* Time out divisor */
+#define VT8500_TXFIFO 0x1000 /* Transmit FIFO (16x8) */
+#define VT8500_RXFIFO 0x1020 /* Receive FIFO (16x10) */
+
+/*
+ * Interrupt enable and status bits
+ */
+
+#define TXDE (1 << 0) /* Tx Data empty */
+#define RXDF (1 << 1) /* Rx Data full */
+#define TXFAE (1 << 2) /* Tx FIFO almost empty */
+#define TXFE (1 << 3) /* Tx FIFO empty */
+#define RXFAF (1 << 4) /* Rx FIFO almost full */
+#define RXFF (1 << 5) /* Rx FIFO full */
+#define TXUDR (1 << 6) /* Tx underrun */
+#define RXOVER (1 << 7) /* Rx overrun */
+#define PER (1 << 8) /* Parity error */
+#define FER (1 << 9) /* Frame error */
+#define TCTS (1 << 10) /* Toggle of CTS */
+#define RXTOUT (1 << 11) /* Rx timeout */
+#define BKDONE (1 << 12) /* Break signal done */
+#define ERR (1 << 13) /* AHB error response */
+
+#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
+#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR)
+
+struct vt8500_port {
+ struct uart_port uart;
+ char name[16];
+ struct clk *clk;
+ unsigned int ier;
+};
+
+static inline void vt8500_write(struct uart_port *port, unsigned int val,
+ unsigned int off)
+{
+ writel(val, port->membase + off);
+}
+
+static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
+{
+ return readl(port->membase + off);
+}
+
+static void vt8500_stop_tx(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port = container_of(port,
+ struct vt8500_port,
+ uart);
+
+ vt8500_port->ier &= ~TX_FIFO_INTS;
+ vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_stop_rx(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port = container_of(port,
+ struct vt8500_port,
+ uart);
+
+ vt8500_port->ier &= ~RX_FIFO_INTS;
+ vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_enable_ms(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port = container_of(port,
+ struct vt8500_port,
+ uart);
+
+ vt8500_port->ier |= TCTS;
+ vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+ if (!tty) {
+ /* Discard data: no tty available */
+ int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
+ u16 ch;
+ while (count--)
+ ch = readw(port->membase + VT8500_RXFIFO);
+ return;
+ }
+
+ /*
+ * Handle overrun
+ */
+ if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+
+ /* and now the main RX loop */
+ while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
+ unsigned int c;
+ char flag = TTY_NORMAL;
+
+ c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
+
+ /* Mask conditions we're ignorning. */
+ c &= ~port->read_status_mask;
+
+ if (c & FER) {
+ port->icount.frame++;
+ flag = TTY_FRAME;
+ } else if (c & PER) {
+ port->icount.parity++;
+ flag = TTY_PARITY;
+ }
+ port->icount.rx++;
+
+ if (!uart_handle_sysrq_char(port, c))
+ tty_insert_flip_char(tty, c, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (port->x_char) {
+ writeb(port->x_char, port->membase + VT8500_TXFIFO);
+ port->icount.tx++;
+ port->x_char = 0;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ vt8500_stop_tx(port);
+ return;
+ }
+
+ while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
+ if (uart_circ_empty(xmit))
+ break;
+
+ writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ vt8500_stop_tx(port);
+}
+
+static void vt8500_start_tx(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port = container_of(port,
+ struct vt8500_port,
+ uart);
+
+ vt8500_port->ier &= ~TX_FIFO_INTS;
+ vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+ handle_tx(port);
+ vt8500_port->ier |= TX_FIFO_INTS;
+ vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+ port->icount.cts++;
+ wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t vt8500_irq(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned long isr;
+
+ spin_lock(&port->lock);
+ isr = vt8500_read(port, VT8500_URISR);
+
+ /* Acknowledge active status bits */
+ vt8500_write(port, isr, VT8500_URISR);
+
+ if (isr & RX_FIFO_INTS)
+ handle_rx(port);
+ if (isr & TX_FIFO_INTS)
+ handle_tx(port);
+ if (isr & TCTS)
+ handle_delta_cts(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int vt8500_tx_empty(struct uart_port *port)
+{
+ return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
+ TIOCSER_TEMT : 0;
+}
+
+static unsigned int vt8500_get_mctrl(struct uart_port *port)
+{
+ unsigned int usr;
+
+ usr = vt8500_read(port, VT8500_URUSR);
+ if (usr & (1 << 4))
+ return TIOCM_CTS;
+ else
+ return 0;
+}
+
+static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
+{
+ if (break_ctl)
+ vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+ VT8500_URLCR);
+}
+
+static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+ unsigned long div;
+ unsigned int loops = 1000;
+
+ div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+
+ if (unlikely((baud < 900) || (baud > 921600)))
+ div |= 7;
+ else
+ div |= (921600 / baud) - 1;
+
+ while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
+ cpu_relax();
+ vt8500_write(port, div, VT8500_URDIV);
+
+ return baud;
+}
+
+static int vt8500_startup(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port =
+ container_of(port, struct vt8500_port, uart);
+ int ret;
+
+ snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+ "vt8500_serial%d", port->line);
+
+ ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
+ vt8500_port->name, port);
+ if (unlikely(ret))
+ return ret;
+
+ vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */
+
+ return 0;
+}
+
+static void vt8500_shutdown(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port =
+ container_of(port, struct vt8500_port, uart);
+
+ vt8500_port->ier = 0;
+
+ /* disable interrupts and FIFOs */
+ vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
+ vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
+ free_irq(port->irq, port);
+}
+
+static void vt8500_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct vt8500_port *vt8500_port =
+ container_of(port, struct vt8500_port, uart);
+ unsigned long flags;
+ unsigned int baud, lcr;
+ unsigned int loops = 1000;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* calculate and set baud rate */
+ baud = uart_get_baud_rate(port, termios, old, 900, 921600);
+ baud = vt8500_set_baud_rate(port, baud);
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+ /* calculate parity */
+ lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
+ lcr &= ~((1 << 5) | (1 << 4));
+ if (termios->c_cflag & PARENB) {
+ lcr |= (1 << 4);
+ termios->c_cflag &= ~CMSPAR;
+ if (termios->c_cflag & PARODD)
+ lcr |= (1 << 5);
+ }
+
+ /* calculate bits per char */
+ lcr &= ~(1 << 2);
+ switch (termios->c_cflag & CSIZE) {
+ case CS7:
+ break;
+ case CS8:
+ default:
+ lcr |= (1 << 2);
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
+ break;
+ }
+
+ /* calculate stop bits */
+ lcr &= ~(1 << 3);
+ if (termios->c_cflag & CSTOPB)
+ lcr |= (1 << 3);
+
+ /* set parity, bits per char, and stop bit */
+ vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
+
+ /* Configure status bits to ignore based on termio flags. */
+ port->read_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->read_status_mask = FER | PER;
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /* Reset FIFOs */
+ vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
+ while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
+ && --loops)
+ cpu_relax();
+
+ /* Every possible FIFO-related interrupt */
+ vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
+
+ /*
+ * CTS flow control
+ */
+ if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
+ vt8500_port->ier |= TCTS;
+
+ vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
+ vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *vt8500_type(struct uart_port *port)
+{
+ struct vt8500_port *vt8500_port =
+ container_of(port, struct vt8500_port, uart);
+ return vt8500_port->name;
+}
+
+static void vt8500_release_port(struct uart_port *port)
+{
+}
+
+static int vt8500_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void vt8500_config_port(struct uart_port *port, int flags)
+{
+ port->type = PORT_VT8500;
+}
+
+static int vt8500_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
+ return -EINVAL;
+ if (unlikely(port->irq != ser->irq))
+ return -EINVAL;
+ return 0;
+}
+
+static struct vt8500_port *vt8500_uart_ports[4];
+static struct uart_driver vt8500_uart_driver;
+
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = vt8500_read(port, VT8500_URFIDX);
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (status & 0x10);
+}
+
+static void vt8500_console_putchar(struct uart_port *port, int c)
+{
+ wait_for_xmitr(port);
+ writeb(c, port->membase + VT8500_TXFIFO);
+}
+
+static void vt8500_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
+ unsigned long ier;
+
+ BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
+
+ ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
+ vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
+
+ uart_console_write(&vt8500_port->uart, s, count,
+ vt8500_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and switch back to FIFO
+ */
+ wait_for_xmitr(&vt8500_port->uart);
+ vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
+}
+
+static int __init vt8500_console_setup(struct console *co, char *options)
+{
+ struct vt8500_port *vt8500_port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
+ return -ENXIO;
+
+ vt8500_port = vt8500_uart_ports[co->index];
+
+ if (!vt8500_port)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&vt8500_port->uart,
+ co, baud, parity, bits, flow);
+}
+
+static struct console vt8500_console = {
+ .name = "ttyWMT",
+ .write = vt8500_console_write,
+ .device = uart_console_device,
+ .setup = vt8500_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &vt8500_uart_driver,
+};
+
+#define VT8500_CONSOLE (&vt8500_console)
+
+#else
+#define VT8500_CONSOLE NULL
+#endif
+
+static struct uart_ops vt8500_uart_pops = {
+ .tx_empty = vt8500_tx_empty,
+ .set_mctrl = vt8500_set_mctrl,
+ .get_mctrl = vt8500_get_mctrl,
+ .stop_tx = vt8500_stop_tx,
+ .start_tx = vt8500_start_tx,
+ .stop_rx = vt8500_stop_rx,
+ .enable_ms = vt8500_enable_ms,
+ .break_ctl = vt8500_break_ctl,
+ .startup = vt8500_startup,
+ .shutdown = vt8500_shutdown,
+ .set_termios = vt8500_set_termios,
+ .type = vt8500_type,
+ .release_port = vt8500_release_port,
+ .request_port = vt8500_request_port,
+ .config_port = vt8500_config_port,
+ .verify_port = vt8500_verify_port,
+};
+
+static struct uart_driver vt8500_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "vt8500_serial",
+ .dev_name = "ttyWMT",
+ .nr = 6,
+ .cons = VT8500_CONSOLE,
+};
+
+static int __init vt8500_serial_probe(struct platform_device *pdev)
+{
+ struct vt8500_port *vt8500_port;
+ struct resource *mmres, *irqres;
+ int ret;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mmres || !irqres)
+ return -ENODEV;
+
+ vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
+ if (!vt8500_port)
+ return -ENOMEM;
+
+ vt8500_port->uart.type = PORT_VT8500;
+ vt8500_port->uart.iotype = UPIO_MEM;
+ vt8500_port->uart.mapbase = mmres->start;
+ vt8500_port->uart.irq = irqres->start;
+ vt8500_port->uart.fifosize = 16;
+ vt8500_port->uart.ops = &vt8500_uart_pops;
+ vt8500_port->uart.line = pdev->id;
+ vt8500_port->uart.dev = &pdev->dev;
+ vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+ vt8500_port->uart.uartclk = 24000000;
+
+ snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+ "VT8500 UART%d", pdev->id);
+
+ vt8500_port->uart.membase = ioremap(mmres->start,
+ mmres->end - mmres->start + 1);
+ if (!vt8500_port->uart.membase) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ vt8500_uart_ports[pdev->id] = vt8500_port;
+
+ uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+
+ platform_set_drvdata(pdev, vt8500_port);
+
+ return 0;
+
+err:
+ kfree(vt8500_port);
+ return ret;
+}
+
+static int __devexit vt8500_serial_remove(struct platform_device *pdev)
+{
+ struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+ kfree(vt8500_port);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_platform_driver = {
+ .probe = vt8500_serial_probe,
+ .remove = vt8500_serial_remove,
+ .driver = {
+ .name = "vt8500_serial",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init vt8500_serial_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&vt8500_uart_driver);
+ if (unlikely(ret))
+ return ret;
+
+ ret = platform_driver_register(&vt8500_platform_driver);
+
+ if (unlikely(ret))
+ uart_unregister_driver(&vt8500_uart_driver);
+
+ return ret;
+}
+
+static void __exit vt8500_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+ unregister_console(&vt8500_console);
+#endif
+ platform_driver_unregister(&vt8500_platform_driver);
+ uart_unregister_driver(&vt8500_uart_driver);
+}
+
+module_init(vt8500_serial_init);
+module_exit(vt8500_serial_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("Driver for vt8500 serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index ceba593dc84f..04113e5304a0 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -101,7 +101,7 @@ static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
return NULL;
if (sfi_use_ioremap)
- return ioremap(phys, size);
+ return ioremap_cache(phys, size);
else
return early_ioremap(phys, size);
}
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index fd0d1b98901c..5f63c3b83828 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/list.h>
-#include <linux/kobject.h>
#include <linux/sysdev.h>
#include <linux/seq_file.h>
#include <linux/err.h>
@@ -90,8 +89,8 @@ struct clk_rate_round_data {
static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
{
unsigned long rate_error, rate_error_prev = ~0UL;
- unsigned long rate_best_fit = rounder->rate;
unsigned long highest, lowest, freq;
+ long rate_best_fit = -ENOENT;
int i;
highest = 0;
@@ -146,7 +145,7 @@ long clk_rate_table_round(struct clk *clk,
};
if (clk->nr_freqs < 1)
- return 0;
+ return -ENOSYS;
return clk_rate_round_helper(&table_round);
}
@@ -418,8 +417,11 @@ int clk_register(struct clk *clk)
list_add(&clk->sibling, &root_clks);
list_add(&clk->node, &clock_list);
+
+#ifdef CONFIG_SH_CLK_CPG_LEGACY
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+#endif
out_unlock:
mutex_unlock(&clock_list_sem);
@@ -455,19 +457,13 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- return clk_set_rate_ex(clk, rate, 0);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
-{
int ret = -EOPNOTSUPP;
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
if (likely(clk->ops && clk->ops->set_rate)) {
- ret = clk->ops->set_rate(clk, rate, algo_id);
+ ret = clk->ops->set_rate(clk, rate);
if (ret != 0)
goto out_unlock;
} else {
@@ -485,7 +481,7 @@ out_unlock:
return ret;
}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+EXPORT_SYMBOL_GPL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
@@ -541,6 +537,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_round_rate);
+long clk_round_parent(struct clk *clk, unsigned long target,
+ unsigned long *best_freq, unsigned long *parent_freq,
+ unsigned int div_min, unsigned int div_max)
+{
+ struct cpufreq_frequency_table *freq, *best = NULL;
+ unsigned long error = ULONG_MAX, freq_high, freq_low, div;
+ struct clk *parent = clk_get_parent(clk);
+
+ if (!parent) {
+ *parent_freq = 0;
+ *best_freq = clk_round_rate(clk, target);
+ return abs(target - *best_freq);
+ }
+
+ for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
+ freq++) {
+ if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ if (unlikely(freq->frequency / target <= div_min - 1)) {
+ unsigned long freq_max;
+
+ freq_max = (freq->frequency + div_min / 2) / div_min;
+ if (error > target - freq_max) {
+ error = target - freq_max;
+ best = freq;
+ if (best_freq)
+ *best_freq = freq_max;
+ }
+
+ pr_debug("too low freq %u, error %lu\n", freq->frequency,
+ target - freq_max);
+
+ if (!error)
+ break;
+
+ continue;
+ }
+
+ if (unlikely(freq->frequency / target >= div_max)) {
+ unsigned long freq_min;
+
+ freq_min = (freq->frequency + div_max / 2) / div_max;
+ if (error > freq_min - target) {
+ error = freq_min - target;
+ best = freq;
+ if (best_freq)
+ *best_freq = freq_min;
+ }
+
+ pr_debug("too high freq %u, error %lu\n", freq->frequency,
+ freq_min - target);
+
+ if (!error)
+ break;
+
+ continue;
+ }
+
+ div = freq->frequency / target;
+ freq_high = freq->frequency / div;
+ freq_low = freq->frequency / (div + 1);
+
+ if (freq_high - target < error) {
+ error = freq_high - target;
+ best = freq;
+ if (best_freq)
+ *best_freq = freq_high;
+ }
+
+ if (target - freq_low < error) {
+ error = target - freq_low;
+ best = freq;
+ if (best_freq)
+ *best_freq = freq_low;
+ }
+
+ pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
+ freq->frequency, div, freq_high, div + 1, freq_low,
+ *best_freq, best->frequency);
+
+ if (!error)
+ break;
+ }
+
+ if (parent_freq)
+ *parent_freq = best->frequency;
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(clk_round_parent);
+
#ifdef CONFIG_PM
static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
{
@@ -561,8 +649,7 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
clkp->ops->set_parent(clkp,
clkp->parent);
if (likely(clkp->ops->set_rate))
- clkp->ops->set_rate(clkp,
- rate, NO_CHANGE);
+ clkp->ops->set_rate(clkp, rate);
else if (likely(clkp->ops->recalc))
clkp->rate = clkp->ops->recalc(clkp);
}
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 3aea5f0ceb09..6172335ae323 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -110,8 +110,7 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
-static int sh_clk_div6_set_rate(struct clk *clk,
- unsigned long rate, int algo_id)
+static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long value;
int idx;
@@ -132,7 +131,7 @@ static int sh_clk_div6_enable(struct clk *clk)
unsigned long value;
int ret;
- ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+ ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
value = __raw_readl(clk->enable_reg);
value &= ~0x100; /* clear stop bit to enable clock */
@@ -253,7 +252,7 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
-static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
{
struct clk_div4_table *d4t = clk->priv;
unsigned long value;
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 873a99ff8f64..9739431092d1 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
* Register the IRQ position with the global IRQ map, then insert
* it in to the radix tree.
*/
- irq_reserve_irqs(irq, 1);
+ irq_reserve_irq(irq);
raw_spin_lock_irqsave(&intc_big_lock, flags);
radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
@@ -198,6 +198,7 @@ int __init register_intc_controller(struct intc_desc *desc)
list_add_tail(&d->list, &intc_list);
raw_spin_lock_init(&d->lock);
+ INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);
d->index = nr_intc_controllers;
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 4187cce20ffd..a3677c9dfe36 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
int i;
for (i = 0; i < nr_vecs; i++)
- irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+ irq_reserve_irq(evt2irq(vectors[i].vect));
}
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index e5bf5d3c698e..4e0ff7181164 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -215,7 +215,7 @@ restart:
entry = radix_tree_deref_slot((void **)entries[i]);
if (unlikely(!entry))
continue;
- if (unlikely(entry == RADIX_TREE_RETRY))
+ if (radix_tree_deref_retry(entry))
goto restart;
irq = create_irq();
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 78f9fd02c1b2..13bfa9d48082 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -111,11 +111,14 @@ config SPI_COLDFIRE_QSPI
will be called coldfire_qspi.
config SPI_DAVINCI
- tristate "SPI controller driver for DaVinci/DA8xx SoC's"
+ tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on SPI_MASTER && ARCH_DAVINCI
select SPI_BITBANG
help
- SPI master controller for DaVinci and DA8xx SPI modules.
+ SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+
+ This driver can also be built as a module. The module will be called
+ davinci_spi.
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
@@ -153,10 +156,10 @@ config SPI_IMX_VER_0_4
def_bool y if ARCH_MX31
config SPI_IMX_VER_0_7
- def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51
+ def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 || ARCH_MX53
config SPI_IMX_VER_2_3
- def_bool y if ARCH_MX51
+ def_bool y if ARCH_MX51 || ARCH_MX53
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
@@ -267,12 +270,15 @@ config SPI_PPC4xx
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on ARCH_PXA && EXPERIMENTAL
- select PXA_SSP
+ depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
+ select PXA_SSP if ARCH_PXA
help
- This enables using a PXA2xx SSP port as a SPI master controller.
- The driver can be configured to use any SSP port and additional
- documentation can be found a Documentation/spi/pxa2xx.
+ This enables using a PXA2xx or Sodaville SSP port as a SPI master
+ controller. The driver can be configured to use any SSP port and
+ additional documentation can be found a Documentation/spi/pxa2xx.
+
+config SPI_PXA2XX_PCI
+ def_bool SPI_PXA2XX && X86_32 && PCI
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
@@ -304,8 +310,8 @@ config SPI_S3C24XX_GPIO
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
- depends on ARCH_S3C64XX && EXPERIMENTAL
- select S3C64XX_DMA
+ depends on (ARCH_S3C64XX || ARCH_S5P64X0)
+ select S3C64XX_DMA if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
@@ -353,7 +359,6 @@ config SPI_XILINX
tristate "Xilinx SPI controller common module"
depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG
- select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
help
This exposes the SPI controller IP from the Xilinx EDK.
@@ -362,19 +367,6 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
-config SPI_XILINX_OF
- tristate "Xilinx SPI controller OF device"
- depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
- help
- This is the OF driver for the SPI controller IP from the Xilinx EDK.
-
-config SPI_XILINX_PLTFM
- tristate "Xilinx SPI controller platform device"
- depends on SPI_XILINX
- help
- This is the platform driver for the SPI controller IP
- from the Xilinx EDK.
-
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900 && EXPERIMENTAL
@@ -396,6 +388,10 @@ config SPI_DW_PCI
tristate "PCI interface driver for DW SPI core"
depends on SPI_DESIGNWARE && PCI
+config SPI_DW_MID_DMA
+ bool "DMA support for DW SPI controller on Intel Moorestown platform"
+ depends on SPI_DW_PCI && INTEL_MID_DMAC
+
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE && HAVE_CLK
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8bc1a5abac1f..3a42463c92a4 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,13 +17,15 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o
obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o
obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
-obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
+obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o
+dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o
obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
+obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o
@@ -43,8 +45,6 @@ obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
-obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
-obj-$(CONFIG_SPI_XILINX_PLTFM) += xilinx_spi_pltfm.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index fb3d1b31772d..71a1219a995d 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -253,11 +253,6 @@
#define STATE_ERROR ((void *) -1)
/*
- * Queue State
- */
-#define QUEUE_RUNNING (0)
-#define QUEUE_STOPPED (1)
-/*
* SSP State - Whether Enabled or Disabled
*/
#define SSP_DISABLED (0)
@@ -344,7 +339,7 @@ struct vendor_data {
* @lock: spinlock to syncronise access to driver data
* @workqueue: a workqueue on which any spi_message request is queued
* @busy: workqueue is busy
- * @run: workqueue is running
+ * @running: workqueue is running
* @pump_transfers: Tasklet used in Interrupt Transfer mode
* @cur_msg: Pointer to current spi_message being processed
* @cur_transfer: Pointer to current spi_transfer
@@ -369,8 +364,8 @@ struct pl022 {
struct work_struct pump_messages;
spinlock_t queue_lock;
struct list_head queue;
- int busy;
- int run;
+ bool busy;
+ bool running;
/* Message transfer pump */
struct tasklet_struct pump_transfers;
struct spi_message *cur_msg;
@@ -782,9 +777,9 @@ static void *next_transfer(struct pl022 *pl022)
static void unmap_free_dma_scatter(struct pl022 *pl022)
{
/* Unmap and free the SG tables */
- dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE);
- dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_rx.nents, DMA_FROM_DEVICE);
sg_free_table(&pl022->sgt_rx);
sg_free_table(&pl022->sgt_tx);
@@ -917,7 +912,7 @@ static int configure_dma(struct pl022 *pl022)
};
unsigned int pages;
int ret;
- int sglen;
+ int rx_sglen, tx_sglen;
struct dma_chan *rxchan = pl022->dma_rx_channel;
struct dma_chan *txchan = pl022->dma_tx_channel;
struct dma_async_tx_descriptor *rxdesc;
@@ -956,7 +951,7 @@ static int configure_dma(struct pl022 *pl022)
tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case WRITING_U32:
- tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;;
+ tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
break;
}
@@ -991,20 +986,20 @@ static int configure_dma(struct pl022 *pl022)
pl022->cur_transfer->len, &pl022->sgt_tx);
/* Map DMA buffers */
- sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_rx.nents, DMA_FROM_DEVICE);
- if (!sglen)
+ if (!rx_sglen)
goto err_rx_sgmap;
- sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE);
- if (!sglen)
+ if (!tx_sglen)
goto err_tx_sgmap;
/* Send both scatterlists */
rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
pl022->sgt_rx.sgl,
- pl022->sgt_rx.nents,
+ rx_sglen,
DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc)
@@ -1012,7 +1007,7 @@ static int configure_dma(struct pl022 *pl022)
txdesc = txchan->device->device_prep_slave_sg(txchan,
pl022->sgt_tx.sgl,
- pl022->sgt_tx.nents,
+ tx_sglen,
DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc)
@@ -1040,10 +1035,10 @@ err_txdesc:
txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
err_rxdesc:
rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
- dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE);
err_tx_sgmap:
- dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_tx.nents, DMA_FROM_DEVICE);
err_rx_sgmap:
sg_free_table(&pl022->sgt_tx);
@@ -1460,8 +1455,8 @@ static void pump_messages(struct work_struct *work)
/* Lock queue and check for queue work */
spin_lock_irqsave(&pl022->queue_lock, flags);
- if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) {
- pl022->busy = 0;
+ if (list_empty(&pl022->queue) || !pl022->running) {
+ pl022->busy = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
return;
}
@@ -1475,7 +1470,7 @@ static void pump_messages(struct work_struct *work)
list_entry(pl022->queue.next, struct spi_message, queue);
list_del_init(&pl022->cur_msg->queue);
- pl022->busy = 1;
+ pl022->busy = true;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
/* Initial message state */
@@ -1507,8 +1502,8 @@ static int __init init_queue(struct pl022 *pl022)
INIT_LIST_HEAD(&pl022->queue);
spin_lock_init(&pl022->queue_lock);
- pl022->run = QUEUE_STOPPED;
- pl022->busy = 0;
+ pl022->running = false;
+ pl022->busy = false;
tasklet_init(&pl022->pump_transfers,
pump_transfers, (unsigned long)pl022);
@@ -1529,12 +1524,12 @@ static int start_queue(struct pl022 *pl022)
spin_lock_irqsave(&pl022->queue_lock, flags);
- if (pl022->run == QUEUE_RUNNING || pl022->busy) {
+ if (pl022->running || pl022->busy) {
spin_unlock_irqrestore(&pl022->queue_lock, flags);
return -EBUSY;
}
- pl022->run = QUEUE_RUNNING;
+ pl022->running = true;
pl022->cur_msg = NULL;
pl022->cur_transfer = NULL;
pl022->cur_chip = NULL;
@@ -1566,7 +1561,8 @@ static int stop_queue(struct pl022 *pl022)
if (!list_empty(&pl022->queue) || pl022->busy)
status = -EBUSY;
- else pl022->run = QUEUE_STOPPED;
+ else
+ pl022->running = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
@@ -1684,7 +1680,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
spin_lock_irqsave(&pl022->queue_lock, flags);
- if (pl022->run == QUEUE_STOPPED) {
+ if (!pl022->running) {
spin_unlock_irqrestore(&pl022->queue_lock, flags);
return -ESHUTDOWN;
}
@@ -1693,7 +1689,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
msg->state = STATE_START;
list_add_tail(&msg->queue, &pl022->queue);
- if (pl022->run == QUEUE_RUNNING && !pl022->busy)
+ if (pl022->running && !pl022->busy)
queue_work(pl022->workqueue, &pl022->pump_messages);
spin_unlock_irqrestore(&pl022->queue_lock, flags);
@@ -1799,7 +1795,7 @@ static int pl022_setup(struct spi_device *spi)
{
struct pl022_config_chip const *chip_info;
struct chip_data *chip;
- struct ssp_clock_params clk_freq;
+ struct ssp_clock_params clk_freq = {0, };
int status = 0;
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
unsigned int bits = spi->bits_per_word;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 154529aacc03..1a478bf88c9d 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -341,9 +341,9 @@ static void atmel_spi_next_message(struct spi_master *master)
/*
* For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
* - The buffer is either valid for CPU access, else NULL
- * - If the buffer is valid, so is its DMA addresss
+ * - If the buffer is valid, so is its DMA address
*
- * This driver manages the dma addresss unless message->is_dma_mapped.
+ * This driver manages the dma address unless message->is_dma_mapped.
*/
static int
atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
@@ -352,8 +352,12 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
if (xfer->tx_buf) {
+ /* tx_buf is a const void* where we need a void * for the dma
+ * mapping */
+ void *nonconst_tx = (void *)xfer->tx_buf;
+
xfer->tx_dma = dma_map_single(dev,
- (void *) xfer->tx_buf, xfer->len,
+ nonconst_tx, xfer->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma))
return -ENOMEM;
diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c
index 052b3c7fa6a0..8856bcca9d29 100644
--- a/drivers/spi/coldfire_qspi.c
+++ b/drivers/spi/coldfire_qspi.c
@@ -317,7 +317,7 @@ static void mcfqspi_work(struct work_struct *work)
msg = container_of(mcfqspi->msgq.next, struct spi_message,
queue);
- list_del_init(&mcfqspi->msgq);
+ list_del_init(&msg->queue);
spin_unlock_irqrestore(&mcfqspi->lock, flags);
spi = msg->spi;
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index b85090caf7cf..6beab99bf95b 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 Texas Instruments.
+ * Copyright (C) 2010 EF Johnson Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,11 +39,6 @@
#define CS_DEFAULT 0xFF
-#define SPI_BUFSIZ (SMP_CACHE_BYTES + 1)
-#define DAVINCI_DMA_DATA_TYPE_S8 0x01
-#define DAVINCI_DMA_DATA_TYPE_S16 0x02
-#define DAVINCI_DMA_DATA_TYPE_S32 0x04
-
#define SPIFMT_PHASE_MASK BIT(16)
#define SPIFMT_POLARITY_MASK BIT(17)
#define SPIFMT_DISTIMER_MASK BIT(18)
@@ -52,34 +48,43 @@
#define SPIFMT_ODD_PARITY_MASK BIT(23)
#define SPIFMT_WDELAY_MASK 0x3f000000u
#define SPIFMT_WDELAY_SHIFT 24
-#define SPIFMT_CHARLEN_MASK 0x0000001Fu
-
-/* SPIGCR1 */
-#define SPIGCR1_SPIENA_MASK 0x01000000u
+#define SPIFMT_PRESCALE_SHIFT 8
/* SPIPC0 */
#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */
#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */
#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */
-#define SPIPC0_EN1FUN_MASK BIT(1)
-#define SPIPC0_EN0FUN_MASK BIT(0)
#define SPIINT_MASKALL 0x0101035F
-#define SPI_INTLVL_1 0x000001FFu
-#define SPI_INTLVL_0 0x00000000u
+#define SPIINT_MASKINT 0x0000015F
+#define SPI_INTLVL_1 0x000001FF
+#define SPI_INTLVL_0 0x00000000
-/* SPIDAT1 */
-#define SPIDAT1_CSHOLD_SHIFT 28
-#define SPIDAT1_CSNR_SHIFT 16
+/* SPIDAT1 (upper 16 bit defines) */
+#define SPIDAT1_CSHOLD_MASK BIT(12)
+
+/* SPIGCR1 */
#define SPIGCR1_CLKMOD_MASK BIT(1)
#define SPIGCR1_MASTER_MASK BIT(0)
+#define SPIGCR1_POWERDOWN_MASK BIT(8)
#define SPIGCR1_LOOPBACK_MASK BIT(16)
+#define SPIGCR1_SPIENA_MASK BIT(24)
/* SPIBUF */
#define SPIBUF_TXFULL_MASK BIT(29)
#define SPIBUF_RXEMPTY_MASK BIT(31)
+/* SPIDELAY */
+#define SPIDELAY_C2TDELAY_SHIFT 24
+#define SPIDELAY_C2TDELAY_MASK (0xFF << SPIDELAY_C2TDELAY_SHIFT)
+#define SPIDELAY_T2CDELAY_SHIFT 16
+#define SPIDELAY_T2CDELAY_MASK (0xFF << SPIDELAY_T2CDELAY_SHIFT)
+#define SPIDELAY_T2EDELAY_SHIFT 8
+#define SPIDELAY_T2EDELAY_MASK (0xFF << SPIDELAY_T2EDELAY_SHIFT)
+#define SPIDELAY_C2EDELAY_SHIFT 0
+#define SPIDELAY_C2EDELAY_MASK 0xFF
+
/* Error Masks */
#define SPIFLG_DLEN_ERR_MASK BIT(0)
#define SPIFLG_TIMEOUT_MASK BIT(1)
@@ -87,29 +92,13 @@
#define SPIFLG_DESYNC_MASK BIT(3)
#define SPIFLG_BITERR_MASK BIT(4)
#define SPIFLG_OVRRUN_MASK BIT(6)
-#define SPIFLG_RX_INTR_MASK BIT(8)
-#define SPIFLG_TX_INTR_MASK BIT(9)
#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24)
-#define SPIFLG_MASK (SPIFLG_DLEN_ERR_MASK \
+#define SPIFLG_ERROR_MASK (SPIFLG_DLEN_ERR_MASK \
| SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
| SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
- | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \
- | SPIFLG_TX_INTR_MASK \
- | SPIFLG_BUF_INIT_ACTIVE_MASK)
-
-#define SPIINT_DLEN_ERR_INTR BIT(0)
-#define SPIINT_TIMEOUT_INTR BIT(1)
-#define SPIINT_PARERR_INTR BIT(2)
-#define SPIINT_DESYNC_INTR BIT(3)
-#define SPIINT_BITERR_INTR BIT(4)
-#define SPIINT_OVRRUN_INTR BIT(6)
-#define SPIINT_RX_INTR BIT(8)
-#define SPIINT_TX_INTR BIT(9)
-#define SPIINT_DMA_REQ_EN BIT(16)
-#define SPIINT_ENABLE_HIGHZ BIT(24)
+ | SPIFLG_OVRRUN_MASK)
-#define SPI_T2CDELAY_SHIFT 16
-#define SPI_C2TDELAY_SHIFT 24
+#define SPIINT_DMA_REQ_EN BIT(16)
/* SPI Controller registers */
#define SPIGCR0 0x00
@@ -118,44 +107,18 @@
#define SPILVL 0x0c
#define SPIFLG 0x10
#define SPIPC0 0x14
-#define SPIPC1 0x18
-#define SPIPC2 0x1c
-#define SPIPC3 0x20
-#define SPIPC4 0x24
-#define SPIPC5 0x28
-#define SPIPC6 0x2c
-#define SPIPC7 0x30
-#define SPIPC8 0x34
-#define SPIDAT0 0x38
#define SPIDAT1 0x3c
#define SPIBUF 0x40
-#define SPIEMU 0x44
#define SPIDELAY 0x48
#define SPIDEF 0x4c
#define SPIFMT0 0x50
-#define SPIFMT1 0x54
-#define SPIFMT2 0x58
-#define SPIFMT3 0x5c
-#define TGINTVEC0 0x60
-#define TGINTVEC1 0x64
-
-struct davinci_spi_slave {
- u32 cmd_to_write;
- u32 clk_ctrl_to_write;
- u32 bytes_per_word;
- u8 active_cs;
-};
/* We have 2 DMA channels per CS, one for RX and one for TX */
struct davinci_spi_dma {
- int dma_tx_channel;
- int dma_rx_channel;
- int dma_tx_sync_dev;
- int dma_rx_sync_dev;
+ int tx_channel;
+ int rx_channel;
+ int dummy_param_slot;
enum dma_event_q eventq;
-
- struct completion dma_tx_completion;
- struct completion dma_rx_completion;
};
/* SPI Controller driver's private data. */
@@ -166,58 +129,63 @@ struct davinci_spi {
u8 version;
resource_size_t pbase;
void __iomem *base;
- size_t region_size;
u32 irq;
struct completion done;
const void *tx;
void *rx;
- u8 *tmp_buf;
- int count;
- struct davinci_spi_dma *dma_channels;
- struct davinci_spi_platform_data *pdata;
+#define SPI_TMP_BUFSZ (SMP_CACHE_BYTES + 1)
+ u8 rx_tmp_buf[SPI_TMP_BUFSZ];
+ int rcount;
+ int wcount;
+ struct davinci_spi_dma dma;
+ struct davinci_spi_platform_data *pdata;
void (*get_rx)(u32 rx_data, struct davinci_spi *);
u32 (*get_tx)(struct davinci_spi *);
- struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT];
+ u8 bytes_per_word[SPI_MAX_CHIPSELECT];
};
-static unsigned use_dma;
+static struct davinci_spi_config davinci_spi_default_cfg;
-static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi)
+static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *dspi)
{
- u8 *rx = davinci_spi->rx;
-
- *rx++ = (u8)data;
- davinci_spi->rx = rx;
+ if (dspi->rx) {
+ u8 *rx = dspi->rx;
+ *rx++ = (u8)data;
+ dspi->rx = rx;
+ }
}
-static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi)
+static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi)
{
- u16 *rx = davinci_spi->rx;
-
- *rx++ = (u16)data;
- davinci_spi->rx = rx;
+ if (dspi->rx) {
+ u16 *rx = dspi->rx;
+ *rx++ = (u16)data;
+ dspi->rx = rx;
+ }
}
-static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi)
+static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
{
- u32 data;
- const u8 *tx = davinci_spi->tx;
-
- data = *tx++;
- davinci_spi->tx = tx;
+ u32 data = 0;
+ if (dspi->tx) {
+ const u8 *tx = dspi->tx;
+ data = *tx++;
+ dspi->tx = tx;
+ }
return data;
}
-static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi)
+static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi)
{
- u32 data;
- const u16 *tx = davinci_spi->tx;
-
- data = *tx++;
- davinci_spi->tx = tx;
+ u32 data = 0;
+ if (dspi->tx) {
+ const u16 *tx = dspi->tx;
+ data = *tx++;
+ dspi->tx = tx;
+ }
return data;
}
@@ -237,55 +205,67 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
iowrite32(v, addr);
}
-static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
-{
- set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
-}
-
-static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
-{
- clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
-}
-
-static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable)
-{
- struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
-
- if (enable)
- set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
- else
- clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
-}
-
/*
* Interface to control the chip select signal
*/
static void davinci_spi_chipselect(struct spi_device *spi, int value)
{
- struct davinci_spi *davinci_spi;
+ struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
- u32 data1_reg_val = 0;
+ u8 chip_sel = spi->chip_select;
+ u16 spidat1 = CS_DEFAULT;
+ bool gpio_chipsel = false;
- davinci_spi = spi_master_get_devdata(spi->master);
- pdata = davinci_spi->pdata;
+ dspi = spi_master_get_devdata(spi->master);
+ pdata = dspi->pdata;
+
+ if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
+ pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
+ gpio_chipsel = true;
/*
* Board specific chip select logic decides the polarity and cs
* line for the controller
*/
- if (value == BITBANG_CS_INACTIVE) {
- set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT);
-
- data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT;
- iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+ if (gpio_chipsel) {
+ if (value == BITBANG_CS_ACTIVE)
+ gpio_set_value(pdata->chip_sel[chip_sel], 0);
+ else
+ gpio_set_value(pdata->chip_sel[chip_sel], 1);
+ } else {
+ if (value == BITBANG_CS_ACTIVE) {
+ spidat1 |= SPIDAT1_CSHOLD_MASK;
+ spidat1 &= ~(0x1 << chip_sel);
+ }
- while ((ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_RXEMPTY_MASK) == 0)
- cpu_relax();
+ iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
}
}
/**
+ * davinci_spi_get_prescale - Calculates the correct prescale value
+ * @maxspeed_hz: the maximum rate the SPI clock can run at
+ *
+ * This function calculates the prescale value that generates a clock rate
+ * less than or equal to the specified maximum.
+ *
+ * Returns: calculated prescale - 1 for easy programming into SPI registers
+ * or negative error number if valid prescalar cannot be updated.
+ */
+static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
+ u32 max_speed_hz)
+{
+ int ret;
+
+ ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz);
+
+ if (ret < 3 || ret > 256)
+ return -EINVAL;
+
+ return ret - 1;
+}
+
+/**
* davinci_spi_setup_transfer - This functions will determine transfer method
* @spi: spi device on which data transfer to be done
* @t: spi transfer in which transfer info is filled
@@ -298,13 +278,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct davinci_spi *davinci_spi;
- struct davinci_spi_platform_data *pdata;
+ struct davinci_spi *dspi;
+ struct davinci_spi_config *spicfg;
u8 bits_per_word = 0;
- u32 hz = 0, prescale = 0, clkspeed;
+ u32 hz = 0, spifmt = 0, prescale = 0;
- davinci_spi = spi_master_get_devdata(spi->master);
- pdata = davinci_spi->pdata;
+ dspi = spi_master_get_devdata(spi->master);
+ spicfg = (struct davinci_spi_config *)spi->controller_data;
+ if (!spicfg)
+ spicfg = &davinci_spi_default_cfg;
if (t) {
bits_per_word = t->bits_per_word;
@@ -320,111 +302,83 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
* 8bit, 16bit or 32bit transfer
*/
if (bits_per_word <= 8 && bits_per_word >= 2) {
- davinci_spi->get_rx = davinci_spi_rx_buf_u8;
- davinci_spi->get_tx = davinci_spi_tx_buf_u8;
- davinci_spi->slave[spi->chip_select].bytes_per_word = 1;
+ dspi->get_rx = davinci_spi_rx_buf_u8;
+ dspi->get_tx = davinci_spi_tx_buf_u8;
+ dspi->bytes_per_word[spi->chip_select] = 1;
} else if (bits_per_word <= 16 && bits_per_word >= 2) {
- davinci_spi->get_rx = davinci_spi_rx_buf_u16;
- davinci_spi->get_tx = davinci_spi_tx_buf_u16;
- davinci_spi->slave[spi->chip_select].bytes_per_word = 2;
+ dspi->get_rx = davinci_spi_rx_buf_u16;
+ dspi->get_tx = davinci_spi_tx_buf_u16;
+ dspi->bytes_per_word[spi->chip_select] = 2;
} else
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
- clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK,
- spi->chip_select);
- set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
- spi->chip_select);
+ /* Set up SPIFMTn register, unique to this chipselect. */
- clkspeed = clk_get_rate(davinci_spi->clk);
- if (hz > clkspeed / 2)
- prescale = 1 << 8;
- if (hz < clkspeed / 256)
- prescale = 255 << 8;
- if (!prescale)
- prescale = ((clkspeed / hz - 1) << 8) & 0x0000ff00;
+ prescale = davinci_spi_get_prescale(dspi, hz);
+ if (prescale < 0)
+ return prescale;
- clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
- set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
+ spifmt = (prescale << SPIFMT_PRESCALE_SHIFT) | (bits_per_word & 0x1f);
- return 0;
-}
+ if (spi->mode & SPI_LSB_FIRST)
+ spifmt |= SPIFMT_SHIFTDIR_MASK;
-static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
-{
- struct spi_device *spi = (struct spi_device *)data;
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
- struct davinci_spi_platform_data *pdata;
+ if (spi->mode & SPI_CPOL)
+ spifmt |= SPIFMT_POLARITY_MASK;
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
- pdata = davinci_spi->pdata;
+ if (!(spi->mode & SPI_CPHA))
+ spifmt |= SPIFMT_PHASE_MASK;
- if (ch_status == DMA_COMPLETE)
- edma_stop(davinci_spi_dma->dma_rx_channel);
- else
- edma_clean_channel(davinci_spi_dma->dma_rx_channel);
+ /*
+ * Version 1 hardware supports two basic SPI modes:
+ * - Standard SPI mode uses 4 pins, with chipselect
+ * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
+ * (distinct from SPI_3WIRE, with just one data wire;
+ * or similar variants without MOSI or without MISO)
+ *
+ * Version 2 hardware supports an optional handshaking signal,
+ * so it can support two more modes:
+ * - 5 pin SPI variant is standard SPI plus SPI_READY
+ * - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+ */
- complete(&davinci_spi_dma->dma_rx_completion);
- /* We must disable the DMA RX request */
- davinci_spi_set_dma_req(spi, 0);
-}
+ if (dspi->version == SPI_VERSION_2) {
-static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data)
-{
- struct spi_device *spi = (struct spi_device *)data;
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
- struct davinci_spi_platform_data *pdata;
+ u32 delay = 0;
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
- pdata = davinci_spi->pdata;
+ spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
+ & SPIFMT_WDELAY_MASK);
- if (ch_status == DMA_COMPLETE)
- edma_stop(davinci_spi_dma->dma_tx_channel);
- else
- edma_clean_channel(davinci_spi_dma->dma_tx_channel);
+ if (spicfg->odd_parity)
+ spifmt |= SPIFMT_ODD_PARITY_MASK;
- complete(&davinci_spi_dma->dma_tx_completion);
- /* We must disable the DMA TX request */
- davinci_spi_set_dma_req(spi, 0);
-}
+ if (spicfg->parity_enable)
+ spifmt |= SPIFMT_PARITYENA_MASK;
-static int davinci_spi_request_dma(struct spi_device *spi)
-{
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
- struct davinci_spi_platform_data *pdata;
- struct device *sdev;
- int r;
+ if (spicfg->timer_disable) {
+ spifmt |= SPIFMT_DISTIMER_MASK;
+ } else {
+ delay |= (spicfg->c2tdelay << SPIDELAY_C2TDELAY_SHIFT)
+ & SPIDELAY_C2TDELAY_MASK;
+ delay |= (spicfg->t2cdelay << SPIDELAY_T2CDELAY_SHIFT)
+ & SPIDELAY_T2CDELAY_MASK;
+ }
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
- pdata = davinci_spi->pdata;
- sdev = davinci_spi->bitbang.master->dev.parent;
+ if (spi->mode & SPI_READY) {
+ spifmt |= SPIFMT_WAITENA_MASK;
+ delay |= (spicfg->t2edelay << SPIDELAY_T2EDELAY_SHIFT)
+ & SPIDELAY_T2EDELAY_MASK;
+ delay |= (spicfg->c2edelay << SPIDELAY_C2EDELAY_SHIFT)
+ & SPIDELAY_C2EDELAY_MASK;
+ }
- r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev,
- davinci_spi_dma_rx_callback, spi,
- davinci_spi_dma->eventq);
- if (r < 0) {
- dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n");
- return -EAGAIN;
+ iowrite32(delay, dspi->base + SPIDELAY);
}
- davinci_spi_dma->dma_rx_channel = r;
- r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev,
- davinci_spi_dma_tx_callback, spi,
- davinci_spi_dma->eventq);
- if (r < 0) {
- edma_free_channel(davinci_spi_dma->dma_rx_channel);
- davinci_spi_dma->dma_rx_channel = -1;
- dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
- return -EAGAIN;
- }
- davinci_spi_dma->dma_tx_channel = r;
+
+ iowrite32(spifmt, dspi->base + SPIFMT0);
return 0;
}
@@ -435,190 +389,40 @@ static int davinci_spi_request_dma(struct spi_device *spi)
*
* This functions sets the default transfer method.
*/
-
static int davinci_spi_setup(struct spi_device *spi)
{
- int retval;
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
- struct device *sdev;
+ int retval = 0;
+ struct davinci_spi *dspi;
+ struct davinci_spi_platform_data *pdata;
- davinci_spi = spi_master_get_devdata(spi->master);
- sdev = davinci_spi->bitbang.master->dev.parent;
+ dspi = spi_master_get_devdata(spi->master);
+ pdata = dspi->pdata;
/* if bits per word length is zero then set it default 8 */
if (!spi->bits_per_word)
spi->bits_per_word = 8;
- davinci_spi->slave[spi->chip_select].cmd_to_write = 0;
-
- if (use_dma && davinci_spi->dma_channels) {
- davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
- if ((davinci_spi_dma->dma_rx_channel == -1)
- || (davinci_spi_dma->dma_tx_channel == -1)) {
- retval = davinci_spi_request_dma(spi);
- if (retval < 0)
- return retval;
- }
- }
-
- /*
- * SPI in DaVinci and DA8xx operate between
- * 600 KHz and 50 MHz
- */
- if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
- dev_dbg(sdev, "Operating frequency is not in acceptable "
- "range\n");
- return -EINVAL;
- }
-
- /*
- * Set up SPIFMTn register, unique to this chipselect.
- *
- * NOTE: we could do all of these with one write. Also, some
- * of the "version 2" features are found in chips that don't
- * support all of them...
- */
- if (spi->mode & SPI_LSB_FIRST)
- set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
- spi->chip_select);
-
- if (spi->mode & SPI_CPOL)
- set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
- spi->chip_select);
+ if (!(spi->mode & SPI_NO_CS)) {
+ if ((pdata->chip_sel == NULL) ||
+ (pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS))
+ set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
- if (!(spi->mode & SPI_CPHA))
- set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
- spi->chip_select);
-
- /*
- * Version 1 hardware supports two basic SPI modes:
- * - Standard SPI mode uses 4 pins, with chipselect
- * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
- * (distinct from SPI_3WIRE, with just one data wire;
- * or similar variants without MOSI or without MISO)
- *
- * Version 2 hardware supports an optional handshaking signal,
- * so it can support two more modes:
- * - 5 pin SPI variant is standard SPI plus SPI_READY
- * - 4 pin with enable is (SPI_READY | SPI_NO_CS)
- */
-
- if (davinci_spi->version == SPI_VERSION_2) {
- clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
- spi->chip_select);
- set_fmt_bits(davinci_spi->base,
- (davinci_spi->pdata->wdelay
- << SPIFMT_WDELAY_SHIFT)
- & SPIFMT_WDELAY_MASK,
- spi->chip_select);
-
- if (davinci_spi->pdata->odd_parity)
- set_fmt_bits(davinci_spi->base,
- SPIFMT_ODD_PARITY_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base,
- SPIFMT_ODD_PARITY_MASK,
- spi->chip_select);
-
- if (davinci_spi->pdata->parity_enable)
- set_fmt_bits(davinci_spi->base,
- SPIFMT_PARITYENA_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base,
- SPIFMT_PARITYENA_MASK,
- spi->chip_select);
-
- if (davinci_spi->pdata->wait_enable)
- set_fmt_bits(davinci_spi->base,
- SPIFMT_WAITENA_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base,
- SPIFMT_WAITENA_MASK,
- spi->chip_select);
-
- if (davinci_spi->pdata->timer_disable)
- set_fmt_bits(davinci_spi->base,
- SPIFMT_DISTIMER_MASK,
- spi->chip_select);
- else
- clear_fmt_bits(davinci_spi->base,
- SPIFMT_DISTIMER_MASK,
- spi->chip_select);
}
- retval = davinci_spi_setup_transfer(spi, NULL);
-
- return retval;
-}
-
-static void davinci_spi_cleanup(struct spi_device *spi)
-{
- struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
- struct davinci_spi_dma *davinci_spi_dma;
-
- davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
- if (use_dma && davinci_spi->dma_channels) {
- davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
- if ((davinci_spi_dma->dma_rx_channel != -1)
- && (davinci_spi_dma->dma_tx_channel != -1)) {
- edma_free_channel(davinci_spi_dma->dma_tx_channel);
- edma_free_channel(davinci_spi_dma->dma_rx_channel);
- }
- }
-}
-
-static int davinci_spi_bufs_prep(struct spi_device *spi,
- struct davinci_spi *davinci_spi)
-{
- int op_mode = 0;
-
- /*
- * REVISIT unless devices disagree about SPI_LOOP or
- * SPI_READY (SPI_NO_CS only allows one device!), this
- * should not need to be done before each message...
- * optimize for both flags staying cleared.
- */
-
- op_mode = SPIPC0_DIFUN_MASK
- | SPIPC0_DOFUN_MASK
- | SPIPC0_CLKFUN_MASK;
- if (!(spi->mode & SPI_NO_CS))
- op_mode |= 1 << spi->chip_select;
if (spi->mode & SPI_READY)
- op_mode |= SPIPC0_SPIENA_MASK;
-
- iowrite32(op_mode, davinci_spi->base + SPIPC0);
+ set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
if (spi->mode & SPI_LOOP)
- set_io_bits(davinci_spi->base + SPIGCR1,
- SPIGCR1_LOOPBACK_MASK);
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
else
- clear_io_bits(davinci_spi->base + SPIGCR1,
- SPIGCR1_LOOPBACK_MASK);
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
- return 0;
+ return retval;
}
-static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
- int int_status)
+static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
{
- struct device *sdev = davinci_spi->bitbang.master->dev.parent;
+ struct device *sdev = dspi->bitbang.master->dev.parent;
if (int_status & SPIFLG_TIMEOUT_MASK) {
dev_dbg(sdev, "SPI Time-out Error\n");
@@ -633,7 +437,7 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
return -EIO;
}
- if (davinci_spi->version == SPI_VERSION_2) {
+ if (dspi->version == SPI_VERSION_2) {
if (int_status & SPIFLG_DLEN_ERR_MASK) {
dev_dbg(sdev, "SPI Data Length Error\n");
return -EIO;
@@ -646,10 +450,6 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
dev_dbg(sdev, "SPI Data Overrun error\n");
return -EIO;
}
- if (int_status & SPIFLG_TX_INTR_MASK) {
- dev_dbg(sdev, "SPI TX intr bit set\n");
- return -EIO;
- }
if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
dev_dbg(sdev, "SPI Buffer Init Active\n");
return -EBUSY;
@@ -660,366 +460,339 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
}
/**
- * davinci_spi_bufs - functions which will handle transfer data
- * @spi: spi device on which data transfer to be done
- * @t: spi transfer in which transfer info is filled
+ * davinci_spi_process_events - check for and handle any SPI controller events
+ * @dspi: the controller data
*
- * This function will put data to be transferred into data register
- * of SPI controller and then wait until the completion will be marked
- * by the IRQ Handler.
+ * This function will check the SPIFLG register and handle any events that are
+ * detected there
*/
-static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
+static int davinci_spi_process_events(struct davinci_spi *dspi)
{
- struct davinci_spi *davinci_spi;
- int int_status, count, ret;
- u8 conv, tmp;
- u32 tx_data, data1_reg_val;
- u32 buf_val, flg_val;
- struct davinci_spi_platform_data *pdata;
-
- davinci_spi = spi_master_get_devdata(spi->master);
- pdata = davinci_spi->pdata;
-
- davinci_spi->tx = t->tx_buf;
- davinci_spi->rx = t->rx_buf;
-
- /* convert len to words based on bits_per_word */
- conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
- davinci_spi->count = t->len / conv;
-
- INIT_COMPLETION(davinci_spi->done);
-
- ret = davinci_spi_bufs_prep(spi, davinci_spi);
- if (ret)
- return ret;
-
- /* Enable SPI */
- set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
-
- iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
- (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
- davinci_spi->base + SPIDELAY);
-
- count = davinci_spi->count;
- data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
- tmp = ~(0x1 << spi->chip_select);
-
- clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
-
- data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+ u32 buf, status, errors = 0, spidat1;
- while ((ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_RXEMPTY_MASK) == 0)
- cpu_relax();
+ buf = ioread32(dspi->base + SPIBUF);
- /* Determine the command to execute READ or WRITE */
- if (t->tx_buf) {
- clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+ if (dspi->rcount > 0 && !(buf & SPIBUF_RXEMPTY_MASK)) {
+ dspi->get_rx(buf & 0xFFFF, dspi);
+ dspi->rcount--;
+ }
- while (1) {
- tx_data = davinci_spi->get_tx(davinci_spi);
+ status = ioread32(dspi->base + SPIFLG);
- data1_reg_val &= ~(0xFFFF);
- data1_reg_val |= (0xFFFF & tx_data);
+ if (unlikely(status & SPIFLG_ERROR_MASK)) {
+ errors = status & SPIFLG_ERROR_MASK;
+ goto out;
+ }
- buf_val = ioread32(davinci_spi->base + SPIBUF);
- if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
- iowrite32(data1_reg_val,
- davinci_spi->base + SPIDAT1);
+ if (dspi->wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) {
+ spidat1 = ioread32(dspi->base + SPIDAT1);
+ dspi->wcount--;
+ spidat1 &= ~0xFFFF;
+ spidat1 |= 0xFFFF & dspi->get_tx(dspi);
+ iowrite32(spidat1, dspi->base + SPIDAT1);
+ }
- count--;
- }
- while (ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_RXEMPTY_MASK)
- cpu_relax();
-
- /* getting the returned byte */
- if (t->rx_buf) {
- buf_val = ioread32(davinci_spi->base + SPIBUF);
- davinci_spi->get_rx(buf_val, davinci_spi);
- }
- if (count <= 0)
- break;
- }
- } else {
- if (pdata->poll_mode) {
- while (1) {
- /* keeps the serial clock going */
- if ((ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_TXFULL_MASK) == 0)
- iowrite32(data1_reg_val,
- davinci_spi->base + SPIDAT1);
-
- while (ioread32(davinci_spi->base + SPIBUF) &
- SPIBUF_RXEMPTY_MASK)
- cpu_relax();
-
- flg_val = ioread32(davinci_spi->base + SPIFLG);
- buf_val = ioread32(davinci_spi->base + SPIBUF);
-
- davinci_spi->get_rx(buf_val, davinci_spi);
-
- count--;
- if (count <= 0)
- break;
- }
- } else { /* Receive in Interrupt mode */
- int i;
+out:
+ return errors;
+}
- for (i = 0; i < davinci_spi->count; i++) {
- set_io_bits(davinci_spi->base + SPIINT,
- SPIINT_BITERR_INTR
- | SPIINT_OVRRUN_INTR
- | SPIINT_RX_INTR);
+static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
+{
+ struct davinci_spi *dspi = data;
+ struct davinci_spi_dma *dma = &dspi->dma;
- iowrite32(data1_reg_val,
- davinci_spi->base + SPIDAT1);
+ edma_stop(lch);
- while (ioread32(davinci_spi->base + SPIINT) &
- SPIINT_RX_INTR)
- cpu_relax();
- }
- iowrite32((data1_reg_val & 0x0ffcffff),
- davinci_spi->base + SPIDAT1);
- }
+ if (status == DMA_COMPLETE) {
+ if (lch == dma->rx_channel)
+ dspi->rcount = 0;
+ if (lch == dma->tx_channel)
+ dspi->wcount = 0;
}
- /*
- * Check for bit error, desync error,parity error,timeout error and
- * receive overflow errors
- */
- int_status = ioread32(davinci_spi->base + SPIFLG);
-
- ret = davinci_spi_check_error(davinci_spi, int_status);
- if (ret != 0)
- return ret;
-
- /* SPI Framework maintains the count only in bytes so convert back */
- davinci_spi->count *= conv;
-
- return t->len;
+ if ((!dspi->wcount && !dspi->rcount) || (status != DMA_COMPLETE))
+ complete(&dspi->done);
}
-#define DAVINCI_DMA_DATA_TYPE_S8 0x01
-#define DAVINCI_DMA_DATA_TYPE_S16 0x02
-#define DAVINCI_DMA_DATA_TYPE_S32 0x04
-
-static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t)
+/**
+ * davinci_spi_bufs - functions which will handle transfer data
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function will put data to be transferred into data register
+ * of SPI controller and then wait until the completion will be marked
+ * by the IRQ Handler.
+ */
+static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct davinci_spi *davinci_spi;
- int int_status = 0;
- int count, temp_count;
- u8 conv = 1;
- u8 tmp;
- u32 data1_reg_val;
- struct davinci_spi_dma *davinci_spi_dma;
- int word_len, data_type, ret;
- unsigned long tx_reg, rx_reg;
+ struct davinci_spi *dspi;
+ int data_type, ret;
+ u32 tx_data, spidat1;
+ u32 errors = 0;
+ struct davinci_spi_config *spicfg;
struct davinci_spi_platform_data *pdata;
+ unsigned uninitialized_var(rx_buf_count);
struct device *sdev;
- davinci_spi = spi_master_get_devdata(spi->master);
- pdata = davinci_spi->pdata;
- sdev = davinci_spi->bitbang.master->dev.parent;
-
- davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
-
- tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1;
- rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF;
-
- davinci_spi->tx = t->tx_buf;
- davinci_spi->rx = t->rx_buf;
+ dspi = spi_master_get_devdata(spi->master);
+ pdata = dspi->pdata;
+ spicfg = (struct davinci_spi_config *)spi->controller_data;
+ if (!spicfg)
+ spicfg = &davinci_spi_default_cfg;
+ sdev = dspi->bitbang.master->dev.parent;
/* convert len to words based on bits_per_word */
- conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
- davinci_spi->count = t->len / conv;
-
- INIT_COMPLETION(davinci_spi->done);
+ data_type = dspi->bytes_per_word[spi->chip_select];
- init_completion(&davinci_spi_dma->dma_rx_completion);
- init_completion(&davinci_spi_dma->dma_tx_completion);
+ dspi->tx = t->tx_buf;
+ dspi->rx = t->rx_buf;
+ dspi->wcount = t->len / data_type;
+ dspi->rcount = dspi->wcount;
- word_len = conv * 8;
-
- if (word_len <= 8)
- data_type = DAVINCI_DMA_DATA_TYPE_S8;
- else if (word_len <= 16)
- data_type = DAVINCI_DMA_DATA_TYPE_S16;
- else if (word_len <= 32)
- data_type = DAVINCI_DMA_DATA_TYPE_S32;
- else
- return -EINVAL;
-
- ret = davinci_spi_bufs_prep(spi, davinci_spi);
- if (ret)
- return ret;
+ spidat1 = ioread32(dspi->base + SPIDAT1);
- /* Put delay val if required */
- iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
- (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
- davinci_spi->base + SPIDELAY);
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
- count = davinci_spi->count; /* the number of elements */
- data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+ INIT_COMPLETION(dspi->done);
- /* CS default = 0xFF */
- tmp = ~(0x1 << spi->chip_select);
+ if (spicfg->io_type == SPI_IO_TYPE_INTR)
+ set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
- clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
-
- data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
-
- /* disable all interrupts for dma transfers */
- clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
- /* Disable SPI to write configuration bits in SPIDAT */
- clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
- iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
- /* Enable SPI */
- set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
-
- while ((ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_RXEMPTY_MASK) == 0)
- cpu_relax();
-
-
- if (t->tx_buf) {
- t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&spi->dev, t->tx_dma)) {
- dev_dbg(sdev, "Unable to DMA map a %d bytes"
- " TX buffer\n", count);
- return -ENOMEM;
- }
- temp_count = count;
+ if (spicfg->io_type != SPI_IO_TYPE_DMA) {
+ /* start the transfer */
+ dspi->wcount--;
+ tx_data = dspi->get_tx(dspi);
+ spidat1 &= 0xFFFF0000;
+ spidat1 |= tx_data & 0xFFFF;
+ iowrite32(spidat1, dspi->base + SPIDAT1);
} else {
- /* We need TX clocking for RX transaction */
- t->tx_dma = dma_map_single(&spi->dev,
- (void *)davinci_spi->tmp_buf, count + 1,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&spi->dev, t->tx_dma)) {
- dev_dbg(sdev, "Unable to DMA map a %d bytes"
- " TX tmp buffer\n", count);
- return -ENOMEM;
+ struct davinci_spi_dma *dma;
+ unsigned long tx_reg, rx_reg;
+ struct edmacc_param param;
+ void *rx_buf;
+
+ dma = &dspi->dma;
+
+ tx_reg = (unsigned long)dspi->pbase + SPIDAT1;
+ rx_reg = (unsigned long)dspi->pbase + SPIBUF;
+
+ /*
+ * Transmit DMA setup
+ *
+ * If there is transmit data, map the transmit buffer, set it
+ * as the source of data and set the source B index to data
+ * size. If there is no transmit data, set the transmit register
+ * as the source of data, and set the source B index to zero.
+ *
+ * The destination is always the transmit register itself. And
+ * the destination never increments.
+ */
+
+ if (t->tx_buf) {
+ t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf,
+ dspi->wcount, DMA_TO_DEVICE);
+ if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+ dev_dbg(sdev, "Unable to DMA map %d bytes"
+ "TX buffer\n", dspi->wcount);
+ return -ENOMEM;
+ }
}
- temp_count = count + 1;
- }
- edma_set_transfer_params(davinci_spi_dma->dma_tx_channel,
- data_type, temp_count, 1, 0, ASYNC);
- edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT);
- edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT);
- edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0);
- edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0);
-
- if (t->rx_buf) {
- /* initiate transaction */
- iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+ param.opt = TCINTEN | EDMA_TCC(dma->tx_channel);
+ param.src = t->tx_buf ? t->tx_dma : tx_reg;
+ param.a_b_cnt = dspi->wcount << 16 | data_type;
+ param.dst = tx_reg;
+ param.src_dst_bidx = t->tx_buf ? data_type : 0;
+ param.link_bcntrld = 0xffff;
+ param.src_dst_cidx = 0;
+ param.ccnt = 1;
+ edma_write_slot(dma->tx_channel, &param);
+ edma_link(dma->tx_channel, dma->dummy_param_slot);
+
+ /*
+ * Receive DMA setup
+ *
+ * If there is receive buffer, use it to receive data. If there
+ * is none provided, use a temporary receive buffer. Set the
+ * destination B index to 0 so effectively only one byte is used
+ * in the temporary buffer (address does not increment).
+ *
+ * The source of receive data is the receive data register. The
+ * source address never increments.
+ */
+
+ if (t->rx_buf) {
+ rx_buf = t->rx_buf;
+ rx_buf_count = dspi->rcount;
+ } else {
+ rx_buf = dspi->rx_tmp_buf;
+ rx_buf_count = sizeof(dspi->rx_tmp_buf);
+ }
- t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count,
- DMA_FROM_DEVICE);
+ t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count,
+ DMA_FROM_DEVICE);
if (dma_mapping_error(&spi->dev, t->rx_dma)) {
dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
- count);
- if (t->tx_buf != NULL)
- dma_unmap_single(NULL, t->tx_dma,
- count, DMA_TO_DEVICE);
+ rx_buf_count);
+ if (t->tx_buf)
+ dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
+ DMA_TO_DEVICE);
return -ENOMEM;
}
- edma_set_transfer_params(davinci_spi_dma->dma_rx_channel,
- data_type, count, 1, 0, ASYNC);
- edma_set_src(davinci_spi_dma->dma_rx_channel,
- rx_reg, INCR, W8BIT);
- edma_set_dest(davinci_spi_dma->dma_rx_channel,
- t->rx_dma, INCR, W8BIT);
- edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0);
- edma_set_dest_index(davinci_spi_dma->dma_rx_channel,
- data_type, 0);
- }
- if ((t->tx_buf) || (t->rx_buf))
- edma_start(davinci_spi_dma->dma_tx_channel);
+ param.opt = TCINTEN | EDMA_TCC(dma->rx_channel);
+ param.src = rx_reg;
+ param.a_b_cnt = dspi->rcount << 16 | data_type;
+ param.dst = t->rx_dma;
+ param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16;
+ param.link_bcntrld = 0xffff;
+ param.src_dst_cidx = 0;
+ param.ccnt = 1;
+ edma_write_slot(dma->rx_channel, &param);
+
+ if (pdata->cshold_bug)
+ iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
+
+ edma_start(dma->rx_channel);
+ edma_start(dma->tx_channel);
+ set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+ }
- if (t->rx_buf)
- edma_start(davinci_spi_dma->dma_rx_channel);
+ /* Wait for the transfer to complete */
+ if (spicfg->io_type != SPI_IO_TYPE_POLL) {
+ wait_for_completion_interruptible(&(dspi->done));
+ } else {
+ while (dspi->rcount > 0 || dspi->wcount > 0) {
+ errors = davinci_spi_process_events(dspi);
+ if (errors)
+ break;
+ cpu_relax();
+ }
+ }
- if ((t->rx_buf) || (t->tx_buf))
- davinci_spi_set_dma_req(spi, 1);
+ clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
+ if (spicfg->io_type == SPI_IO_TYPE_DMA) {
- if (t->tx_buf)
- wait_for_completion_interruptible(
- &davinci_spi_dma->dma_tx_completion);
+ if (t->tx_buf)
+ dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
+ DMA_TO_DEVICE);
- if (t->rx_buf)
- wait_for_completion_interruptible(
- &davinci_spi_dma->dma_rx_completion);
+ dma_unmap_single(NULL, t->rx_dma, rx_buf_count,
+ DMA_FROM_DEVICE);
- dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE);
+ clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+ }
- if (t->rx_buf)
- dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE);
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
/*
* Check for bit error, desync error,parity error,timeout error and
* receive overflow errors
*/
- int_status = ioread32(davinci_spi->base + SPIFLG);
-
- ret = davinci_spi_check_error(davinci_spi, int_status);
- if (ret != 0)
+ if (errors) {
+ ret = davinci_spi_check_error(dspi, errors);
+ WARN(!ret, "%s: error reported but no error found!\n",
+ dev_name(&spi->dev));
return ret;
+ }
- /* SPI Framework maintains the count only in bytes so convert back */
- davinci_spi->count *= conv;
+ if (dspi->rcount != 0 || dspi->wcount != 0) {
+ dev_err(sdev, "SPI data transfer error\n");
+ return -EIO;
+ }
return t->len;
}
/**
- * davinci_spi_irq - IRQ handler for DaVinci SPI
+ * davinci_spi_irq - Interrupt handler for SPI Master Controller
* @irq: IRQ number for this SPI Master
* @context_data: structure for SPI Master controller davinci_spi
+ *
+ * ISR will determine that interrupt arrives either for READ or WRITE command.
+ * According to command it will do the appropriate action. It will check
+ * transfer length and if it is not zero then dispatch transfer command again.
+ * If transfer length is zero then it will indicate the COMPLETION so that
+ * davinci_spi_bufs function can go ahead.
*/
-static irqreturn_t davinci_spi_irq(s32 irq, void *context_data)
+static irqreturn_t davinci_spi_irq(s32 irq, void *data)
{
- struct davinci_spi *davinci_spi = context_data;
- u32 int_status, rx_data = 0;
- irqreturn_t ret = IRQ_NONE;
+ struct davinci_spi *dspi = data;
+ int status;
- int_status = ioread32(davinci_spi->base + SPIFLG);
+ status = davinci_spi_process_events(dspi);
+ if (unlikely(status != 0))
+ clear_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
- while ((int_status & SPIFLG_RX_INTR_MASK)) {
- if (likely(int_status & SPIFLG_RX_INTR_MASK)) {
- ret = IRQ_HANDLED;
+ if ((!dspi->rcount && !dspi->wcount) || status)
+ complete(&dspi->done);
- rx_data = ioread32(davinci_spi->base + SPIBUF);
- davinci_spi->get_rx(rx_data, davinci_spi);
+ return IRQ_HANDLED;
+}
- /* Disable Receive Interrupt */
- iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR),
- davinci_spi->base + SPIINT);
- } else
- (void)davinci_spi_check_error(davinci_spi, int_status);
+static int davinci_spi_request_dma(struct davinci_spi *dspi)
+{
+ int r;
+ struct davinci_spi_dma *dma = &dspi->dma;
- int_status = ioread32(davinci_spi->base + SPIFLG);
+ r = edma_alloc_channel(dma->rx_channel, davinci_spi_dma_callback, dspi,
+ dma->eventq);
+ if (r < 0) {
+ pr_err("Unable to request DMA channel for SPI RX\n");
+ r = -EAGAIN;
+ goto rx_dma_failed;
}
- return ret;
+ r = edma_alloc_channel(dma->tx_channel, davinci_spi_dma_callback, dspi,
+ dma->eventq);
+ if (r < 0) {
+ pr_err("Unable to request DMA channel for SPI TX\n");
+ r = -EAGAIN;
+ goto tx_dma_failed;
+ }
+
+ r = edma_alloc_slot(EDMA_CTLR(dma->tx_channel), EDMA_SLOT_ANY);
+ if (r < 0) {
+ pr_err("Unable to request SPI TX DMA param slot\n");
+ r = -EAGAIN;
+ goto param_failed;
+ }
+ dma->dummy_param_slot = r;
+ edma_link(dma->dummy_param_slot, dma->dummy_param_slot);
+
+ return 0;
+param_failed:
+ edma_free_channel(dma->tx_channel);
+tx_dma_failed:
+ edma_free_channel(dma->rx_channel);
+rx_dma_failed:
+ return r;
}
/**
* davinci_spi_probe - probe function for SPI Master Controller
* @pdev: platform_device structure which contains plateform specific data
+ *
+ * According to Linux Device Model this function will be invoked by Linux
+ * with platform_device struct which contains the device specific info.
+ * This function will map the SPI controller's memory, register IRQ,
+ * Reset SPI controller and setting its registers to default value.
+ * It will invoke spi_bitbang_start to create work queue so that client driver
+ * can register transfer method to work queue.
*/
static int davinci_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
- struct davinci_spi *davinci_spi;
+ struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct resource *r, *mem;
resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
resource_size_t dma_eventq = SPI_NO_RESOURCE;
int i = 0, ret = 0;
+ u32 spipc0;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -1035,8 +808,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, master);
- davinci_spi = spi_master_get_devdata(master);
- if (davinci_spi == NULL) {
+ dspi = spi_master_get_devdata(master);
+ if (dspi == NULL) {
ret = -ENOENT;
goto free_master;
}
@@ -1047,164 +820,143 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
}
- davinci_spi->pbase = r->start;
- davinci_spi->region_size = resource_size(r);
- davinci_spi->pdata = pdata;
+ dspi->pbase = r->start;
+ dspi->pdata = pdata;
- mem = request_mem_region(r->start, davinci_spi->region_size,
- pdev->name);
+ mem = request_mem_region(r->start, resource_size(r), pdev->name);
if (mem == NULL) {
ret = -EBUSY;
goto free_master;
}
- davinci_spi->base = (struct davinci_spi_reg __iomem *)
- ioremap(r->start, davinci_spi->region_size);
- if (davinci_spi->base == NULL) {
+ dspi->base = ioremap(r->start, resource_size(r));
+ if (dspi->base == NULL) {
ret = -ENOMEM;
goto release_region;
}
- davinci_spi->irq = platform_get_irq(pdev, 0);
- if (davinci_spi->irq <= 0) {
+ dspi->irq = platform_get_irq(pdev, 0);
+ if (dspi->irq <= 0) {
ret = -EINVAL;
goto unmap_io;
}
- ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), davinci_spi);
+ ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
+ dspi);
if (ret)
goto unmap_io;
- /* Allocate tmp_buf for tx_buf */
- davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (davinci_spi->tmp_buf == NULL) {
- ret = -ENOMEM;
- goto irq_free;
- }
-
- davinci_spi->bitbang.master = spi_master_get(master);
- if (davinci_spi->bitbang.master == NULL) {
+ dspi->bitbang.master = spi_master_get(master);
+ if (dspi->bitbang.master == NULL) {
ret = -ENODEV;
- goto free_tmp_buf;
+ goto irq_free;
}
- davinci_spi->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(davinci_spi->clk)) {
+ dspi->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dspi->clk)) {
ret = -ENODEV;
goto put_master;
}
- clk_enable(davinci_spi->clk);
-
+ clk_enable(dspi->clk);
master->bus_num = pdev->id;
master->num_chipselect = pdata->num_chipselect;
master->setup = davinci_spi_setup;
- master->cleanup = davinci_spi_cleanup;
-
- davinci_spi->bitbang.chipselect = davinci_spi_chipselect;
- davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;
-
- davinci_spi->version = pdata->version;
- use_dma = pdata->use_dma;
-
- davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
- if (davinci_spi->version == SPI_VERSION_2)
- davinci_spi->bitbang.flags |= SPI_READY;
-
- if (use_dma) {
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (r)
- dma_rx_chan = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (r)
- dma_tx_chan = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (r)
- dma_eventq = r->start;
- }
- if (!use_dma ||
- dma_rx_chan == SPI_NO_RESOURCE ||
- dma_tx_chan == SPI_NO_RESOURCE ||
- dma_eventq == SPI_NO_RESOURCE) {
- davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
- use_dma = 0;
- } else {
- davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
- davinci_spi->dma_channels = kzalloc(master->num_chipselect
- * sizeof(struct davinci_spi_dma), GFP_KERNEL);
- if (davinci_spi->dma_channels == NULL) {
- ret = -ENOMEM;
+ dspi->bitbang.chipselect = davinci_spi_chipselect;
+ dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
+
+ dspi->version = pdata->version;
+
+ dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
+ if (dspi->version == SPI_VERSION_2)
+ dspi->bitbang.flags |= SPI_READY;
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r)
+ dma_rx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r)
+ dma_tx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (r)
+ dma_eventq = r->start;
+
+ dspi->bitbang.txrx_bufs = davinci_spi_bufs;
+ if (dma_rx_chan != SPI_NO_RESOURCE &&
+ dma_tx_chan != SPI_NO_RESOURCE &&
+ dma_eventq != SPI_NO_RESOURCE) {
+ dspi->dma.rx_channel = dma_rx_chan;
+ dspi->dma.tx_channel = dma_tx_chan;
+ dspi->dma.eventq = dma_eventq;
+
+ ret = davinci_spi_request_dma(dspi);
+ if (ret)
goto free_clk;
- }
- for (i = 0; i < master->num_chipselect; i++) {
- davinci_spi->dma_channels[i].dma_rx_channel = -1;
- davinci_spi->dma_channels[i].dma_rx_sync_dev =
- dma_rx_chan;
- davinci_spi->dma_channels[i].dma_tx_channel = -1;
- davinci_spi->dma_channels[i].dma_tx_sync_dev =
- dma_tx_chan;
- davinci_spi->dma_channels[i].eventq = dma_eventq;
- }
- dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
- "Using RX channel = %d , TX channel = %d and "
- "event queue = %d", dma_rx_chan, dma_tx_chan,
+ dev_info(&pdev->dev, "DMA: supported\n");
+ dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, "
+ "event queue: %d\n", dma_rx_chan, dma_tx_chan,
dma_eventq);
}
- davinci_spi->get_rx = davinci_spi_rx_buf_u8;
- davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+ dspi->get_rx = davinci_spi_rx_buf_u8;
+ dspi->get_tx = davinci_spi_tx_buf_u8;
- init_completion(&davinci_spi->done);
+ init_completion(&dspi->done);
/* Reset In/OUT SPI module */
- iowrite32(0, davinci_spi->base + SPIGCR0);
+ iowrite32(0, dspi->base + SPIGCR0);
udelay(100);
- iowrite32(1, davinci_spi->base + SPIGCR0);
+ iowrite32(1, dspi->base + SPIGCR0);
- /* Clock internal */
- if (davinci_spi->pdata->clk_internal)
- set_io_bits(davinci_spi->base + SPIGCR1,
- SPIGCR1_CLKMOD_MASK);
- else
- clear_io_bits(davinci_spi->base + SPIGCR1,
- SPIGCR1_CLKMOD_MASK);
+ /* Set up SPIPC0. CS and ENA init is done in davinci_spi_setup */
+ spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK;
+ iowrite32(spipc0, dspi->base + SPIPC0);
- /* master mode default */
- set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+ /* initialize chip selects */
+ if (pdata->chip_sel) {
+ for (i = 0; i < pdata->num_chipselect; i++) {
+ if (pdata->chip_sel[i] != SPI_INTERN_CS)
+ gpio_direction_output(pdata->chip_sel[i], 1);
+ }
+ }
- if (davinci_spi->pdata->intr_level)
- iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
+ if (pdata->intr_line)
+ iowrite32(SPI_INTLVL_1, dspi->base + SPILVL);
else
- iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+ iowrite32(SPI_INTLVL_0, dspi->base + SPILVL);
- ret = spi_bitbang_start(&davinci_spi->bitbang);
- if (ret)
- goto free_clk;
+ iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
- dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base);
+ /* master mode default */
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+ set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+
+ ret = spi_bitbang_start(&dspi->bitbang);
+ if (ret)
+ goto free_dma;
- if (!pdata->poll_mode)
- dev_info(&pdev->dev, "Operating in interrupt mode"
- " using IRQ %d\n", davinci_spi->irq);
+ dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base);
return ret;
+free_dma:
+ edma_free_channel(dspi->dma.tx_channel);
+ edma_free_channel(dspi->dma.rx_channel);
+ edma_free_slot(dspi->dma.dummy_param_slot);
free_clk:
- clk_disable(davinci_spi->clk);
- clk_put(davinci_spi->clk);
+ clk_disable(dspi->clk);
+ clk_put(dspi->clk);
put_master:
spi_master_put(master);
-free_tmp_buf:
- kfree(davinci_spi->tmp_buf);
irq_free:
- free_irq(davinci_spi->irq, davinci_spi);
+ free_irq(dspi->irq, dspi);
unmap_io:
- iounmap(davinci_spi->base);
+ iounmap(dspi->base);
release_region:
- release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+ release_mem_region(dspi->pbase, resource_size(r));
free_master:
kfree(master);
err:
@@ -1222,27 +974,31 @@ err:
*/
static int __exit davinci_spi_remove(struct platform_device *pdev)
{
- struct davinci_spi *davinci_spi;
+ struct davinci_spi *dspi;
struct spi_master *master;
+ struct resource *r;
master = dev_get_drvdata(&pdev->dev);
- davinci_spi = spi_master_get_devdata(master);
+ dspi = spi_master_get_devdata(master);
- spi_bitbang_stop(&davinci_spi->bitbang);
+ spi_bitbang_stop(&dspi->bitbang);
- clk_disable(davinci_spi->clk);
- clk_put(davinci_spi->clk);
+ clk_disable(dspi->clk);
+ clk_put(dspi->clk);
spi_master_put(master);
- kfree(davinci_spi->tmp_buf);
- free_irq(davinci_spi->irq, davinci_spi);
- iounmap(davinci_spi->base);
- release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+ free_irq(dspi->irq, dspi);
+ iounmap(dspi->base);
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(dspi->pbase, resource_size(r));
return 0;
}
static struct platform_driver davinci_spi_driver = {
- .driver.name = "spi_davinci",
+ .driver = {
+ .name = "spi_davinci",
+ .owner = THIS_MODULE,
+ },
.remove = __exit_p(davinci_spi_remove),
};
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
index 90439314cf67..22af77f98816 100644
--- a/drivers/spi/dw_spi.c
+++ b/drivers/spi/dw_spi.c
@@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
static void wait_till_not_busy(struct dw_spi *dws)
{
- unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
+ unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
while (time_before(jiffies, end)) {
if (!(dw_readw(dws, sr) & SR_BUSY))
return;
+ cpu_relax();
}
dev_err(&dws->master->dev,
- "DW SPI: Status keeps busy for 1000us after a read/write!\n");
+ "DW SPI: Status keeps busy for 5000us after a read/write!\n");
}
static void flush(struct dw_spi *dws)
{
- while (dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+ while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
dw_readw(dws, dr);
+ cpu_relax();
+ }
wait_till_not_busy(dws);
}
@@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
*/
static int map_dma_buffers(struct dw_spi *dws)
{
- if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
- || !dws->cur_chip->enable_dma)
+ if (!dws->cur_msg->is_dma_mapped
+ || !dws->dma_inited
+ || !dws->cur_chip->enable_dma
+ || !dws->dma_ops)
return 0;
if (dws->cur_transfer->tx_dma)
@@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
tasklet_schedule(&dws->pump_transfers);
}
-static void transfer_complete(struct dw_spi *dws)
+void dw_spi_xfer_done(struct dw_spi *dws)
{
/* Update total byte transfered return count actual bytes read */
dws->cur_msg->actual_length += dws->len;
@@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
} else
tasklet_schedule(&dws->pump_transfers);
}
+EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
static irqreturn_t interrupt_transfer(struct dw_spi *dws)
{
@@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
if (dws->tx_end > dws->tx)
spi_umask_intr(dws, SPI_INT_TXEI);
else
- transfer_complete(dws);
+ dw_spi_xfer_done(dws);
}
return IRQ_HANDLED;
@@ -413,12 +419,13 @@ static void poll_transfer(struct dw_spi *dws)
{
while (dws->write(dws))
dws->read(dws);
+ /*
+ * There is a possibility that the last word of a transaction
+ * will be lost if data is not ready. Re-read to solve this issue.
+ */
+ dws->read(dws);
- transfer_complete(dws);
-}
-
-static void dma_transfer(struct dw_spi *dws, int cs_change)
-{
+ dw_spi_xfer_done(dws);
}
static void pump_transfers(unsigned long data)
@@ -587,7 +594,7 @@ static void pump_transfers(unsigned long data)
spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
spi_chip_sel(dws, spi->chip_select);
- /* Set the interrupt mask, for poll mode just diable all int */
+ /* Set the interrupt mask, for poll mode just disable all int */
spi_mask_intr(dws, 0xff);
if (imask)
spi_umask_intr(dws, imask);
@@ -600,7 +607,7 @@ static void pump_transfers(unsigned long data)
}
if (dws->dma_mapped)
- dma_transfer(dws, cs_change);
+ dws->dma_ops->dma_transfer(dws, cs_change);
if (chip->poll_mode)
poll_transfer(dws);
@@ -896,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
- dws->dma_inited = 0;
-
/* Basic HW init */
spi_hw_init(dws);
+ if (dws->dma_ops && dws->dma_ops->dma_init) {
+ ret = dws->dma_ops->dma_init(dws);
+ if (ret) {
+ dev_warn(&master->dev, "DMA init failed\n");
+ dws->dma_inited = 0;
+ }
+ }
+
/* Initial and start queue */
ret = init_queue(dws);
if (ret) {
@@ -925,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
err_queue_alloc:
destroy_queue(dws);
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+ dws->dma_ops->dma_exit(dws);
err_diable_hw:
spi_enable_chip(dws, 0);
free_irq(dws->irq, dws);
@@ -933,7 +948,7 @@ err_free_master:
exit:
return ret;
}
-EXPORT_SYMBOL(dw_spi_add_host);
+EXPORT_SYMBOL_GPL(dw_spi_add_host);
void __devexit dw_spi_remove_host(struct dw_spi *dws)
{
@@ -949,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
"complete, message memory not freed\n");
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+ dws->dma_ops->dma_exit(dws);
spi_enable_chip(dws, 0);
/* Disable clk */
spi_set_clk(dws, 0);
@@ -957,7 +974,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
/* Disconnect from the SPI framework */
spi_unregister_master(dws->master);
}
-EXPORT_SYMBOL(dw_spi_remove_host);
+EXPORT_SYMBOL_GPL(dw_spi_remove_host);
int dw_spi_suspend_host(struct dw_spi *dws)
{
@@ -970,7 +987,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
spi_set_clk(dws, 0);
return ret;
}
-EXPORT_SYMBOL(dw_spi_suspend_host);
+EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
int dw_spi_resume_host(struct dw_spi *dws)
{
@@ -982,7 +999,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
return ret;
}
-EXPORT_SYMBOL(dw_spi_resume_host);
+EXPORT_SYMBOL_GPL(dw_spi_resume_host);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c
new file mode 100644
index 000000000000..c91c966e0717
--- /dev/null
+++ b/drivers/spi/dw_spi_mid.c
@@ -0,0 +1,223 @@
+/*
+ * dw_spi_mid.c - special handling for DW core on Intel MID platform
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/dw_spi.h>
+
+#ifdef CONFIG_SPI_DW_MID_DMA
+#include <linux/intel_mid_dma.h>
+#include <linux/pci.h>
+
+struct mid_dma {
+ struct intel_mid_dma_slave dmas_tx;
+ struct intel_mid_dma_slave dmas_rx;
+};
+
+static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
+{
+ struct dw_spi *dws = param;
+
+ return dws->dmac && (&dws->dmac->dev == chan->device->dev);
+}
+
+static int mid_spi_dma_init(struct dw_spi *dws)
+{
+ struct mid_dma *dw_dma = dws->dma_priv;
+ struct intel_mid_dma_slave *rxs, *txs;
+ dma_cap_mask_t mask;
+
+ /*
+ * Get pci device for DMA controller, currently it could only
+ * be the DMA controller of either Moorestown or Medfield
+ */
+ dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
+ if (!dws->dmac)
+ dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /* 1. Init rx channel */
+ dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
+ if (!dws->rxchan)
+ goto err_exit;
+ rxs = &dw_dma->dmas_rx;
+ rxs->hs_mode = LNW_DMA_HW_HS;
+ rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
+ dws->rxchan->private = rxs;
+
+ /* 2. Init tx channel */
+ dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
+ if (!dws->txchan)
+ goto free_rxchan;
+ txs = &dw_dma->dmas_tx;
+ txs->hs_mode = LNW_DMA_HW_HS;
+ txs->cfg_mode = LNW_DMA_MEM_TO_PER;
+ dws->txchan->private = txs;
+
+ dws->dma_inited = 1;
+ return 0;
+
+free_rxchan:
+ dma_release_channel(dws->rxchan);
+err_exit:
+ return -1;
+
+}
+
+static void mid_spi_dma_exit(struct dw_spi *dws)
+{
+ dma_release_channel(dws->txchan);
+ dma_release_channel(dws->rxchan);
+}
+
+/*
+ * dws->dma_chan_done is cleared before the dma transfer starts,
+ * callback for rx/tx channel will each increment it by 1.
+ * Reaching 2 means the whole spi transaction is done.
+ */
+static void dw_spi_dma_done(void *arg)
+{
+ struct dw_spi *dws = arg;
+
+ if (++dws->dma_chan_done != 2)
+ return;
+ dw_spi_xfer_done(dws);
+}
+
+static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+{
+ struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
+ struct dma_chan *txchan, *rxchan;
+ struct dma_slave_config txconf, rxconf;
+ u16 dma_ctrl = 0;
+
+ /* 1. setup DMA related registers */
+ if (cs_change) {
+ spi_enable_chip(dws, 0);
+ dw_writew(dws, dmardlr, 0xf);
+ dw_writew(dws, dmatdlr, 0x10);
+ if (dws->tx_dma)
+ dma_ctrl |= 0x2;
+ if (dws->rx_dma)
+ dma_ctrl |= 0x1;
+ dw_writew(dws, dmacr, dma_ctrl);
+ spi_enable_chip(dws, 1);
+ }
+
+ dws->dma_chan_done = 0;
+ txchan = dws->txchan;
+ rxchan = dws->rxchan;
+
+ /* 2. Prepare the TX dma transfer */
+ txconf.direction = DMA_TO_DEVICE;
+ txconf.dst_addr = dws->dma_addr;
+ txconf.dst_maxburst = LNW_DMA_MSIZE_16;
+ txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+ (unsigned long) &txconf);
+
+ memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
+ dws->tx_sgl.dma_address = dws->tx_dma;
+ dws->tx_sgl.length = dws->len;
+
+ txdesc = txchan->device->device_prep_slave_sg(txchan,
+ &dws->tx_sgl,
+ 1,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+ txdesc->callback = dw_spi_dma_done;
+ txdesc->callback_param = dws;
+
+ /* 3. Prepare the RX dma transfer */
+ rxconf.direction = DMA_FROM_DEVICE;
+ rxconf.src_addr = dws->dma_addr;
+ rxconf.src_maxburst = LNW_DMA_MSIZE_16;
+ rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+ (unsigned long) &rxconf);
+
+ memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
+ dws->rx_sgl.dma_address = dws->rx_dma;
+ dws->rx_sgl.length = dws->len;
+
+ rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ &dws->rx_sgl,
+ 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+ rxdesc->callback = dw_spi_dma_done;
+ rxdesc->callback_param = dws;
+
+ /* rx must be started before tx due to spi instinct */
+ rxdesc->tx_submit(rxdesc);
+ txdesc->tx_submit(txdesc);
+ return 0;
+}
+
+static struct dw_spi_dma_ops mid_dma_ops = {
+ .dma_init = mid_spi_dma_init,
+ .dma_exit = mid_spi_dma_exit,
+ .dma_transfer = mid_spi_dma_transfer,
+};
+#endif
+
+/* Some specific info for SPI0 controller on Moorestown */
+
+/* HW info for MRST CLk Control Unit, one 32b reg */
+#define MRST_SPI_CLK_BASE 100000000 /* 100m */
+#define MRST_CLK_SPI0_REG 0xff11d86c
+#define CLK_SPI_BDIV_OFFSET 0
+#define CLK_SPI_BDIV_MASK 0x00000007
+#define CLK_SPI_CDIV_OFFSET 9
+#define CLK_SPI_CDIV_MASK 0x00000e00
+#define CLK_SPI_DISABLE_OFFSET 8
+
+int dw_spi_mid_init(struct dw_spi *dws)
+{
+ u32 *clk_reg, clk_cdiv;
+
+ clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
+ if (!clk_reg)
+ return -ENOMEM;
+
+ /* get SPI controller operating freq info */
+ clk_cdiv = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
+ dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
+ iounmap(clk_reg);
+
+ dws->num_cs = 16;
+ dws->fifo_len = 40; /* FIFO has 40 words buffer */
+
+#ifdef CONFIG_SPI_DW_MID_DMA
+ dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
+ if (!dws->dma_priv)
+ return -ENOMEM;
+ dws->dma_ops = &mid_dma_ops;
+#endif
+ return 0;
+}
diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c
index db35bd9c1b24..2fa012c109bc 100644
--- a/drivers/spi/dw_spi_mmio.c
+++ b/drivers/spi/dw_spi_mmio.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -68,8 +69,8 @@ static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
}
dwsmmio->clk = clk_get(&pdev->dev, NULL);
- if (!dwsmmio->clk) {
- ret = -ENODEV;
+ if (IS_ERR(dwsmmio->clk)) {
+ ret = PTR_ERR(dwsmmio->clk);
goto err_irq;
}
clk_enable(dwsmmio->clk);
diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c
index 1f52755dc878..49ec3aa1219f 100644
--- a/drivers/spi/dw_spi_pci.c
+++ b/drivers/spi/dw_spi_pci.c
@@ -1,5 +1,5 @@
/*
- * mrst_spi_pci.c - PCI interface driver for DW SPI Core
+ * dw_spi_pci.c - PCI interface driver for DW SPI Core
*
* Copyright (c) 2009, Intel Corporation.
*
@@ -26,8 +26,8 @@
#define DRIVER_NAME "dw_spi_pci"
struct dw_spi_pci {
- struct pci_dev *pdev;
- struct dw_spi dws;
+ struct pci_dev *pdev;
+ struct dw_spi dws;
};
static int __devinit spi_pci_probe(struct pci_dev *pdev,
@@ -72,9 +72,17 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
dws->parent_dev = &pdev->dev;
dws->bus_num = 0;
dws->num_cs = 4;
- dws->max_freq = 25000000; /* for Moorestwon */
dws->irq = pdev->irq;
- dws->fifo_len = 40; /* FIFO has 40 words buffer */
+
+ /*
+ * Specific handling for Intel MID paltforms, like dma setup,
+ * clock rate, FIFO depth.
+ */
+ if (pdev->device == 0x0800) {
+ ret = dw_spi_mid_init(dws);
+ if (ret)
+ goto err_unmap;
+ }
ret = dw_spi_add_host(dws);
if (ret)
@@ -140,7 +148,7 @@ static int spi_resume(struct pci_dev *pdev)
#endif
static const struct pci_device_id pci_ids[] __devinitdata = {
- /* Intel Moorestown platform SPI controller 0 */
+ /* Intel MID platform SPI controller 0 */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
{},
};
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 983fbbfce76e..8a904c1c8485 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
}
/* bus_num is used only for the case dev->platform_data == NULL */
-static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq, s16 bus_num)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -450,22 +450,7 @@ free_master:
return ret;
}
-static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
-{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
-
- flush_workqueue(mps->workqueue);
- destroy_workqueue(mps->workqueue);
- spi_unregister_master(master);
- free_irq(mps->irq, mps);
- if (mps->psc)
- iounmap(mps->psc);
-
- return 0;
-}
-
-static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
+static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op,
const struct of_device_id *match)
{
const u32 *regaddr_p;
@@ -495,9 +480,19 @@ static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
irq_of_parse_and_map(op->dev.of_node, 0), id);
}
-static int __exit mpc52xx_psc_spi_of_remove(struct platform_device *op)
+static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
{
- return mpc52xx_psc_spi_do_remove(&op->dev);
+ struct spi_master *master = dev_get_drvdata(&op->dev);
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+ flush_workqueue(mps->workqueue);
+ destroy_workqueue(mps->workqueue);
+ spi_unregister_master(master);
+ free_irq(mps->irq, mps);
+ if (mps->psc)
+ iounmap(mps->psc);
+
+ return 0;
}
static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
@@ -510,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
.probe = mpc52xx_psc_spi_of_probe,
- .remove = __exit_p(mpc52xx_psc_spi_of_remove),
+ .remove = __devexit_p(mpc52xx_psc_spi_of_remove),
.driver = {
.name = "mpc52xx-psc-spi",
.owner = THIS_MODULE,
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
index ec9f0b1bf864..84439f655601 100644
--- a/drivers/spi/mpc52xx_spi.c
+++ b/drivers/spi/mpc52xx_spi.c
@@ -563,7 +563,7 @@ static struct of_platform_driver mpc52xx_spi_of_driver = {
.of_match_table = mpc52xx_spi_match,
},
.probe = mpc52xx_spi_probe,
- .remove = __exit_p(mpc52xx_spi_remove),
+ .remove = __devexit_p(mpc52xx_spi_remove),
};
static int __init mpc52xx_spi_init(void)
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 2a651e61bfbf..abb1ffbf3d20 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -397,7 +397,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion);
- dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+ dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE);
/* for TX_ONLY mode, be sure all words have shifted out */
if (rx == NULL) {
@@ -412,7 +412,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (rx != NULL) {
wait_for_completion(&mcspi_dma->dma_rx_completion);
- dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+ dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
omap2_mcspi_set_enable(spi, 0);
if (l & OMAP2_MCSPI_CHCONF_TURBO) {
@@ -1025,11 +1025,6 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
- /* Do DMA mapping "early" for better error reporting and
- * dcache use. Note that if dma_unmap_single() ever starts
- * to do real work on ARM, we'd need to clean up mappings
- * for previous transfers on *ALL* exits of this loop...
- */
if (tx_buf != NULL) {
t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
len, DMA_TO_DEVICE);
@@ -1046,7 +1041,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
'R', len);
if (tx_buf != NULL)
- dma_unmap_single(NULL, t->tx_dma,
+ dma_unmap_single(&spi->dev, t->tx_dma,
len, DMA_TO_DEVICE);
return -EINVAL;
}
@@ -1305,10 +1300,49 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:omap2_mcspi");
+#ifdef CONFIG_SUSPEND
+/*
+ * When SPI wake up from off-mode, CS is in activate state. If it was in
+ * unactive state when driver was suspend, then force it to unactive state at
+ * wake up.
+ */
+static int omap2_mcspi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi_cs *cs;
+
+ omap2_mcspi_enable_clocks(mcspi);
+ list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
+ node) {
+ if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
+
+ /*
+ * We need to toggle CS state for OMAP take this
+ * change in account.
+ */
+ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
+ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
+ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
+ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
+ }
+ }
+ omap2_mcspi_disable_clocks(mcspi);
+ return 0;
+}
+#else
+#define omap2_mcspi_resume NULL
+#endif
+
+static const struct dev_pm_ops omap2_mcspi_pm_ops = {
+ .resume = omap2_mcspi_resume,
+};
+
static struct platform_driver omap2_mcspi_driver = {
.driver = {
.name = "omap2_mcspi",
.owner = THIS_MODULE,
+ .pm = &omap2_mcspi_pm_ops
},
.remove = __exit_p(omap2_mcspi_remove),
};
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index e76b1afafe07..95928833855b 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -23,11 +23,11 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/spi/pxa2xx_spi.h>
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
-#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -35,9 +35,6 @@
#include <asm/irq.h>
#include <asm/delay.h>
-#include <mach/dma.h>
-#include <plat/ssp.h>
-#include <mach/pxa2xx_spi.h>
MODULE_AUTHOR("Stephen Street");
MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define MAX_BUSES 3
-#define RX_THRESH_DFLT 8
-#define TX_THRESH_DFLT 8
#define TIMOUT_DFLT 1000
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
@@ -168,7 +163,10 @@ struct chip_data {
u8 enable_dma;
u8 bits_per_word;
u32 speed_hz;
- int gpio_cs;
+ union {
+ int gpio_cs;
+ unsigned int frm;
+ };
int gpio_cs_inverted;
int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data);
@@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ if (drv_data->ssp_type == CE4100_SSP) {
+ write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
+ return;
+ }
+
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_ASSERT);
return;
@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ if (drv_data->ssp_type == CE4100_SSP)
+ return;
+
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_DEASSERT);
return;
@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
}
+static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+{
+ void __iomem *reg = drv_data->ioaddr;
+
+ if (drv_data->ssp_type == CE4100_SSP)
+ val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
+
+ write_SSSR(val, reg);
+}
+
+static int pxa25x_ssp_comp(struct driver_data *drv_data)
+{
+ if (drv_data->ssp_type == PXA25x_SSP)
+ return 1;
+ if (drv_data->ssp_type == CE4100_SSP)
+ return 1;
+ return 0;
+}
+
static int flush(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data)
read_SSDR(reg);
}
} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
- write_SSSR(SSSR_ROR, reg);
+ write_SSSR_CS(drv_data, SSSR_ROR);
return limit;
}
@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data)
void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
/* Stop and reset */
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- write_SSSR(drv_data->clear_sr, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
flush(drv_data);
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
@@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data)
/* Clear and disable interrupts on SSP and DMA channels*/
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- write_SSSR(drv_data->clear_sr, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
@@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
/* Clear and disable timeout interrupt, do the rest in
* dma_transfer_complete */
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
/* finish this transfer, start the next */
@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
return IRQ_NONE;
}
+static void reset_sccr1(struct driver_data *drv_data)
+{
+ void __iomem *reg = drv_data->ioaddr;
+ struct chip_data *chip = drv_data->cur_chip;
+ u32 sccr1_reg;
+
+ sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
+ sccr1_reg &= ~SSCR1_RFT;
+ sccr1_reg |= chip->threshold;
+ write_SSCR1(sccr1_reg, reg);
+}
+
static void int_error_stop(struct driver_data *drv_data, const char* msg)
{
void __iomem *reg = drv_data->ioaddr;
/* Stop and reset SSP */
- write_SSSR(drv_data->clear_sr, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
+ reset_sccr1(drv_data);
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
flush(drv_data);
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
@@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
void __iomem *reg = drv_data->ioaddr;
/* Stop SSP */
- write_SSSR(drv_data->clear_sr, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
+ reset_sccr1(drv_data);
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
/* Update total byte transfered return count actual bytes read */
@@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
}
if (drv_data->tx == drv_data->tx_end) {
- write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
- /* PXA25x_SSP has no timeout, read trailing bytes */
- if (drv_data->ssp_type == PXA25x_SSP) {
- if (!wait_ssp_rx_stall(reg))
- {
- int_error_stop(drv_data, "interrupt_transfer: "
- "rx stall failed");
- return IRQ_HANDLED;
- }
- if (!drv_data->read(drv_data))
- {
- int_error_stop(drv_data,
- "interrupt_transfer: "
- "trailing byte read failed");
- return IRQ_HANDLED;
+ u32 bytes_left;
+ u32 sccr1_reg;
+
+ sccr1_reg = read_SSCR1(reg);
+ sccr1_reg &= ~SSCR1_TIE;
+
+ /*
+ * PXA25x_SSP has no timeout, set up rx threshould for the
+ * remaing RX bytes.
+ */
+ if (pxa25x_ssp_comp(drv_data)) {
+
+ sccr1_reg &= ~SSCR1_RFT;
+
+ bytes_left = drv_data->rx_end - drv_data->rx;
+ switch (drv_data->n_bytes) {
+ case 4:
+ bytes_left >>= 1;
+ case 2:
+ bytes_left >>= 1;
}
- int_transfer_complete(drv_data);
+
+ if (bytes_left > RX_THRESH_DFLT)
+ bytes_left = RX_THRESH_DFLT;
+
+ sccr1_reg |= SSCR1_RxTresh(bytes_left);
}
+ write_SSCR1(sccr1_reg, reg);
}
/* We did something */
@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
{
struct driver_data *drv_data = dev_id;
void __iomem *reg = drv_data->ioaddr;
+ u32 sccr1_reg = read_SSCR1(reg);
+ u32 mask = drv_data->mask_sr;
+ u32 status;
+
+ status = read_SSSR(reg);
+
+ /* Ignore possible writes if we don't need to write */
+ if (!(sccr1_reg & SSCR1_TIE))
+ mask &= ~SSSR_TFS;
+
+ if (!(status & mask))
+ return IRQ_NONE;
if (!drv_data->cur_msg) {
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
dev_err(&drv_data->pdev->dev, "bad message state "
"in interrupt handler\n");
@@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
{
unsigned long ssp_clk = clk_get_rate(ssp->clk);
- if (ssp->type == PXA25x_SSP)
+ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
else
return ((ssp_clk / rate - 1) & 0xfff) << 8;
@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data)
/* Clear status */
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
- write_SSSR(drv_data->clear_sr, reg);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
}
/* see if we need to reload the config registers */
@@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data)
/* stop the SSP, and update the other bits */
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(chip->timeout, reg);
/* first set CR1 without interrupt and service enables */
write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data)
write_SSCR0(cr0, reg);
} else {
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(chip->timeout, reg);
}
@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi)
uint tx_thres = TX_THRESH_DFLT;
uint rx_thres = RX_THRESH_DFLT;
- if (drv_data->ssp_type != PXA25x_SSP
+ if (!pxa25x_ssp_comp(drv_data)
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
"b/w not 4-32 for type non-PXA25x_SSP\n",
drv_data->ssp_type, spi->bits_per_word);
return -EINVAL;
- }
- else if (drv_data->ssp_type == PXA25x_SSP
+ } else if (pxa25x_ssp_comp(drv_data)
&& (spi->bits_per_word < 4
|| spi->bits_per_word > 16)) {
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
@@ -1259,7 +1317,17 @@ static int setup(struct spi_device *spi)
return -ENOMEM;
}
- chip->gpio_cs = -1;
+ if (drv_data->ssp_type == CE4100_SSP) {
+ if (spi->chip_select > 4) {
+ dev_err(&spi->dev, "failed setup: "
+ "cs number must not be > 4.\n");
+ kfree(chip);
+ return -EINVAL;
+ }
+
+ chip->frm = spi->chip_select;
+ } else
+ chip->gpio_cs = -1;
chip->enable_dma = 0;
chip->timeout = TIMOUT_DFLT;
chip->dma_burst_size = drv_data->master_info->enable_dma ?
@@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi)
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi)
spi_set_ctldata(spi, chip);
+ if (drv_data->ssp_type == CE4100_SSP)
+ return 0;
+
return setup_cs(spi, chip, chip_info);
}
static void cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
if (!chip)
return;
- if (gpio_is_valid(chip->gpio_cs))
+ if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
gpio_free(chip->gpio_cs);
kfree(chip);
}
-static int __init init_queue(struct driver_data *drv_data)
+static int __devinit init_queue(struct driver_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
return 0;
}
-static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->pdev = pdev;
drv_data->ssp = ssp;
+ master->dev.parent = &pdev->dev;
+#ifdef CONFIG_OF
+ master->dev.of_node = pdev->dev.of_node;
+#endif
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR;
- if (ssp->type == PXA25x_SSP) {
+ if (pxa25x_ssp_comp(drv_data)) {
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
drv_data->dma_cr1 = 0;
drv_data->clear_sr = SSSR_ROR;
@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
}
- status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data);
+ status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
+ drv_data);
if (status < 0) {
dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
goto out_error_master_alloc;
@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
| SSCR0_Motorola
| SSCR0_DataSize(8),
drv_data->ioaddr);
- if (drv_data->ssp_type != PXA25x_SSP)
+ if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, drv_data->ioaddr);
write_SSPSP(0, drv_data->ioaddr);
@@ -1723,13 +1800,14 @@ static struct platform_driver driver = {
.pm = &pxa2xx_spi_pm_ops,
#endif
},
+ .probe = pxa2xx_spi_probe,
.remove = pxa2xx_spi_remove,
.shutdown = pxa2xx_spi_shutdown,
};
static int __init pxa2xx_spi_init(void)
{
- return platform_driver_probe(&driver, pxa2xx_spi_probe);
+ return platform_driver_register(&driver);
}
subsys_initcall(pxa2xx_spi_init);
diff --git a/drivers/spi/pxa2xx_spi_pci.c b/drivers/spi/pxa2xx_spi_pci.c
new file mode 100644
index 000000000000..351d8a375b57
--- /dev/null
+++ b/drivers/spi/pxa2xx_spi_pci.c
@@ -0,0 +1,201 @@
+/*
+ * CE4100's SPI device is more or less the same one as found on PXA
+ *
+ */
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+struct awesome_struct {
+ struct ssp_device ssp;
+ struct platform_device spi_pdev;
+ struct pxa2xx_spi_master spi_pdata;
+};
+
+static DEFINE_MUTEX(ssp_lock);
+static LIST_HEAD(ssp_list);
+
+struct ssp_device *pxa_ssp_request(int port, const char *label)
+{
+ struct ssp_device *ssp = NULL;
+
+ mutex_lock(&ssp_lock);
+
+ list_for_each_entry(ssp, &ssp_list, node) {
+ if (ssp->port_id == port && ssp->use_count == 0) {
+ ssp->use_count++;
+ ssp->label = label;
+ break;
+ }
+ }
+
+ mutex_unlock(&ssp_lock);
+
+ if (&ssp->node == &ssp_list)
+ return NULL;
+
+ return ssp;
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_request);
+
+void pxa_ssp_free(struct ssp_device *ssp)
+{
+ mutex_lock(&ssp_lock);
+ if (ssp->use_count) {
+ ssp->use_count--;
+ ssp->label = NULL;
+ } else
+ dev_err(&ssp->pdev->dev, "device already free\n");
+ mutex_unlock(&ssp_lock);
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_free);
+
+static void plat_dev_release(struct device *dev)
+{
+ struct awesome_struct *as = container_of(dev,
+ struct awesome_struct, spi_pdev.dev);
+
+ of_device_node_put(&as->spi_pdev.dev);
+}
+
+static int __devinit ce4100_spi_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ resource_size_t phys_beg;
+ resource_size_t phys_len;
+ struct awesome_struct *spi_info;
+ struct platform_device *pdev;
+ struct pxa2xx_spi_master *spi_pdata;
+ struct ssp_device *ssp;
+
+ ret = pci_enable_device(dev);
+ if (ret)
+ return ret;
+
+ phys_beg = pci_resource_start(dev, 0);
+ phys_len = pci_resource_len(dev, 0);
+
+ if (!request_mem_region(phys_beg, phys_len,
+ "CE4100 SPI")) {
+ dev_err(&dev->dev, "Can't request register space.\n");
+ ret = -EBUSY;
+ return ret;
+ }
+
+ spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
+ if (!spi_info) {
+ ret = -ENOMEM;
+ goto err_kz;
+ }
+ ssp = &spi_info->ssp;
+ pdev = &spi_info->spi_pdev;
+ spi_pdata = &spi_info->spi_pdata;
+
+ pdev->name = "pxa2xx-spi";
+ pdev->id = dev->devfn;
+ pdev->dev.parent = &dev->dev;
+ pdev->dev.platform_data = &spi_info->spi_pdata;
+
+#ifdef CONFIG_OF
+ pdev->dev.of_node = dev->dev.of_node;
+#endif
+ pdev->dev.release = plat_dev_release;
+
+ spi_pdata->num_chipselect = dev->devfn;
+
+ ssp->phys_base = pci_resource_start(dev, 0);
+ ssp->mmio_base = ioremap(phys_beg, phys_len);
+ if (!ssp->mmio_base) {
+ dev_err(&pdev->dev, "failed to ioremap() registers\n");
+ ret = -EIO;
+ goto err_remap;
+ }
+ ssp->irq = dev->irq;
+ ssp->port_id = pdev->id;
+ ssp->type = PXA25x_SSP;
+
+ mutex_lock(&ssp_lock);
+ list_add(&ssp->node, &ssp_list);
+ mutex_unlock(&ssp_lock);
+
+ pci_set_drvdata(dev, spi_info);
+
+ ret = platform_device_register(pdev);
+ if (ret)
+ goto err_dev_add;
+
+ return ret;
+
+err_dev_add:
+ pci_set_drvdata(dev, NULL);
+ mutex_lock(&ssp_lock);
+ list_del(&ssp->node);
+ mutex_unlock(&ssp_lock);
+ iounmap(ssp->mmio_base);
+
+err_remap:
+ kfree(spi_info);
+
+err_kz:
+ release_mem_region(phys_beg, phys_len);
+
+ return ret;
+}
+
+static void __devexit ce4100_spi_remove(struct pci_dev *dev)
+{
+ struct awesome_struct *spi_info;
+ struct platform_device *pdev;
+ struct ssp_device *ssp;
+
+ spi_info = pci_get_drvdata(dev);
+
+ ssp = &spi_info->ssp;
+ pdev = &spi_info->spi_pdev;
+
+ platform_device_unregister(pdev);
+
+ iounmap(ssp->mmio_base);
+ release_mem_region(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+
+ mutex_lock(&ssp_lock);
+ list_del(&ssp->node);
+ mutex_unlock(&ssp_lock);
+
+ pci_set_drvdata(dev, NULL);
+ pci_disable_device(dev);
+ kfree(spi_info);
+}
+
+static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
+
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
+ { },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
+
+static struct pci_driver ce4100_spi_driver = {
+ .name = "ce4100_spi",
+ .id_table = ce4100_spi_devices,
+ .probe = ce4100_spi_probe,
+ .remove = __devexit_p(ce4100_spi_remove),
+};
+
+static int __init ce4100_spi_init(void)
+{
+ return pci_register_driver(&ce4100_spi_driver);
+}
+module_init(ce4100_spi_init);
+
+static void __exit ce4100_spi_exit(void)
+{
+ pci_unregister_driver(&ce4100_spi_driver);
+}
+module_exit(ce4100_spi_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b5a78a1f4421..34bb17f03019 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -28,12 +28,8 @@
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/of_spi.h>
+#include <linux/pm_runtime.h>
-
-/* SPI bustype and spi_master class are registered after board init code
- * provides the SPI device tables, ensuring that both are present by the
- * time controller driver registration causes spi_devices to "enumerate".
- */
static void spidev_release(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
@@ -105,9 +101,8 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-#ifdef CONFIG_PM
-
-static int spi_suspend(struct device *dev, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int spi_legacy_suspend(struct device *dev, pm_message_t message)
{
int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
@@ -122,7 +117,7 @@ static int spi_suspend(struct device *dev, pm_message_t message)
return value;
}
-static int spi_resume(struct device *dev)
+static int spi_legacy_resume(struct device *dev)
{
int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
@@ -137,18 +132,94 @@ static int spi_resume(struct device *dev)
return value;
}
+static int spi_pm_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_suspend(dev);
+ else
+ return spi_legacy_suspend(dev, PMSG_SUSPEND);
+}
+
+static int spi_pm_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_resume(dev);
+ else
+ return spi_legacy_resume(dev);
+}
+
+static int spi_pm_freeze(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_freeze(dev);
+ else
+ return spi_legacy_suspend(dev, PMSG_FREEZE);
+}
+
+static int spi_pm_thaw(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_thaw(dev);
+ else
+ return spi_legacy_resume(dev);
+}
+
+static int spi_pm_poweroff(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_poweroff(dev);
+ else
+ return spi_legacy_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int spi_pm_restore(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm)
+ return pm_generic_restore(dev);
+ else
+ return spi_legacy_resume(dev);
+}
#else
-#define spi_suspend NULL
-#define spi_resume NULL
+#define spi_pm_suspend NULL
+#define spi_pm_resume NULL
+#define spi_pm_freeze NULL
+#define spi_pm_thaw NULL
+#define spi_pm_poweroff NULL
+#define spi_pm_restore NULL
#endif
+static const struct dev_pm_ops spi_pm = {
+ .suspend = spi_pm_suspend,
+ .resume = spi_pm_resume,
+ .freeze = spi_pm_freeze,
+ .thaw = spi_pm_thaw,
+ .poweroff = spi_pm_poweroff,
+ .restore = spi_pm_restore,
+ SET_RUNTIME_PM_OPS(
+ pm_generic_runtime_suspend,
+ pm_generic_runtime_resume,
+ pm_generic_runtime_idle
+ )
+};
+
struct bus_type spi_bus_type = {
.name = "spi",
.dev_attrs = spi_dev_attrs,
.match = spi_match_device,
.uevent = spi_uevent,
- .suspend = spi_suspend,
- .resume = spi_resume,
+ .pm = &spi_pm,
};
EXPORT_SYMBOL_GPL(spi_bus_type);
@@ -202,11 +273,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver);
struct boardinfo {
struct list_head list;
- unsigned n_board_info;
- struct spi_board_info board_info[0];
+ struct spi_board_info board_info;
};
static LIST_HEAD(board_list);
+static LIST_HEAD(spi_master_list);
+
+/*
+ * Used to protect add/del opertion for board_info list and
+ * spi_master list, and their matching process
+ */
static DEFINE_MUTEX(board_lock);
/**
@@ -300,16 +376,16 @@ int spi_add_device(struct spi_device *spi)
*/
status = spi_setup(spi);
if (status < 0) {
- dev_err(dev, "can't %s %s, status %d\n",
- "setup", dev_name(&spi->dev), status);
+ dev_err(dev, "can't setup %s, status %d\n",
+ dev_name(&spi->dev), status);
goto done;
}
/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < 0)
- dev_err(dev, "can't %s %s, status %d\n",
- "add", dev_name(&spi->dev), status);
+ dev_err(dev, "can't add %s, status %d\n",
+ dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
@@ -371,6 +447,20 @@ struct spi_device *spi_new_device(struct spi_master *master,
}
EXPORT_SYMBOL_GPL(spi_new_device);
+static void spi_match_master_to_boardinfo(struct spi_master *master,
+ struct spi_board_info *bi)
+{
+ struct spi_device *dev;
+
+ if (master->bus_num != bi->bus_num)
+ return;
+
+ dev = spi_new_device(master, bi);
+ if (!dev)
+ dev_err(master->dev.parent, "can't create new device for %s\n",
+ bi->modalias);
+}
+
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
@@ -393,43 +483,25 @@ EXPORT_SYMBOL_GPL(spi_new_device);
int __init
spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
- struct boardinfo *bi;
+ struct boardinfo *bi;
+ int i;
- bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+ bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM;
- bi->n_board_info = n;
- memcpy(bi->board_info, info, n * sizeof *info);
-
- mutex_lock(&board_lock);
- list_add_tail(&bi->list, &board_list);
- mutex_unlock(&board_lock);
- return 0;
-}
-/* FIXME someone should add support for a __setup("spi", ...) that
- * creates board info from kernel command lines
- */
-
-static void scan_boardinfo(struct spi_master *master)
-{
- struct boardinfo *bi;
+ for (i = 0; i < n; i++, bi++, info++) {
+ struct spi_master *master;
- mutex_lock(&board_lock);
- list_for_each_entry(bi, &board_list, list) {
- struct spi_board_info *chip = bi->board_info;
- unsigned n;
-
- for (n = bi->n_board_info; n > 0; n--, chip++) {
- if (chip->bus_num != master->bus_num)
- continue;
- /* NOTE: this relies on spi_new_device to
- * issue diagnostics when given bogus inputs
- */
- (void) spi_new_device(master, chip);
- }
+ memcpy(&bi->board_info, info, sizeof(*info));
+ mutex_lock(&board_lock);
+ list_add_tail(&bi->list, &board_list);
+ list_for_each_entry(master, &spi_master_list, list)
+ spi_match_master_to_boardinfo(master, &bi->board_info);
+ mutex_unlock(&board_lock);
}
- mutex_unlock(&board_lock);
+
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -512,6 +584,7 @@ int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = master->dev.parent;
+ struct boardinfo *bi;
int status = -ENODEV;
int dynamic = 0;
@@ -547,8 +620,12 @@ int spi_register_master(struct spi_master *master)
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
- /* populate children from any spi device tables */
- scan_boardinfo(master);
+ mutex_lock(&board_lock);
+ list_add_tail(&master->list, &spi_master_list);
+ list_for_each_entry(bi, &board_list, list)
+ spi_match_master_to_boardinfo(master, &bi->board_info);
+ mutex_unlock(&board_lock);
+
status = 0;
/* Register devices from the device tree */
@@ -579,6 +656,10 @@ void spi_unregister_master(struct spi_master *master)
{
int dummy;
+ mutex_lock(&board_lock);
+ list_del(&master->list);
+ mutex_unlock(&board_lock);
+
dummy = device_for_each_child(&master->dev, NULL, __unregister);
device_unregister(&master->dev);
}
@@ -652,7 +733,7 @@ int spi_setup(struct spi_device *spi)
*/
bad_bits = spi->mode & ~spi->master->mode_bits;
if (bad_bits) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index ab483a0ec6d0..3f223511127b 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -504,6 +504,15 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
dmastat, spistat);
+ if (drv_data->rx != NULL) {
+ u16 cr = read_CTRL(drv_data);
+ /* discard old RX data and clear RXS */
+ bfin_spi_dummy_read(drv_data);
+ write_CTRL(drv_data, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
+ write_CTRL(drv_data, cr & ~BIT_CTL_TIMOD); /* Restore State */
+ write_STAT(drv_data, BIT_STAT_CLR); /* Clear Status */
+ }
+
clear_dma_irqstat(drv_data->dma_channel);
/*
@@ -1099,12 +1108,15 @@ static int bfin_spi_setup(struct spi_device *spi)
}
if (chip->chip_select_num >= MAX_CTRL_CS) {
- ret = gpio_request(chip->cs_gpio, spi->modalias);
- if (ret) {
- dev_err(&spi->dev, "gpio_request() error\n");
- goto pin_error;
+ /* Only request on first setup */
+ if (spi_get_ctldata(spi) == NULL) {
+ ret = gpio_request(chip->cs_gpio, spi->modalias);
+ if (ret) {
+ dev_err(&spi->dev, "gpio_request() error\n");
+ goto pin_error;
+ }
+ gpio_direction_output(chip->cs_gpio, 1);
}
- gpio_direction_output(chip->cs_gpio, 1);
}
dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
index e3b4f6451966..a99e2333b949 100644
--- a/drivers/spi/spi_fsl_espi.c
+++ b/drivers/spi/spi_fsl_espi.c
@@ -258,18 +258,18 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
return mpc8xxx_spi->count;
}
-static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
+static inline void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
{
- if (cmd[1] && cmd[2] && cmd[3]) {
+ if (cmd) {
cmd[1] = (u8)(addr >> 16);
cmd[2] = (u8)(addr >> 8);
cmd[3] = (u8)(addr >> 0);
}
}
-static unsigned int fsl_espi_cmd2addr(u8 *cmd)
+static inline unsigned int fsl_espi_cmd2addr(u8 *cmd)
{
- if (cmd[1] && cmd[2] && cmd[3])
+ if (cmd)
return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0;
return 0;
@@ -395,9 +395,11 @@ static void fsl_espi_rw_trans(struct spi_message *m,
}
}
- addr = fsl_espi_cmd2addr(local_buf);
- addr += pos;
- fsl_espi_addr2cmd(addr, local_buf);
+ if (pos > 0) {
+ addr = fsl_espi_cmd2addr(local_buf);
+ addr += pos;
+ fsl_espi_addr2cmd(addr, local_buf);
+ }
espi_trans->n_tx = n_tx;
espi_trans->n_rx = trans_len;
@@ -507,16 +509,29 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
/* We need handle RX first */
if (events & SPIE_NE) {
- u32 rx_data;
+ u32 rx_data, tmp;
+ u8 rx_data_8;
/* Spin until RX is done */
while (SPIE_RXCNT(events) < min(4, mspi->len)) {
cpu_relax();
events = mpc8xxx_spi_read_reg(&reg_base->event);
}
- mspi->len -= 4;
- rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+ if (mspi->len >= 4) {
+ rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+ } else {
+ tmp = mspi->len;
+ rx_data = 0;
+ while (tmp--) {
+ rx_data_8 = in_8((u8 *)&reg_base->receive);
+ rx_data |= (rx_data_8 << (tmp * 8));
+ }
+
+ rx_data <<= (4 - mspi->len) * 8;
+ }
+
+ mspi->len -= 4;
if (mspi->rx)
mspi->get_rx(rx_data, mspi);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 55a38e2c6c13..1cf9d5faabf4 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -66,7 +66,6 @@ enum spi_imx_devtype {
SPI_IMX_VER_0_5,
SPI_IMX_VER_0_7,
SPI_IMX_VER_2_3,
- SPI_IMX_VER_AUTODETECT,
};
struct spi_imx_data;
@@ -720,9 +719,6 @@ static void spi_imx_cleanup(struct spi_device *spi)
static struct platform_device_id spi_imx_devtype[] = {
{
- .name = DRIVER_NAME,
- .driver_data = SPI_IMX_VER_AUTODETECT,
- }, {
.name = "imx1-cspi",
.driver_data = SPI_IMX_VER_IMX1,
}, {
@@ -747,6 +743,12 @@ static struct platform_device_id spi_imx_devtype[] = {
.name = "imx51-ecspi",
.driver_data = SPI_IMX_VER_2_3,
}, {
+ .name = "imx53-cspi",
+ .driver_data = SPI_IMX_VER_0_7,
+ }, {
+ .name = "imx53-ecspi",
+ .driver_data = SPI_IMX_VER_2_3,
+ }, {
/* sentinel */
}
};
@@ -802,30 +804,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
init_completion(&spi_imx->xfer_done);
- if (pdev->id_entry->driver_data == SPI_IMX_VER_AUTODETECT) {
- if (cpu_is_mx25() || cpu_is_mx35())
- spi_imx->devtype_data =
- spi_imx_devtype_data[SPI_IMX_VER_0_7];
- else if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
- spi_imx->devtype_data =
- spi_imx_devtype_data[SPI_IMX_VER_0_4];
- else if (cpu_is_mx27() || cpu_is_mx21())
- spi_imx->devtype_data =
- spi_imx_devtype_data[SPI_IMX_VER_0_0];
- else if (cpu_is_mx1())
- spi_imx->devtype_data =
- spi_imx_devtype_data[SPI_IMX_VER_IMX1];
- else
- BUG();
- } else
- spi_imx->devtype_data =
- spi_imx_devtype_data[pdev->id_entry->driver_data];
-
- if (!spi_imx->devtype_data.intctrl) {
- dev_err(&pdev->dev, "no support for this device compiled in\n");
- ret = -ENODEV;
- goto out_gpio_free;
- }
+ spi_imx->devtype_data =
+ spi_imx_devtype_data[pdev->id_entry->driver_data];
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -847,7 +827,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
}
spi_imx->irq = platform_get_irq(pdev, 0);
- if (spi_imx->irq <= 0) {
+ if (spi_imx->irq < 0) {
ret = -EINVAL;
goto out_iounmap;
}
diff --git a/drivers/spi/spi_nuc900.c b/drivers/spi/spi_nuc900.c
index dff63be0d0a8..d5be18b3078c 100644
--- a/drivers/spi/spi_nuc900.c
+++ b/drivers/spi/spi_nuc900.c
@@ -449,7 +449,7 @@ err_iomap:
release_mem_region(hw->res->start, resource_size(hw->res));
kfree(hw->ioarea);
err_pdata:
- spi_master_put(hw->master);;
+ spi_master_put(hw->master);
err_nomem:
return err;
diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c
index bb7df02a5472..891e5909038c 100644
--- a/drivers/spi/spi_tegra.c
+++ b/drivers/spi/spi_tegra.c
@@ -513,7 +513,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
}
tspi->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR_OR_NULL(tspi->clk)) {
+ if (IS_ERR(tspi->clk)) {
dev_err(&pdev->dev, "can not get clock\n");
ret = PTR_ERR(tspi->clk);
goto err2;
diff --git a/drivers/spi/spi_topcliff_pch.c b/drivers/spi/spi_topcliff_pch.c
index 58e187f45ec7..79e48d451137 100644
--- a/drivers/spi/spi_topcliff_pch.c
+++ b/drivers/spi/spi_topcliff_pch.c
@@ -267,7 +267,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
if (reg_spsr_val & SPSR_FI_BIT) {
/* disable FI & RFI interrupts */
pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
- SPCR_FIE_BIT | SPCR_TFIE_BIT);
+ SPCR_FIE_BIT | SPCR_RFIE_BIT);
/* transfer is completed;inform pch_spi_process_messages */
data->transfer_complete = true;
@@ -677,15 +677,15 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
{
/* enable interrupts */
if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) {
- /* set receive threhold to PCH_RX_THOLD */
+ /* set receive threshold to PCH_RX_THOLD */
pch_spi_setclr_reg(data->master, PCH_SPCR,
- PCH_RX_THOLD << SPCR_TFIC_FIELD,
- ~MASK_TFIC_SPCR_BITS);
+ PCH_RX_THOLD << SPCR_RFIC_FIELD,
+ ~MASK_RFIC_SPCR_BITS);
/* enable FI and RFI interrupts */
pch_spi_setclr_reg(data->master, PCH_SPCR,
- SPCR_RFIE_BIT | SPCR_TFIE_BIT, 0);
+ SPCR_RFIE_BIT | SPCR_FIE_BIT, 0);
} else {
- /* set receive threhold to maximum */
+ /* set receive threshold to maximum */
pch_spi_setclr_reg(data->master, PCH_SPCR,
PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD,
~MASK_TFIC_SPCR_BITS);
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 4e6245e67995..603428213d21 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -38,7 +38,7 @@
/*
- * This supports acccess to SPI devices using normal userspace I/O calls.
+ * This supports access to SPI devices using normal userspace I/O calls.
* Note that while traditional UNIX/POSIX I/O semantics are half duplex,
* and often mask message boundaries, full SPI support requires full duplex
* transfers. There are several kinds of internal message boundaries to
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 80f2db5bcfd6..7adaef62a991 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -1,26 +1,27 @@
/*
- * xilinx_spi.c
- *
* Xilinx SPI controller driver (master mode only)
*
* 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.
+ * Copyright (c) 2010 Secret Lab Technologies, Ltd.
+ * Copyright (c) 2009 Intel Corporation
+ * 2002-2007 (c) 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 version 2 as
+ * published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/io.h>
-
-#include "xilinx_spi.h"
#include <linux/spi/xilinx_spi.h>
+#include <linux/io.h>
#define XILINX_SPI_NAME "xilinx_spi"
@@ -350,19 +351,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static const struct of_device_id xilinx_spi_of_match[] = {
+ { .compatible = "xlnx,xps-spi-2.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.b", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+#endif
+
struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
- u32 irq, s16 bus_num)
+ u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
{
struct spi_master *master;
struct xilinx_spi *xspi;
- struct xspi_platform_data *pdata = dev->platform_data;
int ret;
- if (!pdata) {
- dev_err(dev, "No platform data attached\n");
- return NULL;
- }
-
master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
if (!master)
return NULL;
@@ -389,21 +393,21 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
}
master->bus_num = bus_num;
- master->num_chipselect = pdata->num_chipselect;
+ master->num_chipselect = num_cs;
#ifdef CONFIG_OF
master->dev.of_node = dev->of_node;
#endif
xspi->mem = *mem;
xspi->irq = irq;
- if (pdata->little_endian) {
+ if (little_endian) {
xspi->read_fn = xspi_read32;
xspi->write_fn = xspi_write32;
} else {
xspi->read_fn = xspi_read32_be;
xspi->write_fn = xspi_write32_be;
}
- xspi->bits_per_word = pdata->bits_per_word;
+ xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;
xspi->rx_fn = xspi_rx8;
@@ -462,6 +466,97 @@ void xilinx_spi_deinit(struct spi_master *master)
}
EXPORT_SYMBOL(xilinx_spi_deinit);
+static int __devinit xilinx_spi_probe(struct platform_device *dev)
+{
+ struct xspi_platform_data *pdata;
+ struct resource *r;
+ int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
+ struct spi_master *master;
+ u8 i;
+
+ pdata = dev->dev.platform_data;
+ if (pdata) {
+ num_cs = pdata->num_chipselect;
+ little_endian = pdata->little_endian;
+ bits_per_word = pdata->bits_per_word;
+ }
+
+#ifdef CONFIG_OF
+ if (dev->dev.of_node) {
+ const __be32 *prop;
+ int len;
+
+ /* number of slave select bits is required */
+ prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
+ &len);
+ if (prop && len >= sizeof(*prop))
+ num_cs = __be32_to_cpup(prop);
+ }
+#endif
+
+ if (!num_cs) {
+ dev_err(&dev->dev, "Missing slave select configuration data\n");
+ return -EINVAL;
+ }
+
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0)
+ return -ENXIO;
+
+ master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
+ little_endian, bits_per_word);
+ if (!master)
+ return -ENODEV;
+
+ if (pdata) {
+ for (i = 0; i < pdata->num_devices; i++)
+ spi_new_device(master, pdata->devices + i);
+ }
+
+ platform_set_drvdata(dev, master);
+ return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+ xilinx_spi_deinit(platform_get_drvdata(dev));
+ platform_set_drvdata(dev, 0);
+
+ return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+
+static struct platform_driver xilinx_spi_driver = {
+ .probe = xilinx_spi_probe,
+ .remove = __devexit_p(xilinx_spi_remove),
+ .driver = {
+ .name = XILINX_SPI_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = xilinx_spi_of_match,
+#endif
+ },
+};
+
+static int __init xilinx_spi_pltfm_init(void)
+{
+ return platform_driver_register(&xilinx_spi_driver);
+}
+module_init(xilinx_spi_pltfm_init);
+
+static void __exit xilinx_spi_pltfm_exit(void)
+{
+ platform_driver_unregister(&xilinx_spi_driver);
+}
+module_exit(xilinx_spi_pltfm_exit);
+
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION("Xilinx SPI driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
deleted file mode 100644
index d211accf68d2..000000000000
--- a/drivers/spi/xilinx_spi.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Xilinx SPI device driver API and platform data header file
- *
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _XILINX_SPI_H_
-#define _XILINX_SPI_H_
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-
-#define XILINX_SPI_NAME "xilinx_spi"
-
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
- u32 irq, s16 bus_num);
-
-void xilinx_spi_deinit(struct spi_master *master);
-#endif
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
deleted file mode 100644
index b66c2dbf20a5..000000000000
--- a/drivers/spi/xilinx_spi_of.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Xilinx SPI OF device driver
- *
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Xilinx SPI devices as OF devices
- *
- * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/of_spi.h>
-
-#include <linux/spi/xilinx_spi.h>
-#include "xilinx_spi.h"
-
-
-static int __devinit xilinx_spi_of_probe(struct platform_device *ofdev,
- const struct of_device_id *match)
-{
- struct spi_master *master;
- struct xspi_platform_data *pdata;
- struct resource r_mem;
- struct resource r_irq;
- int rc = 0;
- const u32 *prop;
- int len;
-
- rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
- if (rc) {
- dev_warn(&ofdev->dev, "invalid address\n");
- return rc;
- }
-
- rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
- if (rc == NO_IRQ) {
- dev_warn(&ofdev->dev, "no IRQ found\n");
- return -ENODEV;
- }
-
- ofdev->dev.platform_data =
- kzalloc(sizeof(struct xspi_platform_data), GFP_KERNEL);
- pdata = ofdev->dev.platform_data;
- if (!pdata)
- return -ENOMEM;
-
- /* number of slave select bits is required */
- prop = of_get_property(ofdev->dev.of_node, "xlnx,num-ss-bits", &len);
- if (!prop || len < sizeof(*prop)) {
- dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
- return -EINVAL;
- }
- pdata->num_chipselect = *prop;
- pdata->bits_per_word = 8;
- master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1);
- if (!master)
- return -ENODEV;
-
- dev_set_drvdata(&ofdev->dev, master);
-
- return 0;
-}
-
-static int __devexit xilinx_spi_remove(struct platform_device *ofdev)
-{
- xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
- dev_set_drvdata(&ofdev->dev, 0);
- kfree(ofdev->dev.platform_data);
- ofdev->dev.platform_data = NULL;
- return 0;
-}
-
-static int __exit xilinx_spi_of_remove(struct platform_device *op)
-{
- return xilinx_spi_remove(op);
-}
-
-static const struct of_device_id xilinx_spi_of_match[] = {
- { .compatible = "xlnx,xps-spi-2.00.a", },
- { .compatible = "xlnx,xps-spi-2.00.b", },
- {}
-};
-
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
-static struct of_platform_driver xilinx_spi_of_driver = {
- .probe = xilinx_spi_of_probe,
- .remove = __exit_p(xilinx_spi_of_remove),
- .driver = {
- .name = "xilinx-xps-spi",
- .owner = THIS_MODULE,
- .of_match_table = xilinx_spi_of_match,
- },
-};
-
-static int __init xilinx_spi_of_init(void)
-{
- return of_register_platform_driver(&xilinx_spi_of_driver);
-}
-module_init(xilinx_spi_of_init);
-
-static void __exit xilinx_spi_of_exit(void)
-{
- of_unregister_platform_driver(&xilinx_spi_of_driver);
-}
-module_exit(xilinx_spi_of_exit);
-
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_DESCRIPTION("Xilinx SPI platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
deleted file mode 100644
index 24debac646a9..000000000000
--- a/drivers/spi/xilinx_spi_pltfm.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Support for Xilinx SPI platform devices
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Xilinx SPI devices as platform devices
- *
- * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-#include <linux/spi/xilinx_spi.h>
-
-#include "xilinx_spi.h"
-
-static int __devinit xilinx_spi_probe(struct platform_device *dev)
-{
- struct xspi_platform_data *pdata;
- struct resource *r;
- int irq;
- struct spi_master *master;
- u8 i;
-
- pdata = dev->dev.platform_data;
- if (!pdata)
- return -ENODEV;
-
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!r)
- return -ENODEV;
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0)
- return -ENXIO;
-
- master = xilinx_spi_init(&dev->dev, r, irq, dev->id);
- if (!master)
- return -ENODEV;
-
- for (i = 0; i < pdata->num_devices; i++)
- spi_new_device(master, pdata->devices + i);
-
- platform_set_drvdata(dev, master);
- return 0;
-}
-
-static int __devexit xilinx_spi_remove(struct platform_device *dev)
-{
- xilinx_spi_deinit(platform_get_drvdata(dev));
- platform_set_drvdata(dev, 0);
-
- return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" XILINX_SPI_NAME);
-
-static struct platform_driver xilinx_spi_driver = {
- .probe = xilinx_spi_probe,
- .remove = __devexit_p(xilinx_spi_remove),
- .driver = {
- .name = XILINX_SPI_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init xilinx_spi_pltfm_init(void)
-{
- return platform_driver_register(&xilinx_spi_driver);
-}
-module_init(xilinx_spi_pltfm_init);
-
-static void __exit xilinx_spi_pltfm_exit(void)
-{
- platform_driver_unregister(&xilinx_spi_driver);
-}
-module_exit(xilinx_spi_pltfm_exit);
-
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_DESCRIPTION("Xilinx SPI platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index ef9c6a04ad8f..744d3f6e4709 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -24,6 +24,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BCM_GVC, 0x4318) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index c68b3dc19e11..3918d2cc5856 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -383,6 +383,35 @@ static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
ssb_dev->id.revision);
}
+#define ssb_config_attr(attrib, field, format_string) \
+static ssize_t \
+attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
+}
+
+ssb_config_attr(core_num, core_index, "%u\n")
+ssb_config_attr(coreid, id.coreid, "0x%04x\n")
+ssb_config_attr(vendor, id.vendor, "0x%04x\n")
+ssb_config_attr(revision, id.revision, "%u\n")
+ssb_config_attr(irq, irq, "%u\n")
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n",
+ ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
+}
+
+static struct device_attribute ssb_device_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(core_num),
+ __ATTR_RO(coreid),
+ __ATTR_RO(vendor),
+ __ATTR_RO(revision),
+ __ATTR_RO(irq),
+ __ATTR_NULL,
+};
+
static struct bus_type ssb_bustype = {
.name = "ssb",
.match = ssb_bus_match,
@@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
.suspend = ssb_device_suspend,
.resume = ssb_device_resume,
.uevent = ssb_device_uevent,
+ .dev_attrs = ssb_device_attrs,
};
static void ssb_buses_lock(void)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 6e88d2b603b4..158449e55044 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
out->antenna_gain.ghz5.a3 = gain;
}
+/* Revs 4 5 and 8 have partially shared layout */
+static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
+{
+ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
+ SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
+ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
+ SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
+ SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
+ SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
+ SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
+ SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
+
+ SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
+ SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
+ SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
+ SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
+ SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
+ SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
+ SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
+ SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
+
+ SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
+ SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
+ SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
+ SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
+ SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
+ SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
+ SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
+ SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
+
+ SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
+ SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
+ SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
+ SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
+ SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
+ SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
+ SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
+ SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
+}
+
static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
{
int i;
@@ -471,6 +511,8 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
sizeof(out->antenna_gain.ghz5));
+ sprom_extract_r458(out, in);
+
/* TODO - get remaining rev 4 stuff needed */
}
@@ -561,6 +603,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
sizeof(out->antenna_gain.ghz5));
+ sprom_extract_r458(out, in);
+
/* TODO - get remaining rev 8 stuff needed */
}
@@ -573,37 +617,34 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
memset(out->et1mac, 0xFF, 6);
+
if ((bus->chip_id & 0xFF00) == 0x4400) {
/* Workaround: The BCM44XX chip has a stupid revision
* number stored in the SPROM.
* Always extract r1. */
out->revision = 1;
+ ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
+ }
+
+ switch (out->revision) {
+ case 1:
+ case 2:
+ case 3:
sprom_extract_r123(out, in);
- } else if (bus->chip_id == 0x4321) {
- /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
- out->revision = 4;
+ break;
+ case 4:
+ case 5:
sprom_extract_r45(out, in);
- } else {
- switch (out->revision) {
- case 1:
- case 2:
- case 3:
- sprom_extract_r123(out, in);
- break;
- case 4:
- case 5:
- sprom_extract_r45(out, in);
- break;
- case 8:
- sprom_extract_r8(out, in);
- break;
- default:
- ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
- " revision %d detected. Will extract"
- " v1\n", out->revision);
- out->revision = 1;
- sprom_extract_r123(out, in);
- }
+ break;
+ case 8:
+ sprom_extract_r8(out, in);
+ break;
+ default:
+ ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+ " revision %d detected. Will extract"
+ " v1\n", out->revision);
+ out->revision = 1;
+ sprom_extract_r123(out, in);
}
if (out->boardflags_lo == 0xFFFF)
@@ -618,7 +659,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
struct ssb_sprom *sprom)
{
const struct ssb_sprom *fallback;
- int err = -ENOMEM;
+ int err;
u16 *buf;
if (!ssb_is_sprom_available(bus)) {
@@ -645,7 +686,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
- goto out;
+ return -ENOMEM;
bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
@@ -655,7 +696,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);
if (!buf)
- goto out;
+ return -ENOMEM;
bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
@@ -677,7 +718,6 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
out_free:
kfree(buf);
-out:
return err;
}
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
index 6536a041d90d..f6c8c81a0025 100644
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_dev *dev,
struct ssb_bus *ssb;
int err = -ENOMEM;
const char *name;
+ u32 val;
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
@@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_dev *dev,
goto err_pci_disable;
pci_set_master(dev);
+ /* Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_read_config_dword(dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
+
err = ssb_bus_pcibus_register(ssb, dev);
if (err)
goto err_pci_release_regions;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index ee079ab9fb28..29884c00c4d5 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -405,10 +405,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
/* Ignore PCI cores on PCI-E cards.
* Ignore PCI-E cores on PCI cards. */
if (dev->id.coreid == SSB_DEV_PCI) {
- if (bus->host_pci->is_pcie)
+ if (pci_is_pcie(bus->host_pci))
continue;
} else {
- if (!bus->host_pci->is_pcie)
+ if (!pci_is_pcie(bus->host_pci))
continue;
}
}
@@ -420,6 +420,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
bus->pcicore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
break;
+ case SSB_DEV_ETHERNET:
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+ (bus->host_pci->device & 0xFF00) == 0x4300) {
+ /* This is a dangling ethernet core on a
+ * wireless device. Ignore it. */
+ continue;
+ }
+ }
+ break;
default:
break;
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 5eafdf435550..5c8fcfc42c3e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -51,9 +51,11 @@ source "drivers/staging/cx25821/Kconfig"
source "drivers/staging/tm6000/Kconfig"
-source "drivers/staging/cpia/Kconfig"
+source "drivers/staging/dabusb/Kconfig"
-source "drivers/staging/stradis/Kconfig"
+source "drivers/staging/se401/Kconfig"
+
+source "drivers/staging/usbvideo/Kconfig"
source "drivers/staging/usbip/Kconfig"
@@ -111,24 +113,24 @@ source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
-source "drivers/staging/udlfb/Kconfig"
-
source "drivers/staging/hv/Kconfig"
source "drivers/staging/vme/Kconfig"
source "drivers/staging/memrar/Kconfig"
+source "drivers/staging/sep/Kconfig"
+
source "drivers/staging/iio/Kconfig"
+source "drivers/staging/cs5535_gpio/Kconfig"
+
source "drivers/staging/zram/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
-source "drivers/staging/batman-adv/Kconfig"
-
source "drivers/staging/samsung-laptop/Kconfig"
source "drivers/staging/sm7xx/Kconfig"
@@ -141,8 +143,6 @@ source "drivers/staging/cxt1e1/Kconfig"
source "drivers/staging/ti-st/Kconfig"
-source "drivers/staging/adis16255/Kconfig"
-
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/msm/Kconfig"
@@ -175,5 +175,9 @@ source "drivers/staging/intel_sst/Kconfig"
source "drivers/staging/speakup/Kconfig"
+source "drivers/staging/cptm1217/Kconfig"
+
+source "drivers/staging/ste_rmi4/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a97a955c094b..d53886317826 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,8 +8,9 @@ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
-obj-$(CONFIG_VIDEO_CPIA) += cpia/
-obj-$(CONFIG_VIDEO_STRADIS) += stradis/
+obj-$(CONFIG_USB_DABUSB) += dabusb/
+obj-$(CONFIG_USB_VICAM) += usbvideo/
+obj-$(CONFIG_USB_SE401) += se401/
obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
@@ -38,22 +39,21 @@ obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
-obj-$(CONFIG_FB_UDL) += udlfb/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/
+obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/
obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
-obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/
obj-$(CONFIG_FB_SM7XX) += sm7xx/
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/
-obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/
@@ -68,3 +68,5 @@ obj-$(CONFIG_BCM_WIMAX) += bcm/
obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SND_INTEL_SST) += intel_sst/
obj-$(CONFIG_SPEAKUP) += speakup/
+obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig
deleted file mode 100644
index a883c1f4478b..000000000000
--- a/drivers/staging/adis16255/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config ADIS16255
- tristate "Analog Devices ADIS16250/16255"
- depends on SPI && SYSFS
- ---help---
- If you say yes here you get support for the Analog Devices
- ADIS16250/16255 Low Power Gyroscope. The driver exposes
- orientation and gyroscope value, as well as sample rate
- to the sysfs.
-
- This driver can also be built as a module. If so, the module
- will be called adis16255.
diff --git a/drivers/staging/adis16255/Makefile b/drivers/staging/adis16255/Makefile
deleted file mode 100644
index 8c3908106bfa..000000000000
--- a/drivers/staging/adis16255/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_ADIS16255) += adis16255.o
diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c
deleted file mode 100644
index 8d4d7cbab979..000000000000
--- a/drivers/staging/adis16255/adis16255.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Analog Devices ADIS16250/ADIS16255 Low Power Gyroscope
- *
- * Written by: Matthias Brugger <m_brugger@web.de>
- *
- * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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 driver just has a bare interface to the sysfs (sample rate in Hz,
- * orientation (x, y, z) and gyroscope data in °/sec.
- *
- * It should be added to iio subsystem when this has left staging.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-
-#include <linux/gpio.h>
-
-#include <linux/spi/spi.h>
-#include <linux/workqueue.h>
-
-#include "adis16255.h"
-
-#define ADIS_STATUS 0x3d
-#define ADIS_SMPL_PRD_MSB 0x37
-#define ADIS_SMPL_PRD_LSB 0x36
-#define ADIS_MSC_CTRL_MSB 0x35
-#define ADIS_MSC_CTRL_LSB 0x34
-#define ADIS_GPIO_CTRL 0x33
-#define ADIS_ALM_SMPL1 0x25
-#define ADIS_ALM_MAG1 0x21
-#define ADIS_GYRO_SCALE 0x17
-#define ADIS_GYRO_OUT 0x05
-#define ADIS_SUPPLY_OUT 0x03
-#define ADIS_ENDURANCE 0x01
-
-/*
- * data structure for every sensor
- *
- * @dev: Driver model representation of the device.
- * @spi: Pointer to the spi device which will manage i/o to spi bus.
- * @data: Last read data from device.
- * @irq_adis: GPIO Number of IRQ signal
- * @irq: irq line manage by kernel
- * @negative: indicates if sensor is upside down (negative == 1)
- * @direction: indicates axis (x, y, z) the sensor is meassuring
- */
-struct spi_adis16255_data {
- struct device dev;
- struct spi_device *spi;
- s16 data;
- int irq;
- u8 negative;
- char direction;
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis,
- u8 adr,
- u8 *rbuf)
-{
- struct spi_device *spi = spiadis->spi;
- struct spi_message msg;
- struct spi_transfer xfer1, xfer2;
- u8 *buf, *rx;
- int ret;
-
- buf = kzalloc(4, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- rx = kzalloc(4, GFP_KERNEL);
- if (rx == NULL) {
- ret = -ENOMEM;
- goto err_buf;
- }
-
- buf[0] = adr;
-
- spi_message_init(&msg);
- memset(&xfer1, 0, sizeof(xfer1));
- memset(&xfer2, 0, sizeof(xfer2));
-
- xfer1.tx_buf = buf;
- xfer1.rx_buf = buf + 2;
- xfer1.len = 2;
- xfer1.delay_usecs = 9;
-
- xfer2.tx_buf = rx + 2;
- xfer2.rx_buf = rx;
- xfer2.len = 2;
-
- spi_message_add_tail(&xfer1, &msg);
- spi_message_add_tail(&xfer2, &msg);
-
- ret = spi_sync(spi, &msg);
- if (ret == 0) {
- rbuf[0] = rx[0];
- rbuf[1] = rx[1];
- }
-
- kfree(rx);
-err_buf:
- kfree(buf);
-
- return ret;
-}
-
-static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis,
- u8 adr1,
- u8 adr2,
- u8 *wbuf)
-{
- struct spi_device *spi = spiadis->spi;
- struct spi_message msg;
- struct spi_transfer xfer1, xfer2;
- u8 *buf, *rx;
- int ret;
-
- buf = kmalloc(4, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- rx = kzalloc(4, GFP_KERNEL);
- if (rx == NULL) {
- ret = -ENOMEM;
- goto err_buf;
- }
-
- spi_message_init(&msg);
- memset(&xfer1, 0, sizeof(xfer1));
- memset(&xfer2, 0, sizeof(xfer2));
-
- buf[0] = adr1 | 0x80;
- buf[1] = *wbuf;
-
- buf[2] = adr2 | 0x80;
- buf[3] = *(wbuf + 1);
-
- xfer1.tx_buf = buf;
- xfer1.rx_buf = rx;
- xfer1.len = 2;
- xfer1.delay_usecs = 9;
-
- xfer2.tx_buf = buf+2;
- xfer2.rx_buf = rx+2;
- xfer2.len = 2;
-
- spi_message_add_tail(&xfer1, &msg);
- spi_message_add_tail(&xfer2, &msg);
-
- ret = spi_sync(spi, &msg);
- if (ret != 0)
- dev_warn(&spi->dev, "write data to %#x %#x failed\n",
- buf[0], buf[2]);
-
- kfree(rx);
-err_buf:
- kfree(buf);
- return ret;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static irqreturn_t adis_irq_thread(int irq, void *dev_id)
-{
- struct spi_adis16255_data *spiadis = dev_id;
- int status;
- u16 value = 0;
-
- status = spi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value);
- if (status != 0) {
- dev_warn(&spiadis->spi->dev, "SPI FAILED\n");
- goto exit;
- }
-
- /* perform on new data only... */
- if (value & 0x8000) {
- /* delete error and new data bit */
- value = value & 0x3fff;
- /* set negative value */
- if (value & 0x2000)
- value = value | 0xe000;
-
- if (likely(spiadis->negative))
- value = -value;
-
- spiadis->data = (s16) value;
- }
-
-exit:
- return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*/
-
-ssize_t adis16255_show_data(struct device *device,
- struct device_attribute *da,
- char *buf)
-{
- struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
- return snprintf(buf, PAGE_SIZE, "%d\n", spiadis->data);
-}
-DEVICE_ATTR(data, S_IRUGO , adis16255_show_data, NULL);
-
-ssize_t adis16255_show_direction(struct device *device,
- struct device_attribute *da,
- char *buf)
-{
- struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
- return snprintf(buf, PAGE_SIZE, "%c\n", spiadis->direction);
-}
-DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL);
-
-ssize_t adis16255_show_sample_rate(struct device *device,
- struct device_attribute *da,
- char *buf)
-{
- struct spi_adis16255_data *spiadis = dev_get_drvdata(device);
- int status = 0;
- u16 value = 0;
- int ts = 0;
-
- status = spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB,
- (u8 *)&value);
- if (status != 0)
- return -EINVAL;
-
- if (value & 0x80) {
- /* timebase = 60.54 ms */
- ts = 60540 * ((0x7f & value) + 1);
- } else {
- /* timebase = 1.953 ms */
- ts = 1953 * ((0x7f & value) + 1);
- }
-
- return snprintf(buf, PAGE_SIZE, "%d\n", (1000*1000)/ts);
-}
-DEVICE_ATTR(sample_rate, S_IRUGO , adis16255_show_sample_rate, NULL);
-
-static struct attribute *adis16255_attributes[] = {
- &dev_attr_data.attr,
- &dev_attr_direction.attr,
- &dev_attr_sample_rate.attr,
- NULL
-};
-
-static const struct attribute_group adis16255_attr_group = {
- .attrs = adis16255_attributes,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int spi_adis16255_shutdown(struct spi_adis16255_data *spiadis)
-{
- u16 value = 0;
- /* turn sensor off */
- spi_adis16255_write_data(spiadis,
- ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
- (u8 *)&value);
- spi_adis16255_write_data(spiadis,
- ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
- (u8 *)&value);
- return 0;
-}
-
-static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis)
-{
- int status = 0;
- u16 value = 0;
-
- status = spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE,
- (u8 *)&value);
- if (status != 0)
- goto err;
- if (value != 0x0800) {
- dev_warn(&spiadis->spi->dev, "Scale factor is none default "
- "value (%.4x)\n", value);
- }
-
- /* timebase = 1.953 ms, Ns = 0 -> 512 Hz sample rate */
- value = 0x0001;
- status = spi_adis16255_write_data(spiadis,
- ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB,
- (u8 *)&value);
- if (status != 0)
- goto err;
-
- /* start internal self-test */
- value = 0x0400;
- status = spi_adis16255_write_data(spiadis,
- ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
- (u8 *)&value);
- if (status != 0)
- goto err;
-
- /* wait 35 ms to finish self-test */
- msleep(35);
-
- value = 0x0000;
- status = spi_adis16255_read_data(spiadis, ADIS_STATUS,
- (u8 *)&value);
- if (status != 0)
- goto err;
-
- if (value & 0x23) {
- if (value & 0x20) {
- dev_warn(&spiadis->spi->dev, "self-test error\n");
- status = -ENODEV;
- goto err;
- } else if (value & 0x3) {
- dev_warn(&spiadis->spi->dev, "Sensor voltage "
- "out of range.\n");
- status = -ENODEV;
- goto err;
- }
- }
-
- /* set interrupt to active high on DIO0 when data ready */
- value = 0x0006;
- status = spi_adis16255_write_data(spiadis,
- ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB,
- (u8 *)&value);
- if (status != 0)
- goto err;
- return status;
-
-err:
- spi_adis16255_shutdown(spiadis);
- return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int __devinit spi_adis16255_probe(struct spi_device *spi)
-{
-
- struct adis16255_init_data *init_data = spi->dev.platform_data;
- struct spi_adis16255_data *spiadis;
- int status = 0;
-
- spiadis = kzalloc(sizeof(*spiadis), GFP_KERNEL);
- if (!spiadis)
- return -ENOMEM;
-
- spiadis->spi = spi;
- spiadis->direction = init_data->direction;
-
- if (init_data->negative)
- spiadis->negative = 1;
-
- status = gpio_request(init_data->irq, "adis16255");
- if (status != 0)
- goto err;
-
- status = gpio_direction_input(init_data->irq);
- if (status != 0)
- goto gpio_err;
-
- spiadis->irq = gpio_to_irq(init_data->irq);
-
- status = request_threaded_irq(spiadis->irq,
- NULL, adis_irq_thread,
- IRQF_DISABLED, "adis-driver", spiadis);
-
- if (status != 0) {
- dev_err(&spi->dev, "IRQ request failed\n");
- goto gpio_err;
- }
-
- dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", init_data->irq, spiadis->irq);
-
- dev_set_drvdata(&spi->dev, spiadis);
- status = sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group);
- if (status != 0)
- goto irq_err;
-
- status = spi_adis16255_bringup(spiadis);
- if (status != 0)
- goto sysfs_err;
-
- dev_info(&spi->dev, "spi_adis16255 driver added!\n");
-
- return status;
-
-sysfs_err:
- sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group);
-irq_err:
- free_irq(spiadis->irq, spiadis);
-gpio_err:
- gpio_free(init_data->irq);
-err:
- kfree(spiadis);
- return status;
-}
-
-static int __devexit spi_adis16255_remove(struct spi_device *spi)
-{
- struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev);
-
- spi_adis16255_shutdown(spiadis);
-
- free_irq(spiadis->irq, spiadis);
- gpio_free(irq_to_gpio(spiadis->irq));
-
- sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group);
-
- kfree(spiadis);
-
- dev_info(&spi->dev, "spi_adis16255 driver removed!\n");
- return 0;
-}
-
-static struct spi_driver spi_adis16255_drv = {
- .driver = {
- .name = "spi_adis16255",
- .owner = THIS_MODULE,
- },
- .probe = spi_adis16255_probe,
- .remove = __devexit_p(spi_adis16255_remove),
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init spi_adis16255_init(void)
-{
- return spi_register_driver(&spi_adis16255_drv);
-}
-module_init(spi_adis16255_init);
-
-static void __exit spi_adis16255_exit(void)
-{
- spi_unregister_driver(&spi_adis16255_drv);
-}
-module_exit(spi_adis16255_exit);
-
-MODULE_AUTHOR("Matthias Brugger");
-MODULE_DESCRIPTION("SPI device driver for ADIS16255 sensor");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/adis16255/adis16255.h b/drivers/staging/adis16255/adis16255.h
deleted file mode 100644
index 03e07001bab2..000000000000
--- a/drivers/staging/adis16255/adis16255.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef ADIS16255_H
-#define ADIS16255_H
-
-#include <linux/types.h>
-
-struct adis16255_init_data {
- char direction;
- u8 negative;
- int irq;
-};
-
-#endif
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 8c95d8c2a4f4..7bb7da7959a2 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -70,7 +70,7 @@ module_param(start_off, uint, 0644);
MODULE_PARM_DESC(start_off,
"Set to 1 to switch off OLED display after it is attached");
-enum oled_pack_mode{
+enum oled_pack_mode {
PACK_MODE_G1,
PACK_MODE_G50,
PACK_MODE_LAST
@@ -620,13 +620,13 @@ static ssize_t class_set_picture(struct device *device,
#define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file
-static DEVICE_ATTR(asus_oled_enabled, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(asus_oled_enabled, S_IWUSR | S_IRUGO,
get_enabled, set_enabled);
-static DEVICE_ATTR(asus_oled_picture, S_IWUGO , NULL, set_picture);
+static DEVICE_ATTR(asus_oled_picture, S_IWUSR , NULL, set_picture);
-static DEVICE_ATTR(enabled, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO,
class_get_enabled, class_set_enabled);
-static DEVICE_ATTR(picture, S_IWUGO, NULL, class_set_picture);
+static DEVICE_ATTR(picture, S_IWUSR, NULL, class_set_picture);
static int asus_oled_probe(struct usb_interface *interface,
const struct usb_device_id *id)
diff --git a/drivers/staging/ath6kl/Kconfig b/drivers/staging/ath6kl/Kconfig
index ae2cdf48b74c..8a5caa30b85f 100644
--- a/drivers/staging/ath6kl/Kconfig
+++ b/drivers/staging/ath6kl/Kconfig
@@ -102,7 +102,7 @@ config AR600x_BT_RESET_PIN
config ATH6KL_CFG80211
bool "CFG80211 support"
- depends on ATH6K_LEGACY
+ depends on ATH6K_LEGACY && CFG80211
help
Enables support for CFG80211 APIs. The default option is to use WEXT. Even with this option enabled, WEXT is not explicitly disabled and the onus of not exercising WEXT lies on the application(s) running in the user space.
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
index c307a5559362..e96662b84ed9 100644
--- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
+++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
@@ -876,7 +876,7 @@ HIFAckInterrupt(HIF_DEVICE *device)
void
HIFUnMaskInterrupt(HIF_DEVICE *device)
{
- int ret;;
+ int ret;
AR_DEBUG_ASSERT(device != NULL);
AR_DEBUG_ASSERT(device->func != NULL);
@@ -1188,7 +1188,7 @@ addHifDevice(struct sdio_func *func)
HIF_DEVICE *hifdevice;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: addHifDevice\n"));
AR_DEBUG_ASSERT(func != NULL);
- hifdevice = (HIF_DEVICE *)kzalloc(sizeof(HIF_DEVICE), GFP_KERNEL);
+ hifdevice = kzalloc(sizeof(HIF_DEVICE), GFP_KERNEL);
AR_DEBUG_ASSERT(hifdevice != NULL);
#if HIF_USE_DMA_BOUNCE_BUFFER
hifdevice->dma_buffer = kmalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
index 22c6c6659f5b..ee8b47746a15 100644
--- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
+++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
@@ -285,9 +285,9 @@ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_I
do {
/* check if host supports scatter requests and it meets our requirements */
- if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+ if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
- device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
+ device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
status = A_ENOTSUP;
break;
}
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
index c5a6d6c16735..126a36a2daa6 100644
--- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c
+++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
@@ -1126,7 +1126,7 @@ ar6000_transfer_bin_file(AR_SOFTC_T *ar, AR6K_BIN_FILE file, A_UINT32 address, A
if ((board_ext_address) && (fw_entry->size == (board_data_size + board_ext_data_size))) {
A_UINT32 param;
- status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (A_UCHAR *)(((A_UINT32)fw_entry->data) + board_data_size), board_ext_data_size);
+ status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (A_UCHAR *)(fw_entry->data + board_data_size), board_ext_data_size);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
@@ -3030,7 +3030,8 @@ ar6000_data_tx(struct sk_buff *skb, struct net_device *dev)
A_UINT8 csumDest=0;
A_UINT8 csum=skb->ip_summed;
if(csumOffload && (csum==CHECKSUM_PARTIAL)){
- csumStart=skb->csum_start-(skb->network_header-skb->head)+sizeof(ATH_LLC_SNAP_HDR);
+ csumStart = (skb->head + skb->csum_start - skb_network_header(skb) +
+ sizeof(ATH_LLC_SNAP_HDR));
csumDest=skb->csum_offset+csumStart;
}
#endif
@@ -4438,7 +4439,7 @@ skip_key:
for (i = assoc_req_ie_pos; i < assoc_req_ie_pos + assocReqLen - 4; i++) {
AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i]));
sprintf(pos, "%2.2x", assocInfo[i]);
- pos += 2;;
+ pos += 2;
}
AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c b/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
index c196098f0859..6b8eeea475cf 100644
--- a/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
+++ b/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
@@ -198,8 +198,8 @@ int ar6000_htc_raw_open(AR_SOFTC_T *ar)
for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
/* Initialize the data structures */
- init_MUTEX(&arRaw->raw_htc_read_sem[streamID]);
- init_MUTEX(&arRaw->raw_htc_write_sem[streamID]);
+ sema_init(&arRaw->raw_htc_read_sem[streamID], 1);
+ sema_init(&arRaw->raw_htc_write_sem[streamID], 1);
init_waitqueue_head(&arRaw->raw_htc_read_queue[streamID]);
init_waitqueue_head(&arRaw->raw_htc_write_queue[streamID]);
diff --git a/drivers/staging/ath6kl/os/linux/cfg80211.c b/drivers/staging/ath6kl/os/linux/cfg80211.c
index c94ad29eeb4d..7269d0a1d618 100644
--- a/drivers/staging/ath6kl/os/linux/cfg80211.c
+++ b/drivers/staging/ath6kl/os/linux/cfg80211.c
@@ -808,7 +808,7 @@ ar6k_cfg80211_scanComplete_event(AR_SOFTC_T *ar, A_STATUS status)
static int
ar6k_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
- A_UINT8 key_index, const A_UINT8 *mac_addr,
+ A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr,
struct key_params *params)
{
AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
@@ -901,7 +901,7 @@ ar6k_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
static int
ar6k_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
- A_UINT8 key_index, const A_UINT8 *mac_addr)
+ A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr)
{
AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
@@ -936,7 +936,8 @@ ar6k_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
static int
ar6k_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
- A_UINT8 key_index, const A_UINT8 *mac_addr, void *cookie,
+ A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr,
+ void *cookie,
void (*callback)(void *cookie, struct key_params*))
{
AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
+++ /dev/null
diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c
index 8f3e2b816129..a08bd7355035 100644
--- a/drivers/staging/autofs/dirhash.c
+++ b/drivers/staging/autofs/dirhash.c
@@ -30,7 +30,7 @@ void autofs_update_usage(struct autofs_dirhash *dh,
struct autofs_dir_ent *ent)
{
autofs_delete_usage(ent); /* Unlink from current position */
- autofs_init_usage(dh,ent); /* Relink at queue tail */
+ autofs_init_usage(dh, ent); /* Relink at queue tail */
}
struct autofs_dir_ent *autofs_expire(struct super_block *sb,
@@ -45,17 +45,18 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
struct path path;
int umount_ok;
- if ( list_empty(&dh->expiry_head) || sbi->catatonic )
+ if (list_empty(&dh->expiry_head) || sbi->catatonic)
return NULL; /* No entries */
/* We keep the list sorted by last_usage and want old stuff */
- ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp);
+ ent = list_entry(dh->expiry_head.next,
+ struct autofs_dir_ent, exp);
if (jiffies - ent->last_usage < timeout)
break;
/* Move to end of list in case expiry isn't desirable */
autofs_update_usage(dh, ent);
/* Check to see that entry is expirable */
- if ( ent->ino < AUTOFS_FIRST_DIR_INO )
+ if (ent->ino < AUTOFS_FIRST_DIR_INO)
return ent; /* Symlinks are always expirable */
/* Get the dentry for the autofs subdirectory */
@@ -63,14 +64,15 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
if (!path.dentry) {
/* Should only happen in catatonic mode */
- printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
+ printk(KERN_DEBUG "autofs: dentry == NULL but inode \
+ range is directory, entry %s\n", ent->name);
autofs_delete_usage(ent);
continue;
}
if (!path.dentry->d_inode) {
dput(path.dentry);
- printk("autofs: negative dentry on expiry queue: %s\n",
+ printk(KERN_DEBUG "autofs: negative dentry on expiry queue: %s\n",
ent->name);
autofs_delete_usage(ent);
continue;
@@ -80,46 +82,54 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
point to the mounted-on-top root. */
if (!S_ISDIR(path.dentry->d_inode->i_mode) ||
!d_mountpoint(path.dentry)) {
- DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
+ DPRINTK(("autofs: not expirable \
+ (not a mounted directory): %s\n", ent->name));
continue;
}
path.mnt = mnt;
path_get(&path);
- if (!follow_down(&path)) {
+ if (!follow_down_one(&path)) {
path_put(&path);
- DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
+ DPRINTK(("autofs: not expirable\
+ (not a mounted directory): %s\n", ent->name));
continue;
}
- while (d_mountpoint(path.dentry) && follow_down(&path))
- ;
+ follow_down(&path, false); // TODO: need to check error
umount_ok = may_umount(path.mnt);
path_put(&path);
if (umount_ok) {
- DPRINTK(("autofs: signaling expire on %s\n", ent->name));
+ DPRINTK(("autofs: signaling expire on %s\n",
+ ent->name));
return ent; /* Expirable! */
}
- DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name));
+
+ DPRINTK(("autofs: didn't expire due to may_umount: %s\n",
+ ent->name));
}
return NULL; /* No expirable entries */
}
-void autofs_initialize_hash(struct autofs_dirhash *dh) {
+void autofs_initialize_hash(struct autofs_dirhash *dh)
+{
memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
INIT_LIST_HEAD(&dh->expiry_head);
}
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh,
+ struct qstr *name)
{
struct autofs_dir_ent *dhn;
DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", name->hash));
- autofs_say(name->name,name->len);
+ autofs_say(name->name, name->len);
- for ( dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
- if ( name->hash == dhn->hash &&
+ for (dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE];
+ dhn;
+ dhn = dhn->next) {
+ if (name->hash == dhn->hash &&
name->len == dhn->len &&
- !memcmp(name->name, dhn->name, name->len) )
+ !memcmp(name->name, dhn->name, name->len))
break;
}
@@ -131,9 +141,9 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
struct autofs_dir_ent **dhnp;
DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash));
- autofs_say(ent->name,ent->len);
+ autofs_say(ent->name, ent->len);
- autofs_init_usage(dh,ent);
+ autofs_init_usage(dh, ent);
if (ent->dentry)
dget(ent->dentry);
@@ -141,19 +151,19 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
ent->next = *dhnp;
ent->back = dhnp;
*dhnp = ent;
- if ( ent->next )
+ if (ent->next)
ent->next->back = &(ent->next);
}
void autofs_hash_delete(struct autofs_dir_ent *ent)
{
*(ent->back) = ent->next;
- if ( ent->next )
+ if (ent->next)
ent->next->back = ent->back;
autofs_delete_usage(ent);
- if ( ent->dentry )
+ if (ent->dentry)
dput(ent->dentry);
kfree(ent->name);
kfree(ent);
@@ -176,37 +186,37 @@ struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh,
bucket = (*ptr >> 16) - 1;
ecount = *ptr & 0xffff;
- if ( bucket < 0 ) {
+ if (bucket < 0)
bucket = ecount = 0;
- }
DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount));
ent = last ? last->next : NULL;
- if ( ent ) {
+ if (ent) {
ecount++;
} else {
- while ( bucket < AUTOFS_HASH_SIZE ) {
+ while (bucket < AUTOFS_HASH_SIZE) {
ent = dh->h[bucket];
- for ( i = ecount ; ent && i ; i-- )
+ for (i = ecount ; ent && i ; i--)
ent = ent->next;
-
+
if (ent) {
ecount++; /* Point to *next* entry */
break;
}
-
+
bucket++; ecount = 0;
}
}
#ifdef DEBUG
- if ( !ent )
- printk("autofs_hash_enum: nothing found\n");
+ if (!ent)
+ printk(KERN_DEBUG "autofs_hash_enum: nothing found\n");
else {
- printk("autofs_hash_enum: found hash %08x, name", ent->hash);
- autofs_say(ent->name,ent->len);
+ printk(KERN_DEBUG "autofs_hash_enum: found hash %08x, name",
+ ent->hash);
+ autofs_say(ent->name, ent->len);
}
#endif
@@ -221,9 +231,9 @@ void autofs_hash_dputall(struct autofs_dirhash *dh)
int i;
struct autofs_dir_ent *ent;
- for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
- for ( ent = dh->h[i] ; ent ; ent = ent->next ) {
- if ( ent->dentry ) {
+ for (i = 0 ; i < AUTOFS_HASH_SIZE ; i++) {
+ for (ent = dh->h[i] ; ent ; ent = ent->next) {
+ if (ent->dentry) {
dput(ent->dentry);
ent->dentry = NULL;
}
@@ -238,10 +248,10 @@ void autofs_hash_nuke(struct autofs_sb_info *sbi)
int i;
struct autofs_dir_ent *ent, *nent;
- for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
- for ( ent = sbi->dirhash.h[i] ; ent ; ent = nent ) {
+ for (i = 0 ; i < AUTOFS_HASH_SIZE ; i++) {
+ for (ent = sbi->dirhash.h[i] ; ent ; ent = nent) {
nent = ent->next;
- if ( ent->dentry )
+ if (ent->dentry)
dput(ent->dentry);
kfree(ent->name);
kfree(ent);
diff --git a/drivers/staging/autofs/root.c b/drivers/staging/autofs/root.c
index 0fdec4befd84..bf0e9755da67 100644
--- a/drivers/staging/autofs/root.c
+++ b/drivers/staging/autofs/root.c
@@ -154,13 +154,16 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
-static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd)
+static int autofs_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct inode * dir;
struct autofs_sb_info *sbi;
struct autofs_dir_ent *ent;
int res;
+ if (nd->flags & LOOKUP_RCU)
+ return -ECHILD;
+
lock_kernel();
dir = dentry->d_parent->d_inode;
sbi = autofs_sbi(dir->i_sb);
@@ -237,7 +240,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
*
* We need to do this before we release the directory semaphore.
*/
- dentry->d_op = &autofs_dentry_operations;
+ d_set_d_op(dentry, &autofs_dentry_operations);
dentry->d_flags |= DCACHE_AUTOFS_PENDING;
d_add(dentry, NULL);
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig
deleted file mode 100644
index 8553f3517454..000000000000
--- a/drivers/staging/batman-adv/Kconfig
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# B.A.T.M.A.N meshing protocol
-#
-
-config BATMAN_ADV
- tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
- depends on NET
- default n
- ---help---
-
- B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
- a routing protocol for multi-hop ad-hoc mesh networks. The
- networks may be wired or wireless. See
- http://www.open-mesh.org/ for more information and user space
- tools.
-
-config BATMAN_ADV_DEBUG
- bool "B.A.T.M.A.N. debugging"
- depends on BATMAN_ADV != n
- ---help---
-
- This is an option for use by developers; most people should
- say N here. This enables compilation of support for
- outputting debugging information to the kernel log. The
- output is controlled via the module parameter debug.
-
diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile
deleted file mode 100644
index 78924283ea74..000000000000
--- a/drivers/staging/batman-adv/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
-#
-# Marek Lindner, Simon Wunderlich
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of version 2 of the GNU General Public
-# License as published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA
-#
-
-obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
-batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o unicast.o
diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README
deleted file mode 100644
index 7c878bb07f3a..000000000000
--- a/drivers/staging/batman-adv/README
+++ /dev/null
@@ -1,240 +0,0 @@
-[state: 04-09-2010]
-
-BATMAN-ADV
-----------
-
-Batman advanced is a new approach to wireless networking which
-does no longer operate on the IP basis. Unlike the batman daemon,
-which exchanges information using UDP packets and sets routing
-tables, batman-advanced operates on ISO/OSI Layer 2 only and uses
-and routes (or better: bridges) Ethernet Frames. It emulates a
-virtual network switch of all nodes participating. Therefore all
-nodes appear to be link local, thus all higher operating proto-
-cols won't be affected by any changes within the network. You can
-run almost any protocol above batman advanced, prominent examples
-are: IPv4, IPv6, DHCP, IPX.
-
-Batman advanced was implemented as a Linux kernel driver to re-
-duce the overhead to a minimum. It does not depend on any (other)
-network driver, and can be used on wifi as well as ethernet lan,
-vpn, etc ... (anything with ethernet-style layer 2).
-
-CONFIGURATION
--------------
-
-Load the batman-adv module into your kernel:
-
-# insmod batman-adv.ko
-
-The module is now waiting for activation. You must add some in-
-terfaces on which batman can operate. After loading the module
-batman advanced will scan your systems interfaces to search for
-compatible interfaces. Once found, it will create subfolders in
-the /sys directories of each supported interface, e.g.
-
-# ls /sys/class/net/eth0/batman_adv/
-# iface_status mesh_iface
-
-If an interface does not have the "batman_adv" subfolder it prob-
-ably is not supported. Not supported interfaces are: loopback,
-non-ethernet and batman's own interfaces.
-
-Note: After the module was loaded it will continuously watch for
-new interfaces to verify the compatibility. There is no need to
-reload the module if you plug your USB wifi adapter into your ma-
-chine after batman advanced was initially loaded.
-
-To activate a given interface simply write "bat0" into its
-"mesh_iface" file inside the batman_adv subfolder:
-
-# echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface
-
-Repeat this step for all interfaces you wish to add. Now batman
-starts using/broadcasting on this/these interface(s).
-
-By reading the "iface_status" file you can check its status:
-
-# cat /sys/class/net/eth0/batman_adv/iface_status
-# active
-
-To deactivate an interface you have to write "none" into its
-"mesh_iface" file:
-
-# echo none > /sys/class/net/eth0/batman_adv/mesh_iface
-
-
-All mesh wide settings can be found in batman's own interface
-folder:
-
-# ls /sys/class/net/bat0/mesh/
-# aggregated_ogms bonding orig_interval vis_mode
-
-
-There is a special folder for debugging informations:
-
-# ls /sys/kernel/debug/batman_adv/bat0/
-# originators socket transtable_global transtable_local
-# vis_data
-
-
-Some of the files contain all sort of status information regard-
-ing the mesh network. For example, you can view the table of
-originators (mesh participants) with:
-
-# cat /sys/kernel/debug/batman_adv/bat0/originators
-
-Other files allow to change batman's behaviour to better fit your
-requirements. For instance, you can check the current originator
-interval (value in milliseconds which determines how often batman
-sends its broadcast packets):
-
-# cat /sys/class/net/bat0/mesh/orig_interval
-# 1000
-
-and also change its value:
-
-# echo 3000 > /sys/class/net/bat0/mesh/orig_interval
-
-In very mobile scenarios, you might want to adjust the originator
-interval to a lower value. This will make the mesh more respon-
-sive to topology changes, but will also increase the overhead.
-
-
-USAGE
------
-
-To make use of your newly created mesh, batman advanced provides
-a new interface "bat0" which you should use from this point on.
-All interfaces added to batman advanced are not relevant any
-longer because batman handles them for you. Basically, one "hands
-over" the data by using the batman interface and batman will make
-sure it reaches its destination.
-
-The "bat0" interface can be used like any other regular inter-
-face. It needs an IP address which can be either statically con-
-figured or dynamically (by using DHCP or similar services):
-
-# NodeA: ifconfig bat0 192.168.0.1
-# NodeB: ifconfig bat0 192.168.0.2
-# NodeB: ping 192.168.0.1
-
-Note: In order to avoid problems remove all IP addresses previ-
-ously assigned to interfaces now used by batman advanced, e.g.
-
-# ifconfig eth0 0.0.0.0
-
-
-VISUALIZATION
--------------
-
-If you want topology visualization, at least one mesh node must
-be configured as VIS-server:
-
-# echo "server" > /sys/class/net/bat0/mesh/vis_mode
-
-Each node is either configured as "server" or as "client" (de-
-fault: "client"). Clients send their topology data to the server
-next to them, and server synchronize with other servers. If there
-is no server configured (default) within the mesh, no topology
-information will be transmitted. With these "synchronizing
-servers", there can be 1 or more vis servers sharing the same (or
-at least very similar) data.
-
-When configured as server, you can get a topology snapshot of
-your mesh:
-
-# cat /sys/kernel/debug/batman_adv/bat0/vis_data
-
-This raw output is intended to be easily parsable and convertable
-with other tools. Have a look at the batctl README if you want a
-vis output in dot or json format for instance and how those out-
-puts could then be visualised in an image.
-
-The raw format consists of comma separated values per entry where
-each entry is giving information about a certain source inter-
-face. Each entry can/has to have the following values:
--> "mac" - mac address of an originator's source interface
- (each line begins with it)
--> "TQ mac value" - src mac's link quality towards mac address
- of a neighbor originator's interface which
- is being used for routing
--> "HNA mac" - HNA announced by source mac
--> "PRIMARY" - this is a primary interface
--> "SEC mac" - secondary mac address of source
- (requires preceding PRIMARY)
-
-The TQ value has a range from 4 to 255 with 255 being the best.
-The HNA entries are showing which hosts are connected to the mesh
-via bat0 or being bridged into the mesh network. The PRIMARY/SEC
-values are only applied on primary interfaces
-
-
-LOGGING/DEBUGGING
------------------
-
-All error messages, warnings and information messages are sent to
-the kernel log. Depending on your operating system distribution
-this can be read in one of a number of ways. Try using the com-
-mands: dmesg, logread, or looking in the files /var/log/kern.log
-or /var/log/syslog. All batman-adv messages are prefixed with
-"batman-adv:" So to see just these messages try
-
-# dmesg | grep batman-adv
-
-When investigating problems with your mesh network it is some-
-times necessary to see more detail debug messages. This must be
-enabled when compiling the batman-adv module. When building bat-
-man-adv as part of kernel, use "make menuconfig" and enable the
-option "B.A.T.M.A.N. debugging".
-
-Those additional debug messages can be accessed using a special
-file in debugfs
-
-# cat /sys/kernel/debug/batman_adv/bat0/log
-
-The additional debug output is by default disabled. It can be en-
-abled during run time. Following log_levels are defined:
-
-0 - All debug output disabled
-1 - Enable messages related to routing / flooding / broadcasting
-2 - Enable route or hna added / changed / deleted
-3 - Enable all messages
-
-The debug output can be changed at runtime using the file
-/sys/class/net/bat0/mesh/log_level. e.g.
-
-# echo 2 > /sys/class/net/bat0/mesh/log_level
-
-will enable debug messages for when routes or HNAs change.
-
-
-BATCTL
-------
-
-As batman advanced operates on layer 2 all hosts participating in
-the virtual switch are completely transparent for all protocols
-above layer 2. Therefore the common diagnosis tools do not work
-as expected. To overcome these problems batctl was created. At
-the moment the batctl contains ping, traceroute, tcpdump and
-interfaces to the kernel module settings.
-
-For more information, please see the manpage (man batctl).
-
-batctl is available on http://www.open-mesh.org/
-
-
-CONTACT
--------
-
-Please send us comments, experiences, questions, anything :)
-
-IRC: #batman on irc.freenode.org
-Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org
- (optional subscription at
- https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n)
-
-You can also contact the Authors:
-
-Marek Lindner <lindner_marek@yahoo.de>
-Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
-
diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO
deleted file mode 100644
index 11c384f8b063..000000000000
--- a/drivers/staging/batman-adv/TODO
+++ /dev/null
@@ -1,14 +0,0 @@
- * remove own list functionality from hash
- * use hlist_head, hlist_node in hash
- * don't use callbacks for compare+choose in hash
- * think about more efficient ways instead of abstraction of hash
- * Request a new review
- * Process the comments from the review
- * Move into mainline proper
-
-Please send all patches to:
- Marek Lindner <lindner_marek@yahoo.de>
- Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
- Andrew Lunn <andrew@lunn.ch>
- b.a.t.m.a.n@lists.open-mesh.org
- Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c
deleted file mode 100644
index 08624d44e231..000000000000
--- a/drivers/staging/batman-adv/aggregation.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "aggregation.h"
-#include "send.h"
-#include "routing.h"
-
-/* calculate the size of the hna information for a given packet */
-static int hna_len(struct batman_packet *batman_packet)
-{
- return batman_packet->num_hna * ETH_ALEN;
-}
-
-/* return true if new_packet can be aggregated with forw_packet */
-static bool can_aggregate_with(struct batman_packet *new_batman_packet,
- int packet_len,
- unsigned long send_time,
- bool directlink,
- struct batman_if *if_incoming,
- struct forw_packet *forw_packet)
-{
- struct batman_packet *batman_packet =
- (struct batman_packet *)forw_packet->skb->data;
- int aggregated_bytes = forw_packet->packet_len + packet_len;
-
- /**
- * we can aggregate the current packet to this aggregated packet
- * if:
- *
- * - the send time is within our MAX_AGGREGATION_MS time
- * - the resulting packet wont be bigger than
- * MAX_AGGREGATION_BYTES
- */
-
- if (time_before(send_time, forw_packet->send_time) &&
- time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
- forw_packet->send_time) &&
- (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
-
- /**
- * check aggregation compatibility
- * -> direct link packets are broadcasted on
- * their interface only
- * -> aggregate packet if the current packet is
- * a "global" packet as well as the base
- * packet
- */
-
- /* packets without direct link flag and high TTL
- * are flooded through the net */
- if ((!directlink) &&
- (!(batman_packet->flags & DIRECTLINK)) &&
- (batman_packet->ttl != 1) &&
-
- /* own packets originating non-primary
- * interfaces leave only that interface */
- ((!forw_packet->own) ||
- (forw_packet->if_incoming->if_num == 0)))
- return true;
-
- /* if the incoming packet is sent via this one
- * interface only - we still can aggregate */
- if ((directlink) &&
- (new_batman_packet->ttl == 1) &&
- (forw_packet->if_incoming == if_incoming) &&
-
- /* packets from direct neighbors or
- * own secondary interface packets
- * (= secondary interface packets in general) */
- (batman_packet->flags & DIRECTLINK ||
- (forw_packet->own &&
- forw_packet->if_incoming->if_num != 0)))
- return true;
- }
-
- return false;
-}
-
-#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
-/* create a new aggregated packet and add this packet to it */
-static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
- unsigned long send_time, bool direct_link,
- struct batman_if *if_incoming,
- int own_packet)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct forw_packet *forw_packet_aggr;
- unsigned long flags;
- unsigned char *skb_buff;
-
- /* own packet should always be scheduled */
- if (!own_packet) {
- if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "batman packet queue full\n");
- return;
- }
- }
-
- forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
- if (!forw_packet_aggr) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- return;
- }
-
- if ((atomic_read(&bat_priv->aggregation_enabled)) &&
- (packet_len < MAX_AGGREGATION_BYTES))
- forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
- sizeof(struct ethhdr));
- else
- forw_packet_aggr->skb = dev_alloc_skb(packet_len +
- sizeof(struct ethhdr));
-
- if (!forw_packet_aggr->skb) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- kfree(forw_packet_aggr);
- return;
- }
- skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
-
- INIT_HLIST_NODE(&forw_packet_aggr->list);
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- forw_packet_aggr->packet_len = packet_len;
- memcpy(skb_buff, packet_buff, packet_len);
-
- forw_packet_aggr->own = own_packet;
- forw_packet_aggr->if_incoming = if_incoming;
- forw_packet_aggr->num_packets = 0;
- forw_packet_aggr->direct_link_flags = 0;
- forw_packet_aggr->send_time = send_time;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |= 1;
-
- /* add new packet to packet list */
- spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
- hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
-
- /* start timer for this packet */
- INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
- send_outstanding_bat_packet);
- queue_delayed_work(bat_event_workqueue,
- &forw_packet_aggr->delayed_work,
- send_time - jiffies);
-}
-
-/* aggregate a new packet into the existing aggregation */
-static void aggregate(struct forw_packet *forw_packet_aggr,
- unsigned char *packet_buff,
- int packet_len,
- bool direct_link)
-{
- unsigned char *skb_buff;
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- memcpy(skb_buff, packet_buff, packet_len);
- forw_packet_aggr->packet_len += packet_len;
- forw_packet_aggr->num_packets++;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |=
- (1 << forw_packet_aggr->num_packets);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct batman_if *if_incoming, char own_packet,
- unsigned long send_time)
-{
- /**
- * _aggr -> pointer to the packet we want to aggregate with
- * _pos -> pointer to the position in the queue
- */
- struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
- struct hlist_node *tmp_node;
- struct batman_packet *batman_packet =
- (struct batman_packet *)packet_buff;
- bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
- unsigned long flags;
-
- /* find position for the packet in the forward queue */
- spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
- /* own packets are not to be aggregated */
- if ((atomic_read(&bat_priv->aggregation_enabled)) && (!own_packet)) {
- hlist_for_each_entry(forw_packet_pos, tmp_node,
- &bat_priv->forw_bat_list, list) {
- if (can_aggregate_with(batman_packet,
- packet_len,
- send_time,
- direct_link,
- if_incoming,
- forw_packet_pos)) {
- forw_packet_aggr = forw_packet_pos;
- break;
- }
- }
- }
-
- /* nothing to aggregate with - either aggregation disabled or no
- * suitable aggregation packet found */
- if (forw_packet_aggr == NULL) {
- /* the following section can run without the lock */
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
-
- /**
- * if we could not aggregate this packet with one of the others
- * we hold it back for a while, so that it might be aggregated
- * later on
- */
- if ((!own_packet) &&
- (atomic_read(&bat_priv->aggregation_enabled)))
- send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
-
- new_aggregated_packet(packet_buff, packet_len,
- send_time, direct_link,
- if_incoming, own_packet);
- } else {
- aggregate(forw_packet_aggr,
- packet_buff, packet_len,
- direct_link);
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
- }
-}
-
-/* unpack the aggregated packets and process them one by one */
-void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
- int packet_len, struct batman_if *if_incoming)
-{
- struct batman_packet *batman_packet;
- int buff_pos = 0;
- unsigned char *hna_buff;
-
- batman_packet = (struct batman_packet *)packet_buff;
-
- do {
- /* network to host order for our 32bit seqno, and the
- orig_interval. */
- batman_packet->seqno = ntohl(batman_packet->seqno);
-
- hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
- receive_bat_packet(ethhdr, batman_packet,
- hna_buff, hna_len(batman_packet),
- if_incoming);
-
- buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
- batman_packet = (struct batman_packet *)
- (packet_buff + buff_pos);
- } while (aggregated_packet(buff_pos, packet_len,
- batman_packet->num_hna));
-}
diff --git a/drivers/staging/batman-adv/aggregation.h b/drivers/staging/batman-adv/aggregation.h
deleted file mode 100644
index 71a91b3da913..000000000000
--- a/drivers/staging/batman-adv/aggregation.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
-#define _NET_BATMAN_ADV_AGGREGATION_H_
-
-#include "main.h"
-
-/* is there another aggregated packet here? */
-static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
-{
- int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
-
- return (next_buff_pos <= packet_len) &&
- (next_buff_pos <= MAX_AGGREGATION_BYTES);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct batman_if *if_incoming, char own_packet,
- unsigned long send_time);
-void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
- int packet_len, struct batman_if *if_incoming);
-
-#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c
deleted file mode 100644
index 57f84a9f8234..000000000000
--- a/drivers/staging/batman-adv/bat_debugfs.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-
-#include <linux/debugfs.h>
-
-#include "bat_debugfs.h"
-#include "translation-table.h"
-#include "originator.h"
-#include "hard-interface.h"
-#include "vis.h"
-#include "icmp_socket.h"
-
-static struct dentry *bat_debugfs;
-
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-#define LOG_BUFF_MASK (log_buff_len-1)
-#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
-
-static int log_buff_len = LOG_BUF_LEN;
-
-static void emit_log_char(struct debug_log *debug_log, char c)
-{
- LOG_BUFF(debug_log->log_end) = c;
- debug_log->log_end++;
-
- if (debug_log->log_end - debug_log->log_start > log_buff_len)
- debug_log->log_start = debug_log->log_end - log_buff_len;
-}
-
-static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
-{
- int printed_len;
- va_list args;
- static char debug_log_buf[256];
- char *p;
- unsigned long flags;
-
- if (!debug_log)
- return 0;
-
- spin_lock_irqsave(&debug_log->lock, flags);
- va_start(args, fmt);
- printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
- fmt, args);
- va_end(args);
-
- for (p = debug_log_buf; *p != 0; p++)
- emit_log_char(debug_log, *p);
-
- spin_unlock_irqrestore(&debug_log->lock, flags);
-
- wake_up(&debug_log->queue_wait);
-
- return 0;
-}
-
-int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
-{
- va_list args;
- char tmp_log_buf[256];
-
- va_start(args, fmt);
- vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- fdebug_log(bat_priv->debug_log, "[%10u] %s",
- (jiffies / HZ), tmp_log_buf);
- va_end(args);
-
- return 0;
-}
-
-static int log_open(struct inode *inode, struct file *file)
-{
- nonseekable_open(inode, file);
- file->private_data = inode->i_private;
- inc_module_count();
- return 0;
-}
-
-static int log_release(struct inode *inode, struct file *file)
-{
- dec_module_count();
- return 0;
-}
-
-static ssize_t log_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct bat_priv *bat_priv = file->private_data;
- struct debug_log *debug_log = bat_priv->debug_log;
- int error, i = 0;
- char c;
- unsigned long flags;
-
- if ((file->f_flags & O_NONBLOCK) &&
- !(debug_log->log_end - debug_log->log_start))
- return -EAGAIN;
-
- if ((!buf) || (count < 0))
- return -EINVAL;
-
- if (count == 0)
- return 0;
-
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
-
- error = wait_event_interruptible(debug_log->queue_wait,
- (debug_log->log_start - debug_log->log_end));
-
- if (error)
- return error;
-
- spin_lock_irqsave(&debug_log->lock, flags);
-
- while ((!error) && (i < count) &&
- (debug_log->log_start != debug_log->log_end)) {
- c = LOG_BUFF(debug_log->log_start);
-
- debug_log->log_start++;
-
- spin_unlock_irqrestore(&debug_log->lock, flags);
-
- error = __put_user(c, buf);
-
- spin_lock_irqsave(&debug_log->lock, flags);
-
- buf++;
- i++;
-
- }
-
- spin_unlock_irqrestore(&debug_log->lock, flags);
-
- if (!error)
- return i;
-
- return error;
-}
-
-static unsigned int log_poll(struct file *file, poll_table *wait)
-{
- struct bat_priv *bat_priv = file->private_data;
- struct debug_log *debug_log = bat_priv->debug_log;
-
- poll_wait(file, &debug_log->queue_wait, wait);
-
- if (debug_log->log_end - debug_log->log_start)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static const struct file_operations log_fops = {
- .open = log_open,
- .release = log_release,
- .read = log_read,
- .poll = log_poll,
- .llseek = no_llseek,
-};
-
-static int debug_log_setup(struct bat_priv *bat_priv)
-{
- struct dentry *d;
-
- if (!bat_priv->debug_dir)
- goto err;
-
- bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
- if (!bat_priv->debug_log)
- goto err;
-
- spin_lock_init(&bat_priv->debug_log->lock);
- init_waitqueue_head(&bat_priv->debug_log->queue_wait);
-
- d = debugfs_create_file("log", S_IFREG | S_IRUSR,
- bat_priv->debug_dir, bat_priv, &log_fops);
- if (d)
- goto err;
-
- return 0;
-
-err:
- return 1;
-}
-
-static void debug_log_cleanup(struct bat_priv *bat_priv)
-{
- kfree(bat_priv->debug_log);
- bat_priv->debug_log = NULL;
-}
-#else /* CONFIG_BATMAN_ADV_DEBUG */
-static int debug_log_setup(struct bat_priv *bat_priv)
-{
- bat_priv->debug_log = NULL;
- return 0;
-}
-
-static void debug_log_cleanup(struct bat_priv *bat_priv)
-{
- return;
-}
-#endif
-
-static int originators_open(struct inode *inode, struct file *file)
-{
- struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, orig_seq_print_text, net_dev);
-}
-
-static int transtable_global_open(struct inode *inode, struct file *file)
-{
- struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, hna_global_seq_print_text, net_dev);
-}
-
-static int transtable_local_open(struct inode *inode, struct file *file)
-{
- struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, hna_local_seq_print_text, net_dev);
-}
-
-static int vis_data_open(struct inode *inode, struct file *file)
-{
- struct net_device *net_dev = (struct net_device *)inode->i_private;
- return single_open(file, vis_seq_print_text, net_dev);
-}
-
-struct bat_debuginfo {
- struct attribute attr;
- const struct file_operations fops;
-};
-
-#define BAT_DEBUGINFO(_name, _mode, _open) \
-struct bat_debuginfo bat_debuginfo_##_name = { \
- .attr = { .name = __stringify(_name), \
- .mode = _mode, }, \
- .fops = { .owner = THIS_MODULE, \
- .open = _open, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
- } \
-};
-
-static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
-static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
-static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
-static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
-
-static struct bat_debuginfo *mesh_debuginfos[] = {
- &bat_debuginfo_originators,
- &bat_debuginfo_transtable_global,
- &bat_debuginfo_transtable_local,
- &bat_debuginfo_vis_data,
- NULL,
-};
-
-void debugfs_init(void)
-{
- bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
- if (bat_debugfs == ERR_PTR(-ENODEV))
- bat_debugfs = NULL;
-}
-
-void debugfs_destroy(void)
-{
- if (bat_debugfs) {
- debugfs_remove_recursive(bat_debugfs);
- bat_debugfs = NULL;
- }
-}
-
-int debugfs_add_meshif(struct net_device *dev)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
- struct bat_debuginfo **bat_debug;
- struct dentry *file;
-
- if (!bat_debugfs)
- goto out;
-
- bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
- if (!bat_priv->debug_dir)
- goto out;
-
- bat_socket_setup(bat_priv);
- debug_log_setup(bat_priv);
-
- for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
- file = debugfs_create_file(((*bat_debug)->attr).name,
- S_IFREG | ((*bat_debug)->attr).mode,
- bat_priv->debug_dir,
- dev, &(*bat_debug)->fops);
- if (!file) {
- bat_err(dev, "Can't add debugfs file: %s/%s\n",
- dev->name, ((*bat_debug)->attr).name);
- goto rem_attr;
- }
- }
-
- return 0;
-rem_attr:
- debugfs_remove_recursive(bat_priv->debug_dir);
- bat_priv->debug_dir = NULL;
-out:
-#ifdef CONFIG_DEBUG_FS
- return -ENOMEM;
-#else
- return 0;
-#endif /* CONFIG_DEBUG_FS */
-}
-
-void debugfs_del_meshif(struct net_device *dev)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
-
- debug_log_cleanup(bat_priv);
-
- if (bat_debugfs) {
- debugfs_remove_recursive(bat_priv->debug_dir);
- bat_priv->debug_dir = NULL;
- }
-}
diff --git a/drivers/staging/batman-adv/bat_debugfs.h b/drivers/staging/batman-adv/bat_debugfs.h
deleted file mode 100644
index 72df532b7d5f..000000000000
--- a/drivers/staging/batman-adv/bat_debugfs.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-
-#ifndef _NET_BATMAN_ADV_DEBUGFS_H_
-#define _NET_BATMAN_ADV_DEBUGFS_H_
-
-#define DEBUGFS_BAT_SUBDIR "batman_adv"
-
-void debugfs_init(void);
-void debugfs_destroy(void);
-int debugfs_add_meshif(struct net_device *dev);
-void debugfs_del_meshif(struct net_device *dev);
-
-#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c
deleted file mode 100644
index bc17fb816300..000000000000
--- a/drivers/staging/batman-adv/bat_sysfs.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "bat_sysfs.h"
-#include "translation-table.h"
-#include "originator.h"
-#include "hard-interface.h"
-#include "vis.h"
-
-#define to_dev(obj) container_of(obj, struct device, kobj)
-
-#define BAT_ATTR(_name, _mode, _show, _store) \
-struct bat_attribute bat_attr_##_name = { \
- .attr = {.name = __stringify(_name), \
- .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-};
-
-static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- int aggr_status = atomic_read(&bat_priv->aggregation_enabled);
-
- return sprintf(buff, "%s\n",
- aggr_status == 0 ? "disabled" : "enabled");
-}
-
-static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- int aggr_tmp = -1;
-
- if (((count == 2) && (buff[0] == '1')) ||
- (strncmp(buff, "enable", 6) == 0))
- aggr_tmp = 1;
-
- if (((count == 2) && (buff[0] == '0')) ||
- (strncmp(buff, "disable", 7) == 0))
- aggr_tmp = 0;
-
- if (aggr_tmp < 0) {
- if (buff[count - 1] == '\n')
- buff[count - 1] = '\0';
-
- bat_info(net_dev,
- "Invalid parameter for 'aggregate OGM' setting"
- "received: %s\n", buff);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp)
- return count;
-
- bat_info(net_dev, "Changing aggregation from: %s to: %s\n",
- atomic_read(&bat_priv->aggregation_enabled) == 1 ?
- "enabled" : "disabled", aggr_tmp == 1 ? "enabled" :
- "disabled");
-
- atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp);
- return count;
-}
-
-static ssize_t show_bond(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- int bond_status = atomic_read(&bat_priv->bonding_enabled);
-
- return sprintf(buff, "%s\n",
- bond_status == 0 ? "disabled" : "enabled");
-}
-
-static ssize_t store_bond(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- int bonding_enabled_tmp = -1;
-
- if (((count == 2) && (buff[0] == '1')) ||
- (strncmp(buff, "enable", 6) == 0))
- bonding_enabled_tmp = 1;
-
- if (((count == 2) && (buff[0] == '0')) ||
- (strncmp(buff, "disable", 7) == 0))
- bonding_enabled_tmp = 0;
-
- if (bonding_enabled_tmp < 0) {
- if (buff[count - 1] == '\n')
- buff[count - 1] = '\0';
-
- bat_err(net_dev,
- "Invalid parameter for 'bonding' setting received: "
- "%s\n", buff);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp)
- return count;
-
- bat_info(net_dev, "Changing bonding from: %s to: %s\n",
- atomic_read(&bat_priv->bonding_enabled) == 1 ?
- "enabled" : "disabled",
- bonding_enabled_tmp == 1 ? "enabled" : "disabled");
-
- atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp);
- return count;
-}
-
-static ssize_t show_frag(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- int frag_status = atomic_read(&bat_priv->frag_enabled);
-
- return sprintf(buff, "%s\n",
- frag_status == 0 ? "disabled" : "enabled");
-}
-
-static ssize_t store_frag(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- int frag_enabled_tmp = -1;
-
- if (((count == 2) && (buff[0] == '1')) ||
- (strncmp(buff, "enable", 6) == 0))
- frag_enabled_tmp = 1;
-
- if (((count == 2) && (buff[0] == '0')) ||
- (strncmp(buff, "disable", 7) == 0))
- frag_enabled_tmp = 0;
-
- if (frag_enabled_tmp < 0) {
- if (buff[count - 1] == '\n')
- buff[count - 1] = '\0';
-
- bat_err(net_dev,
- "Invalid parameter for 'fragmentation' setting on mesh"
- "received: %s\n", buff);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->frag_enabled) == frag_enabled_tmp)
- return count;
-
- bat_info(net_dev, "Changing fragmentation from: %s to: %s\n",
- atomic_read(&bat_priv->frag_enabled) == 1 ?
- "enabled" : "disabled",
- frag_enabled_tmp == 1 ? "enabled" : "disabled");
-
- atomic_set(&bat_priv->frag_enabled, (unsigned)frag_enabled_tmp);
- update_min_mtu(net_dev);
- return count;
-}
-
-static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- int vis_mode = atomic_read(&bat_priv->vis_mode);
-
- return sprintf(buff, "%s\n",
- vis_mode == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server");
-}
-
-static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- unsigned long val;
- int ret, vis_mode_tmp = -1;
-
- ret = strict_strtoul(buff, 10, &val);
-
- if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
- (strncmp(buff, "client", 6) == 0) ||
- (strncmp(buff, "off", 3) == 0))
- vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
-
- if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
- (strncmp(buff, "server", 6) == 0))
- vis_mode_tmp = VIS_TYPE_SERVER_SYNC;
-
- if (vis_mode_tmp < 0) {
- if (buff[count - 1] == '\n')
- buff[count - 1] = '\0';
-
- bat_info(net_dev,
- "Invalid parameter for 'vis mode' setting received: "
- "%s\n", buff);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
- return count;
-
- bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
- atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server");
-
- atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
- return count;
-}
-
-static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
-
- return sprintf(buff, "%i\n",
- atomic_read(&bat_priv->orig_interval));
-}
-
-static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- unsigned long orig_interval_tmp;
- int ret;
-
- ret = strict_strtoul(buff, 10, &orig_interval_tmp);
- if (ret) {
- bat_info(net_dev, "Invalid parameter for 'orig_interval' "
- "setting received: %s\n", buff);
- return -EINVAL;
- }
-
- if (orig_interval_tmp < JITTER * 2) {
- bat_info(net_dev, "New originator interval too small: %li "
- "(min: %i)\n", orig_interval_tmp, JITTER * 2);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp)
- return count;
-
- bat_info(net_dev, "Changing originator interval from: %i to: %li\n",
- atomic_read(&bat_priv->orig_interval),
- orig_interval_tmp);
-
- atomic_set(&bat_priv->orig_interval, orig_interval_tmp);
- return count;
-}
-
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-static ssize_t show_log_level(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- int log_level = atomic_read(&bat_priv->log_level);
-
- return sprintf(buff, "%d\n", log_level);
-}
-
-static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- unsigned long log_level_tmp;
- int ret;
-
- ret = strict_strtoul(buff, 10, &log_level_tmp);
- if (ret) {
- bat_info(net_dev, "Invalid parameter for 'log_level' "
- "setting received: %s\n", buff);
- return -EINVAL;
- }
-
- if (log_level_tmp > 3) {
- bat_info(net_dev, "New log level too big: %li "
- "(max: %i)\n", log_level_tmp, 3);
- return -EINVAL;
- }
-
- if (atomic_read(&bat_priv->log_level) == log_level_tmp)
- return count;
-
- bat_info(net_dev, "Changing log level from: %i to: %li\n",
- atomic_read(&bat_priv->log_level),
- log_level_tmp);
-
- atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp);
- return count;
-}
-#endif
-
-static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR,
- show_aggr_ogms, store_aggr_ogms);
-static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond);
-static BAT_ATTR(fragmentation, S_IRUGO | S_IWUSR, show_frag, store_frag);
-static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
-static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
- show_orig_interval, store_orig_interval);
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-static BAT_ATTR(log_level, S_IRUGO | S_IWUSR, show_log_level, store_log_level);
-#endif
-
-static struct bat_attribute *mesh_attrs[] = {
- &bat_attr_aggregated_ogms,
- &bat_attr_bonding,
- &bat_attr_fragmentation,
- &bat_attr_vis_mode,
- &bat_attr_orig_interval,
-#ifdef CONFIG_BATMAN_ADV_DEBUG
- &bat_attr_log_level,
-#endif
- NULL,
-};
-
-int sysfs_add_meshif(struct net_device *dev)
-{
- struct kobject *batif_kobject = &dev->dev.kobj;
- struct bat_priv *bat_priv = netdev_priv(dev);
- struct bat_attribute **bat_attr;
- int err;
-
- bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
- batif_kobject);
- if (!bat_priv->mesh_obj) {
- bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
- SYSFS_IF_MESH_SUBDIR);
- goto out;
- }
-
- for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
- err = sysfs_create_file(bat_priv->mesh_obj,
- &((*bat_attr)->attr));
- if (err) {
- bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
- dev->name, SYSFS_IF_MESH_SUBDIR,
- ((*bat_attr)->attr).name);
- goto rem_attr;
- }
- }
-
- return 0;
-
-rem_attr:
- for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
- sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
-
- kobject_put(bat_priv->mesh_obj);
- bat_priv->mesh_obj = NULL;
-out:
- return -ENOMEM;
-}
-
-void sysfs_del_meshif(struct net_device *dev)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
- struct bat_attribute **bat_attr;
-
- for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
- sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
-
- kobject_put(bat_priv->mesh_obj);
- bat_priv->mesh_obj = NULL;
-}
-
-static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
- ssize_t length;
-
- if (!batman_if)
- return 0;
-
- length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ?
- "none" : batman_if->soft_iface->name);
-
- hardif_put(batman_if);
-
- return length;
-}
-
-static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
- char *buff, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
- int status_tmp = -1;
- int ret;
-
- if (!batman_if)
- return count;
-
- if (buff[count - 1] == '\n')
- buff[count - 1] = '\0';
-
- if (strlen(buff) >= IFNAMSIZ) {
- pr_err("Invalid parameter for 'mesh_iface' setting received: "
- "interface name too long '%s'\n", buff);
- hardif_put(batman_if);
- return -EINVAL;
- }
-
- if (strncmp(buff, "none", 4) == 0)
- status_tmp = IF_NOT_IN_USE;
- else
- status_tmp = IF_I_WANT_YOU;
-
- if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) &&
- (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) {
- hardif_put(batman_if);
- return count;
- }
-
- if (status_tmp == IF_NOT_IN_USE) {
- rtnl_lock();
- hardif_disable_interface(batman_if);
- rtnl_unlock();
- hardif_put(batman_if);
- return count;
- }
-
- /* if the interface already is in use */
- if (batman_if->if_status != IF_NOT_IN_USE) {
- rtnl_lock();
- hardif_disable_interface(batman_if);
- rtnl_unlock();
- }
-
- ret = hardif_enable_interface(batman_if, buff);
- hardif_put(batman_if);
-
- return ret;
-}
-
-static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
- char *buff)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
- struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
- ssize_t length;
-
- if (!batman_if)
- return 0;
-
- switch (batman_if->if_status) {
- case IF_TO_BE_REMOVED:
- length = sprintf(buff, "disabling\n");
- break;
- case IF_INACTIVE:
- length = sprintf(buff, "inactive\n");
- break;
- case IF_ACTIVE:
- length = sprintf(buff, "active\n");
- break;
- case IF_TO_BE_ACTIVATED:
- length = sprintf(buff, "enabling\n");
- break;
- case IF_NOT_IN_USE:
- default:
- length = sprintf(buff, "not in use\n");
- break;
- }
-
- hardif_put(batman_if);
-
- return length;
-}
-
-static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
- show_mesh_iface, store_mesh_iface);
-static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
-
-static struct bat_attribute *batman_attrs[] = {
- &bat_attr_mesh_iface,
- &bat_attr_iface_status,
- NULL,
-};
-
-int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
-{
- struct kobject *hardif_kobject = &dev->dev.kobj;
- struct bat_attribute **bat_attr;
- int err;
-
- *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
- hardif_kobject);
-
- if (!*hardif_obj) {
- bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
- SYSFS_IF_BAT_SUBDIR);
- goto out;
- }
-
- for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
- err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
- if (err) {
- bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
- dev->name, SYSFS_IF_BAT_SUBDIR,
- ((*bat_attr)->attr).name);
- goto rem_attr;
- }
- }
-
- return 0;
-
-rem_attr:
- for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
- sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
-out:
- return -ENOMEM;
-}
-
-void sysfs_del_hardif(struct kobject **hardif_obj)
-{
- kobject_put(*hardif_obj);
- *hardif_obj = NULL;
-}
diff --git a/drivers/staging/batman-adv/bat_sysfs.h b/drivers/staging/batman-adv/bat_sysfs.h
deleted file mode 100644
index 7f186c007b4f..000000000000
--- a/drivers/staging/batman-adv/bat_sysfs.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-
-#ifndef _NET_BATMAN_ADV_SYSFS_H_
-#define _NET_BATMAN_ADV_SYSFS_H_
-
-#define SYSFS_IF_MESH_SUBDIR "mesh"
-#define SYSFS_IF_BAT_SUBDIR "batman_adv"
-
-struct bat_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
- char *buf);
- ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
- char *buf, size_t count);
-};
-
-int sysfs_add_meshif(struct net_device *dev);
-void sysfs_del_meshif(struct net_device *dev);
-int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
-void sysfs_del_hardif(struct kobject **hardif_obj);
-
-#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c
deleted file mode 100644
index 814274fbaa2f..000000000000
--- a/drivers/staging/batman-adv/bitarray.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich, Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "bitarray.h"
-
-#include <linux/bitops.h>
-
-/* returns true if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno)
-{
- int32_t diff, word_offset, word_num;
-
- diff = last_seqno - curr_seqno;
- if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
- return 0;
- } else {
- /* which word */
- word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
- /* which position in the selected word */
- word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
-
- if (seq_bits[word_num] & 1 << word_offset)
- return 1;
- else
- return 0;
- }
-}
-
-/* turn corresponding bit on, so we can remember that we got the packet */
-void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n)
-{
- int32_t word_offset, word_num;
-
- /* if too old, just drop it */
- if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
- return;
-
- /* which word */
- word_num = n / WORD_BIT_SIZE;
- /* which position in the selected word */
- word_offset = n % WORD_BIT_SIZE;
-
- seq_bits[word_num] |= 1 << word_offset; /* turn the position on */
-}
-
-/* shift the packet array by n places. */
-static void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
-{
- int32_t word_offset, word_num;
- int32_t i;
-
- if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE)
- return;
-
- word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
- word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
-
- for (i = NUM_WORDS - 1; i > word_num; i--) {
- /* going from old to new, so we don't overwrite the data we copy
- * from.
- *
- * left is high, right is low: FEDC BA98 7654 3210
- * ^^ ^^
- * vvvv
- * ^^^^ = from, vvvvv =to, we'd have word_num==1 and
- * word_offset==WORD_BIT_SIZE/2 ????? in this example.
- * (=24 bits)
- *
- * our desired output would be: 9876 5432 1000 0000
- * */
-
- seq_bits[i] =
- (seq_bits[i - word_num] << word_offset) +
- /* take the lower port from the left half, shift it left
- * to its final position */
- (seq_bits[i - word_num - 1] >>
- (WORD_BIT_SIZE-word_offset));
- /* and the upper part of the right half and shift it left to
- * it's position */
- /* for our example that would be: word[0] = 9800 + 0076 =
- * 9876 */
- }
- /* now for our last word, i==word_num, we only have the it's "left"
- * half. that's the 1000 word in our example.*/
-
- seq_bits[i] = (seq_bits[i - word_num] << word_offset);
-
- /* pad the rest with 0, if there is anything */
- i--;
-
- for (; i >= 0; i--)
- seq_bits[i] = 0;
-}
-
-static void bit_reset_window(TYPE_OF_WORD *seq_bits)
-{
- int i;
- for (i = 0; i < NUM_WORDS; i++)
- seq_bits[i] = 0;
-}
-
-
-/* receive and process one packet within the sequence number window.
- *
- * returns:
- * 1 if the window was moved (either new or very old)
- * 0 if the window was not moved/shifted.
- */
-char bit_get_packet(void *priv, TYPE_OF_WORD *seq_bits,
- int32_t seq_num_diff, int8_t set_mark)
-{
- struct bat_priv *bat_priv = (struct bat_priv *)priv;
-
- /* sequence number is slightly older. We already got a sequence number
- * higher than this one, so we just mark it. */
-
- if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) {
- if (set_mark)
- bit_mark(seq_bits, -seq_num_diff);
- return 0;
- }
-
- /* sequence number is slightly newer, so we shift the window and
- * set the mark if required */
-
- if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) {
- bit_shift(seq_bits, seq_num_diff);
-
- if (set_mark)
- bit_mark(seq_bits, 0);
- return 1;
- }
-
- /* sequence number is much newer, probably missed a lot of packets */
-
- if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE)
- || (seq_num_diff < EXPECTED_SEQNO_RANGE)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "We missed a lot of packets (%i) !\n",
- seq_num_diff - 1);
- bit_reset_window(seq_bits);
- if (set_mark)
- bit_mark(seq_bits, 0);
- return 1;
- }
-
- /* received a much older packet. The other host either restarted
- * or the old packet got delayed somewhere in the network. The
- * packet should be dropped without calling this function if the
- * seqno window is protected. */
-
- if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
- || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Other host probably restarted!\n");
-
- bit_reset_window(seq_bits);
- if (set_mark)
- bit_mark(seq_bits, 0);
-
- return 1;
- }
-
- /* never reached */
- return 0;
-}
-
-/* count the hamming weight, how many good packets did we receive? just count
- * the 1's.
- */
-int bit_packet_count(TYPE_OF_WORD *seq_bits)
-{
- int i, hamming = 0;
-
- for (i = 0; i < NUM_WORDS; i++)
- hamming += hweight_long(seq_bits[i]);
-
- return hamming;
-}
diff --git a/drivers/staging/batman-adv/bitarray.h b/drivers/staging/batman-adv/bitarray.h
deleted file mode 100644
index 77b1e61847e8..000000000000
--- a/drivers/staging/batman-adv/bitarray.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich, Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_BITARRAY_H_
-#define _NET_BATMAN_ADV_BITARRAY_H_
-
-/* you should choose something big, if you don't want to waste cpu
- * and keep the type in sync with bit_packet_count */
-#define TYPE_OF_WORD unsigned long
-#define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8)
-
-/* returns true if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno);
-
-/* turn corresponding bit on, so we can remember that we got the packet */
-void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n);
-
-
-/* receive and process one packet, returns 1 if received seq_num is considered
- * new, 0 if old */
-char bit_get_packet(void *priv, TYPE_OF_WORD *seq_bits,
- int32_t seq_num_diff, int8_t set_mark);
-
-/* count the hamming weight, how many good packets did we receive? */
-int bit_packet_count(TYPE_OF_WORD *seq_bits);
-
-#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
deleted file mode 100644
index 80cfa8669585..000000000000
--- a/drivers/staging/batman-adv/hard-interface.c
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "hard-interface.h"
-#include "soft-interface.h"
-#include "send.h"
-#include "translation-table.h"
-#include "routing.h"
-#include "bat_sysfs.h"
-#include "originator.h"
-#include "hash.h"
-
-#include <linux/if_arp.h>
-
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-
-/* protect update critical side of if_list - but not the content */
-static DEFINE_SPINLOCK(if_list_lock);
-
-struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev)
-{
- struct batman_if *batman_if;
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->net_dev == net_dev)
- goto out;
- }
-
- batman_if = NULL;
-
-out:
- if (batman_if)
- hardif_hold(batman_if);
-
- rcu_read_unlock();
- return batman_if;
-}
-
-static int is_valid_iface(struct net_device *net_dev)
-{
- if (net_dev->flags & IFF_LOOPBACK)
- return 0;
-
- if (net_dev->type != ARPHRD_ETHER)
- return 0;
-
- if (net_dev->addr_len != ETH_ALEN)
- return 0;
-
- /* no batman over batman */
-#ifdef HAVE_NET_DEVICE_OPS
- if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
- return 0;
-#else
- if (net_dev->hard_start_xmit == interface_tx)
- return 0;
-#endif
-
- /* Device is being bridged */
- /* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
- return 0; */
-
- return 1;
-}
-
-static struct batman_if *get_active_batman_if(struct net_device *soft_iface)
-{
- struct batman_if *batman_if;
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->soft_iface != soft_iface)
- continue;
-
- if (batman_if->if_status == IF_ACTIVE)
- goto out;
- }
-
- batman_if = NULL;
-
-out:
- if (batman_if)
- hardif_hold(batman_if);
-
- rcu_read_unlock();
- return batman_if;
-}
-
-static void update_primary_addr(struct bat_priv *bat_priv)
-{
- struct vis_packet *vis_packet;
-
- vis_packet = (struct vis_packet *)
- bat_priv->my_vis_info->skb_packet->data;
- memcpy(vis_packet->vis_orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- memcpy(vis_packet->sender_orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
-}
-
-static void set_primary_if(struct bat_priv *bat_priv,
- struct batman_if *batman_if)
-{
- struct batman_packet *batman_packet;
- struct batman_if *old_if;
-
- if (batman_if)
- hardif_hold(batman_if);
-
- old_if = bat_priv->primary_if;
- bat_priv->primary_if = batman_if;
-
- if (old_if)
- hardif_put(old_if);
-
- if (!bat_priv->primary_if)
- return;
-
- batman_packet = (struct batman_packet *)(batman_if->packet_buff);
- batman_packet->flags = PRIMARIES_FIRST_HOP;
- batman_packet->ttl = TTL;
-
- update_primary_addr(bat_priv);
-
- /***
- * hacky trick to make sure that we send the HNA information via
- * our new primary interface
- */
- atomic_set(&bat_priv->hna_local_changed, 1);
-}
-
-static bool hardif_is_iface_up(struct batman_if *batman_if)
-{
- if (batman_if->net_dev->flags & IFF_UP)
- return true;
-
- return false;
-}
-
-static void update_mac_addresses(struct batman_if *batman_if)
-{
- memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
- batman_if->net_dev->dev_addr, ETH_ALEN);
- memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
- batman_if->net_dev->dev_addr, ETH_ALEN);
-}
-
-static void check_known_mac_addr(uint8_t *addr)
-{
- struct batman_if *batman_if;
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if ((batman_if->if_status != IF_ACTIVE) &&
- (batman_if->if_status != IF_TO_BE_ACTIVATED))
- continue;
-
- if (!compare_orig(batman_if->net_dev->dev_addr, addr))
- continue;
-
- pr_warning("The newly added mac address (%pM) already exists "
- "on: %s\n", addr, batman_if->net_dev->name);
- pr_warning("It is strongly recommended to keep mac addresses "
- "unique to avoid problems!\n");
- }
- rcu_read_unlock();
-}
-
-int hardif_min_mtu(struct net_device *soft_iface)
-{
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct batman_if *batman_if;
- /* allow big frames if all devices are capable to do so
- * (have MTU > 1500 + BAT_HEADER_LEN) */
- int min_mtu = ETH_DATA_LEN;
-
- if (atomic_read(&bat_priv->frag_enabled))
- goto out;
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if ((batman_if->if_status != IF_ACTIVE) &&
- (batman_if->if_status != IF_TO_BE_ACTIVATED))
- continue;
-
- if (batman_if->soft_iface != soft_iface)
- continue;
-
- min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN,
- min_mtu);
- }
- rcu_read_unlock();
-out:
- return min_mtu;
-}
-
-/* adjusts the MTU if a new interface with a smaller MTU appeared. */
-void update_min_mtu(struct net_device *soft_iface)
-{
- int min_mtu;
-
- min_mtu = hardif_min_mtu(soft_iface);
- if (soft_iface->mtu != min_mtu)
- soft_iface->mtu = min_mtu;
-}
-
-static void hardif_activate_interface(struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv;
-
- if (batman_if->if_status != IF_INACTIVE)
- return;
-
- bat_priv = netdev_priv(batman_if->soft_iface);
-
- update_mac_addresses(batman_if);
- batman_if->if_status = IF_TO_BE_ACTIVATED;
-
- /**
- * the first active interface becomes our primary interface or
- * the next active interface after the old primay interface was removed
- */
- if (!bat_priv->primary_if)
- set_primary_if(bat_priv, batman_if);
-
- bat_info(batman_if->soft_iface, "Interface activated: %s\n",
- batman_if->net_dev->name);
-
- update_min_mtu(batman_if->soft_iface);
- return;
-}
-
-static void hardif_deactivate_interface(struct batman_if *batman_if)
-{
- if ((batman_if->if_status != IF_ACTIVE) &&
- (batman_if->if_status != IF_TO_BE_ACTIVATED))
- return;
-
- batman_if->if_status = IF_INACTIVE;
-
- bat_info(batman_if->soft_iface, "Interface deactivated: %s\n",
- batman_if->net_dev->name);
-
- update_min_mtu(batman_if->soft_iface);
-}
-
-int hardif_enable_interface(struct batman_if *batman_if, char *iface_name)
-{
- struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
-
- if (batman_if->if_status != IF_NOT_IN_USE)
- goto out;
-
- batman_if->soft_iface = dev_get_by_name(&init_net, iface_name);
-
- if (!batman_if->soft_iface) {
- batman_if->soft_iface = softif_create(iface_name);
-
- if (!batman_if->soft_iface)
- goto err;
-
- /* dev_get_by_name() increases the reference counter for us */
- dev_hold(batman_if->soft_iface);
- }
-
- bat_priv = netdev_priv(batman_if->soft_iface);
- batman_if->packet_len = BAT_PACKET_LEN;
- batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC);
-
- if (!batman_if->packet_buff) {
- bat_err(batman_if->soft_iface, "Can't add interface packet "
- "(%s): out of memory\n", batman_if->net_dev->name);
- goto err;
- }
-
- batman_packet = (struct batman_packet *)(batman_if->packet_buff);
- batman_packet->packet_type = BAT_PACKET;
- batman_packet->version = COMPAT_VERSION;
- batman_packet->flags = 0;
- batman_packet->ttl = 2;
- batman_packet->tq = TQ_MAX_VALUE;
- batman_packet->num_hna = 0;
-
- batman_if->if_num = bat_priv->num_ifaces;
- bat_priv->num_ifaces++;
- batman_if->if_status = IF_INACTIVE;
- orig_hash_add_if(batman_if, bat_priv->num_ifaces);
-
- batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN);
- batman_if->batman_adv_ptype.func = batman_skb_recv;
- batman_if->batman_adv_ptype.dev = batman_if->net_dev;
- hardif_hold(batman_if);
- dev_add_pack(&batman_if->batman_adv_ptype);
-
- atomic_set(&batman_if->seqno, 1);
- atomic_set(&batman_if->frag_seqno, 1);
- bat_info(batman_if->soft_iface, "Adding interface: %s\n",
- batman_if->net_dev->name);
-
- if (atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu <
- ETH_DATA_LEN + BAT_HEADER_LEN)
- bat_info(batman_if->soft_iface,
- "The MTU of interface %s is too small (%i) to handle "
- "the transport of batman-adv packets. Packets going "
- "over this interface will be fragmented on layer2 "
- "which could impact the performance. Setting the MTU "
- "to %zi would solve the problem.\n",
- batman_if->net_dev->name, batman_if->net_dev->mtu,
- ETH_DATA_LEN + BAT_HEADER_LEN);
-
- if (!atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu <
- ETH_DATA_LEN + BAT_HEADER_LEN)
- bat_info(batman_if->soft_iface,
- "The MTU of interface %s is too small (%i) to handle "
- "the transport of batman-adv packets. If you experience"
- " problems getting traffic through try increasing the "
- "MTU to %zi.\n",
- batman_if->net_dev->name, batman_if->net_dev->mtu,
- ETH_DATA_LEN + BAT_HEADER_LEN);
-
- if (hardif_is_iface_up(batman_if))
- hardif_activate_interface(batman_if);
- else
- bat_err(batman_if->soft_iface, "Not using interface %s "
- "(retrying later): interface not active\n",
- batman_if->net_dev->name);
-
- /* begin scheduling originator messages on that interface */
- schedule_own_packet(batman_if);
-
-out:
- return 0;
-
-err:
- return -ENOMEM;
-}
-
-void hardif_disable_interface(struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
-
- if (batman_if->if_status == IF_ACTIVE)
- hardif_deactivate_interface(batman_if);
-
- if (batman_if->if_status != IF_INACTIVE)
- return;
-
- bat_info(batman_if->soft_iface, "Removing interface: %s\n",
- batman_if->net_dev->name);
- dev_remove_pack(&batman_if->batman_adv_ptype);
- hardif_put(batman_if);
-
- bat_priv->num_ifaces--;
- orig_hash_del_if(batman_if, bat_priv->num_ifaces);
-
- if (batman_if == bat_priv->primary_if) {
- struct batman_if *new_if;
-
- new_if = get_active_batman_if(batman_if->soft_iface);
- set_primary_if(bat_priv, new_if);
-
- if (new_if)
- hardif_put(new_if);
- }
-
- kfree(batman_if->packet_buff);
- batman_if->packet_buff = NULL;
- batman_if->if_status = IF_NOT_IN_USE;
-
- /* delete all references to this batman_if */
- purge_orig_ref(bat_priv);
- purge_outstanding_packets(bat_priv, batman_if);
- dev_put(batman_if->soft_iface);
-
- /* nobody uses this interface anymore */
- if (!bat_priv->num_ifaces)
- softif_destroy(batman_if->soft_iface);
-
- batman_if->soft_iface = NULL;
-}
-
-static struct batman_if *hardif_add_interface(struct net_device *net_dev)
-{
- struct batman_if *batman_if;
- int ret;
-
- ret = is_valid_iface(net_dev);
- if (ret != 1)
- goto out;
-
- dev_hold(net_dev);
-
- batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC);
- if (!batman_if) {
- pr_err("Can't add interface (%s): out of memory\n",
- net_dev->name);
- goto release_dev;
- }
-
- ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev);
- if (ret)
- goto free_if;
-
- batman_if->if_num = -1;
- batman_if->net_dev = net_dev;
- batman_if->soft_iface = NULL;
- batman_if->if_status = IF_NOT_IN_USE;
- INIT_LIST_HEAD(&batman_if->list);
- atomic_set(&batman_if->refcnt, 0);
- hardif_hold(batman_if);
-
- check_known_mac_addr(batman_if->net_dev->dev_addr);
-
- spin_lock(&if_list_lock);
- list_add_tail_rcu(&batman_if->list, &if_list);
- spin_unlock(&if_list_lock);
-
- /* extra reference for return */
- hardif_hold(batman_if);
- return batman_if;
-
-free_if:
- kfree(batman_if);
-release_dev:
- dev_put(net_dev);
-out:
- return NULL;
-}
-
-static void hardif_remove_interface(struct batman_if *batman_if)
-{
- /* first deactivate interface */
- if (batman_if->if_status != IF_NOT_IN_USE)
- hardif_disable_interface(batman_if);
-
- if (batman_if->if_status != IF_NOT_IN_USE)
- return;
-
- batman_if->if_status = IF_TO_BE_REMOVED;
-
- /* caller must take if_list_lock */
- list_del_rcu(&batman_if->list);
- synchronize_rcu();
- sysfs_del_hardif(&batman_if->hardif_obj);
- hardif_put(batman_if);
-}
-
-void hardif_remove_interfaces(void)
-{
- struct batman_if *batman_if, *batman_if_tmp;
-
- rtnl_lock();
- spin_lock(&if_list_lock);
- list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) {
- hardif_remove_interface(batman_if);
- }
- spin_unlock(&if_list_lock);
- rtnl_unlock();
-}
-
-static int hard_if_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct net_device *net_dev = (struct net_device *)ptr;
- struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
- struct bat_priv *bat_priv;
-
- if (!batman_if && event == NETDEV_REGISTER)
- batman_if = hardif_add_interface(net_dev);
-
- if (!batman_if)
- goto out;
-
- switch (event) {
- case NETDEV_UP:
- hardif_activate_interface(batman_if);
- break;
- case NETDEV_GOING_DOWN:
- case NETDEV_DOWN:
- hardif_deactivate_interface(batman_if);
- break;
- case NETDEV_UNREGISTER:
- spin_lock(&if_list_lock);
- hardif_remove_interface(batman_if);
- spin_unlock(&if_list_lock);
- break;
- case NETDEV_CHANGEMTU:
- if (batman_if->soft_iface)
- update_min_mtu(batman_if->soft_iface);
- break;
- case NETDEV_CHANGEADDR:
- if (batman_if->if_status == IF_NOT_IN_USE) {
- hardif_put(batman_if);
- goto out;
- }
-
- check_known_mac_addr(batman_if->net_dev->dev_addr);
- update_mac_addresses(batman_if);
-
- bat_priv = netdev_priv(batman_if->soft_iface);
- if (batman_if == bat_priv->primary_if)
- update_primary_addr(bat_priv);
- break;
- default:
- break;
- };
- hardif_put(batman_if);
-
-out:
- return NOTIFY_DONE;
-}
-
-/* receive a packet with the batman ethertype coming on a hard
- * interface */
-int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
-{
- struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
- struct batman_if *batman_if;
- int ret;
-
- batman_if = container_of(ptype, struct batman_if, batman_adv_ptype);
- skb = skb_share_check(skb, GFP_ATOMIC);
-
- /* skb was released by skb_share_check() */
- if (!skb)
- goto err_out;
-
- /* packet should hold at least type and version */
- if (unlikely(!pskb_may_pull(skb, 2)))
- goto err_free;
-
- /* expect a valid ethernet header here. */
- if (unlikely(skb->mac_len != sizeof(struct ethhdr)
- || !skb_mac_header(skb)))
- goto err_free;
-
- if (!batman_if->soft_iface)
- goto err_free;
-
- bat_priv = netdev_priv(batman_if->soft_iface);
-
- if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
- goto err_free;
-
- /* discard frames on not active interfaces */
- if (batman_if->if_status != IF_ACTIVE)
- goto err_free;
-
- batman_packet = (struct batman_packet *)skb->data;
-
- if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
- goto err_free;
- }
-
- /* all receive handlers return whether they received or reused
- * the supplied skb. if not, we have to free the skb. */
-
- switch (batman_packet->packet_type) {
- /* batman originator packet */
- case BAT_PACKET:
- ret = recv_bat_packet(skb, batman_if);
- break;
-
- /* batman icmp packet */
- case BAT_ICMP:
- ret = recv_icmp_packet(skb, batman_if);
- break;
-
- /* unicast packet */
- case BAT_UNICAST:
- ret = recv_unicast_packet(skb, batman_if);
- break;
-
- /* fragmented unicast packet */
- case BAT_UNICAST_FRAG:
- ret = recv_ucast_frag_packet(skb, batman_if);
- break;
-
- /* broadcast packet */
- case BAT_BCAST:
- ret = recv_bcast_packet(skb, batman_if);
- break;
-
- /* vis packet */
- case BAT_VIS:
- ret = recv_vis_packet(skb, batman_if);
- break;
- default:
- ret = NET_RX_DROP;
- }
-
- if (ret == NET_RX_DROP)
- kfree_skb(skb);
-
- /* return NET_RX_SUCCESS in any case as we
- * most probably dropped the packet for
- * routing-logical reasons. */
-
- return NET_RX_SUCCESS;
-
-err_free:
- kfree_skb(skb);
-err_out:
- return NET_RX_DROP;
-}
-
-struct notifier_block hard_if_notifier = {
- .notifier_call = hard_if_event,
-};
diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h
deleted file mode 100644
index d5508899065b..000000000000
--- a/drivers/staging/batman-adv/hard-interface.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
-#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
-
-#define IF_NOT_IN_USE 0
-#define IF_TO_BE_REMOVED 1
-#define IF_INACTIVE 2
-#define IF_ACTIVE 3
-#define IF_TO_BE_ACTIVATED 4
-#define IF_I_WANT_YOU 5
-
-extern struct notifier_block hard_if_notifier;
-
-struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev);
-int hardif_enable_interface(struct batman_if *batman_if, char *iface_name);
-void hardif_disable_interface(struct batman_if *batman_if);
-void hardif_remove_interfaces(void);
-int batman_skb_recv(struct sk_buff *skb,
- struct net_device *dev,
- struct packet_type *ptype,
- struct net_device *orig_dev);
-int hardif_min_mtu(struct net_device *soft_iface);
-void update_min_mtu(struct net_device *soft_iface);
-
-static inline void hardif_hold(struct batman_if *batman_if)
-{
- atomic_inc(&batman_if->refcnt);
-}
-
-static inline void hardif_put(struct batman_if *batman_if)
-{
- if (atomic_dec_and_test(&batman_if->refcnt)) {
- dev_put(batman_if->net_dev);
- kfree(batman_if);
- }
-}
-
-#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c
deleted file mode 100644
index 8ef26eb4949d..000000000000
--- a/drivers/staging/batman-adv/hash.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich, Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "hash.h"
-
-/* clears the hash */
-static void hash_init(struct hashtable_t *hash)
-{
- int i;
-
- hash->elements = 0;
-
- for (i = 0 ; i < hash->size; i++)
- hash->table[i] = NULL;
-}
-
-/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
- * called to remove the elements inside of the hash. if you don't remove the
- * elements, memory might be leaked. */
-void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg)
-{
- struct element_t *bucket, *last_bucket;
- int i;
-
- for (i = 0; i < hash->size; i++) {
- bucket = hash->table[i];
-
- while (bucket != NULL) {
- if (free_cb != NULL)
- free_cb(bucket->data, arg);
-
- last_bucket = bucket;
- bucket = bucket->next;
- kfree(last_bucket);
- }
- }
-
- hash_destroy(hash);
-}
-
-/* free only the hashtable and the hash itself. */
-void hash_destroy(struct hashtable_t *hash)
-{
- kfree(hash->table);
- kfree(hash);
-}
-
-/* iterate though the hash. First element is selected if an iterator
- * initialized with HASHIT() is supplied as iter. Use the returned
- * (or supplied) iterator to access the elements until hash_iterate returns
- * NULL. */
-
-struct hash_it_t *hash_iterate(struct hashtable_t *hash,
- struct hash_it_t *iter)
-{
- if (!hash)
- return NULL;
- if (!iter)
- return NULL;
-
- /* sanity checks first (if our bucket got deleted in the last
- * iteration): */
- if (iter->bucket != NULL) {
- if (iter->first_bucket != NULL) {
- /* we're on the first element and it got removed after
- * the last iteration. */
- if ((*iter->first_bucket) != iter->bucket) {
- /* there are still other elements in the list */
- if ((*iter->first_bucket) != NULL) {
- iter->prev_bucket = NULL;
- iter->bucket = (*iter->first_bucket);
- iter->first_bucket =
- &hash->table[iter->index];
- return iter;
- } else {
- iter->bucket = NULL;
- }
- }
- } else if (iter->prev_bucket != NULL) {
- /*
- * we're not on the first element, and the bucket got
- * removed after the last iteration. the last bucket's
- * next pointer is not pointing to our actual bucket
- * anymore. select the next.
- */
- if (iter->prev_bucket->next != iter->bucket)
- iter->bucket = iter->prev_bucket;
- }
- }
-
- /* now as we are sane, select the next one if there is some */
- if (iter->bucket != NULL) {
- if (iter->bucket->next != NULL) {
- iter->prev_bucket = iter->bucket;
- iter->bucket = iter->bucket->next;
- iter->first_bucket = NULL;
- return iter;
- }
- }
-
- /* if not returned yet, we've reached the last one on the index and have
- * to search forward */
- iter->index++;
- /* go through the entries of the hash table */
- while (iter->index < hash->size) {
- if ((hash->table[iter->index]) != NULL) {
- iter->prev_bucket = NULL;
- iter->bucket = hash->table[iter->index];
- iter->first_bucket = &hash->table[iter->index];
- return iter;
- } else {
- iter->index++;
- }
- }
-
- /* nothing to iterate over anymore */
- return NULL;
-}
-
-/* allocates and clears the hash */
-struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
- hashdata_choose_cb choose)
-{
- struct hashtable_t *hash;
-
- hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
-
- if (hash == NULL)
- return NULL;
-
- hash->size = size;
- hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
-
- if (hash->table == NULL) {
- kfree(hash);
- return NULL;
- }
-
- hash_init(hash);
-
- hash->compare = compare;
- hash->choose = choose;
-
- return hash;
-}
-
-/* adds data to the hashtable. returns 0 on success, -1 on error */
-int hash_add(struct hashtable_t *hash, void *data)
-{
- int index;
- struct element_t *bucket, *prev_bucket = NULL;
-
- if (!hash)
- return -1;
-
- index = hash->choose(data, hash->size);
- bucket = hash->table[index];
-
- while (bucket != NULL) {
- if (hash->compare(bucket->data, data))
- return -1;
-
- prev_bucket = bucket;
- bucket = bucket->next;
- }
-
- /* found the tail of the list, add new element */
- bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
-
- if (bucket == NULL)
- return -1;
-
- bucket->data = data;
- bucket->next = NULL;
-
- /* and link it */
- if (prev_bucket == NULL)
- hash->table[index] = bucket;
- else
- prev_bucket->next = bucket;
-
- hash->elements++;
- return 0;
-}
-
-/* finds data, based on the key in keydata. returns the found data on success,
- * or NULL on error */
-void *hash_find(struct hashtable_t *hash, void *keydata)
-{
- int index;
- struct element_t *bucket;
-
- if (!hash)
- return NULL;
-
- index = hash->choose(keydata , hash->size);
- bucket = hash->table[index];
-
- while (bucket != NULL) {
- if (hash->compare(bucket->data, keydata))
- return bucket->data;
-
- bucket = bucket->next;
- }
-
- return NULL;
-}
-
-/* remove bucket (this might be used in hash_iterate() if you already found the
- * bucket you want to delete and don't need the overhead to find it again with
- * hash_remove(). But usually, you don't want to use this function, as it
- * fiddles with hash-internals. */
-void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
-{
- void *data_save;
-
- data_save = hash_it_t->bucket->data;
-
- if (hash_it_t->prev_bucket != NULL)
- hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
- else if (hash_it_t->first_bucket != NULL)
- (*hash_it_t->first_bucket) = hash_it_t->bucket->next;
-
- kfree(hash_it_t->bucket);
- hash->elements--;
-
- return data_save;
-}
-
-/* removes data from hash, if found. returns pointer do data on success, so you
- * can remove the used structure yourself, or NULL on error . data could be the
- * structure you use with just the key filled, we just need the key for
- * comparing. */
-void *hash_remove(struct hashtable_t *hash, void *data)
-{
- struct hash_it_t hash_it_t;
-
- hash_it_t.index = hash->choose(data, hash->size);
- hash_it_t.bucket = hash->table[hash_it_t.index];
- hash_it_t.prev_bucket = NULL;
-
- while (hash_it_t.bucket != NULL) {
- if (hash->compare(hash_it_t.bucket->data, data)) {
- hash_it_t.first_bucket =
- (hash_it_t.bucket ==
- hash->table[hash_it_t.index] ?
- &hash->table[hash_it_t.index] : NULL);
- return hash_remove_bucket(hash, &hash_it_t);
- }
-
- hash_it_t.prev_bucket = hash_it_t.bucket;
- hash_it_t.bucket = hash_it_t.bucket->next;
- }
-
- return NULL;
-}
-
-/* resize the hash, returns the pointer to the new hash or NULL on
- * error. removes the old hash on success. */
-struct hashtable_t *hash_resize(struct hashtable_t *hash, int size)
-{
- struct hashtable_t *new_hash;
- struct element_t *bucket;
- int i;
-
- /* initialize a new hash with the new size */
- new_hash = hash_new(size, hash->compare, hash->choose);
-
- if (new_hash == NULL)
- return NULL;
-
- /* copy the elements */
- for (i = 0; i < hash->size; i++) {
- bucket = hash->table[i];
-
- while (bucket != NULL) {
- hash_add(new_hash, bucket->data);
- bucket = bucket->next;
- }
- }
-
- /* remove hash and eventual overflow buckets but not the content
- * itself. */
- hash_delete(hash, NULL, NULL);
-
- return new_hash;
-}
diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h
deleted file mode 100644
index 2c8e1762389f..000000000000
--- a/drivers/staging/batman-adv/hash.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich, Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_HASH_H_
-#define _NET_BATMAN_ADV_HASH_H_
-
-#define HASHIT(name) struct hash_it_t name = { \
- .index = -1, .bucket = NULL, \
- .prev_bucket = NULL, \
- .first_bucket = NULL }
-
-
-typedef int (*hashdata_compare_cb)(void *, void *);
-typedef int (*hashdata_choose_cb)(void *, int);
-typedef void (*hashdata_free_cb)(void *, void *);
-
-struct element_t {
- void *data; /* pointer to the data */
- struct element_t *next; /* overflow bucket pointer */
-};
-
-struct hash_it_t {
- int index;
- struct element_t *bucket;
- struct element_t *prev_bucket;
- struct element_t **first_bucket;
-};
-
-struct hashtable_t {
- struct element_t **table; /* the hashtable itself, with the buckets */
- int elements; /* number of elements registered */
- int size; /* size of hashtable */
- hashdata_compare_cb compare;/* callback to a compare function. should
- * compare 2 element datas for their keys,
- * return 0 if same and not 0 if not
- * same */
- hashdata_choose_cb choose; /* the hashfunction, should return an index
- * based on the key in the data of the first
- * argument and the size the second */
-};
-
-/* allocates and clears the hash */
-struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
- hashdata_choose_cb choose);
-
-/* remove bucket (this might be used in hash_iterate() if you already found the
- * bucket you want to delete and don't need the overhead to find it again with
- * hash_remove(). But usually, you don't want to use this function, as it
- * fiddles with hash-internals. */
-void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t);
-
-/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
- * called to remove the elements inside of the hash. if you don't remove the
- * elements, memory might be leaked. */
-void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg);
-
-/* free only the hashtable and the hash itself. */
-void hash_destroy(struct hashtable_t *hash);
-
-/* adds data to the hashtable. returns 0 on success, -1 on error */
-int hash_add(struct hashtable_t *hash, void *data);
-
-/* removes data from hash, if found. returns pointer do data on success, so you
- * can remove the used structure yourself, or NULL on error . data could be the
- * structure you use with just the key filled, we just need the key for
- * comparing. */
-void *hash_remove(struct hashtable_t *hash, void *data);
-
-/* finds data, based on the key in keydata. returns the found data on success,
- * or NULL on error */
-void *hash_find(struct hashtable_t *hash, void *keydata);
-
-/* resize the hash, returns the pointer to the new hash or NULL on
- * error. removes the old hash on success */
-struct hashtable_t *hash_resize(struct hashtable_t *hash, int size);
-
-/* iterate though the hash. first element is selected with iter_in NULL. use
- * the returned iterator to access the elements until hash_it_t returns NULL. */
-struct hash_it_t *hash_iterate(struct hashtable_t *hash,
- struct hash_it_t *iter_in);
-
-#endif /* _NET_BATMAN_ADV_HASH_H_ */
diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c
deleted file mode 100644
index 48856ca73b6a..000000000000
--- a/drivers/staging/batman-adv/icmp_socket.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include "icmp_socket.h"
-#include "send.h"
-#include "types.h"
-#include "hash.h"
-#include "hard-interface.h"
-
-
-static struct socket_client *socket_client_hash[256];
-
-static void bat_socket_add_packet(struct socket_client *socket_client,
- struct icmp_packet_rr *icmp_packet,
- size_t icmp_len);
-
-void bat_socket_init(void)
-{
- memset(socket_client_hash, 0, sizeof(socket_client_hash));
-}
-
-static int bat_socket_open(struct inode *inode, struct file *file)
-{
- unsigned int i;
- struct socket_client *socket_client;
-
- nonseekable_open(inode, file);
-
- socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
-
- if (!socket_client)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) {
- if (!socket_client_hash[i]) {
- socket_client_hash[i] = socket_client;
- break;
- }
- }
-
- if (i == ARRAY_SIZE(socket_client_hash)) {
- pr_err("Error - can't add another packet client: "
- "maximum number of clients reached\n");
- kfree(socket_client);
- return -EXFULL;
- }
-
- INIT_LIST_HEAD(&socket_client->queue_list);
- socket_client->queue_len = 0;
- socket_client->index = i;
- socket_client->bat_priv = inode->i_private;
- spin_lock_init(&socket_client->lock);
- init_waitqueue_head(&socket_client->queue_wait);
-
- file->private_data = socket_client;
-
- inc_module_count();
- return 0;
-}
-
-static int bat_socket_release(struct inode *inode, struct file *file)
-{
- struct socket_client *socket_client = file->private_data;
- struct socket_packet *socket_packet;
- struct list_head *list_pos, *list_pos_tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&socket_client->lock, flags);
-
- /* for all packets in the queue ... */
- list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
- socket_packet = list_entry(list_pos,
- struct socket_packet, list);
-
- list_del(list_pos);
- kfree(socket_packet);
- }
-
- socket_client_hash[socket_client->index] = NULL;
- spin_unlock_irqrestore(&socket_client->lock, flags);
-
- kfree(socket_client);
- dec_module_count();
-
- return 0;
-}
-
-static ssize_t bat_socket_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct socket_client *socket_client = file->private_data;
- struct socket_packet *socket_packet;
- size_t packet_len;
- int error;
- unsigned long flags;
-
- if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
- return -EAGAIN;
-
- if ((!buf) || (count < sizeof(struct icmp_packet)))
- return -EINVAL;
-
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
-
- error = wait_event_interruptible(socket_client->queue_wait,
- socket_client->queue_len);
-
- if (error)
- return error;
-
- spin_lock_irqsave(&socket_client->lock, flags);
-
- socket_packet = list_first_entry(&socket_client->queue_list,
- struct socket_packet, list);
- list_del(&socket_packet->list);
- socket_client->queue_len--;
-
- spin_unlock_irqrestore(&socket_client->lock, flags);
-
- error = __copy_to_user(buf, &socket_packet->icmp_packet,
- socket_packet->icmp_len);
-
- packet_len = socket_packet->icmp_len;
- kfree(socket_packet);
-
- if (error)
- return -EFAULT;
-
- return packet_len;
-}
-
-static ssize_t bat_socket_write(struct file *file, const char __user *buff,
- size_t len, loff_t *off)
-{
- struct socket_client *socket_client = file->private_data;
- struct bat_priv *bat_priv = socket_client->bat_priv;
- struct sk_buff *skb;
- struct icmp_packet_rr *icmp_packet;
-
- struct orig_node *orig_node;
- struct batman_if *batman_if;
- size_t packet_len = sizeof(struct icmp_packet);
- uint8_t dstaddr[ETH_ALEN];
- unsigned long flags;
-
- if (len < sizeof(struct icmp_packet)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Error - can't send packet from char device: "
- "invalid packet size\n");
- return -EINVAL;
- }
-
- if (!bat_priv->primary_if)
- return -EFAULT;
-
- if (len >= sizeof(struct icmp_packet_rr))
- packet_len = sizeof(struct icmp_packet_rr);
-
- skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr));
- if (!skb)
- return -ENOMEM;
-
- skb_reserve(skb, sizeof(struct ethhdr));
- icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
-
- if (!access_ok(VERIFY_READ, buff, packet_len)) {
- len = -EFAULT;
- goto free_skb;
- }
-
- if (__copy_from_user(icmp_packet, buff, packet_len)) {
- len = -EFAULT;
- goto free_skb;
- }
-
- if (icmp_packet->packet_type != BAT_ICMP) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Error - can't send packet from char device: "
- "got bogus packet type (expected: BAT_ICMP)\n");
- len = -EINVAL;
- goto free_skb;
- }
-
- if (icmp_packet->msg_type != ECHO_REQUEST) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Error - can't send packet from char device: "
- "got bogus message type (expected: ECHO_REQUEST)\n");
- len = -EINVAL;
- goto free_skb;
- }
-
- icmp_packet->uid = socket_client->index;
-
- if (icmp_packet->version != COMPAT_VERSION) {
- icmp_packet->msg_type = PARAMETER_PROBLEM;
- icmp_packet->ttl = COMPAT_VERSION;
- bat_socket_add_packet(socket_client, icmp_packet, packet_len);
- goto free_skb;
- }
-
- if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
- goto dst_unreach;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
- icmp_packet->dst));
-
- if (!orig_node)
- goto unlock;
-
- if (!orig_node->router)
- goto unlock;
-
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- if (!batman_if)
- goto dst_unreach;
-
- if (batman_if->if_status != IF_ACTIVE)
- goto dst_unreach;
-
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
-
- if (packet_len == sizeof(struct icmp_packet_rr))
- memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN);
-
-
- send_skb_packet(skb, batman_if, dstaddr);
-
- goto out;
-
-unlock:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-dst_unreach:
- icmp_packet->msg_type = DESTINATION_UNREACHABLE;
- bat_socket_add_packet(socket_client, icmp_packet, packet_len);
-free_skb:
- kfree_skb(skb);
-out:
- return len;
-}
-
-static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
-{
- struct socket_client *socket_client = file->private_data;
-
- poll_wait(file, &socket_client->queue_wait, wait);
-
- if (socket_client->queue_len > 0)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static const struct file_operations fops = {
- .owner = THIS_MODULE,
- .open = bat_socket_open,
- .release = bat_socket_release,
- .read = bat_socket_read,
- .write = bat_socket_write,
- .poll = bat_socket_poll,
- .llseek = no_llseek,
-};
-
-int bat_socket_setup(struct bat_priv *bat_priv)
-{
- struct dentry *d;
-
- if (!bat_priv->debug_dir)
- goto err;
-
- d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
- bat_priv->debug_dir, bat_priv, &fops);
- if (d)
- goto err;
-
- return 0;
-
-err:
- return 1;
-}
-
-static void bat_socket_add_packet(struct socket_client *socket_client,
- struct icmp_packet_rr *icmp_packet,
- size_t icmp_len)
-{
- struct socket_packet *socket_packet;
- unsigned long flags;
-
- socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
-
- if (!socket_packet)
- return;
-
- INIT_LIST_HEAD(&socket_packet->list);
- memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
- socket_packet->icmp_len = icmp_len;
-
- spin_lock_irqsave(&socket_client->lock, flags);
-
- /* while waiting for the lock the socket_client could have been
- * deleted */
- if (!socket_client_hash[icmp_packet->uid]) {
- spin_unlock_irqrestore(&socket_client->lock, flags);
- kfree(socket_packet);
- return;
- }
-
- list_add_tail(&socket_packet->list, &socket_client->queue_list);
- socket_client->queue_len++;
-
- if (socket_client->queue_len > 100) {
- socket_packet = list_first_entry(&socket_client->queue_list,
- struct socket_packet, list);
-
- list_del(&socket_packet->list);
- kfree(socket_packet);
- socket_client->queue_len--;
- }
-
- spin_unlock_irqrestore(&socket_client->lock, flags);
-
- wake_up(&socket_client->queue_wait);
-}
-
-void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
- size_t icmp_len)
-{
- struct socket_client *hash = socket_client_hash[icmp_packet->uid];
-
- if (hash)
- bat_socket_add_packet(hash, icmp_packet, icmp_len);
-}
diff --git a/drivers/staging/batman-adv/icmp_socket.h b/drivers/staging/batman-adv/icmp_socket.h
deleted file mode 100644
index bf9b348cde27..000000000000
--- a/drivers/staging/batman-adv/icmp_socket.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_
-#define _NET_BATMAN_ADV_ICMP_SOCKET_H_
-
-#include "types.h"
-
-#define ICMP_SOCKET "socket"
-
-void bat_socket_init(void);
-int bat_socket_setup(struct bat_priv *bat_priv);
-void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
- size_t icmp_len);
-
-#endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c
deleted file mode 100644
index 0587940d2723..000000000000
--- a/drivers/staging/batman-adv/main.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "bat_sysfs.h"
-#include "bat_debugfs.h"
-#include "routing.h"
-#include "send.h"
-#include "originator.h"
-#include "soft-interface.h"
-#include "icmp_socket.h"
-#include "translation-table.h"
-#include "hard-interface.h"
-#include "types.h"
-#include "vis.h"
-#include "hash.h"
-
-struct list_head if_list;
-
-unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-struct workqueue_struct *bat_event_workqueue;
-
-static int __init batman_init(void)
-{
- INIT_LIST_HEAD(&if_list);
-
- /* the name should not be longer than 10 chars - see
- * http://lwn.net/Articles/23634/ */
- bat_event_workqueue = create_singlethread_workqueue("bat_events");
-
- if (!bat_event_workqueue)
- return -ENOMEM;
-
- bat_socket_init();
- debugfs_init();
-
- register_netdevice_notifier(&hard_if_notifier);
-
- pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
- "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
- COMPAT_VERSION);
-
- return 0;
-}
-
-static void __exit batman_exit(void)
-{
- debugfs_destroy();
- unregister_netdevice_notifier(&hard_if_notifier);
- hardif_remove_interfaces();
-
- flush_workqueue(bat_event_workqueue);
- destroy_workqueue(bat_event_workqueue);
- bat_event_workqueue = NULL;
-
- rcu_barrier();
-}
-
-int mesh_init(struct net_device *soft_iface)
-{
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
-
- spin_lock_init(&bat_priv->orig_hash_lock);
- spin_lock_init(&bat_priv->forw_bat_list_lock);
- spin_lock_init(&bat_priv->forw_bcast_list_lock);
- spin_lock_init(&bat_priv->hna_lhash_lock);
- spin_lock_init(&bat_priv->hna_ghash_lock);
- spin_lock_init(&bat_priv->vis_hash_lock);
- spin_lock_init(&bat_priv->vis_list_lock);
-
- INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
- INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
-
- if (originator_init(bat_priv) < 1)
- goto err;
-
- if (hna_local_init(bat_priv) < 1)
- goto err;
-
- if (hna_global_init(bat_priv) < 1)
- goto err;
-
- hna_local_add(soft_iface, soft_iface->dev_addr);
-
- if (vis_init(bat_priv) < 1)
- goto err;
-
- atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
- goto end;
-
-err:
- pr_err("Unable to allocate memory for mesh information structures: "
- "out of mem ?\n");
- mesh_free(soft_iface);
- return -1;
-
-end:
- return 0;
-}
-
-void mesh_free(struct net_device *soft_iface)
-{
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
-
- atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING);
-
- purge_outstanding_packets(bat_priv, NULL);
-
- vis_quit(bat_priv);
-
- originator_free(bat_priv);
-
- hna_local_free(bat_priv);
- hna_global_free(bat_priv);
-
- atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
-}
-
-void inc_module_count(void)
-{
- try_module_get(THIS_MODULE);
-}
-
-void dec_module_count(void)
-{
- module_put(THIS_MODULE);
-}
-
-/* returns 1 if they are the same originator */
-
-int compare_orig(void *data1, void *data2)
-{
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
-}
-
-/* hashfunction to choose an entry in a hash table of given size */
-/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
-int choose_orig(void *data, int32_t size)
-{
- unsigned char *key = data;
- uint32_t hash = 0;
- size_t i;
-
- for (i = 0; i < 6; i++) {
- hash += key[i];
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
-
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
-
- return hash % size;
-}
-
-int is_my_mac(uint8_t *addr)
-{
- struct batman_if *batman_if;
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->if_status != IF_ACTIVE)
- continue;
-
- if (compare_orig(batman_if->net_dev->dev_addr, addr)) {
- rcu_read_unlock();
- return 1;
- }
- }
- rcu_read_unlock();
- return 0;
-
-}
-
-int is_bcast(uint8_t *addr)
-{
- return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
-}
-
-int is_mcast(uint8_t *addr)
-{
- return *addr & 0x01;
-}
-
-module_init(batman_init);
-module_exit(batman_exit);
-
-MODULE_LICENSE("GPL");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
-#ifdef REVISION_VERSION
-MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
-#else
-MODULE_VERSION(SOURCE_VERSION);
-#endif
diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h
deleted file mode 100644
index 5e3f51681f5e..000000000000
--- a/drivers/staging/batman-adv/main.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_MAIN_H_
-#define _NET_BATMAN_ADV_MAIN_H_
-
-/* Kernel Programming */
-#define LINUX
-
-#define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \
- "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
-#define DRIVER_DESC "B.A.T.M.A.N. advanced"
-#define DRIVER_DEVICE "batman-adv"
-
-#define SOURCE_VERSION "next"
-
-
-/* B.A.T.M.A.N. parameters */
-
-#define TQ_MAX_VALUE 255
-#define JITTER 20
-#define TTL 50 /* Time To Live of broadcast messages */
-
-#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no
- * valid packet comes in -> TODO: check
- * influence on TQ_LOCAL_WINDOW_SIZE */
-#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */
-
-#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
- * messages in squence numbers (should be a
- * multiple of our word size) */
-#define TQ_GLOBAL_WINDOW_SIZE 5
-#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
-#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
-#define TQ_TOTAL_BIDRECT_LIMIT 1
-
-#define TQ_HOP_PENALTY 10
-
-#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
-
-#define PACKBUFF_SIZE 2000
-#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
-
-#define VIS_INTERVAL 5000 /* 5 seconds */
-
-/* how much worse secondary interfaces may be to
- * to be considered as bonding candidates */
-
-#define BONDING_TQ_THRESHOLD 50
-
-#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
- * change the size of
- * forw_packet->direct_link_flags */
-#define MAX_AGGREGATION_MS 100
-
-#define RESET_PROTECTION_MS 30000
-#define EXPECTED_SEQNO_RANGE 65536
-/* don't reset again within 30 seconds */
-
-#define MESH_INACTIVE 0
-#define MESH_ACTIVE 1
-#define MESH_DEACTIVATING 2
-
-#define BCAST_QUEUE_LEN 256
-#define BATMAN_QUEUE_LEN 256
-
-/*
- * Debug Messages
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before
- * kernel messages */
-
-#define DBG_BATMAN 1 /* all messages related to routing / flooding /
- * broadcasting / etc */
-#define DBG_ROUTES 2 /* route or hna added / changed / deleted */
-#define DBG_ALL 3
-
-#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
-
-
-/*
- * Vis
- */
-
-/* #define VIS_SUBCLUSTERS_DISABLED */
-
-/*
- * Kernel headers
- */
-
-#include <linux/mutex.h> /* mutex */
-#include <linux/module.h> /* needed by all modules */
-#include <linux/netdevice.h> /* netdevice */
-#include <linux/if_ether.h> /* ethernet header */
-#include <linux/poll.h> /* poll_table */
-#include <linux/kthread.h> /* kernel threads */
-#include <linux/pkt_sched.h> /* schedule types */
-#include <linux/workqueue.h> /* workqueue */
-#include <linux/slab.h>
-#include <net/sock.h> /* struct sock */
-#include <linux/jiffies.h>
-#include <linux/seq_file.h>
-#include "types.h"
-
-#ifndef REVISION_VERSION
-#define REVISION_VERSION_STR ""
-#else
-#define REVISION_VERSION_STR " "REVISION_VERSION
-#endif
-
-extern struct list_head if_list;
-
-extern unsigned char broadcast_addr[];
-extern struct workqueue_struct *bat_event_workqueue;
-
-int mesh_init(struct net_device *soft_iface);
-void mesh_free(struct net_device *soft_iface);
-void inc_module_count(void);
-void dec_module_count(void);
-int compare_orig(void *data1, void *data2);
-int choose_orig(void *data, int32_t size);
-int is_my_mac(uint8_t *addr);
-int is_bcast(uint8_t *addr);
-int is_mcast(uint8_t *addr);
-
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
-
-#define bat_dbg(type, bat_priv, fmt, arg...) \
- do { \
- if (atomic_read(&bat_priv->log_level) & type) \
- debug_log(bat_priv, fmt, ## arg); \
- } \
- while (0)
-#else /* !CONFIG_BATMAN_ADV_DEBUG */
-static inline void bat_dbg(char type __attribute__((unused)),
- struct bat_priv *bat_priv __attribute__((unused)),
- char *fmt __attribute__((unused)), ...)
-{
-}
-#endif
-
-#define bat_warning(net_dev, fmt, arg...) \
- do { \
- struct net_device *_netdev = (net_dev); \
- struct bat_priv *_batpriv = netdev_priv(_netdev); \
- bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
- pr_warning("%s: " fmt, _netdev->name, ## arg); \
- } while (0)
-#define bat_info(net_dev, fmt, arg...) \
- do { \
- struct net_device *_netdev = (net_dev); \
- struct bat_priv *_batpriv = netdev_priv(_netdev); \
- bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
- pr_info("%s: " fmt, _netdev->name, ## arg); \
- } while (0)
-#define bat_err(net_dev, fmt, arg...) \
- do { \
- struct net_device *_netdev = (net_dev); \
- struct bat_priv *_batpriv = netdev_priv(_netdev); \
- bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
- pr_err("%s: " fmt, _netdev->name, ## arg); \
- } while (0)
-
-#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c
deleted file mode 100644
index 55270080a44b..000000000000
--- a/drivers/staging/batman-adv/originator.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-/* increase the reference counter for this originator */
-
-#include "main.h"
-#include "originator.h"
-#include "hash.h"
-#include "translation-table.h"
-#include "routing.h"
-#include "hard-interface.h"
-#include "unicast.h"
-
-static void purge_orig(struct work_struct *work);
-
-static void start_purge_timer(struct bat_priv *bat_priv)
-{
- INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
- queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
-}
-
-int originator_init(struct bat_priv *bat_priv)
-{
- unsigned long flags;
- if (bat_priv->orig_hash)
- return 1;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- bat_priv->orig_hash = hash_new(128, compare_orig, choose_orig);
-
- if (!bat_priv->orig_hash)
- goto err;
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- start_purge_timer(bat_priv);
- return 1;
-
-err:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return 0;
-}
-
-struct neigh_node *
-create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
- uint8_t *neigh, struct batman_if *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *neigh_node;
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Creating new last-hop neighbor of originator\n");
-
- neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
- if (!neigh_node)
- return NULL;
-
- INIT_LIST_HEAD(&neigh_node->list);
-
- memcpy(neigh_node->addr, neigh, ETH_ALEN);
- neigh_node->orig_node = orig_neigh_node;
- neigh_node->if_incoming = if_incoming;
-
- list_add_tail(&neigh_node->list, &orig_node->neigh_list);
- return neigh_node;
-}
-
-static void free_orig_node(void *data, void *arg)
-{
- struct list_head *list_pos, *list_pos_tmp;
- struct neigh_node *neigh_node;
- struct orig_node *orig_node = (struct orig_node *)data;
- struct bat_priv *bat_priv = (struct bat_priv *)arg;
-
- /* for all neighbors towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
-
- list_del(list_pos);
- kfree(neigh_node);
- }
-
- frag_list_free(&orig_node->frag_list);
- hna_global_del_orig(bat_priv, orig_node, "originator timed out");
-
- kfree(orig_node->bcast_own);
- kfree(orig_node->bcast_own_sum);
- kfree(orig_node);
-}
-
-void originator_free(struct bat_priv *bat_priv)
-{
- unsigned long flags;
-
- if (!bat_priv->orig_hash)
- return;
-
- cancel_delayed_work_sync(&bat_priv->orig_work);
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
- bat_priv->orig_hash = NULL;
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-}
-
-/* this function finds or creates an originator entry for the given
- * address if it does not exits */
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
-{
- struct orig_node *orig_node;
- struct hashtable_t *swaphash;
- int size;
-
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, addr));
-
- if (orig_node)
- return orig_node;
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Creating new originator: %pM\n", addr);
-
- orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
- if (!orig_node)
- return NULL;
-
- INIT_LIST_HEAD(&orig_node->neigh_list);
-
- memcpy(orig_node->orig, addr, ETH_ALEN);
- orig_node->router = NULL;
- orig_node->hna_buff = NULL;
- orig_node->bcast_seqno_reset = jiffies - 1
- - msecs_to_jiffies(RESET_PROTECTION_MS);
- orig_node->batman_seqno_reset = jiffies - 1
- - msecs_to_jiffies(RESET_PROTECTION_MS);
-
- size = bat_priv->num_ifaces * sizeof(TYPE_OF_WORD) * NUM_WORDS;
-
- orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
- if (!orig_node->bcast_own)
- goto free_orig_node;
-
- size = bat_priv->num_ifaces * sizeof(uint8_t);
- orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
-
- INIT_LIST_HEAD(&orig_node->frag_list);
- orig_node->last_frag_packet = 0;
-
- if (!orig_node->bcast_own_sum)
- goto free_bcast_own;
-
- if (hash_add(bat_priv->orig_hash, orig_node) < 0)
- goto free_bcast_own_sum;
-
- if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) {
- swaphash = hash_resize(bat_priv->orig_hash,
- bat_priv->orig_hash->size * 2);
-
- if (!swaphash)
- bat_dbg(DBG_BATMAN, bat_priv,
- "Couldn't resize orig hash table\n");
- else
- bat_priv->orig_hash = swaphash;
- }
-
- return orig_node;
-free_bcast_own_sum:
- kfree(orig_node->bcast_own_sum);
-free_bcast_own:
- kfree(orig_node->bcast_own);
-free_orig_node:
- kfree(orig_node);
- return NULL;
-}
-
-static bool purge_orig_neighbors(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct neigh_node **best_neigh_node)
-{
- struct list_head *list_pos, *list_pos_tmp;
- struct neigh_node *neigh_node;
- bool neigh_purged = false;
-
- *best_neigh_node = NULL;
-
- /* for all neighbors towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
-
- if ((time_after(jiffies,
- neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
- (neigh_node->if_incoming->if_status == IF_INACTIVE) ||
- (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
-
- if (neigh_node->if_incoming->if_status ==
- IF_TO_BE_REMOVED)
- bat_dbg(DBG_BATMAN, bat_priv,
- "neighbor purge: originator %pM, "
- "neighbor: %pM, iface: %s\n",
- orig_node->orig, neigh_node->addr,
- neigh_node->if_incoming->net_dev->name);
- else
- bat_dbg(DBG_BATMAN, bat_priv,
- "neighbor timeout: originator %pM, "
- "neighbor: %pM, last_valid: %lu\n",
- orig_node->orig, neigh_node->addr,
- (neigh_node->last_valid / HZ));
-
- neigh_purged = true;
- list_del(list_pos);
- kfree(neigh_node);
- } else {
- if ((*best_neigh_node == NULL) ||
- (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
- *best_neigh_node = neigh_node;
- }
- }
- return neigh_purged;
-}
-
-static bool purge_orig_node(struct bat_priv *bat_priv,
- struct orig_node *orig_node)
-{
- struct neigh_node *best_neigh_node;
-
- if (time_after(jiffies,
- orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) {
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Originator timeout: originator %pM, last_valid %lu\n",
- orig_node->orig, (orig_node->last_valid / HZ));
- return true;
- } else {
- if (purge_orig_neighbors(bat_priv, orig_node,
- &best_neigh_node)) {
- update_routes(bat_priv, orig_node,
- best_neigh_node,
- orig_node->hna_buff,
- orig_node->hna_buff_len);
- /* update bonding candidates, we could have lost
- * some candidates. */
- update_bonding_candidates(bat_priv, orig_node);
- }
- }
-
- return false;
-}
-
-static void _purge_orig(struct bat_priv *bat_priv)
-{
- HASHIT(hashit);
- struct orig_node *orig_node;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- /* for all origins... */
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
-
- if (purge_orig_node(bat_priv, orig_node)) {
- hash_remove_bucket(bat_priv->orig_hash, &hashit);
- free_orig_node(orig_node, bat_priv);
- }
-
- if (time_after(jiffies, (orig_node->last_frag_packet +
- msecs_to_jiffies(FRAG_TIMEOUT))))
- frag_list_free(&orig_node->frag_list);
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
-}
-
-static void purge_orig(struct work_struct *work)
-{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct bat_priv *bat_priv =
- container_of(delayed_work, struct bat_priv, orig_work);
-
- _purge_orig(bat_priv);
- start_purge_timer(bat_priv);
-}
-
-void purge_orig_ref(struct bat_priv *bat_priv)
-{
- _purge_orig(bat_priv);
-}
-
-int orig_seq_print_text(struct seq_file *seq, void *offset)
-{
- HASHIT(hashit);
- struct net_device *net_dev = (struct net_device *)seq->private;
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- struct orig_node *orig_node;
- struct neigh_node *neigh_node;
- int batman_count = 0;
- int last_seen_secs;
- int last_seen_msecs;
- unsigned long flags;
-
- if ((!bat_priv->primary_if) ||
- (bat_priv->primary_if->if_status != IF_ACTIVE)) {
- if (!bat_priv->primary_if)
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
-
- return seq_printf(seq, "BATMAN mesh %s "
- "disabled - primary interface not active\n",
- net_dev->name);
- }
-
- seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
- SOURCE_VERSION, REVISION_VERSION_STR,
- bat_priv->primary_if->net_dev->name,
- bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
- seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
- "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
- "outgoingIF", "Potential nexthops");
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
-
- orig_node = hashit.bucket->data;
-
- if (!orig_node->router)
- continue;
-
- if (orig_node->router->tq_avg == 0)
- continue;
-
- last_seen_secs = jiffies_to_msecs(jiffies -
- orig_node->last_valid) / 1000;
- last_seen_msecs = jiffies_to_msecs(jiffies -
- orig_node->last_valid) % 1000;
-
- seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
- orig_node->orig, last_seen_secs, last_seen_msecs,
- orig_node->router->tq_avg, orig_node->router->addr,
- orig_node->router->if_incoming->net_dev->name);
-
- list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
- seq_printf(seq, " %pM (%3i)", neigh_node->addr,
- neigh_node->tq_avg);
- }
-
- seq_printf(seq, "\n");
- batman_count++;
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- if ((batman_count == 0))
- seq_printf(seq, "No batman nodes in range ...\n");
-
- return 0;
-}
-
-static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
-{
- void *data_ptr;
-
- data_ptr = kmalloc(max_if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS,
- GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
- return -1;
- }
-
- memcpy(data_ptr, orig_node->bcast_own,
- (max_if_num - 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS);
- kfree(orig_node->bcast_own);
- orig_node->bcast_own = data_ptr;
-
- data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
- return -1;
- }
-
- memcpy(data_ptr, orig_node->bcast_own_sum,
- (max_if_num - 1) * sizeof(uint8_t));
- kfree(orig_node->bcast_own_sum);
- orig_node->bcast_own_sum = data_ptr;
-
- return 0;
-}
-
-int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- struct orig_node *orig_node;
- unsigned long flags;
- HASHIT(hashit);
-
- /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
- * if_num */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
-
- if (orig_node_add_if(orig_node, max_if_num) == -1)
- goto err;
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return 0;
-
-err:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return -ENOMEM;
-}
-
-static int orig_node_del_if(struct orig_node *orig_node,
- int max_if_num, int del_if_num)
-{
- void *data_ptr = NULL;
- int chunk_size;
-
- /* last interface was removed */
- if (max_if_num == 0)
- goto free_bcast_own;
-
- chunk_size = sizeof(TYPE_OF_WORD) * NUM_WORDS;
- data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
- return -1;
- }
-
- /* copy first part */
- memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
-
- /* copy second part */
- memcpy(data_ptr + del_if_num * chunk_size,
- orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
- (max_if_num - del_if_num) * chunk_size);
-
-free_bcast_own:
- kfree(orig_node->bcast_own);
- orig_node->bcast_own = data_ptr;
-
- if (max_if_num == 0)
- goto free_own_sum;
-
- data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
- return -1;
- }
-
- memcpy(data_ptr, orig_node->bcast_own_sum,
- del_if_num * sizeof(uint8_t));
-
- memcpy(data_ptr + del_if_num * sizeof(uint8_t),
- orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
- (max_if_num - del_if_num) * sizeof(uint8_t));
-
-free_own_sum:
- kfree(orig_node->bcast_own_sum);
- orig_node->bcast_own_sum = data_ptr;
-
- return 0;
-}
-
-int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- struct batman_if *batman_if_tmp;
- struct orig_node *orig_node;
- unsigned long flags;
- HASHIT(hashit);
- int ret;
-
- /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
- * if_num */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
-
- ret = orig_node_del_if(orig_node, max_if_num,
- batman_if->if_num);
-
- if (ret == -1)
- goto err;
- }
-
- /* renumber remaining batman interfaces _inside_ of orig_hash_lock */
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if_tmp, &if_list, list) {
- if (batman_if_tmp->if_status == IF_NOT_IN_USE)
- continue;
-
- if (batman_if == batman_if_tmp)
- continue;
-
- if (batman_if->soft_iface != batman_if_tmp->soft_iface)
- continue;
-
- if (batman_if_tmp->if_num > batman_if->if_num)
- batman_if_tmp->if_num--;
- }
- rcu_read_unlock();
-
- batman_if->if_num = -1;
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return 0;
-
-err:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return -ENOMEM;
-}
diff --git a/drivers/staging/batman-adv/originator.h b/drivers/staging/batman-adv/originator.h
deleted file mode 100644
index a97c4004776a..000000000000
--- a/drivers/staging/batman-adv/originator.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
-#define _NET_BATMAN_ADV_ORIGINATOR_H_
-
-int originator_init(struct bat_priv *bat_priv);
-void originator_free(struct bat_priv *bat_priv);
-void purge_orig_ref(struct bat_priv *bat_priv);
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
-struct neigh_node *
-create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
- uint8_t *neigh, struct batman_if *if_incoming);
-int orig_seq_print_text(struct seq_file *seq, void *offset);
-int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
-int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
-
-#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */
diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h
deleted file mode 100644
index 2693383889a4..000000000000
--- a/drivers/staging/batman-adv/packet.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_PACKET_H_
-#define _NET_BATMAN_ADV_PACKET_H_
-
-#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
-
-#define BAT_PACKET 0x01
-#define BAT_ICMP 0x02
-#define BAT_UNICAST 0x03
-#define BAT_BCAST 0x04
-#define BAT_VIS 0x05
-#define BAT_UNICAST_FRAG 0x06
-
-/* this file is included by batctl which needs these defines */
-#define COMPAT_VERSION 13
-#define DIRECTLINK 0x40
-#define VIS_SERVER 0x20
-#define PRIMARIES_FIRST_HOP 0x10
-
-/* ICMP message types */
-#define ECHO_REPLY 0
-#define DESTINATION_UNREACHABLE 3
-#define ECHO_REQUEST 8
-#define TTL_EXCEEDED 11
-#define PARAMETER_PROBLEM 12
-
-/* vis defines */
-#define VIS_TYPE_SERVER_SYNC 0
-#define VIS_TYPE_CLIENT_UPDATE 1
-
-/* fragmentation defines */
-#define UNI_FRAG_HEAD 0x01
-
-struct batman_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
- uint8_t tq;
- uint32_t seqno;
- uint8_t orig[6];
- uint8_t prev_sender[6];
- uint8_t ttl;
- uint8_t num_hna;
-} __attribute__((packed));
-
-#define BAT_PACKET_LEN sizeof(struct batman_packet)
-
-struct icmp_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
- uint8_t ttl;
- uint8_t dst[6];
- uint8_t orig[6];
- uint16_t seqno;
- uint8_t uid;
-} __attribute__((packed));
-
-#define BAT_RR_LEN 16
-
-/* icmp_packet_rr must start with all fields from imcp_packet
- * as this is assumed by code that handles ICMP packets */
-struct icmp_packet_rr {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
- uint8_t ttl;
- uint8_t dst[6];
- uint8_t orig[6];
- uint16_t seqno;
- uint8_t uid;
- uint8_t rr_cur;
- uint8_t rr[BAT_RR_LEN][ETH_ALEN];
-} __attribute__((packed));
-
-struct unicast_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t dest[6];
- uint8_t ttl;
-} __attribute__((packed));
-
-struct unicast_frag_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t dest[6];
- uint8_t ttl;
- uint8_t flags;
- uint8_t orig[6];
- uint16_t seqno;
-} __attribute__((packed));
-
-struct bcast_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t orig[6];
- uint8_t ttl;
- uint32_t seqno;
-} __attribute__((packed));
-
-struct vis_packet {
- uint8_t packet_type;
- uint8_t version; /* batman version field */
- uint8_t vis_type; /* which type of vis-participant sent this? */
- uint8_t entries; /* number of entries behind this struct */
- uint32_t seqno; /* sequence number */
- uint8_t ttl; /* TTL */
- uint8_t vis_orig[6]; /* originator that informs about its
- * neighbors */
- uint8_t target_orig[6]; /* who should receive this packet */
- uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
-} __attribute__((packed));
-
-#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/drivers/staging/batman-adv/ring_buffer.c b/drivers/staging/batman-adv/ring_buffer.c
deleted file mode 100644
index defd37c9be1f..000000000000
--- a/drivers/staging/batman-adv/ring_buffer.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "ring_buffer.h"
-
-void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
-{
- lq_recv[*lq_index] = value;
- *lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
-}
-
-uint8_t ring_buffer_avg(uint8_t lq_recv[])
-{
- uint8_t *ptr;
- uint16_t count = 0, i = 0, sum = 0;
-
- ptr = lq_recv;
-
- while (i < TQ_GLOBAL_WINDOW_SIZE) {
- if (*ptr != 0) {
- count++;
- sum += *ptr;
- }
-
- i++;
- ptr++;
- }
-
- if (count == 0)
- return 0;
-
- return (uint8_t)(sum / count);
-}
diff --git a/drivers/staging/batman-adv/ring_buffer.h b/drivers/staging/batman-adv/ring_buffer.h
deleted file mode 100644
index 6b0cb9aaeba5..000000000000
--- a/drivers/staging/batman-adv/ring_buffer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_RING_BUFFER_H_
-#define _NET_BATMAN_ADV_RING_BUFFER_H_
-
-void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
-uint8_t ring_buffer_avg(uint8_t lq_recv[]);
-
-#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
deleted file mode 100644
index 90102631330b..000000000000
--- a/drivers/staging/batman-adv/routing.c
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "routing.h"
-#include "send.h"
-#include "hash.h"
-#include "soft-interface.h"
-#include "hard-interface.h"
-#include "icmp_socket.h"
-#include "translation-table.h"
-#include "originator.h"
-#include "types.h"
-#include "ring_buffer.h"
-#include "vis.h"
-#include "aggregation.h"
-#include "unicast.h"
-
-void slide_own_bcast_window(struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- HASHIT(hashit);
- struct orig_node *orig_node;
- TYPE_OF_WORD *word;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
- word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
-
- bit_get_packet(bat_priv, word, 1, 0);
- orig_node->bcast_own_sum[batman_if->if_num] =
- bit_packet_count(word);
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-}
-
-static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
- unsigned char *hna_buff, int hna_buff_len)
-{
- if ((hna_buff_len != orig_node->hna_buff_len) ||
- ((hna_buff_len > 0) &&
- (orig_node->hna_buff_len > 0) &&
- (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
-
- if (orig_node->hna_buff_len > 0)
- hna_global_del_orig(bat_priv, orig_node,
- "originator changed hna");
-
- if ((hna_buff_len > 0) && (hna_buff != NULL))
- hna_global_add_orig(bat_priv, orig_node,
- hna_buff, hna_buff_len);
- }
-}
-
-static void update_route(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct neigh_node *neigh_node,
- unsigned char *hna_buff, int hna_buff_len)
-{
- /* route deleted */
- if ((orig_node->router != NULL) && (neigh_node == NULL)) {
-
- bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
- orig_node->orig);
- hna_global_del_orig(bat_priv, orig_node,
- "originator timed out");
-
- /* route added */
- } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
-
- bat_dbg(DBG_ROUTES, bat_priv,
- "Adding route towards: %pM (via %pM)\n",
- orig_node->orig, neigh_node->addr);
- hna_global_add_orig(bat_priv, orig_node,
- hna_buff, hna_buff_len);
-
- /* route changed */
- } else {
- bat_dbg(DBG_ROUTES, bat_priv,
- "Changing route towards: %pM "
- "(now via %pM - was via %pM)\n",
- orig_node->orig, neigh_node->addr,
- orig_node->router->addr);
- }
-
- orig_node->router = neigh_node;
-}
-
-
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, unsigned char *hna_buff,
- int hna_buff_len)
-{
-
- if (orig_node == NULL)
- return;
-
- if (orig_node->router != neigh_node)
- update_route(bat_priv, orig_node, neigh_node,
- hna_buff, hna_buff_len);
- /* may be just HNA changed */
- else
- update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
-}
-
-static int is_bidirectional_neigh(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet,
- struct batman_if *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
- unsigned char total_count;
-
- if (orig_node == orig_neigh_node) {
- list_for_each_entry(tmp_neigh_node,
- &orig_node->neigh_list,
- list) {
-
- if (compare_orig(tmp_neigh_node->addr,
- orig_neigh_node->orig) &&
- (tmp_neigh_node->if_incoming == if_incoming))
- neigh_node = tmp_neigh_node;
- }
-
- if (!neigh_node)
- neigh_node = create_neighbor(orig_node,
- orig_neigh_node,
- orig_neigh_node->orig,
- if_incoming);
- /* create_neighbor failed, return 0 */
- if (!neigh_node)
- return 0;
-
- neigh_node->last_valid = jiffies;
- } else {
- /* find packet count of corresponding one hop neighbor */
- list_for_each_entry(tmp_neigh_node,
- &orig_neigh_node->neigh_list, list) {
-
- if (compare_orig(tmp_neigh_node->addr,
- orig_neigh_node->orig) &&
- (tmp_neigh_node->if_incoming == if_incoming))
- neigh_node = tmp_neigh_node;
- }
-
- if (!neigh_node)
- neigh_node = create_neighbor(orig_neigh_node,
- orig_neigh_node,
- orig_neigh_node->orig,
- if_incoming);
- /* create_neighbor failed, return 0 */
- if (!neigh_node)
- return 0;
- }
-
- orig_node->last_valid = jiffies;
-
- /* pay attention to not get a value bigger than 100 % */
- total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] >
- neigh_node->real_packet_count ?
- neigh_node->real_packet_count :
- orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
-
- /* if we have too few packets (too less data) we set tq_own to zero */
- /* if we receive too few packets it is not considered bidirectional */
- if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
- (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
- orig_neigh_node->tq_own = 0;
- else
- /* neigh_node->real_packet_count is never zero as we
- * only purge old information when getting new
- * information */
- orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) /
- neigh_node->real_packet_count;
-
- /*
- * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
- * affect the nearly-symmetric links only a little, but
- * punishes asymmetric links more. This will give a value
- * between 0 and TQ_MAX_VALUE
- */
- orig_neigh_node->tq_asym_penalty =
- TQ_MAX_VALUE -
- (TQ_MAX_VALUE *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
- (TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE);
-
- batman_packet->tq = ((batman_packet->tq *
- orig_neigh_node->tq_own *
- orig_neigh_node->tq_asym_penalty) /
- (TQ_MAX_VALUE * TQ_MAX_VALUE));
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "bidirectional: "
- "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
- "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
- "total tq: %3i\n",
- orig_node->orig, orig_neigh_node->orig, total_count,
- neigh_node->real_packet_count, orig_neigh_node->tq_own,
- orig_neigh_node->tq_asym_penalty, batman_packet->tq);
-
- /* if link has the minimum required transmission quality
- * consider it bidirectional */
- if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
- return 1;
-
- return 0;
-}
-
-static void update_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- struct batman_if *if_incoming,
- unsigned char *hna_buff, int hna_buff_len,
- char is_duplicate)
-{
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
- int tmp_hna_buff_len;
-
- bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
- "Searching and updating originator entry of received packet\n");
-
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
- if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming)) {
- neigh_node = tmp_neigh_node;
- continue;
- }
-
- if (is_duplicate)
- continue;
-
- ring_buffer_set(tmp_neigh_node->tq_recv,
- &tmp_neigh_node->tq_index, 0);
- tmp_neigh_node->tq_avg =
- ring_buffer_avg(tmp_neigh_node->tq_recv);
- }
-
- if (!neigh_node) {
- struct orig_node *orig_tmp;
-
- orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
- if (!orig_tmp)
- return;
-
- neigh_node = create_neighbor(orig_node, orig_tmp,
- ethhdr->h_source, if_incoming);
- if (!neigh_node)
- return;
- } else
- bat_dbg(DBG_BATMAN, bat_priv,
- "Updating existing last-hop neighbor of originator\n");
-
- orig_node->flags = batman_packet->flags;
- neigh_node->last_valid = jiffies;
-
- ring_buffer_set(neigh_node->tq_recv,
- &neigh_node->tq_index,
- batman_packet->tq);
- neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
-
- if (!is_duplicate) {
- orig_node->last_ttl = batman_packet->ttl;
- neigh_node->last_ttl = batman_packet->ttl;
- }
-
- tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
- batman_packet->num_hna * ETH_ALEN : hna_buff_len);
-
- /* if this neighbor already is our next hop there is nothing
- * to change */
- if (orig_node->router == neigh_node)
- goto update_hna;
-
- /* if this neighbor does not offer a better TQ we won't consider it */
- if ((orig_node->router) &&
- (orig_node->router->tq_avg > neigh_node->tq_avg))
- goto update_hna;
-
- /* if the TQ is the same and the link not more symetric we
- * won't consider it either */
- if ((orig_node->router) &&
- ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
- (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
- >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
- goto update_hna;
-
- update_routes(bat_priv, orig_node, neigh_node,
- hna_buff, tmp_hna_buff_len);
- return;
-
-update_hna:
- update_routes(bat_priv, orig_node, orig_node->router,
- hna_buff, tmp_hna_buff_len);
-}
-
-/* checks whether the host restarted and is in the protection time.
- * returns:
- * 0 if the packet is to be accepted
- * 1 if the packet is to be ignored.
- */
-static int window_protected(struct bat_priv *bat_priv,
- int32_t seq_num_diff,
- unsigned long *last_reset)
-{
- if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
- || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
- if (time_after(jiffies, *last_reset +
- msecs_to_jiffies(RESET_PROTECTION_MS))) {
-
- *last_reset = jiffies;
- bat_dbg(DBG_BATMAN, bat_priv,
- "old packet received, start protection\n");
-
- return 0;
- } else
- return 1;
- }
- return 0;
-}
-
-/* processes a batman packet for all interfaces, adjusts the sequence number and
- * finds out whether it is a duplicate.
- * returns:
- * 1 the packet is a duplicate
- * 0 the packet has not yet been received
- * -1 the packet is old and has been received while the seqno window
- * was protected. Caller should drop it.
- */
-static char count_real_packets(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- struct batman_if *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct orig_node *orig_node;
- struct neigh_node *tmp_neigh_node;
- char is_duplicate = 0;
- int32_t seq_diff;
- int need_update = 0;
- int set_mark;
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (orig_node == NULL)
- return 0;
-
- seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
-
- /* signalize caller that the packet is to be dropped. */
- if (window_protected(bat_priv, seq_diff,
- &orig_node->batman_seqno_reset))
- return -1;
-
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
-
- is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
- orig_node->last_real_seqno,
- batman_packet->seqno);
-
- if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming))
- set_mark = 1;
- else
- set_mark = 0;
-
- /* if the window moved, set the update flag. */
- need_update |= bit_get_packet(bat_priv,
- tmp_neigh_node->real_bits,
- seq_diff, set_mark);
-
- tmp_neigh_node->real_packet_count =
- bit_packet_count(tmp_neigh_node->real_bits);
- }
-
- if (need_update) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "updating last_seqno: old %d, new %d\n",
- orig_node->last_real_seqno, batman_packet->seqno);
- orig_node->last_real_seqno = batman_packet->seqno;
- }
-
- return is_duplicate;
-}
-
-/* copy primary address for bonding */
-static void mark_bonding_address(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet)
-
-{
- if (batman_packet->flags & PRIMARIES_FIRST_HOP)
- memcpy(orig_neigh_node->primary_addr,
- orig_node->orig, ETH_ALEN);
-
- return;
-}
-
-/* mark possible bond.candidates in the neighbor list */
-void update_bonding_candidates(struct bat_priv *bat_priv,
- struct orig_node *orig_node)
-{
- int candidates;
- int interference_candidate;
- int best_tq;
- struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
- struct neigh_node *first_candidate, *last_candidate;
-
- /* update the candidates for this originator */
- if (!orig_node->router) {
- orig_node->bond.candidates = 0;
- return;
- }
-
- best_tq = orig_node->router->tq_avg;
-
- /* update bond.candidates */
-
- candidates = 0;
-
- /* mark other nodes which also received "PRIMARIES FIRST HOP" packets
- * as "bonding partner" */
-
- /* first, zero the list */
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
- tmp_neigh_node->next_bond_candidate = NULL;
- }
-
- first_candidate = NULL;
- last_candidate = NULL;
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
-
- /* only consider if it has the same primary address ... */
- if (memcmp(orig_node->orig,
- tmp_neigh_node->orig_node->primary_addr,
- ETH_ALEN) != 0)
- continue;
-
- /* ... and is good enough to be considered */
- if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
- continue;
-
- /* check if we have another candidate with the same
- * mac address or interface. If we do, we won't
- * select this candidate because of possible interference. */
-
- interference_candidate = 0;
- list_for_each_entry(tmp_neigh_node2,
- &orig_node->neigh_list, list) {
-
- if (tmp_neigh_node2 == tmp_neigh_node)
- continue;
-
- /* we only care if the other candidate is even
- * considered as candidate. */
- if (tmp_neigh_node2->next_bond_candidate == NULL)
- continue;
-
-
- if ((tmp_neigh_node->if_incoming ==
- tmp_neigh_node2->if_incoming)
- || (memcmp(tmp_neigh_node->addr,
- tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
-
- interference_candidate = 1;
- break;
- }
- }
- /* don't care further if it is an interference candidate */
- if (interference_candidate)
- continue;
-
- if (first_candidate == NULL) {
- first_candidate = tmp_neigh_node;
- tmp_neigh_node->next_bond_candidate = first_candidate;
- } else
- tmp_neigh_node->next_bond_candidate = last_candidate;
-
- last_candidate = tmp_neigh_node;
-
- candidates++;
- }
-
- if (candidates > 0) {
- first_candidate->next_bond_candidate = last_candidate;
- orig_node->bond.selected = first_candidate;
- }
-
- orig_node->bond.candidates = candidates;
-}
-
-void receive_bat_packet(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- unsigned char *hna_buff, int hna_buff_len,
- struct batman_if *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batman_if *batman_if;
- struct orig_node *orig_neigh_node, *orig_node;
- char has_directlink_flag;
- char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
- char is_duplicate;
- uint32_t if_incoming_seqno;
-
- /* Silently drop when the batman packet is actually not a
- * correct packet.
- *
- * This might happen if a packet is padded (e.g. Ethernet has a
- * minimum frame length of 64 byte) and the aggregation interprets
- * it as an additional length.
- *
- * TODO: A more sane solution would be to have a bit in the
- * batman_packet to detect whether the packet is the last
- * packet in an aggregation. Here we expect that the padding
- * is always zero (or not 0x01)
- */
- if (batman_packet->packet_type != BAT_PACKET)
- return;
-
- /* could be changed by schedule_own_packet() */
- if_incoming_seqno = atomic_read(&if_incoming->seqno);
-
- has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- is_single_hop_neigh = (compare_orig(ethhdr->h_source,
- batman_packet->orig) ? 1 : 0);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
- "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
- "TTL %d, V %d, IDF %d)\n",
- ethhdr->h_source, if_incoming->net_dev->name,
- if_incoming->net_dev->dev_addr, batman_packet->orig,
- batman_packet->prev_sender, batman_packet->seqno,
- batman_packet->tq, batman_packet->ttl, batman_packet->version,
- has_directlink_flag);
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->if_status != IF_ACTIVE)
- continue;
-
- if (batman_if->soft_iface != if_incoming->soft_iface)
- continue;
-
- if (compare_orig(ethhdr->h_source,
- batman_if->net_dev->dev_addr))
- is_my_addr = 1;
-
- if (compare_orig(batman_packet->orig,
- batman_if->net_dev->dev_addr))
- is_my_orig = 1;
-
- if (compare_orig(batman_packet->prev_sender,
- batman_if->net_dev->dev_addr))
- is_my_oldorig = 1;
-
- if (compare_orig(ethhdr->h_source, broadcast_addr))
- is_broadcast = 1;
- }
- rcu_read_unlock();
-
- if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
- return;
- }
-
- if (is_my_addr) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: received my own broadcast (sender: %pM"
- ")\n",
- ethhdr->h_source);
- return;
- }
-
- if (is_broadcast) {
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "ignoring all packets with broadcast source addr (sender: %pM"
- ")\n", ethhdr->h_source);
- return;
- }
-
- if (is_my_orig) {
- TYPE_OF_WORD *word;
- int offset;
-
- orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
-
- if (!orig_neigh_node)
- return;
-
- /* neighbor has to indicate direct link and it has to
- * come via the corresponding interface */
- /* if received seqno equals last send seqno save new
- * seqno for bidirectional check */
- if (has_directlink_flag &&
- compare_orig(if_incoming->net_dev->dev_addr,
- batman_packet->orig) &&
- (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
- offset = if_incoming->if_num * NUM_WORDS;
- word = &(orig_neigh_node->bcast_own[offset]);
- bit_mark(word, 0);
- orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
- bit_packet_count(word);
- }
-
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "originator packet from myself (via neighbor)\n");
- return;
- }
-
- if (is_my_oldorig) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast echos (sender: "
- "%pM)\n", ethhdr->h_source);
- return;
- }
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (orig_node == NULL)
- return;
-
- is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
-
- if (is_duplicate == -1) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: packet within seqno protection time "
- "(sender: %pM)\n", ethhdr->h_source);
- return;
- }
-
- if (batman_packet->tq == 0) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: originator packet with tq equal 0\n");
- return;
- }
-
- /* avoid temporary routing loops */
- if ((orig_node->router) &&
- (orig_node->router->orig_node->router) &&
- (compare_orig(orig_node->router->addr,
- batman_packet->prev_sender)) &&
- !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
- (compare_orig(orig_node->router->addr,
- orig_node->router->orig_node->router->addr))) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast packets that "
- "may make me loop (sender: %pM)\n", ethhdr->h_source);
- return;
- }
-
- /* if sender is a direct neighbor the sender mac equals
- * originator mac */
- orig_neigh_node = (is_single_hop_neigh ?
- orig_node :
- get_orig_node(bat_priv, ethhdr->h_source));
- if (orig_neigh_node == NULL)
- return;
-
- /* drop packet if sender is not a direct neighbor and if we
- * don't route towards it */
- if (!is_single_hop_neigh &&
- (orig_neigh_node->router == NULL)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: OGM via unknown neighbor!\n");
- return;
- }
-
- is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
- batman_packet, if_incoming);
-
- /* update ranking if it is not a duplicate or has the same
- * seqno and similar ttl as the non-duplicate */
- if (is_bidirectional &&
- (!is_duplicate ||
- ((orig_node->last_real_seqno == batman_packet->seqno) &&
- (orig_node->last_ttl - 3 <= batman_packet->ttl))))
- update_orig(bat_priv, orig_node, ethhdr, batman_packet,
- if_incoming, hna_buff, hna_buff_len, is_duplicate);
-
- mark_bonding_address(bat_priv, orig_node,
- orig_neigh_node, batman_packet);
- update_bonding_candidates(bat_priv, orig_node);
-
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
-
- /* mark direct link on incoming interface */
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 1, hna_buff_len, if_incoming);
-
- bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
- "rebroadcast neighbor packet with direct link flag\n");
- return;
- }
-
- /* multihop originator */
- if (!is_bidirectional) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: not received via bidirectional link\n");
- return;
- }
-
- if (is_duplicate) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: duplicate packet received\n");
- return;
- }
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: rebroadcast originator packet\n");
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 0, hna_buff_len, if_incoming);
-}
-
-int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- struct ethhdr *ethhdr;
- unsigned long flags;
-
- /* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet))))
- return NET_RX_DROP;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* packet with broadcast indication but unicast recipient */
- if (!is_bcast(ethhdr->h_dest))
- return NET_RX_DROP;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- return NET_RX_DROP;
-
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, 0) < 0)
- return NET_RX_DROP;
-
- /* keep skb linear */
- if (skb_linearize(skb) < 0)
- return NET_RX_DROP;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- receive_aggr_bat_packet(ethhdr,
- skb->data,
- skb_headlen(skb),
- batman_if);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- kfree_skb(skb);
- return NET_RX_SUCCESS;
-}
-
-static int recv_my_icmp_packet(struct bat_priv *bat_priv,
- struct sk_buff *skb, size_t icmp_len)
-{
- struct orig_node *orig_node;
- struct icmp_packet_rr *icmp_packet;
- struct ethhdr *ethhdr;
- struct batman_if *batman_if;
- int ret;
- unsigned long flags;
- uint8_t dstaddr[ETH_ALEN];
-
- icmp_packet = (struct icmp_packet_rr *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* add data to device queue */
- if (icmp_packet->msg_type != ECHO_REQUEST) {
- bat_socket_receive_packet(icmp_packet, icmp_len);
- return NET_RX_DROP;
- }
-
- if (!bat_priv->primary_if)
- return NET_RX_DROP;
-
- /* answer echo request (ping) */
- /* get routing information */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
- icmp_packet->orig));
- ret = NET_RX_DROP;
-
- if ((orig_node != NULL) &&
- (orig_node->router != NULL)) {
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
-
- icmp_packet = (struct icmp_packet_rr *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- icmp_packet->msg_type = ECHO_REPLY;
- icmp_packet->ttl = TTL;
-
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
-
- } else
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- return ret;
-}
-
-static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
- struct sk_buff *skb, size_t icmp_len)
-{
- struct orig_node *orig_node;
- struct icmp_packet *icmp_packet;
- struct ethhdr *ethhdr;
- struct batman_if *batman_if;
- int ret;
- unsigned long flags;
- uint8_t dstaddr[ETH_ALEN];
-
- icmp_packet = (struct icmp_packet *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* send TTL exceeded if packet is an echo request (traceroute) */
- if (icmp_packet->msg_type != ECHO_REQUEST) {
- pr_debug("Warning - can't forward icmp packet from %pM to "
- "%pM: ttl exceeded\n", icmp_packet->orig,
- icmp_packet->dst);
- return NET_RX_DROP;
- }
-
- if (!bat_priv->primary_if)
- return NET_RX_DROP;
-
- /* get routing information */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, icmp_packet->orig));
- ret = NET_RX_DROP;
-
- if ((orig_node != NULL) &&
- (orig_node->router != NULL)) {
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
-
- icmp_packet = (struct icmp_packet *) skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- icmp_packet->msg_type = TTL_EXCEEDED;
- icmp_packet->ttl = TTL;
-
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
-
- } else
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- return ret;
-}
-
-
-int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct icmp_packet_rr *icmp_packet;
- struct ethhdr *ethhdr;
- struct orig_node *orig_node;
- struct batman_if *batman_if;
- int hdr_size = sizeof(struct icmp_packet);
- int ret;
- unsigned long flags;
- uint8_t dstaddr[ETH_ALEN];
-
- /**
- * we truncate all incoming icmp packets if they don't match our size
- */
- if (skb->len >= sizeof(struct icmp_packet_rr))
- hdr_size = sizeof(struct icmp_packet_rr);
-
- /* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return NET_RX_DROP;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* packet with unicast indication but broadcast recipient */
- if (is_bcast(ethhdr->h_dest))
- return NET_RX_DROP;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- return NET_RX_DROP;
-
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- return NET_RX_DROP;
-
- icmp_packet = (struct icmp_packet_rr *)skb->data;
-
- /* add record route information if not full */
- if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
- (icmp_packet->rr_cur < BAT_RR_LEN)) {
- memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
- ethhdr->h_dest, ETH_ALEN);
- icmp_packet->rr_cur++;
- }
-
- /* packet for me */
- if (is_my_mac(icmp_packet->dst))
- return recv_my_icmp_packet(bat_priv, skb, hdr_size);
-
- /* TTL exceeded */
- if (icmp_packet->ttl < 2)
- return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size);
-
- ret = NET_RX_DROP;
-
- /* get routing information */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, icmp_packet->dst));
-
- if ((orig_node != NULL) &&
- (orig_node->router != NULL)) {
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
-
- icmp_packet = (struct icmp_packet_rr *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* decrement ttl */
- icmp_packet->ttl--;
-
- /* route it */
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
-
- } else
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- return ret;
-}
-
-/* find a suitable router for this originator, and use
- * bonding if possible. */
-struct neigh_node *find_router(struct orig_node *orig_node,
- struct batman_if *recv_if)
-{
- struct bat_priv *bat_priv;
- struct orig_node *primary_orig_node;
- struct orig_node *router_orig;
- struct neigh_node *router, *first_candidate, *best_router;
- static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
- int bonding_enabled;
-
- if (!orig_node)
- return NULL;
-
- if (!orig_node->router)
- return NULL;
-
- /* without bonding, the first node should
- * always choose the default router. */
-
- if (!recv_if)
- return orig_node->router;
-
- bat_priv = netdev_priv(recv_if->soft_iface);
- bonding_enabled = atomic_read(&bat_priv->bonding_enabled);
-
- if (!bonding_enabled)
- return orig_node->router;
-
- router_orig = orig_node->router->orig_node;
-
- /* if we have something in the primary_addr, we can search
- * for a potential bonding candidate. */
- if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
- return orig_node->router;
-
- /* find the orig_node which has the primary interface. might
- * even be the same as our router_orig in many cases */
-
- if (memcmp(router_orig->primary_addr,
- router_orig->orig, ETH_ALEN) == 0) {
- primary_orig_node = router_orig;
- } else {
- primary_orig_node = hash_find(bat_priv->orig_hash,
- router_orig->primary_addr);
-
- if (!primary_orig_node)
- return orig_node->router;
- }
-
- /* with less than 2 candidates, we can't do any
- * bonding and prefer the original router. */
-
- if (primary_orig_node->bond.candidates < 2)
- return orig_node->router;
-
-
- /* all nodes between should choose a candidate which
- * is is not on the interface where the packet came
- * in. */
- first_candidate = primary_orig_node->bond.selected;
- router = first_candidate;
-
- if (bonding_enabled) {
- /* in the bonding case, send the packets in a round
- * robin fashion over the remaining interfaces. */
- do {
- /* recv_if == NULL on the first node. */
- if (router->if_incoming != recv_if)
- break;
-
- router = router->next_bond_candidate;
- } while (router != first_candidate);
-
- primary_orig_node->bond.selected = router->next_bond_candidate;
-
- } else {
- /* if bonding is disabled, use the best of the
- * remaining candidates which are not using
- * this interface. */
- best_router = first_candidate;
-
- do {
- /* recv_if == NULL on the first node. */
- if ((router->if_incoming != recv_if) &&
- (router->tq_avg > best_router->tq_avg))
- best_router = router;
-
- router = router->next_bond_candidate;
- } while (router != first_candidate);
-
- router = best_router;
- }
-
- return router;
-}
-
-static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
-{
- struct ethhdr *ethhdr;
-
- /* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return -1;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* packet with unicast indication but broadcast recipient */
- if (is_bcast(ethhdr->h_dest))
- return -1;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- return -1;
-
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- return -1;
-
- return 0;
-}
-
-static int route_unicast_packet(struct sk_buff *skb,
- struct batman_if *recv_if, int hdr_size)
-{
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct orig_node *orig_node;
- struct neigh_node *router;
- struct batman_if *batman_if;
- uint8_t dstaddr[ETH_ALEN];
- unsigned long flags;
- struct unicast_packet *unicast_packet;
- struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- unicast_packet = (struct unicast_packet *)skb->data;
-
- /* packet for me */
- if (is_my_mac(unicast_packet->dest)) {
- interface_rx(recv_if->soft_iface, skb, hdr_size);
- return NET_RX_SUCCESS;
- }
-
- /* TTL exceeded */
- if (unicast_packet->ttl < 2) {
- pr_debug("Warning - can't forward unicast packet from %pM to "
- "%pM: ttl exceeded\n", ethhdr->h_source,
- unicast_packet->dest);
- return NET_RX_DROP;
- }
-
- /* get routing information */
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, unicast_packet->dest));
-
- router = find_router(orig_node, recv_if);
-
- if (!router) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
-
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- /* create a copy of the skb, if needed, to modify it. */
- if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
- return NET_RX_DROP;
-
- unicast_packet = (struct unicast_packet *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* decrement ttl */
- unicast_packet->ttl--;
-
- /* route it */
- send_skb_packet(skb, batman_if, dstaddr);
-
- return NET_RX_SUCCESS;
-}
-
-int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct unicast_packet *unicast_packet;
- int hdr_size = sizeof(struct unicast_packet);
-
- if (check_unicast_packet(skb, hdr_size) < 0)
- return NET_RX_DROP;
-
- unicast_packet = (struct unicast_packet *)skb->data;
-
- /* packet for me */
- if (is_my_mac(unicast_packet->dest)) {
- interface_rx(recv_if->soft_iface, skb, hdr_size);
- return NET_RX_SUCCESS;
- }
-
- return route_unicast_packet(skb, recv_if, hdr_size);
-}
-
-int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct unicast_frag_packet *unicast_packet;
- struct orig_node *orig_node;
- struct frag_packet_list_entry *tmp_frag_entry;
- int hdr_size = sizeof(struct unicast_frag_packet);
- unsigned long flags;
-
- if (check_unicast_packet(skb, hdr_size) < 0)
- return NET_RX_DROP;
-
- unicast_packet = (struct unicast_frag_packet *)skb->data;
-
- /* packet for me */
- if (is_my_mac(unicast_packet->dest)) {
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, unicast_packet->orig));
-
- if (!orig_node) {
- pr_debug("couldn't find orig node for fragmentation\n");
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
- flags);
- return NET_RX_DROP;
- }
-
- orig_node->last_frag_packet = jiffies;
-
- if (list_empty(&orig_node->frag_list) &&
- create_frag_buffer(&orig_node->frag_list)) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
- flags);
- return NET_RX_DROP;
- }
-
- tmp_frag_entry =
- search_frag_packet(&orig_node->frag_list,
- unicast_packet);
-
- if (!tmp_frag_entry) {
- create_frag_entry(&orig_node->frag_list, skb);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
- flags);
- return NET_RX_SUCCESS;
- }
-
- skb = merge_frag_packet(&orig_node->frag_list,
- tmp_frag_entry, skb);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- if (!skb)
- return NET_RX_DROP;
-
- interface_rx(recv_if->soft_iface, skb, hdr_size);
- return NET_RX_SUCCESS;
- }
-
- return route_unicast_packet(skb, recv_if, hdr_size);
-}
-
-
-int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct orig_node *orig_node;
- struct bcast_packet *bcast_packet;
- struct ethhdr *ethhdr;
- int hdr_size = sizeof(struct bcast_packet);
- int32_t seq_diff;
- unsigned long flags;
-
- /* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return NET_RX_DROP;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* packet with broadcast indication but unicast recipient */
- if (!is_bcast(ethhdr->h_dest))
- return NET_RX_DROP;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- return NET_RX_DROP;
-
- /* ignore broadcasts sent by myself */
- if (is_my_mac(ethhdr->h_source))
- return NET_RX_DROP;
-
- bcast_packet = (struct bcast_packet *)skb->data;
-
- /* ignore broadcasts originated by myself */
- if (is_my_mac(bcast_packet->orig))
- return NET_RX_DROP;
-
- if (bcast_packet->ttl < 2)
- return NET_RX_DROP;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, bcast_packet->orig));
-
- if (orig_node == NULL) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- /* check whether the packet is a duplicate */
- if (get_bit_status(orig_node->bcast_bits,
- orig_node->last_bcast_seqno,
- ntohl(bcast_packet->seqno))) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
-
- /* check whether the packet is old and the host just restarted. */
- if (window_protected(bat_priv, seq_diff,
- &orig_node->bcast_seqno_reset)) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- /* mark broadcast in flood history, update window position
- * if required. */
- if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
- orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- /* rebroadcast packet */
- add_bcast_packet_to_list(bat_priv, skb);
-
- /* broadcast for me */
- interface_rx(recv_if->soft_iface, skb, hdr_size);
-
- return NET_RX_SUCCESS;
-}
-
-int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct vis_packet *vis_packet;
- struct ethhdr *ethhdr;
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- int hdr_size = sizeof(struct vis_packet);
-
- /* keep skb linear */
- if (skb_linearize(skb) < 0)
- return NET_RX_DROP;
-
- if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return NET_RX_DROP;
-
- vis_packet = (struct vis_packet *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- return NET_RX_DROP;
-
- /* ignore own packets */
- if (is_my_mac(vis_packet->vis_orig))
- return NET_RX_DROP;
-
- if (is_my_mac(vis_packet->sender_orig))
- return NET_RX_DROP;
-
- switch (vis_packet->vis_type) {
- case VIS_TYPE_SERVER_SYNC:
- receive_server_sync_packet(bat_priv, vis_packet,
- skb_headlen(skb));
- break;
-
- case VIS_TYPE_CLIENT_UPDATE:
- receive_client_update_packet(bat_priv, vis_packet,
- skb_headlen(skb));
- break;
-
- default: /* ignore unknown packet */
- break;
- }
-
- /* We take a copy of the data in the packet, so we should
- always free the skbuf. */
- return NET_RX_DROP;
-}
diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h
deleted file mode 100644
index 06ea99df3706..000000000000
--- a/drivers/staging/batman-adv/routing.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_ROUTING_H_
-#define _NET_BATMAN_ADV_ROUTING_H_
-
-#include "types.h"
-
-void slide_own_bcast_window(struct batman_if *batman_if);
-void receive_bat_packet(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- unsigned char *hna_buff, int hna_buff_len,
- struct batman_if *if_incoming);
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, unsigned char *hna_buff,
- int hna_buff_len);
-int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if);
-int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if);
-int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if);
-int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
-int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
-int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
-struct neigh_node *find_router(struct orig_node *orig_node,
- struct batman_if *recv_if);
-void update_bonding_candidates(struct bat_priv *bat_priv,
- struct orig_node *orig_node);
-
-#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
deleted file mode 100644
index 7adf76ddd0ba..000000000000
--- a/drivers/staging/batman-adv/send.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "send.h"
-#include "routing.h"
-#include "translation-table.h"
-#include "soft-interface.h"
-#include "hard-interface.h"
-#include "types.h"
-#include "vis.h"
-#include "aggregation.h"
-
-
-static void send_outstanding_bcast_packet(struct work_struct *work);
-
-/* apply hop penalty for a normal link */
-static uint8_t hop_penalty(const uint8_t tq)
-{
- return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE);
-}
-
-/* when do we schedule our own packet to be sent */
-static unsigned long own_send_time(struct bat_priv *bat_priv)
-{
- return jiffies + msecs_to_jiffies(
- atomic_read(&bat_priv->orig_interval) -
- JITTER + (random32() % 2*JITTER));
-}
-
-/* when do we schedule a forwarded packet to be sent */
-static unsigned long forward_send_time(struct bat_priv *bat_priv)
-{
- return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
-}
-
-/* send out an already prepared packet to the given address via the
- * specified batman interface */
-int send_skb_packet(struct sk_buff *skb,
- struct batman_if *batman_if,
- uint8_t *dst_addr)
-{
- struct ethhdr *ethhdr;
-
- if (batman_if->if_status != IF_ACTIVE)
- goto send_skb_err;
-
- if (unlikely(!batman_if->net_dev))
- goto send_skb_err;
-
- if (!(batman_if->net_dev->flags & IFF_UP)) {
- pr_warning("Interface %s is not up - can't send packet via "
- "that interface!\n", batman_if->net_dev->name);
- goto send_skb_err;
- }
-
- /* push to the ethernet header. */
- if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0)
- goto send_skb_err;
-
- skb_reset_mac_header(skb);
-
- ethhdr = (struct ethhdr *) skb_mac_header(skb);
- memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
- memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
- ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
-
- skb_set_network_header(skb, ETH_HLEN);
- skb->priority = TC_PRIO_CONTROL;
- skb->protocol = __constant_htons(ETH_P_BATMAN);
-
- skb->dev = batman_if->net_dev;
-
- /* dev_queue_xmit() returns a negative result on error. However on
- * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
- * (which is > 0). This will not be treated as an error. */
-
- return dev_queue_xmit(skb);
-send_skb_err:
- kfree_skb(skb);
- return NET_XMIT_DROP;
-}
-
-/* Send a packet to a given interface */
-static void send_packet_to_if(struct forw_packet *forw_packet,
- struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- char *fwd_str;
- uint8_t packet_num;
- int16_t buff_pos;
- struct batman_packet *batman_packet;
- struct sk_buff *skb;
-
- if (batman_if->if_status != IF_ACTIVE)
- return;
-
- packet_num = 0;
- buff_pos = 0;
- batman_packet = (struct batman_packet *)forw_packet->skb->data;
-
- /* adjust all flags and log packets */
- while (aggregated_packet(buff_pos,
- forw_packet->packet_len,
- batman_packet->num_hna)) {
-
- /* we might have aggregated direct link packets with an
- * ordinary base packet */
- if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
- (forw_packet->if_incoming == batman_if))
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
-
- fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
- "Sending own" :
- "Forwarding"));
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
- " IDF %s) on interface %s [%pM]\n",
- fwd_str, (packet_num > 0 ? "aggregated " : ""),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->tq, batman_packet->ttl,
- (batman_packet->flags & DIRECTLINK ?
- "on" : "off"),
- batman_if->net_dev->name, batman_if->net_dev->dev_addr);
-
- buff_pos += sizeof(struct batman_packet) +
- (batman_packet->num_hna * ETH_ALEN);
- packet_num++;
- batman_packet = (struct batman_packet *)
- (forw_packet->skb->data + buff_pos);
- }
-
- /* create clone because function is called more than once */
- skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
- if (skb)
- send_skb_packet(skb, batman_if, broadcast_addr);
-}
-
-/* send a batman packet */
-static void send_packet(struct forw_packet *forw_packet)
-{
- struct batman_if *batman_if;
- struct net_device *soft_iface;
- struct bat_priv *bat_priv;
- struct batman_packet *batman_packet =
- (struct batman_packet *)(forw_packet->skb->data);
- unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- if (!forw_packet->if_incoming) {
- pr_err("Error - can't forward packet: incoming iface not "
- "specified\n");
- return;
- }
-
- soft_iface = forw_packet->if_incoming->soft_iface;
- bat_priv = netdev_priv(soft_iface);
-
- if (forw_packet->if_incoming->if_status != IF_ACTIVE)
- return;
-
- /* multihomed peer assumed */
- /* non-primary OGMs are only broadcasted on their interface */
- if ((directlink && (batman_packet->ttl == 1)) ||
- (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
-
- /* FIXME: what about aggregated packets ? */
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s packet (originator %pM, seqno %d, TTL %d) "
- "on interface %s [%pM]\n",
- (forw_packet->own ? "Sending own" : "Forwarding"),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->ttl,
- forw_packet->if_incoming->net_dev->name,
- forw_packet->if_incoming->net_dev->dev_addr);
-
- /* skb is only used once and than forw_packet is free'd */
- send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
- broadcast_addr);
- forw_packet->skb = NULL;
-
- return;
- }
-
- /* broadcast on every interface */
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->soft_iface != soft_iface)
- continue;
-
- send_packet_to_if(forw_packet, batman_if);
- }
- rcu_read_unlock();
-}
-
-static void rebuild_batman_packet(struct bat_priv *bat_priv,
- struct batman_if *batman_if)
-{
- int new_len;
- unsigned char *new_buff;
- struct batman_packet *batman_packet;
-
- new_len = sizeof(struct batman_packet) +
- (bat_priv->num_local_hna * ETH_ALEN);
- new_buff = kmalloc(new_len, GFP_ATOMIC);
-
- /* keep old buffer if kmalloc should fail */
- if (new_buff) {
- memcpy(new_buff, batman_if->packet_buff,
- sizeof(struct batman_packet));
- batman_packet = (struct batman_packet *)new_buff;
-
- batman_packet->num_hna = hna_local_fill_buffer(bat_priv,
- new_buff + sizeof(struct batman_packet),
- new_len - sizeof(struct batman_packet));
-
- kfree(batman_if->packet_buff);
- batman_if->packet_buff = new_buff;
- batman_if->packet_len = new_len;
- }
-}
-
-void schedule_own_packet(struct batman_if *batman_if)
-{
- struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
- unsigned long send_time;
- struct batman_packet *batman_packet;
- int vis_server;
-
- if ((batman_if->if_status == IF_NOT_IN_USE) ||
- (batman_if->if_status == IF_TO_BE_REMOVED))
- return;
-
- vis_server = atomic_read(&bat_priv->vis_mode);
-
- /**
- * the interface gets activated here to avoid race conditions between
- * the moment of activating the interface in
- * hardif_activate_interface() where the originator mac is set and
- * outdated packets (especially uninitialized mac addresses) in the
- * packet queue
- */
- if (batman_if->if_status == IF_TO_BE_ACTIVATED)
- batman_if->if_status = IF_ACTIVE;
-
- /* if local hna has changed and interface is a primary interface */
- if ((atomic_read(&bat_priv->hna_local_changed)) &&
- (batman_if == bat_priv->primary_if))
- rebuild_batman_packet(bat_priv, batman_if);
-
- /**
- * NOTE: packet_buff might just have been re-allocated in
- * rebuild_batman_packet()
- */
- batman_packet = (struct batman_packet *)batman_if->packet_buff;
-
- /* change sequence number to network order */
- batman_packet->seqno =
- htonl((uint32_t)atomic_read(&batman_if->seqno));
-
- if (vis_server == VIS_TYPE_SERVER_SYNC)
- batman_packet->flags |= VIS_SERVER;
- else
- batman_packet->flags &= ~VIS_SERVER;
-
- atomic_inc(&batman_if->seqno);
-
- slide_own_bcast_window(batman_if);
- send_time = own_send_time(bat_priv);
- add_bat_packet_to_list(bat_priv,
- batman_if->packet_buff,
- batman_if->packet_len,
- batman_if, 1, send_time);
-}
-
-void schedule_forward_packet(struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- uint8_t directlink, int hna_buff_len,
- struct batman_if *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- unsigned char in_tq, in_ttl, tq_avg = 0;
- unsigned long send_time;
-
- if (batman_packet->ttl <= 1) {
- bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
- return;
- }
-
- in_tq = batman_packet->tq;
- in_ttl = batman_packet->ttl;
-
- batman_packet->ttl--;
- memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
-
- /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
- * of our best tq value */
- if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
-
- /* rebroadcast ogm of best ranking neighbor as is */
- if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) {
- batman_packet->tq = orig_node->router->tq_avg;
-
- if (orig_node->router->last_ttl)
- batman_packet->ttl = orig_node->router->last_ttl
- - 1;
- }
-
- tq_avg = orig_node->router->tq_avg;
- }
-
- /* apply hop penalty */
- batman_packet->tq = hop_penalty(batman_packet->tq);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: tq_orig: %i, tq_avg: %i, "
- "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
- in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
- batman_packet->ttl);
-
- batman_packet->seqno = htonl(batman_packet->seqno);
-
- /* switch of primaries first hop flag when forwarding */
- batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
- if (directlink)
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
-
- send_time = forward_send_time(bat_priv);
- add_bat_packet_to_list(bat_priv,
- (unsigned char *)batman_packet,
- sizeof(struct batman_packet) + hna_buff_len,
- if_incoming, 0, send_time);
-}
-
-static void forw_packet_free(struct forw_packet *forw_packet)
-{
- if (forw_packet->skb)
- kfree_skb(forw_packet->skb);
- kfree(forw_packet);
-}
-
-static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
- struct forw_packet *forw_packet,
- unsigned long send_time)
-{
- unsigned long flags;
- INIT_HLIST_NODE(&forw_packet->list);
-
- /* add new packet to packet list */
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list);
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- /* start timer for this packet */
- INIT_DELAYED_WORK(&forw_packet->delayed_work,
- send_outstanding_bcast_packet);
- queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
- send_time);
-}
-
-#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
-/* add a broadcast packet to the queue and setup timers. broadcast packets
- * are sent multiple times to increase probability for beeing received.
- *
- * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
- * errors.
- *
- * The skb is not consumed, so the caller should make sure that the
- * skb is freed. */
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
-{
- struct forw_packet *forw_packet;
- struct bcast_packet *bcast_packet;
-
- if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
- bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
- goto out;
- }
-
- if (!bat_priv->primary_if)
- goto out;
-
- forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
-
- if (!forw_packet)
- goto out_and_inc;
-
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb)
- goto packet_free;
-
- /* as we have a copy now, it is safe to decrease the TTL */
- bcast_packet = (struct bcast_packet *)skb->data;
- bcast_packet->ttl--;
-
- skb_reset_mac_header(skb);
-
- forw_packet->skb = skb;
- forw_packet->if_incoming = bat_priv->primary_if;
-
- /* how often did we send the bcast packet ? */
- forw_packet->num_packets = 0;
-
- _add_bcast_packet_to_list(bat_priv, forw_packet, 1);
- return NETDEV_TX_OK;
-
-packet_free:
- kfree(forw_packet);
-out_and_inc:
- atomic_inc(&bat_priv->bcast_queue_left);
-out:
- return NETDEV_TX_BUSY;
-}
-
-static void send_outstanding_bcast_packet(struct work_struct *work)
-{
- struct batman_if *batman_if;
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct forw_packet *forw_packet =
- container_of(delayed_work, struct forw_packet, delayed_work);
- unsigned long flags;
- struct sk_buff *skb1;
- struct net_device *soft_iface = forw_packet->if_incoming->soft_iface;
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
-
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_del(&forw_packet->list);
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
- goto out;
-
- /* rebroadcast packet */
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->soft_iface != soft_iface)
- continue;
-
- /* send a copy of the saved skb */
- skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
- if (skb1)
- send_skb_packet(skb1, batman_if, broadcast_addr);
- }
- rcu_read_unlock();
-
- forw_packet->num_packets++;
-
- /* if we still have some more bcasts to send */
- if (forw_packet->num_packets < 3) {
- _add_bcast_packet_to_list(bat_priv, forw_packet,
- ((5 * HZ) / 1000));
- return;
- }
-
-out:
- forw_packet_free(forw_packet);
- atomic_inc(&bat_priv->bcast_queue_left);
-}
-
-void send_outstanding_bat_packet(struct work_struct *work)
-{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct forw_packet *forw_packet =
- container_of(delayed_work, struct forw_packet, delayed_work);
- unsigned long flags;
- struct bat_priv *bat_priv;
-
- bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
- spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
- hlist_del(&forw_packet->list);
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
-
- if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
- goto out;
-
- send_packet(forw_packet);
-
- /**
- * we have to have at least one packet in the queue
- * to determine the queues wake up time unless we are
- * shutting down
- */
- if (forw_packet->own)
- schedule_own_packet(forw_packet->if_incoming);
-
-out:
- /* don't count own packet */
- if (!forw_packet->own)
- atomic_inc(&bat_priv->batman_queue_left);
-
- forw_packet_free(forw_packet);
-}
-
-void purge_outstanding_packets(struct bat_priv *bat_priv,
- struct batman_if *batman_if)
-{
- struct forw_packet *forw_packet;
- struct hlist_node *tmp_node, *safe_tmp_node;
- unsigned long flags;
-
- if (batman_if)
- bat_dbg(DBG_BATMAN, bat_priv,
- "purge_outstanding_packets(): %s\n",
- batman_if->net_dev->name);
- else
- bat_dbg(DBG_BATMAN, bat_priv,
- "purge_outstanding_packets()\n");
-
- /* free bcast list */
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
- &bat_priv->forw_bcast_list, list) {
-
- /**
- * if purge_outstanding_packets() was called with an argmument
- * we delete only packets belonging to the given interface
- */
- if ((batman_if) &&
- (forw_packet->if_incoming != batman_if))
- continue;
-
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- /**
- * send_outstanding_bcast_packet() will lock the list to
- * delete the item from the list
- */
- cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- }
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- /* free batman packet list */
- spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
- hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
- &bat_priv->forw_bat_list, list) {
-
- /**
- * if purge_outstanding_packets() was called with an argmument
- * we delete only packets belonging to the given interface
- */
- if ((batman_if) &&
- (forw_packet->if_incoming != batman_if))
- continue;
-
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
-
- /**
- * send_outstanding_bat_packet() will lock the list to
- * delete the item from the list
- */
- cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
- }
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
-}
diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h
deleted file mode 100644
index c4cefa8e4f85..000000000000
--- a/drivers/staging/batman-adv/send.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_SEND_H_
-#define _NET_BATMAN_ADV_SEND_H_
-
-#include "types.h"
-
-int send_skb_packet(struct sk_buff *skb,
- struct batman_if *batman_if,
- uint8_t *dst_addr);
-void schedule_own_packet(struct batman_if *batman_if);
-void schedule_forward_packet(struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- uint8_t directlink, int hna_buff_len,
- struct batman_if *if_outgoing);
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
-void send_outstanding_bat_packet(struct work_struct *work);
-void purge_outstanding_packets(struct bat_priv *bat_priv,
- struct batman_if *batman_if);
-
-#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
deleted file mode 100644
index 3904db9ce7b1..000000000000
--- a/drivers/staging/batman-adv/soft-interface.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "soft-interface.h"
-#include "hard-interface.h"
-#include "routing.h"
-#include "send.h"
-#include "bat_debugfs.h"
-#include "translation-table.h"
-#include "types.h"
-#include "hash.h"
-#include "send.h"
-#include "bat_sysfs.h"
-#include <linux/slab.h>
-#include <linux/ethtool.h>
-#include <linux/etherdevice.h>
-#include "unicast.h"
-
-
-static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
-static void bat_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info);
-static u32 bat_get_msglevel(struct net_device *dev);
-static void bat_set_msglevel(struct net_device *dev, u32 value);
-static u32 bat_get_link(struct net_device *dev);
-static u32 bat_get_rx_csum(struct net_device *dev);
-static int bat_set_rx_csum(struct net_device *dev, u32 data);
-
-static const struct ethtool_ops bat_ethtool_ops = {
- .get_settings = bat_get_settings,
- .get_drvinfo = bat_get_drvinfo,
- .get_msglevel = bat_get_msglevel,
- .set_msglevel = bat_set_msglevel,
- .get_link = bat_get_link,
- .get_rx_csum = bat_get_rx_csum,
- .set_rx_csum = bat_set_rx_csum
-};
-
-int my_skb_head_push(struct sk_buff *skb, unsigned int len)
-{
- int result;
-
- /**
- * TODO: We must check if we can release all references to non-payload
- * data using skb_header_release in our skbs to allow skb_cow_header to
- * work optimally. This means that those skbs are not allowed to read
- * or write any data which is before the current position of skb->data
- * after that call and thus allow other skbs with the same data buffer
- * to write freely in that area.
- */
- result = skb_cow_head(skb, len);
- if (result < 0)
- return result;
-
- skb_push(skb, len);
- return 0;
-}
-
-static int interface_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int interface_release(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static struct net_device_stats *interface_stats(struct net_device *dev)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
- return &bat_priv->stats;
-}
-
-static int interface_set_mac_addr(struct net_device *dev, void *p)
-{
- struct bat_priv *bat_priv = netdev_priv(dev);
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- /* only modify hna-table if it has been initialised before */
- if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
- hna_local_remove(bat_priv, dev->dev_addr,
- "mac address changed");
- hna_local_add(dev, addr->sa_data);
- }
-
- memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
-
- return 0;
-}
-
-static int interface_change_mtu(struct net_device *dev, int new_mtu)
-{
- /* check ranges */
- if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
- return -EINVAL;
-
- dev->mtu = new_mtu;
-
- return 0;
-}
-
-int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
-{
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct bcast_packet *bcast_packet;
- int data_len = skb->len, ret;
-
- if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
- goto dropped;
-
- soft_iface->trans_start = jiffies;
-
- /* TODO: check this for locks */
- hna_local_add(soft_iface, ethhdr->h_source);
-
- /* ethernet packet should be broadcasted */
- if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
- if (!bat_priv->primary_if)
- goto dropped;
-
- if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
- goto dropped;
-
- bcast_packet = (struct bcast_packet *)skb->data;
- bcast_packet->version = COMPAT_VERSION;
- bcast_packet->ttl = TTL;
-
- /* batman packet type: broadcast */
- bcast_packet->packet_type = BAT_BCAST;
-
- /* hw address of first interface is the orig mac because only
- * this mac is known throughout the mesh */
- memcpy(bcast_packet->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
-
- /* set broadcast sequence number */
- bcast_packet->seqno =
- htonl(atomic_inc_return(&bat_priv->bcast_seqno));
-
- add_bcast_packet_to_list(bat_priv, skb);
-
- /* a copy is stored in the bcast list, therefore removing
- * the original skb. */
- kfree_skb(skb);
-
- /* unicast packet */
- } else {
- ret = unicast_send_skb(skb, bat_priv);
- if (ret != 0)
- goto dropped_freed;
- }
-
- bat_priv->stats.tx_packets++;
- bat_priv->stats.tx_bytes += data_len;
- goto end;
-
-dropped:
- kfree_skb(skb);
-dropped_freed:
- bat_priv->stats.tx_dropped++;
-end:
- return NETDEV_TX_OK;
-}
-
-void interface_rx(struct net_device *soft_iface,
- struct sk_buff *skb, int hdr_size)
-{
- struct bat_priv *priv = netdev_priv(soft_iface);
-
- /* check if enough space is available for pulling, and pull */
- if (!pskb_may_pull(skb, hdr_size)) {
- kfree_skb(skb);
- return;
- }
- skb_pull_rcsum(skb, hdr_size);
-/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
-
- /* skb->dev & skb->pkt_type are set here */
- skb->protocol = eth_type_trans(skb, soft_iface);
-
- /* should not be neccesary anymore as we use skb_pull_rcsum()
- * TODO: please verify this and remove this TODO
- * -- Dec 21st 2009, Simon Wunderlich */
-
-/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
-
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
-
- soft_iface->last_rx = jiffies;
-
- netif_rx(skb);
-}
-
-#ifdef HAVE_NET_DEVICE_OPS
-static const struct net_device_ops bat_netdev_ops = {
- .ndo_open = interface_open,
- .ndo_stop = interface_release,
- .ndo_get_stats = interface_stats,
- .ndo_set_mac_address = interface_set_mac_addr,
- .ndo_change_mtu = interface_change_mtu,
- .ndo_start_xmit = interface_tx,
- .ndo_validate_addr = eth_validate_addr
-};
-#endif
-
-static void interface_setup(struct net_device *dev)
-{
- struct bat_priv *priv = netdev_priv(dev);
- char dev_addr[ETH_ALEN];
-
- ether_setup(dev);
-
-#ifdef HAVE_NET_DEVICE_OPS
- dev->netdev_ops = &bat_netdev_ops;
-#else
- dev->open = interface_open;
- dev->stop = interface_release;
- dev->get_stats = interface_stats;
- dev->set_mac_address = interface_set_mac_addr;
- dev->change_mtu = interface_change_mtu;
- dev->hard_start_xmit = interface_tx;
-#endif
- dev->destructor = free_netdev;
-
- /**
- * can't call min_mtu, because the needed variables
- * have not been initialized yet
- */
- dev->mtu = ETH_DATA_LEN;
- dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
- * skbuff for our header */
-
- /* generate random address */
- random_ether_addr(dev_addr);
- memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
-
- SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
-
- memset(priv, 0, sizeof(struct bat_priv));
-}
-
-struct net_device *softif_create(char *name)
-{
- struct net_device *soft_iface;
- struct bat_priv *bat_priv;
- int ret;
-
- soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
- interface_setup);
-
- if (!soft_iface) {
- pr_err("Unable to allocate the batman interface: %s\n", name);
- goto out;
- }
-
- ret = register_netdev(soft_iface);
- if (ret < 0) {
- pr_err("Unable to register the batman interface '%s': %i\n",
- name, ret);
- goto free_soft_iface;
- }
-
- bat_priv = netdev_priv(soft_iface);
-
- atomic_set(&bat_priv->aggregation_enabled, 1);
- atomic_set(&bat_priv->bonding_enabled, 0);
- atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
- atomic_set(&bat_priv->orig_interval, 1000);
- atomic_set(&bat_priv->log_level, 0);
- atomic_set(&bat_priv->frag_enabled, 1);
- atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
- atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
-
- atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
- atomic_set(&bat_priv->bcast_seqno, 1);
- atomic_set(&bat_priv->hna_local_changed, 0);
-
- bat_priv->primary_if = NULL;
- bat_priv->num_ifaces = 0;
-
- ret = sysfs_add_meshif(soft_iface);
- if (ret < 0)
- goto unreg_soft_iface;
-
- ret = debugfs_add_meshif(soft_iface);
- if (ret < 0)
- goto unreg_sysfs;
-
- ret = mesh_init(soft_iface);
- if (ret < 0)
- goto unreg_debugfs;
-
- return soft_iface;
-
-unreg_debugfs:
- debugfs_del_meshif(soft_iface);
-unreg_sysfs:
- sysfs_del_meshif(soft_iface);
-unreg_soft_iface:
- unregister_netdev(soft_iface);
- return NULL;
-
-free_soft_iface:
- free_netdev(soft_iface);
-out:
- return NULL;
-}
-
-void softif_destroy(struct net_device *soft_iface)
-{
- debugfs_del_meshif(soft_iface);
- sysfs_del_meshif(soft_iface);
- mesh_free(soft_iface);
- unregister_netdevice(soft_iface);
-}
-
-/* ethtool */
-static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- cmd->supported = 0;
- cmd->advertising = 0;
- cmd->speed = SPEED_10;
- 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 bat_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "B.A.T.M.A.N. advanced");
- strcpy(info->version, SOURCE_VERSION);
- strcpy(info->fw_version, "N/A");
- strcpy(info->bus_info, "batman");
-}
-
-static u32 bat_get_msglevel(struct net_device *dev)
-{
- return -EOPNOTSUPP;
-}
-
-static void bat_set_msglevel(struct net_device *dev, u32 value)
-{
-}
-
-static u32 bat_get_link(struct net_device *dev)
-{
- return 1;
-}
-
-static u32 bat_get_rx_csum(struct net_device *dev)
-{
- return 0;
-}
-
-static int bat_set_rx_csum(struct net_device *dev, u32 data)
-{
- return -EOPNOTSUPP;
-}
diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h
deleted file mode 100644
index 843a7ec082fe..000000000000
--- a/drivers/staging/batman-adv/soft-interface.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_
-#define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
-
-int my_skb_head_push(struct sk_buff *skb, unsigned int len);
-int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
-void interface_rx(struct net_device *soft_iface,
- struct sk_buff *skb, int hdr_size);
-struct net_device *softif_create(char *name);
-void softif_destroy(struct net_device *soft_iface);
-
-#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/drivers/staging/batman-adv/sysfs-class-net-batman-adv b/drivers/staging/batman-adv/sysfs-class-net-batman-adv
deleted file mode 100644
index 38dd762def4b..000000000000
--- a/drivers/staging/batman-adv/sysfs-class-net-batman-adv
+++ /dev/null
@@ -1,14 +0,0 @@
-
-What: /sys/class/net/<iface>/batman-adv/mesh_iface
-Date: May 2010
-Contact: Marek Lindner <lindner_marek@yahoo.de>
-Description:
- The /sys/class/net/<iface>/batman-adv/mesh_iface file
- displays the batman mesh interface this <iface>
- currently is associated with.
-
-What: /sys/class/net/<iface>/batman-adv/iface_status
-Date: May 2010
-Contact: Marek Lindner <lindner_marek@yahoo.de>
-Description:
- Indicates the status of <iface> as it is seen by batman.
diff --git a/drivers/staging/batman-adv/sysfs-class-net-mesh b/drivers/staging/batman-adv/sysfs-class-net-mesh
deleted file mode 100644
index b4cdb6038bf1..000000000000
--- a/drivers/staging/batman-adv/sysfs-class-net-mesh
+++ /dev/null
@@ -1,41 +0,0 @@
-
-What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
-Date: May 2010
-Contact: Marek Lindner <lindner_marek@yahoo.de>
-Description:
- Indicates whether the batman protocol messages of the
- mesh <mesh_iface> shall be aggregated or not.
-
-What: /sys/class/net/<mesh_iface>/mesh/bonding
-Date: June 2010
-Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
-Description:
- Indicates whether the data traffic going through the
- mesh will be sent using multiple interfaces at the
- same time (if available).
-
-What: /sys/class/net/<mesh_iface>/mesh/fragmentation
-Date: October 2010
-Contact: Andreas Langer <an.langer@gmx.de>
-Description:
- Indicates whether the data traffic going through the
- mesh will be fragmented or silently discarded if the
- packet size exceeds the outgoing interface MTU.
-
-What: /sys/class/net/<mesh_iface>/mesh/orig_interval
-Date: May 2010
-Contact: Marek Lindner <lindner_marek@yahoo.de>
-Description:
- Defines the interval in milliseconds in which batman
- sends its protocol messages.
-
-What: /sys/class/net/<mesh_iface>/mesh/vis_mode
-Date: May 2010
-Contact: Marek Lindner <lindner_marek@yahoo.de>
-Description:
- Each batman node only maintains information about its
- own local neighborhood, therefore generating graphs
- showing the topology of the entire mesh is not easily
- feasible without having a central instance to collect
- the local topologies from all nodes. This file allows
- to activate the collecting (server) mode.
diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c
deleted file mode 100644
index 681ccbda3eac..000000000000
--- a/drivers/staging/batman-adv/translation-table.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "translation-table.h"
-#include "soft-interface.h"
-#include "types.h"
-#include "hash.h"
-
-static void hna_local_purge(struct work_struct *work);
-static void _hna_global_del_orig(struct bat_priv *bat_priv,
- struct hna_global_entry *hna_global_entry,
- char *message);
-
-static void hna_local_start_timer(struct bat_priv *bat_priv)
-{
- INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge);
- queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ);
-}
-
-int hna_local_init(struct bat_priv *bat_priv)
-{
- if (bat_priv->hna_local_hash)
- return 1;
-
- bat_priv->hna_local_hash = hash_new(128, compare_orig, choose_orig);
-
- if (!bat_priv->hna_local_hash)
- return 0;
-
- atomic_set(&bat_priv->hna_local_changed, 0);
- hna_local_start_timer(bat_priv);
-
- return 1;
-}
-
-void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
-{
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct hna_local_entry *hna_local_entry;
- struct hna_global_entry *hna_global_entry;
- struct hashtable_t *swaphash;
- unsigned long flags;
- int required_bytes;
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
- hna_local_entry =
- ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash,
- addr));
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
-
- if (hna_local_entry) {
- hna_local_entry->last_seen = jiffies;
- return;
- }
-
- /* only announce as many hosts as possible in the batman-packet and
- space in batman_packet->num_hna That also should give a limit to
- MAC-flooding. */
- required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN;
- required_bytes += BAT_PACKET_LEN;
-
- if ((required_bytes > ETH_DATA_LEN) ||
- (atomic_read(&bat_priv->aggregation_enabled) &&
- required_bytes > MAX_AGGREGATION_BYTES) ||
- (bat_priv->num_local_hna + 1 > 255)) {
- bat_dbg(DBG_ROUTES, bat_priv,
- "Can't add new local hna entry (%pM): "
- "number of local hna entries exceeds packet size\n",
- addr);
- return;
- }
-
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new local hna entry: %pM\n", addr);
-
- hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
- if (!hna_local_entry)
- return;
-
- memcpy(hna_local_entry->addr, addr, ETH_ALEN);
- hna_local_entry->last_seen = jiffies;
-
- /* the batman interface mac address should never be purged */
- if (compare_orig(addr, soft_iface->dev_addr))
- hna_local_entry->never_purge = 1;
- else
- hna_local_entry->never_purge = 0;
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- hash_add(bat_priv->hna_local_hash, hna_local_entry);
- bat_priv->num_local_hna++;
- atomic_set(&bat_priv->hna_local_changed, 1);
-
- if (bat_priv->hna_local_hash->elements * 4 >
- bat_priv->hna_local_hash->size) {
- swaphash = hash_resize(bat_priv->hna_local_hash,
- bat_priv->hna_local_hash->size * 2);
-
- if (!swaphash)
- pr_err("Couldn't resize local hna hash table\n");
- else
- bat_priv->hna_local_hash = swaphash;
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
-
- /* remove address from global hash if present */
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
-
- hna_global_entry = ((struct hna_global_entry *)
- hash_find(bat_priv->hna_global_hash, addr));
-
- if (hna_global_entry)
- _hna_global_del_orig(bat_priv, hna_global_entry,
- "local hna received");
-
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-}
-
-int hna_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len)
-{
- struct hna_local_entry *hna_local_entry;
- HASHIT(hashit);
- int i = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
-
- if (buff_len < (i + 1) * ETH_ALEN)
- break;
-
- hna_local_entry = hashit.bucket->data;
- memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
-
- i++;
- }
-
- /* if we did not get all new local hnas see you next time ;-) */
- if (i == bat_priv->num_local_hna)
- atomic_set(&bat_priv->hna_local_changed, 0);
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
- return i;
-}
-
-int hna_local_seq_print_text(struct seq_file *seq, void *offset)
-{
- struct net_device *net_dev = (struct net_device *)seq->private;
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- struct hna_local_entry *hna_local_entry;
- HASHIT(hashit);
- HASHIT(hashit_count);
- unsigned long flags;
- size_t buf_size, pos;
- char *buff;
-
- if (!bat_priv->primary_if) {
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
- }
-
- seq_printf(seq, "Locally retrieved addresses (from %s) "
- "announced via HNA:\n",
- net_dev->name);
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- buf_size = 1;
- /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
- while (hash_iterate(bat_priv->hna_local_hash, &hashit_count))
- buf_size += 21;
-
- buff = kmalloc(buf_size, GFP_ATOMIC);
- if (!buff) {
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
- return -ENOMEM;
- }
- buff[0] = '\0';
- pos = 0;
-
- while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
- hna_local_entry = hashit.bucket->data;
-
- pos += snprintf(buff + pos, 22, " * %pM\n",
- hna_local_entry->addr);
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
-
- seq_printf(seq, "%s", buff);
- kfree(buff);
- return 0;
-}
-
-static void _hna_local_del(void *data, void *arg)
-{
- struct bat_priv *bat_priv = (struct bat_priv *)arg;
-
- kfree(data);
- bat_priv->num_local_hna--;
- atomic_set(&bat_priv->hna_local_changed, 1);
-}
-
-static void hna_local_del(struct bat_priv *bat_priv,
- struct hna_local_entry *hna_local_entry,
- char *message)
-{
- bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n",
- hna_local_entry->addr, message);
-
- hash_remove(bat_priv->hna_local_hash, hna_local_entry->addr);
- _hna_local_del(hna_local_entry, bat_priv);
-}
-
-void hna_local_remove(struct bat_priv *bat_priv,
- uint8_t *addr, char *message)
-{
- struct hna_local_entry *hna_local_entry;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- hna_local_entry = (struct hna_local_entry *)
- hash_find(bat_priv->hna_local_hash, addr);
- if (hna_local_entry)
- hna_local_del(bat_priv, hna_local_entry, message);
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
-}
-
-static void hna_local_purge(struct work_struct *work)
-{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct bat_priv *bat_priv =
- container_of(delayed_work, struct bat_priv, hna_work);
- struct hna_local_entry *hna_local_entry;
- HASHIT(hashit);
- unsigned long flags;
- unsigned long timeout;
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
- hna_local_entry = hashit.bucket->data;
-
- timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ;
-
- if ((!hna_local_entry->never_purge) &&
- time_after(jiffies, timeout))
- hna_local_del(bat_priv, hna_local_entry,
- "address timed out");
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
- hna_local_start_timer(bat_priv);
-}
-
-void hna_local_free(struct bat_priv *bat_priv)
-{
- if (!bat_priv->hna_local_hash)
- return;
-
- cancel_delayed_work_sync(&bat_priv->hna_work);
- hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv);
- bat_priv->hna_local_hash = NULL;
-}
-
-int hna_global_init(struct bat_priv *bat_priv)
-{
- if (bat_priv->hna_global_hash)
- return 1;
-
- bat_priv->hna_global_hash = hash_new(128, compare_orig, choose_orig);
-
- if (!bat_priv->hna_global_hash)
- return 0;
-
- return 1;
-}
-
-void hna_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- unsigned char *hna_buff, int hna_buff_len)
-{
- struct hna_global_entry *hna_global_entry;
- struct hna_local_entry *hna_local_entry;
- struct hashtable_t *swaphash;
- int hna_buff_count = 0;
- unsigned long flags;
- unsigned char *hna_ptr;
-
- while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
-
- hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
- hna_global_entry = (struct hna_global_entry *)
- hash_find(bat_priv->hna_global_hash, hna_ptr);
-
- if (!hna_global_entry) {
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock,
- flags);
-
- hna_global_entry =
- kmalloc(sizeof(struct hna_global_entry),
- GFP_ATOMIC);
-
- if (!hna_global_entry)
- break;
-
- memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
-
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new global hna entry: "
- "%pM (via %pM)\n",
- hna_global_entry->addr, orig_node->orig);
-
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
- hash_add(bat_priv->hna_global_hash, hna_global_entry);
-
- }
-
- hna_global_entry->orig_node = orig_node;
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-
- /* remove address from local hash if present */
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
-
- hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
- hna_local_entry = (struct hna_local_entry *)
- hash_find(bat_priv->hna_local_hash, hna_ptr);
-
- if (hna_local_entry)
- hna_local_del(bat_priv, hna_local_entry,
- "global hna received");
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
-
- hna_buff_count++;
- }
-
- /* initialize, and overwrite if malloc succeeds */
- orig_node->hna_buff = NULL;
- orig_node->hna_buff_len = 0;
-
- if (hna_buff_len > 0) {
- orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
- if (orig_node->hna_buff) {
- memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
- orig_node->hna_buff_len = hna_buff_len;
- }
- }
-
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
-
- if (bat_priv->hna_global_hash->elements * 4 >
- bat_priv->hna_global_hash->size) {
- swaphash = hash_resize(bat_priv->hna_global_hash,
- bat_priv->hna_global_hash->size * 2);
-
- if (!swaphash)
- pr_err("Couldn't resize global hna hash table\n");
- else
- bat_priv->hna_global_hash = swaphash;
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-}
-
-int hna_global_seq_print_text(struct seq_file *seq, void *offset)
-{
- struct net_device *net_dev = (struct net_device *)seq->private;
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- struct hna_global_entry *hna_global_entry;
- HASHIT(hashit);
- HASHIT(hashit_count);
- unsigned long flags;
- size_t buf_size, pos;
- char *buff;
-
- if (!bat_priv->primary_if) {
- return seq_printf(seq, "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
- }
-
- seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
- net_dev->name);
-
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
-
- buf_size = 1;
- /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
- while (hash_iterate(bat_priv->hna_global_hash, &hashit_count))
- buf_size += 43;
-
- buff = kmalloc(buf_size, GFP_ATOMIC);
- if (!buff) {
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
- return -ENOMEM;
- }
- buff[0] = '\0';
- pos = 0;
-
- while (hash_iterate(bat_priv->hna_global_hash, &hashit)) {
- hna_global_entry = hashit.bucket->data;
-
- pos += snprintf(buff + pos, 44,
- " * %pM via %pM\n", hna_global_entry->addr,
- hna_global_entry->orig_node->orig);
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-
- seq_printf(seq, "%s", buff);
- kfree(buff);
- return 0;
-}
-
-static void _hna_global_del_orig(struct bat_priv *bat_priv,
- struct hna_global_entry *hna_global_entry,
- char *message)
-{
- bat_dbg(DBG_ROUTES, bat_priv,
- "Deleting global hna entry %pM (via %pM): %s\n",
- hna_global_entry->addr, hna_global_entry->orig_node->orig,
- message);
-
- hash_remove(bat_priv->hna_global_hash, hna_global_entry->addr);
- kfree(hna_global_entry);
-}
-
-void hna_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, char *message)
-{
- struct hna_global_entry *hna_global_entry;
- int hna_buff_count = 0;
- unsigned long flags;
- unsigned char *hna_ptr;
-
- if (orig_node->hna_buff_len == 0)
- return;
-
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
-
- while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
- hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
- hna_global_entry = (struct hna_global_entry *)
- hash_find(bat_priv->hna_global_hash, hna_ptr);
-
- if ((hna_global_entry) &&
- (hna_global_entry->orig_node == orig_node))
- _hna_global_del_orig(bat_priv, hna_global_entry,
- message);
-
- hna_buff_count++;
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-
- orig_node->hna_buff_len = 0;
- kfree(orig_node->hna_buff);
- orig_node->hna_buff = NULL;
-}
-
-static void hna_global_del(void *data, void *arg)
-{
- kfree(data);
-}
-
-void hna_global_free(struct bat_priv *bat_priv)
-{
- if (!bat_priv->hna_global_hash)
- return;
-
- hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL);
- bat_priv->hna_global_hash = NULL;
-}
-
-struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
-{
- struct hna_global_entry *hna_global_entry;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
- hna_global_entry = (struct hna_global_entry *)
- hash_find(bat_priv->hna_global_hash, addr);
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
-
- if (!hna_global_entry)
- return NULL;
-
- return hna_global_entry->orig_node;
-}
diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h
deleted file mode 100644
index 10c4c5c319b6..000000000000
--- a/drivers/staging/batman-adv/translation-table.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
-#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
-
-#include "types.h"
-
-int hna_local_init(struct bat_priv *bat_priv);
-void hna_local_add(struct net_device *soft_iface, uint8_t *addr);
-void hna_local_remove(struct bat_priv *bat_priv,
- uint8_t *addr, char *message);
-int hna_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len);
-int hna_local_seq_print_text(struct seq_file *seq, void *offset);
-void hna_local_free(struct bat_priv *bat_priv);
-int hna_global_init(struct bat_priv *bat_priv);
-void hna_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- unsigned char *hna_buff, int hna_buff_len);
-int hna_global_seq_print_text(struct seq_file *seq, void *offset);
-void hna_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, char *message);
-void hna_global_free(struct bat_priv *bat_priv);
-struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr);
-
-#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h
deleted file mode 100644
index f3f7366231e7..000000000000
--- a/drivers/staging/batman-adv/types.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-
-
-#ifndef _NET_BATMAN_ADV_TYPES_H_
-#define _NET_BATMAN_ADV_TYPES_H_
-
-#include "packet.h"
-#include "bitarray.h"
-
-#define BAT_HEADER_LEN (sizeof(struct ethhdr) + \
- ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \
- sizeof(struct unicast_packet) : \
- sizeof(struct bcast_packet))))
-
-
-struct batman_if {
- struct list_head list;
- int16_t if_num;
- char if_status;
- struct net_device *net_dev;
- atomic_t seqno;
- atomic_t frag_seqno;
- unsigned char *packet_buff;
- int packet_len;
- struct kobject *hardif_obj;
- atomic_t refcnt;
- struct packet_type batman_adv_ptype;
- struct net_device *soft_iface;
-};
-
-/**
- * orig_node - structure for orig_list maintaining nodes of mesh
- * @primary_addr: hosts primary interface address
- * @last_valid: when last packet from this node was received
- * @bcast_seqno_reset: time when the broadcast seqno window was reset
- * @batman_seqno_reset: time when the batman seqno window was reset
- * @flags: for now only VIS_SERVER flag
- * @last_real_seqno: last and best known squence number
- * @last_ttl: ttl of last received packet
- * @last_bcast_seqno: last broadcast sequence number received by this host
- *
- * @candidates: how many candidates are available
- * @selected: next bonding candidate
- */
-struct orig_node {
- uint8_t orig[ETH_ALEN];
- uint8_t primary_addr[ETH_ALEN];
- struct neigh_node *router;
- TYPE_OF_WORD *bcast_own;
- uint8_t *bcast_own_sum;
- uint8_t tq_own;
- int tq_asym_penalty;
- unsigned long last_valid;
- unsigned long bcast_seqno_reset;
- unsigned long batman_seqno_reset;
- uint8_t flags;
- unsigned char *hna_buff;
- int16_t hna_buff_len;
- uint32_t last_real_seqno;
- uint8_t last_ttl;
- TYPE_OF_WORD bcast_bits[NUM_WORDS];
- uint32_t last_bcast_seqno;
- struct list_head neigh_list;
- struct list_head frag_list;
- unsigned long last_frag_packet;
- struct {
- uint8_t candidates;
- struct neigh_node *selected;
- } bond;
-};
-
-/**
- * neigh_node
- * @last_valid: when last packet via this neighbor was received
- */
-struct neigh_node {
- struct list_head list;
- uint8_t addr[ETH_ALEN];
- uint8_t real_packet_count;
- uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
- uint8_t tq_index;
- uint8_t tq_avg;
- uint8_t last_ttl;
- struct neigh_node *next_bond_candidate;
- unsigned long last_valid;
- TYPE_OF_WORD real_bits[NUM_WORDS];
- struct orig_node *orig_node;
- struct batman_if *if_incoming;
-};
-
-
-struct bat_priv {
- atomic_t mesh_state;
- struct net_device_stats stats;
- atomic_t aggregation_enabled;
- atomic_t bonding_enabled;
- atomic_t frag_enabled;
- atomic_t vis_mode;
- atomic_t orig_interval;
- atomic_t log_level;
- atomic_t bcast_seqno;
- atomic_t bcast_queue_left;
- atomic_t batman_queue_left;
- char num_ifaces;
- struct debug_log *debug_log;
- struct batman_if *primary_if;
- struct kobject *mesh_obj;
- struct dentry *debug_dir;
- struct hlist_head forw_bat_list;
- struct hlist_head forw_bcast_list;
- struct list_head vis_send_list;
- struct hashtable_t *orig_hash;
- struct hashtable_t *hna_local_hash;
- struct hashtable_t *hna_global_hash;
- struct hashtable_t *vis_hash;
- spinlock_t orig_hash_lock; /* protects orig_hash */
- spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
- spinlock_t forw_bcast_list_lock; /* protects */
- spinlock_t hna_lhash_lock; /* protects hna_local_hash */
- spinlock_t hna_ghash_lock; /* protects hna_global_hash */
- spinlock_t vis_hash_lock; /* protects vis_hash */
- spinlock_t vis_list_lock; /* protects vis_info::recv_list */
- int16_t num_local_hna;
- atomic_t hna_local_changed;
- struct delayed_work hna_work;
- struct delayed_work orig_work;
- struct delayed_work vis_work;
- struct vis_info *my_vis_info;
-};
-
-struct socket_client {
- struct list_head queue_list;
- unsigned int queue_len;
- unsigned char index;
- spinlock_t lock; /* protects queue_list, queue_len, index */
- wait_queue_head_t queue_wait;
- struct bat_priv *bat_priv;
-};
-
-struct socket_packet {
- struct list_head list;
- size_t icmp_len;
- struct icmp_packet_rr icmp_packet;
-};
-
-struct hna_local_entry {
- uint8_t addr[ETH_ALEN];
- unsigned long last_seen;
- char never_purge;
-};
-
-struct hna_global_entry {
- uint8_t addr[ETH_ALEN];
- struct orig_node *orig_node;
-};
-
-/**
- * forw_packet - structure for forw_list maintaining packets to be
- * send/forwarded
- */
-struct forw_packet {
- struct hlist_node list;
- unsigned long send_time;
- uint8_t own;
- struct sk_buff *skb;
- uint16_t packet_len;
- uint32_t direct_link_flags;
- uint8_t num_packets;
- struct delayed_work delayed_work;
- struct batman_if *if_incoming;
-};
-
-/* While scanning for vis-entries of a particular vis-originator
- * this list collects its interfaces to create a subgraph/cluster
- * out of them later
- */
-struct if_list_entry {
- uint8_t addr[ETH_ALEN];
- bool primary;
- struct hlist_node list;
-};
-
-struct debug_log {
- char log_buff[LOG_BUF_LEN];
- unsigned long log_start;
- unsigned long log_end;
- spinlock_t lock; /* protects log_buff, log_start and log_end */
- wait_queue_head_t queue_wait;
-};
-
-struct frag_packet_list_entry {
- struct list_head list;
- uint16_t seqno;
- struct sk_buff *skb;
-};
-
-struct vis_info {
- unsigned long first_seen;
- struct list_head recv_list;
- /* list of server-neighbors we received a vis-packet
- * from. we should not reply to them. */
- struct list_head send_list;
- struct kref refcount;
- struct bat_priv *bat_priv;
- /* this packet might be part of the vis send queue. */
- struct sk_buff *skb_packet;
- /* vis_info may follow here*/
-} __attribute__((packed));
-
-struct vis_info_entry {
- uint8_t src[ETH_ALEN];
- uint8_t dest[ETH_ALEN];
- uint8_t quality; /* quality = 0 means HNA */
-} __attribute__((packed));
-
-struct recvlist_node {
- struct list_head list;
- uint8_t mac[ETH_ALEN];
-};
-
-#endif /* _NET_BATMAN_ADV_TYPES_H_ */
diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c
deleted file mode 100644
index 0dac50d69c03..000000000000
--- a/drivers/staging/batman-adv/unicast.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Andreas Langer
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "unicast.h"
-#include "send.h"
-#include "soft-interface.h"
-#include "hash.h"
-#include "translation-table.h"
-#include "routing.h"
-#include "hard-interface.h"
-
-
-struct sk_buff *merge_frag_packet(struct list_head *head,
- struct frag_packet_list_entry *tfp,
- struct sk_buff *skb)
-{
- struct unicast_frag_packet *up =
- (struct unicast_frag_packet *)skb->data;
- struct sk_buff *tmp_skb;
-
- /* set skb to the first part and tmp_skb to the second part */
- if (up->flags & UNI_FRAG_HEAD) {
- tmp_skb = tfp->skb;
- } else {
- tmp_skb = skb;
- skb = tfp->skb;
- }
-
- skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
- if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) {
- /* free buffered skb, skb will be freed later */
- kfree_skb(tfp->skb);
- return NULL;
- }
-
- /* move free entry to end */
- tfp->skb = NULL;
- tfp->seqno = 0;
- list_move_tail(&tfp->list, head);
-
- memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len);
- kfree_skb(tmp_skb);
- return skb;
-}
-
-void create_frag_entry(struct list_head *head, struct sk_buff *skb)
-{
- struct frag_packet_list_entry *tfp;
- struct unicast_frag_packet *up =
- (struct unicast_frag_packet *)skb->data;
-
- /* free and oldest packets stand at the end */
- tfp = list_entry((head)->prev, typeof(*tfp), list);
- kfree_skb(tfp->skb);
-
- tfp->seqno = ntohs(up->seqno);
- tfp->skb = skb;
- list_move(&tfp->list, head);
- return;
-}
-
-int create_frag_buffer(struct list_head *head)
-{
- int i;
- struct frag_packet_list_entry *tfp;
-
- for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
- tfp = kmalloc(sizeof(struct frag_packet_list_entry),
- GFP_ATOMIC);
- if (!tfp) {
- frag_list_free(head);
- return -ENOMEM;
- }
- tfp->skb = NULL;
- tfp->seqno = 0;
- INIT_LIST_HEAD(&tfp->list);
- list_add(&tfp->list, head);
- }
-
- return 0;
-}
-
-struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
- struct unicast_frag_packet *up)
-{
- struct frag_packet_list_entry *tfp;
- struct unicast_frag_packet *tmp_up = NULL;
- uint16_t search_seqno;
-
- if (up->flags & UNI_FRAG_HEAD)
- search_seqno = ntohs(up->seqno)+1;
- else
- search_seqno = ntohs(up->seqno)-1;
-
- list_for_each_entry(tfp, head, list) {
-
- if (!tfp->skb)
- continue;
-
- if (tfp->seqno == ntohs(up->seqno))
- goto mov_tail;
-
- tmp_up = (struct unicast_frag_packet *)tfp->skb->data;
-
- if (tfp->seqno == search_seqno) {
-
- if ((tmp_up->flags & UNI_FRAG_HEAD) !=
- (up->flags & UNI_FRAG_HEAD))
- return tfp;
- else
- goto mov_tail;
- }
- }
- return NULL;
-
-mov_tail:
- list_move_tail(&tfp->list, head);
- return NULL;
-}
-
-void frag_list_free(struct list_head *head)
-{
- struct frag_packet_list_entry *pf, *tmp_pf;
-
- if (!list_empty(head)) {
-
- list_for_each_entry_safe(pf, tmp_pf, head, list) {
- kfree_skb(pf->skb);
- list_del(&pf->list);
- kfree(pf);
- }
- }
- return;
-}
-
-static int unicast_send_frag_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
- struct batman_if *batman_if, uint8_t dstaddr[],
- struct orig_node *orig_node)
-{
- struct unicast_frag_packet *ucast_frag1, *ucast_frag2;
- int hdr_len = sizeof(struct unicast_frag_packet);
- struct sk_buff *frag_skb;
- int data_len = skb->len;
-
- if (!bat_priv->primary_if)
- goto dropped;
-
- frag_skb = dev_alloc_skb(data_len - (data_len / 2) + hdr_len);
- skb_split(skb, frag_skb, data_len / 2);
-
- if (my_skb_head_push(frag_skb, hdr_len) < 0 ||
- my_skb_head_push(skb, hdr_len) < 0)
- goto drop_frag;
-
- ucast_frag1 = (struct unicast_frag_packet *)skb->data;
- ucast_frag2 = (struct unicast_frag_packet *)frag_skb->data;
-
- ucast_frag1->version = COMPAT_VERSION;
- ucast_frag1->packet_type = BAT_UNICAST_FRAG;
- ucast_frag1->ttl = TTL;
- memcpy(ucast_frag1->orig,
- bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
- memcpy(ucast_frag1->dest, orig_node->orig, ETH_ALEN);
-
- memcpy(ucast_frag2, ucast_frag1, sizeof(struct unicast_frag_packet));
-
- ucast_frag1->flags |= UNI_FRAG_HEAD;
- ucast_frag2->flags &= ~UNI_FRAG_HEAD;
-
- ucast_frag1->seqno = htons((uint16_t)atomic_inc_return(
- &batman_if->frag_seqno));
-
- ucast_frag2->seqno = htons((uint16_t)atomic_inc_return(
- &batman_if->frag_seqno));
-
- send_skb_packet(skb, batman_if, dstaddr);
- send_skb_packet(frag_skb, batman_if, dstaddr);
- return 0;
-
-drop_frag:
- kfree_skb(frag_skb);
-dropped:
- kfree_skb(skb);
- return 1;
-}
-
-int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
-{
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct unicast_packet *unicast_packet;
- struct orig_node *orig_node;
- struct batman_if *batman_if;
- struct neigh_node *router;
- int data_len = skb->len;
- uint8_t dstaddr[6];
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- /* get routing information */
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
- ethhdr->h_dest));
-
- /* check for hna host */
- if (!orig_node)
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
-
- router = find_router(orig_node, NULL);
-
- if (!router)
- goto unlock;
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
-
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- if (batman_if->if_status != IF_ACTIVE)
- goto dropped;
-
- if (atomic_read(&bat_priv->frag_enabled) &&
- data_len + sizeof(struct unicast_packet) > batman_if->net_dev->mtu)
- return unicast_send_frag_skb(skb, bat_priv, batman_if,
- dstaddr, orig_node);
-
- if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
- goto dropped;
-
- unicast_packet = (struct unicast_packet *)skb->data;
-
- unicast_packet->version = COMPAT_VERSION;
- /* batman packet type: unicast */
- unicast_packet->packet_type = BAT_UNICAST;
- /* set unicast ttl */
- unicast_packet->ttl = TTL;
- /* copy the destination for faster routing */
- memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
-
- send_skb_packet(skb, batman_if, dstaddr);
- return 0;
-
-unlock:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-dropped:
- kfree_skb(skb);
- return 1;
-}
diff --git a/drivers/staging/batman-adv/unicast.h b/drivers/staging/batman-adv/unicast.h
deleted file mode 100644
index 797369771900..000000000000
--- a/drivers/staging/batman-adv/unicast.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2010 B.A.T.M.A.N. contributors:
- *
- * Andreas Langer
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_UNICAST_H_
-#define _NET_BATMAN_ADV_UNICAST_H_
-
-#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */
-#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
-
-struct sk_buff *merge_frag_packet(struct list_head *head,
- struct frag_packet_list_entry *tfp,
- struct sk_buff *skb);
-
-void create_frag_entry(struct list_head *head, struct sk_buff *skb);
-int create_frag_buffer(struct list_head *head);
-struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
- struct unicast_frag_packet *up);
-void frag_list_free(struct list_head *head);
-int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
-
-#endif /* _NET_BATMAN_ADV_UNICAST_H_ */
diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c
deleted file mode 100644
index 3d2c1bccf2e6..000000000000
--- a/drivers/staging/batman-adv/vis.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "send.h"
-#include "translation-table.h"
-#include "vis.h"
-#include "soft-interface.h"
-#include "hard-interface.h"
-#include "hash.h"
-
-#define MAX_VIS_PACKET_SIZE 1000
-
-/* Returns the smallest signed integer in two's complement with the sizeof x */
-#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
-
-/* Checks if a sequence number x is a predecessor/successor of y.
- * they handle overflows/underflows and can correctly check for a
- * predecessor/successor unless the variable sequence number has grown by
- * more then 2**(bitwidth(x)-1)-1.
- * This means that for a uint8_t with the maximum value 255, it would think:
- * - when adding nothing - it is neither a predecessor nor a successor
- * - before adding more than 127 to the starting value - it is a predecessor,
- * - when adding 128 - it is neither a predecessor nor a successor,
- * - after adding more than 127 to the starting value - it is a successor */
-#define seq_before(x, y) ({typeof(x) _dummy = (x - y); \
- _dummy > smallest_signed_int(_dummy); })
-#define seq_after(x, y) seq_before(y, x)
-
-static void start_vis_timer(struct bat_priv *bat_priv);
-
-/* free the info */
-static void free_info(struct kref *ref)
-{
- struct vis_info *info = container_of(ref, struct vis_info, refcount);
- struct bat_priv *bat_priv = info->bat_priv;
- struct recvlist_node *entry, *tmp;
- unsigned long flags;
-
- list_del_init(&info->send_list);
- spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
- list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
- list_del(&entry->list);
- kfree(entry);
- }
-
- spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
- kfree_skb(info->skb_packet);
-}
-
-/* Compare two vis packets, used by the hashing algorithm */
-static int vis_info_cmp(void *data1, void *data2)
-{
- struct vis_info *d1, *d2;
- struct vis_packet *p1, *p2;
- d1 = data1;
- d2 = data2;
- p1 = (struct vis_packet *)d1->skb_packet->data;
- p2 = (struct vis_packet *)d2->skb_packet->data;
- return compare_orig(p1->vis_orig, p2->vis_orig);
-}
-
-/* hash function to choose an entry in a hash table of given size */
-/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
-static int vis_info_choose(void *data, int size)
-{
- struct vis_info *vis_info = data;
- struct vis_packet *packet;
- unsigned char *key;
- uint32_t hash = 0;
- size_t i;
-
- packet = (struct vis_packet *)vis_info->skb_packet->data;
- key = packet->vis_orig;
- for (i = 0; i < ETH_ALEN; i++) {
- hash += key[i];
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
-
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
-
- return hash % size;
-}
-
-/* insert interface to the list of interfaces of one originator, if it
- * does not already exist in the list */
-static void vis_data_insert_interface(const uint8_t *interface,
- struct hlist_head *if_list,
- bool primary)
-{
- struct if_list_entry *entry;
- struct hlist_node *pos;
-
- hlist_for_each_entry(entry, pos, if_list, list) {
- if (compare_orig(entry->addr, (void *)interface))
- return;
- }
-
- /* its a new address, add it to the list */
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry)
- return;
- memcpy(entry->addr, interface, ETH_ALEN);
- entry->primary = primary;
- hlist_add_head(&entry->list, if_list);
-}
-
-static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
-{
- struct if_list_entry *entry;
- struct hlist_node *pos;
- size_t len = 0;
-
- hlist_for_each_entry(entry, pos, if_list, list) {
- if (entry->primary)
- len += sprintf(buff + len, "PRIMARY, ");
- else {
- len += sprintf(buff + len, "SEC %pM, ", entry->addr);
- }
- }
-
- return len;
-}
-
-static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
-{
- struct if_list_entry *entry;
- struct hlist_node *pos;
- size_t count = 0;
-
- hlist_for_each_entry(entry, pos, if_list, list) {
- if (entry->primary)
- count += 9;
- else
- count += 23;
- }
-
- return count;
-}
-
-/* read an entry */
-static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
- uint8_t *src, bool primary)
-{
- /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
- if (primary && entry->quality == 0)
- return sprintf(buff, "HNA %pM, ", entry->dest);
- else if (compare_orig(entry->src, src))
- return sprintf(buff, "TQ %pM %d, ", entry->dest,
- entry->quality);
-
- return 0;
-}
-
-int vis_seq_print_text(struct seq_file *seq, void *offset)
-{
- HASHIT(hashit);
- HASHIT(hashit_count);
- struct vis_info *info;
- struct vis_packet *packet;
- struct vis_info_entry *entries;
- struct net_device *net_dev = (struct net_device *)seq->private;
- struct bat_priv *bat_priv = netdev_priv(net_dev);
- HLIST_HEAD(vis_if_list);
- struct if_list_entry *entry;
- struct hlist_node *pos, *n;
- int i;
- unsigned long flags;
- int vis_server = atomic_read(&bat_priv->vis_mode);
- size_t buff_pos, buf_size;
- char *buff;
-
- if ((!bat_priv->primary_if) ||
- (vis_server == VIS_TYPE_CLIENT_UPDATE))
- return 0;
-
- buf_size = 1;
- /* Estimate length */
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- while (hash_iterate(bat_priv->vis_hash, &hashit_count)) {
- info = hashit_count.bucket->data;
- packet = (struct vis_packet *)info->skb_packet->data;
- entries = (struct vis_info_entry *)
- ((char *)packet + sizeof(struct vis_packet));
-
- for (i = 0; i < packet->entries; i++) {
- if (entries[i].quality == 0)
- continue;
- vis_data_insert_interface(entries[i].src, &vis_if_list,
- compare_orig(entries[i].src, packet->vis_orig));
- }
-
- hlist_for_each_entry(entry, pos, &vis_if_list, list) {
- buf_size += 18 + 26 * packet->entries;
-
- /* add primary/secondary records */
- if (compare_orig(entry->addr, packet->vis_orig))
- buf_size +=
- vis_data_count_prim_sec(&vis_if_list);
-
- buf_size += 1;
- }
-
- hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
- hlist_del(&entry->list);
- kfree(entry);
- }
- }
-
- buff = kmalloc(buf_size, GFP_ATOMIC);
- if (!buff) {
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
- return -ENOMEM;
- }
- buff[0] = '\0';
- buff_pos = 0;
-
- while (hash_iterate(bat_priv->vis_hash, &hashit)) {
- info = hashit.bucket->data;
- packet = (struct vis_packet *)info->skb_packet->data;
- entries = (struct vis_info_entry *)
- ((char *)packet + sizeof(struct vis_packet));
-
- for (i = 0; i < packet->entries; i++) {
- if (entries[i].quality == 0)
- continue;
- vis_data_insert_interface(entries[i].src, &vis_if_list,
- compare_orig(entries[i].src, packet->vis_orig));
- }
-
- hlist_for_each_entry(entry, pos, &vis_if_list, list) {
- buff_pos += sprintf(buff + buff_pos, "%pM,",
- entry->addr);
-
- for (i = 0; i < packet->entries; i++)
- buff_pos += vis_data_read_entry(buff + buff_pos,
- &entries[i],
- entry->addr,
- entry->primary);
-
- /* add primary/secondary records */
- if (compare_orig(entry->addr, packet->vis_orig))
- buff_pos +=
- vis_data_read_prim_sec(buff + buff_pos,
- &vis_if_list);
-
- buff_pos += sprintf(buff + buff_pos, "\n");
- }
-
- hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
- hlist_del(&entry->list);
- kfree(entry);
- }
- }
-
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
-
- seq_printf(seq, "%s", buff);
- kfree(buff);
-
- return 0;
-}
-
-/* add the info packet to the send list, if it was not
- * already linked in. */
-static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info)
-{
- if (list_empty(&info->send_list)) {
- kref_get(&info->refcount);
- list_add_tail(&info->send_list, &bat_priv->vis_send_list);
- }
-}
-
-/* delete the info packet from the send list, if it was
- * linked in. */
-static void send_list_del(struct vis_info *info)
-{
- if (!list_empty(&info->send_list)) {
- list_del_init(&info->send_list);
- kref_put(&info->refcount, free_info);
- }
-}
-
-/* tries to add one entry to the receive list. */
-static void recv_list_add(struct bat_priv *bat_priv,
- struct list_head *recv_list, char *mac)
-{
- struct recvlist_node *entry;
- unsigned long flags;
-
- entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
- if (!entry)
- return;
-
- memcpy(entry->mac, mac, ETH_ALEN);
- spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
- list_add_tail(&entry->list, recv_list);
- spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
-}
-
-/* returns 1 if this mac is in the recv_list */
-static int recv_list_is_in(struct bat_priv *bat_priv,
- struct list_head *recv_list, char *mac)
-{
- struct recvlist_node *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->vis_list_lock, flags);
- list_for_each_entry(entry, recv_list, list) {
- if (memcmp(entry->mac, mac, ETH_ALEN) == 0) {
- spin_unlock_irqrestore(&bat_priv->vis_list_lock,
- flags);
- return 1;
- }
- }
- spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags);
- return 0;
-}
-
-/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
- * broken.. ). vis hash must be locked outside. is_new is set when the packet
- * is newer than old entries in the hash. */
-static struct vis_info *add_packet(struct bat_priv *bat_priv,
- struct vis_packet *vis_packet,
- int vis_info_len, int *is_new,
- int make_broadcast)
-{
- struct vis_info *info, *old_info;
- struct vis_packet *search_packet, *old_packet;
- struct vis_info search_elem;
- struct vis_packet *packet;
-
- *is_new = 0;
- /* sanity check */
- if (!bat_priv->vis_hash)
- return NULL;
-
- /* see if the packet is already in vis_hash */
- search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet));
- if (!search_elem.skb_packet)
- return NULL;
- search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet,
- sizeof(struct vis_packet));
-
- memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
- old_info = hash_find(bat_priv->vis_hash, &search_elem);
- kfree_skb(search_elem.skb_packet);
-
- if (old_info != NULL) {
- old_packet = (struct vis_packet *)old_info->skb_packet->data;
- if (!seq_after(ntohl(vis_packet->seqno),
- ntohl(old_packet->seqno))) {
- if (old_packet->seqno == vis_packet->seqno) {
- recv_list_add(bat_priv, &old_info->recv_list,
- vis_packet->sender_orig);
- return old_info;
- } else {
- /* newer packet is already in hash. */
- return NULL;
- }
- }
- /* remove old entry */
- hash_remove(bat_priv->vis_hash, old_info);
- send_list_del(old_info);
- kref_put(&old_info->refcount, free_info);
- }
-
- info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC);
- if (!info)
- return NULL;
-
- info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) +
- vis_info_len + sizeof(struct ethhdr));
- if (!info->skb_packet) {
- kfree(info);
- return NULL;
- }
- skb_reserve(info->skb_packet, sizeof(struct ethhdr));
- packet = (struct vis_packet *)skb_put(info->skb_packet,
- sizeof(struct vis_packet) +
- vis_info_len);
-
- kref_init(&info->refcount);
- INIT_LIST_HEAD(&info->send_list);
- INIT_LIST_HEAD(&info->recv_list);
- info->first_seen = jiffies;
- info->bat_priv = bat_priv;
- memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len);
-
- /* initialize and add new packet. */
- *is_new = 1;
-
- /* Make it a broadcast packet, if required */
- if (make_broadcast)
- memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
-
- /* repair if entries is longer than packet. */
- if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len)
- packet->entries = vis_info_len / sizeof(struct vis_info_entry);
-
- recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
-
- /* try to add it */
- if (hash_add(bat_priv->vis_hash, info) < 0) {
- /* did not work (for some reason) */
- kref_put(&old_info->refcount, free_info);
- info = NULL;
- }
-
- return info;
-}
-
-/* handle the server sync packet, forward if needed. */
-void receive_server_sync_packet(struct bat_priv *bat_priv,
- struct vis_packet *vis_packet,
- int vis_info_len)
-{
- struct vis_info *info;
- int is_new, make_broadcast;
- unsigned long flags;
- int vis_server = atomic_read(&bat_priv->vis_mode);
-
- make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC);
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- info = add_packet(bat_priv, vis_packet, vis_info_len,
- &is_new, make_broadcast);
- if (!info)
- goto end;
-
- /* only if we are server ourselves and packet is newer than the one in
- * hash.*/
- if (vis_server == VIS_TYPE_SERVER_SYNC && is_new)
- send_list_add(bat_priv, info);
-end:
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
-}
-
-/* handle an incoming client update packet and schedule forward if needed. */
-void receive_client_update_packet(struct bat_priv *bat_priv,
- struct vis_packet *vis_packet,
- int vis_info_len)
-{
- struct vis_info *info;
- struct vis_packet *packet;
- int is_new;
- unsigned long flags;
- int vis_server = atomic_read(&bat_priv->vis_mode);
- int are_target = 0;
-
- /* clients shall not broadcast. */
- if (is_bcast(vis_packet->target_orig))
- return;
-
- /* Are we the target for this VIS packet? */
- if (vis_server == VIS_TYPE_SERVER_SYNC &&
- is_my_mac(vis_packet->target_orig))
- are_target = 1;
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- info = add_packet(bat_priv, vis_packet, vis_info_len,
- &is_new, are_target);
-
- if (!info)
- goto end;
- /* note that outdated packets will be dropped at this point. */
-
- packet = (struct vis_packet *)info->skb_packet->data;
-
- /* send only if we're the target server or ... */
- if (are_target && is_new) {
- packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */
- send_list_add(bat_priv, info);
-
- /* ... we're not the recipient (and thus need to forward). */
- } else if (!is_my_mac(packet->target_orig)) {
- send_list_add(bat_priv, info);
- }
-
-end:
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
-}
-
-/* Walk the originators and find the VIS server with the best tq. Set the packet
- * address to its address and return the best_tq.
- *
- * Must be called with the originator hash locked */
-static int find_best_vis_server(struct bat_priv *bat_priv,
- struct vis_info *info)
-{
- HASHIT(hashit);
- struct orig_node *orig_node;
- struct vis_packet *packet;
- int best_tq = -1;
-
- packet = (struct vis_packet *)info->skb_packet->data;
-
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
- if ((orig_node) && (orig_node->router) &&
- (orig_node->flags & VIS_SERVER) &&
- (orig_node->router->tq_avg > best_tq)) {
- best_tq = orig_node->router->tq_avg;
- memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
- }
- }
- return best_tq;
-}
-
-/* Return true if the vis packet is full. */
-static bool vis_packet_full(struct vis_info *info)
-{
- struct vis_packet *packet;
- packet = (struct vis_packet *)info->skb_packet->data;
-
- if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry)
- < packet->entries + 1)
- return true;
- return false;
-}
-
-/* generates a packet of own vis data,
- * returns 0 on success, -1 if no packet could be generated */
-static int generate_vis_packet(struct bat_priv *bat_priv)
-{
- HASHIT(hashit_local);
- HASHIT(hashit_global);
- struct orig_node *orig_node;
- struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
- struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
- struct vis_info_entry *entry;
- struct hna_local_entry *hna_local_entry;
- int best_tq = -1;
- unsigned long flags;
-
- info->first_seen = jiffies;
- packet->vis_type = atomic_read(&bat_priv->vis_mode);
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
- packet->ttl = TTL;
- packet->seqno = htonl(ntohl(packet->seqno) + 1);
- packet->entries = 0;
- skb_trim(info->skb_packet, sizeof(struct vis_packet));
-
- if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) {
- best_tq = find_best_vis_server(bat_priv, info);
-
- if (best_tq < 0) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
- flags);
- return -1;
- }
- }
-
- while (hash_iterate(bat_priv->orig_hash, &hashit_global)) {
- orig_node = hashit_global.bucket->data;
-
- if (!orig_node->router)
- continue;
-
- if (!compare_orig(orig_node->router->addr, orig_node->orig))
- continue;
-
- if (orig_node->router->if_incoming->if_status != IF_ACTIVE)
- continue;
-
- if (orig_node->router->tq_avg < 1)
- continue;
-
- /* fill one entry into buffer. */
- entry = (struct vis_info_entry *)
- skb_put(info->skb_packet, sizeof(*entry));
- memcpy(entry->src,
- orig_node->router->if_incoming->net_dev->dev_addr,
- ETH_ALEN);
- memcpy(entry->dest, orig_node->orig, ETH_ALEN);
- entry->quality = orig_node->router->tq_avg;
- packet->entries++;
-
- if (vis_packet_full(info)) {
- spin_unlock_irqrestore(
- &bat_priv->orig_hash_lock, flags);
- return 0;
- }
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
- while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) {
- hna_local_entry = hashit_local.bucket->data;
- entry = (struct vis_info_entry *)skb_put(info->skb_packet,
- sizeof(*entry));
- memset(entry->src, 0, ETH_ALEN);
- memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
- entry->quality = 0; /* 0 means HNA */
- packet->entries++;
-
- if (vis_packet_full(info)) {
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock,
- flags);
- return 0;
- }
- }
-
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
- return 0;
-}
-
-/* free old vis packets. Must be called with this vis_hash_lock
- * held */
-static void purge_vis_packets(struct bat_priv *bat_priv)
-{
- HASHIT(hashit);
- struct vis_info *info;
-
- while (hash_iterate(bat_priv->vis_hash, &hashit)) {
- info = hashit.bucket->data;
-
- /* never purge own data. */
- if (info == bat_priv->my_vis_info)
- continue;
-
- if (time_after(jiffies,
- info->first_seen + VIS_TIMEOUT * HZ)) {
- hash_remove_bucket(bat_priv->vis_hash, &hashit);
- send_list_del(info);
- kref_put(&info->refcount, free_info);
- }
- }
-}
-
-static void broadcast_vis_packet(struct bat_priv *bat_priv,
- struct vis_info *info)
-{
- HASHIT(hashit);
- struct orig_node *orig_node;
- struct vis_packet *packet;
- struct sk_buff *skb;
- unsigned long flags;
- struct batman_if *batman_if;
- uint8_t dstaddr[ETH_ALEN];
-
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- packet = (struct vis_packet *)info->skb_packet->data;
-
- /* send to all routers in range. */
- while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
-
- /* if it's a vis server and reachable, send it. */
- if ((!orig_node) || (!orig_node->router))
- continue;
- if (!(orig_node->flags & VIS_SERVER))
- continue;
- /* don't send it if we already received the packet from
- * this node. */
- if (recv_list_is_in(bat_priv, &info->recv_list,
- orig_node->orig))
- continue;
-
- memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- skb = skb_clone(info->skb_packet, GFP_ATOMIC);
- if (skb)
- send_skb_packet(skb, batman_if, dstaddr);
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
-
- }
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-}
-
-static void unicast_vis_packet(struct bat_priv *bat_priv,
- struct vis_info *info)
-{
- struct orig_node *orig_node;
- struct sk_buff *skb;
- struct vis_packet *packet;
- unsigned long flags;
- struct batman_if *batman_if;
- uint8_t dstaddr[ETH_ALEN];
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- packet = (struct vis_packet *)info->skb_packet->data;
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
- packet->target_orig));
-
- if ((!orig_node) || (!orig_node->router))
- goto out;
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-
- skb = skb_clone(info->skb_packet, GFP_ATOMIC);
- if (skb)
- send_skb_packet(skb, batman_if, dstaddr);
-
- return;
-
-out:
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
-}
-
-/* only send one vis packet. called from send_vis_packets() */
-static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
-{
- struct vis_packet *packet;
-
- packet = (struct vis_packet *)info->skb_packet->data;
- if (packet->ttl < 2) {
- pr_debug("Error - can't send vis packet: ttl exceeded\n");
- return;
- }
-
- memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr,
- ETH_ALEN);
- packet->ttl--;
-
- if (is_bcast(packet->target_orig))
- broadcast_vis_packet(bat_priv, info);
- else
- unicast_vis_packet(bat_priv, info);
- packet->ttl++; /* restore TTL */
-}
-
-/* called from timer; send (and maybe generate) vis packet. */
-static void send_vis_packets(struct work_struct *work)
-{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct bat_priv *bat_priv =
- container_of(delayed_work, struct bat_priv, vis_work);
- struct vis_info *info, *temp;
- unsigned long flags;
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- purge_vis_packets(bat_priv);
-
- if (generate_vis_packet(bat_priv) == 0) {
- /* schedule if generation was successful */
- send_list_add(bat_priv, bat_priv->my_vis_info);
- }
-
- list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list,
- send_list) {
-
- kref_get(&info->refcount);
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
-
- if (bat_priv->primary_if)
- send_vis_packet(bat_priv, info);
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- send_list_del(info);
- kref_put(&info->refcount, free_info);
- }
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
- start_vis_timer(bat_priv);
-}
-
-/* init the vis server. this may only be called when if_list is already
- * initialized (e.g. bat0 is initialized, interfaces have been added) */
-int vis_init(struct bat_priv *bat_priv)
-{
- struct vis_packet *packet;
- unsigned long flags;
-
- if (bat_priv->vis_hash)
- return 1;
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
-
- bat_priv->vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
- if (!bat_priv->vis_hash) {
- pr_err("Can't initialize vis_hash\n");
- goto err;
- }
-
- bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
- if (!bat_priv->my_vis_info) {
- pr_err("Can't initialize vis packet\n");
- goto err;
- }
-
- bat_priv->my_vis_info->skb_packet = dev_alloc_skb(
- sizeof(struct vis_packet) +
- MAX_VIS_PACKET_SIZE +
- sizeof(struct ethhdr));
- if (!bat_priv->my_vis_info->skb_packet)
- goto free_info;
-
- skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
- packet = (struct vis_packet *)skb_put(
- bat_priv->my_vis_info->skb_packet,
- sizeof(struct vis_packet));
-
- /* prefill the vis info */
- bat_priv->my_vis_info->first_seen = jiffies -
- msecs_to_jiffies(VIS_INTERVAL);
- INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list);
- INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list);
- kref_init(&bat_priv->my_vis_info->refcount);
- bat_priv->my_vis_info->bat_priv = bat_priv;
- packet->version = COMPAT_VERSION;
- packet->packet_type = BAT_VIS;
- packet->ttl = TTL;
- packet->seqno = 0;
- packet->entries = 0;
-
- INIT_LIST_HEAD(&bat_priv->vis_send_list);
-
- if (hash_add(bat_priv->vis_hash, bat_priv->my_vis_info) < 0) {
- pr_err("Can't add own vis packet into hash\n");
- /* not in hash, need to remove it manually. */
- kref_put(&bat_priv->my_vis_info->refcount, free_info);
- goto err;
- }
-
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
- start_vis_timer(bat_priv);
- return 1;
-
-free_info:
- kfree(bat_priv->my_vis_info);
- bat_priv->my_vis_info = NULL;
-err:
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
- vis_quit(bat_priv);
- return 0;
-}
-
-/* Decrease the reference count on a hash item info */
-static void free_info_ref(void *data, void *arg)
-{
- struct vis_info *info = data;
-
- send_list_del(info);
- kref_put(&info->refcount, free_info);
-}
-
-/* shutdown vis-server */
-void vis_quit(struct bat_priv *bat_priv)
-{
- unsigned long flags;
- if (!bat_priv->vis_hash)
- return;
-
- cancel_delayed_work_sync(&bat_priv->vis_work);
-
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
- /* properly remove, kill timers ... */
- hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
- bat_priv->vis_hash = NULL;
- bat_priv->my_vis_info = NULL;
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags);
-}
-
-/* schedule packets for (re)transmission */
-static void start_vis_timer(struct bat_priv *bat_priv)
-{
- INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets);
- queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work,
- msecs_to_jiffies(VIS_INTERVAL));
-}
diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h
deleted file mode 100644
index 2c3b33089a9b..000000000000
--- a/drivers/staging/batman-adv/vis.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors:
- *
- * Simon Wunderlich, Marek Lindner
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_VIS_H_
-#define _NET_BATMAN_ADV_VIS_H_
-
-#define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */
-
-int vis_seq_print_text(struct seq_file *seq, void *offset);
-void receive_server_sync_packet(struct bat_priv *bat_priv,
- struct vis_packet *vis_packet,
- int vis_info_len);
-void receive_client_update_packet(struct bat_priv *bat_priv,
- struct vis_packet *vis_packet,
- int vis_info_len);
-int vis_init(struct bat_priv *bat_priv);
-void vis_quit(struct bat_priv *bat_priv);
-
-#endif /* _NET_BATMAN_ADV_VIS_H_ */
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index 748460e898d8..32909e2938d5 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -7,53 +7,6 @@
#define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
#include "Debug.h"
-typedef struct _LIST_ENTRY{
- struct _LIST_ENTRY *next;
- struct _LIST_ENTRY *prev;
-} LIST_ENTRY, *PLIST_ENTRY;
-
-typedef struct _BCM_LIST_ENTRY {
-
- LIST_ENTRY Link;
-
-} BCM_LIST_ENTRY, *PBCM_LIST_ENTRY;
-
-typedef enum _RCB_STATUS
-{
- DRIVER_PROCESSED=1,
- APPLICATION_PROCESSED
-} RCB_STATUS, *PRCB_STATUS;
-
-#define fFILLED 1
-#define fEMPTY 0
-
-struct _BCM_CB
-{
- // The network packet that this RCB is receiving
- PVOID pv_packet;
- // Describes the length of the packet .
- UINT ui_packet_length;
- // Pointer to the first buffer in the packet (only one buffer for Rx)
- PUCHAR buffer;
- atomic_t status;
- UINT filled;
-} __attribute__((packed));
-typedef struct _BCM_CB BCM_CB,*PBCM_CB;
-
-typedef BCM_CB BCM_RCB, *PBCM_RCB;
-typedef BCM_CB BCM_TCB, *PBCM_TCB;
-
-/* This is to be stored in the "pvOsDepData" of ADAPTER */
-typedef struct LINUX_DEP_DATA
-{
- struct net_device *virtualdev; /* Our Interface (veth0) */
- struct net_device *actualdev; /* True Interface (eth0) */
- struct net_device_stats netstats; /* Net statistics */
- struct fasync_struct *async_queue; /* For asynchronus notification */
-
-} LINUX_DEP_DATA, *PLINUX_DEP_DATA;
-
-
struct _LEADER
{
USHORT Vcid;
@@ -429,26 +382,28 @@ Driver adapter data structure
struct _MINI_ADAPTER
{
struct _MINI_ADAPTER *next;
- PVOID pvOsDepData;
+ struct net_device *dev;
+ u32 msg_enable;
+
CHAR *caDsxReqResp;
- atomic_t ApplicationRunning;
+ atomic_t ApplicationRunning;
volatile INT CtrlQueueLen;
- atomic_t AppCtrlQueueLen;
- BOOLEAN AppCtrlQueueOverFlow;
- atomic_t CurrentApplicationCount;
- atomic_t RegisteredApplicationCount;
- BOOLEAN TimerActive;
- ULONG StatisticsPointer;
+ atomic_t AppCtrlQueueLen;
+ BOOLEAN AppCtrlQueueOverFlow;
+ atomic_t CurrentApplicationCount;
+ atomic_t RegisteredApplicationCount;
+ BOOLEAN LinkUpStatus;
+ BOOLEAN TimerActive;
+ u32 StatisticsPointer;
struct sk_buff *RxControlHead;
struct sk_buff *RxControlTail;
-// spinlock_t RxControlQueuelock;
+
struct semaphore RxAppControlQueuelock;
struct semaphore fw_download_sema;
PPER_TARANG_DATA pTarangs;
spinlock_t control_queue_lock;
wait_queue_head_t process_read_wait_queue;
- ULONG bcm_jiffies; /* Store Jiffies value */
// the pointer to the first packet we have queued in send
// deserialized miniport support variables
@@ -458,24 +413,15 @@ struct _MINI_ADAPTER
// this to keep track of the Tx and Rx MailBox Registers.
atomic_t CurrNumFreeTxDesc;
// to keep track the no of byte recieved
- atomic_t RxRollOverCount;
USHORT PrevNumRecvDescs;
USHORT CurrNumRecvDescs;
- atomic_t GoodRxByteCount;
- atomic_t GoodRxPktCount;
- atomic_t BadRxByteCount;
- atomic_t RxPacketDroppedCount;
- atomic_t GoodTxByteCount;
- atomic_t TxTotalPacketCount;
- atomic_t TxDroppedPacketCount;
- ULONG LinkUpStatus;
- BOOLEAN TransferMode;
UINT u32TotalDSD;
PacketInfo PackInfo[NO_OF_QUEUES];
S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS];
+ BOOLEAN TransferMode;
/*************** qos ******************/
- UINT bETHCSEnabled;
+ BOOLEAN bETHCSEnabled;
ULONG BEBucketSize;
ULONG rtPSBucketSize;
@@ -483,7 +429,6 @@ struct _MINI_ADAPTER
BOOLEAN AutoLinkUp;
BOOLEAN AutoSyncup;
- struct net_device *dev;
int major;
int minor;
wait_queue_head_t tx_packet_wait_queue;
@@ -491,8 +436,6 @@ struct _MINI_ADAPTER
atomic_t process_waiting;
BOOLEAN fw_download_done;
- unsigned int ctrlpkt_present;
- BOOLEAN packets_given_to_all;
char *txctlpacket[MAX_CNTRL_PKTS];
atomic_t cntrlpktCnt ;
atomic_t index_app_read_cntrlpkt;
@@ -502,34 +445,30 @@ struct _MINI_ADAPTER
struct semaphore rdmwrmsync;
STTARGETDSXBUFFER astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
- ULONG ulFreeTargetBufferCnt;
+ ULONG ulFreeTargetBufferCnt;
ULONG ulCurrentTargetBuffer;
ULONG ulTotalTargetBuffersAvailable;
- unsigned int timeout;
- int irq;
+
unsigned long chip_id;
- unsigned int bFlashBoot;
- unsigned int if_up;
-// spinlock_t sleeper_lock;
- atomic_t rdm_wrm_access;
- atomic_t tx_rx_access;
+
wait_queue_head_t lowpower_mode_wait_queue;
- atomic_t bAbortedByHost;
- BOOLEAN bBinDownloaded;
- BOOLEAN bCfgDownloaded;
- USHORT usBestEffortQueueIndex;
- BOOLEAN bSyncUpRequestSent;
-// struct semaphore data_packet_queue_lock;
+
+ BOOLEAN bFlashBoot;
+ BOOLEAN bBinDownloaded;
+ BOOLEAN bCfgDownloaded;
+ BOOLEAN bSyncUpRequestSent;
+ USHORT usBestEffortQueueIndex;
+
wait_queue_head_t ioctl_fw_dnld_wait_queue;
BOOLEAN waiting_to_fw_download_done;
pid_t fw_download_process_pid;
PSTARGETPARAMS pstargetparams;
BOOLEAN device_removed;
BOOLEAN DeviceAccess;
- INT DDRSetting;
+ BOOLEAN bIsAutoCorrectEnabled;
BOOLEAN bDDRInitDone;
+ INT DDRSetting;
ULONG ulPowerSaveMode;
- BOOLEAN bIsAutoCorrectEnabled;
spinlock_t txtransmitlock;
B_UINT8 txtransmit_running;
/* Thread for control packet handling */
@@ -567,13 +506,13 @@ struct _MINI_ADAPTER
unsigned int usIdleModePattern;
//BOOLEAN bTriedToWakeUpFromShutdown;
BOOLEAN bLinkDownRequested;
- unsigned int check_for_hang;
+
int downloadDDR;
PHS_DEVICE_EXTENSION stBCMPhsContext;
S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
uint8_t ucaPHSPktRestoreBuf[2048];
uint8_t bPHSEnabled;
- int AutoFirmDld;
+ BOOLEAN AutoFirmDld;
BOOLEAN bMipsConfig;
BOOLEAN bDPLLConfig;
UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
@@ -599,10 +538,9 @@ struct _MINI_ADAPTER
struct semaphore NVMRdmWrmLock;
- BOOLEAN bNetworkInterfaceRegistered;
- BOOLEAN bNetdeviceNotifierRegistered;
+
struct device *pstCreatedClassDevice;
- BOOLEAN bUsbClassDriverRegistered;
+
// BOOLEAN InterfaceUpStatus;
PFLASH2X_CS_INFO psFlash2xCSInfo;
PFLASH_CS_INFO psFlashCSInfo ;
@@ -630,17 +568,13 @@ struct _MINI_ADAPTER
struct semaphore LowPowerModeSync;
ULONG liDrainCalculated;
UINT gpioBitMap;
+
S_BCM_DEBUG_STATE stDebugState;
};
typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
-
-typedef struct _DEVICE_EXTENSION
-{
- PMINI_ADAPTER pAdapt;
-}DEVICE_EXTENSION,*PDEVICE_EXTENSION;
-
+#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
struct _ETH_HEADER_STRUC {
UCHAR au8DestinationAddress[6];
@@ -667,8 +601,8 @@ typedef LINK_REQUEST CONTROL_MESSAGE;
typedef struct _DDR_SETTING
{
- ULONG ulRegAddress;
- ULONG ulRegValue;
+ UINT ulRegAddress;
+ UINT ulRegValue;
}DDR_SETTING, *PDDR_SETTING;
typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE;
INT
diff --git a/drivers/staging/bcm/Arp.c b/drivers/staging/bcm/Arp.c
deleted file mode 100644
index d60d8593d2ef..000000000000
--- a/drivers/staging/bcm/Arp.c
+++ /dev/null
@@ -1,94 +0,0 @@
-
-/*
- * File Name: Arp.c
- * Abstract: This file contains the routines for handling ARP PACKETS
- */
-#include "headers.h"
-#define ARP_PKT_SIZE 60
-
-/* =========================================================================
- * Function - reply_to_arp_request()
- *
- * Description - When this host tries to broadcast ARP request packet through
- * the virtual interface (veth0), reply directly to upper layer.
- * This function allocates a new skb for ARP reply packet,
- * fills in the fields of the packet and then sends it to
- * upper layer.
- *
- * Parameters - skb: Pointer to sk_buff structure of the ARP request pkt.
- *
- * Returns - None
- * =========================================================================*/
-
-VOID
-reply_to_arp_request(struct sk_buff *skb)
-{
- PMINI_ADAPTER Adapter;
- struct ArpHeader *pArpHdr = NULL;
- struct ethhdr *pethhdr = NULL;
- UCHAR uiIPHdr[4];
- /* Check for valid skb */
- if(skb == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid skb: Cannot reply to ARP request\n");
- return;
- }
-
-
- Adapter = GET_BCM_ADAPTER(skb->dev);
- /* Print the ARP Request Packet */
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP Packet Dump :");
- BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len);
-
- /*
- * Extract the Ethernet Header and Arp Payload including Header
- */
- pethhdr = (struct ethhdr *)skb->data;
- pArpHdr = (struct ArpHeader *)(skb->data+ETH_HLEN);
-
- if(Adapter->bETHCSEnabled)
- {
- if(memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN))
- {
- bcm_kfree_skb(skb);
- return;
- }
- }
-
- // Set the Ethernet Header First.
- memcpy(pethhdr->h_dest, pethhdr->h_source, ETH_ALEN);
- if(!memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN))
- {
- pethhdr->h_source[5]++;
- }
-
- /* Set the reply to ARP Reply */
- pArpHdr->arp.ar_op = ntohs(ARPOP_REPLY);
-
- /* Set the HW Address properly */
- memcpy(pArpHdr->ar_sha, pethhdr->h_source, ETH_ALEN);
- memcpy(pArpHdr->ar_tha, pethhdr->h_dest, ETH_ALEN);
-
- // Swapping the IP Adddress
- memcpy(uiIPHdr,pArpHdr->ar_sip,4);
- memcpy(pArpHdr->ar_sip,pArpHdr->ar_tip,4);
- memcpy(pArpHdr->ar_tip,uiIPHdr,4);
-
- /* Print the ARP Reply Packet */
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP REPLY PACKET: ");
-
- /* Send the Packet to upper layer */
- BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len);
-
- skb->protocol = eth_type_trans(skb,skb->dev);
- skb->pkt_type = PACKET_HOST;
-
-// skb->mac.raw=skb->data+LEADER_SIZE;
- skb_set_mac_header (skb, LEADER_SIZE);
- netif_rx(skb);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "<=============\n");
- return;
-}
-
-
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index 77fdfe24d999..31674ea1cd48 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -12,7 +12,7 @@
*
* Returns - Zero(Success)
****************************************************************/
-static struct class *bcm_class = NULL;
+
static int bcm_char_open(struct inode *inode, struct file * filp)
{
PMINI_ADAPTER Adapter = NULL;
@@ -93,7 +93,7 @@ static int bcm_char_release(struct inode *inode, struct file *filp)
/*Stop Queuing the control response Packets*/
atomic_dec(&Adapter->ApplicationRunning);
- bcm_kfree(pTarang);
+ kfree(pTarang);
/* remove this filp from the asynchronously notified filp's */
filp->private_data = NULL;
@@ -102,11 +102,11 @@ static int bcm_char_release(struct inode *inode, struct file *filp)
static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
{
- PPER_TARANG_DATA pTarang = (PPER_TARANG_DATA)filp->private_data;
+ PPER_TARANG_DATA pTarang = filp->private_data;
PMINI_ADAPTER Adapter = pTarang->Adapter;
- struct sk_buff* Packet = NULL;
- UINT PktLen = 0;
- int wait_ret_val=0;
+ struct sk_buff* Packet = NULL;
+ ssize_t PktLen = 0;
+ int wait_ret_val=0;
wait_ret_val = wait_event_interruptible(Adapter->process_read_wait_queue,
(pTarang->RxAppControlHead || Adapter->device_removed));
@@ -139,14 +139,16 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l
if(Packet)
{
PktLen = Packet->len;
- if(copy_to_user(buf, Packet->data, PktLen))
+ if(copy_to_user(buf, Packet->data, min_t(size_t, PktLen, size)))
{
- bcm_kfree_skb(Packet);
+ dev_kfree_skb(Packet);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nReturning from copy to user failure \n");
return -EFAULT;
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read %d Bytes From Adapter packet = 0x%p by process %d!\n", PktLen, Packet, current->pid);
- bcm_kfree_skb(Packet);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Read %zd Bytes From Adapter packet = %p by process %d!\n",
+ PktLen, Packet, current->pid);
+ dev_kfree_skb(Packet);
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "<====\n");
@@ -155,15 +157,12 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l
static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
- PPER_TARANG_DATA pTarang = (PPER_TARANG_DATA)filp->private_data;
- void __user *argp = (void __user *)argp;
+ PPER_TARANG_DATA pTarang = filp->private_data;
+ void __user *argp = (void __user *)arg;
PMINI_ADAPTER Adapter = pTarang->Adapter;
INT Status = STATUS_FAILURE;
- IOCTL_BUFFER IoBuffer={};
-#ifndef BCM_SHM_INTERFACE
- int timeout = 0;
-#endif
-
+ int timeout = 0;
+ IOCTL_BUFFER IoBuffer;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", cmd, arg);
@@ -204,50 +203,41 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = vendorextnIoctl(Adapter, cmd, arg);
if(Status != CONTINUE_COMMON_PATH )
- {
return Status;
- }
switch(cmd){
// Rdms for Swin Idle...
case IOCTL_BCM_REGISTER_READ_PRIVATE:
{
RDM_BUFFER sRdmBuffer = {0};
- PCHAR temp_buff = NULL;
- UINT Bufflen = 0;
+ PCHAR temp_buff;
+ UINT Bufflen;
+
/* Copy Ioctl Buffer structure */
- if(copy_from_user((PCHAR)&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+ return -EINVAL;
+ if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
+
+ /* FIXME: need to restrict BuffLen */
Bufflen = IoBuffer.OutputLength + (4 - IoBuffer.OutputLength%4)%4;
- temp_buff = (PCHAR)kmalloc(Bufflen, GFP_KERNEL);
+ temp_buff = kmalloc(Bufflen, GFP_KERNEL);
if(!temp_buff)
- {
- return STATUS_FAILURE;
- }
- if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
+ return -ENOMEM;
+
Status = rdmalt(Adapter, (UINT)sRdmBuffer.Register,
(PUINT)temp_buff, Bufflen);
- if(Status != STATUS_SUCCESS)
- {
- bcm_kfree(temp_buff);
- return Status;
- }
- if(copy_to_user(IoBuffer.OutputBuffer,
- (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength))
+ if(Status == STATUS_SUCCESS)
{
- Status = -EFAULT;
+ if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength))
+ Status = -EFAULT;
}
- bcm_kfree(temp_buff);
+
+ kfree(temp_buff);
break;
}
case IOCTL_BCM_REGISTER_WRITE_PRIVATE:
@@ -256,19 +246,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
UINT uiTempVar=0;
/* Copy Ioctl Buffer structure */
- if(copy_from_user(&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+ return -EINVAL;
+
/* Get WrmBuffer structure */
- if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
+
uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
((uiTempVar == EEPROM_REJECT_REG_1)||
@@ -277,8 +264,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(uiTempVar == EEPROM_REJECT_REG_4)))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
- Status = -EFAULT;
- break;
+ return -EFAULT;
}
Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register,
(PUINT)sWrmBuffer.Data, sizeof(ULONG));
@@ -305,56 +291,39 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(Adapter->bPreparingForLowPowerMode ==TRUE))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Rdms\n");
- Status = -EACCES;
- break;
+ return -EACCES;
}
/* Copy Ioctl Buffer structure */
- if(copy_from_user(&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+ return -EINVAL;
+
+ if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
- temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
+ /* FIXME: don't trust user supplied length */
+ temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
if(!temp_buff)
- {
return STATUS_FAILURE;
- }
- if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
- if(
-#if !defined(BCM_SHM_INTERFACE)
- (((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
-#endif
- ((ULONG)sRdmBuffer.Register & 0x3)
- )
+ if((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+ ((ULONG)sRdmBuffer.Register & 0x3))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "RDM Done On invalid Address : %x Access Denied.\n",
(int)sRdmBuffer.Register);
- Status = -EINVAL;
- break;
+ return -EINVAL;
}
uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK;
Status = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register,
(PUINT)temp_buff, IoBuffer.OutputLength);
- if(Status != STATUS_SUCCESS)
- {
- bcm_kfree(temp_buff);
- return Status;
- }
- if(copy_to_user(IoBuffer.OutputBuffer,
- (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength))
- {
- Status = -EFAULT;
- }
- bcm_kfree(temp_buff);
+ if(Status == STATUS_SUCCESS)
+ if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength))
+ Status = -EFAULT;
+
+ kfree(temp_buff);
break;
}
case IOCTL_BCM_REGISTER_WRITE:
@@ -367,36 +336,28 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(Adapter->bPreparingForLowPowerMode ==TRUE))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Wrms\n");
- Status = -EACCES;
- break;
+ return -EACCES;
}
+
/* Copy Ioctl Buffer structure */
- if(copy_from_user((PCHAR)&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+ return -EINVAL;
+
/* Get WrmBuffer structure */
- if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
- if(
-#if !defined(BCM_SHM_INTERFACE)
+ if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
- (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
-#endif
- ((ULONG)sWrmBuffer.Register & 0x3)
- )
+ if( (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+ ((ULONG)sWrmBuffer.Register & 0x3) )
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n",
(int)sWrmBuffer.Register);
- Status = -EINVAL;
- break;
+ return -EINVAL;
}
+
uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
((uiTempVar == EEPROM_REJECT_REG_1)||
@@ -406,8 +367,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(cmd == IOCTL_BCM_REGISTER_WRITE))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
- Status = -EFAULT;
- break;
+ return -EFAULT;
}
Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register,
@@ -436,19 +396,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(Adapter->bPreparingForLowPowerMode ==TRUE))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"GPIO Can't be set/clear in Low power Mode");
- Status = -EACCES;
- break;
+ return -EACCES;
}
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(gpio_info))
+ return -EINVAL;
if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
uiBit = gpio_info.uiGpioNumber;
uiOperation = gpio_info.uiGpioValue;
@@ -517,8 +472,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
break;
case BCM_LED_THREAD_STATE_CHANGE_REQ:
{
-
- USER_THREAD_REQ threadReq = {0};
+ USER_THREAD_REQ threadReq = { 0 };
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"User made LED thread InActive");
if((Adapter->IdleMode == TRUE) ||
@@ -529,21 +483,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = -EACCES;
break;
}
- Status =copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
- Status= copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength);
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the InputBuffer from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if (IoBuffer.InputLength > sizeof(threadReq))
+ return -EINVAL;
+
+ if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
+
//if LED thread is running(Actively or Inactively) set it state to make inactive
if(Adapter->LEDInfo.led_thread_running)
{
@@ -572,19 +521,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if((Adapter->IdleMode == TRUE) ||
(Adapter->bShutStatus ==TRUE) ||
(Adapter->bPreparingForLowPowerMode ==TRUE))
- {
- Status = -EACCES;
- break;
- }
- if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER))) {
- Status = -EFAULT;
- break;
- }
- if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
- {
- Status = -EFAULT;
- break;
- }
+ return -EACCES;
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(gpio_info))
+ return -EINVAL;
+ if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
uiBit = gpio_info.uiGpioNumber;
//Set the gpio output register
Status = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
@@ -608,25 +551,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if((Adapter->IdleMode == TRUE) ||
(Adapter->bShutStatus ==TRUE) ||
(Adapter->bPreparingForLowPowerMode ==TRUE))
- {
- Status = -EINVAL;
- break;
- }
- Status = copy_from_user( (PCHAR)&IoBuffer, argp, sizeof( IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
+ return -EINVAL;
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(gpio_multi_info))
+ return -EINVAL;
+ if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
- Status = copy_from_user( &gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength);
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
if(IsReqGpioIsLedInNVM(Adapter,pgpio_multi_info[WIMAX_IDX].uiGPIOMask)== FALSE)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",pgpio_multi_info[WIMAX_IDX].uiGPIOMask,Adapter->gpioBitMap);
@@ -686,7 +618,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status);
- Status = -EFAULT;
break;
}
}
@@ -700,25 +631,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if((Adapter->IdleMode == TRUE) ||
(Adapter->bShutStatus ==TRUE) ||
(Adapter->bPreparingForLowPowerMode ==TRUE))
- {
- Status = -EINVAL;
- break;
- }
- Status = copy_from_user(&IoBuffer, argp, sizeof( IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
+ return -EINVAL;
- Status = copy_from_user( &gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength);
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status);
- Status = -EFAULT;
- break;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(gpio_multi_mode))
+ return -EINVAL;
+ if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
Status = rdmaltWithLock( Adapter, ( UINT) GPIO_MODE_REGISTER, ( PUINT) ucResetValue, sizeof( UINT));
if( STATUS_SUCCESS != Status)
@@ -769,7 +689,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status);
- Status = -EFAULT;
break;
}
}
@@ -783,24 +702,20 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
case IOCTL_IDLE_REQ:
{
PVOID pvBuffer=NULL;
+
/* Copy Ioctl Buffer structure */
- if(copy_from_user(&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
- pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL);
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ /* FIXME: don't accept any length from user */
+ pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
if(!pvBuffer)
- {
return -ENOMEM;
- }
- if(copy_from_user(pvBuffer, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
+ if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
{
Status = -EFAULT;
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
break;
}
@@ -820,10 +735,9 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer);
cntrlEnd:
up(&Adapter->LowPowerModeSync);
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
break;
}
-#ifndef BCM_SHM_INTERFACE
case IOCTL_BCM_BUFFER_DOWNLOAD_START:
{
INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock) ;
@@ -844,7 +758,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = reset_card_proc(Adapter);
if(Status)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "reset_card_proc Failed!\n");
+ pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name);
up(&Adapter->fw_download_sema);
up(&Adapter->NVMRdmWrmLock);
break;
@@ -862,7 +776,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
case IOCTL_BCM_BUFFER_DOWNLOAD:
{
- FIRMWARE_INFO *psFwInfo=NULL;
+ FIRMWARE_INFO *psFwInfo = NULL;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid);
do{
if(!down_trylock(&Adapter->fw_download_sema))
@@ -871,29 +785,23 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status=-EINVAL;
break;
}
+
/* Copy Ioctl Buffer structure */
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n");
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
+
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length for FW DLD is : %lx\n",
IoBuffer.InputLength);
- psFwInfo=kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
+
+ if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO))
+ return -EINVAL;
+
+ psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
if(!psFwInfo)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Failed to allocate buffer!!!!\n");
- Status = -ENOMEM;
- break;
- }
- if(copy_from_user(psFwInfo, IoBuffer.InputBuffer,
- IoBuffer.InputLength))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from_user 2 failed\n");
- Status = -EFAULT;
- break;
- }
+ return -ENOMEM;
+
+ if(copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
if(!psFwInfo->pvMappedFirmwareAddress ||
(psFwInfo->u32FirmwareLength == 0))
@@ -929,7 +837,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status != STATUS_SUCCESS)
up(&Adapter->fw_download_sema);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n");
- bcm_kfree(psFwInfo);
+ kfree(psFwInfo);
break;
}
case IOCTL_BCM_BUFFER_DOWNLOAD_STOP:
@@ -946,7 +854,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Adapter->bBinDownloaded=TRUE;
Adapter->bCfgDownloaded=TRUE;
atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
- atomic_set(&Adapter->RxRollOverCount, 0);
+
Adapter->CurrNumRecvDescs=0;
Adapter->downloadDDR = 0;
@@ -999,15 +907,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
up(&Adapter->NVMRdmWrmLock);
break;
}
-#endif
case IOCTL_BE_BUCKET_SIZE:
- Adapter->BEBucketSize = *(PULONG)arg;
- Status = STATUS_SUCCESS;
+ Status = 0;
+ if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
+ Status = -EFAULT;
break;
case IOCTL_RTPS_BUCKET_SIZE:
- Adapter->rtPSBucketSize = *(PULONG)arg;
- Status = STATUS_SUCCESS;
+ Status = 0;
+ if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
+ Status = -EFAULT;
break;
case IOCTL_CHIP_RESET:
{
@@ -1028,11 +937,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
case IOCTL_QOS_THRESHOLD:
{
USHORT uiLoopIndex;
- for(uiLoopIndex = 0 ; uiLoopIndex < NO_OF_QUEUES ; uiLoopIndex++)
- {
- Adapter->PackInfo[uiLoopIndex].uiThreshold = *(PULONG)arg;
+
+ Status = 0;
+ for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
+ if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold,
+ (unsigned long __user *)arg)) {
+ Status = -EFAULT;
+ break;
+ }
}
- Status = STATUS_SUCCESS;
break;
}
@@ -1044,22 +957,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
break;
case IOCTL_GET_PACK_INFO:
- if(copy_to_user(argp, &Adapter->PackInfo,
- sizeof(PacketInfo)*NO_OF_QUEUES))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_to_user(argp, &Adapter->PackInfo, sizeof(PacketInfo)*NO_OF_QUEUES))
+ return -EFAULT;
Status = STATUS_SUCCESS;
break;
case IOCTL_BCM_SWITCH_TRANSFER_MODE:
{
UINT uiData = 0;
if(copy_from_user(&uiData, argp, sizeof(UINT)))
- {
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
+
if(uiData) /* Allow All Packets */
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n");
@@ -1078,22 +985,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
/* Copy Ioctl Buffer structure */
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
- if(copy_to_user(IoBuffer.OutputBuffer,
- VER_FILEVERSION_STR, (UINT)IoBuffer.OutputLength))
- {
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
+
+ if(copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, IoBuffer.OutputLength))
+ return -EFAULT;
Status = STATUS_SUCCESS;
break;
}
case IOCTL_BCM_GET_CURRENT_STATUS:
{
- LINK_STATE *plink_state = NULL;
+ LINK_STATE link_state;
+
/* Copy Ioctl Buffer structure */
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
{
@@ -1101,12 +1003,18 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = -EFAULT;
break;
}
- plink_state = (LINK_STATE*)arg;
- plink_state->bIdleMode = (UCHAR)Adapter->IdleMode;
- plink_state->bShutdownMode = Adapter->bShutStatus;
- plink_state->ucLinkStatus = (UCHAR)Adapter->LinkStatus;
- if(copy_to_user(IoBuffer.OutputBuffer,
- (PUCHAR)plink_state, (UINT)IoBuffer.OutputLength))
+ if (IoBuffer.OutputLength != sizeof(link_state)) {
+ Status = -EINVAL;
+ break;
+ }
+
+ memset(&link_state, 0, sizeof(link_state));
+ link_state.bIdleMode = Adapter->IdleMode;
+ link_state.bShutdownMode = Adapter->bShutStatus;
+ link_state.ucLinkStatus = Adapter->LinkStatus;
+
+ if (copy_to_user(IoBuffer.OutputBuffer, &link_state,
+ min_t(size_t, sizeof(link_state), IoBuffer.OutputLength)))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n");
Status = -EFAULT;
@@ -1118,17 +1026,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
case IOCTL_BCM_SET_MAC_TRACING:
{
UINT tracing_flag;
+
/* copy ioctl Buffer structure */
- if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
- if(copy_from_user(&tracing_flag, IoBuffer.InputBuffer,sizeof(UINT)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
+ if(copy_from_user(&tracing_flag,IoBuffer.InputBuffer,sizeof(UINT)))
+ return -EFAULT;
+
if (tracing_flag)
Adapter->pTarangs->MacTracingEnabled = TRUE;
else
@@ -1138,72 +1043,53 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
case IOCTL_BCM_GET_DSX_INDICATION:
{
ULONG ulSFId=0;
- if(copy_from_user((PCHAR)&IoBuffer, argp,
- sizeof(IOCTL_BUFFER)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid IO buffer!!!" );
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
if(IoBuffer.OutputLength < sizeof(stLocalSFAddIndicationAlt))
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Mismatch req: %lx needed is =0x%zx!!!",
- IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt));
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,
+ "Mismatch req: %lx needed is =0x%zx!!!",
+ IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt));
return -EINVAL;
}
- if(copy_from_user(&ulSFId, IoBuffer.InputBuffer,
- sizeof(ulSFId)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Invalid SFID!!! %lu", ulSFId );
- Status = -EFAULT;
- break;
- }
+
+ if(copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId)))
+ return -EFAULT;
+
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId );
- get_dsx_sf_data_to_application(Adapter, ulSFId,
- IoBuffer.OutputBuffer);
+ get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer);
Status=STATUS_SUCCESS;
}
break;
case IOCTL_BCM_GET_HOST_MIBS:
{
- PCHAR temp_buff;
+ PVOID temp_buff;
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from user for IoBuff failed\n");
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
if(IoBuffer.OutputLength != sizeof(S_MIBS_HOST_STATS_MIBS))
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length Check failed %lu %zd\n", IoBuffer.OutputLength,
- sizeof(S_MIBS_HOST_STATS_MIBS));
- return -EINVAL;
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,
+ "Length Check failed %lu %zd\n",
+ IoBuffer.OutputLength, sizeof(S_MIBS_HOST_STATS_MIBS));
+ return -EINVAL;
}
- temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
-
+ /* FIXME: HOST_STATS are too big for kmalloc (122048)! */
+ temp_buff = kzalloc(sizeof(S_MIBS_HOST_STATS_MIBS), GFP_KERNEL);
if(!temp_buff)
- {
return STATUS_FAILURE;
- }
- Status = ProcessGetHostMibs(Adapter,
- (PUCHAR)temp_buff, IoBuffer.OutputLength);
+ Status = ProcessGetHostMibs(Adapter, temp_buff);
+ GetDroppedAppCntrlPktMibs(temp_buff, pTarang);
- Status = GetDroppedAppCntrlPktMibs((PVOID)temp_buff,
- (PPER_TARANG_DATA)filp->private_data);
-
- if(copy_to_user(IoBuffer.OutputBuffer,(PCHAR)temp_buff,
- sizeof(S_MIBS_HOST_STATS_MIBS)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy to user failed\n");
- bcm_kfree(temp_buff);
- return -EFAULT;
- }
+ if (Status != STATUS_FAILURE)
+ if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS)))
+ Status = -EFAULT;
- bcm_kfree(temp_buff);
+ kfree(temp_buff);
break;
}
@@ -1213,10 +1099,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Adapter->usIdleModePattern = ABORT_IDLE_MODE;
Adapter->bWakeUpDevice = TRUE;
wake_up(&Adapter->process_rx_cntrlpkt);
- #if 0
- Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
- InterfaceAbortIdlemode (Adapter, Adapter->usIdleModePattern);
- #endif
}
Status = STATUS_SUCCESS;
break;
@@ -1235,24 +1117,20 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Status = -EACCES;
break;
}
+
/* Copy Ioctl Buffer structure */
- if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
- pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL);
+ /* FIXME: restrict length */
+ pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
if(!pvBuffer)
- {
return -ENOMEM;
- break;
- }
/* Get WrmBuffer structure */
- if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
{
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
Status = -EFAULT;
break;
}
@@ -1262,7 +1140,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
((ULONG)pBulkBuffer->Register & 0x3))
{
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"WRM Done On invalid Address : %x Access Denied.\n",(int)pBulkBuffer->Register);
Status = -EINVAL;
break;
@@ -1277,7 +1155,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(uiTempVar == EEPROM_REJECT_REG_4)) &&
(cmd == IOCTL_BCM_REGISTER_WRITE))
{
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"EEPROM Access Denied, not in VSG Mode\n");
Status = -EFAULT;
break;
@@ -1293,30 +1171,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n");
}
- bcm_kfree(pvBuffer);
+ kfree(pvBuffer);
break;
}
case IOCTL_BCM_GET_NVM_SIZE:
- {
-
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- //IOLog("failed NVM first");
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
+
if(Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH ) {
- if(copy_to_user(IoBuffer.OutputBuffer,
- (unsigned char *)&Adapter->uiNVMDSDSize, (UINT)sizeof(UINT)))
- {
- Status = -EFAULT;
- return Status;
- }
+ if(copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT)))
+ return -EFAULT;
}
-
Status = STATUS_SUCCESS ;
- }
break;
case IOCTL_BCM_CAL_INIT :
@@ -1325,38 +1192,26 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
UINT uiSectorSize = 0 ;
if(Adapter->eNVMType == NVM_FLASH)
{
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy From User space failed. status :%d", Status);
+ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
return -EFAULT;
- }
- uiSectorSize = *((PUINT)(IoBuffer.InputBuffer)); /* FIXME: unchecked __user access */
+
+ if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT)))
+ return -EFAULT;
+
if((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE))
{
-
- Status = copy_to_user(IoBuffer.OutputBuffer,
- (unsigned char *)&Adapter->uiSectorSize ,
- (UINT)sizeof(UINT));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status);
- return -EFAULT;
- }
+ if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize,
+ sizeof(UINT)))
+ return -EFAULT;
}
else
{
if(IsFlash2x(Adapter))
{
- Status = copy_to_user(IoBuffer.OutputBuffer,
- (unsigned char *)&Adapter->uiSectorSize ,
- (UINT)sizeof(UINT));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status);
- return -EFAULT;
- }
-
+ if (copy_to_user(IoBuffer.OutputBuffer,
+ &Adapter->uiSectorSize ,
+ sizeof(UINT)))
+ return -EFAULT;
}
else
{
@@ -1380,25 +1235,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
break;
case IOCTL_BCM_SET_DEBUG :
+#ifdef DEBUG
{
USER_BCM_DBG_STATE sUserDebugState;
// BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Entered the ioctl %x \n", IOCTL_BCM_SET_DEBUG );
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n");
- Status = copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy from user failed\n");
- Status = -EFAULT;
- break;
- }
- Status = copy_from_user(&sUserDebugState,IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE));
- if(Status)
- {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IoBuffer.InputBuffer failed");
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
return -EFAULT;
- }
+
+ if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE)))
+ return -EFAULT;
+
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ",
sUserDebugState.OnOff, sUserDebugState.Type);
@@ -1421,15 +1270,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
BCM_SHOW_DEBUG_BITMAP(Adapter);
}
+#endif
break;
case IOCTL_BCM_NVM_READ:
case IOCTL_BCM_NVM_WRITE:
{
-
- NVM_READWRITE stNVMReadWrite = {};
+ NVM_READWRITE stNVMReadWrite;
PUCHAR pReadData = NULL;
- void __user * pBuffertobeCopied = NULL;
- ULONG ulDSDMagicNumInUsrBuff = 0 ;
+ ULONG ulDSDMagicNumInUsrBuff = 0;
struct timeval tv0, tv1;
memset(&tv0,0,sizeof(struct timeval));
memset(&tv1,0,sizeof(struct timeval));
@@ -1454,21 +1302,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
/* Copy Ioctl Buffer structure */
if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copy_from_user failed\n");
- Status = -EFAULT;
- break;
- }
- if(IOCTL_BCM_NVM_READ == cmd)
- pBuffertobeCopied = IoBuffer.OutputBuffer;
- else
- pBuffertobeCopied = IoBuffer.InputBuffer;
+ return -EFAULT;
- if(copy_from_user(&stNVMReadWrite, pBuffertobeCopied,sizeof(NVM_READWRITE)))
- {
- Status = -EFAULT;
- break;
- }
+ if(copy_from_user(&stNVMReadWrite,
+ (IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer,
+ sizeof(NVM_READWRITE)))
+ return -EFAULT;
//
// Deny the access if the offset crosses the cal area limit.
@@ -1481,18 +1320,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
break;
}
- pReadData =(PCHAR)kmalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
-
+ pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
if(!pReadData)
return -ENOMEM;
- memset(pReadData,0,stNVMReadWrite.uiNumBytes);
-
if(copy_from_user(pReadData, stNVMReadWrite.pBuffer,
stNVMReadWrite.uiNumBytes))
{
Status = -EFAULT;
- bcm_kfree(pReadData);
+ kfree(pReadData);
break;
}
@@ -1507,7 +1343,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadData);
+ kfree(pReadData);
return -EACCES;
}
@@ -1518,13 +1354,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status != STATUS_SUCCESS)
{
- bcm_kfree(pReadData);
+ kfree(pReadData);
return Status;
}
- if(copy_to_user(stNVMReadWrite.pBuffer,
- pReadData, (UINT)stNVMReadWrite.uiNumBytes))
+ if(copy_to_user(stNVMReadWrite.pBuffer,pReadData, stNVMReadWrite.uiNumBytes))
{
- bcm_kfree(pReadData);
+ kfree(pReadData);
Status = -EFAULT;
}
}
@@ -1539,7 +1374,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadData);
+ kfree(pReadData);
return -EACCES;
}
@@ -1567,7 +1402,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input..");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadData);
+ kfree(pReadData);
return Status;
}
@@ -1576,7 +1411,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input..");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadData);
+ kfree(pReadData);
return Status;
}
}
@@ -1593,7 +1428,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status != STATUS_SUCCESS)
{
- bcm_kfree(pReadData);
+ kfree(pReadData);
return Status;
}
}
@@ -1601,7 +1436,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n",(tv1.tv_sec - tv0.tv_sec)*1000 +(tv1.tv_usec - tv0.tv_usec)/1000);
- bcm_kfree(pReadData);
+ kfree(pReadData);
Status = STATUS_SUCCESS;
}
break;
@@ -1614,7 +1449,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
UINT BuffSize = 0;
UINT ReadBytes = 0;
UINT ReadOffset = 0;
- char __user *OutPutBuff = NULL;
+ void __user *OutPutBuff;
if(IsFlash2x(Adapter) != TRUE)
{
@@ -1623,20 +1458,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called");
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
return -EFAULT;
- }
//Reading FLASH 2.x READ structure
- Status = copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Input Buffer failed");
+ if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE)))
return -EFAULT;
- }
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xRead.Section);
@@ -1672,7 +1499,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadBuff);
+ kfree(pReadBuff);
return -EACCES;
}
@@ -1700,7 +1527,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Copy to use failed with status :%d", Status);
- Status = -EFAULT;
break;
}
NOB = NOB - ReadBytes;
@@ -1712,15 +1538,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadBuff);
+ kfree(pReadBuff);
}
break ;
case IOCTL_BCM_FLASH2X_SECTION_WRITE :
{
FLASH2X_READWRITE sFlash2xWrite = {0};
- PUCHAR pWriteBuff = NULL;
- void __user *InputAddr = NULL;
+ PUCHAR pWriteBuff;
+ void __user *InputAddr;
UINT NOB = 0;
UINT BuffSize = 0;
UINT WriteOffset = 0;
@@ -1737,33 +1563,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_FLASH2X_SECTION_WRITE Called");
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
return -EFAULT;
- }
//Reading FLASH 2.x READ structure
- Status = copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Reading of output Buffer from IOCTL buffer fails");
+ if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE)))
return -EFAULT;
- }
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xWrite.Section);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.offset :%d" ,sFlash2xWrite.offset);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.numOfBytes :%x" ,sFlash2xWrite.numOfBytes);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.bVerify :%x\n" ,sFlash2xWrite.bVerify);
- #if 0
- if((sFlash2xWrite.Section == ISO_IMAGE1) ||(sFlash2xWrite.Section == ISO_IMAGE2) ||
- (sFlash2xWrite.Section == DSD0) || (sFlash2xWrite.Section == DSD1) || (sFlash2xWrite.Section == DSD2))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"ISO/DSD Image write is not allowed.... ");
- return STATUS_FAILURE ;
- }
- #endif
if((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) &&
(sFlash2xWrite.Section != VSA2) )
{
@@ -1783,12 +1593,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
else
BuffSize = NOB ;
- pWriteBuff = (PCHAR)kmalloc(BuffSize, GFP_KERNEL);
+ pWriteBuff = kmalloc(BuffSize, GFP_KERNEL);
if(pWriteBuff == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure");
return -ENOMEM;
- }
+
//extracting the remainder of the given offset.
WriteBytes = Adapter->uiSectorSize ;
@@ -1805,7 +1613,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pWriteBuff);
+ kfree(pWriteBuff);
return -EACCES;
}
@@ -1816,7 +1624,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to user failed with status :%d", Status);
- Status = -EFAULT;
break ;
}
BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pWriteBuff,WriteBytes);
@@ -1844,28 +1651,22 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
} while(NOB > 0);
BcmFlash2xWriteSig(Adapter,sFlash2xWrite.Section);
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pWriteBuff);
+ kfree(pWriteBuff);
}
break ;
case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP :
{
- PFLASH2X_BITMAP psFlash2xBitMap = NULL ;
+ PFLASH2X_BITMAP psFlash2xBitMap;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
return -EFAULT;
- }
+
if(IoBuffer.OutputLength != sizeof(FLASH2X_BITMAP))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Structure size mismatch Lib :0x%lx Driver :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_BITMAP));
- break;
- }
+ return -EINVAL;
- psFlash2xBitMap = (PFLASH2X_BITMAP)kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL);
+ psFlash2xBitMap = kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL);
if(psFlash2xBitMap == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory is not available");
@@ -1880,20 +1681,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(psFlash2xBitMap);
+ kfree(psFlash2xBitMap);
return -EACCES;
}
BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap);
up(&Adapter->NVMRdmWrmLock);
- Status = copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x bitMap failed");
- bcm_kfree(psFlash2xBitMap);
- return -EFAULT;
- }
- bcm_kfree(psFlash2xBitMap);
+ if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP)))
+ Status = -EFAULT;
+
+ kfree(psFlash2xBitMap);
}
break ;
case IOCTL_BCM_SET_ACTIVE_SECTION :
@@ -1911,14 +1708,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
+ return Status;
}
Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT));
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
- return -EFAULT;
+ return Status;
}
down(&Adapter->NVMRdmWrmLock);
@@ -1946,29 +1743,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
Adapter->bAllDSDWriteAllow = FALSE ;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
- #if 0
- SECTION_TYPE section = 0 ;
-
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION Called");
- Status = copy_from_user((PCHAR)&IoBuffer, (PCHAR)arg, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
- }
- Status = copy_from_user((PCHAR)section,(PCHAR)&IoBuffer, sizeof(INT));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of section type failed failed");
- return -EFAULT;
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", section);
- if(section == DSD)
- Adapter->ulFlashCalStart = Adapter->uiActiveDSDOffsetAtFwDld ;
- else
- Status = STATUS_FAILURE ;
- #endif
Status = STATUS_SUCCESS ;
}
break ;
@@ -1989,14 +1763,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status);
- return -EFAULT;
+ return Status;
}
- Status = copy_from_user(&sCopySectStrut,IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION));
+ Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION));
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status);
- return -EFAULT;
+ return Status;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection);
@@ -2067,7 +1841,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- Status = -EFAULT;
break;
}
if(Adapter->eNVMType != NVM_FLASH)
@@ -2080,35 +1853,18 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
{
if(IoBuffer.OutputLength < sizeof(FLASH2X_CS_INFO))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. \nRequired size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_CS_INFO));
- Status = -EINVAL;
- break;
- }
+ return -EINVAL;
- Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x cs info failed");
- Status = -EFAULT;
- break;
- }
+ if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO)))
+ return -EFAULT;
}
else
{
if(IoBuffer.OutputLength < sizeof(FLASH_CS_INFO))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. Required size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH_CS_INFO));
- Status = -EINVAL;
- break;
- }
- Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash CS info failed");
- Status = -EFAULT;
- break;
- }
+ return -EINVAL;
+
+ if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO)))
+ return -EFAULT;
}
}
@@ -2130,13 +1886,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
+ return Status;
}
- Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT));
+ Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
- return -EFAULT;
+ return Status;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", eFlash2xSectionVal);
@@ -2166,13 +1922,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
case IOCTL_BCM_NVM_RAW_READ :
{
- NVM_READWRITE stNVMRead = {};
+ NVM_READWRITE stNVMRead;
INT NOB ;
INT BuffSize ;
INT ReadOffset = 0;
UINT ReadBytes = 0 ;
- PUCHAR pReadBuff = NULL ;
- char __user *OutPutBuff = NULL ;
+ PUCHAR pReadBuff;
+ void __user *OutPutBuff;
if(Adapter->eNVMType != NVM_FLASH)
{
@@ -2189,10 +1945,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
if(copy_from_user(&stNVMRead, IoBuffer.OutputBuffer,sizeof(NVM_READWRITE)))
- {
- Status = -EFAULT;
- break;
- }
+ return -EFAULT;
NOB = stNVMRead.uiNumBytes;
//In Raw-Read max Buff size : 64MB
@@ -2202,11 +1955,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
else
BuffSize = NOB ;
- ReadOffset = stNVMRead.uiOffset ;
+ ReadOffset = stNVMRead.uiOffset;
OutPutBuff = stNVMRead.pBuffer;
-
- pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);
+ pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
if(pReadBuff == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure");
@@ -2220,7 +1972,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
(Adapter->bPreparingForLowPowerMode ==TRUE))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
- bcm_kfree(pReadBuff);
+ kfree(pReadBuff);
up(&Adapter->NVMRdmWrmLock);
return -EACCES;
}
@@ -2241,13 +1993,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
break;
}
- BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff, ReadBytes);
+ BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff,ReadBytes);
Status = copy_to_user(OutPutBuff, pReadBuff,ReadBytes);
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to use failed with status :%d", Status);
- Status = -EFAULT;
break;
}
NOB = NOB - ReadBytes;
@@ -2260,7 +2011,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
}
Adapter->bFlashRawRead = FALSE ;
up(&Adapter->NVMRdmWrmLock);
- bcm_kfree(pReadBuff);
+ kfree(pReadBuff);
break ;
}
@@ -2273,7 +2024,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of Ioctl buffer is failed from user space");
- Status = -EFAULT;
break;
}
@@ -2281,7 +2031,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if(Status)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of control bit mask failed from user space");
- Status = -EFAULT;
break;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask);
@@ -2300,71 +2049,44 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
DevInfo.u32NVMType = Adapter->eNVMType;
DevInfo.u32InterfaceType = BCM_USB;
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- Status = -EFAULT;
- break;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
if(IoBuffer.OutputLength < sizeof(DevInfo))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length is less than actural buffer size");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"user passed buffer size :0x%lX, expected size :0x%zx",IoBuffer.OutputLength, sizeof(DevInfo));
- Status = -EINVAL;
- break;
- }
- Status = copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying Dev info structure to user space buffer failed");
- Status = -EFAULT;
- break;
- }
+ return -EINVAL;
+
+ if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)))
+ return -EFAULT;
}
break ;
case IOCTL_BCM_TIME_SINCE_NET_ENTRY:
{
ST_TIME_ELAPSED stTimeElapsedSinceNetEntry = {0};
- struct timeval tv = {0} ;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
- Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- Status = -EFAULT;
- break;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+ return -EFAULT;
+
if(IoBuffer.OutputLength < sizeof(ST_TIME_ELAPSED))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length:0x%lx is less than expected buff size :0x%zX",IoBuffer.OutputLength,sizeof(ST_TIME_ELAPSED));
- Status = -EINVAL;
- break;
- }
+ return -EINVAL;
- //stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = Adapter->liTimeSinceLastNetEntry;
- do_gettimeofday(&tv);
- stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = tv.tv_sec - Adapter->liTimeSinceLastNetEntry;
+ stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry;
- Status = copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED));
- if(Status)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying ST_TIME_ELAPSED structure to user space buffer failed");
- Status = -EFAULT;
- break;
- }
+ if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED)))
+ return -EFAULT;
}
break;
- default:
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "wrong input %x",cmd);
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In default ioctl %d\n", cmd);
- Status = STATUS_FAILURE;
+ case IOCTL_CLOSE_NOTIFICATION:
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_CLOSE_NOTIFICATION");
+ break;
+ default:
+ pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd);
+ Status = STATUS_FAILURE;
break;
}
return Status;
@@ -2380,59 +2102,37 @@ static struct file_operations bcm_fops = {
.llseek = no_llseek,
};
+extern struct class *bcm_class;
int register_control_device_interface(PMINI_ADAPTER Adapter)
{
+
if(Adapter->major>0)
- return Adapter->major;
- Adapter->major = register_chrdev(0, "tarang", &bcm_fops);
- if(Adapter->major < 0)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "register_chrdev:Failed to registering WiMax control char device!");
- return Adapter->major;
- }
-
- bcm_class = NULL;
- bcm_class = class_create (THIS_MODULE, "tarang");
- if(IS_ERR (bcm_class))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unable to create class\n");
- unregister_chrdev(Adapter->major, "tarang");
- Adapter->major = 0;
- return -ENODEV;
+ return Adapter->major;
+
+ Adapter->major = register_chrdev(0, DEV_NAME, &bcm_fops);
+ if(Adapter->major < 0) {
+ pr_err(DRV_NAME ": could not created character device\n");
+ return Adapter->major;
}
+
Adapter->pstCreatedClassDevice = device_create (bcm_class, NULL,
- MKDEV(Adapter->major, 0),
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
- NULL ,
-#endif
- "tarang");
+ MKDEV(Adapter->major, 0), Adapter,
+ DEV_NAME);
- if(IS_ERR(Adapter->pstCreatedClassDevice))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "class device did not get created : %ld", PTR_ERR(Adapter->pstCreatedClassDevice) );
+ if(IS_ERR(Adapter->pstCreatedClassDevice)) {
+ pr_err(DRV_NAME ": class device create failed\n");
+ unregister_chrdev(Adapter->major, DEV_NAME);
+ return PTR_ERR(Adapter->pstCreatedClassDevice);
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Got Major No: %d", Adapter->major);
- return 0;
+
+ return 0;
}
void unregister_control_device_interface(PMINI_ADAPTER Adapter)
{
- if(Adapter->major > 0)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying class device");
+ if(Adapter->major > 0) {
device_destroy (bcm_class, MKDEV(Adapter->major, 0));
+ unregister_chrdev(Adapter->major, DEV_NAME);
}
- if(!IS_ERR(bcm_class))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying created class ");
- class_destroy (bcm_class);
- bcm_class = NULL;
- }
- if(Adapter->major > 0)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"unregistering character interface");
- unregister_chrdev(Adapter->major, "tarang");
- }
-
}
diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c
index bc2969821421..a6ce2396c791 100644
--- a/drivers/staging/bcm/Bcmnet.c
+++ b/drivers/staging/bcm/Bcmnet.c
@@ -1,264 +1,238 @@
#include "headers.h"
-static INT bcm_notify_event(struct notifier_block *nb, ULONG event, PVOID dev)
+struct net_device *gblpnetdev;
+
+static INT bcm_open(struct net_device *dev)
{
- struct net_device *ndev = (struct net_device*)dev;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- //PMINI_ADAPTER Adapter = (PMINI_ADAPTER)ndev->priv;
- if(strncmp(ndev->name,gblpnetdev->name,5)==0)
- {
- switch(event)
- {
- case NETDEV_CHANGEADDR:
- case NETDEV_GOING_DOWN:
- /*ignore this */
- break;
- case NETDEV_DOWN:
- break;
-
- case NETDEV_UP:
- break;
-
- case NETDEV_REGISTER:
- /* Increment the Reference Count for "veth0" */
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register RefCount: %x\n",
- netdev_refcnt_read(ndev));
- dev_hold(ndev);
- break;
-
- case NETDEV_UNREGISTER:
- /* Decrement the Reference Count for "veth0" */
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregister RefCnt: %x\n",
- netdev_refcnt_read(ndev));
- dev_put(ndev);
- break;
- };
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+ if (Adapter->fw_download_done == FALSE) {
+ pr_notice(PFX "%s: link up failed (download in progress)\n",
+ dev->name);
+ return -EBUSY;
}
- return NOTIFY_DONE;
-}
-/* Notifier block to receive netdevice events */
-static struct notifier_block bcm_notifier_block =
-{
- .notifier_call = bcm_notify_event,
-};
+ if (netif_msg_ifup(Adapter))
+ pr_info(PFX "%s: enabling interface\n", dev->name);
-struct net_device *gblpnetdev;
-/***************************************************************************************/
-/* proto-type of lower function */
-#ifdef BCM_SHM_INTERFACE
-const char *bcmVirtDeviceName="bcmeth";
-#endif
+ if (Adapter->LinkUpStatus) {
+ if (netif_msg_link(Adapter))
+ pr_info(PFX "%s: link up\n", dev->name);
-static INT bcm_open(struct net_device *dev)
-{
- PMINI_ADAPTER Adapter = NULL ; //(PMINI_ADAPTER)dev->priv;
- Adapter = GET_BCM_ADAPTER(dev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "======>");
- if(Adapter->fw_download_done==FALSE)
- return -EINVAL;
- Adapter->if_up=1;
- if(Adapter->LinkUpStatus == 1){
- if(netif_queue_stopped(Adapter->dev)){
- netif_carrier_on(Adapter->dev);
- netif_start_queue(Adapter->dev);
- }
+ netif_carrier_on(Adapter->dev);
+ netif_start_queue(Adapter->dev);
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "<======");
- return 0;
+ return 0;
}
static INT bcm_close(struct net_device *dev)
{
- PMINI_ADAPTER Adapter = NULL ;//gpadapter ;
- Adapter = GET_BCM_ADAPTER(dev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=====>");
- Adapter->if_up=0;
- if(!netif_queue_stopped(dev)) {
- netif_carrier_off(dev);
- netif_stop_queue(dev);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"<=====");
- return 0;
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+ if (netif_msg_ifdown(Adapter))
+ pr_info(PFX "%s: disabling interface\n", dev->name);
+
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ return ClassifyPacket(netdev_priv(dev), skb);
}
-static struct net_device_stats *bcm_get_stats(struct net_device *dev)
+/*******************************************************************
+* Function - bcm_transmit()
+*
+* Description - This is the main transmit function for our virtual
+* interface(eth0). It handles the ARP packets. It
+* clones this packet and then Queue it to a suitable
+* Queue. Then calls the transmit_packet().
+*
+* Parameter - skb - Pointer to the socket buffer structure
+* dev - Pointer to the virtual net device structure
+*
+*********************************************************************/
+
+static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
{
- PLINUX_DEP_DATA pLinuxData=NULL;
- PMINI_ADAPTER Adapter = NULL ;// gpadapter ;
- Adapter = GET_BCM_ADAPTER(dev);
- pLinuxData = (PLINUX_DEP_DATA)(Adapter->pvOsDepData);
-
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Dev = %p, pLinuxData = %p", dev, pLinuxData);
- pLinuxData->netstats.rx_packets=atomic_read(&Adapter->RxRollOverCount)*64*1024+Adapter->PrevNumRecvDescs;
- pLinuxData->netstats.rx_bytes=atomic_read(&Adapter->GoodRxByteCount)+atomic_read(&Adapter->BadRxByteCount);
- pLinuxData->netstats.rx_dropped=atomic_read(&Adapter->RxPacketDroppedCount);
- pLinuxData->netstats.rx_errors=atomic_read(&Adapter->RxPacketDroppedCount);
- pLinuxData->netstats.rx_length_errors=0;
- pLinuxData->netstats.rx_frame_errors=0;
- pLinuxData->netstats.rx_crc_errors=0;
- pLinuxData->netstats.tx_bytes=atomic_read(&Adapter->GoodTxByteCount);
- pLinuxData->netstats.tx_packets=atomic_read(&Adapter->TxTotalPacketCount);
- pLinuxData->netstats.tx_dropped=atomic_read(&Adapter->TxDroppedPacketCount);
-
- return &(pLinuxData->netstats);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+ u16 qindex = skb_get_queue_mapping(skb);
+
+
+ if (Adapter->device_removed || !Adapter->LinkUpStatus)
+ goto drop;
+
+ if (Adapter->TransferMode != IP_PACKET_ONLY_MODE)
+ goto drop;
+
+ if (INVALID_QUEUE_INDEX == qindex)
+ goto drop;
+
+ if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >=
+ SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
+ return NETDEV_TX_BUSY;
+
+ /* Now Enqueue the packet */
+ if (netif_msg_tx_queued(Adapter))
+ pr_info(PFX "%s: enqueueing packet to queue %d\n",
+ dev->name, qindex);
+
+ spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
+ Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
+ Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
+
+ *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies;
+ ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
+ Adapter->PackInfo[qindex].LastTxQueue, skb);
+ atomic_inc(&Adapter->TotalPacketCount);
+ spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
+
+ /* FIXME - this is racy and incorrect, replace with work queue */
+ if (!atomic_read(&Adapter->TxPktAvail)) {
+ atomic_set(&Adapter->TxPktAvail, 1);
+ wake_up(&Adapter->tx_packet_wait_queue);
+ }
+ return NETDEV_TX_OK;
+
+ drop:
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
}
+
+
+
/**
@ingroup init_functions
Register other driver entry points with the kernel
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-static struct net_device_ops bcmNetDevOps = {
+static const struct net_device_ops bcmNetDevOps = {
.ndo_open = bcm_open,
.ndo_stop = bcm_close,
- .ndo_get_stats = bcm_get_stats,
.ndo_start_xmit = bcm_transmit,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_select_queue = bcm_select_queue,
};
-#endif
-int register_networkdev(PMINI_ADAPTER Adapter)
+static struct device_type wimax_type = {
+ .name = "wimax",
+};
+
+static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- int result=0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
- void **temp = NULL; /* actually we're *allocating* the device in alloc_etherdev */
-#endif
- Adapter->dev = alloc_etherdev(sizeof(PMINI_ADAPTER));
- if(!Adapter->dev)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "ERR: No Dev");
- return -ENOMEM;
- }
- gblpnetdev = Adapter->dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
- Adapter->dev->priv = Adapter;
-#else
- temp = netdev_priv(Adapter->dev);
- *temp = (void *)Adapter;
-#endif
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "init adapterptr: %x %x\n", (UINT)Adapter, temp);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
- Adapter->dev->netdev_ops = &bcmNetDevOps;
-#else
- Adapter->dev->open = bcm_open;
- Adapter->dev->stop = bcm_close;
- Adapter->dev->get_stats = bcm_get_stats;
- Adapter->dev->hard_start_xmit = bcm_transmit;
- Adapter->dev->hard_header_len = ETH_HLEN + LEADER_SIZE;
-#endif
-
-#ifndef BCM_SHM_INTERFACE
- Adapter->dev->mtu = MTU_SIZE; /* 1400 Bytes */
- /* Read the MAC Address from EEPROM */
- ReadMacAddressFromNVM(Adapter);
+ 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 bcm_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+ PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter;
+ struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface);
- /* Register the notifier block for getting netdevice events */
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering netdevice notifier\n");
- result = register_netdevice_notifier(&bcm_notifier_block);
- if(result)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier Block did not get registered");
- Adapter->bNetdeviceNotifierRegistered = FALSE;
- return result;
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier got Registered");
- Adapter->bNetdeviceNotifierRegistered = TRUE;
- }
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u",
+ Adapter->uiFlashLayoutMajorVersion,
+ Adapter->uiFlashLayoutMinorVersion);
-#else
-
- Adapter->dev->mtu = CPE_MTU_SIZE;
-
-#if 0
- //for CPE - harcode the virtual mac address
- Adapter->dev->dev_addr[0] = MII_WIMAX_MACADDRESS[0];
- Adapter->dev->dev_addr[1] = MII_WIMAX_MACADDRESS[1];
- Adapter->dev->dev_addr[2] = MII_WIMAX_MACADDRESS[2];
- Adapter->dev->dev_addr[3] = MII_WIMAX_MACADDRESS[3];
- Adapter->dev->dev_addr[4] = MII_WIMAX_MACADDRESS[4];
- Adapter->dev->dev_addr[5] = MII_WIMAX_MACADDRESS[5];
-#else
- ReadMacAddressFromNVM(Adapter);
-#endif
- strcpy(Adapter->dev->name, bcmVirtDeviceName); //Copy the device name
-
-#endif
-
- result = register_netdev(Adapter->dev);
- if (!result)
- {
- Adapter->bNetworkInterfaceRegistered = TRUE ;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Beceem Network device name is %s!", Adapter->dev->name);
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Network device can not be registered!");
- Adapter->bNetworkInterfaceRegistered = FALSE ;
- return result;
- }
+ usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
+}
-#if 0
- Adapter->stDebugState.debug_level = DBG_LVL_CURR;
- Adapter->stDebugState.type =(UINT)0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_OTHERS] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_RX] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_TX] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xffffffff;
+static u32 bcm_get_link(struct net_device *dev)
+{
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
- printk("-------ps_adapter->stDebugState.type=%x\n",Adapter->stDebugState.type);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_OTHERS]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_OTHERS]);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_RX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_RX]);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_TX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_TX]);
-#endif
+ return Adapter->LinkUpStatus;
+}
- return 0;
+static u32 bcm_get_msglevel (struct net_device *dev)
+{
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+ return Adapter->msg_enable;
}
-void bcm_unregister_networkdev(PMINI_ADAPTER Adapter)
+static void bcm_set_msglevel (struct net_device *dev, u32 level)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering the Net Dev...\n");
- if(Adapter->dev && !IS_ERR(Adapter->dev) && Adapter->bNetworkInterfaceRegistered)
- unregister_netdev(Adapter->dev);
- /* Unregister the notifier block */
- if(Adapter->bNetdeviceNotifierRegistered == TRUE)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering netdevice notifier\n");
- unregister_netdevice_notifier(&bcm_notifier_block);
- }
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+ Adapter->msg_enable = level;
}
-static int bcm_init(void)
+static const struct ethtool_ops bcm_ethtool_ops = {
+ .get_settings = bcm_get_settings,
+ .get_drvinfo = bcm_get_drvinfo,
+ .get_link = bcm_get_link,
+ .get_msglevel = bcm_get_msglevel,
+ .set_msglevel = bcm_set_msglevel,
+};
+
+int register_networkdev(PMINI_ADAPTER Adapter)
{
+ struct net_device *net = Adapter->dev;
+ PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
+ struct usb_interface *udev = IntfAdapter->interface;
+ struct usb_device *xdev = IntfAdapter->udev;
+
int result;
- result = InterfaceInitialize();
- if(result)
- {
- printk("Initialisation failed for usbbcm");
- }
- else
- {
- printk("Initialised usbbcm");
+
+ net->netdev_ops = &bcmNetDevOps;
+ net->ethtool_ops = &bcm_ethtool_ops;
+ net->mtu = MTU_SIZE; /* 1400 Bytes */
+ net->tx_queue_len = TX_QLEN;
+ net->flags |= IFF_NOARP;
+
+ netif_carrier_off(net);
+
+ SET_NETDEV_DEVTYPE(net, &wimax_type);
+
+ /* Read the MAC Address from EEPROM */
+ result = ReadMacAddressFromNVM(Adapter);
+ if (result != STATUS_SUCCESS) {
+ dev_err(&udev->dev,
+ PFX "Error in Reading the mac Address: %d", result);
+ return -EIO;
}
- return result;
-}
+ result = register_netdev(net);
+ if (result)
+ return result;
-static void bcm_exit(void)
-{
- printk("%s %s Calling InterfaceExit\n",__FILE__, __FUNCTION__);
- InterfaceExit();
- printk("%s %s InterfaceExit returned\n",__FILE__, __FUNCTION__);
-}
+ gblpnetdev = Adapter->dev;
-module_init(bcm_init);
-module_exit(bcm_exit);
-MODULE_LICENSE ("GPL");
+ if (netif_msg_probe(Adapter))
+ dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n",
+ net->name, xdev->bus->bus_name, xdev->devpath,
+ net->dev_addr);
+ return 0;
+}
+void unregister_networkdev(PMINI_ADAPTER Adapter)
+{
+ struct net_device *net = Adapter->dev;
+ PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
+ struct usb_interface *udev = IntfAdapter->interface;
+ struct usb_device *xdev = IntfAdapter->udev;
+
+ if (netif_msg_probe(Adapter))
+ dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n",
+ net->name, xdev->bus->bus_name, xdev->devpath);
+
+ unregister_netdev(Adapter->dev);
+}
diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c
index 6f388a374ddc..5ac45820d564 100644
--- a/drivers/staging/bcm/CmHost.c
+++ b/drivers/staging/bcm/CmHost.c
@@ -15,6 +15,7 @@ typedef enum _E_CLASSIFIER_ACTION
eDeleteClassifier
}E_CLASSIFIER_ACTION;
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid);
/************************************************************
* Function - SearchSfid
@@ -28,7 +29,7 @@ typedef enum _E_CLASSIFIER_ACTION
* Returns - Queue index for this SFID(If matched)
Else Invalid Queue Index(If Not matched)
************************************************************/
-__inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
+INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
{
INT iIndex=0;
for(iIndex=(NO_OF_QUEUES-1); iIndex>=0; iIndex--)
@@ -47,26 +48,16 @@ __inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
* Returns - Queue index for the free SFID
* Else returns Invalid Index.
****************************************************************/
-__inline INT SearchFreeSfid(PMINI_ADAPTER Adapter)
+static INT SearchFreeSfid(PMINI_ADAPTER Adapter)
{
UINT uiIndex=0;
+
for(uiIndex=0; uiIndex < (NO_OF_QUEUES-1); uiIndex++)
if(Adapter->PackInfo[uiIndex].ulSFID==0)
return uiIndex;
return NO_OF_QUEUES+1;
}
-__inline int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid)
-{
- int iIndex=0;
- for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--)
- if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
- return iIndex;
- return NO_OF_QUEUES+1;
-
-}
-
-
/*
Function: SearchClsid
Description: This routinue would search Classifier having specified ClassifierID as input parameter
@@ -76,7 +67,7 @@ Input parameters: PMINI_ADAPTER Adapter - Adapter Context
Return: int :Classifier table index of matching entry
*/
-__inline int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16 uiClassifierID)
+static int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16 uiClassifierID)
{
unsigned int uiClassifierIndex = 0;
for(uiClassifierIndex=0;uiClassifierIndex<MAX_CLASSIFIERS;uiClassifierIndex++)
@@ -94,7 +85,7 @@ __inline int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16 uiClassifi
This routinue would search Free available Classifier entry in classifier table.
@return free Classifier Entry index in classifier table for specified SF
*/
-static __inline int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
+static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
)
{
unsigned int uiClassifierIndex = 0;
@@ -106,7 +97,7 @@ static __inline int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
return MAX_CLASSIFIERS+1;
}
-VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
+static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
{
//deleting all the packet held in the SF
flush_queue(Adapter,uiSearchRuleIndex);
@@ -985,7 +976,7 @@ static VOID CopyToAdapter( register PMINI_ADAPTER Adapter, /**<Pointer to the A
if(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication)
{
- bcm_kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication);
+ kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication);
Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = NULL;
}
Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = pstAddIndication;
@@ -1061,12 +1052,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X",
pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X",
- pstAddIndication->sfAuthorizedSet.u32MinimumTolerableTrafficRate);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X",
- pstAddIndication->sfAuthorizedSet.u32RequesttransmissionPolicy);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength : 0x%X",
pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam : 0x%X",
@@ -1114,13 +1099,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfAuthorizedSet.u8PagingPreference);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UnsolicitedPollingInterval : 0x%X",
pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignmentLength : 0x%X",
- pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignmentLength);
- for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignment : 0x%X",
- pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "sfAuthorizedSet.u8HARQChannelMapping %x %x %x ",
*(unsigned int*)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping,
@@ -1158,11 +1136,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u8ProtocolLength :0x%X ",
- psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol : 0x%02X ",
@@ -1278,14 +1251,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfAdmittedSet.u8QosParamSet);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority : 0x%02X",
pstAddIndication->sfAdmittedSet.u8TrafficPriority);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MaxSustainedTrafficRate : 0x%02X",
- ntohl(pstAddIndication->sfAdmittedSet.u32MaxSustainedTrafficRate));
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X",
- pstAddIndication->sfAdmittedSet.u32MinimumTolerableTrafficRate);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X",
- pstAddIndication->sfAdmittedSet.u32RequesttransmissionPolicy);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst : 0x%X",
pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X",
@@ -1339,13 +1304,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfAdmittedSet.u16TimeBase);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference : 0x%X",
pstAddIndication->sfAdmittedSet.u8PagingPreference);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignmentLength : 0x%X",
- pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignmentLength);
- for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignment : 0x%X",
- pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference : 0x%02X",
@@ -1378,11 +1336,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolLength :0x%02X ",
- psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ",
psfCSType->cCPacketClassificationRule.u8Protocol);
@@ -1497,20 +1450,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfActiveSet.u8QosParamSet);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority : 0x%02X",
pstAddIndication->sfActiveSet.u8TrafficPriority);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MaxSustainedTrafficRate : 0x%02X",
- ntohl(pstAddIndication->sfActiveSet.u32MaxSustainedTrafficRate));
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst : 0x%X",
pstAddIndication->sfActiveSet.u32MaxTrafficBurst);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X",
pstAddIndication->sfActiveSet.u32MinReservedTrafficRate);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X",
- pstAddIndication->sfActiveSet.u32MinimumTolerableTrafficRate);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X",
- pstAddIndication->sfActiveSet.u32RequesttransmissionPolicy);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength : 0x%02X",
pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam : 0x%02X",
@@ -1558,13 +1501,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
pstAddIndication->sfActiveSet.u16TimeBase);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8PagingPreference : 0x%X",
pstAddIndication->sfActiveSet.u8PagingPreference);
-#if 0
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " MBSZoneIdentifierassignmentLength : 0x%X",
- pstAddIndication->sfActiveSet.MBSZoneIdentifierassignmentLength);
- for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " MBSZoneIdentifierassignment : 0x%X",
- pstAddIndication->sfActiveSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TrafficIndicationPreference : 0x%X",
@@ -1597,11 +1533,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " u8ProtocolLength :0x%X ",
- psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8Protocol : 0x%X ",
psfCSType->cCPacketClassificationRule.u8Protocol);
@@ -1706,12 +1637,8 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet
return 0;
}
ulAddrSFParamSet = ntohl(ulAddrSFParamSet);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " RestoreSFParam: Total Words of DSX Message To Read: 0x%zx From Target At : 0x%lx ",
- nBytesToRead/sizeof(ULONG),ulAddrSFParamSet);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "sizeof(stServiceFlowParamSI) = %zx", sizeof(stServiceFlowParamSI));
//Read out the SF Param Set At the indicated Location
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "nBytesToRead = %x", nBytesToRead);
if(rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0)
return STATUS_FAILURE;
@@ -1719,23 +1646,20 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet
}
-static __inline ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG ulAddrSFParamSet)
+static ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG ulAddrSFParamSet)
{
UINT nBytesToWrite = sizeof(stServiceFlowParamSI);
- UINT uiRetVal =0;
+ int ret = 0;
if(ulAddrSFParamSet == 0 || NULL == pucSrcBuffer)
{
return 0;
}
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " StoreSFParam: Total Words of DSX Message To Write: 0x%zX To Target At : 0x%lX ",(nBytesToWrite/sizeof(ULONG)),ulAddrSFParamSet);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "WRM with %x bytes",nBytesToWrite);
-
- uiRetVal = wrm(Adapter,ulAddrSFParamSet,(PUCHAR)pucSrcBuffer, nBytesToWrite);
- if(uiRetVal < 0) {
+ ret = wrm(Adapter, ulAddrSFParamSet, (u8 *)pucSrcBuffer, nBytesToWrite);
+ if (ret < 0) {
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "%s:%d WRM failed",__FUNCTION__, __LINE__);
- return uiRetVal;
+ return ret;
}
return 1;
}
@@ -1778,7 +1702,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p
}
// For DSA_REQ, only upto "psfAuthorizedSet" parameter should be accessed by driver!
- pstAddIndication=(stLocalSFAddIndication *)kmalloc(sizeof(*pstAddIndication), GFP_KERNEL);
+ pstAddIndication=kmalloc(sizeof(*pstAddIndication), GFP_KERNEL);
if(NULL==pstAddIndication)
return 0;
@@ -1844,7 +1768,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p
(*puBufferLength) = sizeof(stLocalSFAddIndication);
*(stLocalSFAddIndication *)pvBuffer = *pstAddIndication;
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
return 1;
}
@@ -1931,7 +1855,7 @@ static inline stLocalSFAddIndicationAlt
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
return pstAddIndicationDest;
failed_restore_sf_param:
- bcm_kfree(pstAddIndicationDest);
+ kfree(pstAddIndicationDest);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "<=====" );
return NULL;
}
@@ -1988,7 +1912,7 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter)
return 1;
}
-ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid)
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid)
{
ULONG ulTargetDSXBufferAddress;
ULONG ulTargetDsxBufferIndexToUse,ulMaxTry;
@@ -2049,7 +1973,7 @@ INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
{
if(Adapter->caDsxReqResp)
{
- bcm_kfree(Adapter->caDsxReqResp);
+ kfree(Adapter->caDsxReqResp);
}
return 0;
@@ -2102,7 +2026,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " VCID = %x", ntohs(pstAddIndication->u16VCID));
CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
}
break;
case DSA_RSP:
@@ -2118,7 +2042,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
case DSA_ACK:
{
UINT uiSearchRuleIndex=0;
- struct timeval tv = {0};
+
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X",
ntohs(pstAddIndication->u16VCID));
uiSearchRuleIndex=SearchFreeSfid(Adapter);
@@ -2169,7 +2093,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
}
else if(psfLocalSet->bValid && (pstAddIndication->u8CC == 0))
@@ -2200,14 +2124,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
if(!Adapter->LinkUpStatus)
{
netif_carrier_on(Adapter->dev);
- netif_start_queue(Adapter->dev);
+ netif_start_queue(Adapter->dev);
Adapter->LinkUpStatus = 1;
- do_gettimeofday(&tv);
-
+ if (netif_msg_link(Adapter))
+ pr_info(PFX "%s: link up\n", Adapter->dev->name);
atomic_set(&Adapter->TxPktAvail, 1);
wake_up(&Adapter->tx_packet_wait_queue);
- Adapter->liTimeSinceLastNetEntry = tv.tv_sec;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============Tx Service Flow Created!");
+ Adapter->liTimeSinceLastNetEntry = get_seconds();
}
}
}
@@ -2218,13 +2141,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
}
}
else
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID");
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
return FALSE;
}
}
@@ -2239,7 +2162,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP;
CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
}
break;
case DSC_RSP:
@@ -2312,13 +2235,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
else if(pstChangeIndication->u8CC == 6)
{
deleteSFBySfid(Adapter,uiSearchRuleIndex);
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
}
}
else
{
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID");
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
return FALSE;
}
}
@@ -2355,7 +2278,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**<Pointer to the Adap
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n");
break;
default:
- bcm_kfree(pstAddIndication);
+ kfree(pstAddIndication);
return FALSE ;
}
return TRUE;
diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h
index 847782c3765b..8f689769b4ba 100644
--- a/drivers/staging/bcm/CmHost.h
+++ b/drivers/staging/bcm/CmHost.h
@@ -150,8 +150,6 @@ typedef struct stLocalSFChangeIndicationAlt{
ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *puBufferLength);
-ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid);
-
INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
@@ -159,7 +157,6 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter);
BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer);
-VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex);
#pragma pack (pop)
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 8907e211d483..1c7db81a1ee8 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -1,6 +1,5 @@
#include "headers.h"
-#ifndef BCM_SHM_INTERFACE
#define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00
@@ -188,17 +187,6 @@ static DDR_SET_NODE asDPLL_266MHZ[] = {
{0x0f000840,0x0FFF1B00},
{0x0f000870,0x00000002}
};
-#if 0
-static DDR_SET_NODE asDPLL_800MHZ[] = {
- {0x0f000810,0x00000F95},
- {0x0f000810,0x00000F95},
- {0x0f000810,0x00000F95},
- {0x0f000820,0x03F1365B},
- {0x0f000840,0x0FFF0000},
- {0x0f000880,0x000003DD},
- {0x0f000860,0x00000000}
- };
-#endif
#define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11 //index for 0x0F007000
static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {// # DPLL Clock Setting
@@ -788,7 +776,7 @@ int ddr_init(MINI_ADAPTER *Adapter)
{
PDDR_SETTING psDDRSetting=NULL;
ULONG RegCount=0;
- ULONG value = 0;
+ UINT value = 0;
UINT uiResetValue = 0;
UINT uiClockSetting = 0;
int retval = STATUS_SUCCESS;
@@ -982,7 +970,7 @@ int ddr_init(MINI_ADAPTER *Adapter)
{
value = psDDRSetting->ulRegValue;
}
- retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, (PUINT)&value, sizeof(value));
+ retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value));
if(STATUS_SUCCESS != retval) {
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
break;
@@ -1298,5 +1286,4 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
return retval;
}
-#endif
diff --git a/drivers/staging/bcm/Debug.c b/drivers/staging/bcm/Debug.c
deleted file mode 100644
index 2703f304756d..000000000000
--- a/drivers/staging/bcm/Debug.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "headers.h"
-
-static UINT current_debug_level=BCM_SCREAM;
-
-int bcm_print_buffer( UINT debug_level, const char *function_name,
- char *file_name, int line_number, unsigned char *buffer, int bufferlen, enum _BASE_TYPE base)
-{
- static const char * const buff_dump_base[] = {
- "DEC", "HEX", "OCT", "BIN"
- };
- if(debug_level>=current_debug_level)
- {
- int i=0;
- printk("\n%s:%s:%d:Buffer dump of size 0x%x in the %s:\n", file_name, function_name, line_number, bufferlen, buff_dump_base[1]);
- for(;i<bufferlen;i++)
- {
- if(i && !(i%16) )
- printk("\n");
- switch(base)
- {
- case BCM_BASE_TYPE_DEC:
- printk("%03d ", buffer[i]);
- break;
- case BCM_BASE_TYPE_OCT:
- printk("%0x03o ", buffer[i]);
- break;
- case BCM_BASE_TYPE_BIN:
- printk("%02x ", buffer[i]);
- break;
- case BCM_BASE_TYPE_HEX:
- default:
- printk("%02X ", buffer[i]);
- break;
- }
- }
- printk("\n");
- }
- return 0;
-}
-
-
diff --git a/drivers/staging/bcm/Debug.h b/drivers/staging/bcm/Debug.h
index 3d788b59ab57..3138729cf34f 100644
--- a/drivers/staging/bcm/Debug.h
+++ b/drivers/staging/bcm/Debug.h
@@ -9,34 +9,6 @@
#include <linux/string.h>
#define NONE 0xFFFF
-typedef enum _BASE_TYPE
-{
- BCM_BASE_TYPE_DEC,
- BCM_BASE_TYPE_OCT,
- BCM_BASE_TYPE_BIN,
- BCM_BASE_TYPE_HEX,
- BCM_BASE_TYPE_NONE,
-} BASE_TYPE, *PBASE_TYPE;
-
-int bcm_print_buffer( UINT debug_level, const char *function_name,
- char *file_name, int line_number, unsigned char *buffer, int bufferlen, BASE_TYPE base);
-
-#ifdef BCM_SHM_INTERFACE
-#define CPE_VIRTUAL_ERROR_CODE_BASE_ADDR (0xBFC02E00 + 0x4C)
-// ERROR codes for debugging
-extern unsigned char u32ErrorCounter ;
-#define ERROR_DEVICE_REMOVED 0x1
-#define ERROR_LEADER_LENGTH_ZERO 0x2
-#define ERROR_LEADER_LENGTH_CORRUPTED 0x3
-#define ERROR_NO_SKBUFF 0x4
-
-#define ERROR_DL_MODULE 0xaa000000
-extern void CPE_ERROR_LOG(unsigned int module,unsigned int code);
-
-#endif
-
-
-
//--------------------------------------------------------------------------------
@@ -242,44 +214,34 @@ typedef struct _S_BCM_DEBUG_STATE {
//--- Only for direct printk's; "hidden" to API.
#define DBG_TYPE_PRINTK 3
-#define PRINTKS_ON 1 // "hidden" from API, set to 0 to turn off all printk's
-
-#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) do { \
- if ((DBG_TYPE_PRINTK == Type) && (PRINTKS_ON)) { \
- printk ("%s:" string, __FUNCTION__, ##args); \
- printk("\n"); \
- } else if (!Adapter) \
- ; \
- else { \
- if (((dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level) && \
- ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \
- if (dbg_level & DBG_NO_FUNC_PRINT) \
- printk (string, ##args); \
- else \
- { \
- printk ("%s:" string, __FUNCTION__, ##args); \
- printk("\n"); \
- } \
- } \
- } \
-} while (0)
-#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) do { \
- if ((DBG_TYPE_PRINTK == Type) && (PRINTKS_ON)) { \
- bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \
- } else if (!Adapter) \
- ; \
- else { \
- if (((dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level) && \
- ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \
- if (dbg_level & DBG_NO_FUNC_PRINT) \
- bcm_print_buffer( dbg_level, NULL, NULL, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \
- else \
- bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \
- } \
- } \
+#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \
+ do { \
+ if (DBG_TYPE_PRINTK == Type) \
+ pr_info("%s:" string, __func__, ##args); \
+ else if (Adapter && \
+ (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \
+ (Type & Adapter->stDebugState.type) && \
+ (SubType & Adapter->stDebugState.subtype[Type])) { \
+ if (dbg_level & DBG_NO_FUNC_PRINT) \
+ printk(KERN_DEBUG string, ##args); \
+ else \
+ printk(KERN_DEBUG "%s:" string, __func__, ##args); \
+ } \
} while (0)
+#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) do { \
+ if (DBG_TYPE_PRINTK == Type || \
+ (Adapter && \
+ (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \
+ (Type & Adapter->stDebugState.type) && \
+ (SubType & Adapter->stDebugState.subtype[Type]))) { \
+ printk(KERN_DEBUG "%s:\n", __func__); \
+ print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, \
+ 16, 1, buffer, bufferlen, false); \
+ } \
+} while(0)
+
#define BCM_SHOW_DEBUG_BITMAP(Adapter) do { \
int i; \
diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c
index 7b2ec28a4bc1..2b1e9e17e11c 100644
--- a/drivers/staging/bcm/HandleControlPacket.c
+++ b/drivers/staging/bcm/HandleControlPacket.c
@@ -11,8 +11,7 @@ When a control packet is received, analyze the
Enqueue the control packet for Application.
@return None
*/
-VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**<Pointer to the Adapter structure*/
- struct sk_buff *skb) /**<Pointer to the socket buffer*/
+static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb)
{
PPER_TARANG_DATA pTarang = NULL;
BOOLEAN HighPriorityMessage = FALSE;
@@ -20,8 +19,10 @@ VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**<Pointer to the Adapter
CHAR cntrl_msg_mask_bit = 0;
BOOLEAN drop_pkt_flag = TRUE ;
USHORT usStatus = *(PUSHORT)(skb->data);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "=====>");
- /* Get the Leader field */
+
+ if (netif_msg_pktdata(Adapter))
+ print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE,
+ 16, 1, skb->data, skb->len, 0);
switch(usStatus)
{
@@ -134,7 +135,7 @@ VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**<Pointer to the Adapter
}
up(&Adapter->RxAppControlQueuelock);
wake_up(&Adapter->process_read_wait_queue);
- bcm_kfree_skb(skb);
+ dev_kfree_skb(skb);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "After wake_up_interruptible");
}
@@ -185,33 +186,7 @@ int control_packet_handler (PMINI_ADAPTER Adapter /**< pointer to adapter obje
{
DEQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail);
// Adapter->RxControlHead=ctrl_packet->next;
- ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_packets++;
- ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_bytes+=
- ((PLEADER)ctrl_packet->data)->PLength;
- }
- #if 0 //Idle mode debug profiling...
- if(*(PUSHORT)ctrl_packet->data == IDLE_MODE_STATUS)
- {
- puiBuffer = (PUINT)(ctrl_packet->data +sizeof(USHORT));
- if((ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD))
- {
- memset(&tv, 0, sizeof(tv));
- do_gettimeofday(&tv);
- if((ntohl(*(puiBuffer+1)) == 0))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode Wake-up Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode req Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
- }
- }
- else if((ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "GOT IDLE_MODE_SF_UPDATE MSG at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
- }
}
- #endif
spin_unlock_irqrestore (&Adapter->control_queue_lock, flags);
handle_rx_control_packet(Adapter, ctrl_packet);
@@ -234,7 +209,7 @@ INT flushAllAppQ(void)
{
PacketToDrop=pTarang->RxAppControlHead;
DEQUEUEPACKET(pTarang->RxAppControlHead,pTarang->RxAppControlTail);
- bcm_kfree_skb(PacketToDrop);
+ dev_kfree_skb(PacketToDrop);
}
pTarang->AppCtrlQueueLen = 0;
//dropped contrl packet statistics also should be reset.
diff --git a/drivers/staging/bcm/HostMibs.h b/drivers/staging/bcm/HostMibs.h
deleted file mode 100644
index 28a578311378..000000000000
--- a/drivers/staging/bcm/HostMibs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _HOST_MIBS_H
-#define _HOST_MIBS_H
-
-INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
- PVOID ioBuffer,
- ULONG inputBufferLength);
-#endif
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
index 5ec3b896c6a7..91b6fbe33c91 100644
--- a/drivers/staging/bcm/IPv6Protocol.c
+++ b/drivers/staging/bcm/IPv6Protocol.c
@@ -1,5 +1,9 @@
#include "headers.h"
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
+
static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
{
UCHAR *pucRetHeaderPtr = NULL;
@@ -257,7 +261,7 @@ USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
}
-BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
{
UINT uiLoopIndex=0;
UINT uiIpv6AddIndex=0;
@@ -310,7 +314,7 @@ BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pst
return FALSE;
}
-BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
{
UINT uiLoopIndex=0;
UINT uiIpv6AddIndex=0;
@@ -376,7 +380,7 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
}
-VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
+static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
{
UCHAR ucVersion;
UCHAR ucPrio ;
diff --git a/drivers/staging/bcm/IPv6ProtocolHdr.h b/drivers/staging/bcm/IPv6ProtocolHdr.h
index b93f7902e283..a0db5a1de763 100644
--- a/drivers/staging/bcm/IPv6ProtocolHdr.h
+++ b/drivers/staging/bcm/IPv6ProtocolHdr.h
@@ -101,15 +101,12 @@ typedef enum _E_IPADDR_CONTEXT
//Function Prototypes
-BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
-BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
S_CLASSIFIER_RULE *pstClassifierRule );
VOID DumpIpv6Address(ULONG *puIpv6Address);
-VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
extern BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
extern BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c
index 60c0f29f3eef..df64acb06126 100644
--- a/drivers/staging/bcm/InterfaceDld.c
+++ b/drivers/staging/bcm/InterfaceDld.c
@@ -1,20 +1,18 @@
#include "headers.h"
-#ifndef BCM_SHM_INTERFACE
int InterfaceFileDownload( PVOID arg,
struct file *flp,
unsigned int on_chip_loc)
{
- char *buff=NULL;
// unsigned int reg=0;
mm_segment_t oldfs={0};
int errno=0, len=0 /*,is_config_file = 0*/;
loff_t pos=0;
PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg;
//PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter;
+ char *buff=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
- buff=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
if(!buff)
{
return -ENOMEM;
@@ -49,7 +47,7 @@ int InterfaceFileDownload( PVOID arg,
on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB;
}/* End of for(;;)*/
- bcm_kfree(buff);
+ kfree(buff);
return errno;
}
@@ -57,7 +55,7 @@ int InterfaceFileReadbackFromChip( PVOID arg,
struct file *flp,
unsigned int on_chip_loc)
{
- char *buff=NULL, *buff_readback=NULL;
+ char *buff, *buff_readback;
unsigned int reg=0;
mm_segment_t oldfs={0};
int errno=0, len=0, is_config_file = 0;
@@ -66,12 +64,12 @@ int InterfaceFileReadbackFromChip( PVOID arg,
INT Status = STATUS_SUCCESS;
PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg;
- buff=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA);
- buff_readback=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
+ buff=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA);
+ buff_readback=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
if(!buff || !buff_readback)
{
- bcm_kfree(buff);
- bcm_kfree(buff_readback);
+ kfree(buff);
+ kfree(buff_readback);
return -ENOMEM;
}
@@ -138,8 +136,8 @@ int InterfaceFileReadbackFromChip( PVOID arg,
on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB;
}/* End of while(1)*/
exit:
- bcm_kfree(buff);
- bcm_kfree(buff_readback);
+ kfree(buff);
+ kfree(buff_readback);
return Status;
}
@@ -165,7 +163,7 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter,
psFwInfo->pvMappedFirmwareAddress, psFwInfo->u32FirmwareLength);
if(retval)
{
- bcm_kfree (Adapter->pstargetparams);
+ kfree(Adapter->pstargetparams);
Adapter->pstargetparams = NULL;
return -EFAULT;
}
@@ -231,41 +229,6 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter,
return retval;
}
-#if 0
-static int bcm_download_buffer(PMINI_ADAPTER Adapter,
- unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
- unsigned long u32StartingAddress)
-{
- char *buff=NULL;
- unsigned int len = 0;
- int retval = STATUS_SUCCESS;
- buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
-
- len = u32FirmwareLength;
-
- while(u32FirmwareLength)
- {
- len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
- if(STATUS_SUCCESS != (retval = copy_from_user(buff,
- (unsigned char *)mappedbuffer, len)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n");
- break;
- }
- retval = wrm (Adapter, u32StartingAddress, buff, len);
- if(retval)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "wrm failed\n");
- break;
- }
- u32StartingAddress += len;
- u32FirmwareLength -= len;
- mappedbuffer +=len;
- }
- bcm_kfree(buff);
- return retval;
-}
-#endif
static int bcm_compare_buff_contents(unsigned char *readbackbuff,
unsigned char *buff,unsigned int len)
{
@@ -297,58 +260,6 @@ static int bcm_compare_buff_contents(unsigned char *readbackbuff,
}
return retval;
}
-#if 0
-static int bcm_buffer_readback(PMINI_ADAPTER Adapter,
- unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
- unsigned long u32StartingAddress)
-{
- unsigned char *buff = NULL;
- unsigned char *readbackbuff = NULL;
- unsigned int len = u32FirmwareLength;
- int retval = STATUS_SUCCESS;
-
- buff=(unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
- if(NULL == buff)
- return -ENOMEM;
- readbackbuff = (unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,
- GFP_KERNEL);
- if(NULL == readbackbuff)
- {
- bcm_kfree(buff);
- return -ENOMEM;
- }
- while (u32FirmwareLength && !retval)
- {
- len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
-
- /* read from the appl buff and then read from the target, compare */
- if(STATUS_SUCCESS != (retval = copy_from_user(buff,
- (unsigned char *)mappedbuffer, len)))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n");
- break;
- }
- retval = rdm (Adapter, u32StartingAddress, readbackbuff, len);
- if(retval)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "rdm failed\n");
- break;
- }
-
- if (STATUS_SUCCESS !=
- (retval = bcm_compare_buff_contents (readbackbuff, buff, len)))
- {
- break;
- }
- u32StartingAddress += len;
- u32FirmwareLength -= len;
- mappedbuffer +=len;
- }/* end of while (u32FirmwareLength && !retval) */
- bcm_kfree(buff);
- bcm_kfree(readbackbuff);
- return retval;
-}
-#endif
int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
{
int retval = STATUS_SUCCESS;
@@ -375,7 +286,7 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
else
{
- buff = (PUCHAR)kzalloc(psFwInfo->u32FirmwareLength,GFP_KERNEL);
+ buff = kzalloc(psFwInfo->u32FirmwareLength,GFP_KERNEL);
if(buff==NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"Failed in allocation memory");
@@ -389,23 +300,6 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
goto error ;
}
- #if 0
- retval = bcm_download_buffer(Adapter,
- (unsigned char *)psFwInfo->pvMappedFirmwareAddress,
- psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress);
- if(retval != STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "User space buffer download fails....");
- }
- retval = bcm_buffer_readback (Adapter,
- (unsigned char *)psFwInfo->pvMappedFirmwareAddress,
- psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress);
-
- if(retval != STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "read back verifier failed ....");
- }
- #endif
retval = buffDnldVerify(Adapter,
buff,
psFwInfo->u32FirmwareLength,
@@ -417,7 +311,7 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
}
}
error:
- bcm_kfree(buff);
+ kfree(buff);
return retval;
}
@@ -450,11 +344,10 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter,
PUCHAR mappedbuffer, UINT u32FirmwareLength,
ULONG u32StartingAddress)
{
- PUCHAR readbackbuff = NULL;
UINT len = u32FirmwareLength;
INT retval = STATUS_SUCCESS;
+ PUCHAR readbackbuff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,GFP_KERNEL);
- readbackbuff = (PUCHAR)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,GFP_KERNEL);
if(NULL == readbackbuff)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "MEMORY ALLOCATION FAILED");
@@ -480,7 +373,7 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter,
u32FirmwareLength -= len;
mappedbuffer +=len;
}/* end of while (u32FirmwareLength && !retval) */
- bcm_kfree(readbackbuff);
+ kfree(readbackbuff);
return retval;
}
@@ -506,5 +399,4 @@ error:
return status;
}
-#endif
diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c
index 0750382733ff..bf5c0ad86610 100644
--- a/drivers/staging/bcm/InterfaceIdleMode.c
+++ b/drivers/staging/bcm/InterfaceIdleMode.c
@@ -98,14 +98,6 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
Adapter->bTriedToWakeUpFromlowPowerMode = FALSE;
wake_up(&Adapter->lowpower_mode_wait_queue);
- #if 0
- if(Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"LED Thread is Running. Hence Setting the LED Event as IDLEMODE_EXIT");
- Adapter->DriverState = IDLEMODE_EXIT;
- wake_up(&Adapter->LEDInfo.notify_led_event);
- }
- #endif
}
else
@@ -154,17 +146,7 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
return status;
}
-
-VOID InterfaceWriteIdleModeWakePattern(PMINI_ADAPTER Adapter)
-{
-/* BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Low, 0x1d1e);
- BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Low, 0x1d1e);
- BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Upp, 0xd0ea);
- BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Upp, 0xd0ea);*/
- return;
-}
-
-int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
+static int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
{
int status = STATUS_SUCCESS;
unsigned int value;
diff --git a/drivers/staging/bcm/InterfaceIdleMode.h b/drivers/staging/bcm/InterfaceIdleMode.h
index 1bc723d2d72c..859a2ffba6b7 100644
--- a/drivers/staging/bcm/InterfaceIdleMode.h
+++ b/drivers/staging/bcm/InterfaceIdleMode.h
@@ -7,8 +7,6 @@ INT InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int *puiBuffer);
VOID InterfaceWriteIdleModeWakePattern(PMINI_ADAPTER Adapter);
-INT InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern);
-
INT InterfaceWakeUp(PMINI_ADAPTER Adapter);
VOID InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter);
diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c
index 824f9a45007a..d78d5ef1f298 100644
--- a/drivers/staging/bcm/InterfaceInit.c
+++ b/drivers/staging/bcm/InterfaceInit.c
@@ -1,54 +1,63 @@
#include "headers.h"
static struct usb_device_id InterfaceUsbtable[] = {
- { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
+ { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
- { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
+ { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) },
+ { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
- {}
+ { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
+ { }
};
+MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
-VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
+static int debug = -1;
+module_param(debug, uint, 0600);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static const u32 default_msg =
+ NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+ | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
+ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+
+static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
+
+static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
{
- INT i = 0;
- // Wake up the wait_queue...
- if(psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY)
- {
+ int i = 0;
+
+ /* Wake up the wait_queue... */
+ if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;
wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);
}
reset_card_proc(psIntfAdapter->psAdapter);
- //worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms
- //to accertain the device is not being accessed. After this No RDM/WRM should be made.
- while(psIntfAdapter->psAdapter->DeviceAccess)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Device is being Accessed \n");
+ /*
+ * worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms
+ * to accertain the device is not being accessed. After this No RDM/WRM should be made.
+ */
+ while (psIntfAdapter->psAdapter->DeviceAccess) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Device is being accessed.\n");
msleep(100);
}
/* Free interrupt URB */
- //psIntfAdapter->psAdapter->device_removed = TRUE;
- if(psIntfAdapter->psInterruptUrb)
- {
- usb_free_urb(psIntfAdapter->psInterruptUrb);
- }
+ /* psIntfAdapter->psAdapter->device_removed = TRUE; */
+ usb_free_urb(psIntfAdapter->psInterruptUrb);
/* Free transmit URBs */
- for(i = 0; i < MAXIMUM_USB_TCB; i++)
- {
- if(psIntfAdapter->asUsbTcb[i].urb != NULL)
- {
+ for (i = 0; i < MAXIMUM_USB_TCB; i++) {
+ if (psIntfAdapter->asUsbTcb[i].urb != NULL) {
usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
psIntfAdapter->asUsbTcb[i].urb = NULL;
}
}
/* Free receive URB and buffers */
- for(i = 0; i < MAXIMUM_USB_RCB; i++)
- {
- if (psIntfAdapter->asUsbRcb[i].urb != NULL)
- {
- bcm_kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
+ for (i = 0; i < MAXIMUM_USB_RCB; i++) {
+ if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
+ kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
psIntfAdapter->asUsbRcb[i].urb = NULL;
}
@@ -56,151 +65,109 @@ VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
AdapterFree(psIntfAdapter->psAdapter);
}
-
-
-static int usbbcm_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int usbbcm_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t usbbcm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t usbbcm_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
+static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
{
- return 0;
-}
+ unsigned long ulReg = 0;
+ int ret;
-
-VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
-{
- ULONG ulReg = 0;
-
-// Program EP2 MAX_PKT_SIZE
+ /* Program EP2 MAX_PKT_SIZE */
ulReg = ntohl(EP2_MPS_REG);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x128,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
ulReg = ntohl(EP2_MPS);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x12C,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
ulReg = ntohl(EP2_CFG_REG);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x132,4,TRUE);
- if(((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE)
- {
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
+ if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {
ulReg = ntohl(EP2_CFG_INT);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x136,4,TRUE);
- }
- else
- {
-// USE BULK EP as TX in FS mode.
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
+ } else {
+ /* USE BULK EP as TX in FS mode. */
ulReg = ntohl(EP2_CFG_BULK);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x136,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
}
-
-// Program EP4 MAX_PKT_SIZE.
+ /* Program EP4 MAX_PKT_SIZE. */
ulReg = ntohl(EP4_MPS_REG);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x13C,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
ulReg = ntohl(EP4_MPS);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x140,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
-// Program TX EP as interrupt (Alternate Setting)
- if( rdmalt(Adapter,0x0F0110F8, (PUINT)&ulReg,4))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP is failing");
- return ;
+ /* Program TX EP as interrupt(Alternate Setting) */
+ ret = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32));
+ if (ret) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "reading of Tx EP failed\n");
+ return;
}
ulReg |= 0x6;
ulReg = ntohl(ulReg);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1CC,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
ulReg = ntohl(EP4_CFG_REG);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1C8,4,TRUE);
-// Program ISOCHRONOUS EP size to zero.
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
+ /* Program ISOCHRONOUS EP size to zero. */
ulReg = ntohl(ISO_MPS_REG);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1D2,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
ulReg = ntohl(ISO_MPS);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1D6,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
-// Update EEPROM Version.
-// Read 4 bytes from 508 and modify 511 and 510.
-//
- ReadBeceemEEPROM(Adapter,0x1FC,(PUINT)&ulReg);
+ /*
+ * Update EEPROM Version.
+ * Read 4 bytes from 508 and modify 511 and 510.
+ */
+ ReadBeceemEEPROM(Adapter, 0x1FC, (PUINT)&ulReg);
ulReg &= 0x0101FFFF;
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1FC,4,TRUE);
-//
-//Update length field if required. Also make the string NULL terminated.
-//
- ReadBeceemEEPROM(Adapter,0xA8,(PUINT)&ulReg);
- if((ulReg&0x00FF0000)>>16 > 0x30)
- {
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
+
+ /* Update length field if required. Also make the string NULL terminated. */
+
+ ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg);
+ if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0xA8,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
}
- ReadBeceemEEPROM(Adapter,0x148,(PUINT)&ulReg);
- if((ulReg&0x00FF0000)>>16 > 0x30)
- {
+ ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&ulReg);
+ if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x148,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
}
ulReg = 0;
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x122,4,TRUE);
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
ulReg = 0;
- BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1C2,4,TRUE);
-
+ BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
}
-static struct file_operations usbbcm_fops = {
- .open = usbbcm_open,
- .release = usbbcm_release,
- .read = usbbcm_read,
- .write = usbbcm_write,
- .owner = THIS_MODULE,
- .llseek = no_llseek,
-};
-
-static struct usb_class_driver usbbcm_class = {
- .name = "usbbcm",
- .fops = &usbbcm_fops,
- .minor_base = BCM_USB_MINOR_BASE,
-};
-
static int
usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- int retval =0 ;
- PMINI_ADAPTER psAdapter = NULL;
- PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
- struct usb_device *udev = NULL;
-
-// BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usbbcm probe!!");
- if((intf == NULL) || (id == NULL))
- {
- // BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf or id is NULL");
- return -EINVAL;
- }
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int retval;
+ PMINI_ADAPTER psAdapter;
+ PS_INTERFACE_ADAPTER psIntfAdapter;
+ struct net_device *ndev;
- /* Allocate Adapter structure */
- if((psAdapter = kzalloc(sizeof(MINI_ADAPTER), GFP_KERNEL)) == NULL)
- {
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory");
+ /* Reserve one extra queue for the bit-bucket */
+ ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1);
+ if (ndev == NULL) {
+ dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
return -ENOMEM;
}
- /* Init default driver debug state */
+ SET_NETDEV_DEV(ndev, &intf->dev);
- psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
+ psAdapter = netdev_priv(ndev);
+ psAdapter->dev = ndev;
+ psAdapter->msg_enable = netif_msg_init(debug, default_msg);
+
+ /* Init default driver debug state */
+
+ psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
- memset (psAdapter->stDebugState.subtype, 0, sizeof (psAdapter->stDebugState.subtype));
- /* Technically, one can start using BCM_DEBUG_PRINT after this point.
+ /*
+ * Technically, one can start using BCM_DEBUG_PRINT after this point.
* However, realize that by default the Type/Subtype bitmaps are all zero now;
* so no prints will actually appear until the TestApp turns on debug paths via
* the ioctl(); so practically speaking, in early init, no logging happens.
@@ -211,160 +178,128 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
* Further, we turn this OFF once init_module() completes.
*/
- psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
+ psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
BCM_SHOW_DEBUG_BITMAP(psAdapter);
retval = InitAdapter(psAdapter);
- if(retval)
- {
- BCM_DEBUG_PRINT (psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InitAdapter Failed\n");
+ if (retval) {
+ dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
AdapterFree(psAdapter);
return retval;
}
/* Allocate interface adapter structure */
- if((psAdapter->pvInterfaceAdapter =
- kmalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL)) == NULL)
- {
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory");
- AdapterFree (psAdapter);
+ psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL);
+ if (psIntfAdapter == NULL) {
+ dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n");
+ AdapterFree(psAdapter);
return -ENOMEM;
}
- memset(psAdapter->pvInterfaceAdapter, 0, sizeof(S_INTERFACE_ADAPTER));
- psIntfAdapter = InterfaceAdapterGet(psAdapter);
+ psAdapter->pvInterfaceAdapter = psIntfAdapter;
psIntfAdapter->psAdapter = psAdapter;
/* Store usb interface in Interface Adapter */
psIntfAdapter->interface = intf;
usb_set_intfdata(intf, psIntfAdapter);
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p",psIntfAdapter);
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "psIntfAdapter 0x%p\n", psIntfAdapter);
retval = InterfaceAdapterInit(psIntfAdapter);
- if(retval)
- {
+ if (retval) {
/* If the Firmware/Cfg File is not present
- * then return success, let the application
- * download the files.
- */
- if(-ENOENT == retval){
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "File Not Found, Use App to Download\n");
+ * then return success, let the application
+ * download the files.
+ */
+ if (-ENOENT == retval) {
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "File Not Found. Use app to download.\n");
return STATUS_SUCCESS;
}
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapterInit Failed \n");
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "InterfaceAdapterInit failed.\n");
usb_set_intfdata(intf, NULL);
- udev = interface_to_usbdev (intf);
+ udev = interface_to_usbdev(intf);
usb_put_dev(udev);
- if(psAdapter->bUsbClassDriverRegistered == TRUE)
- usb_deregister_dev (intf, &usbbcm_class);
InterfaceAdapterFree(psIntfAdapter);
- return retval ;
+ return retval;
}
- if(psAdapter->chip_id > T3)
- {
- uint32_t uiNackZeroLengthInt=4;
- if(wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt)))
- {
- return -EIO;;
- }
+ if (psAdapter->chip_id > T3) {
+ uint32_t uiNackZeroLengthInt = 4;
+
+ retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt));
+ if (retval)
+ return retval;
}
- udev = interface_to_usbdev (intf);
/* Check whether the USB-Device Supports remote Wake-Up */
- if(USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes)
- {
+ if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
/* If Suspend then only support dynamic suspend */
- if(psAdapter->bDoSuspend)
- {
+ if (psAdapter->bDoSuspend) {
#ifdef CONFIG_PM
- udev->autosuspend_delay = 0;
+ pm_runtime_set_autosuspend_delay(&udev->dev, 0);
intf->needs_remote_wakeup = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- udev->autosuspend_disabled = 0;
-#else
usb_enable_autosuspend(udev);
-#endif
- device_init_wakeup(&intf->dev,1);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
- usb_autopm_disable(intf);
-#endif
+ device_init_wakeup(&intf->dev, 1);
INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n");
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Enabling USB Auto-Suspend\n");
#endif
- }
- else
- {
+ } else {
intf->needs_remote_wakeup = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- udev->autosuspend_disabled = 1;
-#else
usb_disable_autosuspend(udev);
-#endif
}
}
- psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
- return retval;
+ psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
+ return retval;
}
-static void usbbcm_disconnect (struct usb_interface *intf)
+static void usbbcm_disconnect(struct usb_interface *intf)
{
- PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
- PMINI_ADAPTER psAdapter = NULL;
- struct usb_device *udev = NULL;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usb disconnected");
- if(intf == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf pointer is NULL");
- return;
- }
- psIntfAdapter = usb_get_intfdata(intf);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p",psIntfAdapter);
- if(psIntfAdapter == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapter pointer is NULL");
+ PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
+ PMINI_ADAPTER psAdapter;
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ if (psIntfAdapter == NULL)
return;
- }
+
psAdapter = psIntfAdapter->psAdapter;
- if(psAdapter->bDoSuspend)
+ netif_device_detach(psAdapter->dev);
+
+ if (psAdapter->bDoSuspend)
intf->needs_remote_wakeup = 0;
psAdapter->device_removed = TRUE ;
usb_set_intfdata(intf, NULL);
InterfaceAdapterFree(psIntfAdapter);
- udev = interface_to_usbdev (intf);
usb_put_dev(udev);
- usb_deregister_dev (intf, &usbbcm_class);
}
-
-static __inline int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
+static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
{
int i = 0;
- for(i = 0; i < MAXIMUM_USB_TCB; i++)
- {
- if((psIntfAdapter->asUsbTcb[i].urb =
- usb_alloc_urb(0, GFP_KERNEL)) == NULL)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Tx urb for index %d", i);
+
+ for (i = 0; i < MAXIMUM_USB_TCB; i++) {
+ if ((psIntfAdapter->asUsbTcb[i].urb =
+ usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Tx urb for index %d\n", i);
return -ENOMEM;
}
}
- for(i = 0; i < MAXIMUM_USB_RCB; i++)
- {
+ for (i = 0; i < MAXIMUM_USB_RCB; i++) {
if ((psIntfAdapter->asUsbRcb[i].urb =
- usb_alloc_urb(0, GFP_KERNEL)) == NULL)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx urb for index %d", i);
+ usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Rx urb for index %d\n", i);
return -ENOMEM;
}
- if((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
- kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx buffer for index %d", i);
+ if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
+ kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Rx buffer for index %d\n", i);
return -ENOMEM;
}
psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
@@ -372,77 +307,41 @@ static __inline int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
return 0;
}
-
-
static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
{
- INT value = 0;
+ int value = 0;
UINT status = STATUS_SUCCESS;
status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
- if(status != STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "InitCardAndDownloadFirmware failed.\n");
+ if (status != STATUS_SUCCESS) {
+ pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
return status;
}
- if(TRUE == psIntfAdapter->psAdapter->fw_download_done)
- {
-
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Sending first interrupt URB down......");
- if(StartInterruptUrb(psIntfAdapter))
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB");
+ if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
+ if (StartInterruptUrb(psIntfAdapter)) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Cannot send interrupt in URB\n");
}
- //now register the cntrl interface.
- //after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
+ /*
+ * now register the cntrl interface.
+ * after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
+ */
psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;
value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
- if(value == 0)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Mailbox Interrupt has not reached to Driver..");
- }
- else
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Got the mailbox interrupt ...Registering control interface...\n ");
- }
- if(register_control_device_interface(psIntfAdapter->psAdapter) < 0)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Register Control Device failed...");
+ if (value == 0)
+ pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
+
+ if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
+ pr_err(DRV_NAME ": Register Control Device failed.\n");
return -EIO;
}
}
return 0;
}
-#if 0
-static void print_usb_interface_desc(struct usb_interface_descriptor *usb_intf_desc)
-{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** INTERFACE DESCRIPTOR *********************");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength: %x", usb_intf_desc->bLength);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType: %x", usb_intf_desc->bDescriptorType);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceNumber: %x", usb_intf_desc->bInterfaceNumber);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bAlternateSetting: %x", usb_intf_desc->bAlternateSetting);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bNumEndpoints: %x", usb_intf_desc->bNumEndpoints);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceClass: %x", usb_intf_desc->bInterfaceClass);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceSubClass: %x", usb_intf_desc->bInterfaceSubClass);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceProtocol: %x", usb_intf_desc->bInterfaceProtocol);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "iInterface :%x\n",usb_intf_desc->iInterface);
-}
-static void print_usb_endpoint_descriptor(struct usb_endpoint_descriptor *usb_ep_desc)
-{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** ENDPOINT DESCRIPTOR *********************");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength :%x ", usb_ep_desc->bLength);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType :%x ", usb_ep_desc->bDescriptorType);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bEndpointAddress :%x ", usb_ep_desc->bEndpointAddress);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bmAttributes :%x ", usb_ep_desc->bmAttributes);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "wMaxPacketSize :%x ",usb_ep_desc->wMaxPacketSize);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterval :%x ",usb_ep_desc->bInterval);
-}
-
-#endif
static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
@@ -518,124 +417,111 @@ static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descrip
return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd));
}
-INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
+static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
- ULONG value;
- INT retval = 0;
- INT usedIntOutForBulkTransfer = 0 ;
+ unsigned long value;
+ int retval = 0;
+ int usedIntOutForBulkTransfer = 0 ;
BOOLEAN bBcm16 = FALSE;
UINT uiData = 0;
/* Store the usb dev into interface adapter */
- psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(
- psIntfAdapter->interface));
-
- if((psIntfAdapter->udev->speed == USB_SPEED_HIGH))
- {
- psIntfAdapter->bHighSpeedDevice = TRUE ;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO HIGH_SPEED ");
- }
- else
- {
- psIntfAdapter->bHighSpeedDevice = FALSE ;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO FULL_SPEED ");
- }
+ psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
+ psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
- if(rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
- return STATUS_FAILURE;
- }
- if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0)))
- {
- psIntfAdapter->psAdapter->chip_id=(psIntfAdapter->psAdapter->chip_id&~(0xF0));
+ retval = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,
+ (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32));
+ if (retval) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
+ return retval;
}
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "First RDM Chip ID 0x%lx\n", psIntfAdapter->psAdapter->chip_id);
+ if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
+ psIntfAdapter->psAdapter->chip_id &= ~0xF0;
- iface_desc = psIntfAdapter->interface->cur_altsetting;
- //print_usb_interface_desc(&(iface_desc->desc));
+ dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
+ psIntfAdapter->psAdapter->chip_id);
- if(psIntfAdapter->psAdapter->chip_id == T3B)
- {
+ iface_desc = psIntfAdapter->interface->cur_altsetting;
- //
- //T3B device will have EEPROM,check if EEPROM is proper and BCM16 can be done or not.
- //
- BeceemEEPROMBulkRead(psIntfAdapter->psAdapter,&uiData,0x0,4);
- if(uiData == BECM)
- {
+ if (psIntfAdapter->psAdapter->chip_id == T3B) {
+ /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
+ BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
+ if (uiData == BECM)
bBcm16 = TRUE;
- }
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Number of Altsetting aviailable for This Modem 0x%x\n", psIntfAdapter->interface->num_altsetting);
- if(bBcm16 == TRUE)
- {
- //selecting alternate setting one as a default setting for High Speed modem.
- if(psIntfAdapter->bHighSpeedDevice)
- retval= usb_set_interface(psIntfAdapter->udev,DEFAULT_SETTING_0,ALTERNATE_SETTING_1);
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle");
- if(retval || (psIntfAdapter->bHighSpeedDevice == FALSE))
- {
+
+ dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
+ psIntfAdapter->interface->num_altsetting);
+
+ if (bBcm16 == TRUE) {
+ /* selecting alternate setting one as a default setting for High Speed modem. */
+ if (psIntfAdapter->bHighSpeedDevice)
+ retval= usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "BCM16 is applicable on this dongle\n");
+ if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {
usedIntOutForBulkTransfer = EP2 ;
endpoint = &iface_desc->endpoint[EP2].desc;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Interface altsetting got failed or Moemd is configured to FS.hence will work on default setting 0 \n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
/*
- If Modem is high speed device EP2 should be INT OUT End point
- If Mode is FS then EP2 should be bulk end point
- */
- if(((psIntfAdapter->bHighSpeedDevice ==TRUE ) && (bcm_usb_endpoint_is_int_out(endpoint)== FALSE))
- ||((psIntfAdapter->bHighSpeedDevice == FALSE)&& (bcm_usb_endpoint_is_bulk_out(endpoint)== FALSE)))
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Configuring the EEPROM ");
- //change the EP2, EP4 to INT OUT end point
+ * If Modem is high speed device EP2 should be INT OUT End point
+ * If Mode is FS then EP2 should be bulk end point
+ */
+ if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))
+ || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Configuring the EEPROM\n");
+ /* change the EP2, EP4 to INT OUT end point */
ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
/*
- It resets the device and if any thing gets changed in USB descriptor it will show fail and
- re-enumerate the device
- */
+ * It resets the device and if any thing gets changed
+ * in USB descriptor it will show fail and re-enumerate
+ * the device
+ */
retval = usb_reset_device(psIntfAdapter->udev);
- if(retval)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n");
+ if (retval) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "reset failed. Re-enumerating the device.\n");
return retval ;
}
}
- if((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint))
- {
- // Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail.
+ if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
+ /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
UINT _uiData = ntohl(EP2_CFG_INT);
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Reverting Bulk to INT as it is FS MODE");
- BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter,(PUCHAR)&_uiData,0x136,4,TRUE);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Reverting Bulk to INT as it is in Full Speed mode.\n");
+ BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
}
- }
- else
- {
+ } else {
usedIntOutForBulkTransfer = EP4 ;
endpoint = &iface_desc->endpoint[EP4].desc;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting");
- if( bcm_usb_endpoint_is_int_out(endpoint) == FALSE)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix");
- //change the EP2, EP4 to INT OUT end point and use EP4 in altsetting
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Choosing AltSetting as a default setting.\n");
+ if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Dongle does not have BCM16 Fix.\n");
+ /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
/*
- It resets the device and if any thing gets changed in USB descriptor it will show fail and
- re-enumerate the device
- */
+ * It resets the device and if any thing gets changed in
+ * USB descriptor it will show fail and re-enumerate the
+ * device
+ */
retval = usb_reset_device(psIntfAdapter->udev);
- if(retval)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n");
- return retval ;
+ if (retval) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "reset failed. Re-enumerating the device.\n");
+ return retval;
}
}
@@ -644,99 +530,67 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
}
iface_desc = psIntfAdapter->interface->cur_altsetting;
- //print_usb_interface_desc(&(iface_desc->desc));
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Current number of endpoints :%x \n", iface_desc->desc.bNumEndpoints);
- for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value)
- {
- endpoint = &iface_desc->endpoint[value].desc;
- //print_usb_endpoint_descriptor(endpoint);
-
- if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint))
- {
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
- psIntfAdapter->sBulkIn.bulk_in_endpointAddr =
- endpoint->bEndpointAddress;
- psIntfAdapter->sBulkIn.bulk_in_pipe =
+
+ for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
+ endpoint = &iface_desc->endpoint[value].desc;
+
+ if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
+ psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkIn.bulk_in_pipe =
usb_rcvbulkpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
- }
-
- if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint))
- {
+ }
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
- endpoint->bEndpointAddress;
- psIntfAdapter->sBulkOut.bulk_out_pipe =
- usb_sndbulkpipe(psIntfAdapter->udev,
+ if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
+ psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkOut.bulk_out_pipe =
+ usb_sndbulkpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
- }
-
- if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint))
- {
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sIntrIn.int_in_size = buffer_size;
- psIntfAdapter->sIntrIn.int_in_endpointAddr =
- endpoint->bEndpointAddress;
- psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
- psIntfAdapter->sIntrIn.int_in_buffer =
+ }
+
+ if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sIntrIn.int_in_size = buffer_size;
+ psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
+ psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
+ psIntfAdapter->sIntrIn.int_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
- if (!psIntfAdapter->sIntrIn.int_in_buffer) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_in_buffer");
- return -EINVAL;
- }
- //psIntfAdapter->sIntrIn.int_in_pipe =
- }
-
- if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint))
- {
-
- if( !psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
- (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer))
- {
- //use first intout end point as a bulk out end point
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
- //printk("\nINT OUT Endpoing buffer size :%x endpoint :%x\n", buffer_size, value +1);
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
- endpoint->bEndpointAddress;
- psIntfAdapter->sBulkOut.bulk_out_pipe =
- usb_sndintpipe(psIntfAdapter->udev,
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
- psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
+ if (!psIntfAdapter->sIntrIn.int_in_buffer) {
+ dev_err(&psIntfAdapter->udev->dev,
+ "could not allocate interrupt_in_buffer\n");
+ return -EINVAL;
+ }
+ }
+ if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
+ if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
+ (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
+ /* use first intout end point as a bulk out end point */
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
+ psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
+ psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
+ psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
+ } else if (value == EP6) {
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sIntrOut.int_out_size = buffer_size;
+ psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
+ psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
+ psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, GFP_KERNEL);
+ if (!psIntfAdapter->sIntrOut.int_out_buffer) {
+ dev_err(&psIntfAdapter->udev->dev,
+ "could not allocate interrupt_out_buffer\n");
+ return -EINVAL;
+ }
}
- else if(value == EP6)
- {
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sIntrOut.int_out_size = buffer_size;
- psIntfAdapter->sIntrOut.int_out_endpointAddr =
- endpoint->bEndpointAddress;
- psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
- psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size,
- GFP_KERNEL);
- if (!psIntfAdapter->sIntrOut.int_out_buffer)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_out_buffer");
- return -EINVAL;
- }
- }
- }
- }
- usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
- retval = usb_register_dev(psIntfAdapter->interface, &usbbcm_class);
- if(retval)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb register dev failed = %d", retval);
- psIntfAdapter->psAdapter->bUsbClassDriverRegistered = FALSE;
- return retval;
- }
- else
- {
- psIntfAdapter->psAdapter->bUsbClassDriverRegistered = TRUE;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb dev registered");
+ }
}
+ usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
+
psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
InterfaceFileReadbackFromChip;
@@ -744,67 +598,51 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
retval = CreateInterruptUrb(psIntfAdapter);
- if(retval)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb");
+ if (retval) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
+ "Cannot create interrupt urb\n");
return retval;
}
retval = AllocUsbCb(psIntfAdapter);
- if(retval)
- {
+ if (retval)
return retval;
- }
-
- retval = device_run(psIntfAdapter);
- if(retval)
- {
- return retval;
- }
-
-
- return 0;
+ return device_run(psIntfAdapter);
}
-static int InterfaceSuspend (struct usb_interface *intf, pm_message_t message)
+static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
{
PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=================================\n");
- //Bcm_kill_all_URBs(psIntfAdapter);
+
psIntfAdapter->bSuspended = TRUE;
- if(TRUE == psIntfAdapter->bPreparingForBusSuspend)
- {
+ if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
psIntfAdapter->bPreparingForBusSuspend = FALSE;
- if(psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE)
- {
+ if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
psIntfAdapter->psAdapter->IdleMode = TRUE ;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode..");
- }
- else
- {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Host Entered in PMU Idle Mode.\n");
+ } else {
psIntfAdapter->psAdapter->bShutStatus = TRUE;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Shutdown Mode..");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
+ "Host Entered in PMU Shutdown Mode.\n");
}
}
psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE;
- //Signaling the control pkt path
+ /* Signaling the control pkt path */
wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
return 0;
}
-static int InterfaceResume (struct usb_interface *intf)
+static int InterfaceResume(struct usb_interface *intf)
{
- PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
- printk("=================================\n");
+ PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
mdelay(100);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
- intf->pm_usage_cnt =1 ;
-#endif
+
psIntfAdapter->bSuspended = FALSE;
StartInterruptUrb(psIntfAdapter);
@@ -812,57 +650,41 @@ static int InterfaceResume (struct usb_interface *intf)
return 0;
}
-static int InterfacePreReset(struct usb_interface *intf)
-{
- printk("====================>");
- return STATUS_SUCCESS;
-}
-
-static int InterfacePostReset(struct usb_interface *intf)
-{
- printk("Do Post chip reset setting here if it is required");
- return STATUS_SUCCESS;
-}
static struct usb_driver usbbcm_driver = {
- .name = "usbbcm",
- .probe = usbbcm_device_probe,
- .disconnect = usbbcm_disconnect,
- .suspend = InterfaceSuspend,
- .resume = InterfaceResume,
- .pre_reset=InterfacePreReset,
- .post_reset=InterfacePostReset,
- .id_table = InterfaceUsbtable,
- .supports_autosuspend = 1,
+ .name = "usbbcm",
+ .probe = usbbcm_device_probe,
+ .disconnect = usbbcm_disconnect,
+ .suspend = InterfaceSuspend,
+ .resume = InterfaceResume,
+ .id_table = InterfaceUsbtable,
+ .supports_autosuspend = 1,
};
+struct class *bcm_class;
-/*
-Function: InterfaceInitialize
-
-Description: This is the hardware specific initialization Function.
- Registering the driver with NDIS , other device specific NDIS
- and hardware initializations are done here.
-
-Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
+static __init int bcm_init(void)
+{
+ printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
+ printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
+ bcm_class = class_create(THIS_MODULE, DRV_NAME);
+ if (IS_ERR(bcm_class)) {
+ printk(KERN_ERR DRV_NAME ": could not create class\n");
+ return PTR_ERR(bcm_class);
+ }
-Return: BCM_STATUS_SUCCESS - If Initialization of the
- HW Interface was successful.
- Other - If an error occured.
-*/
-INT InterfaceInitialize(void)
-{
-// BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering Usb driver!!");
return usb_register(&usbbcm_driver);
}
-INT InterfaceExit(void)
+static __exit void bcm_exit(void)
{
- //PMINI_ADAPTER psAdapter = NULL;
- int status = 0;
-
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Deregistering Usb driver!!");
usb_deregister(&usbbcm_driver);
- return status;
+ class_destroy(bcm_class);
}
-MODULE_LICENSE ("GPL");
+
+module_init(bcm_init);
+module_exit(bcm_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h
index e7a96e5c5c50..058315a64c05 100644
--- a/drivers/staging/bcm/InterfaceInit.h
+++ b/drivers/staging/bcm/InterfaceInit.h
@@ -8,9 +8,11 @@
#define BCM_USB_PRODUCT_ID_T3 0x0300
#define BCM_USB_PRODUCT_ID_T3B 0x0210
#define BCM_USB_PRODUCT_ID_T3L 0x0220
+#define BCM_USB_PRODUCT_ID_SM250 0xbccd
#define BCM_USB_PRODUCT_ID_SYM 0x15E
#define BCM_USB_PRODUCT_ID_1901 0xe017
#define BCM_USB_PRODUCT_ID_226 0x0132
+#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007
#define BCM_USB_MINOR_BASE 192
@@ -19,33 +21,7 @@ INT InterfaceInitialize(void);
INT InterfaceExit(void);
-#ifndef BCM_SHM_INTERFACE
-INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
-
INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter);
-VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter);
-
-#else
-INT InterfaceAdapterInit(PMINI_ADAPTER Adapter);
-#endif
-
-
-#if 0
-
-ULONG InterfaceClaimAdapter(PMINI_ADAPTER Adapter);
-
-VOID InterfaceDDRControllerInit(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceReset(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceRegisterResources(PMINI_ADAPTER Adapter);
-
-VOID InterfaceUnRegisterResources(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceFirmwareDownload(PMINI_ADAPTER Adapter);
-
-#endif
-
#endif
diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c
index f928fe4d564d..220ff922bdcf 100644
--- a/drivers/staging/bcm/InterfaceIsr.c
+++ b/drivers/staging/bcm/InterfaceIsr.c
@@ -1,6 +1,5 @@
#include "headers.h"
-#ifndef BCM_SHM_INTERFACE
static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
@@ -8,6 +7,10 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)urb->context;
PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter ;
+ if (netif_msg_intr(Adapter))
+ pr_info(PFX "%s: interrupt status %d\n",
+ Adapter->dev->name, status);
+
if(Adapter->device_removed == TRUE)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed.");
@@ -87,7 +90,7 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt IN endPoint has got halted/stalled...need to clear this");
Adapter->bEndPointHalted = TRUE ;
wake_up(&Adapter->tx_packet_wait_queue);
- urb->status = STATUS_SUCCESS ;;
+ urb->status = STATUS_SUCCESS ;
return;
}
/* software-driven interface shutdown */
@@ -164,40 +167,3 @@ INT StartInterruptUrb(PS_INTERFACE_ADAPTER psIntfAdapter)
return status;
}
-/*
-Function: InterfaceEnableInterrupt
-
-Description: This is the hardware specific Function for configuring
- and enabling the interrupts on the device.
-
-Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
-
-
-Return: BCM_STATUS_SUCCESS - If configuring the interrupts was successful.
- Other - If an error occured.
-*/
-
-void InterfaceEnableInterrupt(PMINI_ADAPTER Adapter)
-{
-
-}
-
-/*
-Function: InterfaceDisableInterrupt
-
-Description: This is the hardware specific Function for disabling the interrupts on the device.
-
-Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
-
-
-Return: BCM_STATUS_SUCCESS - If disabling the interrupts was successful.
- Other - If an error occured.
-*/
-
-void InterfaceDisableInterrupt(PMINI_ADAPTER Adapter)
-{
-
-}
-
-#endif
-
diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c
index 8fc893b37fe4..a51185b522cf 100644
--- a/drivers/staging/bcm/InterfaceMisc.c
+++ b/drivers/staging/bcm/InterfaceMisc.c
@@ -1,17 +1,5 @@
#include "headers.h"
-#ifndef BCM_SHM_INTERFACE
-
-PS_INTERFACE_ADAPTER
-InterfaceAdapterGet(PMINI_ADAPTER psAdapter)
-{
- if(psAdapter == NULL)
- {
- return NULL;
- }
- return (PS_INTERFACE_ADAPTER)(psAdapter->pvInterfaceAdapter);
-}
-
INT
InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter,
UINT addr,
@@ -102,7 +90,7 @@ InterfaceWRM(PS_INTERFACE_ADAPTER psIntfAdapter,
if((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB))
{
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL,"Currently Xaction is not allowed on the bus...");
- return EACCES;
+ return -EACCES;
}
if(psIntfAdapter->bSuspended ==TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE)
@@ -236,9 +224,7 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
}
/* Cancel All submitted TX URB's */
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All Submitted TX Urbs \n");
-
- for(i = 0; i < MAXIMUM_USB_TCB; i++)
+ for(i = 0; i < MAXIMUM_USB_TCB; i++)
{
tempUrb = psIntfAdapter->asUsbTcb[i].urb;
if(tempUrb)
@@ -248,9 +234,6 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
}
}
-
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All submitted Rx Urbs \n");
-
for(i = 0; i < MAXIMUM_USB_RCB; i++)
{
tempUrb = psIntfAdapter->asUsbRcb[i].urb;
@@ -261,16 +244,11 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
}
}
-
atomic_set(&psIntfAdapter->uNumTcbUsed, 0);
atomic_set(&psIntfAdapter->uCurrTcb, 0);
atomic_set(&psIntfAdapter->uNumRcbUsed, 0);
atomic_set(&psIntfAdapter->uCurrRcb, 0);
-
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "TCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumTcbUsed), atomic_read(&psIntfAdapter->uCurrTcb));
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "RCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumRcbUsed), atomic_read(&psIntfAdapter->uCurrRcb));
-
}
VOID putUsbSuspend(struct work_struct *work)
@@ -282,9 +260,6 @@ VOID putUsbSuspend(struct work_struct *work)
if(psIntfAdapter->bSuspended == FALSE)
usb_autopm_put_interface(intf);
- else
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Interface Resumed Completely\n");
}
-#endif
diff --git a/drivers/staging/bcm/InterfaceMisc.h b/drivers/staging/bcm/InterfaceMisc.h
index 74c81d45cff4..6c9e39bf9889 100644
--- a/drivers/staging/bcm/InterfaceMisc.h
+++ b/drivers/staging/bcm/InterfaceMisc.h
@@ -1,9 +1,6 @@
#ifndef __INTERFACE_MISC_H
#define __INTERFACE_MISC_H
-PS_INTERFACE_ADAPTER
-InterfaceAdapterGet(PMINI_ADAPTER psAdapter);
-
INT
InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter,
UINT addr,
diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c
index 6fee9684f2ef..533f8ebe0f84 100644
--- a/drivers/staging/bcm/InterfaceRx.c
+++ b/drivers/staging/bcm/InterfaceRx.c
@@ -1,5 +1,15 @@
#include "headers.h"
-extern int SearchVcid(PMINI_ADAPTER , unsigned short);
+
+static int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid)
+{
+ int iIndex=0;
+
+ for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--)
+ if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
+ return iIndex;
+ return NO_OF_QUEUES+1;
+
+}
static PUSB_RCB
@@ -38,13 +48,9 @@ static void read_bulk_callback(struct urb *urb)
PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter;
PLEADER pLeader = urb->transfer_buffer;
-
- #if 0
- int *puiBuffer = NULL;
- struct timeval tv;
- memset(&tv, 0, sizeof(tv));
- do_gettimeofday(&tv);
- #endif
+ if (unlikely(netif_msg_rx_status(Adapter)))
+ pr_info(PFX "%s: rx urb status %d length %d\n",
+ Adapter->dev->name, urb->status, urb->actual_length);
if((Adapter->device_removed == TRUE) ||
(TRUE == Adapter->bEndPointHalted) ||
@@ -89,10 +95,10 @@ static void read_bulk_callback(struct urb *urb)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status,pLeader->PLength,pLeader->Vcid);
if(MAX_CNTL_PKT_SIZE < pLeader->PLength)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Corrupted leader length...%d\n",
- pLeader->PLength);
- atomic_inc(&Adapter->RxPacketDroppedCount);
- atomic_add(pLeader->PLength, &Adapter->BadRxByteCount);
+ if (netif_msg_rx_err(Adapter))
+ pr_info(PFX "%s: corrupted leader length...%d\n",
+ Adapter->dev->name, pLeader->PLength);
+ ++Adapter->dev->stats.rx_dropped;
atomic_dec(&psIntfAdapter->uNumRcbUsed);
return;
}
@@ -145,10 +151,9 @@ static void read_bulk_callback(struct urb *urb)
skb_put (skb, pLeader->PLength + ETH_HLEN);
Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength;
Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength;
- atomic_add(pLeader->PLength, &Adapter->GoodRxByteCount);
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength);
- if(Adapter->if_up)
+ if(netif_running(Adapter->dev))
{
/* Moving ahead by ETH_HLEN to the data ptr as received from FW */
skb_pull(skb, ETH_HLEN);
@@ -173,9 +178,12 @@ static void read_bulk_callback(struct urb *urb)
else
{
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB...");
- bcm_kfree_skb(skb);
+ dev_kfree_skb(skb);
}
- atomic_inc(&Adapter->GoodRxPktCount);
+
+ ++Adapter->dev->stats.rx_packets;
+ Adapter->dev->stats.rx_bytes += pLeader->PLength;
+
for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++)
{
if((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1))
diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c
index 771f7b34d2ec..a842de9de6b5 100644
--- a/drivers/staging/bcm/InterfaceTx.c
+++ b/drivers/staging/bcm/InterfaceTx.c
@@ -1,50 +1,5 @@
#include "headers.h"
-#ifndef BCM_SHM_INTERFACE
-
-/*
-Function: InterfaceTxDataPacket
-
-Description: This is the hardware specific Function for Transmitting
- data packet to the device.
-
-Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
- PVOID Packet - Packet Containing the data to be transmitted
- USHORT usVcid - VCID on which data packet is to be sent
-
-
-Return: BCM_STATUS_SUCCESS - If Tx was successful.
- Other - If an error occured.
-*/
-
-ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid)
-{
- ULONG Status = 0;
- return Status;
-}
-
-/*
-Function: InterfaceTxControlPacket
-
-Description: This is the hardware specific Function for Transmitting
- control packet to the device.
-
-Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
- PVOID pvBuffer - Buffer containg control packet
- UINT uiBufferLength - Buffer Length
-
-Return: BCM_STATUS_SUCCESS - If control packet transmit was successful.
- Other - If an error occured.
-*/
-
-ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength)
-{
- ULONG Status = 0;
-
-
-
- return Status;
-}
/*this is transmit call-back(BULK OUT)*/
static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
@@ -54,10 +9,10 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
PMINI_ADAPTER psAdapter = psIntfAdapter->psAdapter ;
BOOLEAN bpowerDownMsg = FALSE ;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-#if 0
- struct timeval tv;
- UINT time_ms = 0;
-#endif
+
+ if (unlikely(netif_msg_tx_done(Adapter)))
+ pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status);
+
if(urb->status != STATUS_SUCCESS)
{
if(urb->status == -EPIPE)
@@ -78,11 +33,6 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
if(TRUE == psAdapter->bPreparingForLowPowerMode)
{
- #if 0
- do_gettimeofday(&tv);
- time_ms = tv.tv_sec *1000 + tv.tv_usec/1000;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, " %s Idle Mode ACK_Sent got from device at time :0x%x", __FUNCTION__, time_ms);
- #endif
if(((pControlMsg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) &&
(pControlMsg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE)))
@@ -152,17 +102,12 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
}
err_exit :
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- usb_buffer_free(urb->dev, urb->transfer_buffer_length,
- urb->transfer_buffer, urb->transfer_dma);
-#else
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
-#endif
}
-static __inline PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
+static PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
{
PUSB_TCB pTcb = NULL;
UINT index = 0;
@@ -183,20 +128,14 @@ static __inline PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
return pTcb;
}
-static __inline int TransmitTcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_TCB pTcb, PVOID data, int len)
+static int TransmitTcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_TCB pTcb, PVOID data, int len)
{
struct urb *urb = pTcb->urb;
int retval = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- urb->transfer_buffer = usb_buffer_alloc(psIntfAdapter->udev, len,
- GFP_ATOMIC, &urb->transfer_dma);
-#else
urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len,
GFP_ATOMIC, &urb->transfer_dma);
-#endif
-
if (!urb->transfer_buffer)
{
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Error allocating memory\n");
@@ -255,5 +194,4 @@ int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len)
return TransmitTcb(psIntfAdapter, pTcb, data, len);
}
-#endif
diff --git a/drivers/staging/bcm/InterfaceTx.h b/drivers/staging/bcm/InterfaceTx.h
index 053f631e2042..273147577c17 100644
--- a/drivers/staging/bcm/InterfaceTx.h
+++ b/drivers/staging/bcm/InterfaceTx.h
@@ -3,11 +3,5 @@
INT InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len);
-
-ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid);
-
-ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength);
-
-
#endif
diff --git a/drivers/staging/bcm/Interfacemain.h b/drivers/staging/bcm/Interfacemain.h
deleted file mode 100644
index e0db563c5e0f..000000000000
--- a/drivers/staging/bcm/Interfacemain.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _MAIN_
-#define _MAIN_
-#if 0
-typedef struct _MINI_ADAPTER
-{
- S_INTERFACE_ADAPTER stInterfaceAdapter;
-}MINI_ADAPTER,*PMINI_ADAPTER;
-
-#endif
-#endif
diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c
index cae382313ce9..f4cf41c0e46b 100644
--- a/drivers/staging/bcm/LeakyBucket.c
+++ b/drivers/staging/bcm/LeakyBucket.c
@@ -75,14 +75,14 @@ static VOID UpdateTokenCount(register PMINI_ADAPTER Adapter)
* Returns - The number of bytes allowed for transmission.
*
***********************************************************************/
-static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
/* Validate the parameters */
if(NULL == Adapter || (psSF < Adapter->PackInfo &&
(uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority]))
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %ld\n", Adapter, (psSF-Adapter->PackInfo));
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
return 0;
}
@@ -94,51 +94,27 @@ static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %ld Available %u\n",
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount);
psSF->uiPendedLast = 1;
}
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %ld not valid\n", psSF-Adapter->PackInfo);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
return 0;
}
-static __inline void RemovePacketFromQueue(PacketInfo *pPackInfo , struct sk_buff *Packet)
-{
- struct sk_buff *psQueueCurrent=NULL, *psLastQueueNode=NULL;
- psQueueCurrent = pPackInfo->FirstTxQueue;
- while(psQueueCurrent)
- {
- if(Packet == psQueueCurrent)
- {
- if(psQueueCurrent == pPackInfo->FirstTxQueue)
- {
- pPackInfo->FirstTxQueue=psQueueCurrent->next;
- if(psQueueCurrent==pPackInfo->LastTxQueue)
- pPackInfo->LastTxQueue=NULL;
- }
- else
- {
- psLastQueueNode->next=psQueueCurrent->next;
- }
- break;
- }
- psLastQueueNode = psQueueCurrent;
- psQueueCurrent=psQueueCurrent->next;
- }
-}
/**
@ingroup tx_functions
This function despatches packet from the specified queue.
@return Zero(success) or Negative value(failure)
*/
-static __inline INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
- PacketInfo *psSF, /**<Queue identifier*/
- struct sk_buff* Packet) /**<Pointer to the packet to be sent*/
+static INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
+ PacketInfo *psSF, /**<Queue identifier*/
+ struct sk_buff* Packet) /**<Pointer to the packet to be sent*/
{
INT Status=STATUS_FAILURE;
UINT uiIndex =0,PktLen = 0;
@@ -180,8 +156,7 @@ static __inline INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapte
* Returns - None.
*
****************************************************************************/
-static __inline VOID CheckAndSendPacketFromIndex
-(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF)
{
struct sk_buff *QueuePacket=NULL;
char *pControlPacket = NULL;
@@ -189,7 +164,7 @@ static __inline VOID CheckAndSendPacketFromIndex
int iPacketLen=0;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%ld ====>", (psSF-Adapter->PackInfo));
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet
{
if(!psSF->ucDirection )
@@ -197,10 +172,8 @@ static __inline VOID CheckAndSendPacketFromIndex
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Device is in Idle Mode..Hence blocking Data Packets..\n");
- return;
- }
+ return; /* in idle mode */
+
// Check for Free Descriptors
if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS)
{
@@ -208,9 +181,6 @@ static __inline VOID CheckAndSendPacketFromIndex
return ;
}
-#if 0
- PruneQueue(Adapter,(psSF-Adapter->PackInfo));
-#endif
spin_lock_bh(&psSF->SFQueueLock);
QueuePacket=psSF->FirstTxQueue;
@@ -240,7 +210,7 @@ static __inline VOID CheckAndSendPacketFromIndex
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %ld\n", psSF-Adapter->PackInfo);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
psSF->uiCurrentTokenCount, iPacketLen);
//this part indicates that becuase of non-availability of the tokens
@@ -290,17 +260,6 @@ static __inline VOID CheckAndSendPacketFromIndex
}
}
}
-
- if(Status != STATUS_SUCCESS) //Tx of data packet to device Failed
- {
- if(Adapter->bcm_jiffies == 0)
- Adapter->bcm_jiffies = jiffies;
- }
- else
- {
- Adapter->bcm_jiffies = 0;
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<=====");
}
@@ -387,12 +346,7 @@ VOID transmit_packets(PMINI_ADAPTER Adapter)
if(exit_flag == TRUE )
break ;
}/* end of inner while loop */
- if(Adapter->bcm_jiffies == 0 &&
- atomic_read(&Adapter->TotalPacketCount) != 0 &&
- uiPrevTotalCount == atomic_read(&Adapter->TotalPacketCount))
- {
- Adapter->bcm_jiffies = jiffies;
- }
+
update_per_cid_rx (Adapter);
Adapter->txtransmit_running = 0;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h
index 0241234605f1..feb351578c8b 100644
--- a/drivers/staging/bcm/Macros.h
+++ b/drivers/staging/bcm/Macros.h
@@ -4,10 +4,6 @@
#ifndef __MACROS_H__
#define __MACROS_H__
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#define kthread_run(threadfn,data,datafmt)(struct task_struct *)kernel_thread(threadfn,data,0)
-#endif
-
#define TX_TIMER_PERIOD 10 //10 msec
#define MAX_CLASSIFIERS 100
//#define MAX_CLASSIFIERS_PER_SF 20
@@ -17,10 +13,9 @@
#define MAX_DATA_PKTS 200
#define MAX_ETH_SIZE 1536
#define MAX_CNTL_PKT_SIZE 2048
-/* TIMER RELATED */
-#define JIFFIES_2_QUADPART() (ULONG)(jiffies * 10000) // jiffies(1msec) to Quadpart(100nsec)
#define MTU_SIZE 1400
+#define TX_QLEN 5
#define MAC_ADDR_REGISTER 0xbf60d000
@@ -266,7 +261,7 @@ typedef enum _E_PHS_DSC_ACTION
#define FIRMWARE_BEGIN_ADDR 0xBFC00000
-#define INVALID_QUEUE_INDEX (USHORT)-1
+#define INVALID_QUEUE_INDEX NO_OF_QUEUES
#define INVALID_PID (pid_t)-1
#define DDR_80_MHZ 0
@@ -300,12 +295,7 @@ typedef enum _E_PHS_DSC_ACTION
/* Idle Mode Related Registers */
#define DEBUG_INTERRUPT_GENERATOR_REGISTOR 0x0F00007C
-#ifdef BCM_SHM_INTERFACE
-#define SW_ABORT_IDLEMODE_LOC 0xbfc02f9c
-#define CPE_VIRTUAL_MAILBOX_REG 0xBFC02E58
-#else
#define SW_ABORT_IDLEMODE_LOC 0x0FF01FFC
-#endif
#define SW_ABORT_IDLEMODE_PATTERN 0xd0ea1d1e
#define DEVICE_INT_OUT_EP_REG0 0x0F011870
@@ -355,12 +345,7 @@ typedef enum ePMU_MODES
HYBRID_MODE_6 = 2
}PMU_MODE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-#define MAX_RDM_WRM_RETIRES 16
-#else
#define MAX_RDM_WRM_RETIRES 1
-#endif
-
enum eAbortPattern {
ABORT_SHUTDOWN_MODE = 1,
@@ -369,27 +354,6 @@ enum eAbortPattern {
ABORT_IDLE_SYNCDOWN = 3
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
- #define GET_BCM_ADAPTER(net_dev) ({\
- PMINI_ADAPTER __Adapter = NULL; \
- if (net_dev) { \
- __Adapter = (PMINI_ADAPTER)(net_dev->priv); \
- } \
- else { \
- __Adapter = NULL; \
- }__Adapter;} )
-#else
- #define GET_BCM_ADAPTER(net_dev) ({\
- PMINI_ADAPTER __Adapter = NULL; \
- if (net_dev) { \
- __Adapter = (PMINI_ADAPTER)(*((unsigned long *)netdev_priv(net_dev))); \
- } \
- else { \
- __Adapter = NULL; \
- }__Adapter;})
-
-
-#endif
/* Offsets used by driver in skb cb variable */
#define SKB_CB_CLASSIFICATION_OFFSET 0
diff --git a/drivers/staging/bcm/Makefile b/drivers/staging/bcm/Makefile
index c3ae25af670a..652b7f87737c 100644
--- a/drivers/staging/bcm/Makefile
+++ b/drivers/staging/bcm/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_BCM_WIMAX) += bcm_wimax.o
bcm_wimax-y := InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o \
InterfaceIsr.o InterfaceMisc.o InterfaceTx.o \
- Arp.o CmHost.o Debug.o IPv6Protocol.o Qos.o Transmit.o\
+ CmHost.o IPv6Protocol.o Qos.o Transmit.o\
Bcmnet.o DDRInit.o HandleControlPacket.o\
LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\
- Osal_Misc.o led_control.o nvm.o vendorspecificextn.o
+ led_control.o nvm.o vendorspecificextn.o
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index 22550f745917..f585aae9cf8b 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -1,5 +1,12 @@
#include "headers.h"
+static int BcmFileDownload(PMINI_ADAPTER Adapter, const char *path,
+ unsigned int loc);
+static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter);
+static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer);
+static int bcm_parse_target_params(PMINI_ADAPTER Adapter);
+static void beceem_protocol_reset (PMINI_ADAPTER Adapter);
+
static VOID default_wimax_protocol_initialize(PMINI_ADAPTER Adapter)
{
@@ -60,21 +67,11 @@ InitAdapter(PMINI_ADAPTER psAdapter)
//init_waitqueue_head(&psAdapter->device_wake_queue);
psAdapter->fw_download_done=FALSE;
- psAdapter->pvOsDepData = (PLINUX_DEP_DATA) kmalloc(sizeof(LINUX_DEP_DATA),
- GFP_KERNEL);
-
- if(psAdapter->pvOsDepData == NULL)
- {
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Linux Specific Data allocation failed");
- return -ENOMEM;
- }
- memset(psAdapter->pvOsDepData, 0, sizeof(LINUX_DEP_DATA));
default_wimax_protocol_initialize(psAdapter);
for (i=0;i<MAX_CNTRL_PKTS;i++)
{
- psAdapter->txctlpacket[i] = (char *)kmalloc(MAX_CNTL_PKT_SIZE,
- GFP_KERNEL);
+ psAdapter->txctlpacket[i] = kmalloc(MAX_CNTL_PKT_SIZE, GFP_KERNEL);
if(!psAdapter->txctlpacket[i])
{
BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No More Cntl pkts got, max got is %d", i);
@@ -117,7 +114,7 @@ InitAdapter(PMINI_ADAPTER psAdapter)
VOID AdapterFree(PMINI_ADAPTER Adapter)
{
- INT count = 0;
+ int count;
beceem_protocol_reset(Adapter);
@@ -125,72 +122,66 @@ VOID AdapterFree(PMINI_ADAPTER Adapter)
if(Adapter->control_packet_handler && !IS_ERR(Adapter->control_packet_handler))
kthread_stop (Adapter->control_packet_handler);
+
if(Adapter->transmit_packet_thread && !IS_ERR(Adapter->transmit_packet_thread))
- kthread_stop (Adapter->transmit_packet_thread);
- wake_up(&Adapter->process_read_wait_queue);
+ kthread_stop (Adapter->transmit_packet_thread);
+
+ wake_up(&Adapter->process_read_wait_queue);
+
if(Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY))
kthread_stop (Adapter->LEDInfo.led_cntrl_threadid);
- bcm_unregister_networkdev(Adapter);
+
+ unregister_networkdev(Adapter);
+
+ /* FIXME: use proper wait_event and refcounting */
while(atomic_read(&Adapter->ApplicationRunning))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Waiting for Application to close.. %d\n",atomic_read(&Adapter->ApplicationRunning));
msleep(100);
}
unregister_control_device_interface(Adapter);
- if(Adapter->dev && !IS_ERR(Adapter->dev))
- free_netdev(Adapter->dev);
- if(Adapter->pstargetparams != NULL)
- {
- bcm_kfree(Adapter->pstargetparams);
- }
+
+ kfree(Adapter->pstargetparams);
+
for (count =0;count < MAX_CNTRL_PKTS;count++)
- {
- if(Adapter->txctlpacket[count])
- bcm_kfree(Adapter->txctlpacket[count]);
- }
+ kfree(Adapter->txctlpacket[count]);
+
FreeAdapterDsxBuffer(Adapter);
- if(Adapter->pvOsDepData)
- bcm_kfree (Adapter->pvOsDepData);
- if(Adapter->pvInterfaceAdapter)
- bcm_kfree(Adapter->pvInterfaceAdapter);
+
+ kfree(Adapter->pvInterfaceAdapter);
//Free the PHS Interface
PhsCleanup(&Adapter->stBCMPhsContext);
-#ifndef BCM_SHM_INTERFACE
BcmDeAllocFlashCSStructure(Adapter);
-#endif
- bcm_kfree (Adapter);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "<========\n");
+ free_netdev(Adapter->dev);
}
-
-int create_worker_threads(PMINI_ADAPTER psAdapter)
+static int create_worker_threads(PMINI_ADAPTER psAdapter)
{
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Init Threads...");
// Rx Control Packets Processing
psAdapter->control_packet_handler = kthread_run((int (*)(void *))
- control_packet_handler, psAdapter, "CtrlPktHdlr");
+ control_packet_handler, psAdapter, "%s-rx", DRV_NAME);
if(IS_ERR(psAdapter->control_packet_handler))
{
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success\n");
+ pr_notice(DRV_NAME ": could not create control thread\n");
return PTR_ERR(psAdapter->control_packet_handler);
}
+
// Tx Thread
psAdapter->transmit_packet_thread = kthread_run((int (*)(void *))
- tx_pkt_handler, psAdapter, "TxPktThread");
+ tx_pkt_handler, psAdapter, "%s-tx", DRV_NAME);
if(IS_ERR (psAdapter->transmit_packet_thread))
{
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success");
+ pr_notice(DRV_NAME ": could not creat transmit thread\n");
kthread_stop(psAdapter->control_packet_handler);
return PTR_ERR(psAdapter->transmit_packet_thread);
}
return 0;
}
-
-static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path)
+static struct file *open_firmware_file(PMINI_ADAPTER Adapter, const char *path)
{
struct file *flp=NULL;
mm_segment_t oldfs;
@@ -200,26 +191,20 @@ static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path)
set_fs(oldfs);
if(IS_ERR(flp))
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Unable To Open File %s, err %lx",
- path, PTR_ERR(flp));
- flp = NULL;
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Got file descriptor pointer of %s!",
- path);
+ pr_err(DRV_NAME "Unable To Open File %s, err %ld",
+ path, PTR_ERR(flp));
+ flp = NULL;
}
- if(Adapter->device_removed)
- {
- flp = NULL;
- }
+
+ if(Adapter->device_removed)
+ flp = NULL;
return flp;
}
-int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
- char *path, /**< path to image file */
+static int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
+ const char *path, /**< path to image file */
unsigned int loc /**< Download Address on the chip*/
)
{
@@ -248,9 +233,7 @@ int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
goto exit_download;
}
oldfs=get_fs();set_fs(get_ds());
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
vfs_llseek(flp, 0, 0);
-#endif
set_fs(oldfs);
if(Adapter->bcm_file_readback_from_chip(Adapter->pvInterfaceAdapter,
flp, loc))
@@ -265,29 +248,8 @@ exit_download:
if(flp && !(IS_ERR(flp)))
filp_close(flp, current->files);
set_fs(oldfs);
- do_gettimeofday(&tv);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "file download done at %lx", ((tv.tv_sec * 1000) +
- (tv.tv_usec/1000)));
- return errorno;
-}
-
-void bcm_kfree_skb(struct sk_buff *skb)
-{
- if(skb)
- {
- kfree_skb(skb);
- }
- skb = NULL ;
-}
-
-VOID bcm_kfree(VOID *ptr)
-{
- if(ptr)
- {
- kfree(ptr);
- }
- ptr = NULL ;
+ return errorno;
}
/**
@@ -395,13 +357,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
/*Setting bIdleMode_tx_from_host to TRUE to indicate LED control thread to represent
the wake up from idlemode is from host*/
//Adapter->LEDInfo.bIdleMode_tx_from_host = TRUE;
-#if 0
- if(STATUS_SUCCESS != InterfaceIdleModeWakeup(Adapter))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Idle Mode Wake up Failed\n");
- return STATUS_FAILURE;
- }
-#endif
Adapter->bWakeUpDevice = TRUE;
wake_up(&Adapter->process_rx_cntrlpkt);
@@ -489,9 +444,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
atomic_inc(&Adapter->index_wr_txcntrlpkt);
BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, TX_CONTROL,DBG_LVL_ALL, "Calling transmit_packets");
atomic_set(&Adapter->TxPktAvail, 1);
-#ifdef BCM_SHM_INTERFACE
- virtual_mail_box_interrupt();
-#endif
wake_up(&Adapter->tx_packet_wait_queue);
}
else
@@ -530,18 +482,6 @@ static VOID SendStatisticsPointerRequest(PMINI_ADAPTER Adapter,
#endif
-void SendLinkDown(PMINI_ADAPTER Adapter)
-{
- LINK_REQUEST stLinkDownRequest;
- memset(&stLinkDownRequest, 0, sizeof(LINK_REQUEST));
- stLinkDownRequest.Leader.Status=LINK_UP_CONTROL_REQ;
- stLinkDownRequest.Leader.PLength=sizeof(ULONG);//minimum 4 bytes
- stLinkDownRequest.szData[0]=LINK_DOWN_REQ_PAYLOAD;
- Adapter->bLinkDownRequested = TRUE;
-
- CopyBufferToControlPacket(Adapter,&stLinkDownRequest);
-}
-
/******************************************************************
* Function - LinkMessage()
*
@@ -552,7 +492,7 @@ void SendLinkDown(PMINI_ADAPTER Adapter)
*
* Returns - None.
*******************************************************************/
-__inline VOID LinkMessage(PMINI_ADAPTER Adapter)
+VOID LinkMessage(PMINI_ADAPTER Adapter)
{
PLINK_REQUEST pstLinkRequest=NULL;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "=====>");
@@ -594,7 +534,7 @@ __inline VOID LinkMessage(PMINI_ADAPTER Adapter)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Calling CopyBufferToControlPacket");
CopyBufferToControlPacket(Adapter, pstLinkRequest);
- bcm_kfree(pstLinkRequest);
+ kfree(pstLinkRequest);
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "LinkMessage <=====");
return;
@@ -614,8 +554,8 @@ __inline VOID LinkMessage(PMINI_ADAPTER Adapter)
VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s====>",__FUNCTION__);
- Adapter->StatisticsPointer = ntohl(*(PULONG)pvBuffer);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %lx", Adapter->StatisticsPointer);
+ Adapter->StatisticsPointer = ntohl(*(__be32 *)pvBuffer);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %x", (UINT)Adapter->StatisticsPointer);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s <====",__FUNCTION__);
return;
}
@@ -764,7 +704,7 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
/* Wake the LED Thread with IDLEMODE_ENTER State */
Adapter->DriverState = LOWPOWER_MODE_ENTER;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"LED Thread is Running..Hence Setting LED Event as IDLEMODE_ENTER jiffies:%ld",jiffies);;
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"LED Thread is Running..Hence Setting LED Event as IDLEMODE_ENTER jiffies:%ld",jiffies);
wake_up(&Adapter->LEDInfo.notify_led_event);
/* Wait for 1 SEC for LED to OFF */
@@ -787,12 +727,10 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
down(&Adapter->rdmwrmsync);
Adapter->bPreparingForLowPowerMode = TRUE;
up(&Adapter->rdmwrmsync);
-#ifndef BCM_SHM_INTERFACE
//Killing all URBS.
if(Adapter->bDoSuspend == TRUE)
Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
}
else
{
@@ -811,9 +749,7 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"fail to send the Idle mode Request \n");
Adapter->bPreparingForLowPowerMode = FALSE;
-#ifndef BCM_SHM_INTERFACE
StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
}
do_gettimeofday(&tv);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "IdleMode Msg submitter to Q :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
@@ -980,12 +916,10 @@ VOID DumpPackInfo(PMINI_ADAPTER Adapter)
}
-
-__inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
+int reset_card_proc(PMINI_ADAPTER ps_adapter)
{
int retval = STATUS_SUCCESS;
-#ifndef BCM_SHM_INTERFACE
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
unsigned int value = 0, uiResetValue = 0;
@@ -1006,11 +940,9 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
wrmalt(ps_adapter, SYS_CFG, &value, sizeof(value));
}
-#ifndef BCM_SHM_INTERFACE
//killing all submitted URBs.
psIntfAdapter->psAdapter->StopAllXaction = TRUE ;
Bcm_kill_all_URBs(psIntfAdapter);
-#endif
/* Reset the UMA-B Device */
if(ps_adapter->chip_id >= T3LPB)
{
@@ -1111,11 +1043,10 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
err_exit :
psIntfAdapter->psAdapter->StopAllXaction = FALSE ;
-#endif
return retval;
}
-__inline int run_card_proc(PMINI_ADAPTER ps_adapter )
+int run_card_proc(PMINI_ADAPTER ps_adapter )
{
unsigned int value=0;
{
@@ -1146,21 +1077,17 @@ __inline int run_card_proc(PMINI_ADAPTER ps_adapter )
int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
{
- UINT status = STATUS_SUCCESS;
+ int status;
UINT value = 0;
-#ifdef BCM_SHM_INTERFACE
- unsigned char *pConfigFileAddr = (unsigned char *)CPE_MACXVI_CFG_ADDR;
-#endif
/*
* Create the threads first and then download the
* Firm/DDR Settings..
*/
- if((status = create_worker_threads(ps_adapter))<0)
- {
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Cannot create thread");
+ status = create_worker_threads(ps_adapter);
+ if (status<0)
return status;
- }
+
/*
* For Downloading the Firm, parse the cfg file first.
*/
@@ -1169,7 +1096,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
return status;
}
-#ifndef BCM_SHM_INTERFACE
if(ps_adapter->chip_id >= T3LPB)
{
rdmalt(ps_adapter, SYS_CFG, &value, sizeof (value));
@@ -1187,7 +1113,7 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
status = ddr_init(ps_adapter);
if(status)
{
- BCM_DEBUG_PRINT (ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "ddr_init Failed\n");
+ pr_err(DRV_NAME "ddr_init Failed\n");
return status;
}
@@ -1201,7 +1127,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Error downloading CFG file");
goto OUT;
}
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "CFG file downloaded");
if(register_networkdev(ps_adapter))
{
@@ -1266,12 +1191,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
goto OUT;
}
}
-#if 0
- else if(psAdapter->eNVMType == NVM_EEPROM)
- {
- PropagateCalParamsFromEEPROMToMemory();
- }
-#endif
/* Download Firmare */
if ((status = BcmFileDownload( ps_adapter, BIN_FILE, FIRMWARE_BEGIN_ADDR)))
@@ -1280,7 +1199,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
goto OUT;
}
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "BIN file downloaded");
status = run_card_proc(ps_adapter);
if(status)
{
@@ -1299,68 +1217,19 @@ OUT:
wake_up(&ps_adapter->LEDInfo.notify_led_event);
}
-#else
-
- ps_adapter->bDDRInitDone = TRUE;
- //Initializing the NVM.
- BcmInitNVM(ps_adapter);
-
- //Propagating the cal param from Flash to DDR
- value = 0;
- wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value));
- wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value));
-
- if(ps_adapter->eNVMType == NVM_FLASH)
- {
- status = PropagateCalParamsFromFlashToMemory(ps_adapter);
- if(status)
- {
- printk("\nPropogation of Cal param from flash to DDR failed ..\n" );
- }
- }
-
- //Copy config file param to DDR.
- memcpy(pConfigFileAddr,ps_adapter->pstargetparams, sizeof(STARGETPARAMS));
-
- if(register_networkdev(ps_adapter))
- {
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Netdevice failed. Cleanup needs to be performed.");
- return -EIO;
- }
-
-
- status = InitLedSettings (ps_adapter);
- if(status)
- {
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_PRINTK, 0, 0,"INIT LED FAILED\n");
- return status;
- }
-
-
- if(register_control_device_interface(ps_adapter) < 0)
- {
- BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Control Device failed. Cleanup needs to be performed.");
- return -EIO;
- }
-
- ps_adapter->fw_download_done = TRUE;
-#endif
return status;
}
-int bcm_parse_target_params(PMINI_ADAPTER Adapter)
+static int bcm_parse_target_params(PMINI_ADAPTER Adapter)
{
-#ifdef BCM_SHM_INTERFACE
- extern void read_cfg_file(PMINI_ADAPTER Adapter);
-#endif
struct file *flp=NULL;
mm_segment_t oldfs={0};
- char *buff = NULL;
+ char *buff;
int len = 0;
loff_t pos = 0;
- buff=(PCHAR)kmalloc(BUFFER_1K, GFP_KERNEL);
+ buff=kmalloc(BUFFER_1K, GFP_KERNEL);
if(!buff)
{
return -ENOMEM;
@@ -1368,14 +1237,14 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
if((Adapter->pstargetparams =
kmalloc(sizeof(STARGETPARAMS), GFP_KERNEL)) == NULL)
{
- bcm_kfree(buff);
+ kfree(buff);
return -ENOMEM;
}
flp=open_firmware_file(Adapter, CFG_FILE);
if(!flp) {
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "NOT ABLE TO OPEN THE %s FILE \n", CFG_FILE);
- bcm_kfree(buff);
- bcm_kfree(Adapter->pstargetparams);
+ kfree(buff);
+ kfree(Adapter->pstargetparams);
Adapter->pstargetparams = NULL;
return -ENOENT;
}
@@ -1386,8 +1255,8 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
if(len != sizeof(STARGETPARAMS))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"Mismatch in Target Param Structure!\n");
- bcm_kfree(buff);
- bcm_kfree(Adapter->pstargetparams);
+ kfree(buff);
+ kfree(Adapter->pstargetparams);
Adapter->pstargetparams = NULL;
filp_close(flp, current->files);
return -ENOENT;
@@ -1399,37 +1268,34 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
* Values in Adapter->pstargetparams are in network byte order
*/
memcpy(Adapter->pstargetparams, buff, sizeof(STARGETPARAMS));
- bcm_kfree (buff);
+ kfree (buff);
beceem_parse_target_struct(Adapter);
-#ifdef BCM_SHM_INTERFACE
- read_cfg_file(Adapter);
-
-#endif
return STATUS_SUCCESS;
}
void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
{
- UINT uiHostDrvrCfg6 =0, uiEEPROMFlag = 0;;
+ UINT uiHostDrvrCfg6 =0, uiEEPROMFlag = 0;
if(ntohl(Adapter->pstargetparams->m_u32PhyParameter2) & AUTO_SYNC_DISABLE)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Disabled\n");
+ pr_info(DRV_NAME ": AutoSyncup is Disabled\n");
Adapter->AutoSyncup = FALSE;
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Enabled\n");
+ pr_info(DRV_NAME ": AutoSyncup is Enabled\n");
Adapter->AutoSyncup = TRUE;
}
+
if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_LINKUP_ENABLE)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling autolink up");
+ pr_info(DRV_NAME ": Enabling autolink up");
Adapter->AutoLinkUp = TRUE;
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling autolink up");
+ pr_info(DRV_NAME ": Disabling autolink up");
Adapter->AutoLinkUp = FALSE;
}
// Setting the DDR Setting..
@@ -1438,59 +1304,54 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
Adapter->ulPowerSaveMode =
(ntohl(Adapter->pstargetparams->HostDrvrConfig6)>>12)&0x0F;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT,DBG_LVL_ALL, "Power Save Mode: %lx\n",
- Adapter->ulPowerSaveMode);
+ pr_info(DRV_NAME ": DDR Setting: %x\n", Adapter->DDRSetting);
+ pr_info(DRV_NAME ": Power Save Mode: %lx\n", Adapter->ulPowerSaveMode);
if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_FIRM_DOWNLOAD)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling Auto Firmware Download\n");
+ pr_info(DRV_NAME ": Enabling Auto Firmware Download\n");
Adapter->AutoFirmDld = TRUE;
}
else
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling Auto Firmware Download\n");
+ pr_info(DRV_NAME ": Disabling Auto Firmware Download\n");
Adapter->AutoFirmDld = FALSE;
}
uiHostDrvrCfg6 = ntohl(Adapter->pstargetparams->HostDrvrConfig6);
Adapter->bMipsConfig = (uiHostDrvrCfg6>>20)&0x01;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"MIPSConfig : 0x%X\n",Adapter->bMipsConfig);
+ pr_info(DRV_NAME ": MIPSConfig : 0x%X\n",Adapter->bMipsConfig);
//used for backward compatibility.
Adapter->bDPLLConfig = (uiHostDrvrCfg6>>19)&0x01;
Adapter->PmuMode= (uiHostDrvrCfg6 >> 24 ) & 0x03;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "PMU MODE: %x", Adapter->PmuMode);
+ pr_info(DRV_NAME ": PMU MODE: %x", Adapter->PmuMode);
if((uiHostDrvrCfg6 >> HOST_BUS_SUSPEND_BIT ) & (0x01))
{
Adapter->bDoSuspend = TRUE;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Making DoSuspend TRUE as per configFile");
+ pr_info(DRV_NAME ": Making DoSuspend TRUE as per configFile");
}
uiEEPROMFlag = ntohl(Adapter->pstargetparams->m_u32EEPROMFlag);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "uiEEPROMFlag : 0x%X\n",uiEEPROMFlag);
+ pr_info(DRV_NAME ": uiEEPROMFlag : 0x%X\n",uiEEPROMFlag);
Adapter->eNVMType = (NVM_TYPE)((uiEEPROMFlag>>4)&0x3);
-
Adapter->bStatusWrite = (uiEEPROMFlag>>6)&0x1;
- //printk(("bStatusWrite : 0x%X\n", Adapter->bStatusWrite));
Adapter->uiSectorSizeInCFG = 1024*(0xFFFF & ntohl(Adapter->pstargetparams->HostDrvrConfig4));
- //printk(("uiSectorSize : 0x%X\n", Adapter->uiSectorSizeInCFG));
Adapter->bSectorSizeOverride =(bool) ((ntohl(Adapter->pstargetparams->HostDrvrConfig4))>>16)&0x1;
- //printk(MP_INIT,("bSectorSizeOverride : 0x%X\n",Adapter->bSectorSizeOverride));
if(ntohl(Adapter->pstargetparams->m_u32PowerSavingModeOptions) &0x01)
Adapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE;
- //autocorrection part
+
if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)
doPowerAutoCorrection(Adapter);
}
-VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
+static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
{
- UINT reporting_mode = 0;
+ UINT reporting_mode;
reporting_mode = ntohl(psAdapter->pstargetparams->m_u32PowerSavingModeOptions) &0x02 ;
psAdapter->bIsAutoCorrectEnabled = !((char)(psAdapter->ulPowerSaveMode >> 3) & 0x1);
@@ -1504,20 +1365,9 @@ VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
if (psAdapter->bIsAutoCorrectEnabled && (psAdapter->chip_id >= T3LPB))
{
//If reporting mode is enable, switch PMU to PMC
- #if 0
- if(reporting_mode == FALSE)
- {
- psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN;
- psAdapter->bDoSuspend = TRUE;
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMU selected ....");
-
- }
- else
- #endif
{
psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING;
psAdapter->bDoSuspend =FALSE;
- BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMC selected..");
}
@@ -1540,12 +1390,10 @@ VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
#if 0
static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
{
- unsigned char *pucmacaddr = NULL;
- int status = 0, i=0;
- unsigned int temp =0;
+ int status = 0, i = 0;
+ unsigned int temp = 0;
+ unsigned char *pucmacaddr = kmalloc(MAC_ADDRESS_SIZE, GFP_KERNEL);
-
- pucmacaddr = (unsigned char *)kmalloc(MAC_ADDRESS_SIZE, GFP_KERNEL);
if(!pucmacaddr)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "No Buffers to Read the EEPROM Address\n");
@@ -1558,7 +1406,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
if(status != STATUS_SUCCESS)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm Failed..\n");
- bcm_kfree(pucmacaddr);
+ kfree(pucmacaddr);
pucmacaddr = NULL;
goto OUT;
}
@@ -1568,7 +1416,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
if(status != STATUS_SUCCESS)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm Failed..\n");
- bcm_kfree(pucmacaddr);
+ kfree(pucmacaddr);
pucmacaddr = NULL;
goto OUT;
}
@@ -1580,43 +1428,6 @@ OUT:
}
#endif
-#if 0
-INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter)
-{
- unsigned char *puMacAddr = NULL;
- int i =0;
-
- puMacAddr = ReadMacAddrEEPROM(Adapter,0x200);
- if(!puMacAddr)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Couldn't retrieve the Mac Address\n");
- return STATUS_FAILURE;
- }
- else
- {
- if((puMacAddr[0] == 0x0 && puMacAddr[1] == 0x0 &&
- puMacAddr[2] == 0x0 && puMacAddr[3] == 0x0 &&
- puMacAddr[4] == 0x0 && puMacAddr[5] == 0x0) ||
- (puMacAddr[0] == 0xFF && puMacAddr[1] == 0xFF &&
- puMacAddr[2] == 0xFF && puMacAddr[3] == 0xFF &&
- puMacAddr[4] == 0xFF && puMacAddr[5] == 0xFF))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Invalid Mac Address\n");
- bcm_kfree(puMacAddr);
- return STATUS_FAILURE;
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "The Mac Address received is: \n");
- memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
- for(i=0;i<MAC_ADDRESS_SIZE;i++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%02x ", Adapter->dev->dev_addr[i]);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"\n");
- bcm_kfree(puMacAddr);
- }
- return STATUS_SUCCESS;
-}
-#endif
static void convertEndian(B_UINT8 rwFlag, PUINT puiBuffer, UINT uiByteCount)
{
@@ -1640,81 +1451,21 @@ int rdm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
{
INT uiRetVal =0;
-#ifndef BCM_SHM_INTERFACE
uiRetVal = Adapter->interface_rdm(Adapter->pvInterfaceAdapter,
uiAddress, pucBuff, sSize);
if(uiRetVal < 0)
return uiRetVal;
-#else
- int indx;
- uiRetVal = STATUS_SUCCESS;
- if(uiAddress & 0x10000000) {
- // DDR Memory Access
- uiAddress |= CACHE_ADDRESS_MASK;
- memcpy(pucBuff,(unsigned char *)uiAddress ,sSize);
- }
- else {
- // Register, SPRAM, Flash
- uiAddress |= UNCACHE_ADDRESS_MASK;
- if ((uiAddress & FLASH_ADDR_MASK) == (FLASH_CONTIGIOUS_START_ADDR_BCS350 & FLASH_ADDR_MASK))
- {
- #if defined(FLASH_DIRECT_ACCESS)
- memcpy(pucBuff,(unsigned char *)uiAddress ,sSize);
- #else
- printk("\nInvalid GSPI ACCESS :Addr :%#X", uiAddress);
- uiRetVal = STATUS_FAILURE;
- #endif
- }
- else if(((unsigned int )uiAddress & 0x3) ||
- ((unsigned int )pucBuff & 0x3) ||
- ((unsigned int )sSize & 0x3)) {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"rdmalt :unalligned register access uiAddress = %x,pucBuff = %x size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize);
- uiRetVal = STATUS_FAILURE;
- }
- else {
- for (indx=0;indx<sSize;indx+=4){
- *(PUINT)(pucBuff + indx) = *(PUINT)(uiAddress + indx);
- }
- }
- }
-#endif
return uiRetVal;
}
int wrm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
{
int iRetVal;
-#ifndef BCM_SHM_INTERFACE
iRetVal = Adapter->interface_wrm(Adapter->pvInterfaceAdapter,
uiAddress, pucBuff, sSize);
-#else
- int indx;
- if(uiAddress & 0x10000000) {
- // DDR Memory Access
- uiAddress |= CACHE_ADDRESS_MASK;
- memcpy((unsigned char *)(uiAddress),pucBuff,sSize);
- }
- else {
- // Register, SPRAM, Flash
- uiAddress |= UNCACHE_ADDRESS_MASK;
-
- if(((unsigned int )uiAddress & 0x3) ||
- ((unsigned int )pucBuff & 0x3) ||
- ((unsigned int )sSize & 0x3)) {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"wrmalt: unalligned register access uiAddress = %x,pucBuff = %x size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize);
- iRetVal = STATUS_FAILURE;
- }
- else {
- for (indx=0;indx<sSize;indx+=4) {
- *(PUINT)(uiAddress + indx) = *(PUINT)(pucBuff + indx);
- }
- }
- }
- iRetVal = STATUS_SUCCESS;
-#endif
return iRetVal;
}
@@ -1735,26 +1486,7 @@ int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
return uiRetVal;
}
-int rdmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
-{
-
- INT status = STATUS_SUCCESS ;
- down(&Adapter->rdmwrmsync);
-
- if((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus ==TRUE) ||
- (Adapter->bPreparingForLowPowerMode ==TRUE))
- {
- status = -EACCES;
- goto exit;
- }
- status = rdm(Adapter, uiAddress, pucBuff, sSize);
-
-exit:
- up(&Adapter->rdmwrmsync);
- return status ;
-}
int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
{
INT status = STATUS_SUCCESS ;
@@ -1921,10 +1653,8 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
Adapter->bPreparingForLowPowerMode = TRUE;
up(&Adapter->rdmwrmsync);
//Killing all URBS.
-#ifndef BCM_SHM_INTERFACE
if(Adapter->bDoSuspend == TRUE)
Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
}
else
{
@@ -1943,14 +1673,12 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL,"fail to send the Idle mode Request \n");
Adapter->bPreparingForLowPowerMode = FALSE;
-#ifndef BCM_SHM_INTERFACE
StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
}
}
-void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer)
+static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer)
{
B_UINT32 uiResetValue = 0;
@@ -2077,11 +1805,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter)
if(!atomic_read (&Adapter->uiMBupdate))
return;
-#ifdef BCM_SHM_INTERFACE
- if(rdmalt(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0)
-#else
if(rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0)
-#endif
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed\n");
return;
@@ -2107,9 +1831,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter)
void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
{
struct sk_buff* PacketToDrop=NULL;
- struct net_device_stats* netstats=NULL;
-
- netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
+ struct net_device_stats* netstats = &Adapter->dev->stats;
spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
@@ -2130,25 +1852,23 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
Adapter->PackInfo[iQIndex].uiDroppedCountBytes += PacketToDrop->len;
Adapter->PackInfo[iQIndex].uiDroppedCountPackets++;
- bcm_kfree_skb(PacketToDrop);
+ dev_kfree_skb(PacketToDrop);
atomic_dec(&Adapter->TotalPacketCount);
- atomic_inc(&Adapter->TxDroppedPacketCount);
-
}
}
spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
}
-void beceem_protocol_reset (PMINI_ADAPTER Adapter)
+static void beceem_protocol_reset (PMINI_ADAPTER Adapter)
{
- int i =0;
+ int i;
- if(NULL != Adapter->dev)
- {
- netif_carrier_off(Adapter->dev);
- netif_stop_queue(Adapter->dev);
- }
+ if (netif_msg_link(Adapter))
+ pr_notice(PFX "%s: protocol reset\n", Adapter->dev->name);
+
+ netif_carrier_off(Adapter->dev);
+ netif_stop_queue(Adapter->dev);
Adapter->IdleMode = FALSE;
Adapter->LinkUpStatus = FALSE;
@@ -2166,78 +1886,18 @@ void beceem_protocol_reset (PMINI_ADAPTER Adapter)
Adapter->TimerActive = FALSE;
memset(Adapter->astFragmentedPktClassifierTable, 0,
- sizeof(S_FRAGMENTED_PACKET_INFO) *
- MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
+ sizeof(S_FRAGMENTED_PACKET_INFO) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
for(i = 0;i<HiPriority;i++)
{
//resetting only the first size (S_MIBS_SERVICEFLOW_TABLE) for the SF.
// It is same between MIBs and SF.
- memset((PVOID)&Adapter->PackInfo[i],0,sizeof(S_MIBS_SERVICEFLOW_TABLE));
+ memset(&Adapter->PackInfo[i].stMibsExtServiceFlowTable,
+ 0, sizeof(S_MIBS_EXTSERVICEFLOW_PARAMETERS));
}
}
-#ifdef BCM_SHM_INTERFACE
-
-
-#define GET_GTB_DIFF(start, end) \
-( (start) < (end) )? ( (end) - (start) ) : ( ~0x0 - ( (start) - (end)) +1 )
-
-void usdelay ( unsigned int a) {
- unsigned int start= *(unsigned int *)0xaf8051b4;
- unsigned int end = start+1;
- unsigned int diff = 0;
-
- while(1) {
- end = *(unsigned int *)0xaf8051b4;
- diff = (GET_GTB_DIFF(start,end))/80;
- if (diff >= a)
- break;
- }
-}
-void read_cfg_file(PMINI_ADAPTER Adapter) {
-
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Config File Version = 0x%x \n",Adapter->pstargetparams->m_u32CfgVersion );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Center Frequency = 0x%x \n",Adapter->pstargetparams->m_u32CenterFrequency );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band A Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandAScan );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band B Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandBScan );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band C Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandCScan );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ERTPS Options = 0x%x \n",Adapter->pstargetparams->m_u32ErtpsOptions );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PHS Enable = 0x%x \n",Adapter->pstargetparams->m_u32PHSEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Handoff Enable = 0x%x \n",Adapter->pstargetparams->m_u32HoEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved1 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved1 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved2 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved2 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MIMO Enable = 0x%x \n",Adapter->pstargetparams->m_u32MimoEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PKMv2 Enable = 0x%x \n",Adapter->pstargetparams->m_u32SecurityEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Powersaving Modes Enable = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModesEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Power Saving Mode Options = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModeOptions );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ARQ Enable = 0x%x \n",Adapter->pstargetparams->m_u32ArqEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Harq Enable = 0x%x \n",Adapter->pstargetparams->m_u32HarqEnable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"EEPROM Flag = 0x%x \n",Adapter->pstargetparams->m_u32EEPROMFlag );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Customize = 0x%x \n",Adapter->pstargetparams->m_u32Customize );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Bandwidth = 0x%x \n",Adapter->pstargetparams->m_u32ConfigBW );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ShutDown Timer Value = 0x%x \n",Adapter->pstargetparams->m_u32ShutDownInitThresholdTimer );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RadioParameter = 0x%x \n",Adapter->pstargetparams->m_u32RadioParameter );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter1 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter1 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter2 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter2 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter3 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter3 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"m_u32TestOptions = 0x%x \n",Adapter->pstargetparams->m_u32TestOptions );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperDLFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperDLFrame );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperULFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperULFrame );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Corr2MacFlags = 0x%x \n",Adapter->pstargetparams->m_u32Corr2MacFlags );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig1 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig1 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig2 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig2 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig3 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig3 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig4 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig4 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig5 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig5 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig6 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig6 );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Segmented PUSC Enable = 0x%x \n",Adapter->pstargetparams->m_u32SegmentedPUSCenable );
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BamcEnable = 0x%x \n",Adapter->pstargetparams->m_u32BandAMCEnable );
-}
-
-#endif
diff --git a/drivers/staging/bcm/Osal_Misc.c b/drivers/staging/bcm/Osal_Misc.c
deleted file mode 100644
index feefd20a5291..000000000000
--- a/drivers/staging/bcm/Osal_Misc.c
+++ /dev/null
@@ -1,27 +0,0 @@
- /*++
-
- Copyright (c) Beceem Communications Inc.
-
- Module Name:
- WIN_Misc.c
-
- Abstract:
- Implements the Miscelanneous OS Construts
- Linked Lists
- Dispatcher Objects(Events,Semaphores,Spin Locks and the like)
- Files
-
- Revision History:
- Who When What
- -------- -------- ----------------------------------------------
- Name Date Created/reviewed/modified
- Rajeev 24/1/08 Created
- Notes:
-
- --*/
-#include "headers.h"
-
-bool OsalMemCompare(void *dest, void *src, UINT len)
-{
- return (memcmp(src, dest, len));
-}
diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c
index 8a38cf43e795..d1ca1912a74b 100644
--- a/drivers/staging/bcm/PHSModule.c
+++ b/drivers/staging/bcm/PHSModule.c
@@ -1,10 +1,54 @@
#include "headers.h"
+static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static UINT CreateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI);
+
+static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule);
+
+static BOOLEAN DerefPhsRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule);
+
+static UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry);
+
+static UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule);
+
+static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable);
+
+static int phs_compress(S_PHS_RULE *phs_members,unsigned char *in_buf,
+ unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
+
+
+static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
+ unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
+
+static int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
+ S_PHS_RULE *phs_rules,UINT *header_size);
+
+
+static ULONG PhsCompress(void* pvContext,
+ B_UINT16 uiVcid,
+ B_UINT16 uiClsId,
+ void *pvInputBuffer,
+ void *pvOutputBuffer,
+ UINT *pOldHeaderSize,
+ UINT *pNewHeaderSize );
+
+static ULONG PhsDeCompress(void* pvContext,
+ B_UINT16 uiVcid,
+ void *pvInputBuffer,
+ void *pvOutputBuffer,
+ UINT *pInHeaderSize,
+ UINT *pOutHeaderSize);
+
+
+
#define IN
#define OUT
-void DumpDataPacketHeader(PUCHAR pPkt);
-
/*
Function: PHSTransmit
@@ -81,8 +125,6 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
{
- //DumpDataPacketHeader(pucPHSPktHdrInBuf);
-
// Step 2 Supress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
// Suppress only if IP Header and PHS Enabled For the Service Flow
if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
@@ -120,15 +162,15 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
if(newPacket == NULL)
return STATUS_FAILURE;
- bcm_kfree_skb(Packet);
+ dev_kfree_skb(Packet);
*pPacket = Packet = newPacket;
pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
}
numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN);
- OsalMemMove(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
- OsalMemMove(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
+ memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
+ memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
skb_pull(Packet, numBytesCompressed);
return STATUS_SUCCESS;
@@ -223,23 +265,12 @@ int PHSRecieve(PMINI_ADAPTER Adapter,
}
}
- OsalMemMove(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
+ memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
}
return STATUS_SUCCESS;
}
-void DumpDataPacketHeader(PUCHAR pPkt)
-{
- struct iphdr *iphd = (struct iphdr*)pPkt;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Phs Send/Recieve : IP Packet Hdr \n");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"TOS : %x \n",iphd->tos);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Src IP : %x \n",iphd->saddr);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Dest IP : %x \n \n",iphd->daddr);
-
-}
-
void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
{
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
@@ -270,15 +301,9 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
return -EINVAL;
pPhsdeviceExtension->pstServiceFlowPhsRulesTable =
- (S_SERVICEFLOW_TABLE*)OsalMemAlloc(sizeof(S_SERVICEFLOW_TABLE),
- PHS_MEM_TAG);
+ kzalloc(sizeof(S_SERVICEFLOW_TABLE), GFP_KERNEL);
- if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
- {
- OsalZeroMemory(pPhsdeviceExtension->pstServiceFlowPhsRulesTable,
- sizeof(S_SERVICEFLOW_TABLE));
- }
- else
+ if(!pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
return -ENOMEM;
@@ -288,14 +313,8 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
for(i=0;i<MAX_SERVICEFLOWS;i++)
{
S_SERVICEFLOW_ENTRY sServiceFlow = pstServiceFlowTable->stSFList[i];
- sServiceFlow.pstClassifierTable = (S_CLASSIFIER_TABLE*)OsalMemAlloc(
- sizeof(S_CLASSIFIER_TABLE), PHS_MEM_TAG);
- if(sServiceFlow.pstClassifierTable)
- {
- OsalZeroMemory(sServiceFlow.pstClassifierTable,sizeof(S_CLASSIFIER_TABLE));
- pstServiceFlowTable->stSFList[i].pstClassifierTable = sServiceFlow.pstClassifierTable;
- }
- else
+ sServiceFlow.pstClassifierTable = kzalloc(sizeof(S_CLASSIFIER_TABLE), GFP_KERNEL);
+ if(!sServiceFlow.pstClassifierTable)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
free_phs_serviceflow_rules(pPhsdeviceExtension->
@@ -305,9 +324,7 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
}
}
-
- pPhsdeviceExtension->CompressedTxBuffer =
- OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG);
+ pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
if(pPhsdeviceExtension->CompressedTxBuffer == NULL)
{
@@ -317,12 +334,11 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
return -ENOMEM;
}
- pPhsdeviceExtension->UnCompressedRxBuffer =
- OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG);
+ pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
- OsalMemFree(pPhsdeviceExtension->CompressedTxBuffer,PHS_BUFFER_SIZE);
+ kfree(pPhsdeviceExtension->CompressedTxBuffer);
free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
@@ -343,16 +359,11 @@ int PhsCleanup(IN PPHS_DEVICE_EXTENSION pPHSDeviceExt)
pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL;
}
- if(pPHSDeviceExt->CompressedTxBuffer)
- {
- OsalMemFree(pPHSDeviceExt->CompressedTxBuffer,PHS_BUFFER_SIZE);
- pPHSDeviceExt->CompressedTxBuffer = NULL;
- }
- if(pPHSDeviceExt->UnCompressedRxBuffer)
- {
- OsalMemFree(pPHSDeviceExt->UnCompressedRxBuffer,PHS_BUFFER_SIZE);
- pPHSDeviceExt->UnCompressedRxBuffer = NULL;
- }
+ kfree(pPHSDeviceExt->CompressedTxBuffer);
+ pPHSDeviceExt->CompressedTxBuffer = NULL;
+
+ kfree(pPHSDeviceExt->UnCompressedRxBuffer);
+ pPHSDeviceExt->UnCompressedRxBuffer = NULL;
return 0;
}
@@ -478,20 +489,12 @@ ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI)
{
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
{
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule->u8PHSI == u8PHSI)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule
- ->u8RefCnt)
- pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule
- ->u8RefCnt--;
- if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt)
- OsalMemFree(pstClassifierRulesTable
- ->stActivePhsRulesList[nClsidIndex].pstPhsRule,
- sizeof(S_PHS_RULE));
- OsalZeroMemory(&pstClassifierRulesTable
- ->stActivePhsRulesList[nClsidIndex],
+ if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) {
+ if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
+ if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
+ memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0,
sizeof(S_CLASSIFIER_ENTRY));
}
}
@@ -548,10 +551,10 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
if(pstClassifierEntry->pstPhsRule->u8RefCnt)
pstClassifierEntry->pstPhsRule->u8RefCnt--;
if(0==pstClassifierEntry->pstPhsRule->u8RefCnt)
- OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
+ kfree(pstClassifierEntry->pstPhsRule);
}
- OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY));
+ memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
@@ -559,10 +562,8 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
{
- if(pstClassifierEntry->pstPhsRule)
- //Delete the classifier entry
- OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
- OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY));
+ kfree(pstClassifierEntry->pstPhsRule);
+ memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
}
}
return lStatus;
@@ -619,14 +620,11 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
.pstPhsRule->u8RefCnt--;
if(0==pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
- OsalMemFree(pstClassifierRulesTable
- ->stActivePhsRulesList[nClsidIndex].pstPhsRule,
- sizeof(S_PHS_RULE));
+ kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule = NULL;
}
- OsalZeroMemory(&pstClassifierRulesTable
- ->stActivePhsRulesList[nClsidIndex],sizeof(S_CLASSIFIER_ENTRY));
+ memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule)
{
if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
@@ -635,15 +633,12 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
.pstPhsRule->u8RefCnt--;
if(0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
- OsalMemFree(pstClassifierRulesTable
- ->stOldPhsRulesList[nClsidIndex].pstPhsRule,
- sizeof(S_PHS_RULE));
+ kfree(pstClassifierRulesTable
+ ->stOldPhsRulesList[nClsidIndex].pstPhsRule);
pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule = NULL;
}
- OsalZeroMemory(&pstClassifierRulesTable
- ->stOldPhsRulesList[nClsidIndex],
- sizeof(S_CLASSIFIER_ENTRY));
+ memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
}
}
pstServiceFlowEntry->bUsed = FALSE;
@@ -849,7 +844,7 @@ ULONG PhsDeCompress(IN void* pvContext,
// Does not return any value.
//-----------------------------------------------------------------------------
-void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
+static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
{
int i,j;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
@@ -876,8 +871,7 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
->u8RefCnt--;
if(0==pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
->u8RefCnt)
- OsalMemFree(pstClassifierRulesTable->stActivePhsRulesList[j].
- pstPhsRule, sizeof(S_PHS_RULE));
+ kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule);
pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL;
}
if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule)
@@ -888,24 +882,23 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
->u8RefCnt--;
if(0==pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
->u8RefCnt)
- OsalMemFree(pstClassifierRulesTable->stOldPhsRulesList[j]
- .pstPhsRule,sizeof(S_PHS_RULE));
+ kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule);
pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL;
}
}
- OsalMemFree(pstClassifierRulesTable,sizeof(S_CLASSIFIER_TABLE));
+ kfree(pstClassifierRulesTable);
stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
}
}
}
- OsalMemFree(psServiceFlowRulesTable,sizeof(S_SERVICEFLOW_TABLE));
- psServiceFlowRulesTable = NULL;
+ kfree(psServiceFlowRulesTable);
+ psServiceFlowRulesTable = NULL;
}
-BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule)
+static BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule)
{
if(psPhsRule)
{
@@ -988,9 +981,9 @@ UINT GetClassifierEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
return PHS_INVALID_TABLE_INDEX;
}
-UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
- IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
- OUT S_PHS_RULE **ppstPhsRule)
+static UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
+ IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
+ OUT S_PHS_RULE **ppstPhsRule)
{
int i;
S_CLASSIFIER_ENTRY *pstClassifierRule = NULL;
@@ -1102,7 +1095,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
if(psPhsRule->u8PHSFLength)
{
//update PHSF
- OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSF,
+ memcpy(pstClassifierEntry->pstPhsRule->u8PHSF,
psPhsRule->u8PHSF , MAX_PHS_LENGTHS);
}
if(psPhsRule->u8PHSFLength)
@@ -1114,7 +1107,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
if(psPhsRule->u8PHSMLength)
{
//update PHSM
- OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSM,
+ memcpy(pstClassifierEntry->pstPhsRule->u8PHSM,
psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
}
if(psPhsRule->u8PHSMLength)
@@ -1147,7 +1140,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
return uiStatus;
}
-UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
+static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI)
{
@@ -1234,8 +1227,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
{
if(psClassifierRules->pstPhsRule == NULL)
{
- psClassifierRules->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc
- (sizeof(S_PHS_RULE),PHS_MEM_TAG);
+ psClassifierRules->pstPhsRule = kmalloc(sizeof(S_PHS_RULE),GFP_KERNEL);
if(NULL == psClassifierRules->pstPhsRule)
return ERR_PHSRULE_MEMALLOC_FAIL;
@@ -1247,7 +1239,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule;
/* Update The PHS rule */
- OsalMemMove(psClassifierRules->pstPhsRule,
+ memcpy(psClassifierRules->pstPhsRule,
psPhsRule, sizeof(S_PHS_RULE));
}
else
@@ -1259,7 +1251,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
}
-UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
+static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
IN S_CLASSIFIER_ENTRY *pstClassifierEntry,
S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
B_UINT8 u8AssociatedPHSI)
@@ -1289,13 +1281,13 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
//Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId
if(FALSE == bPHSRuleOrphaned)
{
- pstClassifierEntry->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc(sizeof(S_PHS_RULE),PHS_MEM_TAG);
+ pstClassifierEntry->pstPhsRule = kmalloc(sizeof(S_PHS_RULE), GFP_KERNEL);
if(NULL == pstClassifierEntry->pstPhsRule)
{
return ERR_PHSRULE_MEMALLOC_FAIL;
}
}
- OsalMemMove(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE));
+ memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE));
}
else
@@ -1304,14 +1296,8 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
if(bPHSRuleOrphaned)
{
- if(pstClassifierEntry->pstPhsRule)
- {
- //Just Free the PHS Rule as Ref Count is Zero
- OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
+ kfree(pstClassifierEntry->pstPhsRule);
pstClassifierEntry->pstPhsRule = NULL;
-
- }
-
}
pstClassifierEntry->pstPhsRule = pstAddPhsRule;
@@ -1326,7 +1312,7 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
}
-BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule)
+static BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule)
{
if(pstPhsRule==NULL)
return FALSE;
@@ -1345,22 +1331,6 @@ BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable
}
}
-static void DumpBuffer(PVOID BuffVAddress, int xferSize)
-{
- int i;
- int iPrintLength;
- PUCHAR temp=(PUCHAR)BuffVAddress;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- iPrintLength=(xferSize<32?xferSize:32);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n");
-
- for (i=0;i < iPrintLength;i++) {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "%x|",temp[i]);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n");
-}
-
-
void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension)
{
int i,j,k,l;
@@ -1520,8 +1490,8 @@ int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
// size-The number of bytes copied into the output buffer i.e dynamic fields
// 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
//-----------------------------------------------------------------------------
-int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf
- ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
+static int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf
+ ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
{
unsigned char *old_addr = out_buf;
int supress = 0;
@@ -1581,9 +1551,9 @@ int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf
// 0 -Packet has failed the verification.
//-----------------------------------------------------------------------------
- int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
- unsigned char *phsf,unsigned char *phsm,unsigned int phss,
- unsigned int phsv,UINT* new_header_size)
+static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
+ unsigned char *phsf,unsigned char *phsm,unsigned int phss,
+ unsigned int phsv,UINT* new_header_size)
{
unsigned int size=0;
int bit,i=0;
diff --git a/drivers/staging/bcm/PHSModule.h b/drivers/staging/bcm/PHSModule.h
index bf2b5763252c..0dd05a7c55d9 100644
--- a/drivers/staging/bcm/PHSModule.h
+++ b/drivers/staging/bcm/PHSModule.h
@@ -27,19 +27,6 @@ void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension);
int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter);
-void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable);
-
-int phs_compress(S_PHS_RULE *phs_members,unsigned char *in_buf,
- unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
-
-
-int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
- unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
-
-int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
- S_PHS_RULE *phs_rules,UINT *header_size);
-
-
int PhsCleanup(PPHS_DEVICE_EXTENSION pPHSDeviceExt);
//Utility Functions
@@ -52,42 +39,10 @@ ULONG PhsDeleteClassifierRule(void* pvContext, B_UINT16 uiVcid ,B_UINT16 uiClsI
ULONG PhsDeleteSFRules(void* pvContext,B_UINT16 uiVcid) ;
-ULONG PhsCompress(void* pvContext,
- B_UINT16 uiVcid,
- B_UINT16 uiClsId,
- void *pvInputBuffer,
- void *pvOutputBuffer,
- UINT *pOldHeaderSize,
- UINT *pNewHeaderSize );
-
-ULONG PhsDeCompress(void* pvContext,
- B_UINT16 uiVcid,
- void *pvInputBuffer,
- void *pvOutputBuffer,
- UINT *pInHeaderSize,
- UINT *pOutHeaderSize);
-
-
BOOLEAN ValidatePHSRule(S_PHS_RULE *psPhsRule);
-BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule);
-
UINT GetServiceFlowEntry(S_SERVICEFLOW_TABLE *psServiceFlowTable,B_UINT16 uiVcid,S_SERVICEFLOW_ENTRY **ppstServiceFlowEntry);
-UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry);
-
-UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule);
-
-
-UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-UINT CreateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI);
-
-UINT UpdateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-BOOLEAN DerefPhsRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule);
void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension);
diff --git a/drivers/staging/bcm/Protocol.h b/drivers/staging/bcm/Protocol.h
index 00f1cc12356a..b8a4009bdf0c 100644
--- a/drivers/staging/bcm/Protocol.h
+++ b/drivers/staging/bcm/Protocol.h
@@ -85,10 +85,10 @@ typedef struct _ETH_CS_ETH2_FRAME
ETH_HEADER_STRUC EThHdr;
} __attribute__((packed)) ETH_CS_ETH2_FRAME;
+#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800)
+#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd)
+#define ETHERNET_FRAMETYPE_802QVLAN ntohs(0x8100)
-#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800)
-#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd)
-#define ETHERNET_FRAMETYPE_802QVLAN 0x8100
//Per SF CS Specification Encodings
typedef enum _E_SERVICEFLOW_CS_SPEC_
{
diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h
index 70ec8bcafd1e..b80b806c90a3 100644
--- a/drivers/staging/bcm/Prototypes.h
+++ b/drivers/staging/bcm/Prototypes.h
@@ -1,23 +1,12 @@
#ifndef _PROTOTYPES_H_
#define _PROTOTYPES_H_
-int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
- char *path, /**< path to image file */
- unsigned int loc /**< Download Address on the chip*/
- );
VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer);
VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer);
VOID IdleModeResponse(PMINI_ADAPTER Adapter,PUINT puiBuffer);
-void bcm_kfree_skb(struct sk_buff *skb);
-VOID bcm_kfree(VOID *ptr);
-
-
-VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**<Pointer to the Adapter structure*/
- struct sk_buff *skb); /**<Pointer to the socket buffer*/
-
int control_packet_handler (PMINI_ADAPTER Adapter);
VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter,UINT uiSearchRuleIndex);
@@ -38,25 +27,16 @@ VOID SortClassifiers(PMINI_ADAPTER Adapter);
VOID flush_all_queues(PMINI_ADAPTER Adapter);
-USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
- struct iphdr *iphd, /**<Pointer to the IP Hdr of the packet*/
- S_CLASSIFIER_RULE *pstClassifierRule );
-
-VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structure*/
- INT iIndex/**<Queue Index*/
- );
-
VOID PruneQueueAllSF(PMINI_ADAPTER Adapter);
INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid);
-USHORT GetPacketQueueIndex(PMINI_ADAPTER Adapter, /**<Pointer to the driver control structure */
- struct sk_buff* Packet /**< Pointer to the Packet to be sent*/
- );
+USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb);
+
+BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
-VOID
-reply_to_arp_request(struct sk_buff *skb /**<sk_buff of ARP request*/
- );
INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
struct sk_buff *Packet, /**<data buffer*/
@@ -70,11 +50,9 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
char *pControlPacket/**<Control Packet*/
);
-INT bcm_transmit(struct sk_buff *skb, /**< skb */
- struct net_device *dev /**< net device pointer */
- );
int register_networkdev(PMINI_ADAPTER Adapter);
+void unregister_networkdev(PMINI_ADAPTER Adapter);
INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
@@ -82,8 +60,6 @@ VOID AdapterFree(PMINI_ADAPTER Adapter);
INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
-int create_worker_threads(PMINI_ADAPTER psAdapter);
-
int tx_pkt_handler(PMINI_ADAPTER Adapter);
int reset_card_proc(PMINI_ADAPTER Adapter );
@@ -92,7 +68,6 @@ int run_card_proc(PMINI_ADAPTER Adapter );
int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter);
-int bcm_parse_target_params(PMINI_ADAPTER Adapter);
INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter);
@@ -110,26 +85,15 @@ int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __user * user_buffer);
-void SendLinkDown(PMINI_ADAPTER Adapter);
-
void SendIdleModeResponse(PMINI_ADAPTER Adapter);
-void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer);
-
-int ProcessGetHostMibs(PMINI_ADAPTER Adapter, PVOID ioBuffer,
- ULONG inputBufferLength);
-int GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang);
+int ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *buf);
+void GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *ioBuffer, PPER_TARANG_DATA pTarang);
void beceem_parse_target_struct(PMINI_ADAPTER Adapter);
-void doPowerAutoCorrection(PMINI_ADAPTER psAdapter);
-
int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo);
-void bcm_unregister_networkdev(PMINI_ADAPTER Adapter);
-
-int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid);
-
void CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter,
CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex);
@@ -149,7 +113,6 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter);
void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter,B_UINT16 TID,BOOLEAN bFreeAll);
-void beceem_protocol_reset (PMINI_ADAPTER Adapter);
void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex);
@@ -164,31 +127,11 @@ INT BeceemEEPROMBulkRead(
UINT uiNumBytes);
-INT BeceemFlashBulkRead(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes);
-
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData);
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize);
-
-INT BeceemFlashBulkWrite(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes,
- BOOLEAN bVerify);
-
INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter);
-INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter);
-
INT BeceemEEPROMBulkWrite(
PMINI_ADAPTER Adapter,
@@ -198,11 +141,8 @@ INT BeceemEEPROMBulkWrite(
BOOLEAN bVerify);
-INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData);
-
INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData);
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
INT BeceemNVMRead(
PMINI_ADAPTER Adapter,
@@ -217,24 +157,12 @@ INT BeceemNVMWrite(
UINT uiNumBytes,
BOOLEAN bVerify);
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
INT BcmInitNVM(PMINI_ADAPTER Adapter);
-INT BcmGetNvmSize(PMINI_ADAPTER Adapter);
-
-INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
-
-VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter);
+INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
+BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
-INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTION_VAL dsd);
-INT BcmGetActiveDSD(PMINI_ADAPTER Adapter);
-INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTION_VAL IsoImage);
-INT BcmGetActiveISO(PMINI_ADAPTER Adapter);
-B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset);
INT BcmGetFlash2xSectionalBitMap(PMINI_ADAPTER Adapter, PFLASH2X_BITMAP psFlash2xBitMap);
INT BcmFlash2xBulkWrite(
@@ -251,7 +179,6 @@ INT BcmFlash2xBulkRead(
FLASH2X_SECTION_VAL eFlashSectionVal,
UINT uiOffsetWithinSectionVal,
UINT uiNumBytes);
-INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
INT BcmGetSectionValStartOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
@@ -264,34 +191,13 @@ INT BcmFlash2xCorruptSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSect
INT BcmFlash2xWriteSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
INT validateFlash2xReadWrite(PMINI_ADAPTER Adapter, PFLASH2X_READWRITE psFlash2xReadWrite);
INT IsFlash2x(PMINI_ADAPTER Adapter);
-INT GetFlashBaseAddr(PMINI_ADAPTER Adapter);
-INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr);
INT BcmCopySection(PMINI_ADAPTER Adapter,
FLASH2X_SECTION_VAL SrcSection,
FLASH2X_SECTION_VAL DstSection,
UINT offset,
UINT numOfBytes);
-INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset);
-INT BcmMakeFlashCSActive(PMINI_ADAPTER Adapter, UINT offset);
-INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter);
-INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter);
-INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter,
- PUINT pBuff,
- FLASH2X_SECTION_VAL eFlash2xSectionVal,
- UINT uiOffset,
- UINT uiNumBytes
- );
-
-//UINT getNumOfSubSectionWithWRPermisson(PMINI_ADAPTER Adapter, SECTION_TYPE secType);
-BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section);
-INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+
BOOLEAN IsNonCDLessDevice(PMINI_ADAPTER Adapter);
@@ -300,7 +206,6 @@ VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter,PUINT puiBuffer);
int wrmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
int rdmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
-int rdmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
unsigned long u32StartingAddress);
@@ -309,11 +214,6 @@ INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned
VOID putUsbSuspend(struct work_struct *work);
BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios);
-#ifdef BCM_SHM_INTERFACE
-INT beceem_virtual_device_init(void);
-VOID virtual_mail_box_interrupt(void);
-INT beceem_virtual_device_exit(void);
-#endif
#endif
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index 75b2b879633f..8ce4536e6e28 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -4,15 +4,14 @@ This file contains the routines related to Quality of Service.
*/
#include "headers.h"
-BOOLEAN MatchSrcIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulSrcIP);
-BOOLEAN MatchTos(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucTypeOfService);
-BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort);
-BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
-BOOLEAN MatchDestIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulDestIP);
-USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb);
-void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
-BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport);
+static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
+static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport);
+
+static USHORT IpVersion4(PMINI_ADAPTER Adapter, struct iphdr *iphd,
+ S_CLASSIFIER_RULE *pstClassifierRule );
+
+static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex);
+
/*******************************************************************
* Function - MatchSrcIpAddress()
@@ -205,11 +204,10 @@ BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort)
Compares IPV4 Ip address and port number
@return Queue Index.
*/
-USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
- struct iphdr *iphd, /**<Pointer to the IP Hdr of the packet*/
- S_CLASSIFIER_RULE *pstClassifierRule )
+static USHORT IpVersion4(PMINI_ADAPTER Adapter,
+ struct iphdr *iphd,
+ S_CLASSIFIER_RULE *pstClassifierRule )
{
- //IPHeaderFormat *pIpHeader=NULL;
xporthdr *xprt_hdr=NULL;
BOOLEAN bClassificationSucceed=FALSE;
@@ -261,15 +259,6 @@ USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
//if protocol is not TCP or UDP then no need of comparing source port and destination port
if(iphd->protocol!=TCP && iphd->protocol!=UDP)
break;
-#if 0
- //check if memory is available of src and Dest port
- if(ETH_AND_IP_HEADER_LEN + L4_SRC_PORT_LEN + L4_DEST_PORT_LEN > Packet->len)
- {
- //This is not an erroneous condition and pkt will be checked for next classification.
- bClassificationSucceed = FALSE;
- break;
- }
-#endif
//******************Checking Transport Layer Header field if present *****************//
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
(iphd->protocol==UDP)?xprt_hdr->uhdr.source:xprt_hdr->thdr.source);
@@ -312,29 +301,6 @@ USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
return bClassificationSucceed;
}
-/**
-@ingroup tx_functions
-@return Queue Index based on priority.
-*/
-USHORT GetPacketQueueIndex(PMINI_ADAPTER Adapter, /**<Pointer to the driver control structure */
- struct sk_buff* Packet /**< Pointer to the Packet to be sent*/
- )
-{
- USHORT usIndex=-1;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "=====>");
-
- if(NULL==Adapter || NULL==Packet)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got NULL Values<======");
- return -1;
- }
-
- usIndex = ClassifyPacket(Adapter,Packet);
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got Queue Index %x",usIndex);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "GetPacketQueueIndex <==============");
- return usIndex;
-}
VOID PruneQueueAllSF(PMINI_ADAPTER Adapter)
{
@@ -357,23 +323,21 @@ is less than number of bytes in the queue. If so -
drops packets from the Head till the number of bytes is
less than or equal to max queue size for the queue.
*/
-VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structure*/
- INT iIndex/**<Queue Index*/
- )
+static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex)
{
struct sk_buff* PacketToDrop=NULL;
- struct net_device_stats* netstats=NULL;
+ struct net_device_stats *netstats;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d",iIndex);
if(iIndex == HiPriority)
- return;
+ return;
if(!Adapter || (iIndex < 0) || (iIndex > HiPriority))
return;
/* To Store the netdevice statistic */
- netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
+ netstats = &Adapter->dev->stats;
spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
@@ -395,9 +359,13 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
if(PacketToDrop)
{
- if(netstats)
- netstats->tx_dropped++;
- atomic_inc(&Adapter->TxDroppedPacketCount);
+ struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex);
+ if (netif_msg_tx_err(Adapter))
+ pr_info(PFX "%s: tx queue %d overlimit\n",
+ Adapter->dev->name, iIndex);
+
+ txq->tx_dropped++;
+
DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue,
Adapter->PackInfo[iIndex].LastTxQueue);
/// update current bytes and packets count
@@ -407,7 +375,7 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
/// update dropped bytes and packets counts
Adapter->PackInfo[iIndex].uiDroppedCountBytes += PacketToDrop->len;
Adapter->PackInfo[iIndex].uiDroppedCountPackets++;
- bcm_kfree_skb(PacketToDrop);
+ dev_kfree_skb(PacketToDrop);
}
@@ -416,7 +384,6 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
Adapter->PackInfo[iIndex].uiDroppedCountPackets);
atomic_dec(&Adapter->TotalPacketCount);
- Adapter->bcm_jiffies = jiffies;
}
spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
@@ -430,16 +397,15 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
{
INT iQIndex;
UINT uiTotalPacketLength;
- struct sk_buff* PacketToDrop=NULL;
- struct net_device_stats* netstats=NULL;
+ struct sk_buff* PacketToDrop=NULL;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
- /* To Store the netdevice statistic */
- netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
// down(&Adapter->data_packet_queue_lock);
for(iQIndex=LowPriority; iQIndex<HiPriority; iQIndex++)
{
+ struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iQIndex);
+
spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
while(Adapter->PackInfo[iQIndex].FirstTxQueue)
{
@@ -447,8 +413,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
if(PacketToDrop)
{
uiTotalPacketLength = PacketToDrop->len;
- netstats->tx_dropped++;
- atomic_inc(&Adapter->TxDroppedPacketCount);
+ txq->tx_dropped++;
}
else
uiTotalPacketLength = 0;
@@ -457,7 +422,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
Adapter->PackInfo[iQIndex].LastTxQueue);
/* Free the skb */
- bcm_kfree_skb(PacketToDrop);
+ dev_kfree_skb(PacketToDrop);
/// update current bytes and packets count
Adapter->PackInfo[iQIndex].uiCurrentBytesOnHost -= uiTotalPacketLength;
@@ -559,12 +524,6 @@ USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb)
for(uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
{
- if (Adapter->device_removed)
- {
- bClassificationSucceed = FALSE;
- break;
- }
-
if(bClassificationSucceed)
break;
//Iterate through all classifiers which are already in order of priority
@@ -810,7 +769,10 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s
}
-BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport)
+static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,
+ PS_ETHCS_PKT_INFO pstEthCsPktInfo,
+ S_CLASSIFIER_RULE *pstClassifierRule,
+ B_UINT8 EthCSCupport)
{
BOOLEAN bClassificationSucceed = FALSE;
bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((ETH_HEADER_STRUC *)(skb->data))->au8SourceAddress);
@@ -840,9 +802,11 @@ BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_
return bClassificationSucceed;
}
-void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
+static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,
+ PS_ETHCS_PKT_INFO pstEthCsPktInfo)
{
USHORT u16Etype = ntohs(((ETH_HEADER_STRUC*)pvEthPayload)->u16Etype);
+
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype);
if(u16Etype > 0x5dc)
{
diff --git a/drivers/staging/bcm/TODO b/drivers/staging/bcm/TODO
index 366634be5fe1..cd3e9f2ed87a 100644
--- a/drivers/staging/bcm/TODO
+++ b/drivers/staging/bcm/TODO
@@ -1,15 +1,22 @@
+This driver is barely functional in its current state.
+
+BIG:
+ - existing API is (/dev/tarang) should be replaced
+ Is it possible to use same API as Intel Wimax stack and
+ have same user level components.
+ - Qos and queue model is non-standard and inflexible.
+ Use existing TC Qos?
+
TODO:
+ - support more than one board - eliminate global variables
+ - remove developer debug BCM_DEBUG() macros
+ add a limited number of messages through netif_msg()
- fix non-standard kernel style
- - sparse warnings
- checkpatch warnings
- - remove compatiablity code for older kernels
- - remove #ifdef's
- - fix bogus device nameing and reference counting (see bcm_notify_event)
- - fix use of file I/O to load config
- - request firmware
- - update to current network device API
- - merge some files together
+ - use request firmware
+ - fix use of file I/O to load config with better API
+ - merge some files together?
- cleanup/eliminate debug messages
- - integrate with existing Wimax stack?
+
diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c
index 12f9e13457db..0f7000960d50 100644
--- a/drivers/staging/bcm/Transmit.c
+++ b/drivers/staging/bcm/Transmit.c
@@ -6,7 +6,7 @@
digraph transmit1 {
node[shape=box]
edge[weight=5;color=red]
-bcm_transmit->reply_to_arp_request[label="ARP"]
+
bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
GetPacketQueueIndex->IpVersion4[label="IPV4"]
GetPacketQueueIndex->IpVersion6[label="IPV6"]
@@ -35,169 +35,16 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
#include "headers.h"
-/*******************************************************************
-* Function - bcm_transmit()
-*
-* Description - This is the main transmit function for our virtual
-* interface(veth0). It handles the ARP packets. It
-* clones this packet and then Queue it to a suitable
-* Queue. Then calls the transmit_packet().
-*
-* Parameter - skb - Pointer to the socket buffer structure
-* dev - Pointer to the virtual net device structure
-*
-* Returns - zero (success) or -ve value (failure)
-*
-*********************************************************************/
-
-INT bcm_transmit(struct sk_buff *skb, /**< skb */
- struct net_device *dev /**< net device pointer */
- )
-{
- PMINI_ADAPTER Adapter = NULL;
- USHORT qindex=0;
- struct timeval tv;
- UINT pkt_type = 0;
- UINT calltransmit = 0;
-
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__);
-
- memset(&tv, 0, sizeof(tv));
- /* Check for valid parameters */
- if(skb == NULL || dev==NULL)
- {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
- return -EINVAL;
- }
-
- Adapter = GET_BCM_ADAPTER(dev);
- if(!Adapter)
- {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n");
- return -EINVAL;
- }
- if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus)
- {
- if(!netif_queue_stopped(dev)) {
- netif_carrier_off(dev);
- netif_stop_queue(dev);
- }
- return STATUS_FAILURE;
- }
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len);
-
- /*Add Ethernet CS check here*/
- if(Adapter->TransferMode == IP_PACKET_ONLY_MODE )
- {
- pkt_type = ntohs(*(PUSHORT)(skb->data + 12));
- /* Get the queue index where the packet is to be queued */
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index.....");
-
- qindex = GetPacketQueueIndex(Adapter,skb);
-
- if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
- {
- if(pkt_type == ETH_ARP_FRAME)
- {
- /*
- Reply directly to ARP request packet
- ARP Spoofing only if NO ETH CS rule matches for it
- */
- BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x",
-
- (*(PUCHAR)(skb->data + 21)));
-
- reply_to_arp_request(skb);
-
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");
-
- }
- else
- {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
- "Invalid queue index, dropping pkt\n");
-
- bcm_kfree_skb(skb);
- }
- return STATUS_SUCCESS;
- }
-
- if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
- {
- atomic_inc(&Adapter->TxDroppedPacketCount);
- bcm_kfree_skb(skb);
- return STATUS_SUCCESS;
- }
-
- /* Now Enqueue the packet */
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
- spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
- Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
- Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
-
- *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
- ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
- Adapter->PackInfo[qindex].LastTxQueue, skb);
- atomic_inc(&Adapter->TotalPacketCount);
- spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
- do_gettimeofday(&tv);
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n",
- (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec);
-
-#ifdef BCM_SHM_INTERFACE
- spin_lock(&Adapter->txtransmitlock);
- if(Adapter->txtransmit_running == 0)
- {
- Adapter->txtransmit_running = 1;
- calltransmit = 1;
- }
- else
- calltransmit = 0;
-
- spin_unlock(&Adapter->txtransmitlock);
-#endif
- if(calltransmit == 1)
- transmit_packets(Adapter);
- else
- {
- if(!atomic_read(&Adapter->TxPktAvail))
- {
- atomic_set(&Adapter->TxPktAvail, 1);
-#ifdef BCM_SHM_INTERFACE
- virtual_mail_box_interrupt();
-#endif
- wake_up(&Adapter->tx_packet_wait_queue);
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
- }
- else
- bcm_kfree_skb(skb);
-
- return STATUS_SUCCESS;
-}
-
/**
@ingroup ctrl_pkt_functions
This function dispatches control packet to the h/w interface
@return zero(success) or -ve value(failure)
*/
-INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
- char *pControlPacket/**<Control Packet*/
- )
+INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket)
{
- PLEADER PLeader = NULL;
- struct timeval tv;
- memset(&tv, 0, sizeof(tv));
-
-
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
+ PLEADER PLeader = (PLEADER)pControlPacket;
- PLeader=(PLEADER)pControlPacket;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
if(!pControlPacket || !Adapter)
{
@@ -208,12 +55,6 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
- if(Adapter->bcm_jiffies == 0)
- {
- Adapter->bcm_jiffies = jiffies;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
- Adapter->bcm_jiffies);
- }
return STATUS_FAILURE;
}
@@ -224,76 +65,33 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
if(Adapter->device_removed)
return 0;
-#ifndef BCM_SHM_INTERFACE
- Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
- pControlPacket, (PLeader->PLength + LEADER_SIZE));
-#else
- tx_pkts_to_firmware(pControlPacket,(PLeader->PLength + LEADER_SIZE),1);
- if(PLeader->Status==IDLE_MESSAGE)
- {
- if(((CONTROL_MESSAGE*)PLeader)->szData[0] == GO_TO_IDLE_MODE_PAYLOAD &&
- ((CONTROL_MESSAGE*)PLeader)->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Idle Mode Ack Sent to the Device\n");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Host Entering into Idle Mode\n");
- do_gettimeofday(&tv);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "IdleMode Msg sent to f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
- if(Adapter->bDoSuspend != TRUE)
- {
- Adapter->IdleMode = TRUE;
- Adapter->bPreparingForLowPowerMode = FALSE ;
- }
- }
- }
- if((PLeader->Status == LINK_UP_CONTROL_REQ) &&
- ((PUCHAR)pControlPacket)[sizeof(LEADER)] == LINK_UP_ACK &&
- ((PUCHAR)pControlPacket)[sizeof(LEADER)+1] ==
- LINK_SHUTDOWN_REQ_FROM_FIRMWARE &&
- ((PUCHAR)pControlPacket)[sizeof(LEADER)+2] == SHUTDOWN_ACK_FROM_DRIVER)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Shut Down ACK Sent and Host entering Shut State \n");
- if(Adapter->bDoSuspend != TRUE)
- {
- Adapter->bShutStatus = TRUE;
- Adapter->bPreparingForLowPowerMode = FALSE;
- Adapter->bTriedToWakeUpFromlowPowerMode = FALSE;
- }
+ if (netif_msg_pktdata(Adapter))
+ print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE,
+ 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
- }
-#endif
+ Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
+ pControlPacket, (PLeader->PLength + LEADER_SIZE));
- ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_packets++;
- ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_bytes+=
- PLeader->PLength;
atomic_dec(&Adapter->CurrNumFreeTxDesc);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
return STATUS_SUCCESS;
}
-static LEADER Leader={0};
+
/**
@ingroup tx_functions
This function despatches the IP packets with the given vcid
to the target via the host h/w interface.
@return zero(success) or -ve value(failure)
*/
-INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
- struct sk_buff *Packet, /**<data buffer*/
- USHORT Vcid) /**<VCID for this packet*/
+INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid)
{
int status=0;
-#ifdef GDMA_INTERFACE
- int dontfree = 0;
-#endif
BOOLEAN bHeaderSupressionEnabled = FALSE;
B_UINT16 uiClassifierRuleID;
- int QueueIndex = NO_OF_QUEUES + 1;
+ u16 QueueIndex = skb_get_queue_mapping(Packet);
+ LEADER Leader={0};
- if(!Adapter || !Packet)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
- return -EINVAL;
- }
if(Packet->len > MAX_DEVICE_DESC_SIZE)
{
status = STATUS_FAILURE;
@@ -302,14 +100,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
/* Get the Classifier Rule ID */
uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
- QueueIndex = SearchVcid( Adapter,Vcid);
- if(QueueIndex < NO_OF_QUEUES)
- {
- bHeaderSupressionEnabled =
- Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
- bHeaderSupressionEnabled =
- bHeaderSupressionEnabled & Adapter->bPHSEnabled;
- }
+
+ bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
+ & Adapter->bPHSEnabled;
+
if(Adapter->device_removed)
{
status = STATUS_FAILURE;
@@ -327,15 +121,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
Leader.Vcid = Vcid;
- if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
+ if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
Leader.Status = LEADER_STATUS_TCP_ACK;
- }
else
- {
Leader.Status = LEADER_STATUS;
- }
if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
{
@@ -351,68 +140,53 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
skb_push(Packet, LEADER_SIZE);
memcpy(Packet->data, &Leader, LEADER_SIZE);
}
-
else
{
Leader.PLength = Packet->len - ETH_HLEN;
memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
-
-#ifndef BCM_SHM_INTERFACE
status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
Packet->data, (Leader.PLength + LEADER_SIZE));
-#else
- status = tx_pkts_to_firmware(Packet,Packet->len,0);
-#endif
if(status)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
+ ++Adapter->dev->stats.tx_errors;
+ if (netif_msg_tx_err(Adapter))
+ pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name,
+ status);
}
else
{
+ struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex);
Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
- atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
- atomic_inc(&Adapter->TxTotalPacketCount);
-#ifdef GDMA_INTERFACE
- dontfree = 1;
-#endif
- }
- atomic_dec(&Adapter->CurrNumFreeTxDesc);
-
-errExit:
+ txq->tx_bytes += Leader.PLength;
+ ++txq->tx_packets;
- if(STATUS_SUCCESS == status)
- {
Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
Adapter->PackInfo[QueueIndex].uiSentPackets++;
Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
-#ifdef BCM_SHM_INTERFACE
- if(atomic_read(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount) < 0)
- {
- atomic_set(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount, 0);
- }
-#endif
Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
}
+ atomic_dec(&Adapter->CurrNumFreeTxDesc);
-#ifdef GDMA_INTERFACE
- if(!dontfree){
- bcm_kfree_skb(Packet);
- }
-#else
- bcm_kfree_skb(Packet);
-#endif
+errExit:
+
+ dev_kfree_skb(Packet);
return status;
}
+static int tx_pending(PMINI_ADAPTER Adapter)
+{
+ return (atomic_read(&Adapter->TxPktAvail)
+ && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
+ || Adapter->device_removed || (1 == Adapter->downloadDDR);
+}
+
/**
@ingroup tx_functions
Transmit thread
@@ -420,57 +194,26 @@ Transmit thread
int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
)
{
-#ifndef BCM_SHM_INTERFACE
int status = 0;
-#endif
-
- UINT calltransmit = 1;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = %p",Adapter);
-
- while(1)
- {
- if(Adapter->LinkUpStatus){
+ while(! kthread_should_stop()) {
+ /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
+ if(Adapter->LinkUpStatus)
wait_event_timeout(Adapter->tx_packet_wait_queue,
- ((atomic_read(&Adapter->TxPktAvail) &&
- (MINIMUM_PENDING_DESCRIPTORS <
- atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
- (Adapter->device_removed == FALSE))) ||
- (1 == Adapter->downloadDDR) || kthread_should_stop()
-#ifndef BCM_SHM_INTERFACE
- || (TRUE == Adapter->bEndPointHalted)
-#endif
- , msecs_to_jiffies(10));
- }
- else{
- wait_event(Adapter->tx_packet_wait_queue,
- ((atomic_read(&Adapter->TxPktAvail) &&
- (MINIMUM_PENDING_DESCRIPTORS <
- atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
- (Adapter->device_removed == FALSE))) ||
- (1 == Adapter->downloadDDR) || kthread_should_stop()
-#ifndef BCM_SHM_INTERFACE
- || (TRUE == Adapter->bEndPointHalted)
-#endif
- );
- }
-
- if(kthread_should_stop() || Adapter->device_removed)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
- Adapter->transmit_packet_thread = NULL;
- return 0;
- }
+ tx_pending(Adapter), msecs_to_jiffies(10));
+ else
+ wait_event_interruptible(Adapter->tx_packet_wait_queue,
+ tx_pending(Adapter));
-#ifndef BCM_SHM_INTERFACE
+ if (Adapter->device_removed)
+ break;
if(Adapter->downloadDDR == 1)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
Adapter->downloadDDR +=1;
status = download_ddr_settings(Adapter);
if(status)
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
+ pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
continue;
}
@@ -489,7 +232,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
update_per_sf_desc_cnts(Adapter);
}
}
-#endif
if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
Adapter->LinkStatus == SYNC_UP_REQUEST &&
@@ -507,49 +249,12 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
wake_up(&Adapter->process_rx_cntrlpkt);
}
-#ifdef BCM_SHM_INTERFACE
- spin_lock_bh(&Adapter->txtransmitlock);
- if(Adapter->txtransmit_running == 0)
- {
- Adapter->txtransmit_running = 1;
- calltransmit = 1;
- }
- else
- calltransmit = 0;
- spin_unlock_bh(&Adapter->txtransmitlock);
-#endif
-
- if(calltransmit)
- transmit_packets(Adapter);
+ transmit_packets(Adapter);
atomic_set(&Adapter->TxPktAvail, 0);
}
- return 0;
-}
-
-#ifdef BCM_SHM_INTERFACE
-extern PMINI_ADAPTER psAdaptertest;
-void virtual_mail_box_interrupt(void)
-{
-
-#ifndef GDMA_INTERFACE
- PUINT ptr = (PUINT)CPE_VIRTUAL_MAILBOX_REG;
- UINT intval = (UINT)((*ptr & 0xFF00) >> 8);
- if (intval != 0)
- {
- atomic_set(&psAdaptertest->CurrNumFreeTxDesc, intval);
- atomic_set (&psAdaptertest->uiMBupdate, TRUE);
- //make it to 0
- *ptr = *ptr & 0xffff00ff;
- }
-#endif
-}
-unsigned int total_tx_pkts_pending(void)
-{
- return atomic_read(&psAdaptertest->TotalPacketCount);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
+ Adapter->transmit_packet_thread = NULL;
+ return 0;
}
-
-#endif
-
-
diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h
index 4cbe30022248..890778450a86 100644
--- a/drivers/staging/bcm/cntrl_SignalingInterface.h
+++ b/drivers/staging/bcm/cntrl_SignalingInterface.h
@@ -2,19 +2,6 @@
#define CNTRL_SIGNALING_INTERFACE_
-#ifdef BECEEM_TARGET
-
-#include <mac_common.h>
-#include <msg_Dsa.h>
-#include <msg_Dsc.h>
-#include <msg_Dsd.h>
-#include <sch_definitions.h>
-using namespace Beceem;
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
-extern B_UINT32 g_u32Corr2MacFlags;
-#endif
-
-#else
#define DSA_REQ 11
@@ -28,7 +15,6 @@ extern B_UINT32 g_u32Corr2MacFlags;
#define DSD_ACK 19
#define MAX_CLASSIFIERS_IN_SF 4
-#endif
#define MAX_STRING_LEN 20
#define MAX_PHS_LENGTHS 255
@@ -57,37 +43,7 @@ extern B_UINT32 g_u32Corr2MacFlags;
////////////////////////structure Definitions///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// \brief class cCPacketClassificationRule
-#ifdef BECEEM_TARGET
-class CCPacketClassificationRuleSI{
- public:
- /// \brief Constructor for the class
- CCPacketClassificationRuleSI():
- u8ClassifierRulePriority(mClassifierRulePriority),
- u8IPTypeOfServiceLength(mIPTypeOfService),
- u8Protocol(mProtocol),
- u8IPMaskedSourceAddressLength(0),
- u8IPDestinationAddressLength(0),
- u8ProtocolSourcePortRangeLength(0),
- u8ProtocolDestPortRangeLength(0),
- u8EthernetDestMacAddressLength(0),
- u8EthernetSourceMACAddressLength(0),
- u8EthertypeLength(0),
- u16UserPriority(mUserPriority),
- u16VLANID(mVLANID),
- u8AssociatedPHSI(mAssociatedPHSI),
- u16PacketClassificationRuleIndex(mPacketClassifierRuleIndex),
- u8VendorSpecificClassifierParamLength(mVendorSpecificClassifierParamLength),
- u8IPv6FlowLableLength(mIPv6FlowLableLength),
- u8ClassifierActionRule(mClassifierActionRule)
-
- {}
- void Reset()
- {
- CCPacketClassificationRuleSI();
- }
-#else
struct _stCPacketClassificationRuleSI{
-#endif
/** 16bit UserPriority Of The Service Flow*/
B_UINT16 u16UserPriority;
@@ -145,29 +101,10 @@ struct _stCPacketClassificationRuleSI{
B_UINT8 u8ClassifierActionRule;
B_UINT16 u16ValidityBitMap;
};
-#ifndef BECEEM_TARGET
typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI;
-#endif
/// \brief class CPhsRuleSI
-#ifdef BECEEM_TARGET
-class CPhsRuleSI{
- public:
- /// \brief Constructor for the class
- CPhsRuleSI():
- u8PHSI(mPHSI),
- u8PHSFLength(0),
- u8PHSMLength(0),
- u8PHSS(mPHSS),
- u8PHSV(mPHSV),
- u8VendorSpecificPHSParamsLength(mVendorSpecificPHSParamLength){}
- void Reset()
- {
- CPhsRuleSI();
- }
-#else
typedef struct _stPhsRuleSI {
-#endif
/** 8bit PHS Index Of The Service Flow*/
B_UINT8 u8PHSI;
/** PHSF Length Of The Service Flow*/
@@ -188,31 +125,11 @@ typedef struct _stPhsRuleSI {
B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
B_UINT8 u8Padding[2];
-#ifdef BECEEM_TARGET
-};
-#else
}stPhsRuleSI,*pstPhsRuleSI;
typedef stPhsRuleSI CPhsRuleSI;
-#endif
/// \brief structure cConvergenceSLTypes
-#ifdef BECEEM_TARGET
-class CConvergenceSLTypes{
- public:
- /// \brief Constructor for the class
- CConvergenceSLTypes():
- u8ClassfierDSCAction(mClassifierDSCAction),
- u8PhsDSCAction (mPhsDSCAction)
- {}
- void Reset()
- {
- CConvergenceSLTypes();
- cCPacketClassificationRule.Reset();
- cPhsRule.Reset();
- }
-#else
struct _stConvergenceSLTypes{
-#endif
/** 8bit Phs Classfier Action Of The Service Flow*/
B_UINT8 u8ClassfierDSCAction;
/** 8bit Phs DSC Action Of The Service Flow*/
@@ -220,111 +137,15 @@ struct _stConvergenceSLTypes{
/** 16bit Padding */
B_UINT8 u8Padding[2];
/// \brief class cCPacketClassificationRule
-#ifdef BECEEM_TARGET
- CCPacketClassificationRuleSI cCPacketClassificationRule;
-#else
stCPacketClassificationRuleSI cCPacketClassificationRule;
-#endif
/// \brief class CPhsRuleSI
-#ifdef BECEEM_TARGET
- CPhsRuleSI cPhsRule;
-#else
struct _stPhsRuleSI cPhsRule;
-#endif
};
-#ifndef BECEEM_TARGET
typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes;
-#endif
/// \brief structure CServiceFlowParamSI
-#ifdef BECEEM_TARGET
-class CServiceFlowParamSI{
- public:
- /// \brief Constructor for the class
- CServiceFlowParamSI():
- u32SFID(mSFid),
- u16CID(mCid),
- u8ServiceClassNameLength(mServiceClassNameLength),
- u8MBSService(mMBSService),
- u8QosParamSet(mQosParamSetType),
- u8TrafficPriority(mTrafficPriority),
- u32MaxSustainedTrafficRate(mMaximumSustainedTrafficRate),
- u32MaxTrafficBurst(mMaximumTrafficBurst),
- u32MinReservedTrafficRate(mMinimumReservedTrafficRate),
- u8ServiceFlowSchedulingType(mServiceFlowSchedulingType),
- u8RequesttransmissionPolicy(mRequestTransmissionPolicy),
- u32ToleratedJitter(mToleratedJitter),
- u32MaximumLatency(mMaximumLatency),
- u8FixedLengthVSVariableLengthSDUIndicator
- (mFixedLengthVSVariableLength),
- u8SDUSize(mSDUSize),
- u16TargetSAID(mTargetSAID),
- u8ARQEnable(mARQEnable),
- u16ARQWindowSize(mARQWindowSize),
- u16ARQBlockLifeTime(mARQBlockLifeTime),
- u16ARQSyncLossTimeOut(mARQSyncLossTimeOut),
- u8ARQDeliverInOrder(mARQDeliverInOrder),
- u16ARQRxPurgeTimeOut(mARQRXPurgeTimeOut),
- //Add ARQ BLOCK SIZE, ARQ TX and RX delay initializations here
- //after we move to only CORR2
- u8RxARQAckProcessingTime(mRxARQAckProcessingTime),
- u8CSSpecification(mCSSpecification),
- u8TypeOfDataDeliveryService(mTypeOfDataDeliveryService),
- u16SDUInterArrivalTime(mSDUInterArrivalTime),
- u16TimeBase(mTimeBase),
- u8PagingPreference(mPagingPreference),
- u8MBSZoneIdentifierassignment(mMBSZoneIdentifierassignmentLength),
- u8TrafficIndicationPreference(mTrafficIndicationPreference),
- u8GlobalServicesClassNameLength(mGlobalServicesClassNameLength),
- u8SNFeedbackEnabled(mSNFeedbackEnabled),
- u8FSNSize(mFSNSize),
- u8CIDAllocation4activeBSsLength(mCIDAllocation4activeBSsLength),
- u16UnsolicitedGrantInterval(mUnsolicitedGrantInterval),
- u16UnsolicitedPollingInterval(mUnsolicitedPollingInterval),
- u8PDUSNExtendedSubheader4HarqReordering(mPDUSNExtendedSubheader4HarqReordering),
- u8MBSContentsIDLength(mMBSContentsIDLength),
- u8HARQServiceFlows(mHARQServiceFlows),
- u8AuthTokenLength(mAuthTokenLength),
- u8HarqChannelMappingLength(mHarqChannelMappingLength),
- u8VendorSpecificQoSParamLength(mVendorSpecificQoSParamLength),
- bValid(FALSE),
- u8TotalClassifiers()
-{
-//Remove the bolck after we move to Corr2 only code
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
- if((g_u32Corr2MacFlags & CORR_2_DSX) || (g_u32Corr2MacFlags & CORR_2_ARQ))
- {
- /* IEEE Comment #627 / MTG Comment #426 */
- u16ARQBlockSize = mARQBlockSize;
- if(g_u32Corr2MacFlags & CORR_2_ARQ) {
- u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelay;
- if(g_u32VENDOR_TYPE == VENDOR_ALCATEL) {
- u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay_ALU;
- } else {
- u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay;
- }
- }
- else
- {
- u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1;
- u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1;
- }
- }
- else
-#endif
- {
- u16ARQBlockSize = mARQBlockSizeCorr1;
- u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1;
- u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1;
- }
-}
-
- void ComputeMacOverhead(B_UINT8 u8SecOvrhead);
- B_UINT16 GetMacOverhead() { return u16MacOverhead; }
-#else
typedef struct _stServiceFlowParamSI{
-#endif //end of ifdef BECEEM_TARGET
/** 32bitSFID Of The Service Flow*/
B_UINT32 u32SFID;
@@ -367,11 +188,6 @@ typedef struct _stServiceFlowParamSI{
/** 16bit ARQ Purge timeout */
B_UINT16 u16ARQRxPurgeTimeOut;
-#if 0 //def ENABLE_CORRIGENDUM2_UPDATE
-/* IEEE Comment #627 / MTG Comment #426 */
- /// \brief Size of an ARQ block, changed from 2 bytes to 1
- B_UINT8 u8ARQBlockSize;
-#endif
//TODO::Remove this once we move to a new CORR2 driver
/// \brief Size of an ARQ block
B_UINT16 u16ARQBlockSize;
@@ -496,35 +312,18 @@ typedef struct _stServiceFlowParamSI{
B_UINT8 bValid; /**< Validity flag */
B_UINT8 u8Padding; /**< Padding byte*/
-#ifdef BECEEM_TARGET
-/**
-Structure for Convergence SubLayer Types with a maximum of 4 classifiers
-*/
- CConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
-#else
/**
Structure for Convergence SubLayer Types with a maximum of 4 classifiers
*/
stConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
-#endif
-#ifdef BECEEM_TARGET
-};
-#else
} stServiceFlowParamSI, *pstServiceFlowParamSI;
typedef stServiceFlowParamSI CServiceFlowParamSI;
-#endif
/**
structure stLocalSFAddRequest
*/
typedef struct _stLocalSFAddRequest{
-#ifdef BECEEM_TARGET
- _stLocalSFAddRequest( ) :
- u8Type(0x00), eConnectionDir(0x00),
- u16TID(0x0000), u16CID(0x0000), u16VCID(0x0000)
- {}
-#endif
B_UINT8 u8Type; /**< Type*/
B_UINT8 eConnectionDir; /**< Connection direction*/
@@ -535,19 +334,9 @@ typedef struct _stLocalSFAddRequest{
/// \brief 16bitVCID
B_UINT16 u16VCID; /**< 16bit VCID*/
/// \brief structure ParameterSet
-#ifdef BECEEM_SIGNALLING_INTERFACE_API
- CServiceFlowParamSI sfParameterSet;
-#endif
-#ifdef BECEEM_TARGET
- CServiceFlowParamSI *psfParameterSet;
-#else
stServiceFlowParamSI *psfParameterSet; /**< structure ParameterSet*/
-#endif
-#ifdef USING_VXWORKS
- USE_DATA_MEMORY_MANAGER();
-#endif
}stLocalSFAddRequest, *pstLocalSFAddRequest;
@@ -555,12 +344,6 @@ typedef struct _stLocalSFAddRequest{
structure stLocalSFAddIndication
*/
typedef struct _stLocalSFAddIndication{
-#ifdef BECEEM_TARGET
- _stLocalSFAddIndication( ) :
- u8Type(0x00), eConnectionDir(0x00),
- u16TID(0x0000), u16CID(0x0000), u16VCID(0x0000)
- {}
-#endif
B_UINT8 u8Type; /**< Type*/
B_UINT8 eConnectionDir; /**< Connection Direction*/
@@ -571,37 +354,19 @@ typedef struct _stLocalSFAddIndication{
/// \brief 16bitVCID
B_UINT16 u16VCID; /**< 16bitVCID*/
-#ifdef BECEEM_SIGNALLING_INTERFACE_API
- CServiceFlowParamSI sfAuthorizedSet;
- /// \brief structure AdmittedSet
- CServiceFlowParamSI sfAdmittedSet;
- /// \brief structure ActiveSet
- CServiceFlowParamSI sfActiveSet;
-#endif
/// \brief structure AuthorizedSet
-#ifdef BECEEM_TARGET
- CServiceFlowParamSI *psfAuthorizedSet;
- /// \brief structure AdmittedSet
- CServiceFlowParamSI *psfAdmittedSet;
- /// \brief structure ActiveSet
- CServiceFlowParamSI *psfActiveSet;
-#else
/// \brief structure AuthorizedSet
stServiceFlowParamSI *psfAuthorizedSet; /**< AuthorizedSet of type stServiceFlowParamSI*/
/// \brief structure AdmittedSet
stServiceFlowParamSI *psfAdmittedSet; /**< AdmittedSet of type stServiceFlowParamSI*/
/// \brief structure ActiveSet
stServiceFlowParamSI *psfActiveSet; /**< sfActiveSet of type stServiceFlowParamSI*/
-#endif
B_UINT8 u8CC; /**< Confirmation Code*/
B_UINT8 u8Padd; /**< 8-bit Padding */
B_UINT16 u16Padd; /**< 16 bit Padding */
-#ifdef USING_VXWORKS
- USE_DATA_MEMORY_MANAGER();
-#endif
}stLocalSFAddIndication;
@@ -619,33 +384,17 @@ typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFCha
structure stLocalSFDeleteRequest
*/
typedef struct _stLocalSFDeleteRequest{
-#ifdef BECEEM_TARGET
- _stLocalSFDeleteRequest( ) :
- u8Type(0x00), u8Padding(0x00),
- u16TID(0x0000), u32SFID (0x00000000)
- {}
-#endif
B_UINT8 u8Type; /**< Type*/
B_UINT8 u8Padding; /**< Padding byte*/
B_UINT16 u16TID; /**< TID*/
/// \brief 32bitSFID
B_UINT32 u32SFID; /**< SFID*/
-#ifdef USING_VXWORKS
- USE_DATA_MEMORY_MANAGER();
-#endif
}stLocalSFDeleteRequest, *pstLocalSFDeleteRequest;
/**
structure stLocalSFDeleteIndication
*/
typedef struct stLocalSFDeleteIndication{
-#ifdef BECEEM_TARGET
- stLocalSFDeleteIndication( ) :
- u8Type(0x00), u8Padding(0x00),
- u16TID(0x0000), u16CID(0x0000),
- u16VCID(0x0000),u32SFID (0x00000000)
- {}
-#endif
B_UINT8 u8Type; /**< Type */
B_UINT8 u8Padding; /**< Padding */
B_UINT16 u16TID; /**< TID */
@@ -658,9 +407,6 @@ typedef struct stLocalSFDeleteIndication{
/// \brief 8bit Confirmation code
B_UINT8 u8ConfirmationCode; /**< Confirmation code */
B_UINT8 u8Padding1[3]; /**< 3 byte Padding */
-#ifdef USING_VXWORKS
- USE_DATA_MEMORY_MANAGER();
-#endif
}stLocalSFDeleteIndication;
typedef struct _stIM_SFHostNotify
diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h
index 9d4e3aca1b34..1148e5e22eb9 100644
--- a/drivers/staging/bcm/headers.h
+++ b/drivers/staging/bcm/headers.h
@@ -22,7 +22,6 @@
#include <linux/etherdevice.h>
#include <net/ip.h>
#include <linux/wait.h>
-#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
@@ -36,26 +35,10 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/kthread.h>
-#endif
#include <linux/tcp.h>
#include <linux/udp.h>
-#ifndef BCM_SHM_INTERFACE
#include <linux/usb.h>
-#endif
-#ifdef BECEEM_TARGET
-
-#include <mac_common.h>
-#include <msg_Dsa.h>
-#include <msg_Dsc.h>
-#include <msg_Dsd.h>
-#include <sch_definitions.h>
-using namespace Beceem;
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
-extern B_UINT32 g_u32Corr2MacFlags;
-#endif
-#endif
#include "Typedefs.h"
#include "Version.h"
@@ -71,39 +54,28 @@ extern B_UINT32 g_u32Corr2MacFlags;
#include "CmHost.h"
#include "DDRInit.h"
#include "Debug.h"
-#include "HostMibs.h"
#include "IPv6ProtocolHdr.h"
-#include "osal_misc.h"
#include "PHSModule.h"
#include "Protocol.h"
#include "Prototypes.h"
#include "Queue.h"
#include "vendorspecificextn.h"
-#ifndef BCM_SHM_INTERFACE
#include "InterfaceMacros.h"
#include "InterfaceAdapter.h"
#include "InterfaceIsr.h"
-#include "Interfacemain.h"
#include "InterfaceMisc.h"
#include "InterfaceRx.h"
#include "InterfaceTx.h"
-#endif
#include "InterfaceIdleMode.h"
#include "InterfaceInit.h"
-#ifdef BCM_SHM_INTERFACE
-#include <linux/cpe_config.h>
-
-#ifdef GDMA_INTERFACE
-#include "GdmaInterface.h"
-#include "symphony.h"
-#else
-#include "virtual_interface.h"
-
-#endif
-
-#endif
+#define DRV_NAME "beceem"
+#define DEV_NAME "tarang"
+#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver"
+#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc"
+#define DRV_VERSION VER_FILEVERSION_STR
+#define PFX DRV_NAME " "
#endif
diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c
index e9da513b3c24..c13ea5c9a2aa 100644
--- a/drivers/staging/bcm/hostmibs.c
+++ b/drivers/staging/bcm/hostmibs.c
@@ -10,12 +10,8 @@
*/
#include "headers.h"
-INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
- PVOID ioBuffer,
- ULONG inputBufferLength)
+INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs)
{
-
- S_MIBS_HOST_STATS_MIBS *pstHostMibs = NULL;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_PHS_RULE *pstPhsRule = NULL;
S_CLASSIFIER_TABLE *pstClassifierTable = NULL;
@@ -30,15 +26,6 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
return STATUS_FAILURE;
}
- if(ioBuffer == NULL)
- {
- return -EINVAL;
- }
- memset(ioBuffer,0,sizeof(S_MIBS_HOST_STATS_MIBS));
-
- pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer;
-
-
//Copy the classifier Table
for(nClassifierIndex=0; nClassifierIndex < MAX_CLASSIFIERS;
nClassifierIndex++)
@@ -54,7 +41,7 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
{
if(Adapter->PackInfo[nSfIndex].bValid)
{
- OsalMemMove((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE));
+ memcpy((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE));
}
else
{
@@ -83,7 +70,7 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
pstHostMibs->astPhsRulesTable[nPhsTableIndex].ulSFID = Adapter->PackInfo[nSfIndex].ulSFID;
- OsalMemMove(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI,
+ memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI,
&pstPhsRule->u8PHSI,
sizeof(S_PHS_RULE));
nPhsTableIndex++;
@@ -95,12 +82,9 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
}
-
//copy other Host Statistics parameters
- pstHostMibs->stHostInfo.GoodTransmits =
- atomic_read(&Adapter->TxTotalPacketCount);
- pstHostMibs->stHostInfo.GoodReceives =
- atomic_read(&Adapter->GoodRxPktCount);
+ pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets;
+ pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets;
pstHostMibs->stHostInfo.CurrNumFreeDesc =
atomic_read(&Adapter->CurrNumFreeTxDesc);
pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize;
@@ -115,13 +99,10 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
}
-INT GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang)
+VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, const PPER_TARANG_DATA pTarang)
{
- S_MIBS_HOST_STATS_MIBS *pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer;
-
- memcpy((PVOID)&(pstHostMibs->stDroppedAppCntrlMsgs),(PVOID)&(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
-
- return STATUS_SUCCESS ;
+ memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs),
+ &(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
}
diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c
index 97adaae7dfc0..16e939fa15d6 100644
--- a/drivers/staging/bcm/led_control.c
+++ b/drivers/staging/bcm/led_control.c
@@ -108,52 +108,16 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
ulong timeout = 0;
/*Read initial value of packets sent/received */
- Initial_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount);
- Initial_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount);
+ Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets;
+ Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets;
+
/*Scale the rate of transfer to no of blinks.*/
num_of_time_tx= ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
num_of_time_rx= ScaleRateofTransfer((ULONG)rate_of_transfer_rx);
while((Adapter->device_removed == FALSE))
{
- #if 0
- if(0 == num_of_time_tx && 0 == num_of_time_rx)
- {
- timeout = 1000;
- Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event,
- currdriverstate!= Adapter->DriverState || kthread_should_stop(),
- msecs_to_jiffies (timeout));
- if(kthread_should_stop())
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting");
- Adapter->LEDInfo.led_thread_running= BCM_LED_THREAD_DISABLED;
- return EVENT_SIGNALED;
- }
- if(Status)
- return EVENT_SIGNALED;
-
- }
- #endif
-
timeout = 50;
- #if 0
- /*Turn on LED if Tx is high bandwidth*/
- if(num_of_time_tx > MAX_NUM_OF_BLINKS)
- {
- TURN_ON_LED(1<<GPIO_Num_tx, uiTxLedIndex);
- num_of_time_tx = 0;
- bBlinkBothLED = FALSE;
- num_of_time = num_of_time_rx;
- }
- /*Turn on LED if Rx is high bandwidth*/
- if(num_of_time_rx > MAX_NUM_OF_BLINKS)
- {
- TURN_ON_LED(1<<GPIO_Num_rx, uiRxLedIndex);
- num_of_time_rx = 0;
- bBlinkBothLED = FALSE;
- num_of_time = num_of_time_tx;
- }
- #endif
/*Blink Tx and Rx LED when both Tx and Rx is in normal bandwidth*/
if(bBlinkBothLED)
{
@@ -249,9 +213,10 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
* Read the Tx & Rx packets transmission after 1 second and
* calculate rate of transfer
*/
- Final_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount);
+ Final_num_of_packts_tx = Adapter->dev->stats.tx_packets;
+ Final_num_of_packts_rx = Adapter->dev->stats.rx_packets;
+
rate_of_transfer_tx = Final_num_of_packts_tx - Initial_num_of_packts_tx;
- Final_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount);
rate_of_transfer_rx = Final_num_of_packts_rx - Initial_num_of_packts_rx;
/*Read initial value of packets sent/received */
@@ -293,7 +258,7 @@ static INT ValidateDSDParamsChecksum(
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",ulParamOffset, usParamLen);
- puBuffer = OsalMemAlloc(usParamLen,"!MEM");
+ puBuffer = kmalloc(usParamLen, GFP_KERNEL);
if(!puBuffer)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum Allocation failed");
@@ -341,10 +306,7 @@ static INT ValidateDSDParamsChecksum(
}
exit:
- if(puBuffer)
- {
- OsalMemFree(puBuffer, usParamLen);
- }
+ kfree(puBuffer);
return Status;
}
@@ -497,12 +459,10 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
{
int Status = STATUS_SUCCESS;
UCHAR GPIO_Array[NUM_OF_LEDS+1]; /*Array to store GPIO numbers from EEPROM*/
-#ifndef BCM_SHM_INTERFACE
UINT uiIndex = 0;
UINT uiNum_of_LED_Type = 0;
PUCHAR puCFGData = NULL;
UCHAR bData = 0;
-#endif
memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1);
if(!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams))
@@ -524,10 +484,6 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
*bEnableThread = FALSE;
return Status;
}
-#ifdef BCM_SHM_INTERFACE
- *bEnableThread = FALSE;
- return Status ;
-#else
/*
* CONFIG file read successfully. Deallocate the memory of
* uiFileNameBufferSize
@@ -578,23 +534,7 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
}
if(uiNum_of_LED_Type >= NUM_OF_LEDS)
*bEnableThread = FALSE;
-#endif
-#if 0
- for(uiIndex=0; uiIndex<NUM_OF_LEDS; uiIndex++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_Type = %x\n", uiIndex,
- Adapter->LEDInfo.LEDState[uiIndex].LED_Type);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_On_State = %x\n", uiIndex,
- Adapter->LEDInfo.LEDState[uiIndex].LED_On_State);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_Blink_State = %x\n", uiIndex,
- Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].GPIO_Num = %x\n", uiIndex,
- Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: Polarity = %d\n",
- Adapter->LEDInfo.BitPolarty);
-#endif
return Status;
}
//--------------------------------------------------------------------------
@@ -721,20 +661,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
TURN_OFF_LED(1<<GPIO_num, uiLedIndex);
return ;//STATUS_FAILURE;
}
- #if 0
- if(Adapter->device_removed)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"Device removed hence exiting from Led Thread..");
- return ; //-ENODEV;
- }
- #endif
- #if 0
- if((GPIO_num != DISABLE_GPIO_NUM) &&
- ((currdriverstate != FW_DOWNLOAD) &&
- (currdriverstate != NORMAL_OPERATION) &&
- (currdriverstate != IDLEMODE_EXIT)))
- TURN_OFF_LED(1<<GPIO_num, uiLedIndex);
- #endif
if(GPIO_num != DISABLE_GPIO_NUM)
{
@@ -752,10 +678,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
case DRIVER_INIT:
{
currdriverstate = DRIVER_INIT;//Adapter->DriverState;
- #if 0
- LedGpioInit(Adapter);
- Adapter->LEDInfo.bLedInitDone = TRUE;
- #endif
BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate);
if(GPIO_num != DISABLE_GPIO_NUM)
@@ -768,13 +690,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
{
//BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FW_DN_DONE called\n");
currdriverstate = FW_DOWNLOAD;
- #if 0
- if(Adapter->LEDInfo.bLedInitDone == FALSE)
- {
- LedGpioInit(Adapter);
- Adapter->LEDInfo.bLedInitDone = TRUE;
- }
- #endif
BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate);
if(GPIO_num != DISABLE_GPIO_NUM)
@@ -796,12 +711,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
break;
case SHUTDOWN_EXIT:
- #if 0
- if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN)
- {
- LedGpioInit(Adapter);
- }
- #endif
//no break, continue to NO_NETWORK_ENTRY state as well.
case NO_NETWORK_ENTRY:
@@ -875,34 +784,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
break;
case IDLEMODE_EXIT:
{
-#if 0
- UCHAR GPIO_num_tx = DISABLE_GPIO_NUM;
- UCHAR GPIO_num_rx = DISABLE_GPIO_NUM;
- UCHAR uiTxLedIndex = 0;
- UCHAR uiRxLedIndex = 0;
-
- currdriverstate = IDLEMODE_EXIT;
- if(DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN == Adapter->ulPowerSaveMode)
- {
- LedGpioInit(Adapter);
- }
- BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, &GPIO_num_rx, &uiTxLedIndex,&uiRxLedIndex,currdriverstate);
-
- Adapter->LEDInfo.bIdle_led_off = FALSE;
-
- if((GPIO_num_tx == DISABLE_GPIO_NUM) && (GPIO_num_rx == DISABLE_GPIO_NUM))
- {
- GPIO_num = DISABLE_GPIO_NUM ;
- }
- else
- {
- timeout = 50;
- if(Adapter->LEDInfo.bIdleMode_tx_from_host)
- LED_Blink(Adapter, 1<<GPIO_num_tx, uiTxLedIndex, timeout, -1,currdriverstate);
- else
- LED_Blink(Adapter, 1<<GPIO_num_rx, uiRxLedIndex, timeout, -1,currdriverstate);
- }
-#endif
}
break;
case DRIVER_HALT:
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index 41c9ab8a2385..c7292373a65f 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -1,6 +1,56 @@
#include "headers.h"
#define DWORD unsigned int
+
+static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset);
+static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter);
+static INT BcmGetActiveISO(PMINI_ADAPTER Adapter);
+static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
+static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
+static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize);
+
+static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
+static INT BcmGetNvmSize(PMINI_ADAPTER Adapter);
+static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
+static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
+
+static INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+
+static B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset);
+static INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section);
+static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
+
+static INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
+static INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
+static INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
+static INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
+
+static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr);
+static INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter, PUINT pBuff,
+ FLASH2X_SECTION_VAL eFlash2xSectionVal,
+ UINT uiOffset, UINT uiNumBytes);
+static FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter);
+static FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter);
+
+static INT BeceemFlashBulkRead(
+ PMINI_ADAPTER Adapter,
+ PUINT pBuffer,
+ UINT uiOffset,
+ UINT uiNumBytes);
+
+static INT BeceemFlashBulkWrite(
+ PMINI_ADAPTER Adapter,
+ PUINT pBuffer,
+ UINT uiOffset,
+ UINT uiNumBytes,
+ BOOLEAN bVerify);
+
+static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter);
+
+static INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData);
+
// Procedure: ReadEEPROMStatusRegister
//
// Description: Reads the standard EEPROM Status Register.
@@ -228,213 +278,27 @@ INT ReadBeceemEEPROM( PMINI_ADAPTER Adapter,
ReadBeceemEEPROMBulk(Adapter, uiTempOffset + MAX_RW_SIZE, (PUINT)&uiData[4], 4);
}
- OsalMemMove( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4);
+ memcpy( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4);
return STATUS_SUCCESS;
} /* ReadBeceemEEPROM() */
-#if 0
-//-----------------------------------------------------------------------------
-// Procedure: IsEEPROMWriteDone
-//
-// Description: Reads the SPI status to see the status of previous write.
-//
-// Arguments:
-// Adapter - ptr to Adapter object instance
-//
-// Returns:
-// BOOLEAN - TRUE - write went through
-// - FALSE - Write Failed.
-//-----------------------------------------------------------------------------
-
-BOOLEAN IsEEPROMWriteDone(PMINI_ADAPTER Adapter)
-{
- UINT uiRetries = 16;
- //UINT uiStatus = 0;
- UINT value;
-
- //sleep for 1.2ms ..worst case EEPROM write can take up to 1.2ms.
- mdelay(2);
-
- value = 0;
- rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
-
- while(((value >> 14) & 1) == 1)
- {
- // EEPROM_SPI_Q_STATUS1_REG will be cleared only if write back to that.
- value = (0x1 << 14);
- wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
- udelay(1000);
- uiRetries--;
- if(uiRetries == 0)
- {
- return FALSE;
- }
- value = 0;
- rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
- }
- return TRUE;
-
-
-}
-
-
-//-----------------------------------------------------------------------------
-// Procedure: ReadBeceemEEPROMBulk
-//
-// Description: This routine reads 16Byte data from EEPROM
-//
-// Arguments:
-// Adapter - ptr to Adapter object instance
-// dwAddress - EEPROM Offset to read the data from.
-// pdwData - Pointer to double word where data needs to be stored in.
-//
-// Returns:
-// OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData)
-{
- DWORD dwRetries = 16;
- DWORD dwIndex = 0;
- UINT value, tmpVal;
-
-
- value = 0;
- rdmalt (Adapter, 0x0f003008, &value, sizeof(value));
-
- //read 0x0f003020 untill bit 1 of 0x0f003008 is set.
- while(((value >> 1) & 1) == 0)
- {
-
- rdmalt (Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal));
- dwRetries--;
- if(dwRetries == 0)
- {
- return -1;
- }
- value = 0;
- rdmalt (Adapter, 0x0f003008, &value, sizeof(value));
- }
-
- value = dwAddress | 0xfb000000;
- wrmalt (Adapter, 0x0f003018, &value, sizeof(value));
-
- udelay(1000);
- value = 0;
- for(dwIndex = 0;dwIndex < 4 ; dwIndex++)
- {
- value = 0;
- rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
- pdwData[dwIndex] = value;
-
- value = 0;
- rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
- pdwData[dwIndex] |= (value << 8);
-
- value = 0;
- rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
- pdwData[dwIndex] |= (value << 16);
-
- value = 0;
- rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
- pdwData[dwIndex] |= (value << 24);
-
- }
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Procedure: ReadBeceemEEPROM
-//
-// Description: This routine reads 4Byte data from EEPROM
-//
-// Arguments:
-// Adapter - ptr to Adapter object instance
-// dwAddress - EEPROM Offset to read the data from.
-// pdwData - Pointer to double word where data needs to be stored in.
-//
-// Returns:
-// OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData)
-{
-
- DWORD dwReadValue = 0;
- DWORD dwRetries = 16, dwCompleteWord = 0;
- UINT value, tmpVal;
-
- rdmalt(Adapter, 0x0f003008, &value, sizeof(value));
- while (((value >> 1) & 1) == 0) {
- rdmalt(Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal));
-
- if (dwRetries == 0) {
- return -1;
- }
- rdmalt(Adapter, 0x0f003008, &value, sizeof(value));
- }
-
-
- //wrm (0x0f003018, 0xNbXXXXXX) // N is the number of bytes u want to read (0 means 1, f means 16, b is the opcode for page read)
- // Follow it up by N executions of rdm(0x0f003020) to read the rxed bytes from rx queue.
- dwAddress |= 0x3b000000;
- wrmalt(Adapter, 0x0f003018,&dwAddress,4);
- mdelay(10);
- rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
- dwCompleteWord=dwReadValue;
- rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
- dwCompleteWord|=(dwReadValue<<8);
- rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
- dwCompleteWord|=(dwReadValue<<16);
- rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
- dwCompleteWord|=(dwReadValue<<24);
-
- *pdwData = dwCompleteWord;
-
- return 0;
-}
-#endif
INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter)
{
- INT Status=0, i;
- unsigned char puMacAddr[6] = {0};
- INT AllZeroMac = 0;
- INT AllFFMac = 0;
+ INT Status;
+ unsigned char puMacAddr[6];
Status = BeceemNVMRead(Adapter,
(PUINT)&puMacAddr[0],
INIT_PARAMS_1_MACADDRESS_ADDRESS,
MAC_ADDRESS_SIZE);
- if(Status != STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Error in Reading the mac Addres with status :%d", Status);
- return Status;
- }
-
- memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Modem MAC Addr :");
- BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_PRINTK, 0, DBG_LVL_ALL,&Adapter->dev->dev_addr[0],MAC_ADDRESS_SIZE);
- for(i=0;i<MAC_ADDRESS_SIZE;i++)
- {
-
- if(Adapter->dev->dev_addr[i] == 0x00)
- AllZeroMac++;
- if(Adapter->dev->dev_addr[i] == 0xFF)
- AllFFMac++;
-
- }
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\n");
- if(AllZeroMac == MAC_ADDRESS_SIZE)
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all 00's");
- if(AllFFMac == MAC_ADDRESS_SIZE)
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all FF's");
+ if(Status == STATUS_SUCCESS)
+ memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
return Status;
-
}
//-----------------------------------------------------------------------------
@@ -476,7 +340,7 @@ INT BeceemEEPROMBulkRead(
ReadBeceemEEPROMBulk(Adapter,uiTempOffset,(PUINT)&uiData[0],4);
if(uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes))
{
- OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes);
+ memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes);
uiBytesRemaining -= (MAX_RW_SIZE - uiExtraBytes);
uiIndex += (MAX_RW_SIZE - uiExtraBytes);
@@ -484,7 +348,7 @@ INT BeceemEEPROMBulkRead(
}
else
{
- OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining);
+ memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining);
uiIndex += uiBytesRemaining;
uiOffset += uiBytesRemaining;
uiBytesRemaining = 0;
@@ -508,7 +372,7 @@ INT BeceemEEPROMBulkRead(
* We read 4 Dwords of data */
if(0 == ReadBeceemEEPROMBulk(Adapter,uiOffset,&uiData[0],4))
{
- OsalMemMove(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE);
+ memcpy(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE);
uiOffset += MAX_RW_SIZE;
uiBytesRemaining -= MAX_RW_SIZE;
uiIndex += MAX_RW_SIZE;
@@ -523,7 +387,7 @@ INT BeceemEEPROMBulkRead(
{
if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
{
- OsalMemMove(pcBuff+uiIndex,&uiData[0],4);
+ memcpy(pcBuff+uiIndex,&uiData[0],4);
uiOffset += 4;
uiBytesRemaining -= 4;
uiIndex +=4;
@@ -540,7 +404,7 @@ INT BeceemEEPROMBulkRead(
pCharBuff += uiIndex;
if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
{
- OsalMemMove(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested.
+ memcpy(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested.
uiBytesRemaining = 0;
}
else
@@ -571,7 +435,7 @@ INT BeceemEEPROMBulkRead(
// <FAILURE> - if failed.
//-----------------------------------------------------------------------------
-INT BeceemFlashBulkRead(
+static INT BeceemFlashBulkRead(
PMINI_ADAPTER Adapter,
PUINT pBuffer,
UINT uiOffset,
@@ -653,16 +517,8 @@ INT BeceemFlashBulkRead(
//
//-----------------------------------------------------------------------------
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
+static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
{
-#if 0
- if(Adapter->bDDRInitDone)
- {
- return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT|FLASH_SIZE_ADDR);
- }
-
- return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT|FLASH_SIZE_ADDR);
-#endif
if(IsFlash2x(Adapter))
return (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER));
else
@@ -684,7 +540,7 @@ UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
//
//-----------------------------------------------------------------------------
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
+static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
{
UINT uiData = 0;
UINT uiIndex = 0;
@@ -733,60 +589,6 @@ UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
return 0;
}
-#if 0
-/***********************************************************************************/
-//
-// WriteBeceemEEPROM: Writes 4 byte data to EEPROM offset.
-//
-// uiEEPROMOffset - Offset to be written to.
-// uiData - Data to be written.
-//
-/***********************************************************************************/
-
-INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData)
-{
- INT Status = 0;
- ULONG ulRdBk = 0;
- ULONG ulRetryCount = 3;
- UINT value;
-
- if(uiEEPROMOffset > EEPROM_END)
- {
-
- return -1;
- }
-
- uiData = htonl(uiData);
- while(ulRetryCount--)
- {
- value = 0x06000000;
- wrmalt(Adapter, 0x0F003018,&value, sizeof(value));//flush the EEPROM FIFO.
- wrmalt(Adapter, 0x0F00301C,&uiData, sizeof(uiData));
- value = 0x3A000000 | uiEEPROMOffset;
- wrmalt(Adapter, 0x0F003018,&value, sizeof(value));
- __udelay(100000);
- //read back and verify.
- Status = ReadBeceemEEPROM(Adapter,uiEEPROMOffset,(UINT *)&ulRdBk);
- if(Status == 0)
- {
- if(ulRdBk == uiData)
- {
- return Status;
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback does not match\n");
- }
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback failed\n");
- }
- }
-
- return 0;
-}
-#endif
//-----------------------------------------------------------------------------
// Procedure: FlashSectorErase
@@ -973,7 +775,7 @@ static INT flashWrite(
// need not write 0xFFFFFFFF because write requires an erase and erase will
// make whole sector 0xFFFFFFFF.
//
- if (!OsalMemCompare(pData, uiErasePattern, MAX_RW_SIZE))
+ if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE))
{
return 0;
}
@@ -1138,7 +940,7 @@ static INT flashWriteStatus(
// need not write 0xFFFFFFFF because write requires an erase and erase will
// make whole sector 0xFFFFFFFF.
//
- if (!OsalMemCompare(pData,uiErasePattern,MAX_RW_SIZE))
+ if (!memcmp(pData,uiErasePattern,MAX_RW_SIZE))
{
return 0;
}
@@ -1332,7 +1134,7 @@ static ULONG BcmFlashUnProtectBlock(PMINI_ADAPTER Adapter,UINT uiOffset, UINT ui
//
//-----------------------------------------------------------------------------
-INT BeceemFlashBulkWrite(
+static INT BeceemFlashBulkWrite(
PMINI_ADAPTER Adapter,
PUINT pBuffer,
UINT uiOffset,
@@ -1353,15 +1155,6 @@ INT BeceemFlashBulkWrite(
UINT uiTemp = 0;
UINT index = 0;
UINT uiPartOffset = 0;
- #if 0
- struct timeval tv1 = {0};
- struct timeval tv2 = {0};
-
- struct timeval tr = {0};
- struct timeval te = {0};
- struct timeval tw = {0};
- struct timeval twv = {0};
- #endif
#if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
Status = bcmflash_raw_write((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes);
@@ -1377,12 +1170,9 @@ INT BeceemFlashBulkWrite(
uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1);
uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize;
- //pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN');
- pTempBuff = OsalMemAlloc(Adapter->uiSectorSize ,"!MVN");
+ pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
if(NULL == pTempBuff)
- {
goto BeceemFlashBulkWrite_EXIT;
- }
//
// check if the data to be written is overlapped accross sectors
//
@@ -1399,7 +1189,6 @@ INT BeceemFlashBulkWrite(
uiNumSectTobeRead++;
}
}
- #if 1
//Check whether Requested sector is writable or not in case of flash2x write. But if write call is
// for DSD calibration, allow it without checking of sector permission
@@ -1420,7 +1209,6 @@ INT BeceemFlashBulkWrite(
index = index + 1 ;
}
}
- #endif
Adapter->SelectedChip = RESET_CHIP_SELECT;
while(uiNumSectTobeRead)
{
@@ -1448,13 +1236,13 @@ INT BeceemFlashBulkWrite(
if(uiNumSectTobeRead > 1)
{
- OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
+ memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
}
else
{
- OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
+ memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
}
if(IsFlash2x(Adapter))
@@ -1503,7 +1291,7 @@ INT BeceemFlashBulkWrite(
}
else
{
- if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
+ if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
{
if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex]))
{
@@ -1541,10 +1329,8 @@ BeceemFlashBulkWrite_EXIT:
{
BcmRestoreBlockProtectStatus(Adapter,ulStatus);
}
- if(pTempBuff)
- {
- OsalMemFree(pTempBuff,Adapter->uiSectorSize);
- }
+
+ kfree(pTempBuff);
Adapter->SelectedChip = RESET_CHIP_SELECT;
return Status;
@@ -1599,14 +1385,10 @@ static INT BeceemFlashBulkWriteStatus(
uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1);
uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize;
-
-
-// pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN');
- pTempBuff = OsalMemAlloc(Adapter->uiSectorSize,"!MVN");
+ pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
if(NULL == pTempBuff)
- {
goto BeceemFlashBulkWriteStatus_EXIT;
- }
+
//
// check if the data to be written is overlapped accross sectors
//
@@ -1662,13 +1444,13 @@ static INT BeceemFlashBulkWriteStatus(
if(uiNumSectTobeRead > 1)
{
- OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
+ memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
}
else
{
- OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
+ memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
}
if(IsFlash2x(Adapter))
@@ -1698,25 +1480,10 @@ static INT BeceemFlashBulkWriteStatus(
{
for(uiIndex = 0;uiIndex < Adapter->uiSectorSize;uiIndex += MAX_RW_SIZE)
{
-#if 0
- if(0 == BeceemFlashBulkRead(Adapter,uiReadBk,uiOffsetFromSectStart+uiIndex + Adapter->ulFlashCalStart ,MAX_RW_SIZE))
- {
- for(uiReadIndex = 0;uiReadIndex < 4; uiReadIndex++)
- {
- if(*((PUINT)&pTempBuff[uiIndex+uiReadIndex*4]) != uiReadBk[uiReadIndex])
- {
- Status = -1;
- goto BeceemFlashBulkWriteStatus_EXIT;
-
- }
- }
-
- }
-#endif
if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE))
{
- if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
+ if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
{
Status = STATUS_FAILURE;
goto BeceemFlashBulkWriteStatus_EXIT;
@@ -1747,10 +1514,8 @@ BeceemFlashBulkWriteStatus_EXIT:
{
BcmRestoreBlockProtectStatus(Adapter,ulStatus);
}
- if(pTempBuff)
- {
- OsalMemFree(pTempBuff,Adapter->uiSectorSize);
- }
+
+ kfree(pTempBuff);
Adapter->SelectedChip = RESET_CHIP_SELECT;
return Status;
@@ -1771,7 +1536,7 @@ BeceemFlashBulkWriteStatus_EXIT:
INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
{
- PCHAR pBuff = OsalMemAlloc(BUFFER_4K,"3MVN");
+ PCHAR pBuff = kmalloc(BUFFER_4K, GFP_KERNEL);
UINT uiEepromSize = 0;
UINT uiIndex = 0;
UINT uiBytesToCopy = 0;
@@ -1787,14 +1552,14 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
if(0 != BeceemEEPROMBulkRead(Adapter,&uiEepromSize,EEPROM_SIZE_OFFSET,4))
{
- OsalMemFree(pBuff,BUFFER_4K);
+ kfree(pBuff);
return -1;
}
uiEepromSize >>= 16;
if(uiEepromSize > 1024*1024)
{
- OsalMemFree(pBuff,BUFFER_4K);
+ kfree(pBuff);
return -1;
}
@@ -1820,7 +1585,7 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-4,&value, sizeof(value));
value = 0xbeadbead;
wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-8,&value, sizeof(value));
- OsalMemFree(pBuff,MAX_RW_SIZE);
+ kfree(pBuff);
return Status;
@@ -1873,16 +1638,13 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter)
return -1;
}
- pBuff = OsalMemAlloc(uiEepromSize, 0);
-
+ pBuff = kmalloc(uiEepromSize, GFP_KERNEL);
if ( pBuff == NULL )
- {
return -1;
- }
if(0 != BeceemNVMRead(Adapter,(PUINT)pBuff,uiCalStartAddr, uiEepromSize))
{
- OsalMemFree(pBuff, 0);
+ kfree(pBuff);
return -1;
}
@@ -1905,7 +1667,7 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter)
uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
}
- OsalMemFree(pBuff, 0);
+ kfree(pBuff);
return Status;
}
@@ -1947,14 +1709,14 @@ static INT BeceemEEPROMReadBackandVerify(
{// for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster.
BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
- if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
+ if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
{
// re-write
BeceemEEPROMBulkWrite(Adapter,(PUCHAR)(pBuffer+uiIndex),uiOffset,MAX_RW_SIZE,FALSE);
mdelay(3);
BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
- if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
+ if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
{
return -1;
}
@@ -1986,7 +1748,7 @@ static INT BeceemEEPROMReadBackandVerify(
else
{ // Handle the reads less than 4 bytes...
uiData = 0;
- OsalMemMove(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes);
+ memcpy(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes);
BeceemEEPROMBulkRead(Adapter,&uiRdbk,uiOffset,4);
if(memcmp(&uiData, &uiRdbk, uiNumBytes))
@@ -2186,7 +1948,7 @@ INT BeceemEEPROMBulkWrite(
if(uiBytesToCopy >= (16 -uiExtraBytes))
{
- OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes);
+ memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes);
if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
return STATUS_FAILURE;
@@ -2197,7 +1959,7 @@ INT BeceemEEPROMBulkWrite(
}
else
{
- OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy);
+ memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy);
if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
return STATUS_FAILURE;
@@ -2233,7 +1995,7 @@ INT BeceemEEPROMBulkWrite(
// To program non 16byte aligned data, read 16byte and then update.
//
BeceemEEPROMBulkRead(Adapter,&uiData[0],uiOffset,16);
- OsalMemMove(&uiData[0],pBuffer+uiIndex,uiBytesToCopy);
+ memcpy(&uiData[0],pBuffer+uiIndex,uiBytesToCopy);
if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiOffset ) )
@@ -2535,7 +2297,7 @@ INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize)
//
//-----------------------------------------------------------------------------
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize)
+static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize)
{
UINT uiSectorSize = 0;
UINT uiSectorSig = 0;
@@ -2642,20 +2404,8 @@ static INT BcmInitEEPROMQueues(PMINI_ADAPTER Adapter)
INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
{
-#ifdef BCM_SHM_INTERFACE
-#ifdef FLASH_DIRECT_ACCESS
- unsigned int data,data1,data2 = 1;
- wrm(ps_adapter, PAD_SELECT_REGISTER, &data2, 4);
- data1 = rdm(ps_adapter,SYS_CFG,&data,4);
- data1 = rdm(ps_adapter,SYS_CFG,&data,4);
- data2 = (data | 0x80 | 0x8000);
- wrm(ps_adapter,SYS_CFG, &data2,4); // over-write as Flash boot mode
-#endif
- ps_adapter->eNVMType = NVM_FLASH;
-#else
BcmValidateNvmType(ps_adapter);
BcmInitEEPROMQueues(ps_adapter);
-#endif
if(ps_adapter->eNVMType == NVM_AUTODETECT)
{
@@ -2684,7 +2434,7 @@ INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
*/
/***************************************************************************/
-INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
+static INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
{
if(Adapter->eNVMType == NVM_EEPROM)
{
@@ -2708,7 +2458,7 @@ INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
// Returns:
// <VOID>
//-----------------------------------------------------------------------------
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter)
+static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter)
{
//
@@ -2775,7 +2525,7 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
if(psAdapter->psFlash2xCSInfo == NULL)
{
BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate memory for Flash 2.x");
- bcm_kfree(psAdapter->psFlashCSInfo);
+ kfree(psAdapter->psFlashCSInfo);
return -ENOMEM;
}
@@ -2783,8 +2533,8 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
if(psAdapter->psFlash2xVendorInfo == NULL)
{
BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate Vendor Info Memory for Flash 2.x");
- bcm_kfree(psAdapter->psFlashCSInfo);
- bcm_kfree(psAdapter->psFlash2xCSInfo);
+ kfree(psAdapter->psFlashCSInfo);
+ kfree(psAdapter->psFlash2xCSInfo);
return -ENOMEM;
}
@@ -2798,9 +2548,9 @@ INT BcmDeAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0," Adapter structure point is NULL");
return -EINVAL;
}
- bcm_kfree(psAdapter->psFlashCSInfo);
- bcm_kfree(psAdapter->psFlash2xCSInfo);
- bcm_kfree(psAdapter->psFlash2xVendorInfo);
+ kfree(psAdapter->psFlashCSInfo);
+ kfree(psAdapter->psFlash2xCSInfo);
+ kfree(psAdapter->psFlash2xVendorInfo);
return STATUS_SUCCESS ;
}
@@ -2954,7 +2704,7 @@ static INT ConvertEndianOfCSStructure(PFLASH_CS_INFO psFlashCSInfo)
return STATUS_SUCCESS;
}
-INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
+static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
{
return ( Adapter->uiVendorExtnFlag &&
(Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) &&
@@ -3052,7 +2802,7 @@ static VOID UpdateVendorInfo(PMINI_ADAPTER Adapter)
// <VOID>
//-----------------------------------------------------------------------------
-INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
+static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
{
//FLASH_CS_INFO sFlashCsInfo = {0};
@@ -3070,7 +2820,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
memset(Adapter->psFlashCSInfo, 0 ,sizeof(FLASH_CS_INFO));
memset(Adapter->psFlash2xCSInfo, 0 ,sizeof(FLASH2X_CS_INFO));
-#ifndef BCM_SHM_INTERFACE
if(!Adapter->bDDRInitDone)
{
{
@@ -3079,7 +2828,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
}
}
-#endif
// Reading first 8 Bytes to get the Flash Layout
// MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes)
@@ -3147,9 +2895,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
return STATUS_FAILURE;
}
ConvertEndianOf2XCSStructure(Adapter->psFlash2xCSInfo);
-#ifndef BCM_SHM_INTERFACE
BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo,Adapter);
-#endif
if((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) &&
(SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) &&
(FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) &&
@@ -3181,21 +2927,10 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
Concerns: what if CS sector size does not match with this sector size ???
what is the indication of AccessBitMap in CS in flash 2.x ????
*/
-#ifndef BCM_SHM_INTERFACE
Adapter->ulFlashID = BcmReadFlashRDID(Adapter);
-#endif
Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion;
- #if 0
- if(FLASH_PART_SST25VF080B == Adapter->ulFlashID)
- {
- //
- // 1MB flash has been selected. we have to use 64K as sector size no matter what is kept in FLASH_CS.
- //
- Adapter->uiSectorSize = 0x10000;
- }
- #endif
return STATUS_SUCCESS ;
}
@@ -3214,7 +2949,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
//
//-----------------------------------------------------------------------------
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter)
+static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter)
{
UINT uiData = 0;
@@ -3569,39 +3304,6 @@ INT BcmFlash2xBulkWrite(
}
/**
-* ReadDSDHeader : Read the DSD map for the DSD Section val provided in Argument.
-* @Adapter : Beceem Private Data Structure
-* @psDSDHeader :Pointer of the buffer where header has to be read
-* @dsd :value of the Dyanmic DSD like DSD0 of DSD1 or DSD2
-*
-* Return Value:-
-* if suceeds return STATUS_SUCCESS or negative error code.
-**/
-INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTION_VAL dsd)
-{
- INT Status = STATUS_SUCCESS;
-
- Status =BcmFlash2xBulkRead(Adapter,
- (PUINT)psDSDHeader,
- dsd,
- Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader,
- sizeof(DSD_HEADER));
- if(Status == STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageMagicNumber :0X%x", ntohl(psDSDHeader->DSDImageMagicNumber));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageSize :0X%x ",ntohl(psDSDHeader->DSDImageSize));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageCRC :0X%x",ntohl(psDSDHeader->DSDImageCRC));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImagePriority :0X%x",ntohl(psDSDHeader->DSDImagePriority));
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"DSD Header read is failed with status :%d", Status);
- }
-
- return Status;
-}
-
-/**
* BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR
* @Adapter :-Drivers private Data Structure
*
@@ -3609,7 +3311,7 @@ INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTIO
* Return STATUS_SUCESS if get sucess in setting the right DSD else negaive error code
*
**/
-INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
+static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
{
FLASH2X_SECTION_VAL uiHighestPriDSD = 0 ;
@@ -3647,39 +3349,6 @@ INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
return STATUS_SUCCESS;
}
-/**
-* ReadISOUnReservedBytes : Read the ISO map for the ISO Section val provided in Argument.
-* @Adapter : Driver Private Data Structure
-* @psISOHeader :Pointer of the location where header has to be read
-* @IsoImage :value of the Dyanmic ISO like ISO_IMAGE1 of ISO_IMAGE2
-*
-* Return Value:-
-* if suceeds return STATUS_SUCCESS or negative error code.
-**/
-
-INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTION_VAL IsoImage)
-{
- INT Status = STATUS_SUCCESS;
-
- Status = BcmFlash2xBulkRead(Adapter,
- (PUINT)psISOHeader,
- IsoImage,
- 0,
- sizeof(ISO_HEADER));
-
- if(Status == STATUS_SUCCESS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageMagicNumber :0X%x", ntohl(psISOHeader->ISOImageMagicNumber));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageSize :0X%x ",ntohl(psISOHeader->ISOImageSize));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageCRC :0X%x",ntohl(psISOHeader->ISOImageCRC));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImagePriority :0X%x",ntohl(psISOHeader->ISOImagePriority));
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "ISO Header Read failed");
- }
- return Status;
-}
/**
* BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue
@@ -3691,7 +3360,7 @@ INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTIO
*
**/
-INT BcmGetActiveISO(PMINI_ADAPTER Adapter)
+static INT BcmGetActiveISO(PMINI_ADAPTER Adapter)
{
INT HighestPriISO = 0 ;
@@ -4588,7 +4257,7 @@ INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut)
}
- bcm_kfree(Buff);
+ kfree(Buff);
return Status;
}
@@ -4789,7 +4458,7 @@ Return Value:-
Success :- Base Address of the Flash
**/
-INT GetFlashBaseAddr(PMINI_ADAPTER Adapter)
+static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter)
{
UINT uiBaseAddr = 0;
@@ -4866,20 +4535,6 @@ INT BcmCopySection(PMINI_ADAPTER Adapter,
return -EINVAL;
}
- #if 0
- else
- {
- if((SrcSection == VSA0) || (SrcSection == VSA1) || (SrcSection == VSA2))
- {
- if((DstSection != VSA0) && (DstSection != VSA1) && (DstSection != VSA2))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Source and Destion secton is not of same type");
- return -EINVAL;
- }
- }
-
- }
- #endif
//if offset zero means have to copy complete secton
if(numOfBytes == 0)
@@ -4954,7 +4609,7 @@ INT BcmCopySection(PMINI_ADAPTER Adapter,
BytesToBeCopied = numOfBytes;
}
}while(numOfBytes > 0) ;
- bcm_kfree(pBuff);
+ kfree(pBuff);
Adapter->bHeaderChangeAllowed = FALSE ;
return Status;
}
@@ -4979,14 +4634,6 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
UINT uiSectAlignAddr = 0;
UINT sig = 0;
- #if 0
- //if Chenges in Header is allowed, Return back
- if(Adapter->bHeaderChangeAllowed == TRUE)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Header Change is allowed");
- return STATUS_SUCCESS ;
- }
- #endif
//making the offset sector alligned
uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1);
@@ -5024,7 +4671,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
//Replace Buffer content with Header
memcpy(pBuff +offsetToProtect,pTempBuff,HeaderSizeToProtect);
- bcm_kfree(pTempBuff);
+ kfree(pTempBuff);
}
if(bHasHeader && Adapter->bSigCorrupted)
{
@@ -5044,29 +4691,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
return STATUS_SUCCESS ;
}
-INT BcmMakeFlashCSActive(PMINI_ADAPTER Adapter, UINT offset)
-{
- UINT GPIOConfig = 0 ;
-
-
- if(Adapter->bFlashRawRead == FALSE)
- {
- //Applicable for Flash2.x
- if(IsFlash2x(Adapter) == FALSE)
- return STATUS_SUCCESS;
- }
- if(offset/FLASH_PART_SIZE)
- {
- //bit[14..12] -> will select make Active CS1, CS2 or CS3
- // Select CS1, CS2 and CS3 (CS0 is dedicated pin)
- rdmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
- GPIOConfig |= (7 << 12);
- wrmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
- }
-
- return STATUS_SUCCESS ;
-}
/**
BcmDoChipSelect : This will selcet the appropriate chip for writing.
@Adapater :- Bcm Driver Private Data Structure
@@ -5074,7 +4699,7 @@ BcmDoChipSelect : This will selcet the appropriate chip for writing.
OutPut:-
Select the Appropriate chip and retrn status Sucess
**/
-INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
+static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
{
UINT FlashConfig = 0;
INT ChipNum = 0;
@@ -5365,39 +4990,6 @@ INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter,
return Status;
}
-#if 0
-UINT getNumOfSubSectionWithWRPermisson(PMINI_ADAPTER Adapter, SECTION_TYPE secType)
-{
-
- UINT numOfWRSubSec = 0;
- switch(secType)
- {
- case ISO :
- if(IsSectionWritable(Adapter,ISO_IMAGE1))
- numOfWRSubSec = numOfWRSubSec + 1;
- if(IsSectionWritable(Adapter,ISO_IMAGE2))
- numOfWRSubSec = numOfWRSubSec + 1;
- break;
-
- case DSD :
- if(IsSectionWritable(Adapter,DSD2))
- numOfWRSubSec = numOfWRSubSec + 1;
- if(IsSectionWritable(Adapter,DSD1))
- numOfWRSubSec = numOfWRSubSec + 1;
- if(IsSectionWritable(Adapter,DSD0))
- numOfWRSubSec = numOfWRSubSec + 1;
- break ;
-
- case VSA :
- //for VSA Add code Here
- default :
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Invalid secton<%d> is passed", secType);\
- numOfWRSubSec = 0;
-
- }
- return numOfWRSubSec;
-}
-#endif
BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
{
@@ -5479,7 +5071,7 @@ INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section)
return Status ;
}
-INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
{
PUCHAR pBuff = NULL;
@@ -5543,16 +5135,16 @@ INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
else
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
- bcm_kfree(pBuff);
+ kfree(pBuff);
return STATUS_FAILURE;
}
- bcm_kfree(pBuff);
+ kfree(pBuff);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
return STATUS_SUCCESS ;
}
-INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
{
PUCHAR pBuff = NULL;
@@ -5593,14 +5185,14 @@ INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
else
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
- bcm_kfree(pBuff);
+ kfree(pBuff);
return STATUS_FAILURE;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pBuff,MAX_RW_SIZE);
- bcm_kfree(pBuff);
+ kfree(pBuff);
return STATUS_SUCCESS ;
}
diff --git a/drivers/staging/bcm/nvm.h b/drivers/staging/bcm/nvm.h
index 6ec6ca85b501..651b5a455b32 100644
--- a/drivers/staging/bcm/nvm.h
+++ b/drivers/staging/bcm/nvm.h
@@ -323,15 +323,6 @@ typedef struct _ISO_HEADER
-#ifdef BCM_SHM_INTERFACE
-
-#define FLASH_ADDR_MASK 0x1F000000
-extern int bcmflash_raw_read(unsigned int flash_id, unsigned int offset, unsigned char *inbuf, unsigned int len);
-extern int bcmflash_raw_write(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len);
-extern int bcmflash_raw_writenoerase(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len);
-
-
-#endif
#define FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT 0x1C000000
#define FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT 0x1F000000
@@ -414,76 +405,5 @@ extern int bcmflash_raw_writenoerase(unsigned int flash_id, unsigned int offset,
#define FIELD_OFFSET_IN_HEADER(HeaderPointer,Field) ((PUCHAR)&((HeaderPointer)(NULL))->Field - (PUCHAR)(NULL))
-#if 0
-INT BeceemEEPROMBulkRead(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes);
-
-
-INT BeceemFlashBulkRead(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes);
-
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter);
-
-
-
-INT BeceemFlashBulkWrite(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes,
- BOOLEAN bVerify);
-
-INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter);
-
-INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter);
-
-
-INT BeceemEEPROMBulkWrite(
- PMINI_ADAPTER Adapter,
- PUCHAR pBuffer,
- UINT uiOffset,
- UINT uiNumBytes,
- BOOLEAN bVerify);
-
-
-INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData);
-
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
-
-INT BeceemNVMRead(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes);
-
-INT BeceemNVMWrite(
- PMINI_ADAPTER Adapter,
- PUINT pBuffer,
- UINT uiOffset,
- UINT uiNumBytes,
- BOOLEAN bVerify);
-
-INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter);
-
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
-
-INT BcmInitNVM(PMINI_ADAPTER Adapter);
-
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
-
-VOID BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
-
-#endif
-
#endif
diff --git a/drivers/staging/bcm/osal_misc.h b/drivers/staging/bcm/osal_misc.h
deleted file mode 100644
index ff4adde17cd8..000000000000
--- a/drivers/staging/bcm/osal_misc.h
+++ /dev/null
@@ -1,49 +0,0 @@
- /*++
-
- Copyright (c) Beceem Communications Inc.
-
- Module Name:
- OSAL_Misc.h
-
- Abstract:
- Provides the OS Abstracted macros to access:
- Linked Lists
- Dispatcher Objects(Events,Semaphores,Spin Locks and the like)
- Files
-
-
- Revision History:
- Who When What
- -------- -------- ----------------------------------------------
- Name Date Created/reviewed/modified
- Rajeev 24/1/08 Created
- Notes:
-
- --*/
-#ifndef _OSAL_MISC_H_
-#define _OSAL_MISC_H_
-//OSAL Macros
-//OSAL Primitives
-typedef PUCHAR POSAL_NW_PACKET ; //Nw packets
-
-
-#define OsalMemAlloc(n,t) kmalloc(n,GFP_KERNEL)
-
-#define OsalMemFree(x,n) bcm_kfree(x)
-
-#define OsalMemMove(dest, src, len) \
-{ \
- memcpy(dest,src, len); \
-}
-
-#define OsalZeroMemory(pDest, Len) \
-{ \
- memset(pDest,0,Len); \
-}
-
-//#define OsalMemSet(pSrc,Char,Len) memset(pSrc,Char,Len)
-
-bool OsalMemCompare(void *dest, void *src, UINT len);
-
-#endif
-
diff --git a/drivers/staging/brcm80211/README b/drivers/staging/brcm80211/README
index c3ba9bb9b116..99e67669f26b 100644
--- a/drivers/staging/brcm80211/README
+++ b/drivers/staging/brcm80211/README
@@ -43,14 +43,8 @@ Firmware is available from the Linux firmware repository at:
http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
-For all chips, copy brcm/bcm43xx-0-610-809-0.fw and
-brcm/bcm43xx_hdr-0-610-809-0.fw to /lib/firmware/brcm (or wherever firmware is
-normally installed on the system). In the /lib/firmware/brcm directory, then
-create the following symlinks:
-
- ln -s bcm43xx-0-610-809-0.fw bcm43xx-0.fw
- ln -s bcm43xx_hdr-0-610-809-0.fw bcm43xx_hdr-0.fw
-
+For all chips, copy brcm/bcm43xx-0.fw and brcm/bcm43xx_hdr-0.fw to
+/lib/firmware/brcm (or wherever firmware is normally installed on your system).
Currently supported chips
==============
@@ -88,7 +82,9 @@ with the driver.
Contact Info:
=============
-Brett Rudley brudley@broadcom.com
-Henry Ptasinski henryp@broadcom.com
-Nohee Ko noheek@broadcom.com
+Brett Rudley brudley@broadcom.com
+Henry Ptasinski henryp@broadcom.com
+Dowan Kim dowan@broadcom.com
+Roland Vossen rvossen@broadcom.com
+Arend van Spriel arend@broadcom.com
diff --git a/drivers/staging/brcm80211/TODO b/drivers/staging/brcm80211/TODO
index 8803d300b531..24ebadbe4241 100644
--- a/drivers/staging/brcm80211/TODO
+++ b/drivers/staging/brcm80211/TODO
@@ -45,5 +45,7 @@ Contact
=====
Brett Rudley <brudley@broadcom.com>
Henry Ptasinski <henryp@broadcom.com>
-Nohee Ko <noheek@broadcom.com>
+Dowan Kim <dowan@broadcom.com>
+Roland Vossen <rvossen@broadcom.com>
+Arend van Spriel <arend@broadcom.com>
diff --git a/drivers/staging/brcm80211/brcmfmac/README b/drivers/staging/brcm80211/brcmfmac/README
index 43601fa8b17e..be29e4236920 100644
--- a/drivers/staging/brcm80211/brcmfmac/README
+++ b/drivers/staging/brcm80211/brcmfmac/README
@@ -25,8 +25,9 @@ Firmware is available from the Linux firmware repository at:
http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
-For 4329 chip, copy brcm/bcm4329-fullmac-4-218-248-5.bin and
-bcm4329-fullmac-4-218-248-5.txt to /lib/firmware/brcm
+For 4329 chip, copy brcm/bcm4329-fullmac-4.bin and brcm/bcm4329-fullmac-4.txt
+to /lib/firmware/brcm (or wherever firmware is normally installed on your
+system).
Contact Info:
=============
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
index 4c613da3553a..acf43a365081 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
@@ -16,13 +16,14 @@
/* ****************** BCMSDH Interface Functions *************************** */
#include <linux/types.h>
+#include <linux/netdevice.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#include <bcmendian.h>
+#include <osl.h>
#include <bcmutils.h>
#include <hndsoc.h>
#include <siutils.h>
-#include <osl.h>
#include <bcmsdh.h> /* BRCM API for SDIO
clients (such as wl, dhd) */
@@ -38,7 +39,7 @@ struct bcmsdh_info {
bool init_success; /* underlying driver successfully attached */
void *sdioh; /* handler for sdioh */
u32 vendevid; /* Target Vendor and Device ID on SD bus */
- osl_t *osh;
+ struct osl_info *osh;
bool regfail; /* Save status of last
reg_read/reg_write call */
u32 sbwad; /* Save backplane window address */
@@ -55,7 +56,8 @@ void bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
}
#endif
-bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
+bcmsdh_info_t *bcmsdh_attach(struct osl_info *osh, void *cfghdl,
+ void **regsva, uint irq)
{
bcmsdh_info_t *bcmsdh;
@@ -84,7 +86,7 @@ bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
return bcmsdh;
}
-int bcmsdh_detach(osl_t *osh, void *sdh)
+int bcmsdh_detach(struct osl_info *osh, void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
@@ -451,7 +453,7 @@ bool bcmsdh_regfail(void *sdh)
int
bcmsdh_recv_buf(void *sdh, u32 addr, uint fn, uint flags,
- u8 *buf, uint nbytes, void *pkt,
+ u8 *buf, uint nbytes, struct sk_buff *pkt,
bcmsdh_cmplt_fn_t complete, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
index 9028cd01d9d0..d24b5e7d753c 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
@@ -20,8 +20,7 @@
#define __UNDEF_NO_VERSION__
-#include <linuxver.h>
-
+#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/completion.h>
@@ -57,7 +56,7 @@ struct bcmsdh_hc {
#else
struct pci_dev *dev; /* pci device handle */
#endif /* BCMPLATFORM_BUS */
- osl_t *osh;
+ struct osl_info *osh;
void *regs; /* SDIO Host Controller address */
bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
void *ch;
@@ -139,22 +138,11 @@ static int __devexit bcmsdh_remove(struct device *dev);
#endif /* BCMLXSDMMC */
#ifndef BCMLXSDMMC
-static struct device_driver bcmsdh_driver = {
- .name = "pxa2xx-mci",
- .bus = &platform_bus_type,
- .probe = bcmsdh_probe,
- .remove = bcmsdh_remove,
- .suspend = NULL,
- .resume = NULL,
-};
-#endif /* BCMLXSDMMC */
-
-#ifndef BCMLXSDMMC
static
#endif /* BCMLXSDMMC */
int bcmsdh_probe(struct device *dev)
{
- osl_t *osh = NULL;
+ struct osl_info *osh = NULL;
bcmsdh_hc_t *sdhc = NULL;
unsigned long regs = 0;
bcmsdh_info_t *sdh = NULL;
@@ -189,7 +177,7 @@ int bcmsdh_probe(struct device *dev)
}
#endif /* defined(OOB_INTR_ONLY) */
/* allocate SDIO Host Controller state info */
- osh = osl_attach(dev, PCI_BUS, false);
+ osh = osl_attach(dev, PCI_BUS);
if (!osh) {
SDLX_MSG(("%s: osl_attach failed\n", __func__));
goto err;
@@ -258,7 +246,7 @@ static
int bcmsdh_remove(struct device *dev)
{
bcmsdh_hc_t *sdhc, *prev;
- osl_t *osh;
+ struct osl_info *osh;
sdhc = sdhcinfo;
drvinfo.detach(sdhc->ch);
@@ -291,269 +279,23 @@ int bcmsdh_remove(struct device *dev)
return 0;
}
-
-#else /* BCMPLATFORM_BUS */
-
-#if !defined(BCMLXSDMMC)
-/* forward declarations for PCI probe and remove functions. */
-static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
-
-/**
- * pci id table
- */
-static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
-{
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- .driver_data = 0,
-},
-{0,}
-};
-
-MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
-
-/**
- * SDIO Host Controller pci driver info
- */
-static struct pci_driver bcmsdh_pci_driver = {
- .node = {},
- .name = "bcmsdh",
- .id_table = bcmsdh_pci_devid,
- .probe = bcmsdh_pci_probe,
- .remove = bcmsdh_pci_remove,
- .suspend = NULL,
- .resume = NULL,
-};
-
-extern uint sd_pci_slot; /* Force detection to a particular PCI */
- /* slot only . Allows for having multiple */
- /* WL devices at once in a PC */
- /* Only one instance of dhd will be */
- /* usable at a time */
- /* Upper word is bus number, */
- /* lower word is slot number */
- /* Default value of 0xFFFFffff turns this */
- /* off */
-module_param(sd_pci_slot, uint, 0);
-
-/**
- * Detect supported SDIO Host Controller and attach if found.
- *
- * Determine if the device described by pdev is a supported SDIO Host
- * Controller. If so, attach to it and attach to the target device.
- */
-static int __devinit
-bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- osl_t *osh = NULL;
- bcmsdh_hc_t *sdhc = NULL;
- unsigned long regs;
- bcmsdh_info_t *sdh = NULL;
- int rc;
-
- if (sd_pci_slot != 0xFFFFffff) {
- if (pdev->bus->number != (sd_pci_slot >> 16) ||
- PCI_SLOT(pdev->devfn) != (sd_pci_slot & 0xffff)) {
- SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
- __func__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
- "Found compatible SDIOHC" :
- "Probing unknown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- pdev->vendor, pdev->device));
- return -ENODEV;
- }
- SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X "
- "(good PCI location)\n", __func__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
- "Using compatible SDIOHC" : "WARNING, forced use "
- "of unkown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
- pdev->device));
- }
-
- if ((pdev->vendor == VENDOR_TI)
- && ((pdev->device == PCIXX21_FLASHMEDIA_ID)
- || (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
- u32 config_reg;
-
- SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n",
- __func__));
- osh = osl_attach(pdev, PCI_BUS, false);
- if (!osh) {
- SDLX_MSG(("%s: osl_attach failed\n", __func__));
- goto err;
- }
-
- config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
-
- /*
- * Set MMC_SD_DIS bit in FlashMedia Controller.
- * Disbling the SD/MMC Controller in the FlashMedia Controller
- * allows the Standard SD Host Controller to take over control
- * of the SD Slot.
- */
- config_reg |= 0x02;
- OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
- osl_detach(osh);
- }
- /* match this pci device with what we support */
- /* we can't solely rely on this to believe it is
- our SDIO Host Controller! */
- if (!bcmsdh_chipmatch(pdev->vendor, pdev->device))
- return -ENODEV;
-
- /* this is a pci device we might support */
- SDLX_MSG(("%s: Found possible SDIO Host Controller: "
- "bus %d slot %d func %d irq %d\n", __func__,
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), pdev->irq));
-
- /* use bcmsdh_query_device() to get the vendor ID of the target device
- * so it will eventually appear in the Broadcom string on the console
- */
-
- /* allocate SDIO Host Controller state info */
- osh = osl_attach(pdev, PCI_BUS, false);
- if (!osh) {
- SDLX_MSG(("%s: osl_attach failed\n", __func__));
- goto err;
- }
- sdhc = kzalloc(sizeof(bcmsdh_hc_t), GFP_ATOMIC);
- if (!sdhc) {
- SDLX_MSG(("%s: out of memory\n", __func__));
- goto err;
- }
- sdhc->osh = osh;
-
- sdhc->dev = pdev;
-
- /* map to address where host can access */
- pci_set_master(pdev);
- rc = pci_enable_device(pdev);
- if (rc) {
- SDLX_MSG(("%s: Cannot enable PCI device\n", __func__));
- goto err;
- }
- sdh = bcmsdh_attach(osh, (void *)(unsigned long)pci_resource_start(pdev, 0),
- (void **)&regs, pdev->irq);
- if (!sdh) {
- SDLX_MSG(("%s: bcmsdh_attach failed\n", __func__));
- goto err;
- }
-
- sdhc->sdh = sdh;
-
- /* try to attach to the target device */
- sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
- bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
- (void *)regs, NULL, sdh);
- if (!sdhc->ch) {
- SDLX_MSG(("%s: device attach failed\n", __func__));
- goto err;
- }
-
- /* chain SDIO Host Controller info together */
- sdhc->next = sdhcinfo;
- sdhcinfo = sdhc;
-
- return 0;
-
- /* error handling */
-err:
- if (sdhc->sdh)
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
- if (sdhc)
- kfree(sdhc);
- if (osh)
- osl_detach(osh);
- return -ENODEV;
-}
-
-/**
- * Detach from target devices and SDIO Host Controller
- */
-static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev)
-{
- bcmsdh_hc_t *sdhc, *prev;
- osl_t *osh;
-
- /* find the SDIO Host Controller state for this
- pdev and take it out from the list */
- for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
- if (sdhc->dev == pdev) {
- if (prev)
- prev->next = sdhc->next;
- else
- sdhcinfo = NULL;
- break;
- }
- prev = sdhc;
- }
- if (!sdhc)
- return;
-
- drvinfo.detach(sdhc->ch);
-
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
-
- /* release SDIO Host Controller info */
- osh = sdhc->osh;
- kfree(sdhc);
- osl_detach(osh);
-}
-#endif /* BCMLXSDMMC */
#endif /* BCMPLATFORM_BUS */
extern int sdio_function_init(void);
int bcmsdh_register(bcmsdh_driver_t *driver)
{
- int error = 0;
-
drvinfo = *driver;
-#if defined(BCMPLATFORM_BUS)
-#if defined(BCMLXSDMMC)
SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
- error = sdio_function_init();
-#else
- SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
- error = driver_register(&bcmsdh_driver);
-#endif /* defined(BCMLXSDMMC) */
- return error;
-#endif /* defined(BCMPLATFORM_BUS) */
-
-#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- error = pci_register_driver(&bcmsdh_pci_driver);
- if (!error)
- return 0;
-
- SDLX_MSG(("%s: pci_register_driver failed 0x%x\n", __func__, error));
-#endif /* BCMPLATFORM_BUS */
-
- return error;
+ return sdio_function_init();
}
extern void sdio_function_cleanup(void);
void bcmsdh_unregister(void)
{
-#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- driver_unregister(&bcmsdh_driver);
-#endif
-#if defined(BCMLXSDMMC)
sdio_function_cleanup();
-#endif /* BCMLXSDMMC */
-#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- pci_unregister_driver(&bcmsdh_pci_driver);
-#endif /* BCMPLATFORM_BUS */
}
#if defined(OOB_INTR_ONLY)
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index f6c9c4541813..d399b5c76f94 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -14,11 +14,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
+#include <linux/netdevice.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#include <bcmendian.h>
-#include <bcmutils.h>
#include <osl.h>
+#include <bcmutils.h>
#include <sdio.h> /* SDIO Device and Protocol Specs */
#include <sdioh.h> /* SDIO Host Controller Specification */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
@@ -111,7 +112,7 @@ static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
/*
* Public entry points & extern's
*/
-extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq)
+extern sdioh_info_t *sdioh_attach(struct osl_info *osh, void *bar0, uint irq)
{
sdioh_info_t *sd;
int err_ret;
@@ -174,7 +175,7 @@ extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq)
return sd;
}
-extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd)
+extern SDIOH_API_RC sdioh_detach(struct osl_info *osh, sdioh_info_t *sd)
{
sd_trace(("%s\n", __func__));
@@ -750,7 +751,7 @@ sdioh_cis_read(sdioh_info_t *sd, uint func, u8 *cisd, u32 length)
sd_trace(("%s: Func = %d\n", __func__, func));
if (!sd->func_cis_ptr[func]) {
- bzero(cis, length);
+ memset(cis, 0, length);
sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func));
return SDIOH_API_RC_FAIL;
}
@@ -927,13 +928,13 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func,
static SDIOH_API_RC
sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
- uint addr, void *pkt)
+ uint addr, struct sk_buff *pkt)
{
bool fifo = (fix_inc == SDIOH_DATA_FIX);
u32 SGCount = 0;
int err_ret = 0;
- void *pnext;
+ struct sk_buff *pnext;
sd_trace(("%s: Enter\n", __func__));
@@ -943,8 +944,8 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
/* Claim host controller */
sdio_claim_host(gInstance->func[func]);
- for (pnext = pkt; pnext; pnext = PKTNEXT(pnext)) {
- uint pkt_len = PKTLEN(pnext);
+ for (pnext = pkt; pnext; pnext = pnext->next) {
+ uint pkt_len = pnext->len;
pkt_len += 3;
pkt_len &= 0xFFFFFFFC;
@@ -961,23 +962,23 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
* is supposed to give
* us something we can work with.
*/
- ASSERT(((u32) (PKTDATA(pkt)) & DMA_ALIGN_MASK) == 0);
+ ASSERT(((u32) (pkt->data) & DMA_ALIGN_MASK) == 0);
if ((write) && (!fifo)) {
err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((u8 *) PKTDATA(pnext)),
+ ((u8 *) (pnext->data)),
pkt_len);
} else if (write) {
err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((u8 *) PKTDATA(pnext)),
+ ((u8 *) (pnext->data)),
pkt_len);
} else if (fifo) {
err_ret = sdio_readsb(gInstance->func[func],
- ((u8 *) PKTDATA(pnext)),
+ ((u8 *) (pnext->data)),
addr, pkt_len);
} else {
err_ret = sdio_memcpy_fromio(gInstance->func[func],
- ((u8 *) PKTDATA(pnext)),
+ ((u8 *) (pnext->data)),
addr, pkt_len);
}
@@ -1025,10 +1026,10 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
extern SDIOH_API_RC
sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write,
uint func, uint addr, uint reg_width, uint buflen_u,
- u8 *buffer, void *pkt)
+ u8 *buffer, struct sk_buff *pkt)
{
SDIOH_API_RC Status;
- void *mypkt = NULL;
+ struct sk_buff *mypkt = NULL;
sd_trace(("%s: Enter\n", __func__));
@@ -1038,52 +1039,52 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write,
if (pkt == NULL) {
sd_data(("%s: Creating new %s Packet, len=%d\n",
__func__, write ? "TX" : "RX", buflen_u));
- mypkt = PKTGET(sd->osh, buflen_u, write ? true : false);
+ mypkt = pkt_buf_get_skb(sd->osh, buflen_u);
if (!mypkt) {
- sd_err(("%s: PKTGET failed: len %d\n",
+ sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
__func__, buflen_u));
return SDIOH_API_RC_FAIL;
}
/* For a write, copy the buffer data into the packet. */
if (write)
- bcopy(buffer, PKTDATA(mypkt), buflen_u);
+ bcopy(buffer, mypkt->data, buflen_u);
Status =
sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!write)
- bcopy(PKTDATA(mypkt), buffer, buflen_u);
+ bcopy(mypkt->data, buffer, buflen_u);
- PKTFREE(sd->osh, mypkt, write ? true : false);
- } else if (((u32) (PKTDATA(pkt)) & DMA_ALIGN_MASK) != 0) {
+ pkt_buf_free_skb(sd->osh, mypkt, write ? true : false);
+ } else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) {
/* Case 2: We have a packet, but it is unaligned. */
/* In this case, we cannot have a chain. */
- ASSERT(PKTNEXT(pkt) == NULL);
+ ASSERT(pkt->next == NULL);
sd_data(("%s: Creating aligned %s Packet, len=%d\n",
- __func__, write ? "TX" : "RX", PKTLEN(pkt)));
- mypkt = PKTGET(sd->osh, PKTLEN(pkt), write ? true : false);
+ __func__, write ? "TX" : "RX", pkt->len));
+ mypkt = pkt_buf_get_skb(sd->osh, pkt->len);
if (!mypkt) {
- sd_err(("%s: PKTGET failed: len %d\n",
- __func__, PKTLEN(pkt)));
+ sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
+ __func__, pkt->len));
return SDIOH_API_RC_FAIL;
}
/* For a write, copy the buffer data into the packet. */
if (write)
- bcopy(PKTDATA(pkt), PKTDATA(mypkt), PKTLEN(pkt));
+ bcopy(pkt->data, mypkt->data, pkt->len);
Status =
sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!write)
- bcopy(PKTDATA(mypkt), PKTDATA(pkt), PKTLEN(mypkt));
+ bcopy(mypkt->data, pkt->data, mypkt->len);
- PKTFREE(sd->osh, mypkt, write ? true : false);
+ pkt_buf_free_skb(sd->osh, mypkt, write ? true : false);
} else { /* case 3: We have a packet and
it is aligned. */
sd_data(("%s: Aligned %s Packet, direct DMA\n",
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c
index ae7b566b11d7..ceaa47490680 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c
@@ -15,7 +15,9 @@
*/
#include <linux/types.h>
#include <linux/sched.h> /* request_irq() */
+#include <linux/netdevice.h>
#include <bcmdefs.h>
+#include <osl.h>
#include <bcmutils.h>
#include <sdio.h> /* SDIO Specs */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
@@ -211,7 +213,7 @@ int sdio_function_init(void)
if (!gInstance)
return -ENOMEM;
- bzero(&sdmmc_dev, sizeof(sdmmc_dev));
+ memset(&sdmmc_dev, 0, sizeof(sdmmc_dev));
error = sdio_register_driver(&bcmsdh_sdmmc_driver);
return error;
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index 57d06b2da46f..69c6a0272812 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -77,7 +77,7 @@ enum dhd_prealloc_index {
/* Common structure for module and instance linkage */
typedef struct dhd_pub {
/* Linkage ponters */
- osl_t *osh; /* OSL handle */
+ struct osl_info *osh; /* OSL handle */
struct dhd_bus *bus; /* Bus module handle */
struct dhd_prot *prot; /* Protocol module handle */
struct dhd_info *info; /* Info module handle */
@@ -277,15 +277,16 @@ typedef struct dhd_if_event {
*/
/* To allow osl_attach/detach calls from os-independent modules */
-osl_t *dhd_osl_attach(void *pdev, uint bustype);
-void dhd_osl_detach(osl_t *osh);
+struct osl_info *dhd_osl_attach(void *pdev, uint bustype);
+void dhd_osl_detach(struct osl_info *osh);
/* Indication from bus module regarding presence/insertion of dongle.
* Return dhd_pub_t pointer, used as handle to OS module in later calls.
* Returned structure should have bus and prot pointers filled in.
* bus_hdrlen specifies required headroom for bus module header.
*/
-extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen);
+extern dhd_pub_t *dhd_attach(struct osl_info *osh, struct dhd_bus *bus,
+ uint bus_hdrlen);
extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
/* Indication from bus module regarding removal/absence of dongle */
@@ -294,10 +295,12 @@ extern void dhd_detach(dhd_pub_t *dhdp);
/* Indication from bus module to change flow-control state */
extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on);
-extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec);
+extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q,
+ struct sk_buff *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
-extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt);
+extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx,
+ struct sk_buff *rxp, int numpkt);
/* Return pointer to interface name */
extern char *dhd_ifname(dhd_pub_t *dhdp, int idx);
@@ -306,7 +309,7 @@ extern char *dhd_ifname(dhd_pub_t *dhdp, int idx);
extern void dhd_sched_dpc(dhd_pub_t *dhdp);
/* Notify tx completion */
-extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success);
+extern void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success);
/* Query ioctl */
extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf,
@@ -377,7 +380,7 @@ extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, unsigned char * cp,
int len);
/* Send packet to dongle via data channel */
-extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt);
+extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pkt);
/* Send event to host */
extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event,
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
index 3b39c9966f81..cd0d5400bf07 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
@@ -26,8 +26,8 @@ extern int dhd_bus_register(void);
extern void dhd_bus_unregister(void);
/* Download firmware image and nvram image */
-extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t * osh,
- char *fw_path, char *nv_path);
+extern bool dhd_bus_download_firmware(struct dhd_bus *bus,
+ struct osl_info *osh, char *fw_path, char *nv_path);
/* Stop bus module: clear pending frames, disable data flow */
extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex);
@@ -36,7 +36,7 @@ extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex);
extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex);
/* Send a data frame to the dongle. Callee disposes of txp. */
-extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
+extern int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *txp);
/* Send/receive a control message to/from the dongle.
* Expects caller to enforce a single outstanding transaction.
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
index bcbaac9bcdcc..b7b527f5024c 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
@@ -15,6 +15,7 @@
*/
#include <linux/types.h>
+#include <linux/netdevice.h>
#include <bcmdefs.h>
#include <osl.h>
@@ -297,6 +298,15 @@ done:
return ret;
}
+#define PKTSUMNEEDED(skb) \
+ (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL)
+#define PKTSETSUMGOOD(skb, x) \
+ (((struct sk_buff *)(skb))->ip_summed = \
+ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
+
+/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because
+ skb->ip_summed is overloaded */
+
int
dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set)
@@ -309,7 +319,7 @@ void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
}
-void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
+void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, struct sk_buff *pktbuf)
{
#ifdef BDC
struct bdc_header *h;
@@ -320,33 +330,33 @@ void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
#ifdef BDC
/* Push BDC header used to convey priority for buses that don't */
- PKTPUSH(pktbuf, BDC_HEADER_LEN);
+ skb_push(pktbuf, BDC_HEADER_LEN);
- h = (struct bdc_header *)PKTDATA(pktbuf);
+ h = (struct bdc_header *)(pktbuf->data);
h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
if (PKTSUMNEEDED(pktbuf))
h->flags |= BDC_FLAG_SUM_NEEDED;
- h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
+ h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
h->flags2 = 0;
h->rssi = 0;
#endif /* BDC */
BDC_SET_IF_IDX(h, ifidx);
}
-bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 * fcbits)
+bool dhd_proto_fcinfo(dhd_pub_t *dhd, struct sk_buff *pktbuf, u8 * fcbits)
{
#ifdef BDC
struct bdc_header *h;
- if (PKTLEN(pktbuf) < BDC_HEADER_LEN) {
+ if (pktbuf->len < BDC_HEADER_LEN) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n",
- __func__, PKTLEN(pktbuf), BDC_HEADER_LEN));
+ __func__, pktbuf->len, BDC_HEADER_LEN));
return BCME_ERROR;
}
- h = (struct bdc_header *)PKTDATA(pktbuf);
+ h = (struct bdc_header *)(pktbuf->data);
*fcbits = h->priority >> BDC_PRIORITY_FC_SHIFT;
if ((h->flags2 & BDC_FLAG2_FC_FLAG) == BDC_FLAG2_FC_FLAG)
@@ -355,7 +365,7 @@ bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 * fcbits)
return false;
}
-int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
+int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, struct sk_buff *pktbuf)
{
#ifdef BDC
struct bdc_header *h;
@@ -366,13 +376,13 @@ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
#ifdef BDC
/* Pop BDC header used to convey priority for buses that don't */
- if (PKTLEN(pktbuf) < BDC_HEADER_LEN) {
+ if (pktbuf->len < BDC_HEADER_LEN) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n", __func__,
- PKTLEN(pktbuf), BDC_HEADER_LEN));
+ pktbuf->len, BDC_HEADER_LEN));
return BCME_ERROR;
}
- h = (struct bdc_header *)PKTDATA(pktbuf);
+ h = (struct bdc_header *)(pktbuf->data);
*ifidx = BDC_GET_IF_IDX(h);
if (*ifidx >= DHD_MAX_IFS) {
@@ -395,9 +405,9 @@ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
PKTSETSUMGOOD(pktbuf, true);
}
- PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
+ pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
- PKTPULL(pktbuf, BDC_HEADER_LEN);
+ skb_pull(pktbuf, BDC_HEADER_LEN);
#endif /* BDC */
return 0;
@@ -467,7 +477,7 @@ int dhd_prot_init(dhd_pub_t *dhd)
dhd_os_proto_unblock(dhd);
return ret;
}
- memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+ memcpy(dhd->mac.octet, buf, ETH_ALEN);
dhd_os_proto_unblock(dhd);
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
index 703188fc28ec..3dbf72eebd4a 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <bcmdefs.h>
+#include <linux/netdevice.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
@@ -326,9 +327,10 @@ void dhd_store_conn_status(u32 event, u32 status, u32 reason)
}
}
-bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
+bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, struct sk_buff *pkt,
+ int prec)
{
- void *p;
+ struct sk_buff *p;
int eprec = -1; /* precedence to evict from */
bool discard_oldest;
@@ -366,7 +368,7 @@ bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
ASSERT(p);
}
- PKTFREE(dhdp->osh, p, true);
+ pkt_buf_free_skb(dhdp->osh, p, true);
}
/* Enqueue */
@@ -832,7 +834,7 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata,
u16 flags;
int evlen;
- if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
+ if (memcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__));
return BCME_ERROR;
}
@@ -1254,7 +1256,7 @@ int dhd_preinit_ioctls(dhd_pub_t *dhd)
*/
ret = dhd_custom_get_mac_address(ea_addr.octet);
if (!ret) {
- bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN,
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETH_ALEN,
buf, sizeof(buf));
ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
if (ret < 0) {
@@ -1262,7 +1264,7 @@ int dhd_preinit_ioctls(dhd_pub_t *dhd)
__func__, ret));
} else
memcpy(dhd->mac.octet, (void *)&ea_addr,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
}
#endif /* GET_CUSTOM_MAC_ENABLE */
@@ -1532,7 +1534,7 @@ int dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
break;
if (!memcmp
- (bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
+ (bi->BSSID.octet, addr, ETH_ALEN)) {
DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] "
"%X:%X:%X:%X:%X:%X\n",
__func__, l, i, bi->BSSID.octet[0],
@@ -1670,7 +1672,7 @@ int dhd_iscan_request(void *dhdp, u16 action)
char buf[WLC_IOCTL_SMLEN];
memset(&params, 0, sizeof(wl_iscan_params_t));
- memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ memcpy(&params.params.bssid, &ether_bcast, ETH_ALEN);
params.params.bss_type = DOT11_BSSTYPE_ANY;
params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c
index f647034f36d6..c3f18bb3b27c 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c
@@ -14,7 +14,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linuxver.h>
+#include <linux/netdevice.h>
#include <osl.h>
#include <bcmutils.h>
@@ -24,8 +24,8 @@
#include <wlioctl.h>
#include <wl_iw.h>
-#define WL_ERROR(x) printf x
-#define WL_TRACE(x)
+#define WL_ERROR(fmt, args...) printk(fmt, ##args)
+#define WL_TRACE(fmt, args...) no_printk(fmt, ##args)
#ifdef CUSTOMER_HW
extern void bcm_wlan_power_off(int);
@@ -67,13 +67,13 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
#endif
if (dhd_oob_gpio_num < 0) {
- WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined\n",
- __func__));
+ WL_ERROR("%s: ERROR customer specific Host GPIO is NOT defined\n",
+ __func__);
return dhd_oob_gpio_num;
}
- WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
- __func__, dhd_oob_gpio_num));
+ WL_ERROR("%s: customer specific Host GPIO number is (%d)\n",
+ __func__, dhd_oob_gpio_num);
#if defined CUSTOMER_HW
host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num);
@@ -93,40 +93,40 @@ void dhd_customer_gpio_wlan_ctrl(int onoff)
{
switch (onoff) {
case WLAN_RESET_OFF:
- WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n",
- __func__));
+ WL_TRACE("%s: call customer specific GPIO to insert WLAN RESET\n",
+ __func__);
#ifdef CUSTOMER_HW
bcm_wlan_power_off(2);
#endif /* CUSTOMER_HW */
#ifdef CUSTOMER_HW2
wifi_set_power(0, 0);
#endif
- WL_ERROR(("=========== WLAN placed in RESET ========\n"));
+ WL_ERROR("=========== WLAN placed in RESET ========\n");
break;
case WLAN_RESET_ON:
- WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n",
- __func__));
+ WL_TRACE("%s: callc customer specific GPIO to remove WLAN RESET\n",
+ __func__);
#ifdef CUSTOMER_HW
bcm_wlan_power_on(2);
#endif /* CUSTOMER_HW */
#ifdef CUSTOMER_HW2
wifi_set_power(1, 0);
#endif
- WL_ERROR(("=========== WLAN going back to live ========\n"));
+ WL_ERROR("=========== WLAN going back to live ========\n");
break;
case WLAN_POWER_OFF:
- WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n",
- __func__));
+ WL_TRACE("%s: call customer specific GPIO to turn off WL_REG_ON\n",
+ __func__);
#ifdef CUSTOMER_HW
bcm_wlan_power_off(1);
#endif /* CUSTOMER_HW */
break;
case WLAN_POWER_ON:
- WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n",
- __func__));
+ WL_TRACE("%s: call customer specific GPIO to turn on WL_REG_ON\n",
+ __func__);
#ifdef CUSTOMER_HW
bcm_wlan_power_on(1);
#endif /* CUSTOMER_HW */
@@ -140,7 +140,7 @@ void dhd_customer_gpio_wlan_ctrl(int onoff)
/* Function to get custom MAC address */
int dhd_custom_get_mac_address(unsigned char *buf)
{
- WL_TRACE(("%s Enter\n", __func__));
+ WL_TRACE("%s Enter\n", __func__);
if (!buf)
return -EINVAL;
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index e5357875661f..db4508378775 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <bcmdefs.h>
-#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
@@ -211,7 +210,7 @@ typedef struct dhd_if {
int idx; /* iface idx in dongle */
int state; /* interface state */
uint subunit; /* subunit */
- u8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
+ u8 mac_addr[ETH_ALEN]; /* assigned MAC address */
bool attached; /* Delayed attachment when unset */
bool txflowcontrol; /* Per interface flow control indicator */
char name[IFNAMSIZ]; /* linux interface name */
@@ -709,7 +708,7 @@ static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
/* Send down the multicast list first. */
- buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
+ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
bufp = buf = kmalloc(buflen, GFP_ATOMIC);
if (!bufp) {
DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
@@ -727,8 +726,8 @@ static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
netdev_for_each_mc_addr(ha, dev) {
if (!cnt)
break;
- memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
- bufp += ETHER_ADDR_LEN;
+ memcpy(bufp, ha->addr, ETH_ALEN);
+ bufp += ETH_ALEN;
cnt--;
}
@@ -812,7 +811,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
DHD_TRACE(("%s enter\n", __func__));
if (!bcm_mkiovar
- ("cur_etheraddr", (char *)addr, ETHER_ADDR_LEN, buf, 32)) {
+ ("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) {
DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n",
dhd_ifname(&dhd->pub, ifidx)));
return -1;
@@ -828,7 +827,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
DHD_ERROR(("%s: set cur_etheraddr failed\n",
dhd_ifname(&dhd->pub, ifidx)));
} else {
- memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN);
}
return ret;
@@ -998,7 +997,7 @@ static int dhd_set_mac_address(struct net_device *dev, void *addr)
return -1;
ASSERT(dhd->sysioc_tsk);
- memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
+ memcpy(&dhd->macvalue, sa->sa_data, ETH_ALEN);
dhd->set_macaddress = true;
up(&dhd->sysioc_sem);
@@ -1019,7 +1018,7 @@ static void dhd_set_multicast_list(struct net_device *dev)
up(&dhd->sysioc_sem);
}
-int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
+int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf)
{
int ret;
dhd_info_t *dhd = (dhd_info_t *) (dhdp->info);
@@ -1029,13 +1028,13 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
return -ENODEV;
/* Update multicast statistic */
- if (PKTLEN(pktbuf) >= ETHER_ADDR_LEN) {
- u8 *pktdata = (u8 *) PKTDATA(pktbuf);
+ if (pktbuf->len >= ETH_ALEN) {
+ u8 *pktdata = (u8 *) (pktbuf->data);
struct ether_header *eh = (struct ether_header *)pktdata;
- if (ETHER_ISMULTI(eh->ether_dhost))
+ if (is_multicast_ether_addr(eh->ether_dhost))
dhdp->tx_multicast++;
- if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
+ if (ntoh16(eh->ether_type) == ETH_P_PAE)
atomic_inc(&dhd->pend_8021x_cnt);
}
@@ -1053,6 +1052,32 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
return ret;
}
+static inline void *
+osl_pkt_frmnative(struct osl_info *osh, struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+
+ for (nskb = skb; nskb; nskb = nskb->next)
+ osh->pktalloced++;
+
+ return (void *)skb;
+}
+#define PKTFRMNATIVE(osh, skb) \
+ osl_pkt_frmnative((osh), (struct sk_buff *)(skb))
+
+static inline struct sk_buff *
+osl_pkt_tonative(struct osl_info *osh, void *pkt)
+{
+ struct sk_buff *nskb;
+
+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next)
+ osh->pktalloced--;
+
+ return (struct sk_buff *)pkt;
+}
+#define PKTTONATIVE(osh, pkt) \
+ osl_pkt_tonative((osh), (pkt))
+
static int dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
{
int ret;
@@ -1133,13 +1158,15 @@ void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
netif_wake_queue(net);
}
-void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt)
+void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf,
+ int numpkt)
{
dhd_info_t *dhd = (dhd_info_t *) dhdp->info;
struct sk_buff *skb;
unsigned char *eth;
uint len;
- void *data, *pnext, *save_pktbuf;
+ void *data;
+ struct sk_buff *pnext, *save_pktbuf;
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
@@ -1150,8 +1177,8 @@ void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt)
for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
- pnext = PKTNEXT(pktbuf);
- PKTSETNEXT(pktbuf, NULL);
+ pnext = pktbuf->next;
+ pktbuf->next = NULL;
skb = PKTTONATIVE(dhdp->osh, pktbuf);
@@ -1190,7 +1217,7 @@ void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt)
/* Process special event packets and then discard them */
if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM)
dhd_wl_host_event(dhd, &ifidx,
- skb->mac_header,
+ skb_mac_header(skb),
&event, &data);
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1223,7 +1250,7 @@ void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
return;
}
-void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
+void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success)
{
uint ifidx;
dhd_info_t *dhd = (dhd_info_t *) (dhdp->info);
@@ -1232,10 +1259,10 @@ void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
dhd_prot_hdrpull(dhdp, &ifidx, txp);
- eh = (struct ether_header *)PKTDATA(txp);
+ eh = (struct ether_header *)(txp->data);
type = ntoh16(eh->ether_type);
- if (type == ETHER_TYPE_802_1X)
+ if (type == ETH_P_PAE)
atomic_dec(&dhd->pend_8021x_cnt);
}
@@ -1621,6 +1648,51 @@ static int dhd_ethtool(dhd_info_t *dhd, void *uaddr)
return 0;
}
+static s16 linuxbcmerrormap[] = { 0, /* 0 */
+ -EINVAL, /* BCME_ERROR */
+ -EINVAL, /* BCME_BADARG */
+ -EINVAL, /* BCME_BADOPTION */
+ -EINVAL, /* BCME_NOTUP */
+ -EINVAL, /* BCME_NOTDOWN */
+ -EINVAL, /* BCME_NOTAP */
+ -EINVAL, /* BCME_NOTSTA */
+ -EINVAL, /* BCME_BADKEYIDX */
+ -EINVAL, /* BCME_RADIOOFF */
+ -EINVAL, /* BCME_NOTBANDLOCKED */
+ -EINVAL, /* BCME_NOCLK */
+ -EINVAL, /* BCME_BADRATESET */
+ -EINVAL, /* BCME_BADBAND */
+ -E2BIG, /* BCME_BUFTOOSHORT */
+ -E2BIG, /* BCME_BUFTOOLONG */
+ -EBUSY, /* BCME_BUSY */
+ -EINVAL, /* BCME_NOTASSOCIATED */
+ -EINVAL, /* BCME_BADSSIDLEN */
+ -EINVAL, /* BCME_OUTOFRANGECHAN */
+ -EINVAL, /* BCME_BADCHAN */
+ -EFAULT, /* BCME_BADADDR */
+ -ENOMEM, /* BCME_NORESOURCE */
+ -EOPNOTSUPP, /* BCME_UNSUPPORTED */
+ -EMSGSIZE, /* BCME_BADLENGTH */
+ -EINVAL, /* BCME_NOTREADY */
+ -EPERM, /* BCME_NOTPERMITTED */
+ -ENOMEM, /* BCME_NOMEM */
+ -EINVAL, /* BCME_ASSOCIATED */
+ -ERANGE, /* BCME_RANGE */
+ -EINVAL, /* BCME_NOTFOUND */
+ -EINVAL, /* BCME_WME_NOT_ENABLED */
+ -EINVAL, /* BCME_TSPEC_NOTFOUND */
+ -EINVAL, /* BCME_ACM_NOTSUPPORTED */
+ -EINVAL, /* BCME_NOT_WME_ASSOCIATION */
+ -EIO, /* BCME_SDIO_ERROR */
+ -ENODEV, /* BCME_DONGLE_DOWN */
+ -EINVAL, /* BCME_VERSION */
+ -EIO, /* BCME_TXFAIL */
+ -EIO, /* BCME_RXFAIL */
+ -EINVAL, /* BCME_NODEVICE */
+ -EINVAL, /* BCME_NMODE_DISABLED */
+ -ENODATA, /* BCME_NONRESIDENT */
+};
+
static int dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
{
dhd_info_t *dhd = *(dhd_info_t **) netdev_priv(net);
@@ -1742,7 +1814,12 @@ done:
if (buf)
kfree(buf);
- return OSL_ERROR(bcmerror);
+ if (bcmerror > 0)
+ bcmerror = 0;
+ else if (bcmerror < BCME_LAST)
+ bcmerror = BCME_ERROR;
+
+ return linuxbcmerrormap[-bcmerror];
}
static int dhd_stop(struct net_device *net)
@@ -1789,7 +1866,7 @@ static int dhd_open(struct net_device *net)
}
atomic_set(&dhd->pend_8021x_cnt, 0);
- memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
+ memcpy(net->dev_addr, dhd->pub.mac.octet, ETH_ALEN);
#ifdef TOE
/* Get current TOE mode from dongle */
@@ -1814,12 +1891,12 @@ static int dhd_open(struct net_device *net)
return ret;
}
-osl_t *dhd_osl_attach(void *pdev, uint bustype)
+struct osl_info *dhd_osl_attach(void *pdev, uint bustype)
{
- return osl_attach(pdev, bustype, true);
+ return osl_attach(pdev, bustype);
}
-void dhd_osl_detach(osl_t *osh)
+void dhd_osl_detach(struct osl_info *osh)
{
osl_detach(osh);
}
@@ -1845,7 +1922,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
dhd->iflist[ifidx] = ifp;
strlcpy(ifp->name, name, IFNAMSIZ);
if (mac_addr != NULL)
- memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
+ memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
if (handle == NULL) {
ifp->state = WLC_E_IF_ADD;
@@ -1877,7 +1954,8 @@ void dhd_del_if(dhd_info_t *dhd, int ifidx)
up(&dhd->sysioc_sem);
}
-dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
+dhd_pub_t *dhd_attach(struct osl_info *osh, struct dhd_bus *bus,
+ uint bus_hdrlen)
{
dhd_info_t *dhd = NULL;
struct net_device *net;
@@ -1929,7 +2007,7 @@ dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
goto fail;
net->netdev_ops = NULL;
- init_MUTEX(&dhd->proto_sem);
+ sema_init(&dhd->proto_sem, 1);
/* Initialize other structure content */
init_waitqueue_head(&dhd->ioctl_resp_wait);
init_waitqueue_head(&dhd->ctrl_wait);
@@ -1977,7 +2055,7 @@ dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
dhd->timer.function = dhd_watchdog;
/* Initialize thread based operation and lock */
- init_MUTEX(&dhd->sdsem);
+ sema_init(&dhd->sdsem, 1);
if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0))
dhd->threads_only = true;
else
@@ -2199,19 +2277,11 @@ static struct net_device_ops dhd_ops_pri = {
.ndo_set_multicast_list = dhd_set_multicast_list
};
-static struct net_device_ops dhd_ops_virt = {
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
- .ndo_set_multicast_list = dhd_set_multicast_list
-};
-
int dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
{
dhd_info_t *dhd = (dhd_info_t *) dhdp->info;
struct net_device *net;
- u8 temp_addr[ETHER_ADDR_LEN] = {
+ u8 temp_addr[ETH_ALEN] = {
0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
DHD_TRACE(("%s: ifidx %d\n", __func__, ifidx));
@@ -2222,8 +2292,6 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
ASSERT(net);
ASSERT(!net->netdev_ops);
- net->netdev_ops = &dhd_ops_virt;
-
net->netdev_ops = &dhd_ops_pri;
/*
@@ -2231,7 +2299,7 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
*/
if (ifidx != 0) {
/* for virtual interfaces use the primary MAC */
- memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
+ memcpy(temp_addr, dhd->pub.mac.octet, ETH_ALEN);
}
@@ -2259,7 +2327,7 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen;
- memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+ memcpy(net->dev_addr, temp_addr, ETH_ALEN);
if (register_netdev(net) != 0) {
DHD_ERROR(("%s: couldn't register the net device\n",
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c
index bf8df9801030..c66f1c2941e2 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
-#include <linuxver.h>
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
{
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
index cc42fa4a9140..a5309e27b65b 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
@@ -46,15 +46,16 @@ extern int dhd_prot_init(dhd_pub_t *dhdp);
/* Stop protocol: sync w/dongle state. */
extern void dhd_prot_stop(dhd_pub_t *dhdp);
-extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 *fcbits);
+extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, struct sk_buff *pktbuf,
+ u8 *fcbits);
/* Add any protocol-specific data header.
* Caller must reserve prot_hdrlen prepend space.
*/
-extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp);
+extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, struct sk_buff *txp);
/* Remove any protocol-specific data header. */
-extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp);
+extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, struct sk_buff *rxp);
/* Use protocol to issue ioctl to dongle */
extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc,
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index b2281d9dfdcf..3edce44978a1 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <bcmdefs.h>
+#include <linux/netdevice.h>
#include <osl.h>
#include <bcmsdh.h>
@@ -143,7 +144,7 @@
* bufpool was present for gspi bus.
*/
#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
- PKTFREE(bus->dhd->osh, pkt, false);
+ pkt_buf_free_skb(bus->dhd->osh, pkt, false);
DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf,
uint len);
@@ -202,8 +203,8 @@ typedef struct dhd_bus {
u8 rx_seq; /* Receive sequence number (expected) */
bool rxskip; /* Skip receive (awaiting NAK ACK) */
- void *glomd; /* Packet containing glomming descriptor */
- void *glom; /* Packet chain for glommed superframe */
+ struct sk_buff *glomd; /* Packet containing glomming descriptor */
+ struct sk_buff *glom; /* Packet chain for glommed superframe */
uint glomerr; /* Glom packet read errors */
u8 *rxbuf; /* Buffer for receiving control packets */
@@ -356,16 +357,16 @@ extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
-#define PKTALIGN(osh, p, len, align) \
+#define PKTALIGN(_osh, _p, _len, _align) \
do { \
uint datalign; \
- datalign = (unsigned long)PKTDATA((p)); \
- datalign = roundup(datalign, (align)) - datalign; \
- ASSERT(datalign < (align)); \
- ASSERT(PKTLEN((p)) >= ((len) + datalign)); \
+ datalign = (unsigned long)((_p)->data); \
+ datalign = roundup(datalign, (_align)) - datalign; \
+ ASSERT(datalign < (_align)); \
+ ASSERT((_p)->len >= ((_len) + datalign)); \
if (datalign) \
- PKTPULL((p), datalign); \
- PKTSETLEN((p), (len)); \
+ skb_pull((_p), datalign); \
+ __skb_trim((_p), (_len)); \
} while (0)
/* Limit on rounding up frames */
@@ -430,27 +431,30 @@ static int dhdsdio_mem_dump(dhd_bus_t *bus);
#endif /* DHD_DEBUG */
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
-static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
-static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
+static void dhdsdio_release(dhd_bus_t *bus, struct osl_info *osh);
+static void dhdsdio_release_malloc(dhd_bus_t *bus, struct osl_info *osh);
static void dhdsdio_disconnect(void *ptr);
static bool dhdsdio_chipmatch(u16 chipid);
-static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
- void *regsva, u16 devid);
-static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
-static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
-static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t * osh);
+static bool dhdsdio_probe_attach(dhd_bus_t *bus, struct osl_info *osh,
+ void *sdh, void *regsva, u16 devid);
+static bool dhdsdio_probe_malloc(dhd_bus_t *bus, struct osl_info *osh,
+ void *sdh);
+static bool dhdsdio_probe_init(dhd_bus_t *bus, struct osl_info *osh, void *sdh);
+static void dhdsdio_release_dongle(dhd_bus_t *bus, struct osl_info * osh);
static uint process_nvram_vars(char *varbuf, uint len);
static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes, void *pkt,
- bcmsdh_cmplt_fn_t complete, void *handle);
+ uint flags, u8 *buf, uint nbytes,
+ struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete,
+ void *handle);
static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes, void *pkt,
- bcmsdh_cmplt_fn_t complete, void *handle);
+ uint flags, u8 *buf, uint nbytes,
+ struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete,
+ void *handle);
-static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh,
+static bool dhdsdio_download_firmware(struct dhd_bus *bus, struct osl_info *osh,
void *sdh);
static int _dhdsdio_download_firmware(struct dhd_bus *bus);
@@ -900,16 +904,17 @@ void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
/* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */
-static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
+static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan,
+ bool free_pkt)
{
int ret;
- osl_t *osh;
+ struct osl_info *osh;
u8 *frame;
u16 len, pad = 0;
u32 swheader;
uint retries = 0;
bcmsdh_info_t *sdh;
- void *new;
+ struct sk_buff *new;
int i;
DHD_TRACE(("%s: Enter\n", __func__));
@@ -922,46 +927,46 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
goto done;
}
- frame = (u8 *) PKTDATA(pkt);
+ frame = (u8 *) (pkt->data);
/* Add alignment padding, allocate new packet if needed */
pad = ((unsigned long)frame % DHD_SDALIGN);
if (pad) {
- if (PKTHEADROOM(pkt) < pad) {
+ if (skb_headroom(pkt) < pad) {
DHD_INFO(("%s: insufficient headroom %d for %d pad\n",
- __func__, (int)PKTHEADROOM(pkt), pad));
+ __func__, skb_headroom(pkt), pad));
bus->dhd->tx_realloc++;
- new = PKTGET(osh, (PKTLEN(pkt) + DHD_SDALIGN), true);
+ new = pkt_buf_get_skb(osh, (pkt->len + DHD_SDALIGN));
if (!new) {
DHD_ERROR(("%s: couldn't allocate new %d-byte "
"packet\n",
- __func__, PKTLEN(pkt) + DHD_SDALIGN));
+ __func__, pkt->len + DHD_SDALIGN));
ret = BCME_NOMEM;
goto done;
}
- PKTALIGN(osh, new, PKTLEN(pkt), DHD_SDALIGN);
- bcopy(PKTDATA(pkt), PKTDATA(new), PKTLEN(pkt));
+ PKTALIGN(osh, new, pkt->len, DHD_SDALIGN);
+ bcopy(pkt->data, new->data, pkt->len);
if (free_pkt)
- PKTFREE(osh, pkt, true);
+ pkt_buf_free_skb(osh, pkt, true);
/* free the pkt if canned one is not used */
free_pkt = true;
pkt = new;
- frame = (u8 *) PKTDATA(pkt);
+ frame = (u8 *) (pkt->data);
ASSERT(((unsigned long)frame % DHD_SDALIGN) == 0);
pad = 0;
} else {
- PKTPUSH(pkt, pad);
- frame = (u8 *) PKTDATA(pkt);
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
- ASSERT((pad + SDPCM_HDRLEN) <= (int)PKTLEN(pkt));
- bzero(frame, pad + SDPCM_HDRLEN);
+ ASSERT((pad + SDPCM_HDRLEN) <= (int)(pkt->len));
+ memset(frame, 0, pad + SDPCM_HDRLEN);
}
}
ASSERT(pad < DHD_SDALIGN);
/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- len = (u16) PKTLEN(pkt);
+ len = (u16) (pkt->len);
*(u16 *) frame = htol16(len);
*(((u16 *) frame) + 1) = htol16(~len);
@@ -974,7 +979,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
#ifdef DHD_DEBUG
- tx_packets[PKTPRIO(pkt)]++;
+ tx_packets[pkt->priority]++;
if (DHD_BYTES_ON() &&
(((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
(DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
@@ -989,7 +994,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
u16 pad = bus->blocksize - (len % bus->blocksize);
if ((pad <= bus->roundup) && (pad < bus->blocksize))
#ifdef NOTUSED
- if (pad <= PKTTAILROOM(pkt))
+ if (pad <= skb_tailroom(pkt))
#endif /* NOTUSED */
len += pad;
} else if (len % DHD_SDALIGN) {
@@ -999,7 +1004,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
/* Some controllers have trouble with odd bytes -- round to even */
if (forcealign && (len & (ALIGNMENT - 1))) {
#ifdef NOTUSED
- if (PKTTAILROOM(pkt))
+ if (skb_tailroom(pkt))
#endif
len = roundup(len, ALIGNMENT);
#ifdef NOTUSED
@@ -1050,34 +1055,34 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
done:
/* restore pkt buffer pointer before calling tx complete routine */
- PKTPULL(pkt, SDPCM_HDRLEN + pad);
+ skb_pull(pkt, SDPCM_HDRLEN + pad);
dhd_os_sdunlock(bus->dhd);
dhd_txcomplete(bus->dhd, pkt, ret != 0);
dhd_os_sdlock(bus->dhd);
if (free_pkt)
- PKTFREE(osh, pkt, true);
+ pkt_buf_free_skb(osh, pkt, true);
return ret;
}
-int dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
+int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *pkt)
{
int ret = BCME_ERROR;
- osl_t *osh;
+ struct osl_info *osh;
uint datalen, prec;
DHD_TRACE(("%s: Enter\n", __func__));
osh = bus->dhd->osh;
- datalen = PKTLEN(pkt);
+ datalen = pkt->len;
#ifdef SDTEST
/* Push the test header if doing loopback */
if (bus->ext_loop) {
u8 *data;
- PKTPUSH(pkt, SDPCM_TEST_HDRLEN);
- data = PKTDATA(pkt);
+ skb_push(pkt, SDPCM_TEST_HDRLEN);
+ data = pkt->data;
*data++ = SDPCM_TEST_ECHOREQ;
*data++ = (u8) bus->loopid++;
*data++ = (datalen >> 0);
@@ -1087,10 +1092,10 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
#endif /* SDTEST */
/* Add space for the header */
- PKTPUSH(pkt, SDPCM_HDRLEN);
- ASSERT(IS_ALIGNED((unsigned long)PKTDATA(pkt), 2));
+ skb_push(pkt, SDPCM_HDRLEN);
+ ASSERT(IS_ALIGNED((unsigned long)(pkt->data), 2));
- prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
+ prec = PRIO2PREC((pkt->priority & PRIOMASK));
/* Check for existing queue, current flow-control,
pending event, or pending clock */
@@ -1105,9 +1110,9 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
/* Priority based enq */
dhd_os_sdlock_txq(bus->dhd);
if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == false) {
- PKTPULL(pkt, SDPCM_HDRLEN);
+ skb_pull(pkt, SDPCM_HDRLEN);
dhd_txcomplete(bus->dhd, pkt, false);
- PKTFREE(osh, pkt, true);
+ pkt_buf_free_skb(osh, pkt, true);
DHD_ERROR(("%s: out of bus->txq !!!\n", __func__));
ret = BCME_NORESOURCE;
} else {
@@ -1162,7 +1167,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
static uint dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
{
- void *pkt;
+ struct sk_buff *pkt;
u32 intstatus = 0;
uint retries = 0;
int ret = 0, prec_out;
@@ -1186,7 +1191,7 @@ static uint dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
break;
}
dhd_os_sdunlock_txq(bus->dhd);
- datalen = PKTLEN(pkt) - SDPCM_HDRLEN;
+ datalen = pkt->len - SDPCM_HDRLEN;
#ifndef SDTEST
ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
@@ -1247,7 +1252,7 @@ int dhd_bus_txctl(struct dhd_bus *bus, unsigned char *msg, uint msglen)
frame -= doff;
len += doff;
msglen += doff;
- bzero(frame, doff + SDPCM_HDRLEN);
+ memset(frame, 0, doff + SDPCM_HDRLEN);
}
ASSERT(doff < DHD_SDALIGN);
}
@@ -2531,7 +2536,7 @@ static int dhdsdio_write_vars(dhd_bus_t *bus)
if (!vbuffer)
return BCME_NOMEM;
- bzero(vbuffer, varsize);
+ memset(vbuffer, 0, varsize);
bcopy(bus->vars, vbuffer, bus->varsz);
/* Write the vars list */
@@ -2823,7 +2828,7 @@ exit:
void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
{
- osl_t *osh = bus->dhd->osh;
+ struct osl_info *osh = bus->dhd->osh;
u32 local_hostintmask;
u8 saveclk;
uint retries;
@@ -2877,10 +2882,10 @@ void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
/* Clear any held glomming stuff */
if (bus->glomd)
- PKTFREE(osh, bus->glomd, false);
+ pkt_buf_free_skb(osh, bus->glomd, false);
if (bus->glom)
- PKTFREE(osh, bus->glom, false);
+ pkt_buf_free_skb(osh, bus->glom, false);
bus->glom = bus->glomd = NULL;
@@ -3178,8 +3183,8 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
u8 *dptr, num = 0;
u16 sublen, check;
- void *pfirst, *plast, *pnext, *save_pfirst;
- osl_t *osh = bus->dhd->osh;
+ struct sk_buff *pfirst, *plast, *pnext, *save_pfirst;
+ struct osl_info *osh = bus->dhd->osh;
int errcode;
u8 chan, seq, doff, sfdoff;
@@ -3199,8 +3204,8 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
dhd_os_sdlock_rxq(bus->dhd);
pfirst = plast = pnext = NULL;
- dlen = (u16) PKTLEN(bus->glomd);
- dptr = PKTDATA(bus->glomd);
+ dlen = (u16) (bus->glomd->len);
+ dptr = bus->glomd->data;
if (!dlen || (dlen & 1)) {
DHD_ERROR(("%s: bad glomd len(%d), ignore descriptor\n",
__func__, dlen));
@@ -3235,19 +3240,19 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
}
/* Allocate/chain packet for next subframe */
- pnext = PKTGET(osh, sublen + DHD_SDALIGN, false);
+ pnext = pkt_buf_get_skb(osh, sublen + DHD_SDALIGN);
if (pnext == NULL) {
- DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
+ DHD_ERROR(("%s: pkt_buf_get_skb failed, num %d len %d\n",
__func__, num, sublen));
break;
}
- ASSERT(!PKTLINK(pnext));
+ ASSERT(!(pnext->prev));
if (!pfirst) {
ASSERT(!plast);
pfirst = plast = pnext;
} else {
ASSERT(plast);
- PKTSETNEXT(plast, pnext);
+ plast->next = pnext;
plast = pnext;
}
@@ -3271,13 +3276,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
pfirst = pnext = NULL;
} else {
if (pfirst)
- PKTFREE(osh, pfirst, false);
+ pkt_buf_free_skb(osh, pfirst, false);
bus->glom = NULL;
num = 0;
}
/* Done with descriptor packet */
- PKTFREE(osh, bus->glomd, false);
+ pkt_buf_free_skb(osh, bus->glomd, false);
bus->glomd = NULL;
bus->nextlen = 0;
@@ -3290,10 +3295,10 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
if (DHD_GLOM_ON()) {
DHD_GLOM(("%s: try superframe read, packet chain:\n",
__func__));
- for (pnext = bus->glom; pnext; pnext = PKTNEXT(pnext)) {
+ for (pnext = bus->glom; pnext; pnext = pnext->next) {
DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
- pnext, (u8 *) PKTDATA(pnext),
- PKTLEN(pnext), PKTLEN(pnext)));
+ pnext, (u8 *) (pnext->data),
+ pnext->len, pnext->len));
}
}
@@ -3309,7 +3314,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
bcmsdh_cur_sbwad
(bus->sdh), SDIO_FUNC_2,
F2SYNC,
- (u8 *) PKTDATA(pfirst),
+ (u8 *) pfirst->data,
dlen, pfirst, NULL, NULL);
} else if (bus->dataptr) {
errcode = dhd_bcmsdh_recv_buf(bus,
@@ -3346,7 +3351,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
bus->glomerr = 0;
dhdsdio_rxfail(bus, true, false);
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(osh, bus->glom, false);
+ pkt_buf_free_skb(osh, bus->glom, false);
dhd_os_sdunlock_rxq(bus->dhd);
bus->rxglomfail++;
bus->glom = NULL;
@@ -3355,13 +3360,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
}
#ifdef DHD_DEBUG
if (DHD_GLOM_ON()) {
- prhex("SUPERFRAME", PKTDATA(pfirst),
- min_t(int, PKTLEN(pfirst), 48));
+ prhex("SUPERFRAME", pfirst->data,
+ min_t(int, pfirst->len, 48));
}
#endif
/* Validate the superframe header */
- dptr = (u8 *) PKTDATA(pfirst);
+ dptr = (u8 *) (pfirst->data);
sublen = ltoh16_ua(dptr);
check = ltoh16_ua(dptr + sizeof(u16));
@@ -3399,11 +3404,11 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
__func__));
errcode = -1;
} else if ((doff < SDPCM_HDRLEN) ||
- (doff > (PKTLEN(pfirst) - SDPCM_HDRLEN))) {
+ (doff > (pfirst->len - SDPCM_HDRLEN))) {
DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d "
"pkt %d min %d\n",
__func__, doff, sublen,
- PKTLEN(pfirst), SDPCM_HDRLEN));
+ pfirst->len, SDPCM_HDRLEN));
errcode = -1;
}
@@ -3424,14 +3429,14 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
bus->tx_max = txmax;
/* Remove superframe header, remember offset */
- PKTPULL(pfirst, doff);
+ skb_pull(pfirst, doff);
sfdoff = doff;
/* Validate all the subframe headers */
for (num = 0, pnext = pfirst; pnext && !errcode;
- num++, pnext = PKTNEXT(pnext)) {
- dptr = (u8 *) PKTDATA(pnext);
- dlen = (u16) PKTLEN(pnext);
+ num++, pnext = pnext->next) {
+ dptr = (u8 *) (pnext->data);
+ dlen = (u16) (pnext->len);
sublen = ltoh16_ua(dptr);
check = ltoh16_ua(dptr + sizeof(u16));
chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
@@ -3469,13 +3474,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
a couple retries */
if (bus->glomerr++ < 3) {
/* Restore superframe header space */
- PKTPUSH(pfirst, sfdoff);
+ skb_push(pfirst, sfdoff);
dhdsdio_rxfail(bus, true, true);
} else {
bus->glomerr = 0;
dhdsdio_rxfail(bus, true, false);
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(osh, bus->glom, false);
+ pkt_buf_free_skb(osh, bus->glom, false);
dhd_os_sdunlock_rxq(bus->dhd);
bus->rxglomfail++;
bus->glom = NULL;
@@ -3491,10 +3496,10 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
dhd_os_sdlock_rxq(bus->dhd);
for (num = 0; pfirst; rxseq++, pfirst = pnext) {
- pnext = PKTNEXT(pfirst);
- PKTSETNEXT(pfirst, NULL);
+ pnext = pfirst->next;
+ pfirst->next = NULL;
- dptr = (u8 *) PKTDATA(pfirst);
+ dptr = (u8 *) (pfirst->data);
sublen = ltoh16_ua(dptr);
chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
@@ -3502,8 +3507,8 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d "
"chan %d seq %d\n",
- __func__, num, pfirst, PKTDATA(pfirst),
- PKTLEN(pfirst), sublen, chan, seq));
+ __func__, num, pfirst, pfirst->data,
+ pfirst->len, sublen, chan, seq));
ASSERT((chan == SDPCM_DATA_CHANNEL)
|| (chan == SDPCM_EVENT_CHANNEL));
@@ -3519,13 +3524,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
prhex("Rx Subframe Data", dptr, dlen);
#endif
- PKTSETLEN(pfirst, sublen);
- PKTPULL(pfirst, doff);
+ __skb_trim(pfirst, sublen);
+ skb_pull(pfirst, doff);
- if (PKTLEN(pfirst) == 0) {
- PKTFREE(bus->dhd->osh, pfirst, false);
+ if (pfirst->len == 0) {
+ pkt_buf_free_skb(bus->dhd->osh, pfirst, false);
if (plast) {
- PKTSETNEXT(plast, pnext);
+ plast->next = pnext;
} else {
ASSERT(save_pfirst == pfirst);
save_pfirst = pnext;
@@ -3536,9 +3541,9 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
DHD_ERROR(("%s: rx protocol error\n",
__func__));
bus->dhd->rx_errors++;
- PKTFREE(osh, pfirst, false);
+ pkt_buf_free_skb(osh, pfirst, false);
if (plast) {
- PKTSETNEXT(plast, pnext);
+ plast->next = pnext;
} else {
ASSERT(save_pfirst == pfirst);
save_pfirst = pnext;
@@ -3548,7 +3553,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
/* this packet will go up, link back into
chain and count it */
- PKTSETNEXT(pfirst, pnext);
+ pfirst->next = pnext;
plast = pfirst;
num++;
@@ -3556,11 +3561,11 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
if (DHD_GLOM_ON()) {
DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) "
"nxt/lnk %p/%p\n",
- __func__, num, pfirst, PKTDATA(pfirst),
- PKTLEN(pfirst), PKTNEXT(pfirst),
- PKTLINK(pfirst)));
- prhex("", (u8 *) PKTDATA(pfirst),
- min_t(int, PKTLEN(pfirst), 32));
+ __func__, num, pfirst, pfirst->data,
+ pfirst->len, pfirst->next,
+ pfirst->prev));
+ prhex("", (u8 *) pfirst->data,
+ min_t(int, pfirst->len, 32));
}
#endif /* DHD_DEBUG */
}
@@ -3580,7 +3585,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq)
/* Return true if there may be more frames to read */
static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
{
- osl_t *osh = bus->dhd->osh;
+ struct osl_info *osh = bus->dhd->osh;
bcmsdh_info_t *sdh = bus->sdh;
u16 len, check; /* Extracted hardware header fields */
@@ -3588,7 +3593,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
u8 fcbits; /* Extracted fcbits from software header */
u8 delta;
- void *pkt; /* Packet for event or data frames */
+ struct sk_buff *pkt; /* Packet for event or data frames */
u16 pad; /* Number of pad bytes to read */
u16 rdlen; /* Total number of bytes to read */
u8 rxseq; /* Next sequence number to expect */
@@ -3675,7 +3680,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
*/
/* Allocate a packet buffer */
dhd_os_sdlock_rxq(bus->dhd);
- pkt = PKTGET(osh, rdlen + DHD_SDALIGN, false);
+ pkt = pkt_buf_get_skb(osh, rdlen + DHD_SDALIGN);
if (!pkt) {
if (bus->bus == SPI_BUS) {
bus->usebufpool = false;
@@ -3721,7 +3726,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
} else {
/* Give up on data,
request rtx of events */
- DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " "expected rxseq %d\n",
+ DHD_ERROR(("%s (nextlen): pkt_buf_get_skb failed: len %d rdlen %d " "expected rxseq %d\n",
__func__, len, rdlen, rxseq));
/* Just go try again w/normal
header read */
@@ -3732,9 +3737,9 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
if (bus->bus == SPI_BUS)
bus->usebufpool = true;
- ASSERT(!PKTLINK(pkt));
+ ASSERT(!(pkt->prev));
PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
- rxbuf = (u8 *) PKTDATA(pkt);
+ rxbuf = (u8 *) (pkt->data);
/* Read the entire frame */
sdret =
dhd_bcmsdh_recv_buf(bus,
@@ -3748,7 +3753,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
if (sdret < 0) {
DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
__func__, rdlen, sdret));
- PKTFREE(bus->dhd->osh, pkt, false);
+ pkt_buf_free_skb(bus->dhd->osh, pkt, false);
bus->dhd->rx_errors++;
dhd_os_sdunlock_rxq(bus->dhd);
/* Force retry w/normal header read.
@@ -3896,7 +3901,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
doff);
if (bus->usebufpool) {
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(bus->dhd->osh, pkt,
+ pkt_buf_free_skb(bus->dhd->osh, pkt,
false);
dhd_os_sdunlock_rxq(bus->dhd);
}
@@ -4086,10 +4091,10 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
dhd_os_sdlock_rxq(bus->dhd);
- pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), false);
+ pkt = pkt_buf_get_skb(osh, (rdlen + firstread + DHD_SDALIGN));
if (!pkt) {
/* Give up on data, request rtx of events */
- DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
+ DHD_ERROR(("%s: pkt_buf_get_skb failed: rdlen %d chan %d\n",
__func__, rdlen, chan));
bus->dhd->rx_dropped++;
dhd_os_sdunlock_rxq(bus->dhd);
@@ -4098,17 +4103,17 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
dhd_os_sdunlock_rxq(bus->dhd);
- ASSERT(!PKTLINK(pkt));
+ ASSERT(!(pkt->prev));
/* Leave room for what we already read, and align remainder */
- ASSERT(firstread < (PKTLEN(pkt)));
- PKTPULL(pkt, firstread);
+ ASSERT(firstread < pkt->len);
+ skb_pull(pkt, firstread);
PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
/* Read the remaining frame data */
sdret =
dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2,
- F2SYNC, ((u8 *) PKTDATA(pkt)), rdlen,
+ F2SYNC, ((u8 *) (pkt->data)), rdlen,
pkt, NULL, NULL);
bus->f2rxdata++;
ASSERT(sdret != BCME_PENDING);
@@ -4122,7 +4127,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
? "data" : "test")),
sdret));
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(bus->dhd->osh, pkt, false);
+ pkt_buf_free_skb(bus->dhd->osh, pkt, false);
dhd_os_sdunlock_rxq(bus->dhd);
bus->dhd->rx_errors++;
dhdsdio_rxfail(bus, true, RETRYCHAN(chan));
@@ -4130,12 +4135,12 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Copy the already-read portion */
- PKTPUSH(pkt, firstread);
- bcopy(bus->rxhdr, PKTDATA(pkt), firstread);
+ skb_push(pkt, firstread);
+ bcopy(bus->rxhdr, pkt->data, firstread);
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_DATA_ON())
- prhex("Rx Data", PKTDATA(pkt), len);
+ prhex("Rx Data", pkt->data, len);
#endif
deliver:
@@ -4146,12 +4151,12 @@ deliver:
__func__, len));
#ifdef DHD_DEBUG
if (DHD_GLOM_ON()) {
- prhex("Glom Data", PKTDATA(pkt), len);
+ prhex("Glom Data", pkt->data, len);
}
#endif
- PKTSETLEN(pkt, len);
+ __skb_trim(pkt, len);
ASSERT(doff == SDPCM_HDRLEN);
- PKTPULL(pkt, SDPCM_HDRLEN);
+ skb_pull(pkt, SDPCM_HDRLEN);
bus->glomd = pkt;
} else {
DHD_ERROR(("%s: glom superframe w/o "
@@ -4162,8 +4167,8 @@ deliver:
}
/* Fill in packet len and prio, deliver upward */
- PKTSETLEN(pkt, len);
- PKTPULL(pkt, doff);
+ __skb_trim(pkt, len);
+ skb_pull(pkt, doff);
#ifdef SDTEST
/* Test channel packets are processed separately */
@@ -4173,15 +4178,15 @@ deliver:
}
#endif /* SDTEST */
- if (PKTLEN(pkt) == 0) {
+ if (pkt->len == 0) {
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(bus->dhd->osh, pkt, false);
+ pkt_buf_free_skb(bus->dhd->osh, pkt, false);
dhd_os_sdunlock_rxq(bus->dhd);
continue;
} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
DHD_ERROR(("%s: rx protocol error\n", __func__));
dhd_os_sdlock_rxq(bus->dhd);
- PKTFREE(bus->dhd->osh, pkt, false);
+ pkt_buf_free_skb(bus->dhd->osh, pkt, false);
dhd_os_sdunlock_rxq(bus->dhd);
bus->dhd->rx_errors++;
continue;
@@ -4626,11 +4631,11 @@ static void dhdsdio_pktgen_init(dhd_bus_t *bus)
static void dhdsdio_pktgen(dhd_bus_t *bus)
{
- void *pkt;
+ struct sk_buff *pkt;
u8 *data;
uint pktcount;
uint fillbyte;
- osl_t *osh = bus->dhd->osh;
+ struct osl_info *osh = bus->dhd->osh;
u16 len;
/* Display current count if appropriate */
@@ -4658,16 +4663,16 @@ static void dhdsdio_pktgen(dhd_bus_t *bus)
/* Allocate an appropriate-sized packet */
len = bus->pktgen_len;
- pkt = PKTGET(osh,
+ pkt = pkt_buf_get_skb(osh,
(len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
true);
if (!pkt) {
- DHD_ERROR(("%s: PKTGET failed!\n", __func__));
+ DHD_ERROR(("%s: pkt_buf_get_skb failed!\n", __func__));
break;
}
PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN),
DHD_SDALIGN);
- data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN;
+ data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
/* Write test header cmd and extra based on mode */
switch (bus->pktgen_mode) {
@@ -4689,7 +4694,7 @@ static void dhdsdio_pktgen(dhd_bus_t *bus)
default:
DHD_ERROR(("Unrecognized pktgen mode %d\n",
bus->pktgen_mode));
- PKTFREE(osh, pkt, true);
+ pkt_buf_free_skb(osh, pkt, true);
bus->pktgen_count = 0;
return;
}
@@ -4706,9 +4711,9 @@ static void dhdsdio_pktgen(dhd_bus_t *bus)
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_DATA_ON()) {
- data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN;
+ data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
prhex("dhdsdio_pktgen: Tx Data", data,
- PKTLEN(pkt) - SDPCM_HDRLEN);
+ pkt->len - SDPCM_HDRLEN);
}
#endif
@@ -4733,19 +4738,19 @@ static void dhdsdio_pktgen(dhd_bus_t *bus)
static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start)
{
- void *pkt;
+ struct sk_buff *pkt;
u8 *data;
- osl_t *osh = bus->dhd->osh;
+ struct osl_info *osh = bus->dhd->osh;
/* Allocate the packet */
- pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN,
+ pkt = pkt_buf_get_skb(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN,
true);
if (!pkt) {
- DHD_ERROR(("%s: PKTGET failed!\n", __func__));
+ DHD_ERROR(("%s: pkt_buf_get_skb failed!\n", __func__));
return;
}
PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
- data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN;
+ data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
/* Fill in the test header */
*data++ = SDPCM_TEST_SEND;
@@ -4758,9 +4763,9 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start)
bus->pktgen_fail++;
}
-static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
+static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq)
{
- osl_t *osh = bus->dhd->osh;
+ struct osl_info *osh = bus->dhd->osh;
u8 *data;
uint pktlen;
@@ -4770,16 +4775,16 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
u16 offset;
/* Check for min length */
- pktlen = PKTLEN(pkt);
+ pktlen = pkt->len;
if (pktlen < SDPCM_TEST_HDRLEN) {
DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n",
pktlen));
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
return;
}
/* Extract header fields */
- data = PKTDATA(pkt);
+ data = pkt->data;
cmd = *data++;
extra = *data++;
len = *data++;
@@ -4792,7 +4797,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, "
"pktlen %d seq %d" " cmd %d extra %d len %d\n",
pktlen, seq, cmd, extra, len));
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
return;
}
}
@@ -4802,19 +4807,19 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
case SDPCM_TEST_ECHOREQ:
/* Rx->Tx turnaround ok (even on NDIS w/current
implementation) */
- *(u8 *) (PKTDATA(pkt)) = SDPCM_TEST_ECHORSP;
+ *(u8 *) (pkt->data) = SDPCM_TEST_ECHORSP;
if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true) == 0) {
bus->pktgen_sent++;
} else {
bus->pktgen_fail++;
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
}
bus->pktgen_rcvd++;
break;
case SDPCM_TEST_ECHORSP:
if (bus->ext_loop) {
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
bus->pktgen_rcvd++;
break;
}
@@ -4827,12 +4832,12 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
break;
}
}
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
bus->pktgen_rcvd++;
break;
case SDPCM_TEST_DISCARD:
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
bus->pktgen_rcvd++;
break;
@@ -4842,7 +4847,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, "
"pktlen %d seq %d" " cmd %d extra %d len %d\n",
pktlen, seq, cmd, extra, len));
- PKTFREE(osh, pkt, false);
+ pkt_buf_free_skb(osh, pkt, false);
break;
}
@@ -4960,7 +4965,7 @@ extern int dhd_bus_console_in(dhd_pub_t *dhdp, unsigned char *msg, uint msglen)
dhd_bus_t *bus = dhdp->bus;
u32 addr, val;
int rv;
- void *pkt;
+ struct sk_buff *pkt;
/* Address could be zero if CONSOLE := 0 in dongle Makefile */
if (bus->console_addr == 0)
@@ -5003,7 +5008,7 @@ extern int dhd_bus_console_in(dhd_pub_t *dhdp, unsigned char *msg, uint msglen)
/* Bump dongle by sending an empty event pkt.
* sdpcm_sendup (RX) checks for virtual console input.
*/
- pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, true);
+ pkt = pkt_buf_get_skb(bus->dhd->osh, 4 + SDPCM_RESERVE);
if ((pkt != NULL) && bus->clkstate == CLK_AVAIL)
dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, true);
@@ -5061,7 +5066,7 @@ static bool dhdsdio_chipmatch(u16 chipid)
static void *dhdsdio_probe(u16 venid, u16 devid, u16 bus_no,
u16 slot, u16 func, uint bustype, void *regsva,
- osl_t *osh, void *sdh)
+ struct osl_info *osh, void *sdh)
{
int ret;
dhd_bus_t *bus;
@@ -5220,8 +5225,8 @@ fail:
}
static bool
-dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
- u16 devid)
+dhdsdio_probe_attach(struct dhd_bus *bus, struct osl_info *osh, void *sdh,
+ void *regsva, u16 devid)
{
u8 clkctl = 0;
int err = 0;
@@ -5280,7 +5285,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
"failed\n", fn));
break;
}
- bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
+ memset(cis[fn], 0, SBSDIO_CIS_SIZE_LIMIT);
err = bcmsdh_cis_read(sdh, fn, cis[fn],
SBSDIO_CIS_SIZE_LIMIT);
@@ -5378,7 +5383,8 @@ fail:
return false;
}
-static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
+static bool dhdsdio_probe_malloc(dhd_bus_t *bus, struct osl_info *osh,
+ void *sdh)
{
DHD_TRACE(("%s: Enter\n", __func__));
@@ -5419,7 +5425,7 @@ fail:
return false;
}
-static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
+static bool dhdsdio_probe_init(dhd_bus_t *bus, struct osl_info *osh, void *sdh)
{
s32 fnum;
@@ -5496,7 +5502,7 @@ static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
}
bool
-dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
+dhd_bus_download_firmware(struct dhd_bus *bus, struct osl_info *osh,
char *fw_path, char *nv_path)
{
bool ret;
@@ -5509,7 +5515,7 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
}
static bool
-dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
+dhdsdio_download_firmware(struct dhd_bus *bus, struct osl_info *osh, void *sdh)
{
bool ret;
@@ -5524,7 +5530,7 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
}
/* Detach and free everything */
-static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
+static void dhdsdio_release(dhd_bus_t *bus, struct osl_info *osh)
{
DHD_TRACE(("%s: Enter\n", __func__));
@@ -5554,7 +5560,7 @@ static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
DHD_TRACE(("%s: Disconnected\n", __func__));
}
-static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
+static void dhdsdio_release_malloc(dhd_bus_t *bus, struct osl_info *osh)
{
DHD_TRACE(("%s: Enter\n", __func__));
@@ -5573,7 +5579,7 @@ static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
}
}
-static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh)
+static void dhdsdio_release_dongle(dhd_bus_t *bus, struct osl_info *osh)
{
DHD_TRACE(("%s: Enter\n", __func__));
@@ -5986,7 +5992,7 @@ err:
static int
dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags,
- u8 *buf, uint nbytes, void *pkt,
+ u8 *buf, uint nbytes, struct sk_buff *pkt,
bcmsdh_cmplt_fn_t complete, void *handle)
{
int status;
@@ -6000,7 +6006,7 @@ dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags,
static int
dhd_bcmsdh_send_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags,
- u8 *buf, uint nbytes, void *pkt,
+ u8 *buf, uint nbytes, struct sk_buff *pkt,
bcmsdh_cmplt_fn_t complete, void *handle)
{
return bcmsdh_send_buf
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index 3f29488d9c72..991463f4a7f4 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/if_arp.h>
-#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
@@ -30,10 +29,6 @@
#include <dhdioctl.h>
#include <wlioctl.h>
-#include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-
#include <linux/kthread.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
@@ -95,12 +90,12 @@ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx);
static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params);
static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr);
+ u8 key_idx, bool pairwise, const u8 *mac_addr);
static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
void *cookie, void (*callback) (void *cookie,
struct
key_params *
@@ -342,7 +337,7 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl);
struct wl_iface *ci; \
if (unlikely(!(wl_cfg80211_dev && \
(ci = wl_get_drvdata(wl_cfg80211_dev))))) { \
- WL_ERR(("wl_cfg80211_dev is unavailable\n")); \
+ WL_ERR("wl_cfg80211_dev is unavailable\n"); \
BUG(); \
} \
ci_to_wl(ci); \
@@ -352,8 +347,8 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl);
do { \
struct wl_priv *wl = wiphy_to_wl(wiphy); \
if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \
- WL_INFO(("device is not ready : status (%d)\n", \
- (int)wl->status)); \
+ WL_INFO("device is not ready : status (%d)\n", \
+ (int)wl->status); \
return -EIO; \
} \
} while (0)
@@ -618,8 +613,8 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
- WL_ERR(("type (%d) : currently we do not support this type\n",
- type));
+ WL_ERR("type (%d) : currently we do not support this type\n",
+ type);
return -EOPNOTSUPP;
case NL80211_IFTYPE_ADHOC:
wl->conf->mode = WL_MODE_IBSS;
@@ -635,15 +630,15 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
ap = htod32(ap);
wdev = ndev->ieee80211_ptr;
wdev->iftype = type;
- WL_DBG(("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra));
+ WL_DBG("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra);
err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ WL_ERR("WLC_SET_INFRA error (%d)\n", err);
return err;
}
err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_AP error (%d)\n", err));
+ WL_ERR("WLC_SET_AP error (%d)\n", err);
return err;
}
@@ -653,7 +648,7 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
{
- memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ memcpy(&params->bssid, &ether_bcast, ETH_ALEN);
params->bss_type = DOT11_BSSTYPE_ANY;
params->scan_type = 0;
params->nprobes = -1;
@@ -705,7 +700,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action)
if (ssid && ssid->SSID_len)
params_size += sizeof(struct wlc_ssid);
- params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
+ params = kzalloc(params_size, GFP_KERNEL);
if (unlikely(!params))
return -ENOMEM;
memset(params, 0, params_size);
@@ -722,9 +717,9 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action)
iscan->ioctl_buf, WLC_IOCTL_SMLEN);
if (unlikely(err)) {
if (err == -EBUSY) {
- WL_INFO(("system busy : iscan canceled\n"));
+ WL_INFO("system busy : iscan canceled\n");
} else {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
}
}
kfree(params);
@@ -748,7 +743,7 @@ static s32 wl_do_iscan(struct wl_priv *wl)
err = wl_dev_ioctl(wl_to_ndev(wl), WLC_SET_PASSIVE_SCAN,
&passive_scan, sizeof(passive_scan));
if (unlikely(err)) {
- WL_DBG(("error (%d)\n", err));
+ WL_DBG("error (%d)\n", err);
return err;
}
wl_set_mpc(ndev, 0);
@@ -774,12 +769,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
s32 err = 0;
if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) {
- WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
+ WL_ERR("Scanning already : status (%d)\n", (int)wl->status);
return -EAGAIN;
}
if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) {
- WL_ERR(("Scanning being aborted : status (%d)\n",
- (int)wl->status));
+ WL_ERR("Scanning being aborted : status (%d)\n",
+ (int)wl->status);
return -EAGAIN;
}
@@ -811,26 +806,26 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
else
goto scan_out;
} else {
- WL_DBG(("ssid \"%s\", ssid_len (%d)\n",
- ssids->ssid, ssids->ssid_len));
+ WL_DBG("ssid \"%s\", ssid_len (%d)\n",
+ ssids->ssid, ssids->ssid_len);
memset(&sr->ssid, 0, sizeof(sr->ssid));
sr->ssid.SSID_len =
min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
if (sr->ssid.SSID_len) {
memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
- WL_DBG(("Specific scan ssid=\"%s\" len=%d\n",
- sr->ssid.SSID, sr->ssid.SSID_len));
+ WL_DBG("Specific scan ssid=\"%s\" len=%d\n",
+ sr->ssid.SSID, sr->ssid.SSID_len);
spec_scan = true;
} else {
- WL_DBG(("Broadcast scan\n"));
+ WL_DBG("Broadcast scan\n");
}
- WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
+ WL_DBG("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len);
passive_scan = wl->active_scan ? 0 : 1;
err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
&passive_scan, sizeof(passive_scan));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
+ WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
goto scan_out;
}
wl_set_mpc(ndev, 0);
@@ -838,10 +833,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
sizeof(sr->ssid));
if (err) {
if (err == -EBUSY) {
- WL_INFO(("system busy : scan for \"%s\" "
- "canceled\n", sr->ssid.SSID));
+ WL_INFO("system busy : scan for \"%s\" canceled\n",
+ sr->ssid.SSID);
} else {
- WL_ERR(("WLC_SCAN error (%d)\n", err));
+ WL_ERR("WLC_SCAN error (%d)\n", err);
}
wl_set_mpc(ndev, 1);
goto scan_out;
@@ -865,7 +860,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
CHECK_SYS_UP();
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
- WL_DBG(("scan error (%d)\n", err));
+ WL_DBG("scan error (%d)\n", err);
return err;
}
@@ -884,7 +879,7 @@ static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
}
return err;
@@ -907,7 +902,7 @@ wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
BUG_ON(unlikely(!len));
err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
}
*retval = dtoh32(var.val);
@@ -920,7 +915,7 @@ static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
if (unlikely(err)) {
- WL_ERR(("Error (%d)\n", err));
+ WL_ERR("Error (%d)\n", err);
return err;
}
return err;
@@ -932,7 +927,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
if (unlikely(err)) {
- WL_ERR(("Error (%d)\n", err));
+ WL_ERR("Error (%d)\n", err);
return err;
}
return err;
@@ -946,7 +941,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
retry = htod32(retry);
err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry));
if (unlikely(err)) {
- WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
+ WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
return err;
}
return err;
@@ -1006,7 +1001,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP();
if (params->bssid) {
- WL_ERR(("Invalid bssid\n"));
+ WL_ERR("Invalid bssid\n");
return -EOPNOTSUPP;
}
bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
@@ -1032,7 +1027,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
}
if (bss) {
wl->ibss_starter = false;
- WL_DBG(("Found IBSS\n"));
+ WL_DBG("Found IBSS\n");
} else {
wl->ibss_starter = true;
}
@@ -1049,14 +1044,14 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
join_params.ssid.SSID_len = htod32(params->ssid_len);
if (params->bssid)
memcpy(&join_params.params.bssid, params->bssid,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
else
- memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+ memset(&join_params.params.bssid, 0, ETH_ALEN);
err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params,
sizeof(join_params));
if (unlikely(err)) {
- WL_ERR(("Error (%d)\n", err));
+ WL_ERR("Error (%d)\n", err);
return err;
}
return err;
@@ -1087,10 +1082,10 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
else
val = WPA_AUTH_DISABLED;
- WL_DBG(("setting wpa_auth to 0x%0x\n", val));
+ WL_DBG("setting wpa_auth to 0x%0x\n", val);
err = wl_dev_intvar_set(dev, "wpa_auth", val);
if (unlikely(err)) {
- WL_ERR(("set wpa_auth failed (%d)\n", err));
+ WL_ERR("set wpa_auth failed (%d)\n", err);
return err;
}
sec = wl_read_prof(wl, WL_PROF_SEC);
@@ -1109,27 +1104,27 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
switch (sme->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
val = 0;
- WL_DBG(("open system\n"));
+ WL_DBG("open system\n");
break;
case NL80211_AUTHTYPE_SHARED_KEY:
val = 1;
- WL_DBG(("shared key\n"));
+ WL_DBG("shared key\n");
break;
case NL80211_AUTHTYPE_AUTOMATIC:
val = 2;
- WL_DBG(("automatic\n"));
+ WL_DBG("automatic\n");
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
- WL_DBG(("network eap\n"));
+ WL_DBG("network eap\n");
default:
val = 2;
- WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
+ WL_ERR("invalid auth type (%d)\n", sme->auth_type);
break;
}
err = wl_dev_intvar_set(dev, "auth", val);
if (unlikely(err)) {
- WL_ERR(("set auth failed (%d)\n", err));
+ WL_ERR("set auth failed (%d)\n", err);
return err;
}
sec = wl_read_prof(wl, WL_PROF_SEC);
@@ -1162,8 +1157,8 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
pval = AES_ENABLED;
break;
default:
- WL_ERR(("invalid cipher pairwise (%d)\n",
- sme->crypto.ciphers_pairwise[0]));
+ WL_ERR("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
return -EINVAL;
}
}
@@ -1183,16 +1178,16 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
gval = AES_ENABLED;
break;
default:
- WL_ERR(("invalid cipher group (%d)\n",
- sme->crypto.cipher_group));
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
return -EINVAL;
}
}
- WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
+ WL_DBG("pval (%d) gval (%d)\n", pval, gval);
err = wl_dev_intvar_set(dev, "wsec", pval | gval);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
@@ -1214,7 +1209,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
if (sme->crypto.n_akm_suites) {
err = wl_dev_intvar_get(dev, "wpa_auth", &val);
if (unlikely(err)) {
- WL_ERR(("could not get wpa_auth (%d)\n", err));
+ WL_ERR("could not get wpa_auth (%d)\n", err);
return err;
}
if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
@@ -1226,8 +1221,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
val = WPA_AUTH_PSK;
break;
default:
- WL_ERR(("invalid cipher group (%d)\n",
- sme->crypto.cipher_group));
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
return -EINVAL;
}
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
@@ -1239,16 +1234,16 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
val = WPA2_AUTH_PSK;
break;
default:
- WL_ERR(("invalid cipher group (%d)\n",
- sme->crypto.cipher_group));
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
return -EINVAL;
}
}
- WL_DBG(("setting wpa_auth to %d\n", val));
+ WL_DBG("setting wpa_auth to %d\n", val);
err = wl_dev_intvar_set(dev, "wpa_auth", val);
if (unlikely(err)) {
- WL_ERR(("could not set wpa_auth (%d)\n", err));
+ WL_ERR("could not set wpa_auth (%d)\n", err);
return err;
}
}
@@ -1268,11 +1263,11 @@ wl_set_set_sharedkey(struct net_device *dev,
s32 val;
s32 err = 0;
- WL_DBG(("key len (%d)\n", sme->key_len));
+ WL_DBG("key len (%d)\n", sme->key_len);
if (sme->key_len) {
sec = wl_read_prof(wl, WL_PROF_SEC);
- WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
- sec->wpa_versions, sec->cipher_pairwise));
+ WL_DBG("wpa_versions 0x%x cipher_pairwise 0x%x\n",
+ sec->wpa_versions, sec->cipher_pairwise);
if (!
(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
NL80211_WPA_VERSION_2))
@@ -1282,7 +1277,7 @@ wl_set_set_sharedkey(struct net_device *dev,
key.len = (u32) sme->key_len;
key.index = (u32) sme->key_idx;
if (unlikely(key.len > sizeof(key.data))) {
- WL_ERR(("Too long key length (%u)\n", key.len));
+ WL_ERR("Too long key length (%u)\n", key.len);
return -EINVAL;
}
memcpy(key.data, sme->key, key.len);
@@ -1295,27 +1290,27 @@ wl_set_set_sharedkey(struct net_device *dev,
key.algo = CRYPTO_ALGO_WEP128;
break;
default:
- WL_ERR(("Invalid algorithm (%d)\n",
- sme->crypto.ciphers_pairwise[0]));
+ WL_ERR("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
return -EINVAL;
}
/* Set the new key/index */
- WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
- key.len, key.index, key.algo));
- WL_DBG(("key \"%s\"\n", key.data));
+ WL_DBG("key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo);
+ WL_DBG("key \"%s\"\n", key.data);
swap_key_from_BE(&key);
err = wl_dev_ioctl(dev, WLC_SET_KEY, &key,
sizeof(key));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
}
if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
- WL_DBG(("set auth_type to shared key\n"));
+ WL_DBG("set auth_type to shared key\n");
val = 1; /* shared key */
err = wl_dev_intvar_set(dev, "auth", val);
if (unlikely(err)) {
- WL_ERR(("set auth failed (%d)\n", err));
+ WL_ERR("set auth failed (%d)\n", err);
return err;
}
}
@@ -1337,15 +1332,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP();
if (unlikely(!sme->ssid)) {
- WL_ERR(("Invalid ssid\n"));
+ WL_ERR("Invalid ssid\n");
return -EOPNOTSUPP;
}
if (chan) {
wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
- WL_DBG(("channel (%d), center_req (%d)\n", wl->channel,
- chan->center_freq));
+ WL_DBG("channel (%d), center_req (%d)\n",
+ wl->channel, chan->center_freq);
}
- WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
+ WL_DBG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
err = wl_set_wpa_version(dev, sme);
if (unlikely(err))
return err;
@@ -1378,18 +1373,18 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
- memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
- WL_DBG(("join_param_size %d\n", join_params_size));
+ WL_DBG("join_param_size %d\n", join_params_size);
if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
- WL_DBG(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
- join_params.ssid.SSID_len));
+ WL_DBG("ssid \"%s\", len (%d)\n",
+ join_params.ssid.SSID, join_params.ssid.SSID_len);
}
err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
set_bit(WL_STATUS_CONNECTING, &wl->status);
@@ -1406,17 +1401,17 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
bool act = false;
s32 err = 0;
- WL_DBG(("Reason %d\n", reason_code));
+ WL_DBG("Reason %d\n", reason_code);
CHECK_SYS_UP();
act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
if (likely(act)) {
scbval.val = reason_code;
- memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN);
+ memcpy(&scbval.ea, &wl->bssid, ETH_ALEN);
scbval.val = htod32(scbval.val);
err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t));
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
}
@@ -1441,13 +1436,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
break;
case NL80211_TX_POWER_LIMITED:
if (dbm < 0) {
- WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
+ WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
return -EINVAL;
}
break;
case NL80211_TX_POWER_FIXED:
if (dbm < 0) {
- WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
+ WL_ERR("TX_POWER_FIXED - dbm is negative\n");
return -EINVAL;
}
break;
@@ -1457,7 +1452,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
disable = htod32(disable);
err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
+ WL_ERR("WLC_SET_RADIO error (%d)\n", err);
return err;
}
@@ -1468,7 +1463,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
err = wl_dev_intvar_set(ndev, "qtxpower",
(s32) (bcm_mw_to_qdbm(txpwrmw)));
if (unlikely(err)) {
- WL_ERR(("qtxpower error (%d)\n", err));
+ WL_ERR("qtxpower error (%d)\n", err);
return err;
}
wl->conf->tx_power = dbm;
@@ -1487,7 +1482,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
CHECK_SYS_UP();
err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
@@ -1504,12 +1499,12 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
s32 wsec;
s32 err = 0;
- WL_DBG(("key index (%d)\n", key_idx));
+ WL_DBG("key index (%d)\n", key_idx);
CHECK_SYS_UP();
err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
if (unlikely(err)) {
- WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ WL_ERR("WLC_GET_WSEC error (%d)\n", err);
return err;
}
wsec = dtoh32(wsec);
@@ -1520,7 +1515,7 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
sizeof(index));
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
}
}
return err;
@@ -1537,8 +1532,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
key.index = (u32) key_idx;
/* Instead of bcast for ea address for default wep keys,
driver needs it to be Null */
- if (!ETHER_ISMULTI(mac_addr))
- memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN);
+ if (!is_multicast_ether_addr(mac_addr))
+ memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
key.len = (u32) params->key_len;
/* check for key index change */
if (key.len == 0) {
@@ -1546,16 +1541,16 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
swap_key_from_BE(&key);
err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
if (unlikely(err)) {
- WL_ERR(("key delete error (%d)\n", err));
+ WL_ERR("key delete error (%d)\n", err);
return err;
}
} else {
if (key.len > sizeof(key.data)) {
- WL_ERR(("Invalid key length (%d)\n", key.len));
+ WL_ERR("Invalid key length (%d)\n", key.len);
return -EINVAL;
}
- WL_DBG(("Setting the key index %d\n", key.index));
+ WL_DBG("Setting the key index %d\n", key.index);
memcpy(key.data, params->key, key.len);
if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
@@ -1579,26 +1574,26 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
key.algo = CRYPTO_ALGO_WEP1;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP40\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
key.algo = CRYPTO_ALGO_WEP128;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
key.algo = CRYPTO_ALGO_TKIP;
- WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_TKIP\n");
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
key.algo = CRYPTO_ALGO_AES_CCM;
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n");
break;
case WLAN_CIPHER_SUITE_CCMP:
key.algo = CRYPTO_ALGO_AES_CCM;
- WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_CCMP\n");
break;
default:
- WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
swap_key_from_BE(&key);
@@ -1606,7 +1601,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
dhd_wait_pend8021x(dev);
err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
}
}
@@ -1615,7 +1610,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
static s32
wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct wl_wsec_key key;
@@ -1623,7 +1618,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
s32 wsec;
s32 err = 0;
- WL_DBG(("key index (%d)\n", key_idx));
+ WL_DBG("key index (%d)\n", key_idx);
CHECK_SYS_UP();
if (mac_addr)
@@ -1634,7 +1629,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
key.index = (u32) key_idx;
if (unlikely(key.len > sizeof(key.data))) {
- WL_ERR(("Too long key length (%u)\n", key.len));
+ WL_ERR("Too long key length (%u)\n", key.len);
return -EINVAL;
}
memcpy(key.data, params->key, key.len);
@@ -1643,26 +1638,26 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
key.algo = CRYPTO_ALGO_WEP1;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP40\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
key.algo = CRYPTO_ALGO_WEP128;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
key.algo = CRYPTO_ALGO_TKIP;
- WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_TKIP\n");
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
key.algo = CRYPTO_ALGO_AES_CCM;
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n");
break;
case WLAN_CIPHER_SUITE_CCMP:
key.algo = CRYPTO_ALGO_AES_CCM;
- WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_CCMP\n");
break;
default:
- WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
@@ -1670,21 +1665,21 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
swap_key_from_BE(&key);
err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
}
val = WEP_ENABLED;
err = wl_dev_intvar_get(dev, "wsec", &wsec);
if (unlikely(err)) {
- WL_ERR(("get wsec error (%d)\n", err));
+ WL_ERR("get wsec error (%d)\n", err);
return err;
}
wsec &= ~(WEP_ENABLED);
wsec |= val;
err = wl_dev_intvar_set(dev, "wsec", wsec);
if (unlikely(err)) {
- WL_ERR(("set wsec error (%d)\n", err));
+ WL_ERR("set wsec error (%d)\n", err);
return err;
}
@@ -1692,7 +1687,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
val = htod32(val);
err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
+ WL_ERR("WLC_SET_AUTH error (%d)\n", err);
return err;
}
return err;
@@ -1700,7 +1695,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
static s32
wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr)
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct wl_wsec_key key;
s32 err = 0;
@@ -1714,7 +1709,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
key.flags = WL_PRIMARY_KEY;
key.algo = CRYPTO_ALGO_OFF;
- WL_DBG(("key index (%d)\n", key_idx));
+ WL_DBG("key index (%d)\n", key_idx);
/* Set the new key/index */
swap_key_from_BE(&key);
err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
@@ -1722,10 +1717,10 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
if (err == -EINVAL) {
if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
- WL_DBG(("invalid key index (%d)\n", key_idx));
+ WL_DBG("invalid key index (%d)\n", key_idx);
}
} else {
- WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
}
return err;
}
@@ -1733,14 +1728,14 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
val = 0;
err = wl_dev_intvar_get(dev, "wsec", &wsec);
if (unlikely(err)) {
- WL_ERR(("get wsec error (%d)\n", err));
+ WL_ERR("get wsec error (%d)\n", err);
return err;
}
wsec &= ~(WEP_ENABLED);
wsec |= val;
err = wl_dev_intvar_set(dev, "wsec", wsec);
if (unlikely(err)) {
- WL_ERR(("set wsec error (%d)\n", err));
+ WL_ERR("set wsec error (%d)\n", err);
return err;
}
@@ -1748,7 +1743,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
val = htod32(val);
err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
+ WL_ERR("WLC_SET_AUTH error (%d)\n", err);
return err;
}
return err;
@@ -1756,7 +1751,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
static s32
wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr, void *cookie,
+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback) (void *cookie, struct key_params * params))
{
struct key_params params;
@@ -1766,7 +1761,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
s32 wsec;
s32 err = 0;
- WL_DBG(("key index (%d)\n", key_idx));
+ WL_DBG("key index (%d)\n", key_idx);
CHECK_SYS_UP();
memset(&key, 0, sizeof(key));
@@ -1778,7 +1773,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
if (unlikely(err)) {
- WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ WL_ERR("WLC_GET_WSEC error (%d)\n", err);
return err;
}
wsec = dtoh32(wsec);
@@ -1787,22 +1782,22 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
sec = wl_read_prof(wl, WL_PROF_SEC);
if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
params.cipher = WLAN_CIPHER_SUITE_WEP40;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP40\n");
} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
params.cipher = WLAN_CIPHER_SUITE_WEP104;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_WEP104\n");
}
break;
case TKIP_ENABLED:
params.cipher = WLAN_CIPHER_SUITE_TKIP;
- WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_TKIP\n");
break;
case AES_ENABLED:
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n");
break;
default:
- WL_ERR(("Invalid algo (0x%x)\n", wsec));
+ WL_ERR("Invalid algo (0x%x)\n", wsec);
return -EINVAL;
}
@@ -1814,7 +1809,7 @@ static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *dev, u8 key_idx)
{
- WL_INFO(("Not supported\n"));
+ WL_INFO("Not supported\n");
CHECK_SYS_UP();
return -EOPNOTSUPP;
}
@@ -1831,20 +1826,20 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP();
if (unlikely
- (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) {
- WL_ERR(("Wrong Mac address\n"));
+ (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN))) {
+ WL_ERR("Wrong Mac address\n");
return -ENOENT;
}
/* Report the current tx rate */
err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
if (err) {
- WL_ERR(("Could not get rate (%d)\n", err));
+ WL_ERR("Could not get rate (%d)\n", err);
} else {
rate = dtoh32(rate);
sinfo->filled |= STATION_INFO_TX_BITRATE;
sinfo->txrate.legacy = rate * 5;
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+ WL_DBG("Rate %d Mbps\n", rate / 2);
}
if (test_bit(WL_STATUS_CONNECTED, &wl->status)) {
@@ -1852,13 +1847,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val,
sizeof(scb_val_t));
if (unlikely(err)) {
- WL_ERR(("Could not get rssi (%d)\n", err));
+ WL_ERR("Could not get rssi (%d)\n", err);
return err;
}
rssi = dtoh32(scb_val.val);
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = rssi;
- WL_DBG(("RSSI %d dBm\n", rssi));
+ WL_DBG("RSSI %d dBm\n", rssi);
}
return err;
@@ -1874,13 +1869,13 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP();
pm = enabled ? PM_FAST : PM_OFF;
pm = htod32(pm);
- WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
+ WL_DBG("power save %s\n", (pm ? "enabled" : "disabled"));
err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
if (unlikely(err)) {
if (err == -ENODEV)
- WL_DBG(("net_device is not ready yet\n"));
+ WL_DBG("net_device is not ready yet\n");
else
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
return err;
@@ -1932,7 +1927,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
sizeof(rateset));
if (unlikely(err)) {
- WL_ERR(("could not get current rateset (%d)\n", err));
+ WL_ERR("could not get current rateset (%d)\n", err);
return err;
}
@@ -1952,7 +1947,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
rate = val / 500000;
}
- WL_DBG(("rate %d mbps\n", (rate / 2)));
+ WL_DBG("rate %d mbps\n", rate / 2);
/*
*
@@ -1962,7 +1957,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
err_a = wl_dev_intvar_set(dev, "a_rate", rate);
if (unlikely(err_bg && err_a)) {
- WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a));
+ WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
return err_bg | err_a;
}
@@ -2007,12 +2002,12 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
{
int i, j;
- WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
+ WL_DBG("No of elements %d\n", pmk_list->pmkids.npmkid);
for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
- WL_DBG(("PMKID[%d]: %pM =\n", i,
- &pmk_list->pmkids.pmkid[i].BSSID));
+ WL_DBG("PMKID[%d]: %pM =\n", i,
+ &pmk_list->pmkids.pmkid[i].BSSID);
for (j = 0; j < WPA2_PMKID_LEN; j++) {
- WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
+ WL_DBG("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
}
}
if (likely(!err)) {
@@ -2034,11 +2029,11 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
CHECK_SYS_UP();
for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
- ETHER_ADDR_LEN))
+ ETH_ALEN))
break;
if (i < WL_NUM_PMKIDS_MAX) {
memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
WPA2_PMKID_LEN);
if (i == wl->pmk_list->pmkids.npmkid)
@@ -2046,12 +2041,12 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
} else {
err = -EINVAL;
}
- WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
- &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID));
+ WL_DBG("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
+ &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID);
for (i = 0; i < WPA2_PMKID_LEN; i++) {
- WL_DBG(("%02x\n",
- wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].
- PMKID[i]));
+ WL_DBG("%02x\n",
+ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].
+ PMKID[i]);
}
err = wl_update_pmklist(dev, wl->pmk_list, err);
@@ -2069,19 +2064,19 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
int i;
CHECK_SYS_UP();
- memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
- WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
- &pmkid.pmkid[0].BSSID));
+ WL_DBG("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
+ &pmkid.pmkid[0].BSSID);
for (i = 0; i < WPA2_PMKID_LEN; i++) {
- WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
+ WL_DBG("%02x\n", pmkid.pmkid[0].PMKID[i]);
}
for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
if (!memcmp
(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
- ETHER_ADDR_LEN))
+ ETH_ALEN))
break;
if ((wl->pmk_list->pmkids.npmkid > 0)
@@ -2090,7 +2085,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) {
memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID,
&wl->pmk_list->pmkids.pmkid[i + 1].BSSID,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID,
&wl->pmk_list->pmkids.pmkid[i + 1].PMKID,
WPA2_PMKID_LEN);
@@ -2168,13 +2163,13 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
if (unlikely(!wdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
+ WL_ERR("Could not allocate wireless device\n");
return ERR_PTR(-ENOMEM);
}
wdev->wiphy =
wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface);
if (unlikely(!wdev->wiphy)) {
- WL_ERR(("Couldn not allocate wiphy device\n"));
+ WL_ERR("Couldn not allocate wiphy device\n");
err = -ENOMEM;
goto wiphy_new_out;
}
@@ -2204,7 +2199,7 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
#endif /* !WL_POWERSAVE_DISABLED */
err = wiphy_register(wdev->wiphy);
if (unlikely(err < 0)) {
- WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+ WL_ERR("Couldn not register wiphy device (%d)\n", err);
goto wiphy_register_out;
}
return wdev;
@@ -2223,7 +2218,7 @@ static void wl_free_wdev(struct wl_priv *wl)
struct wireless_dev *wdev = wl_to_wdev(wl);
if (unlikely(!wdev)) {
- WL_ERR(("wdev is invalid\n"));
+ WL_ERR("wdev is invalid\n");
return;
}
wiphy_unregister(wdev->wiphy);
@@ -2241,11 +2236,11 @@ static s32 wl_inform_bss(struct wl_priv *wl)
bss_list = wl->bss_list;
if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
- WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n",
- bss_list->version));
+ WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
+ bss_list->version);
return -EOPNOTSUPP;
}
- WL_DBG(("scanned AP count (%d)\n", bss_list->count));
+ WL_DBG("scanned AP count (%d)\n", bss_list->count);
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
err = wl_inform_single_bss(wl, bi);
@@ -2270,14 +2265,14 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
s32 err = 0;
if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
- WL_DBG(("Beacon is larger than buffer. Discarding\n"));
+ WL_DBG("Beacon is larger than buffer. Discarding\n");
return err;
}
notif_bss_info =
kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
WL_BSS_INFO_MAX, GFP_KERNEL);
if (unlikely(!notif_bss_info)) {
- WL_ERR(("notif_bss_info alloc failed\n"));
+ WL_ERR("notif_bss_info alloc failed\n");
return -ENOMEM;
}
mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
@@ -2289,7 +2284,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
notif_bss_info->rssi = bi->RSSI;
- memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
+ memcpy(mgmt->bssid, &bi->BSSID, ETH_ALEN);
mgmt_type = wl->active_scan ?
IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
@@ -2321,17 +2316,17 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
channel = ieee80211_get_channel(wiphy, freq);
- WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n",
- bi->SSID,
- notif_bss_info->rssi, notif_bss_info->channel,
- mgmt->u.beacon.capab_info, &bi->BSSID));
+ WL_DBG("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n",
+ bi->SSID,
+ notif_bss_info->rssi, notif_bss_info->channel,
+ mgmt->u.beacon.capab_info, &bi->BSSID);
signal = notif_bss_info->rssi * 100;
if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
le16_to_cpu
(notif_bss_info->frame_len),
signal, GFP_KERNEL))) {
- WL_ERR(("cfg80211_inform_bss_frame error\n"));
+ WL_ERR("cfg80211_inform_bss_frame error\n");
kfree(notif_bss_info);
return -EINVAL;
}
@@ -2399,12 +2394,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
if (wl_is_ibssmode(wl)) {
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
- WL_DBG(("joined in IBSS network\n"));
+ WL_DBG("joined in IBSS network\n");
} else {
wl_bss_connect_done(wl, ndev, e, data, true);
- WL_DBG(("joined in BSS network \"%s\"\n",
- ((struct wlc_ssid *)
- wl_read_prof(wl, WL_PROF_SSID))->SSID));
+ WL_DBG("joined in BSS network \"%s\"\n",
+ ((struct wlc_ssid *)
+ wl_read_prof(wl, WL_PROF_SSID))->SSID);
}
act = true;
wl_update_prof(wl, e, &act, WL_PROF_ACT);
@@ -2459,7 +2454,7 @@ wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
WL_IOCTL_LEN_MAX);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
memcpy(buf, wl->ioctl_buf, buf_len);
@@ -2479,7 +2474,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
WL_ASSOC_INFO_MAX);
if (unlikely(err)) {
- WL_ERR(("could not get assoc info (%d)\n", err));
+ WL_ERR("could not get assoc info (%d)\n", err);
return err;
}
assoc_info = (struct wl_assoc_ielen *)wl->extra_buf;
@@ -2489,7 +2484,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
WL_ASSOC_INFO_MAX);
if (unlikely(err)) {
- WL_ERR(("could not get assoc req (%d)\n", err));
+ WL_ERR("could not get assoc req (%d)\n", err);
return err;
}
conn_info->req_ie_len = req_len;
@@ -2503,7 +2498,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
WL_ASSOC_INFO_MAX);
if (unlikely(err)) {
- WL_ERR(("could not get assoc resp (%d)\n", err));
+ WL_ERR("could not get assoc resp (%d)\n", err);
return err;
}
conn_info->resp_ie_len = resp_len;
@@ -2513,8 +2508,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
conn_info->resp_ie_len = 0;
conn_info->resp_ie = NULL;
}
- WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
- conn_info->resp_ie_len));
+ WL_DBG("req len (%d) resp len (%d)\n",
+ conn_info->req_ie_len, conn_info->resp_ie_len);
return err;
}
@@ -2547,8 +2542,8 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
join_params->params.chanspec_num =
htod32(join_params->params.chanspec_num);
- WL_DBG(("join_params->params.chanspec_list[0]= %#X, channel %d, chanspec %#X\n",
- join_params->params.chanspec_list[0], ch, chanspec));
+ WL_DBG("join_params->params.chanspec_list[0]= %#X, channel %d, chanspec %#X\n",
+ join_params->params.chanspec_list[0], ch, chanspec);
}
}
@@ -2575,16 +2570,16 @@ static s32 wl_update_bss_info(struct wl_priv *wl)
rtnl_lock();
if (unlikely(!bss)) {
- WL_DBG(("Could not find the AP\n"));
+ WL_DBG("Could not find the AP\n");
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
wl->extra_buf, WL_EXTRA_BUF_MAX);
if (unlikely(err)) {
- WL_ERR(("Could not get bss info %d\n", err));
+ WL_ERR("Could not get bss info %d\n", err);
goto update_bss_info_out;
}
bi = (struct wl_bss_info *)(wl->extra_buf + 4);
- if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN))) {
+ if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETH_ALEN))) {
err = -EIO;
goto update_bss_info_out;
}
@@ -2596,7 +2591,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl)
ie_len = bi->ie_length;
beacon_interval = cpu_to_le16(bi->beacon_period);
} else {
- WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
+ WL_DBG("Found the AP in the list - BSSID %pM\n", bss->bssid);
ie = bss->information_elements;
ie_len = bss->len_information_elements;
beacon_interval = bss->beacon_interval;
@@ -2615,7 +2610,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl)
err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_DTIMPRD,
&dtim_period, sizeof(dtim_period));
if (unlikely(err)) {
- WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
+ WL_ERR("WLC_GET_DTIMPRD error (%d)\n", err);
goto update_bss_info_out;
}
}
@@ -2636,13 +2631,13 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
s32 err = 0;
wl_get_assoc_ies(wl);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ memcpy(&wl->bssid, &e->addr, ETH_ALEN);
wl_update_bss_info(wl);
cfg80211_roamed(ndev,
(u8 *)&wl->bssid,
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
- WL_DBG(("Report roaming result\n"));
+ WL_DBG("Report roaming result\n");
set_bit(WL_STATUS_CONNECTED, &wl->status);
@@ -2657,7 +2652,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
s32 err = 0;
wl_get_assoc_ies(wl);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ memcpy(&wl->bssid, &e->addr, ETH_ALEN);
wl_update_bss_info(wl);
if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
cfg80211_connect_result(ndev,
@@ -2668,15 +2663,15 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
conn_info->resp_ie_len,
completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
GFP_KERNEL);
- WL_DBG(("Report connect result - connection %s\n",
- completed ? "succeeded" : "failed"));
+ WL_DBG("Report connect result - connection %s\n",
+ completed ? "succeeded" : "failed");
} else {
cfg80211_roamed(ndev,
(u8 *)&wl->bssid,
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len,
GFP_KERNEL);
- WL_DBG(("Report roaming result\n"));
+ WL_DBG("Report roaming result\n");
}
set_bit(WL_STATUS_CONNECTED, &wl->status);
@@ -2716,7 +2711,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
return wl_wakeup_iscan(wl_to_iscan(wl));
if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
- WL_ERR(("Scan complete while device not scanning\n"));
+ WL_ERR("Scan complete while device not scanning\n");
return -EINVAL;
}
if (unlikely(!wl->scan_request)) {
@@ -2725,14 +2720,14 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform));
if (unlikely(err)) {
- WL_ERR(("scan busy (%d)\n", err));
+ WL_ERR("scan busy (%d)\n", err);
goto scan_done_out;
}
channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
if (unlikely(channel_inform.scan_channel)) {
- WL_DBG(("channel_inform.scan_channel (%d)\n",
- channel_inform.scan_channel));
+ WL_DBG("channel_inform.scan_channel (%d)\n",
+ channel_inform.scan_channel);
}
wl->bss_list = wl->scan_results;
bss_list = wl->bss_list;
@@ -2740,7 +2735,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
bss_list->buflen = htod32(len);
err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len);
if (unlikely(err)) {
- WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
+ WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
err = -EINVAL;
goto scan_done_out;
}
@@ -2794,55 +2789,54 @@ static void wl_init_eloop_handler(struct wl_event_loop *el)
static s32 wl_init_priv_mem(struct wl_priv *wl)
{
- wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+ wl->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
if (unlikely(!wl->scan_results)) {
- WL_ERR(("Scan results alloc failed\n"));
+ WL_ERR("Scan results alloc failed\n");
goto init_priv_mem_out;
}
- wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL);
+ wl->conf = kzalloc(sizeof(*wl->conf), GFP_KERNEL);
if (unlikely(!wl->conf)) {
- WL_ERR(("wl_conf alloc failed\n"));
+ WL_ERR("wl_conf alloc failed\n");
goto init_priv_mem_out;
}
- wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
+ wl->profile = kzalloc(sizeof(*wl->profile), GFP_KERNEL);
if (unlikely(!wl->profile)) {
- WL_ERR(("wl_profile alloc failed\n"));
+ WL_ERR("wl_profile alloc failed\n");
goto init_priv_mem_out;
}
- wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ wl->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
if (unlikely(!wl->bss_info)) {
- WL_ERR(("Bss information alloc failed\n"));
+ WL_ERR("Bss information alloc failed\n");
goto init_priv_mem_out;
}
- wl->scan_req_int =
- (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
+ wl->scan_req_int = kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
if (unlikely(!wl->scan_req_int)) {
- WL_ERR(("Scan req alloc failed\n"));
+ WL_ERR("Scan req alloc failed\n");
goto init_priv_mem_out;
}
- wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ wl->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
if (unlikely(!wl->ioctl_buf)) {
- WL_ERR(("Ioctl buf alloc failed\n"));
+ WL_ERR("Ioctl buf alloc failed\n");
goto init_priv_mem_out;
}
- wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ wl->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
if (unlikely(!wl->extra_buf)) {
- WL_ERR(("Extra buf alloc failed\n"));
+ WL_ERR("Extra buf alloc failed\n");
goto init_priv_mem_out;
}
- wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
+ wl->iscan = kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
if (unlikely(!wl->iscan)) {
- WL_ERR(("Iscan buf alloc failed\n"));
+ WL_ERR("Iscan buf alloc failed\n");
goto init_priv_mem_out;
}
- wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
+ wl->fw = kzalloc(sizeof(*wl->fw), GFP_KERNEL);
if (unlikely(!wl->fw)) {
- WL_ERR(("fw object alloc failed\n"));
+ WL_ERR("fw object alloc failed\n");
goto init_priv_mem_out;
}
- wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
+ wl->pmk_list = kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
if (unlikely(!wl->pmk_list)) {
- WL_ERR(("pmk list alloc failed\n"));
+ WL_ERR("pmk list alloc failed\n");
goto init_priv_mem_out;
}
@@ -2884,7 +2878,7 @@ static s32 wl_create_event_handler(struct wl_priv *wl)
wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler");
if (IS_ERR(wl->event_tsk)) {
wl->event_tsk = NULL;
- WL_ERR(("failed to create event thread\n"));
+ WL_ERR("failed to create event thread\n");
return -ENOMEM;
}
return 0;
@@ -2917,7 +2911,7 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
struct net_device *ndev = wl_to_ndev(wl);
if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
- WL_ERR(("Scan complete while device not scanning\n"));
+ WL_ERR("Scan complete while device not scanning\n");
return;
}
if (likely(wl->scan_request)) {
@@ -2931,7 +2925,7 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan)
{
if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
- WL_DBG(("wake up iscan\n"));
+ WL_DBG("wake up iscan\n");
up(&iscan->sync);
return 0;
}
@@ -2961,14 +2955,14 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
WL_ISCAN_BUF_MAX);
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
results->buflen = dtoh32(results->buflen);
results->version = dtoh32(results->version);
results->count = dtoh32(results->count);
- WL_DBG(("results->count = %d\n", results->count));
- WL_DBG(("results->buflen = %d\n", results->buflen));
+ WL_DBG("results->count = %d\n", results->count);
+ WL_DBG("results->buflen = %d\n", results->buflen);
*status = dtoh32(list_buf->status);
*bss_list = results;
@@ -3053,7 +3047,7 @@ static s32 wl_iscan_thread(void *data)
err = wl_get_iscan_results(iscan, &status, &wl->bss_list);
if (unlikely(err)) {
status = WL_SCAN_RESULTS_ABORTED;
- WL_ERR(("Abort iscan\n"));
+ WL_ERR("Abort iscan\n");
}
rtnl_unlock();
el->handler[status] (wl);
@@ -3062,7 +3056,7 @@ static s32 wl_iscan_thread(void *data)
del_timer_sync(&iscan->timer);
iscan->timer_on = 0;
}
- WL_DBG(("%s was terminated\n", __func__));
+ WL_DBG("%s was terminated\n", __func__);
return 0;
}
@@ -3073,7 +3067,7 @@ static void wl_iscan_timer(unsigned long data)
if (iscan) {
iscan->timer_on = 0;
- WL_DBG(("timer expired\n"));
+ WL_DBG("timer expired\n");
wl_wakeup_iscan(iscan);
}
}
@@ -3088,7 +3082,7 @@ static s32 wl_invoke_iscan(struct wl_priv *wl)
sema_init(&iscan->sync, 0);
iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
if (IS_ERR(iscan->tsk)) {
- WL_ERR(("Could not create iscan thread\n"));
+ WL_ERR("Could not create iscan thread\n");
iscan->tsk = NULL;
return -ENOMEM;
}
@@ -3123,7 +3117,7 @@ static s32 wl_init_iscan(struct wl_priv *wl)
sema_init(&iscan->sync, 0);
iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
if (IS_ERR(iscan->tsk)) {
- WL_ERR(("Could not create iscan thread\n"));
+ WL_ERR("Could not create iscan thread\n");
iscan->tsk = NULL;
return -ENOMEM;
}
@@ -3192,17 +3186,17 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
s32 err = 0;
if (unlikely(!ndev)) {
- WL_ERR(("ndev is invaild\n"));
+ WL_ERR("ndev is invalid\n");
return -ENODEV;
}
wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL);
if (unlikely(!wl_cfg80211_dev)) {
- WL_ERR(("wl_cfg80211_dev is invalid\n"));
+ WL_ERR("wl_cfg80211_dev is invalid\n");
return -ENOMEM;
}
- WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
+ WL_DBG("func %p\n", wl_cfg80211_get_sdio_func());
wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev);
- if (unlikely(IS_ERR(wdev)))
+ if (IS_ERR(wdev))
return -ENOMEM;
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
@@ -3216,7 +3210,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
wdev->netdev = ndev;
err = wl_init_priv(wl);
if (unlikely(err)) {
- WL_ERR(("Failed to init iwm_priv (%d)\n", err));
+ WL_ERR("Failed to init iwm_priv (%d)\n", err);
goto cfg80211_attach_out;
}
wl_set_drvdata(wl_cfg80211_dev, ci);
@@ -3261,19 +3255,19 @@ static s32 wl_event_handler(void *data)
break;
e = wl_deq_event(wl);
if (unlikely(!e)) {
- WL_ERR(("eqeue empty..\n"));
+ WL_ERR("event queue empty...\n");
BUG();
}
- WL_DBG(("event type (%d)\n", e->etype));
+ WL_DBG("event type (%d)\n", e->etype);
if (wl->el.handler[e->etype]) {
wl->el.handler[e->etype] (wl, wl_to_ndev(wl), &e->emsg,
e->edata);
} else {
- WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
+ WL_DBG("Unknown Event (%d): ignoring\n", e->etype);
}
wl_put_event(e);
}
- WL_DBG(("%s was terminated\n", __func__));
+ WL_DBG("%s was terminated\n", __func__);
return 0;
}
@@ -3286,7 +3280,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
wl_dbg_estr[event_type] : (s8 *) "Unknown";
#endif /* (WL_DBG_LEVEL > 0) */
- WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
+ WL_DBG("event_type (%d):" "WLC_E_" "%s\n", event_type, estr);
if (likely(!wl_enq_event(wl, event_type, e, data)))
wl_wakeup_event(wl);
}
@@ -3341,7 +3335,7 @@ wl_enq_event(struct wl_priv *wl, u32 event, const wl_event_msg_t *msg,
e = kzalloc(sizeof(struct wl_event_q), GFP_KERNEL);
if (unlikely(!e)) {
- WL_ERR(("event alloc failed\n"));
+ WL_ERR("event alloc failed\n");
return -ENOMEM;
}
@@ -3385,8 +3379,8 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
switch (iftype) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
- WL_ERR(("type (%d) : currently we do not support this mode\n",
- iftype));
+ WL_ERR("type (%d) : currently we do not support this mode\n",
+ iftype);
err = -EINVAL;
return err;
case NL80211_IFTYPE_ADHOC:
@@ -3396,20 +3390,20 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
break;
default:
err = -EINVAL;
- WL_ERR(("invalid type (%d)\n", iftype));
+ WL_ERR("invalid type (%d)\n", iftype);
return err;
}
infra = htod32(infra);
ap = htod32(ap);
- WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra));
+ WL_DBG("%s ap (%d), infra (%d)\n", ndev->name, ap, infra);
err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ WL_ERR("WLC_SET_INFRA error (%d)\n", err);
return err;
}
err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_AP error (%d)\n", err));
+ WL_ERR("WLC_SET_AP error (%d)\n", err);
return err;
}
@@ -3431,7 +3425,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up)
err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up));
if (unlikely(err)) {
- WL_ERR(("WLC_UP error (%d)\n", err));
+ WL_ERR("WLC_UP error (%d)\n", err);
}
return err;
}
@@ -3442,7 +3436,7 @@ static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode));
if (unlikely(err)) {
- WL_ERR(("WLC_SET_PM error (%d)\n", err));
+ WL_ERR("WLC_SET_PM error (%d)\n", err);
}
return err;
}
@@ -3459,14 +3453,14 @@ wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("txglomalign error (%d)\n", err));
+ WL_ERR("txglomalign error (%d)\n", err);
goto dongle_glom_out;
}
/* disable glom option per default */
bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("txglom error (%d)\n", err));
+ WL_ERR("txglom error (%d)\n", err);
goto dongle_glom_out;
}
dongle_glom_out:
@@ -3487,7 +3481,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("bcn_timeout error (%d)\n", err));
+ WL_ERR("bcn_timeout error (%d)\n", err);
goto dongle_rom_out;
}
}
@@ -3496,7 +3490,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("roam_off error (%d)\n", err));
+ WL_ERR("roam_off error (%d)\n", err);
goto dongle_rom_out;
}
dongle_rom_out:
@@ -3516,7 +3510,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev)
sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("Get event_msgs error (%d)\n", err));
+ WL_ERR("Get event_msgs error (%d)\n", err);
goto dongle_eventmsg_out;
}
memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
@@ -3544,7 +3538,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev)
sizeof(iovbuf));
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (unlikely(err)) {
- WL_ERR(("Set event_msgs error (%d)\n", err));
+ WL_ERR("Set event_msgs error (%d)\n", err);
goto dongle_eventmsg_out;
}
@@ -3562,9 +3556,9 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
sizeof(scan_assoc_time));
if (err) {
if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan assoc time is not supported\n"));
+ WL_INFO("Scan assoc time is not supported\n");
} else {
- WL_ERR(("Scan assoc time error (%d)\n", err));
+ WL_ERR("Scan assoc time error (%d)\n", err);
}
goto dongle_scantime_out;
}
@@ -3572,9 +3566,9 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
sizeof(scan_unassoc_time));
if (err) {
if (err == -EOPNOTSUPP) {
- WL_INFO(("Scan unassoc time is not supported\n"));
+ WL_INFO("Scan unassoc time is not supported\n");
} else {
- WL_ERR(("Scan unassoc time error (%d)\n", err));
+ WL_ERR("Scan unassoc time error (%d)\n", err);
}
goto dongle_scantime_out;
}
@@ -3595,9 +3589,9 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (err) {
if (err == -EOPNOTSUPP)
- WL_INFO(("arpoe is not supported\n"));
+ WL_INFO("arpoe is not supported\n");
else
- WL_ERR(("arpoe error (%d)\n", err));
+ WL_ERR("arpoe error (%d)\n", err);
goto dongle_offload_out;
}
@@ -3605,9 +3599,9 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (err) {
if (err == -EOPNOTSUPP)
- WL_INFO(("arp_ol is not supported\n"));
+ WL_INFO("arp_ol is not supported\n");
else
- WL_ERR(("arp_ol error (%d)\n", err));
+ WL_ERR("arp_ol error (%d)\n", err);
goto dongle_offload_out;
}
@@ -3620,12 +3614,12 @@ static s32 wl_pattern_atoh(s8 *src, s8 *dst)
{
int i;
if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
- WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
+ WL_ERR("Mask invalid format. Needs to start with 0x\n");
return -1;
}
src = src + 2; /* Skip past 0x */
if (strlen(src) % 2 != 0) {
- WL_ERR(("Mask invalid format. Needs to be of even length\n"));
+ WL_ERR("Mask invalid format. Needs to be of even length\n");
return -1;
}
for (i = 0; *src != '\0'; i++) {
@@ -3684,7 +3678,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
mask_and_pattern[mask_size]));
if (mask_size != pattern_size) {
- WL_ERR(("Mask and pattern not the same size\n"));
+ WL_ERR("Mask and pattern not the same size\n");
err = -EINVAL;
goto dongle_filter_out;
}
@@ -3704,9 +3698,9 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len);
if (err) {
if (err == -EOPNOTSUPP) {
- WL_INFO(("filter not supported\n"));
+ WL_INFO("filter not supported\n");
} else {
- WL_ERR(("filter (%d)\n", err));
+ WL_ERR("filter (%d)\n", err);
}
goto dongle_filter_out;
}
@@ -3717,9 +3711,9 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
if (err) {
if (err == -EOPNOTSUPP) {
- WL_INFO(("filter_mode not supported\n"));
+ WL_INFO("filter_mode not supported\n");
} else {
- WL_ERR(("filter_mode (%d)\n", err));
+ WL_ERR("filter_mode (%d)\n", err);
}
goto dongle_filter_out;
}
@@ -3800,12 +3794,12 @@ static s32 wl_update_wiphybands(struct wl_priv *wl)
err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_PHYLIST, &phy_list,
sizeof(phy_list));
if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
+ WL_ERR("error (%d)\n", err);
return err;
}
phy = ((char *)&phy_list)[1];
- WL_DBG(("%c phy\n", phy));
+ WL_DBG("%c phy\n", phy);
if (phy == 'n' || phy == 'a') {
wiphy = wl_to_wiphy(wl);
wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
@@ -3911,7 +3905,7 @@ static void *wl_read_prof(struct wl_priv *wl, s32 item)
case WL_PROF_SSID:
return &wl->profile->ssid;
}
- WL_ERR(("invalid item (%d)\n", item));
+ WL_ERR("invalid item (%d)\n", item);
return NULL;
}
@@ -3932,9 +3926,9 @@ wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
break;
case WL_PROF_BSSID:
if (data)
- memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
+ memcpy(wl->profile->bssid, data, ETH_ALEN);
else
- memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
+ memset(wl->profile->bssid, 0, ETH_ALEN);
break;
case WL_PROF_SEC:
memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
@@ -3949,7 +3943,7 @@ wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
wl->profile->dtim_period = *(u8 *)data;
break;
default:
- WL_ERR(("unsupported item (%d)\n", item));
+ WL_ERR("unsupported item (%d)\n", item);
err = -EOPNOTSUPP;
break;
}
@@ -3991,7 +3985,7 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
s32 err = 0;
if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
- WL_ERR(("ei crosses buffer boundary\n"));
+ WL_ERR("ei crosses buffer boundary\n");
return -ENOSPC;
}
ie->buf[ie->offset] = t;
@@ -4008,7 +4002,7 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size)
s32 err = 0;
if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
- WL_ERR(("ei_stream crosses buffer boundary\n"));
+ WL_ERR("ei_stream crosses buffer boundary\n");
return -ENOSPC;
}
memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
@@ -4023,7 +4017,7 @@ static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size)
s32 err = 0;
if (unlikely(ie->offset > dst_size)) {
- WL_ERR(("dst_size is not enough\n"));
+ WL_ERR("dst_size is not enough\n");
return -ENOSPC;
}
memcpy(dst, &ie->buf[0], ie->offset);
@@ -4123,37 +4117,37 @@ void *wl_cfg80211_request_fw(s8 *file_name)
const struct firmware *fw_entry = NULL;
s32 err = 0;
- WL_DBG(("file name : \"%s\"\n", file_name));
+ WL_DBG("file name : \"%s\"\n", file_name);
wl = WL_PRIV_GET();
if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
err = request_firmware(&wl->fw->fw_entry, file_name,
&wl_cfg80211_get_sdio_func()->dev);
if (unlikely(err)) {
- WL_ERR(("Could not download fw (%d)\n", err));
+ WL_ERR("Could not download fw (%d)\n", err);
goto req_fw_out;
}
set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
fw_entry = wl->fw->fw_entry;
if (fw_entry) {
- WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
+ WL_DBG("fw size (%zd), data (%p)\n",
+ fw_entry->size, fw_entry->data);
}
} else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
err = request_firmware(&wl->fw->fw_entry, file_name,
&wl_cfg80211_get_sdio_func()->dev);
if (unlikely(err)) {
- WL_ERR(("Could not download nvram (%d)\n", err));
+ WL_ERR("Could not download nvram (%d)\n", err);
goto req_fw_out;
}
set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
fw_entry = wl->fw->fw_entry;
if (fw_entry) {
- WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
- fw_entry->data));
+ WL_DBG("nvram size (%zd), data (%p)\n",
+ fw_entry->size, fw_entry->data);
}
} else {
- WL_DBG(("Downloading already done. Nothing to do more\n"));
+ WL_DBG("Downloading already done. Nothing to do more\n");
err = -EPERM;
}
@@ -4189,10 +4183,10 @@ static void wl_set_mpc(struct net_device *ndev, int mpc)
err = wl_dev_intvar_set(ndev, "mpc", mpc);
if (unlikely(err)) {
- WL_ERR(("fail to set mpc\n"));
+ WL_ERR("fail to set mpc\n");
return;
}
- WL_DBG(("MPC : %d\n", mpc));
+ WL_DBG("MPC : %d\n", mpc);
}
static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
index 770e63f0c8ef..482691be210a 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
@@ -54,34 +54,36 @@ struct wl_ibss;
#define WL_DBG_LEVEL 1 /* 0 invalidates all debug messages.
default is 1 */
-#define WL_ERR(args) \
-do { \
- if (wl_dbg_level & WL_DBG_ERR) { \
- if (net_ratelimit()) { \
- printk(KERN_ERR "ERROR @%s : ", __func__); \
- printk args; \
- } \
- } \
+#define WL_ERR(fmt, args...) \
+do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "ERROR @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
} while (0)
-#define WL_INFO(args) \
-do { \
- if (wl_dbg_level & WL_DBG_INFO) { \
- if (net_ratelimit()) { \
- printk(KERN_ERR "INFO @%s : ", __func__); \
- printk args; \
- } \
- } \
+
+#define WL_INFO(fmt, args...) \
+do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "INFO @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
} while (0)
+
#if (WL_DBG_LEVEL > 0)
-#define WL_DBG(args) \
-do { \
+#define WL_DBG(fmt, args...) \
+do { \
if (wl_dbg_level & WL_DBG_DBG) { \
- printk(KERN_ERR "DEBUG @%s :", __func__); \
- printk args; \
- } \
+ printk(KERN_ERR "DEBUG @%s :" fmt, \
+ __func__, ##args); \
+ } \
} while (0)
#else /* !(WL_DBG_LEVEL > 0) */
-#define WL_DBG(args)
+#define WL_DBG(fmt, args...) noprintk(fmt, ##args)
#endif /* (WL_DBG_LEVEL > 0) */
#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
@@ -237,7 +239,7 @@ struct wl_ibss {
struct wl_profile {
u32 mode;
struct wlc_ssid ssid;
- u8 bssid[ETHER_ADDR_LEN];
+ u8 bssid[ETH_ALEN];
u16 beacon_interval;
u8 dtim_period;
struct wl_security sec;
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c
index 979a494fda59..db6e68eab290 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c
@@ -15,8 +15,9 @@
*/
#include <linux/kthread.h>
+#include <linux/semaphore.h>
#include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/netdevice.h>
#include <osl.h>
#include <wlioctl.h>
@@ -31,20 +32,18 @@
#include <dhd.h>
#include <dhdioctl.h>
-typedef void wlc_info_t;
-typedef void wl_info_t;
typedef const struct si_pub si_t;
#include <wlioctl.h>
#include <proto/ethernet.h>
#include <dngl_stats.h>
#include <dhd.h>
-#define WL_ERROR(x) printf x
-#define WL_TRACE(x)
-#define WL_ASSOC(x)
-#define WL_INFORM(x)
-#define WL_WSEC(x)
-#define WL_SCAN(x)
+
+#define WL_ERROR(fmt, args...) printk(fmt, ##args)
+#define WL_TRACE(fmt, args...) no_printk(fmt, ##args)
+#define WL_INFORM(fmt, args...) no_printk(fmt, ##args)
+#define WL_WSEC(fmt, args...) no_printk(fmt, ##args)
+#define WL_SCAN(fmt, args...) no_printk(fmt, ##args)
#include <wl_iw.h>
@@ -187,12 +186,12 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
int ret = -EINVAL;
if (!dev) {
- WL_ERROR(("%s: dev is null\n", __func__));
+ WL_ERROR("%s: dev is null\n", __func__);
return ret;
}
- WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, "
- "len:%d ,\n", __func__, current->pid, cmd, arg, len));
+ WL_INFORM("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d\n",
+ __func__, current->pid, cmd, arg, len);
if (g_onoff == G_WLAN_SET_ON) {
memset(&ioc, 0, sizeof(ioc));
@@ -205,7 +204,7 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
ret = dev_open(dev);
if (ret) {
- WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
+ WL_ERROR("%s: Error dev_open: %d\n", __func__, ret);
return ret;
}
@@ -214,7 +213,7 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
set_fs(fs);
} else {
- WL_TRACE(("%s: call after driver stop : ignored\n", __func__));
+ WL_TRACE("%s: call after driver stop : ignored\n", __func__);
}
return ret;
}
@@ -335,7 +334,7 @@ wl_iw_config_commit(struct net_device *dev,
int error;
struct sockaddr bssid;
- WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
+ WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
if (error)
@@ -346,11 +345,11 @@ wl_iw_config_commit(struct net_device *dev,
if (!ssid.SSID_len)
return 0;
- bzero(&bssid, sizeof(struct sockaddr));
- error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN);
+ memset(&bssid, 0, sizeof(struct sockaddr));
+ error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN);
if (error) {
- WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __func__,
- ssid.SSID));
+ WL_ERROR("%s: WLC_REASSOC to %s failed\n",
+ __func__, ssid.SSID);
return error;
}
@@ -361,7 +360,7 @@ static int
wl_iw_get_name(struct net_device *dev,
struct iw_request_info *info, char *cwrq, char *extra)
{
- WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
+ WL_TRACE("%s: SIOCGIWNAME\n", dev->name);
strcpy(cwrq, "IEEE 802.11-DS");
@@ -375,7 +374,7 @@ wl_iw_set_freq(struct net_device *dev,
int error, chan;
uint sf = 0;
- WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name));
+ WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name);
if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
chan = fwrq->m;
@@ -410,7 +409,7 @@ wl_iw_get_freq(struct net_device *dev,
channel_info_t ci;
int error;
- WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
+ WL_TRACE("%s: SIOCGIWFREQ\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
if (error)
@@ -427,7 +426,7 @@ wl_iw_set_mode(struct net_device *dev,
{
int infra = 0, ap = 0, error = 0;
- WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
+ WL_TRACE("%s: SIOCSIWMODE\n", dev->name);
switch (*uwrq) {
case IW_MODE_MASTER:
@@ -462,7 +461,7 @@ wl_iw_get_mode(struct net_device *dev,
{
int error, infra = 0, ap = 0;
- WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
+ WL_TRACE("%s: SIOCGIWMODE\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra));
if (error)
@@ -501,14 +500,14 @@ wl_iw_get_range(struct net_device *dev,
{30, 60, 90, 120, 180, 240, 270, 300}
};
- WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
+ WL_TRACE("%s: SIOCGIWRANGE\n", dev->name);
if (!extra)
return -EINVAL;
channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL);
if (!channels) {
- WL_ERROR(("Could not alloc channels\n"));
+ WL_ERROR("Could not alloc channels\n");
return -ENOMEM;
}
list = (wl_u32_list_t *) channels;
@@ -684,14 +683,14 @@ wl_iw_set_spy(struct net_device *dev,
struct sockaddr *addr = (struct sockaddr *)extra;
int i;
- WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
+ WL_TRACE("%s: SIOCSIWSPY\n", dev->name);
if (!extra)
return -EINVAL;
iw->spy_num = min_t(int, ARRAY_SIZE(iw->spy_addr), dwrq->length);
for (i = 0; i < iw->spy_num; i++)
- memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
+ memcpy(&iw->spy_addr[i], addr[i].sa_data, ETH_ALEN);
memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
return 0;
@@ -706,14 +705,14 @@ wl_iw_get_spy(struct net_device *dev,
struct iw_quality *qual = (struct iw_quality *)&addr[iw->spy_num];
int i;
- WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
+ WL_TRACE("%s: SIOCGIWSPY\n", dev->name);
if (!extra)
return -EINVAL;
dwrq->length = iw->spy_num;
for (i = 0; i < iw->spy_num; i++) {
- memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
+ memcpy(addr[i].sa_data, &iw->spy_addr[i], ETH_ALEN);
addr[i].sa_family = AF_UNIX;
memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
iw->spy_qual[i].updated = 0;
@@ -751,8 +750,8 @@ wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params,
join_params->params.chanspec_num =
htod32(join_params->params.chanspec_num);
- WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n",
- __func__, join_params->params.chanspec_list[0]));
+ WL_TRACE("%s join_params->params.chanspec_list[0]= %X\n",
+ __func__, join_params->params.chanspec_list[0]);
}
return 1;
}
@@ -765,16 +764,17 @@ wl_iw_set_wap(struct net_device *dev,
wl_join_params_t join_params;
int join_params_size;
- WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
+ WL_TRACE("%s: SIOCSIWAP\n", dev->name);
if (awrq->sa_family != ARPHRD_ETHER) {
- WL_ERROR(("Invalid Header...sa_family\n"));
+ WL_ERROR("Invalid Header...sa_family\n");
return -EINVAL;
}
- if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
+ if (is_broadcast_ether_addr(awrq->sa_data) ||
+ is_zero_ether_addr(awrq->sa_data)) {
scb_val_t scbval;
- bzero(&scbval, sizeof(scb_val_t));
+ memset(&scbval, 0, sizeof(scb_val_t));
(void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t));
return 0;
@@ -785,23 +785,23 @@ wl_iw_set_wap(struct net_device *dev,
memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
- memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
+ memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN);
- WL_TRACE(("%s target_channel=%d\n", __func__,
- g_wl_iw_params.target_channel));
+ WL_TRACE("%s target_channel=%d\n",
+ __func__, g_wl_iw_params.target_channel);
wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
&join_params_size);
error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
join_params_size);
if (error) {
- WL_ERROR(("%s Invalid ioctl data=%d\n", __func__, error));
+ WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error);
}
if (g_ssid.SSID_len) {
- WL_TRACE(("%s: join SSID=%s BSSID=%pM ch=%d\n",
- __func__, g_ssid.SSID, awrq->sa_data,
- g_wl_iw_params.target_channel));
+ WL_TRACE("%s: join SSID=%s BSSID=%pM ch=%d\n",
+ __func__, g_ssid.SSID, awrq->sa_data,
+ g_wl_iw_params.target_channel);
}
memset(&g_ssid, 0, sizeof(g_ssid));
@@ -812,12 +812,12 @@ static int
wl_iw_get_wap(struct net_device *dev,
struct iw_request_info *info, struct sockaddr *awrq, char *extra)
{
- WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
+ WL_TRACE("%s: SIOCGIWAP\n", dev->name);
awrq->sa_family = ARPHRD_ETHER;
- memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
+ memset(awrq->sa_data, 0, ETH_ALEN);
- (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
+ (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN);
return 0;
}
@@ -831,16 +831,16 @@ wl_iw_mlme(struct net_device *dev,
scb_val_t scbval;
int error = -EINVAL;
- WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
+ WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name);
mlme = (struct iw_mlme *)extra;
if (mlme == NULL) {
- WL_ERROR(("Invalid ioctl data.\n"));
+ WL_ERROR("Invalid ioctl data\n");
return error;
}
scbval.val = mlme->reason_code;
- bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
+ bcopy(&mlme->addr.sa_data, &scbval.ea, ETH_ALEN);
if (mlme->cmd == IW_MLME_DISASSOC) {
scbval.val = htod32(scbval.val);
@@ -853,7 +853,7 @@ wl_iw_mlme(struct net_device *dev,
dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
&scbval, sizeof(scb_val_t));
} else {
- WL_ERROR(("Invalid ioctl data.\n"));
+ WL_ERROR("Invalid ioctl data\n");
return error;
}
@@ -874,7 +874,7 @@ wl_iw_get_aplist(struct net_device *dev,
int error, i;
uint buflen = dwrq->length;
- WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
+ WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
if (!extra)
return -EINVAL;
@@ -886,7 +886,7 @@ wl_iw_get_aplist(struct net_device *dev,
list->buflen = htod32(buflen);
error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen);
if (error) {
- WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
+ WL_ERROR("%d: Scan results error %d\n", __LINE__, error);
kfree(list);
return error;
}
@@ -894,8 +894,8 @@ wl_iw_get_aplist(struct net_device *dev,
list->version = dtoh32(list->version);
list->count = dtoh32(list->count);
if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
- __func__, list->version));
+ WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
+ __func__, list->version);
kfree(list);
return -EINVAL;
}
@@ -911,7 +911,7 @@ wl_iw_get_aplist(struct net_device *dev,
if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
continue;
- memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETH_ALEN);
addr[dwrq->length].sa_family = ARPHRD_ETHER;
qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
@@ -952,13 +952,13 @@ wl_iw_iscan_get_aplist(struct net_device *dev,
wl_bss_info_t *bi = NULL;
int i;
- WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
+ WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
if (!extra)
return -EINVAL;
if ((!iscan) || (!iscan->sysioc_tsk)) {
- WL_ERROR(("%s error\n", __func__));
+ WL_ERROR("%s error\n", __func__);
return 0;
}
@@ -966,9 +966,8 @@ wl_iw_iscan_get_aplist(struct net_device *dev,
while (buf) {
list = &((wl_iscan_results_t *) buf->iscan_buf)->results;
if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("%s : list->version %d != "
- "WL_BSS_INFO_VERSION\n",
- __func__, list->version));
+ WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
+ __func__, list->version);
return -EINVAL;
}
@@ -985,7 +984,7 @@ wl_iw_iscan_get_aplist(struct net_device *dev,
continue;
memcpy(addr[dwrq->length].sa_data, &bi->BSSID,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
addr[dwrq->length].sa_family = ARPHRD_ETHER;
qual[dwrq->length].qual =
rssi_to_qual(dtoh16(bi->RSSI));
@@ -1016,7 +1015,7 @@ static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
{
int err = 0;
- memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ memcpy(&params->bssid, &ether_bcast, ETH_ALEN);
params->bss_type = DOT11_BSSTYPE_ANY;
params->scan_type = 0;
params->nprobes = -1;
@@ -1043,15 +1042,15 @@ static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action)
iscan->iscan_ex_params_p->action = htod16(action);
iscan->iscan_ex_params_p->scan_duration = htod16(0);
- WL_SCAN(("%s : nprobes=%d\n", __func__,
- iscan->iscan_ex_params_p->params.nprobes));
- WL_SCAN(("active_time=%d\n",
- iscan->iscan_ex_params_p->params.active_time));
- WL_SCAN(("passive_time=%d\n",
- iscan->iscan_ex_params_p->params.passive_time));
- WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
- WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
- WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
+ WL_SCAN("%s : nprobes=%d\n",
+ __func__, iscan->iscan_ex_params_p->params.nprobes);
+ WL_SCAN("active_time=%d\n",
+ iscan->iscan_ex_params_p->params.active_time);
+ WL_SCAN("passive_time=%d\n",
+ iscan->iscan_ex_params_p->params.passive_time);
+ WL_SCAN("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time);
+ WL_SCAN("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type);
+ WL_SCAN("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type);
(void)dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
iscan->iscan_ex_param_size, iscan->ioctlbuf,
@@ -1066,7 +1065,7 @@ static void wl_iw_timerfunc(unsigned long data)
if (iscan) {
iscan->timer_on = 0;
if (iscan->iscan_state != ISCAN_STATE_IDLE) {
- WL_TRACE(("timer trigger\n"));
+ WL_TRACE("timer trigger\n");
up(&iscan->sysioc_sem);
}
}
@@ -1101,8 +1100,8 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan)
} else {
buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
if (!buf) {
- WL_ERROR(("%s can't alloc iscan_buf_t : going to abort "
- "currect iscan\n", __func__));
+ WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n",
+ __func__);
MUTEX_UNLOCK_WL_SCAN_SET();
return WL_SCAN_RESULTS_NO_MEM;
}
@@ -1135,11 +1134,11 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan)
results->buflen = dtoh32(results->buflen);
results->version = dtoh32(results->version);
results->count = dtoh32(results->count);
- WL_TRACE(("results->count = %d\n", results->count));
- WL_TRACE(("results->buflen = %d\n", results->buflen));
+ WL_TRACE("results->count = %d\n", results->count);
+ WL_TRACE("results->buflen = %d\n", results->buflen);
status = dtoh32(list_buf->status);
} else {
- WL_ERROR(("%s returns error %d\n", __func__, res));
+ WL_ERROR("%s returns error %d\n", __func__, res);
status = WL_SCAN_RESULTS_NO_MEM;
}
MUTEX_UNLOCK_WL_SCAN_SET();
@@ -1148,8 +1147,8 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan)
static void wl_iw_force_specific_scan(iscan_info_t *iscan)
{
- WL_TRACE(("%s force Specific SCAN for %s\n", __func__,
- g_specific_ssid.SSID));
+ WL_TRACE("%s force Specific SCAN for %s\n",
+ __func__, g_specific_ssid.SSID);
rtnl_lock();
(void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid,
@@ -1166,7 +1165,7 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan)
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
- WL_TRACE(("Send Event ISCAN complete\n"));
+ WL_TRACE("Send Event ISCAN complete\n");
#endif
}
@@ -1190,8 +1189,8 @@ static int _iscan_sysioc_thread(void *data)
status = wl_iw_iscan_get(iscan);
rtnl_unlock();
if (g_scan_specified_ssid && (iscan_pass_abort == true)) {
- WL_TRACE(("%s Get results from specific scan "
- "status = %d\n", __func__, status));
+ WL_TRACE("%s Get results from specific scan status = %d\n",
+ __func__, status);
wl_iw_send_scan_complete(iscan);
iscan_pass_abort = false;
status = -1;
@@ -1199,7 +1198,7 @@ static int _iscan_sysioc_thread(void *data)
switch (status) {
case WL_SCAN_RESULTS_PARTIAL:
- WL_TRACE(("iscanresults incomplete\n"));
+ WL_TRACE("iscanresults incomplete\n");
rtnl_lock();
wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
rtnl_unlock();
@@ -1208,18 +1207,18 @@ static int _iscan_sysioc_thread(void *data)
iscan->timer_on = 1;
break;
case WL_SCAN_RESULTS_SUCCESS:
- WL_TRACE(("iscanresults complete\n"));
+ WL_TRACE("iscanresults complete\n");
iscan->iscan_state = ISCAN_STATE_IDLE;
wl_iw_send_scan_complete(iscan);
break;
case WL_SCAN_RESULTS_PENDING:
- WL_TRACE(("iscanresults pending\n"));
+ WL_TRACE("iscanresults pending\n");
mod_timer(&iscan->timer,
jiffies + iscan->timer_ms * HZ / 1000);
iscan->timer_on = 1;
break;
case WL_SCAN_RESULTS_ABORTED:
- WL_TRACE(("iscanresults aborted\n"));
+ WL_TRACE("iscanresults aborted\n");
iscan->iscan_state = ISCAN_STATE_IDLE;
if (g_scan_specified_ssid == 0)
wl_iw_send_scan_complete(iscan);
@@ -1229,12 +1228,12 @@ static int _iscan_sysioc_thread(void *data)
}
break;
case WL_SCAN_RESULTS_NO_MEM:
- WL_TRACE(("iscanresults can't alloc memory: skip\n"));
+ WL_TRACE("iscanresults can't alloc memory: skip\n");
iscan->iscan_state = ISCAN_STATE_IDLE;
break;
default:
- WL_TRACE(("iscanresults returned unknown status %d\n",
- status));
+ WL_TRACE("iscanresults returned unknown status %d\n",
+ status);
break;
}
}
@@ -1253,11 +1252,11 @@ wl_iw_set_scan(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
int error;
- WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name));
+ WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name);
g_set_essid_before_scan = false;
#if defined(CSCAN)
- WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__));
+ WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
return -EINVAL;
#endif
@@ -1274,9 +1273,8 @@ wl_iw_set_scan(struct net_device *dev,
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
struct iw_scan_req *req = (struct iw_scan_req *)extra;
if (g_scan_specified_ssid) {
- WL_TRACE(("%s Specific SCAN is not done ignore "
- "scan for = %s\n",
- __func__, req->essid));
+ WL_TRACE("%s Specific SCAN is not done ignore scan for = %s\n",
+ __func__, req->essid);
return -EBUSY;
} else {
g_specific_ssid.SSID_len = min_t(size_t,
@@ -1287,9 +1285,9 @@ wl_iw_set_scan(struct net_device *dev,
g_specific_ssid.SSID_len =
htod32(g_specific_ssid.SSID_len);
g_scan_specified_ssid = 1;
- WL_TRACE(("### Specific scan ssid=%s len=%d\n",
- g_specific_ssid.SSID,
- g_specific_ssid.SSID_len));
+ WL_TRACE("### Specific scan ssid=%s len=%d\n",
+ g_specific_ssid.SSID,
+ g_specific_ssid.SSID_len);
}
}
}
@@ -1297,8 +1295,8 @@ wl_iw_set_scan(struct net_device *dev,
error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid,
sizeof(g_specific_ssid));
if (error) {
- WL_TRACE(("#### Set SCAN for %s failed with %d\n",
- g_specific_ssid.SSID, error));
+ WL_TRACE("#### Set SCAN for %s failed with %d\n",
+ g_specific_ssid.SSID, error);
g_scan_specified_ssid = 0;
return -EBUSY;
}
@@ -1317,7 +1315,7 @@ int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
wl_iw_set_event_mask(dev);
- WL_TRACE(("+++: Set Broadcast ISCAN\n"));
+ WL_TRACE("+++: Set Broadcast ISCAN\n");
memset(&ssid, 0, sizeof(ssid));
iscan->list_cur = iscan->list_hdr;
@@ -1346,20 +1344,20 @@ wl_iw_iscan_set_scan(struct net_device *dev,
wlc_ssid_t ssid;
iscan_info_t *iscan = g_iscan;
- WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
+ WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name);
#if defined(CSCAN)
- WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__));
+ WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
return -EINVAL;
#endif
if (g_onoff == G_WLAN_SET_OFF) {
- WL_TRACE(("%s: driver is not up yet after START\n", __func__));
+ WL_TRACE("%s: driver is not up yet after START\n", __func__);
return 0;
}
#ifdef PNO_SUPPORT
if (dhd_dev_get_pno_status(dev)) {
- WL_ERROR(("%s: Scan called when PNO is active\n", __func__));
+ WL_ERROR("%s: Scan called when PNO is active\n", __func__);
}
#endif
@@ -1367,8 +1365,8 @@ wl_iw_iscan_set_scan(struct net_device *dev,
return wl_iw_set_scan(dev, info, wrqu, extra);
if (g_scan_specified_ssid) {
- WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
- __func__));
+ WL_TRACE("%s Specific SCAN already running ignoring BC scan\n",
+ __func__);
return EBUSY;
}
@@ -1386,8 +1384,8 @@ wl_iw_iscan_set_scan(struct net_device *dev,
g_scan_specified_ssid = 0;
if (iscan->iscan_state == ISCAN_STATE_SCANING) {
- WL_TRACE(("%s ISCAN already in progress \n",
- __func__));
+ WL_TRACE("%s ISCAN already in progress\n",
+ __func__);
return 0;
}
}
@@ -1406,7 +1404,7 @@ static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len)
u8 *ie = *wpaie;
if ((ie[1] >= 6) &&
- !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
+ !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
return true;
}
@@ -1422,7 +1420,7 @@ static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len)
u8 *ie = *wpsie;
if ((ie[1] >= 4) &&
- !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
+ !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
return true;
}
@@ -1501,9 +1499,8 @@ wl_iw_get_scan_prep(wl_scan_results_t *list,
for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("%s : list->version %d != "
- "WL_BSS_INFO_VERSION\n",
- __func__, list->version));
+ WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
+ __func__, list->version);
return ret;
}
@@ -1511,11 +1508,11 @@ wl_iw_get_scan_prep(wl_scan_results_t *list,
dtoh32(bi->length)) : list->
bss_info;
- WL_TRACE(("%s : %s\n", __func__, bi->SSID));
+ WL_TRACE("%s : %s\n", __func__, bi->SSID);
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETH_ALEN);
event =
IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
IW_EV_ADDR_LEN);
@@ -1590,11 +1587,11 @@ wl_iw_get_scan_prep(wl_scan_results_t *list,
ret = event - extra;
if (ret < 0) {
- WL_ERROR(("==> Wrong size\n"));
+ WL_ERROR("==> Wrong size\n");
ret = 0;
}
- WL_TRACE(("%s: size=%d bytes prepared\n", __func__,
- (unsigned int)(event - extra)));
+ WL_TRACE("%s: size=%d bytes prepared\n",
+ __func__, (unsigned int)(event - extra));
return (uint)ret;
}
@@ -1614,10 +1611,10 @@ wl_iw_get_scan(struct net_device *dev,
iscan_buf_t *p_buf;
#endif
- WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
+ WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user);
if (!extra) {
- WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
+ WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name);
return -EINVAL;
}
@@ -1631,8 +1628,8 @@ wl_iw_get_scan(struct net_device *dev,
if (g_scan_specified_ssid) {
list = kmalloc(len, GFP_KERNEL);
if (!list) {
- WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n",
- dev->name));
+ WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n",
+ dev->name);
g_scan_specified_ssid = 0;
return -ENOMEM;
}
@@ -1642,8 +1639,8 @@ wl_iw_get_scan(struct net_device *dev,
list->buflen = htod32(len);
error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len);
if (error) {
- WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name,
- __func__, error));
+ WL_ERROR("%s: %s : Scan_results ERROR %d\n",
+ dev->name, __func__, error);
dwrq->length = len;
if (g_scan_specified_ssid) {
g_scan_specified_ssid = 0;
@@ -1656,8 +1653,8 @@ wl_iw_get_scan(struct net_device *dev,
list->count = dtoh32(list->count);
if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
- __func__, list->version));
+ WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
+ __func__, list->version);
if (g_scan_specified_ssid) {
g_scan_specified_ssid = 0;
kfree(list);
@@ -1666,8 +1663,8 @@ wl_iw_get_scan(struct net_device *dev,
}
if (g_scan_specified_ssid) {
- WL_TRACE(("%s: Specified scan APs in the list =%d\n",
- __func__, list->count));
+ WL_TRACE("%s: Specified scan APs in the list =%d\n",
+ __func__, list->count);
len_ret =
(__u16) wl_iw_get_scan_prep(list, info, extra,
buflen_from_user);
@@ -1678,8 +1675,8 @@ wl_iw_get_scan(struct net_device *dev,
while (p_buf != iscan->list_cur) {
list_merge =
&((wl_iscan_results_t *) p_buf->iscan_buf)->results;
- WL_TRACE(("%s: Bcast APs list=%d\n", __func__,
- list_merge->count));
+ WL_TRACE("%s: Bcast APs list=%d\n",
+ __func__, list_merge->count);
if (list_merge->count > 0)
len_ret +=
(__u16) wl_iw_get_scan_prep(list_merge,
@@ -1689,8 +1686,8 @@ wl_iw_get_scan(struct net_device *dev,
}
#else
list_merge = (wl_scan_results_t *) g_scan;
- WL_TRACE(("%s: Bcast APs list=%d\n", __func__,
- list_merge->count));
+ WL_TRACE("%s: Bcast APs list=%d\n",
+ __func__, list_merge->count);
if (list_merge->count > 0)
len_ret +=
(__u16) wl_iw_get_scan_prep(list_merge, info,
@@ -1714,8 +1711,8 @@ wl_iw_get_scan(struct net_device *dev,
dwrq->length = len;
dwrq->flags = 0;
- WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__,
- dwrq->length, list->count));
+ WL_TRACE("%s return to WE %d bytes APs=%d\n",
+ __func__, dwrq->length, list->count);
return 0;
}
@@ -1736,26 +1733,26 @@ wl_iw_iscan_get_scan(struct net_device *dev,
u32 counter = 0;
u8 channel;
- WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __func__,
- dwrq->length));
+ WL_TRACE("%s %s buflen_from_user %d:\n",
+ dev->name, __func__, dwrq->length);
if (!extra) {
- WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
- dev->name));
+ WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
+ dev->name);
return -EINVAL;
}
if ((!iscan) || (!iscan->sysioc_tsk)) {
- WL_ERROR(("%ssysioc_tsk\n", __func__));
+ WL_ERROR("%ssysioc_tsk\n", __func__);
return wl_iw_get_scan(dev, info, dwrq, extra);
}
if (iscan->iscan_state == ISCAN_STATE_SCANING) {
- WL_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev->name));
+ WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name);
return -EAGAIN;
}
- WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
+ WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name);
apcnt = 0;
p_buf = iscan->list_hdr;
while (p_buf != iscan->list_cur) {
@@ -1764,9 +1761,8 @@ wl_iw_iscan_get_scan(struct net_device *dev,
counter += list->count;
if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("%s : list->version %d != "
- "WL_BSS_INFO_VERSION\n",
- __func__, list->version));
+ WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
+ __func__, list->version);
return -EINVAL;
}
@@ -1779,14 +1775,14 @@ wl_iw_iscan_get_scan(struct net_device *dev,
ASSERT(((unsigned long)bi + dtoh32(bi->length)) <=
((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
- if (event + ETHER_ADDR_LEN + bi->SSID_len +
+ if (event + ETH_ALEN + bi->SSID_len +
IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >=
end)
return -E2BIG;
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
event =
IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
IW_EV_ADDR_LEN);
@@ -1876,8 +1872,8 @@ wl_iw_iscan_get_scan(struct net_device *dev,
dwrq->length = event - extra;
dwrq->flags = 0;
- WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__,
- dwrq->length, counter));
+ WL_TRACE("%s return to WE %d bytes APs=%d\n",
+ __func__, dwrq->length, counter);
if (!dwrq->length)
return -EAGAIN;
@@ -1895,7 +1891,7 @@ wl_iw_set_essid(struct net_device *dev,
wl_join_params_t join_params;
int join_params_size;
- WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
+ WL_TRACE("%s: SIOCSIWESSID\n", dev->name);
if (g_set_essid_before_scan)
return -EAGAIN;
@@ -1923,7 +1919,7 @@ wl_iw_set_essid(struct net_device *dev,
memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
- memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
&join_params_size);
@@ -1931,11 +1927,11 @@ wl_iw_set_essid(struct net_device *dev,
error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
join_params_size);
if (error)
- WL_ERROR(("Invalid ioctl data=%d\n", error));
+ WL_ERROR("Invalid ioctl data=%d\n", error);
if (g_ssid.SSID_len) {
- WL_TRACE(("%s: join SSID=%s ch=%d\n", __func__,
- g_ssid.SSID, g_wl_iw_params.target_channel));
+ WL_TRACE("%s: join SSID=%s ch=%d\n",
+ __func__, g_ssid.SSID, g_wl_iw_params.target_channel);
}
return 0;
}
@@ -1948,14 +1944,14 @@ wl_iw_get_essid(struct net_device *dev,
wlc_ssid_t ssid;
int error;
- WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
+ WL_TRACE("%s: SIOCGIWESSID\n", dev->name);
if (!extra)
return -EINVAL;
error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
if (error) {
- WL_ERROR(("Error getting the SSID\n"));
+ WL_ERROR("Error getting the SSID\n");
return error;
}
@@ -1976,7 +1972,7 @@ wl_iw_set_nick(struct net_device *dev,
{
wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
- WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
+ WL_TRACE("%s: SIOCSIWNICKN\n", dev->name);
if (!extra)
return -EINVAL;
@@ -1996,7 +1992,7 @@ wl_iw_get_nick(struct net_device *dev,
{
wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
- WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
+ WL_TRACE("%s: SIOCGIWNICKN\n", dev->name);
if (!extra)
return -EINVAL;
@@ -2014,7 +2010,7 @@ wl_iw_set_rate(struct net_device *dev,
wl_rateset_t rateset;
int error, rate, i, error_bg, error_a;
- WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
+ WL_TRACE("%s: SIOCSIWRATE\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
sizeof(rateset));
@@ -2063,7 +2059,7 @@ wl_iw_get_rate(struct net_device *dev,
{
int error, rate;
- WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
+ WL_TRACE("%s: SIOCGIWRATE\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
if (error)
@@ -2080,7 +2076,7 @@ wl_iw_set_rts(struct net_device *dev,
{
int error, rts;
- WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
+ WL_TRACE("%s: SIOCSIWRTS\n", dev->name);
if (vwrq->disabled)
rts = DOT11_DEFAULT_RTS_LEN;
@@ -2102,7 +2098,7 @@ wl_iw_get_rts(struct net_device *dev,
{
int error, rts;
- WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
+ WL_TRACE("%s: SIOCGIWRTS\n", dev->name);
error = dev_wlc_intvar_get(dev, "rtsthresh", &rts);
if (error)
@@ -2121,7 +2117,7 @@ wl_iw_set_frag(struct net_device *dev,
{
int error, frag;
- WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
+ WL_TRACE("%s: SIOCSIWFRAG\n", dev->name);
if (vwrq->disabled)
frag = DOT11_DEFAULT_FRAG_LEN;
@@ -2143,7 +2139,7 @@ wl_iw_get_frag(struct net_device *dev,
{
int error, fragthreshold;
- WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
+ WL_TRACE("%s: SIOCGIWFRAG\n", dev->name);
error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold);
if (error)
@@ -2163,7 +2159,7 @@ wl_iw_set_txpow(struct net_device *dev,
{
int error, disable;
u16 txpwrmw;
- WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
+ WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name);
disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
disable += WL_RADIO_SW_DISABLE << 16;
@@ -2200,7 +2196,7 @@ wl_iw_get_txpow(struct net_device *dev,
int error, disable, txpwrdbm;
u8 result;
- WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
+ WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable));
if (error)
@@ -2229,7 +2225,7 @@ wl_iw_set_retry(struct net_device *dev,
{
int error, lrl, srl;
- WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
+ WL_TRACE("%s: SIOCSIWRETRY\n", dev->name);
if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
return -EINVAL;
@@ -2277,7 +2273,7 @@ wl_iw_get_retry(struct net_device *dev,
{
int error, lrl, srl;
- WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
+ WL_TRACE("%s: SIOCGIWRETRY\n", dev->name);
vwrq->disabled = 0;
@@ -2317,7 +2313,7 @@ wl_iw_set_encode(struct net_device *dev,
wl_wsec_key_t key;
int error, val, wsec;
- WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
+ WL_TRACE("%s: SIOCSIWENCODE\n", dev->name);
memset(&key, 0, sizeof(key));
@@ -2409,9 +2405,9 @@ wl_iw_get_encode(struct net_device *dev,
wl_wsec_key_t key;
int error, val, wsec, auth;
- WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
+ WL_TRACE("%s: SIOCGIWENCODE\n", dev->name);
- bzero(&key, sizeof(wl_wsec_key_t));
+ memset(&key, 0, sizeof(wl_wsec_key_t));
if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
@@ -2465,7 +2461,7 @@ wl_iw_set_power(struct net_device *dev,
{
int error, pm;
- WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
+ WL_TRACE("%s: SIOCSIWPOWER\n", dev->name);
pm = vwrq->disabled ? PM_OFF : PM_MAX;
@@ -2484,7 +2480,7 @@ wl_iw_get_power(struct net_device *dev,
{
int error, pm;
- WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
+ WL_TRACE("%s: SIOCGIWPOWER\n", dev->name);
error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
if (error)
@@ -2503,7 +2499,7 @@ wl_iw_set_wpaie(struct net_device *dev,
struct iw_request_info *info, struct iw_point *iwp, char *extra)
{
- WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
+ WL_TRACE("%s: SIOCSIWGENIE\n", dev->name);
CHECK_EXTRA_FOR_NULL(extra);
@@ -2516,7 +2512,7 @@ static int
wl_iw_get_wpaie(struct net_device *dev,
struct iw_request_info *info, struct iw_point *iwp, char *extra)
{
- WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
+ WL_TRACE("%s: SIOCGIWGENIE\n", dev->name);
iwp->length = 64;
dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
return 0;
@@ -2531,7 +2527,7 @@ wl_iw_set_encodeext(struct net_device *dev,
int error;
struct iw_encode_ext *iwe;
- WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
+ WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name);
CHECK_EXTRA_FOR_NULL(extra);
@@ -2548,14 +2544,14 @@ wl_iw_set_encodeext(struct net_device *dev,
key.len = iwe->key_len;
- if (!ETHER_ISMULTI(iwe->addr.sa_data))
+ if (!is_multicast_ether_addr(iwe->addr.sa_data))
bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
if (key.len == 0) {
if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- WL_WSEC(("Changing the the primary Key to %d\n",
- key.index));
+ WL_WSEC("Changing the the primary Key to %d\n",
+ key.index);
key.index = htod32(key.index);
error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
&key.index, sizeof(key.index));
@@ -2569,9 +2565,9 @@ wl_iw_set_encodeext(struct net_device *dev,
if (iwe->key_len > sizeof(key.data))
return -EINVAL;
- WL_WSEC(("Setting the key index %d\n", key.index));
+ WL_WSEC("Setting the key index %d\n", key.index);
if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- WL_WSEC(("key is a Primary Key\n"));
+ WL_WSEC("key is a Primary Key\n");
key.flags = WL_PRIMARY_KEY;
}
@@ -2638,15 +2634,15 @@ wl_iw_set_pmksa(struct net_device *dev,
uint i;
int ret = 0;
- WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
+ WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name);
CHECK_EXTRA_FOR_NULL(extra);
iwpmksa = (struct iw_pmksa *)extra;
if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
- WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
- bzero((char *)&pmkid_list, sizeof(pmkid_list));
+ WL_WSEC("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n");
+ memset((char *)&pmkid_list, 0, sizeof(pmkid_list));
}
else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
@@ -2656,30 +2652,30 @@ wl_iw_set_pmksa(struct net_device *dev,
pmkidptr = &pmkid;
bcopy(&iwpmksa->bssid.sa_data[0],
- &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
+ &pmkidptr->pmkid[0].BSSID, ETH_ALEN);
bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID,
WPA2_PMKID_LEN);
- WL_WSEC(("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: "
- "%pM = ", &pmkidptr->pmkid[0].BSSID));
+ WL_WSEC("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: %pM = ",
+ &pmkidptr->pmkid[0].BSSID);
for (j = 0; j < WPA2_PMKID_LEN; j++)
- WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
- WL_WSEC(("\n"));
+ WL_WSEC("%02x ", pmkidptr->pmkid[0].PMKID[j]);
+ WL_WSEC("\n");
}
for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
- if (!bcmp
+ if (!memcmp
(&iwpmksa->bssid.sa_data[0],
- &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN))
+ &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
break;
if ((pmkid_list.pmkids.npmkid > 0)
&& (i < pmkid_list.pmkids.npmkid)) {
- bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
+ memset(&pmkid_list.pmkids.pmkid[i], 0, sizeof(pmkid_t));
for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
bcopy(&pmkid_list.pmkids.pmkid[i + 1].BSSID,
&pmkid_list.pmkids.pmkid[i].BSSID,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
bcopy(&pmkid_list.pmkids.pmkid[i + 1].PMKID,
&pmkid_list.pmkids.pmkid[i].PMKID,
WPA2_PMKID_LEN);
@@ -2691,14 +2687,14 @@ wl_iw_set_pmksa(struct net_device *dev,
else if (iwpmksa->cmd == IW_PMKSA_ADD) {
for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
- if (!bcmp
+ if (!memcmp
(&iwpmksa->bssid.sa_data[0],
- &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN))
+ &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
break;
if (i < MAXPMKID) {
bcopy(&iwpmksa->bssid.sa_data[0],
&pmkid_list.pmkids.pmkid[i].BSSID,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
bcopy(&iwpmksa->pmkid[0],
&pmkid_list.pmkids.pmkid[i].PMKID,
WPA2_PMKID_LEN);
@@ -2710,25 +2706,25 @@ wl_iw_set_pmksa(struct net_device *dev,
uint j;
uint k;
k = pmkid_list.pmkids.npmkid;
- WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ",
- &pmkid_list.pmkids.pmkid[k].BSSID));
+ WL_WSEC("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ",
+ &pmkid_list.pmkids.pmkid[k].BSSID);
for (j = 0; j < WPA2_PMKID_LEN; j++)
- WL_WSEC(("%02x ",
- pmkid_list.pmkids.pmkid[k].PMKID[j]));
- WL_WSEC(("\n"));
+ WL_WSEC("%02x ",
+ pmkid_list.pmkids.pmkid[k].PMKID[j]);
+ WL_WSEC("\n");
}
}
- WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n",
- pmkid_list.pmkids.npmkid));
+ WL_WSEC("PRINTING pmkid LIST - No of elements %d\n",
+ pmkid_list.pmkids.npmkid);
for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
uint j;
- WL_WSEC(("PMKID[%d]: %pM = ", i,
- &pmkid_list.pmkids.pmkid[i].BSSID));
+ WL_WSEC("PMKID[%d]: %pM = ",
+ i, &pmkid_list.pmkids.pmkid[i].BSSID);
for (j = 0; j < WPA2_PMKID_LEN; j++)
- WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
- WL_WSEC(("\n"));
+ WL_WSEC("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]);
+ WL_WSEC("\n");
}
- WL_WSEC(("\n"));
+ WL_WSEC("\n");
if (!ret)
ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
@@ -2742,7 +2738,7 @@ wl_iw_get_encodeext(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
+ WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name);
return 0;
}
@@ -2757,13 +2753,13 @@ wl_iw_set_wpaauth(struct net_device *dev,
int val = 0;
wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
- WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name));
+ WL_TRACE("%s: SIOCSIWAUTH\n", dev->name);
paramid = vwrq->flags & IW_AUTH_INDEX;
paramval = vwrq->value;
- WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
- dev->name, paramid, paramval));
+ WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
+ dev->name, paramid, paramval);
switch (paramid) {
case IW_AUTH_WPA_VERSION:
@@ -2773,8 +2769,8 @@ wl_iw_set_wpaauth(struct net_device *dev,
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
- WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __func__,
- __LINE__, val));
+ WL_INFORM("%s: %d: setting wpa_auth to 0x%0x\n",
+ __func__, __LINE__, val);
error = dev_wlc_intvar_set(dev, "wpa_auth", val);
if (error)
return error;
@@ -2797,20 +2793,19 @@ wl_iw_set_wpaauth(struct net_device *dev,
}
if (iw->privacy_invoked && !val) {
- WL_WSEC(("%s: %s: 'Privacy invoked' true but clearing "
- "wsec, assuming " "we're a WPS enrollee\n",
- dev->name, __func__));
+ WL_WSEC("%s: %s: 'Privacy invoked' true but clearing wsec, assuming we're a WPS enrollee\n",
+ dev->name, __func__);
error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
true);
if (error) {
- WL_WSEC(("Failed to set is_WPS_enrollee\n"));
+ WL_WSEC("Failed to set is_WPS_enrollee\n");
return error;
}
} else if (val) {
error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
false);
if (error) {
- WL_WSEC(("Failed to clear is_WPS_enrollee\n"));
+ WL_WSEC("Failed to clear is_WPS_enrollee\n");
return error;
}
}
@@ -2837,8 +2832,8 @@ wl_iw_set_wpaauth(struct net_device *dev,
else
val = WPA2_AUTH_UNSPECIFIED;
}
- WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __func__,
- __LINE__, val));
+ WL_INFORM("%s: %d: setting wpa_auth to %d\n",
+ __func__, __LINE__, val);
error = dev_wlc_intvar_set(dev, "wpa_auth", val);
if (error)
return error;
@@ -2850,7 +2845,7 @@ wl_iw_set_wpaauth(struct net_device *dev,
break;
case IW_AUTH_80211_AUTH_ALG:
- WL_INFORM(("Setting the D11auth %d\n", paramval));
+ WL_INFORM("Setting the D11auth %d\n", paramval);
if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
val = 0;
else if (paramval == IW_AUTH_ALG_SHARED_KEY)
@@ -2879,8 +2874,8 @@ wl_iw_set_wpaauth(struct net_device *dev,
dev_wlc_intvar_set(dev, "wsec", val);
}
val = 0;
- WL_INFORM(("%s: %d: setting wpa_auth to %d\n",
- __func__, __LINE__, val));
+ WL_INFORM("%s: %d: setting wpa_auth to %d\n",
+ __func__, __LINE__, val);
dev_wlc_intvar_set(dev, "wpa_auth", 0);
return error;
}
@@ -2897,7 +2892,7 @@ wl_iw_set_wpaauth(struct net_device *dev,
#if WIRELESS_EXT > 17
case IW_AUTH_ROAMING_CONTROL:
- WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__));
+ WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
break;
case IW_AUTH_PRIVACY_INVOKED:
{
@@ -2908,8 +2903,7 @@ wl_iw_set_wpaauth(struct net_device *dev,
error = dev_wlc_intvar_set(dev,
"is_WPS_enrollee", false);
if (error) {
- WL_WSEC(("Failed to clear iovar "
- "is_WPS_enrollee\n"));
+ WL_WSEC("Failed to clear iovar is_WPS_enrollee\n");
return error;
}
} else {
@@ -2923,8 +2917,7 @@ wl_iw_set_wpaauth(struct net_device *dev,
"is_WPS_enrollee",
true);
if (error) {
- WL_WSEC(("Failed to set iovar "
- "is_WPS_enrollee\n"));
+ WL_WSEC("Failed to set iovar is_WPS_enrollee\n");
return error;
}
} else {
@@ -2932,8 +2925,7 @@ wl_iw_set_wpaauth(struct net_device *dev,
"is_WPS_enrollee",
false);
if (error) {
- WL_WSEC(("Failed to clear "
- "is_WPS_enrollee\n"));
+ WL_WSEC("Failed to clear is_WPS_enrollee\n");
return error;
}
}
@@ -2960,7 +2952,7 @@ wl_iw_get_wpaauth(struct net_device *dev,
int val;
wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
- WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
+ WL_TRACE("%s: SIOCGIWAUTH\n", dev->name);
paramid = vwrq->flags & IW_AUTH_INDEX;
@@ -3040,7 +3032,7 @@ wl_iw_get_wpaauth(struct net_device *dev,
break;
#if WIRELESS_EXT > 17
case IW_AUTH_ROAMING_CONTROL:
- WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__));
+ WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
break;
case IW_AUTH_PRIVACY_INVOKED:
paramval = iw->privacy_invoked;
@@ -3157,19 +3149,19 @@ int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
char *extra = NULL;
int token_size = 1, max_tokens = 0, ret = 0;
- WL_TRACE(("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
- __func__, cmd));
+ WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
+ __func__, cmd);
if (cmd < SIOCIWFIRST ||
IW_IOCTL_IDX(cmd) >= ARRAY_SIZE(wl_iw_handler)) {
- WL_ERROR(("%s: error in cmd=%x : out of range\n", __func__,
- cmd));
+ WL_ERROR("%s: error in cmd=%x : out of range\n",
+ __func__, cmd);
return -EOPNOTSUPP;
}
handler = wl_iw_handler[IW_IOCTL_IDX(cmd)];
if (!handler) {
- WL_ERROR(("%s: error in cmd=%x : not supported\n",
- __func__, cmd));
+ WL_ERROR("%s: error in cmd=%x : not supported\n",
+ __func__, cmd);
return -EOPNOTSUPP;
}
@@ -3234,9 +3226,8 @@ int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (max_tokens && wrq->u.data.pointer) {
if (wrq->u.data.length > max_tokens) {
- WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d "
- "> max_tokens=%d\n",
- __func__, cmd, wrq->u.data.length, max_tokens));
+ WL_ERROR("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
+ __func__, cmd, wrq->u.data.length, max_tokens);
return -E2BIG;
}
extra = kmalloc(max_tokens * token_size, GFP_KERNEL);
@@ -3339,7 +3330,7 @@ wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason,
memset(stringBuf, 0, buflen);
snprintf(stringBuf, buflen, "%s %s %02d %02d",
name, cause, status, reason);
- WL_INFORM(("Connection status: %s\n", stringBuf));
+ WL_INFORM("Connection status: %s\n", stringBuf);
return true;
} else {
return false;
@@ -3383,46 +3374,46 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
iw = 0;
if (!dev) {
- WL_ERROR(("%s: dev is null\n", __func__));
+ WL_ERROR("%s: dev is null\n", __func__);
return;
}
iw = *(wl_iw_t **) netdev_priv(dev);
- WL_TRACE(("%s: dev=%s event=%d\n", __func__, dev->name, event_type));
+ WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type);
switch (event_type) {
case WLC_E_TXFAIL:
cmd = IWEVTXDROP;
- memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+ memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
break;
#if WIRELESS_EXT > 14
case WLC_E_JOIN:
case WLC_E_ASSOC_IND:
case WLC_E_REASSOC_IND:
- memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+ memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
cmd = IWEVREGISTERED;
break;
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
cmd = SIOCGIWAP;
- bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
+ memset(wrqu.addr.sa_data, 0, ETH_ALEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
- bzero(&extra, ETHER_ADDR_LEN);
+ memset(&extra, 0, ETH_ALEN);
break;
case WLC_E_LINK:
case WLC_E_NDIS_LINK:
cmd = SIOCGIWAP;
if (!(flags & WLC_EVENT_MSG_LINK)) {
- bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
- bzero(&extra, ETHER_ADDR_LEN);
+ memset(wrqu.addr.sa_data, 0, ETH_ALEN);
+ memset(&extra, 0, ETH_ALEN);
WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_LINK_DOWN_TMOUT,
20 * HZ);
} else {
- memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
- WL_TRACE(("Link UP\n"));
+ memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
+ WL_TRACE("Link UP\n");
}
wrqu.addr.sa_family = ARPHRD_ETHER;
@@ -3433,8 +3424,8 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
wrqu.data.length = datalen + 1;
extra[0] = WLC_E_ACTION_FRAME;
memcpy(&extra[1], data, datalen);
- WL_TRACE(("WLC_E_ACTION_FRAME len %d \n",
- wrqu.data.length));
+ WL_TRACE("WLC_E_ACTION_FRAME len %d\n",
+ wrqu.data.length);
}
break;
@@ -3464,7 +3455,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
else
micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
memcpy(micerrevt->src_addr.sa_data, &e->addr,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
micerrevt->src_addr.sa_family = ARPHRD_ETHER;
break;
@@ -3487,14 +3478,14 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
wrqu.data.length = sizeof(struct iw_pmkid_cand);
pmkidcand = pmkcandlist->pmkid_cand;
while (count) {
- bzero(iwpmkidcand,
+ memset(iwpmkidcand, 0,
sizeof(struct iw_pmkid_cand));
if (pmkidcand->preauth)
iwpmkidcand->flags |=
IW_PMKID_CAND_PREAUTH;
bcopy(&pmkidcand->BSSID,
&iwpmkidcand->bssid.sa_data,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
#ifndef SANDGATE2G
wireless_send_event(dev, cmd, &wrqu,
extra);
@@ -3515,13 +3506,13 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
} else {
cmd = SIOCGIWSCAN;
wrqu.data.length = strlen(extra);
- WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific "
- "scan %d\n", g_iscan->iscan_state));
+ WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
+ g_iscan->iscan_state);
}
#else
cmd = SIOCGIWSCAN;
wrqu.data.length = strlen(extra);
- WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
+ WL_TRACE("Event WLC_E_SCAN_COMPLETE\n");
#endif
break;
@@ -3529,9 +3520,9 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
{
wlc_ssid_t *ssid;
ssid = (wlc_ssid_t *) data;
- WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : "
- "find %s len=%d\n", __func__, PNO_EVENT_UP,
- ssid->SSID, ssid->SSID_len));
+ WL_ERROR("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
+ __func__, PNO_EVENT_UP,
+ ssid->SSID, ssid->SSID_len);
WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_PNO_FIND_TMOUT,
20 * HZ);
cmd = IWEVCUSTOM;
@@ -3542,7 +3533,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
break;
default:
- WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
+ WL_TRACE("Unknown Event %d: ignoring\n", event_type);
break;
}
#ifndef SANDGATE2G
@@ -3583,15 +3574,15 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
goto done;
phy_noise = dtoh32(phy_noise);
- WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise));
+ WL_TRACE("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise);
- bzero(&scb_val, sizeof(scb_val_t));
+ memset(&scb_val, 0, sizeof(scb_val_t));
res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
if (res)
goto done;
rssi = dtoh32(scb_val.val);
- WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi));
+ WL_TRACE("wl_iw_get_wireless_stats rssi=%d\n", rssi);
if (rssi <= WL_IW_RSSI_NO_SIGNAL)
wstats->qual.qual = 0;
else if (rssi <= WL_IW_RSSI_VERY_LOW)
@@ -3614,23 +3605,21 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
#endif
#if WIRELESS_EXT > 11
- WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n",
- (int)sizeof(wl_cnt_t)));
+ WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n", sizeof(wl_cnt_t));
memset(&cnt, 0, sizeof(wl_cnt_t));
res =
dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
if (res) {
- WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n",
- res));
+ WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n",
+ res);
goto done;
}
cnt.version = dtoh16(cnt.version);
if (cnt.version != WL_CNT_T_VERSION) {
- WL_TRACE(("\tIncorrect version of counters struct: expected "
- "%d; got %d\n",
- WL_CNT_T_VERSION, cnt.version));
+ WL_TRACE("\tIncorrect version of counters struct: expected %d; got %d\n",
+ WL_CNT_T_VERSION, cnt.version);
goto done;
}
@@ -3641,22 +3630,22 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
wstats->miss.beacon = 0;
- WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
- dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
- dtoh32(cnt.rxfrmtoolong)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
- dtoh32(cnt.rxbadplcp)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n",
- dtoh32(cnt.rxundec)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
- dtoh32(cnt.rxfragerr)));
- WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n",
- dtoh32(cnt.txfail)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n",
- dtoh32(cnt.rxrunt)));
- WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n",
- dtoh32(cnt.rxgiant)));
+ WL_TRACE("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
+ dtoh32(cnt.txframe), dtoh32(cnt.txbyte));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
+ dtoh32(cnt.rxfrmtoolong));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
+ dtoh32(cnt.rxbadplcp));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxundec=%d\n",
+ dtoh32(cnt.rxundec));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
+ dtoh32(cnt.rxfragerr));
+ WL_TRACE("wl_iw_get_wireless_stats counters txfail=%d\n",
+ dtoh32(cnt.txfail));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxrunt=%d\n",
+ dtoh32(cnt.rxrunt));
+ WL_TRACE("wl_iw_get_wireless_stats counters rxgiant=%d\n",
+ dtoh32(cnt.rxgiant));
#endif /* WIRELESS_EXT > 11 */
done:
@@ -3690,8 +3679,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp)
return -ENOMEM;
memset(iscan, 0, sizeof(iscan_info_t));
- iscan->iscan_ex_params_p =
- (wl_iscan_params_t *) kmalloc(params_size, GFP_KERNEL);
+ iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
if (!iscan->iscan_ex_params_p)
return -ENOMEM;
iscan->iscan_ex_param_size = params_size;
@@ -3723,9 +3711,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp)
priv_dev = dev;
MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
#endif
- g_scan = NULL;
-
- g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
+ g_scan = kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
if (!g_scan)
return -ENOMEM;
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.h b/drivers/staging/brcm80211/brcmfmac/wl_iw.h
index edbf61f30b47..c8637c50dc17 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_iw.h
+++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.h
@@ -78,7 +78,7 @@ typedef struct wl_iw_extra_params {
#define CHECK_EXTRA_FOR_NULL(extra) \
if (!extra) { \
- WL_ERROR(("%s: error : extra is null pointer\n", __func__)); \
+ WL_ERROR("%s: error : extra is null pointer\n", __func__); \
return -EINVAL; \
}
diff --git a/drivers/staging/brcm80211/include/bcm_rpc.h b/drivers/staging/brcm80211/include/bcm_rpc.h
deleted file mode 100644
index 77e5d8f71966..000000000000
--- a/drivers/staging/brcm80211/include/bcm_rpc.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BCM_RPC_H_
-#define _BCM_RPC_H_
-
-#include <rpc_osl.h>
-
-typedef struct rpc_info rpc_info_t;
-typedef struct rpc_buf rpc_buf_t;
-struct rpc_transport_info;
-typedef void (*rpc_dispatch_cb_t) (void *ctx, struct rpc_buf *buf);
-typedef void (*rpc_resync_cb_t) (void *ctx);
-typedef void (*rpc_down_cb_t) (void *ctx);
-typedef void (*rpc_txdone_cb_t) (void *ctx, struct rpc_buf *buf);
-extern struct rpc_info *bcm_rpc_attach(void *pdev, osl_t *osh,
- struct rpc_transport_info *rpc_th);
-
-extern void bcm_rpc_detach(struct rpc_info *rpc);
-extern void bcm_rpc_down(struct rpc_info *rpc);
-extern void bcm_rpc_watchdog(struct rpc_info *rpc);
-
-extern struct rpc_buf *bcm_rpc_buf_alloc(struct rpc_info *rpc, int len);
-extern void bcm_rpc_buf_free(struct rpc_info *rpc, struct rpc_buf *b);
-/* get rpc transport handle */
-extern struct rpc_transport_info *bcm_rpc_tp_get(struct rpc_info *rpc);
-
-/* callback for: data_rx, down, resync */
-extern void bcm_rpc_rxcb_init(struct rpc_info *rpc, void *ctx,
- rpc_dispatch_cb_t cb, void *dnctx,
- rpc_down_cb_t dncb, rpc_resync_cb_t resync_cb,
- rpc_txdone_cb_t);
-extern void bcm_rpc_rxcb_deinit(struct rpc_info *rpci);
-
-/* HOST or CLIENT rpc call, requiring no return value */
-extern int bcm_rpc_call(struct rpc_info *rpc, struct rpc_buf *b);
-
-/* HOST rpc call, demanding return.
- * The thread may be suspended and control returns back to OS
- * The thread will resume(waked up) on either the return signal received or timeout
- * The implementation details depend on OS
- */
-extern struct rpc_buf *bcm_rpc_call_with_return(struct rpc_info *rpc,
- struct rpc_buf *b);
-
-/* CLIENT rpc call to respond to bcm_rpc_call_with_return, requiring no return value */
-extern int bcm_rpc_call_return(struct rpc_info *rpc, struct rpc_buf *retb);
-
-extern uint bcm_rpc_buf_header_len(struct rpc_info *rpci);
-
-#define RPC_PKTLOG_SIZE 50 /* Depth of the history */
-#define RPC_PKTLOG_RD_LEN 3
-#define RPC_PKTLOG_DUMP_SIZE 150 /* dump size should be more than the product of above two */
-extern int bcm_rpc_pktlog_get(struct rpc_info *rpci, u32 *buf,
- uint buf_size, bool send);
-extern int bcm_rpc_dump(rpc_info_t *rpci, struct bcmstrbuf *b);
-
-/* HIGH/BMAC: bit 15-8: RPC module, bit 7-0: TP module */
-#define RPC_ERROR_VAL 0x0001
-#define RPC_TRACE_VAL 0x0002
-#define RPC_PKTTRACE_VAL 0x0004
-#define RPC_PKTLOG_VAL 0x0008
-extern void bcm_rpc_msglevel_set(struct rpc_info *rpci, u16 msglevel,
- bool high_low);
-
-#endif /* _BCM_RPC_H_ */
diff --git a/drivers/staging/brcm80211/include/bcm_rpc_tp.h b/drivers/staging/brcm80211/include/bcm_rpc_tp.h
deleted file mode 100644
index bb8dc6dd6f44..000000000000
--- a/drivers/staging/brcm80211/include/bcm_rpc_tp.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _bcm_rpc_tp_h_
-#define _bcm_rpc_tp_h_
-#include <bcm_rpc.h>
-
-#define DBUS_RX_BUFFER_SIZE_RPC (2100) /* rxbufsize for dbus_attach, linux only for now */
-
-#define BCM_RPC_TP_ENCAP_LEN 4 /* TP header is 4 bytes */
-
-#define BCM_RPC_TP_HOST_AGG_MASK 0xffff0000
-#define BCM_RPC_TP_HOST_AGG_SHIFT 16
-#define BCM_RPC_TP_HOST_AGG_AMPDU 0x00010000 /* HOST->DNGL ampdu aggregation */
-#define BCM_RPC_TP_HOST_AGG_TEST 0x00100000 /* HOST->DNGL test aggregation */
-#define BCM_RPC_TP_DNGL_AGG_MASK 0x0000ffff
-#define BCM_RPC_TP_DNGL_AGG_DPC 0x00000001 /* DNGL->HOST data aggregation */
-#define BCM_RPC_TP_DNGL_AGG_FLOWCTL 0x00000002 /* DNGL->HOST tx flowcontrol agg */
-#define BCM_RPC_TP_DNGL_AGG_TEST 0x00000010 /* DNGL->HOST test agg */
-
-#define BCM_RPC_TP_DNGL_AGG_MAX_SFRAME 3 /* max agg subframes, must be <= USB_NTXD */
-#define BCM_RPC_TP_DNGL_AGG_MAX_BYTE 4000 /* max agg bytes */
-
-#define BCM_RPC_TP_HOST_AGG_MAX_SFRAME 3 /* max agg subframes, AMPDU only, 3 is enough */
-#define BCM_RPC_TP_HOST_AGG_MAX_BYTE 3400 /* max agg bytes; to fit 2+ tcp/udp pkts. Each one:
- * 802.3pkt + 802.11 hdr + rpc hdr + tp hdr < 1700B
- * Need to be in sync with dongle usb rx dma
- * rxbufsize(USBBULK_RXBUF_GIANT in usbdev_sb.c)
- */
-/* TP-DBUS pkts flowcontrol */
-#define BCM_RPC_TP_DBUS_NTXQ 50 /* queue size for TX on bulk OUT, aggregation possible */
-#define BCM_RPC_TP_DBUS_NRXQ 50 /* queue size for RX on bulk IN, aggregation possible */
-#define BCM_RPC_TP_DBUS_NRXQ_CTRL 1 /* queue size for RX on ctl EP0 */
-
-#define BCM_RPC_TP_DBUS_NRXQ_PKT (BCM_RPC_TP_DBUS_NRXQ * BCM_RPC_TP_DNGL_AGG_MAX_SFRAME)
-#define BCM_RPC_TP_DBUS_NTXQ_PKT (BCM_RPC_TP_DBUS_NTXQ * BCM_RPC_TP_HOST_AGG_MAX_SFRAME)
-
-typedef struct rpc_transport_info rpc_tp_info_t;
-
-typedef void (*rpc_tx_complete_fn_t) (void *, rpc_buf_t *, int status);
-typedef void (*rpc_rx_fn_t) (void *, rpc_buf_t *);
-
-#ifdef WLC_LOW
-typedef void (*rpc_txflowctl_cb_t) (void *ctx, bool on);
-#endif
-
-extern rpc_tp_info_t *bcm_rpc_tp_attach(osl_t *osh, void *bus);
-extern void bcm_rpc_tp_detach(rpc_tp_info_t *rpcb);
-extern void bcm_rpc_tp_down(rpc_tp_info_t *rpcb);
-extern void bcm_rpc_tp_watchdog(rpc_tp_info_t *rpcb);
-
-extern int bcm_rpc_tp_buf_send(rpc_tp_info_t *rpcb, rpc_buf_t *buf);
-
-/* callback for tx_complete, rx_pkt */
-extern void bcm_rpc_tp_register_cb(rpc_tp_info_t *rpcb,
- rpc_tx_complete_fn_t txcmplt,
- void *tx_context, rpc_rx_fn_t rxpkt,
- void *rx_context, rpc_osl_t *rpc_osh);
-extern void bcm_rpc_tp_deregister_cb(rpc_tp_info_t *rpcb);
-
-/* Buffer manipulation */
-extern uint bcm_rpc_buf_tp_header_len(rpc_tp_info_t *rpcb);
-extern rpc_buf_t *bcm_rpc_tp_buf_alloc(rpc_tp_info_t *rpcb, int len);
-extern void bcm_rpc_tp_buf_free(rpc_tp_info_t *rpcb, rpc_buf_t *buf);
-extern int bcm_rpc_buf_len_get(rpc_tp_info_t *rpcb, rpc_buf_t *b);
-extern int bcm_rpc_buf_len_set(rpc_tp_info_t *rpcb, rpc_buf_t *b, uint len);
-extern rpc_buf_t *bcm_rpc_buf_next_get(rpc_tp_info_t *rpcb, rpc_buf_t *b);
-extern void bcm_rpc_buf_next_set(rpc_tp_info_t *rpcb, rpc_buf_t *b,
- rpc_buf_t *nextb);
-extern unsigned char *bcm_rpc_buf_data(rpc_tp_info_t *rpcb, rpc_buf_t *b);
-extern unsigned char *bcm_rpc_buf_push(rpc_tp_info_t *rpcb, rpc_buf_t *b,
- uint delta);
-extern unsigned char *bcm_rpc_buf_pull(rpc_tp_info_t *rpcb, rpc_buf_t *b,
- uint delta);
-extern void bcm_rpc_tp_buf_release(rpc_tp_info_t *rpcb, rpc_buf_t *buf);
-extern void bcm_rpc_tp_buf_cnt_adjust(rpc_tp_info_t *rpcb, int adjust);
-/* RPC call_with_return */
-extern int bcm_rpc_tp_recv_rtn(rpc_tp_info_t *rpcb);
-extern int bcm_rpc_tp_get_device_speed(rpc_tp_info_t *rpc_th);
-#ifdef BCMDBG
-extern int bcm_rpc_tp_dump(rpc_tp_info_t *rpcb, struct bcmstrbuf *b);
-#endif
-
-#ifdef WLC_LOW
-/* intercept USB pkt to parse RPC header: USB driver rx-> wl_send -> this -> wl driver */
-extern void bcm_rpc_tp_rx_from_dnglbus(rpc_tp_info_t *rpc_th, struct lbuf *lb);
-
-/* RPC callreturn pkt, go to USB driver tx */
-extern int bcm_rpc_tp_send_callreturn(rpc_tp_info_t *rpc_th, rpc_buf_t *b);
-
-extern void bcm_rpc_tp_dump(rpc_tp_info_t *rpcb);
-extern void bcm_rpc_tp_txflowctl(rpc_tp_info_t *rpcb, bool state, int prio);
-extern void bcm_rpc_tp_txflowctlcb_init(rpc_tp_info_t *rpc_th, void *ctx,
- rpc_txflowctl_cb_t cb);
-extern void bcm_rpc_tp_txflowctlcb_deinit(rpc_tp_info_t *rpc_th);
-extern void bcm_rpc_tp_txq_wm_set(rpc_tp_info_t *rpc_th, u8 hiwm,
- u8 lowm);
-extern void bcm_rpc_tp_txq_wm_get(rpc_tp_info_t *rpc_th, u8 *hiwm,
- u8 *lowm);
-#endif /* WLC_LOW */
-
-extern void bcm_rpc_tp_agg_set(rpc_tp_info_t *rpcb, u32 reason, bool set);
-extern void bcm_rpc_tp_agg_limit_set(rpc_tp_info_t *rpc_th, u8 sf,
- u16 bytes);
-extern void bcm_rpc_tp_agg_limit_get(rpc_tp_info_t *rpc_th, u8 *sf,
- u16 *bytes);
-
-#define BCM_RPC_TP_MSG_LEVEL_MASK 0x00ff
-/* dongle msg level */
-#define RPC_TP_MSG_DNGL_ERR_VAL 0x0001 /* DNGL TP error msg */
-#define RPC_TP_MSG_DNGL_DBG_VAL 0x0002 /* DNGL TP dbg msg */
-#define RPC_TP_MSG_DNGL_AGG_VAL 0x0004 /* DNGL TP agg msg */
-#define RPC_TP_MSG_DNGL_DEA_VAL 0x0008 /* DNGL TP deag msg */
-
-/* host msg level */
-#define RPC_TP_MSG_HOST_ERR_VAL 0x0001 /* DNGL TP error msg */
-#define RPC_TP_MSG_HOST_DBG_VAL 0x0002 /* DNGL TP dbg msg */
-#define RPC_TP_MSG_HOST_AGG_VAL 0x0004 /* DNGL TP agg msg */
-#define RPC_TP_MSG_HOST_DEA_VAL 0x0008 /* DNGL TP deag msg */
-
-extern void bcm_rpc_tp_msglevel_set(rpc_tp_info_t *rpc_th, u8 msglevel,
- bool high_low);
-
-#endif /* _bcm_rpc_tp_h_ */
diff --git a/drivers/staging/brcm80211/include/bcm_xdr.h b/drivers/staging/brcm80211/include/bcm_xdr.h
deleted file mode 100644
index 50fbd78a8804..000000000000
--- a/drivers/staging/brcm80211/include/bcm_xdr.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BCM_XDR_H
-#define _BCM_XDR_H
-
-/*
- * bcm_xdr_buf_t
- * Structure used for bookkeeping of a buffer being packed or unpacked.
- * Keeps a current read/write pointer and size as well as
- * the original buffer pointer and size.
- *
- */
-typedef struct {
- u8 *buf; /* pointer to current position in origbuf */
- uint size; /* current (residual) size in bytes */
- u8 *origbuf; /* unmodified pointer to orignal buffer */
- uint origsize; /* unmodified orignal buffer size in bytes */
-} bcm_xdr_buf_t;
-
-void bcm_xdr_buf_init(bcm_xdr_buf_t *b, void *buf, size_t len);
-
-int bcm_xdr_pack_u32(bcm_xdr_buf_t *b, u32 val);
-int bcm_xdr_unpack_u32(bcm_xdr_buf_t *b, u32 *pval);
-int bcm_xdr_pack_s32(bcm_xdr_buf_t *b, s32 val);
-int bcm_xdr_unpack_s32(bcm_xdr_buf_t *b, s32 *pval);
-int bcm_xdr_pack_s8(bcm_xdr_buf_t *b, s8 val);
-int bcm_xdr_unpack_s8(bcm_xdr_buf_t *b, s8 *pval);
-int bcm_xdr_pack_opaque(bcm_xdr_buf_t *b, uint len, void *data);
-int bcm_xdr_unpack_opaque(bcm_xdr_buf_t *b, uint len, void **pdata);
-int bcm_xdr_unpack_opaque_cpy(bcm_xdr_buf_t *b, uint len, void *data);
-int bcm_xdr_pack_opaque_varlen(bcm_xdr_buf_t *b, uint len, void *data);
-int bcm_xdr_unpack_opaque_varlen(bcm_xdr_buf_t *b, uint *plen, void **pdata);
-int bcm_xdr_pack_string(bcm_xdr_buf_t *b, char *str);
-int bcm_xdr_unpack_string(bcm_xdr_buf_t *b, uint *plen, char **pstr);
-
-int bcm_xdr_pack_u8_vec(bcm_xdr_buf_t *, u8 *vec, u32 elems);
-int bcm_xdr_unpack_u8_vec(bcm_xdr_buf_t *, u8 *vec, u32 elems);
-int bcm_xdr_pack_u16_vec(bcm_xdr_buf_t *b, uint len, void *vec);
-int bcm_xdr_unpack_u16_vec(bcm_xdr_buf_t *b, uint len, void *vec);
-int bcm_xdr_pack_u32_vec(bcm_xdr_buf_t *b, uint len, void *vec);
-int bcm_xdr_unpack_u32_vec(bcm_xdr_buf_t *b, uint len, void *vec);
-
-int bcm_xdr_pack_opaque_raw(bcm_xdr_buf_t *b, uint len, void *data);
-int bcm_xdr_pack_opaque_pad(bcm_xdr_buf_t *b);
-
-#endif /* _BCM_XDR_H */
diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h
index dc52e9dbb8b5..74601fc971c9 100644
--- a/drivers/staging/brcm80211/include/bcmdefs.h
+++ b/drivers/staging/brcm80211/include/bcmdefs.h
@@ -42,9 +42,6 @@
#define BCMFASTPATH
#endif
-/* Put some library data/code into ROM to reduce RAM requirements */
-#define BCMROMFN(_fn) _fn
-
/* Bus types */
#define SI_BUS 0 /* SOC Interconnect */
#define PCI_BUS 1 /* PCI target */
@@ -54,35 +51,6 @@
#define SPI_BUS 6 /* gSPI target */
#define RPC_BUS 7 /* RPC target */
-/* Allows size optimization for single-bus image */
-#ifdef BCMBUSTYPE
-#define BUSTYPE(bus) (BCMBUSTYPE)
-#else
-#define BUSTYPE(bus) (bus)
-#endif
-
-/* Allows size optimization for single-backplane image */
-#ifdef BCMCHIPTYPE
-#define CHIPTYPE(bus) (BCMCHIPTYPE)
-#else
-#define CHIPTYPE(bus) (bus)
-#endif
-
-/* Allows size optimization for SPROM support */
-#define SPROMBUS (PCI_BUS)
-
-/* Allows size optimization for single-chip image */
-#ifdef BCMCHIPID
-#define CHIPID(chip) (BCMCHIPID)
-#else
-#define CHIPID(chip) (chip)
-#endif
-
-#ifdef BCMCHIPREV
-#define CHIPREV(rev) (BCMCHIPREV)
-#else
-#define CHIPREV(rev) (rev)
-#endif
/* Defines for DMA Address Width - Shared between OSL and HNDDMA */
#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */
@@ -146,31 +114,11 @@ typedef struct {
#define BCMEXTRAHDROOM 172
-/* Headroom required for dongle-to-host communication. Packets allocated
- * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should
- * leave this much room in front for low-level message headers which may
- * be needed to get across the dongle bus to the host. (These messages
- * don't go over the network, so room for the full WL header above would
- * be a waste.).
-*/
-#define BCMDONGLEHDRSZ 12
-#define BCMDONGLEPADSZ 16
-
-#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
-
#ifdef BCMDBG
-
-#define BCMDBG_ERR
-
#ifndef BCMDBG_ASSERT
#define BCMDBG_ASSERT
-#endif /* BCMDBG_ASSERT */
-
-#endif /* BCMDBG */
-
-#if defined(BCMDBG_ASSERT)
-#define BCMASSERT_SUPPORT
-#endif
+#endif /* BCMDBG_ASSERT */
+#endif /* BCMDBG */
/* Macros for doing definition and get/set of bitfields
* Usage example, e.g. a three-bit field (bits 4-6):
@@ -190,11 +138,10 @@ typedef struct {
(((val) & (~(field ## _M << field ## _S))) | \
((unsigned)(bits) << field ## _S))
-/* define BCMSMALL to remove misc features for memory-constrained environments */
-#define BCMSPACE
-#define bcmspace true /* if (bcmspace) code is retained */
-
/* Max. nvram variable table size */
#define MAXSZ_NVRAM_VARS 4096
+/* handle forward declaration */
+struct wl_info;
+
#endif /* _bcmdefs_h_ */
diff --git a/drivers/staging/brcm80211/include/bcmsdbus.h b/drivers/staging/brcm80211/include/bcmsdbus.h
index ca99495eaa89..89059dd8088b 100644
--- a/drivers/staging/brcm80211/include/bcmsdbus.h
+++ b/drivers/staging/brcm80211/include/bcmsdbus.h
@@ -46,8 +46,8 @@ typedef void (*sdioh_cb_fn_t) (void *);
* The handler shall be provided by all subsequent calls. No local cache
* cfghdl points to the starting address of pci device mapped memory
*/
-extern sdioh_info_t *sdioh_attach(osl_t *osh, void *cfghdl, uint irq);
-extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si);
+extern sdioh_info_t *sdioh_attach(struct osl_info *osh, void *cfghdl, uint irq);
+extern SDIOH_API_RC sdioh_detach(struct osl_info *osh, sdioh_info_t *si);
extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si,
sdioh_cb_fn_t fn, void *argh);
extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si);
@@ -79,7 +79,7 @@ extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma,
uint fix_inc, uint rw, uint fnc_num,
u32 addr, uint regwidth,
u32 buflen, u8 *buffer,
- void *pkt);
+ struct sk_buff *pkt);
/* get cis data */
extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, u8 *cis,
diff --git a/drivers/staging/brcm80211/include/bcmsdh.h b/drivers/staging/brcm80211/include/bcmsdh.h
index 6b80983d43c9..0e1f79919c9c 100644
--- a/drivers/staging/brcm80211/include/bcmsdh.h
+++ b/drivers/staging/brcm80211/include/bcmsdh.h
@@ -40,11 +40,11 @@ typedef void (*bcmsdh_cb_fn_t) (void *);
* implementation may maintain a single "default" handle (e.g. the first or
* most recent one) to enable single-instance implementations to pass NULL.
*/
-extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva,
- uint irq);
+extern bcmsdh_info_t *bcmsdh_attach(struct osl_info *osh, void *cfghdl,
+ void **regsva, uint irq);
/* Detach - freeup resources allocated in attach */
-extern int bcmsdh_detach(osl_t *osh, void *sdh);
+extern int bcmsdh_detach(struct osl_info *osh, void *sdh);
/* Query if SD device interrupts are enabled */
extern bool bcmsdh_intr_query(void *sdh);
@@ -122,7 +122,7 @@ extern int bcmsdh_send_buf(void *sdh, u32 addr, uint fn, uint flags,
u8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete, void *handle);
extern int bcmsdh_recv_buf(void *sdh, u32 addr, uint fn, uint flags,
- u8 *buf, uint nbytes, void *pkt,
+ u8 *buf, uint nbytes, struct sk_buff *pkt,
bcmsdh_cmplt_fn_t complete, void *handle);
/* Flags bits */
@@ -174,8 +174,8 @@ extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
typedef struct {
/* attach to device */
void *(*attach) (u16 vend_id, u16 dev_id, u16 bus, u16 slot,
- u16 func, uint bustype, void *regsva, osl_t *osh,
- void *param);
+ u16 func, uint bustype, void *regsva,
+ struct osl_info *osh, void *param);
/* detach from device */
void (*detach) (void *ch);
} bcmsdh_driver_t;
diff --git a/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h b/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h
index 7d5aa71a7dc7..4d671ddb3af1 100644
--- a/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h
+++ b/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h
@@ -51,7 +51,7 @@ extern void sdioh_sdmmc_osfree(sdioh_info_t *sd);
#define CLIENT_INTR 0x100 /* Get rid of this! */
struct sdioh_info {
- osl_t *osh; /* osh handler */
+ struct osl_info *osh; /* osh handler */
bool client_intr_enabled; /* interrupt connnected flag */
bool intr_handler_valid; /* client driver interrupt handler valid */
sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
@@ -94,8 +94,8 @@ extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
*/
/* Register mapping routines */
-extern u32 *sdioh_sdmmc_reg_map(osl_t *osh, s32 addr, int size);
-extern void sdioh_sdmmc_reg_unmap(osl_t *osh, s32 addr, int size);
+extern u32 *sdioh_sdmmc_reg_map(struct osl_info *osh, s32 addr, int size);
+extern void sdioh_sdmmc_reg_unmap(struct osl_info *osh, s32 addr, int size);
/* Interrupt (de)registration routines */
extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq);
diff --git a/drivers/staging/brcm80211/include/bcmsrom.h b/drivers/staging/brcm80211/include/bcmsrom.h
index 9d53657fdaa1..cdcef746284f 100644
--- a/drivers/staging/brcm80211/include/bcmsrom.h
+++ b/drivers/staging/brcm80211/include/bcmsrom.h
@@ -20,15 +20,15 @@
#include <bcmsrom_fmt.h>
/* Prototypes */
-extern int srom_var_init(si_t *sih, uint bus, void *curmap, osl_t *osh,
- char **vars, uint *count);
+extern int srom_var_init(si_t *sih, uint bus, void *curmap,
+ struct osl_info *osh, char **vars, uint *count);
-extern int srom_read(si_t *sih, uint bus, void *curmap, osl_t *osh,
+extern int srom_read(si_t *sih, uint bus, void *curmap, struct osl_info *osh,
uint byteoff, uint nbytes, u16 *buf, bool check_crc);
/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP
* and extract from it into name=value pairs
*/
-extern int srom_parsecis(osl_t *osh, u8 **pcis, uint ciscnt,
+extern int srom_parsecis(struct osl_info *osh, u8 **pcis, uint ciscnt,
char **vars, uint *count);
#endif /* _bcmsrom_h_ */
diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h
index b53315981be0..a8f76d8199ff 100644
--- a/drivers/staging/brcm80211/include/bcmutils.h
+++ b/drivers/staging/brcm80211/include/bcmutils.h
@@ -30,7 +30,6 @@
};
/* ** driver-only section ** */
-#include <osl.h>
#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */
@@ -56,10 +55,10 @@
#endif
typedef struct pktq_prec {
- void *head; /* first packet to dequeue */
- void *tail; /* last packet to dequeue */
- u16 len; /* number of queued packets */
- u16 max; /* maximum number of queued packets */
+ struct sk_buff *head; /* first packet to dequeue */
+ struct sk_buff *tail; /* last packet to dequeue */
+ u16 len; /* number of queued packets */
+ u16 max; /* maximum number of queued packets */
} pktq_prec_t;
/* multi-priority pkt queue */
@@ -105,23 +104,26 @@
#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
- extern void *pktq_penq(struct pktq *pq, int prec, void *p);
- extern void *pktq_penq_head(struct pktq *pq, int prec, void *p);
- extern void *pktq_pdeq(struct pktq *pq, int prec);
- extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
+extern struct sk_buff *pktq_penq(struct pktq *pq, int prec,
+ struct sk_buff *p);
+extern struct sk_buff *pktq_penq_head(struct pktq *pq, int prec,
+ struct sk_buff *p);
+extern struct sk_buff *pktq_pdeq(struct pktq *pq, int prec);
+extern struct sk_buff *pktq_pdeq_tail(struct pktq *pq, int prec);
+
/* Empty the queue at particular precedence level */
#ifdef BRCM_FULLMAC
- extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec,
+ extern void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec,
bool dir);
#else
- extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec,
+ extern void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec,
bool dir, ifpkt_cb_t fn, int arg);
#endif /* BRCM_FULLMAC */
/* operations on a set of precedences in packet queue */
- extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
- extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
+extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
+extern struct sk_buff *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
/* operations on packet queue as a whole */
@@ -140,20 +142,19 @@
extern void pktq_init(struct pktq *pq, int num_prec, int max_len);
/* prec_out may be NULL if caller is not interested in return value */
- extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
+ extern struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out);
#ifdef BRCM_FULLMAC
- extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir);
+ extern void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir);
#else
- extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir,
+ extern void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
ifpkt_cb_t fn, int arg);
#endif
/* externs */
/* packet */
- extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len,
- unsigned char *buf);
- extern uint pktsegcnt(osl_t *osh, void *p);
- extern uint pkttotlen(osl_t *osh, void *p);
+ extern uint pktfrombuf(struct osl_info *osh, struct sk_buff *p,
+ uint offset, int len, unsigned char *buf);
+ extern uint pkttotlen(struct osl_info *osh, struct sk_buff *p);
/* ethernet address */
extern int bcm_ether_atoe(char *p, struct ether_addr *ea);
@@ -166,7 +167,8 @@
extern char *getvar(char *vars, const char *name);
extern int getintvar(char *vars, const char *name);
#ifdef BCMDBG
- extern void prpkt(const char *msg, osl_t *osh, void *p0);
+ extern void prpkt(const char *msg, struct osl_info *osh,
+ struct sk_buff *p0);
#endif /* BCMDBG */
#define bcm_perf_enable()
#define bcmstats(fmt)
@@ -359,7 +361,21 @@
#define CEIL(x, y) (((x) + ((y)-1)) / (y))
#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
-/* bit map related macros */
+/* map physical to virtual I/O */
+#if !defined(CONFIG_MMC_MSM7X00A)
+#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), \
+ (unsigned long)(size))
+#else
+#define REG_MAP(pa, size) (void *)(0)
+#endif
+
+/* Register operations */
+#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
+#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
+
+#define SET_REG(osh, r, mask, val) \
+ W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val)))
+
#ifndef setbit
#ifndef NBBY /* the BSD family defines NBBY */
#define NBBY 8 /* 8 bits per byte */
diff --git a/drivers/staging/brcm80211/include/d11.h b/drivers/staging/brcm80211/include/d11.h
index c07548c70e30..be2d4970407c 100644
--- a/drivers/staging/brcm80211/include/d11.h
+++ b/drivers/staging/brcm80211/include/d11.h
@@ -17,13 +17,6 @@
#ifndef _D11_H
#define _D11_H
-#include <bcmdefs.h>
-#include <bcmdevs.h>
-#include <hndsoc.h>
-#include <sbhndpio.h>
-#include <sbhnddma.h>
-#include <proto/802.11.h>
-
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
diff --git a/drivers/staging/brcm80211/include/dbus.h b/drivers/staging/brcm80211/include/dbus.h
deleted file mode 100644
index 81ffea79d008..000000000000
--- a/drivers/staging/brcm80211/include/dbus.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __DBUS_H__
-#define __DBUS_H__
-
-#ifdef BCMDBG
-#define DBUSERR(args) do { if (net_ratelimit()) printf args; } while (0)
-#define DBUSTRACE(args)
-#define DBUSDBGLOCK(args)
-
-#else
-#define DBUSTRACE(args)
-#define DBUSERR(args)
-#define DBUSDBGLOCK(args)
-#endif
-
-enum {
- DBUS_OK = 0,
- DBUS_ERR = -200,
- DBUS_ERR_TIMEOUT,
- DBUS_ERR_DISCONNECT,
- DBUS_ERR_NODEVICE,
- DBUS_ERR_UNSUPPORTED,
- DBUS_ERR_PENDING,
- DBUS_ERR_NOMEM,
- DBUS_ERR_TXFAIL,
- DBUS_ERR_TXTIMEOUT,
- DBUS_ERR_TXDROP,
- DBUS_ERR_RXFAIL,
- DBUS_ERR_RXDROP,
- DBUS_ERR_TXCTLFAIL,
- DBUS_ERR_RXCTLFAIL,
- DBUS_ERR_REG_PARAM,
- DBUS_STATUS_CANCELLED
-};
-
-#define ERR_CBMASK_TXFAIL 0x00000001
-#define ERR_CBMASK_RXFAIL 0x00000002
-#define ERR_CBMASK_ALL 0xFFFFFFFF
-
-#define DBUS_CBCTL_WRITE 0
-#define DBUS_CBCTL_READ 1
-
-#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */
-#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */
-
-#define DBUS_BUFFER_SIZE_TX 5000
-#define DBUS_BUFFER_SIZE_RX 5000
-
-#define DBUS_BUFFER_SIZE_TX_NOAGG 2048
-#define DBUS_BUFFER_SIZE_RX_NOAGG 2048
-
-/* DBUS types */
-enum {
- DBUS_USB,
- DBUS_SDIO,
- DBUS_SPI,
- DBUS_UNKNOWN
-};
-
-enum dbus_state {
- DBUS_STATE_DL_PENDING,
- DBUS_STATE_DL_DONE,
- DBUS_STATE_UP,
- DBUS_STATE_DOWN,
- DBUS_STATE_PNP_FWDL,
- DBUS_STATE_DISCONNECT
-};
-
-enum dbus_pnp_state {
- DBUS_PNP_DISCONNECT,
- DBUS_PNP_SLEEP,
- DBUS_PNP_RESUME
-};
-
-typedef enum _DEVICE_SPEED {
- INVALID_SPEED = -1,
- LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */
- FULL_SPEED, /* USB 1.1: 12 Mbps */
- HIGH_SPEED, /* USB 2.0: 480 Mbps */
- SUPER_SPEED, /* USB 3.0: 4.8 Gbps */
-} DEVICE_SPEED;
-
-typedef struct {
- int bustype;
- int vid;
- int pid;
- int devid;
- int chiprev; /* chip revsion number */
- int mtu;
- int nchan; /* Data Channels */
-} dbus_attrib_t;
-
-/* FIX: Account for errors related to DBUS;
- * Let upper layer account for packets/bytes
- */
-typedef struct {
- u32 rx_errors;
- u32 tx_errors;
- u32 rx_dropped;
- u32 tx_dropped;
-} dbus_stats_t;
-
-/*
- * Configurable BUS parameters
- */
-typedef struct {
- bool rxctl_deferrespok;
-} dbus_config_t;
-
-struct dbus_callbacks;
-struct exec_parms;
-
-typedef void *(*probe_cb_t) (void *arg, const char *desc, u32 bustype,
- u32 hdrlen);
-typedef void (*disconnect_cb_t) (void *arg);
-typedef void *(*exec_cb_t) (struct exec_parms *args);
-
-/* Client callbacks registered during dbus_attach() */
-typedef struct dbus_callbacks {
- void (*send_complete) (void *cbarg, void *info, int status);
- void (*recv_buf) (void *cbarg, u8 *buf, int len);
- void (*recv_pkt) (void *cbarg, void *pkt);
- void (*txflowcontrol) (void *cbarg, bool onoff);
- void (*errhandler) (void *cbarg, int err);
- void (*ctl_complete) (void *cbarg, int type, int status);
- void (*state_change) (void *cbarg, int state);
- void *(*pktget) (void *cbarg, uint len, bool send);
- void (*pktfree) (void *cbarg, void *p, bool send);
-} dbus_callbacks_t;
-
-struct dbus_pub;
-struct bcmstrbuf;
-struct dbus_irb;
-struct dbus_irb_rx;
-struct dbus_irb_tx;
-struct dbus_intf_callbacks;
-
-typedef struct {
- void *(*attach) (struct dbus_pub *pub, void *cbarg,
- struct dbus_intf_callbacks *cbs);
- void (*detach) (struct dbus_pub *pub, void *bus);
-
- int (*up) (void *bus);
- int (*down) (void *bus);
- int (*send_irb) (void *bus, struct dbus_irb_tx *txirb);
- int (*recv_irb) (void *bus, struct dbus_irb_rx *rxirb);
- int (*cancel_irb) (void *bus, struct dbus_irb_tx *txirb);
- int (*send_ctl) (void *bus, u8 *buf, int len);
- int (*recv_ctl) (void *bus, u8 *buf, int len);
- int (*get_stats) (void *bus, dbus_stats_t *stats);
- int (*get_attrib) (void *bus, dbus_attrib_t *attrib);
-
- int (*pnp) (void *bus, int event);
- int (*remove) (void *bus);
- int (*resume) (void *bus);
- int (*suspend) (void *bus);
- int (*stop) (void *bus);
- int (*reset) (void *bus);
-
- /* Access to bus buffers directly */
- void *(*pktget) (void *bus, int len);
- void (*pktfree) (void *bus, void *pkt);
-
- int (*iovar_op) (void *bus, const char *name, void *params, int plen,
- void *arg, int len, bool set);
- void (*dump) (void *bus, struct bcmstrbuf *strbuf);
- int (*set_config) (void *bus, dbus_config_t *config);
- int (*get_config) (void *bus, dbus_config_t *config);
-
- bool(*device_exists) (void *bus);
- bool(*dlneeded) (void *bus);
- int (*dlstart) (void *bus, u8 *fw, int len);
- int (*dlrun) (void *bus);
- bool(*recv_needed) (void *bus);
-
- void *(*exec_rxlock) (void *bus, exec_cb_t func,
- struct exec_parms *args);
- void *(*exec_txlock) (void *bus, exec_cb_t func,
- struct exec_parms *args);
-
- int (*tx_timer_init) (void *bus);
- int (*tx_timer_start) (void *bus, uint timeout);
- int (*tx_timer_stop) (void *bus);
-
- int (*sched_dpc) (void *bus);
- int (*lock) (void *bus);
- int (*unlock) (void *bus);
- int (*sched_probe_cb) (void *bus);
-
- int (*shutdown) (void *bus);
-
- int (*recv_stop) (void *bus);
- int (*recv_resume) (void *bus);
-
- /* Add from the bottom */
-} dbus_intf_t;
-
-typedef struct dbus_pub {
- struct osl_info *osh;
- dbus_stats_t stats;
- dbus_attrib_t attrib;
- enum dbus_state busstate;
- DEVICE_SPEED device_speed;
- int ntxq, nrxq, rxsize;
- void *bus;
- struct shared_info *sh;
-} dbus_pub_t;
-
-#define BUS_INFO(bus, type) (((type *) bus)->pub->bus)
-
-/*
- * Public Bus Function Interface
- */
-extern int dbus_register(int vid, int pid, probe_cb_t prcb,
- disconnect_cb_t discb, void *prarg, void *param1,
- void *param2);
-extern int dbus_deregister(void);
-
-extern const dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq,
- int ntxq, void *cbarg,
- dbus_callbacks_t *cbs,
- struct shared_info *sh);
-extern void dbus_detach(const dbus_pub_t *pub);
-
-extern int dbus_up(const dbus_pub_t *pub);
-extern int dbus_down(const dbus_pub_t *pub);
-extern int dbus_stop(const dbus_pub_t *pub);
-extern int dbus_shutdown(const dbus_pub_t *pub);
-extern void dbus_flowctrl_rx(const dbus_pub_t *pub, bool on);
-
-extern int dbus_send_buf(const dbus_pub_t *pub, u8 *buf, int len,
- void *info);
-extern int dbus_send_pkt(const dbus_pub_t *pub, void *pkt, void *info);
-extern int dbus_send_ctl(const dbus_pub_t *pub, u8 *buf, int len);
-extern int dbus_recv_ctl(const dbus_pub_t *pub, u8 *buf, int len);
-
-extern int dbus_get_stats(const dbus_pub_t *pub, dbus_stats_t *stats);
-extern int dbus_get_attrib(const dbus_pub_t *pub, dbus_attrib_t *attrib);
-extern int dbus_get_device_speed(const dbus_pub_t *pub);
-extern int dbus_set_config(const dbus_pub_t *pub, dbus_config_t *config);
-extern int dbus_get_config(const dbus_pub_t *pub, dbus_config_t *config);
-
-extern void *dbus_pktget(const dbus_pub_t *pub, int len);
-extern void dbus_pktfree(const dbus_pub_t *pub, void *pkt);
-
-extern int dbus_set_errmask(const dbus_pub_t *pub, u32 mask);
-extern int dbus_pnp_sleep(const dbus_pub_t *pub);
-extern int dbus_pnp_resume(const dbus_pub_t *pub, int *fw_reload);
-extern int dbus_pnp_disconnect(const dbus_pub_t *pub);
-
-extern int dbus_iovar_op(const dbus_pub_t *pub, const char *name,
- void *params, int plen, void *arg, int len, bool set);
-#ifdef BCMDBG
-extern void dbus_hist_dump(const dbus_pub_t *pub, struct bcmstrbuf *b);
-#endif /* BCMDBG */
-/*
- * Private Common Bus Interface
- */
-
-/* IO Request Block (IRB) */
-typedef struct dbus_irb {
- struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */
-} dbus_irb_t;
-
-typedef struct dbus_irb_rx {
- struct dbus_irb irb; /* Must be first */
- u8 *buf;
- int buf_len;
- int actual_len;
- void *pkt;
- void *info;
- void *arg;
-} dbus_irb_rx_t;
-
-typedef struct dbus_irb_tx {
- struct dbus_irb irb; /* Must be first */
- u8 *buf;
- int len;
- void *pkt;
- int retry_count;
- void *info;
- void *arg;
-} dbus_irb_tx_t;
-
-/* DBUS interface callbacks are different from user callbacks
- * so, internally, different info can be passed to upper layer
- */
-typedef struct dbus_intf_callbacks {
- void (*send_irb_timeout) (void *cbarg, dbus_irb_tx_t *txirb);
- void (*send_irb_complete) (void *cbarg, dbus_irb_tx_t *txirb,
- int status);
- void (*recv_irb_complete) (void *cbarg, dbus_irb_rx_t *rxirb,
- int status);
- void (*errhandler) (void *cbarg, int err);
- void (*ctl_complete) (void *cbarg, int type, int status);
- void (*state_change) (void *cbarg, int state);
- bool(*isr) (void *cbarg, bool *wantdpc);
- bool(*dpc) (void *cbarg, bool bounded);
- void (*watchdog) (void *cbarg);
- void *(*pktget) (void *cbarg, uint len, bool send);
- void (*pktfree) (void *cbarg, void *p, bool send);
- struct dbus_irb *(*getirb) (void *cbarg, bool send);
- void (*rxerr_indicate) (void *cbarg, bool on);
-} dbus_intf_callbacks_t;
-
-/*
- * Porting: To support new bus, port these functions below
- */
-
-/*
- * Bus specific Interface
- * Implemented by dbus_usb.c/dbus_sdio.c
- */
-extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb,
- disconnect_cb_t discb, void *prarg,
- dbus_intf_t **intf, void *param1, void *param2);
-extern int dbus_bus_deregister(void);
-
-/*
- * Bus-specific and OS-specific Interface
- * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c
- */
-extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb,
- disconnect_cb_t discb, void *prarg,
- dbus_intf_t **intf, void *param1,
- void *param2);
-extern int dbus_bus_osl_deregister(void);
-
-/*
- * Bus-specific, OS-specific, HW-specific Interface
- * Mainly for SDIO Host HW controller
- */
-extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb,
- disconnect_cb_t discb, void *prarg,
- dbus_intf_t **intf);
-extern int dbus_bus_osl_hw_deregister(void);
-
-#endif /* __DBUS_H__ */
diff --git a/drivers/staging/brcm80211/include/epivers.h b/drivers/staging/brcm80211/include/epivers.h
deleted file mode 100644
index 2e6b5190ad6c..000000000000
--- a/drivers/staging/brcm80211/include/epivers.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _epivers_h_
-#define _epivers_h_
-
-#define EPI_MAJOR_VERSION 5
-
-#define EPI_MINOR_VERSION 75
-
-#define EPI_RC_NUMBER 11
-
-#define EPI_INCREMENTAL_NUMBER 0
-
-#define EPI_BUILD_NUMBER 1
-
-#define EPI_VERSION { 5, 75, 11, 0 }
-
-#ifdef BCMSDIO
-/* EPI_VERSION_NUM must match FW version */
-#define EPI_VERSION_NUM 0x054b0c00
-#else
-#define EPI_VERSION_NUM 0x054b0b00
-#endif
-
-#define EPI_VERSION_DEV 5.75.11
-
-/* Driver Version String, ASCII, 32 chars max */
-#define EPI_VERSION_STR "5.75.11"
-
-#endif /* _epivers_h_ */
diff --git a/drivers/staging/brcm80211/include/hnddma.h b/drivers/staging/brcm80211/include/hnddma.h
index bee4c89be23d..4c5462baf11e 100644
--- a/drivers/staging/brcm80211/include/hnddma.h
+++ b/drivers/staging/brcm80211/include/hnddma.h
@@ -19,7 +19,7 @@
#ifndef _hnddma_pub_
#define _hnddma_pub_
-typedef const struct hnddma_pub hnddma_t;
+struct hnddma_pub;
#endif /* _hnddma_pub_ */
/* range param for dma_getnexttxp() and dma_txreclaim */
@@ -30,52 +30,54 @@ typedef enum txd_range {
} txd_range_t;
/* dma function type */
-typedef void (*di_detach_t) (hnddma_t *dmah);
-typedef bool(*di_txreset_t) (hnddma_t *dmah);
-typedef bool(*di_rxreset_t) (hnddma_t *dmah);
-typedef bool(*di_rxidle_t) (hnddma_t *dmah);
-typedef void (*di_txinit_t) (hnddma_t *dmah);
-typedef bool(*di_txenabled_t) (hnddma_t *dmah);
-typedef void (*di_rxinit_t) (hnddma_t *dmah);
-typedef void (*di_txsuspend_t) (hnddma_t *dmah);
-typedef void (*di_txresume_t) (hnddma_t *dmah);
-typedef bool(*di_txsuspended_t) (hnddma_t *dmah);
-typedef bool(*di_txsuspendedidle_t) (hnddma_t *dmah);
-typedef int (*di_txfast_t) (hnddma_t *dmah, void *p, bool commit);
-typedef int (*di_txunframed_t) (hnddma_t *dmah, void *p, uint len,
+typedef void (*di_detach_t) (struct hnddma_pub *dmah);
+typedef bool(*di_txreset_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxreset_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxidle_t) (struct hnddma_pub *dmah);
+typedef void (*di_txinit_t) (struct hnddma_pub *dmah);
+typedef bool(*di_txenabled_t) (struct hnddma_pub *dmah);
+typedef void (*di_rxinit_t) (struct hnddma_pub *dmah);
+typedef void (*di_txsuspend_t) (struct hnddma_pub *dmah);
+typedef void (*di_txresume_t) (struct hnddma_pub *dmah);
+typedef bool(*di_txsuspended_t) (struct hnddma_pub *dmah);
+typedef bool(*di_txsuspendedidle_t) (struct hnddma_pub *dmah);
+typedef int (*di_txfast_t) (struct hnddma_pub *dmah, struct sk_buff *p,
+ bool commit);
+typedef int (*di_txunframed_t) (struct hnddma_pub *dmah, void *p, uint len,
bool commit);
-typedef void *(*di_getpos_t) (hnddma_t *di, bool direction);
-typedef void (*di_fifoloopbackenable_t) (hnddma_t *dmah);
-typedef bool(*di_txstopped_t) (hnddma_t *dmah);
-typedef bool(*di_rxstopped_t) (hnddma_t *dmah);
-typedef bool(*di_rxenable_t) (hnddma_t *dmah);
-typedef bool(*di_rxenabled_t) (hnddma_t *dmah);
-typedef void *(*di_rx_t) (hnddma_t *dmah);
-typedef bool(*di_rxfill_t) (hnddma_t *dmah);
-typedef void (*di_txreclaim_t) (hnddma_t *dmah, txd_range_t range);
-typedef void (*di_rxreclaim_t) (hnddma_t *dmah);
-typedef unsigned long (*di_getvar_t) (hnddma_t *dmah, const char *name);
-typedef void *(*di_getnexttxp_t) (hnddma_t *dmah, txd_range_t range);
-typedef void *(*di_getnextrxp_t) (hnddma_t *dmah, bool forceall);
-typedef void *(*di_peeknexttxp_t) (hnddma_t *dmah);
-typedef void *(*di_peeknextrxp_t) (hnddma_t *dmah);
-typedef void (*di_rxparam_get_t) (hnddma_t *dmah, u16 *rxoffset,
+typedef void *(*di_getpos_t) (struct hnddma_pub *di, bool direction);
+typedef void (*di_fifoloopbackenable_t) (struct hnddma_pub *dmah);
+typedef bool(*di_txstopped_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxstopped_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxenable_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxenabled_t) (struct hnddma_pub *dmah);
+typedef void *(*di_rx_t) (struct hnddma_pub *dmah);
+typedef bool(*di_rxfill_t) (struct hnddma_pub *dmah);
+typedef void (*di_txreclaim_t) (struct hnddma_pub *dmah, txd_range_t range);
+typedef void (*di_rxreclaim_t) (struct hnddma_pub *dmah);
+typedef unsigned long (*di_getvar_t) (struct hnddma_pub *dmah,
+ const char *name);
+typedef void *(*di_getnexttxp_t) (struct hnddma_pub *dmah, txd_range_t range);
+typedef void *(*di_getnextrxp_t) (struct hnddma_pub *dmah, bool forceall);
+typedef void *(*di_peeknexttxp_t) (struct hnddma_pub *dmah);
+typedef void *(*di_peeknextrxp_t) (struct hnddma_pub *dmah);
+typedef void (*di_rxparam_get_t) (struct hnddma_pub *dmah, u16 *rxoffset,
u16 *rxbufsize);
-typedef void (*di_txblock_t) (hnddma_t *dmah);
-typedef void (*di_txunblock_t) (hnddma_t *dmah);
-typedef uint(*di_txactive_t) (hnddma_t *dmah);
-typedef void (*di_txrotate_t) (hnddma_t *dmah);
-typedef void (*di_counterreset_t) (hnddma_t *dmah);
-typedef uint(*di_ctrlflags_t) (hnddma_t *dmah, uint mask, uint flags);
-typedef char *(*di_dump_t) (hnddma_t *dmah, struct bcmstrbuf *b,
+typedef void (*di_txblock_t) (struct hnddma_pub *dmah);
+typedef void (*di_txunblock_t) (struct hnddma_pub *dmah);
+typedef uint(*di_txactive_t) (struct hnddma_pub *dmah);
+typedef void (*di_txrotate_t) (struct hnddma_pub *dmah);
+typedef void (*di_counterreset_t) (struct hnddma_pub *dmah);
+typedef uint(*di_ctrlflags_t) (struct hnddma_pub *dmah, uint mask, uint flags);
+typedef char *(*di_dump_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b,
bool dumpring);
-typedef char *(*di_dumptx_t) (hnddma_t *dmah, struct bcmstrbuf *b,
+typedef char *(*di_dumptx_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b,
bool dumpring);
-typedef char *(*di_dumprx_t) (hnddma_t *dmah, struct bcmstrbuf *b,
+typedef char *(*di_dumprx_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b,
bool dumpring);
-typedef uint(*di_rxactive_t) (hnddma_t *dmah);
-typedef uint(*di_txpending_t) (hnddma_t *dmah);
-typedef uint(*di_txcommitted_t) (hnddma_t *dmah);
+typedef uint(*di_rxactive_t) (struct hnddma_pub *dmah);
+typedef uint(*di_txpending_t) (struct hnddma_pub *dmah);
+typedef uint(*di_txcommitted_t) (struct hnddma_pub *dmah);
/* dma opsvec */
typedef struct di_fcn_s {
@@ -141,7 +143,8 @@ struct hnddma_pub {
uint txnobuf; /* tx out of dma descriptors */
};
-extern hnddma_t *dma_attach(osl_t *osh, char *name, si_t *sih,
+extern struct hnddma_pub *dma_attach(struct osl_info *osh, char *name,
+ si_t *sih,
void *dmaregstx, void *dmaregsrx, uint ntxd,
uint nrxd, uint rxbufsize, int rxextheadroom,
uint nrxpost, uint rxoffset, uint *msg_level);
@@ -238,6 +241,6 @@ extern const di_fcn_t dma64proc;
extern uint dma_addrwidth(si_t *sih, void *dmaregs);
/* pio helpers */
-extern void dma_txpioloopback(osl_t *osh, dma32regs_t *);
+extern void dma_txpioloopback(struct osl_info *osh, dma32regs_t *);
#endif /* _hnddma_h_ */
diff --git a/drivers/staging/brcm80211/include/hndpmu.h b/drivers/staging/brcm80211/include/hndpmu.h
index bbcf0eecd212..a0110e4c9ac4 100644
--- a/drivers/staging/brcm80211/include/hndpmu.h
+++ b/drivers/staging/brcm80211/include/hndpmu.h
@@ -28,44 +28,44 @@
#define SET_LDO_VOLTAGE_LNLDO1 9
#define SET_LDO_VOLTAGE_LNLDO2_SEL 10
-extern void si_pmu_init(si_t *sih, osl_t *osh);
-extern void si_pmu_chip_init(si_t *sih, osl_t *osh);
-extern void si_pmu_pll_init(si_t *sih, osl_t *osh, u32 xtalfreq);
-extern void si_pmu_res_init(si_t *sih, osl_t *osh);
-extern void si_pmu_swreg_init(si_t *sih, osl_t *osh);
+extern void si_pmu_init(si_t *sih, struct osl_info *osh);
+extern void si_pmu_chip_init(si_t *sih, struct osl_info *osh);
+extern void si_pmu_pll_init(si_t *sih, struct osl_info *osh, u32 xtalfreq);
+extern void si_pmu_res_init(si_t *sih, struct osl_info *osh);
+extern void si_pmu_swreg_init(si_t *sih, struct osl_info *osh);
-extern u32 si_pmu_force_ilp(si_t *sih, osl_t *osh, bool force);
+extern u32 si_pmu_force_ilp(si_t *sih, struct osl_info *osh, bool force);
-extern u32 si_pmu_si_clock(si_t *sih, osl_t *osh);
-extern u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh);
-extern u32 si_pmu_mem_clock(si_t *sih, osl_t *osh);
-extern u32 si_pmu_alp_clock(si_t *sih, osl_t *osh);
-extern u32 si_pmu_ilp_clock(si_t *sih, osl_t *osh);
+extern u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh);
+extern u32 si_pmu_cpu_clock(si_t *sih, struct osl_info *osh);
+extern u32 si_pmu_mem_clock(si_t *sih, struct osl_info *osh);
+extern u32 si_pmu_alp_clock(si_t *sih, struct osl_info *osh);
+extern u32 si_pmu_ilp_clock(si_t *sih, struct osl_info *osh);
-extern void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh,
+extern void si_pmu_set_switcher_voltage(si_t *sih, struct osl_info *osh,
u8 bb_voltage, u8 rf_voltage);
-extern void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo,
+extern void si_pmu_set_ldo_voltage(si_t *sih, struct osl_info *osh, u8 ldo,
u8 voltage);
-extern u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh);
-extern void si_pmu_rcal(si_t *sih, osl_t *osh);
+extern u16 si_pmu_fast_pwrup_delay(si_t *sih, struct osl_info *osh);
+extern void si_pmu_rcal(si_t *sih, struct osl_info *osh);
extern void si_pmu_pllupd(si_t *sih);
-extern void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid);
+extern void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid);
-extern bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh);
-extern u32 si_pmu_measure_alpclk(si_t *sih, osl_t *osh);
+extern bool si_pmu_is_otp_powered(si_t *sih, struct osl_info *osh);
+extern u32 si_pmu_measure_alpclk(si_t *sih, struct osl_info *osh);
extern u32 si_pmu_chipcontrol(si_t *sih, uint reg, u32 mask, u32 val);
extern u32 si_pmu_regcontrol(si_t *sih, uint reg, u32 mask, u32 val);
extern u32 si_pmu_pllcontrol(si_t *sih, uint reg, u32 mask, u32 val);
extern void si_pmu_pllupd(si_t *sih);
-extern void si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable);
+extern void si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable);
extern void si_pmu_radio_enable(si_t *sih, bool enable);
-extern u32 si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh,
+extern u32 si_pmu_waitforclk_on_backplane(si_t *sih, struct osl_info *osh,
u32 clk, u32 delay);
-extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on);
-extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh,
+extern void si_pmu_otp_power(si_t *sih, struct osl_info *osh, bool on);
+extern void si_sdiod_drive_strength_init(si_t *sih, struct osl_info *osh,
u32 drivestrength);
#endif /* _hndpmu_h_ */
diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h
deleted file mode 100644
index c9c860b6e474..000000000000
--- a/drivers/staging/brcm80211/include/linux_osl.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _linux_osl_h_
-#define _linux_osl_h_
-
-
-/* Linux Kernel: File Operations: start */
-extern void *osl_os_open_image(char *filename);
-extern int osl_os_get_image_block(char *buf, int len, void *image);
-extern void osl_os_close_image(void *image);
-/* Linux Kernel: File Operations: end */
-
-extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag);
-extern void osl_detach(osl_t *osh);
-
-extern u32 g_assert_type;
-
-#if defined(BCMDBG_ASSERT)
-#define ASSERT(exp) \
- do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0)
-extern void osl_assert(char *exp, char *file, int line);
-#else
-#ifdef __GNUC__
-#define GCC_VERSION \
- (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#if GCC_VERSION > 30100
-#define ASSERT(exp) do {} while (0)
-#else
- /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */
-#define ASSERT(exp)
-#endif /* GCC_VERSION > 30100 */
-#endif /* __GNUC__ */
-#endif /* defined(BCMDBG_ASSERT) */
-
-/* PCI configuration space access macros */
-#define OSL_PCI_READ_CONFIG(osh, offset, size) \
- osl_pci_read_config((osh), (offset), (size))
-#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \
- osl_pci_write_config((osh), (offset), (size), (val))
-extern u32 osl_pci_read_config(osl_t *osh, uint offset, uint size);
-extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val);
-
-/* PCI device bus # and slot # */
-#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
-#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
-extern uint osl_pci_bus(osl_t *osh);
-extern uint osl_pci_slot(osl_t *osh);
-
-/* Pkttag flag should be part of public information */
-typedef struct {
- bool pkttag;
- uint pktalloced; /* Number of allocated packet buffers */
- bool mmbus; /* Bus supports memory-mapped register accesses */
- pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */
- void *tx_ctx; /* Context to the callback function */
-#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
- osl_rreg_fn_t rreg_fn; /* Read Register function */
- osl_wreg_fn_t wreg_fn; /* Write Register function */
- void *reg_ctx; /* Context to the reg callback functions */
-#endif
-} osl_pubinfo_t;
-
-#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \
- do { \
- ((osl_pubinfo_t *)osh)->tx_fn = _tx_fn; \
- ((osl_pubinfo_t *)osh)->tx_ctx = _tx_ctx; \
- } while (0)
-
-#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
-#define REGOPSSET(osh, rreg, wreg, ctx) \
- do { \
- ((osl_pubinfo_t *)osh)->rreg_fn = rreg; \
- ((osl_pubinfo_t *)osh)->wreg_fn = wreg; \
- ((osl_pubinfo_t *)osh)->reg_ctx = ctx; \
- } while (0)
-#endif
-
-#define BUS_SWAP32(v) (v)
-
-#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align()
-extern uint osl_dma_consistent_align(void);
-extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align,
- uint *tot, unsigned long *pap);
-
-#ifdef BRCM_FULLMAC
-#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \
- osl_dma_alloc_consistent((osh), (size), (0), (tot), (pap))
-#else
-#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \
- osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap))
-#endif /* BRCM_FULLMAC */
-
-#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
- osl_dma_free_consistent((osh), (void *)(va), (size), (pa))
-extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa);
-
-/* map/unmap direction */
-#define DMA_TX 1 /* TX direction for DMA */
-#define DMA_RX 2 /* RX direction for DMA */
-
-/* map/unmap shared (dma-able) memory */
-#define DMA_MAP(osh, va, size, direction, p, dmah) \
- osl_dma_map((osh), (va), (size), (direction))
-#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \
- osl_dma_unmap((osh), (pa), (size), (direction))
-extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction);
-extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction);
-
-/* API for DMA addressing capability */
-#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0)
-
-/* register access macros */
-#if defined(BCMSDIO)
-#ifdef BRCM_FULLMAC
-#include <bcmsdh.h>
-#endif
-#define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v)))
-#define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r))))
-#endif
-
-#if defined(BCMSDIO)
-#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t *)(osh))->mmbus) \
- mmap_op else bus_op
-#define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t *)(osh))->mmbus) ? \
- mmap_op : bus_op
-#else
-#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op
-#define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op
-#endif
-
-#define OSL_ERROR(bcmerror) osl_error(bcmerror)
-extern int osl_error(int bcmerror);
-
-/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
-#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */
-
-#define OSL_SYSUPTIME() ((u32)jiffies * (1000 / HZ))
-#define printf(fmt, args...) printk(fmt , ## args)
-#ifdef BRCM_FULLMAC
-#include <linux/kernel.h> /* for vsn/printf's */
-#include <linux/string.h> /* for mem*, str* */
-#endif
-/* bcopy's: Linux kernel doesn't provide these (anymore) */
-#define bcopy(src, dst, len) memcpy((dst), (src), (len))
-#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
-#define bzero(b, len) memset((b), '\0', (len))
-
-/* register access macros */
-#if defined(OSLREGOPS)
-#else
-#ifndef IL_BIGENDIAN
-#ifndef __mips__
-#define R_REG(osh, r) (\
- SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(u8) ? readb((volatile u8*)(r)) : \
- sizeof(*(r)) == sizeof(u16) ? readw((volatile u16*)(r)) : \
- readl((volatile u32*)(r)), OSL_READ_REG(osh, r)) \
-)
-#else /* __mips__ */
-#define R_REG(osh, r) (\
- SELECT_BUS_READ(osh, \
- ({ \
- __typeof(*(r)) __osl_v; \
- __asm__ __volatile__("sync"); \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- __osl_v = readb((volatile u8*)(r)); \
- break; \
- case sizeof(u16): \
- __osl_v = readw((volatile u16*)(r)); \
- break; \
- case sizeof(u32): \
- __osl_v = \
- readl((volatile u32*)(r)); \
- break; \
- } \
- __asm__ __volatile__("sync"); \
- __osl_v; \
- }), \
- ({ \
- __typeof(*(r)) __osl_v; \
- __asm__ __volatile__("sync"); \
- __osl_v = OSL_READ_REG(osh, r); \
- __asm__ __volatile__("sync"); \
- __osl_v; \
- })) \
-)
-#endif /* __mips__ */
-
-#define W_REG(osh, r, v) do { \
- SELECT_BUS_WRITE(osh, \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- writeb((u8)(v), (volatile u8*)(r)); break; \
- case sizeof(u16): \
- writew((u16)(v), (volatile u16*)(r)); break; \
- case sizeof(u32): \
- writel((u32)(v), (volatile u32*)(r)); break; \
- }, \
- (OSL_WRITE_REG(osh, r, v))); \
- } while (0)
-#else /* IL_BIGENDIAN */
-#define R_REG(osh, r) (\
- SELECT_BUS_READ(osh, \
- ({ \
- __typeof(*(r)) __osl_v; \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- __osl_v = \
- readb((volatile u8*)((r)^3)); \
- break; \
- case sizeof(u16): \
- __osl_v = \
- readw((volatile u16*)((r)^2)); \
- break; \
- case sizeof(u32): \
- __osl_v = readl((volatile u32*)(r)); \
- break; \
- } \
- __osl_v; \
- }), \
- OSL_READ_REG(osh, r)) \
-)
-#define W_REG(osh, r, v) do { \
- SELECT_BUS_WRITE(osh, \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- writeb((u8)(v), \
- (volatile u8*)((r)^3)); break; \
- case sizeof(u16): \
- writew((u16)(v), \
- (volatile u16*)((r)^2)); break; \
- case sizeof(u32): \
- writel((u32)(v), \
- (volatile u32*)(r)); break; \
- }, \
- (OSL_WRITE_REG(osh, r, v))); \
- } while (0)
-#endif /* IL_BIGENDIAN */
-
-#endif /* OSLREGOPS */
-
-#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
-#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
-
-/* bcopy, bcmp, and bzero functions */
-#define bcopy(src, dst, len) memcpy((dst), (src), (len))
-#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
-#define bzero(b, len) memset((b), '\0', (len))
-
-/* uncached/cached virtual address */
-#ifdef __mips__
-#include <asm/addrspace.h>
-#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va)))
-#define OSL_CACHED(va) ((void *)KSEG0ADDR((va)))
-#else
-#define OSL_UNCACHED(va) ((void *)va)
-#define OSL_CACHED(va) ((void *)va)
-#endif /* mips */
-
-#if defined(mips)
-#define OSL_GETCYCLES(x) ((x) = read_c0_count() * 2)
-#elif defined(__i386__)
-#define OSL_GETCYCLES(x) rdtscl((x))
-#else
-#define OSL_GETCYCLES(x) ((x) = 0)
-#endif /* defined(mips) */
-
-/* dereference an address that may cause a bus exception */
-#ifdef mips
-#define BUSPROBE(val, addr) get_dbe((val), (addr))
-#include <asm/paccess.h>
-#else
-#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; })
-#endif /* mips */
-
-/* map/unmap physical to virtual I/O */
-#if !defined(CONFIG_MMC_MSM7X00A)
-#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
-#else
-#define REG_MAP(pa, size) (void *)(0)
-#endif /* !defined(CONFIG_MMC_MSM7X00A */
-#define REG_UNMAP(va) iounmap((va))
-
-#define R_SM(r) (*(r))
-#define W_SM(r, v) (*(r) = (v))
-#define BZERO_SM(r, len) memset((r), '\0', (len))
-
-#ifdef BRCM_FULLMAC
-#include <linuxver.h> /* use current 2.4.x calling conventions */
-#endif
-
-/* packet primitives */
-#define PKTGET(osh, len, send) osl_pktget((osh), (len))
-#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
-#define PKTDATA(skb) (((struct sk_buff *)(skb))->data)
-#define PKTLEN(skb) (((struct sk_buff *)(skb))->len)
-#define PKTHEADROOM(skb) (PKTDATA(skb)-(((struct sk_buff *)(skb))->head))
-#define PKTTAILROOM(skb) ((((struct sk_buff *)(skb))->end)-(((struct sk_buff *)(skb))->tail))
-#define PKTNEXT(skb) (((struct sk_buff *)(skb))->next)
-#define PKTSETNEXT(skb, x) \
- (((struct sk_buff *)(skb))->next = (struct sk_buff *)(x))
-#define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len))
-#define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes))
-#define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes))
-#define PKTTAG(skb) ((void *)(((struct sk_buff *)(skb))->cb))
-#define PKTALLOCED(osh) (((osl_pubinfo_t *)(osh))->pktalloced)
-#define PKTSETPOOL(osh, skb, x, y) do {} while (0)
-#define PKTPOOL(osh, skb) false
-extern void *osl_pktget(osl_t *osh, uint len);
-extern void osl_pktfree(osl_t *osh, void *skb, bool send);
-
-#ifdef BRCM_FULLMAC
-extern void *osl_pktget_static(osl_t *osh, uint len);
-extern void osl_pktfree_static(osl_t *osh, void *skb, bool send);
-
-static inline void *
-osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb)
-{
- struct sk_buff *nskb;
-
- if (osh->pkttag)
- bzero((void *)skb->cb, OSL_PKTTAG_SZ);
-
- for (nskb = skb; nskb; nskb = nskb->next)
- osh->pktalloced++;
-
- return (void *)skb;
-}
-#define PKTFRMNATIVE(osh, skb) \
- osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb))
-
-static inline struct sk_buff *
-osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt)
-{
- struct sk_buff *nskb;
-
- if (osh->pkttag)
- bzero(((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ);
-
- for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next)
- osh->pktalloced--;
-
- return (struct sk_buff *)pkt;
-}
-#define PKTTONATIVE(osh, pkt) \
- osl_pkt_tonative((osl_pubinfo_t *)(osh), (pkt))
-#else /* !BRCM_FULLMAC */
-#define PKTUNALLOC(osh) (((osl_pubinfo_t *)(osh))->pktalloced--)
-
-#define PKTSETSKIPCT(osh, skb)
-#define PKTCLRSKIPCT(osh, skb)
-#define PKTSKIPCT(osh, skb)
-#endif /* BRCM_FULLMAC */
-
-#define PKTLINK(skb) (((struct sk_buff *)(skb))->prev)
-#define PKTSETLINK(skb, x) (((struct sk_buff *)(skb))->prev = (struct sk_buff*)(x))
-#define PKTPRIO(skb) (((struct sk_buff *)(skb))->priority)
-#define PKTSETPRIO(skb, x) (((struct sk_buff *)(skb))->priority = (x))
-#define PKTSUMNEEDED(skb) (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL)
-#define PKTSETSUMGOOD(skb, x) (((struct sk_buff *)(skb))->ip_summed = \
- ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
-/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */
-#define PKTSHARED(skb) (((struct sk_buff *)(skb))->cloned)
-
-#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
-#define RPC_READ_REG(osh, r) (\
- sizeof(*(r)) == sizeof(u8) ? osl_readb((osh), (volatile u8*)(r)) : \
- sizeof(*(r)) == sizeof(u16) ? osl_readw((osh), (volatile u16*)(r)) : \
- osl_readl((osh), (volatile u32*)(r)) \
-)
-#define RPC_WRITE_REG(osh, r, v) do { \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- osl_writeb((osh), (volatile u8*)(r), (u8)(v)); \
- break; \
- case sizeof(u16): \
- osl_writew((osh), (volatile u16*)(r), (u16)(v)); \
- break; \
- case sizeof(u32): \
- osl_writel((osh), (volatile u32*)(r), (u32)(v)); \
- break; \
- } \
-} while (0)
-
-extern u8 osl_readb(osl_t *osh, volatile u8 *r);
-extern u16 osl_readw(osl_t *osh, volatile u16 *r);
-extern u32 osl_readl(osl_t *osh, volatile u32 *r);
-extern void osl_writeb(osl_t *osh, volatile u8 *r, u8 v);
-extern void osl_writew(osl_t *osh, volatile u16 *r, u16 v);
-extern void osl_writel(osl_t *osh, volatile u32 *r, u32 v);
-#endif /* BCMSDIO */
-
-#endif /* _linux_osl_h_ */
diff --git a/drivers/staging/brcm80211/include/linuxver.h b/drivers/staging/brcm80211/include/linuxver.h
deleted file mode 100644
index dc721413ee29..000000000000
--- a/drivers/staging/brcm80211/include/linuxver.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _linuxver_h_
-#define _linuxver_h_
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/ieee80211.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-
-#undef IP_TOS
-#include <asm/io.h>
-
-#endif /* _linuxver_h_ */
diff --git a/drivers/staging/brcm80211/include/nicpci.h b/drivers/staging/brcm80211/include/nicpci.h
index ce146e88ffdf..928818daedd7 100644
--- a/drivers/staging/brcm80211/include/nicpci.h
+++ b/drivers/staging/brcm80211/include/nicpci.h
@@ -45,17 +45,17 @@
#else
struct sbpcieregs;
-extern u8 pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id,
+extern u8 pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id,
unsigned char *buf, u32 *buflen);
-extern uint pcie_readreg(osl_t *osh, struct sbpcieregs *pcieregs,
+extern uint pcie_readreg(struct osl_info *osh, struct sbpcieregs *pcieregs,
uint addrtype, uint offset);
-extern uint pcie_writereg(osl_t *osh, struct sbpcieregs *pcieregs,
+extern uint pcie_writereg(struct osl_info *osh, struct sbpcieregs *pcieregs,
uint addrtype, uint offset, uint val);
extern u8 pcie_clkreq(void *pch, u32 mask, u32 val);
extern u32 pcie_lcreg(void *pch, u32 mask, u32 val);
-extern void *pcicore_init(si_t *sih, osl_t *osh, void *regs);
+extern void *pcicore_init(si_t *sih, struct osl_info *osh, void *regs);
extern void pcicore_deinit(void *pch);
extern void pcicore_attach(void *pch, char *pvars, int state);
extern void pcicore_hwup(void *pch);
@@ -70,10 +70,10 @@ extern u32 pcicore_pcieserdesreg(void *pch, u32 mdioslave, u32 offset,
extern u32 pcicore_pciereg(void *pch, u32 offset, u32 mask,
u32 val, uint type);
-extern bool pcicore_pmecap_fast(osl_t *osh);
+extern bool pcicore_pmecap_fast(struct osl_info *osh);
extern void pcicore_pmeen(void *pch);
extern void pcicore_pmeclr(void *pch);
extern bool pcicore_pmestat(void *pch);
-#endif /* defined(BCMSDIO) || (defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)) */
+#endif /* defined(BCMSDIO)||(defined(BCMBUSTYPE) && (BCMBUSTYPE==SI_BUS)) */
#endif /* _NICPCI_H */
diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h
index c0ebb3d97220..b28235618d8b 100644
--- a/drivers/staging/brcm80211/include/osl.h
+++ b/drivers/staging/brcm80211/include/osl.h
@@ -18,42 +18,197 @@
#define _osl_h_
/* osl handle type forward declaration */
-typedef struct osl_info osl_t;
+struct osl_info {
+ uint pktalloced; /* Number of allocated packet buffers */
+ bool mmbus; /* Bus supports memory-mapped registers */
+ uint magic;
+ void *pdev;
+ uint bustype;
+};
+
typedef struct osl_dmainfo osldma_t;
-#define OSL_PKTTAG_SZ 32 /* Size of PktTag */
-/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */
-typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status);
+extern struct osl_info *osl_attach(void *pdev, uint bustype);
+extern void osl_detach(struct osl_info *osh);
-#ifdef BCMSDIO
-/* Drivers use REGOPSSET() to register register read/write funcitons */
-typedef unsigned int (*osl_rreg_fn_t) (void *ctx, void *reg, unsigned int size);
-typedef void (*osl_wreg_fn_t) (void *ctx, void *reg, unsigned int val,
- unsigned int size);
-#endif
+extern u32 g_assert_type;
-#include <linux_osl.h>
+#if defined(BCMDBG_ASSERT)
+#define ASSERT(exp) \
+ do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0)
+extern void osl_assert(char *exp, char *file, int line);
+#else
+#define ASSERT(exp) do {} while (0)
+#endif /* defined(BCMDBG_ASSERT) */
-/* --------------------------------------------------------------------------
-** Register manipulation macros.
-*/
+/* PCI device bus # and slot # */
+#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
+#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
+extern uint osl_pci_bus(struct osl_info *osh);
+extern uint osl_pci_slot(struct osl_info *osh);
-#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val)))
+#define BUS_SWAP32(v) (v)
-#ifndef AND_REG
-#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
-#endif /* !AND_REG */
+extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size,
+ u16 align, uint *tot, unsigned long *pap);
+
+#ifdef BRCM_FULLMAC
+#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \
+ osl_dma_alloc_consistent((osh), (size), (0), (tot), (pap))
+#else
+#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \
+ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap))
+#endif /* BRCM_FULLMAC */
-#ifndef OR_REG
-#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
-#endif /* !OR_REG */
+#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
+ osl_dma_free_consistent((osh), (void *)(va), (size), (pa))
+extern void osl_dma_free_consistent(struct osl_info *osh, void *va,
+ uint size, unsigned long pa);
+
+/* map/unmap direction */
+#define DMA_TX 1 /* TX direction for DMA */
+#define DMA_RX 2 /* RX direction for DMA */
+
+/* map/unmap shared (dma-able) memory */
+#define DMA_MAP(osh, va, size, direction, p, dmah) \
+ osl_dma_map((osh), (va), (size), (direction))
+#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \
+ osl_dma_unmap((osh), (pa), (size), (direction))
+extern uint osl_dma_map(struct osl_info *osh, void *va, uint size,
+ int direction);
+extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size,
+ int direction);
+
+/* register access macros */
+#if defined(BCMSDIO)
+#ifdef BRCM_FULLMAC
+#include <bcmsdh.h>
+#endif
+#define OSL_WRITE_REG(osh, r, v) \
+ (bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v)))
+#define OSL_READ_REG(osh, r) \
+ (bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r))))
+#endif
-#if !defined(OSL_SYSUPTIME)
-#define OSL_SYSUPTIME() (0)
-#define OSL_SYSUPTIME_SUPPORT false
+#if defined(BCMSDIO)
+#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) \
+ if ((osh)->mmbus) \
+ mmap_op else bus_op
+#define SELECT_BUS_READ(osh, mmap_op, bus_op) \
+ ((osh)->mmbus) ? mmap_op : bus_op
#else
-#define OSL_SYSUPTIME_SUPPORT true
-#endif /* OSL_SYSUPTIME */
+#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op
+#define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op
+#endif
+
+/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
+#define PKTBUFSZ 2048
+
+#define OSL_SYSUPTIME() ((u32)jiffies * (1000 / HZ))
+#define printf(fmt, args...) printk(fmt , ## args)
+#ifdef BRCM_FULLMAC
+#include <linux/kernel.h> /* for vsn/printf's */
+#include <linux/string.h> /* for mem*, str* */
+#endif
+/* bcopy's: Linux kernel doesn't provide these (anymore) */
+#define bcopy(src, dst, len) memcpy((dst), (src), (len))
+
+/* register access macros */
+#ifndef IL_BIGENDIAN
+#ifndef __mips__
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(u8) ? \
+ readb((volatile u8*)(r)) : \
+ sizeof(*(r)) == sizeof(u16) ? readw((volatile u16*)(r)) : \
+ readl((volatile u32*)(r)), OSL_READ_REG(osh, r)) \
+)
+#else /* __mips__ */
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ __asm__ __volatile__("sync"); \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ __osl_v = readb((volatile u8*)(r)); \
+ break; \
+ case sizeof(u16): \
+ __osl_v = readw((volatile u16*)(r)); \
+ break; \
+ case sizeof(u32): \
+ __osl_v = \
+ readl((volatile u32*)(r)); \
+ break; \
+ } \
+ __asm__ __volatile__("sync"); \
+ __osl_v; \
+ }), \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ __asm__ __volatile__("sync"); \
+ __osl_v = OSL_READ_REG(osh, r); \
+ __asm__ __volatile__("sync"); \
+ __osl_v; \
+ })) \
+)
+#endif /* __mips__ */
+
+#define W_REG(osh, r, v) do { \
+ SELECT_BUS_WRITE(osh, \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ writeb((u8)(v), (volatile u8*)(r)); break; \
+ case sizeof(u16): \
+ writew((u16)(v), (volatile u16*)(r)); break; \
+ case sizeof(u32): \
+ writel((u32)(v), (volatile u32*)(r)); break; \
+ }, \
+ (OSL_WRITE_REG(osh, r, v))); \
+ } while (0)
+#else /* IL_BIGENDIAN */
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ __osl_v = \
+ readb((volatile u8*)((r)^3)); \
+ break; \
+ case sizeof(u16): \
+ __osl_v = \
+ readw((volatile u16*)((r)^2)); \
+ break; \
+ case sizeof(u32): \
+ __osl_v = readl((volatile u32*)(r)); \
+ break; \
+ } \
+ __osl_v; \
+ }), \
+ OSL_READ_REG(osh, r)) \
+)
+#define W_REG(osh, r, v) do { \
+ SELECT_BUS_WRITE(osh, \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ writeb((u8)(v), \
+ (volatile u8*)((r)^3)); break; \
+ case sizeof(u16): \
+ writew((u16)(v), \
+ (volatile u16*)((r)^2)); break; \
+ case sizeof(u32): \
+ writel((u32)(v), \
+ (volatile u32*)(r)); break; \
+ }, \
+ (OSL_WRITE_REG(osh, r, v))); \
+ } while (0)
+#endif /* IL_BIGENDIAN */
+
+#define bcopy(src, dst, len) memcpy((dst), (src), (len))
+
+/* packet primitives */
+extern struct sk_buff *pkt_buf_get_skb(struct osl_info *osh, uint len);
+extern void pkt_buf_free_skb(struct osl_info *osh, struct sk_buff *skb, bool send);
-#endif /* _osl_h_ */
+#endif /* _osl_h_ */
diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h
index cc17b428dd3f..567407de020e 100644
--- a/drivers/staging/brcm80211/include/proto/ethernet.h
+++ b/drivers/staging/brcm80211/include/proto/ethernet.h
@@ -17,28 +17,22 @@
#ifndef _NET_ETHERNET_H_
#define _NET_ETHERNET_H_
+#include <linux/if_ether.h>
+
#include <packed_section_start.h>
-#define ETHER_ADDR_LEN 6
#define ETHER_TYPE_LEN 2
#define ETHER_CRC_LEN 4
-#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
#define ETHER_MIN_LEN 64
#define ETHER_MIN_DATA 46
#define ETHER_MAX_LEN 1518
#define ETHER_MAX_DATA 1500
-#define ETHER_TYPE_MIN 0x0600
-#define ETHER_TYPE_IP 0x0800
-#define ETHER_TYPE_ARP 0x0806
-#define ETHER_TYPE_8021Q 0x8100
#define ETHER_TYPE_BRCM 0x886c
-#define ETHER_TYPE_802_1X 0x888e
-#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
-#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN)
-#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN)
-#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN)
+#define ETHER_DEST_OFFSET (0 * ETH_ALEN)
+#define ETHER_SRC_OFFSET (1 * ETH_ALEN)
+#define ETHER_TYPE_OFFSET (2 * ETH_ALEN)
#define ETHER_IS_VALID_LEN(foo) \
((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
@@ -53,50 +47,18 @@
}
BWL_PRE_PACKED_STRUCT struct ether_header {
- u8 ether_dhost[ETHER_ADDR_LEN];
- u8 ether_shost[ETHER_ADDR_LEN];
+ u8 ether_dhost[ETH_ALEN];
+ u8 ether_shost[ETH_ALEN];
u16 ether_type;
} BWL_POST_PACKED_STRUCT;
BWL_PRE_PACKED_STRUCT struct ether_addr {
- u8 octet[ETHER_ADDR_LEN];
+ u8 octet[ETH_ALEN];
} BWL_POST_PACKED_STRUCT;
-#define ETHER_SET_LOCALADDR(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] | 2))
-#define ETHER_IS_LOCALADDR(ea) (((u8 *)(ea))[0] & 2)
-#define ETHER_CLR_LOCALADDR(ea) (((u8 *)(ea))[0] = \
- (((u8 *)(ea))[0] & 0xd))
-#define ETHER_TOGGLE_LOCALADDR(ea) (((u8 *)(ea))[0] = \
- (((u8 *)(ea))[0] ^ 2))
-
#define ETHER_SET_UNICAST(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] & ~1))
-#define ETHER_ISMULTI(ea) (((const u8 *)(ea))[0] & 1)
-
-#define ether_cmp(a, b) (!(((short *)a)[0] == ((short *)b)[0]) | \
- !(((short *)a)[1] == ((short *)b)[1]) | \
- !(((short *)a)[2] == ((short *)b)[2]))
-
-#define ether_copy(s, d) { \
- ((short *)d)[0] = ((short *)s)[0]; \
- ((short *)d)[1] = ((short *)s)[1]; \
- ((short *)d)[2] = ((short *)s)[2]; }
-
static const struct ether_addr ether_bcast = { {255, 255, 255, 255, 255, 255} };
-static const struct ether_addr ether_null = { {0, 0, 0, 0, 0, 0} };
-
-#define ETHER_ISBCAST(ea) ((((u8 *)(ea))[0] & \
- ((u8 *)(ea))[1] & \
- ((u8 *)(ea))[2] & \
- ((u8 *)(ea))[3] & \
- ((u8 *)(ea))[4] & \
- ((u8 *)(ea))[5]) == 0xff)
-#define ETHER_ISNULLADDR(ea) ((((u8 *)(ea))[0] | \
- ((u8 *)(ea))[1] | \
- ((u8 *)(ea))[2] | \
- ((u8 *)(ea))[3] | \
- ((u8 *)(ea))[4] | \
- ((u8 *)(ea))[5]) == 0)
#define ETHER_MOVE_HDR(d, s) \
do { \
diff --git a/drivers/staging/brcm80211/include/proto/wpa.h b/drivers/staging/brcm80211/include/proto/wpa.h
index ec84c9f2b5ee..10c2fb62df09 100644
--- a/drivers/staging/brcm80211/include/proto/wpa.h
+++ b/drivers/staging/brcm80211/include/proto/wpa.h
@@ -19,95 +19,7 @@
#include <proto/ethernet.h>
-#include <packed_section_start.h>
-
-#define DOT11_RC_INVALID_WPA_IE 13
-#define DOT11_RC_MIC_FAILURE 14
-#define DOT11_RC_4WH_TIMEOUT 15
-#define DOT11_RC_GTK_UPDATE_TIMEOUT 16
-#define DOT11_RC_WPA_IE_MISMATCH 17
-#define DOT11_RC_INVALID_MC_CIPHER 18
-#define DOT11_RC_INVALID_UC_CIPHER 19
-#define DOT11_RC_INVALID_AKMP 20
-#define DOT11_RC_BAD_WPA_VERSION 21
-#define DOT11_RC_INVALID_WPA_CAP 22
-#define DOT11_RC_8021X_AUTH_FAIL 23
-
#define WPA2_PMKID_LEN 16
-
-typedef BWL_PRE_PACKED_STRUCT struct {
- u8 tag;
- u8 length;
- u8 oui[3];
- u8 oui_type;
- BWL_PRE_PACKED_STRUCT struct {
- u8 low;
- u8 high;
- } BWL_POST_PACKED_STRUCT version;
-} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t;
-#define WPA_IE_OUITYPE_LEN 4
-#define WPA_IE_FIXED_LEN 8
-#define WPA_IE_TAG_FIXED_LEN 6
-
-typedef BWL_PRE_PACKED_STRUCT struct {
- u8 tag;
- u8 length;
- BWL_PRE_PACKED_STRUCT struct {
- u8 low;
- u8 high;
- } BWL_POST_PACKED_STRUCT version;
-} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t;
-#define WPA_RSN_IE_FIXED_LEN 4
-#define WPA_RSN_IE_TAG_FIXED_LEN 2
-typedef u8 wpa_pmkid_t[WPA2_PMKID_LEN];
-
-typedef BWL_PRE_PACKED_STRUCT struct {
- u8 oui[3];
- u8 type;
-} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t;
-#define WPA_SUITE_LEN 4
-
-typedef BWL_PRE_PACKED_STRUCT struct {
- BWL_PRE_PACKED_STRUCT struct {
- u8 low;
- u8 high;
- } BWL_POST_PACKED_STRUCT count;
- wpa_suite_t list[1];
-} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
-#define WPA_IE_SUITE_COUNT_LEN 2
-typedef BWL_PRE_PACKED_STRUCT struct {
- BWL_PRE_PACKED_STRUCT struct {
- u8 low;
- u8 high;
- } BWL_POST_PACKED_STRUCT count;
- wpa_pmkid_t list[1];
-} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t;
-
-#define WPA_CIPHER_NONE 0
-#define WPA_CIPHER_WEP_40 1
-#define WPA_CIPHER_TKIP 2
-#define WPA_CIPHER_AES_OCB 3
-#define WPA_CIPHER_AES_CCM 4
-#define WPA_CIPHER_WEP_104 5
-
-#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \
- (cipher) == WPA_CIPHER_WEP_40 || \
- (cipher) == WPA_CIPHER_WEP_104 || \
- (cipher) == WPA_CIPHER_TKIP || \
- (cipher) == WPA_CIPHER_AES_OCB || \
- (cipher) == WPA_CIPHER_AES_CCM)
-
-#define WPA_TKIP_CM_DETECT 60
-#define WPA_TKIP_CM_BLOCK 60
-
-#define RSN_CAP_LEN 2
-
-#define RSN_CAP_PREAUTH 0x0001
-#define RSN_CAP_NOPAIRWISE 0x0002
-#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
-#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2
-#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030
-#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4
#define RSN_CAP_1_REPLAY_CNTR 0
#define RSN_CAP_2_REPLAY_CNTRS 1
#define RSN_CAP_4_REPLAY_CNTRS 2
@@ -118,10 +30,4 @@ typedef BWL_PRE_PACKED_STRUCT struct {
#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT
#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK
-#define WPA_CAP_LEN RSN_CAP_LEN
-
-#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
-
-#include <packed_section_end.h>
-
#endif /* _proto_wpa_h_ */
diff --git a/drivers/staging/brcm80211/include/rpc_osl.h b/drivers/staging/brcm80211/include/rpc_osl.h
index 4a2648001bf0..c59d9ed1397a 100644
--- a/drivers/staging/brcm80211/include/rpc_osl.h
+++ b/drivers/staging/brcm80211/include/rpc_osl.h
@@ -18,7 +18,7 @@
#define _rpcosl_h_
typedef struct rpc_osl rpc_osl_t;
-extern rpc_osl_t *rpc_osl_attach(osl_t *osh);
+extern rpc_osl_t *rpc_osl_attach(struct osl_info *osh);
extern void rpc_osl_detach(rpc_osl_t *rpc_osh);
#define RPC_OSL_LOCK(rpc_osh) rpc_osl_lock((rpc_osh))
diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h
index 57c36507a040..a935092d02df 100644
--- a/drivers/staging/brcm80211/include/siutils.h
+++ b/drivers/staging/brcm80211/include/siutils.h
@@ -19,9 +19,6 @@
#include <hndsoc.h>
-#if !defined(WLC_LOW)
-#include "bcm_rpc.h"
-#endif
/*
* Data structure to export all chip specific common variables
* public (read-only) portion of siutils handle returned by si_attach()
@@ -50,19 +47,12 @@ struct si_pub {
uint socirev; /* SOC interconnect rev */
bool pci_pr32414;
-#if !defined(WLC_LOW)
- rpc_info_t *rpc;
-#endif
};
/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver
* for monolithic driver, it is readonly to prevent accident change
*/
-#if !defined(WLC_LOW)
-typedef struct si_pub si_t;
-#else
typedef const struct si_pub si_t;
-#endif
/*
* Many of the routines below take an 'sih' handle as their first arg.
@@ -128,8 +118,8 @@ typedef void (*gpio_handler_t) (u32 stat, void *arg);
#define GPIO_CTRL_EPA_EN_MASK 0x40
/* === exported functions === */
-extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
- void *sdh, char **vars, uint *varsz);
+extern si_t *si_attach(uint pcidev, struct osl_info *osh, void *regs,
+ uint bustype, void *sdh, char **vars, uint *varsz);
extern void si_detach(si_t *sih);
extern bool si_pci_war16165(si_t *sih);
@@ -138,7 +128,7 @@ extern uint si_coreid(si_t *sih);
extern uint si_flag(si_t *sih);
extern uint si_coreidx(si_t *sih);
extern uint si_corerev(si_t *sih);
-extern void *si_osh(si_t *sih);
+struct osl_info *si_osh(si_t *sih);
extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask,
uint val);
extern void si_write_wrapperreg(si_t *sih, u32 offset, u32 val);
@@ -227,7 +217,7 @@ typedef struct gpioh_item {
/* misc si info needed by some of the routines */
typedef struct si_info {
struct si_pub pub; /* back plane public state (must be first field) */
- void *osh; /* osl os handle */
+ struct osl_info *osh; /* osl os handle */
void *sdh; /* bcmsdh handle */
uint dev_coreid; /* the core provides driver functions */
void *intr_arg; /* interrupt callback function arg */
@@ -305,9 +295,9 @@ typedef struct si_info {
#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
-#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
+#define PCI(si) (((si)->pub.bustype == PCI_BUS) && \
((si)->pub.buscoretype == PCI_CORE_ID))
-#define PCIE(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
+#define PCIE(si) (((si)->pub.bustype == PCI_BUS) && \
((si)->pub.buscoretype == PCIE_CORE_ID))
#define PCI_FORCEHT(si) \
(PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID))
@@ -344,9 +334,9 @@ extern void si_epa_4313war(si_t *sih);
char *si_getnvramflvar(si_t *sih, const char *name);
/* AMBA Interconnect exported externs */
-extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
- void *sdh, char **vars, uint *varsz);
-extern si_t *ai_kattach(osl_t *osh);
+extern si_t *ai_attach(uint pcidev, struct osl_info *osh, void *regs,
+ uint bustype, void *sdh, char **vars, uint *varsz);
+extern si_t *ai_kattach(struct osl_info *osh);
extern void ai_scan(si_t *sih, void *regs, uint devid);
extern uint ai_flag(si_t *sih);
diff --git a/drivers/staging/brcm80211/include/wlioctl.h b/drivers/staging/brcm80211/include/wlioctl.h
index 96866fb8898c..9be793c5f10c 100644
--- a/drivers/staging/brcm80211/include/wlioctl.h
+++ b/drivers/staging/brcm80211/include/wlioctl.h
@@ -33,82 +33,9 @@
#define BWL_DEFAULT_PACKING
#include <packed_section_start.h>
-/* Legacy structure to help keep backward compatible wl tool and tray app */
-
-#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */
-
-typedef struct wl_bss_info_107 {
- u32 version; /* version field */
- u32 length; /* byte length of data in this record,
- * starting at version and including IEs
- */
- struct ether_addr BSSID;
- u16 beacon_period; /* units are Kusec */
- u16 capability; /* Capability information */
- u8 SSID_len;
- u8 SSID[32];
- struct {
- uint count; /* # rates in this set */
- u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
- } rateset; /* supported rates */
- u8 channel; /* Channel no. */
- u16 atim_window; /* units are Kusec */
- u8 dtim_period; /* DTIM period */
- s16 RSSI; /* receive signal strength (in dBm) */
- s8 phy_noise; /* noise (in dBm) */
- u32 ie_length; /* byte length of Information Elements */
- /* variable length Information Elements */
-} wl_bss_info_107_t;
-
-/*
- * Per-BSS information structure.
- */
-
-#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */
-
-/* BSS info structure
- * Applications MUST CHECK ie_offset field and length field to access IEs and
- * next bss_info structure in a vector (in wl_scan_results_t)
- */
-typedef struct wl_bss_info_108 {
- u32 version; /* version field */
- u32 length; /* byte length of data in this record,
- * starting at version and including IEs
- */
- struct ether_addr BSSID;
- u16 beacon_period; /* units are Kusec */
- u16 capability; /* Capability information */
- u8 SSID_len;
- u8 SSID[32];
- struct {
- uint count; /* # rates in this set */
- u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
- } rateset; /* supported rates */
- chanspec_t chanspec; /* chanspec for bss */
- u16 atim_window; /* units are Kusec */
- u8 dtim_period; /* DTIM period */
- s16 RSSI; /* receive signal strength (in dBm) */
- s8 phy_noise; /* noise (in dBm) */
-
- u8 n_cap; /* BSS is 802.11N Capable */
- u32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */
- u8 ctl_ch; /* 802.11N BSS control channel number */
- u32 reserved32[1]; /* Reserved for expansion of BSS properties */
- u8 flags; /* flags */
- u8 reserved[3]; /* Reserved for expansion of BSS properties */
- u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
-
- u16 ie_offset; /* offset at which IEs start, from beginning */
- u32 ie_length; /* byte length of Information Elements */
- /* Add new fields here */
- /* variable length Information Elements */
-} wl_bss_info_108_t;
-
#ifdef BRCM_FULLMAC
+
#define WL_BSS_INFO_VERSION 108 /* current ver of wl_bss_info struct */
-#else
-#define WL_BSS_INFO_VERSION 109 /* current ver of wl_bss_info struct */
-#endif
/* BSS info structure
* Applications MUST CHECK ie_offset field and length field to access IEs and
@@ -148,12 +75,14 @@ typedef struct wl_bss_info {
/* Add new fields here */
/* variable length Information Elements */
} wl_bss_info_t;
+#endif /* BRCM_FULLMAC */
typedef struct wlc_ssid {
u32 SSID_len;
unsigned char SSID[32];
} wlc_ssid_t;
+#ifdef BRCM_FULLMAC
typedef struct chan_scandata {
u8 txpower;
u8 pad;
@@ -308,6 +237,7 @@ typedef struct wl_probe_params {
struct ether_addr bssid;
struct ether_addr mac;
} wl_probe_params_t;
+#endif /* BRCM_FULLMAC */
#define WL_NUMRATES 16 /* max # of rates in a rateset */
typedef struct wl_rateset {
@@ -315,6 +245,7 @@ typedef struct wl_rateset {
u8 rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */
} wl_rateset_t;
+#ifdef BRCM_FULLMAC
typedef struct wl_rateset_args {
u32 count; /* # rates in this set */
u8 rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */
@@ -352,6 +283,8 @@ typedef struct wl_join_params {
} wl_join_params_t;
#define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t))
+#endif /* BRCM_FULLMAC */
+
/* defines used by the nrate iovar */
#define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */
#define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */
@@ -391,6 +324,7 @@ typedef struct {
#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
+#ifdef BRCM_FULLMAC
#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */
#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */
@@ -428,8 +362,11 @@ typedef struct {
cca_congest_t secs[1]; /* Data */
} cca_congest_channel_req_t;
+#endif /* BRCM_FULLMAC */
+
#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */
+#ifdef BRCM_FULLMAC
typedef struct wl_country {
char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in
* the Country IE
@@ -516,6 +453,7 @@ typedef struct wl_rm_rep {
wl_rm_rep_elt_t rep[1]; /* variable length block of reports */
} wl_rm_rep_t;
#define WL_RM_REP_FIXED_LEN 8
+#endif /* BRCM_FULLMAC */
/* Enumerate crypto algorithms */
#define CRYPTO_ALGO_OFF 0
@@ -621,28 +559,6 @@ typedef struct wl_led_info {
u8 activehi;
} wl_led_info_t;
-/* flags */
-#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */
-
-/* srom read/write struct passed through ioctl */
-typedef struct {
- uint byteoff; /* byte offset */
- uint nbytes; /* number of bytes */
- u16 buf[1];
-} srom_rw_t;
-
-/* similar cis (srom or otp) struct [iovar: may not be aligned] */
-typedef struct {
- u32 source; /* cis source */
- u32 byteoff; /* byte offset */
- u32 nbytes; /* number of bytes */
- /* data follows here */
-} cis_rw_t;
-
-#define WLC_CIS_DEFAULT 0 /* built-in default */
-#define WLC_CIS_SROM 1 /* source is sprom */
-#define WLC_CIS_OTP 2 /* source is otp */
-
/* R_REG and W_REG struct passed through ioctl */
typedef struct {
u32 byteoff; /* byte offset of the field in d11regs_t */
@@ -651,102 +567,14 @@ typedef struct {
uint band; /* band (optional) */
} rw_reg_t;
-/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */
-/* PCL - Power Control Loop */
-/* current gain setting is replaced by user input */
-#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */
-#define WL_ATTEN_PCL_ON 1 /* turn on PCL */
-/* current gain setting is maintained */
-#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */
-
-typedef struct {
- u16 auto_ctrl; /* WL_ATTEN_XX */
- u16 bb; /* Baseband attenuation */
- u16 radio; /* Radio attenuation */
- u16 txctl1; /* Radio TX_CTL1 value */
-} atten_t;
-
-/* Per-AC retry parameters */
-struct wme_tx_params_s {
- u8 short_retry;
- u8 short_fallback;
- u8 long_retry;
- u8 long_fallback;
- u16 max_rate; /* In units of 512 Kbps */
-};
-
-typedef struct wme_tx_params_s wme_tx_params_t;
-
-#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT)
-
-/* defines used by poweridx iovar - it controls power in a-band */
-/* current gain setting is maintained */
-#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */
-#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */
-#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */
-#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */
-/* value >= 0 causes
- * - input to be set to that value
- * - PCL to be off
- */
-
-/* Used to get specific link/ac parameters */
-typedef struct {
- int ac;
- u8 val;
- struct ether_addr ea;
-} link_val_t;
-
-#define BCM_MAC_STATUS_INDICATION (0x40010200L)
-
-typedef struct {
- u16 ver; /* version of this struct */
- u16 len; /* length in bytes of this structure */
- u16 cap; /* sta's advertised capabilities */
- u32 flags; /* flags defined below */
- u32 idle; /* time since data pkt rx'd from sta */
- struct ether_addr ea; /* Station address */
- wl_rateset_t rateset; /* rateset in use */
- u32 in; /* seconds elapsed since associated */
- u32 listen_interval_inms; /* Min Listen interval in ms for this STA */
- u32 tx_pkts; /* # of packets transmitted */
- u32 tx_failures; /* # of packets failed */
- u32 rx_ucast_pkts; /* # of unicast packets received */
- u32 rx_mcast_pkts; /* # of multicast packets received */
- u32 tx_rate; /* Rate of last successful tx frame */
- u32 rx_rate; /* Rate of last successful rx frame */
- u32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
- u32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */
-} sta_info_t;
-
-#define WL_OLD_STAINFO_SIZE offsetof(sta_info_t, tx_pkts)
-
-#define WL_STA_VER 3
-
-/* Flags for sta_info_t indicating properties of STA */
-#define WL_STA_BRCM 0x1 /* Running a Broadcom driver */
-#define WL_STA_WME 0x2 /* WMM association */
-#define WL_STA_ABCAP 0x4
-#define WL_STA_AUTHE 0x8 /* Authenticated */
-#define WL_STA_ASSOC 0x10 /* Associated */
-#define WL_STA_AUTHO 0x20 /* Authorized */
-#define WL_STA_WDS 0x40 /* Wireless Distribution System */
-#define WL_STA_WDS_LINKUP 0x80 /* WDS traffic/probes flowing properly */
-#define WL_STA_PS 0x100 /* STA is in power save mode from AP's viewpoint */
-#define WL_STA_APSD_BE 0x200 /* APSD delv/trigger for AC_BE is default enabled */
-#define WL_STA_APSD_BK 0x400 /* APSD delv/trigger for AC_BK is default enabled */
-#define WL_STA_APSD_VI 0x800 /* APSD delv/trigger for AC_VI is default enabled */
-#define WL_STA_APSD_VO 0x1000 /* APSD delv/trigger for AC_VO is default enabled */
-#define WL_STA_N_CAP 0x2000 /* STA 802.11n capable */
-#define WL_STA_SCBSTATS 0x4000 /* Per STA debug stats */
-
-#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */
+#ifdef BRCM_FULLMAC
/* Used to get specific STA parameters */
typedef struct {
u32 val;
struct ether_addr ea;
} scb_val_t;
+#endif /* BRCM_FULLMAC */
/* channel encoding */
typedef struct channel_info {
@@ -770,6 +598,7 @@ typedef struct get_pktcnt {
uint rx_ocast_good_pkt; /* unicast packets destined for others */
} get_pktcnt_t;
+#ifdef BRCM_FULLMAC
/* Linux network driver ioctl encoding */
typedef struct wl_ioctl {
uint cmd; /* common ioctl definition */
@@ -779,11 +608,8 @@ typedef struct wl_ioctl {
uint used; /* bytes read or written (optional) */
uint needed; /* bytes needed (optional) */
} wl_ioctl_t;
+#endif /* BRCM_FULLMAC */
-/* reference to wl_ioctl_t struct used by usermode driver */
-#define ioctl_subtype set /* subtype param */
-#define ioctl_pid used /* pid param */
-#define ioctl_status needed /* status param */
/*
* Structure for passing hardware and software
@@ -810,45 +636,11 @@ typedef struct wlc_rev_info {
#define WL_REV_INFO_LEGACY_LENGTH 48
-#define WL_BRAND_MAX 10
-typedef struct wl_instance_info {
- uint instance;
- char brand[WL_BRAND_MAX];
-} wl_instance_info_t;
-
-/* structure to change size of tx fifo */
-typedef struct wl_txfifo_sz {
- u16 magic;
- u16 fifo;
- u16 size;
-} wl_txfifo_sz_t;
-/* magic pattern used for mismatch driver and wl */
-#define WL_TXFIFO_SZ_MAGIC 0xa5a5
-
-/* Transfer info about an IOVar from the driver */
-/* Max supported IOV name size in bytes, + 1 for nul termination */
-#define WLC_IOV_NAME_LEN 30
-typedef struct wlc_iov_trx_s {
- u8 module;
- u8 type;
- char name[WLC_IOV_NAME_LEN];
-} wlc_iov_trx_t;
-
-/* check this magic number */
-#define WLC_IOCTL_MAGIC 0x14e46c77
-
-#define PROC_ENTRY_NAME "brcm_debug"
-/* bump this number if you change the ioctl interface */
-#define WLC_IOCTL_VERSION 1
-
#ifdef BRCM_FULLMAC
-#define WLC_IOCTL_MAXLEN 8192
-#else
-#define WLC_IOCTL_MAXLEN 3072 /* max length ioctl buffer required */
-#endif
#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */
-#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */
+#define WLC_IOCTL_MAXLEN 8192
+#endif
/* common ioctl definitions */
#define WLC_GET_MAGIC 0
@@ -1399,23 +1191,6 @@ typedef struct {
#define WL_TX_POWER_MCS40_FIRST 28
#define WL_TX_POWER_MCS40_NUM 17
-typedef struct {
- u32 flags;
- chanspec_t chanspec; /* txpwr report for this channel */
- chanspec_t local_chanspec; /* channel on which we are associated */
- u8 local_max; /* local max according to the AP */
- u8 local_constraint; /* local constraint according to the AP */
- s8 antgain[2]; /* Ant gain for each band - from SROM */
- u8 rf_cores; /* count of RF Cores being reported */
- u8 est_Pout[4]; /* Latest tx power out estimate per RF
- * chain without adjustment
- */
- u8 est_Pout_cck; /* Latest CCK tx power out estimate */
- u8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */
- u8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */
- u8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */
- u8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */
-} tx_power_legacy2_t;
#define WL_TX_POWER_RATES 101
#define WL_TX_POWER_CCK_FIRST 0
@@ -1848,63 +1623,6 @@ struct ampdu_retry_tid {
u8 retry; /* retry value */
};
-/* structure for addts arguments */
-/* For ioctls that take a list of TSPEC */
-struct tslist {
- int count; /* number of tspecs */
- struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */
-};
-
-/* structure for addts/delts arguments */
-typedef struct tspec_arg {
- u16 version; /* see definition of TSPEC_ARG_VERSION */
- u16 length; /* length of entire structure */
- uint flag; /* bit field */
- /* TSPEC Arguments */
- struct tsinfo_arg tsinfo; /* TS Info bit field */
- u16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
- u16 max_msdu_size; /* Maximum MSDU Size (bytes) */
- uint min_srv_interval; /* Minimum Service Interval (us) */
- uint max_srv_interval; /* Maximum Service Interval (us) */
- uint inactivity_interval; /* Inactivity Interval (us) */
- uint suspension_interval; /* Suspension Interval (us) */
- uint srv_start_time; /* Service Start Time (us) */
- uint min_data_rate; /* Minimum Data Rate (bps) */
- uint mean_data_rate; /* Mean Data Rate (bps) */
- uint peak_data_rate; /* Peak Data Rate (bps) */
- uint max_burst_size; /* Maximum Burst Size (bytes) */
- uint delay_bound; /* Delay Bound (us) */
- uint min_phy_rate; /* Minimum PHY Rate (bps) */
- u16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */
- u16 medium_time; /* Medium Time (32 us/s periods) */
- u8 dialog_token; /* dialog token */
-} tspec_arg_t;
-
-/* tspec arg for desired station */
-typedef struct tspec_per_sta_arg {
- struct ether_addr ea;
- struct tspec_arg ts;
-} tspec_per_sta_arg_t;
-
-/* structure for max bandwidth for each access category */
-typedef struct wme_max_bandwidth {
- u32 ac[AC_COUNT]; /* max bandwidth for each access category */
-} wme_max_bandwidth_t;
-
-#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t))
-
-/* current version of wl_tspec_arg_t struct */
-#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */
-#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */
-#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */
-#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */
-
-/* define for flag */
-#define TSPEC_PENDING 0 /* TSPEC pending */
-#define TSPEC_ACCEPTED 1 /* TSPEC accepted */
-#define TSPEC_REJECTED 2 /* TSPEC rejected */
-#define TSPEC_UNKNOWN 3 /* TSPEC unknown */
-#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */
/* Software feature flag defines used by wlfeatureflag */
#define WL_SWFL_NOHWRADIO 0x0004
@@ -1913,16 +1631,6 @@ typedef struct wme_max_bandwidth {
#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */
-/*
- * Dongle pattern matching filter.
- */
-
-/* Packet filter types. Currently, only pattern matching is supported. */
-typedef enum wl_pkt_filter_type {
- WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */
-} wl_pkt_filter_type_t;
-
-#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
/* Pattern matching filter. Specifies an offset within received packets to
* start matching, the pattern to match, the size of the pattern, and a bitmask
@@ -1957,20 +1665,6 @@ typedef struct wl_pkt_filter_enable {
u32 enable; /* Enable/disable bool */
} wl_pkt_filter_enable_t;
-/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */
-typedef struct wl_pkt_filter_list {
- u32 num; /* Number of installed packet filters */
- wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */
-} wl_pkt_filter_list_t;
-
-#define WL_PKT_FILTER_LIST_FIXED_LEN offsetof(wl_pkt_filter_list_t, filter)
-
-/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */
-typedef struct wl_pkt_filter_stats {
- u32 num_pkts_matched; /* # filter matches for specified filter id */
- u32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */
- u32 num_pkts_discarded; /* # packets discarded by dongle for all filters */
-} wl_pkt_filter_stats_t;
#define WLC_RSSI_INVALID 0 /* invalid RSSI value */
diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c
index 8287261120f4..3bed37cb59b8 100644
--- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c
+++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c
@@ -20,10 +20,15 @@
#include <linux/string.h>
#include <bcmdefs.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmendian.h>
#include <bcmnvram.h>
#include <sbchipc.h>
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <wlc_phy_int.h>
#include <wlc_phyreg_n.h>
@@ -163,7 +168,7 @@ char *phy_getvar(phy_info_t *pi, const char *name)
return NULL;
for (s = vars; s && *s;) {
- if ((bcmp(s, name, len) == 0) && (s[len] == '='))
+ if ((memcmp(s, name, len) == 0) && (s[len] == '='))
return &s[len + 1];
while (*s++)
@@ -272,7 +277,7 @@ u16 read_radio_reg(phy_info_t *pi, u16 addr)
void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
{
- osl_t *osh;
+ struct osl_info *osh;
if (NORADIO_ENAB(pi->pubpi))
return;
@@ -296,7 +301,7 @@ void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
W_REG(osh, &pi->regs->phy4wdatalo, val);
}
- if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
+ if (pi->sh->bustype == PCI_BUS) {
if (++pi->phy_wreg >= pi->phy_wreg_limit) {
(void)R_REG(osh, &pi->regs->maccontrol);
pi->phy_wreg = 0;
@@ -405,7 +410,7 @@ static bool wlc_phy_war41476(phy_info_t *pi)
u16 read_phy_reg(phy_info_t *pi, u16 addr)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = pi->sh->osh;
@@ -426,7 +431,7 @@ u16 read_phy_reg(phy_info_t *pi, u16 addr)
void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = pi->sh->osh;
@@ -441,7 +446,7 @@ void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
#else
W_REG(osh, (volatile u32 *)(&regs->phyregaddr),
addr | (val << 16));
- if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
+ if (pi->sh->bustype == PCI_BUS) {
if (++pi->phy_wreg >= pi->phy_wreg_limit) {
pi->phy_wreg = 0;
(void)R_REG(osh, &regs->phyversion);
@@ -452,7 +457,7 @@ void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = pi->sh->osh;
@@ -473,7 +478,7 @@ void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = pi->sh->osh;
@@ -494,7 +499,7 @@ void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = pi->sh->osh;
@@ -591,7 +596,7 @@ shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
void wlc_phy_shared_detach(shared_phy_t *phy_sh)
{
- osl_t *osh;
+ struct osl_info *osh;
if (phy_sh) {
osh = phy_sh->osh;
@@ -609,7 +614,7 @@ wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars
u32 sflags = 0;
uint phyversion;
int i;
- osl_t *osh;
+ struct osl_info *osh;
osh = sh->osh;
@@ -1080,8 +1085,8 @@ wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
pi->tbl_data_hi = tblDataHi;
pi->tbl_data_lo = tblDataLo;
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
- CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
+ if ((pi->sh->chip == BCM43224_CHIP_ID ||
+ pi->sh->chip == BCM43421_CHIP_ID) &&
(pi->sh->chiprev == 1)) {
pi->tbl_addr = tblAddr;
pi->tbl_save_id = tbl_id;
@@ -1093,8 +1098,8 @@ void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
{
ASSERT((width == 8) || (width == 16) || (width == 32));
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
- CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
+ if ((pi->sh->chip == BCM43224_CHIP_ID ||
+ pi->sh->chip == BCM43421_CHIP_ID) &&
(pi->sh->chiprev == 1) &&
(pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
read_phy_reg(pi, pi->tbl_data_lo);
@@ -1132,8 +1137,8 @@ wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
- CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
+ if ((pi->sh->chip == BCM43224_CHIP_ID ||
+ pi->sh->chip == BCM43421_CHIP_ID) &&
(pi->sh->chiprev == 1) &&
(tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
read_phy_reg(pi, tblDataLo);
@@ -1175,8 +1180,8 @@ wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
- CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
+ if ((pi->sh->chip == BCM43224_CHIP_ID ||
+ pi->sh->chip == BCM43421_CHIP_ID) &&
(pi->sh->chiprev == 1)) {
(void)read_phy_reg(pi, tblDataLo);
@@ -1534,7 +1539,7 @@ wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
- bzero(channels, sizeof(chanvec_t));
+ memset(channels, 0, sizeof(chanvec_t));
for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
channel = chan_info_all[i].chan;
@@ -1896,7 +1901,7 @@ void wlc_phy_txpower_recalc_target(phy_info_t *pi)
tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
}
- bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset));
+ memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
pi->tx_power_max = tx_pwr_max;
pi->tx_power_min = tx_pwr_min;
pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
@@ -2507,7 +2512,7 @@ wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
s8 cmplx_pwr_dbm[PHY_CORE_MAX];
u8 i;
- bzero((u8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm));
+ memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
@@ -2621,9 +2626,9 @@ wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
u8 wait_crs = 0;
u8 i;
- bzero((u8 *) est, sizeof(est));
- bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
- bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
+ memset((u8 *) est, 0, sizeof(est));
+ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
+ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
num_samps = 1 << log_num_samps;
@@ -2704,8 +2709,8 @@ static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
u8 idx, core;
ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
- bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
- bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
+ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
+ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
@@ -3325,7 +3330,7 @@ const u8 *wlc_phy_get_ofdm_rate_lookup(void)
void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
{
- if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
+ if ((pi->sh->chip == BCM4313_CHIP_ID) &&
(pi->sh->boardflags & BFL_FEM)) {
if (mode) {
u16 txant = 0;
diff --git a/drivers/staging/brcm80211/phy/wlc_phy_hal.h b/drivers/staging/brcm80211/phy/wlc_phy_hal.h
index 52260b2d0eba..514e15e00283 100644
--- a/drivers/staging/brcm80211/phy/wlc_phy_hal.h
+++ b/drivers/staging/brcm80211/phy/wlc_phy_hal.h
@@ -122,11 +122,7 @@ typedef struct shared_phy shared_phy_t;
struct phy_pub;
-#ifdef WLC_HIGH_ONLY
-typedef struct wlc_rpc_phy wlc_phy_t;
-#else
typedef struct phy_pub wlc_phy_t;
-#endif
typedef struct shared_phy_params {
void *osh;
@@ -150,7 +146,6 @@ typedef struct shared_phy_params {
u32 boardflags2;
} shared_phy_params_t;
-#ifdef WLC_LOW
extern shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp);
extern void wlc_phy_shared_detach(shared_phy_t *phy_sh);
@@ -189,7 +184,6 @@ extern void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag);
extern void wlc_phy_switch_radio(wlc_phy_t *ppi, bool on);
extern void wlc_phy_anacore(wlc_phy_t *ppi, bool on);
-#endif /* WLC_LOW */
extern void wlc_phy_BSSinit(wlc_phy_t *ppi, bool bonlyap, int rssi);
diff --git a/drivers/staging/brcm80211/phy/wlc_phy_int.h b/drivers/staging/brcm80211/phy/wlc_phy_int.h
index 9513b87fa163..72eee9120c2f 100644
--- a/drivers/staging/brcm80211/phy/wlc_phy_int.h
+++ b/drivers/staging/brcm80211/phy/wlc_phy_int.h
@@ -527,7 +527,7 @@ typedef struct {
struct shared_phy {
struct phy_info *phy_head;
uint unit;
- osl_t *osh;
+ struct osl_info *osh;
si_t *sih;
void *physhim;
uint corerev;
@@ -1158,7 +1158,7 @@ extern void wlc_phy_table_write_nphy(phy_info_t *pi, u32, u32, u32,
(pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec)))
#define WLC_PHY_WAR_PR51571(pi) \
- if ((BUSTYPE((pi)->sh->bustype) == PCI_BUS) && NREV_LT((pi)->pubpi.phy_rev, 3)) \
+ if (((pi)->sh->bustype == PCI_BUS) && NREV_LT((pi)->pubpi.phy_rev, 3)) \
(void)R_REG((pi)->sh->osh, &(pi)->regs->maccontrol)
extern void wlc_phy_cal_perical_nphy_run(phy_info_t *pi, u8 caltype);
diff --git a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c
index 3d3112ed4e20..3ac2b49d9a9d 100644
--- a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c
+++ b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c
@@ -17,13 +17,18 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <wlc_cfg.h>
#include <qmath.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/pci.h>
#include <siutils.h>
#include <hndpmu.h>
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+
#include <wlc_phy_radio.h>
#include <wlc_phy_int.h>
#include <wlc_phy_lcn.h>
@@ -1327,7 +1332,7 @@ static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
u32 data_buf[64];
phytbl_info_t tab;
- bzero(data_buf, sizeof(data_buf));
+ memset(data_buf, 0, sizeof(data_buf));
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
tab.tbl_width = 32;
@@ -1951,7 +1956,7 @@ wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
cal_gains = *target_gains;
- bzero(ncorr_override, sizeof(ncorr_override));
+ memset(ncorr_override, 0, sizeof(ncorr_override));
for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
cal_gains.gm_gain =
@@ -2529,7 +2534,7 @@ static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
tab.tbl_width = 32;
tab.tbl_offset = 0;
- bzero(temp_offset, sizeof(temp_offset));
+ memset(temp_offset, 0, sizeof(temp_offset));
for (j = 1; j < 128; j += 2)
temp_offset[j] = 0x80000;
diff --git a/drivers/staging/brcm80211/phy/wlc_phy_n.c b/drivers/staging/brcm80211/phy/wlc_phy_n.c
index 950008f122b1..c6cce8de1aee 100644
--- a/drivers/staging/brcm80211/phy/wlc_phy_n.c
+++ b/drivers/staging/brcm80211/phy/wlc_phy_n.c
@@ -18,13 +18,18 @@
#include <linux/string.h>
#include <bcmdefs.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
#include <osl.h>
#include <siutils.h>
#include <sbchipc.h>
#include <hndpmu.h>
#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+
#include <wlc_phy_radio.h>
#include <wlc_phy_int.h>
#include <wlc_phyreg_n.h>
@@ -14554,7 +14559,7 @@ void WLBANDINITFN(wlc_phy_init_nphy) (phy_info_t *pi)
}
}
- if ((!PHY_IPA(pi)) && (CHIPID(pi->sh->chip) == BCM5357_CHIP_ID)) {
+ if ((!PHY_IPA(pi)) && (pi->sh->chip == BCM5357_CHIP_ID)) {
si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA,
CCTRL5357_EXTPA);
}
@@ -17599,7 +17604,7 @@ static void wlc_phy_radio_postinit_2057(phy_info_t *pi)
mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1);
- if (CHIPID(pi->sh->chip) == !BCM6362_CHIP_ID) {
+ if (pi->sh->chip == !BCM6362_CHIP_ID) {
mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x2, 0x2);
}
@@ -18007,8 +18012,8 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi,
write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 |
RADIO_2056_SYN, 0x1f);
- if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID)) {
+ if ((pi->sh->chip == BCM4716_CHIP_ID) ||
+ (pi->sh->chip == BCM47162_CHIP_ID)) {
write_radio_reg(pi,
RADIO_2056_SYN_PLL_LOOPFILTER4 |
@@ -18070,8 +18075,8 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi,
WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
PADG_IDAC, 0xcc);
- if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) ||
- (CHIPID(pi->sh->chip) ==
+ if ((pi->sh->chip == BCM4716_CHIP_ID) ||
+ (pi->sh->chip ==
BCM47162_CHIP_ID)) {
bias = 0x40;
cascbias = 0x45;
@@ -18083,11 +18088,11 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi,
bias = 0x25;
cascbias = 0x20;
- if ((CHIPID(pi->sh->chip) ==
+ if ((pi->sh->chip ==
BCM43224_CHIP_ID)
- || (CHIPID(pi->sh->chip) ==
+ || (pi->sh->chip ==
BCM43225_CHIP_ID)
- || (CHIPID(pi->sh->chip) ==
+ || (pi->sh->chip ==
BCM43421_CHIP_ID)) {
if (pi->sh->chippkg ==
BCM43224_FAB_SMIC) {
@@ -18198,9 +18203,9 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi,
cascbias = 0x30;
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM43225_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM43421_CHIP_ID)) {
+ if ((pi->sh->chip == BCM43224_CHIP_ID) ||
+ (pi->sh->chip == BCM43225_CHIP_ID) ||
+ (pi->sh->chip == BCM43421_CHIP_ID)) {
if (pi->sh->chippkg == BCM43224_FAB_SMIC) {
cascbias = 0x35;
}
@@ -18927,7 +18932,7 @@ static void wlc_phy_spurwar_nphy(phy_info_t *pi)
case 38:
case 102:
case 118:
- if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) &&
+ if ((pi->sh->chip == BCM4716_CHIP_ID) &&
(pi->sh->chippkg == BCM4717_PKG_ID)) {
nphy_adj_tone_id_buf[0] = 32;
nphy_adj_noise_var_buf[0] = 0x21f;
@@ -19062,7 +19067,7 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec,
if (pi->nphy_aband_spurwar_en &&
((val == 38) || (val == 102)
|| (val == 118))) {
- if ((CHIPID(pi->sh->chip) ==
+ if ((pi->sh->chip ==
BCM4716_CHIP_ID)
&& (pi->sh->chippkg ==
BCM4717_PKG_ID)) {
@@ -19077,8 +19082,8 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec,
if (pi->phy_spuravoid == SPURAVOID_FORCEON)
spuravoid = 1;
- if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID)) {
+ if ((pi->sh->chip == BCM4716_CHIP_ID) ||
+ (pi->sh->chip == BCM47162_CHIP_ID)) {
si_pmu_spuravoid(pi->sh->sih, pi->sh->osh, spuravoid);
} else {
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false);
@@ -19086,9 +19091,9 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec,
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true);
}
- if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM43225_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM43421_CHIP_ID)) {
+ if ((pi->sh->chip == BCM43224_CHIP_ID) ||
+ (pi->sh->chip == BCM43225_CHIP_ID) ||
+ (pi->sh->chip == BCM43421_CHIP_ID)) {
if (spuravoid == 1) {
@@ -19105,8 +19110,8 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec,
}
}
- if (!((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) ||
- (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID))) {
+ if (!((pi->sh->chip == BCM4716_CHIP_ID) ||
+ (pi->sh->chip == BCM47162_CHIP_ID))) {
wlapi_bmac_core_phypll_reset(pi->sh->physhim);
}
@@ -21062,11 +21067,11 @@ s16 wlc_phy_tempsense_nphy(phy_info_t *pi)
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16,
&auxADC_rssi_ctrlH_save);
- if (CHIPID(pi->sh->chip) == BCM5357_CHIP_ID) {
+ if (pi->sh->chip == BCM5357_CHIP_ID) {
radio_temp[0] = (193 * (radio_temp[1] + radio_temp2[1])
+ 88 * (auxADC_Vl) - 27111 +
128) / 256;
- } else if (CHIPID(pi->sh->chip) == BCM43236_CHIP_ID) {
+ } else if (pi->sh->chip == BCM43236_CHIP_ID) {
radio_temp[0] = (198 * (radio_temp[1] + radio_temp2[1])
+ 91 * (auxADC_Vl) - 27243 +
128) / 256;
@@ -26277,7 +26282,7 @@ static u32 *wlc_phy_get_ipa_gaintbl_nphy(phy_info_t *pi)
} else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6;
- if (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID) {
+ if (pi->sh->chip == BCM47162_CHIP_ID) {
tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5;
}
@@ -26833,7 +26838,7 @@ wlc_phy_a2_nphy(phy_info_t *pi, nphy_ipa_txcalgains_t *txgains,
phy_a2 = 63;
if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (CHIPID(pi->sh->chip) == BCM6362_CHIP_ID) {
+ if (pi->sh->chip == BCM6362_CHIP_ID) {
phy_a1 = 35;
phy_a3 = 35;
} else if ((pi->pubpi.radiorev == 4)
@@ -26946,7 +26951,7 @@ wlc_phy_a2_nphy(phy_info_t *pi, nphy_ipa_txcalgains_t *txgains,
if (NREV_GE(pi->pubpi.phy_rev, 6)) {
phy_a5 = 0x00f7 | (phy_a4 << 8);
- if (CHIPID(pi->sh->chip) ==
+ if (pi->sh->chip ==
BCM47162_CHIP_ID) {
phy_a5 =
0x10f7 | (phy_a4 <<
diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c
index 6ce9e5d96830..330b88152b65 100644
--- a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c
+++ b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c
@@ -15,6 +15,9 @@
*/
#include <linux/types.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <osl.h>
#include <wlc_phy_int.h>
#include <wlc_phytbl_lcn.h>
diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c
index 7cc2c563c727..a9fc193721ef 100644
--- a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c
+++ b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c
@@ -16,6 +16,9 @@
#include <linux/kernel.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <osl.h>
#include <wlc_phy_int.h>
#include <wlc_phytbl_n.h>
diff --git a/drivers/staging/brcm80211/sys/wl_dbg.h b/drivers/staging/brcm80211/sys/wl_dbg.h
index e63b27ebad5e..54af257598c2 100644
--- a/drivers/staging/brcm80211/sys/wl_dbg.h
+++ b/drivers/staging/brcm80211/sys/wl_dbg.h
@@ -20,15 +20,20 @@
/* wl_msg_level is a bit vector with defs in wlioctl.h */
extern u32 wl_msg_level;
-#define WL_PRINT(args) printf args
-#define WL_NONE(args)
+#define WL_NONE(fmt, args...) no_printk(fmt, ##args)
+
+#define WL_PRINT(level, fmt, args...) \
+do { \
+ if (wl_msg_level & level) \
+ printk(fmt, ##args); \
+} while (0)
#ifdef BCMDBG
-#define WL_ERROR(args) do {if ((wl_msg_level & WL_ERROR_VAL)) WL_PRINT(args); } while (0)
-#define WL_TRACE(args) do {if (wl_msg_level & WL_TRACE_VAL) WL_PRINT(args); } while (0)
-#define WL_AMPDU(args) do {if (wl_msg_level & WL_AMPDU_VAL) WL_PRINT(args); } while (0)
-#define WL_FFPLD(args) do {if (wl_msg_level & WL_FFPLD_VAL) WL_PRINT(args); } while (0)
+#define WL_ERROR(fmt, args...) WL_PRINT(WL_ERROR_VAL, fmt, ##args)
+#define WL_TRACE(fmt, args...) WL_PRINT(WL_TRACE_VAL, fmt, ##args)
+#define WL_AMPDU(fmt, args...) WL_PRINT(WL_AMPDU_VAL, fmt, ##args)
+#define WL_FFPLD(fmt, args...) WL_PRINT(WL_FFPLD_VAL, fmt, ##args)
#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL)
@@ -44,35 +49,50 @@ extern u32 wl_msg_level;
extern u32 wl_ampdu_dbg;
-#define WL_AMPDU_UPDN(args) do {if (wl_ampdu_dbg & WL_AMPDU_UPDN_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_RX(args) do {if (wl_ampdu_dbg & WL_AMPDU_RX_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_ERR(args) do {if (wl_ampdu_dbg & WL_AMPDU_ERR_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_TX(args) do {if (wl_ampdu_dbg & WL_AMPDU_TX_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_CTL(args) do {if (wl_ampdu_dbg & WL_AMPDU_CTL_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_HW(args) do {if (wl_ampdu_dbg & WL_AMPDU_HW_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_HWTXS(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL) {WL_AMPDU(args); } } while (0)
-#define WL_AMPDU_HWDBG(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWDBG_VAL) {WL_AMPDU(args); } } while (0)
+#define WL_AMPDU_PRINT(level, fmt, args...) \
+do { \
+ if (wl_ampdu_dbg & level) { \
+ WL_AMPDU(fmt, ##args); \
+ } \
+} while (0)
+
+#define WL_AMPDU_UPDN(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_UPDN_VAL, fmt, ##args)
+#define WL_AMPDU_RX(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_RX_VAL, fmt, ##args)
+#define WL_AMPDU_ERR(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_ERR_VAL, fmt, ##args)
+#define WL_AMPDU_TX(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_TX_VAL, fmt, ##args)
+#define WL_AMPDU_CTL(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_CTL_VAL, fmt, ##args)
+#define WL_AMPDU_HW(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_HW_VAL, fmt, ##args)
+#define WL_AMPDU_HWTXS(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_HWTXS_VAL, fmt, ##args)
+#define WL_AMPDU_HWDBG(fmt, args...) \
+ WL_AMPDU_PRINT(WL_AMPDU_HWDBG_VAL, fmt, ##args)
#define WL_AMPDU_ERR_ON() (wl_ampdu_dbg & WL_AMPDU_ERR_VAL)
#define WL_AMPDU_HW_ON() (wl_ampdu_dbg & WL_AMPDU_HW_VAL)
#define WL_AMPDU_HWTXS_ON() (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL)
#else /* BCMDBG */
-#define WL_ERROR(args)
-#define WL_TRACE(args)
-#define WL_AMPDU(args)
-#define WL_FFPLD(args)
+#define WL_ERROR(fmt, args...) no_printk(fmt, ##args)
+#define WL_TRACE(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU(fmt, args...) no_printk(fmt, ##args)
+#define WL_FFPLD(fmt, args...) no_printk(fmt, ##args)
#define WL_ERROR_ON() 0
-#define WL_AMPDU_UPDN(args)
-#define WL_AMPDU_RX(args)
-#define WL_AMPDU_ERR(args)
-#define WL_AMPDU_TX(args)
-#define WL_AMPDU_CTL(args)
-#define WL_AMPDU_HW(args)
-#define WL_AMPDU_HWTXS(args)
-#define WL_AMPDU_HWDBG(args)
+#define WL_AMPDU_UPDN(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_RX(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_ERR(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_TX(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_CTL(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_HW(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_HWTXS(fmt, args...) no_printk(fmt, ##args)
+#define WL_AMPDU_HWDBG(fmt, args...) no_printk(fmt, ##args)
#define WL_AMPDU_ERR_ON() 0
#define WL_AMPDU_HW_ON() 0
#define WL_AMPDU_HWTXS_ON() 0
diff --git a/drivers/staging/brcm80211/sys/wl_export.h b/drivers/staging/brcm80211/sys/wl_export.h
index 08442f8e84e0..aa8b5a3ed633 100644
--- a/drivers/staging/brcm80211/sys/wl_export.h
+++ b/drivers/staging/brcm80211/sys/wl_export.h
@@ -45,10 +45,10 @@ extern void wl_add_timer(struct wl_info *wl, struct wl_timer *timer, uint ms,
int periodic);
extern bool wl_del_timer(struct wl_info *wl, struct wl_timer *timer);
-extern uint wl_buf_to_pktcopy(osl_t *osh, void *p, unsigned char *buf, int len,
- uint offset);
-extern void *wl_get_pktbuffer(osl_t *osh, int len);
-extern int wl_set_pktlen(osl_t *osh, void *p, int len);
+extern uint wl_buf_to_pktcopy(struct osl_info *osh, void *p, unsigned char *buf,
+ int len, uint offset);
+extern void *wl_get_pktbuffer(struct osl_info *osh, int len);
+extern int wl_set_pktlen(struct osl_info *osh, void *p, int len);
#define wl_sort_bsslist(a, b) false
diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c
index ad635ee7758e..bdd629d72a75 100644
--- a/drivers/staging/brcm80211/sys/wl_mac80211.c
+++ b/drivers/staging/brcm80211/sys/wl_mac80211.c
@@ -21,72 +21,36 @@
#include <linux/string.h>
#include <linux/pci_ids.h>
#include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
#include <osl.h>
#define WLC_MAXBSSCFG 1 /* single BSS configs */
#include <wlc_cfg.h>
#include <net/mac80211.h>
-#include <epivers.h>
-#ifndef WLC_HIGH_ONLY
#include <phy_version.h>
-#endif
#include <bcmutils.h>
#include <pcicfg.h>
#include <wlioctl.h>
#include <wlc_key.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <wlc_channel.h>
#include <wlc_pub.h>
#include <wlc_scb.h>
#include <wl_dbg.h>
-#ifdef BCMSDIO
-#include <bcmsdh.h>
-#endif
#include <wl_export.h>
-#ifdef WLC_HIGH_ONLY
-#include "dbus.h"
-#include "bcm_rpc_tp.h"
-#include "bcm_rpc.h"
-#include "bcm_xdr.h"
-#include "wlc_rpc.h"
-#endif
#include <wl_mac80211.h>
#include <linux/firmware.h>
-#ifndef WLC_HIGH_ONLY
#include <wl_ucode.h>
#include <d11ucode_ext.h>
-#endif
-#ifdef BCMSDIO
-extern struct device *sdiommc_dev;
-#endif
-
-extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg,
- bool suspend);
-bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw);
-void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc);
-void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset,
- const struct ether_addr *addr);
static void wl_timer(unsigned long data);
static void _wl_timer(wl_timer_t *t);
-#ifdef WLC_HIGH_ONLY
-#define RPCQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->rpcq_lock, (_flags))
-#define RPCQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->rpcq_lock, (_flags))
-#define TXQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->txq_lock, (_flags))
-#define TXQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->txq_lock, (_flags))
-static void wl_rpc_down(void *wlh);
-static void wl_rpcq_free(wl_info_t *wl);
-static void wl_rpcq_dispatch(struct wl_task *task);
-static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf);
-static void wl_start_txqwork(struct wl_task *task);
-static void wl_txq_free(wl_info_t *wl);
-static void wl_timer_task(wl_task_t *task);
-static int wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *),
- void *context);
-#endif /* WLC_HIGH_ONLY */
static int ieee_hw_init(struct ieee80211_hw *hw);
static int ieee_hw_rate_init(struct ieee80211_hw *hw);
@@ -134,16 +98,14 @@ struct ieee80211_tkip_data {
u8 rx_hdr[16], tx_hdr[16];
};
-#ifndef WLC_HIGH_ONLY
-#define WL_DEV_IF(dev) ((wl_if_t *)netdev_priv(dev))
-#define WL_INFO(dev) ((wl_info_t *)(WL_DEV_IF(dev)->wl)) /* points to wl */
-static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev);
-static void wl_release_fw(wl_info_t *wl);
-#endif
+#define WL_DEV_IF(dev) ((struct wl_if *)netdev_priv(dev))
+#define WL_INFO(dev) ((struct wl_info *)(WL_DEV_IF(dev)->wl))
+static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev);
+static void wl_release_fw(struct wl_info *wl);
/* local prototypes */
-static int wl_start(struct sk_buff *skb, wl_info_t *wl);
-static int wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw,
+static int wl_start(struct sk_buff *skb, struct wl_info *wl);
+static int wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw,
struct sk_buff *skb);
static void wl_dpc(unsigned long data);
@@ -152,7 +114,6 @@ MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
-#ifndef BCMSDIO
/* recognized PCI IDs */
static struct pci_device_id wl_id_table[] = {
{PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */
@@ -163,55 +124,18 @@ static struct pci_device_id wl_id_table[] = {
MODULE_DEVICE_TABLE(pci, wl_id_table);
static void wl_remove(struct pci_dev *pdev);
-#endif /* !BCMSDIO */
-#ifdef BCMSDIO
-static uint sd_drivestrength = 6;
-module_param(sd_drivestrength, uint, 0);
-#endif
#ifdef BCMDBG
static int msglevel = 0xdeadbeef;
module_param(msglevel, int, 0);
-#ifndef WLC_HIGH_ONLY
static int phymsglevel = 0xdeadbeef;
module_param(phymsglevel, int, 0);
-#endif /* WLC_HIGH_ONLY */
#endif /* BCMDBG */
-static int oneonly;
-module_param(oneonly, int, 0);
-
-static int piomode;
-module_param(piomode, int, 0);
-
-static int instance_base; /* Starting instance number */
-module_param(instance_base, int, 0);
-
-#if defined(BCMDBG)
-static char *macaddr;
-module_param(macaddr, charp, S_IRUGO);
-#endif
-
-static int nompc = 1;
-module_param(nompc, int, 0);
-
-static char name[IFNAMSIZ] = "eth%d";
-module_param_string(name, name, IFNAMSIZ, 0);
-
-#ifndef SRCBASE
-#define SRCBASE "."
-#endif
-
-#define WL_MAGIC 0xdeadbeef
-
#define HW_TO_WL(hw) (hw->priv)
#define WL_TO_HW(wl) (wl->pub->ieee_hw)
-#ifdef WLC_HIGH_ONLY
-static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb);
-#else
static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-#endif
static int wl_ops_start(struct ieee80211_hw *hw);
static void wl_ops_stop(struct ieee80211_hw *hw);
static int wl_ops_add_interface(struct ieee80211_hw *hw,
@@ -249,28 +173,13 @@ static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-#ifdef WLC_HIGH_ONLY
-static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- int status;
- wl_info_t *wl = hw->priv;
- if (!wl->pub->up) {
- WL_ERROR(("ops->tx called while down\n"));
- status = -ENETDOWN;
- goto done;
- }
- status = wl_start(skb, wl);
- done:
- return status;
-}
-#else
static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
int status;
- wl_info_t *wl = hw->priv;
+ struct wl_info *wl = hw->priv;
WL_LOCK(wl);
if (!wl->pub->up) {
- WL_ERROR(("ops->tx called while down\n"));
+ WL_ERROR("ops->tx called while down\n");
status = -ENETDOWN;
goto done;
}
@@ -279,13 +188,14 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
WL_UNLOCK(wl);
return status;
}
-#endif /* WLC_HIGH_ONLY */
static int wl_ops_start(struct ieee80211_hw *hw)
{
- wl_info_t *wl = hw->priv;
- /* struct ieee80211_channel *curchan = hw->conf.channel; */
- WL_NONE(("%s : Initial channel: %d\n", __func__, curchan->hw_value));
+ struct wl_info *wl = hw->priv;
+ /*
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value);
+ */
WL_LOCK(wl);
ieee80211_wake_queues(hw);
@@ -296,7 +206,7 @@ static int wl_ops_start(struct ieee80211_hw *hw)
static void wl_ops_stop(struct ieee80211_hw *hw)
{
- wl_info_t *wl = hw->priv;
+ struct wl_info *wl = hw->priv;
ASSERT(wl);
WL_LOCK(wl);
wl_down(wl);
@@ -309,7 +219,7 @@ static void wl_ops_stop(struct ieee80211_hw *hw)
static int
wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- wl_info_t *wl;
+ struct wl_info *wl;
int err;
/* Just STA for now */
@@ -318,8 +228,8 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_WDS &&
vif->type != NL80211_IFTYPE_ADHOC) {
- WL_ERROR(("%s: Attempt to add type %d, only STA for now\n",
- __func__, vif->type));
+ WL_ERROR("%s: Attempt to add type %d, only STA for now\n",
+ __func__, vif->type);
return -EOPNOTSUPP;
}
@@ -329,7 +239,7 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
WL_UNLOCK(wl);
if (err != 0)
- WL_ERROR(("%s: wl_up() returned %d\n", __func__, err));
+ WL_ERROR("%s: wl_up() returned %d\n", __func__, err);
return err;
}
@@ -343,7 +253,7 @@ static int
ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
enum nl80211_channel_type type)
{
- wl_info_t *wl = HW_TO_WL(hw);
+ struct wl_info *wl = HW_TO_WL(hw);
int err = 0;
switch (type) {
@@ -355,8 +265,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
break;
case NL80211_CHAN_HT40MINUS:
case NL80211_CHAN_HT40PLUS:
- WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n",
- __func__));
+ WL_ERROR("%s: Need to implement 40 Mhz Channels!\n", __func__);
break;
}
@@ -368,17 +277,17 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
{
struct ieee80211_conf *conf = &hw->conf;
- wl_info_t *wl = HW_TO_WL(hw);
+ struct wl_info *wl = HW_TO_WL(hw);
int err = 0;
int new_int;
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
- WL_NONE(("%s: Setting listen interval to %d\n",
- __func__, conf->listen_interval));
+ WL_NONE("%s: Setting listen interval to %d\n",
+ __func__, conf->listen_interval);
if (wlc_iovar_setint
(wl->wlc, "bcn_li_bcn", conf->listen_interval)) {
- WL_ERROR(("%s: Error setting listen_interval\n",
- __func__));
+ WL_ERROR("%s: Error setting listen_interval\n",
+ __func__);
err = -EIO;
goto config_out;
}
@@ -386,41 +295,42 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
ASSERT(new_int == conf->listen_interval);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR)
- WL_NONE(("Need to set monitor mode\n"));
+ WL_NONE("Need to set monitor mode\n");
if (changed & IEEE80211_CONF_CHANGE_PS)
- WL_NONE(("Need to set Power-save mode\n"));
+ WL_NONE("Need to set Power-save mode\n");
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- WL_NONE(("%s: Setting tx power to %d dbm\n", __func__,
- conf->power_level));
+ WL_NONE("%s: Setting tx power to %d dbm\n",
+ __func__, conf->power_level);
if (wlc_iovar_setint
(wl->wlc, "qtxpower", conf->power_level * 4)) {
- WL_ERROR(("%s: Error setting power_level\n", __func__));
+ WL_ERROR("%s: Error setting power_level\n", __func__);
err = -EIO;
goto config_out;
}
wlc_iovar_getint(wl->wlc, "qtxpower", &new_int);
if (new_int != (conf->power_level * 4))
- WL_ERROR(("%s: Power level req != actual, %d %d\n",
- __func__, conf->power_level * 4, new_int));
+ WL_ERROR("%s: Power level req != actual, %d %d\n",
+ __func__, conf->power_level * 4, new_int);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
err = ieee_set_channel(hw, conf->channel, conf->channel_type);
}
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
- WL_NONE(("%s: srl %d, lrl %d\n", __func__,
- conf->short_frame_max_tx_count,
- conf->long_frame_max_tx_count));
+ WL_NONE("%s: srl %d, lrl %d\n",
+ __func__,
+ conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);
if (wlc_set
(wl->wlc, WLC_SET_SRL,
conf->short_frame_max_tx_count) < 0) {
- WL_ERROR(("%s: Error setting srl\n", __func__));
+ WL_ERROR("%s: Error setting srl\n", __func__);
err = -EIO;
goto config_out;
}
if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count)
< 0) {
- WL_ERROR(("%s: Error setting lrl\n", __func__));
+ WL_ERROR("%s: Error setting lrl\n", __func__);
err = -EIO;
goto config_out;
}
@@ -435,32 +345,29 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
- wl_info_t *wl = HW_TO_WL(hw);
+ struct wl_info *wl = HW_TO_WL(hw);
int val;
-#ifdef WLC_HIGH_ONLY
- WL_LOCK(wl);
-#endif
if (changed & BSS_CHANGED_ASSOC) {
- WL_ERROR(("Associated:\t%s\n", info->assoc ? "True" : "False"));
+ WL_ERROR("Associated:\t%s\n", info->assoc ? "True" : "False");
/* association status changed (associated/disassociated)
* also implies a change in the AID.
*/
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- WL_NONE(("Use_cts_prot:\t%s Implement me\n",
- info->use_cts_prot ? "True" : "False"));
+ WL_NONE("Use_cts_prot:\t%s Implement me\n",
+ info->use_cts_prot ? "True" : "False");
/* CTS protection changed */
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- WL_NONE(("Short preamble:\t%s Implement me\n",
- info->use_short_preamble ? "True" : "False"));
+ WL_NONE("Short preamble:\t%s Implement me\n",
+ info->use_short_preamble ? "True" : "False");
/* preamble changed */
}
if (changed & BSS_CHANGED_ERP_SLOT) {
- WL_NONE(("Changing short slot:\t%s\n",
- info->use_short_slot ? "True" : "False"));
+ WL_NONE("Changing short slot:\t%s\n",
+ info->use_short_slot ? "True" : "False");
if (info->use_short_slot)
val = 1;
else
@@ -470,39 +377,36 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_HT) {
- WL_NONE(("%s: HT mode - Implement me\n", __func__));
+ WL_NONE("%s: HT mode - Implement me\n", __func__);
/* 802.11n parameters changed */
}
if (changed & BSS_CHANGED_BASIC_RATES) {
- WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n",
- (u32) info->basic_rates));
+ WL_NONE("Need to change Basic Rates:\t0x%x! Implement me\n",
+ (u32) info->basic_rates);
/* Basic rateset changed */
}
if (changed & BSS_CHANGED_BEACON_INT) {
- WL_NONE(("Beacon Interval:\t%d Implement me\n",
- info->beacon_int));
+ WL_NONE("Beacon Interval:\t%d Implement me\n",
+ info->beacon_int);
/* Beacon interval changed */
}
if (changed & BSS_CHANGED_BSSID) {
- WL_NONE(("new BSSID:\taid %d bss:%pM\n", info->aid,
- info->bssid));
+ WL_NONE("new BSSID:\taid %d bss:%pM\n",
+ info->aid, info->bssid);
/* BSSID changed, for whatever reason (IBSS and managed mode) */
/* FIXME: need to store bssid in bsscfg */
wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET,
(struct ether_addr *)info->bssid);
}
if (changed & BSS_CHANGED_BEACON) {
- WL_ERROR(("BSS_CHANGED_BEACON\n"));
+ WL_ERROR("BSS_CHANGED_BEACON\n");
/* Beacon data changed, retrieve new beacon (beaconing modes) */
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- WL_ERROR(("Beacon enabled:\t%s\n",
- info->enable_beacon ? "True" : "False"));
+ WL_ERROR("Beacon enabled:\t%s\n",
+ info->enable_beacon ? "True" : "False");
/* Beaconing should be enabled/disabled (beaconing modes) */
}
-#ifdef WLC_HIGH_ONLY
- WL_UNLOCK(wl);
-#endif
return;
}
@@ -511,27 +415,24 @@ wl_ops_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags, u64 multicast)
{
-#ifndef WLC_HIGH_ONLY
- wl_info_t *wl = hw->priv;
-#endif
+ struct wl_info *wl = hw->priv;
changed_flags &= MAC_FILTERS;
*total_flags &= MAC_FILTERS;
if (changed_flags & FIF_PROMISC_IN_BSS)
- WL_ERROR(("FIF_PROMISC_IN_BSS\n"));
+ WL_ERROR("FIF_PROMISC_IN_BSS\n");
if (changed_flags & FIF_ALLMULTI)
- WL_ERROR(("FIF_ALLMULTI\n"));
+ WL_ERROR("FIF_ALLMULTI\n");
if (changed_flags & FIF_FCSFAIL)
- WL_ERROR(("FIF_FCSFAIL\n"));
+ WL_ERROR("FIF_FCSFAIL\n");
if (changed_flags & FIF_PLCPFAIL)
- WL_ERROR(("FIF_PLCPFAIL\n"));
+ WL_ERROR("FIF_PLCPFAIL\n");
if (changed_flags & FIF_CONTROL)
- WL_ERROR(("FIF_CONTROL\n"));
+ WL_ERROR("FIF_CONTROL\n");
if (changed_flags & FIF_OTHER_BSS)
- WL_ERROR(("FIF_OTHER_BSS\n"));
+ WL_ERROR("FIF_OTHER_BSS\n");
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n"));
-#ifndef WLC_HIGH_ONLY
+ WL_NONE("FIF_BCN_PRBRESP_PROMISC\n");
WL_LOCK(wl);
if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
@@ -541,7 +442,6 @@ wl_ops_configure_filter(struct ieee80211_hw *hw,
wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
}
WL_UNLOCK(wl);
-#endif
}
return;
}
@@ -549,25 +449,25 @@ wl_ops_configure_filter(struct ieee80211_hw *hw,
static int
wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
{
- WL_ERROR(("%s: Enter\n", __func__));
+ WL_ERROR("%s: Enter\n", __func__);
return 0;
}
static void wl_ops_sw_scan_start(struct ieee80211_hw *hw)
{
- WL_NONE(("Scan Start\n"));
+ WL_NONE("Scan Start\n");
return;
}
static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw)
{
- WL_NONE(("Scan Complete\n"));
+ WL_NONE("Scan Complete\n");
return;
}
static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
{
- WL_ERROR(("%s: Enter\n", __func__));
+ WL_ERROR("%s: Enter\n", __func__);
return;
}
@@ -575,13 +475,13 @@ static int
wl_ops_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
- WL_ERROR(("%s: Enter\n", __func__));
+ WL_ERROR("%s: Enter\n", __func__);
return 0;
}
static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- WL_ERROR(("%s: Enter\n", __func__));
+ WL_ERROR("%s: Enter\n", __func__);
return 0;
}
@@ -589,10 +489,10 @@ static void
wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
{
- WL_NONE(("%s: Enter\n", __func__));
+ WL_NONE("%s: Enter\n", __func__);
switch (cmd) {
default:
- WL_ERROR(("%s: Uknown cmd = %d\n", __func__, cmd));
+ WL_ERROR("%s: Unknown cmd = %d\n", __func__, cmd);
break;
}
return;
@@ -602,11 +502,11 @@ static int
wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
- wl_info_t *wl = hw->priv;
+ struct wl_info *wl = hw->priv;
- WL_NONE(("%s: Enter (WME config)\n", __func__));
- WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue,
- params->txop, params->cw_min, params->cw_max, params->aifs));
+ WL_NONE("%s: Enter (WME config)\n", __func__);
+ WL_NONE("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue,
+ params->txop, params->cw_min, params->cw_max, params->aifs);
WL_LOCK(wl);
wlc_wme_setparams(wl->wlc, queue, (void *)params, true);
@@ -617,7 +517,7 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
static u64 wl_ops_get_tsf(struct ieee80211_hw *hw)
{
- WL_ERROR(("%s: Enter\n", __func__));
+ WL_ERROR("%s: Enter\n", __func__);
return 0;
}
@@ -628,11 +528,11 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct scb *scb;
int i;
- wl_info_t *wl = hw->priv;
+ struct wl_info *wl = hw->priv;
/* Init the scb */
scb = (struct scb *)sta->drv_priv;
- bzero(scb, sizeof(struct scb));
+ memset(scb, 0, sizeof(struct scb));
for (i = 0; i < NUMPRIO; i++)
scb->seqctl[i] = 0xFFFF;
scb->seqctl_nonqos = 0xFFFF;
@@ -641,20 +541,12 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
wl->pub->global_scb = scb;
wl->pub->global_ampdu = &(scb->scb_ampdu);
wl->pub->global_ampdu->scb = scb;
-#ifdef WLC_HIGH_ONLY
- wl->pub->global_ampdu->max_pdu = AMPDU_NUM_MPDU;
-#else
wl->pub->global_ampdu->max_pdu = 16;
-#endif
pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID,
AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT);
sta->ht_cap.ht_supported = true;
-#ifdef WLC_HIGH_ONLY
- sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_16K;
-#else
sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_64K;
-#endif
sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
@@ -668,7 +560,7 @@ static int
wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- WL_NONE(("%s: Enter\n", __func__));
+ WL_NONE("%s: Enter\n", __func__);
return 0;
}
@@ -681,19 +573,19 @@ wl_ampdu_action(struct ieee80211_hw *hw,
#if defined(BCMDBG)
struct scb *scb = (struct scb *)sta->drv_priv;
#endif
- wl_info_t *wl = hw->priv;
+ struct wl_info *wl = hw->priv;
ASSERT(scb->magic == SCB_MAGIC);
switch (action) {
case IEEE80211_AMPDU_RX_START:
- WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__));
+ WL_NONE("%s: action = IEEE80211_AMPDU_RX_START\n", __func__);
break;
case IEEE80211_AMPDU_RX_STOP:
- WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__));
+ WL_NONE("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__);
break;
case IEEE80211_AMPDU_TX_START:
if (!wlc_aggregatable(wl->wlc, tid)) {
- /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */
+ /* WL_ERROR("START: tid %d is not agg' able, return FAILURE to stack\n", tid); */
return -1;
}
/* XXX: Use the starting sequence number provided ... */
@@ -707,22 +599,18 @@ wl_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_OPERATIONAL:
/* Not sure what to do here */
/* Power save wakeup */
- WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n",
- __func__));
+ WL_NONE("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n",
+ __func__);
break;
default:
- WL_ERROR(("%s: Invalid command, ignoring\n", __func__));
+ WL_ERROR("%s: Invalid command, ignoring\n", __func__);
}
return 0;
}
static const struct ieee80211_ops wl_ops = {
-#ifdef WLC_HIGH_ONLY
- .tx = wl_ops_tx_nl,
-#else
.tx = wl_ops_tx,
-#endif
.start = wl_ops_start,
.stop = wl_ops_stop,
.add_interface = wl_ops_add_interface,
@@ -744,10 +632,10 @@ static const struct ieee80211_ops wl_ops = {
.ampdu_action = wl_ampdu_action,
};
-static int wl_set_hint(wl_info_t *wl, char *abbrev)
+static int wl_set_hint(struct wl_info *wl, char *abbrev)
{
- WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__,
- abbrev[0], abbrev[1]));
+ WL_ERROR("%s: Sending country code %c%c to MAC80211\n",
+ __func__, abbrev[0], abbrev[1]);
return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
}
@@ -762,117 +650,61 @@ static int wl_set_hint(wl_info_t *wl, char *abbrev)
* a warning that this function is defined but not used if we declare
* it as static.
*/
-static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
+static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs,
uint bustype, void *btparam, uint irq)
{
- wl_info_t *wl;
- osl_t *osh;
+ struct wl_info *wl;
+ struct osl_info *osh;
int unit, err;
unsigned long base_addr;
struct ieee80211_hw *hw;
u8 perm[ETH_ALEN];
- unit = wl_found + instance_base;
+ unit = wl_found;
err = 0;
if (unit < 0) {
- WL_ERROR(("wl%d: unit number overflow, exiting\n", unit));
+ WL_ERROR("wl%d: unit number overflow, exiting\n", unit);
return NULL;
}
- if (oneonly && (unit != instance_base)) {
- WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit));
- return NULL;
- }
-
- /* Requires pkttag feature */
- osh = osl_attach(btparam, bustype, true);
+ osh = osl_attach(btparam, bustype);
ASSERT(osh);
-#ifdef WLC_HIGH_ONLY
- hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops);
- if (!hw) {
- WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__));
- ASSERT(0);
- }
-
- bzero(hw->priv, sizeof(*wl));
- wl = hw->priv;
-#else
/* allocate private info */
hw = pci_get_drvdata(btparam); /* btparam == pdev */
wl = hw->priv;
-#endif
ASSERT(wl);
- wl->magic = WL_MAGIC;
wl->osh = osh;
atomic_set(&wl->callbacks, 0);
/* setup the bottom half handler */
tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl);
-#ifdef WLC_HIGH_ONLY
- wl->rpc_th = bcm_rpc_tp_attach(osh, NULL);
- if (wl->rpc_th == NULL) {
- WL_ERROR(("wl%d: %s: bcm_rpc_tp_attach failed!\n", unit,
- __func__));
- goto fail;
- }
-
- wl->rpc = bcm_rpc_attach(NULL, osh, wl->rpc_th);
- if (wl->rpc == NULL) {
- WL_ERROR(("wl%d: %s: bcm_rpc_attach failed!\n", unit,
- __func__));
- goto fail;
- }
-
- /* init tx work queue for wl_start/send pkt; no need to destroy workitem */
- INIT_WORK(&wl->txq_task.work, (work_func_t) wl_start_txqwork);
- wl->txq_task.context = wl;
-#endif /* WLC_HIGH_ONLY */
-#ifdef BCMSDIO
- SET_IEEE80211_DEV(hw, sdiommc_dev);
-#endif
base_addr = regs;
if (bustype == PCI_BUS) {
- /* piomode can be overwritten by command argument */
- wl->piomode = piomode;
- WL_TRACE(("PCI/%s\n", wl->piomode ? "PIO" : "DMA"));
+ wl->piomode = false;
} else if (bustype == RPC_BUS) {
/* Do nothing */
} else {
bustype = PCI_BUS;
- WL_TRACE(("force to PCI\n"));
+ WL_TRACE("force to PCI\n");
}
wl->bcm_bustype = bustype;
-#ifdef WLC_HIGH_ONLY
- if (wl->bcm_bustype == RPC_BUS) {
- wl->regsva = (void *)0;
- btparam = wl->rpc;
- } else
-#endif
wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ);
if (wl->regsva == NULL) {
- WL_ERROR(("wl%d: ioremap() failed\n", unit));
+ WL_ERROR("wl%d: ioremap() failed\n", unit);
goto fail;
}
-#ifdef WLC_HIGH_ONLY
- spin_lock_init(&wl->rpcq_lock);
- spin_lock_init(&wl->txq_lock);
-
- init_MUTEX(&wl->sem);
-#else
spin_lock_init(&wl->lock);
spin_lock_init(&wl->isr_lock);
-#endif
-#ifndef WLC_HIGH_ONLY
/* prepare ucode */
if (wl_request_fw(wl, (struct pci_dev *)btparam)) {
printf("%s: Failed to find firmware usually in %s\n",
@@ -881,17 +713,14 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
wl_remove((struct pci_dev *)btparam);
goto fail1;
}
-#endif
/* common load-time initialization */
wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh,
wl->regsva, wl->bcm_bustype, btparam, &err);
-#ifndef WLC_HIGH_ONLY
wl_release_fw(wl);
-#endif
if (!wl->wlc) {
- printf("%s: %s wlc_attach() failed with code %d\n",
- KBUILD_MODNAME, EPI_VERSION_STR, err);
+ printf("%s: wlc_attach() failed with code %d\n",
+ KBUILD_MODNAME, err);
goto fail;
}
wl->pub = wlc_pub(wl->wlc);
@@ -900,52 +729,35 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
ASSERT(wl->pub->ieee_hw);
ASSERT(wl->pub->ieee_hw->priv == wl);
-#ifdef WLC_HIGH_ONLY
- REGOPSSET(osh, (osl_rreg_fn_t) wlc_reg_read,
- (osl_wreg_fn_t) wlc_reg_write, wl->wlc);
- wl->rpc_dispatch_ctx.rpc = wl->rpc;
- wl->rpc_dispatch_ctx.wlc = wl->wlc;
- bcm_rpc_rxcb_init(wl->rpc, wl, wl_rpc_dispatch_schedule, wl,
- wl_rpc_down, NULL, NULL);
-#endif /* WLC_HIGH_ONLY */
-
- if (nompc) {
- if (wlc_iovar_setint(wl->wlc, "mpc", 0)) {
- WL_ERROR(("wl%d: Error setting MPC variable to 0\n",
- unit));
- }
+
+ if (wlc_iovar_setint(wl->wlc, "mpc", 0)) {
+ WL_ERROR("wl%d: Error setting MPC variable to 0\n", unit);
}
-#ifdef BCMSDIO
- /* Set SDIO drive strength */
- wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength);
-#endif
-#ifdef WLC_LOW
/* register our interrupt handler */
if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
- WL_ERROR(("wl%d: request_irq() failed\n", unit));
+ WL_ERROR("wl%d: request_irq() failed\n", unit);
goto fail;
}
wl->irq = irq;
-#endif /* WLC_LOW */
/* register module */
wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog,
NULL);
if (ieee_hw_init(hw)) {
- WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit, __func__));
+ WL_ERROR("wl%d: %s: ieee_hw_init failed!\n", unit, __func__);
goto fail;
}
- bcopy(&wl->pub->cur_etheraddr, perm, ETHER_ADDR_LEN);
+ bcopy(&wl->pub->cur_etheraddr, perm, ETH_ALEN);
ASSERT(is_valid_ether_addr(perm));
SET_IEEE80211_PERM_ADDR(hw, perm);
err = ieee80211_register_hw(hw);
if (err) {
- WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n",
- __func__, err));
+ WL_ERROR("%s: ieee80211_register_hw failed, status %d\n",
+ __func__, err);
}
if (wl->pub->srom_ccode[0])
@@ -953,19 +765,14 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
else
err = wl_set_hint(wl, "US");
if (err) {
- WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__,
- err));
- }
-#ifndef WLC_HIGH_ONLY
- WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
- EPI_VERSION_STR " (" PHY_VERSION_STR ")", unit));
-#else
- WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
- EPI_VERSION_STR, unit));
-#endif
+ WL_ERROR("%s: regulatory_hint failed, status %d\n",
+ __func__, err);
+ }
+ WL_ERROR("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver (" PHY_VERSION_STR ")",
+ unit);
#ifdef BCMDBG
- printf(" (Compiled in " SRCBASE " at " __TIME__ " on " __DATE__ ")");
+ printf(" (Compiled at " __TIME__ " on " __DATE__ ")");
#endif /* BCMDBG */
printf("\n");
@@ -978,54 +785,6 @@ fail1:
return NULL;
}
-#ifdef WLC_HIGH_ONLY
-static void *wl_dbus_probe_cb(void *arg, const char *desc, u32 bustype,
- u32 hdrlen)
-{
- wl_info_t *wl;
- WL_ERROR(("%s:\n", __func__));
-
- wl = wl_attach(BCM_DNGL_VID, BCM_DNGL_BDC_PID, (unsigned long) NULL, RPC_BUS,
- NULL, 0);
- if (!wl) {
- WL_ERROR(("%s: wl_attach failed\n", __func__));
- }
-
- /* This is later passed to wl_dbus_disconnect_cb */
- return wl;
-}
-
-static void wl_dbus_disconnect_cb(void *arg)
-{
- wl_info_t *wl = arg;
-
- WL_ERROR(("%s:\n", __func__));
-
- if (wl) {
-#ifdef WLC_HIGH_ONLY
- if (wl->pub->ieee_hw) {
- ieee80211_unregister_hw(wl->pub->ieee_hw);
- WL_ERROR(("%s: Back from down\n", __func__));
- }
- wlc_device_removed(wl->wlc);
- wlc_bmac_dngl_reboot(wl->rpc);
- bcm_rpc_down(wl->rpc);
-#endif
- WL_LOCK(wl);
- wl_down(wl);
- WL_UNLOCK(wl);
-#ifdef WLC_HIGH_ONLY
- if (wl->pub->ieee_hw) {
- ieee80211_free_hw(wl->pub->ieee_hw);
- WL_ERROR(("%s: Back from ieee80211_free_hw\n",
- __func__));
- wl->pub->ieee_hw = NULL;
- }
-#endif
- wl_free(wl);
- }
-}
-#endif /* WLC_HIGH_ONLY */
#define CHAN2GHZ(channel, freqency, chflags) { \
@@ -1163,29 +922,13 @@ static struct ieee80211_supported_band wl_band_2GHz_nphy = {
.cap = IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
-#ifdef WLC_HIGH_ONLY
- .ht_supported = true,
- .ampdu_factor = AMPDU_RX_FACTOR_16K,
-#else
.ht_supported = true,
.ampdu_factor = AMPDU_RX_FACTOR_64K,
-#endif
.ampdu_density = AMPDU_DEF_MPDU_DENSITY,
.mcs = {
/* placeholders for now */
-#ifdef WLC_HIGH_ONLY
- /*
- * rx_mask[0] = 0xff by default
- * rx_mask[1] = 0xff if number of rx chain >=2
- * rx_mask[2] = 0xff if number of rx chain >=3
- * rx_mask[4] = 1 if 40Mhz is supported
- */
- .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- .rx_highest = 72, /* max rate of single stream */
-#else
.rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
.rx_highest = 500,
-#endif
.tx_params = IEEE80211_HT_MCS_TX_DEFINED}
}
};
@@ -1212,7 +955,7 @@ static struct ieee80211_supported_band wl_band_5GHz_nphy = {
static int ieee_hw_rate_init(struct ieee80211_hw *hw)
{
- wl_info_t *wl = HW_TO_WL(hw);
+ struct wl_info *wl = HW_TO_WL(hw);
int has_5g;
char phy_list[4];
@@ -1222,20 +965,16 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) {
- WL_ERROR(("Phy list failed\n"));
+ WL_ERROR("Phy list failed\n");
}
- WL_NONE(("%s: phylist = %c\n", __func__, phy_list[0]));
+ WL_NONE("%s: phylist = %c\n", __func__, phy_list[0]);
-#ifndef WLC_HIGH_ONLY
if (phy_list[0] == 'n' || phy_list[0] == 'c') {
if (phy_list[0] == 'c') {
/* Single stream */
wl_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0;
wl_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72;
}
-#else
- if (phy_list[0] == 's') {
-#endif
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy;
} else {
BUG();
@@ -1245,11 +984,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
/* Assume all bands use the same phy. True for 11n devices. */
if (NBANDS_PUB(wl->pub) > 1) {
has_5g++;
-#ifndef WLC_HIGH_ONLY
if (phy_list[0] == 'n' || phy_list[0] == 'c') {
-#else
- if (phy_list[0] == 's') {
-#endif
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&wl_band_5GHz_nphy;
} else {
@@ -1257,7 +992,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
}
}
- WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g));
+ WL_NONE("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g);
return 0;
}
@@ -1288,7 +1023,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
return ieee_hw_rate_init(hw);
}
-#ifndef BCMSDIO
/**
* determines if a device is a WL device, and if so, attaches it.
*
@@ -1300,15 +1034,15 @@ int __devinit
wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc;
- wl_info_t *wl;
+ struct wl_info *wl;
struct ieee80211_hw *hw;
u32 val;
ASSERT(pdev);
- WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__,
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), pdev->irq));
+ WL_TRACE("%s: bus %d slot %d func %d irq %d\n",
+ __func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn), pdev->irq);
if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) ||
(((pdev->device & 0xff00) != 0x4300) &&
@@ -1318,9 +1052,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_enable_device(pdev);
if (rc) {
- WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__,
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn)));
+ WL_ERROR("%s: Cannot enable device %d-%d_%d\n",
+ __func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
return -ENODEV;
}
pci_set_master(pdev);
@@ -1329,9 +1063,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
- hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops);
+ hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops);
if (!hw) {
- WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__));
+ WL_ERROR("%s: ieee80211_alloc_hw failed\n", __func__);
rc = -ENOMEM;
goto err_1;
}
@@ -1340,34 +1074,34 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, hw);
- bzero(hw->priv, sizeof(*wl));
+ memset(hw->priv, 0, sizeof(*wl));
wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0),
PCI_BUS, pdev, pdev->irq);
if (!wl) {
- WL_ERROR(("%s: %s: wl_attach failed!\n",
- KBUILD_MODNAME, __func__));
+ WL_ERROR("%s: %s: wl_attach failed!\n",
+ KBUILD_MODNAME, __func__);
return -ENODEV;
}
return 0;
err_1:
- WL_ERROR(("%s: err_1: Major hoarkage\n", __func__));
+ WL_ERROR("%s: err_1: Major hoarkage\n", __func__);
return 0;
}
#ifdef LINUXSTA_PS
static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
{
- wl_info_t *wl;
+ struct wl_info *wl;
struct ieee80211_hw *hw;
- WL_TRACE(("wl: wl_suspend\n"));
+ WL_TRACE("wl: wl_suspend\n");
hw = pci_get_drvdata(pdev);
wl = HW_TO_WL(hw);
if (!wl) {
- WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n"));
+ WL_ERROR("wl: wl_suspend: pci_get_drvdata failed\n");
return -ENODEV;
}
@@ -1382,16 +1116,16 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
static int wl_resume(struct pci_dev *pdev)
{
- wl_info_t *wl;
+ struct wl_info *wl;
struct ieee80211_hw *hw;
int err = 0;
u32 val;
- WL_TRACE(("wl: wl_resume\n"));
+ WL_TRACE("wl: wl_resume\n");
hw = pci_get_drvdata(pdev);
wl = HW_TO_WL(hw);
if (!wl) {
- WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n"));
+ WL_ERROR("wl: wl_resume: pci_get_drvdata failed\n");
return -ENODEV;
}
@@ -1421,17 +1155,17 @@ static int wl_resume(struct pci_dev *pdev)
static void wl_remove(struct pci_dev *pdev)
{
- wl_info_t *wl;
+ struct wl_info *wl;
struct ieee80211_hw *hw;
hw = pci_get_drvdata(pdev);
wl = HW_TO_WL(hw);
if (!wl) {
- WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n"));
+ WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n");
return;
}
if (!wlc_chipmatch(pdev->vendor, pdev->device)) {
- WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n"));
+ WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n");
return;
}
if (wl->wlc) {
@@ -1439,7 +1173,7 @@ static void wl_remove(struct pci_dev *pdev)
WL_LOCK(wl);
wl_down(wl);
WL_UNLOCK(wl);
- WL_NONE(("%s: Down\n", __func__));
+ WL_NONE("%s: Down\n", __func__);
}
pci_disable_device(pdev);
@@ -1459,7 +1193,6 @@ static struct pci_driver wl_pci_driver = {
.remove = __devexit_p(wl_remove),
.id_table = wl_id_table,
};
-#endif /* !BCMSDIO */
/**
* This is the main entry point for the WL driver.
@@ -1480,7 +1213,6 @@ static int __init wl_module_init(void)
if (var)
wl_msg_level = simple_strtoul(var, NULL, 0);
}
-#ifndef WLC_HIGH_ONLY
{
extern u32 phyhal_msg_level;
@@ -1492,25 +1224,13 @@ static int __init wl_module_init(void)
phyhal_msg_level = simple_strtoul(var, NULL, 0);
}
}
-#endif /* WLC_HIGH_ONLY */
#endif /* BCMDBG */
-#ifndef BCMSDIO
error = pci_register_driver(&wl_pci_driver);
if (!error)
return 0;
-#endif /* !BCMSDIO */
-#ifdef WLC_HIGH_ONLY
- /* BMAC_NOTE: define hardcode number, why NODEVICE is ok ? */
- error =
- dbus_register(BCM_DNGL_VID, 0, wl_dbus_probe_cb,
- wl_dbus_disconnect_cb, NULL, NULL, NULL);
- if (error == DBUS_ERR_NODEVICE) {
- error = DBUS_OK;
- }
-#endif /* WLC_HIGH_ONLY */
return error;
}
@@ -1524,13 +1244,8 @@ static int __init wl_module_init(void)
*/
static void __exit wl_module_exit(void)
{
-#ifndef BCMSDIO
pci_unregister_driver(&wl_pci_driver);
-#endif /* !BCMSDIO */
-#ifdef WLC_HIGH_ONLY
- dbus_deregister();
-#endif /* WLC_HIGH_ONLY */
}
module_init(wl_module_init);
@@ -1543,19 +1258,17 @@ module_exit(wl_module_exit);
* by the wl parameter.
*
*/
-void wl_free(wl_info_t *wl)
+void wl_free(struct wl_info *wl)
{
wl_timer_t *t, *next;
- osl_t *osh;
+ struct osl_info *osh;
ASSERT(wl);
-#ifndef WLC_HIGH_ONLY
/* free ucode data */
if (wl->fw.fw_cnt)
wl_ucode_data_free();
if (wl->irq)
free_irq(wl->irq, wl);
-#endif
/* kill dpc */
tasklet_kill(&wl->tasklet);
@@ -1593,103 +1306,50 @@ void wl_free(wl_info_t *wl)
* unregister_netdev() calls get_stats() which may read chip registers
* so we cannot unmap the chip registers until after calling unregister_netdev() .
*/
- if (wl->regsva && BUSTYPE(wl->bcm_bustype) != SDIO_BUS &&
- BUSTYPE(wl->bcm_bustype) != JTAG_BUS) {
+ if (wl->regsva && wl->bcm_bustype != SDIO_BUS &&
+ wl->bcm_bustype != JTAG_BUS) {
iounmap((void *)wl->regsva);
}
wl->regsva = NULL;
-#ifdef WLC_HIGH_ONLY
- wl_rpcq_free(wl);
-
- wl_txq_free(wl);
-
- if (wl->rpc) {
- bcm_rpc_detach(wl->rpc);
- wl->rpc = NULL;
- }
-
- if (wl->rpc_th) {
- bcm_rpc_tp_detach(wl->rpc_th);
- wl->rpc_th = NULL;
- }
-#endif /* WLC_HIGH_ONLY */
osl_detach(osh);
}
-#ifdef WLC_LOW
/* transmit a packet */
-static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl)
+static int BCMFASTPATH wl_start(struct sk_buff *skb, struct wl_info *wl)
{
if (!wl)
return -ENETDOWN;
return wl_start_int(wl, WL_TO_HW(wl), skb);
}
-#endif /* WLC_LOW */
static int BCMFASTPATH
-wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, struct sk_buff *skb)
+wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb)
{
-#ifdef WLC_HIGH_ONLY
- WL_LOCK(wl);
-#endif
wlc_sendpkt_mac80211(wl->wlc, skb, hw);
-#ifdef WLC_HIGH_ONLY
- WL_UNLOCK(wl);
-#endif
return NETDEV_TX_OK;
}
-void wl_txflowcontrol(wl_info_t *wl, struct wl_if *wlif, bool state, int prio)
+void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state,
+ int prio)
{
- WL_ERROR(("Shouldn't be here %s\n", __func__));
+ WL_ERROR("Shouldn't be here %s\n", __func__);
}
-#if defined(WLC_HIGH_ONLY)
-/* Schedule a completion handler to run at safe time */
-static int
-wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *task),
- void *context)
+void wl_init(struct wl_info *wl)
{
- wl_task_t *task;
-
- WL_TRACE(("wl%d: wl_schedule_task\n", wl->pub->unit));
-
- task = kmalloc(sizeof(wl_task_t), GFP_ATOMIC);
- if (!task) {
- WL_ERROR(("wl%d: wl_schedule_task: out of memory\n", wl->pub->unit));
- return -ENOMEM;
- }
-
- INIT_WORK(&task->work, (work_func_t) fn);
- task->context = context;
-
- if (!schedule_work(&task->work)) {
- WL_ERROR(("wl%d: schedule_work() failed\n", wl->pub->unit));
- kfree(task);
- return -ENOMEM;
- }
-
- atomic_inc(&wl->callbacks);
-
- return 0;
-}
-#endif /* defined(WLC_HIGH_ONLY) */
-
-void wl_init(wl_info_t *wl)
-{
- WL_TRACE(("wl%d: wl_init\n", wl->pub->unit));
+ WL_TRACE("wl%d: wl_init\n", wl->pub->unit);
wl_reset(wl);
wlc_init(wl->wlc);
}
-uint wl_reset(wl_info_t *wl)
+uint wl_reset(struct wl_info *wl)
{
- WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit));
+ WL_TRACE("wl%d: wl_reset\n", wl->pub->unit);
wlc_reset(wl->wlc);
@@ -1703,25 +1363,22 @@ uint wl_reset(wl_info_t *wl)
* These are interrupt on/off entry points. Disable interrupts
* during interrupt state transition.
*/
-void BCMFASTPATH wl_intrson(wl_info_t *wl)
+void BCMFASTPATH wl_intrson(struct wl_info *wl)
{
-#if defined(WLC_LOW)
unsigned long flags;
INT_LOCK(wl, flags);
wlc_intrson(wl->wlc);
INT_UNLOCK(wl, flags);
-#endif /* WLC_LOW */
}
-bool wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth)
+bool wl_alloc_dma_resources(struct wl_info *wl, uint addrwidth)
{
return true;
}
-u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl)
+u32 BCMFASTPATH wl_intrsoff(struct wl_info *wl)
{
-#if defined(WLC_LOW)
unsigned long flags;
u32 status;
@@ -1729,23 +1386,18 @@ u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl)
status = wlc_intrsoff(wl->wlc);
INT_UNLOCK(wl, flags);
return status;
-#else
- return 0;
-#endif /* WLC_LOW */
}
-void wl_intrsrestore(wl_info_t *wl, u32 macintmask)
+void wl_intrsrestore(struct wl_info *wl, u32 macintmask)
{
-#if defined(WLC_LOW)
unsigned long flags;
INT_LOCK(wl, flags);
wlc_intrsrestore(wl->wlc, macintmask);
INT_UNLOCK(wl, flags);
-#endif /* WLC_LOW */
}
-int wl_up(wl_info_t *wl)
+int wl_up(struct wl_info *wl)
{
int error = 0;
@@ -1757,7 +1409,7 @@ int wl_up(wl_info_t *wl)
return error;
}
-void wl_down(wl_info_t *wl)
+void wl_down(struct wl_info *wl)
{
uint callbacks, ret_val = 0;
@@ -1768,24 +1420,21 @@ void wl_down(wl_info_t *wl)
/* wait for down callbacks to complete */
WL_UNLOCK(wl);
-#ifndef WLC_HIGH_ONLY
/* For HIGH_only driver, it's important to actually schedule other work,
* not just spin wait since everything runs at schedule level
*/
SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000);
-#endif /* WLC_HIGH_ONLY */
WL_LOCK(wl);
}
irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id)
{
-#if defined(WLC_LOW)
- wl_info_t *wl;
+ struct wl_info *wl;
bool ours, wantdpc;
unsigned long flags;
- wl = (wl_info_t *) dev_id;
+ wl = (struct wl_info *) dev_id;
WL_ISRLOCK(wl, flags);
@@ -1805,17 +1454,13 @@ irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id)
WL_ISRUNLOCK(wl, flags);
return IRQ_RETVAL(ours);
-#else
- return IRQ_RETVAL(0);
-#endif /* WLC_LOW */
}
static void BCMFASTPATH wl_dpc(unsigned long data)
{
-#ifdef WLC_LOW
- wl_info_t *wl;
+ struct wl_info *wl;
- wl = (wl_info_t *) data;
+ wl = (struct wl_info *) data;
WL_LOCK(wl);
@@ -1846,20 +1491,19 @@ static void BCMFASTPATH wl_dpc(unsigned long data)
done:
WL_UNLOCK(wl);
-#endif /* WLC_LOW */
}
-static void wl_link_up(wl_info_t *wl, char *ifname)
+static void wl_link_up(struct wl_info *wl, char *ifname)
{
- WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname));
+ WL_ERROR("wl%d: link up (%s)\n", wl->pub->unit, ifname);
}
-static void wl_link_down(wl_info_t *wl, char *ifname)
+static void wl_link_down(struct wl_info *wl, char *ifname)
{
- WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname));
+ WL_ERROR("wl%d: link down (%s)\n", wl->pub->unit, ifname);
}
-void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e)
+void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e)
{
switch (e->event.event_type) {
@@ -1877,12 +1521,7 @@ void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e)
static void wl_timer(unsigned long data)
{
-#ifndef WLC_HIGH_ONLY
_wl_timer((wl_timer_t *) data);
-#else
- wl_timer_t *t = (wl_timer_t *) data;
- wl_schedule_task(t->wl, wl_timer_task, t);
-#endif /* WLC_HIGH_ONLY */
}
static void _wl_timer(wl_timer_t *t)
@@ -1906,18 +1545,18 @@ static void _wl_timer(wl_timer_t *t)
WL_UNLOCK(t->wl);
}
-wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg,
+wl_timer_t *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), void *arg,
const char *name)
{
wl_timer_t *t;
t = kmalloc(sizeof(wl_timer_t), GFP_ATOMIC);
if (!t) {
- WL_ERROR(("wl%d: wl_init_timer: out of memory\n", wl->pub->unit));
+ WL_ERROR("wl%d: wl_init_timer: out of memory\n", wl->pub->unit);
return 0;
}
- bzero(t, sizeof(wl_timer_t));
+ memset(t, 0, sizeof(wl_timer_t));
init_timer(&t->timer);
t->timer.data = (unsigned long) t;
@@ -1940,12 +1579,12 @@ wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg,
/* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
* as well as it's easier to make it periodic
*/
-void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic)
+void wl_add_timer(struct wl_info *wl, wl_timer_t *t, uint ms, int periodic)
{
#ifdef BCMDBG
if (t->set) {
- WL_ERROR(("%s: Already set. Name: %s, per %d\n",
- __func__, t->name, periodic));
+ WL_ERROR("%s: Already set. Name: %s, per %d\n",
+ __func__, t->name, periodic);
}
#endif
ASSERT(!t->set);
@@ -1960,7 +1599,7 @@ void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic)
}
/* return true if timer successfully deleted, false if still pending */
-bool wl_del_timer(wl_info_t *wl, wl_timer_t *t)
+bool wl_del_timer(struct wl_info *wl, wl_timer_t *t)
{
if (t->set) {
t->set = false;
@@ -1973,7 +1612,7 @@ bool wl_del_timer(wl_info_t *wl, wl_timer_t *t)
return true;
}
-void wl_free_timer(wl_info_t *wl, wl_timer_t *t)
+void wl_free_timer(struct wl_info *wl, wl_timer_t *t)
{
wl_timer_t *tmp;
@@ -2009,7 +1648,7 @@ void wl_free_timer(wl_info_t *wl, wl_timer_t *t)
static int wl_linux_watchdog(void *ctx)
{
- wl_info_t *wl = (wl_info_t *) ctx;
+ struct wl_info *wl = (struct wl_info *) ctx;
struct net_device_stats *stats = NULL;
uint id;
/* refresh stats */
@@ -2049,233 +1688,12 @@ struct wl_fw_hdr {
u32 idx;
};
-#ifdef WLC_HIGH_ONLY
-static void wl_rpc_down(void *wlh)
-{
- wl_info_t *wl = (wl_info_t *) (wlh);
-
- wlc_device_removed(wl->wlc);
-
- wl_rpcq_free(wl);
-}
-
-static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl)
-{
-
- unsigned long flags;
-
- skb->prev = NULL;
-
- /* Lock the queue as tasklet could be running at this time */
- TXQ_LOCK(wl, flags);
- if (wl->txq_head == NULL)
- wl->txq_head = skb;
- else {
- wl->txq_tail->prev = skb;
- }
- wl->txq_tail = skb;
-
- if (wl->txq_dispatched == false) {
- wl->txq_dispatched = true;
-
- if (schedule_work(&wl->txq_task.work)) {
- atomic_inc(&wl->callbacks);
- } else {
- WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
- wl->pub->unit));
- }
- }
-
- TXQ_UNLOCK(wl, flags);
-
- return 0;
-
-}
-
-static void wl_start_txqwork(struct wl_task *task)
-{
- wl_info_t *wl = (wl_info_t *) task->context;
- struct sk_buff *skb;
- unsigned long flags;
- uint count = 0;
-
- WL_TRACE(("wl%d: wl_start_txqwork\n", wl->pub->unit));
-
- /* First remove an entry then go for execution */
- TXQ_LOCK(wl, flags);
- while (wl->txq_head) {
- skb = wl->txq_head;
- wl->txq_head = skb->prev;
- skb->prev = NULL;
- if (wl->txq_head == NULL)
- wl->txq_tail = NULL;
- TXQ_UNLOCK(wl, flags);
-
- /* it has WL_LOCK/WL_UNLOCK inside */
- wl_start_int(wl, WL_TO_HW(wl), skb);
-
- /* bounded our execution, reshedule ourself next */
- if (++count >= 10)
- break;
-
- TXQ_LOCK(wl, flags);
- }
-
- if (count >= 10) {
- if (!schedule_work(&wl->txq_task.work)) {
- WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
- wl->pub->unit));
- atomic_dec(&wl->callbacks);
- }
- } else {
- wl->txq_dispatched = false;
- TXQ_UNLOCK(wl, flags);
- atomic_dec(&wl->callbacks);
- }
-
- return;
-}
-
-static void wl_txq_free(wl_info_t *wl)
-{
- struct sk_buff *skb;
-
- if (wl->txq_head == NULL) {
- ASSERT(wl->txq_tail == NULL);
- return;
- }
-
- while (wl->txq_head) {
- skb = wl->txq_head;
- wl->txq_head = skb->prev;
- PKTFREE(wl->osh, skb, true);
- }
-
- wl->txq_tail = NULL;
-}
-
-static void wl_rpcq_free(wl_info_t *wl)
-{
- rpc_buf_t *buf;
-
- if (wl->rpcq_head == NULL) {
- ASSERT(wl->rpcq_tail == NULL);
- return;
- }
-
- while (wl->rpcq_head) {
- buf = wl->rpcq_head;
- wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf);
- bcm_rpc_buf_free(wl->rpc_dispatch_ctx.rpc, buf);
- }
-
- wl->rpcq_tail = NULL;
-}
-
-static void wl_rpcq_dispatch(struct wl_task *task)
-{
- wl_info_t *wl = (wl_info_t *) task->context;
- rpc_buf_t *buf;
- unsigned long flags;
-
- /* First remove an entry then go for execution */
- RPCQ_LOCK(wl, flags);
- while (wl->rpcq_head) {
- buf = wl->rpcq_head;
- wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf);
-
- if (wl->rpcq_head == NULL)
- wl->rpcq_tail = NULL;
- RPCQ_UNLOCK(wl, flags);
-
- WL_LOCK(wl);
- wlc_rpc_high_dispatch(&wl->rpc_dispatch_ctx, buf);
- WL_UNLOCK(wl);
-
- RPCQ_LOCK(wl, flags);
- }
-
- wl->rpcq_dispatched = false;
-
- RPCQ_UNLOCK(wl, flags);
-
- kfree(task);
- atomic_dec(&wl->callbacks);
-}
-
-static void wl_rpcq_add(wl_info_t *wl, rpc_buf_t *buf)
-{
- unsigned long flags;
-
- bcm_rpc_buf_next_set(wl->rpc_th, buf, NULL);
-
- /* Lock the queue as tasklet could be running at this time */
- RPCQ_LOCK(wl, flags);
- if (wl->rpcq_head == NULL)
- wl->rpcq_head = buf;
- else
- bcm_rpc_buf_next_set(wl->rpc_th, wl->rpcq_tail, buf);
-
- wl->rpcq_tail = buf;
-
- if (wl->rpcq_dispatched == false) {
- wl->rpcq_dispatched = true;
- wl_schedule_task(wl, wl_rpcq_dispatch, wl);
- }
-
- RPCQ_UNLOCK(wl, flags);
-}
-
-#if defined(BCMDBG)
-static const struct name_entry rpc_name_tbl[] = RPC_ID_TABLE;
-#endif /* BCMDBG */
-
-/* dongle-side rpc dispatch routine */
-static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf)
-{
- bcm_xdr_buf_t b;
- wl_info_t *wl = (wl_info_t *) ctx;
- wlc_rpc_id_t rpc_id;
- int err;
-
- bcm_xdr_buf_init(&b, bcm_rpc_buf_data(wl->rpc_th, buf),
- bcm_rpc_buf_len_get(wl->rpc_th, buf));
-
- err = bcm_xdr_unpack_u32(&b, &rpc_id);
- ASSERT(!err);
- WL_TRACE(("%s: Dispatch id %s\n", __func__,
- WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id)));
-
- /* Handle few emergency ones */
- switch (rpc_id) {
- default:
- wl_rpcq_add(wl, buf);
- break;
- }
-}
-
-static void wl_timer_task(wl_task_t *task)
-{
- wl_timer_t *t = (wl_timer_t *) task->context;
-
- _wl_timer(t);
- kfree(task);
-
- /* This dec is for the task_schedule. The timer related
- * callback is decremented in _wl_timer
- */
- atomic_dec(&t->wl->callbacks);
-}
-#endif /* WLC_HIGH_ONLY */
-
-#ifndef WLC_HIGH_ONLY
char *wl_firmwares[WL_MAX_FW] = {
"brcm/bcm43xx",
NULL
};
-#ifdef WLC_LOW
-int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx)
+int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx)
{
int i, entry;
const u8 *pdata;
@@ -2301,7 +1719,7 @@ int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx)
return -1;
}
-int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx)
+int wl_ucode_init_uint(struct wl_info *wl, u32 *data, u32 idx)
{
int i, entry;
const u8 *pdata;
@@ -2321,22 +1739,21 @@ int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx)
printf("ERROR: ucode tag:%d can not be found!\n", idx);
return -1;
}
-#endif /* WLC_LOW */
-static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev)
+static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev)
{
int status;
struct device *device = &pdev->dev;
char fw_name[100];
int i;
- bzero((void *)&wl->fw, sizeof(struct wl_firmware));
+ memset((void *)&wl->fw, 0, sizeof(struct wl_firmware));
for (i = 0; i < WL_MAX_FW; i++) {
if (wl_firmwares[i] == NULL)
break;
sprintf(fw_name, "%s-%d.fw", wl_firmwares[i],
UCODE_LOADER_API_VER);
- WL_NONE(("request fw %s\n", fw_name));
+ WL_NONE("request fw %s\n", fw_name);
status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
if (status) {
printf("%s: fail to load firmware %s\n",
@@ -2344,7 +1761,7 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev)
wl_release_fw(wl);
return status;
}
- WL_NONE(("request fw %s\n", fw_name));
+ WL_NONE("request fw %s\n", fw_name);
sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i],
UCODE_LOADER_API_VER);
status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
@@ -2356,22 +1773,19 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev)
}
wl->fw.hdr_num_entries[i] =
wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr));
- WL_NONE(("request fw %s find: %d entries\n", fw_name,
- wl->fw.hdr_num_entries[i]));
+ WL_NONE("request fw %s find: %d entries\n",
+ fw_name, wl->fw.hdr_num_entries[i]);
}
wl->fw.fw_cnt = i;
- wl_ucode_data_init(wl);
- return 0;
+ return wl_ucode_data_init(wl);
}
-#ifdef WLC_LOW
void wl_ucode_free_buf(void *p)
{
kfree(p);
}
-#endif /* WLC_LOW */
-static void wl_release_fw(wl_info_t *wl)
+static void wl_release_fw(struct wl_info *wl)
{
int i;
for (i = 0; i < WL_MAX_FW; i++) {
@@ -2379,4 +1793,54 @@ static void wl_release_fw(wl_info_t *wl)
release_firmware(wl->fw.fw_hdr[i]);
}
}
-#endif /* WLC_HIGH_ONLY */
+
+
+/*
+ * checks validity of all firmware images loaded from user space
+ */
+int wl_check_firmwares(struct wl_info *wl)
+{
+ int i;
+ int entry;
+ int rc = 0;
+ const struct firmware *fw;
+ const struct firmware *fw_hdr;
+ struct wl_fw_hdr *ucode_hdr;
+ for (i = 0; i < WL_MAX_FW && rc == 0; i++) {
+ fw = wl->fw.fw_bin[i];
+ fw_hdr = wl->fw.fw_hdr[i];
+ if (fw == NULL && fw_hdr == NULL) {
+ break;
+ } else if (fw == NULL || fw_hdr == NULL) {
+ WL_ERROR("%s: invalid bin/hdr fw\n", __func__);
+ rc = -EBADF;
+ } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) {
+ WL_ERROR("%s: non integral fw hdr file size %d/%zu\n",
+ __func__, fw_hdr->size,
+ sizeof(struct wl_fw_hdr));
+ rc = -EBADF;
+ } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {
+ WL_ERROR("%s: out of bounds fw file size %d\n",
+ __func__, fw->size);
+ rc = -EBADF;
+ } else {
+ /* check if ucode section overruns firmware image */
+ ucode_hdr = (struct wl_fw_hdr *)fw_hdr->data;
+ for (entry = 0; entry < wl->fw.hdr_num_entries[i] && rc;
+ entry++, ucode_hdr++) {
+ if (ucode_hdr->offset + ucode_hdr->len >
+ fw->size) {
+ WL_ERROR("%s: conflicting bin/hdr\n",
+ __func__);
+ rc = -EBADF;
+ }
+ }
+ }
+ }
+ if (rc == 0 && wl->fw.fw_cnt != i) {
+ WL_ERROR("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt);
+ rc = -EBADF;
+ }
+ return rc;
+}
+
diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h
index 78cee4454b0b..bb39b7705947 100644
--- a/drivers/staging/brcm80211/sys/wl_mac80211.h
+++ b/drivers/staging/brcm80211/sys/wl_mac80211.h
@@ -60,58 +60,32 @@ struct wl_firmware {
};
struct wl_info {
- wlc_pub_t *pub; /* pointer to public wlc state */
+ struct wlc_pub *pub; /* pointer to public wlc state */
void *wlc; /* pointer to private common os-independent data */
- osl_t *osh; /* pointer to os handler */
+ struct osl_info *osh; /* pointer to os handler */
u32 magic;
int irq;
-#ifdef WLC_HIGH_ONLY
- struct semaphore sem; /* use semaphore to allow sleep */
-#else
spinlock_t lock; /* per-device perimeter lock */
spinlock_t isr_lock; /* per-device ISR synchronization lock */
-#endif
uint bcm_bustype; /* bus type */
bool piomode; /* set from insmod argument */
void *regsva; /* opaque chip registers virtual address */
atomic_t callbacks; /* # outstanding callback functions */
struct wl_timer *timers; /* timer cleanup queue */
struct tasklet_struct tasklet; /* dpc tasklet */
-#ifdef BCMSDIO
- bcmsdh_info_t *sdh; /* pointer to sdio bus handler */
- unsigned long flags; /* current irq flags */
-#endif /* BCMSDIO */
bool resched; /* dpc needs to be and is rescheduled */
#ifdef LINUXSTA_PS
u32 pci_psstate[16]; /* pci ps-state save/restore */
#endif
/* RPC, handle, lock, txq, workitem */
-#ifdef WLC_HIGH_ONLY
- rpc_info_t *rpc; /* RPC handle */
- rpc_tp_info_t *rpc_th; /* RPC transport handle */
- wlc_rpc_ctx_t rpc_dispatch_ctx;
-
- bool rpcq_dispatched; /* Avoid scheduling multiple tasks */
- spinlock_t rpcq_lock; /* Lock for the queue */
- rpc_buf_t *rpcq_head; /* RPC Q */
- rpc_buf_t *rpcq_tail; /* Points to the last buf */
-
- bool txq_dispatched; /* Avoid scheduling multiple tasks */
- spinlock_t txq_lock; /* Lock for the queue */
- struct sk_buff *txq_head; /* TX Q */
- struct sk_buff *txq_tail; /* Points to the last buf */
-
- wl_task_t txq_task; /* work queue for wl_start() */
-#endif /* WLC_HIGH_ONLY */
uint stats_id; /* the current set of stats */
/* ping-pong stats counters updated by Linux watchdog */
struct net_device_stats stats_watchdog[2];
struct wl_firmware fw;
};
-#ifndef WLC_HIGH_ONLY
#define WL_LOCK(wl) spin_lock_bh(&(wl)->lock)
#define WL_UNLOCK(wl) spin_unlock_bh(&(wl)->lock)
@@ -122,17 +96,6 @@ struct wl_info {
/* locking under WL_LOCK() to synchronize with wl_isr */
#define INT_LOCK(wl, flags) spin_lock_irqsave(&(wl)->isr_lock, flags)
#define INT_UNLOCK(wl, flags) spin_unlock_irqrestore(&(wl)->isr_lock, flags)
-#else /* BCMSDIO */
-
-#define WL_LOCK(wl) down(&(wl)->sem)
-#define WL_UNLOCK(wl) up(&(wl)->sem)
-
-#define WL_ISRLOCK(wl)
-#define WL_ISRUNLOCK(wl)
-#endif /* WLC_HIGH_ONLY */
-
-/* handle forward declaration */
-typedef struct wl_info wl_info_t;
#ifndef PCI_D0
#define PCI_D0 0
@@ -148,14 +111,7 @@ extern irqreturn_t wl_isr(int irq, void *dev_id);
extern int __devinit wl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
-extern void wl_free(wl_info_t *wl);
+extern void wl_free(struct wl_info *wl);
extern int wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-extern int wl_ucode_data_init(wl_info_t *wl);
-extern void wl_ucode_data_free(void);
-#ifdef WLC_LOW
-extern void wl_ucode_free_buf(void *);
-extern int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx);
-extern int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx);
-#endif /* WLC_LOW */
#endif /* _wl_mac80211_h_ */
diff --git a/drivers/staging/brcm80211/sys/wl_ucode.h b/drivers/staging/brcm80211/sys/wl_ucode.h
index a1ba37209f96..2a0f4028f6f3 100644
--- a/drivers/staging/brcm80211/sys/wl_ucode.h
+++ b/drivers/staging/brcm80211/sys/wl_ucode.h
@@ -14,6 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define MIN_FW_SIZE 40000 /* minimum firmware file size in bytes */
+#define MAX_FW_SIZE 150000
+
typedef struct d11init {
u16 addr;
u16 size;
@@ -35,3 +38,12 @@ extern u32 *bcm43xx_24_lcn;
extern u32 bcm43xx_24_lcnsz;
extern u32 *bcm43xx_bommajor;
extern u32 *bcm43xx_bomminor;
+
+extern int wl_ucode_data_init(struct wl_info *wl);
+extern void wl_ucode_data_free(void);
+
+extern int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, unsigned int idx);
+extern int wl_ucode_init_uint(struct wl_info *wl, unsigned *data,
+ unsigned int idx);
+extern void wl_ucode_free_buf(void *);
+extern int wl_check_firmwares(struct wl_info *wl);
diff --git a/drivers/staging/brcm80211/sys/wl_ucode_loader.c b/drivers/staging/brcm80211/sys/wl_ucode_loader.c
index 0b41a9cb1ec9..23e10f3dec0d 100644
--- a/drivers/staging/brcm80211/sys/wl_ucode_loader.c
+++ b/drivers/staging/brcm80211/sys/wl_ucode_loader.c
@@ -14,17 +14,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-typedef struct wl_info wl_info_t;
#include <linux/types.h>
#include <bcmdefs.h>
#include <d11ucode_ext.h>
#include <wl_ucode.h>
-extern int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, unsigned int idx);
-extern int wl_ucode_init_uint(wl_info_t *wl, unsigned *data, unsigned int idx);
-extern int wl_ucode_data_init(wl_info_t *wl);
-extern void wl_ucode_data_free(void);
-extern void wl_ucode_free_buf(void *);
+
d11init_t *d11lcn0bsinitvals24;
d11init_t *d11lcn0initvals24;
@@ -42,8 +37,12 @@ u32 bcm43xx_24_lcnsz;
u32 *bcm43xx_bommajor;
u32 *bcm43xx_bomminor;
-int wl_ucode_data_init(wl_info_t *wl)
+int wl_ucode_data_init(struct wl_info *wl)
{
+ int rc;
+ rc = wl_check_firmwares(wl);
+ if (rc < 0)
+ return rc;
wl_ucode_init_buf(wl, (void **)&d11lcn0bsinitvals24,
D11LCN0BSINITVALS24);
wl_ucode_init_buf(wl, (void **)&d11lcn0initvals24, D11LCN0INITVALS24);
diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c
index 2dc89f9c2635..746439e8fd57 100644
--- a/drivers/staging/brcm80211/sys/wlc_alloc.c
+++ b/drivers/staging/brcm80211/sys/wlc_alloc.c
@@ -17,28 +17,33 @@
#include <linux/string.h>
#include <bcmdefs.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <wlioctl.h>
#include <wlc_pub.h>
#include <wlc_key.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_alloc.h>
+#include <wl_dbg.h>
-static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err,
- uint devid);
-static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub);
+static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit,
+ uint *err, uint devid);
+static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub);
static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid);
-void *wlc_calloc(osl_t *osh, uint unit, uint size)
+void *wlc_calloc(struct osl_info *osh, uint unit, uint size)
{
void *item;
item = kzalloc(size, GFP_ATOMIC);
if (item == NULL)
- WL_ERROR(("wl%d: %s: out of memory\n", unit, __func__));
+ WL_ERROR("wl%d: %s: out of memory\n", unit, __func__);
return item;
}
@@ -58,18 +63,14 @@ void wlc_tunables_init(wlc_tunables_t *tunables, uint devid)
tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT;
tunables->rxbnd = RXBND;
tunables->txsbnd = TXSBND;
-#if defined(WLC_HIGH_ONLY) && defined(NTXD_USB_4319)
- if (devid == BCM4319_CHIP_ID) {
- tunables->ntxd = NTXD_USB_4319;
- }
-#endif /* WLC_HIGH_ONLY */
}
-static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid)
+static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit,
+ uint *err, uint devid)
{
- wlc_pub_t *pub;
+ struct wlc_pub *pub;
- pub = (wlc_pub_t *) wlc_calloc(osh, unit, sizeof(wlc_pub_t));
+ pub = (struct wlc_pub *) wlc_calloc(osh, unit, sizeof(struct wlc_pub));
if (pub == NULL) {
*err = 1001;
goto fail;
@@ -99,7 +100,7 @@ static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid)
return NULL;
}
-static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub)
+static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub)
{
if (pub == NULL)
return;
@@ -114,7 +115,7 @@ static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub)
kfree(pub);
}
-wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit)
+wlc_bsscfg_t *wlc_bsscfg_malloc(struct osl_info *osh, uint unit)
{
wlc_bsscfg_t *cfg;
@@ -134,7 +135,7 @@ wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit)
return NULL;
}
-void wlc_bsscfg_mfree(osl_t *osh, wlc_bsscfg_t *cfg)
+void wlc_bsscfg_mfree(struct osl_info *osh, wlc_bsscfg_t *cfg)
{
if (cfg == NULL)
return;
@@ -155,7 +156,7 @@ void wlc_bsscfg_mfree(osl_t *osh, wlc_bsscfg_t *cfg)
kfree(cfg);
}
-void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg)
+void wlc_bsscfg_ID_assign(struct wlc_info *wlc, wlc_bsscfg_t *bsscfg)
{
bsscfg->ID = wlc->next_bsscfg_ID;
wlc->next_bsscfg_ID++;
@@ -164,11 +165,13 @@ void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg)
/*
* The common driver entry routine. Error codes should be unique
*/
-wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
+struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err,
+ uint devid)
{
- wlc_info_t *wlc;
+ struct wlc_info *wlc;
- wlc = (wlc_info_t *) wlc_calloc(osh, unit, sizeof(wlc_info_t));
+ wlc = (struct wlc_info *) wlc_calloc(osh, unit,
+ sizeof(struct wlc_info));
if (wlc == NULL) {
*err = 1002;
goto fail;
@@ -176,7 +179,7 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
wlc->hwrxoff = WL_HWRXOFF;
- /* allocate wlc_pub_t state structure */
+ /* allocate struct wlc_pub state structure */
wlc->pub = wlc_pub_malloc(osh, unit, err, devid);
if (wlc->pub == NULL) {
*err = 1003;
@@ -184,17 +187,16 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
}
wlc->pub->wlc = wlc;
- /* allocate wlc_hw_info_t state structure */
+ /* allocate struct wlc_hw_info state structure */
- wlc->hw = (wlc_hw_info_t *)wlc_calloc(osh, unit,
- sizeof(wlc_hw_info_t));
+ wlc->hw = (struct wlc_hw_info *)wlc_calloc(osh, unit,
+ sizeof(struct wlc_hw_info));
if (wlc->hw == NULL) {
*err = 1005;
goto fail;
}
wlc->hw->wlc = wlc;
-#ifdef WLC_LOW
wlc->hw->bandstate[0] = (wlc_hwband_t *)wlc_calloc(osh, unit,
(sizeof(wlc_hwband_t) * MAXBANDS));
if (wlc->hw->bandstate[0] == NULL) {
@@ -209,7 +211,6 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
(sizeof(wlc_hwband_t) * i));
}
}
-#endif /* WLC_LOW */
wlc->modulecb = (modulecb_t *)wlc_calloc(osh, unit,
sizeof(modulecb_t) * WLC_MAXMODULES);
@@ -266,8 +267,8 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
goto fail;
}
- wlc->bandstate[0] = (wlcband_t *)wlc_calloc(osh, unit,
- (sizeof(wlcband_t) * MAXBANDS));
+ wlc->bandstate[0] = (struct wlcband *)wlc_calloc(osh, unit,
+ (sizeof(struct wlcband)*MAXBANDS));
if (wlc->bandstate[0] == NULL) {
*err = 1025;
goto fail;
@@ -276,12 +277,13 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
for (i = 1; i < MAXBANDS; i++) {
wlc->bandstate[i] =
- (wlcband_t *) ((unsigned long)wlc->bandstate[0] +
- (sizeof(wlcband_t) * i));
+ (struct wlcband *) ((unsigned long)wlc->bandstate[0]
+ + (sizeof(struct wlcband)*i));
}
}
- wlc->corestate = (wlccore_t *)wlc_calloc(osh, unit, sizeof(wlccore_t));
+ wlc->corestate = (struct wlccore *)wlc_calloc(osh, unit,
+ sizeof(struct wlccore));
if (wlc->corestate == NULL) {
*err = 1026;
goto fail;
@@ -301,7 +303,7 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
return NULL;
}
-void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh)
+void wlc_detach_mfree(struct wlc_info *wlc, struct osl_info *osh)
{
if (wlc == NULL)
return;
@@ -355,12 +357,10 @@ void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh)
}
if (wlc->hw) {
-#ifdef WLC_LOW
if (wlc->hw->bandstate[0]) {
kfree(wlc->hw->bandstate[0]);
wlc->hw->bandstate[0] = NULL;
}
-#endif
/* free hw struct */
kfree(wlc->hw);
diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.h b/drivers/staging/brcm80211/sys/wlc_alloc.h
index 678a2b9784f8..ac34f782b400 100644
--- a/drivers/staging/brcm80211/sys/wlc_alloc.h
+++ b/drivers/staging/brcm80211/sys/wlc_alloc.h
@@ -14,12 +14,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-extern void *wlc_calloc(osl_t *osh, uint unit, uint size);
+extern void *wlc_calloc(struct osl_info *osh, uint unit, uint size);
-extern wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err,
- uint devid);
-extern void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh);
+extern struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit,
+ uint *err, uint devid);
+extern void wlc_detach_mfree(struct wlc_info *wlc, struct osl_info *osh);
struct wlc_bsscfg;
-extern struct wlc_bsscfg *wlc_bsscfg_malloc(osl_t *osh, uint unit);
-extern void wlc_bsscfg_mfree(osl_t *osh, struct wlc_bsscfg *cfg);
+extern struct wlc_bsscfg *wlc_bsscfg_malloc(struct osl_info *osh, uint unit);
+extern void wlc_bsscfg_mfree(struct osl_info *osh, struct wlc_bsscfg *cfg);
diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c
index a4e49f3c1363..d749917f5912 100644
--- a/drivers/staging/brcm80211/sys/wlc_ampdu.c
+++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c
@@ -16,19 +16,19 @@
#include <linux/kernel.h>
#include <wlc_cfg.h>
#include <bcmdefs.h>
-#include <linuxver.h>
-#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmendian.h>
#include <wlioctl.h>
+#include <sbhndpio.h>
#include <sbhnddma.h>
#include <hnddma.h>
#include <d11.h>
#include <wlc_rate.h>
#include <wlc_pub.h>
#include <wlc_key.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_phy_hal.h>
#include <wlc_antsel.h>
@@ -36,11 +36,8 @@
#include <net/mac80211.h>
#include <wlc_ampdu.h>
#include <wl_export.h>
+#include <wl_dbg.h>
-#ifdef WLC_HIGH_ONLY
-#include <bcm_rpc_tp.h>
-#include <wlc_rpctx.h>
-#endif
#define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
#define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
@@ -101,7 +98,7 @@ typedef struct wlc_fifo_info {
/* AMPDU module specific state */
struct ampdu_info {
- wlc_info_t *wlc; /* pointer to main wlc structure */
+ struct wlc_info *wlc; /* pointer to main wlc structure */
int scb_handle; /* scb cubby handle to retrieve data from scb */
u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
@@ -125,11 +122,6 @@ struct ampdu_info {
*/
wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
-#ifdef WLC_HIGH_ONLY
- void *p;
- tx_status_t txs;
- bool waiting_status; /* To help sanity checks */
-#endif
};
#define AMPDU_CLEANUPFLAG_RX (0x1)
@@ -138,38 +130,39 @@ struct ampdu_info {
#define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
#define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
-static void wlc_ffpld_init(ampdu_info_t *ampdu);
-static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int f);
-static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f);
+static void wlc_ffpld_init(struct ampdu_info *ampdu);
+static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
+static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
-static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
+static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
scb_ampdu_t *scb_ampdu,
u8 tid, bool override);
-static void ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu,
+static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu,
+ scb_ampdu_t *scb_ampdu,
u8 tid, bool force);
-static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur);
-static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb);
-static void scb_ampdu_update_config_all(ampdu_info_t *ampdu);
+static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
+static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
+static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
#define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
-static void wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb,
- void *p, tx_status_t *txs,
- u32 frmtxstatus,
- u32 frmtxstatus2);
+static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
+ struct scb *scb,
+ struct sk_buff *p, tx_status_t *txs,
+ u32 frmtxstatus, u32 frmtxstatus2);
-static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, void *p)
+static inline u16 pkt_txh_seqnum(struct wlc_info *wlc, struct sk_buff *p)
{
d11txh_t *txh;
struct dot11_header *h;
- txh = (d11txh_t *) PKTDATA(p);
+ txh = (d11txh_t *) p->data;
h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
return ltoh16(h->seq) >> SEQNUM_SHIFT;
}
-ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc)
+struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
{
- ampdu_info_t *ampdu;
+ struct ampdu_info *ampdu;
int i;
/* some code depends on packed structures */
@@ -179,9 +172,10 @@ ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc)
ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
- ampdu = kzalloc(sizeof(ampdu_info_t), GFP_ATOMIC);
+ ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
if (!ampdu) {
- WL_ERROR(("wl%d: wlc_ampdu_attach: out of mem\n", wlc->pub->unit));
+ WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n",
+ wlc->pub->unit);
return NULL;
}
ampdu->wlc = wlc;
@@ -209,10 +203,6 @@ ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc)
ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
else
ampdu->rx_factor = AMPDU_RX_FACTOR_64K;
-#ifdef WLC_HIGH_ONLY
- /* Restrict to smaller rcv size for BMAC dongle */
- ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
-#endif
ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
@@ -232,7 +222,7 @@ ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc)
return ampdu;
}
-void wlc_ampdu_detach(ampdu_info_t *ampdu)
+void wlc_ampdu_detach(struct ampdu_info *ampdu)
{
int i;
@@ -250,12 +240,12 @@ void wlc_ampdu_detach(ampdu_info_t *ampdu)
kfree(ampdu);
}
-void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb)
+void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb)
{
scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
u8 tid;
- WL_AMPDU_UPDN(("scb_ampdu_cleanup: enter\n"));
+ WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n");
ASSERT(scb_ampdu);
for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
@@ -266,12 +256,12 @@ void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb)
/* reset the ampdu state machine so that it can gracefully handle packets that were
* freed from the dma and tx queues during reinit
*/
-void wlc_ampdu_reset(ampdu_info_t *ampdu)
+void wlc_ampdu_reset(struct ampdu_info *ampdu)
{
- WL_NONE(("%s: Entering\n", __func__));
+ WL_NONE("%s: Entering\n", __func__);
}
-static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb)
+static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
{
scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
int i;
@@ -301,12 +291,12 @@ static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb)
ASSERT(scb_ampdu->release);
}
-void scb_ampdu_update_config_all(ampdu_info_t *ampdu)
+void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
{
scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
}
-static void wlc_ffpld_init(ampdu_info_t *ampdu)
+static void wlc_ffpld_init(struct ampdu_info *ampdu)
{
int i, j;
wlc_fifo_info_t *fifo;
@@ -330,9 +320,9 @@ static void wlc_ffpld_init(ampdu_info_t *ampdu)
* Return 1 if pre-loading not active, -1 if not an underflow event,
* 0 if pre-loading module took care of the event.
*/
-static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
+static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
{
- ampdu_info_t *ampdu = wlc->ampdu;
+ struct ampdu_info *ampdu = wlc->ampdu;
u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
u32 txunfl_ratio;
u8 max_mpdu;
@@ -349,7 +339,7 @@ static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
if (new_txunfl == 0) {
- WL_FFPLD(("check_txunfl : TX status FRAG set but no tx underflows\n"));
+ WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n");
return -1;
}
fifo->prev_txfunfl = cur_txunfl;
@@ -359,7 +349,7 @@ static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
/* check if fifo is big enough */
if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
- WL_FFPLD(("check_txunfl : get xmtfifo_sz failed.\n"));
+ WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n");
return -1;
}
@@ -373,8 +363,8 @@ static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
if (fifo->accum_txfunfl < 10)
return 0;
- WL_FFPLD(("ampdu_count %d tx_underflows %d\n",
- current_ampdu_cnt, fifo->accum_txfunfl));
+ WL_FFPLD("ampdu_count %d tx_underflows %d\n",
+ current_ampdu_cnt, fifo->accum_txfunfl);
/*
compute the current ratio of tx unfl per ampdu.
@@ -427,8 +417,8 @@ static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
(max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
/ (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
- WL_FFPLD(("DMA estimated transfer rate %d; pre-load size %d\n",
- fifo->dmaxferrate, fifo->ampdu_pld_size));
+ WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n",
+ fifo->dmaxferrate, fifo->ampdu_pld_size);
} else {
/* decrease ampdu size */
@@ -450,7 +440,7 @@ static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
return 0;
}
-static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f)
+static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
{
int i;
u32 phy_rate, dma_rate, tmp;
@@ -483,11 +473,12 @@ static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f)
}
static void BCMFASTPATH
-wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, void *p, uint prec)
+wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
+ uint prec)
{
scb_ampdu_t *scb_ampdu;
scb_ampdu_tid_ini_t *ini;
- u8 tid = (u8) PKTPRIO(p);
+ u8 tid = (u8) (p->priority);
scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
@@ -500,11 +491,12 @@ wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, void *p, uint prec)
}
int BCMFASTPATH
-wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
+wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi,
+ struct sk_buff **pdu, int prec)
{
- wlc_info_t *wlc;
- osl_t *osh;
- void *p, *pkt[AMPDU_MAX_MPDU];
+ struct wlc_info *wlc;
+ struct osl_info *osh;
+ struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
u8 tid, ndelim;
int err = 0;
u8 preamble_type = WLC_GF_PREAMBLE;
@@ -540,7 +532,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
ASSERT(p);
- tid = (u8) PKTPRIO(p);
+ tid = (u8) (p->priority);
ASSERT(tid < AMPDU_MAX_SCB_TID);
f = ampdu->fifo_tb + prio2fifo[tid];
@@ -561,7 +553,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
wlc_ampdu_agg(ampdu, scb, p, tid);
if (wlc->block_datafifo) {
- WL_ERROR(("%s: Fifo blocked\n", __func__));
+ WL_ERROR("%s: Fifo blocked\n", __func__);
return BCME_BUSY;
}
rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
@@ -576,7 +568,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
err = wlc_prep_pdu(wlc, p, &fifo);
} else {
- WL_ERROR(("%s: AMPDU flag is off!\n", __func__));
+ WL_ERROR("%s: AMPDU flag is off!\n", __func__);
*pdu = NULL;
err = 0;
break;
@@ -584,14 +576,16 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
if (err) {
if (err == BCME_BUSY) {
- WL_ERROR(("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n", wlc->pub->unit, seq));
+ WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n",
+ wlc->pub->unit, seq);
WLCNTINCR(ampdu->cnt->sduretry);
*pdu = p;
break;
}
/* error in the packet; reject it */
- WL_AMPDU_ERR(("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n", wlc->pub->unit, seq));
+ WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n",
+ wlc->pub->unit, seq);
WLCNTINCR(ampdu->cnt->sdurejected);
*pdu = NULL;
@@ -600,7 +594,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
/* pkt is good to be aggregated */
ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
- txh = (d11txh_t *) PKTDATA(p);
+ txh = (d11txh_t *) p->data;
plcp = (u8 *) (txh + 1);
h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN);
seq = ltoh16(h->seq) >> SEQNUM_SHIFT;
@@ -633,8 +627,8 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
seg_cnt += 1;
- WL_AMPDU_TX(("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
- wlc->pub->unit, count, len));
+ WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
+ wlc->pub->unit, count, len);
/*
* aggregateable mpdu. For ucode/hw agg,
@@ -665,7 +659,8 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
dma_len += (u16) pkttotlen(osh, p);
- WL_AMPDU_TX(("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n", wlc->pub->unit, ampdu_len, seg_cnt, ndelim));
+ WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
+ wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
txh->MacTxControlLow = htol16(mcl);
@@ -695,8 +690,8 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
min(scb_ampdu->max_rxlen,
ampdu->max_txlen[mcs][is40][sgi]);
- WL_NONE(("sendampdu: sgi %d, is40 %d, mcs %d\n", sgi,
- is40, mcs));
+ WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n",
+ sgi, is40, mcs);
maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
@@ -739,13 +734,14 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
/* test whether to add more */
if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
(count == f->mcs2ampdu_table[mcs])) {
- WL_AMPDU_ERR(("wl%d: PR 37644: stopping ampdu at %d for mcs %d", wlc->pub->unit, count, mcs));
+ WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
+ wlc->pub->unit, count, mcs);
break;
}
if (count == scb_ampdu->max_pdu) {
- WL_NONE(("Stop taking from q, reached %d deep\n",
- scb_ampdu->max_pdu));
+ WL_NONE("Stop taking from q, reached %d deep\n",
+ scb_ampdu->max_pdu);
break;
}
@@ -755,7 +751,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
if (p) {
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
- ((u8) PKTPRIO(p) == tid)) {
+ ((u8) (p->priority) == tid)) {
plen =
pkttotlen(osh, p) + AMPDU_MAX_MPDU_OVERHEAD;
@@ -763,15 +759,16 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
if ((plen + ampdu_len) > maxlen) {
p = NULL;
- WL_ERROR(("%s: Bogus plen #1\n",
- __func__));
+ WL_ERROR("%s: Bogus plen #1\n",
+ __func__);
ASSERT(3 == 4);
continue;
}
/* check if there are enough descriptors available */
if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
- WL_ERROR(("%s: No fifo space !!!!!!\n", __func__));
+ WL_ERROR("%s: No fifo space !!!!!!\n",
+ __func__);
p = NULL;
continue;
}
@@ -789,7 +786,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
WLCNTADD(ampdu->cnt->txmpdu, count);
/* patch up the last txh */
- txh = (d11txh_t *) PKTDATA(pkt[count - 1]);
+ txh = (d11txh_t *) pkt[count - 1]->data;
mcl = ltoh16(txh->MacTxControlLow);
mcl &= ~TXC_AMPDU_MASK;
mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
@@ -807,7 +804,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
ampdu_len -= roundup(len, 4) - len;
/* patch up the first txh & plcp */
- txh = (d11txh_t *) PKTDATA(pkt[0]);
+ txh = (d11txh_t *) pkt[0]->data;
plcp = (u8 *) (txh + 1);
WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
@@ -878,27 +875,18 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
}
- WL_AMPDU_TX(("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
- wlc->pub->unit, count, ampdu_len));
+ WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
+ wlc->pub->unit, count, ampdu_len);
/* inform rate_sel if it this is a rate probe pkt */
frameid = ltoh16(txh->TxFrameID);
if (frameid & TXFID_RATE_PROBE_MASK) {
- WL_ERROR(("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n", __func__));
+ WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n",
+ __func__);
}
-#ifdef WLC_HIGH_ONLY
- if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU)
- bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc),
- BCM_RPC_TP_HOST_AGG_AMPDU, true);
-#endif
for (i = 0; i < count; i++)
wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
ampdu->txpkt_weight);
-#ifdef WLC_HIGH_ONLY
- if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU)
- bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc),
- BCM_RPC_TP_HOST_AGG_AMPDU, false);
-#endif
}
/* endif (count) */
@@ -906,11 +894,11 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
}
void BCMFASTPATH
-wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
- tx_status_t *txs)
+wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, tx_status_t *txs)
{
scb_ampdu_t *scb_ampdu;
- wlc_info_t *wlc = ampdu->wlc;
+ struct wlc_info *wlc = ampdu->wlc;
scb_ampdu_tid_ini_t *ini;
u32 s1 = 0, s2 = 0;
struct ieee80211_tx_info *tx_info;
@@ -922,7 +910,7 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
ASSERT(txs->status & TX_STATUS_AMPDU);
scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
ASSERT(scb_ampdu);
- ini = SCB_AMPDU_INI(scb_ampdu, PKTPRIO(p));
+ ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
ASSERT(ini->scb == scb);
/* BMAC_NOTE: For the split driver, second level txstatus comes later
@@ -930,7 +918,6 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
* call the first one
*/
if (txs->status & TX_STATUS_ACK_RCV) {
-#ifdef WLC_LOW
u8 status_delay = 0;
/* wait till the next 8 bytes of txstatus is available */
@@ -948,54 +935,14 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
ASSERT(s1 & TX_STATUS_AMPDU);
s2 = R_REG(wlc->osh, &wlc->regs->frmtxstatus2);
-#else /* WLC_LOW */
-
- /* Store the relevant information in ampdu structure */
- WL_AMPDU_TX(("wl%d: wlc_ampdu_dotxstatus: High Recvd\n",
- wlc->pub->unit));
-
- ASSERT(!ampdu->p);
- ampdu->p = p;
- bcopy(txs, &ampdu->txs, sizeof(tx_status_t));
- ampdu->waiting_status = true;
- return;
-#endif /* WLC_LOW */
}
wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
}
-#ifdef WLC_HIGH_ONLY
-void wlc_ampdu_txstatus_complete(ampdu_info_t *ampdu, u32 s1, u32 s2)
-{
- WL_AMPDU_TX(("wl%d: wlc_ampdu_txstatus_complete: High Recvd 0x%x 0x%x p:%p\n", ampdu->wlc->pub->unit, s1, s2, ampdu->p));
-
- ASSERT(ampdu->waiting_status);
-
- /* The packet may have been freed if the SCB went away, if so, then still free the
- * DMA chain
- */
- if (ampdu->p) {
- struct ieee80211_tx_info *tx_info;
- struct scb *scb;
-
- tx_info = IEEE80211_SKB_CB(ampdu->p);
- scb = (struct scb *)tx_info->control.sta->drv_priv;
-
- wlc_ampdu_dotxstatus_complete(ampdu, scb, ampdu->p, &ampdu->txs,
- s1, s2);
- ampdu->p = NULL;
- }
-
- ampdu->waiting_status = false;
-}
-#endif /* WLC_HIGH_ONLY */
-void rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info,
- tx_status_t *txs, u8 mcs);
-
void
-rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info,
+rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
tx_status_t *txs, u8 mcs)
{
struct ieee80211_tx_rate *txrate = tx_info->status.rates;
@@ -1008,17 +955,15 @@ rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info,
}
}
-extern void wlc_txq_enq(wlc_info_t *wlc, struct scb *scb, void *sdu,
- uint prec);
-
#define SHORTNAME "AMPDU status"
static void BCMFASTPATH
-wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
- tx_status_t *txs, u32 s1, u32 s2)
+wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, tx_status_t *txs,
+ u32 s1, u32 s2)
{
scb_ampdu_t *scb_ampdu;
- wlc_info_t *wlc = ampdu->wlc;
+ struct wlc_info *wlc = ampdu->wlc;
scb_ampdu_tid_ini_t *ini;
u8 bitmap[8], queue, tid;
d11txh_t *txh;
@@ -1037,7 +982,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
#ifdef BCMDBG
u8 hole[AMPDU_MAX_MPDU];
- bzero(hole, sizeof(hole));
+ memset(hole, 0, sizeof(hole));
#endif
ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
@@ -1046,7 +991,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
ASSERT(scb_ampdu);
- tid = (u8) PKTPRIO(p);
+ tid = (u8) (p->priority);
ini = SCB_AMPDU_INI(scb_ampdu, tid);
retry_limit = ampdu->retry_limit_tid[tid];
@@ -1054,7 +999,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
ASSERT(ini->scb == scb);
- bzero(bitmap, sizeof(bitmap));
+ memset(bitmap, 0, sizeof(bitmap));
queue = txs->frameid & TXFID_QUEUE_MASK;
ASSERT(queue < AC_COUNT);
@@ -1091,13 +1036,16 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
if (supr_status) {
update_rate = false;
if (supr_status == TX_STATUS_SUPR_BADCH) {
- WL_ERROR(("%s: Pkt tx suppressed, illegal channel possibly %d\n", __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)));
+ WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n",
+ __func__,
+ CHSPEC_CHANNEL(wlc->default_bss->chanspec));
} else {
if (supr_status == TX_STATUS_SUPR_FRAG)
- WL_NONE(("%s: AMPDU frag err\n",
- __func__));
+ WL_NONE("%s: AMPDU frag err\n",
+ __func__);
else
- WL_ERROR(("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n", __func__, supr_status));
+ WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n",
+ __func__, supr_status);
}
/* no need to retry for badch; will fail again */
if (supr_status == TX_STATUS_SUPR_BADCH ||
@@ -1116,22 +1064,18 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
> 0) {
tx_error = true;
-#ifdef WLC_HIGH_ONLY
- /* With BMAC, TX Underflows should not happen */
- WL_ERROR(("wl%d: BMAC TX Underflow?",
- wlc->pub->unit));
-#endif
}
}
} else if (txs->phyerr) {
update_rate = false;
WLCNTINCR(wlc->pub->_cnt->txphyerr);
- WL_ERROR(("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n", wlc->pub->unit, txs->phyerr));
+ WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
+ wlc->pub->unit, txs->phyerr);
#ifdef BCMDBG
if (WL_ERROR_ON()) {
prpkt("txpkt (AMPDU)", wlc->osh, p);
- wlc_print_txdesc((d11txh_t *) PKTDATA(p));
+ wlc_print_txdesc((d11txh_t *) p->data);
wlc_print_txstatus(txs);
}
#endif /* BCMDBG */
@@ -1142,7 +1086,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
while (p) {
tx_info = IEEE80211_SKB_CB(p);
ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
- txh = (d11txh_t *) PKTDATA(p);
+ txh = (d11txh_t *) p->data;
mcl = ltoh16(txh->MacTxControlLow);
plcp = (u8 *) (txh + 1);
h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN);
@@ -1158,10 +1102,9 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
if (ba_recd) {
bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
- WL_AMPDU_TX(("%s: tid %d seq is %d, start_seq is %d, "
- "bindex is %d set %d, index %d\n",
- __func__, tid, seq, start_seq, bindex,
- isset(bitmap, bindex), index));
+ WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
+ __func__, tid, seq, start_seq, bindex,
+ isset(bitmap, bindex), index);
/* if acked then clear bit and free packet */
if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
@@ -1186,8 +1129,8 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
status & TX_STATUS_FRM_RTX_MASK) >>
TX_STATUS_FRM_RTX_SHIFT;
- PKTPULL(p, D11_PHY_HDR_LEN);
- PKTPULL(p, D11_TXH_LEN);
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
@@ -1212,9 +1155,10 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
ieee80211_tx_info_clear_status(tx_info);
tx_info->flags |=
IEEE80211_TX_STAT_AMPDU_NO_BACK;
- PKTPULL(p, D11_PHY_HDR_LEN);
- PKTPULL(p, D11_TXH_LEN);
- WL_ERROR(("%s: BA Timeout, seq %d, in_transit %d\n", SHORTNAME, seq, ini->tx_in_transit));
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
+ WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n",
+ SHORTNAME, seq, ini->tx_in_transit);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
}
@@ -1242,7 +1186,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
}
static void
-ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
+ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
bool force)
{
scb_ampdu_tid_ini_t *ini;
@@ -1250,8 +1194,8 @@ ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
if (!ini)
return;
- WL_AMPDU_CTL(("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
- ampdu->wlc->pub->unit, tid));
+ WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
+ ampdu->wlc->pub->unit, tid);
if (ini->tx_in_transit && !force)
return;
@@ -1264,7 +1208,7 @@ ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
}
/* initialize the initiator code for tid */
-static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
+static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
scb_ampdu_t *scb_ampdu,
u8 tid, bool override)
{
@@ -1277,7 +1221,7 @@ static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
/* check for per-tid control of ampdu */
if (!ampdu->ini_enable[tid]) {
- WL_ERROR(("%s: Rejecting tid %d\n", __func__, tid));
+ WL_ERROR("%s: Rejecting tid %d\n", __func__, tid);
return NULL;
}
@@ -1290,21 +1234,21 @@ static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
return ini;
}
-int wlc_ampdu_set(ampdu_info_t *ampdu, bool on)
+int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
{
- wlc_info_t *wlc = ampdu->wlc;
+ struct wlc_info *wlc = ampdu->wlc;
wlc->pub->_ampdu = false;
if (on) {
if (!N_ENAB(wlc->pub)) {
- WL_AMPDU_ERR(("wl%d: driver not nmode enabled\n",
- wlc->pub->unit));
+ WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
+ wlc->pub->unit);
return BCME_UNSUPPORTED;
}
if (!wlc_ampdu_cap(ampdu)) {
- WL_AMPDU_ERR(("wl%d: device not ampdu capable\n",
- wlc->pub->unit));
+ WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
+ wlc->pub->unit);
return BCME_UNSUPPORTED;
}
wlc->pub->_ampdu = on;
@@ -1313,7 +1257,7 @@ int wlc_ampdu_set(ampdu_info_t *ampdu, bool on)
return 0;
}
-bool wlc_ampdu_cap(ampdu_info_t *ampdu)
+bool wlc_ampdu_cap(struct ampdu_info *ampdu)
{
if (WLC_PHY_11N_CAP(ampdu->wlc->band))
return true;
@@ -1321,7 +1265,7 @@ bool wlc_ampdu_cap(ampdu_info_t *ampdu)
return false;
}
-static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur)
+static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
{
u32 rate, mcs;
@@ -1343,7 +1287,7 @@ static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur)
}
u8 BCMFASTPATH
-wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb,
+wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
ratespec_t rspec, int phylen)
{
scb_ampdu_t *scb_ampdu;
@@ -1379,25 +1323,25 @@ wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb,
return 0;
}
-void wlc_ampdu_macaddr_upd(wlc_info_t *wlc)
+void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
{
char template[T_RAM_ACCESS_SZ * 2];
/* driver needs to write the ta in the template; ta is at offset 16 */
- bzero(template, sizeof(template));
- bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETHER_ADDR_LEN);
+ memset(template, 0, sizeof(template));
+ bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETH_ALEN);
wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
template);
}
-bool wlc_aggregatable(wlc_info_t *wlc, u8 tid)
+bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
{
return wlc->ampdu->ini_enable[tid];
}
-void wlc_ampdu_shm_upd(ampdu_info_t *ampdu)
+void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
{
- wlc_info_t *wlc = ampdu->wlc;
+ struct wlc_info *wlc = ampdu->wlc;
/* Extend ucode internal watchdog timer to match larger received frames */
if ((ampdu->rx_factor & HT_PARAMS_RX_FACTOR_MASK) ==
diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.h b/drivers/staging/brcm80211/sys/wlc_ampdu.h
index c721b16cc706..03457f63f2ab 100644
--- a/drivers/staging/brcm80211/sys/wlc_ampdu.h
+++ b/drivers/staging/brcm80211/sys/wlc_ampdu.h
@@ -17,24 +17,20 @@
#ifndef _wlc_ampdu_h_
#define _wlc_ampdu_h_
-extern ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc);
-extern void wlc_ampdu_detach(ampdu_info_t *ampdu);
-extern bool wlc_ampdu_cap(ampdu_info_t *ampdu);
-extern int wlc_ampdu_set(ampdu_info_t *ampdu, bool on);
-extern int wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **aggp,
- int prec);
-extern void wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
- tx_status_t *txs);
-extern void wlc_ampdu_reset(ampdu_info_t *ampdu);
-extern void wlc_ampdu_macaddr_upd(wlc_info_t *wlc);
-extern void wlc_ampdu_shm_upd(ampdu_info_t *ampdu);
+extern struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc);
+extern void wlc_ampdu_detach(struct ampdu_info *ampdu);
+extern bool wlc_ampdu_cap(struct ampdu_info *ampdu);
+extern int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
+extern int wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi,
+ struct sk_buff **aggp, int prec);
+extern void wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, tx_status_t *txs);
+extern void wlc_ampdu_reset(struct ampdu_info *ampdu);
+extern void wlc_ampdu_macaddr_upd(struct wlc_info *wlc);
+extern void wlc_ampdu_shm_upd(struct ampdu_info *ampdu);
-extern u8 wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb,
+extern u8 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
ratespec_t rspec, int phylen);
-extern void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb);
-#ifdef WLC_HIGH_ONLY
-extern void wlc_ampdu_txstatus_complete(ampdu_info_t *ampdu, u32 s1,
- u32 s2);
-#endif
+extern void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb);
#endif /* _wlc_ampdu_h_ */
diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c
index 5ff8831d2fa8..402ddf8f3371 100644
--- a/drivers/staging/brcm80211/sys/wlc_antsel.c
+++ b/drivers/staging/brcm80211/sys/wlc_antsel.c
@@ -19,18 +19,23 @@
#ifdef WLANTSEL
#include <linux/kernel.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <wlioctl.h>
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <d11.h>
#include <wlc_rate.h>
#include <wlc_key.h>
#include <wlc_pub.h>
#include <wl_dbg.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_bmac.h>
#include <wlc_phy_hal.h>
@@ -58,10 +63,11 @@
#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */
/* static functions */
-static int wlc_antsel_cfgupd(antsel_info_t *asi, wlc_antselcfg_t *antsel);
-static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id);
-static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg);
-static void wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel,
+static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel);
+static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id);
+static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg);
+static void wlc_antsel_init_cfg(struct antsel_info *asi,
+ wlc_antselcfg_t *antsel,
bool auto_sel);
const u16 mimo_2x4_div_antselpat_tbl[] = {
@@ -88,14 +94,15 @@ const u8 mimo_2x3_div_antselid_tbl[16] = {
0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */
};
-antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh,
- wlc_pub_t *pub,
- wlc_hw_info_t *wlc_hw) {
- antsel_info_t *asi;
+struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc,
+ struct osl_info *osh,
+ struct wlc_pub *pub,
+ struct wlc_hw_info *wlc_hw) {
+ struct antsel_info *asi;
- asi = kzalloc(sizeof(antsel_info_t), GFP_ATOMIC);
+ asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
if (!asi) {
- WL_ERROR(("wl%d: wlc_antsel_attach: out of mem\n", pub->unit));
+ WL_ERROR("wl%d: wlc_antsel_attach: out of mem\n", pub->unit);
return NULL;
}
@@ -124,7 +131,7 @@ antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh,
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
- WL_ERROR(("wlc_antsel_attach: 2o3 board cfg invalid\n"));
+ WL_ERROR("wlc_antsel_attach: 2o3 board cfg invalid\n");
ASSERT(0);
}
break;
@@ -152,7 +159,7 @@ antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh,
return asi;
}
-void wlc_antsel_detach(antsel_info_t *asi)
+void wlc_antsel_detach(struct antsel_info *asi)
{
if (!asi)
return;
@@ -160,7 +167,7 @@ void wlc_antsel_detach(antsel_info_t *asi)
kfree(asi);
}
-void wlc_antsel_init(antsel_info_t *asi)
+void wlc_antsel_init(struct antsel_info *asi)
{
if ((asi->antsel_type == ANTSEL_2x3) ||
(asi->antsel_type == ANTSEL_2x4))
@@ -169,7 +176,7 @@ void wlc_antsel_init(antsel_info_t *asi)
/* boardlevel antenna selection: init antenna selection structure */
static void
-wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel,
+wlc_antsel_init_cfg(struct antsel_info *asi, wlc_antselcfg_t *antsel,
bool auto_sel)
{
if (asi->antsel_type == ANTSEL_2x3) {
@@ -200,7 +207,7 @@ wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel,
}
void BCMFASTPATH
-wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel,
+wlc_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel,
u8 antselid, u8 fbantselid, u8 *antcfg,
u8 *fbantcfg)
{
@@ -232,7 +239,7 @@ wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel,
}
/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */
-u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel)
+u8 wlc_antsel_antsel2id(struct antsel_info *asi, u16 antsel)
{
u8 antselid = 0;
@@ -251,7 +258,7 @@ u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel)
}
/* boardlevel antenna selection: convert id to ant_cfg */
-static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id)
+static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id)
{
u8 antcfg = ANT_SELCFG_DEF_2x2;
@@ -270,7 +277,7 @@ static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id)
}
/* boardlevel antenna selection: convert ant_cfg to mimo_antsel (ucode interface) */
-static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg)
+static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg)
{
u8 idx = WLC_ANTIDX_11N(WLC_ANTSEL_11N(ant_cfg));
u16 mimo_antsel = 0;
@@ -290,9 +297,9 @@ static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg)
}
/* boardlevel antenna selection: ucode interface control */
-static int wlc_antsel_cfgupd(antsel_info_t *asi, wlc_antselcfg_t *antsel)
+static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel)
{
- wlc_info_t *wlc = asi->wlc;
+ struct wlc_info *wlc = asi->wlc;
u8 ant_cfg;
u16 mimo_antsel;
diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h
index 1d048bbea946..8875b5848665 100644
--- a/drivers/staging/brcm80211/sys/wlc_antsel.h
+++ b/drivers/staging/brcm80211/sys/wlc_antsel.h
@@ -16,13 +16,15 @@
#ifndef _wlc_antsel_h_
#define _wlc_antsel_h_
-extern antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh,
- wlc_pub_t *pub,
- wlc_hw_info_t *wlc_hw);
-extern void wlc_antsel_detach(antsel_info_t *asi);
-extern void wlc_antsel_init(antsel_info_t *asi);
-extern void wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel,
+extern struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc,
+ struct osl_info *osh,
+ struct wlc_pub *pub,
+ struct wlc_hw_info *wlc_hw);
+extern void wlc_antsel_detach(struct antsel_info *asi);
+extern void wlc_antsel_init(struct antsel_info *asi);
+extern void wlc_antsel_antcfg_get(struct antsel_info *asi, bool usedef,
+ bool sel,
u8 id, u8 fbid, u8 *antcfg,
u8 *fbantcfg);
-extern u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel);
+extern u8 wlc_antsel_antsel2id(struct antsel_info *asi, u16 antsel);
#endif /* _wlc_antsel_h_ */
diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c
index b70f9d099233..69f600affa46 100644
--- a/drivers/staging/brcm80211/sys/wlc_bmac.c
+++ b/drivers/staging/brcm80211/sys/wlc_bmac.c
@@ -14,13 +14,13 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef WLC_LOW
-#error "This file needs WLC_LOW"
-#endif
#include <linux/kernel.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <bcmdefs.h>
#include <osl.h>
#include <proto/802.11.h>
@@ -42,12 +42,14 @@
#include <wlc_channel.h>
#include <bcmsrom.h>
#include <wlc_key.h>
+#include <bcmdevs.h>
/* BMAC_NOTE: a WLC_HIGH compile include of wlc.h adds in more structures and type
* dependencies. Need to include these to files to allow a clean include of wlc.h
* with WLC_HIGH defined.
* At some point we may be able to skip the include of wlc.h and instead just
* define a stub wlc_info and band struct to allow rpc calls to get the rpc handle.
*/
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_bmac.h>
#include <wlc_phy_shim.h>
@@ -55,9 +57,6 @@
#include <wl_export.h>
#include "wl_ucode.h"
#include "d11ucode_ext.h"
-#ifdef BCMSDIO
-#include <bcmsdh.h>
-#endif
#include <bcmotp.h>
/* BMAC_NOTE: With WLC_HIGH defined, some fns in this file make calls to high level
@@ -69,6 +68,7 @@
#include <pcie_core.h>
#include <wlc_alloc.h>
+#include <wl_dbg.h>
#define TIMER_INTERVAL_WATCHDOG_BMAC 1000 /* watchdog timer, in unit of ms */
@@ -113,64 +113,65 @@ static u16 xmtfifo_sz[][NFIFO] = {
{9, 58, 22, 14, 14, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
};
-static void wlc_clkctl_clk(wlc_hw_info_t *wlc, uint mode);
-static void wlc_coreinit(wlc_info_t *wlc);
+static void wlc_clkctl_clk(struct wlc_hw_info *wlc, uint mode);
+static void wlc_coreinit(struct wlc_info *wlc);
/* used by wlc_wakeucode_init() */
-static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits);
-static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[],
+static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits);
+static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[],
const uint nbytes);
-static void wlc_ucode_download(wlc_hw_info_t *wlc);
-static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw);
+static void wlc_ucode_download(struct wlc_hw_info *wlc);
+static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw);
/* used by wlc_dpc() */
-static bool wlc_bmac_dotxstatus(wlc_hw_info_t *wlc, tx_status_t *txs,
+static bool wlc_bmac_dotxstatus(struct wlc_hw_info *wlc, tx_status_t *txs,
u32 s2);
-static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc);
-static bool wlc_bmac_txstatus(wlc_hw_info_t *wlc, bool bound, bool *fatal);
-static bool wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound);
+static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc);
+static bool wlc_bmac_txstatus(struct wlc_hw_info *wlc, bool bound, bool *fatal);
+static bool wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound);
/* used by wlc_down() */
-static void wlc_flushqueues(wlc_info_t *wlc);
+static void wlc_flushqueues(struct wlc_info *wlc);
-static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs);
-static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw);
-static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw);
+static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs);
+static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw);
+static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw);
/* Low Level Prototypes */
-static u16 wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset,
+static u16 wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset,
u32 sel);
-static void wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v,
- u32 sel);
-static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme);
-static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw);
-static void wlc_ucode_bsinit(wlc_hw_info_t *wlc_hw);
-static bool wlc_validboardtype(wlc_hw_info_t *wlc);
-static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw);
-static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw);
-static void wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init);
-static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw);
-static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw);
-static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw);
-static u32 wlc_wlintrsoff(wlc_info_t *wlc);
-static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask);
-static void wlc_gpio_init(wlc_info_t *wlc);
-static void wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn,
+static void wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset,
+ u16 v, u32 sel);
+static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme);
+static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw);
+static void wlc_ucode_bsinit(struct wlc_hw_info *wlc_hw);
+static bool wlc_validboardtype(struct wlc_hw_info *wlc);
+static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw);
+static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw);
+static void wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init);
+static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw);
+static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw);
+static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw);
+static u32 wlc_wlintrsoff(struct wlc_info *wlc);
+static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask);
+static void wlc_gpio_init(struct wlc_info *wlc);
+static void wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn,
int len);
-static void wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn,
+static void wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn,
int len);
-static void wlc_bmac_bsinit(wlc_info_t *wlc, chanspec_t chanspec);
-static u32 wlc_setband_inact(wlc_info_t *wlc, uint bandunit);
-static void wlc_bmac_setband(wlc_hw_info_t *wlc_hw, uint bandunit,
+static void wlc_bmac_bsinit(struct wlc_info *wlc, chanspec_t chanspec);
+static u32 wlc_setband_inact(struct wlc_info *wlc, uint bandunit);
+static void wlc_bmac_setband(struct wlc_hw_info *wlc_hw, uint bandunit,
chanspec_t chanspec);
-static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot);
-static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw);
-static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw,
+static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw,
+ bool shortslot);
+static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw);
+static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw,
u8 rate);
/* === Low Level functions === */
-void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot)
+void wlc_bmac_set_shortslot(struct wlc_hw_info *wlc_hw, bool shortslot)
{
wlc_hw->shortslot = shortslot;
@@ -186,9 +187,10 @@ void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot)
* or shortslot 11g (9us slots)
* The PSM needs to be suspended for this call.
*/
-static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot)
+static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw,
+ bool shortslot)
{
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs;
osh = wlc_hw->osh;
@@ -205,7 +207,7 @@ static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot)
}
}
-static void WLBANDINITFN(wlc_ucode_bsinit) (wlc_hw_info_t *wlc_hw)
+static void WLBANDINITFN(wlc_ucode_bsinit) (struct wlc_hw_info *wlc_hw)
{
/* init microcode host flags */
wlc_write_mhf(wlc_hw, wlc_hw->band->mhfs);
@@ -215,30 +217,32 @@ static void WLBANDINITFN(wlc_ucode_bsinit) (wlc_hw_info_t *wlc_hw)
if (WLCISNPHY(wlc_hw->band)) {
wlc_write_inits(wlc_hw, d11n0bsinitvals16);
} else {
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
}
} else {
if (D11REV_IS(wlc_hw->corerev, 24)) {
if (WLCISLCNPHY(wlc_hw->band)) {
wlc_write_inits(wlc_hw, d11lcn0bsinitvals24);
} else
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit,
+ wlc_hw->corerev);
} else {
- WL_ERROR(("%s: wl%d: unsupported corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
}
}
}
/* switch to new band but leave it inactive */
-static u32 WLBANDINITFN(wlc_setband_inact) (wlc_info_t *wlc, uint bandunit)
+static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
u32 macintmask;
u32 tmp;
- WL_TRACE(("wl%d: wlc_setband_inact\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_setband_inact\n", wlc_hw->unit);
ASSERT(bandunit != wlc_hw->band->bandunit);
ASSERT(si_iscoreup(wlc_hw->sih));
@@ -269,24 +273,24 @@ static u32 WLBANDINITFN(wlc_setband_inact) (wlc_info_t *wlc, uint bandunit)
* Param 'bound' indicates max. # frames to process before break out.
*/
static bool BCMFASTPATH
-wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound)
+wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound)
{
- void *p;
- void *head = NULL;
- void *tail = NULL;
+ struct sk_buff *p;
+ struct sk_buff *head = NULL;
+ struct sk_buff *tail = NULL;
uint n = 0;
uint bound_limit = bound ? wlc_hw->wlc->pub->tunables->rxbnd : -1;
u32 tsf_h, tsf_l;
wlc_d11rxhdr_t *wlc_rxhdr = NULL;
- WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
/* gather received frames */
while ((p = dma_rx(wlc_hw->di[fifo]))) {
if (!tail)
head = tail = p;
else {
- PKTSETLINK(tail, p);
+ tail->prev = p;
tail = p;
}
@@ -303,11 +307,11 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound)
/* process each frame */
while ((p = head) != NULL) {
- head = PKTLINK(head);
- PKTSETLINK(p, NULL);
+ head = head->prev;
+ p->prev = NULL;
/* record the tsf_l in wlc_rxd11hdr */
- wlc_rxhdr = (wlc_d11rxhdr_t *) PKTDATA(p);
+ wlc_rxhdr = (wlc_d11rxhdr_t *) p->data;
wlc_rxhdr->tsf_l = htol32(tsf_l);
/* compute the RSSI from d11rxhdr and record it in wlc_rxd11hr */
@@ -323,15 +327,15 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound)
* Return true if another dpc needs to be re-scheduled. false otherwise.
* Param 'bounded' indicates if applicable loops should be bounded.
*/
-bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
+bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)
{
u32 macintstatus;
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs = wlc_hw->regs;
bool fatal = false;
if (DEVICEREMOVED(wlc)) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
wl_down(wlc->wl);
return false;
}
@@ -340,8 +344,8 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
macintstatus = wlc->macintstatus;
wlc->macintstatus = 0;
- WL_TRACE(("wl%d: wlc_dpc: macintstatus 0x%x\n", wlc_hw->unit,
- macintstatus));
+ WL_TRACE("wl%d: wlc_dpc: macintstatus 0x%x\n",
+ wlc_hw->unit, macintstatus);
if (macintstatus & MI_PRQ) {
/* Process probe request FIFO */
@@ -364,7 +368,7 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
if (wlc_bmac_txstatus(wlc->hw, bounded, &fatal))
wlc->macintstatus |= MI_TFS;
if (fatal) {
- WL_ERROR(("MI_TFS: fatal\n"));
+ WL_ERROR("MI_TFS: fatal\n");
goto fatal;
}
}
@@ -374,7 +378,7 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
/* ATIM window end */
if (macintstatus & MI_ATIMWINEND) {
- WL_TRACE(("wlc_isr: end of ATIM window\n"));
+ WL_TRACE("wlc_isr: end of ATIM window\n");
OR_REG(wlc_hw->osh, &regs->maccommand, wlc->qvalid);
wlc->qvalid = 0;
@@ -395,7 +399,7 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
/* TX FIFO suspend/flush completion */
if (macintstatus & MI_TXSTOP) {
if (wlc_bmac_tx_fifo_suspended(wlc_hw, TX_DATA_FIFO)) {
- /* WL_ERROR(("dpc: fifo_suspend_comlete\n")); */
+ /* WL_ERROR("dpc: fifo_suspend_comlete\n"); */
}
}
@@ -405,11 +409,12 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
}
if (macintstatus & MI_GP0) {
- WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now));
+ WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n",
+ wlc_hw->unit, wlc_hw->now);
printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
- __func__, CHIPID(wlc_hw->sih->chip),
- CHIPREV(wlc_hw->sih->chiprev));
+ __func__, wlc_hw->sih->chip,
+ wlc_hw->sih->chiprev);
WLCNTINCR(wlc->pub->_cnt->psmwds);
@@ -427,7 +432,8 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
u32 rfd = R_REG(wlc_hw->osh, &regs->phydebug) & PDBG_RFD;
#endif
- WL_ERROR(("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", wlc_hw->unit, rfd));
+ WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n",
+ wlc_hw->unit, rfd);
WLCNTINCR(wlc->pub->_cnt->rfdisable);
}
@@ -452,10 +458,10 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded)
/* common low-level watchdog code */
void wlc_bmac_watchdog(void *arg)
{
- wlc_info_t *wlc = (wlc_info_t *) arg;
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_info *wlc = (struct wlc_info *) arg;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
- WL_TRACE(("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit);
if (!wlc_hw->up)
return;
@@ -476,13 +482,13 @@ void wlc_bmac_watchdog(void *arg)
}
void
-wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, bool mute,
- struct txpwr_limits *txpwr)
+wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw, chanspec_t chanspec,
+ bool mute, struct txpwr_limits *txpwr)
{
uint bandunit;
- WL_TRACE(("wl%d: wlc_bmac_set_chanspec 0x%x\n", wlc_hw->unit,
- chanspec));
+ WL_TRACE("wl%d: wlc_bmac_set_chanspec 0x%x\n",
+ wlc_hw->unit, chanspec);
wlc_hw->chanspec = chanspec;
@@ -520,7 +526,8 @@ wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, bool mute,
}
}
-int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw, wlc_bmac_revinfo_t *revinfo)
+int wlc_bmac_revinfo_get(struct wlc_hw_info *wlc_hw,
+ wlc_bmac_revinfo_t *revinfo)
{
si_t *sih = wlc_hw->sih;
uint idx;
@@ -558,20 +565,20 @@ int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw, wlc_bmac_revinfo_t *revinfo)
return 0;
}
-int wlc_bmac_state_get(wlc_hw_info_t *wlc_hw, wlc_bmac_state_t *state)
+int wlc_bmac_state_get(struct wlc_hw_info *wlc_hw, wlc_bmac_state_t *state)
{
state->machwcap = wlc_hw->machwcap;
return 0;
}
-static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme)
+static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme)
{
uint i;
char name[8];
/* ucode host flag 2 needed for pio mode, independent of band and fifo */
u16 pio_mhf2 = 0;
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
uint unit = wlc_hw->unit;
wlc_tunables_t *tune = wlc->pub->tunables;
@@ -581,7 +588,7 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme)
if (wlc_hw->di[0] == 0) { /* Init FIFOs */
uint addrwidth;
int dma_attach_err = 0;
- osl_t *osh = wlc_hw->osh;
+ struct osl_info *osh = wlc_hw->osh;
/* Find out the DMA addressing capability and let OS know
* All the channels within one DMA core have 'common-minimum' same
@@ -589,10 +596,10 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme)
*/
addrwidth =
dma_addrwidth(wlc_hw->sih, DMAREG(wlc_hw, DMA_TX, 0));
- OSL_DMADDRWIDTH(osh, addrwidth);
if (!wl_alloc_dma_resources(wlc_hw->wlc->wl, addrwidth)) {
- WL_ERROR(("wl%d: wlc_attach: alloc_dma_resources failed\n", unit));
+ WL_ERROR("wl%d: wlc_attach: alloc_dma_resources failed\n",
+ unit);
return false;
}
@@ -665,8 +672,7 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme)
/* Cleaner to leave this as if with AP defined */
if (dma_attach_err) {
- WL_ERROR(("wl%d: wlc_attach: dma_attach failed\n",
- unit));
+ WL_ERROR("wl%d: wlc_attach: dma_attach failed\n", unit);
return false;
}
@@ -684,7 +690,7 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme)
return true;
}
-static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw)
+static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw)
{
uint j;
@@ -702,11 +708,11 @@ static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw)
* initialize software state for each core and band
* put the whole chip in reset(driver down state), no clock
*/
-int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
- bool piomode, osl_t *osh, void *regsva, uint bustype,
- void *btparam)
+int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit,
+ bool piomode, struct osl_info *osh, void *regsva,
+ uint bustype, void *btparam)
{
- wlc_hw_info_t *wlc_hw;
+ struct wlc_hw_info *wlc_hw;
d11regs_t *regs;
char *macaddr = NULL;
char *vars;
@@ -715,8 +721,8 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
bool wme = false;
shared_phy_params_t sha_params;
- WL_TRACE(("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n", unit,
- vendor, device));
+ WL_TRACE("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n",
+ unit, vendor, device);
ASSERT(sizeof(wlc_d11rxhdr_t) <= WL_HWRXOFF);
@@ -729,7 +735,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_hw->band = wlc_hw->bandstate[0];
wlc_hw->_piomode = piomode;
- /* populate wlc_hw_info_t with default values */
+ /* populate struct wlc_hw_info with default values */
wlc_bmac_info_init(wlc_hw);
/*
@@ -740,7 +746,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_hw->sih = si_attach((uint) device, osh, regsva, bustype, btparam,
&wlc_hw->vars, &wlc_hw->vars_size);
if (wlc_hw->sih == NULL) {
- WL_ERROR(("wl%d: wlc_bmac_attach: si_attach failed\n", unit));
+ WL_ERROR("wl%d: wlc_bmac_attach: si_attach failed\n", unit);
err = 11;
goto fail;
}
@@ -760,21 +766,22 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
var = getvar(vars, "vendid");
if (var) {
vendor = (u16) simple_strtoul(var, NULL, 0);
- WL_ERROR(("Overriding vendor id = 0x%x\n", vendor));
+ WL_ERROR("Overriding vendor id = 0x%x\n", vendor);
}
var = getvar(vars, "devid");
if (var) {
u16 devid = (u16) simple_strtoul(var, NULL, 0);
if (devid != 0xffff) {
device = devid;
- WL_ERROR(("Overriding device id = 0x%x\n",
- device));
+ WL_ERROR("Overriding device id = 0x%x\n",
+ device);
}
}
/* verify again the device is supported */
if (!wlc_chipmatch(vendor, device)) {
- WL_ERROR(("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n", unit, vendor, device));
+ WL_ERROR("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n",
+ unit, vendor, device);
err = 12;
goto fail;
}
@@ -809,7 +816,8 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS);
if (!wlc_bmac_validate_chip_access(wlc_hw)) {
- WL_ERROR(("wl%d: wlc_bmac_attach: validate_chip_access failed\n", unit));
+ WL_ERROR("wl%d: wlc_bmac_attach: validate_chip_access failed\n",
+ unit);
err = 14;
goto fail;
}
@@ -821,7 +829,8 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
j = BOARDREV_PROMOTED;
wlc_hw->boardrev = (u16) j;
if (!wlc_validboardtype(wlc_hw)) {
- WL_ERROR(("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n", unit, wlc_hw->sih->boardtype, wlc_hw->boardrev));
+ WL_ERROR("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n",
+ unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
err = 15;
goto fail;
}
@@ -833,7 +842,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
|| (wlc_hw->boardflags & BFL_NOPLLDOWN))
wlc_bmac_pllreq(wlc_hw, true, WLC_PLLREQ_SHARED);
- if ((BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if ((wlc_hw->sih->bustype == PCI_BUS)
&& (si_pci_war16165(wlc_hw->sih)))
wlc->war16165 = true;
@@ -844,7 +853,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
} else
wlc_hw->_nbands = 1;
- if ((CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID))
+ if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
wlc_hw->_nbands = 1;
/* BMAC_NOTE: remove init of pub values when wlc_attach() unconditionally does the
@@ -863,8 +872,8 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
if (wlc_hw->physhim == NULL) {
- WL_ERROR(("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n",
- unit));
+ WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n",
+ unit);
err = 25;
goto fail;
}
@@ -931,7 +940,8 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh,
(void *)regs, wlc_hw->band->bandtype, vars);
if (wlc_hw->band->pi == NULL) {
- WL_ERROR(("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n", unit));
+ WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n",
+ unit);
err = 17;
goto fail;
}
@@ -961,7 +971,9 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
goto bad_phy;
} else {
bad_phy:
- WL_ERROR(("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n", unit, wlc_hw->band->phytype, wlc_hw->band->phyrev));
+ WL_ERROR("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n",
+ unit,
+ wlc_hw->band->phytype, wlc_hw->band->phyrev);
err = 18;
goto fail;
}
@@ -993,7 +1005,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
wlc_coredisable(wlc_hw);
/* Match driver "down" state */
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_down(wlc_hw->sih);
/* register sb interrupt callback functions */
@@ -1016,27 +1028,27 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
/* init etheraddr state variables */
macaddr = wlc_get_macaddr(wlc_hw);
if (macaddr == NULL) {
- WL_ERROR(("wl%d: wlc_bmac_attach: macaddr not found\n", unit));
+ WL_ERROR("wl%d: wlc_bmac_attach: macaddr not found\n", unit);
err = 21;
goto fail;
}
bcm_ether_atoe(macaddr, &wlc_hw->etheraddr);
- if (ETHER_ISBCAST((char *)&wlc_hw->etheraddr) ||
- ETHER_ISNULLADDR((char *)&wlc_hw->etheraddr)) {
- WL_ERROR(("wl%d: wlc_bmac_attach: bad macaddr %s\n", unit,
- macaddr));
+ if (is_broadcast_ether_addr(wlc_hw->etheraddr.octet) ||
+ is_zero_ether_addr(wlc_hw->etheraddr.octet)) {
+ WL_ERROR("wl%d: wlc_bmac_attach: bad macaddr %s\n",
+ unit, macaddr);
err = 22;
goto fail;
}
- WL_ERROR(("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
- __func__, wlc_hw->deviceid, wlc_hw->_nbands,
- wlc_hw->sih->boardtype, macaddr));
+ WL_ERROR("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
+ __func__, wlc_hw->deviceid, wlc_hw->_nbands,
+ wlc_hw->sih->boardtype, macaddr);
return err;
fail:
- WL_ERROR(("wl%d: wlc_bmac_attach: failed with err %d\n", unit, err));
+ WL_ERROR("wl%d: wlc_bmac_attach: failed with err %d\n", unit, err);
return err;
}
@@ -1045,9 +1057,9 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
* may get overrides later in this function
* BMAC_NOTES, move low out and resolve the dangling ones
*/
-void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_info_init(struct wlc_hw_info *wlc_hw)
{
- wlc_info_t *wlc = wlc_hw->wlc;
+ struct wlc_info *wlc = wlc_hw->wlc;
/* set default sw macintmask value */
wlc->defmacintmask = DEF_MACINTMASK;
@@ -1067,11 +1079,11 @@ void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw)
/*
* low level detach
*/
-int wlc_bmac_detach(wlc_info_t *wlc)
+int wlc_bmac_detach(struct wlc_info *wlc)
{
uint i;
wlc_hwband_t *band;
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
int callbacks;
callbacks = 0;
@@ -1082,7 +1094,7 @@ int wlc_bmac_detach(wlc_info_t *wlc)
*/
si_deregister_intr_callback(wlc_hw->sih);
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_sleep(wlc_hw->sih);
}
@@ -1118,9 +1130,9 @@ int wlc_bmac_detach(wlc_info_t *wlc)
}
-void wlc_bmac_reset(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_reset(struct wlc_hw_info *wlc_hw)
{
- WL_TRACE(("wl%d: wlc_bmac_reset\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw->unit);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->reset);
@@ -1135,13 +1147,13 @@ void wlc_bmac_reset(wlc_hw_info_t *wlc_hw)
}
void
-wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec,
+wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec,
bool mute) {
u32 macintmask;
bool fastclk;
- wlc_info_t *wlc = wlc_hw->wlc;
+ struct wlc_info *wlc = wlc_hw->wlc;
- WL_TRACE(("wl%d: wlc_bmac_init\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_init\n", wlc_hw->unit);
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
@@ -1186,11 +1198,11 @@ wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec,
wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC);
}
-int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw)
+int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw)
{
uint coremask;
- WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
ASSERT(wlc_hw->wlc->pub->hw_up && wlc_hw->wlc->macintmask == 0);
@@ -1208,7 +1220,7 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw)
*/
coremask = (1 << wlc_hw->wlc->core->coreidx);
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_setup(wlc_hw->sih, coremask);
ASSERT(si_coreid(wlc_hw->sih) == D11_CORE_ID);
@@ -1219,13 +1231,13 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw)
*/
if (wlc_bmac_radio_read_hwdisabled(wlc_hw)) {
/* put SB PCI in down state again */
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_down(wlc_hw->sih);
wlc_bmac_xtal(wlc_hw, OFF);
return BCME_RADIOOFF;
}
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_up(wlc_hw->sih);
/* reset the d11 core */
@@ -1234,9 +1246,9 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw)
return 0;
}
-int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw)
+int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw)
{
- WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
wlc_hw->up = true;
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
@@ -1248,12 +1260,12 @@ int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw)
return 0;
}
-int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw)
+int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw)
{
bool dev_gone;
uint callbacks = 0;
- WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
if (!wlc_hw->up)
return callbacks;
@@ -1276,12 +1288,12 @@ int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw)
return callbacks;
}
-int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw)
+int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw)
{
uint callbacks = 0;
bool dev_gone;
- WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
if (!wlc_hw->up)
return callbacks;
@@ -1311,7 +1323,7 @@ int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw)
/* turn off primary xtal and pll */
if (!wlc_hw->noreset) {
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS)
+ if (wlc_hw->sih->bustype == PCI_BUS)
si_pci_down(wlc_hw->sih);
wlc_bmac_xtal(wlc_hw, OFF);
}
@@ -1320,7 +1332,7 @@ int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw)
return callbacks;
}
-void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw)
{
if (D11REV_IS(wlc_hw->corerev, 4)) /* no slowclock */
udelay(5);
@@ -1336,29 +1348,30 @@ void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw)
ASSERT(wlc_bmac_read_shm(wlc_hw, M_UCODE_DBGST) != DBGST_ASLEEP);
}
-void wlc_bmac_hw_etheraddr(wlc_hw_info_t *wlc_hw, struct ether_addr *ea)
+void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea)
{
- bcopy(&wlc_hw->etheraddr, ea, ETHER_ADDR_LEN);
+ bcopy(&wlc_hw->etheraddr, ea, ETH_ALEN);
}
-void wlc_bmac_set_hw_etheraddr(wlc_hw_info_t *wlc_hw, struct ether_addr *ea)
+void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw,
+ struct ether_addr *ea)
{
- bcopy(ea, &wlc_hw->etheraddr, ETHER_ADDR_LEN);
+ bcopy(ea, &wlc_hw->etheraddr, ETH_ALEN);
}
-int wlc_bmac_bandtype(wlc_hw_info_t *wlc_hw)
+int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw)
{
return wlc_hw->band->bandtype;
}
-void *wlc_cur_phy(wlc_info_t *wlc)
+void *wlc_cur_phy(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
return (void *)wlc_hw->band->pi;
}
/* control chip clock to save power, enable dynamic clock or force fast clock */
-static void wlc_clkctl_clk(wlc_hw_info_t *wlc_hw, uint mode)
+static void wlc_clkctl_clk(struct wlc_hw_info *wlc_hw, uint mode)
{
if (PMUCTL_ENAB(wlc_hw->sih)) {
/* new chips with PMU, CCS_FORCEHT will distribute the HT clock on backplane,
@@ -1455,11 +1468,11 @@ static void wlc_clkctl_clk(wlc_hw_info_t *wlc_hw, uint mode)
/* set initial host flags value */
static void
-wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init)
+wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
- bzero(mhfs, sizeof(u16) * MHFMAX);
+ memset(mhfs, 0, MHFMAX * sizeof(u16));
mhfs[MHF2] |= mhf2_init;
@@ -1485,7 +1498,7 @@ wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init)
* WLC_BAND_ALL <--- All bands
*/
void
-wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask, u16 val,
+wlc_bmac_mhf(struct wlc_hw_info *wlc_hw, u8 idx, u16 mask, u16 val,
int bands)
{
u16 save;
@@ -1539,7 +1552,7 @@ wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask, u16 val,
}
}
-u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands)
+u16 wlc_bmac_mhf_get(struct wlc_hw_info *wlc_hw, u8 idx, int bands)
{
wlc_hwband_t *band;
ASSERT(idx < MHFMAX);
@@ -1565,7 +1578,7 @@ u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands)
return band->mhfs[idx];
}
-static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs)
+static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs)
{
u8 idx;
u16 addr[] = {
@@ -1583,7 +1596,7 @@ static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs)
/* set the maccontrol register to desired reset state and
* initialize the sw cache of the register
*/
-static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw)
+static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw)
{
/* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
wlc_hw->maccontrol = 0;
@@ -1594,7 +1607,7 @@ static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw)
}
/* set or clear maccontrol bits */
-void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val)
+void wlc_bmac_mctrl(struct wlc_hw_info *wlc_hw, u32 mask, u32 val)
{
u32 maccontrol;
u32 new_maccontrol;
@@ -1616,7 +1629,7 @@ void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val)
}
/* write the software state of maccontrol and overrides to the maccontrol register */
-static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw)
+static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw)
{
u32 maccontrol = wlc_hw->maccontrol;
@@ -1633,7 +1646,7 @@ static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw)
W_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol, maccontrol);
}
-void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw, u32 override_bit)
+void wlc_ucode_wake_override_set(struct wlc_hw_info *wlc_hw, u32 override_bit)
{
ASSERT((wlc_hw->wake_override & override_bit) == 0);
@@ -1650,7 +1663,7 @@ void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw, u32 override_bit)
return;
}
-void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw, u32 override_bit)
+void wlc_ucode_wake_override_clear(struct wlc_hw_info *wlc_hw, u32 override_bit)
{
ASSERT(wlc_hw->wake_override & override_bit);
@@ -1671,7 +1684,7 @@ void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw, u32 override_bit)
* STA 0 1 <--- This will ensure no beacons
* IBSS 0 0
*/
-static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw)
+static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw)
{
wlc_hw->mute_override = 1;
@@ -1687,7 +1700,7 @@ static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw)
}
/* Clear the override on AP and INFRA bits */
-static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw)
+static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw)
{
if (wlc_hw->mute_override == 0)
return;
@@ -1707,16 +1720,16 @@ static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw)
* Write a MAC address to the rcmta structure
*/
void
-wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx,
+wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx,
const struct ether_addr *addr)
{
d11regs_t *regs = wlc_hw->regs;
volatile u16 *objdata16 = (volatile u16 *)&regs->objdata;
u32 mac_hm;
u16 mac_l;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
ASSERT(wlc_hw->corerev > 4);
@@ -1740,16 +1753,16 @@ wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx,
* Write a MAC address to the given match reg offset in the RXE match engine.
*/
void
-wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset,
+wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw, int match_reg_offset,
const struct ether_addr *addr)
{
d11regs_t *regs;
u16 mac_l;
u16 mac_m;
u16 mac_h;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit);
ASSERT((match_reg_offset < RCM_SIZE) || (wlc_hw->corerev == 4));
@@ -1769,7 +1782,7 @@ wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset,
}
void
-wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len,
+wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset, int len,
void *buf)
{
d11regs_t *regs;
@@ -1778,9 +1791,9 @@ wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len,
#ifdef IL_BIGENDIAN
volatile u16 *dptr = NULL;
#endif /* IL_BIGENDIAN */
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit);
regs = wlc_hw->regs;
osh = wlc_hw->osh;
@@ -1812,9 +1825,9 @@ wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len,
}
}
-void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin)
+void wlc_bmac_set_cwmin(struct wlc_hw_info *wlc_hw, u16 newmin)
{
- osl_t *osh;
+ struct osl_info *osh;
osh = wlc_hw->osh;
wlc_hw->band->CWmin = newmin;
@@ -1824,9 +1837,9 @@ void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin)
W_REG(osh, &wlc_hw->regs->objdata, newmin);
}
-void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax)
+void wlc_bmac_set_cwmax(struct wlc_hw_info *wlc_hw, u16 newmax)
{
- osl_t *osh;
+ struct osl_info *osh;
osh = wlc_hw->osh;
wlc_hw->band->CWmax = newmax;
@@ -1836,7 +1849,7 @@ void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax)
W_REG(osh, &wlc_hw->regs->objdata, newmax);
}
-void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw)
+void wlc_bmac_bw_set(struct wlc_hw_info *wlc_hw, u16 bw)
{
bool fastclk;
u32 tmp;
@@ -1861,7 +1874,7 @@ void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw)
}
static void
-wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, int len)
+wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn, int len)
{
d11regs_t *regs = wlc_hw->regs;
@@ -1875,7 +1888,7 @@ wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, int len)
}
static void
-wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, int len)
+wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn, int len)
{
d11regs_t *regs = wlc_hw->regs;
@@ -1890,7 +1903,7 @@ wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, int len)
/* mac is assumed to be suspended at this point */
void
-wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, int len,
+wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info *wlc_hw, void *bcn, int len,
bool both)
{
d11regs_t *regs = wlc_hw->regs;
@@ -1911,10 +1924,10 @@ wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, int len,
}
}
-static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw)
+static void WLBANDINITFN(wlc_bmac_upd_synthpu) (struct wlc_hw_info *wlc_hw)
{
u16 v;
- wlc_info_t *wlc = wlc_hw->wlc;
+ struct wlc_info *wlc = wlc_hw->wlc;
/* update SYNTHPU_DLY */
if (WLCISLCNPHY(wlc->band)) {
@@ -1930,12 +1943,12 @@ static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw)
/* band-specific init */
static void
-WLBANDINITFN(wlc_bmac_bsinit) (wlc_info_t *wlc, chanspec_t chanspec)
+WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
- WL_TRACE(("wl%d: wlc_bmac_bsinit: bandunit %d\n", wlc_hw->unit,
- wlc_hw->band->bandunit));
+ WL_TRACE("wl%d: wlc_bmac_bsinit: bandunit %d\n",
+ wlc_hw->unit, wlc_hw->band->bandunit);
/* sanity check */
if (PHY_TYPE(R_REG(wlc_hw->osh, &wlc_hw->regs->phyversion)) !=
@@ -1969,9 +1982,9 @@ WLBANDINITFN(wlc_bmac_bsinit) (wlc_info_t *wlc, chanspec_t chanspec)
wlc_bmac_upd_synthpu(wlc_hw);
}
-void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk)
+void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk)
{
- WL_TRACE(("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk));
+ WL_TRACE("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk);
wlc_hw->phyclk = clk;
@@ -1994,9 +2007,9 @@ void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk)
}
/* Perform a soft reset of the PHY PLL */
-void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw)
{
- WL_TRACE(("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit);
si_corereg(wlc_hw->sih, SI_CC_IDX,
offsetof(chipcregs_t, chipcontrol_addr), ~0, 0);
@@ -2015,7 +2028,7 @@ void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw)
/* light way to turn on phy clock without reset for NPHY only
* refer to wlc_bmac_core_phy_clk for full version
*/
-void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk)
+void wlc_bmac_phyclk_fgc(struct wlc_hw_info *wlc_hw, bool clk)
{
/* support(necessary for NPHY and HYPHY) only */
if (!WLCISNPHY(wlc_hw->band))
@@ -2028,7 +2041,7 @@ void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk)
}
-void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk)
+void wlc_bmac_macphyclk_set(struct wlc_hw_info *wlc_hw, bool clk)
{
if (ON == clk)
si_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE);
@@ -2036,13 +2049,13 @@ void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk)
si_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0);
}
-void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw)
{
wlc_phy_t *pih = wlc_hw->band->pi;
u32 phy_bw_clkbits;
bool phy_in_reset = false;
- WL_TRACE(("wl%d: wlc_bmac_phy_reset\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_phy_reset\n", wlc_hw->unit);
if (pih == NULL)
return;
@@ -2080,9 +2093,9 @@ void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw)
/* switch to and initialize new band */
static void
-WLBANDINITFN(wlc_bmac_setband) (wlc_hw_info_t *wlc_hw, uint bandunit,
+WLBANDINITFN(wlc_bmac_setband) (struct wlc_hw_info *wlc_hw, uint bandunit,
chanspec_t chanspec) {
- wlc_info_t *wlc = wlc_hw->wlc;
+ struct wlc_info *wlc = wlc_hw->wlc;
u32 macintmask;
ASSERT(NBANDS_HW(wlc_hw) > 1);
@@ -2122,9 +2135,9 @@ WLBANDINITFN(wlc_bmac_setband) (wlc_hw_info_t *wlc_hw, uint bandunit,
}
/* low-level band switch utility routine */
-void WLBANDINITFN(wlc_setxband) (wlc_hw_info_t *wlc_hw, uint bandunit)
+void WLBANDINITFN(wlc_setxband) (struct wlc_hw_info *wlc_hw, uint bandunit)
{
- WL_TRACE(("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit));
+ WL_TRACE("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit);
wlc_hw->band = wlc_hw->bandstate[bandunit];
@@ -2138,19 +2151,19 @@ void WLBANDINITFN(wlc_setxband) (wlc_hw_info_t *wlc_hw, uint bandunit)
}
}
-static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw)
+static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw)
{
/* reject unsupported corerev */
if (!VALID_COREREV(wlc_hw->corerev)) {
- WL_ERROR(("unsupported core rev %d\n", wlc_hw->corerev));
+ WL_ERROR("unsupported core rev %d\n", wlc_hw->corerev);
return false;
}
return true;
}
-static bool wlc_validboardtype(wlc_hw_info_t *wlc_hw)
+static bool wlc_validboardtype(struct wlc_hw_info *wlc_hw)
{
bool goodboard = true;
uint boardrev = wlc_hw->boardrev;
@@ -2174,7 +2187,7 @@ static bool wlc_validboardtype(wlc_hw_info_t *wlc_hw)
return goodboard;
}
-static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw)
+static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw)
{
const char *varname = "macaddr";
char *macaddr;
@@ -2191,7 +2204,8 @@ static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw)
macaddr = getvar(wlc_hw->vars, varname);
if (macaddr == NULL) {
- WL_ERROR(("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n", wlc_hw->unit, varname));
+ WL_ERROR("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n",
+ wlc_hw->unit, varname);
}
return macaddr;
@@ -2203,7 +2217,7 @@ static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw)
* this function could be called when driver is down and w/o clock
* it operates on different registers depending on corerev and boardflag.
*/
-bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw)
+bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info *wlc_hw)
{
bool v, clk, xtal;
u32 resetbits = 0, flags = 0;
@@ -2226,9 +2240,9 @@ bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw)
flags |= SICF_PCLKE;
/* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
- if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID) ||
- (CHIPID(wlc_hw->sih->chip) == BCM43421_CHIP_ID))
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43421_CHIP_ID))
wlc_hw->regs =
(d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID,
0);
@@ -2249,12 +2263,12 @@ bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw)
}
/* Initialize just the hardware when coming out of POR or S3/S5 system states */
-void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw)
{
if (wlc_hw->wlc->pub->hw_up)
return;
- WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__);
/*
* Enable pll and xtal, initialize the power control registers,
@@ -2264,13 +2278,13 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw)
si_clkctl_init(wlc_hw->sih);
wlc_clkctl_clk(wlc_hw, CLK_FAST);
- if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) {
+ if (wlc_hw->sih->bustype == PCI_BUS) {
si_pci_fixcfg(wlc_hw->sih);
/* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
- if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID) ||
- (CHIPID(wlc_hw->sih->chip) == BCM43421_CHIP_ID))
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43421_CHIP_ID))
wlc_hw->regs =
(d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID,
0);
@@ -2283,7 +2297,7 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw)
wlc_hw->wlc->pub->hw_up = true;
if ((wlc_hw->boardflags & BFL_FEM)
- && (CHIPID(wlc_hw->sih->chip) == BCM4313_CHIP_ID)) {
+ && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
if (!
(wlc_hw->boardrev >= 0x1250
&& (wlc_hw->boardflags & BFL_FEM_BT)))
@@ -2291,10 +2305,10 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw)
}
}
-static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo)
+static bool wlc_dma_rxreset(struct wlc_hw_info *wlc_hw, uint fifo)
{
- hnddma_t *di = wlc_hw->di[fifo];
- osl_t *osh;
+ struct hnddma_pub *di = wlc_hw->di[fifo];
+ struct osl_info *osh;
if (D11REV_LT(wlc_hw->corerev, 12)) {
bool rxidle = true;
@@ -2309,7 +2323,8 @@ static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo)
50000);
if (!rxidle && (rcv_frm_cnt != 0))
- WL_ERROR(("wl%d: %s: rxdma[%d] not idle && rcv_frm_cnt(%d) not zero\n", wlc_hw->unit, __func__, fifo, rcv_frm_cnt));
+ WL_ERROR("wl%d: %s: rxdma[%d] not idle && rcv_frm_cnt(%d) not zero\n",
+ wlc_hw->unit, __func__, fifo, rcv_frm_cnt);
mdelay(2);
}
@@ -2324,7 +2339,7 @@ static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo)
* clear software macintstatus for fresh new start
* one testing hack wlc_hw->noreset will bypass the d11/phy reset
*/
-void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags)
+void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags)
{
d11regs_t *regs;
uint i;
@@ -2334,7 +2349,7 @@ void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags)
if (flags == WLC_USE_COREFLAGS)
flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
- WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
regs = wlc_hw->regs;
@@ -2347,17 +2362,20 @@ void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags)
if (si_iscoreup(wlc_hw->sih)) {
for (i = 0; i < NFIFO; i++)
if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) {
- WL_ERROR(("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, i));
+ WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, i);
}
if ((wlc_hw->di[RX_FIFO])
&& (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) {
- WL_ERROR(("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, RX_FIFO));
+ WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, RX_FIFO);
}
if (D11REV_IS(wlc_hw->corerev, 4)
&& wlc_hw->di[RX_TXSTATUS_FIFO]
&& (!wlc_dma_rxreset(wlc_hw, RX_TXSTATUS_FIFO))) {
- WL_ERROR(("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, RX_TXSTATUS_FIFO));
+ WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, RX_TXSTATUS_FIFO);
}
}
/* if noreset, just stop the psm and return */
@@ -2413,14 +2431,14 @@ void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags)
* txfifo sizes needs to be modified(increased) since the newer cores
* have more memory.
*/
-static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw)
+static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw)
{
d11regs_t *regs = wlc_hw->regs;
u16 fifo_nu;
u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
u16 txfifo_def, txfifo_def1;
u16 txfifo_cmd;
- osl_t *osh;
+ struct osl_info *osh;
if (D11REV_LT(wlc_hw->corerev, 9))
goto exit;
@@ -2473,22 +2491,22 @@ static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw)
* config other core registers
* init dma
*/
-static void wlc_coreinit(wlc_info_t *wlc)
+static void wlc_coreinit(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs;
u32 sflags;
uint bcnint_us;
uint i = 0;
bool fifosz_fixup = false;
- osl_t *osh;
+ struct osl_info *osh;
int err = 0;
u16 buf[NFIFO];
regs = wlc_hw->regs;
osh = wlc_hw->osh;
- WL_TRACE(("wl%d: wlc_coreinit\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_coreinit\n", wlc_hw->unit);
/* reset PSM */
wlc_bmac_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
@@ -2511,8 +2529,8 @@ static void wlc_coreinit(wlc_info_t *wlc)
SPINWAIT(((R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD) == 0),
1000 * 1000);
if ((R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD) == 0)
- WL_ERROR(("wl%d: wlc_coreinit: ucode did not self-suspend!\n",
- wlc_hw->unit));
+ WL_ERROR("wl%d: wlc_coreinit: ucode did not self-suspend!\n",
+ wlc_hw->unit);
wlc_gpio_init(wlc);
@@ -2522,18 +2540,18 @@ static void wlc_coreinit(wlc_info_t *wlc)
if (WLCISNPHY(wlc_hw->band))
wlc_write_inits(wlc_hw, d11n0initvals16);
else
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
} else if (D11REV_IS(wlc_hw->corerev, 24)) {
if (WLCISLCNPHY(wlc_hw->band)) {
wlc_write_inits(wlc_hw, d11lcn0initvals24);
} else {
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
}
} else {
- WL_ERROR(("%s: wl%d: unsupported corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
}
/* For old ucode, txfifo sizes needs to be modified(increased) for Corerev >= 9 */
@@ -2575,7 +2593,8 @@ static void wlc_coreinit(wlc_info_t *wlc)
err = -1;
}
if (err != 0) {
- WL_ERROR(("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n", buf[i], wlc_hw->xmtfifo_sz[i], i));
+ WL_ERROR("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n",
+ buf[i], wlc_hw->xmtfifo_sz[i], i);
/* DO NOT ASSERT corerev < 4 even there is a mismatch
* shmem, since driver don't overwrite those chip and
* ucode initialize data will be used.
@@ -2684,15 +2703,15 @@ static void wlc_coreinit(wlc_info_t *wlc)
* - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
*/
-void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode)
+void wlc_bmac_switch_macfreq(struct wlc_hw_info *wlc_hw, u8 spurmode)
{
d11regs_t *regs;
- osl_t *osh;
+ struct osl_info *osh;
regs = wlc_hw->regs;
osh = wlc_hw->osh;
- if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID)) {
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) {
if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */
W_REG(osh, &regs->tsf_clk_frac_l, 0x2082);
W_REG(osh, &regs->tsf_clk_frac_h, 0x8);
@@ -2715,12 +2734,12 @@ void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode)
}
/* Initialize GPIOs that are controlled by D11 core */
-static void wlc_gpio_init(wlc_info_t *wlc)
+static void wlc_gpio_init(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs;
u32 gc, gm;
- osl_t *osh;
+ struct osl_info *osh;
regs = wlc_hw->regs;
osh = wlc_hw->osh;
@@ -2780,9 +2799,9 @@ static void wlc_gpio_init(wlc_info_t *wlc)
si_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
}
-static void wlc_ucode_download(wlc_hw_info_t *wlc_hw)
+static void wlc_ucode_download(struct wlc_hw_info *wlc_hw)
{
- wlc_info_t *wlc;
+ struct wlc_info *wlc;
wlc = wlc_hw->wlc;
if (wlc_hw->ucode_loaded)
@@ -2794,30 +2813,30 @@ static void wlc_ucode_download(wlc_hw_info_t *wlc_hw)
bcm43xx_16_mimosz);
wlc_hw->ucode_loaded = true;
} else
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
} else if (D11REV_IS(wlc_hw->corerev, 24)) {
if (WLCISLCNPHY(wlc_hw->band)) {
wlc_ucode_write(wlc_hw, bcm43xx_24_lcn,
bcm43xx_24_lcnsz);
wlc_hw->ucode_loaded = true;
} else {
- WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev));
+ WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
}
}
}
-static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[],
+static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[],
const uint nbytes) {
- osl_t *osh;
+ struct osl_info *osh;
d11regs_t *regs = wlc_hw->regs;
uint i;
uint count;
osh = wlc_hw->osh;
- WL_TRACE(("wl%d: wlc_ucode_write\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_ucode_write\n", wlc_hw->unit);
ASSERT(IS_ALIGNED(nbytes, sizeof(u32)));
@@ -2829,13 +2848,13 @@ static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[],
W_REG(osh, &regs->objdata, ucode[i]);
}
-static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits)
+static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits)
{
int i;
- osl_t *osh;
+ struct osl_info *osh;
volatile u8 *base;
- WL_TRACE(("wl%d: wlc_write_inits\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_write_inits\n", wlc_hw->unit);
osh = wlc_hw->osh;
base = (volatile u8 *)wlc_hw->regs;
@@ -2852,7 +2871,7 @@ static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits)
}
}
-static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw)
+static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw)
{
u16 phyctl;
u16 phytxant = wlc_hw->bmac_phytxant;
@@ -2869,7 +2888,7 @@ static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw)
wlc_bmac_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
}
-void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant)
+void wlc_bmac_txant_set(struct wlc_hw_info *wlc_hw, u16 phytxant)
{
/* update sw state */
wlc_hw->bmac_phytxant = phytxant;
@@ -2881,12 +2900,12 @@ void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant)
}
-u16 wlc_bmac_get_txant(wlc_hw_info_t *wlc_hw)
+u16 wlc_bmac_get_txant(struct wlc_hw_info *wlc_hw)
{
return (u16) wlc_hw->wlc->stf->txant;
}
-void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type)
+void wlc_bmac_antsel_type_set(struct wlc_hw_info *wlc_hw, u8 antsel_type)
{
wlc_hw->antsel_type = antsel_type;
@@ -2894,7 +2913,7 @@ void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type)
wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
}
-void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw)
+void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw)
{
bool fatal = false;
uint unit;
@@ -2911,44 +2930,45 @@ void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw)
if (!intstatus)
continue;
- WL_TRACE(("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n", unit,
- idx, intstatus));
+ WL_TRACE("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n",
+ unit, idx, intstatus);
if (intstatus & I_RO) {
- WL_ERROR(("wl%d: fifo %d: receive fifo overflow\n",
- unit, idx));
+ WL_ERROR("wl%d: fifo %d: receive fifo overflow\n",
+ unit, idx);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxoflo);
fatal = true;
}
if (intstatus & I_PC) {
- WL_ERROR(("wl%d: fifo %d: descriptor error\n", unit,
- idx));
+ WL_ERROR("wl%d: fifo %d: descriptor error\n",
+ unit, idx);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmade);
fatal = true;
}
if (intstatus & I_PD) {
- WL_ERROR(("wl%d: fifo %d: data error\n", unit, idx));
+ WL_ERROR("wl%d: fifo %d: data error\n", unit, idx);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmada);
fatal = true;
}
if (intstatus & I_DE) {
- WL_ERROR(("wl%d: fifo %d: descriptor protocol error\n",
- unit, idx));
+ WL_ERROR("wl%d: fifo %d: descriptor protocol error\n",
+ unit, idx);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmape);
fatal = true;
}
if (intstatus & I_RU) {
- WL_ERROR(("wl%d: fifo %d: receive descriptor underflow\n", unit, idx));
+ WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n",
+ idx, unit);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxuflo[idx]);
}
if (intstatus & I_XU) {
- WL_ERROR(("wl%d: fifo %d: transmit fifo underflow\n",
- idx, unit));
+ WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n",
+ idx, unit);
WLCNTINCR(wlc_hw->wlc->pub->_cnt->txuflo);
fatal = true;
}
@@ -2962,9 +2982,9 @@ void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw)
}
}
-void wlc_intrson(wlc_info_t *wlc)
+void wlc_intrson(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
ASSERT(wlc->defmacintmask);
wlc->macintmask = wlc->defmacintmask;
W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask);
@@ -2975,7 +2995,7 @@ void wlc_intrson(wlc_info_t *wlc)
* but also because per-port code may require sync with valid interrupt.
*/
-static u32 wlc_wlintrsoff(wlc_info_t *wlc)
+static u32 wlc_wlintrsoff(struct wlc_info *wlc)
{
if (!wlc->hw->up)
return 0;
@@ -2983,7 +3003,7 @@ static u32 wlc_wlintrsoff(wlc_info_t *wlc)
return wl_intrsoff(wlc->wl);
}
-static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask)
+static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask)
{
if (!wlc->hw->up)
return;
@@ -2991,9 +3011,9 @@ static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask)
wl_intrsrestore(wlc->wl, macintmask);
}
-u32 wlc_intrsoff(wlc_info_t *wlc)
+u32 wlc_intrsoff(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
u32 macintmask;
if (!wlc_hw->clk)
@@ -3010,9 +3030,9 @@ u32 wlc_intrsoff(wlc_info_t *wlc)
return wlc->macintstatus ? 0 : macintmask;
}
-void wlc_intrsrestore(wlc_info_t *wlc, u32 macintmask)
+void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
if (!wlc_hw->clk)
return;
@@ -3020,7 +3040,7 @@ void wlc_intrsrestore(wlc_info_t *wlc, u32 macintmask)
W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask);
}
-void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool on, mbool flags)
+void wlc_bmac_mute(struct wlc_hw_info *wlc_hw, bool on, mbool flags)
{
struct ether_addr null_ether_addr = { {0, 0, 0, 0, 0, 0} };
@@ -3056,12 +3076,12 @@ void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool on, mbool flags)
wlc_ucode_mute_override_clear(wlc_hw);
}
-void wlc_bmac_set_deaf(wlc_hw_info_t *wlc_hw, bool user_flag)
+void wlc_bmac_set_deaf(struct wlc_hw_info *wlc_hw, bool user_flag)
{
wlc_phy_set_deaf(wlc_hw->band->pi, user_flag);
}
-int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo, uint *blocks)
+int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info *wlc_hw, uint fifo, uint *blocks)
{
if (fifo >= NFIFO)
return BCME_RANGE;
@@ -3071,7 +3091,7 @@ int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo, uint *blocks)
return 0;
}
-int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo, uint blocks)
+int wlc_bmac_xmtfifo_sz_set(struct wlc_hw_info *wlc_hw, uint fifo, uint blocks)
{
if (fifo >= NFIFO || blocks > 299)
return BCME_RANGE;
@@ -3091,7 +3111,7 @@ int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo, uint blocks)
* be pulling data into a tx fifo, by the time the MAC acks the suspend
* request.
*/
-bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo)
+bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info *wlc_hw, uint tx_fifo)
{
/* check that a suspend has been requested and is no longer pending */
@@ -3110,7 +3130,7 @@ bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo)
return false;
}
-void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo)
+void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info *wlc_hw, uint tx_fifo)
{
u8 fifo = 1 << tx_fifo;
@@ -3141,7 +3161,7 @@ void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo)
}
}
-void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo)
+void wlc_bmac_tx_fifo_resume(struct wlc_hw_info *wlc_hw, uint tx_fifo)
{
/* BMAC_NOTE: WLC_TX_FIFO_ENAB is done in wlc_dpc() for DMA case but need to be done
* here for PIO otherwise the watchdog will catch the inconsistency and fire
@@ -3169,20 +3189,20 @@ void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo)
* 0 if the interrupt is not for us, or we are in some special cases;
* device interrupt status bits otherwise.
*/
-static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr)
+static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs = wlc_hw->regs;
u32 macintstatus;
u32 intstatus_rxfifo, intstatus_txsfifo;
- osl_t *osh;
+ struct osl_info *osh;
osh = wlc_hw->osh;
/* macintstatus includes a DMA interrupt summary bit */
macintstatus = R_REG(osh, &regs->macintstatus);
- WL_TRACE(("wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus));
+ WL_TRACE("wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus);
/* detect cardbus removed, in power down(suspend) and in reset */
if (DEVICEREMOVED(wlc))
@@ -3207,9 +3227,7 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr)
*/
/* turn off the interrupts */
W_REG(osh, &regs->macintmask, 0);
-#ifndef BCMSDIO
(void)R_REG(osh, &regs->macintmask); /* sync readback */
-#endif
wlc->macintmask = 0;
/* clear device interrupts */
@@ -3224,7 +3242,9 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr)
R_REG(osh,
&regs->intctrlregs[RX_TXSTATUS_FIFO].
intstatus);
- WL_TRACE(("wl%d: intstatus_rxfifo 0x%x, intstatus_txsfifo 0x%x\n", wlc_hw->unit, intstatus_rxfifo, intstatus_txsfifo));
+ WL_TRACE("wl%d: intstatus_rxfifo 0x%x, intstatus_txsfifo 0x%x\n",
+ wlc_hw->unit,
+ intstatus_rxfifo, intstatus_txsfifo);
/* defer unsolicited interrupt hints */
intstatus_rxfifo &= DEF_RXINTMASK;
@@ -3261,7 +3281,7 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr)
/* Update wlc->macintstatus and wlc->intstatus[]. */
/* Return true if they are updated successfully. false otherwise */
-bool wlc_intrsupd(wlc_info_t *wlc)
+bool wlc_intrsupd(struct wlc_info *wlc)
{
u32 macintstatus;
@@ -3286,9 +3306,9 @@ bool wlc_intrsupd(wlc_info_t *wlc)
* *wantdpc will be set to true if further wlc_dpc() processing is required,
* false otherwise.
*/
-bool BCMFASTPATH wlc_isr(wlc_info_t *wlc, bool *wantdpc)
+bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
u32 macintstatus;
*wantdpc = false;
@@ -3300,7 +3320,7 @@ bool BCMFASTPATH wlc_isr(wlc_info_t *wlc, bool *wantdpc)
macintstatus = wlc_intstatus(wlc, true);
if (macintstatus == 0xffffffff)
- WL_ERROR(("DEVICEREMOVED detected in the ISR code path.\n"));
+ WL_ERROR("DEVICEREMOVED detected in the ISR code path\n");
/* it is not for us */
if (macintstatus == 0)
@@ -3317,20 +3337,20 @@ bool BCMFASTPATH wlc_isr(wlc_info_t *wlc, bool *wantdpc)
}
/* process tx completion events for corerev < 5 */
-static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw)
+static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc_hw)
{
- void *status_p;
+ struct sk_buff *status_p;
tx_status_t *txs;
- osl_t *osh;
+ struct osl_info *osh;
bool fatal = false;
- WL_TRACE(("wl%d: wlc_txstatusrecv\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_txstatusrecv\n", wlc_hw->unit);
osh = wlc_hw->osh;
while (!fatal && (status_p = dma_rx(wlc_hw->di[RX_TXSTATUS_FIFO]))) {
- txs = (tx_status_t *) PKTDATA(status_p);
+ txs = (tx_status_t *) status_p->data;
/* MAC uses little endian only */
ltoh16_buf((void *)txs, sizeof(tx_status_t));
@@ -3340,7 +3360,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw)
fatal = wlc_bmac_dotxstatus(wlc_hw, txs, 0);
- PKTFREE(osh, status_p, false);
+ pkt_buf_free_skb(osh, status_p, false);
}
if (fatal)
@@ -3353,7 +3373,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw)
}
static bool BCMFASTPATH
-wlc_bmac_dotxstatus(wlc_hw_info_t *wlc_hw, tx_status_t *txs, u32 s2)
+wlc_bmac_dotxstatus(struct wlc_hw_info *wlc_hw, tx_status_t *txs, u32 s2)
{
/* discard intermediate indications for ucode with one legitimate case:
* e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
@@ -3372,12 +3392,12 @@ wlc_bmac_dotxstatus(wlc_hw_info_t *wlc_hw, tx_status_t *txs, u32 s2)
* Return true if more tx status need to be processed. false otherwise.
*/
static bool BCMFASTPATH
-wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal)
+wlc_bmac_txstatus(struct wlc_hw_info *wlc_hw, bool bound, bool *fatal)
{
bool morepending = false;
- wlc_info_t *wlc = wlc_hw->wlc;
+ struct wlc_info *wlc = wlc_hw->wlc;
- WL_TRACE(("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit);
if (D11REV_IS(wlc_hw->corerev, 4)) {
/* to retire soon */
@@ -3388,7 +3408,7 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal)
} else {
/* corerev >= 5 */
d11regs_t *regs;
- osl_t *osh;
+ struct osl_info *osh;
tx_status_t txstatus, *txs;
u32 s1, s2;
uint n = 0;
@@ -3402,8 +3422,8 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal)
&& (s1 = R_REG(osh, &regs->frmtxstatus)) & TXS_V) {
if (s1 == 0xffffffff) {
- WL_ERROR(("wl%d: %s: dead chip\n",
- wlc_hw->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n",
+ wlc_hw->unit, __func__);
ASSERT(s1 != 0xffffffff);
return morepending;
}
@@ -3436,15 +3456,15 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal)
return morepending;
}
-void wlc_suspend_mac_and_wait(wlc_info_t *wlc)
+void wlc_suspend_mac_and_wait(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs = wlc_hw->regs;
u32 mc, mi;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n", wlc_hw->unit,
- wlc_hw->band->bandunit));
+ WL_TRACE("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n",
+ wlc_hw->unit, wlc_hw->band->bandunit);
/*
* Track overlapping suspend requests
@@ -3461,7 +3481,7 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc)
mc = R_REG(osh, &regs->maccontrol);
if (mc == 0xffffffff) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
wl_down(wlc->wl);
return;
}
@@ -3471,7 +3491,7 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc)
mi = R_REG(osh, &regs->macintstatus);
if (mi == 0xffffffff) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
wl_down(wlc->wl);
return;
}
@@ -3483,15 +3503,18 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc)
WLC_MAX_MAC_SUSPEND);
if (!(R_REG(osh, &regs->macintstatus) & MI_MACSSPNDD)) {
- WL_ERROR(("wl%d: wlc_suspend_mac_and_wait: waited %d uS and "
- "MI_MACSSPNDD is still not on.\n",
- wlc_hw->unit, WLC_MAX_MAC_SUSPEND));
- WL_ERROR(("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n", wlc_hw->unit, R_REG(osh, &regs->psmdebug), R_REG(osh, &regs->phydebug), R_REG(osh, &regs->psm_brc)));
+ WL_ERROR("wl%d: wlc_suspend_mac_and_wait: waited %d uS and MI_MACSSPNDD is still not on.\n",
+ wlc_hw->unit, WLC_MAX_MAC_SUSPEND);
+ WL_ERROR("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n",
+ wlc_hw->unit,
+ R_REG(osh, &regs->psmdebug),
+ R_REG(osh, &regs->phydebug),
+ R_REG(osh, &regs->psm_brc));
}
mc = R_REG(osh, &regs->maccontrol);
if (mc == 0xffffffff) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__);
wl_down(wlc->wl);
return;
}
@@ -3500,15 +3523,15 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc)
ASSERT(!(mc & MCTL_EN_MAC));
}
-void wlc_enable_mac(wlc_info_t *wlc)
+void wlc_enable_mac(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
d11regs_t *regs = wlc_hw->regs;
u32 mc, mi;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: wlc_enable_mac: bandunit %d\n", wlc_hw->unit,
- wlc->band->bandunit));
+ WL_TRACE("wl%d: wlc_enable_mac: bandunit %d\n",
+ wlc_hw->unit, wlc->band->bandunit);
/*
* Track overlapping suspend requests
@@ -3539,7 +3562,7 @@ void wlc_enable_mac(wlc_info_t *wlc)
wlc_ucode_wake_override_clear(wlc_hw, WLC_WAKE_OVERRIDE_MACSUSPEND);
}
-void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie, bool isht)
+void wlc_bmac_ifsctl_edcrs_set(struct wlc_hw_info *wlc_hw, bool abie, bool isht)
{
if (!(WLCISNPHY(wlc_hw->band) && (D11REV_GE(wlc_hw->corerev, 16))))
return;
@@ -3575,7 +3598,7 @@ void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie, bool isht)
}
}
-static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw)
+static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw)
{
u8 rate;
u8 rates[8] = {
@@ -3609,7 +3632,7 @@ static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw)
}
}
-static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw, u8 rate)
+static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw, u8 rate)
{
uint i;
u8 plcp_rate = 0;
@@ -3642,7 +3665,7 @@ static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw, u8 rate)
return 2 * wlc_bmac_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
}
-void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode)
+void wlc_bmac_band_stf_ss_set(struct wlc_hw_info *wlc_hw, u8 stf_mode)
{
wlc_hw->hw_stf_ss_opmode = stf_mode;
@@ -3651,7 +3674,7 @@ void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode)
}
void BCMFASTPATH
-wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr,
+wlc_bmac_read_tsf(struct wlc_hw_info *wlc_hw, u32 *tsf_l_ptr,
u32 *tsf_h_ptr)
{
d11regs_t *regs = wlc_hw->regs;
@@ -3663,14 +3686,14 @@ wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr,
return;
}
-bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
+bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw)
{
d11regs_t *regs;
u32 w, val;
volatile u16 *reg16;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: validate_chip_access\n", wlc_hw->unit));
+ WL_TRACE("wl%d: validate_chip_access\n", wlc_hw->unit);
regs = wlc_hw->regs;
osh = wlc_hw->osh;
@@ -3690,7 +3713,8 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
(void)R_REG(osh, &regs->objaddr);
val = R_REG(osh, &regs->objdata);
if (val != (u32) 0xaa5555aa) {
- WL_ERROR(("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n", wlc_hw->unit, val));
+ WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n",
+ wlc_hw->unit, val);
return false;
}
@@ -3702,7 +3726,8 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
(void)R_REG(osh, &regs->objaddr);
val = R_REG(osh, &regs->objdata);
if (val != (u32) 0x55aaaa55) {
- WL_ERROR(("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n", wlc_hw->unit, val));
+ WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n",
+ wlc_hw->unit, val);
return false;
}
@@ -3732,12 +3757,14 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
/* verify with the 16 bit registers that have no side effects */
val = R_REG(osh, &regs->tsf_cfpstrt_l);
if (val != (uint) 0xBBBB) {
- WL_ERROR(("wl%d: validate_chip_access: tsf_cfpstrt_l = 0x%x, expected" " 0x%x\n", wlc_hw->unit, val, 0xBBBB));
+ WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_l = 0x%x, expected 0x%x\n",
+ wlc_hw->unit, val, 0xBBBB);
return false;
}
val = R_REG(osh, &regs->tsf_cfpstrt_h);
if (val != (uint) 0xCCCC) {
- WL_ERROR(("wl%d: validate_chip_access: tsf_cfpstrt_h = 0x%x, expected" " 0x%x\n", wlc_hw->unit, val, 0xCCCC));
+ WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_h = 0x%x, expected 0x%x\n",
+ wlc_hw->unit, val, 0xCCCC);
return false;
}
@@ -3749,7 +3776,10 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
w = R_REG(osh, &regs->maccontrol);
if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
(w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
- WL_ERROR(("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w, (MCTL_IHR_EN | MCTL_WAKE), (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE)));
+ WL_ERROR("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n",
+ wlc_hw->unit, w,
+ (MCTL_IHR_EN | MCTL_WAKE),
+ (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
return false;
}
@@ -3758,13 +3788,13 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw)
#define PHYPLL_WAIT_US 100000
-void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on)
+void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on)
{
d11regs_t *regs;
- osl_t *osh;
+ struct osl_info *osh;
u32 tmp;
- WL_TRACE(("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit));
+ WL_TRACE("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit);
tmp = 0;
regs = wlc_hw->regs;
@@ -3785,8 +3815,8 @@ void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on)
tmp = R_REG(osh, &regs->clk_ctl_st);
if ((tmp & (CCS_ERSRC_AVAIL_HT)) !=
(CCS_ERSRC_AVAIL_HT)) {
- WL_ERROR(("%s: turn on PHY PLL failed\n",
- __func__));
+ WL_ERROR("%s: turn on PHY PLL failed\n",
+ __func__);
ASSERT(0);
}
} else {
@@ -3803,8 +3833,8 @@ void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on)
(CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
!=
(CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) {
- WL_ERROR(("%s: turn on PHY PLL failed\n",
- __func__));
+ WL_ERROR("%s: turn on PHY PLL failed\n",
+ __func__);
ASSERT(0);
}
}
@@ -3817,11 +3847,11 @@ void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on)
}
}
-void wlc_coredisable(wlc_hw_info_t *wlc_hw)
+void wlc_coredisable(struct wlc_hw_info *wlc_hw)
{
bool dev_gone;
- WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
ASSERT(!wlc_hw->up);
@@ -3857,9 +3887,9 @@ void wlc_coredisable(wlc_hw_info_t *wlc_hw)
}
/* power both the pll and external oscillator on/off */
-void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want)
+void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want)
{
- WL_TRACE(("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want));
+ WL_TRACE("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want);
/* dont power down if plldown is false or we must poll hw radio disable */
if (!want && wlc_hw->pllreq)
@@ -3876,9 +3906,9 @@ void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want)
}
}
-static void wlc_flushqueues(wlc_info_t *wlc)
+static void wlc_flushqueues(struct wlc_info *wlc)
{
- wlc_hw_info_t *wlc_hw = wlc->hw;
+ struct wlc_hw_info *wlc_hw = wlc->hw;
uint i;
wlc->txpend16165war = 0;
@@ -3888,8 +3918,8 @@ static void wlc_flushqueues(wlc_info_t *wlc)
if (wlc_hw->di[i]) {
dma_txreclaim(wlc_hw->di[i], HNDDMA_RANGE_ALL);
TXPKTPENDCLR(wlc, i);
- WL_TRACE(("wlc_flushqueues: pktpend fifo %d cleared\n",
- i));
+ WL_TRACE("wlc_flushqueues: pktpend fifo %d cleared\n",
+ i);
}
/* free any posted rx packets */
@@ -3898,12 +3928,12 @@ static void wlc_flushqueues(wlc_info_t *wlc)
dma_rxreclaim(wlc_hw->di[RX_TXSTATUS_FIFO]);
}
-u16 wlc_bmac_read_shm(wlc_hw_info_t *wlc_hw, uint offset)
+u16 wlc_bmac_read_shm(struct wlc_hw_info *wlc_hw, uint offset)
{
return wlc_bmac_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
}
-void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v)
+void wlc_bmac_write_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v)
{
wlc_bmac_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
}
@@ -3912,7 +3942,7 @@ void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v)
* SHM 'offset' needs to be an even address and
* Buffer length 'len' must be an even number of bytes
*/
-void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v, int len)
+void wlc_bmac_set_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v, int len)
{
int i;
@@ -3929,7 +3959,7 @@ void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v, int len)
}
static u16
-wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, u32 sel)
+wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset, u32 sel)
{
d11regs_t *regs = wlc_hw->regs;
volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
@@ -3950,7 +3980,7 @@ wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, u32 sel)
}
static void
-wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, u32 sel)
+wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset, u16 v, u32 sel)
{
d11regs_t *regs = wlc_hw->regs;
volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
@@ -3973,7 +4003,7 @@ wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, u32 sel)
* 'sel' selects the type of memory
*/
void
-wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, uint offset, const void *buf,
+wlc_bmac_copyto_objmem(struct wlc_hw_info *wlc_hw, uint offset, const void *buf,
int len, u32 sel)
{
u16 v;
@@ -3999,7 +4029,7 @@ wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, uint offset, const void *buf,
* 'sel' selects the type of memory
*/
void
-wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset, void *buf,
+wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset, void *buf,
int len, u32 sel)
{
u16 v;
@@ -4020,16 +4050,16 @@ wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset, void *buf,
}
}
-void wlc_bmac_copyfrom_vars(wlc_hw_info_t *wlc_hw, char **buf, uint *len)
+void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf, uint *len)
{
- WL_TRACE(("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n",
- wlc_hw->vars_size));
+ WL_TRACE("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n",
+ wlc_hw->vars_size);
*buf = wlc_hw->vars;
*len = wlc_hw->vars_size;
}
-void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, u16 LRL)
+void wlc_bmac_retrylimit_upd(struct wlc_hw_info *wlc_hw, u16 SRL, u16 LRL)
{
wlc_hw->SRL = SRL;
wlc_hw->LRL = LRL;
@@ -4047,17 +4077,17 @@ void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, u16 LRL)
}
}
-void wlc_bmac_set_noreset(wlc_hw_info_t *wlc_hw, bool noreset_flag)
+void wlc_bmac_set_noreset(struct wlc_hw_info *wlc_hw, bool noreset_flag)
{
wlc_hw->noreset = noreset_flag;
}
-void wlc_bmac_set_ucode_loaded(wlc_hw_info_t *wlc_hw, bool ucode_loaded)
+void wlc_bmac_set_ucode_loaded(struct wlc_hw_info *wlc_hw, bool ucode_loaded)
{
wlc_hw->ucode_loaded = ucode_loaded;
}
-void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit)
+void wlc_bmac_pllreq(struct wlc_hw_info *wlc_hw, bool set, mbool req_bit)
{
ASSERT(req_bit);
@@ -4088,7 +4118,7 @@ void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit)
return;
}
-void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on)
+void wlc_bmac_set_clk(struct wlc_hw_info *wlc_hw, bool on)
{
if (on) {
/* power up pll and oscillator */
@@ -4110,7 +4140,7 @@ void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on)
}
/* this will be true for all ai chips */
-bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok)
+bool wlc_bmac_taclear(struct wlc_hw_info *wlc_hw, bool ta_ok)
{
return true;
}
@@ -4118,7 +4148,7 @@ bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok)
/* Lower down relevant GPIOs like LED when going down w/o
* doing PCI config cycles or touching interrupts
*/
-void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw)
+void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw)
{
if ((wlc_hw == NULL) || (wlc_hw->sih == NULL))
return;
@@ -4126,17 +4156,17 @@ void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw)
/* Only chips with internal bus or PCIE cores or certain PCI cores
* are able to switch cores w/o disabling interrupts
*/
- if (!((BUSTYPE(wlc_hw->sih->bustype) == SI_BUS) ||
- ((BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) &&
+ if (!((wlc_hw->sih->bustype == SI_BUS) ||
+ ((wlc_hw->sih->bustype == PCI_BUS) &&
((wlc_hw->sih->buscoretype == PCIE_CORE_ID) ||
(wlc_hw->sih->buscorerev >= 13)))))
return;
- WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__);
return;
}
-bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable)
+bool wlc_bmac_radio_hw(struct wlc_hw_info *wlc_hw, bool enable)
{
/* Do not access Phy registers if core is not up */
if (si_iscoreup(wlc_hw->sih) == false)
@@ -4171,7 +4201,7 @@ bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable)
return true;
}
-u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate)
+u16 wlc_bmac_rate_shm_offset(struct wlc_hw_info *wlc_hw, u8 rate)
{
u16 table_ptr;
u8 phy_rate, index;
@@ -4195,12 +4225,12 @@ u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate)
return 2 * wlc_bmac_read_shm(wlc_hw, table_ptr + (index * 2));
}
-void wlc_bmac_set_txpwr_percent(wlc_hw_info_t *wlc_hw, u8 val)
+void wlc_bmac_set_txpwr_percent(struct wlc_hw_info *wlc_hw, u8 val)
{
wlc_phy_txpwr_percent_set(wlc_hw->band->pi, val);
}
-void wlc_bmac_antsel_set(wlc_hw_info_t *wlc_hw, u32 antsel_avail)
+void wlc_bmac_antsel_set(struct wlc_hw_info *wlc_hw, u32 antsel_avail)
{
wlc_hw->antsel_avail = antsel_avail;
}
diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h
index 872bc8d866d2..98150aaff3a3 100644
--- a/drivers/staging/brcm80211/sys/wlc_bmac.h
+++ b/drivers/staging/brcm80211/sys/wlc_bmac.h
@@ -57,7 +57,8 @@ typedef struct wlc_bmac_revinfo {
} band[MAXBANDS];
} wlc_bmac_revinfo_t;
-/* dup state between BMAC(wlc_hw_info_t) and HIGH(wlc_info_t) driver */
+/* dup state between BMAC(struct wlc_hw_info) and HIGH(struct wlc_info)
+ driver */
typedef struct wlc_bmac_state {
u32 machwcap; /* mac hw capibility */
u32 preamble_ovr; /* preamble override */
@@ -130,148 +131,143 @@ typedef enum {
WLCHW_STATE_LAST
} wlc_bmac_state_id_t;
-extern int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device,
- uint unit, bool piomode, osl_t *osh, void *regsva,
- uint bustype, void *btparam);
-extern int wlc_bmac_detach(wlc_info_t *wlc);
+extern int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device,
+ uint unit, bool piomode, struct osl_info *osh,
+ void *regsva, uint bustype, void *btparam);
+extern int wlc_bmac_detach(struct wlc_info *wlc);
extern void wlc_bmac_watchdog(void *arg);
-extern void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw);
+extern void wlc_bmac_info_init(struct wlc_hw_info *wlc_hw);
/* up/down, reset, clk */
-#ifdef WLC_LOW
-extern void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want);
-#endif
+extern void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want);
-extern void wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw,
+extern void wlc_bmac_copyto_objmem(struct wlc_hw_info *wlc_hw,
uint offset, const void *buf, int len,
u32 sel);
-extern void wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset,
+extern void wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset,
void *buf, int len, u32 sel);
#define wlc_bmac_copyfrom_shm(wlc_hw, offset, buf, len) \
wlc_bmac_copyfrom_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL)
#define wlc_bmac_copyto_shm(wlc_hw, offset, buf, len) \
wlc_bmac_copyto_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL)
-extern void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk);
-extern void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on);
-extern void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk);
-extern void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk);
-extern void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags);
-extern void wlc_bmac_reset(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec,
+extern void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk);
+extern void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on);
+extern void wlc_bmac_phyclk_fgc(struct wlc_hw_info *wlc_hw, bool clk);
+extern void wlc_bmac_macphyclk_set(struct wlc_hw_info *wlc_hw, bool clk);
+extern void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags);
+extern void wlc_bmac_reset(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec,
bool mute);
-extern int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw);
-extern int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw);
-extern int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw);
-extern int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags);
-extern void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode);
+extern int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw);
+extern int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw);
+extern int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw);
+extern int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags);
+extern void wlc_bmac_switch_macfreq(struct wlc_hw_info *wlc_hw, u8 spurmode);
/* chanspec, ucode interface */
-extern int wlc_bmac_bandtype(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec,
+extern int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw,
+ chanspec_t chanspec,
bool mute, struct txpwr_limits *txpwr);
-extern void wlc_bmac_txfifo(wlc_hw_info_t *wlc_hw, uint fifo, void *p,
+extern void wlc_bmac_txfifo(struct wlc_hw_info *wlc_hw, uint fifo, void *p,
bool commit, u16 frameid, u8 txpktpend);
-extern int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo,
+extern int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info *wlc_hw, uint fifo,
uint *blocks);
-extern void wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask,
+extern void wlc_bmac_mhf(struct wlc_hw_info *wlc_hw, u8 idx, u16 mask,
u16 val, int bands);
-extern void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val);
-extern u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands);
-extern int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo,
+extern void wlc_bmac_mctrl(struct wlc_hw_info *wlc_hw, u32 mask, u32 val);
+extern u16 wlc_bmac_mhf_get(struct wlc_hw_info *wlc_hw, u8 idx, int bands);
+extern int wlc_bmac_xmtfifo_sz_set(struct wlc_hw_info *wlc_hw, uint fifo,
uint blocks);
-extern void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant);
-extern u16 wlc_bmac_get_txant(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type);
-extern int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw,
+extern void wlc_bmac_txant_set(struct wlc_hw_info *wlc_hw, u16 phytxant);
+extern u16 wlc_bmac_get_txant(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_antsel_type_set(struct wlc_hw_info *wlc_hw,
+ u8 antsel_type);
+extern int wlc_bmac_revinfo_get(struct wlc_hw_info *wlc_hw,
wlc_bmac_revinfo_t *revinfo);
-extern int wlc_bmac_state_get(wlc_hw_info_t *wlc_hw, wlc_bmac_state_t *state);
-extern void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v);
-extern u16 wlc_bmac_read_shm(wlc_hw_info_t *wlc_hw, uint offset);
-extern void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v,
+extern int wlc_bmac_state_get(struct wlc_hw_info *wlc_hw,
+ wlc_bmac_state_t *state);
+extern void wlc_bmac_write_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v);
+extern u16 wlc_bmac_read_shm(struct wlc_hw_info *wlc_hw, uint offset);
+extern void wlc_bmac_set_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v,
int len);
-extern void wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset,
+extern void wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset,
int len, void *buf);
-extern void wlc_bmac_copyfrom_vars(wlc_hw_info_t *wlc_hw, char **buf,
+extern void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf,
uint *len);
-extern void wlc_bmac_process_ps_switch(wlc_hw_info_t *wlc,
+extern void wlc_bmac_process_ps_switch(struct wlc_hw_info *wlc,
struct ether_addr *ea, s8 ps_on);
-extern void wlc_bmac_hw_etheraddr(wlc_hw_info_t *wlc_hw,
+extern void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw,
struct ether_addr *ea);
-extern void wlc_bmac_set_hw_etheraddr(wlc_hw_info_t *wlc_hw,
+extern void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw,
struct ether_addr *ea);
-extern bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw);
+extern bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw);
-extern bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw);
-extern void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot);
-extern void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool want, mbool flags);
-extern void wlc_bmac_set_deaf(wlc_hw_info_t *wlc_hw, bool user_flag);
-extern void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode);
+extern bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info *wlc_hw);
+extern void wlc_bmac_set_shortslot(struct wlc_hw_info *wlc_hw, bool shortslot);
+extern void wlc_bmac_mute(struct wlc_hw_info *wlc_hw, bool want, mbool flags);
+extern void wlc_bmac_set_deaf(struct wlc_hw_info *wlc_hw, bool user_flag);
+extern void wlc_bmac_band_stf_ss_set(struct wlc_hw_info *wlc_hw, u8 stf_mode);
-extern void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw);
-extern bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo);
-extern void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo);
-extern void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo);
+extern void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw);
+extern bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info *wlc_hw,
+ uint tx_fifo);
+extern void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info *wlc_hw, uint tx_fifo);
+extern void wlc_bmac_tx_fifo_resume(struct wlc_hw_info *wlc_hw, uint tx_fifo);
-extern void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw,
+extern void wlc_ucode_wake_override_set(struct wlc_hw_info *wlc_hw,
u32 override_bit);
-extern void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw,
+extern void wlc_ucode_wake_override_clear(struct wlc_hw_info *wlc_hw,
u32 override_bit);
-extern void wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx,
+extern void wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx,
const struct ether_addr *addr);
-extern void wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset,
+extern void wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw,
+ int match_reg_offset,
const struct ether_addr *addr);
-extern void wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn,
- int len, bool both);
+extern void wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info *wlc_hw,
+ void *bcn, int len, bool both);
-extern void wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr,
+extern void wlc_bmac_read_tsf(struct wlc_hw_info *wlc_hw, u32 *tsf_l_ptr,
u32 *tsf_h_ptr);
-extern void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin);
-extern void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax);
-extern void wlc_bmac_set_noreset(wlc_hw_info_t *wlc, bool noreset_flag);
-extern void wlc_bmac_set_ucode_loaded(wlc_hw_info_t *wlc, bool ucode_loaded);
+extern void wlc_bmac_set_cwmin(struct wlc_hw_info *wlc_hw, u16 newmin);
+extern void wlc_bmac_set_cwmax(struct wlc_hw_info *wlc_hw, u16 newmax);
+extern void wlc_bmac_set_noreset(struct wlc_hw_info *wlc, bool noreset_flag);
+extern void wlc_bmac_set_ucode_loaded(struct wlc_hw_info *wlc,
+ bool ucode_loaded);
-extern void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL,
+extern void wlc_bmac_retrylimit_upd(struct wlc_hw_info *wlc_hw, u16 SRL,
u16 LRL);
-extern void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw);
+extern void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw);
-#ifdef WLC_HIGH_ONLY
-extern void wlc_bmac_dngl_reboot(rpc_info_t *);
-extern void wlc_bmac_dngl_rpc_agg(rpc_info_t *, u16 agg);
-extern void wlc_bmac_dngl_rpc_msglevel(rpc_info_t *, u16 level);
-extern void wlc_bmac_dngl_rpc_txq_wm_set(rpc_info_t *rpc, u32 wm);
-extern void wlc_bmac_dngl_rpc_txq_wm_get(rpc_info_t *rpc, u32 *wm);
-extern void wlc_bmac_dngl_rpc_agg_limit_set(rpc_info_t *rpc, u32 val);
-extern void wlc_bmac_dngl_rpc_agg_limit_get(rpc_info_t *rpc, u32 *pval);
-extern int wlc_bmac_debug_template(wlc_hw_info_t *wlc_hw);
-#endif
/* API for BMAC driver (e.g. wlc_phy.c etc) */
-extern void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw);
-extern void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit);
-extern void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on);
-extern bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok);
+extern void wlc_bmac_bw_set(struct wlc_hw_info *wlc_hw, u16 bw);
+extern void wlc_bmac_pllreq(struct wlc_hw_info *wlc_hw, bool set,
+ mbool req_bit);
+extern void wlc_bmac_set_clk(struct wlc_hw_info *wlc_hw, bool on);
+extern bool wlc_bmac_taclear(struct wlc_hw_info *wlc_hw, bool ta_ok);
extern void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw);
-extern void wlc_bmac_dump(wlc_hw_info_t *wlc_hw, struct bcmstrbuf *b,
+extern void wlc_bmac_dump(struct wlc_hw_info *wlc_hw, struct bcmstrbuf *b,
wlc_bmac_dump_id_t dump_id);
-extern void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw);
+extern void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw);
-extern bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable);
-extern u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate);
+extern bool wlc_bmac_radio_hw(struct wlc_hw_info *wlc_hw, bool enable);
+extern u16 wlc_bmac_rate_shm_offset(struct wlc_hw_info *wlc_hw, u8 rate);
-extern void wlc_bmac_assert_type_set(wlc_hw_info_t *wlc_hw, u32 type);
-extern void wlc_bmac_set_txpwr_percent(wlc_hw_info_t *wlc_hw, u8 val);
-extern void wlc_bmac_blink_sync(wlc_hw_info_t *wlc_hw, u32 led_pins);
-extern void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie,
+extern void wlc_bmac_assert_type_set(struct wlc_hw_info *wlc_hw, u32 type);
+extern void wlc_bmac_set_txpwr_percent(struct wlc_hw_info *wlc_hw, u8 val);
+extern void wlc_bmac_blink_sync(struct wlc_hw_info *wlc_hw, u32 led_pins);
+extern void wlc_bmac_ifsctl_edcrs_set(struct wlc_hw_info *wlc_hw, bool abie,
bool isht);
-extern void wlc_bmac_antsel_set(wlc_hw_info_t *wlc_hw, u32 antsel_avail);
+extern void wlc_bmac_antsel_set(struct wlc_hw_info *wlc_hw, u32 antsel_avail);
diff --git a/drivers/staging/brcm80211/sys/wlc_bsscfg.h b/drivers/staging/brcm80211/sys/wlc_bsscfg.h
index ae5542ab0334..d6a1971c69a0 100644
--- a/drivers/staging/brcm80211/sys/wlc_bsscfg.h
+++ b/drivers/staging/brcm80211/sys/wlc_bsscfg.h
@@ -34,7 +34,8 @@ typedef struct wlc_bsscfg wlc_bsscfg_t;
#define MAXMACLIST 64 /* max # source MAC matches */
#define BCN_TEMPLATE_COUNT 2
-/* Iterator for "associated" STA bss configs: (wlc_info_t *wlc, int idx, wlc_bsscfg_t *cfg) */
+/* Iterator for "associated" STA bss configs:
+ (struct wlc_info *wlc, int idx, wlc_bsscfg_t *cfg) */
#define FOREACH_AS_STA(wlc, idx, cfg) \
for (idx = 0; (int) idx < WLC_MAXBSSCFG; idx++) \
if ((cfg = (wlc)->bsscfg[idx]) && BSSCFG_STA(cfg) && cfg->associated)
diff --git a/drivers/staging/brcm80211/sys/wlc_cfg.h b/drivers/staging/brcm80211/sys/wlc_cfg.h
index a415e1fd2c05..3decb7d1a5e5 100644
--- a/drivers/staging/brcm80211/sys/wlc_cfg.h
+++ b/drivers/staging/brcm80211/sys/wlc_cfg.h
@@ -23,14 +23,6 @@
#define IS_SINGLEBAND_5G(device) 0
-/* Keep WLC_HIGH_ONLY, WLC_SPLIT for USB extension later on */
-#if !defined(WLC_LOW)
-#define WLC_HIGH_ONLY
-#endif
-#if !defined(WLC_LOW)
-#define WLC_SPLIT
-#endif
-
/* **** Core type/rev defaults **** */
#define D11_DEFAULT 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
* also need to update wlc.h MAXCOREREV
@@ -61,22 +53,6 @@
* 3 5356a0
*/
-#ifdef BCMSDIO
-#define D11CONF 0x100000
-#define SSLPNCONF 2
-#define GCCONF 0
-#define ACCONF 0
-#define NCONF 0
-#define LPCONF 0
-#define LCNCONF 0
-#define NTXD 32
-#define NRXD 16
-#define NRXBUFPOST 8
-#define WLC_DATAHIWAT 32
-#define RXBND 8
-#define MAXPKTCB 64
-#define AMPDU_NUM_MPDU 8
-#endif
/* For undefined values, use defaults */
#ifndef D11CONF
diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c
index 509280337e34..a35c15214880 100644
--- a/drivers/staging/brcm80211/sys/wlc_channel.c
+++ b/drivers/staging/brcm80211/sys/wlc_channel.c
@@ -19,16 +19,21 @@
#include <bcmdefs.h>
#include <wlc_cfg.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmutils.h>
#include <siutils.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <wlioctl.h>
#include <wlc_pub.h>
#include <wlc_key.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_bmac.h>
#include <wlc_stf.h>
#include <wlc_channel.h>
+#include <wl_dbg.h>
typedef struct wlc_cm_band {
u8 locale_flags; /* locale_info_t flags */
@@ -39,8 +44,8 @@ typedef struct wlc_cm_band {
} wlc_cm_band_t;
struct wlc_cm_info {
- wlc_pub_t *pub;
- wlc_info_t *wlc;
+ struct wlc_pub *pub;
+ struct wlc_info *wlc;
char srom_ccode[WLC_CNTRY_BUF_SZ]; /* Country Code in SROM */
uint srom_regrev; /* Regulatory Rev for the SROM ccode */
const country_info_t *country; /* current country def */
@@ -377,7 +382,7 @@ void wlc_locale_get_channels(const locale_info_t *locale, chanvec_t *channels)
{
u8 i;
- bzero(channels, sizeof(chanvec_t));
+ memset(channels, 0, sizeof(chanvec_t));
for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
if (locale->valid_channels & (1 << i)) {
@@ -562,8 +567,8 @@ struct chan20_info chan20_info[] = {
const locale_info_t *wlc_get_locale_2g(u8 locale_idx)
{
if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) {
- WL_ERROR(("%s: locale 2g index size out of range %d\n",
- __func__, locale_idx));
+ WL_ERROR("%s: locale 2g index size out of range %d\n",
+ __func__, locale_idx);
ASSERT(locale_idx < ARRAY_SIZE(g_locale_2g_table));
return NULL;
}
@@ -573,8 +578,8 @@ const locale_info_t *wlc_get_locale_2g(u8 locale_idx)
const locale_info_t *wlc_get_locale_5g(u8 locale_idx)
{
if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) {
- WL_ERROR(("%s: locale 5g index size out of range %d\n",
- __func__, locale_idx));
+ WL_ERROR("%s: locale 5g index size out of range %d\n",
+ __func__, locale_idx);
ASSERT(locale_idx < ARRAY_SIZE(g_locale_5g_table));
return NULL;
}
@@ -584,8 +589,8 @@ const locale_info_t *wlc_get_locale_5g(u8 locale_idx)
const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx)
{
if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) {
- WL_ERROR(("%s: mimo 2g index size out of range %d\n", __func__,
- locale_idx));
+ WL_ERROR("%s: mimo 2g index size out of range %d\n",
+ __func__, locale_idx);
return NULL;
}
return g_mimo_2g_table[locale_idx];
@@ -594,26 +599,26 @@ const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx)
const locale_mimo_info_t *wlc_get_mimo_5g(u8 locale_idx)
{
if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) {
- WL_ERROR(("%s: mimo 5g index size out of range %d\n", __func__,
- locale_idx));
+ WL_ERROR("%s: mimo 5g index size out of range %d\n",
+ __func__, locale_idx);
return NULL;
}
return g_mimo_5g_table[locale_idx];
}
-wlc_cm_info_t *wlc_channel_mgr_attach(wlc_info_t *wlc)
+wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc)
{
wlc_cm_info_t *wlc_cm;
char country_abbrev[WLC_CNTRY_BUF_SZ];
const country_info_t *country;
- wlc_pub_t *pub = wlc->pub;
+ struct wlc_pub *pub = wlc->pub;
char *ccode;
- WL_TRACE(("wl%d: wlc_channel_mgr_attach\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_channel_mgr_attach\n", wlc->pub->unit);
wlc_cm = kzalloc(sizeof(wlc_cm_info_t), GFP_ATOMIC);
if (wlc_cm == NULL) {
- WL_ERROR(("wl%d: %s: out of memory", pub->unit, __func__));
+ WL_ERROR("wl%d: %s: out of memory", pub->unit, __func__);
return NULL;
}
wlc_cm->pub = pub;
@@ -624,12 +629,13 @@ wlc_cm_info_t *wlc_channel_mgr_attach(wlc_info_t *wlc)
ccode = getvar(wlc->pub->vars, "ccode");
if (ccode) {
strncpy(wlc->pub->srom_ccode, ccode, WLC_CNTRY_BUF_SZ - 1);
- WL_NONE(("%s: SROM country code is %c%c\n", __func__,
- wlc->pub->srom_ccode[0], wlc->pub->srom_ccode[1]));
+ WL_NONE("%s: SROM country code is %c%c\n",
+ __func__,
+ wlc->pub->srom_ccode[0], wlc->pub->srom_ccode[1]);
}
/* internal country information which must match regulatory constraints in firmware */
- bzero(country_abbrev, WLC_CNTRY_BUF_SZ);
+ memset(country_abbrev, 0, WLC_CNTRY_BUF_SZ);
strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
country = wlc_country_lookup(wlc, country_abbrev);
@@ -659,7 +665,7 @@ const char *wlc_channel_country_abbrev(wlc_cm_info_t *wlc_cm)
u8 wlc_channel_locale_flags(wlc_cm_info_t *wlc_cm)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
return wlc_cm->bandstate[wlc->band->bandunit].locale_flags;
}
@@ -711,7 +717,9 @@ wlc_set_countrycode_rev(wlc_cm_info_t *wlc_cm,
char mapped_ccode[WLC_CNTRY_BUF_SZ];
uint mapped_regrev;
- WL_NONE(("%s: (country_abbrev \"%s\", ccode \"%s\", regrev %d) SPROM \"%s\"/%u\n", __func__, country_abbrev, ccode, regrev, wlc_cm->srom_ccode, wlc_cm->srom_regrev));
+ WL_NONE("%s: (country_abbrev \"%s\", ccode \"%s\", regrev %d) SPROM \"%s\"/%u\n",
+ __func__, country_abbrev, ccode, regrev,
+ wlc_cm->srom_ccode, wlc_cm->srom_regrev);
/* if regrev is -1, lookup the mapped country code,
* otherwise use the ccode and regrev directly
@@ -750,7 +758,7 @@ wlc_set_country_common(wlc_cm_info_t *wlc_cm,
{
const locale_mimo_info_t *li_mimo;
const locale_info_t *locale;
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
char prev_country_abbrev[WLC_CNTRY_BUF_SZ];
ASSERT(country != NULL);
@@ -758,7 +766,7 @@ wlc_set_country_common(wlc_cm_info_t *wlc_cm,
/* save current country state */
wlc_cm->country = country;
- bzero(&prev_country_abbrev, WLC_CNTRY_BUF_SZ);
+ memset(&prev_country_abbrev, 0, WLC_CNTRY_BUF_SZ);
strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
WLC_CNTRY_BUF_SZ - 1);
@@ -814,7 +822,7 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm,
char *mapped_ccode,
uint *mapped_regrev)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
const country_info_t *country;
uint srom_regrev = wlc_cm->srom_regrev;
const char *srom_ccode = wlc_cm->srom_ccode;
@@ -822,8 +830,8 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm,
/* check for currently supported ccode size */
if (strlen(ccode) > (WLC_CNTRY_BUF_SZ - 1)) {
- WL_ERROR(("wl%d: %s: ccode \"%s\" too long for match\n",
- wlc->pub->unit, __func__, ccode));
+ WL_ERROR("wl%d: %s: ccode \"%s\" too long for match\n",
+ wlc->pub->unit, __func__, ccode);
return NULL;
}
@@ -838,7 +846,7 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm,
if (!strcmp(srom_ccode, ccode)) {
*mapped_regrev = srom_regrev;
mapped = 0;
- WL_ERROR(("srom_code == ccode %s\n", __func__));
+ WL_ERROR("srom_code == ccode %s\n", __func__);
ASSERT(0);
} else {
mapped =
@@ -890,7 +898,7 @@ static const country_info_t *wlc_country_lookup_direct(const char *ccode,
}
}
- WL_ERROR(("%s: Returning NULL\n", __func__));
+ WL_ERROR("%s: Returning NULL\n", __func__);
ASSERT(0);
return NULL;
}
@@ -898,9 +906,9 @@ static const country_info_t *wlc_country_lookup_direct(const char *ccode,
static int
wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
uint i, j;
- wlcband_t *band;
+ struct wlcband *band;
const locale_info_t *li;
chanvec_t sup_chan;
const locale_mimo_info_t *li_mimo;
@@ -952,7 +960,7 @@ wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country)
*/
static void wlc_channels_commit(wlc_cm_info_t *wlc_cm)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
uint chan;
struct txpwr_limits txpwr;
@@ -969,7 +977,9 @@ static void wlc_channels_commit(wlc_cm_info_t *wlc_cm)
if (chan == INVCHANNEL) {
/* country/locale with no valid channels, set the radio disable bit */
mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- WL_ERROR(("wl%d: %s: no valid channel for \"%s\" nbands %d bandlocked %d\n", wlc->pub->unit, __func__, wlc_cm->country_abbrev, NBANDS(wlc), wlc->bandlocked));
+ WL_ERROR("wl%d: %s: no valid channel for \"%s\" nbands %d bandlocked %d\n",
+ wlc->pub->unit, __func__,
+ wlc_cm->country_abbrev, NBANDS(wlc), wlc->bandlocked);
} else
if (mboolisset(wlc->pub->radio_disabled,
WL_RADIO_COUNTRY_DISABLE)) {
@@ -998,12 +1008,12 @@ static void wlc_channels_commit(wlc_cm_info_t *wlc_cm)
/* reset the quiet channels vector to the union of the restricted and radar channel sets */
void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
uint i, j;
- wlcband_t *band;
+ struct wlcband *band;
const chanvec_t *chanvec;
- bzero(&wlc_cm->quiet_channels, sizeof(chanvec_t));
+ memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t));
band = wlc->band;
for (i = 0; i < NBANDS(wlc);
@@ -1036,7 +1046,7 @@ bool wlc_quiet_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chspec)
*/
bool wlc_valid_channel20_db(wlc_cm_info_t *wlc_cm, uint val)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
return VALID_CHANNEL20(wlc, val) ||
(!wlc->bandlocked
@@ -1054,7 +1064,7 @@ wlc_valid_channel20_in_band(wlc_cm_info_t *wlc_cm, uint bandunit, uint val)
/* Is the channel valid for the current locale and current band? */
bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
return ((val < MAXCHANNEL) &&
isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
@@ -1064,7 +1074,7 @@ bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val)
/* Is the 40 MHz allowed for the current locale and specified band? */
bool wlc_valid_40chanspec_in_band(wlc_cm_info_t *wlc_cm, uint bandunit)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
return (((wlc_cm->bandstate[bandunit].
locale_flags & (WLC_NO_MIMO | WLC_NO_40MHZ)) == 0)
@@ -1162,7 +1172,7 @@ void
wlc_channel_set_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chanspec,
u8 local_constraint_qdbm)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
struct txpwr_limits txpwr;
wlc_channel_reg_limits(wlc_cm, chanspec, &txpwr);
@@ -1179,7 +1189,7 @@ int
wlc_channel_set_txpower_limit(wlc_cm_info_t *wlc_cm,
u8 local_constraint_qdbm)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
struct txpwr_limits txpwr;
wlc_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
@@ -1299,13 +1309,13 @@ void
wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec,
txpwr_limits_t *txpwr)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
uint i;
uint chan;
int maxpwr;
int delta;
const country_info_t *country;
- wlcband_t *band;
+ struct wlcband *band;
const locale_info_t *li;
int conducted_max;
int conducted_ofdm_max;
@@ -1314,7 +1324,7 @@ wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec,
int maxpwr_idx;
uint j;
- bzero(txpwr, sizeof(txpwr_limits_t));
+ memset(txpwr, 0, sizeof(txpwr_limits_t));
if (!wlc_valid_chanspec_db(wlc_cm, chanspec)) {
country = wlc_country_lookup(wlc, wlc->autocountry_default);
@@ -1528,13 +1538,13 @@ static bool wlc_japan_ccode(const char *ccode)
static bool
wlc_valid_chanspec_ext(wlc_cm_info_t *wlc_cm, chanspec_t chspec, bool dualband)
{
- wlc_info_t *wlc = wlc_cm->wlc;
+ struct wlc_info *wlc = wlc_cm->wlc;
u8 channel = CHSPEC_CHANNEL(chspec);
/* check the chanspec */
if (wf_chspec_malformed(chspec)) {
- WL_ERROR(("wl%d: malformed chanspec 0x%x\n", wlc->pub->unit,
- chspec));
+ WL_ERROR("wl%d: malformed chanspec 0x%x\n",
+ wlc->pub->unit, chspec);
ASSERT(0);
return false;
}
diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c
index 7e1bf0e2ecdd..dabd7094cd73 100644
--- a/drivers/staging/brcm80211/sys/wlc_event.c
+++ b/drivers/staging/brcm80211/sys/wlc_event.c
@@ -16,9 +16,13 @@
#include <linux/kernel.h>
#include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <wlioctl.h>
#include <wlc_cfg.h>
#include <wlc_pub.h>
@@ -32,6 +36,7 @@
#ifdef MSGTRACE
#include <msgtrace.h>
#endif
+#include <wl_dbg.h>
/* Local prototypes */
static void wlc_timer_cb(void *arg);
@@ -42,7 +47,7 @@ struct wlc_eventq {
wlc_event_t *tail;
struct wlc_info *wlc;
void *wl;
- wlc_pub_t *pub;
+ struct wlc_pub *pub;
bool tpending;
bool workpending;
struct wl_timer *timer;
@@ -53,7 +58,8 @@ struct wlc_eventq {
/*
* Export functions
*/
-wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc, void *wl,
+wlc_eventq_t *wlc_eventq_attach(struct wlc_pub *pub, struct wlc_info *wlc,
+ void *wl,
wlc_eventq_cb_t cb)
{
wlc_eventq_t *eq;
@@ -69,8 +75,8 @@ wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc, void *wl,
eq->timer = wl_init_timer(eq->wl, wlc_timer_cb, eq, "eventq");
if (!eq->timer) {
- WL_ERROR(("wl%d: wlc_eventq_attach: timer failed\n",
- pub->unit));
+ WL_ERROR("wl%d: wlc_eventq_attach: timer failed\n",
+ pub->unit);
kfree(eq);
return NULL;
}
diff --git a/drivers/staging/brcm80211/sys/wlc_event.h b/drivers/staging/brcm80211/sys/wlc_event.h
index e443dae258b7..e75582dcdd93 100644
--- a/drivers/staging/brcm80211/sys/wlc_event.h
+++ b/drivers/staging/brcm80211/sys/wlc_event.h
@@ -21,7 +21,8 @@ typedef struct wlc_eventq wlc_eventq_t;
typedef void (*wlc_eventq_cb_t) (void *arg);
-extern wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc,
+extern wlc_eventq_t *wlc_eventq_attach(struct wlc_pub *pub,
+ struct wlc_info *wlc,
void *wl, wlc_eventq_cb_t cb);
extern int wlc_eventq_detach(wlc_eventq_t *eq);
extern int wlc_eventq_down(wlc_eventq_t *eq);
@@ -38,7 +39,7 @@ extern int wlc_eventq_query_ind(wlc_eventq_t *eq, void *bitvect);
extern int wlc_eventq_test_ind(wlc_eventq_t *eq, int et);
extern int wlc_eventq_set_ind(wlc_eventq_t *eq, uint et, bool on);
extern void wlc_eventq_flush(wlc_eventq_t *eq);
-extern void wlc_assign_event_msg(wlc_info_t *wlc, wl_event_msg_t *msg,
+extern void wlc_assign_event_msg(struct wlc_info *wlc, wl_event_msg_t *msg,
const wlc_event_t *e, u8 *data,
u32 len);
diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c
index feaffcc64ec6..1d5d01ac0a9b 100644
--- a/drivers/staging/brcm80211/sys/wlc_mac80211.c
+++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c
@@ -15,9 +15,10 @@
*/
#include <linux/kernel.h>
#include <linux/ctype.h>
+#include <linux/etherdevice.h>
#include <bcmdefs.h>
+#include <bcmdevs.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmwifi.h>
@@ -27,7 +28,7 @@
#include <pcicfg.h>
#include <bcmsrom.h>
#include <wlioctl.h>
-#include <epivers.h>
+#include <sbhndpio.h>
#include <sbhnddma.h>
#include <hnddma.h>
#include <hndpmu.h>
@@ -37,6 +38,7 @@
#include <wlc_key.h>
#include <wlc_bsscfg.h>
#include <wlc_channel.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_bmac.h>
#include <wlc_scb.h>
@@ -47,27 +49,11 @@
#include <wlc_ampdu.h>
#include <wlc_event.h>
#include <wl_export.h>
-#ifdef BCMSDIO
-#include <bcmsdh.h>
-#else
#include "d11ucode_ext.h"
-#endif
-#ifdef WLC_HIGH_ONLY
-#include <bcm_rpc_tp.h>
-#include <bcm_rpc.h>
-#include <bcm_xdr.h>
-#include <wlc_rpc.h>
-#include <wlc_rpctx.h>
-#endif /* WLC_HIGH_ONLY */
#include <wlc_alloc.h>
#include <net/mac80211.h>
+#include <wl_dbg.h>
-#ifdef WLC_HIGH_ONLY
-#undef R_REG
-#undef W_REG
-#define R_REG(osh, r) RPC_READ_REG(osh, r)
-#define W_REG(osh, r, v) RPC_WRITE_REG(osh, r, v)
-#endif
/*
* buffer length needed for wlc_format_ssid
@@ -107,12 +93,8 @@
/* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */
#define BCMCFID(wlc, fid) wlc_bmac_write_shm((wlc)->hw, M_BCMC_FID, (fid))
-#ifndef WLC_HIGH_ONLY
-#define WLC_WAR16165(wlc) (BUSTYPE(wlc->pub->sih->bustype) == PCI_BUS && \
+#define WLC_WAR16165(wlc) (wlc->pub->sih->bustype == PCI_BUS && \
(!AP_ENAB(wlc->pub)) && (wlc->war16165))
-#else
-#define WLC_WAR16165(wlc) (false)
-#endif /* WLC_HIGH_ONLY */
/* debug/trace */
uint wl_msg_level =
@@ -135,9 +117,11 @@ uint wl_msg_level =
#define SCAN_IN_PROGRESS(x) 0
+#define EPI_VERSION_NUM 0x054b0b00
+
#ifdef BCMDBG
/* pointer to most recently allocated wl/wlc */
-static wlc_info_t *wlc_info_dbg = (wlc_info_t *) (NULL);
+static struct wlc_info *wlc_info_dbg = (struct wlc_info *) (NULL);
#endif
/* IOVar table */
@@ -238,91 +222,91 @@ static const u8 acbitmap2maxprio[] = {
#define WLC_REPLAY_CNTRS_VALUE WPA_CAP_16_REPLAY_CNTRS
/* local prototypes */
-extern void wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec);
-static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc,
- struct ieee80211_hw *hw, void *p,
+static u16 BCMFASTPATH wlc_d11hdrs_mac80211(struct wlc_info *wlc,
+ struct ieee80211_hw *hw,
+ struct sk_buff *p,
struct scb *scb, uint frag,
uint nfrags, uint queue,
uint next_frag_len,
wsec_key_t *key,
ratespec_t rspec_override);
-bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw);
-void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend);
-static void wlc_bss_default_init(wlc_info_t *wlc);
-static void wlc_ucode_mac_upd(wlc_info_t *wlc);
-static ratespec_t mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band,
- u32 int_val);
-static void wlc_tx_prec_map_init(wlc_info_t *wlc);
+
+static void wlc_bss_default_init(struct wlc_info *wlc);
+static void wlc_ucode_mac_upd(struct wlc_info *wlc);
+static ratespec_t mac80211_wlc_set_nrate(struct wlc_info *wlc,
+ struct wlcband *cur_band, u32 int_val);
+static void wlc_tx_prec_map_init(struct wlc_info *wlc);
static void wlc_watchdog(void *arg);
static void wlc_watchdog_by_timer(void *arg);
-static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg);
-static int wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val,
+static int wlc_set_rateset(struct wlc_info *wlc, wlc_rateset_t *rs_arg);
+static int wlc_iovar_rangecheck(struct wlc_info *wlc, u32 val,
const bcm_iovar_t *vi);
-static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc);
+static u8 wlc_local_constraint_qdbm(struct wlc_info *wlc);
/* send and receive */
-static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh);
-static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi);
-static void wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi,
+static wlc_txq_info_t *wlc_txq_alloc(struct wlc_info *wlc,
+ struct osl_info *osh);
+static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh,
+ wlc_txq_info_t *qi);
+static void wlc_txflowcontrol_signal(struct wlc_info *wlc, wlc_txq_info_t *qi,
bool on, int prio);
-static void wlc_txflowcontrol_reset(wlc_info_t *wlc);
-static u16 wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec,
+static void wlc_txflowcontrol_reset(struct wlc_info *wlc);
+static u16 wlc_compute_airtime(struct wlc_info *wlc, ratespec_t rspec,
uint length);
static void wlc_compute_cck_plcp(ratespec_t rate, uint length, u8 *plcp);
static void wlc_compute_ofdm_plcp(ratespec_t rate, uint length, u8 *plcp);
static void wlc_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp);
-static u16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate,
+static u16 wlc_compute_frame_dur(struct wlc_info *wlc, ratespec_t rate,
u8 preamble_type, uint next_frag_len);
-static void wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh,
- void *p);
-static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate,
+static void wlc_recvctl(struct wlc_info *wlc, struct osl_info *osh,
+ d11rxhdr_t *rxh, struct sk_buff *p);
+static uint wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t rate,
u8 preamble_type, uint dur);
-static uint wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rate,
+static uint wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rate,
u8 preamble_type);
-static uint wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rate,
+static uint wlc_calc_cts_time(struct wlc_info *wlc, ratespec_t rate,
u8 preamble_type);
/* interrupt, up/down, band */
-static void wlc_setband(wlc_info_t *wlc, uint bandunit);
-static chanspec_t wlc_init_chanspec(wlc_info_t *wlc);
-static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec);
-static void wlc_bsinit(wlc_info_t *wlc);
-static int wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
+static void wlc_setband(struct wlc_info *wlc, uint bandunit);
+static chanspec_t wlc_init_chanspec(struct wlc_info *wlc);
+static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec);
+static void wlc_bsinit(struct wlc_info *wlc);
+static int wlc_duty_cycle_set(struct wlc_info *wlc, int duty_cycle, bool isOFDM,
bool writeToShm);
-static void wlc_radio_hwdisable_upd(wlc_info_t *wlc);
-static bool wlc_radio_monitor_start(wlc_info_t *wlc);
+static void wlc_radio_hwdisable_upd(struct wlc_info *wlc);
+static bool wlc_radio_monitor_start(struct wlc_info *wlc);
static void wlc_radio_timer(void *arg);
-static void wlc_radio_enable(wlc_info_t *wlc);
-static void wlc_radio_upd(wlc_info_t *wlc);
+static void wlc_radio_enable(struct wlc_info *wlc);
+static void wlc_radio_upd(struct wlc_info *wlc);
/* scan, association, BSS */
-static uint wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rate,
+static uint wlc_calc_ba_time(struct wlc_info *wlc, ratespec_t rate,
u8 preamble_type);
-static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap);
-static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val);
-void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode);
-static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val);
-static void wlc_war16165(wlc_info_t *wlc, bool tx);
+static void wlc_update_mimo_band_bwcap(struct wlc_info *wlc, u8 bwcap);
+static void wlc_ht_update_sgi_rx(struct wlc_info *wlc, int val);
+static void wlc_ht_update_ldpc(struct wlc_info *wlc, s8 val);
+static void wlc_war16165(struct wlc_info *wlc, bool tx);
static void wlc_process_eventq(void *arg);
-static void wlc_wme_retries_write(wlc_info_t *wlc);
-static bool wlc_attach_stf_ant_init(wlc_info_t *wlc);
-static uint wlc_attach_module(wlc_info_t *wlc);
-static void wlc_detach_module(wlc_info_t *wlc);
-static void wlc_timers_deinit(wlc_info_t *wlc);
-static void wlc_down_led_upd(wlc_info_t *wlc);
-static uint wlc_down_del_timer(wlc_info_t *wlc);
-static void wlc_ofdm_rateset_war(wlc_info_t *wlc);
-static int _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len,
+static void wlc_wme_retries_write(struct wlc_info *wlc);
+static bool wlc_attach_stf_ant_init(struct wlc_info *wlc);
+static uint wlc_attach_module(struct wlc_info *wlc);
+static void wlc_detach_module(struct wlc_info *wlc);
+static void wlc_timers_deinit(struct wlc_info *wlc);
+static void wlc_down_led_upd(struct wlc_info *wlc);
+static uint wlc_down_del_timer(struct wlc_info *wlc);
+static void wlc_ofdm_rateset_war(struct wlc_info *wlc);
+static int _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len,
struct wlc_if *wlcif);
#if defined(BCMDBG)
-void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr)
+void wlc_get_rcmta(struct wlc_info *wlc, int idx, struct ether_addr *addr)
{
d11regs_t *regs = wlc->regs;
u32 v32;
- osl_t *osh;
+ struct osl_info *osh;
- WL_TRACE(("wl%d: %s\n", WLCWLUNIT(wlc), __func__));
+ WL_TRACE("wl%d: %s\n", WLCWLUNIT(wlc), __func__);
ASSERT(wlc->pub->corerev > 4);
@@ -344,14 +328,14 @@ void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr)
#endif /* defined(BCMDBG) */
/* keep the chip awake if needed */
-bool wlc_stay_awake(wlc_info_t *wlc)
+bool wlc_stay_awake(struct wlc_info *wlc)
{
return true;
}
/* conditions under which the PM bit should be set in outgoing frames and STAY_AWAKE is meaningful
*/
-bool wlc_ps_allowed(wlc_info_t *wlc)
+bool wlc_ps_allowed(struct wlc_info *wlc)
{
int idx;
wlc_bsscfg_t *cfg;
@@ -378,9 +362,9 @@ bool wlc_ps_allowed(wlc_info_t *wlc)
return true;
}
-void wlc_reset(wlc_info_t *wlc)
+void wlc_reset(struct wlc_info *wlc)
{
- WL_TRACE(("wl%d: wlc_reset\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_reset\n", wlc->pub->unit);
wlc->check_for_unaligned_tbtt = false;
@@ -389,34 +373,19 @@ void wlc_reset(wlc_info_t *wlc)
wlc_statsupd(wlc);
/* reset our snapshot of macstat counters */
- bzero((char *)wlc->core->macstat_snapshot, sizeof(macstat_t));
+ memset((char *)wlc->core->macstat_snapshot, 0,
+ sizeof(macstat_t));
}
wlc_bmac_reset(wlc->hw);
wlc_ampdu_reset(wlc->ampdu);
wlc->txretried = 0;
-#ifdef WLC_HIGH_ONLY
- /* Need to set a flag(to be cleared asynchronously by BMAC driver with high call)
- * in order to prevent wlc_rpctx_txreclaim() from screwing wlc_rpctx_getnexttxp(),
- * which could be invoked by already QUEUED high call(s) from BMAC driver before
- * wlc_bmac_reset() finishes.
- * It's not needed before in monolithic driver model because d11core interrupts would
- * have been cleared instantly in wlc_bmac_reset() and no txstatus interrupt
- * will come to driver to fetch those flushed dma pkt pointers.
- */
- wlc->reset_bmac_pending = true;
-
- wlc_rpctx_txreclaim(wlc->rpctx);
-
- wlc_stf_phy_txant_upd(wlc);
- wlc_phy_ant_rxdiv_set(wlc->band->pi, wlc->stf->ant_rx_ovr);
-#endif
}
-void wlc_fatal_error(wlc_info_t *wlc)
+void wlc_fatal_error(struct wlc_info *wlc)
{
- WL_ERROR(("wl%d: fatal error, reinitializing\n", wlc->pub->unit));
+ WL_ERROR("wl%d: fatal error, reinitializing\n", wlc->pub->unit);
wl_init(wlc->wl);
}
@@ -425,7 +394,7 @@ void wlc_fatal_error(wlc_info_t *wlc)
* if other configurations are in conflict (bandlocked, 11n mode disabled,
* invalid channel for current country, etc.)
*/
-static chanspec_t wlc_init_chanspec(wlc_info_t *wlc)
+static chanspec_t wlc_init_chanspec(struct wlc_info *wlc)
{
chanspec_t chanspec =
1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
@@ -441,7 +410,7 @@ static chanspec_t wlc_init_chanspec(wlc_info_t *wlc)
struct scb global_scb;
-static void wlc_init_scb(wlc_info_t *wlc, struct scb *scb)
+static void wlc_init_scb(struct wlc_info *wlc, struct scb *scb)
{
int i;
scb->flags = SCB_WMECAP | SCB_HTCAP;
@@ -449,7 +418,7 @@ static void wlc_init_scb(wlc_info_t *wlc, struct scb *scb)
scb->seqnum[i] = 0;
}
-void wlc_init(wlc_info_t *wlc)
+void wlc_init(struct wlc_info *wlc)
{
d11regs_t *regs;
chanspec_t chanspec;
@@ -457,7 +426,7 @@ void wlc_init(wlc_info_t *wlc)
wlc_bsscfg_t *bsscfg;
bool mute = false;
- WL_TRACE(("wl%d: wlc_init\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_init\n", wlc->pub->unit);
regs = wlc->regs;
@@ -583,13 +552,13 @@ void wlc_init(wlc_info_t *wlc)
}
}
-void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc)
+void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc)
{
wlc->bcnmisc_monitor = promisc;
wlc_mac_bcn_promisc(wlc);
}
-void wlc_mac_bcn_promisc(wlc_info_t *wlc)
+void wlc_mac_bcn_promisc(struct wlc_info *wlc)
{
if ((AP_ENAB(wlc->pub) && (N_ENAB(wlc->pub) || wlc->band->gmode)) ||
wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor)
@@ -599,7 +568,7 @@ void wlc_mac_bcn_promisc(wlc_info_t *wlc)
}
/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
-void wlc_mac_promisc(wlc_info_t *wlc)
+void wlc_mac_promisc(struct wlc_info *wlc)
{
u32 promisc_bits = 0;
@@ -621,7 +590,7 @@ void wlc_mac_promisc(wlc_info_t *wlc)
}
/* check if hps and wake states of sw and hw are in sync */
-bool wlc_ps_check(wlc_info_t *wlc)
+bool wlc_ps_check(struct wlc_info *wlc)
{
bool res = true;
bool hps, wake;
@@ -636,8 +605,8 @@ bool wlc_ps_check(wlc_info_t *wlc)
* to avoid assert
*/
if (tmp == 0xffffffff) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit,
- __func__));
+ WL_ERROR("wl%d: %s: dead chip\n",
+ wlc->pub->unit, __func__);
return DEVICEREMOVED(wlc);
}
@@ -646,7 +615,8 @@ bool wlc_ps_check(wlc_info_t *wlc)
if (hps != ((tmp & MCTL_HPS) != 0)) {
int idx;
wlc_bsscfg_t *cfg;
- WL_ERROR(("wl%d: hps not sync, sw %d, maccontrol 0x%x\n", wlc->pub->unit, hps, tmp));
+ WL_ERROR("wl%d: hps not sync, sw %d, maccontrol 0x%x\n",
+ wlc->pub->unit, hps, tmp);
FOREACH_BSS(wlc, idx, cfg) {
if (!BSSCFG_STA(cfg))
continue;
@@ -654,23 +624,14 @@ bool wlc_ps_check(wlc_info_t *wlc)
res = false;
}
-#ifdef WLC_LOW
/* For a monolithic build the wake check can be exact since it looks at wake
* override bits. The MCTL_WAKE bit should match the 'wake' value.
*/
wake = STAY_AWAKE(wlc) || wlc->hw->wake_override;
wake_ok = (wake == ((tmp & MCTL_WAKE) != 0));
-#else
- /* For a split build we will not have access to any wake overrides from the low
- * level. The check can only make sure the MCTL_WAKE bit is on if the high
- * level 'wake' value is true. If the high level 'wake' is false, the MCTL_WAKE
- * may be either true or false due to the low level override.
- */
- wake = STAY_AWAKE(wlc);
- wake_ok = (wake && ((tmp & MCTL_WAKE) != 0)) || !wake;
-#endif
if (hps && !wake_ok) {
- WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp));
+ WL_ERROR("wl%d: wake not sync, sw %d maccontrol 0x%x\n",
+ wlc->pub->unit, wake, tmp);
res = false;
}
}
@@ -679,7 +640,7 @@ bool wlc_ps_check(wlc_info_t *wlc)
}
/* push sw hps and wake state through hardware */
-void wlc_set_ps_ctrl(wlc_info_t *wlc)
+void wlc_set_ps_ctrl(struct wlc_info *wlc)
{
u32 v1, v2;
bool hps, wake;
@@ -688,8 +649,8 @@ void wlc_set_ps_ctrl(wlc_info_t *wlc)
hps = PS_ALLOWED(wlc);
wake = hps ? (STAY_AWAKE(wlc)) : true;
- WL_TRACE(("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n", wlc->pub->unit,
- hps, wake));
+ WL_TRACE("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n",
+ wlc->pub->unit, hps, wake);
v1 = R_REG(wlc->osh, &wlc->regs->maccontrol);
v2 = 0;
@@ -714,7 +675,7 @@ void wlc_set_ps_ctrl(wlc_info_t *wlc)
int wlc_set_mac(wlc_bsscfg_t *cfg)
{
int err = 0;
- wlc_info_t *wlc = cfg->wlc;
+ struct wlc_info *wlc = cfg->wlc;
if (cfg == wlc->cfg) {
/* enter the MAC addr into the RXE match registers */
@@ -731,7 +692,7 @@ int wlc_set_mac(wlc_bsscfg_t *cfg)
*/
void wlc_set_bssid(wlc_bsscfg_t *cfg)
{
- wlc_info_t *wlc = cfg->wlc;
+ struct wlc_info *wlc = cfg->wlc;
/* if primary config, we need to update BSSID in RXE match registers */
if (cfg == wlc->cfg) {
@@ -748,7 +709,7 @@ void wlc_set_bssid(wlc_bsscfg_t *cfg)
* Suspend the the MAC and update the slot timing
* for standard 11b/g (20us slots) or shortslot 11g (9us slots).
*/
-void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot)
+void wlc_switch_shortslot(struct wlc_info *wlc, bool shortslot)
{
int idx;
wlc_bsscfg_t *cfg;
@@ -776,7 +737,7 @@ void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot)
wlc_bmac_set_shortslot(wlc->hw, shortslot);
}
-static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc)
+static u8 wlc_local_constraint_qdbm(struct wlc_info *wlc)
{
u8 local;
s16 local_max;
@@ -803,7 +764,7 @@ static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc)
}
/* propagate home chanspec to all bsscfgs in case bsscfg->current_bss->chanspec is referenced */
-void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
+void wlc_set_home_chanspec(struct wlc_info *wlc, chanspec_t chanspec)
{
if (wlc->home_chanspec != chanspec) {
int idx;
@@ -821,7 +782,7 @@ void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
}
}
-static void wlc_set_phy_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
+static void wlc_set_phy_chanspec(struct wlc_info *wlc, chanspec_t chanspec)
{
/* Save our copy of the chanspec */
wlc->chanspec = chanspec;
@@ -840,15 +801,15 @@ static void wlc_set_phy_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
}
-void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
+void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec)
{
uint bandunit;
bool switchband = false;
chanspec_t old_chanspec = wlc->chanspec;
if (!wlc_valid_chanspec_db(wlc->cmi, chanspec)) {
- WL_ERROR(("wl%d: %s: Bad channel %d\n",
- wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)));
+ WL_ERROR("wl%d: %s: Bad channel %d\n",
+ wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));
ASSERT(wlc_valid_chanspec_db(wlc->cmi, chanspec));
return;
}
@@ -859,7 +820,9 @@ void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
switchband = true;
if (wlc->bandlocked) {
- WL_ERROR(("wl%d: %s: chspec %d band is locked!\n", wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)));
+ WL_ERROR("wl%d: %s: chspec %d band is locked!\n",
+ wlc->pub->unit, __func__,
+ CHSPEC_CHANNEL(chanspec));
return;
}
/* BMAC_NOTE: should the setband call come after the wlc_bmac_chanspec() ?
@@ -895,7 +858,7 @@ void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec)
}
#if defined(BCMDBG)
-static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len)
+static int wlc_get_current_txpwr(struct wlc_info *wlc, void *pwr, uint len)
{
txpwr_limits_t txpwr;
tx_power_t power;
@@ -909,7 +872,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len)
else if (len < sizeof(tx_power_t))
return BCME_BUFTOOSHORT;
- bzero(&power, sizeof(tx_power_t));
+ memset(&power, 0, sizeof(tx_power_t));
power.chanspec = WLC_BAND_PI_RADIO_CHANSPEC;
if (wlc->pub->associated)
@@ -1031,7 +994,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len)
} else {
int band_idx = CHSPEC_IS2G(power.chanspec) ? 0 : 1;
- bzero(old_power, sizeof(tx_power_legacy_t));
+ memset(old_power, 0, sizeof(tx_power_legacy_t));
old_power->txpwr_local_max = power.local_max;
old_power->txpwr_local_constraint = power.local_constraint;
@@ -1064,7 +1027,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len)
}
#endif /* defined(BCMDBG) */
-static u32 wlc_watchdog_backup_bi(wlc_info_t *wlc)
+static u32 wlc_watchdog_backup_bi(struct wlc_info *wlc)
{
u32 bi;
bi = 2 * wlc->cfg->current_bss->dtim_period *
@@ -1083,7 +1046,7 @@ static u32 wlc_watchdog_backup_bi(wlc_info_t *wlc)
/* Change to run the watchdog either from a periodic timer or from tbtt handler.
* Call watchdog from tbtt handler if tbtt is true, watchdog timer otherwise.
*/
-void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt)
+void wlc_watchdog_upd(struct wlc_info *wlc, bool tbtt)
{
/* make sure changing watchdog driver is allowed */
if (!wlc->pub->up || !wlc->pub->align_wd_tbtt)
@@ -1112,7 +1075,7 @@ void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt)
}
}
-ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs)
+ratespec_t wlc_lowest_basic_rspec(struct wlc_info *wlc, wlc_rateset_t *rs)
{
ratespec_t lowest_basic_rspec;
uint i;
@@ -1140,7 +1103,7 @@ ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs)
* ratespec CCK ant = wlc->stf->txant
* OFDM ant = 3
*/
-void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, ratespec_t bcn_rspec)
+void wlc_beacon_phytxctl_txant_upd(struct wlc_info *wlc, ratespec_t bcn_rspec)
{
u16 phyctl;
u16 phytxant = wlc->stf->phytxant;
@@ -1159,9 +1122,9 @@ void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, ratespec_t bcn_rspec)
/* centralized protection config change function to simplify debugging, no consistency checking
* this should be called only on changes to avoid overhead in periodic function
*/
-void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val)
+void wlc_protection_upd(struct wlc_info *wlc, uint idx, int val)
{
- WL_TRACE(("wlc_protection_upd: idx %d, val %d\n", idx, val));
+ WL_TRACE("wlc_protection_upd: idx %d, val %d\n", idx, val);
switch (idx) {
case WLC_PROT_G_SPEC:
@@ -1205,7 +1168,7 @@ void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val)
}
-static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val)
+static void wlc_ht_update_sgi_rx(struct wlc_info *wlc, int val)
{
wlc->ht_cap.cap &= ~(HT_CAP_SHORT_GI_20 | HT_CAP_SHORT_GI_40);
wlc->ht_cap.cap |= (val & WLC_N_SGI_20) ? HT_CAP_SHORT_GI_20 : 0;
@@ -1217,7 +1180,7 @@ static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val)
}
}
-static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val)
+static void wlc_ht_update_ldpc(struct wlc_info *wlc, s8 val)
{
wlc->stf->ldpc = val;
@@ -1236,7 +1199,7 @@ static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val)
* ucode, hwmac update
* Channel dependent updates for ucode and hw
*/
-static void wlc_ucode_mac_upd(wlc_info_t *wlc)
+static void wlc_ucode_mac_upd(struct wlc_info *wlc)
{
/* enable or disable any active IBSSs depending on whether or not
* we are on the home channel
@@ -1263,13 +1226,13 @@ static void wlc_ucode_mac_upd(wlc_info_t *wlc)
wlc_mac_promisc(wlc);
}
-static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec)
+static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec)
{
wlc_rateset_t default_rateset;
uint parkband;
uint i, band_order[2];
- WL_TRACE(("wl%d: wlc_bandinit_ordered\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_bandinit_ordered\n", wlc->pub->unit);
/*
* We might have been bandlocked during down and the chip power-cycled (hibernate).
* figure out the right band to park on
@@ -1310,10 +1273,10 @@ static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec)
}
/* band-specific init */
-static void WLBANDINITFN(wlc_bsinit) (wlc_info_t *wlc)
+static void WLBANDINITFN(wlc_bsinit) (struct wlc_info *wlc)
{
- WL_TRACE(("wl%d: wlc_bsinit: bandunit %d\n", wlc->pub->unit,
- wlc->band->bandunit));
+ WL_TRACE("wl%d: wlc_bsinit: bandunit %d\n",
+ wlc->pub->unit, wlc->band->bandunit);
/* write ucode ACK/CTS rate table */
wlc_set_ratetable(wlc);
@@ -1328,7 +1291,7 @@ static void WLBANDINITFN(wlc_bsinit) (wlc_info_t *wlc)
}
/* switch to and initialize new band */
-static void WLBANDINITFN(wlc_setband) (wlc_info_t *wlc, uint bandunit)
+static void WLBANDINITFN(wlc_setband) (struct wlc_info *wlc, uint bandunit)
{
int idx;
wlc_bsscfg_t *cfg;
@@ -1353,7 +1316,7 @@ static void WLBANDINITFN(wlc_setband) (wlc_info_t *wlc, uint bandunit)
}
/* Initialize a WME Parameter Info Element with default STA parameters from WMM Spec, Table 12 */
-void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe)
+void wlc_wme_initparams_sta(struct wlc_info *wlc, wme_param_ie_t *pe)
{
static const wme_param_ie_t stadef = {
WME_OUI,
@@ -1378,7 +1341,7 @@ void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe)
memcpy(pe, &stadef, sizeof(*pe));
}
-void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
+void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend)
{
int i;
shm_acparams_t acp_shm;
@@ -1389,7 +1352,7 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
/* Only apply params if the core is out of reset and has clocks */
if (!wlc->clk) {
- WL_ERROR(("wl%d: %s : no-clock\n", wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s : no-clock\n", wlc->pub->unit, __func__);
return;
}
@@ -1402,7 +1365,7 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
wlc->wme_admctl = 0;
do {
- bzero((char *)&acp_shm, sizeof(shm_acparams_t));
+ memset((char *)&acp_shm, 0, sizeof(shm_acparams_t));
/* find out which ac this set of params applies to */
ASSERT(aci < AC_COUNT);
/* set the admission control policy for this AC */
@@ -1421,8 +1384,8 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
if (acp_shm.aifs < EDCF_AIFSN_MIN
|| acp_shm.aifs > EDCF_AIFSN_MAX) {
- WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n",
- wlc->pub->unit, acp_shm.aifs));
+ WL_ERROR("wl%d: wlc_edcf_setparams: bad aifs %d\n",
+ wlc->pub->unit, acp_shm.aifs);
continue;
}
@@ -1459,7 +1422,7 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend)
void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend)
{
- wlc_info_t *wlc = cfg->wlc;
+ struct wlc_info *wlc = cfg->wlc;
uint aci, i, j;
edcf_acparam_t *edcf_acp;
shm_acparams_t acp_shm;
@@ -1483,7 +1446,7 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend)
wlc->wme_admctl = 0;
for (i = 0; i < AC_COUNT; i++, edcf_acp++) {
- bzero((char *)&acp_shm, sizeof(shm_acparams_t));
+ memset((char *)&acp_shm, 0, sizeof(shm_acparams_t));
/* find out which ac this set of params applies to */
aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
ASSERT(aci < AC_COUNT);
@@ -1505,8 +1468,8 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend)
if (acp_shm.aifs < EDCF_AIFSN_MIN
|| acp_shm.aifs > EDCF_AIFSN_MAX) {
- WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n",
- wlc->pub->unit, acp_shm.aifs));
+ WL_ERROR("wl%d: wlc_edcf_setparams: bad aifs %d\n",
+ wlc->pub->unit, acp_shm.aifs);
continue;
}
@@ -1548,20 +1511,19 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend)
}
-bool wlc_timers_init(wlc_info_t *wlc, int unit)
+bool wlc_timers_init(struct wlc_info *wlc, int unit)
{
wlc->wdtimer = wl_init_timer(wlc->wl, wlc_watchdog_by_timer,
wlc, "watchdog");
if (!wlc->wdtimer) {
- WL_ERROR(("wl%d: wl_init_timer for wdtimer failed\n", unit));
+ WL_ERROR("wl%d: wl_init_timer for wdtimer failed\n", unit);
goto fail;
}
wlc->radio_timer = wl_init_timer(wlc->wl, wlc_radio_timer,
wlc, "radio");
if (!wlc->radio_timer) {
- WL_ERROR(("wl%d: wl_init_timer for radio_timer failed\n",
- unit));
+ WL_ERROR("wl%d: wl_init_timer for radio_timer failed\n", unit);
goto fail;
}
@@ -1575,7 +1537,7 @@ bool wlc_timers_init(wlc_info_t *wlc, int unit)
* Initialize wlc_info default values ...
* may get overrides later in this function
*/
-void wlc_info_init(wlc_info_t *wlc, int unit)
+void wlc_info_init(struct wlc_info *wlc, int unit)
{
int i;
/* Assume the device is there until proven otherwise */
@@ -1686,7 +1648,7 @@ void wlc_info_init(wlc_info_t *wlc, int unit)
wlc->pr80838_war = true;
}
-static bool wlc_state_bmac_sync(wlc_info_t *wlc)
+static bool wlc_state_bmac_sync(struct wlc_info *wlc)
{
wlc_bmac_state_t state_bmac;
@@ -1700,7 +1662,7 @@ static bool wlc_state_bmac_sync(wlc_info_t *wlc)
return true;
}
-static uint wlc_attach_module(wlc_info_t *wlc)
+static uint wlc_attach_module(struct wlc_info *wlc)
{
uint err = 0;
uint unit;
@@ -1708,15 +1670,14 @@ static uint wlc_attach_module(wlc_info_t *wlc)
wlc->asi = wlc_antsel_attach(wlc, wlc->osh, wlc->pub, wlc->hw);
if (wlc->asi == NULL) {
- WL_ERROR(("wl%d: wlc_attach: wlc_antsel_attach failed\n",
- unit));
+ WL_ERROR("wl%d: wlc_attach: wlc_antsel_attach failed\n", unit);
err = 44;
goto fail;
}
wlc->ampdu = wlc_ampdu_attach(wlc);
if (wlc->ampdu == NULL) {
- WL_ERROR(("wl%d: wlc_attach: wlc_ampdu_attach failed\n", unit));
+ WL_ERROR("wl%d: wlc_attach: wlc_ampdu_attach failed\n", unit);
err = 50;
goto fail;
}
@@ -1725,13 +1686,13 @@ static uint wlc_attach_module(wlc_info_t *wlc)
wlc->eventq =
wlc_eventq_attach(wlc->pub, wlc, wlc->wl, wlc_process_eventq);
if (wlc->eventq == NULL) {
- WL_ERROR(("wl%d: wlc_attach: wlc_eventq_attachfailed\n", unit));
+ WL_ERROR("wl%d: wlc_attach: wlc_eventq_attachfailed\n", unit);
err = 57;
goto fail;
}
if ((wlc_stf_attach(wlc) != 0)) {
- WL_ERROR(("wl%d: wlc_attach: wlc_stf_attach failed\n", unit));
+ WL_ERROR("wl%d: wlc_attach: wlc_stf_attach failed\n", unit);
err = 68;
goto fail;
}
@@ -1739,9 +1700,9 @@ static uint wlc_attach_module(wlc_info_t *wlc)
return err;
}
-wlc_pub_t *wlc_pub(void *wlc)
+struct wlc_pub *wlc_pub(void *wlc)
{
- return ((wlc_info_t *) wlc)->pub;
+ return ((struct wlc_info *) wlc)->pub;
}
#define CHIP_SUPPORTS_11N(wlc) 1
@@ -1750,25 +1711,25 @@ wlc_pub_t *wlc_pub(void *wlc)
* The common driver entry routine. Error codes should be unique
*/
void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
- osl_t *osh, void *regsva, uint bustype, void *btparam,
- uint *perr)
+ struct osl_info *osh, void *regsva, uint bustype,
+ void *btparam, uint *perr)
{
- wlc_info_t *wlc;
+ struct wlc_info *wlc;
uint err = 0;
uint j;
- wlc_pub_t *pub;
+ struct wlc_pub *pub;
wlc_txq_info_t *qi;
uint n_disabled;
- WL_NONE(("wl%d: %s: vendor 0x%x device 0x%x\n", unit, __func__, vendor,
- device));
+ WL_NONE("wl%d: %s: vendor 0x%x device 0x%x\n",
+ unit, __func__, vendor, device);
ASSERT(WSEC_MAX_RCMTA_KEYS <= WSEC_MAX_KEYS);
ASSERT(WSEC_MAX_DEFAULT_KEYS == WLC_DEFAULT_KEYS);
/* some code depends on packed structures */
- ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN);
- ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN);
+ ASSERT(sizeof(struct ether_addr) == ETH_ALEN);
+ ASSERT(sizeof(struct ether_header) == ETH_HLEN);
ASSERT(sizeof(d11regs_t) == SI_CORE_SIZE);
ASSERT(sizeof(ofdm_phy_hdr_t) == D11_PHY_HDR_LEN);
ASSERT(sizeof(cck_phy_hdr_t) == D11_PHY_HDR_LEN);
@@ -1780,8 +1741,10 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
ASSERT(sizeof(struct dot11_bcn_prb) == DOT11_BCN_PRB_LEN);
ASSERT(sizeof(tx_status_t) == TXSTATUS_LEN);
ASSERT(sizeof(ht_cap_ie_t) == HT_CAP_IE_LEN);
+#ifdef BRCM_FULLMAC
ASSERT(offsetof(wl_scan_params_t, channel_list) ==
WL_SCAN_PARAMS_FIXED_SIZE);
+#endif
ASSERT(IS_ALIGNED(offsetof(wsec_key_t, data), sizeof(u32)));
ASSERT(ISPOWEROF2(MA_WINDOW_SZ));
@@ -1797,8 +1760,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
|| (WPA_CAP_4_REPLAY_CNTRS == WLC_REPLAY_CNTRS_VALUE
&& 4 == WLC_NUMRXIVS));
- /* allocate wlc_info_t state and its substructures */
- wlc = (wlc_info_t *) wlc_attach_malloc(osh, unit, &err, device);
+ /* allocate struct wlc_info state and its substructures */
+ wlc = (struct wlc_info *) wlc_attach_malloc(osh, unit, &err, device);
if (wlc == NULL)
goto fail;
wlc->osh = osh;
@@ -1819,7 +1782,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
/* By default restrict TKIP associations from 11n STA's */
wlc->ht_wsec_restriction = WLC_HT_TKIP_RESTRICT;
- /* populate wlc_info_t with default values */
+ /* populate struct wlc_info with default values */
wlc_info_init(wlc, unit);
/* update sta/ap related parameters */
@@ -1851,10 +1814,6 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
/* propagate *vars* from BMAC driver to high driver */
wlc_bmac_copyfrom_vars(wlc->hw, &pub->vars, &wlc->vars_size);
-#ifdef WLC_HIGH_ONLY
- WL_TRACE(("nvram : vars %p , vars_size %d\n", pub->vars,
- wlc->vars_size));
-#endif
/* set maximum allowed duty cycle */
wlc->tx_duty_cycle_ofdm =
@@ -1872,19 +1831,17 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
wlc->stf->hw_rxchain);
-#ifdef WLC_LOW
/* pull up some info resulting from the low attach */
{
int i;
for (i = 0; i < NFIFO; i++)
wlc->core->txavail[i] = wlc->hw->txavail[i];
}
-#endif /* WLC_LOW */
wlc_bmac_hw_etheraddr(wlc->hw, &wlc->perm_etheraddr);
bcopy((char *)&wlc->perm_etheraddr, (char *)&pub->cur_etheraddr,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
for (j = 0; j < NBANDS(wlc); j++) {
/* Use band 1 for single band 11a */
@@ -1942,7 +1899,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
goto fail;
if (!wlc_timers_init(wlc, unit)) {
- WL_ERROR(("wl%d: %s: wlc_init_timer failed\n", unit, __func__));
+ WL_ERROR("wl%d: %s: wlc_init_timer failed\n", unit, __func__);
err = 32;
goto fail;
}
@@ -1950,8 +1907,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
/* depend on rateset, gmode */
wlc->cmi = wlc_channel_mgr_attach(wlc);
if (!wlc->cmi) {
- WL_ERROR(("wl%d: %s: wlc_channel_mgr_attach failed\n", unit,
- __func__));
+ WL_ERROR("wl%d: %s: wlc_channel_mgr_attach failed\n",
+ unit, __func__);
err = 33;
goto fail;
}
@@ -1966,8 +1923,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
/* allocate our initial queue */
qi = wlc_txq_alloc(wlc, osh);
if (qi == NULL) {
- WL_ERROR(("wl%d: %s: failed to malloc tx queue\n", unit,
- __func__));
+ WL_ERROR("wl%d: %s: failed to malloc tx queue\n",
+ unit, __func__);
err = 100;
goto fail;
}
@@ -2037,7 +1994,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
wlc_radio_mpc_upd(wlc);
if (WLANTSEL_ENAB(wlc)) {
- if ((CHIPID(wlc->pub->sih->chip)) == BCM43235_CHIP_ID) {
+ if ((wlc->pub->sih->chip) == BCM43235_CHIP_ID) {
if ((getintvar(wlc->pub->vars, "aa2g") == 7) ||
(getintvar(wlc->pub->vars, "aa5g") == 7)) {
wlc_bmac_antsel_set(wlc->hw, 1);
@@ -2053,7 +2010,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
return (void *)wlc;
fail:
- WL_ERROR(("wl%d: %s: failed with err %d\n", unit, __func__, err));
+ WL_ERROR("wl%d: %s: failed with err %d\n", unit, __func__, err);
if (wlc)
wlc_detach(wlc);
@@ -2062,7 +2019,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
return NULL;
}
-static void wlc_attach_antgain_init(wlc_info_t *wlc)
+static void wlc_attach_antgain_init(struct wlc_info *wlc)
{
uint unit;
unit = wlc->pub->unit;
@@ -2071,7 +2028,8 @@ static void wlc_attach_antgain_init(wlc_info_t *wlc)
/* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
wlc->band->antgain = 8;
} else if (wlc->band->antgain == -1) {
- WL_ERROR(("wl%d: %s: Invalid antennas available in srom, using 2dB\n", unit, __func__));
+ WL_ERROR("wl%d: %s: Invalid antennas available in srom, using 2dB\n",
+ unit, __func__);
wlc->band->antgain = 8;
} else {
s8 gain, fract;
@@ -2093,7 +2051,7 @@ static void wlc_attach_antgain_init(wlc_info_t *wlc)
}
}
-static bool wlc_attach_stf_ant_init(wlc_info_t *wlc)
+static bool wlc_attach_stf_ant_init(struct wlc_info *wlc)
{
int aa;
uint unit;
@@ -2110,7 +2068,8 @@ static bool wlc_attach_stf_ant_init(wlc_info_t *wlc)
aa = (s8) getintvar(vars,
(BAND_5G(bandtype) ? "aa1" : "aa0"));
if ((aa < 1) || (aa > 15)) {
- WL_ERROR(("wl%d: %s: Invalid antennas available in srom (0x%x), using 3.\n", unit, __func__, aa));
+ WL_ERROR("wl%d: %s: Invalid antennas available in srom (0x%x), using 3\n",
+ unit, __func__, aa);
aa = 3;
}
@@ -2132,136 +2091,8 @@ static bool wlc_attach_stf_ant_init(wlc_info_t *wlc)
return true;
}
-#ifdef WLC_HIGH_ONLY
-/* HIGH_ONLY bmac_attach, which sync over LOW_ONLY bmac_attach states */
-int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit,
- bool piomode, osl_t *osh, void *regsva, uint bustype,
- void *btparam)
-{
- wlc_bmac_revinfo_t revinfo;
- uint idx = 0;
- rpc_info_t *rpc = (rpc_info_t *) btparam;
- ASSERT(bustype == RPC_BUS);
-
- /* install the rpc handle in the various state structures used by stub RPC functions */
- wlc->rpc = rpc;
- wlc->hw->rpc = rpc;
- wlc->hw->osh = osh;
-
- wlc->regs = 0;
-
- wlc->rpctx = wlc_rpctx_attach(wlc->pub, wlc);
- if (wlc->rpctx == NULL)
- return -1;
-
- /*
- * FIFO 0
- * TX: TX_AC_BK_FIFO (TX AC Background data packets)
- */
- /* Always initialized */
- ASSERT(NRPCTXBUFPOST <= NTXD);
- wlc_rpctx_fifoinit(wlc->rpctx, TX_DATA_FIFO, NRPCTXBUFPOST);
- wlc_rpctx_fifoinit(wlc->rpctx, TX_CTL_FIFO, NRPCTXBUFPOST);
- wlc_rpctx_fifoinit(wlc->rpctx, TX_BCMC_FIFO, NRPCTXBUFPOST);
-
- /* VI and BK inited only if WME */
- if (WME_ENAB(wlc->pub)) {
- wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_BK_FIFO, NRPCTXBUFPOST);
- wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_VI_FIFO, NRPCTXBUFPOST);
- }
-
- /* Allocate SB handle */
- wlc->pub->sih = osl_malloc(wlc->osh, sizeof(si_t));
- if (!wlc->pub->sih)
- return -1;
- bzero(wlc->pub->sih, sizeof(si_t));
-
- /* sync up revinfo with BMAC */
- bzero(&revinfo, sizeof(wlc_bmac_revinfo_t));
- if (wlc_bmac_revinfo_get(wlc->hw, &revinfo) != 0)
- return -1;
- wlc->vendorid = (u16) revinfo.vendorid;
- wlc->deviceid = (u16) revinfo.deviceid;
-
- wlc->pub->boardrev = (u16) revinfo.boardrev;
- wlc->pub->corerev = revinfo.corerev;
- wlc->pub->sromrev = (u8) revinfo.sromrev;
- wlc->pub->sih->chiprev = revinfo.chiprev;
- wlc->pub->sih->chip = revinfo.chip;
- wlc->pub->sih->chippkg = revinfo.chippkg;
- wlc->pub->sih->boardtype = revinfo.boardtype;
- wlc->pub->sih->boardvendor = revinfo.boardvendor;
- wlc->pub->sih->bustype = revinfo.bustype;
- wlc->pub->sih->buscoretype = revinfo.buscoretype;
- wlc->pub->sih->buscorerev = revinfo.buscorerev;
- wlc->pub->sih->issim = (bool) revinfo.issim;
- wlc->pub->sih->rpc = rpc;
-
- if (revinfo.nbands == 0 || revinfo.nbands > 2)
- return -1;
- wlc->pub->_nbands = revinfo.nbands;
-
- for (idx = 0; idx < wlc->pub->_nbands; idx++) {
- uint bandunit, bandtype; /* To access bandstate */
- wlc_phy_t *pi = osl_malloc(wlc->osh, sizeof(wlc_phy_t));
-
- if (!pi)
- return -1;
- bzero(pi, sizeof(wlc_phy_t));
- pi->rpc = rpc;
-
- bandunit = revinfo.band[idx].bandunit;
- bandtype = revinfo.band[idx].bandtype;
- wlc->bandstate[bandunit]->radiorev =
- (u8) revinfo.band[idx].radiorev;
- wlc->bandstate[bandunit]->phytype =
- (u16) revinfo.band[idx].phytype;
- wlc->bandstate[bandunit]->phyrev =
- (u16) revinfo.band[idx].phyrev;
- wlc->bandstate[bandunit]->radioid =
- (u16) revinfo.band[idx].radioid;
- wlc->bandstate[bandunit]->abgphy_encore =
- revinfo.band[idx].abgphy_encore;
-
- wlc->bandstate[bandunit]->pi = pi;
- wlc->bandstate[bandunit]->bandunit = bandunit;
- wlc->bandstate[bandunit]->bandtype = bandtype;
- }
-
- /* misc stuff */
-
- return 0;
-}
-
-/* Free the convenience handles */
-int wlc_bmac_detach(wlc_info_t *wlc)
-{
- uint idx;
-
- if (wlc->pub->sih) {
- osl_mfree(wlc->osh, (void *)wlc->pub->sih, sizeof(si_t));
- wlc->pub->sih = NULL;
- }
-
- for (idx = 0; idx < MAXBANDS; idx++)
- if (wlc->bandstate[idx]->pi) {
- kfree(wlc->bandstate[idx]->pi);
- wlc->bandstate[idx]->pi = NULL;
- }
-
- if (wlc->rpctx) {
- wlc_rpctx_detach(wlc->rpctx);
- wlc->rpctx = NULL;
- }
-
- return 0;
-
-}
-
-#endif /* WLC_HIGH_ONLY */
-
-static void wlc_timers_deinit(wlc_info_t *wlc)
+static void wlc_timers_deinit(struct wlc_info *wlc)
{
/* free timer state */
if (wlc->wdtimer) {
@@ -2274,7 +2105,7 @@ static void wlc_timers_deinit(wlc_info_t *wlc)
}
}
-static void wlc_detach_module(wlc_info_t *wlc)
+static void wlc_detach_module(struct wlc_info *wlc)
{
if (wlc->asi) {
wlc_antsel_detach(wlc->asi);
@@ -2297,7 +2128,7 @@ static void wlc_detach_module(wlc_info_t *wlc)
* One exception is sb register access, which is possible if crystal is turned on
* After "down" state, driver should avoid software timer with the exception of radio_monitor.
*/
-uint wlc_detach(wlc_info_t *wlc)
+uint wlc_detach(struct wlc_info *wlc)
{
uint i;
uint callbacks = 0;
@@ -2305,7 +2136,7 @@ uint wlc_detach(wlc_info_t *wlc)
if (wlc == NULL)
return 0;
- WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc->pub->unit, __func__);
ASSERT(!wlc->pub->up);
@@ -2328,15 +2159,6 @@ uint wlc_detach(wlc_info_t *wlc)
/* free other state */
-#ifdef WLC_HIGH_ONLY
- /* High-Only driver has an allocated copy of vars, monolithic just
- * references the wlc->hw->vars which is freed in wlc_bmac_detach()
- */
- if (wlc->pub->vars) {
- kfree(wlc->pub->vars);
- wlc->pub->vars = NULL;
- }
-#endif
#ifdef BCMDBG
if (wlc->country_ie_override) {
@@ -2360,13 +2182,6 @@ uint wlc_detach(wlc_info_t *wlc)
/* Detach from iovar manager */
wlc_module_unregister(wlc->pub, "wlc_iovars", wlc);
- /*
- if (wlc->ap) {
- wlc_ap_detach(wlc->ap);
- wlc->ap = NULL;
- }
- */
-
while (wlc->tx_queues != NULL) {
wlc_txq_free(wlc, wlc->osh, wlc->tx_queues);
}
@@ -2383,7 +2198,7 @@ uint wlc_detach(wlc_info_t *wlc)
}
/* update state that depends on the current value of "ap" */
-void wlc_ap_upd(wlc_info_t *wlc)
+void wlc_ap_upd(struct wlc_info *wlc)
{
if (AP_ENAB(wlc->pub))
wlc->PLCPHdr_override = WLC_PLCP_AUTO; /* AP: short not allowed, but not enforced */
@@ -2398,7 +2213,7 @@ void wlc_ap_upd(wlc_info_t *wlc)
}
/* read hwdisable state and propagate to wlc flag */
-static void wlc_radio_hwdisable_upd(wlc_info_t *wlc)
+static void wlc_radio_hwdisable_upd(struct wlc_info *wlc)
{
if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off)
return;
@@ -2411,17 +2226,17 @@ static void wlc_radio_hwdisable_upd(wlc_info_t *wlc)
}
/* return true if Minimum Power Consumption should be entered, false otherwise */
-bool wlc_is_non_delay_mpc(wlc_info_t *wlc)
+bool wlc_is_non_delay_mpc(struct wlc_info *wlc)
{
return false;
}
-bool wlc_ismpc(wlc_info_t *wlc)
+bool wlc_ismpc(struct wlc_info *wlc)
{
return (wlc->mpc_delay_off == 0) && (wlc_is_non_delay_mpc(wlc));
}
-void wlc_radio_mpc_upd(wlc_info_t *wlc)
+void wlc_radio_mpc_upd(struct wlc_info *wlc)
{
bool mpc_radio, radio_state;
@@ -2477,7 +2292,7 @@ void wlc_radio_mpc_upd(wlc_info_t *wlc)
* centralized radio disable/enable function,
* invoke radio enable/disable after updating hwradio status
*/
-static void wlc_radio_upd(wlc_info_t *wlc)
+static void wlc_radio_upd(struct wlc_info *wlc)
{
if (wlc->pub->radio_disabled)
wlc_radio_disable(wlc);
@@ -2486,7 +2301,7 @@ static void wlc_radio_upd(wlc_info_t *wlc)
}
/* maintain LED behavior in down state */
-static void wlc_down_led_upd(wlc_info_t *wlc)
+static void wlc_down_led_upd(struct wlc_info *wlc)
{
ASSERT(!wlc->pub->up);
@@ -2499,7 +2314,7 @@ static void wlc_down_led_upd(wlc_info_t *wlc)
}
}
-void wlc_radio_disable(wlc_info_t *wlc)
+void wlc_radio_disable(struct wlc_info *wlc)
{
if (!wlc->pub->up) {
wlc_down_led_upd(wlc);
@@ -2510,7 +2325,7 @@ void wlc_radio_disable(wlc_info_t *wlc)
wl_down(wlc->wl);
}
-static void wlc_radio_enable(wlc_info_t *wlc)
+static void wlc_radio_enable(struct wlc_info *wlc)
{
if (wlc->pub->up)
return;
@@ -2526,10 +2341,10 @@ static void wlc_radio_enable(wlc_info_t *wlc)
/* periodical query hw radio button while driver is "down" */
static void wlc_radio_timer(void *arg)
{
- wlc_info_t *wlc = (wlc_info_t *) arg;
+ struct wlc_info *wlc = (struct wlc_info *) arg;
if (DEVICEREMOVED(wlc)) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__);
wl_down(wlc->wl);
return;
}
@@ -2544,7 +2359,7 @@ static void wlc_radio_timer(void *arg)
wlc_radio_upd(wlc);
}
-static bool wlc_radio_monitor_start(wlc_info_t *wlc)
+static bool wlc_radio_monitor_start(struct wlc_info *wlc)
{
/* Don't start the timer if HWRADIO feature is disabled */
if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO))
@@ -2556,7 +2371,7 @@ static bool wlc_radio_monitor_start(wlc_info_t *wlc)
return true;
}
-bool wlc_radio_monitor_stop(wlc_info_t *wlc)
+bool wlc_radio_monitor_stop(struct wlc_info *wlc)
{
if (!wlc->radio_monitor)
return true;
@@ -2570,7 +2385,7 @@ bool wlc_radio_monitor_stop(wlc_info_t *wlc)
}
/* bring the driver down, but don't reset hardware */
-void wlc_out(wlc_info_t *wlc)
+void wlc_out(struct wlc_info *wlc)
{
wlc_bmac_set_noreset(wlc->hw, true);
wlc_radio_upd(wlc);
@@ -2591,7 +2406,7 @@ void wlc_out(wlc_info_t *wlc)
* if there is no packet pending for the FIFO, then the corresponding prec bits should be set
* in prec_map. Of course, ignore this rule when block_datafifo is set
*/
-static bool wlc_tx_prec_map_verify(wlc_info_t *wlc)
+static bool wlc_tx_prec_map_verify(struct wlc_info *wlc)
{
/* For non-WME, both fifos have overlapping prec_map. So it's an error only if both
* fail the check.
@@ -2613,7 +2428,7 @@ static bool wlc_tx_prec_map_verify(wlc_info_t *wlc)
static void wlc_watchdog_by_timer(void *arg)
{
- wlc_info_t *wlc = (wlc_info_t *) arg;
+ struct wlc_info *wlc = (struct wlc_info *) arg;
wlc_watchdog(arg);
if (WLC_WATCHDOG_TBTT(wlc)) {
/* set to normal osl watchdog period */
@@ -2626,17 +2441,17 @@ static void wlc_watchdog_by_timer(void *arg)
/* common watchdog code */
static void wlc_watchdog(void *arg)
{
- wlc_info_t *wlc = (wlc_info_t *) arg;
+ struct wlc_info *wlc = (struct wlc_info *) arg;
int i;
wlc_bsscfg_t *cfg;
- WL_TRACE(("wl%d: wlc_watchdog\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_watchdog\n", wlc->pub->unit);
if (!wlc->pub->up)
return;
if (DEVICEREMOVED(wlc)) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__);
wl_down(wlc->wl);
return;
}
@@ -2667,13 +2482,7 @@ static void wlc_watchdog(void *arg)
if (wlc->pub->radio_disabled)
return;
-#ifdef WLC_LOW
wlc_bmac_watchdog(wlc);
-#endif
-#ifdef WLC_HIGH_ONLY
- /* maintenance */
- wlc_bmac_rpc_watchdog(wlc);
-#endif
/* occasionally sample mac stat counters to detect 16-bit counter wrap */
if ((WLC_UPDATE_STATS(wlc))
@@ -2702,10 +2511,8 @@ static void wlc_watchdog(void *arg)
wlc->tempsense_lasttime = wlc->pub->now;
wlc_tempsense_upd(wlc);
}
-#ifdef WLC_LOW
/* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */
ASSERT(wlc_bmac_taclear(wlc->hw, true));
-#endif
/* Verify that tx_prec_map and fifos are in sync to avoid lock ups */
ASSERT(wlc_tx_prec_map_verify(wlc));
@@ -2714,9 +2521,9 @@ static void wlc_watchdog(void *arg)
}
/* make interface operational */
-int wlc_up(wlc_info_t *wlc)
+int wlc_up(struct wlc_info *wlc)
{
- WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc->pub->unit, __func__);
/* HW is turned off so don't try to access it */
if (wlc->pub->hw_off || DEVICEREMOVED(wlc))
@@ -2728,7 +2535,7 @@ int wlc_up(wlc_info_t *wlc)
}
if ((wlc->pub->boardflags & BFL_FEM)
- && (CHIPID(wlc->pub->sih->chip) == BCM4313_CHIP_ID)) {
+ && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) {
if (wlc->pub->boardrev >= 0x1250
&& (wlc->pub->boardflags & BFL_FEM_BT)) {
wlc_mhf(wlc, MHF5, MHF5_4313_GPIOCTRL,
@@ -2761,7 +2568,8 @@ int wlc_up(wlc_info_t *wlc)
if (!BSSCFG_STA(bsscfg)
|| !bsscfg->enable || !bsscfg->BSS)
continue;
- WL_ERROR(("wl%d.%d: wlc_up: rfdisable -> " "wlc_bsscfg_disable()\n", wlc->pub->unit, idx));
+ WL_ERROR("wl%d.%d: wlc_up: rfdisable -> " "wlc_bsscfg_disable()\n",
+ wlc->pub->unit, idx);
}
}
} else
@@ -2822,10 +2630,10 @@ int wlc_up(wlc_info_t *wlc)
}
/* Initialize the base precedence map for dequeueing from txq based on WME settings */
-static void wlc_tx_prec_map_init(wlc_info_t *wlc)
+static void wlc_tx_prec_map_init(struct wlc_info *wlc)
{
wlc->tx_prec_map = WLC_PREC_BMP_ALL;
- bzero(wlc->fifo2prec_map, sizeof(u16) * NFIFO);
+ memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
/* For non-WME, both fifos have overlapping MAXPRIO. So just disable all precedences
* if either is full.
@@ -2841,7 +2649,7 @@ static void wlc_tx_prec_map_init(wlc_info_t *wlc)
}
}
-static uint wlc_down_del_timer(wlc_info_t *wlc)
+static uint wlc_down_del_timer(struct wlc_info *wlc)
{
uint callbacks = 0;
@@ -2853,7 +2661,7 @@ static uint wlc_down_del_timer(wlc_info_t *wlc)
* disable the hardware, free any transient buffer state.
* Return a count of the number of driver callbacks still pending.
*/
-uint wlc_down(wlc_info_t *wlc)
+uint wlc_down(struct wlc_info *wlc)
{
uint callbacks = 0;
@@ -2861,12 +2669,12 @@ uint wlc_down(wlc_info_t *wlc)
bool dev_gone = false;
wlc_txq_info_t *qi;
- WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__));
+ WL_TRACE("wl%d: %s:\n", wlc->pub->unit, __func__);
/* check if we are already in the going down path */
if (wlc->going_down) {
- WL_ERROR(("wl%d: %s: Driver going down so return\n",
- wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s: Driver going down so return\n",
+ wlc->pub->unit, __func__);
return 0;
}
if (!wlc->pub->up)
@@ -2922,14 +2730,11 @@ uint wlc_down(wlc_info_t *wlc)
/* wlc_bmac_down_finish has done wlc_coredisable(). so clk is off */
wlc->clk = false;
-#ifdef WLC_HIGH_ONLY
- wlc_rpctx_txreclaim(wlc->rpctx);
-#endif
/* Verify all packets are flushed from the driver */
- if (PKTALLOCED(wlc->osh) != 0) {
- WL_ERROR(("%d packets not freed at wlc_down!!!!!!\n",
- PKTALLOCED(wlc->osh)));
+ if (wlc->osh->pktalloced != 0) {
+ WL_ERROR("%d packets not freed at wlc_down!!!!!!\n",
+ wlc->osh->pktalloced);
}
#ifdef BCMDBG
/* Since all the packets should have been freed,
@@ -2943,7 +2748,7 @@ uint wlc_down(wlc_info_t *wlc)
}
/* Set the current gmode configuration */
-int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
+int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config)
{
int ret = 0;
uint i;
@@ -2958,7 +2763,7 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
bool preamble_restrict = false; /* Restrict association to stations that support short
* preambles
*/
- wlcband_t *band;
+ struct wlcband *band;
/* if N-support is enabled, allow Gmode set as long as requested
* Gmode is not GMODE_LEGACY_B
@@ -2985,10 +2790,10 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
wlc_protection_upd(wlc, WLC_PROT_G_USER, gmode);
/* Clear supported rates filter */
- bzero(&wlc->sup_rates_override, sizeof(wlc_rateset_t));
+ memset(&wlc->sup_rates_override, 0, sizeof(wlc_rateset_t));
/* Clear rateset override */
- bzero(&rs, sizeof(wlc_rateset_t));
+ memset(&rs, 0, sizeof(wlc_rateset_t));
switch (gmode) {
case GMODE_LEGACY_B:
@@ -3026,8 +2831,8 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
default:
/* Error */
- WL_ERROR(("wl%d: %s: invalid gmode %d\n", wlc->pub->unit,
- __func__, gmode));
+ WL_ERROR("wl%d: %s: invalid gmode %d\n",
+ wlc->pub->unit, __func__, gmode);
return BCME_UNSUPPORTED;
}
@@ -3093,7 +2898,7 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config)
return ret;
}
-static int wlc_nmode_validate(wlc_info_t *wlc, s32 nmode)
+static int wlc_nmode_validate(struct wlc_info *wlc, s32 nmode)
{
int err = 0;
@@ -3117,7 +2922,7 @@ static int wlc_nmode_validate(wlc_info_t *wlc, s32 nmode)
return err;
}
-int wlc_set_nmode(wlc_info_t *wlc, s32 nmode)
+int wlc_set_nmode(struct wlc_info *wlc, s32 nmode)
{
uint i;
int err;
@@ -3176,7 +2981,7 @@ int wlc_set_nmode(wlc_info_t *wlc, s32 nmode)
return err;
}
-static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg)
+static int wlc_set_rateset(struct wlc_info *wlc, wlc_rateset_t *rs_arg)
{
wlc_rateset_t rs, new;
uint bandunit;
@@ -3219,18 +3024,18 @@ static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg)
}
/* simplified integer set interface for common ioctl handler */
-int wlc_set(wlc_info_t *wlc, int cmd, int arg)
+int wlc_set(struct wlc_info *wlc, int cmd, int arg)
{
return wlc_ioctl(wlc, cmd, (void *)&arg, sizeof(arg), NULL);
}
/* simplified integer get interface for common ioctl handler */
-int wlc_get(wlc_info_t *wlc, int cmd, int *arg)
+int wlc_get(struct wlc_info *wlc, int cmd, int *arg)
{
return wlc_ioctl(wlc, cmd, arg, sizeof(int), NULL);
}
-static void wlc_ofdm_rateset_war(wlc_info_t *wlc)
+static void wlc_ofdm_rateset_war(struct wlc_info *wlc)
{
u8 r;
bool war = false;
@@ -3246,14 +3051,16 @@ static void wlc_ofdm_rateset_war(wlc_info_t *wlc)
}
int
-wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
+wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len,
+ struct wlc_if *wlcif)
{
return _wlc_ioctl(wlc, cmd, arg, len, wlcif);
}
/* common ioctl handler. return: 0=ok, -1=error, positive=particular error */
static int
-_wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
+_wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len,
+ struct wlc_if *wlcif)
{
int val, *pval;
bool bool_val;
@@ -3265,7 +3072,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
uint band;
rw_reg_t *r;
wlc_bsscfg_t *bsscfg;
- osl_t *osh;
+ struct osl_info *osh;
wlc_bss_info_t *current_bss;
/* update bsscfg pointer */
@@ -3280,7 +3087,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
/* If the device is turned off, then it's not "removed" */
if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) {
- WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__);
wl_down(wlc->wl);
return BCME_ERROR;
}
@@ -3300,8 +3107,8 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
bool_val = val != 0;
if (cmd != WLC_SET_CHANNEL)
- WL_NONE(("WLC_IOCTL: cmd %d val 0x%x (%d) len %d\n", cmd,
- (uint) val, val, len));
+ WL_NONE("WLC_IOCTL: cmd %d val 0x%x (%d) len %d\n",
+ cmd, (uint)val, val, len);
bcmerror = 0;
regs = wlc->regs;
@@ -3321,8 +3128,8 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
default:
if ((arg == NULL) || (len <= 0)) {
- WL_ERROR(("wl%d: %s: Command %d needs arguments\n",
- wlc->pub->unit, __func__, cmd));
+ WL_ERROR("wl%d: %s: Command %d needs arguments\n",
+ wlc->pub->unit, __func__, cmd);
bcmerror = BCME_BADARG;
goto done;
}
@@ -3388,10 +3195,6 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
wlc_set_chanspec(wlc, chspec);
wlc_enable_mac(wlc);
}
-#ifdef WLC_HIGH_ONLY
- /* delay for channel change */
- msleep(50);
-#endif
break;
}
@@ -3659,8 +3462,8 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
/* 4322 supports antdiv in phy, no need to set it to ucode */
if (WLCISNPHY(wlc->band)
&& D11REV_IS(wlc->pub->corerev, 16)) {
- WL_ERROR(("wl%d: can't set ucantdiv for 4322\n",
- wlc->pub->unit));
+ WL_ERROR("wl%d: can't set ucantdiv for 4322\n",
+ wlc->pub->unit);
bcmerror = BCME_UNSUPPORTED;
} else
wlc_mhf(wlc, MHF1, MHF1_ANTDIV,
@@ -3757,8 +3560,8 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
if ((radiomask == 0) || (radiomask & ~validbits)
|| (radioval & ~validbits)
|| ((radioval & ~radiomask) != 0)) {
- WL_ERROR(("SET_RADIO with wrong bits 0x%x\n",
- val));
+ WL_ERROR("SET_RADIO with wrong bits 0x%x\n",
+ val);
bcmerror = BCME_RANGE;
break;
}
@@ -3788,7 +3591,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
break;
}
- bzero((char *)&key, sizeof(key));
+ memset((char *)&key, 0, sizeof(key));
if (src_key) {
key.index = src_key->id;
key.len = src_key->len;
@@ -3800,7 +3603,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
key.flags |= WL_PRIMARY_KEY;
bcopy(src_key->ea.octet, key.ea.octet,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
}
bcopy((char *)&key, arg, sizeof(key));
@@ -3835,8 +3638,8 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
u16 lo;
u32 hi;
/* group keys in WPA-NONE (IBSS only, AES and TKIP) use a global TXIV */
- if ((bsscfg->WPA_auth & WPA_AUTH_NONE)
- && ETHER_ISNULLADDR(&key->ea)) {
+ if ((bsscfg->WPA_auth & WPA_AUTH_NONE) &&
+ is_zero_ether_addr(key->ea.octet)) {
lo = bsscfg->wpa_none_txiv.lo;
hi = bsscfg->wpa_none_txiv.hi;
} else {
@@ -3885,7 +3688,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
wlc_rateset_t rs;
wl_rateset_t *ret_rs = (wl_rateset_t *) arg;
- bzero(&rs, sizeof(wlc_rateset_t));
+ memset(&rs, 0, sizeof(wlc_rateset_t));
wlc_default_rateset(wlc, (wlc_rateset_t *) &rs);
if (len < (int)(rs.count + sizeof(rs.count))) {
@@ -3913,7 +3716,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
break;
}
- bzero(&rs, sizeof(wlc_rateset_t));
+ memset(&rs, 0, sizeof(wlc_rateset_t));
/* Copy only legacy rateset section */
rs.count = in_rs->count;
@@ -4247,7 +4050,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
/* check for an empty rateset to clear the override */
if (rs.count == 0) {
- bzero(&wlc->sup_rates_override,
+ memset(&wlc->sup_rates_override, 0,
sizeof(wlc_rateset_t));
break;
}
@@ -4394,7 +4197,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
#endif
case WLC_LAST:
- WL_ERROR(("%s: WLC_LAST\n", __func__));
+ WL_ERROR("%s: WLC_LAST\n", __func__);
}
done:
@@ -4406,21 +4209,19 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif)
}
}
-#ifdef WLC_LOW
/* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */
/* In hw_off condition, IOCTLs that reach here are deemed safe but taclear would
* certainly result in getting -1 for register reads. So skip ta_clear altogether
*/
if (!(wlc->pub->hw_off))
ASSERT(wlc_bmac_taclear(wlc->hw, ta_ok) || !ta_ok);
-#endif
return bcmerror;
}
#if defined(BCMDBG)
/* consolidated register access ioctl error checking */
-int wlc_iocregchk(wlc_info_t *wlc, uint band)
+int wlc_iocregchk(struct wlc_info *wlc, uint band)
{
/* if band is specified, it must be the current band */
if ((band != WLC_BAND_AUTO) && (band != (uint) wlc->band->bandtype))
@@ -4440,7 +4241,7 @@ int wlc_iocregchk(wlc_info_t *wlc, uint band)
#if defined(BCMDBG)
/* For some ioctls, make sure that the pi pointer matches the current phy */
-int wlc_iocpichk(wlc_info_t *wlc, uint phytype)
+int wlc_iocpichk(struct wlc_info *wlc, uint phytype)
{
if (wlc->band->phytype != phytype)
return BCME_BADBAND;
@@ -4474,21 +4275,21 @@ static const bcm_iovar_t *wlc_iovar_lookup(const bcm_iovar_t *table,
}
/* simplified integer get interface for common WLC_GET_VAR ioctl handler */
-int wlc_iovar_getint(wlc_info_t *wlc, const char *name, int *arg)
+int wlc_iovar_getint(struct wlc_info *wlc, const char *name, int *arg)
{
return wlc_iovar_op(wlc, name, NULL, 0, arg, sizeof(s32), IOV_GET,
NULL);
}
/* simplified integer set interface for common WLC_SET_VAR ioctl handler */
-int wlc_iovar_setint(wlc_info_t *wlc, const char *name, int arg)
+int wlc_iovar_setint(struct wlc_info *wlc, const char *name, int arg)
{
return wlc_iovar_op(wlc, name, NULL, 0, (void *)&arg, sizeof(arg),
IOV_SET, NULL);
}
/* simplified s8 get interface for common WLC_GET_VAR ioctl handler */
-int wlc_iovar_gets8(wlc_info_t *wlc, const char *name, s8 *arg)
+int wlc_iovar_gets8(struct wlc_info *wlc, const char *name, s8 *arg)
{
int iovar_int;
int err;
@@ -4507,11 +4308,11 @@ int wlc_iovar_gets8(wlc_info_t *wlc, const char *name, s8 *arg)
* calling function must keep 'iovars' until wlc_module_unregister is called.
* 'iovar' must have the last entry's name field being NULL as terminator.
*/
-int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars,
+int wlc_module_register(struct wlc_pub *pub, const bcm_iovar_t *iovars,
const char *name, void *hdl, iovar_fn_t i_fn,
watchdog_fn_t w_fn, down_fn_t d_fn)
{
- wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
+ struct wlc_info *wlc = (struct wlc_info *) pub->wlc;
int i;
ASSERT(name != NULL);
@@ -4537,9 +4338,9 @@ int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars,
}
/* unregister module callbacks */
-int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl)
+int wlc_module_unregister(struct wlc_pub *pub, const char *name, void *hdl)
{
- wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
+ struct wlc_info *wlc = (struct wlc_info *) pub->wlc;
int i;
if (wlc == NULL)
@@ -4550,7 +4351,7 @@ int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl)
for (i = 0; i < WLC_MAXMODULES; i++) {
if (!strcmp(wlc->modulecb[i].name, name) &&
(wlc->modulecb[i].hdl == hdl)) {
- bzero(&wlc->modulecb[i], sizeof(modulecb_t));
+ memset(&wlc->modulecb[i], 0, sizeof(modulecb_t));
return 0;
}
}
@@ -4560,7 +4361,7 @@ int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl)
}
/* Write WME tunable parameters for retransmit/max rate from wlc struct to ucode */
-static void wlc_wme_retries_write(wlc_info_t *wlc)
+static void wlc_wme_retries_write(struct wlc_info *wlc)
{
int ac;
@@ -4582,7 +4383,7 @@ static void wlc_wme_retries_write(wlc_info_t *wlc)
* All pointers may point into the same buffer.
*/
int
-wlc_iovar_op(wlc_info_t *wlc, const char *name,
+wlc_iovar_op(struct wlc_info *wlc, const char *name,
void *params, int p_len, void *arg, int len,
bool set, struct wlc_if *wlcif)
{
@@ -4606,8 +4407,8 @@ wlc_iovar_op(wlc_info_t *wlc, const char *name,
if (!set && (len == sizeof(int)) &&
!(IS_ALIGNED((unsigned long)(arg), (uint) sizeof(int)))) {
- WL_ERROR(("wl%d: %s unaligned get ptr for %s\n",
- wlc->pub->unit, __func__, name));
+ WL_ERROR("wl%d: %s unaligned get ptr for %s\n",
+ wlc->pub->unit, __func__, name);
ASSERT(0);
}
@@ -4622,11 +4423,6 @@ wlc_iovar_op(wlc_info_t *wlc, const char *name,
/* iovar name not found */
if (i >= WLC_MAXMODULES) {
err = BCME_UNSUPPORTED;
-#ifdef WLC_HIGH_ONLY
- err =
- bcmsdh_iovar_op(wlc->btparam, name, params, p_len, arg, len,
- set);
-#endif
goto exit;
}
@@ -4658,10 +4454,10 @@ wlc_iovar_op(wlc_info_t *wlc, const char *name,
}
int
-wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg, int len,
+wlc_iovar_check(struct wlc_pub *pub, const bcm_iovar_t *vi, void *arg, int len,
bool set)
{
- wlc_info_t *wlc = (wlc_info_t *) pub->wlc;
+ struct wlc_info *wlc = (struct wlc_info *) pub->wlc;
int err = 0;
s32 int_val = 0;
@@ -4729,7 +4525,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
const char *name, void *params, uint p_len, void *arg, int len,
int val_size, struct wlc_if *wlcif)
{
- wlc_info_t *wlc = hdl;
+ struct wlc_info *wlc = hdl;
wlc_bsscfg_t *bsscfg;
int err = 0;
s32 int_val = 0;
@@ -4739,7 +4535,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
bool bool_val2;
wlc_bss_info_t *current_bss;
- WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__));
+ WL_TRACE("wl%d: %s\n", wlc->pub->unit, __func__);
bsscfg = NULL;
current_bss = NULL;
@@ -4762,8 +4558,8 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
bool_val = (int_val != 0) ? true : false;
bool_val2 = (int_val2 != 0) ? true : false;
- WL_TRACE(("wl%d: %s: id %d\n", wlc->pub->unit, __func__,
- IOV_ID(actionid)));
+ WL_TRACE("wl%d: %s: id %d\n",
+ wlc->pub->unit, __func__, IOV_ID(actionid));
/* Do the actual parameter implementation */
switch (actionid) {
@@ -4821,7 +4617,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
break;
default:
- WL_ERROR(("wl%d: %s: unsupported\n", wlc->pub->unit, __func__));
+ WL_ERROR("wl%d: %s: unsupported\n", wlc->pub->unit, __func__);
err = BCME_UNSUPPORTED;
break;
}
@@ -4833,7 +4629,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
}
static int
-wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val, const bcm_iovar_t *vi)
+wlc_iovar_rangecheck(struct wlc_info *wlc, u32 val, const bcm_iovar_t *vi)
{
int err = 0;
u32 min_val = 0;
@@ -4930,7 +4726,7 @@ void wlc_print_txstatus(tx_status_t *txs)
#define MACSTATUPD(name) \
wlc_ctrupd_cache(macstats.name, &wlc->core->macstat_snapshot->name, &wlc->pub->_cnt->name)
-void wlc_statsupd(wlc_info_t *wlc)
+void wlc_statsupd(struct wlc_info *wlc)
{
int i;
#ifdef BCMDBG
@@ -4956,8 +4752,8 @@ void wlc_statsupd(wlc_info_t *wlc)
/* check for rx fifo 0 overflow */
delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
if (delta)
- WL_ERROR(("wl%d: %u rx fifo 0 overflows!\n", wlc->pub->unit,
- delta));
+ WL_ERROR("wl%d: %u rx fifo 0 overflows!\n",
+ wlc->pub->unit, delta);
/* check for tx fifo underflows */
for (i = 0; i < NFIFO; i++) {
@@ -4965,8 +4761,8 @@ void wlc_statsupd(wlc_info_t *wlc)
(u16) (wlc->core->macstat_snapshot->txfunfl[i] -
txfunfl[i]);
if (delta)
- WL_ERROR(("wl%d: %u tx fifo %d underflows!\n",
- wlc->pub->unit, delta, i));
+ WL_ERROR("wl%d: %u tx fifo %d underflows!\n",
+ wlc->pub->unit, delta, i);
}
#endif /* BCMDBG */
@@ -5015,7 +4811,7 @@ void wlc_statsupd(wlc_info_t *wlc)
bool wlc_chipmatch(u16 vendor, u16 device)
{
if (vendor != VENDOR_BROADCOM) {
- WL_ERROR(("wlc_chipmatch: unknown vendor id %04x\n", vendor));
+ WL_ERROR("wlc_chipmatch: unknown vendor id %04x\n", vendor);
return false;
}
@@ -5027,7 +4823,7 @@ bool wlc_chipmatch(u16 vendor, u16 device)
if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
return true;
- WL_ERROR(("wlc_chipmatch: unknown device id %04x\n", device));
+ WL_ERROR("wlc_chipmatch: unknown device id %04x\n", device);
return false;
}
@@ -5182,20 +4978,12 @@ int wlc_format_ssid(char *buf, const unsigned char ssid[], uint ssid_len)
}
#endif /* defined(BCMDBG) */
-u16 wlc_rate_shm_offset(wlc_info_t *wlc, u8 rate)
+u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate)
{
return wlc_bmac_rate_shm_offset(wlc->hw, rate);
}
/* Callback for device removed */
-#if defined(WLC_HIGH_ONLY)
-void wlc_device_removed(void *arg)
-{
- wlc_info_t *wlc = (wlc_info_t *) arg;
-
- wlc->device_present = false;
-}
-#endif /* WLC_HIGH_ONLY */
/*
* Attempts to queue a packet onto a multiple-precedence queue,
@@ -5207,16 +4995,16 @@ void wlc_device_removed(void *arg)
* Returns true if packet consumed (queued), false if not.
*/
bool BCMFASTPATH
-wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec)
+wlc_prec_enq(struct wlc_info *wlc, struct pktq *q, void *pkt, int prec)
{
return wlc_prec_enq_head(wlc, q, pkt, prec, false);
}
bool BCMFASTPATH
-wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
- bool head)
+wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt,
+ int prec, bool head)
{
- void *p;
+ struct sk_buff *p;
int eprec = -1; /* precedence to evict from */
/* Determine precedence from which to evict packet, if any */
@@ -5226,8 +5014,8 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
p = pktq_peek_tail(q, &eprec);
ASSERT(p != NULL);
if (eprec > prec) {
- WL_ERROR(("%s: Failing: eprec %d > prec %d\n", __func__,
- eprec, prec));
+ WL_ERROR("%s: Failing: eprec %d > prec %d\n",
+ __func__, eprec, prec);
return false;
}
}
@@ -5243,8 +5031,8 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
/* Refuse newer packet unless configured to discard oldest */
if (eprec == prec && !discard_oldest) {
- WL_ERROR(("%s: No where to go, prec == %d\n", __func__,
- prec));
+ WL_ERROR("%s: No where to go, prec == %d\n",
+ __func__, prec);
return false;
}
@@ -5256,14 +5044,14 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
/* Increment wme stats */
if (WME_ENAB(wlc->pub)) {
WLCNTINCR(wlc->pub->_wme_cnt->
- tx_failed[WME_PRIO2AC(PKTPRIO(p))].packets);
+ tx_failed[WME_PRIO2AC(p->priority)].packets);
WLCNTADD(wlc->pub->_wme_cnt->
- tx_failed[WME_PRIO2AC(PKTPRIO(p))].bytes,
+ tx_failed[WME_PRIO2AC(p->priority)].bytes,
pkttotlen(wlc->osh, p));
}
ASSERT(0);
- PKTFREE(wlc->osh, p, true);
+ pkt_buf_free_skb(wlc->osh, p, true);
WLCNTINCR(wlc->pub->_cnt->txnobuf);
}
@@ -5277,25 +5065,26 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec,
return true;
}
-void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec)
+void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu,
+ uint prec)
{
- wlc_info_t *wlc = (wlc_info_t *) ctx;
+ struct wlc_info *wlc = (struct wlc_info *) ctx;
wlc_txq_info_t *qi = wlc->active_queue; /* Check me */
struct pktq *q = &qi->q;
int prio;
- prio = PKTPRIO(sdu);
+ prio = sdu->priority;
ASSERT(pktq_max(q) >= wlc->pub->tunables->datahiwat);
if (!wlc_prec_enq(wlc, q, sdu, prec)) {
if (!EDCF_ENAB(wlc->pub)
|| (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL))
- WL_ERROR(("wl%d: wlc_txq_enq: txq overflow\n",
- wlc->pub->unit));
+ WL_ERROR("wl%d: wlc_txq_enq: txq overflow\n",
+ wlc->pub->unit);
/* ASSERT(9 == 8); *//* XXX we might hit this condtion in case packet flooding from mac80211 stack */
- PKTFREE(wlc->osh, sdu, true);
+ pkt_buf_free_skb(wlc->osh, sdu, true);
WLCNTINCR(wlc->pub->_cnt->txnobuf);
}
@@ -5317,13 +5106,14 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec)
}
bool BCMFASTPATH
-wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw)
+wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu,
+ struct ieee80211_hw *hw)
{
u8 prio;
uint fifo;
void *pkt;
struct scb *scb = &global_scb;
- struct dot11_header *d11_header = (struct dot11_header *)PKTDATA(sdu);
+ struct dot11_header *d11_header = (struct dot11_header *)(sdu->data);
u16 type, fc;
ASSERT(sdu);
@@ -5332,13 +5122,13 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw)
type = FC_TYPE(fc);
/* 802.11 standard requires management traffic to go at highest priority */
- prio = (type == FC_TYPE_DATA ? PKTPRIO(sdu) : MAXPRIO);
+ prio = (type == FC_TYPE_DATA ? sdu->priority : MAXPRIO);
fifo = prio2fifo[prio];
- ASSERT((uint) PKTHEADROOM(sdu) >= TXOFF);
- ASSERT(!PKTSHARED(sdu));
- ASSERT(!PKTNEXT(sdu));
- ASSERT(!PKTLINK(sdu));
+ ASSERT((uint) skb_headroom(sdu) >= TXOFF);
+ ASSERT(!(sdu->cloned));
+ ASSERT(!(sdu->next));
+ ASSERT(!(sdu->prev));
ASSERT(fifo < NFIFO);
pkt = sdu;
@@ -5352,9 +5142,9 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw)
return 0;
}
-void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi)
+void BCMFASTPATH wlc_send_q(struct wlc_info *wlc, wlc_txq_info_t *qi)
{
- void *pkt[DOT11_MAXNUMFRAGS];
+ struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
int prec;
u16 prec_map;
int err = 0, i, count;
@@ -5427,7 +5217,7 @@ void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi)
* for MC frames so is used as part of the sequence number.
*/
static inline u16
-bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh)
+bcmc_fid_generate(struct wlc_info *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh)
{
u16 frameid;
@@ -5441,13 +5231,14 @@ bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh)
}
void BCMFASTPATH
-wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend)
+wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p, bool commit,
+ s8 txpktpend)
{
u16 frameid = INVALIDFID;
d11txh_t *txh;
ASSERT(fifo < NFIFO);
- txh = (d11txh_t *) PKTDATA(p);
+ txh = (d11txh_t *) (p->data);
/* When a BC/MC frame is being committed to the BCMC fifo via DMA (NOT PIO), update
* ucode or BSS info as appropriate.
@@ -5460,21 +5251,14 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend)
if (WLC_WAR16165(wlc))
wlc_war16165(wlc, true);
-#ifdef WLC_HIGH_ONLY
- if (RPCTX_ENAB(wlc->pub)) {
- (void)wlc_rpctx_tx(wlc->rpctx, fifo, p, commit, frameid,
- txpktpend);
- return;
- }
-#else
/* Bump up pending count for if not using rpc. If rpc is used, this will be handled
* in wlc_bmac_txfifo()
*/
if (commit) {
TXPKTPENDINC(wlc, fifo, txpktpend);
- WL_TRACE(("wlc_txfifo, pktpend inc %d to %d\n", txpktpend,
- TXPKTPENDGET(wlc, fifo)));
+ WL_TRACE("wlc_txfifo, pktpend inc %d to %d\n",
+ txpktpend, TXPKTPENDGET(wlc, fifo));
}
/* Commit BCMC sequence number in the SHM frame ID location */
@@ -5482,13 +5266,12 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend)
BCMCFID(wlc, frameid);
if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) {
- WL_ERROR(("wlc_txfifo: fatal, toss frames !!!\n"));
+ WL_ERROR("wlc_txfifo: fatal, toss frames !!!\n");
}
-#endif /* WLC_HIGH_ONLY */
}
static u16
-wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length)
+wlc_compute_airtime(struct wlc_info *wlc, ratespec_t rspec, uint length)
{
u16 usec = 0;
uint mac_rate = RSPEC2RATE(rspec);
@@ -5523,7 +5306,8 @@ wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length)
usec = (length << 3) / 11;
break;
default:
- WL_ERROR(("wl%d: wlc_compute_airtime: unsupported rspec 0x%x\n", wlc->pub->unit, rspec));
+ WL_ERROR("wl%d: wlc_compute_airtime: unsupported rspec 0x%x\n",
+ wlc->pub->unit, rspec);
ASSERT((const char *)"Bad phy_rate" == NULL);
break;
}
@@ -5533,7 +5317,7 @@ wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length)
}
void BCMFASTPATH
-wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rspec, uint length, u8 *plcp)
+wlc_compute_plcp(struct wlc_info *wlc, ratespec_t rspec, uint length, u8 *plcp)
{
if (IS_MCS(rspec)) {
wlc_compute_mimo_plcp(rspec, length, plcp);
@@ -5574,7 +5358,7 @@ wlc_compute_ofdm_plcp(ratespec_t rspec, u32 length, u8 *plcp)
rate_signal = rate_info[rate] & RATE_MASK;
ASSERT(rate_signal != 0);
- bzero(plcp, D11_PHY_HDR_LEN);
+ memset(plcp, 0, D11_PHY_HDR_LEN);
D11A_PHY_HDR_SRATE((ofdm_phy_hdr_t *) plcp, rate_signal);
tmp = (length & 0xfff) << 5;
@@ -5619,7 +5403,7 @@ static void wlc_cck_plcp_set(int rate_500, uint length, u8 *plcp)
break;
default:
- WL_ERROR(("wlc_cck_plcp_set: unsupported rate %d\n", rate_500));
+ WL_ERROR("wlc_cck_plcp_set: unsupported rate %d\n", rate_500);
rate_500 = WLC_RATE_1M;
usec = length << 3;
break;
@@ -5657,7 +5441,7 @@ static void wlc_compute_cck_plcp(ratespec_t rspec, uint length, u8 *plcp)
* preamble_type use short/GF or long/MM PLCP header
*/
static u16 BCMFASTPATH
-wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type,
+wlc_compute_frame_dur(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type,
uint next_frag_len)
{
u16 dur, sifs;
@@ -5691,7 +5475,7 @@ wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type,
* frame_len next MPDU frame length in bytes
*/
u16 BCMFASTPATH
-wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate,
+wlc_compute_rtscts_dur(struct wlc_info *wlc, bool cts_only, ratespec_t rts_rate,
ratespec_t frame_rate, u8 rts_preamble_type,
u8 frame_preamble_type, uint frame_len, bool ba)
{
@@ -5722,7 +5506,7 @@ wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate,
return dur;
}
-static bool wlc_phy_rspec_check(wlc_info_t *wlc, u16 bw, ratespec_t rspec)
+static bool wlc_phy_rspec_check(struct wlc_info *wlc, u16 bw, ratespec_t rspec)
{
if (IS_MCS(rspec)) {
uint mcs = rspec & RSPEC_RATE_MASK;
@@ -5748,7 +5532,7 @@ static bool wlc_phy_rspec_check(wlc_info_t *wlc, u16 bw, ratespec_t rspec)
return true;
}
-u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec)
+u16 BCMFASTPATH wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec)
{
u16 phyctl1 = 0;
u16 bw;
@@ -5759,7 +5543,8 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec)
bw = RSPEC_GET_BW(rspec);
/* 10Mhz is not supported yet */
if (bw < PHY_TXC1_BW_20MHZ) {
- WL_ERROR(("wlc_phytxctl1_calc: bw %d is not supported yet, set to 20L\n", bw));
+ WL_ERROR("wlc_phytxctl1_calc: bw %d is not supported yet, set to 20L\n",
+ bw);
bw = PHY_TXC1_BW_20MHZ;
}
@@ -5784,7 +5569,7 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec)
/* get the phyctl byte from rate phycfg table */
phycfg = wlc_rate_legacy_phyctl(RSPEC2RATE(rspec));
if (phycfg == -1) {
- WL_ERROR(("wlc_phytxctl1_calc: wrong legacy OFDM/CCK rate\n"));
+ WL_ERROR("wlc_phytxctl1_calc: wrong legacy OFDM/CCK rate\n");
ASSERT(0);
phycfg = 0;
}
@@ -5798,16 +5583,14 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec)
/* phy clock must support 40Mhz if tx descriptor uses it */
if ((phyctl1 & PHY_TXC1_BW_MASK) >= PHY_TXC1_BW_40MHZ) {
ASSERT(CHSPEC_WLC_BW(wlc->chanspec) == WLC_40_MHZ);
-#ifndef WLC_HIGH_ONLY
ASSERT(wlc->chanspec == wlc_phy_chanspec_get(wlc->band->pi));
-#endif
}
#endif /* BCMDBG */
return phyctl1;
}
ratespec_t BCMFASTPATH
-wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec,
+wlc_rspec_to_rts_rspec(struct wlc_info *wlc, ratespec_t rspec, bool use_rspec,
u16 mimo_ctlchbw)
{
ratespec_t rts_rspec = 0;
@@ -5863,15 +5646,15 @@ wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec,
*
*/
static u16 BCMFASTPATH
-wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
- void *p, struct scb *scb, uint frag,
+wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw,
+ struct sk_buff *p, struct scb *scb, uint frag,
uint nfrags, uint queue, uint next_frag_len,
wsec_key_t *key, ratespec_t rspec_override)
{
struct dot11_header *h;
d11txh_t *txh;
u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
- osl_t *osh;
+ struct osl_info *osh;
int len, phylen, rts_phylen;
u16 fc, type, frameid, mch, phyctl, xfts, mainrates;
u16 seq = 0, mcl = 0, status = 0;
@@ -5911,7 +5694,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
osh = wlc->osh;
/* locate 802.11 MAC header */
- h = (struct dot11_header *)PKTDATA(p);
+ h = (struct dot11_header *)(p->data);
fc = ltoh16(h->fc);
type = FC_TYPE(fc);
@@ -5935,29 +5718,29 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
ASSERT(tx_info);
/* add PLCP */
- plcp = PKTPUSH(p, D11_PHY_HDR_LEN);
+ plcp = skb_push(p, D11_PHY_HDR_LEN);
/* add Broadcom tx descriptor header */
- txh = (d11txh_t *) PKTPUSH(p, D11_TXH_LEN);
- bzero((char *)txh, D11_TXH_LEN);
+ txh = (d11txh_t *) skb_push(p, D11_TXH_LEN);
+ memset((char *)txh, 0, D11_TXH_LEN);
/* setup frameid */
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
/* non-AP STA should never use BCMC queue */
ASSERT(queue != TX_BCMC_FIFO);
if (queue == TX_BCMC_FIFO) {
- WL_ERROR(("wl%d: %s: ASSERT queue == TX_BCMC!\n",
- WLCWLUNIT(wlc), __func__));
+ WL_ERROR("wl%d: %s: ASSERT queue == TX_BCMC!\n",
+ WLCWLUNIT(wlc), __func__);
frameid = bcmc_fid_generate(wlc, NULL, txh);
} else {
/* Increment the counter for first fragment */
if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
- SCB_SEQNUM(scb, PKTPRIO(p))++;
+ SCB_SEQNUM(scb, p->priority)++;
}
/* extract fragment number from frame first */
seq = ltoh16(seq) & FRAGNUM_MASK;
- seq |= (SCB_SEQNUM(scb, PKTPRIO(p)) << SEQNUM_SHIFT);
+ seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT);
h->seq = htol16(seq);
frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
@@ -5981,13 +5764,6 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
if (txrate[1]->idx < 0) {
txrate[1] = txrate[0];
}
-#ifdef WLC_HIGH_ONLY
- /* Double protection , just in case */
- if (txrate[0]->idx > HIGHEST_SINGLE_STREAM_MCS)
- txrate[0]->idx = HIGHEST_SINGLE_STREAM_MCS;
- if (txrate[1]->idx > HIGHEST_SINGLE_STREAM_MCS)
- txrate[1]->idx = HIGHEST_SINGLE_STREAM_MCS;
-#endif
for (k = 0; k < hw->max_rates; k++) {
is_mcs[k] =
@@ -6034,7 +5810,8 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
ASSERT(RSPEC_ACTIVE(rspec[k]));
rspec[k] = WLC_RATE_1M;
} else {
- if (WLANTSEL_ENAB(wlc) && !ETHER_ISMULTI(&h->a1)) {
+ if (WLANTSEL_ENAB(wlc) &&
+ !is_multicast_ether_addr(h->a1.octet)) {
/* set tx antenna config */
wlc_antsel_antcfg_get(wlc->asi, false, false, 0,
0, &antcfg, &fbantcfg);
@@ -6131,7 +5908,8 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
&& (!IS_MCS(rspec[k]))) {
- WL_ERROR(("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n", WLCWLUNIT(wlc), __func__));
+ WL_ERROR("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n",
+ WLCWLUNIT(wlc), __func__);
ASSERT(0 && "Rate mismatch");
}
@@ -6195,7 +5973,8 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
plcp[0];
/* DUR field for main rate */
- if ((fc != FC_PS_POLL) && !ETHER_ISMULTI(&h->a1) && !use_rifs) {
+ if ((fc != FC_PS_POLL) &&
+ !is_multicast_ether_addr(h->a1.octet) && !use_rifs) {
durid =
wlc_compute_frame_dur(wlc, rspec[0], preamble_type[0],
next_frag_len);
@@ -6213,7 +5992,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
/* DUR field for fallback rate */
if (fc == FC_PS_POLL)
txh->FragDurFallback = h->durid;
- else if (ETHER_ISMULTI(&h->a1) || use_rifs)
+ else if (is_multicast_ether_addr(h->a1.octet) || use_rifs)
txh->FragDurFallback = 0;
else {
durid = wlc_compute_frame_dur(wlc, rspec[1],
@@ -6225,7 +6004,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
if (frag == 0)
mcl |= TXC_STARTMSDU;
- if (!ETHER_ISMULTI(&h->a1))
+ if (!is_multicast_ether_addr(h->a1.octet))
mcl |= TXC_IMMEDACK;
if (BAND_5G(wlc->band->bandtype))
@@ -6260,7 +6039,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
txh->TxFesTimeFallback = htol16(0);
/* TxFrameRA */
- bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETHER_ADDR_LEN);
+ bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETH_ALEN);
/* TxFrameID */
txh->TxFrameID = htol16(frameid);
@@ -6347,11 +6126,11 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
if (use_cts) {
rts->fc = htol16(FC_CTS);
- bcopy((char *)&h->a2, (char *)&rts->ra, ETHER_ADDR_LEN);
+ bcopy((char *)&h->a2, (char *)&rts->ra, ETH_ALEN);
} else {
rts->fc = htol16((u16) FC_RTS);
bcopy((char *)&h->a1, (char *)&rts->ra,
- 2 * ETHER_ADDR_LEN);
+ 2 * ETH_ALEN);
}
/* mainrate
@@ -6362,9 +6141,10 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) rts_plcp) :
rts_plcp[0]) << 8;
} else {
- bzero((char *)txh->RTSPhyHeader, D11_PHY_HDR_LEN);
- bzero((char *)&txh->rts_frame, sizeof(struct dot11_rts_frame));
- bzero((char *)txh->RTSPLCPFallback,
+ memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
+ memset((char *)&txh->rts_frame, 0,
+ sizeof(struct dot11_rts_frame));
+ memset((char *)txh->RTSPLCPFallback, 0,
sizeof(txh->RTSPLCPFallback));
txh->RTSDurFallback = 0;
}
@@ -6453,7 +6233,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
uint frag_dur, dur, dur_fallback;
- ASSERT(!ETHER_ISMULTI(&h->a1));
+ ASSERT(!is_multicast_ether_addr(h->a1.octet));
/* WME: Update TXOP threshold */
if ((!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) && (frag == 0)) {
@@ -6523,19 +6303,23 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw,
}
}
} else
- WL_ERROR(("wl%d: %s txop invalid for rate %d\n",
- wlc->pub->unit, fifo_names[queue],
- RSPEC2RATE(rspec[0])));
+ WL_ERROR("wl%d: %s txop invalid for rate %d\n",
+ wlc->pub->unit, fifo_names[queue],
+ RSPEC2RATE(rspec[0]));
if (dur > wlc->edcf_txop[ac])
- WL_ERROR(("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__, fifo_names[queue], phylen, wlc->fragthresh[queue], dur, wlc->edcf_txop[ac]));
+ WL_ERROR("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",
+ wlc->pub->unit, __func__,
+ fifo_names[queue],
+ phylen, wlc->fragthresh[queue],
+ dur, wlc->edcf_txop[ac]);
}
}
return 0;
}
-void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs)
+void wlc_tbtt(struct wlc_info *wlc, d11regs_t *regs)
{
wlc_bsscfg_t *cfg = wlc->cfg;
@@ -6571,19 +6355,19 @@ void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs)
}
/* GP timer is a freerunning 32 bit counter, decrements at 1 us rate */
-void wlc_hwtimer_gptimer_set(wlc_info_t *wlc, uint us)
+void wlc_hwtimer_gptimer_set(struct wlc_info *wlc, uint us)
{
ASSERT(wlc->pub->corerev >= 3); /* no gptimer in earlier revs */
W_REG(wlc->osh, &wlc->regs->gptimer, us);
}
-void wlc_hwtimer_gptimer_abort(wlc_info_t *wlc)
+void wlc_hwtimer_gptimer_abort(struct wlc_info *wlc)
{
ASSERT(wlc->pub->corerev >= 3);
W_REG(wlc->osh, &wlc->regs->gptimer, 0);
}
-static void wlc_hwtimer_gptimer_cb(wlc_info_t *wlc)
+static void wlc_hwtimer_gptimer_cb(struct wlc_info *wlc)
{
/* when interrupt is generated, the counter is loaded with last value
* written and continue to decrement. So it has to be cleaned first
@@ -6596,7 +6380,7 @@ static void wlc_hwtimer_gptimer_cb(wlc_info_t *wlc)
* POLICY: no macinstatus change, no bounding loop.
* All dpc bounding should be handled in BMAC dpc, like txstatus and rxint
*/
-void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
+void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus)
{
d11regs_t *regs = wlc->regs;
#ifdef BCMDBG
@@ -6634,8 +6418,8 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
if (macintstatus & ~(MI_TBTT | MI_TXSTOP)) {
bcm_format_flags(int_flags, macintstatus, flagstr,
sizeof(flagstr));
- WL_TRACE(("wl%d: macintstatus 0x%x %s\n", wlc->pub->unit,
- macintstatus, flagstr));
+ WL_TRACE("wl%d: macintstatus 0x%x %s\n",
+ wlc->pub->unit, macintstatus, flagstr);
}
#endif /* BCMDBG */
@@ -6650,11 +6434,12 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
wlc_tbtt(wlc, regs);
if (macintstatus & MI_GP0) {
- WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc->pub->unit, wlc->pub->now));
+ WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n",
+ wlc->pub->unit, wlc->pub->now);
printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
- __func__, CHIPID(wlc->pub->sih->chip),
- CHIPREV(wlc->pub->sih->chiprev));
+ __func__, wlc->pub->sih->chip,
+ wlc->pub->sih->chiprev);
WLCNTINCR(wlc->pub->_cnt->psmwds);
@@ -6668,7 +6453,9 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
}
if (macintstatus & MI_RFDISABLE) {
- WL_ERROR(("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", wlc->pub->unit, R_REG(wlc->osh, &regs->phydebug) & PDBG_RFD));
+ WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n",
+ wlc->pub->unit,
+ R_REG(wlc->osh, &regs->phydebug) & PDBG_RFD);
/* delay the cleanup to wl_down in IBSS case */
if ((R_REG(wlc->osh, &regs->phydebug) & PDBG_RFD)) {
int idx;
@@ -6677,7 +6464,8 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
if (!BSSCFG_STA(bsscfg) || !bsscfg->enable
|| !bsscfg->BSS)
continue;
- WL_ERROR(("wl%d: wlc_dpc: rfdisable -> wlc_bsscfg_disable()\n", wlc->pub->unit));
+ WL_ERROR("wl%d: wlc_dpc: rfdisable -> wlc_bsscfg_disable()\n",
+ wlc->pub->unit);
}
}
}
@@ -6686,14 +6474,12 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus)
if (!pktq_empty(&wlc->active_queue->q))
wlc_send_q(wlc, wlc->active_queue);
-#ifndef WLC_HIGH_ONLY
ASSERT(wlc_ps_check(wlc));
-#endif
}
-static void *wlc_15420war(wlc_info_t *wlc, uint queue)
+static void *wlc_15420war(struct wlc_info *wlc, uint queue)
{
- hnddma_t *di;
+ struct hnddma_pub *di;
void *p;
ASSERT(queue < NFIFO);
@@ -6715,13 +6501,14 @@ static void *wlc_15420war(wlc_info_t *wlc, uint queue)
if (dma_txactive(wlc->hw->di[queue]) == 0) {
WLCNTINCR(wlc->pub->_cnt->txdmawar);
if (!dma_txreset(di))
- WL_ERROR(("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", wlc->pub->unit, __func__, queue));
+ WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n",
+ wlc->pub->unit, __func__, queue);
dma_txinit(di);
}
return p;
}
-static void wlc_war16165(wlc_info_t *wlc, bool tx)
+static void wlc_war16165(struct wlc_info *wlc, bool tx)
{
if (tx) {
/* the post-increment is used in STAY_AWAKE macro */
@@ -6737,14 +6524,14 @@ static void wlc_war16165(wlc_info_t *wlc, bool tx)
/* process an individual tx_status_t */
/* WLC_HIGH_API */
bool BCMFASTPATH
-wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
+wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2)
{
- void *p;
+ struct sk_buff *p;
uint queue;
d11txh_t *txh;
struct scb *scb = NULL;
bool free_pdu;
- osl_t *osh;
+ struct osl_info *osh;
int tx_rts, tx_frame_count, tx_rts_count;
uint totlen, supr_status;
bool lastframe;
@@ -6768,7 +6555,7 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
((txs->
status & TX_STATUS_FRM_RTX_MASK) >>
TX_STATUS_FRM_RTX_SHIFT));
- WL_ERROR(("%s: INTERMEDIATE but not AMPDU\n", __func__));
+ WL_ERROR("%s: INTERMEDIATE but not AMPDU\n", __func__);
return false;
}
@@ -6789,12 +6576,12 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
if (p == NULL)
goto fatal;
- txh = (d11txh_t *) PKTDATA(p);
+ txh = (d11txh_t *) (p->data);
mcl = ltoh16(txh->MacTxControlLow);
if (txs->phyerr) {
- WL_ERROR(("phyerr 0x%x, rate 0x%x\n", txs->phyerr,
- txh->MainRates));
+ WL_ERROR("phyerr 0x%x, rate 0x%x\n",
+ txs->phyerr, txh->MainRates);
wlc_print_txdesc(txh);
wlc_print_txstatus(txs);
}
@@ -6825,8 +6612,8 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
supr_status = txs->status & TX_STATUS_SUPR_MASK;
if (supr_status == TX_STATUS_SUPR_BADCH)
- WL_NONE(("%s: Pkt tx suppressed, possibly channel %d\n",
- __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)));
+ WL_NONE("%s: Pkt tx suppressed, possibly channel %d\n",
+ __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
tx_rts = htol16(txh->MacTxControlLow) & TXC_SENDRTS;
tx_frame_count =
@@ -6837,7 +6624,7 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
lastframe = (fc & FC_MOREFRAG) == 0;
if (!lastframe) {
- WL_ERROR(("Not last frame!\n"));
+ WL_ERROR("Not last frame!\n");
} else {
u16 sfbl, lfbl;
ieee80211_tx_info_clear_status(tx_info);
@@ -6879,17 +6666,17 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
wlc_txfifo_complete(wlc, queue, 1);
if (lastframe) {
- PKTSETNEXT(p, NULL);
- PKTSETLINK(p, NULL);
+ p->next = NULL;
+ p->prev = NULL;
wlc->txretried = 0;
/* remove PLCP & Broadcom tx descriptor header */
- PKTPULL(p, D11_PHY_HDR_LEN);
- PKTPULL(p, D11_TXH_LEN);
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
WLCNTINCR(wlc->pub->_cnt->ieee_tx_status);
} else {
- WL_ERROR(("%s: Not last frame => not calling tx_status\n",
- __func__));
+ WL_ERROR("%s: Not last frame => not calling tx_status\n",
+ __func__);
}
return false;
@@ -6897,24 +6684,18 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2)
fatal:
ASSERT(0);
if (p)
- PKTFREE(osh, p, true);
+ pkt_buf_free_skb(osh, p, true);
-#ifdef WLC_HIGH_ONLY
- /* If this is a split driver, do the big-hammer here.
- * If this is a monolithic driver, wlc_bmac.c:wlc_dpc() will do the big-hammer.
- */
- wl_init(wlc->wl);
-#endif
return true;
}
void BCMFASTPATH
-wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend)
+wlc_txfifo_complete(struct wlc_info *wlc, uint fifo, s8 txpktpend)
{
TXPKTPENDDEC(wlc, fifo, txpktpend);
- WL_TRACE(("wlc_txfifo_complete, pktpend dec %d to %d\n", txpktpend,
- TXPKTPENDGET(wlc, fifo)));
+ WL_TRACE("wlc_txfifo_complete, pktpend dec %d to %d\n",
+ txpktpend, TXPKTPENDGET(wlc, fifo));
/* There is more room; mark precedences related to this FIFO sendable */
WLC_TX_FIFO_ENAB(wlc, fifo);
@@ -7014,7 +6795,7 @@ u32 wlc_calc_tbtt_offset(u32 bp, u32 tsf_h, u32 tsf_l)
}
/* Update beacon listen interval in shared memory */
-void wlc_bcn_li_upd(wlc_info_t *wlc)
+void wlc_bcn_li_upd(struct wlc_info *wlc)
{
if (AP_ENAB(wlc->pub))
return;
@@ -7028,7 +6809,7 @@ void wlc_bcn_li_upd(wlc_info_t *wlc)
}
static void
-prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p,
+prep_mac80211_status(struct wlc_info *wlc, d11rxhdr_t *rxh, struct sk_buff *p,
struct ieee80211_rx_status *rx_status)
{
u32 tsf_l, tsf_h;
@@ -7061,7 +6842,7 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p,
/* qual */
rx_status->antenna = (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; /* ant */
- plcp = PKTDATA(p);
+ plcp = p->data;
rspec = wlc_compute_rspec(rxh, plcp);
if (IS_MCS(rspec)) {
@@ -7108,19 +6889,19 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p,
rx_status->rate_idx = 11;
break;
default:
- WL_ERROR(("%s: Unknown rate\n", __func__));
+ WL_ERROR("%s: Unknown rate\n", __func__);
}
/* Determine short preamble and rate_idx */
preamble = 0;
if (IS_CCK(rspec)) {
if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
- WL_ERROR(("Short CCK\n"));
+ WL_ERROR("Short CCK\n");
rx_status->flag |= RX_FLAG_SHORTPRE;
} else if (IS_OFDM(rspec)) {
rx_status->flag |= RX_FLAG_SHORTPRE;
} else {
- WL_ERROR(("%s: Unknown modulation\n", __func__));
+ WL_ERROR("%s: Unknown modulation\n", __func__);
}
}
@@ -7129,16 +6910,17 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p,
if (rxh->RxStatus1 & RXS_DECERR) {
rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
- WL_ERROR(("%s: RX_FLAG_FAILED_PLCP_CRC\n", __func__));
+ WL_ERROR("%s: RX_FLAG_FAILED_PLCP_CRC\n", __func__);
}
if (rxh->RxStatus1 & RXS_FCSERR) {
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- WL_ERROR(("%s: RX_FLAG_FAILED_FCS_CRC\n", __func__));
+ WL_ERROR("%s: RX_FLAG_FAILED_FCS_CRC\n", __func__);
}
}
static void
-wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p)
+wlc_recvctl(struct wlc_info *wlc, struct osl_info *osh, d11rxhdr_t *rxh,
+ struct sk_buff *p)
{
int len_mpdu;
struct ieee80211_rx_status rx_status;
@@ -7155,12 +6937,12 @@ wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p)
prep_mac80211_status(wlc, rxh, p, &rx_status);
/* mac header+body length, exclude CRC and plcp header */
- len_mpdu = PKTLEN(p) - D11_PHY_HDR_LEN - DOT11_FCS_LEN;
- PKTPULL(p, D11_PHY_HDR_LEN);
- PKTSETLEN(p, len_mpdu);
+ len_mpdu = p->len - D11_PHY_HDR_LEN - DOT11_FCS_LEN;
+ skb_pull(p, D11_PHY_HDR_LEN);
+ __skb_trim(p, len_mpdu);
- ASSERT(!PKTNEXT(p));
- ASSERT(!PKTLINK(p));
+ ASSERT(!(p->next));
+ ASSERT(!(p->prev));
ASSERT(IS_ALIGNED((unsigned long)skb->data, 2));
@@ -7168,17 +6950,17 @@ wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p)
ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
WLCNTINCR(wlc->pub->_cnt->ieee_rx);
- PKTUNALLOC(osh);
+ osh->pktalloced--;
return;
}
-void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list)
+void wlc_bss_list_free(struct wlc_info *wlc, wlc_bss_list_t *bss_list)
{
uint index;
wlc_bss_info_t *bi;
if (!bss_list) {
- WL_ERROR(("%s: Attempting to free NULL list\n", __func__));
+ WL_ERROR("%s: Attempting to free NULL list\n", __func__);
return;
}
/* inspect all BSS descriptor */
@@ -7201,48 +6983,48 @@ void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list)
* Param 'bound' indicates max. # frames to process before break out.
*/
/* WLC_HIGH_API */
-void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
+void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p)
{
d11rxhdr_t *rxh;
struct dot11_header *h;
- osl_t *osh;
+ struct osl_info *osh;
u16 fc;
uint len;
bool is_amsdu;
- WL_TRACE(("wl%d: wlc_recv\n", wlc->pub->unit));
+ WL_TRACE("wl%d: wlc_recv\n", wlc->pub->unit);
osh = wlc->osh;
/* frame starts with rxhdr */
- rxh = (d11rxhdr_t *) PKTDATA(p);
+ rxh = (d11rxhdr_t *) (p->data);
/* strip off rxhdr */
- PKTPULL(p, wlc->hwrxoff);
+ skb_pull(p, wlc->hwrxoff);
/* fixup rx header endianness */
ltoh16_buf((void *)rxh, sizeof(d11rxhdr_t));
/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
if (rxh->RxStatus1 & RXS_PBPRES) {
- if (PKTLEN(p) < 2) {
+ if (p->len < 2) {
WLCNTINCR(wlc->pub->_cnt->rxrunt);
- WL_ERROR(("wl%d: wlc_recv: rcvd runt of len %d\n",
- wlc->pub->unit, PKTLEN(p)));
+ WL_ERROR("wl%d: wlc_recv: rcvd runt of len %d\n",
+ wlc->pub->unit, p->len);
goto toss;
}
- PKTPULL(p, 2);
+ skb_pull(p, 2);
}
- h = (struct dot11_header *)(PKTDATA(p) + D11_PHY_HDR_LEN);
- len = PKTLEN(p);
+ h = (struct dot11_header *)(p->data + D11_PHY_HDR_LEN);
+ len = p->len;
if (rxh->RxStatus1 & RXS_FCSERR) {
if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
- WL_ERROR(("FCSERR while scanning******* - tossing\n"));
+ WL_ERROR("FCSERR while scanning******* - tossing\n");
goto toss;
} else {
- WL_ERROR(("RCSERR!!!\n"));
+ WL_ERROR("RCSERR!!!\n");
goto toss;
}
}
@@ -7261,10 +7043,10 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
if (!is_amsdu) {
/* CTS and ACK CTL frames are w/o a2 */
if (FC_TYPE(fc) == FC_TYPE_DATA || FC_TYPE(fc) == FC_TYPE_MNG) {
- if ((ETHER_ISNULLADDR(&h->a2) || ETHER_ISMULTI(&h->a2))) {
- WL_ERROR(("wl%d: %s: dropping a frame with "
- "invalid src mac address, a2: %pM\n",
- wlc->pub->unit, __func__, &h->a2));
+ if ((is_zero_ether_addr(h->a2.octet) ||
+ is_multicast_ether_addr(h->a2.octet))) {
+ WL_ERROR("wl%d: %s: dropping a frame with invalid src mac address, a2: %pM\n",
+ wlc->pub->unit, __func__, &h->a2);
WLCNTINCR(wlc->pub->_cnt->rxbadsrcmac);
goto toss;
}
@@ -7279,7 +7061,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
}
if (is_amsdu) {
- WL_ERROR(("%s: is_amsdu causing toss\n", __func__));
+ WL_ERROR("%s: is_amsdu causing toss\n", __func__);
goto toss;
}
@@ -7287,7 +7069,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
return;
toss:
- PKTFREE(osh, p, false);
+ pkt_buf_free_skb(osh, p, false);
}
/* calculate frame duration for Mixed-mode L-SIG spoofing, return
@@ -7297,12 +7079,12 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p)
* len = 3(nsyms + nstream + 3) - 3
*/
u16 BCMFASTPATH
-wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len)
+wlc_calc_lsig_len(struct wlc_info *wlc, ratespec_t ratespec, uint mac_len)
{
uint nsyms, len = 0, kNdps;
- WL_TRACE(("wl%d: wlc_calc_lsig_len: rate %d, len%d\n", wlc->pub->unit,
- RSPEC2RATE(ratespec), mac_len));
+ WL_TRACE("wl%d: wlc_calc_lsig_len: rate %d, len%d\n",
+ wlc->pub->unit, RSPEC2RATE(ratespec), mac_len);
if (IS_MCS(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
@@ -7338,7 +7120,7 @@ wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len)
/* calculate frame duration of a given rate and length, return time in usec unit */
uint BCMFASTPATH
-wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
+wlc_calc_frame_time(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type,
uint mac_len)
{
uint nsyms, dur = 0, Ndps, kNdps;
@@ -7346,11 +7128,12 @@ wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
if (rate == 0) {
ASSERT(0);
- WL_ERROR(("wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit));
+ WL_ERROR("wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit);
rate = WLC_RATE_1M;
}
- WL_TRACE(("wl%d: wlc_calc_frame_time: rspec 0x%x, preamble_type %d, len%d\n", wlc->pub->unit, ratespec, preamble_type, mac_len));
+ WL_TRACE("wl%d: wlc_calc_frame_time: rspec 0x%x, preamble_type %d, len%d\n",
+ wlc->pub->unit, ratespec, preamble_type, mac_len);
if (IS_MCS(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
@@ -7408,13 +7191,14 @@ wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
/* The opposite of wlc_calc_frame_time */
static uint
-wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
+wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type,
uint dur)
{
uint nsyms, mac_len, Ndps, kNdps;
uint rate = RSPEC2RATE(ratespec);
- WL_TRACE(("wl%d: wlc_calc_frame_len: rspec 0x%x, preamble_type %d, dur %d\n", wlc->pub->unit, ratespec, preamble_type, dur));
+ WL_TRACE("wl%d: wlc_calc_frame_len: rspec 0x%x, preamble_type %d, dur %d\n",
+ wlc->pub->unit, ratespec, preamble_type, dur);
if (IS_MCS(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
@@ -7454,10 +7238,10 @@ wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type,
}
static uint
-wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
+wlc_calc_ba_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type)
{
- WL_TRACE(("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n",
- wlc->pub->unit, rspec, preamble_type));
+ WL_TRACE("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
/* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
* or equal to the rate of the immediately previous frame in the FES
*/
@@ -7471,12 +7255,12 @@ wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
}
static uint BCMFASTPATH
-wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
+wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type)
{
uint dur = 0;
- WL_TRACE(("wl%d: wlc_calc_ack_time: rspec 0x%x, preamble_type %d\n",
- wlc->pub->unit, rspec, preamble_type));
+ WL_TRACE("wl%d: wlc_calc_ack_time: rspec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
/* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
* or equal to the rate of the immediately previous frame in the FES
*/
@@ -7491,15 +7275,15 @@ wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
}
static uint
-wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type)
+wlc_calc_cts_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type)
{
- WL_TRACE(("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n",
- wlc->pub->unit, rspec, preamble_type));
+ WL_TRACE("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
return wlc_calc_ack_time(wlc, rspec, preamble_type);
}
/* derive wlc->band->basic_rate[] table from 'rateset' */
-void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset)
+void wlc_rate_lookup_init(struct wlc_info *wlc, wlc_rateset_t *rateset)
{
u8 rate;
u8 mandatory;
@@ -7509,7 +7293,7 @@ void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset)
uint i;
/* incoming rates are in 500kbps units as in 802.11 Supported Rates */
- bzero(br, WLC_MAXRATE + 1);
+ memset(br, 0, WLC_MAXRATE + 1);
/* For each basic rate in the rates list, make an entry in the
* best basic lookup.
@@ -7523,7 +7307,8 @@ void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset)
rate = (rateset->rates[i] & RATE_MASK);
if (rate > WLC_MAXRATE) {
- WL_ERROR(("wlc_rate_lookup_init: invalid rate 0x%X in rate set\n", rateset->rates[i]));
+ WL_ERROR("wlc_rate_lookup_init: invalid rate 0x%X in rate set\n",
+ rateset->rates[i]);
continue;
}
@@ -7588,7 +7373,7 @@ void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset)
}
}
-static void wlc_write_rate_shm(wlc_info_t *wlc, u8 rate, u8 basic_rate)
+static void wlc_write_rate_shm(struct wlc_info *wlc, u8 rate, u8 basic_rate)
{
u8 phy_rate, index;
u8 basic_phy_rate, basic_index;
@@ -7621,7 +7406,7 @@ static void wlc_write_rate_shm(wlc_info_t *wlc, u8 rate, u8 basic_rate)
wlc_write_shm(wlc, (basic_table + index * 2), basic_ptr);
}
-static const wlc_rateset_t *wlc_rateset_get_hwrs(wlc_info_t *wlc)
+static const wlc_rateset_t *wlc_rateset_get_hwrs(struct wlc_info *wlc)
{
const wlc_rateset_t *rs_dflt;
@@ -7638,7 +7423,7 @@ static const wlc_rateset_t *wlc_rateset_get_hwrs(wlc_info_t *wlc)
return rs_dflt;
}
-void wlc_set_ratetable(wlc_info_t *wlc)
+void wlc_set_ratetable(struct wlc_info *wlc)
{
const wlc_rateset_t *rs_dflt;
wlc_rateset_t rs;
@@ -7674,7 +7459,8 @@ void wlc_set_ratetable(wlc_info_t *wlc)
* Return true if the specified rate is supported by the specified band.
* WLC_BAND_AUTO indicates the current band.
*/
-bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rspec, int band, bool verbose)
+bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rspec, int band,
+ bool verbose)
{
wlc_rateset_t *hw_rateset;
uint i;
@@ -7701,16 +7487,17 @@ bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rspec, int band, bool verbose)
return true;
error:
if (verbose) {
- WL_ERROR(("wl%d: wlc_valid_rate: rate spec 0x%x not in hw_rateset\n", wlc->pub->unit, rspec));
+ WL_ERROR("wl%d: wlc_valid_rate: rate spec 0x%x not in hw_rateset\n",
+ wlc->pub->unit, rspec);
}
return false;
}
-static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap)
+static void wlc_update_mimo_band_bwcap(struct wlc_info *wlc, u8 bwcap)
{
uint i;
- wlcband_t *band;
+ struct wlcband *band;
for (i = 0; i < NBANDS(wlc); i++) {
if (IS_SINGLEBAND_5G(wlc->deviceid))
@@ -7734,7 +7521,7 @@ static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap)
wlc->mimo_band_bwcap = bwcap;
}
-void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len)
+void wlc_mod_prb_rsp_rate_table(struct wlc_info *wlc, uint frame_len)
{
const wlc_rateset_t *rs_dflt;
wlc_rateset_t rs;
@@ -7777,14 +7564,14 @@ void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len)
}
u16
-wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, bool short_preamble,
- bool phydelay)
+wlc_compute_bcntsfoff(struct wlc_info *wlc, ratespec_t rspec,
+ bool short_preamble, bool phydelay)
{
uint bcntsfoff = 0;
if (IS_MCS(rspec)) {
- WL_ERROR(("wl%d: recd beacon with mcs rate; rspec 0x%x\n",
- wlc->pub->unit, rspec));
+ WL_ERROR("wl%d: recd beacon with mcs rate; rspec 0x%x\n",
+ wlc->pub->unit, rspec);
} else if (IS_OFDM(rspec)) {
/* tx delay from MAC through phy to air (2.1 usec) +
* phy header time (preamble + PLCP SIGNAL == 20 usec) +
@@ -7824,7 +7611,7 @@ wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, bool short_preamble,
* and included up to, but not including, the 4 byte FCS.
*/
static void
-wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec,
+wlc_bcn_prb_template(struct wlc_info *wlc, uint type, ratespec_t bcn_rspec,
wlc_bsscfg_t *cfg, u16 *buf, int *len)
{
cck_phy_hdr_t *plcp;
@@ -7843,7 +7630,7 @@ wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec,
*len = hdr_len + body_len; /* return actual size */
/* format PHY and MAC headers */
- bzero((char *)buf, hdr_len);
+ memset((char *)buf, 0, hdr_len);
plcp = (cck_phy_hdr_t *) buf;
@@ -7872,9 +7659,9 @@ wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec,
/* A1 filled in by MAC for prb resp, broadcast for bcn */
if (type == FC_BEACON)
bcopy((const char *)&ether_bcast, (char *)&h->da,
- ETHER_ADDR_LEN);
- bcopy((char *)&cfg->cur_etheraddr, (char *)&h->sa, ETHER_ADDR_LEN);
- bcopy((char *)&cfg->BSSID, (char *)&h->bssid, ETHER_ADDR_LEN);
+ ETH_ALEN);
+ bcopy((char *)&cfg->cur_etheraddr, (char *)&h->sa, ETH_ALEN);
+ bcopy((char *)&cfg->BSSID, (char *)&h->bssid, ETH_ALEN);
/* SEQ filled in by MAC */
@@ -7891,7 +7678,7 @@ int wlc_get_header_len()
* template updated.
* Otherwise, it updates the hardware template.
*/
-void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
+void wlc_bss_update_beacon(struct wlc_info *wlc, wlc_bsscfg_t *cfg)
{
int len = BCN_TMPL_LEN;
@@ -7907,7 +7694,7 @@ void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
u16 bcn[BCN_TMPL_LEN / 2];
u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
d11regs_t *regs = wlc->regs;
- osl_t *osh = NULL;
+ struct osl_info *osh = NULL;
osh = wlc->osh;
@@ -7944,7 +7731,7 @@ void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
/*
* Update all beacons for the system.
*/
-void wlc_update_beacon(wlc_info_t *wlc)
+void wlc_update_beacon(struct wlc_info *wlc)
{
int idx;
wlc_bsscfg_t *bsscfg;
@@ -7957,14 +7744,14 @@ void wlc_update_beacon(wlc_info_t *wlc)
}
/* Write ssid into shared memory */
-void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
+void wlc_shm_ssid_upd(struct wlc_info *wlc, wlc_bsscfg_t *cfg)
{
u8 *ssidptr = cfg->SSID;
u16 base = M_SSID;
u8 ssidbuf[DOT11_MAX_SSID_LEN];
/* padding the ssid with zero and copy it into shm */
- bzero(ssidbuf, DOT11_MAX_SSID_LEN);
+ memset(ssidbuf, 0, DOT11_MAX_SSID_LEN);
bcopy(ssidptr, ssidbuf, cfg->SSID_len);
wlc_copyto_shm(wlc, base, ssidbuf, DOT11_MAX_SSID_LEN);
@@ -7973,7 +7760,7 @@ void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg)
wlc_write_shm(wlc, M_SSIDLEN, (u16) cfg->SSID_len);
}
-void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend)
+void wlc_update_probe_resp(struct wlc_info *wlc, bool suspend)
{
int idx;
wlc_bsscfg_t *bsscfg;
@@ -7986,7 +7773,7 @@ void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend)
}
void
-wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend)
+wlc_bss_update_probe_resp(struct wlc_info *wlc, wlc_bsscfg_t *cfg, bool suspend)
{
u16 prb_resp[BCN_TMPL_LEN / 2];
int len = BCN_TMPL_LEN;
@@ -8027,9 +7814,9 @@ wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend)
}
/* prepares pdu for transmission. returns BCM error codes */
-int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop)
+int wlc_prep_pdu(struct wlc_info *wlc, struct sk_buff *pdu, uint *fifop)
{
- osl_t *osh;
+ struct osl_info *osh;
uint fifo;
d11txh_t *txh;
struct dot11_header *h;
@@ -8039,7 +7826,7 @@ int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop)
osh = wlc->osh;
ASSERT(pdu);
- txh = (d11txh_t *) PKTDATA(pdu);
+ txh = (d11txh_t *) (pdu->data);
ASSERT(txh);
h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
ASSERT(h);
@@ -8066,7 +7853,7 @@ int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop)
}
/* init tx reported rate mechanism */
-void wlc_reprate_init(wlc_info_t *wlc)
+void wlc_reprate_init(struct wlc_info *wlc)
{
int i;
wlc_bsscfg_t *bsscfg;
@@ -8080,13 +7867,13 @@ void wlc_reprate_init(wlc_info_t *wlc)
void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg)
{
bsscfg->txrspecidx = 0;
- bzero((char *)bsscfg->txrspec, sizeof(bsscfg->txrspec));
+ memset((char *)bsscfg->txrspec, 0, sizeof(bsscfg->txrspec));
}
/* Retrieve a consolidated set of revision information,
* typically for the WLC_GET_REVINFO ioctl
*/
-int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len)
+int wlc_get_revision_info(struct wlc_info *wlc, void *buf, uint len)
{
wlc_rev_info_t *rinfo = (wlc_rev_info_t *) buf;
@@ -8120,7 +7907,7 @@ int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len)
return BCME_OK;
}
-void wlc_default_rateset(wlc_info_t *wlc, wlc_rateset_t *rs)
+void wlc_default_rateset(struct wlc_info *wlc, wlc_rateset_t *rs)
{
wlc_rateset_default(rs, NULL, wlc->band->phytype, wlc->band->bandtype,
false, RATE_MASK_FULL, (bool) N_ENAB(wlc->pub),
@@ -8128,14 +7915,14 @@ void wlc_default_rateset(wlc_info_t *wlc, wlc_rateset_t *rs)
wlc->stf->txstreams);
}
-static void wlc_bss_default_init(wlc_info_t *wlc)
+static void wlc_bss_default_init(struct wlc_info *wlc)
{
chanspec_t chanspec;
- wlcband_t *band;
+ struct wlcband *band;
wlc_bss_info_t *bi = wlc->default_bss;
/* init default and target BSS with some sane initial values */
- bzero((char *)(bi), sizeof(wlc_bss_info_t));
+ memset((char *)(bi), 0, sizeof(wlc_bss_info_t));
bi->beacon_period = ISSIM_ENAB(wlc->pub->sih) ? BEACON_INTERVAL_DEF_QT :
BEACON_INTERVAL_DEFAULT;
bi->dtim_period = ISSIM_ENAB(wlc->pub->sih) ? DTIM_INTERVAL_DEF_QT :
@@ -8166,7 +7953,7 @@ static void wlc_bss_default_init(wlc_info_t *wlc)
/* Deferred event processing */
static void wlc_process_eventq(void *arg)
{
- wlc_info_t *wlc = (wlc_info_t *) arg;
+ struct wlc_info *wlc = (struct wlc_info *) arg;
wlc_event_t *etmp;
while ((etmp = wlc_eventq_deq(wlc->eventq))) {
@@ -8192,7 +7979,8 @@ wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high, u32 b_low)
}
static ratespec_t
-mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
+mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band,
+ u32 int_val)
{
u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
u8 rate = int_val & NRATE_RATE_MASK;
@@ -8211,8 +7999,8 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
if (N_ENAB(wlc->pub) && ismcs) {
/* mcs only allowed when nmode */
if (stf > PHY_TXC1_MODE_SDM) {
- WL_ERROR(("wl%d: %s: Invalid stf\n", WLCWLUNIT(wlc),
- __func__));
+ WL_ERROR("wl%d: %s: Invalid stf\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
@@ -8222,8 +8010,8 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
if (!CHSPEC_IS40(wlc->home_chanspec) ||
((stf != PHY_TXC1_MODE_SISO)
&& (stf != PHY_TXC1_MODE_CDD))) {
- WL_ERROR(("wl%d: %s: Invalid mcs 32\n",
- WLCWLUNIT(wlc), __func__));
+ WL_ERROR("wl%d: %s: Invalid mcs 32\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
@@ -8231,7 +8019,8 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
} else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
/* mcs > 7 must use stf SDM */
if (stf != PHY_TXC1_MODE_SDM) {
- WL_TRACE(("wl%d: %s: enabling SDM mode for mcs %d\n", WLCWLUNIT(wlc), __func__, rate));
+ WL_TRACE("wl%d: %s: enabling SDM mode for mcs %d\n",
+ WLCWLUNIT(wlc), __func__, rate);
stf = PHY_TXC1_MODE_SDM;
}
} else {
@@ -8239,37 +8028,37 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
if ((stf > PHY_TXC1_MODE_STBC) ||
(!WLC_STBC_CAP_PHY(wlc)
&& (stf == PHY_TXC1_MODE_STBC))) {
- WL_ERROR(("wl%d: %s: Invalid STBC\n",
- WLCWLUNIT(wlc), __func__));
+ WL_ERROR("wl%d: %s: Invalid STBC\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
}
} else if (IS_OFDM(rate)) {
if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
- WL_ERROR(("wl%d: %s: Invalid OFDM\n", WLCWLUNIT(wlc),
- __func__));
+ WL_ERROR("wl%d: %s: Invalid OFDM\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
} else if (IS_CCK(rate)) {
if ((cur_band->bandtype != WLC_BAND_2G)
|| (stf != PHY_TXC1_MODE_SISO)) {
- WL_ERROR(("wl%d: %s: Invalid CCK\n", WLCWLUNIT(wlc),
- __func__));
+ WL_ERROR("wl%d: %s: Invalid CCK\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
} else {
- WL_ERROR(("wl%d: %s: Unknown rate type\n", WLCWLUNIT(wlc),
- __func__));
+ WL_ERROR("wl%d: %s: Unknown rate type\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
/* make sure multiple antennae are available for non-siso rates */
if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
- WL_ERROR(("wl%d: %s: SISO antenna but !SISO request\n",
- WLCWLUNIT(wlc), __func__));
+ WL_ERROR("wl%d: %s: SISO antenna but !SISO request\n",
+ WLCWLUNIT(wlc), __func__);
bcmerror = BCME_RANGE;
goto done;
}
@@ -8300,13 +8089,13 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val)
return rspec;
done:
- WL_ERROR(("Hoark\n"));
+ WL_ERROR("Hoark\n");
return rate;
}
/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
static int
-wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
+wlc_duty_cycle_set(struct wlc_info *wlc, int duty_cycle, bool isOFDM,
bool writeToShm)
{
int idle_busy_ratio_x_16 = 0;
@@ -8314,8 +8103,7 @@ wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
M_TX_IDLE_BUSY_RATIO_X_16_CCK;
if (duty_cycle > 100 || duty_cycle < 0) {
- WL_ERROR(("wl%d: duty cycle value off limit\n",
- wlc->pub->unit));
+ WL_ERROR("wl%d: duty cycle value off limit\n", wlc->pub->unit);
return BCME_RANGE;
}
if (duty_cycle)
@@ -8335,7 +8123,7 @@ wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM,
/* Read a single u16 from shared memory.
* SHM 'offset' needs to be an even address
*/
-u16 wlc_read_shm(wlc_info_t *wlc, uint offset)
+u16 wlc_read_shm(struct wlc_info *wlc, uint offset)
{
return wlc_bmac_read_shm(wlc->hw, offset);
}
@@ -8343,7 +8131,7 @@ u16 wlc_read_shm(wlc_info_t *wlc, uint offset)
/* Write a single u16 to shared memory.
* SHM 'offset' needs to be an even address
*/
-void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v)
+void wlc_write_shm(struct wlc_info *wlc, uint offset, u16 v)
{
wlc_bmac_write_shm(wlc->hw, offset, v);
}
@@ -8352,7 +8140,7 @@ void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v)
* SHM 'offset' needs to be an even address and
* Range length 'len' must be an even number of bytes
*/
-void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len)
+void wlc_set_shm(struct wlc_info *wlc, uint offset, u16 v, int len)
{
/* offset and len need to be even */
ASSERT((offset & 1) == 0);
@@ -8368,7 +8156,7 @@ void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len)
* SHM 'offset' needs to be an even address and
* Buffer length 'len' must be an even number of bytes
*/
-void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, int len)
+void wlc_copyto_shm(struct wlc_info *wlc, uint offset, const void *buf, int len)
{
/* offset and len need to be even */
ASSERT((offset & 1) == 0);
@@ -8384,7 +8172,7 @@ void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, int len)
* SHM 'offset' needs to be an even address and
* Buffer length 'len' must be an even number of bytes
*/
-void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len)
+void wlc_copyfrom_shm(struct wlc_info *wlc, uint offset, void *buf, int len)
{
/* offset and len need to be even */
ASSERT((offset & 1) == 0);
@@ -8397,71 +8185,73 @@ void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len)
}
/* wrapper BMAC functions to for HIGH driver access */
-void wlc_mctrl(wlc_info_t *wlc, u32 mask, u32 val)
+void wlc_mctrl(struct wlc_info *wlc, u32 mask, u32 val)
{
wlc_bmac_mctrl(wlc->hw, mask, val);
}
-void wlc_corereset(wlc_info_t *wlc, u32 flags)
+void wlc_corereset(struct wlc_info *wlc, u32 flags)
{
wlc_bmac_corereset(wlc->hw, flags);
}
-void wlc_mhf(wlc_info_t *wlc, u8 idx, u16 mask, u16 val, int bands)
+void wlc_mhf(struct wlc_info *wlc, u8 idx, u16 mask, u16 val, int bands)
{
wlc_bmac_mhf(wlc->hw, idx, mask, val, bands);
}
-u16 wlc_mhf_get(wlc_info_t *wlc, u8 idx, int bands)
+u16 wlc_mhf_get(struct wlc_info *wlc, u8 idx, int bands)
{
return wlc_bmac_mhf_get(wlc->hw, idx, bands);
}
-int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks)
+int wlc_xmtfifo_sz_get(struct wlc_info *wlc, uint fifo, uint *blocks)
{
return wlc_bmac_xmtfifo_sz_get(wlc->hw, fifo, blocks);
}
-void wlc_write_template_ram(wlc_info_t *wlc, int offset, int len, void *buf)
+void wlc_write_template_ram(struct wlc_info *wlc, int offset, int len,
+ void *buf)
{
wlc_bmac_write_template_ram(wlc->hw, offset, len, buf);
}
-void wlc_write_hw_bcntemplates(wlc_info_t *wlc, void *bcn, int len, bool both)
+void wlc_write_hw_bcntemplates(struct wlc_info *wlc, void *bcn, int len,
+ bool both)
{
wlc_bmac_write_hw_bcntemplates(wlc->hw, bcn, len, both);
}
void
-wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset,
+wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset,
const struct ether_addr *addr)
{
wlc_bmac_set_addrmatch(wlc->hw, match_reg_offset, addr);
}
-void wlc_set_rcmta(wlc_info_t *wlc, int idx, const struct ether_addr *addr)
+void wlc_set_rcmta(struct wlc_info *wlc, int idx, const struct ether_addr *addr)
{
wlc_bmac_set_rcmta(wlc->hw, idx, addr);
}
-void wlc_read_tsf(wlc_info_t *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr)
+void wlc_read_tsf(struct wlc_info *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr)
{
wlc_bmac_read_tsf(wlc->hw, tsf_l_ptr, tsf_h_ptr);
}
-void wlc_set_cwmin(wlc_info_t *wlc, u16 newmin)
+void wlc_set_cwmin(struct wlc_info *wlc, u16 newmin)
{
wlc->band->CWmin = newmin;
wlc_bmac_set_cwmin(wlc->hw, newmin);
}
-void wlc_set_cwmax(wlc_info_t *wlc, u16 newmax)
+void wlc_set_cwmax(struct wlc_info *wlc, u16 newmax)
{
wlc->band->CWmax = newmax;
wlc_bmac_set_cwmax(wlc->hw, newmax);
}
-void wlc_fifoerrors(wlc_info_t *wlc)
+void wlc_fifoerrors(struct wlc_info *wlc)
{
wlc_bmac_fifoerrors(wlc->hw);
@@ -8469,19 +8259,16 @@ void wlc_fifoerrors(wlc_info_t *wlc)
/* Search mem rw utilities */
-void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit)
+void wlc_pllreq(struct wlc_info *wlc, bool set, mbool req_bit)
{
wlc_bmac_pllreq(wlc->hw, set, req_bit);
}
-void wlc_reset_bmac_done(wlc_info_t *wlc)
+void wlc_reset_bmac_done(struct wlc_info *wlc)
{
-#ifdef WLC_HIGH_ONLY
- wlc->reset_bmac_pending = false;
-#endif
}
-void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode)
+void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode)
{
wlc->ht_cap.cap &= ~HT_CAP_MIMO_PS_MASK;
wlc->ht_cap.cap |= (mimops_mode << HT_CAP_MIMO_PS_SHIFT);
@@ -8494,7 +8281,7 @@ void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode)
/* check for the particular priority flow control bit being set */
bool
-wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *q, int prio)
+wlc_txflowcontrol_prio_isset(struct wlc_info *wlc, wlc_txq_info_t *q, int prio)
{
uint prio_mask;
@@ -8509,12 +8296,13 @@ wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *q, int prio)
}
/* propogate the flow control to all interfaces using the given tx queue */
-void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio)
+void wlc_txflowcontrol(struct wlc_info *wlc, wlc_txq_info_t *qi,
+ bool on, int prio)
{
uint prio_bits;
uint cur_bits;
- WL_ERROR(("%s: flow contro kicks in\n", __func__));
+ WL_ERROR("%s: flow control kicks in\n", __func__);
if (prio == ALLPRIO) {
prio_bits = TXQ_STOP_FOR_PRIOFC_MASK;
@@ -8551,7 +8339,7 @@ void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio)
}
void
-wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
+wlc_txflowcontrol_override(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on,
uint override)
{
uint prev_override;
@@ -8598,7 +8386,7 @@ wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
}
}
-static void wlc_txflowcontrol_reset(wlc_info_t *wlc)
+static void wlc_txflowcontrol_reset(struct wlc_info *wlc)
{
wlc_txq_info_t *qi;
@@ -8611,10 +8399,10 @@ static void wlc_txflowcontrol_reset(wlc_info_t *wlc)
}
static void
-wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
+wlc_txflowcontrol_signal(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on,
int prio)
{
- wlc_if_t *wlcif;
+ struct wlc_if *wlcif;
for (wlcif = wlc->wlcif_list; wlcif != NULL; wlcif = wlcif->next) {
if (wlcif->qi == qi && wlcif->flags & WLC_IF_LINKED)
@@ -8622,7 +8410,7 @@ wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
}
}
-static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh)
+static wlc_txq_info_t *wlc_txq_alloc(struct wlc_info *wlc, struct osl_info *osh)
{
wlc_txq_info_t *qi, *p;
@@ -8652,7 +8440,8 @@ static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh)
return qi;
}
-static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi)
+static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh,
+ wlc_txq_info_t *qi)
{
wlc_txq_info_t *p;
diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h
index 6a77591234b7..5df996b78911 100644
--- a/drivers/staging/brcm80211/sys/wlc_mac80211.h
+++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h
@@ -17,19 +17,10 @@
#ifndef _wlc_h_
#define _wlc_h_
-#include <wlc_types.h>
-
-#include <wl_dbg.h>
#include <wlioctl.h>
-#include <wlc_event.h>
#include <wlc_phy_hal.h>
#include <wlc_channel.h>
-#ifdef WLC_SPLIT
-#include <bcm_rpc.h>
-#endif
-
#include <wlc_bsscfg.h>
-
#include <wlc_scb.h>
#define MA_WINDOW_SZ 8 /* moving average window size */
@@ -220,15 +211,11 @@ extern const u8 prio2fifo[];
* (some platforms return all 0).
* If clocks are present, call the sb routine which will figure out if the device is removed.
*/
-#ifdef WLC_HIGH_ONLY
-#define DEVICEREMOVED(wlc) (!wlc->device_present)
-#else
#define DEVICEREMOVED(wlc) \
((wlc->hw->clk) ? \
((R_REG(wlc->hw->osh, &wlc->hw->regs->maccontrol) & \
(MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN) : \
(si_deviceremoved(wlc->hw->sih)))
-#endif /* WLC_HIGH_ONLY */
#define WLCWLUNIT(wlc) ((wlc)->pub->unit)
@@ -315,22 +302,20 @@ typedef struct wlc_stf {
/*
* core state (mac)
*/
-typedef struct wlccore {
-#ifdef WLC_LOW
+struct wlccore {
uint coreidx; /* # sb enumerated core */
/* fifo */
uint *txavail[NFIFO]; /* # tx descriptors available */
s16 txpktpend[NFIFO]; /* tx admission control */
-#endif /* WLC_LOW */
macstat_t *macstat_snapshot; /* mac hw prev read values */
-} wlccore_t;
+};
/*
* band state (phy+ana+radio)
*/
-typedef struct wlcband {
+struct wlcband {
int bandtype; /* WLC_BAND_2G, WLC_BAND_5G */
uint bandunit; /* bandstate[] index */
@@ -359,13 +344,13 @@ typedef struct wlcband {
u16 CWmin; /* The minimum size of contention window, in unit of aSlotTime */
u16 CWmax; /* The maximum size of contention window, in unit of aSlotTime */
u16 bcntsfoff; /* beacon tsf offset */
-} wlcband_t;
+};
/* generic function callback takes just one arg */
typedef void (*cb_fn_t) (void *);
/* tx completion callback takes 3 args */
-typedef void (*pkcb_fn_t) (wlc_info_t *wlc, uint txstatus, void *arg);
+typedef void (*pkcb_fn_t) (struct wlc_info *wlc, uint txstatus, void *arg);
typedef struct pkt_cb {
pkcb_fn_t fn; /* function to call when tx frame completes */
@@ -398,14 +383,14 @@ typedef struct dumpcb_s {
/* virtual interface */
struct wlc_if {
- wlc_if_t *next;
+ struct wlc_if *next;
u8 type; /* WLC_IFTYPE_BSS or WLC_IFTYPE_WDS */
u8 index; /* assigned in wl_add_if(), index of the wlif if any,
* not necessarily corresponding to bsscfg._idx or
* AID2PVBMAP(scb).
*/
u8 flags; /* flags for the interface */
- wl_if_t *wlif; /* pointer to wlif */
+ struct wl_if *wlif; /* pointer to wlif */
struct wlc_txq_info *qi; /* pointer to associated tx queue */
union {
struct scb *scb; /* pointer to scb if WLC_IFTYPE_WDS */
@@ -416,7 +401,6 @@ struct wlc_if {
/* flags for the interface */
#define WLC_IF_LINKED 0x02 /* this interface is linked to a wl_if */
-#ifdef WLC_LOW
typedef struct wlc_hwband {
int bandtype; /* WLC_BAND_2G, WLC_BAND_5G */
uint bandunit; /* bandstate[] index */
@@ -433,20 +417,15 @@ typedef struct wlc_hwband {
wlc_phy_t *pi; /* pointer to phy specific information */
bool abgphy_encore;
} wlc_hwband_t;
-#endif /* WLC_LOW */
struct wlc_hw_info {
-#ifdef WLC_SPLIT
- rpc_info_t *rpc; /* Handle to RPC module */
-#endif
- osl_t *osh; /* pointer to os handle */
+ struct osl_info *osh; /* pointer to os handle */
bool _piomode; /* true if pio mode */
- wlc_info_t *wlc;
+ struct wlc_info *wlc;
/* fifo */
- hnddma_t *di[NFIFO]; /* hnddma handles, per fifo */
+ struct hnddma_pub *di[NFIFO]; /* hnddma handles, per fifo */
-#ifdef WLC_LOW
uint unit; /* device instance number */
/* version info */
@@ -497,31 +476,21 @@ struct wlc_hw_info {
bool forcefastclk; /* true if the h/w is forcing the use of fast clk */
bool clk; /* core is out of reset and has clock */
bool sbclk; /* sb has clock */
- bmac_pmq_t *bmac_pmq; /* bmac PM states derived from ucode PMQ */
+ struct bmac_pmq *bmac_pmq; /* bmac PM states derived from ucode PMQ */
bool phyclk; /* phy is out of reset and has clock */
bool dma_lpbk; /* core is in DMA loopback */
-#ifdef BCMSDIO
- void *sdh;
-#endif
bool ucode_loaded; /* true after ucode downloaded */
-#ifdef WLC_LOW_ONLY
- struct wl_timer *wdtimer; /* timer for watchdog routine */
- struct ether_addr orig_etheraddr; /* original hw ethernet address */
- u16 rpc_dngl_agg; /* rpc agg control for dongle */
- u32 mem_required_def; /* memory required to replenish RX DMA ring */
- u32 mem_required_lower; /* memory required with lower RX bound */
- u32 mem_required_least; /* minimum memory requirement to handle RX */
-
-#endif /* WLC_LOW_ONLY */
u8 hw_stf_ss_opmode; /* STF single stream operation mode */
u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic
* 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board
*/
- u32 antsel_avail; /* put antsel_info_t here if more info is needed */
-#endif /* WLC_LOW */
+ u32 antsel_avail; /*
+ * put struct antsel_info here if more info is
+ * needed
+ */
};
/* TX Queue information
@@ -541,15 +510,12 @@ typedef struct wlc_txq_info {
* Principal common (os-independent) software data structure.
*/
struct wlc_info {
- wlc_pub_t *pub; /* pointer to wlc public state */
- osl_t *osh; /* pointer to os handle */
+ struct wlc_pub *pub; /* pointer to wlc public state */
+ struct osl_info *osh; /* pointer to os handle */
struct wl_info *wl; /* pointer to os-specific private state */
d11regs_t *regs; /* pointer to device registers */
- wlc_hw_info_t *hw; /* HW related state used primarily by BMAC */
-#ifdef WLC_SPLIT
- rpc_info_t *rpc; /* Handle to RPC module */
-#endif
+ struct wlc_hw_info *hw; /* HW related state used primarily by BMAC */
/* clock */
int clkreq_override; /* setting for clkreq for PCIE : Auto, 0, 1 */
@@ -566,10 +532,11 @@ struct wlc_info {
bool clk; /* core is out of reset and has clock */
/* multiband */
- wlccore_t *core; /* pointer to active io core */
- wlcband_t *band; /* pointer to active per-band state */
- wlccore_t *corestate; /* per-core state (one per hw core) */
- wlcband_t *bandstate[MAXBANDS]; /* per-band state (one per phy/radio) */
+ struct wlccore *core; /* pointer to active io core */
+ struct wlcband *band; /* pointer to active per-band state */
+ struct wlccore *corestate; /* per-core state (one per hw core) */
+ /* per-band state (one per phy/radio): */
+ struct wlcband *bandstate[MAXBANDS];
bool war16165; /* PCI slow clock 16165 war flag */
@@ -584,15 +551,9 @@ struct wlc_info {
s8 txpwr_local_max; /* regulatory local txpwr max */
u8 txpwr_local_constraint; /* local power contraint in dB */
-#ifdef WLC_HIGH_ONLY
- rpctx_info_t *rpctx; /* RPC TX module */
- bool reset_bmac_pending; /* bmac reset is in progressing */
- u32 rpc_agg; /* host agg: bit 16-31, bmac agg: bit 0-15 */
- u32 rpc_msglevel; /* host rpc: bit 16-31, bmac rpc: bit 0-15 */
-#endif
- ampdu_info_t *ampdu; /* ampdu module handler */
- antsel_info_t *asi; /* antsel module handler */
+ struct ampdu_info *ampdu; /* ampdu module handler */
+ struct antsel_info *asi; /* antsel module handler */
wlc_cm_info_t *cmi; /* channel manager module handler */
void *btparam; /* bus type specific cookie */
@@ -792,8 +753,6 @@ struct wlc_info {
ac_bitmap_t apsd_trigger_ac; /* Permissible Acess Category in which APSD Null
* Trigger frames can be send
*/
- wlc_ap_info_t *ap;
-
u8 htphy_membership; /* HT PHY membership */
bool _regulatory_domain; /* 802.11d enabled? */
@@ -811,7 +770,7 @@ struct wlc_info {
u16 next_bsscfg_ID;
- wlc_if_t *wlcif_list; /* linked list of wlc_if structs */
+ struct wlc_if *wlcif_list; /* linked list of wlc_if structs */
wlc_txq_info_t *active_queue; /* txq for the currently active transmit context */
u32 mpc_dur; /* total time (ms) in mpc mode except for the
* portion since radio is turned off last time
@@ -825,8 +784,8 @@ struct wlc_info {
/* antsel module specific state */
struct antsel_info {
- wlc_info_t *wlc; /* pointer to main wlc structure */
- wlc_pub_t *pub; /* pointer to public fn */
+ struct wlc_info *wlc; /* pointer to main wlc structure */
+ struct wlc_pub *pub; /* pointer to public fn */
u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic
* 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board
*/
@@ -842,23 +801,9 @@ struct antsel_info {
#define IS_MBAND_UNLOCKED(wlc) \
((NBANDS(wlc) > 1) && !(wlc)->bandlocked)
-#ifdef WLC_LOW
#define WLC_BAND_PI_RADIO_CHANSPEC wlc_phy_chanspec_get(wlc->band->pi)
-#else
-#define WLC_BAND_PI_RADIO_CHANSPEC (wlc->chanspec)
-#endif
/* sum the individual fifo tx pending packet counts */
-#if defined(WLC_HIGH_ONLY)
-#define TXPKTPENDTOT(wlc) (wlc_rpctx_txpktpend((wlc)->rpctx, 0, true))
-#define TXPKTPENDGET(wlc, fifo) (wlc_rpctx_txpktpend((wlc)->rpctx, (fifo), false))
-#define TXPKTPENDINC(wlc, fifo, val) (wlc_rpctx_txpktpendinc((wlc)->rpctx, (fifo), (val)))
-#define TXPKTPENDDEC(wlc, fifo, val) (wlc_rpctx_txpktpenddec((wlc)->rpctx, (fifo), (val)))
-#define TXPKTPENDCLR(wlc, fifo) (wlc_rpctx_txpktpendclr((wlc)->rpctx, (fifo)))
-#define TXAVAIL(wlc, fifo) (wlc_rpctx_txavail((wlc)->rpctx, (fifo)))
-#define GETNEXTTXP(wlc, _queue) (wlc_rpctx_getnexttxp((wlc)->rpctx, (_queue)))
-
-#else
#define TXPKTPENDTOT(wlc) ((wlc)->core->txpktpend[0] + (wlc)->core->txpktpend[1] + \
(wlc)->core->txpktpend[2] + (wlc)->core->txpktpend[3])
#define TXPKTPENDGET(wlc, fifo) ((wlc)->core->txpktpend[(fifo)])
@@ -868,48 +813,49 @@ struct antsel_info {
#define TXAVAIL(wlc, fifo) (*(wlc)->core->txavail[(fifo)])
#define GETNEXTTXP(wlc, _queue) \
dma_getnexttxp((wlc)->hw->di[(_queue)], HNDDMA_RANGE_TRANSMITTED)
-#endif /* WLC_HIGH_ONLY */
#define WLC_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \
- ((len1 == len2) && !bcmp(ssid1, ssid2, len1))
-
-/* API shared by both WLC_HIGH and WLC_LOW driver */
-extern void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus);
-extern void wlc_fatal_error(wlc_info_t *wlc);
-extern void wlc_bmac_rpc_watchdog(wlc_info_t *wlc);
-extern void wlc_recv(wlc_info_t *wlc, void *p);
-extern bool wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2);
-extern void wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit,
- s8 txpktpend);
-extern void wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend);
-extern void wlc_info_init(wlc_info_t *wlc, int unit);
+ ((len1 == len2) && !memcmp(ssid1, ssid2, len1))
+
+extern void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus);
+extern void wlc_fatal_error(struct wlc_info *wlc);
+extern void wlc_bmac_rpc_watchdog(struct wlc_info *wlc);
+extern void wlc_recv(struct wlc_info *wlc, struct sk_buff *p);
+extern bool wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2);
+extern void wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p,
+ bool commit, s8 txpktpend);
+extern void wlc_txfifo_complete(struct wlc_info *wlc, uint fifo, s8 txpktpend);
+extern void wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu,
+ uint prec);
+extern void wlc_info_init(struct wlc_info *wlc, int unit);
extern void wlc_print_txstatus(tx_status_t *txs);
-extern int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks);
-extern void wlc_write_template_ram(wlc_info_t *wlc, int offset, int len,
+extern int wlc_xmtfifo_sz_get(struct wlc_info *wlc, uint fifo, uint *blocks);
+extern void wlc_write_template_ram(struct wlc_info *wlc, int offset, int len,
void *buf);
-extern void wlc_write_hw_bcntemplates(wlc_info_t *wlc, void *bcn, int len,
+extern void wlc_write_hw_bcntemplates(struct wlc_info *wlc, void *bcn, int len,
bool both);
#if defined(BCMDBG)
-extern void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr);
+extern void wlc_get_rcmta(struct wlc_info *wlc, int idx,
+ struct ether_addr *addr);
#endif
-extern void wlc_set_rcmta(wlc_info_t *wlc, int idx,
+extern void wlc_set_rcmta(struct wlc_info *wlc, int idx,
const struct ether_addr *addr);
-extern void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset,
+extern void wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset,
const struct ether_addr *addr);
-extern void wlc_read_tsf(wlc_info_t *wlc, u32 *tsf_l_ptr,
+extern void wlc_read_tsf(struct wlc_info *wlc, u32 *tsf_l_ptr,
u32 *tsf_h_ptr);
-extern void wlc_set_cwmin(wlc_info_t *wlc, u16 newmin);
-extern void wlc_set_cwmax(wlc_info_t *wlc, u16 newmax);
-extern void wlc_fifoerrors(wlc_info_t *wlc);
-extern void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit);
-extern void wlc_reset_bmac_done(wlc_info_t *wlc);
-extern void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val);
-extern void wlc_hwtimer_gptimer_set(wlc_info_t *wlc, uint us);
-extern void wlc_hwtimer_gptimer_abort(wlc_info_t *wlc);
+extern void wlc_set_cwmin(struct wlc_info *wlc, u16 newmin);
+extern void wlc_set_cwmax(struct wlc_info *wlc, u16 newmax);
+extern void wlc_fifoerrors(struct wlc_info *wlc);
+extern void wlc_pllreq(struct wlc_info *wlc, bool set, mbool req_bit);
+extern void wlc_reset_bmac_done(struct wlc_info *wlc);
+extern void wlc_protection_upd(struct wlc_info *wlc, uint idx, int val);
+extern void wlc_hwtimer_gptimer_set(struct wlc_info *wlc, uint us);
+extern void wlc_hwtimer_gptimer_abort(struct wlc_info *wlc);
#if defined(BCMDBG)
extern void wlc_print_rxh(d11rxhdr_t *rxh);
-extern void wlc_print_hdrs(wlc_info_t *wlc, const char *prefix, u8 *frame,
+extern void wlc_print_hdrs(struct wlc_info *wlc, const char *prefix, u8 *frame,
d11txh_t *txh, d11rxhdr_t *rxh, uint len);
extern void wlc_print_txdesc(d11txh_t *txh);
#endif
@@ -917,124 +863,126 @@ extern void wlc_print_txdesc(d11txh_t *txh);
extern void wlc_print_dot11_mac_hdr(u8 *buf, int len);
#endif
-#ifdef WLC_LOW
-extern void wlc_setxband(wlc_hw_info_t *wlc_hw, uint bandunit);
-extern void wlc_coredisable(wlc_hw_info_t *wlc_hw);
-#endif
+extern void wlc_setxband(struct wlc_hw_info *wlc_hw, uint bandunit);
+extern void wlc_coredisable(struct wlc_hw_info *wlc_hw);
-extern bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rate, int band,
+extern bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rate, int band,
bool verbose);
-extern void wlc_ap_upd(wlc_info_t *wlc);
+extern void wlc_ap_upd(struct wlc_info *wlc);
/* helper functions */
-extern void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg);
-extern int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config);
+extern void wlc_shm_ssid_upd(struct wlc_info *wlc, wlc_bsscfg_t *cfg);
+extern int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config);
-extern void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc);
-extern void wlc_mac_bcn_promisc(wlc_info_t *wlc);
-extern void wlc_mac_promisc(wlc_info_t *wlc);
-extern void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on,
+extern void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc);
+extern void wlc_mac_bcn_promisc(struct wlc_info *wlc);
+extern void wlc_mac_promisc(struct wlc_info *wlc);
+extern void wlc_txflowcontrol(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on,
int prio);
-extern void wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi,
+extern void wlc_txflowcontrol_override(struct wlc_info *wlc, wlc_txq_info_t *qi,
bool on, uint override);
-extern bool wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *qi,
- int prio);
-extern void wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi);
-extern int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifo);
+extern bool wlc_txflowcontrol_prio_isset(struct wlc_info *wlc,
+ wlc_txq_info_t *qi, int prio);
+extern void wlc_send_q(struct wlc_info *wlc, wlc_txq_info_t *qi);
+extern int wlc_prep_pdu(struct wlc_info *wlc, struct sk_buff *pdu, uint *fifo);
-extern u16 wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec,
+extern u16 wlc_calc_lsig_len(struct wlc_info *wlc, ratespec_t ratespec,
uint mac_len);
-extern ratespec_t wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec,
+extern ratespec_t wlc_rspec_to_rts_rspec(struct wlc_info *wlc, ratespec_t rspec,
bool use_rspec, u16 mimo_ctlchbw);
-extern u16 wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only,
+extern u16 wlc_compute_rtscts_dur(struct wlc_info *wlc, bool cts_only,
ratespec_t rts_rate, ratespec_t frame_rate,
u8 rts_preamble_type,
u8 frame_preamble_type, uint frame_len,
bool ba);
-extern void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs);
+extern void wlc_tbtt(struct wlc_info *wlc, d11regs_t *regs);
#if defined(BCMDBG)
-extern void wlc_dump_ie(wlc_info_t *wlc, bcm_tlv_t *ie, struct bcmstrbuf *b);
+extern void wlc_dump_ie(struct wlc_info *wlc, bcm_tlv_t *ie,
+ struct bcmstrbuf *b);
#endif
-extern bool wlc_ps_check(wlc_info_t *wlc);
-extern void wlc_reprate_init(wlc_info_t *wlc);
+extern bool wlc_ps_check(struct wlc_info *wlc);
+extern void wlc_reprate_init(struct wlc_info *wlc);
extern void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg);
extern void wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high,
u32 b_low);
extern u32 wlc_calc_tbtt_offset(u32 bi, u32 tsf_h, u32 tsf_l);
/* Shared memory access */
-extern void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v);
-extern u16 wlc_read_shm(wlc_info_t *wlc, uint offset);
-extern void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len);
-extern void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf,
+extern void wlc_write_shm(struct wlc_info *wlc, uint offset, u16 v);
+extern u16 wlc_read_shm(struct wlc_info *wlc, uint offset);
+extern void wlc_set_shm(struct wlc_info *wlc, uint offset, u16 v, int len);
+extern void wlc_copyto_shm(struct wlc_info *wlc, uint offset, const void *buf,
int len);
-extern void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len);
+extern void wlc_copyfrom_shm(struct wlc_info *wlc, uint offset, void *buf,
+ int len);
-extern void wlc_update_beacon(wlc_info_t *wlc);
-extern void wlc_bss_update_beacon(wlc_info_t *wlc, struct wlc_bsscfg *bsscfg);
+extern void wlc_update_beacon(struct wlc_info *wlc);
+extern void wlc_bss_update_beacon(struct wlc_info *wlc,
+ struct wlc_bsscfg *bsscfg);
-extern void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend);
-extern void wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg,
+extern void wlc_update_probe_resp(struct wlc_info *wlc, bool suspend);
+extern void wlc_bss_update_probe_resp(struct wlc_info *wlc, wlc_bsscfg_t *cfg,
bool suspend);
-extern bool wlc_ismpc(wlc_info_t *wlc);
-extern bool wlc_is_non_delay_mpc(wlc_info_t *wlc);
-extern void wlc_radio_mpc_upd(wlc_info_t *wlc);
-extern bool wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec);
-extern bool wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt,
- int prec, bool head);
-extern u16 wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec);
-extern void wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rate, uint length,
+extern bool wlc_ismpc(struct wlc_info *wlc);
+extern bool wlc_is_non_delay_mpc(struct wlc_info *wlc);
+extern void wlc_radio_mpc_upd(struct wlc_info *wlc);
+extern bool wlc_prec_enq(struct wlc_info *wlc, struct pktq *q, void *pkt,
+ int prec);
+extern bool wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q,
+ struct sk_buff *pkt, int prec, bool head);
+extern u16 wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec);
+extern void wlc_compute_plcp(struct wlc_info *wlc, ratespec_t rate, uint length,
u8 *plcp);
-extern uint wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec,
+extern uint wlc_calc_frame_time(struct wlc_info *wlc, ratespec_t ratespec,
u8 preamble_type, uint mac_len);
-extern void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec);
+extern void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec);
-extern bool wlc_timers_init(wlc_info_t *wlc, int unit);
+extern bool wlc_timers_init(struct wlc_info *wlc, int unit);
extern const bcm_iovar_t wlc_iovars[];
extern int wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid,
const char *name, void *params, uint p_len, void *arg,
- int len, int val_size, wlc_if_t *wlcif);
+ int len, int val_size, struct wlc_if *wlcif);
#if defined(BCMDBG)
-extern void wlc_print_ies(wlc_info_t *wlc, u8 *ies, uint ies_len);
+extern void wlc_print_ies(struct wlc_info *wlc, u8 *ies, uint ies_len);
#endif
-extern int wlc_set_nmode(wlc_info_t *wlc, s32 nmode);
-extern void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode);
-extern void wlc_mimops_action_ht_send(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg,
- u8 mimops_mode);
+extern int wlc_set_nmode(struct wlc_info *wlc, s32 nmode);
+extern void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode);
+extern void wlc_mimops_action_ht_send(struct wlc_info *wlc,
+ wlc_bsscfg_t *bsscfg, u8 mimops_mode);
-extern void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot);
+extern void wlc_switch_shortslot(struct wlc_info *wlc, bool shortslot);
extern void wlc_set_bssid(wlc_bsscfg_t *cfg);
extern void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend);
-extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg,
- bool suspend);
-extern void wlc_set_ratetable(wlc_info_t *wlc);
+extern void wlc_set_ratetable(struct wlc_info *wlc);
extern int wlc_set_mac(wlc_bsscfg_t *cfg);
-extern void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc,
+extern void wlc_beacon_phytxctl_txant_upd(struct wlc_info *wlc,
ratespec_t bcn_rate);
-extern void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len);
-extern ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs);
-extern u16 wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec,
+extern void wlc_mod_prb_rsp_rate_table(struct wlc_info *wlc, uint frame_len);
+extern ratespec_t wlc_lowest_basic_rspec(struct wlc_info *wlc,
+ wlc_rateset_t *rs);
+extern u16 wlc_compute_bcntsfoff(struct wlc_info *wlc, ratespec_t rspec,
bool short_preamble, bool phydelay);
-extern void wlc_radio_disable(wlc_info_t *wlc);
-extern void wlc_bcn_li_upd(wlc_info_t *wlc);
-
-extern int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len);
-extern void wlc_out(wlc_info_t *wlc);
-extern void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec);
-extern void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt);
-extern bool wlc_ps_allowed(wlc_info_t *wlc);
-extern bool wlc_stay_awake(wlc_info_t *wlc);
-extern void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe);
-
-extern void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list);
+extern void wlc_radio_disable(struct wlc_info *wlc);
+extern void wlc_bcn_li_upd(struct wlc_info *wlc);
+
+extern int wlc_get_revision_info(struct wlc_info *wlc, void *buf, uint len);
+extern void wlc_out(struct wlc_info *wlc);
+extern void wlc_set_home_chanspec(struct wlc_info *wlc, chanspec_t chanspec);
+extern void wlc_watchdog_upd(struct wlc_info *wlc, bool tbtt);
+extern bool wlc_ps_allowed(struct wlc_info *wlc);
+extern bool wlc_stay_awake(struct wlc_info *wlc);
+extern void wlc_wme_initparams_sta(struct wlc_info *wlc, wme_param_ie_t *pe);
+
+extern void wlc_bss_list_free(struct wlc_info *wlc, wlc_bss_list_t *bss_list);
+extern void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode);
#endif /* _wlc_h_ */
diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c
index bf8e2e1a15f6..8bd4ede4c92a 100644
--- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c
+++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c
@@ -24,9 +24,10 @@
#include <linux/kernel.h>
#include <bcmdefs.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
-#include <bcmutils.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <osl.h>
+#include <bcmutils.h>
#include <proto/802.11.h>
#include <bcmwifi.h>
@@ -46,6 +47,7 @@
#include <wlc_channel.h>
#include <bcmsrom.h>
#include <wlc_key.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
@@ -53,21 +55,23 @@
#include <wlc_phy_shim.h>
#include <wlc_phy_hal.h>
#include <wl_export.h>
+#include <wl_dbg.h>
/* PHY SHIM module specific state */
struct wlc_phy_shim_info {
- wlc_hw_info_t *wlc_hw; /* pointer to main wlc_hw structure */
+ struct wlc_hw_info *wlc_hw; /* pointer to main wlc_hw structure */
void *wlc; /* pointer to main wlc structure */
void *wl; /* pointer to os-specific private state */
};
-wlc_phy_shim_info_t *wlc_phy_shim_attach(wlc_hw_info_t *wlc_hw,
+wlc_phy_shim_info_t *wlc_phy_shim_attach(struct wlc_hw_info *wlc_hw,
void *wl, void *wlc) {
wlc_phy_shim_info_t *physhim = NULL;
physhim = kzalloc(sizeof(wlc_phy_shim_info_t), GFP_ATOMIC);
if (!physhim) {
- WL_ERROR(("wl%d: wlc_phy_shim_attach: out of mem\n", wlc_hw->unit));
+ WL_ERROR("wl%d: wlc_phy_shim_attach: out of mem\n",
+ wlc_hw->unit);
return NULL;
}
physhim->wlc_hw = wlc_hw;
diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h
index a6a8c33483c9..146a6904a39b 100644
--- a/drivers/staging/brcm80211/sys/wlc_pub.h
+++ b/drivers/staging/brcm80211/sys/wlc_pub.h
@@ -251,7 +251,7 @@ typedef int (*iovar_fn_t) (void *handle, const bcm_iovar_t *vi,
* Public portion of "common" os-independent state structure.
* The wlc handle points at this.
*/
-typedef struct wlc_pub {
+struct wlc_pub {
void *wlc;
struct ieee80211_hw *ieee_hw;
@@ -260,7 +260,7 @@ typedef struct wlc_pub {
uint mac80211_state;
uint unit; /* device instance number */
uint corerev; /* core revision */
- osl_t *osh; /* pointer to os handle */
+ struct osl_info *osh; /* pointer to os handle */
si_t *sih; /* SB handle (cookie for siutils calls) */
char *vars; /* "environment" name=value */
bool up; /* interface up and running */
@@ -318,9 +318,6 @@ typedef struct wlc_pub {
* is implemented properly in osl of that port
* when it enables this Power Save feature.
*/
-#ifdef BCMSDIO
- uint sdiod_drive_strength; /* SDIO drive strength */
-#endif /* BCMSDIO */
u16 boardrev; /* version # of particular board */
u8 sromrev; /* version # of the srom */
@@ -333,7 +330,7 @@ typedef struct wlc_pub {
bool _lmacproto; /* lmac protocol module included and enabled */
bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */
bool _ampdumac; /* mac assist ampdu enabled or not */
-} wlc_pub_t;
+};
/* wl_monitor rx status per packet */
typedef struct wl_rxsts {
@@ -437,17 +434,13 @@ struct wlc_if;
#define EDCF_ENAB(pub) (WME_ENAB(pub))
#define QOS_ENAB(pub) (WME_ENAB(pub) || N_ENAB(pub))
-#define MONITOR_ENAB(wlc) (bcmspace && (wlc)->monitor)
-
-#define PROMISC_ENAB(wlc) (bcmspace && (wlc)->promisc)
-
-extern void wlc_pkttag_info_move(wlc_pub_t *pub, void *pkt_from, void *pkt_to);
+#define MONITOR_ENAB(wlc) ((wlc)->monitor)
-#define WLPKTTAGSCB(p) (WLPKTTAG(p)->_scb)
+#define PROMISC_ENAB(wlc) ((wlc)->promisc)
#define WLC_PREC_COUNT 16 /* Max precedence level implemented */
-/* pri is PKTPRIO encoded in the packet. This maps the Packet priority to
+/* pri is priority encoded in the packet. This maps the Packet priority to
* enqueue precedence as defined in wlc_prec_map
*/
extern const u8 wlc_prio2prec_map[];
@@ -497,8 +490,8 @@ extern const u8 wme_fifo2ac[];
/* common functions for every port */
extern void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit,
- bool piomode, osl_t *osh, void *regsva, uint bustype,
- void *btparam, uint *perr);
+ bool piomode, struct osl_info *osh, void *regsva,
+ uint bustype, void *btparam, uint *perr);
extern uint wlc_detach(struct wlc_info *wlc);
extern int wlc_up(struct wlc_info *wlc);
extern uint wlc_down(struct wlc_info *wlc);
@@ -517,8 +510,10 @@ extern void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask);
extern bool wlc_intrsupd(struct wlc_info *wlc);
extern bool wlc_isr(struct wlc_info *wlc, bool *wantdpc);
extern bool wlc_dpc(struct wlc_info *wlc, bool bounded);
-extern bool wlc_send80211_raw(struct wlc_info *wlc, wlc_if_t *wlcif, void *p,
- uint ac);
+extern bool wlc_send80211_raw(struct wlc_info *wlc, struct wlc_if *wlcif,
+ void *p, uint ac);
+extern bool wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu,
+ struct ieee80211_hw *hw);
extern int wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params,
int p_len, void *arg, int len, bool set,
struct wlc_if *wlcif);
@@ -527,8 +522,13 @@ extern int wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len,
/* helper functions */
extern void wlc_statsupd(struct wlc_info *wlc);
extern int wlc_get_header_len(void);
+extern void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc);
+extern void wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset,
+ const struct ether_addr *addr);
+extern void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg,
+ bool suspend);
-extern wlc_pub_t *wlc_pub(void *wlc);
+extern struct wlc_pub *wlc_pub(void *wlc);
/* common functions for every port */
extern int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw);
@@ -554,13 +554,15 @@ extern void wlc_scb_ratesel_init_all(struct wlc_info *wlc);
/* ioctl */
extern int wlc_iovar_gets8(struct wlc_info *wlc, const char *name,
s8 *arg);
-extern int wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg,
+extern int wlc_iovar_check(struct wlc_pub *pub, const bcm_iovar_t *vi,
+ void *arg,
int len, bool set);
-extern int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars,
+extern int wlc_module_register(struct wlc_pub *pub, const bcm_iovar_t *iovars,
const char *name, void *hdl, iovar_fn_t iovar_fn,
watchdog_fn_t watchdog_fn, down_fn_t down_fn);
-extern int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl);
+extern int wlc_module_unregister(struct wlc_pub *pub, const char *name,
+ void *hdl);
extern void wlc_event_if(struct wlc_info *wlc, struct wlc_bsscfg *cfg,
wlc_event_t *e, const struct ether_addr *addr);
extern void wlc_suspend_mac_and_wait(struct wlc_info *wlc);
@@ -617,10 +619,6 @@ extern void wlc_pmkid_event(struct wlc_bsscfg *cfg);
#define BAND_2G_NAME "2.4G"
#define BAND_5G_NAME "5G"
-#if defined(BCMSDIO) || defined(WLC_HIGH_ONLY)
-void wlc_device_removed(void *arg);
-#endif
-
/* BMAC RPC: 7 u32 params: pkttotlen, fifo, commit, fid, txpktpend, pktflag, rpc_id */
#define WLC_RPCTX_PARAMS 32
diff --git a/drivers/staging/brcm80211/sys/wlc_rate.c b/drivers/staging/brcm80211/sys/wlc_rate.c
index d2d72568756d..ab7d0bed3c0a 100644
--- a/drivers/staging/brcm80211/sys/wlc_rate.c
+++ b/drivers/staging/brcm80211/sys/wlc_rate.c
@@ -17,12 +17,14 @@
#include <bcmdefs.h>
#include <wlc_cfg.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmendian.h>
#include <wlioctl.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <proto/802.11.h>
#include <d11.h>
#include <wlc_rate.h>
@@ -297,7 +299,7 @@ wlc_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs,
uint count;
uint i;
- bzero(rateset, sizeof(rateset));
+ memset(rateset, 0, sizeof(rateset));
count = rs->count;
for (i = 0; i < count; i++) {
diff --git a/drivers/staging/brcm80211/sys/wlc_rpc.h b/drivers/staging/brcm80211/sys/wlc_rpc.h
deleted file mode 100644
index db39645ccbdc..000000000000
--- a/drivers/staging/brcm80211/sys/wlc_rpc.h
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _WLC_RPC_H_
-#define _WLC_RPC_H_
-
-#include <wlc_types.h>
-
-/* RPC IDs, reordering is OK. This needs to be in sync with RPC_ID_TABLE below */
-typedef enum {
- WLRPC_NULL_ID = 0,
- WLRPC_WLC_REG_READ_ID,
- WLRPC_WLC_REG_WRITE_ID,
- WLRPC_WLC_MHF_SET_ID,
- WLRPC_WLC_MHF_GET_ID,
- WLRPC_WLC_BMAC_UP_PREP_ID,
- WLRPC_WLC_BMAC_UP_FINISH_ID,
- WLRPC_WLC_BMAC_DOWN_PREP_ID,
- WLRPC_WLC_BMAC_DOWN_FINISH_ID,
- WLRPC_WLC_BMAC_WRITE_HW_BCNTEMPLATES_ID,
- WLRPC_WLC_BMAC_RESET_ID,
- WLRPC_WLC_DNGL_REBOOT_ID,
- WLRPC_WLC_BMAC_RPC_TXQ_WM_SET_ID,
- WLRPC_WLC_BMAC_RPC_TXQ_WM_GET_ID,
- WLRPC_WLC_BMAC_RPC_AGG_SET_ID,
- WLRPC_WLC_BMAC_RPC_MSGLEVEL_SET_ID,
- WLRPC_WLC_BMAC_RPC_AGG_LIMIT_SET_ID,
- WLRPC_WLC_BMAC_RPC_AGG_LIMIT_GET_ID,
- WLRPC_WLC_BMAC_INIT_ID,
- WLRPC_WLC_BMAC_SET_CWMIN_ID,
- WLRPC_WLC_BMAC_MUTE_ID,
- WLRPC_WLC_PHY_DOIOVAR_ID,
- WLRPC_WLC_PHY_HOLD_UPD_ID,
- WLRPC_WLC_PHY_MUTE_UPD_ID,
- WLRPC_WLC_PHY_CLEAR_TSSI_ID,
- WLRPC_WLC_PHY_ANT_RXDIV_GET_ID,
- WLRPC_WLC_PHY_ANT_RXDIV_SET_ID,
- WLRPC_WLC_PHY_PREAMBLE_SET_ID,
- WLRPC_WLC_PHY_FREQTRACK_END_ID,
- WLRPC_WLC_PHY_FREQTRACK_START_ID,
- WLRPC_WLC_PHY_IOCTL_ID,
- WLRPC_WLC_PHY_NOISE_SAMPLE_REQUEST_ID,
- WLRPC_WLC_PHY_CAL_PERICAL_ID,
- WLRPC_WLC_PHY_TXPOWER_GET_ID,
- WLRPC_WLC_PHY_TXPOWER_SET_ID,
- WLRPC_WLC_PHY_TXPOWER_SROMLIMIT_ID,
- WLRPC_WLC_PHY_RADAR_DETECT_ENABLE_ID,
- WLRPC_WLC_PHY_RADAR_DETECT_RUN_ID,
- WLRPC_WLC_PHY_TEST_ISON_ID,
- WLRPC_WLC_BMAC_COPYFROM_OBJMEM_ID,
- WLRPC_WLC_BMAC_COPYTO_OBJMEM_ID,
- WLRPC_WLC_ENABLE_MAC_ID,
- WLRPC_WLC_MCTRL_ID,
- WLRPC_WLC_CORERESET_ID,
- WLRPC_WLC_BMAC_READ_SHM_ID,
- WLRPC_WLC_BMAC_READ_TSF_ID,
- WLRPC_WLC_BMAC_SET_ADDRMATCH_ID,
- WLRPC_WLC_BMAC_SET_CWMAX_ID,
- WLRPC_WLC_BMAC_SET_RCMTA_ID,
- WLRPC_WLC_BMAC_SET_SHM_ID,
- WLRPC_WLC_SUSPEND_MAC_AND_WAIT_ID,
- WLRPC_WLC_BMAC_WRITE_SHM_ID,
- WLRPC_WLC_BMAC_WRITE_TEMPLATE_RAM_ID,
- WLRPC_WLC_TX_FIFO_SUSPEND_ID,
- WLRPC_WLC_TX_FIFO_RESUME_ID,
- WLRPC_WLC_TX_FIFO_SUSPENDED_ID,
- WLRPC_WLC_HW_ETHERADDR_ID,
- WLRPC_WLC_SET_HW_ETHERADDR_ID,
- WLRPC_WLC_BMAC_CHANSPEC_SET_ID,
- WLRPC_WLC_BMAC_TXANT_SET_ID,
- WLRPC_WLC_BMAC_ANTSEL_TYPE_SET_ID,
- WLRPC_WLC_BMAC_TXFIFO_ID,
- WLRPC_WLC_RADIO_READ_HWDISABLED_ID,
- WLRPC_WLC_RM_CCA_MEASURE_ID,
- WLRPC_WLC_SET_SHORTSLOT_ID,
- WLRPC_WLC_WAIT_FOR_WAKE_ID,
- WLRPC_WLC_PHY_TXPOWER_GET_CURRENT_ID,
- WLRPC_WLC_PHY_TXPOWER_HW_CTRL_GET_ID,
- WLRPC_WLC_PHY_TXPOWER_HW_CTRL_SET_ID,
- WLRPC_WLC_PHY_BSSINIT_ID,
- WLRPC_WLC_BAND_STF_SS_SET_ID,
- WLRPC_WLC_PHY_BAND_FIRST_CHANSPEC_ID,
- WLRPC_WLC_PHY_TXPOWER_LIMIT_SET_ID,
- WLRPC_WLC_PHY_BAND_CHANNELS_ID,
- WLRPC_WLC_BMAC_REVINFO_GET_ID,
- WLRPC_WLC_BMAC_STATE_GET_ID,
- WLRPC_WLC_BMAC_XMTFIFO_SZ_GET_ID,
- WLRPC_WLC_BMAC_XMTFIFO_SZ_SET_ID,
- WLRPC_WLC_BMAC_VALIDATE_CHIP_ACCESS_ID,
- WLRPC_WLC_RM_CCA_COMPLETE_ID,
- WLRPC_WLC_RECV_ID,
- WLRPC_WLC_DOTXSTATUS_ID,
- WLRPC_WLC_HIGH_DPC_ID,
- WLRPC_WLC_FATAL_ERROR_ID,
- WLRPC_WLC_PHY_SET_CHANNEL_14_WIDE_FILTER_ID,
- WLRPC_WLC_PHY_NOISE_AVG_ID,
- WLRPC_WLC_PHYCHAIN_INIT_ID,
- WLRPC_WLC_PHYCHAIN_SET_ID,
- WLRPC_WLC_PHYCHAIN_GET_ID,
- WLRPC_WLC_PHY_TKIP_RIFS_WAR_ID,
- WLRPC_WLC_BMAC_COPYFROM_VARS_ID,
- WLRPC_WLC_BMAC_RETRYLIMIT_UPD_ID,
- WLRPC_WLC_BMAC_BTC_MODE_SET_ID,
- WLRPC_WLC_BMAC_BTC_MODE_GET_ID,
- WLRPC_WLC_BMAC_BTC_WIRE_SET_ID,
- WLRPC_WLC_BMAC_BTC_WIRE_GET_ID,
- WLRPC_WLC_BMAC_SET_NORESET_ID,
- WLRPC_WLC_AMPDU_TXSTATUS_COMPLETE_ID,
- WLRPC_WLC_BMAC_FIFOERRORS_ID,
- WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MIN_ID,
- WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MAX_ID,
- WLRPC_WLC_NOISE_CB_ID,
- WLRPC_WLC_BMAC_LED_HW_DEINIT_ID,
- WLRPC_WLC_BMAC_LED_HW_MASK_INIT_ID,
- WLRPC_WLC_PLLREQ_ID,
- WLRPC_WLC_BMAC_TACLEAR_ID,
- WLRPC_WLC_BMAC_SET_CLK_ID,
- WLRPC_WLC_PHY_OFDM_RATESET_WAR_ID,
- WLRPC_WLC_PHY_BF_PREEMPT_ENABLE_ID,
- WLRPC_WLC_BMAC_DOIOVARS_ID,
- WLRPC_WLC_BMAC_DUMP_ID,
- WLRPC_WLC_CISWRITE_ID,
- WLRPC_WLC_CISDUMP_ID,
- WLRPC_WLC_UPDATE_PHY_MODE_ID,
- WLRPC_WLC_RESET_BMAC_DONE_ID,
- WLRPC_WLC_BMAC_LED_BLINK_EVENT_ID,
- WLRPC_WLC_BMAC_LED_SET_ID,
- WLRPC_WLC_BMAC_LED_BLINK_ID,
- WLRPC_WLC_BMAC_LED_ID,
- WLRPC_WLC_BMAC_RATE_SHM_OFFSET_ID,
- WLRPC_SI_ISCORE_UP_ID,
- WLRPC_WLC_BMAC_PS_SWITCH_ID,
- WLRPC_WLC_PHY_STF_SSMODE_GET_ID,
- WLRPC_WLC_BMAC_DEBUG_ID,
- WLRPC_WLC_EXTLOG_MSG_ID,
- WLRPC_WLC_EXTLOG_CFG_ID,
- WLRPC_BCM_ASSERT_LOG_ID,
- WLRPC_BCM_ASSERT_TYPE_ID,
- WLRPC_WLC_BMAC_SET_PHYCAL_CACHE_FLAG_ID,
- WLRPC_WLC_BMAC_GET_PHYCAL_CACHE_FLAG_ID,
- WLRPC_WLC_PHY_CAL_CACHE_INIT_ID,
- WLRPC_WLC_PHY_CAL_CACHE_DEINIT_ID,
- WLRPC_WLC_BMAC_HW_UP_ID,
- WLRPC_WLC_BMAC_SET_TXPWR_PERCENT_ID,
- WLRPC_WLC_PHYCHAIN_ACTIVE_GET_ID,
- WLRPC_WLC_BMAC_BLINK_SYNC_ID,
- WLRPC_WLC_BMAC_UCODE_DBGSEL_SET_ID,
- WLRPC_WLC_BMAC_UCODE_DBGSEL_GET_ID,
- WLRPC_WLC_PHY_RADAR_DETECT_MODE_SET_ID,
- WLRPC_WLC_PHY_ACIM_NOISEM_RESET_NPHY_ID,
- WLRPC_WLC_PHY_INTERFER_SET_NPHY_ID,
- WLRPC_WLC_BMAC_IFSCTL_EDCRS_SET_ID,
- WLRPC_WLC_PKTENGTX,
- WLRPC_WLC_BMAC_SET_DEAF,
- WLRPC_WLC_BMAC_CLEAR_DEAF,
- WLRPC_WLC_BMAC_BTC_FLAGS_SET_ID,
- WLRPC_WLC_BMAC_BTC_FLAGS_GET_ID,
- WLRPC_WLC_BMAC_SET_RCMTA_TYPE_ID,
- WLRPC_WLC_BMAC_BTC_FLAGS_UPD_ID,
- WLRPC_WLC_BMAC_BTC_STUCKWAR_ID,
- WLRPC_WLC_BMAC_CCA_STATS_READ_ID,
- WLRPC_WLC_BMAC_ANTSEL_SET_ID,
- WLRPC_WLC_BMAC_SET_UCODE_LOADED,
- WLRPC_WLC_PHY_LDPC_SET_ID,
-
- WLRPC_LAST
-} wlc_rpc_id_t;
-
-#if defined(BCMDBG) | 0
-struct name_entry {
- int id;
- char *name;
-};
-
-#define NAME_ENTRY(x) {x, #x}
-
-#define RPC_ID_TABLE { \
- NAME_ENTRY(WLRPC_WLC_REG_READ_ID), \
- NAME_ENTRY(WLRPC_WLC_REG_WRITE_ID), \
- NAME_ENTRY(WLRPC_WLC_MHF_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_MHF_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_UP_PREP_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_UP_FINISH_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_DOWN_PREP_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_DOWN_FINISH_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_HW_BCNTEMPLATES_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RESET_ID), \
- NAME_ENTRY(WLRPC_WLC_DNGL_REBOOT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_TXQ_WM_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_TXQ_WM_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_MSGLEVEL_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_LIMIT_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_LIMIT_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_INIT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_CWMIN_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_MUTE_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_DOIOVAR_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_HOLD_UPD_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_MUTE_UPD_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_CLEAR_TSSI_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_ANT_RXDIV_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_ANT_RXDIV_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_PREAMBLE_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_FREQTRACK_END_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_FREQTRACK_START_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_IOCTL_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_NOISE_SAMPLE_REQUEST_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_CAL_PERICAL_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_SROMLIMIT_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_ENABLE_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_RUN_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TEST_ISON_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_COPYFROM_OBJMEM_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_COPYTO_OBJMEM_ID), \
- NAME_ENTRY(WLRPC_WLC_ENABLE_MAC_ID), \
- NAME_ENTRY(WLRPC_WLC_MCTRL_ID), \
- NAME_ENTRY(WLRPC_WLC_CORERESET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_READ_SHM_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_READ_TSF_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_ADDRMATCH_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_CWMAX_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_RCMTA_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_SHM_ID), \
- NAME_ENTRY(WLRPC_WLC_SUSPEND_MAC_AND_WAIT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_SHM_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_TEMPLATE_RAM_ID), \
- NAME_ENTRY(WLRPC_WLC_TX_FIFO_SUSPEND_ID), \
- NAME_ENTRY(WLRPC_WLC_TX_FIFO_RESUME_ID), \
- NAME_ENTRY(WLRPC_WLC_TX_FIFO_SUSPENDED_ID), \
- NAME_ENTRY(WLRPC_WLC_HW_ETHERADDR_ID), \
- NAME_ENTRY(WLRPC_WLC_SET_HW_ETHERADDR_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_CHANSPEC_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_TXANT_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_ANTSEL_TYPE_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_TXFIFO_ID), \
- NAME_ENTRY(WLRPC_WLC_RADIO_READ_HWDISABLED_ID), \
- NAME_ENTRY(WLRPC_WLC_RM_CCA_MEASURE_ID), \
- NAME_ENTRY(WLRPC_WLC_SET_SHORTSLOT_ID), \
- NAME_ENTRY(WLRPC_WLC_WAIT_FOR_WAKE_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_CURRENT_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_HW_CTRL_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_HW_CTRL_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_BSSINIT_ID), \
- NAME_ENTRY(WLRPC_WLC_BAND_STF_SS_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_BAND_FIRST_CHANSPEC_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_LIMIT_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_BAND_CHANNELS_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_REVINFO_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_STATE_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_XMTFIFO_SZ_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_XMTFIFO_SZ_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_VALIDATE_CHIP_ACCESS_ID), \
- NAME_ENTRY(WLRPC_WLC_RM_CCA_COMPLETE_ID), \
- NAME_ENTRY(WLRPC_WLC_RECV_ID), \
- NAME_ENTRY(WLRPC_WLC_DOTXSTATUS_ID), \
- NAME_ENTRY(WLRPC_WLC_HIGH_DPC_ID), \
- NAME_ENTRY(WLRPC_WLC_FATAL_ERROR_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_SET_CHANNEL_14_WIDE_FILTER_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_NOISE_AVG_ID), \
- NAME_ENTRY(WLRPC_WLC_PHYCHAIN_INIT_ID), \
- NAME_ENTRY(WLRPC_WLC_PHYCHAIN_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHYCHAIN_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TKIP_RIFS_WAR_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_COPYFROM_VARS_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RETRYLIMIT_UPD_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_MODE_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_MODE_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_WIRE_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_WIRE_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_NORESET_ID), \
- NAME_ENTRY(WLRPC_WLC_AMPDU_TXSTATUS_COMPLETE_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_FIFOERRORS_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MIN_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MAX_ID), \
- NAME_ENTRY(WLRPC_WLC_NOISE_CB_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_HW_DEINIT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_HW_MASK_INIT_ID), \
- NAME_ENTRY(WLRPC_WLC_PLLREQ_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_TACLEAR_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_CLK_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_OFDM_RATESET_WAR_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_BF_PREEMPT_ENABLE_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_DOIOVARS_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_DUMP_ID), \
- NAME_ENTRY(WLRPC_WLC_CISWRITE_ID), \
- NAME_ENTRY(WLRPC_WLC_CISDUMP_ID), \
- NAME_ENTRY(WLRPC_WLC_UPDATE_PHY_MODE_ID), \
- NAME_ENTRY(WLRPC_WLC_RESET_BMAC_DONE_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_BLINK_EVENT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_BLINK_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_LED_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_RATE_SHM_OFFSET_ID), \
- NAME_ENTRY(WLRPC_SI_ISCORE_UP_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_PS_SWITCH_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_STF_SSMODE_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_DEBUG_ID), \
- NAME_ENTRY(WLRPC_WLC_EXTLOG_MSG_ID), \
- NAME_ENTRY(WLRPC_WLC_EXTLOG_CFG_ID), \
- NAME_ENTRY(WLRPC_BCM_ASSERT_LOG_ID), \
- NAME_ENTRY(WLRPC_BCM_ASSERT_TYPE_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_PHYCAL_CACHE_FLAG_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_GET_PHYCAL_CACHE_FLAG_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_CAL_CACHE_INIT_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_CAL_CACHE_DEINIT_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_HW_UP_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_TXPWR_PERCENT_ID), \
- NAME_ENTRY(WLRPC_WLC_PHYCHAIN_ACTIVE_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BLINK_SYNC_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_UCODE_DBGSEL_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_UCODE_DBGSEL_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_MODE_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_ACIM_NOISEM_RESET_NPHY_ID), \
- NAME_ENTRY(WLRPC_WLC_PHY_INTERFER_SET_NPHY_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_IFSCTL_EDCRS_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_PKTENGTX), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_DEAF), \
- NAME_ENTRY(WLRPC_WLC_BMAC_CLEAR_DEAF), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_FLAGS_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_BTC_FLAGS_GET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_RCMTA_TYPE_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_CCA_STATS_READ_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_ANTSEL_SET_ID), \
- NAME_ENTRY(WLRPC_WLC_BMAC_SET_UCODE_LOADED), \
- NAME_ENTRY(WLRPC_WLC_PHY_LDPC_SET_ID), \
- {0, NULL} \
- }
-
-static __inline char *_wlc_rpc_id_lookup(const struct name_entry *tbl, int _id)
-{
- const struct name_entry *elt = tbl;
- static char __unknown[64];
- for (; elt->name != NULL; elt++) {
- if (_id == elt->id)
- break;
- }
- if (_id == elt->id)
- strncpy(__unknown, elt->name, sizeof(__unknown));
- else
- snprintf(__unknown, sizeof(__unknown), "ID:%d", _id);
- return __unknown;
-}
-
-#define WLC_RPC_ID_LOOKUP(tbl, _id) (_wlc_rpc_id_lookup(tbl, _id))
-
-#endif /* BCMDBG */
-
-/* refer to txpwr_limits_t for each elements, mcs32 is the at the end for 1 byte */
-#define TXPOWER_XDR_SZ (roundup(WLC_NUM_RATES_CCK, 4) + roundup(WLC_NUM_RATES_OFDM, 4) * 4 + \
- roundup(WLC_NUM_RATES_MCS_1_STREAM, 4) * 6 + roundup(WLC_NUM_RATES_MCS_2_STREAM, 4) * 2 + \
- roundup(1, 4))
-
-#define wlc_rpc_txpwr_limits(b, txpwr, op, err) \
- do { \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->cck, WLC_NUM_RATES_CCK); \
- ASSERT(!(err)); \
- \
- /* 20 MHz Legacy OFDM rates with SISO transmission */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm, WLC_NUM_RATES_OFDM); \
- ASSERT(!(err)); \
- \
- /* 20 MHz Legacy OFDM rates with CDD transmission */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_cdd, WLC_NUM_RATES_OFDM); \
- ASSERT(!(err)); \
- \
- /* 40 MHz Legacy OFDM rates with SISO transmission */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_40_siso, WLC_NUM_RATES_OFDM); \
- ASSERT(!(err)); \
- \
- /* 40 MHz Legacy OFDM rates with CDD transmission */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_40_cdd, WLC_NUM_RATES_OFDM); \
- ASSERT(!(err)); \
- \
- /* 20MHz MCS rates SISO/CDD/STBC/SDM */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_siso, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_cdd, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_stbc, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_mimo, WLC_NUM_RATES_MCS_2_STREAM); \
- ASSERT(!(err)); \
- \
- /* 40MHz MCS rates SISO/CDD/STBC/SDM */ \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_siso, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_cdd, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_stbc, WLC_NUM_RATES_MCS_1_STREAM); \
- ASSERT(!(err)); \
- \
- (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_mimo, WLC_NUM_RATES_MCS_2_STREAM); \
- ASSERT(!(err)); \
- } while (0)
-
-typedef struct wlc_rpc_ctx {
- rpc_info_t *rpc;
- wlc_info_t *wlc;
- wlc_hw_info_t *wlc_hw;
-} wlc_rpc_ctx_t;
-
-static inline rpc_buf_t *wlc_rpc_buf_alloc(rpc_info_t *rpc, bcm_xdr_buf_t *b,
- uint len, wlc_rpc_id_t rpc_id)
-{
- rpc_buf_t *rpc_buf;
-
- rpc_buf = bcm_rpc_buf_alloc(rpc, len + sizeof(u32));
-
- if (!rpc_buf)
- return NULL;
-
- bcm_xdr_buf_init(b, bcm_rpc_buf_data(bcm_rpc_tp_get(rpc), rpc_buf),
- len + sizeof(u32));
-
- bcm_xdr_pack_u32(b, rpc_id);
-
- return rpc_buf;
-}
-
-#if defined(BCMDBG)
-static __inline wlc_rpc_id_t
-wlc_rpc_id_get(struct rpc_info *rpc, rpc_buf_t *buf)
-{
- wlc_rpc_id_t rpc_id;
- bcm_xdr_buf_t b;
-
- bcm_xdr_buf_init(&b, bcm_rpc_buf_data(bcm_rpc_tp_get(rpc), buf),
- sizeof(u32));
-
- bcm_xdr_unpack_u32(&b, (u32 *)((unsigned long) & rpc_id));
- return rpc_id;
-}
-#endif
-
-static __inline int _wlc_rpc_call(struct rpc_info *rpc, rpc_buf_t *send)
-{
- int _err = 0;
-#if defined(BCMDBG)
- wlc_rpc_id_t rpc_id = wlc_rpc_id_get(rpc, send);
- /* const struct name_entry rpc_name_tbl[] = RPC_ID_TABLE; */
- static struct name_entry rpc_name_tbl[] = RPC_ID_TABLE;
- WL_TRACE(("%s: Called id %s\n", __func__,
- WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id)));
-#endif
- _err = bcm_rpc_call(rpc, send);
- if (_err) {
-#if defined(BCMDBG)
- WL_ERROR(("%s: Call id %s FAILED\n", __func__,
- WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id)));
-#endif
- _err = 0;
- }
- return _err;
-}
-
-#define wlc_rpc_call(rpc, send) (_wlc_rpc_call(rpc, send))
-
-#include <sbhnddma.h>
-#include <sbhndpio.h>
-#include <d11.h>
-
-#ifdef WLC_LOW
-extern void wlc_rpc_bmac_dispatch(wlc_rpc_ctx_t *rpc_ctx, struct rpc_buf *buf);
-extern void wlc_rpc_bmac_dump_txfifohist(wlc_hw_info_t *wlc_hw,
- bool dump_clear);
-#else
-extern void wlc_rpc_high_dispatch(wlc_rpc_ctx_t *ctx, struct rpc_buf *buf);
-#endif
-
-/* Packed structure for ease of transport across RPC bus along u32 boundary */
-typedef struct wlc_rpc_txstatus {
- u32 PAD_framelen;
- u32 status_frameid;
- u32 sequence_lasttxtime;
- u32 ackphyrxsh_phyerr;
-} wlc_rpc_txstatus_t;
-
-static inline
- void txstatus2rpc_txstatus(tx_status_t *txstatus,
- wlc_rpc_txstatus_t *rpc_txstatus)
-{
- rpc_txstatus->PAD_framelen = txstatus->framelen;
- rpc_txstatus->status_frameid =
- (txstatus->status << 16) | txstatus->frameid;
- rpc_txstatus->sequence_lasttxtime =
- (txstatus->sequence << 16) | txstatus->lasttxtime;
- rpc_txstatus->ackphyrxsh_phyerr =
- (txstatus->ackphyrxsh << 16) | txstatus->phyerr;
-}
-
-static inline
- void rpc_txstatus2txstatus(wlc_rpc_txstatus_t *rpc_txstatus,
- tx_status_t *txstatus)
-{
- txstatus->framelen = rpc_txstatus->PAD_framelen & 0xffff;
- txstatus->status = (rpc_txstatus->status_frameid >> 16) & 0xffff;
- txstatus->frameid = rpc_txstatus->status_frameid & 0xffff;
- txstatus->sequence = (rpc_txstatus->sequence_lasttxtime >> 16) & 0xffff;
- txstatus->lasttxtime = rpc_txstatus->sequence_lasttxtime & 0xffff;
- txstatus->ackphyrxsh = (rpc_txstatus->ackphyrxsh_phyerr >> 16) & 0xffff;
- txstatus->phyerr = rpc_txstatus->ackphyrxsh_phyerr & 0xffff;
-}
-
-extern void wlc_bmac_dngl_reboot(rpc_info_t *rpc);
-
-#endif /* WLC_RPC_H */
diff --git a/drivers/staging/brcm80211/sys/wlc_rpctx.h b/drivers/staging/brcm80211/sys/wlc_rpctx.h
deleted file mode 100644
index 7427154a4bd4..000000000000
--- a/drivers/staging/brcm80211/sys/wlc_rpctx.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _wlc_rpctx_h_
-#define _wlc_rpctx_h_
-
-/* forward declaration */
-struct wlc_info;
-
-/* This controls how many packets are given to the dongle. This is required as
- * NTXD needs to be power of 2 but we may not have enough memory to absorb that
- * large number of frames
- */
-#ifndef NRPCTXBUFPOST
-#define NRPCTXBUFPOST NTXD
-#endif
-
-#if defined(WLC_HIGH_ONLY)
-
-struct wlc_rpc_phy {
- struct rpc_info *rpc;
-};
-
-#define RPCTX_ENAB(pub) (true)
-extern rpctx_info_t *wlc_rpctx_attach(wlc_pub_t *pub, struct wlc_info *wlc);
-extern int wlc_rpctx_fifoinit(rpctx_info_t *rpctx, uint fifo, uint ntxd);
-extern void wlc_rpctx_detach(rpctx_info_t *rpctx);
-extern int wlc_rpctx_dump(rpctx_info_t *rpctx, struct bcmstrbuf *b);
-extern void *wlc_rpctx_getnexttxp(rpctx_info_t *rpctx, uint fifo);
-extern void wlc_rpctx_txreclaim(rpctx_info_t *rpctx);
-extern uint wlc_rpctx_txavail(rpctx_info_t *rpctx, uint fifo);
-extern int wlc_rpctx_pkteng(rpctx_info_t *rpctx, uint fifo, void *p);
-extern int wlc_rpctx_tx(rpctx_info_t *rpctx, uint fifo, void *p, bool commit,
- u16 frameid, u8 txpktpend);
-extern void wlc_rpctx_txpktpendinc(rpctx_info_t *rpctx, uint fifo, u8 val);
-extern void wlc_rpctx_txpktpenddec(rpctx_info_t *rpctx, uint fifo, u8 val);
-extern void wlc_rpctx_txpktpendclr(rpctx_info_t *rpctx, uint fifo);
-extern int wlc_rpctx_txpktpend(rpctx_info_t *rpctx, uint fifo, bool all);
-
-#else
-#define RPCTX_ENAB(pub) (false)
-#define wlc_rpctx_attach(pub, wlc) (NULL)
-#define wlc_rpctx_fifoinit(rpctx, fifo, ntxd) (0)
-#define wlc_rpctx_detach(rpctx) ASSERT(0)
-#define wlc_rpctx_txavail(rpctx, f) (false)
-#define wlc_rpctx_dump(rpctx, b) (0)
-#define wlc_rpctx_getnexttxp(rpctx, f) (NULL)
-#define wlc_rpctx_txreclaim(rpctx) ASSERT(0)
-#define wlc_rpctx_pkteng(rpctx, fifo, p) do { } while (0)
-#define wlc_rpctx_tx(rpctx, f, p, c, fid, t) (0)
-#define wlc_rpctx_txpktpendinc(rpctx, f, val) do { } while (0)
-#define wlc_rpctx_txpktpenddec(rpctx, f, val) do { } while (0)
-#define wlc_rpctx_txpktpendclr(rpctx, f) do { } while (0)
-#define wlc_rpctx_txpktpend(rpctx, f, all) (0)
-
-#endif /* WLC_HIGH */
-
-#endif /* _wlc_rpctx_h_ */
diff --git a/drivers/staging/brcm80211/sys/wlc_scb.h b/drivers/staging/brcm80211/sys/wlc_scb.h
index ce26c740e6c1..fe84e993b52a 100644
--- a/drivers/staging/brcm80211/sys/wlc_scb.h
+++ b/drivers/staging/brcm80211/sys/wlc_scb.h
@@ -19,7 +19,7 @@
#include <proto/802.1d.h>
-extern bool wlc_aggregatable(wlc_info_t *wlc, u8 tid);
+extern bool wlc_aggregatable(struct wlc_info *wlc, u8 tid);
#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
/* structure to store per-tid state for the ampdu initiator */
diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c
index 4728ad90e295..8975b09a7438 100644
--- a/drivers/staging/brcm80211/sys/wlc_stf.c
+++ b/drivers/staging/brcm80211/sys/wlc_stf.c
@@ -15,8 +15,8 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <wlc_cfg.h>
-#include <linuxver.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
@@ -25,29 +25,33 @@
#include <proto/802.11.h>
#include <wlioctl.h>
#include <bcmwifi.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
#include <d11.h>
#include <wlc_rate.h>
#include <wlc_pub.h>
#include <wlc_key.h>
#include <wlc_channel.h>
#include <wlc_bsscfg.h>
+#include <wlc_event.h>
#include <wlc_mac80211.h>
#include <wlc_scb.h>
#include <wl_export.h>
#include <wlc_bmac.h>
#include <wlc_stf.h>
+#include <wl_dbg.h>
#define WLC_STF_SS_STBC_RX(wlc) (WLCISNPHY(wlc->band) && \
NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6))
-static s8 wlc_stf_stbc_rx_get(wlc_info_t *wlc);
-static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val);
-static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 val);
-static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val);
-static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val);
+static s8 wlc_stf_stbc_rx_get(struct wlc_info *wlc);
+static bool wlc_stf_stbc_tx_set(struct wlc_info *wlc, s32 int_val);
+static int wlc_stf_txcore_set(struct wlc_info *wlc, u8 Nsts, u8 val);
+static int wlc_stf_spatial_policy_set(struct wlc_info *wlc, int val);
+static void wlc_stf_stbc_rx_ht_update(struct wlc_info *wlc, int val);
-static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc);
-static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec);
+static void _wlc_stf_phy_txant_upd(struct wlc_info *wlc);
+static u16 _wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec);
#define NSTS_1 1
#define NSTS_2 2
@@ -61,7 +65,7 @@ const u8 txcore_default[5] = {
(0x0f) /* For Nsts = 4, enable all cores */
};
-static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val)
+static void wlc_stf_stbc_rx_ht_update(struct wlc_info *wlc, int val)
{
ASSERT((val == HT_CAP_RX_STBC_NO)
|| (val == HT_CAP_RX_STBC_ONE_STREAM));
@@ -82,7 +86,7 @@ static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val)
}
/* every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to turn on/off txchain */
-void wlc_tempsense_upd(wlc_info_t *wlc)
+void wlc_tempsense_upd(struct wlc_info *wlc)
{
wlc_phy_t *pi = wlc->band->pi;
uint active_chains, txchain;
@@ -106,7 +110,7 @@ void wlc_tempsense_upd(wlc_info_t *wlc)
}
void
-wlc_stf_ss_algo_channel_get(wlc_info_t *wlc, u16 *ss_algo_channel,
+wlc_stf_ss_algo_channel_get(struct wlc_info *wlc, u16 *ss_algo_channel,
chanspec_t chanspec)
{
tx_power_t power;
@@ -147,12 +151,12 @@ wlc_stf_ss_algo_channel_get(wlc_info_t *wlc, u16 *ss_algo_channel,
setbit(ss_algo_channel, PHY_TXC1_MODE_STBC);
}
-static s8 wlc_stf_stbc_rx_get(wlc_info_t *wlc)
+static s8 wlc_stf_stbc_rx_get(struct wlc_info *wlc)
{
return (wlc->ht_cap.cap & HT_CAP_RX_STBC_MASK) >> HT_CAP_RX_STBC_SHIFT;
}
-static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val)
+static bool wlc_stf_stbc_tx_set(struct wlc_info *wlc, s32 int_val)
{
if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) {
return false;
@@ -173,7 +177,7 @@ static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val)
return true;
}
-bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val)
+bool wlc_stf_stbc_rx_set(struct wlc_info *wlc, s32 int_val)
{
if ((int_val != HT_CAP_RX_STBC_NO)
&& (int_val != HT_CAP_RX_STBC_ONE_STREAM)) {
@@ -190,10 +194,10 @@ bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val)
return true;
}
-static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 core_mask)
+static int wlc_stf_txcore_set(struct wlc_info *wlc, u8 Nsts, u8 core_mask)
{
- WL_TRACE(("wl%d: %s: Nsts %d core_mask %x\n",
- wlc->pub->unit, __func__, Nsts, core_mask));
+ WL_TRACE("wl%d: %s: Nsts %d core_mask %x\n",
+ wlc->pub->unit, __func__, Nsts, core_mask);
ASSERT((Nsts > 0) && (Nsts <= MAX_STREAMS_SUPPORTED));
@@ -227,12 +231,12 @@ static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 core_mask)
return BCME_OK;
}
-static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val)
+static int wlc_stf_spatial_policy_set(struct wlc_info *wlc, int val)
{
int i;
u8 core_mask = 0;
- WL_TRACE(("wl%d: %s: val %x\n", wlc->pub->unit, __func__, val));
+ WL_TRACE("wl%d: %s: val %x\n", wlc->pub->unit, __func__, val);
wlc->stf->spatial_policy = (s8) val;
for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) {
@@ -243,7 +247,7 @@ static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val)
return BCME_OK;
}
-int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force)
+int wlc_stf_txchain_set(struct wlc_info *wlc, s32 int_val, bool force)
{
u8 txchain = (u8) int_val;
u8 txstreams;
@@ -274,13 +278,15 @@ int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force)
if (RSPEC_STF(wlc->bandstate[i]->rspec_override)
!= PHY_TXC1_MODE_SISO) {
wlc->bandstate[i]->rspec_override = 0;
- WL_ERROR(("%s(): temp sense override non-SISO" " rspec_override.\n", __func__));
+ WL_ERROR("%s(): temp sense override non-SISO rspec_override\n",
+ __func__);
}
if (RSPEC_STF
(wlc->bandstate[i]->mrspec_override) !=
PHY_TXC1_MODE_SISO) {
wlc->bandstate[i]->mrspec_override = 0;
- WL_ERROR(("%s(): temp sense override non-SISO" " mrspec_override.\n", __func__));
+ WL_ERROR("%s(): temp sense override non-SISO mrspec_override\n",
+ __func__);
}
}
}
@@ -303,7 +309,7 @@ int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force)
return BCME_OK;
}
-int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val)
+int wlc_stf_rxchain_set(struct wlc_info *wlc, s32 int_val)
{
u8 rxchain_cnt;
u8 rxchain = (u8) int_val;
@@ -367,7 +373,7 @@ int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val)
}
/* update wlc->stf->ss_opmode which represents the operational stf_ss mode we're using */
-int wlc_stf_ss_update(wlc_info_t *wlc, wlcband_t *band)
+int wlc_stf_ss_update(struct wlc_info *wlc, struct wlcband *band)
{
int ret_code = 0;
u8 prev_stf_ss;
@@ -402,7 +408,7 @@ int wlc_stf_ss_update(wlc_info_t *wlc, wlcband_t *band)
return ret_code;
}
-int wlc_stf_attach(wlc_info_t *wlc)
+int wlc_stf_attach(struct wlc_info *wlc)
{
wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO;
wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD;
@@ -425,11 +431,11 @@ int wlc_stf_attach(wlc_info_t *wlc)
return 0;
}
-void wlc_stf_detach(wlc_info_t *wlc)
+void wlc_stf_detach(struct wlc_info *wlc)
{
}
-int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val)
+int wlc_stf_ant_txant_validate(struct wlc_info *wlc, s8 val)
{
int bcmerror = BCME_OK;
@@ -476,7 +482,7 @@ int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val)
* do tx-antenna selection for SISO transmissions
* for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 means both cores active
*/
-static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc)
+static void _wlc_stf_phy_txant_upd(struct wlc_info *wlc)
{
s8 txant;
@@ -517,12 +523,12 @@ static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc)
wlc_bmac_txant_set(wlc->hw, wlc->stf->phytxant);
}
-void wlc_stf_phy_txant_upd(wlc_info_t *wlc)
+void wlc_stf_phy_txant_upd(struct wlc_info *wlc)
{
_wlc_stf_phy_txant_upd(wlc);
}
-void wlc_stf_phy_chain_calc(wlc_info_t *wlc)
+void wlc_stf_phy_chain_calc(struct wlc_info *wlc)
{
/* get available rx/tx chains */
wlc->stf->hw_txchain = (u8) getintvar(wlc->pub->vars, "txchain");
@@ -559,7 +565,7 @@ void wlc_stf_phy_chain_calc(wlc_info_t *wlc)
wlc_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION);
}
-static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec)
+static u16 _wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec)
{
u16 phytxant = wlc->stf->phytxant;
@@ -572,12 +578,12 @@ static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec)
return phytxant;
}
-u16 wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec)
+u16 wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec)
{
return _wlc_stf_phytxchain_sel(wlc, rspec);
}
-u16 wlc_stf_d11hdrs_phyctl_txant(wlc_info_t *wlc, ratespec_t rspec)
+u16 wlc_stf_d11hdrs_phyctl_txant(struct wlc_info *wlc, ratespec_t rspec)
{
u16 phytxant = wlc->stf->phytxant;
u16 mask = PHY_TXC_ANT_MASK;
diff --git a/drivers/staging/brcm80211/sys/wlc_stf.h b/drivers/staging/brcm80211/sys/wlc_stf.h
index ee9b02a119bb..8de6382e620d 100644
--- a/drivers/staging/brcm80211/sys/wlc_stf.h
+++ b/drivers/staging/brcm80211/sys/wlc_stf.h
@@ -20,23 +20,24 @@
#define MIN_SPATIAL_EXPANSION 0
#define MAX_SPATIAL_EXPANSION 1
-extern int wlc_stf_attach(wlc_info_t *wlc);
-extern void wlc_stf_detach(wlc_info_t *wlc);
+extern int wlc_stf_attach(struct wlc_info *wlc);
+extern void wlc_stf_detach(struct wlc_info *wlc);
-extern void wlc_tempsense_upd(wlc_info_t *wlc);
-extern void wlc_stf_ss_algo_channel_get(wlc_info_t *wlc,
+extern void wlc_tempsense_upd(struct wlc_info *wlc);
+extern void wlc_stf_ss_algo_channel_get(struct wlc_info *wlc,
u16 *ss_algo_channel,
chanspec_t chanspec);
-extern int wlc_stf_ss_update(wlc_info_t *wlc, struct wlcband *band);
-extern void wlc_stf_phy_txant_upd(wlc_info_t *wlc);
-extern int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force);
-extern int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val);
-extern bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val);
+extern int wlc_stf_ss_update(struct wlc_info *wlc, struct wlcband *band);
+extern void wlc_stf_phy_txant_upd(struct wlc_info *wlc);
+extern int wlc_stf_txchain_set(struct wlc_info *wlc, s32 int_val, bool force);
+extern int wlc_stf_rxchain_set(struct wlc_info *wlc, s32 int_val);
+extern bool wlc_stf_stbc_rx_set(struct wlc_info *wlc, s32 int_val);
-extern int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val);
-extern void wlc_stf_phy_txant_upd(wlc_info_t *wlc);
-extern void wlc_stf_phy_chain_calc(wlc_info_t *wlc);
-extern u16 wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec);
-extern u16 wlc_stf_d11hdrs_phyctl_txant(wlc_info_t *wlc, ratespec_t rspec);
-extern u16 wlc_stf_spatial_expansion_get(wlc_info_t *wlc, ratespec_t rspec);
+extern int wlc_stf_ant_txant_validate(struct wlc_info *wlc, s8 val);
+extern void wlc_stf_phy_txant_upd(struct wlc_info *wlc);
+extern void wlc_stf_phy_chain_calc(struct wlc_info *wlc);
+extern u16 wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec);
+extern u16 wlc_stf_d11hdrs_phyctl_txant(struct wlc_info *wlc, ratespec_t rspec);
+extern u16 wlc_stf_spatial_expansion_get(struct wlc_info *wlc,
+ ratespec_t rspec);
#endif /* _wlc_stf_h_ */
diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h
index 33047ebab979..df6e04c6ac58 100644
--- a/drivers/staging/brcm80211/sys/wlc_types.h
+++ b/drivers/staging/brcm80211/sys/wlc_types.h
@@ -19,34 +19,19 @@
/* forward declarations */
-typedef struct wlc_info wlc_info_t;
-typedef struct wlc_hw_info wlc_hw_info_t;
-typedef struct wlc_if wlc_if_t;
-typedef struct wl_if wl_if_t;
-typedef struct led_info led_info_t;
-typedef struct bmac_led bmac_led_t;
-typedef struct bmac_led_info bmac_led_info_t;
-typedef struct scb_module scb_module_t;
-typedef struct ba_info ba_info_t;
-typedef struct ampdu_info ampdu_info_t;
-typedef struct ratesel_info ratesel_info_t;
-typedef struct wlc_ap_info wlc_ap_info_t;
-typedef struct wlc_auth_info wlc_auth_info_t;
-typedef struct supplicant supplicant_t;
-typedef struct authenticator authenticator_t;
-typedef struct antsel_info antsel_info_t;
-#if !defined(WLC_LOW)
-typedef struct rpctx_info rpctx_info_t;
-#endif
-#ifdef WLC_LOW
-typedef struct bmac_pmq bmac_pmq_t;
-#endif
+struct wlc_info;
+struct wlc_hw_info;
+struct wlc_if;
+struct wl_if;
+struct ampdu_info;
+struct antsel_info;
+struct bmac_pmq;
struct d11init;
#ifndef _hnddma_pub_
#define _hnddma_pub_
-typedef const struct hnddma_pub hnddma_t;
+struct hnddma_pub;
#endif /* _hnddma_pub_ */
#endif /* _wlc_types_h_ */
diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c
index 75a7e3a5c009..ddd2f9d64c20 100644
--- a/drivers/staging/brcm80211/util/aiutils.c
+++ b/drivers/staging/brcm80211/util/aiutils.c
@@ -14,11 +14,16 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmutils.h>
#include <siutils.h>
#include <hndsoc.h>
@@ -26,8 +31,8 @@
#include <pcicfg.h>
#include <bcmdevs.h>
-#define BCM47162_DMP() ((CHIPID(sih->chip) == BCM47162_CHIP_ID) && \
- (CHIPREV(sih->chiprev) == 0) && \
+#define BCM47162_DMP() ((sih->chip == BCM47162_CHIP_ID) && \
+ (sih->chiprev == 0) && \
(sii->coreid[sii->curidx] == MIPS74K_CORE_ID))
/* EROM parsing */
@@ -115,7 +120,7 @@ void ai_scan(si_t *sih, void *regs, uint devid)
erombase = R_REG(sii->osh, &cc->eromptr);
- switch (BUSTYPE(sih->bustype)) {
+ switch (sih->bustype) {
case SI_BUS:
eromptr = (u32 *) REG_MAP(erombase, SI_CORE_SIZE);
break;
@@ -125,7 +130,7 @@ void ai_scan(si_t *sih, void *regs, uint devid)
sii->curwrap = (void *)((unsigned long)regs + SI_CORE_SIZE);
/* Now point the window at the erom */
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
+ pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, erombase);
eromptr = regs;
break;
@@ -330,7 +335,7 @@ void *ai_setcoreidx(si_t *sih, uint coreidx)
ASSERT((sii->intrsenabled_fn == NULL)
|| !(*(sii)->intrsenabled_fn) ((sii)->intr_arg));
- switch (BUSTYPE(sih->bustype)) {
+ switch (sih->bustype) {
case SI_BUS:
/* map new one */
if (!sii->regs[coreidx]) {
@@ -347,10 +352,10 @@ void *ai_setcoreidx(si_t *sih, uint coreidx)
case PCI_BUS:
/* point bar0 window */
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr);
+ pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, addr);
regs = sii->curmap;
/* point bar0 2nd 4KB window */
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap);
+ pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN2, wrap);
break;
#ifdef BCMSDIO
@@ -504,7 +509,7 @@ uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
if (coreidx >= SI_MAXCORES)
return 0;
- if (BUSTYPE(sih->bustype) == SI_BUS) {
+ if (sih->bustype == SI_BUS) {
/* If internal bus, we can always get at everything */
fast = true;
/* map if does not exist */
@@ -514,7 +519,7 @@ uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
ASSERT(GOODREGS(sii->regs[coreidx]));
}
r = (u32 *) ((unsigned char *) sii->regs[coreidx] + regoff);
- } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
+ } else if (sih->bustype == PCI_BUS) {
/* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c
index c909832c7ee1..d820e7b9e970 100644
--- a/drivers/staging/brcm80211/util/bcmotp.c
+++ b/drivers/staging/brcm80211/util/bcmotp.c
@@ -14,11 +14,13 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <bcmdefs.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmdevs.h>
#include <bcmutils.h>
#include <siutils.h>
@@ -77,7 +79,7 @@ typedef struct {
uint ccrev; /* chipc revision */
otp_fn_t *fn; /* OTP functions */
si_t *sih; /* Saved sb handle */
- osl_t *osh;
+ struct osl_info *osh;
#ifdef BCMIPXOTP
/* IPX OTP section */
@@ -221,7 +223,7 @@ static int ipxotp_max_rgnsz(si_t *sih, int osizew)
{
int ret = 0;
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
@@ -271,8 +273,8 @@ static void _ipxotp_init(otpinfo_t *oi, chipcregs_t *cc)
/* Read OTP lock bits and subregion programmed indication bits */
oi->status = R_REG(oi->osh, &cc->otpstatus);
- if ((CHIPID(oi->sih->chip) == BCM43224_CHIP_ID)
- || (CHIPID(oi->sih->chip) == BCM43225_CHIP_ID)) {
+ if ((oi->sih->chip == BCM43224_CHIP_ID)
+ || (oi->sih->chip == BCM43225_CHIP_ID)) {
u32 p_bits;
p_bits =
(ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
@@ -569,7 +571,7 @@ static int hndotp_size(void *oh)
static u16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn)
{
otpinfo_t *oi = (otpinfo_t *) oh;
- osl_t *osh;
+ struct osl_info *osh;
volatile u16 *ptr;
ASSERT(wn < ((oi->size / 2) + OTP_RC_LIM_OFF));
@@ -584,7 +586,7 @@ static u16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn)
static u16 hndotp_otproff(void *oh, chipcregs_t *cc, int woff)
{
otpinfo_t *oi = (otpinfo_t *) oh;
- osl_t *osh;
+ struct osl_info *osh;
volatile u16 *ptr;
ASSERT(woff >= (-((int)oi->size / 2)));
@@ -603,7 +605,7 @@ static u16 hndotp_read_bit(void *oh, chipcregs_t *cc, uint idx)
otpinfo_t *oi = (otpinfo_t *) oh;
uint k, row, col;
u32 otpp, st;
- osl_t *osh;
+ struct osl_info *osh;
osh = si_osh(oi->sih);
row = idx / 65;
@@ -636,7 +638,7 @@ static void *hndotp_init(si_t *sih)
otpinfo_t *oi;
u32 cap = 0, clkdiv, otpdiv = 0;
void *ret = NULL;
- osl_t *osh;
+ struct osl_info *osh;
oi = &otpinfo;
@@ -900,7 +902,7 @@ void *otp_init(si_t *sih)
void *ret = NULL;
oi = &otpinfo;
- bzero(oi, sizeof(otpinfo_t));
+ memset(oi, 0, sizeof(otpinfo_t));
oi->ccrev = sih->ccrev;
diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c
index 1282ef7eb922..19d45026a5ee 100644
--- a/drivers/staging/brcm80211/util/bcmsrom.c
+++ b/drivers/staging/brcm80211/util/bcmsrom.c
@@ -15,9 +15,11 @@
*/
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/etherdevice.h>
#include <bcmdefs.h>
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <stdarg.h>
#include <bcmutils.h>
#include <hndsoc.h>
@@ -66,29 +68,30 @@ extern uint _varsz;
#define SROM_CIS_SINGLE 1
-static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars,
- uint *count);
+static int initvars_srom_si(si_t *sih, struct osl_info *osh, void *curmap,
+ char **vars, uint *count);
static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off,
varbuf_t *b);
static int initvars_srom_pci(si_t *sih, void *curmap, char **vars,
uint *count);
static int initvars_flash_si(si_t *sih, char **vars, uint *count);
#ifdef BCMSDIO
-static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count);
-static int sprom_cmd_sdio(osl_t *osh, u8 cmd);
-static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data);
+static int initvars_cis_sdio(struct osl_info *osh, char **vars, uint *count);
+static int sprom_cmd_sdio(struct osl_info *osh, u8 cmd);
+static int sprom_read_sdio(struct osl_info *osh, u16 addr, u16 *data);
#endif /* BCMSDIO */
-static int sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff,
- u16 *buf, uint nwords, bool check_crc);
+static int sprom_read_pci(struct osl_info *osh, si_t *sih, u16 *sprom,
+ uint wordoff, u16 *buf, uint nwords, bool check_crc);
#if defined(BCMNVRAMR)
-static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz);
+static int otp_read_pci(struct osl_info *osh, si_t *sih, u16 *buf, uint bufsz);
#endif
-static u16 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd,
+static u16 srom_cc_cmd(si_t *sih, struct osl_info *osh, void *ccregs, u32 cmd,
uint wordoff, u16 data);
-static int initvars_table(osl_t *osh, char *start, char *end, char **vars,
- uint *count);
-static int initvars_flash(si_t *sih, osl_t *osh, char **vp, uint len);
+static int initvars_table(struct osl_info *osh, char *start, char *end,
+ char **vars, uint *count);
+static int initvars_flash(si_t *sih, struct osl_info *osh, char **vp,
+ uint len);
/* Initialization of varbuf structure */
static void varbuf_init(varbuf_t *b, char *buf, uint size)
@@ -129,7 +132,7 @@ static int varbuf_append(varbuf_t *b, const char *fmt, ...)
if (s != NULL) {
len = (size_t) (s - b->buf);
for (s = b->base; s < b->buf;) {
- if ((bcmp(s, b->buf, len) == 0) && s[len] == '=') {
+ if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') {
len = strlen(s) + 1;
memmove(s, (s + len),
((b->buf + r + 1) - (s + len)));
@@ -155,21 +158,21 @@ static int varbuf_append(varbuf_t *b, const char *fmt, ...)
* Initialize local vars from the right source for this platform.
* Return 0 on success, nonzero on error.
*/
-int srom_var_init(si_t *sih, uint bustype, void *curmap, osl_t *osh,
+int srom_var_init(si_t *sih, uint bustype, void *curmap, struct osl_info *osh,
char **vars, uint *count)
{
uint len;
len = 0;
- ASSERT(bustype == BUSTYPE(bustype));
+ ASSERT(bustype == bustype);
if (vars == NULL || count == NULL)
return 0;
*vars = NULL;
*count = 0;
- switch (BUSTYPE(bustype)) {
+ switch (bustype) {
case SI_BUS:
case JTAG_BUS:
return initvars_srom_si(sih, osh, curmap, vars, count);
@@ -194,7 +197,7 @@ int srom_var_init(si_t *sih, uint bustype, void *curmap, osl_t *osh,
/* support only 16-bit word read from srom */
int
-srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
+srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh,
uint byteoff, uint nbytes, u16 *buf, bool check_crc)
{
uint off, nw;
@@ -202,7 +205,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
uint i;
#endif /* BCMSDIO */
- ASSERT(bustype == BUSTYPE(bustype));
+ ASSERT(bustype == bustype);
/* check input - 16-bit access only */
if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > SROM_MAX)
@@ -211,7 +214,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
off = byteoff / 2;
nw = nbytes / 2;
- if (BUSTYPE(bustype) == PCI_BUS) {
+ if (bustype == PCI_BUS) {
if (!curmap)
return 1;
@@ -233,7 +236,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
}
#endif
#ifdef BCMSDIO
- } else if (BUSTYPE(bustype) == SDIO_BUS) {
+ } else if (bustype == SDIO_BUS) {
off = byteoff / 2;
nw = nbytes / 2;
for (i = 0; i < nw; i++) {
@@ -242,7 +245,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh,
return 1;
}
#endif /* BCMSDIO */
- } else if (BUSTYPE(bustype) == SI_BUS) {
+ } else if (bustype == SI_BUS) {
return 1;
} else {
return 1;
@@ -376,7 +379,8 @@ u8 patch_pair;
/* For dongle HW, accept partial calibration parameters */
#define BCMDONGLECASE(n)
-int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count)
+int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars,
+ uint *count)
{
char eabuf[32];
char *base;
@@ -402,7 +406,7 @@ int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count)
return -2;
varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
- bzero(base, MAXSZ_NVRAM_VARS);
+ memset(base, 0, MAXSZ_NVRAM_VARS);
eabuf[0] = '\0';
for (cisnum = 0; cisnum < ciscnt; cisnum++) {
cis = *pcis++;
@@ -496,12 +500,12 @@ int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count)
break;
default:
/* set macaddr if HNBU_MACADDR not seen yet */
- if (eabuf[0] == '\0'
- && cis[i] == LAN_NID
- && !(ETHER_ISNULLADDR(&cis[i + 2]))
- && !(ETHER_ISMULTI(&cis[i + 2]))) {
+ if (eabuf[0] == '\0' &&
+ cis[i] == LAN_NID &&
+ !is_zero_ether_addr(&cis[i + 2]) &&
+ !is_multicast_ether_addr(&cis[i + 2])) {
ASSERT(cis[i + 1] ==
- ETHER_ADDR_LEN);
+ ETH_ALEN);
snprintf(eabuf, sizeof(eabuf),
"%pM", &cis[i + 2]);
@@ -970,8 +974,8 @@ int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count)
break;
case HNBU_MACADDR:
- if (!(ETHER_ISNULLADDR(&cis[i + 1])) &&
- !(ETHER_ISMULTI(&cis[i + 1]))) {
+ if (!is_zero_ether_addr(&cis[i + 1]) &&
+ !is_multicast_ether_addr(&cis[i + 1])) {
snprintf(eabuf, sizeof(eabuf),
"%pM", &cis[i + 1]);
@@ -1405,8 +1409,8 @@ int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count)
* not in the bus cores.
*/
static u16
-srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd, uint wordoff,
- u16 data)
+srom_cc_cmd(si_t *sih, struct osl_info *osh, void *ccregs, u32 cmd,
+ uint wordoff, u16 data)
{
chipcregs_t *cc = (chipcregs_t *) ccregs;
uint wait_cnt = 1000;
@@ -1439,7 +1443,7 @@ srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd, uint wordoff,
* Return 0 on success, nonzero on error.
*/
static int
-sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff,
+sprom_read_pci(struct osl_info *osh, si_t *sih, u16 *sprom, uint wordoff,
u16 *buf, uint nwords, bool check_crc)
{
int err = 0;
@@ -1499,7 +1503,7 @@ sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff,
}
#if defined(BCMNVRAMR)
-static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz)
+static int otp_read_pci(struct osl_info *osh, si_t *sih, u16 *buf, uint bufsz)
{
u8 *otp;
uint sz = OTP_SZ_MAX / 2; /* size in words */
@@ -1547,8 +1551,8 @@ static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz)
* Create variable table from memory.
* Return 0 on success, nonzero on error.
*/
-static int initvars_table(osl_t *osh, char *start, char *end, char **vars,
- uint *count)
+static int initvars_table(struct osl_info *osh, char *start, char *end,
+ char **vars, uint *count)
{
int c = (int)(end - start);
@@ -1574,7 +1578,8 @@ static int initvars_table(osl_t *osh, char *start, char *end, char **vars,
* of the table upon enter and to the end of the table upon exit when success.
* Return 0 on success, nonzero on error.
*/
-static int initvars_flash(si_t *sih, osl_t *osh, char **base, uint len)
+static int initvars_flash(si_t *sih, struct osl_info *osh, char **base,
+ uint len)
{
char *vp = *base;
char *flash;
@@ -1634,7 +1639,7 @@ static int initvars_flash(si_t *sih, osl_t *osh, char **base, uint len)
*/
static int initvars_flash_si(si_t *sih, char **vars, uint *count)
{
- osl_t *osh = si_osh(sih);
+ struct osl_info *osh = si_osh(sih);
char *vp, *base;
int err;
@@ -1845,7 +1850,7 @@ static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count)
u32 sr;
varbuf_t b;
char *vp, *base = NULL;
- osl_t *osh = si_osh(sih);
+ struct osl_info *osh = si_osh(sih);
bool flash = false;
int err = 0;
@@ -1986,7 +1991,7 @@ static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count)
* Read the SDIO cis and call parsecis to initialize the vars.
* Return 0 on success, nonzero on error.
*/
-static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count)
+static int initvars_cis_sdio(struct osl_info *osh, char **vars, uint *count)
{
u8 *cis[SBSDIO_NUM_FUNCTION + 1];
uint fn, numfn;
@@ -2020,7 +2025,7 @@ static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count)
}
/* set SDIO sprom command register */
-static int sprom_cmd_sdio(osl_t *osh, u8 cmd)
+static int sprom_cmd_sdio(struct osl_info *osh, u8 cmd)
{
u8 status = 0;
uint wait_cnt = 1000;
@@ -2040,7 +2045,7 @@ static int sprom_cmd_sdio(osl_t *osh, u8 cmd)
}
/* read a word from the SDIO srom */
-static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data)
+static int sprom_read_sdio(struct osl_info *osh, u16 addr, u16 *data)
{
u8 addr_l, addr_h, data_l, data_h;
@@ -2068,8 +2073,8 @@ static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data)
}
#endif /* BCMSDIO */
-static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars,
- uint *varsz)
+static int initvars_srom_si(si_t *sih, struct osl_info *osh, void *curmap,
+ char **vars, uint *varsz)
{
/* Search flash nvram section for srom variables */
return initvars_flash_si(sih, vars, varsz);
diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c
index 9789ea45ecd6..fd30cc6fb7f8 100644
--- a/drivers/staging/brcm80211/util/bcmutils.c
+++ b/drivers/staging/brcm80211/util/bcmutils.c
@@ -19,8 +19,10 @@
#include <linux/string.h>
#include <bcmdefs.h>
#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
#include <osl.h>
-#include <linuxver.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmnvram.h>
@@ -30,26 +32,26 @@
#include <proto/802.1d.h>
#include <proto/802.11.h>
-
/* copy a buffer into a pkt buffer chain */
-uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
+uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, uint offset, int len,
+ unsigned char *buf)
{
uint n, ret = 0;
/* skip 'offset' bytes */
- for (; p && offset; p = PKTNEXT(p)) {
- if (offset < (uint) PKTLEN(p))
+ for (; p && offset; p = p->next) {
+ if (offset < (uint) (p->len))
break;
- offset -= PKTLEN(p);
+ offset -= p->len;
}
if (!p)
return 0;
/* copy the data */
- for (; p && len; p = PKTNEXT(p)) {
- n = min((uint) PKTLEN(p) - offset, (uint) len);
- bcopy(buf, PKTDATA(p) + offset, n);
+ for (; p && len; p = p->next) {
+ n = min((uint) (p->len) - offset, (uint) len);
+ bcopy(buf, p->data + offset, n);
buf += n;
len -= n;
ret += n;
@@ -59,13 +61,13 @@ uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
return ret;
}
/* return total length of buffer chain */
-uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
+uint BCMFASTPATH pkttotlen(struct osl_info *osh, struct sk_buff *p)
{
uint total;
total = 0;
- for (; p; p = PKTNEXT(p))
- total += PKTLEN(p);
+ for (; p; p = p->next)
+ total += p->len;
return total;
}
@@ -73,12 +75,13 @@ uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
* osl multiple-precedence packet queue
* hi_prec is always >= the number of the highest non-empty precedence
*/
-void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
+struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec,
+ struct sk_buff *p)
{
struct pktq_prec *q;
ASSERT(prec >= 0 && prec < pq->num_prec);
- ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
+ ASSERT(p->prev == NULL); /* queueing chains not allowed */
ASSERT(!pktq_full(pq));
ASSERT(!pktq_pfull(pq, prec));
@@ -86,7 +89,7 @@ void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
q = &pq->q[prec];
if (q->head)
- PKTSETLINK(q->tail, p);
+ q->tail->prev = p;
else
q->head = p;
@@ -101,12 +104,13 @@ void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
return p;
}
-void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
+struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec,
+ struct sk_buff *p)
{
struct pktq_prec *q;
ASSERT(prec >= 0 && prec < pq->num_prec);
- ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
+ ASSERT(p->prev == NULL); /* queueing chains not allowed */
ASSERT(!pktq_full(pq));
ASSERT(!pktq_pfull(pq, prec));
@@ -116,7 +120,7 @@ void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
if (q->head == NULL)
q->tail = p;
- PKTSETLINK(p, q->head);
+ p->prev = q->head;
q->head = p;
q->len++;
@@ -128,10 +132,10 @@ void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
return p;
}
-void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
+struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
{
struct pktq_prec *q;
- void *p;
+ struct sk_buff *p;
ASSERT(prec >= 0 && prec < pq->num_prec);
@@ -141,7 +145,7 @@ void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
if (p == NULL)
return NULL;
- q->head = PKTLINK(p);
+ q->head = p->prev;
if (q->head == NULL)
q->tail = NULL;
@@ -149,15 +153,15 @@ void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
pq->len--;
- PKTSETLINK(p, NULL);
+ p->prev = NULL;
return p;
}
-void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
+struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
{
struct pktq_prec *q;
- void *p, *prev;
+ struct sk_buff *p, *prev;
ASSERT(prec >= 0 && prec < pq->num_prec);
@@ -167,11 +171,11 @@ void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
if (p == NULL)
return NULL;
- for (prev = NULL; p != q->tail; p = PKTLINK(p))
+ for (prev = NULL; p != q->tail; p = p->prev)
prev = p;
if (prev)
- PKTSETLINK(prev, NULL);
+ prev->prev = NULL;
else
q->head = NULL;
@@ -184,17 +188,17 @@ void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
}
#ifdef BRCM_FULLMAC
-void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
+void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir)
{
struct pktq_prec *q;
- void *p;
+ struct sk_buff *p;
q = &pq->q[prec];
p = q->head;
while (p) {
- q->head = PKTLINK(p);
- PKTSETLINK(p, NULL);
- PKTFREE(osh, p, dir);
+ q->head = p->prev;
+ p->prev = NULL;
+ pkt_buf_free_skb(osh, p, dir);
q->len--;
pq->len--;
p = q->head;
@@ -203,7 +207,7 @@ void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
q->tail = NULL;
}
-void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
+void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir)
{
int prec;
for (prec = 0; prec < pq->num_prec; prec++)
@@ -212,11 +216,11 @@ void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
}
#else /* !BRCM_FULLMAC */
void
-pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
- int arg)
+pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
+ ifpkt_cb_t fn, int arg)
{
struct pktq_prec *q;
- void *p, *prev = NULL;
+ struct sk_buff *p, *prev = NULL;
q = &pq->q[prec];
p = q->head;
@@ -224,17 +228,17 @@ pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
if (fn == NULL || (*fn) (p, arg)) {
bool head = (p == q->head);
if (head)
- q->head = PKTLINK(p);
+ q->head = p->prev;
else
- PKTSETLINK(prev, PKTLINK(p));
- PKTSETLINK(p, NULL);
- PKTFREE(osh, p, dir);
+ prev->prev = p->prev;
+ p->prev = NULL;
+ pkt_buf_free_skb(osh, p, dir);
q->len--;
pq->len--;
- p = (head ? q->head : PKTLINK(prev));
+ p = (head ? q->head : prev->prev);
} else {
prev = p;
- p = PKTLINK(p);
+ p = p->prev;
}
}
@@ -244,7 +248,8 @@ pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
}
}
-void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
+void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
+ ifpkt_cb_t fn, int arg)
{
int prec;
for (prec = 0; prec < pq->num_prec; prec++)
@@ -261,7 +266,7 @@ void pktq_init(struct pktq *pq, int num_prec, int max_len)
ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
/* pq is variable size; only zero out what's requested */
- bzero(pq,
+ memset(pq, 0,
offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
pq->num_prec = (u16) num_prec;
@@ -272,7 +277,7 @@ void pktq_init(struct pktq *pq, int num_prec, int max_len)
pq->q[prec].max = pq->max;
}
-void *pktq_peek_tail(struct pktq *pq, int *prec_out)
+struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
{
int prec;
@@ -303,10 +308,11 @@ int pktq_mlen(struct pktq *pq, uint prec_bmp)
return len;
}
/* Priority dequeue from a specific set of precedences */
-void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
+struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
+ int *prec_out)
{
struct pktq_prec *q;
- void *p;
+ struct sk_buff *p;
int prec;
if (pq->len == 0)
@@ -325,7 +331,7 @@ void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
if (p == NULL)
return NULL;
- q->head = PKTLINK(p);
+ q->head = p->prev;
if (q->head == NULL)
q->tail = NULL;
@@ -336,7 +342,7 @@ void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
pq->len--;
- PKTSETLINK(p, NULL);
+ p->prev = NULL;
return p;
}
@@ -373,7 +379,7 @@ char *getvar(char *vars, const char *name)
/* first look in vars[] */
for (s = vars; s && *s;) {
- if ((bcmp(s, name, len) == 0) && (s[len] == '='))
+ if ((memcmp(s, name, len) == 0) && (s[len] == '='))
return &s[len + 1];
while (*s++)
@@ -404,15 +410,15 @@ int getintvar(char *vars, const char *name)
#if defined(BCMDBG)
/* pretty hex print a pkt buffer chain */
-void prpkt(const char *msg, osl_t *osh, void *p0)
+void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0)
{
- void *p;
+ struct sk_buff *p;
if (msg && (msg[0] != '\0'))
printf("%s:\n", msg);
- for (p = p0; p; p = PKTNEXT(p))
- prhex(NULL, PKTDATA(p), PKTLEN(p));
+ for (p = p0; p; p = p->next)
+ prhex(NULL, p->data, p->len);
}
#endif /* defined(BCMDBG) */
diff --git a/drivers/staging/brcm80211/util/bcmwifi.c b/drivers/staging/brcm80211/util/bcmwifi.c
index 1bb6c78eece7..81e54bd7a554 100644
--- a/drivers/staging/brcm80211/util/bcmwifi.c
+++ b/drivers/staging/brcm80211/util/bcmwifi.c
@@ -15,6 +15,10 @@
*/
#include <linux/ctype.h>
#include <linux/kernel.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
+#include <osl.h>
#include <bcmdefs.h>
#include <bcmutils.h>
#include <bcmwifi.h>
diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c
index fe503e7de563..d08869239d5b 100644
--- a/drivers/staging/brcm80211/util/hnddma.c
+++ b/drivers/staging/brcm80211/util/hnddma.c
@@ -16,7 +16,8 @@
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linuxver.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#include <osl.h>
@@ -28,6 +29,10 @@
#include <sbhnddma.h>
#include <hnddma.h>
+#if defined(__mips__)
+#include <asm/addrspace.h>
+#endif
+
/* debug/trace */
#ifdef BCMDBG
#define DMA_ERROR(args) \
@@ -68,11 +73,12 @@ static uint dma_msg_level;
#define DI_INFO(dmah) ((dma_info_t *)dmah)
+#define R_SM(r) (*(r))
+#define W_SM(r, v) (*(r) = (v))
+
/* dma engine software state */
typedef struct dma_info {
- struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t,
- * which could be const
- */
+ struct hnddma_pub hnddma; /* exported structure */
uint *msg_level; /* message level pointer */
char name[MAXNAMEL]; /* callers name for diag msgs */
@@ -222,7 +228,7 @@ static void _dma_counterreset(dma_info_t *di);
static void _dma_fifoloopbackenable(dma_info_t *di);
static uint _dma_ctrlflags(dma_info_t *di, uint mask, uint flags);
static u8 dma_align_sizetobits(uint size);
-static void *dma_ringalloc(osl_t *osh, u32 boundary, uint size,
+static void *dma_ringalloc(struct osl_info *osh, u32 boundary, uint size,
u16 *alignbits, uint *alloced,
dmaaddr_t *descpa, osldma_t **dmah);
@@ -231,7 +237,7 @@ static bool dma32_alloc(dma_info_t *di, uint direction);
static bool dma32_txreset(dma_info_t *di);
static bool dma32_rxreset(dma_info_t *di);
static bool dma32_txsuspendedidle(dma_info_t *di);
-static int dma32_txfast(dma_info_t *di, void *p0, bool commit);
+static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit);
static void *dma32_getnexttxp(dma_info_t *di, txd_range_t range);
static void *dma32_getnextrxp(dma_info_t *di, bool forceall);
static void dma32_txrotate(dma_info_t *di);
@@ -246,14 +252,14 @@ static bool dma32_txstopped(dma_info_t *di);
static bool dma32_rxstopped(dma_info_t *di);
static bool dma32_rxenabled(dma_info_t *di);
-static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs);
+static bool _dma32_addrext(struct osl_info *osh, dma32regs_t *dma32regs);
/* Prototypes for 64-bit routines */
static bool dma64_alloc(dma_info_t *di, uint direction);
static bool dma64_txreset(dma_info_t *di);
static bool dma64_rxreset(dma_info_t *di);
static bool dma64_txsuspendedidle(dma_info_t *di);
-static int dma64_txfast(dma_info_t *di, void *p0, bool commit);
+static int dma64_txfast(dma_info_t *di, struct sk_buff *p0, bool commit);
static int dma64_txunframed(dma_info_t *di, void *p0, uint len, bool commit);
static void *dma64_getpos(dma_info_t *di, bool direction);
static void *dma64_getnexttxp(dma_info_t *di, txd_range_t range);
@@ -270,7 +276,7 @@ static void dma64_txreclaim(dma_info_t *di, txd_range_t range);
static bool dma64_txstopped(dma_info_t *di);
static bool dma64_rxstopped(dma_info_t *di);
static bool dma64_rxenabled(dma_info_t *di);
-static bool _dma64_addrext(osl_t *osh, dma64regs_t *dma64regs);
+static bool _dma64_addrext(struct osl_info *osh, dma64regs_t *dma64regs);
static inline u32 parity32(u32 data);
@@ -368,10 +374,10 @@ static const di_fcn_t dma32proc = {
39
};
-hnddma_t *dma_attach(osl_t *osh, char *name, si_t *sih, void *dmaregstx,
- void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize,
- int rxextheadroom, uint nrxpost, uint rxoffset,
- uint *msg_level)
+struct hnddma_pub *dma_attach(struct osl_info *osh, char *name, si_t *sih,
+ void *dmaregstx, void *dmaregsrx, uint ntxd,
+ uint nrxd, uint rxbufsize, int rxextheadroom,
+ uint nrxpost, uint rxoffset, uint *msg_level)
{
dma_info_t *di;
uint size;
@@ -570,7 +576,7 @@ hnddma_t *dma_attach(osl_t *osh, char *name, si_t *sih, void *dmaregstx,
}
}
- return (hnddma_t *) di;
+ return (struct hnddma_pub *) di;
fail:
_dma_detach(di);
@@ -663,7 +669,7 @@ dma64_dd_upd(dma_info_t *di, dma64dd_t *ddring, dmaaddr_t pa, uint outidx,
}
}
-static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs)
+static bool _dma32_addrext(struct osl_info *osh, dma32regs_t *dma32regs)
{
u32 w;
@@ -902,7 +908,7 @@ static void _dma_rxinit(dma_info_t *di)
/* clear rx descriptor ring */
if (DMA64_ENAB(di) && DMA64_MODE(di)) {
- BZERO_SM((void *)di->rxd64,
+ memset((void *)di->rxd64, '\0',
(di->nrxd * sizeof(dma64dd_t)));
/* DMA engine with out alignment requirement requires table to be inited
@@ -916,7 +922,7 @@ static void _dma_rxinit(dma_info_t *di)
if (di->aligndesc_4k)
_dma_ddtable_init(di, DMA_RX, di->rxdpa);
} else if (DMA32_ENAB(di)) {
- BZERO_SM((void *)di->rxd32,
+ memset((void *)di->rxd32, '\0',
(di->nrxd * sizeof(dma32dd_t)));
_dma_rxenable(di);
_dma_ddtable_init(di, DMA_RX, di->rxdpa);
@@ -978,7 +984,7 @@ _dma_rx_param_get(dma_info_t *di, u16 *rxoffset, u16 *rxbufsize)
*/
static void *BCMFASTPATH _dma_rx(dma_info_t *di)
{
- void *p, *head, *tail;
+ struct sk_buff *p, *head, *tail;
uint len;
uint pkt_len;
int resid = 0;
@@ -988,30 +994,31 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di)
if (head == NULL)
return NULL;
- len = ltoh16(*(u16 *) (PKTDATA(head)));
+ len = ltoh16(*(u16 *) (head->data));
DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
#if defined(__mips__)
+#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va)))
if (!len) {
- while (!(len = *(u16 *) OSL_UNCACHED(PKTDATA(head))))
+ while (!(len = *(u16 *) OSL_UNCACHED(head->data)))
udelay(1);
- *(u16 *) PKTDATA(head) = htol16((u16) len);
+ *(u16 *) (head->data) = htol16((u16) len);
}
#endif /* defined(__mips__) */
/* set actual length */
pkt_len = min((di->rxoffset + len), di->rxbufsize);
- PKTSETLEN(head, pkt_len);
+ __skb_trim(head, pkt_len);
resid = len - (di->rxbufsize - di->rxoffset);
/* check for single or multi-buffer rx */
if (resid > 0) {
tail = head;
while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
- PKTSETNEXT(tail, p);
+ tail->next = p;
pkt_len = min(resid, (int)di->rxbufsize);
- PKTSETLEN(p, pkt_len);
+ __skb_trim(p, pkt_len);
tail = p;
resid -= di->rxbufsize;
@@ -1037,7 +1044,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di)
if ((di->hnddma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n",
di->name, len));
- PKTFREE(di->osh, head, false);
+ pkt_buf_free_skb(di->osh, head, false);
di->hnddma.rxgiants++;
goto next_frame;
}
@@ -1053,7 +1060,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di)
*/
static bool BCMFASTPATH _dma_rxfill(dma_info_t *di)
{
- void *p;
+ struct sk_buff *p;
u16 rxin, rxout;
u32 flags = 0;
uint n;
@@ -1085,7 +1092,7 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di)
size to be allocated
*/
- p = osl_pktget(di->osh, di->rxbufsize + extra_offset);
+ p = pkt_buf_get_skb(di->osh, di->rxbufsize + extra_offset);
if (p == NULL) {
DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n",
@@ -1109,17 +1116,18 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di)
}
/* reserve an extra headroom, if applicable */
if (extra_offset)
- PKTPULL(p, extra_offset);
+ skb_pull(p, extra_offset);
/* Do a cached write instead of uncached write since DMA_MAP
* will flush the cache.
*/
- *(u32 *) (PKTDATA(p)) = 0;
+ *(u32 *) (p->data) = 0;
if (DMASGLIST_ENAB)
- bzero(&di->rxp_dmah[rxout], sizeof(hnddma_seg_map_t));
+ memset(&di->rxp_dmah[rxout], 0,
+ sizeof(hnddma_seg_map_t));
- pa = DMA_MAP(di->osh, PKTDATA(p),
+ pa = DMA_MAP(di->osh, p->data,
di->rxbufsize, DMA_RX, p, &di->rxp_dmah[rxout]);
ASSERT(IS_ALIGNED(PHYSADDRLO(pa), 4));
@@ -1220,15 +1228,10 @@ static void _dma_rxreclaim(dma_info_t *di)
{
void *p;
- /* "unused local" warning suppression for OSLs that
- * define PKTFREE() without using the di->osh arg
- */
- di = di;
-
DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
while ((p = _dma_getnextrxp(di, true)))
- PKTFREE(di->osh, p, false);
+ pkt_buf_free_skb(di->osh, p, false);
}
static void *BCMFASTPATH _dma_getnextrxp(dma_info_t *di, bool forceall)
@@ -1372,7 +1375,7 @@ static unsigned long _dma_getvar(dma_info_t *di, const char *name)
return 0;
}
-void dma_txpioloopback(osl_t *osh, dma32regs_t *regs)
+void dma_txpioloopback(struct osl_info *osh, dma32regs_t *regs)
{
OR_REG(osh, &regs->control, XC_LE);
}
@@ -1395,7 +1398,7 @@ u8 dma_align_sizetobits(uint size)
* descriptor ring size aligned location. This will ensure that the ring will
* not cross page boundary
*/
-static void *dma_ringalloc(osl_t *osh, u32 boundary, uint size,
+static void *dma_ringalloc(struct osl_info *osh, u32 boundary, uint size,
u16 *alignbits, uint *alloced,
dmaaddr_t *descpa, osldma_t **dmah)
{
@@ -1434,7 +1437,7 @@ static void dma32_txinit(dma_info_t *di)
di->hnddma.txavail = di->ntxd - 1;
/* clear tx descriptor ring */
- BZERO_SM((void *)di->txd32, (di->ntxd * sizeof(dma32dd_t)));
+ memset((void *)di->txd32, '\0', (di->ntxd * sizeof(dma32dd_t)));
if ((di->hnddma.dmactrlflags & DMA_CTRL_PEN) == 0)
control |= XC_PD;
@@ -1491,7 +1494,7 @@ static void dma32_txreclaim(dma_info_t *di, txd_range_t range)
return;
while ((p = dma32_getnexttxp(di, range)))
- PKTFREE(di->osh, p, true);
+ pkt_buf_free_skb(di->osh, p, true);
}
static bool dma32_txstopped(dma_info_t *di)
@@ -1651,9 +1654,9 @@ static bool dma32_txsuspendedidle(dma_info_t *di)
* WARNING: call must check the return value for error.
* the error(toss frames) could be fatal and cause many subsequent hard to debug problems
*/
-static int dma32_txfast(dma_info_t *di, void *p0, bool commit)
+static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit)
{
- void *p, *next;
+ struct sk_buff *p, *next;
unsigned char *data;
uint len;
u16 txout;
@@ -1672,12 +1675,12 @@ static int dma32_txfast(dma_info_t *di, void *p0, bool commit)
uint nsegs, j;
hnddma_seg_map_t *map;
- data = PKTDATA(p);
- len = PKTLEN(p);
+ data = p->data;
+ len = p->len;
#ifdef BCM_DMAPAD
len += PKTDMAPAD(di->osh, p);
#endif
- next = PKTNEXT(p);
+ next = p->next;
/* return nonzero if out of tx descriptors */
if (NEXTTXD(txout) == di->txin)
@@ -1687,7 +1690,8 @@ static int dma32_txfast(dma_info_t *di, void *p0, bool commit)
continue;
if (DMASGLIST_ENAB)
- bzero(&di->txp_dmah[txout], sizeof(hnddma_seg_map_t));
+ memset(&di->txp_dmah[txout], 0,
+ sizeof(hnddma_seg_map_t));
/* get physical address of buffer start */
pa = DMA_MAP(di->osh, data, len, DMA_TX, p,
@@ -1761,7 +1765,7 @@ static int dma32_txfast(dma_info_t *di, void *p0, bool commit)
outoftxd:
DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
- PKTFREE(di->osh, p0, true);
+ pkt_buf_free_skb(di->osh, p0, true);
di->hnddma.txavail = 0;
di->hnddma.txnobuf++;
return -1;
@@ -1959,7 +1963,7 @@ static void dma32_txrotate(dma_info_t *di)
if (DMASGLIST_ENAB) {
bcopy(&di->txp_dmah[old], &di->txp_dmah[new],
sizeof(hnddma_seg_map_t));
- bzero(&di->txp_dmah[old], sizeof(hnddma_seg_map_t));
+ memset(&di->txp_dmah[old], 0, sizeof(hnddma_seg_map_t));
}
di->txp[old] = NULL;
@@ -1989,7 +1993,7 @@ static void dma64_txinit(dma_info_t *di)
di->hnddma.txavail = di->ntxd - 1;
/* clear tx descriptor ring */
- BZERO_SM((void *)di->txd64, (di->ntxd * sizeof(dma64dd_t)));
+ memset((void *)di->txd64, '\0', (di->ntxd * sizeof(dma64dd_t)));
/* DMA engine with out alignment requirement requires table to be inited
* before enabling the engine
@@ -2060,7 +2064,7 @@ static void BCMFASTPATH dma64_txreclaim(dma_info_t *di, txd_range_t range)
while ((p = dma64_getnexttxp(di, range))) {
/* For unframed data, we don't have any packets to free */
if (!(di->hnddma.dmactrlflags & DMA_CTRL_UNFRAMED))
- PKTFREE(di->osh, p, true);
+ pkt_buf_free_skb(di->osh, p, true);
}
}
@@ -2300,9 +2304,10 @@ static int dma64_txunframed(dma_info_t *di, void *buf, uint len, bool commit)
* WARNING: call must check the return value for error.
* the error(toss frames) could be fatal and cause many subsequent hard to debug problems
*/
-static int BCMFASTPATH dma64_txfast(dma_info_t *di, void *p0, bool commit)
+static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0,
+ bool commit)
{
- void *p, *next;
+ struct sk_buff *p, *next;
unsigned char *data;
uint len;
u16 txout;
@@ -2321,12 +2326,12 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, void *p0, bool commit)
uint nsegs, j;
hnddma_seg_map_t *map;
- data = PKTDATA(p);
- len = PKTLEN(p);
+ data = p->data;
+ len = p->len;
#ifdef BCM_DMAPAD
len += PKTDMAPAD(di->osh, p);
#endif /* BCM_DMAPAD */
- next = PKTNEXT(p);
+ next = p->next;
/* return nonzero if out of tx descriptors */
if (NEXTTXD(txout) == di->txin)
@@ -2337,7 +2342,8 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, void *p0, bool commit)
/* get physical address of buffer start */
if (DMASGLIST_ENAB)
- bzero(&di->txp_dmah[txout], sizeof(hnddma_seg_map_t));
+ memset(&di->txp_dmah[txout], 0,
+ sizeof(hnddma_seg_map_t));
pa = DMA_MAP(di->osh, data, len, DMA_TX, p,
&di->txp_dmah[txout]);
@@ -2409,7 +2415,7 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, void *p0, bool commit)
outoftxd:
DMA_ERROR(("%s: dma_txfast: out of txds !!!\n", di->name));
- PKTFREE(di->osh, p0, true);
+ pkt_buf_free_skb(di->osh, p0, true);
di->hnddma.txavail = 0;
di->hnddma.txnobuf++;
return -1;
@@ -2563,7 +2569,7 @@ static void *BCMFASTPATH dma64_getnextrxp(dma_info_t *di, bool forceall)
return rxp;
}
-static bool _dma64_addrext(osl_t *osh, dma64regs_t * dma64regs)
+static bool _dma64_addrext(struct osl_info *osh, dma64regs_t * dma64regs)
{
u32 w;
OR_REG(osh, &dma64regs->control, D64_XC_AE);
@@ -2635,7 +2641,7 @@ static void dma64_txrotate(dma_info_t *di)
if (DMASGLIST_ENAB) {
bcopy(&di->txp_dmah[old], &di->txp_dmah[new],
sizeof(hnddma_seg_map_t));
- bzero(&di->txp_dmah[old], sizeof(hnddma_seg_map_t));
+ memset(&di->txp_dmah[old], 0, sizeof(hnddma_seg_map_t));
}
di->txp[old] = NULL;
@@ -2654,7 +2660,7 @@ static void dma64_txrotate(dma_info_t *di)
uint dma_addrwidth(si_t *sih, void *dmaregs)
{
dma32regs_t *dma32regs;
- osl_t *osh;
+ struct osl_info *osh;
osh = si_osh(sih);
@@ -2664,8 +2670,8 @@ uint dma_addrwidth(si_t *sih, void *dmaregs)
/* backplane are 64-bit capable */
if (si_backplane64(sih))
/* If bus is System Backplane or PCIE then we can access 64-bits */
- if ((BUSTYPE(sih->bustype) == SI_BUS) ||
- ((BUSTYPE(sih->bustype) == PCI_BUS) &&
+ if ((sih->bustype == SI_BUS) ||
+ ((sih->bustype == PCI_BUS) &&
(sih->buscoretype == PCIE_CORE_ID)))
return DMADDRWIDTH_64;
@@ -2679,8 +2685,8 @@ uint dma_addrwidth(si_t *sih, void *dmaregs)
dma32regs = (dma32regs_t *) dmaregs;
/* For System Backplane, PCIE bus or addrext feature, 32-bits ok */
- if ((BUSTYPE(sih->bustype) == SI_BUS) ||
- ((BUSTYPE(sih->bustype) == PCI_BUS)
+ if ((sih->bustype == SI_BUS) ||
+ ((sih->bustype == PCI_BUS)
&& sih->buscoretype == PCIE_CORE_ID)
|| (_dma32_addrext(osh, dma32regs)))
return DMADDRWIDTH_32;
diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c
index a8f3306c1d2b..6cc59a895868 100644
--- a/drivers/staging/brcm80211/util/hndpmu.c
+++ b/drivers/staging/brcm80211/util/hndpmu.c
@@ -13,9 +13,14 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
@@ -40,23 +45,23 @@
#define PMU_NONE(args)
/* PLL controls/clocks */
-static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc,
+static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc,
u32 xtal);
-static u32 si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc);
-static u32 si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc);
+static u32 si_pmu1_cpuclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc);
+static u32 si_pmu1_alpclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc);
/* PMU resources */
static bool si_pmu_res_depfltr_bb(si_t *sih);
static bool si_pmu_res_depfltr_ncb(si_t *sih);
static bool si_pmu_res_depfltr_paldo(si_t *sih);
static bool si_pmu_res_depfltr_npaldo(si_t *sih);
-static u32 si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc,
+static u32 si_pmu_res_deps(si_t *sih, struct osl_info *osh, chipcregs_t *cc,
u32 rsrcs, bool all);
-static uint si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc,
+static uint si_pmu_res_uptime(si_t *sih, struct osl_info *osh, chipcregs_t *cc,
u8 rsrc);
static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax);
static void si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc,
- osl_t *osh, u8 spuravoid);
+ struct osl_info *osh, u8 spuravoid);
static void si_pmu_set_4330_plldivs(si_t *sih);
@@ -101,7 +106,7 @@ void si_pmu_pllupd(si_t *sih)
}
/* Setup switcher voltage */
-void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh, u8 bb_voltage,
+void si_pmu_set_switcher_voltage(si_t *sih, struct osl_info *osh, u8 bb_voltage,
u8 rf_voltage)
{
chipcregs_t *cc;
@@ -124,14 +129,14 @@ void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh, u8 bb_voltage,
si_setcoreidx(sih, origidx);
}
-void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo, u8 voltage)
+void si_pmu_set_ldo_voltage(si_t *sih, struct osl_info *osh, u8 ldo, u8 voltage)
{
u8 sr_cntl_shift = 0, rc_shift = 0, shift = 0, mask = 0;
u8 addr = 0;
ASSERT(sih->cccaps & CC_CAP_PMU);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4336_CHIP_ID:
switch (ldo) {
case SET_LDO_VOLTAGE_CLDO_PWM:
@@ -182,7 +187,7 @@ void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo, u8 voltage)
/* d11 slow to fast clock transition time in slow clock cycles */
#define D11SCC_SLOW2FAST_TRANSITION 2
-u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh)
+u16 si_pmu_fast_pwrup_delay(si_t *sih, struct osl_info *osh)
{
uint delay = PMU_MAX_TRANSITION_DLY;
chipcregs_t *cc;
@@ -199,7 +204,7 @@ u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
case BCM43421_CHIP_ID:
@@ -259,7 +264,7 @@ u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh)
return (u16) delay;
}
-u32 si_pmu_force_ilp(si_t *sih, osl_t *osh, bool force)
+u32 si_pmu_force_ilp(si_t *sih, struct osl_info *osh, bool force)
{
chipcregs_t *cc;
uint origidx;
@@ -599,7 +604,7 @@ static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax)
rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
/* determine min/max rsrc masks */
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
case BCM43421_CHIP_ID:
@@ -677,7 +682,7 @@ static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax)
}
/* initialize PMU resources */
-void si_pmu_res_init(si_t *sih, osl_t *osh)
+void si_pmu_res_init(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -696,7 +701,7 @@ void si_pmu_res_init(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
/* Optimize resources up/down timers */
if (ISSIM_ENAB(sih)) {
@@ -1095,7 +1100,7 @@ static const pmu1_xtaltab0_t *si_pmu1_xtaltab0(si_t *sih)
#ifdef BCMDBG
char chn[8];
#endif
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
return pmu1_xtaltab0_880_4329;
case BCM4319_CHIP_ID:
@@ -1123,7 +1128,7 @@ static const pmu1_xtaltab0_t *si_pmu1_xtaldef0(si_t *sih)
char chn[8];
#endif
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
/* Default to 38400Khz */
return &pmu1_xtaltab0_880_4329[PMU1_XTALTAB0_880_38400K];
@@ -1155,7 +1160,7 @@ static u32 si_pmu1_pllfvco0(si_t *sih)
char chn[8];
#endif
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
return FVCO_880;
case BCM4319_CHIP_ID:
@@ -1178,7 +1183,7 @@ static u32 si_pmu1_pllfvco0(si_t *sih)
/* query alp/xtal clock frequency */
static u32
-si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc)
+si_pmu1_alpclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc)
{
const pmu1_xtaltab0_t *xt;
u32 xf;
@@ -1203,7 +1208,8 @@ si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc)
* case the xtal frequency is unknown to the s/w so we need to call
* si_pmu1_xtaldef0() wherever it is needed to return a default value.
*/
-static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
+static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc,
+ u32 xtal)
{
const pmu1_xtaltab0_t *xt;
u32 tmp;
@@ -1233,8 +1239,8 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
*/
if ((((R_REG(osh, &cc->pmucontrol) & PCTL_XTALFREQ_MASK) >>
PCTL_XTALFREQ_SHIFT) == xt->xf) &&
- !((CHIPID(sih->chip) == BCM4319_CHIP_ID)
- || (CHIPID(sih->chip) == BCM4330_CHIP_ID))) {
+ !((sih->chip == BCM4319_CHIP_ID)
+ || (sih->chip == BCM4330_CHIP_ID))) {
PMU_MSG(("PLL already programmed for %d.%d MHz\n",
xt->fref / 1000, xt->fref % 1000));
return;
@@ -1244,7 +1250,7 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
PMU_MSG(("Programming PLL for %d.%d MHz\n", xt->fref / 1000,
xt->fref % 1000));
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
/* Change the BBPLL drive strength to 8 for all channels */
buf_strength = 0x888888;
@@ -1351,11 +1357,11 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
p2div << PMU1_PLL0_PC0_P2DIV_SHIFT) & PMU1_PLL0_PC0_P2DIV_MASK);
W_REG(osh, &cc->pllcontrol_data, tmp);
- if ((CHIPID(sih->chip) == BCM4330_CHIP_ID))
+ if ((sih->chip == BCM4330_CHIP_ID))
si_pmu_set_4330_plldivs(sih);
- if ((CHIPID(sih->chip) == BCM4329_CHIP_ID)
- && (CHIPREV(sih->chiprev) == 0)) {
+ if ((sih->chip == BCM4329_CHIP_ID)
+ && (sih->chiprev == 0)) {
W_REG(osh, &cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
tmp = R_REG(osh, &cc->pllcontrol_data);
@@ -1363,9 +1369,9 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
tmp = tmp | DOT11MAC_880MHZ_CLK_DIVISOR_VAL;
W_REG(osh, &cc->pllcontrol_data, tmp);
}
- if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4336_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4330_CHIP_ID))
+ if ((sih->chip == BCM4319_CHIP_ID) ||
+ (sih->chip == BCM4336_CHIP_ID) ||
+ (sih->chip == BCM4330_CHIP_ID))
ndiv_mode = PMU1_PLL0_PC2_NDIV_MODE_MFB;
else
ndiv_mode = PMU1_PLL0_PC2_NDIV_MODE_MASH;
@@ -1407,7 +1413,7 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
/* to operate the 4319 usb in 24MHz/48MHz; chipcontrol[2][84:83] needs
* to be updated.
*/
- if ((CHIPID(sih->chip) == BCM4319_CHIP_ID)
+ if ((sih->chip == BCM4319_CHIP_ID)
&& (xt->fref != XTAL_FREQ_30000MHZ)) {
W_REG(osh, &cc->chipcontrol_addr, PMU1_PLL0_CHIPCTL2);
tmp =
@@ -1436,8 +1442,8 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
PCTL_ILP_DIV_MASK) |
((xt->xf << PCTL_XTALFREQ_SHIFT) & PCTL_XTALFREQ_MASK);
- if ((CHIPID(sih->chip) == BCM4329_CHIP_ID)
- && CHIPREV(sih->chiprev) == 0) {
+ if ((sih->chip == BCM4329_CHIP_ID)
+ && sih->chiprev == 0) {
/* clear the htstretch before clearing HTReqEn */
AND_REG(osh, &cc->clkstretch, ~CSTRETCH_HT);
tmp &= ~PCTL_HT_REQ_EN;
@@ -1448,7 +1454,7 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal)
/* query the CPU clock frequency */
static u32
-si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc)
+si_pmu1_cpuclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc)
{
u32 tmp, m1div;
#ifdef BCMDBG
@@ -1502,7 +1508,7 @@ si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc)
}
/* initialize PLL */
-void si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq)
+void si_pmu_pll_init(si_t *sih, struct osl_info *osh, uint xtalfreq)
{
chipcregs_t *cc;
uint origidx;
@@ -1517,7 +1523,7 @@ void si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
if (xtalfreq == 0)
xtalfreq = 38400;
@@ -1555,7 +1561,7 @@ void si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq)
}
/* query alp/xtal clock frequency */
-u32 si_pmu_alp_clock(si_t *sih, osl_t *osh)
+u32 si_pmu_alp_clock(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -1571,7 +1577,7 @@ u32 si_pmu_alp_clock(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
case BCM43421_CHIP_ID:
@@ -1616,7 +1622,7 @@ u32 si_pmu_alp_clock(si_t *sih, osl_t *osh)
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
*/
static u32
-si_pmu5_clock(si_t *sih, osl_t *osh, chipcregs_t *cc, uint pll0,
+si_pmu5_clock(si_t *sih, struct osl_info *osh, chipcregs_t *cc, uint pll0,
uint m) {
u32 tmp, div, ndiv, p1, p2, fc;
@@ -1631,7 +1637,7 @@ si_pmu5_clock(si_t *sih, osl_t *osh, chipcregs_t *cc, uint pll0,
return 0;
}
- if (CHIPID(sih->chip) == BCM5357_CHIP_ID) {
+ if (sih->chip == BCM5357_CHIP_ID) {
/* Detect failure in clock setting */
if ((R_REG(osh, &cc->chipstatus) & 0x40000) != 0) {
return 133 * 1000000;
@@ -1669,7 +1675,7 @@ si_pmu5_clock(si_t *sih, osl_t *osh, chipcregs_t *cc, uint pll0,
/* For designs that feed the same clock to both backplane
* and CPU just return the CPU clock speed.
*/
-u32 si_pmu_si_clock(si_t *sih, osl_t *osh)
+u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -1685,7 +1691,7 @@ u32 si_pmu_si_clock(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
case BCM43421_CHIP_ID:
@@ -1702,7 +1708,7 @@ u32 si_pmu_si_clock(si_t *sih, osl_t *osh)
PMU5_MAINPLL_SI);
break;
case BCM4329_CHIP_ID:
- if (CHIPREV(sih->chiprev) == 0)
+ if (sih->chiprev == 0)
clock = 38400 * 1000;
else
clock = si_pmu1_cpuclk0(sih, osh, cc);
@@ -1748,7 +1754,7 @@ u32 si_pmu_si_clock(si_t *sih, osl_t *osh)
}
/* query CPU clock frequency */
-u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh)
+u32 si_pmu_cpu_clock(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -1757,14 +1763,14 @@ u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh)
ASSERT(sih->cccaps & CC_CAP_PMU);
if ((sih->pmurev >= 5) &&
- !((CHIPID(sih->chip) == BCM4329_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4319_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM43236_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4336_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4330_CHIP_ID))) {
+ !((sih->chip == BCM4329_CHIP_ID) ||
+ (sih->chip == BCM4319_CHIP_ID) ||
+ (sih->chip == BCM43236_CHIP_ID) ||
+ (sih->chip == BCM4336_CHIP_ID) ||
+ (sih->chip == BCM4330_CHIP_ID))) {
uint pll;
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM5356_CHIP_ID:
pll = PMU5356_MAINPLL_PLL0;
break;
@@ -1792,7 +1798,7 @@ u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh)
}
/* query memory clock frequency */
-u32 si_pmu_mem_clock(si_t *sih, osl_t *osh)
+u32 si_pmu_mem_clock(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -1801,14 +1807,14 @@ u32 si_pmu_mem_clock(si_t *sih, osl_t *osh)
ASSERT(sih->cccaps & CC_CAP_PMU);
if ((sih->pmurev >= 5) &&
- !((CHIPID(sih->chip) == BCM4329_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4319_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4330_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM4336_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM43236_CHIP_ID))) {
+ !((sih->chip == BCM4329_CHIP_ID) ||
+ (sih->chip == BCM4319_CHIP_ID) ||
+ (sih->chip == BCM4330_CHIP_ID) ||
+ (sih->chip == BCM4336_CHIP_ID) ||
+ (sih->chip == BCM43236_CHIP_ID))) {
uint pll;
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM5356_CHIP_ID:
pll = PMU5356_MAINPLL_PLL0;
break;
@@ -1841,7 +1847,7 @@ u32 si_pmu_mem_clock(si_t *sih, osl_t *osh)
static u32 ilpcycles_per_sec;
-u32 si_pmu_ilp_clock(si_t *sih, osl_t *osh)
+u32 si_pmu_ilp_clock(si_t *sih, struct osl_info *osh)
{
if (ISSIM_ENAB(sih))
return ILP_CLOCK;
@@ -1905,7 +1911,7 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
void
-si_sdiod_drive_strength_init(si_t *sih, osl_t *osh,
+si_sdiod_drive_strength_init(si_t *sih, struct osl_info *osh,
u32 drivestrength) {
chipcregs_t *cc;
uint origidx, intr_val = 0;
@@ -1976,7 +1982,7 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh,
}
/* initialize PMU */
-void si_pmu_init(si_t *sih, osl_t *osh)
+void si_pmu_init(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -1993,7 +1999,7 @@ void si_pmu_init(si_t *sih, osl_t *osh)
else if (sih->pmurev >= 2)
OR_REG(osh, &cc->pmucontrol, PCTL_NOILP_ON_WAIT);
- if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 2)) {
+ if ((sih->chip == BCM4329_CHIP_ID) && (sih->chiprev == 2)) {
/* Fix for 4329b0 bad LPOM state. */
W_REG(osh, &cc->regcontrol_addr, 2);
OR_REG(osh, &cc->regcontrol_data, 0x100);
@@ -2008,7 +2014,7 @@ void si_pmu_init(si_t *sih, osl_t *osh)
/* Return up time in ILP cycles for the given resource. */
static uint
-si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc,
+si_pmu_res_uptime(si_t *sih, struct osl_info *osh, chipcregs_t *cc,
u8 rsrc) {
u32 deps;
uint up, i, dup, dmax;
@@ -2045,7 +2051,7 @@ si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc,
/* Return dependancies (direct or all/indirect) for the given resources */
static u32
-si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 rsrcs,
+si_pmu_res_deps(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u32 rsrcs,
bool all)
{
u32 deps = 0;
@@ -2065,7 +2071,7 @@ si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 rsrcs,
}
/* power up/down OTP through PMU resources */
-void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on)
+void si_pmu_otp_power(si_t *sih, struct osl_info *osh, bool on)
{
chipcregs_t *cc;
uint origidx;
@@ -2084,7 +2090,7 @@ void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
rsrcs = PMURES_BIT(RES4329_OTP_PU);
break;
@@ -2135,7 +2141,7 @@ void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on)
si_setcoreidx(sih, origidx);
}
-void si_pmu_rcal(si_t *sih, osl_t *osh)
+void si_pmu_rcal(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
@@ -2147,7 +2153,7 @@ void si_pmu_rcal(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:{
u8 rcal_code;
u32 val;
@@ -2218,7 +2224,7 @@ void si_pmu_rcal(si_t *sih, osl_t *osh)
si_setcoreidx(sih, origidx);
}
-void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid)
+void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid)
{
chipcregs_t *cc;
uint origidx, intr_val;
@@ -2230,7 +2236,7 @@ void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid)
ASSERT(cc != NULL);
/* force the HT off */
- if (CHIPID(sih->chip) == BCM4336_CHIP_ID) {
+ if (sih->chip == BCM4336_CHIP_ID) {
tmp = R_REG(osh, &cc->max_res_mask);
tmp &= ~RES4336_HT_AVAIL;
W_REG(osh, &cc->max_res_mask, tmp);
@@ -2244,7 +2250,7 @@ void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid)
si_pmu_spuravoid_pllupdate(sih, cc, osh, spuravoid);
/* enable HT back on */
- if (CHIPID(sih->chip) == BCM4336_CHIP_ID) {
+ if (sih->chip == BCM4336_CHIP_ID) {
tmp = R_REG(osh, &cc->max_res_mask);
tmp |= RES4336_HT_AVAIL;
W_REG(osh, &cc->max_res_mask, tmp);
@@ -2255,7 +2261,7 @@ void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid)
}
static void
-si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, osl_t *osh,
+si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, struct osl_info *osh,
u8 spuravoid)
{
u32 tmp = 0;
@@ -2263,14 +2269,14 @@ si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, osl_t *osh,
u8 bcm5357_bcm43236_p1div[] = { 0x1, 0x5, 0x5 };
u8 bcm5357_bcm43236_ndiv[] = { 0x30, 0xf6, 0xfc };
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM5357_CHIP_ID:
case BCM43235_CHIP_ID:
case BCM43236_CHIP_ID:
case BCM43238_CHIP_ID:
/* BCM5357 needs to touch PLL1_PLLCTL[02], so offset PLL0_PLLCTL[02] by 6 */
- phypll_offset = (CHIPID(sih->chip) == BCM5357_CHIP_ID) ? 6 : 0;
+ phypll_offset = (sih->chip == BCM5357_CHIP_ID) ? 6 : 0;
/* RMW only the P1 divider */
W_REG(osh, &cc->pllcontrol_addr,
@@ -2451,7 +2457,7 @@ si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, osl_t *osh,
W_REG(osh, &cc->pmucontrol, tmp);
}
-bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh)
+bool si_pmu_is_otp_powered(si_t *sih, struct osl_info *osh)
{
uint idx;
chipcregs_t *cc;
@@ -2462,7 +2468,7 @@ bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh)
cc = si_setcoreidx(sih, SI_CC_IDX);
ASSERT(cc != NULL);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
st = (R_REG(osh, &cc->res_state) & PMURES_BIT(RES4329_OTP_PU))
!= 0;
@@ -2503,9 +2509,9 @@ bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh)
void
#if defined(BCMDBG)
-si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable)
+si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable)
#else
-si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable)
+si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable)
#endif
{
chipcregs_t *cc;
@@ -2521,7 +2527,7 @@ si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable)
}
/* initialize PMU chip controls and other chip level stuff */
-void si_pmu_chip_init(si_t *sih, osl_t *osh)
+void si_pmu_chip_init(si_t *sih, struct osl_info *osh)
{
uint origidx;
@@ -2543,11 +2549,11 @@ void si_pmu_chip_init(si_t *sih, osl_t *osh)
}
/* initialize PMU switch/regulators */
-void si_pmu_swreg_init(si_t *sih, osl_t *osh)
+void si_pmu_swreg_init(si_t *sih, struct osl_info *osh)
{
ASSERT(sih->cccaps & CC_CAP_PMU);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4336_CHIP_ID:
/* Reduce CLDO PWM output voltage to 1.2V */
si_pmu_set_ldo_voltage(sih, osh, SET_LDO_VOLTAGE_CLDO_PWM, 0xe);
@@ -2556,7 +2562,7 @@ void si_pmu_swreg_init(si_t *sih, osl_t *osh)
0xe);
/* Reduce LNLDO1 output voltage to 1.2V */
si_pmu_set_ldo_voltage(sih, osh, SET_LDO_VOLTAGE_LNLDO1, 0xe);
- if (CHIPREV(sih->chiprev) == 0)
+ if (sih->chiprev == 0)
si_pmu_regcontrol(sih, 2, 0x400000, 0x400000);
break;
@@ -2573,7 +2579,7 @@ void si_pmu_radio_enable(si_t *sih, bool enable)
{
ASSERT(sih->cccaps & CC_CAP_PMU);
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4319_CHIP_ID:
if (enable)
si_write_wrapperreg(sih, AI_OOBSELOUTB74,
@@ -2587,7 +2593,7 @@ void si_pmu_radio_enable(si_t *sih, bool enable)
/* Wait for a particular clock level to be on the backplane */
u32
-si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, u32 clk,
+si_pmu_waitforclk_on_backplane(si_t *sih, struct osl_info *osh, u32 clk,
u32 delay)
{
chipcregs_t *cc;
@@ -2616,7 +2622,7 @@ si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, u32 clk,
#define EXT_ILP_HZ 32768
-u32 si_pmu_measure_alpclk(si_t *sih, osl_t *osh)
+u32 si_pmu_measure_alpclk(si_t *sih, struct osl_info *osh)
{
chipcregs_t *cc;
uint origidx;
diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c
index 2bb5b8722df6..e6716e823baa 100644
--- a/drivers/staging/brcm80211/util/linux_osl.c
+++ b/drivers/staging/brcm80211/util/linux_osl.c
@@ -20,145 +20,57 @@
#include <asm/paccess.h>
#endif /* mips */
#include <bcmendian.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <pcicfg.h>
-#define PCI_CFG_RETRY 10
-
#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
-struct osl_info {
- osl_pubinfo_t pub;
- uint magic;
- void *pdev;
- uint failed;
- uint bustype;
-};
-
/* Global ASSERT type flag */
u32 g_assert_type;
-#ifdef BRCM_FULLMAC
-static s16 linuxbcmerrormap[] = { 0, /* 0 */
- -EINVAL, /* BCME_ERROR */
- -EINVAL, /* BCME_BADARG */
- -EINVAL, /* BCME_BADOPTION */
- -EINVAL, /* BCME_NOTUP */
- -EINVAL, /* BCME_NOTDOWN */
- -EINVAL, /* BCME_NOTAP */
- -EINVAL, /* BCME_NOTSTA */
- -EINVAL, /* BCME_BADKEYIDX */
- -EINVAL, /* BCME_RADIOOFF */
- -EINVAL, /* BCME_NOTBANDLOCKED */
- -EINVAL, /* BCME_NOCLK */
- -EINVAL, /* BCME_BADRATESET */
- -EINVAL, /* BCME_BADBAND */
- -E2BIG, /* BCME_BUFTOOSHORT */
- -E2BIG, /* BCME_BUFTOOLONG */
- -EBUSY, /* BCME_BUSY */
- -EINVAL, /* BCME_NOTASSOCIATED */
- -EINVAL, /* BCME_BADSSIDLEN */
- -EINVAL, /* BCME_OUTOFRANGECHAN */
- -EINVAL, /* BCME_BADCHAN */
- -EFAULT, /* BCME_BADADDR */
- -ENOMEM, /* BCME_NORESOURCE */
- -EOPNOTSUPP, /* BCME_UNSUPPORTED */
- -EMSGSIZE, /* BCME_BADLENGTH */
- -EINVAL, /* BCME_NOTREADY */
- -EPERM, /* BCME_NOTPERMITTED */
- -ENOMEM, /* BCME_NOMEM */
- -EINVAL, /* BCME_ASSOCIATED */
- -ERANGE, /* BCME_RANGE */
- -EINVAL, /* BCME_NOTFOUND */
- -EINVAL, /* BCME_WME_NOT_ENABLED */
- -EINVAL, /* BCME_TSPEC_NOTFOUND */
- -EINVAL, /* BCME_ACM_NOTSUPPORTED */
- -EINVAL, /* BCME_NOT_WME_ASSOCIATION */
- -EIO, /* BCME_SDIO_ERROR */
- -ENODEV, /* BCME_DONGLE_DOWN */
- -EINVAL, /* BCME_VERSION */
- -EIO, /* BCME_TXFAIL */
- -EIO, /* BCME_RXFAIL */
- -EINVAL, /* BCME_NODEVICE */
- -EINVAL, /* BCME_NMODE_DISABLED */
- -ENODATA, /* BCME_NONRESIDENT */
-
-/* When an new error code is added to bcmutils.h, add os
- * spcecific error translation here as well
- */
-/* check if BCME_LAST changed since the last time this function was updated */
-#if BCME_LAST != -42
-#error "You need to add a OS error translation in the linuxbcmerrormap \
- for new error code defined in bcmutils.h"
-#endif
-};
-
-/* translate bcmerrors into linux errors */
-int osl_error(int bcmerror)
-{
- if (bcmerror > 0)
- bcmerror = 0;
- else if (bcmerror < BCME_LAST)
- bcmerror = BCME_ERROR;
-
- /* Array bounds covered by ASSERT in osl_attach */
- return linuxbcmerrormap[-bcmerror];
-}
-#endif /* BRCM_FULLMAC */
-
-osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
+struct osl_info *osl_attach(void *pdev, uint bustype)
{
- osl_t *osh;
+ struct osl_info *osh;
- osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
+ osh = kmalloc(sizeof(struct osl_info), GFP_ATOMIC);
ASSERT(osh);
- bzero(osh, sizeof(osl_t));
-
-#ifdef BRCM_FULLMAC
- /* Check that error map has the right number of entries in it */
- ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(linuxbcmerrormap) - 1));
-#endif /* BRCM_FULLMAC */
+ memset(osh, 0, sizeof(struct osl_info));
osh->magic = OS_HANDLE_MAGIC;
- osh->failed = 0;
osh->pdev = pdev;
- osh->pub.pkttag = pkttag;
osh->bustype = bustype;
switch (bustype) {
case PCI_BUS:
case SI_BUS:
case PCMCIA_BUS:
- osh->pub.mmbus = true;
+ osh->mmbus = true;
break;
case JTAG_BUS:
case SDIO_BUS:
case USB_BUS:
case SPI_BUS:
case RPC_BUS:
- osh->pub.mmbus = false;
+ osh->mmbus = false;
break;
default:
ASSERT(false);
break;
}
-#if defined(BCMDBG) && !defined(BRCM_FULLMAC)
- if (pkttag) {
- struct sk_buff *skb;
- ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb));
- }
-#endif
return osh;
}
-void osl_detach(osl_t *osh)
+void osl_detach(struct osl_info *osh)
{
if (osh == NULL)
return;
@@ -167,8 +79,7 @@ void osl_detach(osl_t *osh)
kfree(osh);
}
-/* Return a new packet. zero out pkttag */
-void *BCMFASTPATH osl_pktget(osl_t *osh, uint len)
+struct sk_buff *BCMFASTPATH pkt_buf_get_skb(struct osl_info *osh, uint len)
{
struct sk_buff *skb;
@@ -177,24 +88,20 @@ void *BCMFASTPATH osl_pktget(osl_t *osh, uint len)
skb_put(skb, len);
skb->priority = 0;
- osh->pub.pktalloced++;
+ osh->pktalloced++;
}
- return (void *)skb;
+ return skb;
}
/* Free the driver packet. Free the tag if present */
-void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send)
+void BCMFASTPATH pkt_buf_free_skb(struct osl_info *osh, struct sk_buff *skb, bool send)
{
- struct sk_buff *skb, *nskb;
+ struct sk_buff *nskb;
int nest = 0;
- skb = (struct sk_buff *)p;
ASSERT(skb);
- if (send && osh->pub.tx_fn)
- osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
-
/* perversion: we use skb->next to chain multi-skb packets */
while (skb) {
nskb = skb->next;
@@ -211,63 +118,14 @@ void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send)
*/
dev_kfree_skb(skb);
- osh->pub.pktalloced--;
+ osh->pktalloced--;
nest++;
skb = nskb;
}
}
-u32 osl_pci_read_config(osl_t *osh, uint offset, uint size)
-{
- uint val = 0;
- uint retry = PCI_CFG_RETRY;
-
- ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
-
- /* only 4byte access supported */
- ASSERT(size == 4);
-
- do {
- pci_read_config_dword(osh->pdev, offset, &val);
- if (val != 0xffffffff)
- break;
- } while (retry--);
-
-#ifdef BCMDBG
- if (retry < PCI_CFG_RETRY)
- printk("PCI CONFIG READ access to %d required %d retries\n",
- offset, (PCI_CFG_RETRY - retry));
-#endif /* BCMDBG */
-
- return val;
-}
-
-void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
-{
- uint retry = PCI_CFG_RETRY;
-
- ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
-
- /* only 4byte access supported */
- ASSERT(size == 4);
-
- do {
- pci_write_config_dword(osh->pdev, offset, val);
- if (offset != PCI_BAR0_WIN)
- break;
- if (osl_pci_read_config(osh, offset, size) == val)
- break;
- } while (retry--);
-
-#if defined(BCMDBG) && !defined(BRCM_FULLMAC)
- if (retry < PCI_CFG_RETRY)
- printk("PCI CONFIG WRITE access to %d required %d retries\n",
- offset, (PCI_CFG_RETRY - retry));
-#endif /* BCMDBG */
-}
-
/* return bus # for the pci device pointed by osh->pdev */
-uint osl_pci_bus(osl_t *osh)
+uint osl_pci_bus(struct osl_info *osh)
{
ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
@@ -275,40 +133,37 @@ uint osl_pci_bus(osl_t *osh)
}
/* return slot # for the pci device pointed by osh->pdev */
-uint osl_pci_slot(osl_t *osh)
+uint osl_pci_slot(struct osl_info *osh)
{
ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
}
-uint osl_dma_consistent_align(void)
-{
- return PAGE_SIZE;
-}
-
-void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits,
+void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, u16 align_bits,
uint *alloced, unsigned long *pap)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
if (align_bits) {
u16 align = (1 << align_bits);
- if (!IS_ALIGNED(DMA_CONSISTENT_ALIGN, align))
+ if (!IS_ALIGNED(PAGE_SIZE, align))
size += align;
*alloced = size;
}
return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
}
-void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa)
+void osl_dma_free_consistent(struct osl_info *osh, void *va, uint size,
+ unsigned long pa)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
}
-uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction)
+uint BCMFASTPATH osl_dma_map(struct osl_info *osh, void *va, uint size,
+ int direction)
{
int dir;
@@ -317,7 +172,8 @@ uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction)
return pci_map_single(osh->pdev, va, size, dir);
}
-void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
+void BCMFASTPATH osl_dma_unmap(struct osl_info *osh, uint pa, uint size,
+ int direction)
{
int dir;
@@ -373,52 +229,3 @@ void osl_assert(char *exp, char *file, int line)
}
#endif /* defined(BCMDBG_ASSERT) */
-#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
-u8 osl_readb(osl_t *osh, volatile u8 *r)
-{
- osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- return (u8) ((rreg) (ctx, (void *)r, sizeof(u8)));
-}
-
-u16 osl_readw(osl_t *osh, volatile u16 *r)
-{
- osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- return (u16) ((rreg) (ctx, (void *)r, sizeof(u16)));
-}
-
-u32 osl_readl(osl_t *osh, volatile u32 *r)
-{
- osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- return (u32) ((rreg) (ctx, (void *)r, sizeof(u32)));
-}
-
-void osl_writeb(osl_t *osh, volatile u8 *r, u8 v)
-{
- osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- ((wreg) (ctx, (void *)r, v, sizeof(u8)));
-}
-
-void osl_writew(osl_t *osh, volatile u16 *r, u16 v)
-{
- osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- ((wreg) (ctx, (void *)r, v, sizeof(u16)));
-}
-
-void osl_writel(osl_t *osh, volatile u32 *r, u32 v)
-{
- osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn;
- void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx;
-
- ((wreg) (ctx, (void *)r, v, sizeof(u32)));
-}
-#endif /* BCMSDIO */
diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c
index 23f86dd7b159..56e658c429a8 100644
--- a/drivers/staging/brcm80211/util/nicpci.c
+++ b/drivers/staging/brcm80211/util/nicpci.c
@@ -14,8 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/string.h>
-#include <linuxver.h>
+#include <linux/pci.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
@@ -35,7 +36,7 @@ typedef struct {
} regs; /* Memory mapped register to the core */
si_t *sih; /* System interconnect handle */
- osl_t *osh; /* OSL handle */
+ struct osl_info *osh; /* OSL handle */
u8 pciecap_lcreg_offset; /* PCIE capability LCreg offset in the config space */
bool pcie_pr42767;
u8 pcie_polarity;
@@ -47,7 +48,8 @@ typedef struct {
/* debug/trace */
#define PCI_ERROR(args)
-#define PCIE_PUB(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
+#define PCIE_PUB(sih) \
+ (((sih)->bustype == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID))
/* routines to access mdio slave device registers */
static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk);
@@ -71,35 +73,6 @@ static bool pcicore_pmecap(pcicore_info_t *pi);
#define PCIE_ASPM(sih) ((PCIE_PUB(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5)))
-#define DWORD_ALIGN(x) (x & ~(0x03))
-#define BYTE_POS(x) (x & 0x3)
-#define WORD_POS(x) (x & 0x1)
-
-#define BYTE_SHIFT(x) (8 * BYTE_POS(x))
-#define WORD_SHIFT(x) (16 * WORD_POS(x))
-
-#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
-#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
-
-#define read_pci_cfg_byte(a) \
- (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
-
-#define read_pci_cfg_word(a) \
- (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
-
-#define write_pci_cfg_byte(a, val) do { \
- u32 tmpval; \
- tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
- val << BYTE_POS(a); \
- OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
- } while (0)
-
-#define write_pci_cfg_word(a, val) do { \
- u32 tmpval; \
- tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
- val << WORD_POS(a); \
- OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
- } while (0)
/* delay needed between the mdio control/ mdiodata register data access */
#define PR28829_DELAY() udelay(10)
@@ -107,7 +80,7 @@ static bool pcicore_pmecap(pcicore_info_t *pi);
/* Initialize the PCI core. It's caller's responsibility to make sure that this is done
* only once
*/
-void *pcicore_init(si_t *sih, osl_t *osh, void *regs)
+void *pcicore_init(si_t *sih, struct osl_info *osh, void *regs)
{
pcicore_info_t *pi;
@@ -149,8 +122,8 @@ void pcicore_deinit(void *pch)
/* return cap_offset if requested capability exists in the PCI config space */
/* Note that it's caller's responsibility to make sure it's a pci bus */
u8
-pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf,
- u32 *buflen)
+pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id,
+ unsigned char *buf, u32 *buflen)
{
u8 cap_id;
u8 cap_ptr = 0;
@@ -158,29 +131,29 @@ pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf,
u8 byte_val;
/* check for Header type 0 */
- byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
+ pci_read_config_byte(osh->pdev, PCI_CFG_HDR, &byte_val);
if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
goto end;
/* check if the capability pointer field exists */
- byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
+ pci_read_config_byte(osh->pdev, PCI_CFG_STAT, &byte_val);
if (!(byte_val & PCI_CAPPTR_PRESENT))
goto end;
- cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
+ pci_read_config_byte(osh->pdev, PCI_CFG_CAPPTR, &cap_ptr);
/* check if the capability pointer is 0x00 */
if (cap_ptr == 0x00)
goto end;
/* loop thr'u the capability list and see if the pcie capabilty exists */
- cap_id = read_pci_cfg_byte(cap_ptr);
+ pci_read_config_byte(osh->pdev, cap_ptr, &cap_id);
while (cap_id != req_cap_id) {
- cap_ptr = read_pci_cfg_byte((cap_ptr + 1));
+ pci_read_config_byte(osh->pdev, cap_ptr + 1, &cap_ptr);
if (cap_ptr == 0x00)
break;
- cap_id = read_pci_cfg_byte(cap_ptr);
+ pci_read_config_byte(osh->pdev, cap_ptr, &cap_id);
}
if (cap_id != req_cap_id) {
goto end;
@@ -199,7 +172,7 @@ pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf,
bufsize = SZPCR - cap_data;
*buflen = bufsize;
while (bufsize--) {
- *buf = read_pci_cfg_byte(cap_data);
+ pci_read_config_byte(osh->pdev, cap_data, buf);
cap_data++;
buf++;
}
@@ -210,7 +183,8 @@ pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf,
/* ***** Register Access API */
uint
-pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset)
+pcie_readreg(struct osl_info *osh, sbpcieregs_t *pcieregs, uint addrtype,
+ uint offset)
{
uint retval = 0xFFFFFFFF;
@@ -236,8 +210,8 @@ pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset)
}
uint
-pcie_writereg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset,
- uint val)
+pcie_writereg(struct osl_info *osh, sbpcieregs_t *pcieregs, uint addrtype,
+ uint offset, uint val)
{
ASSERT(pcieregs != NULL);
@@ -373,15 +347,15 @@ u8 pcie_clkreq(void *pch, u32 mask, u32 val)
if (!offset)
return 0;
- reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, offset, &reg_val);
/* set operation */
if (mask) {
if (val)
reg_val |= PCIE_CLKREQ_ENAB;
else
reg_val &= ~PCIE_CLKREQ_ENAB;
- OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(u32), reg_val);
- reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32));
+ pci_write_config_dword(pi->osh->pdev, offset, reg_val);
+ pci_read_config_dword(pi->osh->pdev, offset, &reg_val);
}
if (reg_val & PCIE_CLKREQ_ENAB)
return 1;
@@ -393,7 +367,7 @@ static void pcie_extendL1timer(pcicore_info_t *pi, bool extend)
{
u32 w;
si_t *sih = pi->sih;
- osl_t *osh = pi->osh;
+ struct osl_info *osh = pi->osh;
sbpcieregs_t *pcieregs = pi->regs.pcieregs;
if (!PCIE_PUB(sih) || sih->buscorerev < 7)
@@ -502,12 +476,12 @@ static void pcie_war_aspm_clkreq(pcicore_info_t *pi)
W_REG(pi->osh, reg16, val16);
- w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset,
+ &w);
w &= ~PCIE_ASPM_ENAB;
w |= pi->pcie_war_aspm_ovr;
- OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
- sizeof(u32), w);
+ pci_write_config_dword(pi->osh->pdev,
+ pi->pciecap_lcreg_offset, w);
}
reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
@@ -577,7 +551,7 @@ static void pcie_war_noplldown(pcicore_info_t *pi)
static void pcie_war_pci_setup(pcicore_info_t *pi)
{
si_t *sih = pi->sih;
- osl_t *osh = pi->osh;
+ struct osl_info *osh = pi->osh;
sbpcieregs_t *pcieregs = pi->regs.pcieregs;
u32 w;
@@ -694,11 +668,9 @@ void pcicore_sleep(void *pch)
if (!pi || !PCIE_ASPM(pi->sih))
return;
- w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset, &w);
w &= ~PCIE_CAP_LCREG_ASPML1;
- OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(u32),
- w);
+ pci_write_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset, w);
pi->pcie_pr42767 = false;
}
@@ -718,7 +690,7 @@ void pcicore_down(void *pch, int state)
/* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */
/* Just uses PCI config accesses to find out, when needed before sb_attach is done */
-bool pcicore_pmecap_fast(osl_t *osh)
+bool pcicore_pmecap_fast(struct osl_info *osh)
{
u8 cap_ptr;
u32 pmecap;
@@ -730,7 +702,7 @@ bool pcicore_pmecap_fast(osl_t *osh)
if (!cap_ptr)
return false;
- pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(u32));
+ pci_read_config_dword(osh->pdev, cap_ptr, &pmecap);
return (pmecap & PME_CAP_PM_STATES) != 0;
}
@@ -753,9 +725,8 @@ static bool pcicore_pmecap(pcicore_info_t *pi)
pi->pmecap_offset = cap_ptr;
- pmecap =
- OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset,
+ &pmecap);
/* At least one state can generate PME */
pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0;
@@ -774,11 +745,11 @@ void pcicore_pmeen(void *pch)
if (!pcicore_pmecap(pi))
return;
- w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET,
+ &w);
w |= (PME_CSR_PME_EN);
- OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
- sizeof(u32), w);
+ pci_write_config_dword(pi->osh->pdev,
+ pi->pmecap_offset + PME_CSR_OFFSET, w);
}
/*
@@ -792,8 +763,8 @@ bool pcicore_pmestat(void *pch)
if (!pcicore_pmecap(pi))
return false;
- w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET,
+ &w);
return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT;
}
@@ -808,22 +779,23 @@ void pcicore_pmeclr(void *pch)
if (!pcicore_pmecap(pi))
return;
- w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
- sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET,
+ &w);
PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w));
/* PMESTAT is cleared by writing 1 to it */
w &= ~(PME_CSR_PME_EN);
- OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET,
- sizeof(u32), w);
+ pci_write_config_dword(pi->osh->pdev,
+ pi->pmecap_offset + PME_CSR_OFFSET, w);
}
u32 pcie_lcreg(void *pch, u32 mask, u32 val)
{
pcicore_info_t *pi = (pcicore_info_t *) pch;
u8 offset;
+ u32 tmpval;
offset = pi->pciecap_lcreg_offset;
if (!offset)
@@ -831,9 +803,10 @@ u32 pcie_lcreg(void *pch, u32 mask, u32 val)
/* set operation */
if (mask)
- OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(u32), val);
+ pci_write_config_dword(pi->osh->pdev, offset, val);
- return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32));
+ pci_read_config_dword(pi->osh->pdev, offset, &tmpval);
+ return tmpval;
}
u32
@@ -842,7 +815,7 @@ pcicore_pciereg(void *pch, u32 offset, u32 mask, u32 val, uint type)
u32 reg_val = 0;
pcicore_info_t *pi = (pcicore_info_t *) pch;
sbpcieregs_t *pcieregs = pi->regs.pcieregs;
- osl_t *osh = pi->osh;
+ struct osl_info *osh = pi->osh;
if (mask) {
PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val));
diff --git a/drivers/staging/brcm80211/util/nvram/nvram_ro.c b/drivers/staging/brcm80211/util/nvram/nvram_ro.c
index f80375cd6801..e4d41ee78e2a 100644
--- a/drivers/staging/brcm80211/util/nvram/nvram_ro.c
+++ b/drivers/staging/brcm80211/util/nvram/nvram_ro.c
@@ -49,7 +49,7 @@ static char *findvar(char *vars, char *lim, const char *name);
/* copy flash to ram */
static void get_flash_nvram(si_t *sih, struct nvram_header *nvh)
{
- osl_t *osh;
+ struct osl_info *osh;
uint nvs, bufsz;
vars_t *new;
@@ -133,7 +133,7 @@ static char *findvar(char *vars, char *lim, const char *name)
len = strlen(name);
for (s = vars; (s < lim) && *s;) {
- if ((bcmp(s, name, len) == 0) && (s[len] == '='))
+ if ((memcmp(s, name, len) == 0) && (s[len] == '='))
return &s[len + 1];
while (*s++)
diff --git a/drivers/staging/brcm80211/util/sbutils.c b/drivers/staging/brcm80211/util/sbutils.c
index e4c0baba553d..63c3ab1866a4 100644
--- a/drivers/staging/brcm80211/util/sbutils.c
+++ b/drivers/staging/brcm80211/util/sbutils.c
@@ -16,6 +16,9 @@
#include <linux/types.h>
#include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
@@ -87,7 +90,7 @@ static u32 _sb_coresba(si_info_t *sii)
{
u32 sbaddr = 0;
- switch (BUSTYPE(sii->pub.bustype)) {
+ switch (sii->pub.bustype) {
case SPI_BUS:
case SDIO_BUS:
sbaddr = (u32)(unsigned long)sii->curmap;
@@ -248,7 +251,7 @@ static uint _sb_scan(si_info_t *sii, u32 sba, void *regs, uint bus, u32 sbba,
else {
/* Older chips */
SI_ERROR(("sb_chip2numcores: unsupported chip "
- "0x%x\n", CHIPID(sii->pub.chip)));
+ "0x%x\n", sii->pub.chip));
ASSERT(0);
numcores = 1;
}
@@ -344,7 +347,7 @@ static void *_sb_setcoreidx(si_info_t *sii, uint coreidx)
u32 sbaddr = sii->coresba[coreidx];
void *regs;
- switch (BUSTYPE(sii->pub.bustype)) {
+ switch (sii->pub.bustype) {
#ifdef BCMSDIO
case SPI_BUS:
case SDIO_BUS:
@@ -409,8 +412,8 @@ bool sb_taclear(si_t *sih, bool details)
sii = SI_INFO(sih);
- if ((BUSTYPE(sii->pub.bustype) == SDIO_BUS) ||
- (BUSTYPE(sii->pub.bustype) == SPI_BUS)) {
+ if ((sii->pub.bustype == SDIO_BUS) ||
+ (sii->pub.bustype == SPI_BUS)) {
INTR_OFF(sii, intr_val);
origidx = si_coreidx(sih);
diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c
index f3ea7e1a7aef..b66de9b35a5a 100644
--- a/drivers/staging/brcm80211/util/siutils.c
+++ b/drivers/staging/brcm80211/util/siutils.c
@@ -14,11 +14,16 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
#include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmdevs.h>
@@ -53,7 +58,7 @@
#endif
/* local prototypes */
-static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
+static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
void *regs, uint bustype, void *sdh, char **vars,
uint *varsz);
static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
@@ -81,8 +86,8 @@ static u32 si_gpioreservation;
* vars - pointer to a pointer area for "environment" variables
* varsz - pointer to int to return the size of the vars
*/
-si_t *si_attach(uint devid, osl_t *osh, void *regs, uint bustype, void *sdh,
- char **vars, uint *varsz)
+si_t *si_attach(uint devid, struct osl_info *osh, void *regs, uint bustype,
+ void *sdh, char **vars, uint *varsz)
{
si_info_t *sii;
@@ -113,12 +118,12 @@ static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
#ifndef BRCM_FULLMAC
/* kludge to enable the clock on the 4306 which lacks a slowclock */
- if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii))
+ if (bustype == PCI_BUS && !si_ispcie(sii))
si_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
#endif
#if defined(BCMSDIO)
- if (BUSTYPE(bustype) == SDIO_BUS) {
+ if (bustype == SDIO_BUS) {
int err;
u8 clkset;
@@ -220,7 +225,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
i, cid, crev, sii->coresba[i], sii->regs[i]));
- if (BUSTYPE(bustype) == PCI_BUS) {
+ if (bustype == PCI_BUS) {
if (cid == PCI_CORE_ID) {
pciidx = i;
pcirev = crev;
@@ -232,8 +237,8 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
}
}
#ifdef BCMSDIO
- else if (((BUSTYPE(bustype) == SDIO_BUS) ||
- (BUSTYPE(bustype) == SPI_BUS)) &&
+ else if (((bustype == SDIO_BUS) ||
+ (bustype == SPI_BUS)) &&
((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) {
sii->pub.buscorerev = crev;
sii->pub.buscoretype = cid;
@@ -255,7 +260,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
* or downloaded code was
* already running.
*/
- if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
+ if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
si_core_disable(&sii->pub, 0);
@@ -281,7 +286,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
sii->pub.buscoretype, sii->pub.buscorerev));
/* fixup necessary chip/core configurations */
- if (BUSTYPE(sii->pub.bustype) == PCI_BUS) {
+ if (sii->pub.bustype == PCI_BUS) {
if (SI_FAST(sii)) {
if (!sii->pch) {
sii->pch = (void *)pcicore_init(
@@ -308,10 +313,10 @@ static __used void si_nvram_process(si_info_t *sii, char *pvars)
uint w = 0;
/* get boardtype and boardrev */
- switch (BUSTYPE(sii->pub.bustype)) {
+ switch (sii->pub.bustype) {
case PCI_BUS:
/* do a pci config read to get subsystem id and subvendor id */
- w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(u32));
+ pci_read_config_dword(sii->osh->pdev, PCI_CFG_SVID, &w);
/* Let nvram variables override subsystem Vend/ID */
sii->pub.boardvendor = (u16)si_getdevpathintvar(&sii->pub,
"boardvendor");
@@ -364,7 +369,7 @@ static __used void si_nvram_process(si_info_t *sii, char *pvars)
/* this is will make Sonics calls directly, since Sonics is no longer supported in the Si abstraction */
/* this has been customized for the bcm 4329 ONLY */
#ifdef BCMSDIO
-static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
+static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
void *regs, uint bustype, void *sdh,
char **vars, uint *varsz)
{
@@ -376,7 +381,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
ASSERT(GOODREGS(regs));
- bzero((unsigned char *) sii, sizeof(si_info_t));
+ memset((unsigned char *) sii, 0, sizeof(si_info_t));
savewin = 0;
@@ -390,11 +395,6 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
cc = (chipcregs_t *) sii->curmap;
sih->bustype = bustype;
- if (bustype != BUSTYPE(bustype)) {
- SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype)));
- return NULL;
- }
-
/* bus/core/clk setup for register access */
if (!si_buscore_prep(sii, bustype, devid, sdh)) {
SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n",
@@ -414,7 +414,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
- if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) &&
+ if ((sih->chip == BCM4329_CHIP_ID) &&
(sih->chippkg != BCM4329_289PIN_PKG_ID))
sih->chippkg = BCM4329_182PIN_PKG_ID;
@@ -444,7 +444,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
/* Init nvram from sprom/otp if they exist */
if (srom_var_init
- (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) {
+ (&sii->pub, bustype, regs, sii->osh, vars, varsz)) {
SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
goto exit;
}
@@ -499,7 +499,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
}
#else /* BCMSDIO */
-static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
+static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
void *regs, uint bustype, void *sdh,
char **vars, uint *varsz)
{
@@ -511,7 +511,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
ASSERT(GOODREGS(regs));
- bzero((unsigned char *) sii, sizeof(si_info_t));
+ memset((unsigned char *) sii, 0, sizeof(si_info_t));
savewin = 0;
@@ -522,30 +522,29 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
sii->osh = osh;
/* check to see if we are a si core mimic'ing a pci core */
- if ((bustype == PCI_BUS) &&
- (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(u32)) ==
- 0xffffffff)) {
- SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " "devid:0x%x\n", __func__, devid));
- bustype = SI_BUS;
+ if (bustype == PCI_BUS) {
+ pci_read_config_dword(sii->osh->pdev, PCI_SPROM_CONTROL, &w);
+ if (w == 0xffffffff) {
+ SI_ERROR(("%s: incoming bus is PCI but it's a lie, "
+ " switching to SI devid:0x%x\n",
+ __func__, devid));
+ bustype = SI_BUS;
+ }
}
/* find Chipcommon address */
if (bustype == PCI_BUS) {
- savewin =
- OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(u32));
+ pci_read_config_dword(sii->osh->pdev, PCI_BAR0_WIN, &savewin);
if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
savewin = SI_ENUM_BASE;
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE);
+ pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN,
+ SI_ENUM_BASE);
cc = (chipcregs_t *) regs;
} else {
cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
}
sih->bustype = bustype;
- if (bustype != BUSTYPE(bustype)) {
- SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype)));
- return NULL;
- }
/* bus/core/clk setup for register access */
if (!si_buscore_prep(sii, bustype, devid, sdh)) {
@@ -569,7 +568,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
sih->issim = IS_SIM(sih->chippkg);
/* scan for cores */
- if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
+ if (sii->pub.socitype == SOCI_AI) {
SI_MSG(("Found chip type AI (0x%08x)\n", w));
/* pass chipc address instead of original core base */
ai_scan(&sii->pub, (void *)cc, devid);
@@ -592,10 +591,10 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
/* assume current core is CC */
if ((sii->pub.ccrev == 0x25)
&&
- ((CHIPID(sih->chip) == BCM43236_CHIP_ID
- || CHIPID(sih->chip) == BCM43235_CHIP_ID
- || CHIPID(sih->chip) == BCM43238_CHIP_ID)
- && (CHIPREV(sii->pub.chiprev) <= 2))) {
+ ((sih->chip == BCM43236_CHIP_ID
+ || sih->chip == BCM43235_CHIP_ID
+ || sih->chip == BCM43238_CHIP_ID)
+ && (sii->pub.chiprev <= 2))) {
if ((cc->chipstatus & CST43236_BP_CLK) != 0) {
uint clkdiv;
@@ -613,7 +612,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
/* Init nvram from sprom/otp if they exist */
if (srom_var_init
- (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) {
+ (&sii->pub, bustype, regs, sii->osh, vars, varsz)) {
SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
goto exit;
}
@@ -651,10 +650,10 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
pcicore_attach(sii->pch, pvars, SI_DOATTACH);
}
- if ((CHIPID(sih->chip) == BCM43224_CHIP_ID) ||
- (CHIPID(sih->chip) == BCM43421_CHIP_ID)) {
+ if ((sih->chip == BCM43224_CHIP_ID) ||
+ (sih->chip == BCM43421_CHIP_ID)) {
/* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */
- if (CHIPREV(sih->chiprev) == 0) {
+ if (sih->chiprev == 0) {
SI_MSG(("Applying 43224A0 WARs\n"));
si_corereg(sih, SI_CC_IDX,
offsetof(chipcregs_t, chipcontrol),
@@ -663,28 +662,28 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE,
CCTRL_43224A0_12MA_LED_DRIVE);
}
- if (CHIPREV(sih->chiprev) >= 1) {
+ if (sih->chiprev >= 1) {
SI_MSG(("Applying 43224B0+ WARs\n"));
si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE,
CCTRL_43224B0_12MA_LED_DRIVE);
}
}
- if (CHIPID(sih->chip) == BCM4313_CHIP_ID) {
+ if (sih->chip == BCM4313_CHIP_ID) {
/* enable 12 mA drive strenth for 4313 and set chipControl register bit 1 */
SI_MSG(("Applying 4313 WARs\n"));
si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE,
CCTRL_4313_12MA_LED_DRIVE);
}
- if (CHIPID(sih->chip) == BCM4331_CHIP_ID) {
+ if (sih->chip == BCM4331_CHIP_ID) {
/* Enable Ext PA lines depending on chip package option */
si_chipcontrl_epa4331(sih, true);
}
return sii;
exit:
- if (BUSTYPE(sih->bustype) == PCI_BUS) {
+ if (sih->bustype == PCI_BUS) {
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
@@ -708,17 +707,17 @@ void si_detach(si_t *sih)
if (sii == NULL)
return;
- if (BUSTYPE(sih->bustype) == SI_BUS)
+ if (sih->bustype == SI_BUS)
for (idx = 0; idx < SI_MAXCORES; idx++)
if (sii->regs[idx]) {
- REG_UNMAP(sii->regs[idx]);
+ iounmap(sii->regs[idx]);
sii->regs[idx] = NULL;
}
#ifndef BRCM_FULLMAC
nvram_exit((void *)si_local); /* free up nvram buffers */
- if (BUSTYPE(sih->bustype) == PCI_BUS) {
+ if (sih->bustype == PCI_BUS) {
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
@@ -730,7 +729,7 @@ void si_detach(si_t *sih)
kfree(sii);
}
-void *si_osh(si_t *sih)
+struct osl_info *si_osh(si_t *sih)
{
si_info_t *sii;
@@ -766,7 +765,7 @@ void si_deregister_intr_callback(si_t *sih)
uint si_flag(si_t *sih)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_flag(sih);
else {
ASSERT(0);
@@ -776,7 +775,7 @@ uint si_flag(si_t *sih)
void si_setint(si_t *sih, int siflag)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
ai_setint(sih, siflag);
else
ASSERT(0);
@@ -808,7 +807,7 @@ bool si_backplane64(si_t *sih)
#ifndef BCMSDIO
uint si_corerev(si_t *sih)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_corerev(sih);
else {
ASSERT(0);
@@ -851,7 +850,7 @@ void *si_setcore(si_t *sih, uint coreid, uint coreunit)
if (!GOODIDX(idx))
return NULL;
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_setcoreidx(sih, idx);
else {
#ifdef BCMSDIO
@@ -866,7 +865,7 @@ void *si_setcore(si_t *sih, uint coreid, uint coreunit)
#ifndef BCMSDIO
void *si_setcoreidx(si_t *sih, uint coreidx)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_setcoreidx(sih, coreidx);
else {
ASSERT(0);
@@ -918,7 +917,7 @@ void si_restore_core(si_t *sih, uint coreid, uint intr_val)
u32 si_core_cflags(si_t *sih, u32 mask, u32 val)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_core_cflags(sih, mask, val);
else {
ASSERT(0);
@@ -928,7 +927,7 @@ u32 si_core_cflags(si_t *sih, u32 mask, u32 val)
u32 si_core_sflags(si_t *sih, u32 mask, u32 val)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_core_sflags(sih, mask, val);
else {
ASSERT(0);
@@ -938,7 +937,7 @@ u32 si_core_sflags(si_t *sih, u32 mask, u32 val)
bool si_iscoreup(si_t *sih)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_iscoreup(sih);
else {
#ifdef BCMSDIO
@@ -953,7 +952,7 @@ bool si_iscoreup(si_t *sih)
void si_write_wrapperreg(si_t *sih, u32 offset, u32 val)
{
/* only for 4319, no requirement for SOCI_SB */
- if (CHIPTYPE(sih->socitype) == SOCI_AI) {
+ if (sih->socitype == SOCI_AI) {
ai_write_wrap_reg(sih, offset, val);
}
}
@@ -961,7 +960,7 @@ void si_write_wrapperreg(si_t *sih, u32 offset, u32 val)
uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
return ai_corereg(sih, coreidx, regoff, mask, val);
else {
#ifdef BCMSDIO
@@ -976,7 +975,7 @@ uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
void si_core_disable(si_t *sih, u32 bits)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
ai_core_disable(sih, bits);
#ifdef BCMSDIO
else
@@ -986,7 +985,7 @@ void si_core_disable(si_t *sih, u32 bits)
void si_core_reset(si_t *sih, u32 bits, u32 resetbits)
{
- if (CHIPTYPE(sih->socitype) == SOCI_AI)
+ if (sih->socitype == SOCI_AI)
ai_core_reset(sih, bits, resetbits);
#ifdef BCMSDIO
else
@@ -1043,8 +1042,8 @@ void si_watchdog(si_t *sih, uint ticks)
if (PMUCTL_ENAB(sih)) {
- if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
- (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
+ if ((sih->chip == BCM4319_CHIP_ID) &&
+ (sih->chiprev == 0) && (ticks != 0)) {
si_corereg(sih, SI_CC_IDX,
offsetof(chipcregs_t, clk_ctl_st), ~0, 0x2);
si_setcore(sih, USB20D_CORE_ID, 0);
@@ -1085,16 +1084,18 @@ void si_watchdog(si_t *sih, uint ticks)
static uint si_slowclk_src(si_info_t *sii)
{
chipcregs_t *cc;
+ u32 val;
ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
if (sii->pub.ccrev < 6) {
- if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
- (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(u32))
- & PCI_CFG_GPIO_SCS))
- return SCC_SS_PCI;
- else
- return SCC_SS_XTAL;
+ if (sii->pub.bustype == PCI_BUS) {
+ pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT,
+ &val);
+ if (val & PCI_CFG_GPIO_SCS)
+ return SCC_SS_PCI;
+ }
+ return SCC_SS_XTAL;
} else if (sii->pub.ccrev < 10) {
cc = (chipcregs_t *) si_setcoreidx(&sii->pub, sii->curidx);
return R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK;
@@ -1264,7 +1265,7 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on)
sii = SI_INFO(sih);
- switch (BUSTYPE(sih->bustype)) {
+ switch (sih->bustype) {
#ifdef BCMSDIO
case SDIO_BUS:
@@ -1276,12 +1277,9 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on)
if (PCIE(sii))
return -1;
- in = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_IN, sizeof(u32));
- out =
- OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(u32));
- outen =
- OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUTEN,
- sizeof(u32));
+ pci_read_config_dword(sii->osh->pdev, PCI_GPIO_IN, &in);
+ pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, &out);
+ pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUTEN, &outen);
/*
* Avoid glitching the clock if GPRS is already using it.
@@ -1302,18 +1300,18 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on)
out |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
- sizeof(u32), out);
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN,
- sizeof(u32), outen);
+ pci_write_config_dword(sii->osh->pdev,
+ PCI_GPIO_OUT, out);
+ pci_write_config_dword(sii->osh->pdev,
+ PCI_GPIO_OUTEN, outen);
udelay(XTAL_ON_DELAY);
}
/* turn pll on */
if (what & PLL) {
out &= ~PCI_CFG_GPIO_PLL;
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
- sizeof(u32), out);
+ pci_write_config_dword(sii->osh->pdev,
+ PCI_GPIO_OUT, out);
mdelay(2);
}
} else {
@@ -1321,10 +1319,10 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on)
out &= ~PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
- sizeof(u32), out);
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN,
- sizeof(u32), outen);
+ pci_write_config_dword(sii->osh->pdev,
+ PCI_GPIO_OUT, out);
+ pci_write_config_dword(sii->osh->pdev,
+ PCI_GPIO_OUTEN, outen);
}
default:
@@ -1378,7 +1376,7 @@ static bool _si_clkctl_cc(si_info_t *sii, uint mode)
INTR_OFF(sii, intr_val);
origidx = sii->curidx;
- if ((BUSTYPE(sii->pub.bustype) == SI_BUS) &&
+ if ((sii->pub.bustype == SI_BUS) &&
si_setcore(&sii->pub, MIPS33_CORE_ID, 0) &&
(si_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10))
goto done;
@@ -1460,7 +1458,7 @@ int si_devpath(si_t *sih, char *path, int size)
if (!path || size <= 0)
return -1;
- switch (BUSTYPE(sih->bustype)) {
+ switch (sih->bustype) {
case SI_BUS:
case JTAG_BUS:
slen = snprintf(path, (size_t) size, "sb/%u/", si_coreidx(sih));
@@ -1550,7 +1548,7 @@ static __used bool si_ispcie(si_info_t *sii)
{
u8 cap_ptr;
- if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
+ if (sii->pub.bustype != PCI_BUS)
return false;
cap_ptr =
@@ -1617,7 +1615,7 @@ void si_pci_up(si_t *sih)
sii = SI_INFO(sih);
/* if not pci bus, we're done */
- if (BUSTYPE(sih->bustype) != PCI_BUS)
+ if (sih->bustype != PCI_BUS)
return;
if (PCI_FORCEHT(sii))
@@ -1646,7 +1644,7 @@ void si_pci_down(si_t *sih)
sii = SI_INFO(sih);
/* if not pci bus, we're done */
- if (BUSTYPE(sih->bustype) != PCI_BUS)
+ if (sih->bustype != PCI_BUS)
return;
/* release FORCEHT since chip is going to "down" state */
@@ -1669,7 +1667,7 @@ void si_pci_setup(si_t *sih, uint coremask)
sii = SI_INFO(sih);
- if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
+ if (sii->pub.bustype != PCI_BUS)
return;
ASSERT(PCI(sii) || PCIE(sii));
@@ -1692,9 +1690,9 @@ void si_pci_setup(si_t *sih, uint coremask)
*/
if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) {
/* pci config write to set this core bit in PCIIntMask */
- w = OSL_PCI_READ_CONFIG(sii->osh, PCI_INT_MASK, sizeof(u32));
+ pci_read_config_dword(sii->osh->pdev, PCI_INT_MASK, &w);
w |= (coremask << PCI_SBIM_SHIFT);
- OSL_PCI_WRITE_CONFIG(sii->osh, PCI_INT_MASK, sizeof(u32), w);
+ pci_write_config_dword(sii->osh->pdev, PCI_INT_MASK, w);
} else {
/* set sbintvec bit for our flag number */
si_setint(sih, siflag);
@@ -1731,7 +1729,7 @@ int si_pci_fixcfg(si_t *sih)
si_info_t *sii = SI_INFO(sih);
- ASSERT(BUSTYPE(sii->pub.bustype) == PCI_BUS);
+ ASSERT(sii->pub.bustype == PCI_BUS);
/* Fixup PI in SROM shadow area to enable the correct PCI core access */
/* save the current index */
@@ -1777,7 +1775,7 @@ u32 si_gpiocontrol(si_t *sih, u32 mask, u32 val, u8 priority)
* ignore reservation if it's high priority (e.g., test apps)
*/
if ((priority != GPIO_HI_PRIORITY) &&
- (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
+ (sih->bustype == SI_BUS) && (val || mask)) {
mask = priority ? (si_gpioreservation & mask) :
((si_gpioreservation | mask) & ~(si_gpioreservation));
val &= mask;
@@ -1929,10 +1927,10 @@ bool si_deviceremoved(si_t *sih)
sii = SI_INFO(sih);
- switch (BUSTYPE(sih->bustype)) {
+ switch (sih->bustype) {
case PCI_BUS:
ASSERT(sii->osh != NULL);
- w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(u32));
+ pci_read_config_dword(sii->osh->pdev, PCI_CFG_VID, &w);
if ((w & 0xFFFF) != VENDOR_BROADCOM)
return true;
break;
@@ -1959,7 +1957,7 @@ bool si_is_sprom_available(si_t *sih)
return sromctrl & SRC_PRESENT;
}
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
return (sih->chipst & CST4329_SPROM_SEL) != 0;
case BCM4319_CHIP_ID:
@@ -1979,7 +1977,7 @@ bool si_is_sprom_available(si_t *sih)
bool si_is_otp_disabled(si_t *sih)
{
- switch (CHIPID(sih->chip)) {
+ switch (sih->chip) {
case BCM4329_CHIP_ID:
return (sih->chipst & CST4329_SPROM_OTP_SEL_MASK) ==
CST4329_OTP_PWRDN;
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 4a29ed737e3f..dca861ee0466 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -117,8 +117,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
for (driv = comedi_drivers; driv; driv = driv->next) {
if (!try_module_get(driv->module)) {
- printk
- (KERN_INFO "comedi: failed to increment module count, skipping\n");
+ printk(KERN_INFO "comedi: failed to increment module count, skipping\n");
continue;
}
if (driv->num_names) {
@@ -205,9 +204,8 @@ int comedi_driver_unregister(struct comedi_driver *driver)
mutex_lock(&dev->mutex);
if (dev->attached && dev->driver == driver) {
if (dev->use_count)
- printk
- (KERN_WARNING "BUG! detaching device with use_count=%d\n",
- dev->use_count);
+ printk(KERN_WARNING "BUG! detaching device with use_count=%d\n",
+ dev->use_count);
comedi_device_detach(dev);
}
mutex_unlock(&dev->mutex);
@@ -442,7 +440,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned i;
for (i = 0; i < async->n_buf_pages; ++i) {
if (async->buf_page_list[i].virt_addr) {
- clear_bit(PG_reserved, &(virt_to_page(async->buf_page_list[i].virt_addr)->flags));
+ clear_bit(PG_reserved,
+ &(virt_to_page(async->buf_page_list[i].
+ virt_addr)->flags));
if (s->async_dma_dir != DMA_NONE) {
dma_free_coherent(dev->hw_dev,
PAGE_SIZE,
@@ -470,10 +470,8 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
struct page **pages = NULL;
async->buf_page_list =
- vmalloc(sizeof(struct comedi_buf_page) * n_pages);
+ vzalloc(sizeof(struct comedi_buf_page) * n_pages);
if (async->buf_page_list) {
- memset(async->buf_page_list, 0,
- sizeof(struct comedi_buf_page) * n_pages);
pages = vmalloc(sizeof(struct page *) * n_pages);
}
if (pages) {
@@ -496,8 +494,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
break;
set_bit(PG_reserved,
- &(virt_to_page(async->buf_page_list[i].virt_addr)->flags));
- pages[i] = virt_to_page(async->buf_page_list[i].virt_addr);
+ &(virt_to_page(async->buf_page_list[i].
+ virt_addr)->flags));
+ pages[i] = virt_to_page(async->buf_page_list[i].
+ virt_addr);
}
}
if (i == n_pages) {
@@ -514,7 +514,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
NULL) {
break;
}
- clear_bit(PG_reserved, &(virt_to_page(async->buf_page_list[i].virt_addr)->flags));
+ clear_bit(PG_reserved,
+ &(virt_to_page(async->
+ buf_page_list[i].
+ virt_addr)->flags));
if (s->async_dma_dir != DMA_NONE) {
dma_free_coherent(dev->hw_dev,
PAGE_SIZE,
@@ -646,8 +649,7 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes)
{
if ((int)(async->buf_write_count + nbytes -
async->buf_write_alloc_count) > 0) {
- printk
- (KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n");
+ printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n");
nbytes = async->buf_write_alloc_count - async->buf_write_count;
}
async->buf_write_count += nbytes;
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
index 7361d508bf37..0e6affd95962 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
@@ -1008,7 +1008,7 @@ int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev,
b_ExternGate = (unsigned char) data[3];
b_CycleMode = (unsigned char) data[4];
b_InterruptEnable = (unsigned char) data[5];
- i_ReturnValue = insn->n;;
+ i_ReturnValue = insn->n;
devpriv->tsk_Current = current; /* Save the current process task structure */
/**************************/
/* Test the module number */
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index 93d7c056741d..76f2483871a7 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -2710,10 +2710,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else {
outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
}
- /* Enable the interrupt for the controler */
+ /* Enable the interrupt for the controller */
dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
- printk("\nEnable the interrupt for the controler");
+ printk("\nEnable the interrupt for the controller");
}
printk("\nRead Eeprom");
i_EepromReadMainHeader(io_addr[0], this_board->pc_EepromChip,
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
index 912bc0fc54bf..a76ed2553fb4 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
@@ -225,7 +225,7 @@ int i_APCI1710_Reset(struct comedi_device *dev)
devpriv->s_BoardInfos.b_BoardVersion = 1;
- /* Enable the interrupt for the controler */
+ /* Enable the interrupt for the controller */
dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38);
outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38);
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
index 2a8a6c730920..62f421a06f05 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
@@ -2850,7 +2850,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
i_Logic = 0;
i_CounterLogic = 0;
i_InterruptMask = 0;
- i_InputChannel = 0;;
+ i_InputChannel = 0;
i_TimerCounter1Enabled = 0;
i_TimerCounter2Enabled = 0;
i_WatchdogCounter3Enabled = 0;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
index 12fcc35ecc52..8a584a014b0b 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
@@ -335,7 +335,7 @@ int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subde
return -EINVAL;
} /* if else data[3]==1) */
} /* if else data[3]==0) */
- return (insn->n);;
+ return (insn->n);
}
/*
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
index b943a06e70dc..a93e2349ad3a 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
@@ -3011,7 +3011,7 @@ int i_APCI3200_Reset(struct comedi_device *dev)
outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
- /* Enable the interrupt for the controler */
+ /* Enable the interrupt for the controller */
dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
outl(0, devpriv->i_IobaseAddon); /* Resets the output */
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index 356a1891e2e7..acaceb01629a 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -339,7 +339,7 @@ int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subde
int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;;
+ unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;
ul_Channel_no = CR_CHAN(insn->chanspec);
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 5d064577b2f1..7edeb1103dc8 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -971,7 +971,7 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (thisboard->ao_chans > 0) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = thisboard->ao_chans;;
+ s->n_chan = thisboard->ao_chans;
s->maxdata = (1 << thisboard->ao_bits) - 1;
s->range_table = &pci230_ao_range;
s->insn_write = &pci230_ao_winsn;
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 0345b4caba73..bb93685d8b93 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -169,7 +169,7 @@ static int das16cs_attach(struct comedi_device *dev,
if (!link)
return -EIO;
- dev->iobase = link->resource[0]->start;;
+ dev->iobase = link->resource[0]->start;
printk("I/O base=0x%04lx ", dev->iobase);
printk("fingerprint:\n");
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index cfcbd9b8f393..d8aefb23d6b9 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -370,7 +370,7 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
memset(devs_opened, 0, sizeof(devs_opened));
- devpriv->name[0] = 0;;
+ devpriv->name[0] = 0;
/* Loop through all comedi devices specified on the command-line,
building our device list */
for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 0560a7451512..06059850dae2 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -262,7 +262,7 @@ struct dt9812_usb_cmd {
#define DT9812_NUM_SLOTS 16
-static DECLARE_MUTEX(dt9812_mutex);
+static DEFINE_SEMAPHORE(dt9812_mutex);
static const struct usb_device_id dt9812_table[] = {
{USB_DEVICE(0x0867, 0x9812)},
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 39a6a850d63c..e4711ef54719 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -19,7 +19,7 @@
* - 16 bit
*
* only ONE PCI-20341 module possible
- * only ONE PCI-20006 module possible
+ * only ONE PCI-20006 module possible
* no extern trigger implemented
*
* NOT WORKING (but soon) only 4 on-board differential channels supported
@@ -83,11 +83,11 @@ options for PCI-20341M:
#include "../comedidev.h"
#define PCI20000_ID 0x1d
-#define PCI20341_ID 0x77
-#define PCI20006_ID 0xe3
+#define PCI20341_ID 0x77
+#define PCI20006_ID 0xe3
#define PCI20xxx_EMPTY_ID 0xff
-#define PCI20000_OFFSET 0x100
+#define PCI20000_OFFSET 0x100
#define PCI20000_MODULES 3
#define PCI20000_DIO_0 0x80
@@ -246,7 +246,7 @@ static int pci20xxx_attach(struct comedi_device *dev,
pci20006_init(dev, s, it->options[2 * i + 2],
it->options[2 * i + 3]);
printk(KERN_INFO "comedi%d: "
- "ii_pci20kc PCI-20006 module in slot %d \n",
+ "ii_pci20kc PCI-20006 module in slot %d\n",
dev->minor, i + 1);
break;
case PCI20341_ID:
@@ -255,7 +255,7 @@ static int pci20xxx_attach(struct comedi_device *dev,
pci20341_init(dev, s, it->options[2 * i + 2],
it->options[2 * i + 3]);
printk(KERN_INFO "comedi%d: "
- "ii_pci20kc PCI-20341 module in slot %d \n",
+ "ii_pci20kc PCI-20341 module in slot %d\n",
dev->minor, i + 1);
break;
default:
@@ -376,9 +376,20 @@ static int pci20341_insn_read(struct comedi_device *dev,
static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 };
static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 };
-static const struct comedi_lrange range_bipolar0_5 = { 1, {BIP_RANGE(0.5)} };
-static const struct comedi_lrange range_bipolar0_05 = { 1, {BIP_RANGE(0.05)} };
-static const struct comedi_lrange range_bipolar0_025 = { 1, {BIP_RANGE(0.025)} };
+static const struct comedi_lrange range_bipolar0_5 = {
+ 1,
+ {BIP_RANGE(0.5)}
+};
+
+static const struct comedi_lrange range_bipolar0_05 = {
+ 1,
+ {BIP_RANGE(0.05)}
+};
+
+static const struct comedi_lrange range_bipolar0_025 = {
+ 1,
+ {BIP_RANGE(0.025)}
+};
static const struct comedi_lrange *const pci20341_ranges[] = {
&range_bipolar5,
@@ -408,12 +419,18 @@ static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
s->maxdata = 0xffff;
s->range_table = pci20341_ranges[opt0];
- option = sdp->pci20341.timebase | PCI20341_REPMODE; /* depends on gain, trigger, repetition mode */
-
- writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG); /* initialize Module */
- writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS); /* set Pacer */
- writeb(option, sdp->iobase + PCI20341_OPT_REG); /* option register */
- writeb(sdp->pci20341.settling_time, sdp->iobase + PCI20341_SET_TIME_REG); /* settling time counter */
+ /* depends on gain, trigger, repetition mode */
+ option = sdp->pci20341.timebase | PCI20341_REPMODE;
+
+ /* initialize Module */
+ writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG);
+ /* set Pacer */
+ writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS);
+ /* option register */
+ writeb(option, sdp->iobase + PCI20341_OPT_REG);
+ /* settling time counter */
+ writeb(sdp->pci20341.settling_time,
+ sdp->iobase + PCI20341_SET_TIME_REG);
/* trigger not implemented */
return 0;
}
@@ -429,11 +446,15 @@ static int pci20341_insn_read(struct comedi_device *dev,
unsigned int clb; /* channel list byte */
unsigned int boarddata;
- writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG); /* write number of input channels */
+ /* write number of input channels */
+ writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG);
clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3)
| CR_CHAN(insn->chanspec);
writeb(clb, sdp->iobase + PCI20341_CHAN_LIST);
- writeb(0x00, sdp->iobase + PCI20341_CC_RESET); /* reset settling time counter and trigger delay counter */
+
+ /* reset settling time counter and trigger delay counter */
+ writeb(0x00, sdp->iobase + PCI20341_CC_RESET);
+
writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET);
/* generate Pacer */
@@ -444,9 +465,12 @@ static int pci20341_insn_read(struct comedi_device *dev,
* the whole interrupt stuff
*/
j = 0;
- readb(sdp->iobase + PCI20341_SOFT_PACER); /* generate Pacer */
+ /* generate Pacer */
+ readb(sdp->iobase + PCI20341_SOFT_PACER);
+
eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
- while ((eoc < 0x80) && j < 100) { /* poll Interrupt Flag */
+ /* poll Interrupt Flag */
+ while ((eoc < 0x80) && j < 100) {
j++;
eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
}
@@ -460,7 +484,9 @@ static int pci20341_insn_read(struct comedi_device *dev,
lo = readb(sdp->iobase + PCI20341_LDATA);
hi = readb(sdp->iobase + PCI20341_LDATA + 1);
boarddata = lo + 0x100 * hi;
- data[i] = (short)((boarddata + 0x8000) & 0xffff); /* board-data -> comedi-data */
+
+ /* board-data -> comedi-data */
+ data[i] = (short)((boarddata + 0x8000) & 0xffff);
}
return i;
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 8b383ee959b2..5c6c72744167 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -54,6 +54,7 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
#define PCI_VENDOR_ID_JR3 0x1762
#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111
+#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111
#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112
#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
@@ -73,6 +74,8 @@ static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
{
PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
+ PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL,
@@ -807,6 +810,10 @@ static int jr3_pci_attach(struct comedi_device *dev,
devpriv->n_channels = 1;
}
break;
+ case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW:{
+ devpriv->n_channels = 1;
+ }
+ break;
case PCI_DEVICE_ID_JR3_2_CHANNEL:{
devpriv->n_channels = 2;
}
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index b0d44b547a69..a9611587460a 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -62,11 +62,10 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
unsigned input_select_bits = 0;
if (enable) {
- if (read_not_write) {
+ if (read_not_write)
input_select_bits |= Gi_Read_Acknowledges_Irq;
- } else {
+ else
input_select_bits |= Gi_Write_Acknowledges_Irq;
- }
}
ni_tio_set_bits(counter,
NITIO_Gi_Input_Select_Reg(counter->counter_index),
@@ -84,9 +83,8 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
gi_dma_config_bits |= Gi_DMA_Enable_Bit;
gi_dma_config_bits |= Gi_DMA_Int_Bit;
}
- if (read_not_write == 0) {
+ if (read_not_write == 0)
gi_dma_config_bits |= Gi_DMA_Write_Bit;
- }
ni_tio_set_bits(counter,
NITIO_Gi_DMA_Config_Reg(counter->
counter_index),
@@ -174,7 +172,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async)
static int ni_tio_output_cmd(struct ni_gpct *counter,
struct comedi_async *async)
{
- printk("ni_tio: output commands not yet implemented.\n");
+ printk(KERN_ERR "ni_tio: output commands not yet implemented.\n");
return -ENOTSUPP;
counter->mite_chan->dir = COMEDI_OUTPUT;
@@ -198,9 +196,8 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async)
set_gate_source = 1;
gate_source = cmd->convert_arg;
}
- if (set_gate_source) {
+ if (set_gate_source)
retval = ni_tio_set_gate_src(counter, 0, gate_source);
- }
if (cmd->flags & TRIG_WAKE_EOS) {
ni_tio_set_bits(counter,
NITIO_Gi_Interrupt_Enable_Reg(counter->
@@ -221,22 +218,21 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async)
spin_lock_irqsave(&counter->lock, flags);
if (counter->mite_chan == NULL) {
- printk
- ("ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n");
+ printk(KERN_ERR "ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n");
retval = -EIO;
} else {
retval = ni_tio_cmd_setup(counter, async);
if (retval == 0) {
- if (cmd->flags & CMDF_WRITE) {
+ if (cmd->flags & CMDF_WRITE)
retval = ni_tio_output_cmd(counter, async);
- } else {
+ else
retval = ni_tio_input_cmd(counter, async);
- }
}
}
spin_unlock_irqrestore(&counter->lock, flags);
return retval;
}
+EXPORT_SYMBOL_GPL(ni_tio_cmd);
int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd)
{
@@ -342,6 +338,7 @@ int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd)
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
int ni_tio_cancel(struct ni_gpct *counter)
{
@@ -349,9 +346,8 @@ int ni_tio_cancel(struct ni_gpct *counter)
ni_tio_arm(counter, 0, 0);
spin_lock_irqsave(&counter->lock, flags);
- if (counter->mite_chan) {
+ if (counter->mite_chan)
mite_dma_disarm(counter->mite_chan);
- }
spin_unlock_irqrestore(&counter->lock, flags);
ni_tio_configure_dma(counter, 0, 0);
@@ -361,10 +357,11 @@ int ni_tio_cancel(struct ni_gpct *counter)
0x0);
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_cancel);
- /* During buffered input counter operation for e-series, the gate interrupt is acked
- automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits
- in the input select register. */
+ /* During buffered input counter operation for e-series, the gate
+ interrupt is acked automatically by the dma controller, due to the
+ Gi_Read/Write_Acknowledges_IRQ bits in the input select register. */
static int should_ack_gate(struct ni_gpct *counter)
{
unsigned long flags;
@@ -372,7 +369,10 @@ static int should_ack_gate(struct ni_gpct *counter)
switch (counter->counter_dev->variant) {
case ni_gpct_variant_m_series:
- case ni_gpct_variant_660x: /* not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual) */
+ /* not sure if 660x really supports gate
+ interrupts (the bits are not listed
+ in register-level manual) */
+ case ni_gpct_variant_660x:
return 1;
break;
case ni_gpct_variant_e_series:
@@ -416,7 +416,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) {
ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index);
if (gate_error) {
- /*660x don't support automatic acknowledgement of gate interrupt via dma read/write
+ /*660x don't support automatic acknowledgement
+ of gate interrupt via dma read/write
and report bogus gate errors */
if (counter->counter_dev->variant !=
ni_gpct_variant_660x) {
@@ -429,9 +430,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
if (tc_error)
*tc_error = 1;
}
- if (gi_status & Gi_TC_Bit) {
+ if (gi_status & Gi_TC_Bit)
ack |= Gi_TC_Interrupt_Ack_Bit;
- }
if (gi_status & Gi_Gate_Interrupt_Bit) {
if (should_ack_gate(counter))
ack |= Gi_Gate_Interrupt_Ack_Bit;
@@ -452,13 +452,14 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
NITIO_Gxx_Joint_Status2_Reg
(counter->counter_index)) &
Gi_Permanent_Stale_Bit(counter->counter_index)) {
- printk("%s: Gi_Permanent_Stale_Data detected.\n",
- __FUNCTION__);
+ printk(KERN_INFO "%s: Gi_Permanent_Stale_Data detected.\n",
+ __func__);
if (perm_stale_data)
*perm_stale_data = 1;
}
}
}
+EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm);
void ni_tio_handle_interrupt(struct ni_gpct *counter,
struct comedi_subdevice *s)
@@ -472,20 +473,19 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter,
ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error,
&perm_stale_data, NULL);
if (gate_error) {
- printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__);
+ printk(KERN_NOTICE "%s: Gi_Gate_Error detected.\n", __func__);
s->async->events |= COMEDI_CB_OVERFLOW;
}
- if (perm_stale_data) {
+ if (perm_stale_data)
s->async->events |= COMEDI_CB_ERROR;
- }
switch (counter->counter_dev->variant) {
case ni_gpct_variant_m_series:
case ni_gpct_variant_660x:
if (read_register(counter,
- NITIO_Gi_DMA_Status_Reg
- (counter->counter_index)) & Gi_DRQ_Error_Bit)
- {
- printk("%s: Gi_DRQ_Error detected.\n", __FUNCTION__);
+ NITIO_Gi_DMA_Status_Reg
+ (counter->counter_index)) & Gi_DRQ_Error_Bit) {
+ printk(KERN_NOTICE "%s: Gi_DRQ_Error detected.\n",
+ __func__);
s->async->events |= COMEDI_CB_OVERFLOW;
}
break;
@@ -506,6 +506,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter,
mite_sync_input_dma(counter->mite_chan, s->async);
spin_unlock_irqrestore(&counter->lock, flags);
}
+EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
void ni_tio_set_mite_channel(struct ni_gpct *counter,
struct mite_channel *mite_chan)
@@ -516,6 +517,7 @@ void ni_tio_set_mite_channel(struct ni_gpct *counter,
counter->mite_chan = mite_chan;
spin_unlock_irqrestore(&counter->lock, flags);
}
+EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
static int __init ni_tiocmd_init_module(void)
{
@@ -529,10 +531,3 @@ static void __exit ni_tiocmd_cleanup_module(void)
}
module_exit(ni_tiocmd_cleanup_module);
-
-EXPORT_SYMBOL_GPL(ni_tio_cmd);
-EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
-EXPORT_SYMBOL_GPL(ni_tio_cancel);
-EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
-EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
-EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm);
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 60ebfc3c75fd..aa8aeeee043f 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -753,7 +753,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
struct pci_dev *pcidev;
int ret;
- resource_size_t physLas0; /* configuation */
+ resource_size_t physLas0; /* configuration */
resource_size_t physLas1; /* data area */
resource_size_t physLcfg; /* PLX9080 */
#ifdef USE_DMA
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 3607aaee4af6..2b34daedc3d7 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -114,7 +114,7 @@ static const int s526_ports[] = {
};
struct counter_mode_register_t {
-#if defined (__LITTLE_ENDIAN_BITFIELD)
+#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned short coutSource:1;
unsigned short coutPolarity:1;
unsigned short autoLoadResetRcap:3;
@@ -207,7 +207,9 @@ static const struct s526_board s526_boards[] = {
/* this structure is for data unique to this hardware driver. If
several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+ feel free to suggest moving the variable to the struct comedi_device
+ struct.
+*/
struct s526_private {
int data;
@@ -304,7 +306,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* int subdev_channel = 0; */
union cmReg cmReg;
- printk("comedi%d: s526: ", dev->minor);
+ printk(KERN_INFO "comedi%d: s526: ", dev->minor);
iobase = it->options[0];
if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
@@ -317,7 +319,8 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/*** make it a little quieter, exw, 8/29/06
for (i = 0; i < S526_NUM_PORTS; i++) {
- printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
+ printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
+ inw(ADDR_REG(s526_ports[i])));
}
***/
@@ -402,7 +405,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_UNUSED;
}
- printk("attached\n");
+ printk(KERN_INFO "attached\n");
return 1;
@@ -411,7 +414,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* One-shot (software trigger) */
cmReg.reg.coutSource = 0; /* out RCAP */
cmReg.reg.coutPolarity = 1; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 1; /* Auto load 0:disabled, 1:enabled */
+ cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
cmReg.reg.ctEnableCtrl = 2; /* Hardware */
cmReg.reg.clockSource = 2; /* Internal */
@@ -426,10 +429,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */
-
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Reset RCAP (fires one-shot) */
+ outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
#else
@@ -447,11 +452,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
cmReg.reg.reserved = 0;
n = 0;
- printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M,
- n));
+ printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
+ cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
udelay(1000);
- printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
/* Load the pre-load register high word */
/* value = (short) (0x55); */
@@ -466,20 +472,23 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Reset the counter if it is software preload */
if (cmReg.reg.autoLoadResetRcap == 0) {
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); /* Reset the counter */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); /* Load the counter from PR0 */
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
}
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
udelay(1000);
- printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
#endif
- printk("Current registres:\n");
+ printk(KERN_INFO "Current registres:\n");
for (i = 0; i < S526_NUM_PORTS; i++) {
- printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]),
- inw(ADDR_REG(s526_ports[i])));
+ printk(KERN_INFO "0x%02lx: 0x%04x\n",
+ ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
}
return 1;
}
@@ -494,7 +503,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
*/
static int s526_detach(struct comedi_device *dev)
{
- printk("comedi%d: s526: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor);
if (dev->iobase > 0)
release_region(dev->iobase, S526_IOSIZE);
@@ -513,7 +522,7 @@ static int s526_gpct_rinsn(struct comedi_device *dev,
/* Check if (n > 0) */
if (insn->n <= 0) {
- printk("s526: INSN_READ: n should be > 0\n");
+ printk(KERN_ERR "s526: INSN_READ: n should be > 0\n");
return -EINVAL;
}
/* Read the low word first */
@@ -522,7 +531,8 @@ static int s526_gpct_rinsn(struct comedi_device *dev,
datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
data[i] = (int)(datahigh & 0x00FF);
data[i] = (data[i] << 16) | (datalow & 0xFFFF);
-/* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow); */
+ /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n",
+ counter_channel, data[i], datahigh, datalow); */
}
return i;
}
@@ -536,7 +546,8 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
short value;
union cmReg cmReg;
-/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); */
+ /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n",
+ subdev_channel); */
for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
devpriv->s526_gpct_config[subdev_channel].data[i] =
@@ -554,7 +565,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
data[2]: Pre-load Register Value
data[3]: Conter Control Register
*/
- printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
+ printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
devpriv->s526_gpct_config[subdev_channel].app =
PositionMeasurement;
@@ -563,7 +574,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
/* One-shot (software trigger) */
cmReg.reg.coutSource = 0; /* out RCAP */
cmReg.reg.coutPolarity = 1; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
+ cmReg.reg.autoLoadResetRcap = 0;/* Auto load disabled */
cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
cmReg.reg.ctEnableCtrl = 2; /* Hardware */
cmReg.reg.clockSource = 2; /* Internal */
@@ -578,10 +589,13 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */
+ /* Reset RCAP (fires one-shot) */
+ outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
#endif
@@ -594,30 +608,34 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
/* Reset the counter if it is software preload */
if (cmReg.reg.autoLoadResetRcap == 0) {
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */
-/* outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); Load the counter from PR0 */
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0
+ * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ */
}
#else
- cmReg.reg.countDirCtrl = 0; /* 0 quadrature, 1 software control */
+ /* 0 quadrature, 1 software control */
+ cmReg.reg.countDirCtrl = 0;
/* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */
- if (insn->data[1] == GPCT_X2) {
+ if (insn->data[1] == GPCT_X2)
cmReg.reg.clockSource = 1;
- } else if (insn->data[1] == GPCT_X4) {
+ else if (insn->data[1] == GPCT_X4)
cmReg.reg.clockSource = 2;
- } else {
+ else
cmReg.reg.clockSource = 0;
- }
/* When to take into account the indexpulse: */
- if (insn->data[2] == GPCT_IndexPhaseLowLow) {
+ /*if (insn->data[2] == GPCT_IndexPhaseLowLow) {
} else if (insn->data[2] == GPCT_IndexPhaseLowHigh) {
} else if (insn->data[2] == GPCT_IndexPhaseHighLow) {
} else if (insn->data[2] == GPCT_IndexPhaseHighHigh) {
- }
+ }*/
/* Take into account the index pulse? */
if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
- cmReg.reg.autoLoadResetRcap = 4; /* Auto load with INDEX^ */
+ /* Auto load with INDEX^ */
+ cmReg.reg.autoLoadResetRcap = 4;
/* Set Counter Mode Register */
cmReg.value = (short)(insn->data[1] & 0xFFFF);
@@ -638,8 +656,10 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
}
/* Reset the counter if it is software preload */
if (cmReg.reg.autoLoadResetRcap == 0) {
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
}
#endif
break;
@@ -652,7 +672,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
data[3]: Pre-load Register 1 Value
data[4]: Conter Control Register
*/
- printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n");
+ printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n");
devpriv->s526_gpct_config[subdev_channel].app =
SinglePulseGeneration;
@@ -697,7 +717,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
data[3]: Pre-load Register 1 Value
data[4]: Conter Control Register
*/
- printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n");
+ printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n");
devpriv->s526_gpct_config[subdev_channel].app =
PulseTrainGeneration;
@@ -735,7 +755,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
break;
default:
- printk("s526: unsupported GPCT_insn_config\n");
+ printk(KERN_ERR "s526: unsupported GPCT_insn_config\n");
return -EINVAL;
break;
}
@@ -751,20 +771,21 @@ static int s526_gpct_winsn(struct comedi_device *dev,
short value;
union cmReg cmReg;
- printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
+ printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n",
+ subdev_channel);
cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
- printk("s526: Counter Mode Register: %x\n", cmReg.value);
+ printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value);
/* Check what Application of Counter this channel is configured for */
switch (devpriv->s526_gpct_config[subdev_channel].app) {
case PositionMeasurement:
- printk("S526: INSN_WRITE: PM\n");
+ printk(KERN_INFO "S526: INSN_WRITE: PM\n");
outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
subdev_channel));
outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
break;
case SinglePulseGeneration:
- printk("S526: INSN_WRITE: SPG\n");
+ printk(KERN_INFO "S526: INSN_WRITE: SPG\n");
outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
subdev_channel));
outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
@@ -777,14 +798,14 @@ static int s526_gpct_winsn(struct comedi_device *dev,
The above periods must be expressed as a multiple of the
pulse frequency on the selected source
*/
- printk("S526: INSN_WRITE: PTG\n");
+ printk(KERN_INFO "S526: INSN_WRITE: PTG\n");
if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
(devpriv->s526_gpct_config[subdev_channel]).data[0] =
insn->data[0];
(devpriv->s526_gpct_config[subdev_channel]).data[1] =
insn->data[1];
} else {
- printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
+ printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
insn->data[0], insn->data[1]);
return -EINVAL;
}
@@ -873,7 +894,7 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
if (i == TIMEOUT) {
/* printk() should be used instead of printk()
* whenever the code can be called from real-time. */
- printk("s526: ADC(0x%04x) timeout\n",
+ printk(KERN_ERR "s526: ADC(0x%04x) timeout\n",
inw(ADDR_REG(REG_ISR)));
return -ETIMEDOUT;
}
@@ -906,11 +927,14 @@ static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
* very useful, but that's how the interface is defined. */
for (i = 0; i < insn->n; i++) {
/* a typical programming sequence */
-/* outw(data[i], dev->iobase + REG_ADD); write the data to preload register */
- outw(data[i], ADDR_REG(REG_ADD)); /* write the data to preload register */
+ /* write the data to preload register
+ * outw(data[i], dev->iobase + REG_ADD);
+ */
+ /* write the data to preload register */
+ outw(data[i], ADDR_REG(REG_ADD));
devpriv->ao_readback[chan] = data[i];
/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */
- outw(val + 1, ADDR_REG(REG_DAC)); /* starts the D/A conversion. */
+ outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/
}
/* return the number of samples read/written */
@@ -954,7 +978,7 @@ static int s526_dio_insn_bits(struct comedi_device *dev,
/* on return, data[1] contains the value of the digital
* input and output lines. */
- data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */
+ data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */
/* or we could just return the software copy of the output values if
* it was a purely digital output subdevice */
/* data[1]=s->state & 0xFF; */
@@ -969,7 +993,7 @@ static int s526_dio_insn_config(struct comedi_device *dev,
int chan = CR_CHAN(insn->chanspec);
int group, mask;
- printk("S526 DIO insn_config\n");
+ printk(KERN_INFO "S526 DIO insn_config\n");
/* The input or output configuration of each digital line is
* configured by a special insn_config instruction. chanspec
@@ -980,11 +1004,12 @@ static int s526_dio_insn_config(struct comedi_device *dev,
mask = 0xF << (group << 2);
switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
- s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode
+ /* bit 10/11 set the group 1/2's mode */
+ s->state |= 1 << (group + 10);
s->io_bits |= mask;
break;
case INSN_CONFIG_DIO_INPUT:
- s->state &= ~(1 << (group + 10));// 1 is output, 0 is input.
+ s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */
s->io_bits &= ~mask;
break;
case INSN_CONFIG_DIO_QUERY:
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 6131e2dd0591..696ee045e25f 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -315,7 +315,7 @@ struct usbduxsub {
*/
static struct usbduxsub usbduxsub[NUMUSBDUX];
-static DECLARE_MUTEX(start_stop_sem);
+static DEFINE_SEMAPHORE(start_stop_sem);
/*
* Stops the data acquision
@@ -2295,8 +2295,8 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp)
usbduxsub_tmp->inBuffer = NULL;
kfree(usbduxsub_tmp->insnBuffer);
usbduxsub_tmp->insnBuffer = NULL;
- kfree(usbduxsub_tmp->inBuffer);
- usbduxsub_tmp->inBuffer = NULL;
+ kfree(usbduxsub_tmp->outBuffer);
+ usbduxsub_tmp->outBuffer = NULL;
kfree(usbduxsub_tmp->dac_commands);
usbduxsub_tmp->dac_commands = NULL;
kfree(usbduxsub_tmp->dux_commands);
@@ -2367,7 +2367,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
dev_dbg(dev, "comedi_: usbdux: "
"usbduxsub[%d] is ready to connect to comedi.\n", index);
- init_MUTEX(&(usbduxsub[index].sem));
+ sema_init(&(usbduxsub[index].sem), 1);
/* save a pointer to the usb device */
usbduxsub[index].usbdev = udev;
@@ -2398,7 +2398,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
if (!usbduxsub[index].dux_commands) {
dev_err(dev, "comedi_: usbdux: "
- "error alloc space for dac commands\n");
+ "error alloc space for dux commands\n");
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 0a164a9a66c3..5b15e6df54e6 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -199,7 +199,7 @@ struct usbduxfastsub_s {
*/
static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
-static DECLARE_MUTEX(start_stop_sem);
+static DEFINE_SEMAPHORE(start_stop_sem);
/*
* bulk transfers to usbduxfast
@@ -1504,7 +1504,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
"connect to comedi.\n", index);
#endif
- init_MUTEX(&(usbduxfastsub[index].sem));
+ sema_init(&(usbduxfastsub[index].sem), 1);
/* save a pointer to the usb device */
usbduxfastsub[index].usbdev = udev;
diff --git a/drivers/staging/cpia/Kconfig b/drivers/staging/cpia/Kconfig
deleted file mode 100644
index 205d247ad373..000000000000
--- a/drivers/staging/cpia/Kconfig
+++ /dev/null
@@ -1,39 +0,0 @@
-config VIDEO_CPIA
- tristate "CPiA Video For Linux (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca cpia1 module
- instead. Note that you need atleast version 0.6.4 of libv4l for
- the cpia1 gspca module.
-
- This is the video4linux driver for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Labs Video
- Blaster Webcam II. If you have one of these cameras, say Y here
- and select parallel port and/or USB lowlevel support below,
- otherwise say N. This will not work with the Creative Webcam III.
-
- Please read <file:Documentation/video4linux/README.cpia> for more
- information.
-
- This driver is also available as a module (cpia).
-
-config VIDEO_CPIA_PP
- tristate "CPiA Parallel Port Lowlevel Support"
- depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
- help
- This is the lowlevel parallel port support for cameras based on
- Vision's CPiA (Colour Processor Interface ASIC), such as the
- Creative Webcam II. If you have the parallel port version of one
- of these cameras, say Y here, otherwise say N. It is also available
- as a module (cpia_pp).
-
-config VIDEO_CPIA_USB
- tristate "CPiA USB Lowlevel Support"
- depends on VIDEO_CPIA && USB
- help
- This is the lowlevel USB support for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Webcam II.
- If you have the USB version of one of these cameras, say Y here,
- otherwise say N. This will not work with the Creative Webcam III.
- It is also available as a module (cpia_usb).
diff --git a/drivers/staging/cpia/Makefile b/drivers/staging/cpia/Makefile
deleted file mode 100644
index 89e52f10d739..000000000000
--- a/drivers/staging/cpia/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_VIDEO_CPIA) += cpia.o
-obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
-obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
-
-EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/cpia/TODO b/drivers/staging/cpia/TODO
deleted file mode 100644
index ccb1c0775eec..000000000000
--- a/drivers/staging/cpia/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-This is an obsolete driver for some cpia-based webcams that use the parallel port.
-We couldn't find anyone with this hardware in order to port it to use V4L2.
-
-Also, parallel-port webcams are obsolete nowadays.
-
-If nobody take care on it, the driver will be removed for 2.6.38.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/cpia/cpia.c b/drivers/staging/cpia/cpia.c
deleted file mode 100644
index 933ae4c8cb9a..000000000000
--- a/drivers/staging/cpia/cpia.c
+++ /dev/null
@@ -1,4032 +0,0 @@
-/*
- * cpia CPiA driver
- *
- * Supports CPiA based Video Camera's.
- *
- * (C) Copyright 1999-2000 Peter Pregler
- * (C) Copyright 1999-2000 Scott J. Bertin
- * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
- * (C) Copyright 2000 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <linux/mutex.h>
-
-#include "cpia.h"
-
-static int video_nr = -1;
-
-#ifdef MODULE
-module_param(video_nr, int, 0);
-MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
-MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("video");
-#endif
-
-static unsigned short colorspace_conv;
-module_param(colorspace_conv, ushort, 0444);
-MODULE_PARM_DESC(colorspace_conv,
- " Colorspace conversion:"
- "\n 0 = disable, 1 = enable"
- "\n Default value is 0"
- );
-
-#define ABOUT "V4L-Driver for Vision CPiA based cameras"
-
-#define CPIA_MODULE_CPIA (0<<5)
-#define CPIA_MODULE_SYSTEM (1<<5)
-#define CPIA_MODULE_VP_CTRL (5<<5)
-#define CPIA_MODULE_CAPTURE (6<<5)
-#define CPIA_MODULE_DEBUG (7<<5)
-
-#define INPUT (DATA_IN << 8)
-#define OUTPUT (DATA_OUT << 8)
-
-#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
-#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
-#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
-#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
-#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
-#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
-#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
-#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
-
-#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
-#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
-#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
-#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
-#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
-#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
-#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
-#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
-#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
-#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
-#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
-#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
-#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
-
-#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
-#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
-#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
-#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
-#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
-#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
-#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
-#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
-#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
-#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
-#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
-#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
-#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
-#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
-#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
-#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
-#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
-
-#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
-#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
-#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
-#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
-#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
-#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
-#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
-#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
-#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
-#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
-#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
-#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
-#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
-#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
-#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
-
-#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
-#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
-#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
-#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
-#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
-#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
-#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
-#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
-
-enum {
- FRAME_READY, /* Ready to grab into */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
-};
-
-#define COMMAND_NONE 0x0000
-#define COMMAND_SETCOMPRESSION 0x0001
-#define COMMAND_SETCOMPRESSIONTARGET 0x0002
-#define COMMAND_SETCOLOURPARAMS 0x0004
-#define COMMAND_SETFORMAT 0x0008
-#define COMMAND_PAUSE 0x0010
-#define COMMAND_RESUME 0x0020
-#define COMMAND_SETYUVTHRESH 0x0040
-#define COMMAND_SETECPTIMING 0x0080
-#define COMMAND_SETCOMPRESSIONPARAMS 0x0100
-#define COMMAND_SETEXPOSURE 0x0200
-#define COMMAND_SETCOLOURBALANCE 0x0400
-#define COMMAND_SETSENSORFPS 0x0800
-#define COMMAND_SETAPCOR 0x1000
-#define COMMAND_SETFLICKERCTRL 0x2000
-#define COMMAND_SETVLOFFSET 0x4000
-#define COMMAND_SETLIGHTS 0x8000
-
-#define ROUND_UP_EXP_FOR_FLICKER 15
-
-/* Constants for automatic frame rate adjustment */
-#define MAX_EXP 302
-#define MAX_EXP_102 255
-#define LOW_EXP 140
-#define VERY_LOW_EXP 70
-#define TC 94
-#define EXP_ACC_DARK 50
-#define EXP_ACC_LIGHT 90
-#define HIGH_COMP_102 160
-#define MAX_COMP 239
-#define DARK_TIME 3
-#define LIGHT_TIME 3
-
-/* Maximum number of 10ms loops to wait for the stream to become ready */
-#define READY_TIMEOUT 100
-
-/* Developer's Guide Table 5 p 3-34
- * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
-static u8 flicker_jumps[2][2][4] =
-{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
- { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
-};
-
-/* forward declaration of local function */
-static void reset_camera_struct(struct cam_data *cam);
-static int find_over_exposure(int brightness);
-static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
- int on);
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/**********************************************************************
- *
- * /proc interface
- *
- **********************************************************************/
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *cpia_proc_root=NULL;
-
-static int cpia_proc_show(struct seq_file *m, void *v)
-{
- struct cam_data *cam = m->private;
- int tmp;
- char tmpstr[29];
-
- seq_printf(m, "read-only\n-----------------------\n");
- seq_printf(m, "V4L Driver version: %d.%d.%d\n",
- CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
- seq_printf(m, "CPIA Version: %d.%02d (%d.%d)\n",
- cam->params.version.firmwareVersion,
- cam->params.version.firmwareRevision,
- cam->params.version.vcVersion,
- cam->params.version.vcRevision);
- seq_printf(m, "CPIA PnP-ID: %04x:%04x:%04x\n",
- cam->params.pnpID.vendor, cam->params.pnpID.product,
- cam->params.pnpID.deviceRevision);
- seq_printf(m, "VP-Version: %d.%d %04x\n",
- cam->params.vpVersion.vpVersion,
- cam->params.vpVersion.vpRevision,
- cam->params.vpVersion.cameraHeadID);
-
- seq_printf(m, "system_state: %#04x\n",
- cam->params.status.systemState);
- seq_printf(m, "grab_state: %#04x\n",
- cam->params.status.grabState);
- seq_printf(m, "stream_state: %#04x\n",
- cam->params.status.streamState);
- seq_printf(m, "fatal_error: %#04x\n",
- cam->params.status.fatalError);
- seq_printf(m, "cmd_error: %#04x\n",
- cam->params.status.cmdError);
- seq_printf(m, "debug_flags: %#04x\n",
- cam->params.status.debugFlags);
- seq_printf(m, "vp_status: %#04x\n",
- cam->params.status.vpStatus);
- seq_printf(m, "error_code: %#04x\n",
- cam->params.status.errorCode);
- /* QX3 specific entries */
- if (cam->params.qx3.qx3_detected) {
- seq_printf(m, "button: %4d\n",
- cam->params.qx3.button);
- seq_printf(m, "cradled: %4d\n",
- cam->params.qx3.cradled);
- }
- seq_printf(m, "video_size: %s\n",
- cam->params.format.videoSize == VIDEOSIZE_CIF ?
- "CIF " : "QCIF");
- seq_printf(m, "roi: (%3d, %3d) to (%3d, %3d)\n",
- cam->params.roi.colStart*8,
- cam->params.roi.rowStart*4,
- cam->params.roi.colEnd*8,
- cam->params.roi.rowEnd*4);
- seq_printf(m, "actual_fps: %3d\n", cam->fps);
- seq_printf(m, "transfer_rate: %4dkB/s\n",
- cam->transfer_rate);
-
- seq_printf(m, "\nread-write\n");
- seq_printf(m, "----------------------- current min"
- " max default comment\n");
- seq_printf(m, "brightness: %8d %8d %8d %8d\n",
- cam->params.colourParams.brightness, 0, 100, 50);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits contrast to 80 */
- tmp = 80;
- else
- tmp = 96;
-
- seq_printf(m, "contrast: %8d %8d %8d %8d"
- " steps of 8\n",
- cam->params.colourParams.contrast, 0, tmp, 48);
- seq_printf(m, "saturation: %8d %8d %8d %8d\n",
- cam->params.colourParams.saturation, 0, 100, 50);
- tmp = (25000+5000*cam->params.sensorFps.baserate)/
- (1<<cam->params.sensorFps.divisor);
- seq_printf(m, "sensor_fps: %4d.%03d %8d %8d %8d\n",
- tmp/1000, tmp%1000, 3, 30, 15);
- seq_printf(m, "stream_start_line: %8d %8d %8d %8d\n",
- 2*cam->params.streamStartLine, 0,
- cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
- cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
- seq_printf(m, "sub_sample: %8s %8s %8s %8s\n",
- cam->params.format.subSample == SUBSAMPLE_420 ?
- "420" : "422", "420", "422", "422");
- seq_printf(m, "yuv_order: %8s %8s %8s %8s\n",
- cam->params.format.yuvOrder == YUVORDER_YUYV ?
- "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
- seq_printf(m, "ecp_timing: %8s %8s %8s %8s\n",
- cam->params.ecpTiming ? "slow" : "normal", "slow",
- "normal", "normal");
-
- if (cam->params.colourBalance.balanceMode == 2) {
- sprintf(tmpstr, "auto");
- } else {
- sprintf(tmpstr, "manual");
- }
- seq_printf(m, "color_balance_mode: %8s %8s %8s"
- " %8s\n", tmpstr, "manual", "auto", "auto");
- seq_printf(m, "red_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.redGain, 0, 212, 32);
- seq_printf(m, "green_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.greenGain, 0, 212, 6);
- seq_printf(m, "blue_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.blueGain, 0, 212, 92);
-
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits gain to 2 */
- sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
- else
- sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
-
- if (cam->params.exposure.gainMode == 0)
- seq_printf(m, "max_gain: unknown %28s"
- " powers of 2\n", tmpstr);
- else
- seq_printf(m, "max_gain: %8d %28s"
- " 1,2,4 or 8 \n",
- 1<<(cam->params.exposure.gainMode-1), tmpstr);
-
- switch(cam->params.exposure.expMode) {
- case 1:
- case 3:
- sprintf(tmpstr, "manual");
- break;
- case 2:
- sprintf(tmpstr, "auto");
- break;
- default:
- sprintf(tmpstr, "unknown");
- break;
- }
- seq_printf(m, "exposure_mode: %8s %8s %8s"
- " %8s\n", tmpstr, "manual", "auto", "auto");
- seq_printf(m, "centre_weight: %8s %8s %8s %8s\n",
- (2-cam->params.exposure.centreWeight) ? "on" : "off",
- "off", "on", "on");
- seq_printf(m, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
- 1<<cam->params.exposure.gain, 1, 1);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits fineExp/2 to 127 */
- tmp = 254;
- else
- tmp = 510;
-
- seq_printf(m, "fine_exp: %8d %8d %8d %8d\n",
- cam->params.exposure.fineExp*2, 0, tmp, 0);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits coarseExpHi to 0 */
- tmp = MAX_EXP_102;
- else
- tmp = MAX_EXP;
-
- seq_printf(m, "coarse_exp: %8d %8d %8d"
- " %8d\n", cam->params.exposure.coarseExpLo+
- 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
- seq_printf(m, "red_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
- seq_printf(m, "green1_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.green1Comp, COMP_GREEN1, 255,
- COMP_GREEN1);
- seq_printf(m, "green2_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.green2Comp, COMP_GREEN2, 255,
- COMP_GREEN2);
- seq_printf(m, "blue_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
-
- seq_printf(m, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain1, 0, 0xff, 0x1c);
- seq_printf(m, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain2, 0, 0xff, 0x1a);
- seq_printf(m, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain4, 0, 0xff, 0x2d);
- seq_printf(m, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain8, 0, 0xff, 0x2a);
- seq_printf(m, "vl_offset_gain1: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain1, 0, 255, 24);
- seq_printf(m, "vl_offset_gain2: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain2, 0, 255, 28);
- seq_printf(m, "vl_offset_gain4: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain4, 0, 255, 30);
- seq_printf(m, "vl_offset_gain8: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain8, 0, 255, 30);
- seq_printf(m, "flicker_control: %8s %8s %8s %8s\n",
- cam->params.flickerControl.flickerMode ? "on" : "off",
- "off", "on", "off");
- seq_printf(m, "mains_frequency: %8d %8d %8d %8d"
- " only 50/60\n",
- cam->mainsFreq ? 60 : 50, 50, 60, 50);
- if(cam->params.flickerControl.allowableOverExposure < 0)
- seq_printf(m, "allowable_overexposure: %4dauto auto %8d auto\n",
- -cam->params.flickerControl.allowableOverExposure,
- 255);
- else
- seq_printf(m, "allowable_overexposure: %8d auto %8d auto\n",
- cam->params.flickerControl.allowableOverExposure,
- 255);
- seq_printf(m, "compression_mode: ");
- switch(cam->params.compression.mode) {
- case CPIA_COMPRESSION_NONE:
- seq_printf(m, "%8s", "none");
- break;
- case CPIA_COMPRESSION_AUTO:
- seq_printf(m, "%8s", "auto");
- break;
- case CPIA_COMPRESSION_MANUAL:
- seq_printf(m, "%8s", "manual");
- break;
- default:
- seq_printf(m, "%8s", "unknown");
- break;
- }
- seq_printf(m, " none,auto,manual auto\n");
- seq_printf(m, "decimation_enable: %8s %8s %8s %8s\n",
- cam->params.compression.decimation ==
- DECIMATION_ENAB ? "on":"off", "off", "on",
- "off");
- seq_printf(m, "compression_target: %9s %9s %9s %9s\n",
- cam->params.compressionTarget.frTargeting ==
- CPIA_COMPRESSION_TARGET_FRAMERATE ?
- "framerate":"quality",
- "framerate", "quality", "quality");
- seq_printf(m, "target_framerate: %8d %8d %8d %8d\n",
- cam->params.compressionTarget.targetFR, 1, 30, 15);
- seq_printf(m, "target_quality: %8d %8d %8d %8d\n",
- cam->params.compressionTarget.targetQ, 1, 64, 5);
- seq_printf(m, "y_threshold: %8d %8d %8d %8d\n",
- cam->params.yuvThreshold.yThreshold, 0, 31, 6);
- seq_printf(m, "uv_threshold: %8d %8d %8d %8d\n",
- cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
- seq_printf(m, "hysteresis: %8d %8d %8d %8d\n",
- cam->params.compressionParams.hysteresis, 0, 255, 3);
- seq_printf(m, "threshold_max: %8d %8d %8d %8d\n",
- cam->params.compressionParams.threshMax, 0, 255, 11);
- seq_printf(m, "small_step: %8d %8d %8d %8d\n",
- cam->params.compressionParams.smallStep, 0, 255, 1);
- seq_printf(m, "large_step: %8d %8d %8d %8d\n",
- cam->params.compressionParams.largeStep, 0, 255, 3);
- seq_printf(m, "decimation_hysteresis: %8d %8d %8d %8d\n",
- cam->params.compressionParams.decimationHysteresis,
- 0, 255, 2);
- seq_printf(m, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
- cam->params.compressionParams.frDiffStepThresh,
- 0, 255, 5);
- seq_printf(m, "q_diff_step_thresh: %8d %8d %8d %8d\n",
- cam->params.compressionParams.qDiffStepThresh,
- 0, 255, 3);
- seq_printf(m, "decimation_thresh_mod: %8d %8d %8d %8d\n",
- cam->params.compressionParams.decimationThreshMod,
- 0, 255, 2);
- /* QX3 specific entries */
- if (cam->params.qx3.qx3_detected) {
- seq_printf(m, "toplight: %8s %8s %8s %8s\n",
- cam->params.qx3.toplight ? "on" : "off",
- "off", "on", "off");
- seq_printf(m, "bottomlight: %8s %8s %8s %8s\n",
- cam->params.qx3.bottomlight ? "on" : "off",
- "off", "on", "off");
- }
-
- return 0;
-}
-
-static int cpia_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cpia_proc_show, PDE(inode)->data);
-}
-
-static int match(char *checkstr, char **buffer, size_t *count,
- int *find_colon, int *err)
-{
- int ret, colon_found = 1;
- int len = strlen(checkstr);
- ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
- if (ret) {
- *buffer += len;
- *count -= len;
- if (*find_colon) {
- colon_found = 0;
- while (*count && (**buffer == ' ' || **buffer == '\t' ||
- (!colon_found && **buffer == ':'))) {
- if (**buffer == ':')
- colon_found = 1;
- --*count;
- ++*buffer;
- }
- if (!*count || !colon_found)
- *err = -EINVAL;
- *find_colon = 0;
- }
- }
- return ret;
-}
-
-static unsigned long int value(char **buffer, size_t *count, int *err)
-{
- char *p;
- unsigned long int ret;
- ret = simple_strtoul(*buffer, &p, 0);
- if (p == *buffer)
- *err = -EINVAL;
- else {
- *count -= p - *buffer;
- *buffer = p;
- }
- return ret;
-}
-
-static ssize_t cpia_proc_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data;
- struct cam_params new_params;
- char *page, *buffer;
- int retval, find_colon;
- int size = count;
- unsigned long val = 0;
- u32 command_flags = 0;
- u8 new_mains;
-
- /*
- * This code to copy from buf to page is shamelessly copied
- * from the comx driver
- */
- if (count > PAGE_SIZE) {
- printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE);
- return -ENOSPC;
- }
-
- if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
-
- if(copy_from_user(page, buf, count))
- {
- retval = -EFAULT;
- goto out;
- }
-
- if (page[count-1] == '\n')
- page[count-1] = '\0';
- else if (count < PAGE_SIZE)
- page[count] = '\0';
- else if (page[count]) {
- retval = -EINVAL;
- goto out;
- }
-
- buffer = page;
-
- if (mutex_lock_interruptible(&cam->param_lock))
- return -ERESTARTSYS;
-
- /*
- * Skip over leading whitespace
- */
- while (count && isspace(*buffer)) {
- --count;
- ++buffer;
- }
-
- memcpy(&new_params, &cam->params, sizeof(struct cam_params));
- new_mains = cam->mainsFreq;
-
-#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
-#define VALUE (value(&buffer,&count, &retval))
-#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
- new_params.version.firmwareRevision == (y))
-
- retval = 0;
- while (count && !retval) {
- find_colon = 1;
- if (MATCH("brightness")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100)
- new_params.colourParams.brightness = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- if(new_params.flickerControl.allowableOverExposure < 0)
- new_params.flickerControl.allowableOverExposure =
- -find_over_exposure(new_params.colourParams.brightness);
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
-
- } else if (MATCH("contrast")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100) {
- /* contrast is in steps of 8, so round*/
- val = ((val + 3) / 8) * 8;
- /* 1-02 firmware limits contrast to 80*/
- if (FIRMWARE_VERSION(1,2) && val > 80)
- val = 80;
-
- new_params.colourParams.contrast = val;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- } else if (MATCH("saturation")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100)
- new_params.colourParams.saturation = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- } else if (MATCH("sensor_fps")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- /* find values so that sensorFPS is minimized,
- * but >= val */
- if (val > 30)
- retval = -EINVAL;
- else if (val > 25) {
- new_params.sensorFps.divisor = 0;
- new_params.sensorFps.baserate = 1;
- } else if (val > 15) {
- new_params.sensorFps.divisor = 0;
- new_params.sensorFps.baserate = 0;
- } else if (val > 12) {
- new_params.sensorFps.divisor = 1;
- new_params.sensorFps.baserate = 1;
- } else if (val > 7) {
- new_params.sensorFps.divisor = 1;
- new_params.sensorFps.baserate = 0;
- } else if (val > 6) {
- new_params.sensorFps.divisor = 2;
- new_params.sensorFps.baserate = 1;
- } else if (val > 3) {
- new_params.sensorFps.divisor = 2;
- new_params.sensorFps.baserate = 0;
- } else {
- new_params.sensorFps.divisor = 3;
- /* Either base rate would work here */
- new_params.sensorFps.baserate = 1;
- }
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- }
- command_flags |= COMMAND_SETSENSORFPS;
- cam->exposure_status = EXPOSURE_NORMAL;
- } else if (MATCH("stream_start_line")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- int max_line = 288;
-
- if (new_params.format.videoSize == VIDEOSIZE_QCIF)
- max_line = 144;
- if (val <= max_line)
- new_params.streamStartLine = val/2;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("sub_sample")) {
- if (!retval && MATCH("420"))
- new_params.format.subSample = SUBSAMPLE_420;
- else if (!retval && MATCH("422"))
- new_params.format.subSample = SUBSAMPLE_422;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFORMAT;
- } else if (MATCH("yuv_order")) {
- if (!retval && MATCH("YUYV"))
- new_params.format.yuvOrder = YUVORDER_YUYV;
- else if (!retval && MATCH("UYVY"))
- new_params.format.yuvOrder = YUVORDER_UYVY;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFORMAT;
- } else if (MATCH("ecp_timing")) {
- if (!retval && MATCH("normal"))
- new_params.ecpTiming = 0;
- else if (!retval && MATCH("slow"))
- new_params.ecpTiming = 1;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETECPTIMING;
- } else if (MATCH("color_balance_mode")) {
- if (!retval && MATCH("manual"))
- new_params.colourBalance.balanceMode = 3;
- else if (!retval && MATCH("auto"))
- new_params.colourBalance.balanceMode = 2;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("red_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.redGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("green_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.greenGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("blue_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.blueGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("max_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- /* 1-02 firmware limits gain to 2 */
- if (FIRMWARE_VERSION(1,2) && val > 2)
- val = 2;
- switch(val) {
- case 1:
- new_params.exposure.gainMode = 1;
- break;
- case 2:
- new_params.exposure.gainMode = 2;
- break;
- case 4:
- new_params.exposure.gainMode = 3;
- break;
- case 8:
- new_params.exposure.gainMode = 4;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- }
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("exposure_mode")) {
- if (!retval && MATCH("auto"))
- new_params.exposure.expMode = 2;
- else if (!retval && MATCH("manual")) {
- if (new_params.exposure.expMode == 2)
- new_params.exposure.expMode = 3;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- } else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("centre_weight")) {
- if (!retval && MATCH("on"))
- new_params.exposure.centreWeight = 1;
- else if (!retval && MATCH("off"))
- new_params.exposure.centreWeight = 2;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- switch(val) {
- case 1:
- new_params.exposure.gain = 0;
- break;
- case 2:
- new_params.exposure.gain = 1;
- break;
- case 4:
- new_params.exposure.gain = 2;
- break;
- case 8:
- new_params.exposure.gain = 3;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- new_params.exposure.expMode = 1;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETEXPOSURE;
- if (new_params.exposure.gain >
- new_params.exposure.gainMode-1)
- retval = -EINVAL;
- }
- } else if (MATCH("fine_exp")) {
- if (!retval)
- val = VALUE/2;
-
- if (!retval) {
- if (val < 256) {
- /* 1-02 firmware limits fineExp/2 to 127*/
- if (FIRMWARE_VERSION(1,2) && val > 127)
- val = 127;
- new_params.exposure.fineExp = val;
- new_params.exposure.expMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("coarse_exp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= MAX_EXP) {
- if (FIRMWARE_VERSION(1,2) &&
- val > MAX_EXP_102)
- val = MAX_EXP_102;
- new_params.exposure.coarseExpLo =
- val & 0xff;
- new_params.exposure.coarseExpHi =
- val >> 8;
- new_params.exposure.expMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("red_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_RED && val <= 255) {
- new_params.exposure.redComp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("green1_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_GREEN1 && val <= 255) {
- new_params.exposure.green1Comp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("green2_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_GREEN2 && val <= 255) {
- new_params.exposure.green2Comp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("blue_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_BLUE && val <= 255) {
- new_params.exposure.blueComp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain1")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain1 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain2")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain2 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain4")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain4 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain8")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain8 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("vl_offset_gain1")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain1 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain2")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain2 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain4")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain4 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain8")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain8 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("flicker_control")) {
- if (!retval && MATCH("on")) {
- set_flicker(&new_params, &command_flags, 1);
- } else if (!retval && MATCH("off")) {
- set_flicker(&new_params, &command_flags, 0);
- } else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else if (MATCH("mains_frequency")) {
- if (!retval && MATCH("50")) {
- new_mains = 0;
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else if (!retval && MATCH("60")) {
- new_mains = 1;
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- } else if (MATCH("allowable_overexposure")) {
- if (!retval && MATCH("auto")) {
- new_params.flickerControl.allowableOverExposure =
- -find_over_exposure(new_params.colourParams.brightness);
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff) {
- new_params.flickerControl.
- allowableOverExposure = val;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- }
- } else if (MATCH("compression_mode")) {
- if (!retval && MATCH("none"))
- new_params.compression.mode =
- CPIA_COMPRESSION_NONE;
- else if (!retval && MATCH("auto"))
- new_params.compression.mode =
- CPIA_COMPRESSION_AUTO;
- else if (!retval && MATCH("manual"))
- new_params.compression.mode =
- CPIA_COMPRESSION_MANUAL;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSION;
- } else if (MATCH("decimation_enable")) {
- if (!retval && MATCH("off"))
- new_params.compression.decimation = 0;
- else if (!retval && MATCH("on"))
- new_params.compression.decimation = 1;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSION;
- } else if (MATCH("compression_target")) {
- if (!retval && MATCH("quality"))
- new_params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_QUALITY;
- else if (!retval && MATCH("framerate"))
- new_params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_FRAMERATE;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("target_framerate")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if(val > 0 && val <= 30)
- new_params.compressionTarget.targetFR = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("target_quality")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if(val > 0 && val <= 64)
- new_params.compressionTarget.targetQ = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("y_threshold")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val < 32)
- new_params.yuvThreshold.yThreshold = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETYUVTHRESH;
- } else if (MATCH("uv_threshold")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val < 32)
- new_params.yuvThreshold.uvThreshold = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETYUVTHRESH;
- } else if (MATCH("hysteresis")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.hysteresis = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("threshold_max")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.threshMax = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("small_step")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.smallStep = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("large_step")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.largeStep = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("decimation_hysteresis")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.decimationHysteresis = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("fr_diff_step_thresh")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.frDiffStepThresh = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("q_diff_step_thresh")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.qDiffStepThresh = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("decimation_thresh_mod")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.decimationThreshMod = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("toplight")) {
- if (!retval && MATCH("on"))
- new_params.qx3.toplight = 1;
- else if (!retval && MATCH("off"))
- new_params.qx3.toplight = 0;
- else
- retval = -EINVAL;
- command_flags |= COMMAND_SETLIGHTS;
- } else if (MATCH("bottomlight")) {
- if (!retval && MATCH("on"))
- new_params.qx3.bottomlight = 1;
- else if (!retval && MATCH("off"))
- new_params.qx3.bottomlight = 0;
- else
- retval = -EINVAL;
- command_flags |= COMMAND_SETLIGHTS;
- } else {
- DBG("No match found\n");
- retval = -EINVAL;
- }
-
- if (!retval) {
- while (count && isspace(*buffer) && *buffer != '\n') {
- --count;
- ++buffer;
- }
- if (count) {
- if (*buffer == '\0' && count != 1)
- retval = -EINVAL;
- else if (*buffer != '\n' && *buffer != ';' &&
- *buffer != '\0')
- retval = -EINVAL;
- else {
- --count;
- ++buffer;
- }
- }
- }
- }
-#undef MATCH
-#undef VALUE
-#undef FIRMWARE_VERSION
- if (!retval) {
- if (command_flags & COMMAND_SETCOLOURPARAMS) {
- /* Adjust cam->vp to reflect these changes */
- cam->vp.brightness =
- new_params.colourParams.brightness*65535/100;
- cam->vp.contrast =
- new_params.colourParams.contrast*65535/100;
- cam->vp.colour =
- new_params.colourParams.saturation*65535/100;
- }
- if((command_flags & COMMAND_SETEXPOSURE) &&
- new_params.exposure.expMode == 2)
- cam->exposure_status = EXPOSURE_NORMAL;
-
- memcpy(&cam->params, &new_params, sizeof(struct cam_params));
- cam->mainsFreq = new_mains;
- cam->cmd_queue |= command_flags;
- retval = size;
- } else
- DBG("error: %d\n", retval);
-
- mutex_unlock(&cam->param_lock);
-
-out:
- free_page((unsigned long)page);
- return retval;
-}
-
-static const struct file_operations cpia_proc_fops = {
- .owner = THIS_MODULE,
- .open = cpia_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = cpia_proc_write,
-};
-
-static void create_proc_cpia_cam(struct cam_data *cam)
-{
- struct proc_dir_entry *ent;
-
- if (!cpia_proc_root || !cam)
- return;
-
- ent = proc_create_data(video_device_node_name(&cam->vdev),
- S_IRUGO|S_IWUSR, cpia_proc_root,
- &cpia_proc_fops, cam);
- if (!ent)
- return;
-
- /*
- size of the proc entry is 3736 bytes for the standard webcam;
- the extra features of the QX3 microscope add 189 bytes.
- (we have not yet probed the camera to see which type it is).
- */
- ent->size = 3736 + 189;
- cam->proc_entry = ent;
-}
-
-static void destroy_proc_cpia_cam(struct cam_data *cam)
-{
- if (!cam || !cam->proc_entry)
- return;
-
- remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root);
- cam->proc_entry = NULL;
-}
-
-static void proc_cpia_create(void)
-{
- cpia_proc_root = proc_mkdir("cpia", NULL);
-
- if (!cpia_proc_root)
- LOG("Unable to initialise /proc/cpia\n");
-}
-
-static void __exit proc_cpia_destroy(void)
-{
- remove_proc_entry("cpia", NULL);
-}
-#endif /* CONFIG_PROC_FS */
-
-/* ----------------------- debug functions ---------------------- */
-
-#define printstatus(cam) \
- DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
- cam->params.status.systemState, cam->params.status.grabState, \
- cam->params.status.streamState, cam->params.status.fatalError, \
- cam->params.status.cmdError, cam->params.status.debugFlags, \
- cam->params.status.vpStatus, cam->params.status.errorCode);
-
-/* ----------------------- v4l helpers -------------------------- */
-
-/* supported frame palettes and depths */
-static inline int valid_mode(u16 palette, u16 depth)
-{
- if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
- (palette == VIDEO_PALETTE_YUYV && depth == 16))
- return 1;
-
- if (colorspace_conv)
- return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
- (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
- (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
- (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
- (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
- (palette == VIDEO_PALETTE_UYVY && depth == 16);
-
- return 0;
-}
-
-static int match_videosize( int width, int height )
-{
- /* return the best match, where 'best' is as always
- * the largest that is not bigger than what is requested. */
- if (width>=352 && height>=288)
- return VIDEOSIZE_352_288; /* CIF */
-
- if (width>=320 && height>=240)
- return VIDEOSIZE_320_240; /* SIF */
-
- if (width>=288 && height>=216)
- return VIDEOSIZE_288_216;
-
- if (width>=256 && height>=192)
- return VIDEOSIZE_256_192;
-
- if (width>=224 && height>=168)
- return VIDEOSIZE_224_168;
-
- if (width>=192 && height>=144)
- return VIDEOSIZE_192_144;
-
- if (width>=176 && height>=144)
- return VIDEOSIZE_176_144; /* QCIF */
-
- if (width>=160 && height>=120)
- return VIDEOSIZE_160_120; /* QSIF */
-
- if (width>=128 && height>=96)
- return VIDEOSIZE_128_96;
-
- if (width>=88 && height>=72)
- return VIDEOSIZE_88_72;
-
- if (width>=64 && height>=48)
- return VIDEOSIZE_64_48;
-
- if (width>=48 && height>=48)
- return VIDEOSIZE_48_48;
-
- return -1;
-}
-
-/* these are the capture sizes we support */
-static void set_vw_size(struct cam_data *cam)
-{
- /* the col/row/start/end values are the result of simple math */
- /* study the SetROI-command in cpia developers guide p 2-22 */
- /* streamStartLine is set to the recommended value in the cpia */
- /* developers guide p 3-37 */
- switch(cam->video_size) {
- case VIDEOSIZE_CIF:
- cam->vw.width = 352;
- cam->vw.height = 288;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=0;
- cam->params.roi.rowStart=0;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_SIF:
- cam->vw.width = 320;
- cam->vw.height = 240;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=2;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_288_216:
- cam->vw.width = 288;
- cam->vw.height = 216;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=4;
- cam->params.roi.rowStart=9;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_256_192:
- cam->vw.width = 256;
- cam->vw.height = 192;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=6;
- cam->params.roi.rowStart=12;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_224_168:
- cam->vw.width = 224;
- cam->vw.height = 168;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=8;
- cam->params.roi.rowStart=15;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_192_144:
- cam->vw.width = 192;
- cam->vw.height = 144;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=10;
- cam->params.roi.rowStart=18;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_QCIF:
- cam->vw.width = 176;
- cam->vw.height = 144;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=0;
- cam->params.roi.rowStart=0;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_QSIF:
- cam->vw.width = 160;
- cam->vw.height = 120;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=1;
- cam->params.roi.rowStart=3;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_128_96:
- cam->vw.width = 128;
- cam->vw.height = 96;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=3;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_88_72:
- cam->vw.width = 88;
- cam->vw.height = 72;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=5;
- cam->params.roi.rowStart=9;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_64_48:
- cam->vw.width = 64;
- cam->vw.height = 48;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=7;
- cam->params.roi.rowStart=12;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_48_48:
- cam->vw.width = 48;
- cam->vw.height = 48;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=8;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 60;
- break;
- default:
- LOG("bad videosize value: %d\n", cam->video_size);
- return;
- }
-
- if(cam->vc.width == 0)
- cam->vc.width = cam->vw.width;
- if(cam->vc.height == 0)
- cam->vc.height = cam->vw.height;
-
- cam->params.roi.colStart += cam->vc.x >> 3;
- cam->params.roi.colEnd = cam->params.roi.colStart +
- (cam->vc.width >> 3);
- cam->params.roi.rowStart += cam->vc.y >> 2;
- cam->params.roi.rowEnd = cam->params.roi.rowStart +
- (cam->vc.height >> 2);
-
- return;
-}
-
-static int allocate_frame_buf(struct cam_data *cam)
-{
- int i;
-
- cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
- if (!cam->frame_buf)
- return -ENOBUFS;
-
- for (i = 0; i < FRAME_NUM; i++)
- cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
-
- return 0;
-}
-
-static int free_frame_buf(struct cam_data *cam)
-{
- int i;
-
- rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
- cam->frame_buf = NULL;
- for (i=0; i < FRAME_NUM; i++)
- cam->frame[i].data = NULL;
-
- return 0;
-}
-
-
-static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
-{
- int i;
-
- for (i=0; i < FRAME_NUM; i++)
- frame[i].state = FRAME_UNUSED;
- return;
-}
-
-/**********************************************************************
- *
- * General functions
- *
- **********************************************************************/
-/* send an arbitrary command to the camera */
-static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
-{
- int retval, datasize;
- u8 cmd[8], data[8];
-
- switch(command) {
- case CPIA_COMMAND_GetCPIAVersion:
- case CPIA_COMMAND_GetPnPID:
- case CPIA_COMMAND_GetCameraStatus:
- case CPIA_COMMAND_GetVPVersion:
- datasize=8;
- break;
- case CPIA_COMMAND_GetColourParams:
- case CPIA_COMMAND_GetColourBalance:
- case CPIA_COMMAND_GetExposure:
- mutex_lock(&cam->param_lock);
- datasize=8;
- break;
- case CPIA_COMMAND_ReadMCPorts:
- case CPIA_COMMAND_ReadVCRegs:
- datasize = 4;
- break;
- default:
- datasize=0;
- break;
- }
-
- cmd[0] = command>>8;
- cmd[1] = command&0xff;
- cmd[2] = a;
- cmd[3] = b;
- cmd[4] = c;
- cmd[5] = d;
- cmd[6] = datasize;
- cmd[7] = 0;
-
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval) {
- DBG("%x - failed, retval=%d\n", command, retval);
- if (command == CPIA_COMMAND_GetColourParams ||
- command == CPIA_COMMAND_GetColourBalance ||
- command == CPIA_COMMAND_GetExposure)
- mutex_unlock(&cam->param_lock);
- } else {
- switch(command) {
- case CPIA_COMMAND_GetCPIAVersion:
- cam->params.version.firmwareVersion = data[0];
- cam->params.version.firmwareRevision = data[1];
- cam->params.version.vcVersion = data[2];
- cam->params.version.vcRevision = data[3];
- break;
- case CPIA_COMMAND_GetPnPID:
- cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
- cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
- cam->params.pnpID.deviceRevision =
- data[4]+(((u16)data[5])<<8);
- break;
- case CPIA_COMMAND_GetCameraStatus:
- cam->params.status.systemState = data[0];
- cam->params.status.grabState = data[1];
- cam->params.status.streamState = data[2];
- cam->params.status.fatalError = data[3];
- cam->params.status.cmdError = data[4];
- cam->params.status.debugFlags = data[5];
- cam->params.status.vpStatus = data[6];
- cam->params.status.errorCode = data[7];
- break;
- case CPIA_COMMAND_GetVPVersion:
- cam->params.vpVersion.vpVersion = data[0];
- cam->params.vpVersion.vpRevision = data[1];
- cam->params.vpVersion.cameraHeadID =
- data[2]+(((u16)data[3])<<8);
- break;
- case CPIA_COMMAND_GetColourParams:
- cam->params.colourParams.brightness = data[0];
- cam->params.colourParams.contrast = data[1];
- cam->params.colourParams.saturation = data[2];
- mutex_unlock(&cam->param_lock);
- break;
- case CPIA_COMMAND_GetColourBalance:
- cam->params.colourBalance.redGain = data[0];
- cam->params.colourBalance.greenGain = data[1];
- cam->params.colourBalance.blueGain = data[2];
- mutex_unlock(&cam->param_lock);
- break;
- case CPIA_COMMAND_GetExposure:
- cam->params.exposure.gain = data[0];
- cam->params.exposure.fineExp = data[1];
- cam->params.exposure.coarseExpLo = data[2];
- cam->params.exposure.coarseExpHi = data[3];
- cam->params.exposure.redComp = data[4];
- cam->params.exposure.green1Comp = data[5];
- cam->params.exposure.green2Comp = data[6];
- cam->params.exposure.blueComp = data[7];
- mutex_unlock(&cam->param_lock);
- break;
-
- case CPIA_COMMAND_ReadMCPorts:
- if (!cam->params.qx3.qx3_detected)
- break;
- /* test button press */
- cam->params.qx3.button = ((data[1] & 0x02) == 0);
- if (cam->params.qx3.button) {
- /* button pressed - unlock the latch */
- do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
- do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
- }
-
- /* test whether microscope is cradled */
- cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
- break;
-
- default:
- break;
- }
- }
- return retval;
-}
-
-/* send a command to the camera with an additional data transaction */
-static int do_command_extended(struct cam_data *cam, u16 command,
- u8 a, u8 b, u8 c, u8 d,
- u8 e, u8 f, u8 g, u8 h,
- u8 i, u8 j, u8 k, u8 l)
-{
- int retval;
- u8 cmd[8], data[8];
-
- cmd[0] = command>>8;
- cmd[1] = command&0xff;
- cmd[2] = a;
- cmd[3] = b;
- cmd[4] = c;
- cmd[5] = d;
- cmd[6] = 8;
- cmd[7] = 0;
- data[0] = e;
- data[1] = f;
- data[2] = g;
- data[3] = h;
- data[4] = i;
- data[5] = j;
- data[6] = k;
- data[7] = l;
-
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval)
- DBG("%x - failed\n", command);
-
- return retval;
-}
-
-/**********************************************************************
- *
- * Colorspace conversion
- *
- **********************************************************************/
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
- int linesize, int mmap_kludge)
-{
- int y, u, v, r, g, b, y1;
-
- /* Odd lines use the same u and v as the previous line.
- * Because of compression, it is necessary to get this
- * information from the decoded image. */
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- r = ((*(rgb+1-linesize)) & 0x7c) << 1;
- g = ((*(rgb-linesize)) & 0xe0) >> 4 |
- ((*(rgb+1-linesize)) & 0x03) << 6;
- b = ((*(rgb-linesize)) & 0x1f) << 3;
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u - 53294 * v;
- b = 132278 * u;
- *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
- *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
- *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
- *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
- return 4;
- case VIDEO_PALETTE_RGB565:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- r = (*(rgb+1-linesize)) & 0xf8;
- g = ((*(rgb-linesize)) & 0xe0) >> 3 |
- ((*(rgb+1-linesize)) & 0x07) << 5;
- b = ((*(rgb-linesize)) & 0x1f) << 3;
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u - 53294 * v;
- b = 132278 * u;
- *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
- *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
- *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
- *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
- return 4;
- break;
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- if (mmap_kludge) {
- r = *(rgb+2-linesize);
- g = *(rgb+1-linesize);
- b = *(rgb-linesize);
- } else {
- r = *(rgb-linesize);
- g = *(rgb+1-linesize);
- b = *(rgb+2-linesize);
- }
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u + -53294 * v;
- b = 132278 * u;
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- if(out_fmt == VIDEO_PALETTE_RGB32)
- rgb++;
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- if(out_fmt == VIDEO_PALETTE_RGB32)
- rgb++;
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- if(out_fmt == VIDEO_PALETTE_RGB32)
- return 8;
- return 6;
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- y = *yuv++;
- u = *(rgb+1-linesize);
- y1 = *yuv;
- v = *(rgb+3-linesize);
- *rgb++ = y;
- *rgb++ = u;
- *rgb++ = y1;
- *rgb = v;
- return 4;
- case VIDEO_PALETTE_UYVY:
- u = *(rgb-linesize);
- y = *yuv++;
- v = *(rgb+2-linesize);
- y1 = *yuv;
- *rgb++ = u;
- *rgb++ = y;
- *rgb++ = v;
- *rgb = y1;
- return 4;
- case VIDEO_PALETTE_GREY:
- *rgb++ = *yuv++;
- *rgb = *yuv;
- return 2;
- default:
- DBG("Empty: %d\n", out_fmt);
- return 0;
- }
-}
-
-
-static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
- int in_uyvy, int mmap_kludge)
-{
- int y, u, v, r, g, b, y1;
-
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- if (in_uyvy) {
- u = *yuv++ - 128;
- y = (*yuv++ - 16) * 76310;
- v = *yuv++ - 128;
- y1 = (*yuv - 16) * 76310;
- } else {
- y = (*yuv++ - 16) * 76310;
- u = *yuv++ - 128;
- y1 = (*yuv++ - 16) * 76310;
- v = *yuv - 128;
- }
- r = 104635 * v;
- g = -25690 * u + -53294 * v;
- b = 132278 * u;
- break;
- default:
- y = *yuv++;
- u = *yuv++;
- y1 = *yuv++;
- v = *yuv;
- /* Just to avoid compiler warnings */
- r = 0;
- g = 0;
- b = 0;
- break;
- }
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
- *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
- *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
- *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
- return 4;
- case VIDEO_PALETTE_RGB565:
- *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
- *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
- *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
- *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
- return 4;
- case VIDEO_PALETTE_RGB24:
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- return 6;
- case VIDEO_PALETTE_RGB32:
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- rgb++;
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- rgb++;
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- return 8;
- case VIDEO_PALETTE_GREY:
- *rgb++ = y;
- *rgb = y1;
- return 2;
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- *rgb++ = y;
- *rgb++ = u;
- *rgb++ = y1;
- *rgb = v;
- return 4;
- case VIDEO_PALETTE_UYVY:
- *rgb++ = u;
- *rgb++ = y;
- *rgb++ = v;
- *rgb = y1;
- return 4;
- default:
- DBG("Empty: %d\n", out_fmt);
- return 0;
- }
-}
-
-static int skipcount(int count, int fmt)
-{
- switch(fmt) {
- case VIDEO_PALETTE_GREY:
- return count;
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_UYVY:
- return 2*count;
- case VIDEO_PALETTE_RGB24:
- return 3*count;
- case VIDEO_PALETTE_RGB32:
- return 4*count;
- default:
- return 0;
- }
-}
-
-static int parse_picture(struct cam_data *cam, int size)
-{
- u8 *obuf, *ibuf, *end_obuf;
- int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
- int rows, cols, linesize, subsample_422;
-
- /* make sure params don't change while we are decoding */
- mutex_lock(&cam->param_lock);
-
- obuf = cam->decompressed_frame.data;
- end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
- ibuf = cam->raw_image;
- origsize = size;
- out_fmt = cam->vp.palette;
-
- if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
- LOG("header not found\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
-
- if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
- LOG("wrong video size\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
-
- if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
- LOG("illegal subtype %d\n",ibuf[17]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- subsample_422 = ibuf[17] == SUBSAMPLE_422;
-
- if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
- LOG("illegal yuvorder %d\n",ibuf[18]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- in_uyvy = ibuf[18] == YUVORDER_UYVY;
-
- if ((ibuf[24] != cam->params.roi.colStart) ||
- (ibuf[25] != cam->params.roi.colEnd) ||
- (ibuf[26] != cam->params.roi.rowStart) ||
- (ibuf[27] != cam->params.roi.rowEnd)) {
- LOG("ROI mismatch\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- cols = 8*(ibuf[25] - ibuf[24]);
- rows = 4*(ibuf[27] - ibuf[26]);
-
-
- if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
- LOG("illegal compression %d\n",ibuf[28]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- compressed = (ibuf[28] == COMPRESSED);
-
- if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
- LOG("illegal decimation %d\n",ibuf[29]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- decimation = (ibuf[29] == DECIMATION_ENAB);
-
- cam->params.yuvThreshold.yThreshold = ibuf[30];
- cam->params.yuvThreshold.uvThreshold = ibuf[31];
- cam->params.status.systemState = ibuf[32];
- cam->params.status.grabState = ibuf[33];
- cam->params.status.streamState = ibuf[34];
- cam->params.status.fatalError = ibuf[35];
- cam->params.status.cmdError = ibuf[36];
- cam->params.status.debugFlags = ibuf[37];
- cam->params.status.vpStatus = ibuf[38];
- cam->params.status.errorCode = ibuf[39];
- cam->fps = ibuf[41];
- mutex_unlock(&cam->param_lock);
-
- linesize = skipcount(cols, out_fmt);
- ibuf += FRAME_HEADER_SIZE;
- size -= FRAME_HEADER_SIZE;
- ll = ibuf[0] | (ibuf[1] << 8);
- ibuf += 2;
- even_line = 1;
-
- while (size > 0) {
- size -= (ll+2);
- if (size < 0) {
- LOG("Insufficient data in buffer\n");
- return -1;
- }
-
- while (ll > 1) {
- if (!compressed || (compressed && !(*ibuf & 1))) {
- if(subsample_422 || even_line) {
- obuf += yuvconvert(ibuf, obuf, out_fmt,
- in_uyvy, cam->mmap_kludge);
- ibuf += 4;
- ll -= 4;
- } else {
- /* SUBSAMPLE_420 on an odd line */
- obuf += convert420(ibuf, obuf,
- out_fmt, linesize,
- cam->mmap_kludge);
- ibuf += 2;
- ll -= 2;
- }
- } else {
- /*skip compressed interval from previous frame*/
- obuf += skipcount(*ibuf >> 1, out_fmt);
- if (obuf > end_obuf) {
- LOG("Insufficient buffer size\n");
- return -1;
- }
- ++ibuf;
- ll--;
- }
- }
- if (ll == 1) {
- if (*ibuf != EOL) {
- DBG("EOL not found giving up after %d/%d"
- " bytes\n", origsize-size, origsize);
- return -1;
- }
-
- ++ibuf; /* skip over EOL */
-
- if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
- (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
- size -= 4;
- break;
- }
-
- if(decimation) {
- /* skip the odd lines for now */
- obuf += linesize;
- }
-
- if (size > 1) {
- ll = ibuf[0] | (ibuf[1] << 8);
- ibuf += 2; /* skip over line length */
- }
- if(!decimation)
- even_line = !even_line;
- } else {
- LOG("line length was not 1 but %d after %d/%d bytes\n",
- ll, origsize-size, origsize);
- return -1;
- }
- }
-
- if(decimation) {
- /* interpolate odd rows */
- int i, j;
- u8 *prev, *next;
- prev = cam->decompressed_frame.data;
- obuf = prev+linesize;
- next = obuf+linesize;
- for(i=1; i<rows-1; i+=2) {
- for(j=0; j<linesize; ++j) {
- *obuf++ = ((int)*prev++ + *next++) / 2;
- }
- prev += linesize;
- obuf += linesize;
- next += linesize;
- }
- /* last row is odd, just copy previous row */
- memcpy(obuf, prev, linesize);
- }
-
- cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
-
- return cam->decompressed_frame.count;
-}
-
-/* InitStreamCap wrapper to select correct start line */
-static inline int init_stream_cap(struct cam_data *cam)
-{
- return do_command(cam, CPIA_COMMAND_InitStreamCap,
- 0, cam->params.streamStartLine, 0, 0);
-}
-
-
-/* find_over_exposure
- * Finds a suitable value of OverExposure for use with SetFlickerCtrl
- * Some calculation is required because this value changes with the brightness
- * set with SetColourParameters
- *
- * Parameters: Brightness - last brightness value set with SetColourParameters
- *
- * Returns: OverExposure value to use with SetFlickerCtrl
- */
-#define FLICKER_MAX_EXPOSURE 250
-#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
-#define FLICKER_BRIGHTNESS_CONSTANT 59
-static int find_over_exposure(int brightness)
-{
- int MaxAllowableOverExposure, OverExposure;
-
- MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
- FLICKER_BRIGHTNESS_CONSTANT;
-
- if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
- OverExposure = MaxAllowableOverExposure;
- } else {
- OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
- }
-
- return OverExposure;
-}
-#undef FLICKER_MAX_EXPOSURE
-#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
-#undef FLICKER_BRIGHTNESS_CONSTANT
-
-/* update various camera modes and settings */
-static void dispatch_commands(struct cam_data *cam)
-{
- mutex_lock(&cam->param_lock);
- if (cam->cmd_queue==COMMAND_NONE) {
- mutex_unlock(&cam->param_lock);
- return;
- }
- DEB_BYTE(cam->cmd_queue);
- DEB_BYTE(cam->cmd_queue>>8);
- if (cam->cmd_queue & COMMAND_SETFORMAT) {
- do_command(cam, CPIA_COMMAND_SetFormat,
- cam->params.format.videoSize,
- cam->params.format.subSample,
- cam->params.format.yuvOrder, 0);
- do_command(cam, CPIA_COMMAND_SetROI,
- cam->params.roi.colStart, cam->params.roi.colEnd,
- cam->params.roi.rowStart, cam->params.roi.rowEnd);
- cam->first_frame = 1;
- }
-
- if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
- do_command(cam, CPIA_COMMAND_SetColourParams,
- cam->params.colourParams.brightness,
- cam->params.colourParams.contrast,
- cam->params.colourParams.saturation, 0);
-
- if (cam->cmd_queue & COMMAND_SETAPCOR)
- do_command(cam, CPIA_COMMAND_SetApcor,
- cam->params.apcor.gain1,
- cam->params.apcor.gain2,
- cam->params.apcor.gain4,
- cam->params.apcor.gain8);
-
- if (cam->cmd_queue & COMMAND_SETVLOFFSET)
- do_command(cam, CPIA_COMMAND_SetVLOffset,
- cam->params.vlOffset.gain1,
- cam->params.vlOffset.gain2,
- cam->params.vlOffset.gain4,
- cam->params.vlOffset.gain8);
-
- if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
- do_command_extended(cam, CPIA_COMMAND_SetExposure,
- cam->params.exposure.gainMode,
- 1,
- cam->params.exposure.compMode,
- cam->params.exposure.centreWeight,
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- cam->params.exposure.redComp,
- cam->params.exposure.green1Comp,
- cam->params.exposure.green2Comp,
- cam->params.exposure.blueComp);
- if(cam->params.exposure.expMode != 1) {
- do_command_extended(cam, CPIA_COMMAND_SetExposure,
- 0,
- cam->params.exposure.expMode,
- 0, 0,
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- 0, 0, 0, 0);
- }
- }
-
- if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
- if (cam->params.colourBalance.balanceMode == 1) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 1,
- cam->params.colourBalance.redGain,
- cam->params.colourBalance.greenGain,
- cam->params.colourBalance.blueGain);
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 3, 0, 0, 0);
- }
- if (cam->params.colourBalance.balanceMode == 2) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 2, 0, 0, 0);
- }
- if (cam->params.colourBalance.balanceMode == 3) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 3, 0, 0, 0);
- }
- }
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
- do_command(cam, CPIA_COMMAND_SetCompressionTarget,
- cam->params.compressionTarget.frTargeting,
- cam->params.compressionTarget.targetFR,
- cam->params.compressionTarget.targetQ, 0);
-
- if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
- do_command(cam, CPIA_COMMAND_SetYUVThresh,
- cam->params.yuvThreshold.yThreshold,
- cam->params.yuvThreshold.uvThreshold, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
- do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
- 0, 0, 0, 0,
- cam->params.compressionParams.hysteresis,
- cam->params.compressionParams.threshMax,
- cam->params.compressionParams.smallStep,
- cam->params.compressionParams.largeStep,
- cam->params.compressionParams.decimationHysteresis,
- cam->params.compressionParams.frDiffStepThresh,
- cam->params.compressionParams.qDiffStepThresh,
- cam->params.compressionParams.decimationThreshMod);
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
- do_command(cam, CPIA_COMMAND_SetCompression,
- cam->params.compression.mode,
- cam->params.compression.decimation, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETSENSORFPS)
- do_command(cam, CPIA_COMMAND_SetSensorFPS,
- cam->params.sensorFps.divisor,
- cam->params.sensorFps.baserate, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
- do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
- cam->params.flickerControl.flickerMode,
- cam->params.flickerControl.coarseJump,
- abs(cam->params.flickerControl.allowableOverExposure),
- 0);
-
- if (cam->cmd_queue & COMMAND_SETECPTIMING)
- do_command(cam, CPIA_COMMAND_SetECPTiming,
- cam->params.ecpTiming, 0, 0, 0);
-
- if (cam->cmd_queue & COMMAND_PAUSE)
- do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
-
- if (cam->cmd_queue & COMMAND_RESUME)
- init_stream_cap(cam);
-
- if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
- {
- int p1 = (cam->params.qx3.bottomlight == 0) << 1;
- int p2 = (cam->params.qx3.toplight == 0) << 3;
- do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
- do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
- }
-
- cam->cmd_queue = COMMAND_NONE;
- mutex_unlock(&cam->param_lock);
- return;
-}
-
-
-
-static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
- int on)
-{
- /* Everything in here is from the Windows driver */
-#define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
- params->version.firmwareRevision == (y))
-/* define for compgain calculation */
-#if 0
-#define COMPGAIN(base, curexp, newexp) \
- (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
-#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
- (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
-#else
- /* equivalent functions without floating point math */
-#define COMPGAIN(base, curexp, newexp) \
- (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
-#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
- (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
-#endif
-
-
- int currentexp = params->exposure.coarseExpLo +
- params->exposure.coarseExpHi*256;
- int startexp;
- if (on) {
- int cj = params->flickerControl.coarseJump;
- params->flickerControl.flickerMode = 1;
- params->flickerControl.disabled = 0;
- if(params->exposure.expMode != 2)
- *command_flags |= COMMAND_SETEXPOSURE;
- params->exposure.expMode = 2;
- currentexp = currentexp << params->exposure.gain;
- params->exposure.gain = 0;
- /* round down current exposure to nearest value */
- startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
- if(startexp < 1)
- startexp = 1;
- startexp = (startexp * cj) - 1;
- if(FIRMWARE_VERSION(1,2))
- while(startexp > MAX_EXP_102)
- startexp -= cj;
- else
- while(startexp > MAX_EXP)
- startexp -= cj;
- params->exposure.coarseExpLo = startexp & 0xff;
- params->exposure.coarseExpHi = startexp >> 8;
- if (currentexp > startexp) {
- if (currentexp > (2 * startexp))
- currentexp = 2 * startexp;
- params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
- params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
- params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
- params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
- } else {
- params->exposure.redComp = COMP_RED;
- params->exposure.green1Comp = COMP_GREEN1;
- params->exposure.green2Comp = COMP_GREEN2;
- params->exposure.blueComp = COMP_BLUE;
- }
- if(FIRMWARE_VERSION(1,2))
- params->exposure.compMode = 0;
- else
- params->exposure.compMode = 1;
-
- params->apcor.gain1 = 0x18;
- params->apcor.gain2 = 0x18;
- params->apcor.gain4 = 0x16;
- params->apcor.gain8 = 0x14;
- *command_flags |= COMMAND_SETAPCOR;
- } else {
- params->flickerControl.flickerMode = 0;
- params->flickerControl.disabled = 1;
- /* Coarse = average of equivalent coarse for each comp channel */
- startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
- startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
- startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
- startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
- startexp = startexp >> 2;
- while(startexp > MAX_EXP &&
- params->exposure.gain < params->exposure.gainMode-1) {
- startexp = startexp >> 1;
- ++params->exposure.gain;
- }
- if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
- startexp = MAX_EXP_102;
- if(startexp > MAX_EXP)
- startexp = MAX_EXP;
- params->exposure.coarseExpLo = startexp&0xff;
- params->exposure.coarseExpHi = startexp >> 8;
- params->exposure.redComp = COMP_RED;
- params->exposure.green1Comp = COMP_GREEN1;
- params->exposure.green2Comp = COMP_GREEN2;
- params->exposure.blueComp = COMP_BLUE;
- params->exposure.compMode = 1;
- *command_flags |= COMMAND_SETEXPOSURE;
- params->apcor.gain1 = 0x18;
- params->apcor.gain2 = 0x16;
- params->apcor.gain4 = 0x24;
- params->apcor.gain8 = 0x34;
- *command_flags |= COMMAND_SETAPCOR;
- }
- params->vlOffset.gain1 = 20;
- params->vlOffset.gain2 = 24;
- params->vlOffset.gain4 = 26;
- params->vlOffset.gain8 = 26;
- *command_flags |= COMMAND_SETVLOFFSET;
-#undef FIRMWARE_VERSION
-#undef EXP_FROM_COMP
-#undef COMPGAIN
-}
-
-#define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
- cam->params.version.firmwareRevision == (y))
-/* monitor the exposure and adjust the sensor frame rate if needed */
-static void monitor_exposure(struct cam_data *cam)
-{
- u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
- int retval, light_exp, dark_exp, very_dark_exp;
- int old_exposure, new_exposure, framerate;
-
- /* get necessary stats and register settings from camera */
- /* do_command can't handle this, so do it ourselves */
- cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
- cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
- cmd[2] = 30;
- cmd[3] = 4;
- cmd[4] = 9;
- cmd[5] = 8;
- cmd[6] = 8;
- cmd[7] = 0;
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval) {
- LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
- retval);
- return;
- }
- exp_acc = data[0];
- bcomp = data[1];
- gain = data[2];
- coarseL = data[3];
-
- mutex_lock(&cam->param_lock);
- light_exp = cam->params.colourParams.brightness +
- TC - 50 + EXP_ACC_LIGHT;
- if(light_exp > 255)
- light_exp = 255;
- dark_exp = cam->params.colourParams.brightness +
- TC - 50 - EXP_ACC_DARK;
- if(dark_exp < 0)
- dark_exp = 0;
- very_dark_exp = dark_exp/2;
-
- old_exposure = cam->params.exposure.coarseExpHi * 256 +
- cam->params.exposure.coarseExpLo;
-
- if(!cam->params.flickerControl.disabled) {
- /* Flicker control on */
- int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
- bcomp += 128; /* decode */
- if(bcomp >= max_comp && exp_acc < dark_exp) {
- /* dark */
- if(exp_acc < very_dark_exp) {
- /* very dark */
- if(cam->exposure_status == EXPOSURE_VERY_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_DARK;
- cam->exposure_count = 1;
- }
- } else {
- /* just dark */
- if(cam->exposure_status == EXPOSURE_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_DARK;
- cam->exposure_count = 1;
- }
- }
- } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
- /* light */
- if(old_exposure <= VERY_LOW_EXP) {
- /* very light */
- if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_LIGHT;
- cam->exposure_count = 1;
- }
- } else {
- /* just light */
- if(cam->exposure_status == EXPOSURE_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_LIGHT;
- cam->exposure_count = 1;
- }
- }
- } else {
- /* not dark or light */
- cam->exposure_status = EXPOSURE_NORMAL;
- }
- } else {
- /* Flicker control off */
- if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
- /* dark */
- if(exp_acc < very_dark_exp) {
- /* very dark */
- if(cam->exposure_status == EXPOSURE_VERY_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_DARK;
- cam->exposure_count = 1;
- }
- } else {
- /* just dark */
- if(cam->exposure_status == EXPOSURE_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_DARK;
- cam->exposure_count = 1;
- }
- }
- } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
- /* light */
- if(old_exposure <= VERY_LOW_EXP) {
- /* very light */
- if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_LIGHT;
- cam->exposure_count = 1;
- }
- } else {
- /* just light */
- if(cam->exposure_status == EXPOSURE_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_LIGHT;
- cam->exposure_count = 1;
- }
- }
- } else {
- /* not dark or light */
- cam->exposure_status = EXPOSURE_NORMAL;
- }
- }
-
- framerate = cam->fps;
- if(framerate > 30 || framerate < 1)
- framerate = 1;
-
- if(!cam->params.flickerControl.disabled) {
- /* Flicker control on */
- if((cam->exposure_status == EXPOSURE_VERY_DARK ||
- cam->exposure_status == EXPOSURE_DARK) &&
- cam->exposure_count >= DARK_TIME*framerate &&
- cam->params.sensorFps.divisor < 3) {
-
- /* dark for too long */
- ++cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
- new_exposure = cam->params.flickerControl.coarseJump-1;
- while(new_exposure < old_exposure/2)
- new_exposure += cam->params.flickerControl.coarseJump;
- cam->params.exposure.coarseExpLo = new_exposure & 0xff;
- cam->params.exposure.coarseExpHi = new_exposure >> 8;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically decreasing sensor_fps\n");
-
- } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
- cam->exposure_status == EXPOSURE_LIGHT) &&
- cam->exposure_count >= LIGHT_TIME*framerate &&
- cam->params.sensorFps.divisor > 0) {
-
- /* light for too long */
- int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
-
- --cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
- new_exposure = cam->params.flickerControl.coarseJump-1;
- while(new_exposure < 2*old_exposure &&
- new_exposure+
- cam->params.flickerControl.coarseJump < max_exp)
- new_exposure += cam->params.flickerControl.coarseJump;
- cam->params.exposure.coarseExpLo = new_exposure & 0xff;
- cam->params.exposure.coarseExpHi = new_exposure >> 8;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically increasing sensor_fps\n");
- }
- } else {
- /* Flicker control off */
- if((cam->exposure_status == EXPOSURE_VERY_DARK ||
- cam->exposure_status == EXPOSURE_DARK) &&
- cam->exposure_count >= DARK_TIME*framerate &&
- cam->params.sensorFps.divisor < 3) {
-
- /* dark for too long */
- ++cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- if(cam->params.exposure.gain > 0) {
- --cam->params.exposure.gain;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- }
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically decreasing sensor_fps\n");
-
- } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
- cam->exposure_status == EXPOSURE_LIGHT) &&
- cam->exposure_count >= LIGHT_TIME*framerate &&
- cam->params.sensorFps.divisor > 0) {
-
- /* light for too long */
- --cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- if(cam->params.exposure.gain <
- cam->params.exposure.gainMode-1) {
- ++cam->params.exposure.gain;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- }
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically increasing sensor_fps\n");
- }
- }
- mutex_unlock(&cam->param_lock);
-}
-
-/*-----------------------------------------------------------------*/
-/* if flicker is switched off, this function switches it back on.It checks,
- however, that conditions are suitable before restarting it.
- This should only be called for firmware version 1.2.
-
- It also adjust the colour balance when an exposure step is detected - as
- long as flicker is running
-*/
-static void restart_flicker(struct cam_data *cam)
-{
- int cam_exposure, old_exp;
- if(!FIRMWARE_VERSION(1,2))
- return;
- mutex_lock(&cam->param_lock);
- if(cam->params.flickerControl.flickerMode == 0 ||
- cam->raw_image[39] == 0) {
- mutex_unlock(&cam->param_lock);
- return;
- }
- cam_exposure = cam->raw_image[39]*2;
- old_exp = cam->params.exposure.coarseExpLo +
- cam->params.exposure.coarseExpHi*256;
- /*
- see how far away camera exposure is from a valid
- flicker exposure value
- */
- cam_exposure %= cam->params.flickerControl.coarseJump;
- if(!cam->params.flickerControl.disabled &&
- cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
- /* Flicker control auto-disabled */
- cam->params.flickerControl.disabled = 1;
- }
-
- if(cam->params.flickerControl.disabled &&
- cam->params.flickerControl.flickerMode &&
- old_exp > cam->params.flickerControl.coarseJump +
- ROUND_UP_EXP_FOR_FLICKER) {
- /* exposure is now high enough to switch
- flicker control back on */
- set_flicker(&cam->params, &cam->cmd_queue, 1);
- if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
- cam->params.exposure.expMode == 2)
- cam->exposure_status = EXPOSURE_NORMAL;
-
- }
- mutex_unlock(&cam->param_lock);
-}
-#undef FIRMWARE_VERSION
-
-static int clear_stall(struct cam_data *cam)
-{
- /* FIXME: Does this actually work? */
- LOG("Clearing stall\n");
-
- cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
- do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
- return cam->params.status.streamState != STREAM_PAUSED;
-}
-
-/* kernel thread function to read image from camera */
-static int fetch_frame(void *data)
-{
- int image_size, retry;
- struct cam_data *cam = (struct cam_data *)data;
- unsigned long oldjif, rate, diff;
-
- /* Allow up to two bad images in a row to be read and
- * ignored before an error is reported */
- for (retry = 0; retry < 3; ++retry) {
- if (retry)
- DBG("retry=%d\n", retry);
-
- if (!cam->ops)
- continue;
-
- /* load first frame always uncompressed */
- if (cam->first_frame &&
- cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
- do_command(cam, CPIA_COMMAND_SetCompression,
- CPIA_COMPRESSION_NONE,
- NO_DECIMATION, 0, 0);
- /* Trial & error - Discarding a frame prevents the
- first frame from having an error in the data. */
- do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
- }
-
- /* init camera upload */
- if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
- cam->params.streamStartLine, 0, 0))
- continue;
-
- if (cam->ops->wait_for_stream_ready) {
- /* loop until image ready */
- int count = 0;
- do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
- while (cam->params.status.streamState != STREAM_READY) {
- if(++count > READY_TIMEOUT)
- break;
- if(cam->params.status.streamState ==
- STREAM_PAUSED) {
- /* Bad news */
- if(!clear_stall(cam))
- return -EIO;
- }
-
- cond_resched();
-
- /* sleep for 10 ms, hopefully ;) */
- msleep_interruptible(10);
- if (signal_pending(current))
- return -EINTR;
-
- do_command(cam, CPIA_COMMAND_GetCameraStatus,
- 0, 0, 0, 0);
- }
- if(cam->params.status.streamState != STREAM_READY) {
- continue;
- }
- }
-
- cond_resched();
-
- /* grab image from camera */
- oldjif = jiffies;
- image_size = cam->ops->streamRead(cam->lowlevel_data,
- cam->raw_image, 0);
- if (image_size <= 0) {
- DBG("streamRead failed: %d\n", image_size);
- continue;
- }
-
- rate = image_size * HZ / 1024;
- diff = jiffies-oldjif;
- cam->transfer_rate = diff==0 ? rate : rate/diff;
- /* diff==0 ? unlikely but possible */
-
- /* Switch flicker control back on if it got turned off */
- restart_flicker(cam);
-
- /* If AEC is enabled, monitor the exposure and
- adjust the sensor frame rate if needed */
- if(cam->params.exposure.expMode == 2)
- monitor_exposure(cam);
-
- /* camera idle now so dispatch queued commands */
- dispatch_commands(cam);
-
- /* Update our knowledge of the camera state */
- do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
- do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
- do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
-
- /* decompress and convert image to by copying it from
- * raw_image to decompressed_frame
- */
-
- cond_resched();
-
- cam->image_size = parse_picture(cam, image_size);
- if (cam->image_size <= 0) {
- DBG("parse_picture failed %d\n", cam->image_size);
- if(cam->params.compression.mode !=
- CPIA_COMPRESSION_NONE) {
- /* Compression may not work right if we
- had a bad frame, get the next one
- uncompressed. */
- cam->first_frame = 1;
- do_command(cam, CPIA_COMMAND_SetGrabMode,
- CPIA_GRAB_SINGLE, 0, 0, 0);
- /* FIXME: Trial & error - need up to 70ms for
- the grab mode change to complete ? */
- msleep_interruptible(70);
- if (signal_pending(current))
- return -EINTR;
- }
- } else
- break;
- }
-
- if (retry < 3) {
- /* FIXME: this only works for double buffering */
- if (cam->frame[cam->curframe].state == FRAME_READY) {
- memcpy(cam->frame[cam->curframe].data,
- cam->decompressed_frame.data,
- cam->decompressed_frame.count);
- cam->frame[cam->curframe].state = FRAME_DONE;
- } else
- cam->decompressed_frame.state = FRAME_DONE;
-
- if (cam->first_frame) {
- cam->first_frame = 0;
- do_command(cam, CPIA_COMMAND_SetCompression,
- cam->params.compression.mode,
- cam->params.compression.decimation, 0, 0);
-
- /* Switch from single-grab to continuous grab */
- do_command(cam, CPIA_COMMAND_SetGrabMode,
- CPIA_GRAB_CONTINUOUS, 0, 0, 0);
- }
- return 0;
- }
- return -EIO;
-}
-
-static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
-{
- if (!cam->frame_buf) {
- /* we do lazy allocation */
- int err;
- if ((err = allocate_frame_buf(cam)))
- return err;
- }
-
- cam->curframe = vm->frame;
- cam->frame[cam->curframe].state = FRAME_READY;
- return fetch_frame(cam);
-}
-
-static int goto_high_power(struct cam_data *cam)
-{
- if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
- return -EIO;
- msleep_interruptible(40); /* windows driver does it too */
- if(signal_pending(current))
- return -EINTR;
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -EIO;
- if (cam->params.status.systemState == HI_POWER_STATE) {
- DBG("camera now in HIGH power state\n");
- return 0;
- }
- printstatus(cam);
- return -EIO;
-}
-
-static int goto_low_power(struct cam_data *cam)
-{
- if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
- return -1;
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -1;
- if (cam->params.status.systemState == LO_POWER_STATE) {
- DBG("camera now in LOW power state\n");
- return 0;
- }
- printstatus(cam);
- return -1;
-}
-
-static void save_camera_state(struct cam_data *cam)
-{
- if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
- do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
- if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
- do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
-
- DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- cam->params.exposure.redComp,
- cam->params.exposure.green1Comp,
- cam->params.exposure.green2Comp,
- cam->params.exposure.blueComp);
- DBG("%d/%d/%d\n",
- cam->params.colourBalance.redGain,
- cam->params.colourBalance.greenGain,
- cam->params.colourBalance.blueGain);
-}
-
-static int set_camera_state(struct cam_data *cam)
-{
- cam->cmd_queue = COMMAND_SETCOMPRESSION |
- COMMAND_SETCOMPRESSIONTARGET |
- COMMAND_SETCOLOURPARAMS |
- COMMAND_SETFORMAT |
- COMMAND_SETYUVTHRESH |
- COMMAND_SETECPTIMING |
- COMMAND_SETCOMPRESSIONPARAMS |
- COMMAND_SETEXPOSURE |
- COMMAND_SETCOLOURBALANCE |
- COMMAND_SETSENSORFPS |
- COMMAND_SETAPCOR |
- COMMAND_SETFLICKERCTRL |
- COMMAND_SETVLOFFSET;
-
- do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
- dispatch_commands(cam);
-
- /* Wait 6 frames for the sensor to get all settings and
- AEC/ACB to settle */
- msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
- (1 << cam->params.sensorFps.divisor) + 10);
-
- if(signal_pending(current))
- return -EINTR;
-
- save_camera_state(cam);
-
- return 0;
-}
-
-static void get_version_information(struct cam_data *cam)
-{
- /* GetCPIAVersion */
- do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
-
- /* GetPnPID */
- do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
-}
-
-/* initialize camera */
-static int reset_camera(struct cam_data *cam)
-{
- int err;
- /* Start the camera in low power mode */
- if (goto_low_power(cam)) {
- if (cam->params.status.systemState != WARM_BOOT_STATE)
- return -ENODEV;
-
- /* FIXME: this is just dirty trial and error */
- err = goto_high_power(cam);
- if(err)
- return err;
- do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
- if (goto_low_power(cam))
- return -ENODEV;
- }
-
- /* procedure described in developer's guide p3-28 */
-
- /* Check the firmware version. */
- cam->params.version.firmwareVersion = 0;
- get_version_information(cam);
- if (cam->params.version.firmwareVersion != 1)
- return -ENODEV;
-
- /* A bug in firmware 1-02 limits gainMode to 2 */
- if(cam->params.version.firmwareRevision <= 2 &&
- cam->params.exposure.gainMode > 2) {
- cam->params.exposure.gainMode = 2;
- }
-
- /* set QX3 detected flag */
- cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
- cam->params.pnpID.product == 0x0001);
-
- /* The fatal error checking should be done after
- * the camera powers up (developer's guide p 3-38) */
-
- /* Set streamState before transition to high power to avoid bug
- * in firmware 1-02 */
- do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
- STREAM_NOT_READY, 0);
-
- /* GotoHiPower */
- err = goto_high_power(cam);
- if (err)
- return err;
-
- /* Check the camera status */
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -EIO;
-
- if (cam->params.status.fatalError) {
- DBG("fatal_error: %#04x\n",
- cam->params.status.fatalError);
- DBG("vp_status: %#04x\n",
- cam->params.status.vpStatus);
- if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
- /* Fatal error in camera */
- return -EIO;
- } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
- /* Firmware 1-02 may do this for parallel port cameras,
- * just clear the flags (developer's guide p 3-38) */
- do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
- FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
- }
- }
-
- /* Check the camera status again */
- if (cam->params.status.fatalError) {
- if (cam->params.status.fatalError)
- return -EIO;
- }
-
- /* VPVersion can't be retrieved before the camera is in HiPower,
- * so get it here instead of in get_version_information. */
- do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
-
- /* set camera to a known state */
- return set_camera_state(cam);
-}
-
-static void put_cam(struct cpia_camera_ops* ops)
-{
- module_put(ops->owner);
-}
-
-/* ------------------------- V4L interface --------------------- */
-static int cpia_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct cam_data *cam = video_get_drvdata(dev);
- int err;
-
- if (!cam) {
- DBG("Internal error, cam_data not found!\n");
- return -ENODEV;
- }
-
- if (cam->open_count > 0) {
- DBG("Camera already open\n");
- return -EBUSY;
- }
-
- if (!try_module_get(cam->ops->owner))
- return -ENODEV;
-
- mutex_lock(&cam->busy_lock);
- err = -ENOMEM;
- if (!cam->raw_image) {
- cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
- if (!cam->raw_image)
- goto oops;
- }
-
- if (!cam->decompressed_frame.data) {
- cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
- if (!cam->decompressed_frame.data)
- goto oops;
- }
-
- /* open cpia */
- err = -ENODEV;
- if (cam->ops->open(cam->lowlevel_data))
- goto oops;
-
- /* reset the camera */
- if ((err = reset_camera(cam)) != 0) {
- cam->ops->close(cam->lowlevel_data);
- goto oops;
- }
-
- err = -EINTR;
- if(signal_pending(current))
- goto oops;
-
- /* Set ownership of /proc/cpia/videoX to current user */
- if(cam->proc_entry)
- cam->proc_entry->uid = current_uid();
-
- /* set mark for loading first frame uncompressed */
- cam->first_frame = 1;
-
- /* init it to something */
- cam->mmap_kludge = 0;
-
- ++cam->open_count;
- file->private_data = dev;
- mutex_unlock(&cam->busy_lock);
- return 0;
-
- oops:
- if (cam->decompressed_frame.data) {
- rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
- cam->decompressed_frame.data = NULL;
- }
- if (cam->raw_image) {
- rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
- cam->raw_image = NULL;
- }
- mutex_unlock(&cam->busy_lock);
- put_cam(cam->ops);
- return err;
-}
-
-static int cpia_close(struct file *file)
-{
- struct video_device *dev = file->private_data;
- struct cam_data *cam = video_get_drvdata(dev);
-
- if (cam->ops) {
- /* Return ownership of /proc/cpia/videoX to root */
- if(cam->proc_entry)
- cam->proc_entry->uid = 0;
-
- /* save camera state for later open (developers guide ch 3.5.3) */
- save_camera_state(cam);
-
- /* GotoLoPower */
- goto_low_power(cam);
-
- /* Update the camera status */
- do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
-
- /* cleanup internal state stuff */
- free_frames(cam->frame);
-
- /* close cpia */
- cam->ops->close(cam->lowlevel_data);
-
- put_cam(cam->ops);
- }
-
- if (--cam->open_count == 0) {
- /* clean up capture-buffers */
- if (cam->raw_image) {
- rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
- cam->raw_image = NULL;
- }
-
- if (cam->decompressed_frame.data) {
- rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
- cam->decompressed_frame.data = NULL;
- }
-
- if (cam->frame_buf)
- free_frame_buf(cam);
-
- if (!cam->ops)
- kfree(cam);
- }
- file->private_data = NULL;
-
- return 0;
-}
-
-static ssize_t cpia_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *dev = file->private_data;
- struct cam_data *cam = video_get_drvdata(dev);
- int err;
-
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- if (!buf) {
- DBG("buf NULL\n");
- mutex_unlock(&cam->busy_lock);
- return -EINVAL;
- }
-
- if (!count) {
- DBG("count 0\n");
- mutex_unlock(&cam->busy_lock);
- return 0;
- }
-
- if (!cam->ops) {
- DBG("ops NULL\n");
- mutex_unlock(&cam->busy_lock);
- return -ENODEV;
- }
-
- /* upload frame */
- cam->decompressed_frame.state = FRAME_READY;
- cam->mmap_kludge=0;
- if((err = fetch_frame(cam)) != 0) {
- DBG("ERROR from fetch_frame: %d\n", err);
- mutex_unlock(&cam->busy_lock);
- return err;
- }
- cam->decompressed_frame.state = FRAME_UNUSED;
-
- /* copy data to user space */
- if (cam->decompressed_frame.count > count) {
- DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
- (unsigned long) count);
- mutex_unlock(&cam->busy_lock);
- return -EFAULT;
- }
- if (copy_to_user(buf, cam->decompressed_frame.data,
- cam->decompressed_frame.count)) {
- DBG("copy_to_user failed\n");
- mutex_unlock(&cam->busy_lock);
- return -EFAULT;
- }
-
- mutex_unlock(&cam->busy_lock);
- return cam->decompressed_frame.count;
-}
-
-static long cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct video_device *dev = file->private_data;
- struct cam_data *cam = video_get_drvdata(dev);
- int retval = 0;
-
- if (!cam || !cam->ops)
- return -ENODEV;
-
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- /* DBG("cpia_ioctl: %u\n", cmd); */
-
- switch (cmd) {
- /* query capabilities */
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
-
- DBG("VIDIOCGCAP\n");
- strcpy(b->name, "CPiA Camera");
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 352; /* VIDEOSIZE_CIF */
- b->maxheight = 288;
- b->minwidth = 48; /* VIDEOSIZE_48_48 */
- b->minheight = 48;
- break;
- }
-
- /* get/set video source - we are a camera and nothing else */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- DBG("VIDIOCGCHAN\n");
- if (v->channel != 0) {
- retval = -EINVAL;
- break;
- }
-
- v->channel = 0;
- strcpy(v->name, "Camera");
- v->tuners = 0;
- v->flags = 0;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = 0;
- break;
- }
-
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
-
- DBG("VIDIOCSCHAN\n");
- if (v->channel != 0)
- retval = -EINVAL;
- break;
- }
-
- /* image properties */
- case VIDIOCGPICT:
- {
- struct video_picture *pic = arg;
- DBG("VIDIOCGPICT\n");
- *pic = cam->vp;
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *vp = arg;
-
- DBG("VIDIOCSPICT\n");
-
- /* check validity */
- DBG("palette: %d\n", vp->palette);
- DBG("depth: %d\n", vp->depth);
- if (!valid_mode(vp->palette, vp->depth)) {
- retval = -EINVAL;
- break;
- }
-
- mutex_lock(&cam->param_lock);
- /* brightness, colour, contrast need no check 0-65535 */
- cam->vp = *vp;
- /* update cam->params.colourParams */
- cam->params.colourParams.brightness = vp->brightness*100/65535;
- cam->params.colourParams.contrast = vp->contrast*100/65535;
- cam->params.colourParams.saturation = vp->colour*100/65535;
- /* contrast is in steps of 8, so round */
- cam->params.colourParams.contrast =
- ((cam->params.colourParams.contrast + 3) / 8) * 8;
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2 &&
- cam->params.colourParams.contrast > 80) {
- /* 1-02 firmware limits contrast to 80 */
- cam->params.colourParams.contrast = 80;
- }
-
- /* Adjust flicker control if necessary */
- if(cam->params.flickerControl.allowableOverExposure < 0)
- cam->params.flickerControl.allowableOverExposure =
- -find_over_exposure(cam->params.colourParams.brightness);
- if(cam->params.flickerControl.flickerMode != 0)
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
-
- /* queue command to update camera */
- cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
- mutex_unlock(&cam->param_lock);
- DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
- vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
- vp->contrast);
- break;
- }
-
- /* get/set capture window */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
- DBG("VIDIOCGWIN\n");
-
- *vw = cam->vw;
- break;
- }
-
- case VIDIOCSWIN:
- {
- /* copy_from_user, check validity, copy to internal structure */
- struct video_window *vw = arg;
- DBG("VIDIOCSWIN\n");
-
- if (vw->clipcount != 0) { /* clipping not supported */
- retval = -EINVAL;
- break;
- }
- if (vw->clips != NULL) { /* clipping not supported */
- retval = -EINVAL;
- break;
- }
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- mutex_lock(&cam->param_lock);
- if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
- int video_size = match_videosize(vw->width, vw->height);
-
- if (video_size < 0) {
- retval = -EINVAL;
- mutex_unlock(&cam->param_lock);
- break;
- }
- cam->video_size = video_size;
-
- /* video size is changing, reset the subcapture area */
- memset(&cam->vc, 0, sizeof(cam->vc));
-
- set_vw_size(cam);
- DBG("%d / %d\n", cam->vw.width, cam->vw.height);
- cam->cmd_queue |= COMMAND_SETFORMAT;
- }
-
- mutex_unlock(&cam->param_lock);
-
- /* setformat ignored by camera during streaming,
- * so stop/dispatch/start */
- if (cam->cmd_queue & COMMAND_SETFORMAT) {
- DBG("\n");
- dispatch_commands(cam);
- }
- DBG("%d/%d:%d\n", cam->video_size,
- cam->vw.width, cam->vw.height);
- break;
- }
-
- /* mmap interface */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- DBG("VIDIOCGMBUF\n");
- memset(vm, 0, sizeof(*vm));
- vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
- vm->frames = FRAME_NUM;
- for (i = 0; i < FRAME_NUM; i++)
- vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
- int video_size;
-
- DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
- vm->width, vm->height);
- if (vm->frame<0||vm->frame>=FRAME_NUM) {
- retval = -EINVAL;
- break;
- }
-
- /* set video format */
- cam->vp.palette = vm->format;
- switch(vm->format) {
- case VIDEO_PALETTE_GREY:
- cam->vp.depth=8;
- break;
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_UYVY:
- cam->vp.depth = 16;
- break;
- case VIDEO_PALETTE_RGB24:
- cam->vp.depth = 24;
- break;
- case VIDEO_PALETTE_RGB32:
- cam->vp.depth = 32;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- if (retval)
- break;
-
- /* set video size */
- video_size = match_videosize(vm->width, vm->height);
- if (video_size < 0) {
- retval = -EINVAL;
- break;
- }
- if (video_size != cam->video_size) {
- cam->video_size = video_size;
-
- /* video size is changing, reset the subcapture area */
- memset(&cam->vc, 0, sizeof(cam->vc));
-
- set_vw_size(cam);
- cam->cmd_queue |= COMMAND_SETFORMAT;
- dispatch_commands(cam);
- }
- /* according to v4l-spec we must start streaming here */
- cam->mmap_kludge = 1;
- retval = capture_frame(cam, vm);
-
- break;
- }
-
- case VIDIOCSYNC:
- {
- int *frame = arg;
-
- //DBG("VIDIOCSYNC: %d\n", *frame);
-
- if (*frame<0 || *frame >= FRAME_NUM) {
- retval = -EINVAL;
- break;
- }
-
- switch (cam->frame[*frame].state) {
- case FRAME_UNUSED:
- case FRAME_READY:
- case FRAME_GRABBING:
- DBG("sync to unused frame %d\n", *frame);
- retval = -EINVAL;
- break;
-
- case FRAME_DONE:
- cam->frame[*frame].state = FRAME_UNUSED;
- //DBG("VIDIOCSYNC: %d synced\n", *frame);
- break;
- }
- if (retval == -EINTR) {
- /* FIXME - xawtv does not handle this nice */
- retval = 0;
- }
- break;
- }
-
- case VIDIOCGCAPTURE:
- {
- struct video_capture *vc = arg;
-
- DBG("VIDIOCGCAPTURE\n");
-
- *vc = cam->vc;
-
- break;
- }
-
- case VIDIOCSCAPTURE:
- {
- struct video_capture *vc = arg;
-
- DBG("VIDIOCSCAPTURE\n");
-
- if (vc->decimation != 0) { /* How should this be used? */
- retval = -EINVAL;
- break;
- }
- if (vc->flags != 0) { /* Even/odd grab not supported */
- retval = -EINVAL;
- break;
- }
-
- /* Clip to the resolution we can set for the ROI
- (every 8 columns and 4 rows) */
- vc->x = vc->x & ~(__u32)7;
- vc->y = vc->y & ~(__u32)3;
- vc->width = vc->width & ~(__u32)7;
- vc->height = vc->height & ~(__u32)3;
-
- if(vc->width == 0 || vc->height == 0 ||
- vc->x + vc->width > cam->vw.width ||
- vc->y + vc->height > cam->vw.height) {
- retval = -EINVAL;
- break;
- }
-
- DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
-
- mutex_lock(&cam->param_lock);
-
- cam->vc.x = vc->x;
- cam->vc.y = vc->y;
- cam->vc.width = vc->width;
- cam->vc.height = vc->height;
-
- set_vw_size(cam);
- cam->cmd_queue |= COMMAND_SETFORMAT;
-
- mutex_unlock(&cam->param_lock);
-
- /* setformat ignored by camera during streaming,
- * so stop/dispatch/start */
- dispatch_commands(cam);
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- DBG("VIDIOCGUNIT\n");
-
- vu->video = cam->vdev.minor;
- vu->vbi = VIDEO_NO_UNIT;
- vu->radio = VIDEO_NO_UNIT;
- vu->audio = VIDEO_NO_UNIT;
- vu->teletext = VIDEO_NO_UNIT;
-
- break;
- }
-
-
- /* pointless to implement overlay with this camera */
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCKEY:
- /* tuner interface - we have none */
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- /* audio interface - we have none */
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- retval = -EINVAL;
- break;
- default:
- retval = -ENOIOCTLCMD;
- break;
- }
-
- mutex_unlock(&cam->busy_lock);
- return retval;
-}
-
-static long cpia_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, cpia_do_ioctl);
-}
-
-
-/* FIXME */
-static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long page, pos;
- struct cam_data *cam = video_get_drvdata(dev);
- int retval;
-
- if (!cam || !cam->ops)
- return -ENODEV;
-
- DBG("cpia_mmap: %ld\n", size);
-
- if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
- return -EINVAL;
-
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- if (!cam->frame_buf) { /* we do lazy allocation */
- if ((retval = allocate_frame_buf(cam))) {
- mutex_unlock(&cam->busy_lock);
- return retval;
- }
- }
-
- pos = (unsigned long)(cam->frame_buf);
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&cam->busy_lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- DBG("cpia_mmap: %ld\n", size);
- mutex_unlock(&cam->busy_lock);
-
- return 0;
-}
-
-static const struct v4l2_file_operations cpia_fops = {
- .owner = THIS_MODULE,
- .open = cpia_open,
- .release = cpia_close,
- .read = cpia_read,
- .mmap = cpia_mmap,
- .ioctl = cpia_ioctl,
-};
-
-static struct video_device cpia_template = {
- .name = "CPiA Camera",
- .fops = &cpia_fops,
- .release = video_device_release_empty,
-};
-
-/* initialise cam_data structure */
-static void reset_camera_struct(struct cam_data *cam)
-{
- /* The following parameter values are the defaults from
- * "Software Developer's Guide for CPiA Cameras". Any changes
- * to the defaults are noted in comments. */
- cam->params.colourParams.brightness = 50;
- cam->params.colourParams.contrast = 48;
- cam->params.colourParams.saturation = 50;
- cam->params.exposure.gainMode = 4;
- cam->params.exposure.expMode = 2; /* AEC */
- cam->params.exposure.compMode = 1;
- cam->params.exposure.centreWeight = 1;
- cam->params.exposure.gain = 0;
- cam->params.exposure.fineExp = 0;
- cam->params.exposure.coarseExpLo = 185;
- cam->params.exposure.coarseExpHi = 0;
- cam->params.exposure.redComp = COMP_RED;
- cam->params.exposure.green1Comp = COMP_GREEN1;
- cam->params.exposure.green2Comp = COMP_GREEN2;
- cam->params.exposure.blueComp = COMP_BLUE;
- cam->params.colourBalance.balanceMode = 2; /* ACB */
- cam->params.colourBalance.redGain = 32;
- cam->params.colourBalance.greenGain = 6;
- cam->params.colourBalance.blueGain = 92;
- cam->params.apcor.gain1 = 0x18;
- cam->params.apcor.gain2 = 0x16;
- cam->params.apcor.gain4 = 0x24;
- cam->params.apcor.gain8 = 0x34;
- cam->params.flickerControl.flickerMode = 0;
- cam->params.flickerControl.disabled = 1;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->params.flickerControl.allowableOverExposure =
- -find_over_exposure(cam->params.colourParams.brightness);
- cam->params.vlOffset.gain1 = 20;
- cam->params.vlOffset.gain2 = 24;
- cam->params.vlOffset.gain4 = 26;
- cam->params.vlOffset.gain8 = 26;
- cam->params.compressionParams.hysteresis = 3;
- cam->params.compressionParams.threshMax = 11;
- cam->params.compressionParams.smallStep = 1;
- cam->params.compressionParams.largeStep = 3;
- cam->params.compressionParams.decimationHysteresis = 2;
- cam->params.compressionParams.frDiffStepThresh = 5;
- cam->params.compressionParams.qDiffStepThresh = 3;
- cam->params.compressionParams.decimationThreshMod = 2;
- /* End of default values from Software Developer's Guide */
-
- cam->transfer_rate = 0;
- cam->exposure_status = EXPOSURE_NORMAL;
-
- /* Set Sensor FPS to 15fps. This seems better than 30fps
- * for indoor lighting. */
- cam->params.sensorFps.divisor = 1;
- cam->params.sensorFps.baserate = 1;
-
- cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
- cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
-
- cam->params.format.subSample = SUBSAMPLE_422;
- cam->params.format.yuvOrder = YUVORDER_YUYV;
-
- cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
- cam->params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_QUALITY;
- cam->params.compressionTarget.targetFR = 15; /* From windows driver */
- cam->params.compressionTarget.targetQ = 5; /* From windows driver */
-
- cam->params.qx3.qx3_detected = 0;
- cam->params.qx3.toplight = 0;
- cam->params.qx3.bottomlight = 0;
- cam->params.qx3.button = 0;
- cam->params.qx3.cradled = 0;
-
- cam->video_size = VIDEOSIZE_CIF;
-
- cam->vp.colour = 32768; /* 50% */
- cam->vp.hue = 32768; /* 50% */
- cam->vp.brightness = 32768; /* 50% */
- cam->vp.contrast = 32768; /* 50% */
- cam->vp.whiteness = 0; /* not used -> grayscale only */
- cam->vp.depth = 24; /* to be set by user */
- cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
-
- cam->vc.x = 0;
- cam->vc.y = 0;
- cam->vc.width = 0;
- cam->vc.height = 0;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- set_vw_size(cam);
- cam->vw.chromakey = 0;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
- cam->vw.clips = NULL;
-
- cam->cmd_queue = COMMAND_NONE;
- cam->first_frame = 1;
-
- return;
-}
-
-/* initialize cam_data structure */
-static void init_camera_struct(struct cam_data *cam,
- struct cpia_camera_ops *ops )
-{
- int i;
-
- /* Default everything to 0 */
- memset(cam, 0, sizeof(struct cam_data));
-
- cam->ops = ops;
- mutex_init(&cam->param_lock);
- mutex_init(&cam->busy_lock);
-
- reset_camera_struct(cam);
-
- cam->proc_entry = NULL;
-
- memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
- video_set_drvdata(&cam->vdev, cam);
-
- cam->curframe = 0;
- for (i = 0; i < FRAME_NUM; i++) {
- cam->frame[i].width = 0;
- cam->frame[i].height = 0;
- cam->frame[i].state = FRAME_UNUSED;
- cam->frame[i].data = NULL;
- }
- cam->decompressed_frame.width = 0;
- cam->decompressed_frame.height = 0;
- cam->decompressed_frame.state = FRAME_UNUSED;
- cam->decompressed_frame.data = NULL;
-}
-
-struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
-{
- struct cam_data *camera;
-
- if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
- return NULL;
-
-
- init_camera_struct( camera, ops );
- camera->lowlevel_data = lowlevel;
-
- /* register v4l device */
- if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- kfree(camera);
- printk(KERN_DEBUG "video_register_device failed\n");
- return NULL;
- }
-
- /* get version information from camera: open/reset/close */
-
- /* open cpia */
- if (camera->ops->open(camera->lowlevel_data))
- return camera;
-
- /* reset the camera */
- if (reset_camera(camera) != 0) {
- camera->ops->close(camera->lowlevel_data);
- return camera;
- }
-
- /* close cpia */
- camera->ops->close(camera->lowlevel_data);
-
-#ifdef CONFIG_PROC_FS
- create_proc_cpia_cam(camera);
-#endif
-
- printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
- camera->params.version.firmwareVersion,
- camera->params.version.firmwareRevision,
- camera->params.version.vcVersion,
- camera->params.version.vcRevision);
- printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
- camera->params.pnpID.vendor,
- camera->params.pnpID.product,
- camera->params.pnpID.deviceRevision);
- printk(KERN_INFO " VP-Version: %d.%d %04x\n",
- camera->params.vpVersion.vpVersion,
- camera->params.vpVersion.vpRevision,
- camera->params.vpVersion.cameraHeadID);
-
- return camera;
-}
-
-void cpia_unregister_camera(struct cam_data *cam)
-{
- DBG("unregistering video\n");
- video_unregister_device(&cam->vdev);
- if (cam->open_count) {
- put_cam(cam->ops);
- DBG("camera open -- setting ops to NULL\n");
- cam->ops = NULL;
- }
-
-#ifdef CONFIG_PROC_FS
- DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev));
- destroy_proc_cpia_cam(cam);
-#endif
- if (!cam->open_count) {
- DBG("freeing camera\n");
- kfree(cam);
- }
-}
-
-static int __init cpia_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
- CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
-
- printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
- "allowed, it is disabled by default now. Users should fix the "
- "applications in case they don't work without conversion "
- "reenabled by setting the 'colorspace_conv' module "
- "parameter to 1\n");
-
-#ifdef CONFIG_PROC_FS
- proc_cpia_create();
-#endif
-
- return 0;
-}
-
-static void __exit cpia_exit(void)
-{
-#ifdef CONFIG_PROC_FS
- proc_cpia_destroy();
-#endif
-}
-
-module_init(cpia_init);
-module_exit(cpia_exit);
-
-/* Exported symbols for modules. */
-
-EXPORT_SYMBOL(cpia_register_camera);
-EXPORT_SYMBOL(cpia_unregister_camera);
diff --git a/drivers/staging/cpia/cpia.h b/drivers/staging/cpia/cpia.h
deleted file mode 100644
index 8f0cfee4b8a1..000000000000
--- a/drivers/staging/cpia/cpia.h
+++ /dev/null
@@ -1,432 +0,0 @@
-#ifndef cpia_h
-#define cpia_h
-
-/*
- * CPiA Parallel Port Video4Linux driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * (C) Copyright 1999 Bas Huisman,
- * Peter Pregler,
- * Scott J. Bertin,
- * VLSI Vision 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#define CPIA_MAJ_VER 1
-#define CPIA_MIN_VER 2
-#define CPIA_PATCH_VER 3
-
-#define CPIA_PP_MAJ_VER CPIA_MAJ_VER
-#define CPIA_PP_MIN_VER CPIA_MIN_VER
-#define CPIA_PP_PATCH_VER CPIA_PATCH_VER
-
-#define CPIA_USB_MAJ_VER CPIA_MAJ_VER
-#define CPIA_USB_MIN_VER CPIA_MIN_VER
-#define CPIA_USB_PATCH_VER CPIA_PATCH_VER
-
-#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
-#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
-
-#ifdef __KERNEL__
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-
-struct cpia_camera_ops
-{
- /* open sets privdata to point to structure for this camera.
- * Returns negative value on error, otherwise 0.
- */
- int (*open)(void *privdata);
-
- /* Registers callback function cb to be called with cbdata
- * when an image is ready. If cb is NULL, only single image grabs
- * should be used. cb should immediately call streamRead to read
- * the data or data may be lost. Returns negative value on error,
- * otherwise 0.
- */
- int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
- void *cbdata);
-
- /* transferCmd sends commands to the camera. command MUST point to
- * an 8 byte buffer in kernel space. data can be NULL if no extra
- * data is needed. The size of the data is given by the last 2
- * bytes of command. data must also point to memory in kernel space.
- * Returns negative value on error, otherwise 0.
- */
- int (*transferCmd)(void *privdata, u8 *command, u8 *data);
-
- /* streamStart initiates stream capture mode.
- * Returns negative value on error, otherwise 0.
- */
- int (*streamStart)(void *privdata);
-
- /* streamStop terminates stream capture mode.
- * Returns negative value on error, otherwise 0.
- */
- int (*streamStop)(void *privdata);
-
- /* streamRead reads a frame from the camera. buffer points to a
- * buffer large enough to hold a complete frame in kernel space.
- * noblock indicates if this should be a non blocking read.
- * Returns the number of bytes read, or negative value on error.
- */
- int (*streamRead)(void *privdata, u8 *buffer, int noblock);
-
- /* close disables the device until open() is called again.
- * Returns negative value on error, otherwise 0.
- */
- int (*close)(void *privdata);
-
- /* If wait_for_stream_ready is non-zero, wait until the streamState
- * is STREAM_READY before calling streamRead.
- */
- int wait_for_stream_ready;
-
- /*
- * Used to maintain lowlevel module usage counts
- */
- struct module *owner;
-};
-
-struct cpia_frame {
- u8 *data;
- int count;
- int width;
- int height;
- volatile int state;
-};
-
-struct cam_params {
- struct {
- u8 firmwareVersion;
- u8 firmwareRevision;
- u8 vcVersion;
- u8 vcRevision;
- } version;
- struct {
- u16 vendor;
- u16 product;
- u16 deviceRevision;
- } pnpID;
- struct {
- u8 vpVersion;
- u8 vpRevision;
- u16 cameraHeadID;
- } vpVersion;
- struct {
- u8 systemState;
- u8 grabState;
- u8 streamState;
- u8 fatalError;
- u8 cmdError;
- u8 debugFlags;
- u8 vpStatus;
- u8 errorCode;
- } status;
- struct {
- u8 brightness;
- u8 contrast;
- u8 saturation;
- } colourParams;
- struct {
- u8 gainMode;
- u8 expMode;
- u8 compMode;
- u8 centreWeight;
- u8 gain;
- u8 fineExp;
- u8 coarseExpLo;
- u8 coarseExpHi;
- u8 redComp;
- u8 green1Comp;
- u8 green2Comp;
- u8 blueComp;
- } exposure;
- struct {
- u8 balanceMode;
- u8 redGain;
- u8 greenGain;
- u8 blueGain;
- } colourBalance;
- struct {
- u8 divisor;
- u8 baserate;
- } sensorFps;
- struct {
- u8 gain1;
- u8 gain2;
- u8 gain4;
- u8 gain8;
- } apcor;
- struct {
- u8 disabled;
- u8 flickerMode;
- u8 coarseJump;
- int allowableOverExposure;
- } flickerControl;
- struct {
- u8 gain1;
- u8 gain2;
- u8 gain4;
- u8 gain8;
- } vlOffset;
- struct {
- u8 mode;
- u8 decimation;
- } compression;
- struct {
- u8 frTargeting;
- u8 targetFR;
- u8 targetQ;
- } compressionTarget;
- struct {
- u8 yThreshold;
- u8 uvThreshold;
- } yuvThreshold;
- struct {
- u8 hysteresis;
- u8 threshMax;
- u8 smallStep;
- u8 largeStep;
- u8 decimationHysteresis;
- u8 frDiffStepThresh;
- u8 qDiffStepThresh;
- u8 decimationThreshMod;
- } compressionParams;
- struct {
- u8 videoSize; /* CIF/QCIF */
- u8 subSample;
- u8 yuvOrder;
- } format;
- struct { /* Intel QX3 specific data */
- u8 qx3_detected; /* a QX3 is present */
- u8 toplight; /* top light lit , R/W */
- u8 bottomlight; /* bottom light lit, R/W */
- u8 button; /* snapshot button pressed (R/O) */
- u8 cradled; /* microscope is in cradle (R/O) */
- } qx3;
- struct {
- u8 colStart; /* skip first 8*colStart pixels */
- u8 colEnd; /* finish at 8*colEnd pixels */
- u8 rowStart; /* skip first 4*rowStart lines */
- u8 rowEnd; /* finish at 4*rowEnd lines */
- } roi;
- u8 ecpTiming;
- u8 streamStartLine;
-};
-
-enum v4l_camstates {
- CPIA_V4L_IDLE = 0,
- CPIA_V4L_ERROR,
- CPIA_V4L_COMMAND,
- CPIA_V4L_GRABBING,
- CPIA_V4L_STREAMING,
- CPIA_V4L_STREAMING_PAUSED,
-};
-
-#define FRAME_NUM 2 /* double buffering for now */
-
-struct cam_data {
- struct list_head cam_data_list;
-
- struct mutex busy_lock; /* guard against SMP multithreading */
- struct cpia_camera_ops *ops; /* lowlevel driver operations */
- void *lowlevel_data; /* private data for lowlevel driver */
- u8 *raw_image; /* buffer for raw image data */
- struct cpia_frame decompressed_frame;
- /* buffer to hold decompressed frame */
- int image_size; /* sizeof last decompressed image */
- int open_count; /* # of process that have camera open */
-
- /* camera status */
- int fps; /* actual fps reported by the camera */
- int transfer_rate; /* transfer rate from camera in kB/s */
- u8 mainsFreq; /* for flicker control */
-
- /* proc interface */
- struct mutex param_lock; /* params lock for this camera */
- struct cam_params params; /* camera settings */
- struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
-
- /* v4l */
- int video_size; /* VIDEO_SIZE_ */
- volatile enum v4l_camstates camstate; /* v4l layer status */
- struct video_device vdev; /* v4l videodev */
- struct video_picture vp; /* v4l camera settings */
- struct video_window vw; /* v4l capture area */
- struct video_capture vc; /* v4l subcapture area */
-
- /* mmap interface */
- int curframe; /* the current frame to grab into */
- u8 *frame_buf; /* frame buffer data */
- struct cpia_frame frame[FRAME_NUM];
- /* FRAME_NUM-buffering, so we need a array */
-
- int first_frame;
- int mmap_kludge; /* 'wrong' byte order for mmap */
- volatile u32 cmd_queue; /* queued commands */
- int exposure_status; /* EXPOSURE_* */
- int exposure_count; /* number of frames at this status */
-};
-
-/* cpia_register_camera is called by low level driver for each camera.
- * A unique camera number is returned, or a negative value on error */
-struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
-
-/* cpia_unregister_camera is called by low level driver when a camera
- * is removed. This must not fail. */
-void cpia_unregister_camera(struct cam_data *cam);
-
-/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
- * one byte 16bit DMA alignment
- */
-#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
-
-/* constant value's */
-#define MAGIC_0 0x19
-#define MAGIC_1 0x68
-#define DATA_IN 0xC0
-#define DATA_OUT 0x40
-#define VIDEOSIZE_QCIF 0 /* 176x144 */
-#define VIDEOSIZE_CIF 1 /* 352x288 */
-#define VIDEOSIZE_SIF 2 /* 320x240 */
-#define VIDEOSIZE_QSIF 3 /* 160x120 */
-#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */
-#define VIDEOSIZE_64_48 5
-#define VIDEOSIZE_128_96 6
-#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF
-#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF
-#define VIDEOSIZE_192_144 7
-#define VIDEOSIZE_224_168 8
-#define VIDEOSIZE_256_192 9
-#define VIDEOSIZE_288_216 10
-#define VIDEOSIZE_320_240 VIDEOSIZE_SIF
-#define VIDEOSIZE_352_288 VIDEOSIZE_CIF
-#define VIDEOSIZE_88_72 11 /* quarter CIF */
-#define SUBSAMPLE_420 0
-#define SUBSAMPLE_422 1
-#define YUVORDER_YUYV 0
-#define YUVORDER_UYVY 1
-#define NOT_COMPRESSED 0
-#define COMPRESSED 1
-#define NO_DECIMATION 0
-#define DECIMATION_ENAB 1
-#define EOI 0xff /* End Of Image */
-#define EOL 0xfd /* End Of Line */
-#define FRAME_HEADER_SIZE 64
-
-/* Image grab modes */
-#define CPIA_GRAB_SINGLE 0
-#define CPIA_GRAB_CONTINUOUS 1
-
-/* Compression parameters */
-#define CPIA_COMPRESSION_NONE 0
-#define CPIA_COMPRESSION_AUTO 1
-#define CPIA_COMPRESSION_MANUAL 2
-#define CPIA_COMPRESSION_TARGET_QUALITY 0
-#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
-
-/* Return offsets for GetCameraState */
-#define SYSTEMSTATE 0
-#define GRABSTATE 1
-#define STREAMSTATE 2
-#define FATALERROR 3
-#define CMDERROR 4
-#define DEBUGFLAGS 5
-#define VPSTATUS 6
-#define ERRORCODE 7
-
-/* SystemState */
-#define UNINITIALISED_STATE 0
-#define PASS_THROUGH_STATE 1
-#define LO_POWER_STATE 2
-#define HI_POWER_STATE 3
-#define WARM_BOOT_STATE 4
-
-/* GrabState */
-#define GRAB_IDLE 0
-#define GRAB_ACTIVE 1
-#define GRAB_DONE 2
-
-/* StreamState */
-#define STREAM_NOT_READY 0
-#define STREAM_READY 1
-#define STREAM_OPEN 2
-#define STREAM_PAUSED 3
-#define STREAM_FINISHED 4
-
-/* Fatal Error, CmdError, and DebugFlags */
-#define CPIA_FLAG 1
-#define SYSTEM_FLAG 2
-#define INT_CTRL_FLAG 4
-#define PROCESS_FLAG 8
-#define COM_FLAG 16
-#define VP_CTRL_FLAG 32
-#define CAPTURE_FLAG 64
-#define DEBUG_FLAG 128
-
-/* VPStatus */
-#define VP_STATE_OK 0x00
-
-#define VP_STATE_FAILED_VIDEOINIT 0x01
-#define VP_STATE_FAILED_AECACBINIT 0x02
-#define VP_STATE_AEC_MAX 0x04
-#define VP_STATE_ACB_BMAX 0x08
-
-#define VP_STATE_ACB_RMIN 0x10
-#define VP_STATE_ACB_GMIN 0x20
-#define VP_STATE_ACB_RMAX 0x40
-#define VP_STATE_ACB_GMAX 0x80
-
-/* default (minimum) compensation values */
-#define COMP_RED 220
-#define COMP_GREEN1 214
-#define COMP_GREEN2 COMP_GREEN1
-#define COMP_BLUE 230
-
-/* exposure status */
-#define EXPOSURE_VERY_LIGHT 0
-#define EXPOSURE_LIGHT 1
-#define EXPOSURE_NORMAL 2
-#define EXPOSURE_DARK 3
-#define EXPOSURE_VERY_DARK 4
-
-/* ErrorCode */
-#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
-#define ALOG(fmt,args...) printk(fmt, ##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
-
-#ifdef _CPIA_DEBUG_
-#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
-#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
-#else
-#define DBG(fmn,args...) do {} while(0)
-#endif
-
-#define DEB_BYTE(p)\
- DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
- (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
- (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
-
-#endif /* __KERNEL__ */
-
-#endif /* cpia_h */
diff --git a/drivers/staging/cpia/cpia_pp.c b/drivers/staging/cpia/cpia_pp.c
deleted file mode 100644
index f5604c16a092..000000000000
--- a/drivers/staging/cpia/cpia_pp.c
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * cpia_pp CPiA Parallel Port driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
- * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
- * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.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.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/parport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <linux/kmod.h>
-
-/* #define _CPIA_DEBUG_ define for verbose debug output */
-#include "cpia.h"
-
-static int cpia_pp_open(void *privdata);
-static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata);
-static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
-static int cpia_pp_streamStart(void *privdata);
-static int cpia_pp_streamStop(void *privdata);
-static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
-static int cpia_pp_close(void *privdata);
-
-
-#define ABOUT "Parallel port driver for Vision CPiA based cameras"
-
-#define PACKET_LENGTH 8
-
-/* Magic numbers for defining port-device mappings */
-#define PPCPIA_PARPORT_UNSPEC -4
-#define PPCPIA_PARPORT_AUTO -3
-#define PPCPIA_PARPORT_OFF -2
-#define PPCPIA_PARPORT_NONE -1
-
-static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
-static char *parport[PARPORT_MAX] = {NULL,};
-
-MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
-MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
-MODULE_LICENSE("GPL");
-
-module_param_array(parport, charp, NULL, 0);
-MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
-
-struct pp_cam_entry {
- struct pardevice *pdev;
- struct parport *port;
- struct work_struct cb_task;
- void (*cb_func)(void *cbdata);
- void *cb_data;
- int open_count;
- wait_queue_head_t wq_stream;
- /* image state flags */
- int image_ready; /* we got an interrupt */
- int image_complete; /* we have seen 4 EOI */
-
- int streaming; /* we are in streaming mode */
- int stream_irq;
-};
-
-static struct cpia_camera_ops cpia_pp_ops =
-{
- cpia_pp_open,
- cpia_pp_registerCallback,
- cpia_pp_transferCmd,
- cpia_pp_streamStart,
- cpia_pp_streamStop,
- cpia_pp_streamRead,
- cpia_pp_close,
- 1,
- THIS_MODULE
-};
-
-static LIST_HEAD(cam_list);
-static spinlock_t cam_list_lock_pp;
-
-/* FIXME */
-static void cpia_parport_enable_irq( struct parport *port ) {
- parport_enable_irq(port);
- mdelay(10);
- return;
-}
-
-static void cpia_parport_disable_irq( struct parport *port ) {
- parport_disable_irq(port);
- mdelay(10);
- return;
-}
-
-/* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility
- * Link Flag during negotiation */
-#define UPLOAD_FLAG 0x08
-#define NIBBLE_TRANSFER 0x01
-#define ECP_TRANSFER 0x03
-
-#define PARPORT_CHUNK_SIZE PAGE_SIZE
-
-
-static void cpia_pp_run_callback(struct work_struct *work)
-{
- void (*cb_func)(void *cbdata);
- void *cb_data;
- struct pp_cam_entry *cam;
-
- cam = container_of(work, struct pp_cam_entry, cb_task);
- cb_func = cam->cb_func;
- cb_data = cam->cb_data;
-
- cb_func(cb_data);
-}
-
-/****************************************************************************
- *
- * CPiA-specific low-level parport functions for nibble uploads
- *
- ***************************************************************************/
-/* CPiA nonstandard "Nibble" mode (no nDataAvail signal after each byte). */
-/* The standard kernel parport_ieee1284_read_nibble() fails with the CPiA... */
-
-static size_t cpia_read_nibble (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- /* adapted verbatim, with one change, from
- parport_ieee1284_read_nibble() in drivers/parport/ieee1284-ops.c */
-
- unsigned char *buf = buffer;
- int i;
- unsigned char byte = 0;
-
- len *= 2; /* in nibbles */
- for (i=0; i < len; i++) {
- unsigned char nibble;
-
- /* The CPiA firmware suppresses the use of nDataAvail (nFault LO)
- * after every second nibble to signal that more
- * data is available. (the total number of Bytes that
- * should be sent is known; if too few are received, an error
- * will be recorded after a timeout).
- * This is incompatible with parport_ieee1284_read_nibble(),
- * which expects to find nFault LO after every second nibble.
- */
-
- /* Solution: modify cpia_read_nibble to only check for
- * nDataAvail before the first nibble is sent.
- */
-
- /* Does the error line indicate end of data? */
- if (((i /*& 1*/) == 0) &&
- (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
- DBG("%s: No more nibble data (%d bytes)\n",
- port->name, i/2);
- goto end_of_data;
- }
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK, 0)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
- port->name, i/2);
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- break;
- }
-
-
- /* Read a nibble. */
- nibble = parport_read_status (port) >> 3;
- nibble &= ~8;
- if ((nibble & 0x10) == 0)
- nibble |= 8;
- nibble &= 0xf;
-
- /* Event 10: Set nAutoFd high. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 11\n",
- port->name);
- break;
- }
-
- if (i & 1) {
- /* Second nibble */
- byte |= nibble << 4;
- *buf++ = byte;
- } else
- byte = nibble;
- }
-
- if (i == len) {
- /* Read the last nibble without checking data avail. */
- if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
- end_of_data:
- /* Go to reverse idle phase. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- }
- else
- port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
- }
-
- return i/2;
-}
-
-/* CPiA nonstandard "Nibble Stream" mode (2 nibbles per cycle, instead of 1)
- * (See CPiA Data sheet p. 31)
- *
- * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a
- * nonstandard variant of nibble mode which allows the same (mediocre)
- * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable
- * parallel ports, but works also for non-TRISTATE-capable ports.
- * (Standard nibble mode only send 4 bits per cycle)
- *
- */
-
-static size_t cpia_read_nibble_stream(struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- int i;
- unsigned char *buf = buffer;
- int endseen = 0;
-
- for (i=0; i < len; i++) {
- unsigned char nibble[2], byte = 0;
- int j;
-
- /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */
- if (endseen > 3 )
- break;
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK, 0)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
- port->name, i/2);
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- break;
- }
-
- /* Read lower nibble */
- nibble[0] = parport_read_status (port) >>3;
-
- /* Event 10: Set nAutoFd high. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 11\n",
- port->name);
- break;
- }
-
- /* Read upper nibble */
- nibble[1] = parport_read_status (port) >>3;
-
- /* reassemble the byte */
- for (j = 0; j < 2 ; j++ ) {
- nibble[j] &= ~8;
- if ((nibble[j] & 0x10) == 0)
- nibble[j] |= 8;
- nibble[j] &= 0xf;
- }
- byte = (nibble[0] |(nibble[1] << 4));
- *buf++ = byte;
-
- if(byte == EOI)
- endseen++;
- else
- endseen = 0;
- }
- return i;
-}
-
-/****************************************************************************
- *
- * EndTransferMode
- *
- ***************************************************************************/
-static void EndTransferMode(struct pp_cam_entry *cam)
-{
- parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
-}
-
-/****************************************************************************
- *
- * ForwardSetup
- *
- ***************************************************************************/
-static int ForwardSetup(struct pp_cam_entry *cam)
-{
- int retry;
-
- /* The CPiA uses ECP protocol for Downloads from the Host to the camera.
- * This will be software-emulated if ECP hardware is not present
- */
-
- /* the usual camera maximum response time is 10ms, but after receiving
- * some commands, it needs up to 40ms. (Data Sheet p. 32)*/
-
- for(retry = 0; retry < 4; ++retry) {
- if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
- break;
- }
- mdelay(10);
- }
- if(retry == 4) {
- DBG("Unable to negotiate IEEE1284 ECP Download mode\n");
- return -1;
- }
- return 0;
-}
-/****************************************************************************
- *
- * ReverseSetup
- *
- ***************************************************************************/
-static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
-{
- int retry;
- int upload_mode, mode = IEEE1284_MODE_ECP;
- int transfer_mode = ECP_TRANSFER;
-
- if (!(cam->port->modes & PARPORT_MODE_ECP) &&
- !(cam->port->modes & PARPORT_MODE_TRISTATE)) {
- mode = IEEE1284_MODE_NIBBLE;
- transfer_mode = NIBBLE_TRANSFER;
- }
-
- upload_mode = mode;
- if(extensibility) mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK;
-
- /* the usual camera maximum response time is 10ms, but after
- * receiving some commands, it needs up to 40ms. */
-
- for(retry = 0; retry < 4; ++retry) {
- if(!parport_negotiate(cam->port, mode)) {
- break;
- }
- mdelay(10);
- }
- if(retry == 4) {
- if(extensibility)
- DBG("Unable to negotiate upload extensibility mode\n");
- else
- DBG("Unable to negotiate upload mode\n");
- return -1;
- }
- if(extensibility) cam->port->ieee1284.mode = upload_mode;
- return 0;
-}
-
-/****************************************************************************
- *
- * WritePacket
- *
- ***************************************************************************/
-static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
-{
- int retval=0;
- int size_written;
-
- if (packet == NULL) {
- return -EINVAL;
- }
- if (ForwardSetup(cam)) {
- DBG("Write failed in setup\n");
- return -EIO;
- }
- size_written = parport_write(cam->port, packet, size);
- if(size_written != size) {
- DBG("Write failed, wrote %d/%d\n", size_written, size);
- retval = -EIO;
- }
- EndTransferMode(cam);
- return retval;
-}
-
-/****************************************************************************
- *
- * ReadPacket
- *
- ***************************************************************************/
-static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
-{
- int retval=0;
-
- if (packet == NULL) {
- return -EINVAL;
- }
- if (ReverseSetup(cam, 0)) {
- return -EIO;
- }
-
- /* support for CPiA variant nibble reads */
- if(cam->port->ieee1284.mode == IEEE1284_MODE_NIBBLE) {
- if(cpia_read_nibble(cam->port, packet, size, 0) != size)
- retval = -EIO;
- } else {
- if(parport_read(cam->port, packet, size) != size)
- retval = -EIO;
- }
- EndTransferMode(cam);
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamStart
- *
- ***************************************************************************/
-static int cpia_pp_streamStart(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
- DBG("\n");
- cam->streaming=1;
- cam->image_ready=0;
- //if (ReverseSetup(cam,1)) return -EIO;
- if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamStop
- *
- ***************************************************************************/
-static int cpia_pp_streamStop(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
-
- DBG("\n");
- cam->streaming=0;
- cpia_parport_disable_irq(cam->port);
- //EndTransferMode(cam);
-
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamRead
- *
- ***************************************************************************/
-static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
-{
- int bytes_read;
-
- /* support for CPiA variant "nibble stream" reads */
- if(port->ieee1284.mode == IEEE1284_MODE_NIBBLE)
- bytes_read = cpia_read_nibble_stream(port,buffer,len,0);
- else {
- int new_bytes;
- for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
- new_bytes = parport_read(port, buffer+bytes_read,
- len-bytes_read);
- if(new_bytes < 0) break;
- }
- }
- return bytes_read;
-}
-
-static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
-{
- struct pp_cam_entry *cam = privdata;
- int read_bytes = 0;
- int i, endseen, block_size, new_bytes;
-
- if(cam == NULL) {
- DBG("Internal driver error: cam is NULL\n");
- return -EINVAL;
- }
- if(buffer == NULL) {
- DBG("Internal driver error: buffer is NULL\n");
- return -EINVAL;
- }
- //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
- if( cam->stream_irq ) {
- DBG("%d\n", cam->image_ready);
- cam->image_ready--;
- }
- cam->image_complete=0;
- if (0/*cam->streaming*/) {
- if(!cam->image_ready) {
- if(noblock) return -EWOULDBLOCK;
- interruptible_sleep_on(&cam->wq_stream);
- if( signal_pending(current) ) return -EINTR;
- DBG("%d\n", cam->image_ready);
- }
- } else {
- if (ReverseSetup(cam, 1)) {
- DBG("unable to ReverseSetup\n");
- return -EIO;
- }
- }
- endseen = 0;
- block_size = PARPORT_CHUNK_SIZE;
- while( !cam->image_complete ) {
- cond_resched();
-
- new_bytes = cpia_pp_read(cam->port, buffer, block_size );
- if( new_bytes <= 0 ) {
- break;
- }
- i=-1;
- while(++i<new_bytes && endseen<4) {
- if(*buffer==EOI) {
- endseen++;
- } else {
- endseen=0;
- }
- buffer++;
- }
- read_bytes += i;
- if( endseen==4 ) {
- cam->image_complete=1;
- break;
- }
- if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
- block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
- }
- }
- EndTransferMode(cam);
- return cam->image_complete ? read_bytes : -EIO;
-}
-/****************************************************************************
- *
- * cpia_pp_transferCmd
- *
- ***************************************************************************/
-static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
-{
- int err;
- int retval=0;
- int databytes;
- struct pp_cam_entry *cam = privdata;
-
- if(cam == NULL) {
- DBG("Internal driver error: cam is NULL\n");
- return -EINVAL;
- }
- if(command == NULL) {
- DBG("Internal driver error: command is NULL\n");
- return -EINVAL;
- }
- databytes = (((int)command[7])<<8) | command[6];
- if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
- DBG("Error writing command\n");
- return err;
- }
- if(command[0] == DATA_IN) {
- u8 buffer[8];
- if(data == NULL) {
- DBG("Internal driver error: data is NULL\n");
- return -EINVAL;
- }
- if((err = ReadPacket(cam, buffer, 8)) < 0) {
- DBG("Error reading command result\n");
- return err;
- }
- memcpy(data, buffer, databytes);
- } else if(command[0] == DATA_OUT) {
- if(databytes > 0) {
- if(data == NULL) {
- DBG("Internal driver error: data is NULL\n");
- retval = -EINVAL;
- } else {
- if((err=WritePacket(cam, data, databytes)) < 0){
- DBG("Error writing command data\n");
- return err;
- }
- }
- }
- } else {
- DBG("Unexpected first byte of command: %x\n", command[0]);
- retval = -EINVAL;
- }
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_open
- *
- ***************************************************************************/
-static int cpia_pp_open(void *privdata)
-{
- struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
-
- if (cam == NULL)
- return -EINVAL;
-
- if(cam->open_count == 0) {
- if (parport_claim(cam->pdev)) {
- DBG("failed to claim the port\n");
- return -EBUSY;
- }
- parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
- parport_data_forward(cam->port);
- parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
- udelay(50);
- parport_write_control(cam->port,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_INIT);
- }
-
- ++cam->open_count;
-
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_registerCallback
- *
- ***************************************************************************/
-static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
-{
- struct pp_cam_entry *cam = privdata;
- int retval = 0;
-
- if(cam->port->irq != PARPORT_IRQ_NONE) {
- cam->cb_func = cb;
- cam->cb_data = cbdata;
- INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
- } else {
- retval = -1;
- }
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_close
- *
- ***************************************************************************/
-static int cpia_pp_close(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
- if (--cam->open_count == 0) {
- parport_release(cam->pdev);
- }
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_register
- *
- ***************************************************************************/
-static int cpia_pp_register(struct parport *port)
-{
- struct pardevice *pdev = NULL;
- struct pp_cam_entry *cam;
- struct cam_data *cpia;
-
- if (!(port->modes & PARPORT_MODE_PCSPP)) {
- LOG("port is not supported by CPiA driver\n");
- return -ENXIO;
- }
-
- cam = kzalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
- if (cam == NULL) {
- LOG("failed to allocate camera structure\n");
- return -ENOMEM;
- }
-
- pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
- NULL, 0, cam);
-
- if (!pdev) {
- LOG("failed to parport_register_device\n");
- kfree(cam);
- return -ENXIO;
- }
-
- cam->pdev = pdev;
- cam->port = port;
- init_waitqueue_head(&cam->wq_stream);
-
- cam->streaming = 0;
- cam->stream_irq = 0;
-
- if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
- LOG("failed to cpia_register_camera\n");
- parport_unregister_device(pdev);
- kfree(cam);
- return -ENXIO;
- }
- spin_lock( &cam_list_lock_pp );
- list_add( &cpia->cam_data_list, &cam_list );
- spin_unlock( &cam_list_lock_pp );
-
- return 0;
-}
-
-static void cpia_pp_detach (struct parport *port)
-{
- struct list_head *tmp;
- struct cam_data *cpia = NULL;
- struct pp_cam_entry *cam;
-
- spin_lock( &cam_list_lock_pp );
- list_for_each (tmp, &cam_list) {
- cpia = list_entry(tmp, struct cam_data, cam_data_list);
- cam = (struct pp_cam_entry *) cpia->lowlevel_data;
- if (cam && cam->port->number == port->number) {
- list_del(&cpia->cam_data_list);
- break;
- }
- cpia = NULL;
- }
- spin_unlock( &cam_list_lock_pp );
-
- if (!cpia) {
- DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
- return;
- }
-
- cam = (struct pp_cam_entry *) cpia->lowlevel_data;
- cpia_unregister_camera(cpia);
- if(cam->open_count > 0)
- cpia_pp_close(cam);
- parport_unregister_device(cam->pdev);
- cpia->lowlevel_data = NULL;
- kfree(cam);
-}
-
-static void cpia_pp_attach (struct parport *port)
-{
- unsigned int i;
-
- switch (parport_nr[0])
- {
- case PPCPIA_PARPORT_UNSPEC:
- case PPCPIA_PARPORT_AUTO:
- if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
- port->probe_info[0].cmdset == NULL ||
- strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
- return;
-
- cpia_pp_register(port);
-
- break;
-
- default:
- for (i = 0; i < PARPORT_MAX; ++i) {
- if (port->number == parport_nr[i]) {
- cpia_pp_register(port);
- break;
- }
- }
- break;
- }
-}
-
-static struct parport_driver cpia_pp_driver = {
- .name = "cpia_pp",
- .attach = cpia_pp_attach,
- .detach = cpia_pp_detach,
-};
-
-static int __init cpia_pp_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
- CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
-
- if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
- printk(" disabled\n");
- return 0;
- }
-
- spin_lock_init( &cam_list_lock_pp );
-
- if (parport_register_driver (&cpia_pp_driver)) {
- LOG ("unable to register with parport\n");
- return -EIO;
- }
- return 0;
-}
-
-static int __init cpia_init(void)
-{
- if (parport[0]) {
- /* The user gave some parameters. Let's see what they were. */
- if (!strncmp(parport[0], "auto", 4)) {
- parport_nr[0] = PPCPIA_PARPORT_AUTO;
- } else {
- int n;
- for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
- if (!strncmp(parport[n], "none", 4)) {
- parport_nr[n] = PPCPIA_PARPORT_NONE;
- } else {
- char *ep;
- unsigned long r = simple_strtoul(parport[n], &ep, 0);
- if (ep != parport[n]) {
- parport_nr[n] = r;
- } else {
- LOG("bad port specifier `%s'\n", parport[n]);
- return -ENODEV;
- }
- }
- }
- }
- }
- return cpia_pp_init();
-}
-
-static void __exit cpia_cleanup(void)
-{
- parport_unregister_driver(&cpia_pp_driver);
- return;
-}
-
-module_init(cpia_init);
-module_exit(cpia_cleanup);
diff --git a/drivers/staging/cpia/cpia_usb.c b/drivers/staging/cpia/cpia_usb.c
deleted file mode 100644
index 58d193ff591c..000000000000
--- a/drivers/staging/cpia/cpia_usb.c
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- * cpia_usb CPiA USB driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * Copyright (C) 1999 Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
- * Copyright (C) 1999, 2000 Johannes Erdfelt <johannes@erdfelt.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.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/usb.h>
-
-#include "cpia.h"
-
-#define USB_REQ_CPIA_GRAB_FRAME 0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
-#define WAIT_FOR_NEXT_FRAME 0
-#define FORCE_FRAME_UPLOAD 1
-
-#define FRAMES_PER_DESC 10
-#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
-#define CPIA_NUMSBUF 2
-#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
-
-struct cpia_sbuf {
- char *data;
- struct urb *urb;
-};
-
-#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
-enum framebuf_status {
- FRAME_EMPTY,
- FRAME_READING,
- FRAME_READY,
- FRAME_ERROR,
-};
-
-struct framebuf {
- int length;
- enum framebuf_status status;
- u8 data[FRAMEBUF_LEN];
- struct framebuf *next;
-};
-
-struct usb_cpia {
- /* Device structure */
- struct usb_device *dev;
-
- unsigned char iface;
- wait_queue_head_t wq_stream;
-
- int cursbuf; /* Current receiving sbuf */
- struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
-
- int streaming;
- int open;
- int present;
- struct framebuf *buffers[3];
- struct framebuf *curbuff, *workbuff;
-};
-
-static int cpia_usb_open(void *privdata);
-static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata);
-static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
-static int cpia_usb_streamStart(void *privdata);
-static int cpia_usb_streamStop(void *privdata);
-static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
-static int cpia_usb_close(void *privdata);
-
-#define ABOUT "USB driver for Vision CPiA based cameras"
-
-static struct cpia_camera_ops cpia_usb_ops = {
- cpia_usb_open,
- cpia_usb_registerCallback,
- cpia_usb_transferCmd,
- cpia_usb_streamStart,
- cpia_usb_streamStop,
- cpia_usb_streamRead,
- cpia_usb_close,
- 0,
- THIS_MODULE
-};
-
-static LIST_HEAD(cam_list);
-static spinlock_t cam_list_lock_usb;
-
-static void cpia_usb_complete(struct urb *urb)
-{
- int i;
- char *cdata;
- struct usb_cpia *ucpia;
-
- if (!urb || !urb->context)
- return;
-
- ucpia = (struct usb_cpia *) urb->context;
-
- if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
- return;
-
- if (ucpia->workbuff->status == FRAME_EMPTY) {
- ucpia->workbuff->status = FRAME_READING;
- ucpia->workbuff->length = 0;
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st)
- printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
-
- if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
- printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
- return;
- }
-
- if (n) {
- if ((ucpia->workbuff->length > 0) ||
- (0x19 == cdata[0] && 0x68 == cdata[1])) {
- memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
- ucpia->workbuff->length += n;
- } else
- DBG("Ignoring packet!\n");
- } else {
- if (ucpia->workbuff->length > 4 &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
- ucpia->workbuff->status = FRAME_READY;
- ucpia->curbuff = ucpia->workbuff;
- ucpia->workbuff = ucpia->workbuff->next;
- ucpia->workbuff->status = FRAME_EMPTY;
- ucpia->workbuff->length = 0;
-
- if (waitqueue_active(&ucpia->wq_stream))
- wake_up_interruptible(&ucpia->wq_stream);
- }
- }
- }
-
- /* resubmit */
- urb->dev = ucpia->dev;
- if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
-}
-
-static int cpia_usb_open(void *privdata)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
- struct urb *urb;
- int ret, retval = 0, fx, err;
-
- if (!ucpia)
- return -EINVAL;
-
- ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ucpia->sbuf[0].data)
- return -EINVAL;
-
- ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ucpia->sbuf[1].data) {
- retval = -EINVAL;
- goto error_0;
- }
-
- ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
- if (ret < 0) {
- printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
- retval = -EBUSY;
- goto error_1;
- }
-
- ucpia->buffers[0]->status = FRAME_EMPTY;
- ucpia->buffers[0]->length = 0;
- ucpia->buffers[1]->status = FRAME_EMPTY;
- ucpia->buffers[1]->length = 0;
- ucpia->buffers[2]->status = FRAME_EMPTY;
- ucpia->buffers[2]->length = 0;
- ucpia->curbuff = ucpia->buffers[0];
- ucpia->workbuff = ucpia->buffers[1];
-
- /* We double buffer the Iso lists, and also know the polling
- * interval is every frame (1 == (1 << (bInterval -1))).
- */
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
- retval = -ENOMEM;
- goto error_1;
- }
-
- ucpia->sbuf[0].urb = urb;
- urb->dev = ucpia->dev;
- urb->context = ucpia;
- urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ucpia->sbuf[0].data;
- urb->complete = cpia_usb_complete;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->interval = 1;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 1\n");
- retval = -ENOMEM;
- goto error_urb0;
- }
-
- ucpia->sbuf[1].urb = urb;
- urb->dev = ucpia->dev;
- urb->context = ucpia;
- urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ucpia->sbuf[1].data;
- urb->complete = cpia_usb_complete;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->interval = 1;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- /* queue the ISO urbs, and resubmit in the completion handler */
- err = usb_submit_urb(ucpia->sbuf[0].urb, GFP_KERNEL);
- if (err) {
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
- err);
- goto error_urb1;
- }
- err = usb_submit_urb(ucpia->sbuf[1].urb, GFP_KERNEL);
- if (err) {
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
- err);
- goto error_urb1;
- }
-
- ucpia->streaming = 1;
- ucpia->open = 1;
-
- return 0;
-
-error_urb1: /* free urb 1 */
- usb_free_urb(ucpia->sbuf[1].urb);
- ucpia->sbuf[1].urb = NULL;
-error_urb0: /* free urb 0 */
- usb_free_urb(ucpia->sbuf[0].urb);
- ucpia->sbuf[0].urb = NULL;
-error_1:
- kfree (ucpia->sbuf[1].data);
- ucpia->sbuf[1].data = NULL;
-error_0:
- kfree (ucpia->sbuf[0].data);
- ucpia->sbuf[0].data = NULL;
-
- return retval;
-}
-
-//
-// convenience functions
-//
-
-/****************************************************************************
- *
- * WritePacket
- *
- ***************************************************************************/
-static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
-{
- if (!packet)
- return -EINVAL;
-
- return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- packet[1] + (packet[0] << 8),
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, 1000);
-}
-
-/****************************************************************************
- *
- * ReadPacket
- *
- ***************************************************************************/
-static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
-{
- if (!packet || size <= 0)
- return -EINVAL;
-
- return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- packet[1] + (packet[0] << 8),
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, 1000);
-}
-
-static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
-{
- int err = 0;
- int databytes;
- struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
- struct usb_device *udev = ucpia->dev;
-
- if (!udev) {
- DBG("Internal driver error: udev is NULL\n");
- return -EINVAL;
- }
-
- if (!command) {
- DBG("Internal driver error: command is NULL\n");
- return -EINVAL;
- }
-
- databytes = (((int)command[7])<<8) | command[6];
-
- if (command[0] == DATA_IN) {
- u8 buffer[8];
-
- if (!data) {
- DBG("Internal driver error: data is NULL\n");
- return -EINVAL;
- }
-
- err = ReadPacket(udev, command, buffer, 8);
- if (err < 0)
- return err;
-
- memcpy(data, buffer, databytes);
- } else if(command[0] == DATA_OUT)
- WritePacket(udev, command, data, databytes);
- else {
- DBG("Unexpected first byte of command: %x\n", command[0]);
- err = -EINVAL;
- }
-
- return 0;
-}
-
-static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamStart(void *privdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamStop(void *privdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
- struct framebuf *mybuff;
-
- if (!ucpia || !ucpia->present)
- return -1;
-
- if (ucpia->curbuff->status != FRAME_READY)
- interruptible_sleep_on(&ucpia->wq_stream);
- else
- DBG("Frame already waiting!\n");
-
- mybuff = ucpia->curbuff;
-
- if (!mybuff)
- return -1;
-
- if (mybuff->status != FRAME_READY || mybuff->length < 4) {
- DBG("Something went wrong!\n");
- return -1;
- }
-
- memcpy(frame, mybuff->data, mybuff->length);
- mybuff->status = FRAME_EMPTY;
-
-/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
-/* mybuff->length, frame[0], frame[1], */
-/* frame[mybuff->length-4], frame[mybuff->length-3], */
-/* frame[mybuff->length-2], frame[mybuff->length-1]); */
-
- return mybuff->length;
-}
-
-static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
-{
- if (!ucpia->streaming)
- return;
-
- ucpia->streaming = 0;
-
- /* Set packet size to 0 */
- if (try) {
- int ret;
-
- ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
- if (ret < 0) {
- printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
- return;
- }
- }
-
- /* Unschedule all of the iso td's */
- if (ucpia->sbuf[1].urb) {
- usb_kill_urb(ucpia->sbuf[1].urb);
- usb_free_urb(ucpia->sbuf[1].urb);
- ucpia->sbuf[1].urb = NULL;
- }
-
- kfree(ucpia->sbuf[1].data);
- ucpia->sbuf[1].data = NULL;
-
- if (ucpia->sbuf[0].urb) {
- usb_kill_urb(ucpia->sbuf[0].urb);
- usb_free_urb(ucpia->sbuf[0].urb);
- ucpia->sbuf[0].urb = NULL;
- }
-
- kfree(ucpia->sbuf[0].data);
- ucpia->sbuf[0].data = NULL;
-}
-
-static int cpia_usb_close(void *privdata)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
-
- if(!ucpia)
- return -ENODEV;
-
- ucpia->open = 0;
-
- /* ucpia->present = 0 protects against trying to reset the
- * alt setting if camera is physically disconnected while open */
- cpia_usb_free_resources(ucpia, ucpia->present);
-
- return 0;
-}
-
-/* Probing and initializing */
-
-static int cpia_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_host_interface *interface;
- struct usb_cpia *ucpia;
- struct cam_data *cam;
- int ret;
-
- /* A multi-config CPiA camera? */
- if (udev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- interface = intf->cur_altsetting;
-
- printk(KERN_INFO "USB CPiA camera found\n");
-
- ucpia = kzalloc(sizeof(*ucpia), GFP_KERNEL);
- if (!ucpia) {
- printk(KERN_ERR "couldn't kmalloc cpia struct\n");
- return -ENOMEM;
- }
-
- ucpia->dev = udev;
- ucpia->iface = interface->desc.bInterfaceNumber;
- init_waitqueue_head(&ucpia->wq_stream);
-
- ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
- if (!ucpia->buffers[0]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
- goto fail_alloc_0;
- }
-
- ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
- if (!ucpia->buffers[1]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
- goto fail_alloc_1;
- }
-
- ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
- if (!ucpia->buffers[2]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
- goto fail_alloc_2;
- }
-
- ucpia->buffers[0]->next = ucpia->buffers[1];
- ucpia->buffers[1]->next = ucpia->buffers[2];
- ucpia->buffers[2]->next = ucpia->buffers[0];
-
- ret = usb_set_interface(udev, ucpia->iface, 0);
- if (ret < 0) {
- printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
- /* goto fail_all; */
- }
-
- /* Before register_camera, important */
- ucpia->present = 1;
-
- cam = cpia_register_camera(&cpia_usb_ops, ucpia);
- if (!cam) {
- LOG("failed to cpia_register_camera\n");
- goto fail_all;
- }
-
- spin_lock( &cam_list_lock_usb );
- list_add( &cam->cam_data_list, &cam_list );
- spin_unlock( &cam_list_lock_usb );
-
- usb_set_intfdata(intf, cam);
- return 0;
-
-fail_all:
- vfree(ucpia->buffers[2]);
- ucpia->buffers[2] = NULL;
-fail_alloc_2:
- vfree(ucpia->buffers[1]);
- ucpia->buffers[1] = NULL;
-fail_alloc_1:
- vfree(ucpia->buffers[0]);
- ucpia->buffers[0] = NULL;
-fail_alloc_0:
- kfree(ucpia);
- return -EIO;
-}
-
-static void cpia_disconnect(struct usb_interface *intf);
-
-static struct usb_device_id cpia_id_table [] = {
- { USB_DEVICE(0x0553, 0x0002) },
- { USB_DEVICE(0x0813, 0x0001) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, cpia_id_table);
-MODULE_LICENSE("GPL");
-
-
-static struct usb_driver cpia_driver = {
- .name = "cpia",
- .probe = cpia_probe,
- .disconnect = cpia_disconnect,
- .id_table = cpia_id_table,
-};
-
-static void cpia_disconnect(struct usb_interface *intf)
-{
- struct cam_data *cam = usb_get_intfdata(intf);
- struct usb_cpia *ucpia;
-
- usb_set_intfdata(intf, NULL);
- if (!cam)
- return;
-
- ucpia = (struct usb_cpia *) cam->lowlevel_data;
- spin_lock( &cam_list_lock_usb );
- list_del(&cam->cam_data_list);
- spin_unlock( &cam_list_lock_usb );
-
- ucpia->present = 0;
-
- cpia_unregister_camera(cam);
- if(ucpia->open)
- cpia_usb_close(cam->lowlevel_data);
-
- ucpia->curbuff->status = FRAME_ERROR;
-
- if (waitqueue_active(&ucpia->wq_stream))
- wake_up_interruptible(&ucpia->wq_stream);
-
- ucpia->curbuff = ucpia->workbuff = NULL;
-
- vfree(ucpia->buffers[2]);
- ucpia->buffers[2] = NULL;
-
- vfree(ucpia->buffers[1]);
- ucpia->buffers[1] = NULL;
-
- vfree(ucpia->buffers[0]);
- ucpia->buffers[0] = NULL;
-
- cam->lowlevel_data = NULL;
- kfree(ucpia);
-}
-
-static int __init usb_cpia_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
- CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
-
- spin_lock_init(&cam_list_lock_usb);
- return usb_register(&cpia_driver);
-}
-
-static void __exit usb_cpia_cleanup(void)
-{
- usb_deregister(&cpia_driver);
-}
-
-
-module_init (usb_cpia_init);
-module_exit (usb_cpia_cleanup);
-
diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig
new file mode 100644
index 000000000000..43b1cc0a50a5
--- /dev/null
+++ b/drivers/staging/cptm1217/Kconfig
@@ -0,0 +1,12 @@
+config TOUCHSCREEN_CLEARPAD_TM1217
+ tristate "Synaptics Clearpad TM1217"
+ depends on I2C
+ depends on GPIOLIB
+ depends on INPUT
+ help
+ Say Y here if you have a Synaptics Clearpad TM1217 Controller
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called clearpad_tm1217.
diff --git a/drivers/staging/cptm1217/Makefile b/drivers/staging/cptm1217/Makefile
new file mode 100644
index 000000000000..8961fafa80e7
--- /dev/null
+++ b/drivers/staging/cptm1217/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += clearpad_tm1217.o
+
diff --git a/drivers/staging/cptm1217/TODO b/drivers/staging/cptm1217/TODO
new file mode 100644
index 000000000000..303922465e4d
--- /dev/null
+++ b/drivers/staging/cptm1217/TODO
@@ -0,0 +1,5 @@
+- Wait for the official upstream general clearpad drivers as promised over
+ the past few months
+- Merge any device support needed from this driver into it
+- Delete this driver
+
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
new file mode 100644
index 000000000000..76e4b782d2fb
--- /dev/null
+++ b/drivers/staging/cptm1217/clearpad_tm1217.c
@@ -0,0 +1,675 @@
+/*
+ * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad
+ * TM1217 controller
+ *
+ * Copyright (C) 2008 Intel 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; ifnot, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "cp_tm1217.h"
+
+#define CPTM1217_DEVICE_NAME "cptm1217"
+#define CPTM1217_DRIVER_NAME CPTM1217_DEVICE_NAME
+
+#define MAX_TOUCH_SUPPORTED 2
+#define TOUCH_SUPPORTED 1
+#define SAMPLING_FREQ 80 /* Frequency in HZ */
+#define DELAY_BTWIN_SAMPLE (1000 / SAMPLING_FREQ)
+#define WAIT_FOR_RESPONSE 5 /* 5msec just works */
+#define MAX_RETRIES 5 /* As above */
+#define INCREMENTAL_DELAY 5 /* As above */
+
+/* Regster Definitions */
+#define TMA1217_DEV_STATUS 0x13 /* Device Status */
+#define TMA1217_INT_STATUS 0x14 /* Interrupt Status */
+
+/* Controller can detect upto 2 possible finger touches.
+ * Each finger touch provides 12 bit X Y co-ordinates, the values are split
+ * across 2 registers, and an 8 bit Z value */
+#define TMA1217_FINGER_STATE 0x18 /* Finger State */
+#define TMA1217_FINGER1_X_HIGHER8 0x19 /* Higher 8 bit of X coordinate */
+#define TMA1217_FINGER1_Y_HIGHER8 0x1A /* Higher 8 bit of Y coordinate */
+#define TMA1217_FINGER1_XY_LOWER4 0x1B /* Lower 4 bits of X and Y */
+#define TMA1217_FINGER1_Z_VALUE 0x1D /* 8 bit Z value for finger 1 */
+#define TMA1217_FINGER2_X_HIGHER8 0x1E /* Higher 8 bit of X coordinate */
+#define TMA1217_FINGER2_Y_HIGHER8 0x1F /* Higher 8 bit of Y coordinate */
+#define TMA1217_FINGER2_XY_LOWER4 0x20 /* Lower 4 bits of X and Y */
+#define TMA1217_FINGER2_Z_VALUE 0x22 /* 8 bit Z value for finger 2 */
+#define TMA1217_DEVICE_CTRL 0x23 /* Device Control */
+#define TMA1217_INTERRUPT_ENABLE 0x24 /* Interrupt Enable */
+#define TMA1217_REPORT_MODE 0x2B /* Reporting Mode */
+#define TMA1217_MAX_X_LOWER8 0x31 /* Bit 0-7 for Max X */
+#define TMA1217_MAX_X_HIGHER4 0x32 /* Bit 8-11 for Max X */
+#define TMA1217_MAX_Y_LOWER8 0x33 /* Bit 0-7 for Max Y */
+#define TMA1217_MAX_Y_HIGHER4 0x34 /* Bit 8-11 for Max Y */
+#define TMA1217_DEVICE_CMD_RESET 0x67 /* Device CMD reg for reset */
+#define TMA1217_DEVICE_CMD_REZERO 0x69 /* Device CMD reg for rezero */
+
+#define TMA1217_MANUFACTURER_ID 0x73 /* Manufacturer Id */
+#define TMA1217_PRODUCT_FAMILY 0x75 /* Product Family */
+#define TMA1217_FIRMWARE_REVISION 0x76 /* Firmware Revision */
+#define TMA1217_SERIAL_NO_HIGH 0x7C /* Bit 8-15 of device serial no. */
+#define TMA1217_SERIAL_NO_LOW 0x7D /* Bit 0-7 of device serial no. */
+#define TMA1217_PRODUCT_ID_START 0x7E /* Start address for 10 byte ID */
+#define TMA1217_DEVICE_CAPABILITY 0x8B /* Reporting capability */
+
+
+/*
+ * The touch position structure.
+ */
+struct touch_state {
+ int x;
+ int y;
+ bool button;
+};
+
+/* Device Specific info given by the controller */
+struct cp_dev_info {
+ u16 maxX;
+ u16 maxY;
+};
+
+/* Vendor related info given by the controller */
+struct cp_vendor_info {
+ u8 vendor_id;
+ u8 product_family;
+ u8 firmware_rev;
+ u16 serial_no;
+};
+
+/*
+ * Private structure to store the device details
+ */
+struct cp_tm1217_device {
+ struct i2c_client *client;
+ struct device *dev;
+ struct cp_vendor_info vinfo;
+ struct cp_dev_info dinfo;
+ struct input_dev_info {
+ char phys[32];
+ char name[128];
+ struct input_dev *input;
+ struct touch_state touch;
+ } cp_input_info[MAX_TOUCH_SUPPORTED];
+
+ int thread_running;
+ struct mutex thread_mutex;
+
+ int gpio;
+};
+
+
+/* The following functions are used to read/write registers on the device
+ * as per the RMI prorocol. Technically, a page select should be written
+ * before doing read/write but since the register offsets are below 0xFF
+ * we can use the default value of page which is 0x00
+ */
+static int cp_tm1217_read(struct cp_tm1217_device *ts,
+ u8 *req, int size)
+{
+ int i, retval;
+
+ /* Send the address */
+ retval = i2c_master_send(ts->client, &req[0], 1);
+ if (retval != 1) {
+ dev_err(ts->dev, "cp_tm1217: I2C send failed\n");
+ return retval;
+ }
+ msleep(WAIT_FOR_RESPONSE);
+ for (i = 0; i < MAX_RETRIES; i++) {
+ retval = i2c_master_recv(ts->client, &req[1], size);
+ if (retval == size) {
+ break;
+ } else {
+ msleep(INCREMENTAL_DELAY);
+ dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i);
+ }
+ }
+ if (retval != size)
+ dev_err(ts->dev, "cp_tm1217: Read from device failed\n");
+
+ return retval;
+}
+
+static int cp_tm1217_write(struct cp_tm1217_device *ts,
+ u8 *req, int size)
+{
+ int retval;
+
+ /* Send the address and the data to be written */
+ retval = i2c_master_send(ts->client, &req[0], size + 1);
+ if (retval != size + 1) {
+ dev_err(ts->dev, "cp_tm1217: I2C write failed: %d\n", retval);
+ return retval;
+ }
+ /* Wait for the write to complete. TBD why this is required */
+ msleep(WAIT_FOR_RESPONSE);
+
+ return size;
+}
+
+static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts)
+{
+ u8 req[2];
+ int retval;
+
+ req[0] = TMA1217_INTERRUPT_ENABLE;
+ req[1] = 0x0;
+ retval = cp_tm1217_write(ts, req, 1);
+ if (retval != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts)
+{
+ u8 req[2];
+ int retval;
+
+ req[0] = TMA1217_INTERRUPT_ENABLE;
+ req[1] = 0xa;
+ retval = cp_tm1217_write(ts, req, 1);
+ if (retval != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static void process_touch(struct cp_tm1217_device *ts, int index)
+{
+ int retval;
+ struct input_dev_info *input_info =
+ (struct input_dev_info *)&ts->cp_input_info[index];
+ u8 xy_data[6];
+
+ if (index == 0)
+ xy_data[0] = TMA1217_FINGER1_X_HIGHER8;
+ else
+ xy_data[0] = TMA1217_FINGER2_X_HIGHER8;
+
+ retval = cp_tm1217_read(ts, xy_data, 5);
+ if (retval < 5) {
+ dev_err(ts->dev, "cp_tm1217: XY read from device failed\n");
+ return;
+ }
+
+ /* Note: Currently not using the Z values but may be requried in
+ the future. */
+ input_info->touch.x = (xy_data[1] << 4)
+ | (xy_data[3] & 0x0F);
+ input_info->touch.y = (xy_data[2] << 4)
+ | ((xy_data[3] & 0xF0) >> 4);
+ input_report_abs(input_info->input, ABS_X, input_info->touch.x);
+ input_report_abs(input_info->input, ABS_Y, input_info->touch.y);
+ input_sync(input_info->input);
+}
+
+static void cp_tm1217_get_data(struct cp_tm1217_device *ts)
+{
+ u8 req[2];
+ int retval, i, finger_touched = 0;
+
+ do {
+ req[0] = TMA1217_FINGER_STATE;
+ retval = cp_tm1217_read(ts, req, 1);
+ if (retval != 1) {
+ dev_err(ts->dev,
+ "cp_tm1217: Read from device failed\n");
+ continue;
+ }
+ finger_touched = 0;
+ /* Start sampling until the pressure is below
+ threshold */
+ for (i = 0; i < TOUCH_SUPPORTED; i++) {
+ if (req[1] & 0x3) {
+ finger_touched++;
+ if (ts->cp_input_info[i].touch.button == 0) {
+ /* send the button touch event */
+ input_report_key(
+ ts->cp_input_info[i].input,
+ BTN_TOUCH, 1);
+ ts->cp_input_info[i].touch.button = 1;
+ }
+ process_touch(ts, i);
+ } else {
+ if (ts->cp_input_info[i].touch.button == 1) {
+ /* send the button release event */
+ input_report_key(
+ ts->cp_input_info[i].input,
+ BTN_TOUCH, 0);
+ input_sync(ts->cp_input_info[i].input);
+ ts->cp_input_info[i].touch.button = 0;
+ }
+ }
+ req[1] = req[1] >> 2;
+ }
+ msleep(DELAY_BTWIN_SAMPLE);
+ } while (finger_touched > 0);
+}
+
+static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle)
+{
+ struct cp_tm1217_device *ts = (struct cp_tm1217_device *) handle;
+ u8 req[2];
+ int retval;
+
+ /* Chedk if another thread is already running */
+ mutex_lock(&ts->thread_mutex);
+ if (ts->thread_running == 1) {
+ mutex_unlock(&ts->thread_mutex);
+ return IRQ_HANDLED;
+ } else {
+ ts->thread_running = 1;
+ mutex_unlock(&ts->thread_mutex);
+ }
+
+ /* Mask the interrupts */
+ retval = cp_tm1217_mask_interrupt(ts);
+
+ /* Read the Interrupt Status register to find the cause of the
+ Interrupt */
+ req[0] = TMA1217_INT_STATUS;
+ retval = cp_tm1217_read(ts, req, 1);
+ if (retval != 1)
+ goto exit_thread;
+
+ if (!(req[1] & 0x8))
+ goto exit_thread;
+
+ cp_tm1217_get_data(ts);
+
+exit_thread:
+ /* Unmask the interrupts before going to sleep */
+ retval = cp_tm1217_unmask_interrupt(ts);
+
+ mutex_lock(&ts->thread_mutex);
+ ts->thread_running = 0;
+ mutex_unlock(&ts->thread_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int cp_tm1217_init_data(struct cp_tm1217_device *ts)
+{
+ int retval;
+ u8 req[2];
+
+ /* Read the vendor id/ fw revision etc. Ignoring return check as this
+ is non critical info */
+ req[0] = TMA1217_MANUFACTURER_ID;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->vinfo.vendor_id = req[1];
+
+ req[0] = TMA1217_PRODUCT_FAMILY;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->vinfo.product_family = req[1];
+
+ req[0] = TMA1217_FIRMWARE_REVISION;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->vinfo.firmware_rev = req[1];
+
+ req[0] = TMA1217_SERIAL_NO_HIGH;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->vinfo.serial_no = (req[1] << 8);
+
+ req[0] = TMA1217_SERIAL_NO_LOW;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->vinfo.serial_no = ts->vinfo.serial_no | req[1];
+
+ req[0] = TMA1217_MAX_X_HIGHER4;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->dinfo.maxX = (req[1] & 0xF) << 8;
+
+ req[0] = TMA1217_MAX_X_LOWER8;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->dinfo.maxX = ts->dinfo.maxX | req[1];
+
+ req[0] = TMA1217_MAX_Y_HIGHER4;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->dinfo.maxY = (req[1] & 0xF) << 8;
+
+ req[0] = TMA1217_MAX_Y_LOWER8;
+ retval = cp_tm1217_read(ts, req, 1);
+ ts->dinfo.maxY = ts->dinfo.maxY | req[1];
+
+ return 0;
+
+}
+
+/*
+ * Set up a GPIO for use as the interrupt. We can't simply do this at
+ * boot time because the GPIO drivers themselves may not be around at
+ * boot/firmware set up time to do the work. Instead defer it to driver
+ * detection.
+ */
+
+static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
+{
+ int retval;
+
+ /* Hook up the irq handler */
+ retval = gpio_request(ts->gpio, "cp_tm1217_touch");
+ if (retval < 0) {
+ dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
+ retval);
+ return retval;
+ }
+
+ retval = gpio_direction_input(ts->gpio);
+ if (retval < 0) {
+ dev_err(ts->dev,
+ "cp_tm1217: GPIO direction configuration failed, error %d\n",
+ retval);
+ gpio_free(ts->gpio);
+ return retval;
+ }
+
+ retval = gpio_to_irq(ts->gpio);
+ if (retval < 0) {
+ dev_err(ts->dev, "cp_tm1217: GPIO to IRQ failedi,"
+ " error %d\n", retval);
+ gpio_free(ts->gpio);
+ }
+ dev_dbg(ts->dev,
+ "cp_tm1217: Got IRQ number is %d for GPIO %d\n",
+ retval, ts->gpio);
+ return retval;
+}
+
+static int cp_tm1217_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cp_tm1217_device *ts;
+ struct input_dev *input_dev;
+ struct input_dev_info *input_info;
+ struct cp_tm1217_platform_data *pdata;
+ u8 req[2];
+ int i, retval;
+
+ /* No pdata is fine - we then use "normal" IRQ mode */
+
+ pdata = client->dev.platform_data;
+
+ ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL);
+ if (!ts) {
+ dev_err(&client->dev,
+ "cp_tm1217: Private Device Struct alloc failed\n");
+ return -ENOMEM;
+ }
+
+ ts->client = client;
+ ts->dev = &client->dev;
+ i2c_set_clientdata(client, ts);
+
+ ts->thread_running = 0;
+ mutex_init(&ts->thread_mutex);
+
+ /* Reset the Controller */
+ req[0] = TMA1217_DEVICE_CMD_RESET;
+ req[1] = 0x1;
+ retval = cp_tm1217_write(ts, req, 1);
+ if (retval != 1) {
+ dev_err(ts->dev, "cp_tm1217: Controller reset failed\n");
+ kfree(ts);
+ return -EIO;
+ }
+
+ /* Clear up the interrupt status from reset. */
+ req[0] = TMA1217_INT_STATUS;
+ retval = cp_tm1217_read(ts, req, 1);
+
+ /* Mask all the interrupts */
+ retval = cp_tm1217_mask_interrupt(ts);
+
+ /* Read the controller information */
+ cp_tm1217_init_data(ts);
+
+ /* The following code will register multiple event devices when
+ multi-pointer is enabled, the code has not been tested
+ with MPX */
+ for (i = 0; i < TOUCH_SUPPORTED; i++) {
+ input_dev = input_allocate_device();
+ if (input_dev == NULL) {
+ dev_err(ts->dev,
+ "cp_tm1217:Input Device Struct alloc failed\n");
+ kfree(ts);
+ return -ENOMEM;
+ }
+ input_info = &ts->cp_input_info[i];
+ snprintf(input_info->name, sizeof(input_info->name),
+ "cp_tm1217_touchscreen_%d", i);
+ input_dev->name = input_info->name;
+ snprintf(input_info->phys, sizeof(input_info->phys),
+ "%s/input%d", dev_name(&client->dev), i);
+
+ input_dev->phys = input_info->phys;
+ input_dev->id.bustype = BUS_I2C;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0);
+
+ retval = input_register_device(input_dev);
+ if (retval) {
+ dev_err(ts->dev,
+ "Input dev registration failed for %s\n",
+ input_dev->name);
+ goto fail;
+ }
+ input_info->input = input_dev;
+ }
+
+ /* Setup the reporting mode to send an interrupt only when
+ finger arrives or departs. */
+ req[0] = TMA1217_REPORT_MODE;
+ req[1] = 0x02;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ /* Setup the device to no sleep mode for now and make it configured */
+ req[0] = TMA1217_DEVICE_CTRL;
+ req[1] = 0x84;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ /* Check for the status of the device */
+ req[0] = TMA1217_DEV_STATUS;
+ retval = cp_tm1217_read(ts, req, 1);
+ if (req[1] != 0) {
+ dev_err(ts->dev,
+ "cp_tm1217: Device Status 0x%x != 0: config failed\n",
+ req[1]);
+
+ retval = -EIO;
+ goto fail;
+ }
+
+ if (pdata && pdata->gpio) {
+ ts->gpio = pdata->gpio;
+ retval = cp_tm1217_setup_gpio_irq(ts);
+ } else
+ retval = client->irq;
+
+ if (retval < 0) {
+ dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
+ retval);
+ goto fail;
+ }
+
+ client->irq = retval;
+
+
+ retval = request_threaded_irq(client->irq,
+ NULL, cp_tm1217_sample_thread,
+ IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts);
+ if (retval < 0) {
+ dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval);
+ goto fail_gpio;
+ }
+
+ /* Unmask the interrupts */
+ retval = cp_tm1217_unmask_interrupt(ts);
+ if (retval == 0)
+ return 0;
+
+ free_irq(client->irq, ts);
+fail_gpio:
+ if (ts->gpio)
+ gpio_free(ts->gpio);
+fail:
+ /* Clean up before returning failure */
+ for (i = 0; i < TOUCH_SUPPORTED; i++) {
+ if (ts->cp_input_info[i].input) {
+ input_unregister_device(ts->cp_input_info[i].input);
+ input_free_device(ts->cp_input_info[i].input);
+ }
+ }
+ kfree(ts);
+ return retval;
+
+}
+
+/*
+ * cp_tm1217 suspend
+ *
+ */
+static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+ u8 req[2];
+ int retval;
+
+ /* Put the controller to sleep */
+ req[0] = TMA1217_DEVICE_CTRL;
+ retval = cp_tm1217_read(ts, req, 1);
+ req[1] = (req[1] & 0xF8) | 0x1;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+/*
+ * cp_tm1217_resume
+ *
+ */
+static int cp_tm1217_resume(struct i2c_client *client)
+{
+ struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+ u8 req[2];
+ int retval;
+
+ /* Take the controller out of sleep */
+ req[0] = TMA1217_DEVICE_CTRL;
+ retval = cp_tm1217_read(ts, req, 1);
+ req[1] = (req[1] & 0xF8) | 0x4;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ /* Restore the register settings sinc the power to the
+ could have been cut off */
+
+ /* Setup the reporting mode to send an interrupt only when
+ finger arrives or departs. */
+ req[0] = TMA1217_REPORT_MODE;
+ req[1] = 0x02;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ /* Setup the device to no sleep mode for now and make it configured */
+ req[0] = TMA1217_DEVICE_CTRL;
+ req[1] = 0x84;
+ retval = cp_tm1217_write(ts, req, 1);
+
+ /* Setup the interrupt mask */
+ retval = cp_tm1217_unmask_interrupt(ts);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+
+/*
+ * cp_tm1217_remove
+ *
+ */
+static int cp_tm1217_remove(struct i2c_client *client)
+{
+ struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+ int i;
+
+ free_irq(client->irq, ts);
+ if (ts->gpio)
+ gpio_free(ts->gpio);
+ for (i = 0; i < TOUCH_SUPPORTED; i++)
+ input_unregister_device(ts->cp_input_info[i].input);
+ kfree(ts);
+ return 0;
+}
+
+static struct i2c_device_id cp_tm1217_idtable[] = {
+ { CPTM1217_DEVICE_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable);
+
+static struct i2c_driver cp_tm1217_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = CPTM1217_DRIVER_NAME,
+ },
+ .id_table = cp_tm1217_idtable,
+ .probe = cp_tm1217_probe,
+ .remove = cp_tm1217_remove,
+ .suspend = cp_tm1217_suspend,
+ .resume = cp_tm1217_resume,
+};
+
+static int __init clearpad_tm1217_init(void)
+{
+ return i2c_add_driver(&cp_tm1217_driver);
+}
+
+static void __exit clearpad_tm1217_exit(void)
+{
+ i2c_del_driver(&cp_tm1217_driver);
+}
+
+module_init(clearpad_tm1217_init);
+module_exit(clearpad_tm1217_exit);
+
+MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
+MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/cptm1217/cp_tm1217.h b/drivers/staging/cptm1217/cp_tm1217.h
new file mode 100644
index 000000000000..a0ce31db53f8
--- /dev/null
+++ b/drivers/staging/cptm1217/cp_tm1217.h
@@ -0,0 +1,9 @@
+#ifndef __LINUX_I2C_CP_TM1217_H
+#define __LINUX_I2C_CP_TM1217_H
+
+struct cp_tm1217_platform_data
+{
+ int gpio; /* If not set uses the IRQ resource 0 */
+};
+
+#endif
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
index f63185790c48..153ddbf4247d 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.c
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -1711,7 +1711,7 @@ enum BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp, void *buffer, ui
}
BCMLOG(BCMLOG_INFO, "Firmware Downloaded Successfully\n");
- return BC_STS_SUCCESS;;
+ return BC_STS_SUCCESS;
}
enum BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw,
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index 28c6b8ced424..719e70bc871e 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -516,7 +516,7 @@ static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
BCMLOG_ENTER;
- pinfo = (struct crystalhd_adp *) pci_get_drvdata(pdev);
+ pinfo = pci_get_drvdata(pdev);
if (!pinfo) {
BCMLOG_ERR("could not get adp\n");
return;
@@ -626,7 +626,7 @@ int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
struct crystalhd_ioctl_data *temp;
enum BC_STATUS sts = BC_STS_SUCCESS;
- adp = (struct crystalhd_adp *)pci_get_drvdata(pdev);
+ adp = pci_get_drvdata(pdev);
if (!adp) {
BCMLOG_ERR("could not get adp\n");
return -ENODEV;
@@ -660,7 +660,7 @@ int chd_dec_pci_resume(struct pci_dev *pdev)
enum BC_STATUS sts = BC_STS_SUCCESS;
int rc;
- adp = (struct crystalhd_adp *)pci_get_drvdata(pdev);
+ adp = pci_get_drvdata(pdev);
if (!adp) {
BCMLOG_ERR("could not get adp\n");
return -ENODEV;
diff --git a/drivers/staging/cs5535_gpio/Kconfig b/drivers/staging/cs5535_gpio/Kconfig
new file mode 100644
index 000000000000..a1b3a8d2b866
--- /dev/null
+++ b/drivers/staging/cs5535_gpio/Kconfig
@@ -0,0 +1,11 @@
+config CS5535_GPIO
+ tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
+ depends on X86_32
+ help
+ Note: this driver is DEPRECATED. Please use the cs5535-gpio module
+ in the GPIO section instead (CONFIG_GPIO_CS5535).
+
+ Give userspace access to the GPIO pins on the AMD CS5535 and
+ CS5536 Geode companion devices.
+
+ If compiled as a module, it will be called cs5535_gpio.
diff --git a/drivers/staging/cs5535_gpio/Makefile b/drivers/staging/cs5535_gpio/Makefile
new file mode 100644
index 000000000000..d67c4b85f191
--- /dev/null
+++ b/drivers/staging/cs5535_gpio/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
diff --git a/drivers/staging/cs5535_gpio/TODO b/drivers/staging/cs5535_gpio/TODO
new file mode 100644
index 000000000000..98d1cd1e2363
--- /dev/null
+++ b/drivers/staging/cs5535_gpio/TODO
@@ -0,0 +1,6 @@
+This is an obsolete driver for some the CS5535 and CS5536 southbridge GPIOs.
+It has been replaced by a driver that makes use of the Linux GPIO subsystem.
+Please switch to that driver, and let dilinger@queued.net know if there's
+anything missing from the new driver.
+
+This driver is scheduled for removal in 2.6.40.
diff --git a/drivers/char/cs5535_gpio.c b/drivers/staging/cs5535_gpio/cs5535_gpio.c
index 0cf1e5fad9ab..0cf1e5fad9ab 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/staging/cs5535_gpio/cs5535_gpio.c
diff --git a/drivers/staging/cx25821/Kconfig b/drivers/staging/cx25821/Kconfig
index 1d73334d2a44..b2656957aa8f 100644
--- a/drivers/staging/cx25821/Kconfig
+++ b/drivers/staging/cx25821/Kconfig
@@ -1,11 +1,11 @@
config VIDEO_CX25821
tristate "Conexant cx25821 support"
- depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+ depends on DVB_CORE && VIDEO_DEV && PCI && I2C
depends on BKL # please fix
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEO_TVEEPROM
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
select VIDEO_CX25840
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c
index 2a01dc057b2c..160f6693aa33 100644
--- a/drivers/staging/cx25821/cx25821-alsa.c
+++ b/drivers/staging/cx25821/cx25821-alsa.c
@@ -20,6 +20,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -42,11 +44,16 @@
#define AUDIO_SRAM_CHANNEL SRAM_CH08
-#define dprintk(level, fmt, arg...) if (debug >= level) \
- printk(KERN_INFO "%s/1: " fmt, chip->dev->name , ## arg)
-
-#define dprintk_core(level, fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name , ## arg)
+#define dprintk(level, fmt, arg...) \
+do { \
+ if (debug >= level) \
+ pr_info("%s/1: " fmt, chip->dev->name, ##arg); \
+} while (0)
+#define dprintk_core(level, fmt, arg...) \
+do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \
+} while (0)
/****************************************************************************
Data type declarations - Can be moded to a header file later
@@ -173,12 +180,11 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
FLD_AUD_CLK_ENABLE);
- /* printk(KERN_INFO "DEBUG: Start audio DMA, %d B/line,"
- "cmds_start(0x%x)= %d lines/FIFO, %d periods, "
- "%d byte buffer\n", buf->bpl,
- audio_ch->cmds_start,
- cx_read(audio_ch->cmds_start + 12)>>1,
- chip->num_periods, buf->bpl *chip->num_periods);
+ /*
+ pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n",
+ buf->bpl, audio_ch->cmds_start,
+ cx_read(audio_ch->cmds_start + 12)>>1,
+ chip->num_periods, buf->bpl * chip->num_periods);
*/
/* Enables corresponding bits at AUD_INT_STAT */
@@ -259,8 +265,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
/* risc op code error */
if (status & AUD_INT_OPC_ERR) {
- printk(KERN_WARNING "WARNING %s/1: Audio risc op code error\n",
- dev->name);
+ pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name);
cx_clear(AUD_INT_DMA_CTL,
FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
@@ -269,8 +274,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
[AUDIO_SRAM_CHANNEL]);
}
if (status & AUD_INT_DN_SYNC) {
- printk(KERN_WARNING "WARNING %s: Downstream sync error!\n",
- dev->name);
+ pr_warn("WARNING %s: Downstream sync error!\n", dev->name);
cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
return;
}
@@ -388,8 +392,7 @@ static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream)
unsigned int bpl = 0;
if (!chip) {
- printk(KERN_ERR "DEBUG: cx25821 can't find device struct."
- " Can't proceed with open\n");
+ pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n");
return -ENODEV;
}
@@ -479,8 +482,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
chip->period_size, chip->num_periods,
1);
if (ret < 0) {
- printk(KERN_INFO
- "DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
+ pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
goto error;
}
@@ -608,8 +610,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
if (err < 0) {
- printk(KERN_INFO "ERROR: FAILED snd_pcm_new() in %s\n",
- __func__);
+ pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__);
return err;
}
pcm->private_data = chip;
@@ -629,7 +630,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
* Only boards with eeprom and byte 1 at eeprom=1 have it
*/
-static const struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = {
{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
@@ -674,23 +675,21 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
int err;
if (devno >= SNDRV_CARDS) {
- printk(KERN_INFO "DEBUG ERROR: devno >= SNDRV_CARDS %s\n",
- __func__);
+ pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__);
return -ENODEV;
}
if (!enable[devno]) {
++devno;
- printk(KERN_INFO "DEBUG ERROR: !enable[devno] %s\n", __func__);
+ pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__);
return -ENOENT;
}
err = snd_card_create(index[devno], id[devno], THIS_MODULE,
sizeof(struct cx25821_audio_dev), &card);
if (err < 0) {
- printk(KERN_INFO
- "DEBUG ERROR: cannot create snd_card_new in %s\n",
- __func__);
+ pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
+ __func__);
return err;
}
@@ -712,16 +711,15 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
IRQF_SHARED | IRQF_DISABLED, chip->dev->name, chip);
if (err < 0) {
- printk(KERN_ERR "ERROR %s: can't get IRQ %d for ALSA\n",
+ pr_err("ERROR %s: can't get IRQ %d for ALSA\n",
chip->dev->name, dev->pci->irq);
goto error;
}
err = snd_cx25821_pcm(chip, 0, "cx25821 Digital");
if (err < 0) {
- printk(KERN_INFO
- "DEBUG ERROR: cannot create snd_cx25821_pcm %s\n",
- __func__);
+ pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n",
+ __func__);
goto error;
}
@@ -732,13 +730,13 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
chip->iobase, chip->irq);
strcpy(card->mixername, "CX25821");
- printk(KERN_INFO "%s/%i: ALSA support for cx25821 boards\n",
- card->driver, devno);
+ pr_info("%s/%i: ALSA support for cx25821 boards\n",
+ card->driver, devno);
err = snd_card_register(card);
if (err < 0) {
- printk(KERN_INFO "DEBUG ERROR: cannot register sound card %s\n",
- __func__);
+ pr_info("DEBUG ERROR: cannot register sound card %s\n",
+ __func__);
goto error;
}
@@ -778,8 +776,7 @@ static int cx25821_alsa_init(void)
}
if (dev == NULL)
- printk(KERN_INFO
- "cx25821 ERROR ALSA: no cx25821 cards found\n");
+ pr_info("ERROR ALSA: no cx25821 cards found\n");
return 0;
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/staging/cx25821/cx25821-audio-upstream.c
index 1607b0d86e6f..7992a3ba526f 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.c
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821-video.h"
#include "cx25821-audio-upstream.h"
@@ -221,7 +223,7 @@ void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
if (!dev->_audio_is_running) {
printk(KERN_DEBUG
- "cx25821: No audio file is currently running so return!\n");
+ pr_fmt("No audio file is currently running so return!\n"));
return;
}
/* Disable RISC interrupts */
@@ -281,19 +283,19 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
__func__, dev->_audiofilename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR "%s: File has no file operations registered!\n",
+ pr_err("%s(): File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk(KERN_ERR "%s: File has no READ operations registered!\n",
+ pr_err("%s(): File has no READ operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -320,9 +322,8 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
frame_offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Audio file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Audio file\n",
+ __func__);
break;
}
}
@@ -346,7 +347,7 @@ static void cx25821_audioups_handler(struct work_struct *work)
container_of(work, struct cx25821_dev, _audio_work_entry);
if (!dev) {
- printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
+ pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
__func__);
return;
}
@@ -373,19 +374,19 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
__func__, dev->_audiofilename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR "%s: File has no file operations registered!\n",
+ pr_err("%s(): File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk(KERN_ERR "%s: File has no READ operations registered!\n",
+ pr_err("%s(): File has no READ operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -414,9 +415,8 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Audio file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Audio file\n",
+ __func__);
break;
}
}
@@ -459,7 +459,7 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
if (!dev->_risc_virt_addr) {
printk(KERN_DEBUG
- "cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning.\n");
+ pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
return -ENOMEM;
}
/* Clear out memory at address */
@@ -474,7 +474,7 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
if (!dev->_audiodata_buf_virt_addr) {
printk(KERN_DEBUG
- "cx25821 ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning.\n");
+ pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
return -ENOMEM;
}
/* Clear out memory at address */
@@ -490,7 +490,7 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
dev->_audio_lines_count);
if (ret < 0) {
printk(KERN_DEBUG
- "cx25821 ERROR creating audio upstream RISC programs!\n");
+ pr_fmt("ERROR creating audio upstream RISC programs!\n"));
goto error;
}
@@ -569,16 +569,16 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
spin_unlock(&dev->slock);
} else {
if (status & FLD_AUD_SRC_OF)
- printk(KERN_WARNING "%s: Audio Received Overflow Error Interrupt!\n",
- __func__);
+ pr_warn("%s(): Audio Received Overflow Error Interrupt!\n",
+ __func__);
if (status & FLD_AUD_SRC_SYNC)
- printk(KERN_WARNING "%s: Audio Received Sync Error Interrupt!\n",
- __func__);
+ pr_warn("%s(): Audio Received Sync Error Interrupt!\n",
+ __func__);
if (status & FLD_AUD_SRC_OPC_ERR)
- printk(KERN_WARNING "%s: Audio Received OpCode Error Interrupt!\n",
- __func__);
+ pr_warn("%s(): Audio Received OpCode Error Interrupt!\n",
+ __func__);
/* Read and write back the interrupt status register to clear
* our bits */
@@ -586,8 +586,8 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
}
if (dev->_audiofile_status == END_OF_FILE) {
- printk(KERN_WARNING "cx25821: EOF Channel Audio Framecount = %d\n",
- dev->_audioframe_count);
+ pr_warn("EOF Channel Audio Framecount = %d\n",
+ dev->_audioframe_count);
return -1;
}
/* ElSE, set the interrupt mask register, re-enable irq. */
@@ -644,9 +644,8 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
/* 10 millisecond timeout */
if (count++ > 1000) {
- printk(KERN_ERR
- "cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
- __func__);
+ pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n",
+ __func__);
return;
}
@@ -696,8 +695,8 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get upstream IRQ %d\n", dev->name,
- dev->pci->irq);
+ pr_err("%s: can't get upstream IRQ %d\n",
+ dev->name, dev->pci->irq);
goto fail_irq;
}
@@ -726,7 +725,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
int str_length = 0;
if (dev->_audio_is_running) {
- printk(KERN_WARNING "Audio Channel is still running so return!\n");
+ pr_warn("Audio Channel is still running so return!\n");
return 0;
}
@@ -740,7 +739,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
if (!dev->_irq_audio_queues) {
printk(KERN_DEBUG
- "cx25821 ERROR: create_singlethread_workqueue() for Audio FAILED!\n");
+ pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
return -ENOMEM;
}
@@ -787,8 +786,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
retval =
cx25821_audio_upstream_buffer_prepare(dev, sram_ch, _line_size);
if (retval < 0) {
- printk(KERN_ERR
- "%s: Failed to set up Audio upstream buffers!\n",
+ pr_err("%s: Failed to set up Audio upstream buffers!\n",
dev->name);
goto error;
}
diff --git a/drivers/staging/cx25821/cx25821-cards.c b/drivers/staging/cx25821/cx25821-cards.c
index da0f56d50e27..94e8d685c889 100644
--- a/drivers/staging/cx25821/cx25821-cards.c
+++ b/drivers/staging/cx25821/cx25821-cards.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c
index 300da319b065..a216b620b718 100644
--- a/drivers/staging/cx25821/cx25821-core.c
+++ b/drivers/staging/cx25821/cx25821-core.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/i2c.h>
#include <linux/slab.h>
#include "cx25821.h"
@@ -332,7 +334,7 @@ struct cx25821_dmaqueue mpegq;
static int cx25821_risc_decode(u32 risc)
{
- static char *instr[16] = {
+ static const char * const instr[16] = {
[RISC_SYNC >> 28] = "sync",
[RISC_WRITE >> 28] = "write",
[RISC_WRITEC >> 28] = "writec",
@@ -344,7 +346,7 @@ static int cx25821_risc_decode(u32 risc)
[RISC_WRITECM >> 28] = "writecm",
[RISC_WRITECR >> 28] = "writecr",
};
- static int incr[16] = {
+ static const int incr[16] = {
[RISC_WRITE >> 28] = 3,
[RISC_JUMP >> 28] = 3,
[RISC_SKIP >> 28] = 1,
@@ -353,7 +355,7 @@ static int cx25821_risc_decode(u32 risc)
[RISC_WRITECM >> 28] = 3,
[RISC_WRITECR >> 28] = 4,
};
- static char *bits[] = {
+ static const char * const bits[] = {
"12", "13", "14", "resync",
"cnt0", "cnt1", "18", "19",
"20", "21", "22", "23",
@@ -361,13 +363,13 @@ static int cx25821_risc_decode(u32 risc)
};
int i;
- printk("0x%08x [ %s", risc,
- instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+ pr_cont("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]);
+ pr_cont(" %s", bits[i]);
}
- printk(" count=%d ]\n", risc & 0xfff);
+ pr_cont(" count=%d ]\n", risc & 0xfff);
return incr[risc >> 28] ? incr[risc >> 28] : 1;
}
@@ -620,16 +622,15 @@ void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
u32 risc;
unsigned int i, j, n;
- printk(KERN_WARNING "%s: %s - dma channel status dump\n", dev->name,
- ch->name);
+ pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name);
for (i = 0; i < ARRAY_SIZE(name); i++)
- printk(KERN_WARNING "cmds + 0x%2x: %-15s: 0x%08x\n", i * 4,
- name[i], cx_read(ch->cmds_start + 4 * i));
+ pr_warn("cmds + 0x%2x: %-15s: 0x%08x\n",
+ i * 4, name[i], cx_read(ch->cmds_start + 4 * i));
j = i * 4;
for (i = 0; i < 4;) {
risc = cx_read(ch->cmds_start + 4 * (i + 14));
- printk(KERN_WARNING "cmds + 0x%2x: risc%d: ", j + i * 4, i);
+ pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i);
i += cx25821_risc_decode(risc);
}
@@ -637,36 +638,35 @@ void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
risc = cx_read(ch->ctrl_start + 4 * i);
/* No consideration for bits 63-32 */
- printk(KERN_WARNING "ctrl + 0x%2x (0x%08x): iq %x: ", i * 4,
- ch->ctrl_start + 4 * i, i);
+ pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
+ i * 4, ch->ctrl_start + 4 * i, i);
n = cx25821_risc_decode(risc);
for (j = 1; j < n; j++) {
risc = cx_read(ch->ctrl_start + 4 * (i + j));
- printk(KERN_WARNING
- "ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
- 4 * (i + j), i + j, risc, j);
+ pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
+ 4 * (i + j), i + j, risc, j);
}
}
- printk(KERN_WARNING " : fifo: 0x%08x -> 0x%x\n",
- ch->fifo_start, ch->fifo_start + ch->fifo_size);
- printk(KERN_WARNING " : ctrl: 0x%08x -> 0x%x\n",
- ch->ctrl_start, ch->ctrl_start + 6 * 16);
- printk(KERN_WARNING " : ptr1_reg: 0x%08x\n",
- cx_read(ch->ptr1_reg));
- printk(KERN_WARNING " : ptr2_reg: 0x%08x\n",
- cx_read(ch->ptr2_reg));
- printk(KERN_WARNING " : cnt1_reg: 0x%08x\n",
- cx_read(ch->cnt1_reg));
- printk(KERN_WARNING " : cnt2_reg: 0x%08x\n",
- cx_read(ch->cnt2_reg));
+ pr_warn(" : fifo: 0x%08x -> 0x%x\n",
+ ch->fifo_start, ch->fifo_start + ch->fifo_size);
+ pr_warn(" : ctrl: 0x%08x -> 0x%x\n",
+ ch->ctrl_start, ch->ctrl_start + 6 * 16);
+ pr_warn(" : ptr1_reg: 0x%08x\n",
+ cx_read(ch->ptr1_reg));
+ pr_warn(" : ptr2_reg: 0x%08x\n",
+ cx_read(ch->ptr2_reg));
+ pr_warn(" : cnt1_reg: 0x%08x\n",
+ cx_read(ch->cnt1_reg));
+ pr_warn(" : cnt2_reg: 0x%08x\n",
+ cx_read(ch->cnt2_reg));
}
EXPORT_SYMBOL(cx25821_sram_channel_dump);
void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
struct sram_channel *ch)
{
- static char *name[] = {
+ static const char * const name[] = {
"init risc lo",
"init risc hi",
"cdt base",
@@ -686,18 +686,18 @@ void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
u32 risc, value, tmp;
unsigned int i, j, n;
- printk(KERN_INFO "\n%s: %s - dma Audio channel status dump\n",
- dev->name, ch->name);
+ pr_info("\n%s: %s - dma Audio channel status dump\n",
+ dev->name, ch->name);
for (i = 0; i < ARRAY_SIZE(name); i++)
- printk(KERN_INFO "%s: cmds + 0x%2x: %-15s: 0x%08x\n",
- dev->name, i * 4, name[i],
- cx_read(ch->cmds_start + 4 * i));
+ pr_info("%s: cmds + 0x%2x: %-15s: 0x%08x\n",
+ dev->name, i * 4, name[i],
+ cx_read(ch->cmds_start + 4 * i));
j = i * 4;
for (i = 0; i < 4;) {
risc = cx_read(ch->cmds_start + 4 * (i + 14));
- printk(KERN_WARNING "cmds + 0x%2x: risc%d: ", j + i * 4, i);
+ pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i);
i += cx25821_risc_decode(risc);
}
@@ -705,44 +705,43 @@ void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
risc = cx_read(ch->ctrl_start + 4 * i);
/* No consideration for bits 63-32 */
- printk(KERN_WARNING "ctrl + 0x%2x (0x%08x): iq %x: ", i * 4,
- ch->ctrl_start + 4 * i, i);
+ pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
+ i * 4, ch->ctrl_start + 4 * i, i);
n = cx25821_risc_decode(risc);
for (j = 1; j < n; j++) {
risc = cx_read(ch->ctrl_start + 4 * (i + j));
- printk(KERN_WARNING
- "ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
- 4 * (i + j), i + j, risc, j);
+ pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
+ 4 * (i + j), i + j, risc, j);
}
}
- printk(KERN_WARNING " : fifo: 0x%08x -> 0x%x\n",
- ch->fifo_start, ch->fifo_start + ch->fifo_size);
- printk(KERN_WARNING " : ctrl: 0x%08x -> 0x%x\n",
- ch->ctrl_start, ch->ctrl_start + 6 * 16);
- printk(KERN_WARNING " : ptr1_reg: 0x%08x\n",
- cx_read(ch->ptr1_reg));
- printk(KERN_WARNING " : ptr2_reg: 0x%08x\n",
- cx_read(ch->ptr2_reg));
- printk(KERN_WARNING " : cnt1_reg: 0x%08x\n",
- cx_read(ch->cnt1_reg));
- printk(KERN_WARNING " : cnt2_reg: 0x%08x\n",
- cx_read(ch->cnt2_reg));
+ pr_warn(" : fifo: 0x%08x -> 0x%x\n",
+ ch->fifo_start, ch->fifo_start + ch->fifo_size);
+ pr_warn(" : ctrl: 0x%08x -> 0x%x\n",
+ ch->ctrl_start, ch->ctrl_start + 6 * 16);
+ pr_warn(" : ptr1_reg: 0x%08x\n",
+ cx_read(ch->ptr1_reg));
+ pr_warn(" : ptr2_reg: 0x%08x\n",
+ cx_read(ch->ptr2_reg));
+ pr_warn(" : cnt1_reg: 0x%08x\n",
+ cx_read(ch->cnt1_reg));
+ pr_warn(" : cnt2_reg: 0x%08x\n",
+ cx_read(ch->cnt2_reg));
for (i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 56 + (i * 4));
- printk(KERN_WARNING "instruction %d = 0x%x\n", i, risc);
+ pr_warn("instruction %d = 0x%x\n", i, risc);
}
/* read data from the first cdt buffer */
risc = cx_read(AUD_A_CDT);
- printk(KERN_WARNING "\nread cdt loc=0x%x\n", risc);
+ pr_warn("\nread cdt loc=0x%x\n", risc);
for (i = 0; i < 8; i++) {
n = cx_read(risc + i * 4);
- printk(KERN_WARNING "0x%x ", n);
+ pr_cont("0x%x ", n);
}
- printk(KERN_WARNING "\n\n");
+ pr_cont("\n\n");
value = cx_read(CLK_RST);
CX25821_INFO(" CLK_RST = 0x%x\n\n", value);
@@ -870,7 +869,7 @@ static int cx25821_get_resources(struct cx25821_dev *dev)
dev->name))
return 0;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ pr_err("%s: can't get MMIO memory @ 0x%llx\n",
dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
return -EBUSY;
@@ -880,8 +879,8 @@ static void cx25821_dev_checkrevision(struct cx25821_dev *dev)
{
dev->hwrevision = cx_read(RDR_CFG2) & 0xff;
- printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", __func__,
- dev->hwrevision);
+ pr_info("%s(): Hardware revision = 0x%02x\n",
+ __func__, dev->hwrevision);
}
static void cx25821_iounmap(struct cx25821_dev *dev)
@@ -901,9 +900,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
{
int io_size = 0, i;
- printk(KERN_INFO "\n***********************************\n");
- printk(KERN_INFO "cx25821 set up\n");
- printk(KERN_INFO "***********************************\n\n");
+ pr_info("\n***********************************\n");
+ pr_info("cx25821 set up\n");
+ pr_info("***********************************\n\n");
mutex_init(&dev->lock);
@@ -920,13 +919,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821");
if (dev->pci->device != 0x8210) {
- printk(KERN_INFO
- "%s() Exiting. Incorrect Hardware device = 0x%02x\n",
- __func__, dev->pci->device);
+ pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
+ __func__, dev->pci->device);
return -1;
} else {
- printk(KERN_INFO "Athena Hardware device = 0x%02x\n",
- dev->pci->device);
+ pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device);
}
/* Apply a sensible clock frequency for the PCIe bridge */
@@ -956,8 +953,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */
if (cx25821_get_resources(dev) < 0) {
- printk(KERN_ERR "%s No more PCIe resources for "
- "subsystem: %04x:%04x\n",
+ pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n",
dev->name, dev->pci->subsystem_vendor,
dev->pci->subsystem_device);
@@ -985,11 +981,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->bmmio = (u8 __iomem *) dev->lmmio;
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- dev->name, dev->pci->subsystem_vendor,
- dev->pci->subsystem_device, cx25821_boards[dev->board].name,
- dev->board, card[dev->nr] == dev->board ?
- "insmod option" : "autodetected");
+ pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, cx25821_boards[dev->board].name,
+ dev->board, card[dev->nr] == dev->board ?
+ "insmod option" : "autodetected");
/* init hardware */
cx25821_initialize(dev);
@@ -1004,8 +1000,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
cx25821_card_setup(dev);
if (medusa_video_init(dev) < 0)
- CX25821_ERR("%s() Failed to initialize medusa!\n"
- , __func__);
+ CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__);
cx25821_video_register(dev);
@@ -1017,13 +1012,12 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
if (video_register_device
(dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
cx25821_videoioctl_unregister(dev);
- printk(KERN_ERR
- "%s() Failed to register video adapter for IOCTL, so \
- unregistering videoioctl device.\n", __func__);
+ pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n",
+ __func__);
}
cx25821_dev_checkrevision(dev);
- CX25821_INFO("cx25821 setup done!\n");
+ CX25821_INFO("setup done!\n");
return 0;
}
@@ -1362,20 +1356,20 @@ void cx25821_print_irqbits(char *name, char *tag, char **strings,
{
unsigned int i;
- printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
+ printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits);
for (i = 0; i < len; i++) {
if (!(bits & (1 << i)))
continue;
if (strings[i])
- printk(" %s", strings[i]);
+ pr_cont(" %s", strings[i]);
else
- printk(" %d", i);
+ pr_cont(" %d", i);
if (!(mask & (1 << i)))
continue;
- printk("*");
+ pr_cont("*");
}
- printk("\n");
+ pr_cont("\n");
}
EXPORT_SYMBOL(cx25821_print_irqbits);
@@ -1405,12 +1399,12 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
if (pci_enable_device(pci_dev)) {
err = -EIO;
- printk(KERN_INFO "pci enable failed! ");
+ pr_info("pci enable failed!\n");
goto fail_unregister_device;
}
- printk(KERN_INFO "cx25821 Athena pci enable !\n");
+ pr_info("Athena pci enable !\n");
err = cx25821_dev_setup(dev);
if (err) {
@@ -1423,14 +1417,13 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
/* 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)dev->base_io_addr);
+ pr_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)dev->base_io_addr);
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev, 0xffffffff)) {
- printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+ pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
err = -EIO;
goto fail_irq;
}
@@ -1440,15 +1433,14 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
dev->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
- pci_dev->irq);
+ pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq);
goto fail_irq;
}
return 0;
fail_irq:
- printk(KERN_INFO "cx25821 cx25821_initdev() can't get IRQ !\n");
+ pr_info("cx25821_initdev() can't get IRQ !\n");
cx25821_dev_unregister(dev);
fail_unregister_pci:
@@ -1510,9 +1502,10 @@ static struct pci_driver cx25821_pci_driver = {
static int __init cx25821_init(void)
{
INIT_LIST_HEAD(&cx25821_devlist);
- printk(KERN_INFO "cx25821 driver version %d.%d.%d loaded\n",
- (CX25821_VERSION_CODE >> 16) & 0xff,
- (CX25821_VERSION_CODE >> 8) & 0xff, CX25821_VERSION_CODE & 0xff);
+ pr_info("driver version %d.%d.%d loaded\n",
+ (CX25821_VERSION_CODE >> 16) & 0xff,
+ (CX25821_VERSION_CODE >> 8) & 0xff,
+ CX25821_VERSION_CODE & 0xff);
return pci_register_driver(&cx25821_pci_driver);
}
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/staging/cx25821/cx25821-i2c.c
index 2b14bcca6897..130dfebebe20 100644
--- a/drivers/staging/cx25821/cx25821-i2c.c
+++ b/drivers/staging/cx25821/cx25821-i2c.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821.h"
#include <linux/i2c.h>
@@ -32,10 +34,11 @@ static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
-#define dprintk(level, fmt, arg...)\
- do { if (i2c_debug >= level)\
- printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
- } while (0)
+#define dprintk(level, fmt, arg...) \
+do { \
+ if (i2c_debug >= level) \
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \
+} while (0)
#define I2C_WAIT_DELAY 32
#define I2C_WAIT_RETRY 64
@@ -98,7 +101,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
if (!i2c_slave_did_ack(i2c_adap))
return -EIO;
- dprintk(1, "%s() returns 0\n", __func__);
+ dprintk(1, "%s(): returns 0\n", __func__);
return 0;
}
@@ -163,7 +166,7 @@ eio:
retval = -EIO;
err:
if (i2c_debug)
- printk(KERN_ERR " ERR: %d\n", retval);
+ pr_err(" ERR: %d\n", retval);
return retval;
}
@@ -187,7 +190,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
if (!i2c_slave_did_ack(i2c_adap))
return -EIO;
- dprintk(1, "%s() returns 0\n", __func__);
+ dprintk(1, "%s(): returns 0\n", __func__);
return 0;
}
@@ -227,7 +230,7 @@ eio:
retval = -EIO;
err:
if (i2c_debug)
- printk(KERN_ERR " ERR: %d\n", retval);
+ pr_err(" ERR: %d\n", retval);
return retval;
}
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index 1e11e0ce2d0a..fc780d0908dc 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821.h"
#include "cx25821-medusa-video.h"
#include "cx25821-biffuncs.h"
@@ -499,9 +501,8 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
/* validate the width - cannot be negative */
if (width > MAX_WIDTH) {
- printk
- ("cx25821 %s() : width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
- __func__, width, MAX_WIDTH);
+ pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
+ __func__, width, MAX_WIDTH);
width = MAX_WIDTH;
}
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
index 405e2db72b0f..e2efacdfb874 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821-video.h"
#include "cx25821-video-upstream-ch2.h"
@@ -211,8 +213,7 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
u32 tmp = 0;
if (!dev->_is_running_ch2) {
- printk
- ("cx25821: No video file is currently running so return!\n");
+ pr_info("No video file is currently running so return!\n");
return;
}
/* Disable RISC interrupts */
@@ -301,19 +302,19 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename_ch2, open_errno);
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename_ch2, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk("%s: File has no file operations registered!",
+ pr_err("%s(): File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk("%s: File has no READ operations registered!",
+ pr_err("%s(): File has no READ operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -340,9 +341,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
frame_offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Video file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+ __func__);
break;
}
}
@@ -366,8 +366,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
container_of(work, struct cx25821_dev, _irq_work_entry_ch2);
if (!dev) {
- printk("ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
+ pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
+ __func__);
return;
}
@@ -393,21 +393,20 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename_ch2, open_errno);
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename_ch2, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk("%s: File has no file operations registered!",
+ pr_err("%s(): File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk
- ("%s: File has no READ operations registered! Returning.",
- __func__);
+ pr_err("%s(): File has no READ operations registered! Returning\n",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -435,9 +434,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Video file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+ __func__);
break;
}
}
@@ -483,8 +481,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2;
if (!dev->_dma_virt_addr_ch2) {
- printk
- ("cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
+ pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
return -ENOMEM;
}
@@ -504,8 +501,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2;
if (!dev->_data_buf_virt_addr_ch2) {
- printk
- ("cx25821: FAILED to allocate memory for data buffer! Returning.\n");
+ pr_err("FAILED to allocate memory for data buffer! Returning\n");
return -ENOMEM;
}
@@ -521,8 +517,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
dev->_lines_count_ch2);
if (ret < 0) {
- printk(KERN_INFO
- "cx25821: Failed creating Video Upstream Risc programs!\n");
+ pr_info("Failed creating Video Upstream Risc programs!\n");
goto error;
}
@@ -602,8 +597,8 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
}
if (dev->_file_status_ch2 == END_OF_FILE) {
- printk("cx25821: EOF Channel 2 Framecount = %d\n",
- dev->_frame_count_ch2);
+ pr_info("EOF Channel 2 Framecount = %d\n",
+ dev->_frame_count_ch2);
return -1;
}
/* ElSE, set the interrupt mask register, re-enable irq. */
@@ -714,8 +709,8 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get upstream IRQ %d\n", dev->name,
- dev->pci->irq);
+ pr_err("%s: can't get upstream IRQ %d\n",
+ dev->name, dev->pci->irq);
goto fail_irq;
}
/* Start the DMA engine */
@@ -744,7 +739,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
int str_length = 0;
if (dev->_is_running_ch2) {
- printk("Video Channel is still running so return!\n");
+ pr_info("Video Channel is still running so return!\n");
return 0;
}
@@ -756,8 +751,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
create_singlethread_workqueue("cx25821_workqueue2");
if (!dev->_irq_queues_ch2) {
- printk
- ("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
+ pr_err("create_singlethread_workqueue() for Video FAILED!\n");
return -ENOMEM;
}
/*
@@ -829,8 +823,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
dev->_line_size_ch2);
if (retval < 0) {
- printk(KERN_ERR
- "%s: Failed to set up Video upstream buffers!\n",
+ pr_err("%s: Failed to set up Video upstream buffers!\n",
dev->name);
goto error;
}
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/staging/cx25821/cx25821-video-upstream.c
index 16bf74d65912..31b4e3c74c8d 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821-video.h"
#include "cx25821-video-upstream.h"
@@ -257,8 +259,7 @@ void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
u32 tmp = 0;
if (!dev->_is_running) {
- printk
- (KERN_INFO "cx25821: No video file is currently running so return!\n");
+ pr_info("No video file is currently running so return!\n");
return;
}
/* Disable RISC interrupts */
@@ -346,23 +347,20 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR
- "%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename, open_errno);
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR
- "%s: File has no file operations registered!",
- __func__);
+ pr_err("%s(): File has no file operations registered!\n",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk(KERN_ERR
- "%s: File has no READ operations registered!",
- __func__);
+ pr_err("%s(): File has no READ operations registered!\n",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -388,10 +386,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
frame_offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more bytes to \
- read from Video file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+ __func__);
break;
}
}
@@ -415,9 +411,8 @@ static void cx25821_vidups_handler(struct work_struct *work)
container_of(work, struct cx25821_dev, _irq_work_entry);
if (!dev) {
- printk(KERN_ERR
- "ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
+ pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
+ __func__);
return;
}
@@ -443,23 +438,20 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+ pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
__func__, dev->_filename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR
- "%s: File has no file operations registered!",
- __func__);
+ pr_err("%s(): File has no file operations registered!\n",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk(KERN_ERR
- "%s: File has no READ operations registered! \
- Returning.",
- __func__);
+ pr_err("%s(): File has no READ operations registered! Returning\n",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -487,10 +479,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
offset += vfs_read_retval;
if (vfs_read_retval < line_size) {
- printk(KERN_INFO
- "Done: exit %s() since no more \
- bytes to read from Video file.\n",
- __func__);
+ pr_info("Done: exit %s() since no more bytes to read from Video file\n",
+ __func__);
break;
}
}
@@ -534,9 +524,7 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
dev->_risc_size = dev->upstream_riscbuf_size;
if (!dev->_dma_virt_addr) {
- printk
- (KERN_ERR "cx25821: FAILED to allocate memory for Risc \
- buffer! Returning.\n");
+ pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
return -ENOMEM;
}
@@ -556,9 +544,7 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
dev->_data_buf_size = dev->upstream_databuf_size;
if (!dev->_data_buf_virt_addr) {
- printk
- (KERN_ERR "cx25821: FAILED to allocate memory for data \
- buffer! Returning.\n");
+ pr_err("FAILED to allocate memory for data buffer! Returning\n");
return -ENOMEM;
}
@@ -574,8 +560,7 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
dev->_lines_count);
if (ret < 0) {
- printk(KERN_INFO
- "cx25821: Failed creating Video Upstream Risc programs!\n");
+ pr_info("Failed creating Video Upstream Risc programs!\n");
goto error;
}
@@ -652,22 +637,20 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
spin_unlock(&dev->slock);
} else {
if (status & FLD_VID_SRC_UF)
- printk
- (KERN_ERR "%s: Video Received Underflow Error \
- Interrupt!\n", __func__);
+ pr_err("%s(): Video Received Underflow Error Interrupt!\n",
+ __func__);
if (status & FLD_VID_SRC_SYNC)
- printk(KERN_ERR "%s: Video Received Sync Error \
- Interrupt!\n", __func__);
+ pr_err("%s(): Video Received Sync Error Interrupt!\n",
+ __func__);
if (status & FLD_VID_SRC_OPC_ERR)
- printk(KERN_ERR "%s: Video Received OpCode Error \
- Interrupt!\n", __func__);
+ pr_err("%s(): Video Received OpCode Error Interrupt!\n",
+ __func__);
}
if (dev->_file_status == END_OF_FILE) {
- printk(KERN_ERR "cx25821: EOF Channel 1 Framecount = %d\n",
- dev->_frame_count);
+ pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count);
return -1;
}
/* ElSE, set the interrupt mask register, re-enable irq. */
@@ -775,8 +758,8 @@ int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
request_irq(dev->pci->irq, cx25821_upstream_irq,
IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get upstream IRQ %d\n", dev->name,
- dev->pci->irq);
+ pr_err("%s: can't get upstream IRQ %d\n",
+ dev->name, dev->pci->irq);
goto fail_irq;
}
@@ -806,7 +789,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
int str_length = 0;
if (dev->_is_running) {
- printk(KERN_INFO "Video Channel is still running so return!\n");
+ pr_info("Video Channel is still running so return!\n");
return 0;
}
@@ -817,9 +800,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
if (!dev->_irq_queues) {
- printk
- (KERN_ERR "cx25821: create_singlethread_workqueue() for \
- Video FAILED!\n");
+ pr_err("create_singlethread_workqueue() for Video FAILED!\n");
return -ENOMEM;
}
/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
@@ -895,8 +876,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
/* Allocating buffers and prepare RISC program */
retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size);
if (retval < 0) {
- printk(KERN_ERR
- "%s: Failed to set up Video upstream buffers!\n",
+ pr_err("%s: Failed to set up Video upstream buffers!\n",
dev->name);
goto error;
}
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index e7f1d5778cec..0d8d75670516 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -24,7 +24,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "cx25821-video.h"
+#include <linux/smp_lock.h>
MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
@@ -92,7 +95,7 @@ int cx25821_get_format_size(void)
return ARRAY_SIZE(formats);
}
-struct cx25821_fmt *format_by_fourcc(unsigned int fourcc)
+struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
@@ -104,7 +107,7 @@ struct cx25821_fmt *format_by_fourcc(unsigned int fourcc)
if (formats[i].fourcc == fourcc)
return formats + i;
- printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc);
+ pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc);
return NULL;
}
@@ -159,15 +162,15 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
else
mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
if (bc != 1)
- printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
+ pr_err("%s: %d buffers handled (should be 1)\n",
__func__, bc);
}
#ifdef TUNER_FLAG
int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
{
- dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__,
- (unsigned int)norm, v4l2_norm_to_name(norm));
+ dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
+ __func__, (unsigned int)norm, v4l2_norm_to_name(norm));
dev->tvnorm = norm;
@@ -267,7 +270,7 @@ int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
struct v4l2_routing route;
memset(&route, 0, sizeof(route));
- dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
+ dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
__func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
dev->input = input;
@@ -400,8 +403,8 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
/* risc op code error */
if (status & (1 << 16)) {
- printk(KERN_WARNING "%s, %s: video risc op code error\n",
- dev->name, channel->name);
+ pr_warn("%s, %s: video risc op code error\n",
+ dev->name, channel->name);
cx_clear(channel->dma_ctl, 0x11);
cx25821_sram_channel_dump(dev, channel);
}
@@ -458,7 +461,7 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
btcx_riscmem_free(dev->pci,
&dev->channels[chan_num].vidq.stopper);
- printk(KERN_WARNING "device %d released!\n", chan_num);
+ pr_warn("device %d released!\n", chan_num);
}
}
@@ -590,7 +593,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
init_buffer = 1;
rc = videobuf_iolock(q, &buf->vb, NULL);
if (0 != rc) {
- printk(KERN_DEBUG "videobuf_iolock failed!\n");
+ printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
goto fail;
}
}
@@ -848,7 +851,7 @@ static int video_open(struct file *file)
pix_format =
(dev->channels[ch_id].pixel_formats ==
PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
+ fh->fmt = cx25821_format_by_fourcc(pix_format);
v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
@@ -1010,7 +1013,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (0 != err)
return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
fh->vidq.field = f->fmt.pix.field;
/* check if width and height is valid based on set standard */
@@ -1038,8 +1041,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->channels[fh->channel_id].cif_width = fh->width;
medusa_set_resolution(dev, fh->width, SRAM_CH00);
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
+ dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width,
+ fh->height, fh->vidq.field);
v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
@@ -1070,14 +1073,14 @@ static int vidioc_log_status(struct file *file, void *priv)
u32 tmp = 0;
snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
+ pr_info("%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
cx25821_call_all(dev, core, log_status);
tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 0 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
+ pr_info("Video input 0 is %s\n",
+ (tmp & 0x11) ? "streaming" : "stopped");
+ pr_info("%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
return 0;
}
@@ -1119,7 +1122,7 @@ int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fo
enum v4l2_field field;
unsigned int maxw, maxh;
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
@@ -1186,34 +1189,6 @@ int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int cx25821_vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct cx25821_fh *fh = priv;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int err;
-
- q = get_queue(fh);
- memset(&req, 0, sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q, &req);
- if (err < 0)
- return err;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
-}
-#endif
-
int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
struct cx25821_fh *fh = priv;
@@ -1298,8 +1273,6 @@ int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i)
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]);
@@ -1319,7 +1292,7 @@ int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
*i = dev->input;
- dprintk(1, "%s() returns %d\n", __func__, *i);
+ dprintk(1, "%s(): returns %d\n", __func__, *i);
return 0;
}
@@ -1339,7 +1312,7 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
}
if (i > 2) {
- dprintk(1, "%s() -EINVAL\n", __func__);
+ dprintk(1, "%s(): -EINVAL\n", __func__);
return -EINVAL;
}
@@ -1390,7 +1363,7 @@ int cx25821_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_freque
if (0 != err)
return err;
} else {
- printk(KERN_ERR "Invalid fh pointer!\n");
+ pr_err("Invalid fh pointer!\n");
return -EINVAL;
}
@@ -1733,12 +1706,10 @@ static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
data_from_user = (struct upstream_user_struct *)arg;
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
+ if (!data_from_user) {
+ pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+ return 0;
+ }
command = data_from_user->command;
@@ -1776,12 +1747,10 @@ static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
data_from_user = (struct upstream_user_struct *)arg;
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
+ if (!data_from_user) {
+ pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+ return 0;
+ }
command = data_from_user->command;
@@ -1819,12 +1788,10 @@ static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
data_from_user = (struct upstream_user_struct *)arg;
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
+ if (!data_from_user) {
+ pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
+ return 0;
+ }
command = data_from_user->command;
@@ -1866,12 +1833,10 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
data_from_user = (struct downstream_user_struct *)arg;
- if (!data_from_user) {
- printk(
- "cx25821 in %s(): User data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
+ if (!data_from_user) {
+ pr_err("%s(): User data is INVALID. Returning\n", __func__);
+ return 0;
+ }
command = data_from_user->command;
@@ -2022,9 +1987,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_log_status = vidioc_log_status,
.vidioc_g_priority = cx25821_vidioc_g_priority,
.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
#ifdef TUNER_FLAG
.vidioc_g_tuner = cx25821_vidioc_g_tuner,
.vidioc_s_tuner = cx25821_vidioc_s_tuner,
diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h
index cc6034b1a95d..f4ee8051b8b3 100644
--- a/drivers/staging/cx25821/cx25821-video.h
+++ b/drivers/staging/cx25821/cx25821-video.h
@@ -40,19 +40,15 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* Include V4L1 specific functions. Should be removed soon */
-#include <linux/videodev.h>
-#endif
-
#define TUNER_FLAG
#define VIDEO_DEBUG 0
-#define dprintk(level, fmt, arg...)\
- do { if (VIDEO_DEBUG >= level)\
- printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
- } while (0)
+#define dprintk(level, fmt, arg...) \
+do { \
+ if (VIDEO_DEBUG >= level) \
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \
+} while (0)
/* For IOCTL to identify running upstream */
#define UPSTREAM_START_VIDEO 700
@@ -87,7 +83,7 @@ extern unsigned int vid_limit;
#define FORMAT_FLAGS_PACKED 0x01
extern struct cx25821_fmt formats[];
-extern struct cx25821_fmt *format_by_fourcc(unsigned int fourcc);
+extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
extern void cx25821_dump_video_queue(struct cx25821_dev *dev,
@@ -133,7 +129,6 @@ extern int cx25821_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap);
extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
-extern int cx25821_vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf);
extern int cx25821_vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p);
extern int cx25821_vidioc_querybuf(struct file *file, void *priv,
diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h
index c94000125782..55115235f7f6 100644
--- a/drivers/staging/cx25821/cx25821.h
+++ b/drivers/staging/cx25821/cx25821.h
@@ -519,9 +519,12 @@ extern struct sram_channel cx25821_sram_channels[];
#define Set_GPIO_Bit(Bit) (1 << Bit)
#define Clear_GPIO_Bit(Bit) (~(1 << Bit))
-#define CX25821_ERR(fmt, args...) printk(KERN_ERR "cx25821(%d): " fmt, dev->board, ## args)
-#define CX25821_WARN(fmt, args...) printk(KERN_WARNING "cx25821(%d): " fmt, dev->board , ## args)
-#define CX25821_INFO(fmt, args...) printk(KERN_INFO "cx25821(%d): " fmt, dev->board , ## args)
+#define CX25821_ERR(fmt, args...) \
+ pr_err("(%d): " fmt, dev->board, ##args)
+#define CX25821_WARN(fmt, args...) \
+ pr_warn("(%d): " fmt, dev->board, ##args)
+#define CX25821_INFO(fmt, args...) \
+ pr_info("(%d): " fmt, dev->board, ##args)
extern int cx25821_i2c_register(struct cx25821_i2c *bus);
extern void cx25821_card_setup(struct cx25821_dev *dev);
diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c
index dcbe6b628455..52224cdc967d 100644
--- a/drivers/staging/cxt1e1/comet.c
+++ b/drivers/staging/cxt1e1/comet.c
@@ -29,7 +29,7 @@
#endif
-extern int log_level;
+extern int cxt1e1_log_level;
#define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */
#define COMET_NUM_UNITS 5 /* Number of points per entry in table */
@@ -292,12 +292,12 @@ init_comet (void *ci, comet_t * comet, u_int32_t port_mode, int clockmaster,
* i.e.FPMODE=0 (@0x20) */
if ((moreParams & CFG_CLK_PORT_MASK) == CFG_CLK_PORT_INTERNAL)
{
- if (log_level >= LOG_SBEBUG12)
+ if (cxt1e1_log_level >= LOG_SBEBUG12)
pr_info(">> %s: clockmaster internal clock\n", __func__);
pci_write_32 ((u_int32_t *) &comet->tx_time, 0x0d); /* internal oscillator */
} else /* external clock source */
{
- if (log_level >= LOG_SBEBUG12)
+ if (cxt1e1_log_level >= LOG_SBEBUG12)
pr_info(">> %s: clockmaster external clock\n", __func__);
pci_write_32 ((u_int32_t *) &comet->tx_time, 0x09); /* loop timing
* (external) */
@@ -312,7 +312,7 @@ init_comet (void *ci, comet_t * comet, u_int32_t port_mode, int clockmaster,
pci_write_32 ((u_int32_t *) &comet->brif_cfg, 0x21); /* Slave Mode (CMODE=1) */
pci_write_32 ((u_int32_t *) &comet->brif_fpcfg, 0x20); /* Slave Mode i.e.
* FPMODE=1 (@0x20) */
- if (log_level >= LOG_SBEBUG12)
+ if (cxt1e1_log_level >= LOG_SBEBUG12)
pr_info(">> %s: clockslave internal clock\n", __func__);
pci_write_32 ((u_int32_t *) &comet->tx_time, 0x0d); /* oscillator timing */
}
diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c
index ab399c2f7488..d9a9aa3571d9 100644
--- a/drivers/staging/cxt1e1/functions.c
+++ b/drivers/staging/cxt1e1/functions.c
@@ -54,7 +54,7 @@ static int dummy = 0;
#endif
-extern int log_level;
+extern int cxt1e1_log_level;
extern int drvr_state;
@@ -67,7 +67,7 @@ pci_read_32 (u_int32_t *p)
FLUSH_PCI_READ ();
v = le32_to_cpu (*p);
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("pci_read : %x = %x\n", (u_int32_t) p, v);
return v;
#else
@@ -80,7 +80,7 @@ void
pci_write_32 (u_int32_t *p, u_int32_t v)
{
#ifdef FLOW_DEBUG
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("pci_write: %x = %x\n", (u_int32_t) p, v);
#endif
*p = cpu_to_le32 (v);
@@ -118,7 +118,7 @@ watchdog_func (unsigned long arg)
if (drvr_state != SBE_DRVR_AVAILABLE)
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state);
return;
}
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c
index 89200e7af26c..c517cc22f391 100644
--- a/drivers/staging/cxt1e1/hwprobe.c
+++ b/drivers/staging/cxt1e1/hwprobe.c
@@ -37,7 +37,7 @@
#define STATIC static
#endif
-extern int log_level;
+extern int cxt1e1_log_level;
extern int error_flag;
extern int drvr_state;
@@ -143,7 +143,7 @@ hdw_sn_get (hdw_info_t * hi, int brdno)
if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk)
{
/* bad crc, data is suspect */
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: EEPROM cksum error\n", hi->devname);
hi->mfg_info_sts = EEPROM_CRCERR;
} else
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index c7930287e3db..0f78f8962751 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -108,9 +108,9 @@ extern int unregister_hdlc_device_v7 (hdlc_device *);
#endif
int error_flag; /* module load error reporting */
-int log_level = LOG_ERROR;
+int cxt1e1_log_level = LOG_ERROR;
int log_level_default = LOG_ERROR;
-module_param(log_level, int, 0444);
+module_param(cxt1e1_log_level, int, 0444);
int cxt1e1_max_mru = MUSYCC_MRU;
int max_mru_default = MUSYCC_MRU;
@@ -497,7 +497,7 @@ create_chan (struct net_device * ndev, ci_t * ci,
rtnl_lock (); /* needed due to Ioctl calling sequence */
if (ret)
{
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: create_chan[%d] registration error = %d.\n",
ci->devname, cp->channum, ret);
free_netdev (dev); /* cleanup */
@@ -722,11 +722,11 @@ do_get_chan_stats (struct net_device * ndev, void *data)
STATIC status_t
do_set_loglevel (struct net_device * ndev, void *data)
{
- unsigned int log_level;
+ unsigned int cxt1e1_log_level;
- if (copy_from_user (&log_level, data, sizeof (int)))
+ if (copy_from_user (&cxt1e1_log_level, data, sizeof (int)))
return -EFAULT;
- sbecom_set_loglevel (log_level);
+ sbecom_set_loglevel (cxt1e1_log_level);
return 0;
}
@@ -1115,9 +1115,9 @@ c4_mod_init (void)
return -rtn; /* installation failure - see system log */
/* housekeeping notifications */
- if (log_level != log_level_default)
- pr_info("NOTE: driver parameter <log_level> changed from default %d to %d.\n",
- log_level_default, log_level);
+ if (cxt1e1_log_level != log_level_default)
+ pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n",
+ log_level_default, cxt1e1_log_level);
if (cxt1e1_max_mru != max_mru_default)
pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n",
max_mru_default, cxt1e1_max_mru);
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index fc15610f6974..f274c77fb3fc 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -97,7 +97,7 @@ char SBEid_pmcc4_musyccc[] =
/* global driver variables */
extern ci_t *c4_list;
extern int drvr_state;
-extern int log_level;
+extern int cxt1e1_log_level;
extern int cxt1e1_max_mru;
extern int cxt1e1_max_mtu;
@@ -627,7 +627,7 @@ rewrite:
if ((r != req) && (req != SR_CHIP_RESET) && (++rcnt <= MUSYCC_SR_RETRY_CNT))
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: %d - reissue srv req/last %x/%x (hdw reads %x), Chan %d.\n",
pi->up->devname, rcnt, req, pi->sr_last, r,
(pi->portnum * MUSYCC_NCHANS) + (req & 0x1f));
@@ -951,7 +951,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
ch = pi->chan[gchan];
if (ch == 0 || ch->state != UP)
{
- if (log_level >= LOG_ERROR)
+ if (cxt1e1_log_level >= LOG_ERROR)
pr_info("%s: intr: xmit EOM on uninitialized channel %d\n",
pi->up->devname, gchan);
}
@@ -1002,7 +1002,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
}
if (status & MUSYCC_TX_OWNED)
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
{
pr_info("%s: Port %d Chan %2d - unexpected TX msg ownership intr (md %p sts %x)\n",
pi->up->devname, pi->portnum, ch->channum,
@@ -1016,7 +1016,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
break; /* Not our mdesc, done */
} else
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: Port %d Chan %2d - recovered TX msg ownership [%d] (md %p sts %x)\n",
pi->up->devname, pi->portnum, ch->channum, readCount, md, status);
}
@@ -1054,7 +1054,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
}
md->status = 0;
#ifdef RLD_TXFULL_DEBUG
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
pr_info("~~ tx_eom: tx_full %x txd_free %d -> %d\n",
ch->tx_full, ch->txd_free, ch->txd_free + 1);
#endif
@@ -1063,7 +1063,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
if ((ch->p.chan_mode != CFG_CH_PROTO_TRANS) && (status & EOBIRQ_ENABLE))
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: Mode (%x) incorrect EOB status (%x)\n",
pi->up->devname, ch->p.chan_mode, status);
if ((status & EOMIRQ_ENABLE) == 0)
@@ -1094,7 +1094,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
{
#ifdef RLD_TXFULL_DEBUG
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
pr_info("tx_eom[%d]: enable xmit tx_full no more, txd_free %d txd_num/2 %d\n",
ch->channum,
ch->txd_free, ch->txd_num / 2);
@@ -1108,7 +1108,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan)
#ifdef RLD_TXFULL_DEBUG
else if (ch->tx_full)
{
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
pr_info("tx_eom[%d]: bypass TX enable though room available? (txd_free %d txd_num/2 %d)\n",
ch->channum,
ch->txd_free, ch->txd_num / 2);
@@ -1138,7 +1138,7 @@ musycc_bh_rx_eom (mpi_t * pi, int gchan)
ch = pi->chan[gchan];
if (ch == 0 || ch->state != UP)
{
- if (log_level > LOG_ERROR)
+ if (cxt1e1_log_level > LOG_ERROR)
pr_info("%s: intr: receive EOM on uninitialized channel %d\n",
pi->up->devname, gchan);
return;
@@ -1269,7 +1269,7 @@ musycc_intr_th_handler (void *devp)
if (nextInt != INTRPTS_NEXTINT (ci->intlog.this_status_new))
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
{
pr_info("%s: note - updated ISD from %08x to %08x\n",
ci->devname, status,
@@ -1337,11 +1337,11 @@ musycc_intr_th_handler (void *devp)
ci->intlog.last_status_new = ci->intlog.this_status_new;
ci->intlog.this_status_new = currInt;
- if ((log_level >= LOG_WARN) && (status & INTRPTS_INTFULL_M))
+ if ((cxt1e1_log_level >= LOG_WARN) && (status & INTRPTS_INTFULL_M))
{
pr_info("%s: Interrupt queue full condition occurred\n", ci->devname);
}
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("%s: interrupts pending, isd @ 0x%p: %x curr %d cnt %d NEXT %d\n",
ci->devname, &ci->reg->isd,
status, nextInt, intCnt, (intCnt + nextInt) & (INT_QUEUE_SIZE - 1));
@@ -1448,7 +1448,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
if ((currInt == badInt) || (currInt == badInt2)) /* catch failure of Bug
* Fix checking */
{
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: Illegal Interrupt Detected @ 0x%p, mod %d.)\n",
ci->devname, &ci->iqd_p[headx], headx);
@@ -1483,7 +1483,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
ci->iqd_p[headx] = __constant_cpu_to_le32 (INT_EMPTY_ENTRY);
FLUSH_MEM_WRITE ();
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
{
if (err != 0)
pr_info(" %08x -> err: %2d,", currInt, err);
@@ -1497,7 +1497,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
switch (event)
{
case EVE_SACK: /* Service Request Acknowledge */
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
{
volatile u_int32_t r;
@@ -1534,7 +1534,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
}
break;
default:
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: unexpected interrupt event: %d, iqd[%d]: %08x, port: %d\n", ci->devname,
event, headx, currInt, group);
break;
@@ -1573,9 +1573,9 @@ musycc_intr_bh_tasklet (ci_t * ci)
{
#ifdef RLD_TRANS_DEBUG
- if (1 || log_level >= LOG_MONITOR)
+ if (1 || cxt1e1_log_level >= LOG_MONITOR)
#else
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
#endif
{
pr_info("%s: TX buffer underflow [ONR] on channel %d, mode %x QStopped %x free %d\n",
@@ -1605,7 +1605,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
ch->s.rx_over_errors++;
ch->ch_start_rx = CH_START_RX_ONR;
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
{
pr_info("%s: RX buffer overflow [ONR] on channel %d, mode %x\n",
ci->devname, ch->channum, ch->p.chan_mode);
@@ -1623,7 +1623,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
* Per MUSYCC manual, Section 6.4.8.3 [Transmit Errors],
* this BUFF error requires Transmit channel reactivation.
*/
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: TX buffer underrun [BUFF] on channel %d, mode %x\n",
ci->devname, ch->channum, ch->p.chan_mode);
} else /* RX buffer overrun */
@@ -1636,7 +1636,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
* space for this channel. Receive channel reactivation is
* not required, but data has been lost.
*/
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: RX buffer overrun [BUFF] on channel %d, mode %x\n",
ci->devname, ch->channum, ch->p.chan_mode);
/*
@@ -1658,7 +1658,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
} /* switch on err */
/* Check for interrupt lost condition */
- if ((currInt & INTRPT_ILOST_M) && (log_level >= LOG_ERROR))
+ if ((currInt & INTRPT_ILOST_M) && (cxt1e1_log_level >= LOG_ERROR))
{
pr_info("%s: Interrupt queue overflow - ILOST asserted\n",
ci->devname);
@@ -1667,7 +1667,7 @@ musycc_intr_bh_tasklet (ci_t * ci)
FLUSH_MEM_WRITE ();
FLUSH_MEM_READ ();
} /* while */
- if ((log_level >= LOG_MONITOR2) && (ci->iqp_headx != ci->iqp_tailx))
+ if ((cxt1e1_log_level >= LOG_MONITOR2) && (ci->iqp_headx != ci->iqp_tailx))
{
int bh;
@@ -1821,9 +1821,9 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
return EROFS; /* how else to flag unwritable state ? */
#ifdef RLD_TRANS_DEBUGx
- if (1 || log_level >= LOG_MONITOR2)
+ if (1 || cxt1e1_log_level >= LOG_MONITOR2)
#else
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
#endif
{
pr_info("++ start_xmt[%d]: state %x start %x full %d free %d required %d stopped %x\n",
@@ -1846,7 +1846,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
if (txd_need_cnt == 0)
{
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
pr_info("%s channel %d: no TX data in User buffer\n", ci->devname, channum);
OS_mem_token_free (mem_token);
return 0; /* no data to send */
@@ -1857,7 +1857,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
if (txd_need_cnt > ch->txd_num) /* never enough descriptors for this
* large a buffer */
{
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
{
pr_info("start_xmit: discarding buffer, insufficient descriptor cnt %d, need %d.\n",
ch->txd_num, txd_need_cnt + 1);
@@ -1874,7 +1874,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
/************************************************************/
if (txd_need_cnt > ch->txd_free)
{
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
{
pr_info("start_xmit[%d]: EBUSY - need more descriptors, have %d of %d need %d\n",
channum, ch->txd_free, ch->txd_num, txd_need_cnt);
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index 5c8a3eb0cfc3..341e7a92f099 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -135,7 +135,7 @@ void musycc_serv_req (mpi_t *, u_int32_t);
void musycc_update_timeslots (mpi_t *);
extern void musycc_update_tx_thp (mch_t *);
-extern int log_level;
+extern int cxt1e1_log_level;
extern int cxt1e1_max_mru;
extern int cxt1e1_max_mtu;
extern int max_rxdesc_used, max_rxdesc_default;
@@ -168,12 +168,12 @@ sbecom_set_loglevel (int d)
* for card 0 only */
} else
{
- if (log_level != d)
+ if (cxt1e1_log_level != d)
{
- pr_info("log level changed from %d to %d\n", log_level, d);
- log_level = d; /* set new */
+ pr_info("log level changed from %d to %d\n", cxt1e1_log_level, d);
+ cxt1e1_log_level = d; /* set new */
} else
- pr_info("log level is %d\n", log_level);
+ pr_info("log level is %d\n", cxt1e1_log_level);
}
}
@@ -513,7 +513,7 @@ checkPorts (ci_t * ci)
if ((value == 0x1c) || (value == 0x19) || (value == 0x12))
c4_loop_port (ci, portnum, COMET_MDIAG_LBOFF); /* take port out of any
* loopbk mode */
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
if (value != 0x3f)
pr_warning("%s: BOC value = %x on Port %d\n",
ci->devname, value, portnum);
@@ -533,7 +533,7 @@ c4_watchdog (ci_t * ci)
{
if (drvr_state != SBE_DRVR_AVAILABLE)
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("drvr not available (%x)\n", drvr_state);
return;
}
@@ -794,19 +794,19 @@ c4_loop_port (ci_t * ci, int portnum, u_int8_t cmd)
}
pci_write_32 ((u_int32_t *) &comet->mdiag, cmd);
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: loopback mode changed to %2x from %2x on Port %d\n",
ci->devname, cmd, loopValue, portnum);
loopValue = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK;
if (loopValue != cmd)
{
- if (log_level >= LOG_ERROR)
+ if (cxt1e1_log_level >= LOG_ERROR)
pr_info("%s: write to loop register failed, unknown state for Port %d\n",
ci->devname, portnum);
}
} else
{
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: loopback already in that mode (%2x)\n",
ci->devname, loopValue);
}
@@ -997,7 +997,7 @@ c4_set_port (ci_t * ci, int portnum)
pi = &ci->port[portnum];
pp = &ci->port[portnum].p;
e1mode = IS_FRAME_ANY_E1 (pp->port_mode);
- if (log_level >= LOG_MONITOR2)
+ if (cxt1e1_log_level >= LOG_MONITOR2)
{
pr_info("%s: c4_set_port[%d]: entered, e1mode = %x, openchans %d.\n",
ci->devname,
@@ -1278,12 +1278,12 @@ c4_fifo_alloc (mpi_t * pi, int chan, int *len)
}
if (max != *len)
{
- if (log_level >= LOG_WARN)
+ if (cxt1e1_log_level >= LOG_WARN)
pr_info("%s: wanted to allocate %d fifo space, but got only %d\n",
pi->up->devname, *len, max);
*len = max;
}
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("%s: allocated %d fifo at %d for channel %d/%d\n",
pi->up->devname, max, start, chan, pi->p.portnum);
for (i = maxstart; i < (maxstart + max); i++)
@@ -1296,7 +1296,7 @@ c4_fifo_free (mpi_t * pi, int chan)
{
int i;
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("%s: deallocated fifo for channel %d/%d\n",
pi->up->devname, chan, pi->p.portnum);
for (i = 0; i < 32; i++)
@@ -1321,7 +1321,7 @@ c4_chan_up (ci_t * ci, int channum)
return ENOENT;
if (ch->state == UP)
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: channel already UP, graceful early exit\n",
ci->devname);
return 0;
@@ -1334,7 +1334,7 @@ c4_chan_up (ci_t * ci, int channum)
{
if (ch->p.bitmask[i] & pi->tsm[i])
{
- if (1 || log_level >= LOG_WARN)
+ if (1 || cxt1e1_log_level >= LOG_WARN)
{
pr_info("%s: c4_chan_up[%d] EINVAL (attempt to cfg in-use or unavailable TimeSlot[%d])\n",
ci->devname, channum, i);
@@ -1351,7 +1351,7 @@ c4_chan_up (ci_t * ci, int channum)
nbuf = nts / 8 ? nts / 8 : 1;
if (!nbuf)
{
- /* if( log_level >= LOG_WARN) */
+ /* if( cxt1e1_log_level >= LOG_WARN) */
pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n",
ci->devname, channum);
return ENOBUFS; /* this should not happen */
@@ -1420,7 +1420,7 @@ c4_chan_up (ci_t * ci, int channum)
#if 0
/* DEBUG INFO */
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: mode %x rxnum %d (rxused %d def %d) txnum %d (txused %d def %d)\n",
ci->devname, ch->p.chan_mode,
rxnum, max_rxdesc_used, max_rxdesc_default,
@@ -1451,7 +1451,7 @@ c4_chan_up (ci_t * ci, int channum)
if (!(m = OS_mem_token_alloc (cxt1e1_max_mru)))
{
- if (log_level >= LOG_MONITOR)
+ if (cxt1e1_log_level >= LOG_MONITOR)
pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n",
ci->devname, channum, cxt1e1_max_mru);
goto errfree;
diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h
index 5a72cb5cff42..501a331ded5b 100644
--- a/drivers/staging/cxt1e1/sbecom_inline_linux.h
+++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h
@@ -86,7 +86,7 @@ pci_read_32 (u_int32_t *p)
FLUSH_PCI_READ ();
v = le32_to_cpu (*p);
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("pci_read : %x = %x\n", (u_int32_t) p, v);
return v;
#else
@@ -99,7 +99,7 @@ static inline void
pci_write_32 (u_int32_t *p, u_int32_t v)
{
#ifdef FLOW_DEBUG
- if (log_level >= LOG_DEBUG)
+ if (cxt1e1_log_level >= LOG_DEBUG)
pr_info("pci_write: %x = %x\n", (u_int32_t) p, v);
#endif
*p = cpu_to_le32 (v);
diff --git a/drivers/staging/dabusb/Kconfig b/drivers/staging/dabusb/Kconfig
new file mode 100644
index 000000000000..87bdc425d3c5
--- /dev/null
+++ b/drivers/staging/dabusb/Kconfig
@@ -0,0 +1,14 @@
+config USB_DABUSB
+ tristate "DABUSB driver"
+ depends on USB
+ ---help---
+ A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
+ brought to you by the DAB-Team
+ <http://wwwbode.cs.tum.edu/Par/arch/dab/>. This driver can be taken
+ as an example for URB-based bulk, control, and isochronous
+ transactions. URB's are explained in
+ <Documentation/usb/URB.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dabusb.
+
diff --git a/drivers/staging/dabusb/Makefile b/drivers/staging/dabusb/Makefile
new file mode 100644
index 000000000000..2ff2f228e5f9
--- /dev/null
+++ b/drivers/staging/dabusb/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_USB_DABUSB) += dabusb.o
+
diff --git a/drivers/staging/dabusb/TODO b/drivers/staging/dabusb/TODO
new file mode 100644
index 000000000000..f9c0314ea0c1
--- /dev/null
+++ b/drivers/staging/dabusb/TODO
@@ -0,0 +1,5 @@
+This is a driver for an experimental sample developed in 2003. The driver
+never supported any commercial product, nor had any known user.
+If nobody takes care on it, the driver will be removed for 2.6.39.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/media/video/dabusb.c b/drivers/staging/dabusb/dabusb.c
index f3e25e91366d..f3e25e91366d 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/staging/dabusb/dabusb.c
diff --git a/drivers/media/video/dabusb.h b/drivers/staging/dabusb/dabusb.h
index 00eb34c863eb..00eb34c863eb 100644
--- a/drivers/media/video/dabusb.h
+++ b/drivers/staging/dabusb/dabusb.h
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c
index b996697e7eb2..15d7efeed292 100644
--- a/drivers/staging/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/dt3155v4l/dt3155v4l.c
@@ -876,9 +876,6 @@ static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
.vidioc_s_crop = dt3155_ioc_s_crop,
.vidioc_enum_framesizes = dt3155_ioc_enum_framesizes,
.vidioc_enum_frameintervals = dt3155_ioc_enum_frameintervals,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = iocgmbuf,
-#endif
*/
};
diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig
index 9d5fe4ddc30a..bd96f39f2735 100644
--- a/drivers/staging/easycap/Kconfig
+++ b/drivers/staging/easycap/Kconfig
@@ -1,7 +1,6 @@
config EASYCAP
tristate "EasyCAP USB ID 05e1:0408 support"
depends on USB && VIDEO_DEV
- depends on BKL # please fix
---help---
This is an integrated audio/video driver for EasyCAP cards with
diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/easycap/Makefile
index 8a3d911aee5d..f1f2fbebf8f6 100644
--- a/drivers/staging/easycap/Makefile
+++ b/drivers/staging/easycap/Makefile
@@ -10,4 +10,5 @@ ccflags-y := -Wall
ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT
ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H
ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS
+ccflags-y += -DEASYCAP_NEEDS_UNLOCKED_IOCTL
diff --git a/drivers/staging/easycap/README b/drivers/staging/easycap/README
index 3775481f05e8..6b5ac0d34bd9 100644
--- a/drivers/staging/easycap/README
+++ b/drivers/staging/easycap/README
@@ -24,6 +24,9 @@ Two kinds of EasyCAP have this USB ID, namely:
BUILD OPTIONS AND DEPENDENCIES
------------------------------
+Unless EASYCAP_DEBUG is defined during compilation it will not be possible
+to select a debug level at the time of module installation.
+
If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation
the built module is entirely independent of the videodev module, and when
the EasyCAP is physically plugged into a USB port the special files
@@ -33,41 +36,54 @@ respectively.
If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation
the built easycap module is configured to register with the videodev module,
in which case the special files created when the EasyCAP is plugged in are
-/dev/video0 and /dev/easysnd0. Use of the easycap module as a client of
-the videodev module has received very little testing as of June 2010.
+/dev/video0 and /dev/easysnd0.
+
+During in-tree builds the following should should be defined whenever the
+parameter EASYCAP_IS_VIDEODEV_CLIENT is defined:
+
+EASYCAP_NEEDS_V4L2_DEVICE_H
+EASYCAP_NEEDS_V4L2_FOPS
+EASYCAP_NEEDS_UNLOCKED_IOCTL
+
+If the build is performed out-of-tree against older kernels the parameters
+to be defined depend on the kernel version in a way which will not be
+discussed here.
-KNOWN BUILD PROBLEMS
+KNOWN RUNTIME ISSUES
--------------------
-(1) Recent gcc versions may generate the message:
+(1) Intentionally, this driver will not stream material which is unambiguously
+identified by the hardware as copy-protected. Normal video output will be
+present for about a minute but will then freeze when this situation arises.
- warning: the frame size of .... bytes is larger than 1024 bytes
+(2) The controls for luminance, contrast, saturation, hue and volume may not
+always work properly.
-This warning can be suppressed by specifying in the Makefile:
+(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
- EXTRA_CFLAGS += -Wframe-larger-than=8192
-but it would be preferable to remove the cause of the warning.
+INPUT NUMBERING
+---------------
+For the EasyCAP with S-VIDEO input cable the driver regards a request for
+inputs numbered 0 or 1 as referring to CVBS and a request for input
+numbered 5 as referring to S-VIDEO.
-KNOWN RUNTIME ISSUES
---------------------
+For the EasyCAP with four CVBS inputs the driver expects to be asked for
+any one of inputs numbered 1,2,3,4. If input 0 is asked for, it is
+interpreted as input 1.
-(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any
-output at start-up. Closing mplayer (or whatever the user program is) and
-restarting it restores normal performance without any other remedial action
-being necessary. The reason for this is not known.
-(2) Intentionally, this driver will not stream material which is unambiguously
-identified by the hardware as copy-protected. The video output will freeze
-within about a minute when this situation arises.
+MODULE PARAMETERS
+-----------------
-(3) The controls for luminance, contrast, saturation, hue and volume may not
-always work properly.
+Three module parameters are defined:
-(4) Reduced-resolution S-Video seems to suffer from moire artefacts. No
-attempt has yet been made to rememdy this.
+debug the easycap module is configured at diagnostic level n (0 to 9)
+gain audio gain level n (0 to 31, default is 16)
+bars 0 => testcard bars when incoming video signal is lost
+ 1 => testcard bars when incoming video signal is lost (default)
SUPPORTED TV STANDARDS AND RESOLUTIONS
@@ -82,18 +98,29 @@ usable as (for example) the "norm=" parameter in the mplayer command:
PAL_60, NTSC_443,
PAL_M.
+In addition, the driver offers "custom" pseudo-standards with a framerate
+which is 20% of the usual framerate. These pseudo-standards are named:
+
+ PAL_BGHIN_SLOW, NTSC_N_443_SLOW,
+ PAL_Nc_SLOW, NTSC_N_SLOW,
+ SECAM_SLOW, NTSC_M_SLOW, NTSC_M_JP_SLOW,
+ PAL_60_SLOW, NTSC_443_SLOW,
+ PAL_M_SLOW.
+
+
The available picture sizes are:
at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240;
- at 30 frames per second: 720x480, 640x480, 360x240, 320x240;
+ at 30 frames per second: 720x480, 640x480, 360x240, 320x240.
WHAT'S TESTED AND WHAT'S NOT
----------------------------
-This driver is known to work with mplayer, mencoder, tvtime and sufficiently
-recent versions of vlc. An interface to ffmpeg is implemented, but serious
-audio-video synchronization problems remain.
+This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
+xawtv, gstreamer and sufficiently recent versions of vlc. An interface
+to ffmpeg is implemented, but serious audio-video synchronization problems
+remain.
The driver is designed to support all the TV standards accepted by the
hardware, but as yet it has actually been tested on only a few of these.
@@ -101,10 +128,7 @@ hardware, but as yet it has actually been tested on only a few of these.
I have been unable to test and calibrate the S-video input myself because I
do not possess any equipment with S-video output.
-This driver does not understand the V4L1 IOCTL commands, so programs such
-as camorama are not compatible. There are reports that the driver does
-work with sufficiently recent (V4L2) versions of zoneminder, but I have not
-attempted to confirm this myself.
+This driver does not understand the V4L1 IOCTL commands.
UDEV RULES
@@ -120,6 +144,17 @@ ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
LABEL="easycap_rules_end"
+MODPROBE CONFIGURATION
+----------------------
+
+The easycap module is in competition with the module snd-usb-audio for the
+EasyCAP's audio channel, and its installation can be aided by providing a
+file in directory /etc/modprobe.d with content:
+
+options easycap gain=16 bars=1
+install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
+
+
ACKNOWLEGEMENTS AND REFERENCES
------------------------------
This driver makes use of information contained in the Syntek Semicon DC-1125
diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
index f3c827eb0abe..8ebf96f8a242 100644
--- a/drivers/staging/easycap/easycap.h
+++ b/drivers/staging/easycap/easycap.h
@@ -33,6 +33,7 @@
* EASYCAP_NEEDS_USBVIDEO_H
* EASYCAP_NEEDS_V4L2_DEVICE_H
* EASYCAP_NEEDS_V4L2_FOPS
+ * EASYCAP_NEEDS_UNLOCKED_IOCTL
*
* IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
* OPTIONS.
@@ -42,42 +43,31 @@
#if (!defined(EASYCAP_H))
#define EASYCAP_H
-#if defined(EASYCAP_DEBUG)
-#if (9 < EASYCAP_DEBUG)
-#error Debug levels 0 to 9 are okay.\
- To achieve higher levels, remove this trap manually from easycap.h
-#endif
-#endif /*EASYCAP_DEBUG*/
+/*---------------------------------------------------------------------------*/
+/*
+ * THESE ARE NORMALLY DEFINED
+ */
+/*---------------------------------------------------------------------------*/
+#define PATIENCE 500
+#undef PREFER_NTSC
+#define PERSEVERE
/*---------------------------------------------------------------------------*/
/*
* THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
*/
/*---------------------------------------------------------------------------*/
-#undef PREFER_NTSC
#undef EASYCAP_TESTCARD
#undef EASYCAP_TESTTONE
-#undef LOCKFRAME
#undef NOREADBACK
#undef AUDIOTIME
/*---------------------------------------------------------------------------*/
-/*
- *
- * DEFINE BRIDGER TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS.
- *
- * *** UNDER DEVELOPMENT/TESTING - NOT READY YET!***
- *
- */
-/*---------------------------------------------------------------------------*/
-#undef BRIDGER
-/*---------------------------------------------------------------------------*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/kref.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/uaccess.h>
@@ -92,25 +82,14 @@
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
-#if (!defined(__OLD_VIDIOC_))
-#define __OLD_VIDIOC_
-#endif /* !defined(__OLD_VIDIOC_) */
-
#include <media/v4l2-dev.h>
-
#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
#include <media/v4l2-device.h>
#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
-#if (!defined(__OLD_VIDIOC_))
-#define __OLD_VIDIOC_
-#endif /* !defined(__OLD_VIDIOC_) */
#include <linux/videodev2.h>
-
#include <linux/soundcard.h>
-
#if defined(EASYCAP_NEEDS_USBVIDEO_H)
#include <config/video/usbvideo.h>
#endif /*EASYCAP_NEEDS_USBVIDEO_H*/
@@ -121,7 +100,6 @@
#define STRINGIZE_AGAIN(x) #x
#define STRINGIZE(x) STRINGIZE_AGAIN(x)
-
/*---------------------------------------------------------------------------*/
/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd
*
@@ -135,12 +113,12 @@
#define USB_EASYCAP_VENDOR_ID 0x05e1
#define USB_EASYCAP_PRODUCT_ID 0x0408
-#define EASYCAP_DRIVER_VERSION "0.8.21"
+#define EASYCAP_DRIVER_VERSION "0.8.41"
#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
#define USB_SKEL_MINOR_BASE 192
-#define VIDEO_DEVICE_MANY 8
-
+#define DONGLE_MANY 8
+#define INPUT_MANY 6
/*---------------------------------------------------------------------------*/
/*
* DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
@@ -164,6 +142,8 @@
#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
#error video_isoc_buffer[.] will not be big enough
#endif
+#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
+#define VIDEO_LOST_TOLERATE 50
/*---------------------------------------------------------------------------*/
/*
* VIDEO BUFFERS
@@ -210,7 +190,17 @@
#define NTSC_M_JP 5
#define PAL_60 7
#define PAL_M 9
-#define STANDARD_MANY 10
+#define PAL_BGHIN_SLOW 10
+#define PAL_Nc_SLOW 12
+#define SECAM_SLOW 14
+#define NTSC_N_SLOW 16
+#define NTSC_N_443_SLOW 18
+#define NTSC_M_SLOW 11
+#define NTSC_443_SLOW 13
+#define NTSC_M_JP_SLOW 15
+#define PAL_60_SLOW 17
+#define PAL_M_SLOW 19
+#define STANDARD_MANY 20
/*---------------------------------------------------------------------------*/
/*
* ENUMS
@@ -238,7 +228,6 @@ PIXELFORMAT_MANY
enum {
FIELD_NONE,
FIELD_INTERLACED,
-FIELD_ALTERNATE,
INTERLACE_MANY
};
#define SETTINGS_MANY (STANDARD_MANY * \
@@ -251,11 +240,18 @@ INTERLACE_MANY
* STRUCTURE DEFINITIONS
*/
/*---------------------------------------------------------------------------*/
+struct easycap_dongle {
+struct easycap *peasycap;
+struct mutex mutex_video;
+struct mutex mutex_audio;
+};
+/*---------------------------------------------------------------------------*/
struct data_buffer {
struct list_head list_head;
void *pgo;
void *pto;
__u16 kount;
+__u16 input;
};
/*---------------------------------------------------------------------------*/
struct data_urb {
@@ -274,6 +270,22 @@ __u16 mask;
char name[128];
struct v4l2_format v4l2_format;
};
+struct inputset {
+int input;
+int input_ok;
+int standard_offset;
+int standard_offset_ok;
+int format_offset;
+int format_offset_ok;
+int brightness;
+int brightness_ok;
+int contrast;
+int contrast_ok;
+int saturation;
+int saturation_ok;
+int hue;
+int hue_ok;
+};
/*---------------------------------------------------------------------------*/
/*
* easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
@@ -282,6 +294,19 @@ struct v4l2_format v4l2_format;
*/
/*---------------------------------------------------------------------------*/
struct easycap {
+#define TELLTALE "expectedstring"
+char telltale[16];
+int isdongle;
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+struct video_device video_device;
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+struct v4l2_device v4l2_device;
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+int status;
unsigned int audio_pages_per_fragment;
unsigned int audio_bytes_per_fragment;
unsigned int audio_buffer_page_many;
@@ -291,26 +316,14 @@ unsigned int audio_buffer_page_many;
__s16 oldaudio;
#endif /*UPSAMPLE*/
-struct easycap_format easycap_format[1 + SETTINGS_MANY];
-
int ilk;
bool microphone;
-/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
-struct video_device *pvideo_device;
-#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
struct usb_device *pusb_device;
struct usb_interface *pusb_interface;
struct kref kref;
-struct mutex mutex_mmap_video[FRAME_BUFFER_MANY];
-struct mutex mutex_timeval0;
-struct mutex mutex_timeval1;
-
int queued[FRAME_BUFFER_MANY];
int done[FRAME_BUFFER_MANY];
@@ -321,16 +334,24 @@ int input;
int polled;
int standard_offset;
int format_offset;
+struct inputset inputset[INPUT_MANY];
+bool ntsc;
int fps;
int usec;
int tolerate;
+int skip;
+int skipped;
+int lost[INPUT_MANY];
int merit[180];
struct timeval timeval0;
struct timeval timeval1;
struct timeval timeval2;
+struct timeval timeval3;
+struct timeval timeval6;
struct timeval timeval7;
+struct timeval timeval8;
long long int dnbydt;
int video_interface;
@@ -347,8 +368,6 @@ int video_idle;
int video_eof;
int video_junk;
-int fudge;
-
struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
struct data_buffer \
field_buffer[FIELD_BUFFER_MANY][(FIELD_BUFFER_SIZE/PAGE_SIZE)];
@@ -358,6 +377,13 @@ struct data_buffer \
struct list_head urb_video_head;
struct list_head *purb_video_head;
+__u8 cache[8];
+__u8 *pcache;
+int video_mt;
+int audio_mt;
+long long audio_bytes;
+__u32 isequence;
+
int vma_many;
/*---------------------------------------------------------------------------*/
@@ -383,7 +409,6 @@ int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */
*/
/*---------------------------------------------------------------------------*/
__u32 pixelformat;
-__u32 field;
int width;
int height;
int bytesperpixel;
@@ -463,8 +488,10 @@ struct data_buffer audio_buffer[];
void easycap_complete(struct urb *);
int easycap_open(struct inode *, struct file *);
int easycap_release(struct inode *, struct file *);
-long easycap_ioctl(struct file *, unsigned int, unsigned long);
-
+long easycap_ioctl_noinode(struct file *, unsigned int, \
+ unsigned long);
+int easycap_ioctl(struct inode *, struct file *, unsigned int, \
+ unsigned long);
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
int easycap_open_noinode(struct file *);
@@ -489,12 +516,10 @@ int kill_video_urbs(struct easycap *);
int field2frame(struct easycap *);
int redaub(struct easycap *, void *, void *, \
int, int, __u8, __u8, bool);
-void debrief(struct easycap *);
-void sayreadonly(struct easycap *);
void easycap_testcard(struct easycap *, int);
-int explain_ioctl(__u32);
-int explain_cid(__u32);
int fillin_formats(void);
+int reset(struct easycap *);
+int newinput(struct easycap *, int);
int adjust_standard(struct easycap *, v4l2_std_id);
int adjust_format(struct easycap *, __u32, __u32, __u32, \
int, bool);
@@ -512,7 +537,10 @@ void easysnd_complete(struct urb *);
ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);
int easysnd_open(struct inode *, struct file *);
int easysnd_release(struct inode *, struct file *);
-long easysnd_ioctl(struct file *, unsigned int, unsigned long);
+long easysnd_ioctl_noinode(struct file *, unsigned int, \
+ unsigned long);
+int easysnd_ioctl(struct inode *, struct file *, unsigned int, \
+ unsigned long);
unsigned int easysnd_poll(struct file *, poll_table *);
void easysnd_delete(struct kref *);
int submit_audio_urbs(struct easycap *);
@@ -532,11 +560,11 @@ int wakeup_device(struct usb_device *);
int confirm_resolution(struct usb_device *);
int confirm_stream(struct usb_device *);
-int setup_stk(struct usb_device *);
-int setup_saa(struct usb_device *);
+int setup_stk(struct usb_device *, bool);
+int setup_saa(struct usb_device *, bool);
int setup_vt(struct usb_device *);
-int check_stk(struct usb_device *);
-int check_saa(struct usb_device *);
+int check_stk(struct usb_device *, bool);
+int check_saa(struct usb_device *, bool);
int ready_saa(struct usb_device *);
int merit_saa(struct usb_device *);
int check_vt(struct usb_device *);
@@ -554,12 +582,9 @@ int stop_100(struct usb_device *);
int write_300(struct usb_device *);
int read_vt(struct usb_device *, __u16);
int write_vt(struct usb_device *, __u16, __u16);
-
-int set2to78(struct usb_device *);
-int set2to93(struct usb_device *);
-
int regset(struct usb_device *, __u16, __u16);
int regget(struct usb_device *, __u16, void *);
+int isdongle(struct easycap *);
/*---------------------------------------------------------------------------*/
struct signed_div_result {
long long int quotient;
@@ -587,24 +612,41 @@ unsigned long long int remainder;
} \
} while (0)
/*---------------------------------------------------------------------------*/
-
+/*
+ * MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
+ * THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
+ * POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
+ * IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE. BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
#define SAY(format, args...) do { \
- printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+ printk(KERN_DEBUG "easycap:: %s: " \
+ format, __func__, ##args); \
+} while (0)
+#define SAM(format, args...) do { \
+ printk(KERN_DEBUG "easycap::%i%s: " \
+ format, peasycap->isdongle, __func__, ##args);\
} while (0)
-
#if defined(EASYCAP_DEBUG)
#define JOT(n, format, args...) do { \
if (n <= easycap_debug) { \
- printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+ printk(KERN_DEBUG "easycap:: %s: " \
+ format, __func__, ##args);\
} \
} while (0)
+#define JOM(n, format, args...) do { \
+ if (n <= easycap_debug) { \
+ printk(KERN_DEBUG "easycap::%i%s: " \
+ format, peasycap->isdongle, __func__, ##args);\
+ } \
+} while (0)
+
#else
#define JOT(n, format, args...) do {} while (0)
+#define JOM(n, format, args...) do {} while (0)
#endif /*EASYCAP_DEBUG*/
-#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__)
-
#define MICROSECONDS(X, Y) \
((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \
(long long int)(X.tv_usec - Y.tv_usec))
diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h
index 1d10d7ea7d68..b6b571843125 100644
--- a/drivers/staging/easycap/easycap_debug.h
+++ b/drivers/staging/easycap/easycap_debug.h
@@ -25,3 +25,5 @@
*/
/*****************************************************************************/
extern int easycap_debug;
+extern int easycap_gain;
+extern struct easycap_dongle easycap_dongle[];
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c
index 9a42ae02cd5d..447953a4e80c 100644
--- a/drivers/staging/easycap/easycap_ioctl.c
+++ b/drivers/staging/easycap/easycap_ioctl.c
@@ -36,53 +36,101 @@
* UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
* FOLLOWING:
* peasycap->standard_offset
+ * peasycap->inputset[peasycap->input].standard_offset
* peasycap->fps
* peasycap->usec
* peasycap->tolerate
+ * peasycap->skip
*/
/*---------------------------------------------------------------------------*/
int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
{
struct easycap_standard const *peasycap_standard;
__u16 reg, set;
-int ir, rc, need;
+int ir, rc, need, k;
unsigned int itwas, isnow;
+bool resubmit;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
peasycap_standard = &easycap_standard[0];
while (0xFFFF != peasycap_standard->mask) {
- if (std_id & peasycap_standard->v4l2_standard.id)
+ if (std_id == peasycap_standard->v4l2_standard.id)
break;
peasycap_standard++;
}
if (0xFFFF == peasycap_standard->mask) {
- SAY("ERROR: 0x%08X=std_id: standard not found\n", \
+ peasycap_standard = &easycap_standard[0];
+ while (0xFFFF != peasycap_standard->mask) {
+ if (std_id & peasycap_standard->v4l2_standard.id)
+ break;
+ peasycap_standard++;
+ }
+}
+if (0xFFFF == peasycap_standard->mask) {
+ SAM("ERROR: 0x%08X=std_id: standard not found\n", \
(unsigned int)std_id);
return -EINVAL;
}
-SAY("user requests standard: %s\n", \
+SAM("selected standard: %s\n", \
&(peasycap_standard->v4l2_standard.name[0]));
if (peasycap->standard_offset == \
(int)(peasycap_standard - &easycap_standard[0])) {
- SAY("requested standard already in effect\n");
+ SAM("requested standard already in effect\n");
return 0;
}
peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]);
+for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].standard_offset_ok) {
+ peasycap->inputset[k].standard_offset = \
+ peasycap->standard_offset;
+ }
+}
+if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].standard_offset = \
+ peasycap->standard_offset;
+ peasycap->inputset[peasycap->input].standard_offset_ok = 1;
+} else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
peasycap_standard->v4l2_standard.frameperiod.numerator;
-if (!peasycap->fps) {
- SAY("MISTAKE: frames-per-second is zero\n");
- return -EFAULT;
+switch (peasycap->fps) {
+case 6:
+case 30: {
+ peasycap->ntsc = true;
+ break;
}
-JOT(8, "%i frames-per-second\n", peasycap->fps);
-peasycap->usec = 1000000 / (2 * peasycap->fps);
-peasycap->tolerate = 1000 * (25 / peasycap->fps);
-
-kill_video_urbs(peasycap);
-
+case 5:
+case 25: {
+ peasycap->ntsc = false;
+ break;
+}
+default: {
+ SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
+ return -ENOENT;
+}
+}
+JOM(8, "%i frames-per-second\n", peasycap->fps);
+if (0x8000 & peasycap_standard->mask) {
+ peasycap->skip = 5;
+ peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
+ peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
+} else {
+ peasycap->skip = 0;
+ peasycap->usec = 1000000 / (2 * peasycap->fps);
+ peasycap->tolerate = 1000 * (25 / peasycap->fps);
+}
+if (peasycap->video_isoc_streaming) {
+ resubmit = true;
+ kill_video_urbs(peasycap);
+} else
+ resubmit = false;
/*--------------------------------------------------------------------------*/
/*
* SAA7113H DATASHEET PAGE 44, TABLE 42
@@ -94,55 +142,41 @@ case NTSC_M_JP: {
reg = 0x0A; set = 0x95;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+ SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
-
-
- set2to78(peasycap->pusb_device);
-
-
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
- SAY("ERROR: failed to set SAA register " \
+ SAM("ERROR: failed to set SAA register " \
"0x%02X to 0x%02X for JP standard\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-
- set2to78(peasycap->pusb_device);
-
}
reg = 0x0B; set = 0x48;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+ SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
-
- set2to78(peasycap->pusb_device);
-
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != rc)
- SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
+ SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
"for JP standard\n", reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-
- set2to78(peasycap->pusb_device);
-
}
/*--------------------------------------------------------------------------*/
/*
@@ -176,23 +210,20 @@ default:
if (need) {
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: failed to read SAA register 0x%02X\n", reg);
+ SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
else
itwas = (unsigned int)ir;
-
- set2to78(peasycap->pusb_device);
-
rc = write_saa(peasycap->pusb_device, reg, set);
if (0 != write_saa(peasycap->pusb_device, reg, set)) {
- SAY("ERROR: failed to set SAA register " \
+ SAM("ERROR: failed to set SAA register " \
"0x%02X to 0x%02X for table 42\n", reg, set);
} else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"to 0x%02X\n", reg, isnow);
else
- JOT(8, "SAA register 0x%02X changed " \
+ JOM(8, "SAA register 0x%02X changed " \
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
@@ -204,7 +235,7 @@ if (need) {
reg = 0x08;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: failed to read SAA register 0x%02X " \
+ SAM("ERROR: failed to read SAA register 0x%02X " \
"so cannot reset\n", reg);
else {
itwas = (unsigned int)ir;
@@ -212,19 +243,18 @@ else {
set = itwas | 0x40 ;
else
set = itwas & ~0x40 ;
-
-set2to78(peasycap->pusb_device);
-
-rc = write_saa(peasycap->pusb_device, reg, set);
-if (0 != rc)
- SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
-else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
- else
- JOT(8, "SAA register 0x%02X changed " \
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ rc = write_saa(peasycap->pusb_device, reg, set);
+ if (0 != rc)
+ SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
+ reg, set);
+ else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \
+ reg, isnow);
+ else
+ JOM(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
/*--------------------------------------------------------------------------*/
@@ -235,7 +265,7 @@ else {
reg = 0x40;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: failed to read SAA register 0x%02X " \
+ SAM("ERROR: failed to read SAA register 0x%02X " \
"so cannot reset\n", reg);
else {
itwas = (unsigned int)ir;
@@ -243,19 +273,18 @@ else {
set = itwas | 0x80 ;
else
set = itwas & ~0x80 ;
-
-set2to78(peasycap->pusb_device);
-
-rc = write_saa(peasycap->pusb_device, reg, set);
-if (0 != rc)
- SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
-else {
- isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
- if (0 > ir)
- JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
- else
- JOT(8, "SAA register 0x%02X changed " \
- "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ rc = write_saa(peasycap->pusb_device, reg, set);
+ if (0 != rc)
+ SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
+ reg, set);
+ else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \
+ reg, isnow);
+ else
+ JOM(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
}
/*--------------------------------------------------------------------------*/
@@ -266,41 +295,39 @@ else {
reg = 0x5A;
ir = read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
+ SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
itwas = (unsigned int)ir;
if (peasycap_standard->mask & 0x0001)
set = 0x0A ;
else
set = 0x07 ;
-
- set2to78(peasycap->pusb_device);
-
if (0 != write_saa(peasycap->pusb_device, reg, set))
- SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
+ SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
reg, set);
else {
isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
if (0 > ir)
- JOT(8, "SAA register 0x%02X changed "
+ JOM(8, "SAA register 0x%02X changed "
"to 0x%02X\n", reg, isnow);
else
- JOT(8, "SAA register 0x%02X changed "
+ JOM(8, "SAA register 0x%02X changed "
"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
}
- if (0 != check_saa(peasycap->pusb_device))
- SAY("ERROR: check_saa() failed\n");
+if (true == resubmit)
+ submit_video_urbs(peasycap);
return 0;
}
/*****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
- * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE
- * CURRENT VALUE OF peasycap->standard_offset.
+ * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
+ * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
+ *
* PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
* THIS ROUTINE UPDATES THE FOLLOWING:
* peasycap->format_offset
+ * peasycap->inputset[peasycap->input].format_offset
* peasycap->pixelformat
- * peasycap->field
* peasycap->height
* peasycap->width
* peasycap->bytesperpixel
@@ -321,39 +348,93 @@ int adjust_format(struct easycap *peasycap, \
struct easycap_format *peasycap_format, *peasycap_best_format;
__u16 mask;
struct usb_device *p;
-int miss, multiplier, best;
-char bf[5], *pc;
+int miss, multiplier, best, k;
+char bf[5], fo[32], *pc;
__u32 uc;
+bool resubmit;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+if (0 > peasycap->standard_offset) {
+ JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
+ return -EBUSY;
+}
p = peasycap->pusb_device;
if ((struct usb_device *)NULL == p) {
- SAY("ERROR: peaycap->pusb_device is NULL\n");
+ SAM("ERROR: peaycap->pusb_device is NULL\n");
return -EFAULT;
}
pc = &bf[0];
-uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0;
-mask = easycap_standard[peasycap->standard_offset].mask;
-SAY("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
+uc = pixelformat;
+memcpy((void *)pc, (void *)(&uc), 4);
+bf[4] = 0;
+mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
+SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
width, height, pc, pixelformat, field, mask);
+switch (field) {
+case V4L2_FIELD_ANY: {
+ strcpy(&fo[0], "V4L2_FIELD_ANY ");
+ break;
+}
+case V4L2_FIELD_NONE: {
+ strcpy(&fo[0], "V4L2_FIELD_NONE");
+ break;
+}
+case V4L2_FIELD_TOP: {
+ strcpy(&fo[0], "V4L2_FIELD_TOP");
+ break;
+}
+case V4L2_FIELD_BOTTOM: {
+ strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
+ break;
+}
+case V4L2_FIELD_INTERLACED: {
+ strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
+ break;
+}
+case V4L2_FIELD_SEQ_TB: {
+ strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
+ break;
+}
+case V4L2_FIELD_SEQ_BT: {
+ strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
+ break;
+}
+case V4L2_FIELD_ALTERNATE: {
+ strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
+ break;
+}
+case V4L2_FIELD_INTERLACED_TB: {
+ strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
+ break;
+}
+case V4L2_FIELD_INTERLACED_BT: {
+ strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
+ break;
+}
+default: {
+ strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN ");
+ break;
+}
+}
+SAM("sought: %s\n", &fo[0]);
if (V4L2_FIELD_ANY == field) {
- field = V4L2_FIELD_INTERLACED;
- SAY("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n");
+ field = V4L2_FIELD_NONE;
+ SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
}
peasycap_best_format = (struct easycap_format *)NULL;
peasycap_format = &easycap_format[0];
while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
- JOT(16, ".> %i %i 0x%08X %ix%i\n", \
+ JOM(16, ".> %i %i 0x%08X %ix%i\n", \
peasycap_format->mask & 0x01,
peasycap_format->v4l2_format.fmt.pix.field,
peasycap_format->v4l2_format.fmt.pix.pixelformat,
peasycap_format->v4l2_format.fmt.pix.width,
peasycap_format->v4l2_format.fmt.pix.height);
- if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+ if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
(peasycap_format->v4l2_format.fmt.pix.field == field) && \
(peasycap_format->v4l2_format.fmt.pix.pixelformat == \
pixelformat) && \
@@ -365,11 +446,11 @@ while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
peasycap_format++;
}
if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
- SAY("cannot do: %ix%i with standard mask 0x%02X\n", \
+ SAM("cannot do: %ix%i with standard mask 0x%02X\n", \
width, height, mask);
peasycap_format = &easycap_format[0]; best = -1;
while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
- if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+ if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
(peasycap_format->v4l2_format.fmt.pix\
.field == field) && \
(peasycap_format->v4l2_format.fmt.pix\
@@ -386,16 +467,16 @@ if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
peasycap_format++;
}
if (-1 == best) {
- SAY("cannot do %ix... with standard mask 0x%02X\n", \
+ SAM("cannot do %ix... with standard mask 0x%02X\n", \
width, mask);
- SAY("cannot do ...x%i with standard mask 0x%02X\n", \
+ SAM("cannot do ...x%i with standard mask 0x%02X\n", \
height, mask);
- SAY(" %ix%i unmatched\n", width, height);
+ SAM(" %ix%i unmatched\n", width, height);
return peasycap->format_offset;
}
}
if ((struct easycap_format *)NULL == peasycap_best_format) {
- SAY("MISTAKE: peasycap_best_format is NULL");
+ SAM("MISTAKE: peasycap_best_format is NULL");
return -EINVAL;
}
peasycap_format = peasycap_best_format;
@@ -406,23 +487,43 @@ if (true == try)
/*...........................................................................*/
if (false != try) {
- SAY("MISTAKE: true==try where is should be false\n");
+ SAM("MISTAKE: true==try where is should be false\n");
return -EINVAL;
}
-SAY("actioning: %ix%i %s\n", \
+SAM("actioning: %ix%i %s\n", \
peasycap_format->v4l2_format.fmt.pix.width, \
peasycap_format->v4l2_format.fmt.pix.height,
&peasycap_format->name[0]);
peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
-peasycap->field = peasycap_format->v4l2_format.fmt.pix.field;
peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
-peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ;
+
+
+for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].format_offset_ok) {
+ peasycap->inputset[k].format_offset = \
+ peasycap->format_offset;
+ }
+}
+if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].format_offset = \
+ peasycap->format_offset;
+ peasycap->inputset[peasycap->input].format_offset_ok = 1;
+} else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
+
+
+
+peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
if (0x0100 & peasycap_format->mask)
peasycap->byteswaporder = true;
else
peasycap->byteswaporder = false;
+if (0x0200 & peasycap_format->mask)
+ peasycap->skip = 5;
+else
+ peasycap->skip = 0;
if (0x0800 & peasycap_format->mask)
peasycap->decimatepixel = true;
else
@@ -439,27 +540,11 @@ peasycap->videofieldamount = multiplier * peasycap->width * \
multiplier * peasycap->height;
peasycap->frame_buffer_used = peasycap->bytesperpixel * \
peasycap->width * peasycap->height;
-
-if (true == peasycap->offerfields) {
- SAY("WARNING: %i=peasycap->field is untested: " \
- "please report problems\n", peasycap->field);
-
-
-/*
- * FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT:
- *
- * peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2;
- *
- * SO DO NOT RISK IT YET.
- *
- */
-
-
-
-}
-
-kill_video_urbs(peasycap);
-
+if (peasycap->video_isoc_streaming) {
+ resubmit = true;
+ kill_video_urbs(peasycap);
+} else
+ resubmit = false;
/*---------------------------------------------------------------------------*/
/*
* PAL
@@ -474,13 +559,13 @@ if (0 == (0x01 & peasycap_format->mask)) {
(288 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
- SAY("ERROR: set_resolution() failed\n");
+ SAM("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \
(576 == peasycap_format->v4l2_format.fmt.pix.height)) {
if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
- SAY("ERROR: set_resolution() failed\n");
+ SAM("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
@@ -491,11 +576,11 @@ if (0 == (0x01 & peasycap_format->mask)) {
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
- SAY("ERROR: set_resolution() failed\n");
+ SAM("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else {
- SAY("MISTAKE: bad format, cannot set resolution\n");
+ SAM("MISTAKE: bad format, cannot set resolution\n");
return -EINVAL;
}
/*---------------------------------------------------------------------------*/
@@ -512,7 +597,7 @@ if (0 == (0x01 & peasycap_format->mask)) {
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
- SAY("ERROR: set_resolution() failed\n");
+ SAM("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
@@ -523,28 +608,31 @@ if (0 == (0x01 & peasycap_format->mask)) {
(240 == \
peasycap_format->v4l2_format.fmt.pix.height))) {
if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
- SAY("ERROR: set_resolution() failed\n");
+ SAM("ERROR: set_resolution() failed\n");
return -EINVAL;
}
} else {
- SAY("MISTAKE: bad format, cannot set resolution\n");
+ SAM("MISTAKE: bad format, cannot set resolution\n");
return -EINVAL;
}
}
/*---------------------------------------------------------------------------*/
-
-check_stk(peasycap->pusb_device);
-
+if (true == resubmit)
+ submit_video_urbs(peasycap);
return (int)(peasycap_best_format - &easycap_format[0]);
}
/*****************************************************************************/
int adjust_brightness(struct easycap *peasycap, int value)
{
unsigned int mood;
-int i1;
+int i1, k;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
@@ -553,37 +641,56 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
+
+ if ((easycap_control[i1].minimum <= peasycap->brightness) && \
+ (easycap_control[i1].maximum >= \
+ peasycap->brightness)) {
+ if (peasycap->brightness == value) {
+ SAM("unchanged brightness at 0x%02X\n", \
+ value);
+ return 0;
+ }
+ }
peasycap->brightness = value;
+ for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].brightness_ok)
+ peasycap->inputset[k].brightness = \
+ peasycap->brightness;
+ }
+ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].brightness = \
+ peasycap->brightness;
+ peasycap->inputset[peasycap->input].brightness_ok = 1;
+ } else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
mood = 0x00FF & (unsigned int)peasycap->brightness;
-
- set2to78(peasycap->pusb_device);
-
if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
- SAY("adjusting brightness to 0x%02X\n", mood);
+ SAM("adjusting brightness to 0x%02X\n", mood);
return 0;
} else {
- SAY("WARNING: failed to adjust brightness " \
+ SAM("WARNING: failed to adjust brightness " \
"to 0x%02X\n", mood);
return -ENOENT;
}
-
- set2to78(peasycap->pusb_device);
-
break;
}
i1++;
}
-SAY("WARNING: failed to adjust brightness: control not found\n");
+SAM("WARNING: failed to adjust brightness: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_contrast(struct easycap *peasycap, int value)
{
unsigned int mood;
-int i1;
+int i1, k;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
@@ -592,37 +699,58 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
- peasycap->contrast = value;
- mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
- set2to78(peasycap->pusb_device);
+
+ if ((easycap_control[i1].minimum <= peasycap->contrast) && \
+ (easycap_control[i1].maximum >= \
+ peasycap->contrast)) {
+ if (peasycap->contrast == value) {
+ SAM("unchanged contrast at 0x%02X\n", value);
+ return 0;
+ }
+ }
+ peasycap->contrast = value;
+ for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].contrast_ok) {
+ peasycap->inputset[k].contrast = \
+ peasycap->contrast;
+ }
+ }
+ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].contrast = \
+ peasycap->contrast;
+ peasycap->inputset[peasycap->input].contrast_ok = 1;
+ } else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
+ mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
- SAY("adjusting contrast to 0x%02X\n", mood);
+ SAM("adjusting contrast to 0x%02X\n", mood);
return 0;
} else {
- SAY("WARNING: failed to adjust contrast to " \
+ SAM("WARNING: failed to adjust contrast to " \
"0x%02X\n", mood);
return -ENOENT;
}
-
- set2to78(peasycap->pusb_device);
-
break;
}
i1++;
}
-SAY("WARNING: failed to adjust contrast: control not found\n");
+SAM("WARNING: failed to adjust contrast: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_saturation(struct easycap *peasycap, int value)
{
unsigned int mood;
-int i1;
+int i1, k;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
@@ -631,37 +759,58 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
- peasycap->saturation = value;
- mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
- set2to78(peasycap->pusb_device);
+ if ((easycap_control[i1].minimum <= peasycap->saturation) && \
+ (easycap_control[i1].maximum >= \
+ peasycap->saturation)) {
+ if (peasycap->saturation == value) {
+ SAM("unchanged saturation at 0x%02X\n", \
+ value);
+ return 0;
+ }
+ }
+ peasycap->saturation = value;
+ for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].saturation_ok) {
+ peasycap->inputset[k].saturation = \
+ peasycap->saturation;
+ }
+ }
+ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].saturation = \
+ peasycap->saturation;
+ peasycap->inputset[peasycap->input].saturation_ok = 1;
+ } else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
+ mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
- SAY("adjusting saturation to 0x%02X\n", mood);
+ SAM("adjusting saturation to 0x%02X\n", mood);
return 0;
} else {
- SAY("WARNING: failed to adjust saturation to " \
+ SAM("WARNING: failed to adjust saturation to " \
"0x%02X\n", mood);
return -ENOENT;
}
break;
-
- set2to78(peasycap->pusb_device);
-
}
i1++;
}
-SAY("WARNING: failed to adjust saturation: control not found\n");
+SAM("WARNING: failed to adjust saturation: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
int adjust_hue(struct easycap *peasycap, int value)
{
unsigned int mood;
-int i1, i2;
+int i1, i2, k;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
@@ -670,27 +819,40 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
(easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
+
+ if ((easycap_control[i1].minimum <= peasycap->hue) && \
+ (easycap_control[i1].maximum >= \
+ peasycap->hue)) {
+ if (peasycap->hue == value) {
+ SAM("unchanged hue at 0x%02X\n", value);
+ return 0;
+ }
+ }
peasycap->hue = value;
+ for (k = 0; k < INPUT_MANY; k++) {
+ if (!peasycap->inputset[k].hue_ok)
+ peasycap->inputset[k].hue = peasycap->hue;
+ }
+ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+ peasycap->inputset[peasycap->input].hue = \
+ peasycap->hue;
+ peasycap->inputset[peasycap->input].hue_ok = 1;
+ } else
+ JOM(8, "%i=peasycap->input\n", peasycap->input);
i2 = peasycap->hue - 128;
mood = 0x00FF & ((int) i2);
-
- set2to78(peasycap->pusb_device);
-
if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
- SAY("adjusting hue to 0x%02X\n", mood);
+ SAM("adjusting hue to 0x%02X\n", mood);
return 0;
} else {
- SAY("WARNING: failed to adjust hue to 0x%02X\n", mood);
+ SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
return -ENOENT;
}
-
- set2to78(peasycap->pusb_device);
-
break;
}
i1++;
}
-SAY("WARNING: failed to adjust hue: control not found\n");
+SAM("WARNING: failed to adjust hue: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
@@ -699,33 +861,45 @@ int adjust_volume(struct easycap *peasycap, int value)
__s8 mood;
int i1;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
if ((easycap_control[i1].minimum > value) || \
- (easycap_control[i1].maximum < value))
+ (easycap_control[i1].maximum < value))
value = easycap_control[i1].default_value;
+ if ((easycap_control[i1].minimum <= peasycap->volume) && \
+ (easycap_control[i1].maximum >= \
+ peasycap->volume)) {
+ if (peasycap->volume == value) {
+ SAM("unchanged volume at 0x%02X\n", value);
+ return 0;
+ }
+ }
peasycap->volume = value;
mood = (16 > peasycap->volume) ? 16 : \
((31 < peasycap->volume) ? 31 : \
(__s8) peasycap->volume);
if (!audio_gainset(peasycap->pusb_device, mood)) {
- SAY("adjusting volume to 0x%01X\n", mood);
+ SAM("adjusting volume to 0x%02X\n", mood);
return 0;
} else {
- SAY("WARNING: failed to adjust volume to " \
- "0x%1X\n", mood);
+ SAM("WARNING: failed to adjust volume to " \
+ "0x%2X\n", mood);
return -ENOENT;
}
break;
}
i1++;
}
-SAY("WARNING: failed to adjust volume: control not found\n");
+SAM("WARNING: failed to adjust volume: control not found\n");
return -ENOENT;
}
/*****************************************************************************/
@@ -744,8 +918,12 @@ int adjust_mute(struct easycap *peasycap, int value)
{
int i1;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
i1 = 0;
@@ -756,13 +934,13 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
case 1: {
peasycap->audio_idle = 1;
peasycap->timeval0.tv_sec = 0;
- SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+ SAM("adjusting mute: %i=peasycap->audio_idle\n", \
peasycap->audio_idle);
return 0;
}
default: {
peasycap->audio_idle = 0;
- SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+ SAM("adjusting mute: %i=peasycap->audio_idle\n", \
peasycap->audio_idle);
return 0;
}
@@ -771,47 +949,107 @@ while (0xFFFFFFFF != easycap_control[i1].id) {
}
i1++;
}
-SAY("WARNING: failed to adjust mute: control not found\n");
+SAM("WARNING: failed to adjust mute: control not found\n");
return -ENOENT;
}
-
-/*--------------------------------------------------------------------------*/
-static int easycap_ioctl_bkl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+/*****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
+ (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
+long
+easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
+ return (long)easycap_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+int
+easycap_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
-static struct easycap *peasycap;
-static struct usb_device *p;
-static __u32 isequence;
+struct easycap *peasycap;
+struct usb_device *p;
+int kd;
+if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ return -ERESTARTSYS;
+}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -1;
}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap\n");
+ return -EFAULT;
+}
p = peasycap->pusb_device;
-if ((struct usb_device *)NULL == p) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+if (NULL == p) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i].mutex_video\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
/*---------------------------------------------------------------------------*/
/*
- * MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO
- * DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND:
- * easycap_ioctl.c: warning:
- * the frame size of ... bytes is larger than 1024 bytes
- */
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
+ p = peasycap->pusb_device;
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+} else {
+/*---------------------------------------------------------------------------*/
+/*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+}
/*---------------------------------------------------------------------------*/
switch (cmd) {
case VIDIOC_QUERYCAP: {
- static struct v4l2_capability v4l2_capability;
- static char version[16], *p1, *p2;
- static int i, rc, k[3];
- static long lng;
+ struct v4l2_capability v4l2_capability;
+ char version[16], *p1, *p2;
+ int i, rc, k[3];
+ long lng;
- JOT(8, "VIDIOC_QUERYCAP\n");
+ JOM(8, "VIDIOC_QUERYCAP\n");
if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
- SAY("ERROR: bad driver version string\n"); return -EINVAL;
+ SAM("ERROR: bad driver version string\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
}
strcpy(&version[0], EASYCAP_DRIVER_VERSION);
for (i = 0; i < 3; i++)
@@ -826,8 +1064,9 @@ case VIDIOC_QUERYCAP: {
if (3 > i) {
rc = (int) strict_strtol(p1, 10, &lng);
if (0 != rc) {
- SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \
+ SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \
rc, p1);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
k[i] = (int)lng;
@@ -844,7 +1083,7 @@ case VIDIOC_QUERYCAP: {
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE;
v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
- JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
+ JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \
sizeof(v4l2_capability.card));
@@ -853,26 +1092,26 @@ case VIDIOC_QUERYCAP: {
sizeof(v4l2_capability.bus_info)) < 0) {
strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \
sizeof(v4l2_capability.bus_info));
- JOT(8, "%s=v4l2_capability.bus_info\n", \
+ JOM(8, "%s=v4l2_capability.bus_info\n", \
&v4l2_capability.bus_info[0]);
}
if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
sizeof(struct v4l2_capability))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMINPUT: {
- static struct v4l2_input v4l2_input;
- static __u32 index;
+ struct v4l2_input v4l2_input;
+ __u32 index;
- JOT(8, "VIDIOC_ENUMINPUT\n");
+ JOM(8, "VIDIOC_ENUMINPUT\n");
if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
sizeof(struct v4l2_input))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
@@ -889,7 +1128,7 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 1: {
@@ -901,7 +1140,7 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 2: {
@@ -913,7 +1152,7 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 3: {
@@ -925,7 +1164,7 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 4: {
@@ -937,7 +1176,7 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
case 5: {
@@ -949,31 +1188,32 @@ case VIDIOC_ENUMINPUT: {
v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
V4L2_STD_NTSC ;
v4l2_input.status = 0;
- JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
break;
}
default: {
- JOT(8, "%i=index: exhausts inputs\n", index);
+ JOM(8, "%i=index: exhausts inputs\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
sizeof(struct v4l2_input))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_INPUT: {
- static __u32 index;
+ __u32 index;
- JOT(8, "VIDIOC_G_INPUT\n");
+ JOM(8, "VIDIOC_G_INPUT\n");
index = (__u32)peasycap->input;
- JOT(8, "user is told: %i\n", index);
+ JOM(8, "user is told: %i\n", index);
if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@@ -981,79 +1221,89 @@ case VIDIOC_G_INPUT: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_INPUT:
{
- static __u32 index;
+ __u32 index;
+ int rc;
- JOT(8, "VIDIOC_S_INPUT\n");
+ JOM(8, "VIDIOC_S_INPUT\n");
if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- JOT(8, "user requests input %i\n", index);
+ JOM(8, "user requests input %i\n", index);
if ((int)index == peasycap->input) {
- SAY("requested input already in effect\n");
+ SAM("requested input already in effect\n");
break;
}
- if ((0 > index) || (5 < index)) {
- JOT(8, "ERROR: bad requested input: %i\n", index);
+ if ((0 > index) || (INPUT_MANY <= index)) {
+ JOM(8, "ERROR: bad requested input: %i\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
- peasycap->input = (int)index;
-
- select_input(peasycap->pusb_device, peasycap->input, 9);
+ rc = newinput(peasycap, (int)index);
+ if (0 == rc) {
+ JOM(8, "newinput(.,%i) OK\n", (int)index);
+ } else {
+ SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDIO: {
- JOT(8, "VIDIOC_ENUMAUDIO\n");
+ JOM(8, "VIDIOC_ENUMAUDIO\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDOUT: {
- static struct v4l2_audioout v4l2_audioout;
+ struct v4l2_audioout v4l2_audioout;
- JOT(8, "VIDIOC_ENUMAUDOUT\n");
+ JOM(8, "VIDIOC_ENUMAUDOUT\n");
if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
sizeof(struct v4l2_audioout))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (0 != v4l2_audioout.index)
+ if (0 != v4l2_audioout.index) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
v4l2_audioout.index = 0;
strcpy(&v4l2_audioout.name[0], "Soundtrack");
if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
sizeof(struct v4l2_audioout))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYCTRL: {
- static int i1;
- static struct v4l2_queryctrl v4l2_queryctrl;
+ int i1;
+ struct v4l2_queryctrl v4l2_queryctrl;
- JOT(8, "VIDIOC_QUERYCTRL\n");
+ JOM(8, "VIDIOC_QUERYCTRL\n");
if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
sizeof(struct v4l2_queryctrl))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
if (easycap_control[i1].id == v4l2_queryctrl.id) {
- JOT(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \
+ JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \
".name\n", &easycap_control[i1].name[0], i1);
memcpy(&v4l2_queryctrl, &easycap_control[i1], \
sizeof(struct v4l2_queryctrl));
@@ -1062,127 +1312,137 @@ case VIDIOC_QUERYCTRL: {
i1++;
}
if (0xFFFFFFFF == easycap_control[i1].id) {
- JOT(8, "%i=index: exhausts controls\n", i1);
+ JOM(8, "%i=index: exhausts controls\n", i1);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
sizeof(struct v4l2_queryctrl))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYMENU: {
- JOT(8, "VIDIOC_QUERYMENU unsupported\n");
+ JOM(8, "VIDIOC_QUERYMENU unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CTRL: {
- static struct v4l2_control v4l2_control;
+ struct v4l2_control *pv4l2_control;
- JOT(8, "VIDIOC_G_CTRL\n");
-
- if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
+ JOM(8, "VIDIOC_G_CTRL\n");
+ pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL);
+ if (!pv4l2_control) {
+ SAM("ERROR: out of memory\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ENOMEM;
+ }
+ if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
- POUT;
+ kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- switch (v4l2_control.id) {
+ switch (pv4l2_control->id) {
case V4L2_CID_BRIGHTNESS: {
- v4l2_control.value = peasycap->brightness;
- JOT(8, "user enquires brightness: %i\n", v4l2_control.value);
+ pv4l2_control->value = peasycap->brightness;
+ JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
break;
}
case V4L2_CID_CONTRAST: {
- v4l2_control.value = peasycap->contrast;
- JOT(8, "user enquires contrast: %i\n", v4l2_control.value);
+ pv4l2_control->value = peasycap->contrast;
+ JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
break;
}
case V4L2_CID_SATURATION: {
- v4l2_control.value = peasycap->saturation;
- JOT(8, "user enquires saturation: %i\n", v4l2_control.value);
+ pv4l2_control->value = peasycap->saturation;
+ JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
break;
}
case V4L2_CID_HUE: {
- v4l2_control.value = peasycap->hue;
- JOT(8, "user enquires hue: %i\n", v4l2_control.value);
+ pv4l2_control->value = peasycap->hue;
+ JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
break;
}
case V4L2_CID_AUDIO_VOLUME: {
- v4l2_control.value = peasycap->volume;
- JOT(8, "user enquires volume: %i\n", v4l2_control.value);
+ pv4l2_control->value = peasycap->volume;
+ JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
break;
}
case V4L2_CID_AUDIO_MUTE: {
if (1 == peasycap->mute)
- v4l2_control.value = true;
+ pv4l2_control->value = true;
else
- v4l2_control.value = false;
- JOT(8, "user enquires mute: %i\n", v4l2_control.value);
+ pv4l2_control->value = false;
+ JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
break;
}
default: {
- SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
- v4l2_control.id);
- explain_cid(v4l2_control.id);
+ SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+ pv4l2_control->id);
+ kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
- if (0 != copy_to_user((void __user *)arg, &v4l2_control, \
+ if (0 != copy_to_user((void __user *)arg, pv4l2_control, \
sizeof(struct v4l2_control))) {
- POUT;
+ kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
+ kfree(pv4l2_control);
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(VIDIOC_S_CTRL_OLD)
case VIDIOC_S_CTRL_OLD: {
- JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
+ JOM(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
}
#endif /*VIDIOC_S_CTRL_OLD*/
case VIDIOC_S_CTRL:
{
- static struct v4l2_control v4l2_control;
+ struct v4l2_control v4l2_control;
- JOT(8, "VIDIOC_S_CTRL\n");
+ JOM(8, "VIDIOC_S_CTRL\n");
if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
switch (v4l2_control.id) {
case V4L2_CID_BRIGHTNESS: {
- JOT(8, "user requests brightness %i\n", v4l2_control.value);
+ JOM(8, "user requests brightness %i\n", v4l2_control.value);
if (0 != adjust_brightness(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_CONTRAST: {
- JOT(8, "user requests contrast %i\n", v4l2_control.value);
+ JOM(8, "user requests contrast %i\n", v4l2_control.value);
if (0 != adjust_contrast(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_SATURATION: {
- JOT(8, "user requests saturation %i\n", v4l2_control.value);
+ JOM(8, "user requests saturation %i\n", v4l2_control.value);
if (0 != adjust_saturation(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_HUE: {
- JOT(8, "user requests hue %i\n", v4l2_control.value);
+ JOM(8, "user requests hue %i\n", v4l2_control.value);
if (0 != adjust_hue(peasycap, v4l2_control.value))
;
break;
}
case V4L2_CID_AUDIO_VOLUME: {
- JOT(8, "user requests volume %i\n", v4l2_control.value);
+ JOM(8, "user requests volume %i\n", v4l2_control.value);
if (0 != adjust_volume(peasycap, v4l2_control.value))
;
break;
@@ -1190,40 +1450,41 @@ case VIDIOC_S_CTRL:
case V4L2_CID_AUDIO_MUTE: {
int mute;
- JOT(8, "user requests mute %i\n", v4l2_control.value);
+ JOM(8, "user requests mute %i\n", v4l2_control.value);
if (true == v4l2_control.value)
mute = 1;
else
mute = 0;
if (0 != adjust_mute(peasycap, mute))
- SAY("WARNING: failed to adjust mute to %i\n", mute);
+ SAM("WARNING: failed to adjust mute to %i\n", mute);
break;
}
default: {
- SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+ SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
v4l2_control.id);
- explain_cid(v4l2_control.id);
- return -EINVAL;
- }
- }
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
+ }
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_EXT_CTRLS: {
- JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+ JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FMT: {
- static __u32 index;
- static struct v4l2_fmtdesc v4l2_fmtdesc;
+ __u32 index;
+ struct v4l2_fmtdesc v4l2_fmtdesc;
- JOT(8, "VIDIOC_ENUM_FMT\n");
+ JOM(8, "VIDIOC_ENUM_FMT\n");
if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
sizeof(struct v4l2_fmtdesc))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
@@ -1238,117 +1499,327 @@ case VIDIOC_ENUM_FMT: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "uyvy");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 1: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "yuy2");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 2: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "rgb24");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 3: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "rgb32");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 4: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "bgr24");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
case 5: {
v4l2_fmtdesc.flags = 0;
strcpy(&v4l2_fmtdesc.description[0], "bgr32");
v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
- JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
break;
}
default: {
- JOT(8, "%i=index: exhausts formats\n", index);
+ JOM(8, "%i=index: exhausts formats\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
sizeof(struct v4l2_fmtdesc))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
+ * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FRAMESIZES: {
- JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n");
- return -EINVAL;
+ __u32 index;
+ struct v4l2_frmsizeenum v4l2_frmsizeenum;
+
+ JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
+
+ if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
+ sizeof(struct v4l2_frmsizeenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
+
+ index = v4l2_frmsizeenum.index;
+
+ v4l2_frmsizeenum.type = (__u32) V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ if (true == peasycap->ntsc) {
+ switch (index) {
+ case 0: {
+ v4l2_frmsizeenum.discrete.width = 640;
+ v4l2_frmsizeenum.discrete.height = 480;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 1: {
+ v4l2_frmsizeenum.discrete.width = 320;
+ v4l2_frmsizeenum.discrete.height = 240;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 2: {
+ v4l2_frmsizeenum.discrete.width = 720;
+ v4l2_frmsizeenum.discrete.height = 480;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 3: {
+ v4l2_frmsizeenum.discrete.width = 360;
+ v4l2_frmsizeenum.discrete.height = 240;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ default: {
+ JOM(8, "%i=index: exhausts framesizes\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
+ }
+ }
+ } else {
+ switch (index) {
+ case 0: {
+ v4l2_frmsizeenum.discrete.width = 640;
+ v4l2_frmsizeenum.discrete.height = 480;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 1: {
+ v4l2_frmsizeenum.discrete.width = 320;
+ v4l2_frmsizeenum.discrete.height = 240;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 2: {
+ v4l2_frmsizeenum.discrete.width = 704;
+ v4l2_frmsizeenum.discrete.height = 576;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 3: {
+ v4l2_frmsizeenum.discrete.width = 720;
+ v4l2_frmsizeenum.discrete.height = 576;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ case 4: {
+ v4l2_frmsizeenum.discrete.width = 360;
+ v4l2_frmsizeenum.discrete.height = 288;
+ JOM(8, "%i=index: %ix%i\n", index, \
+ (int)(v4l2_frmsizeenum.\
+ discrete.width), \
+ (int)(v4l2_frmsizeenum.\
+ discrete.height));
+ break;
+ }
+ default: {
+ JOM(8, "%i=index: exhausts framesizes\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
+ }
+ }
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
+ sizeof(struct v4l2_frmsizeenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
+ break;
}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
+ * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUM_FRAMEINTERVALS: {
- JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n");
- return -EINVAL;
+ __u32 index;
+ int denominator;
+ struct v4l2_frmivalenum v4l2_frmivalenum;
+
+ JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
+
+ if (peasycap->fps)
+ denominator = peasycap->fps;
+ else {
+ if (true == peasycap->ntsc)
+ denominator = 30;
+ else
+ denominator = 25;
+ }
+
+ if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
+ sizeof(struct v4l2_frmivalenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
+
+ index = v4l2_frmivalenum.index;
+
+ v4l2_frmivalenum.type = (__u32) V4L2_FRMIVAL_TYPE_DISCRETE;
+
+ switch (index) {
+ case 0: {
+ v4l2_frmivalenum.discrete.numerator = 1;
+ v4l2_frmivalenum.discrete.denominator = denominator;
+ JOM(8, "%i=index: %i/%i\n", index, \
+ (int)(v4l2_frmivalenum.discrete.numerator), \
+ (int)(v4l2_frmivalenum.discrete.denominator));
+ break;
+ }
+ case 1: {
+ v4l2_frmivalenum.discrete.numerator = 1;
+ v4l2_frmivalenum.discrete.denominator = denominator/5;
+ JOM(8, "%i=index: %i/%i\n", index, \
+ (int)(v4l2_frmivalenum.discrete.numerator), \
+ (int)(v4l2_frmivalenum.discrete.denominator));
+ break;
+ }
+ default: {
+ JOM(8, "%i=index: exhausts frameintervals\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
+ }
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
+ sizeof(struct v4l2_frmivalenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EFAULT;
+ }
+ break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_FMT: {
- static struct v4l2_format v4l2_format;
- static struct v4l2_pix_format v4l2_pix_format;
-
- JOT(8, "VIDIOC_G_FMT\n");
-
- if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
+ struct v4l2_format *pv4l2_format;
+ struct v4l2_pix_format *pv4l2_pix_format;
+
+ JOM(8, "VIDIOC_G_FMT\n");
+ pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
+ if (!pv4l2_format) {
+ SAM("ERROR: out of memory\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ENOMEM;
+ }
+ pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
+ if (!pv4l2_pix_format) {
+ SAM("ERROR: out of memory\n");
+ kfree(pv4l2_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ENOMEM;
+ }
+ if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
- POUT;
+ kfree(pv4l2_format);
+ kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- POUT;
+ if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ kfree(pv4l2_format);
+ kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
- memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
- v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memcpy(&(v4l2_format.fmt.pix), \
- &(easycap_format[peasycap->format_offset]\
- .v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
- JOT(8, "user is told: %s\n", \
+ memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+ pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ memcpy(&pv4l2_format->fmt.pix, \
+ &easycap_format[peasycap->format_offset]\
+ .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
+ JOM(8, "user is told: %s\n", \
&easycap_format[peasycap->format_offset].name[0]);
- if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
+ if (0 != copy_to_user((void __user *)arg, pv4l2_format, \
sizeof(struct v4l2_format))) {
- POUT;
+ kfree(pv4l2_format);
+ kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
+ kfree(pv4l2_format);
+ kfree(pv4l2_pix_format);
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT: {
- static struct v4l2_format v4l2_format;
- static struct v4l2_pix_format v4l2_pix_format;
- static bool try;
- static int best_format;
+ struct v4l2_format v4l2_format;
+ struct v4l2_pix_format v4l2_pix_format;
+ bool try;
+ int best_format;
if (VIDIOC_TRY_FMT == cmd) {
- JOT(8, "VIDIOC_TRY_FMT\n");
+ JOM(8, "VIDIOC_TRY_FMT\n");
try = true;
} else {
- JOT(8, "VIDIOC_S_FMT\n");
+ JOM(8, "VIDIOC_S_FMT\n");
try = false;
}
if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
@@ -1359,7 +1830,12 @@ case VIDIOC_S_FMT: {
v4l2_format.fmt.pix.field, \
try);
if (0 > best_format) {
- JOT(8, "WARNING: adjust_format() returned %i\n", best_format);
+ if (-EBUSY == best_format) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EBUSY;
+ }
+ JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOENT;
}
/*...........................................................................*/
@@ -1368,29 +1844,29 @@ case VIDIOC_S_FMT: {
memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\
.v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
- JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
+ JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
sizeof(struct v4l2_format))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_CROPCAP: {
- static struct v4l2_cropcap v4l2_cropcap;
+ struct v4l2_cropcap v4l2_cropcap;
- JOT(8, "VIDIOC_CROPCAP\n");
+ JOM(8, "VIDIOC_CROPCAP\n");
if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
sizeof(struct v4l2_cropcap))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1405,11 +1881,11 @@ case VIDIOC_CROPCAP: {
v4l2_cropcap.pixelaspect.numerator = 1;
v4l2_cropcap.pixelaspect.denominator = 1;
- JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
+ JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
sizeof(struct v4l2_cropcap))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@@ -1417,13 +1893,15 @@ case VIDIOC_CROPCAP: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CROP:
case VIDIOC_S_CROP: {
- JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
+ JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYSTD: {
- JOT(8, "VIDIOC_QUERYSTD: " \
+ JOM(8, "VIDIOC_QUERYSTD: " \
"EasyCAP is incapable of detecting standard\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
break;
}
@@ -1436,16 +1914,16 @@ case VIDIOC_QUERYSTD: {
*/
/*---------------------------------------------------------------------------*/
case VIDIOC_ENUMSTD: {
- static int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
- static struct v4l2_standard v4l2_standard;
- static __u32 index;
- static struct easycap_standard const *peasycap_standard;
+ int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
+ struct v4l2_standard v4l2_standard;
+ __u32 index;
+ struct easycap_standard const *peasycap_standard;
- JOT(8, "VIDIOC_ENUMSTD\n");
+ JOM(8, "VIDIOC_ENUMSTD\n");
if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
sizeof(struct v4l2_standard))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
index = v4l2_standard.index;
@@ -1466,10 +1944,11 @@ case VIDIOC_ENUMSTD: {
peasycap_standard++;
}
if (0xFFFF == peasycap_standard->mask) {
- JOT(8, "%i=index: exhausts standards\n", index);
+ JOM(8, "%i=index: exhausts standards\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
- JOT(8, "%i=index: %s\n", index, \
+ JOM(8, "%i=index: %s\n", index, \
&(peasycap_standard->v4l2_standard.name[0]));
memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), \
sizeof(struct v4l2_standard));
@@ -1478,87 +1957,101 @@ case VIDIOC_ENUMSTD: {
if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
sizeof(struct v4l2_standard))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_STD: {
- static v4l2_std_id std_id;
- static struct easycap_standard const *peasycap_standard;
+ v4l2_std_id std_id;
+ struct easycap_standard const *peasycap_standard;
+
+ JOM(8, "VIDIOC_G_STD\n");
- JOT(8, "VIDIOC_G_STD\n");
+ if (0 > peasycap->standard_offset) {
+ JOM(8, "%i=peasycap->standard_offset\n", \
+ peasycap->standard_offset);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EBUSY;
+ }
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
peasycap_standard = &easycap_standard[peasycap->standard_offset];
std_id = peasycap_standard->v4l2_standard.id;
- JOT(8, "user is told: %s\n", \
+ JOM(8, "user is told: %s\n", \
&peasycap_standard->v4l2_standard.name[0]);
if (0 != copy_to_user((void __user *)arg, &std_id, \
sizeof(v4l2_std_id))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_STD: {
- static v4l2_std_id std_id;
- static int rc;
+ v4l2_std_id std_id;
+ int rc;
- JOT(8, "VIDIOC_S_STD\n");
+ JOM(8, "VIDIOC_S_STD\n");
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
+ JOM(8, "User requests standard: 0x%08X%08X\n", \
+ (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \
+ (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
+
rc = adjust_standard(peasycap, std_id);
if (0 > rc) {
- JOT(8, "WARNING: adjust_standard() returned %i\n", rc);
+ JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOENT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_REQBUFS: {
- static int nbuffers;
- static struct v4l2_requestbuffers v4l2_requestbuffers;
+ int nbuffers;
+ struct v4l2_requestbuffers v4l2_requestbuffers;
- JOT(8, "VIDIOC_REQBUFS\n");
+ JOM(8, "VIDIOC_REQBUFS\n");
if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
sizeof(struct v4l2_requestbuffers))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
nbuffers = v4l2_requestbuffers.count;
- JOT(8, " User requests %i buffers ...\n", nbuffers);
+ JOM(8, " User requests %i buffers ...\n", nbuffers);
if (nbuffers < 2)
nbuffers = 2;
if (nbuffers > FRAME_BUFFER_MANY)
nbuffers = FRAME_BUFFER_MANY;
if (v4l2_requestbuffers.count == nbuffers) {
- JOT(8, " ... agree to %i buffers\n", \
+ JOM(8, " ... agree to %i buffers\n", \
nbuffers);
} else {
- JOT(8, " ... insist on %i buffers\n", \
+ JOM(8, " ... insist on %i buffers\n", \
nbuffers);
v4l2_requestbuffers.count = nbuffers;
}
@@ -1566,32 +2059,35 @@ case VIDIOC_REQBUFS: {
if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
sizeof(struct v4l2_requestbuffers))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYBUF: {
- static __u32 index;
- static struct v4l2_buffer v4l2_buffer;
+ __u32 index;
+ struct v4l2_buffer v4l2_buffer;
- JOT(8, "VIDIOC_QUERYBUF\n");
+ JOM(8, "VIDIOC_QUERYBUF\n");
if (peasycap->video_eof) {
- JOT(8, "returning -1 because %i=video_eof\n", \
+ JOM(8, "returning -EIO because %i=video_eof\n", \
peasycap->video_eof);
- return -1;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
index = v4l2_buffer.index;
if (index < 0 || index >= peasycap->frame_buffer_many)
return -EINVAL;
@@ -1602,49 +2098,55 @@ case VIDIOC_QUERYBUF: {
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
peasycap->done[index] | \
peasycap->queued[index];
- v4l2_buffer.field = peasycap->field;
+ v4l2_buffer.field = V4L2_FIELD_NONE;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;
v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
v4l2_buffer.length = FRAME_BUFFER_SIZE;
- JOT(16, " %10i=index\n", v4l2_buffer.index);
- JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
- JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
- JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
- JOT(16, " %10i=field\n", v4l2_buffer.field);
- JOT(16, " %10li=timestamp.tv_usec\n", \
+ JOM(16, " %10i=index\n", v4l2_buffer.index);
+ JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
+ JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
+ JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
+ JOM(16, " %10i=field\n", v4l2_buffer.field);
+ JOM(16, " %10li=timestamp.tv_usec\n", \
(long)v4l2_buffer.timestamp.tv_usec);
- JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
- JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
- JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
- JOT(16, " %10i=length\n", v4l2_buffer.length);
+ JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
+ JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
+ JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
+ JOM(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QBUF: {
- static struct v4l2_buffer v4l2_buffer;
+ struct v4l2_buffer v4l2_buffer;
- JOT(8, "VIDIOC_QBUF\n");
+ JOM(8, "VIDIOC_QBUF\n");
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- if (v4l2_buffer.memory != V4L2_MEMORY_MMAP)
+ }
+ if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
if (v4l2_buffer.index < 0 || \
- (v4l2_buffer.index >= peasycap->frame_buffer_many))
+ (v4l2_buffer.index >= peasycap->frame_buffer_many)) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
peasycap->done[v4l2_buffer.index] = 0;
@@ -1652,11 +2154,11 @@ case VIDIOC_QBUF: {
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- JOT(8, "..... user queueing frame buffer %i\n", \
+ JOM(8, "..... user queueing frame buffer %i\n", \
(int)v4l2_buffer.index);
peasycap->frame_lock = 0;
@@ -1667,36 +2169,60 @@ case VIDIOC_QBUF: {
case VIDIOC_DQBUF:
{
#if defined(AUDIOTIME)
- static struct signed_div_result sdr;
- static long long int above, below, dnbydt, fudge, sll;
- static unsigned long long int ull;
- static struct timeval timeval0;
+ struct signed_div_result sdr;
+ long long int above, below, dnbydt, fudge, sll;
+ unsigned long long int ull;
+ struct timeval timeval8;
struct timeval timeval1;
#endif /*AUDIOTIME*/
- static struct timeval timeval, timeval2;
- static int i, j;
- static struct v4l2_buffer v4l2_buffer;
+ struct timeval timeval, timeval2;
+ int i, j;
+ struct v4l2_buffer v4l2_buffer;
+ int rcdq;
+ __u16 input;
- JOT(8, "VIDIOC_DQBUF\n");
+ JOM(8, "VIDIOC_DQBUF\n");
if ((peasycap->video_idle) || (peasycap->video_eof)) {
- JOT(8, "returning -EIO because " \
+ JOM(8, "returning -EIO because " \
"%i=video_idle %i=video_eof\n", \
peasycap->video_idle, peasycap->video_eof);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
+
+ if (true == peasycap->offerfields) {
+ /*-----------------------------------------------------------*/
+ /*
+ * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
+ * V4L2_FIELD_BOTTOM
+ */
+ /*-----------------------------------------------------------*/
+ if (V4L2_FIELD_TOP == v4l2_buffer.field)
+ JOM(8, "user wants V4L2_FIELD_TOP\n");
+ else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
+ JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
+ else if (V4L2_FIELD_ANY == v4l2_buffer.field)
+ JOM(8, "user wants V4L2_FIELD_ANY\n");
+ else
+ JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", \
+ v4l2_buffer.field);
+ }
if (!peasycap->video_isoc_streaming) {
- JOT(16, "returning -EIO because video urbs not streaming\n");
+ JOM(16, "returning -EIO because video urbs not streaming\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
/*---------------------------------------------------------------------------*/
@@ -1708,19 +2234,28 @@ case VIDIOC_DQBUF:
/*---------------------------------------------------------------------------*/
if (!peasycap->polled) {
- if (-EIO == easycap_dqbuf(peasycap, 0))
- return -EIO;
+ do {
+ rcdq = easycap_dqbuf(peasycap, 0);
+ if (-EIO == rcdq) {
+ JOM(8, "returning -EIO because " \
+ "dqbuf() returned -EIO\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EIO;
+ }
+ } while (0 != rcdq);
} else {
- if (peasycap->video_eof)
+ if (peasycap->video_eof) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
+ }
}
if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
- SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
+ SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
peasycap->done[peasycap->frame_read]);
}
peasycap->polled = 0;
- if (!(isequence % 10)) {
+ if (!(peasycap->isequence % 10)) {
for (i = 0; i < 179; i++)
peasycap->merit[i] = peasycap->merit[i+1];
peasycap->merit[179] = merit_saa(peasycap->pusb_device);
@@ -1728,7 +2263,7 @@ case VIDIOC_DQBUF:
for (i = 0; i < 180; i++)
j += peasycap->merit[i];
if (90 < j) {
- SAY("easycap driver shutting down " \
+ SAM("easycap driver shutting down " \
"on condition blue\n");
peasycap->video_eof = 1; peasycap->audio_eof = 1;
}
@@ -1738,31 +2273,23 @@ case VIDIOC_DQBUF:
v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.bytesused = peasycap->frame_buffer_used;
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
- v4l2_buffer.field = peasycap->field;
- if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field)
- v4l2_buffer.field = \
- 0x000F & (peasycap->\
- frame_buffer[peasycap->frame_read][0].kount);
+ if (true == peasycap->offerfields)
+ v4l2_buffer.field = V4L2_FIELD_BOTTOM;
+ else
+ v4l2_buffer.field = V4L2_FIELD_NONE;
do_gettimeofday(&timeval);
timeval2 = timeval;
#if defined(AUDIOTIME)
if (!peasycap->timeval0.tv_sec) {
- timeval0 = timeval;
+ timeval8 = timeval;
timeval1 = timeval;
timeval2 = timeval;
dnbydt = 192000;
-
- if (mutex_lock_interruptible(&(peasycap->mutex_timeval0)))
- return -ERESTARTSYS;
- peasycap->timeval0 = timeval0;
- mutex_unlock(&(peasycap->mutex_timeval0));
+ peasycap->timeval0 = timeval8;
} else {
- if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
- return -ERESTARTSYS;
dnbydt = peasycap->dnbydt;
timeval1 = peasycap->timeval1;
- mutex_unlock(&(peasycap->mutex_timeval1));
above = dnbydt * MICROSECONDS(timeval, timeval1);
below = 192000;
sdr = signed_div(above, below);
@@ -1774,72 +2301,76 @@ case VIDIOC_DQBUF:
timeval2.tv_usec = sdr.remainder;
timeval2.tv_sec = timeval1.tv_sec + sdr.quotient;
}
- if (!(isequence % 500)) {
+ if (!(peasycap->isequence % 500)) {
fudge = ((long long int)(1000000)) * \
((long long int)(timeval.tv_sec - \
timeval2.tv_sec)) + \
(long long int)(timeval.tv_usec - \
- timeval2.tv_usec);
+ timeval2.tv_usec);
sdr = signed_div(fudge, 1000);
sll = sdr.quotient;
ull = sdr.remainder;
- SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
+ SAM("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
}
#endif /*AUDIOTIME*/
v4l2_buffer.timestamp = timeval2;
- v4l2_buffer.sequence = isequence++;
+ v4l2_buffer.sequence = peasycap->isequence++;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;
v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
v4l2_buffer.length = FRAME_BUFFER_SIZE;
- JOT(16, " %10i=index\n", v4l2_buffer.index);
- JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
- JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
- JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
- JOT(16, " %10i=field\n", v4l2_buffer.field);
- JOT(16, " %10li=timestamp.tv_usec\n", \
+ JOM(16, " %10i=index\n", v4l2_buffer.index);
+ JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
+ JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
+ JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
+ JOM(16, " %10i=field\n", v4l2_buffer.field);
+ JOM(16, " %10li=timestamp.tv_sec\n", \
+ (long)v4l2_buffer.timestamp.tv_sec);
+ JOM(16, " %10li=timestamp.tv_usec\n", \
(long)v4l2_buffer.timestamp.tv_usec);
- JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
- JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
- JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
- JOT(16, " %10i=length\n", v4l2_buffer.length);
+ JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
+ JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
+ JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
+ JOM(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
- POUT;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- JOT(8, "..... user is offered frame buffer %i\n", \
+ input = peasycap->frame_buffer[peasycap->frame_read][0].input;
+ if (0x08 & input) {
+ JOM(8, "user is offered frame buffer %i, input %i\n", \
+ peasycap->frame_read, (0x07 & input));
+ } else {
+ JOM(8, "user is offered frame buffer %i\n", \
peasycap->frame_read);
+ }
peasycap->frame_lock = 1;
+ JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
if (peasycap->frame_read == peasycap->frame_fill) {
if (peasycap->frame_lock) {
- JOT(8, "ERROR: filling frame buffer " \
+ JOM(8, "WORRY: filling frame buffer " \
"while offered to user\n");
}
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*---------------------------------------------------------------------------*/
-/*
- * AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED;
- * VIDEO URBS HAVE NOT.
- */
-/*---------------------------------------------------------------------------*/
case VIDIOC_STREAMON: {
- static int i;
+ int i;
- JOT(8, "VIDIOC_STREAMON\n");
+ JOM(8, "VIDIOC_STREAMON\n");
- isequence = 0;
+ peasycap->isequence = 0;
for (i = 0; i < 180; i++)
peasycap->merit[i] = 0;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
submit_video_urbs(peasycap);
@@ -1851,10 +2382,11 @@ case VIDIOC_STREAMON: {
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_STREAMOFF: {
- JOT(8, "VIDIOC_STREAMOFF\n");
+ JOM(8, "VIDIOC_STREAMOFF\n");
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
@@ -1866,7 +2398,7 @@ case VIDIOC_STREAMOFF: {
* THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
*/
/*---------------------------------------------------------------------------*/
- JOT(8, "calling wake_up on wq_video and wq_audio\n");
+ JOM(8, "calling wake_up on wq_video and wq_audio\n");
wake_up_interruptible(&(peasycap->wq_video));
wake_up_interruptible(&(peasycap->wq_audio));
/*---------------------------------------------------------------------------*/
@@ -1874,111 +2406,200 @@ case VIDIOC_STREAMOFF: {
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_PARM: {
- static struct v4l2_streamparm v4l2_streamparm;
+ struct v4l2_streamparm *pv4l2_streamparm;
- JOT(8, "VIDIOC_G_PARM\n");
-
- if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \
+ JOM(8, "VIDIOC_G_PARM\n");
+ pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL);
+ if (!pv4l2_streamparm) {
+ SAM("ERROR: out of memory\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ENOMEM;
+ }
+ if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \
sizeof(struct v4l2_streamparm))) {
- POUT;
+ kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
- if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- POUT;
+ if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
- v4l2_streamparm.parm.capture.capability = 0;
- v4l2_streamparm.parm.capture.capturemode = 0;
- v4l2_streamparm.parm.capture.timeperframe.numerator = 1;
- v4l2_streamparm.parm.capture.timeperframe.denominator = 30;
- v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many;
- v4l2_streamparm.parm.capture.extendedmode = 0;
- if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \
+ pv4l2_streamparm->parm.capture.capability = 0;
+ pv4l2_streamparm->parm.capture.capturemode = 0;
+ pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
+
+ if (peasycap->fps) {
+ pv4l2_streamparm->parm.capture.timeperframe.\
+ denominator = peasycap->fps;
+ } else {
+ if (true == peasycap->ntsc) {
+ pv4l2_streamparm->parm.capture.timeperframe.\
+ denominator = 30;
+ } else {
+ pv4l2_streamparm->parm.capture.timeperframe.\
+ denominator = 25;
+ }
+ }
+
+ pv4l2_streamparm->parm.capture.readbuffers = \
+ peasycap->frame_buffer_many;
+ pv4l2_streamparm->parm.capture.extendedmode = 0;
+ if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \
sizeof(struct v4l2_streamparm))) {
- POUT;
+ kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
+ kfree(pv4l2_streamparm);
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_PARM: {
- JOT(8, "VIDIOC_S_PARM unsupported\n");
+ JOM(8, "VIDIOC_S_PARM unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_AUDIO: {
- JOT(8, "VIDIOC_G_AUDIO unsupported\n");
+ JOM(8, "VIDIOC_G_AUDIO unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_AUDIO: {
- JOT(8, "VIDIOC_S_AUDIO unsupported\n");
+ JOM(8, "VIDIOC_S_AUDIO unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_TUNER: {
- JOT(8, "VIDIOC_S_TUNER unsupported\n");
+ JOM(8, "VIDIOC_S_TUNER unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY: {
- JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
+ JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_TUNER: {
- JOT(8, "VIDIOC_G_TUNER unsupported\n");
+ JOM(8, "VIDIOC_G_TUNER unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY: {
- JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
+ JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
default: {
- JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
- explain_ioctl(cmd);
- POUT;
+ JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOIOCTLCMD;
}
}
+mutex_unlock(&easycap_dongle[kd].mutex_video);
+JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
return 0;
}
-
-long easycap_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct inode *inode = file->f_dentry->d_inode;
- long ret;
-
- lock_kernel();
- ret = easycap_ioctl_bkl(inode, file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-
-/*--------------------------------------------------------------------------*/
-static int easysnd_ioctl_bkl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+/*****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
+ (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
+long
+easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
+ return (long)easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+int
+easysnd_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct easycap *peasycap;
struct usb_device *p;
+int kd;
+if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ return -ERESTARTSYS;
+}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL.\n");
- return -1;
+ return -EFAULT;
+}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap\n");
+ return -EFAULT;
}
p = peasycap->pusb_device;
+if (NULL == p) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+/*---------------------------------------------------------------------------*/
+/*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -EFAULT;
+ }
+ p = peasycap->pusb_device;
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+} else {
+/*---------------------------------------------------------------------------*/
+/*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+}
/*---------------------------------------------------------------------------*/
switch (cmd) {
case SNDCTL_DSP_GETCAPS: {
int caps;
- JOT(8, "SNDCTL_DSP_GETCAPS\n");
+ JOM(8, "SNDCTL_DSP_GETCAPS\n");
#if defined(UPSAMPLE)
if (true == peasycap->microphone)
@@ -1992,13 +2613,15 @@ case SNDCTL_DSP_GETCAPS: {
caps = 0x04400000;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETFMTS: {
int incoming;
- JOT(8, "SNDCTL_DSP_GETFMTS\n");
+ JOM(8, "SNDCTL_DSP_GETFMTS\n");
#if defined(UPSAMPLE)
if (true == peasycap->microphone)
@@ -2012,16 +2635,20 @@ case SNDCTL_DSP_GETFMTS: {
incoming = AFMT_S16_LE;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SETFMT: {
int incoming, outgoing;
- JOT(8, "SNDCTL_DSP_SETFMT\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_SETFMT\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
if (true == peasycap->microphone)
@@ -2036,22 +2663,27 @@ case SNDCTL_DSP_SETFMT: {
#endif /*UPSAMPLE*/
if (incoming != outgoing) {
- JOT(8, "........... %i=outgoing\n", outgoing);
- JOT(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
- JOT(8, " cf. %i=AFMT_U8\n", AFMT_U8);
+ JOM(8, "........... %i=outgoing\n", outgoing);
+ JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
+ JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8);
if (0 != copy_to_user((void __user *)arg, &outgoing, \
- sizeof(int)))
+ sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EINVAL ;
}
break;
}
case SNDCTL_DSP_STEREO: {
int incoming;
- JOT(8, "SNDCTL_DSP_STEREO\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_STEREO\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
if (true == peasycap->microphone)
@@ -2065,16 +2697,20 @@ case SNDCTL_DSP_STEREO: {
incoming = 1;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SPEED: {
int incoming;
- JOT(8, "SNDCTL_DSP_SPEED\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_SPEED\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
if (true == peasycap->microphone)
@@ -2088,29 +2724,37 @@ case SNDCTL_DSP_SPEED: {
incoming = 48000;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETTRIGGER: {
int incoming;
- JOT(8, "SNDCTL_DSP_GETTRIGGER\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
incoming = PCM_ENABLE_INPUT;
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SETTRIGGER: {
int incoming;
- JOT(8, "SNDCTL_DSP_SETTRIGGER\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
- JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
+ JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
"0x%x=PCM_ENABLE_OUTPUT\n", \
PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
;
@@ -2121,19 +2765,23 @@ case SNDCTL_DSP_SETTRIGGER: {
}
case SNDCTL_DSP_GETBLKSIZE: {
int incoming;
- JOT(8, "SNDCTL_DSP_GETBLKSIZE\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
- JOT(8, "........... %i=incoming\n", incoming);
+ }
+ JOM(8, "........... %i=incoming\n", incoming);
incoming = peasycap->audio_bytes_per_fragment;
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETISPACE: {
struct audio_buf_info audio_buf_info;
- JOT(8, "SNDCTL_DSP_GETISPACE\n");
+ JOM(8, "SNDCTL_DSP_GETISPACE\n");
audio_buf_info.bytes = peasycap->audio_bytes_per_fragment;
audio_buf_info.fragments = 1;
@@ -2141,555 +2789,31 @@ case SNDCTL_DSP_GETISPACE: {
audio_buf_info.fragstotal = 0;
if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
- sizeof(int)))
+ sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
+case 0x00005401:
+case 0x00005402:
+case 0x00005403:
+case 0x00005404:
+case 0x00005405:
+case 0x00005406: {
+ JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ENOIOCTLCMD;
+}
default: {
- JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
- POUT;
+ JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ENOIOCTLCMD;
}
}
+mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0;
}
+/*****************************************************************************/
-long easysnd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct inode *inode = file->f_dentry->d_inode;
- long ret;
-
- lock_kernel();
- ret = easysnd_ioctl_bkl(inode, file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-/*****************************************************************************/
-int explain_ioctl(__u32 wot)
-{
-int k;
-/*---------------------------------------------------------------------------*/
-/*
- * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
- * SHELL SCRIPT:
- * #
- * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
- * grep "^#define VIDIOC_" - | grep -v "_OLD" - | \
- * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
- * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
- * sed -e "s, ,,g;s, ,,g" >ioctl.tmp
- * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
- * exit 0
- * #
- * AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY.
- *
- * THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
- * SHELL SCRIPT:
- * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \
- * grep "^#define VIDIOC" - | grep -v "_OLD" - | \
- * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
- * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
- * sed -e "s, ,,g;s, ,,g" >ioctl.tmp
- * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
- * exit 0
- * #
- */
-/*---------------------------------------------------------------------------*/
-static struct mess {
- __u32 command;
- char name[64];
-} mess[] = {
-#if defined(VIDIOC_QUERYCAP)
-{VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"},
-#endif
-#if defined(VIDIOC_RESERVED)
-{VIDIOC_RESERVED, "VIDIOC_RESERVED"},
-#endif
-#if defined(VIDIOC_ENUM_FMT)
-{VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"},
-#endif
-#if defined(VIDIOC_G_FMT)
-{VIDIOC_G_FMT, "VIDIOC_G_FMT"},
-#endif
-#if defined(VIDIOC_S_FMT)
-{VIDIOC_S_FMT, "VIDIOC_S_FMT"},
-#endif
-#if defined(VIDIOC_REQBUFS)
-{VIDIOC_REQBUFS, "VIDIOC_REQBUFS"},
-#endif
-#if defined(VIDIOC_QUERYBUF)
-{VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"},
-#endif
-#if defined(VIDIOC_G_FBUF)
-{VIDIOC_G_FBUF, "VIDIOC_G_FBUF"},
-#endif
-#if defined(VIDIOC_S_FBUF)
-{VIDIOC_S_FBUF, "VIDIOC_S_FBUF"},
-#endif
-#if defined(VIDIOC_OVERLAY)
-{VIDIOC_OVERLAY, "VIDIOC_OVERLAY"},
-#endif
-#if defined(VIDIOC_QBUF)
-{VIDIOC_QBUF, "VIDIOC_QBUF"},
-#endif
-#if defined(VIDIOC_DQBUF)
-{VIDIOC_DQBUF, "VIDIOC_DQBUF"},
-#endif
-#if defined(VIDIOC_STREAMON)
-{VIDIOC_STREAMON, "VIDIOC_STREAMON"},
-#endif
-#if defined(VIDIOC_STREAMOFF)
-{VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"},
-#endif
-#if defined(VIDIOC_G_PARM)
-{VIDIOC_G_PARM, "VIDIOC_G_PARM"},
-#endif
-#if defined(VIDIOC_S_PARM)
-{VIDIOC_S_PARM, "VIDIOC_S_PARM"},
-#endif
-#if defined(VIDIOC_G_STD)
-{VIDIOC_G_STD, "VIDIOC_G_STD"},
-#endif
-#if defined(VIDIOC_S_STD)
-{VIDIOC_S_STD, "VIDIOC_S_STD"},
-#endif
-#if defined(VIDIOC_ENUMSTD)
-{VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"},
-#endif
-#if defined(VIDIOC_ENUMINPUT)
-{VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"},
-#endif
-#if defined(VIDIOC_G_CTRL)
-{VIDIOC_G_CTRL, "VIDIOC_G_CTRL"},
-#endif
-#if defined(VIDIOC_S_CTRL)
-{VIDIOC_S_CTRL, "VIDIOC_S_CTRL"},
-#endif
-#if defined(VIDIOC_G_TUNER)
-{VIDIOC_G_TUNER, "VIDIOC_G_TUNER"},
-#endif
-#if defined(VIDIOC_S_TUNER)
-{VIDIOC_S_TUNER, "VIDIOC_S_TUNER"},
-#endif
-#if defined(VIDIOC_G_AUDIO)
-{VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"},
-#endif
-#if defined(VIDIOC_S_AUDIO)
-{VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"},
-#endif
-#if defined(VIDIOC_QUERYCTRL)
-{VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"},
-#endif
-#if defined(VIDIOC_QUERYMENU)
-{VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"},
-#endif
-#if defined(VIDIOC_G_INPUT)
-{VIDIOC_G_INPUT, "VIDIOC_G_INPUT"},
-#endif
-#if defined(VIDIOC_S_INPUT)
-{VIDIOC_S_INPUT, "VIDIOC_S_INPUT"},
-#endif
-#if defined(VIDIOC_G_OUTPUT)
-{VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"},
-#endif
-#if defined(VIDIOC_S_OUTPUT)
-{VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"},
-#endif
-#if defined(VIDIOC_ENUMOUTPUT)
-{VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"},
-#endif
-#if defined(VIDIOC_G_AUDOUT)
-{VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"},
-#endif
-#if defined(VIDIOC_S_AUDOUT)
-{VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"},
-#endif
-#if defined(VIDIOC_G_MODULATOR)
-{VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"},
-#endif
-#if defined(VIDIOC_S_MODULATOR)
-{VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"},
-#endif
-#if defined(VIDIOC_G_FREQUENCY)
-{VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"},
-#endif
-#if defined(VIDIOC_S_FREQUENCY)
-{VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"},
-#endif
-#if defined(VIDIOC_CROPCAP)
-{VIDIOC_CROPCAP, "VIDIOC_CROPCAP"},
-#endif
-#if defined(VIDIOC_G_CROP)
-{VIDIOC_G_CROP, "VIDIOC_G_CROP"},
-#endif
-#if defined(VIDIOC_S_CROP)
-{VIDIOC_S_CROP, "VIDIOC_S_CROP"},
-#endif
-#if defined(VIDIOC_G_JPEGCOMP)
-{VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"},
-#endif
-#if defined(VIDIOC_S_JPEGCOMP)
-{VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"},
-#endif
-#if defined(VIDIOC_QUERYSTD)
-{VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"},
-#endif
-#if defined(VIDIOC_TRY_FMT)
-{VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"},
-#endif
-#if defined(VIDIOC_ENUMAUDIO)
-{VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"},
-#endif
-#if defined(VIDIOC_ENUMAUDOUT)
-{VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"},
-#endif
-#if defined(VIDIOC_G_PRIORITY)
-{VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"},
-#endif
-#if defined(VIDIOC_S_PRIORITY)
-{VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"},
-#endif
-#if defined(VIDIOC_G_SLICED_VBI_CAP)
-{VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"},
-#endif
-#if defined(VIDIOC_LOG_STATUS)
-{VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"},
-#endif
-#if defined(VIDIOC_G_EXT_CTRLS)
-{VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"},
-#endif
-#if defined(VIDIOC_S_EXT_CTRLS)
-{VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"},
-#endif
-#if defined(VIDIOC_TRY_EXT_CTRLS)
-{VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"},
-#endif
-#if defined(VIDIOC_ENUM_FRAMESIZES)
-{VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"},
-#endif
-#if defined(VIDIOC_ENUM_FRAMEINTERVALS)
-{VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"},
-#endif
-#if defined(VIDIOC_G_ENC_INDEX)
-{VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"},
-#endif
-#if defined(VIDIOC_ENCODER_CMD)
-{VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"},
-#endif
-#if defined(VIDIOC_TRY_ENCODER_CMD)
-{VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"},
-#endif
-#if defined(VIDIOC_G_CHIP_IDENT)
-{VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"},
-#endif
-
-#if defined(VIDIOC_OVERLAY_OLD)
-{VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"},
-#endif
-#if defined(VIDIOC_S_PARM_OLD)
-{VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"},
-#endif
-#if defined(VIDIOC_S_CTRL_OLD)
-{VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"},
-#endif
-#if defined(VIDIOC_G_AUDIO_OLD)
-{VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"},
-#endif
-#if defined(VIDIOC_G_AUDOUT_OLD)
-{VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"},
-#endif
-#if defined(VIDIOC_CROPCAP_OLD)
-{VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"},
-#endif
-{0xFFFFFFFF, ""}
-};
-
-static struct mess mess1[] = \
-{
-#if defined(VIDIOCGCAP)
-{VIDIOCGCAP, "VIDIOCGCAP"},
-#endif
-#if defined(VIDIOCGCHAN)
-{VIDIOCGCHAN, "VIDIOCGCHAN"},
-#endif
-#if defined(VIDIOCSCHAN)
-{VIDIOCSCHAN, "VIDIOCSCHAN"},
-#endif
-#if defined(VIDIOCGTUNER)
-{VIDIOCGTUNER, "VIDIOCGTUNER"},
-#endif
-#if defined(VIDIOCSTUNER)
-{VIDIOCSTUNER, "VIDIOCSTUNER"},
-#endif
-#if defined(VIDIOCGPICT)
-{VIDIOCGPICT, "VIDIOCGPICT"},
-#endif
-#if defined(VIDIOCSPICT)
-{VIDIOCSPICT, "VIDIOCSPICT"},
-#endif
-#if defined(VIDIOCCAPTURE)
-{VIDIOCCAPTURE, "VIDIOCCAPTURE"},
-#endif
-#if defined(VIDIOCGWIN)
-{VIDIOCGWIN, "VIDIOCGWIN"},
-#endif
-#if defined(VIDIOCSWIN)
-{VIDIOCSWIN, "VIDIOCSWIN"},
-#endif
-#if defined(VIDIOCGFBUF)
-{VIDIOCGFBUF, "VIDIOCGFBUF"},
-#endif
-#if defined(VIDIOCSFBUF)
-{VIDIOCSFBUF, "VIDIOCSFBUF"},
-#endif
-#if defined(VIDIOCKEY)
-{VIDIOCKEY, "VIDIOCKEY"},
-#endif
-#if defined(VIDIOCGFREQ)
-{VIDIOCGFREQ, "VIDIOCGFREQ"},
-#endif
-#if defined(VIDIOCSFREQ)
-{VIDIOCSFREQ, "VIDIOCSFREQ"},
-#endif
-#if defined(VIDIOCGAUDIO)
-{VIDIOCGAUDIO, "VIDIOCGAUDIO"},
-#endif
-#if defined(VIDIOCSAUDIO)
-{VIDIOCSAUDIO, "VIDIOCSAUDIO"},
-#endif
-#if defined(VIDIOCSYNC)
-{VIDIOCSYNC, "VIDIOCSYNC"},
-#endif
-#if defined(VIDIOCMCAPTURE)
-{VIDIOCMCAPTURE, "VIDIOCMCAPTURE"},
-#endif
-#if defined(VIDIOCGMBUF)
-{VIDIOCGMBUF, "VIDIOCGMBUF"},
-#endif
-#if defined(VIDIOCGUNIT)
-{VIDIOCGUNIT, "VIDIOCGUNIT"},
-#endif
-#if defined(VIDIOCGCAPTURE)
-{VIDIOCGCAPTURE, "VIDIOCGCAPTURE"},
-#endif
-#if defined(VIDIOCSCAPTURE)
-{VIDIOCSCAPTURE, "VIDIOCSCAPTURE"},
-#endif
-#if defined(VIDIOCSPLAYMODE)
-{VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"},
-#endif
-#if defined(VIDIOCSWRITEMODE)
-{VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"},
-#endif
-#if defined(VIDIOCGPLAYINFO)
-{VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"},
-#endif
-#if defined(VIDIOCSMICROCODE)
-{VIDIOCSMICROCODE, "VIDIOCSMICROCODE"},
-#endif
-{0xFFFFFFFF, ""}
-};
-
-k = 0;
-while (mess[k].name[0]) {
- if (wot == mess[k].command) {
- JOT(8, "ioctl 0x%08X is %s\n", \
- mess[k].command, &mess[k].name[0]);
- return 0;
- }
- k++;
-}
-JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot);
-
-k = 0;
-while (mess1[k].name[0]) {
- if (wot == mess1[k].command) {
- JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \
- mess1[k].command, &mess1[k].name[0]);
- return 0;
- }
- k++;
-}
-JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot);
-return -1;
-}
-/*****************************************************************************/
-int explain_cid(__u32 wot)
-{
-int k;
-/*---------------------------------------------------------------------------*/
-/*
- * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
- * SHELL SCRIPT:
- * #
- * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
- * grep "^#define V4L2_CID_" | \
- * sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \
- * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
- * sed -e "s, ,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp
- * echo "{0xFFFFFFFF,\"\"}" >>cid.tmp
- * exit 0
- * #
- */
-/*---------------------------------------------------------------------------*/
-static struct mess
-{
-__u32 command;
-char name[64];
-} mess[] = {
-#if defined(V4L2_CID_USER_CLASS)
-{V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"},
-#endif
-#if defined(V4L2_CID_BRIGHTNESS)
-{V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"},
-#endif
-#if defined(V4L2_CID_CONTRAST)
-{V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"},
-#endif
-#if defined(V4L2_CID_SATURATION)
-{V4L2_CID_SATURATION, "V4L2_CID_SATURATION"},
-#endif
-#if defined(V4L2_CID_HUE)
-{V4L2_CID_HUE, "V4L2_CID_HUE"},
-#endif
-#if defined(V4L2_CID_AUDIO_VOLUME)
-{V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"},
-#endif
-#if defined(V4L2_CID_AUDIO_BALANCE)
-{V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"},
-#endif
-#if defined(V4L2_CID_AUDIO_BASS)
-{V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"},
-#endif
-#if defined(V4L2_CID_AUDIO_TREBLE)
-{V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"},
-#endif
-#if defined(V4L2_CID_AUDIO_MUTE)
-{V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"},
-#endif
-#if defined(V4L2_CID_AUDIO_LOUDNESS)
-{V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"},
-#endif
-#if defined(V4L2_CID_BLACK_LEVEL)
-{V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"},
-#endif
-#if defined(V4L2_CID_AUTO_WHITE_BALANCE)
-{V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"},
-#endif
-#if defined(V4L2_CID_DO_WHITE_BALANCE)
-{V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"},
-#endif
-#if defined(V4L2_CID_RED_BALANCE)
-{V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"},
-#endif
-#if defined(V4L2_CID_BLUE_BALANCE)
-{V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"},
-#endif
-#if defined(V4L2_CID_GAMMA)
-{V4L2_CID_GAMMA, "V4L2_CID_GAMMA"},
-#endif
-#if defined(V4L2_CID_WHITENESS)
-{V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"},
-#endif
-#if defined(V4L2_CID_EXPOSURE)
-{V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"},
-#endif
-#if defined(V4L2_CID_AUTOGAIN)
-{V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"},
-#endif
-#if defined(V4L2_CID_GAIN)
-{V4L2_CID_GAIN, "V4L2_CID_GAIN"},
-#endif
-#if defined(V4L2_CID_HFLIP)
-{V4L2_CID_HFLIP, "V4L2_CID_HFLIP"},
-#endif
-#if defined(V4L2_CID_VFLIP)
-{V4L2_CID_VFLIP, "V4L2_CID_VFLIP"},
-#endif
-#if defined(V4L2_CID_HCENTER)
-{V4L2_CID_HCENTER, "V4L2_CID_HCENTER"},
-#endif
-#if defined(V4L2_CID_VCENTER)
-{V4L2_CID_VCENTER, "V4L2_CID_VCENTER"},
-#endif
-#if defined(V4L2_CID_POWER_LINE_FREQUENCY)
-{V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"},
-#endif
-#if defined(V4L2_CID_HUE_AUTO)
-{V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"},
-#endif
-#if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE)
-{V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"},
-#endif
-#if defined(V4L2_CID_SHARPNESS)
-{V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"},
-#endif
-#if defined(V4L2_CID_BACKLIGHT_COMPENSATION)
-{V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"},
-#endif
-#if defined(V4L2_CID_CHROMA_AGC)
-{V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"},
-#endif
-#if defined(V4L2_CID_COLOR_KILLER)
-{V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"},
-#endif
-#if defined(V4L2_CID_LASTP1)
-{V4L2_CID_LASTP1, "V4L2_CID_LASTP1"},
-#endif
-#if defined(V4L2_CID_CAMERA_CLASS)
-{V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"},
-#endif
-#if defined(V4L2_CID_EXPOSURE_AUTO)
-{V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"},
-#endif
-#if defined(V4L2_CID_EXPOSURE_ABSOLUTE)
-{V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"},
-#endif
-#if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY)
-{V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"},
-#endif
-#if defined(V4L2_CID_PAN_RELATIVE)
-{V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"},
-#endif
-#if defined(V4L2_CID_TILT_RELATIVE)
-{V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"},
-#endif
-#if defined(V4L2_CID_PAN_RESET)
-{V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"},
-#endif
-#if defined(V4L2_CID_TILT_RESET)
-{V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"},
-#endif
-#if defined(V4L2_CID_PAN_ABSOLUTE)
-{V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"},
-#endif
-#if defined(V4L2_CID_TILT_ABSOLUTE)
-{V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"},
-#endif
-#if defined(V4L2_CID_FOCUS_ABSOLUTE)
-{V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"},
-#endif
-#if defined(V4L2_CID_FOCUS_RELATIVE)
-{V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"},
-#endif
-#if defined(V4L2_CID_FOCUS_AUTO)
-{V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"},
-#endif
-{0xFFFFFFFF, ""}
-};
-
-k = 0;
-while (mess[k].name[0]) {
- if (wot == mess[k].command) {
- JOT(8, "ioctl 0x%08X is %s\n", \
- mess[k].command, &mess[k].name[0]);
- return 0;
- }
- k++;
-}
-JOT(8, "cid 0x%08X is not in videodev2.h\n", wot);
-return -1;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c
index ad1fc4cc471a..28c4d1e3c02f 100644
--- a/drivers/staging/easycap/easycap_low.c
+++ b/drivers/staging/easycap/easycap_low.c
@@ -38,148 +38,209 @@
*/
/****************************************************************************/
-#include "easycap_debug.h"
#include "easycap.h"
+#include "easycap_debug.h"
/*--------------------------------------------------------------------------*/
-const struct stk1160config { int reg; int set; } stk1160config[256] = {
- {0x000, 0x0098},
- {0x002, 0x0093},
-
- {0x001, 0x0003},
- {0x003, 0x0080},
- {0x00D, 0x0000},
- {0x00F, 0x0002},
- {0x018, 0x0010},
- {0x019, 0x0000},
- {0x01A, 0x0014},
- {0x01B, 0x000E},
- {0x01C, 0x0046},
-
- {0x100, 0x0033},
- {0x103, 0x0000},
- {0x104, 0x0000},
- {0x105, 0x0000},
- {0x106, 0x0000},
-
-#if defined(PREFER_NTSC)
-
-#undef OLDMARGIN
-#if defined(OLDMARGIN)
- {0x110, 0x0008},
-#else
- {0x110, 0x0014},
-#endif /*OLDMARGIN*/
-
- {0x111, 0x0000},
- {0x112, 0x0003},
- {0x113, 0x0000},
-
-#if defined(OLDMARGIN)
- {0x114, 0x0508},
-#else
- {0x114, 0x0514},
-#endif /*OLDMARGIN*/
-
- {0x115, 0x0005},
- {0x116, 0x00F3},
- {0x117, 0x0000},
-
-#else /* ! PREFER_NTSC*/
-
-#if defined(OLDMARGIN)
- {0x110, 0x0008},
-#else
- {0x110, 0x0014},
-#endif /*OLDMARGIN*/
-
- {0x111, 0x0000},
- {0x112, 0x0020},
- {0x113, 0x0000},
-
-#if defined(OLDMARGIN)
- {0x114, 0x0508},
-#else
- {0x114, 0x0514},
-#endif /*OLDMARGIN*/
-
- {0x115, 0x0005},
- {0x116, 0x0110},
- {0x117, 0x0001},
-
-#endif /* ! PREFER_NTSC*/
-
- {0x202, 0x000F},
- {0x203, 0x004A},
- {0x2FF, 0x0000},
-/*---------------------------------------------------------------------------*/
- {0xFFF, 0xFFFF}
- };
+const struct stk1160config { int reg; int set; } stk1160configPAL[256] = {
+ {0x000, 0x0098},
+ {0x002, 0x0093},
+
+ {0x001, 0x0003},
+ {0x003, 0x0080},
+ {0x00D, 0x0000},
+ {0x00F, 0x0002},
+ {0x018, 0x0010},
+ {0x019, 0x0000},
+ {0x01A, 0x0014},
+ {0x01B, 0x000E},
+ {0x01C, 0x0046},
+
+ {0x100, 0x0033},
+ {0x103, 0x0000},
+ {0x104, 0x0000},
+ {0x105, 0x0000},
+ {0x106, 0x0000},
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * RESOLUTION 640x480
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ {0x110, 0x0008},
+ {0x111, 0x0000},
+ {0x112, 0x0020},
+ {0x113, 0x0000},
+ {0x114, 0x0508},
+ {0x115, 0x0005},
+ {0x116, 0x0110},
+ {0x117, 0x0001},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ {0x202, 0x000F},
+ {0x203, 0x004A},
+ {0x2FF, 0x0000},
+
+ {0xFFF, 0xFFFF}
+};
/*--------------------------------------------------------------------------*/
-const struct saa7113config { int reg; int set; } saa7113config[256] = {
- {0x01, 0x08},
- {0x02, 0x80},
- {0x03, 0x33},
- {0x04, 0x00},
- {0x05, 0x00},
- {0x06, 0xE9},
- {0x07, 0x0D},
-#if defined(PREFER_NTSC)
- {0x08, 0x78},
-#else
- {0x08, 0x38},
-#endif /* ! PREFER_NTSC*/
- {0x09, 0x00},
- {0x0A, SAA_0A_DEFAULT},
- {0x0B, SAA_0B_DEFAULT},
- {0x0C, SAA_0C_DEFAULT},
- {0x0D, SAA_0D_DEFAULT},
- {0x0E, 0x01},
- {0x0F, 0x36},
- {0x10, 0x00},
- {0x11, 0x0C},
- {0x12, 0xE7},
- {0x13, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
-#if defined(PREFER_NTSC)
- {0x40, 0x82},
+const struct stk1160config stk1160configNTSC[256] = {
+ {0x000, 0x0098},
+ {0x002, 0x0093},
+
+ {0x001, 0x0003},
+ {0x003, 0x0080},
+ {0x00D, 0x0000},
+ {0x00F, 0x0002},
+ {0x018, 0x0010},
+ {0x019, 0x0000},
+ {0x01A, 0x0014},
+ {0x01B, 0x000E},
+ {0x01C, 0x0046},
+
+ {0x100, 0x0033},
+ {0x103, 0x0000},
+ {0x104, 0x0000},
+ {0x105, 0x0000},
+ {0x106, 0x0000},
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * RESOLUTION 640x480
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ {0x110, 0x0008},
+ {0x111, 0x0000},
+ {0x112, 0x0003},
+ {0x113, 0x0000},
+ {0x114, 0x0508},
+ {0x115, 0x0005},
+ {0x116, 0x00F3},
+ {0x117, 0x0000},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ {0x202, 0x000F},
+ {0x203, 0x004A},
+ {0x2FF, 0x0000},
+
+ {0xFFF, 0xFFFF}
+};
+/*--------------------------------------------------------------------------*/
+const struct saa7113config { int reg; int set; } saa7113configPAL[256] = {
+ {0x01, 0x08},
+#if defined(ANTIALIAS)
+ {0x02, 0xC0},
#else
- {0x40, 0x02},
-#endif /* ! PREFER_NTSC*/
- {0x41, 0xFF},
- {0x42, 0xFF},
- {0x43, 0xFF},
- {0x44, 0xFF},
- {0x45, 0xFF},
- {0x46, 0xFF},
- {0x47, 0xFF},
- {0x48, 0xFF},
- {0x49, 0xFF},
- {0x4A, 0xFF},
- {0x4B, 0xFF},
- {0x4C, 0xFF},
- {0x4D, 0xFF},
- {0x4E, 0xFF},
- {0x4F, 0xFF},
- {0x50, 0xFF},
- {0x51, 0xFF},
- {0x52, 0xFF},
- {0x53, 0xFF},
- {0x54, 0xFF},
- {0x55, 0xFF},
- {0x56, 0xFF},
- {0x57, 0xFF},
- {0x58, 0x40},
- {0x59, 0x54},
-#if defined(PREFER_NTSC)
- {0x5A, 0x0A},
+ {0x02, 0x80},
+#endif /*ANTIALIAS*/
+ {0x03, 0x33},
+ {0x04, 0x00},
+ {0x05, 0x00},
+ {0x06, 0xE9},
+ {0x07, 0x0D},
+ {0x08, 0x38},
+ {0x09, 0x00},
+ {0x0A, SAA_0A_DEFAULT},
+ {0x0B, SAA_0B_DEFAULT},
+ {0x0C, SAA_0C_DEFAULT},
+ {0x0D, SAA_0D_DEFAULT},
+ {0x0E, 0x01},
+ {0x0F, 0x36},
+ {0x10, 0x00},
+ {0x11, 0x0C},
+ {0x12, 0xE7},
+ {0x13, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x40, 0x02},
+ {0x41, 0xFF},
+ {0x42, 0xFF},
+ {0x43, 0xFF},
+ {0x44, 0xFF},
+ {0x45, 0xFF},
+ {0x46, 0xFF},
+ {0x47, 0xFF},
+ {0x48, 0xFF},
+ {0x49, 0xFF},
+ {0x4A, 0xFF},
+ {0x4B, 0xFF},
+ {0x4C, 0xFF},
+ {0x4D, 0xFF},
+ {0x4E, 0xFF},
+ {0x4F, 0xFF},
+ {0x50, 0xFF},
+ {0x51, 0xFF},
+ {0x52, 0xFF},
+ {0x53, 0xFF},
+ {0x54, 0xFF},
+ {0x55, 0xFF},
+ {0x56, 0xFF},
+ {0x57, 0xFF},
+ {0x58, 0x40},
+ {0x59, 0x54},
+ {0x5A, 0x07},
+ {0x5B, 0x83},
+
+ {0xFF, 0xFF}
+};
+/*--------------------------------------------------------------------------*/
+const struct saa7113config saa7113configNTSC[256] = {
+ {0x01, 0x08},
+#if defined(ANTIALIAS)
+ {0x02, 0xC0},
#else
- {0x5A, 0x07},
-#endif /* ! PREFER_NTSC*/
- {0x5B, 0x83},
- {0xFF, 0xFF}
- };
+ {0x02, 0x80},
+#endif /*ANTIALIAS*/
+ {0x03, 0x33},
+ {0x04, 0x00},
+ {0x05, 0x00},
+ {0x06, 0xE9},
+ {0x07, 0x0D},
+ {0x08, 0x78},
+ {0x09, 0x00},
+ {0x0A, SAA_0A_DEFAULT},
+ {0x0B, SAA_0B_DEFAULT},
+ {0x0C, SAA_0C_DEFAULT},
+ {0x0D, SAA_0D_DEFAULT},
+ {0x0E, 0x01},
+ {0x0F, 0x36},
+ {0x10, 0x00},
+ {0x11, 0x0C},
+ {0x12, 0xE7},
+ {0x13, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x40, 0x82},
+ {0x41, 0xFF},
+ {0x42, 0xFF},
+ {0x43, 0xFF},
+ {0x44, 0xFF},
+ {0x45, 0xFF},
+ {0x46, 0xFF},
+ {0x47, 0xFF},
+ {0x48, 0xFF},
+ {0x49, 0xFF},
+ {0x4A, 0xFF},
+ {0x4B, 0xFF},
+ {0x4C, 0xFF},
+ {0x4D, 0xFF},
+ {0x4E, 0xFF},
+ {0x4F, 0xFF},
+ {0x50, 0xFF},
+ {0x51, 0xFF},
+ {0x52, 0xFF},
+ {0x53, 0xFF},
+ {0x54, 0xFF},
+ {0x55, 0xFF},
+ {0x56, 0xFF},
+ {0x57, 0xFF},
+ {0x58, 0x40},
+ {0x59, 0x54},
+ {0x5A, 0x0A},
+ {0x5B, 0x83},
+
+ {0xFF, 0xFF}
+};
/*--------------------------------------------------------------------------*/
/****************************************************************************/
@@ -187,6 +248,9 @@ int
confirm_resolution(struct usb_device *p)
{
__u8 get0, get1, get2, get3, get4, get5, get6, get7;
+
+if (NULL == p)
+ return -ENODEV;
GET(p, 0x0110, &get0);
GET(p, 0x0111, &get1);
GET(p, 0x0112, &get2);
@@ -227,6 +291,8 @@ confirm_stream(struct usb_device *p)
__u16 get2;
__u8 igot;
+if (NULL == p)
+ return -ENODEV;
GET(p, 0x0100, &igot); get2 = 0x80 & igot;
if (0x80 == get2)
JOT(8, "confirm_stream: OK\n");
@@ -236,15 +302,24 @@ return 0;
}
/****************************************************************************/
int
-setup_stk(struct usb_device *p)
+setup_stk(struct usb_device *p, bool ntsc)
{
int i0;
+if (NULL == p)
+ return -ENODEV;
i0 = 0;
-while (0xFFF != stk1160config[i0].reg) {
- SET(p, stk1160config[i0].reg, stk1160config[i0].set);
- i0++;
+if (true == ntsc) {
+ while (0xFFF != stk1160configNTSC[i0].reg) {
+ SET(p, stk1160configNTSC[i0].reg, stk1160configNTSC[i0].set);
+ i0++;
+ }
+} else {
+ while (0xFFF != stk1160configPAL[i0].reg) {
+ SET(p, stk1160configPAL[i0].reg, stk1160configPAL[i0].set);
+ i0++;
}
+}
write_300(p);
@@ -252,19 +327,26 @@ return 0;
}
/****************************************************************************/
int
-setup_saa(struct usb_device *p)
+setup_saa(struct usb_device *p, bool ntsc)
{
int i0, ir;
-
-set2to78(p);
-
-
+if (NULL == p)
+ return -ENODEV;
i0 = 0;
-while (0xFF != saa7113config[i0].reg) {
- ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set);
- i0++;
+if (true == ntsc) {
+ while (0xFF != saa7113configNTSC[i0].reg) {
+ ir = write_saa(p, saa7113configNTSC[i0].reg, \
+ saa7113configNTSC[i0].set);
+ i0++;
}
+} else {
+ while (0xFF != saa7113configPAL[i0].reg) {
+ ir = write_saa(p, saa7113configPAL[i0].reg, \
+ saa7113configPAL[i0].set);
+ i0++;
+ }
+}
return 0;
}
/****************************************************************************/
@@ -273,6 +355,8 @@ write_000(struct usb_device *p, __u16 set2, __u16 set0)
{
__u8 igot0, igot2;
+if (NULL == p)
+ return -ENODEV;
GET(p, 0x0002, &igot2);
GET(p, 0x0000, &igot0);
SET(p, 0x0002, set2);
@@ -283,6 +367,8 @@ return 0;
int
write_saa(struct usb_device *p, __u16 reg0, __u16 set0)
{
+if (NULL == p)
+ return -ENODEV;
SET(p, 0x200, 0x00);
SET(p, 0x204, reg0);
SET(p, 0x205, set0);
@@ -306,6 +392,8 @@ __u8 igot;
__u16 got502, got503;
__u16 set502, set503;
+if (NULL == p)
+ return -ENODEV;
SET(p, 0x0504, reg0);
SET(p, 0x0500, 0x008B);
@@ -341,6 +429,8 @@ read_vt(struct usb_device *p, __u16 reg0)
__u8 igot;
__u16 got502, got503;
+if (NULL == p)
+ return -ENODEV;
SET(p, 0x0504, reg0);
SET(p, 0x0500, 0x008B);
@@ -360,6 +450,8 @@ return (got503 << 8) | got502;
int
write_300(struct usb_device *p)
{
+if (NULL == p)
+ return -ENODEV;
SET(p, 0x300, 0x0012);
SET(p, 0x350, 0x002D);
SET(p, 0x351, 0x0001);
@@ -376,24 +468,48 @@ return 0;
*/
/*--------------------------------------------------------------------------*/
int
-check_saa(struct usb_device *p)
+check_saa(struct usb_device *p, bool ntsc)
{
int i0, ir, rc;
-i0 = 0;
+if (NULL == p)
+ return -ENODEV;
+i0 = 0;
rc = 0;
-while (0xFF != saa7113config[i0].reg) {
- if (0x0F == saa7113config[i0].reg) {
- i0++; continue;
+if (true == ntsc) {
+ while (0xFF != saa7113configNTSC[i0].reg) {
+ if (0x0F == saa7113configNTSC[i0].reg) {
+ i0++;
+ continue;
+ }
+
+ ir = read_saa(p, saa7113configNTSC[i0].reg);
+ if (ir != saa7113configNTSC[i0].set) {
+ SAY("SAA register 0x%02X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ saa7113configNTSC[i0].reg, \
+ ir, saa7113configNTSC[i0].set);
+ rc--;
+ }
+ i0++;
}
+} else {
+ while (0xFF != saa7113configPAL[i0].reg) {
+ if (0x0F == saa7113configPAL[i0].reg) {
+ i0++;
+ continue;
+ }
- ir = read_saa(p, saa7113config[i0].reg);
- if (ir != saa7113config[i0].set) {
- SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \
- saa7113config[i0].reg, ir, saa7113config[i0].set);
- rc--;
+ ir = read_saa(p, saa7113configPAL[i0].reg);
+ if (ir != saa7113configPAL[i0].set) {
+ SAY("SAA register 0x%02X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ saa7113configPAL[i0].reg, \
+ ir, saa7113configPAL[i0].set);
+ rc--;
+ }
+ i0++;
}
- i0++;
}
if (-8 > rc)
return rc;
@@ -406,6 +522,8 @@ merit_saa(struct usb_device *p)
{
int rc;
+if (NULL == p)
+ return -ENODEV;
rc = read_saa(p, 0x1F);
if ((0 > rc) || (0x02 & rc))
return 1 ;
@@ -416,29 +534,46 @@ else
int
ready_saa(struct usb_device *p)
{
-int j, rc;
-static int max = 10;
-
+int j, rc, rate;
+const int max = 5, marktime = PATIENCE/5;
+/*--------------------------------------------------------------------------*/
+/*
+ * RETURNS 0 FOR INTERLACED 50 Hz
+ * 1 FOR NON-INTERLACED 50 Hz
+ * 2 FOR INTERLACED 60 Hz
+ * 3 FOR NON-INTERLACED 60 Hz
+*/
+/*--------------------------------------------------------------------------*/
+if (NULL == p)
+ return -ENODEV;
j = 0;
while (max > j) {
rc = read_saa(p, 0x1F);
if (0 <= rc) {
- if ((1 == (0x01 & rc))&&(0 == (0x40 & rc)))
+ if (0 == (0x40 & rc))
+ break;
+ if (1 == (0x01 & rc))
break;
}
- msleep(100); j++;
+ msleep(marktime);
+ j++;
}
if (max == j)
return -1;
else {
- if (0x20 & rc)
+ if (0x20 & rc) {
+ rate = 2;
JOT(8, "hardware detects 60 Hz\n");
- else
+ } else {
+ rate = 0;
JOT(8, "hardware detects 50 Hz\n");
+ }
if (0x80 & rc)
JOT(8, "hardware detects interlacing\n");
- else
+ else {
+ rate++;
JOT(8, "hardware detects no interlacing\n");
+ }
}
return 0;
}
@@ -447,45 +582,80 @@ return 0;
/*
* NOTE: THE FOLLOWING ARE NOT CHECKED:
* REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN
- * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set)
+ * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config....[.].set)
*/
/*--------------------------------------------------------------------------*/
int
-check_stk(struct usb_device *p)
+check_stk(struct usb_device *p, bool ntsc)
{
int i0, ir;
-i0 = 0;
-while (0xFFF != stk1160config[i0].reg) {
- if (0x000 == stk1160config[i0].reg) {
- i0++; continue;
- }
- if (0x002 == stk1160config[i0].reg) {
- i0++; continue;
- }
-
- ir = read_stk(p, stk1160config[i0].reg);
- if (0x100 == stk1160config[i0].reg) {
- if ((ir != (0xFF & stk1160config[i0].set)) && \
- (ir != (0x80 | (0xFF & stk1160config[i0].set))) && \
- (0xFFFF != stk1160config[i0].set)) {
- SAY("STK register 0x%03X has 0x%02X, " \
- "expected 0x%02X\n", \
- stk1160config[i0].reg, ir, \
- stk1160config[i0].set);
+if (NULL == p)
+ return -ENODEV;
+i0 = 0;
+if (true == ntsc) {
+ while (0xFFF != stk1160configNTSC[i0].reg) {
+ if (0x000 == stk1160configNTSC[i0].reg) {
+ i0++; continue;
+ }
+ if (0x002 == stk1160configNTSC[i0].reg) {
+ i0++; continue;
+ }
+ ir = read_stk(p, stk1160configNTSC[i0].reg);
+ if (0x100 == stk1160configNTSC[i0].reg) {
+ if ((ir != (0xFF & stk1160configNTSC[i0].set)) && \
+ (ir != (0x80 | (0xFF & \
+ stk1160configNTSC[i0].set))) && \
+ (0xFFFF != \
+ stk1160configNTSC[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160configNTSC[i0].reg, \
+ ir, stk1160configNTSC[i0].set);
+ }
+ i0++; continue;
}
- i0++; continue;
+ if ((ir != (0xFF & stk1160configNTSC[i0].set)) && \
+ (0xFFFF != stk1160configNTSC[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160configNTSC[i0].reg, \
+ ir, stk1160configNTSC[i0].set);
}
-
- if ((ir != (0xFF & stk1160config[i0].set)) && \
- (0xFFFF != stk1160config[i0].set)) {
- SAY("STK register 0x%03X has 0x%02X, " \
- "expected 0x%02X\n", \
- stk1160config[i0].reg, ir, \
- stk1160config[i0].set);
+ i0++;
+ }
+} else {
+ while (0xFFF != stk1160configPAL[i0].reg) {
+ if (0x000 == stk1160configPAL[i0].reg) {
+ i0++; continue;
}
- i0++;
+ if (0x002 == stk1160configPAL[i0].reg) {
+ i0++; continue;
+ }
+ ir = read_stk(p, stk1160configPAL[i0].reg);
+ if (0x100 == stk1160configPAL[i0].reg) {
+ if ((ir != (0xFF & stk1160configPAL[i0].set)) && \
+ (ir != (0x80 | (0xFF & \
+ stk1160configPAL[i0].set))) && \
+ (0xFFFF != \
+ stk1160configPAL[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160configPAL[i0].reg, \
+ ir, stk1160configPAL[i0].set);
+ }
+ i0++; continue;
+ }
+ if ((ir != (0xFF & stk1160configPAL[i0].set)) && \
+ (0xFFFF != stk1160configPAL[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160configPAL[i0].reg, \
+ ir, stk1160configPAL[i0].set);
+ }
+ i0++;
}
+}
return 0;
}
/****************************************************************************/
@@ -494,6 +664,8 @@ read_saa(struct usb_device *p, __u16 reg0)
{
__u8 igot;
+if (NULL == p)
+ return -ENODEV;
SET(p, 0x208, reg0);
SET(p, 0x200, 0x20);
if (0 != wait_i2c(p))
@@ -508,12 +680,14 @@ read_stk(struct usb_device *p, __u32 reg0)
{
__u8 igot;
+if (NULL == p)
+ return -ENODEV;
igot = 0;
GET(p, reg0, &igot);
return igot;
}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
/*
* HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE
*
@@ -534,81 +708,100 @@ return igot;
int
select_input(struct usb_device *p, int input, int mode)
{
+int ir;
+if (NULL == p)
+ return -ENODEV;
stop_100(p);
-
-msleep(20);
switch (input) {
case 0:
case 1: {
- SET(p, 0x0000, 0x0098); break;
+ if (0 != write_saa(p, 0x02, 0x80)) {
+ SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \
+ input);
+ }
+ SET(p, 0x0000, 0x0098);
+ SET(p, 0x0002, 0x0078);
+ break;
}
case 2: {
- SET(p, 0x0000, 0x0090); break;
+ if (0 != write_saa(p, 0x02, 0x80)) {
+ SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \
+ input);
+ }
+ SET(p, 0x0000, 0x0090);
+ SET(p, 0x0002, 0x0078);
+ break;
}
case 3: {
- SET(p, 0x0000, 0x0088); break;
+ if (0 != write_saa(p, 0x02, 0x80)) {
+ SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \
+ input);
+ }
+ SET(p, 0x0000, 0x0088);
+ SET(p, 0x0002, 0x0078);
+ break;
}
case 4: {
- SET(p, 0x0000, 0x0080); break;
+ if (0 != write_saa(p, 0x02, 0x80)) {
+ SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \
+ input);
+ }
+ SET(p, 0x0000, 0x0080);
+ SET(p, 0x0002, 0x0078);
+ break;
}
case 5: {
if (9 != mode)
mode = 7;
switch (mode) {
- case 7:
- {
+ case 7: {
if (0 != write_saa(p, 0x02, 0x87)) {
- SAY("ERROR: failed to set SAA " \
- "register 0x02 for input " \
- "%i\n", input);
+ SAY("ERROR: failed to set SAA register 0x02 " \
+ "for input %i\n", input);
}
if (0 != write_saa(p, 0x05, 0xFF)) {
- SAY("ERROR: failed to set SAA " \
- "register 0x05 for input " \
- "%i\n", input);
+ SAY("ERROR: failed to set SAA register 0x05 " \
+ "for input %i\n", input);
}
break;
}
- case 9:
- {
+ case 9: {
if (0 != write_saa(p, 0x02, 0x89)) {
- SAY("ERROR: failed to set SAA " \
- "register 0x02 for input " \
- "%i\n", input);
+ SAY("ERROR: failed to set SAA register 0x02 " \
+ "for input %i\n", input);
}
if (0 != write_saa(p, 0x05, 0x00)) {
- SAY("ERROR: failed to set SAA " \
- "register 0x05 for input " \
- "%i\n", input);
+ SAY("ERROR: failed to set SAA register 0x05 " \
+ "for input %i\n", input);
}
- break;
+ break;
}
- default:
- {
+ default: {
SAY("MISTAKE: bad mode: %i\n", mode);
return -1;
- }
+ }
}
if (0 != write_saa(p, 0x04, 0x00)) {
- SAY("ERROR: failed to set SAA register 0x04 " \
- "for input %i\n", input);
+ SAY("ERROR: failed to set SAA register 0x04 for input %i\n", \
+ input);
}
if (0 != write_saa(p, 0x09, 0x80)) {
- SAY("ERROR: failed to set SAA register 0x09 " \
- "for input %i\n", input);
+ SAY("ERROR: failed to set SAA register 0x09 for input %i\n", \
+ input);
}
+ SET(p, 0x0002, 0x0093);
break;
}
-default:
- {
+default: {
SAY("ERROR: bad input: %i\n", input);
return -1;
}
}
-msleep(20);
-SET(p, 0x0002, 0x0093);
-msleep(20);
+ir = read_stk(p, 0x00);
+JOT(8, "STK register 0x00 has 0x%02X\n", ir);
+ir = read_saa(p, 0x02);
+JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
start_100(p);
@@ -621,6 +814,8 @@ set_resolution(struct usb_device *p, \
{
__u16 u0x0111, u0x0113, u0x0115, u0x0117;
+if (NULL == p)
+ return -ENODEV;
u0x0111 = ((0xFF00 & set0) >> 8);
u0x0113 = ((0xFF00 & set1) >> 8);
u0x0115 = ((0xFF00 & set2) >> 8);
@@ -641,13 +836,25 @@ return 0;
int
start_100(struct usb_device *p)
{
-__u16 get0;
-__u8 igot;
-
-GET(p, 0x0100, &igot); get0 = igot;
-msleep(0x1f4);
+__u16 get116, get117, get0;
+__u8 igot116, igot117, igot;
+
+if (NULL == p)
+ return -ENODEV;
+GET(p, 0x0116, &igot116);
+get116 = igot116;
+GET(p, 0x0117, &igot117);
+get117 = igot117;
+SET(p, 0x0116, 0x0000);
+SET(p, 0x0117, 0x0000);
+
+GET(p, 0x0100, &igot);
+get0 = igot;
SET(p, 0x0100, (0x80 | get0));
-msleep(0x1f4);
+
+SET(p, 0x0116, get116);
+SET(p, 0x0117, get117);
+
return 0;
}
/****************************************************************************/
@@ -657,10 +864,11 @@ stop_100(struct usb_device *p)
__u16 get0;
__u8 igot;
-GET(p, 0x0100, &igot); get0 = igot;
-msleep(0x1f4);
+if (NULL == p)
+ return -ENODEV;
+GET(p, 0x0100, &igot);
+get0 = igot;
SET(p, 0x0100, (0x7F & get0));
-msleep(0x1f4);
return 0;
}
/****************************************************************************/
@@ -674,9 +882,11 @@ wait_i2c(struct usb_device *p)
{
__u16 get0;
__u8 igot;
-const int max = 4;
+const int max = 2;
int k;
+if (NULL == p)
+ return -ENODEV;
for (k = 0; k < max; k++) {
GET(p, 0x0201, &igot); get0 = igot;
switch (get0) {
@@ -685,7 +895,7 @@ for (k = 0; k < max; k++) {
return 0;
}
case 0x00: {
- msleep(10);
+ msleep(20);
continue;
}
default: {
@@ -703,8 +913,7 @@ __u16 igot;
int rc0, rc1;
if (!pusb_device)
- return -EFAULT;
-
+ return -ENODEV;
rc1 = 0; igot = 0;
rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)0x01, \
@@ -741,27 +950,14 @@ case 0x204:
case 0x205:
case 0x350:
case 0x351: {
- if (0 != igot) {
+ if (0 != (0xFF & igot)) {
JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \
igot, index);
}
break;
}
-case 0x114:
-case 0x116: {
- if ((0xFF & value) != igot) {
- JOT(8, "unexpected 0x%02X != 0x%02X " \
- "for STK register 0x%03X\n", \
- igot, value, index);
- }
-break;
-}
-case 0x200: {
- if (0 == igot)
- break;
-}
default: {
- if (value != igot) {
+ if ((0xFF & value) != (0xFF & igot)) {
JOT(8, "unexpected 0x%02X != 0x%02X " \
"for STK register 0x%03X\n", \
igot, value, index);
@@ -780,8 +976,7 @@ regget(struct usb_device *pusb_device, __u16 index, void *pvoid)
int ir;
if (!pusb_device)
- return -EFAULT;
-
+ return -ENODEV;
ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
(__u8)0x00, \
(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
@@ -796,6 +991,8 @@ return 0xFF & ir;
int
wakeup_device(struct usb_device *pusb_device)
{
+if (!pusb_device)
+ return -ENODEV;
return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(__u8)USB_REQ_SET_FEATURE, \
(__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \
@@ -806,6 +1003,12 @@ return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(int)50000);
}
/*****************************************************************************/
+int
+audio_setup(struct easycap *peasycap)
+{
+struct usb_device *pusb_device;
+unsigned char buffer[1];
+int rc, id1, id2;
/*---------------------------------------------------------------------------*/
/*
* IMPORTANT:
@@ -814,29 +1017,21 @@ return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
* TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.
*/
/*---------------------------------------------------------------------------*/
-int
-audio_setup(struct easycap *peasycap)
-{
-struct usb_device *pusb_device;
-static __u8 request = 0x01;
-static __u8 requesttype = \
+const __u8 request = 0x01;
+const __u8 requesttype = \
(__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
-
-static __u16 value_unmute = 0x0200;
-static __u16 index = 0x0301;
-
-static unsigned char buffer[1];
-static __u16 length = 1;
-int rc, id1, id2;
+const __u16 value_unmute = 0x0200;
+const __u16 index = 0x0301;
+const __u16 length = 1;
if (NULL == peasycap)
return -EFAULT;
pusb_device = peasycap->pusb_device;
if (NULL == pusb_device)
- return -EFAULT;
+ return -ENODEV;
-JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \
+JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \
requesttype, request, \
(0x00FF & value_unmute), \
(0xFF00 & value_unmute) >> 8, \
@@ -875,41 +1070,25 @@ if (rc != (int)length)
* THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
*/
/*--------------------------------------------------------------------------*/
-
SET(pusb_device, 0x0500, 0x0094);
-
SET(pusb_device, 0x0500, 0x008C);
-
SET(pusb_device, 0x0506, 0x0001);
SET(pusb_device, 0x0507, 0x0000);
-
id1 = read_vt(pusb_device, 0x007C);
id2 = read_vt(pusb_device, 0x007E);
-SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2);
-
+SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
/*---------------------------------------------------------------------------*/
/*
-* SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB.
-*
-* THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN
-* THERE IS NO SEPARATE AUDIO CHIP PRESENT.
+ * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
*/
/*---------------------------------------------------------------------------*/
-
-write_vt(pusb_device, 0x0002, 0x8000);
-write_vt(pusb_device, 0x001C, 0x8000);
-
-write_vt(pusb_device, 0x000E, 0x0000);
-write_vt(pusb_device, 0x0010, 0x0000);
-write_vt(pusb_device, 0x0012, 0x8000);
-write_vt(pusb_device, 0x0016, 0x0000);
-
-write_vt(pusb_device, 0x001A, 0x0404);
-write_vt(pusb_device, 0x0002, 0x0000);
-write_vt(pusb_device, 0x001C, 0x0000);
-
+if (31 < easycap_gain)
+ easycap_gain = 31;
+if (0 > easycap_gain)
+ easycap_gain = 0;
+if (0 != audio_gainset(pusb_device, (__s8)easycap_gain))
+ SAY("ERROR: audio_gainset() failed\n");
check_vt(pusb_device);
-
return 0;
}
/*****************************************************************************/
@@ -918,6 +1097,8 @@ check_vt(struct usb_device *pusb_device)
{
int igot;
+if (!pusb_device)
+ return -ENODEV;
igot = read_vt(pusb_device, 0x0002);
if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x02\n");
@@ -942,17 +1123,23 @@ if (0 > igot)
if (0x8000 & igot)
SAY("register 0x%02X muted\n", 0x12);
+igot = read_vt(pusb_device, 0x0014);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x14\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x14);
+
igot = read_vt(pusb_device, 0x0016);
if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x16\n");
if (0x8000 & igot)
SAY("register 0x%02X muted\n", 0x16);
-igot = read_vt(pusb_device, 0x001A);
+igot = read_vt(pusb_device, 0x0018);
if (0 > igot)
- SAY("ERROR: failed to read VT1612A register 0x1A\n");
+ SAY("ERROR: failed to read VT1612A register 0x18\n");
if (0x8000 & igot)
- SAY("register 0x%02X muted\n", 0x1A);
+ SAY("register 0x%02X muted\n", 0x18);
igot = read_vt(pusb_device, 0x001C);
if (0 > igot)
@@ -964,14 +1151,18 @@ return 0;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
-/*
- * NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
- * audio_gainset(pusb_device, 0x000F);
+/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
+ * audio_gainset(pusb_device, 0x000F);
*
- * IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN.
- * IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN.
- * THERE IS NEVER ANY (ADDITIONAL) ATTENUATION.
- */
+ * loud dB register 0x10 dB register 0x1C dB total
+ * 0 -34.5 0 -34.5
+ * .. .... . ....
+ * 15 10.5 0 10.5
+ * 16 12.0 0 12.0
+ * 17 12.0 1.5 13.5
+ * .. .... .... ....
+ * 31 12.0 22.5 34.5
+*/
/*---------------------------------------------------------------------------*/
int
audio_gainset(struct usb_device *pusb_device, __s8 loud)
@@ -980,25 +1171,65 @@ int igot;
__u8 u8;
__u16 mute;
-if (16 > loud)
- loud = 16;
-u8 = 0x000F & (__u8)(loud - 16);
+if (NULL == pusb_device)
+ return -ENODEV;
+if (0 > loud)
+ loud = 0;
+if (31 < loud)
+ loud = 31;
write_vt(pusb_device, 0x0002, 0x8000);
+/*---------------------------------------------------------------------------*/
+igot = read_vt(pusb_device, 0x000E);
+if (0 > igot) {
+ SAY("ERROR: failed to read VT1612A register 0x0E\n");
+ mute = 0x0000;
+} else
+ mute = 0x8000 & ((unsigned int)igot);
+mute = 0;
+
+if (16 > loud)
+ u8 = 0x01 | (0x001F & (((__u8)(15 - loud)) << 1));
+else
+ u8 = 0;
+JOT(8, "0x%04X=(mute|u8) for VT1612A register 0x0E\n", mute | u8);
+write_vt(pusb_device, 0x000E, (mute | u8));
+/*---------------------------------------------------------------------------*/
+igot = read_vt(pusb_device, 0x0010);
+if (0 > igot) {
+ SAY("ERROR: failed to read VT1612A register 0x10\n");
+ mute = 0x0000;
+} else
+ mute = 0x8000 & ((unsigned int)igot);
+mute = 0;
+
+JOT(8, "0x%04X=(mute|u8|(u8<<8)) for VT1612A register 0x10,...0x18\n", \
+ mute | u8 | (u8 << 8));
+write_vt(pusb_device, 0x0010, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0012, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0014, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0016, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0018, (mute | u8 | (u8 << 8)));
+/*---------------------------------------------------------------------------*/
igot = read_vt(pusb_device, 0x001C);
if (0 > igot) {
SAY("ERROR: failed to read VT1612A register 0x1C\n");
mute = 0x0000;
} else
mute = 0x8000 & ((unsigned int)igot);
+mute = 0;
-JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8));
+if (16 <= loud)
+ u8 = 0x000F & (__u8)(loud - 16);
+else
+ u8 = 0;
-write_vt(pusb_device, 0x001C, 0x8000);
+JOT(8, "0x%04X=(mute|u8|(u8<<8)) for VT1612A register 0x1C\n", \
+ mute | u8 | (u8 << 8));
write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x001A, 0x0404);
write_vt(pusb_device, 0x0002, 0x0000);
-
return 0;
}
/*****************************************************************************/
@@ -1007,35 +1238,11 @@ audio_gainget(struct usb_device *pusb_device)
{
int igot;
+if (NULL == pusb_device)
+ return -ENODEV;
igot = read_vt(pusb_device, 0x001C);
if (0 > igot)
SAY("ERROR: failed to read VT1612A register 0x1C\n");
return igot;
}
/*****************************************************************************/
-int
-set2to78(struct usb_device *p)
-{
-int ir;
-
-msleep(20);
-ir = regset(p, 0x0002, 0x0078);
-if (0 > ir)
- SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
-msleep(20);
-return ir;
-}
-/*****************************************************************************/
-int
-set2to93(struct usb_device *p)
-{
-int ir;
-
-msleep(20);
-ir = regset(p, 0x0002, 0x0093);
-if (0 > ir)
- SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
-msleep(20);
-return ir;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
index 5a4bbd9b453f..acc1f56e6f29 100644
--- a/drivers/staging/easycap/easycap_main.c
+++ b/drivers/staging/easycap/easycap_main.c
@@ -30,9 +30,29 @@
#include "easycap.h"
#include "easycap_standard.h"
+#include "easycap_ioctl.h"
-int easycap_debug;
-module_param(easycap_debug, int, S_IRUGO | S_IWUSR);
+static int easycap_debug;
+static int easycap_bars;
+int easycap_gain = 16;
+module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
+module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
+module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
+
+/*---------------------------------------------------------------------------*/
+/*
+ * dongle_this IS INDISPENSIBLY static BECAUSE FUNCTION easycap_usb_probe()
+ * IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
+ * ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
+ * PROBING INTERFACES 1 AND 2.
+ *
+ * IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL.
+*/
+/*---------------------------------------------------------------------------*/
+
+struct easycap_dongle easycap_dongle[DONGLE_MANY];
+static int dongle_this;
+static int dongle_done;
/*---------------------------------------------------------------------------*/
/*
@@ -63,22 +83,25 @@ const struct file_operations easycap_fops = {
.owner = THIS_MODULE,
.open = easycap_open,
.release = easycap_release,
- .unlocked_ioctl = easycap_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easycap_ioctl_noinode,
+#else
+ .ioctl = easycap_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.poll = easycap_poll,
.mmap = easycap_mmap,
.llseek = no_llseek,
};
struct vm_operations_struct easycap_vm_ops = {
-.open = easycap_vma_open,
-.close = easycap_vma_close,
-.fault = easycap_vma_fault,
+ .open = easycap_vma_open,
+ .close = easycap_vma_close,
+ .fault = easycap_vma_fault,
};
struct usb_class_driver easycap_class = {
-.name = "usb/easycap%d",
-.fops = &easycap_fops,
-.minor_base = USB_SKEL_MINOR_BASE,
+ .name = "usb/easycap%d",
+ .fops = &easycap_fops,
+ .minor_base = USB_SKEL_MINOR_BASE,
};
-
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
#if defined(EASYCAP_NEEDS_V4L2_FOPS)
@@ -86,16 +109,17 @@ const struct v4l2_file_operations v4l2_fops = {
.owner = THIS_MODULE,
.open = easycap_open_noinode,
.release = easycap_release_noinode,
- .unlocked_ioctl = easycap_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easycap_ioctl_noinode,
+#else
+ .ioctl = easycap_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.poll = easycap_poll,
.mmap = easycap_mmap,
};
#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
-int video_device_many /*=0*/;
-struct video_device *pvideo_array[VIDEO_DEVICE_MANY], *pvideo_device;
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
/*--------------------------------------------------------------------------*/
/*
* PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
@@ -105,7 +129,11 @@ const struct file_operations easysnd_fops = {
.owner = THIS_MODULE,
.open = easysnd_open,
.release = easysnd_release,
- .unlocked_ioctl = easysnd_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easysnd_ioctl_noinode,
+#else
+ .ioctl = easysnd_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.read = easysnd_read,
.llseek = no_llseek,
};
@@ -115,17 +143,26 @@ struct usb_class_driver easysnd_class = {
.minor_base = USB_SKEL_MINOR_BASE,
};
/****************************************************************************/
-/*--------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
/*
- * IT IS NOT APPROPRIATE FOR easycap_open() TO SUBMIT THE VIDEO URBS HERE,
- * BECAUSE THERE WILL ALWAYS BE SUBSEQUENT NEGOTIATION OF TV STANDARD AND
- * FORMAT BY IOCTL AND IT IS INADVISABLE TO HAVE THE URBS RUNNING WHILE
- * REGISTERS OF THE SA7113H ARE BEING MANIPULATED.
- *
- * THE SUBMISSION OF VIDEO URBS IS THEREFORE DELAYED UNTIL THE IOCTL COMMAND
- * STREAMON IS RECEIVED.
- */
-/*--------------------------------------------------------------------------*/
+ * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
+*/
+/*---------------------------------------------------------------------------*/
+int
+isdongle(struct easycap *peasycap)
+{
+int k;
+if (NULL == peasycap)
+ return -2;
+for (k = 0; k < DONGLE_MANY; k++) {
+ if (easycap_dongle[k].peasycap == peasycap) {
+ peasycap->isdongle = k;
+ return k;
+ }
+}
+return -1;
+}
+/*****************************************************************************/
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
int
@@ -140,15 +177,17 @@ easycap_open(struct inode *inode, struct file *file)
{
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
struct usb_interface *pusb_interface;
+#else
+struct video_device *pvideo_device;
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
-struct usb_device *p;
struct easycap *peasycap;
-int i, k, m, rc;
+int rc;
JOT(4, "\n");
SAY("==========OPEN=========\n");
peasycap = (struct easycap *)NULL;
+/*---------------------------------------------------------------------------*/
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
if ((struct inode *)NULL == inode) {
SAY("ERROR: inode is NULL.\n");
@@ -162,161 +201,427 @@ if (!pusb_interface) {
peasycap = usb_get_intfdata(pusb_interface);
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#else
-for (i = 0; i < video_device_many; i++) {
- pvideo_device = pvideo_array[i];
- if ((struct video_device *)NULL != pvideo_device) {
- peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
- break;
- }
+pvideo_device = video_devdata(file);
+if ((struct video_device *)NULL == pvideo_device) {
+ SAY("ERROR: pvideo_device is NULL.\n");
+ return -EFAULT;
}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
-if ((struct easycap *)NULL == peasycap) {
- SAY("MISTAKE: peasycap is NULL\n");
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
-file->private_data = peasycap;
-/*---------------------------------------------------------------------------*/
-/*
- * INITIALIZATION
- */
-/*---------------------------------------------------------------------------*/
-JOT(4, "starting initialization\n");
-
-for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
- memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
}
-p = peasycap->pusb_device;
-if ((struct usb_device *)NULL == p) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
} else {
- JOT(16, "0x%08lX=peasycap->pusb_device\n", \
+ JOM(16, "0x%08lX=peasycap->pusb_device\n", \
(long int)peasycap->pusb_device);
}
+file->private_data = peasycap;
rc = wakeup_device(peasycap->pusb_device);
if (0 == rc)
- JOT(8, "wakeup_device() OK\n");
+ JOM(8, "wakeup_device() OK\n");
else {
- SAY("ERROR: wakeup_device() returned %i\n", rc);
+ SAM("ERROR: wakeup_device() returned %i\n", rc);
+ if (-ENODEV == rc)
+ SAM("ERROR: wakeup_device() returned -ENODEV\n");
+ else
+ SAM("ERROR: wakeup_device() returned %i\n", rc);
+ return rc;
+}
+peasycap->input = 0;
+rc = reset(peasycap);
+if (0 != rc) {
+ SAM("ERROR: reset() returned %i\n", rc);
return -EFAULT;
}
-rc = setup_stk(p); peasycap->input = 0;
-if (0 == rc)
- JOT(8, "setup_stk() OK\n");
-else {
- SAY("ERROR: setup_stk() returned %i\n", rc);
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * RESET THE HARDWARE TO ITS REFERENCE STATE.
+ *
+ * THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
+ * A BAD VIDEO FRAME SIZE.
+*/
+/*---------------------------------------------------------------------------*/
+int
+reset(struct easycap *peasycap)
+{
+struct easycap_standard const *peasycap_standard;
+int i, rc, input, rate;
+bool ntsc, other;
+
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
-rc = setup_saa(p);
+input = peasycap->input;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
+ * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
+ * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
+ * A SWITCH BETWEEN PAL AND NTSC.
+ *
+ * FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
+ * COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
+*/
+/*---------------------------------------------------------------------------*/
+other = false;
+if (true == peasycap->ntsc)
+ JOM(8, "true=peasycap->ntsc\n");
+else
+ JOM(8, "false=peasycap->ntsc\n");
+rate = ready_saa(peasycap->pusb_device);
+if (0 > rate) {
+ JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
+ if (true == peasycap->ntsc) {
+ JOM(8, "... trying PAL ...\n"); ntsc = false;
+ } else {
+ JOM(8, "... trying NTSC ...\n"); ntsc = true;
+}
+rc = setup_stk(peasycap->pusb_device, ntsc);
if (0 == rc)
- JOT(8, "setup_saa() OK\n");
+ JOM(4, "setup_stk() OK\n");
else {
- SAY("ERROR: setup_saa() returned %i\n", rc);
+ SAM("ERROR: setup_stk() returned %i\n", rc);
return -EFAULT;
}
-rc = check_saa(p);
+rc = setup_saa(peasycap->pusb_device, ntsc);
if (0 == rc)
- JOT(8, "check_saa() OK\n");
-else if (-8 < rc)
- SAY("check_saa() returned %i\n", rc);
+ JOM(4, "setup_saa() OK\n");
else {
- SAY("ERROR: check_saa() returned %i\n", rc);
+ SAM("ERROR: setup_saa() returned %i\n", rc);
return -EFAULT;
}
-peasycap->standard_offset = -1;
+rate = ready_saa(peasycap->pusb_device);
+if (0 > rate) {
+ JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
+ JOM(8, "... saa register 0x1F has 0x%02X\n", \
+ read_saa(peasycap->pusb_device, 0x1F));
+ ntsc = peasycap->ntsc;
+ } else {
+ JOM(8, "... success at second try: %i=rate\n", rate);
+ ntsc = (0 < (rate/2)) ? true : false ;
+ other = true;
+ }
+} else {
+ JOM(8, "... success at first try: %i=rate\n", rate);
+ ntsc = (0 < rate/2) ? true : false ;
+}
+if (true == ntsc)
+ JOM(8, "true=ntsc\n");
+else
+ JOM(8, "false=ntsc\n");
/*---------------------------------------------------------------------------*/
-#if defined(PREFER_NTSC)
-rc = adjust_standard(peasycap, V4L2_STD_NTSC_M);
+rc = setup_stk(peasycap->pusb_device, ntsc);
if (0 == rc)
- JOT(8, "adjust_standard(.,NTSC_M) OK\n");
+ JOM(4, "setup_stk() OK\n");
else {
- SAY("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc);
+ SAM("ERROR: setup_stk() returned %i\n", rc);
return -EFAULT;
}
-rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
- false);
-if (0 <= rc)
- JOT(8, "adjust_format(.,640,480,UYVY) OK\n");
+rc = setup_saa(peasycap->pusb_device, ntsc);
+if (0 == rc)
+ JOM(4, "setup_saa() OK\n");
else {
- SAY("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc);
+ SAM("ERROR: setup_saa() returned %i\n", rc);
return -EFAULT;
}
-#else
+for (i = 0; i < 180; i++)
+ peasycap->merit[i] = 0;
+peasycap->video_eof = 0;
+peasycap->audio_eof = 0;
+do_gettimeofday(&peasycap->timeval7);
+/*---------------------------------------------------------------------------*/
+/*
+ * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
+ *
+ * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
+*/
+/*---------------------------------------------------------------------------*/
+peasycap->input = -8192;
+peasycap->standard_offset = -8192;
+if (true == other) {
+ peasycap_standard = &easycap_standard[0];
+ while (0xFFFF != peasycap_standard->mask) {
+ if (true == ntsc) {
+ if (NTSC_M == \
+ peasycap_standard->v4l2_standard.index) {
+ peasycap->inputset[input].standard_offset = \
+ peasycap_standard - \
+ &easycap_standard[0];
+ break;
+ }
+ } else {
+ if (PAL_BGHIN == \
+ peasycap_standard->v4l2_standard.index) {
+ peasycap->inputset[input].standard_offset = \
+ peasycap_standard -
+ &easycap_standard[0];
+ break;
+ }
+ }
+ peasycap_standard++;
+ }
+ if (0xFFFF == peasycap_standard->mask) {
+ SAM("ERROR: standard not found\n");
+ return -EINVAL;
+ }
+JOM(8, "%i=peasycap->inputset[%i].standard_offset\n", \
+ peasycap->inputset[input].standard_offset, input);
+}
+peasycap->format_offset = -8192;
+peasycap->brightness = -8192;
+peasycap->contrast = -8192;
+peasycap->saturation = -8192;
+peasycap->hue = -8192;
+
+rc = newinput(peasycap, input);
-rc = adjust_standard(peasycap, \
- (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
- V4L2_STD_PAL_I | V4L2_STD_PAL_N));
if (0 == rc)
- JOT(8, "adjust_standard(.,PAL_BGHIN) OK\n");
+ JOM(4, "restored input, standard and format\n");
else {
- SAY("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc);
+ SAM("ERROR: newinput(.,%i) returned %i\n", rc, input);
return -EFAULT;
}
-rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
- false);
-if (0 <= rc)
- JOT(8, "adjust_format(.,640,480,uyvy,false) OK\n");
-else {
- SAY("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc);
+if (true == peasycap->ntsc)
+ JOM(8, "true=peasycap->ntsc\n");
+else
+ JOM(8, "false=peasycap->ntsc\n");
+
+if (0 > peasycap->input) {
+ SAM("MISTAKE: %i=peasycap->input\n", peasycap->input);
+ return -ENOENT;
+}
+if (0 > peasycap->standard_offset) {
+ SAM("MISTAKE: %i=peasycap->standard_offset\n", \
+ peasycap->standard_offset);
+ return -ENOENT;
+}
+if (0 > peasycap->format_offset) {
+ SAM("MISTAKE: %i=peasycap->format_offset\n", \
+ peasycap->format_offset);
+ return -ENOENT;
+}
+if (0 > peasycap->brightness) {
+ SAM("MISTAKE: %i=peasycap->brightness\n", peasycap->brightness);
+ return -ENOENT;
+}
+if (0 > peasycap->contrast) {
+ SAM("MISTAKE: %i=peasycap->contrast\n", peasycap->contrast);
+ return -ENOENT;
+}
+if (0 > peasycap->saturation) {
+ SAM("MISTAKE: %i=peasycap->saturation\n", peasycap->saturation);
+ return -ENOENT;
+}
+if (0 > peasycap->hue) {
+ SAM("MISTAKE: %i=peasycap->hue\n", peasycap->hue);
+ return -ENOENT;
+}
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
+ * OTHERWISE:
+ * KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
+ * _read AND _fill POINTERS.
+ * SELECT THE NEW INPUT.
+ * ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
+ * ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
+ * RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
+ *
+ * NOTE:
+ * THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
+ * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
+*/
+/*---------------------------------------------------------------------------*/
+int
+newinput(struct easycap *peasycap, int input)
+{
+int rc, k, m, mood, off;
+int inputnow, video_idlenow, audio_idlenow;
+bool resubmit;
+
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+JOM(8, "%i=input sought\n", input);
-#endif /* !PREFER_NTSC*/
+if (0 > input && INPUT_MANY <= input)
+ return -ENOENT;
+inputnow = peasycap->input;
+if (input == inputnow)
+ return 0;
/*---------------------------------------------------------------------------*/
-rc = adjust_brightness(peasycap, -8192);
+/*
+ * IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
+ * STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
+ * IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
+ * ROUTINE.
+*/
+/*---------------------------------------------------------------------------*/
+video_idlenow = peasycap->video_idle;
+audio_idlenow = peasycap->audio_idle;
+
+peasycap->video_idle = 1;
+peasycap->audio_idle = 1;
+if (peasycap->video_isoc_streaming) {
+ resubmit = true;
+ kill_video_urbs(peasycap);
+} else
+ resubmit = false;
+/*---------------------------------------------------------------------------*/
+if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ return -ENODEV;
+}
+rc = usb_set_interface(peasycap->pusb_device,
+ peasycap->video_interface, \
+ peasycap->video_altsetting_off);
if (0 != rc) {
- SAY("ERROR: adjust_brightness(default) returned %i\n", rc);
+ SAM("ERROR: usb_set_interface() returned %i\n", rc);
return -EFAULT;
}
-rc = adjust_contrast(peasycap, -8192);
+rc = stop_100(peasycap->pusb_device);
if (0 != rc) {
- SAY("ERROR: adjust_contrast(default) returned %i\n", rc);
+ SAM("ERROR: stop_100() returned %i\n", rc);
return -EFAULT;
}
-rc = adjust_saturation(peasycap, -8192);
-if (0 != rc) {
- SAY("ERROR: adjust_saturation(default) returned %i\n", rc);
- return -EFAULT;
+for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
+ memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
}
-rc = adjust_hue(peasycap, -8192);
-if (0 != rc) {
- SAY("ERROR: adjust_hue(default) returned %i\n", rc);
- return -EFAULT;
+for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
+ memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
+}
+peasycap->field_page = 0;
+peasycap->field_read = 0;
+peasycap->field_fill = 0;
+
+peasycap->frame_read = 0;
+peasycap->frame_fill = 0;
+for (k = 0; k < peasycap->input; k++) {
+ (peasycap->frame_fill)++;
+ if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+ peasycap->frame_fill = 0;
}
+peasycap->input = input;
+select_input(peasycap->pusb_device, peasycap->input, 9);
/*---------------------------------------------------------------------------*/
-rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \
- peasycap->video_altsetting_on);
-if (0 == rc)
- JOT(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \
- peasycap->video_altsetting_on);
-else {
- SAY("ERROR: usb_set_interface() returned %i\n", rc);
+if (input == peasycap->inputset[input].input) {
+ off = peasycap->inputset[input].standard_offset;
+ if (off != peasycap->standard_offset) {
+ rc = adjust_standard(peasycap, \
+ easycap_standard[off].v4l2_standard.id);
+ if (0 != rc) {
+ SAM("ERROR: adjust_standard() returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->standard_offset\n", \
+ peasycap->standard_offset);
+ } else {
+ JOM(8, "%i=peasycap->standard_offset unchanged\n", \
+ peasycap->standard_offset);
+ }
+ off = peasycap->inputset[input].format_offset;
+ if (off != peasycap->format_offset) {
+ rc = adjust_format(peasycap, \
+ easycap_format[off].v4l2_format.fmt.pix.width, \
+ easycap_format[off].v4l2_format.fmt.pix.height, \
+ easycap_format[off].v4l2_format.fmt.pix.pixelformat, \
+ easycap_format[off].v4l2_format.fmt.pix.field, false);
+ if (0 > rc) {
+ SAM("ERROR: adjust_format() returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->format_offset\n", peasycap->format_offset);
+ } else {
+ JOM(8, "%i=peasycap->format_offset unchanged\n", \
+ peasycap->format_offset);
+ }
+ mood = peasycap->inputset[input].brightness;
+ if (mood != peasycap->brightness) {
+ rc = adjust_brightness(peasycap, mood);
+ if (0 != rc) {
+ SAM("ERROR: adjust_brightness returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->brightness\n", peasycap->brightness);
+ }
+ mood = peasycap->inputset[input].contrast;
+ if (mood != peasycap->contrast) {
+ rc = adjust_contrast(peasycap, mood);
+ if (0 != rc) {
+ SAM("ERROR: adjust_contrast returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
+ }
+ mood = peasycap->inputset[input].saturation;
+ if (mood != peasycap->saturation) {
+ rc = adjust_saturation(peasycap, mood);
+ if (0 != rc) {
+ SAM("ERROR: adjust_saturation returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->saturation\n", peasycap->saturation);
+ }
+ mood = peasycap->inputset[input].hue;
+ if (mood != peasycap->hue) {
+ rc = adjust_hue(peasycap, mood);
+ if (0 != rc) {
+ SAM("ERROR: adjust_hue returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(8, "%i=peasycap->hue\n", peasycap->hue);
+ }
+} else {
+ SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
+ return -ENOENT;
+}
+/*---------------------------------------------------------------------------*/
+if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ return -ENODEV;
+}
+rc = usb_set_interface(peasycap->pusb_device,
+ peasycap->video_interface, \
+ peasycap->video_altsetting_on);
+if (0 != rc) {
+ SAM("ERROR: usb_set_interface() returned %i\n", rc);
return -EFAULT;
}
-rc = start_100(p);
-if (0 == rc)
- JOT(8, "start_100() OK\n");
-else {
- SAY("ERROR: start_100() returned %i\n", rc);
+rc = start_100(peasycap->pusb_device);
+if (0 != rc) {
+ SAM("ERROR: start_100() returned %i\n", rc);
return -EFAULT;
}
+if (true == resubmit)
+ submit_video_urbs(peasycap);
+
peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
-peasycap->video_idle = 0;
+peasycap->video_idle = video_idlenow;
+peasycap->audio_idle = audio_idlenow;
peasycap->video_junk = 0;
-for (i = 0; i < 180; i++)
- peasycap->merit[i] = 0;
-peasycap->video_eof = 0;
-peasycap->audio_eof = 0;
-do_gettimeofday(&peasycap->timeval7);
-
-peasycap->fudge = 0;
-
-JOT(4, "finished initialization\n");
return 0;
}
/*****************************************************************************/
@@ -326,33 +631,25 @@ submit_video_urbs(struct easycap *peasycap)
struct data_urb *pdata_urb;
struct urb *purb;
struct list_head *plist_head;
-int j, isbad, m, rc;
+int j, isbad, nospc, m, rc;
int isbuf;
-if ((struct list_head *)NULL == peasycap->purb_video_head) {
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
+
+if (NULL == peasycap->purb_video_head) {
SAY("ERROR: peasycap->urb_video_head uninitialized\n");
return -EFAULT;
}
-if ((struct usb_device *)NULL == peasycap->pusb_device) {
+if (NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
+ return -ENODEV;
}
if (!peasycap->video_isoc_streaming) {
-
-
-
-
-
-
-
-
- JOT(4, "submission of all video urbs\n");
- if (0 != ready_saa(peasycap->pusb_device)) {
- SAY("ERROR: not ready to capture after waiting " \
- "one second\n");
- SAY("..... continuing anyway\n");
- }
- isbad = 0; m = 0;
+ JOM(4, "submission of all video urbs\n");
+ isbad = 0; nospc = 0; m = 0;
list_for_each(plist_head, (peasycap->purb_video_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
if (NULL != pdata_urb) {
@@ -389,44 +686,57 @@ if (!peasycap->video_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_KERNEL);
if (0 != rc) {
isbad++;
- SAY("ERROR: usb_submit_urb() failed " \
+ SAM("ERROR: usb_submit_urb() failed " \
"for urb with rc:\n");
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n");
+ SAM("ERROR: -ENOMEM=" \
+ "usb_submit_urb()\n");
break;
}
case -ENODEV: {
- SAY("ENODEV\n");
+ SAM("ERROR: -ENODEV=" \
+ "usb_submit_urb()\n");
break;
}
case -ENXIO: {
- SAY("ENXIO\n");
+ SAM("ERROR: -ENXIO=" \
+ "usb_submit_urb()\n");
break;
}
case -EINVAL: {
- SAY("EINVAL\n");
+ SAM("ERROR: -EINVAL=" \
+ "usb_submit_urb()\n");
break;
}
case -EAGAIN: {
- SAY("EAGAIN\n");
+ SAM("ERROR: -EAGAIN=" \
+ "usb_submit_urb()\n");
break;
}
case -EFBIG: {
- SAY("EFBIG\n");
+ SAM("ERROR: -EFBIG=" \
+ "usb_submit_urb()\n");
break;
}
case -EPIPE: {
- SAY("EPIPE\n");
+ SAM("ERROR: -EPIPE=" \
+ "usb_submit_urb()\n");
break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n");
+ SAM("ERROR: -EMSGSIZE=" \
+ "usb_submit_urb()\n");
+ break;
+ }
+ case -ENOSPC: {
+ nospc++;
break;
}
default: {
- SAY("unknown error code %i\n",\
- rc);
+ SAM("ERROR: %i=" \
+ "usb_submit_urb()\n",\
+ rc);
break;
}
}
@@ -434,14 +744,20 @@ if (!peasycap->video_isoc_streaming) {
m++;
}
} else {
- isbad++;
+ isbad++;
}
} else {
isbad++;
}
}
+ if (nospc) {
+ SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
+ SAM("..... possibly inadequate USB bandwidth\n");
+ peasycap->video_eof = 1;
+ }
+
if (isbad) {
- JOT(4, "attempting cleanup instead of submitting\n");
+ JOM(4, "attempting cleanup instead of submitting\n");
list_for_each(plist_head, (peasycap->purb_video_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, \
list_head);
@@ -454,16 +770,10 @@ if (!peasycap->video_isoc_streaming) {
peasycap->video_isoc_streaming = 0;
} else {
peasycap->video_isoc_streaming = 1;
- JOT(4, "submitted %i video urbs\n", m);
+ JOM(4, "submitted %i video urbs\n", m);
}
-
-
-
-
-
-
} else {
- JOT(4, "already streaming video urbs\n");
+ JOM(4, "already streaming video urbs\n");
}
return 0;
}
@@ -475,35 +785,32 @@ int m;
struct list_head *plist_head;
struct data_urb *pdata_urb;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (peasycap->video_isoc_streaming) {
-
-
-
if ((struct list_head *)NULL != peasycap->purb_video_head) {
peasycap->video_isoc_streaming = 0;
- JOT(4, "killing video urbs\n");
+ JOM(4, "killing video urbs\n");
m = 0;
list_for_each(plist_head, (peasycap->purb_video_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, \
list_head);
- if ((struct data_urb *)NULL != pdata_urb) {
- if ((struct urb *)NULL != pdata_urb->purb) {
+ if (NULL != pdata_urb) {
+ if (NULL != pdata_urb->purb) {
usb_kill_urb(pdata_urb->purb);
m++;
}
}
}
- JOT(4, "%i video urbs killed\n", m);
+ JOM(4, "%i video urbs killed\n", m);
} else {
- SAY("ERROR: peasycap->purb_video_head is NULL\n");
+ SAM("ERROR: peasycap->purb_video_head is NULL\n");
return -EFAULT;
}
} else {
- JOT(8, "%i=video_isoc_streaming, no video urbs killed\n", \
+ JOM(8, "%i=video_isoc_streaming, no video urbs killed\n", \
peasycap->video_isoc_streaming);
}
return 0;
@@ -533,11 +840,15 @@ if (NULL == peasycap) {
SAY("ending unsuccessfully\n");
return -EFAULT;
}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
if (0 != kill_video_urbs(peasycap)) {
- SAY("ERROR: kill_video_urbs() failed\n");
+ SAM("ERROR: kill_video_urbs() failed\n");
return -EFAULT;
}
-JOT(4, "ending successfully\n");
+JOM(4, "ending successfully\n");
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#else
#
@@ -550,63 +861,45 @@ return 0;
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
int
-videodev_release(struct video_device *pvd)
+videodev_release(struct video_device *pvideo_device)
{
struct easycap *peasycap;
-int i, j, k;
JOT(4, "\n");
-k = 0;
-for (i = 0; i < video_device_many; i++) {
- pvideo_device = pvideo_array[i];
- if ((struct video_device *)NULL != pvideo_device) {
- if (pvd->minor == pvideo_device->minor) {
- peasycap = (struct easycap *)\
- video_get_drvdata(pvideo_device);
- if ((struct easycap *)NULL == peasycap) {
- SAY("ERROR: peasycap is NULL\n");
- SAY("ending unsuccessfully\n");
- return -EFAULT;
- }
- if (0 != kill_video_urbs(peasycap)) {
- SAY("ERROR: kill_video_urbs() failed\n");
- return -EFAULT;
- }
- JOT(4, "freeing video_device structure: " \
- "/dev/video%i\n", i);
- kfree((void *)pvideo_device);
- for (j = i; j < (VIDEO_DEVICE_MANY - 1); j++)
- pvideo_array[j] = pvideo_array[j + 1];
- video_device_many--; k++;
- break;
- }
- }
-}
-if (!k) {
- SAY("ERROR: lost video_device structure for %i=minor\n", pvd->minor);
- SAY("cannot free: may cause memory leak\n");
+peasycap = video_get_drvdata(pvideo_device);
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
SAY("ending unsuccessfully\n");
return -EFAULT;
}
-
-JOT(4, "ending successfully\n");
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
+if (0 != kill_video_urbs(peasycap)) {
+ SAM("ERROR: kill_video_urbs() failed\n");
+ return -EFAULT;
+}
+JOM(4, "ending successfully\n");
return 0;
}
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/****************************************************************************/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
- * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().
- * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.
- * peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.
+ * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
+ * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
+ *
+ * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
+ * peasycap->pusb_device IS NO LONGER VALID.
*/
/*---------------------------------------------------------------------------*/
void
easycap_delete(struct kref *pkref)
{
-int k, m, lost;
+int k, m, gone, kd;
int allocation_video_urb, allocation_video_page, allocation_video_struct;
int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
int registered_video, registered_audio;
@@ -617,22 +910,27 @@ struct list_head *plist_head, *plist_next;
JOT(4, "\n");
peasycap = container_of(pkref, struct easycap, kref);
-if ((struct easycap *)NULL == peasycap) {
- SAY("ERROR: peasycap is NULL: cannot perform deletions\n");
+if (NULL == peasycap) {
+ SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
+ return;
+}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
return;
}
+kd = isdongle(peasycap);
/*---------------------------------------------------------------------------*/
/*
* FREE VIDEO.
*/
/*---------------------------------------------------------------------------*/
if ((struct list_head *)NULL != peasycap->purb_video_head) {
- JOT(4, "freeing video urbs\n");
+ JOM(4, "freeing video urbs\n");
m = 0;
list_for_each(plist_head, (peasycap->purb_video_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
if (NULL == pdata_urb)
- JOT(4, "ERROR: pdata_urb is NULL\n");
+ JOM(4, "ERROR: pdata_urb is NULL\n");
else {
if ((struct urb *)NULL != pdata_urb->purb) {
usb_free_urb(pdata_urb->purb);
@@ -643,9 +941,9 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) {
}
}
- JOT(4, "%i video urbs freed\n", m);
+ JOM(4, "%i video urbs freed\n", m);
/*---------------------------------------------------------------------------*/
- JOT(4, "freeing video data_urb structures.\n");
+ JOM(4, "freeing video data_urb structures.\n");
m = 0;
list_for_each_safe(plist_head, plist_next, peasycap->purb_video_head) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
@@ -656,14 +954,12 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) {
m++;
}
}
- JOT(4, "%i video data_urb structures freed\n", m);
- JOT(4, "setting peasycap->purb_video_head=NULL\n");
+ JOM(4, "%i video data_urb structures freed\n", m);
+ JOM(4, "setting peasycap->purb_video_head=NULL\n");
peasycap->purb_video_head = (struct list_head *)NULL;
- } else {
-JOT(4, "peasycap->purb_video_head is NULL\n");
}
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing video isoc buffers.\n");
+JOM(4, "freeing video isoc buffers.\n");
m = 0;
for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
if ((void *)NULL != peasycap->video_isoc_buffer[k].pgo) {
@@ -676,10 +972,10 @@ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
m++;
}
}
-JOT(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));
+JOM(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing video field buffers.\n");
-lost = 0;
+JOM(4, "freeing video field buffers.\n");
+gone = 0;
for (k = 0; k < FIELD_BUFFER_MANY; k++) {
for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
@@ -687,14 +983,14 @@ for (k = 0; k < FIELD_BUFFER_MANY; k++) {
(peasycap->field_buffer[k][m].pgo));
peasycap->field_buffer[k][m].pgo = (void *)NULL;
peasycap->allocation_video_page -= 1;
- lost++;
+ gone++;
}
}
}
-JOT(4, "video field buffers freed: %i pages\n", lost);
+JOM(4, "video field buffers freed: %i pages\n", gone);
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing video frame buffers.\n");
-lost = 0;
+JOM(4, "freeing video frame buffers.\n");
+gone = 0;
for (k = 0; k < FRAME_BUFFER_MANY; k++) {
for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) {
@@ -702,23 +998,23 @@ for (k = 0; k < FRAME_BUFFER_MANY; k++) {
(peasycap->frame_buffer[k][m].pgo));
peasycap->frame_buffer[k][m].pgo = (void *)NULL;
peasycap->allocation_video_page -= 1;
- lost++;
+ gone++;
}
}
}
-JOT(4, "video frame buffers freed: %i pages\n", lost);
+JOM(4, "video frame buffers freed: %i pages\n", gone);
/*---------------------------------------------------------------------------*/
/*
* FREE AUDIO.
*/
/*---------------------------------------------------------------------------*/
if ((struct list_head *)NULL != peasycap->purb_audio_head) {
- JOT(4, "freeing audio urbs\n");
+ JOM(4, "freeing audio urbs\n");
m = 0;
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
if (NULL == pdata_urb)
- JOT(4, "ERROR: pdata_urb is NULL\n");
+ JOM(4, "ERROR: pdata_urb is NULL\n");
else {
if ((struct urb *)NULL != pdata_urb->purb) {
usb_free_urb(pdata_urb->purb);
@@ -728,9 +1024,9 @@ if ((struct list_head *)NULL != peasycap->purb_audio_head) {
}
}
}
- JOT(4, "%i audio urbs freed\n", m);
+ JOM(4, "%i audio urbs freed\n", m);
/*---------------------------------------------------------------------------*/
- JOT(4, "freeing audio data_urb structures.\n");
+ JOM(4, "freeing audio data_urb structures.\n");
m = 0;
list_for_each_safe(plist_head, plist_next, peasycap->purb_audio_head) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
@@ -741,14 +1037,12 @@ if ((struct list_head *)NULL != peasycap->purb_audio_head) {
m++;
}
}
-JOT(4, "%i audio data_urb structures freed\n", m);
-JOT(4, "setting peasycap->purb_audio_head=NULL\n");
+JOM(4, "%i audio data_urb structures freed\n", m);
+JOM(4, "setting peasycap->purb_audio_head=NULL\n");
peasycap->purb_audio_head = (struct list_head *)NULL;
-} else {
-JOT(4, "peasycap->purb_audio_head is NULL\n");
}
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing audio isoc buffers.\n");
+JOM(4, "freeing audio isoc buffers.\n");
m = 0;
for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
if ((void *)NULL != peasycap->audio_isoc_buffer[k].pgo) {
@@ -761,22 +1055,22 @@ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
m++;
}
}
-JOT(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
+JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
m * (0x01 << AUDIO_ISOC_ORDER));
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing audio buffers.\n");
-lost = 0;
+JOM(4, "freeing audio buffers.\n");
+gone = 0;
for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
free_page((unsigned long)(peasycap->audio_buffer[k].pgo));
peasycap->audio_buffer[k].pgo = (void *)NULL;
peasycap->allocation_audio_page -= 1;
- lost++;
+ gone++;
}
}
-JOT(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost);
+JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", gone);
/*---------------------------------------------------------------------------*/
-JOT(4, "freeing easycap structure.\n");
+JOM(4, "freeing easycap structure.\n");
allocation_video_urb = peasycap->allocation_video_urb;
allocation_video_page = peasycap->allocation_video_page;
allocation_video_struct = peasycap->allocation_video_struct;
@@ -785,15 +1079,16 @@ allocation_audio_urb = peasycap->allocation_audio_urb;
allocation_audio_page = peasycap->allocation_audio_page;
allocation_audio_struct = peasycap->allocation_audio_struct;
registered_audio = peasycap->registered_audio;
-m = 0;
-if ((struct easycap *)NULL != peasycap) {
- kfree(peasycap); peasycap = (struct easycap *)NULL;
+
+kfree(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ easycap_dongle[kd].peasycap = (struct easycap *)NULL;
+ JOT(4, " null-->easycap_dongle[%i].peasycap\n", kd);
allocation_video_struct -= sizeof(struct easycap);
- m++;
+} else {
+ SAY("ERROR: cannot purge easycap_dongle[].peasycap");
}
-JOT(4, "%i easycap structure freed\n", m);
/*---------------------------------------------------------------------------*/
-
SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
SAY("%8i= video pages after all deletions\n", allocation_video_page);
SAY("%8i= video structs after all deletions\n", allocation_video_struct);
@@ -810,27 +1105,85 @@ return;
unsigned int easycap_poll(struct file *file, poll_table *wait)
{
struct easycap *peasycap;
+int rc, kd;
JOT(8, "\n");
if (NULL == ((poll_table *)wait))
JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
-if (NULL == ((struct file *)file)) {
+if ((struct file *)NULL == file) {
SAY("ERROR: file pointer is NULL\n");
- return -EFAULT;
+ return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
+if (NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ /*-------------------------------------------------------------------*/
+ /*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
+ * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+ */
+ /*-------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", \
+ (unsigned long int) peasycap);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+} else
+ /*-------------------------------------------------------------------*/
+ /*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
+ * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
+ * HAVE FAILED. BAIL OUT.
+ */
+ /*-------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+/*---------------------------------------------------------------------------*/
+rc = easycap_dqbuf(peasycap, 0);
peasycap->polled = 1;
-
-if (0 == easycap_dqbuf(peasycap, 0))
+mutex_unlock(&easycap_dongle[kd].mutex_video);
+if (0 == rc)
return POLLIN | POLLRDNORM;
else
return POLLERR;
-
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
@@ -841,7 +1194,7 @@ else
int
easycap_dqbuf(struct easycap *peasycap, int mode)
{
-int miss, rc;
+int input, ifield, miss, rc;
JOT(8, "\n");
@@ -849,129 +1202,188 @@ if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+if (NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+ifield = 0;
+JOM(8, "%i=ifield\n", ifield);
+/*---------------------------------------------------------------------------*/
+/*
+ * CHECK FOR LOST INPUT SIGNAL.
+ *
+ * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
+ * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
+ * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
+ * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS:
+ *
+ * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
+ * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
+ * INPUT 0 UNPLUGGED, INPUT 4 PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
+ * INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
+*/
+/*---------------------------------------------------------------------------*/
+input = peasycap->input;
+if (0 <= input && INPUT_MANY > input) {
+ rc = read_saa(peasycap->pusb_device, 0x1F);
+ if (0 <= rc) {
+ if (rc & 0x40)
+ peasycap->lost[input] += 1;
+ else
+ peasycap->lost[input] -= 2;
+
+ if (0 > peasycap->lost[input])
+ peasycap->lost[input] = 0;
+ else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
+ peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
+ }
+}
/*---------------------------------------------------------------------------*/
/*
- * WAIT FOR FIELD 0
+ * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM)
*/
/*---------------------------------------------------------------------------*/
miss = 0;
-if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
- return -ERESTARTSYS;
while ((peasycap->field_read == peasycap->field_fill) || \
(0 != (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) || \
- (0 != (0x00FF & peasycap->field_buffer\
+ (ifield != (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))) {
- mutex_unlock(&(peasycap->mutex_mmap_video[0]));
-
if (mode)
return -EAGAIN;
- JOT(8, "first wait on wq_video, " \
+ JOM(8, "first wait on wq_video, " \
"%i=field_read %i=field_fill\n", \
peasycap->field_read, peasycap->field_fill);
- msleep(1);
if (0 != (wait_event_interruptible(peasycap->wq_video, \
(peasycap->video_idle || peasycap->video_eof || \
((peasycap->field_read != peasycap->field_fill) && \
(0 == (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) && \
- (0 == (0x00FF & peasycap->field_buffer\
- [peasycap->field_read][0].kount))))))){
- SAY("aborted by signal\n");
+ (ifield == (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].kount))))))) {
+ SAM("aborted by signal\n");
return -EIO;
}
if (peasycap->video_idle) {
- JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
- return -EIO;
+ JOM(8, "%i=peasycap->video_idle ... returning -EAGAIN\n", \
+ peasycap->video_idle);
+ return -EAGAIN;
}
if (peasycap->video_eof) {
- JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
- debrief(peasycap);
+ JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+ #if defined(PERSEVERE)
+ if (1 == peasycap->status) {
+ JOM(8, "persevering ...\n");
+ peasycap->video_eof = 0;
+ peasycap->audio_eof = 0;
+ if (0 != reset(peasycap)) {
+ JOM(8, " ... failed ... returning -EIO\n");
+ peasycap->video_eof = 1;
+ peasycap->audio_eof = 1;
+ kill_video_urbs(peasycap);
+ return -EIO;
+ }
+ peasycap->status = 0;
+ JOM(8, " ... OK ... returning -EAGAIN\n");
+ return -EAGAIN;
+ }
+ #endif /*PERSEVERE*/
+ peasycap->video_eof = 1;
+ peasycap->audio_eof = 1;
kill_video_urbs(peasycap);
+ JOM(8, "returning -EIO\n");
return -EIO;
}
miss++;
-if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
- return -ERESTARTSYS;
}
-mutex_unlock(&(peasycap->mutex_mmap_video[0]));
-JOT(8, "first awakening on wq_video after %i waits\n", miss);
+JOM(8, "first awakening on wq_video after %i waits\n", miss);
rc = field2frame(peasycap);
if (0 != rc)
- SAY("ERROR: field2frame() returned %i\n", rc);
-
-if (true == peasycap->offerfields) {
- peasycap->frame_read = peasycap->frame_fill;
- (peasycap->frame_fill)++;
- if (peasycap->frame_buffer_many <= peasycap->frame_fill)
- peasycap->frame_fill = 0;
-
- if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
- peasycap->frame_buffer[peasycap->frame_read][0].kount = \
- V4L2_FIELD_BOTTOM;
- } else {
- peasycap->frame_buffer[peasycap->frame_read][0].kount = \
- V4L2_FIELD_TOP;
- }
-JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
-JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
-}
+ SAM("ERROR: field2frame() returned %i\n", rc);
/*---------------------------------------------------------------------------*/
/*
- * WAIT FOR FIELD 1
+ * WAIT FOR THE OTHER FIELD
*/
/*---------------------------------------------------------------------------*/
+if (ifield)
+ ifield = 0;
+else
+ ifield = 1;
miss = 0;
-if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
- return -ERESTARTSYS;
while ((peasycap->field_read == peasycap->field_fill) || \
(0 != (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) || \
- (0 == (0x00FF & peasycap->field_buffer\
+ (ifield != (0x00FF & peasycap->field_buffer\
[peasycap->field_read][0].kount))) {
- mutex_unlock(&(peasycap->mutex_mmap_video[0]));
-
if (mode)
return -EAGAIN;
- JOT(8, "second wait on wq_video, " \
+ JOM(8, "second wait on wq_video, " \
"%i=field_read %i=field_fill\n", \
peasycap->field_read, peasycap->field_fill);
- msleep(1);
if (0 != (wait_event_interruptible(peasycap->wq_video, \
(peasycap->video_idle || peasycap->video_eof || \
((peasycap->field_read != peasycap->field_fill) && \
(0 == (0xFF00 & peasycap->field_buffer\
[peasycap->field_read][0].kount)) && \
- (0 != (0x00FF & peasycap->field_buffer\
- [peasycap->field_read][0].kount))))))){
- SAY("aborted by signal\n");
+ (ifield == (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].\
+ kount))))))) {
+ SAM("aborted by signal\n");
return -EIO;
}
if (peasycap->video_idle) {
- JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
- return -EIO;
+ JOM(8, "%i=peasycap->video_idle ... returning -EAGAIN\n", \
+ peasycap->video_idle);
+ return -EAGAIN;
}
if (peasycap->video_eof) {
- JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
- debrief(peasycap);
+ JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+ #if defined(PERSEVERE)
+ if (1 == peasycap->status) {
+ JOM(8, "persevering ...\n");
+ peasycap->video_eof = 0;
+ peasycap->audio_eof = 0;
+ if (0 != reset(peasycap)) {
+ JOM(8, " ... failed ... returning -EIO\n");
+ peasycap->video_eof = 1;
+ peasycap->audio_eof = 1;
+ kill_video_urbs(peasycap);
+ return -EIO;
+ }
+ peasycap->status = 0;
+ JOM(8, " ... OK ... returning -EAGAIN\n");
+ return -EAGAIN;
+ }
+ #endif /*PERSEVERE*/
+ peasycap->video_eof = 1;
+ peasycap->audio_eof = 1;
kill_video_urbs(peasycap);
+ JOM(8, "returning -EIO\n");
return -EIO;
}
miss++;
-if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
- return -ERESTARTSYS;
}
-mutex_unlock(&(peasycap->mutex_mmap_video[0]));
-JOT(8, "second awakening on wq_video after %i waits\n", miss);
+JOM(8, "second awakening on wq_video after %i waits\n", miss);
rc = field2frame(peasycap);
if (0 != rc)
- SAY("ERROR: field2frame() returned %i\n", rc);
-
+ SAM("ERROR: field2frame() returned %i\n", rc);
+/*---------------------------------------------------------------------------*/
+/*
+ * WASTE THIS FRAME
+*/
+/*---------------------------------------------------------------------------*/
+if (0 != peasycap->skip) {
+ peasycap->skipped++;
+ if (peasycap->skip != peasycap->skipped)
+ return peasycap->skip - peasycap->skipped;
+ peasycap->skipped = 0;
+}
+/*---------------------------------------------------------------------------*/
peasycap->frame_read = peasycap->frame_fill;
peasycap->queued[peasycap->frame_read] = 0;
peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;
@@ -988,8 +1400,8 @@ if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
V4L2_FIELD_BOTTOM;
}
-JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
-JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
+JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
+JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
return 0;
}
@@ -1003,14 +1415,12 @@ return 0;
* odd==false IS TRANSFERRED TO THE FRAME BUFFER.
*
* THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
- * CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED
- * TO DATE HAS DONE THIS. BUGS ARE LIKELY.
+ * CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
*/
/*---------------------------------------------------------------------------*/
int
field2frame(struct easycap *peasycap)
{
-static struct timeval timeval0;
struct timeval timeval;
long long int above, below;
__u32 remainder;
@@ -1019,16 +1429,26 @@ struct signed_div_result sdr;
void *pex, *pad;
int kex, kad, mex, mad, rex, rad, rad2;
int c2, c3, w2, w3, cz, wz;
-int rc, bytesperpixel, multiplier, much, more, over, rump, caches;
+int rc, bytesperpixel, multiplier, much, more, over, rump, caches, input;
__u8 mask, margin;
-bool odd, isuy, decimatepixel, offerfields;
+bool odd, isuy, decimatepixel, offerfields, badinput;
+
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
-JOT(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \
+badinput = false;
+input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
+
+JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " \
+ "frame buffer %i\n", \
peasycap->field_buffer[peasycap->field_read][0].kount,\
+ peasycap->field_buffer[peasycap->field_read][0].input,\
peasycap->field_read, peasycap->frame_fill);
-JOT(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
+JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
if (true == peasycap->offerfields)
- JOT(8, "===== offerfields\n");
+ JOM(8, "===== offerfields\n");
/*---------------------------------------------------------------------------*/
/*
@@ -1036,15 +1456,17 @@ if (true == peasycap->offerfields)
*/
/*---------------------------------------------------------------------------*/
if (peasycap->field_read == peasycap->field_fill) {
- SAY("ERROR: on entry, still filling field buffer %i\n", \
+ SAM("ERROR: on entry, still filling field buffer %i\n", \
peasycap->field_read);
return 0;
}
#if defined(EASYCAP_TESTCARD)
easycap_testcard(peasycap, peasycap->field_read);
#else
-if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount))
- easycap_testcard(peasycap, peasycap->field_read);
+if (0 <= input && INPUT_MANY > input) {
+ if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
+ easycap_testcard(peasycap, peasycap->field_read);
+}
#endif /*EASYCAP_TESTCARD*/
/*---------------------------------------------------------------------------*/
@@ -1055,7 +1477,7 @@ decimatepixel = peasycap->decimatepixel;
if ((2 != bytesperpixel) && \
(3 != bytesperpixel) && \
(4 != bytesperpixel)) {
- SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+ SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
return -EFAULT;
}
if (true == decimatepixel)
@@ -1082,8 +1504,8 @@ if (peasycap->field_buffer[kex][0].kount)
else
odd = false;
-if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) {
- JOT(8, " initial skipping %4i bytes p.%4i\n", \
+if ((true == odd) && (false == decimatepixel)) {
+ JOM(8, " initial skipping %4i bytes p.%4i\n", \
w3/multiplier, mad);
pad += (w3 / multiplier); rad -= (w3 / multiplier);
}
@@ -1108,7 +1530,7 @@ while (cz < wz) {
rump = 0;
if (much % 2) {
- SAY("MISTAKE: much is odd\n");
+ SAM("MISTAKE: much is odd\n");
return -EFAULT;
}
@@ -1116,13 +1538,11 @@ while (cz < wz) {
much) / 2;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (1 < bytesperpixel) {
- if ((rad * \
- 2) < (much * \
- bytesperpixel)) {
+ if (rad * 2 < much * bytesperpixel) {
/*
** INJUDICIOUS ALTERATION OF THIS
- ** BLOCK WILL CAUSE BREAKAGE.
- ** BEWARE.
+ ** STATEMENT BLOCK WILL CAUSE
+ ** BREAKAGE. BEWARE.
**/
rad2 = rad + bytesperpixel - 1;
much = ((((2 * \
@@ -1145,18 +1565,25 @@ while (cz < wz) {
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
} else {
- SAY("MISTAKE: %i=bytesperpixel\n", \
+ SAM("MISTAKE: %i=bytesperpixel\n", \
bytesperpixel);
return -EFAULT;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (rump)
caches++;
-
+ if (true == badinput) {
+ JOM(8, "ERROR: 0x%02X=->field_buffer" \
+ "[%i][%i].input, " \
+ "0x%02X=(0x08|->input)\n", \
+ peasycap->field_buffer\
+ [kex][mex].input, kex, mex, \
+ (0x08|peasycap->input));
+ }
rc = redaub(peasycap, pad, pex, much, more, \
mask, margin, isuy);
if (0 > rc) {
- SAY("ERROR: redaub() failed\n");
+ SAM("ERROR: redaub() failed\n");
return -EFAULT;
}
if (much % 4) {
@@ -1171,6 +1598,9 @@ while (cz < wz) {
mex++;
pex = peasycap->field_buffer[kex][mex].pgo;
rex = PAGE_SIZE;
+ if (peasycap->field_buffer[kex][mex].input != \
+ (0x08|peasycap->input))
+ badinput = true;
}
pad += more;
rad -= more;
@@ -1190,7 +1620,7 @@ while (cz < wz) {
* UNLESS IT IS THE LAST LINE OF AN ODD FRAME
*/
/*---------------------------------------------------------------------------*/
- if (((false == odd) || (cz != wz))&&(false == offerfields)) {
+ if ((false == odd) || (cz != wz)) {
over = w3;
do {
if (!rad) {
@@ -1224,7 +1654,7 @@ while (cz < wz) {
rump = 0;
if (much % 2) {
- SAY("MISTAKE: much is odd\n");
+ SAM("MISTAKE: much is odd\n");
return -EFAULT;
}
@@ -1232,12 +1662,11 @@ while (cz < wz) {
much) / 4;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (1 < bytesperpixel) {
- if ((rad * 4) < (much * \
- bytesperpixel)) {
+ if (rad * 4 < much * bytesperpixel) {
/*
** INJUDICIOUS ALTERATION OF THIS
- ** BLOCK WILL CAUSE BREAKAGE.
- ** BEWARE.
+ ** STATEMENT BLOCK WILL CAUSE
+ ** BREAKAGE. BEWARE.
**/
rad2 = rad + bytesperpixel - 1;
much = ((((2 * rad2)/bytesperpixel)/2)\
@@ -1261,7 +1690,7 @@ while (cz < wz) {
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
} else {
- SAY("MISTAKE: %i=bytesperpixel\n", \
+ SAM("MISTAKE: %i=bytesperpixel\n", \
bytesperpixel);
return -EFAULT;
}
@@ -1269,10 +1698,18 @@ while (cz < wz) {
if (rump)
caches++;
+ if (true == badinput) {
+ JOM(8, "ERROR: 0x%02X=->field_buffer" \
+ "[%i][%i].input, " \
+ "0x%02X=(0x08|->input)\n", \
+ peasycap->field_buffer\
+ [kex][mex].input, kex, mex, \
+ (0x08|peasycap->input));
+ }
rc = redaub(peasycap, pad, pex, much, more, \
mask, margin, isuy);
if (0 > rc) {
- SAY("ERROR: redaub() failed\n");
+ SAM("ERROR: redaub() failed\n");
return -EFAULT;
}
over -= much; cz += much;
@@ -1281,6 +1718,9 @@ while (cz < wz) {
mex++;
pex = peasycap->field_buffer[kex][mex].pgo;
rex = PAGE_SIZE;
+ if (peasycap->field_buffer[kex][mex].input != \
+ (0x08|peasycap->input))
+ badinput = true;
}
pad += more;
rad -= more;
@@ -1307,6 +1747,16 @@ while (cz < wz) {
mex++;
pex = peasycap->field_buffer[kex][mex].pgo;
rex = PAGE_SIZE;
+ if (peasycap->field_buffer[kex][mex].input != \
+ (0x08|peasycap->input)) {
+ JOM(8, "ERROR: 0x%02X=->field_buffer"\
+ "[%i][%i].input, " \
+ "0x%02X=(0x08|->input)\n", \
+ peasycap->field_buffer\
+ [kex][mex].input, kex, mex, \
+ (0x08|peasycap->input));
+ badinput = true;
+ }
}
much = over;
if (rex < much)
@@ -1325,39 +1775,39 @@ while (cz < wz) {
/*---------------------------------------------------------------------------*/
c2 = (mex + 1)*PAGE_SIZE - rex;
if (cz != c2)
- SAY("ERROR: discrepancy %i in bytes read\n", c2 - cz);
+ SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
c3 = (mad + 1)*PAGE_SIZE - rad;
if (false == decimatepixel) {
if (bytesperpixel * \
cz != c3) \
- SAY("ERROR: discrepancy %i in bytes written\n", \
+ SAM("ERROR: discrepancy %i in bytes written\n", \
c3 - (bytesperpixel * \
cz));
} else {
if (false == odd) {
if (bytesperpixel * \
cz != (4 * c3))
- SAY("ERROR: discrepancy %i in bytes written\n", \
+ SAM("ERROR: discrepancy %i in bytes written\n", \
(2*c3)-(bytesperpixel * \
cz));
} else {
if (0 != c3)
- SAY("ERROR: discrepancy %i " \
+ SAM("ERROR: discrepancy %i " \
"in bytes written\n", c3);
}
}
if (rump)
- SAY("ERROR: undischarged cache at end of line in frame buffer\n");
+ SAM("WORRY: undischarged cache at end of line in frame buffer\n");
-JOT(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
-JOT(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);
+JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
+JOM(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);
if (true == odd)
- JOT(8, "+++++ field2frame(): frame buffer %i is full\n", kad);
+ JOM(8, "+++++ field2frame(): frame buffer %i is full\n", kad);
if (peasycap->field_read == peasycap->field_fill)
- SAY("WARNING: on exit, filling field buffer %i\n", \
+ SAM("WARNING: on exit, filling field buffer %i\n", \
peasycap->field_read);
/*---------------------------------------------------------------------------*/
/*
@@ -1365,23 +1815,24 @@ if (peasycap->field_read == peasycap->field_fill)
*/
/*---------------------------------------------------------------------------*/
do_gettimeofday(&timeval);
-if (timeval0.tv_sec) {
+if (peasycap->timeval6.tv_sec) {
below = ((long long int)(1000000)) * \
- ((long long int)(timeval.tv_sec - timeval0.tv_sec)) + \
- (long long int)(timeval.tv_usec - timeval0.tv_usec);
+ ((long long int)(timeval.tv_sec - \
+ peasycap->timeval6.tv_sec)) + \
+ (long long int)(timeval.tv_usec - peasycap->timeval6.tv_usec);
above = (long long int)1000000;
sdr = signed_div(above, below);
above = sdr.quotient;
remainder = (__u32)sdr.remainder;
- JOT(8, "video streaming at %3lli.%03i fields per second\n", above, \
+ JOM(8, "video streaming at %3lli.%03i fields per second\n", above, \
(remainder/1000));
}
-timeval0 = timeval;
+peasycap->timeval6 = timeval;
if (caches)
- JOT(8, "%i=caches\n", caches);
+ JOM(8, "%i=caches\n", caches);
return 0;
}
/*****************************************************************************/
@@ -1434,7 +1885,7 @@ redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, \
__u8 mask, __u8 margin, bool isuy)
{
static __s32 ay[256], bu[256], rv[256], gu[256], gv[256];
-static __u8 cache[8], *pcache;
+__u8 *pcache;
__u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
int bytesperpixel;
bool byteswaporder, decimatepixel, last;
@@ -1442,7 +1893,7 @@ int j, rump;
__s32 s32;
if (much % 2) {
- SAY("MISTAKE: much is odd\n");
+ SAM("MISTAKE: much is odd\n");
return -EFAULT;
}
bytesperpixel = peasycap->bytesperpixel;
@@ -1475,30 +1926,31 @@ if (!bu[255]) {
ay[j] = ay[16];
for (j = 236; j < 256; j++)
ay[j] = ay[235];
- JOT(8, "lookup tables are prepared\n");
+ JOM(8, "lookup tables are prepared\n");
}
-if ((__u8 *)NULL == pcache)
- pcache = &cache[0];
+pcache = peasycap->pcache;
+if (NULL == pcache)
+ pcache = &peasycap->cache[0];
/*---------------------------------------------------------------------------*/
/*
* TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
*/
/*---------------------------------------------------------------------------*/
if (!pcache) {
- SAY("MISTAKE: pcache is NULL\n");
+ SAM("MISTAKE: pcache is NULL\n");
return -EFAULT;
}
-if (pcache != &cache[0])
- JOT(16, "cache has %i bytes\n", (int)(pcache - &cache[0]));
-p2 = &cache[0];
-p3 = (__u8 *)pad - (int)(pcache - &cache[0]);
+if (pcache != &peasycap->cache[0])
+ JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
+p2 = &peasycap->cache[0];
+p3 = (__u8 *)pad - (int)(pcache - &peasycap->cache[0]);
while (p2 < pcache) {
*p3++ = *p2; p2++;
}
-pcache = &cache[0];
+pcache = &peasycap->cache[0];
if (p3 != pad) {
- SAY("MISTAKE: pointer misalignment\n");
+ SAM("MISTAKE: pointer misalignment\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
@@ -1513,7 +1965,7 @@ else
v = *(p2 - 1);
if (rump)
- JOT(16, "%4i=much %4i=more %i=rump\n", much, more, rump);
+ JOM(16, "%4i=much %4i=more %i=rump\n", much, more, rump);
/*---------------------------------------------------------------------------*/
switch (bytesperpixel) {
@@ -1619,7 +2071,7 @@ case 3:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = r;
@@ -1634,7 +2086,7 @@ case 3:
break;
}
default: {
- SAY("MISTAKE: %i=rump\n", \
+ SAM("MISTAKE: %i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
}
@@ -1692,7 +2144,7 @@ case 3:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = b;
@@ -1707,7 +2159,7 @@ case 3:
break;
}
default: {
- SAY("MISTAKE: %i=rump\n", \
+ SAM("MISTAKE: %i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
}
@@ -1768,7 +2220,7 @@ case 3:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = r;
@@ -1783,7 +2235,7 @@ case 3:
break;
}
default: {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"%i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
@@ -1844,7 +2296,7 @@ case 3:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = b;
@@ -1859,7 +2311,7 @@ case 3:
break;
}
default: {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"%i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
@@ -1924,7 +2376,7 @@ case 4:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = r;
@@ -1948,7 +2400,7 @@ case 4:
break;
}
default: {
- SAY("MISTAKE: %i=rump\n", \
+ SAM("MISTAKE: %i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
}
@@ -2006,7 +2458,7 @@ case 4:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = b;
@@ -2030,7 +2482,7 @@ case 4:
break;
}
default: {
- SAY("MISTAKE: %i=rump\n", \
+ SAM("MISTAKE: %i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
}
@@ -2093,7 +2545,7 @@ case 4:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = r;
@@ -2117,7 +2569,7 @@ case 4:
break;
}
default: {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"%i=rump\n", \
bytesperpixel - \
rump);
@@ -2178,7 +2630,7 @@ case 4:
0 : (__u8)s32);
if ((true == last) && rump) {
- pcache = &cache[0];
+ pcache = &peasycap->cache[0];
switch (bytesperpixel - rump) {
case 1: {
*p3 = b;
@@ -2202,7 +2654,7 @@ case 4:
break;
}
default: {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"%i=rump\n", \
bytesperpixel - rump);
return -EFAULT;
@@ -2226,48 +2678,13 @@ case 4:
break;
}
default: {
- SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+ SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
return -EFAULT;
}
}
return 0;
}
/*****************************************************************************/
-void
-debrief(struct easycap *peasycap)
-{
-if ((struct usb_device *)NULL != peasycap->pusb_device) {
- check_stk(peasycap->pusb_device);
- check_saa(peasycap->pusb_device);
- sayreadonly(peasycap);
- SAY("%i=peasycap->field_fill\n", peasycap->field_fill);
- SAY("%i=peasycap->field_read\n", peasycap->field_read);
- SAY("%i=peasycap->frame_fill\n", peasycap->frame_fill);
- SAY("%i=peasycap->frame_read\n", peasycap->frame_read);
-}
-return;
-}
-/*****************************************************************************/
-void
-sayreadonly(struct easycap *peasycap)
-{
-static int done;
-int got00, got1F, got60, got61, got62;
-
-if ((!done) && ((struct usb_device *)NULL != peasycap->pusb_device)) {
- done = 1;
- got00 = read_saa(peasycap->pusb_device, 0x00);
- got1F = read_saa(peasycap->pusb_device, 0x1F);
- got60 = read_saa(peasycap->pusb_device, 0x60);
- got61 = read_saa(peasycap->pusb_device, 0x61);
- got62 = read_saa(peasycap->pusb_device, 0x62);
- SAY("0x%02X=reg0x00 0x%02X=reg0x1F\n", got00, got1F);
- SAY("0x%02X=reg0x60 0x%02X=reg0x61 0x%02X=reg0x62\n", \
- got60, got61, got62);
-}
-return;
-}
-/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
@@ -2292,11 +2709,16 @@ easycap_vma_open(struct vm_area_struct *pvma)
struct easycap *peasycap;
peasycap = pvma->vm_private_data;
-if (NULL != peasycap)
- peasycap->vma_many++;
-
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return;
+}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return;
+}
+peasycap->vma_many++;
JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
-
return;
}
/*****************************************************************************/
@@ -2306,10 +2728,16 @@ easycap_vma_close(struct vm_area_struct *pvma)
struct easycap *peasycap;
peasycap = pvma->vm_private_data;
-if (NULL != peasycap) {
- peasycap->vma_many--;
- JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return;
+}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return;
}
+peasycap->vma_many--;
+JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
return;
}
/*****************************************************************************/
@@ -2355,24 +2783,22 @@ if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return retcode;
}
-mutex_lock(&(peasycap->mutex_mmap_video[0]));
/*---------------------------------------------------------------------------*/
pbuf = peasycap->frame_buffer[k][m].pgo;
if (NULL == pbuf) {
- SAY("ERROR: pbuf is NULL\n");
+ SAM("ERROR: pbuf is NULL\n");
goto finish;
}
page = virt_to_page(pbuf);
if (NULL == page) {
- SAY("ERROR: page is NULL\n");
+ SAM("ERROR: page is NULL\n");
goto finish;
}
get_page(page);
/*---------------------------------------------------------------------------*/
finish:
-mutex_unlock(&(peasycap->mutex_mmap_video[0]));
if (NULL == page) {
- SAY("ERROR: page is NULL after get_page(page)\n");
+ SAM("ERROR: page is NULL after get_page(page)\n");
} else {
pvmf->page = page;
retcode = VM_FAULT_MINOR;
@@ -2383,7 +2809,7 @@ return retcode;
/*---------------------------------------------------------------------------*/
/*
* ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
- * PROVIDED peasycap->video_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,
+ * PROVIDED peasycap->video_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
* IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
*
* THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
@@ -2400,7 +2826,8 @@ return retcode;
* 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS
* 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA
* 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA
- * 0 != (kount & 0x0400) => FIELD WAS SUBMITTED BY BRIDGER ROUTINE
+ * 0 != (kount & 0x1000) => BUFFER HAS DATA FROM DISPARATE INPUTS
+ * 0 != (kount & 0x0400) => RESERVED
* 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED
* 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY?
*/
@@ -2408,19 +2835,14 @@ return retcode;
void
easycap_complete(struct urb *purb)
{
-static int mt;
struct easycap *peasycap;
struct data_buffer *pfield_buffer;
char errbuf[16];
int i, more, much, leap, rc, last;
int videofieldamount;
-unsigned int override;
+unsigned int override, bad;
int framestatus, framelength, frameactual, frameoffset;
__u8 *pu;
-#if defined(BRIDGER)
-struct timeval timeval;
-long long usec;
-#endif /*BRIDGER*/
if (NULL == purb) {
SAY("ERROR: easycap_complete(): purb is NULL\n");
@@ -2431,74 +2853,78 @@ if (NULL == peasycap) {
SAY("ERROR: easycap_complete(): peasycap is NULL\n");
return;
}
-
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return;
+}
if (peasycap->video_eof)
return;
-
for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
break;
-JOT(16, "%2i=urb\n", i);
+JOM(16, "%2i=urb\n", i);
last = peasycap->video_isoc_sequence;
if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \
(0 != i)) || \
(((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \
((last + 1) != i))) {
- SAY("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i);
+ JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n", last, i);
}
peasycap->video_isoc_sequence = i;
if (peasycap->video_idle) {
- JOT(16, "%i=video_idle %i=video_isoc_streaming\n", \
+ JOM(16, "%i=video_idle %i=video_isoc_streaming\n", \
peasycap->video_idle, peasycap->video_isoc_streaming);
if (peasycap->video_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
- SAY("ERROR: while %i=video_idle, " \
- "usb_submit_urb() failed with rc:\n", \
- peasycap->video_idle);
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n");
+ SAM("ENOMEM\n");
break;
}
case -ENODEV: {
- SAY("ENODEV\n");
+ SAM("ENODEV\n");
break;
}
case -ENXIO: {
- SAY("ENXIO\n");
+ SAM("ENXIO\n");
break;
}
case -EINVAL: {
- SAY("EINVAL\n");
+ SAM("EINVAL\n");
break;
}
case -EAGAIN: {
- SAY("EAGAIN\n");
+ SAM("EAGAIN\n");
break;
}
case -EFBIG: {
- SAY("EFBIG\n");
+ SAM("EFBIG\n");
break;
}
case -EPIPE: {
- SAY("EPIPE\n");
+ SAM("EPIPE\n");
break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n");
+ SAM("EMSGSIZE\n");
break;
}
case -ENOSPC: {
- SAY("ENOSPC\n");
+ SAM("ENOSPC\n");
break;
}
default: {
- SAY("0x%08X\n", rc);
+ SAM("0x%08X\n", rc);
break;
}
}
+ if (-ENODEV != rc) \
+ SAM("ERROR: while %i=video_idle, " \
+ "usb_submit_urb() " \
+ "failed with rc:\n", \
+ peasycap->video_idle);
}
}
return;
@@ -2506,80 +2932,80 @@ return;
override = 0;
/*---------------------------------------------------------------------------*/
if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAY("ERROR: bad peasycap->field_fill\n");
+ SAM("ERROR: bad peasycap->field_fill\n");
return;
}
if (purb->status) {
if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
- JOT(8, "urb status -ESHUTDOWN or -ENOENT\n");
+ JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
return;
}
(peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
- SAY("ERROR: bad urb status:\n");
+ SAM("ERROR: bad urb status:\n");
switch (purb->status) {
case -EINPROGRESS: {
- SAY("-EINPROGRESS\n"); break;
+ SAM("-EINPROGRESS\n"); break;
}
case -ENOSR: {
- SAY("-ENOSR\n"); break;
+ SAM("-ENOSR\n"); break;
}
case -EPIPE: {
- SAY("-EPIPE\n"); break;
+ SAM("-EPIPE\n"); break;
}
case -EOVERFLOW: {
- SAY("-EOVERFLOW\n"); break;
+ SAM("-EOVERFLOW\n"); break;
}
case -EPROTO: {
- SAY("-EPROTO\n"); break;
+ SAM("-EPROTO\n"); break;
}
case -EILSEQ: {
- SAY("-EILSEQ\n"); break;
+ SAM("-EILSEQ\n"); break;
}
case -ETIMEDOUT: {
- SAY("-ETIMEDOUT\n"); break;
+ SAM("-ETIMEDOUT\n"); break;
}
case -EMSGSIZE: {
- SAY("-EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n"); break;
}
case -EOPNOTSUPP: {
- SAY("-EOPNOTSUPP\n"); break;
+ SAM("-EOPNOTSUPP\n"); break;
}
case -EPFNOSUPPORT: {
- SAY("-EPFNOSUPPORT\n"); break;
+ SAM("-EPFNOSUPPORT\n"); break;
}
case -EAFNOSUPPORT: {
- SAY("-EAFNOSUPPORT\n"); break;
+ SAM("-EAFNOSUPPORT\n"); break;
}
case -EADDRINUSE: {
- SAY("-EADDRINUSE\n"); break;
+ SAM("-EADDRINUSE\n"); break;
}
case -EADDRNOTAVAIL: {
- SAY("-EADDRNOTAVAIL\n"); break;
+ SAM("-EADDRNOTAVAIL\n"); break;
}
case -ENOBUFS: {
- SAY("-ENOBUFS\n"); break;
+ SAM("-ENOBUFS\n"); break;
}
case -EISCONN: {
- SAY("-EISCONN\n"); break;
+ SAM("-EISCONN\n"); break;
}
case -ENOTCONN: {
- SAY("-ENOTCONN\n"); break;
+ SAM("-ENOTCONN\n"); break;
}
case -ESHUTDOWN: {
- SAY("-ESHUTDOWN\n"); break;
+ SAM("-ESHUTDOWN\n"); break;
}
case -ENOENT: {
- SAY("-ENOENT\n"); break;
+ SAM("-ENOENT\n"); break;
}
case -ECONNRESET: {
- SAY("-ECONNRESET\n"); break;
+ SAM("-ECONNRESET\n"); break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("ENOSPC\n"); break;
}
default: {
- SAY("unknown error code 0x%08X\n", purb->status); break;
+ SAM("unknown error code 0x%08X\n", purb->status); break;
}
}
/*---------------------------------------------------------------------------*/
@@ -2638,7 +3064,7 @@ if (purb->status) {
strcpy(&errbuf[0], "-ECONNRESET"); break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("ENOSPC\n"); break;
}
case -ESHUTDOWN: {
strcpy(&errbuf[0], "-ESHUTDOWN"); break;
@@ -2653,7 +3079,7 @@ if (purb->status) {
frameactual = purb->iso_frame_desc[i].actual_length;
frameoffset = purb->iso_frame_desc[i].offset;
- JOT(16, "frame[%2i]:" \
+ JOM(16, "frame[%2i]:" \
"%4i=status " \
"%4i=actual " \
"%4i=length " \
@@ -2667,19 +3093,20 @@ if (purb->status) {
PAGE_SIZE) + \
(int)(pfield_buffer->pto - pfield_buffer->pgo);
if (4 == more)
- mt++;
+ peasycap->video_mt++;
if (4 < more) {
- if (mt) {
- JOT(8, "%4i empty video urb frames\n", mt);
- mt = 0;
+ if (peasycap->video_mt) {
+ JOM(8, "%4i empty video urb frames\n", \
+ peasycap->video_mt);
+ peasycap->video_mt = 0;
}
if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAY("ERROR: bad peasycap->field_fill\n");
+ SAM("ERROR: bad peasycap->field_fill\n");
return;
}
if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
peasycap->field_page) {
- SAY("ERROR: bad peasycap->field_page\n");
+ SAM("ERROR: bad peasycap->field_page\n");
return;
}
pfield_buffer = &peasycap->field_buffer\
@@ -2712,11 +3139,13 @@ if (purb->status) {
peasycap->videofieldamount) {
if (2 == videofieldamount - \
peasycap->\
- videofieldamount)
+ videofieldamount) {
(peasycap->field_buffer\
[peasycap->field_fill]\
[0].kount) |= 0x0100;
- else
+ peasycap->video_junk += (1 + \
+ VIDEO_JUNK_TOLERATE);
+ } else
(peasycap->field_buffer\
[peasycap->field_fill]\
[0].kount) |= 0x4000;
@@ -2727,53 +3156,74 @@ if (purb->status) {
[peasycap->field_fill]\
[0].kount) |= 0x2000;
}
- if (!(0xFF00 & peasycap->field_buffer\
+ bad = 0xFF00 & peasycap->field_buffer\
[peasycap->field_fill]\
- [0].kount)) {
- (peasycap->video_junk)--;
- if (-16 > peasycap->video_junk)
- peasycap->video_junk = -16;
- peasycap->field_read = \
+ [0].kount;
+ if (!bad) {
+ (peasycap->video_junk)--;
+ if (-VIDEO_JUNK_TOLERATE > \
+ peasycap->video_junk) \
+ peasycap->video_junk =\
+ -VIDEO_JUNK_TOLERATE;
+ peasycap->field_read = \
(peasycap->\
field_fill)++;
-
- if (FIELD_BUFFER_MANY <= \
- peasycap->field_fill)
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- pfield_buffer = &peasycap->\
- field_buffer\
- [peasycap->field_fill]\
- [peasycap->field_page];
- pfield_buffer->pto = \
+ if (FIELD_BUFFER_MANY <= \
+ peasycap->\
+ field_fill)
+ peasycap->\
+ field_fill = 0;
+ peasycap->field_page = 0;
+ pfield_buffer = &peasycap->\
+ field_buffer\
+ [peasycap->\
+ field_fill]\
+ [peasycap->\
+ field_page];
+ pfield_buffer->pto = \
pfield_buffer->pgo;
-
- JOT(8, "bumped to: %i=peasycap->" \
- "field_fill %i=parity\n", \
- peasycap->field_fill, \
- 0x00FF & pfield_buffer->kount);
- JOT(8, "field buffer %i has %i " \
- "bytes fit to be read\n", \
- peasycap->field_read, \
- videofieldamount);
- JOT(8, "wakeup call to wq_video, " \
- "%i=field_read %i=field_fill "\
- "%i=parity\n", \
- peasycap->field_read, \
- peasycap->field_fill, \
- 0x00FF & peasycap->\
- field_buffer[peasycap->\
- field_read][0].kount);
- wake_up_interruptible(&(peasycap->\
- wq_video));
- do_gettimeofday(&peasycap->timeval7);
+ JOM(8, "bumped to: %i="\
+ "peasycap->" \
+ "field_fill %i="\
+ "parity\n", \
+ peasycap->field_fill, \
+ 0x00FF & \
+ pfield_buffer->kount);
+ JOM(8, "field buffer %i has "\
+ "%i bytes fit to be "\
+ "read\n", \
+ peasycap->field_read, \
+ videofieldamount);
+ JOM(8, "wakeup call to "\
+ "wq_video, " \
+ "%i=field_read "\
+ "%i=field_fill "\
+ "%i=parity\n", \
+ peasycap->field_read, \
+ peasycap->field_fill, \
+ 0x00FF & peasycap->\
+ field_buffer\
+ [peasycap->\
+ field_read][0].kount);
+ wake_up_interruptible\
+ (&(peasycap->\
+ wq_video));
+ do_gettimeofday\
+ (&peasycap->timeval7);
} else {
peasycap->video_junk++;
- JOT(8, "field buffer %i had %i " \
- "bytes, now discarded\n", \
+ if (bad & 0x0010) \
+ peasycap->video_junk += \
+ (1 + VIDEO_JUNK_TOLERATE/2);
+ JOM(8, "field buffer %i had %i " \
+ "bytes, now discarded: "\
+ "0x%04X\n", \
peasycap->field_fill, \
- videofieldamount);
-
+ videofieldamount,\
+ (0xFF00 & \
+ peasycap->field_buffer\
+ [peasycap->field_fill][0].\
+ kount));
(peasycap->field_fill)++;
if (FIELD_BUFFER_MANY <= \
@@ -2787,20 +3237,22 @@ if (purb->status) {
pfield_buffer->pto = \
pfield_buffer->pgo;
- JOT(8, "bumped to: %i=peasycap->" \
+ JOM(8, "bumped to: %i=peasycap->" \
"field_fill %i=parity\n", \
peasycap->field_fill, \
0x00FF & pfield_buffer->kount);
}
if (8 == more) {
- JOT(8, "end-of-field: received " \
+ JOM(8, "end-of-field: received " \
"parity byte 0x%02X\n", \
(0xFF & *pu));
if (0x40 & *pu)
pfield_buffer->kount = 0x0000;
else
pfield_buffer->kount = 0x0001;
- JOT(8, "end-of-field: 0x%02X=kount\n",\
+ pfield_buffer->input = 0x08 | \
+ (0x07 & peasycap->input);
+ JOM(8, "end-of-field: 0x%02X=kount\n",\
0xFF & pfield_buffer->kount);
}
}
@@ -2813,12 +3265,12 @@ if (purb->status) {
more -= leap;
if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
- SAY("ERROR: bad peasycap->field_fill\n");
+ SAM("ERROR: bad peasycap->field_fill\n");
return;
}
if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
peasycap->field_page) {
- SAY("ERROR: bad peasycap->field_page\n");
+ SAM("ERROR: bad peasycap->field_page\n");
return;
}
pfield_buffer = &peasycap->field_buffer\
@@ -2829,7 +3281,7 @@ if (purb->status) {
[peasycap->field_page];
if (PAGE_SIZE < (pfield_buffer->pto - \
pfield_buffer->pgo)) {
- SAY("ERROR: bad pfield_buffer->pto\n");
+ SAM("ERROR: bad pfield_buffer->pto\n");
return;
}
if (PAGE_SIZE == (pfield_buffer->pto - \
@@ -2837,7 +3289,7 @@ if (purb->status) {
(peasycap->field_page)++;
if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
peasycap->field_page) {
- JOT(16, "wrapping peasycap->" \
+ JOM(16, "wrapping peasycap->" \
"field_page\n");
peasycap->field_page = 0;
}
@@ -2847,6 +3299,15 @@ if (purb->status) {
[peasycap->field_page];
pfield_buffer->pto = \
pfield_buffer->pgo;
+ pfield_buffer->input = 0x08 | \
+ (0x07 & peasycap->input);
+ if ((peasycap->field_buffer[peasycap->\
+ field_fill][0]).\
+ input != \
+ pfield_buffer->input)
+ (peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [0]).kount |= 0x1000;
}
much = PAGE_SIZE - (int)(pfield_buffer->pto - \
@@ -2865,55 +3326,6 @@ if (purb->status) {
}
/*---------------------------------------------------------------------------*/
/*
- *
- *
- * *** UNDER DEVELOPMENT/TESTING - NOT READY YET! ***
- *
- *
- *
- * VIDEOTAPES MAY HAVE BEEN MANUALLY PAUSED AND RESTARTED DURING RECORDING.
- * THIS CAUSES LOSS OF SYNC, CONFUSING DOWNSTREAM USERSPACE PROGRAMS WHICH
- * MAY INTERPRET THE INTERRUPTION AS A SYMPTOM OF LATENCY. TO OVERCOME THIS
- * THE DRIVER BRIDGES THE HIATUS BY SENDING DUMMY VIDEO FRAMES AT ROUGHLY
- * THE RIGHT TIME INTERVALS IN THE HOPE OF PERSUADING THE DOWNSTREAM USERSPACE
- * PROGRAM TO RESUME NORMAL SERVICE WHEN THE INTERRUPTION IS OVER.
- */
-/*---------------------------------------------------------------------------*/
-#if defined(BRIDGER)
-do_gettimeofday(&timeval);
-if (peasycap->timeval7.tv_sec) {
- usec = 1000000*(timeval.tv_sec - peasycap->timeval7.tv_sec) + \
- (timeval.tv_usec - peasycap->timeval7.tv_usec);
- if (usec > (peasycap->usec + peasycap->tolerate)) {
- JOT(8, "bridging hiatus\n");
- peasycap->video_junk = 0;
- peasycap->field_buffer[peasycap->field_fill][0].kount |= 0x0400;
-
- peasycap->field_read = (peasycap->field_fill)++;
-
- if (FIELD_BUFFER_MANY <= peasycap->field_fill) \
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- pfield_buffer = &peasycap->field_buffer\
- [peasycap->field_fill][peasycap->field_page];
- pfield_buffer->pto = pfield_buffer->pgo;
-
- JOT(8, "bumped to: %i=peasycap->field_fill %i=parity\n", \
- peasycap->field_fill, 0x00FF & pfield_buffer->kount);
- JOT(8, "field buffer %i has %i bytes to be overwritten\n", \
- peasycap->field_read, videofieldamount);
- JOT(8, "wakeup call to wq_video, " \
- "%i=field_read %i=field_fill %i=parity\n", \
- peasycap->field_read, peasycap->field_fill, \
- 0x00FF & \
- peasycap->field_buffer[peasycap->field_read][0].kount);
- wake_up_interruptible(&(peasycap->wq_video));
- do_gettimeofday(&peasycap->timeval7);
- }
-}
-#endif /*BRIDGER*/
-/*---------------------------------------------------------------------------*/
-/*
* RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
*
* IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
@@ -2921,51 +3333,57 @@ if (peasycap->timeval7.tv_sec) {
*/
/*---------------------------------------------------------------------------*/
if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
- SAY("easycap driver shutting down on condition green\n");
+ SAM("easycap driver shutting down on condition green\n");
+ peasycap->status = 1;
peasycap->video_eof = 1;
+ peasycap->video_junk = 0;
+ wake_up_interruptible(&peasycap->wq_video);
+#if !defined(PERSEVERE)
peasycap->audio_eof = 1;
- peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY;
- wake_up_interruptible(&(peasycap->wq_video));
- wake_up_interruptible(&(peasycap->wq_audio));
+ wake_up_interruptible(&peasycap->wq_audio);
+#endif /*PERSEVERE*/
return;
}
if (peasycap->video_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
- SAY("ERROR: while %i=video_idle, usb_submit_urb() failed " \
- "with rc:\n", peasycap->video_idle);
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n"); break;
+ SAM("ENOMEM\n"); break;
}
case -ENODEV: {
- SAY("ENODEV\n"); break;
+ SAM("ENODEV\n"); break;
}
case -ENXIO: {
- SAY("ENXIO\n"); break;
+ SAM("ENXIO\n"); break;
}
case -EINVAL: {
- SAY("EINVAL\n"); break;
+ SAM("EINVAL\n"); break;
}
case -EAGAIN: {
- SAY("EAGAIN\n"); break;
+ SAM("EAGAIN\n"); break;
}
case -EFBIG: {
- SAY("EFBIG\n"); break;
+ SAM("EFBIG\n"); break;
}
case -EPIPE: {
- SAY("EPIPE\n"); break;
+ SAM("EPIPE\n"); break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n"); break;
+ SAM("EMSGSIZE\n"); break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("ENOSPC\n"); break;
}
default: {
- SAY("0x%08X\n", rc); break;
+ SAM("0x%08X\n", rc); break;
}
}
+ if (-ENODEV != rc) \
+ SAM("ERROR: while %i=video_idle, " \
+ "usb_submit_urb() " \
+ "failed with rc:\n", \
+ peasycap->video_idle);
}
}
return;
@@ -2977,8 +3395,8 @@ return;
* FIXME
*
*
- * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS
- * PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
+ * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP
+ * IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
* IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
*
* THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
@@ -2994,7 +3412,7 @@ struct usb_endpoint_descriptor *pepd;
struct usb_interface_descriptor *pusb_interface_descriptor;
struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;
struct urb *purb;
-static struct easycap *peasycap /*=NULL*/;
+struct easycap *peasycap;
struct data_urb *pdata_urb;
size_t wMaxPacketSize;
int ISOCwMaxPacketSize;
@@ -3004,19 +3422,32 @@ int CTRLwMaxPacketSize;
__u8 bEndpointAddress;
__u8 ISOCbEndpointAddress;
__u8 INTbEndpointAddress;
-int isin, i, j, k, m;
+int isin, i, j, k, m, rc;
__u8 bInterfaceNumber;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
void *pbuf;
int okalt[8], isokalt;
-int okepn[8], isokepn;
-int okmps[8], isokmps;
+int okepn[8];
+int okmps[8];
int maxpacketsize;
-int rc;
+__u16 mask;
+__s32 value;
+struct easycap_format *peasycap_format;
JOT(4, "\n");
+if (!dongle_done) {
+ dongle_done = 1;
+ for (k = 0; k < DONGLE_MANY; k++) {
+ easycap_dongle[k].peasycap = (struct easycap *)NULL;
+ mutex_init(&easycap_dongle[k].mutex_video);
+ mutex_init(&easycap_dongle[k].mutex_audio);
+ }
+}
+
+peasycap = (struct easycap *)NULL;
+
if ((struct usb_interface *)NULL == pusb_interface) {
SAY("ERROR: pusb_interface is NULL\n");
return -EFAULT;
@@ -3117,46 +3548,83 @@ JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \
/*
* A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
* IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap. THIS
- * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE DEVICE WAS PHYSICALLY
- * UNPLUGGED.
- */
+ * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
+ * PHYSICALLY UNPLUGGED.
+ *
+ * THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
+ * INTERFACES 1 AND 2 ARE PROBED.
+ *
+ * IF TWO EasyCAPs ARE PLUGGED IN NEARLY SIMULTANEOUSLY THERE WILL
+ * BE TROUBLE. BEWARE.
+*/
/*---------------------------------------------------------------------------*/
if (0 == bInterfaceNumber) {
peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
if (NULL == peasycap) {
SAY("ERROR: Could not allocate peasycap\n");
return -ENOMEM;
- } else {
- peasycap->allocation_video_struct = sizeof(struct easycap);
- peasycap->allocation_video_page = 0;
- peasycap->allocation_video_urb = 0;
- peasycap->allocation_audio_struct = 0;
- peasycap->allocation_audio_page = 0;
- peasycap->allocation_audio_urb = 0;
}
+ SAM("allocated 0x%08lX=peasycap\n", (unsigned long int) peasycap);
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+ SAM("where 0x%08lX=&peasycap->video_device\n", \
+ (unsigned long int) &peasycap->video_device);
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+ SAM("and 0x%08lX=&peasycap->v4l2_device\n", \
+ (unsigned long int) &peasycap->v4l2_device);
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*---------------------------------------------------------------------------*/
/*
- * INITIALIZE THE NEW easycap STRUCTURE.
- * NO PARAMETERS ARE SPECIFIED HERE REQUIRING THE SETTING OF REGISTERS.
- * THAT IS DONE FIRST BY easycap_open() AND LATER BY easycap_ioctl().
- */
+ * PERFORM URGENT INTIALIZATIONS ...
+*/
/*---------------------------------------------------------------------------*/
- peasycap->pusb_device = pusb_device;
- peasycap->pusb_interface = pusb_interface;
-
+ strcpy(&peasycap->telltale[0], TELLTALE);
kref_init(&peasycap->kref);
- JOT(8, "intf[%i]: after kref_init(..._video) " \
+ JOM(8, "intf[%i]: after kref_init(..._video) " \
"%i=peasycap->kref.refcount.counter\n", \
bInterfaceNumber, peasycap->kref.refcount.counter);
- init_waitqueue_head(&(peasycap->wq_video));
- init_waitqueue_head(&(peasycap->wq_audio));
+ init_waitqueue_head(&peasycap->wq_video);
+ init_waitqueue_head(&peasycap->wq_audio);
+
+ for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
+ if (NULL == easycap_dongle[dongle_this].peasycap) {
+ if (0 == mutex_is_locked(&easycap_dongle\
+ [dongle_this].mutex_video)) {
+ if (0 == mutex_is_locked(&easycap_dongle\
+ [dongle_this].mutex_audio)) {
+ easycap_dongle\
+ [dongle_this].peasycap = \
+ peasycap;
+ JOM(8, "intf[%i]: peasycap-->easycap" \
+ "_dongle[%i].peasycap\n", \
+ bInterfaceNumber, dongle_this);
+ break;
+ }
+ }
+ }
+ }
+ if (DONGLE_MANY <= dongle_this) {
+ SAM("ERROR: too many dongles\n");
+ return -ENOMEM;
+ }
- mutex_init(&(peasycap->mutex_timeval0));
- mutex_init(&(peasycap->mutex_timeval1));
+ peasycap->allocation_video_struct = sizeof(struct easycap);
+ peasycap->allocation_video_page = 0;
+ peasycap->allocation_video_urb = 0;
+ peasycap->allocation_audio_struct = 0;
+ peasycap->allocation_audio_page = 0;
+ peasycap->allocation_audio_urb = 0;
- for (k = 0; k < FRAME_BUFFER_MANY; k++)
- mutex_init(&(peasycap->mutex_mmap_video[k]));
+/*---------------------------------------------------------------------------*/
+/*
+ * ... AND FURTHER INITIALIZE THE STRUCTURE
+*/
+/*---------------------------------------------------------------------------*/
+ peasycap->pusb_device = pusb_device;
+ peasycap->pusb_interface = pusb_interface;
peasycap->ilk = 0;
peasycap->microphone = false;
@@ -3177,46 +3645,172 @@ if (0 == bInterfaceNumber) {
peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
- if ((struct mutex *)NULL == &(peasycap->mutex_mmap_video[0])) {
- SAY("ERROR: &(peasycap->mutex_mmap_video[%i]) is NULL\n", 0);
- return -EFAULT;
- }
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->lost[k] = 0;
+ peasycap->skip = 0;
+ peasycap->skipped = 0;
+ peasycap->offerfields = 0;
/*---------------------------------------------------------------------------*/
/*
- * DYNAMICALLY FILL IN THE AVAILABLE FORMATS.
+ * DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
*/
/*---------------------------------------------------------------------------*/
rc = fillin_formats();
if (0 > rc) {
- SAY("ERROR: fillin_formats() returned %i\n", rc);
+ SAM("ERROR: fillin_formats() returned %i\n", rc);
return -EFAULT;
}
- JOT(4, "%i formats available\n", rc);
- } else {
+ JOM(4, "%i formats available\n", rc);
/*---------------------------------------------------------------------------*/
- if ((struct easycap *)NULL == peasycap) {
- SAY("ERROR: peasycap is NULL " \
- "when probing interface %i\n", \
- bInterfaceNumber);
- return -EFAULT;
+/*
+ * ... AND POPULATE easycap.inputset[]
+*/
+/*---------------------------------------------------------------------------*/
+ for (k = 0; k < INPUT_MANY; k++) {
+ peasycap->inputset[k].input_ok = 0;
+ peasycap->inputset[k].standard_offset_ok = 0;
+ peasycap->inputset[k].format_offset_ok = 0;
+ peasycap->inputset[k].brightness_ok = 0;
+ peasycap->inputset[k].contrast_ok = 0;
+ peasycap->inputset[k].saturation_ok = 0;
+ peasycap->inputset[k].hue_ok = 0;
+ }
+ if (true == peasycap->ntsc) {
+ i = 0;
+ m = 0;
+ mask = 0;
+ while (0xFFFF != easycap_standard[i].mask) {
+ if (NTSC_M == easycap_standard[i].\
+ v4l2_standard.index) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++) {
+ peasycap->inputset[k].\
+ standard_offset = i;
+ }
+ mask = easycap_standard[i].mask;
+ }
+ i++;
}
+ } else {
+ i = 0;
+ m = 0;
+ mask = 0;
+ while (0xFFFF != easycap_standard[i].mask) {
+ if (PAL_BGHIN == easycap_standard[i].\
+ v4l2_standard.index) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++) {
+ peasycap->inputset[k].\
+ standard_offset = i;
+ }
+ mask = easycap_standard[i].mask;
+ }
+ i++;
+ }
+ }
- JOT(8, "kref_get() with %i=peasycap->kref.refcount.counter\n", \
- (int)peasycap->kref.refcount.counter);
- kref_get(&peasycap->kref);
+ if (1 != m) {
+ SAM("MISTAKE: easycap.inputset[].standard_offset " \
+ "unpopulated, %i=m\n", m);
+ return -ENOENT;
+ }
+
+ peasycap_format = &easycap_format[0];
+ i = 0;
+ m = 0;
+ while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+ if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+ (peasycap_format->\
+ v4l2_format.fmt.pix.field == \
+ V4L2_FIELD_NONE) && \
+ (peasycap_format->\
+ v4l2_format.fmt.pix.pixelformat == \
+ V4L2_PIX_FMT_UYVY) && \
+ (peasycap_format->\
+ v4l2_format.fmt.pix.width == \
+ 640) && \
+ (peasycap_format->\
+ v4l2_format.fmt.pix.height == 480)) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].format_offset = i;
+ break;
+ }
+ peasycap_format++;
+ i++;
+ }
+ if (1 != m) {
+ SAM("MISTAKE: easycap.inputset[].format_offset unpopulated\n");
+ return -ENOENT;
+ }
+
+ i = 0;
+ m = 0;
+ while (0xFFFFFFFF != easycap_control[i].id) {
+ value = easycap_control[i].default_value;
+ if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].brightness = value;
+ } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].contrast = value;
+ } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].saturation = value;
+ } else if (V4L2_CID_HUE == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].hue = value;
+ }
+ i++;
+ }
+ if (4 != m) {
+ SAM("MISTAKE: easycap.inputset[].brightness,... " \
+ "underpopulated\n");
+ return -ENOENT;
+ }
+ for (k = 0; k < INPUT_MANY; k++)
+ peasycap->inputset[k].input = k;
+ JOM(4, "populated easycap.inputset[]\n");
+ JOM(4, "finished initialization\n");
+} else {
+/*---------------------------------------------------------------------------*/
+ /*
+ * FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
+ * THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF
+ * THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
+ * SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE.
+ */
+/*---------------------------------------------------------------------------*/
+ if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
+ SAY("ERROR: bad dongle count\n");
+ return -EFAULT;
+ }
+ peasycap = easycap_dongle[dongle_this].peasycap;
+ JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \
+ bInterfaceNumber, dongle_this);
+
+ if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL when probing interface %i\n", \
+ bInterfaceNumber);
+ return -EFAULT;
+ }
}
/*---------------------------------------------------------------------------*/
if ((USB_CLASS_VIDEO == bInterfaceClass) || \
- (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+ (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
if (-1 == peasycap->video_interface) {
peasycap->video_interface = bInterfaceNumber;
- JOT(4, "setting peasycap->video_interface=%i\n", \
+ JOM(4, "setting peasycap->video_interface=%i\n", \
peasycap->video_interface);
} else {
if (peasycap->video_interface != bInterfaceNumber) {
- SAY("ERROR: attempting to reset " \
+ SAM("ERROR: attempting to reset " \
"peasycap->video_interface\n");
- SAY("...... continuing with " \
+ SAM("...... continuing with " \
"%i=peasycap->video_interface\n", \
peasycap->video_interface);
}
@@ -3225,13 +3819,13 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \
(0x02 == bInterfaceSubClass)) {
if (-1 == peasycap->audio_interface) {
peasycap->audio_interface = bInterfaceNumber;
- JOT(4, "setting peasycap->audio_interface=%i\n", \
+ JOM(4, "setting peasycap->audio_interface=%i\n", \
peasycap->audio_interface);
} else {
if (peasycap->audio_interface != bInterfaceNumber) {
- SAY("ERROR: attempting to reset " \
+ SAM("ERROR: attempting to reset " \
"peasycap->audio_interface\n");
- SAY("...... continuing with " \
+ SAM("...... continuing with " \
"%i=peasycap->audio_interface\n", \
peasycap->audio_interface);
}
@@ -3244,37 +3838,35 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \
*/
/*---------------------------------------------------------------------------*/
isokalt = 0;
-isokepn = 0;
-isokmps = 0;
for (i = 0; i < pusb_interface->num_altsetting; i++) {
pusb_host_interface = &(pusb_interface->altsetting[i]);
if ((struct usb_host_interface *)NULL == pusb_host_interface) {
- SAY("ERROR: pusb_host_interface is NULL\n");
+ SAM("ERROR: pusb_host_interface is NULL\n");
return -EFAULT;
}
pusb_interface_descriptor = &(pusb_host_interface->desc);
if ((struct usb_interface_descriptor *)NULL == \
pusb_interface_descriptor) {
- SAY("ERROR: pusb_interface_descriptor is NULL\n");
+ SAM("ERROR: pusb_interface_descriptor is NULL\n");
return -EFAULT;
}
- JOT(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bDescriptorType);
- JOT(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceNumber);
- JOT(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bAlternateSetting);
- JOT(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bNumEndpoints);
- JOT(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceClass);
- JOT(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceSubClass);
- JOT(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceProtocol);
- JOT(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \
+ JOM(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \
bInterfaceNumber, i, pusb_interface_descriptor->iInterface);
ISOCwMaxPacketSize = -1;
@@ -3285,86 +3877,80 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
INTbEndpointAddress = 0;
if (0 == pusb_interface_descriptor->bNumEndpoints)
- JOT(4, "intf[%i]alt[%i] has no endpoints\n", \
+ JOM(4, "intf[%i]alt[%i] has no endpoints\n", \
bInterfaceNumber, i);
/*---------------------------------------------------------------------------*/
for (j = 0; j < pusb_interface_descriptor->bNumEndpoints; j++) {
pepd = &(pusb_host_interface->endpoint[j].desc);
if ((struct usb_endpoint_descriptor *)NULL == pepd) {
- SAY("ERROR: pepd is NULL.\n");
- SAY("...... skipping\n");
+ SAM("ERROR: pepd is NULL.\n");
+ SAM("...... skipping\n");
continue;
}
wMaxPacketSize = le16_to_cpu(pepd->wMaxPacketSize);
bEndpointAddress = pepd->bEndpointAddress;
- JOT(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \
+ JOM(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \
bInterfaceNumber, i, j, \
pepd->bEndpointAddress);
- JOT(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \
+ JOM(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \
bInterfaceNumber, i, j, \
pepd->bmAttributes);
- JOT(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \
+ JOM(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \
bInterfaceNumber, i, j, \
pepd->wMaxPacketSize);
- JOT(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n",
+ JOM(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n",
bInterfaceNumber, i, j, \
pepd->bInterval);
if (pepd->bEndpointAddress & USB_DIR_IN) {
- JOT(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\
bInterfaceNumber, i, j);
isin = 1;
} else {
- JOT(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\
bInterfaceNumber, i, j);
- SAY("ERROR: OUT endpoint unexpected\n");
- SAY("...... continuing\n");
+ SAM("ERROR: OUT endpoint unexpected\n");
+ SAM("...... continuing\n");
isin = 0;
}
if ((pepd->bmAttributes & \
USB_ENDPOINT_XFERTYPE_MASK) == \
USB_ENDPOINT_XFER_ISOC) {
- JOT(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\
bInterfaceNumber, i, j);
if (isin) {
switch (bInterfaceClass) {
case USB_CLASS_VIDEO:
case USB_CLASS_VENDOR_SPEC: {
if (!peasycap) {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"peasycap is NULL\n");
return -EFAULT;
}
if (pepd->wMaxPacketSize) {
if (8 > isokalt) {
okalt[isokalt] = i;
- JOT(4,\
+ JOM(4,\
"%i=okalt[%i]\n", \
okalt[isokalt], \
isokalt);
- isokalt++;
- }
- if (8 > isokepn) {
- okepn[isokepn] = \
+ okepn[isokalt] = \
pepd->\
bEndpointAddress & \
0x0F;
- JOT(4,\
+ JOM(4,\
"%i=okepn[%i]\n", \
- okepn[isokepn], \
- isokepn);
- isokepn++;
- }
- if (8 > isokmps) {
- okmps[isokmps] = \
+ okepn[isokalt], \
+ isokalt);
+ okmps[isokalt] = \
le16_to_cpu(pepd->\
wMaxPacketSize);
- JOT(4,\
+ JOM(4,\
"%i=okmps[%i]\n", \
- okmps[isokmps], \
- isokmps);
- isokmps++;
+ okmps[isokalt], \
+ isokalt);
+ isokalt++;
}
} else {
if (-1 == peasycap->\
@@ -3372,16 +3958,16 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
peasycap->\
video_altsetting_off =\
i;
- JOT(4, "%i=video_" \
+ JOM(4, "%i=video_" \
"altsetting_off " \
"<====\n", \
peasycap->\
video_altsetting_off);
} else {
- SAY("ERROR: peasycap" \
+ SAM("ERROR: peasycap" \
"->video_altsetting_" \
"off already set\n");
- SAY("...... " \
+ SAM("...... " \
"continuing with " \
"%i=peasycap->video_" \
"altsetting_off\n", \
@@ -3395,39 +3981,33 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
if (0x02 != bInterfaceSubClass)
break;
if (!peasycap) {
- SAY("MISTAKE: " \
+ SAM("MISTAKE: " \
"peasycap is NULL\n");
return -EFAULT;
}
if (pepd->wMaxPacketSize) {
if (8 > isokalt) {
okalt[isokalt] = i ;
- JOT(4,\
+ JOM(4,\
"%i=okalt[%i]\n", \
okalt[isokalt], \
isokalt);
- isokalt++;
- }
- if (8 > isokepn) {
- okepn[isokepn] = \
+ okepn[isokalt] = \
pepd->\
bEndpointAddress & \
0x0F;
- JOT(4,\
+ JOM(4,\
"%i=okepn[%i]\n", \
- okepn[isokepn], \
- isokepn);
- isokepn++;
- }
- if (8 > isokmps) {
- okmps[isokmps] = \
+ okepn[isokalt], \
+ isokalt);
+ okmps[isokalt] = \
le16_to_cpu(pepd->\
wMaxPacketSize);
- JOT(4,\
+ JOM(4,\
"%i=okmps[%i]\n",\
- okmps[isokmps], \
- isokmps);
- isokmps++;
+ okmps[isokalt], \
+ isokalt);
+ isokalt++;
}
} else {
if (-1 == peasycap->\
@@ -3435,16 +4015,16 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
peasycap->\
audio_altsetting_off =\
i;
- JOT(4, "%i=audio_" \
+ JOM(4, "%i=audio_" \
"altsetting_off " \
"<====\n", \
peasycap->\
audio_altsetting_off);
} else {
- SAY("ERROR: peasycap" \
+ SAM("ERROR: peasycap" \
"->audio_altsetting_" \
"off already set\n");
- SAY("...... " \
+ SAM("...... " \
"continuing with " \
"%i=peasycap->\
audio_altsetting_" \
@@ -3462,19 +4042,19 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
} else if ((pepd->bmAttributes & \
USB_ENDPOINT_XFERTYPE_MASK) ==\
USB_ENDPOINT_XFER_BULK) {
- JOT(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\
bInterfaceNumber, i, j);
} else if ((pepd->bmAttributes & \
USB_ENDPOINT_XFERTYPE_MASK) ==\
USB_ENDPOINT_XFER_INT) {
- JOT(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\
bInterfaceNumber, i, j);
} else {
- JOT(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\
+ JOM(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\
bInterfaceNumber, i, j);
}
if (0 == pepd->wMaxPacketSize) {
- JOT(4, "intf[%i]alt[%i]end[%i] " \
+ JOM(4, "intf[%i]alt[%i]end[%i] " \
"has zero packet size\n", \
bInterfaceNumber, i, j);
}
@@ -3485,7 +4065,7 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) {
* PERFORM INITIALIZATION OF THE PROBED INTERFACE
*/
/*---------------------------------------------------------------------------*/
-JOT(4, "initialization begins for interface %i\n", \
+JOM(4, "initialization begins for interface %i\n", \
pusb_interface_descriptor->bInterfaceNumber);
switch (bInterfaceNumber) {
/*---------------------------------------------------------------------------*/
@@ -3495,89 +4075,78 @@ switch (bInterfaceNumber) {
/*---------------------------------------------------------------------------*/
case 0: {
if (!peasycap) {
- SAY("MISTAKE: peasycap is NULL\n");
+ SAM("MISTAKE: peasycap is NULL\n");
return -EFAULT;
}
if (!isokalt) {
- SAY("ERROR: no viable video_altsetting_on\n");
+ SAM("ERROR: no viable video_altsetting_on\n");
return -ENOENT;
} else {
peasycap->video_altsetting_on = okalt[isokalt - 1];
- JOT(4, "%i=video_altsetting_on <====\n", \
+ JOM(4, "%i=video_altsetting_on <====\n", \
peasycap->video_altsetting_on);
}
- if (!isokepn) {
- SAY("ERROR: no viable video_endpointnumber\n");
- return -ENOENT;
- } else {
- peasycap->video_endpointnumber = okepn[isokepn - 1];
- JOT(4, "%i=video_endpointnumber\n", \
- peasycap->video_endpointnumber);
- }
- if (!isokmps) {
- SAY("ERROR: no viable video_maxpacketsize\n");
- return -ENOENT;
/*---------------------------------------------------------------------------*/
/*
* DECIDE THE VIDEO STREAMING PARAMETERS
*/
/*---------------------------------------------------------------------------*/
+ peasycap->video_endpointnumber = okepn[isokalt - 1];
+ JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
+ maxpacketsize = okmps[isokalt - 1];
+ if (USB_2_0_MAXPACKETSIZE > maxpacketsize) {
+ peasycap->video_isoc_maxframesize = maxpacketsize;
} else {
- maxpacketsize = okmps[isokmps - 1] - 1024;
- if (USB_2_0_MAXPACKETSIZE > maxpacketsize) {
- peasycap->video_isoc_maxframesize = maxpacketsize;
- } else {
- peasycap->video_isoc_maxframesize = \
- USB_2_0_MAXPACKETSIZE;
- }
- JOT(4, "%i=video_isoc_maxframesize\n", \
- peasycap->video_isoc_maxframesize);
- if (0 >= peasycap->video_isoc_maxframesize) {
- SAY("ERROR: bad video_isoc_maxframesize\n");
- return -ENOENT;
- }
- peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
- JOT(4, "%i=video_isoc_framesperdesc\n", \
- peasycap->video_isoc_framesperdesc);
- if (0 >= peasycap->video_isoc_framesperdesc) {
- SAY("ERROR: bad video_isoc_framesperdesc\n");
- return -ENOENT;
- }
- peasycap->video_isoc_buffer_size = \
- peasycap->video_isoc_maxframesize * \
- peasycap->video_isoc_framesperdesc;
- JOT(4, "%i=video_isoc_buffer_size\n", \
- peasycap->video_isoc_buffer_size);
- if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \
- peasycap->video_isoc_buffer_size) {
- SAY("MISTAKE: " \
- "peasycap->video_isoc_buffer_size too big\n");
- return -EFAULT;
- }
+ peasycap->video_isoc_maxframesize = \
+ USB_2_0_MAXPACKETSIZE;
+ }
+ JOM(4, "%i=video_isoc_maxframesize\n", \
+ peasycap->video_isoc_maxframesize);
+ if (0 >= peasycap->video_isoc_maxframesize) {
+ SAM("ERROR: bad video_isoc_maxframesize\n");
+ SAM(" possibly because port is USB 1.1\n");
+ return -ENOENT;
+ }
+ peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
+ JOM(4, "%i=video_isoc_framesperdesc\n", \
+ peasycap->video_isoc_framesperdesc);
+ if (0 >= peasycap->video_isoc_framesperdesc) {
+ SAM("ERROR: bad video_isoc_framesperdesc\n");
+ return -ENOENT;
+ }
+ peasycap->video_isoc_buffer_size = \
+ peasycap->video_isoc_maxframesize * \
+ peasycap->video_isoc_framesperdesc;
+ JOM(4, "%i=video_isoc_buffer_size\n", \
+ peasycap->video_isoc_buffer_size);
+ if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \
+ peasycap->video_isoc_buffer_size) {
+ SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
+ return -EFAULT;
}
/*---------------------------------------------------------------------------*/
if (-1 == peasycap->video_interface) {
- SAY("MISTAKE: video_interface is unset\n");
+ SAM("MISTAKE: video_interface is unset\n");
return -EFAULT;
}
if (-1 == peasycap->video_altsetting_on) {
- SAY("MISTAKE: video_altsetting_on is unset\n");
+ SAM("MISTAKE: video_altsetting_on is unset\n");
return -EFAULT;
}
if (-1 == peasycap->video_altsetting_off) {
- SAY("MISTAKE: video_interface_off is unset\n");
+ SAM("MISTAKE: video_interface_off is unset\n");
return -EFAULT;
}
if (-1 == peasycap->video_endpointnumber) {
- SAY("MISTAKE: video_endpointnumber is unset\n");
+ SAM("MISTAKE: video_endpointnumber is unset\n");
return -EFAULT;
}
if (-1 == peasycap->video_isoc_maxframesize) {
- SAY("MISTAKE: video_isoc_maxframesize is unset\n");
+ SAM("MISTAKE: video_isoc_maxframesize is unset\n");
return -EFAULT;
}
if (-1 == peasycap->video_isoc_buffer_size) {
- SAY("MISTAKE: video_isoc_buffer_size is unset\n");
+ SAM("MISTAKE: video_isoc_buffer_size is unset\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
@@ -3588,20 +4157,20 @@ case 0: {
INIT_LIST_HEAD(&(peasycap->urb_video_head));
peasycap->purb_video_head = &(peasycap->urb_video_head);
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i frame buffers of size %li\n", \
+ JOM(4, "allocating %i frame buffers of size %li\n", \
FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
- JOT(4, ".... each scattered over %li pages\n", \
+ JOM(4, ".... each scattered over %li pages\n", \
FRAME_BUFFER_SIZE/PAGE_SIZE);
for (k = 0; k < FRAME_BUFFER_MANY; k++) {
for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
if ((void *)NULL != peasycap->frame_buffer[k][m].pgo)
- SAY("attempting to reallocate frame " \
+ SAM("attempting to reallocate frame " \
" buffers\n");
else {
pbuf = (void *)__get_free_page(GFP_KERNEL);
if ((void *)NULL == pbuf) {
- SAY("ERROR: Could not allocate frame "\
+ SAM("ERROR: Could not allocate frame "\
"buffer %i page %i\n", k, m);
return -ENOMEM;
} else
@@ -3615,23 +4184,23 @@ case 0: {
peasycap->frame_fill = 0;
peasycap->frame_read = 0;
- JOT(4, "allocation of frame buffers done: %i pages\n", k * \
+ JOM(4, "allocation of frame buffers done: %i pages\n", k * \
m);
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i field buffers of size %li\n", \
+ JOM(4, "allocating %i field buffers of size %li\n", \
FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
- JOT(4, ".... each scattered over %li pages\n", \
+ JOM(4, ".... each scattered over %li pages\n", \
FIELD_BUFFER_SIZE/PAGE_SIZE);
for (k = 0; k < FIELD_BUFFER_MANY; k++) {
for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
- SAY("ERROR: attempting to reallocate " \
+ SAM("ERROR: attempting to reallocate " \
"field buffers\n");
} else {
pbuf = (void *) __get_free_page(GFP_KERNEL);
if ((void *)NULL == pbuf) {
- SAY("ERROR: Could not allocate field" \
+ SAM("ERROR: Could not allocate field" \
" buffer %i page %i\n", k, m);
return -ENOMEM;
}
@@ -3647,18 +4216,18 @@ case 0: {
peasycap->field_fill = 0;
peasycap->field_page = 0;
peasycap->field_read = 0;
- JOT(4, "allocation of field buffers done: %i pages\n", k * \
+ JOM(4, "allocation of field buffers done: %i pages\n", k * \
m);
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i isoc video buffers of size %i\n", \
+ JOM(4, "allocating %i isoc video buffers of size %i\n", \
VIDEO_ISOC_BUFFER_MANY, \
peasycap->video_isoc_buffer_size);
- JOT(4, ".... each occupying contiguous memory pages\n");
+ JOM(4, ".... each occupying contiguous memory pages\n");
for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
pbuf = (void *)__get_free_pages(GFP_KERNEL, VIDEO_ISOC_ORDER);
if (NULL == pbuf) {
- SAY("ERROR: Could not allocate isoc video buffer " \
+ SAM("ERROR: Could not allocate isoc video buffer " \
"%i\n", k);
return -ENOMEM;
} else
@@ -3670,26 +4239,26 @@ case 0: {
peasycap->video_isoc_buffer_size;
peasycap->video_isoc_buffer[k].kount = k;
}
- JOT(4, "allocation of isoc video buffers done: %i pages\n", \
+ JOM(4, "allocation of isoc video buffers done: %i pages\n", \
k * (0x01 << VIDEO_ISOC_ORDER));
/*---------------------------------------------------------------------------*/
/*
* ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
*/
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
- JOT(4, "using %i=peasycap->video_isoc_framesperdesc\n", \
+ JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n", \
peasycap->video_isoc_framesperdesc);
- JOT(4, "using %i=peasycap->video_isoc_maxframesize\n", \
+ JOM(4, "using %i=peasycap->video_isoc_maxframesize\n", \
peasycap->video_isoc_maxframesize);
- JOT(4, "using %i=peasycap->video_isoc_buffer_sizen", \
+ JOM(4, "using %i=peasycap->video_isoc_buffer_sizen", \
peasycap->video_isoc_buffer_size);
for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, \
GFP_KERNEL);
if (NULL == purb) {
- SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer " \
"%i\n", k);
return -ENOMEM;
} else
@@ -3697,7 +4266,7 @@ case 0: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
if (NULL == pdata_urb) {
- SAY("ERROR: Could not allocate struct data_urb.\n");
+ SAM("ERROR: Could not allocate struct data_urb.\n");
return -ENOMEM;
} else
peasycap->allocation_video_struct += \
@@ -3714,30 +4283,30 @@ case 0: {
*/
/*---------------------------------------------------------------------------*/
if (!k) {
- JOT(4, "initializing video urbs thus:\n");
- JOT(4, " purb->interval = 1;\n");
- JOT(4, " purb->dev = peasycap->pusb_device;\n");
- JOT(4, " purb->pipe = usb_rcvisocpipe" \
+ JOM(4, "initializing video urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe" \
"(peasycap->pusb_device,%i);\n", \
peasycap->video_endpointnumber);
- JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOT(4, " purb->transfer_buffer = peasycap->" \
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = peasycap->" \
"video_isoc_buffer[.].pgo;\n");
- JOT(4, " purb->transfer_buffer_length = %i;\n", \
+ JOM(4, " purb->transfer_buffer_length = %i;\n", \
peasycap->video_isoc_buffer_size);
- JOT(4, " purb->complete = easycap_complete;\n");
- JOT(4, " purb->context = peasycap;\n");
- JOT(4, " purb->start_frame = 0;\n");
- JOT(4, " purb->number_of_packets = %i;\n", \
+ JOM(4, " purb->complete = easycap_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n", \
peasycap->video_isoc_framesperdesc);
- JOT(4, " for (j = 0; j < %i; j++)\n", \
+ JOM(4, " for (j = 0; j < %i; j++)\n", \
peasycap->video_isoc_framesperdesc);
- JOT(4, " {\n");
- JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
peasycap->video_isoc_maxframesize);
- JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n", \
peasycap->video_isoc_maxframesize);
- JOT(4, " }\n");
+ JOM(4, " }\n");
}
purb->interval = 1;
@@ -3759,13 +4328,33 @@ case 0: {
peasycap->video_isoc_maxframesize;
}
}
- JOT(4, "allocation of %i struct urb done.\n", k);
+ JOM(4, "allocation of %i struct urb done.\n", k);
/*--------------------------------------------------------------------------*/
/*
* SAVE POINTER peasycap IN THIS INTERFACE.
*/
/*--------------------------------------------------------------------------*/
usb_set_intfdata(pusb_interface, peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ * IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
+ * THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
+ * CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
+ * BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
+#if defined(PREFER_NTSC)
+ peasycap->ntsc = true;
+ JOM(8, "defaulting initially to NTSC\n");
+#else
+ peasycap->ntsc = false;
+ JOM(8, "defaulting initially to PAL\n");
+#endif /*PREFER_NTSC*/
+ rc = reset(peasycap);
+ if (0 != rc) {
+ SAM("ERROR: reset() returned %i\n", rc);
+ return -EFAULT;
+ }
/*--------------------------------------------------------------------------*/
/*
* THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
@@ -3776,48 +4365,58 @@ case 0: {
err("Not able to get a minor for this device");
usb_set_intfdata(pusb_interface, NULL);
return -ENODEV;
- } else
+ } else {
(peasycap->registered_video)++;
- SAY("easycap attached to minor #%d\n", pusb_interface->minor);
- break;
-/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-#else
- pvideo_device = (struct video_device *)\
- kzalloc(sizeof(struct video_device), GFP_KERNEL);
- if ((struct video_device *)NULL == pvideo_device) {
- SAY("ERROR: Could not allocate structure video_device\n");
- return -ENOMEM;
+ SAM("easycap attached to minor #%d\n", pusb_interface->minor);
+ break;
}
- if (VIDEO_DEVICE_MANY <= video_device_many) {
- SAY("ERROR: Too many /dev/videos\n");
- return -ENOMEM;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+ if (0 != (v4l2_device_register(&(pusb_interface->dev), \
+ &(peasycap->v4l2_device)))) {
+ SAM("v4l2_device_register() failed\n");
+ return -ENODEV;
+ } else {
+ JOM(4, "registered device instance: %s\n", \
+ &(peasycap->v4l2_device.name[0]));
}
- pvideo_array[video_device_many] = pvideo_device; video_device_many++;
+/*---------------------------------------------------------------------------*/
+/*
+ * FIXME
+ *
+ *
+ * THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
+*/
+/*---------------------------------------------------------------------------*/
+ peasycap->video_device.v4l2_dev = (struct v4l2_device *)NULL;
+/*---------------------------------------------------------------------------*/
+
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
- strcpy(&pvideo_device->name[0], "easycapdc60");
+ strcpy(&peasycap->video_device.name[0], "easycapdc60");
#if defined(EASYCAP_NEEDS_V4L2_FOPS)
- pvideo_device->fops = &v4l2_fops;
+ peasycap->video_device.fops = &v4l2_fops;
#else
- pvideo_device->fops = &easycap_fops;
+ peasycap->video_device.fops = &easycap_fops;
#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
- pvideo_device->minor = -1;
- pvideo_device->release = (void *)(&videodev_release);
+ peasycap->video_device.minor = -1;
+ peasycap->video_device.release = (void *)(&videodev_release);
- video_set_drvdata(pvideo_device, (void *)peasycap);
+ video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
- rc = video_register_device(pvideo_device, VFL_TYPE_GRABBER, -1);
- if (0 != rc) {
+ if (0 != (video_register_device(&(peasycap->video_device), \
+ VFL_TYPE_GRABBER, -1))) {
err("Not able to register with videodev");
- videodev_release(pvideo_device);
+ videodev_release(&(peasycap->video_device));
return -ENODEV;
} else {
- peasycap->pvideo_device = pvideo_device;
(peasycap->registered_video)++;
- JOT(4, "registered with videodev: %i=minor\n", \
- pvideo_device->minor);
+ SAM("registered with videodev: %i=minor\n", \
+ peasycap->video_device.minor);
}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
break;
}
/*--------------------------------------------------------------------------*/
@@ -3827,125 +4426,118 @@ case 0: {
*/
/*--------------------------------------------------------------------------*/
case 1: {
+ if (!peasycap) {
+ SAM("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+ }
/*--------------------------------------------------------------------------*/
/*
* SAVE POINTER peasycap IN INTERFACE 1
*/
/*--------------------------------------------------------------------------*/
usb_set_intfdata(pusb_interface, peasycap);
- JOT(4, "no initialization required for interface %i\n", \
+ JOM(4, "no initialization required for interface %i\n", \
pusb_interface_descriptor->bInterfaceNumber);
break;
}
/*--------------------------------------------------------------------------*/
case 2: {
if (!peasycap) {
- SAY("MISTAKE: peasycap is NULL\n");
+ SAM("MISTAKE: peasycap is NULL\n");
return -EFAULT;
}
if (!isokalt) {
- SAY("ERROR: no viable audio_altsetting_on\n");
+ SAM("ERROR: no viable audio_altsetting_on\n");
return -ENOENT;
} else {
peasycap->audio_altsetting_on = okalt[isokalt - 1];
- JOT(4, "%i=audio_altsetting_on <====\n", \
+ JOM(4, "%i=audio_altsetting_on <====\n", \
peasycap->audio_altsetting_on);
}
- if (!isokepn) {
- SAY("ERROR: no viable audio_endpointnumber\n");
+
+ peasycap->audio_endpointnumber = okepn[isokalt - 1];
+ JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
+
+ peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
+ JOM(4, "%i=audio_isoc_maxframesize\n", \
+ peasycap->audio_isoc_maxframesize);
+ if (0 >= peasycap->audio_isoc_maxframesize) {
+ SAM("ERROR: bad audio_isoc_maxframesize\n");
return -ENOENT;
- } else {
- peasycap->audio_endpointnumber = okepn[isokepn - 1];
- JOT(4, "%i=audio_endpointnumber\n", \
- peasycap->audio_endpointnumber);
}
- if (!isokmps) {
- SAY("ERROR: no viable audio_maxpacketsize\n");
- return -ENOENT;
+ if (9 == peasycap->audio_isoc_maxframesize) {
+ peasycap->ilk |= 0x02;
+ SAM("hardware is FOUR-CVBS\n");
+ peasycap->microphone = true;
+ peasycap->audio_pages_per_fragment = 4;
+ } else if (256 == peasycap->audio_isoc_maxframesize) {
+ peasycap->ilk &= ~0x02;
+ SAM("hardware is CVBS+S-VIDEO\n");
+ peasycap->microphone = false;
+ peasycap->audio_pages_per_fragment = 4;
} else {
- peasycap->audio_isoc_maxframesize = okmps[isokmps - 1];
- JOT(4, "%i=audio_isoc_maxframesize\n", \
- peasycap->audio_isoc_maxframesize);
- if (0 >= peasycap->audio_isoc_maxframesize) {
- SAY("ERROR: bad audio_isoc_maxframesize\n");
- return -ENOENT;
- }
- if (9 == peasycap->audio_isoc_maxframesize) {
- peasycap->ilk |= 0x02;
- SAY("hardware is FOUR-CVBS\n");
- peasycap->microphone = true;
- peasycap->audio_pages_per_fragment = 4;
- } else if (256 == peasycap->audio_isoc_maxframesize) {
- peasycap->ilk &= ~0x02;
- SAY("hardware is CVBS+S-VIDEO\n");
- peasycap->microphone = false;
- peasycap->audio_pages_per_fragment = 4;
- } else {
- SAY("hardware is unidentified:\n");
- SAY("%i=audio_isoc_maxframesize\n", \
+ SAM("hardware is unidentified:\n");
+ SAM("%i=audio_isoc_maxframesize\n", \
peasycap->audio_isoc_maxframesize);
- return -ENOENT;
- }
+ return -ENOENT;
+ }
- peasycap->audio_bytes_per_fragment = \
+ peasycap->audio_bytes_per_fragment = \
peasycap->audio_pages_per_fragment * \
PAGE_SIZE ;
- peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \
+ peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \
peasycap->audio_pages_per_fragment);
- JOT(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
- JOT(4, "%6i=audio_pages_per_fragment\n", \
+ JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
+ JOM(4, "%6i=audio_pages_per_fragment\n", \
peasycap->audio_pages_per_fragment);
- JOT(4, "%6i=audio_bytes_per_fragment\n", \
+ JOM(4, "%6i=audio_bytes_per_fragment\n", \
peasycap->audio_bytes_per_fragment);
- JOT(4, "%6i=audio_buffer_page_many\n", \
+ JOM(4, "%6i=audio_buffer_page_many\n", \
peasycap->audio_buffer_page_many);
- peasycap->audio_isoc_framesperdesc = 128;
+ peasycap->audio_isoc_framesperdesc = 128;
- JOT(4, "%i=audio_isoc_framesperdesc\n", \
+ JOM(4, "%i=audio_isoc_framesperdesc\n", \
peasycap->audio_isoc_framesperdesc);
- if (0 >= peasycap->audio_isoc_framesperdesc) {
- SAY("ERROR: bad audio_isoc_framesperdesc\n");
- return -ENOENT;
- }
+ if (0 >= peasycap->audio_isoc_framesperdesc) {
+ SAM("ERROR: bad audio_isoc_framesperdesc\n");
+ return -ENOENT;
+ }
- peasycap->audio_isoc_buffer_size = \
+ peasycap->audio_isoc_buffer_size = \
peasycap->audio_isoc_maxframesize * \
peasycap->audio_isoc_framesperdesc;
- JOT(4, "%i=audio_isoc_buffer_size\n", \
+ JOM(4, "%i=audio_isoc_buffer_size\n", \
peasycap->audio_isoc_buffer_size);
- if (AUDIO_ISOC_BUFFER_SIZE < \
- peasycap->audio_isoc_buffer_size) {
- SAY("MISTAKE: audio_isoc_buffer_size bigger "
+ if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
+ SAM("MISTAKE: audio_isoc_buffer_size bigger "
"than %li=AUDIO_ISOC_BUFFER_SIZE\n", \
AUDIO_ISOC_BUFFER_SIZE);
- return -EFAULT;
- }
+ return -EFAULT;
}
-
if (-1 == peasycap->audio_interface) {
- SAY("MISTAKE: audio_interface is unset\n");
+ SAM("MISTAKE: audio_interface is unset\n");
return -EFAULT;
}
if (-1 == peasycap->audio_altsetting_on) {
- SAY("MISTAKE: audio_altsetting_on is unset\n");
+ SAM("MISTAKE: audio_altsetting_on is unset\n");
return -EFAULT;
}
if (-1 == peasycap->audio_altsetting_off) {
- SAY("MISTAKE: audio_interface_off is unset\n");
+ SAM("MISTAKE: audio_interface_off is unset\n");
return -EFAULT;
}
if (-1 == peasycap->audio_endpointnumber) {
- SAY("MISTAKE: audio_endpointnumber is unset\n");
+ SAM("MISTAKE: audio_endpointnumber is unset\n");
return -EFAULT;
}
if (-1 == peasycap->audio_isoc_maxframesize) {
- SAY("MISTAKE: audio_isoc_maxframesize is unset\n");
+ SAM("MISTAKE: audio_isoc_maxframesize is unset\n");
return -EFAULT;
}
if (-1 == peasycap->audio_isoc_buffer_size) {
- SAY("MISTAKE: audio_isoc_buffer_size is unset\n");
+ SAM("MISTAKE: audio_isoc_buffer_size is unset\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
@@ -3956,17 +4548,17 @@ case 2: {
INIT_LIST_HEAD(&(peasycap->urb_audio_head));
peasycap->purb_audio_head = &(peasycap->urb_audio_head);
- JOT(4, "allocating an audio buffer\n");
- JOT(4, ".... scattered over %i pages\n", \
+ JOM(4, "allocating an audio buffer\n");
+ JOM(4, ".... scattered over %i pages\n", \
peasycap->audio_buffer_page_many);
for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
- SAY("ERROR: attempting to reallocate audio buffers\n");
+ SAM("ERROR: attempting to reallocate audio buffers\n");
} else {
pbuf = (void *) __get_free_page(GFP_KERNEL);
if ((void *)NULL == pbuf) {
- SAY("ERROR: Could not allocate audio " \
+ SAM("ERROR: Could not allocate audio " \
"buffer page %i\n", k);
return -ENOMEM;
} else
@@ -3979,16 +4571,16 @@ case 2: {
peasycap->audio_fill = 0;
peasycap->audio_read = 0;
- JOT(4, "allocation of audio buffer done: %i pages\n", k);
+ JOM(4, "allocation of audio buffer done: %i pages\n", k);
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i isoc audio buffers of size %i\n", \
+ JOM(4, "allocating %i isoc audio buffers of size %i\n", \
AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);
- JOT(4, ".... each occupying contiguous memory pages\n");
+ JOM(4, ".... each occupying contiguous memory pages\n");
for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
if (NULL == pbuf) {
- SAY("ERROR: Could not allocate isoc audio buffer " \
+ SAM("ERROR: Could not allocate isoc audio buffer " \
"%i\n", k);
return -ENOMEM;
} else
@@ -4000,25 +4592,25 @@ case 2: {
peasycap->audio_isoc_buffer_size;
peasycap->audio_isoc_buffer[k].kount = k;
}
- JOT(4, "allocation of isoc audio buffers done.\n");
+ JOM(4, "allocation of isoc audio buffers done.\n");
/*---------------------------------------------------------------------------*/
/*
* ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
*/
/*---------------------------------------------------------------------------*/
- JOT(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
- JOT(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \
+ JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \
peasycap->audio_isoc_framesperdesc);
- JOT(4, "using %i=peasycap->audio_isoc_maxframesize\n", \
+ JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n", \
peasycap->audio_isoc_maxframesize);
- JOT(4, "using %i=peasycap->audio_isoc_buffer_size\n", \
+ JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n", \
peasycap->audio_isoc_buffer_size);
for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, \
GFP_KERNEL);
if (NULL == purb) {
- SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer " \
"%i\n", k);
return -ENOMEM;
} else
@@ -4026,7 +4618,7 @@ case 2: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
if (NULL == pdata_urb) {
- SAY("ERROR: Could not allocate struct data_urb.\n");
+ SAM("ERROR: Could not allocate struct data_urb.\n");
return -ENOMEM;
} else
peasycap->allocation_audio_struct += \
@@ -4043,30 +4635,30 @@ case 2: {
*/
/*---------------------------------------------------------------------------*/
if (!k) {
- JOT(4, "initializing audio urbs thus:\n");
- JOT(4, " purb->interval = 1;\n");
- JOT(4, " purb->dev = peasycap->pusb_device;\n");
- JOT(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \
+ JOM(4, "initializing audio urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \
"pusb_device,%i);\n", \
peasycap->audio_endpointnumber);
- JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOT(4, " purb->transfer_buffer = " \
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = " \
"peasycap->audio_isoc_buffer[.].pgo;\n");
- JOT(4, " purb->transfer_buffer_length = %i;\n", \
+ JOM(4, " purb->transfer_buffer_length = %i;\n", \
peasycap->audio_isoc_buffer_size);
- JOT(4, " purb->complete = easysnd_complete;\n");
- JOT(4, " purb->context = peasycap;\n");
- JOT(4, " purb->start_frame = 0;\n");
- JOT(4, " purb->number_of_packets = %i;\n", \
+ JOM(4, " purb->complete = easysnd_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n", \
peasycap->audio_isoc_framesperdesc);
- JOT(4, " for (j = 0; j < %i; j++)\n", \
+ JOM(4, " for (j = 0; j < %i; j++)\n", \
peasycap->audio_isoc_framesperdesc);
- JOT(4, " {\n");
- JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
peasycap->audio_isoc_maxframesize);
- JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n", \
peasycap->audio_isoc_maxframesize);
- JOT(4, " }\n");
+ JOM(4, " }\n");
}
purb->interval = 1;
@@ -4088,7 +4680,7 @@ case 2: {
peasycap->audio_isoc_maxframesize;
}
}
- JOT(4, "allocation of %i struct urb done.\n", k);
+ JOM(4, "allocation of %i struct urb done.\n", k);
/*---------------------------------------------------------------------------*/
/*
* SAVE POINTER peasycap IN THIS INTERFACE.
@@ -4105,14 +4697,18 @@ case 2: {
err("Not able to get a minor for this device.");
usb_set_intfdata(pusb_interface, NULL);
return -ENODEV;
- } else
+ } else {
+ JOM(8, "kref_get() with %i=peasycap->kref.refcount.counter\n",\
+ (int)peasycap->kref.refcount.counter);
+ kref_get(&peasycap->kref);
(peasycap->registered_audio)++;
+ }
/*---------------------------------------------------------------------------*/
/*
* LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO.
*/
/*---------------------------------------------------------------------------*/
- SAY("easysnd attached to minor #%d\n", pusb_interface->minor);
+ SAM("easysnd attached to minor #%d\n", pusb_interface->minor);
break;
}
/*---------------------------------------------------------------------------*/
@@ -4121,20 +4717,19 @@ case 2: {
*/
/*---------------------------------------------------------------------------*/
default: {
- JOT(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
+ JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
return -EINVAL;
}
}
-JOT(4, "ends successfully for interface %i\n", \
+JOM(4, "ends successfully for interface %i\n", \
pusb_interface_descriptor->bInterfaceNumber);
return 0;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
- * WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY
- * UNPLUGGED.
- * HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.
+ * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
+ * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
*/
/*---------------------------------------------------------------------------*/
void
@@ -4147,7 +4742,14 @@ struct easycap *peasycap;
struct list_head *plist_head;
struct data_urb *pdata_urb;
-int minor, m;
+int minor, m, kd;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+struct v4l2_device *pv4l2_device;
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
JOT(4, "\n");
@@ -4169,107 +4771,188 @@ bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
minor = pusb_interface->minor;
JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+if (1 == bInterfaceNumber)
+ return;
+
peasycap = usb_get_intfdata(pusb_interface);
-if ((struct easycap *)NULL == peasycap)
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
-else {
- peasycap->pusb_device = (struct usb_device *)NULL;
- switch (bInterfaceNumber) {
-/*---------------------------------------------------------------------------*/
- case 0: {
- if ((struct list_head *)NULL != peasycap->purb_video_head) {
- JOT(4, "killing video urbs\n");
- m = 0;
- list_for_each(plist_head, (peasycap->purb_video_head))
- {
- pdata_urb = list_entry(plist_head, \
- struct data_urb, list_head);
- if ((struct data_urb *)NULL != pdata_urb) {
- if ((struct urb *)NULL != \
- pdata_urb->purb) {
- usb_kill_urb(pdata_urb->purb);
- m++;
- }
+ return;
+}
+/*---------------------------------------------------------------------------*/
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+#
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+/*---------------------------------------------------------------------------*/
+/*
+ * SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
+ * BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
+ * REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
+ * TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
+*/
+/*---------------------------------------------------------------------------*/
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ pv4l2_device = usb_get_intfdata(pusb_interface);
+ if ((struct v4l2_device *)NULL == pv4l2_device) {
+ SAY("ERROR: pv4l2_device is NULL\n");
+ return;
+ }
+ peasycap = (struct easycap *) \
+ container_of(pv4l2_device, struct easycap, v4l2_device);
+}
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
+peasycap->video_eof = 1;
+peasycap->audio_eof = 1;
+wake_up_interruptible(&(peasycap->wq_video));
+wake_up_interruptible(&(peasycap->wq_audio));
+/*---------------------------------------------------------------------------*/
+switch (bInterfaceNumber) {
+case 0: {
+ if ((struct list_head *)NULL != peasycap->purb_video_head) {
+ JOM(4, "killing video urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_video_head))
+ {
+ pdata_urb = list_entry(plist_head, \
+ struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != \
+ pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
}
}
- JOT(4, "%i video urbs killed\n", m);
- } else
- SAY("ERROR: peasycap->purb_video_head is NULL\n");
- break;
+ }
+ JOM(4, "%i video urbs killed\n", m);
}
+ break;
+}
/*---------------------------------------------------------------------------*/
- case 2: {
- if ((struct list_head *)NULL != peasycap->purb_audio_head) {
- JOT(4, "killing audio urbs\n");
- m = 0;
- list_for_each(plist_head, \
- (peasycap->purb_audio_head)) {
- pdata_urb = list_entry(plist_head, \
- struct data_urb, list_head);
- if ((struct data_urb *)NULL != pdata_urb) {
- if ((struct urb *)NULL != \
- pdata_urb->purb) {
- usb_kill_urb(pdata_urb->purb);
- m++;
- }
+case 2: {
+ if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+ JOM(4, "killing audio urbs\n");
+ m = 0;
+ list_for_each(plist_head, \
+ (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, \
+ struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != \
+ pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
}
}
- JOT(4, "%i audio urbs killed\n", m);
- } else
- SAY("ERROR: peasycap->purb_audio_head is NULL\n");
- break;
+ }
+ JOM(4, "%i audio urbs killed\n", m);
}
+ break;
+}
/*---------------------------------------------------------------------------*/
- default:
- break;
- }
+default:
+ break;
}
/*--------------------------------------------------------------------------*/
/*
* DEREGISTER
+ *
+ * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
+ * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
+ * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
*/
/*--------------------------------------------------------------------------*/
+kd = isdongle(peasycap);
switch (bInterfaceNumber) {
case 0: {
+ if (0 <= kd && DONGLE_MANY > kd) {
+ wake_up_interruptible(&peasycap->wq_video);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].\
+ mutex_video)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i]." \
+ "mutex_video\n", kd);
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ } else
+ SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
+/*---------------------------------------------------------------------------*/
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
if ((struct easycap *)NULL == peasycap) {
- SAY("ERROR: peasycap has become NULL\n");
+ SAM("ERROR: peasycap has become NULL\n");
} else {
- lock_kernel();
usb_deregister_dev(pusb_interface, &easycap_class);
(peasycap->registered_video)--;
-
- JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
- unlock_kernel();
- SAY("easycap detached from minor #%d\n", minor);
+ JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+ SAM("easycap detached from minor #%d\n", minor);
}
-/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#else
- if ((struct easycap *)NULL == peasycap)
- SAY("ERROR: peasycap has become NULL\n");
- else {
- lock_kernel();
- video_unregister_device(peasycap->pvideo_device);
- (peasycap->registered_video)--;
- unlock_kernel();
- JOT(4, "unregistered with videodev: %i=minor\n", \
- pvideo_device->minor);
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+ if (!peasycap->v4l2_device.name[0]) {
+ SAM("ERROR: peasycap->v4l2_device.name is empty\n");
+ if (0 <= kd && DONGLE_MANY > kd)
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return;
}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+ v4l2_device_disconnect(&peasycap->v4l2_device);
+ JOM(4, "v4l2_device_disconnect() OK\n");
+ v4l2_device_unregister(&peasycap->v4l2_device);
+ JOM(4, "v4l2_device_unregister() OK\n");
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+
+ video_unregister_device(&peasycap->video_device);
+ JOM(4, "intf[%i]: video_unregister_device() OK\n", bInterfaceNumber);
+ (peasycap->registered_video)--;
+ JOM(4, "unregistered with videodev: %i=minor\n", minor);
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+ if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+ }
break;
}
case 2: {
- lock_kernel();
+ if (0 <= kd && DONGLE_MANY > kd) {
+ wake_up_interruptible(&peasycap->wq_audio);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].\
+ mutex_audio)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i]." \
+ "mutex_audio\n", kd);
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+ } else
+ SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
usb_deregister_dev(pusb_interface, &easysnd_class);
- if ((struct easycap *)NULL != peasycap)
- (peasycap->registered_audio)--;
+ (peasycap->registered_audio)--;
- JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
- unlock_kernel();
+ JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+ SAM("easysnd detached from minor #%d\n", minor);
- SAY("easysnd detached from minor #%d\n", minor);
+ if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ JOM(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
+ }
break;
}
default:
@@ -4280,25 +4963,42 @@ default:
* CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
*/
/*---------------------------------------------------------------------------*/
-if ((struct easycap *)NULL == peasycap) {
- SAY("ERROR: peasycap has become NULL\n");
- SAY("cannot call kref_put()\n");
- SAY("ending unsuccessfully: may cause memory leak\n");
- return;
-}
if (!peasycap->kref.refcount.counter) {
- SAY("ERROR: peasycap->kref.refcount.counter is zero " \
+ SAM("ERROR: peasycap->kref.refcount.counter is zero "
"so cannot call kref_put()\n");
- SAY("ending unsuccessfully: may cause memory leak\n");
+ SAM("ending unsuccessfully: may cause memory leak\n");
return;
}
-JOT(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \
+if (0 <= kd && DONGLE_MANY > kd) {
+ JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
+ SAM("ending unsuccessfully: may cause memory leak\n");
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_audio\n", kd);
+ mutex_unlock(&(easycap_dongle[kd].mutex_video));
+ JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+ SAM("ending unsuccessfully: may cause memory leak\n");
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+}
+JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", \
bInterfaceNumber, (int)peasycap->kref.refcount.counter);
kref_put(&peasycap->kref, easycap_delete);
JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
+if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&(easycap_dongle[kd].mutex_audio));
+ JOT(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ JOT(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+}
/*---------------------------------------------------------------------------*/
-
-JOT(4, "ends\n");
+JOM(4, "ends\n");
return;
}
/*****************************************************************************/
@@ -4308,7 +5008,8 @@ easycap_module_init(void)
int result;
SAY("========easycap=======\n");
-JOT(4, "begins. %i=debug\n", easycap_debug);
+JOT(4, "begins. %i=debug %i=bars %i=gain\n", easycap_debug, easycap_bars, \
+ easycap_gain);
SAY("version: " EASYCAP_DRIVER_VERSION "\n");
/*---------------------------------------------------------------------------*/
/*
@@ -4349,6 +5050,9 @@ MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
MODULE_VERSION(EASYCAP_DRIVER_VERSION);
#if defined(EASYCAP_DEBUG)
-MODULE_PARM_DESC(easycap_debug, "debug: 0 (default), 1, 2,...");
+MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
#endif /*EASYCAP_DEBUG*/
+MODULE_PARM_DESC(bars, \
+ "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
+MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c
index 38d94051241d..df3f17d361b1 100644
--- a/drivers/staging/easycap/easycap_settings.c
+++ b/drivers/staging/easycap/easycap_settings.c
@@ -33,11 +33,15 @@
* THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
* 0 => 25 fps
* 1 => 30 fps
+ *
+ * THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
+ * 0 => full framerate
+ * 1 => 20% framerate
*/
/*---------------------------------------------------------------------------*/
const struct easycap_standard easycap_standard[] = {
{
-.mask = 0x000F & PAL_BGHIN ,
+.mask = 0x00FF & PAL_BGHIN ,
.v4l2_standard = {
.index = PAL_BGHIN,
.id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
@@ -50,7 +54,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & NTSC_N_443 ,
+.mask = 0x00FF & NTSC_N_443 ,
.v4l2_standard = {
.index = NTSC_N_443,
.id = V4L2_STD_UNKNOWN,
@@ -62,7 +66,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & PAL_Nc ,
+.mask = 0x00FF & PAL_Nc ,
.v4l2_standard = {
.index = PAL_Nc,
.id = V4L2_STD_PAL_Nc,
@@ -74,7 +78,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & NTSC_N ,
+.mask = 0x00FF & NTSC_N ,
.v4l2_standard = {
.index = NTSC_N,
.id = V4L2_STD_UNKNOWN,
@@ -86,7 +90,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & SECAM ,
+.mask = 0x00FF & SECAM ,
.v4l2_standard = {
.index = SECAM,
.id = V4L2_STD_SECAM,
@@ -98,7 +102,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & NTSC_M ,
+.mask = 0x00FF & NTSC_M ,
.v4l2_standard = {
.index = NTSC_M,
.id = V4L2_STD_NTSC_M,
@@ -110,7 +114,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & NTSC_M_JP ,
+.mask = 0x00FF & NTSC_M_JP ,
.v4l2_standard = {
.index = NTSC_M_JP,
.id = V4L2_STD_NTSC_M_JP,
@@ -122,7 +126,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & PAL_60 ,
+.mask = 0x00FF & PAL_60 ,
.v4l2_standard = {
.index = PAL_60,
.id = V4L2_STD_PAL_60,
@@ -134,7 +138,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & NTSC_443 ,
+.mask = 0x00FF & NTSC_443 ,
.v4l2_standard = {
.index = NTSC_443,
.id = V4L2_STD_NTSC_443,
@@ -146,7 +150,7 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
-.mask = 0x000F & PAL_M ,
+.mask = 0x00FF & PAL_M ,
.v4l2_standard = {
.index = PAL_M,
.id = V4L2_STD_PAL_M,
@@ -158,6 +162,128 @@ const struct easycap_standard easycap_standard[] = {
},
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
{
+.mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
+.v4l2_standard = {
+ .index = PAL_BGHIN_SLOW,
+ .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
+ V4L2_STD_PAL_I | V4L2_STD_PAL_N | \
+ (((v4l2_std_id)0x01) << 32)),
+ .name = "PAL_BGHIN_SLOW",
+ .frameperiod = {1, 5},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
+.v4l2_standard = {
+ .index = NTSC_N_443_SLOW,
+ .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
+ .name = "NTSC_N_443_SLOW",
+ .frameperiod = {1, 5},
+ .framelines = 480,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
+.v4l2_standard = {
+ .index = PAL_Nc_SLOW,
+ .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
+ .name = "PAL_Nc_SLOW",
+ .frameperiod = {1, 5},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
+.v4l2_standard = {
+ .index = NTSC_N_SLOW,
+ .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
+ .name = "NTSC_N_SLOW",
+ .frameperiod = {1, 5},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & SECAM_SLOW),
+.v4l2_standard = {
+ .index = SECAM_SLOW,
+ .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
+ .name = "SECAM_SLOW",
+ .frameperiod = {1, 5},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
+.v4l2_standard = {
+ .index = NTSC_M_SLOW,
+ .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
+ .name = "NTSC_M_SLOW",
+ .frameperiod = {1, 6},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
+.v4l2_standard = {
+ .index = NTSC_M_JP_SLOW,
+ .id = (V4L2_STD_NTSC_M_JP | (((v4l2_std_id)0x01) << 32)),
+ .name = "NTSC_M_JP_SLOW",
+ .frameperiod = {1, 6},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & PAL_60_SLOW),
+.v4l2_standard = {
+ .index = PAL_60_SLOW,
+ .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
+ .name = "PAL_60_SLOW",
+ .frameperiod = {1, 6},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
+.v4l2_standard = {
+ .index = NTSC_443_SLOW,
+ .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
+ .name = "NTSC_443_SLOW",
+ .frameperiod = {1, 6},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x8000 | (0x00FF & PAL_M_SLOW),
+.v4l2_standard = {
+ .index = PAL_M_SLOW,
+ .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
+ .name = "PAL_M_SLOW",
+ .frameperiod = {1, 6},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
.mask = 0xFFFF
}
};
@@ -165,15 +291,16 @@ const struct easycap_standard easycap_standard[] = {
/*
* THE 16-BIT easycap_format.mask HAS MEANING:
* (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
- * BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS
- * BITS 4-7: NUMBER OF BYTES PER PIXEL
+ * BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS
+ * BITS 5-7: NUMBER OF BYTES PER PIXEL
* BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED
* BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS
- * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
- * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
- * (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS
+ * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
+ * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
+ * BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED
+ * (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
* IT FOLLOWS THAT:
- * bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4)
+ * bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5)
* byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
*
* decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
@@ -197,65 +324,135 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
mask1 = 0x0000;
switch (i) {
case PAL_BGHIN: {
- mask1 = PAL_BGHIN;
+ mask1 = 0x1F & PAL_BGHIN;
strcpy(&name1[0], "PAL_BGHIN");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case SECAM: {
- mask1 = SECAM;
+ mask1 = 0x1F & SECAM;
strcpy(&name1[0], "SECAM");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_Nc: {
- mask1 = PAL_Nc;
+ mask1 = 0x1F & PAL_Nc;
strcpy(&name1[0], "PAL_Nc");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_60: {
- mask1 = PAL_60;
+ mask1 = 0x1F & PAL_60;
strcpy(&name1[0], "PAL_60");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case PAL_M: {
- mask1 = PAL_M;
+ mask1 = 0x1F & PAL_M;
strcpy(&name1[0], "PAL_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
break;
}
case NTSC_M: {
- mask1 = NTSC_M;
+ mask1 = 0x1F & NTSC_M;
strcpy(&name1[0], "NTSC_M");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_443: {
- mask1 = NTSC_443;
+ mask1 = 0x1F & NTSC_443;
strcpy(&name1[0], "NTSC_443");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_M_JP: {
- mask1 = NTSC_M_JP;
+ mask1 = 0x1F & NTSC_M_JP;
strcpy(&name1[0], "NTSC_M_JP");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N: {
- mask1 = NTSC_M;
+ mask1 = 0x1F & NTSC_M;
strcpy(&name1[0], "NTSC_N");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
case NTSC_N_443: {
- mask1 = NTSC_N_443;
+ mask1 = 0x1F & NTSC_N_443;
strcpy(&name1[0], "NTSC_N_443");
colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
break;
}
+ case PAL_BGHIN_SLOW: {
+ mask1 = 0x001F & PAL_BGHIN_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "PAL_BGHIN_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case SECAM_SLOW: {
+ mask1 = 0x001F & SECAM_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "SECAM_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_Nc_SLOW: {
+ mask1 = 0x001F & PAL_Nc_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "PAL_Nc_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_60_SLOW: {
+ mask1 = 0x001F & PAL_60_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "PAL_60_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_M_SLOW: {
+ mask1 = 0x001F & PAL_M_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "PAL_M_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case NTSC_M_SLOW: {
+ mask1 = 0x001F & NTSC_M_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "NTSC_M_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_443_SLOW: {
+ mask1 = 0x001F & NTSC_443_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "NTSC_443_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_M_JP_SLOW: {
+ mask1 = 0x001F & NTSC_M_JP_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "NTSC_M_JP_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_N_SLOW: {
+ mask1 = 0x001F & NTSC_N_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "NTSC_N_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_N_443_SLOW: {
+ mask1 = 0x001F & NTSC_N_443_SLOW;
+ mask1 |= 0x0200;
+ strcpy(&name1[0], "NTSC_N_443_SLOW");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
default:
return -1;
}
@@ -311,39 +508,39 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
case FMT_UYVY: {
strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY));
pixelformat = V4L2_PIX_FMT_UYVY;
- mask3 |= (0x02 << 4);
+ mask3 |= (0x02 << 5);
break;
}
case FMT_YUY2: {
strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2));
pixelformat = V4L2_PIX_FMT_YUYV;
- mask3 |= (0x02 << 4);
+ mask3 |= (0x02 << 5);
mask3 |= 0x0100;
break;
}
case FMT_RGB24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24));
pixelformat = V4L2_PIX_FMT_RGB24;
- mask3 |= (0x03 << 4);
+ mask3 |= (0x03 << 5);
break;
}
case FMT_RGB32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32));
pixelformat = V4L2_PIX_FMT_RGB32;
- mask3 |= (0x04 << 4);
+ mask3 |= (0x04 << 5);
break;
}
case FMT_BGR24: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24));
pixelformat = V4L2_PIX_FMT_BGR24;
- mask3 |= (0x03 << 4);
+ mask3 |= (0x03 << 5);
mask3 |= 0x0100;
break;
}
case FMT_BGR32: {
strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32));
pixelformat = V4L2_PIX_FMT_BGR32;
- mask3 |= (0x04 << 4);
+ mask3 |= (0x04 << 5);
mask3 |= 0x0100;
break;
}
@@ -363,13 +560,8 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) {
}
case FIELD_INTERLACED: {
strcpy(&name4[0], "-i");
- field = V4L2_FIELD_INTERLACED;
- break;
- }
- case FIELD_ALTERNATE: {
- strcpy(&name4[0], "-a");
mask4 |= 0x1000;
- field = V4L2_FIELD_ALTERNATE;
+ field = V4L2_FIELD_INTERLACED;
break;
}
default:
@@ -413,7 +605,7 @@ return n;
}
/*---------------------------------------------------------------------------*/
struct v4l2_queryctrl easycap_control[] = \
- {{
+{{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
@@ -485,5 +677,5 @@ struct v4l2_queryctrl easycap_control[] = \
{
.id = 0xFFFFFFFF
}
- };
+};
/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c
index 63562bda738e..24d8bb4e449e 100644
--- a/drivers/staging/easycap/easycap_sound.c
+++ b/drivers/staging/easycap/easycap_sound.c
@@ -36,17 +36,15 @@
/*---------------------------------------------------------------------------*/
/*
* ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
- * PROVIDED peasycap->audio_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,
+ * PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
* IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
*/
/*---------------------------------------------------------------------------*/
void
easysnd_complete(struct urb *purb)
{
-static int mt;
struct easycap *peasycap;
struct data_buffer *paudio_buffer;
-char errbuf[16];
__u8 *p1, *p2;
__s16 s16;
int i, j, more, much, leap, rc;
@@ -66,48 +64,62 @@ if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return;
}
-much = 0;
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap\n");
+ return;
+}
+much = 0;
if (peasycap->audio_idle) {
- JOT(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
+ JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
peasycap->audio_idle, peasycap->audio_isoc_streaming);
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
- SAY("ERROR: while %i=audio_idle, " \
+ if (-ENODEV != rc)
+ SAM("ERROR: while %i=audio_idle, " \
"usb_submit_urb() failed with rc:\n", \
peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n"); break;
+ SAM("-ENOMEM\n");
+ break;
}
case -ENODEV: {
- SAY("ENODEV\n"); break;
+ break;
}
case -ENXIO: {
- SAY("ENXIO\n"); break;
+ SAM("-ENXIO\n");
+ break;
}
case -EINVAL: {
- SAY("EINVAL\n"); break;
+ SAM("-EINVAL\n");
+ break;
}
case -EAGAIN: {
- SAY("EAGAIN\n"); break;
+ SAM("-EAGAIN\n");
+ break;
}
case -EFBIG: {
- SAY("EFBIG\n"); break;
+ SAM("-EFBIG\n");
+ break;
}
case -EPIPE: {
- SAY("EPIPE\n"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n");
+ break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("-ENOSPC\n");
+ break;
}
default: {
- SAY("0x%08X\n", rc); break;
+ SAM("unknown error: 0x%08X\n", rc);
+ break;
}
}
}
@@ -116,74 +128,95 @@ return;
}
/*---------------------------------------------------------------------------*/
if (purb->status) {
- if (-ESHUTDOWN == purb->status) {
- JOT(16, "immediate return because -ESHUTDOWN=purb->status\n");
+ if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
+ JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
return;
}
- SAY("ERROR: non-zero urb status:\n");
+ SAM("ERROR: non-zero urb status:\n");
switch (purb->status) {
case -EINPROGRESS: {
- SAY("-EINPROGRESS\n"); break;
+ SAM("-EINPROGRESS\n");
+ break;
}
case -ENOSR: {
- SAY("-ENOSR\n"); break;
+ SAM("-ENOSR\n");
+ break;
}
case -EPIPE: {
- SAY("-EPIPE\n"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -EOVERFLOW: {
- SAY("-EOVERFLOW\n"); break;
+ SAM("-EOVERFLOW\n");
+ break;
}
case -EPROTO: {
- SAY("-EPROTO\n"); break;
+ SAM("-EPROTO\n");
+ break;
}
case -EILSEQ: {
- SAY("-EILSEQ\n"); break;
+ SAM("-EILSEQ\n");
+ break;
}
case -ETIMEDOUT: {
- SAY("-ETIMEDOUT\n"); break;
+ SAM("-ETIMEDOUT\n");
+ break;
}
case -EMSGSIZE: {
- SAY("-EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n");
+ break;
}
case -EOPNOTSUPP: {
- SAY("-EOPNOTSUPP\n"); break;
+ SAM("-EOPNOTSUPP\n");
+ break;
}
case -EPFNOSUPPORT: {
- SAY("-EPFNOSUPPORT\n"); break;
+ SAM("-EPFNOSUPPORT\n");
+ break;
}
case -EAFNOSUPPORT: {
- SAY("-EAFNOSUPPORT\n"); break;
+ SAM("-EAFNOSUPPORT\n");
+ break;
}
case -EADDRINUSE: {
- SAY("-EADDRINUSE\n"); break;
+ SAM("-EADDRINUSE\n");
+ break;
}
case -EADDRNOTAVAIL: {
- SAY("-EADDRNOTAVAIL\n"); break;
+ SAM("-EADDRNOTAVAIL\n");
+ break;
}
case -ENOBUFS: {
- SAY("-ENOBUFS\n"); break;
+ SAM("-ENOBUFS\n");
+ break;
}
case -EISCONN: {
- SAY("-EISCONN\n"); break;
+ SAM("-EISCONN\n");
+ break;
}
case -ENOTCONN: {
- SAY("-ENOTCONN\n"); break;
+ SAM("-ENOTCONN\n");
+ break;
}
case -ESHUTDOWN: {
- SAY("-ESHUTDOWN\n"); break;
+ SAM("-ESHUTDOWN\n");
+ break;
}
case -ENOENT: {
- SAY("-ENOENT\n"); break;
+ SAM("-ENOENT\n");
+ break;
}
case -ECONNRESET: {
- SAY("-ECONNRESET\n"); break;
+ SAM("-ECONNRESET\n");
+ break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("ENOSPC\n");
+ break;
}
default: {
- SAY("unknown error code 0x%08X\n", purb->status); break;
+ SAM("unknown error code 0x%08X\n", purb->status);
+ break;
}
}
/*---------------------------------------------------------------------------*/
@@ -196,35 +229,43 @@ if (purb->status) {
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
- SAY("ERROR: while %i=audio_idle, usb_submit_urb() "
+ SAM("ERROR: while %i=audio_idle, usb_submit_urb() "
"failed with rc:\n", peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n"); break;
+ SAM("-ENOMEM\n");
+ break;
}
case -ENODEV: {
- SAY("ENODEV\n"); break;
+ SAM("-ENODEV\n");
+ break;
}
case -ENXIO: {
- SAY("ENXIO\n"); break;
+ SAM("-ENXIO\n");
+ break;
}
case -EINVAL: {
- SAY("EINVAL\n"); break;
+ SAM("-EINVAL\n");
+ break;
}
case -EAGAIN: {
- SAY("EAGAIN\n"); break;
+ SAM("-EAGAIN\n");
+ break;
}
case -EFBIG: {
- SAY("EFBIG\n"); break;
+ SAM("-EFBIG\n");
+ break;
}
case -EPIPE: {
- SAY("EPIPE\n"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n");
+ break;
}
default: {
- SAY("0x%08X\n", rc); break;
+ SAM("0x%08X\n", rc); break;
}
}
}
@@ -243,72 +284,80 @@ oldaudio = peasycap->oldaudio;
for (i = 0; i < purb->number_of_packets; i++) {
switch (purb->iso_frame_desc[i].status) {
case 0: {
- strcpy(&errbuf[0], "OK"); break;
+ break;
}
case -ENOENT: {
- strcpy(&errbuf[0], "-ENOENT"); break;
+ SAM("-ENOENT\n");
+ break;
}
case -EINPROGRESS: {
- strcpy(&errbuf[0], "-EINPROGRESS"); break;
+ SAM("-EINPROGRESS\n");
+ break;
}
case -EPROTO: {
- strcpy(&errbuf[0], "-EPROTO"); break;
+ SAM("-EPROTO\n");
+ break;
}
case -EILSEQ: {
- strcpy(&errbuf[0], "-EILSEQ"); break;
+ SAM("-EILSEQ\n");
+ break;
}
case -ETIME: {
- strcpy(&errbuf[0], "-ETIME"); break;
+ SAM("-ETIME\n");
+ break;
}
case -ETIMEDOUT: {
- strcpy(&errbuf[0], "-ETIMEDOUT"); break;
+ SAM("-ETIMEDOUT\n");
+ break;
}
case -EPIPE: {
- strcpy(&errbuf[0], "-EPIPE"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -ECOMM: {
- strcpy(&errbuf[0], "-ECOMM"); break;
+ SAM("-ECOMM\n");
+ break;
}
case -ENOSR: {
- strcpy(&errbuf[0], "-ENOSR"); break;
+ SAM("-ENOSR\n");
+ break;
}
case -EOVERFLOW: {
- strcpy(&errbuf[0], "-EOVERFLOW"); break;
+ SAM("-EOVERFLOW\n");
+ break;
}
case -EREMOTEIO: {
- strcpy(&errbuf[0], "-EREMOTEIO"); break;
+ SAM("-EREMOTEIO\n");
+ break;
}
case -ENODEV: {
- strcpy(&errbuf[0], "-ENODEV"); break;
+ SAM("-ENODEV\n");
+ break;
}
case -EXDEV: {
- strcpy(&errbuf[0], "-EXDEV"); break;
+ SAM("-EXDEV\n");
+ break;
}
case -EINVAL: {
- strcpy(&errbuf[0], "-EINVAL"); break;
+ SAM("-EINVAL\n");
+ break;
}
case -ECONNRESET: {
- strcpy(&errbuf[0], "-ECONNRESET"); break;
+ SAM("-ECONNRESET\n");
+ break;
}
case -ENOSPC: {
- strcpy(&errbuf[0], "-ENOSPC"); break;
+ SAM("-ENOSPC\n");
+ break;
}
case -ESHUTDOWN: {
- strcpy(&errbuf[0], "-ESHUTDOWN"); break;
+ SAM("-ESHUTDOWN\n");
+ break;
}
default: {
- strcpy(&errbuf[0], "UNKNOWN"); break;
- }
+ SAM("unknown error:0x%08X\n", purb->iso_frame_desc[i].status);
+ break;
}
- if ((!purb->iso_frame_desc[i].status) && 0) {
- JOT(16, "frame[%2i]: %i=status{=%16s} " \
- "%5i=actual " \
- "%5i=length " \
- "%3i=offset\n", \
- i, purb->iso_frame_desc[i].status, &errbuf[0],
- purb->iso_frame_desc[i].actual_length,
- purb->iso_frame_desc[i].length,
- purb->iso_frame_desc[i].offset);
}
if (!purb->iso_frame_desc[i].status) {
more = purb->iso_frame_desc[i].actual_length;
@@ -319,11 +368,12 @@ for (i = 0; i < purb->number_of_packets; i++) {
#endif
if (!more)
- mt++;
+ peasycap->audio_mt++;
else {
- if (mt) {
- JOT(16, "%4i empty audio urb frames\n", mt);
- mt = 0;
+ if (peasycap->audio_mt) {
+ JOM(16, "%4i empty audio urb frames\n", \
+ peasycap->audio_mt);
+ peasycap->audio_mt = 0;
}
p1 = (__u8 *)(purb->transfer_buffer + \
@@ -340,13 +390,13 @@ for (i = 0; i < purb->number_of_packets; i++) {
/*---------------------------------------------------------------------------*/
while (more) {
if (0 > more) {
- SAY("easysnd_complete: MISTAKE: " \
+ SAM("easysnd_complete: MISTAKE: " \
"more is negative\n");
return;
}
if (peasycap->audio_buffer_page_many <= \
peasycap->audio_fill) {
- SAY("ERROR: bad " \
+ SAM("ERROR: bad " \
"peasycap->audio_fill\n");
return;
}
@@ -355,7 +405,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
[peasycap->audio_fill];
if (PAGE_SIZE < (paudio_buffer->pto - \
paudio_buffer->pgo)) {
- SAY("ERROR: bad paudio_buffer->pto\n");
+ SAM("ERROR: bad paudio_buffer->pto\n");
return;
}
if (PAGE_SIZE == (paudio_buffer->pto - \
@@ -374,7 +424,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
peasycap->audio_fill)
peasycap->audio_fill = 0;
- JOT(12, "bumped peasycap->" \
+ JOM(12, "bumped peasycap->" \
"audio_fill to %i\n", \
peasycap->audio_fill);
@@ -387,7 +437,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
if (!(peasycap->audio_fill % \
peasycap->\
audio_pages_per_fragment)) {
- JOT(12, "wakeup call on wq_" \
+ JOM(12, "wakeup call on wq_" \
"audio, %i=frag reading %i" \
"=fragment fill\n", \
(peasycap->audio_read / \
@@ -414,7 +464,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
} else {
#if defined(UPSAMPLE)
if (much % 16)
- JOT(8, "MISTAKE? much" \
+ JOM(8, "MISTAKE? much" \
" is not divisible by 16\n");
if (much > (16 * \
more))
@@ -468,7 +518,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
}
}
} else {
- JOT(12, "discarding audio samples because " \
+ JOM(12, "discarding audio samples because " \
"%i=purb->iso_frame_desc[i].status\n", \
purb->iso_frame_desc[i].status);
}
@@ -486,38 +536,50 @@ peasycap->oldaudio = oldaudio;
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
- SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \
+ if (-ENODEV != rc) {
+ SAM("ERROR: while %i=audio_idle, " \
+ "usb_submit_urb() failed " \
"with rc:\n", peasycap->audio_idle);
+ }
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n"); break;
+ SAM("-ENOMEM\n");
+ break;
}
case -ENODEV: {
- SAY("ENODEV\n"); break;
+ break;
}
case -ENXIO: {
- SAY("ENXIO\n"); break;
+ SAM("-ENXIO\n");
+ break;
}
case -EINVAL: {
- SAY("EINVAL\n"); break;
+ SAM("-EINVAL\n");
+ break;
}
case -EAGAIN: {
- SAY("EAGAIN\n"); break;
+ SAM("-EAGAIN\n");
+ break;
}
case -EFBIG: {
- SAY("EFBIG\n"); break;
+ SAM("-EFBIG\n");
+ break;
}
case -EPIPE: {
- SAY("EPIPE\n"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n");
+ break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ SAM("-ENOSPC\n");
+ break;
}
default: {
- SAY("0x%08X\n", rc); break;
+ SAM("unknown error: 0x%08X\n", rc);
+ break;
}
}
}
@@ -529,8 +591,7 @@ return;
/*
* THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
* STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
- * HAVE AN IOCTL INTERFACE. THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED
- * MUCH LATER: SEE COMMENTS IN FILE easycap_main.c.
+ * HAVE AN IOCTL INTERFACE.
*/
/*---------------------------------------------------------------------------*/
int
@@ -539,8 +600,15 @@ easysnd_open(struct inode *inode, struct file *file)
struct usb_interface *pusb_interface;
struct easycap *peasycap;
int subminor, rc;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+struct v4l2_device *pv4l2_device;
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-JOT(4, "begins.\n");
+JOT(4, "begins\n");
subminor = iminor(inode);
@@ -556,70 +624,90 @@ if (NULL == peasycap) {
SAY("ending unsuccessfully\n");
return -1;
}
+/*---------------------------------------------------------------------------*/
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+#
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+/*---------------------------------------------------------------------------*/
+/*
+ * SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
+ * BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
+ * REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
+ * TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
+*/
+/*---------------------------------------------------------------------------*/
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ pv4l2_device = usb_get_intfdata(pusb_interface);
+ if ((struct v4l2_device *)NULL == pv4l2_device) {
+ SAY("ERROR: pv4l2_device is NULL\n");
+ return -EFAULT;
+ }
+ peasycap = (struct easycap *) \
+ container_of(pv4l2_device, struct easycap, v4l2_device);
+}
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
file->private_data = peasycap;
/*---------------------------------------------------------------------------*/
/*
- * INITIALIZATION.
+ * INITIALIZATION
*/
/*---------------------------------------------------------------------------*/
-JOT(4, "starting initialization\n");
+JOM(4, "starting initialization\n");
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
- return -EFAULT;
-} else {
- JOT(16, "0x%08lX=peasycap->pusb_device\n", \
- (long int)peasycap->pusb_device);
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ return -ENODEV;
}
+JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
rc = audio_setup(peasycap);
if (0 <= rc)
- JOT(8, "audio_setup() returned %i\n", rc);
+ JOM(8, "audio_setup() returned %i\n", rc);
else
- JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
+ JOM(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device has become NULL\n");
- return -EFAULT;
-}
-rc = adjust_volume(peasycap, -8192);
-if (0 != rc) {
- SAY("ERROR: adjust_volume(default) returned %i\n", rc);
- return -EFAULT;
+ SAM("ERROR: peasycap->pusb_device has become NULL\n");
+ return -ENODEV;
}
/*---------------------------------------------------------------------------*/
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device has become NULL\n");
- return -EFAULT;
+ SAM("ERROR: peasycap->pusb_device has become NULL\n");
+ return -ENODEV;
}
rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
peasycap->audio_altsetting_on);
-JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
+JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
-if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device has become NULL\n");
- return -EFAULT;
-}
rc = wakeup_device(peasycap->pusb_device);
if (0 == rc)
- JOT(8, "wakeup_device() returned %i\n", rc);
+ JOM(8, "wakeup_device() returned %i\n", rc);
else
- JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc);
+ JOM(8, "ERROR: wakeup_device() returned %i\n", rc);
-if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device has become NULL\n");
- return -EFAULT;
-}
-submit_audio_urbs(peasycap);
+peasycap->audio_eof = 0;
peasycap->audio_idle = 0;
peasycap->timeval1.tv_sec = 0;
peasycap->timeval1.tv_usec = 0;
-JOT(4, "finished initialization\n");
+submit_audio_urbs(peasycap);
+
+JOM(4, "finished initialization\n");
return 0;
}
/*****************************************************************************/
@@ -635,11 +723,15 @@ if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL.\n");
return -EFAULT;
}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
if (0 != kill_audio_urbs(peasycap)) {
- SAY("ERROR: kill_audio_urbs() failed\n");
+ SAM("ERROR: kill_audio_urbs() failed\n");
return -EFAULT;
}
-JOT(4, "ending successfully\n");
+JOM(4, "ending successfully\n");
return 0;
}
/*****************************************************************************/
@@ -648,12 +740,11 @@ easysnd_read(struct file *file, char __user *puserspacebuffer, \
size_t kount, loff_t *poff)
{
struct timeval timeval;
-static struct timeval timeval1;
-static long long int audio_bytes, above, below, mean;
+long long int above, below, mean;
struct signed_div_result sdr;
unsigned char *p0;
long int kount1, more, rc, l0, lm;
-int fragment;
+int fragment, kd;
struct easycap *peasycap;
struct data_buffer *pdata_buffer;
size_t szret;
@@ -671,23 +762,89 @@ size_t szret;
JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
-peasycap = (struct easycap *)(file->private_data);
+if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ return -ERESTARTSYS;
+}
+peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR in easysnd_read(): peasycap is NULL\n");
return -EFAULT;
}
+if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
+ return -EFAULT;
+}
+if (NULL == peasycap->pusb_device) {
+ SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&(easycap_dongle[kd].mutex_audio))) {
+ SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
/*---------------------------------------------------------------------------*/
+/*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+ SAY("ERROR: bad peasycap: 0x%08lX\n", \
+ (unsigned long int) peasycap);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+} else {
+/*---------------------------------------------------------------------------*/
+/*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+}
+/*---------------------------------------------------------------------------*/
+if (file->f_flags & O_NONBLOCK)
+ JOT(16, "NONBLOCK kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
+else
+ JOT(8, "BLOCKING kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
+
if ((0 > peasycap->audio_read) || \
(peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
- SAY("ERROR: peasycap->audio_read out of range\n");
+ SAM("ERROR: peasycap->audio_read out of range\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
- SAY("ERROR: pdata_buffer is NULL\n");
+ SAM("ERROR: pdata_buffer is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
-JOT(12, "before wait, %i=frag read %i=frag fill\n", \
+JOM(12, "before wait, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / peasycap->audio_pages_per_fragment), \
(peasycap->audio_fill / peasycap->audio_pages_per_fragment));
fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
@@ -695,7 +852,8 @@ while ((fragment == (peasycap->audio_fill / \
peasycap->audio_pages_per_fragment)) || \
(0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
if (file->f_flags & O_NONBLOCK) {
- JOT(16, "returning -EAGAIN as instructed\n");
+ JOM(16, "returning -EAGAIN as instructed\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EAGAIN;
}
rc = wait_event_interruptible(peasycap->wq_audio, \
@@ -704,50 +862,56 @@ while ((fragment == (peasycap->audio_fill / \
peasycap->audio_pages_per_fragment)) && \
(0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
if (0 != rc) {
- SAY("aborted by signal\n");
+ SAM("aborted by signal\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (peasycap->audio_eof) {
- JOT(8, "returning 0 because %i=audio_eof\n", \
+ JOM(8, "returning 0 because %i=audio_eof\n", \
peasycap->audio_eof);
kill_audio_urbs(peasycap);
- msleep(500);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0;
}
if (peasycap->audio_idle) {
- JOT(16, "returning 0 because %i=audio_idle\n", \
+ JOM(16, "returning 0 because %i=audio_idle\n", \
peasycap->audio_idle);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0;
}
if (!peasycap->audio_isoc_streaming) {
- JOT(16, "returning 0 because audio urbs not streaming\n");
+ JOM(16, "returning 0 because audio urbs not streaming\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0;
}
}
-JOT(12, "after wait, %i=frag read %i=frag fill\n", \
+JOM(12, "after wait, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / peasycap->audio_pages_per_fragment), \
(peasycap->audio_fill / peasycap->audio_pages_per_fragment));
szret = (size_t)0;
while (fragment == (peasycap->audio_read / \
peasycap->audio_pages_per_fragment)) {
if (NULL == pdata_buffer->pgo) {
- SAY("ERROR: pdata_buffer->pgo is NULL\n");
+ SAM("ERROR: pdata_buffer->pgo is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
- SAY("ERROR: pdata_buffer->pto is NULL\n");
+ SAM("ERROR: pdata_buffer->pto is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
if (0 > kount1) {
- SAY("easysnd_read: MISTAKE: kount1 is negative\n");
+ SAM("easysnd_read: MISTAKE: kount1 is negative\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (!kount1) {
(peasycap->audio_read)++;
if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
peasycap->audio_read = 0;
- JOT(12, "bumped peasycap->audio_read to %i\n", \
+ JOM(12, "bumped peasycap->audio_read to %i\n", \
peasycap->audio_read);
if (fragment != (peasycap->audio_read / \
@@ -757,30 +921,34 @@ while (fragment == (peasycap->audio_read / \
if ((0 > peasycap->audio_read) || \
(peasycap->audio_buffer_page_many <= \
peasycap->audio_read)) {
- SAY("ERROR: peasycap->audio_read out of range\n");
+ SAM("ERROR: peasycap->audio_read out of range\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
- SAY("ERROR: pdata_buffer is NULL\n");
+ SAM("ERROR: pdata_buffer is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pgo) {
- SAY("ERROR: pdata_buffer->pgo is NULL\n");
+ SAM("ERROR: pdata_buffer->pgo is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
- SAY("ERROR: pdata_buffer->pto is NULL\n");
+ SAM("ERROR: pdata_buffer->pto is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
}
- JOT(12, "ready to send %li bytes\n", (long int) kount1);
- JOT(12, "still to send %li bytes\n", (long int) kount);
+ JOM(12, "ready to send %li bytes\n", (long int) kount1);
+ JOM(12, "still to send %li bytes\n", (long int) kount);
more = kount1;
if (more > kount)
more = kount;
- JOT(12, "agreed to send %li bytes from page %i\n", \
+ JOM(12, "agreed to send %li bytes from page %i\n", \
more, peasycap->audio_read);
if (!more)
break;
@@ -798,7 +966,8 @@ while (fragment == (peasycap->audio_read / \
/*---------------------------------------------------------------------------*/
rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
if (0 != rc) {
- SAY("ERROR: copy_to_user() returned %li\n", rc);
+ SAM("ERROR: copy_to_user() returned %li\n", rc);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
}
*poff += (loff_t)more;
@@ -807,11 +976,11 @@ while (fragment == (peasycap->audio_read / \
puserspacebuffer += more;
kount -= (size_t)more;
}
-JOT(12, "after read, %i=frag read %i=frag fill\n", \
+JOM(12, "after read, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / peasycap->audio_pages_per_fragment), \
(peasycap->audio_fill / peasycap->audio_pages_per_fragment));
if (kount < 0) {
- SAY("MISTAKE: %li=kount %li=szret\n", \
+ SAM("MISTAKE: %li=kount %li=szret\n", \
(long int)kount, (long int)szret);
}
/*---------------------------------------------------------------------------*/
@@ -827,11 +996,11 @@ if (peasycap->audio_sample) {
mean = peasycap->audio_niveau;
sdr = signed_div(mean, peasycap->audio_sample);
- JOT(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \
+ JOM(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \
sdr.quotient, above, peasycap->audio_sample);
sdr = signed_div(above, 32768);
- JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
+ JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
}
/*---------------------------------------------------------------------------*/
/*
@@ -840,33 +1009,28 @@ if (peasycap->audio_sample) {
/*---------------------------------------------------------------------------*/
do_gettimeofday(&timeval);
if (!peasycap->timeval1.tv_sec) {
- audio_bytes = 0;
- timeval1 = timeval;
-
- if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
- return -ERESTARTSYS;
- peasycap->timeval1 = timeval1;
- mutex_unlock(&(peasycap->mutex_timeval1));
+ peasycap->audio_bytes = 0;
+ peasycap->timeval3 = timeval;
+ peasycap->timeval1 = peasycap->timeval3;
sdr.quotient = 192000;
} else {
- audio_bytes += (long long int) szret;
+ peasycap->audio_bytes += (long long int) szret;
below = ((long long int)(1000000)) * \
- ((long long int)(timeval.tv_sec - timeval1.tv_sec)) + \
- (long long int)(timeval.tv_usec - timeval1.tv_usec);
- above = 1000000 * ((long long int) audio_bytes);
+ ((long long int)(timeval.tv_sec - \
+ peasycap->timeval3.tv_sec)) + \
+ (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
+ above = 1000000 * ((long long int) peasycap->audio_bytes);
if (below)
sdr = signed_div(above, below);
else
sdr.quotient = 192000;
}
-JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
-if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
- return -ERESTARTSYS;
+JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
peasycap->dnbydt = sdr.quotient;
-mutex_unlock(&(peasycap->mutex_timeval1));
-JOT(8, "returning %li\n", (long int)szret);
+JOM(8, "returning %li\n", (long int)szret);
+mutex_unlock(&easycap_dongle[kd].mutex_audio);
return szret;
}
/*****************************************************************************/
@@ -881,27 +1045,31 @@ submit_audio_urbs(struct easycap *peasycap)
struct data_urb *pdata_urb;
struct urb *purb;
struct list_head *plist_head;
-int j, isbad, m, rc;
+int j, isbad, nospc, m, rc;
int isbuf;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if ((struct list_head *)NULL == peasycap->purb_audio_head) {
- SAY("ERROR: peasycap->urb_audio_head uninitialized\n");
+ SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
return -EFAULT;
}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
- SAY("ERROR: peasycap->pusb_device is NULL\n");
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
if (!peasycap->audio_isoc_streaming) {
- JOT(4, "initial submission of all audio urbs\n");
+ JOM(4, "initial submission of all audio urbs\n");
rc = usb_set_interface(peasycap->pusb_device,
peasycap->audio_interface, \
peasycap->audio_altsetting_on);
- JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \
+ JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", \
peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
- isbad = 0; m = 0;
+ isbad = 0; nospc = 0; m = 0;
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, list_head);
if (NULL != pdata_urb) {
@@ -938,39 +1106,49 @@ if (!peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_KERNEL);
if (0 != rc) {
isbad++;
- SAY("ERROR: usb_submit_urb() failed" \
+ SAM("ERROR: usb_submit_urb() failed" \
" for urb with rc:\n");
switch (rc) {
case -ENOMEM: {
- SAY("ENOMEM\n"); break;
+ SAM("-ENOMEM\n");
+ break;
}
case -ENODEV: {
- SAY("ENODEV\n"); break;
+ SAM("-ENODEV\n");
+ break;
}
case -ENXIO: {
- SAY("ENXIO\n"); break;
+ SAM("-ENXIO\n");
+ break;
}
case -EINVAL: {
- SAY("EINVAL\n"); break;
+ SAM("-EINVAL\n");
+ break;
}
case -EAGAIN: {
- SAY("EAGAIN\n"); break;
+ SAM("-EAGAIN\n");
+ break;
}
case -EFBIG: {
- SAY("EFBIG\n"); break;
+ SAM("-EFBIG\n");
+ break;
}
case -EPIPE: {
- SAY("EPIPE\n"); break;
+ SAM("-EPIPE\n");
+ break;
}
case -EMSGSIZE: {
- SAY("EMSGSIZE\n"); break;
+ SAM("-EMSGSIZE\n");
+ break;
}
case -ENOSPC: {
- SAY("ENOSPC\n"); break;
+ nospc++;
+ break;
}
default: {
- SAY("unknown error code %i\n",\
- rc); break;
+ SAM("unknown error code %i\n",\
+ rc);
+ break;
}
}
} else {
@@ -983,8 +1161,13 @@ if (!peasycap->audio_isoc_streaming) {
isbad++;
}
}
+ if (nospc) {
+ SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
+ SAM("..... possibly inadequate USB bandwidth\n");
+ peasycap->audio_eof = 1;
+ }
if (isbad) {
- JOT(4, "attempting cleanup instead of submitting\n");
+ JOM(4, "attempting cleanup instead of submitting\n");
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, \
list_head);
@@ -997,10 +1180,10 @@ if (!peasycap->audio_isoc_streaming) {
peasycap->audio_isoc_streaming = 0;
} else {
peasycap->audio_isoc_streaming = 1;
- JOT(4, "submitted %i audio urbs\n", m);
+ JOM(4, "submitted %i audio urbs\n", m);
}
} else
- JOT(4, "already streaming audio urbs\n");
+ JOM(4, "already streaming audio urbs\n");
return 0;
}
@@ -1017,10 +1200,14 @@ int m;
struct list_head *plist_head;
struct data_urb *pdata_urb;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
if (peasycap->audio_isoc_streaming) {
if ((struct list_head *)NULL != peasycap->purb_audio_head) {
peasycap->audio_isoc_streaming = 0;
- JOT(4, "killing audio urbs\n");
+ JOM(4, "killing audio urbs\n");
m = 0;
list_for_each(plist_head, (peasycap->purb_audio_head)) {
pdata_urb = list_entry(plist_head, struct data_urb,
@@ -1032,13 +1219,13 @@ if (peasycap->audio_isoc_streaming) {
}
}
}
- JOT(4, "%i audio urbs killed\n", m);
+ JOM(4, "%i audio urbs killed\n", m);
} else {
- SAY("ERROR: peasycap->purb_audio_head is NULL\n");
+ SAM("ERROR: peasycap->purb_audio_head is NULL\n");
return -EFAULT;
}
} else {
- JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
+ JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
peasycap->audio_isoc_streaming);
}
return 0;
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c
index 3c2ce28fab95..e27dfe9a9ba3 100644
--- a/drivers/staging/easycap/easycap_testcard.c
+++ b/drivers/staging/easycap/easycap_testcard.c
@@ -29,37 +29,69 @@
#include "easycap_debug.h"
/*****************************************************************************/
-#define TESTCARD_BYTESPERLINE (2 * 1440)
+#define TESTCARD_BYTESPERLINE (2 * 720)
void
-easycap_testcard(struct easycap *peasycap, int field_fill)
+easycap_testcard(struct easycap *peasycap, int field)
{
int total;
int y, u, v, r, g, b;
unsigned char uyvy[4];
-
-int i1, line, k, m, n, more, much, barwidth;
+int i1, line, k, m, n, more, much, barwidth, barheight;
unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
struct data_buffer *pfield_buffer;
-JOT(8, "%i=field_fill\n", field_fill);
-
-if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) {
- SAY("ERROR: image is too wide\n");
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return;
+}
+JOM(8, "%i=field\n", field);
+switch (peasycap->width) {
+case 720:
+case 360: {
+ barwidth = (2 * 720) / 8;
+ break;
+}
+case 704:
+case 352: {
+ barwidth = (2 * 704) / 8;
+ break;
+}
+case 640:
+case 320: {
+ barwidth = (2 * 640) / 8;
+ break;
+}
+default: {
+ SAM("ERROR: cannot set barwidth\n");
return;
}
-if (peasycap->width % 16) {
- SAY("ERROR: indivisible image width\n");
+}
+if (TESTCARD_BYTESPERLINE < barwidth) {
+ SAM("ERROR: barwidth is too large\n");
return;
}
-
+switch (peasycap->height) {
+case 576:
+case 288: {
+ barheight = 576;
+ break;
+}
+case 480:
+case 240: {
+ barheight = 480;
+ break;
+}
+default: {
+ SAM("ERROR: cannot set barheight\n");
+ return;
+}
+}
total = 0;
-barwidth = (2 * peasycap->width) / 8;
-
-k = field_fill;
+k = field;
m = 0;
n = 0;
-for (line = 0; line < (peasycap->height / 2); line++) {
+for (line = 0; line < (barheight / 2); line++) {
for (i1 = 0; i1 < 8; i1++) {
r = (i1 * 256)/8;
g = (i1 * 256)/8;
@@ -88,15 +120,15 @@ for (line = 0; line < (peasycap->height / 2); line++) {
while (more) {
if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
- SAY("ERROR: bad m reached\n");
+ SAM("ERROR: bad m reached\n");
return;
}
if (PAGE_SIZE < n) {
- SAY("ERROR: bad n reached\n"); return;
+ SAM("ERROR: bad n reached\n"); return;
}
if (0 > more) {
- SAY("ERROR: internal fault\n");
+ SAM("ERROR: internal fault\n");
return;
}
@@ -117,10 +149,6 @@ for (line = 0; line < (peasycap->height / 2); line++) {
}
}
}
-
-JOT(8, "%i=total\n", total);
-if (total != peasycap->width * peasycap->height)
- SAY("ERROR: wrong number of bytes written: %i\n", total);
return;
}
/*****************************************************************************/
@@ -157,35 +185,35 @@ for (i1 = 0; i1 <= last; i1++)
printf("%6i, ", i2); printf("%6i\n};\n", i2);
}
}
-return(0);
+return 0;
}
-----------------------------------------------------------------------------*/
int tones[2048] = {
- 0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005,
- 2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466,
- 4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822,
- 7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018,
- 9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002,
- 11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728,
- 13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155,
- 14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249,
- 15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985,
- 16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346,
- 16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323,
- 16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917,
- 15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136,
- 14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001,
- 13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536,
- 12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777,
- 10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765,
- 8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547,
- 6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175,
- 3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705,
- 1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803,
- -1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294,
- -3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708,
- -6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988,
- -8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079,
+0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005,
+2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466,
+4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822,
+7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018,
+9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002,
+11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728,
+13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155,
+14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249,
+15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985,
+16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346,
+16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323,
+16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917,
+15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136,
+14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001,
+13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536,
+12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777,
+10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765,
+8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547,
+6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175,
+3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705,
+1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803,
+-1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294,
+-3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708,
+-6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988,
+-8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079,
-10471, -10471, -10853, -10853, -11224, -11224, -11585, -11585, -11935, -11935,
-12273, -12273, -12600, -12600, -12916, -12916, -13219, -13219, -13510, -13510,
-13788, -13788, -14053, -14053, -14304, -14304, -14543, -14543, -14767, -14767,
@@ -198,35 +226,35 @@ int tones[2048] = {
-14353, -14353, -14104, -14104, -13842, -13842, -13566, -13566, -13278, -13278,
-12977, -12977, -12665, -12665, -12340, -12340, -12003, -12003, -11656, -11656,
-11297, -11297, -10928, -10928, -10548, -10548, -10159, -10159, -9759, -9759,
- -9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634,
- -7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329,
- -4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900,
- -2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402,
- 100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105,
- 2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563,
- 5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914,
- 7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102,
- 9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077,
- 11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791,
- 13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205,
- 14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286,
- 15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007,
- 16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353,
- 16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314,
- 16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892,
- 15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098,
- 14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948,
- 13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471,
- 12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701,
- 10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680,
- 8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455,
- 5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078,
- 3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605,
- 1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904,
- -1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393,
- -3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802,
- -6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075,
- -8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159,
+-9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634,
+-7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329,
+-4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900,
+-2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402,
+100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105,
+2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563,
+5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914,
+7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102,
+9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077,
+11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791,
+13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205,
+14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286,
+15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007,
+16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353,
+16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314,
+16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892,
+15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098,
+14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948,
+13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471,
+12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701,
+10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680,
+8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455,
+5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078,
+3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605,
+1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904,
+-1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393,
+-3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802,
+-6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075,
+-8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159,
-10548, -10548, -10928, -10928, -11297, -11297, -11656, -11656, -12003, -12003,
-12340, -12340, -12665, -12665, -12977, -12977, -13278, -13278, -13566, -13566,
-13842, -13842, -14104, -14104, -14353, -14353, -14589, -14589, -14810, -14810,
@@ -239,35 +267,35 @@ int tones[2048] = {
-14304, -14304, -14053, -14053, -13788, -13788, -13510, -13510, -13219, -13219,
-12916, -12916, -12600, -12600, -12273, -12273, -11935, -11935, -11585, -11585,
-11224, -11224, -10853, -10853, -10471, -10471, -10079, -10079, -9679, -9679,
- -9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545,
- -7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234,
- -4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801,
- -2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301,
- 201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204,
- 2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659,
- 5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005,
- 7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185,
- 9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150,
- 11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854,
- 13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255,
- 14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322,
- 15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028,
- 16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359,
- 16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305,
- 16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868,
- 15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058,
- 14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895,
- 13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406,
- 12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625,
- 10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594,
- 8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362,
- 5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980,
- 3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505,
- 1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004,
- -1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491,
- -3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896,
- -6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162,
- -8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237,
+-9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545,
+-7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234,
+-4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801,
+-2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301,
+201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204,
+2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659,
+5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005,
+7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185,
+9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150,
+11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854,
+13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255,
+14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322,
+15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028,
+16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359,
+16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305,
+16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868,
+15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058,
+14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895,
+13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406,
+12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625,
+10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594,
+8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362,
+5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980,
+3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505,
+1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004,
+-1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491,
+-3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896,
+-6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162,
+-8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237,
-10625, -10625, -11002, -11002, -11370, -11370, -11726, -11726, -12072, -12072,
-12406, -12406, -12728, -12728, -13038, -13038, -13337, -13337, -13622, -13622,
-13895, -13895, -14155, -14155, -14401, -14401, -14634, -14634, -14853, -14853,
@@ -280,35 +308,35 @@ int tones[2048] = {
-14255, -14255, -14001, -14001, -13733, -13733, -13452, -13452, -13159, -13159,
-12854, -12854, -12536, -12536, -12207, -12207, -11866, -11866, -11513, -11513,
-11150, -11150, -10777, -10777, -10393, -10393, -10000, -10000, -9597, -9597,
- -9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456,
- -7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139,
- -4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701,
- -2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201,
- 301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304,
- 2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756,
- 5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095,
- 7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268,
- 9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224,
- 11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916,
- 13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304,
- 14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357,
- 15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049,
- 16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364,
- 16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294,
- 16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842,
- 15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018,
- 14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842,
- 13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340,
- 12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548,
- 10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509,
- 8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269,
- 5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883,
- 3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405,
- 904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105,
- -1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589,
- -4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990,
- -6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249,
- -8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315,
+-9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456,
+-7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139,
+-4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701,
+-2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201,
+301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304,
+2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756,
+5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095,
+7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268,
+9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224,
+11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916,
+13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304,
+14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357,
+15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049,
+16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364,
+16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294,
+16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842,
+15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018,
+14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842,
+13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340,
+12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548,
+10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509,
+8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269,
+5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883,
+3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405,
+904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105,
+-1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589,
+-4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990,
+-6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249,
+-8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315,
-10701, -10701, -11077, -11077, -11442, -11442, -11796, -11796, -12139, -12139,
-12471, -12471, -12791, -12791, -13099, -13099, -13395, -13395, -13678, -13678,
-13948, -13948, -14205, -14205, -14449, -14449, -14679, -14679, -14895, -14895,
@@ -321,35 +349,35 @@ int tones[2048] = {
-14205, -14205, -13948, -13948, -13678, -13678, -13395, -13395, -13099, -13099,
-12791, -12791, -12471, -12471, -12139, -12139, -11796, -11796, -11442, -11442,
-11077, -11077, -10701, -10701, -10315, -10315, -9920, -9920, -9516, -9516,
- -9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366,
- -6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043,
- -4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602,
- -2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100,
- 402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404,
- 2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852,
- 5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186,
- 7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351,
- 9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297,
- 11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977,
- 13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353,
- 14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392,
- 15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069,
- 16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368,
- 16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284,
- 16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817,
- 15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978,
- 14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788,
- 13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273,
- 11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471,
- 10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423,
- 7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176,
- 5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785,
- 3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305,
- 803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205,
- -1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687,
- -4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083,
- -6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336,
- -8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393,
+-9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366,
+-6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043,
+-4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602,
+-2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100,
+402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404,
+2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852,
+5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186,
+7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351,
+9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297,
+11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977,
+13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353,
+14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392,
+15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069,
+16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368,
+16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284,
+16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817,
+15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978,
+14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788,
+13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273,
+11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471,
+10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423,
+7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176,
+5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785,
+3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305,
+803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205,
+-1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687,
+-4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083,
+-6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336,
+-8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393,
-10777, -10777, -11150, -11150, -11513, -11513, -11866, -11866, -12207, -12207,
-12536, -12536, -12854, -12854, -13159, -13159, -13452, -13452, -13733, -13733,
-14001, -14001, -14255, -14255, -14496, -14496, -14723, -14723, -14937, -14937,
@@ -362,10 +390,10 @@ int tones[2048] = {
-14155, -14155, -13895, -13895, -13622, -13622, -13337, -13337, -13038, -13038,
-12728, -12728, -12406, -12406, -12072, -12072, -11726, -11726, -11370, -11370,
-11002, -11002, -10625, -10625, -10237, -10237, -9840, -9840, -9434, -9434,
- -9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276,
- -6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948,
- -4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503,
- -2005, -2005, -1505, -1505, -1004, -1004, -502, -502
+-9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276,
+-6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948,
+-4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503,
+-2005, -2005, -1505, -1505, -1004, -1004, -502, -502
};
/*****************************************************************************/
void
@@ -375,10 +403,12 @@ int i1;
unsigned char *p2;
struct data_buffer *paudio_buffer;
-JOT(8, "%i=audio_fill\n", audio_fill);
-
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return;
+}
+JOM(8, "%i=audio_fill\n", audio_fill);
paudio_buffer = &peasycap->audio_buffer[audio_fill];
-
p2 = (unsigned char *)(paudio_buffer->pgo);
for (i1 = 0; i1 < PAGE_SIZE; i1 += 4, p2 += 4) {
*p2 = (unsigned char) (0x00FF & tones[i1/2]);
diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c
index 10bcb45d73a3..f62ba7a68f34 100644
--- a/drivers/staging/et131x/et131x_initpci.c
+++ b/drivers/staging/et131x/et131x_initpci.c
@@ -783,7 +783,7 @@ static void __devexit et131x_pci_remove(struct pci_dev *pdev)
/* Retrieve the net_device pointer from the pci_dev struct, as well
* as the private adapter struct
*/
- netdev = (struct net_device *) pci_get_drvdata(pdev);
+ netdev = pci_get_drvdata(pdev);
adapter = netdev_priv(netdev);
/* Perform device cleanup */
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index ef7fbf8b069a..2babb034a254 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -89,7 +89,7 @@ static int debug = ALPHATRACK_DEBUG;
/* Use our own dbg macro */
#define dbg_info(dev, format, arg...) do \
- { if (debug) dev_info(dev , format , ## arg); } while (0)
+ { if (debug) dev_info(dev , format , ## arg); } while (0)
#define alphatrack_ocmd_info(dev, cmd, format, arg...)
@@ -769,7 +769,7 @@ static int usb_alphatrack_probe(struct usb_interface *intf,
}
dev->write_buffer =
- kmalloc(sizeof(struct alphatrack_ocmd) * true_size, GFP_KERNEL);
+ kmalloc(true_size * sizeof(struct alphatrack_ocmd), GFP_KERNEL);
if (!dev->write_buffer) {
dev_err(&intf->dev, "Couldn't allocate write_buffer\n");
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index a145a15cfdb3..8894ab14f167 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -204,7 +204,7 @@ static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
t->value = temp; \
return count; \
} \
- static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+ static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value);
show_int(enable);
show_int(offline);
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index eed7e94308db..588afd5a5ddb 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -132,7 +132,7 @@ inline void ft1000_asic_write(struct net_device *dev, u16 offset, u16 value)
//---------------------------------------------------------------------------
static inline u16 ft1000_read_fifo_len(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
if (info->AsicID == ELECTRABUZZ_ID) {
return (ft1000_read_reg(dev, FT1000_REG_UFIFO_STAT) - 16);
@@ -155,7 +155,7 @@ static inline u16 ft1000_read_fifo_len(struct net_device *dev)
//---------------------------------------------------------------------------
u16 ft1000_read_dpram(struct net_device * dev, int offset)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
u16 data;
@@ -184,7 +184,7 @@ u16 ft1000_read_dpram(struct net_device * dev, int offset)
static inline void ft1000_write_dpram(struct net_device *dev,
int offset, u16 value)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
// Provide mutual exclusive access while reading ASIC registers.
@@ -208,7 +208,7 @@ static inline void ft1000_write_dpram(struct net_device *dev,
//---------------------------------------------------------------------------
u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
u16 data;
@@ -242,7 +242,7 @@ u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index)
static inline void ft1000_write_dpram_mag_16(struct net_device *dev,
int offset, u16 value, int Index)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
// Provide mutual exclusive access while reading ASIC registers.
@@ -270,7 +270,7 @@ static inline void ft1000_write_dpram_mag_16(struct net_device *dev,
//---------------------------------------------------------------------------
u32 ft1000_read_dpram_mag_32(struct net_device *dev, int offset)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
u32 data;
@@ -298,7 +298,7 @@ u32 ft1000_read_dpram_mag_32(struct net_device *dev, int offset)
//---------------------------------------------------------------------------
void ft1000_write_dpram_mag_32(struct net_device *dev, int offset, u32 value)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
unsigned long flags;
// Provide mutual exclusive access while reading ASIC registers.
@@ -320,7 +320,7 @@ void ft1000_write_dpram_mag_32(struct net_device *dev, int offset, u32 value)
//---------------------------------------------------------------------------
static void ft1000_enable_interrupts(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 tempword;
DEBUG(1, "ft1000_hw:ft1000_enable_interrupts()\n");
@@ -345,7 +345,7 @@ static void ft1000_enable_interrupts(struct net_device *dev)
//---------------------------------------------------------------------------
static void ft1000_disable_interrupts(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 tempword;
DEBUG(1, "ft1000_hw: ft1000_disable_interrupts()\n");
@@ -370,7 +370,7 @@ static void ft1000_disable_interrupts(struct net_device *dev)
//---------------------------------------------------------------------------
static void ft1000_reset_asic(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 tempword;
DEBUG(1, "ft1000_hw:ft1000_reset_asic called\n");
@@ -414,7 +414,7 @@ static void ft1000_reset_asic(struct net_device *dev)
//---------------------------------------------------------------------------
static int ft1000_reset_card(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 tempword;
int i;
unsigned long flags;
@@ -618,7 +618,7 @@ static void ft1000_hbchk(u_long data)
FT1000_INFO *info;
USHORT tempword;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
if (info->CardReady == 1) {
// Perform dsp heartbeat check
@@ -831,7 +831,7 @@ static void ft1000_hbchk(u_long data)
//---------------------------------------------------------------------------
void ft1000_send_cmd (struct net_device *dev, u16 *ptempbuffer, int size, u16 qtype)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
int i;
u16 tempword;
unsigned long flags;
@@ -916,7 +916,7 @@ void ft1000_send_cmd (struct net_device *dev, u16 *ptempbuffer, int size, u16 qt
//---------------------------------------------------------------------------
BOOLEAN ft1000_receive_cmd(struct net_device *dev, u16 * pbuffer, int maxsz, u16 *pnxtph)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 size;
u16 *ppseudohdr;
int i;
@@ -1009,7 +1009,7 @@ BOOLEAN ft1000_receive_cmd(struct net_device *dev, u16 * pbuffer, int maxsz, u16
//---------------------------------------------------------------------------
void ft1000_proc_drvmsg(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 msgtype;
u16 tempword;
PMEDIAMSG pmediamsg;
@@ -1292,7 +1292,7 @@ void ft1000_proc_drvmsg(struct net_device *dev)
//---------------------------------------------------------------------------
int ft1000_parse_dpram_msg(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 doorbell;
u16 portid;
u16 nxtph;
@@ -1449,7 +1449,7 @@ int ft1000_parse_dpram_msg(struct net_device *dev)
//---------------------------------------------------------------------------
static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 i;
u32 templong;
u16 tempword;
@@ -1596,7 +1596,7 @@ static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum)
int ft1000_copy_up_pkt(struct net_device *dev)
{
u16 tempword;
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 len;
struct sk_buff *skb;
u16 i;
@@ -1783,7 +1783,7 @@ int ft1000_copy_up_pkt(struct net_device *dev)
//---------------------------------------------------------------------------
int ft1000_copy_down_pkt(struct net_device *dev, u16 * packet, u16 len)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
union {
PSEUDO_HDR blk;
u16 buff[sizeof(PSEUDO_HDR) >> 1];
@@ -1943,7 +1943,7 @@ int ft1000_copy_down_pkt(struct net_device *dev, u16 * packet, u16 len)
static struct net_device_stats *ft1000_stats(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
return (&info->stats);
}
@@ -1967,7 +1967,7 @@ static int ft1000_open(struct net_device *dev)
static int ft1000_close(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
DEBUG(0, "ft1000_hw: ft1000_close()\n");
@@ -1989,7 +1989,7 @@ static int ft1000_close(struct net_device *dev)
static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u8 *pdata;
DEBUG(1, "ft1000_hw: ft1000_start_xmit()\n");
@@ -2026,7 +2026,7 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
static irqreturn_t ft1000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
u16 tempword;
u16 inttype;
int cnt;
@@ -2091,7 +2091,7 @@ static irqreturn_t ft1000_interrupt(int irq, void *dev_id)
void stop_ft1000_card(struct net_device *dev)
{
- FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev);
+ FT1000_INFO *info = netdev_priv(dev);
PPROV_RECORD ptr;
// int cnt;
@@ -2127,7 +2127,7 @@ static void ft1000_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
FT1000_INFO *ft_info;
- ft_info = (FT1000_INFO *) netdev_priv(dev);
+ ft_info = netdev_priv(dev);
snprintf(info->driver, 32, "ft1000");
snprintf(info->bus_info, ETHTOOL_BUSINFO_LEN, "PCMCIA 0x%lx",
@@ -2139,7 +2139,7 @@ static void ft1000_get_drvinfo(struct net_device *dev,
static u32 ft1000_get_link(struct net_device *dev)
{
FT1000_INFO *info;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
return info->mediastate;
}
@@ -2185,7 +2185,7 @@ struct net_device *init_ft1000_card(unsigned short irq, int port,
}
SET_NETDEV_DEV(dev, fdev);
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
memset(info, 0, sizeof(FT1000_INFO));
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
index b45de9bc1b20..935608e72007 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
@@ -65,7 +65,7 @@ int ft1000ReadProc(char *page, char **start, off_t off,
time_t delta;
dev = (struct net_device *)data;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
if (off > 0) {
*eof = 1;
@@ -174,7 +174,7 @@ static int ft1000NotifyProc(struct notifier_block *this, unsigned long event,
struct net_device *dev = ptr;
FT1000_INFO *info;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
switch (event) {
case NETDEV_CHANGENAME:
@@ -195,7 +195,7 @@ void ft1000InitProc(struct net_device *dev)
{
FT1000_INFO *info;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
info->proc_ft1000 = proc_mkdir(FT1000_PROC, init_net.proc_net);
create_proc_read_entry(dev->name, 0644, info->proc_ft1000,
@@ -208,7 +208,7 @@ void ft1000CleanupProc(struct net_device *dev)
{
FT1000_INFO *info;
- info = (FT1000_INFO *) netdev_priv(dev);
+ info = netdev_priv(dev);
remove_proc_entry(dev->name, info->proc_ft1000);
remove_proc_entry(FT1000_PROC, init_net.proc_net);
diff --git a/drivers/staging/ft1000/ft1000-usb/Makefile b/drivers/staging/ft1000/ft1000-usb/Makefile
index dd87ecd7918e..f0f524015888 100644
--- a/drivers/staging/ft1000/ft1000-usb/Makefile
+++ b/drivers/staging/ft1000/ft1000-usb/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_FT1000_USB) += ft1000.o
-ft1000-y := ft1000_chdev.o ft1000_download.o ft1000_hw.o ft1000_proc.o ft1000_usb.o
+ft1000-y := ft1000_debug.o ft1000_download.o ft1000_hw.o ft1000_proc.o ft1000_usb.o
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c
index 87a6487531c2..149ba59f96bf 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c
@@ -27,33 +27,22 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/kmod.h>
#include <linux/ioctl.h>
-#include <linux/unistd.h>
-
+#include <linux/debugfs.h>
#include "ft1000_usb.h"
-//#include "ft1000_ioctl.h"
static int ft1000_flarion_cnt = 0;
-//need to looking usage of ft1000Handle
-
-static int ft1000_ChOpen (struct inode *Inode, struct file *File);
-static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait);
-static long ft1000_ChIoctl(struct file *File, unsigned int Command,
- unsigned long Argument);
-static int ft1000_ChRelease (struct inode *Inode, struct file *File);
-
-// Global pointer to device object
-static struct ft1000_device *pdevobj[MAX_NUM_CARDS + 2];
-//static devfs_handle_t ft1000Handle[MAX_NUM_CARDS];
+static int ft1000_open (struct inode *inode, struct file *file);
+static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait);
+static long ft1000_ioctl(struct file *file, unsigned int command,
+ unsigned long argument);
+static int ft1000_release (struct inode *inode, struct file *file);
// List to free receive command buffer pool
struct list_head freercvpool;
@@ -63,103 +52,18 @@ spinlock_t free_buff_lock;
int numofmsgbuf = 0;
-// Global variable to indicate that all provisioning data is sent to DSP
-//BOOLEAN fProvComplete;
-
//
// Table of entry-point routines for char device
//
static struct file_operations ft1000fops =
{
- .unlocked_ioctl = ft1000_ChIoctl,
- .poll = ft1000_ChPoll,
- .open = ft1000_ChOpen,
- .release = ft1000_ChRelease,
+ .unlocked_ioctl = ft1000_ioctl,
+ .poll = ft1000_poll_dev,
+ .open = ft1000_open,
+ .release = ft1000_release,
.llseek = no_llseek,
};
-
-
-
-//---------------------------------------------------------------------------
-// Function: exec_mknod
-//
-// Parameters:
-//
-// Returns:
-//
-// Description:
-//
-// Notes:
-//
-//---------------------------------------------------------------------------
-static int exec_mknod (void *pdata)
-{
- struct ft1000_info *info;
- char mjnum[4];
- char minornum[4];
- char temp[32];
- int retcode;
-// int i; //aelias [-] reason : unused variable
- char *envp[] = { "HOME=/", "PATH=/usr/bin:/bin", NULL };
- char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
-
- info = pdata;
- DEBUG("ft1000_chdev:exec_mknod is called with major number = %d\n", info->DeviceMajor);
- sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
- sprintf(mjnum, "%d", info->DeviceMajor);
- sprintf(minornum, "%d", info->CardNumber);
-
- //char *argv[]={"mknod","-m 666",temp,"c",mjnum,minornum,NULL};
-// char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL};
-
- //for (i=0; i<7;i++)
- // DEBUG("argv[%d]=%s\n", i, argv[i]);
-
-
- retcode = call_usermodehelper ("/bin/mknod", argv, envp, 1);
- if (retcode) {
- DEBUG("ft1000_chdev:exec_mknod failed to make the node: retcode = %d\n", retcode);
- }
-
-
-
- return retcode;
-
-}
-
-//---------------------------------------------------------------------------
-// Function: rm_mknod
-//
-// Description: This module removes the FT1000 device file
-//
-//---------------------------------------------------------------------------
-static int rm_mknod (void *pdata)
-{
-
- struct ft1000_info *info;
- //char *argv[4]={"rm", "-f", "/dev/FT1000", NULL};
- int retcode;
- char temp[32];
- char *argv[]={"rm", "-f", temp, NULL};
-
- info = (struct ft1000_info *)pdata;
- DEBUG("ft1000_chdev:rm_mknod is called for device %s\n", info->DeviceName);
- sprintf(temp, "%s%s", "/dev/", info->DeviceName) ;
-
-// char *argv[]={"rm", "-f", temp, NULL};
-
- retcode = call_usermodehelper ("/bin/rm", argv, NULL, 1);
- if (retcode) {
- DEBUG("ft1000_chdev:rm_mknod failed to remove the node: retcode = %d\n", retcode);
- }
- else
- DEBUG("ft1000_chdev:rm_mknod done!\n");
-
-
- return retcode;
-
-}
//---------------------------------------------------------------------------
// Function: ft1000_get_buffer
//
@@ -233,81 +137,55 @@ void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist)
// Notes: Only called by init_module().
//
//---------------------------------------------------------------------------
-int ft1000_CreateDevice(struct ft1000_device *dev)
+int ft1000_create_dev(struct ft1000_device *dev)
{
struct ft1000_info *info = netdev_priv(dev->net);
int result;
int i;
- pid_t pid;
+ struct dentry *dir, *file;
+ struct ft1000_debug_dirs *tmp;
// make a new device name
- sprintf(info->DeviceName, "%s%d", "FT100", info->CardNumber);
-
- // Delete any existing FT1000 node
- pid = kernel_thread (rm_mknod,(void *)info, 0);
- msleep(1000);
+ sprintf(info->DeviceName, "%s%d", "FT1000_", info->CardNumber);
- DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt);
+ DEBUG("%s: number of instance = %d\n", __func__, ft1000_flarion_cnt);
DEBUG("DeviceCreated = %x\n", info->DeviceCreated);
- //save the device info to global array
- pdevobj[info->CardNumber] = dev;
-
- DEBUG("ft1000_CreateDevice: ******SAVED pdevobj[%d]=%p\n", info->CardNumber, pdevobj[info->CardNumber]); //aelias [+] reason:up
-
if (info->DeviceCreated)
{
- DEBUG("ft1000_CreateDevice: \"%s\" already registered\n", info->DeviceName);
+ DEBUG("%s: \"%s\" already registered\n", __func__, info->DeviceName);
return -EIO;
}
// register the device
- DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName);
- info->DeviceMajor = 0;
-
- result = register_chrdev(info->DeviceMajor, info->DeviceName, &ft1000fops);
- if (result < 0)
- {
- DEBUG("ft1000_CreateDevice: unable to get major %d\n", info->DeviceMajor);
- return result;
- }
+ DEBUG("%s: \"%s\" debugfs device registration\n", __func__, info->DeviceName);
- DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName);
-
- // save a dynamic device major number
- if (info->DeviceMajor == 0)
- {
- info->DeviceMajor = result;
- DEBUG("ft1000_PcdCreateDevice: device major = %d\n", info->DeviceMajor);
- }
+ tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL);
+ if (tmp == NULL) {
+ result = -1;
+ goto fail;
+ }
- // Create a thread to call user mode app to mknod
- pid = kernel_thread (exec_mknod, (void *)info, 0);
+ dir = debugfs_create_dir(info->DeviceName, 0);
+ if (IS_ERR(dir)) {
+ result = PTR_ERR(dir);
+ goto debug_dir_fail;
+ }
- // initialize application information
- info->appcnt = 0;
+ file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir,
+ dev, &ft1000fops);
+ if (IS_ERR(file)) {
+ result = PTR_ERR(file);
+ goto debug_file_fail;
+ }
-// if (ft1000_flarion_cnt == 0) {
-//
-// DEBUG("Initialize free_buff_lock and freercvpool\n");
-// spin_lock_init(&free_buff_lock);
-//
-// // initialize a list of buffers to be use for queuing up receive command data
-// INIT_LIST_HEAD (&freercvpool);
-//
-// // create list of free buffers
-// for (i=0; i<NUM_OF_FREE_BUFFERS; i++) {
-// // Get memory for DPRAM_DATA link list
-// pdpram_blk = kmalloc ( sizeof(struct dpram_blk), GFP_KERNEL );
-// // Get a block of memory to store command data
-// pdpram_blk->pbuffer = kmalloc ( MAX_CMD_SQSIZE, GFP_KERNEL );
-// // link provisioning data
-// list_add_tail (&pdpram_blk->list, &freercvpool);
-// }
-// numofmsgbuf = NUM_OF_FREE_BUFFERS;
-// }
+ tmp->dent = dir;
+ tmp->file = file;
+ tmp->int_number = info->CardNumber;
+ list_add(&(tmp->list), &(info->nodes.list));
+ DEBUG("%s: registered debugfs directory \"%s\"\n", __func__, info->DeviceName);
// initialize application information
info->appcnt = 0;
@@ -324,17 +202,17 @@ int ft1000_CreateDevice(struct ft1000_device *dev)
INIT_LIST_HEAD (&info->app_info[i].app_sqlist);
}
-
-
-
-// ft1000Handle[info->CardNumber] = devfs_register(NULL, info->DeviceName, DEVFS_FL_AUTO_DEVNUM, 0, 0,
-// S_IFCHR | S_IRUGO | S_IWUGO, &ft1000fops, NULL);
-
-
info->DeviceCreated = TRUE;
ft1000_flarion_cnt++;
- return result;
+ return 0;
+
+debug_file_fail:
+ debugfs_remove(dir);
+debug_dir_fail:
+ kfree(tmp);
+fail:
+ return result;
}
//---------------------------------------------------------------------------
@@ -347,27 +225,33 @@ int ft1000_CreateDevice(struct ft1000_device *dev)
// Notes: Only called by cleanup_module().
//
//---------------------------------------------------------------------------
-void ft1000_DestroyDevice(struct net_device *dev)
+void ft1000_destroy_dev(struct net_device *dev)
{
struct ft1000_info *info = netdev_priv(dev);
- int result = 0;
- pid_t pid;
int i;
struct dpram_blk *pdpram_blk;
struct dpram_blk *ptr;
+ struct list_head *pos, *q;
+ struct ft1000_debug_dirs *dir;
- DEBUG("ft1000_chdev:ft1000_DestroyDevice called\n");
+ DEBUG("%s called\n", __func__);
if (info->DeviceCreated)
{
ft1000_flarion_cnt--;
- unregister_chrdev(info->DeviceMajor, info->DeviceName);
- DEBUG("ft1000_DestroyDevice: unregistered device \"%s\", result = %d\n",
- info->DeviceName, result);
-
- pid = kernel_thread (rm_mknod, (void *)info, 0);
+ list_for_each_safe(pos, q, &info->nodes.list) {
+ dir = list_entry(pos, struct ft1000_debug_dirs, list);
+ if (dir->int_number == info->CardNumber) {
+ debugfs_remove(dir->file);
+ debugfs_remove(dir->dent);
+ list_del(pos);
+ kfree(dir);
+ }
+ }
+ DEBUG("%s: unregistered device \"%s\"\n", __func__,
+ info->DeviceName);
// Make sure we free any memory reserve for slow Queue
for (i=0; i<MAX_NUM_APP; i++) {
@@ -389,19 +273,14 @@ void ft1000_DestroyDevice(struct net_device *dev)
kfree(ptr);
}
}
-
-// devfs_unregister(ft1000Handle[info->CardNumber]);
-
info->DeviceCreated = FALSE;
-
- pdevobj[info->CardNumber] = NULL;
}
}
//---------------------------------------------------------------------------
-// Function: ft1000_ChOpen
+// Function: ft1000_open
//
// Parameters:
//
@@ -410,28 +289,19 @@ void ft1000_DestroyDevice(struct net_device *dev)
// Notes:
//
//---------------------------------------------------------------------------
-static int ft1000_ChOpen (struct inode *Inode, struct file *File)
+static int ft1000_open (struct inode *inode, struct file *file)
{
struct ft1000_info *info;
+ struct ft1000_device *dev = (struct ft1000_device *)inode->i_private;
int i,num;
- DEBUG("ft1000_ChOpen called\n");
- num = (MINOR(Inode->i_rdev) & 0xf);
- DEBUG("ft1000_ChOpen: minor number=%d\n", num);
+ DEBUG("%s called\n", __func__);
+ num = (MINOR(inode->i_rdev) & 0xf);
+ DEBUG("ft1000_open: minor number=%d\n", num);
- for (i=0; i<5; i++)
- DEBUG("pdevobj[%d]=%p\n", i, pdevobj[i]); //aelias [+] reason: down
+ info = file->private_data = netdev_priv(dev->net);
- if ( pdevobj[num] != NULL )
- //info = (struct ft1000_info *)(pdevobj[num]->net->priv);
- info = (struct ft1000_info *)netdev_priv(pdevobj[num]->net);
- else
- {
- DEBUG("ft1000_ChOpen: can not find device object %d\n", num);
- return -1;
- }
-
- DEBUG("f_owner = %p number of application = %d\n", (&File->f_owner), info->appcnt );
+ DEBUG("f_owner = %p number of application = %d\n", (&file->f_owner), info->appcnt );
// Check if maximum number of application exceeded
if (info->appcnt > MAX_NUM_APP) {
@@ -453,21 +323,19 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File)
}
info->appcnt++;
- info->app_info[i].fileobject = &File->f_owner;
+ info->app_info[i].fileobject = &file->f_owner;
info->app_info[i].nTxMsg = 0;
info->app_info[i].nRxMsg = 0;
info->app_info[i].nTxMsgReject = 0;
info->app_info[i].nRxMsgMiss = 0;
- File->private_data = pdevobj[num]->net;
-
- nonseekable_open(Inode, File);
+ nonseekable_open(inode, file);
return 0;
}
//---------------------------------------------------------------------------
-// Function: ft1000_ChPoll
+// Function: ft1000_poll_dev
//
// Parameters:
//
@@ -477,47 +345,47 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File)
//
//---------------------------------------------------------------------------
-static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait)
+static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait)
{
struct net_device *dev = file->private_data;
struct ft1000_info *info;
int i;
- //DEBUG("ft1000_ChPoll called\n");
+ //DEBUG("ft1000_poll_dev called\n");
if (ft1000_flarion_cnt == 0) {
- DEBUG("FT1000:ft1000_ChPoll called when ft1000_flarion_cnt is zero\n");
+ DEBUG("FT1000:ft1000_poll_dev called when ft1000_flarion_cnt is zero\n");
return (-EBADF);
}
- info = (struct ft1000_info *) netdev_priv(dev);
+ info = netdev_priv(dev);
// Search for matching file object
for (i=0; i<MAX_NUM_APP; i++) {
if ( info->app_info[i].fileobject == &file->f_owner) {
- //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id);
break;
}
}
// Could not find application info block
if (i == MAX_NUM_APP) {
- DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
+ DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n");
return ( -EACCES );
}
if (list_empty(&info->app_info[i].app_sqlist) == 0) {
- DEBUG("FT1000:ft1000_ChPoll:Message detected in slow queue\n");
+ DEBUG("FT1000:ft1000_poll_dev:Message detected in slow queue\n");
return(POLLIN | POLLRDNORM | POLLPRI);
}
poll_wait (file, &info->app_info[i].wait_dpram_msg, wait);
- //DEBUG("FT1000:ft1000_ChPoll:Polling for data from DSP\n");
+ //DEBUG("FT1000:ft1000_poll_dev:Polling for data from DSP\n");
return (0);
}
//---------------------------------------------------------------------------
-// Function: ft1000_ChIoctl
+// Function: ft1000_ioctl
//
// Parameters:
//
@@ -526,11 +394,10 @@ static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait)
// Notes:
//
//---------------------------------------------------------------------------
-static long ft1000_ChIoctl (struct file *File, unsigned int Command,
- unsigned long Argument)
+static long ft1000_ioctl (struct file *file, unsigned int command,
+ unsigned long argument)
{
- void __user *argp = (void __user *)Argument;
- struct net_device *dev;
+ void __user *argp = (void __user *)argument;
struct ft1000_info *info;
struct ft1000_device *ft1000dev;
int result=0;
@@ -551,25 +418,24 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
unsigned short ledStat=0;
unsigned short conStat=0;
- //DEBUG("ft1000_ChIoctl called\n");
+ //DEBUG("ft1000_ioctl called\n");
if (ft1000_flarion_cnt == 0) {
- DEBUG("FT1000:ft1000_ChIoctl called when ft1000_flarion_cnt is zero\n");
+ DEBUG("FT1000:ft1000_ioctl called when ft1000_flarion_cnt is zero\n");
return (-EBADF);
}
- //DEBUG("FT1000:ft1000_ChIoctl:Command = 0x%x Argument = 0x%8x\n", Command, (u32)Argument);
+ //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument);
- dev = File->private_data;
- info = (struct ft1000_info *) netdev_priv(dev);
- ft1000dev = info->pFt1000Dev;
- cmd = _IOC_NR(Command);
- //DEBUG("FT1000:ft1000_ChIoctl:cmd = 0x%x\n", cmd);
+ info = file->private_data;
+ ft1000dev = info->pFt1000Dev;
+ cmd = _IOC_NR(command);
+ //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd);
// process the command
switch (cmd) {
case IOCTL_REGISTER_CMD:
- DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_REGISTER called\n");
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_REGISTER called\n");
result = get_user(tempword, (__u16 __user*)argp);
if (result) {
DEBUG("result = %d failed to get_user\n", result);
@@ -578,9 +444,9 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
if (tempword == DSPBCMSGID) {
// Search for matching file object
for (i=0; i<MAX_NUM_APP; i++) {
- if ( info->app_info[i].fileobject == &File->f_owner) {
+ if ( info->app_info[i].fileobject == &file->f_owner) {
info->app_info[i].DspBCMsgFlag = 1;
- DEBUG("FT1000:ft1000_ChIoctl:Registered for broadcast messages\n");
+ DEBUG("FT1000:ft1000_ioctl:Registered for broadcast messages\n");
break;
}
}
@@ -588,34 +454,34 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
break;
case IOCTL_GET_VER_CMD:
- DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_VER called\n");
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_VER called\n");
get_ver_data.drv_ver = FT1000_DRV_VER;
if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data)) ) {
- DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
result = -EFAULT;
break;
}
- DEBUG("FT1000:ft1000_ChIoctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver);
+ DEBUG("FT1000:ft1000_ioctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver);
break;
case IOCTL_CONNECT:
// Connect Message
- DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_CONNECT\n");
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_CONNECT\n");
ConnectionMsg[79] = 0xfc;
CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
break;
case IOCTL_DISCONNECT:
// Disconnect Message
- DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_DISCONNECT\n");
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_DISCONNECT\n");
ConnectionMsg[79] = 0xfd;
CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
break;
case IOCTL_GET_DSP_STAT_CMD:
- //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DSP_STAT called\n");
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DSP_STAT called\n");
memset(&get_stat_data, 0, sizeof(get_stat_data));
memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
@@ -623,12 +489,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
memcpy(get_stat_data.eui64, info->eui64, EUISZ);
if (info->ProgConStat != 0xFF) {
- ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (PUCHAR)&ledStat, FT1000_MAG_DSP_LED_INDX);
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
get_stat_data.LedStat = ntohs(ledStat);
- DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat);
- ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (PUCHAR)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+ DEBUG("FT1000:ft1000_ioctl: LedStat = 0x%x\n", get_stat_data.LedStat);
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
get_stat_data.ConStat = ntohs(conStat);
- DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat);
+ DEBUG("FT1000:ft1000_ioctl: ConStat = 0x%x\n", get_stat_data.ConStat);
}
else {
get_stat_data.ConStat = 0x0f;
@@ -643,7 +509,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm);
if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data)) ) {
- DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
result = -EFAULT;
break;
}
@@ -651,17 +517,17 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
break;
case IOCTL_SET_DPRAM_CMD:
{
- IOCTL_DPRAM_BLK *dpram_data;
+ IOCTL_DPRAM_BLK *dpram_data = NULL;
//IOCTL_DPRAM_COMMAND dpram_command;
- USHORT qtype;
- USHORT msgsz;
+ u16 qtype;
+ u16 msgsz;
struct pseudo_hdr *ppseudo_hdr;
- PUSHORT pmsg;
- USHORT total_len;
- USHORT app_index;
+ u16 *pmsg;
+ u16 total_len;
+ u16 app_index;
u16 status;
- //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n");
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_SET_DPRAM called\n");
if (ft1000_flarion_cnt == 0) {
@@ -680,15 +546,15 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
if (info->CardReady) {
- //DEBUG("FT1000:ft1000_ChIoctl: try to SET_DPRAM \n");
+ //DEBUG("FT1000:ft1000_ioctl: try to SET_DPRAM \n");
// Get the length field to see how many bytes to copy
result = get_user(msgsz, (__u16 __user *)argp);
msgsz = ntohs (msgsz);
- //DEBUG("FT1000:ft1000_ChIoctl: length of message = %d\n", msgsz);
+ //DEBUG("FT1000:ft1000_ioctl: length of message = %d\n", msgsz);
if (msgsz > MAX_CMD_SQSIZE) {
- DEBUG("FT1000:ft1000_ChIoctl: bad message length = %d\n", msgsz);
+ DEBUG("FT1000:ft1000_ioctl: bad message length = %d\n", msgsz);
result = -EINVAL;
break;
}
@@ -698,22 +564,14 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
if (!dpram_data)
break;
- //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) {
- if ( copy_from_user(&dpram_data, argp, msgsz+2) ) {
+ if ( copy_from_user(dpram_data, argp, msgsz+2) ) {
DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
result = -EFAULT;
}
else {
-#if 0
- // whc - for debugging only
- ptr = (char *)&dpram_data;
- for (i=0; i<msgsz; i++) {
- DEBUG(1,"FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
- }
-#endif
// Check if this message came from a registered application
for (i=0; i<MAX_NUM_APP; i++) {
- if ( info->app_info[i].fileobject == &File->f_owner) {
+ if ( info->app_info[i].fileobject == &file->f_owner) {
break;
}
}
@@ -726,16 +584,15 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
app_index = i;
// Check message qtype type which is the lower byte within qos_class
- //qtype = ntohs(dpram_command.dpram_blk.pseudohdr.qos_class) & 0xff;
qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff;
- //DEBUG("FT1000_ft1000_ChIoctl: qtype = %d\n", qtype);
+ //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype);
if (qtype) {
}
else {
// Put message into Slow Queue
// Only put a message into the DPRAM if msg doorbell is available
status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
- //DEBUG("FT1000_ft1000_ChIoctl: READ REGISTER tempword=%x\n", tempword);
+ //DEBUG("FT1000_ft1000_ioctl: READ REGISTER tempword=%x\n", tempword);
if (tempword & FT1000_DB_DPRAM_TX) {
// Suspend for 2ms and try again due to DSP doorbell busy
mdelay(2);
@@ -751,7 +608,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
mdelay(3);
status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
if (tempword & FT1000_DB_DPRAM_TX) {
- DEBUG("FT1000:ft1000_ChIoctl:Doorbell not available\n");
+ DEBUG("FT1000:ft1000_ioctl:Doorbell not available\n");
result = -ENOTTY;
kfree(dpram_data);
break;
@@ -761,13 +618,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
}
}
- //DEBUG("FT1000_ft1000_ChIoctl: finished reading register\n");
+ //DEBUG("FT1000_ft1000_ioctl: finished reading register\n");
// Make sure we are within the limits of the slow queue memory limitation
if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) {
// Need to put sequence number plus new checksum for message
- //pmsg = (PUSHORT)&dpram_command.dpram_blk.pseudohdr;
- pmsg = (PUSHORT)&dpram_data->pseudohdr;
+ pmsg = (u16 *)&dpram_data->pseudohdr;
ppseudo_hdr = (struct pseudo_hdr *)pmsg;
total_len = msgsz+2;
if (total_len & 0x1) {
@@ -786,17 +642,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
}
pmsg++;
ppseudo_hdr = (struct pseudo_hdr *)pmsg;
-#if 0
- ptr = dpram_data;
- DEBUG("FT1000:ft1000_ChIoctl: Command Send\n");
- for (i=0; i<total_len; i++) {
- DEBUG("FT1000:ft1000_ChIoctl: data %d = 0x%x\n", i, *ptr++);
- }
-#endif
- //dpram_command.extra = 0;
-
- //CardSendCommand(ft1000dev,(unsigned char*)&dpram_command,total_len+2);
- CardSendCommand(ft1000dev,(unsigned short*)dpram_data,total_len+2);
+ CardSendCommand(ft1000dev,(unsigned short*)dpram_data,total_len+2);
info->app_info[app_index].nTxMsg++;
@@ -808,7 +654,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
}
}
else {
- DEBUG("FT1000:ft1000_ChIoctl: Card not ready take messages\n");
+ DEBUG("FT1000:ft1000_ioctl: Card not ready take messages\n");
result = -EACCES;
}
kfree(dpram_data);
@@ -821,7 +667,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
IOCTL_DPRAM_BLK __user *pioctl_dpram;
int msglen;
- //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM called\n");
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM called\n");
if (ft1000_flarion_cnt == 0) {
return (-EBADF);
@@ -829,15 +675,15 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
// Search for matching file object
for (i=0; i<MAX_NUM_APP; i++) {
- if ( info->app_info[i].fileobject == &File->f_owner) {
- //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
+ if ( info->app_info[i].fileobject == &file->f_owner) {
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id);
break;
}
}
// Could not find application info block
if (i == MAX_NUM_APP) {
- DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n");
+ DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n");
result = -EBADF;
break;
}
@@ -845,22 +691,22 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
result = 0;
pioctl_dpram = argp;
if (list_empty(&info->app_info[i].app_sqlist) == 0) {
- //DEBUG("FT1000:ft1000_ChIoctl:Message detected in slow queue\n");
+ //DEBUG("FT1000:ft1000_ioctl:Message detected in slow queue\n");
spin_lock_irqsave(&free_buff_lock, flags);
pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list);
list_del(&pdpram_blk->list);
info->app_info[i].NumOfMsg--;
- //DEBUG("FT1000:ft1000_ChIoctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg);
+ //DEBUG("FT1000:ft1000_ioctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg);
spin_unlock_irqrestore(&free_buff_lock, flags);
msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
result = get_user(msglen, &pioctl_dpram->total_len);
if (result)
break;
msglen = htons(msglen);
- //DEBUG("FT1000:ft1000_ChIoctl:msg length = %x\n", msglen);
+ //DEBUG("FT1000:ft1000_ioctl:msg length = %x\n", msglen);
if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen))
{
- DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
result = -EFAULT;
break;
}
@@ -868,12 +714,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
ft1000_free_buffer(pdpram_blk, &freercvpool);
result = msglen;
}
- //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM no message\n");
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM no message\n");
}
break;
default:
- DEBUG("FT1000:ft1000_ChIoctl:unknown command: 0x%x\n", Command);
+ DEBUG("FT1000:ft1000_ioctl:unknown command: 0x%x\n", command);
result = -ENOTTY;
break;
}
@@ -882,7 +728,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
}
//---------------------------------------------------------------------------
-// Function: ft1000_ChRelease
+// Function: ft1000_release
//
// Parameters:
//
@@ -891,17 +737,17 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
// Notes:
//
//---------------------------------------------------------------------------
-static int ft1000_ChRelease (struct inode *Inode, struct file *File)
+static int ft1000_release (struct inode *inode, struct file *file)
{
struct ft1000_info *info;
struct net_device *dev;
int i;
struct dpram_blk *pdpram_blk;
- DEBUG("ft1000_ChRelease called\n");
+ DEBUG("ft1000_release called\n");
- dev = File->private_data;
- info = (struct ft1000_info *) netdev_priv(dev);
+ dev = file->private_data;
+ info = netdev_priv(dev);
if (ft1000_flarion_cnt == 0) {
info->appcnt--;
@@ -910,8 +756,8 @@ static int ft1000_ChRelease (struct inode *Inode, struct file *File)
// Search for matching file object
for (i=0; i<MAX_NUM_APP; i++) {
- if ( info->app_info[i].fileobject == &File->f_owner) {
- //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id);
+ if ( info->app_info[i].fileobject == &file->f_owner) {
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id);
break;
}
}
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c
index 4dd456fbab9b..17546d8ec08d 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c
@@ -123,11 +123,11 @@ struct dsp_image_info {
// Notes:
//
//---------------------------------------------------------------------------
-static ULONG check_usb_db (struct ft1000_device *ft1000dev)
+static u32 check_usb_db (struct ft1000_device *ft1000dev)
{
int loopcnt;
- USHORT temp;
- ULONG status;
+ u16 temp;
+ u32 status;
loopcnt = 0;
while (loopcnt < 10)
@@ -190,7 +190,7 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev)
// Function: get_handshake
//
// Parameters: struct ft1000_device - device structure
-// USHORT expected_value - the handshake value expected
+// u16 expected_value - the handshake value expected
//
// Returns: handshakevalue - success
// HANDSHAKE_TIMEOUT_VALUE - failure
@@ -200,11 +200,11 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev)
// Notes:
//
//---------------------------------------------------------------------------
-static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_value)
+static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value)
{
- USHORT handshake;
+ u16 handshake;
int loopcnt;
- ULONG status=0;
+ u32 status=0;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
loopcnt = 0;
@@ -228,7 +228,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL);
}
- status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+ status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
//DEBUG("get_handshake: handshake is %x\n", tempx);
handshake = ntohs(handshake);
//DEBUG("get_handshake: after swap, handshake is %x\n", handshake);
@@ -259,7 +259,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
// Function: put_handshake
//
// Parameters: struct ft1000_device - device structure
-// USHORT handshake_value - handshake to be written
+// u16 handshake_value - handshake to be written
//
// Returns: none
//
@@ -269,30 +269,30 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
// Notes:
//
//---------------------------------------------------------------------------
-static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value)
+static void put_handshake(struct ft1000_device *ft1000dev,u16 handshake_value)
{
- ULONG tempx;
- USHORT tempword;
- ULONG status;
+ u32 tempx;
+ u16 tempword;
+ u32 status;
- tempx = (ULONG)handshake_value;
+ tempx = (u32)handshake_value;
tempx = ntohl(tempx);
- tempword = (USHORT)(tempx & 0xffff);
+ tempword = (u16)(tempx & 0xffff);
status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 0);
- tempword = (USHORT)(tempx >> 16);
+ tempword = (u16)(tempx >> 16);
status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 1);
status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL);
}
-static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected_value)
+static u16 get_handshake_usb(struct ft1000_device *ft1000dev, u16 expected_value)
{
- USHORT handshake;
+ u16 handshake;
int loopcnt;
- USHORT temp;
- ULONG status=0;
+ u16 temp;
+ u32 status=0;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
loopcnt = 0;
@@ -300,10 +300,10 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
while (loopcnt < 100)
{
if (pft1000info->usbboot == 2) {
- status = ft1000_read_dpram32 (ft1000dev, 0, (PUCHAR)&(pft1000info->tempbuf[0]), 64);
+ status = ft1000_read_dpram32 (ft1000dev, 0, (u8 *)&(pft1000info->tempbuf[0]), 64);
for (temp=0; temp<16; temp++)
DEBUG("tempbuf %d = 0x%x\n", temp, pft1000info->tempbuf[temp]);
- status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+ status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
DEBUG("handshake from read_dpram16 = 0x%x\n", handshake);
if (pft1000info->dspalive == pft1000info->tempbuf[6])
handshake = 0;
@@ -313,7 +313,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
}
}
else {
- status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+ status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
}
loopcnt++;
msleep(10);
@@ -327,7 +327,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
return HANDSHAKE_TIMEOUT_VALUE;
}
-static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_value)
+static void put_handshake_usb(struct ft1000_device *ft1000dev,u16 handshake_value)
{
int i;
@@ -346,44 +346,44 @@ static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_v
// Notes:
//
//---------------------------------------------------------------------------
-static USHORT get_request_type(struct ft1000_device *ft1000dev)
+static u16 get_request_type(struct ft1000_device *ft1000dev)
{
- USHORT request_type;
- ULONG status;
- USHORT tempword;
- ULONG tempx;
+ u16 request_type;
+ u32 status;
+ u16 tempword;
+ u32 tempx;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
if ( pft1000info->bootmode == 1)
{
- status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx);
+ status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
tempx = ntohl(tempx);
}
else
{
tempx = 0;
- status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1);
+ status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
tempx |= (tempword << 16);
tempx = ntohl(tempx);
}
- request_type = (USHORT)tempx;
+ request_type = (u16)tempx;
//DEBUG("get_request_type: request_type is %x\n", request_type);
return request_type;
}
-static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
+static u16 get_request_type_usb(struct ft1000_device *ft1000dev)
{
- USHORT request_type;
- ULONG status;
- USHORT tempword;
- ULONG tempx;
+ u16 request_type;
+ u32 status;
+ u16 tempword;
+ u32 tempx;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
if ( pft1000info->bootmode == 1)
{
- status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx);
+ status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
tempx = ntohl(tempx);
}
else
@@ -394,12 +394,12 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
}
else {
tempx = 0;
- status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1);
+ status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
}
tempx |= (tempword << 16);
tempx = ntohl(tempx);
}
- request_type = (USHORT)tempx;
+ request_type = (u16)tempx;
//DEBUG("get_request_type: request_type is %x\n", request_type);
return request_type;
@@ -420,22 +420,22 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
//---------------------------------------------------------------------------
static long get_request_value(struct ft1000_device *ft1000dev)
{
- ULONG value;
- USHORT tempword;
- ULONG status;
+ u32 value;
+ u16 tempword;
+ u32 status;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
if ( pft1000info->bootmode == 1)
{
- status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&value);
+ status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&value);
value = ntohl(value);
}
else
{
- status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 0);
+ status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0);
value = tempword;
- status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1);
+ status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
value |= (tempword << 16);
value = ntohl(value);
}
@@ -449,9 +449,9 @@ static long get_request_value(struct ft1000_device *ft1000dev)
#if 0
static long get_request_value_usb(struct ft1000_device *ft1000dev)
{
- ULONG value;
- USHORT tempword;
- ULONG status;
+ u32 value;
+ u16 tempword;
+ u32 status;
struct ft1000_info * pft1000info = netdev_priv(ft1000dev->net);
if (pft1000info->usbboot == 2) {
@@ -460,7 +460,7 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev)
}
else {
value = 0;
- status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1);
+ status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
}
value |= (tempword << 16);
@@ -490,11 +490,11 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev)
//---------------------------------------------------------------------------
static void put_request_value(struct ft1000_device *ft1000dev, long lvalue)
{
- ULONG tempx;
- ULONG status;
+ u32 tempx;
+ u32 status;
tempx = ntohl(lvalue);
- status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempx);
+ status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempx);
@@ -516,10 +516,10 @@ static void put_request_value(struct ft1000_device *ft1000dev, long lvalue)
// Notes:
//
//---------------------------------------------------------------------------
-static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
+static u16 hdr_checksum(struct pseudo_hdr *pHdr)
{
- USHORT *usPtr = (USHORT *)pHdr;
- USHORT chksum;
+ u16 *usPtr = (u16 *)pHdr;
+ u16 chksum;
chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
@@ -533,8 +533,8 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
// Function: write_blk
//
// Parameters: struct ft1000_device - device structure
-// USHORT **pUsFile - DSP image file pointer in USHORT
-// UCHAR **pUcFile - DSP image file pointer in UCHAR
+// u16 **pUsFile - DSP image file pointer in u16
+// u8 **pUcFile - DSP image file pointer in u8
// long word_length - lenght of the buffer to be written
// to DPRAM
//
@@ -546,20 +546,20 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
// Notes:
//
//---------------------------------------------------------------------------
-static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length)
+static u32 write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
{
- ULONG Status = STATUS_SUCCESS;
- USHORT dpram;
+ u32 Status = STATUS_SUCCESS;
+ u16 dpram;
long temp_word_length;
int loopcnt, i, j;
- USHORT *pTempFile;
- USHORT tempword;
- USHORT tempbuffer[64];
- USHORT resultbuffer[64];
+ u16 *pTempFile;
+ u16 tempword;
+ u16 tempbuffer[64];
+ u16 resultbuffer[64];
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
//DEBUG("FT1000:download:start word_length = %d\n",(int)word_length);
- dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
tempword = *(*pUsFile);
(*pUsFile)++;
Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0);
@@ -569,7 +569,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
*pUcFile = *pUcFile + 4;
word_length--;
- tempword = (USHORT)word_length;
+ tempword = (u16)word_length;
word_length = (word_length / 16) + 1;
pTempFile = *pUsFile;
temp_word_length = word_length;
@@ -602,24 +602,24 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
if (pft1000info->bootmode == 0)
{
if (dpram >= 0x3F4)
- Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 8);
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8);
else
- Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64);
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
}
else
{
for (j=0; j<10; j++)
{
- Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64);
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
if (Status == STATUS_SUCCESS)
{
// Work around for ASIC bit stuffing problem.
if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
{
- Status = ft1000_write_dpram32(ft1000dev, dpram+12, (PUCHAR)&tempbuffer[24], 64);
+ Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64);
}
// Let's check the data written
- Status = ft1000_read_dpram32 (ft1000dev, dpram, (PUCHAR)&resultbuffer[0], 64);
+ Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64);
if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
{
for (i=0; i<28; i++)
@@ -633,7 +633,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
break;
}
}
- Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (PUCHAR)&resultbuffer[0], 64);
+ Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64);
for (i=0; i<16; i++)
{
if (resultbuffer[i] != tempbuffer[i+24])
@@ -689,8 +689,8 @@ static void usb_dnld_complete (struct urb *urb)
// Function: write_blk_fifo
//
// Parameters: struct ft1000_device - device structure
-// USHORT **pUsFile - DSP image file pointer in USHORT
-// UCHAR **pUcFile - DSP image file pointer in UCHAR
+// u16 **pUsFile - DSP image file pointer in u16
+// u8 **pUcFile - DSP image file pointer in u8
// long word_length - lenght of the buffer to be written
// to DPRAM
//
@@ -702,9 +702,9 @@ static void usb_dnld_complete (struct urb *urb)
// Notes:
//
//---------------------------------------------------------------------------
-static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length)
+static u32 write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
{
- ULONG Status = STATUS_SUCCESS;
+ u32 Status = STATUS_SUCCESS;
int byte_length;
long aligncnt;
@@ -770,36 +770,36 @@ static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile,
// Returns: status - return code
//---------------------------------------------------------------------------
-u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength)
+u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength)
{
- u16 Status = STATUS_SUCCESS;
- UINT uiState;
- USHORT handshake;
- struct pseudo_hdr *pHdr;
- USHORT usHdrLength;
+ u16 status = STATUS_SUCCESS;
+ u32 state;
+ u16 handshake;
+ struct pseudo_hdr *pseudo_header;
+ u16 pseudo_header_len;
long word_length;
- USHORT request;
- USHORT temp;
- USHORT tempword;
+ u16 request;
+ u16 temp;
+ u16 tempword;
- struct dsp_file_hdr *pFileHdr5;
- struct dsp_image_info *pDspImageInfoV6 = NULL;
+ struct dsp_file_hdr *file_hdr;
+ struct dsp_image_info *dsp_img_info = NULL;
long requested_version;
- BOOLEAN bGoodVersion;
- struct drv_msg *pMailBoxData;
- USHORT *pUsData = NULL;
- USHORT *pUsFile = NULL;
- UCHAR *pUcFile = NULL;
- UCHAR *pBootEnd = NULL, *pCodeEnd= NULL;
- int imageN;
+ bool correct_version;
+ struct drv_msg *mailbox_data;
+ u16 *data = NULL;
+ u16 *s_file = NULL;
+ u8 *c_file = NULL;
+ u8 *boot_end = NULL, *code_end= NULL;
+ int image;
long loader_code_address, loader_code_size = 0;
long run_address = 0, run_size = 0;
- ULONG templong;
- ULONG image_chksum = 0;
+ u32 templong;
+ u32 image_chksum = 0;
- USHORT dpram = 0;
- PUCHAR pbuffer;
+ u16 dpram = 0;
+ u8 *pbuffer;
struct prov_record *pprov_record;
struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
@@ -814,24 +814,24 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
// Get version id of file, at first 4 bytes of file, for newer files.
//
- uiState = STATE_START_DWNLD;
+ state = STATE_START_DWNLD;
- pFileHdr5 = (struct dsp_file_hdr *)pFileStart;
+ file_hdr = (struct dsp_file_hdr *)pFileStart;
ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK);
- pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset);
- pUcFile = (UCHAR *)(pFileStart + pFileHdr5->loader_offset);
+ s_file = (u16 *)(pFileStart + file_hdr->loader_offset);
+ c_file = (u8 *)(pFileStart + file_hdr->loader_offset);
- pBootEnd = (UCHAR *)(pFileStart + pFileHdr5->loader_code_end);
+ boot_end = (u8 *)(pFileStart + file_hdr->loader_code_end);
- loader_code_address = pFileHdr5->loader_code_address;
- loader_code_size = pFileHdr5->loader_code_size;
- bGoodVersion = FALSE;
+ loader_code_address = file_hdr->loader_code_address;
+ loader_code_size = file_hdr->loader_code_size;
+ correct_version = FALSE;
- while ((Status == STATUS_SUCCESS) && (uiState != STATE_DONE_FILE))
+ while ((status == STATUS_SUCCESS) && (state != STATE_DONE_FILE))
{
- switch (uiState)
+ switch (state)
{
case STATE_START_DWNLD:
DEBUG("FT1000:STATE_START_DWNLD\n");
@@ -848,10 +848,10 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
else
{
DEBUG("FT1000:download:Download error: Handshake failed\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
- uiState = STATE_BOOT_DWNLD;
+ state = STATE_BOOT_DWNLD;
break;
@@ -878,11 +878,11 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
case REQUEST_DONE_BL:
DEBUG("FT1000:REQUEST_DONE_BL\n");
/* Reposition ptrs to beginning of code section */
- pUsFile = (USHORT *)(pBootEnd);
- pUcFile = (UCHAR *)(pBootEnd);
- //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile);
- //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile);
- uiState = STATE_CODE_DWNLD;
+ s_file = (u16 *)(boot_end);
+ c_file = (u8 *)(boot_end);
+ //DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file);
+ //DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file);
+ state = STATE_CODE_DWNLD;
pft1000info->fcodeldr = 1;
break;
case REQUEST_CODE_SEGMENT:
@@ -893,33 +893,33 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
if (word_length > MAX_LENGTH)
{
DEBUG("FT1000:download:Download error: Max length exceeded\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
- if ( (word_length*2 + pUcFile) > pBootEnd)
+ if ( (word_length*2 + c_file) > boot_end)
{
/*
* Error, beyond boot code range.
*/
DEBUG("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n",
(int)word_length);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
/*
* Position ASIC DPRAM auto-increment pointer.
*/
- dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
if (word_length & 0x1)
word_length++;
word_length = word_length / 2;
- Status = write_blk(ft1000dev, &pUsFile, &pUcFile, word_length);
- //DEBUG("write_blk returned %d\n", Status);
+ status = write_blk(ft1000dev, &s_file, &c_file, word_length);
+ //DEBUG("write_blk returned %d\n", status);
break;
default:
DEBUG("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",request);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
if (pft1000info->usbboot)
@@ -930,7 +930,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
else
{
DEBUG("FT1000:download:Download error: Handshake failed\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
break;
@@ -959,7 +959,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
break;
case REQUEST_RUN_ADDRESS:
DEBUG("FT1000:download: REQUEST_RUN_ADDRESS\n");
- if (bGoodVersion)
+ if (correct_version)
{
DEBUG("FT1000:download:run_address = 0x%8x\n", (int)run_address);
put_request_value(ft1000dev, run_address);
@@ -967,13 +967,13 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
else
{
DEBUG("FT1000:download:Download error: Got Run address request before image offset request.\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
break;
case REQUEST_CODE_LENGTH:
DEBUG("FT1000:download:REQUEST_CODE_LENGTH\n");
- if (bGoodVersion)
+ if (correct_version)
{
DEBUG("FT1000:download:run_size = 0x%8x\n", (int)run_size);
put_request_value(ft1000dev, run_size);
@@ -981,23 +981,23 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
else
{
DEBUG("FT1000:download:Download error: Got Size request before image offset request.\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
break;
case REQUEST_DONE_CL:
pft1000info->usbboot = 3;
/* Reposition ptrs to beginning of provisioning section */
- pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset);
- pUcFile = (UCHAR *)(pFileStart + pFileHdr5->commands_offset);
- uiState = STATE_DONE_DWNLD;
+ s_file = (u16 *)(pFileStart + file_hdr->commands_offset);
+ c_file = (u8 *)(pFileStart + file_hdr->commands_offset);
+ state = STATE_DONE_DWNLD;
break;
case REQUEST_CODE_SEGMENT:
//DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n");
- if (!bGoodVersion)
+ if (!correct_version)
{
DEBUG("FT1000:download:Download error: Got Code Segment request before image offset request.\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
#if 0
@@ -1011,28 +1011,28 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
#endif
{
DEBUG("FT1000:download:Download error: Max length exceeded\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
- if ( (word_length*2 + pUcFile) > pCodeEnd)
+ if ( (word_length*2 + c_file) > code_end)
{
/*
* Error, beyond boot code range.
*/
DEBUG("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n",
(int)word_length);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
/*
* Position ASIC DPRAM auto-increment pointer.
*/
- dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
if (word_length & 0x1)
word_length++;
word_length = word_length / 2;
- write_blk_fifo (ft1000dev, &pUsFile, &pUcFile, word_length);
+ write_blk_fifo (ft1000dev, &s_file, &c_file, word_length);
if (pft1000info->usbboot == 0)
pft1000info->usbboot++;
if (pft1000info->usbboot == 1) {
@@ -1047,14 +1047,14 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
// Convert length from byte count to word count. Make sure we round up.
word_length = (long)(pft1000info->DSPInfoBlklen + 1)/2;
put_request_value(ft1000dev, word_length);
- pMailBoxData = (struct drv_msg *)&(pft1000info->DSPInfoBlk[0]);
+ mailbox_data = (struct drv_msg *)&(pft1000info->DSPInfoBlk[0]);
/*
* Position ASIC DPRAM auto-increment pointer.
*/
- pUsData = (USHORT *)&pMailBoxData->data[0];
- dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+ data = (u16 *)&mailbox_data->data[0];
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
if (word_length & 0x1)
word_length++;
@@ -1064,25 +1064,25 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
for (; word_length > 0; word_length--) /* In words */
{
- templong = *pUsData++;
- templong |= (*pUsData++ << 16);
- Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong);
+ templong = *data++;
+ templong |= (*data++ << 16);
+ status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong);
}
break;
case REQUEST_VERSION_INFO:
DEBUG("FT1000:download:REQUEST_VERSION_INFO\n");
- word_length = pFileHdr5->version_data_size;
+ word_length = file_hdr->version_data_size;
put_request_value(ft1000dev, word_length);
/*
* Position ASIC DPRAM auto-increment pointer.
*/
- pUsFile = (USHORT *)(pFileStart + pFileHdr5->version_data_offset);
+ s_file = (u16 *)(pFileStart + file_hdr->version_data_offset);
- dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
if (word_length & 0x1)
word_length++;
@@ -1092,59 +1092,59 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
for (; word_length > 0; word_length--) /* In words */
{
- templong = ntohs(*pUsFile++);
- temp = ntohs(*pUsFile++);
+ templong = ntohs(*s_file++);
+ temp = ntohs(*s_file++);
templong |= (temp << 16);
- Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong);
+ status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong);
}
break;
case REQUEST_CODE_BY_VERSION:
DEBUG("FT1000:download:REQUEST_CODE_BY_VERSION\n");
- bGoodVersion = FALSE;
+ correct_version = FALSE;
requested_version = get_request_value(ft1000dev);
- pDspImageInfoV6 = (struct dsp_image_info *)(pFileStart + sizeof(struct dsp_file_hdr ));
+ dsp_img_info = (struct dsp_image_info *)(pFileStart + sizeof(struct dsp_file_hdr ));
- for (imageN = 0; imageN < pFileHdr5->nDspImages; imageN++)
+ for (image = 0; image < file_hdr->nDspImages; image++)
{
- temp = (USHORT)(pDspImageInfoV6->version);
+ temp = (u16)(dsp_img_info->version);
templong = temp;
- temp = (USHORT)(pDspImageInfoV6->version >> 16);
+ temp = (u16)(dsp_img_info->version >> 16);
templong |= (temp << 16);
- if (templong == (ULONG)requested_version)
+ if (templong == (u32)requested_version)
{
- bGoodVersion = TRUE;
- DEBUG("FT1000:download: bGoodVersion is TRUE\n");
- pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset);
- pUcFile = (UCHAR *)(pFileStart + pDspImageInfoV6->begin_offset);
- pCodeEnd = (UCHAR *)(pFileStart + pDspImageInfoV6->end_offset);
- run_address = pDspImageInfoV6->run_address;
- run_size = pDspImageInfoV6->image_size;
- image_chksum = (ULONG)pDspImageInfoV6->checksum;
+ correct_version = TRUE;
+ DEBUG("FT1000:download: correct_version is TRUE\n");
+ s_file = (u16 *)(pFileStart + dsp_img_info->begin_offset);
+ c_file = (u8 *)(pFileStart + dsp_img_info->begin_offset);
+ code_end = (u8 *)(pFileStart + dsp_img_info->end_offset);
+ run_address = dsp_img_info->run_address;
+ run_size = dsp_img_info->image_size;
+ image_chksum = (u32)dsp_img_info->checksum;
break;
}
- pDspImageInfoV6++;
+ dsp_img_info++;
} //end of for
- if (!bGoodVersion)
+ if (!correct_version)
{
/*
* Error, beyond boot code range.
*/
DEBUG("FT1000:download:Download error: Bad Version Request = 0x%x.\n",(int)requested_version);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
break;
default:
DEBUG("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",request);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
}
if (pft1000info->usbboot)
@@ -1155,94 +1155,94 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe
else
{
DEBUG("FT1000:download:Download error: Handshake failed\n");
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
break;
case STATE_DONE_DWNLD:
DEBUG("FT1000:download:Code loader is done...\n");
- uiState = STATE_SECTION_PROV;
+ state = STATE_SECTION_PROV;
break;
case STATE_SECTION_PROV:
DEBUG("FT1000:download:STATE_SECTION_PROV\n");
- pHdr = (struct pseudo_hdr *)pUcFile;
+ pseudo_header = (struct pseudo_hdr *)c_file;
- if (pHdr->checksum == hdr_checksum(pHdr))
+ if (pseudo_header->checksum == hdr_checksum(pseudo_header))
{
- if (pHdr->portdest != 0x80 /* Dsp OAM */)
+ if (pseudo_header->portdest != 0x80 /* Dsp OAM */)
{
- uiState = STATE_DONE_PROV;
+ state = STATE_DONE_PROV;
break;
}
- usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
+ pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */
// Get buffer for provisioning data
- pbuffer = kmalloc((usHdrLength + sizeof(struct pseudo_hdr)), GFP_ATOMIC);
+ pbuffer = kmalloc((pseudo_header_len + sizeof(struct pseudo_hdr)), GFP_ATOMIC);
if (pbuffer) {
- memcpy(pbuffer, (void *)pUcFile, (UINT)(usHdrLength + sizeof(struct pseudo_hdr)));
+ memcpy(pbuffer, (void *)c_file, (u32)(pseudo_header_len + sizeof(struct pseudo_hdr)));
// link provisioning data
pprov_record = kmalloc(sizeof(struct prov_record), GFP_ATOMIC);
if (pprov_record) {
pprov_record->pprov_data = pbuffer;
list_add_tail (&pprov_record->list, &pft1000info->prov_list);
// Move to next entry if available
- pUcFile = (UCHAR *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
- if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) {
- uiState = STATE_DONE_FILE;
+ c_file = (u8 *)((unsigned long)c_file + (u32)((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
+ if ( (unsigned long)(c_file) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) {
+ state = STATE_DONE_FILE;
}
}
else {
kfree(pbuffer);
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
}
else {
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
}
else
{
/* Checksum did not compute */
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
}
- DEBUG("ft1000:download: after STATE_SECTION_PROV, uiState = %d, Status= %d\n", uiState, Status);
+ DEBUG("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n", state, status);
break;
case STATE_DONE_PROV:
DEBUG("FT1000:download:STATE_DONE_PROV\n");
- uiState = STATE_DONE_FILE;
+ state = STATE_DONE_FILE;
break;
default:
- Status = STATUS_FAILURE;
+ status = STATUS_FAILURE;
break;
} /* End Switch */
- if (Status != STATUS_SUCCESS) {
+ if (status != STATUS_SUCCESS) {
break;
}
/****
// Check if Card is present
- Status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK);
- if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) {
+ status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK);
+ if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) {
break;
}
- Status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID);
- if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) {
+ status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID);
+ if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) {
break;
}
****/
} /* End while */
- DEBUG("Download exiting with status = 0x%8x\n", Status);
+ DEBUG("Download exiting with status = 0x%8x\n", status);
ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL);
- return Status;
+ return status;
}
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index 5b89ee2a2971..643a63794ade 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -41,37 +41,9 @@ static int ft1000_chkcard (struct ft1000_device *dev);
//Jim
static u8 tempbuffer[1600];
-static unsigned long gCardIndex;
#define MAX_RCV_LOOP 100
-/****************************************************************
- * ft1000_control_complete
- ****************************************************************/
-static void ft1000_control_complete(struct urb *urb)
-{
- struct ft1000_device *ft1000dev = (struct ft1000_device *)urb->context;
-
- //DEBUG("FT1000_CONTROL_COMPLETE ENTERED\n");
- if (ft1000dev == NULL )
- {
- DEBUG("NULL ft1000dev, failure\n");
- return ;
- }
- else if ( ft1000dev->dev == NULL )
- {
- DEBUG("NULL ft1000dev->dev, failure\n");
- return ;
- }
-
- if(waitqueue_active(&ft1000dev->control_wait))
- {
- wake_up(&ft1000dev->control_wait);
- }
-
- //DEBUG("FT1000_CONTROL_COMPLETE RETURNED\n");
-}
-
//---------------------------------------------------------------------------
// Function: ft1000_control
//
@@ -187,7 +159,7 @@ u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegInd
// Notes:
//
//---------------------------------------------------------------------------
-u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx)
+u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx)
{
u16 ret = STATUS_SUCCESS;
@@ -223,7 +195,7 @@ u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRe
//
//---------------------------------------------------------------------------
-u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt)
+u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt)
{
u16 ret = STATUS_SUCCESS;
@@ -262,7 +234,7 @@ u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buf
// Notes:
//
//---------------------------------------------------------------------------
-u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt)
+u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt)
{
u16 ret = STATUS_SUCCESS;
@@ -299,7 +271,7 @@ u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR bu
// Notes:
//
//---------------------------------------------------------------------------
-u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow)
+u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow)
{
u16 ret = STATUS_SUCCESS;
@@ -347,7 +319,7 @@ u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buf
// Notes:
//
//---------------------------------------------------------------------------
-u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow)
+u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow)
{
u16 ret = STATUS_SUCCESS;
@@ -392,10 +364,10 @@ u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT va
// Notes:
//
//---------------------------------------------------------------------------
-u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer)
+u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer)
{
- UCHAR buf[16];
- USHORT pos;
+ u8 buf[16];
+ u16 pos;
u16 ret = STATUS_SUCCESS;
//DEBUG("fix_ft1000_read_dpram32: indx: %d \n", indx);
@@ -441,14 +413,14 @@ u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR
// Notes:
//
//---------------------------------------------------------------------------
-u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer)
+u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer)
{
- USHORT pos1;
- USHORT pos2;
- USHORT i;
- UCHAR buf[32];
- UCHAR resultbuffer[32];
- PUCHAR pdata;
+ u16 pos1;
+ u16 pos2;
+ u16 i;
+ u8 buf[32];
+ u8 resultbuffer[32];
+ u8 *pdata;
u16 ret = STATUS_SUCCESS;
//DEBUG("fix_ft1000_write_dpram32: Entered:\n");
@@ -472,7 +444,7 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
return ret;
}
- ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16);
+ ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16);
if (ret == STATUS_SUCCESS)
{
buffer = pdata;
@@ -487,8 +459,8 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
if (ret == STATUS_FAILURE)
{
- ret = ft1000_write_dpram32(ft1000dev, pos1, (PUCHAR)&tempbuffer[0], 16);
- ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16);
+ ret = ft1000_write_dpram32(ft1000dev, pos1, (u8 *)&tempbuffer[0], 16);
+ ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16);
if (ret == STATUS_SUCCESS)
{
buffer = pdata;
@@ -518,10 +490,10 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
//
// Returns: None
//-----------------------------------------------------------------------
-static void card_reset_dsp (struct ft1000_device *ft1000dev, BOOLEAN value)
+static void card_reset_dsp (struct ft1000_device *ft1000dev, bool value)
{
u16 status = STATUS_SUCCESS;
- USHORT tempword;
+ u16 tempword;
status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_SUP_CTRL);
@@ -620,8 +592,8 @@ void CardSendCommand(struct ft1000_device *ft1000dev, void *ptempbuffer, int siz
int dsp_reload(struct ft1000_device *ft1000dev)
{
u16 status;
- USHORT tempword;
- ULONG templong;
+ u16 tempword;
+ u32 templong;
struct ft1000_info *pft1000info;
@@ -648,7 +620,7 @@ int dsp_reload(struct ft1000_device *ft1000dev)
status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
// Let's check for FEFE
- status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (PUCHAR)&templong, 4);
+ status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (u8 *)&templong, 4);
DEBUG("templong (fefe) = 0x%8x\n", templong);
// call codeloader
@@ -753,7 +725,7 @@ static int ft1000_reset_card (struct net_device *dev)
// Initialize DSP heartbeat area to ho
ft1000_write_dpram16(ft1000dev, FT1000_MAG_HI_HO, ho_mag, FT1000_MAG_HI_HO_INDX);
- ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (PCHAR)&tempword, FT1000_MAG_HI_HO_INDX);
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (u8 *)&tempword, FT1000_MAG_HI_HO_INDX);
DEBUG("ft1000_hw:ft1000_reset_card:hi_ho value = 0x%x\n", tempword);
@@ -800,8 +772,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
int i, ret_val;
struct list_head *cur, *tmp;
char card_nr[2];
-
- gCardIndex=0; //mbelian
+ unsigned long gCardIndex = 0;
DEBUG("Enter init_ft1000_netdev...\n");
@@ -813,7 +784,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
return -ENOMEM;
}
- pInfo = (struct ft1000_info *) netdev_priv(netdev);
+ pInfo = netdev_priv(netdev);
//DEBUG("init_ft1000_netdev: gFt1000Info=%x, netdev=%x, ft1000dev=%x\n", gFt1000Info, netdev, ft1000dev);
@@ -821,9 +792,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
dev_alloc_name(netdev, netdev->name);
- //for the first inserted card, decide the card index beginning number, in case there are existing network interfaces
- if ( gCardIndex == 0 )
- {
DEBUG("init_ft1000_netdev: network device name is %s\n", netdev->name);
if ( strncmp(netdev->name,"eth", 3) == 0) {
@@ -843,13 +811,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
ret_val = -ENXIO;
goto err_net;
}
- }
- else
- {
- //not the first inserted card, increase card number by 1
- pInfo->CardNumber = gCardIndex;
- /*DEBUG("card number = %d\n", pInfo->CardNumber);*/ //mbelian
- }
memset(&pInfo->stats, 0, sizeof(struct net_device_stats) );
@@ -862,7 +823,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
pInfo->mediastate = 0;
pInfo->fifo_cnt = 0;
pInfo->DeviceCreated = FALSE;
- pInfo->DeviceMajor = 0;
pInfo->CurrentInterruptEnableMask = ISR_DEFAULT_MASK;
pInfo->InterruptsEnabled = FALSE;
pInfo->CardReady = 0;
@@ -874,13 +834,11 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
pInfo->fCondResetPend = 0;
pInfo->usbboot = 0;
pInfo->dspalive = 0;
- for (i=0;i<32 ;i++ )
- {
- pInfo->tempbuf[i] = 0;
- }
+ memset(&pInfo->tempbuf[0], 0, sizeof(pInfo->tempbuf));
INIT_LIST_HEAD(&pInfo->prov_list);
+ INIT_LIST_HEAD(&pInfo->nodes.list);
//mbelian
#ifdef HAVE_NET_DEVICE_OPS
netdev->netdev_ops = &ftnet_ops;
@@ -982,7 +940,7 @@ int reg_ft1000_netdev(struct ft1000_device *ft1000dev, struct usb_interface *int
//Create character device, implemented by Jim
- ft1000_CreateDevice(ft1000dev);
+ ft1000_create_dev(ft1000dev);
DEBUG ("reg_ft1000_netdev returned\n");
@@ -1026,178 +984,6 @@ static void ft1000_usb_transmit_complete(struct urb *urb)
//DEBUG("Return from ft1000_usb_transmit_complete\n");
}
-
-/****************************************************************
- * ft1000_control
- ****************************************************************/
-static int ft1000_read_fifo_reg(struct ft1000_device *ft1000dev,unsigned int pipe,
- u8 request,
- u8 requesttype,
- u16 value,
- u16 index,
- void *data,
- u16 size,
- int timeout)
-{
- u16 ret;
-
- DECLARE_WAITQUEUE(wait, current);
- struct urb *urb;
- struct usb_ctrlrequest *dr;
- int status;
-
- if (ft1000dev == NULL )
- {
- DEBUG("NULL ft1000dev, failure\n");
- return STATUS_FAILURE;
- }
- else if ( ft1000dev->dev == NULL )
- {
- DEBUG("NULL ft1000dev->dev, failure\n");
- return STATUS_FAILURE;
- }
-
- spin_lock(&ft1000dev->device_lock);
-
- if(in_interrupt())
- {
- spin_unlock(&ft1000dev->device_lock);
- return -EBUSY;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- dr = kmalloc(sizeof(struct usb_ctrlrequest), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-
- if(!urb || !dr)
- {
- kfree(dr);
- usb_free_urb(urb);
- spin_unlock(&ft1000dev->device_lock);
- return -ENOMEM;
- }
-
-
-
- dr->bRequestType = requesttype;
- dr->bRequest = request;
- dr->wValue = value;
- dr->wIndex = index;
- dr->wLength = size;
-
- usb_fill_control_urb(urb, ft1000dev->dev, pipe, (char*)dr, (void*)data, size, (void *)ft1000_control_complete, (void*)ft1000dev);
-
-
- init_waitqueue_head(&ft1000dev->control_wait);
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- add_wait_queue(&ft1000dev->control_wait, &wait);
-
-
-
-
- status = usb_submit_urb(urb, GFP_KERNEL);
-
- if(status)
- {
- usb_free_urb(urb);
- kfree(dr);
- remove_wait_queue(&ft1000dev->control_wait, &wait);
- spin_unlock(&ft1000dev->device_lock);
- return status;
- }
-
- if(urb->status == -EINPROGRESS)
- {
- while(timeout && urb->status == -EINPROGRESS)
- {
- status = timeout = schedule_timeout(timeout);
- }
- }
- else
- {
- status = 1;
- }
-
- remove_wait_queue(&ft1000dev->control_wait, &wait);
-
- if(!status)
- {
- usb_unlink_urb(urb);
- printk("ft1000 timeout\n");
- status = -ETIMEDOUT;
- }
- else
- {
- status = urb->status;
-
- if(urb->status)
- {
- printk("ft1000 control message failed (urb addr: %p) with error number: %i\n", urb, (int)status);
-
- usb_clear_halt(ft1000dev->dev, usb_rcvctrlpipe(ft1000dev->dev, 0));
- usb_clear_halt(ft1000dev->dev, usb_sndctrlpipe(ft1000dev->dev, 0));
- usb_unlink_urb(urb);
- }
- }
-
-
-
- usb_free_urb(urb);
- kfree(dr);
- spin_unlock(&ft1000dev->device_lock);
- return ret;
-
-
-}
-
-//---------------------------------------------------------------------------
-// Function: ft1000_read_fifo_len
-//
-// Parameters: ft1000dev - device structure
-//
-//
-// Returns: none
-//
-// Description: read the fifo length register content
-//
-// Notes:
-//
-//---------------------------------------------------------------------------
-static inline u16 ft1000_read_fifo_len (struct net_device *dev)
-{
- u16 temp;
- u16 ret;
-
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
- struct ft1000_device *ft1000dev = info->pFt1000Dev;
-// DEBUG("ft1000_read_fifo_len: enter ft1000dev %x\n", ft1000dev); //aelias [-] reason: warning: format ???%x??? expects type ???unsigned int???, but argument 2 has type ???struct ft1000_device *???
- DEBUG("ft1000_read_fifo_len: enter ft1000dev %p\n", ft1000dev); //aelias [+] reason: up
-
- ret = STATUS_SUCCESS;
-
- ret = ft1000_read_fifo_reg(ft1000dev,
- usb_rcvctrlpipe(ft1000dev->dev,0),
- HARLEY_READ_REGISTER,
- HARLEY_READ_OPERATION,
- 0,
- FT1000_REG_MAG_UFSR,
- &temp,
- 2,
- LARGE_TIMEOUT);
-
- if (ret>0)
- ret = STATUS_SUCCESS;
- else
- ret = STATUS_FAILURE;
-
- DEBUG("ft1000_read_fifo_len: returned %d\n", temp);
-
- return (temp- 16);
-
-}
-
-
//---------------------------------------------------------------------------
//
// Function: ft1000_copy_down_pkt
@@ -1219,16 +1005,15 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
struct ft1000_device *pFt1000Dev = pInfo->pFt1000Dev;
- int i, count, ret;
- USHORT *pTemp;
- USHORT checksum;
+ int count, ret;
u8 *t;
+ struct pseudo_hdr hdr;
if (!pInfo->CardReady)
{
DEBUG("ft1000_copy_down_pkt::Card Not Ready\n");
- return STATUS_FAILURE;
+ return -ENODEV;
}
@@ -1240,27 +1025,27 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
{
DEBUG("Error:ft1000_copy_down_pkt:Message Size Overflow!\n");
DEBUG("size = %d\n", count);
- return STATUS_FAILURE;
+ return -EINVAL;
}
if ( count % 4)
count = count + (4- (count %4) );
- pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]);
- *pTemp ++ = ntohs(count);
- *pTemp ++ = 0x1020;
- *pTemp ++ = 0x2010;
- *pTemp ++ = 0x9100;
- *pTemp ++ = 0;
- *pTemp ++ = 0;
- *pTemp ++ = 0;
- pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]);
- checksum = *pTemp ++;
- for (i=1; i<7; i++)
- {
- checksum ^= *pTemp ++;
- }
- *pTemp++ = checksum;
+ memset(&hdr, 0, sizeof(struct pseudo_hdr));
+
+ hdr.length = ntohs(count);
+ hdr.source = 0x10;
+ hdr.destination = 0x20;
+ hdr.portdest = 0x20;
+ hdr.portsrc = 0x10;
+ hdr.sh_str_id = 0x91;
+ hdr.control = 0x00;
+
+ hdr.checksum = hdr.length ^ hdr.source ^ hdr.destination ^
+ hdr.portdest ^ hdr.portsrc ^ hdr.sh_str_id ^
+ hdr.control;
+
+ memcpy(&pFt1000Dev->tx_buf[0], &hdr, sizeof(hdr));
memcpy(&(pFt1000Dev->tx_buf[sizeof(struct pseudo_hdr)]), packet, len);
netif_stop_queue(netdev);
@@ -1283,25 +1068,18 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
}*/
- ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC);
- if(ret)
- {
+ ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC);
+ if (ret) {
DEBUG("ft1000 failed tx_urb %d\n", ret);
-
- return STATUS_FAILURE;
-
- }
- else
- {
- //DEBUG("ft1000 sucess tx_urb %d\n", ret);
-
- pInfo->stats.tx_packets++;
- pInfo->stats.tx_bytes += (len+14);
- }
+ return ret;
+ } else {
+ pInfo->stats.tx_packets++;
+ pInfo->stats.tx_bytes += (len+14);
+ }
//DEBUG("ft1000_copy_down_pkt() exit\n");
- return STATUS_SUCCESS;
+ return 0;
}
//---------------------------------------------------------------------------
@@ -1331,14 +1109,13 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ( skb == NULL )
{
DEBUG ("ft1000_hw: ft1000_start_xmit:skb == NULL!!!\n" );
- return STATUS_FAILURE;
+ return NETDEV_TX_OK;
}
if ( pFt1000Dev->status & FT1000_STATUS_CLOSING)
{
DEBUG("network driver is closed, return\n");
- dev_kfree_skb(skb);
- return STATUS_SUCCESS;
+ goto err;
}
//DEBUG("ft1000_start_xmit 1:length of packet = %d\n", skb->len);
@@ -1357,28 +1134,24 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* Drop packet is mediastate is down */
DEBUG("ft1000_hw:ft1000_start_xmit:mediastate is down\n");
- dev_kfree_skb(skb);
- return STATUS_SUCCESS;
+ goto err;
}
if ( (skb->len < ENET_HEADER_SIZE) || (skb->len > ENET_MAX_SIZE) )
{
/* Drop packet which has invalid size */
DEBUG("ft1000_hw:ft1000_start_xmit:invalid ethernet length\n");
- dev_kfree_skb(skb);
- return STATUS_SUCCESS;
+ goto err;
}
//mbelian
- if(ft1000_copy_down_pkt (dev, (pdata+ENET_HEADER_SIZE-2), skb->len - ENET_HEADER_SIZE + 2) == STATUS_FAILURE)
- {
- dev_kfree_skb(skb);
- return STATUS_SUCCESS;
- }
+ ft1000_copy_down_pkt(dev, (pdata+ENET_HEADER_SIZE-2),
+ skb->len - ENET_HEADER_SIZE + 2);
- dev_kfree_skb(skb);
+err:
+ dev_kfree_skb(skb);
//DEBUG(" ft1000_start_xmit() exit\n");
- return 0;
+ return NETDEV_TX_OK;
}
//---------------------------------------------------------------------------
@@ -1424,7 +1197,7 @@ static int ft1000_copy_up_pkt (struct urb *urb)
//DEBUG("ft1000_copy_up_pkt: transfer_buffer_length=%d, actual_buffer_len=%d\n",
// urb->transfer_buffer_length, urb->actual_length);
- chksum = (PUSHORT)ft1000dev->rx_buf;
+ chksum = (u16 *)ft1000dev->rx_buf;
tempword = *chksum++;
for (i=1; i<7; i++)
@@ -1521,7 +1294,7 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info)
{
DEBUG("network driver is closed, return\n");
//usb_kill_urb(pFt1000Dev->rx_urb); //mbelian
- return STATUS_SUCCESS;
+ return -ENODEV;
}
usb_fill_bulk_urb(pFt1000Dev->rx_urb,
@@ -1536,12 +1309,12 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info)
if((result = usb_submit_urb(pFt1000Dev->rx_urb, GFP_ATOMIC)))
{
printk("ft1000_submit_rx_urb: submitting rx_urb %d failed\n", result);
- return STATUS_FAILURE;
+ return result;
}
//DEBUG("ft1000_submit_rx_urb exit: result=%d\n", result);
- return STATUS_SUCCESS;
+ return 0;
}
//---------------------------------------------------------------------------
@@ -1560,8 +1333,9 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info)
//---------------------------------------------------------------------------
static int ft1000_open (struct net_device *dev)
{
- struct ft1000_info *pInfo = (struct ft1000_info *)netdev_priv(dev);
+ struct ft1000_info *pInfo = netdev_priv(dev);
struct timeval tv; //mbelian
+ int ret;
DEBUG("ft1000_open is called for card %d\n", pInfo->CardNumber);
//DEBUG("ft1000_open: dev->addr=%x, dev->addr_len=%d\n", dev->addr, dev->addr_len);
@@ -1579,8 +1353,9 @@ static int ft1000_open (struct net_device *dev)
netif_carrier_on(dev); //mbelian
- ft1000_submit_rx_urb(pInfo);
- return 0;
+ ret = ft1000_submit_rx_urb(pInfo);
+
+ return ret;
}
//---------------------------------------------------------------------------
@@ -1599,7 +1374,7 @@ static int ft1000_open (struct net_device *dev)
//---------------------------------------------------------------------------
int ft1000_close(struct net_device *net)
{
- struct ft1000_info *pInfo = (struct ft1000_info *) netdev_priv(net);
+ struct ft1000_info *pInfo = netdev_priv(net);
struct ft1000_device *ft1000dev = pInfo->pFt1000Dev;
//DEBUG ("ft1000_close: netdev->refcnt=%d\n", net->refcnt);
@@ -1622,7 +1397,7 @@ int ft1000_close(struct net_device *net)
static struct net_device_stats *ft1000_netdev_stats(struct net_device *dev)
{
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
+ struct ft1000_info *info = netdev_priv(dev);
return &(info->stats); //mbelian
}
@@ -1648,7 +1423,7 @@ Jim
static int ft1000_chkcard (struct ft1000_device *dev) {
u16 tempword;
u16 status;
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net);
+ struct ft1000_info *info = netdev_priv(dev->net);
if (info->fCondResetPend)
{
@@ -1692,13 +1467,13 @@ static int ft1000_chkcard (struct ft1000_device *dev) {
// = 1 (successful)
//
//---------------------------------------------------------------------------
-static BOOLEAN ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) {
+static bool ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) {
u16 size, ret;
u16 *ppseudohdr;
int i;
u16 tempword;
- ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (PUCHAR)&size, FT1000_MAG_PH_LEN_INDX);
+ ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (u8 *)&size, FT1000_MAG_PH_LEN_INDX);
size = ntohs(size) + PSEUDOSZ;
if (size > maxsz) {
DEBUG("FT1000:ft1000_receive_cmd:Invalid command length = %d\n", size);
@@ -1748,15 +1523,15 @@ static BOOLEAN ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int
static int ft1000_dsp_prov(void *arg)
{
struct ft1000_device *dev = (struct ft1000_device *)arg;
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net);
+ struct ft1000_info *info = netdev_priv(dev->net);
u16 tempword;
u16 len;
u16 i=0;
struct prov_record *ptr;
struct pseudo_hdr *ppseudo_hdr;
- PUSHORT pmsg;
+ u16 *pmsg;
u16 status;
- USHORT TempShortBuf [256];
+ u16 TempShortBuf [256];
DEBUG("*** DspProv Entered\n");
@@ -1792,7 +1567,7 @@ static int ft1000_dsp_prov(void *arg)
len = htons(len);
len += PSEUDOSZ;
- pmsg = (PUSHORT)ptr->pprov_data;
+ pmsg = (u16 *)ptr->pprov_data;
ppseudo_hdr = (struct pseudo_hdr *)pmsg;
// Insert slow queue sequence number
ppseudo_hdr->seq_num = info->squeseqnum++;
@@ -1809,7 +1584,7 @@ static int ft1000_dsp_prov(void *arg)
TempShortBuf[1] = htons (len);
memcpy(&TempShortBuf[2], ppseudo_hdr, len);
- status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&TempShortBuf[0], (unsigned short)(len+2));
+ status = ft1000_write_dpram32 (dev, 0, (u8 *)&TempShortBuf[0], (unsigned short)(len+2));
status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL);
list_del(&ptr->list);
@@ -1831,7 +1606,7 @@ static int ft1000_dsp_prov(void *arg)
static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net);
+ struct ft1000_info *info = netdev_priv(dev->net);
u16 msgtype;
u16 tempword;
struct media_msg *pmediamsg;
@@ -1839,7 +1614,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
struct drv_msg *pdrvmsg;
u16 i;
struct pseudo_hdr *ppseudo_hdr;
- PUSHORT pmsg;
+ u16 *pmsg;
u16 status;
union {
u8 byte[2];
@@ -1971,7 +1746,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
tempword = ntohs(pdrvmsg->length);
info->DSPInfoBlklen = tempword;
if (tempword < (MAX_DSP_SESS_REC-4) ) {
- pmsg = (PUSHORT)&pdrvmsg->data[0];
+ pmsg = (u16 *)&pdrvmsg->data[0];
for (i=0; i<((tempword+1)/2); i++) {
DEBUG("FT1000:drivermsg:dsp info data = 0x%x\n", *pmsg);
info->DSPInfoBlk[i+10] = *pmsg++;
@@ -2003,10 +1778,10 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
// Put message into Slow Queue
// Form Pseudo header
- pmsg = (PUSHORT)info->DSPInfoBlk;
+ pmsg = (u16 *)info->DSPInfoBlk;
*pmsg++ = 0;
*pmsg++ = htons(info->DSPInfoBlklen+20+info->DSPInfoBlklen);
- ppseudo_hdr = (struct pseudo_hdr *)(PUSHORT)&info->DSPInfoBlk[2];
+ ppseudo_hdr = (struct pseudo_hdr *)(u16 *)&info->DSPInfoBlk[2];
ppseudo_hdr->length = htons(info->DSPInfoBlklen+4+info->DSPInfoBlklen);
ppseudo_hdr->source = 0x10;
ppseudo_hdr->destination = 0x20;
@@ -2028,7 +1803,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
}
info->DSPInfoBlk[10] = 0x7200;
info->DSPInfoBlk[11] = htons(info->DSPInfoBlklen);
- status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22));
+ status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22));
status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL);
info->DrvMsgPend = 0;
@@ -2053,7 +1828,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
if ( (tempword & FT1000_DB_DPRAM_TX) == 0) {
// Put message into Slow Queue
// Form Pseudo header
- pmsg = (PUSHORT)&tempbuffer[0];
+ pmsg = (u16 *)&tempbuffer[0];
ppseudo_hdr = (struct pseudo_hdr *)pmsg;
ppseudo_hdr->length = htons(0x0012);
ppseudo_hdr->source = 0x10;
@@ -2074,7 +1849,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
for (i=1; i<7; i++) {
ppseudo_hdr->checksum ^= *pmsg++;
}
- pmsg = (PUSHORT)&tempbuffer[16];
+ pmsg = (u16 *)&tempbuffer[16];
*pmsg++ = htons(RSP_DRV_ERR_RPT_MSG);
*pmsg++ = htons(0x000e);
*pmsg++ = htons(info->DSP_TIME[0]);
@@ -2089,7 +1864,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
*pmsg++ = convert.wrd;
*pmsg++ = htons(info->DrvErrNum);
- CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (USHORT)(0x0012 + PSEUDOSZ));
+ CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (u16)(0x0012 + PSEUDOSZ));
info->DrvErrNum = 0;
}
info->DrvMsgPend = 0;
@@ -2114,15 +1889,15 @@ out:
int ft1000_poll(void* dev_id) {
struct ft1000_device *dev = (struct ft1000_device *)dev_id;
- struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net);
+ struct ft1000_info *info = netdev_priv(dev->net);
u16 tempword;
u16 status;
u16 size;
int i;
- USHORT data;
- USHORT modulo;
- USHORT portid;
+ u16 data;
+ u16 modulo;
+ u16 portid;
u16 nxtph;
struct dpram_blk *pdpram_blk;
struct pseudo_hdr *ppseudo_hdr;
@@ -2143,14 +1918,14 @@ int ft1000_poll(void* dev_id) {
if (tempword & FT1000_DB_DPRAM_RX) {
//DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX\n");
- status = ft1000_read_dpram16(dev, 0x200, (PUCHAR)&data, 0);
+ status = ft1000_read_dpram16(dev, 0x200, (u8 *)&data, 0);
//DEBUG("ft1000_poll:FT1000_DB_DPRAM_RX:ft1000_read_dpram16:size = 0x%x\n", data);
size = ntohs(data) + 16 + 2; //wai
if (size % 4) {
modulo = 4 - (size % 4);
size = size + modulo;
}
- status = ft1000_read_dpram16(dev, 0x201, (PUCHAR)&portid, 1);
+ status = ft1000_read_dpram16(dev, 0x201, (u8 *)&portid, 1);
portid &= 0xff;
//DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX : portid 0x%x\n", portid);
@@ -2285,7 +2060,7 @@ int ft1000_poll(void* dev_id) {
status = ft1000_write_register (dev, FT1000_ASIC_RESET_REQ, FT1000_REG_DOORBELL);
status = ft1000_write_register (dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
// copy dsp session record from Adapter block
- status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPSess.Rec[0], 1024);
+ status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPSess.Rec[0], 1024);
// Program WMARK register
status = ft1000_write_register (dev, 0x600, FT1000_REG_MAG_WATERMARK);
// ring doorbell to tell DSP that ASIC is out of reset
@@ -2299,10 +2074,10 @@ int ft1000_poll(void* dev_id) {
if (info->fAppMsgPend == 0) {
// Reset ASIC and DSP
- status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (PUCHAR)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX);
- status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (PUCHAR)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX);
- status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (PUCHAR)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX);
- status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (PUCHAR)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (u8 *)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (u8 *)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (u8 *)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (u8 *)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX);
info->CardReady = 0;
info->DrvErrNum = DSP_CONDRESET_INFO;
DEBUG("ft1000_hw:DSP conditional reset requested\n");
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h
index c58074131014..ab9312f9f326 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h
@@ -4,7 +4,7 @@
#include "ft1000_usb.h"
-extern u16 ft1000_read_register(struct usb_device *dev, PUSHORT Data, u8 nRegIndx);
-extern u16 ft1000_write_register(struct usb_device *dev, USHORT value, u8 nRegIndx);
+extern u16 ft1000_read_register(struct usb_device *dev, u16 *Data, u8 nRegIndx);
+extern u16 ft1000_write_register(struct usb_device *dev, u16 value, u8 nRegIndx);
#endif
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
index 36cdd588fa98..b87542abbe86 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
@@ -1,3 +1,24 @@
+/*
+ * ft1000_proc.c - ft1000 proc interface
+ *
+ * Copyright (C) 2009-2010 Quintec
+ * (C) 2010 Open-nandra
+ * <marek.belisko@open-nandra.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
@@ -14,219 +35,217 @@
#define PUTX_TO_PAGE(len,page,message,size,var) \
len += snprintf(page+len, PAGE_SIZE - len, message); \
- for(i = 0; i < (size - 1); i++) \
- { \
+ for (i = 0; i < (size - 1); i++) {\
len += snprintf(page+len, PAGE_SIZE - len, "%02x:", var[i]); \
} \
len += snprintf(page+len, PAGE_SIZE - len, "%02x\n", var[i])
#define PUTD_TO_PAGE(len,page,message,size,var) \
len += snprintf(page+len, PAGE_SIZE - len, message); \
- for(i = 0; i < (size - 1); i++) \
- { \
+ for (i = 0; i < (size - 1); i++) {\
len += snprintf(page+len, PAGE_SIZE - len, "%d.", var[i]); \
} \
len += snprintf(page+len, PAGE_SIZE - len, "%d\n", var[i])
-
-
-//#ifdef INIT_NET_NS
#define FTNET_PROC init_net.proc_net
-//#else
-//#define FTNET_PROC proc_net
-//#endif
-u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, USHORT indx,
- PUCHAR buffer, u8 highlow);
+u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, u16 indx,
+ u8 *buffer, u8 highlow);
static int
-ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof,
+ft1000ReadProc(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
- struct net_device *dev;
- int len;
- int i;
- unsigned short ledStat;
- unsigned short conStat;
+ struct net_device *dev;
+ int len;
+ int i;
+ unsigned short ledStat;
+ unsigned short conStat;
struct ft1000_info *info;
- char *status[] = { "Idle (Disconnect)", "Searching", "Active (Connected)",
- "Waiting for L2", "Sleep", "No Coverage", "", ""
- };
-
- char *signal[] = { "", "*", "**", "***", "****" };
- int strength;
- int quality;
- struct timeval tv;
- time_t delta;
-
- dev = (struct net_device *) data;
- info = (struct ft1000_info *) netdev_priv(dev);
-
- if (off > 0)
- {
- *eof = 1;
- return 0;
- }
-
-
- if (info->ProgConStat != 0xFF)
- {
- ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_LED,
- (PUCHAR) & ledStat, FT1000_MAG_DSP_LED_INDX);
- info->LedStat = ntohs (ledStat);
-
- ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE,
- (PUCHAR) & conStat, FT1000_MAG_DSP_CON_STATE_INDX);
- info->ConStat = ntohs (conStat);
- do_gettimeofday (&tv);
- delta = (tv.tv_sec - info->ConTm);
- }
- else
- {
- info->ConStat = 0xf;
- delta = 0;
- }
-
-
-
- i = (info->LedStat) & 0xf;
- switch (i)
- {
- case 0x1:
- strength = 1;
- break;
- case 0x3:
- strength = 2;
- break;
- case 0x7:
- strength = 3;
- break;
- case 0xf:
- strength = 4;
- break;
- default:
- strength = 0;
- }
-
- i = (info->LedStat >> 8) & 0xf;
- switch (i)
- {
- case 0x1:
- quality = 1;
- break;
- case 0x3:
- quality = 2;
- break;
- case 0x7:
- quality = 3;
- break;
- case 0xf:
- quality = 4;
- break;
- default:
- quality = 0;
- }
-
-
- len = 0;
- PUTM_TO_PAGE (len, page, "Connection Time: %02ld:%02ld:%02ld\n",
- ((delta / 3600) % 24), ((delta / 60) % 60), (delta % 60));
- PUTM_TO_PAGE (len, page, "Connection Time[s]: %ld\n", delta);
- PUTM_TO_PAGE (len, page, "Asic ID: %s\n",
- (info->AsicID) ==
- ELECTRABUZZ_ID ? "ELECTRABUZZ ASIC" : "MAGNEMITE ASIC");
- PUTX_TO_PAGE (len, page, "SKU: ", SKUSZ, info->Sku);
- PUTX_TO_PAGE (len, page, "EUI64: ", EUISZ, info->eui64);
- PUTD_TO_PAGE (len, page, "DSP version number: ", DSPVERSZ, info->DspVer);
- PUTX_TO_PAGE (len, page, "Hardware Serial Number: ", HWSERNUMSZ,
- info->HwSerNum);
- PUTX_TO_PAGE (len, page, "Caliberation Version: ", CALVERSZ,
- info->RfCalVer);
- PUTD_TO_PAGE (len, page, "Caliberation Date: ", CALDATESZ, info->RfCalDate);
- PUTM_TO_PAGE (len, page, "Media State: %s\n",
- (info->mediastate) ? "link" : "no link");
- PUTM_TO_PAGE (len, page, "Connection Status: %s\n",
- status[((info->ConStat) & 0x7)]);
- PUTM_TO_PAGE (len, page, "RX packets: %ld\n", info->stats.rx_packets);
- PUTM_TO_PAGE (len, page, "TX packets: %ld\n", info->stats.tx_packets);
- PUTM_TO_PAGE (len, page, "RX bytes: %ld\n", info->stats.rx_bytes);
- PUTM_TO_PAGE (len, page, "TX bytes: %ld\n", info->stats.tx_bytes);
- PUTM_TO_PAGE (len, page, "Signal Strength: %s\n", signal[strength]);
- PUTM_TO_PAGE (len, page, "Signal Quality: %s\n", signal[quality]);
-
-
-
-
- return len;
+ char *status[] = {
+ "Idle (Disconnect)",
+ "Searching",
+ "Active (Connected)",
+ "Waiting for L2",
+ "Sleep",
+ "No Coverage",
+ "",
+ "",
+ };
+
+ char *signal[] = { "", "*", "**", "***", "****" };
+ int strength;
+ int quality;
+ struct timeval tv;
+ time_t delta;
+
+ dev = (struct net_device *) data;
+ info = netdev_priv(dev);
+
+ if (off > 0) {
+ *eof = 1;
+ return 0;
+ }
+
+
+ if (info->ProgConStat != 0xFF) {
+ ft1000_read_dpram16(info->pFt1000Dev, FT1000_MAG_DSP_LED,
+ (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
+ info->LedStat = ntohs(ledStat);
+
+ ft1000_read_dpram16(info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE,
+ (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+ info->ConStat = ntohs(conStat);
+ do_gettimeofday(&tv);
+ delta = (tv.tv_sec - info->ConTm);
+ } else {
+ info->ConStat = 0xf;
+ delta = 0;
+ }
+
+ i = (info->LedStat) & 0xf;
+ switch (i) {
+ case 0x1:
+ strength = 1;
+ break;
+ case 0x3:
+ strength = 2;
+ break;
+ case 0x7:
+ strength = 3;
+ break;
+ case 0xf:
+ strength = 4;
+ break;
+ default:
+ strength = 0;
+ }
+
+ i = (info->LedStat >> 8) & 0xf;
+ switch (i) {
+ case 0x1:
+ quality = 1;
+ break;
+ case 0x3:
+ quality = 2;
+ break;
+ case 0x7:
+ quality = 3;
+ break;
+ case 0xf:
+ quality = 4;
+ break;
+ default:
+ quality = 0;
+ }
+
+ len = 0;
+ PUTM_TO_PAGE(len, page, "Connection Time: %02ld:%02ld:%02ld\n",
+ ((delta / 3600) % 24), ((delta / 60) % 60), (delta % 60));
+ PUTM_TO_PAGE(len, page, "Connection Time[s]: %ld\n", delta);
+ PUTM_TO_PAGE(len, page, "Asic ID: %s\n",
+ (info->AsicID) ==
+ ELECTRABUZZ_ID ? "ELECTRABUZZ ASIC" : "MAGNEMITE ASIC");
+ PUTX_TO_PAGE(len, page, "SKU: ", SKUSZ, info->Sku);
+ PUTX_TO_PAGE(len, page, "EUI64: ", EUISZ, info->eui64);
+ PUTD_TO_PAGE(len, page, "DSP version number: ", DSPVERSZ, info->DspVer);
+ PUTX_TO_PAGE(len, page, "Hardware Serial Number: ", HWSERNUMSZ,
+ info->HwSerNum);
+ PUTX_TO_PAGE(len, page, "Caliberation Version: ", CALVERSZ,
+ info->RfCalVer);
+ PUTD_TO_PAGE(len, page, "Caliberation Date: ", CALDATESZ,
+ info->RfCalDate);
+ PUTM_TO_PAGE(len, page, "Media State: %s\n",
+ (info->mediastate) ? "link" : "no link");
+ PUTM_TO_PAGE(len, page, "Connection Status: %s\n",
+ status[((info->ConStat) & 0x7)]);
+ PUTM_TO_PAGE(len, page, "RX packets: %ld\n", info->stats.rx_packets);
+ PUTM_TO_PAGE(len, page, "TX packets: %ld\n", info->stats.tx_packets);
+ PUTM_TO_PAGE(len, page, "RX bytes: %ld\n", info->stats.rx_bytes);
+ PUTM_TO_PAGE(len, page, "TX bytes: %ld\n", info->stats.tx_bytes);
+ PUTM_TO_PAGE(len, page, "Signal Strength: %s\n", signal[strength]);
+ PUTM_TO_PAGE(len, page, "Signal Quality: %s\n", signal[quality]);
+
+ return len;
}
static int
-ft1000NotifyProc (struct notifier_block *this, unsigned long event, void *ptr)
+ft1000NotifyProc(struct notifier_block *this, unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = ptr;
struct ft1000_info *info;
- struct proc_dir_entry *ft1000_proc_file;
-
-info = (struct ft1000_info *) netdev_priv(dev);
-
-
- switch (event)
- {
- case NETDEV_CHANGENAME:
- remove_proc_entry (info->netdevname, info->ft1000_proc_dir);
- ft1000_proc_file = create_proc_read_entry (dev->name, 0644,
- info->ft1000_proc_dir,
- ft1000ReadProc, dev);
- snprintf (info->netdevname, IFNAMSIZ, "%s", dev->name);
- break;
- }
- return NOTIFY_DONE;
+ struct proc_dir_entry *ft1000_proc_file;
+
+ info = netdev_priv(dev);
+
+ switch (event) {
+ case NETDEV_CHANGENAME:
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+ ft1000_proc_file = create_proc_read_entry(dev->name, 0644,
+ info->ft1000_proc_dir,
+ ft1000ReadProc, dev);
+ snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name);
+ break;
+ }
+
+ return NOTIFY_DONE;
}
static struct notifier_block ft1000_netdev_notifier = {
- .notifier_call = ft1000NotifyProc
+ .notifier_call = ft1000NotifyProc,
};
-void
-ft1000InitProc (struct net_device *dev)
+int ft1000_init_proc(struct net_device *dev)
{
struct ft1000_info *info;
- struct proc_dir_entry *ft1000_proc_file;
- info = (struct ft1000_info *) netdev_priv(dev);
-
-
- info->ft1000_proc_dir = proc_mkdir (FT1000_PROC_DIR, FTNET_PROC);
- if (info->ft1000_proc_dir == NULL)
- {
- remove_proc_entry (FT1000_PROC_DIR, FTNET_PROC);
- }
-
-
- ft1000_proc_file =
- create_proc_read_entry (dev->name, 0644, info->ft1000_proc_dir,
- ft1000ReadProc, dev);
- if (ft1000_proc_file == NULL)
- {
- remove_proc_entry (info->netdevname, info->ft1000_proc_dir);
- }
-
- snprintf (info->netdevname, IFNAMSIZ, "%s", dev->name);
- register_netdevice_notifier (&ft1000_netdev_notifier);
- return;
+ struct proc_dir_entry *ft1000_proc_file;
+ int ret = 0;
+
+ info = netdev_priv(dev);
+
+ info->ft1000_proc_dir = proc_mkdir(FT1000_PROC_DIR, FTNET_PROC);
+ if (info->ft1000_proc_dir == NULL) {
+ printk(KERN_WARNING "Unable to create %s dir.\n",
+ FT1000_PROC_DIR);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ft1000_proc_file =
+ create_proc_read_entry(dev->name, 0644,
+ info->ft1000_proc_dir, ft1000ReadProc, dev);
+
+ if (ft1000_proc_file == NULL) {
+ printk(KERN_WARNING "Unable to create /proc entry.\n");
+ ret = -EINVAL;
+ goto fail_entry;
+ }
+
+ snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name);
+
+ ret = register_netdevice_notifier(&ft1000_netdev_notifier);
+ if (ret)
+ goto fail_notif;
+
+ return 0;
+
+fail_notif:
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+fail_entry:
+ remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC);
+fail:
+ return ret;
}
-void
-ft1000CleanupProc(struct ft1000_info *info)
+void ft1000_cleanup_proc(struct ft1000_info *info)
{
- remove_proc_entry (info->netdevname, info->ft1000_proc_dir);
- remove_proc_entry (FT1000_PROC_DIR, FTNET_PROC);
- unregister_netdevice_notifier (&ft1000_netdev_notifier);
-
- return;
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+ remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC);
+ unregister_netdevice_notifier(&ft1000_netdev_notifier);
}
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
index 28f55b2030e9..79482ac1c489 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
@@ -36,7 +36,7 @@ static struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static BOOLEAN gPollingfailed = FALSE;
+static bool gPollingfailed = FALSE;
int ft1000_poll_thread(void *arg)
{
int ret = STATUS_SUCCESS;
@@ -64,7 +64,7 @@ static int ft1000_probe(struct usb_interface *interface,
int i, ret = 0, size;
struct ft1000_device *ft1000dev;
- struct ft1000_info *pft1000info;
+ struct ft1000_info *pft1000info = NULL;
const struct firmware *dsp_fw;
ft1000dev = kmalloc(sizeof(struct ft1000_device), GFP_KERNEL);
@@ -84,7 +84,6 @@ static int ft1000_probe(struct usb_interface *interface,
ft1000dev->dev = dev;
ft1000dev->status = 0;
ft1000dev->net = NULL;
- spin_lock_init(&ft1000dev->device_lock);
ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC);
ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -164,7 +163,7 @@ static int ft1000_probe(struct usb_interface *interface,
if (ret)
goto err_load;
- pft1000info = (struct ft1000_info *) netdev_priv(ft1000dev->net);
+ pft1000info = netdev_priv(ft1000dev->net);
DEBUG("In probe: pft1000info=%p\n", pft1000info);
ret = dsp_reload(ft1000dev);
@@ -176,14 +175,18 @@ static int ft1000_probe(struct usb_interface *interface,
gPollingfailed = FALSE;
pft1000info->pPollThread =
kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll");
+
+ if (IS_ERR(pft1000info->pPollThread)) {
+ ret = PTR_ERR(pft1000info->pPollThread);
+ goto err_load;
+ }
+
msleep(500);
while (!pft1000info->CardReady) {
if (gPollingfailed) {
- if (pft1000info->pPollThread)
- kthread_stop(pft1000info->pPollThread);
ret = -EIO;
- goto err_load;
+ goto err_thread;
}
msleep(100);
DEBUG("ft1000_probe::Waiting for Card Ready\n");
@@ -193,14 +196,21 @@ static int ft1000_probe(struct usb_interface *interface,
ret = reg_ft1000_netdev(ft1000dev, interface);
if (ret)
- goto err_load;
+ goto err_thread;
- pft1000info->NetDevRegDone = 1;
+ ret = ft1000_init_proc(ft1000dev->net);
+ if (ret)
+ goto err_proc;
- ft1000InitProc(ft1000dev->net);
+ pft1000info->NetDevRegDone = 1;
return 0;
+err_proc:
+ unregister_netdev(ft1000dev->net);
+ free_netdev(ft1000dev->net);
+err_thread:
+ kthread_stop(pft1000info->pPollThread);
err_load:
kfree(pFileStart);
err_fw:
@@ -218,7 +228,7 @@ static void ft1000_disconnect(struct usb_interface *interface)
DEBUG("In disconnect pft1000info=%p\n", pft1000info);
if (pft1000info) {
- ft1000CleanupProc(pft1000info);
+ ft1000_cleanup_proc(pft1000info);
if (pft1000info->pPollThread)
kthread_stop(pft1000info->pPollThread);
@@ -226,7 +236,7 @@ static void ft1000_disconnect(struct usb_interface *interface)
if (pft1000info->pFt1000Dev->net) {
DEBUG("ft1000_disconnect: destroy char driver\n");
- ft1000_DestroyDevice(pft1000info->pFt1000Dev->net);
+ ft1000_destroy_dev(pft1000info->pFt1000Dev->net);
unregister_netdev(pft1000info->pFt1000Dev->net);
DEBUG
("ft1000_disconnect: network device unregisterd\n");
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
index a9d419a98a06..a143e9ca4f08 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
@@ -98,16 +98,6 @@ struct prov_record {
/*end of Jim*/
#define DEBUG(args...) printk(KERN_INFO args)
-#define UCHAR u8
-#define USHORT u16
-#define ULONG u32 /* WTF ??? */
-#define BOOLEAN u8
-#define PULONG u32 *
-#define PUSHORT u16 *
-#define PUCHAR u8 *
-#define PCHAR u8 *
-#define UINT u32
-
#define FALSE 0
#define TRUE 1
@@ -372,15 +362,15 @@ struct prov_record {
-#define ISR_EMPTY (UCHAR)0x00 // no bits set in ISR
+#define ISR_EMPTY (u8)0x00 // no bits set in ISR
-#define ISR_DOORBELL_ACK (UCHAR)0x01 // the doorbell i sent has been recieved.
+#define ISR_DOORBELL_ACK (u8)0x01 // the doorbell i sent has been recieved.
-#define ISR_DOORBELL_PEND (UCHAR)0x02 // doorbell for me
+#define ISR_DOORBELL_PEND (u8)0x02 // doorbell for me
-#define ISR_RCV (UCHAR)0x04 // packet received with no errors
+#define ISR_RCV (u8)0x04 // packet received with no errors
-#define ISR_WATERMARK (UCHAR)0x08 //
+#define ISR_WATERMARK (u8)0x08 //
@@ -466,12 +456,9 @@ struct ft1000_device
{
struct usb_device *dev;
struct net_device *net;
- spinlock_t device_lock;
u32 status;
- wait_queue_head_t control_wait;
-
struct urb *rx_urb;
struct urb *tx_urb;
@@ -486,6 +473,13 @@ struct ft1000_device
// struct net_device_stats stats; //mbelian
} __attribute__ ((packed));
+struct ft1000_debug_dirs {
+ struct list_head list;
+ struct dentry *dent;
+ struct dentry *file;
+ int int_number;
+};
+
struct ft1000_info {
struct ft1000_device *pFt1000Dev;
struct net_device_stats stats;
@@ -497,9 +491,9 @@ struct ft1000_info {
unsigned char usbboot;
unsigned short dspalive;
u16 ASIC_ID;
- BOOLEAN fProvComplete;
- BOOLEAN fCondResetPend;
- BOOLEAN fAppMsgPend;
+ bool fProvComplete;
+ bool fCondResetPend;
+ bool fAppMsgPend;
char *pfwimg;
int fwimgsz;
u16 DrvErrNum;
@@ -520,7 +514,7 @@ struct ft1000_info {
int NetDevRegDone;
u8 CardNumber;
u8 DeviceName[15];
- int DeviceMajor;
+ struct ft1000_debug_dirs nodes;
int registered;
int mediastate;
int dhcpflg;
@@ -567,26 +561,26 @@ struct dpram_blk {
} __attribute__ ((packed));
u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegIndx);
-u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx);
-u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt);
-u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt);
-u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow);
-u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow);
-u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer);
-u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer);
+u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx);
+u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt);
+u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt);
+u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow);
+u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow);
+u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer);
+u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer);
extern void *pFileStart;
extern size_t FileLength;
extern int numofmsgbuf;
int ft1000_close (struct net_device *dev);
-u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength);
+u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength);
extern struct list_head freercvpool;
extern spinlock_t free_buff_lock; // lock to arbitrate free buffer list for receive command data
-int ft1000_CreateDevice(struct ft1000_device *dev);
-void ft1000_DestroyDevice(struct net_device *dev);
+int ft1000_create_dev(struct ft1000_device *dev);
+void ft1000_destroy_dev(struct net_device *dev);
extern void CardSendCommand(struct ft1000_device *ft1000dev, void *ptempbuffer, int size);
struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist);
@@ -600,8 +594,8 @@ struct usb_interface;
int reg_ft1000_netdev(struct ft1000_device *ft1000dev, struct usb_interface *intf);
int ft1000_poll(void* dev_id);
-void ft1000InitProc(struct net_device *dev);
-void ft1000CleanupProc(struct ft1000_info *info);
+int ft1000_init_proc(struct net_device *dev);
+void ft1000_cleanup_proc(struct ft1000_info *info);
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
index 3aecd30f0d1e..1da57df5cbcb 100644
--- a/drivers/staging/go7007/Kconfig
+++ b/drivers/staging/go7007/Kconfig
@@ -1,10 +1,10 @@
config VIDEO_GO7007
tristate "WIS GO7007 MPEG encoder support"
- depends on VIDEO_DEV && PCI && I2C && INPUT
+ depends on VIDEO_DEV && PCI && I2C
depends on BKL # please fix
depends on SND
select VIDEOBUF_DMA_SG
- depends on VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select SND_PCM
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index b3f42f37a313..6c9279a6d606 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -199,7 +199,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
struct go7007 *go = i2c_get_adapdata(adapter);
struct v4l2_device *v4l2_dev = &go->v4l2_dev;
- if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL))
+ if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
return 0;
printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
@@ -624,7 +624,7 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
go->dvd_mode = 0;
go->interlace_coding = 0;
for (i = 0; i < 4; ++i)
- go->modet[i].enable = 0;;
+ go->modet[i].enable = 0;
for (i = 0; i < 1624; ++i)
go->modet_map[i] = 0;
go->audio_deliver = NULL;
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index b46349bb43bf..acd39bd75b1c 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
hv_vmbus-y := vmbus_drv.o osd.o \
- vmbus.o hv.o connection.o channel.o \
+ hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
hv_storvsc-y := storvsc_drv.o storvsc.o
hv_blkvsc-y := blkvsc_drv.o blkvsc.o
diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c
index d5b0abd771ab..bc16d9172eb2 100644
--- a/drivers/staging/hv/blkvsc.c
+++ b/drivers/staging/hv/blkvsc.c
@@ -25,24 +25,24 @@
#include "osd.h"
#include "storvsc.c"
-static const char *gBlkDriverName = "blkvsc";
+static const char *g_blk_driver_name = "blkvsc";
/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-static const struct hv_guid gBlkVscDeviceType = {
+static const struct hv_guid g_blk_device_type = {
.data = {
0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
}
};
-static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
+static int blk_vsc_on_device_add(struct hv_device *device, void *additional_info)
{
- struct storvsc_device_info *deviceInfo;
+ struct storvsc_device_info *device_info;
int ret = 0;
- deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
+ device_info = (struct storvsc_device_info *)additional_info;
- ret = StorVscOnDeviceAdd(Device, AdditionalInfo);
+ ret = stor_vsc_on_device_add(device, additional_info);
if (ret != 0)
return ret;
@@ -51,31 +51,31 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
* id. For IDE devices, the device instance id is formatted as
* <bus id> * - <device id> - 8899 - 000000000000.
*/
- deviceInfo->PathId = Device->deviceInstance.data[3] << 24 |
- Device->deviceInstance.data[2] << 16 |
- Device->deviceInstance.data[1] << 8 |
- Device->deviceInstance.data[0];
+ device_info->path_id = device->deviceInstance.data[3] << 24 |
+ device->deviceInstance.data[2] << 16 |
+ device->deviceInstance.data[1] << 8 |
+ device->deviceInstance.data[0];
- deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 |
- Device->deviceInstance.data[4];
+ device_info->target_id = device->deviceInstance.data[5] << 8 |
+ device->deviceInstance.data[4];
return ret;
}
-int BlkVscInitialize(struct hv_driver *Driver)
+int blk_vsc_initialize(struct hv_driver *driver)
{
- struct storvsc_driver_object *storDriver;
+ struct storvsc_driver_object *stor_driver;
int ret = 0;
- storDriver = (struct storvsc_driver_object *)Driver;
+ stor_driver = (struct storvsc_driver_object *)driver;
/* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
+ /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */
- Driver->name = gBlkDriverName;
- memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid));
+ driver->name = g_blk_driver_name;
+ memcpy(&driver->deviceType, &g_blk_device_type, sizeof(struct hv_guid));
- storDriver->RequestExtSize = sizeof(struct storvsc_request_extension);
+ stor_driver->request_ext_size = sizeof(struct storvsc_request_extension);
/*
* Divide the ring buffer data size (which is 1 page less than the ring
@@ -83,20 +83,20 @@ int BlkVscInitialize(struct hv_driver *Driver)
* by the max request size (which is
* vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
*/
- storDriver->MaxOutstandingRequestsPerChannel =
- ((storDriver->RingBufferSize - PAGE_SIZE) /
+ stor_driver->max_outstanding_req_per_channel =
+ ((stor_driver->ring_buffer_size - PAGE_SIZE) /
ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET +
sizeof(struct vstor_packet) + sizeof(u64),
sizeof(u64)));
DPRINT_INFO(BLKVSC, "max io outstd %u",
- storDriver->MaxOutstandingRequestsPerChannel);
+ stor_driver->max_outstanding_req_per_channel);
/* Setup the dispatch table */
- storDriver->Base.OnDeviceAdd = BlkVscOnDeviceAdd;
- storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove;
- storDriver->Base.OnCleanup = StorVscOnCleanup;
- storDriver->OnIORequest = StorVscOnIORequest;
+ stor_driver->base.OnDeviceAdd = blk_vsc_on_device_add;
+ stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove;
+ stor_driver->base.OnCleanup = stor_vsc_on_cleanup;
+ stor_driver->on_io_request = stor_vsc_on_io_request;
return ret;
}
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index 3f81ca591064..b3d05fcfe6d2 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -177,13 +177,13 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx;
int ret;
- storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size;
+ storvsc_drv_obj->ring_buffer_size = blkvsc_ringbuffer_size;
/* Callback to client driver to complete the initialization */
- drv_init(&storvsc_drv_obj->Base);
+ drv_init(&storvsc_drv_obj->base);
- drv_ctx->driver.name = storvsc_drv_obj->Base.name;
- memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType,
+ drv_ctx->driver.name = storvsc_drv_obj->base.name;
+ memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType,
sizeof(struct hv_guid));
drv_ctx->probe = blkvsc_probe;
@@ -230,8 +230,8 @@ static void blkvsc_drv_exit(void)
device_unregister(current_dev);
}
- if (storvsc_drv_obj->Base.OnCleanup)
- storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base);
+ if (storvsc_drv_obj->base.OnCleanup)
+ storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base);
vmbus_child_driver_unregister(drv_ctx);
@@ -262,7 +262,7 @@ static int blkvsc_probe(struct device *device)
DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter");
- if (!storvsc_drv_obj->Base.OnDeviceAdd) {
+ if (!storvsc_drv_obj->base.OnDeviceAdd) {
DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set");
ret = -1;
goto Cleanup;
@@ -284,7 +284,7 @@ static int blkvsc_probe(struct device *device)
blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device),
sizeof(struct blkvsc_request) +
- storvsc_drv_obj->RequestExtSize, 0,
+ storvsc_drv_obj->request_ext_size, 0,
SLAB_HWCACHE_ALIGN, NULL);
if (!blkdev->request_pool) {
ret = -ENOMEM;
@@ -293,7 +293,7 @@ static int blkvsc_probe(struct device *device)
/* Call to the vsc driver to add the device */
- ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, &device_info);
+ ret = storvsc_drv_obj->base.OnDeviceAdd(device_obj, &device_info);
if (ret != 0) {
DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device");
goto Cleanup;
@@ -301,9 +301,9 @@ static int blkvsc_probe(struct device *device)
blkdev->device_ctx = device_ctx;
/* this identified the device 0 or 1 */
- blkdev->target = device_info.TargetId;
+ blkdev->target = device_info.target_id;
/* this identified the ide ctrl 0 or 1 */
- blkdev->path = device_info.PathId;
+ blkdev->path = device_info.path_id;
dev_set_drvdata(device, blkdev);
@@ -391,7 +391,7 @@ static int blkvsc_probe(struct device *device)
return ret;
Remove:
- storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
+ storvsc_drv_obj->base.OnDeviceRemove(device_obj);
Cleanup:
if (blkdev) {
@@ -459,9 +459,9 @@ static int blkvsc_do_flush(struct block_device_context *blkdev)
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = 0;
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 0;
+ blkvsc_req->request.data_buffer.PfnArray[0] = 0;
+ blkvsc_req->request.data_buffer.Offset = 0;
+ blkvsc_req->request.data_buffer.Length = 0;
blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE;
blkvsc_req->cmd_len = 10;
@@ -506,9 +506,9 @@ static int blkvsc_do_inquiry(struct block_device_context *blkdev)
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 64;
+ blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf);
+ blkvsc_req->request.data_buffer.Offset = 0;
+ blkvsc_req->request.data_buffer.Length = 64;
blkvsc_req->cmnd[0] = INQUIRY;
blkvsc_req->cmnd[1] = 0x1; /* Get product data */
@@ -593,9 +593,9 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 8;
+ blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf);
+ blkvsc_req->request.data_buffer.Offset = 0;
+ blkvsc_req->request.data_buffer.Length = 8;
blkvsc_req->cmnd[0] = READ_CAPACITY;
blkvsc_req->cmd_len = 16;
@@ -614,7 +614,7 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
/* check error */
- if (blkvsc_req->request.Status) {
+ if (blkvsc_req->request.status) {
scsi_normalize_sense(blkvsc_req->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr);
@@ -670,9 +670,9 @@ static int blkvsc_do_read_capacity16(struct block_device_context *blkdev)
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 12;
+ blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf);
+ blkvsc_req->request.data_buffer.Offset = 0;
+ blkvsc_req->request.data_buffer.Length = 12;
blkvsc_req->cmnd[0] = 0x9E; /* READ_CAPACITY16; */
blkvsc_req->cmd_len = 16;
@@ -691,7 +691,7 @@ static int blkvsc_do_read_capacity16(struct block_device_context *blkdev)
wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
/* check error */
- if (blkvsc_req->request.Status) {
+ if (blkvsc_req->request.status) {
scsi_normalize_sense(blkvsc_req->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr);
if (sense_hdr.asc == 0x3A) {
@@ -741,14 +741,14 @@ static int blkvsc_remove(struct device *device)
DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n");
- if (!storvsc_drv_obj->Base.OnDeviceRemove)
+ if (!storvsc_drv_obj->base.OnDeviceRemove)
return -1;
/*
* Call to the vsc driver to let it know that the device is being
* removed
*/
- ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
+ ret = storvsc_drv_obj->base.OnDeviceRemove(device_obj);
if (ret != 0) {
/* TODO: */
DPRINT_ERR(BLKVSC_DRV,
@@ -865,38 +865,38 @@ static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
(blkvsc_req->write) ? "WRITE" : "READ",
(unsigned long) blkvsc_req->sector_start,
blkvsc_req->sector_count,
- blkvsc_req->request.DataBuffer.Offset,
- blkvsc_req->request.DataBuffer.Length);
+ blkvsc_req->request.data_buffer.Offset,
+ blkvsc_req->request.data_buffer.Length);
#if 0
- for (i = 0; i < (blkvsc_req->request.DataBuffer.Length >> 12); i++) {
+ for (i = 0; i < (blkvsc_req->request.data_buffer.Length >> 12); i++) {
DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - "
"req %p pfn[%d] %llx\n",
blkvsc_req, i,
- blkvsc_req->request.DataBuffer.PfnArray[i]);
+ blkvsc_req->request.data_buffer.PfnArray[i]);
}
#endif
storvsc_req = &blkvsc_req->request;
- storvsc_req->Extension = (void *)((unsigned long)blkvsc_req +
+ storvsc_req->extension = (void *)((unsigned long)blkvsc_req +
sizeof(struct blkvsc_request));
- storvsc_req->Type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
+ storvsc_req->type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
- storvsc_req->OnIOCompletion = request_completion;
- storvsc_req->Context = blkvsc_req;
+ storvsc_req->on_io_completion = request_completion;
+ storvsc_req->context = blkvsc_req;
- storvsc_req->Host = blkdev->port;
- storvsc_req->Bus = blkdev->path;
- storvsc_req->TargetId = blkdev->target;
- storvsc_req->LunId = 0; /* this is not really used at all */
+ storvsc_req->host = blkdev->port;
+ storvsc_req->bus = blkdev->path;
+ storvsc_req->target_id = blkdev->target;
+ storvsc_req->lun_id = 0; /* this is not really used at all */
- storvsc_req->CdbLen = blkvsc_req->cmd_len;
- storvsc_req->Cdb = blkvsc_req->cmnd;
+ storvsc_req->cdb_len = blkvsc_req->cmd_len;
+ storvsc_req->cdb = blkvsc_req->cmnd;
- storvsc_req->SenseBuffer = blkvsc_req->sense_buffer;
- storvsc_req->SenseBufferSize = SCSI_SENSE_BUFFERSIZE;
+ storvsc_req->sense_buffer = blkvsc_req->sense_buffer;
+ storvsc_req->sense_buffer_size = SCSI_SENSE_BUFFERSIZE;
- ret = storvsc_drv_obj->OnIORequest(&blkdev->device_ctx->device_obj,
+ ret = storvsc_drv_obj->on_io_request(&blkdev->device_ctx->device_obj,
&blkvsc_req->request);
if (ret == 0)
blkdev->num_outstanding_reqs++;
@@ -992,8 +992,10 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
blkvsc_req->dev = blkdev;
blkvsc_req->req = req;
- blkvsc_req->request.DataBuffer.Offset = bvec->bv_offset;
- blkvsc_req->request.DataBuffer.Length = 0;
+ blkvsc_req->request.data_buffer.Offset
+ = bvec->bv_offset;
+ blkvsc_req->request.data_buffer.Length
+ = 0;
/* Add to the group */
blkvsc_req->group = group;
@@ -1007,8 +1009,11 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
}
/* Add the curr bvec/segment to the curr blkvsc_req */
- blkvsc_req->request.DataBuffer.PfnArray[databuf_idx] = page_to_pfn(bvec->bv_page);
- blkvsc_req->request.DataBuffer.Length += bvec->bv_len;
+ blkvsc_req->request.data_buffer.
+ PfnArray[databuf_idx]
+ = page_to_pfn(bvec->bv_page);
+ blkvsc_req->request.data_buffer.Length
+ += bvec->bv_len;
prev_bvec = bvec;
@@ -1073,7 +1078,7 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
{
struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->Context;
+ (struct blkvsc_request *)request->context;
struct block_device_context *blkdev =
(struct block_device_context *)blkvsc_req->dev;
struct scsi_sense_hdr sense_hdr;
@@ -1083,7 +1088,7 @@ static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
blkdev->num_outstanding_reqs--;
- if (blkvsc_req->request.Status)
+ if (blkvsc_req->request.status)
if (scsi_normalize_sense(blkvsc_req->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr))
scsi_print_sense_hdr("blkvsc", &sense_hdr);
@@ -1095,7 +1100,7 @@ static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
static void blkvsc_request_completion(struct hv_storvsc_request *request)
{
struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->Context;
+ (struct blkvsc_request *)request->context;
struct block_device_context *blkdev =
(struct block_device_context *)blkvsc_req->dev;
unsigned long flags;
@@ -1110,7 +1115,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request)
(blkvsc_req->write) ? "WRITE" : "READ",
(unsigned long)blkvsc_req->sector_start,
blkvsc_req->sector_count,
- blkvsc_req->request.DataBuffer.Length,
+ blkvsc_req->request.data_buffer.Length,
blkvsc_req->group->outstanding,
blkdev->num_outstanding_reqs);
@@ -1137,7 +1142,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request)
list_del(&comp_req->req_entry);
if (!__blk_end_request(comp_req->req,
- (!comp_req->request.Status ? 0 : -EIO),
+ (!comp_req->request.status ? 0 : -EIO),
comp_req->sector_count * blkdev->sector_size)) {
/*
* All the sectors have been xferred ie the
@@ -1195,7 +1200,7 @@ static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
if (comp_req->req) {
ret = __blk_end_request(comp_req->req,
- (!comp_req->request.Status ? 0 : -EIO),
+ (!comp_req->request.status ? 0 : -EIO),
comp_req->sector_count *
blkdev->sector_size);
@@ -1482,7 +1487,7 @@ static int __init blkvsc_init(void)
DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing....");
- ret = blkvsc_drv_init(BlkVscInitialize);
+ ret = blkvsc_drv_init(blk_vsc_initialize);
return ret;
}
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index 26ebc77f22b7..45a627d77b41 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -43,24 +43,24 @@ static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
int j = 0;
DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
- MonitorPage, MonitorPage->TriggerState);
+ MonitorPage, MonitorPage->trigger_state);
for (i = 0; i < 4; i++)
DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
- MonitorPage->TriggerGroup[i].AsUINT64);
+ MonitorPage->trigger_group[i].as_uint64);
for (i = 0; i < 4; i++) {
for (j = 0; j < 32; j++) {
DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
- MonitorPage->Latency[i][j]);
+ MonitorPage->latency[i][j]);
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 32; j++) {
DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].ConnectionId.Asu32);
+ MonitorPage->parameter[i][j].connectionid.asu32);
DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].FlagNumber);
+ MonitorPage->parameter[i][j].flag_number);
}
}
}
@@ -74,21 +74,21 @@ static void vmbus_setevent(struct vmbus_channel *channel)
{
struct hv_monitor_page *monitorpage;
- if (channel->OfferMsg.MonitorAllocated) {
+ if (channel->offermsg.monitor_allocated) {
/* Each u32 represents 32 channels */
- set_bit(channel->OfferMsg.ChildRelId & 31,
+ set_bit(channel->offermsg.child_relid & 31,
(unsigned long *) gVmbusConnection.SendInterruptPage +
- (channel->OfferMsg.ChildRelId >> 5));
+ (channel->offermsg.child_relid >> 5));
monitorpage = gVmbusConnection.MonitorPages;
monitorpage++; /* Get the child to parent monitor page */
- set_bit(channel->MonitorBit,
- (unsigned long *)&monitorpage->TriggerGroup
- [channel->MonitorGroup].Pending);
+ set_bit(channel->monitor_bit,
+ (unsigned long *)&monitorpage->trigger_group
+ [channel->monitor_grp].pending);
} else {
- VmbusSetEvent(channel->OfferMsg.ChildRelId);
+ VmbusSetEvent(channel->offermsg.child_relid);
}
}
@@ -97,19 +97,19 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel)
{
struct hv_monitor_page *monitorPage;
- if (Channel->OfferMsg.MonitorAllocated) {
+ if (Channel->offermsg.monitor_allocated) {
/* Each u32 represents 32 channels */
- clear_bit(Channel->OfferMsg.ChildRelId & 31,
+ clear_bit(Channel->offermsg.child_relid & 31,
(unsigned long *)gVmbusConnection.SendInterruptPage +
- (Channel->OfferMsg.ChildRelId >> 5));
+ (Channel->offermsg.child_relid >> 5));
monitorPage =
(struct hv_monitor_page *)gVmbusConnection.MonitorPages;
monitorPage++; /* Get the child to parent monitor page */
- clear_bit(Channel->MonitorBit,
- (unsigned long *)&monitorPage->TriggerGroup
- [Channel->MonitorGroup].Pending);
+ clear_bit(Channel->monitor_bit,
+ (unsigned long *)&monitorPage->trigger_group
+ [Channel->monitor_grp].Pending);
}
}
@@ -121,42 +121,42 @@ void vmbus_get_debug_info(struct vmbus_channel *channel,
struct vmbus_channel_debug_info *debuginfo)
{
struct hv_monitor_page *monitorpage;
- u8 monitor_group = (u8)channel->OfferMsg.MonitorId / 32;
- u8 monitor_offset = (u8)channel->OfferMsg.MonitorId % 32;
+ u8 monitor_group = (u8)channel->offermsg.monitorid / 32;
+ u8 monitor_offset = (u8)channel->offermsg.monitorid % 32;
/* u32 monitorBit = 1 << monitorOffset; */
- debuginfo->RelId = channel->OfferMsg.ChildRelId;
- debuginfo->State = channel->State;
- memcpy(&debuginfo->InterfaceType,
- &channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
- memcpy(&debuginfo->InterfaceInstance,
- &channel->OfferMsg.Offer.InterfaceInstance,
+ debuginfo->relid = channel->offermsg.child_relid;
+ debuginfo->state = channel->state;
+ memcpy(&debuginfo->interfacetype,
+ &channel->offermsg.offer.InterfaceType, sizeof(struct hv_guid));
+ memcpy(&debuginfo->interface_instance,
+ &channel->offermsg.offer.InterfaceInstance,
sizeof(struct hv_guid));
monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
- debuginfo->MonitorId = channel->OfferMsg.MonitorId;
+ debuginfo->monitorid = channel->offermsg.monitorid;
- debuginfo->ServerMonitorPending =
- monitorpage->TriggerGroup[monitor_group].Pending;
- debuginfo->ServerMonitorLatency =
- monitorpage->Latency[monitor_group][monitor_offset];
- debuginfo->ServerMonitorConnectionId =
- monitorpage->Parameter[monitor_group]
- [monitor_offset].ConnectionId.u.Id;
+ debuginfo->servermonitor_pending =
+ monitorpage->trigger_group[monitor_group].pending;
+ debuginfo->servermonitor_latency =
+ monitorpage->latency[monitor_group][monitor_offset];
+ debuginfo->servermonitor_connectionid =
+ monitorpage->parameter[monitor_group]
+ [monitor_offset].connectionid.u.id;
monitorpage++;
- debuginfo->ClientMonitorPending =
- monitorpage->TriggerGroup[monitor_group].Pending;
- debuginfo->ClientMonitorLatency =
- monitorpage->Latency[monitor_group][monitor_offset];
- debuginfo->ClientMonitorConnectionId =
- monitorpage->Parameter[monitor_group]
- [monitor_offset].ConnectionId.u.Id;
+ debuginfo->clientmonitor_pending =
+ monitorpage->trigger_group[monitor_group].pending;
+ debuginfo->clientmonitor_latency =
+ monitorpage->latency[monitor_group][monitor_offset];
+ debuginfo->clientmonitor_connectionid =
+ monitorpage->parameter[monitor_group]
+ [monitor_offset].connectionid.u.id;
- RingBufferGetDebugInfo(&channel->Inbound, &debuginfo->Inbound);
- RingBufferGetDebugInfo(&channel->Outbound, &debuginfo->Outbound);
+ ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
+ ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
}
/*
@@ -176,11 +176,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
/* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
/* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
- newchannel->OnChannelCallback = onchannelcallback;
- newchannel->ChannelCallbackContext = context;
+ newchannel->onchannel_callback = onchannelcallback;
+ newchannel->channel_callback_context = context;
/* Allocate the ring buffer */
- out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size)
+ out = osd_page_alloc((send_ringbuffer_size + recv_ringbuffer_size)
>> PAGE_SHIFT);
if (!out)
return -ENOMEM;
@@ -189,17 +189,17 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
in = (void *)((unsigned long)out + send_ringbuffer_size);
- newchannel->RingBufferPages = out;
- newchannel->RingBufferPageCount = (send_ringbuffer_size +
+ newchannel->ringbuffer_pages = out;
+ newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
recv_ringbuffer_size) >> PAGE_SHIFT;
- ret = RingBufferInit(&newchannel->Outbound, out, send_ringbuffer_size);
+ ret = ringbuffer_init(&newchannel->outbound, out, send_ringbuffer_size);
if (ret != 0) {
err = ret;
goto errorout;
}
- ret = RingBufferInit(&newchannel->Inbound, in, recv_ringbuffer_size);
+ ret = ringbuffer_init(&newchannel->inbound, in, recv_ringbuffer_size);
if (ret != 0) {
err = ret;
goto errorout;
@@ -210,13 +210,13 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
newchannel);
- newchannel->RingBufferGpadlHandle = 0;
+ newchannel->ringbuffer_gpadlhandle = 0;
ret = vmbus_establish_gpadl(newchannel,
- newchannel->Outbound.RingBuffer,
+ newchannel->outbound.ring_buffer,
send_ringbuffer_size +
recv_ringbuffer_size,
- &newchannel->RingBufferGpadlHandle);
+ &newchannel->ringbuffer_gpadlhandle);
if (ret != 0) {
err = ret;
@@ -225,12 +225,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
"size %d recv ring %p size %d, downstreamoffset %d>",
- newchannel, newchannel->OfferMsg.ChildRelId,
- newchannel->RingBufferGpadlHandle,
- newchannel->Outbound.RingBuffer,
- newchannel->Outbound.RingSize,
- newchannel->Inbound.RingBuffer,
- newchannel->Inbound.RingSize,
+ newchannel, newchannel->offermsg.child_relid,
+ newchannel->ringbuffer_gpadlhandle,
+ newchannel->outbound.ring_buffer,
+ newchannel->outbound.ring_size,
+ newchannel->inbound.ring_buffer,
+ newchannel->inbound.ring_size,
send_ringbuffer_size);
/* Create and init the channel open message */
@@ -242,20 +242,20 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
goto errorout;
}
- openInfo->WaitEvent = osd_WaitEventCreate();
- if (!openInfo->WaitEvent) {
+ openInfo->waitevent = osd_waitevent_create();
+ if (!openInfo->waitevent) {
err = -ENOMEM;
goto errorout;
}
- openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
- openMsg->Header.MessageType = ChannelMessageOpenChannel;
- openMsg->OpenId = newchannel->OfferMsg.ChildRelId; /* FIXME */
- openMsg->ChildRelId = newchannel->OfferMsg.ChildRelId;
- openMsg->RingBufferGpadlHandle = newchannel->RingBufferGpadlHandle;
- openMsg->DownstreamRingBufferPageOffset = send_ringbuffer_size >>
+ openMsg = (struct vmbus_channel_open_channel *)openInfo->msg;
+ openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL;
+ openMsg->openid = newchannel->offermsg.child_relid; /* FIXME */
+ openMsg->child_relid = newchannel->offermsg.child_relid;
+ openMsg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
+ openMsg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
PAGE_SHIFT;
- openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
+ openMsg->server_contextarea_gpadlhandle = 0; /* TODO */
if (userdatalen > MAX_USER_DEFINED_BYTES) {
err = -EINVAL;
@@ -263,10 +263,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
}
if (userdatalen)
- memcpy(openMsg->UserData, userdata, userdatalen);
+ memcpy(openMsg->userdata, userdata, userdatalen);
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&openInfo->MsgListEntry,
+ list_add_tail(&openInfo->msglistentry,
&gVmbusConnection.ChannelMsgList);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
@@ -280,27 +280,27 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
}
/* FIXME: Need to time-out here */
- osd_WaitEventWait(openInfo->WaitEvent);
+ osd_waitevent_wait(openInfo->waitevent);
- if (openInfo->Response.OpenResult.Status == 0)
+ if (openInfo->response.open_result.status == 0)
DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
else
DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
- newchannel, openInfo->Response.OpenResult.Status);
+ newchannel, openInfo->response.open_result.status);
Cleanup:
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&openInfo->MsgListEntry);
+ list_del(&openInfo->msglistentry);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
- kfree(openInfo->WaitEvent);
+ kfree(openInfo->waitevent);
kfree(openInfo);
return 0;
errorout:
- RingBufferCleanup(&newchannel->Outbound);
- RingBufferCleanup(&newchannel->Inbound);
- osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size)
+ ringbuffer_cleanup(&newchannel->outbound);
+ ringbuffer_cleanup(&newchannel->inbound);
+ osd_page_free(out, (send_ringbuffer_size + recv_ringbuffer_size)
>> PAGE_SHIFT);
kfree(openInfo);
return err;
@@ -322,7 +322,7 @@ static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
for (i = 0; i < pfncount; i++)
DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
- i, gpadl->Pfn[i]);
+ i, gpadl->pfn[i]);
}
/*
@@ -336,18 +336,18 @@ static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl)
DPRINT_DBG(VMBUS,
"gpadl header - relid %d, range count %d, range buflen %d",
- gpadl->ChildRelId, gpadl->RangeCount, gpadl->RangeBufLen);
- for (i = 0; i < gpadl->RangeCount; i++) {
- pagecount = gpadl->Range[i].ByteCount >> PAGE_SHIFT;
+ gpadl->child_relid, gpadl->rangecount, gpadl->range_buflen);
+ for (i = 0; i < gpadl->rangecount; i++) {
+ pagecount = gpadl->range[i].ByteCount >> PAGE_SHIFT;
pagecount = (pagecount > 26) ? 26 : pagecount;
DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
- "page count %d", i, gpadl->Range[i].ByteCount,
- gpadl->Range[i].ByteOffset, pagecount);
+ "page count %d", i, gpadl->range[i].ByteCount,
+ gpadl->range[i].ByteOffset, pagecount);
for (j = 0; j < pagecount; j++)
DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
- gpadl->Range[i].PfnArray[j]);
+ gpadl->range[i].PfnArray[j]);
}
}
@@ -391,18 +391,18 @@ static int create_gpadl_header(void *kbuffer, u32 size,
if (!msgheader)
goto nomem;
- INIT_LIST_HEAD(&msgheader->SubMsgList);
- msgheader->MessageSize = msgsize;
+ INIT_LIST_HEAD(&msgheader->submsglist);
+ msgheader->msgsize = msgsize;
gpadl_header = (struct vmbus_channel_gpadl_header *)
- msgheader->Msg;
- gpadl_header->RangeCount = 1;
- gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
+ msgheader->msg;
+ gpadl_header->rangecount = 1;
+ gpadl_header->range_buflen = sizeof(struct gpa_range) +
pagecount * sizeof(u64);
- gpadl_header->Range[0].ByteOffset = 0;
- gpadl_header->Range[0].ByteCount = size;
+ gpadl_header->range[0].ByteOffset = 0;
+ gpadl_header->range[0].ByteCount = size;
for (i = 0; i < pfncount; i++)
- gpadl_header->Range[0].PfnArray[i] = pfn+i;
+ gpadl_header->range[0].PfnArray[i] = pfn+i;
*msginfo = msgheader;
*messagecount = 1;
@@ -428,10 +428,10 @@ static int create_gpadl_header(void *kbuffer, u32 size,
/* FIXME: we probably need to more if this fails */
if (!msgbody)
goto nomem;
- msgbody->MessageSize = msgsize;
+ msgbody->msgsize = msgsize;
(*messagecount)++;
gpadl_body =
- (struct vmbus_channel_gpadl_body *)msgbody->Msg;
+ (struct vmbus_channel_gpadl_body *)msgbody->msg;
/*
* FIXME:
@@ -440,11 +440,11 @@ static int create_gpadl_header(void *kbuffer, u32 size,
*/
/* gpadl_body->Gpadl = kbuffer; */
for (i = 0; i < pfncurr; i++)
- gpadl_body->Pfn[i] = pfn + pfnsum + i;
+ gpadl_body->pfn[i] = pfn + pfnsum + i;
/* add to msg header */
- list_add_tail(&msgbody->MsgListEntry,
- &msgheader->SubMsgList);
+ list_add_tail(&msgbody->msglistentry,
+ &msgheader->submsglist);
pfnsum += pfncurr;
pfnleft -= pfncurr;
}
@@ -456,17 +456,17 @@ static int create_gpadl_header(void *kbuffer, u32 size,
msgheader = kzalloc(msgsize, GFP_KERNEL);
if (msgheader == NULL)
goto nomem;
- msgheader->MessageSize = msgsize;
+ msgheader->msgsize = msgsize;
gpadl_header = (struct vmbus_channel_gpadl_header *)
- msgheader->Msg;
- gpadl_header->RangeCount = 1;
- gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
+ msgheader->msg;
+ gpadl_header->rangecount = 1;
+ gpadl_header->range_buflen = sizeof(struct gpa_range) +
pagecount * sizeof(u64);
- gpadl_header->Range[0].ByteOffset = 0;
- gpadl_header->Range[0].ByteCount = size;
+ gpadl_header->range[0].ByteOffset = 0;
+ gpadl_header->range[0].ByteCount = size;
for (i = 0; i < pagecount; i++)
- gpadl_header->Range[0].PfnArray[i] = pfn+i;
+ gpadl_header->range[0].PfnArray[i] = pfn+i;
*msginfo = msgheader;
*messagecount = 1;
@@ -508,21 +508,21 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
if (ret)
return ret;
- msginfo->WaitEvent = osd_WaitEventCreate();
- if (!msginfo->WaitEvent) {
+ msginfo->waitevent = osd_waitevent_create();
+ if (!msginfo->waitevent) {
ret = -ENOMEM;
goto Cleanup;
}
- gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->Msg;
- gpadlmsg->Header.MessageType = ChannelMessageGpadlHeader;
- gpadlmsg->ChildRelId = channel->OfferMsg.ChildRelId;
- gpadlmsg->Gpadl = next_gpadl_handle;
+ gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
+ gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
+ gpadlmsg->child_relid = channel->offermsg.child_relid;
+ gpadlmsg->gpadl = next_gpadl_handle;
dump_gpadl_header(gpadlmsg);
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&msginfo->MsgListEntry,
+ list_add_tail(&msginfo->msglistentry,
&gVmbusConnection.ChannelMsgList);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
@@ -530,9 +530,9 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
kbuffer, size, msgcount);
DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
- msginfo->MessageSize - sizeof(*msginfo));
+ msginfo->msgsize - sizeof(*msginfo));
- ret = VmbusPostMessage(gpadlmsg, msginfo->MessageSize -
+ ret = VmbusPostMessage(gpadlmsg, msginfo->msgsize -
sizeof(*msginfo));
if (ret != 0) {
DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
@@ -540,48 +540,48 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
}
if (msgcount > 1) {
- list_for_each(curr, &msginfo->SubMsgList) {
+ list_for_each(curr, &msginfo->submsglist) {
/* FIXME: should this use list_entry() instead ? */
submsginfo = (struct vmbus_channel_msginfo *)curr;
gpadl_body =
- (struct vmbus_channel_gpadl_body *)submsginfo->Msg;
+ (struct vmbus_channel_gpadl_body *)submsginfo->msg;
- gpadl_body->Header.MessageType =
- ChannelMessageGpadlBody;
- gpadl_body->Gpadl = next_gpadl_handle;
+ gpadl_body->header.msgtype =
+ CHANNELMSG_GPADL_BODY;
+ gpadl_body->gpadl = next_gpadl_handle;
DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
- submsginfo->MessageSize -
+ submsginfo->msgsize -
sizeof(*submsginfo));
- dump_gpadl_body(gpadl_body, submsginfo->MessageSize -
+ dump_gpadl_body(gpadl_body, submsginfo->msgsize -
sizeof(*submsginfo));
ret = VmbusPostMessage(gpadl_body,
- submsginfo->MessageSize -
+ submsginfo->msgsize -
sizeof(*submsginfo));
if (ret != 0)
goto Cleanup;
}
}
- osd_WaitEventWait(msginfo->WaitEvent);
+ osd_waitevent_wait(msginfo->waitevent);
/* At this point, we received the gpadl created msg */
DPRINT_DBG(VMBUS, "Received GPADL created "
"(relid %d, status %d handle %x)",
- channel->OfferMsg.ChildRelId,
- msginfo->Response.GpadlCreated.CreationStatus,
- gpadlmsg->Gpadl);
+ channel->offermsg.child_relid,
+ msginfo->response.gpadl_created.creation_status,
+ gpadlmsg->gpadl);
- *gpadl_handle = gpadlmsg->Gpadl;
+ *gpadl_handle = gpadlmsg->gpadl;
Cleanup:
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&msginfo->MsgListEntry);
+ list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
- kfree(msginfo->WaitEvent);
+ kfree(msginfo->waitevent);
kfree(msginfo);
return ret;
}
@@ -604,20 +604,20 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
if (!info)
return -ENOMEM;
- info->WaitEvent = osd_WaitEventCreate();
- if (!info->WaitEvent) {
+ info->waitevent = osd_waitevent_create();
+ if (!info->waitevent) {
kfree(info);
return -ENOMEM;
}
- msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
+ msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
- msg->Header.MessageType = ChannelMessageGpadlTeardown;
- msg->ChildRelId = channel->OfferMsg.ChildRelId;
- msg->Gpadl = gpadl_handle;
+ msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
+ msg->child_relid = channel->offermsg.child_relid;
+ msg->gpadl = gpadl_handle;
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&info->MsgListEntry,
+ list_add_tail(&info->msglistentry,
&gVmbusConnection.ChannelMsgList);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
@@ -628,14 +628,14 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
/* something... */
}
- osd_WaitEventWait(info->WaitEvent);
+ osd_waitevent_wait(info->waitevent);
/* Received a torndown response */
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&info->MsgListEntry);
+ list_del(&info->msglistentry);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
- kfree(info->WaitEvent);
+ kfree(info->waitevent);
kfree(info);
return ret;
}
@@ -652,7 +652,7 @@ void vmbus_close(struct vmbus_channel *channel)
int ret;
/* Stop callback and cancel the timer asap */
- channel->OnChannelCallback = NULL;
+ channel->onchannel_callback = NULL;
del_timer_sync(&channel->poll_timer);
/* Send a closing message */
@@ -663,11 +663,11 @@ void vmbus_close(struct vmbus_channel *channel)
if (!info)
return;
- /* info->waitEvent = osd_WaitEventCreate(); */
+ /* info->waitEvent = osd_waitevent_create(); */
- msg = (struct vmbus_channel_close_channel *)info->Msg;
- msg->Header.MessageType = ChannelMessageCloseChannel;
- msg->ChildRelId = channel->OfferMsg.ChildRelId;
+ msg = (struct vmbus_channel_close_channel *)info->msg;
+ msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
+ msg->child_relid = channel->offermsg.child_relid;
ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
if (ret != 0) {
@@ -676,17 +676,17 @@ void vmbus_close(struct vmbus_channel *channel)
}
/* Tear down the gpadl for the channel's ring buffer */
- if (channel->RingBufferGpadlHandle)
+ if (channel->ringbuffer_gpadlhandle)
vmbus_teardown_gpadl(channel,
- channel->RingBufferGpadlHandle);
+ channel->ringbuffer_gpadlhandle);
/* TODO: Send a msg to release the childRelId */
/* Cleanup the ring buffers for this channel */
- RingBufferCleanup(&channel->Outbound);
- RingBufferCleanup(&channel->Inbound);
+ ringbuffer_cleanup(&channel->outbound);
+ ringbuffer_cleanup(&channel->inbound);
- osd_PageFree(channel->RingBufferPages, channel->RingBufferPageCount);
+ osd_page_free(channel->ringbuffer_pages, channel->ringbuffer_pagecount);
kfree(info);
@@ -696,9 +696,9 @@ void vmbus_close(struct vmbus_channel *channel)
* caller will free the channel
*/
- if (channel->State == CHANNEL_OPEN_STATE) {
+ if (channel->state == CHANNEL_OPEN_STATE) {
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&channel->ListEntry);
+ list_del(&channel->listentry);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
free_channel(channel);
@@ -752,10 +752,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+ ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -817,10 +817,10 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+ ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -886,10 +886,10 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+ ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -923,7 +923,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
spin_lock_irqsave(&channel->inbound_lock, flags);
- ret = RingBufferPeek(&channel->Inbound, &desc,
+ ret = ringbuffer_peek(&channel->inbound, &desc,
sizeof(struct vmpacket_descriptor));
if (ret != 0) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
@@ -940,7 +940,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
"flag %d tid %llx pktlen %d datalen %d> ",
- channel, channel->OfferMsg.ChildRelId, desc.Type,
+ channel, channel->offermsg.child_relid, desc.Type,
desc.Flags, desc.TransactionId, packetlen, userlen);
*buffer_actual_len = userlen;
@@ -956,7 +956,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
*requestid = desc.TransactionId;
/* Copy over the packet to the user buffer */
- ret = RingBufferRead(&channel->Inbound, buffer, userlen,
+ ret = ringbuffer_read(&channel->inbound, buffer, userlen,
(desc.DataOffset8 << 3));
spin_unlock_irqrestore(&channel->inbound_lock, flags);
@@ -983,7 +983,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
spin_lock_irqsave(&channel->inbound_lock, flags);
- ret = RingBufferPeek(&channel->Inbound, &desc,
+ ret = ringbuffer_peek(&channel->inbound, &desc,
sizeof(struct vmpacket_descriptor));
if (ret != 0) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
@@ -999,7 +999,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
"flag %d tid %llx pktlen %d datalen %d> ",
- channel, channel->OfferMsg.ChildRelId, desc.Type,
+ channel, channel->offermsg.child_relid, desc.Type,
desc.Flags, desc.TransactionId, packetlen, userlen);
*buffer_actual_len = packetlen;
@@ -1015,7 +1015,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
*requestid = desc.TransactionId;
/* Copy over the entire packet to the user buffer */
- ret = RingBufferRead(&channel->Inbound, buffer, packetlen, 0);
+ ret = ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
spin_unlock_irqrestore(&channel->inbound_lock, flags);
return 0;
@@ -1030,7 +1030,7 @@ void vmbus_onchannel_event(struct vmbus_channel *channel)
dump_vmbus_channel(channel);
/* ASSERT(Channel->OnChannelCallback); */
- channel->OnChannelCallback(channel->ChannelCallbackContext);
+ channel->onchannel_callback(channel->channel_callback_context);
mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100));
}
@@ -1042,8 +1042,8 @@ void vmbus_ontimer(unsigned long data)
{
struct vmbus_channel *channel = (struct vmbus_channel *)data;
- if (channel->OnChannelCallback)
- channel->OnChannelCallback(channel->ChannelCallbackContext);
+ if (channel->onchannel_callback)
+ channel->onchannel_callback(channel->channel_callback_context);
}
/*
@@ -1051,7 +1051,7 @@ void vmbus_ontimer(unsigned long data)
*/
static void dump_vmbus_channel(struct vmbus_channel *channel)
{
- DPRINT_DBG(VMBUS, "Channel (%d)", channel->OfferMsg.ChildRelId);
- DumpRingInfo(&channel->Outbound, "Outbound ");
- DumpRingInfo(&channel->Inbound, "Inbound ");
+ DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid);
+ dump_ring_info(&channel->outbound, "Outbound ");
+ dump_ring_info(&channel->inbound, "Inbound ");
}
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 45dbe305afed..d44d5c39f68b 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -251,8 +251,8 @@ static struct vmbus_channel *alloc_channel(void)
channel->poll_timer.data = (unsigned long)channel;
channel->poll_timer.function = vmbus_ontimer;
- channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
- if (!channel->ControlWQ) {
+ channel->controlwq = create_workqueue("hv_vmbus_ctl");
+ if (!channel->controlwq) {
kfree(channel);
return NULL;
}
@@ -263,12 +263,14 @@ static struct vmbus_channel *alloc_channel(void)
/*
* release_hannel - Release the vmbus channel object itself
*/
-static inline void release_channel(void *context)
+static void release_channel(struct work_struct *work)
{
- struct vmbus_channel *channel = context;
+ struct vmbus_channel *channel = container_of(work,
+ struct vmbus_channel,
+ work);
DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
- destroy_workqueue(channel->ControlWQ);
+ destroy_workqueue(channel->controlwq);
DPRINT_DBG(VMBUS, "channel released (%p)", channel);
kfree(channel);
@@ -286,8 +288,8 @@ void free_channel(struct vmbus_channel *channel)
* workqueue/thread context
* ie we can't destroy ourselves.
*/
- osd_schedule_callback(gVmbusConnection.WorkQueue, release_channel,
- channel);
+ INIT_WORK(&channel->work, release_channel);
+ queue_work(gVmbusConnection.WorkQueue, &channel->work);
}
@@ -308,29 +310,46 @@ static void count_hv_channel(void)
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
}
+/*
+ * vmbus_process_rescind_offer -
+ * Rescind the offer by initiating a device removal
+ */
+static void vmbus_process_rescind_offer(struct work_struct *work)
+{
+ struct vmbus_channel *channel = container_of(work,
+ struct vmbus_channel,
+ work);
+
+ vmbus_child_device_unregister(channel->device_obj);
+}
/*
* vmbus_process_offer - Process the offer by creating a channel/device
* associated with this offer
*/
-static void vmbus_process_offer(void *context)
+static void vmbus_process_offer(struct work_struct *work)
{
- struct vmbus_channel *newchannel = context;
+ struct vmbus_channel *newchannel = container_of(work,
+ struct vmbus_channel,
+ work);
struct vmbus_channel *channel;
bool fnew = true;
int ret;
int cnt;
unsigned long flags;
+ /* The next possible work is rescind handling */
+ INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
+
/* Make sure this is a new offer */
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
- if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
- &newchannel->OfferMsg.Offer.InterfaceType,
+ list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) {
+ if (!memcmp(&channel->offermsg.offer.InterfaceType,
+ &newchannel->offermsg.offer.InterfaceType,
sizeof(struct hv_guid)) &&
- !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
- &newchannel->OfferMsg.Offer.InterfaceInstance,
+ !memcmp(&channel->offermsg.offer.InterfaceInstance,
+ &newchannel->offermsg.offer.InterfaceInstance,
sizeof(struct hv_guid))) {
fnew = false;
break;
@@ -338,14 +357,14 @@ static void vmbus_process_offer(void *context)
}
if (fnew)
- list_add_tail(&newchannel->ListEntry,
+ list_add_tail(&newchannel->listentry,
&gVmbusConnection.ChannelList);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
if (!fnew) {
DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
- newchannel->OfferMsg.ChildRelId);
+ newchannel->offermsg.child_relid);
free_channel(newchannel);
return;
}
@@ -355,27 +374,27 @@ static void vmbus_process_offer(void *context)
* We need to set the DeviceObject field before calling
* VmbusChildDeviceAdd()
*/
- newchannel->DeviceObject = VmbusChildDeviceCreate(
- &newchannel->OfferMsg.Offer.InterfaceType,
- &newchannel->OfferMsg.Offer.InterfaceInstance,
+ newchannel->device_obj = vmbus_child_device_create(
+ &newchannel->offermsg.offer.InterfaceType,
+ &newchannel->offermsg.offer.InterfaceInstance,
newchannel);
DPRINT_DBG(VMBUS, "child device object allocated - %p",
- newchannel->DeviceObject);
+ newchannel->device_obj);
/*
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
- ret = VmbusChildDeviceAdd(newchannel->DeviceObject);
+ ret = VmbusChildDeviceAdd(newchannel->device_obj);
if (ret != 0) {
DPRINT_ERR(VMBUS,
"unable to add child device object (relid %d)",
- newchannel->OfferMsg.ChildRelId);
+ newchannel->offermsg.child_relid);
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&newchannel->ListEntry);
+ list_del(&newchannel->listentry);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
free_channel(newchannel);
@@ -385,11 +404,11 @@ static void vmbus_process_offer(void *context)
* so that when we do close the channel normally, we
* can cleanup properly
*/
- newchannel->State = CHANNEL_OPEN_STATE;
+ newchannel->state = CHANNEL_OPEN_STATE;
/* Open IC channels */
for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
- if (memcmp(&newchannel->OfferMsg.Offer.InterfaceType,
+ if (memcmp(&newchannel->offermsg.offer.InterfaceType,
&hv_cb_utils[cnt].data,
sizeof(struct hv_guid)) == 0 &&
vmbus_open(newchannel, 2 * PAGE_SIZE,
@@ -406,17 +425,6 @@ static void vmbus_process_offer(void *context)
}
/*
- * vmbus_process_rescind_offer -
- * Rescind the offer by initiating a device removal
- */
-static void vmbus_process_rescind_offer(void *context)
-{
- struct vmbus_channel *channel = context;
-
- VmbusChildDeviceRemove(channel->DeviceObject);
-}
-
-/*
* vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
*
* We ignore all offers except network and storage offers. For each network and
@@ -434,7 +442,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
offer = (struct vmbus_channel_offer_channel *)hdr;
for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
- if (memcmp(&offer->Offer.InterfaceType,
+ if (memcmp(&offer->offer.InterfaceType,
&gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
fsupported = 1;
break;
@@ -443,12 +451,12 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
if (!fsupported) {
DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
- "child relid %d", offer->ChildRelId);
+ "child relid %d", offer->child_relid);
return;
}
- guidtype = &offer->Offer.InterfaceType;
- guidinstance = &offer->Offer.InterfaceInstance;
+ guidtype = &offer->offer.InterfaceType;
+ guidinstance = &offer->offer.InterfaceInstance;
DPRINT_INFO(VMBUS, "Channel offer notification - "
"child relid %d monitor id %d allocated %d, "
@@ -456,8 +464,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
"%02x%02x%02x%02x%02x%02x%02x%02x} "
"instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}",
- offer->ChildRelId, offer->MonitorId,
- offer->MonitorAllocated,
+ offer->child_relid, offer->monitorid,
+ offer->monitor_allocated,
guidtype->data[3], guidtype->data[2],
guidtype->data[1], guidtype->data[0],
guidtype->data[5], guidtype->data[4],
@@ -484,14 +492,14 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
DPRINT_DBG(VMBUS, "channel object allocated - %p", newchannel);
- memcpy(&newchannel->OfferMsg, offer,
+ memcpy(&newchannel->offermsg, offer,
sizeof(struct vmbus_channel_offer_channel));
- newchannel->MonitorGroup = (u8)offer->MonitorId / 32;
- newchannel->MonitorBit = (u8)offer->MonitorId % 32;
+ newchannel->monitor_grp = (u8)offer->monitorid / 32;
+ newchannel->monitor_bit = (u8)offer->monitorid % 32;
/* TODO: Make sure the offer comes from our parent partition */
- osd_schedule_callback(newchannel->ControlWQ, vmbus_process_offer,
- newchannel);
+ INIT_WORK(&newchannel->work, vmbus_process_offer);
+ queue_work(newchannel->controlwq, &newchannel->work);
}
/*
@@ -505,16 +513,16 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
struct vmbus_channel *channel;
rescind = (struct vmbus_channel_rescind_offer *)hdr;
- channel = GetChannelFromRelId(rescind->ChildRelId);
+ channel = GetChannelFromRelId(rescind->child_relid);
if (channel == NULL) {
DPRINT_DBG(VMBUS, "channel not found for relId %d",
- rescind->ChildRelId);
+ rescind->child_relid);
return;
}
- osd_schedule_callback(channel->ControlWQ,
- vmbus_process_rescind_offer,
- channel);
+ /* work is initialized for vmbus_process_rescind_offer() from
+ * vmbus_process_offer() where the channel got created */
+ queue_work(channel->controlwq, &channel->work);
}
/*
@@ -545,7 +553,7 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
unsigned long flags;
result = (struct vmbus_channel_open_result *)hdr;
- DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
+ DPRINT_DBG(VMBUS, "vmbus open result - %d", result->status);
/*
* Find the open msg, copy the result and signal/unblock the wait event
@@ -556,17 +564,17 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
/* FIXME: this should probably use list_entry() instead */
msginfo = (struct vmbus_channel_msginfo *)curr;
requestheader =
- (struct vmbus_channel_message_header *)msginfo->Msg;
+ (struct vmbus_channel_message_header *)msginfo->msg;
- if (requestheader->MessageType == ChannelMessageOpenChannel) {
+ if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
openmsg =
- (struct vmbus_channel_open_channel *)msginfo->Msg;
- if (openmsg->ChildRelId == result->ChildRelId &&
- openmsg->OpenId == result->OpenId) {
- memcpy(&msginfo->Response.OpenResult,
+ (struct vmbus_channel_open_channel *)msginfo->msg;
+ if (openmsg->child_relid == result->child_relid &&
+ openmsg->openid == result->openid) {
+ memcpy(&msginfo->response.open_result,
result,
sizeof(struct vmbus_channel_open_result));
- osd_WaitEventSet(msginfo->WaitEvent);
+ osd_waitevent_set(msginfo->waitevent);
break;
}
}
@@ -592,7 +600,7 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
- gpadlcreated->CreationStatus);
+ gpadlcreated->creation_status);
/*
* Find the establish msg, copy the result and signal/unblock the wait
@@ -604,19 +612,19 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
/* FIXME: this should probably use list_entry() instead */
msginfo = (struct vmbus_channel_msginfo *)curr;
requestheader =
- (struct vmbus_channel_message_header *)msginfo->Msg;
+ (struct vmbus_channel_message_header *)msginfo->msg;
- if (requestheader->MessageType == ChannelMessageGpadlHeader) {
+ if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
gpadlheader =
(struct vmbus_channel_gpadl_header *)requestheader;
- if ((gpadlcreated->ChildRelId ==
- gpadlheader->ChildRelId) &&
- (gpadlcreated->Gpadl == gpadlheader->Gpadl)) {
- memcpy(&msginfo->Response.GpadlCreated,
+ if ((gpadlcreated->child_relid ==
+ gpadlheader->child_relid) &&
+ (gpadlcreated->gpadl == gpadlheader->gpadl)) {
+ memcpy(&msginfo->response.gpadl_created,
gpadlcreated,
sizeof(struct vmbus_channel_gpadl_created));
- osd_WaitEventSet(msginfo->WaitEvent);
+ osd_waitevent_set(msginfo->waitevent);
break;
}
}
@@ -652,17 +660,17 @@ static void vmbus_ongpadl_torndown(
/* FIXME: this should probably use list_entry() instead */
msginfo = (struct vmbus_channel_msginfo *)curr;
requestheader =
- (struct vmbus_channel_message_header *)msginfo->Msg;
+ (struct vmbus_channel_message_header *)msginfo->msg;
- if (requestheader->MessageType == ChannelMessageGpadlTeardown) {
+ if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
gpadl_teardown =
(struct vmbus_channel_gpadl_teardown *)requestheader;
- if (gpadl_torndown->Gpadl == gpadl_teardown->Gpadl) {
- memcpy(&msginfo->Response.GpadlTorndown,
+ if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
+ memcpy(&msginfo->response.gpadl_torndown,
gpadl_torndown,
sizeof(struct vmbus_channel_gpadl_torndown));
- osd_WaitEventSet(msginfo->WaitEvent);
+ osd_waitevent_set(msginfo->waitevent);
break;
}
}
@@ -694,16 +702,16 @@ static void vmbus_onversion_response(
/* FIXME: this should probably use list_entry() instead */
msginfo = (struct vmbus_channel_msginfo *)curr;
requestheader =
- (struct vmbus_channel_message_header *)msginfo->Msg;
+ (struct vmbus_channel_message_header *)msginfo->msg;
- if (requestheader->MessageType ==
- ChannelMessageInitiateContact) {
+ if (requestheader->msgtype ==
+ CHANNELMSG_INITIATE_CONTACT) {
initiate =
(struct vmbus_channel_initiate_contact *)requestheader;
- memcpy(&msginfo->Response.VersionResponse,
+ memcpy(&msginfo->response.version_response,
version_response,
sizeof(struct vmbus_channel_version_response));
- osd_WaitEventSet(msginfo->WaitEvent);
+ osd_waitevent_set(msginfo->waitevent);
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
@@ -711,24 +719,24 @@ static void vmbus_onversion_response(
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
- gChannelMessageTable[ChannelMessageCount] = {
- {ChannelMessageInvalid, NULL},
- {ChannelMessageOfferChannel, vmbus_onoffer},
- {ChannelMessageRescindChannelOffer, vmbus_onoffer_rescind},
- {ChannelMessageRequestOffers, NULL},
- {ChannelMessageAllOffersDelivered, vmbus_onoffers_delivered},
- {ChannelMessageOpenChannel, NULL},
- {ChannelMessageOpenChannelResult, vmbus_onopen_result},
- {ChannelMessageCloseChannel, NULL},
- {ChannelMessageGpadlHeader, NULL},
- {ChannelMessageGpadlBody, NULL},
- {ChannelMessageGpadlCreated, vmbus_ongpadl_created},
- {ChannelMessageGpadlTeardown, NULL},
- {ChannelMessageGpadlTorndown, vmbus_ongpadl_torndown},
- {ChannelMessageRelIdReleased, NULL},
- {ChannelMessageInitiateContact, NULL},
- {ChannelMessageVersionResponse, vmbus_onversion_response},
- {ChannelMessageUnload, NULL},
+ gChannelMessageTable[CHANNELMSG_COUNT] = {
+ {CHANNELMSG_INVALID, NULL},
+ {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer},
+ {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind},
+ {CHANNELMSG_REQUESTOFFERS, NULL},
+ {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered},
+ {CHANNELMSG_OPENCHANNEL, NULL},
+ {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
+ {CHANNELMSG_CLOSECHANNEL, NULL},
+ {CHANNELMSG_GPADL_HEADER, NULL},
+ {CHANNELMSG_GPADL_BODY, NULL},
+ {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created},
+ {CHANNELMSG_GPADL_TEARDOWN, NULL},
+ {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown},
+ {CHANNELMSG_RELID_RELEASED, NULL},
+ {CHANNELMSG_INITIATE_CONTACT, NULL},
+ {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response},
+ {CHANNELMSG_UNLOAD, NULL},
};
/*
@@ -742,29 +750,25 @@ void vmbus_onmessage(void *context)
struct vmbus_channel_message_header *hdr;
int size;
- hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
- size = msg->Header.PayloadSize;
+ hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+ size = msg->header.payload_size;
- DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
+ DPRINT_DBG(VMBUS, "message type %d size %d", hdr->msgtype, size);
- if (hdr->MessageType >= ChannelMessageCount) {
+ if (hdr->msgtype >= CHANNELMSG_COUNT) {
DPRINT_ERR(VMBUS,
"Received invalid channel message type %d size %d",
- hdr->MessageType, size);
+ hdr->msgtype, size);
print_hex_dump_bytes("", DUMP_PREFIX_NONE,
- (unsigned char *)msg->u.Payload, size);
- kfree(msg);
+ (unsigned char *)msg->u.payload, size);
return;
}
- if (gChannelMessageTable[hdr->MessageType].messageHandler)
- gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
+ if (gChannelMessageTable[hdr->msgtype].messageHandler)
+ gChannelMessageTable[hdr->msgtype].messageHandler(hdr);
else
DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
- hdr->MessageType);
-
- /* Free the msg that was allocated in VmbusOnMsgDPC() */
- kfree(msg);
+ hdr->msgtype);
}
/*
@@ -782,15 +786,15 @@ int vmbus_request_offers(void)
if (!msginfo)
return -ENOMEM;
- msginfo->WaitEvent = osd_WaitEventCreate();
- if (!msginfo->WaitEvent) {
+ msginfo->waitevent = osd_waitevent_create();
+ if (!msginfo->waitevent) {
kfree(msginfo);
return -ENOMEM;
}
- msg = (struct vmbus_channel_message_header *)msginfo->Msg;
+ msg = (struct vmbus_channel_message_header *)msginfo->msg;
- msg->MessageType = ChannelMessageRequestOffers;
+ msg->msgtype = CHANNELMSG_REQUESTOFFERS;
/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
@@ -808,7 +812,7 @@ int vmbus_request_offers(void)
goto Cleanup;
}
- /* osd_WaitEventWait(msgInfo->waitEvent); */
+ /* osd_waitevent_wait(msgInfo->waitEvent); */
/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
@@ -817,7 +821,7 @@ int vmbus_request_offers(void)
Cleanup:
if (msginfo) {
- kfree(msginfo->WaitEvent);
+ kfree(msginfo->waitevent);
kfree(msginfo);
}
@@ -837,17 +841,17 @@ void vmbus_release_unattached_channels(void)
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
- ListEntry) {
+ listentry) {
if (channel == start)
break;
- if (!channel->DeviceObject->Driver) {
- list_del(&channel->ListEntry);
+ if (!channel->device_obj->Driver) {
+ list_del(&channel->listentry);
DPRINT_INFO(VMBUS,
"Releasing unattached device object %p",
- channel->DeviceObject);
+ channel->device_obj);
- VmbusChildDeviceRemove(channel->DeviceObject);
+ vmbus_child_device_unregister(channel->device_obj);
free_channel(channel);
} else {
if (!start)
diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h
index d16cc0811169..de6b2a0ebf70 100644
--- a/drivers/staging/hv/channel_mgmt.h
+++ b/drivers/staging/hv/channel_mgmt.h
@@ -33,60 +33,60 @@
/* Version 1 messages */
enum vmbus_channel_message_type {
- ChannelMessageInvalid = 0,
- ChannelMessageOfferChannel = 1,
- ChannelMessageRescindChannelOffer = 2,
- ChannelMessageRequestOffers = 3,
- ChannelMessageAllOffersDelivered = 4,
- ChannelMessageOpenChannel = 5,
- ChannelMessageOpenChannelResult = 6,
- ChannelMessageCloseChannel = 7,
- ChannelMessageGpadlHeader = 8,
- ChannelMessageGpadlBody = 9,
- ChannelMessageGpadlCreated = 10,
- ChannelMessageGpadlTeardown = 11,
- ChannelMessageGpadlTorndown = 12,
- ChannelMessageRelIdReleased = 13,
- ChannelMessageInitiateContact = 14,
- ChannelMessageVersionResponse = 15,
- ChannelMessageUnload = 16,
+ CHANNELMSG_INVALID = 0,
+ CHANNELMSG_OFFERCHANNEL = 1,
+ CHANNELMSG_RESCIND_CHANNELOFFER = 2,
+ CHANNELMSG_REQUESTOFFERS = 3,
+ CHANNELMSG_ALLOFFERS_DELIVERED = 4,
+ CHANNELMSG_OPENCHANNEL = 5,
+ CHANNELMSG_OPENCHANNEL_RESULT = 6,
+ CHANNELMSG_CLOSECHANNEL = 7,
+ CHANNELMSG_GPADL_HEADER = 8,
+ CHANNELMSG_GPADL_BODY = 9,
+ CHANNELMSG_GPADL_CREATED = 10,
+ CHANNELMSG_GPADL_TEARDOWN = 11,
+ CHANNELMSG_GPADL_TORNDOWN = 12,
+ CHANNELMSG_RELID_RELEASED = 13,
+ CHANNELMSG_INITIATE_CONTACT = 14,
+ CHANNELMSG_VERSION_RESPONSE = 15,
+ CHANNELMSG_UNLOAD = 16,
#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
- ChannelMessageViewRangeAdd = 17,
- ChannelMessageViewRangeRemove = 18,
+ CHANNELMSG_VIEWRANGE_ADD = 17,
+ CHANNELMSG_VIEWRANGE_REMOVE = 18,
#endif
- ChannelMessageCount
+ CHANNELMSG_COUNT
};
struct vmbus_channel_message_header {
- enum vmbus_channel_message_type MessageType;
- u32 Padding;
+ enum vmbus_channel_message_type msgtype;
+ u32 padding;
} __attribute__((packed));
/* Query VMBus Version parameters */
struct vmbus_channel_query_vmbus_version {
- struct vmbus_channel_message_header Header;
- u32 Version;
+ struct vmbus_channel_message_header header;
+ u32 version;
} __attribute__((packed));
/* VMBus Version Supported parameters */
struct vmbus_channel_version_supported {
- struct vmbus_channel_message_header Header;
- bool VersionSupported;
+ struct vmbus_channel_message_header header;
+ bool version_supported;
} __attribute__((packed));
/* Offer Channel parameters */
struct vmbus_channel_offer_channel {
- struct vmbus_channel_message_header Header;
- struct vmbus_channel_offer Offer;
- u32 ChildRelId;
- u8 MonitorId;
- bool MonitorAllocated;
+ struct vmbus_channel_message_header header;
+ struct vmbus_channel_offer offer;
+ u32 child_relid;
+ u8 monitorid;
+ bool monitor_allocated;
} __attribute__((packed));
/* Rescind Offer parameters */
struct vmbus_channel_rescind_offer {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
} __attribute__((packed));
/*
@@ -100,43 +100,43 @@ struct vmbus_channel_rescind_offer {
/* Open Channel parameters */
struct vmbus_channel_open_channel {
- struct vmbus_channel_message_header Header;
+ struct vmbus_channel_message_header header;
/* Identifies the specific VMBus channel that is being opened. */
- u32 ChildRelId;
+ u32 child_relid;
/* ID making a particular open request at a channel offer unique. */
- u32 OpenId;
+ u32 openid;
/* GPADL for the channel's ring buffer. */
- u32 RingBufferGpadlHandle;
+ u32 ringbuffer_gpadlhandle;
/* GPADL for the channel's server context save area. */
- u32 ServerContextAreaGpadlHandle;
+ u32 server_contextarea_gpadlhandle;
/*
* The upstream ring buffer begins at offset zero in the memory
* described by RingBufferGpadlHandle. The downstream ring buffer
* follows it at this offset (in pages).
*/
- u32 DownstreamRingBufferPageOffset;
+ u32 downstream_ringbuffer_pageoffset;
/* User-specific data to be passed along to the server endpoint. */
- unsigned char UserData[MAX_USER_DEFINED_BYTES];
+ unsigned char userdata[MAX_USER_DEFINED_BYTES];
} __attribute__((packed));
/* Open Channel Result parameters */
struct vmbus_channel_open_result {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 OpenId;
- u32 Status;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 openid;
+ u32 status;
} __attribute__((packed));
/* Close channel parameters; */
struct vmbus_channel_close_channel {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
} __attribute__((packed));
/* Channel Message GPADL */
@@ -151,72 +151,72 @@ struct vmbus_channel_close_channel {
* follow-up packet that contains more.
*/
struct vmbus_channel_gpadl_header {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
- u16 RangeBufLen;
- u16 RangeCount;
- struct gpa_range Range[0];
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u16 range_buflen;
+ u16 rangecount;
+ struct gpa_range range[0];
} __attribute__((packed));
/* This is the followup packet that contains more PFNs. */
struct vmbus_channel_gpadl_body {
- struct vmbus_channel_message_header Header;
- u32 MessageNumber;
- u32 Gpadl;
- u64 Pfn[0];
+ struct vmbus_channel_message_header header;
+ u32 msgnumber;
+ u32 gpadl;
+ u64 pfn[0];
} __attribute__((packed));
struct vmbus_channel_gpadl_created {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
- u32 CreationStatus;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u32 creation_status;
} __attribute__((packed));
struct vmbus_channel_gpadl_teardown {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
} __attribute__((packed));
struct vmbus_channel_gpadl_torndown {
- struct vmbus_channel_message_header Header;
- u32 Gpadl;
+ struct vmbus_channel_message_header header;
+ u32 gpadl;
} __attribute__((packed));
#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
struct vmbus_channel_view_range_add {
- struct vmbus_channel_message_header Header;
- PHYSICAL_ADDRESS ViewRangeBase;
- u64 ViewRangeLength;
- u32 ChildRelId;
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u64 viewrange_length;
+ u32 child_relid;
} __attribute__((packed));
struct vmbus_channel_view_range_remove {
- struct vmbus_channel_message_header Header;
- PHYSICAL_ADDRESS ViewRangeBase;
- u32 ChildRelId;
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u32 child_relid;
} __attribute__((packed));
#endif
struct vmbus_channel_relid_released {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
} __attribute__((packed));
struct vmbus_channel_initiate_contact {
- struct vmbus_channel_message_header Header;
- u32 VMBusVersionRequested;
- u32 Padding2;
- u64 InterruptPage;
- u64 MonitorPage1;
- u64 MonitorPage2;
+ struct vmbus_channel_message_header header;
+ u32 vmbus_version_requested;
+ u32 padding2;
+ u64 interrupt_page;
+ u64 monitor_page1;
+ u64 monitor_page2;
} __attribute__((packed));
struct vmbus_channel_version_response {
- struct vmbus_channel_message_header Header;
- bool VersionSupported;
+ struct vmbus_channel_message_header header;
+ bool version_supported;
} __attribute__((packed));
enum vmbus_channel_state {
@@ -226,54 +226,55 @@ enum vmbus_channel_state {
};
struct vmbus_channel {
- struct list_head ListEntry;
+ struct list_head listentry;
- struct hv_device *DeviceObject;
+ struct hv_device *device_obj;
struct timer_list poll_timer; /* SA-111 workaround */
+ struct work_struct work;
- enum vmbus_channel_state State;
+ enum vmbus_channel_state state;
- struct vmbus_channel_offer_channel OfferMsg;
+ struct vmbus_channel_offer_channel offermsg;
/*
* These are based on the OfferMsg.MonitorId.
* Save it here for easy access.
*/
- u8 MonitorGroup;
- u8 MonitorBit;
+ u8 monitor_grp;
+ u8 monitor_bit;
- u32 RingBufferGpadlHandle;
+ u32 ringbuffer_gpadlhandle;
/* Allocated memory for ring buffer */
- void *RingBufferPages;
- u32 RingBufferPageCount;
- struct hv_ring_buffer_info Outbound; /* send to parent */
- struct hv_ring_buffer_info Inbound; /* receive from parent */
+ void *ringbuffer_pages;
+ u32 ringbuffer_pagecount;
+ struct hv_ring_buffer_info outbound; /* send to parent */
+ struct hv_ring_buffer_info inbound; /* receive from parent */
spinlock_t inbound_lock;
- struct workqueue_struct *ControlWQ;
+ struct workqueue_struct *controlwq;
/* Channel callback are invoked in this workqueue context */
/* HANDLE dataWorkQueue; */
- void (*OnChannelCallback)(void *context);
- void *ChannelCallbackContext;
+ void (*onchannel_callback)(void *context);
+ void *channel_callback_context;
};
struct vmbus_channel_debug_info {
- u32 RelId;
- enum vmbus_channel_state State;
- struct hv_guid InterfaceType;
- struct hv_guid InterfaceInstance;
- u32 MonitorId;
- u32 ServerMonitorPending;
- u32 ServerMonitorLatency;
- u32 ServerMonitorConnectionId;
- u32 ClientMonitorPending;
- u32 ClientMonitorLatency;
- u32 ClientMonitorConnectionId;
-
- struct hv_ring_buffer_debug_info Inbound;
- struct hv_ring_buffer_debug_info Outbound;
+ u32 relid;
+ enum vmbus_channel_state state;
+ struct hv_guid interfacetype;
+ struct hv_guid interface_instance;
+ u32 monitorid;
+ u32 servermonitor_pending;
+ u32 servermonitor_latency;
+ u32 servermonitor_connectionid;
+ u32 clientmonitor_pending;
+ u32 clientmonitor_latency;
+ u32 clientmonitor_connectionid;
+
+ struct hv_ring_buffer_debug_info inbound;
+ struct hv_ring_buffer_debug_info outbound;
};
/*
@@ -282,28 +283,28 @@ struct vmbus_channel_debug_info {
*/
struct vmbus_channel_msginfo {
/* Bookkeeping stuff */
- struct list_head MsgListEntry;
+ struct list_head msglistentry;
/* So far, this is only used to handle gpadl body message */
- struct list_head SubMsgList;
+ struct list_head submsglist;
/* Synchronize the request/response if needed */
- struct osd_waitevent *WaitEvent;
+ struct osd_waitevent *waitevent;
union {
- struct vmbus_channel_version_supported VersionSupported;
- struct vmbus_channel_open_result OpenResult;
- struct vmbus_channel_gpadl_torndown GpadlTorndown;
- struct vmbus_channel_gpadl_created GpadlCreated;
- struct vmbus_channel_version_response VersionResponse;
- } Response;
-
- u32 MessageSize;
+ struct vmbus_channel_version_supported version_supported;
+ struct vmbus_channel_open_result open_result;
+ struct vmbus_channel_gpadl_torndown gpadl_torndown;
+ struct vmbus_channel_gpadl_created gpadl_created;
+ struct vmbus_channel_version_response version_response;
+ } response;
+
+ u32 msgsize;
/*
* The channel message that goes out on the "wire".
* It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
*/
- unsigned char Msg[0];
+ unsigned char msg[0];
};
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index f8477072ace4..c2e298ff4834 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -66,7 +66,7 @@ int VmbusConnect(void)
* Setup the vmbus event connection for channel interrupt
* abstraction stuff
*/
- gVmbusConnection.InterruptPage = osd_PageAlloc(1);
+ gVmbusConnection.InterruptPage = osd_page_alloc(1);
if (gVmbusConnection.InterruptPage == NULL) {
ret = -1;
goto Cleanup;
@@ -81,7 +81,7 @@ int VmbusConnect(void)
* Setup the monitor notification facility. The 1st page for
* parent->child and the 2nd page for child->parent
*/
- gVmbusConnection.MonitorPages = osd_PageAlloc(2);
+ gVmbusConnection.MonitorPages = osd_page_alloc(2);
if (gVmbusConnection.MonitorPages == NULL) {
ret = -1;
goto Cleanup;
@@ -95,19 +95,19 @@ int VmbusConnect(void)
goto Cleanup;
}
- msgInfo->WaitEvent = osd_WaitEventCreate();
- if (!msgInfo->WaitEvent) {
+ msgInfo->waitevent = osd_waitevent_create();
+ if (!msgInfo->waitevent) {
ret = -ENOMEM;
goto Cleanup;
}
- msg = (struct vmbus_channel_initiate_contact *)msgInfo->Msg;
+ msg = (struct vmbus_channel_initiate_contact *)msgInfo->msg;
- msg->Header.MessageType = ChannelMessageInitiateContact;
- msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
- msg->InterruptPage = virt_to_phys(gVmbusConnection.InterruptPage);
- msg->MonitorPage1 = virt_to_phys(gVmbusConnection.MonitorPages);
- msg->MonitorPage2 = virt_to_phys(
+ msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
+ msg->vmbus_version_requested = VMBUS_REVISION_NUMBER;
+ msg->interrupt_page = virt_to_phys(gVmbusConnection.InterruptPage);
+ msg->monitor_page1 = virt_to_phys(gVmbusConnection.MonitorPages);
+ msg->monitor_page2 = virt_to_phys(
(void *)((unsigned long)gVmbusConnection.MonitorPages +
PAGE_SIZE));
@@ -116,30 +116,30 @@ int VmbusConnect(void)
* receive the response before returning from this routine
*/
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&msgInfo->MsgListEntry,
+ list_add_tail(&msgInfo->msglistentry,
&gVmbusConnection.ChannelMsgList);
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, "
"monitor1 pfn %llx,, monitor2 pfn %llx",
- msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
+ msg->interrupt_page, msg->monitor_page1, msg->monitor_page2);
DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
ret = VmbusPostMessage(msg,
sizeof(struct vmbus_channel_initiate_contact));
if (ret != 0) {
- list_del(&msgInfo->MsgListEntry);
+ list_del(&msgInfo->msglistentry);
goto Cleanup;
}
/* Wait for the connection response */
- osd_WaitEventWait(msgInfo->WaitEvent);
+ osd_waitevent_wait(msgInfo->waitevent);
- list_del(&msgInfo->MsgListEntry);
+ list_del(&msgInfo->msglistentry);
/* Check if successful */
- if (msgInfo->Response.VersionResponse.VersionSupported) {
+ if (msgInfo->response.version_response.version_supported) {
DPRINT_INFO(VMBUS, "Vmbus connected!!");
gVmbusConnection.ConnectState = Connected;
@@ -151,7 +151,7 @@ int VmbusConnect(void)
goto Cleanup;
}
- kfree(msgInfo->WaitEvent);
+ kfree(msgInfo->waitevent);
kfree(msgInfo);
return 0;
@@ -162,17 +162,17 @@ Cleanup:
destroy_workqueue(gVmbusConnection.WorkQueue);
if (gVmbusConnection.InterruptPage) {
- osd_PageFree(gVmbusConnection.InterruptPage, 1);
+ osd_page_free(gVmbusConnection.InterruptPage, 1);
gVmbusConnection.InterruptPage = NULL;
}
if (gVmbusConnection.MonitorPages) {
- osd_PageFree(gVmbusConnection.MonitorPages, 2);
+ osd_page_free(gVmbusConnection.MonitorPages, 2);
gVmbusConnection.MonitorPages = NULL;
}
if (msgInfo) {
- kfree(msgInfo->WaitEvent);
+ kfree(msgInfo->waitevent);
kfree(msgInfo);
}
@@ -195,14 +195,14 @@ int VmbusDisconnect(void)
if (!msg)
return -ENOMEM;
- msg->MessageType = ChannelMessageUnload;
+ msg->msgtype = CHANNELMSG_UNLOAD;
ret = VmbusPostMessage(msg,
sizeof(struct vmbus_channel_message_header));
if (ret != 0)
goto Cleanup;
- osd_PageFree(gVmbusConnection.InterruptPage, 1);
+ osd_page_free(gVmbusConnection.InterruptPage, 1);
/* TODO: iterate thru the msg list and free up */
destroy_workqueue(gVmbusConnection.WorkQueue);
@@ -226,8 +226,8 @@ struct vmbus_channel *GetChannelFromRelId(u32 relId)
unsigned long flags;
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
- if (channel->OfferMsg.ChildRelId == relId) {
+ list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) {
+ if (channel->offermsg.child_relid == relId) {
foundChannel = channel;
break;
}
@@ -309,9 +309,9 @@ int VmbusPostMessage(void *buffer, size_t bufferLen)
{
union hv_connection_id connId;
- connId.Asu32 = 0;
- connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
- return HvPostMessage(connId, 1, buffer, bufferLen);
+ connId.asu32 = 0;
+ connId.u.id = VMBUS_MESSAGE_CONNECTION_ID;
+ return hv_post_message(connId, 1, buffer, bufferLen);
}
/*
@@ -324,5 +324,5 @@ int VmbusSetEvent(u32 childRelId)
(unsigned long *)gVmbusConnection.SendInterruptPage +
(childRelId >> 5));
- return HvSignalEvent();
+ return hv_signal_event();
}
diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c
index 86b1ddd90404..a34d713d9c57 100644
--- a/drivers/staging/hv/hv.c
+++ b/drivers/staging/hv/hv.c
@@ -28,17 +28,18 @@
#include "vmbus_private.h"
/* The one and only */
-struct hv_context gHvContext = {
- .SynICInitialized = false,
- .HypercallPage = NULL,
- .SignalEventParam = NULL,
- .SignalEventBuffer = NULL,
+struct hv_context hv_context = {
+ .synic_initialized = false,
+ .hypercall_page = NULL,
+ .signal_event_param = NULL,
+ .signal_event_buffer = NULL,
};
/*
- * HvQueryHypervisorPresence - Query the cpuid for presense of windows hypervisor
+ * query_hypervisor_presence
+ * - Query the cpuid for presense of windows hypervisor
*/
-static int HvQueryHypervisorPresence(void)
+static int query_hypervisor_presence(void)
{
unsigned int eax;
unsigned int ebx;
@@ -50,22 +51,22 @@ static int HvQueryHypervisorPresence(void)
ebx = 0;
ecx = 0;
edx = 0;
- op = HvCpuIdFunctionVersionAndFeatures;
+ op = HVCPUID_VERSION_FEATURES;
cpuid(op, &eax, &ebx, &ecx, &edx);
return ecx & HV_PRESENT_BIT;
}
/*
- * HvQueryHypervisorInfo - Get version info of the windows hypervisor
+ * query_hypervisor_info - Get version info of the windows hypervisor
*/
-static int HvQueryHypervisorInfo(void)
+static int query_hypervisor_info(void)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
- unsigned int maxLeaf;
+ unsigned int max_leaf;
unsigned int op;
/*
@@ -76,7 +77,7 @@ static int HvQueryHypervisorInfo(void)
ebx = 0;
ecx = 0;
edx = 0;
- op = HvCpuIdFunctionHvVendorAndMaxFunction;
+ op = HVCPUID_VENDOR_MAXFUNCTION;
cpuid(op, &eax, &ebx, &ecx, &edx);
DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
@@ -93,12 +94,12 @@ static int HvQueryHypervisorInfo(void)
((edx >> 16) & 0xFF),
((edx >> 24) & 0xFF));
- maxLeaf = eax;
+ max_leaf = eax;
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
- op = HvCpuIdFunctionHvInterface;
+ op = HVCPUID_INTERFACE;
cpuid(op, &eax, &ebx, &ecx, &edx);
DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
@@ -107,12 +108,12 @@ static int HvQueryHypervisorInfo(void)
((eax >> 16) & 0xFF),
((eax >> 24) & 0xFF));
- if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
+ if (max_leaf >= HVCPUID_VERSION) {
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
- op = HvCpuIdFunctionMsHvVersion;
+ op = HVCPUID_VERSION;
cpuid(op, &eax, &ebx, &ecx, &edx);
DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",\
eax,
@@ -122,80 +123,81 @@ static int HvQueryHypervisorInfo(void)
edx >> 24,
edx & 0xFFFFFF);
}
- return maxLeaf;
+ return max_leaf;
}
/*
- * HvDoHypercall - Invoke the specified hypercall
+ * do_hypercall- Invoke the specified hypercall
*/
-static u64 HvDoHypercall(u64 Control, void *Input, void *Output)
+static u64 do_hypercall(u64 control, void *input, void *output)
{
#ifdef CONFIG_X86_64
- u64 hvStatus = 0;
- u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
- u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
- volatile void *hypercallPage = gHvContext.HypercallPage;
+ u64 hv_status = 0;
+ u64 input_address = (input) ? virt_to_phys(input) : 0;
+ u64 output_address = (output) ? virt_to_phys(output) : 0;
+ volatile void *hypercall_page = hv_context.hypercall_page;
DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p "
"output phys %llx virt %p hypercall %p>",
- Control, inputAddress, Input,
- outputAddress, Output, hypercallPage);
+ control, input_address, input,
+ output_address, output, hypercall_page);
- __asm__ __volatile__("mov %0, %%r8" : : "r" (outputAddress) : "r8");
- __asm__ __volatile__("call *%3" : "=a" (hvStatus) :
- "c" (Control), "d" (inputAddress),
- "m" (hypercallPage));
+ __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
+ __asm__ __volatile__("call *%3" : "=a" (hv_status) :
+ "c" (control), "d" (input_address),
+ "m" (hypercall_page));
- DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
+ DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hv_status);
- return hvStatus;
+ return hv_status;
#else
- u32 controlHi = Control >> 32;
- u32 controlLo = Control & 0xFFFFFFFF;
- u32 hvStatusHi = 1;
- u32 hvStatusLo = 1;
- u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
- u32 inputAddressHi = inputAddress >> 32;
- u32 inputAddressLo = inputAddress & 0xFFFFFFFF;
- u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
- u32 outputAddressHi = outputAddress >> 32;
- u32 outputAddressLo = outputAddress & 0xFFFFFFFF;
- volatile void *hypercallPage = gHvContext.HypercallPage;
+ u32 control_hi = control >> 32;
+ u32 control_lo = control & 0xFFFFFFFF;
+ u32 hv_status_hi = 1;
+ u32 hv_status_lo = 1;
+ u64 input_address = (input) ? virt_to_phys(input) : 0;
+ u32 input_address_hi = input_address >> 32;
+ u32 input_address_lo = input_address & 0xFFFFFFFF;
+ u64 output_address = (output) ? virt_to_phys(output) : 0;
+ u32 output_address_hi = output_address >> 32;
+ u32 output_address_lo = output_address & 0xFFFFFFFF;
+ volatile void *hypercall_page = hv_context.hypercall_page;
DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
- Control, Input, Output);
+ control, input, output);
- __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi),
- "=a"(hvStatusLo) : "d" (controlHi),
- "a" (controlLo), "b" (inputAddressHi),
- "c" (inputAddressLo), "D"(outputAddressHi),
- "S"(outputAddressLo), "m" (hypercallPage));
+ __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
+ "=a"(hv_status_lo) : "d" (control_hi),
+ "a" (control_lo), "b" (input_address_hi),
+ "c" (input_address_lo), "D"(output_address_hi),
+ "S"(output_address_lo), "m" (hypercall_page));
DPRINT_DBG(VMBUS, "Hypercall <return %llx>",
- hvStatusLo | ((u64)hvStatusHi << 32));
+ hv_status_lo | ((u64)hv_status_hi << 32));
- return hvStatusLo | ((u64)hvStatusHi << 32);
+ return hv_status_lo | ((u64)hv_status_hi << 32);
#endif /* !x86_64 */
}
/*
- * HvInit - Main initialization routine.
+ * hv_init - Main initialization routine.
*
* This routine must be called before any other routines in here are called
*/
-int HvInit(void)
+int hv_init(void)
{
int ret = 0;
- int maxLeaf;
- union hv_x64_msr_hypercall_contents hypercallMsr;
- void *virtAddr = NULL;
+ int max_leaf;
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+ void *virtaddr = NULL;
- memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
- memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
+ memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+ memset(hv_context.synic_message_page, 0,
+ sizeof(void *) * MAX_NUM_CPUS);
- if (!HvQueryHypervisorPresence()) {
+ if (!query_hypervisor_presence()) {
DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
goto Cleanup;
}
@@ -203,146 +205,148 @@ int HvInit(void)
DPRINT_INFO(VMBUS,
"Windows hypervisor detected! Retrieving more info...");
- maxLeaf = HvQueryHypervisorInfo();
+ max_leaf = query_hypervisor_info();
/* HvQueryHypervisorFeatures(maxLeaf); */
/*
* We only support running on top of Hyper-V
*/
- rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
+ rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
- if (gHvContext.GuestId != 0) {
+ if (hv_context.guestid != 0) {
DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
- gHvContext.GuestId);
+ hv_context.guestid);
goto Cleanup;
}
/* Write our OS info */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
- gHvContext.GuestId = HV_LINUX_GUEST_ID;
+ hv_context.guestid = HV_LINUX_GUEST_ID;
/* See if the hypercall page is already set */
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
/*
* Allocate the hypercall page memory
- * virtAddr = osd_PageAlloc(1);
+ * virtaddr = osd_page_alloc(1);
*/
- virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
+ virtaddr = osd_virtual_alloc_exec(PAGE_SIZE);
- if (!virtAddr) {
+ if (!virtaddr) {
DPRINT_ERR(VMBUS,
"unable to allocate hypercall page!!");
goto Cleanup;
}
- hypercallMsr.Enable = 1;
+ hypercall_msr.enable = 1;
- hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
/* Confirm that hypercall page did get setup. */
- hypercallMsr.AsUINT64 = 0;
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ hypercall_msr.as_uint64 = 0;
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
- if (!hypercallMsr.Enable) {
+ if (!hypercall_msr.enable) {
DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
goto Cleanup;
}
- gHvContext.HypercallPage = virtAddr;
+ hv_context.hypercall_page = virtaddr;
DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
- gHvContext.HypercallPage,
- (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
+ hv_context.hypercall_page,
+ (u64)hypercall_msr.guest_physical_address << PAGE_SHIFT);
/* Setup the global signal event param for the signal event hypercall */
- gHvContext.SignalEventBuffer =
+ hv_context.signal_event_buffer =
kmalloc(sizeof(struct hv_input_signal_event_buffer),
GFP_KERNEL);
- if (!gHvContext.SignalEventBuffer)
+ if (!hv_context.signal_event_buffer)
goto Cleanup;
- gHvContext.SignalEventParam =
+ hv_context.signal_event_param =
(struct hv_input_signal_event *)
- (ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer,
+ (ALIGN_UP((unsigned long)
+ hv_context.signal_event_buffer,
HV_HYPERCALL_PARAM_ALIGN));
- gHvContext.SignalEventParam->ConnectionId.Asu32 = 0;
- gHvContext.SignalEventParam->ConnectionId.u.Id =
+ hv_context.signal_event_param->connectionid.asu32 = 0;
+ hv_context.signal_event_param->connectionid.u.id =
VMBUS_EVENT_CONNECTION_ID;
- gHvContext.SignalEventParam->FlagNumber = 0;
- gHvContext.SignalEventParam->RsvdZ = 0;
+ hv_context.signal_event_param->flag_number = 0;
+ hv_context.signal_event_param->rsvdz = 0;
return ret;
Cleanup:
- if (virtAddr) {
- if (hypercallMsr.Enable) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ if (virtaddr) {
+ if (hypercall_msr.enable) {
+ hypercall_msr.as_uint64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
}
- vfree(virtAddr);
+ vfree(virtaddr);
}
ret = -1;
return ret;
}
/*
- * HvCleanup - Cleanup routine.
+ * hv_cleanup - Cleanup routine.
*
* This routine is called normally during driver unloading or exiting.
*/
-void HvCleanup(void)
+void hv_cleanup(void)
{
- union hv_x64_msr_hypercall_contents hypercallMsr;
+ union hv_x64_msr_hypercall_contents hypercall_msr;
- kfree(gHvContext.SignalEventBuffer);
- gHvContext.SignalEventBuffer = NULL;
- gHvContext.SignalEventParam = NULL;
+ kfree(hv_context.signal_event_buffer);
+ hv_context.signal_event_buffer = NULL;
+ hv_context.signal_event_param = NULL;
- if (gHvContext.HypercallPage) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- vfree(gHvContext.HypercallPage);
- gHvContext.HypercallPage = NULL;
+ if (hv_context.hypercall_page) {
+ hypercall_msr.as_uint64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ vfree(hv_context.hypercall_page);
+ hv_context.hypercall_page = NULL;
}
}
/*
- * HvPostMessage - Post a message using the hypervisor message IPC.
+ * hv_post_message - Post a message using the hypervisor message IPC.
*
* This involves a hypercall.
*/
-u16 HvPostMessage(union hv_connection_id connectionId,
- enum hv_message_type messageType,
- void *payload, size_t payloadSize)
+u16 hv_post_message(union hv_connection_id connection_id,
+ enum hv_message_type message_type,
+ void *payload, size_t payload_size)
{
- struct alignedInput {
+ struct aligned_input {
u64 alignment8;
struct hv_input_post_message msg;
};
- struct hv_input_post_message *alignedMsg;
+ struct hv_input_post_message *aligned_msg;
u16 status;
unsigned long addr;
- if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
+ if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -1;
- addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC);
+ addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
if (!addr)
return -1;
- alignedMsg = (struct hv_input_post_message *)
+ aligned_msg = (struct hv_input_post_message *)
(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
- alignedMsg->ConnectionId = connectionId;
- alignedMsg->MessageType = messageType;
- alignedMsg->PayloadSize = payloadSize;
- memcpy((void *)alignedMsg->Payload, payload, payloadSize);
+ aligned_msg->connectionid = connection_id;
+ aligned_msg->message_type = message_type;
+ aligned_msg->payload_size = payload_size;
+ memcpy((void *)aligned_msg->payload, payload, payload_size);
- status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF;
+ status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
+ & 0xFFFF;
kfree((void *)addr);
@@ -351,38 +355,40 @@ u16 HvPostMessage(union hv_connection_id connectionId,
/*
- * HvSignalEvent - Signal an event on the specified connection using the hypervisor event IPC.
+ * hv_signal_event -
+ * Signal an event on the specified connection using the hypervisor event IPC.
*
* This involves a hypercall.
*/
-u16 HvSignalEvent(void)
+u16 hv_signal_event(void)
{
u16 status;
- status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam,
+ status = do_hypercall(HVCALL_SIGNAL_EVENT,
+ hv_context.signal_event_param,
NULL) & 0xFFFF;
return status;
}
/*
- * HvSynicInit - Initialize the Synthethic Interrupt Controller.
+ * hv_synic_init - Initialize the Synthethic Interrupt Controller.
*
* If it is already initialized by another entity (ie x2v shim), we need to
* retrieve the initialized message and event pages. Otherwise, we create and
* initialize the message and event pages.
*/
-void HvSynicInit(void *irqarg)
+void hv_synic_init(void *irqarg)
{
u64 version;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
- union hv_synic_sint sharedSint;
+ union hv_synic_sint shared_sint;
union hv_synic_scontrol sctrl;
- u32 irqVector = *((u32 *)(irqarg));
+ u32 irq_vector = *((u32 *)(irqarg));
int cpu = smp_processor_id();
- if (!gHvContext.HypercallPage)
+ if (!hv_context.hypercall_page)
return;
/* Check the version */
@@ -390,110 +396,112 @@ void HvSynicInit(void *irqarg)
DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
- gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
+ hv_context.synic_message_page[cpu] =
+ (void *)get_zeroed_page(GFP_ATOMIC);
- if (gHvContext.synICMessagePage[cpu] == NULL) {
+ if (hv_context.synic_message_page[cpu] == NULL) {
DPRINT_ERR(VMBUS,
"unable to allocate SYNIC message page!!");
goto Cleanup;
}
- gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
+ hv_context.synic_event_page[cpu] =
+ (void *)get_zeroed_page(GFP_ATOMIC);
- if (gHvContext.synICEventPage[cpu] == NULL) {
+ if (hv_context.synic_event_page[cpu] == NULL) {
DPRINT_ERR(VMBUS,
"unable to allocate SYNIC event page!!");
goto Cleanup;
}
/* Setup the Synic's message page */
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 1;
- simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
+ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+ simp.simp_enabled = 1;
+ simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
>> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.as_uint64);
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
/* Setup the Synic's event page */
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 1;
- siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+ siefp.siefp_enabled = 1;
+ siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
>> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.as_uint64);
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
/* Setup the interception SINT. */
/* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
- /* interceptionSint.AsUINT64); */
+ /* interceptionSint.as_uint64); */
/* Setup the shared SINT. */
- rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
+ rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
- sharedSint.AsUINT64 = 0;
- sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
- sharedSint.Masked = false;
- sharedSint.AutoEoi = true;
+ shared_sint.as_uint64 = 0;
+ shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
+ shared_sint.masked = false;
+ shared_sint.auto_eoi = true;
DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx",
- sharedSint.AsUINT64);
+ shared_sint.as_uint64);
- wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
+ wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
/* Enable the global synic bit */
- rdmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
- sctrl.Enable = 1;
+ rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+ sctrl.enable = 1;
- wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
+ wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
- gHvContext.SynICInitialized = true;
+ hv_context.synic_initialized = true;
return;
Cleanup:
- if (gHvContext.synICEventPage[cpu])
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
+ if (hv_context.synic_event_page[cpu])
+ osd_page_free(hv_context.synic_event_page[cpu], 1);
- if (gHvContext.synICMessagePage[cpu])
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
+ if (hv_context.synic_message_page[cpu])
+ osd_page_free(hv_context.synic_message_page[cpu], 1);
return;
}
/*
- * HvSynicCleanup - Cleanup routine for HvSynicInit().
+ * hv_synic_cleanup - Cleanup routine for hv_synic_init().
*/
-void HvSynicCleanup(void *arg)
+void hv_synic_cleanup(void *arg)
{
- union hv_synic_sint sharedSint;
+ union hv_synic_sint shared_sint;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
int cpu = smp_processor_id();
- if (!gHvContext.SynICInitialized)
+ if (!hv_context.synic_initialized)
return;
- rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
+ rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
- sharedSint.Masked = 1;
+ shared_sint.masked = 1;
/* Need to correctly cleanup in the case of SMP!!! */
/* Disable the interrupt */
- wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
+ wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 0;
- simp.BaseSimpGpa = 0;
+ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+ simp.simp_enabled = 0;
+ simp.base_simp_gpa = 0;
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 0;
- siefp.BaseSiefpGpa = 0;
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+ siefp.siefp_enabled = 0;
+ siefp.base_siefp_gpa = 0;
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
+ osd_page_free(hv_context.synic_message_page[cpu], 1);
+ osd_page_free(hv_context.synic_event_page[cpu], 1);
}
diff --git a/drivers/staging/hv/hv.h b/drivers/staging/hv/hv.h
index 41f5ebb86e17..829aff81bb30 100644
--- a/drivers/staging/hv/hv.h
+++ b/drivers/staging/hv/hv.h
@@ -92,49 +92,49 @@ static const struct hv_guid VMBUS_SERVICE_ID = {
struct hv_input_signal_event_buffer {
- u64 Align8;
- struct hv_input_signal_event Event;
+ u64 align8;
+ struct hv_input_signal_event event;
};
struct hv_context {
/* We only support running on top of Hyper-V
* So at this point this really can only contain the Hyper-V ID
*/
- u64 GuestId;
+ u64 guestid;
- void *HypercallPage;
+ void *hypercall_page;
- bool SynICInitialized;
+ bool synic_initialized;
/*
* This is used as an input param to HvCallSignalEvent hypercall. The
* input param is immutable in our usage and must be dynamic mem (vs
* stack or global). */
- struct hv_input_signal_event_buffer *SignalEventBuffer;
+ struct hv_input_signal_event_buffer *signal_event_buffer;
/* 8-bytes aligned of the buffer above */
- struct hv_input_signal_event *SignalEventParam;
+ struct hv_input_signal_event *signal_event_param;
- void *synICMessagePage[MAX_NUM_CPUS];
- void *synICEventPage[MAX_NUM_CPUS];
+ void *synic_message_page[MAX_NUM_CPUS];
+ void *synic_event_page[MAX_NUM_CPUS];
};
-extern struct hv_context gHvContext;
+extern struct hv_context hv_context;
/* Hv Interface */
-extern int HvInit(void);
+extern int hv_init(void);
-extern void HvCleanup(void);
+extern void hv_cleanup(void);
-extern u16 HvPostMessage(union hv_connection_id connectionId,
- enum hv_message_type messageType,
- void *payload, size_t payloadSize);
+extern u16 hv_post_message(union hv_connection_id connection_id,
+ enum hv_message_type message_type,
+ void *payload, size_t payload_size);
-extern u16 HvSignalEvent(void);
+extern u16 hv_signal_event(void);
-extern void HvSynicInit(void *irqarg);
+extern void hv_synic_init(void *irqarg);
-extern void HvSynicCleanup(void *arg);
+extern void hv_synic_cleanup(void *arg);
#endif /* __HV_H__ */
diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h
index 9eb818ee07ba..70e863ad0464 100644
--- a/drivers/staging/hv/hv_api.h
+++ b/drivers/staging/hv/hv_api.h
@@ -510,21 +510,21 @@
/*
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
- * is set by CPUID(HvCpuIdFunctionVersionAndFeatures).
+ * is set by CPUID(HVCPUID_VERSION_FEATURES).
*/
enum hv_cpuid_function {
- HvCpuIdFunctionVersionAndFeatures = 0x00000001,
- HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000,
- HvCpuIdFunctionHvInterface = 0x40000001,
+ HVCPUID_VERSION_FEATURES = 0x00000001,
+ HVCPUID_VENDOR_MAXFUNCTION = 0x40000000,
+ HVCPUID_INTERFACE = 0x40000001,
/*
* The remaining functions depend on the value of
- * HvCpuIdFunctionInterface
+ * HVCPUID_INTERFACE
*/
- HvCpuIdFunctionMsHvVersion = 0x40000002,
- HvCpuIdFunctionMsHvFeatures = 0x40000003,
- HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004,
- HvCpuIdFunctionMsHvImplementationLimits = 0x40000005,
+ HVCPUID_VERSION = 0x40000002,
+ HVCPUID_FEATURES = 0x40000003,
+ HVCPUID_ENLIGHTENMENT_INFO = 0x40000004,
+ HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005,
};
/* Define the virtual APIC registers */
@@ -575,30 +575,30 @@ enum hv_cpuid_function {
/* Define hypervisor message types. */
enum hv_message_type {
- HvMessageTypeNone = 0x00000000,
+ HVMSG_NONE = 0x00000000,
/* Memory access messages. */
- HvMessageTypeUnmappedGpa = 0x80000000,
- HvMessageTypeGpaIntercept = 0x80000001,
+ HVMSG_UNMAPPED_GPA = 0x80000000,
+ HVMSG_GPA_INTERCEPT = 0x80000001,
/* Timer notification messages. */
- HvMessageTimerExpired = 0x80000010,
+ HVMSG_TIMER_EXPIRED = 0x80000010,
/* Error messages. */
- HvMessageTypeInvalidVpRegisterValue = 0x80000020,
- HvMessageTypeUnrecoverableException = 0x80000021,
- HvMessageTypeUnsupportedFeature = 0x80000022,
+ HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+ HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
+ HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
/* Trace buffer complete messages. */
- HvMessageTypeEventLogBufferComplete = 0x80000040,
+ HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
/* Platform-specific processor intercept messages. */
- HvMessageTypeX64IoPortIntercept = 0x80010000,
- HvMessageTypeX64MsrIntercept = 0x80010001,
- HvMessageTypeX64CpuidIntercept = 0x80010002,
- HvMessageTypeX64ExceptionIntercept = 0x80010003,
- HvMessageTypeX64ApicEoi = 0x80010004,
- HvMessageTypeX64LegacyFpError = 0x80010005
+ HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
+ HVMSG_X64_MSR_INTERCEPT = 0x80010001,
+ HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
+ HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
+ HVMSG_X64_APIC_EOI = 0x80010004,
+ HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
};
/* Define the number of synthetic interrupt sources. */
@@ -610,103 +610,103 @@ enum hv_message_type {
/* Define connection identifier type. */
union hv_connection_id {
- u32 Asu32;
+ u32 asu32;
struct {
- u32 Id:24;
- u32 Reserved:8;
+ u32 id:24;
+ u32 reserved:8;
} u;
};
/* Define port identifier type. */
union hv_port_id {
- u32 Asu32;
+ u32 asu32;
struct {
- u32 Id:24;
- u32 Reserved:8;
+ u32 id:24;
+ u32 reserved:8;
} u ;
};
/* Define port type. */
enum hv_port_type {
- HvPortTypeMessage = 1,
- HvPortTypeEvent = 2,
- HvPortTypeMonitor = 3
+ HVPORT_MSG = 1,
+ HVPORT_EVENT = 2,
+ HVPORT_MONITOR = 3
};
/* Define port information structure. */
struct hv_port_info {
- enum hv_port_type PortType;
- u32 Padding;
+ enum hv_port_type port_type;
+ u32 padding;
union {
struct {
- u32 TargetSint;
- u32 TargetVp;
- u64 RsvdZ;
- } MessagePortInfo;
+ u32 target_sint;
+ u32 target_vp;
+ u64 rsvdz;
+ } message_port_info;
struct {
- u32 TargetSint;
- u32 TargetVp;
- u16 BaseFlagNumber;
- u16 FlagCount;
- u32 RsvdZ;
- } EventPortInfo;
+ u32 target_sint;
+ u32 target_vp;
+ u16 base_flag_bumber;
+ u16 flag_count;
+ u32 rsvdz;
+ } event_port_info;
struct {
- u64 MonitorAddress;
- u64 RsvdZ;
- } MonitorPortInfo;
+ u64 monitor_address;
+ u64 rsvdz;
+ } monitor_port_info;
};
};
struct hv_connection_info {
- enum hv_port_type PortType;
- u32 Padding;
+ enum hv_port_type port_type;
+ u32 padding;
union {
struct {
- u64 RsvdZ;
- } MessageConnectionInfo;
+ u64 rsvdz;
+ } message_connection_info;
struct {
- u64 RsvdZ;
- } EventConnectionInfo;
+ u64 rsvdz;
+ } event_connection_info;
struct {
- u64 MonitorAddress;
- } MonitorConnectionInfo;
+ u64 monitor_address;
+ } monitor_connection_info;
};
};
/* Define synthetic interrupt controller message flags. */
union hv_message_flags {
- u8 Asu8;
+ u8 asu8;
struct {
- u8 MessagePending:1;
- u8 Reserved:7;
+ u8 msg_pending:1;
+ u8 reserved:7;
};
};
/* Define synthetic interrupt controller message header. */
struct hv_message_header {
- enum hv_message_type MessageType;
- u8 PayloadSize;
- union hv_message_flags MessageFlags;
- u8 Reserved[2];
+ enum hv_message_type message_type;
+ u8 payload_size;
+ union hv_message_flags message_flags;
+ u8 reserved[2];
union {
- u64 Sender;
- union hv_port_id Port;
+ u64 sender;
+ union hv_port_id port;
};
};
/* Define timer message payload structure. */
struct hv_timer_message_payload {
- u32 TimerIndex;
- u32 Reserved;
- u64 ExpirationTime; /* When the timer expired */
- u64 DeliveryTime; /* When the message was delivered */
+ u32 timer_index;
+ u32 reserved;
+ u64 expiration_time; /* When the timer expired */
+ u64 delivery_time; /* When the message was delivered */
};
/* Define synthetic interrupt controller message format. */
struct hv_message {
- struct hv_message_header Header;
+ struct hv_message_header header;
union {
- u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
} u ;
};
@@ -715,82 +715,82 @@ struct hv_message {
/* Define the synthetic interrupt message page layout. */
struct hv_message_page {
- struct hv_message SintMessage[HV_SYNIC_SINT_COUNT];
+ struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
};
/* Define the synthetic interrupt controller event flags format. */
union hv_synic_event_flags {
- u8 Flags8[HV_EVENT_FLAGS_BYTE_COUNT];
- u32 Flags32[HV_EVENT_FLAGS_DWORD_COUNT];
+ u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
+ u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
};
/* Define the synthetic interrupt flags page layout. */
struct hv_synic_event_flags_page {
- union hv_synic_event_flags SintEventFlags[HV_SYNIC_SINT_COUNT];
+ union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT];
};
/* Define SynIC control register. */
union hv_synic_scontrol {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 Enable:1;
- u64 Reserved:63;
+ u64 enable:1;
+ u64 reserved:63;
};
};
/* Define synthetic interrupt source. */
union hv_synic_sint {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 Vector:8;
- u64 Reserved1:8;
- u64 Masked:1;
- u64 AutoEoi:1;
- u64 Reserved2:46;
+ u64 vector:8;
+ u64 reserved1:8;
+ u64 masked:1;
+ u64 auto_eoi:1;
+ u64 reserved2:46;
};
};
/* Define the format of the SIMP register */
union hv_synic_simp {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 SimpEnabled:1;
- u64 Preserved:11;
- u64 BaseSimpGpa:52;
+ u64 simp_enabled:1;
+ u64 preserved:11;
+ u64 base_simp_gpa:52;
};
};
/* Define the format of the SIEFP register */
union hv_synic_siefp {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 SiefpEnabled:1;
- u64 Preserved:11;
- u64 BaseSiefpGpa:52;
+ u64 siefp_enabled:1;
+ u64 preserved:11;
+ u64 base_siefp_gpa:52;
};
};
/* Definitions for the monitored notification facility */
union hv_monitor_trigger_group {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u32 Pending;
- u32 Armed;
+ u32 pending;
+ u32 armed;
};
};
struct hv_monitor_parameter {
- union hv_connection_id ConnectionId;
- u16 FlagNumber;
- u16 RsvdZ;
+ union hv_connection_id connectionid;
+ u16 flagnumber;
+ u16 rsvdz;
};
union hv_monitor_trigger_state {
- u32 Asu32;
+ u32 asu32;
struct {
- u32 GroupEnable:4;
- u32 RsvdZ:28;
+ u32 group_enable:4;
+ u32 rsvdz:28;
};
};
@@ -814,42 +814,42 @@ union hv_monitor_trigger_state {
/* | 840 | Rsvd4[0] | */
/* ------------------------------------------------------ */
struct hv_monitor_page {
- union hv_monitor_trigger_state TriggerState;
- u32 RsvdZ1;
+ union hv_monitor_trigger_state trigger_state;
+ u32 rsvdz1;
- union hv_monitor_trigger_group TriggerGroup[4];
- u64 RsvdZ2[3];
+ union hv_monitor_trigger_group trigger_group[4];
+ u64 rsvdz2[3];
- s32 NextCheckTime[4][32];
+ s32 next_checktime[4][32];
- u16 Latency[4][32];
- u64 RsvdZ3[32];
+ u16 latency[4][32];
+ u64 rsvdz3[32];
- struct hv_monitor_parameter Parameter[4][32];
+ struct hv_monitor_parameter parameter[4][32];
- u8 RsvdZ4[1984];
+ u8 rsvdz4[1984];
};
/* Declare the various hypercall operations. */
enum hv_call_code {
- HvCallPostMessage = 0x005c,
- HvCallSignalEvent = 0x005d,
+ HVCALL_POST_MESSAGE = 0x005c,
+ HVCALL_SIGNAL_EVENT = 0x005d,
};
-/* Definition of the HvPostMessage hypercall input structure. */
+/* Definition of the hv_post_message hypercall input structure. */
struct hv_input_post_message {
- union hv_connection_id ConnectionId;
- u32 Reserved;
- enum hv_message_type MessageType;
- u32 PayloadSize;
- u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ union hv_connection_id connectionid;
+ u32 reserved;
+ enum hv_message_type message_type;
+ u32 payload_size;
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
};
-/* Definition of the HvSignalEvent hypercall input structure. */
+/* Definition of the hv_signal_event hypercall input structure. */
struct hv_input_signal_event {
- union hv_connection_id ConnectionId;
- u16 FlagNumber;
- u16 RsvdZ;
+ union hv_connection_id connectionid;
+ u16 flag_number;
+ u16 rsvdz;
};
/*
@@ -859,16 +859,16 @@ struct hv_input_signal_event {
/* Version info reported by guest OS's */
enum hv_guest_os_vendor {
- HvGuestOsVendorMicrosoft = 0x0001
+ HVGUESTOS_VENDOR_MICROSOFT = 0x0001
};
enum hv_guest_os_microsoft_ids {
- HvGuestOsMicrosoftUndefined = 0x00,
- HvGuestOsMicrosoftMSDOS = 0x01,
- HvGuestOsMicrosoftWindows3x = 0x02,
- HvGuestOsMicrosoftWindows9x = 0x03,
- HvGuestOsMicrosoftWindowsNT = 0x04,
- HvGuestOsMicrosoftWindowsCE = 0x05
+ HVGUESTOS_MICROSOFT_UNDEFINED = 0x00,
+ HVGUESTOS_MICROSOFT_MSDOS = 0x01,
+ HVGUESTOS_MICROSOFT_WINDOWS3X = 0x02,
+ HVGUESTOS_MICROSOFT_WINDOWS9X = 0x03,
+ HVGUESTOS_MICROSOFT_WINDOWSNT = 0x04,
+ HVGUESTOS_MICROSOFT_WINDOWSCE = 0x05
};
/*
@@ -877,14 +877,14 @@ enum hv_guest_os_microsoft_ids {
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
union hv_x64_msr_guest_os_id_contents {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 BuildNumber:16;
- u64 ServiceVersion:8; /* Service Pack, etc. */
- u64 MinorVersion:8;
- u64 MajorVersion:8;
- u64 OsId:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
- u64 VendorId:16; /* enum hv_guest_os_vendor */
+ u64 build_number:16;
+ u64 service_version:8; /* Service Pack, etc. */
+ u64 minor_version:8;
+ u64 major_version:8;
+ u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
+ u64 vendor_id:16; /* enum hv_guest_os_vendor */
};
};
@@ -894,11 +894,11 @@ union hv_x64_msr_guest_os_id_contents {
#define HV_X64_MSR_HYPERCALL 0x40000001
union hv_x64_msr_hypercall_contents {
- u64 AsUINT64;
+ u64 as_uint64;
struct {
- u64 Enable:1;
- u64 Reserved:11;
- u64 GuestPhysicalAddress:52;
+ u64 enable:1;
+ u64 reserved:11;
+ u64 guest_physical_address:52;
};
};
diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c
index 702a478d5542..0074581f20e8 100644
--- a/drivers/staging/hv/hv_utils.c
+++ b/drivers/staging/hv/hv_utils.c
@@ -38,12 +38,14 @@
#include "vmbus_api.h"
#include "utils.h"
+static u8 *shut_txf_buf;
+static u8 *time_txf_buf;
+static u8 *hbeat_txf_buf;
static void shutdown_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
u8 execute_shutdown = false;
@@ -52,24 +54,23 @@ static void shutdown_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, shut_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
recvlen, requestid);
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, negop, buf);
+ prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
} else {
- shutdown_msg = (struct shutdown_msg_data *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
+ shutdown_msg =
+ (struct shutdown_msg_data *)&shut_txf_buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
switch (shutdown_msg->flags) {
case 0:
@@ -93,13 +94,11 @@ static void shutdown_onchannelcallback(void *context)
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- vmbus_sendpacket(channel, buf,
+ vmbus_sendpacket(channel, shut_txf_buf,
recvlen, requestid,
VmbusPacketTypeDataInBand, 0);
}
- kfree(buf);
-
if (execute_shutdown == true)
orderly_poweroff(false);
}
@@ -150,28 +149,25 @@ static inline void adj_guesttime(u64 hosttime, u8 flags)
static void timesync_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, time_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
recvlen, requestid);
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, NULL, buf);
+ prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
} else {
- timedatap = (struct ictimesync_data *)&buf[
+ timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
adj_guesttime(timedatap->parenttime, timedatap->flags);
@@ -180,12 +176,10 @@ static void timesync_onchannelcallback(void *context)
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- vmbus_sendpacket(channel, buf,
+ vmbus_sendpacket(channel, time_txf_buf,
recvlen, requestid,
VmbusPacketTypeDataInBand, 0);
}
-
- kfree(buf);
}
/*
@@ -196,33 +190,28 @@ static void timesync_onchannelcallback(void *context)
static void heartbeat_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct heartbeat_msg_data *heartbeat_msg;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, hbeat_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
recvlen, requestid);
- icmsghdrp = (struct icmsg_hdr *)&buf[
- sizeof(struct vmbuspipe_hdr)];
-
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, NULL, buf);
+ prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
} else {
- heartbeat_msg = (struct heartbeat_msg_data *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
+ heartbeat_msg =
+ (struct heartbeat_msg_data *)&hbeat_txf_buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
heartbeat_msg->seq_num);
@@ -233,12 +222,10 @@ static void heartbeat_onchannelcallback(void *context)
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- vmbus_sendpacket(channel, buf,
+ vmbus_sendpacket(channel, hbeat_txf_buf,
recvlen, requestid,
VmbusPacketTypeDataInBand, 0);
}
-
- kfree(buf);
}
static const struct pci_device_id __initconst
@@ -271,15 +258,28 @@ static int __init init_hyperv_utils(void)
if (!dmi_check_system(hv_utils_dmi_table))
return -ENODEV;
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
+ shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+ if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
+ printk(KERN_INFO
+ "Unable to allocate memory for receive buffer\n");
+ kfree(shut_txf_buf);
+ kfree(time_txf_buf);
+ kfree(hbeat_txf_buf);
+ return -ENOMEM;
+ }
+
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
&shutdown_onchannelcallback;
hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
&timesync_onchannelcallback;
hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
&heartbeat_onchannelcallback;
hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
@@ -290,17 +290,21 @@ static void exit_hyperv_utils(void)
{
printk(KERN_INFO "De-Registered HyperV Utility Driver\n");
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
&chn_cb_negotiate;
hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
&chn_cb_negotiate;
hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
&chn_cb_negotiate;
hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
+
+ kfree(shut_txf_buf);
+ kfree(time_txf_buf);
+ kfree(hbeat_txf_buf);
}
module_init(init_hyperv_utils);
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 4c2632cb19e9..df9cd131e953 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -31,147 +31,149 @@
/* Globals */
-static const char *gDriverName = "netvsc";
+static const char *driver_name = "netvsc";
/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
-static const struct hv_guid gNetVscDeviceType = {
+static const struct hv_guid netvsc_device_type = {
.data = {
0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
}
};
-static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo);
+static int netvsc_device_add(struct hv_device *device, void *additional_info);
-static int NetVscOnDeviceRemove(struct hv_device *Device);
+static int netvsc_device_remove(struct hv_device *device);
-static void NetVscOnCleanup(struct hv_driver *Driver);
+static void netvsc_cleanup(struct hv_driver *driver);
-static void NetVscOnChannelCallback(void *context);
+static void netvsc_channel_cb(void *context);
-static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device);
+static int netvsc_init_send_buf(struct hv_device *device);
-static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device);
+static int netvsc_init_recv_buf(struct hv_device *device);
-static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice);
+static int netvsc_destroy_send_buf(struct netvsc_device *net_device);
-static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice);
+static int netvsc_destroy_recv_buf(struct netvsc_device *net_device);
-static int NetVscConnectToVsp(struct hv_device *Device);
+static int netvsc_connect_vsp(struct hv_device *device);
-static void NetVscOnSendCompletion(struct hv_device *Device,
- struct vmpacket_descriptor *Packet);
+static void netvsc_send_completion(struct hv_device *device,
+ struct vmpacket_descriptor *packet);
-static int NetVscOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet);
+static int netvsc_send(struct hv_device *device,
+ struct hv_netvsc_packet *packet);
-static void NetVscOnReceive(struct hv_device *Device,
- struct vmpacket_descriptor *Packet);
+static void netvsc_receive(struct hv_device *device,
+ struct vmpacket_descriptor *packet);
-static void NetVscOnReceiveCompletion(void *Context);
+static void netvsc_receive_completion(void *context);
-static void NetVscSendReceiveCompletion(struct hv_device *Device,
- u64 TransactionId);
+static void netvsc_send_recv_completion(struct hv_device *device,
+ u64 transaction_id);
-static struct netvsc_device *AllocNetDevice(struct hv_device *Device)
+static struct netvsc_device *alloc_net_device(struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
- if (!netDevice)
+ net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
+ if (!net_device)
return NULL;
/* Set to 2 to allow both inbound and outbound traffic */
- atomic_cmpxchg(&netDevice->RefCount, 0, 2);
+ atomic_cmpxchg(&net_device->refcnt, 0, 2);
- netDevice->Device = Device;
- Device->Extension = netDevice;
+ net_device->dev = device;
+ device->Extension = net_device;
- return netDevice;
+ return net_device;
}
-static void FreeNetDevice(struct netvsc_device *Device)
+static void free_net_device(struct netvsc_device *device)
{
- WARN_ON(atomic_read(&Device->RefCount) == 0);
- Device->Device->Extension = NULL;
- kfree(Device);
+ WARN_ON(atomic_read(&device->refcnt) == 0);
+ device->dev->Extension = NULL;
+ kfree(device);
}
/* Get the net device object iff exists and its refcount > 1 */
-static struct netvsc_device *GetOutboundNetDevice(struct hv_device *Device)
+static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = Device->Extension;
- if (netDevice && atomic_read(&netDevice->RefCount) > 1)
- atomic_inc(&netDevice->RefCount);
+ net_device = device->Extension;
+ if (net_device && atomic_read(&net_device->refcnt) > 1)
+ atomic_inc(&net_device->refcnt);
else
- netDevice = NULL;
+ net_device = NULL;
- return netDevice;
+ return net_device;
}
/* Get the net device object iff exists and its refcount > 0 */
-static struct netvsc_device *GetInboundNetDevice(struct hv_device *Device)
+static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = Device->Extension;
- if (netDevice && atomic_read(&netDevice->RefCount))
- atomic_inc(&netDevice->RefCount);
+ net_device = device->Extension;
+ if (net_device && atomic_read(&net_device->refcnt))
+ atomic_inc(&net_device->refcnt);
else
- netDevice = NULL;
+ net_device = NULL;
- return netDevice;
+ return net_device;
}
-static void PutNetDevice(struct hv_device *Device)
+static void put_net_device(struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = Device->Extension;
+ net_device = device->Extension;
/* ASSERT(netDevice); */
- atomic_dec(&netDevice->RefCount);
+ atomic_dec(&net_device->refcnt);
}
-static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *Device)
+static struct netvsc_device *release_outbound_net_device(
+ struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = Device->Extension;
- if (netDevice == NULL)
+ net_device = device->Extension;
+ if (net_device == NULL)
return NULL;
/* Busy wait until the ref drop to 2, then set it to 1 */
- while (atomic_cmpxchg(&netDevice->RefCount, 2, 1) != 2)
+ while (atomic_cmpxchg(&net_device->refcnt, 2, 1) != 2)
udelay(100);
- return netDevice;
+ return net_device;
}
-static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *Device)
+static struct netvsc_device *release_inbound_net_device(
+ struct hv_device *device)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
- netDevice = Device->Extension;
- if (netDevice == NULL)
+ net_device = device->Extension;
+ if (net_device == NULL)
return NULL;
/* Busy wait until the ref drop to 1, then set it to 0 */
- while (atomic_cmpxchg(&netDevice->RefCount, 1, 0) != 1)
+ while (atomic_cmpxchg(&net_device->refcnt, 1, 0) != 1)
udelay(100);
- Device->Extension = NULL;
- return netDevice;
+ device->Extension = NULL;
+ return net_device;
}
/*
- * NetVscInitialize - Main entry point
+ * netvsc_initialize - Main entry point
*/
-int NetVscInitialize(struct hv_driver *drv)
+int netvsc_initialize(struct hv_driver *drv)
{
struct netvsc_driver *driver = (struct netvsc_driver *)drv;
@@ -185,8 +187,8 @@ int NetVscInitialize(struct hv_driver *drv)
/* Make sure we are at least 2 pages since 1 page is used for control */
/* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */
- drv->name = gDriverName;
- memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid));
+ drv->name = driver_name;
+ memcpy(&drv->deviceType, &netvsc_device_type, sizeof(struct hv_guid));
/* Make sure it is set by the caller */
/* FIXME: These probably should still be tested in some way */
@@ -194,24 +196,24 @@ int NetVscInitialize(struct hv_driver *drv)
/* ASSERT(driver->OnLinkStatusChanged); */
/* Setup the dispatch table */
- driver->Base.OnDeviceAdd = NetVscOnDeviceAdd;
- driver->Base.OnDeviceRemove = NetVscOnDeviceRemove;
- driver->Base.OnCleanup = NetVscOnCleanup;
+ driver->base.OnDeviceAdd = netvsc_device_add;
+ driver->base.OnDeviceRemove = netvsc_device_remove;
+ driver->base.OnCleanup = netvsc_cleanup;
- driver->OnSend = NetVscOnSend;
+ driver->send = netvsc_send;
- RndisFilterInit(driver);
+ rndis_filter_init(driver);
return 0;
}
-static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
+static int netvsc_init_recv_buf(struct hv_device *device)
{
int ret = 0;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
+ struct netvsc_device *net_device;
+ struct nvsp_message *init_packet;
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_outbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return -1;
@@ -220,12 +222,12 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
/* page-size grandularity */
/* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */
- netDevice->ReceiveBuffer =
- osd_PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT);
- if (!netDevice->ReceiveBuffer) {
+ net_device->recv_buf =
+ osd_page_alloc(net_device->recv_buf_size >> PAGE_SHIFT);
+ if (!net_device->recv_buf) {
DPRINT_ERR(NETVSC,
"unable to allocate receive buffer of size %d",
- netDevice->ReceiveBufferSize);
+ net_device->recv_buf_size);
ret = -1;
goto Cleanup;
}
@@ -240,32 +242,34 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
* channel. Note: This call uses the vmbus connection rather
* than the channel to establish the gpadl handle.
*/
- ret = vmbus_establish_gpadl(Device->channel, netDevice->ReceiveBuffer,
- netDevice->ReceiveBufferSize,
- &netDevice->ReceiveBufferGpadlHandle);
+ ret = vmbus_establish_gpadl(device->channel, net_device->recv_buf,
+ net_device->recv_buf_size,
+ &net_device->recv_buf_gpadl_handle);
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to establish receive buffer's gpadl");
goto Cleanup;
}
- /* osd_WaitEventWait(ext->ChannelInitEvent); */
+ /* osd_waitevent_wait(ext->ChannelInitEvent); */
/* Notify the NetVsp of the gpadl handle */
DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer...");
- initPacket = &netDevice->ChannelInitPacket;
+ init_packet = &net_device->channel_init_pkt;
- memset(initPacket, 0, sizeof(struct nvsp_message));
+ memset(init_packet, 0, sizeof(struct nvsp_message));
- initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
+ init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF;
+ init_packet->msg.v1_msg.send_recv_buf.
+ gpadl_handle = net_device->recv_buf_gpadl_handle;
+ init_packet->msg.v1_msg.
+ send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
/* Send the gpadl notification request */
- ret = vmbus_sendpacket(Device->channel, initPacket,
+ ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
- (unsigned long)initPacket,
+ (unsigned long)init_packet,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
@@ -274,13 +278,15 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(netDevice->ChannelInitEvent);
+ osd_waitevent_wait(net_device->channel_init_event);
/* Check the response */
- if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) {
+ if (init_packet->msg.v1_msg.
+ send_recv_buf_complete.status != NVSP_STAT_SUCCESS) {
DPRINT_ERR(NETVSC, "Unable to complete receive buffer "
"initialzation with NetVsp - status %d",
- initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status);
+ init_packet->msg.v1_msg.
+ send_recv_buf_complete.status);
ret = -1;
goto Cleanup;
}
@@ -289,32 +295,36 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
/* ASSERT(netDevice->ReceiveSectionCount == 0); */
/* ASSERT(netDevice->ReceiveSections == NULL); */
- netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections;
+ net_device->recv_section_cnt = init_packet->msg.
+ v1_msg.send_recv_buf_complete.num_sections;
- netDevice->ReceiveSections = kmalloc(netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL);
- if (netDevice->ReceiveSections == NULL) {
+ net_device->recv_section = kmalloc(net_device->recv_section_cnt
+ * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL);
+ if (net_device->recv_section == NULL) {
ret = -1;
goto Cleanup;
}
- memcpy(netDevice->ReceiveSections,
- initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections,
- netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section));
+ memcpy(net_device->recv_section,
+ init_packet->msg.v1_msg.
+ send_recv_buf_complete.sections,
+ net_device->recv_section_cnt *
+ sizeof(struct nvsp_1_receive_buffer_section));
DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, "
"endoffset %d, suballoc size %d, num suballocs %d)",
- netDevice->ReceiveSectionCount,
- netDevice->ReceiveSections[0].Offset,
- netDevice->ReceiveSections[0].EndOffset,
- netDevice->ReceiveSections[0].SubAllocationSize,
- netDevice->ReceiveSections[0].NumSubAllocations);
+ net_device->recv_section_cnt,
+ net_device->recv_section[0].offset,
+ net_device->recv_section[0].end_offset,
+ net_device->recv_section[0].sub_alloc_size,
+ net_device->recv_section[0].num_sub_allocs);
/*
* For 1st release, there should only be 1 section that represents the
* entire receive buffer
*/
- if (netDevice->ReceiveSectionCount != 1 ||
- netDevice->ReceiveSections->Offset != 0) {
+ if (net_device->recv_section_cnt != 1 ||
+ net_device->recv_section->offset != 0) {
ret = -1;
goto Cleanup;
}
@@ -322,26 +332,26 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
goto Exit;
Cleanup:
- NetVscDestroyReceiveBuffer(netDevice);
+ netvsc_destroy_recv_buf(net_device);
Exit:
- PutNetDevice(Device);
+ put_net_device(device);
return ret;
}
-static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
+static int netvsc_init_send_buf(struct hv_device *device)
{
int ret = 0;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
+ struct netvsc_device *net_device;
+ struct nvsp_message *init_packet;
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_outbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return -1;
}
- if (netDevice->SendBufferSize <= 0) {
+ if (net_device->send_buf_size <= 0) {
ret = -EINVAL;
goto Cleanup;
}
@@ -349,11 +359,11 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
/* page-size grandularity */
/* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */
- netDevice->SendBuffer =
- osd_PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT);
- if (!netDevice->SendBuffer) {
+ net_device->send_buf =
+ osd_page_alloc(net_device->send_buf_size >> PAGE_SHIFT);
+ if (!net_device->send_buf) {
DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d",
- netDevice->SendBufferSize);
+ net_device->send_buf_size);
ret = -1;
goto Cleanup;
}
@@ -367,31 +377,33 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
* channel. Note: This call uses the vmbus connection rather
* than the channel to establish the gpadl handle.
*/
- ret = vmbus_establish_gpadl(Device->channel, netDevice->SendBuffer,
- netDevice->SendBufferSize,
- &netDevice->SendBufferGpadlHandle);
+ ret = vmbus_establish_gpadl(device->channel, net_device->send_buf,
+ net_device->send_buf_size,
+ &net_device->send_buf_gpadl_handle);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl");
goto Cleanup;
}
- /* osd_WaitEventWait(ext->ChannelInitEvent); */
+ /* osd_waitevent_wait(ext->ChannelInitEvent); */
/* Notify the NetVsp of the gpadl handle */
DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer...");
- initPacket = &netDevice->ChannelInitPacket;
+ init_packet = &net_device->channel_init_pkt;
- memset(initPacket, 0, sizeof(struct nvsp_message));
+ memset(init_packet, 0, sizeof(struct nvsp_message));
- initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID;
+ init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF;
+ init_packet->msg.v1_msg.send_recv_buf.
+ gpadl_handle = net_device->send_buf_gpadl_handle;
+ init_packet->msg.v1_msg.send_recv_buf.id =
+ NETVSC_SEND_BUFFER_ID;
/* Send the gpadl notification request */
- ret = vmbus_sendpacket(Device->channel, initPacket,
+ ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
- (unsigned long)initPacket,
+ (unsigned long)init_packet,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
@@ -400,32 +412,35 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(netDevice->ChannelInitEvent);
+ osd_waitevent_wait(net_device->channel_init_event);
/* Check the response */
- if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) {
+ if (init_packet->msg.v1_msg.
+ send_send_buf_complete.status != NVSP_STAT_SUCCESS) {
DPRINT_ERR(NETVSC, "Unable to complete send buffer "
"initialzation with NetVsp - status %d",
- initPacket->Messages.Version1Messages.SendSendBufferComplete.Status);
+ init_packet->msg.v1_msg.
+ send_send_buf_complete.status);
ret = -1;
goto Cleanup;
}
- netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize;
+ net_device->send_section_size = init_packet->
+ msg.v1_msg.send_send_buf_complete.section_size;
goto Exit;
Cleanup:
- NetVscDestroySendBuffer(netDevice);
+ netvsc_destroy_send_buf(net_device);
Exit:
- PutNetDevice(Device);
+ put_net_device(device);
return ret;
}
-static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
+static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
{
- struct nvsp_message *revokePacket;
+ struct nvsp_message *revoke_packet;
int ret = 0;
/*
@@ -434,20 +449,23 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
* NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
* to send a revoke msg here
*/
- if (NetDevice->ReceiveSectionCount) {
+ if (net_device->recv_section_cnt) {
DPRINT_INFO(NETVSC,
"Sending NvspMessage1TypeRevokeReceiveBuffer...");
/* Send the revoke receive buffer */
- revokePacket = &NetDevice->RevokePacket;
- memset(revokePacket, 0, sizeof(struct nvsp_message));
+ revoke_packet = &net_device->revoke_packet;
+ memset(revoke_packet, 0, sizeof(struct nvsp_message));
- revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer;
- revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
+ revoke_packet->hdr.msg_type =
+ NVSP_MSG1_TYPE_REVOKE_RECV_BUF;
+ revoke_packet->msg.v1_msg.
+ revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
- ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket,
+ ret = vmbus_sendpacket(net_device->dev->channel,
+ revoke_packet,
sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
+ (unsigned long)revoke_packet,
VmbusPacketTypeDataInBand, 0);
/*
* If we failed here, we might as well return and
@@ -461,11 +479,11 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
}
/* Teardown the gpadl on the vsp end */
- if (NetDevice->ReceiveBufferGpadlHandle) {
+ if (net_device->recv_buf_gpadl_handle) {
DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL...");
- ret = vmbus_teardown_gpadl(NetDevice->Device->channel,
- NetDevice->ReceiveBufferGpadlHandle);
+ ret = vmbus_teardown_gpadl(net_device->dev->channel,
+ net_device->recv_buf_gpadl_handle);
/* If we failed here, we might as well return and have a leak rather than continue and a bugchk */
if (ret != 0) {
@@ -473,30 +491,30 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
"unable to teardown receive buffer's gpadl");
return -1;
}
- NetDevice->ReceiveBufferGpadlHandle = 0;
+ net_device->recv_buf_gpadl_handle = 0;
}
- if (NetDevice->ReceiveBuffer) {
+ if (net_device->recv_buf) {
DPRINT_INFO(NETVSC, "Freeing up receive buffer...");
/* Free up the receive buffer */
- osd_PageFree(NetDevice->ReceiveBuffer,
- NetDevice->ReceiveBufferSize >> PAGE_SHIFT);
- NetDevice->ReceiveBuffer = NULL;
+ osd_page_free(net_device->recv_buf,
+ net_device->recv_buf_size >> PAGE_SHIFT);
+ net_device->recv_buf = NULL;
}
- if (NetDevice->ReceiveSections) {
- NetDevice->ReceiveSectionCount = 0;
- kfree(NetDevice->ReceiveSections);
- NetDevice->ReceiveSections = NULL;
+ if (net_device->recv_section) {
+ net_device->recv_section_cnt = 0;
+ kfree(net_device->recv_section);
+ net_device->recv_section = NULL;
}
return ret;
}
-static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
+static int netvsc_destroy_send_buf(struct netvsc_device *net_device)
{
- struct nvsp_message *revokePacket;
+ struct nvsp_message *revoke_packet;
int ret = 0;
/*
@@ -505,20 +523,23 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
* NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
* to send a revoke msg here
*/
- if (NetDevice->SendSectionSize) {
+ if (net_device->send_section_size) {
DPRINT_INFO(NETVSC,
"Sending NvspMessage1TypeRevokeSendBuffer...");
/* Send the revoke send buffer */
- revokePacket = &NetDevice->RevokePacket;
- memset(revokePacket, 0, sizeof(struct nvsp_message));
+ revoke_packet = &net_device->revoke_packet;
+ memset(revoke_packet, 0, sizeof(struct nvsp_message));
- revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer;
- revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID;
+ revoke_packet->hdr.msg_type =
+ NVSP_MSG1_TYPE_REVOKE_SEND_BUF;
+ revoke_packet->msg.v1_msg.
+ revoke_send_buf.id = NETVSC_SEND_BUFFER_ID;
- ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket,
+ ret = vmbus_sendpacket(net_device->dev->channel,
+ revoke_packet,
sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
+ (unsigned long)revoke_packet,
VmbusPacketTypeDataInBand, 0);
/*
* If we failed here, we might as well return and have a leak
@@ -532,10 +553,10 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
}
/* Teardown the gpadl on the vsp end */
- if (NetDevice->SendBufferGpadlHandle) {
+ if (net_device->send_buf_gpadl_handle) {
DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL...");
- ret = vmbus_teardown_gpadl(NetDevice->Device->channel,
- NetDevice->SendBufferGpadlHandle);
+ ret = vmbus_teardown_gpadl(net_device->dev->channel,
+ net_device->send_buf_gpadl_handle);
/*
* If we failed here, we might as well return and have a leak
@@ -546,49 +567,51 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
"gpadl");
return -1;
}
- NetDevice->SendBufferGpadlHandle = 0;
+ net_device->send_buf_gpadl_handle = 0;
}
- if (NetDevice->SendBuffer) {
+ if (net_device->send_buf) {
DPRINT_INFO(NETVSC, "Freeing up send buffer...");
/* Free up the receive buffer */
- osd_PageFree(NetDevice->SendBuffer,
- NetDevice->SendBufferSize >> PAGE_SHIFT);
- NetDevice->SendBuffer = NULL;
+ osd_page_free(net_device->send_buf,
+ net_device->send_buf_size >> PAGE_SHIFT);
+ net_device->send_buf = NULL;
}
return ret;
}
-static int NetVscConnectToVsp(struct hv_device *Device)
+static int netvsc_connect_vsp(struct hv_device *device)
{
int ret;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
- int ndisVersion;
+ struct netvsc_device *net_device;
+ struct nvsp_message *init_packet;
+ int ndis_version;
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_outbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return -1;
}
- initPacket = &netDevice->ChannelInitPacket;
+ init_packet = &net_device->channel_init_pkt;
- memset(initPacket, 0, sizeof(struct nvsp_message));
- initPacket->Header.MessageType = NvspMessageTypeInit;
- initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION;
- initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION;
+ memset(init_packet, 0, sizeof(struct nvsp_message));
+ init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
+ init_packet->msg.init_msg.init.min_protocol_ver =
+ NVSP_MIN_PROTOCOL_VERSION;
+ init_packet->msg.init_msg.init.max_protocol_ver =
+ NVSP_MAX_PROTOCOL_VERSION;
DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit...");
/* Send the init request */
- ret = vmbus_sendpacket(Device->channel, initPacket,
+ ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
- (unsigned long)initPacket,
+ (unsigned long)init_packet,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -597,47 +620,52 @@ static int NetVscConnectToVsp(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(netDevice->ChannelInitEvent);
+ osd_waitevent_wait(net_device->channel_init_event);
/* Now, check the response */
/* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */
DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)",
- initPacket->Messages.InitMessages.InitComplete.Status,
- initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength);
+ init_packet->msg.init_msg.init_complete.status,
+ init_packet->msg.init_msg.
+ init_complete.max_mdl_chain_len);
- if (initPacket->Messages.InitMessages.InitComplete.Status !=
- NvspStatusSuccess) {
+ if (init_packet->msg.init_msg.init_complete.status !=
+ NVSP_STAT_SUCCESS) {
DPRINT_ERR(NETVSC,
"unable to initialize with netvsp (status 0x%x)",
- initPacket->Messages.InitMessages.InitComplete.Status);
+ init_packet->msg.init_msg.init_complete.status);
ret = -1;
goto Cleanup;
}
- if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) {
+ if (init_packet->msg.init_msg.init_complete.
+ negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) {
DPRINT_ERR(NETVSC, "unable to initialize with netvsp "
"(version expected 1 got %d)",
- initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion);
+ init_packet->msg.init_msg.
+ init_complete.negotiated_protocol_ver);
ret = -1;
goto Cleanup;
}
DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion...");
/* Send the ndis version */
- memset(initPacket, 0, sizeof(struct nvsp_message));
+ memset(init_packet, 0, sizeof(struct nvsp_message));
- ndisVersion = 0x00050000;
+ ndis_version = 0x00050000;
- initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion;
- initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion =
- (ndisVersion & 0xFFFF0000) >> 16;
- initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion =
- ndisVersion & 0xFFFF;
+ init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
+ init_packet->msg.v1_msg.
+ send_ndis_ver.ndis_major_ver =
+ (ndis_version & 0xFFFF0000) >> 16;
+ init_packet->msg.v1_msg.
+ send_ndis_ver.ndis_minor_ver =
+ ndis_version & 0xFFFF;
/* Send the init request */
- ret = vmbus_sendpacket(Device->channel, initPacket,
+ ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
- (unsigned long)initPacket,
+ (unsigned long)init_packet,
VmbusPacketTypeDataInBand, 0);
if (ret != 0) {
DPRINT_ERR(NETVSC,
@@ -651,51 +679,52 @@ static int NetVscConnectToVsp(struct hv_device *Device)
* packet) since our Vmbus always set the
* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag
*/
- /* osd_WaitEventWait(NetVscChannel->ChannelInitEvent); */
+ /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */
/* Post the big receive buffer to NetVSP */
- ret = NetVscInitializeReceiveBufferWithNetVsp(Device);
+ ret = netvsc_init_recv_buf(device);
if (ret == 0)
- ret = NetVscInitializeSendBufferWithNetVsp(Device);
+ ret = netvsc_init_send_buf(device);
Cleanup:
- PutNetDevice(Device);
+ put_net_device(device);
return ret;
}
-static void NetVscDisconnectFromVsp(struct netvsc_device *NetDevice)
+static void NetVscDisconnectFromVsp(struct netvsc_device *net_device)
{
- NetVscDestroyReceiveBuffer(NetDevice);
- NetVscDestroySendBuffer(NetDevice);
+ netvsc_destroy_recv_buf(net_device);
+ netvsc_destroy_send_buf(net_device);
}
/*
- * NetVscOnDeviceAdd - Callback when the device belonging to this driver is added
+ * netvsc_device_add - Callback when the device belonging to this
+ * driver is added
*/
-static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
+static int netvsc_device_add(struct hv_device *device, void *additional_info)
{
int ret = 0;
int i;
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
struct hv_netvsc_packet *packet, *pos;
- struct netvsc_driver *netDriver =
- (struct netvsc_driver *)Device->Driver;
+ struct netvsc_driver *net_driver =
+ (struct netvsc_driver *)device->Driver;
- netDevice = AllocNetDevice(Device);
- if (!netDevice) {
+ net_device = alloc_net_device(device);
+ if (!net_device) {
ret = -1;
goto Cleanup;
}
- DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice);
+ DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", net_device);
/* Initialize the NetVSC channel extension */
- netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE;
- spin_lock_init(&netDevice->receive_packet_list_lock);
+ net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+ spin_lock_init(&net_device->recv_pkt_list_lock);
- netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE;
+ net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
- INIT_LIST_HEAD(&netDevice->ReceivePacketList);
+ INIT_LIST_HEAD(&net_device->recv_pkt_list);
for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
@@ -707,19 +736,19 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
NETVSC_RECEIVE_PACKETLIST_COUNT, i);
break;
}
- list_add_tail(&packet->ListEntry,
- &netDevice->ReceivePacketList);
+ list_add_tail(&packet->list_ent,
+ &net_device->recv_pkt_list);
}
- netDevice->ChannelInitEvent = osd_WaitEventCreate();
- if (!netDevice->ChannelInitEvent) {
+ net_device->channel_init_event = osd_waitevent_create();
+ if (!net_device->channel_init_event) {
ret = -ENOMEM;
goto Cleanup;
}
/* Open the channel */
- ret = vmbus_open(Device->channel, netDriver->RingBufferSize,
- netDriver->RingBufferSize, NULL, 0,
- NetVscOnChannelCallback, Device);
+ ret = vmbus_open(device->channel, net_driver->ring_buf_size,
+ net_driver->ring_buf_size, NULL, 0,
+ netvsc_channel_cb, device);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to open channel: %d", ret);
@@ -731,7 +760,7 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***");
/* Connect with the NetVsp */
- ret = NetVscConnectToVsp(Device);
+ ret = netvsc_connect_vsp(device);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret);
ret = -1;
@@ -745,174 +774,178 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
close:
/* Now, we can close the channel safely */
- vmbus_close(Device->channel);
+ vmbus_close(device->channel);
Cleanup:
- if (netDevice) {
- kfree(netDevice->ChannelInitEvent);
+ if (net_device) {
+ kfree(net_device->channel_init_event);
list_for_each_entry_safe(packet, pos,
- &netDevice->ReceivePacketList,
- ListEntry) {
- list_del(&packet->ListEntry);
+ &net_device->recv_pkt_list,
+ list_ent) {
+ list_del(&packet->list_ent);
kfree(packet);
}
- ReleaseOutboundNetDevice(Device);
- ReleaseInboundNetDevice(Device);
+ release_outbound_net_device(device);
+ release_inbound_net_device(device);
- FreeNetDevice(netDevice);
+ free_net_device(net_device);
}
return ret;
}
/*
- * NetVscOnDeviceRemove - Callback when the root bus device is removed
+ * netvsc_device_remove - Callback when the root bus device is removed
*/
-static int NetVscOnDeviceRemove(struct hv_device *Device)
+static int netvsc_device_remove(struct hv_device *device)
{
- struct netvsc_device *netDevice;
- struct hv_netvsc_packet *netvscPacket, *pos;
+ struct netvsc_device *net_device;
+ struct hv_netvsc_packet *netvsc_packet, *pos;
DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...",
- Device->Extension);
+ device->Extension);
/* Stop outbound traffic ie sends and receives completions */
- netDevice = ReleaseOutboundNetDevice(Device);
- if (!netDevice) {
+ net_device = release_outbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "No net device present!!");
return -1;
}
/* Wait for all send completions */
- while (atomic_read(&netDevice->NumOutstandingSends)) {
+ while (atomic_read(&net_device->num_outstanding_sends)) {
DPRINT_INFO(NETVSC, "waiting for %d requests to complete...",
- atomic_read(&netDevice->NumOutstandingSends));
+ atomic_read(&net_device->num_outstanding_sends));
udelay(100);
}
DPRINT_INFO(NETVSC, "Disconnecting from netvsp...");
- NetVscDisconnectFromVsp(netDevice);
+ NetVscDisconnectFromVsp(net_device);
DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...",
- Device->Extension);
+ device->Extension);
/* Stop inbound traffic ie receives and sends completions */
- netDevice = ReleaseInboundNetDevice(Device);
+ net_device = release_inbound_net_device(device);
/* At this point, no one should be accessing netDevice except in here */
- DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice);
+ DPRINT_INFO(NETVSC, "net device (%p) safe to remove", net_device);
/* Now, we can close the channel safely */
- vmbus_close(Device->channel);
+ vmbus_close(device->channel);
/* Release all resources */
- list_for_each_entry_safe(netvscPacket, pos,
- &netDevice->ReceivePacketList, ListEntry) {
- list_del(&netvscPacket->ListEntry);
- kfree(netvscPacket);
+ list_for_each_entry_safe(netvsc_packet, pos,
+ &net_device->recv_pkt_list, list_ent) {
+ list_del(&netvsc_packet->list_ent);
+ kfree(netvsc_packet);
}
- kfree(netDevice->ChannelInitEvent);
- FreeNetDevice(netDevice);
+ kfree(net_device->channel_init_event);
+ free_net_device(net_device);
return 0;
}
/*
- * NetVscOnCleanup - Perform any cleanup when the driver is removed
+ * netvsc_cleanup - Perform any cleanup when the driver is removed
*/
-static void NetVscOnCleanup(struct hv_driver *drv)
+static void netvsc_cleanup(struct hv_driver *drv)
{
}
-static void NetVscOnSendCompletion(struct hv_device *Device,
- struct vmpacket_descriptor *Packet)
+static void netvsc_send_completion(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
{
- struct netvsc_device *netDevice;
- struct nvsp_message *nvspPacket;
- struct hv_netvsc_packet *nvscPacket;
+ struct netvsc_device *net_device;
+ struct nvsp_message *nvsp_packet;
+ struct hv_netvsc_packet *nvsc_packet;
- netDevice = GetInboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_inbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return;
}
- nvspPacket = (struct nvsp_message *)((unsigned long)Packet + (Packet->DataOffset8 << 3));
+ nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
+ (packet->DataOffset8 << 3));
DPRINT_DBG(NETVSC, "send completion packet - type %d",
- nvspPacket->Header.MessageType);
+ nvsp_packet->hdr.msg_type);
- if ((nvspPacket->Header.MessageType == NvspMessageTypeInitComplete) ||
- (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendReceiveBufferComplete) ||
- (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendSendBufferComplete)) {
+ if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
+ (nvsp_packet->hdr.msg_type ==
+ NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
+ (nvsp_packet->hdr.msg_type ==
+ NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) {
/* Copy the response back */
- memcpy(&netDevice->ChannelInitPacket, nvspPacket,
+ memcpy(&net_device->channel_init_pkt, nvsp_packet,
sizeof(struct nvsp_message));
- osd_WaitEventSet(netDevice->ChannelInitEvent);
- } else if (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendRNDISPacketComplete) {
+ osd_waitevent_set(net_device->channel_init_event);
+ } else if (nvsp_packet->hdr.msg_type ==
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
/* Get the send context */
- nvscPacket = (struct hv_netvsc_packet *)(unsigned long)Packet->TransactionId;
+ nvsc_packet = (struct hv_netvsc_packet *)(unsigned long)
+ packet->TransactionId;
/* ASSERT(nvscPacket); */
/* Notify the layer above us */
- nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext);
+ nvsc_packet->completion.send.send_completion(
+ nvsc_packet->completion.send.send_completion_ctx);
- atomic_dec(&netDevice->NumOutstandingSends);
+ atomic_dec(&net_device->num_outstanding_sends);
} else {
DPRINT_ERR(NETVSC, "Unknown send completion packet type - "
- "%d received!!", nvspPacket->Header.MessageType);
+ "%d received!!", nvsp_packet->hdr.msg_type);
}
- PutNetDevice(Device);
+ put_net_device(device);
}
-static int NetVscOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
+static int netvsc_send(struct hv_device *device,
+ struct hv_netvsc_packet *packet)
{
- struct netvsc_device *netDevice;
+ struct netvsc_device *net_device;
int ret = 0;
struct nvsp_message sendMessage;
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_outbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
- "ignoring outbound packets", netDevice);
+ "ignoring outbound packets", net_device);
return -2;
}
- sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket;
- if (Packet->IsDataPacket) {
+ sendMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
+ if (packet->is_data_pkt) {
/* 0 is RMC_DATA; */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0;
+ sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 0;
} else {
/* 1 is RMC_CONTROL; */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1;
+ sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1;
}
/* Not using send buffer section */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF;
- sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0;
-
- if (Packet->PageBufferCount) {
- ret = vmbus_sendpacket_pagebuffer(Device->channel,
- Packet->PageBuffers,
- Packet->PageBufferCount,
+ sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index =
+ 0xFFFFFFFF;
+ sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0;
+
+ if (packet->page_buf_cnt) {
+ ret = vmbus_sendpacket_pagebuffer(device->channel,
+ packet->page_buf,
+ packet->page_buf_cnt,
&sendMessage,
sizeof(struct nvsp_message),
- (unsigned long)Packet);
+ (unsigned long)packet);
} else {
- ret = vmbus_sendpacket(Device->channel, &sendMessage,
+ ret = vmbus_sendpacket(device->channel, &sendMessage,
sizeof(struct nvsp_message),
- (unsigned long)Packet,
+ (unsigned long)packet,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -920,31 +953,31 @@ static int NetVscOnSend(struct hv_device *Device,
if (ret != 0)
DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d",
- Packet, ret);
+ packet, ret);
- atomic_inc(&netDevice->NumOutstandingSends);
- PutNetDevice(Device);
+ atomic_inc(&net_device->num_outstanding_sends);
+ put_net_device(device);
return ret;
}
-static void NetVscOnReceive(struct hv_device *Device,
- struct vmpacket_descriptor *Packet)
+static void netvsc_receive(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
{
- struct netvsc_device *netDevice;
- struct vmtransfer_page_packet_header *vmxferpagePacket;
- struct nvsp_message *nvspPacket;
- struct hv_netvsc_packet *netvscPacket = NULL;
+ struct netvsc_device *net_device;
+ struct vmtransfer_page_packet_header *vmxferpage_packet;
+ struct nvsp_message *nvsp_packet;
+ struct hv_netvsc_packet *netvsc_packet = NULL;
unsigned long start;
- unsigned long end, endVirtual;
+ unsigned long end, end_virtual;
/* struct netvsc_driver *netvscDriver; */
- struct xferpage_packet *xferpagePacket = NULL;
+ struct xferpage_packet *xferpage_packet = NULL;
int i, j;
- int count = 0, bytesRemain = 0;
+ int count = 0, bytes_remain = 0;
unsigned long flags;
LIST_HEAD(listHead);
- netDevice = GetInboundNetDevice(Device);
- if (!netDevice) {
+ net_device = get_inbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return;
@@ -954,39 +987,40 @@ static void NetVscOnReceive(struct hv_device *Device,
* All inbound packets other than send completion should be xfer page
* packet
*/
- if (Packet->Type != VmbusPacketTypeDataUsingTransferPages) {
+ if (packet->Type != VmbusPacketTypeDataUsingTransferPages) {
DPRINT_ERR(NETVSC, "Unknown packet type received - %d",
- Packet->Type);
- PutNetDevice(Device);
+ packet->Type);
+ put_net_device(device);
return;
}
- nvspPacket = (struct nvsp_message *)((unsigned long)Packet +
- (Packet->DataOffset8 << 3));
+ nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
+ (packet->DataOffset8 << 3));
/* Make sure this is a valid nvsp packet */
- if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket) {
+ if (nvsp_packet->hdr.msg_type !=
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT) {
DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d",
- nvspPacket->Header.MessageType);
- PutNetDevice(Device);
+ nvsp_packet->hdr.msg_type);
+ put_net_device(device);
return;
}
DPRINT_DBG(NETVSC, "NVSP packet received - type %d",
- nvspPacket->Header.MessageType);
+ nvsp_packet->hdr.msg_type);
- vmxferpagePacket = (struct vmtransfer_page_packet_header *)Packet;
+ vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet;
- if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) {
+ if (vmxferpage_packet->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) {
DPRINT_ERR(NETVSC, "Invalid xfer page set id - "
"expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID,
- vmxferpagePacket->TransferPageSetId);
- PutNetDevice(Device);
+ vmxferpage_packet->TransferPageSetId);
+ put_net_device(device);
return;
}
DPRINT_DBG(NETVSC, "xfer page - range count %d",
- vmxferpagePacket->RangeCount);
+ vmxferpage_packet->RangeCount);
/*
* Grab free packets (range count + 1) to represent this xfer
@@ -994,13 +1028,13 @@ static void NetVscOnReceive(struct hv_device *Device,
* We grab it here so that we know exactly how many we can
* fulfil
*/
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
- while (!list_empty(&netDevice->ReceivePacketList)) {
- list_move_tail(netDevice->ReceivePacketList.next, &listHead);
- if (++count == vmxferpagePacket->RangeCount + 1)
+ spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
+ while (!list_empty(&net_device->recv_pkt_list)) {
+ list_move_tail(net_device->recv_pkt_list.next, &listHead);
+ if (++count == vmxferpage_packet->RangeCount + 1)
break;
}
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags);
+ spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
/*
* We need at least 2 netvsc pkts (1 to represent the xfer
@@ -1010,140 +1044,149 @@ static void NetVscOnReceive(struct hv_device *Device,
if (count < 2) {
DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. "
"Dropping this xfer page packet completely!",
- count, vmxferpagePacket->RangeCount + 1);
+ count, vmxferpage_packet->RangeCount + 1);
/* Return it to the freelist */
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
+ spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
for (i = count; i != 0; i--) {
list_move_tail(listHead.next,
- &netDevice->ReceivePacketList);
+ &net_device->recv_pkt_list);
}
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock,
+ spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
flags);
- NetVscSendReceiveCompletion(Device,
- vmxferpagePacket->d.TransactionId);
+ netvsc_send_recv_completion(device,
+ vmxferpage_packet->d.TransactionId);
- PutNetDevice(Device);
+ put_net_device(device);
return;
}
/* Remove the 1st packet to represent the xfer page packet itself */
- xferpagePacket = (struct xferpage_packet *)listHead.next;
- list_del(&xferpagePacket->ListEntry);
+ xferpage_packet = (struct xferpage_packet *)listHead.next;
+ list_del(&xferpage_packet->list_ent);
/* This is how much we can satisfy */
- xferpagePacket->Count = count - 1;
+ xferpage_packet->count = count - 1;
/* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */
/* vmxferpagePacket->RangeCount); */
- if (xferpagePacket->Count != vmxferpagePacket->RangeCount) {
+ if (xferpage_packet->count != vmxferpage_packet->RangeCount) {
DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer "
- "page...got %d", vmxferpagePacket->RangeCount,
- xferpagePacket->Count);
+ "page...got %d", vmxferpage_packet->RangeCount,
+ xferpage_packet->count);
}
/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
for (i = 0; i < (count - 1); i++) {
- netvscPacket = (struct hv_netvsc_packet *)listHead.next;
- list_del(&netvscPacket->ListEntry);
+ netvsc_packet = (struct hv_netvsc_packet *)listHead.next;
+ list_del(&netvsc_packet->list_ent);
/* Initialize the netvsc packet */
- netvscPacket->XferPagePacket = xferpagePacket;
- netvscPacket->Completion.Recv.OnReceiveCompletion =
- NetVscOnReceiveCompletion;
- netvscPacket->Completion.Recv.ReceiveCompletionContext =
- netvscPacket;
- netvscPacket->Device = Device;
+ netvsc_packet->xfer_page_pkt = xferpage_packet;
+ netvsc_packet->completion.recv.recv_completion =
+ netvsc_receive_completion;
+ netvsc_packet->completion.recv.recv_completion_ctx =
+ netvsc_packet;
+ netvsc_packet->device = device;
/* Save this so that we can send it back */
- netvscPacket->Completion.Recv.ReceiveCompletionTid =
- vmxferpagePacket->d.TransactionId;
+ netvsc_packet->completion.recv.recv_completion_tid =
+ vmxferpage_packet->d.TransactionId;
- netvscPacket->TotalDataBufferLength =
- vmxferpagePacket->Ranges[i].ByteCount;
- netvscPacket->PageBufferCount = 1;
+ netvsc_packet->total_data_buflen =
+ vmxferpage_packet->Ranges[i].ByteCount;
+ netvsc_packet->page_buf_cnt = 1;
/* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */
/* vmxferpagePacket->Ranges[i].ByteCount < */
/* netDevice->ReceiveBufferSize); */
- netvscPacket->PageBuffers[0].Length =
- vmxferpagePacket->Ranges[i].ByteCount;
+ netvsc_packet->page_buf[0].Length =
+ vmxferpage_packet->Ranges[i].ByteCount;
- start = virt_to_phys((void *)((unsigned long)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset));
+ start = virt_to_phys((void *)((unsigned long)net_device->
+ recv_buf + vmxferpage_packet->Ranges[i].ByteOffset));
- netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT;
- endVirtual = (unsigned long)netDevice->ReceiveBuffer
- + vmxferpagePacket->Ranges[i].ByteOffset
- + vmxferpagePacket->Ranges[i].ByteCount - 1;
- end = virt_to_phys((void *)endVirtual);
+ netvsc_packet->page_buf[0].Pfn = start >> PAGE_SHIFT;
+ end_virtual = (unsigned long)net_device->recv_buf
+ + vmxferpage_packet->Ranges[i].ByteOffset
+ + vmxferpage_packet->Ranges[i].ByteCount - 1;
+ end = virt_to_phys((void *)end_virtual);
/* Calculate the page relative offset */
- netvscPacket->PageBuffers[0].Offset =
- vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE - 1);
+ netvsc_packet->page_buf[0].Offset =
+ vmxferpage_packet->Ranges[i].ByteOffset &
+ (PAGE_SIZE - 1);
if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) {
/* Handle frame across multiple pages: */
- netvscPacket->PageBuffers[0].Length =
- (netvscPacket->PageBuffers[0].Pfn << PAGE_SHIFT)
+ netvsc_packet->page_buf[0].Length =
+ (netvsc_packet->page_buf[0].Pfn <<
+ PAGE_SHIFT)
+ PAGE_SIZE - start;
- bytesRemain = netvscPacket->TotalDataBufferLength -
- netvscPacket->PageBuffers[0].Length;
+ bytes_remain = netvsc_packet->total_data_buflen -
+ netvsc_packet->page_buf[0].Length;
for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) {
- netvscPacket->PageBuffers[j].Offset = 0;
- if (bytesRemain <= PAGE_SIZE) {
- netvscPacket->PageBuffers[j].Length = bytesRemain;
- bytesRemain = 0;
+ netvsc_packet->page_buf[j].Offset = 0;
+ if (bytes_remain <= PAGE_SIZE) {
+ netvsc_packet->page_buf[j].Length =
+ bytes_remain;
+ bytes_remain = 0;
} else {
- netvscPacket->PageBuffers[j].Length = PAGE_SIZE;
- bytesRemain -= PAGE_SIZE;
+ netvsc_packet->page_buf[j].Length =
+ PAGE_SIZE;
+ bytes_remain -= PAGE_SIZE;
}
- netvscPacket->PageBuffers[j].Pfn =
- virt_to_phys((void *)(endVirtual - bytesRemain)) >> PAGE_SHIFT;
- netvscPacket->PageBufferCount++;
- if (bytesRemain == 0)
+ netvsc_packet->page_buf[j].Pfn =
+ virt_to_phys((void *)(end_virtual -
+ bytes_remain)) >> PAGE_SHIFT;
+ netvsc_packet->page_buf_cnt++;
+ if (bytes_remain == 0)
break;
}
/* ASSERT(bytesRemain == 0); */
}
DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => "
"(pfn %llx, offset %u, len %u)", i,
- vmxferpagePacket->Ranges[i].ByteOffset,
- vmxferpagePacket->Ranges[i].ByteCount,
- netvscPacket->PageBuffers[0].Pfn,
- netvscPacket->PageBuffers[0].Offset,
- netvscPacket->PageBuffers[0].Length);
+ vmxferpage_packet->Ranges[i].ByteOffset,
+ vmxferpage_packet->Ranges[i].ByteCount,
+ netvsc_packet->page_buf[0].Pfn,
+ netvsc_packet->page_buf[0].Offset,
+ netvsc_packet->page_buf[0].Length);
/* Pass it to the upper layer */
- ((struct netvsc_driver *)Device->Driver)->OnReceiveCallback(Device, netvscPacket);
+ ((struct netvsc_driver *)device->Driver)->
+ recv_cb(device, netvsc_packet);
- NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext);
+ netvsc_receive_completion(netvsc_packet->
+ completion.recv.recv_completion_ctx);
}
/* ASSERT(list_empty(&listHead)); */
- PutNetDevice(Device);
+ put_net_device(device);
}
-static void NetVscSendReceiveCompletion(struct hv_device *Device,
- u64 TransactionId)
+static void netvsc_send_recv_completion(struct hv_device *device,
+ u64 transaction_id)
{
struct nvsp_message recvcompMessage;
int retries = 0;
int ret;
DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx",
- TransactionId);
+ transaction_id);
- recvcompMessage.Header.MessageType =
- NvspMessage1TypeSendRNDISPacketComplete;
+ recvcompMessage.hdr.msg_type =
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
/* FIXME: Pass in the status */
- recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess;
+ recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status =
+ NVSP_STAT_SUCCESS;
retry_send_cmplt:
/* Send the completion */
- ret = vmbus_sendpacket(Device->channel, &recvcompMessage,
- sizeof(struct nvsp_message), TransactionId,
+ ret = vmbus_sendpacket(device->channel, &recvcompMessage,
+ sizeof(struct nvsp_message), transaction_id,
VmbusPacketTypeCompletion, 0);
if (ret == 0) {
/* success */
@@ -1152,7 +1195,7 @@ retry_send_cmplt:
/* no more room...wait a bit and attempt to retry 3 times */
retries++;
DPRINT_ERR(NETVSC, "unable to send receive completion pkt "
- "(tid %llx)...retrying %d", TransactionId, retries);
+ "(tid %llx)...retrying %d", transaction_id, retries);
if (retries < 4) {
udelay(100);
@@ -1160,22 +1203,22 @@ retry_send_cmplt:
} else {
DPRINT_ERR(NETVSC, "unable to send receive completion "
"pkt (tid %llx)...give up retrying",
- TransactionId);
+ transaction_id);
}
} else {
DPRINT_ERR(NETVSC, "unable to send receive completion pkt - "
- "%llx", TransactionId);
+ "%llx", transaction_id);
}
}
/* Send a receive completion packet to RNDIS device (ie NetVsp) */
-static void NetVscOnReceiveCompletion(void *Context)
+static void netvsc_receive_completion(void *context)
{
- struct hv_netvsc_packet *packet = Context;
- struct hv_device *device = (struct hv_device *)packet->Device;
- struct netvsc_device *netDevice;
- u64 transactionId = 0;
- bool fSendReceiveComp = false;
+ struct hv_netvsc_packet *packet = context;
+ struct hv_device *device = (struct hv_device *)packet->device;
+ struct netvsc_device *net_device;
+ u64 transaction_id = 0;
+ bool fsend_receive_comp = false;
unsigned long flags;
/* ASSERT(packet->XferPagePacket); */
@@ -1185,49 +1228,49 @@ static void NetVscOnReceiveCompletion(void *Context)
* send out receive completion, we are using GetInboundNetDevice()
* since we may have disable outbound traffic already.
*/
- netDevice = GetInboundNetDevice(device);
- if (!netDevice) {
+ net_device = get_inbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
return;
}
/* Overloading use of the lock. */
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
+ spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
/* ASSERT(packet->XferPagePacket->Count > 0); */
- packet->XferPagePacket->Count--;
+ packet->xfer_page_pkt->count--;
/*
* Last one in the line that represent 1 xfer page packet.
* Return the xfer page packet itself to the freelist
*/
- if (packet->XferPagePacket->Count == 0) {
- fSendReceiveComp = true;
- transactionId = packet->Completion.Recv.ReceiveCompletionTid;
- list_add_tail(&packet->XferPagePacket->ListEntry,
- &netDevice->ReceivePacketList);
+ if (packet->xfer_page_pkt->count == 0) {
+ fsend_receive_comp = true;
+ transaction_id = packet->completion.recv.recv_completion_tid;
+ list_add_tail(&packet->xfer_page_pkt->list_ent,
+ &net_device->recv_pkt_list);
}
/* Put the packet back */
- list_add_tail(&packet->ListEntry, &netDevice->ReceivePacketList);
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags);
+ list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
+ spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
/* Send a receive completion for the xfer page packet */
- if (fSendReceiveComp)
- NetVscSendReceiveCompletion(device, transactionId);
+ if (fsend_receive_comp)
+ netvsc_send_recv_completion(device, transaction_id);
- PutNetDevice(device);
+ put_net_device(device);
}
-static void NetVscOnChannelCallback(void *Context)
+static void netvsc_channel_cb(void *context)
{
int ret;
- struct hv_device *device = Context;
- struct netvsc_device *netDevice;
- u32 bytesRecvd;
- u64 requestId;
+ struct hv_device *device = context;
+ struct netvsc_device *net_device;
+ u32 bytes_recvd;
+ u64 request_id;
unsigned char *packet;
struct vmpacket_descriptor *desc;
unsigned char *buffer;
@@ -1241,37 +1284,37 @@ static void NetVscOnChannelCallback(void *Context)
return;
buffer = packet;
- netDevice = GetInboundNetDevice(device);
- if (!netDevice) {
+ net_device = get_inbound_net_device(device);
+ if (!net_device) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
- "ignoring inbound packets", netDevice);
+ "ignoring inbound packets", net_device);
goto out;
}
do {
ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
- &bytesRecvd, &requestId);
+ &bytes_recvd, &request_id);
if (ret == 0) {
- if (bytesRecvd > 0) {
+ if (bytes_recvd > 0) {
DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx",
- bytesRecvd, requestId);
+ bytes_recvd, request_id);
desc = (struct vmpacket_descriptor *)buffer;
switch (desc->Type) {
case VmbusPacketTypeCompletion:
- NetVscOnSendCompletion(device, desc);
+ netvsc_send_completion(device, desc);
break;
case VmbusPacketTypeDataUsingTransferPages:
- NetVscOnReceive(device, desc);
+ netvsc_receive(device, desc);
break;
default:
DPRINT_ERR(NETVSC,
"unhandled packet type %d, "
"tid %llx len %d\n",
- desc->Type, requestId,
- bytesRecvd);
+ desc->Type, request_id,
+ bytes_recvd);
break;
}
@@ -1293,20 +1336,20 @@ static void NetVscOnChannelCallback(void *Context)
}
} else if (ret == -2) {
/* Handle large packet */
- buffer = kmalloc(bytesRecvd, GFP_ATOMIC);
+ buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
if (buffer == NULL) {
/* Try again next time around */
DPRINT_ERR(NETVSC,
"unable to allocate buffer of size "
- "(%d)!!", bytesRecvd);
+ "(%d)!!", bytes_recvd);
break;
}
- bufferlen = bytesRecvd;
+ bufferlen = bytes_recvd;
}
} while (1);
- PutNetDevice(device);
+ put_net_device(device);
out:
kfree(buffer);
return;
diff --git a/drivers/staging/hv/netvsc.h b/drivers/staging/hv/netvsc.h
index c71dce5b3f7c..932a77ccdc04 100644
--- a/drivers/staging/hv/netvsc.h
+++ b/drivers/staging/hv/netvsc.h
@@ -38,48 +38,48 @@
#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
enum {
- NvspMessageTypeNone = 0,
+ NVSP_MSG_TYPE_NONE = 0,
/* Init Messages */
- NvspMessageTypeInit = 1,
- NvspMessageTypeInitComplete = 2,
+ NVSP_MSG_TYPE_INIT = 1,
+ NVSP_MSG_TYPE_INIT_COMPLETE = 2,
- NvspVersionMessageStart = 100,
+ NVSP_VERSION_MSG_START = 100,
/* Version 1 Messages */
- NvspMessage1TypeSendNdisVersion = NvspVersionMessageStart,
+ NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START,
- NvspMessage1TypeSendReceiveBuffer,
- NvspMessage1TypeSendReceiveBufferComplete,
- NvspMessage1TypeRevokeReceiveBuffer,
+ NVSP_MSG1_TYPE_SEND_RECV_BUF,
+ NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE,
+ NVSP_MSG1_TYPE_REVOKE_RECV_BUF,
- NvspMessage1TypeSendSendBuffer,
- NvspMessage1TypeSendSendBufferComplete,
- NvspMessage1TypeRevokeSendBuffer,
+ NVSP_MSG1_TYPE_SEND_SEND_BUF,
+ NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE,
+ NVSP_MSG1_TYPE_REVOKE_SEND_BUF,
- NvspMessage1TypeSendRNDISPacket,
- NvspMessage1TypeSendRNDISPacketComplete,
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT,
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE,
/*
* This should be set to the number of messages for the version with
* the maximum number of messages.
*/
- NvspNumMessagePerVersion = 9,
+ NVSP_NUM_MSG_PER_VERSION = 9,
};
enum {
- NvspStatusNone = 0,
- NvspStatusSuccess,
- NvspStatusFailure,
- NvspStatusProtocolVersionRangeTooNew,
- NvspStatusProtocolVersionRangeTooOld,
- NvspStatusInvalidRndisPacket,
- NvspStatusBusy,
- NvspStatusMax,
+ NVSP_STAT_NONE = 0,
+ NVSP_STAT_SUCCESS,
+ NVSP_STAT_FAIL,
+ NVSP_STAT_PROTOCOL_TOO_NEW,
+ NVSP_STAT_PROTOCOL_TOO_OLD,
+ NVSP_STAT_INVALID_RNDIS_PKT,
+ NVSP_STAT_BUSY,
+ NVSP_STAT_MAX,
};
struct nvsp_message_header {
- u32 MessageType;
+ u32 msg_type;
};
/* Init Messages */
@@ -90,8 +90,8 @@ struct nvsp_message_header {
* versioning (i.e. this message will be the same for ever).
*/
struct nvsp_message_init {
- u32 MinProtocolVersion;
- u32 MaxProtocolVersion;
+ u32 min_protocol_ver;
+ u32 max_protocol_ver;
} __attribute__((packed));
/*
@@ -100,14 +100,14 @@ struct nvsp_message_init {
* (i.e. this message will be the same for ever).
*/
struct nvsp_message_init_complete {
- u32 NegotiatedProtocolVersion;
- u32 MaximumMdlChainLength;
- u32 Status;
+ u32 negotiated_protocol_ver;
+ u32 max_mdl_chain_len;
+ u32 status;
} __attribute__((packed));
union nvsp_message_init_uber {
- struct nvsp_message_init Init;
- struct nvsp_message_init_complete InitComplete;
+ struct nvsp_message_init init;
+ struct nvsp_message_init_complete init_complete;
} __attribute__((packed));
/* Version 1 Messages */
@@ -117,8 +117,8 @@ union nvsp_message_init_uber {
* can use this information when handling OIDs sent by the VSC.
*/
struct nvsp_1_message_send_ndis_version {
- u32 NdisMajorVersion;
- u32 NdisMinorVersion;
+ u32 ndis_major_ver;
+ u32 ndis_minor_ver;
} __attribute__((packed));
/*
@@ -126,15 +126,15 @@ struct nvsp_1_message_send_ndis_version {
* can then use the receive buffer to send data to the VSC.
*/
struct nvsp_1_message_send_receive_buffer {
- u32 GpadlHandle;
- u16 Id;
+ u32 gpadl_handle;
+ u16 id;
} __attribute__((packed));
struct nvsp_1_receive_buffer_section {
- u32 Offset;
- u32 SubAllocationSize;
- u32 NumSubAllocations;
- u32 EndOffset;
+ u32 offset;
+ u32 sub_alloc_size;
+ u32 num_sub_allocs;
+ u32 end_offset;
} __attribute__((packed));
/*
@@ -143,8 +143,8 @@ struct nvsp_1_receive_buffer_section {
* buffer.
*/
struct nvsp_1_message_send_receive_buffer_complete {
- u32 Status;
- u32 NumSections;
+ u32 status;
+ u32 num_sections;
/*
* The receive buffer is split into two parts, a large suballocation
@@ -165,7 +165,7 @@ struct nvsp_1_message_send_receive_buffer_complete {
* LargeOffset SmallOffset
*/
- struct nvsp_1_receive_buffer_section Sections[1];
+ struct nvsp_1_receive_buffer_section sections[1];
} __attribute__((packed));
/*
@@ -174,7 +174,7 @@ struct nvsp_1_message_send_receive_buffer_complete {
* again.
*/
struct nvsp_1_message_revoke_receive_buffer {
- u16 Id;
+ u16 id;
};
/*
@@ -182,8 +182,8 @@ struct nvsp_1_message_revoke_receive_buffer {
* can then use the send buffer to send data to the VSP.
*/
struct nvsp_1_message_send_send_buffer {
- u32 GpadlHandle;
- u16 Id;
+ u32 gpadl_handle;
+ u16 id;
} __attribute__((packed));
/*
@@ -192,7 +192,7 @@ struct nvsp_1_message_send_send_buffer {
* buffer.
*/
struct nvsp_1_message_send_send_buffer_complete {
- u32 Status;
+ u32 status;
/*
* The VSC gets to choose the size of the send buffer and the VSP gets
@@ -200,7 +200,7 @@ struct nvsp_1_message_send_send_buffer_complete {
* dynamic reconfigurations when the cost of GPA-direct buffers
* decreases.
*/
- u32 SectionSize;
+ u32 section_size;
} __attribute__((packed));
/*
@@ -208,7 +208,7 @@ struct nvsp_1_message_send_send_buffer_complete {
* completes this transaction, the vsp should never use the send buffer again.
*/
struct nvsp_1_message_revoke_send_buffer {
- u16 Id;
+ u16 id;
};
/*
@@ -221,7 +221,7 @@ struct nvsp_1_message_send_rndis_packet {
* channels of communication. However, the Network VSP only has one.
* Therefore, the channel travels with the RNDIS packet.
*/
- u32 ChannelType;
+ u32 channel_type;
/*
* This field is used to send part or all of the data through a send
@@ -229,8 +229,8 @@ struct nvsp_1_message_send_rndis_packet {
* index is 0xFFFFFFFF, then the send buffer is not being used and all
* of the data was sent through other VMBus mechanisms.
*/
- u32 SendBufferSectionIndex;
- u32 SendBufferSectionSize;
+ u32 send_buf_section_index;
+ u32 send_buf_section_size;
} __attribute__((packed));
/*
@@ -239,35 +239,35 @@ struct nvsp_1_message_send_rndis_packet {
* message cannot use any resources associated with the original RNDIS packet.
*/
struct nvsp_1_message_send_rndis_packet_complete {
- u32 Status;
+ u32 status;
};
union nvsp_1_message_uber {
- struct nvsp_1_message_send_ndis_version SendNdisVersion;
+ struct nvsp_1_message_send_ndis_version send_ndis_ver;
- struct nvsp_1_message_send_receive_buffer SendReceiveBuffer;
+ struct nvsp_1_message_send_receive_buffer send_recv_buf;
struct nvsp_1_message_send_receive_buffer_complete
- SendReceiveBufferComplete;
- struct nvsp_1_message_revoke_receive_buffer RevokeReceiveBuffer;
+ send_recv_buf_complete;
+ struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf;
- struct nvsp_1_message_send_send_buffer SendSendBuffer;
- struct nvsp_1_message_send_send_buffer_complete SendSendBufferComplete;
- struct nvsp_1_message_revoke_send_buffer RevokeSendBuffer;
+ struct nvsp_1_message_send_send_buffer send_send_buf;
+ struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete;
+ struct nvsp_1_message_revoke_send_buffer revoke_send_buf;
- struct nvsp_1_message_send_rndis_packet SendRNDISPacket;
+ struct nvsp_1_message_send_rndis_packet send_rndis_pkt;
struct nvsp_1_message_send_rndis_packet_complete
- SendRNDISPacketComplete;
+ send_rndis_pkt_complete;
} __attribute__((packed));
union nvsp_all_messages {
- union nvsp_message_init_uber InitMessages;
- union nvsp_1_message_uber Version1Messages;
+ union nvsp_message_init_uber init_msg;
+ union nvsp_1_message_uber v1_msg;
} __attribute__((packed));
/* ALL Messages */
struct nvsp_message {
- struct nvsp_message_header Header;
- union nvsp_all_messages Messages;
+ struct nvsp_message_header hdr;
+ union nvsp_all_messages msg;
} __attribute__((packed));
@@ -293,39 +293,39 @@ struct nvsp_message {
/* Per netvsc channel-specific */
struct netvsc_device {
- struct hv_device *Device;
+ struct hv_device *dev;
- atomic_t RefCount;
- atomic_t NumOutstandingSends;
+ atomic_t refcnt;
+ atomic_t num_outstanding_sends;
/*
* List of free preallocated hv_netvsc_packet to represent receive
* packet
*/
- struct list_head ReceivePacketList;
- spinlock_t receive_packet_list_lock;
+ struct list_head recv_pkt_list;
+ spinlock_t recv_pkt_list_lock;
/* Send buffer allocated by us but manages by NetVSP */
- void *SendBuffer;
- u32 SendBufferSize;
- u32 SendBufferGpadlHandle;
- u32 SendSectionSize;
+ void *send_buf;
+ u32 send_buf_size;
+ u32 send_buf_gpadl_handle;
+ u32 send_section_size;
/* Receive buffer allocated by us but manages by NetVSP */
- void *ReceiveBuffer;
- u32 ReceiveBufferSize;
- u32 ReceiveBufferGpadlHandle;
- u32 ReceiveSectionCount;
- struct nvsp_1_receive_buffer_section *ReceiveSections;
+ void *recv_buf;
+ u32 recv_buf_size;
+ u32 recv_buf_gpadl_handle;
+ u32 recv_section_cnt;
+ struct nvsp_1_receive_buffer_section *recv_section;
/* Used for NetVSP initialization protocol */
- struct osd_waitevent *ChannelInitEvent;
- struct nvsp_message ChannelInitPacket;
+ struct osd_waitevent *channel_init_event;
+ struct nvsp_message channel_init_pkt;
- struct nvsp_message RevokePacket;
+ struct nvsp_message revoke_packet;
/* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
/* Holds rndis device info */
- void *Extension;
+ void *extension;
};
#endif /* _NETVSC_H_ */
diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h
index 4b5b3ac458c8..b4bed3636594 100644
--- a/drivers/staging/hv/netvsc_api.h
+++ b/drivers/staging/hv/netvsc_api.h
@@ -32,10 +32,10 @@ struct hv_netvsc_packet;
/* Represent the xfer page packet which contains 1 or more netvsc packet */
struct xferpage_packet {
- struct list_head ListEntry;
+ struct list_head list_ent;
/* # of netvsc packets this xfer packet contains */
- u32 Count;
+ u32 count;
};
/* The number of pages which are enough to cover jumbo frame buffer. */
@@ -47,70 +47,70 @@ struct xferpage_packet {
*/
struct hv_netvsc_packet {
/* Bookkeeping stuff */
- struct list_head ListEntry;
+ struct list_head list_ent;
- struct hv_device *Device;
- bool IsDataPacket;
+ struct hv_device *device;
+ bool is_data_pkt;
/*
* Valid only for receives when we break a xfer page packet
* into multiple netvsc packets
*/
- struct xferpage_packet *XferPagePacket;
+ struct xferpage_packet *xfer_page_pkt;
union {
struct{
- u64 ReceiveCompletionTid;
- void *ReceiveCompletionContext;
- void (*OnReceiveCompletion)(void *context);
- } Recv;
+ u64 recv_completion_tid;
+ void *recv_completion_ctx;
+ void (*recv_completion)(void *context);
+ } recv;
struct{
- u64 SendCompletionTid;
- void *SendCompletionContext;
- void (*OnSendCompletion)(void *context);
- } Send;
- } Completion;
+ u64 send_completion_tid;
+ void *send_completion_ctx;
+ void (*send_completion)(void *context);
+ } send;
+ } completion;
- /* This points to the memory after PageBuffers */
- void *Extension;
+ /* This points to the memory after page_buf */
+ void *extension;
- u32 TotalDataBufferLength;
+ u32 total_data_buflen;
/* Points to the send/receive buffer where the ethernet frame is */
- u32 PageBufferCount;
- struct hv_page_buffer PageBuffers[NETVSC_PACKET_MAXPAGE];
+ u32 page_buf_cnt;
+ struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
};
/* Represents the net vsc driver */
struct netvsc_driver {
/* Must be the first field */
/* Which is a bug FIXME! */
- struct hv_driver Base;
+ struct hv_driver base;
- u32 RingBufferSize;
- u32 RequestExtSize;
+ u32 ring_buf_size;
+ u32 req_ext_size;
/*
* This is set by the caller to allow us to callback when we
* receive a packet from the "wire"
*/
- int (*OnReceiveCallback)(struct hv_device *dev,
+ int (*recv_cb)(struct hv_device *dev,
struct hv_netvsc_packet *packet);
- void (*OnLinkStatusChanged)(struct hv_device *dev, u32 Status);
+ void (*link_status_change)(struct hv_device *dev, u32 status);
/* Specific to this driver */
- int (*OnSend)(struct hv_device *dev, struct hv_netvsc_packet *packet);
+ int (*send)(struct hv_device *dev, struct hv_netvsc_packet *packet);
- void *Context;
+ void *ctx;
};
struct netvsc_device_info {
- unsigned char MacAddr[6];
- bool LinkState; /* 0 - link up, 1 - link down */
+ unsigned char mac_adr[6];
+ bool link_state; /* 0 - link up, 1 - link down */
};
/* Interface */
-int NetVscInitialize(struct hv_driver *drv);
-int RndisFilterOnOpen(struct hv_device *Device);
-int RndisFilterOnClose(struct hv_device *Device);
+int netvsc_initialize(struct hv_driver *drv);
+int rndis_filter_open(struct hv_device *dev);
+int rndis_filter_close(struct hv_device *dev);
#endif /* _NETVSC_API_H_ */
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 141535295a41..0147b407512c 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -66,6 +66,9 @@ MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
/* The one and only one */
static struct netvsc_driver_context g_netvsc_drv;
+/* no-op so the netdev core doesn't return -EINVAL when modifying the the
+ * multicast address list in SIOCADDMULTI. hv is setup to get all multicast
+ * when it calls RndisFilterOnOpen() */
static void netvsc_set_multicast_list(struct net_device *net)
{
}
@@ -78,7 +81,7 @@ static int netvsc_open(struct net_device *net)
if (netif_carrier_ok(net)) {
/* Open up the device */
- ret = RndisFilterOnOpen(device_obj);
+ ret = rndis_filter_open(device_obj);
if (ret != 0) {
DPRINT_ERR(NETVSC_DRV,
"unable to open device (ret %d).", ret);
@@ -101,7 +104,7 @@ static int netvsc_close(struct net_device *net)
netif_stop_queue(net);
- ret = RndisFilterOnClose(device_obj);
+ ret = rndis_filter_close(device_obj);
if (ret != 0)
DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
@@ -112,7 +115,7 @@ static void netvsc_xmit_completion(void *context)
{
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
struct sk_buff *skb = (struct sk_buff *)
- (unsigned long)packet->Completion.Send.SendCompletionTid;
+ (unsigned long)packet->completion.send.send_completion_tid;
kfree(packet);
@@ -151,7 +154,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
(num_pages * sizeof(struct hv_page_buffer)) +
- net_drv_obj->RequestExtSize, GFP_ATOMIC);
+ net_drv_obj->req_ext_size, GFP_ATOMIC);
if (!packet) {
/* out of memory, silently drop packet */
DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet");
@@ -161,40 +164,40 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
return NETDEV_TX_OK;
}
- packet->Extension = (void *)(unsigned long)packet +
+ packet->extension = (void *)(unsigned long)packet +
sizeof(struct hv_netvsc_packet) +
(num_pages * sizeof(struct hv_page_buffer));
/* Setup the rndis header */
- packet->PageBufferCount = num_pages;
+ packet->page_buf_cnt = num_pages;
/* TODO: Flush all write buffers/ memory fence ??? */
/* wmb(); */
/* Initialize it from the skb */
- packet->TotalDataBufferLength = skb->len;
+ packet->total_data_buflen = skb->len;
/* Start filling in the page buffers starting after RNDIS buffer. */
- packet->PageBuffers[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
- packet->PageBuffers[1].Offset
+ packet->page_buf[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
+ packet->page_buf[1].Offset
= (unsigned long)skb->data & (PAGE_SIZE - 1);
- packet->PageBuffers[1].Length = skb_headlen(skb);
+ packet->page_buf[1].Length = skb_headlen(skb);
/* Additional fragments are after SKB data */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- packet->PageBuffers[i+2].Pfn = page_to_pfn(f->page);
- packet->PageBuffers[i+2].Offset = f->page_offset;
- packet->PageBuffers[i+2].Length = f->size;
+ packet->page_buf[i+2].Pfn = page_to_pfn(f->page);
+ packet->page_buf[i+2].Offset = f->page_offset;
+ packet->page_buf[i+2].Length = f->size;
}
/* Set the completion routine */
- packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion;
- packet->Completion.Send.SendCompletionContext = packet;
- packet->Completion.Send.SendCompletionTid = (unsigned long)skb;
+ packet->completion.send.send_completion = netvsc_xmit_completion;
+ packet->completion.send.send_completion_ctx = packet;
+ packet->completion.send.send_completion_tid = (unsigned long)skb;
- ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj,
+ ret = net_drv_obj->send(&net_device_ctx->device_ctx->device_obj,
packet);
if (ret == 0) {
net->stats.tx_bytes += skb->len;
@@ -260,7 +263,7 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
}
/* Allocate a skb - TODO direct I/O to pages? */
- skb = netdev_alloc_skb_ip_align(net, packet->TotalDataBufferLength);
+ skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
if (unlikely(!skb)) {
++net->stats.rx_dropped;
return 0;
@@ -273,17 +276,17 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
* Copy to skb. This copy is needed here since the memory pointed by
* hv_netvsc_packet cannot be deallocated
*/
- for (i = 0; i < packet->PageBufferCount; i++) {
- data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn),
+ for (i = 0; i < packet->page_buf_cnt; i++) {
+ data = kmap_atomic(pfn_to_page(packet->page_buf[i].Pfn),
KM_IRQ1);
data = (void *)(unsigned long)data +
- packet->PageBuffers[i].Offset;
+ packet->page_buf[i].Offset;
- memcpy(skb_put(skb, packet->PageBuffers[i].Length), data,
- packet->PageBuffers[i].Length);
+ memcpy(skb_put(skb, packet->page_buf[i].Length), data,
+ packet->page_buf[i].Length);
kunmap_atomic((void *)((unsigned long)data -
- packet->PageBuffers[i].Offset), KM_IRQ1);
+ packet->page_buf[i].Offset), KM_IRQ1);
}
local_irq_restore(flags);
@@ -346,7 +349,7 @@ static int netvsc_probe(struct device *device)
struct netvsc_device_info device_info;
int ret;
- if (!net_drv_obj->Base.OnDeviceAdd)
+ if (!net_drv_obj->base.OnDeviceAdd)
return -1;
net = alloc_etherdev(sizeof(struct net_device_context));
@@ -363,7 +366,7 @@ static int netvsc_probe(struct device *device)
dev_set_drvdata(device, net);
/* Notify the netvsc driver of the new device */
- ret = net_drv_obj->Base.OnDeviceAdd(device_obj, &device_info);
+ ret = net_drv_obj->base.OnDeviceAdd(device_obj, &device_info);
if (ret != 0) {
free_netdev(net);
dev_set_drvdata(device, NULL);
@@ -382,10 +385,10 @@ static int netvsc_probe(struct device *device)
* out of sync with the device's link status
*/
if (!netif_carrier_ok(net))
- if (!device_info.LinkState)
+ if (!device_info.link_state)
netif_carrier_on(net);
- memcpy(net->dev_addr, device_info.MacAddr, ETH_ALEN);
+ memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
net->netdev_ops = &device_ops;
@@ -398,7 +401,7 @@ static int netvsc_probe(struct device *device)
ret = register_netdev(net);
if (ret != 0) {
/* Remove the device and release the resource */
- net_drv_obj->Base.OnDeviceRemove(device_obj);
+ net_drv_obj->base.OnDeviceRemove(device_obj);
free_netdev(net);
}
@@ -422,7 +425,7 @@ static int netvsc_remove(struct device *device)
return 0;
}
- if (!net_drv_obj->Base.OnDeviceRemove)
+ if (!net_drv_obj->base.OnDeviceRemove)
return -1;
/* Stop outbound asap */
@@ -435,7 +438,7 @@ static int netvsc_remove(struct device *device)
* Call to the vsc driver to let it know that the device is being
* removed
*/
- ret = net_drv_obj->Base.OnDeviceRemove(device_obj);
+ ret = net_drv_obj->base.OnDeviceRemove(device_obj);
if (ret != 0) {
/* TODO: */
DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret);
@@ -481,8 +484,8 @@ static void netvsc_drv_exit(void)
device_unregister(current_dev);
}
- if (netvsc_drv_obj->Base.OnCleanup)
- netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base);
+ if (netvsc_drv_obj->base.OnCleanup)
+ netvsc_drv_obj->base.OnCleanup(&netvsc_drv_obj->base);
vmbus_child_driver_unregister(drv_ctx);
@@ -495,15 +498,15 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx;
int ret;
- net_drv_obj->RingBufferSize = ring_size * PAGE_SIZE;
- net_drv_obj->OnReceiveCallback = netvsc_recv_callback;
- net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback;
+ net_drv_obj->ring_buf_size = ring_size * PAGE_SIZE;
+ net_drv_obj->recv_cb = netvsc_recv_callback;
+ net_drv_obj->link_status_change = netvsc_linkstatus_callback;
/* Callback to client driver to complete the initialization */
- drv_init(&net_drv_obj->Base);
+ drv_init(&net_drv_obj->base);
- drv_ctx->driver.name = net_drv_obj->Base.name;
- memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType,
+ drv_ctx->driver.name = net_drv_obj->base.name;
+ memcpy(&drv_ctx->class_id, &net_drv_obj->base.deviceType,
sizeof(struct hv_guid));
drv_ctx->probe = netvsc_probe;
@@ -536,7 +539,7 @@ static int __init netvsc_init(void)
if (!dmi_check_system(hv_netvsc_dmi_table))
return -ENODEV;
- return netvsc_drv_init(NetVscInitialize);
+ return netvsc_drv_init(netvsc_initialize);
}
static void __exit netvsc_exit(void)
diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c
index 8c3eb278a81f..b5a3940331b3 100644
--- a/drivers/staging/hv/osd.c
+++ b/drivers/staging/hv/osd.c
@@ -43,13 +43,7 @@
#include <linux/slab.h>
#include "osd.h"
-struct osd_callback_struct {
- struct work_struct work;
- void (*callback)(void *);
- void *data;
-};
-
-void *osd_VirtualAllocExec(unsigned int size)
+void *osd_virtual_alloc_exec(unsigned int size)
{
#ifdef __x86_64__
return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
@@ -60,7 +54,7 @@ void *osd_VirtualAllocExec(unsigned int size)
}
/**
- * osd_PageAlloc() - Allocate pages
+ * osd_page_alloc() - Allocate pages
* @count: Total number of Kernel pages you want to allocate
*
* Tries to allocate @count number of consecutive free kernel pages.
@@ -68,7 +62,7 @@ void *osd_VirtualAllocExec(unsigned int size)
* If successfull it will return pointer to the @count pages.
* Mainly used by Hyper-V drivers.
*/
-void *osd_PageAlloc(unsigned int count)
+void *osd_page_alloc(unsigned int count)
{
void *p;
@@ -85,26 +79,26 @@ void *osd_PageAlloc(unsigned int count)
/* if (p) memset(p, 0, PAGE_SIZE); */
/* return p; */
}
-EXPORT_SYMBOL_GPL(osd_PageAlloc);
+EXPORT_SYMBOL_GPL(osd_page_alloc);
/**
- * osd_PageFree() - Free pages
+ * osd_page_free() - Free pages
* @page: Pointer to the first page to be freed
* @count: Total number of Kernel pages you free
*
- * Frees the pages allocated by osd_PageAlloc()
+ * Frees the pages allocated by osd_page_alloc()
* Mainly used by Hyper-V drivers.
*/
-void osd_PageFree(void *page, unsigned int count)
+void osd_page_free(void *page, unsigned int count)
{
free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
/*struct page* p = virt_to_page(page);
__free_page(p);*/
}
-EXPORT_SYMBOL_GPL(osd_PageFree);
+EXPORT_SYMBOL_GPL(osd_page_free);
/**
- * osd_WaitEventCreate() - Create the event queue
+ * osd_waitevent_create() - Create the event queue
*
* Allocates memory for a &struct osd_waitevent. And then calls
* init_waitqueue_head to set up the wait queue for the event.
@@ -114,7 +108,7 @@ EXPORT_SYMBOL_GPL(osd_PageFree);
* Returns pointer to &struct osd_waitevent
* Mainly used by Hyper-V drivers.
*/
-struct osd_waitevent *osd_WaitEventCreate(void)
+struct osd_waitevent *osd_waitevent_create(void)
{
struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent),
GFP_KERNEL);
@@ -125,14 +119,14 @@ struct osd_waitevent *osd_WaitEventCreate(void)
init_waitqueue_head(&wait->event);
return wait;
}
-EXPORT_SYMBOL_GPL(osd_WaitEventCreate);
+EXPORT_SYMBOL_GPL(osd_waitevent_create);
/**
- * osd_WaitEventSet() - Wake up the process
- * @waitEvent: Structure to event to be woken up
+ * osd_waitevent_set() - Wake up the process
+ * @wait_event: Structure to event to be woken up
*
- * @waitevent is of type &struct osd_waitevent
+ * @wait_event is of type &struct osd_waitevent
*
* Wake up the sleeping process so it can do some work.
* And set condition indicator in &struct osd_waitevent to indicate
@@ -140,18 +134,18 @@ EXPORT_SYMBOL_GPL(osd_WaitEventCreate);
*
* Only used by Network and Storage Hyper-V drivers.
*/
-void osd_WaitEventSet(struct osd_waitevent *waitEvent)
+void osd_waitevent_set(struct osd_waitevent *wait_event)
{
- waitEvent->condition = 1;
- wake_up_interruptible(&waitEvent->event);
+ wait_event->condition = 1;
+ wake_up_interruptible(&wait_event->event);
}
-EXPORT_SYMBOL_GPL(osd_WaitEventSet);
+EXPORT_SYMBOL_GPL(osd_waitevent_set);
/**
- * osd_WaitEventWait() - Wait for event till condition is true
- * @waitEvent: Structure to event to be put to sleep
+ * osd_waitevent_wait() - Wait for event till condition is true
+ * @wait_event: Structure to event to be put to sleep
*
- * @waitevent is of type &struct osd_waitevent
+ * @wait_event is of type &struct osd_waitevent
*
* Set up the process to sleep until waitEvent->condition get true.
* And set condition indicator in &struct osd_waitevent to indicate
@@ -161,25 +155,25 @@ EXPORT_SYMBOL_GPL(osd_WaitEventSet);
*
* Mainly used by Hyper-V drivers.
*/
-int osd_WaitEventWait(struct osd_waitevent *waitEvent)
+int osd_waitevent_wait(struct osd_waitevent *wait_event)
{
int ret = 0;
- ret = wait_event_interruptible(waitEvent->event,
- waitEvent->condition);
- waitEvent->condition = 0;
+ ret = wait_event_interruptible(wait_event->event,
+ wait_event->condition);
+ wait_event->condition = 0;
return ret;
}
-EXPORT_SYMBOL_GPL(osd_WaitEventWait);
+EXPORT_SYMBOL_GPL(osd_waitevent_wait);
/**
- * osd_WaitEventWaitEx() - Wait for event or timeout for process wakeup
- * @waitEvent: Structure to event to be put to sleep
- * @TimeoutInMs: Total number of Milliseconds to wait before waking up
+ * osd_waitevent_waitex() - Wait for event or timeout for process wakeup
+ * @wait_event: Structure to event to be put to sleep
+ * @timeout_in_ms: Total number of Milliseconds to wait before waking up
*
- * @waitevent is of type &struct osd_waitevent
+ * @wait_event is of type &struct osd_waitevent
* Set up the process to sleep until @waitEvent->condition get true or
- * @TimeoutInMs (Time out in Milliseconds) has been reached.
+ * @timeout_in_ms (Time out in Milliseconds) has been reached.
* And set condition indicator in &struct osd_waitevent to indicate
* the process is in a sleeping state.
*
@@ -187,42 +181,14 @@ EXPORT_SYMBOL_GPL(osd_WaitEventWait);
*
* Mainly used by Hyper-V drivers.
*/
-int osd_WaitEventWaitEx(struct osd_waitevent *waitEvent, u32 TimeoutInMs)
+int osd_waitevent_waitex(struct osd_waitevent *wait_event, u32 timeout_in_ms)
{
int ret = 0;
- ret = wait_event_interruptible_timeout(waitEvent->event,
- waitEvent->condition,
- msecs_to_jiffies(TimeoutInMs));
- waitEvent->condition = 0;
+ ret = wait_event_interruptible_timeout(wait_event->event,
+ wait_event->condition,
+ msecs_to_jiffies(timeout_in_ms));
+ wait_event->condition = 0;
return ret;
}
-EXPORT_SYMBOL_GPL(osd_WaitEventWaitEx);
-
-static void osd_callback_work(struct work_struct *work)
-{
- struct osd_callback_struct *cb = container_of(work,
- struct osd_callback_struct,
- work);
- (cb->callback)(cb->data);
- kfree(cb);
-}
-
-int osd_schedule_callback(struct workqueue_struct *wq,
- void (*func)(void *),
- void *data)
-{
- struct osd_callback_struct *cb;
-
- cb = kmalloc(sizeof(*cb), GFP_KERNEL);
- if (!cb) {
- printk(KERN_ERR "unable to allocate memory in osd_schedule_callback\n");
- return -1;
- }
-
- cb->callback = func;
- cb->data = data;
- INIT_WORK(&cb->work, osd_callback_work);
- return queue_work(wq, &cb->work);
-}
-
+EXPORT_SYMBOL_GPL(osd_waitevent_waitex);
diff --git a/drivers/staging/hv/osd.h b/drivers/staging/hv/osd.h
index ce064e8ea644..870ef0768833 100644
--- a/drivers/staging/hv/osd.h
+++ b/drivers/staging/hv/osd.h
@@ -50,21 +50,17 @@ struct osd_waitevent {
/* Osd routines */
-extern void *osd_VirtualAllocExec(unsigned int size);
+extern void *osd_virtual_alloc_exec(unsigned int size);
-extern void *osd_PageAlloc(unsigned int count);
-extern void osd_PageFree(void *page, unsigned int count);
+extern void *osd_page_alloc(unsigned int count);
+extern void osd_page_free(void *page, unsigned int count);
-extern struct osd_waitevent *osd_WaitEventCreate(void);
-extern void osd_WaitEventSet(struct osd_waitevent *waitEvent);
-extern int osd_WaitEventWait(struct osd_waitevent *waitEvent);
+extern struct osd_waitevent *osd_waitevent_create(void);
+extern void osd_waitevent_set(struct osd_waitevent *wait_event);
+extern int osd_waitevent_wait(struct osd_waitevent *wait_event);
-/* If >0, waitEvent got signaled. If ==0, timeout. If < 0, error */
-extern int osd_WaitEventWaitEx(struct osd_waitevent *waitEvent,
- u32 TimeoutInMs);
-
-int osd_schedule_callback(struct workqueue_struct *wq,
- void (*func)(void *),
- void *data);
+/* If >0, wait_event got signaled. If ==0, timeout. If < 0, error */
+extern int osd_waitevent_waitex(struct osd_waitevent *wait_event,
+ u32 timeout_in_ms);
#endif /* _OSD_H_ */
diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c
index d78c569ac94a..4d53392f1e60 100644
--- a/drivers/staging/hv/ring_buffer.c
+++ b/drivers/staging/hv/ring_buffer.c
@@ -38,7 +38,7 @@
/*++
Name:
- GetRingBufferAvailBytes()
+ get_ringbuffer_availbytes()
Description:
Get number of bytes available to read and to write to
@@ -46,33 +46,34 @@ Description:
--*/
static inline void
-GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
+get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
+ u32 *read, u32 *write)
{
u32 read_loc, write_loc;
/* Capture the read/write indices before they changed */
- read_loc = rbi->RingBuffer->ReadIndex;
- write_loc = rbi->RingBuffer->WriteIndex;
+ read_loc = rbi->ring_buffer->read_index;
+ write_loc = rbi->ring_buffer->write_index;
- *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
- *read = rbi->RingDataSize - *write;
+ *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize);
+ *read = rbi->ring_datasize - *write;
}
/*++
Name:
- GetNextWriteLocation()
+ get_next_write_location()
Description:
Get the next write location for the specified ring buffer
--*/
static inline u32
-GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
+get_next_write_location(struct hv_ring_buffer_info *ring_info)
{
- u32 next = RingInfo->RingBuffer->WriteIndex;
+ u32 next = ring_info->ring_buffer->write_index;
- /* ASSERT(next < RingInfo->RingDataSize); */
+ /* ASSERT(next < ring_info->RingDataSize); */
return next;
}
@@ -80,34 +81,34 @@ GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
/*++
Name:
- SetNextWriteLocation()
+ set_next_write_location()
Description:
Set the next write location for the specified ring buffer
--*/
static inline void
-SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
- u32 NextWriteLocation)
+set_next_write_location(struct hv_ring_buffer_info *ring_info,
+ u32 next_write_location)
{
- RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
+ ring_info->ring_buffer->write_index = next_write_location;
}
/*++
Name:
- GetNextReadLocation()
+ get_next_read_location()
Description:
Get the next read location for the specified ring buffer
--*/
static inline u32
-GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
+get_next_read_location(struct hv_ring_buffer_info *ring_info)
{
- u32 next = RingInfo->RingBuffer->ReadIndex;
+ u32 next = ring_info->ring_buffer->read_index;
- /* ASSERT(next < RingInfo->RingDataSize); */
+ /* ASSERT(next < ring_info->RingDataSize); */
return next;
}
@@ -115,7 +116,7 @@ GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
/*++
Name:
- GetNextReadLocationWithOffset()
+ get_next_readlocation_withoffset()
Description:
Get the next read location + offset for the specified ring buffer.
@@ -123,13 +124,14 @@ Description:
--*/
static inline u32
-GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
+get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
+ u32 offset)
{
- u32 next = RingInfo->RingBuffer->ReadIndex;
+ u32 next = ring_info->ring_buffer->read_index;
- /* ASSERT(next < RingInfo->RingDataSize); */
- next += Offset;
- next %= RingInfo->RingDataSize;
+ /* ASSERT(next < ring_info->RingDataSize); */
+ next += offset;
+ next %= ring_info->ring_datasize;
return next;
}
@@ -137,141 +139,145 @@ GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
/*++
Name:
- SetNextReadLocation()
+ set_next_read_location()
Description:
Set the next read location for the specified ring buffer
--*/
static inline void
-SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
+set_next_read_location(struct hv_ring_buffer_info *ring_info,
+ u32 next_read_location)
{
- RingInfo->RingBuffer->ReadIndex = NextReadLocation;
+ ring_info->ring_buffer->read_index = next_read_location;
}
/*++
Name:
- GetRingBuffer()
+ get_ring_buffer()
Description:
Get the start of the ring buffer
--*/
static inline void *
-GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
+get_ring_buffer(struct hv_ring_buffer_info *ring_info)
{
- return (void *)RingInfo->RingBuffer->Buffer;
+ return (void *)ring_info->ring_buffer->buffer;
}
/*++
Name:
- GetRingBufferSize()
+ get_ring_buffersize()
Description:
Get the size of the ring buffer
--*/
static inline u32
-GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
+get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
{
- return RingInfo->RingDataSize;
+ return ring_info->ring_datasize;
}
/*++
Name:
- GetRingBufferIndices()
+ get_ring_bufferindices()
Description:
Get the read and write indices as u64 of the specified ring buffer
--*/
static inline u64
-GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
+get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
{
- return (u64)RingInfo->RingBuffer->WriteIndex << 32;
+ return (u64)ring_info->ring_buffer->write_index << 32;
}
/*++
Name:
- DumpRingInfo()
+ dump_ring_info()
Description:
Dump out to console the ring buffer info
--*/
-void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
+void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix)
{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
+ u32 bytes_avail_towrite;
+ u32 bytes_avail_toread;
- GetRingBufferAvailBytes(RingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
+ get_ringbuffer_availbytes(ring_info,
+ &bytes_avail_toread,
+ &bytes_avail_towrite);
DPRINT(VMBUS,
DEBUG_RING_LVL,
"%s <<ringinfo %p buffer %p avail write %u "
"avail read %u read idx %u write idx %u>>",
- Prefix,
- RingInfo,
- RingInfo->RingBuffer->Buffer,
- bytesAvailToWrite,
- bytesAvailToRead,
- RingInfo->RingBuffer->ReadIndex,
- RingInfo->RingBuffer->WriteIndex);
+ prefix,
+ ring_info,
+ ring_info->ring_buffer->buffer,
+ bytes_avail_towrite,
+ bytes_avail_toread,
+ ring_info->ring_buffer->read_index,
+ ring_info->ring_buffer->write_index);
}
/* Internal routines */
static u32
-CopyToRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- u32 StartWriteOffset,
- void *Src,
- u32 SrcLen);
+copyto_ringbuffer(
+ struct hv_ring_buffer_info *ring_info,
+ u32 start_write_offset,
+ void *src,
+ u32 srclen);
static u32
-CopyFromRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- void *Dest,
- u32 DestLen,
- u32 StartReadOffset);
+copyfrom_ringbuffer(
+ struct hv_ring_buffer_info *ring_info,
+ void *dest,
+ u32 destlen,
+ u32 start_read_offset);
/*++
Name:
- RingBufferGetDebugInfo()
+ ringbuffer_get_debuginfo()
Description:
Get various debug metrics for the specified ring buffer
--*/
-void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info)
{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
-
- if (RingInfo->RingBuffer) {
- GetRingBufferAvailBytes(RingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
-
- debug_info->BytesAvailToRead = bytesAvailToRead;
- debug_info->BytesAvailToWrite = bytesAvailToWrite;
- debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
- debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
- debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
+ u32 bytes_avail_towrite;
+ u32 bytes_avail_toread;
+
+ if (ring_info->ring_buffer) {
+ get_ringbuffer_availbytes(ring_info,
+ &bytes_avail_toread,
+ &bytes_avail_towrite);
+
+ debug_info->bytes_avail_toread = bytes_avail_toread;
+ debug_info->bytes_avail_towrite = bytes_avail_towrite;
+ debug_info->current_read_index =
+ ring_info->ring_buffer->read_index;
+ debug_info->current_write_index =
+ ring_info->ring_buffer->write_index;
+ debug_info->current_interrupt_mask =
+ ring_info->ring_buffer->interrupt_mask;
}
}
@@ -279,40 +285,42 @@ void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
/*++
Name:
- GetRingBufferInterruptMask()
+ get_ringbuffer_interrupt_mask()
Description:
Get the interrupt mask for the specified ring buffer
--*/
-u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
+u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi)
{
- return rbi->RingBuffer->InterruptMask;
+ return rbi->ring_buffer->interrupt_mask;
}
/*++
Name:
- RingBufferInit()
+ ringbuffer_init()
Description:
Initialize the ring buffer
--*/
-int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
+int ringbuffer_init(struct hv_ring_buffer_info *ring_info,
+ void *buffer, u32 buflen)
{
if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
return -EINVAL;
- memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
+ memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
- RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
- RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
+ ring_info->ring_buffer = (struct hv_ring_buffer *)buffer;
+ ring_info->ring_buffer->read_index =
+ ring_info->ring_buffer->write_index = 0;
- RingInfo->RingSize = BufferLen;
- RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
+ ring_info->ring_size = buflen;
+ ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
- spin_lock_init(&RingInfo->ring_lock);
+ spin_lock_init(&ring_info->ring_lock);
return 0;
}
@@ -320,97 +328,97 @@ int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 Buffe
/*++
Name:
- RingBufferCleanup()
+ ringbuffer_cleanup()
Description:
Cleanup the ring buffer
--*/
-void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
+void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{
}
/*++
Name:
- RingBufferWrite()
+ ringbuffer_write()
Description:
Write to the ring buffer
--*/
-int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
+int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct scatterlist *sglist, u32 sgcount)
{
int i = 0;
- u32 byteAvailToWrite;
- u32 byteAvailToRead;
- u32 totalBytesToWrite = 0;
+ u32 bytes_avail_towrite;
+ u32 bytes_avail_toread;
+ u32 totalbytes_towrite = 0;
struct scatterlist *sg;
- volatile u32 nextWriteLocation;
- u64 prevIndices = 0;
+ volatile u32 next_write_location;
+ u64 prev_indices = 0;
unsigned long flags;
for_each_sg(sglist, sg, sgcount, i)
{
- totalBytesToWrite += sg->length;
+ totalbytes_towrite += sg->length;
}
- totalBytesToWrite += sizeof(u64);
+ totalbytes_towrite += sizeof(u64);
- spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
+ spin_lock_irqsave(&outring_info->ring_lock, flags);
- GetRingBufferAvailBytes(OutRingInfo,
- &byteAvailToRead,
- &byteAvailToWrite);
+ get_ringbuffer_availbytes(outring_info,
+ &bytes_avail_toread,
+ &bytes_avail_towrite);
- DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
+ DPRINT_DBG(VMBUS, "Writing %u bytes...", totalbytes_towrite);
- /* DumpRingInfo(OutRingInfo, "BEFORE "); */
+ /* Dumpring_info(Outring_info, "BEFORE "); */
/* If there is only room for the packet, assume it is full. */
/* Otherwise, the next time around, we think the ring buffer */
/* is empty since the read index == write index */
- if (byteAvailToWrite <= totalBytesToWrite) {
+ if (bytes_avail_towrite <= totalbytes_towrite) {
DPRINT_DBG(VMBUS,
"No more space left on outbound ring buffer "
"(needed %u, avail %u)",
- totalBytesToWrite,
- byteAvailToWrite);
+ totalbytes_towrite,
+ bytes_avail_towrite);
- spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return -1;
}
/* Write to the ring buffer */
- nextWriteLocation = GetNextWriteLocation(OutRingInfo);
+ next_write_location = get_next_write_location(outring_info);
for_each_sg(sglist, sg, sgcount, i)
{
- nextWriteLocation = CopyToRingBuffer(OutRingInfo,
- nextWriteLocation,
+ next_write_location = copyto_ringbuffer(outring_info,
+ next_write_location,
sg_virt(sg),
sg->length);
}
/* Set previous packet start */
- prevIndices = GetRingBufferIndices(OutRingInfo);
+ prev_indices = get_ring_bufferindices(outring_info);
- nextWriteLocation = CopyToRingBuffer(OutRingInfo,
- nextWriteLocation,
- &prevIndices,
+ next_write_location = copyto_ringbuffer(outring_info,
+ next_write_location,
+ &prev_indices,
sizeof(u64));
/* Make sure we flush all writes before updating the writeIndex */
mb();
/* Now, update the write location */
- SetNextWriteLocation(OutRingInfo, nextWriteLocation);
+ set_next_write_location(outring_info, next_write_location);
- /* DumpRingInfo(OutRingInfo, "AFTER "); */
+ /* Dumpring_info(Outring_info, "AFTER "); */
- spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return 0;
}
@@ -418,47 +426,48 @@ int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
/*++
Name:
- RingBufferPeek()
+ ringbuffer_peek()
Description:
Read without advancing the read index
--*/
-int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
+int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
+ void *Buffer, u32 buflen)
{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
- u32 nextReadLocation = 0;
+ u32 bytes_avail_towrite;
+ u32 bytes_avail_toread;
+ u32 next_read_location = 0;
unsigned long flags;
- spin_lock_irqsave(&InRingInfo->ring_lock, flags);
+ spin_lock_irqsave(&Inring_info->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
+ get_ringbuffer_availbytes(Inring_info,
+ &bytes_avail_toread,
+ &bytes_avail_towrite);
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen) {
+ if (bytes_avail_toread < buflen) {
/* DPRINT_DBG(VMBUS,
"got callback but not enough to read "
"<avail to read %d read size %d>!!",
- bytesAvailToRead,
+ bytes_avail_toread,
BufferLen); */
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
return -1;
}
/* Convert to byte offset */
- nextReadLocation = GetNextReadLocation(InRingInfo);
+ next_read_location = get_next_read_location(Inring_info);
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
+ next_read_location = copyfrom_ringbuffer(Inring_info,
Buffer,
- BufferLen,
- nextReadLocation);
+ buflen,
+ next_read_location);
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
return 0;
}
@@ -467,58 +476,59 @@ int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 Buf
/*++
Name:
- RingBufferRead()
+ ringbuffer_read()
Description:
Read and advance the read index
--*/
-int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
- u32 BufferLen, u32 Offset)
+int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
+ u32 buflen, u32 offset)
{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
- u32 nextReadLocation = 0;
- u64 prevIndices = 0;
+ u32 bytes_avail_towrite;
+ u32 bytes_avail_toread;
+ u32 next_read_location = 0;
+ u64 prev_indices = 0;
unsigned long flags;
- if (BufferLen <= 0)
+ if (buflen <= 0)
return -EINVAL;
- spin_lock_irqsave(&InRingInfo->ring_lock, flags);
+ spin_lock_irqsave(&inring_info->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
+ get_ringbuffer_availbytes(inring_info,
+ &bytes_avail_toread,
+ &bytes_avail_towrite);
- DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
+ DPRINT_DBG(VMBUS, "Reading %u bytes...", buflen);
- /* DumpRingInfo(InRingInfo, "BEFORE "); */
+ /* Dumpring_info(Inring_info, "BEFORE "); */
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen) {
+ if (bytes_avail_toread < buflen) {
DPRINT_DBG(VMBUS,
"got callback but not enough to read "
"<avail to read %d read size %d>!!",
- bytesAvailToRead,
- BufferLen);
+ bytes_avail_toread,
+ buflen);
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return -1;
}
- nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
+ next_read_location =
+ get_next_readlocation_withoffset(inring_info, offset);
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
+ next_read_location = copyfrom_ringbuffer(inring_info,
+ buffer,
+ buflen,
+ next_read_location);
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
- &prevIndices,
+ next_read_location = copyfrom_ringbuffer(inring_info,
+ &prev_indices,
sizeof(u64),
- nextReadLocation);
+ next_read_location);
/* Make sure all reads are done before we update the read index since */
/* the writer may start writing to the read area once the read index */
@@ -526,11 +536,11 @@ int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
mb();
/* Update the read index */
- SetNextReadLocation(InRingInfo, nextReadLocation);
+ set_next_read_location(inring_info, next_read_location);
- /* DumpRingInfo(InRingInfo, "AFTER "); */
+ /* Dumpring_info(Inring_info, "AFTER "); */
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
+ spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return 0;
}
@@ -539,7 +549,7 @@ int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
/*++
Name:
- CopyToRingBuffer()
+ copyto_ringbuffer()
Description:
Helper routine to copy from source to ring buffer.
@@ -547,37 +557,37 @@ Description:
--*/
static u32
-CopyToRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- u32 StartWriteOffset,
- void *Src,
- u32 SrcLen)
+copyto_ringbuffer(
+ struct hv_ring_buffer_info *ring_info,
+ u32 start_write_offset,
+ void *src,
+ u32 srclen)
{
- void *ringBuffer = GetRingBuffer(RingInfo);
- u32 ringBufferSize = GetRingBufferSize(RingInfo);
- u32 fragLen;
+ void *ring_buffer = get_ring_buffer(ring_info);
+ u32 ring_buffer_size = get_ring_buffersize(ring_info);
+ u32 frag_len;
/* wrap-around detected! */
- if (SrcLen > ringBufferSize - StartWriteOffset) {
+ if (srclen > ring_buffer_size - start_write_offset) {
DPRINT_DBG(VMBUS, "wrap-around detected!");
- fragLen = ringBufferSize - StartWriteOffset;
- memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
- memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
+ frag_len = ring_buffer_size - start_write_offset;
+ memcpy(ring_buffer + start_write_offset, src, frag_len);
+ memcpy(ring_buffer, src + frag_len, srclen - frag_len);
} else
- memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
+ memcpy(ring_buffer + start_write_offset, src, srclen);
- StartWriteOffset += SrcLen;
- StartWriteOffset %= ringBufferSize;
+ start_write_offset += srclen;
+ start_write_offset %= ring_buffer_size;
- return StartWriteOffset;
+ return start_write_offset;
}
/*++
Name:
- CopyFromRingBuffer()
+ copyfrom_ringbuffer()
Description:
Helper routine to copy to source from ring buffer.
@@ -585,34 +595,34 @@ Description:
--*/
static u32
-CopyFromRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- void *Dest,
- u32 DestLen,
- u32 StartReadOffset)
+copyfrom_ringbuffer(
+ struct hv_ring_buffer_info *ring_info,
+ void *dest,
+ u32 destlen,
+ u32 start_read_offset)
{
- void *ringBuffer = GetRingBuffer(RingInfo);
- u32 ringBufferSize = GetRingBufferSize(RingInfo);
+ void *ring_buffer = get_ring_buffer(ring_info);
+ u32 ring_buffer_size = get_ring_buffersize(ring_info);
- u32 fragLen;
+ u32 frag_len;
/* wrap-around detected at the src */
- if (DestLen > ringBufferSize - StartReadOffset) {
+ if (destlen > ring_buffer_size - start_read_offset) {
DPRINT_DBG(VMBUS, "src wrap-around detected!");
- fragLen = ringBufferSize - StartReadOffset;
+ frag_len = ring_buffer_size - start_read_offset;
- memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
- memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
+ memcpy(dest, ring_buffer + start_read_offset, frag_len);
+ memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
} else
- memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
+ memcpy(dest, ring_buffer + start_read_offset, destlen);
- StartReadOffset += DestLen;
- StartReadOffset %= ringBufferSize;
+ start_read_offset += destlen;
+ start_read_offset %= ring_buffer_size;
- return StartReadOffset;
+ return start_read_offset;
}
diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h
index a7f1717c6a56..7bd6ecf2f015 100644
--- a/drivers/staging/hv/ring_buffer.h
+++ b/drivers/staging/hv/ring_buffer.h
@@ -29,18 +29,18 @@
struct hv_ring_buffer {
/* Offset in bytes from the start of ring data below */
- volatile u32 WriteIndex;
+ volatile u32 write_index;
/* Offset in bytes from the start of ring data below */
- volatile u32 ReadIndex;
+ volatile u32 read_index;
- volatile u32 InterruptMask;
+ volatile u32 interrupt_mask;
/* Pad it to PAGE_SIZE so that data starts on page boundary */
- u8 Reserved[4084];
+ u8 reserved[4084];
/* NOTE:
- * The InterruptMask field is used only for channels but since our
+ * The interrupt_mask field is used only for channels but since our
* vmbus connection also uses this data structure and its data starts
* here, we commented out this field.
*/
@@ -50,24 +50,24 @@ struct hv_ring_buffer {
* Ring data starts here + RingDataStartOffset
* !!! DO NOT place any fields below this !!!
*/
- u8 Buffer[0];
+ u8 buffer[0];
} __attribute__((packed));
struct hv_ring_buffer_info {
- struct hv_ring_buffer *RingBuffer;
- u32 RingSize; /* Include the shared header */
+ struct hv_ring_buffer *ring_buffer;
+ u32 ring_size; /* Include the shared header */
spinlock_t ring_lock;
- u32 RingDataSize; /* < ringSize */
- u32 RingDataStartOffset;
+ u32 ring_datasize; /* < ring_size */
+ u32 ring_data_startoffset;
};
struct hv_ring_buffer_debug_info {
- u32 CurrentInterruptMask;
- u32 CurrentReadIndex;
- u32 CurrentWriteIndex;
- u32 BytesAvailToRead;
- u32 BytesAvailToWrite;
+ u32 current_interrupt_mask;
+ u32 current_read_index;
+ u32 current_write_index;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
};
@@ -75,28 +75,28 @@ struct hv_ring_buffer_debug_info {
/* Interface */
-int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer,
- u32 BufferLen);
+int ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
-void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo);
+void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
-int RingBufferWrite(struct hv_ring_buffer_info *RingInfo,
+int ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct scatterlist *sglist,
u32 sgcount);
-int RingBufferPeek(struct hv_ring_buffer_info *RingInfo, void *Buffer,
- u32 BufferLen);
+int ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
-int RingBufferRead(struct hv_ring_buffer_info *RingInfo,
- void *Buffer,
- u32 BufferLen,
- u32 Offset);
+int ringbuffer_read(struct hv_ring_buffer_info *ring_info,
+ void *buffer,
+ u32 buflen,
+ u32 offset);
-u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *RingInfo);
+u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info);
-void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix);
+void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix);
-void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info);
#endif /* _RING_BUFFER_H_ */
diff --git a/drivers/staging/hv/rndis.h b/drivers/staging/hv/rndis.h
index 723e1f15b90d..014de047b86d 100644
--- a/drivers/staging/hv/rndis.h
+++ b/drivers/staging/hv/rndis.h
@@ -288,24 +288,24 @@
#define RNDIS_DF_RAW_DATA 0x00000004
/* Remote NDIS medium types. */
-#define RNdisMedium802_3 0x00000000
-#define RNdisMedium802_5 0x00000001
-#define RNdisMediumFddi 0x00000002
-#define RNdisMediumWan 0x00000003
-#define RNdisMediumLocalTalk 0x00000004
-#define RNdisMediumArcnetRaw 0x00000006
-#define RNdisMediumArcnet878_2 0x00000007
-#define RNdisMediumAtm 0x00000008
-#define RNdisMediumWirelessWan 0x00000009
-#define RNdisMediumIrda 0x0000000a
-#define RNdisMediumCoWan 0x0000000b
+#define RNDIS_MEDIUM_802_3 0x00000000
+#define RNDIS_MEDIUM_802_5 0x00000001
+#define RNDIS_MEDIUM_FDDI 0x00000002
+#define RNDIS_MEDIUM_WAN 0x00000003
+#define RNDIS_MEDIUM_LOCAL_TALK 0x00000004
+#define RNDIS_MEDIUM_ARCNET_RAW 0x00000006
+#define RNDIS_MEDIUM_ARCNET_878_2 0x00000007
+#define RNDIS_MEDIUM_ATM 0x00000008
+#define RNDIS_MEDIUM_WIRELESS_WAN 0x00000009
+#define RNDIS_MEDIUM_IRDA 0x0000000a
+#define RNDIS_MEDIUM_CO_WAN 0x0000000b
/* Not a real medium, defined as an upper-bound */
-#define RNdisMediumMax 0x0000000d
+#define RNDIS_MEDIUM_MAX 0x0000000d
/* Remote NDIS medium connection states. */
-#define RNdisMediaStateConnected 0x00000000
-#define RNdisMediaStateDisconnected 0x00000001
+#define RNDIS_MEDIA_STATE_CONNECTED 0x00000000
+#define RNDIS_MEDIA_STATE_DISCONNECTED 0x00000001
/* Remote NDIS version numbers */
#define RNDIS_MAJOR_VERSION 0x00000001
@@ -314,106 +314,106 @@
/* NdisInitialize message */
struct rndis_initialize_request {
- u32 RequestId;
- u32 MajorVersion;
- u32 MinorVersion;
- u32 MaxTransferSize;
+ u32 req_id;
+ u32 major_ver;
+ u32 minor_ver;
+ u32 max_xfer_size;
};
/* Response to NdisInitialize */
struct rndis_initialize_complete {
- u32 RequestId;
- u32 Status;
- u32 MajorVersion;
- u32 MinorVersion;
- u32 DeviceFlags;
- u32 Medium;
- u32 MaxPacketsPerMessage;
- u32 MaxTransferSize;
- u32 PacketAlignmentFactor;
- u32 AFListOffset;
- u32 AFListSize;
+ u32 req_id;
+ u32 status;
+ u32 major_ver;
+ u32 minor_ver;
+ u32 dev_flags;
+ u32 medium;
+ u32 max_pkt_per_msg;
+ u32 max_xfer_size;
+ u32 pkt_alignment_factor;
+ u32 af_list_offset;
+ u32 af_list_size;
};
/* Call manager devices only: Information about an address family */
/* supported by the device is appended to the response to NdisInitialize. */
struct rndis_co_address_family {
- u32 AddressFamily;
- u32 MajorVersion;
- u32 MinorVersion;
+ u32 address_family;
+ u32 major_ver;
+ u32 minor_ver;
};
/* NdisHalt message */
struct rndis_halt_request {
- u32 RequestId;
+ u32 req_id;
};
/* NdisQueryRequest message */
struct rndis_query_request {
- u32 RequestId;
- u32 Oid;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 oid;
+ u32 info_buflen;
+ u32 info_buf_offset;
+ u32 dev_vc_handle;
};
/* Response to NdisQueryRequest */
struct rndis_query_complete {
- u32 RequestId;
- u32 Status;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ u32 req_id;
+ u32 status;
+ u32 info_buflen;
+ u32 info_buf_offset;
};
/* NdisSetRequest message */
struct rndis_set_request {
- u32 RequestId;
- u32 Oid;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 oid;
+ u32 info_buflen;
+ u32 info_buf_offset;
+ u32 dev_vc_handle;
};
/* Response to NdisSetRequest */
struct rndis_set_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* NdisReset message */
struct rndis_reset_request {
- u32 Reserved;
+ u32 reserved;
};
/* Response to NdisReset */
struct rndis_reset_complete {
- u32 Status;
- u32 AddressingReset;
+ u32 status;
+ u32 addressing_reset;
};
/* NdisMIndicateStatus message */
struct rndis_indicate_status {
- u32 Status;
- u32 StatusBufferLength;
- u32 StatusBufferOffset;
+ u32 status;
+ u32 status_buflen;
+ u32 status_buf_offset;
};
/* Diagnostic information passed as the status buffer in */
/* struct rndis_indicate_status messages signifying error conditions. */
struct rndis_diagnostic_info {
- u32 DiagStatus;
- u32 ErrorOffset;
+ u32 diag_status;
+ u32 error_offset;
};
/* NdisKeepAlive message */
struct rndis_keepalive_request {
- u32 RequestId;
+ u32 req_id;
};
/* Response to NdisKeepAlive */
struct rndis_keepalive_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/*
@@ -422,39 +422,39 @@ struct rndis_keepalive_complete {
* to 0 for connectionless data, otherwise it contains the VC handle.
*/
struct rndis_packet {
- u32 DataOffset;
- u32 DataLength;
- u32 OOBDataOffset;
- u32 OOBDataLength;
- u32 NumOOBDataElements;
- u32 PerPacketInfoOffset;
- u32 PerPacketInfoLength;
- u32 VcHandle;
- u32 Reserved;
+ u32 data_offset;
+ u32 data_len;
+ u32 oob_data_offset;
+ u32 oob_data_len;
+ u32 num_oob_data_elements;
+ u32 per_pkt_info_offset;
+ u32 per_pkt_info_len;
+ u32 vc_handle;
+ u32 reserved;
};
/* Optional Out of Band data associated with a Data message. */
struct rndis_oobd {
- u32 Size;
- u32 Type;
- u32 ClassInformationOffset;
+ u32 size;
+ u32 type;
+ u32 class_info_offset;
};
/* Packet extension field contents associated with a Data message. */
struct rndis_per_packet_info {
- u32 Size;
- u32 Type;
- u32 PerPacketInformationOffset;
+ u32 size;
+ u32 type;
+ u32 per_pkt_info_offset;
};
/* Format of Information buffer passed in a SetRequest for the OID */
/* OID_GEN_RNDIS_CONFIG_PARAMETER. */
struct rndis_config_parameter_info {
- u32 ParameterNameOffset;
- u32 ParameterNameLength;
- u32 ParameterType;
- u32 ParameterValueOffset;
- u32 ParameterValueLength;
+ u32 parameter_name_offset;
+ u32 parameter_name_length;
+ u32 parameter_type;
+ u32 parameter_value_offset;
+ u32 parameter_value_length;
};
/* Values for ParameterType in struct rndis_config_parameter_info */
@@ -466,187 +466,188 @@ struct rndis_config_parameter_info {
/* CoNdisMiniportCreateVc message */
struct rcondis_mp_create_vc {
- u32 RequestId;
- u32 NdisVcHandle;
+ u32 req_id;
+ u32 ndis_vc_handle;
};
/* Response to CoNdisMiniportCreateVc */
struct rcondis_mp_create_vc_complete {
- u32 RequestId;
- u32 DeviceVcHandle;
- u32 Status;
+ u32 req_id;
+ u32 dev_vc_handle;
+ u32 status;
};
/* CoNdisMiniportDeleteVc message */
struct rcondis_mp_delete_vc {
- u32 RequestId;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 dev_vc_handle;
};
/* Response to CoNdisMiniportDeleteVc */
struct rcondis_mp_delete_vc_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* CoNdisMiniportQueryRequest message */
struct rcondis_mp_query_request {
- u32 RequestId;
- u32 RequestType;
- u32 Oid;
- u32 DeviceVcHandle;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ u32 req_id;
+ u32 request_type;
+ u32 oid;
+ u32 dev_vc_handle;
+ u32 info_buflen;
+ u32 info_buf_offset;
};
/* CoNdisMiniportSetRequest message */
struct rcondis_mp_set_request {
- u32 RequestId;
- u32 RequestType;
- u32 Oid;
- u32 DeviceVcHandle;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ u32 req_id;
+ u32 request_type;
+ u32 oid;
+ u32 dev_vc_handle;
+ u32 info_buflen;
+ u32 info_buf_offset;
};
/* CoNdisIndicateStatus message */
struct rcondis_indicate_status {
- u32 NdisVcHandle;
- u32 Status;
- u32 StatusBufferLength;
- u32 StatusBufferOffset;
+ u32 ndis_vc_handle;
+ u32 status;
+ u32 status_buflen;
+ u32 status_buf_offset;
};
/* CONDIS Call/VC parameters */
struct rcondis_specific_parameters {
- u32 ParameterType;
- u32 ParameterLength;
- u32 ParameterOffset;
+ u32 parameter_type;
+ u32 parameter_length;
+ u32 parameter_lffset;
};
struct rcondis_media_parameters {
- u32 Flags;
- u32 Reserved1;
- u32 Reserved2;
- struct rcondis_specific_parameters MediaSpecific;
+ u32 flags;
+ u32 reserved1;
+ u32 reserved2;
+ struct rcondis_specific_parameters media_specific;
};
struct rndis_flowspec {
- u32 TokenRate;
- u32 TokenBucketSize;
- u32 PeakBandwidth;
- u32 Latency;
- u32 DelayVariation;
- u32 ServiceType;
- u32 MaxSduSize;
- u32 MinimumPolicedSize;
+ u32 token_rate;
+ u32 token_bucket_size;
+ u32 peak_bandwidth;
+ u32 latency;
+ u32 delay_variation;
+ u32 service_type;
+ u32 max_sdu_size;
+ u32 minimum_policed_size;
};
struct rcondis_call_manager_parameters {
- struct rndis_flowspec Transmit;
- struct rndis_flowspec Receive;
- struct rcondis_specific_parameters CallMgrSpecific;
+ struct rndis_flowspec transmit;
+ struct rndis_flowspec receive;
+ struct rcondis_specific_parameters call_mgr_specific;
};
/* CoNdisMiniportActivateVc message */
struct rcondis_mp_activate_vc_request {
- u32 RequestId;
- u32 Flags;
- u32 DeviceVcHandle;
- u32 MediaParamsOffset;
- u32 MediaParamsLength;
- u32 CallMgrParamsOffset;
- u32 CallMgrParamsLength;
+ u32 req_id;
+ u32 flags;
+ u32 dev_vc_handle;
+ u32 media_params_offset;
+ u32 media_params_length;
+ u32 call_mgr_params_offset;
+ u32 call_mgr_params_length;
};
/* Response to CoNdisMiniportActivateVc */
struct rcondis_mp_activate_vc_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* CoNdisMiniportDeactivateVc message */
struct rcondis_mp_deactivate_vc_request {
- u32 RequestId;
- u32 Flags;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 flags;
+ u32 dev_vc_handle;
};
/* Response to CoNdisMiniportDeactivateVc */
struct rcondis_mp_deactivate_vc_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* union with all of the RNDIS messages */
union rndis_message_container {
- struct rndis_packet Packet;
- struct rndis_initialize_request InitializeRequest;
- struct rndis_halt_request HaltRequest;
- struct rndis_query_request QueryRequest;
- struct rndis_set_request SetRequest;
- struct rndis_reset_request ResetRequest;
- struct rndis_keepalive_request KeepaliveRequest;
- struct rndis_indicate_status IndicateStatus;
- struct rndis_initialize_complete InitializeComplete;
- struct rndis_query_complete QueryComplete;
- struct rndis_set_complete SetComplete;
- struct rndis_reset_complete ResetComplete;
- struct rndis_keepalive_complete KeepaliveComplete;
- struct rcondis_mp_create_vc CoMiniportCreateVc;
- struct rcondis_mp_delete_vc CoMiniportDeleteVc;
- struct rcondis_indicate_status CoIndicateStatus;
- struct rcondis_mp_activate_vc_request CoMiniportActivateVc;
- struct rcondis_mp_deactivate_vc_request CoMiniportDeactivateVc;
- struct rcondis_mp_create_vc_complete CoMiniportCreateVcComplete;
- struct rcondis_mp_delete_vc_complete CoMiniportDeleteVcComplete;
- struct rcondis_mp_activate_vc_complete CoMiniportActivateVcComplete;
- struct rcondis_mp_deactivate_vc_complete CoMiniportDeactivateVcComplete;
+ struct rndis_packet pkt;
+ struct rndis_initialize_request init_req;
+ struct rndis_halt_request halt_req;
+ struct rndis_query_request query_req;
+ struct rndis_set_request set_req;
+ struct rndis_reset_request reset_req;
+ struct rndis_keepalive_request keep_alive_req;
+ struct rndis_indicate_status indicate_status;
+ struct rndis_initialize_complete init_complete;
+ struct rndis_query_complete query_complete;
+ struct rndis_set_complete set_complete;
+ struct rndis_reset_complete reset_complete;
+ struct rndis_keepalive_complete keep_alive_complete;
+ struct rcondis_mp_create_vc co_miniport_create_vc;
+ struct rcondis_mp_delete_vc co_miniport_delete_vc;
+ struct rcondis_indicate_status co_indicate_status;
+ struct rcondis_mp_activate_vc_request co_miniport_activate_vc;
+ struct rcondis_mp_deactivate_vc_request co_miniport_deactivate_vc;
+ struct rcondis_mp_create_vc_complete co_miniport_create_vc_complete;
+ struct rcondis_mp_delete_vc_complete co_miniport_delete_vc_complete;
+ struct rcondis_mp_activate_vc_complete co_miniport_activate_vc_complete;
+ struct rcondis_mp_deactivate_vc_complete
+ co_miniport_deactivate_vc_complete;
};
/* Remote NDIS message format */
struct rndis_message {
- u32 NdisMessageType;
+ u32 ndis_msg_type;
/* Total length of this message, from the beginning */
/* of the sruct rndis_message, in bytes. */
- u32 MessageLength;
+ u32 msg_len;
/* Actual message */
- union rndis_message_container Message;
+ union rndis_message_container msg;
};
/* Handy macros */
/* get the size of an RNDIS message. Pass in the message type, */
/* struct rndis_set_request, struct rndis_packet for example */
-#define RNDIS_MESSAGE_SIZE(Message) \
- (sizeof(Message) + (sizeof(struct rndis_message) - \
+#define RNDIS_MESSAGE_SIZE(msg) \
+ (sizeof(msg) + (sizeof(struct rndis_message) - \
sizeof(union rndis_message_container)))
/* get pointer to info buffer with message pointer */
-#define MESSAGE_TO_INFO_BUFFER(Message) \
- (((unsigned char *)(Message)) + Message->InformationBufferOffset)
+#define MESSAGE_TO_INFO_BUFFER(msg) \
+ (((unsigned char *)(msg)) + msg->info_buf_offset)
/* get pointer to status buffer with message pointer */
-#define MESSAGE_TO_STATUS_BUFFER(Message) \
- (((unsigned char *)(Message)) + Message->StatusBufferOffset)
+#define MESSAGE_TO_STATUS_BUFFER(msg) \
+ (((unsigned char *)(msg)) + msg->status_buf_offset)
/* get pointer to OOBD buffer with message pointer */
-#define MESSAGE_TO_OOBD_BUFFER(Message) \
- (((unsigned char *)(Message)) + Message->OOBDataOffset)
+#define MESSAGE_TO_OOBD_BUFFER(msg) \
+ (((unsigned char *)(msg)) + msg->oob_data_offset)
/* get pointer to data buffer with message pointer */
-#define MESSAGE_TO_DATA_BUFFER(Message) \
- (((unsigned char *)(Message)) + Message->PerPacketInfoOffset)
+#define MESSAGE_TO_DATA_BUFFER(msg) \
+ (((unsigned char *)(msg)) + msg->per_pkt_info_offset)
/* get pointer to contained message from NDIS_MESSAGE pointer */
-#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(RndisMessage) \
- ((void *) &RndisMessage->Message)
+#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(rndis_msg) \
+ ((void *) &rndis_msg->msg)
/* get pointer to contained message from NDIS_MESSAGE pointer */
-#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(RndisMessage) \
- ((void *) RndisMessage)
+#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(rndis_msg) \
+ ((void *) rndis_msg)
#endif /* _RNDIS_H_ */
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
index fa2141f454f0..53676dcbf381 100644
--- a/drivers/staging/hv/rndis_filter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -32,7 +32,7 @@
/* Data types */
struct rndis_filter_driver_object {
/* The original driver */
- struct netvsc_driver InnerDriver;
+ struct netvsc_driver inner_drv;
};
enum rndis_device_state {
@@ -43,63 +43,63 @@ enum rndis_device_state {
};
struct rndis_device {
- struct netvsc_device *NetDevice;
+ struct netvsc_device *net_dev;
- enum rndis_device_state State;
- u32 LinkStatus;
- atomic_t NewRequestId;
+ enum rndis_device_state state;
+ u32 link_stat;
+ atomic_t new_req_id;
spinlock_t request_lock;
- struct list_head RequestList;
+ struct list_head req_list;
- unsigned char HwMacAddr[ETH_ALEN];
+ unsigned char hw_mac_adr[ETH_ALEN];
};
struct rndis_request {
- struct list_head ListEntry;
- struct osd_waitevent *WaitEvent;
+ struct list_head list_ent;
+ struct osd_waitevent *waitevent;
/*
* FIXME: We assumed a fixed size response here. If we do ever need to
* handle a bigger response, we can either define a max response
* message or add a response buffer variable above this field
*/
- struct rndis_message ResponseMessage;
+ struct rndis_message response_msg;
/* Simplify allocation by having a netvsc packet inline */
- struct hv_netvsc_packet Packet;
- struct hv_page_buffer Buffer;
+ struct hv_netvsc_packet pkt;
+ struct hv_page_buffer buf;
/* FIXME: We assumed a fixed size request here. */
- struct rndis_message RequestMessage;
+ struct rndis_message request_msg;
};
struct rndis_filter_packet {
- void *CompletionContext;
- void (*OnCompletion)(void *context);
- struct rndis_message Message;
+ void *completion_ctx;
+ void (*completion)(void *context);
+ struct rndis_message msg;
};
-static int RndisFilterOnDeviceAdd(struct hv_device *Device,
- void *AdditionalInfo);
+static int rndis_filte_device_add(struct hv_device *dev,
+ void *additional_info);
-static int RndisFilterOnDeviceRemove(struct hv_device *Device);
+static int rndis_filter_device_remove(struct hv_device *dev);
-static void RndisFilterOnCleanup(struct hv_driver *Driver);
+static void rndis_filter_cleanup(struct hv_driver *drv);
-static int RndisFilterOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet);
+static int rndis_filter_send(struct hv_device *dev,
+ struct hv_netvsc_packet *pkt);
-static void RndisFilterOnSendCompletion(void *Context);
+static void rndis_filter_send_completion(void *ctx);
-static void RndisFilterOnSendRequestCompletion(void *Context);
+static void rndis_filter_send_request_completion(void *ctx);
/* The one and only */
-static struct rndis_filter_driver_object gRndisFilter;
+static struct rndis_filter_driver_object rndis_filter;
-static struct rndis_device *GetRndisDevice(void)
+static struct rndis_device *get_rndis_device(void)
{
struct rndis_device *device;
@@ -109,19 +109,19 @@ static struct rndis_device *GetRndisDevice(void)
spin_lock_init(&device->request_lock);
- INIT_LIST_HEAD(&device->RequestList);
+ INIT_LIST_HEAD(&device->req_list);
- device->State = RNDIS_DEV_UNINITIALIZED;
+ device->state = RNDIS_DEV_UNINITIALIZED;
return device;
}
-static struct rndis_request *GetRndisRequest(struct rndis_device *Device,
- u32 MessageType,
- u32 MessageLength)
+static struct rndis_request *get_rndis_request(struct rndis_device *dev,
+ u32 msg_type,
+ u32 msg_len)
{
struct rndis_request *request;
- struct rndis_message *rndisMessage;
+ struct rndis_message *rndis_msg;
struct rndis_set_request *set;
unsigned long flags;
@@ -129,61 +129,61 @@ static struct rndis_request *GetRndisRequest(struct rndis_device *Device,
if (!request)
return NULL;
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
+ request->waitevent = osd_waitevent_create();
+ if (!request->waitevent) {
kfree(request);
return NULL;
}
- rndisMessage = &request->RequestMessage;
- rndisMessage->NdisMessageType = MessageType;
- rndisMessage->MessageLength = MessageLength;
+ rndis_msg = &request->request_msg;
+ rndis_msg->ndis_msg_type = msg_type;
+ rndis_msg->msg_len = msg_len;
/*
* Set the request id. This field is always after the rndis header for
* request/response packet types so we just used the SetRequest as a
* template
*/
- set = &rndisMessage->Message.SetRequest;
- set->RequestId = atomic_inc_return(&Device->NewRequestId);
+ set = &rndis_msg->msg.set_req;
+ set->req_id = atomic_inc_return(&dev->new_req_id);
/* Add to the request list */
- spin_lock_irqsave(&Device->request_lock, flags);
- list_add_tail(&request->ListEntry, &Device->RequestList);
- spin_unlock_irqrestore(&Device->request_lock, flags);
+ spin_lock_irqsave(&dev->request_lock, flags);
+ list_add_tail(&request->list_ent, &dev->req_list);
+ spin_unlock_irqrestore(&dev->request_lock, flags);
return request;
}
-static void PutRndisRequest(struct rndis_device *Device,
- struct rndis_request *Request)
+static void put_rndis_request(struct rndis_device *dev,
+ struct rndis_request *req)
{
unsigned long flags;
- spin_lock_irqsave(&Device->request_lock, flags);
- list_del(&Request->ListEntry);
- spin_unlock_irqrestore(&Device->request_lock, flags);
+ spin_lock_irqsave(&dev->request_lock, flags);
+ list_del(&req->list_ent);
+ spin_unlock_irqrestore(&dev->request_lock, flags);
- kfree(Request->WaitEvent);
- kfree(Request);
+ kfree(req->waitevent);
+ kfree(req);
}
-static void DumpRndisMessage(struct rndis_message *RndisMessage)
+static void dump_rndis_message(struct rndis_message *rndis_msg)
{
- switch (RndisMessage->NdisMessageType) {
+ switch (rndis_msg->ndis_msg_type) {
case REMOTE_NDIS_PACKET_MSG:
DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, "
"data offset %u data len %u, # oob %u, "
"oob offset %u, oob len %u, pkt offset %u, "
"pkt len %u",
- RndisMessage->MessageLength,
- RndisMessage->Message.Packet.DataOffset,
- RndisMessage->Message.Packet.DataLength,
- RndisMessage->Message.Packet.NumOOBDataElements,
- RndisMessage->Message.Packet.OOBDataOffset,
- RndisMessage->Message.Packet.OOBDataLength,
- RndisMessage->Message.Packet.PerPacketInfoOffset,
- RndisMessage->Message.Packet.PerPacketInfoLength);
+ rndis_msg->msg_len,
+ rndis_msg->msg.pkt.data_offset,
+ rndis_msg->msg.pkt.data_len,
+ rndis_msg->msg.pkt.num_oob_data_elements,
+ rndis_msg->msg.pkt.oob_data_offset,
+ rndis_msg->msg.pkt.oob_data_len,
+ rndis_msg->msg.pkt.per_pkt_info_offset,
+ rndis_msg->msg.pkt.per_pkt_info_len);
break;
case REMOTE_NDIS_INITIALIZE_CMPLT:
@@ -191,147 +191,157 @@ static void DumpRndisMessage(struct rndis_message *RndisMessage)
"(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
"device flags %d, max xfer size 0x%x, max pkts %u, "
"pkt aligned %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.InitializeComplete.RequestId,
- RndisMessage->Message.InitializeComplete.Status,
- RndisMessage->Message.InitializeComplete.MajorVersion,
- RndisMessage->Message.InitializeComplete.MinorVersion,
- RndisMessage->Message.InitializeComplete.DeviceFlags,
- RndisMessage->Message.InitializeComplete.MaxTransferSize,
- RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage,
- RndisMessage->Message.InitializeComplete.PacketAlignmentFactor);
+ rndis_msg->msg_len,
+ rndis_msg->msg.init_complete.req_id,
+ rndis_msg->msg.init_complete.status,
+ rndis_msg->msg.init_complete.major_ver,
+ rndis_msg->msg.init_complete.minor_ver,
+ rndis_msg->msg.init_complete.dev_flags,
+ rndis_msg->msg.init_complete.max_xfer_size,
+ rndis_msg->msg.init_complete.
+ max_pkt_per_msg,
+ rndis_msg->msg.init_complete.
+ pkt_alignment_factor);
break;
case REMOTE_NDIS_QUERY_CMPLT:
DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT "
"(len %u, id 0x%x, status 0x%x, buf len %u, "
"buf offset %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.QueryComplete.RequestId,
- RndisMessage->Message.QueryComplete.Status,
- RndisMessage->Message.QueryComplete.InformationBufferLength,
- RndisMessage->Message.QueryComplete.InformationBufferOffset);
+ rndis_msg->msg_len,
+ rndis_msg->msg.query_complete.req_id,
+ rndis_msg->msg.query_complete.status,
+ rndis_msg->msg.query_complete.
+ info_buflen,
+ rndis_msg->msg.query_complete.
+ info_buf_offset);
break;
case REMOTE_NDIS_SET_CMPLT:
DPRINT_DBG(NETVSC,
"REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)",
- RndisMessage->MessageLength,
- RndisMessage->Message.SetComplete.RequestId,
- RndisMessage->Message.SetComplete.Status);
+ rndis_msg->msg_len,
+ rndis_msg->msg.set_complete.req_id,
+ rndis_msg->msg.set_complete.status);
break;
case REMOTE_NDIS_INDICATE_STATUS_MSG:
DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG "
"(len %u, status 0x%x, buf len %u, buf offset %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.IndicateStatus.Status,
- RndisMessage->Message.IndicateStatus.StatusBufferLength,
- RndisMessage->Message.IndicateStatus.StatusBufferOffset);
+ rndis_msg->msg_len,
+ rndis_msg->msg.indicate_status.status,
+ rndis_msg->msg.indicate_status.status_buflen,
+ rndis_msg->msg.indicate_status.status_buf_offset);
break;
default:
DPRINT_DBG(NETVSC, "0x%x (len %u)",
- RndisMessage->NdisMessageType,
- RndisMessage->MessageLength);
+ rndis_msg->ndis_msg_type,
+ rndis_msg->msg_len);
break;
}
}
-static int RndisFilterSendRequest(struct rndis_device *Device,
- struct rndis_request *Request)
+static int rndis_filter_send_request(struct rndis_device *dev,
+ struct rndis_request *req)
{
int ret;
struct hv_netvsc_packet *packet;
/* Setup the packet to send it */
- packet = &Request->Packet;
+ packet = &req->pkt;
- packet->IsDataPacket = false;
- packet->TotalDataBufferLength = Request->RequestMessage.MessageLength;
- packet->PageBufferCount = 1;
+ packet->is_data_pkt = false;
+ packet->total_data_buflen = req->request_msg.msg_len;
+ packet->page_buf_cnt = 1;
- packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >>
+ packet->page_buf[0].Pfn = virt_to_phys(&req->request_msg) >>
PAGE_SHIFT;
- packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength;
- packet->PageBuffers[0].Offset =
- (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1);
+ packet->page_buf[0].Length = req->request_msg.msg_len;
+ packet->page_buf[0].Offset =
+ (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
- packet->Completion.Send.SendCompletionContext = Request;/* packet; */
- packet->Completion.Send.OnSendCompletion =
- RndisFilterOnSendRequestCompletion;
- packet->Completion.Send.SendCompletionTid = (unsigned long)Device;
+ packet->completion.send.send_completion_ctx = req;/* packet; */
+ packet->completion.send.send_completion =
+ rndis_filter_send_request_completion;
+ packet->completion.send.send_completion_tid = (unsigned long)dev;
- ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet);
+ ret = rndis_filter.inner_drv.send(dev->net_dev->dev, packet);
return ret;
}
-static void RndisFilterReceiveResponse(struct rndis_device *Device,
- struct rndis_message *Response)
+static void rndis_filter_receive_response(struct rndis_device *dev,
+ struct rndis_message *resp)
{
struct rndis_request *request = NULL;
bool found = false;
unsigned long flags;
- spin_lock_irqsave(&Device->request_lock, flags);
- list_for_each_entry(request, &Device->RequestList, ListEntry) {
+ spin_lock_irqsave(&dev->request_lock, flags);
+ list_for_each_entry(request, &dev->req_list, list_ent) {
/*
* All request/response message contains RequestId as the 1st
* field
*/
- if (request->RequestMessage.Message.InitializeRequest.RequestId
- == Response->Message.InitializeComplete.RequestId) {
+ if (request->request_msg.msg.init_req.req_id
+ == resp->msg.init_complete.req_id) {
DPRINT_DBG(NETVSC, "found rndis request for "
"this response (id 0x%x req type 0x%x res "
"type 0x%x)",
- request->RequestMessage.Message.InitializeRequest.RequestId,
- request->RequestMessage.NdisMessageType,
- Response->NdisMessageType);
+ request->request_msg.msg.
+ init_req.req_id,
+ request->request_msg.ndis_msg_type,
+ resp->ndis_msg_type);
found = true;
break;
}
}
- spin_unlock_irqrestore(&Device->request_lock, flags);
+ spin_unlock_irqrestore(&dev->request_lock, flags);
if (found) {
- if (Response->MessageLength <= sizeof(struct rndis_message)) {
- memcpy(&request->ResponseMessage, Response,
- Response->MessageLength);
+ if (resp->msg_len <= sizeof(struct rndis_message)) {
+ memcpy(&request->response_msg, resp,
+ resp->msg_len);
} else {
DPRINT_ERR(NETVSC, "rndis response buffer overflow "
"detected (size %u max %zu)",
- Response->MessageLength,
+ resp->msg_len,
sizeof(struct rndis_filter_packet));
- if (Response->NdisMessageType ==
+ if (resp->ndis_msg_type ==
REMOTE_NDIS_RESET_CMPLT) {
/* does not have a request id field */
- request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW;
+ request->response_msg.msg.reset_complete.
+ status = STATUS_BUFFER_OVERFLOW;
} else {
- request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW;
+ request->response_msg.msg.
+ init_complete.status =
+ STATUS_BUFFER_OVERFLOW;
}
}
- osd_WaitEventSet(request->WaitEvent);
+ osd_waitevent_set(request->waitevent);
} else {
DPRINT_ERR(NETVSC, "no rndis request found for this response "
"(id 0x%x res type 0x%x)",
- Response->Message.InitializeComplete.RequestId,
- Response->NdisMessageType);
+ resp->msg.init_complete.req_id,
+ resp->ndis_msg_type);
}
}
-static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device,
- struct rndis_message *Response)
+static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
+ struct rndis_message *resp)
{
struct rndis_indicate_status *indicate =
- &Response->Message.IndicateStatus;
-
- if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) {
- gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1);
- } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) {
- gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0);
+ &resp->msg.indicate_status;
+
+ if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
+ rndis_filter.inner_drv.link_status_change(
+ dev->net_dev->dev, 1);
+ } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
+ rndis_filter.inner_drv.link_status_change(
+ dev->net_dev->dev, 0);
} else {
/*
* TODO:
@@ -339,18 +349,18 @@ static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device,
}
}
-static void RndisFilterReceiveData(struct rndis_device *Device,
- struct rndis_message *Message,
- struct hv_netvsc_packet *Packet)
+static void rndis_filter_receive_data(struct rndis_device *dev,
+ struct rndis_message *msg,
+ struct hv_netvsc_packet *pkt)
{
- struct rndis_packet *rndisPacket;
- u32 dataOffset;
+ struct rndis_packet *rndis_pkt;
+ u32 data_offset;
/* empty ethernet frame ?? */
/* ASSERT(Packet->PageBuffers[0].Length > */
/* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */
- rndisPacket = &Message->Message.Packet;
+ rndis_pkt = &msg->msg.pkt;
/*
* FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this
@@ -358,48 +368,48 @@ static void RndisFilterReceiveData(struct rndis_device *Device,
*/
/* Remove the rndis header and pass it back up the stack */
- dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset;
+ data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
- Packet->TotalDataBufferLength -= dataOffset;
- Packet->PageBuffers[0].Offset += dataOffset;
- Packet->PageBuffers[0].Length -= dataOffset;
+ pkt->total_data_buflen -= data_offset;
+ pkt->page_buf[0].Offset += data_offset;
+ pkt->page_buf[0].Length -= data_offset;
- Packet->IsDataPacket = true;
+ pkt->is_data_pkt = true;
- gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device,
- Packet);
+ rndis_filter.inner_drv.recv_cb(dev->net_dev->dev,
+ pkt);
}
-static int RndisFilterOnReceive(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
+static int rndis_filter_receive(struct hv_device *dev,
+ struct hv_netvsc_packet *pkt)
{
- struct netvsc_device *netDevice = Device->Extension;
- struct rndis_device *rndisDevice;
- struct rndis_message rndisMessage;
- struct rndis_message *rndisHeader;
+ struct netvsc_device *net_dev = dev->Extension;
+ struct rndis_device *rndis_dev;
+ struct rndis_message rndis_msg;
+ struct rndis_message *rndis_hdr;
- if (!netDevice)
+ if (!net_dev)
return -EINVAL;
/* Make sure the rndis device state is initialized */
- if (!netDevice->Extension) {
+ if (!net_dev->extension) {
DPRINT_ERR(NETVSC, "got rndis message but no rndis device..."
"dropping this message!");
return -1;
}
- rndisDevice = (struct rndis_device *)netDevice->Extension;
- if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) {
+ rndis_dev = (struct rndis_device *)net_dev->extension;
+ if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
DPRINT_ERR(NETVSC, "got rndis message but rndis device "
"uninitialized...dropping this message!");
return -1;
}
- rndisHeader = (struct rndis_message *)kmap_atomic(
- pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0);
+ rndis_hdr = (struct rndis_message *)kmap_atomic(
+ pfn_to_page(pkt->page_buf[0].Pfn), KM_IRQ0);
- rndisHeader = (void *)((unsigned long)rndisHeader +
- Packet->PageBuffers[0].Offset);
+ rndis_hdr = (void *)((unsigned long)rndis_hdr +
+ pkt->page_buf[0].Offset);
/* Make sure we got a valid rndis message */
/*
@@ -408,39 +418,39 @@ static int RndisFilterOnReceive(struct hv_device *Device,
* range shows 52 bytes
* */
#if 0
- if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) {
- kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset,
+ if (pkt->total_data_buflen != rndis_hdr->msg_len) {
+ kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset,
KM_IRQ0);
DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u "
"bytes got %u)...dropping this message!",
- rndisHeader->MessageLength,
- Packet->TotalDataBufferLength);
+ rndis_hdr->msg_len,
+ pkt->total_data_buflen);
return -1;
}
#endif
- if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) &&
- (rndisHeader->MessageLength > sizeof(struct rndis_message))) {
+ if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
+ (rndis_hdr->msg_len > sizeof(struct rndis_message))) {
DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow "
"detected (got %u, max %zu)...marking it an error!",
- rndisHeader->MessageLength,
+ rndis_hdr->msg_len,
sizeof(struct rndis_message));
}
- memcpy(&rndisMessage, rndisHeader,
- (rndisHeader->MessageLength > sizeof(struct rndis_message)) ?
+ memcpy(&rndis_msg, rndis_hdr,
+ (rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
sizeof(struct rndis_message) :
- rndisHeader->MessageLength);
+ rndis_hdr->msg_len);
- kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0);
+ kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0);
- DumpRndisMessage(&rndisMessage);
+ dump_rndis_message(&rndis_msg);
- switch (rndisMessage.NdisMessageType) {
+ switch (rndis_msg.ndis_msg_type) {
case REMOTE_NDIS_PACKET_MSG:
/* data msg */
- RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet);
+ rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt);
break;
case REMOTE_NDIS_INITIALIZE_CMPLT:
@@ -449,37 +459,37 @@ static int RndisFilterOnReceive(struct hv_device *Device,
/* case REMOTE_NDIS_RESET_CMPLT: */
/* case REMOTE_NDIS_KEEPALIVE_CMPLT: */
/* completion msgs */
- RndisFilterReceiveResponse(rndisDevice, &rndisMessage);
+ rndis_filter_receive_response(rndis_dev, &rndis_msg);
break;
case REMOTE_NDIS_INDICATE_STATUS_MSG:
/* notification msgs */
- RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage);
+ rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
break;
default:
DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)",
- rndisMessage.NdisMessageType,
- rndisMessage.MessageLength);
+ rndis_msg.ndis_msg_type,
+ rndis_msg.msg_len);
break;
}
return 0;
}
-static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
- void *Result, u32 *ResultSize)
+static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
+ void *result, u32 *result_size)
{
struct rndis_request *request;
- u32 inresultSize = *ResultSize;
+ u32 inresult_size = *result_size;
struct rndis_query_request *query;
- struct rndis_query_complete *queryComplete;
+ struct rndis_query_complete *query_complete;
int ret = 0;
- if (!Result)
+ if (!result)
return -EINVAL;
- *ResultSize = 0;
- request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG,
+ *result_size = 0;
+ request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_query_request));
if (!request) {
ret = -1;
@@ -487,71 +497,71 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
}
/* Setup the rndis query */
- query = &request->RequestMessage.Message.QueryRequest;
- query->Oid = Oid;
- query->InformationBufferOffset = sizeof(struct rndis_query_request);
- query->InformationBufferLength = 0;
- query->DeviceVcHandle = 0;
+ query = &request->request_msg.msg.query_req;
+ query->oid = oid;
+ query->info_buf_offset = sizeof(struct rndis_query_request);
+ query->info_buflen = 0;
+ query->dev_vc_handle = 0;
- ret = RndisFilterSendRequest(Device, request);
+ ret = rndis_filter_send_request(dev, request);
if (ret != 0)
goto Cleanup;
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->waitevent);
/* Copy the response back */
- queryComplete = &request->ResponseMessage.Message.QueryComplete;
+ query_complete = &request->response_msg.msg.query_complete;
- if (queryComplete->InformationBufferLength > inresultSize) {
+ if (query_complete->info_buflen > inresult_size) {
ret = -1;
goto Cleanup;
}
- memcpy(Result,
- (void *)((unsigned long)queryComplete +
- queryComplete->InformationBufferOffset),
- queryComplete->InformationBufferLength);
+ memcpy(result,
+ (void *)((unsigned long)query_complete +
+ query_complete->info_buf_offset),
+ query_complete->info_buflen);
- *ResultSize = queryComplete->InformationBufferLength;
+ *result_size = query_complete->info_buflen;
Cleanup:
if (request)
- PutRndisRequest(Device, request);
+ put_rndis_request(dev, request);
return ret;
}
-static int RndisFilterQueryDeviceMac(struct rndis_device *Device)
+static int rndis_filter_query_device_mac(struct rndis_device *dev)
{
u32 size = ETH_ALEN;
- return RndisFilterQueryDevice(Device,
+ return rndis_filter_query_device(dev,
RNDIS_OID_802_3_PERMANENT_ADDRESS,
- Device->HwMacAddr, &size);
+ dev->hw_mac_adr, &size);
}
-static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device)
+static int rndis_filter_query_device_link_status(struct rndis_device *dev)
{
u32 size = sizeof(u32);
- return RndisFilterQueryDevice(Device,
+ return rndis_filter_query_device(dev,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
- &Device->LinkStatus, &size);
+ &dev->link_stat, &size);
}
-static int RndisFilterSetPacketFilter(struct rndis_device *Device,
- u32 NewFilter)
+static int rndis_filter_set_packet_filter(struct rndis_device *dev,
+ u32 new_filter)
{
struct rndis_request *request;
struct rndis_set_request *set;
- struct rndis_set_complete *setComplete;
+ struct rndis_set_complete *set_complete;
u32 status;
int ret;
/* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */
/* sizeof(struct rndis_message)); */
- request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG,
+ request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
sizeof(u32));
if (!request) {
@@ -560,19 +570,19 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device,
}
/* Setup the rndis set */
- set = &request->RequestMessage.Message.SetRequest;
- set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
- set->InformationBufferLength = sizeof(u32);
- set->InformationBufferOffset = sizeof(struct rndis_set_request);
+ set = &request->request_msg.msg.set_req;
+ set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
+ set->info_buflen = sizeof(u32);
+ set->info_buf_offset = sizeof(struct rndis_set_request);
memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
- &NewFilter, sizeof(u32));
+ &new_filter, sizeof(u32));
- ret = RndisFilterSendRequest(Device, request);
+ ret = rndis_filter_send_request(dev, request);
if (ret != 0)
goto Cleanup;
- ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/);
+ ret = osd_waitevent_waitex(request->waitevent, 2000/*2sec*/);
if (!ret) {
ret = -1;
DPRINT_ERR(NETVSC, "timeout before we got a set response...");
@@ -584,27 +594,27 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device,
} else {
if (ret > 0)
ret = 0;
- setComplete = &request->ResponseMessage.Message.SetComplete;
- status = setComplete->Status;
+ set_complete = &request->response_msg.msg.set_complete;
+ status = set_complete->status;
}
Cleanup:
if (request)
- PutRndisRequest(Device, request);
+ put_rndis_request(dev, request);
Exit:
return ret;
}
-int RndisFilterInit(struct netvsc_driver *Driver)
+int rndis_filter_init(struct netvsc_driver *drv)
{
DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd",
sizeof(struct rndis_filter_packet));
- Driver->RequestExtSize = sizeof(struct rndis_filter_packet);
+ drv->req_ext_size = sizeof(struct rndis_filter_packet);
/* Driver->Context = rndisDriver; */
- memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object));
+ memset(&rndis_filter, 0, sizeof(struct rndis_filter_driver_object));
/*rndisDriver->Driver = Driver;
@@ -612,38 +622,38 @@ int RndisFilterInit(struct netvsc_driver *Driver)
rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/
/* Save the original dispatch handlers before we override it */
- gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd;
- gRndisFilter.InnerDriver.Base.OnDeviceRemove =
- Driver->Base.OnDeviceRemove;
- gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup;
+ rndis_filter.inner_drv.base.OnDeviceAdd = drv->base.OnDeviceAdd;
+ rndis_filter.inner_drv.base.OnDeviceRemove =
+ drv->base.OnDeviceRemove;
+ rndis_filter.inner_drv.base.OnCleanup = drv->base.OnCleanup;
/* ASSERT(Driver->OnSend); */
/* ASSERT(Driver->OnReceiveCallback); */
- gRndisFilter.InnerDriver.OnSend = Driver->OnSend;
- gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback;
- gRndisFilter.InnerDriver.OnLinkStatusChanged =
- Driver->OnLinkStatusChanged;
+ rndis_filter.inner_drv.send = drv->send;
+ rndis_filter.inner_drv.recv_cb = drv->recv_cb;
+ rndis_filter.inner_drv.link_status_change =
+ drv->link_status_change;
/* Override */
- Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd;
- Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove;
- Driver->Base.OnCleanup = RndisFilterOnCleanup;
- Driver->OnSend = RndisFilterOnSend;
+ drv->base.OnDeviceAdd = rndis_filte_device_add;
+ drv->base.OnDeviceRemove = rndis_filter_device_remove;
+ drv->base.OnCleanup = rndis_filter_cleanup;
+ drv->send = rndis_filter_send;
/* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
- Driver->OnReceiveCallback = RndisFilterOnReceive;
+ drv->recv_cb = rndis_filter_receive;
return 0;
}
-static int RndisFilterInitDevice(struct rndis_device *Device)
+static int rndis_filter_init_device(struct rndis_device *dev)
{
struct rndis_request *request;
struct rndis_initialize_request *init;
- struct rndis_initialize_complete *initComplete;
+ struct rndis_initialize_complete *init_complete;
u32 status;
int ret;
- request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG,
+ request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
if (!request) {
ret = -1;
@@ -651,105 +661,105 @@ static int RndisFilterInitDevice(struct rndis_device *Device)
}
/* Setup the rndis set */
- init = &request->RequestMessage.Message.InitializeRequest;
- init->MajorVersion = RNDIS_MAJOR_VERSION;
- init->MinorVersion = RNDIS_MINOR_VERSION;
+ init = &request->request_msg.msg.init_req;
+ init->major_ver = RNDIS_MAJOR_VERSION;
+ init->minor_ver = RNDIS_MINOR_VERSION;
/* FIXME: Use 1536 - rounded ethernet frame size */
- init->MaxTransferSize = 2048;
+ init->max_xfer_size = 2048;
- Device->State = RNDIS_DEV_INITIALIZING;
+ dev->state = RNDIS_DEV_INITIALIZING;
- ret = RndisFilterSendRequest(Device, request);
+ ret = rndis_filter_send_request(dev, request);
if (ret != 0) {
- Device->State = RNDIS_DEV_UNINITIALIZED;
+ dev->state = RNDIS_DEV_UNINITIALIZED;
goto Cleanup;
}
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->waitevent);
- initComplete = &request->ResponseMessage.Message.InitializeComplete;
- status = initComplete->Status;
+ init_complete = &request->response_msg.msg.init_complete;
+ status = init_complete->status;
if (status == RNDIS_STATUS_SUCCESS) {
- Device->State = RNDIS_DEV_INITIALIZED;
+ dev->state = RNDIS_DEV_INITIALIZED;
ret = 0;
} else {
- Device->State = RNDIS_DEV_UNINITIALIZED;
+ dev->state = RNDIS_DEV_UNINITIALIZED;
ret = -1;
}
Cleanup:
if (request)
- PutRndisRequest(Device, request);
+ put_rndis_request(dev, request);
return ret;
}
-static void RndisFilterHaltDevice(struct rndis_device *Device)
+static void rndis_filter_halt_device(struct rndis_device *dev)
{
struct rndis_request *request;
struct rndis_halt_request *halt;
/* Attempt to do a rndis device halt */
- request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG,
+ request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
if (!request)
goto Cleanup;
/* Setup the rndis set */
- halt = &request->RequestMessage.Message.HaltRequest;
- halt->RequestId = atomic_inc_return(&Device->NewRequestId);
+ halt = &request->request_msg.msg.halt_req;
+ halt->req_id = atomic_inc_return(&dev->new_req_id);
/* Ignore return since this msg is optional. */
- RndisFilterSendRequest(Device, request);
+ rndis_filter_send_request(dev, request);
- Device->State = RNDIS_DEV_UNINITIALIZED;
+ dev->state = RNDIS_DEV_UNINITIALIZED;
Cleanup:
if (request)
- PutRndisRequest(Device, request);
+ put_rndis_request(dev, request);
return;
}
-static int RndisFilterOpenDevice(struct rndis_device *Device)
+static int rndis_filter_open_device(struct rndis_device *dev)
{
int ret;
- if (Device->State != RNDIS_DEV_INITIALIZED)
+ if (dev->state != RNDIS_DEV_INITIALIZED)
return 0;
- ret = RndisFilterSetPacketFilter(Device,
+ ret = rndis_filter_set_packet_filter(dev,
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
if (ret == 0)
- Device->State = RNDIS_DEV_DATAINITIALIZED;
+ dev->state = RNDIS_DEV_DATAINITIALIZED;
return ret;
}
-static int RndisFilterCloseDevice(struct rndis_device *Device)
+static int rndis_filter_close_device(struct rndis_device *dev)
{
int ret;
- if (Device->State != RNDIS_DEV_DATAINITIALIZED)
+ if (dev->state != RNDIS_DEV_DATAINITIALIZED)
return 0;
- ret = RndisFilterSetPacketFilter(Device, 0);
+ ret = rndis_filter_set_packet_filter(dev, 0);
if (ret == 0)
- Device->State = RNDIS_DEV_INITIALIZED;
+ dev->state = RNDIS_DEV_INITIALIZED;
return ret;
}
-static int RndisFilterOnDeviceAdd(struct hv_device *Device,
- void *AdditionalInfo)
+static int rndis_filte_device_add(struct hv_device *dev,
+ void *additional_info)
{
int ret;
struct netvsc_device *netDevice;
struct rndis_device *rndisDevice;
- struct netvsc_device_info *deviceInfo = AdditionalInfo;
+ struct netvsc_device_info *deviceInfo = additional_info;
- rndisDevice = GetRndisDevice();
+ rndisDevice = get_rndis_device();
if (!rndisDevice)
return -1;
@@ -760,7 +770,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
* NOTE! Once the channel is created, we may get a receive callback
* (RndisFilterOnReceive()) before this call is completed
*/
- ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo);
+ ret = rndis_filter.inner_drv.base.OnDeviceAdd(dev, additional_info);
if (ret != 0) {
kfree(rndisDevice);
return ret;
@@ -768,15 +778,15 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
/* Initialize the rndis device */
- netDevice = Device->Extension;
+ netDevice = dev->Extension;
/* ASSERT(netDevice); */
/* ASSERT(netDevice->Device); */
- netDevice->Extension = rndisDevice;
- rndisDevice->NetDevice = netDevice;
+ netDevice->extension = rndisDevice;
+ rndisDevice->net_dev = netDevice;
/* Send the rndis initialization message */
- ret = RndisFilterInitDevice(rndisDevice);
+ ret = rndis_filter_init_device(rndisDevice);
if (ret != 0) {
/*
* TODO: If rndis init failed, we will need to shut down the
@@ -785,7 +795,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
}
/* Get the mac address */
- ret = RndisFilterQueryDeviceMac(rndisDevice);
+ ret = rndis_filter_query_device_mac(rndisDevice);
if (ret != 0) {
/*
* TODO: shutdown rndis device and the channel
@@ -793,62 +803,62 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
}
DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM",
- rndisDevice, rndisDevice->HwMacAddr);
+ rndisDevice, rndisDevice->hw_mac_adr);
- memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN);
+ memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN);
- RndisFilterQueryDeviceLinkStatus(rndisDevice);
+ rndis_filter_query_device_link_status(rndisDevice);
- deviceInfo->LinkState = rndisDevice->LinkStatus;
+ deviceInfo->link_state = rndisDevice->link_stat;
DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice,
- ((deviceInfo->LinkState) ? ("down") : ("up")));
+ ((deviceInfo->link_state) ? ("down") : ("up")));
return ret;
}
-static int RndisFilterOnDeviceRemove(struct hv_device *Device)
+static int rndis_filter_device_remove(struct hv_device *dev)
{
- struct netvsc_device *netDevice = Device->Extension;
- struct rndis_device *rndisDevice = netDevice->Extension;
+ struct netvsc_device *net_dev = dev->Extension;
+ struct rndis_device *rndis_dev = net_dev->extension;
/* Halt and release the rndis device */
- RndisFilterHaltDevice(rndisDevice);
+ rndis_filter_halt_device(rndis_dev);
- kfree(rndisDevice);
- netDevice->Extension = NULL;
+ kfree(rndis_dev);
+ net_dev->extension = NULL;
/* Pass control to inner driver to remove the device */
- gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device);
+ rndis_filter.inner_drv.base.OnDeviceRemove(dev);
return 0;
}
-static void RndisFilterOnCleanup(struct hv_driver *Driver)
+static void rndis_filter_cleanup(struct hv_driver *drv)
{
}
-int RndisFilterOnOpen(struct hv_device *Device)
+int rndis_filter_open(struct hv_device *dev)
{
- struct netvsc_device *netDevice = Device->Extension;
+ struct netvsc_device *netDevice = dev->Extension;
if (!netDevice)
return -EINVAL;
- return RndisFilterOpenDevice(netDevice->Extension);
+ return rndis_filter_open_device(netDevice->extension);
}
-int RndisFilterOnClose(struct hv_device *Device)
+int rndis_filter_close(struct hv_device *dev)
{
- struct netvsc_device *netDevice = Device->Extension;
+ struct netvsc_device *netDevice = dev->Extension;
if (!netDevice)
return -EINVAL;
- return RndisFilterCloseDevice(netDevice->Extension);
+ return rndis_filter_close_device(netDevice->extension);
}
-static int RndisFilterOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
+static int rndis_filter_send(struct hv_device *dev,
+ struct hv_netvsc_packet *pkt)
{
int ret;
struct rndis_filter_packet *filterPacket;
@@ -857,62 +867,62 @@ static int RndisFilterOnSend(struct hv_device *Device,
u32 rndisMessageSize;
/* Add the rndis header */
- filterPacket = (struct rndis_filter_packet *)Packet->Extension;
+ filterPacket = (struct rndis_filter_packet *)pkt->extension;
/* ASSERT(filterPacket); */
memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
- rndisMessage = &filterPacket->Message;
+ rndisMessage = &filterPacket->msg;
rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
- rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG;
- rndisMessage->MessageLength = Packet->TotalDataBufferLength +
+ rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
+ rndisMessage->msg_len = pkt->total_data_buflen +
rndisMessageSize;
- rndisPacket = &rndisMessage->Message.Packet;
- rndisPacket->DataOffset = sizeof(struct rndis_packet);
- rndisPacket->DataLength = Packet->TotalDataBufferLength;
+ rndisPacket = &rndisMessage->msg.pkt;
+ rndisPacket->data_offset = sizeof(struct rndis_packet);
+ rndisPacket->data_len = pkt->total_data_buflen;
- Packet->IsDataPacket = true;
- Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
- Packet->PageBuffers[0].Offset =
+ pkt->is_data_pkt = true;
+ pkt->page_buf[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
+ pkt->page_buf[0].Offset =
(unsigned long)rndisMessage & (PAGE_SIZE-1);
- Packet->PageBuffers[0].Length = rndisMessageSize;
+ pkt->page_buf[0].Length = rndisMessageSize;
/* Save the packet send completion and context */
- filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion;
- filterPacket->CompletionContext =
- Packet->Completion.Send.SendCompletionContext;
+ filterPacket->completion = pkt->completion.send.send_completion;
+ filterPacket->completion_ctx =
+ pkt->completion.send.send_completion_ctx;
/* Use ours */
- Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion;
- Packet->Completion.Send.SendCompletionContext = filterPacket;
+ pkt->completion.send.send_completion = rndis_filter_send_completion;
+ pkt->completion.send.send_completion_ctx = filterPacket;
- ret = gRndisFilter.InnerDriver.OnSend(Device, Packet);
+ ret = rndis_filter.inner_drv.send(dev, pkt);
if (ret != 0) {
/*
* Reset the completion to originals to allow retries from
* above
*/
- Packet->Completion.Send.OnSendCompletion =
- filterPacket->OnCompletion;
- Packet->Completion.Send.SendCompletionContext =
- filterPacket->CompletionContext;
+ pkt->completion.send.send_completion =
+ filterPacket->completion;
+ pkt->completion.send.send_completion_ctx =
+ filterPacket->completion_ctx;
}
return ret;
}
-static void RndisFilterOnSendCompletion(void *Context)
+static void rndis_filter_send_completion(void *ctx)
{
- struct rndis_filter_packet *filterPacket = Context;
+ struct rndis_filter_packet *filterPacket = ctx;
/* Pass it back to the original handler */
- filterPacket->OnCompletion(filterPacket->CompletionContext);
+ filterPacket->completion(filterPacket->completion_ctx);
}
-static void RndisFilterOnSendRequestCompletion(void *Context)
+static void rndis_filter_send_request_completion(void *ctx)
{
/* Noop */
}
diff --git a/drivers/staging/hv/rndis_filter.h b/drivers/staging/hv/rndis_filter.h
index 764b9bf3e5dc..4da18f3cbade 100644
--- a/drivers/staging/hv/rndis_filter.h
+++ b/drivers/staging/hv/rndis_filter.h
@@ -50,6 +50,6 @@
/* Interface */
-extern int RndisFilterInit(struct netvsc_driver *driver);
+extern int rndis_filter_init(struct netvsc_driver *driver);
#endif /* _RNDISFILTER_H_ */
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 19e87f689fa0..9295113e09b9 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -34,43 +34,43 @@
struct storvsc_request_extension {
/* LIST_ENTRY ListEntry; */
- struct hv_storvsc_request *Request;
- struct hv_device *Device;
+ struct hv_storvsc_request *request;
+ struct hv_device *device;
/* Synchronize the request/response if needed */
- struct osd_waitevent *WaitEvent;
+ struct osd_waitevent *wait_event;
- struct vstor_packet VStorPacket;
+ struct vstor_packet vstor_packet;
};
/* A storvsc device is a device object that contains a vmbus channel */
struct storvsc_device {
- struct hv_device *Device;
+ struct hv_device *device;
/* 0 indicates the device is being destroyed */
- atomic_t RefCount;
+ atomic_t ref_count;
- atomic_t NumOutstandingRequests;
+ atomic_t num_outstanding_req;
/*
* Each unique Port/Path/Target represents 1 channel ie scsi
* controller. In reality, the pathid, targetid is always 0
* and the port is set by us
*/
- unsigned int PortNumber;
- unsigned char PathId;
- unsigned char TargetId;
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
/* LIST_ENTRY OutstandingRequestList; */
/* HANDLE OutstandingRequestLock; */
/* Used for vsc/vsp channel reset process */
- struct storvsc_request_extension InitRequest;
- struct storvsc_request_extension ResetRequest;
+ struct storvsc_request_extension init_request;
+ struct storvsc_request_extension reset_request;
};
-static const char *gDriverName = "storvsc";
+static const char *g_driver_name = "storvsc";
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
static const struct hv_guid gStorVscDeviceType = {
@@ -81,131 +81,133 @@ static const struct hv_guid gStorVscDeviceType = {
};
-static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
+static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
- if (!storDevice)
+ stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
+ if (!stor_device)
return NULL;
/* Set to 2 to allow both inbound and outbound traffics */
- /* (ie GetStorDevice() and MustGetStorDevice()) to proceed. */
- atomic_cmpxchg(&storDevice->RefCount, 0, 2);
+ /* (ie get_stor_device() and must_get_stor_device()) to proceed. */
+ atomic_cmpxchg(&stor_device->ref_count, 0, 2);
- storDevice->Device = Device;
- Device->Extension = storDevice;
+ stor_device->device = device;
+ device->Extension = stor_device;
- return storDevice;
+ return stor_device;
}
-static inline void FreeStorDevice(struct storvsc_device *Device)
+static inline void free_stor_device(struct storvsc_device *device)
{
- /* ASSERT(atomic_read(&Device->RefCount) == 0); */
- kfree(Device);
+ /* ASSERT(atomic_read(&device->ref_count) == 0); */
+ kfree(device);
}
/* Get the stordevice object iff exists and its refcount > 1 */
-static inline struct storvsc_device *GetStorDevice(struct hv_device *Device)
+static inline struct storvsc_device *get_stor_device(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = (struct storvsc_device *)Device->Extension;
- if (storDevice && atomic_read(&storDevice->RefCount) > 1)
- atomic_inc(&storDevice->RefCount);
+ stor_device = (struct storvsc_device *)device->Extension;
+ if (stor_device && atomic_read(&stor_device->ref_count) > 1)
+ atomic_inc(&stor_device->ref_count);
else
- storDevice = NULL;
+ stor_device = NULL;
- return storDevice;
+ return stor_device;
}
/* Get the stordevice object iff exists and its refcount > 0 */
-static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device)
+static inline struct storvsc_device *must_get_stor_device(
+ struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = (struct storvsc_device *)Device->Extension;
- if (storDevice && atomic_read(&storDevice->RefCount))
- atomic_inc(&storDevice->RefCount);
+ stor_device = (struct storvsc_device *)device->Extension;
+ if (stor_device && atomic_read(&stor_device->ref_count))
+ atomic_inc(&stor_device->ref_count);
else
- storDevice = NULL;
+ stor_device = NULL;
- return storDevice;
+ return stor_device;
}
-static inline void PutStorDevice(struct hv_device *Device)
+static inline void put_stor_device(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
+ stor_device = (struct storvsc_device *)device->Extension;
+ /* ASSERT(stor_device); */
- atomic_dec(&storDevice->RefCount);
- /* ASSERT(atomic_read(&storDevice->RefCount)); */
+ atomic_dec(&stor_device->ref_count);
+ /* ASSERT(atomic_read(&stor_device->ref_count)); */
}
-/* Drop ref count to 1 to effectively disable GetStorDevice() */
-static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device)
+/* Drop ref count to 1 to effectively disable get_stor_device() */
+static inline struct storvsc_device *release_stor_device(
+ struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
+ stor_device = (struct storvsc_device *)device->Extension;
+ /* ASSERT(stor_device); */
/* Busy wait until the ref drop to 2, then set it to 1 */
- while (atomic_cmpxchg(&storDevice->RefCount, 2, 1) != 2)
+ while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2)
udelay(100);
- return storDevice;
+ return stor_device;
}
-/* Drop ref count to 0. No one can use StorDevice object. */
-static inline struct storvsc_device *FinalReleaseStorDevice(
- struct hv_device *Device)
+/* Drop ref count to 0. No one can use stor_device object. */
+static inline struct storvsc_device *final_release_stor_device(
+ struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
+ stor_device = (struct storvsc_device *)device->Extension;
+ /* ASSERT(stor_device); */
/* Busy wait until the ref drop to 1, then set it to 0 */
- while (atomic_cmpxchg(&storDevice->RefCount, 1, 0) != 1)
+ while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1)
udelay(100);
- Device->Extension = NULL;
- return storDevice;
+ device->Extension = NULL;
+ return stor_device;
}
-static int StorVscChannelInit(struct hv_device *Device)
+static int stor_vsc_channel_init(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
struct storvsc_request_extension *request;
- struct vstor_packet *vstorPacket;
+ struct vstor_packet *vstor_packet;
int ret;
- storDevice = GetStorDevice(Device);
- if (!storDevice) {
+ stor_device = get_stor_device(device);
+ if (!stor_device) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
return -1;
}
- request = &storDevice->InitRequest;
- vstorPacket = &request->VStorPacket;
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
/*
* Now, initiate the vsc/vsp initialization protocol on the open
* channel
*/
memset(request, 0, sizeof(struct storvsc_request_extension));
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
+ request->wait_event = osd_waitevent_create();
+ if (!request->wait_event) {
ret = -ENOMEM;
goto nomem;
}
- vstorPacket->Operation = VStorOperationBeginInitialization;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
/*SpinlockAcquire(gDriverExt.packetListLock);
INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry);
@@ -213,7 +215,7 @@ static int StorVscChannelInit(struct hv_device *Device)
DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION...");
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VmbusPacketTypeDataInBand,
@@ -224,27 +226,27 @@ static int StorVscChannelInit(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->wait_event);
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0) {
DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed "
"(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
+ vstor_packet->operation, vstor_packet->status);
goto Cleanup;
}
DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION...");
/* reuse the packet for version range supported */
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationQueryProtocolVersion;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- vstorPacket->Version.MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT;
- FILL_VMSTOR_REVISION(vstorPacket->Version.Revision);
+ vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
+ FILL_VMSTOR_REVISION(vstor_packet->version.revision);
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VmbusPacketTypeDataInBand,
@@ -255,27 +257,27 @@ static int StorVscChannelInit(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->wait_event);
/* TODO: Check returned version */
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0) {
DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed "
"(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
+ vstor_packet->operation, vstor_packet->status);
goto Cleanup;
}
/* Query channel properties */
DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION...");
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationQueryProperties;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
- vstorPacket->StorageChannelProperties.PortNumber =
- storDevice->PortNumber;
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->storage_channel_properties.port_number =
+ stor_device->port_number;
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VmbusPacketTypeDataInBand,
@@ -287,31 +289,32 @@ static int StorVscChannelInit(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->wait_event);
/* TODO: Check returned version */
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0) {
DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed "
"(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
+ vstor_packet->operation, vstor_packet->status);
goto Cleanup;
}
- storDevice->PathId = vstorPacket->StorageChannelProperties.PathId;
- storDevice->TargetId = vstorPacket->StorageChannelProperties.TargetId;
+ stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
+ stor_device->target_id
+ = vstor_packet->storage_channel_properties.target_id;
DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x",
- vstorPacket->StorageChannelProperties.Flags,
- vstorPacket->StorageChannelProperties.MaxTransferBytes);
+ vstor_packet->storage_channel_properties.flags,
+ vstor_packet->storage_channel_properties.max_transfer_bytes);
DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION...");
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationEndInitialization;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VmbusPacketTypeDataInBand,
@@ -323,125 +326,125 @@ static int StorVscChannelInit(struct hv_device *Device)
goto Cleanup;
}
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->wait_event);
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0) {
DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed "
"(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
+ vstor_packet->operation, vstor_packet->status);
goto Cleanup;
}
DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****");
Cleanup:
- kfree(request->WaitEvent);
- request->WaitEvent = NULL;
+ kfree(request->wait_event);
+ request->wait_event = NULL;
nomem:
- PutStorDevice(Device);
+ put_stor_device(device);
return ret;
}
-static void StorVscOnIOCompletion(struct hv_device *Device,
- struct vstor_packet *VStorPacket,
- struct storvsc_request_extension *RequestExt)
+static void stor_vsc_on_io_completion(struct hv_device *device,
+ struct vstor_packet *vstor_packet,
+ struct storvsc_request_extension *request_ext)
{
struct hv_storvsc_request *request;
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
- storDevice = MustGetStorDevice(Device);
- if (!storDevice) {
+ stor_device = must_get_stor_device(device);
+ if (!stor_device) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
return;
}
DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p "
- "completed bytes xfer %u", RequestExt,
- VStorPacket->VmSrb.DataTransferLength);
+ "completed bytes xfer %u", request_ext,
+ vstor_packet->vm_srb.data_transfer_length);
- /* ASSERT(RequestExt != NULL); */
- /* ASSERT(RequestExt->Request != NULL); */
+ /* ASSERT(request_ext != NULL); */
+ /* ASSERT(request_ext->request != NULL); */
- request = RequestExt->Request;
+ request = request_ext->request;
/* ASSERT(request->OnIOCompletion != NULL); */
/* Copy over the status...etc */
- request->Status = VStorPacket->VmSrb.ScsiStatus;
+ request->status = vstor_packet->vm_srb.scsi_status;
- if (request->Status != 0 || VStorPacket->VmSrb.SrbStatus != 1) {
+ if (request->status != 0 || vstor_packet->vm_srb.srb_status != 1) {
DPRINT_WARN(STORVSC,
"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
- request->Cdb[0], VStorPacket->VmSrb.ScsiStatus,
- VStorPacket->VmSrb.SrbStatus);
+ request->cdb[0], vstor_packet->vm_srb.scsi_status,
+ vstor_packet->vm_srb.srb_status);
}
- if ((request->Status & 0xFF) == 0x02) {
+ if ((request->status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
- if (VStorPacket->VmSrb.SrbStatus & 0x80) {
+ if (vstor_packet->vm_srb.srb_status & 0x80) {
/* autosense data available */
DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data "
- "valid - len %d\n", RequestExt,
- VStorPacket->VmSrb.SenseInfoLength);
+ "valid - len %d\n", request_ext,
+ vstor_packet->vm_srb.sense_info_length);
- /* ASSERT(VStorPacket->VmSrb.SenseInfoLength <= */
+ /* ASSERT(vstor_packet->vm_srb.sense_info_length <= */
/* request->SenseBufferSize); */
- memcpy(request->SenseBuffer,
- VStorPacket->VmSrb.SenseData,
- VStorPacket->VmSrb.SenseInfoLength);
+ memcpy(request->sense_buffer,
+ vstor_packet->vm_srb.sense_data,
+ vstor_packet->vm_srb.sense_info_length);
- request->SenseBufferSize =
- VStorPacket->VmSrb.SenseInfoLength;
+ request->sense_buffer_size =
+ vstor_packet->vm_srb.sense_info_length;
}
}
/* TODO: */
- request->BytesXfer = VStorPacket->VmSrb.DataTransferLength;
+ request->bytes_xfer = vstor_packet->vm_srb.data_transfer_length;
- request->OnIOCompletion(request);
+ request->on_io_completion(request);
- atomic_dec(&storDevice->NumOutstandingRequests);
+ atomic_dec(&stor_device->num_outstanding_req);
- PutStorDevice(Device);
+ put_stor_device(device);
}
-static void StorVscOnReceive(struct hv_device *Device,
- struct vstor_packet *VStorPacket,
- struct storvsc_request_extension *RequestExt)
+static void stor_vsc_on_receive(struct hv_device *device,
+ struct vstor_packet *vstor_packet,
+ struct storvsc_request_extension *request_ext)
{
- switch (VStorPacket->Operation) {
- case VStorOperationCompleteIo:
+ switch (vstor_packet->operation) {
+ case VSTOR_OPERATION_COMPLETE_IO:
DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION");
- StorVscOnIOCompletion(Device, VStorPacket, RequestExt);
+ stor_vsc_on_io_completion(device, vstor_packet, request_ext);
break;
- case VStorOperationRemoveDevice:
+ case VSTOR_OPERATION_REMOVE_DEVICE:
DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION");
/* TODO: */
break;
default:
DPRINT_INFO(STORVSC, "Unknown operation received - %d",
- VStorPacket->Operation);
+ vstor_packet->operation);
break;
}
}
-static void StorVscOnChannelCallback(void *context)
+static void stor_vsc_on_channel_callback(void *context)
{
struct hv_device *device = (struct hv_device *)context;
- struct storvsc_device *storDevice;
- u32 bytesRecvd;
- u64 requestId;
+ struct storvsc_device *stor_device;
+ u32 bytes_recvd;
+ u64 request_id;
unsigned char packet[ALIGN_UP(sizeof(struct vstor_packet), 8)];
struct storvsc_request_extension *request;
int ret;
/* ASSERT(device); */
- storDevice = MustGetStorDevice(device);
- if (!storDevice) {
+ stor_device = must_get_stor_device(device);
+ if (!stor_device) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
return;
@@ -450,32 +453,33 @@ static void StorVscOnChannelCallback(void *context)
do {
ret = vmbus_recvpacket(device->channel, packet,
ALIGN_UP(sizeof(struct vstor_packet), 8),
- &bytesRecvd, &requestId);
- if (ret == 0 && bytesRecvd > 0) {
+ &bytes_recvd, &request_id);
+ if (ret == 0 && bytes_recvd > 0) {
DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx",
- bytesRecvd, requestId);
+ bytes_recvd, request_id);
- /* ASSERT(bytesRecvd == sizeof(struct vstor_packet)); */
+ /* ASSERT(bytes_recvd ==
+ sizeof(struct vstor_packet)); */
request = (struct storvsc_request_extension *)
- (unsigned long)requestId;
+ (unsigned long)request_id;
/* ASSERT(request);c */
- /* if (vstorPacket.Flags & SYNTHETIC_FLAG) */
- if ((request == &storDevice->InitRequest) ||
- (request == &storDevice->ResetRequest)) {
+ /* if (vstor_packet.Flags & SYNTHETIC_FLAG) */
+ if ((request == &stor_device->init_request) ||
+ (request == &stor_device->reset_request)) {
/* DPRINT_INFO(STORVSC,
* "reset completion - operation "
* "%u status %u",
- * vstorPacket.Operation,
- * vstorPacket.Status); */
+ * vstor_packet.Operation,
+ * vstor_packet.Status); */
- memcpy(&request->VStorPacket, packet,
+ memcpy(&request->vstor_packet, packet,
sizeof(struct vstor_packet));
- osd_WaitEventSet(request->WaitEvent);
+ osd_waitevent_set(request->wait_event);
} else {
- StorVscOnReceive(device,
+ stor_vsc_on_receive(device,
(struct vstor_packet *)packet,
request);
}
@@ -485,52 +489,55 @@ static void StorVscOnChannelCallback(void *context)
}
} while (1);
- PutStorDevice(device);
+ put_stor_device(device);
return;
}
-static int StorVscConnectToVsp(struct hv_device *Device)
+static int stor_vsc_connect_to_vsp(struct hv_device *device)
{
struct vmstorage_channel_properties props;
- struct storvsc_driver_object *storDriver;
+ struct storvsc_driver_object *stor_driver;
int ret;
- storDriver = (struct storvsc_driver_object *)Device->Driver;
+ stor_driver = (struct storvsc_driver_object *)device->Driver;
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
/* Open the channel */
- ret = vmbus_open(Device->channel,
- storDriver->RingBufferSize, storDriver->RingBufferSize,
+ ret = vmbus_open(device->channel,
+ stor_driver->ring_buffer_size,
+ stor_driver->ring_buffer_size,
(void *)&props,
sizeof(struct vmstorage_channel_properties),
- StorVscOnChannelCallback, Device);
+ stor_vsc_on_channel_callback, device);
DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d",
- props.PathId, props.TargetId, props.MaxTransferBytes);
+ props.path_id, props.target_id, props.max_transfer_bytes);
if (ret != 0) {
DPRINT_ERR(STORVSC, "unable to open channel: %d", ret);
return -1;
}
- ret = StorVscChannelInit(Device);
+ ret = stor_vsc_channel_init(device);
return ret;
}
/*
- * StorVscOnDeviceAdd - Callback when the device belonging to this driver is added
+ * stor_vsc_on_device_add - Callback when the device belonging to this driver
+ * is added
*/
-static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
+static int stor_vsc_on_device_add(struct hv_device *device,
+ void *additional_info)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
/* struct vmstorage_channel_properties *props; */
- struct storvsc_device_info *deviceInfo;
+ struct storvsc_device_info *device_info;
int ret = 0;
- deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
- storDevice = AllocStorDevice(Device);
- if (!storDevice) {
+ device_info = (struct storvsc_device_info *)additional_info;
+ stor_device = alloc_stor_device(device);
+ if (!stor_device) {
ret = -1;
goto Cleanup;
}
@@ -550,103 +557,103 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
storChannel->PathId = props->PathId;
storChannel->TargetId = props->TargetId; */
- storDevice->PortNumber = deviceInfo->PortNumber;
+ stor_device->port_number = device_info->port_number;
/* Send it back up */
- ret = StorVscConnectToVsp(Device);
+ ret = stor_vsc_connect_to_vsp(device);
- /* deviceInfo->PortNumber = storDevice->PortNumber; */
- deviceInfo->PathId = storDevice->PathId;
- deviceInfo->TargetId = storDevice->TargetId;
+ /* device_info->PortNumber = stor_device->PortNumber; */
+ device_info->path_id = stor_device->path_id;
+ device_info->target_id = stor_device->target_id;
DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n",
- storDevice->PortNumber, storDevice->PathId,
- storDevice->TargetId);
+ stor_device->port_number, stor_device->path_id,
+ stor_device->target_id);
Cleanup:
return ret;
}
/*
- * StorVscOnDeviceRemove - Callback when the our device is being removed
+ * stor_vsc_on_device_remove - Callback when the our device is being removed
*/
-static int StorVscOnDeviceRemove(struct hv_device *Device)
+static int stor_vsc_on_device_remove(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
DPRINT_INFO(STORVSC, "disabling storage device (%p)...",
- Device->Extension);
+ device->Extension);
- storDevice = ReleaseStorDevice(Device);
+ stor_device = release_stor_device(device);
/*
* At this point, all outbound traffic should be disable. We
* only allow inbound traffic (responses) to proceed so that
* outstanding requests can be completed.
*/
- while (atomic_read(&storDevice->NumOutstandingRequests)) {
+ while (atomic_read(&stor_device->num_outstanding_req)) {
DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- atomic_read(&storDevice->NumOutstandingRequests));
+ atomic_read(&stor_device->num_outstanding_req));
udelay(100);
}
DPRINT_INFO(STORVSC, "removing storage device (%p)...",
- Device->Extension);
+ device->Extension);
- storDevice = FinalReleaseStorDevice(Device);
+ stor_device = final_release_stor_device(device);
- DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice);
+ DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", stor_device);
/* Close the channel */
- vmbus_close(Device->channel);
+ vmbus_close(device->channel);
- FreeStorDevice(storDevice);
+ free_stor_device(stor_device);
return 0;
}
-int StorVscOnHostReset(struct hv_device *Device)
+int stor_vsc_on_host_reset(struct hv_device *device)
{
- struct storvsc_device *storDevice;
+ struct storvsc_device *stor_device;
struct storvsc_request_extension *request;
- struct vstor_packet *vstorPacket;
+ struct vstor_packet *vstor_packet;
int ret;
DPRINT_INFO(STORVSC, "resetting host adapter...");
- storDevice = GetStorDevice(Device);
- if (!storDevice) {
+ stor_device = get_stor_device(device);
+ if (!stor_device) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
return -1;
}
- request = &storDevice->ResetRequest;
- vstorPacket = &request->VStorPacket;
+ request = &stor_device->reset_request;
+ vstor_packet = &request->vstor_packet;
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
+ request->wait_event = osd_waitevent_create();
+ if (!request->wait_event) {
ret = -ENOMEM;
goto Cleanup;
}
- vstorPacket->Operation = VStorOperationResetBus;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
- vstorPacket->VmSrb.PathId = storDevice->PathId;
+ vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->vm_srb.path_id = stor_device->path_id;
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
- (unsigned long)&storDevice->ResetRequest,
+ (unsigned long)&stor_device->reset_request,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d",
- vstorPacket, ret);
+ vstor_packet, ret);
goto Cleanup;
}
/* FIXME: Add a timeout */
- osd_WaitEventWait(request->WaitEvent);
+ osd_waitevent_wait(request->wait_event);
- kfree(request->WaitEvent);
+ kfree(request->wait_event);
DPRINT_INFO(STORVSC, "host adapter reset completed");
/*
@@ -655,118 +662,118 @@ int StorVscOnHostReset(struct hv_device *Device)
*/
Cleanup:
- PutStorDevice(Device);
+ put_stor_device(device);
return ret;
}
/*
- * StorVscOnIORequest - Callback to initiate an I/O request
+ * stor_vsc_on_io_request - Callback to initiate an I/O request
*/
-static int StorVscOnIORequest(struct hv_device *Device,
- struct hv_storvsc_request *Request)
+static int stor_vsc_on_io_request(struct hv_device *device,
+ struct hv_storvsc_request *request)
{
- struct storvsc_device *storDevice;
- struct storvsc_request_extension *requestExtension;
- struct vstor_packet *vstorPacket;
+ struct storvsc_device *stor_device;
+ struct storvsc_request_extension *request_extension;
+ struct vstor_packet *vstor_packet;
int ret = 0;
- requestExtension =
- (struct storvsc_request_extension *)Request->Extension;
- vstorPacket = &requestExtension->VStorPacket;
- storDevice = GetStorDevice(Device);
+ request_extension =
+ (struct storvsc_request_extension *)request->extension;
+ vstor_packet = &request_extension->vstor_packet;
+ stor_device = get_stor_device(device);
DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, "
- "Extension %p", Device, storDevice, Request,
- requestExtension);
+ "Extension %p", device, stor_device, request,
+ request_extension);
DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d",
- Request, Request->DataBuffer.Length, Request->Bus,
- Request->TargetId, Request->LunId, Request->CdbLen);
+ request, request->data_buffer.Length, request->bus,
+ request->target_id, request->lun_id, request->cdb_len);
- if (!storDevice) {
+ if (!stor_device) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
return -2;
}
- /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb,
- * Request->CdbLen); */
+ /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, request->Cdb,
+ * request->CdbLen); */
- requestExtension->Request = Request;
- requestExtension->Device = Device;
+ request_extension->request = request;
+ request_extension->device = device;
- memset(vstorPacket, 0 , sizeof(struct vstor_packet));
+ memset(vstor_packet, 0 , sizeof(struct vstor_packet));
- vstorPacket->Flags |= REQUEST_COMPLETION_FLAG;
+ vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
- vstorPacket->VmSrb.Length = sizeof(struct vmscsi_request);
+ vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
- vstorPacket->VmSrb.PortNumber = Request->Host;
- vstorPacket->VmSrb.PathId = Request->Bus;
- vstorPacket->VmSrb.TargetId = Request->TargetId;
- vstorPacket->VmSrb.Lun = Request->LunId;
+ vstor_packet->vm_srb.port_number = request->host;
+ vstor_packet->vm_srb.path_id = request->bus;
+ vstor_packet->vm_srb.target_id = request->target_id;
+ vstor_packet->vm_srb.lun = request->lun_id;
- vstorPacket->VmSrb.SenseInfoLength = SENSE_BUFFER_SIZE;
+ vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
/* Copy over the scsi command descriptor block */
- vstorPacket->VmSrb.CdbLength = Request->CdbLen;
- memcpy(&vstorPacket->VmSrb.Cdb, Request->Cdb, Request->CdbLen);
+ vstor_packet->vm_srb.cdb_length = request->cdb_len;
+ memcpy(&vstor_packet->vm_srb.cdb, request->cdb, request->cdb_len);
- vstorPacket->VmSrb.DataIn = Request->Type;
- vstorPacket->VmSrb.DataTransferLength = Request->DataBuffer.Length;
+ vstor_packet->vm_srb.data_in = request->type;
+ vstor_packet->vm_srb.data_transfer_length = request->data_buffer.Length;
- vstorPacket->Operation = VStorOperationExecuteSRB;
+ vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, "
"lun %d senselen %d cdblen %d",
- vstorPacket->VmSrb.Length,
- vstorPacket->VmSrb.PortNumber,
- vstorPacket->VmSrb.PathId,
- vstorPacket->VmSrb.TargetId,
- vstorPacket->VmSrb.Lun,
- vstorPacket->VmSrb.SenseInfoLength,
- vstorPacket->VmSrb.CdbLength);
-
- if (requestExtension->Request->DataBuffer.Length) {
- ret = vmbus_sendpacket_multipagebuffer(Device->channel,
- &requestExtension->Request->DataBuffer,
- vstorPacket,
+ vstor_packet->vm_srb.length,
+ vstor_packet->vm_srb.port_number,
+ vstor_packet->vm_srb.path_id,
+ vstor_packet->vm_srb.target_id,
+ vstor_packet->vm_srb.lun,
+ vstor_packet->vm_srb.sense_info_length,
+ vstor_packet->vm_srb.cdb_length);
+
+ if (request_extension->request->data_buffer.Length) {
+ ret = vmbus_sendpacket_multipagebuffer(device->channel,
+ &request_extension->request->data_buffer,
+ vstor_packet,
sizeof(struct vstor_packet),
- (unsigned long)requestExtension);
+ (unsigned long)request_extension);
} else {
- ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
- (unsigned long)requestExtension,
+ (unsigned long)request_extension,
VmbusPacketTypeDataInBand,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
}
if (ret != 0) {
DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d",
- vstorPacket, ret);
+ vstor_packet, ret);
}
- atomic_inc(&storDevice->NumOutstandingRequests);
+ atomic_inc(&stor_device->num_outstanding_req);
- PutStorDevice(Device);
+ put_stor_device(device);
return ret;
}
/*
- * StorVscOnCleanup - Perform any cleanup when the driver is removed
+ * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed
*/
-static void StorVscOnCleanup(struct hv_driver *Driver)
+static void stor_vsc_on_cleanup(struct hv_driver *driver)
{
}
/*
- * StorVscInitialize - Main entry point
+ * stor_vsc_initialize - Main entry point
*/
-int StorVscInitialize(struct hv_driver *Driver)
+int stor_vsc_initialize(struct hv_driver *driver)
{
- struct storvsc_driver_object *storDriver;
+ struct storvsc_driver_object *stor_driver;
- storDriver = (struct storvsc_driver_object *)Driver;
+ stor_driver = (struct storvsc_driver_object *)driver;
DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd "
"sizeof(struct storvsc_request_extension)=%zd "
@@ -778,13 +785,14 @@ int StorVscInitialize(struct hv_driver *Driver)
sizeof(struct vmscsi_request));
/* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
+ /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */
- Driver->name = gDriverName;
- memcpy(&Driver->deviceType, &gStorVscDeviceType,
+ driver->name = g_driver_name;
+ memcpy(&driver->deviceType, &gStorVscDeviceType,
sizeof(struct hv_guid));
- storDriver->RequestExtSize = sizeof(struct storvsc_request_extension);
+ stor_driver->request_ext_size =
+ sizeof(struct storvsc_request_extension);
/*
* Divide the ring buffer data size (which is 1 page less
@@ -792,22 +800,22 @@ int StorVscInitialize(struct hv_driver *Driver)
* the ring buffer indices) by the max request size (which is
* vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
*/
- storDriver->MaxOutstandingRequestsPerChannel =
- ((storDriver->RingBufferSize - PAGE_SIZE) /
+ stor_driver->max_outstanding_req_per_channel =
+ ((stor_driver->ring_buffer_size - PAGE_SIZE) /
ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET +
sizeof(struct vstor_packet) + sizeof(u64),
sizeof(u64)));
DPRINT_INFO(STORVSC, "max io %u, currently %u\n",
- storDriver->MaxOutstandingRequestsPerChannel,
+ stor_driver->max_outstanding_req_per_channel,
STORVSC_MAX_IO_REQUESTS);
/* Setup the dispatch table */
- storDriver->Base.OnDeviceAdd = StorVscOnDeviceAdd;
- storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove;
- storDriver->Base.OnCleanup = StorVscOnCleanup;
+ stor_driver->base.OnDeviceAdd = stor_vsc_on_device_add;
+ stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove;
+ stor_driver->base.OnCleanup = stor_vsc_on_cleanup;
- storDriver->OnIORequest = StorVscOnIORequest;
+ stor_driver->on_io_request = stor_vsc_on_io_request;
return 0;
}
diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h
index 8505a1c5f9ee..fbf57556d890 100644
--- a/drivers/staging/hv/storvsc_api.h
+++ b/drivers/staging/hv/storvsc_api.h
@@ -53,58 +53,58 @@ enum storvsc_request_type{
};
struct hv_storvsc_request {
- enum storvsc_request_type Type;
- u32 Host;
- u32 Bus;
- u32 TargetId;
- u32 LunId;
- u8 *Cdb;
- u32 CdbLen;
- u32 Status;
- u32 BytesXfer;
+ enum storvsc_request_type type;
+ u32 host;
+ u32 bus;
+ u32 target_id;
+ u32 lun_id;
+ u8 *cdb;
+ u32 cdb_len;
+ u32 status;
+ u32 bytes_xfer;
- unsigned char *SenseBuffer;
- u32 SenseBufferSize;
+ unsigned char *sense_buffer;
+ u32 sense_buffer_size;
- void *Context;
+ void *context;
- void (*OnIOCompletion)(struct hv_storvsc_request *Request);
+ void (*on_io_completion)(struct hv_storvsc_request *request);
/* This points to the memory after DataBuffer */
- void *Extension;
+ void *extension;
- struct hv_multipage_buffer DataBuffer;
+ struct hv_multipage_buffer data_buffer;
};
/* Represents the block vsc driver */
struct storvsc_driver_object {
/* Must be the first field */
/* Which is a bug FIXME! */
- struct hv_driver Base;
+ struct hv_driver base;
/* Set by caller (in bytes) */
- u32 RingBufferSize;
+ u32 ring_buffer_size;
/* Allocate this much private extension for each I/O request */
- u32 RequestExtSize;
+ u32 request_ext_size;
/* Maximum # of requests in flight per channel/device */
- u32 MaxOutstandingRequestsPerChannel;
+ u32 max_outstanding_req_per_channel;
/* Specific to this driver */
- int (*OnIORequest)(struct hv_device *Device,
- struct hv_storvsc_request *Request);
+ int (*on_io_request)(struct hv_device *device,
+ struct hv_storvsc_request *request);
};
struct storvsc_device_info {
- unsigned int PortNumber;
- unsigned char PathId;
- unsigned char TargetId;
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
};
/* Interface */
-int StorVscInitialize(struct hv_driver *driver);
-int StorVscOnHostReset(struct hv_device *Device);
-int BlkVscInitialize(struct hv_driver *driver);
+int stor_vsc_initialize(struct hv_driver *driver);
+int stor_vsc_on_host_reset(struct hv_device *device);
+int blk_vsc_initialize(struct hv_driver *driver);
#endif /* _STORVSC_API_H_ */
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 41d9acf4cd61..17f1b344fbc5 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -72,8 +72,7 @@ struct storvsc_driver_context {
/* Static decl */
static int storvsc_probe(struct device *dev);
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
- void (*done)(struct scsi_cmnd *));
+static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
static int storvsc_device_alloc(struct scsi_device *);
static int storvsc_device_configure(struct scsi_device *);
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
@@ -141,28 +140,28 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv.drv_obj;
struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx;
- storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size;
+ storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size;
/* Callback to client driver to complete the initialization */
- drv_init(&storvsc_drv_obj->Base);
+ drv_init(&storvsc_drv_obj->base);
DPRINT_INFO(STORVSC_DRV,
"request extension size %u, max outstanding reqs %u",
- storvsc_drv_obj->RequestExtSize,
- storvsc_drv_obj->MaxOutstandingRequestsPerChannel);
+ storvsc_drv_obj->request_ext_size,
+ storvsc_drv_obj->max_outstanding_req_per_channel);
- if (storvsc_drv_obj->MaxOutstandingRequestsPerChannel <
+ if (storvsc_drv_obj->max_outstanding_req_per_channel <
STORVSC_MAX_IO_REQUESTS) {
DPRINT_ERR(STORVSC_DRV,
"The number of outstanding io requests (%d) "
"is larger than that supported (%d) internally.",
STORVSC_MAX_IO_REQUESTS,
- storvsc_drv_obj->MaxOutstandingRequestsPerChannel);
+ storvsc_drv_obj->max_outstanding_req_per_channel);
return -1;
}
- drv_ctx->driver.name = storvsc_drv_obj->Base.name;
- memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType,
+ drv_ctx->driver.name = storvsc_drv_obj->base.name;
+ memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType,
sizeof(struct hv_guid));
drv_ctx->probe = storvsc_probe;
@@ -207,8 +206,8 @@ static void storvsc_drv_exit(void)
device_unregister(current_dev);
}
- if (storvsc_drv_obj->Base.OnCleanup)
- storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base);
+ if (storvsc_drv_obj->base.OnCleanup)
+ storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base);
vmbus_child_driver_unregister(drv_ctx);
return;
@@ -232,7 +231,7 @@ static int storvsc_probe(struct device *device)
struct host_device_context *host_device_ctx;
struct storvsc_device_info device_info;
- if (!storvsc_drv_obj->Base.OnDeviceAdd)
+ if (!storvsc_drv_obj->base.OnDeviceAdd)
return -1;
host = scsi_host_alloc(&scsi_driver,
@@ -253,7 +252,7 @@ static int storvsc_probe(struct device *device)
host_device_ctx->request_pool =
kmem_cache_create(dev_name(&device_ctx->device),
sizeof(struct storvsc_cmd_request) +
- storvsc_drv_obj->RequestExtSize, 0,
+ storvsc_drv_obj->request_ext_size, 0,
SLAB_HWCACHE_ALIGN, NULL);
if (!host_device_ctx->request_pool) {
@@ -261,9 +260,9 @@ static int storvsc_probe(struct device *device)
return -ENOMEM;
}
- device_info.PortNumber = host->host_no;
+ device_info.port_number = host->host_no;
/* Call to the vsc driver to add the device */
- ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj,
+ ret = storvsc_drv_obj->base.OnDeviceAdd(device_obj,
(void *)&device_info);
if (ret != 0) {
DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device");
@@ -273,8 +272,8 @@ static int storvsc_probe(struct device *device)
}
/* host_device_ctx->port = device_info.PortNumber; */
- host_device_ctx->path = device_info.PathId;
- host_device_ctx->target = device_info.TargetId;
+ host_device_ctx->path = device_info.path_id;
+ host_device_ctx->target = device_info.target_id;
/* max # of devices per target */
host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
@@ -288,7 +287,7 @@ static int storvsc_probe(struct device *device)
if (ret != 0) {
DPRINT_ERR(STORVSC_DRV, "unable to add scsi host device");
- storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
+ storvsc_drv_obj->base.OnDeviceRemove(device_obj);
kmem_cache_destroy(host_device_ctx->request_pool);
scsi_host_put(host);
@@ -318,14 +317,14 @@ static int storvsc_remove(struct device *device)
(struct host_device_context *)host->hostdata;
- if (!storvsc_drv_obj->Base.OnDeviceRemove)
+ if (!storvsc_drv_obj->base.OnDeviceRemove)
return -1;
/*
* Call to the vsc driver to let it know that the device is being
* removed
*/
- ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
+ ret = storvsc_drv_obj->base.OnDeviceRemove(device_obj);
if (ret != 0) {
/* TODO: */
DPRINT_ERR(STORVSC, "unable to remove vsc device (ret %d)",
@@ -351,7 +350,7 @@ static int storvsc_remove(struct device *device)
static void storvsc_commmand_completion(struct hv_storvsc_request *request)
{
struct storvsc_cmd_request *cmd_request =
- (struct storvsc_cmd_request *)request->Context;
+ (struct storvsc_cmd_request *)request->context;
struct scsi_cmnd *scmnd = cmd_request->cmd;
struct host_device_context *host_device_ctx =
(struct host_device_context *)scmnd->device->host->hostdata;
@@ -376,16 +375,17 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
cmd_request->bounce_sgl_count);
}
- scmnd->result = request->Status;
+ scmnd->result = request->status;
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
- request->SenseBufferSize, &sense_hdr))
+ request->sense_buffer_size, &sense_hdr))
scsi_print_sense_hdr("storvsc", &sense_hdr);
}
- /* ASSERT(request->BytesXfer <= request->DataBuffer.Length); */
- scsi_set_resid(scmnd, request->DataBuffer.Length - request->BytesXfer);
+ /* ASSERT(request->BytesXfer <= request->data_buffer.Length); */
+ scsi_set_resid(scmnd,
+ request->data_buffer.Length - request->bytes_xfer);
scsi_done_fn = scmnd->scsi_done;
@@ -595,7 +595,7 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
/*
* storvsc_queuecommand - Initiate command processing
*/
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
+static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
int ret;
@@ -658,42 +658,42 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
request = &cmd_request->request;
- request->Extension =
+ request->extension =
(void *)((unsigned long)cmd_request + request_size);
DPRINT_DBG(STORVSC_DRV, "req %p size %d ext %d", request, request_size,
- storvsc_drv_obj->RequestExtSize);
+ storvsc_drv_obj->request_ext_size);
/* Build the SRB */
switch (scmnd->sc_data_direction) {
case DMA_TO_DEVICE:
- request->Type = WRITE_TYPE;
+ request->type = WRITE_TYPE;
break;
case DMA_FROM_DEVICE:
- request->Type = READ_TYPE;
+ request->type = READ_TYPE;
break;
default:
- request->Type = UNKNOWN_TYPE;
+ request->type = UNKNOWN_TYPE;
break;
}
- request->OnIOCompletion = storvsc_commmand_completion;
- request->Context = cmd_request;/* scmnd; */
+ request->on_io_completion = storvsc_commmand_completion;
+ request->context = cmd_request;/* scmnd; */
/* request->PortId = scmnd->device->channel; */
- request->Host = host_device_ctx->port;
- request->Bus = scmnd->device->channel;
- request->TargetId = scmnd->device->id;
- request->LunId = scmnd->device->lun;
+ request->host = host_device_ctx->port;
+ request->bus = scmnd->device->channel;
+ request->target_id = scmnd->device->id;
+ request->lun_id = scmnd->device->lun;
/* ASSERT(scmnd->cmd_len <= 16); */
- request->CdbLen = scmnd->cmd_len;
- request->Cdb = scmnd->cmnd;
+ request->cdb_len = scmnd->cmd_len;
+ request->cdb = scmnd->cmnd;
- request->SenseBuffer = scmnd->sense_buffer;
- request->SenseBufferSize = SCSI_SENSE_BUFFERSIZE;
+ request->sense_buffer = scmnd->sense_buffer;
+ request->sense_buffer_size = SCSI_SENSE_BUFFERSIZE;
- request->DataBuffer.Length = scsi_bufflen(scmnd);
+ request->data_buffer.Length = scsi_bufflen(scmnd);
if (scsi_sg_count(scmnd)) {
sgl = (struct scatterlist *)scsi_sglist(scmnd);
sg_count = scsi_sg_count(scmnd);
@@ -734,25 +734,25 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
sg_count = cmd_request->bounce_sgl_count;
}
- request->DataBuffer.Offset = sgl[0].offset;
+ request->data_buffer.Offset = sgl[0].offset;
for (i = 0; i < sg_count; i++) {
DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n",
i, sgl[i].length, sgl[i].offset);
- request->DataBuffer.PfnArray[i] =
+ request->data_buffer.PfnArray[i] =
page_to_pfn(sg_page((&sgl[i])));
}
} else if (scsi_sglist(scmnd)) {
/* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */
- request->DataBuffer.Offset =
+ request->data_buffer.Offset =
virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
- request->DataBuffer.PfnArray[0] =
+ request->data_buffer.PfnArray[0] =
virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
}
retry_request:
/* Invokes the vsc to start an IO */
- ret = storvsc_drv_obj->OnIORequest(&device_ctx->device_obj,
+ ret = storvsc_drv_obj->on_io_request(&device_ctx->device_obj,
&cmd_request->request);
if (ret == -1) {
/* no more space */
@@ -783,6 +783,8 @@ retry_request:
return ret;
}
+static DEF_SCSI_QCMD(storvsc_queuecommand)
+
static int storvsc_merge_bvec(struct request_queue *q,
struct bvec_merge_data *bmd, struct bio_vec *bvec)
{
@@ -843,7 +845,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
scmnd->device, &device_ctx->device_obj);
/* Invokes the vsc to reset the host/bus */
- ret = StorVscOnHostReset(&device_ctx->device_obj);
+ ret = stor_vsc_on_host_reset(&device_ctx->device_obj);
if (ret != 0)
return ret;
@@ -938,7 +940,7 @@ static int __init storvsc_init(void)
int ret;
DPRINT_INFO(STORVSC_DRV, "Storvsc initializing....");
- ret = storvsc_drv_init(StorVscInitialize);
+ ret = storvsc_drv_init(stor_vsc_initialize);
return ret;
}
diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c
deleted file mode 100644
index d449daf81976..000000000000
--- a/drivers/staging/hv/vmbus.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include "osd.h"
-#include "logging.h"
-#include "version_info.h"
-#include "vmbus_private.h"
-
-static const char *gDriverName = "vmbus";
-
-/*
- * Windows vmbus does not defined this.
- * We defined this to be consistent with other devices
- */
-/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
-static const struct hv_guid gVmbusDeviceType = {
- .data = {
- 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
- 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
- }
-};
-
-/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
-static const struct hv_guid gVmbusDeviceId = {
- .data = {
- 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
- 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
- }
-};
-
-static struct hv_driver *gDriver; /* vmbus driver object */
-static struct hv_device *gDevice; /* vmbus root device */
-
-/*
- * VmbusGetChannelOffers - Retrieve the channel offers from the parent partition
- */
-static void VmbusGetChannelOffers(void)
-{
- vmbus_request_offers();
-}
-
-/*
- * VmbusCreateChildDevice - Creates the child device on the bus that represents the channel offer
- */
-struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
- struct hv_guid *DeviceInstance,
- struct vmbus_channel *channel)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance,
- channel);
-}
-
-/*
- * VmbusChildDeviceAdd - Registers the child device with the vmbus
- */
-int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
-}
-
-/*
- * VmbusChildDeviceRemove Unregisters the child device from the vmbus
- */
-void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- vmbusDriver->OnChildDeviceRemove(ChildDevice);
-}
-
-/*
- * VmbusOnDeviceAdd - Callback when the root bus device is added
- */
-static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
-{
- u32 *irqvector = AdditionalInfo;
- int ret;
-
- gDevice = dev;
-
- memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
- memcpy(&gDevice->deviceInstance, &gVmbusDeviceId,
- sizeof(struct hv_guid));
-
- /* strcpy(dev->name, "vmbus"); */
- /* SynIC setup... */
- on_each_cpu(HvSynicInit, (void *)irqvector, 1);
-
- /* Connect to VMBus in the root partition */
- ret = VmbusConnect();
-
- /* VmbusSendEvent(device->localPortId+1); */
- return ret;
-}
-
-/*
- * VmbusOnDeviceRemove - Callback when the root bus device is removed
- */
-static int VmbusOnDeviceRemove(struct hv_device *dev)
-{
- int ret = 0;
-
- vmbus_release_unattached_channels();
- VmbusDisconnect();
- on_each_cpu(HvSynicCleanup, NULL, 1);
- return ret;
-}
-
-/*
- * VmbusOnCleanup - Perform any cleanup when the driver is removed
- */
-static void VmbusOnCleanup(struct hv_driver *drv)
-{
- /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
-
- HvCleanup();
-}
-
-/*
- * VmbusOnMsgDPC - DPC routine to handle messages from the hypervisior
- */
-static void VmbusOnMsgDPC(struct hv_driver *drv)
-{
- int cpu = smp_processor_id();
- void *page_addr = gHvContext.synICMessagePage[cpu];
- struct hv_message *msg = (struct hv_message *)page_addr +
- VMBUS_MESSAGE_SINT;
- struct hv_message *copied;
-
- while (1) {
- if (msg->Header.MessageType == HvMessageTypeNone) {
- /* no msg */
- break;
- } else {
- copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC);
- if (copied == NULL)
- continue;
-
- osd_schedule_callback(gVmbusConnection.WorkQueue,
- vmbus_onmessage,
- (void *)copied);
- }
-
- msg->Header.MessageType = HvMessageTypeNone;
-
- /*
- * Make sure the write to MessageType (ie set to
- * HvMessageTypeNone) happens before we read the
- * MessagePending and EOMing. Otherwise, the EOMing
- * will not deliver any more messages since there is
- * no empty slot
- */
- mb();
-
- if (msg->Header.MessageFlags.MessagePending) {
- /*
- * This will cause message queue rescan to
- * possibly deliver another msg from the
- * hypervisor
- */
- wrmsrl(HV_X64_MSR_EOM, 0);
- }
- }
-}
-
-/*
- * VmbusOnEventDPC - DPC routine to handle events from the hypervisior
- */
-static void VmbusOnEventDPC(struct hv_driver *drv)
-{
- /* TODO: Process any events */
- VmbusOnEvents();
-}
-
-/*
- * VmbusOnISR - ISR routine
- */
-static int VmbusOnISR(struct hv_driver *drv)
-{
- int ret = 0;
- int cpu = smp_processor_id();
- void *page_addr;
- struct hv_message *msg;
- union hv_synic_event_flags *event;
-
- page_addr = gHvContext.synICMessagePage[cpu];
- msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
-
- /* Check if there are actual msgs to be process */
- if (msg->Header.MessageType != HvMessageTypeNone) {
- DPRINT_DBG(VMBUS, "received msg type %d size %d",
- msg->Header.MessageType,
- msg->Header.PayloadSize);
- ret |= 0x1;
- }
-
- /* TODO: Check if there are events to be process */
- page_addr = gHvContext.synICEventPage[cpu];
- event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
-
- /* Since we are a child, we only need to check bit 0 */
- if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) {
- DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
- ret |= 0x2;
- }
-
- return ret;
-}
-
-/*
- * VmbusInitialize - Main entry point
- */
-int VmbusInitialize(struct hv_driver *drv)
-{
- struct vmbus_driver *driver = (struct vmbus_driver *)drv;
- int ret;
-
- DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
- HV_DRV_VERSION);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
- VMBUS_REVISION_NUMBER);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
- VMBUS_MESSAGE_SINT);
- DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, "
- "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
- sizeof(struct vmbus_channel_packet_page_buffer),
- sizeof(struct vmbus_channel_packet_multipage_buffer));
-
- drv->name = gDriverName;
- memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
-
- /* Setup dispatch table */
- driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
- driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
- driver->Base.OnCleanup = VmbusOnCleanup;
- driver->OnIsr = VmbusOnISR;
- driver->OnMsgDpc = VmbusOnMsgDPC;
- driver->OnEventDpc = VmbusOnEventDPC;
- driver->GetChannelOffers = VmbusGetChannelOffers;
-
- /* Hypervisor initialization...setup hypercall page..etc */
- ret = HvInit();
- if (ret != 0)
- DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
- ret);
- gDriver = drv;
-
- return ret;
-}
diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h
index 2af42e550076..2da3f52610b3 100644
--- a/drivers/staging/hv/vmbus_api.h
+++ b/drivers/staging/hv/vmbus_api.h
@@ -115,28 +115,4 @@ struct hv_device {
void *Extension;
};
-/* Vmbus driver object */
-struct vmbus_driver {
- /* !! Must be the 1st field !! */
- /* FIXME if ^, then someone is doing somthing stupid */
- struct hv_driver Base;
-
- /* Set by the caller */
- struct hv_device * (*OnChildDeviceCreate)(struct hv_guid *DeviceType,
- struct hv_guid *DeviceInstance,
- struct vmbus_channel *channel);
- void (*OnChildDeviceDestroy)(struct hv_device *device);
- int (*OnChildDeviceAdd)(struct hv_device *RootDevice,
- struct hv_device *ChildDevice);
- void (*OnChildDeviceRemove)(struct hv_device *device);
-
- /* Set by the callee */
- int (*OnIsr)(struct hv_driver *driver);
- void (*OnMsgDpc)(struct hv_driver *driver);
- void (*OnEventDpc)(struct hv_driver *driver);
- void (*GetChannelOffers)(void);
-};
-
-int VmbusInitialize(struct hv_driver *drv);
-
#endif /* _VMBUS_API_H_ */
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 0d9f3a411e72..84fdb64d3ceb 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -33,6 +33,7 @@
#include "logging.h"
#include "vmbus.h"
#include "channel.h"
+#include "vmbus_private.h"
/* FIXME! We need to do this dynamically for PIC and APIC system */
@@ -46,7 +47,7 @@ struct vmbus_driver_context {
/* The driver field is not used in here. Instead, the bus field is */
/* used to represent the driver */
struct driver_context drv_ctx;
- struct vmbus_driver drv_obj;
+ struct hv_driver drv_obj;
struct bus_type bus;
struct tasklet_struct msg_dpc;
@@ -69,13 +70,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id);
static void vmbus_device_release(struct device *device);
static void vmbus_bus_release(struct device *device);
-static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
- struct hv_guid *instance,
- struct vmbus_channel *channel);
-static void vmbus_child_device_destroy(struct hv_device *device_obj);
-static int vmbus_child_device_register(struct hv_device *root_device_obj,
- struct hv_device *child_device_obj);
-static void vmbus_child_device_unregister(struct hv_device *child_device_obj);
static ssize_t vmbus_show_device_attr(struct device *dev,
struct device_attribute *dev_attr,
char *buf);
@@ -129,6 +123,182 @@ static struct vmbus_driver_context g_vmbus_drv = {
.bus.dev_attrs = vmbus_device_attrs,
};
+static const char *gDriverName = "hyperv";
+
+/*
+ * Windows vmbus does not defined this.
+ * We defined this to be consistent with other devices
+ */
+/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
+static const struct hv_guid gVmbusDeviceType = {
+ .data = {
+ 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
+ 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
+ }
+};
+
+/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
+static const struct hv_guid gVmbusDeviceId = {
+ .data = {
+ 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
+ 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
+ }
+};
+
+static struct hv_device *gDevice; /* vmbus root device */
+
+/*
+ * VmbusChildDeviceAdd - Registers the child device with the vmbus
+ */
+int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
+{
+ return vmbus_child_device_register(gDevice, ChildDevice);
+}
+
+/*
+ * VmbusOnDeviceAdd - Callback when the root bus device is added
+ */
+static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
+{
+ u32 *irqvector = AdditionalInfo;
+ int ret;
+
+ gDevice = dev;
+
+ memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
+ memcpy(&gDevice->deviceInstance, &gVmbusDeviceId,
+ sizeof(struct hv_guid));
+
+ /* strcpy(dev->name, "vmbus"); */
+ /* SynIC setup... */
+ on_each_cpu(hv_synic_init, (void *)irqvector, 1);
+
+ /* Connect to VMBus in the root partition */
+ ret = VmbusConnect();
+
+ /* VmbusSendEvent(device->localPortId+1); */
+ return ret;
+}
+
+/*
+ * VmbusOnDeviceRemove - Callback when the root bus device is removed
+ */
+static int VmbusOnDeviceRemove(struct hv_device *dev)
+{
+ int ret = 0;
+
+ vmbus_release_unattached_channels();
+ VmbusDisconnect();
+ on_each_cpu(hv_synic_cleanup, NULL, 1);
+ return ret;
+}
+
+/*
+ * VmbusOnCleanup - Perform any cleanup when the driver is removed
+ */
+static void VmbusOnCleanup(struct hv_driver *drv)
+{
+ /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
+
+ hv_cleanup();
+}
+
+struct onmessage_work_context {
+ struct work_struct work;
+ struct hv_message msg;
+};
+
+static void vmbus_onmessage_work(struct work_struct *work)
+{
+ struct onmessage_work_context *ctx;
+
+ ctx = container_of(work, struct onmessage_work_context,
+ work);
+ vmbus_onmessage(&ctx->msg);
+ kfree(ctx);
+}
+
+/*
+ * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior
+ */
+static void vmbus_on_msg_dpc(struct hv_driver *drv)
+{
+ int cpu = smp_processor_id();
+ void *page_addr = hv_context.synic_message_page[cpu];
+ struct hv_message *msg = (struct hv_message *)page_addr +
+ VMBUS_MESSAGE_SINT;
+ struct onmessage_work_context *ctx;
+
+ while (1) {
+ if (msg->header.message_type == HVMSG_NONE) {
+ /* no msg */
+ break;
+ } else {
+ ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+ if (ctx == NULL)
+ continue;
+ INIT_WORK(&ctx->work, vmbus_onmessage_work);
+ memcpy(&ctx->msg, msg, sizeof(*msg));
+ queue_work(gVmbusConnection.WorkQueue, &ctx->work);
+ }
+
+ msg->header.message_type = HVMSG_NONE;
+
+ /*
+ * Make sure the write to MessageType (ie set to
+ * HVMSG_NONE) happens before we read the
+ * MessagePending and EOMing. Otherwise, the EOMing
+ * will not deliver any more messages since there is
+ * no empty slot
+ */
+ mb();
+
+ if (msg->header.message_flags.msg_pending) {
+ /*
+ * This will cause message queue rescan to
+ * possibly deliver another msg from the
+ * hypervisor
+ */
+ wrmsrl(HV_X64_MSR_EOM, 0);
+ }
+ }
+}
+
+/*
+ * vmbus_on_isr - ISR routine
+ */
+static int vmbus_on_isr(struct hv_driver *drv)
+{
+ int ret = 0;
+ int cpu = smp_processor_id();
+ void *page_addr;
+ struct hv_message *msg;
+ union hv_synic_event_flags *event;
+
+ page_addr = hv_context.synic_message_page[cpu];
+ msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
+
+ /* Check if there are actual msgs to be process */
+ if (msg->header.message_type != HVMSG_NONE) {
+ DPRINT_DBG(VMBUS, "received msg type %d size %d",
+ msg->header.message_type,
+ msg->header.payload_size);
+ ret |= 0x1;
+ }
+
+ /* TODO: Check if there are events to be process */
+ page_addr = hv_context.synic_event_page[cpu];
+ event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
+
+ /* Since we are a child, we only need to check bit 0 */
+ if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
+ DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]);
+ ret |= 0x2;
+ }
+
+ return ret;
+}
+
static void get_channel_info(struct hv_device *device,
struct hv_device_info *info)
{
@@ -139,35 +309,38 @@ static void get_channel_info(struct hv_device *device,
vmbus_get_debug_info(device->channel, &debug_info);
- info->ChannelId = debug_info.RelId;
- info->ChannelState = debug_info.State;
- memcpy(&info->ChannelType, &debug_info.InterfaceType,
+ info->ChannelId = debug_info.relid;
+ info->ChannelState = debug_info.state;
+ memcpy(&info->ChannelType, &debug_info.interfacetype,
sizeof(struct hv_guid));
- memcpy(&info->ChannelInstance, &debug_info.InterfaceInstance,
+ memcpy(&info->ChannelInstance, &debug_info.interface_instance,
sizeof(struct hv_guid));
- info->MonitorId = debug_info.MonitorId;
-
- info->ServerMonitorPending = debug_info.ServerMonitorPending;
- info->ServerMonitorLatency = debug_info.ServerMonitorLatency;
- info->ServerMonitorConnectionId = debug_info.ServerMonitorConnectionId;
-
- info->ClientMonitorPending = debug_info.ClientMonitorPending;
- info->ClientMonitorLatency = debug_info.ClientMonitorLatency;
- info->ClientMonitorConnectionId = debug_info.ClientMonitorConnectionId;
-
- info->Inbound.InterruptMask = debug_info.Inbound.CurrentInterruptMask;
- info->Inbound.ReadIndex = debug_info.Inbound.CurrentReadIndex;
- info->Inbound.WriteIndex = debug_info.Inbound.CurrentWriteIndex;
- info->Inbound.BytesAvailToRead = debug_info.Inbound.BytesAvailToRead;
- info->Inbound.BytesAvailToWrite = debug_info.Inbound.BytesAvailToWrite;
-
- info->Outbound.InterruptMask = debug_info.Outbound.CurrentInterruptMask;
- info->Outbound.ReadIndex = debug_info.Outbound.CurrentReadIndex;
- info->Outbound.WriteIndex = debug_info.Outbound.CurrentWriteIndex;
- info->Outbound.BytesAvailToRead = debug_info.Outbound.BytesAvailToRead;
+ info->MonitorId = debug_info.monitorid;
+
+ info->ServerMonitorPending = debug_info.servermonitor_pending;
+ info->ServerMonitorLatency = debug_info.servermonitor_latency;
+ info->ServerMonitorConnectionId = debug_info.servermonitor_connectionid;
+
+ info->ClientMonitorPending = debug_info.clientmonitor_pending;
+ info->ClientMonitorLatency = debug_info.clientmonitor_latency;
+ info->ClientMonitorConnectionId = debug_info.clientmonitor_connectionid;
+
+ info->Inbound.InterruptMask = debug_info.inbound.current_interrupt_mask;
+ info->Inbound.ReadIndex = debug_info.inbound.current_read_index;
+ info->Inbound.WriteIndex = debug_info.inbound.current_write_index;
+ info->Inbound.BytesAvailToRead = debug_info.inbound.bytes_avail_toread;
+ info->Inbound.BytesAvailToWrite =
+ debug_info.inbound.bytes_avail_towrite;
+
+ info->Outbound.InterruptMask =
+ debug_info.outbound.current_interrupt_mask;
+ info->Outbound.ReadIndex = debug_info.outbound.current_read_index;
+ info->Outbound.WriteIndex = debug_info.outbound.current_write_index;
+ info->Outbound.BytesAvailToRead =
+ debug_info.outbound.bytes_avail_toread;
info->Outbound.BytesAvailToWrite =
- debug_info.Outbound.BytesAvailToWrite;
+ debug_info.outbound.bytes_avail_towrite;
}
/*
@@ -286,44 +459,55 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
* - setup the vmbus root device
* - retrieve the channel offers
*/
-static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
+static int vmbus_bus_init(void)
{
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
- struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
+ struct hv_driver *driver = &g_vmbus_drv.drv_obj;
struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
int ret;
unsigned int vector;
- /*
- * Set this up to allow lower layer to callback to add/remove child
- * devices on the bus
- */
- vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create;
- vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy;
- vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register;
- vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister;
-
- /* Call to bus driver to initialize */
- ret = drv_init(&vmbus_drv_obj->Base);
+ DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
+ HV_DRV_VERSION);
+ DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
+ VMBUS_REVISION_NUMBER);
+ DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
+ VMBUS_MESSAGE_SINT);
+ DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, "
+ "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
+ sizeof(struct vmbus_channel_packet_page_buffer),
+ sizeof(struct vmbus_channel_packet_multipage_buffer));
+
+ driver->name = gDriverName;
+ memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
+
+ /* Setup dispatch table */
+ driver->OnDeviceAdd = VmbusOnDeviceAdd;
+ driver->OnDeviceRemove = VmbusOnDeviceRemove;
+ driver->OnCleanup = VmbusOnCleanup;
+
+ /* Hypervisor initialization...setup hypercall page..etc */
+ ret = hv_init();
if (ret != 0) {
- DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
+ DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
+ ret);
goto cleanup;
}
/* Sanity checks */
- if (!vmbus_drv_obj->Base.OnDeviceAdd) {
+ if (!driver->OnDeviceAdd) {
DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
ret = -1;
goto cleanup;
}
- vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
+ vmbus_drv_ctx->bus.name = driver->name;
/* Initialize the bus context */
tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc,
- (unsigned long)vmbus_drv_obj);
+ (unsigned long)driver);
tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc,
- (unsigned long)vmbus_drv_obj);
+ (unsigned long)driver);
/* Now, register the bus driver with LDM */
ret = bus_register(&vmbus_drv_ctx->bus);
@@ -334,7 +518,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
/* Get the interrupt resource */
ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM,
- vmbus_drv_obj->Base.name, NULL);
+ driver->name, NULL);
if (ret != 0) {
DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d",
@@ -352,7 +536,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
/* Call to bus driver to add the root device */
memset(dev_ctx, 0, sizeof(struct vm_device));
- ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
+ ret = driver->OnDeviceAdd(&dev_ctx->device_obj, &vector);
if (ret != 0) {
DPRINT_ERR(VMBUS_DRV,
"ERROR - Unable to add vmbus root device");
@@ -392,9 +576,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
goto cleanup;
}
-
- vmbus_drv_obj->GetChannelOffers();
-
+ vmbus_request_offers();
wait_for_completion(&hv_channel_ready);
cleanup:
@@ -408,17 +590,17 @@ cleanup:
*/
static void vmbus_bus_exit(void)
{
- struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
+ struct hv_driver *driver = &g_vmbus_drv.drv_obj;
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
/* Remove the root device */
- if (vmbus_drv_obj->Base.OnDeviceRemove)
- vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
+ if (driver->OnDeviceRemove)
+ driver->OnDeviceRemove(&dev_ctx->device_obj);
- if (vmbus_drv_obj->Base.OnCleanup)
- vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
+ if (driver->OnCleanup)
+ driver->OnCleanup(driver);
/* Unregister the root bus device */
device_unregister(&dev_ctx->device);
@@ -446,7 +628,6 @@ static void vmbus_bus_exit(void)
*/
int vmbus_child_driver_register(struct driver_context *driver_ctx)
{
- struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
int ret;
DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
@@ -457,7 +638,7 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx)
ret = driver_register(&driver_ctx->driver);
- vmbus_drv_obj->GetChannelOffers();
+ vmbus_request_offers();
return ret;
}
@@ -489,9 +670,9 @@ EXPORT_SYMBOL(vmbus_child_driver_unregister);
* vmbus_child_device_create - Creates and registers a new child device
* on the vmbus.
*/
-static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
- struct hv_guid *instance,
- struct vmbus_channel *channel)
+struct hv_device *vmbus_child_device_create(struct hv_guid *type,
+ struct hv_guid *instance,
+ struct vmbus_channel *channel)
{
struct vm_device *child_device_ctx;
struct hv_device *child_device_obj;
@@ -538,8 +719,8 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
/*
* vmbus_child_device_register - Register the child device on the specified bus
*/
-static int vmbus_child_device_register(struct hv_device *root_device_obj,
- struct hv_device *child_device_obj)
+int vmbus_child_device_register(struct hv_device *root_device_obj,
+ struct hv_device *child_device_obj)
{
int ret = 0;
struct vm_device *root_device_ctx =
@@ -583,7 +764,7 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
* vmbus_child_device_unregister - Remove the specified child device
* from the vmbus.
*/
-static void vmbus_child_device_unregister(struct hv_device *device_obj)
+void vmbus_child_device_unregister(struct hv_device *device_obj)
{
struct vm_device *device_ctx = to_vm_device(device_obj);
@@ -601,13 +782,6 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj)
}
/*
- * vmbus_child_device_destroy - Destroy the specified child device on the vmbus.
- */
-static void vmbus_child_device_destroy(struct hv_device *device_obj)
-{
-}
-
-/*
* vmbus_uevent - add uevent for our device
*
* This routine is invoked when a device is added or removed on the vmbus to
@@ -701,7 +875,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct vmbus_driver_context *vmbus_drv_ctx =
(struct vmbus_driver_context *)driver_ctx;
- device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base;
+ device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj;
DPRINT_INFO(VMBUS_DRV,
"device object (%p) set to driver object (%p)",
&device_ctx->device_obj,
@@ -849,7 +1023,6 @@ static void vmbus_device_release(struct device *device)
{
struct vm_device *device_ctx = device_to_vm_device(device);
- /* vmbus_child_device_destroy(&device_ctx->device_obj); */
kfree(device_ctx);
/* !!DO NOT REFERENCE device_ctx anymore at this point!! */
@@ -860,36 +1033,28 @@ static void vmbus_device_release(struct device *device)
*/
static void vmbus_msg_dpc(unsigned long data)
{
- struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
-
- /* ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); */
+ struct hv_driver *driver = (struct hv_driver *)data;
/* Call to bus driver to handle interrupt */
- vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
+ vmbus_on_msg_dpc(driver);
}
/*
- * vmbus_msg_dpc - Tasklet routine to handle hypervisor events
+ * vmbus_event_dpc - Tasklet routine to handle hypervisor events
*/
static void vmbus_event_dpc(unsigned long data)
{
- struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
-
- /* ASSERT(vmbus_drv_obj->OnEventDpc != NULL); */
-
/* Call to bus driver to handle interrupt */
- vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
+ VmbusOnEvents();
}
static irqreturn_t vmbus_isr(int irq, void *dev_id)
{
- struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj;
+ struct hv_driver *driver = &g_vmbus_drv.drv_obj;
int ret;
- /* ASSERT(vmbus_driver_obj->OnIsr != NULL); */
-
/* Call to bus driver to handle interrupt */
- ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
+ ret = vmbus_on_isr(driver);
/* Schedules a dpc if necessary */
if (ret > 0) {
@@ -928,7 +1093,7 @@ static int __init vmbus_init(void)
if (!dmi_check_system(microsoft_hv_dmi_table))
return -ENODEV;
- return vmbus_bus_init(VmbusInitialize);
+ return vmbus_bus_init();
}
static void __exit vmbus_exit(void)
diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h
index 09eaec964b30..07f6d22eeabb 100644
--- a/drivers/staging/hv/vmbus_private.h
+++ b/drivers/staging/hv/vmbus_private.h
@@ -102,13 +102,14 @@ extern struct VMBUS_CONNECTION gVmbusConnection;
/* General vmbus interface */
-struct hv_device *VmbusChildDeviceCreate(struct hv_guid *deviceType,
+struct hv_device *vmbus_child_device_create(struct hv_guid *deviceType,
struct hv_guid *deviceInstance,
struct vmbus_channel *channel);
int VmbusChildDeviceAdd(struct hv_device *Device);
-
-void VmbusChildDeviceRemove(struct hv_device *Device);
+int vmbus_child_device_register(struct hv_device *root_device_obj,
+ struct hv_device *child_device_obj);
+void vmbus_child_device_unregister(struct hv_device *device_obj);
/* static void */
/* VmbusChildDeviceDestroy( */
diff --git a/drivers/staging/hv/vstorage.h b/drivers/staging/hv/vstorage.h
index 4ea597d7a7d7..ae8be84394d5 100644
--- a/drivers/staging/hv/vstorage.h
+++ b/drivers/staging/hv/vstorage.h
@@ -27,15 +27,17 @@
#define REVISION_STRING(REVISION_) #REVISION_
#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \
-{ \
- char *revisionString = REVISION_STRING($Revision : 6 $) + 11; \
- RESULT_LVALUE_ = 0; \
- while (*revisionString >= '0' && *revisionString <= '9') { \
- RESULT_LVALUE_ *= 10; \
- RESULT_LVALUE_ += *revisionString - '0'; \
- revisionString++; \
- } \
-}
+ do { \
+ char *revision_string \
+ = REVISION_STRING($Rev : 6 $) + 6; \
+ RESULT_LVALUE_ = 0; \
+ while (*revision_string >= '0' \
+ && *revision_string <= '9') { \
+ RESULT_LVALUE_ *= 10; \
+ RESULT_LVALUE_ += *revision_string - '0'; \
+ revision_string++; \
+ } \
+ } while (0)
/* Major/minor macros. Minor version is in LSB, meaning that earlier flat */
/* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */
@@ -65,17 +67,17 @@
/* Packet structure describing virtual storage requests. */
enum vstor_packet_operation {
- VStorOperationCompleteIo = 1,
- VStorOperationRemoveDevice = 2,
- VStorOperationExecuteSRB = 3,
- VStorOperationResetLun = 4,
- VStorOperationResetAdapter = 5,
- VStorOperationResetBus = 6,
- VStorOperationBeginInitialization = 7,
- VStorOperationEndInitialization = 8,
- VStorOperationQueryProtocolVersion = 9,
- VStorOperationQueryProperties = 10,
- VStorOperationMaximum = 10
+ VSTOR_OPERATION_COMPLETE_IO = 1,
+ VSTOR_OPERATION_REMOVE_DEVICE = 2,
+ VSTOR_OPERATION_EXECUTE_SRB = 3,
+ VSTOR_OPERATION_RESET_LUN = 4,
+ VSTOR_OPERATION_RESET_ADAPTER = 5,
+ VSTOR_OPERATION_RESET_BUS = 6,
+ VSTOR_OPERATION_BEGIN_INITIALIZATION = 7,
+ VSTOR_OPERATION_END_INITIALIZATION = 8,
+ VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9,
+ VSTOR_OPERATION_QUERY_PROPERTIES = 10,
+ VSTOR_OPERATION_MAXIMUM = 10
};
/*
@@ -89,31 +91,29 @@ enum vstor_packet_operation {
#define SENSE_BUFFER_SIZE 0x12
#endif
-#define MAX_DATA_BUFFER_LENGTH_WITH_PADDING 0x14
+#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14
struct vmscsi_request {
- unsigned short Length;
- unsigned char SrbStatus;
- unsigned char ScsiStatus;
+ unsigned short length;
+ unsigned char srb_status;
+ unsigned char scsi_status;
- unsigned char PortNumber;
- unsigned char PathId;
- unsigned char TargetId;
- unsigned char Lun;
+ unsigned char port_number;
+ unsigned char path_id;
+ unsigned char target_id;
+ unsigned char lun;
- unsigned char CdbLength;
- unsigned char SenseInfoLength;
- unsigned char DataIn;
- unsigned char Reserved;
+ unsigned char cdb_length;
+ unsigned char sense_info_length;
+ unsigned char data_in;
+ unsigned char reserved;
- unsigned int DataTransferLength;
+ unsigned int data_transfer_length;
union {
- unsigned char Cdb[CDB16GENERIC_LENGTH];
-
- unsigned char SenseData[SENSE_BUFFER_SIZE];
-
- unsigned char ReservedArray[MAX_DATA_BUFFER_LENGTH_WITH_PADDING];
+ unsigned char cdb[CDB16GENERIC_LENGTH];
+ unsigned char sense_data[SENSE_BUFFER_SIZE];
+ unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
};
} __attribute((packed));
@@ -123,24 +123,24 @@ struct vmscsi_request {
* properties of the channel.
*/
struct vmstorage_channel_properties {
- unsigned short ProtocolVersion;
- unsigned char PathId;
- unsigned char TargetId;
+ unsigned short protocol_version;
+ unsigned char path_id;
+ unsigned char target_id;
/* Note: port number is only really known on the client side */
- unsigned int PortNumber;
- unsigned int Flags;
- unsigned int MaxTransferBytes;
+ unsigned int port_number;
+ unsigned int flags;
+ unsigned int max_transfer_bytes;
/* This id is unique for each channel and will correspond with */
/* vendor specific data in the inquirydata */
- unsigned long long UniqueId;
+ unsigned long long unique_id;
} __attribute__((packed));
/* This structure is sent during the storage protocol negotiations. */
struct vmstorage_protocol_version {
/* Major (MSW) and minor (LSW) version numbers. */
- unsigned short MajorMinor;
+ unsigned short major_minor;
/*
* Revision number is auto-incremented whenever this file is changed
@@ -148,7 +148,7 @@ struct vmstorage_protocol_version {
* definitely indicate incompatibility--but it does indicate mismatched
* builds.
*/
- unsigned short Revision;
+ unsigned short revision;
} __attribute__((packed));
/* Channel Property Flags */
@@ -157,13 +157,13 @@ struct vmstorage_protocol_version {
struct vstor_packet {
/* Requested operation type */
- enum vstor_packet_operation Operation;
+ enum vstor_packet_operation operation;
/* Flags - see below for values */
- unsigned int Flags;
+ unsigned int flags;
/* Status of the request returned from the server side. */
- unsigned int Status;
+ unsigned int status;
/* Data payload area */
union {
@@ -171,13 +171,13 @@ struct vstor_packet {
* Structure used to forward SCSI commands from the
* client to the server.
*/
- struct vmscsi_request VmSrb;
+ struct vmscsi_request vm_srb;
/* Structure used to query channel properties. */
- struct vmstorage_channel_properties StorageChannelProperties;
+ struct vmstorage_channel_properties storage_channel_properties;
/* Used during version negotiations. */
- struct vmstorage_protocol_version Version;
+ struct vmstorage_protocol_version version;
};
} __attribute__((packed));
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio
index fdb017a1c1a2..2dde97de75f8 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio
@@ -1,11 +1,12 @@
-What: /sys/bus/iio/devices/device[n]
+What: /sys/bus/iio/devices/deviceX
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
Hardware chip or device accessed by on communication port.
- Corresponds to a grouping of sensor channels.
+ Corresponds to a grouping of sensor channels. X is the IIO
+ index of the device.
-What: /sys/bus/iio/devices/trigger[n]
+What: /sys/bus/iio/devices/triggerX
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -13,25 +14,26 @@ Description:
May be provided by a device driver that also has an IIO device
based on hardware generated events (e.g. data ready) or
provided by a separate driver for other hardware (e.g.
- periodic timer, gpio or high resolution timer).
+ periodic timer, GPIO or high resolution timer).
Contains trigger type specific elements. These do not
generalize well and hence are not documented in this file.
+ X is the IIO index of the trigger.
-What: /sys/bus/iio/devices/device[n]:buffer
+What: /sys/bus/iio/devices/deviceX:buffer
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Link to /sys/class/iio/device[n]/device[n]:buffer. n indicates
+ Link to /sys/class/iio/deviceX/deviceX:buffer. X indicates
the device with which this buffer buffer is associated.
-What: /sys/.../device[n]/name
+What: /sys/bus/iio/devices/deviceX/name
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Description of the physical chip / device. Typically a part
- number.
+ Description of the physical chip / device for device X.
+ Typically a part number.
-What: /sys/.../device[n]/sampling_frequency
+What: /sys/bus/iio/devices/deviceX/sampling_frequency
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -44,158 +46,233 @@ Description:
relevant directories. If it effects all of the above
then it is to be found in the base device directory as here.
-What: /sys/.../device[n]/sampling_frequency_available
+What: /sys/bus/iio/devices/deviceX/sampling_frequency_available
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
When the internal sampling clock can only take a small
- discrete set of values, this file lists those availale.
+ discrete set of values, this file lists those available.
-What: /sys/.../device[n]/in[m][_name]_raw
+What: /sys/bus/iio/devices/deviceX/inY_raw
+What: /sys/bus/iio/devices/deviceX/inY_supply_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no bias removal etc) voltage measurement from
- channel m. name is used in special cases where this does
- not correspond to externally available input (e.g. supply
- voltage monitoring in which case the file is in_supply_raw).
- If the device supports events on this channel then m must be
- specified (even on named channels) so as to allow the source
- of event codes to be identified.
-
-What: /sys/.../device[n]/in[m][_name]_offset
+ channel Y. In special cases where the channel does not
+ correspond to externally available input one of the named
+ versions may be used. The number must always be specified and
+ unique to allow association with event codes.
+
+What: /sys/bus/iio/devices/deviceX/inY-inZ_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- If known for a device, offset to be added to in[m]_raw prior
- to scaling by in[_name][m]_scale in order to obtain voltage in
- millivolts. Not present if the offset is always 0 or unknown.
- If m is not present, then voltage offset applies to all in
- channels. May be writable if a variable offset is controlled
- by the device. Note that this is different to calibbias which
- is for devices that apply offsets to compensate for variation
- between different instances of the part, typically adjusted by
- using some hardware supported calibration procedure.
+ Raw (unscaled) differential voltage measurement equivalent to
+ channel Y - channel Z where these channel numbers apply to the
+ physically equivalent inputs when non differential readings are
+ separately available. In differential only parts, then all that
+ is required is a consistent labeling.
-What: /sys/.../device[n]/in[m][_name]_offset_available
+What: /sys/bus/iio/devices/deviceX/temp_raw
+What: /sys/bus/iio/devices/deviceX/temp_x_raw
+What: /sys/bus/iio/devices/deviceX/temp_y_raw
+What: /sys/bus/iio/devices/deviceX/temp_z_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- If a small number of discrete offset values are available, this
- will be a space separated list. If these are independant (but
- options the same) for individual offsets then m should not be
- present.
+ Raw (unscaled no bias removal etc) temperature measurement.
+ It an axis is specified it generally means that the temperature
+ sensor is associated with one part of a compound device (e.g.
+ a gyroscope axis).
-What: /sys/.../device[n]/in[m][_name]_offset_[min|max]
+What: /sys/bus/iio/devices/deviceX/accel_x_raw
+What: /sys/bus/iio/devices/deviceX/accel_y_raw
+What: /sys/bus/iio/devices/deviceX/accel_z_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- If a more or less continuous range of voltage offsets are
- supported then these specify the minimum and maximum. If shared
- by all in channels then m is not present.
+ Acceleration in direction x, y or z (may be arbitrarily assigned
+ but should match other such assignments on device)
+ channel m (not present if only one accelerometer channel at
+ this orientation). Has all of the equivalent parameters as per
+ inY. Units after application of scale and offset are m/s^2.
-What: /sys/.../device[n]/in[m][_name]_calibbias
+What: /sys/bus/iio/devices/deviceX/gyro_x_raw
+What: /sys/bus/iio/devices/deviceX/gyro_y_raw
+What: /sys/bus/iio/devices/deviceX/gyro_z_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Hardware applied calibration offset. (assumed to fix production
- inaccuracies)
+ Angular velocity about axis x, y or z (may be arbitrarily
+ assigned) Data converted by application of offset then scale to
+ radians per second. Has all the equivalent parameters as
+ per inY.
-What /sys/.../device[n]/in[m][_name]_calibscale
+What: /sys/bus/iio/devices/deviceX/incli_x_raw
+What: /sys/bus/iio/devices/deviceX/incli_y_raw
+What: /sys/bus/iio/devices/deviceX/incli_z_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Hardware applied calibration scale factor. (assumed to fix
- production inaccuracies)
+ Inclination raw reading about axis x, y or z (may be
+ arbitrarily assigned). Data converted by application of offset
+ and scale to Degrees.
-What: /sys/.../device[n]/in[m][_name]_scale
+What: /sys/bus/iio/devices/deviceX/magn_x_raw
+What: /sys/bus/iio/devices/deviceX/magn_y_raw
+What: /sys/bus/iio/devices/deviceX/magn_z_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- If known for a device, scale to be applied to volt[m]_raw post
- addition of in[_name][m]_offset in order to obtain the measured
- voltage in millivolts. If shared across all in channels then
- m is not present.
+ Magnetic field along axis x, y or z (may be arbitrarily
+ assigned) channel m (not present if only one magnetometer
+ at this orientation). Data converted by application of
+ offset then scale to Gauss. Has all the equivalent modifiers
+ as per inY.
-What: /sys/.../device[n]/in[m]-in[o]_raw
-KernelVersion: 2.6.35
+What: /sys/bus/iio/devices/deviceX/accel_x_peak_raw
+What: /sys/bus/iio/devices/deviceX/accel_y_peak_raw
+What: /sys/bus/iio/devices/deviceX/accel_z_peak_raw
+KernelVersion: 2.6.36
Contact: linux-iio@vger.kernel.org
Description:
- Raw (unscaled) differential voltage measurement equivalent to
- channel m - channel o where these channel numbers apply to the
- physically equivalent inputs when non differential readings are
- separately available. In differential only parts, then all that
- is required is a consistent labelling.
+ Some devices provide a store of the highest value seen since
+ some reset condition. These attributes allow access to this
+ and are otherwise the direct equivalent of the
+ <type>Y[_name]_raw attributes.
-What: /sys/.../device[n]/accel[_x|_y|_z][m]_raw
-KernelVersion: 2.6.35
+What: /sys/bus/iio/devices/deviceX/accel_xyz_squared_peak_raw
+KernelVersion: 2.6.36
Contact: linux-iio@vger.kernel.org
Description:
- Acceleration in direction x, y or z (may be arbitrarily assigned
- but should match other such assignments on device)
- channel m (not present if only one accelerometer channel at
- this orientation). Has all of the equivalent parameters as per
- in[m]. Units after application of scale and offset are m/s^2.
+ A computed peak value based on the sum squared magnitude of
+ the underlying value in the specified directions.
-What: /sys/.../device[n]/gyro[_x|_y|_z][m]_raw
+What: /sys/bus/iio/devices/deviceX/accel_offset
+What: /sys/bus/iio/devices/deviceX/temp_offset
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Angular velocity about axis x, y or z (may be arbitrarily
- assigned) channel m (not present if only one gyroscope at
- this orientation).
- Data converted by application of offset then scale to
- radians per second. Has all the equivalent parameters as
- per in[m].
-
-What: /sys/.../device[n]/incli[_x|_y|_z][m]_raw
+ If known for a device, offset to be added to <type>[Y]_raw prior
+ to scaling by <type>[Y]_scale in order to obtain value in the
+ <type> units as specified in <type>[y]_raw documentation.
+ Not present if the offset is always 0 or unknown. If Y is not
+ present, then the offset applies to all in channels of <type>.
+ May be writable if a variable offset can be applied on the
+ device. Note that this is different to calibbias which
+ is for devices (or drivers) that apply offsets to compensate
+ for variation between different instances of the part, typically
+ adjusted by using some hardware supported calibration procedure.
+
+What: /sys/bus/iio/devices/deviceX/inY_scale
+What: /sys/bus/iio/devices/deviceX/inY_supply_scale
+What: /sys/bus/iio/devices/deviceX/in_scale
+What: /sys/bus/iio/devices/deviceX/accel_scale
+What: /sys/bus/iio/devices/deviceX/accel_peak_scale
+What: /sys/bus/iio/devices/deviceX/gyro_scale
+What: /sys/bus/iio/devices/deviceX/magn_scale
+What: /sys/bus/iio/devices/deviceX/magn_x_scale
+What: /sys/bus/iio/devices/deviceX/magn_y_scale
+What: /sys/bus/iio/devices/deviceX/magn_z_scale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Inclination raw reading about axis x, y or z (may be arbitarily
- assigned) channel m (not present if only one inclinometer at
- this orientation). Data converted by application of offset
- and scale to Degrees.
-
-What: /sys/.../device[n]/magn[_x|_y|_z][m]_raw
+ If known for a device, scale to be applied to <type>Y[_name]_raw
+ post addition of <type>[Y][_name]_offset in order to obtain the
+ measured value in <type> units as specified in
+ <type>[Y][_name]_raw documentation.. If shared across all in
+ channels then Y is not present and the value is called
+ <type>[Y][_name]_scale. The peak modifier means this value
+ is applied to <type>Y[_name]_peak_raw values.
+
+What: /sys/bus/iio/devices/deviceX/accel_x_calibbias
+What: /sys/bus/iio/devices/deviceX/accel_y_calibbias
+What: /sys/bus/iio/devices/deviceX/accel_z_calibbias
+What: /sys/bus/iio/devices/deviceX/gyro_x_calibbias
+What: /sys/bus/iio/devices/deviceX/gyro_y_calibbias
+What: /sys/bus/iio/devices/deviceX/gyro_z_calibbias
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Magnetic field along axis x, y or z (may be arbitrarily
- assigned) channel m (not present if only one magnetometer
- at this orientation). Data converted by application of
- offset then scale to Gauss. Has all the equivalent modifiers
- as per in[m].
-
-What: /sys/.../device[n]/device[n]:event[m]
+ Hardware applied calibration offset. (assumed to fix production
+ inaccuracies). If shared across all channels, <type>_calibbias
+ is used.
+
+What /sys/bus/iio/devices/deviceX/inY_calibscale
+What /sys/bus/iio/devices/deviceX/inY_supply_calibscale
+What /sys/bus/iio/devices/deviceX/in_calibscale
+What /sys/bus/iio/devices/deviceX/accel_x_calibscale
+What /sys/bus/iio/devices/deviceX/accel_y_calibscale
+What /sys/bus/iio/devices/deviceX/accel_z_calibscale
+What /sys/bus/iio/devices/deviceX/gyro_x_calibscale
+What /sys/bus/iio/devices/deviceX/gyro_y_calibscale
+What /sys/bus/iio/devices/deviceX/gyro_z_calibscale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Configuration of which hardware generated events are passed up to
- userspace. Some of these are a bit complex to generalize so this
- section is a work in progress.
+ Hardware applied calibration scale factor. (assumed to fix
+ production inaccuracies). If shared across all channels,
+ <type>_calibscale is used.
-What: /sys/.../device[n]:event[m]/dev
-KernelVersion: 2.6.35
+What: /sys/bus/iio/devices/deviceX/accel_scale_available
+KernelVersion: 2.635
Contact: linux-iio@vger.kernel.org
Description:
- major:minor character device numbers for the event line.
+ If a discrete set of scale values are available, they
+ are listed in this attribute.
-Taking accel_x0 as an example
+What: /sys/bus/iio/devices/deviceX/deviceX:eventY
+KernelVersion: 2.6.35
+Contact: linux-iio@vger.kernel.org
+Description:
+ Configuration of which hardware generated events are passed up
+ to user-space.
-What: /sys/.../device[n]:event[m]/accel_x0_thresh[_rising|_falling]_en
+What: /sys/bus/iio/devices/deviceX:event/dev
+What: /sys/bus/iio/devices/deviceX:eventY/dev
+KernelVersion: 2.6.35
+Contact: linux-iio@vger.kernel.org
+Description:
+ major:minor character device numbers for the event line Y of
+ device X.
+
+What: /sys/.../deviceX:eventY/accel_x_thresh_rising_en
+What: /sys/.../deviceX:eventY/accel_x_thresh_falling_en
+What: /sys/.../deviceX:eventY/accel_y_thresh_rising_en
+What: /sys/.../deviceX:eventY/accel_y_thresh_falling_en
+What: /sys/.../deviceX:eventY/accel_z_thresh_rising_en
+What: /sys/.../deviceX:eventY/accel_z_thresh_falling_en
+What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_en
+What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_en
+What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_en
+What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_en
+What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_en
+What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_en
+What: /sys/.../deviceX:eventY/magn_x_thresh_rising_en
+What: /sys/.../deviceX:eventY/magn_x_thresh_falling_en
+What: /sys/.../deviceX:eventY/magn_y_thresh_rising_en
+What: /sys/.../deviceX:eventY/magn_y_thresh_falling_en
+What: /sys/.../deviceX:eventY/magn_z_thresh_rising_en
+What: /sys/.../deviceX:eventY/magn_z_thresh_falling_en
+What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_en
+What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_en
+What: /sys/.../deviceX:eventY/inZ_thresh_rising_en
+What: /sys/.../deviceX:eventY/inZ_thresh_falling_en
+What: /sys/.../deviceX:eventY/temp_thresh_rising_en
+What: /sys/.../deviceX:eventY/temp_thresh_falling_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Event generated when accel_x0 passes a threshold in the specfied
+ Event generated when channel passes a threshold in the specified
(_rising|_falling) direction. If the direction is not specified,
then either the device will report an event which ever direction
a single threshold value is called in (e.g.
- accel_x0_<raw|input>_thresh_value) or
- accel_x0_<raw|input>_thresh_rising_value and
- accel_x0_<raw|input>_thresh_falling_value may take different
- values, but the device can only enable both thresholds or
- neither.
+ <type>[Z][_name]_<raw|input>_thresh_value) or
+ <type>[Z][_name]_<raw|input>_thresh_rising_value and
+ <type>[Z][_name]_<raw|input>_thresh_falling_value may take
+ different values, but the device can only enable both thresholds
+ or neither.
Note the driver will assume the last p events requested are
to be enabled where p is however many it supports (which may
vary depending on the exact set requested. So if you want to be
@@ -205,186 +282,338 @@ Description:
a given event type is enabled a future point (and not those for
whatever event was previously enabled).
-What: /sys/.../accel_x0_<raw|input>_thresh[_rising|_falling]_value
+What: /sys/.../deviceX:eventY/accel_x_roc_rising_en
+What: /sys/.../deviceX:eventY/accel_x_roc_falling_en
+What: /sys/.../deviceX:eventY/accel_y_roc_rising_en
+What: /sys/.../deviceX:eventY/accel_y_roc_falling_en
+What: /sys/.../deviceX:eventY/accel_z_roc_rising_en
+What: /sys/.../deviceX:eventY/accel_z_roc_falling_en
+What: /sys/.../deviceX:eventY/gyro_x_roc_rising_en
+What: /sys/.../deviceX:eventY/gyro_x_roc_falling_en
+What: /sys/.../deviceX:eventY/gyro_y_roc_rising_en
+What: /sys/.../deviceX:eventY/gyro_y_roc_falling_en
+What: /sys/.../deviceX:eventY/gyro_z_roc_rising_en
+What: /sys/.../deviceX:eventY/gyro_z_roc_falling_en
+What: /sys/.../deviceX:eventY/magn_x_roc_rising_en
+What: /sys/.../deviceX:eventY/magn_x_roc_falling_en
+What: /sys/.../deviceX:eventY/magn_y_roc_rising_en
+What: /sys/.../deviceX:eventY/magn_y_roc_falling_en
+What: /sys/.../deviceX:eventY/magn_z_roc_rising_en
+What: /sys/.../deviceX:eventY/magn_z_roc_falling_en
+What: /sys/.../deviceX:eventY/inZ_supply_roc_rising_en
+What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_en
+What: /sys/.../deviceX:eventY/inZ_roc_rising_en
+What: /sys/.../deviceX:eventY/inZ_roc_falling_en
+What: /sys/.../deviceX:eventY/temp_roc_rising_en
+What: /sys/.../deviceX:eventY/temp_roc_falling_en
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Event generated when channel passes a threshold on the rate of
+ change (1st differential) in the specified (_rising|_falling)
+ direction. If the direction is not specified, then either the
+ device will report an event which ever direction a single
+ threshold value is called in (e.g.
+ <type>[Z][_name]_<raw|input>_roc_value) or
+ <type>[Z][_name]_<raw|input>_roc_rising_value and
+ <type>[Z][_name]_<raw|input>_roc_falling_value may take
+ different values, but the device can only enable both rate of
+ change thresholds or neither.
+ Note the driver will assume the last p events requested are
+ to be enabled where p is however many it supports (which may
+ vary depending on the exact set requested. So if you want to be
+ sure you have set what you think you have, check the contents of
+ these attributes after everything is configured. Drivers may
+ have to buffer any parameters so that they are consistent when
+ a given event type is enabled a future point (and not those for
+ whatever event was previously enabled).
+
+What: /sys/.../deviceX:eventY/accel_x_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/accel_x_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/accel_y_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/accel_y_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/accel_z_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/accel_z_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/magn_x_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/magn_x_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/magn_y_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/magn_y_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/magn_z_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/magn_z_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_rising_value
+What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value
+What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Specifies the value of threshold that the device is comparing
against for the events enabled by
- accel_x0_<raw|input>_thresh[_rising|falling]_en.
- If seperate exist for the two directions, but direction is
- not specified for this attribute, then a single threshold value
- applies to both directions.
+ <type>Z[_name]_thresh[_rising|falling]_en.
+ If separate attributes exist for the two directions, but
+ direction is not specified for this attribute, then a single
+ threshold value applies to both directions.
The raw or input element of the name indicates whether the
value is in raw device units or in processed units (as _raw
and _input do on sysfs direct channel read attributes).
-What: /sys/.../accel_x0_thresh[_rising|_falling]_meanperiod
+What: /sys/.../deviceX:eventY/accel_x_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/accel_x_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/accel_y_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/accel_y_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/accel_z_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/accel_z_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/gyro_x_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/gyro_x_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/gyro_y_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/gyro_y_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/gyro_z_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/gyro_z_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/magn_x_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/magn_x_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/magn_y_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/magn_y_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/magn_z_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/magn_z_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_rising_value
+What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value
+What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Period of time (in seconds) over which the raw channel value
- is averaged before being compared with the threshold set in
- accel_x0_thresh[_rising|_falling]_meanperiod. If direction is
- not specified then this mean period applies to both directions.
+ Specifies the value of rate of change threshold that the
+ device is comparing against for the events enabled by
+ <type>[Z][_name]_roc[_rising|falling]_en.
+ If separate attributes exist for the two directions,
+ but direction is not specified for this attribute,
+ then a single threshold value applies to both directions.
+ The raw or input element of the name indicates whether the
+ value is in raw device units or in processed units (as _raw
+ and _input do on sysfs direct channel read attributes).
-What: /sys/.../accel_x0_thresh[_rising|_falling]_period
+What: /sys/.../deviceX:eventY/accel_x_thresh_rising_period
+What: /sys/.../deviceX:eventY/accel_x_thresh_falling_period
+hat: /sys/.../deviceX:eventY/accel_x_roc_rising_period
+What: /sys/.../deviceX:eventY/accel_x_roc_falling_period
+What: /sys/.../deviceX:eventY/accel_y_thresh_rising_period
+What: /sys/.../deviceX:eventY/accel_y_thresh_falling_period
+What: /sys/.../deviceX:eventY/accel_y_roc_rising_period
+What: /sys/.../deviceX:eventY/accel_y_roc_falling_period
+What: /sys/.../deviceX:eventY/accel_z_thresh_rising_period
+What: /sys/.../deviceX:eventY/accel_z_thresh_falling_period
+What: /sys/.../deviceX:eventY/accel_z_roc_rising_period
+What: /sys/.../deviceX:eventY/accel_z_roc_falling_period
+What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_period
+What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_period
+What: /sys/.../deviceX:eventY/gyro_x_roc_rising_period
+What: /sys/.../deviceX:eventY/gyro_x_roc_falling_period
+What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_period
+What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_period
+What: /sys/.../deviceX:eventY/gyro_y_roc_rising_period
+What: /sys/.../deviceX:eventY/gyro_y_roc_falling_period
+What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_period
+What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_period
+What: /sys/.../deviceX:eventY/gyro_z_roc_rising_period
+What: /sys/.../deviceX:eventY/gyro_z_roc_falling_period
+What: /sys/.../deviceX:eventY/magn_x_thresh_rising_period
+What: /sys/.../deviceX:eventY/magn_x_thresh_falling_period
+What: /sys/.../deviceX:eventY/magn_x_roc_rising_period
+What: /sys/.../deviceX:eventY/magn_x_roc_falling_period
+What: /sys/.../deviceX:eventY/magn_y_thresh_rising_period
+What: /sys/.../deviceX:eventY/magn_y_thresh_falling_period
+What: /sys/.../deviceX:eventY/magn_y_roc_rising_period
+What: /sys/.../deviceX:eventY/magn_y_roc_falling_period
+What: /sys/.../deviceX:eventY/magn_z_thresh_rising_period
+What: /sys/.../deviceX:eventY/magn_z_thresh_falling_period
+What: /sys/.../deviceX:eventY/magn_z_roc_rising_period
+What: /sys/.../deviceX:eventY/magn_z_roc_falling_period
+What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_period
+What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_period
+What: /sys/.../deviceX:eventY/inz_supply_roc_rising_period
+What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_period
+What: /sys/.../deviceX:eventY/inZ_thresh_rising_period
+What: /sys/.../deviceX:eventY/inZ_thresh_falling_period
+What: /sys/.../deviceX:eventY/inZ_roc_rising_period
+What: /sys/.../deviceX:eventY/inZ_roc_falling_period
+What: /sys/.../deviceX:eventY/temp_thresh_rising_period
+What: /sys/.../deviceX:eventY/temp_thresh_falling_period
+What: /sys/.../deviceX:eventY/temp_roc_rising_period
+What: /sys/.../deviceX:eventY/temp_roc_falling_period
+What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_period
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Period of time (in seconds) for which the threshold must be
- passed before an event is generated. If direction is not
+ Period of time (in seconds) for which the condition must be
+ met before an event is generated. If direction is not
specified then this period applies to both directions.
-What: /sys/.../device[n]:event[m]/accel_x0_mag[_rising|_falling]_en
+What: /sys/.../deviceX:eventY/accel_mag_en
+What: /sys/.../deviceX:eventY/accel_mag_rising_en
+What: /sys/.../deviceX:eventY/accel_mag_falling_en
+What: /sys/.../deviceX:eventY/accel_x_mag_en
+What: /sys/.../deviceX:eventY/accel_x_mag_rising_en
+What: /sys/.../deviceX:eventY/accel_x_mag_falling_en
+What: /sys/.../deviceX:eventY/accel_y_mag_en
+What: /sys/.../deviceX:eventY/accel_y_mag_rising_en
+What: /sys/.../deviceX:eventY/accel_y_mag_falling_en
+What: /sys/.../deviceX:eventY/accel_z_mag_en
+What: /sys/.../deviceX:eventY/accel_z_mag_rising_en
+What: /sys/.../deviceX:eventY/accel_z_mag_falling_en
+What: /sys/.../deviceX:eventY/accel_x&y&z_mag_rising_en
+What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Similar to accel_x0_thresh[_rising|_falling]_en, but here the
+ Similar to accel_x_thresh[_rising|_falling]_en, but here the
magnitude of the channel is compared to the threshold, not its
signed value.
-What: /sys/.../accel_x0_<raw|input>_mag[_rising|_falling]_value
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- The value to which the magnitude of the channel is compared.
-
-What: /sys/.../accel_x0_mag[_rising|_falling]_meanperiod
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Period of time (in seconds) over which the value of the channel
- is averaged before being compared to the threshold
-
-What: /sys/.../accel_x0_mag[_rising|_falling]_period
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Period of time (in seconds) for which the condition must be true
- before an event occurs.
-
-What: /sys/.../device[n]:event[m]/accel_x0_roc[_rising|_falling]_en
+What: /sys/.../accel_raw_mag_value
+What: /sys/.../accel_x_raw_mag_rising_value
+What: /sys/.../accel_y_raw_mag_rising_value
+What: /sys/.../accel_z_raw_mag_rising_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Similar to accel_x0_thresh[_rising|_falling]_en, but here the
- first differential is compared with the threshold.
+ The value to which the magnitude of the channel is compared. If
+ number or direction is not specified, applies to all channels of
+ this type.
-What: /sys/.../accel_x0_<raw|input>_roc[_rising|_falling]_value
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- The value to which the first differential of the channel is
- compared.
-
-What: /sys/.../accel_x0_roc[_rising|_falling]_meanperiod
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Period of time (in seconds) over which the value of the channel
- is averaged before being compared to the threshold
-
-What: /sys/.../accel_x0_roc[_rising|_falling]_period
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Period of time (in seconds) for which the condition must be true
- before an event occurs.
-
-What: /sys/.../device[n]/device[n]:buffer:event/dev
+What: /sys/bus/iio/devices/deviceX:buffer:event/dev
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Buffer for device n event character device major:minor numbers.
+ Buffer for device X event character device major:minor numbers.
-What: /sys/.../device[n]/device[n]:buffer:access/dev
+What: /sys/bus/iio/devices/deviceX:buffer:access/dev
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
- Buffer for device n access character device o major:minor numbers.
+ Buffer for device X access character device major:minor numbers.
-What: /sys/.../device[n]:buffer/trigger
+What: /sys/bus/iio/devices/deviceX:buffer/trigger
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
The name of the trigger source being used, as per string given
- in /sys/class/iio/trigger[n]/name.
+ in /sys/class/iio/triggerY/name.
-What: /sys/.../device[n]:buffer/length
+What: /sys/bus/iio/devices/deviceX:buffer/length
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
Number of scans contained by the buffer.
-What: /sys/.../device[n]:buffer/bytes_per_datum
+What: /sys/bus/iio/devices/deviceX:buffer/bytes_per_datum
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Bytes per scan. Due to alignment fun, the scan may be larger
than implied directly by the scan_element parameters.
-What: /sys/.../device[n]:buffer/enable
+What: /sys/bus/iio/devices/deviceX:buffer/enable
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
Actually start the buffer capture up. Will start trigger
if first device and appropriate.
-What: /sys/.../device[n]:buffer/alignment
-KernelVersion: 2.6.35
-Contact: linux-iio@vger.kernel.org
-Description:
- Minimum data alignment. Scan elements larger than this are
- aligned to the nearest power of 2 times this. (may not be
- true in weird hardware buffers that pack data well)
-
-What: /sys/.../device[n]/buffer/scan_elements
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Directory containing interfaces for elements that will be
captured for a single triggered sample set in the buffer.
-What: /sys/.../device[n]/buffer/scan_elements/accel_x0_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/timestamp_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_supply_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY-inZ_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_en
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Scan element control for triggered data capture.
-What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_type
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/in-in_type
+What: /sys/.../deviceX:buffer/scan_elements/inY_supply_type
+What: /sys/.../deviceX:buffer/scan_elements/timestamp_type
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Description of the scan element data storage within the buffer
- and hence the form in which it is read from userspace.
- Form is [s|u]bits/storagebits. s or u specifies if signed
- (2's complement) or unsigned. bits is the number of bits of
- data and storagebits is the space (after padding) that it
- occupies in the buffer. Note that some devices will have
- additional information in the unused bits so to get a clean
- value, the bits value must be used to mask the buffer output
- value appropriately. The storagebits value also specifies the
- data alignment. So s48/64 will be a signed 48 bit integer
- stored in a 64 bit location aligned to a a64 bit boundary.
+ and hence the form in which it is read from user-space.
+ Form is [s|u]bits/storagebits[>>shift]. s or u specifies if
+ signed (2's complement) or unsigned. bits is the number of bits
+ of data and storagebits is the space (after padding) that it
+ occupies in the buffer. shift if specified, is the shift that
+ needs to be applied prior to masking out unused bits. Some
+ devices put their data in the middle of the transferred elements
+ with additional information on both sides. Note that some
+ devices will have additional information in the unused bits
+ so to get a clean value, the bits value must be used to mask
+ the buffer output value appropriately. The storagebits value
+ also specifies the data alignment. So s48/64>>2 will be a
+ signed 48 bit integer stored in a 64 bit location aligned to
+ a a64 bit boundary. To obtain the clean value, shift right 2
+ and apply a mask to zero the top 16 bits of the result.
For other storage combinations this attribute will be extended
appropriately.
-What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_index
+What: /sys/.../deviceX:buffer/scan_elements/accel_type_available
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ If the type parameter can take one of a small set of values,
+ this attribute lists them.
+
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_index
+What: /sys/.../deviceX:buffer/scan_elements/inY_supply_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_index
+What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_index
+What: /sys/.../deviceX:buffer/scan_elements/timestamp_index
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
A single positive integer specifying the position of this
- scan element in the buffer. Note these are not dependant on
- what is enabled and may not be contiguous. Thus for userspace
+ scan element in the buffer. Note these are not dependent on
+ what is enabled and may not be contiguous. Thus for user-space
to establish the full layout these must be used in conjunction
with all _en attributes to establish which channels are present,
and the relevant _type attributes to establish the data storage
format.
-
-What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_shift
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- A bit shift (to right) that must be applied prior to
- extracting the bits specified by accel[_x0]_precision.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
new file mode 100644
index 000000000000..ffdd5478a35d
--- /dev/null
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
@@ -0,0 +1,93 @@
+
+What: /sys/bus/iio/devices/.../ddsX_freqY
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Stores frequency into tuning word Y.
+ There will be more than one ddsX_freqY file, which allows for
+ pin controlled FSK Frequency Shift Keying
+ (ddsX_pincontrol_freq_en is active) or the user can control
+ the desired active tuning word by writing Y to the
+ ddsX_freqsymbol file.
+
+What: /sys/bus/iio/devices/.../ddsX_freqY_scale
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Scale to be applied to ddsX_freqY in order to obtain the
+ desired value in Hz. If shared across all frequency registers
+ Y is not present. It is also possible X is not present if
+ shared across all channels.
+
+What: /sys/bus/iio/devices/.../ddsX_freqsymbol
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specifies the active output frequency tuning word. The value
+ corresponds to the Y in ddsX_freqY. To exit this mode the user
+ can write ddsX_pincontrol_freq_en or ddsX_out_enable file.
+
+What: /sys/bus/iio/devices/.../ddsX_phaseY
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Stores phase into Y.
+ There will be more than one ddsX_phaseY file, which allows for
+ pin controlled PSK Phase Shift Keying
+ (ddsX_pincontrol_phase_en is active) or the user can
+ control the desired phase Y which is added to the phase
+ accumulator output by writing Y to the en_phase file.
+
+What: /sys/bus/iio/devices/.../ddsX_phaseY_scale
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Scale to be applied to ddsX_phaseY in order to obtain the
+ desired value in rad. If shared across all phase registers
+ Y is not present. It is also possible X is not present if
+ shared across all channels.
+
+What: /sys/bus/iio/devices/.../ddsX_phasesymbol
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specifies the active phase Y which is added to the phase
+ accumulator output. The value corresponds to the Y in
+ ddsX_phaseY. To exit this mode the user can write
+ ddsX_pincontrol_phase_en or disable file.
+
+What: /sys/bus/iio/devices/.../ddsX_pincontrol_en
+What: /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
+What: /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ ddsX_pincontrol_en: Both, the active frequency and phase is
+ controlled by the respective phase and frequency control inputs.
+ In case the device in question allows to independent controls,
+ then there are dedicated files (ddsX_pincontrol_freq_en,
+ ddsX_pincontrol_phase_en).
+
+What: /sys/bus/iio/devices/.../ddsX_out_enable
+What: /sys/bus/iio/devices/.../ddsX_outY_enable
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ ddsX_outY_enable controls signal generation on output Y of
+ channel X. Y may be suppressed if all channels are
+ controlled together.
+
+What: /sys/bus/iio/devices/.../ddsX_outY_wavetype
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specifies the output waveform.
+ (sine, triangle, ramp, square, ...)
+ For a list of available output waveform options read
+ available_output_modes.
+
+What: /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Lists all available output waveform options.
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index ed48815a916b..e2ac07d86110 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -42,11 +42,15 @@ config IIO_TRIGGER
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
+source "drivers/staging/iio/addac/Kconfig"
+source "drivers/staging/iio/dac/Kconfig"
+source "drivers/staging/iio/dds/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/imu/Kconfig"
source "drivers/staging/iio/light/Kconfig"
source "drivers/staging/iio/magnetometer/Kconfig"
-
+source "drivers/staging/iio/meter/Kconfig"
+source "drivers/staging/iio/resolver/Kconfig"
source "drivers/staging/iio/trigger/Kconfig"
endif # IIO
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index e909674920fc..f9b5fb2fe8f1 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -11,8 +11,13 @@ obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
obj-y += accel/
obj-y += adc/
+obj-y += addac/
+obj-y += dac/
+obj-y += dds/
obj-y += gyro/
obj-y += imu/
obj-y += light/
-obj-y += trigger/
obj-y += magnetometer/
+obj-y += meter/
+obj-y += resolver/
+obj-y += trigger/
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index 898cba1c939f..d1ad35e24abb 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -61,6 +61,10 @@ necessitate a header that is also visible from arch board
files. (avoided at the moment to keep the driver set
contained in staging).
+ADI Drivers:
+CC the device-drivers-devel@blackfin.uclinux.org mailing list when
+e-mailing the normal IIO list (see below).
+
Documentation
1) Lots of cleanup and expansion.
2) Some device require indvidual docs.
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index 5926c03be1a5..a34f1d3e673c 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -3,6 +3,33 @@
#
comment "Accelerometers"
+config ADIS16201
+ tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16201 dual-axis
+ digital inclinometer and accelerometer.
+
+config ADIS16203
+ tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16203 Programmable
+ 360 Degrees Inclinometer.
+
+config ADIS16204
+ tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16204 Programmable
+ High-g Digital Impact Sensor and Recorder.
+
config ADIS16209
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index ff84703a16f6..1b2a6d3ddafa 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -2,6 +2,18 @@
# Makefile for industrial I/O accelerometer drivers
#
+adis16201-y := adis16201_core.o
+adis16201-$(CONFIG_IIO_RING_BUFFER) += adis16201_ring.o adis16201_trigger.o
+obj-$(CONFIG_ADIS16201) += adis16201.o
+
+adis16203-y := adis16203_core.o
+adis16203-$(CONFIG_IIO_RING_BUFFER) += adis16203_ring.o adis16203_trigger.o
+obj-$(CONFIG_ADIS16203) += adis16203.o
+
+adis16204-y := adis16204_core.o
+adis16204-$(CONFIG_IIO_RING_BUFFER) += adis16204_ring.o adis16204_trigger.o
+obj-$(CONFIG_ADIS16204) += adis16204.o
+
adis16209-y := adis16209_core.o
adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o
obj-$(CONFIG_ADIS16209) += adis16209.o
diff --git a/drivers/staging/iio/accel/accel.h b/drivers/staging/iio/accel/accel.h
index f5f61b2497aa..50651f835cea 100644
--- a/drivers/staging/iio/accel/accel.h
+++ b/drivers/staging/iio/accel/accel.h
@@ -65,3 +65,23 @@
#define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \
IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr)
+#define IIO_DEV_ATTR_ACCEL_XY(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_xy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_PEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_peak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XPEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_xpeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_YPEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_ypeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_ZPEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_zpeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_xypeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XYZPEAK(_show, _addr) \
+ IIO_DEVICE_ATTR(accel_xyzpeak, S_IRUGO, _show, NULL, _addr)
diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h
new file mode 100644
index 000000000000..c9bf22c13428
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16201.h
@@ -0,0 +1,150 @@
+#ifndef SPI_ADIS16201_H_
+#define SPI_ADIS16201_H_
+
+#define ADIS16201_STARTUP_DELAY 220 /* ms */
+
+#define ADIS16201_READ_REG(a) a
+#define ADIS16201_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16201_FLASH_CNT 0x00 /* Flash memory write count */
+#define ADIS16201_SUPPLY_OUT 0x02 /* Output, power supply */
+#define ADIS16201_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
+#define ADIS16201_YACCL_OUT 0x06 /* Output, y-axis accelerometer */
+#define ADIS16201_AUX_ADC 0x08 /* Output, auxiliary ADC input */
+#define ADIS16201_TEMP_OUT 0x0A /* Output, temperature */
+#define ADIS16201_XINCL_OUT 0x0C /* Output, x-axis inclination */
+#define ADIS16201_YINCL_OUT 0x0E /* Output, y-axis inclination */
+#define ADIS16201_XACCL_OFFS 0x10 /* Calibration, x-axis acceleration offset */
+#define ADIS16201_YACCL_OFFS 0x12 /* Calibration, y-axis acceleration offset */
+#define ADIS16201_XACCL_SCALE 0x14 /* x-axis acceleration scale factor */
+#define ADIS16201_YACCL_SCALE 0x16 /* y-axis acceleration scale factor */
+#define ADIS16201_XINCL_OFFS 0x18 /* Calibration, x-axis inclination offset */
+#define ADIS16201_YINCL_OFFS 0x1A /* Calibration, y-axis inclination offset */
+#define ADIS16201_XINCL_SCALE 0x1C /* x-axis inclination scale factor */
+#define ADIS16201_YINCL_SCALE 0x1E /* y-axis inclination scale factor */
+#define ADIS16201_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16201_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16201_ALM_SMPL1 0x24 /* Alarm 1, sample period */
+#define ADIS16201_ALM_SMPL2 0x26 /* Alarm 2, sample period */
+#define ADIS16201_ALM_CTRL 0x28 /* Alarm control */
+#define ADIS16201_AUX_DAC 0x30 /* Auxiliary DAC data */
+#define ADIS16201_GPIO_CTRL 0x32 /* General-purpose digital input/output control */
+#define ADIS16201_MSC_CTRL 0x34 /* Miscellaneous control */
+#define ADIS16201_SMPL_PRD 0x36 /* Internal sample period (rate) control */
+#define ADIS16201_AVG_CNT 0x38 /* Operation, filter configuration */
+#define ADIS16201_SLP_CNT 0x3A /* Operation, sleep mode control */
+#define ADIS16201_DIAG_STAT 0x3C /* Diagnostics, system status register */
+#define ADIS16201_GLOB_CMD 0x3E /* Operation, system command register */
+
+#define ADIS16201_OUTPUTS 7
+
+/* MSC_CTRL */
+#define ADIS16201_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */
+#define ADIS16201_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16201_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 (1 << 0) /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* DIAG_STAT */
+#define ADIS16201_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */
+#define ADIS16201_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
+#define ADIS16201_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */
+#define ADIS16201_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */
+
+/* GLOB_CMD */
+#define ADIS16201_GLOB_CMD_SW_RESET (1<<7)
+#define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16201_MAX_TX 14
+#define ADIS16201_MAX_RX 14
+
+#define ADIS16201_ERROR_ACTIVE (1<<14)
+
+/**
+ * struct adis16201_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16201_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+int adis16201_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16201_scan {
+ ADIS16201_SCAN_SUPPLY,
+ ADIS16201_SCAN_ACC_X,
+ ADIS16201_SCAN_ACC_Y,
+ ADIS16201_SCAN_AUX_ADC,
+ ADIS16201_SCAN_TEMP,
+ ADIS16201_SCAN_INCLI_X,
+ ADIS16201_SCAN_INCLI_Y,
+};
+
+void adis16201_remove_trigger(struct iio_dev *indio_dev);
+int adis16201_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16201_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+int adis16201_configure_ring(struct iio_dev *indio_dev);
+void adis16201_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16201_initialize_ring(struct iio_ring_buffer *ring);
+void adis16201_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16201_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16201_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16201_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16201_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16201_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16201_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16201_H_ */
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
new file mode 100644
index 000000000000..79b785a0013a
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -0,0 +1,659 @@
+/*
+ * ADIS16201 Programmable Digital Vibration Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "inclinometer.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16201.h"
+
+#define DRIVER_NAME "adis16201"
+
+static int adis16201_check_status(struct device *dev);
+
+/**
+ * adis16201_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16201_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16201_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16201_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16201_spi_write_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .tx_buf = st->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16201_WRITE_REG(lower_reg_address);
+ st->tx[1] = value & 0xFF;
+ st->tx[2] = ADIS16201_WRITE_REG(lower_reg_address + 1);
+ st->tx[3] = (value >> 8) & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16201_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16201_spi_read_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16201_READ_REG(lower_reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ lower_reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t adis16201_read_12bit_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16201_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16201_ERROR_ACTIVE) {
+ ret = adis16201_check_status(dev);
+ if (ret)
+ return ret;
+ }
+
+ return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16201_read_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u16 val;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16201_spi_read_reg_16(dev, ADIS16201_TEMP_OUT, (u16 *)&val);
+ if (ret)
+ goto error_ret;
+
+ if (val & ADIS16201_ERROR_ACTIVE) {
+ ret = adis16201_check_status(dev);
+ if (ret)
+ goto error_ret;
+ }
+
+ val &= 0xFFF;
+ ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static ssize_t adis16201_read_9bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16201_ERROR_ACTIVE) {
+ ret = adis16201_check_status(dev);
+ if (ret)
+ goto error_ret;
+ }
+ val = ((s16)(val << 7) >> 7);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16201_read_12bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16201_ERROR_ACTIVE) {
+ ret = adis16201_check_status(dev);
+ if (ret)
+ goto error_ret;
+ }
+
+ val = ((s16)(val << 4) >> 4);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16201_read_14bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16201_ERROR_ACTIVE) {
+ ret = adis16201_check_status(dev);
+ if (ret)
+ goto error_ret;
+ }
+
+ val = ((s16)(val << 2) >> 2);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16201_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16201_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int adis16201_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16201_spi_write_reg_8(dev,
+ ADIS16201_GLOB_CMD,
+ ADIS16201_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
+static ssize_t adis16201_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -EINVAL;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return adis16201_reset(dev);
+ }
+ return -EINVAL;
+}
+
+int adis16201_set_irq(struct device *dev, bool enable)
+{
+ int ret = 0;
+ u16 msc;
+
+ ret = adis16201_spi_read_reg_16(dev, ADIS16201_MSC_CTRL, &msc);
+ if (ret)
+ goto error_ret;
+
+ msc |= ADIS16201_MSC_CTRL_ACTIVE_HIGH;
+ msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_DIO1;
+ if (enable)
+ msc |= ADIS16201_MSC_CTRL_DATA_RDY_EN;
+ else
+ msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_EN;
+
+ ret = adis16201_spi_write_reg_16(dev, ADIS16201_MSC_CTRL, msc);
+
+error_ret:
+ return ret;
+}
+
+static int adis16201_check_status(struct device *dev)
+{
+ u16 status;
+ int ret;
+
+ ret = adis16201_spi_read_reg_16(dev, ADIS16201_DIAG_STAT, &status);
+ if (ret < 0) {
+ dev_err(dev, "Reading status failed\n");
+ goto error_ret;
+ }
+ ret = status & 0xF;
+ if (ret)
+ ret = -EFAULT;
+
+ if (status & ADIS16201_DIAG_STAT_SPI_FAIL)
+ dev_err(dev, "SPI failure\n");
+ if (status & ADIS16201_DIAG_STAT_FLASH_UPT)
+ dev_err(dev, "Flash update failed\n");
+ if (status & ADIS16201_DIAG_STAT_POWER_HIGH)
+ dev_err(dev, "Power supply above 3.625V\n");
+ if (status & ADIS16201_DIAG_STAT_POWER_LOW)
+ dev_err(dev, "Power supply below 3.15V\n");
+
+error_ret:
+ return ret;
+}
+
+static int adis16201_self_test(struct device *dev)
+{
+ int ret;
+ ret = adis16201_spi_write_reg_16(dev,
+ ADIS16201_MSC_CTRL,
+ ADIS16201_MSC_CTRL_SELF_TEST_EN);
+ if (ret) {
+ dev_err(dev, "problem starting self test");
+ goto err_ret;
+ }
+
+ ret = adis16201_check_status(dev);
+
+err_ret:
+ return ret;
+}
+
+static int adis16201_initial_setup(struct adis16201_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* Disable IRQ */
+ ret = adis16201_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ /* Do self test */
+ ret = adis16201_self_test(dev);
+ if (ret) {
+ dev_err(dev, "self test failure");
+ goto err_ret;
+ }
+
+ /* Read status register to check the result */
+ ret = adis16201_check_status(dev);
+ if (ret) {
+ adis16201_reset(dev);
+ dev_err(dev, "device not playing ball -> reset");
+ msleep(ADIS16201_STARTUP_DELAY);
+ ret = adis16201_check_status(dev);
+ if (ret) {
+ dev_err(dev, "giving up");
+ goto err_ret;
+ }
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+ st->us->chip_select, st->us->irq);
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16201_read_12bit_unsigned,
+ ADIS16201_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16201_read_12bit_unsigned,
+ ADIS16201_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_ACCEL_X(adis16201_read_14bit_signed,
+ ADIS16201_XACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_Y(adis16201_read_14bit_signed,
+ ADIS16201_YACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
+ adis16201_read_12bit_signed,
+ adis16201_write_16bit,
+ ADIS16201_XACCL_OFFS);
+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
+ adis16201_read_12bit_signed,
+ adis16201_write_16bit,
+ ADIS16201_YACCL_OFFS);
+static IIO_CONST_ATTR(accel_scale, "0.4625");
+
+static IIO_DEV_ATTR_INCLI_X(adis16201_read_14bit_signed,
+ ADIS16201_XINCL_OUT);
+static IIO_DEV_ATTR_INCLI_Y(adis16201_read_14bit_signed,
+ ADIS16201_YINCL_OUT);
+static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO,
+ adis16201_read_9bit_signed,
+ adis16201_write_16bit,
+ ADIS16201_XACCL_OFFS);
+static IIO_DEV_ATTR_INCLI_Y_OFFSET(S_IWUSR | S_IRUGO,
+ adis16201_read_9bit_signed,
+ adis16201_write_16bit,
+ ADIS16201_YACCL_OFFS);
+static IIO_CONST_ATTR(incli_scale, "0.1");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16201_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16201_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16201");
+
+static struct attribute *adis16201_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16201_event_attribute_group = {
+ .attrs = adis16201_event_attributes,
+};
+
+static struct attribute *adis16201_attributes[] = {
+ &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+ &iio_const_attr_in0_supply_scale.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
+ &iio_const_attr_in1_scale.dev_attr.attr,
+ &iio_dev_attr_accel_x_raw.dev_attr.attr,
+ &iio_dev_attr_accel_y_raw.dev_attr.attr,
+ &iio_dev_attr_accel_x_offset.dev_attr.attr,
+ &iio_dev_attr_accel_y_offset.dev_attr.attr,
+ &iio_const_attr_accel_scale.dev_attr.attr,
+ &iio_dev_attr_incli_x_raw.dev_attr.attr,
+ &iio_dev_attr_incli_y_raw.dev_attr.attr,
+ &iio_dev_attr_incli_x_offset.dev_attr.attr,
+ &iio_dev_attr_incli_y_offset.dev_attr.attr,
+ &iio_const_attr_incli_scale.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16201_attribute_group = {
+ .attrs = adis16201_attributes,
+};
+
+static int __devinit adis16201_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16201_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16201_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16201_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16201_event_attribute_group;
+ st->indio_dev->attrs = &adis16201_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16201_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16201_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16201");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16201_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = adis16201_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ adis16201_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (spi->irq)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16201_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16201_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int adis16201_remove(struct spi_device *spi)
+{
+ struct adis16201_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16201_remove_trigger(indio_dev);
+ if (spi->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16201_uninitialize_ring(indio_dev->ring);
+ iio_device_unregister(indio_dev);
+ adis16201_unconfigure_ring(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver adis16201_driver = {
+ .driver = {
+ .name = "adis16201",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16201_probe,
+ .remove = __devexit_p(adis16201_remove),
+};
+
+static __init int adis16201_init(void)
+{
+ return spi_register_driver(&adis16201_driver);
+}
+module_init(adis16201_init);
+
+static __exit void adis16201_exit(void)
+{
+ spi_unregister_driver(&adis16201_driver);
+}
+module_exit(adis16201_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16201 Programmable Digital Vibration Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
new file mode 100644
index 000000000000..e6870a2721f1
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -0,0 +1,218 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16201.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16201_SCAN_SUPPLY, ADIS16201_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(accel_x, ADIS16201_SCAN_ACC_X, ADIS16201_XACCL_OUT, NULL);
+static IIO_SCAN_EL_C(accel_y, ADIS16201_SCAN_ACC_Y, ADIS16201_YACCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16);
+static IIO_SCAN_EL_C(in0, ADIS16201_SCAN_AUX_ADC, ADIS16201_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16201_SCAN_TEMP, ADIS16201_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_C(incli_x, ADIS16201_SCAN_INCLI_X,
+ ADIS16201_XINCL_OUT, NULL);
+static IIO_SCAN_EL_C(incli_y, ADIS16201_SCAN_INCLI_Y,
+ ADIS16201_YINCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16);
+static IIO_SCAN_EL_TIMESTAMP(7);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16201_scan_el_attrs[] = {
+ &iio_scan_el_in_supply.dev_attr.attr,
+ &iio_const_attr_in_supply_index.dev_attr.attr,
+ &iio_const_attr_in_supply_type.dev_attr.attr,
+ &iio_scan_el_accel_x.dev_attr.attr,
+ &iio_const_attr_accel_x_index.dev_attr.attr,
+ &iio_scan_el_accel_y.dev_attr.attr,
+ &iio_const_attr_accel_y_index.dev_attr.attr,
+ &iio_const_attr_accel_type.dev_attr.attr,
+ &iio_scan_el_in0.dev_attr.attr,
+ &iio_const_attr_in0_index.dev_attr.attr,
+ &iio_const_attr_in0_type.dev_attr.attr,
+ &iio_scan_el_temp.dev_attr.attr,
+ &iio_const_attr_temp_index.dev_attr.attr,
+ &iio_const_attr_temp_type.dev_attr.attr,
+ &iio_scan_el_incli_x.dev_attr.attr,
+ &iio_const_attr_incli_x_index.dev_attr.attr,
+ &iio_scan_el_incli_y.dev_attr.attr,
+ &iio_const_attr_incli_y_index.dev_attr.attr,
+ &iio_const_attr_incli_type.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adis16201_scan_el_group = {
+ .attrs = adis16201_scan_el_attrs,
+ .name = "scan_elements",
+};
+
+/**
+ * adis16201_poll_func_th() top half interrupt handler called by trigger
+ * @private_data: iio_dev
+ **/
+static void adis16201_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+ st->last_timestamp = time;
+ schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16201_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16201_read_ring_data(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[ADIS16201_OUTPUTS + 1];
+ int ret;
+ int i;
+
+ mutex_lock(&st->buf_lock);
+
+ spi_message_init(&msg);
+
+ memset(xfers, 0, sizeof(xfers));
+ for (i = 0; i <= ADIS16201_OUTPUTS; i++) {
+ xfers[i].bits_per_word = 8;
+ xfers[i].cs_change = 1;
+ xfers[i].len = 2;
+ xfers[i].delay_usecs = 20;
+ xfers[i].tx_buf = st->tx + 2 * i;
+ st->tx[2 * i] = ADIS16201_READ_REG(ADIS16201_SUPPLY_OUT + 2 * i);
+ st->tx[2 * i + 1] = 0;
+ if (i >= 1)
+ xfers[i].rx_buf = rx + 2 * (i - 1);
+ spi_message_add_tail(&xfers[i], &msg);
+ }
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16201_trigger_bh_to_ring(struct work_struct *work_s)
+{
+ struct adis16201_state *st
+ = container_of(work_s, struct adis16201_state,
+ work_trigger_to_ring);
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+ int i = 0;
+ s16 *data;
+ size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+ data = kmalloc(datasize, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&st->us->dev, "memory alloc failed in ring bh");
+ return;
+ }
+
+ if (ring->scan_count)
+ if (adis16201_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+ for (; i < ring->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (ring->scan_timestamp)
+ *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+ ring->access.store_to(ring,
+ (u8 *)data,
+ st->last_timestamp);
+
+ iio_trigger_notify_done(st->indio_dev->trig);
+ kfree(data);
+
+ return;
+}
+
+void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
+{
+ kfree(indio_dev->pollfunc);
+ iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16201_configure_ring(struct iio_dev *indio_dev)
+{
+ int ret = 0;
+ struct adis16201_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring;
+ INIT_WORK(&st->work_trigger_to_ring, adis16201_trigger_bh_to_ring);
+
+ ring = iio_sw_rb_allocate(indio_dev);
+ if (!ring) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ indio_dev->ring = ring;
+ /* Effectively select the ring buffer implementation */
+ iio_ring_sw_register_funcs(&ring->access);
+ ring->bpe = 2;
+ ring->scan_el_attrs = &adis16201_scan_el_group;
+ ring->scan_timestamp = true;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
+ ring->owner = THIS_MODULE;
+
+ /* Set default scan mode */
+ iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+ iio_scan_mask_set(ring, iio_scan_el_accel_x.number);
+ iio_scan_mask_set(ring, iio_scan_el_accel_y.number);
+ iio_scan_mask_set(ring, iio_scan_el_temp.number);
+ iio_scan_mask_set(ring, iio_scan_el_in0.number);
+ iio_scan_mask_set(ring, iio_scan_el_incli_x.number);
+ iio_scan_mask_set(ring, iio_scan_el_incli_y.number);
+
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16201_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
+ indio_dev->modes |= INDIO_RING_TRIGGERED;
+ return 0;
+
+error_iio_sw_rb_free:
+ iio_sw_rb_free(indio_dev->ring);
+ return ret;
+}
+
+int adis16201_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16201_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+ iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c
new file mode 100644
index 000000000000..8a9cea1986e7
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16201_trigger.c
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16201.h"
+
+/**
+ * adis16201_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16201_data_rdy_trig_poll(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adis16201_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_trigger *trig = st->trig;
+
+ iio_trigger_poll(trig, timestamp);
+
+ return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16201_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16201_trigger_attrs[] = {
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group adis16201_trigger_attr_group = {
+ .attrs = adis16201_trigger_attrs,
+};
+
+/**
+ * adis16201_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16201_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct adis16201_state *st = trig->private_data;
+ struct iio_dev *indio_dev = st->indio_dev;
+ int ret = 0;
+
+ dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+ ret = adis16201_set_irq(&st->indio_dev->dev, state);
+ if (state == false) {
+ iio_remove_event_from_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]
+ ->ev_list);
+ flush_scheduled_work();
+ } else {
+ iio_add_event_to_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]->ev_list);
+ }
+ return ret;
+}
+
+/**
+ * adis16201_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig: the datardy trigger
+ **/
+static int adis16201_trig_try_reen(struct iio_trigger *trig)
+{
+ struct adis16201_state *st = trig->private_data;
+ enable_irq(st->us->irq);
+ return 0;
+}
+
+int adis16201_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct adis16201_state *st = indio_dev->dev_data;
+
+ st->trig = iio_allocate_trigger();
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16201-dev%d",
+ indio_dev->id);
+ if (!st->trig->name) {
+ ret = -ENOMEM;
+ goto error_free_trig;
+ }
+ st->trig->dev.parent = &st->us->dev;
+ st->trig->owner = THIS_MODULE;
+ st->trig->private_data = st;
+ st->trig->set_trigger_state = &adis16201_data_rdy_trigger_set_state;
+ st->trig->try_reenable = &adis16201_trig_try_reen;
+ st->trig->control_attrs = &adis16201_trigger_attr_group;
+ ret = iio_trigger_register(st->trig);
+
+ /* select default trigger */
+ indio_dev->trig = st->trig;
+ if (ret)
+ goto error_free_trig_name;
+
+ return 0;
+
+error_free_trig_name:
+ kfree(st->trig->name);
+error_free_trig:
+ iio_free_trigger(st->trig);
+
+ return ret;
+}
+
+void adis16201_remove_trigger(struct iio_dev *indio_dev)
+{
+ struct adis16201_state *state = indio_dev->dev_data;
+
+ iio_trigger_unregister(state->trig);
+ kfree(state->trig->name);
+ iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h
new file mode 100644
index 000000000000..b39323eac9e3
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16203.h
@@ -0,0 +1,143 @@
+#ifndef SPI_ADIS16203_H_
+#define SPI_ADIS16203_H_
+
+#define ADIS16203_STARTUP_DELAY 220 /* ms */
+
+#define ADIS16203_READ_REG(a) a
+#define ADIS16203_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16203_FLASH_CNT 0x00 /* Flash memory write count */
+#define ADIS16203_SUPPLY_OUT 0x02 /* Output, power supply */
+#define ADIS16203_AUX_ADC 0x08 /* Output, auxiliary ADC input */
+#define ADIS16203_TEMP_OUT 0x0A /* Output, temperature */
+#define ADIS16203_XINCL_OUT 0x0C /* Output, x-axis inclination */
+#define ADIS16203_YINCL_OUT 0x0E /* Output, y-axis inclination */
+#define ADIS16203_INCL_NULL 0x18 /* Incline null calibration */
+#define ADIS16203_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16203_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16203_ALM_SMPL1 0x24 /* Alarm 1, sample period */
+#define ADIS16203_ALM_SMPL2 0x26 /* Alarm 2, sample period */
+#define ADIS16203_ALM_CTRL 0x28 /* Alarm control */
+#define ADIS16203_AUX_DAC 0x30 /* Auxiliary DAC data */
+#define ADIS16203_GPIO_CTRL 0x32 /* General-purpose digital input/output control */
+#define ADIS16203_MSC_CTRL 0x34 /* Miscellaneous control */
+#define ADIS16203_SMPL_PRD 0x36 /* Internal sample period (rate) control */
+#define ADIS16203_AVG_CNT 0x38 /* Operation, filter configuration */
+#define ADIS16203_SLP_CNT 0x3A /* Operation, sleep mode control */
+#define ADIS16203_DIAG_STAT 0x3C /* Diagnostics, system status register */
+#define ADIS16203_GLOB_CMD 0x3E /* Operation, system command register */
+
+#define ADIS16203_OUTPUTS 5
+
+/* MSC_CTRL */
+#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
+#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN (1 << 9) /* Reverses rotation of both inclination outputs */
+#define ADIS16203_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */
+#define ADIS16203_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16203_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 (1 << 0) /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* DIAG_STAT */
+#define ADIS16203_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag */
+#define ADIS16203_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */
+#define ADIS16203_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
+#define ADIS16203_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */
+#define ADIS16203_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */
+
+/* GLOB_CMD */
+#define ADIS16203_GLOB_CMD_SW_RESET (1<<7)
+#define ADIS16203_GLOB_CMD_CLEAR_STAT (1<<4)
+#define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16203_MAX_TX 12
+#define ADIS16203_MAX_RX 10
+
+#define ADIS16203_ERROR_ACTIVE (1<<14)
+
+/**
+ * struct adis16203_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16203_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+int adis16203_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16203_scan {
+ ADIS16203_SCAN_SUPPLY,
+ ADIS16203_SCAN_AUX_ADC,
+ ADIS16203_SCAN_TEMP,
+ ADIS16203_SCAN_INCLI_X,
+ ADIS16203_SCAN_INCLI_Y,
+};
+
+void adis16203_remove_trigger(struct iio_dev *indio_dev);
+int adis16203_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16203_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+int adis16203_configure_ring(struct iio_dev *indio_dev);
+void adis16203_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16203_initialize_ring(struct iio_ring_buffer *ring);
+void adis16203_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16203_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16203_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16203_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16203_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16203_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16203_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16203_H_ */
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
new file mode 100644
index 000000000000..b57f19087a93
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -0,0 +1,568 @@
+/*
+ * ADIS16203 Programmable Digital Vibration Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "inclinometer.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16203.h"
+
+#define DRIVER_NAME "adis16203"
+
+static int adis16203_check_status(struct device *dev);
+
+/**
+ * adis16203_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16203_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16203_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16203_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16203_spi_write_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .tx_buf = st->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16203_WRITE_REG(lower_reg_address);
+ st->tx[1] = value & 0xFF;
+ st->tx[2] = ADIS16203_WRITE_REG(lower_reg_address + 1);
+ st->tx[3] = (value >> 8) & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16203_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16203_spi_read_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16203_READ_REG(lower_reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ lower_reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t adis16203_read_12bit_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16203_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16203_ERROR_ACTIVE)
+ adis16203_check_status(dev);
+
+ return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16203_read_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u16 val;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16203_spi_read_reg_16(dev, ADIS16203_TEMP_OUT, (u16 *)&val);
+ if (ret)
+ goto error_ret;
+
+ if (val & ADIS16203_ERROR_ACTIVE)
+ adis16203_check_status(dev);
+
+ val &= 0xFFF;
+ ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static ssize_t adis16203_read_14bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16203_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16203_ERROR_ACTIVE)
+ adis16203_check_status(dev);
+
+ val = ((s16)(val << 2) >> 2);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16203_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16203_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int adis16203_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16203_spi_write_reg_8(dev,
+ ADIS16203_GLOB_CMD,
+ ADIS16203_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
+static ssize_t adis16203_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -EINVAL;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return adis16203_reset(dev);
+ }
+ return -EINVAL;
+}
+
+int adis16203_set_irq(struct device *dev, bool enable)
+{
+ int ret = 0;
+ u16 msc;
+
+ ret = adis16203_spi_read_reg_16(dev, ADIS16203_MSC_CTRL, &msc);
+ if (ret)
+ goto error_ret;
+
+ msc |= ADIS16203_MSC_CTRL_ACTIVE_HIGH;
+ msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_DIO1;
+ if (enable)
+ msc |= ADIS16203_MSC_CTRL_DATA_RDY_EN;
+ else
+ msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_EN;
+
+ ret = adis16203_spi_write_reg_16(dev, ADIS16203_MSC_CTRL, msc);
+
+error_ret:
+ return ret;
+}
+
+static int adis16203_check_status(struct device *dev)
+{
+ u16 status;
+ int ret;
+
+ ret = adis16203_spi_read_reg_16(dev, ADIS16203_DIAG_STAT, &status);
+ if (ret < 0) {
+ dev_err(dev, "Reading status failed\n");
+ goto error_ret;
+ }
+ ret = status & 0x1F;
+
+ if (status & ADIS16203_DIAG_STAT_SELFTEST_FAIL)
+ dev_err(dev, "Self test failure\n");
+ if (status & ADIS16203_DIAG_STAT_SPI_FAIL)
+ dev_err(dev, "SPI failure\n");
+ if (status & ADIS16203_DIAG_STAT_FLASH_UPT)
+ dev_err(dev, "Flash update failed\n");
+ if (status & ADIS16203_DIAG_STAT_POWER_HIGH)
+ dev_err(dev, "Power supply above 3.625V\n");
+ if (status & ADIS16203_DIAG_STAT_POWER_LOW)
+ dev_err(dev, "Power supply below 3.15V\n");
+
+error_ret:
+ return ret;
+}
+
+static int adis16203_self_test(struct device *dev)
+{
+ int ret;
+ ret = adis16203_spi_write_reg_16(dev,
+ ADIS16203_MSC_CTRL,
+ ADIS16203_MSC_CTRL_SELF_TEST_EN);
+ if (ret) {
+ dev_err(dev, "problem starting self test");
+ goto err_ret;
+ }
+
+ adis16203_check_status(dev);
+
+err_ret:
+ return ret;
+}
+
+static int adis16203_initial_setup(struct adis16203_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* Disable IRQ */
+ ret = adis16203_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ /* Do self test */
+ ret = adis16203_self_test(dev);
+ if (ret) {
+ dev_err(dev, "self test failure");
+ goto err_ret;
+ }
+
+ /* Read status register to check the result */
+ ret = adis16203_check_status(dev);
+ if (ret) {
+ adis16203_reset(dev);
+ dev_err(dev, "device not playing ball -> reset");
+ msleep(ADIS16203_STARTUP_DELAY);
+ ret = adis16203_check_status(dev);
+ if (ret) {
+ dev_err(dev, "giving up");
+ goto err_ret;
+ }
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+ st->us->chip_select, st->us->irq);
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16203_read_12bit_unsigned,
+ ADIS16203_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16203_read_12bit_unsigned,
+ ADIS16203_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_INCLI_X(adis16203_read_14bit_signed,
+ ADIS16203_XINCL_OUT);
+static IIO_DEV_ATTR_INCLI_Y(adis16203_read_14bit_signed,
+ ADIS16203_YINCL_OUT);
+static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO,
+ adis16203_read_14bit_signed,
+ adis16203_write_16bit,
+ ADIS16203_INCL_NULL);
+static IIO_CONST_ATTR(incli_scale, "0.025");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16203_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16203_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16203");
+
+static struct attribute *adis16203_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16203_event_attribute_group = {
+ .attrs = adis16203_event_attributes,
+};
+
+static struct attribute *adis16203_attributes[] = {
+ &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+ &iio_const_attr_in0_supply_scale.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
+ &iio_const_attr_in1_scale.dev_attr.attr,
+ &iio_dev_attr_incli_x_raw.dev_attr.attr,
+ &iio_dev_attr_incli_y_raw.dev_attr.attr,
+ &iio_dev_attr_incli_x_offset.dev_attr.attr,
+ &iio_const_attr_incli_scale.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16203_attribute_group = {
+ .attrs = adis16203_attributes,
+};
+
+static int __devinit adis16203_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16203_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16203_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16203_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16203_event_attribute_group;
+ st->indio_dev->attrs = &adis16203_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16203_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16203_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16203");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16203_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = adis16203_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ adis16203_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (spi->irq)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16203_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16203_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int adis16203_remove(struct spi_device *spi)
+{
+ struct adis16203_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16203_remove_trigger(indio_dev);
+ if (spi->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16203_uninitialize_ring(indio_dev->ring);
+ iio_device_unregister(indio_dev);
+ adis16203_unconfigure_ring(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver adis16203_driver = {
+ .driver = {
+ .name = "adis16203",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16203_probe,
+ .remove = __devexit_p(adis16203_remove),
+};
+
+static __init int adis16203_init(void)
+{
+ return spi_register_driver(&adis16203_driver);
+}
+module_init(adis16203_init);
+
+static __exit void adis16203_exit(void)
+{
+ spi_unregister_driver(&adis16203_driver);
+}
+module_exit(adis16203_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable Digital Vibration Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
new file mode 100644
index 000000000000..3d774f7efa25
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -0,0 +1,211 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16203.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16203_SCAN_SUPPLY, ADIS16203_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(in0, ADIS16203_SCAN_AUX_ADC, ADIS16203_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16203_SCAN_TEMP, ADIS16203_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_C(incli_x, ADIS16203_SCAN_INCLI_X,
+ ADIS16203_XINCL_OUT, NULL);
+static IIO_SCAN_EL_C(incli_y, ADIS16203_SCAN_INCLI_Y,
+ ADIS16203_YINCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16);
+static IIO_SCAN_EL_TIMESTAMP(5);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16203_scan_el_attrs[] = {
+ &iio_scan_el_in_supply.dev_attr.attr,
+ &iio_const_attr_in_supply_index.dev_attr.attr,
+ &iio_const_attr_in_supply_type.dev_attr.attr,
+ &iio_scan_el_in0.dev_attr.attr,
+ &iio_const_attr_in0_index.dev_attr.attr,
+ &iio_const_attr_in0_type.dev_attr.attr,
+ &iio_scan_el_temp.dev_attr.attr,
+ &iio_const_attr_temp_index.dev_attr.attr,
+ &iio_const_attr_temp_type.dev_attr.attr,
+ &iio_scan_el_incli_x.dev_attr.attr,
+ &iio_const_attr_incli_x_index.dev_attr.attr,
+ &iio_scan_el_incli_y.dev_attr.attr,
+ &iio_const_attr_incli_y_index.dev_attr.attr,
+ &iio_const_attr_incli_type.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adis16203_scan_el_group = {
+ .attrs = adis16203_scan_el_attrs,
+ .name = "scan_elements",
+};
+
+/**
+ * adis16203_poll_func_th() top half interrupt handler called by trigger
+ * @private_data: iio_dev
+ **/
+static void adis16203_poll_func_th(struct iio_dev *indio_dev, s64 timestamp)
+{
+ struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+ st->last_timestamp = timestamp;
+ schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16203_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16203_read_ring_data(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
+ int ret;
+ int i;
+
+ mutex_lock(&st->buf_lock);
+
+ spi_message_init(&msg);
+
+ memset(xfers, 0, sizeof(xfers));
+ for (i = 0; i <= ADIS16203_OUTPUTS; i++) {
+ xfers[i].bits_per_word = 8;
+ xfers[i].cs_change = 1;
+ xfers[i].len = 2;
+ xfers[i].delay_usecs = 20;
+ xfers[i].tx_buf = st->tx + 2 * i;
+ if (i < 1) /* SUPPLY_OUT: 0x02, AUX_ADC: 0x08 */
+ st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i);
+ else
+ st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i + 6);
+ st->tx[2 * i + 1] = 0;
+ if (i >= 1)
+ xfers[i].rx_buf = rx + 2 * (i - 1);
+ spi_message_add_tail(&xfers[i], &msg);
+ }
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16203_trigger_bh_to_ring(struct work_struct *work_s)
+{
+ struct adis16203_state *st
+ = container_of(work_s, struct adis16203_state,
+ work_trigger_to_ring);
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+ int i = 0;
+ s16 *data;
+ size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+ data = kmalloc(datasize, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&st->us->dev, "memory alloc failed in ring bh");
+ return;
+ }
+
+ if (ring->scan_count)
+ if (adis16203_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+ for (; i < ring->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (ring->scan_timestamp)
+ *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+ ring->access.store_to(ring,
+ (u8 *)data,
+ st->last_timestamp);
+
+ iio_trigger_notify_done(st->indio_dev->trig);
+ kfree(data);
+
+ return;
+}
+
+void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
+{
+ kfree(indio_dev->pollfunc);
+ iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16203_configure_ring(struct iio_dev *indio_dev)
+{
+ int ret = 0;
+ struct adis16203_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring;
+ INIT_WORK(&st->work_trigger_to_ring, adis16203_trigger_bh_to_ring);
+
+ ring = iio_sw_rb_allocate(indio_dev);
+ if (!ring) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ indio_dev->ring = ring;
+ /* Effectively select the ring buffer implementation */
+ iio_ring_sw_register_funcs(&ring->access);
+ ring->bpe = 2;
+ ring->scan_el_attrs = &adis16203_scan_el_group;
+ ring->scan_timestamp = true;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
+ ring->owner = THIS_MODULE;
+
+ /* Set default scan mode */
+ iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+ iio_scan_mask_set(ring, iio_scan_el_temp.number);
+ iio_scan_mask_set(ring, iio_scan_el_in0.number);
+ iio_scan_mask_set(ring, iio_scan_el_incli_x.number);
+ iio_scan_mask_set(ring, iio_scan_el_incli_y.number);
+
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16203_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
+ indio_dev->modes |= INDIO_RING_TRIGGERED;
+ return 0;
+
+error_iio_sw_rb_free:
+ iio_sw_rb_free(indio_dev->ring);
+ return ret;
+}
+
+int adis16203_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16203_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+ iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c
new file mode 100644
index 000000000000..50be51c25dc2
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16203_trigger.c
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16203.h"
+
+/**
+ * adis16203_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16203_data_rdy_trig_poll(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adis16203_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_trigger *trig = st->trig;
+
+ iio_trigger_poll(trig, timestamp);
+
+ return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16203_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16203_trigger_attrs[] = {
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group adis16203_trigger_attr_group = {
+ .attrs = adis16203_trigger_attrs,
+};
+
+/**
+ * adis16203_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16203_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct adis16203_state *st = trig->private_data;
+ struct iio_dev *indio_dev = st->indio_dev;
+ int ret = 0;
+
+ dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+ ret = adis16203_set_irq(&st->indio_dev->dev, state);
+ if (state == false) {
+ iio_remove_event_from_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]
+ ->ev_list);
+ flush_scheduled_work();
+ } else {
+ iio_add_event_to_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]->ev_list);
+ }
+ return ret;
+}
+
+/**
+ * adis16203_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig: the datardy trigger
+ **/
+static int adis16203_trig_try_reen(struct iio_trigger *trig)
+{
+ struct adis16203_state *st = trig->private_data;
+ enable_irq(st->us->irq);
+ return 0;
+}
+
+int adis16203_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct adis16203_state *st = indio_dev->dev_data;
+
+ st->trig = iio_allocate_trigger();
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16203-dev%d",
+ indio_dev->id);
+ if (!st->trig->name) {
+ ret = -ENOMEM;
+ goto error_free_trig;
+ }
+ st->trig->dev.parent = &st->us->dev;
+ st->trig->owner = THIS_MODULE;
+ st->trig->private_data = st;
+ st->trig->set_trigger_state = &adis16203_data_rdy_trigger_set_state;
+ st->trig->try_reenable = &adis16203_trig_try_reen;
+ st->trig->control_attrs = &adis16203_trigger_attr_group;
+ ret = iio_trigger_register(st->trig);
+
+ /* select default trigger */
+ indio_dev->trig = st->trig;
+ if (ret)
+ goto error_free_trig_name;
+
+ return 0;
+
+error_free_trig_name:
+ kfree(st->trig->name);
+error_free_trig:
+ iio_free_trigger(st->trig);
+
+ return ret;
+}
+
+void adis16203_remove_trigger(struct iio_dev *indio_dev)
+{
+ struct adis16203_state *state = indio_dev->dev_data;
+
+ iio_trigger_unregister(state->trig);
+ kfree(state->trig->name);
+ iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/accel/adis16204.h b/drivers/staging/iio/accel/adis16204.h
new file mode 100644
index 000000000000..e9ed7cb048cf
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16204.h
@@ -0,0 +1,151 @@
+#ifndef SPI_ADIS16204_H_
+#define SPI_ADIS16204_H_
+
+#define ADIS16204_STARTUP_DELAY 220 /* ms */
+
+#define ADIS16204_READ_REG(a) a
+#define ADIS16204_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16204_FLASH_CNT 0x00 /* Flash memory write count */
+#define ADIS16204_SUPPLY_OUT 0x02 /* Output, power supply */
+#define ADIS16204_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
+#define ADIS16204_YACCL_OUT 0x06 /* Output, y-axis accelerometer */
+#define ADIS16204_AUX_ADC 0x08 /* Output, auxiliary ADC input */
+#define ADIS16204_TEMP_OUT 0x0A /* Output, temperature */
+#define ADIS16204_X_PEAK_OUT 0x0C /* Twos complement */
+#define ADIS16204_Y_PEAK_OUT 0x0E /* Twos complement */
+#define ADIS16204_XACCL_NULL 0x10 /* Calibration, x-axis acceleration offset null */
+#define ADIS16204_YACCL_NULL 0x12 /* Calibration, y-axis acceleration offset null */
+#define ADIS16204_XACCL_SCALE 0x14 /* X-axis scale factor calibration register */
+#define ADIS16204_YACCL_SCALE 0x16 /* Y-axis scale factor calibration register */
+#define ADIS16204_XY_RSS_OUT 0x18 /* XY combined acceleration (RSS) */
+#define ADIS16204_XY_PEAK_OUT 0x1A /* Peak, XY combined output (RSS) */
+#define ADIS16204_CAP_BUF_1 0x1C /* Capture buffer output register 1 */
+#define ADIS16204_CAP_BUF_2 0x1E /* Capture buffer output register 2 */
+#define ADIS16204_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16204_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16204_ALM_CTRL 0x28 /* Alarm control */
+#define ADIS16204_CAPT_PNTR 0x2A /* Capture register address pointer */
+#define ADIS16204_AUX_DAC 0x30 /* Auxiliary DAC data */
+#define ADIS16204_GPIO_CTRL 0x32 /* General-purpose digital input/output control */
+#define ADIS16204_MSC_CTRL 0x34 /* Miscellaneous control */
+#define ADIS16204_SMPL_PRD 0x36 /* Internal sample period (rate) control */
+#define ADIS16204_AVG_CNT 0x38 /* Operation, filter configuration */
+#define ADIS16204_SLP_CNT 0x3A /* Operation, sleep mode control */
+#define ADIS16204_DIAG_STAT 0x3C /* Diagnostics, system status register */
+#define ADIS16204_GLOB_CMD 0x3E /* Operation, system command register */
+
+#define ADIS16204_OUTPUTS 5
+
+/* MSC_CTRL */
+#define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
+#define ADIS16204_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */
+#define ADIS16204_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16204_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16204_MSC_CTRL_DATA_RDY_DIO2 (1 << 0) /* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
+
+/* DIAG_STAT */
+#define ADIS16204_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16204_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16204_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag: 1 = error condition,
+ 0 = normal operation */
+#define ADIS16204_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */
+#define ADIS16204_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
+#define ADIS16204_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */
+#define ADIS16204_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 2.975 V */
+
+/* GLOB_CMD */
+#define ADIS16204_GLOB_CMD_SW_RESET (1<<7)
+#define ADIS16204_GLOB_CMD_CLEAR_STAT (1<<4)
+#define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16204_MAX_TX 24
+#define ADIS16204_MAX_RX 24
+
+#define ADIS16204_ERROR_ACTIVE (1<<14)
+
+/**
+ * struct adis16204_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16204_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+int adis16204_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16204_scan {
+ ADIS16204_SCAN_SUPPLY,
+ ADIS16204_SCAN_ACC_X,
+ ADIS16204_SCAN_ACC_Y,
+ ADIS16204_SCAN_AUX_ADC,
+ ADIS16204_SCAN_TEMP,
+};
+
+void adis16204_remove_trigger(struct iio_dev *indio_dev);
+int adis16204_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16204_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+int adis16204_configure_ring(struct iio_dev *indio_dev);
+void adis16204_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16204_initialize_ring(struct iio_ring_buffer *ring);
+void adis16204_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16204_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16204_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16204_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16204_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16204_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16204_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16204_H_ */
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
new file mode 100644
index 000000000000..cc15e40726fc
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -0,0 +1,613 @@
+/*
+ * ADIS16204 Programmable High-g Digital Impact Sensor and Recorder
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16204.h"
+
+#define DRIVER_NAME "adis16204"
+
+static int adis16204_check_status(struct device *dev);
+
+/**
+ * adis16204_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16204_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16204_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16204_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16204_spi_write_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .tx_buf = st->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16204_WRITE_REG(lower_reg_address);
+ st->tx[1] = value & 0xFF;
+ st->tx[2] = ADIS16204_WRITE_REG(lower_reg_address + 1);
+ st->tx[3] = (value >> 8) & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16204_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16204_spi_read_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = 20,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16204_READ_REG(lower_reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ lower_reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t adis16204_read_12bit_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16204_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16204_ERROR_ACTIVE)
+ adis16204_check_status(dev);
+
+ return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16204_read_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ ssize_t ret;
+ u16 val;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16204_spi_read_reg_16(dev, ADIS16204_TEMP_OUT, (u16 *)&val);
+ if (ret)
+ goto error_ret;
+
+ if (val & ADIS16204_ERROR_ACTIVE)
+ adis16204_check_status(dev);
+
+ val &= 0xFFF;
+ ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static ssize_t adis16204_read_12bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16204_ERROR_ACTIVE)
+ adis16204_check_status(dev);
+
+ val = ((s16)(val << 4) >> 4);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16204_read_14bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s16 val = 0;
+ ssize_t ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (!ret) {
+ if (val & ADIS16204_ERROR_ACTIVE)
+ adis16204_check_status(dev);
+
+ val = ((s16)(val << 2) >> 2);
+ ret = sprintf(buf, "%d\n", val);
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16204_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16204_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int adis16204_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16204_spi_write_reg_8(dev,
+ ADIS16204_GLOB_CMD,
+ ADIS16204_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
+static ssize_t adis16204_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -EINVAL;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return adis16204_reset(dev);
+ }
+ return -EINVAL;
+}
+
+int adis16204_set_irq(struct device *dev, bool enable)
+{
+ int ret = 0;
+ u16 msc;
+
+ ret = adis16204_spi_read_reg_16(dev, ADIS16204_MSC_CTRL, &msc);
+ if (ret)
+ goto error_ret;
+
+ msc |= ADIS16204_MSC_CTRL_ACTIVE_HIGH;
+ msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_DIO2;
+ if (enable)
+ msc |= ADIS16204_MSC_CTRL_DATA_RDY_EN;
+ else
+ msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_EN;
+
+ ret = adis16204_spi_write_reg_16(dev, ADIS16204_MSC_CTRL, msc);
+
+error_ret:
+ return ret;
+}
+
+static int adis16204_check_status(struct device *dev)
+{
+ u16 status;
+ int ret;
+
+ ret = adis16204_spi_read_reg_16(dev, ADIS16204_DIAG_STAT, &status);
+ if (ret < 0) {
+ dev_err(dev, "Reading status failed\n");
+ goto error_ret;
+ }
+ ret = status & 0x1F;
+
+ if (status & ADIS16204_DIAG_STAT_SELFTEST_FAIL)
+ dev_err(dev, "Self test failure\n");
+ if (status & ADIS16204_DIAG_STAT_SPI_FAIL)
+ dev_err(dev, "SPI failure\n");
+ if (status & ADIS16204_DIAG_STAT_FLASH_UPT)
+ dev_err(dev, "Flash update failed\n");
+ if (status & ADIS16204_DIAG_STAT_POWER_HIGH)
+ dev_err(dev, "Power supply above 3.625V\n");
+ if (status & ADIS16204_DIAG_STAT_POWER_LOW)
+ dev_err(dev, "Power supply below 2.975V\n");
+
+error_ret:
+ return ret;
+}
+
+static int adis16204_self_test(struct device *dev)
+{
+ int ret;
+ ret = adis16204_spi_write_reg_16(dev,
+ ADIS16204_MSC_CTRL,
+ ADIS16204_MSC_CTRL_SELF_TEST_EN);
+ if (ret) {
+ dev_err(dev, "problem starting self test");
+ goto err_ret;
+ }
+
+ adis16204_check_status(dev);
+
+err_ret:
+ return ret;
+}
+
+static int adis16204_initial_setup(struct adis16204_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* Disable IRQ */
+ ret = adis16204_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ /* Do self test */
+ ret = adis16204_self_test(dev);
+ if (ret) {
+ dev_err(dev, "self test failure");
+ goto err_ret;
+ }
+
+ /* Read status register to check the result */
+ ret = adis16204_check_status(dev);
+ if (ret) {
+ adis16204_reset(dev);
+ dev_err(dev, "device not playing ball -> reset");
+ msleep(ADIS16204_STARTUP_DELAY);
+ ret = adis16204_check_status(dev);
+ if (ret) {
+ dev_err(dev, "giving up");
+ goto err_ret;
+ }
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+ st->us->chip_select, st->us->irq);
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16204_read_12bit_unsigned,
+ ADIS16204_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16204_read_12bit_unsigned,
+ ADIS16204_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_ACCEL_X(adis16204_read_14bit_signed,
+ ADIS16204_XACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_Y(adis16204_read_14bit_signed,
+ ADIS16204_YACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_XY(adis16204_read_14bit_signed,
+ ADIS16204_XY_RSS_OUT);
+static IIO_DEV_ATTR_ACCEL_XPEAK(adis16204_read_14bit_signed,
+ ADIS16204_X_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_YPEAK(adis16204_read_14bit_signed,
+ ADIS16204_Y_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed,
+ ADIS16204_XY_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
+ adis16204_read_12bit_signed,
+ adis16204_write_16bit,
+ ADIS16204_XACCL_NULL);
+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
+ adis16204_read_12bit_signed,
+ adis16204_write_16bit,
+ ADIS16204_YACCL_NULL);
+static IIO_CONST_ATTR(accel_x_scale, "0.017125");
+static IIO_CONST_ATTR(accel_y_scale, "0.008407");
+static IIO_CONST_ATTR(accel_xy_scale, "0.017125");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16204_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16204_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16204");
+
+static struct attribute *adis16204_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16204_event_attribute_group = {
+ .attrs = adis16204_event_attributes,
+};
+
+static struct attribute *adis16204_attributes[] = {
+ &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+ &iio_const_attr_in0_supply_scale.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
+ &iio_const_attr_in1_scale.dev_attr.attr,
+ &iio_dev_attr_accel_x_raw.dev_attr.attr,
+ &iio_dev_attr_accel_y_raw.dev_attr.attr,
+ &iio_dev_attr_accel_xy.dev_attr.attr,
+ &iio_dev_attr_accel_xpeak.dev_attr.attr,
+ &iio_dev_attr_accel_ypeak.dev_attr.attr,
+ &iio_dev_attr_accel_xypeak.dev_attr.attr,
+ &iio_dev_attr_accel_x_offset.dev_attr.attr,
+ &iio_dev_attr_accel_y_offset.dev_attr.attr,
+ &iio_const_attr_accel_x_scale.dev_attr.attr,
+ &iio_const_attr_accel_y_scale.dev_attr.attr,
+ &iio_const_attr_accel_xy_scale.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16204_attribute_group = {
+ .attrs = adis16204_attributes,
+};
+
+static int __devinit adis16204_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16204_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16204_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16204_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16204_event_attribute_group;
+ st->indio_dev->attrs = &adis16204_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16204_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16204_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16204");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16204_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = adis16204_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ adis16204_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (spi->irq)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16204_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16204_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int adis16204_remove(struct spi_device *spi)
+{
+ struct adis16204_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16204_remove_trigger(indio_dev);
+ if (spi->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16204_uninitialize_ring(indio_dev->ring);
+ iio_device_unregister(indio_dev);
+ adis16204_unconfigure_ring(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver adis16204_driver = {
+ .driver = {
+ .name = "adis16204",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16204_probe,
+ .remove = __devexit_p(adis16204_remove),
+};
+
+static __init int adis16204_init(void)
+{
+ return spi_register_driver(&adis16204_driver);
+}
+module_init(adis16204_init);
+
+static __exit void adis16204_exit(void)
+{
+ spi_unregister_driver(&adis16204_driver);
+}
+module_exit(adis16204_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
new file mode 100644
index 000000000000..420b160fe3ab
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -0,0 +1,206 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16204.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16204_SCAN_SUPPLY, ADIS16204_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(accel_x, ADIS16204_SCAN_ACC_X, ADIS16204_XACCL_OUT, NULL);
+static IIO_SCAN_EL_C(accel_y, ADIS16204_SCAN_ACC_Y, ADIS16204_YACCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16);
+static IIO_SCAN_EL_C(in0, ADIS16204_SCAN_AUX_ADC, ADIS16204_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16204_SCAN_TEMP, ADIS16204_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_TIMESTAMP(5);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16204_scan_el_attrs[] = {
+ &iio_scan_el_in_supply.dev_attr.attr,
+ &iio_const_attr_in_supply_index.dev_attr.attr,
+ &iio_const_attr_in_supply_type.dev_attr.attr,
+ &iio_scan_el_accel_x.dev_attr.attr,
+ &iio_const_attr_accel_x_index.dev_attr.attr,
+ &iio_scan_el_accel_y.dev_attr.attr,
+ &iio_const_attr_accel_y_index.dev_attr.attr,
+ &iio_const_attr_accel_type.dev_attr.attr,
+ &iio_scan_el_in0.dev_attr.attr,
+ &iio_const_attr_in0_index.dev_attr.attr,
+ &iio_const_attr_in0_type.dev_attr.attr,
+ &iio_scan_el_temp.dev_attr.attr,
+ &iio_const_attr_temp_index.dev_attr.attr,
+ &iio_const_attr_temp_type.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adis16204_scan_el_group = {
+ .attrs = adis16204_scan_el_attrs,
+ .name = "scan_elements",
+};
+
+/**
+ * adis16204_poll_func_th() top half interrupt handler called by trigger
+ * @private_data: iio_dev
+ **/
+static void adis16204_poll_func_th(struct iio_dev *indio_dev, s64 timestamp)
+{
+ struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+ st->last_timestamp = timestamp;
+ schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16204_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16204_read_ring_data(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
+ int ret;
+ int i;
+
+ mutex_lock(&st->buf_lock);
+
+ spi_message_init(&msg);
+
+ memset(xfers, 0, sizeof(xfers));
+ for (i = 0; i <= ADIS16204_OUTPUTS; i++) {
+ xfers[i].bits_per_word = 8;
+ xfers[i].cs_change = 1;
+ xfers[i].len = 2;
+ xfers[i].delay_usecs = 20;
+ xfers[i].tx_buf = st->tx + 2 * i;
+ st->tx[2 * i] = ADIS16204_READ_REG(ADIS16204_SUPPLY_OUT + 2 * i);
+ st->tx[2 * i + 1] = 0;
+ if (i >= 1)
+ xfers[i].rx_buf = rx + 2 * (i - 1);
+ spi_message_add_tail(&xfers[i], &msg);
+ }
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16204_trigger_bh_to_ring(struct work_struct *work_s)
+{
+ struct adis16204_state *st
+ = container_of(work_s, struct adis16204_state,
+ work_trigger_to_ring);
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+ int i = 0;
+ s16 *data;
+ size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+ data = kmalloc(datasize, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&st->us->dev, "memory alloc failed in ring bh");
+ return;
+ }
+
+ if (ring->scan_count)
+ if (adis16204_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+ for (; i < ring->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (ring->scan_timestamp)
+ *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+ ring->access.store_to(ring,
+ (u8 *)data,
+ st->last_timestamp);
+
+ iio_trigger_notify_done(st->indio_dev->trig);
+ kfree(data);
+
+ return;
+}
+
+void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
+{
+ kfree(indio_dev->pollfunc);
+ iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16204_configure_ring(struct iio_dev *indio_dev)
+{
+ int ret = 0;
+ struct adis16204_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring;
+ INIT_WORK(&st->work_trigger_to_ring, adis16204_trigger_bh_to_ring);
+
+ ring = iio_sw_rb_allocate(indio_dev);
+ if (!ring) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ indio_dev->ring = ring;
+ /* Effectively select the ring buffer implementation */
+ iio_ring_sw_register_funcs(&ring->access);
+ ring->bpe = 2;
+ ring->scan_el_attrs = &adis16204_scan_el_group;
+ ring->scan_timestamp = true;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
+ ring->owner = THIS_MODULE;
+
+ /* Set default scan mode */
+ iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+ iio_scan_mask_set(ring, iio_scan_el_accel_x.number);
+ iio_scan_mask_set(ring, iio_scan_el_accel_y.number);
+ iio_scan_mask_set(ring, iio_scan_el_temp.number);
+ iio_scan_mask_set(ring, iio_scan_el_in0.number);
+
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16204_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
+ indio_dev->modes |= INDIO_RING_TRIGGERED;
+ return 0;
+
+error_iio_sw_rb_free:
+ iio_sw_rb_free(indio_dev->ring);
+ return ret;
+}
+
+int adis16204_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16204_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+ iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c
new file mode 100644
index 000000000000..8e9db90e51eb
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16204_trigger.c
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16204.h"
+
+/**
+ * adis16204_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16204_data_rdy_trig_poll(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adis16204_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_trigger *trig = st->trig;
+
+ iio_trigger_poll(trig, timestamp);
+
+ return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16204_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16204_trigger_attrs[] = {
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group adis16204_trigger_attr_group = {
+ .attrs = adis16204_trigger_attrs,
+};
+
+/**
+ * adis16204_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16204_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct adis16204_state *st = trig->private_data;
+ struct iio_dev *indio_dev = st->indio_dev;
+ int ret = 0;
+
+ dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+ ret = adis16204_set_irq(&st->indio_dev->dev, state);
+ if (state == false) {
+ iio_remove_event_from_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]
+ ->ev_list);
+ flush_scheduled_work();
+ } else {
+ iio_add_event_to_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]->ev_list);
+ }
+ return ret;
+}
+
+/**
+ * adis16204_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig: the datardy trigger
+ **/
+static int adis16204_trig_try_reen(struct iio_trigger *trig)
+{
+ struct adis16204_state *st = trig->private_data;
+ enable_irq(st->us->irq);
+ return 0;
+}
+
+int adis16204_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct adis16204_state *st = indio_dev->dev_data;
+
+ st->trig = iio_allocate_trigger();
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16204-dev%d",
+ indio_dev->id);
+ if (!st->trig->name) {
+ ret = -ENOMEM;
+ goto error_free_trig;
+ }
+ st->trig->dev.parent = &st->us->dev;
+ st->trig->owner = THIS_MODULE;
+ st->trig->private_data = st;
+ st->trig->set_trigger_state = &adis16204_data_rdy_trigger_set_state;
+ st->trig->try_reenable = &adis16204_trig_try_reen;
+ st->trig->control_attrs = &adis16204_trigger_attr_group;
+ ret = iio_trigger_register(st->trig);
+
+ /* select default trigger */
+ indio_dev->trig = st->trig;
+ if (ret)
+ goto error_free_trig_name;
+
+ return 0;
+
+error_free_trig_name:
+ kfree(st->trig->name);
+error_free_trig:
+ iio_free_trigger(st->trig);
+
+ return ret;
+}
+
+void adis16204_remove_trigger(struct iio_dev *indio_dev)
+{
+ struct adis16204_state *state = indio_dev->dev_data;
+
+ iio_trigger_unregister(state->trig);
+ kfree(state->trig->name);
+ iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 033135c6f226..8eba0af98ed5 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -105,7 +105,7 @@ static int adis16209_read_ring_data(struct device *dev, u8 *rx)
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
- xfers[i].delay_usecs = 20;
+ xfers[i].delay_usecs = 30;
xfers[i].tx_buf = st->tx + 2 * i;
st->tx[2 * i]
= ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i);
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index c86d1498737d..1c1e98aee2d9 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -507,7 +507,7 @@ static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL,
adis16220_write_reset, 0);
#define IIO_DEV_ATTR_CAPTURE(_store) \
- IIO_DEVICE_ATTR(capture, S_IWUGO, NULL, _store, 0)
+ IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0)
static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture);
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 330d5d6dbba4..1fd088a11076 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -517,7 +517,7 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th);
if (ret)
- goto error_iio_sw_rb_free;;
+ goto error_iio_sw_rb_free;
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index acb67677e563..86869cd233ae 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -27,6 +27,41 @@ config MAX1363_RING_BUFFER
Say yes here to include ring buffer support in the MAX1363
ADC driver.
+config AD7150
+ tristate "Analog Devices ad7150/1/6 capacitive sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices capacitive sensors.
+ (ad7150, ad7151, ad7156) Provides direct access via sysfs.
+
+config AD7152
+ tristate "Analog Devices ad7152/3 capacitive sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices capacitive sensors.
+ (ad7152, ad7153) Provides direct access via sysfs.
+
+config AD7291
+ tristate "Analog Devices AD7291 temperature sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices AD7291
+ temperature sensors.
+
+config AD7298
+ tristate "Analog Devices AD7298 temperature sensor and ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD7298
+ temperature sensors and ADC.
+
+config AD7314
+ tristate "Analog Devices AD7314 temperature sensor driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD7314
+ temperature sensors.
+
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
@@ -50,9 +85,9 @@ config AD799X_RING_BUFFER
config AD7476
tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
depends on SPI
- select IIO_RING_BUFFER
+ select IIO_RING_BUFFER
select IIO_SW_RING
- select IIO_TRIGGER
+ select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495
@@ -61,3 +96,55 @@ config AD7476
To compile this driver as a module, choose M here: the
module will be called ad7476.
+
+config AD7887
+ tristate "Analog Devices AD7887 ADC driver"
+ depends on SPI
+ select IIO_RING_BUFFER
+ select IIO_SW_RING
+ select IIO_TRIGGER
+ help
+ Say yes here to build support for Analog Devices
+ AD7887 SPI analog to digital convertor (ADC).
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7887.
+
+config AD7745
+ tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices capacitive sensors.
+ (AD7745, AD7746, AD7747) Provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7745.
+
+config AD7816
+ tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD7816/7/8
+ temperature sensors and ADC.
+
+config ADT75
+ tristate "Analog Devices ADT75 temperature sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices ADT75
+ temperature sensors.
+
+config ADT7310
+ tristate "Analog Devices ADT7310 temperature sensor driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADT7310
+ temperature sensors.
+
+config ADT7410
+ tristate "Analog Devices ADT7410 temperature sensor driver"
+ depends on I2C
+ help
+ Say yes here to build support for Analog Devices ADT7410
+ temperature sensors.
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index b62c319bcedd..6f231a2cb777 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -14,3 +14,18 @@ obj-$(CONFIG_AD799X) += ad799x.o
ad7476-y := ad7476_core.o
ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o
obj-$(CONFIG_AD7476) += ad7476.o
+
+ad7887-y := ad7887_core.o
+ad7887-$(CONFIG_IIO_RING_BUFFER) += ad7887_ring.o
+obj-$(CONFIG_AD7887) += ad7887.o
+
+obj-$(CONFIG_AD7150) += ad7150.o
+obj-$(CONFIG_AD7152) += ad7152.o
+obj-$(CONFIG_AD7291) += ad7291.o
+obj-$(CONFIG_AD7298) += ad7298.o
+obj-$(CONFIG_AD7314) += ad7314.o
+obj-$(CONFIG_AD7745) += ad7745.o
+obj-$(CONFIG_AD7816) += ad7816.o
+obj-$(CONFIG_ADT75) += adt75.o
+obj-$(CONFIG_ADT7310) += adt7310.o
+obj-$(CONFIG_ADT7410) += adt7410.o
diff --git a/drivers/staging/iio/adc/ad7150.c b/drivers/staging/iio/adc/ad7150.c
new file mode 100644
index 000000000000..8555766109d8
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7150.c
@@ -0,0 +1,877 @@
+/*
+ * AD7150 capacitive sensor driver supporting AD7150/1/6
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7150 registers definition
+ */
+
+#define AD7150_STATUS 0
+#define AD7150_STATUS_OUT1 (1 << 3)
+#define AD7150_STATUS_OUT2 (1 << 5)
+#define AD7150_CH1_DATA_HIGH 1
+#define AD7150_CH1_DATA_LOW 2
+#define AD7150_CH2_DATA_HIGH 3
+#define AD7150_CH2_DATA_LOW 4
+#define AD7150_CH1_AVG_HIGH 5
+#define AD7150_CH1_AVG_LOW 6
+#define AD7150_CH2_AVG_HIGH 7
+#define AD7150_CH2_AVG_LOW 8
+#define AD7150_CH1_SENSITIVITY 9
+#define AD7150_CH1_THR_HOLD_H 9
+#define AD7150_CH1_TIMEOUT 10
+#define AD7150_CH1_THR_HOLD_L 10
+#define AD7150_CH1_SETUP 11
+#define AD7150_CH2_SENSITIVITY 12
+#define AD7150_CH2_THR_HOLD_H 12
+#define AD7150_CH2_TIMEOUT 13
+#define AD7150_CH2_THR_HOLD_L 13
+#define AD7150_CH2_SETUP 14
+#define AD7150_CFG 15
+#define AD7150_CFG_FIX (1 << 7)
+#define AD7150_PD_TIMER 16
+#define AD7150_CH1_CAPDAC 17
+#define AD7150_CH2_CAPDAC 18
+#define AD7150_SN3 19
+#define AD7150_SN2 20
+#define AD7150_SN1 21
+#define AD7150_SN0 22
+#define AD7150_ID 23
+
+#define AD7150_MAX_CONV_MODE 4
+
+/*
+ * struct ad7150_chip_info - chip specifc information
+ */
+
+struct ad7150_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ bool inter;
+ s64 last_timestamp;
+ u16 ch1_threshold; /* Ch1 Threshold (in fixed threshold mode) */
+ u8 ch1_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */
+ u8 ch1_timeout; /* Ch1 Timeout (in adaptive threshold mode) */
+ u8 ch1_setup;
+ u16 ch2_threshold; /* Ch2 Threshold (in fixed threshold mode) */
+ u8 ch2_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */
+ u8 ch2_timeout; /* Ch1 Timeout (in adaptive threshold mode) */
+ u8 ch2_setup;
+ u8 powerdown_timer;
+ char threshold_mode[10]; /* adaptive/fixed threshold mode */
+ int old_state;
+ char *conversion_mode;
+};
+
+struct ad7150_conversion_mode {
+ char *name;
+ u8 reg_cfg;
+};
+
+struct ad7150_conversion_mode ad7150_conv_mode_table[AD7150_MAX_CONV_MODE] = {
+ { "idle", 0 },
+ { "continuous-conversion", 1 },
+ { "single-conversion", 2 },
+ { "power-down", 3 },
+};
+
+/*
+ * ad7150 register access by I2C
+ */
+
+static int ad7150_i2c_read(struct ad7150_chip_info *chip, u8 reg, u8 *data, int len)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_master_send(client, &reg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C write error\n");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, data, len);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ad7150_i2c_write(struct ad7150_chip_info *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ u8 tx[2] = {
+ reg,
+ data,
+ };
+
+ ret = i2c_master_send(client, tx, 2);
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \
+ IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(_show) \
+ IIO_DEVICE_ATTR(available_threshold_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_THRESHOLD_MODE(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(threshold_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_THRESHOLD(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_threshold, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_THRESHOLD(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_threshold, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_SENSITIVITY(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_sensitivity, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SENSITIVITY(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_sensitivity, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_TIMEOUT(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_timeout, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_TIMEOUT(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_timeout, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_VALUE(_show) \
+ IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH2_VALUE(_show) \
+ IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_POWERDOWN_TIMER(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(powerdown_timer, _mode, _show, _store, 0)
+
+static ssize_t ad7150_show_conversion_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ int len = 0;
+
+ for (i = 0; i < AD7150_MAX_CONV_MODE; i++)
+ len += sprintf(buf + len, "%s\n", ad7150_conv_mode_table[i].name);
+
+ return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7150_show_conversion_modes);
+
+static ssize_t ad7150_show_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad7150_store_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ u8 cfg;
+ int i;
+
+ ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1);
+
+ for (i = 0; i < AD7150_MAX_CONV_MODE; i++) {
+ if (strncmp(buf, ad7150_conv_mode_table[i].name,
+ strlen(ad7150_conv_mode_table[i].name) - 1) == 0) {
+ chip->conversion_mode = ad7150_conv_mode_table[i].name;
+ cfg |= 0x18 | ad7150_conv_mode_table[i].reg_cfg;
+ ad7150_i2c_write(chip, AD7150_CFG, cfg);
+ return len;
+ }
+ }
+
+ dev_err(dev, "not supported conversion mode\n");
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+ ad7150_show_conversion_mode,
+ ad7150_store_conversion_mode);
+
+static ssize_t ad7150_show_threshold_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "adaptive\nfixed\n");
+}
+
+static IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(ad7150_show_threshold_modes);
+
+static ssize_t ad7150_show_ch1_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ u8 data[2];
+
+ ad7150_i2c_read(chip, AD7150_CH1_DATA_HIGH, data, 2);
+ return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH1_VALUE(ad7150_show_ch1_value);
+
+static ssize_t ad7150_show_ch2_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ u8 data[2];
+
+ ad7150_i2c_read(chip, AD7150_CH2_DATA_HIGH, data, 2);
+ return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH2_VALUE(ad7150_show_ch2_value);
+
+static ssize_t ad7150_show_threshold_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%s\n", chip->threshold_mode);
+}
+
+static ssize_t ad7150_store_threshold_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ u8 cfg;
+
+ ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1);
+
+ if (strncmp(buf, "fixed", 5) == 0) {
+ strcpy(chip->threshold_mode, "fixed");
+ cfg |= AD7150_CFG_FIX;
+ ad7150_i2c_write(chip, AD7150_CFG, cfg);
+
+ return len;
+ } else if (strncmp(buf, "adaptive", 8) == 0) {
+ strcpy(chip->threshold_mode, "adaptive");
+ cfg &= ~AD7150_CFG_FIX;
+ ad7150_i2c_write(chip, AD7150_CFG, cfg);
+
+ return len;
+ }
+
+ dev_err(dev, "not supported threshold mode\n");
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_THRESHOLD_MODE(S_IRUGO | S_IWUSR,
+ ad7150_show_threshold_mode,
+ ad7150_store_threshold_mode);
+
+static ssize_t ad7150_show_ch1_threshold(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch1_threshold);
+}
+
+static ssize_t ad7150_store_ch1_threshold(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_H, data >> 8);
+ ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_L, data);
+ chip->ch1_threshold = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_THRESHOLD(S_IRUGO | S_IWUSR,
+ ad7150_show_ch1_threshold,
+ ad7150_store_ch1_threshold);
+
+static ssize_t ad7150_show_ch2_threshold(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch2_threshold);
+}
+
+static ssize_t ad7150_store_ch2_threshold(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_H, data >> 8);
+ ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_L, data);
+ chip->ch2_threshold = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_THRESHOLD(S_IRUGO | S_IWUSR,
+ ad7150_show_ch2_threshold,
+ ad7150_store_ch2_threshold);
+
+static ssize_t ad7150_show_ch1_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch1_sensitivity);
+}
+
+static ssize_t ad7150_store_ch1_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH1_SENSITIVITY, data);
+ chip->ch1_sensitivity = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SENSITIVITY(S_IRUGO | S_IWUSR,
+ ad7150_show_ch1_sensitivity,
+ ad7150_store_ch1_sensitivity);
+
+static ssize_t ad7150_show_ch2_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch2_sensitivity);
+}
+
+static ssize_t ad7150_store_ch2_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH2_SENSITIVITY, data);
+ chip->ch2_sensitivity = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SENSITIVITY(S_IRUGO | S_IWUSR,
+ ad7150_show_ch2_sensitivity,
+ ad7150_store_ch2_sensitivity);
+
+static ssize_t ad7150_show_ch1_timeout(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch1_timeout);
+}
+
+static ssize_t ad7150_store_ch1_timeout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH1_TIMEOUT, data);
+ chip->ch1_timeout = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_TIMEOUT(S_IRUGO | S_IWUSR,
+ ad7150_show_ch1_timeout,
+ ad7150_store_ch1_timeout);
+
+static ssize_t ad7150_show_ch2_timeout(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch2_timeout);
+}
+
+static ssize_t ad7150_store_ch2_timeout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH2_TIMEOUT, data);
+ chip->ch2_timeout = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_TIMEOUT(S_IRUGO | S_IWUSR,
+ ad7150_show_ch2_timeout,
+ ad7150_store_ch2_timeout);
+
+static ssize_t ad7150_show_ch1_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->ch1_setup);
+}
+
+static ssize_t ad7150_store_ch1_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH1_SETUP, data);
+ chip->ch1_setup = data;
+ return len;
+ }
+
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR,
+ ad7150_show_ch1_setup,
+ ad7150_store_ch1_setup);
+
+static ssize_t ad7150_show_ch2_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->ch2_setup);
+}
+
+static ssize_t ad7150_store_ch2_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7150_i2c_write(chip, AD7150_CH2_SETUP, data);
+ chip->ch2_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR,
+ ad7150_show_ch2_setup,
+ ad7150_store_ch2_setup);
+
+static ssize_t ad7150_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7150_show_name, NULL, 0);
+
+static ssize_t ad7150_show_powerdown_timer(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->powerdown_timer);
+}
+
+static ssize_t ad7150_store_powerdown_timer(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x40)) {
+ chip->powerdown_timer = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_POWERDOWN_TIMER(S_IRUGO | S_IWUSR,
+ ad7150_show_powerdown_timer,
+ ad7150_store_powerdown_timer);
+
+static struct attribute *ad7150_attributes[] = {
+ &iio_dev_attr_available_threshold_modes.dev_attr.attr,
+ &iio_dev_attr_threshold_mode.dev_attr.attr,
+ &iio_dev_attr_ch1_threshold.dev_attr.attr,
+ &iio_dev_attr_ch2_threshold.dev_attr.attr,
+ &iio_dev_attr_ch1_timeout.dev_attr.attr,
+ &iio_dev_attr_ch2_timeout.dev_attr.attr,
+ &iio_dev_attr_ch1_setup.dev_attr.attr,
+ &iio_dev_attr_ch2_setup.dev_attr.attr,
+ &iio_dev_attr_ch1_sensitivity.dev_attr.attr,
+ &iio_dev_attr_ch2_sensitivity.dev_attr.attr,
+ &iio_dev_attr_powerdown_timer.dev_attr.attr,
+ &iio_dev_attr_ch1_value.dev_attr.attr,
+ &iio_dev_attr_ch2_value.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7150_attribute_group = {
+ .attrs = ad7150_attributes,
+};
+
+/*
+ * threshold events
+ */
+
+#define IIO_EVENT_CODE_CH1_HIGH IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_CH1_LOW IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_CH2_HIGH IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_CH2_LOW IIO_BUFFER_EVENT_CODE(3)
+
+#define IIO_EVENT_ATTR_CH1_HIGH_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ch1_high, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH2_HIGH_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ch2_high, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH1_LOW_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ch1_low, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH2_LOW_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ch2_low, _evlist, _show, _store, _mask)
+
+static void ad7150_interrupt_handler_bh(struct work_struct *work_s)
+{
+ struct ad7150_chip_info *chip =
+ container_of(work_s, struct ad7150_chip_info, thresh_work);
+ u8 int_status;
+
+ enable_irq(chip->client->irq);
+
+ ad7150_i2c_read(chip, AD7150_STATUS, &int_status, 1);
+
+ if ((int_status & AD7150_STATUS_OUT1) && !(chip->old_state & AD7150_STATUS_OUT1))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_CH1_HIGH,
+ chip->last_timestamp);
+ else if ((!(int_status & AD7150_STATUS_OUT1)) && (chip->old_state & AD7150_STATUS_OUT1))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_CH1_LOW,
+ chip->last_timestamp);
+
+ if ((int_status & AD7150_STATUS_OUT2) && !(chip->old_state & AD7150_STATUS_OUT2))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_CH2_HIGH,
+ chip->last_timestamp);
+ else if ((!(int_status & AD7150_STATUS_OUT2)) && (chip->old_state & AD7150_STATUS_OUT2))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_CH2_LOW,
+ chip->last_timestamp);
+}
+
+static int ad7150_interrupt_handler_th(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct ad7150_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(threshold, &ad7150_interrupt_handler_th);
+
+static ssize_t ad7150_query_out_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ /*
+ * AD7150 provides two logic output channels, which can be used as interrupt
+ * but the pins are not configurable
+ */
+ return sprintf(buf, "1\n");
+}
+
+static ssize_t ad7150_set_out_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return len;
+}
+
+IIO_EVENT_ATTR_CH1_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH2_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH1_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH2_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+
+static struct attribute *ad7150_event_attributes[] = {
+ &iio_event_attr_ch1_high.dev_attr.attr,
+ &iio_event_attr_ch2_high.dev_attr.attr,
+ &iio_event_attr_ch1_low.dev_attr.attr,
+ &iio_event_attr_ch2_low.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad7150_event_attribute_group = {
+ .attrs = ad7150_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7150_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0, regdone = 0;
+ struct ad7150_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ /* Echipabilish that the iio_dev is a child of the i2c device */
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &ad7150_attribute_group;
+ chip->indio_dev->event_attrs = &ad7150_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)(chip);
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+ regdone = 1;
+
+ if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "ad7150");
+ if (ret)
+ goto error_free_dev;
+
+ iio_add_event_to_list(iio_event_attr_ch2_low.listel,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, ad7150_interrupt_handler_bh);
+ }
+
+ dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq);
+
+ return 0;
+
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(chip->indio_dev);
+ else
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad7150_remove(struct i2c_client *client)
+{
+ struct ad7150_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id ad7150_id[] = {
+ { "ad7150", 0 },
+ { "ad7151", 0 },
+ { "ad7156", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7150_id);
+
+static struct i2c_driver ad7150_driver = {
+ .driver = {
+ .name = "ad7150",
+ },
+ .probe = ad7150_probe,
+ .remove = __devexit_p(ad7150_remove),
+ .id_table = ad7150_id,
+};
+
+static __init int ad7150_init(void)
+{
+ return i2c_add_driver(&ad7150_driver);
+}
+
+static __exit void ad7150_exit(void)
+{
+ i2c_del_driver(&ad7150_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7150/1/6 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7150_init);
+module_exit(ad7150_exit);
diff --git a/drivers/staging/iio/adc/ad7152.c b/drivers/staging/iio/adc/ad7152.c
new file mode 100644
index 000000000000..fa7f84062307
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7152.c
@@ -0,0 +1,610 @@
+/*
+ * AD7152 capacitive sensor driver supporting AD7152/3
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7152 registers definition
+ */
+
+#define AD7152_STATUS 0
+#define AD7152_STATUS_RDY1 (1 << 0)
+#define AD7152_STATUS_RDY2 (1 << 1)
+#define AD7152_CH1_DATA_HIGH 1
+#define AD7152_CH1_DATA_LOW 2
+#define AD7152_CH2_DATA_HIGH 3
+#define AD7152_CH2_DATA_LOW 4
+#define AD7152_CH1_OFFS_HIGH 5
+#define AD7152_CH1_OFFS_LOW 6
+#define AD7152_CH2_OFFS_HIGH 7
+#define AD7152_CH2_OFFS_LOW 8
+#define AD7152_CH1_GAIN_HIGH 9
+#define AD7152_CH1_GAIN_LOW 10
+#define AD7152_CH1_SETUP 11
+#define AD7152_CH2_GAIN_HIGH 12
+#define AD7152_CH2_GAIN_LOW 13
+#define AD7152_CH2_SETUP 14
+#define AD7152_CFG 15
+#define AD7152_RESEVERD 16
+#define AD7152_CAPDAC_POS 17
+#define AD7152_CAPDAC_NEG 18
+#define AD7152_CFG2 26
+
+#define AD7152_MAX_CONV_MODE 6
+
+/*
+ * struct ad7152_chip_info - chip specifc information
+ */
+
+struct ad7152_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ u16 ch1_offset; /* Channel 1 offset calibration coefficient */
+ u16 ch1_gain; /* Channel 1 gain coefficient */
+ u8 ch1_setup;
+ u16 ch2_offset; /* Channel 2 offset calibration coefficient */
+ u16 ch2_gain; /* Channel 1 gain coefficient */
+ u8 ch2_setup;
+ u8 filter_rate_setup; /* Capacitive channel digital filter setup; conversion time/update rate setup per channel */
+ char *conversion_mode;
+};
+
+struct ad7152_conversion_mode {
+ char *name;
+ u8 reg_cfg;
+};
+
+struct ad7152_conversion_mode ad7152_conv_mode_table[AD7152_MAX_CONV_MODE] = {
+ { "idle", 0 },
+ { "continuous-conversion", 1 },
+ { "single-conversion", 2 },
+ { "power-down", 3 },
+ { "offset-calibration", 5 },
+ { "gain-calibration", 6 },
+};
+
+/*
+ * ad7152 register access by I2C
+ */
+
+static int ad7152_i2c_read(struct ad7152_chip_info *chip, u8 reg, u8 *data, int len)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_master_send(client, &reg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C write error\n");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, data, len);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ }
+
+ return ret;
+}
+
+static int ad7152_i2c_write(struct ad7152_chip_info *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ u8 tx[2] = {
+ reg,
+ data,
+ };
+
+ ret = i2c_master_send(client, tx, 2);
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \
+ IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_OFFSET(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_offset, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_OFFSET(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_offset, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_GAIN(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_GAIN(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_VALUE(_show) \
+ IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH2_VALUE(_show) \
+ IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_FILTER_RATE_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(filter_rate_setup, _mode, _show, _store, 0)
+
+static ssize_t ad7152_show_conversion_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ int len = 0;
+
+ for (i = 0; i < AD7152_MAX_CONV_MODE; i++)
+ len += sprintf(buf + len, "%s ", ad7152_conv_mode_table[i].name);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7152_show_conversion_modes);
+
+static ssize_t ad7152_show_ch1_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ u8 data[2];
+
+ ad7152_i2c_read(chip, AD7152_CH1_DATA_HIGH, data, 2);
+ return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH1_VALUE(ad7152_show_ch1_value);
+
+static ssize_t ad7152_show_ch2_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ u8 data[2];
+
+ ad7152_i2c_read(chip, AD7152_CH2_DATA_HIGH, data, 2);
+ return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH2_VALUE(ad7152_show_ch2_value);
+
+static ssize_t ad7152_show_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad7152_store_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ u8 cfg;
+ int i;
+
+ ad7152_i2c_read(chip, AD7152_CFG, &cfg, 1);
+
+ for (i = 0; i < AD7152_MAX_CONV_MODE; i++)
+ if (strncmp(buf, ad7152_conv_mode_table[i].name,
+ strlen(ad7152_conv_mode_table[i].name) - 1) == 0) {
+ chip->conversion_mode = ad7152_conv_mode_table[i].name;
+ cfg |= 0x18 | ad7152_conv_mode_table[i].reg_cfg;
+ ad7152_i2c_write(chip, AD7152_CFG, cfg);
+ return len;
+ }
+
+ dev_err(dev, "not supported conversion mode\n");
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+ ad7152_show_conversion_mode,
+ ad7152_store_conversion_mode);
+
+static ssize_t ad7152_show_ch1_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch1_offset);
+}
+
+static ssize_t ad7152_store_ch1_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7152_i2c_write(chip, AD7152_CH1_OFFS_HIGH, data >> 8);
+ ad7152_i2c_write(chip, AD7152_CH1_OFFS_LOW, data);
+ chip->ch1_offset = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_OFFSET(S_IRUGO | S_IWUSR,
+ ad7152_show_ch1_offset,
+ ad7152_store_ch1_offset);
+
+static ssize_t ad7152_show_ch2_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch2_offset);
+}
+
+static ssize_t ad7152_store_ch2_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7152_i2c_write(chip, AD7152_CH2_OFFS_HIGH, data >> 8);
+ ad7152_i2c_write(chip, AD7152_CH2_OFFS_LOW, data);
+ chip->ch2_offset = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_OFFSET(S_IRUGO | S_IWUSR,
+ ad7152_show_ch2_offset,
+ ad7152_store_ch2_offset);
+
+static ssize_t ad7152_show_ch1_gain(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch1_gain);
+}
+
+static ssize_t ad7152_store_ch1_gain(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7152_i2c_write(chip, AD7152_CH1_GAIN_HIGH, data >> 8);
+ ad7152_i2c_write(chip, AD7152_CH1_GAIN_LOW, data);
+ chip->ch1_gain = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_GAIN(S_IRUGO | S_IWUSR,
+ ad7152_show_ch1_gain,
+ ad7152_store_ch1_gain);
+
+static ssize_t ad7152_show_ch2_gain(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->ch2_gain);
+}
+
+static ssize_t ad7152_store_ch2_gain(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad7152_i2c_write(chip, AD7152_CH2_GAIN_HIGH, data >> 8);
+ ad7152_i2c_write(chip, AD7152_CH2_GAIN_LOW, data);
+ chip->ch2_gain = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_GAIN(S_IRUGO | S_IWUSR,
+ ad7152_show_ch2_gain,
+ ad7152_store_ch2_gain);
+
+static ssize_t ad7152_show_ch1_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->ch1_setup);
+}
+
+static ssize_t ad7152_store_ch1_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7152_i2c_write(chip, AD7152_CH1_SETUP, data);
+ chip->ch1_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR,
+ ad7152_show_ch1_setup,
+ ad7152_store_ch1_setup);
+
+static ssize_t ad7152_show_ch2_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->ch2_setup);
+}
+
+static ssize_t ad7152_store_ch2_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7152_i2c_write(chip, AD7152_CH2_SETUP, data);
+ chip->ch2_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR,
+ ad7152_show_ch2_setup,
+ ad7152_store_ch2_setup);
+
+static ssize_t ad7152_show_filter_rate_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->filter_rate_setup);
+}
+
+static ssize_t ad7152_store_filter_rate_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad7152_i2c_write(chip, AD7152_CFG2, data);
+ chip->filter_rate_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_FILTER_RATE_SETUP(S_IRUGO | S_IWUSR,
+ ad7152_show_filter_rate_setup,
+ ad7152_store_filter_rate_setup);
+
+static ssize_t ad7152_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7152_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7152_show_name, NULL, 0);
+
+static struct attribute *ad7152_attributes[] = {
+ &iio_dev_attr_available_conversion_modes.dev_attr.attr,
+ &iio_dev_attr_conversion_mode.dev_attr.attr,
+ &iio_dev_attr_ch1_gain.dev_attr.attr,
+ &iio_dev_attr_ch2_gain.dev_attr.attr,
+ &iio_dev_attr_ch1_offset.dev_attr.attr,
+ &iio_dev_attr_ch2_offset.dev_attr.attr,
+ &iio_dev_attr_ch1_value.dev_attr.attr,
+ &iio_dev_attr_ch2_value.dev_attr.attr,
+ &iio_dev_attr_ch1_setup.dev_attr.attr,
+ &iio_dev_attr_ch2_setup.dev_attr.attr,
+ &iio_dev_attr_filter_rate_setup.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7152_attribute_group = {
+ .attrs = ad7152_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7152_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct ad7152_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ /* Echipabilish that the iio_dev is a child of the i2c device */
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &ad7152_attribute_group;
+ chip->indio_dev->dev_data = (void *)(chip);
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ dev_err(&client->dev, "%s capacitive sensor registered\n", id->name);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad7152_remove(struct i2c_client *client)
+{
+ struct ad7152_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id ad7152_id[] = {
+ { "ad7152", 0 },
+ { "ad7153", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7152_id);
+
+static struct i2c_driver ad7152_driver = {
+ .driver = {
+ .name = "ad7152",
+ },
+ .probe = ad7152_probe,
+ .remove = __devexit_p(ad7152_remove),
+ .id_table = ad7152_id,
+};
+
+static __init int ad7152_init(void)
+{
+ return i2c_add_driver(&ad7152_driver);
+}
+
+static __exit void ad7152_exit(void)
+{
+ i2c_del_driver(&ad7152_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7152/3 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7152_init);
+module_exit(ad7152_exit);
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
new file mode 100644
index 000000000000..34041a72aa52
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -0,0 +1,1039 @@
+/*
+ * AD7291 digital temperature sensor driver supporting AD7291
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7291 registers definition
+ */
+#define AD7291_COMMAND 0
+#define AD7291_VOLTAGE 1
+#define AD7291_T_SENSE 2
+#define AD7291_T_AVERAGE 3
+#define AD7291_VOLTAGE_LIMIT_BASE 4
+#define AD7291_VOLTAGE_LIMIT_COUNT 8
+#define AD7291_T_SENSE_HIGH 0x1c
+#define AD7291_T_SENSE_LOW 0x1d
+#define AD7291_T_SENSE_HYST 0x1e
+#define AD7291_VOLTAGE_ALERT_STATUS 0x1f
+#define AD7291_T_ALERT_STATUS 0x20
+
+/*
+ * AD7291 command
+ */
+#define AD7291_AUTOCYCLE 0x1
+#define AD7291_RESET 0x2
+#define AD7291_ALART_CLEAR 0x4
+#define AD7291_ALART_POLARITY 0x8
+#define AD7291_EXT_REF 0x10
+#define AD7291_NOISE_DELAY 0x20
+#define AD7291_T_SENSE_MASK 0x40
+#define AD7291_VOLTAGE_MASK 0xff00
+#define AD7291_VOLTAGE_OFFSET 0x8
+
+/*
+ * AD7291 value masks
+ */
+#define AD7291_CHANNEL_MASK 0xf000
+#define AD7291_VALUE_MASK 0xfff
+#define AD7291_T_VALUE_SIGN 0x400
+#define AD7291_T_VALUE_FLOAT_OFFSET 2
+#define AD7291_T_VALUE_FLOAT_MASK 0x2
+
+/*
+ * struct ad7291_chip_info - chip specifc information
+ */
+
+struct ad7291_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ u16 command;
+ u8 channels; /* Active voltage channels */
+};
+
+/*
+ * struct ad7291_chip_info - chip specifc information
+ */
+
+struct ad7291_limit_regs {
+ u16 data_high;
+ u16 data_low;
+ u16 hysteresis;
+};
+
+/*
+ * ad7291 register access by I2C
+ */
+static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ *data = swab16((u16)ret);
+
+ return 0;
+}
+
+static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_word_data(client, reg, swab16(data));
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+/* Returns negative errno, or else the number of words read. */
+static int ad7291_i2c_read_data(struct ad7291_chip_info *chip, u8 reg, u16 *data)
+{
+ struct i2c_client *client = chip->client;
+ u8 commands[4];
+ int ret = 0;
+ int i, count;
+
+ if (reg == AD7291_T_SENSE || reg == AD7291_T_AVERAGE)
+ count = 2;
+ else if (reg == AD7291_VOLTAGE) {
+ if (!chip->channels) {
+ dev_err(&client->dev, "No voltage channel is selected.\n");
+ return -EINVAL;
+ }
+ count = 2 + chip->channels * 2;
+ } else {
+ dev_err(&client->dev, "I2C wrong data register\n");
+ return -EINVAL;
+ }
+
+ commands[0] = 0;
+ commands[1] = (chip->command >> 8) & 0xff;
+ commands[2] = chip->command & 0xff;
+ commands[3] = reg;
+
+ ret = i2c_master_send(client, commands, 4);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C master send error\n");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, (u8 *)data, count);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C master receive error\n");
+ return ret;
+ }
+ ret >>= 2;
+
+ for (i = 0; i < ret; i++)
+ data[i] = swab16(data[i]);
+
+ return ret;
+}
+
+static ssize_t ad7291_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+
+ if (chip->command & AD7291_AUTOCYCLE)
+ return sprintf(buf, "autocycle\n");
+ else
+ return sprintf(buf, "command\n");
+}
+
+static ssize_t ad7291_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command & (~AD7291_AUTOCYCLE);
+ if (strcmp(buf, "autocycle"))
+ command |= AD7291_AUTOCYCLE;
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+ if (ret)
+ return -EIO;
+
+ chip->command = command;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ ad7291_show_mode,
+ ad7291_store_mode,
+ 0);
+
+static ssize_t ad7291_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "command\nautocycle\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7291_show_available_modes, NULL, 0);
+
+static ssize_t ad7291_store_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command | AD7291_RESET;
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+ NULL,
+ ad7291_store_reset,
+ 0);
+
+static ssize_t ad7291_show_ext_ref(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->command & AD7291_EXT_REF));
+}
+
+static ssize_t ad7291_store_ext_ref(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command & (~AD7291_EXT_REF);
+ if (strcmp(buf, "1"))
+ command |= AD7291_EXT_REF;
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+ if (ret)
+ return -EIO;
+
+ chip->command = command;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
+ ad7291_show_ext_ref,
+ ad7291_store_ext_ref,
+ 0);
+
+static ssize_t ad7291_show_noise_delay(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->command & AD7291_NOISE_DELAY));
+}
+
+static ssize_t ad7291_store_noise_delay(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command & (~AD7291_NOISE_DELAY);
+ if (strcmp(buf, "1"))
+ command |= AD7291_NOISE_DELAY;
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+ if (ret)
+ return -EIO;
+
+ chip->command = command;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(noise_delay, S_IRUGO | S_IWUSR,
+ ad7291_show_noise_delay,
+ ad7291_store_noise_delay,
+ 0);
+
+static ssize_t ad7291_show_t_sense(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ ret = ad7291_i2c_read_data(chip, AD7291_T_SENSE, &data);
+ if (ret)
+ return -EIO;
+
+ if (data & AD7291_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (AD7291_T_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ (data >> AD7291_T_VALUE_FLOAT_OFFSET),
+ (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7291_show_t_sense, NULL, 0);
+
+static ssize_t ad7291_show_t_average(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ ret = ad7291_i2c_read_data(chip, AD7291_T_AVERAGE, &data);
+ if (ret)
+ return -EIO;
+
+ if (data & AD7291_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (AD7291_T_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ (data >> AD7291_T_VALUE_FLOAT_OFFSET),
+ (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7291_show_t_average, NULL, 0);
+
+static ssize_t ad7291_show_voltage(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 data[AD7291_VOLTAGE_LIMIT_COUNT];
+ int i, size, ret;
+
+ ret = ad7291_i2c_read_data(chip, AD7291_VOLTAGE, data);
+ if (ret)
+ return -EIO;
+
+ for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
+ if (chip->command & (AD7291_T_SENSE_MASK << i)) {
+ ret = sprintf(buf, "channel[%d]=%d\n", i,
+ data[i] & AD7291_VALUE_MASK);
+ if (ret < 0)
+ break;
+ buf += ret;
+ size += ret;
+ }
+ }
+
+ return size;
+}
+
+static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7291_show_voltage, NULL, 0);
+
+static ssize_t ad7291_show_channel_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%x\n", (chip->command & AD7291_VOLTAGE_MASK) >>
+ AD7291_VOLTAGE_OFFSET);
+}
+
+static ssize_t ad7291_store_channel_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ unsigned long data;
+ int i, ret;
+
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data > 0xff)
+ return -EINVAL;
+
+ command = chip->command & (~AD7291_VOLTAGE_MASK);
+ command |= data << AD7291_VOLTAGE_OFFSET;
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+ if (ret)
+ return -EIO;
+
+ chip->command = command;
+
+ for (i = 0, chip->channels = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
+ if (chip->command & (AD7291_T_SENSE_MASK << i))
+ chip->channels++;
+ }
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
+ ad7291_show_channel_mask,
+ ad7291_store_channel_mask,
+ 0);
+
+static ssize_t ad7291_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7291_show_name, NULL, 0);
+
+static struct attribute *ad7291_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_dev_attr_ext_ref.dev_attr.attr,
+ &iio_dev_attr_noise_delay.dev_attr.attr,
+ &iio_dev_attr_t_sense.dev_attr.attr,
+ &iio_dev_attr_t_average.dev_attr.attr,
+ &iio_dev_attr_voltage.dev_attr.attr,
+ &iio_dev_attr_channel_mask.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7291_attribute_group = {
+ .attrs = ad7291_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_AD7291_T_SENSE_HIGH IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_AD7291_T_SENSE_LOW IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_AD7291_T_AVG_HIGH IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_AD7291_T_AVG_LOW IIO_BUFFER_EVENT_CODE(3)
+#define IIO_EVENT_CODE_AD7291_VOLTAGE_BASE IIO_BUFFER_EVENT_CODE(4)
+
+static void ad7291_interrupt_bh(struct work_struct *work_s)
+{
+ struct ad7291_chip_info *chip =
+ container_of(work_s, struct ad7291_chip_info, thresh_work);
+ u16 t_status, v_status;
+ u16 command;
+ int i;
+
+ if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
+ return;
+
+ if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status))
+ return;
+
+ if (!(t_status || v_status))
+ return;
+
+ command = chip->command | AD7291_ALART_CLEAR;
+ ad7291_i2c_write(chip, AD7291_COMMAND, command);
+
+ command = chip->command & ~AD7291_ALART_CLEAR;
+ ad7291_i2c_write(chip, AD7291_COMMAND, command);
+
+ enable_irq(chip->client->irq);
+
+ for (i = 0; i < 4; i++) {
+ if (t_status & (1 << i))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_AD7291_T_SENSE_HIGH + i,
+ chip->last_timestamp);
+ }
+
+ for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT*2; i++) {
+ if (v_status & (1 << i))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_AD7291_VOLTAGE_BASE + i,
+ chip->last_timestamp);
+ }
+}
+
+static int ad7291_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(ad7291, &ad7291_interrupt);
+
+static inline ssize_t ad7291_show_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ ret = ad7291_i2c_read(chip, bound_reg, &data);
+ if (ret)
+ return -EIO;
+
+ data &= AD7291_VALUE_MASK;
+ if (data & AD7291_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (AD7291_T_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ data >> AD7291_T_VALUE_FLOAT_OFFSET,
+ (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static inline ssize_t ad7291_set_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ long tmp1, tmp2;
+ u16 data;
+ char *pos;
+ int ret;
+
+ pos = strchr(buf, '.');
+
+ ret = strict_strtol(buf, 10, &tmp1);
+
+ if (ret || tmp1 > 127 || tmp1 < -128)
+ return -EINVAL;
+
+ if (pos) {
+ len = strlen(pos);
+ if (len > AD7291_T_VALUE_FLOAT_OFFSET)
+ len = AD7291_T_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 25) * 25;
+ }
+
+ if (tmp1 < 0)
+ data = (u16)(-tmp1);
+ else
+ data = (u16)tmp1;
+ data = (data << AD7291_T_VALUE_FLOAT_OFFSET) |
+ (tmp2 & AD7291_T_VALUE_FLOAT_MASK);
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (AD7291_T_VALUE_SIGN << 1) - data;
+
+ ret = ad7291_i2c_write(chip, bound_reg, data);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+static ssize_t ad7291_show_t_sense_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return ad7291_show_t_bound(dev, attr,
+ AD7291_T_SENSE_HIGH, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return ad7291_set_t_bound(dev, attr,
+ AD7291_T_SENSE_HIGH, buf, len);
+}
+
+static ssize_t ad7291_show_t_sense_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return ad7291_show_t_bound(dev, attr,
+ AD7291_T_SENSE_LOW, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return ad7291_set_t_bound(dev, attr,
+ AD7291_T_SENSE_LOW, buf, len);
+}
+
+static ssize_t ad7291_show_t_sense_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return ad7291_show_t_bound(dev, attr,
+ AD7291_T_SENSE_HYST, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return ad7291_set_t_bound(dev, attr,
+ AD7291_T_SENSE_HYST, buf, len);
+}
+
+static inline ssize_t ad7291_show_v_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ int ret;
+
+ if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE ||
+ bound_reg >= AD7291_VOLTAGE_LIMIT_BASE +
+ AD7291_VOLTAGE_LIMIT_COUNT)
+ return -EINVAL;
+
+ ret = ad7291_i2c_read(chip, bound_reg, &data);
+ if (ret)
+ return -EIO;
+
+ data &= AD7291_VALUE_MASK;
+
+ return sprintf(buf, "%d\n", data);
+}
+
+static inline ssize_t ad7291_set_v_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7291_chip_info *chip = dev_info->dev_data;
+ unsigned long value;
+ u16 data;
+ int ret;
+
+ if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE ||
+ bound_reg >= AD7291_VOLTAGE_LIMIT_BASE +
+ AD7291_VOLTAGE_LIMIT_COUNT)
+ return -EINVAL;
+
+ ret = strict_strtoul(buf, 10, &value);
+
+ if (ret || value >= 4096)
+ return -EINVAL;
+
+ data = (u16)value;
+ ret = ad7291_i2c_write(chip, bound_reg, data);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+static int ad7291_get_voltage_limit_regs(const char *channel)
+{
+ int index;
+
+ if (strlen(channel) < 3 && channel[0] != 'v')
+ return -EINVAL;
+
+ index = channel[1] - '0';
+ if (index >= AD7291_VOLTAGE_LIMIT_COUNT)
+ return -EINVAL;
+
+ return index;
+}
+
+static ssize_t ad7291_show_voltage_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_show_t_bound(dev, attr, regs, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_set_t_bound(dev, attr, regs, buf, len);
+}
+
+static ssize_t ad7291_show_voltage_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_show_t_bound(dev, attr, regs+1, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_set_t_bound(dev, attr, regs+1, buf, len);
+}
+
+static ssize_t ad7291_show_voltage_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_show_t_bound(dev, attr, regs+2, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int regs;
+
+ regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+ if (regs < 0)
+ return regs;
+
+ return ad7291_set_t_bound(dev, attr, regs+2, buf, len);
+}
+
+IIO_EVENT_ATTR_SH(t_sense_high, iio_event_ad7291,
+ ad7291_show_t_sense_high, ad7291_set_t_sense_high, 0);
+IIO_EVENT_ATTR_SH(t_sense_low, iio_event_ad7291,
+ ad7291_show_t_sense_low, ad7291_set_t_sense_low, 0);
+IIO_EVENT_ATTR_SH(t_sense_hyst, iio_event_ad7291,
+ ad7291_show_t_sense_hyst, ad7291_set_t_sense_hyst, 0);
+
+IIO_EVENT_ATTR_SH(v0_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v0_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v0_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v1_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v1_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v1_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v2_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v2_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v2_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v3_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v3_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v3_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v4_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v4_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v4_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v5_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v5_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v5_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v6_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v6_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v6_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v7_high, iio_event_ad7291,
+ ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v7_low, iio_event_ad7291,
+ ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v7_hyst, iio_event_ad7291,
+ ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+
+static struct attribute *ad7291_event_attributes[] = {
+ &iio_event_attr_t_sense_high.dev_attr.attr,
+ &iio_event_attr_t_sense_low.dev_attr.attr,
+ &iio_event_attr_t_sense_hyst.dev_attr.attr,
+ &iio_event_attr_v0_high.dev_attr.attr,
+ &iio_event_attr_v0_low.dev_attr.attr,
+ &iio_event_attr_v0_hyst.dev_attr.attr,
+ &iio_event_attr_v1_high.dev_attr.attr,
+ &iio_event_attr_v1_low.dev_attr.attr,
+ &iio_event_attr_v1_hyst.dev_attr.attr,
+ &iio_event_attr_v2_high.dev_attr.attr,
+ &iio_event_attr_v2_low.dev_attr.attr,
+ &iio_event_attr_v2_hyst.dev_attr.attr,
+ &iio_event_attr_v3_high.dev_attr.attr,
+ &iio_event_attr_v3_low.dev_attr.attr,
+ &iio_event_attr_v3_hyst.dev_attr.attr,
+ &iio_event_attr_v4_high.dev_attr.attr,
+ &iio_event_attr_v4_low.dev_attr.attr,
+ &iio_event_attr_v4_hyst.dev_attr.attr,
+ &iio_event_attr_v5_high.dev_attr.attr,
+ &iio_event_attr_v5_low.dev_attr.attr,
+ &iio_event_attr_v5_hyst.dev_attr.attr,
+ &iio_event_attr_v6_high.dev_attr.attr,
+ &iio_event_attr_v6_low.dev_attr.attr,
+ &iio_event_attr_v6_hyst.dev_attr.attr,
+ &iio_event_attr_v7_high.dev_attr.attr,
+ &iio_event_attr_v7_low.dev_attr.attr,
+ &iio_event_attr_v7_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad7291_event_attribute_group = {
+ .attrs = ad7291_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7291_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ad7291_chip_info *chip;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(struct ad7291_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+ chip->command = AD7291_NOISE_DELAY | AD7291_T_SENSE_MASK;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &ad7291_attribute_group;
+ chip->indio_dev->event_attrs = &ad7291_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ if (client->irq > 0) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_LOW,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_ad7291.
+ * All event attributes bind to the same event handler.
+ * So, only register event handler once.
+ */
+ iio_add_event_to_list(&iio_event_ad7291,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, ad7291_interrupt_bh);
+
+ /* set irq polarity low level */
+ chip->command |= AD7291_ALART_POLARITY;
+ }
+
+ ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_irq;
+ }
+
+ dev_info(&client->dev, "%s temperature sensor registered.\n",
+ id->name);
+
+ return 0;
+
+error_unreg_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit ad7291_remove(struct i2c_client *client)
+{
+ struct ad7291_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ if (client->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id ad7291_id[] = {
+ { "ad7291", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7291_id);
+
+static struct i2c_driver ad7291_driver = {
+ .driver = {
+ .name = "ad7291",
+ },
+ .probe = ad7291_probe,
+ .remove = __devexit_p(ad7291_remove),
+ .id_table = ad7291_id,
+};
+
+static __init int ad7291_init(void)
+{
+ return i2c_add_driver(&ad7291_driver);
+}
+
+static __exit void ad7291_exit(void)
+{
+ i2c_del_driver(&ad7291_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7291 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7291_init);
+module_exit(ad7291_exit);
diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c
new file mode 100644
index 000000000000..1a080c977637
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298.c
@@ -0,0 +1,501 @@
+/*
+ * AD7298 digital temperature sensor driver supporting AD7298
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7298 command
+ */
+#define AD7298_PD 0x1
+#define AD7298_T_AVG_MASK 0x2
+#define AD7298_EXT_REF 0x4
+#define AD7298_T_SENSE_MASK 0x20
+#define AD7298_VOLTAGE_MASK 0x3fc0
+#define AD7298_VOLTAGE_OFFSET 0x6
+#define AD7298_VOLTAGE_LIMIT_COUNT 8
+#define AD7298_REPEAT 0x40
+#define AD7298_WRITE 0x80
+
+/*
+ * AD7298 value masks
+ */
+#define AD7298_CHANNEL_MASK 0xf000
+#define AD7298_VALUE_MASK 0xfff
+#define AD7298_T_VALUE_SIGN 0x400
+#define AD7298_T_VALUE_FLOAT_OFFSET 2
+#define AD7298_T_VALUE_FLOAT_MASK 0x2
+
+/*
+ * struct ad7298_chip_info - chip specifc information
+ */
+
+struct ad7298_chip_info {
+ const char *name;
+ struct spi_device *spi_dev;
+ struct iio_dev *indio_dev;
+ u16 command;
+ u16 busy_pin;
+ u8 channels; /* Active voltage channels */
+};
+
+/*
+ * ad7298 register access by SPI
+ */
+static int ad7298_spi_write(struct ad7298_chip_info *chip, u16 data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+
+ data |= AD7298_WRITE;
+ data = cpu_to_be16(data);
+ ret = spi_write(spi_dev, (u8 *)&data, sizeof(data));
+ if (ret < 0)
+ dev_err(&spi_dev->dev, "SPI write error\n");
+
+ return ret;
+}
+
+static int ad7298_spi_read(struct ad7298_chip_info *chip, u16 mask, u16 *data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+ u8 count = chip->channels;
+ u16 command;
+ int i;
+
+ if (mask & AD7298_T_SENSE_MASK) {
+ command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_VOLTAGE_MASK);
+ command |= AD7298_T_SENSE_MASK;
+ count = 1;
+ } else if (mask & AD7298_T_AVG_MASK) {
+ command = chip->command & ~AD7298_VOLTAGE_MASK;
+ command |= AD7298_T_SENSE_MASK | AD7298_T_AVG_MASK;
+ count = 2;
+ } else if (mask & AD7298_VOLTAGE_MASK) {
+ command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_T_SENSE_MASK);
+ count = chip->channels;
+ }
+
+ ret = ad7298_spi_write(chip, chip->command);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write command error\n");
+ return ret;
+ }
+
+ ret = spi_read(spi_dev, (u8 *)&command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read error\n");
+ return ret;
+ }
+
+ i = 10000;
+ while (i && gpio_get_value(chip->busy_pin)) {
+ cpu_relax();
+ i--;
+ }
+ if (!i) {
+ dev_err(&spi_dev->dev, "Always in busy convertion.\n");
+ return -EBUSY;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = spi_read(spi_dev, (u8 *)&data[i], sizeof(data[i]));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read error\n");
+ return ret;
+ }
+ *data = be16_to_cpu(data[i]);
+ }
+
+ return 0;
+}
+
+static ssize_t ad7298_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+
+ if (chip->command & AD7298_REPEAT)
+ return sprintf(buf, "repeat\n");
+ else
+ return sprintf(buf, "normal\n");
+}
+
+static ssize_t ad7298_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+
+ if (strcmp(buf, "repeat"))
+ chip->command |= AD7298_REPEAT;
+ else
+ chip->command &= (~AD7298_REPEAT);
+
+ return 1;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ ad7298_show_mode,
+ ad7298_store_mode,
+ 0);
+
+static ssize_t ad7298_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "normal\nrepeat\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7298_show_available_modes, NULL, 0);
+
+static ssize_t ad7298_store_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command & ~AD7298_PD;
+
+ ret = ad7298_spi_write(chip, command);
+ if (ret)
+ return -EIO;
+
+ command = chip->command | AD7298_PD;
+
+ ret = ad7298_spi_write(chip, command);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+ NULL,
+ ad7298_store_reset,
+ 0);
+
+static ssize_t ad7298_show_ext_ref(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->command & AD7298_EXT_REF));
+}
+
+static ssize_t ad7298_store_ext_ref(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ u16 command;
+ int ret;
+
+ command = chip->command & (~AD7298_EXT_REF);
+ if (strcmp(buf, "1"))
+ command |= AD7298_EXT_REF;
+
+ ret = ad7298_spi_write(chip, command);
+ if (ret)
+ return -EIO;
+
+ chip->command = command;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
+ ad7298_show_ext_ref,
+ ad7298_store_ext_ref,
+ 0);
+
+static ssize_t ad7298_show_t_sense(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ ret = ad7298_spi_read(chip, AD7298_T_SENSE_MASK, &data);
+ if (ret)
+ return -EIO;
+
+ if (data & AD7298_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (AD7298_T_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ (data >> AD7298_T_VALUE_FLOAT_OFFSET),
+ (data & AD7298_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7298_show_t_sense, NULL, 0);
+
+static ssize_t ad7298_show_t_average(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ u16 data[2];
+ char sign = ' ';
+ int ret;
+
+ ret = ad7298_spi_read(chip, AD7298_T_AVG_MASK, data);
+ if (ret)
+ return -EIO;
+
+ if (data[1] & AD7298_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data[1] = (AD7298_T_VALUE_SIGN << 1) - data[1];
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ (data[1] >> AD7298_T_VALUE_FLOAT_OFFSET),
+ (data[1] & AD7298_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7298_show_t_average, NULL, 0);
+
+static ssize_t ad7298_show_voltage(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ u16 data[AD7298_VOLTAGE_LIMIT_COUNT];
+ int i, size, ret;
+
+ ret = ad7298_spi_read(chip, AD7298_VOLTAGE_MASK, data);
+ if (ret)
+ return -EIO;
+
+ for (i = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
+ if (chip->command & (AD7298_T_SENSE_MASK << i)) {
+ ret = sprintf(buf, "channel[%d]=%d\n", i,
+ data[i] & AD7298_VALUE_MASK);
+ if (ret < 0)
+ break;
+ buf += ret;
+ size += ret;
+ }
+ }
+
+ return size;
+}
+
+static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7298_show_voltage, NULL, 0);
+
+static ssize_t ad7298_show_channel_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%x\n", (chip->command & AD7298_VOLTAGE_MASK) >>
+ AD7298_VOLTAGE_OFFSET);
+}
+
+static ssize_t ad7298_store_channel_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int i, ret;
+
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data > 0xff)
+ return -EINVAL;
+
+ chip->command &= (~AD7298_VOLTAGE_MASK);
+ chip->command |= data << AD7298_VOLTAGE_OFFSET;
+
+ for (i = 0, chip->channels = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
+ if (chip->command & (AD7298_T_SENSE_MASK << i))
+ chip->channels++;
+ }
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
+ ad7298_show_channel_mask,
+ ad7298_store_channel_mask,
+ 0);
+
+static ssize_t ad7298_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
+
+static struct attribute *ad7298_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_dev_attr_ext_ref.dev_attr.attr,
+ &iio_dev_attr_t_sense.dev_attr.attr,
+ &iio_dev_attr_t_average.dev_attr.attr,
+ &iio_dev_attr_voltage.dev_attr.attr,
+ &iio_dev_attr_channel_mask.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7298_attribute_group = {
+ .attrs = ad7298_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+static int __devinit ad7298_probe(struct spi_device *spi_dev)
+{
+ struct ad7298_chip_info *chip;
+ unsigned short *pins = spi_dev->dev.platform_data;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(struct ad7298_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ dev_set_drvdata(&spi_dev->dev, chip);
+
+ chip->spi_dev = spi_dev;
+ chip->name = spi_dev->modalias;
+ chip->busy_pin = pins[0];
+
+ ret = gpio_request(chip->busy_pin, chip->name);
+ if (ret) {
+ dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
+ chip->busy_pin);
+ goto error_free_chip;
+ }
+ gpio_direction_input(chip->busy_pin);
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_gpio;
+ }
+
+ chip->indio_dev->dev.parent = &spi_dev->dev;
+ chip->indio_dev->attrs = &ad7298_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
+ chip->name);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_gpio:
+ gpio_free(chip->busy_pin);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit ad7298_remove(struct spi_device *spi_dev)
+{
+ struct ad7298_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ dev_set_drvdata(&spi_dev->dev, NULL);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ gpio_free(chip->busy_pin);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7298_id[] = {
+ { "ad7298", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, ad7298_id);
+
+static struct spi_driver ad7298_driver = {
+ .driver = {
+ .name = "ad7298",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7298_probe,
+ .remove = __devexit_p(ad7298_remove),
+ .id_table = ad7298_id,
+};
+
+static __init int ad7298_init(void)
+{
+ return spi_register_driver(&ad7298_driver);
+}
+
+static __exit void ad7298_exit(void)
+{
+ spi_unregister_driver(&ad7298_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7298 digital"
+ " temperature sensor and ADC driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7298_init);
+module_exit(ad7298_exit);
diff --git a/drivers/staging/iio/adc/ad7314.c b/drivers/staging/iio/adc/ad7314.c
new file mode 100644
index 000000000000..8c17b1fe9026
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7314.c
@@ -0,0 +1,308 @@
+/*
+ * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7314 power mode
+ */
+#define AD7314_PD 0x2000
+
+/*
+ * AD7314 temperature masks
+ */
+#define AD7314_TEMP_SIGN 0x200
+#define AD7314_TEMP_MASK 0x7FE0
+#define AD7314_TEMP_OFFSET 5
+#define AD7314_TEMP_FLOAT_OFFSET 2
+#define AD7314_TEMP_FLOAT_MASK 0x3
+
+/*
+ * ADT7301 and ADT7302 temperature masks
+ */
+#define ADT7301_TEMP_SIGN 0x2000
+#define ADT7301_TEMP_MASK 0x2FFF
+#define ADT7301_TEMP_FLOAT_OFFSET 5
+#define ADT7301_TEMP_FLOAT_MASK 0x1F
+
+/*
+ * struct ad7314_chip_info - chip specifc information
+ */
+
+struct ad7314_chip_info {
+ const char *name;
+ struct spi_device *spi_dev;
+ struct iio_dev *indio_dev;
+ s64 last_timestamp;
+ u8 mode;
+};
+
+/*
+ * ad7314 register access by SPI
+ */
+
+static int ad7314_spi_read(struct ad7314_chip_info *chip, u16 *data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+ u16 value;
+
+ ret = spi_read(spi_dev, (u8 *)&value, sizeof(value));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read error\n");
+ return ret;
+ }
+
+ *data = be16_to_cpu((u16)value);
+
+ return ret;
+}
+
+static int ad7314_spi_write(struct ad7314_chip_info *chip, u16 data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+ u16 value = cpu_to_be16(data);
+
+ ret = spi_write(spi_dev, (u8 *)&value, sizeof(value));
+ if (ret < 0)
+ dev_err(&spi_dev->dev, "SPI write error\n");
+
+ return ret;
+}
+
+static ssize_t ad7314_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7314_chip_info *chip = dev_info->dev_data;
+
+ if (chip->mode)
+ return sprintf(buf, "power-save\n");
+ else
+ return sprintf(buf, "full\n");
+}
+
+static ssize_t ad7314_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7314_chip_info *chip = dev_info->dev_data;
+ u16 mode = 0;
+ int ret;
+
+ if (!strcmp(buf, "full"))
+ mode = AD7314_PD;
+
+ ret = ad7314_spi_write(chip, mode);
+ if (ret)
+ return -EIO;
+
+ chip->mode = mode;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ ad7314_show_mode,
+ ad7314_store_mode,
+ 0);
+
+static ssize_t ad7314_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "full\npower-save\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7314_show_available_modes, NULL, 0);
+
+static ssize_t ad7314_show_temperature(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7314_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ if (chip->mode) {
+ ret = ad7314_spi_write(chip, 0);
+ if (ret)
+ return -EIO;
+ }
+
+ ret = ad7314_spi_read(chip, &data);
+ if (ret)
+ return -EIO;
+
+ if (chip->mode)
+ ad7314_spi_write(chip, chip->mode);
+
+ if (strcmp(chip->name, "ad7314")) {
+ data = (data & AD7314_TEMP_MASK) >>
+ AD7314_TEMP_OFFSET;
+ if (data & AD7314_TEMP_SIGN) {
+ data = (AD7314_TEMP_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ data >> AD7314_TEMP_FLOAT_OFFSET,
+ (data & AD7314_TEMP_FLOAT_MASK) * 25);
+ } else {
+ data &= ADT7301_TEMP_MASK;
+ if (data & ADT7301_TEMP_SIGN) {
+ data = (ADT7301_TEMP_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.5d\n", sign,
+ data >> ADT7301_TEMP_FLOAT_OFFSET,
+ (data & ADT7301_TEMP_FLOAT_MASK) * 3125);
+ }
+}
+
+static IIO_DEVICE_ATTR(temperature, S_IRUGO, ad7314_show_temperature, NULL, 0);
+
+static ssize_t ad7314_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7314_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL, 0);
+
+static struct attribute *ad7314_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_temperature.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7314_attribute_group = {
+ .attrs = ad7314_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7314_probe(struct spi_device *spi_dev)
+{
+ struct ad7314_chip_info *chip;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(struct ad7314_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ dev_set_drvdata(&spi_dev->dev, chip);
+
+ chip->spi_dev = spi_dev;
+ chip->name = spi_dev->modalias;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = &spi_dev->dev;
+ chip->indio_dev->attrs = &ad7314_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ dev_info(&spi_dev->dev, "%s temperature sensor registered.\n",
+ chip->name);
+
+ return 0;
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit ad7314_remove(struct spi_device *spi_dev)
+{
+ struct ad7314_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ dev_set_drvdata(&spi_dev->dev, NULL);
+ if (spi_dev->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7314_id[] = {
+ { "adt7301", 0 },
+ { "adt7302", 0 },
+ { "ad7314", 0 },
+ {}
+};
+
+static struct spi_driver ad7314_driver = {
+ .driver = {
+ .name = "ad7314",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7314_probe,
+ .remove = __devexit_p(ad7314_remove),
+ .id_table = ad7314_id,
+};
+
+static __init int ad7314_init(void)
+{
+ return spi_register_driver(&ad7314_driver);
+}
+
+static __exit void ad7314_exit(void)
+{
+ spi_unregister_driver(&ad7314_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7314_init);
+module_exit(ad7314_exit);
diff --git a/drivers/staging/iio/adc/ad7745.c b/drivers/staging/iio/adc/ad7745.c
new file mode 100644
index 000000000000..ab7ef8450ae2
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7745.c
@@ -0,0 +1,734 @@
+/*
+ * AD774X capacitive sensor driver supporting AD7745/6/7
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD774X registers definition
+ */
+
+#define AD774X_STATUS 0
+#define AD774X_STATUS_RDY (1 << 2)
+#define AD774X_STATUS_RDYVT (1 << 1)
+#define AD774X_STATUS_RDYCAP (1 << 0)
+#define AD774X_CAP_DATA_HIGH 1
+#define AD774X_CAP_DATA_MID 2
+#define AD774X_CAP_DATA_LOW 3
+#define AD774X_VT_DATA_HIGH 4
+#define AD774X_VT_DATA_MID 5
+#define AD774X_VT_DATA_LOW 6
+#define AD774X_CAP_SETUP 7
+#define AD774X_VT_SETUP 8
+#define AD774X_EXEC_SETUP 9
+#define AD774X_CFG 10
+#define AD774X_CAPDACA 11
+#define AD774X_CAPDACB 12
+#define AD774X_CAPDAC_EN (1 << 7)
+#define AD774X_CAP_OFFH 13
+#define AD774X_CAP_OFFL 14
+#define AD774X_CAP_GAINH 15
+#define AD774X_CAP_GAINL 16
+#define AD774X_VOLT_GAINH 17
+#define AD774X_VOLT_GAINL 18
+
+#define AD774X_MAX_CONV_MODE 6
+
+/*
+ * struct ad774x_chip_info - chip specifc information
+ */
+
+struct ad774x_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ bool inter;
+ s64 last_timestamp;
+ u16 cap_offs; /* Capacitive offset */
+ u16 cap_gain; /* Capacitive gain calibration */
+ u16 volt_gain; /* Voltage gain calibration */
+ u8 cap_setup;
+ u8 vt_setup;
+ u8 exec_setup;
+
+ char *conversion_mode;
+};
+
+struct ad774x_conversion_mode {
+ char *name;
+ u8 reg_cfg;
+};
+
+struct ad774x_conversion_mode ad774x_conv_mode_table[AD774X_MAX_CONV_MODE] = {
+ { "idle", 0 },
+ { "continuous-conversion", 1 },
+ { "single-conversion", 2 },
+ { "power-down", 3 },
+ { "offset-calibration", 5 },
+ { "gain-calibration", 6 },
+};
+
+/*
+ * ad774x register access by I2C
+ */
+
+static int ad774x_i2c_read(struct ad774x_chip_info *chip, u8 reg, u8 *data, int len)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_master_send(client, &reg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C write error\n");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, data, len);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ad774x_i2c_write(struct ad774x_chip_info *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ u8 tx[2] = {
+ reg,
+ data,
+ };
+
+ ret = i2c_master_send(client, tx, 2);
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \
+ IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(cap_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_VT_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(in0_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_EXEC_SETUP(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(exec_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_VOLT_GAIN(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(in0_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_OFFS(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(cap_offs, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_GAIN(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(cap_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_DATA(_show) \
+ IIO_DEVICE_ATTR(cap0_raw, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_VT_DATA(_show) \
+ IIO_DEVICE_ATTR(in0_raw, S_IRUGO, _show, NULL, 0)
+
+static ssize_t ad774x_show_conversion_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ int len = 0;
+
+ for (i = 0; i < AD774X_MAX_CONV_MODE; i++)
+ len += sprintf(buf + len, "%s ", ad774x_conv_mode_table[i].name);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad774x_show_conversion_modes);
+
+static ssize_t ad774x_show_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad774x_store_conversion_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ u8 cfg;
+ int i;
+
+ ad774x_i2c_read(chip, AD774X_CFG, &cfg, 1);
+
+ for (i = 0; i < AD774X_MAX_CONV_MODE; i++) {
+ if (strncmp(buf, ad774x_conv_mode_table[i].name,
+ strlen(ad774x_conv_mode_table[i].name) - 1) == 0) {
+ chip->conversion_mode = ad774x_conv_mode_table[i].name;
+ cfg |= 0x18 | ad774x_conv_mode_table[i].reg_cfg;
+ ad774x_i2c_write(chip, AD774X_CFG, cfg);
+ return len;
+ }
+ }
+
+ dev_err(dev, "not supported conversion mode\n");
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+ ad774x_show_conversion_mode,
+ ad774x_store_conversion_mode);
+
+static ssize_t ad774x_show_dac_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ u8 data;
+
+ ad774x_i2c_read(chip, this_attr->address, &data, 1);
+
+ return sprintf(buf, "%02x\n", data & 0x7F);
+}
+
+static ssize_t ad774x_store_dac_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if (!ret) {
+ ad774x_i2c_write(chip, this_attr->address,
+ (data ? AD774X_CAPDAC_EN : 0) | (data & 0x7F));
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEVICE_ATTR(capdac0_raw, S_IRUGO | S_IWUSR,
+ ad774x_show_dac_value,
+ ad774x_store_dac_value,
+ AD774X_CAPDACA);
+
+static IIO_DEVICE_ATTR(capdac1_raw, S_IRUGO | S_IWUSR,
+ ad774x_show_dac_value,
+ ad774x_store_dac_value,
+ AD774X_CAPDACB);
+
+static ssize_t ad774x_show_cap_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->cap_setup);
+}
+
+static ssize_t ad774x_store_cap_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad774x_i2c_write(chip, AD774X_CAP_SETUP, data);
+ chip->cap_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_SETUP(S_IRUGO | S_IWUSR,
+ ad774x_show_cap_setup,
+ ad774x_store_cap_setup);
+
+static ssize_t ad774x_show_vt_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->vt_setup);
+}
+
+static ssize_t ad774x_store_vt_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad774x_i2c_write(chip, AD774X_VT_SETUP, data);
+ chip->vt_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_VT_SETUP(S_IRUGO | S_IWUSR,
+ ad774x_show_vt_setup,
+ ad774x_store_vt_setup);
+
+static ssize_t ad774x_show_exec_setup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%02x\n", chip->exec_setup);
+}
+
+static ssize_t ad774x_store_exec_setup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x100)) {
+ ad774x_i2c_write(chip, AD774X_EXEC_SETUP, data);
+ chip->exec_setup = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_EXEC_SETUP(S_IRUGO | S_IWUSR,
+ ad774x_show_exec_setup,
+ ad774x_store_exec_setup);
+
+static ssize_t ad774x_show_volt_gain(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->volt_gain);
+}
+
+static ssize_t ad774x_store_volt_gain(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad774x_i2c_write(chip, AD774X_VOLT_GAINH, data >> 8);
+ ad774x_i2c_write(chip, AD774X_VOLT_GAINL, data);
+ chip->volt_gain = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_VOLT_GAIN(S_IRUGO | S_IWUSR,
+ ad774x_show_volt_gain,
+ ad774x_store_volt_gain);
+
+static ssize_t ad774x_show_cap_data(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ char tmp[3];
+
+ ad774x_i2c_read(chip, AD774X_CAP_DATA_HIGH, tmp, 3);
+ data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
+
+ return sprintf(buf, "%ld\n", data);
+}
+
+static IIO_DEV_ATTR_CAP_DATA(ad774x_show_cap_data);
+
+static ssize_t ad774x_show_vt_data(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ char tmp[3];
+
+ ad774x_i2c_read(chip, AD774X_VT_DATA_HIGH, tmp, 3);
+ data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
+
+ return sprintf(buf, "%ld\n", data);
+}
+
+static IIO_DEV_ATTR_VT_DATA(ad774x_show_vt_data);
+
+static ssize_t ad774x_show_cap_offs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->cap_offs);
+}
+
+static ssize_t ad774x_store_cap_offs(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad774x_i2c_write(chip, AD774X_CAP_OFFH, data >> 8);
+ ad774x_i2c_write(chip, AD774X_CAP_OFFL, data);
+ chip->cap_offs = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_OFFS(S_IRUGO | S_IWUSR,
+ ad774x_show_cap_offs,
+ ad774x_store_cap_offs);
+
+static ssize_t ad774x_show_cap_gain(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->cap_gain);
+}
+
+static ssize_t ad774x_store_cap_gain(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+
+ if ((!ret) && (data < 0x10000)) {
+ ad774x_i2c_write(chip, AD774X_CAP_GAINH, data >> 8);
+ ad774x_i2c_write(chip, AD774X_CAP_GAINL, data);
+ chip->cap_gain = data;
+ return len;
+ }
+
+ return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_GAIN(S_IRUGO | S_IWUSR,
+ ad774x_show_cap_gain,
+ ad774x_store_cap_gain);
+
+static ssize_t ad774x_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad774x_show_name, NULL, 0);
+
+static struct attribute *ad774x_attributes[] = {
+ &iio_dev_attr_available_conversion_modes.dev_attr.attr,
+ &iio_dev_attr_conversion_mode.dev_attr.attr,
+ &iio_dev_attr_cap_setup.dev_attr.attr,
+ &iio_dev_attr_in0_setup.dev_attr.attr,
+ &iio_dev_attr_exec_setup.dev_attr.attr,
+ &iio_dev_attr_cap_offs.dev_attr.attr,
+ &iio_dev_attr_cap_gain.dev_attr.attr,
+ &iio_dev_attr_in0_gain.dev_attr.attr,
+ &iio_dev_attr_in0_raw.dev_attr.attr,
+ &iio_dev_attr_cap0_raw.dev_attr.attr,
+ &iio_dev_attr_capdac0_raw.dev_attr.attr,
+ &iio_dev_attr_capdac1_raw.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad774x_attribute_group = {
+ .attrs = ad774x_attributes,
+};
+
+/*
+ * data ready events
+ */
+
+#define IIO_EVENT_CODE_CAP_RDY IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_VT_RDY IIO_BUFFER_EVENT_CODE(1)
+
+#define IIO_EVENT_ATTR_CAP_RDY_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(cap_rdy, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_VT_RDY_SH(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(vt_rdy, _evlist, _show, _store, _mask)
+
+static void ad774x_interrupt_handler_bh(struct work_struct *work_s)
+{
+ struct ad774x_chip_info *chip =
+ container_of(work_s, struct ad774x_chip_info, thresh_work);
+ u8 int_status;
+
+ enable_irq(chip->client->irq);
+
+ ad774x_i2c_read(chip, AD774X_STATUS, &int_status, 1);
+
+ if (int_status & AD774X_STATUS_RDYCAP)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_CAP_RDY,
+ chip->last_timestamp);
+
+ if (int_status & AD774X_STATUS_RDYVT)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_VT_RDY,
+ chip->last_timestamp);
+}
+
+static int ad774x_interrupt_handler_th(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct ad774x_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(data_rdy, &ad774x_interrupt_handler_th);
+
+static ssize_t ad774x_query_out_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ /*
+ * AD774X provides one /RDY pin, which can be used as interrupt
+ * but the pin is not configurable
+ */
+ return sprintf(buf, "1\n");
+}
+
+static ssize_t ad774x_set_out_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return len;
+}
+
+IIO_EVENT_ATTR_CAP_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0);
+IIO_EVENT_ATTR_VT_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0);
+
+static struct attribute *ad774x_event_attributes[] = {
+ &iio_event_attr_cap_rdy.dev_attr.attr,
+ &iio_event_attr_vt_rdy.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad774x_event_attribute_group = {
+ .attrs = ad774x_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad774x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0, regdone = 0;
+ struct ad774x_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ /* Establish that the iio_dev is a child of the i2c device */
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &ad774x_attribute_group;
+ chip->indio_dev->event_attrs = &ad774x_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)(chip);
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+ regdone = 1;
+
+ if (client->irq) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ad774x");
+ if (ret)
+ goto error_free_dev;
+
+ iio_add_event_to_list(iio_event_attr_cap_rdy.listel,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, ad774x_interrupt_handler_bh);
+ }
+
+ dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq);
+
+ return 0;
+
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(chip->indio_dev);
+ else
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad774x_remove(struct i2c_client *client)
+{
+ struct ad774x_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ if (client->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id ad774x_id[] = {
+ { "ad7745", 0 },
+ { "ad7746", 0 },
+ { "ad7747", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad774x_id);
+
+static struct i2c_driver ad774x_driver = {
+ .driver = {
+ .name = "ad774x",
+ },
+ .probe = ad774x_probe,
+ .remove = __devexit_p(ad774x_remove),
+ .id_table = ad774x_id,
+};
+
+static __init int ad774x_init(void)
+{
+ return i2c_add_driver(&ad774x_driver);
+}
+
+static __exit void ad774x_exit(void)
+{
+ i2c_del_driver(&ad774x_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7745/6/7 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad774x_init);
+module_exit(ad774x_exit);
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
new file mode 100644
index 000000000000..ad7415a6b8d9
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -0,0 +1,535 @@
+/*
+ * AD7816 digital temperature sensor driver supporting AD7816/7/8
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7816 config masks
+ */
+#define AD7816_FULL 0x1
+#define AD7816_PD 0x2
+#define AD7816_CS_MASK 0x7
+#define AD7816_CS_MAX 0x4
+
+/*
+ * AD7816 temperature masks
+ */
+#define AD7816_VALUE_OFFSET 6
+#define AD7816_BOUND_VALUE_BASE 0x8
+#define AD7816_BOUND_VALUE_MIN -95
+#define AD7816_BOUND_VALUE_MAX 152
+#define AD7816_TEMP_FLOAT_OFFSET 2
+#define AD7816_TEMP_FLOAT_MASK 0x3
+
+
+/*
+ * struct ad7816_chip_info - chip specifc information
+ */
+
+struct ad7816_chip_info {
+ const char *name;
+ struct spi_device *spi_dev;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ u16 rdwr_pin;
+ u16 convert_pin;
+ u16 busy_pin;
+ u8 oti_data[AD7816_CS_MAX+1];
+ u8 channel_id; /* 0 always be temperature */
+ u8 mode;
+};
+
+/*
+ * ad7816 data access by SPI
+ */
+static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+
+ gpio_set_value(chip->rdwr_pin, 1);
+ gpio_set_value(chip->rdwr_pin, 0);
+ ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI channel setting error\n");
+ return ret;
+ }
+ gpio_set_value(chip->rdwr_pin, 1);
+
+
+ if (chip->mode == AD7816_PD) { /* operating mode 2 */
+ gpio_set_value(chip->convert_pin, 1);
+ gpio_set_value(chip->convert_pin, 0);
+ } else { /* operating mode 1 */
+ gpio_set_value(chip->convert_pin, 0);
+ gpio_set_value(chip->convert_pin, 1);
+ }
+
+ while (gpio_get_value(chip->busy_pin))
+ cpu_relax();
+
+ gpio_set_value(chip->rdwr_pin, 0);
+ gpio_set_value(chip->rdwr_pin, 1);
+ ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI data read error\n");
+ return ret;
+ }
+
+ *data = be16_to_cpu(*data);
+
+ return ret;
+}
+
+static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ int ret = 0;
+
+ gpio_set_value(chip->rdwr_pin, 1);
+ gpio_set_value(chip->rdwr_pin, 0);
+ ret = spi_write(spi_dev, &data, sizeof(data));
+ if (ret < 0)
+ dev_err(&spi_dev->dev, "SPI oti data write error\n");
+
+ return ret;
+}
+
+static ssize_t ad7816_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+
+ if (chip->mode)
+ return sprintf(buf, "power-save\n");
+ else
+ return sprintf(buf, "full\n");
+}
+
+static ssize_t ad7816_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+
+ if (strcmp(buf, "full")) {
+ gpio_set_value(chip->rdwr_pin, 1);
+ chip->mode = AD7816_FULL;
+ } else {
+ gpio_set_value(chip->rdwr_pin, 0);
+ chip->mode = AD7816_PD;
+ }
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ ad7816_show_mode,
+ ad7816_store_mode,
+ 0);
+
+static ssize_t ad7816_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "full\npower-save\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes, NULL, 0);
+
+static ssize_t ad7816_show_channel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", chip->channel_id);
+}
+
+static ssize_t ad7816_store_channel(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
+ dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
+ data, chip->name);
+ return -EINVAL;
+ } else if (strcmp(chip->name, "ad7818") == 0 && data > 1) {
+ dev_err(&chip->spi_dev->dev,
+ "Invalid channel id %lu for ad7818.\n", data);
+ return -EINVAL;
+ } else if (strcmp(chip->name, "ad7816") == 0 && data > 0) {
+ dev_err(&chip->spi_dev->dev,
+ "Invalid channel id %lu for ad7816.\n", data);
+ return -EINVAL;
+ }
+
+ chip->channel_id = data;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR,
+ ad7816_show_channel,
+ ad7816_store_channel,
+ 0);
+
+
+static ssize_t ad7816_show_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ s8 value;
+ int ret;
+
+ ret = ad7816_spi_read(chip, &data);
+ if (ret)
+ return -EIO;
+
+ data >>= AD7816_VALUE_OFFSET;
+
+ if (chip->channel_id == 0) {
+ value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
+ data &= AD7816_TEMP_FLOAT_MASK;
+ if (value < 0)
+ data = (1 << AD7816_TEMP_FLOAT_OFFSET) - data;
+ return sprintf(buf, "%d.%.2d\n", value, data * 25);
+ } else
+ return sprintf(buf, "%u\n", data);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0);
+
+static ssize_t ad7816_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7816_show_name, NULL, 0);
+
+static struct attribute *ad7816_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_channel.dev_attr.attr,
+ &iio_dev_attr_value.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7816_attribute_group = {
+ .attrs = ad7816_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_AD7816_OTI IIO_BUFFER_EVENT_CODE(0)
+
+static void ad7816_interrupt_bh(struct work_struct *work_s)
+{
+ struct ad7816_chip_info *chip =
+ container_of(work_s, struct ad7816_chip_info, thresh_work);
+
+ enable_irq(chip->spi_dev->irq);
+
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_AD7816_OTI,
+ chip->last_timestamp);
+}
+
+static int ad7816_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(ad7816, &ad7816_interrupt);
+
+static ssize_t ad7816_show_oti(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+ int value;
+
+ if (chip->channel_id > AD7816_CS_MAX) {
+ dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
+ return -EINVAL;
+ } else if (chip->channel_id == 0) {
+ value = AD7816_BOUND_VALUE_MIN +
+ (chip->oti_data[chip->channel_id] -
+ AD7816_BOUND_VALUE_BASE);
+ return sprintf(buf, "%d\n", value);
+ } else
+ return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
+}
+
+static inline ssize_t ad7816_set_oti(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7816_chip_info *chip = dev_info->dev_data;
+ long value;
+ u8 data;
+ int ret;
+
+ ret = strict_strtol(buf, 10, &value);
+
+ if (chip->channel_id > AD7816_CS_MAX) {
+ dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
+ return -EINVAL;
+ } else if (chip->channel_id == 0) {
+ if (ret || value < AD7816_BOUND_VALUE_MIN ||
+ value > AD7816_BOUND_VALUE_MAX)
+ return -EINVAL;
+
+ data = (u8)(value - AD7816_BOUND_VALUE_MIN +
+ AD7816_BOUND_VALUE_BASE);
+ } else {
+ if (ret || value < AD7816_BOUND_VALUE_BASE || value > 255)
+ return -EINVAL;
+
+ data = (u8)value;
+ }
+
+ ret = ad7816_spi_write(chip, data);
+ if (ret)
+ return -EIO;
+
+ chip->oti_data[chip->channel_id] = data;
+
+ return len;
+}
+
+IIO_EVENT_ATTR_SH(oti, iio_event_ad7816,
+ ad7816_show_oti, ad7816_set_oti, 0);
+
+static struct attribute *ad7816_event_attributes[] = {
+ &iio_event_attr_oti.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad7816_event_attribute_group = {
+ .attrs = ad7816_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7816_probe(struct spi_device *spi_dev)
+{
+ struct ad7816_chip_info *chip;
+ unsigned short *pins = spi_dev->dev.platform_data;
+ int ret = 0;
+ int i;
+
+ if (!pins) {
+ dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct ad7816_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ dev_set_drvdata(&spi_dev->dev, chip);
+
+ chip->spi_dev = spi_dev;
+ chip->name = spi_dev->modalias;
+ for (i = 0; i <= AD7816_CS_MAX; i++)
+ chip->oti_data[i] = 203;
+ chip->rdwr_pin = pins[0];
+ chip->convert_pin = pins[1];
+ chip->busy_pin = pins[2];
+
+ ret = gpio_request(chip->rdwr_pin, chip->name);
+ if (ret) {
+ dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n",
+ chip->rdwr_pin);
+ goto error_free_chip;
+ }
+ gpio_direction_input(chip->rdwr_pin);
+ ret = gpio_request(chip->convert_pin, chip->name);
+ if (ret) {
+ dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n",
+ chip->convert_pin);
+ goto error_free_gpio_rdwr;
+ }
+ gpio_direction_input(chip->convert_pin);
+ ret = gpio_request(chip->busy_pin, chip->name);
+ if (ret) {
+ dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
+ chip->busy_pin);
+ goto error_free_gpio_convert;
+ }
+ gpio_direction_input(chip->busy_pin);
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_gpio;
+ }
+
+ chip->indio_dev->dev.parent = &spi_dev->dev;
+ chip->indio_dev->attrs = &ad7816_attribute_group;
+ chip->indio_dev->event_attrs = &ad7816_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ if (spi_dev->irq) {
+ /* Only low trigger is supported in ad7816/7/8 */
+ ret = iio_register_interrupt_line(spi_dev->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_LOW,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_ad7816.
+ * All event attributes bind to the same event handler.
+ * So, only register event handler once.
+ */
+ iio_add_event_to_list(&iio_event_ad7816,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, ad7816_interrupt_bh);
+ }
+
+ dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
+ chip->name);
+
+ return 0;
+
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_gpio:
+ gpio_free(chip->busy_pin);
+error_free_gpio_convert:
+ gpio_free(chip->convert_pin);
+error_free_gpio_rdwr:
+ gpio_free(chip->rdwr_pin);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit ad7816_remove(struct spi_device *spi_dev)
+{
+ struct ad7816_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ dev_set_drvdata(&spi_dev->dev, NULL);
+ if (spi_dev->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ gpio_free(chip->busy_pin);
+ gpio_free(chip->convert_pin);
+ gpio_free(chip->rdwr_pin);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7816_id[] = {
+ { "ad7816", 0 },
+ { "ad7817", 0 },
+ { "ad7818", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, ad7816_id);
+
+static struct spi_driver ad7816_driver = {
+ .driver = {
+ .name = "ad7816",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7816_probe,
+ .remove = __devexit_p(ad7816_remove),
+ .id_table = ad7816_id,
+};
+
+static __init int ad7816_init(void)
+{
+ return spi_register_driver(&ad7816_driver);
+}
+
+static __exit void ad7816_exit(void)
+{
+ spi_unregister_driver(&ad7816_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7816_init);
+module_exit(ad7816_exit);
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
new file mode 100644
index 000000000000..8c2a218c9496
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -0,0 +1,105 @@
+/*
+ * AD7887 SPI ADC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_ADC_AD7887_H_
+#define IIO_ADC_AD7887_H_
+
+#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */
+#define AD7887_DUAL (1 << 4) /* dual-channel mode */
+#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */
+#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */
+#define AD7887_PM_MODE1 (0) /* CS based shutdown */
+#define AD7887_PM_MODE2 (1) /* full on */
+#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */
+#define AD7887_PM_MODE4 (3) /* standby mode */
+
+enum ad7887_channels {
+ AD7887_CH0,
+ AD7887_CH0_CH1,
+ AD7887_CH1,
+};
+
+#define RES_MASK(bits) ((1 << (bits)) - 1) /* TODO: move this into a common header */
+
+/*
+ * TODO: struct ad7887_platform_data needs to go into include/linux/iio
+ */
+
+struct ad7887_platform_data {
+ /* External Vref voltage applied */
+ u16 vref_mv;
+ /*
+ * AD7887:
+ * In single channel mode en_dual = flase, AIN1/Vref pins assumes its
+ * Vref function. In dual channel mode en_dual = true, AIN1 becomes the
+ * second input channel, and Vref is internally connected to Vdd.
+ */
+ bool en_dual;
+ /*
+ * AD7887:
+ * use_onchip_ref = true, the Vref is internally connected to the 2.500V
+ * Voltage reference. If use_onchip_ref = false, the reference voltage
+ * is supplied by AIN1/Vref
+ */
+ bool use_onchip_ref;
+};
+
+struct ad7887_chip_info {
+ u8 bits; /* number of ADC bits */
+ u8 storagebits; /* number of bits read from the ADC */
+ u8 left_shift; /* number of bits the sample must be shifted */
+ char sign; /* [s]igned or [u]nsigned */
+ u16 int_vref_mv; /* internal reference voltage */
+};
+
+struct ad7887_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ const struct ad7887_chip_info *chip_info;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ atomic_t protect_ring;
+ u16 int_vref_mv;
+ bool en_dual;
+ struct spi_transfer xfer[4];
+ struct spi_message msg[3];
+ struct spi_message *ring_msg;
+ unsigned char tx_cmd_buf[8];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+
+ unsigned char data[4] ____cacheline_aligned;
+};
+
+enum ad7887_supported_device_ids {
+ ID_AD7887
+};
+
+#ifdef CONFIG_IIO_RING_BUFFER
+int ad7887_scan_from_ring(struct ad7887_state *st, long mask);
+int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev);
+void ad7887_ring_cleanup(struct iio_dev *indio_dev);
+#else /* CONFIG_IIO_RING_BUFFER */
+static inline int ad7887_scan_from_ring(struct ad7887_state *st, long mask)
+{
+ return 0;
+}
+
+static inline int
+ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void ad7887_ring_cleanup(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* IIO_ADC_AD7887_H_ */
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
new file mode 100644
index 000000000000..685908995d49
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -0,0 +1,305 @@
+/*
+ * AD7887 SPI ADC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "adc.h"
+
+#include "ad7887.h"
+
+static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch)
+{
+ int ret = spi_sync(st->spi, &st->msg[ch]);
+ if (ret)
+ return ret;
+
+ return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1];
+}
+
+static ssize_t ad7887_scan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7887_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+
+ mutex_lock(&dev_info->mlock);
+ if (iio_ring_enabled(dev_info))
+ ret = ad7887_scan_from_ring(st, 1 << this_attr->address);
+ else
+ ret = ad7887_scan_direct(st, this_attr->address);
+ mutex_unlock(&dev_info->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", (ret >> st->chip_info->left_shift) &
+ RES_MASK(st->chip_info->bits));
+}
+static IIO_DEV_ATTR_IN_RAW(0, ad7887_scan, 0);
+static IIO_DEV_ATTR_IN_RAW(1, ad7887_scan, 1);
+
+static ssize_t ad7887_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ /* Driver currently only support internal vref */
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7887_state *st = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
+
+ return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7887_show_scale, NULL, 0);
+
+static ssize_t ad7887_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7887_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7887_show_name, NULL, 0);
+
+static struct attribute *ad7887_attributes[] = {
+ &iio_dev_attr_in0_raw.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
+ &iio_dev_attr_in_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7887_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7887_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if ((attr == &iio_dev_attr_in1_raw.dev_attr.attr) && !st->en_dual)
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group ad7887_attribute_group = {
+ .attrs = ad7887_attributes,
+ .is_visible = ad7887_attr_is_visible,
+};
+
+static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
+ /*
+ * More devices added in future
+ */
+ [ID_AD7887] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 0,
+ .sign = IIO_SCAN_EL_TYPE_UNSIGNED,
+ .int_vref_mv = 2500,
+ },
+};
+
+static int __devinit ad7887_probe(struct spi_device *spi)
+{
+ struct ad7887_platform_data *pdata = spi->dev.platform_data;
+ struct ad7887_state *st;
+ int ret, voltage_uv = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ voltage_uv = regulator_get_voltage(st->reg);
+ }
+
+ st->chip_info =
+ &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ spi_set_drvdata(spi, st);
+
+ atomic_set(&st->protect_ring, 0);
+ st->spi = spi;
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ /* Estabilish that the iio_dev is a child of the spi device */
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad7887_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default message */
+
+ st->tx_cmd_buf[0] = AD7887_CH_AIN0 | AD7887_PM_MODE4 |
+ ((pdata && pdata->use_onchip_ref) ?
+ 0 : AD7887_REF_DIS);
+
+ st->xfer[0].rx_buf = &st->data[0];
+ st->xfer[0].tx_buf = &st->tx_cmd_buf[0];
+ st->xfer[0].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH0]);
+ spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]);
+
+ if (pdata && pdata->en_dual) {
+ st->tx_cmd_buf[0] |= AD7887_DUAL | AD7887_REF_DIS;
+
+ st->tx_cmd_buf[2] = AD7887_CH_AIN1 | AD7887_DUAL |
+ AD7887_REF_DIS | AD7887_PM_MODE4;
+ st->tx_cmd_buf[4] = AD7887_CH_AIN0 | AD7887_DUAL |
+ AD7887_REF_DIS | AD7887_PM_MODE4;
+ st->tx_cmd_buf[6] = AD7887_CH_AIN1 | AD7887_DUAL |
+ AD7887_REF_DIS | AD7887_PM_MODE4;
+
+ st->xfer[1].rx_buf = &st->data[0];
+ st->xfer[1].tx_buf = &st->tx_cmd_buf[2];
+ st->xfer[1].len = 2;
+
+ st->xfer[2].rx_buf = &st->data[2];
+ st->xfer[2].tx_buf = &st->tx_cmd_buf[4];
+ st->xfer[2].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH0_CH1]);
+ spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]);
+ spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]);
+
+ st->xfer[3].rx_buf = &st->data[0];
+ st->xfer[3].tx_buf = &st->tx_cmd_buf[6];
+ st->xfer[3].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH1]);
+ spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
+
+ st->en_dual = true;
+
+ if (pdata && pdata->vref_mv)
+ st->int_vref_mv = pdata->vref_mv;
+ else if (voltage_uv)
+ st->int_vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev, "reference voltage unspecified\n");
+
+ } else {
+ if (pdata && pdata->vref_mv)
+ st->int_vref_mv = pdata->vref_mv;
+ else if (pdata && pdata->use_onchip_ref)
+ st->int_vref_mv = st->chip_info->int_vref_mv;
+ else
+ dev_warn(&spi->dev, "reference voltage unspecified\n");
+ }
+
+
+ ret = ad7887_register_ring_funcs_and_init(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
+ if (ret)
+ goto error_cleanup_ring;
+ return 0;
+
+error_cleanup_ring:
+ ad7887_ring_cleanup(st->indio_dev);
+ iio_device_unregister(st->indio_dev);
+error_free_device:
+ iio_free_device(st->indio_dev);
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int ad7887_remove(struct spi_device *spi)
+{
+ struct ad7887_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+ iio_ring_buffer_unregister(indio_dev->ring);
+ ad7887_ring_cleanup(indio_dev);
+ iio_device_unregister(indio_dev);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ kfree(st);
+ return 0;
+}
+
+static const struct spi_device_id ad7887_id[] = {
+ {"ad7887", ID_AD7887},
+ {}
+};
+
+static struct spi_driver ad7887_driver = {
+ .driver = {
+ .name = "ad7887",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7887_probe,
+ .remove = __devexit_p(ad7887_remove),
+ .id_table = ad7887_id,
+};
+
+static int __init ad7887_init(void)
+{
+ return spi_register_driver(&ad7887_driver);
+}
+module_init(ad7887_init);
+
+static void __exit ad7887_exit(void)
+{
+ spi_unregister_driver(&ad7887_driver);
+}
+module_exit(ad7887_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad7887");
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
new file mode 100644
index 000000000000..6b9cb1f95a1e
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2010 Analog Devices Inc.
+ * Copyright (C) 2008 Jonathan Cameron
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * ad7887_ring.c
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+#include "../trigger.h"
+#include "../sysfs.h"
+
+#include "ad7887.h"
+
+static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+
+static ssize_t ad7887_show_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7887_state *st = indio_dev->dev_data;
+
+ return sprintf(buf, "%c%d/%d>>%d\n", st->chip_info->sign,
+ st->chip_info->bits, st->chip_info->storagebits,
+ st->chip_info->left_shift);
+}
+static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7887_show_type, NULL, 0);
+
+static struct attribute *ad7887_scan_el_attrs[] = {
+ &iio_scan_el_in0.dev_attr.attr,
+ &iio_const_attr_in0_index.dev_attr.attr,
+ &iio_scan_el_in1.dev_attr.attr,
+ &iio_const_attr_in1_index.dev_attr.attr,
+ &iio_dev_attr_in_type.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7887_scan_el_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7887_state *st = indio_dev->dev_data;
+
+ mode_t mode = attr->mode;
+
+ if ((attr == &iio_scan_el_in1.dev_attr.attr) ||
+ (attr == &iio_const_attr_in1_index.dev_attr.attr))
+ if (!st->en_dual)
+ mode = 0;
+
+ return mode;
+}
+
+static struct attribute_group ad7887_scan_el_group = {
+ .name = "scan_elements",
+ .attrs = ad7887_scan_el_attrs,
+ .is_visible = ad7887_scan_el_attr_is_visible,
+};
+
+int ad7887_scan_from_ring(struct ad7887_state *st, long mask)
+{
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+ int count = 0, ret;
+ u16 *ring_data;
+
+ if (!(ring->scan_mask & mask)) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+
+ ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL);
+ if (ring_data == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = ring->access.read_last(ring, (u8 *) ring_data);
+ if (ret)
+ goto error_free_ring_data;
+
+ /* for single channel scan the result is stored with zero offset */
+ if ((ring->scan_mask == ((1 << 1) | (1 << 0))) && (mask == (1 << 1)))
+ count = 1;
+
+ ret = be16_to_cpu(ring_data[count]);
+
+error_free_ring_data:
+ kfree(ring_data);
+error_ret:
+ return ret;
+}
+
+/**
+ * ad7887_ring_preenable() setup the parameters of the ring before enabling
+ *
+ * The complex nature of the setting of the nuber of bytes per datum is due
+ * to this driver currently ensuring that the timestamp is stored at an 8
+ * byte boundary.
+ **/
+static int ad7887_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7887_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ size_t d_size;
+
+ if (indio_dev->ring->access.set_bytes_per_datum) {
+ d_size = st->chip_info->storagebits / 8 + sizeof(s64);
+ if (d_size % 8)
+ d_size += 8 - (d_size % 8);
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ d_size);
+ }
+
+ switch (ring->scan_mask) {
+ case (1 << 0):
+ st->ring_msg = &st->msg[AD7887_CH0];
+ break;
+ case (1 << 1):
+ st->ring_msg = &st->msg[AD7887_CH1];
+ /* Dummy read: push CH1 setting down to hardware */
+ spi_sync(st->spi, st->ring_msg);
+ break;
+ case ((1 << 1) | (1 << 0)):
+ st->ring_msg = &st->msg[AD7887_CH0_CH1];
+ break;
+ }
+
+ return 0;
+}
+
+static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad7887_state *st = indio_dev->dev_data;
+
+ /* dummy read: restore default CH0 settin */
+ return spi_sync(st->spi, &st->msg[AD7887_CH0]);
+}
+
+/**
+ * ad7887_poll_func_th() th of trigger launched polling to ring buffer
+ *
+ * As sampling only occurs on spi comms occuring, leave timestamping until
+ * then. Some triggers will generate their own time stamp. Currently
+ * there is no way of notifying them when no one cares.
+ **/
+static void ad7887_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ad7887_state *st = indio_dev->dev_data;
+
+ schedule_work(&st->poll_work);
+ return;
+}
+/**
+ * ad7887_poll_bh_to_ring() bh of trigger launched polling to ring buffer
+ * @work_s: the work struct through which this was scheduled
+ *
+ * Currently there is no option in this driver to disable the saving of
+ * timestamps within the ring.
+ * I think the one copy of this at a time was to avoid problems if the
+ * trigger was set far too high and the reads then locked up the computer.
+ **/
+static void ad7887_poll_bh_to_ring(struct work_struct *work_s)
+{
+ struct ad7887_state *st = container_of(work_s, struct ad7887_state,
+ poll_work);
+ struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring);
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ s64 time_ns;
+ __u8 *buf;
+ int b_sent;
+ size_t d_size;
+
+ unsigned int bytes = ring->scan_count * st->chip_info->storagebits / 8;
+
+ /* Ensure the timestamp is 8 byte aligned */
+ d_size = bytes + sizeof(s64);
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+
+ /* Ensure only one copy of this function running at a time */
+ if (atomic_inc_return(&st->protect_ring) > 1)
+ return;
+
+ buf = kzalloc(d_size, GFP_KERNEL);
+ if (buf == NULL)
+ return;
+
+ b_sent = spi_sync(st->spi, st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ time_ns = iio_get_time_ns();
+
+ memcpy(buf, st->data, bytes);
+ memcpy(buf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+
+ indio_dev->ring->access.store_to(&sw_ring->buf, buf, time_ns);
+done:
+ kfree(buf);
+ atomic_dec(&st->protect_ring);
+}
+
+int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct ad7887_state *st = indio_dev->dev_data;
+ int ret;
+
+ indio_dev->ring = iio_sw_rb_allocate(indio_dev);
+ if (!indio_dev->ring) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* Effectively select the ring buffer implementation */
+ iio_ring_sw_register_funcs(&indio_dev->ring->access);
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7887_poll_func_th);
+ if (ret)
+ goto error_deallocate_sw_rb;
+
+ /* Ring buffer functions - here trigger setup related */
+
+ indio_dev->ring->preenable = &ad7887_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->postdisable = &ad7887_ring_postdisable;
+ indio_dev->ring->scan_el_attrs = &ad7887_scan_el_group;
+
+ INIT_WORK(&st->poll_work, &ad7887_poll_bh_to_ring);
+
+ /* Flag that polled ring buffering is possible */
+ indio_dev->modes |= INDIO_RING_TRIGGERED;
+ return 0;
+error_deallocate_sw_rb:
+ iio_sw_rb_free(indio_dev->ring);
+error_ret:
+ return ret;
+}
+
+void ad7887_ring_cleanup(struct iio_dev *indio_dev)
+{
+ /* ensure that the trigger has been detached */
+ if (indio_dev->trig) {
+ iio_put_trigger(indio_dev->trig);
+ iio_trigger_dettach_poll_func(indio_dev->trig,
+ indio_dev->pollfunc);
+ }
+ kfree(indio_dev->pollfunc);
+ iio_sw_rb_free(indio_dev->ring);
+}
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
new file mode 100644
index 000000000000..771a409ee94c
--- /dev/null
+++ b/drivers/staging/iio/adc/adt7310.c
@@ -0,0 +1,952 @@
+/*
+ * ADT7310 digital temperature sensor driver supporting ADT7310
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT7310 registers definition
+ */
+
+#define ADT7310_STATUS 0
+#define ADT7310_CONFIG 1
+#define ADT7310_TEMPERATURE 2
+#define ADT7310_ID 3
+#define ADT7310_T_CRIT 4
+#define ADT7310_T_HYST 5
+#define ADT7310_T_ALARM_HIGH 6
+#define ADT7310_T_ALARM_LOW 7
+
+/*
+ * ADT7310 status
+ */
+#define ADT7310_STAT_T_LOW 0x10
+#define ADT7310_STAT_T_HIGH 0x20
+#define ADT7310_STAT_T_CRIT 0x40
+#define ADT7310_STAT_NOT_RDY 0x80
+
+/*
+ * ADT7310 config
+ */
+#define ADT7310_FAULT_QUEUE_MASK 0x3
+#define ADT7310_CT_POLARITY 0x4
+#define ADT7310_INT_POLARITY 0x8
+#define ADT7310_EVENT_MODE 0x10
+#define ADT7310_MODE_MASK 0x60
+#define ADT7310_ONESHOT 0x20
+#define ADT7310_SPS 0x40
+#define ADT7310_PD 0x60
+#define ADT7310_RESOLUTION 0x80
+
+/*
+ * ADT7310 masks
+ */
+#define ADT7310_T16_VALUE_SIGN 0x8000
+#define ADT7310_T16_VALUE_FLOAT_OFFSET 7
+#define ADT7310_T16_VALUE_FLOAT_MASK 0x7F
+#define ADT7310_T13_VALUE_SIGN 0x1000
+#define ADT7310_T13_VALUE_OFFSET 3
+#define ADT7310_T13_VALUE_FLOAT_OFFSET 4
+#define ADT7310_T13_VALUE_FLOAT_MASK 0xF
+#define ADT7310_T_HYST_MASK 0xF
+#define ADT7310_DEVICE_ID_MASK 0x7
+#define ADT7310_MANUFACTORY_ID_MASK 0xF8
+#define ADT7310_MANUFACTORY_ID_OFFSET 3
+
+
+#define ADT7310_CMD_REG_MASK 0x28
+#define ADT7310_CMD_REG_OFFSET 3
+#define ADT7310_CMD_READ 0x40
+#define ADT7310_CMD_CON_READ 0x4
+
+#define ADT7310_IRQS 2
+
+/*
+ * struct adt7310_chip_info - chip specifc information
+ */
+
+struct adt7310_chip_info {
+ const char *name;
+ struct spi_device *spi_dev;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ u8 config;
+};
+
+/*
+ * adt7310 register access by SPI
+ */
+
+static int adt7310_spi_read_word(struct adt7310_chip_info *chip, u8 reg, u16 *data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+ int ret = 0;
+
+ command |= ADT7310_CMD_READ;
+ ret = spi_write(spi_dev, &command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write command error\n");
+ return ret;
+ }
+
+ ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read word error\n");
+ return ret;
+ }
+
+ *data = be16_to_cpu(*data);
+
+ return 0;
+}
+
+static int adt7310_spi_write_word(struct adt7310_chip_info *chip, u8 reg, u16 data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ u8 buf[3];
+ int ret = 0;
+
+ buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+ buf[1] = (u8)(data >> 8);
+ buf[2] = (u8)(data & 0xFF);
+
+ ret = spi_write(spi_dev, buf, 3);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write word error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int adt7310_spi_read_byte(struct adt7310_chip_info *chip, u8 reg, u8 *data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+ int ret = 0;
+
+ command |= ADT7310_CMD_READ;
+ ret = spi_write(spi_dev, &command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write command error\n");
+ return ret;
+ }
+
+ ret = spi_read(spi_dev, data, sizeof(*data));
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read byte error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adt7310_spi_write_byte(struct adt7310_chip_info *chip, u8 reg, u8 data)
+{
+ struct spi_device *spi_dev = chip->spi_dev;
+ u8 buf[2];
+ int ret = 0;
+
+ buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+ buf[1] = data;
+
+ ret = spi_write(spi_dev, buf, 2);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write byte error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static ssize_t adt7310_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u8 config;
+
+ config = chip->config & ADT7310_MODE_MASK;
+
+ switch (config) {
+ case ADT7310_PD:
+ return sprintf(buf, "power-down\n");
+ case ADT7310_ONESHOT:
+ return sprintf(buf, "one-shot\n");
+ case ADT7310_SPS:
+ return sprintf(buf, "sps\n");
+ default:
+ return sprintf(buf, "full\n");
+ }
+}
+
+static ssize_t adt7310_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u16 config;
+ int ret;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & (~ADT7310_MODE_MASK);
+ if (strcmp(buf, "power-down"))
+ config |= ADT7310_PD;
+ else if (strcmp(buf, "one-shot"))
+ config |= ADT7310_ONESHOT;
+ else if (strcmp(buf, "sps"))
+ config |= ADT7310_SPS;
+
+ ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ adt7310_show_mode,
+ adt7310_store_mode,
+ 0);
+
+static ssize_t adt7310_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "full\none-shot\nsps\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7310_show_available_modes, NULL, 0);
+
+static ssize_t adt7310_show_resolution(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ int ret;
+ int bits;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ if (chip->config & ADT7310_RESOLUTION)
+ bits = 16;
+ else
+ bits = 13;
+
+ return sprintf(buf, "%d bits\n", bits);
+}
+
+static ssize_t adt7310_store_resolution(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ u16 config;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & (~ADT7310_RESOLUTION);
+ if (data)
+ config |= ADT7310_RESOLUTION;
+
+ ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
+ adt7310_show_resolution,
+ adt7310_store_resolution,
+ 0);
+
+static ssize_t adt7310_show_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u8 id;
+ int ret;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_ID, &id);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
+ id & ADT7310_DEVICE_ID_MASK,
+ (id & ADT7310_MANUFACTORY_ID_MASK) >> ADT7310_MANUFACTORY_ID_OFFSET);
+}
+
+static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
+ adt7310_show_id,
+ NULL,
+ 0);
+
+static ssize_t adt7310_convert_temperature(struct adt7310_chip_info *chip,
+ u16 data, char *buf)
+{
+ char sign = ' ';
+
+ if (chip->config & ADT7310_RESOLUTION) {
+ if (data & ADT7310_T16_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data);
+ sign = '-';
+ }
+ return sprintf(buf, "%c%d.%.7d\n", sign,
+ (data >> ADT7310_T16_VALUE_FLOAT_OFFSET),
+ (data & ADT7310_T16_VALUE_FLOAT_MASK) * 78125);
+ } else {
+ if (data & ADT7310_T13_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data >>= ADT7310_T13_VALUE_OFFSET;
+ data = (ADT7310_T13_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+ return sprintf(buf, "%c%d.%.4d\n", sign,
+ (data >> ADT7310_T13_VALUE_FLOAT_OFFSET),
+ (data & ADT7310_T13_VALUE_FLOAT_MASK) * 625);
+ }
+}
+
+static ssize_t adt7310_show_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u8 status;
+ u16 data;
+ int ret, i = 0;
+
+ do {
+ ret = adt7310_spi_read_byte(chip, ADT7310_STATUS, &status);
+ if (ret)
+ return -EIO;
+ i++;
+ if (i == 10000)
+ return -EIO;
+ } while (status & ADT7310_STAT_NOT_RDY);
+
+ ret = adt7310_spi_read_word(chip, ADT7310_TEMPERATURE, &data);
+ if (ret)
+ return -EIO;
+
+ return adt7310_convert_temperature(chip, data, buf);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt7310_show_value, NULL, 0);
+
+static ssize_t adt7310_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7310_show_name, NULL, 0);
+
+static struct attribute *adt7310_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_resolution.dev_attr.attr,
+ &iio_dev_attr_id.dev_attr.attr,
+ &iio_dev_attr_value.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adt7310_attribute_group = {
+ .attrs = adt7310_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7310_ABOVE_ALARM IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7310_BELLOW_ALARM IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7310_ABOVE_CRIT IIO_BUFFER_EVENT_CODE(2)
+
+static void adt7310_interrupt_bh(struct work_struct *work_s)
+{
+ struct adt7310_chip_info *chip =
+ container_of(work_s, struct adt7310_chip_info, thresh_work);
+ u8 status;
+
+ if (adt7310_spi_read_byte(chip, ADT7310_STATUS, &status))
+ return;
+
+ if (status & ADT7310_STAT_T_HIGH)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7310_ABOVE_ALARM,
+ chip->last_timestamp);
+ if (status & ADT7310_STAT_T_LOW)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7310_BELLOW_ALARM,
+ chip->last_timestamp);
+ if (status & ADT7310_STAT_T_CRIT)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7310_ABOVE_CRIT,
+ chip->last_timestamp);
+}
+
+static int adt7310_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(adt7310, &adt7310_interrupt);
+IIO_EVENT_SH(adt7310_ct, &adt7310_interrupt);
+
+static ssize_t adt7310_show_event_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ if (chip->config & ADT7310_EVENT_MODE)
+ return sprintf(buf, "interrupt\n");
+ else
+ return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt7310_set_event_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u16 config;
+ int ret;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config &= ~ADT7310_EVENT_MODE;
+ if (strcmp(buf, "comparator") != 0)
+ config |= ADT7310_EVENT_MODE;
+
+ ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return len;
+}
+
+static ssize_t adt7310_show_available_event_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt7310_show_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", chip->config & ADT7310_FAULT_QUEUE_MASK);
+}
+
+static ssize_t adt7310_set_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+ u8 config;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret || data > 3)
+ return -EINVAL;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT7310_FAULT_QUEUE_MASK;
+ config |= data;
+ ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return len;
+}
+
+static inline ssize_t adt7310_show_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ int ret;
+
+ ret = adt7310_spi_read_word(chip, bound_reg, &data);
+ if (ret)
+ return -EIO;
+
+ return adt7310_convert_temperature(chip, data, buf);
+}
+
+static inline ssize_t adt7310_set_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ long tmp1, tmp2;
+ u16 data;
+ char *pos;
+ int ret;
+
+ pos = strchr(buf, '.');
+
+ ret = strict_strtol(buf, 10, &tmp1);
+
+ if (ret || tmp1 > 127 || tmp1 < -128)
+ return -EINVAL;
+
+ if (pos) {
+ len = strlen(pos);
+
+ if (chip->config & ADT7310_RESOLUTION) {
+ if (len > ADT7310_T16_VALUE_FLOAT_OFFSET)
+ len = ADT7310_T16_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 78125) * 78125;
+ } else {
+ if (len > ADT7310_T13_VALUE_FLOAT_OFFSET)
+ len = ADT7310_T13_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 625) * 625;
+ }
+ }
+
+ if (tmp1 < 0)
+ data = (u16)(-tmp1);
+ else
+ data = (u16)tmp1;
+
+ if (chip->config & ADT7310_RESOLUTION) {
+ data = (data << ADT7310_T16_VALUE_FLOAT_OFFSET) |
+ (tmp2 & ADT7310_T16_VALUE_FLOAT_MASK);
+
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data);
+ } else {
+ data = (data << ADT7310_T13_VALUE_FLOAT_OFFSET) |
+ (tmp2 & ADT7310_T13_VALUE_FLOAT_MASK);
+
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (ADT7310_T13_VALUE_SIGN << 1) - data;
+ data <<= ADT7310_T13_VALUE_OFFSET;
+ }
+
+ ret = adt7310_spi_write_word(chip, bound_reg, data);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static ssize_t adt7310_show_t_alarm_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7310_show_t_bound(dev, attr,
+ ADT7310_T_ALARM_HIGH, buf);
+}
+
+static inline ssize_t adt7310_set_t_alarm_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7310_set_t_bound(dev, attr,
+ ADT7310_T_ALARM_HIGH, buf, len);
+}
+
+static ssize_t adt7310_show_t_alarm_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7310_show_t_bound(dev, attr,
+ ADT7310_T_ALARM_LOW, buf);
+}
+
+static inline ssize_t adt7310_set_t_alarm_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7310_set_t_bound(dev, attr,
+ ADT7310_T_ALARM_LOW, buf, len);
+}
+
+static ssize_t adt7310_show_t_crit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7310_show_t_bound(dev, attr,
+ ADT7310_T_CRIT, buf);
+}
+
+static inline ssize_t adt7310_set_t_crit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7310_set_t_bound(dev, attr,
+ ADT7310_T_CRIT, buf, len);
+}
+
+static ssize_t adt7310_show_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ int ret;
+ u8 t_hyst;
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_T_HYST, &t_hyst);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", t_hyst & ADT7310_T_HYST_MASK);
+}
+
+static inline ssize_t adt7310_set_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7310_chip_info *chip = dev_info->dev_data;
+ int ret;
+ unsigned long data;
+ u8 t_hyst;
+
+ ret = strict_strtol(buf, 10, &data);
+
+ if (ret || data > ADT7310_T_HYST_MASK)
+ return -EINVAL;
+
+ t_hyst = (u8)data;
+
+ ret = adt7310_spi_write_byte(chip, ADT7310_T_HYST, t_hyst);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7310,
+ adt7310_show_event_mode, adt7310_set_event_mode, 0);
+IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7310,
+ adt7310_show_available_event_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7310,
+ adt7310_show_fault_queue, adt7310_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7310,
+ adt7310_show_t_alarm_high, adt7310_set_t_alarm_high, 0);
+IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7310,
+ adt7310_show_t_alarm_low, adt7310_set_t_alarm_low, 0);
+IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7310_ct,
+ adt7310_show_t_crit, adt7310_set_t_crit, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7310,
+ adt7310_show_t_hyst, adt7310_set_t_hyst, 0);
+
+static struct attribute *adt7310_event_int_attributes[] = {
+ &iio_event_attr_event_mode.dev_attr.attr,
+ &iio_event_attr_available_event_modes.dev_attr.attr,
+ &iio_event_attr_fault_queue.dev_attr.attr,
+ &iio_event_attr_t_alarm_high.dev_attr.attr,
+ &iio_event_attr_t_alarm_low.dev_attr.attr,
+ &iio_event_attr_t_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute *adt7310_event_ct_attributes[] = {
+ &iio_event_attr_event_mode.dev_attr.attr,
+ &iio_event_attr_available_event_modes.dev_attr.attr,
+ &iio_event_attr_fault_queue.dev_attr.attr,
+ &iio_event_attr_t_crit.dev_attr.attr,
+ &iio_event_attr_t_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = {
+ {
+ .attrs = adt7310_event_int_attributes,
+ },
+ {
+ .attrs = adt7310_event_ct_attributes,
+ }
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7310_probe(struct spi_device *spi_dev)
+{
+ struct adt7310_chip_info *chip;
+ int ret = 0;
+ unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
+ unsigned long irq_flags;
+
+ chip = kzalloc(sizeof(struct adt7310_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ dev_set_drvdata(&spi_dev->dev, chip);
+
+ chip->spi_dev = spi_dev;
+ chip->name = spi_dev->modalias;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = &spi_dev->dev;
+ chip->indio_dev->attrs = &adt7310_attribute_group;
+ chip->indio_dev->event_attrs = adt7310_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = ADT7310_IRQS;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ /* CT critcal temperature event. line 0 */
+ if (spi_dev->irq) {
+ if (adt7310_platform_data[2])
+ irq_flags = adt7310_platform_data[2];
+ else
+ irq_flags = IRQF_TRIGGER_LOW;
+ ret = iio_register_interrupt_line(spi_dev->irq,
+ chip->indio_dev,
+ 0,
+ irq_flags,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_adt7310.
+ * All event attributes bind to the same event handler.
+ * One event handler can only be added to one event list.
+ */
+ iio_add_event_to_list(&iio_event_adt7310,
+ &chip->indio_dev->interrupts[0]->ev_list);
+ }
+
+ /* INT bound temperature alarm event. line 1 */
+ if (adt7310_platform_data[0]) {
+ ret = iio_register_interrupt_line(adt7310_platform_data[0],
+ chip->indio_dev,
+ 1,
+ adt7310_platform_data[1],
+ chip->name);
+ if (ret)
+ goto error_unreg_ct_irq;
+
+ /*
+ * The event handler list element refer to iio_event_adt7310.
+ * All event attributes bind to the same event handler.
+ * One event handler can only be added to one event list.
+ */
+ iio_add_event_to_list(&iio_event_adt7310_ct,
+ &chip->indio_dev->interrupts[1]->ev_list);
+ }
+
+ if (spi_dev->irq && adt7310_platform_data[0]) {
+ INIT_WORK(&chip->thresh_work, adt7310_interrupt_bh);
+
+ ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_int_irq;
+ }
+
+ /* set irq polarity low level */
+ chip->config &= ~ADT7310_CT_POLARITY;
+
+ if (adt7310_platform_data[1] & IRQF_TRIGGER_HIGH)
+ chip->config |= ADT7310_INT_POLARITY;
+ else
+ chip->config &= ~ADT7310_INT_POLARITY;
+
+ ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_int_irq;
+ }
+ }
+
+ dev_info(&spi_dev->dev, "%s temperature sensor registered.\n",
+ chip->name);
+
+ return 0;
+
+error_unreg_int_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 1);
+error_unreg_ct_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit adt7310_remove(struct spi_device *spi_dev)
+{
+ struct adt7310_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+ struct iio_dev *indio_dev = chip->indio_dev;
+ unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
+
+ dev_set_drvdata(&spi_dev->dev, NULL);
+ if (adt7310_platform_data[0])
+ iio_unregister_interrupt_line(indio_dev, 1);
+ if (spi_dev->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct spi_device_id adt7310_id[] = {
+ { "adt7310", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+ .driver = {
+ .name = "adt7310",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = adt7310_probe,
+ .remove = __devexit_p(adt7310_remove),
+ .id_table = adt7310_id,
+};
+
+static __init int adt7310_init(void)
+{
+ return spi_register_driver(&adt7310_driver);
+}
+
+static __exit void adt7310_exit(void)
+{
+ spi_unregister_driver(&adt7310_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7310 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7310_init);
+module_exit(adt7310_exit);
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
new file mode 100644
index 000000000000..c345f27ec7fc
--- /dev/null
+++ b/drivers/staging/iio/adc/adt7410.c
@@ -0,0 +1,915 @@
+/*
+ * ADT7410 digital temperature sensor driver supporting ADT7410
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE 0
+#define ADT7410_STATUS 2
+#define ADT7410_CONFIG 3
+#define ADT7410_T_ALARM_HIGH 4
+#define ADT7410_T_ALARM_LOW 6
+#define ADT7410_T_CRIT 8
+#define ADT7410_T_HYST 0xA
+#define ADT7410_ID 0xB
+#define ADT7410_RESET 0x2F
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW 0x10
+#define ADT7410_STAT_T_HIGH 0x20
+#define ADT7410_STAT_T_CRIT 0x40
+#define ADT7410_STAT_NOT_RDY 0x80
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK 0x3
+#define ADT7410_CT_POLARITY 0x4
+#define ADT7410_INT_POLARITY 0x8
+#define ADT7410_EVENT_MODE 0x10
+#define ADT7410_MODE_MASK 0x60
+#define ADT7410_ONESHOT 0x20
+#define ADT7410_SPS 0x40
+#define ADT7410_PD 0x60
+#define ADT7410_RESOLUTION 0x80
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T16_VALUE_SIGN 0x8000
+#define ADT7410_T16_VALUE_FLOAT_OFFSET 7
+#define ADT7410_T16_VALUE_FLOAT_MASK 0x7F
+#define ADT7410_T13_VALUE_SIGN 0x1000
+#define ADT7410_T13_VALUE_OFFSET 3
+#define ADT7410_T13_VALUE_FLOAT_OFFSET 4
+#define ADT7410_T13_VALUE_FLOAT_MASK 0xF
+#define ADT7410_T_HYST_MASK 0xF
+#define ADT7410_DEVICE_ID_MASK 0xF
+#define ADT7410_MANUFACTORY_ID_MASK 0xF0
+#define ADT7410_MANUFACTORY_ID_OFFSET 4
+
+#define ADT7410_IRQS 2
+
+/*
+ * struct adt7410_chip_info - chip specifc information
+ */
+
+struct adt7410_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ u8 config;
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+
+static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ *data = swab16((u16)ret);
+
+ return 0;
+}
+
+static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_word_data(client, reg, swab16(data));
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ *data = (u8)ret;
+
+ return 0;
+}
+
+static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_byte_data(client, reg, data);
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+static ssize_t adt7410_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u8 config;
+
+ config = chip->config & ADT7410_MODE_MASK;
+
+ switch (config) {
+ case ADT7410_PD:
+ return sprintf(buf, "power-down\n");
+ case ADT7410_ONESHOT:
+ return sprintf(buf, "one-shot\n");
+ case ADT7410_SPS:
+ return sprintf(buf, "sps\n");
+ default:
+ return sprintf(buf, "full\n");
+ }
+}
+
+static ssize_t adt7410_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u16 config;
+ int ret;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & (~ADT7410_MODE_MASK);
+ if (strcmp(buf, "power-down"))
+ config |= ADT7410_PD;
+ else if (strcmp(buf, "one-shot"))
+ config |= ADT7410_ONESHOT;
+ else if (strcmp(buf, "sps"))
+ config |= ADT7410_SPS;
+
+ ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ adt7410_show_mode,
+ adt7410_store_mode,
+ 0);
+
+static ssize_t adt7410_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "full\none-shot\nsps\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0);
+
+static ssize_t adt7410_show_resolution(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ int ret;
+ int bits;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ if (chip->config & ADT7410_RESOLUTION)
+ bits = 16;
+ else
+ bits = 13;
+
+ return sprintf(buf, "%d bits\n", bits);
+}
+
+static ssize_t adt7410_store_resolution(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ u16 config;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & (~ADT7410_RESOLUTION);
+ if (data)
+ config |= ADT7410_RESOLUTION;
+
+ ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
+ adt7410_show_resolution,
+ adt7410_store_resolution,
+ 0);
+
+static ssize_t adt7410_show_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u8 id;
+ int ret;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_ID, &id);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
+ id & ADT7410_DEVICE_ID_MASK,
+ (id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET);
+}
+
+static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
+ adt7410_show_id,
+ NULL,
+ 0);
+
+static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip,
+ u16 data, char *buf)
+{
+ char sign = ' ';
+
+ if (chip->config & ADT7410_RESOLUTION) {
+ if (data & ADT7410_T16_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
+ sign = '-';
+ }
+ return sprintf(buf, "%c%d.%.7d\n", sign,
+ (data >> ADT7410_T16_VALUE_FLOAT_OFFSET),
+ (data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125);
+ } else {
+ if (data & ADT7410_T13_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data >>= ADT7410_T13_VALUE_OFFSET;
+ data = (ADT7410_T13_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+ return sprintf(buf, "%c%d.%.4d\n", sign,
+ (data >> ADT7410_T13_VALUE_FLOAT_OFFSET),
+ (data & ADT7410_T13_VALUE_FLOAT_MASK) * 625);
+ }
+}
+
+static ssize_t adt7410_show_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u8 status;
+ u16 data;
+ int ret, i = 0;
+
+ do {
+ ret = adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status);
+ if (ret)
+ return -EIO;
+ i++;
+ if (i == 10000)
+ return -EIO;
+ } while (status & ADT7410_STAT_NOT_RDY);
+
+ ret = adt7410_i2c_read_word(chip, ADT7410_TEMPERATURE, &data);
+ if (ret)
+ return -EIO;
+
+ return adt7410_convert_temperature(chip, data, buf);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0);
+
+static ssize_t adt7410_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL, 0);
+
+static struct attribute *adt7410_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_resolution.dev_attr.attr,
+ &iio_dev_attr_id.dev_attr.attr,
+ &iio_dev_attr_value.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adt7410_attribute_group = {
+ .attrs = adt7410_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7410_ABOVE_ALARM IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7410_BELLOW_ALARM IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7410_ABOVE_CRIT IIO_BUFFER_EVENT_CODE(2)
+
+static void adt7410_interrupt_bh(struct work_struct *work_s)
+{
+ struct adt7410_chip_info *chip =
+ container_of(work_s, struct adt7410_chip_info, thresh_work);
+ u8 status;
+
+ if (adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status))
+ return;
+
+ enable_irq(chip->client->irq);
+
+ if (status & ADT7410_STAT_T_HIGH)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7410_ABOVE_ALARM,
+ chip->last_timestamp);
+ if (status & ADT7410_STAT_T_LOW)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7410_BELLOW_ALARM,
+ chip->last_timestamp);
+ if (status & ADT7410_STAT_T_CRIT)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7410_ABOVE_CRIT,
+ chip->last_timestamp);
+}
+
+static int adt7410_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(adt7410, &adt7410_interrupt);
+IIO_EVENT_SH(adt7410_ct, &adt7410_interrupt);
+
+static ssize_t adt7410_show_event_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ if (chip->config & ADT7410_EVENT_MODE)
+ return sprintf(buf, "interrupt\n");
+ else
+ return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt7410_set_event_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u16 config;
+ int ret;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config &= ~ADT7410_EVENT_MODE;
+ if (strcmp(buf, "comparator") != 0)
+ config |= ADT7410_EVENT_MODE;
+
+ ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static ssize_t adt7410_show_available_event_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt7410_show_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK);
+}
+
+static ssize_t adt7410_set_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+ u8 config;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret || data > 3)
+ return -EINVAL;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT7410_FAULT_QUEUE_MASK;
+ config |= data;
+ ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static inline ssize_t adt7410_show_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ int ret;
+
+ ret = adt7410_i2c_read_word(chip, bound_reg, &data);
+ if (ret)
+ return -EIO;
+
+ return adt7410_convert_temperature(chip, data, buf);
+}
+
+static inline ssize_t adt7410_set_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ long tmp1, tmp2;
+ u16 data;
+ char *pos;
+ int ret;
+
+ pos = strchr(buf, '.');
+
+ ret = strict_strtol(buf, 10, &tmp1);
+
+ if (ret || tmp1 > 127 || tmp1 < -128)
+ return -EINVAL;
+
+ if (pos) {
+ len = strlen(pos);
+
+ if (chip->config & ADT7410_RESOLUTION) {
+ if (len > ADT7410_T16_VALUE_FLOAT_OFFSET)
+ len = ADT7410_T16_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 78125) * 78125;
+ } else {
+ if (len > ADT7410_T13_VALUE_FLOAT_OFFSET)
+ len = ADT7410_T13_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 625) * 625;
+ }
+ }
+
+ if (tmp1 < 0)
+ data = (u16)(-tmp1);
+ else
+ data = (u16)tmp1;
+
+ if (chip->config & ADT7410_RESOLUTION) {
+ data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) |
+ (tmp2 & ADT7410_T16_VALUE_FLOAT_MASK);
+
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
+ } else {
+ data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) |
+ (tmp2 & ADT7410_T13_VALUE_FLOAT_MASK);
+
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (ADT7410_T13_VALUE_SIGN << 1) - data;
+ data <<= ADT7410_T13_VALUE_OFFSET;
+ }
+
+ ret = adt7410_i2c_write_word(chip, bound_reg, data);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+static ssize_t adt7410_show_t_alarm_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7410_show_t_bound(dev, attr,
+ ADT7410_T_ALARM_HIGH, buf);
+}
+
+static inline ssize_t adt7410_set_t_alarm_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7410_set_t_bound(dev, attr,
+ ADT7410_T_ALARM_HIGH, buf, len);
+}
+
+static ssize_t adt7410_show_t_alarm_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7410_show_t_bound(dev, attr,
+ ADT7410_T_ALARM_LOW, buf);
+}
+
+static inline ssize_t adt7410_set_t_alarm_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7410_set_t_bound(dev, attr,
+ ADT7410_T_ALARM_LOW, buf, len);
+}
+
+static ssize_t adt7410_show_t_crit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7410_show_t_bound(dev, attr,
+ ADT7410_T_CRIT, buf);
+}
+
+static inline ssize_t adt7410_set_t_crit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7410_set_t_bound(dev, attr,
+ ADT7410_T_CRIT, buf, len);
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ int ret;
+ u8 t_hyst;
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_T_HYST, &t_hyst);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK);
+}
+
+static inline ssize_t adt7410_set_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7410_chip_info *chip = dev_info->dev_data;
+ int ret;
+ unsigned long data;
+ u8 t_hyst;
+
+ ret = strict_strtol(buf, 10, &data);
+
+ if (ret || data > ADT7410_T_HYST_MASK)
+ return -EINVAL;
+
+ t_hyst = (u8)data;
+
+ ret = adt7410_i2c_write_byte(chip, ADT7410_T_HYST, t_hyst);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7410,
+ adt7410_show_event_mode, adt7410_set_event_mode, 0);
+IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7410,
+ adt7410_show_available_event_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7410,
+ adt7410_show_fault_queue, adt7410_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7410,
+ adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0);
+IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7410,
+ adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0);
+IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7410_ct,
+ adt7410_show_t_crit, adt7410_set_t_crit, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7410,
+ adt7410_show_t_hyst, adt7410_set_t_hyst, 0);
+
+static struct attribute *adt7410_event_int_attributes[] = {
+ &iio_event_attr_event_mode.dev_attr.attr,
+ &iio_event_attr_available_event_modes.dev_attr.attr,
+ &iio_event_attr_fault_queue.dev_attr.attr,
+ &iio_event_attr_t_alarm_high.dev_attr.attr,
+ &iio_event_attr_t_alarm_low.dev_attr.attr,
+ &iio_event_attr_t_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute *adt7410_event_ct_attributes[] = {
+ &iio_event_attr_event_mode.dev_attr.attr,
+ &iio_event_attr_available_event_modes.dev_attr.attr,
+ &iio_event_attr_fault_queue.dev_attr.attr,
+ &iio_event_attr_t_crit.dev_attr.attr,
+ &iio_event_attr_t_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = {
+ {
+ .attrs = adt7410_event_int_attributes,
+ },
+ {
+ .attrs = adt7410_event_ct_attributes,
+ }
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7410_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7410_chip_info *chip;
+ int ret = 0;
+ unsigned long *adt7410_platform_data = client->dev.platform_data;
+
+ chip = kzalloc(sizeof(struct adt7410_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &adt7410_attribute_group;
+ chip->indio_dev->event_attrs = adt7410_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = ADT7410_IRQS;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ /* CT critcal temperature event. line 0 */
+ if (client->irq) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_LOW,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_adt7410.
+ * All event attributes bind to the same event handler.
+ * One event handler can only be added to one event list.
+ */
+ iio_add_event_to_list(&iio_event_adt7410,
+ &chip->indio_dev->interrupts[0]->ev_list);
+ }
+
+ /* INT bound temperature alarm event. line 1 */
+ if (adt7410_platform_data[0]) {
+ ret = iio_register_interrupt_line(adt7410_platform_data[0],
+ chip->indio_dev,
+ 1,
+ adt7410_platform_data[1],
+ chip->name);
+ if (ret)
+ goto error_unreg_ct_irq;
+
+ /*
+ * The event handler list element refer to iio_event_adt7410.
+ * All event attributes bind to the same event handler.
+ * One event handler can only be added to one event list.
+ */
+ iio_add_event_to_list(&iio_event_adt7410_ct,
+ &chip->indio_dev->interrupts[1]->ev_list);
+ }
+
+ if (client->irq && adt7410_platform_data[0]) {
+ INIT_WORK(&chip->thresh_work, adt7410_interrupt_bh);
+
+ ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_int_irq;
+ }
+
+ /* set irq polarity low level */
+ chip->config &= ~ADT7410_CT_POLARITY;
+
+ if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH)
+ chip->config |= ADT7410_INT_POLARITY;
+ else
+ chip->config &= ~ADT7410_INT_POLARITY;
+
+ ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_int_irq;
+ }
+ }
+
+ dev_info(&client->dev, "%s temperature sensor registered.\n",
+ id->name);
+
+ return 0;
+
+error_unreg_int_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 1);
+error_unreg_ct_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit adt7410_remove(struct i2c_client *client)
+{
+ struct adt7410_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+ unsigned long *adt7410_platform_data = client->dev.platform_data;
+
+ if (adt7410_platform_data[0])
+ iio_unregister_interrupt_line(indio_dev, 1);
+ if (client->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id adt7410_id[] = {
+ { "adt7410", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adt7410_id);
+
+static struct i2c_driver adt7410_driver = {
+ .driver = {
+ .name = "adt7410",
+ },
+ .probe = adt7410_probe,
+ .remove = __devexit_p(adt7410_remove),
+ .id_table = adt7410_id,
+};
+
+static __init int adt7410_init(void)
+{
+ return i2c_add_driver(&adt7410_driver);
+}
+
+static __exit void adt7410_exit(void)
+{
+ i2c_del_driver(&adt7410_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7410 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7410_init);
+module_exit(adt7410_exit);
diff --git a/drivers/staging/iio/adc/adt75.c b/drivers/staging/iio/adc/adt75.c
new file mode 100644
index 000000000000..aff4d31eb89c
--- /dev/null
+++ b/drivers/staging/iio/adc/adt75.c
@@ -0,0 +1,732 @@
+/*
+ * ADT75 digital temperature sensor driver supporting ADT75
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT75 registers definition
+ */
+
+#define ADT75_TEMPERATURE 0
+#define ADT75_CONFIG 1
+#define ADT75_T_HYST 2
+#define ADT75_T_OS 3
+#define ADT75_ONESHOT 4
+
+/*
+ * ADT75 config
+ */
+#define ADT75_PD 0x1
+#define ADT75_OS_INT 0x2
+#define ADT75_OS_POLARITY 0x4
+#define ADT75_FAULT_QUEUE_MASK 0x18
+#define ADT75_FAULT_QUEUE_OFFSET 3
+#define ADT75_SMBUS_ALART 0x8
+
+/*
+ * ADT75 masks
+ */
+#define ADT75_VALUE_SIGN 0x800
+#define ADT75_VALUE_OFFSET 4
+#define ADT75_VALUE_FLOAT_OFFSET 4
+#define ADT75_VALUE_FLOAT_MASK 0xF
+
+
+/*
+ * struct adt75_chip_info - chip specifc information
+ */
+
+struct adt75_chip_info {
+ const char *name;
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ u8 config;
+};
+
+/*
+ * adt75 register access by I2C
+ */
+
+static int adt75_i2c_read(struct adt75_chip_info *chip, u8 reg, u8 *data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0, len;
+
+ ret = i2c_smbus_write_byte(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read register address error\n");
+ return ret;
+ }
+
+ if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT)
+ len = 1;
+ else
+ len = 2;
+
+ ret = i2c_master_recv(client, data, len);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int adt75_i2c_write(struct adt75_chip_info *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT)
+ ret = i2c_smbus_write_byte_data(client, reg, data);
+ else
+ ret = i2c_smbus_write_word_data(client, reg, data);
+
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+static ssize_t adt75_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+
+ if (chip->config & ADT75_PD)
+ return sprintf(buf, "power-save\n");
+ else
+ return sprintf(buf, "full\n");
+}
+
+static ssize_t adt75_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ int ret;
+ u8 config;
+
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT75_PD;
+ if (!strcmp(buf, "full"))
+ config |= ADT75_PD;
+
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ adt75_show_mode,
+ adt75_store_mode,
+ 0);
+
+static ssize_t adt75_show_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "full\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt75_show_available_modes, NULL, 0);
+
+static ssize_t adt75_show_oneshot(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->config & ADT75_ONESHOT));
+}
+
+static ssize_t adt75_store_oneshot(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ unsigned long data = 0;
+ int ret;
+ u8 config;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT75_ONESHOT;
+ if (data)
+ config |= ADT75_ONESHOT;
+
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(oneshot, S_IRUGO | S_IWUSR,
+ adt75_show_oneshot,
+ adt75_store_oneshot,
+ 0);
+
+static ssize_t adt75_show_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ if (chip->config & ADT75_PD) {
+ dev_err(dev, "Can't read value in power-down mode.\n");
+ return -EIO;
+ }
+
+ if (chip->config & ADT75_ONESHOT) {
+ /* write to active converter */
+ ret = i2c_smbus_write_byte(chip->client, ADT75_ONESHOT);
+ if (ret)
+ return -EIO;
+ }
+
+ ret = adt75_i2c_read(chip, ADT75_TEMPERATURE, (u8 *)&data);
+ if (ret)
+ return -EIO;
+
+ data = swab16(data) >> ADT75_VALUE_OFFSET;
+ if (data & ADT75_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (ADT75_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.4d\n", sign,
+ (data >> ADT75_VALUE_FLOAT_OFFSET),
+ (data & ADT75_VALUE_FLOAT_MASK) * 625);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt75_show_value, NULL, 0);
+
+static ssize_t adt75_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt75_show_name, NULL, 0);
+
+static struct attribute *adt75_attributes[] = {
+ &iio_dev_attr_available_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_oneshot.dev_attr.attr,
+ &iio_dev_attr_value.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adt75_attribute_group = {
+ .attrs = adt75_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT75_OTI IIO_BUFFER_EVENT_CODE(0)
+
+static void adt75_interrupt_bh(struct work_struct *work_s)
+{
+ struct adt75_chip_info *chip =
+ container_of(work_s, struct adt75_chip_info, thresh_work);
+
+ enable_irq(chip->client->irq);
+
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT75_OTI,
+ chip->last_timestamp);
+}
+
+static int adt75_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adt75_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(adt75, &adt75_interrupt);
+
+static ssize_t adt75_show_oti_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ if (chip->config & ADT75_OS_INT)
+ return sprintf(buf, "interrupt\n");
+ else
+ return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt75_set_oti_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ int ret;
+ u8 config;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT75_OS_INT;
+ if (strcmp(buf, "comparator") != 0)
+ config |= ADT75_OS_INT;
+
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static ssize_t adt75_show_available_oti_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt75_show_smbus_alart(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", !!(chip->config & ADT75_SMBUS_ALART));
+}
+
+static ssize_t adt75_set_smbus_alart(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ unsigned long data = 0;
+ int ret;
+ u8 config;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT75_SMBUS_ALART;
+ if (data)
+ config |= ADT75_SMBUS_ALART;
+
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+
+static ssize_t adt75_show_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ int ret;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", (chip->config & ADT75_FAULT_QUEUE_MASK) >>
+ ADT75_FAULT_QUEUE_OFFSET);
+}
+
+static ssize_t adt75_set_fault_queue(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+ u8 config;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret || data > 3)
+ return -EINVAL;
+
+ /* retrive ALART status */
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret)
+ return -EIO;
+
+ config = chip->config & ~ADT75_FAULT_QUEUE_MASK;
+ config |= (data << ADT75_FAULT_QUEUE_OFFSET);
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+ if (ret)
+ return -EIO;
+
+ chip->config = config;
+
+ return ret;
+}
+static inline ssize_t adt75_show_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ u16 data;
+ char sign = ' ';
+ int ret;
+
+ ret = adt75_i2c_read(chip, bound_reg, (u8 *)&data);
+ if (ret)
+ return -EIO;
+
+ data = swab16(data) >> ADT75_VALUE_OFFSET;
+ if (data & ADT75_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (ADT75_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.4d\n", sign,
+ (data >> ADT75_VALUE_FLOAT_OFFSET),
+ (data & ADT75_VALUE_FLOAT_MASK) * 625);
+}
+
+static inline ssize_t adt75_set_t_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt75_chip_info *chip = dev_info->dev_data;
+ long tmp1, tmp2;
+ u16 data;
+ char *pos;
+ int ret;
+
+ pos = strchr(buf, '.');
+
+ ret = strict_strtol(buf, 10, &tmp1);
+
+ if (ret || tmp1 > 127 || tmp1 < -128)
+ return -EINVAL;
+
+ if (pos) {
+ len = strlen(pos);
+ if (len > ADT75_VALUE_FLOAT_OFFSET)
+ len = ADT75_VALUE_FLOAT_OFFSET;
+ pos[len] = 0;
+ ret = strict_strtol(pos, 10, &tmp2);
+
+ if (!ret)
+ tmp2 = (tmp2 / 625) * 625;
+ }
+
+ if (tmp1 < 0)
+ data = (u16)(-tmp1);
+ else
+ data = (u16)tmp1;
+ data = (data << ADT75_VALUE_FLOAT_OFFSET) | (tmp2 & ADT75_VALUE_FLOAT_MASK);
+ if (tmp1 < 0)
+ /* convert positive value to supplyment */
+ data = (ADT75_VALUE_SIGN << 1) - data;
+ data <<= ADT75_VALUE_OFFSET;
+ data = swab16(data);
+
+ ret = adt75_i2c_write(chip, bound_reg, (u8)data);
+ if (ret)
+ return -EIO;
+
+ return ret;
+}
+
+static ssize_t adt75_show_t_os(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt75_show_t_bound(dev, attr,
+ ADT75_T_OS, buf);
+}
+
+static inline ssize_t adt75_set_t_os(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt75_set_t_bound(dev, attr,
+ ADT75_T_OS, buf, len);
+}
+
+static ssize_t adt75_show_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt75_show_t_bound(dev, attr,
+ ADT75_T_HYST, buf);
+}
+
+static inline ssize_t adt75_set_t_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt75_set_t_bound(dev, attr,
+ ADT75_T_HYST, buf, len);
+}
+
+IIO_EVENT_ATTR_SH(oti_mode, iio_event_adt75,
+ adt75_show_oti_mode, adt75_set_oti_mode, 0);
+IIO_EVENT_ATTR_SH(available_oti_modes, iio_event_adt75,
+ adt75_show_available_oti_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(smbus_alart, iio_event_adt75,
+ adt75_show_smbus_alart, adt75_set_smbus_alart, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt75,
+ adt75_show_fault_queue, adt75_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_os, iio_event_adt75,
+ adt75_show_t_os, adt75_set_t_os, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt75,
+ adt75_show_t_hyst, adt75_set_t_hyst, 0);
+
+static struct attribute *adt75_event_attributes[] = {
+ &iio_event_attr_oti_mode.dev_attr.attr,
+ &iio_event_attr_available_oti_modes.dev_attr.attr,
+ &iio_event_attr_smbus_alart.dev_attr.attr,
+ &iio_event_attr_fault_queue.dev_attr.attr,
+ &iio_event_attr_t_os.dev_attr.attr,
+ &iio_event_attr_t_hyst.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adt75_event_attribute_group = {
+ .attrs = adt75_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt75_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt75_chip_info *chip;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(struct adt75_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, chip);
+
+ chip->client = client;
+ chip->name = id->name;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = &client->dev;
+ chip->indio_dev->attrs = &adt75_attribute_group;
+ chip->indio_dev->event_attrs = &adt75_event_attribute_group;
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ if (client->irq > 0) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_LOW,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_adt75.
+ * All event attributes bind to the same event handler.
+ * So, only register event handler once.
+ */
+ iio_add_event_to_list(&iio_event_adt75,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, adt75_interrupt_bh);
+
+ ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_irq;
+ }
+
+ /* set irq polarity low level */
+ chip->config &= ~ADT75_OS_POLARITY;
+
+ ret = adt75_i2c_write(chip, ADT75_CONFIG, chip->config);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_irq;
+ }
+ }
+
+ dev_info(&client->dev, "%s temperature sensor registered.\n",
+ id->name);
+
+ return 0;
+error_unreg_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit adt75_remove(struct i2c_client *client)
+{
+ struct adt75_chip_info *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ if (client->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id adt75_id[] = {
+ { "adt75", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adt75_id);
+
+static struct i2c_driver adt75_driver = {
+ .driver = {
+ .name = "adt75",
+ },
+ .probe = adt75_probe,
+ .remove = __devexit_p(adt75_remove),
+ .id_table = adt75_id,
+};
+
+static __init int adt75_init(void)
+{
+ return i2c_add_driver(&adt75_driver);
+}
+
+static __exit void adt75_exit(void)
+{
+ i2c_del_driver(&adt75_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT75 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt75_init);
+module_exit(adt75_exit);
diff --git a/drivers/staging/iio/addac/Kconfig b/drivers/staging/iio/addac/Kconfig
new file mode 100644
index 000000000000..9847baf02700
--- /dev/null
+++ b/drivers/staging/iio/addac/Kconfig
@@ -0,0 +1,25 @@
+#
+# ADDAC drivers
+#
+comment "Analog digital bi-direction convertors"
+
+config ADT7316
+ tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver"
+ help
+ Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318
+ and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC.
+
+config ADT7316_SPI
+ tristate "support SPI bus connection"
+ depends on SPI && ADT7316
+ default y
+ help
+ Say yes here to build SPI bus support for Analog Devices ADT7316/7/8
+ and ADT7516/7/9.
+
+config ADT7316_I2C
+ tristate "support I2C bus connection"
+ depends on I2C && ADT7316
+ help
+ Say yes here to build I2C bus support for Analog Devices ADT7316/7/8
+ and ADT7516/7/9.
diff --git a/drivers/staging/iio/addac/Makefile b/drivers/staging/iio/addac/Makefile
new file mode 100644
index 000000000000..4c7686133692
--- /dev/null
+++ b/drivers/staging/iio/addac/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for industrial I/O ADDAC drivers
+#
+
+obj-$(CONFIG_ADT7316) += adt7316.o
+obj-$(CONFIG_ADT7316_SPI) += adt7316-spi.o
+obj-$(CONFIG_ADT7316_I2C) += adt7316-i2c.o
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
new file mode 100644
index 000000000000..52d1ea349635
--- /dev/null
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -0,0 +1,170 @@
+/*
+ * I2C bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
+ * sensor, ADC and DAC
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+
+#include "adt7316.h"
+
+/*
+ * adt7316 register access by I2C
+ */
+static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
+{
+ struct i2c_client *cl = client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_byte(cl, reg);
+ if (ret < 0) {
+ dev_err(&cl->dev, "I2C fail to select reg\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0) {
+ dev_err(&cl->dev, "I2C read error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adt7316_i2c_write(void *client, u8 reg, u8 data)
+{
+ struct i2c_client *cl = client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_byte_data(cl, reg, data);
+ if (ret < 0)
+ dev_err(&cl->dev, "I2C write error\n");
+
+ return ret;
+}
+
+static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data)
+{
+ struct i2c_client *cl = client;
+ int i, ret = 0;
+
+ if (count > ADT7316_REG_MAX_ADDR)
+ count = ADT7316_REG_MAX_ADDR;
+
+ for (i = 0; i < count; i++) {
+ ret = adt7316_i2c_read(cl, reg, &data[i]);
+ if (ret < 0) {
+ dev_err(&cl->dev, "I2C multi read error\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data)
+{
+ struct i2c_client *cl = client;
+ int i, ret = 0;
+
+ if (count > ADT7316_REG_MAX_ADDR)
+ count = ADT7316_REG_MAX_ADDR;
+
+ for (i = 0; i < count; i++) {
+ ret = adt7316_i2c_write(cl, reg, data[i]);
+ if (ret < 0) {
+ dev_err(&cl->dev, "I2C multi write error\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7316_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7316_bus bus = {
+ .client = client,
+ .irq = client->irq,
+ .irq_flags = IRQF_TRIGGER_LOW,
+ .read = adt7316_i2c_read,
+ .write = adt7316_i2c_write,
+ .multi_read = adt7316_i2c_multi_read,
+ .multi_write = adt7316_i2c_multi_write,
+ };
+
+ return adt7316_probe(&client->dev, &bus, id->name);
+}
+
+static int __devexit adt7316_i2c_remove(struct i2c_client *client)
+{
+ return adt7316_remove(&client->dev);;
+}
+
+static const struct i2c_device_id adt7316_i2c_id[] = {
+ { "adt7316", 0 },
+ { "adt7317", 0 },
+ { "adt7318", 0 },
+ { "adt7516", 0 },
+ { "adt7517", 0 },
+ { "adt7519", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
+
+#ifdef CONFIG_PM
+static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+ return adt7316_disable(&client->dev);
+}
+
+static int adt7316_i2c_resume(struct i2c_client *client)
+{
+ return adt7316_enable(&client->dev);
+}
+#else
+# define adt7316_i2c_suspend NULL
+# define adt7316_i2c_resume NULL
+#endif
+
+static struct i2c_driver adt7316_driver = {
+ .driver = {
+ .name = "adt7316",
+ .owner = THIS_MODULE,
+ },
+ .probe = adt7316_i2c_probe,
+ .remove = __devexit_p(adt7316_i2c_remove),
+ .suspend = adt7316_i2c_suspend,
+ .resume = adt7316_i2c_resume,
+ .id_table = adt7316_i2c_id,
+};
+
+static __init int adt7316_i2c_init(void)
+{
+ return i2c_add_driver(&adt7316_driver);
+}
+
+static __exit void adt7316_i2c_exit(void)
+{
+ i2c_del_driver(&adt7316_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and"
+ "ADT7516/7/8 digital temperature sensor, ADC and DAC");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7316_i2c_init);
+module_exit(adt7316_i2c_exit);
diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
new file mode 100644
index 000000000000..369d4d01ed97
--- /dev/null
+++ b/drivers/staging/iio/addac/adt7316-spi.c
@@ -0,0 +1,180 @@
+/*
+ * API bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
+ * sensor, ADC and DAC
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include "adt7316.h"
+
+#define ADT7316_SPI_MAX_FREQ_HZ 5000000
+#define ADT7316_SPI_CMD_READ 0x91
+#define ADT7316_SPI_CMD_WRITE 0x90
+
+/*
+ * adt7316 register access by SPI
+ */
+
+static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data)
+{
+ struct spi_device *spi_dev = client;
+ u8 cmd[2];
+ int ret = 0;
+
+ if (count > ADT7316_REG_MAX_ADDR)
+ count = ADT7316_REG_MAX_ADDR;
+
+ cmd[0] = ADT7316_SPI_CMD_WRITE;
+ cmd[1] = reg;
+
+ ret = spi_write(spi_dev, cmd, 2);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI fail to select reg\n");
+ return ret;
+ }
+
+ cmd[0] = ADT7316_SPI_CMD_READ;
+
+ ret = spi_write_then_read(spi_dev, cmd, 1, data, count);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI read data error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data)
+{
+ struct spi_device *spi_dev = client;
+ u8 buf[ADT7316_REG_MAX_ADDR + 2];
+ int i, ret = 0;
+
+ if (count > ADT7316_REG_MAX_ADDR)
+ count = ADT7316_REG_MAX_ADDR;
+
+ buf[0] = ADT7316_SPI_CMD_WRITE;
+ buf[1] = reg;
+ for (i = 0; i < count; i++)
+ buf[i + 2] = data[i];
+
+ ret = spi_write(spi_dev, buf, count + 2);
+ if (ret < 0) {
+ dev_err(&spi_dev->dev, "SPI write error\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int adt7316_spi_read(void *client, u8 reg, u8 *data)
+{
+ return adt7316_spi_multi_read(client, reg, 1, data);
+}
+
+static int adt7316_spi_write(void *client, u8 reg, u8 val)
+{
+ return adt7316_spi_multi_write(client, reg, 1, &val);
+}
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7316_spi_probe(struct spi_device *spi_dev)
+{
+ struct adt7316_bus bus = {
+ .client = spi_dev,
+ .irq = spi_dev->irq,
+ .irq_flags = IRQF_TRIGGER_LOW,
+ .read = adt7316_spi_read,
+ .write = adt7316_spi_write,
+ .multi_read = adt7316_spi_multi_read,
+ .multi_write = adt7316_spi_multi_write,
+ };
+
+ /* don't exceed max specified SPI CLK frequency */
+ if (spi_dev->max_speed_hz > ADT7316_SPI_MAX_FREQ_HZ) {
+ dev_err(&spi_dev->dev, "SPI CLK %d Hz?\n",
+ spi_dev->max_speed_hz);
+ return -EINVAL;
+ }
+
+ /* switch from default I2C protocol to SPI protocol */
+ adt7316_spi_write(spi_dev, 0, 0);
+ adt7316_spi_write(spi_dev, 0, 0);
+ adt7316_spi_write(spi_dev, 0, 0);
+
+ return adt7316_probe(&spi_dev->dev, &bus, spi_dev->modalias);
+}
+
+static int __devexit adt7316_spi_remove(struct spi_device *spi_dev)
+{
+ return adt7316_remove(&spi_dev->dev);
+}
+
+static const struct spi_device_id adt7316_spi_id[] = {
+ { "adt7316", 0 },
+ { "adt7317", 0 },
+ { "adt7318", 0 },
+ { "adt7516", 0 },
+ { "adt7517", 0 },
+ { "adt7519", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
+
+#ifdef CONFIG_PM
+static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message)
+{
+ return adt7316_disable(&spi_dev->dev);
+}
+
+static int adt7316_spi_resume(struct spi_device *spi_dev)
+{
+ return adt7316_enable(&spi_dev->dev);
+}
+#else
+# define adt7316_spi_suspend NULL
+# define adt7316_spi_resume NULL
+#endif
+
+static struct spi_driver adt7316_driver = {
+ .driver = {
+ .name = "adt7316",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = adt7316_spi_probe,
+ .remove = __devexit_p(adt7316_spi_remove),
+ .suspend = adt7316_spi_suspend,
+ .resume = adt7316_spi_resume,
+ .id_table = adt7316_spi_id,
+};
+
+static __init int adt7316_spi_init(void)
+{
+ return spi_register_driver(&adt7316_driver);
+}
+
+static __exit void adt7316_spi_exit(void)
+{
+ spi_unregister_driver(&adt7316_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and"
+ "ADT7516/7/9 digital temperature sensor, ADC and DAC");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7316_spi_init);
+module_exit(adt7316_spi_exit);
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
new file mode 100644
index 000000000000..d1b5b13629d9
--- /dev/null
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -0,0 +1,2402 @@
+/*
+ * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
+ *
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "adt7316.h"
+
+/*
+ * ADT7316 registers definition
+ */
+#define ADT7316_INT_STAT1 0x0
+#define ADT7316_INT_STAT2 0x1
+#define ADT7316_LSB_IN_TEMP_VDD 0x3
+#define ADT7316_LSB_IN_TEMP_MASK 0x3
+#define ADT7316_LSB_VDD_MASK 0xC
+#define ADT7316_LSB_VDD_OFFSET 2
+#define ADT7316_LSB_EX_TEMP_AIN 0x4
+#define ADT7316_LSB_EX_TEMP_MASK 0x3
+#define ADT7516_LSB_AIN_SHIFT 2
+#define ADT7316_AD_MSB_DATA_BASE 0x6
+#define ADT7316_AD_MSB_DATA_REGS 3
+#define ADT7516_AD_MSB_DATA_REGS 6
+#define ADT7316_MSB_VDD 0x6
+#define ADT7316_MSB_IN_TEMP 0x7
+#define ADT7316_MSB_EX_TEMP 0x8
+#define ADT7516_MSB_AIN1 0x8
+#define ADT7516_MSB_AIN2 0x9
+#define ADT7516_MSB_AIN3 0xA
+#define ADT7516_MSB_AIN4 0xB
+#define ADT7316_DA_DATA_BASE 0x10
+#define ADT7316_DA_MSB_DATA_REGS 4
+#define ADT7316_LSB_DAC_A 0x10
+#define ADT7316_MSB_DAC_A 0x11
+#define ADT7316_LSB_DAC_B 0x12
+#define ADT7316_MSB_DAC_B 0x13
+#define ADT7316_LSB_DAC_C 0x14
+#define ADT7316_MSB_DAC_C 0x15
+#define ADT7316_LSB_DAC_D 0x16
+#define ADT7316_MSB_DAC_D 0x17
+#define ADT7316_CONFIG1 0x18
+#define ADT7316_CONFIG2 0x19
+#define ADT7316_CONFIG3 0x1A
+#define ADT7316_LDAC_CONFIG 0x1B
+#define ADT7316_DAC_CONFIG 0x1C
+#define ADT7316_INT_MASK1 0x1D
+#define ADT7316_INT_MASK2 0x1E
+#define ADT7316_IN_TEMP_OFFSET 0x1F
+#define ADT7316_EX_TEMP_OFFSET 0x20
+#define ADT7316_IN_ANALOG_TEMP_OFFSET 0x21
+#define ADT7316_EX_ANALOG_TEMP_OFFSET 0x22
+#define ADT7316_VDD_HIGH 0x23
+#define ADT7316_VDD_LOW 0x24
+#define ADT7316_IN_TEMP_HIGH 0x25
+#define ADT7316_IN_TEMP_LOW 0x26
+#define ADT7316_EX_TEMP_HIGH 0x27
+#define ADT7316_EX_TEMP_LOW 0x28
+#define ADT7516_AIN2_HIGH 0x2B
+#define ADT7516_AIN2_LOW 0x2C
+#define ADT7516_AIN3_HIGH 0x2D
+#define ADT7516_AIN3_LOW 0x2E
+#define ADT7516_AIN4_HIGH 0x2F
+#define ADT7516_AIN4_LOW 0x30
+#define ADT7316_DEVICE_ID 0x4D
+#define ADT7316_MANUFACTURE_ID 0x4E
+#define ADT7316_DEVICE_REV 0x4F
+#define ADT7316_SPI_LOCK_STAT 0x7F
+
+/*
+ * ADT7316 config1
+ */
+#define ADT7316_EN 0x1
+#define ADT7516_SEL_EX_TEMP 0x4
+#define ADT7516_SEL_AIN1_2_EX_TEMP_MASK 0x6
+#define ADT7516_SEL_AIN3 0x8
+#define ADT7316_INT_EN 0x20
+#define ADT7316_INT_POLARITY 0x40
+#define ADT7316_PD 0x80
+
+/*
+ * ADT7316 config2
+ */
+#define ADT7316_AD_SINGLE_CH_MASK 0x3
+#define ADT7516_AD_SINGLE_CH_MASK 0x7
+#define ADT7316_AD_SINGLE_CH_VDD 0
+#define ADT7316_AD_SINGLE_CH_IN 1
+#define ADT7316_AD_SINGLE_CH_EX 2
+#define ADT7516_AD_SINGLE_CH_AIN1 2
+#define ADT7516_AD_SINGLE_CH_AIN2 3
+#define ADT7516_AD_SINGLE_CH_AIN3 4
+#define ADT7516_AD_SINGLE_CH_AIN4 5
+#define ADT7316_AD_SINGLE_CH_MODE 0x10
+#define ADT7316_DISABLE_AVERAGING 0x20
+#define ADT7316_EN_SMBUS_TIMEOUT 0x40
+#define ADT7316_RESET 0x80
+
+/*
+ * ADT7316 config3
+ */
+#define ADT7316_ADCLK_22_5 0x1
+#define ADT7316_DA_HIGH_RESOLUTION 0x2
+#define ADT7316_DA_EN_VIA_DAC_LDCA 0x4
+#define ADT7516_AIN_IN_VREF 0x10
+#define ADT7316_EN_IN_TEMP_PROP_DACA 0x20
+#define ADT7316_EN_EX_TEMP_PROP_DACB 0x40
+
+/*
+ * ADT7316 DAC config
+ */
+#define ADT7316_DA_2VREF_CH_MASK 0xF
+#define ADT7316_DA_EN_MODE_MASK 0x30
+#define ADT7316_DA_EN_MODE_SINGLE 0x00
+#define ADT7316_DA_EN_MODE_AB_CD 0x10
+#define ADT7316_DA_EN_MODE_ABCD 0x20
+#define ADT7316_DA_EN_MODE_LDAC 0x30
+#define ADT7316_VREF_BYPASS_DAC_AB 0x40
+#define ADT7316_VREF_BYPASS_DAC_CD 0x80
+
+/*
+ * ADT7316 LDAC config
+ */
+#define ADT7316_LDAC_EN_DA_MASK 0xF
+#define ADT7316_DAC_IN_VREF 0x10
+#define ADT7516_DAC_AB_IN_VREF 0x10
+#define ADT7516_DAC_CD_IN_VREF 0x20
+#define ADT7516_DAC_IN_VREF_OFFSET 4
+#define ADT7516_DAC_IN_VREF_MASK 0x30
+
+/*
+ * ADT7316 INT_MASK2
+ */
+#define ADT7316_INT_MASK2_VDD 0x10
+
+/*
+ * ADT7316 value masks
+ */
+#define ADT7316_VALUE_MASK 0xfff
+#define ADT7316_T_VALUE_SIGN 0x400
+#define ADT7316_T_VALUE_FLOAT_OFFSET 2
+#define ADT7316_T_VALUE_FLOAT_MASK 0x2
+
+/*
+ * Chip ID
+ */
+#define ID_ADT7316 0x1
+#define ID_ADT7317 0x2
+#define ID_ADT7318 0x3
+#define ID_ADT7516 0x11
+#define ID_ADT7517 0x12
+#define ID_ADT7519 0x14
+
+#define ID_FAMILY_MASK 0xF0
+#define ID_ADT73XX 0x0
+#define ID_ADT75XX 0x10
+
+/*
+ * struct adt7316_chip_info - chip specifc information
+ */
+
+struct adt7316_chip_info {
+ const char *name;
+ struct iio_dev *indio_dev;
+ struct work_struct thresh_work;
+ s64 last_timestamp;
+ struct adt7316_bus bus;
+ u16 ldac_pin;
+ u16 int_mask; /* 0x2f */
+ u8 config1;
+ u8 config2;
+ u8 config3;
+ u8 dac_config; /* DAC config */
+ u8 ldac_config; /* LDAC config */
+ u8 dac_bits; /* 8, 10, 12 */
+ u8 id; /* chip id */
+};
+
+/*
+ * Logic interrupt mask for user application to enable
+ * interrupts.
+ */
+#define ADT7316_IN_TEMP_HIGH_INT_MASK 0x1
+#define ADT7316_IN_TEMP_LOW_INT_MASK 0x2
+#define ADT7316_EX_TEMP_HIGH_INT_MASK 0x4
+#define ADT7316_EX_TEMP_LOW_INT_MASK 0x8
+#define ADT7316_EX_TEMP_FAULT_INT_MASK 0x10
+#define ADT7516_AIN1_INT_MASK 0x4
+#define ADT7516_AIN2_INT_MASK 0x20
+#define ADT7516_AIN3_INT_MASK 0x40
+#define ADT7516_AIN4_INT_MASK 0x80
+#define ADT7316_VDD_INT_MASK 0x100
+#define ADT7316_TEMP_INT_MASK 0x1F
+#define ADT7516_AIN_INT_MASK 0xE0
+#define ADT7316_TEMP_AIN_INT_MASK \
+ (ADT7316_TEMP_INT_MASK | ADT7316_TEMP_INT_MASK)
+
+/*
+ * struct adt7316_chip_info - chip specifc information
+ */
+
+struct adt7316_limit_regs {
+ u16 data_high;
+ u16 data_low;
+};
+
+static ssize_t adt7316_show_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
+}
+
+static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
+ int enable)
+{
+ u8 config1;
+ int ret;
+
+ if (enable)
+ config1 = chip->config1 | ADT7316_EN;
+ else
+ config1 = chip->config1 & ~ADT7316_EN;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+ if (ret)
+ return -EIO;
+
+ chip->config1 = config1;
+
+ return ret;
+
+}
+
+static ssize_t adt7316_store_enabled(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ int enable;
+
+ if (!memcmp(buf, "1", 1))
+ enable = 1;
+ else
+ enable = 0;
+
+ if (_adt7316_store_enabled(chip, enable) < 0)
+ return -EIO;
+ else
+ return len;
+}
+
+static IIO_DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR,
+ adt7316_show_enabled,
+ adt7316_store_enabled,
+ 0);
+
+static ssize_t adt7316_show_select_ex_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+ return -EPERM;
+
+ return sprintf(buf, "%d\n", !!(chip->config1 & ADT7516_SEL_EX_TEMP));
+}
+
+static ssize_t adt7316_store_select_ex_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config1;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+ return -EPERM;
+
+ config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP);
+ if (!memcmp(buf, "1", 1))
+ config1 |= ADT7516_SEL_EX_TEMP;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+ if (ret)
+ return -EIO;
+
+ chip->config1 = config1;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(select_ex_temp, S_IRUGO | S_IWUSR,
+ adt7316_show_select_ex_temp,
+ adt7316_store_select_ex_temp,
+ 0);
+
+static ssize_t adt7316_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
+ return sprintf(buf, "single_channel\n");
+ else
+ return sprintf(buf, "round_robin\n");
+}
+
+static ssize_t adt7316_store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config2;
+ int ret;
+
+ config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MODE);
+ if (!memcmp(buf, "single_channel", 14))
+ config2 |= ADT7316_AD_SINGLE_CH_MODE;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+ if (ret)
+ return -EIO;
+
+ chip->config2 = config2;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ adt7316_show_mode,
+ adt7316_store_mode,
+ 0);
+
+static ssize_t adt7316_show_all_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "single_channel\nround_robin\n");
+}
+
+static IIO_DEVICE_ATTR(all_modes, S_IRUGO, adt7316_show_all_modes, NULL, 0);
+
+static ssize_t adt7316_show_ad_channel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+ return -EPERM;
+
+ switch (chip->config2 & ADT7516_AD_SINGLE_CH_MASK) {
+ case ADT7316_AD_SINGLE_CH_VDD:
+ return sprintf(buf, "0 - VDD\n");
+ case ADT7316_AD_SINGLE_CH_IN:
+ return sprintf(buf, "1 - Internal Temperature\n");
+ case ADT7316_AD_SINGLE_CH_EX:
+ if (((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) &&
+ (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
+ return sprintf(buf, "2 - AIN1\n");
+ else
+ return sprintf(buf, "2 - External Temperature\n");
+ case ADT7516_AD_SINGLE_CH_AIN2:
+ if ((chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
+ return sprintf(buf, "3 - AIN2\n");
+ else
+ return sprintf(buf, "N/A\n");
+ case ADT7516_AD_SINGLE_CH_AIN3:
+ if (chip->config1 & ADT7516_SEL_AIN3)
+ return sprintf(buf, "4 - AIN3\n");
+ else
+ return sprintf(buf, "N/A\n");
+ case ADT7516_AD_SINGLE_CH_AIN4:
+ return sprintf(buf, "5 - AIN4\n");
+ default:
+ return sprintf(buf, "N/A\n");
+ };
+}
+
+static ssize_t adt7316_store_ad_channel(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config2;
+ unsigned long data = 0;
+ int ret;
+
+ if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+ return -EPERM;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+ if (data > 5)
+ return -EINVAL;
+
+ config2 = chip->config2 & (~ADT7516_AD_SINGLE_CH_MASK);
+ } else {
+ if (data > 2)
+ return -EINVAL;
+
+ config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK);
+ }
+
+
+ config2 |= data;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+ if (ret)
+ return -EIO;
+
+ chip->config2 = config2;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(ad_channel, S_IRUGO | S_IWUSR,
+ adt7316_show_ad_channel,
+ adt7316_store_ad_channel,
+ 0);
+
+static ssize_t adt7316_show_all_ad_channels(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+ return -EPERM;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
+ "2 - External Temperature or AIN2\n"
+ "3 - AIN2\n4 - AIN3\n5 - AIN4\n");
+ else
+ return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
+ "2 - External Temperature\n");
+}
+
+static IIO_DEVICE_ATTR(all_ad_channels, S_IRUGO,
+ adt7316_show_all_ad_channels, NULL, 0);
+
+static ssize_t adt7316_show_disable_averaging(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->config2 & ADT7316_DISABLE_AVERAGING));
+}
+
+static ssize_t adt7316_store_disable_averaging(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config2;
+ int ret;
+
+ config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING);
+ if (!memcmp(buf, "1", 1))
+ config2 |= ADT7316_DISABLE_AVERAGING;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+ if (ret)
+ return -EIO;
+
+ chip->config2 = config2;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(disable_averaging, S_IRUGO | S_IWUSR,
+ adt7316_show_disable_averaging,
+ adt7316_store_disable_averaging,
+ 0);
+
+static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->config2 & ADT7316_EN_SMBUS_TIMEOUT));
+}
+
+static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config2;
+ int ret;
+
+ config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT);
+ if (!memcmp(buf, "1", 1))
+ config2 |= ADT7316_EN_SMBUS_TIMEOUT;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+ if (ret)
+ return -EIO;
+
+ chip->config2 = config2;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR,
+ adt7316_show_enable_smbus_timeout,
+ adt7316_store_enable_smbus_timeout,
+ 0);
+
+
+static ssize_t adt7316_store_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config2;
+ int ret;
+
+ config2 = chip->config2 | ADT7316_RESET;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+ NULL,
+ adt7316_store_reset,
+ 0);
+
+static ssize_t adt7316_show_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
+}
+
+static ssize_t adt7316_store_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config1;
+ int ret;
+
+ config1 = chip->config1 & (~ADT7316_PD);
+ if (!memcmp(buf, "1", 1))
+ config1 |= ADT7316_PD;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+ if (ret)
+ return -EIO;
+
+ chip->config1 = config1;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(powerdown, S_IRUGO | S_IWUSR,
+ adt7316_show_powerdown,
+ adt7316_store_powerdown,
+ 0);
+
+static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
+}
+
+static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config3;
+ int ret;
+
+ config3 = chip->config3 & (~ADT7316_ADCLK_22_5);
+ if (!memcmp(buf, "1", 1))
+ config3 |= ADT7316_ADCLK_22_5;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+ if (ret)
+ return -EIO;
+
+ chip->config3 = config3;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(fast_ad_clock, S_IRUGO | S_IWUSR,
+ adt7316_show_fast_ad_clock,
+ adt7316_store_fast_ad_clock,
+ 0);
+
+static ssize_t adt7316_show_da_high_resolution(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
+ if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
+ return sprintf(buf, "1 (12 bits)\n");
+ else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+ return sprintf(buf, "1 (10 bits)\n");
+ }
+
+ return sprintf(buf, "0 (8 bits)\n");
+}
+
+static ssize_t adt7316_store_da_high_resolution(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config3;
+ int ret;
+
+ chip->dac_bits = 8;
+
+ if (!memcmp(buf, "1", 1)) {
+ config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION;
+ if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
+ chip->dac_bits = 12;
+ else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+ chip->dac_bits = 10;
+ } else
+ config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+ if (ret)
+ return -EIO;
+
+ chip->config3 = config3;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(da_high_resolution, S_IRUGO | S_IWUSR,
+ adt7316_show_da_high_resolution,
+ adt7316_store_da_high_resolution,
+ 0);
+
+static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+ return -EPERM;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->config3 & ADT7516_AIN_IN_VREF));
+}
+
+static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config3;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+ return -EPERM;
+
+ if (memcmp(buf, "1", 1))
+ config3 = chip->config3 & (~ADT7516_AIN_IN_VREF);
+ else
+ config3 = chip->config3 | ADT7516_AIN_IN_VREF;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+ if (ret)
+ return -EIO;
+
+ chip->config3 = config3;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(AIN_internal_Vref, S_IRUGO | S_IWUSR,
+ adt7316_show_AIN_internal_Vref,
+ adt7316_store_AIN_internal_Vref,
+ 0);
+
+
+static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA));
+}
+
+static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config3;
+ int ret;
+
+ config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA);
+ if (!memcmp(buf, "1", 1))
+ config3 |= ADT7316_EN_IN_TEMP_PROP_DACA;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+ if (ret)
+ return -EIO;
+
+ chip->config3 = config3;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(enable_proportion_DACA, S_IRUGO | S_IWUSR,
+ adt7316_show_enable_prop_DACA,
+ adt7316_store_enable_prop_DACA,
+ 0);
+
+static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB));
+}
+
+static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config3;
+ int ret;
+
+ config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB);
+ if (!memcmp(buf, "1", 1))
+ config3 |= ADT7316_EN_EX_TEMP_PROP_DACB;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+ if (ret)
+ return -EIO;
+
+ chip->config3 = config3;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(enable_proportion_DACB, S_IRUGO | S_IWUSR,
+ adt7316_show_enable_prop_DACB,
+ adt7316_store_enable_prop_DACB,
+ 0);
+
+static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%x\n",
+ chip->dac_config & ADT7316_DA_2VREF_CH_MASK);
+}
+
+static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 dac_config;
+ unsigned long data = 0;
+ int ret;
+
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data > ADT7316_DA_2VREF_CH_MASK)
+ return -EINVAL;
+
+ dac_config = chip->dac_config & (~ADT7316_DA_2VREF_CH_MASK);
+ dac_config |= data;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+ if (ret)
+ return -EIO;
+
+ chip->dac_config = dac_config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, S_IRUGO | S_IWUSR,
+ adt7316_show_DAC_2Vref_ch_mask,
+ adt7316_store_DAC_2Vref_ch_mask,
+ 0);
+
+static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+ return sprintf(buf, "manual\n");
+ else {
+ switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
+ case ADT7316_DA_EN_MODE_SINGLE:
+ return sprintf(buf, "0 - auto at any MSB DAC writing\n");
+ case ADT7316_DA_EN_MODE_AB_CD:
+ return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n");
+ case ADT7316_DA_EN_MODE_ABCD:
+ return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n");
+ default: /* ADT7316_DA_EN_MODE_LDAC */
+ return sprintf(buf, "3 - manual\n");
+ };
+ }
+}
+
+static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 dac_config;
+ unsigned long data;
+ int ret;
+
+ if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+ return -EPERM;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret || data > ADT7316_DA_EN_MODE_MASK)
+ return -EINVAL;
+
+ dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK);
+ dac_config |= data;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+ if (ret)
+ return -EIO;
+
+ chip->dac_config = dac_config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_update_mode, S_IRUGO | S_IWUSR,
+ adt7316_show_DAC_update_mode,
+ adt7316_store_DAC_update_mode,
+ 0);
+
+static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
+ return sprintf(buf, "0 - auto at any MSB DAC writing\n"
+ "1 - auto at MSB DAC AB and CD writing\n"
+ "2 - auto at MSB DAC ABCD writing\n"
+ "3 - manual\n");
+ else
+ return sprintf(buf, "manual\n");
+}
+
+static IIO_DEVICE_ATTR(all_DAC_update_modes, S_IRUGO,
+ adt7316_show_all_DAC_update_modes, NULL, 0);
+
+
+static ssize_t adt7316_store_update_DAC(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 ldac_config;
+ unsigned long data;
+ int ret;
+
+ if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) {
+ if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) !=
+ ADT7316_DA_EN_MODE_LDAC)
+ return -EPERM;
+
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data > ADT7316_LDAC_EN_DA_MASK)
+ return -EINVAL;
+
+ ldac_config = chip->ldac_config & (~ADT7316_LDAC_EN_DA_MASK);
+ ldac_config |= data;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG,
+ ldac_config);
+ if (ret)
+ return -EIO;
+ } else {
+ gpio_set_value(chip->ldac_pin, 0);
+ gpio_set_value(chip->ldac_pin, 1);
+ }
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(update_DAC, S_IRUGO | S_IWUSR,
+ NULL,
+ adt7316_store_update_DAC,
+ 0);
+
+static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return -EPERM;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB));
+}
+
+static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 dac_config;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return -EPERM;
+
+ dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
+ if (!memcmp(buf, "1", 1))
+ dac_config |= ADT7316_VREF_BYPASS_DAC_AB;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+ if (ret)
+ return -EIO;
+
+ chip->dac_config = dac_config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, S_IRUGO | S_IWUSR,
+ adt7316_show_DA_AB_Vref_bypass,
+ adt7316_store_DA_AB_Vref_bypass,
+ 0);
+
+static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return -EPERM;
+
+ return sprintf(buf, "%d\n",
+ !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD));
+}
+
+static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 dac_config;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return -EPERM;
+
+ dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
+ if (!memcmp(buf, "1", 1))
+ dac_config |= ADT7316_VREF_BYPASS_DAC_CD;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+ if (ret)
+ return -EIO;
+
+ chip->dac_config = dac_config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, S_IRUGO | S_IWUSR,
+ adt7316_show_DA_CD_Vref_bypass,
+ adt7316_store_DA_CD_Vref_bypass,
+ 0);
+
+static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return sprintf(buf, "0x%x\n",
+ (chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >>
+ ADT7516_DAC_IN_VREF_OFFSET);
+ else
+ return sprintf(buf, "%d\n",
+ !!(chip->dac_config & ADT7316_DAC_IN_VREF));
+}
+
+static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 ldac_config;
+ unsigned long data;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data > 3)
+ return -EINVAL;
+
+ ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK);
+ if (data & 0x1)
+ ldac_config |= ADT7516_DAC_AB_IN_VREF;
+ else if (data & 0x2)
+ ldac_config |= ADT7516_DAC_CD_IN_VREF;
+ } else {
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret)
+ return -EINVAL;
+
+ ldac_config = chip->ldac_config & (~ADT7316_DAC_IN_VREF);
+ if (data)
+ ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF;
+ }
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, ldac_config);
+ if (ret)
+ return -EIO;
+
+ chip->ldac_config = ldac_config;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_internal_Vref, S_IRUGO | S_IWUSR,
+ adt7316_show_DAC_internal_Vref,
+ adt7316_store_DAC_internal_Vref,
+ 0);
+
+static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
+ int channel, char *buf)
+{
+ u16 data;
+ u8 msb, lsb;
+ char sign = ' ';
+ int ret;
+
+ if ((chip->config2 & ADT7316_AD_SINGLE_CH_MODE) &&
+ channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK))
+ return -EPERM;
+
+ switch (channel) {
+ case ADT7316_AD_SINGLE_CH_IN:
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_LSB_IN_TEMP_VDD, &lsb);
+ if (ret)
+ return -EIO;
+
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+ if (ret)
+ return -EIO;
+
+ data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+ data |= lsb & ADT7316_LSB_IN_TEMP_MASK;
+ break;
+ case ADT7316_AD_SINGLE_CH_VDD:
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_LSB_IN_TEMP_VDD, &lsb);
+ if (ret)
+ return -EIO;
+
+ ret = chip->bus.read(chip->bus.client,
+
+ ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+ if (ret)
+ return -EIO;
+
+ data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+ data |= (lsb & ADT7316_LSB_VDD_MASK) >> ADT7316_LSB_VDD_OFFSET;
+ return sprintf(buf, "%d\n", data);
+ default: /* ex_temp and ain */
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_LSB_EX_TEMP_AIN, &lsb);
+ if (ret)
+ return -EIO;
+
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+ if (ret)
+ return -EIO;
+
+ data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+ data |= lsb & (ADT7316_LSB_EX_TEMP_MASK <<
+ (ADT7516_LSB_AIN_SHIFT * (channel -
+ (ADT7316_MSB_EX_TEMP - ADT7316_AD_MSB_DATA_BASE))));
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ return sprintf(buf, "%d\n", data);
+ else
+ break;
+ };
+
+ if (data & ADT7316_T_VALUE_SIGN) {
+ /* convert supplement to positive value */
+ data = (ADT7316_T_VALUE_SIGN << 1) - data;
+ sign = '-';
+ }
+
+ return sprintf(buf, "%c%d.%.2d\n", sign,
+ (data >> ADT7316_T_VALUE_FLOAT_OFFSET),
+ (data & ADT7316_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static ssize_t adt7316_show_VDD(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
+}
+static IIO_DEVICE_ATTR(VDD, S_IRUGO, adt7316_show_VDD, NULL, 0);
+
+static ssize_t adt7316_show_in_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
+}
+
+static IIO_DEVICE_ATTR(in_temp, S_IRUGO, adt7316_show_in_temp, NULL, 0);
+
+static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
+}
+
+static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
+static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
+
+static ssize_t adt7316_show_AIN2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
+}
+static IIO_DEVICE_ATTR(AIN2, S_IRUGO, adt7316_show_AIN2, NULL, 0);
+
+static ssize_t adt7316_show_AIN3(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
+}
+static IIO_DEVICE_ATTR(AIN3, S_IRUGO, adt7316_show_AIN3, NULL, 0);
+
+static ssize_t adt7316_show_AIN4(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
+}
+static IIO_DEVICE_ATTR(AIN4, S_IRUGO, adt7316_show_AIN4, NULL, 0);
+
+static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip,
+ int offset_addr, char *buf)
+{
+ int data;
+ u8 val;
+ int ret;
+
+ ret = chip->bus.read(chip->bus.client, offset_addr, &val);
+ if (ret)
+ return -EIO;
+
+ data = (int)val;
+ if (val & 0x80)
+ data -= 256;
+
+ return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip,
+ int offset_addr, const char *buf, size_t len)
+{
+ long data;
+ u8 val;
+ int ret;
+
+ ret = strict_strtol(buf, 10, &data);
+ if (ret || data > 127 || data < -128)
+ return -EINVAL;
+
+ if (data < 0)
+ data += 256;
+
+ val = (u8)data;
+
+ ret = chip->bus.write(chip->bus.client, offset_addr, val);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static ssize_t adt7316_show_in_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_in_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR,
+ adt7316_show_in_temp_offset,
+ adt7316_store_in_temp_offset, 0);
+
+static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR,
+ adt7316_show_ex_temp_offset,
+ adt7316_store_ex_temp_offset, 0);
+
+static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_temp_offset(chip,
+ ADT7316_IN_ANALOG_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_temp_offset(chip,
+ ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(in_analog_temp_offset, S_IRUGO | S_IWUSR,
+ adt7316_show_in_analog_temp_offset,
+ adt7316_store_in_analog_temp_offset, 0);
+
+static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_temp_offset(chip,
+ ADT7316_EX_ANALOG_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_temp_offset(chip,
+ ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(ex_analog_temp_offset, S_IRUGO | S_IWUSR,
+ adt7316_show_ex_analog_temp_offset,
+ adt7316_store_ex_analog_temp_offset, 0);
+
+static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
+ int channel, char *buf)
+{
+ u16 data;
+ u8 msb, lsb, offset;
+ int ret;
+
+ if (channel >= ADT7316_DA_MSB_DATA_REGS ||
+ (channel == 0 &&
+ (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+ (channel == 1 &&
+ (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+ return -EPERM;
+
+ offset = chip->dac_bits - 8;
+
+ if (chip->dac_bits > 8) {
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_DA_DATA_BASE + channel * 2, &lsb);
+ if (ret)
+ return -EIO;
+ }
+
+ ret = chip->bus.read(chip->bus.client,
+ ADT7316_DA_DATA_BASE + 1 + channel * 2, &msb);
+ if (ret)
+ return -EIO;
+
+ data = (msb << offset) + (lsb & ((1 << offset) - 1));
+
+ return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
+ int channel, const char *buf, size_t len)
+{
+ u8 msb, lsb, offset;
+ unsigned long data;
+ int ret;
+
+ if (channel >= ADT7316_DA_MSB_DATA_REGS ||
+ (channel == 0 &&
+ (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+ (channel == 1 &&
+ (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+ return -EPERM;
+
+ offset = chip->dac_bits - 8;
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret || data >= (1 << chip->dac_bits))
+ return -EINVAL;
+
+ if (chip->dac_bits > 8) {
+ lsb = data & (1 << offset);
+ ret = chip->bus.write(chip->bus.client,
+ ADT7316_DA_DATA_BASE + channel * 2, lsb);
+ if (ret)
+ return -EIO;
+ }
+
+ msb = data >> offset;
+ ret = chip->bus.write(chip->bus.client,
+ ADT7316_DA_DATA_BASE + 1 + channel * 2, msb);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static ssize_t adt7316_show_DAC_A(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_DAC(chip, 0, buf);
+}
+
+static ssize_t adt7316_store_DAC_A(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_DAC(chip, 0, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_A, S_IRUGO | S_IWUSR, adt7316_show_DAC_A,
+ adt7316_store_DAC_A, 0);
+
+static ssize_t adt7316_show_DAC_B(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_DAC(chip, 1, buf);
+}
+
+static ssize_t adt7316_store_DAC_B(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_DAC(chip, 1, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_B, S_IRUGO | S_IWUSR, adt7316_show_DAC_B,
+ adt7316_store_DAC_B, 0);
+
+static ssize_t adt7316_show_DAC_C(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_DAC(chip, 2, buf);
+}
+
+static ssize_t adt7316_store_DAC_C(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_DAC(chip, 2, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_C, S_IRUGO | S_IWUSR, adt7316_show_DAC_C,
+ adt7316_store_DAC_C, 0);
+
+static ssize_t adt7316_show_DAC_D(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_show_DAC(chip, 3, buf);
+}
+
+static ssize_t adt7316_store_DAC_D(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return adt7316_store_DAC(chip, 3, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_D, S_IRUGO | S_IWUSR, adt7316_show_DAC_D,
+ adt7316_store_DAC_D, 0);
+
+static ssize_t adt7316_show_device_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 id;
+ int ret;
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_ID, &id);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", id);
+}
+
+static IIO_DEVICE_ATTR(device_id, S_IRUGO, adt7316_show_device_id, NULL, 0);
+
+static ssize_t adt7316_show_manufactorer_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 id;
+ int ret;
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_MANUFACTURE_ID, &id);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", id);
+}
+
+static IIO_DEVICE_ATTR(manufactorer_id, S_IRUGO,
+ adt7316_show_manufactorer_id, NULL, 0);
+
+static ssize_t adt7316_show_device_rev(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 rev;
+ int ret;
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_REV, &rev);
+ if (ret)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", rev);
+}
+
+static IIO_DEVICE_ATTR(device_rev, S_IRUGO, adt7316_show_device_rev, NULL, 0);
+
+static ssize_t adt7316_show_bus_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 stat;
+ int ret;
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_SPI_LOCK_STAT, &stat);
+ if (ret)
+ return -EIO;
+
+ if (stat)
+ return sprintf(buf, "spi\n");
+ else
+ return sprintf(buf, "i2c\n");
+}
+
+static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0);
+
+static ssize_t adt7316_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7316_show_name, NULL, 0);
+
+static struct attribute *adt7316_attributes[] = {
+ &iio_dev_attr_all_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_dev_attr_enabled.dev_attr.attr,
+ &iio_dev_attr_ad_channel.dev_attr.attr,
+ &iio_dev_attr_all_ad_channels.dev_attr.attr,
+ &iio_dev_attr_disable_averaging.dev_attr.attr,
+ &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
+ &iio_dev_attr_powerdown.dev_attr.attr,
+ &iio_dev_attr_fast_ad_clock.dev_attr.attr,
+ &iio_dev_attr_da_high_resolution.dev_attr.attr,
+ &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
+ &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
+ &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
+ &iio_dev_attr_DAC_update_mode.dev_attr.attr,
+ &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
+ &iio_dev_attr_update_DAC.dev_attr.attr,
+ &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
+ &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
+ &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
+ &iio_dev_attr_VDD.dev_attr.attr,
+ &iio_dev_attr_in_temp.dev_attr.attr,
+ &iio_dev_attr_ex_temp.dev_attr.attr,
+ &iio_dev_attr_in_temp_offset.dev_attr.attr,
+ &iio_dev_attr_ex_temp_offset.dev_attr.attr,
+ &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
+ &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
+ &iio_dev_attr_DAC_A.dev_attr.attr,
+ &iio_dev_attr_DAC_B.dev_attr.attr,
+ &iio_dev_attr_DAC_C.dev_attr.attr,
+ &iio_dev_attr_DAC_D.dev_attr.attr,
+ &iio_dev_attr_device_id.dev_attr.attr,
+ &iio_dev_attr_manufactorer_id.dev_attr.attr,
+ &iio_dev_attr_device_rev.dev_attr.attr,
+ &iio_dev_attr_bus_type.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adt7316_attribute_group = {
+ .attrs = adt7316_attributes,
+};
+
+static struct attribute *adt7516_attributes[] = {
+ &iio_dev_attr_all_modes.dev_attr.attr,
+ &iio_dev_attr_mode.dev_attr.attr,
+ &iio_dev_attr_select_ex_temp.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_dev_attr_enabled.dev_attr.attr,
+ &iio_dev_attr_ad_channel.dev_attr.attr,
+ &iio_dev_attr_all_ad_channels.dev_attr.attr,
+ &iio_dev_attr_disable_averaging.dev_attr.attr,
+ &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
+ &iio_dev_attr_powerdown.dev_attr.attr,
+ &iio_dev_attr_fast_ad_clock.dev_attr.attr,
+ &iio_dev_attr_AIN_internal_Vref.dev_attr.attr,
+ &iio_dev_attr_da_high_resolution.dev_attr.attr,
+ &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
+ &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
+ &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
+ &iio_dev_attr_DAC_update_mode.dev_attr.attr,
+ &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
+ &iio_dev_attr_update_DAC.dev_attr.attr,
+ &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
+ &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
+ &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
+ &iio_dev_attr_VDD.dev_attr.attr,
+ &iio_dev_attr_in_temp.dev_attr.attr,
+ &iio_dev_attr_ex_temp_AIN1.dev_attr.attr,
+ &iio_dev_attr_AIN2.dev_attr.attr,
+ &iio_dev_attr_AIN3.dev_attr.attr,
+ &iio_dev_attr_AIN4.dev_attr.attr,
+ &iio_dev_attr_in_temp_offset.dev_attr.attr,
+ &iio_dev_attr_ex_temp_offset.dev_attr.attr,
+ &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
+ &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
+ &iio_dev_attr_DAC_A.dev_attr.attr,
+ &iio_dev_attr_DAC_B.dev_attr.attr,
+ &iio_dev_attr_DAC_C.dev_attr.attr,
+ &iio_dev_attr_DAC_D.dev_attr.attr,
+ &iio_dev_attr_device_id.dev_attr.attr,
+ &iio_dev_attr_manufactorer_id.dev_attr.attr,
+ &iio_dev_attr_device_rev.dev_attr.attr,
+ &iio_dev_attr_bus_type.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adt7516_attribute_group = {
+ .attrs = adt7516_attributes,
+};
+
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7316_IN_TEMP_LOW IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_HIGH IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_LOW IIO_BUFFER_EVENT_CODE(3)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_FAULT IIO_BUFFER_EVENT_CODE(4)
+#define IIO_EVENT_CODE_ADT7516_AIN1 IIO_BUFFER_EVENT_CODE(5)
+#define IIO_EVENT_CODE_ADT7516_AIN2 IIO_BUFFER_EVENT_CODE(6)
+#define IIO_EVENT_CODE_ADT7516_AIN3 IIO_BUFFER_EVENT_CODE(7)
+#define IIO_EVENT_CODE_ADT7516_AIN4 IIO_BUFFER_EVENT_CODE(8)
+#define IIO_EVENT_CODE_ADT7316_VDD IIO_BUFFER_EVENT_CODE(9)
+
+static void adt7316_interrupt_bh(struct work_struct *work_s)
+{
+ struct adt7316_chip_info *chip =
+ container_of(work_s, struct adt7316_chip_info, thresh_work);
+ u8 stat1, stat2;
+ int i, ret, count;
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT1, &stat1);
+ if (!ret) {
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ count = 8;
+ else
+ count = 5;
+
+ for (i = 0; i < count; i++) {
+ if (stat1 & (1 << i))
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH + i,
+ chip->last_timestamp);
+ }
+ }
+
+ ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT2, &stat2);
+ if (!ret) {
+ if (stat2 & ADT7316_INT_MASK2_VDD)
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_ADT7316_VDD,
+ chip->last_timestamp);
+ }
+
+ enable_irq(chip->bus.irq);
+}
+
+static int adt7316_interrupt(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ chip->last_timestamp = timestamp;
+ schedule_work(&chip->thresh_work);
+
+ return 0;
+}
+
+IIO_EVENT_SH(adt7316, &adt7316_interrupt);
+
+/*
+ * Show mask of enabled interrupts in Hex.
+ */
+static ssize_t adt7316_show_int_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "0x%x\n", chip->int_mask);
+}
+
+/*
+ * Set 1 to the mask in Hex to enabled interrupts.
+ */
+static ssize_t adt7316_set_int_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ unsigned long data;
+ int ret;
+ u8 mask;
+
+ ret = strict_strtoul(buf, 16, &data);
+ if (ret || data >= ADT7316_VDD_INT_MASK + 1)
+ return -EINVAL;
+
+ if (data & ADT7316_VDD_INT_MASK)
+ mask = 0; /* enable vdd int */
+ else
+ mask = ADT7316_INT_MASK2_VDD; /* disable vdd int */
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK2, mask);
+ if (!ret) {
+ chip->int_mask &= ~ADT7316_VDD_INT_MASK;
+ chip->int_mask |= data & ADT7316_VDD_INT_MASK;
+ }
+
+ if (data & ADT7316_TEMP_AIN_INT_MASK) {
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX)
+ /* mask in reg is opposite, set 1 to disable */
+ mask = (~data) & ADT7316_TEMP_INT_MASK;
+ else
+ /* mask in reg is opposite, set 1 to disable */
+ mask = (~data) & ADT7316_TEMP_AIN_INT_MASK;
+ }
+ ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK1, mask);
+
+ chip->int_mask = mask;
+
+ return len;
+}
+static inline ssize_t adt7316_show_ad_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 val;
+ int data;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
+ bound_reg > ADT7316_EX_TEMP_LOW)
+ return -EPERM;
+
+ ret = chip->bus.read(chip->bus.client, bound_reg, &val);
+ if (ret)
+ return -EIO;
+
+ data = (int)val;
+
+ if (!((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
+ (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) {
+ if (data & 0x80)
+ data -= 256;
+ }
+
+ return sprintf(buf, "%d\n", data);
+}
+
+static inline ssize_t adt7316_set_ad_bound(struct device *dev,
+ struct device_attribute *attr,
+ u8 bound_reg,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ long data;
+ u8 val;
+ int ret;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
+ bound_reg > ADT7316_EX_TEMP_LOW)
+ return -EPERM;
+
+ ret = strict_strtol(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
+ (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) {
+ if (data > 255 || data < 0)
+ return -EINVAL;
+ } else {
+ if (data > 127 || data < -128)
+ return -EINVAL;
+
+ if (data < 0)
+ data += 256;
+ }
+
+ val = (u8)data;
+
+ ret = chip->bus.write(chip->bus.client, bound_reg, val);
+ if (ret)
+ return -EIO;
+
+ return len;
+}
+
+static ssize_t adt7316_show_in_temp_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7316_IN_TEMP_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_in_temp_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7316_IN_TEMP_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_in_temp_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7316_IN_TEMP_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_in_temp_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7316_IN_TEMP_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ex_temp_ain1_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7316_EX_TEMP_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ex_temp_ain1_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7316_EX_TEMP_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ex_temp_ain1_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7316_EX_TEMP_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ex_temp_ain1_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7316_EX_TEMP_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain2_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN2_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain2_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN2_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain2_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN2_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain2_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN2_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain3_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN3_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain3_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN3_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain3_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN3_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain3_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN3_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain4_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN4_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain4_high(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN4_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain4_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return adt7316_show_ad_bound(dev, attr,
+ ADT7516_AIN4_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain4_low(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return adt7316_set_ad_bound(dev, attr,
+ ADT7516_AIN4_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_int_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
+}
+
+static ssize_t adt7316_set_int_enabled(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ u8 config1;
+ int ret;
+
+ config1 = chip->config1 & (~ADT7316_INT_EN);
+ if (!memcmp(buf, "1", 1))
+ config1 |= ADT7316_INT_EN;
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+ if (ret)
+ return -EIO;
+
+ chip->config1 = config1;
+
+ return len;
+}
+
+
+IIO_EVENT_ATTR_SH(int_mask, iio_event_adt7316,
+ adt7316_show_int_mask, adt7316_set_int_mask, 0);
+IIO_EVENT_ATTR_SH(in_temp_high, iio_event_adt7316,
+ adt7316_show_in_temp_high, adt7316_set_in_temp_high, 0);
+IIO_EVENT_ATTR_SH(in_temp_low, iio_event_adt7316,
+ adt7316_show_in_temp_low, adt7316_set_in_temp_low, 0);
+IIO_EVENT_ATTR_SH(ex_temp_high, iio_event_adt7316,
+ adt7316_show_ex_temp_ain1_high,
+ adt7316_set_ex_temp_ain1_high, 0);
+IIO_EVENT_ATTR_SH(ex_temp_low, iio_event_adt7316,
+ adt7316_show_ex_temp_ain1_low,
+ adt7316_set_ex_temp_ain1_low, 0);
+IIO_EVENT_ATTR_SH(ex_temp_ain1_high, iio_event_adt7316,
+ adt7316_show_ex_temp_ain1_high,
+ adt7316_set_ex_temp_ain1_high, 0);
+IIO_EVENT_ATTR_SH(ex_temp_ain1_low, iio_event_adt7316,
+ adt7316_show_ex_temp_ain1_low,
+ adt7316_set_ex_temp_ain1_low, 0);
+IIO_EVENT_ATTR_SH(ain2_high, iio_event_adt7316,
+ adt7316_show_ain2_high, adt7316_set_ain2_high, 0);
+IIO_EVENT_ATTR_SH(ain2_low, iio_event_adt7316,
+ adt7316_show_ain2_low, adt7316_set_ain2_low, 0);
+IIO_EVENT_ATTR_SH(ain3_high, iio_event_adt7316,
+ adt7316_show_ain3_high, adt7316_set_ain3_high, 0);
+IIO_EVENT_ATTR_SH(ain3_low, iio_event_adt7316,
+ adt7316_show_ain3_low, adt7316_set_ain3_low, 0);
+IIO_EVENT_ATTR_SH(ain4_high, iio_event_adt7316,
+ adt7316_show_ain4_high, adt7316_set_ain4_high, 0);
+IIO_EVENT_ATTR_SH(ain4_low, iio_event_adt7316,
+ adt7316_show_ain4_low, adt7316_set_ain4_low, 0);
+IIO_EVENT_ATTR_SH(int_enabled, iio_event_adt7316,
+ adt7316_show_int_enabled, adt7316_set_int_enabled, 0);
+
+static struct attribute *adt7316_event_attributes[] = {
+ &iio_event_attr_int_mask.dev_attr.attr,
+ &iio_event_attr_in_temp_high.dev_attr.attr,
+ &iio_event_attr_in_temp_low.dev_attr.attr,
+ &iio_event_attr_ex_temp_high.dev_attr.attr,
+ &iio_event_attr_ex_temp_low.dev_attr.attr,
+ &iio_event_attr_int_enabled.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adt7316_event_attribute_group = {
+ .attrs = adt7316_event_attributes,
+};
+
+static struct attribute *adt7516_event_attributes[] = {
+ &iio_event_attr_int_mask.dev_attr.attr,
+ &iio_event_attr_in_temp_high.dev_attr.attr,
+ &iio_event_attr_in_temp_low.dev_attr.attr,
+ &iio_event_attr_ex_temp_ain1_high.dev_attr.attr,
+ &iio_event_attr_ex_temp_ain1_low.dev_attr.attr,
+ &iio_event_attr_ain2_high.dev_attr.attr,
+ &iio_event_attr_ain2_low.dev_attr.attr,
+ &iio_event_attr_ain3_high.dev_attr.attr,
+ &iio_event_attr_ain3_low.dev_attr.attr,
+ &iio_event_attr_ain4_high.dev_attr.attr,
+ &iio_event_attr_ain4_low.dev_attr.attr,
+ &iio_event_attr_int_enabled.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group adt7516_event_attribute_group = {
+ .attrs = adt7516_event_attributes,
+};
+
+#ifdef CONFIG_PM
+int adt7316_disable(struct device *dev)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return _adt7316_store_enabled(chip, 0);
+}
+EXPORT_SYMBOL(adt7316_disable);
+
+int adt7316_enable(struct device *dev)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+
+ return _adt7316_store_enabled(chip, 1);
+}
+EXPORT_SYMBOL(adt7316_enable);
+#endif
+
+/*
+ * device probe and remove
+ */
+int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
+ const char *name)
+{
+ struct adt7316_chip_info *chip;
+ unsigned short *adt7316_platform_data = dev->platform_data;
+ int ret = 0;
+
+ chip = kzalloc(sizeof(struct adt7316_chip_info), GFP_KERNEL);
+
+ if (chip == NULL)
+ return -ENOMEM;
+
+ /* this is only used for device removal purposes */
+ dev_set_drvdata(dev, chip);
+
+ chip->bus = *bus;
+ chip->name = name;
+
+ if (name[4] == '3')
+ chip->id = ID_ADT7316 + (name[6] - '6');
+ else if (name[4] == '5')
+ chip->id = ID_ADT7516 + (name[6] - '6');
+ else
+ return -ENODEV;
+
+ chip->ldac_pin = adt7316_platform_data[1];
+ if (chip->ldac_pin) {
+ chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ chip->config1 |= ADT7516_SEL_AIN3;
+ }
+ chip->int_mask = ADT7316_TEMP_INT_MASK | ADT7316_VDD_INT_MASK;
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+ chip->int_mask |= ADT7516_AIN_INT_MASK;
+
+ chip->indio_dev = iio_allocate_device();
+ if (chip->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_chip;
+ }
+
+ chip->indio_dev->dev.parent = dev;
+ if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+ chip->indio_dev->attrs = &adt7516_attribute_group;
+ chip->indio_dev->event_attrs = &adt7516_event_attribute_group;
+ } else {
+ chip->indio_dev->attrs = &adt7316_attribute_group;
+ chip->indio_dev->event_attrs = &adt7316_event_attribute_group;
+ }
+ chip->indio_dev->dev_data = (void *)chip;
+ chip->indio_dev->driver_module = THIS_MODULE;
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(chip->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ if (chip->bus.irq > 0) {
+ if (adt7316_platform_data[0])
+ chip->bus.irq_flags = adt7316_platform_data[0];
+
+ ret = iio_register_interrupt_line(chip->bus.irq,
+ chip->indio_dev,
+ 0,
+ chip->bus.irq_flags,
+ chip->name);
+ if (ret)
+ goto error_unreg_dev;
+
+ /*
+ * The event handler list element refer to iio_event_adt7316.
+ * All event attributes bind to the same event handler.
+ * So, only register event handler once.
+ */
+ iio_add_event_to_list(&iio_event_adt7316,
+ &chip->indio_dev->interrupts[0]->ev_list);
+
+ INIT_WORK(&chip->thresh_work, adt7316_interrupt_bh);
+
+ if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH)
+ chip->config1 |= ADT7316_INT_POLARITY;
+ }
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_irq;
+ }
+
+ ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3);
+ if (ret) {
+ ret = -EIO;
+ goto error_unreg_irq;
+ }
+
+ dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n",
+ chip->name);
+
+ return 0;
+
+error_unreg_irq:
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+ iio_device_unregister(chip->indio_dev);
+error_free_dev:
+ iio_free_device(chip->indio_dev);
+error_free_chip:
+ kfree(chip);
+
+ return ret;
+}
+EXPORT_SYMBOL(adt7316_probe);
+
+int __devexit adt7316_remove(struct device *dev)
+{
+
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct adt7316_chip_info *chip = dev_info->dev_data;
+ struct iio_dev *indio_dev = chip->indio_dev;
+
+ dev_set_drvdata(dev, NULL);
+ if (chip->bus.irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+ iio_device_unregister(indio_dev);
+ iio_free_device(chip->indio_dev);
+ kfree(chip);
+
+ return 0;
+}
+EXPORT_SYMBOL(adt7316_remove);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7316/7/8 and ADT7516/7/9 digital"
+ " temperature sensor, ADC and DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h
new file mode 100644
index 000000000000..d34bd679bb4e
--- /dev/null
+++ b/drivers/staging/iio/addac/adt7316.h
@@ -0,0 +1,33 @@
+/*
+ * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADT7316_H_
+#define _ADT7316_H_
+
+#include <linux/types.h>
+
+#define ADT7316_REG_MAX_ADDR 0x3F
+
+struct adt7316_bus {
+ void *client;
+ int irq;
+ int irq_flags;
+ int (*read) (void *client, u8 reg, u8 *data);
+ int (*write) (void *client, u8 reg, u8 val);
+ int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data);
+ int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
+};
+
+#ifdef CONFIG_PM
+int adt7316_disable(struct device *dev);
+int adt7316_enable(struct device *dev);
+#endif
+int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name);
+int adt7316_remove(struct device *dev);
+
+#endif
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
new file mode 100644
index 000000000000..9191bd23cc08
--- /dev/null
+++ b/drivers/staging/iio/dac/Kconfig
@@ -0,0 +1,21 @@
+#
+# DAC drivers
+#
+comment "Digital to analog convertors"
+
+config AD5624R_SPI
+ tristate "Analog Devices AD5624/44/64R DAC spi driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD5624R, AD5644R and
+ AD5664R convertors (DAC). This driver uses the common SPI interface.
+
+config AD5446
+ tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5541A/12A DAC SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD5444, AD5446,
+ AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5446.
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile
new file mode 100644
index 000000000000..7cf331b4e001
--- /dev/null
+++ b/drivers/staging/iio/dac/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O DAC drivers
+#
+
+obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
+obj-$(CONFIG_AD5446) += ad5446.o
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
new file mode 100644
index 000000000000..e3387cd31145
--- /dev/null
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -0,0 +1,323 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "dac.h"
+
+#include "ad5446.h"
+
+static void ad5446_store_sample(struct ad5446_state *st, unsigned val)
+{
+ st->data.d16 = cpu_to_be16(AD5446_LOAD |
+ (val << st->chip_info->left_shift));
+}
+
+static void ad5542_store_sample(struct ad5446_state *st, unsigned val)
+{
+ st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift);
+}
+
+static void ad5620_store_sample(struct ad5446_state *st, unsigned val)
+{
+ st->data.d16 = cpu_to_be16(AD5620_LOAD |
+ (val << st->chip_info->left_shift));
+}
+
+static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
+{
+ val |= AD5660_LOAD;
+ st->data.d24[0] = (val >> 16) & 0xFF;
+ st->data.d24[1] = (val >> 8) & 0xFF;
+ st->data.d24[2] = val & 0xFF;
+}
+
+static ssize_t ad5446_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+
+ if (val > RES_MASK(st->chip_info->bits)) {
+ ret = -EINVAL;
+ goto error_ret;
+ }
+
+ mutex_lock(&dev_info->mlock);
+ st->chip_info->store_sample(st, val);
+ ret = spi_sync(st->spi, &st->msg);
+ mutex_unlock(&dev_info->mlock);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0);
+
+static ssize_t ad5446_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
+
+ return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0);
+
+static ssize_t ad5446_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0);
+
+static struct attribute *ad5446_attributes[] = {
+ &iio_dev_attr_out0_raw.dev_attr.attr,
+ &iio_dev_attr_out_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad5446_attribute_group = {
+ .attrs = ad5446_attributes,
+};
+
+static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
+ [ID_AD5444] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 2,
+ .store_sample = ad5446_store_sample,
+ },
+ [ID_AD5446] = {
+ .bits = 14,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5446_store_sample,
+ },
+ [ID_AD5542A] = {
+ .bits = 16,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5542_store_sample,
+ },
+ [ID_AD5512A] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 4,
+ .store_sample = ad5542_store_sample,
+ },
+ [ID_AD5620_2500] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 2,
+ .int_vref_mv = 2500,
+ .store_sample = ad5620_store_sample,
+ },
+ [ID_AD5620_1250] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 2,
+ .int_vref_mv = 1250,
+ .store_sample = ad5620_store_sample,
+ },
+ [ID_AD5640_2500] = {
+ .bits = 14,
+ .storagebits = 16,
+ .left_shift = 0,
+ .int_vref_mv = 2500,
+ .store_sample = ad5620_store_sample,
+ },
+ [ID_AD5640_1250] = {
+ .bits = 14,
+ .storagebits = 16,
+ .left_shift = 0,
+ .int_vref_mv = 1250,
+ .store_sample = ad5620_store_sample,
+ },
+ [ID_AD5660_2500] = {
+ .bits = 16,
+ .storagebits = 24,
+ .left_shift = 0,
+ .int_vref_mv = 2500,
+ .store_sample = ad5660_store_sample,
+ },
+ [ID_AD5660_1250] = {
+ .bits = 16,
+ .storagebits = 24,
+ .left_shift = 0,
+ .int_vref_mv = 1250,
+ .store_sample = ad5660_store_sample,
+ },
+};
+
+static int __devinit ad5446_probe(struct spi_device *spi)
+{
+ struct ad5446_state *st;
+ int ret, voltage_uv = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ voltage_uv = regulator_get_voltage(st->reg);
+ }
+
+ st->chip_info =
+ &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ spi_set_drvdata(spi, st);
+
+ st->spi = spi;
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ /* Estabilish that the iio_dev is a child of the spi device */
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad5446_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default message */
+
+ st->xfer.tx_buf = &st->data;
+ st->xfer.len = st->chip_info->storagebits / 8;
+
+ spi_message_init(&st->msg);
+ spi_message_add_tail(&st->xfer, &st->msg);
+
+ switch (spi_get_device_id(spi)->driver_data) {
+ case ID_AD5620_2500:
+ case ID_AD5620_1250:
+ case ID_AD5640_2500:
+ case ID_AD5640_1250:
+ case ID_AD5660_2500:
+ case ID_AD5660_1250:
+ st->vref_mv = st->chip_info->int_vref_mv;
+ break;
+ default:
+ if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev,
+ "reference voltage unspecified\n");
+ }
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
+ return 0;
+
+error_free_device:
+ iio_free_device(st->indio_dev);
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int ad5446_remove(struct spi_device *spi)
+{
+ struct ad5446_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ iio_device_unregister(indio_dev);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ kfree(st);
+ return 0;
+}
+
+static const struct spi_device_id ad5446_id[] = {
+ {"ad5444", ID_AD5444},
+ {"ad5446", ID_AD5446},
+ {"ad5542a", ID_AD5542A},
+ {"ad5512a", ID_AD5512A},
+ {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
+ {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
+ {"ad5640-2500", ID_AD5640_2500},
+ {"ad5640-1250", ID_AD5640_1250},
+ {"ad5660-2500", ID_AD5660_2500},
+ {"ad5660-1250", ID_AD5660_1250},
+ {}
+};
+
+static struct spi_driver ad5446_driver = {
+ .driver = {
+ .name = "ad5446",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad5446_probe,
+ .remove = __devexit_p(ad5446_remove),
+ .id_table = ad5446_id,
+};
+
+static int __init ad5446_init(void)
+{
+ return spi_register_driver(&ad5446_driver);
+}
+module_init(ad5446_init);
+
+static void __exit ad5446_exit(void)
+{
+ spi_unregister_driver(&ad5446_driver);
+}
+module_exit(ad5446_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad5446");
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
new file mode 100644
index 000000000000..902542e22c4a
--- /dev/null
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -0,0 +1,96 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_AD5446_H_
+#define IIO_DAC_AD5446_H_
+
+/* DAC Control Bits */
+
+#define AD5446_LOAD (0x0 << 14) /* Load and update */
+#define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */
+#define AD5446_NOP (0x2 << 14) /* No operation */
+#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */
+
+#define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/
+#define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */
+#define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */
+#define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */
+
+#define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/
+#define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */
+#define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */
+#define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @indio_dev: the industrial I/O device
+ * @spi: spi_device
+ * @chip_info: chip model specific constants, available modes etc
+ * @reg: supply regulator
+ * @poll_work: bottom half of polling interrupt handler
+ * @vref_mv: actual reference voltage used
+ * @xfer: default spi transfer
+ * @msg: default spi message
+ * @data: spi transmit buffer
+ */
+
+struct ad5446_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ const struct ad5446_chip_info *chip_info;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ unsigned short vref_mv;
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ union {
+ unsigned short d16;
+ unsigned char d24[3];
+ } data;
+};
+
+/**
+ * struct ad5446_chip_info - chip specific information
+ * @bits: accuracy of the DAC in bits
+ * @storagebits: number of bits written to the DAC
+ * @left_shift: number of bits the datum must be shifted
+ * @int_vref_mv: AD5620/40/60: the internal reference voltage
+ * @store_sample: chip specific helper function to store the datum
+ */
+
+struct ad5446_chip_info {
+ u8 bits;
+ u8 storagebits;
+ u8 left_shift;
+ u16 int_vref_mv;
+ void (*store_sample) (struct ad5446_state *st, unsigned val);
+};
+
+/**
+ * ad5446_supported_device_ids:
+ * The AD5620/40/60 parts are available in different fixed internal reference
+ * voltage options. The actual part numbers may look differently
+ * (and a bit cryptic), however this style is used to make clear which
+ * parts are supported here.
+ */
+
+enum ad5446_supported_device_ids {
+ ID_AD5444,
+ ID_AD5446,
+ ID_AD5542A,
+ ID_AD5512A,
+ ID_AD5620_2500,
+ ID_AD5620_1250,
+ ID_AD5640_2500,
+ ID_AD5640_1250,
+ ID_AD5660_2500,
+ ID_AD5660_1250,
+};
+
+#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h
new file mode 100644
index 000000000000..ce518be652b7
--- /dev/null
+++ b/drivers/staging/iio/dac/ad5624r.h
@@ -0,0 +1,21 @@
+#ifndef SPI_AD5624R_H_
+#define SPI_AD5624R_H_
+
+#define AD5624R_DAC_CHANNELS 4
+
+#define AD5624R_ADDR_DAC0 0x0
+#define AD5624R_ADDR_DAC1 0x1
+#define AD5624R_ADDR_DAC2 0x2
+#define AD5624R_ADDR_DAC3 0x3
+#define AD5624R_ADDR_ALL_DAC 0x7
+
+#define AD5624R_CMD_WRITE_INPUT_N 0x0
+#define AD5624R_CMD_UPDATE_DAC_N 0x1
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3
+#define AD5624R_CMD_POWERDOWN_DAC 0x4
+#define AD5624R_CMD_RESET 0x5
+#define AD5624R_CMD_LDAC_SETUP 0x6
+#define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7
+
+#endif
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
new file mode 100644
index 000000000000..2b1c6dde4fdd
--- /dev/null
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -0,0 +1,300 @@
+/*
+ * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "dac.h"
+#include "ad5624r.h"
+
+/**
+ * struct ad5624r_state - device related storage
+ * @indio_dev: associated industrial IO device
+ * @us: spi device
+ **/
+struct ad5624r_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *us;
+ int data_len;
+ int ldac_mode;
+ int dac_power_mode[AD5624R_DAC_CHANNELS];
+ int internal_ref;
+};
+
+static int ad5624r_spi_write(struct spi_device *spi,
+ u8 cmd, u8 addr, u16 val, u8 len)
+{
+ u32 data;
+ u8 msg[3];
+
+ /*
+ * The input shift register is 24 bits wide. The first two bits are don't care bits.
+ * The next three are the command bits, C2 to C0, followed by the 3-bit DAC address,
+ * A2 to A0, and then the 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
+ * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, for the AD5664R,
+ * AD5644R, and AD5624R, respectively.
+ */
+ data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
+ msg[0] = data >> 16;
+ msg[1] = data >> 8;
+ msg[2] = data;
+
+ return spi_write(spi, msg, 3);
+}
+
+static ssize_t ad5624r_write_dac(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ long readin;
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = strict_strtol(buf, 10, &readin);
+ if (ret)
+ return ret;
+
+ ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
+ this_attr->address, readin, st->data_len);
+ return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_ldac_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+
+ return sprintf(buf, "%x\n", st->ldac_mode);
+}
+
+static ssize_t ad5624r_write_ldac_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ long readin;
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+
+ ret = strict_strtol(buf, 16, &readin);
+ if (ret)
+ return ret;
+
+ ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0,
+ readin & 0xF, 16);
+ st->ldac_mode = readin & 0xF;
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_dac_power_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ return sprintf(buf, "%d\n", st->dac_power_mode[this_attr->address]);
+}
+
+static ssize_t ad5624r_write_dac_power_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ long readin;
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = strict_strtol(buf, 10, &readin);
+ if (ret)
+ return ret;
+
+ ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
+ ((readin & 0x3) << 4) |
+ (1 << this_attr->address), 16);
+
+ st->dac_power_mode[this_attr->address] = readin & 0x3;
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_internal_ref_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+
+ return sprintf(buf, "%d\n", st->internal_ref);
+}
+
+static ssize_t ad5624r_write_internal_ref_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ long readin;
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ad5624r_state *st = indio_dev->dev_data;
+
+ ret = strict_strtol(buf, 10, &readin);
+ if (ret)
+ return ret;
+
+ ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
+ !!readin, 16);
+
+ st->internal_ref = !!readin;
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0);
+static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1);
+static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2);
+static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3);
+
+static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode,
+ ad5624r_write_ldac_mode, 0);
+static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR,
+ ad5624r_read_internal_ref_mode,
+ ad5624r_write_internal_ref_mode, 0);
+
+#define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr)
+
+static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode,
+ ad5624r_write_dac_power_mode, 0);
+static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode,
+ ad5624r_write_dac_power_mode, 1);
+static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode,
+ ad5624r_write_dac_power_mode, 2);
+static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode,
+ ad5624r_write_dac_power_mode, 3);
+
+static struct attribute *ad5624r_attributes[] = {
+ &iio_dev_attr_out0_raw.dev_attr.attr,
+ &iio_dev_attr_out1_raw.dev_attr.attr,
+ &iio_dev_attr_out2_raw.dev_attr.attr,
+ &iio_dev_attr_out3_raw.dev_attr.attr,
+ &iio_dev_attr_dac_power_mode_0.dev_attr.attr,
+ &iio_dev_attr_dac_power_mode_1.dev_attr.attr,
+ &iio_dev_attr_dac_power_mode_2.dev_attr.attr,
+ &iio_dev_attr_dac_power_mode_3.dev_attr.attr,
+ &iio_dev_attr_ldac_mode.dev_attr.attr,
+ &iio_dev_attr_internal_ref.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad5624r_attribute_group = {
+ .attrs = ad5624r_attributes,
+};
+
+static int __devinit ad5624r_probe(struct spi_device *spi)
+{
+ struct ad5624r_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ st->data_len = spi_get_device_id(spi)->driver_data;
+
+ st->us = spi;
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 0;
+ st->indio_dev->event_attrs = NULL;
+
+ st->indio_dev->attrs = &ad5624r_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ spi->mode = SPI_MODE_0;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->indio_dev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad5624r_remove(struct spi_device *spi)
+{
+ struct ad5624r_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->indio_dev);
+ kfree(st);
+
+ return 0;
+}
+
+static const struct spi_device_id ad5624r_id[] = {
+ {"ad5624r", 12},
+ {"ad5644r", 14},
+ {"ad5664r", 16},
+ {}
+};
+
+static struct spi_driver ad5624r_driver = {
+ .driver = {
+ .name = "ad5624r",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad5624r_probe,
+ .remove = __devexit_p(ad5624r_remove),
+ .id_table = ad5624r_id,
+};
+
+static __init int ad5624r_spi_init(void)
+{
+ return spi_register_driver(&ad5624r_driver);
+}
+module_init(ad5624r_spi_init);
+
+static __exit void ad5624r_spi_exit(void)
+{
+ spi_unregister_driver(&ad5624r_driver);
+}
+module_exit(ad5624r_spi_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h
new file mode 100644
index 000000000000..1d82f353241c
--- /dev/null
+++ b/drivers/staging/iio/dac/dac.h
@@ -0,0 +1,6 @@
+/*
+ * dac.h - sysfs attributes associated with DACs
+ */
+
+#define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \
+ IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr)
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig
new file mode 100644
index 000000000000..a047da62daf0
--- /dev/null
+++ b/drivers/staging/iio/dds/Kconfig
@@ -0,0 +1,56 @@
+#
+# Direct Digital Synthesis drivers
+#
+comment "Direct Digital Synthesis"
+
+config AD5930
+ tristate "Analog Devices ad5930/5932 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad5930/ad5932, provides direct access via sysfs.
+
+config AD9832
+ tristate "Analog Devices ad9832/5 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9832 and ad9835, provides direct access via sysfs.
+
+config AD9834
+ tristate "Analog Devices ad9833/4/ driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ AD9833 and AD9834, provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad9834.
+
+config AD9850
+ tristate "Analog Devices ad9850/1 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9850/1, provides direct access via sysfs.
+
+config AD9852
+ tristate "Analog Devices ad9852/4 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9852/4, provides direct access via sysfs.
+
+config AD9910
+ tristate "Analog Devices ad9910 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9910, provides direct access via sysfs.
+
+config AD9951
+ tristate "Analog Devices ad9951 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9951, provides direct access via sysfs.
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile
new file mode 100644
index 000000000000..147746176b9b
--- /dev/null
+++ b/drivers/staging/iio/dds/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for Direct Digital Synthesis drivers
+#
+
+obj-$(CONFIG_AD5930) += ad5930.o
+obj-$(CONFIG_AD9832) += ad9832.o
+obj-$(CONFIG_AD9834) += ad9834.o
+obj-$(CONFIG_AD9850) += ad9850.o
+obj-$(CONFIG_AD9852) += ad9852.o
+obj-$(CONFIG_AD9910) += ad9910.o
+obj-$(CONFIG_AD9951) += ad9951.o
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c
new file mode 100644
index 000000000000..f80039c5d539
--- /dev/null
+++ b/drivers/staging/iio/dds/ad5930.c
@@ -0,0 +1,170 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad5930
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad5930"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad5903_config {
+ u16 control;
+ u16 incnum;
+ u16 frqdelt[2];
+ u16 incitvl;
+ u16 buritvl;
+ u16 strtfrq[2];
+};
+
+struct ad5930_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad5930_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad5903_config *config = (struct ad5903_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad5930_state *st = idev->dev_data;
+
+ config->control = (config->control & ~value_mask);
+ config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
+ config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
+ config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
+ config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
+ config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
+ config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
+ config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
+
+ xfer.len = len;
+ xfer.tx_buf = config;
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
+
+static struct attribute *ad5930_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad5930_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad5930_attributes,
+};
+
+static int __devinit ad5930_probe(struct spi_device *spi)
+{
+ struct ad5930_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad5930_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 16;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad5930_remove(struct spi_device *spi)
+{
+ struct ad5930_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad5930_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad5930_probe,
+ .remove = __devexit_p(ad5930_remove),
+};
+
+static __init int ad5930_spi_init(void)
+{
+ return spi_register_driver(&ad5930_driver);
+}
+module_init(ad5930_spi_init);
+
+static __exit void ad5930_spi_exit(void)
+{
+ spi_unregister_driver(&ad5930_driver);
+}
+module_exit(ad5930_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad5930 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
new file mode 100644
index 000000000000..e911893b3db0
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9832.c
@@ -0,0 +1,264 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9832
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9832"
+
+#define value_mask (u16)0xf000
+#define cmd_shift 12
+#define add_shift 8
+#define AD9832_SYNC (1 << 13)
+#define AD9832_SELSRC (1 << 12)
+#define AD9832_SLEEP (1 << 13)
+#define AD9832_RESET (1 << 12)
+#define AD9832_CLR (1 << 11)
+
+#define ADD_FREQ0LL 0x0
+#define ADD_FREQ0HL 0x1
+#define ADD_FREQ0LM 0x2
+#define ADD_FREQ0HM 0x3
+#define ADD_FREQ1LL 0x4
+#define ADD_FREQ1HL 0x5
+#define ADD_FREQ1LM 0x6
+#define ADD_FREQ1HM 0x7
+#define ADD_PHASE0L 0x8
+#define ADD_PHASE0H 0x9
+#define ADD_PHASE1L 0xa
+#define ADD_PHASE1H 0xb
+#define ADD_PHASE2L 0xc
+#define ADD_PHASE2H 0xd
+#define ADD_PHASE3L 0xe
+#define ADD_PHASE3H 0xf
+
+#define CMD_PHA8BITSW 0x1
+#define CMD_PHA16BITSW 0x0
+#define CMD_FRE8BITSW 0x3
+#define CMD_FRE16BITSW 0x2
+#define CMD_SELBITSCTL 0x6
+
+struct ad9832_setting {
+ u16 freq0[4];
+ u16 freq1[4];
+ u16 phase0[2];
+ u16 phase1[2];
+ u16 phase2[2];
+ u16 phase3[2];
+};
+
+struct ad9832_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9832_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9832_setting config;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9832_state *st = idev->dev_data;
+
+ config.freq0[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LL << add_shift | buf[0]);
+ config.freq0[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HL << add_shift | buf[1]);
+ config.freq0[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LM << add_shift | buf[2]);
+ config.freq0[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HM << add_shift | buf[3]);
+ config.freq1[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LL << add_shift | buf[4]);
+ config.freq1[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HL << add_shift | buf[5]);
+ config.freq1[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LM << add_shift | buf[6]);
+ config.freq1[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HM << add_shift | buf[7]);
+
+ config.phase0[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE0L << add_shift | buf[9]);
+ config.phase0[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE0H << add_shift | buf[10]);
+ config.phase1[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE1L << add_shift | buf[11]);
+ config.phase1[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE1H << add_shift | buf[12]);
+ config.phase2[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE2L << add_shift | buf[13]);
+ config.phase2[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE2H << add_shift | buf[14]);
+ config.phase3[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE3L << add_shift | buf[15]);
+ config.phase3[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE3H << add_shift | buf[16]);
+
+ xfer.len = 2 * len;
+ xfer.tx_buf = &config;
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9832_set_parameter, 0);
+
+static struct attribute *ad9832_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9832_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9832_attributes,
+};
+
+static void ad9832_init(struct ad9832_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u16 config = 0;
+
+ config = 0x3 << 14 | AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ config = 0x2 << 14 | AD9832_SYNC | AD9832_SELSRC;
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ config = CMD_SELBITSCTL << cmd_shift;
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ config = 0x3 << 14;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+
+
+}
+
+static int __devinit ad9832_probe(struct spi_device *spi)
+{
+ struct ad9832_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9832_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 16;
+ spi_setup(spi);
+ ad9832_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9832_remove(struct spi_device *spi)
+{
+ struct ad9832_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9832_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9832_probe,
+ .remove = __devexit_p(ad9832_remove),
+};
+
+static __init int ad9832_spi_init(void)
+{
+ return spi_register_driver(&ad9832_driver);
+}
+module_init(ad9832_spi_init);
+
+static __exit void ad9832_spi_exit(void)
+{
+ spi_unregister_driver(&ad9832_driver);
+}
+module_exit(ad9832_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9832 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c
new file mode 100644
index 000000000000..eb1a681874f9
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9834.c
@@ -0,0 +1,477 @@
+/*
+ * AD9834 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <asm/div64.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "dds.h"
+
+#include "ad9834.h"
+
+static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout)
+{
+ unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS);
+ do_div(freqreg, mclk);
+ return freqreg;
+}
+
+static int ad9834_write_frequency(struct ad9834_state *st,
+ unsigned long addr, unsigned long fout)
+{
+ unsigned long regval;
+
+ if (fout > (st->mclk / 2))
+ return -EINVAL;
+
+ regval = ad9834_calc_freqreg(st->mclk, fout);
+
+ st->freq_data[0] = cpu_to_be16(addr | (regval &
+ RES_MASK(AD9834_FREQ_BITS / 2)));
+ st->freq_data[1] = cpu_to_be16(addr | ((regval >>
+ (AD9834_FREQ_BITS / 2)) &
+ RES_MASK(AD9834_FREQ_BITS / 2)));
+
+ return spi_sync(st->spi, &st->freq_msg);;
+}
+
+static int ad9834_write_phase(struct ad9834_state *st,
+ unsigned long addr, unsigned long phase)
+{
+ if (phase > (1 << AD9834_PHASE_BITS))
+ return -EINVAL;
+ st->data = cpu_to_be16(addr | phase);
+
+ return spi_sync(st->spi, &st->msg);
+}
+
+static ssize_t ad9834_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+
+ mutex_lock(&dev_info->mlock);
+ switch (this_attr->address) {
+ case AD9834_REG_FREQ0:
+ case AD9834_REG_FREQ1:
+ ret = ad9834_write_frequency(st, this_attr->address, val);
+ break;
+ case AD9834_REG_PHASE0:
+ case AD9834_REG_PHASE1:
+ ret = ad9834_write_phase(st, this_attr->address, val);
+ break;
+ case AD9834_OPBITEN:
+ if (st->control & AD9834_MODE) {
+ ret = -EINVAL; /* AD9843 reserved mode */
+ break;
+ }
+
+ if (val)
+ st->control |= AD9834_OPBITEN;
+ else
+ st->control &= ~AD9834_OPBITEN;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_PIN_SW:
+ if (val)
+ st->control |= AD9834_PIN_SW;
+ else
+ st->control &= ~AD9834_PIN_SW;
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_FSEL:
+ case AD9834_PSEL:
+ if (val == 0)
+ st->control &= ~(this_attr->address | AD9834_PIN_SW);
+ else if (val == 1) {
+ st->control |= this_attr->address;
+ st->control &= ~AD9834_PIN_SW;
+ } else {
+ ret = -EINVAL;
+ break;
+ }
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_RESET:
+ if (val)
+ st->control &= ~AD9834_RESET;
+ else
+ st->control |= AD9834_RESET;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ mutex_unlock(&dev_info->mlock);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ad9834_store_wavetype(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret = 0;
+ bool is_ad9833 = st->devid == ID_AD9833;
+
+ mutex_lock(&dev_info->mlock);
+
+ switch (this_attr->address) {
+ case 0:
+ if (sysfs_streq(buf, "sine")) {
+ st->control &= ~AD9834_MODE;
+ if (is_ad9833)
+ st->control &= ~AD9834_OPBITEN;
+ } else if (sysfs_streq(buf, "triangle")) {
+ if (is_ad9833) {
+ st->control &= ~AD9834_OPBITEN;
+ st->control |= AD9834_MODE;
+ } else if (st->control & AD9834_OPBITEN) {
+ ret = -EINVAL; /* AD9843 reserved mode */
+ } else {
+ st->control |= AD9834_MODE;
+ }
+ } else if (is_ad9833 && sysfs_streq(buf, "square")) {
+ st->control &= ~AD9834_MODE;
+ st->control |= AD9834_OPBITEN;
+ } else {
+ ret = -EINVAL;
+ }
+
+ break;
+ case 1:
+ if (sysfs_streq(buf, "square") &&
+ !(st->control & AD9834_MODE)) {
+ st->control &= ~AD9834_MODE;
+ st->control |= AD9834_OPBITEN;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!ret) {
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ }
+ mutex_unlock(&dev_info->mlock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad9834_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad9834_show_name, NULL, 0);
+
+static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+ char *str;
+
+ if (st->devid == ID_AD9833)
+ str = "sine triangle square";
+ else if (st->control & AD9834_OPBITEN)
+ str = "sine";
+ else
+ str = "sine triangle";
+
+ return sprintf(buf, "%s\n", str);
+}
+
+
+static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO,
+ ad9834_show_out0_wavetype_available, NULL, 0);
+
+static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+ char *str;
+
+ if (st->control & AD9834_MODE)
+ str = "";
+ else
+ str = "square";
+
+ return sprintf(buf, "%s\n", str);
+}
+
+static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO,
+ ad9834_show_out1_wavetype_available, NULL, 0);
+
+/**
+ * see dds.h for further information
+ */
+
+static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0);
+static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1);
+static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL);
+static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
+
+static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0);
+static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1);
+static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL);
+static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
+
+static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+ ad9834_write, AD9834_PIN_SW);
+static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET);
+static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL,
+ ad9834_write, AD9834_OPBITEN);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
+
+static struct attribute *ad9834_attributes[] = {
+ &iio_dev_attr_dds0_freq0.dev_attr.attr,
+ &iio_dev_attr_dds0_freq1.dev_attr.attr,
+ &iio_const_attr_dds0_freq_scale.dev_attr.attr,
+ &iio_dev_attr_dds0_phase0.dev_attr.attr,
+ &iio_dev_attr_dds0_phase1.dev_attr.attr,
+ &iio_const_attr_dds0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
+ &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_dds0_out_enable.dev_attr.attr,
+ &iio_dev_attr_dds0_out1_enable.dev_attr.attr,
+ &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr,
+ &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad9834_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (st->devid == ID_AD9834)
+ return mode;
+
+ if ((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) ||
+ (attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) ||
+ (attr ==
+ &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group ad9834_attribute_group = {
+ .attrs = ad9834_attributes,
+ .is_visible = ad9834_attr_is_visible,
+};
+
+static int __devinit ad9834_probe(struct spi_device *spi)
+{
+ struct ad9834_platform_data *pdata = spi->dev.platform_data;
+ struct ad9834_state *st;
+ int ret;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ st->mclk = pdata->mclk;
+
+ spi_set_drvdata(spi, st);
+
+ st->spi = spi;
+ st->devid = spi_get_device_id(spi)->driver_data;
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad9834_attribute_group;
+ st->indio_dev->dev_data = (void *) st;
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default messages */
+
+ st->xfer.tx_buf = &st->data;
+ st->xfer.len = 2;
+
+ spi_message_init(&st->msg);
+ spi_message_add_tail(&st->xfer, &st->msg);
+
+ st->freq_xfer[0].tx_buf = &st->freq_data[0];
+ st->freq_xfer[0].len = 2;
+ st->freq_xfer[0].cs_change = 1;
+ st->freq_xfer[1].tx_buf = &st->freq_data[1];
+ st->freq_xfer[1].len = 2;
+
+ spi_message_init(&st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
+
+ st->control = AD9834_B28 | AD9834_RESET;
+
+ if (!pdata->en_div2)
+ st->control |= AD9834_DIV2;
+
+ if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834))
+ st->control |= AD9834_SIGN_PIB;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret) {
+ dev_err(&spi->dev, "device init failed\n");
+ goto error_free_device;
+ }
+
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1);
+ if (ret)
+ goto error_free_device;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
+ return 0;
+
+error_free_device:
+ iio_free_device(st->indio_dev);
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9834_remove(struct spi_device *spi)
+{
+ struct ad9834_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->indio_dev);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ kfree(st);
+ return 0;
+}
+
+static const struct spi_device_id ad9834_id[] = {
+ {"ad9833", ID_AD9833},
+ {"ad9834", ID_AD9834},
+ {}
+};
+
+static struct spi_driver ad9834_driver = {
+ .driver = {
+ .name = "ad9834",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9834_probe,
+ .remove = __devexit_p(ad9834_remove),
+ .id_table = ad9834_id,
+};
+
+static int __init ad9834_init(void)
+{
+ return spi_register_driver(&ad9834_driver);
+}
+module_init(ad9834_init);
+
+static void __exit ad9834_exit(void)
+{
+ spi_unregister_driver(&ad9834_driver);
+}
+module_exit(ad9834_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9833/AD9834 DDS");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad9834");
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/dds/ad9834.h
new file mode 100644
index 000000000000..0fc3b8859e9e
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9834.h
@@ -0,0 +1,112 @@
+/*
+ * AD9834 SPI DDS driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DDS_AD9834_H_
+#define IIO_DDS_AD9834_H_
+
+/* Registers */
+
+#define AD9834_REG_CMD (0 << 14)
+#define AD9834_REG_FREQ0 (1 << 14)
+#define AD9834_REG_FREQ1 (2 << 14)
+#define AD9834_REG_PHASE0 (6 << 13)
+#define AD9834_REG_PHASE1 (7 << 13)
+
+/* Command Control Bits */
+
+#define AD9834_B28 (1 << 13)
+#define AD9834_HLB (1 << 12)
+#define AD9834_FSEL (1 << 11)
+#define AD9834_PSEL (1 << 10)
+#define AD9834_PIN_SW (1 << 9)
+#define AD9834_RESET (1 << 8)
+#define AD9834_SLEEP1 (1 << 7)
+#define AD9834_SLEEP12 (1 << 6)
+#define AD9834_OPBITEN (1 << 5)
+#define AD9834_SIGN_PIB (1 << 4)
+#define AD9834_DIV2 (1 << 3)
+#define AD9834_MODE (1 << 1)
+
+#define AD9834_FREQ_BITS 28
+#define AD9834_PHASE_BITS 12
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/**
+ * struct ad9834_state - driver instance specific data
+ * @indio_dev: the industrial I/O device
+ * @spi: spi_device
+ * @reg: supply regulator
+ * @mclk: external master clock
+ * @control: cached control word
+ * @xfer: default spi transfer
+ * @msg: default spi message
+ * @freq_xfer: tuning word spi transfer
+ * @freq_msg: tuning word spi message
+ * @data: spi transmit buffer
+ * @freq_data: tuning word spi transmit buffer
+ */
+
+struct ad9834_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned int mclk;
+ unsigned short control;
+ unsigned short devid;
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ struct spi_transfer freq_xfer[2];
+ struct spi_message freq_msg;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned short data ____cacheline_aligned;
+ unsigned short freq_data[2] ;
+};
+
+
+/*
+ * TODO: struct ad7887_platform_data needs to go into include/linux/iio
+ */
+
+/**
+ * struct ad9834_platform_data - platform specific information
+ * @mclk: master clock in Hz
+ * @freq0: power up freq0 tuning word in Hz
+ * @freq1: power up freq1 tuning word in Hz
+ * @phase0: power up phase0 value [0..4095] correlates with 0..2PI
+ * @phase1: power up phase1 value [0..4095] correlates with 0..2PI
+ * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin
+ * @en_signbit_msb_out: the MSB (or MSB/2) of the DAC data is connected to the
+ * SIGN BIT OUT pin. en_div2 controls whether it is the MSB
+ * or MSB/2 that is output. if en_signbit_msb_out=false,
+ * the on-board comparator is connected to SIGN BIT OUT
+ */
+
+struct ad9834_platform_data {
+ unsigned int mclk;
+ unsigned int freq0;
+ unsigned int freq1;
+ unsigned short phase0;
+ unsigned short phase1;
+ bool en_div2;
+ bool en_signbit_msb_out;
+};
+
+/**
+ * ad9834_supported_device_ids:
+ */
+
+enum ad9834_supported_device_ids {
+ ID_AD9833,
+ ID_AD9834,
+};
+
+#endif /* IIO_DDS_AD9834_H_ */
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c
new file mode 100644
index 000000000000..b259bfeaf5aa
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9850.c
@@ -0,0 +1,156 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9850
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9850"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad9850_config {
+ u8 control[5];
+};
+
+struct ad9850_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9850_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9850_config *config = (struct ad9850_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9850_state *st = idev->dev_data;
+
+ xfer.len = len;
+ xfer.tx_buf = config;
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0);
+
+static struct attribute *ad9850_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9850_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9850_attributes,
+};
+
+static int __devinit ad9850_probe(struct spi_device *spi)
+{
+ struct ad9850_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9850_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 16;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9850_remove(struct spi_device *spi)
+{
+ struct ad9850_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9850_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9850_probe,
+ .remove = __devexit_p(ad9850_remove),
+};
+
+static __init int ad9850_spi_init(void)
+{
+ return spi_register_driver(&ad9850_driver);
+}
+module_init(ad9850_spi_init);
+
+static __exit void ad9850_spi_exit(void)
+{
+ spi_unregister_driver(&ad9850_driver);
+}
+module_exit(ad9850_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9850 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c
new file mode 100644
index 000000000000..594fb6a94331
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9852.c
@@ -0,0 +1,305 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9852
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9852"
+
+#define addr_phaad1 0x0
+#define addr_phaad2 0x1
+#define addr_fretu1 0x2
+#define addr_fretu2 0x3
+#define addr_delfre 0x4
+#define addr_updclk 0x5
+#define addr_ramclk 0x6
+#define addr_contrl 0x7
+#define addr_optskm 0x8
+#define addr_optskr 0xa
+#define addr_dacctl 0xb
+
+#define COMPPD (1 << 4)
+#define REFMULT2 (1 << 2)
+#define BYPPLL (1 << 5)
+#define PLLRANG (1 << 6)
+#define IEUPCLK (1)
+#define OSKEN (1 << 5)
+
+#define read_bit (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9852_config {
+ u8 phajst0[3];
+ u8 phajst1[3];
+ u8 fretun1[6];
+ u8 fretun2[6];
+ u8 dltafre[6];
+ u8 updtclk[5];
+ u8 ramprat[4];
+ u8 control[5];
+ u8 outpskm[3];
+ u8 outpskr[2];
+ u8 daccntl[3];
+};
+
+struct ad9852_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9852_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9852_config *config = (struct ad9852_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9852_state *st = idev->dev_data;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->phajst0[0];
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->phajst1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->fretun1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->fretun2[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->dltafre[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->updtclk[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 4;
+ xfer.tx_buf = &config->ramprat[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->control[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->outpskm[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config->outpskr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->daccntl[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0);
+
+static void ad9852_init(struct ad9852_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 config[5];
+
+ config[0] = addr_contrl;
+ config[1] = COMPPD;
+ config[2] = REFMULT2 | BYPPLL | PLLRANG;
+ config[3] = IEUPCLK;
+ config[4] = OSKEN;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9852_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9852_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9852_attributes,
+};
+
+static int __devinit ad9852_probe(struct spi_device *spi)
+{
+ struct ad9852_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9852_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9852_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9852_remove(struct spi_device *spi)
+{
+ struct ad9852_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9852_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9852_probe,
+ .remove = __devexit_p(ad9852_remove),
+};
+
+static __init int ad9852_spi_init(void)
+{
+ return spi_register_driver(&ad9852_driver);
+}
+module_init(ad9852_spi_init);
+
+static __exit void ad9852_spi_exit(void)
+{
+ spi_unregister_driver(&ad9852_driver);
+}
+module_exit(ad9852_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9852 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c
new file mode 100644
index 000000000000..e8fb75cb66ec
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9910.c
@@ -0,0 +1,440 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9910
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9910"
+
+#define CFR1 0x0
+#define CFR2 0x1
+#define CFR3 0x2
+
+#define AUXDAC 0x3
+#define IOUPD 0x4
+#define FTW 0x7
+#define POW 0x8
+#define ASF 0x9
+#define MULTC 0x0A
+#define DIG_RAMPL 0x0B
+#define DIG_RAMPS 0x0C
+#define DIG_RAMPR 0x0D
+#define SIN_TONEP0 0x0E
+#define SIN_TONEP1 0x0F
+#define SIN_TONEP2 0x10
+#define SIN_TONEP3 0x11
+#define SIN_TONEP4 0x12
+#define SIN_TONEP5 0x13
+#define SIN_TONEP6 0x14
+#define SIN_TONEP7 0x15
+
+#define RAM_ENABLE (1 << 7)
+
+#define MANUAL_OSK (1 << 7)
+#define INVSIC (1 << 6)
+#define DDS_SINEOP (1)
+
+#define AUTO_OSK (1)
+#define OSKEN (1 << 1)
+#define LOAD_ARR (1 << 2)
+#define CLR_PHA (1 << 3)
+#define CLR_DIG (1 << 4)
+#define ACLR_PHA (1 << 5)
+#define ACLR_DIG (1 << 6)
+#define LOAD_LRR (1 << 7)
+
+#define LSB_FST (1)
+#define SDIO_IPT (1 << 1)
+#define EXT_PWD (1 << 3)
+#define ADAC_PWD (1 << 4)
+#define REFCLK_PWD (1 << 5)
+#define DAC_PWD (1 << 6)
+#define DIG_PWD (1 << 7)
+
+#define ENA_AMP (1)
+#define READ_FTW (1)
+#define DIGR_LOW (1 << 1)
+#define DIGR_HIGH (1 << 2)
+#define DIGR_ENA (1 << 3)
+#define SYNCCLK_ENA (1 << 6)
+#define ITER_IOUPD (1 << 7)
+
+#define TX_ENA (1 << 1)
+#define PDCLK_INV (1 << 2)
+#define PDCLK_ENB (1 << 3)
+
+#define PARA_ENA (1 << 4)
+#define SYNC_DIS (1 << 5)
+#define DATA_ASS (1 << 6)
+#define MATCH_ENA (1 << 7)
+
+#define PLL_ENA (1)
+#define PFD_RST (1 << 2)
+#define REFCLK_RST (1 << 6)
+#define REFCLK_BYP (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9910_config {
+ u8 auxdac[5];
+ u8 ioupd[5];
+ u8 ftw[5];
+ u8 pow[3];
+ u8 asf[5];
+ u8 multc[5];
+ u8 dig_rampl[9];
+ u8 dig_ramps[9];
+ u8 dig_rampr[5];
+ u8 sin_tonep0[9];
+ u8 sin_tonep1[9];
+ u8 sin_tonep2[9];
+ u8 sin_tonep3[9];
+ u8 sin_tonep4[9];
+ u8 sin_tonep5[9];
+ u8 sin_tonep6[9];
+ u8 sin_tonep7[9];
+};
+
+struct ad9910_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9910_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9910_config *config = (struct ad9910_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9910_state *st = idev->dev_data;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->auxdac[0];
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ioupd[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ftw[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->pow[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->asf[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->multc[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->dig_rampl[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->dig_ramps[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->dig_rampr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep0[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep2[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep3[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep4[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep5[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep6[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep7[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
+
+static void ad9910_init(struct ad9910_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 cfr[5];
+
+ cfr[0] = CFR1;
+ cfr[1] = 0;
+ cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
+ cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
+ cfr[4] = 0;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR2;
+ cfr[1] = ENA_AMP;
+ cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
+ cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
+ cfr[4] = PARA_ENA;
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR3;
+ cfr[1] = PLL_ENA;
+ cfr[2] = 0;
+ cfr[3] = REFCLK_RST | REFCLK_BYP;
+ cfr[4] = 0;
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9910_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9910_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9910_attributes,
+};
+
+static int __devinit ad9910_probe(struct spi_device *spi)
+{
+ struct ad9910_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9910_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9910_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9910_remove(struct spi_device *spi)
+{
+ struct ad9910_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9910_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9910_probe,
+ .remove = __devexit_p(ad9910_remove),
+};
+
+static __init int ad9910_spi_init(void)
+{
+ return spi_register_driver(&ad9910_driver);
+}
+module_init(ad9910_spi_init);
+
+static __exit void ad9910_spi_exit(void)
+{
+ spi_unregister_driver(&ad9910_driver);
+}
+module_exit(ad9910_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9910 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c
new file mode 100644
index 000000000000..57eddf6d4713
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9951.c
@@ -0,0 +1,249 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9951
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9951"
+
+#define CFR1 0x0
+#define CFR2 0x1
+
+#define AUTO_OSK (1)
+#define OSKEN (1 << 1)
+#define LOAD_ARR (1 << 2)
+
+#define AUTO_SYNC (1 << 7)
+
+#define LSB_FST (1)
+#define SDIO_IPT (1 << 1)
+#define CLR_PHA (1 << 2)
+#define SINE_OPT (1 << 4)
+#define ACLR_PHA (1 << 5)
+
+#define VCO_RANGE (1 << 2)
+
+#define CRS_OPT (1 << 1)
+#define HMANU_SYNC (1 << 2)
+#define HSPD_SYNC (1 << 3)
+
+/* Register format: 1 byte addr + value */
+struct ad9951_config {
+ u8 asf[3];
+ u8 arr[2];
+ u8 ftw0[5];
+ u8 ftw1[3];
+};
+
+struct ad9951_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9951_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9951_config *config = (struct ad9951_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9951_state *st = idev->dev_data;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->asf[0];
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config->arr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ftw0[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->ftw1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
+
+static void ad9951_init(struct ad9951_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 cfr[5];
+
+ cfr[0] = CFR1;
+ cfr[1] = 0;
+ cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
+ cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
+ cfr[4] = 0;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR2;
+ cfr[1] = VCO_RANGE;
+ cfr[2] = HSPD_SYNC;
+ cfr[3] = 0;
+
+ xfer.len = 4;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9951_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9951_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9951_attributes,
+};
+
+static int __devinit ad9951_probe(struct spi_device *spi)
+{
+ struct ad9951_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9951_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9951_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9951_remove(struct spi_device *spi)
+{
+ struct ad9951_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9951_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9951_probe,
+ .remove = __devexit_p(ad9951_remove),
+};
+
+static __init int ad9951_spi_init(void)
+{
+ return spi_register_driver(&ad9951_driver);
+}
+module_init(ad9951_spi_init);
+
+static __exit void ad9951_spi_exit(void)
+{
+ spi_unregister_driver(&ad9951_driver);
+}
+module_exit(ad9951_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9951 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h
new file mode 100644
index 000000000000..d8ac3a93baf6
--- /dev/null
+++ b/drivers/staging/iio/dds/dds.h
@@ -0,0 +1,110 @@
+/*
+ * dds.h - sysfs attributes associated with DDS devices
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqY
+ */
+
+#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqY_scale
+ */
+
+#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(dds##_channel##_freq_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqsymbol
+ */
+
+#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phaseY
+ */
+
+#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phaseY_scale
+ */
+
+#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(dds##_channel##_phase_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phasesymbol
+ */
+
+#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_out_enable
+ */
+
+#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_enable
+ */
+
+#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
+ _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_wavetype
+ */
+
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \
+ S_IWUSR, NULL, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+ */
+
+#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
+ IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\
+ _modes);
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig
index c4043610c0df..236f15fdbfc9 100644
--- a/drivers/staging/iio/gyro/Kconfig
+++ b/drivers/staging/iio/gyro/Kconfig
@@ -3,11 +3,45 @@
#
comment "Digital gyroscope sensors"
+config ADIS16060
+ tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices adis16060 wide bandwidth
+ yaw rate gyroscope with SPI.
+
+config ADIS16080
+ tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices adis16080/100 Yaw Rate
+ Gyroscope with SPI.
+
+config ADIS16130
+ tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADIS16130 High Precision
+ Angular Rate Sensor driver.
+
config ADIS16260
- tristate "Analog Devices ADIS16260/5 Digital Gyroscope Sensor SPI driver"
+ tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver"
depends on SPI
select IIO_TRIGGER if IIO_RING_BUFFER
select IIO_SW_RING if IIO_RING_BUFFER
help
- Say yes here to build support for Analog Devices adis16260/5
+ Say yes here to build support for Analog Devices ADIS16260 ADIS16265
programmable digital gyroscope sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called adis16260.
+
+config ADIS16251
+ tristate "Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices adis16261 programmable
+ digital gyroscope sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called adis16251.
diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile
index b5f0dc01122c..2764c15025a5 100644
--- a/drivers/staging/iio/gyro/Makefile
+++ b/drivers/staging/iio/gyro/Makefile
@@ -2,6 +2,18 @@
# Makefile for digital gyroscope sensor drivers
#
+adis16060-y := adis16060_core.o
+obj-$(CONFIG_ADIS16060) += adis16060.o
+
+adis16080-y := adis16080_core.o
+obj-$(CONFIG_ADIS16080) += adis16080.o
+
+adis16130-y := adis16130_core.o
+obj-$(CONFIG_ADIS16130) += adis16130.o
+
adis16260-y := adis16260_core.o
adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o
obj-$(CONFIG_ADIS16260) += adis16260.o
+
+adis16251-y := adis16251_core.o
+obj-$(CONFIG_ADIS16251) += adis16251.o
diff --git a/drivers/staging/iio/gyro/adis16060.h b/drivers/staging/iio/gyro/adis16060.h
new file mode 100644
index 000000000000..5c00e5385ee0
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16060.h
@@ -0,0 +1,101 @@
+#ifndef SPI_ADIS16060_H_
+#define SPI_ADIS16060_H_
+
+#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
+#define ADIS16060_SUPPLY_OUT 0x10 /* Measure Temperature */
+#define ADIS16060_AIN2 0x80 /* Measure AIN2 */
+#define ADIS16060_AIN1 0x40 /* Measure AIN1 */
+#define ADIS16060_TEMP_OUT 0x22 /* Set Positive Self-Test and Output for Angular Rate */
+#define ADIS16060_ANGL_OUT 0x21 /* Set Negative Self-Test and Output for Angular Rate */
+
+#define ADIS16060_MAX_TX 3
+#define ADIS16060_MAX_RX 3
+
+/**
+ * struct adis16060_state - device instance specific data
+ * @us_w: actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16060_state {
+ struct spi_device *us_w;
+ struct spi_device *us_r;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16060_scan {
+ ADIS16060_SCAN_GYRO,
+ ADIS16060_SCAN_TEMP,
+ ADIS16060_SCAN_ADC_1,
+ ADIS16060_SCAN_ADC_2,
+};
+
+void adis16060_remove_trigger(struct iio_dev *indio_dev);
+int adis16060_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16060_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int adis16060_configure_ring(struct iio_dev *indio_dev);
+void adis16060_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16060_initialize_ring(struct iio_ring_buffer *ring);
+void adis16060_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16060_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16060_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16060_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16060_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16060_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16060_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16060_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16060_H_ */
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
new file mode 100644
index 000000000000..fc48aca04bd3
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -0,0 +1,319 @@
+/*
+ * ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16060.h"
+
+#define DRIVER_NAME "adis16060"
+
+struct adis16060_state *adis16060_st;
+
+int adis16060_spi_write(struct device *dev,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16060_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = 0;
+ st->tx[1] = 0;
+ st->tx[2] = val; /* The last 8 bits clocked in are latched */
+
+ ret = spi_write(st->us_w, st->tx, 3);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+int adis16060_spi_read(struct device *dev,
+ u16 *val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16060_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+
+ ret = spi_read(st->us_r, st->rx, 3);
+
+ /* The internal successive approximation ADC begins the conversion process
+ * on the falling edge of MSEL1 and starts to place data MSB first on the
+ * DOUT line at the 6th falling edge of SCLK
+ */
+ if (ret == 0)
+ *val = ((st->rx[0] & 0x3) << 12) | (st->rx[1] << 4) | ((st->rx[2] >> 4) & 0xF);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static ssize_t adis16060_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ u16 val;
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16060_spi_read(dev, &val);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret == 0)
+ return sprintf(buf, "%d\n", val);
+ else
+ return ret;
+}
+
+static ssize_t adis16060_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 16, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16060_spi_write(dev, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_IN(_show) \
+ IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
+
+#define IIO_DEV_ATTR_OUT(_store) \
+ IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
+
+static IIO_DEV_ATTR_IN(adis16060_read);
+static IIO_DEV_ATTR_OUT(adis16060_write);
+
+static IIO_CONST_ATTR(name, "adis16060");
+
+static struct attribute *adis16060_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16060_event_attribute_group = {
+ .attrs = adis16060_event_attributes,
+};
+
+static struct attribute *adis16060_attributes[] = {
+ &iio_dev_attr_in.dev_attr.attr,
+ &iio_dev_attr_out.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16060_attribute_group = {
+ .attrs = adis16060_attributes,
+};
+
+static int __devinit adis16060_r_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16060_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16060_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16060_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us_r = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16060_event_attribute_group;
+ st->indio_dev->attrs = &adis16060_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16060_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16060_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16060");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16060_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ adis16060_st = st;
+ return 0;
+
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16060_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16060_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16060_r_remove(struct spi_device *spi)
+{
+ struct adis16060_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16060_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16060_uninitialize_ring(indio_dev->ring);
+ adis16060_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static int __devinit adis16060_w_probe(struct spi_device *spi)
+{
+ int ret;
+ struct adis16060_state *st = adis16060_st;
+ if (!st) {
+ ret = -ENODEV;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+ st->us_w = spi;
+ return 0;
+
+error_ret:
+ return ret;
+}
+
+static int adis16060_w_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct spi_driver adis16060_r_driver = {
+ .driver = {
+ .name = "adis16060_r",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16060_r_probe,
+ .remove = __devexit_p(adis16060_r_remove),
+};
+
+static struct spi_driver adis16060_w_driver = {
+ .driver = {
+ .name = "adis16060_w",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16060_w_probe,
+ .remove = __devexit_p(adis16060_w_remove),
+};
+
+static __init int adis16060_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&adis16060_r_driver);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_register_driver(&adis16060_w_driver);
+ if (ret < 0) {
+ spi_unregister_driver(&adis16060_r_driver);
+ return ret;
+ }
+
+ return 0;
+}
+module_init(adis16060_init);
+
+static __exit void adis16060_exit(void)
+{
+ spi_unregister_driver(&adis16060_w_driver);
+ spi_unregister_driver(&adis16060_r_driver);
+}
+module_exit(adis16060_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16080.h b/drivers/staging/iio/gyro/adis16080.h
new file mode 100644
index 000000000000..3fcbe67f7c31
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16080.h
@@ -0,0 +1,102 @@
+#ifndef SPI_ADIS16080_H_
+#define SPI_ADIS16080_H_
+
+#define ADIS16080_DIN_CODE 4 /* Output data format setting. 0: Twos complement. 1: Offset binary. */
+#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
+#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
+#define ADIS16080_DIN_AIN1 (2 << 10)
+#define ADIS16080_DIN_AIN2 (3 << 10)
+#define ADIS16080_DIN_WRITE (1 << 15) /* 1: Write contents on DIN to control register.
+ * 0: No changes to control register.
+ */
+
+#define ADIS16080_MAX_TX 2
+#define ADIS16080_MAX_RX 2
+
+/**
+ * struct adis16080_state - device instance specific data
+ * @us: actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16080_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16080_scan {
+ ADIS16080_SCAN_GYRO,
+ ADIS16080_SCAN_TEMP,
+ ADIS16080_SCAN_ADC_1,
+ ADIS16080_SCAN_ADC_2,
+};
+
+void adis16080_remove_trigger(struct iio_dev *indio_dev);
+int adis16080_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16080_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int adis16080_configure_ring(struct iio_dev *indio_dev);
+void adis16080_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16080_initialize_ring(struct iio_ring_buffer *ring);
+void adis16080_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16080_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16080_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16080_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16080_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16080_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16080_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16080_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16080_H_ */
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
new file mode 100644
index 000000000000..0efb768db7d3
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -0,0 +1,271 @@
+/*
+ * ADIS16080/100 Yaw Rate Gyroscope with SPI driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16080.h"
+
+#define DRIVER_NAME "adis16080"
+
+struct adis16080_state *adis16080_st;
+
+int adis16080_spi_write(struct device *dev,
+ u16 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = val >> 8;
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+int adis16080_spi_read(struct device *dev,
+ u16 *val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+
+ ret = spi_read(st->us, st->rx, 2);
+
+ if (ret == 0)
+ *val = ((st->rx[0] & 0xF) << 8) | st->rx[1];
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static ssize_t adis16080_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ u16 val;
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16080_spi_read(dev, &val);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret == 0)
+ return sprintf(buf, "%d\n", val);
+ else
+ return ret;
+}
+
+static ssize_t adis16080_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 16, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16080_spi_write(dev, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_IN(_show) \
+ IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
+
+#define IIO_DEV_ATTR_OUT(_store) \
+ IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
+
+static IIO_DEV_ATTR_IN(adis16080_read);
+static IIO_DEV_ATTR_OUT(adis16080_write);
+
+static IIO_CONST_ATTR(name, "adis16080");
+
+static struct attribute *adis16080_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16080_event_attribute_group = {
+ .attrs = adis16080_event_attributes,
+};
+
+static struct attribute *adis16080_attributes[] = {
+ &iio_dev_attr_in.dev_attr.attr,
+ &iio_dev_attr_out.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16080_attribute_group = {
+ .attrs = adis16080_attributes,
+};
+
+static int __devinit adis16080_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16080_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16080_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16080_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16080_event_attribute_group;
+ st->indio_dev->attrs = &adis16080_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16080_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16080_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16080");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16080_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ adis16080_st = st;
+ return 0;
+
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16080_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16080_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16080_remove(struct spi_device *spi)
+{
+ struct adis16080_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16080_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16080_uninitialize_ring(indio_dev->ring);
+ adis16080_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver adis16080_driver = {
+ .driver = {
+ .name = "adis16080",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16080_probe,
+ .remove = __devexit_p(adis16080_remove),
+};
+
+static __init int adis16080_init(void)
+{
+ return spi_register_driver(&adis16080_driver);
+}
+module_init(adis16080_init);
+
+static __exit void adis16080_exit(void)
+{
+ spi_unregister_driver(&adis16080_driver);
+}
+module_exit(adis16080_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16130.h b/drivers/staging/iio/gyro/adis16130.h
new file mode 100644
index 000000000000..ab80ef6a8961
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16130.h
@@ -0,0 +1,108 @@
+#ifndef SPI_ADIS16130_H_
+#define SPI_ADIS16130_H_
+
+#define ADIS16130_CON 0x0
+#define ADIS16130_CON_RD (1 << 6)
+#define ADIS16130_IOP 0x1
+#define ADIS16130_IOP_ALL_RDY (1 << 3) /* 1 = data-ready signal low when unread data on all channels; */
+#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
+#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
+#define ADIS16130_TEMPDATA 0xA /* Temperature output */
+#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
+#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
+#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
+#define ADIS16130_TEMPCS_EN (1 << 3)
+#define ADIS16130_RATECONV 0x30
+#define ADIS16130_TEMPCONV 0x32
+#define ADIS16130_MODE 0x38
+#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
+
+#define ADIS16130_MAX_TX 4
+#define ADIS16130_MAX_RX 4
+
+/**
+ * struct adis16130_state - device instance specific data
+ * @us: actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16130_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ u32 mode; /* 1: 24bits mode 0:16bits mode */
+ struct mutex buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16130_scan {
+ ADIS16130_SCAN_GYRO,
+ ADIS16130_SCAN_TEMP,
+};
+
+void adis16130_remove_trigger(struct iio_dev *indio_dev);
+int adis16130_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16130_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int adis16130_configure_ring(struct iio_dev *indio_dev);
+void adis16130_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16130_initialize_ring(struct iio_ring_buffer *ring);
+void adis16130_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16130_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16130_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16130_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16130_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16130_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16130_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16130_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16130_H_ */
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
new file mode 100644
index 000000000000..49ffc7b26e8a
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -0,0 +1,313 @@
+/*
+ * ADIS16130 Digital Output, High Precision Angular Rate Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16130.h"
+
+#define DRIVER_NAME "adis16130"
+
+struct adis16130_state *adis16130_st;
+
+int adis16130_spi_write(struct device *dev, u8 reg_addr,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = reg_addr;
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+int adis16130_spi_read(struct device *dev, u8 reg_addr,
+ u32 *val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+
+ st->tx[0] = ADIS16130_CON_RD | reg_addr;
+ if (st->mode)
+ ret = spi_read(st->us, st->rx, 4);
+ else
+ ret = spi_read(st->us, st->rx, 3);
+
+ if (ret == 0) {
+ if (st->mode)
+ *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+ else
+ *val = (st->rx[1] << 8) | st->rx[2];
+ }
+
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static ssize_t adis16130_gyro_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ u32 val;
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16130_spi_read(dev, ADIS16130_RATEDATA, &val);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret == 0)
+ return sprintf(buf, "%d\n", val);
+ else
+ return ret;
+}
+
+static ssize_t adis16130_temp_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ u32 val;
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16130_spi_read(dev, ADIS16130_TEMPDATA, &val);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret == 0)
+ return sprintf(buf, "%d\n", val);
+ else
+ return ret;
+}
+
+static ssize_t adis16130_bitsmode_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+ return sprintf(buf, "%d\n", st->mode);
+}
+
+static ssize_t adis16130_bitsmode_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 16, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16130_spi_write(dev, ADIS16130_MODE, !!val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16130_temp_read);
+
+static IIO_CONST_ATTR(name, "adis16130");
+
+static IIO_DEV_ATTR_GYRO(adis16130_gyro_read,
+ ADIS16130_RATEDATA);
+
+#define IIO_DEV_ATTR_BITS_MODE(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bits_mode, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_BITS_MODE(S_IWUSR | S_IRUGO, adis16130_bitsmode_read, adis16130_bitsmode_write,
+ ADIS16130_MODE);
+
+static struct attribute *adis16130_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16130_event_attribute_group = {
+ .attrs = adis16130_event_attributes,
+};
+
+static struct attribute *adis16130_attributes[] = {
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_gyro_raw.dev_attr.attr,
+ &iio_dev_attr_bits_mode.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16130_attribute_group = {
+ .attrs = adis16130_attributes,
+};
+
+static int __devinit adis16130_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16130_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16130_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16130_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16130_event_attribute_group;
+ st->indio_dev->attrs = &adis16130_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+ st->mode = 1;
+
+ ret = adis16130_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16130_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16130");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16130_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ adis16130_st = st;
+ return 0;
+
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16130_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16130_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16130_remove(struct spi_device *spi)
+{
+ struct adis16130_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ adis16130_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16130_uninitialize_ring(indio_dev->ring);
+ adis16130_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver adis16130_driver = {
+ .driver = {
+ .name = "adis16130",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16130_probe,
+ .remove = __devexit_p(adis16130_remove),
+};
+
+static __init int adis16130_init(void)
+{
+ return spi_register_driver(&adis16130_driver);
+}
+module_init(adis16130_init);
+
+static __exit void adis16130_exit(void)
+{
+ spi_unregister_driver(&adis16130_driver);
+}
+module_exit(adis16130_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16251.h b/drivers/staging/iio/gyro/adis16251.h
new file mode 100644
index 000000000000..d23852cf78e8
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16251.h
@@ -0,0 +1,185 @@
+#ifndef SPI_ADIS16251_H_
+#define SPI_ADIS16251_H_
+
+#define ADIS16251_STARTUP_DELAY 220 /* ms */
+
+#define ADIS16251_READ_REG(a) a
+#define ADIS16251_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16251_ENDURANCE 0x00 /* Flash memory write count */
+#define ADIS16251_SUPPLY_OUT 0x02 /* Power supply measurement */
+#define ADIS16251_GYRO_OUT 0x04 /* X-axis gyroscope output */
+#define ADIS16251_AUX_ADC 0x0A /* analog input channel measurement */
+#define ADIS16251_TEMP_OUT 0x0C /* internal temperature measurement */
+#define ADIS16251_ANGL_OUT 0x0E /* angle displacement */
+#define ADIS16251_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */
+#define ADIS16251_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
+#define ADIS16251_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */
+#define ADIS16251_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */
+#define ADIS16251_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */
+#define ADIS16251_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */
+#define ADIS16251_ALM_CTRL 0x28 /* Alarm control */
+#define ADIS16251_AUX_DAC 0x30 /* Auxiliary DAC data */
+#define ADIS16251_GPIO_CTRL 0x32 /* Control, digital I/O line */
+#define ADIS16251_MSC_CTRL 0x34 /* Control, data ready, self-test settings */
+#define ADIS16251_SMPL_PRD 0x36 /* Control, internal sample rate */
+#define ADIS16251_SENS_AVG 0x38 /* Control, dynamic range, filtering */
+#define ADIS16251_SLP_CNT 0x3A /* Control, sleep mode initiation */
+#define ADIS16251_DIAG_STAT 0x3C /* Diagnostic, error flags */
+#define ADIS16251_GLOB_CMD 0x3E /* Control, global commands */
+
+#define ADIS16251_ERROR_ACTIVE (1<<14)
+#define ADIS16251_NEW_DATA (1<<14)
+
+/* MSC_CTRL */
+#define ADIS16251_MSC_CTRL_INT_SELF_TEST (1<<10) /* Internal self-test enable */
+#define ADIS16251_MSC_CTRL_NEG_SELF_TEST (1<<9)
+#define ADIS16251_MSC_CTRL_POS_SELF_TEST (1<<8)
+#define ADIS16251_MSC_CTRL_DATA_RDY_EN (1<<2)
+#define ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
+#define ADIS16251_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
+
+/* SMPL_PRD */
+#define ADIS16251_SMPL_PRD_TIME_BASE (1<<7) /* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
+#define ADIS16251_SMPL_PRD_DIV_MASK 0x7F
+
+/* SLP_CNT */
+#define ADIS16251_SLP_CNT_POWER_OFF 0x80
+
+/* DIAG_STAT */
+#define ADIS16251_DIAG_STAT_ALARM2 (1<<9)
+#define ADIS16251_DIAG_STAT_ALARM1 (1<<8)
+#define ADIS16251_DIAG_STAT_SELF_TEST (1<<5)
+#define ADIS16251_DIAG_STAT_OVERFLOW (1<<4)
+#define ADIS16251_DIAG_STAT_SPI_FAIL (1<<3)
+#define ADIS16251_DIAG_STAT_FLASH_UPT (1<<2)
+#define ADIS16251_DIAG_STAT_POWER_HIGH (1<<1)
+#define ADIS16251_DIAG_STAT_POWER_LOW (1<<0)
+
+#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16251_DIAG_STAT_ALARM2 | \
+ ADIS16251_DIAG_STAT_ALARM1 | \
+ ADIS16251_DIAG_STAT_SELF_TEST | \
+ ADIS16251_DIAG_STAT_OVERFLOW | \
+ ADIS16251_DIAG_STAT_SPI_FAIL | \
+ ADIS16251_DIAG_STAT_FLASH_UPT | \
+ ADIS16251_DIAG_STAT_POWER_HIGH | \
+ ADIS16251_DIAG_STAT_POWER_LOW)
+
+/* GLOB_CMD */
+#define ADIS16251_GLOB_CMD_SW_RESET (1<<7)
+#define ADIS16251_GLOB_CMD_FLASH_UPD (1<<3)
+#define ADIS16251_GLOB_CMD_DAC_LATCH (1<<2)
+#define ADIS16251_GLOB_CMD_FAC_CALIB (1<<1)
+#define ADIS16251_GLOB_CMD_AUTO_NULL (1<<0)
+
+#define ADIS16251_MAX_TX 24
+#define ADIS16251_MAX_RX 24
+
+#define ADIS16251_SPI_SLOW (u32)(300 * 1000)
+#define ADIS16251_SPI_BURST (u32)(1000 * 1000)
+#define ADIS16251_SPI_FAST (u32)(2000 * 1000)
+
+/**
+ * struct adis16251_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16251_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+
+int adis16251_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val);
+
+int adis16251_spi_read_burst(struct device *dev, u8 *rx);
+
+int adis16251_spi_read_sequence(struct device *dev,
+ u8 *tx, u8 *rx, int num);
+
+int adis16251_set_irq(struct device *dev, bool enable);
+
+int adis16251_reset(struct device *dev);
+
+int adis16251_stop_device(struct device *dev);
+
+int adis16251_check_status(struct device *dev);
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16251_scan {
+ ADIS16251_SCAN_SUPPLY,
+ ADIS16251_SCAN_GYRO,
+ ADIS16251_SCAN_TEMP,
+ ADIS16251_SCAN_ADC_0,
+};
+
+void adis16251_remove_trigger(struct iio_dev *indio_dev);
+int adis16251_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16251_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int adis16251_configure_ring(struct iio_dev *indio_dev);
+void adis16251_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16251_initialize_ring(struct iio_ring_buffer *ring);
+void adis16251_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16251_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16251_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+adis16251_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int adis16251_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void adis16251_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16251_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+
+static inline void adis16251_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16251_H_ */
diff --git a/drivers/staging/iio/gyro/adis16251_core.c b/drivers/staging/iio/gyro/adis16251_core.c
new file mode 100644
index 000000000000..a0d400f7ee62
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16251_core.c
@@ -0,0 +1,777 @@
+/*
+ * ADIS16251 Programmable Digital Gyroscope Sensor Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16251.h"
+
+#define DRIVER_NAME "adis16251"
+
+/* At the moment the spi framework doesn't allow global setting of cs_change.
+ * It's in the likely to be added comment at the top of spi.h.
+ * This means that use cannot be made of spi_write etc.
+ */
+
+/**
+ * adis16251_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+int adis16251_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16251_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16251_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16251_spi_write_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .tx_buf = st->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16251_WRITE_REG(lower_reg_address);
+ st->tx[1] = value & 0xFF;
+ st->tx[2] = ADIS16251_WRITE_REG(lower_reg_address + 1);
+ st->tx[3] = (value >> 8) & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/**
+ * adis16251_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ * is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16251_spi_read_reg_16(struct device *dev,
+ u8 lower_reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16251_READ_REG(lower_reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+ st->tx[3] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ lower_reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+/**
+ * adis16251_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+int adis16251_spi_read_burst(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+ u32 old_speed_hz = st->us->max_speed_hz;
+ int ret;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 0,
+ }, {
+ .rx_buf = rx,
+ .bits_per_word = 8,
+ .len = 24,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16251_READ_REG(ADIS16251_GLOB_CMD);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+
+ st->us->max_speed_hz = min(ADIS16251_SPI_BURST, old_speed_hz);
+ spi_setup(st->us);
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ st->us->max_speed_hz = old_speed_hz;
+ spi_setup(st->us);
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+/**
+ * adis16251_spi_read_sequence() - read a sequence of 16-bit registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @tx: register addresses in bytes 0,2,4,6... (min size is 2*num bytes)
+ * @rx: somewhere to pass back the value read (min size is 2*num bytes)
+ **/
+int adis16251_spi_read_sequence(struct device *dev,
+ u8 *tx, u8 *rx, int num)
+{
+ struct spi_message msg;
+ struct spi_transfer *xfers;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+ int ret, i;
+
+ xfers = kzalloc(num + 1, GFP_KERNEL);
+ if (xfers == NULL) {
+ dev_err(&st->us->dev, "memory alloc failed");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ /* tx: |add1|addr2|addr3|...|addrN |zero|
+ * rx: |zero|res1 |res2 |...|resN-1|resN| */
+ spi_message_init(&msg);
+ for (i = 0; i < num + 1; i++) {
+ if (i > 0)
+ xfers[i].rx_buf = st->rx + 2*(i - 1);
+ if (i < num)
+ xfers[i].tx_buf = st->tx + 2*i;
+ xfers[i].bits_per_word = 8;
+ xfers[i].len = 2;
+ xfers[i].cs_change = 1;
+ spi_message_add_tail(&xfers[i], &msg);
+ }
+
+ mutex_lock(&st->buf_lock);
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when reading sequence");
+
+ mutex_unlock(&st->buf_lock);
+ kfree(xfers);
+
+error_ret:
+ return ret;
+}
+
+static ssize_t adis16251_spi_read_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf,
+ unsigned bits)
+{
+ int ret;
+ s16 val = 0;
+ unsigned shift = 16 - bits;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16251_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16251_ERROR_ACTIVE)
+ adis16251_check_status(dev);
+ val = ((s16)(val << shift) >> shift);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adis16251_read_12bit_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16251_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16251_ERROR_ACTIVE)
+ adis16251_check_status(dev);
+
+ return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16251_read_14bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16251_spi_read_signed(dev, attr, buf, 14);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16251_read_12bit_signed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ ssize_t ret;
+
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16251_spi_read_signed(dev, attr, buf, 12);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static ssize_t adis16251_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = adis16251_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t adis16251_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u16 t;
+ int sps;
+ ret = adis16251_spi_read_reg_16(dev,
+ ADIS16251_SMPL_PRD,
+ &t);
+ if (ret)
+ return ret;
+ sps = (t & ADIS16251_SMPL_PRD_TIME_BASE) ? 8 : 256;
+ sps /= (t & ADIS16251_SMPL_PRD_DIV_MASK) + 1;
+ len = sprintf(buf, "%d SPS\n", sps);
+ return len;
+}
+
+static ssize_t adis16251_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+ long val;
+ int ret;
+ u8 t;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ t = (256 / val);
+ if (t > 0)
+ t--;
+ t &= ADIS16251_SMPL_PRD_DIV_MASK;
+ if ((t & ADIS16251_SMPL_PRD_DIV_MASK) >= 0x0A)
+ st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+ else
+ st->us->max_speed_hz = ADIS16251_SPI_FAST;
+
+ ret = adis16251_spi_write_reg_8(dev,
+ ADIS16251_SMPL_PRD,
+ t);
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t adis16251_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return adis16251_reset(dev);
+ }
+ return -1;
+}
+
+
+
+int adis16251_set_irq(struct device *dev, bool enable)
+{
+ int ret;
+ u16 msc;
+ ret = adis16251_spi_read_reg_16(dev, ADIS16251_MSC_CTRL, &msc);
+ if (ret)
+ goto error_ret;
+
+ msc |= ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH;
+ if (enable)
+ msc |= ADIS16251_MSC_CTRL_DATA_RDY_EN;
+ else
+ msc &= ~ADIS16251_MSC_CTRL_DATA_RDY_EN;
+
+ ret = adis16251_spi_write_reg_16(dev, ADIS16251_MSC_CTRL, msc);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+int adis16251_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16251_spi_write_reg_8(dev,
+ ADIS16251_GLOB_CMD,
+ ADIS16251_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
+/* Power down the device */
+int adis16251_stop_device(struct device *dev)
+{
+ int ret;
+ u16 val = ADIS16251_SLP_CNT_POWER_OFF;
+
+ ret = adis16251_spi_write_reg_16(dev, ADIS16251_SLP_CNT, val);
+ if (ret)
+ dev_err(dev, "problem with turning device off: SLP_CNT");
+
+ return ret;
+}
+
+static int adis16251_self_test(struct device *dev)
+{
+ int ret;
+
+ ret = adis16251_spi_write_reg_16(dev,
+ ADIS16251_MSC_CTRL,
+ ADIS16251_MSC_CTRL_INT_SELF_TEST);
+ if (ret) {
+ dev_err(dev, "problem starting self test");
+ goto err_ret;
+ }
+
+ adis16251_check_status(dev);
+
+err_ret:
+ return ret;
+}
+
+int adis16251_check_status(struct device *dev)
+{
+ u16 status;
+ int ret;
+
+ ret = adis16251_spi_read_reg_16(dev, ADIS16251_DIAG_STAT, &status);
+
+ if (ret < 0) {
+ dev_err(dev, "Reading status failed\n");
+ goto error_ret;
+ }
+
+ if (!(status & ADIS16251_DIAG_STAT_ERR_MASK)) {
+ ret = 0;
+ goto error_ret;
+ }
+
+ ret = -EFAULT;
+
+ if (status & ADIS16251_DIAG_STAT_ALARM2)
+ dev_err(dev, "Alarm 2 active\n");
+ if (status & ADIS16251_DIAG_STAT_ALARM1)
+ dev_err(dev, "Alarm 1 active\n");
+ if (status & ADIS16251_DIAG_STAT_SELF_TEST)
+ dev_err(dev, "Self test error\n");
+ if (status & ADIS16251_DIAG_STAT_OVERFLOW)
+ dev_err(dev, "Sensor overrange\n");
+ if (status & ADIS16251_DIAG_STAT_SPI_FAIL)
+ dev_err(dev, "SPI failure\n");
+ if (status & ADIS16251_DIAG_STAT_FLASH_UPT)
+ dev_err(dev, "Flash update failed\n");
+ if (status & ADIS16251_DIAG_STAT_POWER_HIGH)
+ dev_err(dev, "Power supply above 5.25V\n");
+ if (status & ADIS16251_DIAG_STAT_POWER_LOW)
+ dev_err(dev, "Power supply below 4.75V\n");
+
+error_ret:
+ return ret;
+}
+
+static int adis16251_initial_setup(struct adis16251_state *st)
+{
+ int ret;
+ u16 smp_prd;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* use low spi speed for init */
+ st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+ st->us->mode = SPI_MODE_3;
+ spi_setup(st->us);
+
+ /* Disable IRQ */
+ ret = adis16251_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ /* Do self test */
+
+ /* Read status register to check the result */
+ ret = adis16251_check_status(dev);
+ if (ret) {
+ adis16251_reset(dev);
+ dev_err(dev, "device not playing ball -> reset");
+ msleep(ADIS16251_STARTUP_DELAY);
+ ret = adis16251_check_status(dev);
+ if (ret) {
+ dev_err(dev, "giving up");
+ goto err_ret;
+ }
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+ st->us->chip_select, st->us->irq);
+
+ /* use high spi speed if possible */
+ ret = adis16251_spi_read_reg_16(dev, ADIS16251_SMPL_PRD, &smp_prd);
+ if (!ret && (smp_prd & ADIS16251_SMPL_PRD_DIV_MASK) < 0x0A) {
+ st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+ spi_setup(st->us);
+ }
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16251_read_12bit_signed,
+ ADIS16251_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.0018315");
+
+static IIO_DEV_ATTR_GYRO(adis16251_read_14bit_signed,
+ ADIS16251_GYRO_OUT);
+static IIO_DEV_ATTR_GYRO_SCALE(S_IWUSR | S_IRUGO,
+ adis16251_read_12bit_signed,
+ adis16251_write_16bit,
+ ADIS16251_GYRO_SCALE);
+static IIO_DEV_ATTR_GYRO_OFFSET(S_IWUSR | S_IRUGO,
+ adis16251_read_12bit_signed,
+ adis16251_write_16bit,
+ ADIS16251_GYRO_OFF);
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16251_read_12bit_signed);
+static IIO_CONST_ATTR(temp_offset, "25 K");
+static IIO_CONST_ATTR(temp_scale, "0.1453 K");
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(1, aux, adis16251_read_12bit_unsigned,
+ ADIS16251_AUX_ADC);
+static IIO_CONST_ATTR(in1_aux_scale, "0.0006105");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ adis16251_read_frequency,
+ adis16251_write_frequency);
+static IIO_DEV_ATTR_ANGL(adis16251_read_14bit_signed,
+ ADIS16251_ANGL_OUT);
+
+static IIO_DEV_ATTR_RESET(adis16251_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.129 ~ 256");
+
+static IIO_CONST_ATTR(name, "adis16251");
+
+static struct attribute *adis16251_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group adis16251_event_attribute_group = {
+ .attrs = adis16251_event_attributes,
+};
+
+static struct attribute *adis16251_attributes[] = {
+ &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+ &iio_const_attr_in0_supply_scale.dev_attr.attr,
+ &iio_dev_attr_gyro_raw.dev_attr.attr,
+ &iio_dev_attr_gyro_scale.dev_attr.attr,
+ &iio_dev_attr_gyro_offset.dev_attr.attr,
+ &iio_dev_attr_angl_raw.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_in1_aux_raw.dev_attr.attr,
+ &iio_const_attr_in1_aux_scale.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16251_attribute_group = {
+ .attrs = adis16251_attributes,
+};
+
+static int __devinit adis16251_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct adis16251_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADIS16251_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADIS16251_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &adis16251_event_attribute_group;
+ st->indio_dev->attrs = &adis16251_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis16251_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = adis16251_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ "adis16251");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = adis16251_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = adis16251_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ adis16251_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ adis16251_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ adis16251_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16251_remove(struct spi_device *spi)
+{
+ int ret;
+ struct adis16251_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ ret = adis16251_stop_device(&(indio_dev->dev));
+ if (ret)
+ goto err_ret;
+
+ flush_scheduled_work();
+
+ adis16251_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ adis16251_uninitialize_ring(indio_dev->ring);
+ adis16251_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+
+err_ret:
+ return ret;
+}
+
+static struct spi_driver adis16251_driver = {
+ .driver = {
+ .name = "adis16251",
+ .owner = THIS_MODULE,
+ },
+ .probe = adis16251_probe,
+ .remove = __devexit_p(adis16251_remove),
+};
+
+static __init int adis16251_init(void)
+{
+ return spi_register_driver(&adis16251_driver);
+}
+module_init(adis16251_init);
+
+static __exit void adis16251_exit(void)
+{
+ spi_unregister_driver(&adis16251_driver);
+}
+module_exit(adis16251_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h
index 812440af57d6..c1fd4364287f 100644
--- a/drivers/staging/iio/gyro/adis16260.h
+++ b/drivers/staging/iio/gyro/adis16260.h
@@ -1,5 +1,6 @@
#ifndef SPI_ADIS16260_H_
#define SPI_ADIS16260_H_
+#include "adis16260_platform_data.h"
#define ADIS16260_STARTUP_DELAY 220 /* ms */
@@ -92,6 +93,7 @@
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
+ * @negate: negate the scale parameter
**/
struct adis16260_state {
struct spi_device *us;
@@ -102,6 +104,7 @@ struct adis16260_state {
u8 *tx;
u8 *rx;
struct mutex buf_lock;
+ unsigned negate:1;
};
int adis16260_set_irq(struct device *dev, bool enable);
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 7d7716e5857c..045e27da980a 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -1,5 +1,5 @@
/*
- * ADIS16260 Programmable Digital Gyroscope Sensor Driver
+ * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver
*
* Copyright 2010 Analog Devices Inc.
*
@@ -134,8 +134,6 @@ static int adis16260_spi_read_reg_16(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16260_READ_REG(lower_reg_address);
st->tx[1] = 0;
- st->tx[2] = 0;
- st->tx[3] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
@@ -293,6 +291,22 @@ static ssize_t adis16260_write_frequency(struct device *dev,
return ret ? ret : len;
}
+static ssize_t adis16260_read_gyro_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16260_state *st = iio_dev_get_devdata(indio_dev);
+ ssize_t ret = 0;
+
+ if (st->negate)
+ ret = sprintf(buf, "-");
+ /* Take the iio_dev status lock */
+ ret += sprintf(buf + ret, "%s\n", "0.00127862821");
+
+ return ret;
+}
+
static int adis16260_reset(struct device *dev)
{
int ret;
@@ -447,18 +461,6 @@ static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply,
ADIS16260_SUPPLY_OUT);
static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.0018315");
-static IIO_DEV_ATTR_GYRO(adis16260_read_14bit_signed,
- ADIS16260_GYRO_OUT);
-static IIO_CONST_ATTR_GYRO_SCALE("0.00127862821");
-static IIO_DEV_ATTR_GYRO_CALIBSCALE(S_IWUSR | S_IRUGO,
- adis16260_read_14bit_signed,
- adis16260_write_16bit,
- ADIS16260_GYRO_SCALE);
-static IIO_DEV_ATTR_GYRO_CALIBBIAS(S_IWUSR | S_IRUGO,
- adis16260_read_12bit_signed,
- adis16260_write_16bit,
- ADIS16260_GYRO_OFF);
-
static IIO_DEV_ATTR_TEMP_RAW(adis16260_read_12bit_unsigned);
static IIO_CONST_ATTR_TEMP_OFFSET("25");
static IIO_CONST_ATTR_TEMP_SCALE("0.1453");
@@ -470,8 +472,6 @@ static IIO_CONST_ATTR(in1_scale, "0.0006105");
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16260_read_frequency,
adis16260_write_frequency);
-static IIO_DEV_ATTR_ANGL(adis16260_read_14bit_signed,
- ADIS16260_ANGL_OUT);
static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16260_write_reset, 0);
@@ -487,38 +487,70 @@ static struct attribute_group adis16260_event_attribute_group = {
.attrs = adis16260_event_attributes,
};
-static struct attribute *adis16260_attributes[] = {
- &iio_dev_attr_in0_supply_raw.dev_attr.attr,
- &iio_const_attr_in0_supply_scale.dev_attr.attr,
- &iio_dev_attr_gyro_raw.dev_attr.attr,
- &iio_const_attr_gyro_scale.dev_attr.attr,
- &iio_dev_attr_gyro_calibscale.dev_attr.attr,
- &iio_dev_attr_gyro_calibbias.dev_attr.attr,
- &iio_dev_attr_angl_raw.dev_attr.attr,
- &iio_dev_attr_temp_raw.dev_attr.attr,
- &iio_const_attr_temp_offset.dev_attr.attr,
- &iio_const_attr_temp_scale.dev_attr.attr,
- &iio_dev_attr_in1_raw.dev_attr.attr,
- &iio_const_attr_in1_scale.dev_attr.attr,
- &iio_dev_attr_sampling_frequency.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
- &iio_const_attr_name.dev_attr.attr,
- NULL
-};
+#define ADIS16260_GYRO_ATTR_SET(axis) \
+ IIO_DEV_ATTR_GYRO##axis(adis16260_read_14bit_signed, \
+ ADIS16260_GYRO_OUT); \
+ static IIO_DEV_ATTR_GYRO##axis##_SCALE(S_IRUGO, \
+ adis16260_read_gyro_scale, \
+ NULL, \
+ 0); \
+ static IIO_DEV_ATTR_GYRO##axis##_CALIBSCALE(S_IRUGO | S_IWUSR, \
+ adis16260_read_12bit_unsigned, \
+ adis16260_write_16bit, \
+ ADIS16260_GYRO_SCALE); \
+ static IIO_DEV_ATTR_GYRO##axis##_CALIBBIAS(S_IWUSR | S_IRUGO, \
+ adis16260_read_12bit_signed, \
+ adis16260_write_16bit, \
+ ADIS16260_GYRO_OFF); \
+ static IIO_DEV_ATTR_ANGL##axis(adis16260_read_14bit_signed, \
+ ADIS16260_ANGL_OUT);
+
+static ADIS16260_GYRO_ATTR_SET();
+static ADIS16260_GYRO_ATTR_SET(_X);
+static ADIS16260_GYRO_ATTR_SET(_Y);
+static ADIS16260_GYRO_ATTR_SET(_Z);
+
+#define ADIS16260_ATTR_GROUP(axis) \
+ struct attribute *adis16260_attributes##axis[] = { \
+ &iio_dev_attr_in0_supply_raw.dev_attr.attr, \
+ &iio_const_attr_in0_supply_scale.dev_attr.attr, \
+ &iio_dev_attr_gyro##axis##_raw.dev_attr.attr, \
+ &iio_dev_attr_gyro##axis##_scale.dev_attr.attr, \
+ &iio_dev_attr_gyro##axis##_calibscale.dev_attr.attr, \
+ &iio_dev_attr_gyro##axis##_calibbias.dev_attr.attr, \
+ &iio_dev_attr_angl##axis##_raw.dev_attr.attr, \
+ &iio_dev_attr_temp_raw.dev_attr.attr, \
+ &iio_const_attr_temp_offset.dev_attr.attr, \
+ &iio_const_attr_temp_scale.dev_attr.attr, \
+ &iio_dev_attr_in1_raw.dev_attr.attr, \
+ &iio_const_attr_in1_scale.dev_attr.attr, \
+ &iio_dev_attr_sampling_frequency.dev_attr.attr, \
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr, \
+ &iio_dev_attr_reset.dev_attr.attr, \
+ &iio_const_attr_name.dev_attr.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group adis16260_attribute_group##axis \
+ = { \
+ .attrs = adis16260_attributes##axis, \
+ };
-static const struct attribute_group adis16260_attribute_group = {
- .attrs = adis16260_attributes,
-};
+static ADIS16260_ATTR_GROUP();
+static ADIS16260_ATTR_GROUP(_x);
+static ADIS16260_ATTR_GROUP(_y);
+static ADIS16260_ATTR_GROUP(_z);
static int __devinit adis16260_probe(struct spi_device *spi)
{
int ret, regdone = 0;
+ struct adis16260_platform_data *pd = spi->dev.platform_data;
struct adis16260_state *st = kzalloc(sizeof *st, GFP_KERNEL);
if (!st) {
ret = -ENOMEM;
goto error_ret;
}
+ if (pd)
+ st->negate = pd->negate;
/* this is only used for removal purposes */
spi_set_drvdata(spi, st);
@@ -545,7 +577,24 @@ static int __devinit adis16260_probe(struct spi_device *spi)
st->indio_dev->dev.parent = &spi->dev;
st->indio_dev->num_interrupt_lines = 1;
st->indio_dev->event_attrs = &adis16260_event_attribute_group;
- st->indio_dev->attrs = &adis16260_attribute_group;
+ if (pd && pd->direction)
+ switch (pd->direction) {
+ case 'x':
+ st->indio_dev->attrs = &adis16260_attribute_group_x;
+ break;
+ case 'y':
+ st->indio_dev->attrs = &adis16260_attribute_group_y;
+ break;
+ case 'z':
+ st->indio_dev->attrs = &adis16260_attribute_group_z;
+ break;
+ default:
+ st->indio_dev->attrs = &adis16260_attribute_group;
+ break;
+ }
+ else
+ st->indio_dev->attrs = &adis16260_attribute_group;
+
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
@@ -635,6 +684,18 @@ err_ret:
return ret;
}
+/*
+ * These parts do not need to be differentiated until someone adds
+ * support for the on chip filtering.
+ */
+static const struct spi_device_id adis16260_id[] = {
+ {"adis16260", 0},
+ {"adis16265", 0},
+ {"adis16250", 0},
+ {"adis16255", 0},
+ {}
+};
+
static struct spi_driver adis16260_driver = {
.driver = {
.name = "adis16260",
@@ -642,6 +703,7 @@ static struct spi_driver adis16260_driver = {
},
.probe = adis16260_probe,
.remove = __devexit_p(adis16260_remove),
+ .id_table = adis16260_id,
};
static __init int adis16260_init(void)
diff --git a/drivers/staging/iio/gyro/adis16260_platform_data.h b/drivers/staging/iio/gyro/adis16260_platform_data.h
new file mode 100644
index 000000000000..12802e97be92
--- /dev/null
+++ b/drivers/staging/iio/gyro/adis16260_platform_data.h
@@ -0,0 +1,19 @@
+/*
+ * ADIS16260 Programmable Digital Gyroscope Sensor Driver Platform Data
+ *
+ * Based on adis16255.h Matthia Brugger <m_brugger&web.de>
+ *
+ * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * struct adis16260_platform_data - instance specific data
+ * @direction: x y or z
+ * @negate: flag to indicate value should be inverted.
+ **/
+struct adis16260_platform_data {
+ char direction;
+ unsigned negate:1;
+};
diff --git a/drivers/staging/iio/gyro/gyro.h b/drivers/staging/iio/gyro/gyro.h
index 98b837b775a2..b4ea5bf161ff 100644
--- a/drivers/staging/iio/gyro/gyro.h
+++ b/drivers/staging/iio/gyro/gyro.h
@@ -71,3 +71,12 @@
#define IIO_DEV_ATTR_ANGL(_show, _addr) \
IIO_DEVICE_ATTR(angl_raw, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGL_X(_show, _addr) \
+ IIO_DEVICE_ATTR(angl_x_raw, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGL_Y(_show, _addr) \
+ IIO_DEVICE_ATTR(angl_y_raw, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGL_Z(_show, _addr) \
+ IIO_DEVICE_ATTR(angl_z_raw, S_IRUGO, _show, NULL, _addr)
diff --git a/drivers/staging/iio/imu/adis16350_core.c b/drivers/staging/iio/imu/adis16350_core.c
index 97c1ec8594ce..cf7176bc766b 100644
--- a/drivers/staging/iio/imu/adis16350_core.c
+++ b/drivers/staging/iio/imu/adis16350_core.c
@@ -570,6 +570,7 @@ static struct attribute *adis16350_attributes[] = {
&iio_dev_attr_temp_y_raw.dev_attr.attr,
&iio_dev_attr_temp_z_raw.dev_attr.attr,
&iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
&iio_dev_attr_in1_raw.dev_attr.attr,
&iio_const_attr_in1_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig
new file mode 100644
index 000000000000..12e36e460693
--- /dev/null
+++ b/drivers/staging/iio/meter/Kconfig
@@ -0,0 +1,61 @@
+#
+# IIO meter drivers configuration
+#
+comment "Active energy metering IC"
+
+config ADE7753
+ tristate "Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction
+ Metering IC with di/dt Sensor Interface.
+
+config ADE7754
+ tristate "Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADE7754 Polyphase
+ Multifunction Energy Metering IC Driver.
+
+config ADE7758
+ tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices ADE7758 Polyphase
+ Multifunction Energy Metering IC with Per Phase Information Driver.
+
+config ADE7759
+ tristate "Analog Devices ADE7759 Active Energy Metering IC Driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADE7758 Active Energy
+ Metering IC with di/dt Sensor Interface.
+
+config ADE7854
+ tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver"
+ depends on SPI || I2C
+ help
+ Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase
+ Multifunction Energy Metering IC Driver.
+
+config ADE7854_I2C
+ tristate "support I2C bus connection"
+ depends on ADE7854 && I2C
+ default y
+ help
+ Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ade7854-i2c.
+
+config ADE7854_SPI
+ tristate "support SPI bus connection"
+ depends on ADE7854 && SPI
+ default y
+ help
+ Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ade7854-spi.
diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile
new file mode 100644
index 000000000000..0cc7d5140dfe
--- /dev/null
+++ b/drivers/staging/iio/meter/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for metering ic drivers
+#
+
+obj-$(CONFIG_ADE7753) += ade7753.o
+obj-$(CONFIG_ADE7754) += ade7754.o
+
+ade7758-y := ade7758_core.o
+ade7758-$(CONFIG_IIO_RING_BUFFER) += ade7758_ring.o ade7758_trigger.o
+obj-$(CONFIG_ADE7758) += ade7758.o
+
+obj-$(CONFIG_ADE7759) += ade7759.o
+obj-$(CONFIG_ADE7854) += ade7854.o
+obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o
+obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
new file mode 100644
index 000000000000..e72afbd2b841
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -0,0 +1,730 @@
+/*
+ * ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7753.h"
+
+int ade7753_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7753_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7753_spi_write_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7753_WRITE_REG(reg_address);
+ st->tx[1] = (value >> 8) & 0xFF;
+ st->tx[2] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7753_spi_read_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7753_READ_REG(reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7753_spi_read_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 3,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7753_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7753_spi_read_reg_24(struct device *dev,
+ u8 reg_address,
+ u32 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 4,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7753_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+ st->tx[3] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t ade7753_read_8bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7753_spi_read_reg_8(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7753_read_16bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7753_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7753_read_24bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7753_spi_read_reg_24(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7753_write_8bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7753_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7753_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7753_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int ade7753_reset(struct device *dev)
+{
+ int ret;
+ u16 val;
+ ade7753_spi_read_reg_16(dev,
+ ADE7753_MODE,
+ &val);
+ val |= 1 << 6; /* Software Chip Reset */
+ ret = ade7753_spi_write_reg_16(dev,
+ ADE7753_MODE,
+ val);
+
+ return ret;
+}
+
+static ssize_t ade7753_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return ade7753_reset(dev);
+ }
+ return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
+static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
+static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
+static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_CFDEN);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_CFNUM);
+static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM);
+static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_PHCAL);
+static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_APOS);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_SAGCYC);
+static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_SAGLVL);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_LINECYC);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_WDIV);
+static IIO_DEV_ATTR_IRMS(S_IWUSR | S_IRUGO,
+ ade7753_read_24bit,
+ NULL,
+ ADE7753_IRMS);
+static IIO_DEV_ATTR_VRMS(S_IRUGO,
+ ade7753_read_24bit,
+ NULL,
+ ADE7753_VRMS);
+static IIO_DEV_ATTR_IRMSOS(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_IRMSOS);
+static IIO_DEV_ATTR_VRMSOS(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_VRMSOS);
+static IIO_DEV_ATTR_WGAIN(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_WGAIN);
+static IIO_DEV_ATTR_VAGAIN(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_VAGAIN);
+static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+ ade7753_read_16bit,
+ ade7753_write_16bit,
+ ADE7753_GAIN);
+static IIO_DEV_ATTR_IPKLVL(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_IPKLVL);
+static IIO_DEV_ATTR_VPKLVL(S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_VPKLVL);
+static IIO_DEV_ATTR_IPEAK(S_IRUGO,
+ ade7753_read_24bit,
+ NULL,
+ ADE7753_IPEAK);
+static IIO_DEV_ATTR_VPEAK(S_IRUGO,
+ ade7753_read_24bit,
+ NULL,
+ ADE7753_VPEAK);
+static IIO_DEV_ATTR_VPERIOD(S_IRUGO,
+ ade7753_read_16bit,
+ NULL,
+ ADE7753_PERIOD);
+static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_CH1OS);
+static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_CH2OS);
+
+static int ade7753_set_irq(struct device *dev, bool enable)
+{
+ int ret;
+ u8 irqen;
+ ret = ade7753_spi_read_reg_8(dev, ADE7753_IRQEN, &irqen);
+ if (ret)
+ goto error_ret;
+
+ if (enable)
+ irqen |= 1 << 3; /* Enables an interrupt when a data is
+ present in the waveform register */
+ else
+ irqen &= ~(1 << 3);
+
+ ret = ade7753_spi_write_reg_8(dev, ADE7753_IRQEN, irqen);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+/* Power down the device */
+int ade7753_stop_device(struct device *dev)
+{
+ int ret;
+ u16 val;
+ ade7753_spi_read_reg_16(dev,
+ ADE7753_MODE,
+ &val);
+ val |= 1 << 4; /* AD converters can be turned off */
+ ret = ade7753_spi_write_reg_16(dev,
+ ADE7753_MODE,
+ val);
+
+ return ret;
+}
+
+static int ade7753_initial_setup(struct ade7753_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* use low spi speed for init */
+ st->us->mode = SPI_MODE_3;
+ spi_setup(st->us);
+
+ /* Disable IRQ */
+ ret = ade7753_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ ade7753_reset(dev);
+ msleep(ADE7753_STARTUP_DELAY);
+
+err_ret:
+ return ret;
+}
+
+static ssize_t ade7753_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u8 t;
+ int sps;
+ ret = ade7753_spi_read_reg_8(dev,
+ ADE7753_MODE,
+ &t);
+ if (ret)
+ return ret;
+
+ t = (t >> 11) & 0x3;
+ sps = 27900 / (1 + t);
+
+ len = sprintf(buf, "%d SPS\n", sps);
+ return len;
+}
+
+static ssize_t ade7753_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+ unsigned long val;
+ int ret;
+ u16 reg, t;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ t = (27900 / val);
+ if (t > 0)
+ t--;
+
+ if (t > 1)
+ st->us->max_speed_hz = ADE7753_SPI_SLOW;
+ else
+ st->us->max_speed_hz = ADE7753_SPI_FAST;
+
+ ret = ade7753_spi_read_reg_16(dev,
+ ADE7753_MODE,
+ &reg);
+ if (ret)
+ goto out;
+
+ reg &= ~(3 << 11);
+ reg |= t << 11;
+
+ ret = ade7753_spi_write_reg_16(dev,
+ ADE7753_MODE,
+ reg);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "-25 C");
+static IIO_CONST_ATTR(temp_scale, "0.67 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ ade7753_read_frequency,
+ ade7753_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7753_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
+
+static IIO_CONST_ATTR(name, "ade7753");
+
+static struct attribute *ade7753_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group ade7753_event_attribute_group = {
+ .attrs = ade7753_event_attributes,
+};
+
+static struct attribute *ade7753_attributes[] = {
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_phcal.dev_attr.attr,
+ &iio_dev_attr_cfden.dev_attr.attr,
+ &iio_dev_attr_aenergy.dev_attr.attr,
+ &iio_dev_attr_laenergy.dev_attr.attr,
+ &iio_dev_attr_vaenergy.dev_attr.attr,
+ &iio_dev_attr_lvaenergy.dev_attr.attr,
+ &iio_dev_attr_cfnum.dev_attr.attr,
+ &iio_dev_attr_apos.dev_attr.attr,
+ &iio_dev_attr_sagcyc.dev_attr.attr,
+ &iio_dev_attr_saglvl.dev_attr.attr,
+ &iio_dev_attr_linecyc.dev_attr.attr,
+ &iio_dev_attr_chksum.dev_attr.attr,
+ &iio_dev_attr_pga_gain.dev_attr.attr,
+ &iio_dev_attr_wgain.dev_attr.attr,
+ &iio_dev_attr_choff_1.dev_attr.attr,
+ &iio_dev_attr_choff_2.dev_attr.attr,
+ &iio_dev_attr_wdiv.dev_attr.attr,
+ &iio_dev_attr_irms.dev_attr.attr,
+ &iio_dev_attr_vrms.dev_attr.attr,
+ &iio_dev_attr_irmsos.dev_attr.attr,
+ &iio_dev_attr_vrmsos.dev_attr.attr,
+ &iio_dev_attr_vagain.dev_attr.attr,
+ &iio_dev_attr_ipklvl.dev_attr.attr,
+ &iio_dev_attr_vpklvl.dev_attr.attr,
+ &iio_dev_attr_ipeak.dev_attr.attr,
+ &iio_dev_attr_vpeak.dev_attr.attr,
+ &iio_dev_attr_vperiod.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7753_attribute_group = {
+ .attrs = ade7753_attributes,
+};
+
+static int __devinit ade7753_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct ade7753_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADE7753_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADE7753_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &ade7753_event_attribute_group;
+ st->indio_dev->attrs = &ade7753_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ade7753_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = ade7753_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ade7753");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = ade7753_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = ade7753_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ ade7753_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ ade7753_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ ade7753_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7753_remove(struct spi_device *spi)
+{
+ int ret;
+ struct ade7753_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ ret = ade7753_stop_device(&(indio_dev->dev));
+ if (ret)
+ goto err_ret;
+
+ flush_scheduled_work();
+
+ ade7753_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ ade7753_uninitialize_ring(indio_dev->ring);
+ ade7753_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+
+err_ret:
+ return ret;
+}
+
+static struct spi_driver ade7753_driver = {
+ .driver = {
+ .name = "ade7753",
+ .owner = THIS_MODULE,
+ },
+ .probe = ade7753_probe,
+ .remove = __devexit_p(ade7753_remove),
+};
+
+static __init int ade7753_init(void)
+{
+ return spi_register_driver(&ade7753_driver);
+}
+module_init(ade7753_init);
+
+static __exit void ade7753_exit(void)
+{
+ spi_unregister_driver(&ade7753_driver);
+}
+module_exit(ade7753_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h
new file mode 100644
index 000000000000..a3722b8c90fa
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7753.h
@@ -0,0 +1,140 @@
+#ifndef _ADE7753_H
+#define _ADE7753_H
+
+#define ADE7753_WAVEFORM 0x01
+#define ADE7753_AENERGY 0x02
+#define ADE7753_RAENERGY 0x03
+#define ADE7753_LAENERGY 0x04
+#define ADE7753_VAENERGY 0x05
+#define ADE7753_RVAENERGY 0x06
+#define ADE7753_LVAENERGY 0x07
+#define ADE7753_LVARENERGY 0x08
+#define ADE7753_MODE 0x09
+#define ADE7753_IRQEN 0x0A
+#define ADE7753_STATUS 0x0B
+#define ADE7753_RSTSTATUS 0x0C
+#define ADE7753_CH1OS 0x0D
+#define ADE7753_CH2OS 0x0E
+#define ADE7753_GAIN 0x0F
+#define ADE7753_PHCAL 0x10
+#define ADE7753_APOS 0x11
+#define ADE7753_WGAIN 0x12
+#define ADE7753_WDIV 0x13
+#define ADE7753_CFNUM 0x14
+#define ADE7753_CFDEN 0x15
+#define ADE7753_IRMS 0x16
+#define ADE7753_VRMS 0x17
+#define ADE7753_IRMSOS 0x18
+#define ADE7753_VRMSOS 0x19
+#define ADE7753_VAGAIN 0x1A
+#define ADE7753_VADIV 0x1B
+#define ADE7753_LINECYC 0x1C
+#define ADE7753_ZXTOUT 0x1D
+#define ADE7753_SAGCYC 0x1E
+#define ADE7753_SAGLVL 0x1F
+#define ADE7753_IPKLVL 0x20
+#define ADE7753_VPKLVL 0x21
+#define ADE7753_IPEAK 0x22
+#define ADE7753_RSTIPEAK 0x23
+#define ADE7753_VPEAK 0x24
+#define ADE7753_RSTVPEAK 0x25
+#define ADE7753_TEMP 0x26
+#define ADE7753_PERIOD 0x27
+#define ADE7753_TMODE 0x3D
+#define ADE7753_CHKSUM 0x3E
+#define ADE7753_DIEREV 0x3F
+
+#define ADE7753_READ_REG(a) a
+#define ADE7753_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7753_MAX_TX 4
+#define ADE7753_MAX_RX 4
+#define ADE7753_STARTUP_DELAY 1
+
+#define ADE7753_SPI_SLOW (u32)(300 * 1000)
+#define ADE7753_SPI_BURST (u32)(1000 * 1000)
+#define ADE7753_SPI_FAST (u32)(2000 * 1000)
+
+#define DRIVER_NAME "ade7753"
+
+/**
+ * struct ade7753_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct ade7753_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7753_scan {
+ ADE7753_SCAN_ACTIVE_POWER,
+ ADE7753_SCAN_CH1,
+ ADE7753_SCAN_CH2,
+};
+
+void ade7753_remove_trigger(struct iio_dev *indio_dev);
+int ade7753_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7753_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int ade7753_configure_ring(struct iio_dev *indio_dev);
+void ade7753_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7753_initialize_ring(struct iio_ring_buffer *ring);
+void ade7753_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7753_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7753_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+ade7753_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int ade7753_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void ade7753_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7753_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+static inline void ade7753_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
new file mode 100644
index 000000000000..23dedfa7a270
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -0,0 +1,756 @@
+/*
+ * ADE7754 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7754.h"
+
+static int ade7754_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7754_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7754_spi_write_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7754_WRITE_REG(reg_address);
+ st->tx[1] = (value >> 8) & 0xFF;
+ st->tx[2] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7754_spi_read_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7754_READ_REG(reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7754_spi_read_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 3,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7754_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7754_spi_read_reg_24(struct device *dev,
+ u8 reg_address,
+ u32 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 4,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7754_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+ st->tx[3] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t ade7754_read_8bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7754_spi_read_reg_8(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7754_read_16bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7754_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7754_read_24bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7754_spi_read_reg_24(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7754_write_8bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7754_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7754_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7754_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int ade7754_reset(struct device *dev)
+{
+ int ret;
+ u8 val;
+ ade7754_spi_read_reg_8(dev,
+ ADE7754_OPMODE,
+ &val);
+ val |= 1 << 6; /* Software Chip Reset */
+ ret = ade7754_spi_write_reg_8(dev,
+ ADE7754_OPMODE,
+ val);
+
+ return ret;
+}
+
+
+static ssize_t ade7754_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return ade7754_reset(dev);
+ }
+ return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
+static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
+static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
+static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY);
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_CPHCAL);
+static IIO_DEV_ATTR_AAPOS(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_AAPOS);
+static IIO_DEV_ATTR_BAPOS(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_BAPOS);
+static IIO_DEV_ATTR_CAPOS(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CAPOS);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_WDIV);
+static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+ ade7754_read_8bit,
+ ade7754_write_8bit,
+ ADE7754_VADIV);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CFNUM);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CFDEN);
+static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_AAPGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_BAPGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CAPGAIN);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_CIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+ ade7754_read_24bit,
+ NULL,
+ ADE7754_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+ ade7754_read_16bit,
+ ade7754_write_16bit,
+ ADE7754_CVRMSOS);
+
+static int ade7754_set_irq(struct device *dev, bool enable)
+{
+ int ret;
+ u16 irqen;
+ ret = ade7754_spi_read_reg_16(dev, ADE7754_IRQEN, &irqen);
+ if (ret)
+ goto error_ret;
+
+ if (enable)
+ irqen |= 1 << 14; /* Enables an interrupt when a data is
+ present in the waveform register */
+ else
+ irqen &= ~(1 << 14);
+
+ ret = ade7754_spi_write_reg_16(dev, ADE7754_IRQEN, irqen);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+/* Power down the device */
+static int ade7754_stop_device(struct device *dev)
+{
+ int ret;
+ u8 val;
+ ade7754_spi_read_reg_8(dev,
+ ADE7754_OPMODE,
+ &val);
+ val |= 7 << 3; /* ADE7754 powered down */
+ ret = ade7754_spi_write_reg_8(dev,
+ ADE7754_OPMODE,
+ val);
+
+ return ret;
+}
+
+static int ade7754_initial_setup(struct ade7754_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* use low spi speed for init */
+ st->us->mode = SPI_MODE_3;
+ spi_setup(st->us);
+
+ /* Disable IRQ */
+ ret = ade7754_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ ade7754_reset(dev);
+ msleep(ADE7754_STARTUP_DELAY);
+
+err_ret:
+ return ret;
+}
+
+static ssize_t ade7754_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u8 t;
+ int sps;
+ ret = ade7754_spi_read_reg_8(dev,
+ ADE7754_WAVMODE,
+ &t);
+ if (ret)
+ return ret;
+
+ t = (t >> 3) & 0x3;
+ sps = 26000 / (1 + t);
+
+ len = sprintf(buf, "%d SPS\n", sps);
+ return len;
+}
+
+static ssize_t ade7754_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+ unsigned long val;
+ int ret;
+ u8 reg, t;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ t = (26000 / val);
+ if (t > 0)
+ t--;
+
+ if (t > 1)
+ st->us->max_speed_hz = ADE7754_SPI_SLOW;
+ else
+ st->us->max_speed_hz = ADE7754_SPI_FAST;
+
+ ret = ade7754_spi_read_reg_8(dev,
+ ADE7754_WAVMODE,
+ &reg);
+ if (ret)
+ goto out;
+
+ reg &= ~(3 << 3);
+ reg |= t << 3;
+
+ ret = ade7754_spi_write_reg_8(dev,
+ ADE7754_WAVMODE,
+ reg);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "129 C");
+static IIO_CONST_ATTR(temp_scale, "4 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ ade7754_read_frequency,
+ ade7754_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7754_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
+
+static IIO_CONST_ATTR(name, "ade7754");
+
+static struct attribute *ade7754_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group ade7754_event_attribute_group = {
+ .attrs = ade7754_event_attributes,
+};
+
+static struct attribute *ade7754_attributes[] = {
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_aenergy.dev_attr.attr,
+ &iio_dev_attr_laenergy.dev_attr.attr,
+ &iio_dev_attr_vaenergy.dev_attr.attr,
+ &iio_dev_attr_lvaenergy.dev_attr.attr,
+ &iio_dev_attr_vpeak.dev_attr.attr,
+ &iio_dev_attr_ipeak.dev_attr.attr,
+ &iio_dev_attr_aphcal.dev_attr.attr,
+ &iio_dev_attr_bphcal.dev_attr.attr,
+ &iio_dev_attr_cphcal.dev_attr.attr,
+ &iio_dev_attr_aapos.dev_attr.attr,
+ &iio_dev_attr_bapos.dev_attr.attr,
+ &iio_dev_attr_capos.dev_attr.attr,
+ &iio_dev_attr_wdiv.dev_attr.attr,
+ &iio_dev_attr_vadiv.dev_attr.attr,
+ &iio_dev_attr_cfnum.dev_attr.attr,
+ &iio_dev_attr_cfden.dev_attr.attr,
+ &iio_dev_attr_active_power_a_gain.dev_attr.attr,
+ &iio_dev_attr_active_power_b_gain.dev_attr.attr,
+ &iio_dev_attr_active_power_c_gain.dev_attr.attr,
+ &iio_dev_attr_airms.dev_attr.attr,
+ &iio_dev_attr_birms.dev_attr.attr,
+ &iio_dev_attr_cirms.dev_attr.attr,
+ &iio_dev_attr_avrms.dev_attr.attr,
+ &iio_dev_attr_bvrms.dev_attr.attr,
+ &iio_dev_attr_cvrms.dev_attr.attr,
+ &iio_dev_attr_airmsos.dev_attr.attr,
+ &iio_dev_attr_birmsos.dev_attr.attr,
+ &iio_dev_attr_cirmsos.dev_attr.attr,
+ &iio_dev_attr_avrmsos.dev_attr.attr,
+ &iio_dev_attr_bvrmsos.dev_attr.attr,
+ &iio_dev_attr_cvrmsos.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7754_attribute_group = {
+ .attrs = ade7754_attributes,
+};
+
+
+
+static int __devinit ade7754_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct ade7754_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADE7754_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADE7754_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &ade7754_event_attribute_group;
+ st->indio_dev->attrs = &ade7754_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ade7754_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = ade7754_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ade7754");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = ade7754_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = ade7754_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ ade7754_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ ade7754_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ ade7754_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7754_remove(struct spi_device *spi)
+{
+ int ret;
+ struct ade7754_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ ret = ade7754_stop_device(&(indio_dev->dev));
+ if (ret)
+ goto err_ret;
+
+ flush_scheduled_work();
+
+ ade7754_remove_trigger(indio_dev);
+ if (spi->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ ade7754_uninitialize_ring(indio_dev->ring);
+ ade7754_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+
+err_ret:
+ return ret;
+}
+
+static struct spi_driver ade7754_driver = {
+ .driver = {
+ .name = "ade7754",
+ .owner = THIS_MODULE,
+ },
+ .probe = ade7754_probe,
+ .remove = __devexit_p(ade7754_remove),
+};
+
+static __init int ade7754_init(void)
+{
+ return spi_register_driver(&ade7754_driver);
+}
+module_init(ade7754_init);
+
+static __exit void ade7754_exit(void)
+{
+ spi_unregister_driver(&ade7754_driver);
+}
+module_exit(ade7754_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7754.h b/drivers/staging/iio/meter/ade7754.h
new file mode 100644
index 000000000000..f6a3e4b926cf
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7754.h
@@ -0,0 +1,161 @@
+#ifndef _ADE7754_H
+#define _ADE7754_H
+
+#define ADE7754_AENERGY 0x01
+#define ADE7754_RAENERGY 0x02
+#define ADE7754_LAENERGY 0x03
+#define ADE7754_VAENERGY 0x04
+#define ADE7754_RVAENERGY 0x05
+#define ADE7754_LVAENERGY 0x06
+#define ADE7754_PERIOD 0x07
+#define ADE7754_TEMP 0x08
+#define ADE7754_WFORM 0x09
+#define ADE7754_OPMODE 0x0A
+#define ADE7754_MMODE 0x0B
+#define ADE7754_WAVMODE 0x0C
+#define ADE7754_WATMODE 0x0D
+#define ADE7754_VAMODE 0x0E
+#define ADE7754_IRQEN 0x0F
+#define ADE7754_STATUS 0x10
+#define ADE7754_RSTATUS 0x11
+#define ADE7754_ZXTOUT 0x12
+#define ADE7754_LINCYC 0x13
+#define ADE7754_SAGCYC 0x14
+#define ADE7754_SAGLVL 0x15
+#define ADE7754_VPEAK 0x16
+#define ADE7754_IPEAK 0x17
+#define ADE7754_GAIN 0x18
+#define ADE7754_AWG 0x19
+#define ADE7754_BWG 0x1A
+#define ADE7754_CWG 0x1B
+#define ADE7754_AVAG 0x1C
+#define ADE7754_BVAG 0x1D
+#define ADE7754_CVAG 0x1E
+#define ADE7754_APHCAL 0x1F
+#define ADE7754_BPHCAL 0x20
+#define ADE7754_CPHCAL 0x21
+#define ADE7754_AAPOS 0x22
+#define ADE7754_BAPOS 0x23
+#define ADE7754_CAPOS 0x24
+#define ADE7754_CFNUM 0x25
+#define ADE7754_CFDEN 0x26
+#define ADE7754_WDIV 0x27
+#define ADE7754_VADIV 0x28
+#define ADE7754_AIRMS 0x29
+#define ADE7754_BIRMS 0x2A
+#define ADE7754_CIRMS 0x2B
+#define ADE7754_AVRMS 0x2C
+#define ADE7754_BVRMS 0x2D
+#define ADE7754_CVRMS 0x2E
+#define ADE7754_AIRMSOS 0x2F
+#define ADE7754_BIRMSOS 0x30
+#define ADE7754_CIRMSOS 0x31
+#define ADE7754_AVRMSOS 0x32
+#define ADE7754_BVRMSOS 0x33
+#define ADE7754_CVRMSOS 0x34
+#define ADE7754_AAPGAIN 0x35
+#define ADE7754_BAPGAIN 0x36
+#define ADE7754_CAPGAIN 0x37
+#define ADE7754_AVGAIN 0x38
+#define ADE7754_BVGAIN 0x39
+#define ADE7754_CVGAIN 0x3A
+#define ADE7754_CHKSUM 0x3E
+#define ADE7754_VERSION 0x3F
+
+#define ADE7754_READ_REG(a) a
+#define ADE7754_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7754_MAX_TX 4
+#define ADE7754_MAX_RX 4
+#define ADE7754_STARTUP_DELAY 1
+
+#define ADE7754_SPI_SLOW (u32)(300 * 1000)
+#define ADE7754_SPI_BURST (u32)(1000 * 1000)
+#define ADE7754_SPI_FAST (u32)(2000 * 1000)
+
+#define DRIVER_NAME "ade7754"
+
+/**
+ * struct ade7754_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct ade7754_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7754_scan {
+ ADE7754_SCAN_PHA_V,
+ ADE7754_SCAN_PHB_V,
+ ADE7754_SCAN_PHC_V,
+ ADE7754_SCAN_PHA_I,
+ ADE7754_SCAN_PHB_I,
+ ADE7754_SCAN_PHC_I,
+};
+
+void ade7754_remove_trigger(struct iio_dev *indio_dev);
+int ade7754_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7754_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int ade7754_configure_ring(struct iio_dev *indio_dev);
+void ade7754_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7754_initialize_ring(struct iio_ring_buffer *ring);
+void ade7754_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7754_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7754_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+ade7754_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int ade7754_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void ade7754_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7754_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+static inline void ade7754_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
new file mode 100644
index 000000000000..df5bb7ba5a0f
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -0,0 +1,171 @@
+#ifndef _ADE7758_H
+#define _ADE7758_H
+
+#define ADE7758_AWATTHR 0x01
+#define ADE7758_BWATTHR 0x02
+#define ADE7758_CWATTHR 0x03
+#define ADE7758_AVARHR 0x04
+#define ADE7758_BVARHR 0x05
+#define ADE7758_CVARHR 0x06
+#define ADE7758_AVAHR 0x07
+#define ADE7758_BVAHR 0x08
+#define ADE7758_CVAHR 0x09
+#define ADE7758_AIRMS 0x0A
+#define ADE7758_BIRMS 0x0B
+#define ADE7758_CIRMS 0x0C
+#define ADE7758_AVRMS 0x0D
+#define ADE7758_BVRMS 0x0E
+#define ADE7758_CVRMS 0x0F
+#define ADE7758_FREQ 0x10
+#define ADE7758_TEMP 0x11
+#define ADE7758_WFORM 0x12
+#define ADE7758_OPMODE 0x13
+#define ADE7758_MMODE 0x14
+#define ADE7758_WAVMODE 0x15
+#define ADE7758_COMPMODE 0x16
+#define ADE7758_LCYCMODE 0x17
+#define ADE7758_MASK 0x18
+#define ADE7758_STATUS 0x19
+#define ADE7758_RSTATUS 0x1A
+#define ADE7758_ZXTOUT 0x1B
+#define ADE7758_LINECYC 0x1C
+#define ADE7758_SAGCYC 0x1D
+#define ADE7758_SAGLVL 0x1E
+#define ADE7758_VPINTLVL 0x1F
+#define ADE7758_IPINTLVL 0x20
+#define ADE7758_VPEAK 0x21
+#define ADE7758_IPEAK 0x22
+#define ADE7758_GAIN 0x23
+#define ADE7758_AVRMSGAIN 0x24
+#define ADE7758_BVRMSGAIN 0x25
+#define ADE7758_CVRMSGAIN 0x26
+#define ADE7758_AIGAIN 0x27
+#define ADE7758_BIGAIN 0x28
+#define ADE7758_CIGAIN 0x29
+#define ADE7758_AWG 0x2A
+#define ADE7758_BWG 0x2B
+#define ADE7758_CWG 0x2C
+#define ADE7758_AVARG 0x2D
+#define ADE7758_BVARG 0x2E
+#define ADE7758_CVARG 0x2F
+#define ADE7758_AVAG 0x30
+#define ADE7758_BVAG 0x31
+#define ADE7758_CVAG 0x32
+#define ADE7758_AVRMSOS 0x33
+#define ADE7758_BVRMSOS 0x34
+#define ADE7758_CVRMSOS 0x35
+#define ADE7758_AIRMSOS 0x36
+#define ADE7758_BIRMSOS 0x37
+#define ADE7758_CIRMSOS 0x38
+#define ADE7758_AWAITOS 0x39
+#define ADE7758_BWAITOS 0x3A
+#define ADE7758_CWAITOS 0x3B
+#define ADE7758_AVAROS 0x3C
+#define ADE7758_BVAROS 0x3D
+#define ADE7758_CVAROS 0x3E
+#define ADE7758_APHCAL 0x3F
+#define ADE7758_BPHCAL 0x40
+#define ADE7758_CPHCAL 0x41
+#define ADE7758_WDIV 0x42
+#define ADE7758_VADIV 0x44
+#define ADE7758_VARDIV 0x43
+#define ADE7758_APCFNUM 0x45
+#define ADE7758_APCFDEN 0x46
+#define ADE7758_VARCFNUM 0x47
+#define ADE7758_VARCFDEN 0x48
+#define ADE7758_CHKSUM 0x7E
+#define ADE7758_VERSION 0x7F
+
+#define ADE7758_READ_REG(a) a
+#define ADE7758_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7758_MAX_TX 8
+#define ADE7758_MAX_RX 4
+#define ADE7758_STARTUP_DELAY 1
+
+#define ADE7758_SPI_SLOW (u32)(300 * 1000)
+#define ADE7758_SPI_BURST (u32)(1000 * 1000)
+#define ADE7758_SPI_FAST (u32)(2000 * 1000)
+
+#define DRIVER_NAME "ade7758"
+
+/**
+ * struct ade7758_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct ade7758_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+#ifdef CONFIG_IIO_RING_BUFFER
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7758_scan {
+ ADE7758_SCAN_WFORM,
+};
+
+void ade7758_remove_trigger(struct iio_dev *indio_dev);
+int ade7758_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7758_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int ade7758_configure_ring(struct iio_dev *indio_dev);
+void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7758_initialize_ring(struct iio_ring_buffer *ring);
+void ade7758_uninitialize_ring(struct iio_ring_buffer *ring);
+int ade7758_set_irq(struct device *dev, bool enable);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7758_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7758_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+ade7758_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int ade7758_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7758_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+static inline void ade7758_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
new file mode 100644
index 000000000000..b7634cb7aa4f
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -0,0 +1,866 @@
+/*
+ * ADE7758 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7758.h"
+
+int ade7758_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7758_spi_write_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_WRITE_REG(reg_address);
+ st->tx[1] = (value >> 8) & 0xFF;
+ st->tx[2] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7758_spi_write_reg_24(struct device *dev,
+ u8 reg_address,
+ u32 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 4,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_WRITE_REG(reg_address);
+ st->tx[1] = (value >> 16) & 0xFF;
+ st->tx[2] = (value >> 8) & 0xFF;
+ st->tx[3] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7758_spi_read_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_READ_REG(reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7758_spi_read_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 3,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7758_spi_read_reg_24(struct device *dev,
+ u8 reg_address,
+ u32 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 4,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+ st->tx[3] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t ade7758_read_8bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7758_spi_read_reg_8(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7758_read_16bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7758_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7758_read_24bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7758_spi_read_reg_24(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7758_write_8bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7758_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7758_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7758_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+int ade7758_reset(struct device *dev)
+{
+ int ret;
+ u8 val;
+ ade7758_spi_read_reg_8(dev,
+ ADE7758_OPMODE,
+ &val);
+ val |= 1 << 6; /* Software Chip Reset */
+ ret = ade7758_spi_write_reg_8(dev,
+ ADE7758_OPMODE,
+ val);
+
+ return ret;
+}
+
+static ssize_t ade7758_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return ade7758_reset(dev);
+ }
+ return -1;
+}
+
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_CPHCAL);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_WDIV);
+static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+ ade7758_read_8bit,
+ ade7758_write_8bit,
+ ADE7758_VADIV);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_CIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+ ade7758_read_24bit,
+ NULL,
+ ADE7758_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_CVRMSOS);
+static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_AIGAIN);
+static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_BIGAIN);
+static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_CIGAIN);
+static IIO_DEV_ATTR_AVRMSGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_AVRMSGAIN);
+static IIO_DEV_ATTR_BVRMSGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_BVRMSGAIN);
+static IIO_DEV_ATTR_CVRMSGAIN(S_IWUSR | S_IRUGO,
+ ade7758_read_16bit,
+ ade7758_write_16bit,
+ ADE7758_CVRMSGAIN);
+
+int ade7758_set_irq(struct device *dev, bool enable)
+{
+ int ret;
+ u32 irqen;
+ ret = ade7758_spi_read_reg_24(dev, ADE7758_MASK, &irqen);
+ if (ret)
+ goto error_ret;
+
+ if (enable)
+ irqen |= 1 << 16; /* Enables an interrupt when a data is
+ present in the waveform register */
+ else
+ irqen &= ~(1 << 16);
+
+ ret = ade7758_spi_write_reg_24(dev, ADE7758_MASK, irqen);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+/* Power down the device */
+static int ade7758_stop_device(struct device *dev)
+{
+ int ret;
+ u8 val;
+ ade7758_spi_read_reg_8(dev,
+ ADE7758_OPMODE,
+ &val);
+ val |= 7 << 3; /* ADE7758 powered down */
+ ret = ade7758_spi_write_reg_8(dev,
+ ADE7758_OPMODE,
+ val);
+
+ return ret;
+}
+
+static int ade7758_initial_setup(struct ade7758_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* use low spi speed for init */
+ st->us->mode = SPI_MODE_3;
+ spi_setup(st->us);
+
+ /* Disable IRQ */
+ ret = ade7758_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ ade7758_reset(dev);
+ msleep(ADE7758_STARTUP_DELAY);
+
+err_ret:
+ return ret;
+}
+
+static ssize_t ade7758_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u8 t;
+ int sps;
+ ret = ade7758_spi_read_reg_8(dev,
+ ADE7758_WAVMODE,
+ &t);
+ if (ret)
+ return ret;
+
+ t = (t >> 5) & 0x3;
+ sps = 26040 / (1 << t);
+
+ len = sprintf(buf, "%d SPS\n", sps);
+ return len;
+}
+
+static ssize_t ade7758_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ unsigned long val;
+ int ret;
+ u8 reg, t;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ t = (26040 / val);
+ if (t > 0)
+ t >>= 1;
+
+ if (t > 1)
+ st->us->max_speed_hz = ADE7758_SPI_SLOW;
+ else
+ st->us->max_speed_hz = ADE7758_SPI_FAST;
+
+ ret = ade7758_spi_read_reg_8(dev,
+ ADE7758_WAVMODE,
+ &reg);
+ if (ret)
+ goto out;
+
+ reg &= ~(5 << 3);
+ reg |= t << 5;
+
+ ret = ade7758_spi_write_reg_8(dev,
+ ADE7758_WAVMODE,
+ reg);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ade7758_read_waveform_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u8 t;
+ ret = ade7758_spi_read_reg_8(dev,
+ ADE7758_WAVMODE,
+ &t);
+ if (ret)
+ return ret;
+
+ t = (t >> 2) & 0x7;
+
+ len = sprintf(buf, "%d\n", t);
+
+ return len;
+}
+
+static ssize_t ade7758_write_waveform_type(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ unsigned long val;
+ int ret;
+ u8 reg;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val > 4)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = ade7758_spi_read_reg_8(dev,
+ ADE7758_WAVMODE,
+ &reg);
+ if (ret)
+ goto out;
+
+ reg &= ~(7 << 2);
+ reg |= val << 2;
+
+ ret = ade7758_spi_write_reg_8(dev,
+ ADE7758_WAVMODE,
+ reg);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "129 C");
+static IIO_CONST_ATTR(temp_scale, "4 C");
+
+static IIO_DEV_ATTR_AWATTHR(ade7758_read_16bit,
+ ADE7758_AWATTHR);
+static IIO_DEV_ATTR_BWATTHR(ade7758_read_16bit,
+ ADE7758_BWATTHR);
+static IIO_DEV_ATTR_CWATTHR(ade7758_read_16bit,
+ ADE7758_CWATTHR);
+static IIO_DEV_ATTR_AVARHR(ade7758_read_16bit,
+ ADE7758_AVARHR);
+static IIO_DEV_ATTR_BVARHR(ade7758_read_16bit,
+ ADE7758_BVARHR);
+static IIO_DEV_ATTR_CVARHR(ade7758_read_16bit,
+ ADE7758_CVARHR);
+static IIO_DEV_ATTR_AVAHR(ade7758_read_16bit,
+ ADE7758_AVAHR);
+static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit,
+ ADE7758_BVAHR);
+static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit,
+ ADE7758_CVAHR);
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ ade7758_read_frequency,
+ ade7758_write_frequency);
+
+/**
+ * IIO_DEV_ATTR_WAVEFORM_TYPE - set the type of waveform.
+ * @_mode: sysfs file mode/permissions
+ * @_show: output method for the attribute
+ * @_store: input method for the attribute
+ **/
+#define IIO_DEV_ATTR_WAVEFORM_TYPE(_mode, _show, _store) \
+ IIO_DEVICE_ATTR(waveform_type, _mode, _show, _store, 0)
+
+static IIO_DEV_ATTR_WAVEFORM_TYPE(S_IWUSR | S_IRUGO,
+ ade7758_read_waveform_type,
+ ade7758_write_waveform_type);
+
+static IIO_DEV_ATTR_RESET(ade7758_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
+
+static IIO_CONST_ATTR(name, "ade7758");
+
+static struct attribute *ade7758_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group ade7758_event_attribute_group = {
+ .attrs = ade7758_event_attributes,
+};
+
+static struct attribute *ade7758_attributes[] = {
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_dev_attr_waveform_type.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_awatthr.dev_attr.attr,
+ &iio_dev_attr_bwatthr.dev_attr.attr,
+ &iio_dev_attr_cwatthr.dev_attr.attr,
+ &iio_dev_attr_avarhr.dev_attr.attr,
+ &iio_dev_attr_bvarhr.dev_attr.attr,
+ &iio_dev_attr_cvarhr.dev_attr.attr,
+ &iio_dev_attr_avahr.dev_attr.attr,
+ &iio_dev_attr_bvahr.dev_attr.attr,
+ &iio_dev_attr_cvahr.dev_attr.attr,
+ &iio_dev_attr_vpeak.dev_attr.attr,
+ &iio_dev_attr_ipeak.dev_attr.attr,
+ &iio_dev_attr_aphcal.dev_attr.attr,
+ &iio_dev_attr_bphcal.dev_attr.attr,
+ &iio_dev_attr_cphcal.dev_attr.attr,
+ &iio_dev_attr_wdiv.dev_attr.attr,
+ &iio_dev_attr_vadiv.dev_attr.attr,
+ &iio_dev_attr_airms.dev_attr.attr,
+ &iio_dev_attr_birms.dev_attr.attr,
+ &iio_dev_attr_cirms.dev_attr.attr,
+ &iio_dev_attr_avrms.dev_attr.attr,
+ &iio_dev_attr_bvrms.dev_attr.attr,
+ &iio_dev_attr_cvrms.dev_attr.attr,
+ &iio_dev_attr_aigain.dev_attr.attr,
+ &iio_dev_attr_bigain.dev_attr.attr,
+ &iio_dev_attr_cigain.dev_attr.attr,
+ &iio_dev_attr_avrmsgain.dev_attr.attr,
+ &iio_dev_attr_bvrmsgain.dev_attr.attr,
+ &iio_dev_attr_cvrmsgain.dev_attr.attr,
+ &iio_dev_attr_airmsos.dev_attr.attr,
+ &iio_dev_attr_birmsos.dev_attr.attr,
+ &iio_dev_attr_cirmsos.dev_attr.attr,
+ &iio_dev_attr_avrmsos.dev_attr.attr,
+ &iio_dev_attr_bvrmsos.dev_attr.attr,
+ &iio_dev_attr_cvrmsos.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7758_attribute_group = {
+ .attrs = ade7758_attributes,
+};
+
+
+
+static int __devinit ade7758_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct ade7758_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADE7758_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADE7758_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &ade7758_event_attribute_group;
+ st->indio_dev->attrs = &ade7758_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ade7758_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = ade7758_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ade7758");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = ade7758_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = ade7758_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ ade7758_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ ade7758_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ ade7758_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int ade7758_remove(struct spi_device *spi)
+{
+ int ret;
+ struct ade7758_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ ret = ade7758_stop_device(&(indio_dev->dev));
+ if (ret)
+ goto err_ret;
+
+ flush_scheduled_work();
+
+ ade7758_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ ade7758_uninitialize_ring(indio_dev->ring);
+ iio_device_unregister(indio_dev);
+ ade7758_unconfigure_ring(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+
+err_ret:
+ return ret;
+}
+
+static struct spi_driver ade7758_driver = {
+ .driver = {
+ .name = "ade7758",
+ .owner = THIS_MODULE,
+ },
+ .probe = ade7758_probe,
+ .remove = __devexit_p(ade7758_remove),
+};
+
+static __init int ade7758_init(void)
+{
+ return spi_register_driver(&ade7758_driver);
+}
+module_init(ade7758_init);
+
+static __exit void ade7758_exit(void)
+{
+ spi_unregister_driver(&ade7758_driver);
+}
+module_exit(ade7758_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
new file mode 100644
index 000000000000..274b4a07808c
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -0,0 +1,212 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "../accel/accel.h"
+#include "../trigger.h"
+#include "ade7758.h"
+
+/**
+ * combine_8_to_32() utility function to munge to u8s into u32
+ **/
+static inline u32 combine_8_to_32(u8 lower, u8 mid, u8 upper)
+{
+ u32 _lower = lower;
+ u32 _mid = mid;
+ u32 _upper = upper;
+
+ return _lower | (_mid << 8) | (_upper << 16);
+}
+
+static IIO_SCAN_EL_C(wform, ADE7758_SCAN_WFORM, ADE7758_WFORM, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(wform, s, 24, 32);
+static IIO_SCAN_EL_TIMESTAMP(1);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *ade7758_scan_el_attrs[] = {
+ &iio_scan_el_wform.dev_attr.attr,
+ &iio_const_attr_wform_index.dev_attr.attr,
+ &iio_const_attr_wform_type.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ade7758_scan_el_group = {
+ .attrs = ade7758_scan_el_attrs,
+ .name = "scan_elements",
+};
+
+/**
+ * ade7758_poll_func_th() top half interrupt handler called by trigger
+ * @private_data: iio_dev
+ **/
+static void ade7758_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ st->last_timestamp = time;
+ schedule_work(&st->work_trigger_to_ring);
+ /* Indicate that this interrupt is being handled */
+
+ /* Technically this is trigger related, but without this
+ * handler running there is currently no way for the interrupt
+ * to clear.
+ */
+}
+
+/**
+ * ade7758_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+static int ade7758_spi_read_burst(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = rx,
+ .bits_per_word = 8,
+ .len = 4,
+ }, {
+ .tx_buf = st->tx + 4,
+ .rx_buf = rx,
+ .bits_per_word = 8,
+ .len = 4,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7758_READ_REG(ADE7758_RSTATUS);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+ st->tx[3] = 0;
+ st->tx[4] = ADE7758_READ_REG(ADE7758_WFORM);
+ st->tx[5] = 0;
+ st->tx[6] = 0;
+ st->tx[7] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when reading WFORM value\n");
+
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void ade7758_trigger_bh_to_ring(struct work_struct *work_s)
+{
+ struct ade7758_state *st
+ = container_of(work_s, struct ade7758_state,
+ work_trigger_to_ring);
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+ int i = 0;
+ s32 *data;
+ size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+ data = kmalloc(datasize, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&st->us->dev, "memory alloc failed in ring bh");
+ return;
+ }
+
+ if (ring->scan_count)
+ if (ade7758_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0)
+ for (; i < ring->scan_count; i++)
+ data[i] = combine_8_to_32(st->rx[i*2+2],
+ st->rx[i*2+1],
+ st->rx[i*2]);
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (ring->scan_timestamp)
+ *((s64 *)
+ (((u32)data + 4 * ring->scan_count + 4) & ~0x7)) =
+ st->last_timestamp;
+
+ ring->access.store_to(ring,
+ (u8 *)data,
+ st->last_timestamp);
+
+ iio_trigger_notify_done(st->indio_dev->trig);
+ kfree(data);
+
+ return;
+}
+
+void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
+{
+ kfree(indio_dev->pollfunc);
+ iio_sw_rb_free(indio_dev->ring);
+}
+
+int ade7758_configure_ring(struct iio_dev *indio_dev)
+{
+ int ret = 0;
+ struct ade7758_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring;
+ INIT_WORK(&st->work_trigger_to_ring, ade7758_trigger_bh_to_ring);
+
+ ring = iio_sw_rb_allocate(indio_dev);
+ if (!ring) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ indio_dev->ring = ring;
+ /* Effectively select the ring buffer implementation */
+ iio_ring_sw_register_funcs(&ring->access);
+ ring->bpe = 4;
+ ring->scan_el_attrs = &ade7758_scan_el_group;
+ ring->scan_timestamp = true;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
+ ring->owner = THIS_MODULE;
+
+ /* Set default scan mode */
+ iio_scan_mask_set(ring, iio_scan_el_wform.number);
+
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ade7758_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
+ indio_dev->modes |= INDIO_RING_TRIGGERED;
+ return 0;
+
+error_iio_sw_rb_free:
+ iio_sw_rb_free(indio_dev->ring);
+ return ret;
+}
+
+int ade7758_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return iio_ring_buffer_register(ring, 0);
+}
+
+void ade7758_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+ iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
new file mode 100644
index 000000000000..60abca0c28ff
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -0,0 +1,125 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "ade7758.h"
+
+/**
+ * ade7758_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int ade7758_data_rdy_trig_poll(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int no_test)
+{
+ struct ade7758_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_trigger *trig = st->trig;
+
+ iio_trigger_poll(trig, timestamp);
+
+ return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &ade7758_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *ade7758_trigger_attrs[] = {
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7758_trigger_attr_group = {
+ .attrs = ade7758_trigger_attrs,
+};
+
+/**
+ * ade7758_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct ade7758_state *st = trig->private_data;
+ struct iio_dev *indio_dev = st->indio_dev;
+ int ret = 0;
+
+ dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+ ret = ade7758_set_irq(&st->indio_dev->dev, state);
+ if (state == false) {
+ iio_remove_event_from_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]
+ ->ev_list);
+ /* possible quirk with handler currently worked around
+ by ensuring the work queue is empty */
+ flush_scheduled_work();
+ } else {
+ iio_add_event_to_list(&iio_event_data_rdy_trig,
+ &indio_dev->interrupts[0]->ev_list);
+ }
+ return ret;
+}
+
+/**
+ * ade7758_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig: the datardy trigger
+ **/
+static int ade7758_trig_try_reen(struct iio_trigger *trig)
+{
+ struct ade7758_state *st = trig->private_data;
+ enable_irq(st->us->irq);
+ /* irq reenabled so success! */
+ return 0;
+}
+
+int ade7758_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct ade7758_state *st = indio_dev->dev_data;
+
+ st->trig = iio_allocate_trigger();
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "ade7758-dev%d",
+ indio_dev->id);
+ if (!st->trig->name) {
+ ret = -ENOMEM;
+ goto error_free_trig;
+ }
+ st->trig->dev.parent = &st->us->dev;
+ st->trig->owner = THIS_MODULE;
+ st->trig->private_data = st;
+ st->trig->set_trigger_state = &ade7758_data_rdy_trigger_set_state;
+ st->trig->try_reenable = &ade7758_trig_try_reen;
+ st->trig->control_attrs = &ade7758_trigger_attr_group;
+ ret = iio_trigger_register(st->trig);
+
+ /* select default trigger */
+ indio_dev->trig = st->trig;
+ if (ret)
+ goto error_free_trig_name;
+
+ return 0;
+
+error_free_trig_name:
+ kfree(st->trig->name);
+error_free_trig:
+ iio_free_trigger(st->trig);
+
+ return ret;
+}
+
+void ade7758_remove_trigger(struct iio_dev *indio_dev)
+{
+ struct ade7758_state *state = indio_dev->dev_data;
+
+ iio_trigger_unregister(state->trig);
+ kfree(state->trig->name);
+ iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
new file mode 100644
index 000000000000..fafc3c1e5aaa
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -0,0 +1,670 @@
+/*
+ * ADE7759 Active Energy Metering IC with di/dt Sensor Interface Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7759.h"
+
+int ade7759_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7759_WRITE_REG(reg_address);
+ st->tx[1] = val;
+
+ ret = spi_write(st->us, st->tx, 2);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7759_spi_write_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7759_WRITE_REG(reg_address);
+ st->tx[1] = (value >> 8) & 0xFF;
+ st->tx[2] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7759_spi_read_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7759_READ_REG(reg_address);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = st->rx[1];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7759_spi_read_reg_16(struct device *dev,
+ u8 reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 3,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7759_READ_REG(reg_address);
+ st->tx[1] = 0;
+ st->tx[2] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7759_spi_read_reg_40(struct device *dev,
+ u8 reg_address,
+ u64 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 6,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7759_READ_REG(reg_address);
+ memset(&st->tx[1], 0 , 5);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->us, &msg);
+ if (ret) {
+ dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = ((u64)st->rx[1] << 32) | (st->rx[2] << 24) |
+ (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static ssize_t ade7759_read_8bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7759_spi_read_reg_8(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7759_read_16bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7759_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7759_read_40bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u64 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = ade7759_spi_read_reg_40(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t ade7759_write_8bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7759_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7759_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = ade7759_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int ade7759_reset(struct device *dev)
+{
+ int ret;
+ u16 val;
+ ade7759_spi_read_reg_16(dev,
+ ADE7759_MODE,
+ &val);
+ val |= 1 << 6; /* Software Chip Reset */
+ ret = ade7759_spi_write_reg_16(dev,
+ ADE7759_MODE,
+ val);
+
+ return ret;
+}
+
+static ssize_t ade7759_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return ade7759_reset(dev);
+ }
+ return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+ ade7759_read_16bit,
+ ade7759_write_16bit,
+ ADE7759_CFDEN);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_CFNUM);
+static IIO_DEV_ATTR_CHKSUM(ade7759_read_8bit, ADE7759_CHKSUM);
+static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+ ade7759_read_16bit,
+ ade7759_write_16bit,
+ ADE7759_PHCAL);
+static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+ ade7759_read_16bit,
+ ade7759_write_16bit,
+ ADE7759_APOS);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_SAGCYC);
+static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_SAGLVL);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_LINECYC);
+static IIO_DEV_ATTR_LENERGY(ade7759_read_40bit, ADE7759_LENERGY);
+static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_GAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(S_IWUSR | S_IRUGO,
+ ade7759_read_16bit,
+ ade7759_write_16bit,
+ ADE7759_APGAIN);
+static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_CH1OS);
+static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_CH2OS);
+
+static int ade7759_set_irq(struct device *dev, bool enable)
+{
+ int ret;
+ u8 irqen;
+ ret = ade7759_spi_read_reg_8(dev, ADE7759_IRQEN, &irqen);
+ if (ret)
+ goto error_ret;
+
+ if (enable)
+ irqen |= 1 << 3; /* Enables an interrupt when a data is
+ present in the waveform register */
+ else
+ irqen &= ~(1 << 3);
+
+ ret = ade7759_spi_write_reg_8(dev, ADE7759_IRQEN, irqen);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+/* Power down the device */
+int ade7759_stop_device(struct device *dev)
+{
+ int ret;
+ u16 val;
+ ade7759_spi_read_reg_16(dev,
+ ADE7759_MODE,
+ &val);
+ val |= 1 << 4; /* AD converters can be turned off */
+ ret = ade7759_spi_write_reg_16(dev,
+ ADE7759_MODE,
+ val);
+
+ return ret;
+}
+
+static int ade7759_initial_setup(struct ade7759_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* use low spi speed for init */
+ st->us->mode = SPI_MODE_3;
+ spi_setup(st->us);
+
+ /* Disable IRQ */
+ ret = ade7759_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ ade7759_reset(dev);
+ msleep(ADE7759_STARTUP_DELAY);
+
+err_ret:
+ return ret;
+}
+
+static ssize_t ade7759_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret, len = 0;
+ u16 t;
+ int sps;
+ ret = ade7759_spi_read_reg_16(dev,
+ ADE7759_MODE,
+ &t);
+ if (ret)
+ return ret;
+
+ t = (t >> 3) & 0x3;
+ sps = 27900 / (1 + t);
+
+ len = sprintf(buf, "%d SPS\n", sps);
+ return len;
+}
+
+static ssize_t ade7759_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+ unsigned long val;
+ int ret;
+ u16 reg, t;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ t = (27900 / val);
+ if (t > 0)
+ t--;
+
+ if (t > 1)
+ st->us->max_speed_hz = ADE7759_SPI_SLOW;
+ else
+ st->us->max_speed_hz = ADE7759_SPI_FAST;
+
+ ret = ade7759_spi_read_reg_16(dev,
+ ADE7759_MODE,
+ &reg);
+ if (ret)
+ goto out;
+
+ reg &= ~(3 << 13);
+ reg |= t << 13;
+
+ ret = ade7759_spi_write_reg_16(dev,
+ ADE7759_MODE,
+ reg);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7759_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "70 C");
+static IIO_CONST_ATTR(temp_scale, "1 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ ade7759_read_frequency,
+ ade7759_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7759_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
+
+static IIO_CONST_ATTR(name, "ade7759");
+
+static struct attribute *ade7759_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group ade7759_event_attribute_group = {
+ .attrs = ade7759_event_attributes,
+};
+
+static struct attribute *ade7759_attributes[] = {
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_phcal.dev_attr.attr,
+ &iio_dev_attr_cfden.dev_attr.attr,
+ &iio_dev_attr_aenergy.dev_attr.attr,
+ &iio_dev_attr_cfnum.dev_attr.attr,
+ &iio_dev_attr_apos.dev_attr.attr,
+ &iio_dev_attr_sagcyc.dev_attr.attr,
+ &iio_dev_attr_saglvl.dev_attr.attr,
+ &iio_dev_attr_linecyc.dev_attr.attr,
+ &iio_dev_attr_lenergy.dev_attr.attr,
+ &iio_dev_attr_chksum.dev_attr.attr,
+ &iio_dev_attr_pga_gain.dev_attr.attr,
+ &iio_dev_attr_active_power_gain.dev_attr.attr,
+ &iio_dev_attr_choff_1.dev_attr.attr,
+ &iio_dev_attr_choff_2.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7759_attribute_group = {
+ .attrs = ade7759_attributes,
+};
+
+static int __devinit ade7759_probe(struct spi_device *spi)
+{
+ int ret, regdone = 0;
+ struct ade7759_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, st);
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADE7759_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADE7759_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ st->us = spi;
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &ade7759_event_attribute_group;
+ st->indio_dev->attrs = &ade7759_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ade7759_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = ade7759_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (spi->irq) {
+ ret = iio_register_interrupt_line(spi->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ade7759");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = ade7759_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+
+ /* Get the device into a sane initial state */
+ ret = ade7759_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ ade7759_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ ade7759_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ ade7759_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7759_remove(struct spi_device *spi)
+{
+ int ret;
+ struct ade7759_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ ret = ade7759_stop_device(&(indio_dev->dev));
+ if (ret)
+ goto err_ret;
+
+ flush_scheduled_work();
+
+ ade7759_remove_trigger(indio_dev);
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ ade7759_uninitialize_ring(indio_dev->ring);
+ ade7759_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+
+err_ret:
+ return ret;
+}
+
+static struct spi_driver ade7759_driver = {
+ .driver = {
+ .name = "ade7759",
+ .owner = THIS_MODULE,
+ },
+ .probe = ade7759_probe,
+ .remove = __devexit_p(ade7759_remove),
+};
+
+static __init int ade7759_init(void)
+{
+ return spi_register_driver(&ade7759_driver);
+}
+module_init(ade7759_init);
+
+static __exit void ade7759_exit(void)
+{
+ spi_unregister_driver(&ade7759_driver);
+}
+module_exit(ade7759_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7759 Active Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7759.h b/drivers/staging/iio/meter/ade7759.h
new file mode 100644
index 000000000000..813dea2676a9
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7759.h
@@ -0,0 +1,122 @@
+#ifndef _ADE7759_H
+#define _ADE7759_H
+
+#define ADE7759_WAVEFORM 0x01
+#define ADE7759_AENERGY 0x02
+#define ADE7759_RSTENERGY 0x03
+#define ADE7759_STATUS 0x04
+#define ADE7759_RSTSTATUS 0x05
+#define ADE7759_MODE 0x06
+#define ADE7759_CFDEN 0x07
+#define ADE7759_CH1OS 0x08
+#define ADE7759_CH2OS 0x09
+#define ADE7759_GAIN 0x0A
+#define ADE7759_APGAIN 0x0B
+#define ADE7759_PHCAL 0x0C
+#define ADE7759_APOS 0x0D
+#define ADE7759_ZXTOUT 0x0E
+#define ADE7759_SAGCYC 0x0F
+#define ADE7759_IRQEN 0x10
+#define ADE7759_SAGLVL 0x11
+#define ADE7759_TEMP 0x12
+#define ADE7759_LINECYC 0x13
+#define ADE7759_LENERGY 0x14
+#define ADE7759_CFNUM 0x15
+#define ADE7759_CHKSUM 0x1E
+#define ADE7759_DIEREV 0x1F
+
+#define ADE7759_READ_REG(a) a
+#define ADE7759_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7759_MAX_TX 6
+#define ADE7759_MAX_RX 6
+#define ADE7759_STARTUP_DELAY 1
+
+#define ADE7759_SPI_SLOW (u32)(300 * 1000)
+#define ADE7759_SPI_BURST (u32)(1000 * 1000)
+#define ADE7759_SPI_FAST (u32)(2000 * 1000)
+
+#define DRIVER_NAME "ade7759"
+
+/**
+ * struct ade7759_state - device instance specific data
+ * @us: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct ade7759_state {
+ struct spi_device *us;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ struct mutex buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7759_scan {
+ ADE7759_SCAN_ACTIVE_POWER,
+ ADE7759_SCAN_CH1_CH2,
+ ADE7759_SCAN_CH1,
+ ADE7759_SCAN_CH2,
+};
+
+void ade7759_remove_trigger(struct iio_dev *indio_dev);
+int ade7759_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7759_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int ade7759_configure_ring(struct iio_dev *indio_dev);
+void ade7759_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7759_initialize_ring(struct iio_ring_buffer *ring);
+void ade7759_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7759_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7759_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+ade7759_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static int ade7759_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void ade7759_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7759_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+static inline void ade7759_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
new file mode 100644
index 000000000000..4578e7b7f460
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -0,0 +1,272 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "../iio.h"
+#include "ade7854.h"
+
+static int ade7854_i2c_write_reg_8(struct device *dev,
+ u16 reg_address,
+ u8 value)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+ st->tx[2] = value;
+
+ ret = i2c_master_send(st->i2c, st->tx, 3);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_i2c_write_reg_16(struct device *dev,
+ u16 reg_address,
+ u16 value)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+ st->tx[2] = (value >> 8) & 0xFF;
+ st->tx[3] = value & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 4);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_i2c_write_reg_24(struct device *dev,
+ u16 reg_address,
+ u32 value)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+ st->tx[2] = (value >> 16) & 0xFF;
+ st->tx[3] = (value >> 8) & 0xFF;
+ st->tx[4] = value & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 5);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_i2c_write_reg_32(struct device *dev,
+ u16 reg_address,
+ u32 value)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+ st->tx[2] = (value >> 24) & 0xFF;
+ st->tx[3] = (value >> 16) & 0xFF;
+ st->tx[4] = (value >> 8) & 0xFF;
+ st->tx[5] = value & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 6);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_i2c_read_reg_8(struct device *dev,
+ u16 reg_address,
+ u8 *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 2);
+ if (ret)
+ goto out;
+
+ ret = i2c_master_recv(st->i2c, st->rx, 1);
+ if (ret)
+ goto out;
+
+ *val = st->rx[0];
+out:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_i2c_read_reg_16(struct device *dev,
+ u16 reg_address,
+ u16 *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 2);
+ if (ret)
+ goto out;
+
+ ret = i2c_master_recv(st->i2c, st->rx, 2);
+ if (ret)
+ goto out;
+
+ *val = (st->rx[0] << 8) | st->rx[1];
+out:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_i2c_read_reg_24(struct device *dev,
+ u16 reg_address,
+ u32 *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 2);
+ if (ret)
+ goto out;
+
+ ret = i2c_master_recv(st->i2c, st->rx, 3);
+ if (ret)
+ goto out;
+
+ *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
+out:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_i2c_read_reg_32(struct device *dev,
+ u16 reg_address,
+ u32 *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = (reg_address >> 8) & 0xFF;
+ st->tx[1] = reg_address & 0xFF;
+
+ ret = i2c_master_send(st->i2c, st->tx, 2);
+ if (ret)
+ goto out;
+
+ ret = i2c_master_recv(st->i2c, st->rx, 3);
+ if (ret)
+ goto out;
+
+ *val = (st->rx[0] << 24) | (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+out:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int __devinit ade7854_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ i2c_set_clientdata(client, st);
+ st->read_reg_8 = ade7854_i2c_read_reg_8;
+ st->read_reg_16 = ade7854_i2c_read_reg_16;
+ st->read_reg_24 = ade7854_i2c_read_reg_24;
+ st->read_reg_32 = ade7854_i2c_read_reg_32;
+ st->write_reg_8 = ade7854_i2c_write_reg_8;
+ st->write_reg_16 = ade7854_i2c_write_reg_16;
+ st->write_reg_24 = ade7854_i2c_write_reg_24;
+ st->write_reg_32 = ade7854_i2c_write_reg_32;
+ st->i2c = client;
+ st->irq = client->irq;
+
+ ret = ade7854_probe(st, &client->dev);
+ if (ret) {
+ kfree(st);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int __devexit ade7854_i2c_remove(struct i2c_client *client)
+{
+ return ade7854_remove(i2c_get_clientdata(client));
+}
+
+static const struct i2c_device_id ade7854_id[] = {
+ { "ade7854", 0 },
+ { "ade7858", 0 },
+ { "ade7868", 0 },
+ { "ade7878", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ade7854_id);
+
+static struct i2c_driver ade7854_i2c_driver = {
+ .driver = {
+ .name = "ade7854",
+ },
+ .probe = ade7854_i2c_probe,
+ .remove = __devexit_p(ade7854_i2c_remove),
+ .id_table = ade7854_id,
+};
+
+static __init int ade7854_i2c_init(void)
+{
+ return i2c_add_driver(&ade7854_i2c_driver);
+}
+module_init(ade7854_i2c_init);
+
+static __exit void ade7854_i2c_exit(void)
+{
+ i2c_del_driver(&ade7854_i2c_driver);
+}
+module_exit(ade7854_i2c_exit);
+
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
new file mode 100644
index 000000000000..fe58103ed4ca
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -0,0 +1,360 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (SPI Bus)
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+
+#include "../iio.h"
+#include "ade7854.h"
+
+static int ade7854_spi_write_reg_8(struct device *dev,
+ u16 reg_address,
+ u8 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 4,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7854_WRITE_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_spi_write_reg_16(struct device *dev,
+ u16 reg_address,
+ u16 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 5,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7854_WRITE_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = (value >> 8) & 0xFF;
+ st->tx[4] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_spi_write_reg_24(struct device *dev,
+ u16 reg_address,
+ u32 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 6,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7854_WRITE_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = (value >> 16) & 0xFF;
+ st->tx[4] = (value >> 8) & 0xFF;
+ st->tx[5] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_spi_write_reg_32(struct device *dev,
+ u16 reg_address,
+ u32 value)
+{
+ int ret;
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 7,
+ }
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7854_WRITE_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = (value >> 24) & 0xFF;
+ st->tx[4] = (value >> 16) & 0xFF;
+ st->tx[5] = (value >> 8) & 0xFF;
+ st->tx[6] = value & 0xFF;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ mutex_unlock(&st->buf_lock);
+
+ return ret;
+}
+
+static int ade7854_spi_read_reg_8(struct device *dev,
+ u16 reg_address,
+ u8 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 4,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+
+ st->tx[0] = ADE7854_READ_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ if (ret) {
+ dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = st->rx[3];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_spi_read_reg_16(struct device *dev,
+ u16 reg_address,
+ u16 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 5,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADE7854_READ_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = 0;
+ st->tx[4] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ if (ret) {
+ dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[3] << 8) | st->rx[4];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_spi_read_reg_24(struct device *dev,
+ u16 reg_address,
+ u32 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 6,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+
+ st->tx[0] = ADE7854_READ_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = 0;
+ st->tx[4] = 0;
+ st->tx[5] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ if (ret) {
+ dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int ade7854_spi_read_reg_32(struct device *dev,
+ u16 reg_address,
+ u32 *val)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 7,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+
+ st->tx[0] = ADE7854_READ_REG;
+ st->tx[1] = (reg_address >> 8) & 0xFF;
+ st->tx[2] = reg_address & 0xFF;
+ st->tx[3] = 0;
+ st->tx[4] = 0;
+ st->tx[5] = 0;
+ st->tx[6] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(xfers, &msg);
+ ret = spi_sync(st->spi, &msg);
+ if (ret) {
+ dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X",
+ reg_address);
+ goto error_ret;
+ }
+ *val = (st->rx[3] << 24) | (st->rx[4] << 16) | (st->rx[5] << 8) | st->rx[6];
+
+error_ret:
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
+static int __devinit ade7854_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ spi_set_drvdata(spi, st);
+ st->read_reg_8 = ade7854_spi_read_reg_8;
+ st->read_reg_16 = ade7854_spi_read_reg_16;
+ st->read_reg_24 = ade7854_spi_read_reg_24;
+ st->read_reg_32 = ade7854_spi_read_reg_32;
+ st->write_reg_8 = ade7854_spi_write_reg_8;
+ st->write_reg_16 = ade7854_spi_write_reg_16;
+ st->write_reg_24 = ade7854_spi_write_reg_24;
+ st->write_reg_32 = ade7854_spi_write_reg_32;
+ st->irq = spi->irq;
+ st->spi = spi;
+
+ ret = ade7854_probe(st, &spi->dev);
+ if (ret) {
+ kfree(st);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ade7854_spi_remove(struct spi_device *spi)
+{
+ ade7854_remove(spi_get_drvdata(spi));
+
+ return 0;
+}
+
+static struct spi_driver ade7854_driver = {
+ .driver = {
+ .name = "ade7854",
+ .owner = THIS_MODULE,
+ },
+ .probe = ade7854_spi_probe,
+ .remove = __devexit_p(ade7854_spi_remove),
+};
+
+static __init int ade7854_init(void)
+{
+ return spi_register_driver(&ade7854_driver);
+}
+module_init(ade7854_init);
+
+static __exit void ade7854_exit(void)
+{
+ spi_unregister_driver(&ade7854_driver);
+}
+module_exit(ade7854_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC SPI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
new file mode 100644
index 000000000000..a13d5048cf42
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -0,0 +1,680 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7854.h"
+
+static ssize_t ade7854_read_8bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val = 0;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = st->read_reg_8(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_read_16bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = st->read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_read_24bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 val = 0;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = st->read_reg_24(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7854_read_32bit(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ ret = st->read_reg_32(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_write_8bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = st->write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_16bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = st->write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_24bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = st->write_reg_24(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_32bit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ long val;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+ ret = st->write_reg_32(dev, this_attr->address, val);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static int ade7854_reset(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ u16 val;
+
+ st->read_reg_16(dev, ADE7854_CONFIG, &val);
+ val |= 1 << 7; /* Software Chip Reset */
+ ret = st->write_reg_16(dev, ADE7854_CONFIG, val);
+
+ return ret;
+}
+
+
+static ssize_t ade7854_write_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (len < 1)
+ return -1;
+ switch (buf[0]) {
+ case '1':
+ case 'y':
+ case 'Y':
+ return ade7854_reset(dev);
+ }
+ return -1;
+}
+
+static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AIGAIN);
+static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BIGAIN);
+static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CIGAIN);
+static IIO_DEV_ATTR_NIGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_NIGAIN);
+static IIO_DEV_ATTR_AVGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AVGAIN);
+static IIO_DEV_ATTR_BVGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BVGAIN);
+static IIO_DEV_ATTR_CVGAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CVGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AVAGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BVAGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CVAGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AWATTOS);
+static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BWATTOS);
+static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CWATTOS);
+static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_AVAROS);
+static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_BVAROS);
+static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+ ade7854_read_24bit,
+ ade7854_write_24bit,
+ ADE7854_CVAROS);
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+ ade7854_read_32bit,
+ ade7854_write_32bit,
+ ADE7854_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+ ade7854_read_32bit,
+ ade7854_write_32bit,
+ ADE7854_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CPHCAL);
+static IIO_DEV_ATTR_CF1DEN(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CF1DEN);
+static IIO_DEV_ATTR_CF2DEN(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CF2DEN);
+static IIO_DEV_ATTR_CF3DEN(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CF3DEN);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_LINECYC);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+ ade7854_read_8bit,
+ ade7854_write_8bit,
+ ADE7854_SAGCYC);
+static IIO_DEV_ATTR_CFCYC(S_IWUSR | S_IRUGO,
+ ade7854_read_8bit,
+ ade7854_write_8bit,
+ ADE7854_CFCYC);
+static IIO_DEV_ATTR_PEAKCYC(S_IWUSR | S_IRUGO,
+ ade7854_read_8bit,
+ ade7854_write_8bit,
+ ADE7854_PEAKCYC);
+static IIO_DEV_ATTR_CHKSUM(ade7854_read_24bit,
+ ADE7854_CHECKSUM);
+static IIO_DEV_ATTR_ANGLE0(ade7854_read_24bit,
+ ADE7854_ANGLE0);
+static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit,
+ ADE7854_ANGLE1);
+static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit,
+ ADE7854_ANGLE2);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_CIRMS);
+static IIO_DEV_ATTR_NIRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_NIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+ ade7854_read_24bit,
+ NULL,
+ ADE7854_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+ ade7854_read_16bit,
+ ade7854_write_16bit,
+ ADE7854_CVRMSOS);
+static IIO_DEV_ATTR_VOLT_A(ade7854_read_24bit,
+ ADE7854_VAWV);
+static IIO_DEV_ATTR_VOLT_B(ade7854_read_24bit,
+ ADE7854_VBWV);
+static IIO_DEV_ATTR_VOLT_C(ade7854_read_24bit,
+ ADE7854_VCWV);
+static IIO_DEV_ATTR_CURRENT_A(ade7854_read_24bit,
+ ADE7854_IAWV);
+static IIO_DEV_ATTR_CURRENT_B(ade7854_read_24bit,
+ ADE7854_IBWV);
+static IIO_DEV_ATTR_CURRENT_C(ade7854_read_24bit,
+ ADE7854_ICWV);
+static IIO_DEV_ATTR_AWATTHR(ade7854_read_32bit,
+ ADE7854_AWATTHR);
+static IIO_DEV_ATTR_BWATTHR(ade7854_read_32bit,
+ ADE7854_BWATTHR);
+static IIO_DEV_ATTR_CWATTHR(ade7854_read_32bit,
+ ADE7854_CWATTHR);
+static IIO_DEV_ATTR_AFWATTHR(ade7854_read_32bit,
+ ADE7854_AFWATTHR);
+static IIO_DEV_ATTR_BFWATTHR(ade7854_read_32bit,
+ ADE7854_BFWATTHR);
+static IIO_DEV_ATTR_CFWATTHR(ade7854_read_32bit,
+ ADE7854_CFWATTHR);
+static IIO_DEV_ATTR_AVARHR(ade7854_read_32bit,
+ ADE7854_AVARHR);
+static IIO_DEV_ATTR_BVARHR(ade7854_read_32bit,
+ ADE7854_BVARHR);
+static IIO_DEV_ATTR_CVARHR(ade7854_read_32bit,
+ ADE7854_CVARHR);
+static IIO_DEV_ATTR_AVAHR(ade7854_read_32bit,
+ ADE7854_AVAHR);
+static IIO_DEV_ATTR_BVAHR(ade7854_read_32bit,
+ ADE7854_BVAHR);
+static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit,
+ ADE7854_CVAHR);
+
+static int ade7854_set_irq(struct device *dev, bool enable)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+ int ret;
+ u32 irqen;
+
+ ret = st->read_reg_32(dev, ADE7854_MASK0, &irqen);
+ if (ret)
+ goto error_ret;
+
+ if (enable)
+ irqen |= 1 << 17; /* 1: interrupt enabled when all periodical
+ (at 8 kHz rate) DSP computations finish. */
+ else
+ irqen &= ~(1 << 17);
+
+ ret = st->write_reg_32(dev, ADE7854_MASK0, irqen);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+}
+
+static int ade7854_initial_setup(struct ade7854_state *st)
+{
+ int ret;
+ struct device *dev = &st->indio_dev->dev;
+
+ /* Disable IRQ */
+ ret = ade7854_set_irq(dev, false);
+ if (ret) {
+ dev_err(dev, "disable irq failed");
+ goto err_ret;
+ }
+
+ ade7854_reset(dev);
+ msleep(ADE7854_STARTUP_DELAY);
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_RESET(ade7854_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
+
+static IIO_CONST_ATTR(name, "ade7854");
+
+static struct attribute *ade7854_event_attributes[] = {
+ NULL
+};
+
+static struct attribute_group ade7854_event_attribute_group = {
+ .attrs = ade7854_event_attributes,
+};
+
+static struct attribute *ade7854_attributes[] = {
+ &iio_dev_attr_aigain.dev_attr.attr,
+ &iio_dev_attr_bigain.dev_attr.attr,
+ &iio_dev_attr_cigain.dev_attr.attr,
+ &iio_dev_attr_nigain.dev_attr.attr,
+ &iio_dev_attr_avgain.dev_attr.attr,
+ &iio_dev_attr_bvgain.dev_attr.attr,
+ &iio_dev_attr_cvgain.dev_attr.attr,
+ &iio_dev_attr_linecyc.dev_attr.attr,
+ &iio_dev_attr_sagcyc.dev_attr.attr,
+ &iio_dev_attr_cfcyc.dev_attr.attr,
+ &iio_dev_attr_peakcyc.dev_attr.attr,
+ &iio_dev_attr_chksum.dev_attr.attr,
+ &iio_dev_attr_apparent_power_a_gain.dev_attr.attr,
+ &iio_dev_attr_apparent_power_b_gain.dev_attr.attr,
+ &iio_dev_attr_apparent_power_c_gain.dev_attr.attr,
+ &iio_dev_attr_active_power_a_offset.dev_attr.attr,
+ &iio_dev_attr_active_power_b_offset.dev_attr.attr,
+ &iio_dev_attr_active_power_c_offset.dev_attr.attr,
+ &iio_dev_attr_reactive_power_a_gain.dev_attr.attr,
+ &iio_dev_attr_reactive_power_b_gain.dev_attr.attr,
+ &iio_dev_attr_reactive_power_c_gain.dev_attr.attr,
+ &iio_dev_attr_reactive_power_a_offset.dev_attr.attr,
+ &iio_dev_attr_reactive_power_b_offset.dev_attr.attr,
+ &iio_dev_attr_reactive_power_c_offset.dev_attr.attr,
+ &iio_dev_attr_awatthr.dev_attr.attr,
+ &iio_dev_attr_bwatthr.dev_attr.attr,
+ &iio_dev_attr_cwatthr.dev_attr.attr,
+ &iio_dev_attr_afwatthr.dev_attr.attr,
+ &iio_dev_attr_bfwatthr.dev_attr.attr,
+ &iio_dev_attr_cfwatthr.dev_attr.attr,
+ &iio_dev_attr_avarhr.dev_attr.attr,
+ &iio_dev_attr_bvarhr.dev_attr.attr,
+ &iio_dev_attr_cvarhr.dev_attr.attr,
+ &iio_dev_attr_angle0.dev_attr.attr,
+ &iio_dev_attr_angle1.dev_attr.attr,
+ &iio_dev_attr_angle2.dev_attr.attr,
+ &iio_dev_attr_avahr.dev_attr.attr,
+ &iio_dev_attr_bvahr.dev_attr.attr,
+ &iio_dev_attr_cvahr.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_const_attr_name.dev_attr.attr,
+ &iio_dev_attr_vpeak.dev_attr.attr,
+ &iio_dev_attr_ipeak.dev_attr.attr,
+ &iio_dev_attr_aphcal.dev_attr.attr,
+ &iio_dev_attr_bphcal.dev_attr.attr,
+ &iio_dev_attr_cphcal.dev_attr.attr,
+ &iio_dev_attr_cf1den.dev_attr.attr,
+ &iio_dev_attr_cf2den.dev_attr.attr,
+ &iio_dev_attr_cf3den.dev_attr.attr,
+ &iio_dev_attr_airms.dev_attr.attr,
+ &iio_dev_attr_birms.dev_attr.attr,
+ &iio_dev_attr_cirms.dev_attr.attr,
+ &iio_dev_attr_nirms.dev_attr.attr,
+ &iio_dev_attr_avrms.dev_attr.attr,
+ &iio_dev_attr_bvrms.dev_attr.attr,
+ &iio_dev_attr_cvrms.dev_attr.attr,
+ &iio_dev_attr_airmsos.dev_attr.attr,
+ &iio_dev_attr_birmsos.dev_attr.attr,
+ &iio_dev_attr_cirmsos.dev_attr.attr,
+ &iio_dev_attr_avrmsos.dev_attr.attr,
+ &iio_dev_attr_bvrmsos.dev_attr.attr,
+ &iio_dev_attr_cvrmsos.dev_attr.attr,
+ &iio_dev_attr_volt_a.dev_attr.attr,
+ &iio_dev_attr_volt_b.dev_attr.attr,
+ &iio_dev_attr_volt_c.dev_attr.attr,
+ &iio_dev_attr_current_a.dev_attr.attr,
+ &iio_dev_attr_current_b.dev_attr.attr,
+ &iio_dev_attr_current_c.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ade7854_attribute_group = {
+ .attrs = ade7854_attributes,
+};
+
+int ade7854_probe(struct ade7854_state *st, struct device *dev)
+{
+ int ret, regdone = 0;
+
+ /* Allocate the comms buffers */
+ st->rx = kzalloc(sizeof(*st->rx)*ADE7854_MAX_RX, GFP_KERNEL);
+ if (st->rx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->tx = kzalloc(sizeof(*st->tx)*ADE7854_MAX_TX, GFP_KERNEL);
+ if (st->tx == NULL) {
+ ret = -ENOMEM;
+ goto error_free_rx;
+ }
+ mutex_init(&st->buf_lock);
+ /* setup the industrialio driver allocated elements */
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_tx;
+ }
+
+ st->indio_dev->dev.parent = dev;
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs = &ade7854_event_attribute_group;
+ st->indio_dev->attrs = &ade7854_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ade7854_configure_ring(st->indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_unreg_ring_funcs;
+ regdone = 1;
+
+ ret = ade7854_initialize_ring(st->indio_dev->ring);
+ if (ret) {
+ printk(KERN_ERR "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+
+ if (st->irq) {
+ ret = iio_register_interrupt_line(st->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_FALLING,
+ "ade7854");
+ if (ret)
+ goto error_uninitialize_ring;
+
+ ret = ade7854_probe_trigger(st->indio_dev);
+ if (ret)
+ goto error_unregister_line;
+ }
+ /* Get the device into a sane initial state */
+ ret = ade7854_initial_setup(st);
+ if (ret)
+ goto error_remove_trigger;
+
+ return 0;
+
+error_remove_trigger:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ ade7854_remove_trigger(st->indio_dev);
+error_unregister_line:
+ if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+ ade7854_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+ ade7854_unconfigure_ring(st->indio_dev);
+error_free_dev:
+ if (regdone)
+ iio_device_unregister(st->indio_dev);
+ else
+ iio_free_device(st->indio_dev);
+error_free_tx:
+ kfree(st->tx);
+error_free_rx:
+ kfree(st->rx);
+error_free_st:
+ kfree(st);
+ return ret;
+
+}
+EXPORT_SYMBOL(ade7854_probe);
+
+int ade7854_remove(struct ade7854_state *st)
+{
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ flush_scheduled_work();
+
+ ade7854_remove_trigger(indio_dev);
+ if (st->irq)
+ iio_unregister_interrupt_line(indio_dev, 0);
+
+ ade7854_uninitialize_ring(indio_dev->ring);
+ ade7854_unconfigure_ring(indio_dev);
+ iio_device_unregister(indio_dev);
+ kfree(st->tx);
+ kfree(st->rx);
+ kfree(st);
+
+ return 0;
+}
+EXPORT_SYMBOL(ade7854_remove);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h
new file mode 100644
index 000000000000..47690e521ec1
--- /dev/null
+++ b/drivers/staging/iio/meter/ade7854.h
@@ -0,0 +1,245 @@
+#ifndef _ADE7854_H
+#define _ADE7854_H
+
+#define ADE7854_AIGAIN 0x4380
+#define ADE7854_AVGAIN 0x4381
+#define ADE7854_BIGAIN 0x4382
+#define ADE7854_BVGAIN 0x4383
+#define ADE7854_CIGAIN 0x4384
+#define ADE7854_CVGAIN 0x4385
+#define ADE7854_NIGAIN 0x4386
+#define ADE7854_AIRMSOS 0x4387
+#define ADE7854_AVRMSOS 0x4388
+#define ADE7854_BIRMSOS 0x4389
+#define ADE7854_BVRMSOS 0x438A
+#define ADE7854_CIRMSOS 0x438B
+#define ADE7854_CVRMSOS 0x438C
+#define ADE7854_NIRMSOS 0x438D
+#define ADE7854_AVAGAIN 0x438E
+#define ADE7854_BVAGAIN 0x438F
+#define ADE7854_CVAGAIN 0x4390
+#define ADE7854_AWGAIN 0x4391
+#define ADE7854_AWATTOS 0x4392
+#define ADE7854_BWGAIN 0x4393
+#define ADE7854_BWATTOS 0x4394
+#define ADE7854_CWGAIN 0x4395
+#define ADE7854_CWATTOS 0x4396
+#define ADE7854_AVARGAIN 0x4397
+#define ADE7854_AVAROS 0x4398
+#define ADE7854_BVARGAIN 0x4399
+#define ADE7854_BVAROS 0x439A
+#define ADE7854_CVARGAIN 0x439B
+#define ADE7854_CVAROS 0x439C
+#define ADE7854_AFWGAIN 0x439D
+#define ADE7854_AFWATTOS 0x439E
+#define ADE7854_BFWGAIN 0x439F
+#define ADE7854_BFWATTOS 0x43A0
+#define ADE7854_CFWGAIN 0x43A1
+#define ADE7854_CFWATTOS 0x43A2
+#define ADE7854_AFVARGAIN 0x43A3
+#define ADE7854_AFVAROS 0x43A4
+#define ADE7854_BFVARGAIN 0x43A5
+#define ADE7854_BFVAROS 0x43A6
+#define ADE7854_CFVARGAIN 0x43A7
+#define ADE7854_CFVAROS 0x43A8
+#define ADE7854_VATHR1 0x43A9
+#define ADE7854_VATHR0 0x43AA
+#define ADE7854_WTHR1 0x43AB
+#define ADE7854_WTHR0 0x43AC
+#define ADE7854_VARTHR1 0x43AD
+#define ADE7854_VARTHR0 0x43AE
+#define ADE7854_RSV 0x43AF
+#define ADE7854_VANOLOAD 0x43B0
+#define ADE7854_APNOLOAD 0x43B1
+#define ADE7854_VARNOLOAD 0x43B2
+#define ADE7854_VLEVEL 0x43B3
+#define ADE7854_DICOEFF 0x43B5
+#define ADE7854_HPFDIS 0x43B6
+#define ADE7854_ISUMLVL 0x43B8
+#define ADE7854_ISUM 0x43BF
+#define ADE7854_AIRMS 0x43C0
+#define ADE7854_AVRMS 0x43C1
+#define ADE7854_BIRMS 0x43C2
+#define ADE7854_BVRMS 0x43C3
+#define ADE7854_CIRMS 0x43C4
+#define ADE7854_CVRMS 0x43C5
+#define ADE7854_NIRMS 0x43C6
+#define ADE7854_RUN 0xE228
+#define ADE7854_AWATTHR 0xE400
+#define ADE7854_BWATTHR 0xE401
+#define ADE7854_CWATTHR 0xE402
+#define ADE7854_AFWATTHR 0xE403
+#define ADE7854_BFWATTHR 0xE404
+#define ADE7854_CFWATTHR 0xE405
+#define ADE7854_AVARHR 0xE406
+#define ADE7854_BVARHR 0xE407
+#define ADE7854_CVARHR 0xE408
+#define ADE7854_AFVARHR 0xE409
+#define ADE7854_BFVARHR 0xE40A
+#define ADE7854_CFVARHR 0xE40B
+#define ADE7854_AVAHR 0xE40C
+#define ADE7854_BVAHR 0xE40D
+#define ADE7854_CVAHR 0xE40E
+#define ADE7854_IPEAK 0xE500
+#define ADE7854_VPEAK 0xE501
+#define ADE7854_STATUS0 0xE502
+#define ADE7854_STATUS1 0xE503
+#define ADE7854_OILVL 0xE507
+#define ADE7854_OVLVL 0xE508
+#define ADE7854_SAGLVL 0xE509
+#define ADE7854_MASK0 0xE50A
+#define ADE7854_MASK1 0xE50B
+#define ADE7854_IAWV 0xE50C
+#define ADE7854_IBWV 0xE50D
+#define ADE7854_ICWV 0xE50E
+#define ADE7854_VAWV 0xE510
+#define ADE7854_VBWV 0xE511
+#define ADE7854_VCWV 0xE512
+#define ADE7854_AWATT 0xE513
+#define ADE7854_BWATT 0xE514
+#define ADE7854_CWATT 0xE515
+#define ADE7854_AVA 0xE519
+#define ADE7854_BVA 0xE51A
+#define ADE7854_CVA 0xE51B
+#define ADE7854_CHECKSUM 0xE51F
+#define ADE7854_VNOM 0xE520
+#define ADE7854_PHSTATUS 0xE600
+#define ADE7854_ANGLE0 0xE601
+#define ADE7854_ANGLE1 0xE602
+#define ADE7854_ANGLE2 0xE603
+#define ADE7854_PERIOD 0xE607
+#define ADE7854_PHNOLOAD 0xE608
+#define ADE7854_LINECYC 0xE60C
+#define ADE7854_ZXTOUT 0xE60D
+#define ADE7854_COMPMODE 0xE60E
+#define ADE7854_GAIN 0xE60F
+#define ADE7854_CFMODE 0xE610
+#define ADE7854_CF1DEN 0xE611
+#define ADE7854_CF2DEN 0xE612
+#define ADE7854_CF3DEN 0xE613
+#define ADE7854_APHCAL 0xE614
+#define ADE7854_BPHCAL 0xE615
+#define ADE7854_CPHCAL 0xE616
+#define ADE7854_PHSIGN 0xE617
+#define ADE7854_CONFIG 0xE618
+#define ADE7854_MMODE 0xE700
+#define ADE7854_ACCMODE 0xE701
+#define ADE7854_LCYCMODE 0xE702
+#define ADE7854_PEAKCYC 0xE703
+#define ADE7854_SAGCYC 0xE704
+#define ADE7854_CFCYC 0xE705
+#define ADE7854_HSDC_CFG 0xE706
+#define ADE7854_CONFIG2 0xEC01
+
+#define ADE7854_READ_REG 0x1
+#define ADE7854_WRITE_REG 0x0
+
+#define ADE7854_MAX_TX 7
+#define ADE7854_MAX_RX 7
+#define ADE7854_STARTUP_DELAY 1
+
+#define ADE7854_SPI_SLOW (u32)(300 * 1000)
+#define ADE7854_SPI_BURST (u32)(1000 * 1000)
+#define ADE7854_SPI_FAST (u32)(2000 * 1000)
+
+#define DRIVER_NAME "ade7854"
+
+/**
+ * struct ade7854_state - device instance specific data
+ * @spi: actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter: used to check if new interrupt has been triggered
+ * @last_timestamp: passing timestamp from th to bh of interrupt handler
+ * @indio_dev: industrial I/O device structure
+ * @trig: data ready trigger registered with iio
+ * @tx: transmit buffer
+ * @rx: recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct ade7854_state {
+ struct spi_device *spi;
+ struct i2c_client *i2c;
+ struct work_struct work_trigger_to_ring;
+ s64 last_timestamp;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ u8 *tx;
+ u8 *rx;
+ int (*read_reg_8) (struct device *, u16, u8 *);
+ int (*read_reg_16) (struct device *, u16, u16 *);
+ int (*read_reg_24) (struct device *, u16, u32 *);
+ int (*read_reg_32) (struct device *, u16, u32 *);
+ int (*write_reg_8) (struct device *, u16, u8);
+ int (*write_reg_16) (struct device *, u16, u16);
+ int (*write_reg_24) (struct device *, u16, u32);
+ int (*write_reg_32) (struct device *, u16, u32);
+ int irq;
+ struct mutex buf_lock;
+};
+
+extern int ade7854_probe(struct ade7854_state *st, struct device *dev);
+extern int ade7854_remove(struct ade7854_state *st);
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7854_scan {
+ ADE7854_SCAN_PHA_V,
+ ADE7854_SCAN_PHB_V,
+ ADE7854_SCAN_PHC_V,
+ ADE7854_SCAN_PHA_I,
+ ADE7854_SCAN_PHB_I,
+ ADE7854_SCAN_PHC_I,
+};
+
+void ade7854_remove_trigger(struct iio_dev *indio_dev);
+int ade7854_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7854_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+
+int ade7854_configure_ring(struct iio_dev *indio_dev);
+void ade7854_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7854_initialize_ring(struct iio_ring_buffer *ring);
+void ade7854_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7854_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7854_probe_trigger(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline ssize_t
+ade7854_read_data_from_ring(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static inline int ade7854_configure_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void ade7854_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7854_initialize_ring(struct iio_ring_buffer *ring)
+{
+ return 0;
+}
+static inline void ade7854_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
new file mode 100644
index 000000000000..142c50d71fda
--- /dev/null
+++ b/drivers/staging/iio/meter/meter.h
@@ -0,0 +1,396 @@
+#include "../sysfs.h"
+
+/* metering ic types of attribute */
+
+#define IIO_DEV_ATTR_CURRENT_A_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_A_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(volt_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_B_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(volt_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_C_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(volt_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_A_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(current_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(apparent_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(apparent_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(apparent_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(active_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_A(_show, _addr) \
+ IIO_DEVICE_ATTR(current_a, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B(_show, _addr) \
+ IIO_DEVICE_ATTR(current_b, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C(_show, _addr) \
+ IIO_DEVICE_ATTR(current_c, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_A(_show, _addr) \
+ IIO_DEVICE_ATTR(volt_a, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_B(_show, _addr) \
+ IIO_DEVICE_ATTR(volt_b, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_C(_show, _addr) \
+ IIO_DEVICE_ATTR(volt_c, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(aenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(lenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_RAENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(raenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LAENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(laenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VAENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(vaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LVAENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(lvaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_RVAENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(rvaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LVARENERGY(_show, _addr) \
+ IIO_DEVICE_ATTR(lvarenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CHKSUM(_show, _addr) \
+ IIO_DEVICE_ATTR(chksum, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE0(_show, _addr) \
+ IIO_DEVICE_ATTR(angle0, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE1(_show, _addr) \
+ IIO_DEVICE_ATTR(angle1, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE2(_show, _addr) \
+ IIO_DEVICE_ATTR(angle2, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(awatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(bwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(cwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AFWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(afwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BFWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(bfwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CFWATTHR(_show, _addr) \
+ IIO_DEVICE_ATTR(cfwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AVARHR(_show, _addr) \
+ IIO_DEVICE_ATTR(avarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BVARHR(_show, _addr) \
+ IIO_DEVICE_ATTR(bvarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CVARHR(_show, _addr) \
+ IIO_DEVICE_ATTR(cvarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AVAHR(_show, _addr) \
+ IIO_DEVICE_ATTR(avahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BVAHR(_show, _addr) \
+ IIO_DEVICE_ATTR(bvahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CVAHR(_show, _addr) \
+ IIO_DEVICE_ATTR(cvahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PHCAL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(phcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APHCAL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(aphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BPHCAL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CPHCAL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(apos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AAPOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(aapos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BAPOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bapos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CAPOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(capos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMSGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(avrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMSGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bvrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMSGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cvrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(aigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_NIGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(nigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(avgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bvgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cvgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_WGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(wgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_WDIV(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(wdiv, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFNUM(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cfnum, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFDEN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cfden, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF1DEN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cf1den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF2DEN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cf2den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF3DEN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cf3den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(irms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(airms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(birms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cirms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_NIRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(nirms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(avrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bvrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cvrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(irmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(airmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(birmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cirmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(avrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(bvrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMSOS(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cvrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VAGAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vagain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PGA_GAIN(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(pga_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VADIV(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vadiv, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_LINECYC(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(linecyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_SAGCYC(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(sagcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFCYC(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(cfcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PEAKCYC(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(peakcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_SAGLVL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(saglvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IPKLVL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(ipklvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPKLVL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vpklvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IPEAK(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(ipeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_RIPEAK(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(ripeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPEAK(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vpeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_RVPEAK(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(rvpeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CH_OFF(_num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(choff_##_num, _mode, _show, _store, _addr)
+
+/* active energy register, AENERGY, is more than half full */
+#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask)
+
+/* a SAG on the line voltage */
+#define IIO_EVENT_ATTR_LINE_VOLT_SAG(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(line_volt_sag, _evlist, _show, _store, _mask)
+
+/*
+ * Indicates the end of energy accumulation over an integer number
+ * of half line cycles
+ */
+#define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask)
+
+/* on the rising and falling edge of the the voltage waveform */
+#define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask)
+
+/* the active energy register has overflowed */
+#define IIO_EVENT_ATTR_AENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(aenergy_overflow, _evlist, _show, _store, _mask)
+
+/* the apparent energy register has overflowed */
+#define IIO_EVENT_ATTR_VAENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(vaenergy_overflow, _evlist, _show, _store, _mask)
+
+/* the active energy register, VAENERGY, is more than half full */
+#define IIO_EVENT_ATTR_VAENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(vaenergy_half_full, _evlist, _show, _store, _mask)
+
+/* the power has gone from negative to positive */
+#define IIO_EVENT_ATTR_PPOS(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ppos, _evlist, _show, _store, _mask)
+
+/* the power has gone from positive to negative */
+#define IIO_EVENT_ATTR_PNEG(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(pneg, _evlist, _show, _store, _mask)
+
+/* waveform sample from Channel 1 has exceeded the IPKLVL value */
+#define IIO_EVENT_ATTR_IPKLVL_EXC(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(ipklvl_exc, _evlist, _show, _store, _mask)
+
+/* waveform sample from Channel 2 has exceeded the VPKLVL value */
+#define IIO_EVENT_ATTR_VPKLVL_EXC(_evlist, _show, _store, _mask) \
+ IIO_EVENT_ATTR_SH(vpklvl_exc, _evlist, _show, _store, _mask)
+
diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig
new file mode 100644
index 000000000000..a4a363429355
--- /dev/null
+++ b/drivers/staging/iio/resolver/Kconfig
@@ -0,0 +1,54 @@
+#
+# Resolver/Synchro drivers
+#
+comment "Resolver to digital converters"
+
+config AD2S90
+ tristate "Analog Devices ad2s90 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices spi resolver
+ to digital converters, ad2s90, provides direct access via sysfs.
+
+config AD2S120X
+ tristate "Analog Devices ad2s120x driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices spi resolver
+ to digital converters, ad2s1200 and ad2s1205, provides direct access
+ via sysfs.
+
+config AD2S1210
+ tristate "Analog Devices ad2s1210 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices spi resolver
+ to digital converters, ad2s1210, provides direct access via sysfs.
+
+choice
+ prompt "Resolution Control"
+ depends on AD2S1210
+ default AD2S1210_GPIO_NONE
+ help
+ In normal mode, the resolution of the digital output is selected
+ using the RES0 and RES1 input pins. In configuration mode, the
+ resolution is selected by setting the RES0 and RES1 bits in the
+ control regsiter. When switching between normal mode and configuration
+ mode, there are some schemes to keep them matchs.
+
+config AD2S1210_GPIO_INPUT
+ bool "read resolution from gpio pins"
+ help
+ GPIO pins are sampling RES0 and RES1 pins, read the resolution
+ settings from the GPIO pins.
+
+config AD2S1210_GPIO_OUTPUT
+ bool "set gpio pins to set resolution"
+ help
+ RES0 and RES1 pins are controlled by GPIOs, setting GPIO pins to
+ set the resolution.
+
+config AD2S1210_GPIO_NONE
+ bool "take the responsibility by user"
+
+endchoice
diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile
new file mode 100644
index 000000000000..0b84a89e6cac
--- /dev/null
+++ b/drivers/staging/iio/resolver/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Resolver/Synchro drivers
+#
+
+obj-$(CONFIG_AD2S90) += ad2s90.o
+obj-$(CONFIG_AD2S120X) += ad2s120x.o
+obj-$(CONFIG_AD2S1210) += ad2s1210.o
diff --git a/drivers/staging/iio/resolver/ad2s120x.c b/drivers/staging/iio/resolver/ad2s120x.c
new file mode 100644
index 000000000000..8f497a23976c
--- /dev/null
+++ b/drivers/staging/iio/resolver/ad2s120x.c
@@ -0,0 +1,310 @@
+/*
+ * ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s120x"
+
+/* input pin sample and rdvel is controlled by driver */
+#define AD2S120X_PN 2
+
+/* input clock on serial interface */
+#define AD2S120X_HZ 8192000
+/* clock period in nano second */
+#define AD2S120X_TSCLK (1000000000/AD2S120X_HZ)
+
+struct ad2s120x_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+ unsigned short sample;
+ unsigned short rdvel;
+ u8 rx[2];
+ u8 tx[2];
+};
+
+static ssize_t ad2s120x_show_pos_vel(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret = 0;
+ ssize_t len = 0;
+ u16 pos;
+ s16 vel;
+ u8 status;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s120x_state *st = idev->dev_data;
+
+ xfer.len = 1;
+ xfer.tx_buf = st->tx;
+ xfer.rx_buf = st->rx;
+ mutex_lock(&st->lock);
+
+ gpio_set_value(st->sample, 0);
+ /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+ udelay(1);
+ gpio_set_value(st->sample, 1);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ status = st->rx[1];
+ pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ len = sprintf(buf, "%d %c%c%c%c ", pos,
+ (status & 0x8) ? 'P' : 'V',
+ (status & 0x4) ? 'd' : '_',
+ (status & 0x2) ? 'l' : '_',
+ (status & 0x1) ? '1' : '0');
+
+ /* delay 18 ns */
+ /* ndelay(18); */
+
+ gpio_set_value(st->rdvel, 0);
+ /* ndelay(5);*/
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ status = st->rx[1];
+ vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
+ vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
+ (status & 0x8) ? 'P' : 'V',
+ (status & 0x4) ? 'd' : '_',
+ (status & 0x2) ? 'l' : '_',
+ (status & 0x1) ? '1' : '0');
+error_ret:
+ gpio_set_value(st->rdvel, 1);
+ /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad2s120x_show_pos(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret = 0;
+ ssize_t len = 0;
+ u16 pos;
+ u8 status;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s120x_state *st = idev->dev_data;
+
+ xfer.len = 1;
+ xfer.tx_buf = st->tx;
+ xfer.rx_buf = st->rx;
+ mutex_lock(&st->lock);
+
+ gpio_set_value(st->sample, 0);
+ /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+ udelay(1);
+ gpio_set_value(st->sample, 1);
+ gpio_set_value(st->rdvel, 1);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ status = st->rx[1];
+ pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ len = sprintf(buf, "%d %c%c%c%c ", pos,
+ (status & 0x8) ? 'P' : 'V',
+ (status & 0x4) ? 'd' : '_',
+ (status & 0x2) ? 'l' : '_',
+ (status & 0x1) ? '1' : '0');
+error_ret:
+ /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad2s120x_show_vel(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret = 0;
+ ssize_t len = 0;
+ s16 vel;
+ u8 status;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s120x_state *st = idev->dev_data;
+
+ xfer.len = 1;
+ xfer.tx_buf = st->tx;
+ xfer.rx_buf = st->rx;
+ mutex_lock(&st->lock);
+
+ gpio_set_value(st->sample, 0);
+ /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+ udelay(1);
+ gpio_set_value(st->sample, 1);
+
+ gpio_set_value(st->rdvel, 0);
+ /* ndelay(5);*/
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ status = st->rx[1];
+ vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
+ vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
+ (status & 0x8) ? 'P' : 'V',
+ (status & 0x4) ? 'd' : '_',
+ (status & 0x2) ? 'l' : '_',
+ (status & 0x1) ? '1' : '0');
+error_ret:
+ gpio_set_value(st->rdvel, 1);
+ /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(description,
+ "12-Bit R/D Converter with Reference Oscillator");
+static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, ad2s120x_show_pos_vel, NULL, 0);
+static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_pos, NULL, 0);
+static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_vel, NULL, 0);
+
+static struct attribute *ad2s120x_attributes[] = {
+ &iio_const_attr_description.dev_attr.attr,
+ &iio_dev_attr_pos_vel.dev_attr.attr,
+ &iio_dev_attr_pos.dev_attr.attr,
+ &iio_dev_attr_vel.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad2s120x_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad2s120x_attributes,
+};
+
+static int __devinit ad2s120x_probe(struct spi_device *spi)
+{
+ struct ad2s120x_state *st;
+ int pn, ret = 0;
+ unsigned short *pins = spi->dev.platform_data;
+
+ for (pn = 0; pn < AD2S120X_PN; pn++) {
+ if (gpio_request(pins[pn], DRV_NAME)) {
+ pr_err("%s: request gpio pin %d failed\n",
+ DRV_NAME, pins[pn]);
+ goto error_ret;
+ }
+ gpio_direction_output(pins[pn], 1);
+ }
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+ st->sample = pins[0];
+ st->rdvel = pins[1];
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad2s120x_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+
+ spi->max_speed_hz = AD2S120X_HZ;
+ spi->mode = SPI_MODE_3;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ for (--pn; pn >= 0; pn--)
+ gpio_free(pins[pn]);
+ return ret;
+}
+
+static int __devexit ad2s120x_remove(struct spi_device *spi)
+{
+ struct ad2s120x_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad2s120x_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad2s120x_probe,
+ .remove = __devexit_p(ad2s120x_remove),
+};
+
+static __init int ad2s120x_spi_init(void)
+{
+ return spi_register_driver(&ad2s120x_driver);
+}
+module_init(ad2s120x_spi_init);
+
+static __exit void ad2s120x_spi_exit(void)
+{
+ spi_unregister_driver(&ad2s120x_driver);
+}
+module_exit(ad2s120x_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
new file mode 100644
index 000000000000..c12f64cc40df
--- /dev/null
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -0,0 +1,872 @@
+/*
+ * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s1210"
+
+#define DEF_CONTROL 0x7E
+
+#define MSB_IS_HIGH 0x80
+#define MSB_IS_LOW 0x7F
+#define PHASE_LOCK_RANGE_44 0x20
+#define ENABLE_HYSTERESIS 0x10
+#define SET_ENRES1 0x08
+#define SET_ENRES0 0x04
+#define SET_RES1 0x02
+#define SET_RES0 0x01
+
+#define SET_ENRESOLUTION (SET_ENRES1 | SET_ENRES0)
+#define SET_RESOLUTION (SET_RES1 | SET_RES0)
+
+#define REG_POSITION 0x80
+#define REG_VELOCITY 0x82
+#define REG_LOS_THRD 0x88
+#define REG_DOS_OVR_THRD 0x89
+#define REG_DOS_MIS_THRD 0x8A
+#define REG_DOS_RST_MAX_THRD 0x8B
+#define REG_DOS_RST_MIN_THRD 0x8C
+#define REG_LOT_HIGH_THRD 0x8D
+#define REG_LOT_LOW_THRD 0x8E
+#define REG_EXCIT_FREQ 0x91
+#define REG_CONTROL 0x92
+#define REG_SOFT_RESET 0xF0
+#define REG_FAULT 0xFF
+
+/* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */
+#define AD2S1210_SAA 3
+#if defined(CONFIG_AD2S1210_GPIO_INPUT) || defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+# define AD2S1210_RES 2
+#else
+# define AD2S1210_RES 0
+#endif
+#define AD2S1210_PN (AD2S1210_SAA + AD2S1210_RES)
+
+#define AD2S1210_MIN_CLKIN 6144000
+#define AD2S1210_MAX_CLKIN 10240000
+#define AD2S1210_MIN_EXCIT 2000
+#define AD2S1210_MAX_EXCIT 20000
+#define AD2S1210_MIN_FCW 0x4
+#define AD2S1210_MAX_FCW 0x50
+
+/* default input clock on serial interface */
+#define AD2S1210_DEF_CLKIN 8192000
+/* clock period in nano second */
+#define AD2S1210_DEF_TCK (1000000000/AD2S1210_DEF_CLKIN)
+#define AD2S1210_DEF_EXCIT 10000
+
+enum ad2s1210_mode {
+ MOD_POS = 0,
+ MOD_VEL,
+ MOD_RESERVED,
+ MOD_CONFIG,
+};
+
+enum ad2s1210_res {
+ RES_10 = 10,
+ RES_12 = 12,
+ RES_14 = 14,
+ RES_16 = 16,
+};
+
+static unsigned int resolution_value[] = {
+ RES_10, RES_12, RES_14, RES_16};
+
+struct ad2s1210_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+ struct spi_transfer xfer;
+ unsigned int hysteresis;
+ unsigned int old_data;
+ enum ad2s1210_mode mode;
+ enum ad2s1210_res resolution;
+ unsigned int fclkin;
+ unsigned int fexcit;
+ unsigned short sample;
+ unsigned short a0;
+ unsigned short a1;
+ unsigned short res0;
+ unsigned short res1;
+ u8 rx[3];
+ u8 tx[3];
+};
+
+static inline void start_sample(struct ad2s1210_state *st)
+{
+ gpio_set_value(st->sample, 0);
+}
+
+static inline void stop_sample(struct ad2s1210_state *st)
+{
+ gpio_set_value(st->sample, 1);
+}
+
+static inline void set_mode(enum ad2s1210_mode mode, struct ad2s1210_state *st)
+{
+ switch (mode) {
+ case MOD_POS:
+ gpio_set_value(st->a0, 0);
+ gpio_set_value(st->a1, 0);
+ break;
+ case MOD_VEL:
+ gpio_set_value(st->a0, 0);
+ gpio_set_value(st->a1, 1);
+ break;
+ case MOD_CONFIG:
+ gpio_set_value(st->a0, 1);
+ gpio_set_value(st->a1, 1);
+ break;
+ default:
+ /* set to reserved mode */
+ gpio_set_value(st->a0, 1);
+ gpio_set_value(st->a1, 0);
+ }
+ st->mode = mode;
+}
+
+/* write 1 bytes (address or data) to the chip */
+static int config_write(struct ad2s1210_state *st,
+ unsigned char data)
+{
+ struct spi_message msg;
+ int ret = 0;
+
+ st->xfer.len = 1;
+ set_mode(MOD_CONFIG, st);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ st->tx[0] = data;
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ return ret;
+ st->old_data = 1;
+ return ret;
+}
+
+/* read value from one of the registers */
+static int config_read(struct ad2s1210_state *st,
+ unsigned char address,
+ unsigned char *data)
+{
+ struct spi_message msg;
+ int ret = 0;
+
+ st->xfer.len = 2;
+ set_mode(MOD_CONFIG, st);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ st->tx[0] = address | MSB_IS_HIGH;
+ st->tx[1] = REG_FAULT;
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ return ret;
+ *data = st->rx[1];
+ st->old_data = 1;
+ return ret;
+}
+
+static inline void update_frequency_control_word(struct ad2s1210_state *st)
+{
+ unsigned char fcw;
+ fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin);
+ if (fcw >= AD2S1210_MIN_FCW && fcw <= AD2S1210_MAX_FCW) {
+ config_write(st, REG_EXCIT_FREQ);
+ config_write(st, fcw);
+ } else
+ pr_err("ad2s1210: FCW out of range\n");
+}
+
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+static inline unsigned char read_resolution_pin(struct ad2s1210_state *st)
+{
+ unsigned int data;
+ data = (gpio_get_value(st->res0) << 1) |
+ gpio_get_value(st->res1);
+ return resolution_value[data];
+}
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+static inline void set_resolution_pin(struct ad2s1210_state *st)
+{
+ switch (st->resolution) {
+ case RES_10:
+ gpio_set_value(st->res0, 0);
+ gpio_set_value(st->res1, 0);
+ break;
+ case RES_12:
+ gpio_set_value(st->res0, 0);
+ gpio_set_value(st->res1, 1);
+ break;
+ case RES_14:
+ gpio_set_value(st->res0, 1);
+ gpio_set_value(st->res1, 0);
+ break;
+ case RES_16:
+ gpio_set_value(st->res0, 1);
+ gpio_set_value(st->res1, 1);
+ break;
+ }
+}
+#endif
+
+static inline void soft_reset(struct ad2s1210_state *st)
+{
+ config_write(st, REG_SOFT_RESET);
+ config_write(st, 0x0);
+}
+
+
+/* return the OLD DATA since last spi bus write */
+static ssize_t ad2s1210_show_raw(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ int ret;
+
+ mutex_lock(&st->lock);
+ if (st->old_data) {
+ ret = sprintf(buf, "0x%x\n", st->rx[0]);
+ st->old_data = 0;
+ } else
+ ret = 0;
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+static ssize_t ad2s1210_store_raw(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned long udata;
+ unsigned char data;
+ int ret;
+
+ ret = strict_strtoul(buf, 16, &udata);
+ if (ret)
+ return -EINVAL;
+ data = udata & 0xff;
+ mutex_lock(&st->lock);
+ config_write(st, data);
+ mutex_unlock(&st->lock);
+ return 1;
+}
+
+static ssize_t ad2s1210_store_softreset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ mutex_lock(&st->lock);
+ soft_reset(st);
+ mutex_unlock(&st->lock);
+ return len;
+}
+
+static ssize_t ad2s1210_show_fclkin(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ return sprintf(buf, "%d\n", st->fclkin);
+}
+
+static ssize_t ad2s1210_store_fclkin(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned long fclkin;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &fclkin);
+ if (!ret && fclkin >= AD2S1210_MIN_CLKIN &&
+ fclkin <= AD2S1210_MAX_CLKIN) {
+ mutex_lock(&st->lock);
+ st->fclkin = fclkin;
+ } else {
+ pr_err("ad2s1210: fclkin out of range\n");
+ return -EINVAL;
+ }
+ update_frequency_control_word(st);
+ soft_reset(st);
+ mutex_unlock(&st->lock);
+ return len;
+}
+
+static ssize_t ad2s1210_show_fexcit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ return sprintf(buf, "%d\n", st->fexcit);
+}
+
+static ssize_t ad2s1210_store_fexcit(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned long fexcit;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &fexcit);
+ if (!ret && fexcit >= AD2S1210_MIN_EXCIT &&
+ fexcit <= AD2S1210_MAX_EXCIT) {
+ mutex_lock(&st->lock);
+ st->fexcit = fexcit;
+ } else {
+ pr_err("ad2s1210: excitation frequency out of range\n");
+ return -EINVAL;
+ }
+ update_frequency_control_word(st);
+ soft_reset(st);
+ mutex_unlock(&st->lock);
+ return len;
+}
+
+static ssize_t ad2s1210_show_control(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned char data;
+ mutex_lock(&st->lock);
+ config_read(st, REG_CONTROL, &data);
+ mutex_unlock(&st->lock);
+ return sprintf(buf, "0x%x\n", data);
+}
+
+static ssize_t ad2s1210_store_control(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned long udata;
+ unsigned char data;
+ int ret;
+
+ ret = strict_strtoul(buf, 16, &udata);
+ if (ret) {
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ mutex_lock(&st->lock);
+ config_write(st, REG_CONTROL);
+ data = udata & MSB_IS_LOW;
+ config_write(st, data);
+ config_read(st, REG_CONTROL, &data);
+ if (data & MSB_IS_HIGH) {
+ ret = -EIO;
+ pr_err("ad2s1210: write control register fail\n");
+ goto error_ret;
+ }
+ st->resolution = resolution_value[data & SET_RESOLUTION];
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+ data = read_resolution_pin(st);
+ if (data != st->resolution)
+ pr_warning("ad2s1210: resolution settings not match\n");
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+ set_resolution_pin(st);
+#endif
+ ret = len;
+ if (data & ENABLE_HYSTERESIS)
+ st->hysteresis = 1;
+ else
+ st->hysteresis = 0;
+error_ret:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+static ssize_t ad2s1210_show_resolution(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ return sprintf(buf, "%d\n", st->resolution);
+}
+
+static ssize_t ad2s1210_store_resolution(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned char data;
+ unsigned long udata;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &udata);
+ if (ret || udata < RES_10 || udata > RES_16) {
+ pr_err("ad2s1210: resolution out of range\n");
+ return -EINVAL;
+ }
+ mutex_lock(&st->lock);
+ config_read(st, REG_CONTROL, &data);
+ data &= ~SET_RESOLUTION;
+ data |= (udata - RES_10) >> 1;
+ config_write(st, REG_CONTROL);
+ config_write(st, data & MSB_IS_LOW);
+ config_read(st, REG_CONTROL, &data);
+ if (data & MSB_IS_HIGH) {
+ ret = -EIO;
+ pr_err("ad2s1210: setting resolution fail\n");
+ goto error_ret;
+ }
+ st->resolution = resolution_value[data & SET_RESOLUTION];
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+ data = read_resolution_pin(st);
+ if (data != st->resolution)
+ pr_warning("ad2s1210: resolution settings not match\n");
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+ set_resolution_pin(st);
+#endif
+ ret = len;
+error_ret:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+/* read the fault register since last sample */
+static ssize_t ad2s1210_show_fault(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ ssize_t len = 0;
+ unsigned char data;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+
+ mutex_lock(&st->lock);
+ ret = config_read(st, REG_FAULT, &data);
+
+ if (ret)
+ goto error_ret;
+ len = sprintf(buf, "0x%x\n", data);
+error_ret:
+ mutex_unlock(&st->lock);
+ return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_clear_fault(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned char data;
+
+ mutex_lock(&st->lock);
+ start_sample(st);
+ /* delay (2 * tck + 20) nano seconds */
+ udelay(1);
+ stop_sample(st);
+ config_read(st, REG_FAULT, &data);
+ start_sample(st);
+ stop_sample(st);
+ mutex_unlock(&st->lock);
+
+ return 0;
+}
+
+static ssize_t ad2s1210_show_reg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned char data;
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+
+ mutex_lock(&st->lock);
+ config_read(st, iattr->address, &data);
+ mutex_unlock(&st->lock);
+ return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t ad2s1210_store_reg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+ unsigned long data;
+ int ret;
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+
+ ret = strict_strtoul(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+ mutex_lock(&st->lock);
+ config_write(st, iattr->address);
+ config_write(st, data & MSB_IS_LOW);
+ mutex_unlock(&st->lock);
+ return len;
+}
+
+static ssize_t ad2s1210_show_pos(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ int ret = 0;
+ ssize_t len = 0;
+ u16 pos;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+
+ st->xfer.len = 2;
+ mutex_lock(&st->lock);
+ start_sample(st);
+ /* delay (6 * tck + 20) nano seconds */
+ udelay(1);
+
+ set_mode(MOD_POS, st);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1]));
+ if (st->hysteresis)
+ pos >>= 16 - st->resolution;
+ len = sprintf(buf, "%d\n", pos);
+error_ret:
+ stop_sample(st);
+ /* delay (2 * tck + 20) nano seconds */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_show_vel(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ unsigned short negative;
+ int ret = 0;
+ ssize_t len = 0;
+ s16 vel;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+
+ st->xfer.len = 2;
+ mutex_lock(&st->lock);
+ start_sample(st);
+ /* delay (6 * tck + 20) nano seconds */
+ udelay(1);
+
+ set_mode(MOD_VEL, st);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ negative = st->rx[0] & 0x80;
+ vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1]));
+ vel >>= 16 - st->resolution;
+ if (negative) {
+ negative = (0xffff >> st->resolution) << st->resolution;
+ vel |= negative;
+ }
+ len = sprintf(buf, "%d\n", vel);
+error_ret:
+ stop_sample(st);
+ /* delay (2 * tck + 20) nano seconds */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_show_pos_vel(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ unsigned short negative;
+ int ret = 0;
+ ssize_t len = 0;
+ u16 pos;
+ s16 vel;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s1210_state *st = idev->dev_data;
+
+ st->xfer.len = 2;
+ mutex_lock(&st->lock);
+ start_sample(st);
+ /* delay (6 * tck + 20) nano seconds */
+ udelay(1);
+
+ set_mode(MOD_POS, st);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1]));
+ if (st->hysteresis)
+ pos >>= 16 - st->resolution;
+ len = sprintf(buf, "%d ", pos);
+
+ st->xfer.len = 2;
+ set_mode(MOD_VEL, st);
+ spi_message_init(&msg);
+ spi_message_add_tail(&st->xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ negative = st->rx[0] & 0x80;
+ vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1]));
+ vel >>= 16 - st->resolution;
+ if (negative) {
+ negative = (0xffff >> st->resolution) << st->resolution;
+ vel |= negative;
+ }
+ len += sprintf(buf + len, "%d\n", vel);
+error_ret:
+ stop_sample(st);
+ /* delay (2 * tck + 20) nano seconds */
+ udelay(1);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(description,
+ "Variable Resolution, 10-Bit to 16Bit R/D\n\
+Converter with Reference Oscillator");
+static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUSR,
+ ad2s1210_show_raw, ad2s1210_store_raw, 0);
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+ NULL, ad2s1210_store_softreset, 0);
+static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR,
+ ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0);
+static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR,
+ ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0);
+static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUSR,
+ ad2s1210_show_control, ad2s1210_store_control, 0);
+static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUSR,
+ ad2s1210_show_resolution, ad2s1210_store_resolution, 0);
+static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUSR,
+ ad2s1210_show_fault, ad2s1210_clear_fault, 0);
+static IIO_DEVICE_ATTR(pos, S_IRUGO,
+ ad2s1210_show_pos, NULL, 0);
+static IIO_DEVICE_ATTR(vel, S_IRUGO,
+ ad2s1210_show_vel, NULL, 0);
+static IIO_DEVICE_ATTR(pos_vel, S_IRUGO,
+ ad2s1210_show_pos_vel, NULL, 0);
+static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_LOS_THRD);
+static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_OVR_THRD);
+static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_MIS_THRD);
+static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MAX_THRD);
+static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MIN_THRD);
+static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_HIGH_THRD);
+static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR,
+ ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_LOW_THRD);
+
+static struct attribute *ad2s1210_attributes[] = {
+ &iio_const_attr_description.dev_attr.attr,
+ &iio_dev_attr_raw_io.dev_attr.attr,
+ &iio_dev_attr_reset.dev_attr.attr,
+ &iio_dev_attr_fclkin.dev_attr.attr,
+ &iio_dev_attr_fexcit.dev_attr.attr,
+ &iio_dev_attr_control.dev_attr.attr,
+ &iio_dev_attr_bits.dev_attr.attr,
+ &iio_dev_attr_fault.dev_attr.attr,
+ &iio_dev_attr_pos.dev_attr.attr,
+ &iio_dev_attr_vel.dev_attr.attr,
+ &iio_dev_attr_pos_vel.dev_attr.attr,
+ &iio_dev_attr_los_thrd.dev_attr.attr,
+ &iio_dev_attr_dos_ovr_thrd.dev_attr.attr,
+ &iio_dev_attr_dos_mis_thrd.dev_attr.attr,
+ &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr,
+ &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr,
+ &iio_dev_attr_lot_high_thrd.dev_attr.attr,
+ &iio_dev_attr_lot_low_thrd.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad2s1210_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad2s1210_attributes,
+};
+
+static int __devinit ad2s1210_initial(struct ad2s1210_state *st)
+{
+ unsigned char data;
+ int ret;
+
+ mutex_lock(&st->lock);
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+ st->resolution = read_resolution_pin(st);
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+ set_resolution_pin(st);
+#endif
+
+ config_write(st, REG_CONTROL);
+ data = DEF_CONTROL & ~(SET_RESOLUTION);
+ data |= (st->resolution - RES_10) >> 1;
+ config_write(st, data);
+ ret = config_read(st, REG_CONTROL, &data);
+ if (ret)
+ goto error_ret;
+
+ if (data & MSB_IS_HIGH) {
+ ret = -EIO;
+ goto error_ret;
+ }
+
+ update_frequency_control_word(st);
+ soft_reset(st);
+error_ret:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+static int __devinit ad2s1210_probe(struct spi_device *spi)
+{
+ struct ad2s1210_state *st;
+ int pn, ret = 0;
+ unsigned short *pins = spi->dev.platform_data;
+
+ for (pn = 0; pn < AD2S1210_PN; pn++) {
+ if (gpio_request(pins[pn], DRV_NAME)) {
+ pr_err("%s: request gpio pin %d failed\n",
+ DRV_NAME, pins[pn]);
+ goto error_ret;
+ }
+ if (pn < AD2S1210_SAA)
+ gpio_direction_output(pins[pn], 1);
+ else {
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+ gpio_direction_input(pins[pn]);
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+ gpio_direction_output(pins[pn], 1);
+#endif
+ }
+ }
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+ st->xfer.tx_buf = st->tx;
+ st->xfer.rx_buf = st->rx;
+ st->hysteresis = 1;
+ st->mode = MOD_CONFIG;
+ st->resolution = RES_12;
+ st->fclkin = AD2S1210_DEF_CLKIN;
+ st->fexcit = AD2S1210_DEF_EXCIT;
+ st->sample = pins[0];
+ st->a0 = pins[1];
+ st->a1 = pins[2];
+ st->res0 = pins[3];
+ st->res1 = pins[4];
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad2s1210_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+
+ if (spi->max_speed_hz != AD2S1210_DEF_CLKIN)
+ st->fclkin = spi->max_speed_hz;
+ spi->mode = SPI_MODE_3;
+ spi_setup(spi);
+
+ ad2s1210_initial(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ for (--pn; pn >= 0; pn--)
+ gpio_free(pins[pn]);
+ return ret;
+}
+
+static int __devexit ad2s1210_remove(struct spi_device *spi)
+{
+ struct ad2s1210_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad2s1210_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad2s1210_probe,
+ .remove = __devexit_p(ad2s1210_remove),
+};
+
+static __init int ad2s1210_spi_init(void)
+{
+ return spi_register_driver(&ad2s1210_driver);
+}
+module_init(ad2s1210_spi_init);
+
+static __exit void ad2s1210_spi_exit(void)
+{
+ spi_unregister_driver(&ad2s1210_driver);
+}
+module_exit(ad2s1210_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
new file mode 100644
index 000000000000..4143535242d9
--- /dev/null
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -0,0 +1,159 @@
+/*
+ * ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s90"
+
+struct ad2s90_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+ u8 rx[2];
+ u8 tx[2];
+};
+
+static ssize_t ad2s90_show_angular(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ ssize_t len = 0;
+ u16 val;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad2s90_state *st = idev->dev_data;
+
+ xfer.len = 1;
+ xfer.tx_buf = st->tx;
+ xfer.rx_buf = st->rx;
+ mutex_lock(&st->lock);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ len = sprintf(buf, "%d\n", val);
+error_ret:
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_SIMPLE_RESOLVER(_show) \
+ IIO_DEVICE_ATTR(angular, S_IRUGO, _show, NULL, 0)
+
+static IIO_CONST_ATTR(description,
+ "Low Cost, Complete 12-Bit Resolver-to-Digital Converter");
+static IIO_DEV_ATTR_SIMPLE_RESOLVER(ad2s90_show_angular);
+
+static struct attribute *ad2s90_attributes[] = {
+ &iio_const_attr_description.dev_attr.attr,
+ &iio_dev_attr_angular.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad2s90_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad2s90_attributes,
+};
+
+static int __devinit ad2s90_probe(struct spi_device *spi)
+{
+ struct ad2s90_state *st;
+ int ret = 0;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ spi_set_drvdata(spi, st);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ st->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad2s90_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+
+ /* need 600ns between CS and the first falling edge of SCLK */
+ spi->max_speed_hz = 830000;
+ spi->mode = SPI_MODE_3;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad2s90_remove(struct spi_device *spi)
+{
+ struct ad2s90_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad2s90_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad2s90_probe,
+ .remove = __devexit_p(ad2s90_remove),
+};
+
+static __init int ad2s90_spi_init(void)
+{
+ return spi_register_driver(&ad2s90_driver);
+}
+module_init(ad2s90_spi_init);
+
+static __exit void ad2s90_spi_exit(void)
+{
+ spi_unregister_driver(&ad2s90_driver);
+}
+module_exit(ad2s90_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S90 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h
index ee91a95a8b95..24b74ddcd083 100644
--- a/drivers/staging/iio/sysfs.h
+++ b/drivers/staging/iio/sysfs.h
@@ -108,6 +108,12 @@ struct iio_const_attr {
IIO_DEVICE_ATTR(name, S_IRUGO, _show, NULL, 0)
/**
+ * IIO_DEV_ATTR_RESET: resets the device
+ **/
+#define IIO_DEV_ATTR_RESET(_store) \
+ IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, _store, 0)
+
+/**
* IIO_CONST_ATTR_NAME - constant identifier
* @_string: the name
**/
diff --git a/drivers/staging/intel_sst/Kconfig b/drivers/staging/intel_sst/Kconfig
index b46bd9d1b324..82391077b384 100644
--- a/drivers/staging/intel_sst/Kconfig
+++ b/drivers/staging/intel_sst/Kconfig
@@ -8,6 +8,7 @@ config SND_INTEL_SST
config SND_INTELMID
tristate "Intel MID sound card driver"
+ depends on SOUND && SND
select SND_PCM
select SND_SEQUENCER
select SND_JACK
diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c
index 24d3928e7071..ce4a9f79ccd2 100644
--- a/drivers/staging/intel_sst/intel_sst.c
+++ b/drivers/staging/intel_sst/intel_sst.c
@@ -29,11 +29,14 @@
* This file contains all init functions
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/miscdevice.h>
+#include <linux/pm_runtime.h>
#include <asm/mrst.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
@@ -169,17 +172,17 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
{
int i, ret = 0;
- pr_debug("sst: Probe for DID %x\n", pci->device);
+ pr_debug("Probe for DID %x\n", pci->device);
mutex_lock(&drv_ctx_lock);
if (sst_drv_ctx) {
- pr_err("sst: Only one sst handle is supported\n");
+ pr_err("Only one sst handle is supported\n");
mutex_unlock(&drv_ctx_lock);
return -EBUSY;
}
sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL);
if (!sst_drv_ctx) {
- pr_err("sst: intel_sst malloc fail\n");
+ pr_err("malloc fail\n");
mutex_unlock(&drv_ctx_lock);
return -ENOMEM;
}
@@ -226,7 +229,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
spin_lock_init(&sst_drv_ctx->list_spin_lock);
sst_drv_ctx->max_streams = pci_id->driver_data;
- pr_debug("sst: Got drv data max stream %d\n",
+ pr_debug("Got drv data max stream %d\n",
sst_drv_ctx->max_streams);
for (i = 1; i <= sst_drv_ctx->max_streams; i++) {
struct stream_info *stream = &sst_drv_ctx->streams[i];
@@ -241,18 +244,18 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->mmap_mem =
kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL);
if (sst_drv_ctx->mmap_mem) {
- pr_debug("sst: Got memory %p size 0x%x\n",
+ pr_debug("Got memory %p size 0x%x\n",
sst_drv_ctx->mmap_mem,
sst_drv_ctx->mmap_len);
break;
}
if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) {
- pr_err("sst: mem alloc fail...abort!!\n");
+ pr_err("mem alloc fail...abort!!\n");
ret = -ENOMEM;
goto free_process_reply_wq;
}
sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
- pr_debug("sst:mem alloc failed...trying %d\n",
+ pr_debug("mem alloc failed...trying %d\n",
sst_drv_ctx->mmap_len);
}
}
@@ -260,7 +263,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
/* Init the device */
ret = pci_enable_device(pci);
if (ret) {
- pr_err("sst: device cant be enabled\n");
+ pr_err("device cant be enabled\n");
goto do_free_mem;
}
sst_drv_ctx->pci = pci_dev_get(pci);
@@ -273,25 +276,25 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
if (!sst_drv_ctx->shim)
goto do_release_regions;
- pr_debug("sst: SST Shim Ptr %p\n", sst_drv_ctx->shim);
+ pr_debug("SST Shim Ptr %p\n", sst_drv_ctx->shim);
/* Shared SRAM */
sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2);
if (!sst_drv_ctx->mailbox)
goto do_unmap_shim;
- pr_debug("sst: SRAM Ptr %p\n", sst_drv_ctx->mailbox);
+ pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox);
/* IRAM */
sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
if (!sst_drv_ctx->iram)
goto do_unmap_sram;
- pr_debug("sst:IRAM Ptr %p\n", sst_drv_ctx->iram);
+ pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram);
/* DRAM */
sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
if (!sst_drv_ctx->dram)
goto do_unmap_iram;
- pr_debug("sst: DRAM Ptr %p\n", sst_drv_ctx->dram);
+ pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram);
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
@@ -301,26 +304,31 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx);
if (ret)
goto do_unmap_dram;
- pr_debug("sst: Registered IRQ 0x%x\n", pci->irq);
+ pr_debug("Registered IRQ 0x%x\n", pci->irq);
+
+ /*Register LPE Control as misc driver*/
+ ret = misc_register(&lpe_ctrl);
+ if (ret) {
+ pr_err("couldn't register control device\n");
+ goto do_free_irq;
+ }
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
ret = misc_register(&lpe_dev);
if (ret) {
- pr_err("sst: couldn't register LPE device\n");
- goto do_free_irq;
- }
-
- /*Register LPE Control as misc driver*/
- ret = misc_register(&lpe_ctrl);
- if (ret) {
- pr_err("sst: couldn't register misc driver\n");
- goto do_free_irq;
- }
+ pr_err("couldn't register misc driver\n");
+ goto do_free_misc;
+ }
}
sst_drv_ctx->lpe_stalled = 0;
- pr_debug("sst: ...successfully done!!!\n");
+ pm_runtime_set_active(&pci->dev);
+ pm_runtime_enable(&pci->dev);
+ pm_runtime_allow(&pci->dev);
+ pr_debug("...successfully done!!!\n");
return ret;
+do_free_misc:
+ misc_deregister(&lpe_ctrl);
do_free_irq:
free_irq(pci->irq, sst_drv_ctx);
do_unmap_dram:
@@ -347,7 +355,7 @@ free_mad_wq:
destroy_workqueue(sst_drv_ctx->mad_wq);
do_free_drv_ctx:
kfree(sst_drv_ctx);
- pr_err("sst: Probe failed with 0x%x\n", ret);
+ pr_err("Probe failed with 0x%x\n", ret);
return ret;
}
@@ -365,10 +373,9 @@ static void __devexit intel_sst_remove(struct pci_dev *pci)
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ misc_deregister(&lpe_ctrl);
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
misc_deregister(&lpe_dev);
- misc_deregister(&lpe_ctrl);
- }
free_irq(pci->irq, sst_drv_ctx);
iounmap(sst_drv_ctx->dram);
iounmap(sst_drv_ctx->iram);
@@ -404,10 +411,12 @@ int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
{
union config_status_reg csr;
- pr_debug("sst: intel_sst_suspend called\n");
+ pr_debug("intel_sst_suspend called\n");
- if (sst_drv_ctx->pb_streams != 0 || sst_drv_ctx->cp_streams != 0)
- return -EPERM;
+ if (sst_drv_ctx->stream_cnt) {
+ pr_err("active streams,not able to suspend\n");
+ return -EBUSY;
+ }
/*Assert RESET on LPE Processor*/
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full = csr.full | 0x2;
@@ -434,17 +443,17 @@ int intel_sst_resume(struct pci_dev *pci)
{
int ret = 0;
- pr_debug("sst: intel_sst_resume called\n");
+ pr_debug("intel_sst_resume called\n");
if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
- pr_err("sst: SST is not in suspended state\n");
- return -EPERM;
+ pr_err("SST is not in suspended state\n");
+ return 0;
}
sst_drv_ctx = pci_get_drvdata(pci);
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
ret = pci_enable_device(pci);
if (ret)
- pr_err("sst: device cant be enabled\n");
+ pr_err("device cant be enabled\n");
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
@@ -452,6 +461,34 @@ int intel_sst_resume(struct pci_dev *pci)
return 0;
}
+static int intel_sst_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ pr_debug("runtime_suspend called\n");
+ return intel_sst_suspend(pci_dev, PMSG_SUSPEND);
+}
+
+static int intel_sst_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ pr_debug("runtime_resume called\n");
+ return intel_sst_resume(pci_dev);
+}
+
+static int intel_sst_runtime_idle(struct device *dev)
+{
+ pr_debug("runtime_idle called\n");
+ if (sst_drv_ctx->stream_cnt == 0 && sst_drv_ctx->am_cnt == 0)
+ pm_schedule_suspend(dev, SST_SUSPEND_DELAY);
+ return -EBUSY;
+}
+
+static const struct dev_pm_ops intel_sst_pm = {
+ .runtime_suspend = intel_sst_runtime_suspend,
+ .runtime_resume = intel_sst_runtime_resume,
+ .runtime_idle = intel_sst_runtime_idle,
+};
+
/* PCI Routines */
static struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRST_PCI_ID), 3},
@@ -468,6 +505,9 @@ static struct pci_driver driver = {
#ifdef CONFIG_PM
.suspend = intel_sst_suspend,
.resume = intel_sst_resume,
+ .driver = {
+ .pm = &intel_sst_pm,
+ },
#endif
};
@@ -482,14 +522,14 @@ static int __init intel_sst_init(void)
{
/* Init all variables, data structure etc....*/
int ret = 0;
- pr_debug("sst: INFO: ******** SST DRIVER loading.. Ver: %s\n",
+ pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n",
SST_DRIVER_VERSION);
mutex_init(&drv_ctx_lock);
/* Register with PCI */
ret = pci_register_driver(&driver);
if (ret)
- pr_err("sst: PCI register failed\n");
+ pr_err("PCI register failed\n");
return ret;
}
@@ -504,7 +544,7 @@ static void __exit intel_sst_exit(void)
{
pci_unregister_driver(&driver);
- pr_debug("sst: driver unloaded\n");
+ pr_debug("driver unloaded\n");
return;
}
diff --git a/drivers/staging/intel_sst/intel_sst.h b/drivers/staging/intel_sst/intel_sst.h
index 1f19f0d1d316..cb03ff7d1a21 100644
--- a/drivers/staging/intel_sst/intel_sst.h
+++ b/drivers/staging/intel_sst/intel_sst.h
@@ -29,6 +29,7 @@
* and middleware.
* This file is shared between the SST and MAD drivers
*/
+#include "intel_sst_ioctl.h"
#define SST_CARD_NAMES "intel_mid_card"
@@ -107,10 +108,15 @@ struct snd_pmic_ops {
int (*power_down_pmic) (void);
};
+struct intel_sst_pcm_control {
+ int (*open) (struct snd_sst_params *str_param);
+ int (*device_control) (int cmd, void *arg);
+ int (*close) (unsigned int str_id);
+};
struct intel_sst_card_ops {
char *module_name;
unsigned int vendor_id;
- int (*control_set) (int control_element, void *value);
+ struct intel_sst_pcm_control *pcm_control;
struct snd_pmic_ops *scard_ops;
};
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c
index 463e5cba8307..a367991d5600 100644
--- a/drivers/staging/intel_sst/intel_sst_app_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_app_interface.c
@@ -27,14 +27,16 @@
* Upper layer interfaces (MAD driver, MMF) to SST driver
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/uio.h>
#include <linux/aio.h>
#include <linux/uaccess.h>
#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
#include <linux/ioctl.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_MRST_RAR_HANDLER
#include <linux/rar_register.h>
#include "../../../drivers/staging/memrar/memrar.h"
@@ -59,14 +61,14 @@ static int intel_sst_check_device(void)
{
int retval = 0;
if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) {
- pr_warn("sst: Sound card not availble\n ");
+ pr_warn("Sound card not available\n");
return -EIO;
}
if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
- pr_debug("sst: Resuming from Suspended state\n");
+ pr_debug("Resuming from Suspended state\n");
retval = intel_sst_resume(sst_drv_ctx->pci);
if (retval) {
- pr_debug("sst: Resume Failed= %#x,abort\n", retval);
+ pr_debug("Resume Failed= %#x,abort\n", retval);
return retval;
}
}
@@ -98,15 +100,22 @@ static int intel_sst_check_device(void)
*/
int intel_sst_open(struct inode *i_node, struct file *file_ptr)
{
- int retval = intel_sst_check_device();
- if (retval)
- return retval;
+ unsigned int retval;
mutex_lock(&sst_drv_ctx->stream_lock);
+ pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
+ retval = intel_sst_check_device();
+ if (retval) {
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ return retval;
+ }
+
if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) {
struct ioctl_pvt_data *data =
kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL);
if (!data) {
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
mutex_unlock(&sst_drv_ctx->stream_lock);
return -ENOMEM;
}
@@ -116,9 +125,10 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr)
data->pvt_id = sst_assign_pvt_id(sst_drv_ctx);
data->str_id = 0;
file_ptr->private_data = (void *)data;
- pr_debug("sst: pvt_id handle = %d!\n", data->pvt_id);
+ pr_debug("pvt_id handle = %d!\n", data->pvt_id);
} else {
retval = -EUSERS;
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
mutex_unlock(&sst_drv_ctx->stream_lock);
}
return retval;
@@ -137,18 +147,26 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr)
*/
int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr)
{
- int retval = intel_sst_check_device();
- if (retval)
- return retval;
+ unsigned int retval;
/* audio manager open */
mutex_lock(&sst_drv_ctx->stream_lock);
+ pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
+ retval = intel_sst_check_device();
+ if (retval) {
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ return retval;
+ }
+
if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) {
sst_drv_ctx->am_cnt++;
- pr_debug("sst: AM handle opened...\n");
+ pr_debug("AM handle opened...\n");
file_ptr->private_data = NULL;
- } else
+ } else {
retval = -EACCES;
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+ }
mutex_unlock(&sst_drv_ctx->stream_lock);
return retval;
@@ -167,10 +185,11 @@ int intel_sst_release(struct inode *i_node, struct file *file_ptr)
{
struct ioctl_pvt_data *data = file_ptr->private_data;
- pr_debug("sst: Release called, closing app handle\n");
+ pr_debug("Release called, closing app handle\n");
mutex_lock(&sst_drv_ctx->stream_lock);
sst_drv_ctx->encoded_cnt--;
sst_drv_ctx->stream_cnt--;
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
mutex_unlock(&sst_drv_ctx->stream_lock);
free_stream_context(data->str_id);
kfree(data);
@@ -182,8 +201,9 @@ int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr)
/* audio manager close */
mutex_lock(&sst_drv_ctx->stream_lock);
sst_drv_ctx->am_cnt--;
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
mutex_unlock(&sst_drv_ctx->stream_lock);
- pr_debug("sst: AM handle closed\n");
+ pr_debug("AM handle closed\n");
return 0;
}
@@ -209,7 +229,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
return -EINVAL;
length = vma->vm_end - vma->vm_start;
- pr_debug("sst: called for stream %d length 0x%x\n", str_id, length);
+ pr_debug("called for stream %d length 0x%x\n", str_id, length);
if (length > sst_drv_ctx->mmap_len)
return -ENOMEM;
@@ -232,7 +252,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
else
sst_drv_ctx->streams[str_id].mmapped = true;
- pr_debug("sst: mmap ret 0x%x\n", retval);
+ pr_debug("mmap ret 0x%x\n", retval);
return retval;
}
@@ -244,12 +264,12 @@ static int intel_sst_mmap_play_capture(u32 str_id,
int retval, i;
struct stream_info *stream;
struct snd_sst_mmap_buff_entry *buf_entry;
+ struct snd_sst_mmap_buff_entry *tmp_buf;
- pr_debug("sst:called for str_id %d\n", str_id);
+ pr_debug("called for str_id %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return -EINVAL;
- BUG_ON(!mmap_buf);
stream = &sst_drv_ctx->streams[str_id];
if (stream->mmapped != true)
@@ -262,14 +282,24 @@ static int intel_sst_mmap_play_capture(u32 str_id,
stream->curr_bytes = 0;
stream->cumm_bytes = 0;
- pr_debug("sst:new buffers count %d status %d\n",
+ tmp_buf = kcalloc(mmap_buf->entries, sizeof(*tmp_buf), GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+ if (copy_from_user(tmp_buf, (void __user *)mmap_buf->buff,
+ mmap_buf->entries * sizeof(*tmp_buf))) {
+ retval = -EFAULT;
+ goto out_free;
+ }
+
+ pr_debug("new buffers count %d status %d\n",
mmap_buf->entries, stream->status);
- buf_entry = mmap_buf->buff;
+ buf_entry = tmp_buf;
for (i = 0; i < mmap_buf->entries; i++) {
- BUG_ON(!buf_entry);
bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
- if (!bufs)
- return -ENOMEM;
+ if (!bufs) {
+ retval = -ENOMEM;
+ goto out_free;
+ }
bufs->size = buf_entry->size;
bufs->offset = buf_entry->offset;
bufs->addr = sst_drv_ctx->mmap_mem;
@@ -291,15 +321,17 @@ static int intel_sst_mmap_play_capture(u32 str_id,
stream->status = STREAM_RUNNING;
if (stream->ops == STREAM_OPS_PLAYBACK) {
if (sst_play_frame(str_id) < 0) {
- pr_warn("sst: play frames fail\n");
+ pr_warn("play frames fail\n");
mutex_unlock(&stream->lock);
- return -EIO;
+ retval = -EIO;
+ goto out_free;
}
} else if (stream->ops == STREAM_OPS_CAPTURE) {
if (sst_capture_frame(str_id) < 0) {
- pr_warn("sst: capture frame fail\n");
+ pr_warn("capture frame fail\n");
mutex_unlock(&stream->lock);
- return -EIO;
+ retval = -EIO;
+ goto out_free;
}
}
}
@@ -313,7 +345,10 @@ static int intel_sst_mmap_play_capture(u32 str_id,
if (retval >= 0)
retval = stream->cumm_bytes;
- pr_debug("sst:end of play/rec ioctl bytes = %d!!\n", retval);
+ pr_debug("end of play/rec ioctl bytes = %d!!\n", retval);
+
+out_free:
+ kfree(tmp_buf);
return retval;
}
@@ -335,7 +370,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) {
/* stream is not started yet */
- pr_debug("sst: Stream isn't in started state %d, prev %d\n",
+ pr_debug("Stream isn't in started state %d, prev %d\n",
stream->status, stream->prev);
} else if ((stream->status == STREAM_RUNNING ||
stream->status == STREAM_PAUSED) &&
@@ -344,13 +379,13 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
if (stream->ops == STREAM_OPS_PLAYBACK ||
stream->ops == STREAM_OPS_PLAYBACK_DRM) {
if (sst_play_frame(str_id) < 0) {
- pr_warn("sst: play frames failed\n");
+ pr_warn("play frames failed\n");
mutex_unlock(&stream->lock);
return -EIO;
}
} else if (stream->ops == STREAM_OPS_CAPTURE) {
if (sst_capture_frame(str_id) < 0) {
- pr_warn("sst: capture frames failed\n ");
+ pr_warn("capture frames failed\n");
mutex_unlock(&stream->lock);
return -EIO;
}
@@ -365,7 +400,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk);
if (retval) {
stream->status = STREAM_INIT;
- pr_debug("sst: wait returned error...\n");
+ pr_debug("wait returned error...\n");
}
return retval;
}
@@ -377,7 +412,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
{
struct sst_stream_bufs *stream_bufs;
unsigned long index, mmap_len;
- unsigned char *bufp;
+ unsigned char __user *bufp;
unsigned long size, copied_size;
int retval = 0, add_to_list = 0;
static int sent_offset;
@@ -463,7 +498,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
if (((unsigned long)iovec[index].iov_base
+ iovec[index].iov_len) <
((unsigned long)iovec[index].iov_base)) {
- pr_debug("sst: Buffer overflows");
+ pr_debug("Buffer overflows\n");
kfree(stream_bufs);
return -EINVAL;
}
@@ -476,7 +511,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
}
copied_size += size;
- pr_debug("sst: copied_size - %lx\n", copied_size);
+ pr_debug("copied_size - %lx\n", copied_size);
if ((copied_size >= mmap_len) ||
(stream->sg_index == nr_segs)) {
add_to_list = 1;
@@ -506,15 +541,13 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
int retval = 0;
/* copy sent buffers */
- pr_debug("sst: capture stream copying to user now...\n");
+ pr_debug("capture stream copying to user now...\n");
list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
if (kbufs->in_use == true) {
/* copy to user */
list_for_each_entry_safe(entry, _entry,
copy_to_list, node) {
- if (copy_to_user((void *)
- iovec[entry->iov_index].iov_base +
- entry->iov_offset,
+ if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset,
kbufs->addr + entry->offset,
entry->size)) {
/* Clean up the list and return error */
@@ -526,7 +559,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
}
}
}
- pr_debug("sst: end of cap copy\n");
+ pr_debug("end of cap copy\n");
return retval;
}
@@ -578,7 +611,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
return -EINVAL;
stream = &sst_drv_ctx->streams[str_id];
if (stream->mmapped == true) {
- pr_warn("sst: user write and stream is mapped");
+ pr_warn("user write and stream is mapped\n");
return -EIO;
}
if (!count)
@@ -586,11 +619,11 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
stream->curr_bytes = 0;
stream->cumm_bytes = 0;
/* copy user buf details */
- pr_debug("sst: new buffers %p, copy size %d, status %d\n" ,
+ pr_debug("new buffers %p, copy size %d, status %d\n" ,
buf, (int) count, (int) stream->status);
stream->buf_type = SST_BUF_USER_STATIC;
- iovec.iov_base = (void *)buf;
+ iovec.iov_base = buf;
iovec.iov_len = count;
nr_segs = 1;
@@ -606,7 +639,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
stream->cur_ptr = NULL;
if (retval >= 0)
retval = stream->cumm_bytes;
- pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ pr_debug("end of play/rec bytes = %d!!\n", retval);
return retval;
}
@@ -627,7 +660,7 @@ int intel_sst_write(struct file *file_ptr, const char __user *buf,
int str_id = data->str_id;
struct stream_info *stream = &sst_drv_ctx->streams[str_id];
- pr_debug("sst: called for %d\n", str_id);
+ pr_debug("called for %d\n", str_id);
if (stream->status == STREAM_UN_INIT ||
stream->status == STREAM_DECODE) {
return -EBADRQC;
@@ -653,12 +686,12 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
int str_id = data->str_id;
struct stream_info *stream;
- pr_debug("sst: entry - %ld\n", nr_segs);
+ pr_debug("entry - %ld\n", nr_segs);
if (is_sync_kiocb(kiocb) == false)
return -EINVAL;
- pr_debug("sst: called for str_id %d\n", str_id);
+ pr_debug("called for str_id %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return -EINVAL;
@@ -671,7 +704,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
}
stream->curr_bytes = 0;
stream->cumm_bytes = 0;
- pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+ pr_debug("new segs %ld, offset %d, status %d\n" ,
nr_segs, (int) offset, (int) stream->status);
stream->buf_type = SST_BUF_USER_STATIC;
do {
@@ -686,7 +719,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
stream->cur_ptr = NULL;
if (retval >= 0)
retval = stream->cumm_bytes;
- pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ pr_debug("end of play/rec bytes = %d!!\n", retval);
return retval;
}
@@ -707,7 +740,7 @@ int intel_sst_read(struct file *file_ptr, char __user *buf,
int str_id = data->str_id;
struct stream_info *stream = &sst_drv_ctx->streams[str_id];
- pr_debug("sst: called for %d\n", str_id);
+ pr_debug("called for %d\n", str_id);
if (stream->status == STREAM_UN_INIT ||
stream->status == STREAM_DECODE)
return -EBADRQC;
@@ -732,14 +765,14 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
int str_id = data->str_id;
struct stream_info *stream;
- pr_debug("sst: entry - %ld\n", nr_segs);
+ pr_debug("entry - %ld\n", nr_segs);
if (is_sync_kiocb(kiocb) == false) {
- pr_debug("sst: aio_read from user space is not allowed\n");
+ pr_debug("aio_read from user space is not allowed\n");
return -EINVAL;
}
- pr_debug("sst: called for str_id %d\n", str_id);
+ pr_debug("called for str_id %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return -EINVAL;
@@ -752,7 +785,7 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
stream->curr_bytes = 0;
stream->cumm_bytes = 0;
- pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+ pr_debug("new segs %ld, offset %d, status %d\n" ,
nr_segs, (int) offset, (int) stream->status);
stream->buf_type = SST_BUF_USER_STATIC;
do {
@@ -767,34 +800,169 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
stream->cur_ptr = NULL;
if (retval >= 0)
retval = stream->cumm_bytes;
- pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ pr_debug("end of play/rec bytes = %d!!\n", retval);
return retval;
}
/* sst_print_stream_params - prints the stream parameters (debug fn)*/
static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm)
{
- pr_debug("sst: codec params:result =%d\n",
+ pr_debug("codec params:result = %d\n",
get_prm->codec_params.result);
- pr_debug("sst: codec params:stream = %d\n",
+ pr_debug("codec params:stream = %d\n",
get_prm->codec_params.stream_id);
- pr_debug("sst: codec params:codec = %d\n",
+ pr_debug("codec params:codec = %d\n",
get_prm->codec_params.codec);
- pr_debug("sst: codec params:ops = %d\n",
+ pr_debug("codec params:ops = %d\n",
get_prm->codec_params.ops);
- pr_debug("sst: codec params:stream_type= %d\n",
+ pr_debug("codec params:stream_type = %d\n",
get_prm->codec_params.stream_type);
- pr_debug("sst: pcmparams:sfreq= %d\n",
+ pr_debug("pcmparams:sfreq = %d\n",
get_prm->pcm_params.sfreq);
- pr_debug("sst: pcmparams:num_chan= %d\n",
+ pr_debug("pcmparams:num_chan = %d\n",
get_prm->pcm_params.num_chan);
- pr_debug("sst: pcmparams:pcm_wd_sz= %d\n",
+ pr_debug("pcmparams:pcm_wd_sz = %d\n",
get_prm->pcm_params.pcm_wd_sz);
return;
}
/**
- * intel_sst_ioctl - recieves the device ioctl's
+ * sst_create_algo_ipc - create ipc msg for algorithm parameters
+ *
+ * @algo_params: Algorithm parameters
+ * @msg: post msg pointer
+ *
+ * This function is called to create ipc msg
+ */
+int sst_create_algo_ipc(struct snd_ppp_params *algo_params,
+ struct ipc_post **msg)
+{
+ if (sst_create_large_msg(msg))
+ return -ENOMEM;
+ sst_fill_header(&(*msg)->header,
+ IPC_IA_ALG_PARAMS, 1, algo_params->str_id);
+ (*msg)->header.part.data = sizeof(u32) +
+ sizeof(*algo_params) + algo_params->size;
+ memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32));
+ memcpy((*msg)->mailbox_data + sizeof(u32),
+ algo_params, sizeof(*algo_params));
+ return 0;
+}
+
+/**
+ * sst_send_algo_ipc - send ipc msg for algorithm parameters
+ *
+ * @msg: post msg pointer
+ *
+ * This function is called to send ipc msg
+ */
+int sst_send_algo_ipc(struct ipc_post **msg)
+{
+ sst_drv_ctx->ppp_params_blk.condition = false;
+ sst_drv_ctx->ppp_params_blk.ret_code = 0;
+ sst_drv_ctx->ppp_params_blk.on = true;
+ sst_drv_ctx->ppp_params_blk.data = NULL;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT);
+}
+
+/**
+ * intel_sst_ioctl_dsp - recieves the device ioctl's
+ *
+ * @cmd:Ioctl cmd
+ * @arg:data
+ *
+ * This function is called when a user space component
+ * sends a DSP Ioctl to SST driver
+ */
+long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ struct snd_ppp_params algo_params;
+ struct snd_ppp_params *algo_params_copied;
+ struct ipc_post *msg;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(SNDRV_SST_SET_ALGO):
+ if (copy_from_user(&algo_params, (void __user *)arg,
+ sizeof(algo_params)))
+ return -EFAULT;
+ if (algo_params.size > SST_MAILBOX_SIZE)
+ return -EMSGSIZE;
+
+ pr_debug("Algo ID %d Str id %d Enable %d Size %d\n",
+ algo_params.algo_id, algo_params.str_id,
+ algo_params.enable, algo_params.size);
+ retval = sst_create_algo_ipc(&algo_params, &msg);
+ if (retval)
+ break;
+ algo_params.reserved = 0;
+ if (copy_from_user(msg->mailbox_data + sizeof(algo_params),
+ algo_params.params, algo_params.size))
+ return -EFAULT;
+
+ retval = sst_send_algo_ipc(&msg);
+ if (retval) {
+ pr_debug("Error in sst_set_algo = %d\n", retval);
+ retval = -EIO;
+ }
+ break;
+
+ case _IOC_NR(SNDRV_SST_GET_ALGO):
+ if (copy_from_user(&algo_params, (void __user *)arg,
+ sizeof(algo_params)))
+ return -EFAULT;
+ pr_debug("Algo ID %d Str id %d Enable %d Size %d\n",
+ algo_params.algo_id, algo_params.str_id,
+ algo_params.enable, algo_params.size);
+ retval = sst_create_algo_ipc(&algo_params, &msg);
+ if (retval)
+ break;
+ algo_params.reserved = 1;
+ retval = sst_send_algo_ipc(&msg);
+ if (retval) {
+ pr_debug("Error in sst_get_algo = %d\n", retval);
+ retval = -EIO;
+ break;
+ }
+ algo_params_copied = (struct snd_ppp_params *)
+ sst_drv_ctx->ppp_params_blk.data;
+ if (algo_params_copied->size > algo_params.size) {
+ pr_debug("mem insufficient to copy\n");
+ retval = -EMSGSIZE;
+ goto free_mem;
+ } else {
+ char __user *tmp;
+
+ if (copy_to_user(algo_params.params,
+ algo_params_copied->params,
+ algo_params_copied->size)) {
+ retval = -EFAULT;
+ goto free_mem;
+ }
+ tmp = (char __user *)arg + offsetof(
+ struct snd_ppp_params, size);
+ if (copy_to_user(tmp, &algo_params_copied->size,
+ sizeof(__u32))) {
+ retval = -EFAULT;
+ goto free_mem;
+ }
+
+ }
+free_mem:
+ kfree(algo_params_copied->params);
+ kfree(algo_params_copied);
+ break;
+ }
+ return retval;
+}
+
+/**
+ * intel_sst_ioctl - receives the device ioctl's
* @file_ptr:pointer to file
* @cmd:Ioctl cmd
* @arg:data
@@ -820,7 +988,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
switch (_IOC_NR(cmd)) {
case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
- pr_debug("sst: IOCTL_PAUSE recieved for %d!\n", str_id);
+ pr_debug("IOCTL_PAUSE received for %d!\n", str_id);
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
@@ -829,7 +997,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
break;
case _IOC_NR(SNDRV_SST_STREAM_RESUME):
- pr_debug("sst: SNDRV_SST_IOCTL_RESUME recieved!\n");
+ pr_debug("SNDRV_SST_IOCTL_RESUME received!\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
@@ -838,25 +1006,33 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
break;
case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
- struct snd_sst_params *str_param = (struct snd_sst_params *)arg;
+ struct snd_sst_params str_param;
- pr_debug("sst: IOCTL_SET_PARAMS recieved!\n");
+ pr_debug("IOCTL_SET_PARAMS received!\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
}
+ if (copy_from_user(&str_param, (void __user *)arg,
+ sizeof(str_param))) {
+ retval = -EFAULT;
+ break;
+ }
+
if (!str_id) {
- retval = sst_get_stream(str_param);
+ retval = sst_get_stream(&str_param);
if (retval > 0) {
struct stream_info *str_info;
+ char __user *dest;
+
sst_drv_ctx->stream_cnt++;
data->str_id = retval;
str_info = &sst_drv_ctx->streams[retval];
str_info->src = SST_DRV;
- retval = copy_to_user(&str_param->stream_id,
- &retval, sizeof(__u32));
+ dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id);
+ retval = copy_to_user(dest, &retval, sizeof(__u32));
if (retval)
retval = -EFAULT;
} else {
@@ -864,18 +1040,16 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
retval = -EINVAL;
}
} else {
- pr_debug("sst: SET_STREAM_PARAMS recieved!\n");
+ pr_debug("SET_STREAM_PARAMS received!\n");
/* allocated set params only */
- retval = sst_set_stream_param(str_id, str_param);
+ retval = sst_set_stream_param(str_id, &str_param);
/* Block the call for reply */
if (!retval) {
int sfreq = 0, word_size = 0, num_channel = 0;
- sfreq = str_param->sparams.uc.pcm_params.sfreq;
- word_size = str_param->sparams.
- uc.pcm_params.pcm_wd_sz;
- num_channel = str_param->
- sparams.uc.pcm_params.num_chan;
- if (str_param->ops == STREAM_OPS_CAPTURE) {
+ sfreq = str_param.sparams.uc.pcm_params.sfreq;
+ word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz;
+ num_channel = str_param.sparams.uc.pcm_params.num_chan;
+ if (str_param.ops == STREAM_OPS_CAPTURE) {
sst_drv_ctx->scard_ops->\
set_pcm_audio_params(sfreq,
word_size, num_channel);
@@ -885,50 +1059,48 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
break;
}
case _IOC_NR(SNDRV_SST_SET_VOL): {
- struct snd_sst_vol *set_vol;
- struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
- pr_debug("sst: SET_VOLUME recieved for %d!\n",
- rec_vol->stream_id);
- if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
- pr_debug("sst: invalid operation!\n");
- retval = -EPERM;
- break;
- }
- set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC);
- if (!set_vol) {
- pr_debug("sst: mem allocation failed\n");
- retval = -ENOMEM;
+ struct snd_sst_vol set_vol;
+
+ if (copy_from_user(&set_vol, (void __user *)arg,
+ sizeof(set_vol))) {
+ pr_debug("copy failed\n");
+ retval = -EFAULT;
break;
}
- if (copy_from_user(set_vol, rec_vol, sizeof(*set_vol))) {
- pr_debug("sst: copy failed\n");
- retval = -EFAULT;
+ pr_debug("SET_VOLUME recieved for %d!\n",
+ set_vol.stream_id);
+ if (minor == STREAM_MODULE && set_vol.stream_id == 0) {
+ pr_debug("invalid operation!\n");
+ retval = -EPERM;
break;
}
- retval = sst_set_vol(set_vol);
- kfree(set_vol);
+ retval = sst_set_vol(&set_vol);
break;
}
case _IOC_NR(SNDRV_SST_GET_VOL): {
- struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
struct snd_sst_vol get_vol;
- pr_debug("sst: IOCTL_GET_VOLUME recieved for stream = %d!\n",
- rec_vol->stream_id);
- if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
- pr_debug("sst: invalid operation!\n");
+
+ if (copy_from_user(&get_vol, (void __user *)arg,
+ sizeof(get_vol))) {
+ retval = -EFAULT;
+ break;
+ }
+ pr_debug("IOCTL_GET_VOLUME recieved for stream = %d!\n",
+ get_vol.stream_id);
+ if (minor == STREAM_MODULE && get_vol.stream_id == 0) {
+ pr_debug("invalid operation!\n");
retval = -EPERM;
break;
}
- get_vol.stream_id = rec_vol->stream_id;
retval = sst_get_vol(&get_vol);
if (retval) {
retval = -EIO;
break;
}
- pr_debug("sst: id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
+ pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
get_vol.stream_id, get_vol.volume,
get_vol.ramp_duration, get_vol.ramp_type);
- if (copy_to_user((struct snd_sst_vol *)arg,
+ if (copy_to_user((struct snd_sst_vol __user *)arg,
&get_vol, sizeof(get_vol))) {
retval = -EFAULT;
break;
@@ -938,31 +1110,26 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
}
case _IOC_NR(SNDRV_SST_MUTE): {
- struct snd_sst_mute *set_mute;
- struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg;
- pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n",
- rec_mute->stream_id);
- if (minor == STREAM_MODULE && rec_mute->stream_id == 0) {
- retval = -EPERM;
- break;
- }
- set_mute = kzalloc(sizeof(*set_mute), GFP_ATOMIC);
- if (!set_mute) {
- retval = -ENOMEM;
+ struct snd_sst_mute set_mute;
+
+ if (copy_from_user(&set_mute, (void __user *)arg,
+ sizeof(set_mute))) {
+ retval = -EFAULT;
break;
}
- if (copy_from_user(set_mute, rec_mute, sizeof(*set_mute))) {
- retval = -EFAULT;
+ pr_debug("SNDRV_SST_SET_VOLUME recieved for %d!\n",
+ set_mute.stream_id);
+ if (minor == STREAM_MODULE && set_mute.stream_id == 0) {
+ retval = -EPERM;
break;
}
- retval = sst_set_mute(set_mute);
- kfree(set_mute);
+ retval = sst_set_mute(&set_mute);
break;
}
case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
struct snd_sst_get_stream_params get_params;
- pr_debug("sst: IOCTL_GET_PARAMS recieved!\n");
+ pr_debug("IOCTL_GET_PARAMS received!\n");
if (minor != 0) {
retval = -EBADRQC;
break;
@@ -973,7 +1140,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
retval = -EIO;
break;
}
- if (copy_to_user((struct snd_sst_get_stream_params *)arg,
+ if (copy_to_user((struct snd_sst_get_stream_params __user *)arg,
&get_params, sizeof(get_params))) {
retval = -EFAULT;
break;
@@ -983,18 +1150,24 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
}
case _IOC_NR(SNDRV_SST_MMAP_PLAY):
- case _IOC_NR(SNDRV_SST_MMAP_CAPTURE):
- pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
+ case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): {
+ struct snd_sst_mmap_buffs mmap_buf;
+
+ pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
}
- retval = intel_sst_mmap_play_capture(str_id,
- (struct snd_sst_mmap_buffs *)arg);
+ if (copy_from_user(&mmap_buf, (void __user *)arg,
+ sizeof(mmap_buf))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = intel_sst_mmap_play_capture(str_id, &mmap_buf);
break;
-
+ }
case _IOC_NR(SNDRV_SST_STREAM_DROP):
- pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n");
+ pr_debug("SNDRV_SST_IOCTL_DROP received!\n");
if (minor != STREAM_MODULE) {
retval = -EINVAL;
break;
@@ -1003,24 +1176,23 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
break;
case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): {
- unsigned long long *ms = (unsigned long long *)arg;
struct snd_sst_tstamp tstamp = {0};
unsigned long long time, freq, mod;
- pr_debug("sst: SNDRV_SST_STREAM_GET_TSTAMP recieved!\n");
+ pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
}
memcpy_fromio(&tstamp,
- ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
- +(str_id * sizeof(tstamp))),
+ sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
sizeof(tstamp));
time = tstamp.samples_rendered;
freq = (unsigned long long) tstamp.sampling_frequency;
time = time * 1000; /* converting it to ms */
mod = do_div(time, freq);
- if (copy_to_user(ms, &time, sizeof(*ms)))
+ if (copy_to_user((void __user *)arg, &time,
+ sizeof(unsigned long long)))
retval = -EFAULT;
break;
}
@@ -1028,7 +1200,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_SST_STREAM_START):{
struct stream_info *stream;
- pr_debug("sst: SNDRV_SST_STREAM_START recieved!\n");
+ pr_debug("SNDRV_SST_STREAM_START received!\n");
if (minor != STREAM_MODULE) {
retval = -EINVAL;
break;
@@ -1065,97 +1237,123 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
}
case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
- struct snd_sst_target_device *target_device;
+ struct snd_sst_target_device target_device;
- pr_debug("sst: SET_TARGET_DEVICE recieved!\n");
- target_device = (struct snd_sst_target_device *)arg;
- BUG_ON(!target_device);
+ pr_debug("SET_TARGET_DEVICE recieved!\n");
+ if (copy_from_user(&target_device, (void __user *)arg,
+ sizeof(target_device))) {
+ retval = -EFAULT;
+ break;
+ }
if (minor != AM_MODULE) {
retval = -EBADRQC;
break;
}
- retval = sst_target_device_select(target_device);
+ retval = sst_target_device_select(&target_device);
break;
}
case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
- struct snd_sst_driver_info *info =
- (struct snd_sst_driver_info *)arg;
+ struct snd_sst_driver_info info;
- pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n");
- info->version = SST_VERSION_NUM;
+ pr_debug("SNDRV_SST_DRIVER_INFO recived\n");
+ info.version = SST_VERSION_NUM;
/* hard coding, shud get sumhow later */
- info->active_pcm_streams = sst_drv_ctx->stream_cnt -
+ info.active_pcm_streams = sst_drv_ctx->stream_cnt -
sst_drv_ctx->encoded_cnt;
- info->active_enc_streams = sst_drv_ctx->encoded_cnt;
- info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
- info->max_enc_streams = MAX_ENC_STREAM;
- info->buf_per_stream = sst_drv_ctx->mmap_len;
+ info.active_enc_streams = sst_drv_ctx->encoded_cnt;
+ info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
+ info.max_enc_streams = MAX_ENC_STREAM;
+ info.buf_per_stream = sst_drv_ctx->mmap_len;
+ if (copy_to_user((void __user *)arg, &info,
+ sizeof(info)))
+ retval = -EFAULT;
break;
}
case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
- struct snd_sst_dbufs *param =
- (struct snd_sst_dbufs *)arg, dbufs_local;
- int i;
+ struct snd_sst_dbufs param;
+ struct snd_sst_dbufs dbufs_local;
struct snd_sst_buffs ibufs, obufs;
- struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
- obuf_temp[param->obufs->entries];
+ struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
+ char __user *dest;
- pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
+ pr_debug("SNDRV_SST_STREAM_DECODE received\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
}
- if (!param) {
- retval = -EINVAL;
+ if (copy_from_user(&param, (void __user *)arg,
+ sizeof(param))) {
+ retval = -EFAULT;
break;
}
- dbufs_local.input_bytes_consumed = param->input_bytes_consumed;
+ dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
dbufs_local.output_bytes_produced =
- param->output_bytes_produced;
- dbufs_local.ibufs = &ibufs;
- dbufs_local.obufs = &obufs;
- dbufs_local.ibufs->entries = param->ibufs->entries;
- dbufs_local.ibufs->type = param->ibufs->type;
- dbufs_local.obufs->entries = param->obufs->entries;
- dbufs_local.obufs->type = param->obufs->type;
-
- dbufs_local.ibufs->buff_entry = ibuf_temp;
- for (i = 0; i < dbufs_local.ibufs->entries; i++) {
- ibuf_temp[i].buffer =
- param->ibufs->buff_entry[i].buffer;
- ibuf_temp[i].size =
- param->ibufs->buff_entry[i].size;
+ param.output_bytes_produced;
+
+ if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) {
+ retval = -EFAULT;
+ break;
}
- dbufs_local.obufs->buff_entry = obuf_temp;
- for (i = 0; i < dbufs_local.obufs->entries; i++) {
- obuf_temp[i].buffer =
- param->obufs->buff_entry[i].buffer;
- obuf_temp[i].size =
- param->obufs->buff_entry[i].size;
+ if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) {
+ retval = -EFAULT;
+ break;
}
+
+ ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL);
+ obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL);
+ if (!ibuf_tmp || !obuf_tmp) {
+ retval = -ENOMEM;
+ goto free_iobufs;
+ }
+
+ if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry,
+ ibufs.entries * sizeof(*ibuf_tmp))) {
+ retval = -EFAULT;
+ goto free_iobufs;
+ }
+ ibufs.buff_entry = ibuf_tmp;
+ dbufs_local.ibufs = &ibufs;
+
+ if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry,
+ obufs.entries * sizeof(*obuf_tmp))) {
+ retval = -EFAULT;
+ goto free_iobufs;
+ }
+ obufs.buff_entry = obuf_tmp;
+ dbufs_local.obufs = &obufs;
+
retval = sst_decode(str_id, &dbufs_local);
- if (retval)
- retval = -EAGAIN;
- if (copy_to_user(&param->input_bytes_consumed,
+ if (retval) {
+ retval = -EAGAIN;
+ goto free_iobufs;
+ }
+
+ dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+ if (copy_to_user(dest,
&dbufs_local.input_bytes_consumed,
sizeof(unsigned long long))) {
- retval = -EFAULT;
- break;
+ retval = -EFAULT;
+ goto free_iobufs;
}
- if (copy_to_user(&param->output_bytes_produced,
+
+ dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+ if (copy_to_user(dest,
&dbufs_local.output_bytes_produced,
sizeof(unsigned long long))) {
- retval = -EFAULT;
- break;
+ retval = -EFAULT;
+ goto free_iobufs;
}
+free_iobufs:
+ kfree(ibuf_tmp);
+ kfree(obuf_tmp);
break;
}
case _IOC_NR(SNDRV_SST_STREAM_DRAIN):
- pr_debug("sst: SNDRV_SST_STREAM_DRAIN recived\n");
+ pr_debug("SNDRV_SST_STREAM_DRAIN received\n");
if (minor != STREAM_MODULE) {
retval = -EINVAL;
break;
@@ -1164,17 +1362,16 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
break;
case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): {
- unsigned long long *bytes = (unsigned long long *)arg;
+ unsigned long long __user *bytes = (unsigned long long __user *)arg;
struct snd_sst_tstamp tstamp = {0};
- pr_debug("sst: STREAM_BYTES_DECODED recieved!\n");
+ pr_debug("STREAM_BYTES_DECODED received!\n");
if (minor != STREAM_MODULE) {
retval = -EINVAL;
break;
}
memcpy_fromio(&tstamp,
- ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
- +(str_id * sizeof(tstamp))),
+ sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
sizeof(tstamp));
if (copy_to_user(bytes, &tstamp.bytes_processed,
sizeof(*bytes)))
@@ -1184,7 +1381,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_SST_FW_INFO): {
struct snd_sst_fw_info *fw_info;
- pr_debug("sst: SNDRV_SST_FW_INFO recived\n");
+ pr_debug("SNDRV_SST_FW_INFO received\n");
fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC);
if (!fw_info) {
@@ -1197,7 +1394,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
kfree(fw_info);
break;
}
- if (copy_to_user((struct snd_sst_dbufs *)arg,
+ if (copy_to_user((struct snd_sst_dbufs __user *)arg,
fw_info, sizeof(*fw_info))) {
kfree(fw_info);
retval = -EFAULT;
@@ -1207,10 +1404,18 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
kfree(fw_info);
break;
}
+ case _IOC_NR(SNDRV_SST_GET_ALGO):
+ case _IOC_NR(SNDRV_SST_SET_ALGO):
+ if (minor != AM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = intel_sst_ioctl_dsp(cmd, arg);
+ break;
default:
retval = -EINVAL;
}
- pr_debug("sst: intel_sst_ioctl:complete ret code = %d\n", retval);
+ pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval);
return retval;
}
diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h
index 73a98c851e4a..0a60e865b696 100644
--- a/drivers/staging/intel_sst/intel_sst_common.h
+++ b/drivers/staging/intel_sst/intel_sst_common.h
@@ -28,15 +28,15 @@
* Common private declarations for SST
*/
-#define SST_DRIVER_VERSION "1.2.05"
-#define SST_VERSION_NUM 0x1205
+#define SST_DRIVER_VERSION "1.2.09"
+#define SST_VERSION_NUM 0x1209
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
-#define SST_FW_FILENAME_MRST "fw_sst_080a.bin"
-#define SST_FW_FILENAME_MFLD "fw_sst_082f.bin"
#define SST_MRST_PCI_ID 0x080A
#define SST_MFLD_PCI_ID 0x082F
+#define PCI_ID_LENGTH 4
+#define SST_SUSPEND_DELAY 2000
enum sst_states {
SST_FW_LOADED = 1,
@@ -231,8 +231,8 @@ struct stream_info {
spinlock_t pcm_lock;
bool mmapped;
unsigned int sg_index; /* current buf Index */
- unsigned char *cur_ptr; /* Current static bufs */
- struct snd_sst_buf_entry *buf_entry;
+ unsigned char __user *cur_ptr; /* Current static bufs */
+ struct snd_sst_buf_entry __user *buf_entry;
struct sst_block data_blk; /* stream ops block */
struct sst_block ctrl_blk; /* stream control cmd block */
enum snd_sst_buf_type buf_type;
@@ -392,7 +392,7 @@ struct intel_sst_drv {
struct stream_info streams[MAX_NUM_STREAMS];
struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
- struct sst_block tgt_dev_blk, fw_info_blk,
+ struct sst_block tgt_dev_blk, fw_info_blk, ppp_params_blk,
vol_info_blk, mute_info_blk, hs_info_blk;
struct mutex list_lock;/* mutex for IPC list locking */
spinlock_t list_spin_lock; /* mutex for IPC list locking */
diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c
index 669e298016f2..ea8e251b5099 100644
--- a/drivers/staging/intel_sst/intel_sst_drv_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c
@@ -26,10 +26,13 @@
* Upper layer interfaces (MAD driver, MMF) to SST driver
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
@@ -45,17 +48,18 @@ int sst_download_fw(void)
{
int retval;
const struct firmware *fw_sst;
- const char *name;
+ char name[20];
+
if (sst_drv_ctx->sst_state != SST_UN_INIT)
return -EPERM;
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
- name = SST_FW_FILENAME_MRST;
- else
- name = SST_FW_FILENAME_MFLD;
- pr_debug("sst: Downloading %s FW now...\n", name);
+
+ snprintf(name, sizeof(name), "%s%04x%s", "fw_sst_",
+ sst_drv_ctx->pci_id, ".bin");
+
+ pr_debug("Downloading %s FW now...\n", name);
retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev);
if (retval) {
- pr_err("sst: request fw failed %d\n", retval);
+ pr_err("request fw failed %d\n", retval);
return retval;
}
sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID;
@@ -66,7 +70,7 @@ int sst_download_fw(void)
retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]);
if (retval)
- pr_err("sst: fw download failed %d\n" , retval);
+ pr_err("fw download failed %d\n" , retval);
end_restore:
release_firmware(fw_sst);
sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
@@ -90,7 +94,7 @@ int sst_stalled(void)
retry--;
}
- pr_debug("sst: in Stalled State\n");
+ pr_debug("in Stalled State\n");
return retval;
}
@@ -138,23 +142,23 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
str_param->codec, str_param->device_type);
if (retval < 0) {
- pr_err("sst: sst_alloc_stream failed %d\n", retval);
+ pr_err("sst_alloc_stream failed %d\n", retval);
return retval;
}
- pr_debug("sst: Stream allocated %d\n", retval);
+ pr_debug("Stream allocated %d\n", retval);
str_id = retval;
str_info = &sst_drv_ctx->streams[str_id];
/* Block the call for reply */
retval = sst_wait_interruptible_timeout(sst_drv_ctx,
&str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) {
- pr_debug("sst: FW alloc failed retval %d, ret_code %d\n",
+ pr_debug("FW alloc failed retval %d, ret_code %d\n",
retval, str_info->ctrl_blk.ret_code);
str_id = -str_info->ctrl_blk.ret_code; /*return error*/
*lib_dnld = str_info->ctrl_blk.data;
sst_clean_stream(str_info);
} else
- pr_debug("sst: FW Stream allocated sucess\n");
+ pr_debug("FW Stream allocated success\n");
return str_id; /*will ret either error (in above if) or correct str id*/
}
@@ -171,9 +175,9 @@ static int sst_get_sfreq(struct snd_sst_params *str_param)
case SST_CODEC_TYPE_MP3:
return str_param->sparams.uc.mp3_params.sfreq;
case SST_CODEC_TYPE_AAC:
- return str_param->sparams.uc.aac_params.sfreq;;
+ return str_param->sparams.uc.aac_params.sfreq;
case SST_CODEC_TYPE_WMA9:
- return str_param->sparams.uc.wma_params.sfreq;;
+ return str_param->sparams.uc.wma_params.sfreq;
default:
return 0;
}
@@ -196,14 +200,14 @@ int sst_get_stream(struct snd_sst_params *str_param)
/* codec download is required */
struct snd_sst_alloc_response *response;
- pr_debug("sst: Codec is required.... trying that\n");
+ pr_debug("Codec is required.... trying that\n");
if (lib_dnld == NULL) {
- pr_err("sst: lib download null!!! abort\n");
+ pr_err("lib download null!!! abort\n");
return -EIO;
}
i = sst_get_block_stream(sst_drv_ctx);
response = sst_drv_ctx->alloc_block[i].ops_block.data;
- pr_debug("sst: alloc block allocated = %d\n", i);
+ pr_debug("alloc block allocated = %d\n", i);
if (i < 0) {
kfree(lib_dnld);
return -ENOMEM;
@@ -213,15 +217,15 @@ int sst_get_stream(struct snd_sst_params *str_param)
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
if (!retval) {
- pr_debug("sst: codec was downloaded sucesfully\n");
+ pr_debug("codec was downloaded successfully\n");
retval = sst_get_stream_allocated(str_param, &lib_dnld);
if (retval <= 0)
goto err;
- pr_debug("sst: Alloc done stream id %d\n", retval);
+ pr_debug("Alloc done stream id %d\n", retval);
} else {
- pr_debug("sst: codec download failed\n");
+ pr_debug("codec download failed\n");
retval = -EIO;
goto err;
}
@@ -279,97 +283,138 @@ void sst_process_mad_ops(struct work_struct *work)
retval = sst_start_stream(mad_ops->stream_id);
break;
case SST_SND_STREAM_PROCESS:
- pr_debug("sst: play/capt frames...\n");
+ pr_debug("play/capt frames...\n");
break;
default:
- pr_err("sst: wrong control_ops reported\n");
+ pr_err(" wrong control_ops reported\n");
}
return;
}
+
+void send_intial_rx_timeslot(void)
+{
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID &&
+ sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT
+ && sst_drv_ctx->pmic_vendor != SND_NC)
+ sst_enable_rx_timeslot(sst_drv_ctx->rx_time_slot_status);
+}
+
/*
- * sst_control_set - Set Control params
+ * sst_open_pcm_stream - Open PCM interface
*
- * @control_list: list of controls to be set
+ * @str_param: parameters of pcm stream
*
- * This function is called by MID sound card driver to set
- * SST/Sound card controls. This is registered with MID driver
+ * This function is called by MID sound card driver to open
+ * a new pcm interface
*/
-int sst_control_set(int control_element, void *value)
+int sst_open_pcm_stream(struct snd_sst_params *str_param)
{
- int retval = 0, str_id = 0;
- struct stream_info *stream;
+ struct stream_info *str_info;
+ int retval;
+
+ pm_runtime_get_sync(&sst_drv_ctx->pci->dev);
if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
- /*LPE is suspended, resume it before proceding*/
- pr_debug("sst: Resuming from Suspended state\n");
+ /* LPE is suspended, resume it before proceding*/
+ pr_debug("Resuming from Suspended state\n");
retval = intel_sst_resume(sst_drv_ctx->pci);
if (retval) {
- pr_err("sst: Resume Failed = %#x, abort\n", retval);
+ pr_err("Resume Failed = %#x, abort\n", retval);
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
return retval;
}
}
if (sst_drv_ctx->sst_state == SST_UN_INIT) {
/* FW is not downloaded */
- pr_debug("sst: DSP Downloading FW now...\n");
+ pr_debug("DSP Downloading FW now...\n");
retval = sst_download_fw();
if (retval) {
- pr_err("sst: FW download fail %x, abort\n", retval);
+ pr_err("FW download fail %x, abort\n", retval);
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
return retval;
}
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID &&
- sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT
- && sst_drv_ctx->pmic_vendor != SND_NC)
- sst_enable_rx_timeslot(
- sst_drv_ctx->rx_time_slot_status);
+ send_intial_rx_timeslot();
}
- switch (control_element) {
- case SST_SND_ALLOC: {
- struct snd_sst_params *str_param;
- struct stream_info *str_info;
+ if (!str_param) {
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+ return -EINVAL;
+ }
- str_param = (struct snd_sst_params *)value;
- BUG_ON(!str_param);
- retval = sst_get_stream(str_param);
- if (retval >= 0)
- sst_drv_ctx->stream_cnt++;
+ retval = sst_get_stream(str_param);
+ if (retval > 0) {
+ sst_drv_ctx->stream_cnt++;
str_info = &sst_drv_ctx->streams[retval];
str_info->src = MAD_DRV;
- break;
- }
+ } else
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+
+ return retval;
+}
+/*
+ * sst_close_pcm_stream - Close PCM interface
+ *
+ * @str_id: stream id to be closed
+ *
+ * This function is called by MID sound card driver to close
+ * an existing pcm interface
+ */
+int sst_close_pcm_stream(unsigned int str_id)
+{
+ struct stream_info *stream;
+
+ pr_debug("sst: stream free called\n");
+ if (sst_validate_strid(str_id))
+ return -EINVAL;
+ stream = &sst_drv_ctx->streams[str_id];
+ free_stream_context(str_id);
+ stream->pcm_substream = NULL;
+ stream->status = STREAM_UN_INIT;
+ stream->period_elapsed = NULL;
+ sst_drv_ctx->stream_cnt--;
+ pr_debug("sst: will call runtime put now\n");
+ pm_runtime_put(&sst_drv_ctx->pci->dev);
+ return 0;
+}
+
+/*
+ * sst_device_control - Set Control params
+ *
+ * @cmd: control cmd to be set
+ * @arg: command argument
+ *
+ * This function is called by MID sound card driver to set
+ * SST/Sound card controls for an opened stream.
+ * This is registered with MID driver
+ */
+int sst_device_control(int cmd, void *arg)
+{
+ int retval = 0, str_id = 0;
+
+ switch (cmd) {
case SST_SND_PAUSE:
case SST_SND_RESUME:
case SST_SND_DROP:
case SST_SND_START:
- sst_drv_ctx->mad_ops.control_op = control_element;
- sst_drv_ctx->mad_ops.stream_id = *(int *)value;
+ sst_drv_ctx->mad_ops.control_op = cmd;
+ sst_drv_ctx->mad_ops.stream_id = *(int *)arg;
queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq);
break;
- case SST_SND_FREE:
- str_id = *(int *)value;
- stream = &sst_drv_ctx->streams[str_id];
- free_stream_context(str_id);
- stream->pcm_substream = NULL;
- stream->status = STREAM_UN_INIT;
- stream->period_elapsed = NULL;
- sst_drv_ctx->stream_cnt--;
- break;
-
case SST_SND_STREAM_INIT: {
struct pcm_stream_info *str_info;
struct stream_info *stream;
- pr_debug("sst: stream init called\n");
- str_info = (struct pcm_stream_info *)value;
+ pr_debug("stream init called\n");
+ str_info = (struct pcm_stream_info *)arg;
str_id = str_info->str_id;
retval = sst_validate_strid(str_id);
if (retval)
break;
stream = &sst_drv_ctx->streams[str_id];
- pr_debug("sst: setting the period ptrs\n");
+ pr_debug("setting the period ptrs\n");
stream->pcm_substream = str_info->mad_substream;
stream->period_elapsed = str_info->period_elapsed;
stream->sfreq = str_info->sfreq;
@@ -384,7 +429,7 @@ int sst_control_set(int control_element, void *value)
struct stream_info *stream;
- stream_info = (struct pcm_stream_info *)value;
+ stream_info = (struct pcm_stream_info *)arg;
str_id = stream_info->str_id;
retval = sst_validate_strid(str_id);
if (retval)
@@ -398,26 +443,26 @@ int sst_control_set(int control_element, void *value)
+(str_id * sizeof(fw_tstamp))),
sizeof(fw_tstamp));
- pr_debug("sst: Pointer Query on strid = %d ops %d\n",
+ pr_debug("Pointer Query on strid = %d ops %d\n",
str_id, stream->ops);
if (stream->ops == STREAM_OPS_PLAYBACK)
stream_info->buffer_ptr = fw_tstamp.samples_rendered;
else
stream_info->buffer_ptr = fw_tstamp.samples_processed;
- pr_debug("sst: Samples rendered = %llu, buffer ptr %llu\n",
+ pr_debug("Samples rendered = %llu, buffer ptr %llu\n",
fw_tstamp.samples_rendered, stream_info->buffer_ptr);
break;
}
case SST_ENABLE_RX_TIME_SLOT: {
- int status = *(int *)value;
+ int status = *(int *)arg;
sst_drv_ctx->rx_time_slot_status = status ;
sst_enable_rx_timeslot(status);
break;
}
default:
/* Illegal case */
- pr_warn("sst: illegal req\n");
+ pr_warn("illegal req\n");
return -EINVAL;
}
@@ -425,8 +470,14 @@ int sst_control_set(int control_element, void *value)
}
+struct intel_sst_pcm_control pcm_ops = {
+ .open = sst_open_pcm_stream,
+ .device_control = sst_device_control,
+ .close = sst_close_pcm_stream,
+};
+
struct intel_sst_card_ops sst_pmic_ops = {
- .control_set = sst_control_set,
+ .pcm_control = &pcm_ops,
};
/*
@@ -439,12 +490,12 @@ struct intel_sst_card_ops sst_pmic_ops = {
int register_sst_card(struct intel_sst_card_ops *card)
{
if (!sst_drv_ctx) {
- pr_err("sst: No SST driver register card reject\n");
+ pr_err("No SST driver register card reject\n");
return -ENODEV;
}
if (!card || !card->module_name) {
- pr_err("sst: Null Pointer Passed\n");
+ pr_err("Null Pointer Passed\n");
return -EINVAL;
}
if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) {
@@ -456,17 +507,17 @@ int register_sst_card(struct intel_sst_card_ops *card)
sst_pmic_ops.module_name = card->module_name;
sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
- card->control_set = sst_pmic_ops.control_set;
+ card->pcm_control = sst_pmic_ops.pcm_control;
sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
} else {
- pr_err("sst: strcmp fail %s\n", card->module_name);
+ pr_err("strcmp fail %s\n", card->module_name);
return -EINVAL;
}
} else {
/* already registered a driver */
- pr_err("sst: Repeat for registeration..denied\n");
+ pr_err("Repeat for registration..denied\n");
return -EBADRQC;
}
return 0;
@@ -482,11 +533,11 @@ EXPORT_SYMBOL_GPL(register_sst_card);
*/
void unregister_sst_card(struct intel_sst_card_ops *card)
{
- if (sst_pmic_ops.control_set == card->control_set) {
+ if (sst_pmic_ops.pcm_control == card->pcm_control) {
/* unreg */
sst_pmic_ops.module_name = "";
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
- pr_debug("sst: Unregistered %s\n", card->module_name);
+ pr_debug("Unregistered %s\n", card->module_name);
}
return;
}
diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c
index d80a6ee2deb8..6e5c9152da9f 100644
--- a/drivers/staging/intel_sst/intel_sst_dsp.c
+++ b/drivers/staging/intel_sst/intel_sst_dsp.c
@@ -29,6 +29,9 @@
* This file contains all dsp controlling functions like firmware download,
* setting/resetting dsp cores, etc
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/firmware.h>
@@ -47,8 +50,9 @@ static int intel_sst_reset_dsp_mrst(void)
{
union config_status_reg csr;
- pr_debug("sst: Resetting the DSP in mrst\n");
- csr.full = 0x3a2;
+ pr_debug("Resetting the DSP in mrst\n");
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.full |= 0x382;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.part.strb_cntr_rst = 0;
@@ -68,7 +72,7 @@ static int intel_sst_reset_dsp_medfield(void)
{
union config_status_reg csr;
- pr_debug("sst: Resetting the DSP in medfield\n");
+ pr_debug("Resetting the DSP in medfield\n");
csr.full = 0x048303E2;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
@@ -90,7 +94,7 @@ static int sst_start_mrst(void)
csr.part.run_stall = 0;
csr.part.sst_reset = 0;
csr.part.strb_cntr_rst = 1;
- pr_debug("sst: Setting SST to execute_mrst 0x%x\n", csr.full);
+ pr_debug("Setting SST to execute_mrst 0x%x\n", csr.full);
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
@@ -111,7 +115,7 @@ static int sst_start_medfield(void)
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
csr.full = 0x04830061;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
- pr_debug("sst: Starting the DSP_medfld\n");
+ pr_debug("Starting the DSP_medfld\n");
return 0;
}
@@ -130,16 +134,16 @@ static int sst_parse_module(struct fw_module_header *module)
u32 count;
void __iomem *ram;
- pr_debug("sst: module sign %s size %x blocks %x type %x\n",
+ pr_debug("module sign %s size %x blocks %x type %x\n",
module->signature, module->mod_size,
module->blocks, module->type);
- pr_debug("sst: module entrypoint 0x%x\n", module->entry_point);
+ pr_debug("module entrypoint 0x%x\n", module->entry_point);
block = (void *)module + sizeof(*module);
for (count = 0; count < module->blocks; count++) {
if (block->size <= 0) {
- pr_err("sst: block size invalid\n");
+ pr_err("block size invalid\n");
return -EINVAL;
}
switch (block->type) {
@@ -150,7 +154,7 @@ static int sst_parse_module(struct fw_module_header *module)
ram = sst_drv_ctx->dram;
break;
default:
- pr_err("sst: wrong ram type0x%x in block0x%x\n",
+ pr_err("wrong ram type0x%x in block0x%x\n",
block->type, count);
return -EINVAL;
}
@@ -184,10 +188,10 @@ static int sst_parse_fw_image(const struct firmware *sst_fw)
if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
(sst_fw->size != header->file_size + sizeof(*header))) {
/* Invalid FW signature */
- pr_err("sst: InvalidFW sign/filesize mismatch\n");
+ pr_err("Invalid FW sign/filesize mismatch\n");
return -EINVAL;
}
- pr_debug("sst: header sign=%s size=%x modules=%x fmt=%x size=%x\n",
+ pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n",
header->signature, header->file_size, header->modules,
header->file_format, sizeof(*header));
module = (void *)sst_fw->data + sizeof(*header);
@@ -214,7 +218,7 @@ int sst_load_fw(const struct firmware *fw, void *context)
{
int ret_val;
- pr_debug("sst: load_fw called\n");
+ pr_debug("load_fw called\n");
BUG_ON(!fw);
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
@@ -239,7 +243,7 @@ int sst_load_fw(const struct firmware *fw, void *context)
if (ret_val)
return ret_val;
- pr_debug("sst: fw loaded successful!!!\n");
+ pr_debug("fw loaded successful!!!\n");
return ret_val;
}
@@ -261,7 +265,7 @@ static int sst_download_library(const struct firmware *fw_lib,
pvt_id = sst_assign_pvt_id(sst_drv_ctx);
i = sst_get_block_stream(sst_drv_ctx);
- pr_debug("sst: alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
+ pr_debug("alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
if (i < 0) {
kfree(msg);
return -ENOMEM;
@@ -281,11 +285,11 @@ static int sst_download_library(const struct firmware *fw_lib,
if (retval) {
/* error */
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
- pr_err("sst: Prep codec downloaded failed %d\n",
+ pr_err("Prep codec downloaded failed %d\n",
retval);
return -EIO;
}
- pr_debug("sst: FW responded, ready for download now...\n");
+ pr_debug("FW responded, ready for download now...\n");
/* downloading on success */
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_FW_LOADED;
@@ -325,7 +329,7 @@ static int sst_download_library(const struct firmware *fw_lib,
list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
spin_unlock(&sst_drv_ctx->list_spin_lock);
sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
- pr_debug("sst: Waiting for FW response Download complete\n");
+ pr_debug("Waiting for FW response Download complete\n");
sst_drv_ctx->alloc_block[i].ops_block.condition = false;
retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
if (retval) {
@@ -337,7 +341,7 @@ static int sst_download_library(const struct firmware *fw_lib,
return -EIO;
}
- pr_debug("sst: FW sucess on Download complete\n");
+ pr_debug("FW success on Download complete\n");
sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_FW_RUNNING;
@@ -360,14 +364,14 @@ static int sst_validate_library(const struct firmware *fw_lib,
header = (struct fw_header *)fw_lib->data;
if (header->modules != 1) {
- pr_err("sst: Module no mismatch found\n ");
+ pr_err("Module no mismatch found\n");
err = -EINVAL;
goto exit;
}
module = (void *)fw_lib->data + sizeof(*header);
*entry_point = module->entry_point;
- pr_debug("sst: Module entry point 0x%x\n", *entry_point);
- pr_debug("sst: Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
+ pr_debug("Module entry point 0x%x\n", *entry_point);
+ pr_debug("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
module->signature, module->mod_size,
module->blocks, module->type);
@@ -381,20 +385,20 @@ static int sst_validate_library(const struct firmware *fw_lib,
dsize += block->size;
break;
default:
- pr_err("sst: Invalid block type for 0x%x\n", n_blk);
+ pr_err("Invalid block type for 0x%x\n", n_blk);
err = -EINVAL;
goto exit;
}
block = (void *)block + sizeof(*block) + block->size;
}
if (isize > slot->iram_size || dsize > slot->dram_size) {
- pr_err("sst: library exceeds size allocated\n");
+ pr_err("library exceeds size allocated\n");
err = -EINVAL;
goto exit;
} else
- pr_debug("sst: Library is safe for download...\n");
+ pr_debug("Library is safe for download...\n");
- pr_debug("sst: iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
+ pr_debug("iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
isize, dsize, slot->iram_size, slot->dram_size);
exit:
return err;
@@ -414,15 +418,15 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
memset(buf, 0, sizeof(buf));
- pr_debug("sst: Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
+ pr_debug("Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
- pr_debug("sst: Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
+ pr_debug("Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
lib->lib_info.lib_version, lib->lib_info.lib_name,
lib->lib_info.lib_caps, lib->lib_info.media_type);
- pr_debug("sst: IRAM Size 0x%x, offset 0x%x\n",
+ pr_debug("IRAM Size 0x%x, offset 0x%x\n",
lib->slot_info.iram_size, lib->slot_info.iram_offset);
- pr_debug("sst: DRAM Size 0x%x, offset 0x%x\n",
+ pr_debug("DRAM Size 0x%x, offset 0x%x\n",
lib->slot_info.dram_size, lib->slot_info.dram_offset);
switch (lib->lib_info.lib_type) {
@@ -442,7 +446,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
type = "wma9_";
break;
default:
- pr_err("sst: Invalid codec type\n");
+ pr_err("Invalid codec type\n");
error = -EINVAL;
goto wake;
}
@@ -458,11 +462,11 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
lib->slot_info.slot_num);
len += snprintf(buf + len, sizeof(buf) - len, ".bin");
- pr_debug("sst: Requesting %s\n", buf);
+ pr_debug("Requesting %s\n", buf);
error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
if (error) {
- pr_err("sst: library load failed %d\n", error);
+ pr_err("library load failed %d\n", error);
goto wake;
}
error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
@@ -476,7 +480,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
goto wake_free;
/* lib is downloaded and init send alloc again */
- pr_debug("sst: Library is downloaded now...\n");
+ pr_debug("Library is downloaded now...\n");
wake_free:
/* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
release_firmware(fw_lib);
diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
index 9d3c36807e07..8df313d10d2a 100644
--- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h
+++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
@@ -31,6 +31,7 @@
*/
#define MAX_NUM_STREAMS_MRST 3
+#define MAX_NUM_STREAMS_MFLD 6
#define MAX_NUM_STREAMS 6
#define MAX_DBG_RW_BYTES 80
#define MAX_NUM_SCATTER_BUFFERS 8
@@ -67,6 +68,8 @@
#define IPC_IA_CAPT_VOICE 0x17
#define IPC_IA_DECODE_FRAMES 0x18
+#define IPC_IA_ALG_PARAMS 0x1A
+
/* I2L Stream config/control msgs */
#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
@@ -141,73 +144,87 @@ enum sst_error_codes {
/* Error code,response to msgId: Description */
/* Common error codes */
SST_SUCCESS = 0, /* Success */
- SST_ERR_INVALID_STREAM_ID, /* Invalid stream ID */
- SST_ERR_INVALID_MSG_ID, /* Invalid message ID */
- SST_ERR_INVALID_STREAM_OP, /* Invalid stream operation request */
- SST_ERR_INVALID_PARAMS, /* Invalid params */
- SST_ERR_INVALID_CODEC, /* Invalid codec type */
- SST_ERR_INVALID_MEDIA_TYPE, /* Invalid media type */
- SST_ERR_STREAM_ERR, /* ANY: Stream control or config or
- processing error */
+ SST_ERR_INVALID_STREAM_ID = 1,
+ SST_ERR_INVALID_MSG_ID = 2,
+ SST_ERR_INVALID_STREAM_OP = 3,
+ SST_ERR_INVALID_PARAMS = 4,
+ SST_ERR_INVALID_CODEC = 5,
+ SST_ERR_INVALID_MEDIA_TYPE = 6,
+ SST_ERR_STREAM_ERR = 7,
/* IPC specific error codes */
- SST_IPC_ERR_CALL_BACK_NOT_REGD, /* Call back for msg not regd */
- SST_IPC_ERR_STREAM_NOT_ALLOCATED, /* Stream is not allocated */
- SST_IPC_ERR_STREAM_ALLOC_FAILED, /* ALLOC:Stream alloc failed */
- SST_IPC_ERR_GET_STREAM_FAILED, /* ALLOC:Get stream id failed*/
- SST_ERR_MOD_NOT_AVAIL, /* SET/GET: Mod(AEC/AGC/ALC) not available */
- SST_ERR_MOD_DNLD_RQD, /* SET/GET: Mod(AEC/AGC/ALC) download required */
- SST_ERR_STREAM_STOPPED, /* ANY: Stream is in stopped state */
- SST_ERR_STREAM_IN_USE, /* ANY: Stream is already in use */
+ SST_IPC_ERR_CALL_BACK_NOT_REGD = 8,
+ SST_IPC_ERR_STREAM_NOT_ALLOCATED = 9,
+ SST_IPC_ERR_STREAM_ALLOC_FAILED = 10,
+ SST_IPC_ERR_GET_STREAM_FAILED = 11,
+ SST_ERR_MOD_NOT_AVAIL = 12,
+ SST_ERR_MOD_DNLD_RQD = 13,
+ SST_ERR_STREAM_STOPPED = 14,
+ SST_ERR_STREAM_IN_USE = 15,
/* Capture specific error codes */
- SST_CAP_ERR_INCMPLTE_CAPTURE_MSG,/* ANY:Incomplete message */
- SST_CAP_ERR_CAPTURE_FAIL, /* ANY:Capture op failed */
- SST_CAP_ERR_GET_DDR_NEW_SGLIST,
- SST_CAP_ERR_UNDER_RUN, /* lack of input data */
- SST_CAP_ERR_OVERFLOW, /* lack of output space */
+ SST_CAP_ERR_INCMPLTE_CAPTURE_MSG = 16,
+ SST_CAP_ERR_CAPTURE_FAIL = 17,
+ SST_CAP_ERR_GET_DDR_NEW_SGLIST = 18,
+ SST_CAP_ERR_UNDER_RUN = 19,
+ SST_CAP_ERR_OVERFLOW = 20,
/* Playback specific error codes*/
- SST_PB_ERR_INCMPLTE_PLAY_MSG, /* ANY: Incomplete message */
- SST_PB_ERR_PLAY_FAIL, /* ANY: Playback operation failed */
- SST_PB_ERR_GET_DDR_NEW_SGLIST,
+ SST_PB_ERR_INCMPLTE_PLAY_MSG = 21,
+ SST_PB_ERR_PLAY_FAIL = 22,
+ SST_PB_ERR_GET_DDR_NEW_SGLIST = 23,
/* Codec manager specific error codes */
- SST_LIB_ERR_LIB_DNLD_REQUIRED, /* ALLOC: Codec download required */
- SST_LIB_ERR_LIB_NOT_SUPPORTED, /* Library is not supported */
+ SST_LIB_ERR_LIB_DNLD_REQUIRED = 24,
+ SST_LIB_ERR_LIB_NOT_SUPPORTED = 25,
/* Library manager specific error codes */
- SST_SCC_ERR_PREP_DNLD_FAILED, /* Failed to prepare for codec download */
- SST_SCC_ERR_LIB_DNLD_RES_FAILED, /* Lib download resume failed */
+ SST_SCC_ERR_PREP_DNLD_FAILED = 26,
+ SST_SCC_ERR_LIB_DNLD_RES_FAILED = 27,
/* Scheduler specific error codes */
- SST_SCH_ERR_FAIL, /* REPORT: */
+ SST_SCH_ERR_FAIL = 28,
/* DMA specific error codes */
- SST_DMA_ERR_NO_CHNL_AVAILABLE, /* DMA Ch not available */
- SST_DMA_ERR_INVALID_INPUT_PARAMS, /* Invalid input params */
- SST_DMA_ERR_CHNL_ALREADY_SUSPENDED, /* Ch is suspended */
- SST_DMA_ERR_CHNL_ALREADY_STARTED, /* Ch already started */
- SST_DMA_ERR_CHNL_NOT_ENABLED, /* Ch not enabled */
- SST_DMA_ERR_TRANSFER_FAILED, /* Transfer failed */
- SST_SSP_ERR_ALREADY_ENABLED, /* REPORT: SSP already enabled */
- SST_SSP_ERR_ALREADY_DISABLED, /* REPORT: SSP already disabled */
- SST_SSP_ERR_NOT_INITIALIZED,
+ SST_DMA_ERR_NO_CHNL_AVAILABLE = 29,
+ SST_DMA_ERR_INVALID_INPUT_PARAMS = 30,
+ SST_DMA_ERR_CHNL_ALREADY_SUSPENDED = 31,
+ SST_DMA_ERR_CHNL_ALREADY_STARTED = 32,
+ SST_DMA_ERR_CHNL_NOT_ENABLED = 33,
+ SST_DMA_ERR_TRANSFER_FAILED = 34,
+
+ SST_SSP_ERR_ALREADY_ENABLED = 35,
+ SST_SSP_ERR_ALREADY_DISABLED = 36,
+ SST_SSP_ERR_NOT_INITIALIZED = 37,
+ SST_SSP_ERR_SRAM_NO_DMA_DATA = 38,
/* Other error codes */
- SST_ERR_MOD_INIT_FAIL, /* Firmware Module init failed */
+ SST_ERR_MOD_INIT_FAIL = 39,
/* FW init error codes */
- SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED,
- SST_RDR_ERR_ROUTE_ALREADY_STARTED,
- SST_RDR_PREP_CODEC_DNLD_FAILED,
+ SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED = 40,
+ SST_RDR_ERR_ROUTE_ALREADY_STARTED = 41,
+ SST_RDR_ERR_IO_DEV_SEL_FAILED = 42,
+ SST_RDR_PREP_CODEC_DNLD_FAILED = 43,
/* Memory debug error codes */
- SST_ERR_DBG_MEM_READ_FAIL,
- SST_ERR_DBG_MEM_WRITE_FAIL,
-
- /* Decode error codes */
- SST_ERR_DEC_NEED_INPUT_BUF,
-
+ SST_ERR_DBG_MEM_READ_FAIL = 44,
+ SST_ERR_DBG_MEM_WRITE_FAIL = 45,
+ SST_ERR_INSUFFICIENT_INPUT_SG_LIST = 46,
+ SST_ERR_INSUFFICIENT_OUTPUT_SG_LIST = 47,
+
+ SST_ERR_BUFFER_NOT_AVAILABLE = 48,
+ SST_ERR_BUFFER_NOT_ALLOCATED = 49,
+ SST_ERR_INVALID_REGION_TYPE = 50,
+ SST_ERR_NULL_PTR = 51,
+ SST_ERR_INVALID_BUFFER_SIZE = 52,
+ SST_ERR_INVALID_BUFFER_INDEX = 53,
+
+ /*IIPC specific error codes */
+ SST_IIPC_QUEUE_FULL = 54,
+ SST_IIPC_ERR_MSG_SND_FAILED = 55,
+ SST_PB_ERR_UNDERRUN_OCCURED = 56,
+ SST_RDR_INSUFFICIENT_MIXER_BUFFER = 57,
+ SST_INVALID_TIME_SLOTS = 58,
};
enum dbg_mem_data_type {
diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h
index 03b931619a3e..bebc395a3c1f 100644
--- a/drivers/staging/intel_sst/intel_sst_ioctl.h
+++ b/drivers/staging/intel_sst/intel_sst_ioctl.h
@@ -190,21 +190,15 @@ struct snd_prp_params {
__u32 reserved; /* No pre-processing defined yet */
};
-struct snd_params_block {
- __u32 type; /*Type of the parameter*/
- __u32 size; /*size of the parameters in the block*/
- __u8 params[0]; /*Parameters of the algorithm*/
-};
-
/* Pre and post processing params structure */
struct snd_ppp_params {
- enum sst_algo_types algo_id;/* Post/Pre processing algorithm ID */
+ __u8 algo_id;/* Post/Pre processing algorithm ID */
__u8 str_id; /*Only 5 bits used 0 - 31 are valid*/
__u8 enable; /* 0= disable, 1= enable*/
__u8 reserved;
__u32 size; /*Size of parameters for all blocks*/
- struct snd_params_block params[0];
-};
+ void *params;
+} __attribute__ ((packed));
struct snd_sst_postproc_info {
__u32 src_min; /* Supported SRC Min sampling freq */
@@ -431,5 +425,8 @@ struct snd_sst_dbufs {
#define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *)
#define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \
struct snd_sst_target_device *)
+/*DSP Ioctls on /dev/intel_sst_ctrl only*/
+#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *)
+#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *)
#endif /* __INTEL_SST_IOCTL_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c
index 39c67fa0bd0c..0742dde2685d 100644
--- a/drivers/staging/intel_sst/intel_sst_ipc.c
+++ b/drivers/staging/intel_sst/intel_sst_ipc.c
@@ -26,6 +26,8 @@
* This file defines all ipc functions
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
@@ -75,16 +77,16 @@ void sst_post_message(struct work_struct *work)
/*To check if LPE is in stalled state.*/
retval = sst_stalled();
if (retval < 0) {
- pr_err("sst: in stalled state\n");
+ pr_err("in stalled state\n");
return;
}
- pr_debug("sst: post message called\n");
+ pr_debug("post message called\n");
spin_lock(&sst_drv_ctx->list_spin_lock);
/* check list */
if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
/* list is empty, mask imr */
- pr_debug("sst: Empty msg queue... masking\n");
+ pr_debug("Empty msg queue... masking\n");
imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
imr.part.done_interrupt = 1;
/* dummy register for shim workaround */
@@ -97,7 +99,7 @@ void sst_post_message(struct work_struct *work)
header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
if (header.part.busy) {
/* busy, unmask */
- pr_debug("sst: Busy not free... unmasking\n");
+ pr_debug("Busy not free... unmasking\n");
imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
imr.part.done_interrupt = 0;
/* dummy register for shim workaround */
@@ -109,8 +111,8 @@ void sst_post_message(struct work_struct *work)
msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
struct ipc_post, node);
list_del(&msg->node);
- pr_debug("sst: Post message: header = %x\n", msg->header.full);
- pr_debug("sst: size: = %x\n", msg->header.part.data);
+ pr_debug("Post message: header = %x\n", msg->header.full);
+ pr_debug("size: = %x\n", msg->header.part.data);
if (msg->header.part.large)
memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
msg->mailbox_data, msg->header.part.data);
@@ -166,13 +168,13 @@ int process_fw_init(struct sst_ipc_msg_wq *msg)
(struct ipc_header_fw_init *)msg->mailbox;
int retval = 0;
- pr_debug("sst: *** FW Init msg came***\n");
+ pr_debug("*** FW Init msg came***\n");
if (init->result) {
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_ERROR;
mutex_unlock(&sst_drv_ctx->sst_lock);
- pr_debug("sst: FW Init failed, Error %x\n", init->result);
- pr_err("sst: FW Init failed, Error %x\n", init->result);
+ pr_debug("FW Init failed, Error %x\n", init->result);
+ pr_err("FW Init failed, Error %x\n", init->result);
retval = -init->result;
return retval;
}
@@ -180,12 +182,13 @@ int process_fw_init(struct sst_ipc_msg_wq *msg)
sst_send_sound_card_type();
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_FW_RUNNING;
+ sst_drv_ctx->lpe_stalled = 0;
mutex_unlock(&sst_drv_ctx->sst_lock);
- pr_debug("sst: FW Version %x.%x\n",
+ pr_debug("FW Version %x.%x\n",
init->fw_version.major, init->fw_version.minor);
- pr_debug("sst: Build No %x Type %x\n",
+ pr_debug("Build No %x Type %x\n",
init->fw_version.build, init->fw_version.type);
- pr_debug("sst: Build date %s Time %s\n",
+ pr_debug(" Build date %s Time %s\n",
init->build_info.date, init->build_info.time);
sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
return retval;
@@ -204,19 +207,19 @@ void sst_process_message(struct work_struct *work)
container_of(work, struct sst_ipc_msg_wq, wq);
int str_id = msg->header.part.str_id;
- pr_debug("sst: IPC process for %x\n", msg->header.full);
+ pr_debug("IPC process for %x\n", msg->header.full);
/* based on msg in list call respective handler */
switch (msg->header.part.msg_id) {
case IPC_SST_BUF_UNDER_RUN:
case IPC_SST_BUF_OVER_RUN:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
- pr_err("sst: Buffer under/overrun for%d\n",
+ pr_err("Buffer under/overrun for %d\n",
msg->header.part.str_id);
- pr_err("sst: Got Underrun & not to send data...ignore\n");
+ pr_err("Got Underrun & not to send data...ignore\n");
break;
case IPC_SST_GET_PLAY_FRAMES:
@@ -224,35 +227,35 @@ void sst_process_message(struct work_struct *work)
struct stream_info *stream ;
if (sst_validate_strid(str_id)) {
- pr_err("sst: strid %d invalid\n", str_id);
+ pr_err("strid %d invalid\n", str_id);
break;
}
/* call sst_play_frame */
stream = &sst_drv_ctx->streams[str_id];
- pr_debug("sst: sst_play_frames for %d\n",
+ pr_debug("sst_play_frames for %d\n",
msg->header.part.str_id);
mutex_lock(&sst_drv_ctx->streams[str_id].lock);
sst_play_frame(msg->header.part.str_id);
mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
break;
} else
- pr_err("sst: sst_play_frames for Penwell!!\n");
+ pr_err("sst_play_frames for Penwell!!\n");
case IPC_SST_GET_CAPT_FRAMES:
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
struct stream_info *stream;
/* call sst_capture_frame */
if (sst_validate_strid(str_id)) {
- pr_err("sst: str id %d invalid\n", str_id);
+ pr_err("str id %d invalid\n", str_id);
break;
}
stream = &sst_drv_ctx->streams[str_id];
- pr_debug("sst: sst_capture_frames for %d\n",
+ pr_debug("sst_capture_frames for %d\n",
msg->header.part.str_id);
mutex_lock(&stream->lock);
if (stream->mmapped == false &&
stream->src == SST_DRV) {
- pr_debug("sst: waking up block for copy.\n");
+ pr_debug("waking up block for copy.\n");
stream->data_blk.ret_code = 0;
stream->data_blk.condition = true;
stream->data_blk.on = false;
@@ -261,11 +264,11 @@ void sst_process_message(struct work_struct *work)
sst_capture_frame(msg->header.part.str_id);
mutex_unlock(&stream->lock);
} else
- pr_err("sst: sst_play_frames for Penwell!!\n");
+ pr_err("sst_play_frames for Penwell!!\n");
break;
case IPC_IA_PRINT_STRING:
- pr_debug("sst: been asked to print something by fw\n");
+ pr_debug("been asked to print something by fw\n");
/* TBD */
break;
@@ -277,12 +280,12 @@ void sst_process_message(struct work_struct *work)
case IPC_SST_STREAM_PROCESS_FATAL_ERR:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
- pr_err("sst: codec fatal error %x stream %d...\n",
+ pr_err("codec fatal error %x stream %d...\n",
msg->header.full, msg->header.part.str_id);
- pr_err("sst: Dropping the stream\n");
+ pr_err("Dropping the stream\n");
sst_drop_stream(msg->header.part.str_id);
break;
case IPC_IA_LPE_GETTING_STALLED:
@@ -293,7 +296,7 @@ void sst_process_message(struct work_struct *work)
break;
default:
/* Illegal case */
- pr_err("sst: Unhandled msg %x header %x\n",
+ pr_err("Unhandled msg %x header %x\n",
msg->header.part.msg_id, msg->header.full);
}
sst_clear_interrupt();
@@ -322,7 +325,7 @@ void sst_process_reply(struct work_struct *work)
if (!msg->header.part.data) {
sst_drv_ctx->tgt_dev_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
sst_drv_ctx->tgt_dev_blk.ret_code =
-msg->header.part.data;
@@ -333,6 +336,55 @@ void sst_process_reply(struct work_struct *work)
wake_up(&sst_drv_ctx->wait_queue);
}
break;
+ case IPC_IA_ALG_PARAMS: {
+ pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full);
+ pr_debug("sst: data value %x\n", msg->header.part.data);
+ pr_debug("sst: large value %x\n", msg->header.part.large);
+
+ if (!msg->header.part.large) {
+ if (!msg->header.part.data) {
+ pr_debug("sst: alg set success\n");
+ sst_drv_ctx->ppp_params_blk.ret_code = 0;
+ } else {
+ pr_debug("sst: alg set failed\n");
+ sst_drv_ctx->ppp_params_blk.ret_code =
+ -msg->header.part.data;
+ }
+
+ } else if (msg->header.part.data) {
+ struct snd_ppp_params *mailbox_params, *get_params;
+ char *params;
+
+ pr_debug("sst: alg get success\n");
+ mailbox_params = (struct snd_ppp_params *)msg->mailbox;
+ get_params = kzalloc(sizeof(*get_params), GFP_KERNEL);
+ if (get_params == NULL) {
+ pr_err("sst: out of memory for ALG PARAMS");
+ break;
+ }
+ memcpy_fromio(get_params, mailbox_params,
+ sizeof(*get_params));
+ get_params->params = kzalloc(mailbox_params->size,
+ GFP_KERNEL);
+ if (get_params->params == NULL) {
+ kfree(get_params);
+ pr_err("sst: out of memory for ALG PARAMS block");
+ break;
+ }
+ params = msg->mailbox;
+ params = params + sizeof(*mailbox_params) - sizeof(u32);
+ memcpy_fromio(get_params->params, params,
+ get_params->size);
+ sst_drv_ctx->ppp_params_blk.ret_code = 0;
+ sst_drv_ctx->ppp_params_blk.data = get_params;
+ }
+
+ if (sst_drv_ctx->ppp_params_blk.on == true) {
+ sst_drv_ctx->ppp_params_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ }
case IPC_IA_GET_FW_INFO: {
struct snd_sst_fw_info *fw_info =
(struct snd_sst_fw_info *)msg->mailbox;
@@ -340,7 +392,7 @@ void sst_process_reply(struct work_struct *work)
int major = fw_info->fw_version.major;
int minor = fw_info->fw_version.minor;
int build = fw_info->fw_version.build;
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n",
major, minor, build);
@@ -349,13 +401,13 @@ void sst_process_reply(struct work_struct *work)
sizeof(struct snd_sst_fw_info));
sst_drv_ctx->fw_info_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
sst_drv_ctx->fw_info_blk.ret_code =
-msg->header.part.data;
}
if (sst_drv_ctx->fw_info_blk.on == true) {
- pr_debug("sst: Memcopy succedded\n");
+ pr_debug("Memcopy succeeded\n");
sst_drv_ctx->fw_info_blk.on = false;
sst_drv_ctx->fw_info_blk.condition = true;
wake_up(&sst_drv_ctx->wait_queue);
@@ -364,11 +416,11 @@ void sst_process_reply(struct work_struct *work)
}
case IPC_IA_SET_STREAM_MUTE:
if (!msg->header.part.data) {
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
sst_drv_ctx->mute_info_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
sst_drv_ctx->mute_info_blk.ret_code =
-msg->header.part.data;
@@ -382,11 +434,11 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_SET_STREAM_VOL:
if (!msg->header.part.data) {
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
sst_drv_ctx->vol_info_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id,
msg->header.part.data);
sst_drv_ctx->vol_info_blk.ret_code =
@@ -402,15 +454,15 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_GET_STREAM_VOL:
if (msg->header.part.large) {
- pr_debug("sst: Large Msg Received Successfully\n");
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Large Msg Received Successfully\n");
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
memcpy_fromio(sst_drv_ctx->vol_info_blk.data,
(void *) msg->mailbox,
sizeof(struct snd_sst_vol));
sst_drv_ctx->vol_info_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err("Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
sst_drv_ctx->vol_info_blk.ret_code =
-msg->header.part.data;
@@ -424,18 +476,18 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_GET_STREAM_PARAMS:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
str_info = &sst_drv_ctx->streams[str_id];
if (msg->header.part.large) {
- pr_debug("sst: Get stream large success\n");
+ pr_debug("Get stream large success\n");
memcpy_fromio(str_info->ctrl_blk.data,
((void *)(msg->mailbox)),
sizeof(struct snd_sst_fw_get_stream_params));
str_info->ctrl_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err("Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
str_info->ctrl_blk.ret_code = -msg->header.part.data;
}
@@ -447,19 +499,19 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_DECODE_FRAMES:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
str_info = &sst_drv_ctx->streams[str_id];
if (msg->header.part.large) {
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
memcpy_fromio(str_info->data_blk.data,
((void *)(msg->mailbox)),
sizeof(struct snd_sst_decode_info));
str_info->data_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err("Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
str_info->data_blk.ret_code = -msg->header.part.data;
}
@@ -471,17 +523,17 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_DRAIN_STREAM:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
str_info = &sst_drv_ctx->streams[str_id];
if (!msg->header.part.data) {
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
str_info->ctrl_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
str_info->ctrl_blk.ret_code = -msg->header.part.data;
@@ -496,7 +548,7 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_DROP_STREAM:
if (sst_validate_strid(str_id)) {
- pr_err("sst: str id %d invalid\n", str_id);
+ pr_err("str id %d invalid\n", str_id);
break;
}
str_info = &sst_drv_ctx->streams[str_id];
@@ -504,12 +556,12 @@ void sst_process_reply(struct work_struct *work)
struct snd_sst_drop_response *drop_resp =
(struct snd_sst_drop_response *)msg->mailbox;
- pr_debug("sst: Drop ret bytes %x\n", drop_resp->bytes);
+ pr_debug("Drop ret bytes %x\n", drop_resp->bytes);
str_info->curr_bytes = drop_resp->bytes;
str_info->ctrl_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id, msg->header.part.data);
str_info->ctrl_blk.ret_code = -msg->header.part.data;
}
@@ -521,10 +573,10 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_ENABLE_RX_TIME_SLOT:
if (!msg->header.part.data) {
- pr_debug("sst: RX_TIME_SLOT success\n");
+ pr_debug("RX_TIME_SLOT success\n");
sst_drv_ctx->hs_info_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id,
msg->header.part.data);
sst_drv_ctx->hs_info_blk.ret_code =
@@ -541,17 +593,17 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_SET_STREAM_PARAMS:
str_info = &sst_drv_ctx->streams[str_id];
if (!msg->header.part.data) {
- pr_debug("sst: Msg succedded %x\n",
+ pr_debug("Msg succeeded %x\n",
msg->header.part.msg_id);
str_info->ctrl_blk.ret_code = 0;
} else {
- pr_err("sst: Msg %x reply error %x\n",
+ pr_err(" Msg %x reply error %x\n",
msg->header.part.msg_id,
msg->header.part.data);
str_info->ctrl_blk.ret_code = -msg->header.part.data;
}
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n", str_id);
+ pr_err(" stream id %d invalid\n", str_id);
break;
}
@@ -564,9 +616,9 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_FREE_STREAM:
if (!msg->header.part.data) {
- pr_debug("sst: Stream %d freed\n", str_id);
+ pr_debug("Stream %d freed\n", str_id);
} else {
- pr_err("sst: Free for %d ret error %x\n",
+ pr_err("Free for %d ret error %x\n",
str_id, msg->header.part.data);
}
break;
@@ -575,7 +627,7 @@ void sst_process_reply(struct work_struct *work)
struct snd_sst_alloc_response *resp =
(struct snd_sst_alloc_response *)msg->mailbox;
if (resp->str_type.result)
- pr_err("sst: error alloc stream = %x\n",
+ pr_err("error alloc stream = %x\n",
resp->str_type.result);
sst_alloc_stream_response(str_id, resp);
break;
@@ -584,21 +636,21 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_PLAY_FRAMES:
case IPC_IA_CAPT_FRAMES:
if (sst_validate_strid(str_id)) {
- pr_err("sst: stream id %d invalid\n" , str_id);
+ pr_err("stream id %d invalid\n", str_id);
break;
}
- pr_debug("sst: Ack for play/capt frames recived\n");
+ pr_debug("Ack for play/capt frames received\n");
break;
case IPC_IA_PREP_LIB_DNLD: {
struct snd_sst_str_type *str_type =
(struct snd_sst_str_type *)msg->mailbox;
- pr_debug("sst: Prep Lib download %x\n",
+ pr_debug("Prep Lib download %x\n",
msg->header.part.msg_id);
if (str_type->result)
- pr_err("sst: Prep lib download %x\n", str_type->result);
+ pr_err("Prep lib download %x\n", str_type->result);
else
- pr_debug("sst: Can download codec now...\n");
+ pr_debug("Can download codec now...\n");
sst_wake_up_alloc_block(sst_drv_ctx, str_id,
str_type->result, NULL);
break;
@@ -609,12 +661,12 @@ void sst_process_reply(struct work_struct *work)
(struct snd_sst_lib_download_info *)msg->mailbox;
int retval = resp->result;
- pr_debug("sst: Lib downloaded %x\n", msg->header.part.msg_id);
+ pr_debug("Lib downloaded %x\n", msg->header.part.msg_id);
if (resp->result) {
- pr_err("sst: err in lib dload %x\n", resp->result);
+ pr_err("err in lib dload %x\n", resp->result);
} else {
- pr_debug("sst: Codec download complete...\n");
- pr_debug("sst: codec Type %d Ver %d Built %s: %s\n",
+ pr_debug("Codec download complete...\n");
+ pr_debug("codec Type %d Ver %d Built %s: %s\n",
resp->dload_lib.lib_info.lib_type,
resp->dload_lib.lib_info.lib_version,
resp->dload_lib.lib_info.b_date,
@@ -639,17 +691,17 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_GET_FW_BUILD_INF: {
struct sst_fw_build_info *build =
(struct sst_fw_build_info *)msg->mailbox;
- pr_debug("sst: Build date:%sTime:%s", build->date, build->time);
+ pr_debug("Build date:%sTime:%s", build->date, build->time);
break;
}
case IPC_IA_SET_PMIC_TYPE:
break;
case IPC_IA_START_STREAM:
- pr_debug("sst: reply for START STREAM %x\n", msg->header.full);
+ pr_debug("reply for START STREAM %x\n", msg->header.full);
break;
default:
/* Illegal case */
- pr_err("sst: process reply:default = %x\n", msg->header.full);
+ pr_err("process reply:default = %x\n", msg->header.full);
}
sst_clear_interrupt();
return;
diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/drivers/staging/intel_sst/intel_sst_pvt.c
index 6487e192bf93..01f8c3b1cf74 100644
--- a/drivers/staging/intel_sst/intel_sst_pvt.c
+++ b/drivers/staging/intel_sst/intel_sst_pvt.c
@@ -29,6 +29,8 @@
* This file contains all private functions
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/firmware.h>
@@ -60,7 +62,7 @@ int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
}
}
if (i == MAX_ACTIVE_STREAM) {
- pr_err("sst: max alloc_stream reached");
+ pr_err("max alloc_stream reached\n");
i = -EBUSY; /* active stream limit reached */
}
return i;
@@ -84,14 +86,14 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
block->condition)) {
/* event wake */
if (block->ret_code < 0) {
- pr_err("sst: stream failed %d\n", block->ret_code);
+ pr_err("stream failed %d\n", block->ret_code);
retval = -EBUSY;
} else {
- pr_debug("sst: event up\n");
+ pr_debug("event up\n");
retval = 0;
}
} else {
- pr_err("sst: signal interrupted\n");
+ pr_err("signal interrupted\n");
retval = -EINTR;
}
return retval;
@@ -115,18 +117,18 @@ int sst_wait_interruptible_timeout(
{
int retval = 0;
- pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n");
+ pr_debug("sst_wait_interruptible_timeout - waiting....\n");
if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
block->condition,
msecs_to_jiffies(timeout))) {
if (block->ret_code < 0)
- pr_err("sst: stream failed %d\n", block->ret_code);
+ pr_err("stream failed %d\n", block->ret_code);
else
- pr_debug("sst: event up\n");
+ pr_debug("event up\n");
retval = block->ret_code;
} else {
block->on = false;
- pr_err("sst: timeout occured...\n");
+ pr_err("timeout occurred...\n");
/*setting firmware state as uninit so that the
firmware will get re-downloaded on next request
this is because firmare not responding for 5 sec
@@ -156,18 +158,18 @@ int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
/* NOTE:
Observed that FW processes the alloc msg and replies even
before the alloc thread has finished execution */
- pr_debug("sst: waiting for %x, condition %x\n",
+ pr_debug("waiting for %x, condition %x\n",
block->sst_id, block->ops_block.condition);
if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
block->ops_block.condition,
msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
/* event wake */
- pr_debug("sst: Event wake %x\n", block->ops_block.condition);
- pr_debug("sst: message ret: %d\n", block->ops_block.ret_code);
+ pr_debug("Event wake %x\n", block->ops_block.condition);
+ pr_debug("message ret: %d\n", block->ops_block.ret_code);
retval = block->ops_block.ret_code;
} else {
block->ops_block.on = false;
- pr_err("sst: Wait timed-out %x\n", block->ops_block.condition);
+ pr_err("Wait timed-out %x\n", block->ops_block.condition);
/* settign firmware state as uninit so that the
firmware will get redownloaded on next request
this is because firmare not responding for 5 sec
@@ -192,14 +194,14 @@ int sst_create_large_msg(struct ipc_post **arg)
msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
if (!msg) {
- pr_err("sst: kzalloc msg failed\n");
+ pr_err("kzalloc msg failed\n");
return -ENOMEM;
}
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
if (!msg->mailbox_data) {
kfree(msg);
- pr_err("sst: kzalloc mailbox_data failed");
+ pr_err("kzalloc mailbox_data failed");
return -ENOMEM;
};
*arg = msg;
@@ -219,7 +221,7 @@ int sst_create_short_msg(struct ipc_post **arg)
msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
if (!msg) {
- pr_err("sst: kzalloc msg failed\n");
+ pr_err("kzalloc msg failed\n");
return -ENOMEM;
}
msg->mailbox_data = NULL;
@@ -290,10 +292,10 @@ int sst_enable_rx_timeslot(int status)
struct ipc_post *msg = NULL;
if (sst_create_short_msg(&msg)) {
- pr_err("sst: mem allocation failed\n");
+ pr_err("mem allocation failed\n");
return -ENOMEM;
}
- pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n");
+ pr_debug("ipc message sending: ENABLE_RX_TIME_SLOT\n");
sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
msg->header.part.data = status;
sst_drv_ctx->hs_info_blk.condition = false;
diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c
index b2c4b7067da0..795e42ab7360 100644
--- a/drivers/staging/intel_sst/intel_sst_stream.c
+++ b/drivers/staging/intel_sst/intel_sst_stream.c
@@ -26,6 +26,8 @@
* This file contains the stream operations of SST driver
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
@@ -45,8 +47,8 @@
*/
int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
{
- if (device >= MAX_NUM_STREAMS) {
- pr_debug("sst: device type invalid %d\n", device);
+ if (device > MAX_NUM_STREAMS_MFLD) {
+ pr_debug("device type invalid %d\n", device);
return -EINVAL;
}
if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) {
@@ -71,15 +73,15 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
*pcm_slot = 0x0F;
else {
- pr_debug("sst: No condition satisfied.. ret err\n");
+ pr_debug("No condition satisfied.. ret err\n");
return -EINVAL;
}
} else {
- pr_debug("sst: this stream state is not uni-init, is %d\n",
+ pr_debug("this stream state is not uni-init, is %d\n",
sst_drv_ctx->streams[device].status);
return -EBADRQC;
}
- pr_debug("sst: returning slot %x\n", *pcm_slot);
+ pr_debug("returning slot %x\n", *pcm_slot);
return 0;
}
/**
@@ -96,7 +98,7 @@ static unsigned int get_mrst_stream_id(void)
if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT)
return i;
}
- pr_debug("sst: Didnt find empty stream for mrst\n");
+ pr_debug("Didnt find empty stream for mrst\n");
return -EBUSY;
}
@@ -305,7 +307,7 @@ int sst_pause_stream(int str_id)
if (str_info->prev == STREAM_UN_INIT)
return -EBADRQC;
if (str_info->ctrl_blk.on == true) {
- pr_err("SST ERR: control path is in use\n ");
+ pr_err("SST ERR: control path is in use\n");
return -EINVAL;
}
if (sst_create_short_msg(&msg))
@@ -333,7 +335,7 @@ int sst_pause_stream(int str_id)
}
} else {
retval = -EBADRQC;
- pr_err("SST ERR:BADQRC for stream\n ");
+ pr_err("SST ERR: BADQRC for stream\n");
}
return retval;
@@ -468,7 +470,7 @@ int sst_drop_stream(int str_id)
}
} else {
retval = -EBADRQC;
- pr_err("SST ERR:BADQRC for stream\n");
+ pr_err("SST ERR: BADQRC for stream\n");
}
return retval;
}
diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
index fbae39fda5c0..85789ba65186 100644
--- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c
+++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
@@ -26,13 +26,15 @@
* This file contains the stream operations of SST driver
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/syscalls.h>
#include <linux/firmware.h>
#include <linux/sched.h>
-#include <linux/rar_register.h>
#ifdef CONFIG_MRST_RAR_HANDLER
-#include "../../../drivers/staging/memrar/memrar.h"
+#include <linux/rar_register.h>
+#include "../memrar/memrar.h"
#endif
#include "intel_sst_ioctl.h"
#include "intel_sst.h"
@@ -53,7 +55,7 @@ int sst_get_stream_params(int str_id,
struct stream_info *str_info;
struct snd_sst_fw_get_stream_params *fw_params;
- pr_debug("sst: get_stream for %d\n", str_id);
+ pr_debug("get_stream for %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return retval;
@@ -61,16 +63,16 @@ int sst_get_stream_params(int str_id,
str_info = &sst_drv_ctx->streams[str_id];
if (str_info->status != STREAM_UN_INIT) {
if (str_info->ctrl_blk.on == true) {
- pr_err("sst: control path in use\n");
+ pr_err("control path in use\n");
return -EINVAL;
}
if (sst_create_short_msg(&msg)) {
- pr_err("sst: message creation failed\n");
+ pr_err("message creation failed\n");
return -ENOMEM;
}
fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC);
if (!fw_params) {
- pr_err("sst: mem allcoation failed\n ");
+ pr_err("mem allocation failed\n");
kfree(msg);
return -ENOMEM;
}
@@ -104,7 +106,7 @@ int sst_get_stream_params(int str_id,
get_params->codec_params.stream_type = str_info->str_type;
kfree(fw_params);
} else {
- pr_debug("sst: Stream is not in the init state\n");
+ pr_debug("Stream is not in the init state\n");
}
return retval;
}
@@ -125,17 +127,17 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
BUG_ON(!str_param);
if (sst_drv_ctx->streams[str_id].ops != str_param->ops) {
- pr_err("sst: Invalid operation\n");
+ pr_err("Invalid operation\n");
return -EINVAL;
}
retval = sst_validate_strid(str_id);
if (retval)
return retval;
- pr_debug("sst: set_stream for %d\n", str_id);
+ pr_debug("set_stream for %d\n", str_id);
str_info = &sst_drv_ctx->streams[str_id];
if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) {
if (str_info->ctrl_blk.on == true) {
- pr_err("sst: control path in use\n");
+ pr_err("control path in use\n");
return -EAGAIN;
}
if (sst_create_large_msg(&msg))
@@ -163,7 +165,7 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
}
} else {
retval = -EBADRQC;
- pr_err("sst: BADQRC for stream\n");
+ pr_err("BADQRC for stream\n");
}
return retval;
}
@@ -183,7 +185,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
struct snd_sst_vol *fw_get_vol;
int str_id = get_vol->stream_id;
- pr_debug("sst: get vol called\n");
+ pr_debug("get vol called\n");
if (sst_create_short_msg(&msg))
return -ENOMEM;
@@ -195,7 +197,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
sst_drv_ctx->vol_info_blk.on = true;
fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC);
if (!fw_get_vol) {
- pr_err("sst: mem allocation failed\n");
+ pr_err("mem allocation failed\n");
kfree(msg);
return -ENOMEM;
}
@@ -209,10 +211,10 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
if (retval)
retval = -EIO;
else {
- pr_debug("sst: stream id %d\n", fw_get_vol->stream_id);
- pr_debug("sst: volume %d\n", fw_get_vol->volume);
- pr_debug("sst: ramp duration %d\n", fw_get_vol->ramp_duration);
- pr_debug("sst: ramp_type %d\n", fw_get_vol->ramp_type);
+ pr_debug("stream id %d\n", fw_get_vol->stream_id);
+ pr_debug("volume %d\n", fw_get_vol->volume);
+ pr_debug("ramp duration %d\n", fw_get_vol->ramp_duration);
+ pr_debug("ramp_type %d\n", fw_get_vol->ramp_type);
memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol));
}
return retval;
@@ -231,10 +233,10 @@ int sst_set_vol(struct snd_sst_vol *set_vol)
int retval = 0;
struct ipc_post *msg = NULL;
- pr_debug("sst: set vol called\n");
+ pr_debug("set vol called\n");
if (sst_create_large_msg(&msg)) {
- pr_err("sst: message creation failed\n");
+ pr_err("message creation failed\n");
return -ENOMEM;
}
sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1,
@@ -254,7 +256,7 @@ int sst_set_vol(struct snd_sst_vol *set_vol)
retval = sst_wait_interruptible_timeout(sst_drv_ctx,
&sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT);
if (retval) {
- pr_err("sst: error in set_vol = %d\n", retval);
+ pr_err("error in set_vol = %d\n", retval);
retval = -EIO;
}
return retval;
@@ -273,10 +275,10 @@ int sst_set_mute(struct snd_sst_mute *set_mute)
int retval = 0;
struct ipc_post *msg = NULL;
- pr_debug("sst: set mute called\n");
+ pr_debug("set mute called\n");
if (sst_create_large_msg(&msg)) {
- pr_err("sst: message creation failed\n");
+ pr_err("message creation failed\n");
return -ENOMEM;
}
sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1,
@@ -297,7 +299,7 @@ int sst_set_mute(struct snd_sst_mute *set_mute)
retval = sst_wait_interruptible_timeout(sst_drv_ctx,
&sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT);
if (retval) {
- pr_err("sst: error in set_mute = %d\n", retval);
+ pr_err("error in set_mute = %d\n", retval);
retval = -EIO;
}
return retval;
@@ -358,20 +360,20 @@ int sst_parse_target(struct snd_sst_slot_info *slot)
slot->device_type == SND_SST_DEVICE_PCM) {
retval = sst_activate_target(slot);
if (retval)
- pr_err("sst: SST_Activate_target_fail\n");
+ pr_err("SST_Activate_target_fail\n");
else
- pr_err("sst: SST_Activate_target_pass\n");
+ pr_err("SST_Activate_target_pass\n");
return retval;
} else if (slot->action == SND_SST_PORT_PREPARE &&
slot->device_type == SND_SST_DEVICE_PCM) {
retval = sst_prepare_target(slot);
if (retval)
- pr_err("sst: SST_prepare_target_fail\n");
+ pr_err("SST_prepare_target_fail\n");
else
- pr_err("sst: SST_prepare_target_pass\n");
+ pr_err("SST_prepare_target_pass\n");
return retval;
} else {
- pr_err("sst: slot_action : %d, device_type: %d\n",
+ pr_err("slot_action : %d, device_type: %d\n",
slot->action, slot->device_type);
return retval;
}
@@ -383,7 +385,7 @@ int sst_send_target(struct snd_sst_target_device *target)
struct ipc_post *msg;
if (sst_create_large_msg(&msg)) {
- pr_err("sst: message creation failed\n");
+ pr_err("message creation failed\n");
return -ENOMEM;
}
sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0);
@@ -399,11 +401,11 @@ int sst_send_target(struct snd_sst_target_device *target)
list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
spin_unlock(&sst_drv_ctx->list_spin_lock);
sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
- pr_debug("sst: message sent- waiting\n");
+ pr_debug("message sent- waiting\n");
retval = sst_wait_interruptible_timeout(sst_drv_ctx,
&sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT);
if (retval)
- pr_err("sst: target device ipc failed = 0x%x\n", retval);
+ pr_err("target device ipc failed = 0x%x\n", retval);
return retval;
}
@@ -439,7 +441,7 @@ int sst_target_device_validate(struct snd_sst_target_device *target)
goto err;
} else {
err:
- pr_err("sst: i/p params incorrect\n");
+ pr_err("i/p params incorrect\n");
return -EINVAL;
}
}
@@ -460,15 +462,15 @@ int sst_target_device_select(struct snd_sst_target_device *target)
{
int retval, i, prepare_count = 0;
- pr_debug("sst: Target Device Select\n");
+ pr_debug("Target Device Select\n");
if (target->device_route < 0 || target->device_route > 2) {
- pr_err("sst: device route is invalid\n");
+ pr_err("device route is invalid\n");
return -EINVAL;
}
if (target->device_route != 0) {
- pr_err("sst: Unsupported config\n");
+ pr_err("Unsupported config\n");
return -EIO;
}
retval = sst_target_device_validate(target);
@@ -480,18 +482,18 @@ int sst_target_device_select(struct snd_sst_target_device *target)
return retval;
for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) {
if (target->devices[i].action == SND_SST_PORT_ACTIVATE) {
- pr_debug("sst: activate called in %d\n", i);
+ pr_debug("activate called in %d\n", i);
retval = sst_parse_target(&target->devices[i]);
if (retval)
return retval;
} else if (target->devices[i].action == SND_SST_PORT_PREPARE) {
- pr_debug("sst: PREPARE in %d, Forwading\n", i);
+ pr_debug("PREPARE in %d, Forwarding\n", i);
retval = sst_parse_target(&target->devices[i]);
if (retval) {
- pr_err("sst: Parse Target fail %d", retval);
+ pr_err("Parse Target fail %d\n", retval);
return retval;
}
- pr_debug("sst: Parse Target successful %d", retval);
+ pr_debug("Parse Target successful %d\n", retval);
if (target->devices[i].device_type ==
SND_SST_DEVICE_PCM)
prepare_count++;
@@ -512,11 +514,11 @@ static inline int sst_get_RAR(struct RAR_buffer *buffers, int count)
rar_status = rar_handle_to_bus(buffers, count);
if (count != rar_status) {
- pr_err("sst: The rar CALL Failed");
+ pr_err("The rar CALL Failed");
retval = -EIO;
}
if (buffers->info.type != RAR_TYPE_AUDIO) {
- pr_err("sst: Invalid RAR type\n");
+ pr_err("Invalid RAR type\n");
return -EINVAL;
}
return retval;
@@ -539,10 +541,10 @@ static int sst_create_sg_list(struct stream_info *stream,
if (kbufs->in_use == false) {
#ifdef CONFIG_MRST_RAR_HANDLER
if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
- pr_debug("sst: DRM playback handling\n");
+ pr_debug("DRM playback handling\n");
rar_buffers.info.handle = (__u32)kbufs->addr;
rar_buffers.info.size = kbufs->size;
- pr_debug("sst: rar handle 0x%x size=0x%x",
+ pr_debug("rar handle 0x%x size=0x%x\n",
rar_buffers.info.handle,
rar_buffers.info.size);
retval = sst_get_RAR(&rar_buffers, 1);
@@ -552,7 +554,7 @@ static int sst_create_sg_list(struct stream_info *stream,
sg_list->addr[i].addr = rar_buffers.bus_address;
/* rar_buffers.info.size; */
sg_list->addr[i].size = (__u32)kbufs->size;
- pr_debug("sst: phyaddr[%d] 0x%x Size:0x%x\n"
+ pr_debug("phyaddr[%d] 0x%x Size:0x%x\n"
, i, sg_list->addr[i].addr,
sg_list->addr[i].size);
}
@@ -562,7 +564,7 @@ static int sst_create_sg_list(struct stream_info *stream,
virt_to_phys((void *)
kbufs->addr + kbufs->offset);
sg_list->addr[i].size = kbufs->size;
- pr_debug("sst: phyaddr[%d]:0x%x Size:0x%x\n"
+ pr_debug("phyaddr[%d]:0x%x Size:0x%x\n"
, i , sg_list->addr[i].addr, kbufs->size);
}
stream->curr_bytes += sg_list->addr[i].size;
@@ -574,7 +576,7 @@ static int sst_create_sg_list(struct stream_info *stream,
}
sg_list->num_entries = i;
- pr_debug("sst:sg list entries = %d\n", sg_list->num_entries);
+ pr_debug("sg list entries = %d\n", sg_list->num_entries);
return i;
}
@@ -595,7 +597,7 @@ int sst_play_frame(int str_id)
struct sst_stream_bufs *kbufs = NULL, *_kbufs;
struct stream_info *stream;
- pr_debug("sst: play frame for %d\n", str_id);
+ pr_debug("play frame for %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return retval;
@@ -615,14 +617,14 @@ int sst_play_frame(int str_id)
stream->curr_bytes = 0;
if (list_empty(&stream->bufs)) {
/* no user buffer available */
- pr_debug("sst: Null buffer stream status %d\n", stream->status);
+ pr_debug("Null buffer stream status %d\n", stream->status);
stream->prev = stream->status;
stream->status = STREAM_INIT;
- pr_debug("sst:new stream status = %d\n", stream->status);
+ pr_debug("new stream status = %d\n", stream->status);
if (stream->need_draining == true) {
- pr_debug("sst:draining stream\n");
+ pr_debug("draining stream\n");
if (sst_create_short_msg(&msg)) {
- pr_err("sst: mem alloc failed\n");
+ pr_err("mem allocation failed\n");
return -ENOMEM;
}
sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM,
@@ -633,7 +635,7 @@ int sst_play_frame(int str_id)
spin_unlock(&sst_drv_ctx->list_spin_lock);
sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
} else if (stream->data_blk.on == true) {
- pr_debug("sst:user list empty.. wake\n");
+ pr_debug("user list empty.. wake\n");
/* unblock */
stream->data_blk.ret_code = 0;
stream->data_blk.condition = true;
@@ -678,7 +680,7 @@ int sst_capture_frame(int str_id)
struct stream_info *stream;
- pr_debug("sst:capture frame for %d\n", str_id);
+ pr_debug("capture frame for %d\n", str_id);
retval = sst_validate_strid(str_id);
if (retval)
return retval;
@@ -688,19 +690,19 @@ int sst_capture_frame(int str_id)
if (kbufs->in_use == true) {
list_del(&kbufs->node);
kfree(kbufs);
- pr_debug("sst:del node\n");
+ pr_debug("del node\n");
}
}
if (list_empty(&stream->bufs)) {
/* no user buffer available */
- pr_debug("sst:Null buffer!!!!stream status %d\n",
+ pr_debug("Null buffer!!!!stream status %d\n",
stream->status);
stream->prev = stream->status;
stream->status = STREAM_INIT;
- pr_debug("sst:new stream status = %d\n",
+ pr_debug("new stream status = %d\n",
stream->status);
if (stream->data_blk.on == true) {
- pr_debug("sst:user list empty.. wake\n");
+ pr_debug("user list empty.. wake\n");
/* unblock */
stream->data_blk.ret_code = 0;
stream->data_blk.condition = true;
@@ -731,7 +733,7 @@ int sst_capture_frame(int str_id)
stream->cumm_bytes += stream->curr_bytes;
stream->curr_bytes = 0;
- pr_debug("sst:Cum bytes = %d\n", stream->cumm_bytes);
+ pr_debug("Cum bytes = %d\n", stream->cumm_bytes);
return 0;
}
@@ -743,7 +745,7 @@ static unsigned int calculate_min_size(struct snd_sst_buffs *bufs)
if (bufs->buff_entry[i].size < min_val)
min_val = bufs->buff_entry[i].size;
}
- pr_debug("sst:min_val = %d\n", min_val);
+ pr_debug("min_val = %d\n", min_val);
return min_val;
}
@@ -754,7 +756,7 @@ static unsigned int calculate_max_size(struct snd_sst_buffs *bufs)
if (bufs->buff_entry[i].size > max_val)
max_val = bufs->buff_entry[i].size;
}
- pr_debug("sst:max_val = %d\n", max_val);
+ pr_debug("max_val = %d\n", max_val);
return max_val;
}
@@ -773,7 +775,7 @@ static int sst_allocate_decode_buf(struct stream_info *str_info,
if (dbufs->ibufs->entries == dbufs->obufs->entries)
return 0;
else {
- pr_err("sst: RAR entries dont match\n");
+ pr_err("RAR entries dont match\n");
return -EINVAL;
}
} else
@@ -783,26 +785,26 @@ static int sst_allocate_decode_buf(struct stream_info *str_info,
}
#endif
if (!str_info->decode_ibuf) {
- pr_debug("sst:no i/p buffers, trying full size\n");
+ pr_debug("no i/p buffers, trying full size\n");
str_info->decode_isize = cum_input_given;
str_info->decode_ibuf = kzalloc(str_info->decode_isize,
GFP_KERNEL);
str_info->idecode_alloc = str_info->decode_isize;
}
if (!str_info->decode_ibuf) {
- pr_debug("sst:buff alloc failed, try max size\n");
+ pr_debug("buff alloc failed, try max size\n");
str_info->decode_isize = calculate_max_size(dbufs->ibufs);
str_info->decode_ibuf = kzalloc(
str_info->decode_isize, GFP_KERNEL);
str_info->idecode_alloc = str_info->decode_isize;
}
if (!str_info->decode_ibuf) {
- pr_debug("sst:buff alloc failed, try min size\n");
+ pr_debug("buff alloc failed, try min size\n");
str_info->decode_isize = calculate_min_size(dbufs->ibufs);
str_info->decode_ibuf = kzalloc(str_info->decode_isize,
GFP_KERNEL);
if (!str_info->decode_ibuf) {
- pr_err("sst: mem allocation failed\n");
+ pr_err("mem allocation failed\n");
return -ENOMEM;
}
str_info->idecode_alloc = str_info->decode_isize;
@@ -820,7 +822,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
struct ipc_post *msg = NULL;
int retval = 0;
- pr_debug("SST DBGsst_set_mute:called\n");
+ pr_debug("SST DBG:sst_set_mute:called\n");
if (str_info->decode_ibuf_type == SST_BUF_RAR) {
#ifdef CONFIG_MRST_RAR_HANDLER
@@ -857,7 +859,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
dec_info->input_bytes_consumed = 0;
dec_info->output_bytes_produced = 0;
if (sst_create_large_msg(&msg)) {
- pr_err("sst: message creation failed\n");
+ pr_err("message creation failed\n");
return -ENOMEM;
}
@@ -878,13 +880,13 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
return retval;
}
+#ifdef CONFIG_MRST_RAR_HANDLER
static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
struct snd_sst_dbufs *dbufs,
int *input_index, int *in_copied,
int *input_index_valid_size, int *new_entry_flag)
{
int retval = 0;
-#ifdef CONFIG_MRST_RAR_HANDLER
int i;
if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
@@ -894,7 +896,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
dbufs->ibufs->buff_entry[i].buffer,
sizeof(__u32));
if (retval) {
- pr_err("sst:cpy from user fail\n");
+ pr_err("cpy from user fail\n");
return -EAGAIN;
}
rar_buffers.info.type = dbufs->ibufs->type;
@@ -919,9 +921,10 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
str_info->decode_ibuf_type = dbufs->ibufs->type;
*in_copied = str_info->decode_isize;
}
-#endif
return retval;
}
+#endif
+
/*This function is used to prepare the kernel input buffers with contents
before sending for decode*/
static int sst_prepare_input_buffers(struct stream_info *str_info,
@@ -931,7 +934,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
{
int i, cpy_size, retval = 0;
- pr_debug("sst:input_index = %d, input entries = %d\n",
+ pr_debug("input_index = %d, input entries = %d\n",
*input_index, dbufs->ibufs->entries);
for (i = *input_index; i < dbufs->ibufs->entries; i++) {
#ifdef CONFIG_MRST_RAR_HANDLER
@@ -939,7 +942,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
dbufs, input_index, in_copied,
input_index_valid_size, new_entry_flag);
if (retval) {
- pr_err("sst: In prepare input buffers for RAR\n");
+ pr_err("In prepare input buffers for RAR\n");
return -EIO;
}
#endif
@@ -947,10 +950,10 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
if (*input_index_valid_size == 0)
*input_index_valid_size =
dbufs->ibufs->buff_entry[i].size;
- pr_debug("sst:inout addr = %p, size = %d\n",
+ pr_debug("inout addr = %p, size = %d\n",
dbufs->ibufs->buff_entry[i].buffer,
*input_index_valid_size);
- pr_debug("sst:decode_isize = %d, in_copied %d\n",
+ pr_debug("decode_isize = %d, in_copied %d\n",
str_info->decode_isize, *in_copied);
if (*input_index_valid_size <=
(str_info->decode_isize - *in_copied))
@@ -958,12 +961,12 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
else
cpy_size = str_info->decode_isize - *in_copied;
- pr_debug("sst:cpy size = %d\n", cpy_size);
+ pr_debug("cpy size = %d\n", cpy_size);
if (!dbufs->ibufs->buff_entry[i].buffer) {
- pr_err("sst: i/p buffer is null\n");
+ pr_err("i/p buffer is null\n");
return -EINVAL;
}
- pr_debug("sst:Try copy To %p, From %p, size %d\n",
+ pr_debug("Try copy To %p, From %p, size %d\n",
str_info->decode_ibuf + *in_copied,
dbufs->ibufs->buff_entry[i].buffer, cpy_size);
@@ -972,22 +975,22 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
(void *) dbufs->ibufs->buff_entry[i].buffer,
cpy_size);
if (retval) {
- pr_err("sst: copy from user failed\n");
+ pr_err("copy from user failed\n");
return -EIO;
}
*in_copied += cpy_size;
*input_index_valid_size -= cpy_size;
- pr_debug("sst:in buff size = %d, in_copied = %d\n",
+ pr_debug("in buff size = %d, in_copied = %d\n",
*input_index_valid_size, *in_copied);
if (*input_index_valid_size != 0) {
- pr_debug("sst:more input buffers left\n");
+ pr_debug("more input buffers left\n");
dbufs->ibufs->buff_entry[i].buffer += cpy_size;
break;
}
if (*in_copied == str_info->decode_isize &&
*input_index_valid_size == 0 &&
(i+1) <= dbufs->ibufs->entries) {
- pr_debug("sst:all input buffers copied\n");
+ pr_debug("all input buffers copied\n");
*new_entry_flag = true;
*input_index = i + 1;
break;
@@ -1005,23 +1008,23 @@ static int sst_prepare_output_buffers(struct stream_info *str_info,
{
int i, cpy_size, retval = 0;
- pr_debug("sst:output_index = %d, output entries = %d\n",
+ pr_debug("output_index = %d, output entries = %d\n",
*output_index,
dbufs->obufs->entries);
for (i = *output_index; i < dbufs->obufs->entries; i++) {
*output_index = i;
- pr_debug("sst:output addr = %p, size = %d\n",
+ pr_debug("output addr = %p, size = %d\n",
dbufs->obufs->buff_entry[i].buffer,
dbufs->obufs->buff_entry[i].size);
- pr_debug("sst:output_size = %d, out_copied = %d\n",
+ pr_debug("output_size = %d, out_copied = %d\n",
output_size, *out_copied);
if (dbufs->obufs->buff_entry[i].size <
(output_size - *out_copied))
cpy_size = dbufs->obufs->buff_entry[i].size;
else
cpy_size = output_size - *out_copied;
- pr_debug("sst:cpy size = %d\n", cpy_size);
- pr_debug("sst:Try copy To: %p, From %p, size %d\n",
+ pr_debug("cpy size = %d\n", cpy_size);
+ pr_debug("Try copy To: %p, From %p, size %d\n",
dbufs->obufs->buff_entry[i].buffer,
sst_drv_ctx->mmap_mem + *out_copied,
cpy_size);
@@ -1029,13 +1032,13 @@ static int sst_prepare_output_buffers(struct stream_info *str_info,
sst_drv_ctx->mmap_mem + *out_copied,
cpy_size);
if (retval) {
- pr_err("sst: copy to user failed\n");
+ pr_err("copy to user failed\n");
return -EIO;
} else
- pr_debug("sst:copy to user passed\n");
+ pr_debug("copy to user passed\n");
*out_copied += cpy_size;
dbufs->obufs->buff_entry[i].size -= cpy_size;
- pr_debug("sst:o/p buff size %d, out_copied %d\n",
+ pr_debug("o/p buff size %d, out_copied %d\n",
dbufs->obufs->buff_entry[i].size, *out_copied);
if (dbufs->obufs->buff_entry[i].size != 0) {
*output_index = i;
@@ -1073,7 +1076,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
unsigned long long input_bytes, output_bytes;
sst_drv_ctx->scard_ops->power_down_pmic();
- pr_debug("sst: Powering_down_PMIC...\n");
+ pr_debug("Powering_down_PMIC...\n");
retval = sst_validate_strid(str_id);
if (retval)
@@ -1081,7 +1084,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
str_info = &sst_drv_ctx->streams[str_id];
if (str_info->status != STREAM_INIT) {
- pr_err("sst: invalid stream state = %d\n",
+ pr_err("invalid stream state = %d\n",
str_info->status);
return -EINVAL;
}
@@ -1098,7 +1101,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
retval = sst_allocate_decode_buf(str_info, dbufs,
cum_input_given, cum_output_given);
if (retval) {
- pr_err("sst: mem allocation failed, abort!!!\n");
+ pr_err("mem allocation failed, abort!!!\n");
retval = -ENOMEM;
goto finish;
}
@@ -1114,7 +1117,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
dbufs, &input_index, &in_copied,
&input_index_valid_size, &new_entry_flag);
if (retval) {
- pr_err("sst: prepare in buffers failed\n");
+ pr_err("prepare in buffers failed\n");
goto finish;
}
@@ -1145,8 +1148,8 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
str_info->decode_osize = dbufs->obufs->
buff_entry[output_index].size;
str_info->decode_obuf_type = dbufs->obufs->type;
- pr_debug("sst:DRM handling\n");
- pr_debug("o/p_add=0x%lu Size=0x%x",
+ pr_debug("DRM handling\n");
+ pr_debug("o/p_add=0x%lu Size=0x%x\n",
(unsigned long) str_info->decode_obuf,
str_info->decode_osize);
} else {
@@ -1160,7 +1163,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
if (str_info->decode_isize > in_copied) {
str_info->decode_isize = in_copied;
- pr_debug("sst:i/p size = %d\n",
+ pr_debug("i/p size = %d\n",
str_info->decode_isize);
}
}
@@ -1168,20 +1171,19 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
retval = sst_send_decode_mess(str_id, str_info, &dec_info);
if (retval || dec_info.input_bytes_consumed == 0) {
- pr_err(
- "SST ERR: mess failed or no input consumed\n");
+ pr_err("SST ERR: mess failed or no input consumed\n");
goto finish;
}
input_bytes = dec_info.input_bytes_consumed;
output_bytes = dec_info.output_bytes_produced;
- pr_debug("sst:in_copied=%d, con=%lld, prod=%lld\n",
+ pr_debug("in_copied=%d, con=%lld, prod=%lld\n",
in_copied, input_bytes, output_bytes);
if (dbufs->obufs->type == SST_BUF_RAR) {
output_index += 1;
if (output_index == dbufs->obufs->entries) {
copy_in_done = true;
- pr_debug("sst:all i/p cpy done\n");
+ pr_debug("all i/p cpy done\n");
}
total_output += output_bytes;
} else {
@@ -1190,14 +1192,14 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
retval = sst_prepare_output_buffers(str_info, dbufs,
&output_index, output_size, &out_copied);
if (retval) {
- pr_err("sst:prep out buff fail\n");
+ pr_err("prep out buff fail\n");
goto finish;
}
if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
if (in_copied != input_bytes) {
int bytes_left = in_copied -
input_bytes;
- pr_debug("sst:bytes %d\n",
+ pr_debug("bytes %d\n",
bytes_left);
if (new_entry_flag == true)
input_index--;
@@ -1237,7 +1239,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
total_output += out_copied;
if (str_info->decode_osize != out_copied) {
str_info->decode_osize -= out_copied;
- pr_debug("sst:output size modified = %d\n",
+ pr_debug("output size modified = %d\n",
str_info->decode_osize);
}
}
@@ -1251,16 +1253,16 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
} else {
if (total_output == cum_output_given) {
copy_out_done = true;
- pr_debug("sst:all o/p cpy done\n");
+ pr_debug("all o/p cpy done\n");
}
if (total_input == cum_input_given) {
copy_in_done = true;
- pr_debug("sst:all i/p cpy done\n");
+ pr_debug("all i/p cpy done\n");
}
}
- pr_debug("sst:copy_out = %d, copy_in = %d\n",
+ pr_debug("copy_out = %d, copy_in = %d\n",
copy_out_done, copy_in_done);
}
@@ -1269,7 +1271,7 @@ finish:
dbufs->output_bytes_produced = total_output;
str_info->status = str_info->prev;
str_info->prev = STREAM_DECODE;
- str_info->decode_ibuf = NULL;
kfree(str_info->decode_ibuf);
+ str_info->decode_ibuf = NULL;
return retval;
}
diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c
index 4c0264ceaa88..fb2292186703 100644
--- a/drivers/staging/intel_sst/intelmid.c
+++ b/drivers/staging/intel_sst/intelmid.c
@@ -24,6 +24,9 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ALSA driver for Intel MID sound card chipset
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -101,12 +104,10 @@ static struct snd_pcm_hardware snd_intelmad_stream = {
static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- int ret_val = 0;
+ int ret_val = 0, str_id;
struct snd_intelmad *intelmaddata;
struct mad_stream_pvt *stream;
- /*struct stream_buffer buffer_to_sst;*/
-
-
+ struct intel_sst_pcm_control *sst_ops;
WARN_ON(!substream);
@@ -115,38 +116,35 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
WARN_ON(!intelmaddata->sstdrv_ops);
WARN_ON(!intelmaddata->sstdrv_ops->scard_ops);
+ sst_ops = intelmaddata->sstdrv_ops->pcm_control;
+ str_id = stream->stream_info.str_id;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- pr_debug("sst: Trigger Start\n");
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_START,
- &stream->stream_info.str_id);
+ pr_debug("Trigger Start\n");
+ ret_val = sst_ops->device_control(SST_SND_START, &str_id);
if (ret_val)
return ret_val;
stream->stream_status = RUNNING;
stream->substream = substream;
- stream->stream_status = RUNNING;
break;
case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("sst: in stop\n");
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
- &stream->stream_info.str_id);
+ pr_debug("in stop\n");
+ ret_val = sst_ops->device_control(SST_SND_DROP, &str_id);
if (ret_val)
return ret_val;
stream->stream_status = DROPPED;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pr_debug("sst: in pause\n");
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE,
- &stream->stream_info.str_id);
+ pr_debug("in pause\n");
+ ret_val = sst_ops->device_control(SST_SND_PAUSE, &str_id);
if (ret_val)
return ret_val;
stream->stream_status = PAUSED;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("sst: in pause release\n");
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME,
- &stream->stream_info.str_id);
+ pr_debug("in pause release\n");
+ ret_val = sst_ops->device_control(SST_SND_RESUME, &str_id);
if (ret_val)
return ret_val;
stream->stream_status = RUNNING;
@@ -170,19 +168,19 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
int ret_val = 0;
struct snd_intelmad *intelmaddata;
- pr_debug("sst: pcm_prepare called\n");
+ pr_debug("pcm_prepare called\n");
WARN_ON(!substream);
stream = substream->runtime->private_data;
intelmaddata = snd_pcm_substream_chip(substream);
- pr_debug("sst: pb cnt = %d cap cnt = %d\n",\
+ pr_debug("pb cnt = %d cap cnt = %d\n",\
intelmaddata->playback_cnt,
intelmaddata->capture_cnt);
if (stream->stream_info.str_id) {
- pr_debug("sst: Prepare called for already set stream\n");
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
- &stream->stream_info.str_id);
+ pr_debug("Prepare called for already set stream\n");
+ ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control(
+ SST_SND_DROP, &stream->stream_info.str_id);
return ret_val;
}
@@ -197,7 +195,7 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
/* return back the stream id */
snprintf(substream->pcm->id, sizeof(substream->pcm->id),
"%d", stream->stream_info.str_id);
- pr_debug("sst: stream id to user = %s\n",
+ pr_debug("stream id to user = %s\n",
substream->pcm->id);
ret_val = snd_intelmad_init_stream(substream);
@@ -212,7 +210,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
{
int ret_val;
- pr_debug("sst: snd_intelmad_hw_params called\n");
+ pr_debug("snd_intelmad_hw_params called\n");
ret_val = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
memset(substream->runtime->dma_area, 0,
@@ -223,7 +221,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
static int snd_intelmad_hw_free(struct snd_pcm_substream *substream)
{
- pr_debug("sst: snd_intelmad_hw_free called\n");
+ pr_debug("snd_intelmad_hw_free called\n");
return snd_pcm_lib_free_pages(substream);
}
@@ -250,15 +248,15 @@ static snd_pcm_uframes_t snd_intelmad_pcm_pointer
if (stream->stream_status == INIT)
return 0;
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER,
- &stream->stream_info);
+ ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control(
+ SST_SND_BUFFER_POINTER, &stream->stream_info);
if (ret_val) {
- pr_err("sst: error code = 0x%x\n", ret_val);
+ pr_err("error code = 0x%x\n", ret_val);
return ret_val;
}
- pr_debug("sst: samples reported out 0x%llx\n",
+ pr_debug("samples reported out 0x%llx\n",
stream->stream_info.buffer_ptr);
- pr_debug("sst: Frame bits:: %d period_count :: %d\n",
+ pr_debug("Frame bits:: %d period_count :: %d\n",
(int)substream->runtime->frame_bits,
(int)substream->runtime->period_size);
@@ -277,26 +275,26 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream)
{
struct snd_intelmad *intelmaddata;
struct mad_stream_pvt *stream;
- int ret_val = 0;
+ int ret_val = 0, str_id;
WARN_ON(!substream);
stream = substream->runtime->private_data;
+ str_id = stream->stream_info.str_id;
- pr_debug("sst: snd_intelmad_close called\n");
+ pr_debug("sst: snd_intelmad_close called for %d\n", str_id);
intelmaddata = snd_pcm_substream_chip(substream);
- pr_debug("sst: str id = %d\n", stream->stream_info.str_id);
+ pr_debug("str id = %d\n", stream->stream_info.str_id);
if (stream->stream_info.str_id) {
/* SST API to actually stop/free the stream */
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE,
- &stream->stream_info.str_id);
+ ret_val = intelmaddata->sstdrv_ops->pcm_control->close(str_id);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
intelmaddata->playback_cnt--;
else
intelmaddata->capture_cnt--;
}
- pr_debug("sst: snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
+ pr_debug("snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
intelmaddata->playback_cnt, intelmaddata->capture_cnt);
kfree(substream->runtime->private_data);
return ret_val;
@@ -319,7 +317,7 @@ static int snd_intelmad_open(struct snd_pcm_substream *substream,
WARN_ON(!substream);
- pr_debug("sst: snd_intelmad_open called\n");
+ pr_debug("snd_intelmad_open called\n");
intelmaddata = snd_pcm_substream_chip(substream);
runtime = substream->runtime;
@@ -456,17 +454,17 @@ void sst_mad_send_jack_report(struct snd_jack *jack,
{
if (!jack) {
- pr_debug("sst: MAD error jack empty\n");
+ pr_debug("MAD error jack empty\n");
} else {
- pr_debug("sst: MAD send jack report for = %d!!!\n", status);
- pr_debug("sst: MAD send jack report %d\n", jack->type);
+ pr_debug("MAD send jack report for = %d!!!\n", status);
+ pr_debug("MAD send jack report %d\n", jack->type);
snd_jack_report(jack, status);
/*button pressed and released */
if (buttonpressevent)
snd_jack_report(jack, 0);
- pr_debug("sst: MAD sending jack report Done !!!\n");
+ pr_debug("MAD sending jack report Done !!!\n");
}
@@ -490,7 +488,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
if (intsts & 0x4) {
if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("sst: Audio interrupt enable\n");
+ pr_debug("Audio interrupt enable\n");
sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
@@ -500,7 +498,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
}
/* send headphone detect */
- pr_debug("sst: MAD headphone %d\n", intsts & 0x4);
+ pr_debug("MAD headphone %d\n", intsts & 0x4);
jack = &intelmaddata->jack[0].jack;
present = !(intelmaddata->jack[0].jack_status);
intelmaddata->jack[0].jack_status = present;
@@ -510,7 +508,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
if (intsts & 0x2) {
/* send short push */
- pr_debug("sst: MAD short push %d\n", intsts & 0x2);
+ pr_debug("MAD short push %d\n", intsts & 0x2);
jack = &intelmaddata->jack[2].jack;
present = 1;
jack_event_flag = 1;
@@ -518,7 +516,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
}
if (intsts & 0x1) {
/* send long push */
- pr_debug("sst: MAD long push %d\n", intsts & 0x1);
+ pr_debug("MAD long push %d\n", intsts & 0x1);
jack = &intelmaddata->jack[3].jack;
present = 1;
jack_event_flag = 1;
@@ -526,7 +524,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
}
if (intsts & 0x8) {
if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("sst: Audio interrupt enable\n");
+ pr_debug("Audio interrupt enable\n");
sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
@@ -535,7 +533,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
intelmaddata->jack[1].jack_status = 0;
}
/* send headset detect */
- pr_debug("sst: MAD headset = %d\n", intsts & 0x8);
+ pr_debug("MAD headset = %d\n", intsts & 0x8);
jack = &intelmaddata->jack[1].jack;
present = !(intelmaddata->jack[1].jack_status);
intelmaddata->jack[1].jack_status = present;
@@ -558,10 +556,10 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
scard_ops = intelmaddata->sstdrv_ops->scard_ops;
- pr_debug("sst: previous value: %x\n", intelmaddata->jack_prev_state);
+ pr_debug("previous value: %x\n", intelmaddata->jack_prev_state);
if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("sst: Audio interrupt enable\n");
+ pr_debug("Audio interrupt enable\n");
intelmaddata->jack_prev_state = 0xC0;
intelmid_audio_interrupt_enable = 1;
}
@@ -572,12 +570,12 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
sc_access_read.reg_addr = 0x201;
sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
value = (sc_access_read.value);
- pr_debug("sst: value returned = 0x%x\n", value);
+ pr_debug("value returned = 0x%x\n", value);
}
if (jack_prev_state == 0xc0 && value == 0x40) {
/*headset detected. */
- pr_debug("sst: MAD headset inserted\n");
+ pr_debug("MAD headset inserted\n");
jack = &intelmaddata->jack[1].jack;
present = 1;
jack_event_flag = 1;
@@ -587,7 +585,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
if (jack_prev_state == 0xc0 && value == 0x00) {
/* headphone detected. */
- pr_debug("sst: MAD headphone inserted\n");
+ pr_debug("MAD headphone inserted\n");
jack = &intelmaddata->jack[0].jack;
present = 1;
jack_event_flag = 1;
@@ -596,9 +594,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
if (jack_prev_state == 0x40 && value == 0xc0) {
/*headset removed*/
- pr_debug("sst: Jack headset status %d\n",
+ pr_debug("Jack headset status %d\n",
intelmaddata->jack[1].jack_status);
- pr_debug("sst: MAD headset removed\n");
+ pr_debug("MAD headset removed\n");
jack = &intelmaddata->jack[1].jack;
present = 0;
jack_event_flag = 1;
@@ -607,9 +605,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
if (jack_prev_state == 0x00 && value == 0xc0) {
/* headphone detected. */
- pr_debug("sst: Jack headphone status %d\n",
+ pr_debug("Jack headphone status %d\n",
intelmaddata->jack[0].jack_status);
- pr_debug("sst: headphone removed\n");
+ pr_debug("headphone removed\n");
jack = &intelmaddata->jack[0].jack;
present = 0;
jack_event_flag = 1;
@@ -618,7 +616,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
if (jack_prev_state == 0x40 && value == 0x00) {
/*button pressed*/
do_gettimeofday(&intelmaddata->jack[1].buttonpressed);
- pr_debug("sst: MAD button press detected n");
+ pr_debug("MAD button press detected\n");
}
@@ -628,19 +626,19 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
do_gettimeofday(
&intelmaddata->jack[1].buttonreleased);
/*button pressed */
- pr_debug("sst: Button Released detected\n");
+ pr_debug("Button Released detected\n");
timediff = intelmaddata->jack[1].
buttonreleased.tv_sec - intelmaddata->
jack[1].buttonpressed.tv_sec;
buttonpressflag = 1;
if (timediff > 1) {
- pr_debug("sst: long press detected\n");
+ pr_debug("long press detected\n");
/* send headphone detect/undetect */
jack = &intelmaddata->jack[3].jack;
present = 1;
jack_event_flag = 1;
} else {
- pr_debug("sst: short press detected\n");
+ pr_debug("short press detected\n");
/* send headphone detect/undetect */
jack = &intelmaddata->jack[2].jack;
present = 1;
@@ -667,24 +665,24 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
sc_access_read.reg_addr = 0x132;
sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
value = (sc_access_read.value);
- pr_debug("sst: value returned = 0x%x\n", value);
+ pr_debug("value returned = 0x%x\n", value);
}
if (intsts & 0x1) {
- pr_debug("sst: headset detected\n");
+ pr_debug("headset detected\n");
/* send headset detect/undetect */
jack = &intelmaddata->jack[1].jack;
present = (value == 0x1) ? 1 : 0;
jack_event_flag = 1;
}
if (intsts & 0x2) {
- pr_debug("sst: headphone detected\n");
+ pr_debug("headphone detected\n");
/* send headphone detect/undetect */
jack = &intelmaddata->jack[0].jack;
present = (value == 0x2) ? 1 : 0;
jack_event_flag = 1;
}
if (intsts & 0x4) {
- pr_debug("sst: short push detected\n");
+ pr_debug("short push detected\n");
/* send short push */
jack = &intelmaddata->jack[2].jack;
present = 1;
@@ -692,7 +690,7 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
buttonpressflag = 1;
}
if (intsts & 0x8) {
- pr_debug("sst: long push detected\n");
+ pr_debug("long push detected\n");
/* send long push */
jack = &intelmaddata->jack[3].jack;
present = 1;
@@ -738,12 +736,12 @@ static int __devinit snd_intelmad_register_irq(
u32 regbase = AUDINT_BASE, regsize = 8;
char *drv_name;
- pr_debug("sst: irq reg done, regbase 0x%x, regsize 0x%x\n",
+ pr_debug("irq reg done, regbase 0x%x, regsize 0x%x\n",
regbase, regsize);
intelmaddata->int_base = ioremap_nocache(regbase, regsize);
if (!intelmaddata->int_base)
- pr_err("sst: Mapping of cache failed\n");
- pr_debug("sst: irq = 0x%x\n", intelmaddata->irq);
+ pr_err("Mapping of cache failed\n");
+ pr_debug("irq = 0x%x\n", intelmaddata->irq);
if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
drv_name = DRIVER_NAME_MFLD;
else
@@ -753,7 +751,7 @@ static int __devinit snd_intelmad_register_irq(
IRQF_SHARED, drv_name,
intelmaddata);
if (ret_val)
- pr_err("sst: cannot register IRQ\n");
+ pr_err("cannot register IRQ\n");
return ret_val;
}
@@ -775,10 +773,10 @@ static int __devinit snd_intelmad_sst_register(
if (ret_val)
return ret_val;
sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0));
- pr_debug("sst: orginal n extrated vendor id = 0x%x %d\n",
+ pr_debug("orginal n extrated vendor id = 0x%x %d\n",
vendor_addr.value, sst_card_vendor_id);
if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) {
- pr_err("sst: vendor card not supported!!\n");
+ pr_err("vendor card not supported!!\n");
return -EIO;
}
} else
@@ -801,7 +799,7 @@ static int __devinit snd_intelmad_sst_register(
/* registering with SST driver to get access to SST APIs to use */
ret_val = register_sst_card(intelmaddata->sstdrv_ops);
if (ret_val) {
- pr_err("sst: sst card registration failed\n");
+ pr_err("sst card registration failed\n");
return ret_val;
}
@@ -832,7 +830,7 @@ static int __devinit snd_intelmad_pcm_new(struct snd_card *card,
char name[32] = INTEL_MAD;
struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL;
- pr_debug("sst: called for pb %d, cp %d, idx %d\n", pb, cap, index);
+ pr_debug("called for pb %d, cp %d, idx %d\n", pb, cap, index);
ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm);
if (ret_val)
return ret_val;
@@ -878,7 +876,7 @@ static int __devinit snd_intelmad_pcm(struct snd_card *card,
WARN_ON(!card);
WARN_ON(!intelmaddata);
- pr_debug("sst: snd_intelmad_pcm called\n");
+ pr_debug("snd_intelmad_pcm called\n");
ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0);
if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT)
return ret_val;
@@ -903,7 +901,7 @@ static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
struct snd_jack *jack;
int retval;
- pr_debug("sst: snd_intelmad_jack called\n");
+ pr_debug("snd_intelmad_jack called\n");
jack = &intelmaddata->jack[0].jack;
retval = snd_jack_new(intelmaddata->card, "Headphone",
SND_JACK_HEADPHONE, &jack);
@@ -982,9 +980,9 @@ static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata)
ret_val = snd_ctl_add(card,
snd_ctl_new1(&controls[idx],
intelmaddata));
- pr_debug("sst: mixer[idx]=%d added\n", idx);
+ pr_debug("mixer[idx]=%d added\n", idx);
if (ret_val) {
- pr_err("sst: in adding of control index = %d\n", idx);
+ pr_err("in adding of control index = %d\n", idx);
break;
}
}
@@ -999,7 +997,7 @@ static int snd_intelmad_dev_free(struct snd_device *device)
intelmaddata = device->device_data;
- pr_debug("sst: snd_intelmad_dev_free called\n");
+ pr_debug("snd_intelmad_dev_free called\n");
snd_card_free(intelmaddata->card);
/*genl_unregister_family(&audio_event_genl_family);*/
unregister_sst_card(intelmaddata->sstdrv_ops);
@@ -1040,23 +1038,23 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
const struct platform_device_id *id = platform_get_device_id(pdev);
unsigned int cpu_id = (unsigned int)id->driver_data;
- pr_debug("sst: probe for %s cpu_id %d\n", pdev->name, cpu_id);
+ pr_debug("probe for %s cpu_id %d\n", pdev->name, cpu_id);
if (!strcmp(pdev->name, DRIVER_NAME_MRST))
- pr_debug("sst: detected MRST\n");
+ pr_debug("detected MRST\n");
else if (!strcmp(pdev->name, DRIVER_NAME_MFLD))
- pr_debug("sst: detected MFLD\n");
+ pr_debug("detected MFLD\n");
else {
- pr_err("sst: detected unknown device abort!!\n");
+ pr_err("detected unknown device abort!!\n");
return -EIO;
}
if ((cpu_id < CPU_CHIP_LINCROFT) || (cpu_id > CPU_CHIP_PENWELL)) {
- pr_err("sst: detected unknown cpu_id abort!!\n");
+ pr_err("detected unknown cpu_id abort!!\n");
return -EIO;
}
/* allocate memory for saving internal context and working */
intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL);
if (!intelmaddata) {
- pr_debug("sst: mem alloctn fail\n");
+ pr_debug("mem alloctn fail\n");
return -ENOMEM;
}
@@ -1064,7 +1062,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops),
GFP_KERNEL);
if (!intelmaddata->sstdrv_ops) {
- pr_err("sst: mem allocation for ops fail\n");
+ pr_err("mem allocation for ops fail\n");
kfree(intelmaddata);
return -ENOMEM;
}
@@ -1073,7 +1071,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
/* create a card instance with ALSA framework */
ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);
if (ret_val) {
- pr_err("sst: snd_card_create fail\n");
+ pr_err("snd_card_create fail\n");
goto free_allocs;
}
@@ -1092,7 +1090,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
/* registering with LPE driver to get access to SST APIs to use */
ret_val = snd_intelmad_sst_register(intelmaddata);
if (ret_val) {
- pr_err("sst: snd_intelmad_sst_register failed\n");
+ pr_err("snd_intelmad_sst_register failed\n");
goto free_allocs;
}
@@ -1100,19 +1098,19 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
ret_val = snd_intelmad_pcm(card, intelmaddata);
if (ret_val) {
- pr_err("sst: snd_intelmad_pcm failed\n");
+ pr_err("snd_intelmad_pcm failed\n");
goto free_allocs;
}
ret_val = snd_intelmad_mixer(intelmaddata);
if (ret_val) {
- pr_err("sst: snd_intelmad_mixer failed\n");
+ pr_err("snd_intelmad_mixer failed\n");
goto free_allocs;
}
ret_val = snd_intelmad_jack(intelmaddata);
if (ret_val) {
- pr_err("sst: snd_intelmad_jack failed\n");
+ pr_err("snd_intelmad_jack failed\n");
goto free_allocs;
}
@@ -1126,31 +1124,31 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
ret_val = snd_intelmad_register_irq(intelmaddata);
if (ret_val) {
- pr_err("sst: snd_intelmad_register_irq fail\n");
+ pr_err("snd_intelmad_register_irq fail\n");
goto free_allocs;
}
/* internal function call to register device with ALSA */
ret_val = snd_intelmad_create(intelmaddata, card);
if (ret_val) {
- pr_err("sst: snd_intelmad_create failed\n");
+ pr_err("snd_intelmad_create failed\n");
goto free_allocs;
}
card->private_data = &intelmaddata;
snd_card_set_dev(card, &pdev->dev);
ret_val = snd_card_register(card);
if (ret_val) {
- pr_err("sst: snd_card_register failed\n");
+ pr_err("snd_card_register failed\n");
goto free_allocs;
}
- pr_debug("sst:snd_intelmad_probe complete\n");
+ pr_debug("snd_intelmad_probe complete\n");
return ret_val;
free_mad_jack_wq:
destroy_workqueue(intelmaddata->mad_jack_wq);
free_allocs:
- pr_err("sst: probe failed\n");
+ pr_err("probe failed\n");
snd_card_free(card);
kfree(intelmaddata->sstdrv_ops);
kfree(intelmaddata);
@@ -1200,7 +1198,7 @@ static struct platform_driver snd_intelmad_driver = {
*/
static int __init alsa_card_intelmad_init(void)
{
- pr_debug("sst: mad_init called\n");
+ pr_debug("mad_init called\n");
return platform_driver_register(&snd_intelmad_driver);
}
@@ -1211,7 +1209,7 @@ static int __init alsa_card_intelmad_init(void)
*/
static void __exit alsa_card_intelmad_exit(void)
{
- pr_debug("sst:mad_exit called\n");
+ pr_debug("mad_exit called\n");
return platform_driver_unregister(&snd_intelmad_driver);
}
diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h
index 81e744816765..0ce103185848 100644
--- a/drivers/staging/intel_sst/intelmid.h
+++ b/drivers/staging/intel_sst/intelmid.h
@@ -178,9 +178,4 @@ extern struct snd_kcontrol_new snd_intelmad_controls_mrst[];
extern struct snd_kcontrol_new snd_intelmad_controls_mfld[];
extern struct snd_pmic_ops *intelmad_vendor_ops[];
-/* This is an enabler hook as the platform detection logic isn't yet
- present and depends on some firmware and DMI support to detect AAVA
- devices. It will vanish once the AAVA platform support is merged */
-#define is_aava() 0
-
#endif /* __INTELMID_H */
diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c
index 03b4ece02f91..69af0704ce94 100644
--- a/drivers/staging/intel_sst/intelmid_ctrl.c
+++ b/drivers/staging/intel_sst/intelmid_ctrl.c
@@ -24,6 +24,9 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ALSA driver handling mixer controls for Intel MAD chipset
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <sound/core.h>
#include <sound/control.h>
#include "jack.h"
@@ -216,7 +219,7 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
- pr_debug("sst: snd_intelmad_volume_get called\n");
+ pr_debug("snd_intelmad_volume_get called\n");
WARN_ON(!uval);
WARN_ON(!kcontrol);
@@ -273,7 +276,7 @@ static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol,
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
- pr_debug("sst: Mute_get called\n");
+ pr_debug("Mute_get called\n");
WARN_ON(!uval);
WARN_ON(!kcontrol);
@@ -332,7 +335,7 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
- pr_debug("sst: volume set called:%ld %ld\n",
+ pr_debug("volume set called:%ld %ld\n",
uval->value.integer.value[0],
uval->value.integer.value[1]);
@@ -387,7 +390,7 @@ static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol,
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
- pr_debug("sst: snd_intelmad_mute_set called\n");
+ pr_debug("snd_intelmad_mute_set called\n");
WARN_ON(!uval);
WARN_ON(!kcontrol);
@@ -455,7 +458,7 @@ static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol,
{
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
- pr_debug("sst: device_get called\n");
+ pr_debug("device_get called\n");
WARN_ON(!uval);
WARN_ON(!kcontrol);
@@ -491,8 +494,9 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
struct snd_intelmad *intelmaddata;
struct snd_pmic_ops *scard_ops;
int ret_val = 0, vendor, status;
+ struct intel_sst_pcm_control *pcm_control;
- pr_debug("sst: snd_intelmad_device_set called\n");
+ pr_debug("snd_intelmad_device_set called\n");
WARN_ON(!uval);
WARN_ON(!kcontrol);
@@ -518,15 +522,13 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
case INPUT_SEL:
vendor = intelmaddata->sstdrv_ops->vendor_id;
if ((vendor == SND_MX) || (vendor == SND_FS)) {
- if (uval->value.enumerated.item[0] == HS_MIC) {
+ pcm_control = intelmaddata->sstdrv_ops->pcm_control;
+ if (uval->value.enumerated.item[0] == HS_MIC)
status = 1;
- intelmaddata->sstdrv_ops->
- control_set(SST_ENABLE_RX_TIME_SLOT, &status);
- } else {
+ else
status = 0;
- intelmaddata->sstdrv_ops->
- control_set(SST_ENABLE_RX_TIME_SLOT, &status);
- }
+ pcm_control->device_control(
+ SST_ENABLE_RX_TIME_SLOT, &status);
}
ret_val = scard_ops->set_input_dev(
uval->value.enumerated.item[0]);
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c
index 4d1755efceef..da093ed0cd88 100644
--- a/drivers/staging/intel_sst/intelmid_msic_control.c
+++ b/drivers/staging/intel_sst/intelmid_msic_control.c
@@ -24,6 +24,8 @@
* This file contains the control operations of msic vendors
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/file.h>
#include "intel_sst.h"
@@ -83,7 +85,7 @@ static int msic_init_card(void)
snd_msic_ops.cap_on = 0;
snd_msic_ops.input_dev_id = DMIC; /*def dev*/
snd_msic_ops.output_dev_id = STEREO_HEADPHONE;
- pr_debug("sst: msic init complete!!\n");
+ pr_debug("msic init complete!!\n");
return 0;
}
@@ -173,7 +175,7 @@ static int msic_power_up_pb(unsigned int device)
return retval;
}
- pr_debug("sst: powering up pb.... Device %d\n", device);
+ pr_debug("powering up pb.... Device %d\n", device);
sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
switch (device) {
case SND_SST_DEVICE_HEADSET:
@@ -205,7 +207,7 @@ static int msic_power_up_pb(unsigned int device)
break;
default:
- pr_warn("sst: Wrong Device %d, selected %d\n",
+ pr_warn("Wrong Device %d, selected %d\n",
device, snd_msic_ops.output_dev_id);
}
return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1);
@@ -268,7 +270,7 @@ static int msic_power_up_cp(unsigned int device)
return retval;
}
- pr_debug("sst: powering up cp....%d\n", snd_msic_ops.input_dev_id);
+ pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id);
sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
snd_msic_ops.cap_on = 1;
if (snd_msic_ops.input_dev_id == AMIC)
@@ -283,7 +285,7 @@ static int msic_power_down(void)
{
int retval = 0;
- pr_debug("sst: powering dn msic\n");
+ pr_debug("powering dn msic\n");
snd_msic_ops.pb_on = 0;
snd_msic_ops.cap_on = 0;
return retval;
@@ -293,7 +295,7 @@ static int msic_power_down_pb(void)
{
int retval = 0;
- pr_debug("sst: powering dn pb....\n");
+ pr_debug("powering dn pb....\n");
snd_msic_ops.pb_on = 0;
return retval;
}
@@ -302,7 +304,7 @@ static int msic_power_down_cp(void)
{
int retval = 0;
- pr_debug("sst: powering dn cp....\n");
+ pr_debug("powering dn cp....\n");
snd_msic_ops.cap_on = 0;
return retval;
}
@@ -311,7 +313,7 @@ static int msic_set_selected_output_dev(u8 value)
{
int retval = 0;
- pr_debug("sst: msic set selected output:%d\n", value);
+ pr_debug("msic set selected output:%d\n", value);
snd_msic_ops.output_dev_id = value;
if (snd_msic_ops.pb_on)
msic_power_up_pb(SND_SST_DEVICE_HEADSET);
@@ -330,15 +332,15 @@ static int msic_set_selected_input_dev(u8 value)
};
int retval = 0;
- pr_debug("sst: msic_set_selected_input_dev:%d\n", value);
+ pr_debug("msic_set_selected_input_dev:%d\n", value);
snd_msic_ops.input_dev_id = value;
switch (value) {
case AMIC:
- pr_debug("sst: Selecting AMIC1\n");
+ pr_debug("Selecting AMIC1\n");
retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1);
break;
case DMIC:
- pr_debug("sst: Selecting DMIC1\n");
+ pr_debug("Selecting DMIC1\n");
retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1);
break;
default:
diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c
index 9ed9475ccc7b..3ba9daf67526 100644
--- a/drivers/staging/intel_sst/intelmid_pvt.c
+++ b/drivers/staging/intel_sst/intelmid_pvt.c
@@ -23,6 +23,9 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ALSA driver for Intel MID sound card chipset - holding private functions
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/io.h>
#include <asm/intel_scu_ipc.h>
#include <sound/core.h>
@@ -50,7 +53,7 @@ void period_elapsed(void *mad_substream)
if (stream->stream_status != RUNNING)
return;
- pr_debug("sst: calling period elapsed\n");
+ pr_debug("calling period elapsed\n");
snd_pcm_period_elapsed(substream);
return;
}
@@ -76,8 +79,8 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
param.uc.pcm_params.period_count = substream->runtime->period_size;
param.uc.pcm_params.ring_buffer_addr =
virt_to_phys(substream->runtime->dma_area);
- pr_debug("sst: period_cnt = %d\n", param.uc.pcm_params.period_count);
- pr_debug("sst: sfreq= %d, wd_sz = %d\n",
+ pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count);
+ pr_debug("sfreq= %d, wd_sz = %d\n",
param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz);
str_params.sparams = param;
@@ -85,24 +88,22 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
str_params.ops = STREAM_OPS_PLAYBACK;
- pr_debug("sst: Playbck stream,Device %d\n", stream->device);
+ pr_debug("Playbck stream,Device %d\n", stream->device);
} else {
str_params.ops = STREAM_OPS_CAPTURE;
stream->device = SND_SST_DEVICE_CAPTURE;
- pr_debug("sst: Capture stream,Device %d\n", stream->device);
+ pr_debug("Capture stream,Device %d\n", stream->device);
}
str_params.device_type = stream->device;
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC,
- &str_params);
- pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n",
- ret_val);
+ ret_val = intelmaddata->sstdrv_ops->pcm_control->open(&str_params);
+ pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
if (ret_val < 0)
return ret_val;
stream->stream_info.str_id = ret_val;
stream->stream_status = INIT;
stream->stream_info.buffer_ptr = 0;
- pr_debug("sst: str id : %d\n", stream->stream_info.str_id);
+ pr_debug("str id : %d\n", stream->stream_info.str_id);
return ret_val;
}
@@ -113,15 +114,15 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream);
int ret_val;
- pr_debug("sst: setting buffer ptr param\n");
+ pr_debug("setting buffer ptr param\n");
stream->stream_info.period_elapsed = period_elapsed;
stream->stream_info.mad_substream = substream;
stream->stream_info.buffer_ptr = 0;
stream->stream_info.sfreq = substream->runtime->rate;
- ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT,
- &stream->stream_info);
+ ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control(
+ SST_SND_STREAM_INIT, &stream->stream_info);
if (ret_val)
- pr_err("sst: control_set ret error %d\n", ret_val);
+ pr_err("control_set ret error %d\n", ret_val);
return ret_val;
}
@@ -145,30 +146,29 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access,
for (i = 0; i < num_val; i++) {
retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr,
sc_access[i].value);
- if (retval) {
- pr_err("sst: IPC write failed!!! %d\n", retval);
- return retval;
- }
+ if (retval)
+ goto err;
}
} else if (type == PMIC_READ) {
for (i = 0; i < num_val; i++) {
retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr,
&(sc_access[i].value));
- if (retval) {
- pr_err("sst: IPC read failed!!!!!%d\n", retval);
- return retval;
- }
+ if (retval)
+ goto err;
}
} else {
for (i = 0; i < num_val; i++) {
retval = intel_scu_ipc_update_register(
sc_access[i].reg_addr, sc_access[i].value,
sc_access[i].mask);
- if (retval) {
- pr_err("sst: IPC Modify failed!!!%d\n", retval);
- return retval;
- }
+ if (retval)
+ goto err;
}
}
- return retval;
+ return 0;
+err:
+ pr_err("IPC failed for cmd %d, %d\n", retval, type);
+ pr_err("reg:0x%2x addr:0x%2x\n",
+ sc_access[i].reg_addr, sc_access[i].value);
+ return retval;
}
diff --git a/drivers/staging/intel_sst/intelmid_v0_control.c b/drivers/staging/intel_sst/intelmid_v0_control.c
index f586d62ac9af..7859225e3d60 100644
--- a/drivers/staging/intel_sst/intelmid_v0_control.c
+++ b/drivers/staging/intel_sst/intelmid_v0_control.c
@@ -26,6 +26,8 @@
* This file contains the control operations of vendor 1
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/file.h>
#include "intel_sst.h"
@@ -151,7 +153,7 @@ static int fs_power_up_pb(unsigned int port)
if (retval)
return retval;
- pr_debug("sst: in fs power up pb\n");
+ pr_debug("in fs power up pb\n");
return fs_enable_audiodac(UNMUTE);
}
@@ -173,7 +175,7 @@ static int fs_power_down_pb(void)
if (retval)
return retval;
- pr_debug("sst: in fsl power down pb\n");
+ pr_debug("in fsl power down pb\n");
return fs_enable_audiodac(UNMUTE);
}
@@ -380,7 +382,7 @@ static int fs_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
}
- pr_debug("sst: sfreq:%d,Register value = %x\n", sfreq, config1);
+ pr_debug("sfreq:%d,Register value = %x\n", sfreq, config1);
if (word_size == 24) {
sc_access[0].reg_addr = AUDIOPORT1;
@@ -438,18 +440,18 @@ static int fs_set_selected_input_dev(u8 value)
switch (value) {
case AMIC:
- pr_debug("sst: Selecting amic not supported in mono cfg\n");
+ pr_debug("Selecting amic not supported in mono cfg\n");
return sst_sc_reg_access(sc_access_mic, PMIC_READ_MODIFY, 2);
break;
case HS_MIC:
- pr_debug("sst: Selecting hsmic\n");
+ pr_debug("Selecting hsmic\n");
return sst_sc_reg_access(sc_access_hsmic,
PMIC_READ_MODIFY, 2);
break;
case DMIC:
- pr_debug("sst: Selecting dmic\n");
+ pr_debug("Selecting dmic\n");
return sst_sc_reg_access(sc_access_dmic, PMIC_READ_MODIFY, 2);
break;
@@ -505,7 +507,7 @@ static int fs_set_mute(int dev_id, u8 value)
return retval;
- pr_debug("sst: dev_id:0x%x value:0x%x\n", dev_id, value);
+ pr_debug("dev_id:0x%x value:0x%x\n", dev_id, value);
switch (dev_id) {
case PMIC_SND_DMIC_MUTE:
sc_access[0].reg_addr = MICCTRL;
@@ -606,7 +608,7 @@ static int fs_set_vol(int dev_id, int value)
switch (dev_id) {
case PMIC_SND_LEFT_PB_VOL:
- pr_debug("sst: PMIC_SND_LEFT_PB_VOL:%d\n", value);
+ pr_debug("PMIC_SND_LEFT_PB_VOL:%d\n", value);
sc_access[0].value = sc_access[1].value = value;
sc_access[0].reg_addr = AUD16;
sc_access[1].reg_addr = AUD15;
@@ -616,7 +618,7 @@ static int fs_set_vol(int dev_id, int value)
break;
case PMIC_SND_RIGHT_PB_VOL:
- pr_debug("sst: PMIC_SND_RIGHT_PB_VOL:%d\n", value);
+ pr_debug("PMIC_SND_RIGHT_PB_VOL:%d\n", value);
sc_access[0].value = sc_access[1].value = value;
sc_access[0].reg_addr = AUD17;
sc_access[1].reg_addr = AUD15;
@@ -629,7 +631,7 @@ static int fs_set_vol(int dev_id, int value)
reg_num = 2;
break;
case PMIC_SND_CAPTURE_VOL:
- pr_debug("sst: PMIC_SND_CAPTURE_VOL:%d\n", value);
+ pr_debug("PMIC_SND_CAPTURE_VOL:%d\n", value);
sc_access[0].reg_addr = MICLICTRL1;
sc_access[1].reg_addr = MICLICTRL2;
sc_access[2].reg_addr = DMICCTRL1;
@@ -726,17 +728,17 @@ static int fs_get_vol(int dev_id, int *value)
switch (dev_id) {
case PMIC_SND_CAPTURE_VOL:
- pr_debug("sst: PMIC_SND_CAPTURE_VOL\n");
+ pr_debug("PMIC_SND_CAPTURE_VOL\n");
sc_access.reg_addr = MICLICTRL1;
mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
break;
case PMIC_SND_LEFT_PB_VOL:
- pr_debug("sst: PMIC_SND_LEFT_PB_VOL\n");
+ pr_debug("PMIC_SND_LEFT_PB_VOL\n");
sc_access.reg_addr = AUD16;
mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
break;
case PMIC_SND_RIGHT_PB_VOL:
- pr_debug("sst: PMIC_SND_RT_PB_VOL\n");
+ pr_debug("PMIC_SND_RT_PB_VOL\n");
sc_access.reg_addr = AUD17;
mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
break;
@@ -745,9 +747,9 @@ static int fs_get_vol(int dev_id, int *value)
}
retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
- pr_debug("sst: value read = 0x%x\n", sc_access.value);
+ pr_debug("value read = 0x%x\n", sc_access.value);
*value = (int) (sc_access.value & mask);
- pr_debug("sst: value returned = 0x%x\n", *value);
+ pr_debug("value returned = 0x%x\n", *value);
return retval;
}
diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c
index 9de86b2f6b08..478cfecdefd7 100644
--- a/drivers/staging/intel_sst/intelmid_v1_control.c
+++ b/drivers/staging/intel_sst/intelmid_v1_control.c
@@ -25,6 +25,8 @@
* This file contains the control operations of vendor 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/file.h>
#include <asm/mrst.h>
@@ -132,56 +134,6 @@ static int mx_init_card(void)
return sst_sc_reg_access(sc_access, PMIC_WRITE, 47);
}
-static int mx_init_capture_card(void)
-{
- struct sc_reg_access sc_access[] = {
- {0x206, 0x5a, 0x0},
- {0x207, 0xbe, 0x0},
- {0x208, 0x90, 0x0},
- {0x209, 0x32, 0x0},
- {0x20e, 0x22, 0x0},
- {0x210, 0x84, 0x0},
- {0x223, 0x20, 0x0},
- {0x226, 0xC0, 0x0},
- };
-
- int retval = 0;
-
- retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 8);
- if (0 != retval) {
- /* pmic communication fails */
- pr_debug("sst: pmic commn failed\n");
- return retval;
- }
-
- pr_debug("sst: Capture configuration complete!!\n");
- return 0;
-}
-
-static int mx_init_playback_card(void)
-{
- struct sc_reg_access sc_access[] = {
- {0x206, 0x00, 0x0},
- {0x207, 0x00, 0x0},
- {0x208, 0x00, 0x0},
- {0x209, 0x51, 0x0},
- {0x20e, 0x51, 0x0},
- {0x210, 0x21, 0x0},
- {0x223, 0x01, 0x0},
- };
- int retval = 0;
-
- retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
- if (0 != retval) {
- /* pmic communication fails */
- pr_debug("sst: pmic commn failed\n");
- return retval;
- }
-
- pr_debug("sst: Playback configuration complete!!\n");
- return 0;
-}
-
static int mx_enable_audiodac(int value)
{
struct sc_reg_access sc_access[3];
@@ -204,7 +156,7 @@ static int mx_enable_audiodac(int value)
retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
if (retval)
return retval;
- pr_debug("sst: mute status = %d", snd_pmic_ops_mx.mute_status);
+ pr_debug("mute status = %d\n", snd_pmic_ops_mx.mute_status);
if (snd_pmic_ops_mx.mute_status == MUTE ||
snd_pmic_ops_mx.master_mute == MUTE)
return retval;
@@ -412,7 +364,7 @@ static int mx_set_pcm_voice_params(void)
if (retval)
return retval;
}
- pr_debug("sst: SST DBG mx_set_pcm_voice_params called\n");
+ pr_debug("SST DBG:mx_set_pcm_voice_params called\n");
return sst_sc_reg_access(sc_access, PMIC_WRITE, 44);
}
@@ -529,7 +481,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
return retval;
}
- pr_debug("sst: mx_set_selected_output_dev dev_id:0x%x\n", dev_id);
+ pr_debug("mx_set_selected_output_dev dev_id:0x%x\n", dev_id);
snd_pmic_ops_mx.output_dev_id = dev_id;
switch (dev_id) {
case STEREO_HEADPHONE:
@@ -549,7 +501,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
num_reg = 1;
break;
case RECEIVER:
- pr_debug("sst: RECEIVER Koski selected\n");
+ pr_debug("RECEIVER Koski selected\n");
/* configuration - AS enable, receiver enable */
sc_access[0].reg_addr = 0xFF;
@@ -559,7 +511,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
num_reg = 1;
break;
default:
- pr_err("sst: Not a valid output dev\n");
+ pr_err("Not a valid output dev\n");
return 0;
}
return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg);
@@ -598,7 +550,7 @@ static int mx_set_selected_input_dev(u8 dev_id)
return retval;
}
snd_pmic_ops_mx.input_dev_id = dev_id;
- pr_debug("sst: mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
+ pr_debug("mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
switch (dev_id) {
case AMIC:
@@ -646,7 +598,7 @@ static int mx_set_mute(int dev_id, u8 value)
}
- pr_debug("sst: set_mute dev_id:0x%x , value:%d\n", dev_id, value);
+ pr_debug("set_mute dev_id:0x%x , value:%d\n", dev_id, value);
switch (dev_id) {
case PMIC_SND_DMIC_MUTE:
@@ -760,7 +712,7 @@ static int mx_set_vol(int dev_id, int value)
if (retval)
return retval;
}
- pr_debug("sst: set_vol dev_id:0x%x ,value:%d\n", dev_id, value);
+ pr_debug("set_vol dev_id:0x%x ,value:%d\n", dev_id, value);
switch (dev_id) {
case PMIC_SND_RECEIVER_VOL:
return 0;
@@ -875,7 +827,7 @@ static int mx_get_vol(int dev_id, int *value)
if (retval)
return retval;
*value = -(sc_access.value & mask);
- pr_debug("sst: get volume value extracted %d\n", *value);
+ pr_debug("get volume value extracted %d\n", *value);
return retval;
}
diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c
index 3a7de769842a..e38e89df6e84 100644
--- a/drivers/staging/intel_sst/intelmid_v2_control.c
+++ b/drivers/staging/intel_sst/intelmid_v2_control.c
@@ -26,6 +26,8 @@
* This file contains the control operations of vendor 3
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/pci.h>
#include <linux/file.h>
#include "intel_sst.h"
@@ -120,7 +122,7 @@ static int nc_init_card(void)
snd_pmic_ops_nc.master_mute = UNMUTE;
snd_pmic_ops_nc.mute_status = UNMUTE;
sst_sc_reg_access(sc_access, PMIC_WRITE, 26);
- pr_debug("sst: init complete!!\n");
+ pr_debug("init complete!!\n");
return 0;
}
@@ -169,7 +171,7 @@ static int nc_power_up_pb(unsigned int port)
nc_enable_audiodac(MUTE);
msleep(30);
- pr_debug("sst: powering up pb....\n");
+ pr_debug("powering up pb....\n");
sc_access[0].reg_addr = VAUDIOCNT;
sc_access[0].value = 0x27;
@@ -222,7 +224,7 @@ static int nc_power_up_cp(unsigned int port)
return retval;
- pr_debug("sst: powering up cp....\n");
+ pr_debug("powering up cp....\n");
if (port == 0xFF)
return 0;
@@ -275,7 +277,7 @@ static int nc_power_down(void)
nc_enable_audiodac(MUTE);
- pr_debug("sst: powering dn nc_power_down ....\n");
+ pr_debug("powering dn nc_power_down ....\n");
msleep(30);
@@ -324,7 +326,7 @@ static int nc_power_down_pb(void)
if (retval)
return retval;
- pr_debug("sst: powering dn pb....\n");
+ pr_debug("powering dn pb....\n");
nc_enable_audiodac(MUTE);
@@ -370,7 +372,7 @@ static int nc_power_down_cp(void)
if (retval)
return retval;
- pr_debug("sst: powering dn cp....\n");
+ pr_debug("powering dn cp....\n");
return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
}
@@ -400,7 +402,7 @@ static int nc_set_pcm_voice_params(void)
return retval;
sst_sc_reg_access(sc_access, PMIC_WRITE, 14);
- pr_debug("sst: Voice parameters set successfully!!\n");
+ pr_debug("Voice parameters set successfully!!\n");
return 0;
}
@@ -451,20 +453,20 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
sc_access.value = 0x07;
sc_access.reg_addr = RMUTE;
- pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_access.value);
+ pr_debug("RIGHT_HP_MUTE value%d\n", sc_access.value);
sc_access.mask = MASK2;
sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
} else {
sc_access.value = 0x00;
sc_access.reg_addr = RMUTE;
- pr_debug("sst: RIGHT_HP_MUTE value %d\n", sc_access.value);
+ pr_debug("RIGHT_HP_MUTE value %d\n", sc_access.value);
sc_access.mask = MASK2;
sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
}
- pr_debug("sst: word_size = %d\n", word_size);
+ pr_debug("word_size = %d\n", word_size);
if (word_size == 24) {
sc_access.reg_addr = AUDIOPORT2;
@@ -477,7 +479,7 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
}
sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
- pr_debug("sst: word_size = %d\n", word_size);
+ pr_debug("word_size = %d\n", word_size);
sc_access.reg_addr = AUDIOPORT1;
sc_access.mask = MASK5|MASK4|MASK1|MASK0;
if (word_size == 16)
@@ -508,7 +510,7 @@ static int nc_set_selected_output_dev(u8 value)
retval = nc_init_card();
if (retval)
return retval;
- pr_debug("sst: nc set selected output:%d\n", value);
+ pr_debug("nc set selected output:%d\n", value);
switch (value) {
case STEREO_HEADPHONE:
retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2);
@@ -517,7 +519,7 @@ static int nc_set_selected_output_dev(u8 value)
retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2);
break;
default:
- pr_err("sst: rcvd illegal request: %d\n", value);
+ pr_err("rcvd illegal request: %d\n", value);
return -EINVAL;
}
return retval;
@@ -541,7 +543,7 @@ static int nc_audio_init(void)
};
sst_sc_reg_access(sc_access, PMIC_WRITE, 12);
- pr_debug("sst: Audio Init successfully!!\n");
+ pr_debug("Audio Init successfully!!\n");
/*set output device */
nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id);
@@ -549,13 +551,13 @@ static int nc_audio_init(void)
if (snd_pmic_ops_nc.num_channel == 1) {
sc_acces.value = 0x07;
sc_acces.reg_addr = RMUTE;
- pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+ pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value);
sc_acces.mask = MASK2;
sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
} else {
sc_acces.value = 0x00;
sc_acces.reg_addr = RMUTE;
- pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+ pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value);
sc_acces.mask = MASK2;
sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
}
@@ -629,11 +631,11 @@ static int nc_set_mute(int dev_id, u8 value)
if (retval)
return retval;
- pr_debug("sst: set device id::%d, value %d\n", dev_id, value);
+ pr_debug("set device id::%d, value %d\n", dev_id, value);
switch (dev_id) {
case PMIC_SND_MUTE_ALL:
- pr_debug("sst: PMIC_SND_MUTE_ALL value %d\n", value);
+ pr_debug("PMIC_SND_MUTE_ALL value %d\n", value);
snd_pmic_ops_nc.mute_status = value;
snd_pmic_ops_nc.master_mute = value;
if (value == UNMUTE) {
@@ -669,7 +671,7 @@ static int nc_set_mute(int dev_id, u8 value)
}
break;
case PMIC_SND_HP_MIC_MUTE:
- pr_debug("sst: PMIC_SND_HPMIC_MUTE value %d\n", value);
+ pr_debug("PMIC_SND_HPMIC_MUTE value %d\n", value);
if (value == UNMUTE) {
/* unmute the system, set the 6th bit to one */
sc_access[0].value = 0x00;
@@ -682,7 +684,7 @@ static int nc_set_mute(int dev_id, u8 value)
retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
break;
case PMIC_SND_AMIC_MUTE:
- pr_debug("sst: PMIC_SND_AMIC_MUTE value %d\n", value);
+ pr_debug("PMIC_SND_AMIC_MUTE value %d\n", value);
if (value == UNMUTE) {
/* unmute the system, set the 6th bit to one */
sc_access[0].value = 0x00;
@@ -696,7 +698,7 @@ static int nc_set_mute(int dev_id, u8 value)
break;
case PMIC_SND_DMIC_MUTE:
- pr_debug("sst: INPUT_MUTE_DMIC value%d\n", value);
+ pr_debug("INPUT_MUTE_DMIC value%d\n", value);
if (value == UNMUTE) {
/* unmute the system, set the 6th bit to one */
sc_access[1].value = 0x00;
@@ -724,13 +726,13 @@ static int nc_set_mute(int dev_id, u8 value)
if (dev_id == PMIC_SND_LEFT_HP_MUTE) {
sc_access[0].reg_addr = LMUTE;
- pr_debug("sst: LEFT_HP_MUTE value %d\n",
+ pr_debug("LEFT_HP_MUTE value %d\n",
sc_access[0].value);
} else {
if (snd_pmic_ops_nc.num_channel == 1)
sc_access[0].value = 0x04;
sc_access[0].reg_addr = RMUTE;
- pr_debug("sst: RIGHT_HP_MUTE value %d\n",
+ pr_debug("RIGHT_HP_MUTE value %d\n",
sc_access[0].value);
}
sc_access[0].mask = MASK2;
@@ -743,7 +745,7 @@ static int nc_set_mute(int dev_id, u8 value)
else
sc_access[0].value = 0x03;
sc_access[0].reg_addr = LMUTE;
- pr_debug("sst: SPEAKER_MUTE %d\n", sc_access[0].value);
+ pr_debug("SPEAKER_MUTE %d\n", sc_access[0].value);
sc_access[0].mask = MASK1;
retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
break;
@@ -764,10 +766,10 @@ static int nc_set_vol(int dev_id, int value)
if (retval)
return retval;
- pr_debug("sst: set volume:%d\n", dev_id);
+ pr_debug("set volume:%d\n", dev_id);
switch (dev_id) {
case PMIC_SND_CAPTURE_VOL:
- pr_debug("sst: PMIC_SND_CAPTURE_VOL:value::%d\n", value);
+ pr_debug("PMIC_SND_CAPTURE_VOL:value::%d\n", value);
sc_access[0].value = sc_access[1].value =
sc_access[2].value = -value;
sc_access[0].mask = sc_access[1].mask = sc_access[2].mask =
@@ -779,7 +781,7 @@ static int nc_set_vol(int dev_id, int value)
break;
case PMIC_SND_LEFT_PB_VOL:
- pr_debug("sst: PMIC_SND_LEFT_HP_VOL %d\n", value);
+ pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value);
sc_access[0].value = -value;
sc_access[0].reg_addr = AUDIOLVOL;
sc_access[0].mask =
@@ -788,7 +790,7 @@ static int nc_set_vol(int dev_id, int value)
break;
case PMIC_SND_RIGHT_PB_VOL:
- pr_debug("sst: PMIC_SND_RIGHT_HP_VOL value %d\n", value);
+ pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value);
if (snd_pmic_ops_nc.num_channel == 1) {
sc_access[0].value = 0x04;
sc_access[0].reg_addr = RMUTE;
@@ -821,11 +823,11 @@ static int nc_set_selected_input_dev(u8 value)
return retval;
snd_pmic_ops_nc.input_dev_id = value;
- pr_debug("sst: nc set selected input:%d\n", value);
+ pr_debug("nc set selected input:%d\n", value);
switch (value) {
case AMIC:
- pr_debug("sst: Selecting AMIC\n");
+ pr_debug("Selecting AMIC\n");
sc_access[0].reg_addr = 0x107;
sc_access[0].value = 0x40;
sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
@@ -842,7 +844,7 @@ static int nc_set_selected_input_dev(u8 value)
break;
case HS_MIC:
- pr_debug("sst: Selecting HS_MIC\n");
+ pr_debug("Selecting HS_MIC\n");
sc_access[0].reg_addr = 0x107;
sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
sc_access[0].value = 0x10;
@@ -859,7 +861,7 @@ static int nc_set_selected_input_dev(u8 value)
break;
case DMIC:
- pr_debug("sst: DMIC\n");
+ pr_debug("DMIC\n");
sc_access[0].reg_addr = 0x107;
sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
sc_access[0].value = 0x0B;
@@ -871,7 +873,7 @@ static int nc_set_selected_input_dev(u8 value)
sc_access[2].mask = MASK6;
sc_access[3].reg_addr = 0x109;
sc_access[3].mask = MASK6;
- sc_access[3].value = 0x40;
+ sc_access[3].value = 0x00;
num_val = 4;
break;
default:
@@ -890,23 +892,23 @@ static int nc_get_mute(int dev_id, u8 *value)
if (retval)
return retval;
- pr_debug("sst: get mute::%d\n", dev_id);
+ pr_debug("get mute::%d\n", dev_id);
switch (dev_id) {
case PMIC_SND_AMIC_MUTE:
- pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC1\n");
+ pr_debug("PMIC_SND_INPUT_MUTE_MIC1\n");
sc_access.reg_addr = LILSEL;
mask = MASK6;
break;
case PMIC_SND_HP_MIC_MUTE:
- pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC2\n");
+ pr_debug("PMIC_SND_INPUT_MUTE_MIC2\n");
sc_access.reg_addr = LIRSEL;
mask = MASK6;
break;
case PMIC_SND_LEFT_HP_MUTE:
case PMIC_SND_RIGHT_HP_MUTE:
mask = MASK2;
- pr_debug("sst: PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
+ pr_debug("PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
if (dev_id == PMIC_SND_RIGHT_HP_MUTE)
sc_access.reg_addr = RMUTE;
else
@@ -914,12 +916,12 @@ static int nc_get_mute(int dev_id, u8 *value)
break;
case PMIC_SND_LEFT_SPEAKER_MUTE:
- pr_debug("sst: PMIC_MONO_EARPIECE_MUTE\n");
+ pr_debug("PMIC_MONO_EARPIECE_MUTE\n");
sc_access.reg_addr = RMUTE;
mask = MASK1;
break;
case PMIC_SND_DMIC_MUTE:
- pr_debug("sst: PMIC_SND_INPUT_MUTE_DMIC\n");
+ pr_debug("PMIC_SND_INPUT_MUTE_DMIC\n");
sc_access.reg_addr = 0x105;
mask = MASK6;
break;
@@ -928,16 +930,16 @@ static int nc_get_mute(int dev_id, u8 *value)
}
retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
- pr_debug("sst: reg value = %d\n", sc_access.value);
+ pr_debug("reg value = %d\n", sc_access.value);
if (retval)
return retval;
*value = (sc_access.value) & mask;
- pr_debug("sst: masked value = %d\n", *value);
+ pr_debug("masked value = %d\n", *value);
if (*value)
*value = 0;
else
*value = 1;
- pr_debug("sst: value returned = 0x%x\n", *value);
+ pr_debug("value returned = 0x%x\n", *value);
return retval;
}
@@ -953,19 +955,19 @@ static int nc_get_vol(int dev_id, int *value)
switch (dev_id) {
case PMIC_SND_CAPTURE_VOL:
- pr_debug("sst: PMIC_SND_INPUT_CAPTURE_VOL\n");
+ pr_debug("PMIC_SND_INPUT_CAPTURE_VOL\n");
sc_access.reg_addr = LILSEL;
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
break;
case PMIC_SND_RIGHT_PB_VOL:
- pr_debug("sst: GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+ pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n");
sc_access.reg_addr = AUDIOLVOL;
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
break;
case PMIC_SND_LEFT_PB_VOL:
- pr_debug("sst: GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+ pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
sc_access.reg_addr = AUDIORVOL;
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
break;
@@ -975,9 +977,9 @@ static int nc_get_vol(int dev_id, int *value)
}
retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
- pr_debug("sst: value read = 0x%x\n", sc_access.value);
+ pr_debug("value read = 0x%x\n", sc_access.value);
*value = -((sc_access.value) & mask);
- pr_debug("sst: get vol value returned = %d\n", *value);
+ pr_debug("get vol value returned = %d\n", *value);
return retval;
}
diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c
index 1934805844f2..515e448852a0 100644
--- a/drivers/staging/keucr/init.c
+++ b/drivers/staging/keucr/init.c
@@ -11,43 +11,37 @@
#include "transport.h"
#include "init.h"
-BYTE IsSSFDCCompliance;
-BYTE IsXDCompliance;
-extern DWORD MediaChange;
-extern int Check_D_MediaFmt(struct us_data *);
+BYTE IsSSFDCCompliance;
+BYTE IsXDCompliance;
-//----- ENE_InitMedia() ----------------------------------------
+/*
+ * ENE_InitMedia():
+ */
int ENE_InitMedia(struct us_data *us)
{
int result;
BYTE MiscReg03 = 0;
- printk("--- Initial Nedia ---\n");
+ printk(KERN_INFO "--- Init Media ---\n");
result = ENE_Read_BYTE(us, REG_CARD_STATUS, &MiscReg03);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Read register fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Read register fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- printk("MiscReg03 = %x\n", MiscReg03);
+ printk(KERN_INFO "MiscReg03 = %x\n", MiscReg03);
- if (MiscReg03 & 0x01)
- {
- if (!us->SD_Status.Ready)
- {
+ if (MiscReg03 & 0x01) {
+ if (!us->SD_Status.Ready) {
result = ENE_SDInit(us);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
}
}
- if (MiscReg03 & 0x02)
- {
- if (!us->SM_Status.Ready && !us->MS_Status.Ready)
- {
+ if (MiscReg03 & 0x02) {
+ if (!us->SM_Status.Ready && !us->MS_Status.Ready) {
result = ENE_SMInit(us);
- if (result != USB_STOR_XFER_GOOD)
- {
+ if (result != USB_STOR_XFER_GOOD) {
result = ENE_MSInit(us);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -58,13 +52,15 @@ int ENE_InitMedia(struct us_data *us)
return result;
}
-//----- ENE_Read_BYTE() ----------------------------------------
+/*
+ * ENE_Read_BYTE() :
+ */
int ENE_Read_BYTE(struct us_data *us, WORD index, void *buf)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x01;
bcb->Flags = 0x80;
@@ -76,92 +72,87 @@ int ENE_Read_BYTE(struct us_data *us, WORD index, void *buf)
return result;
}
-//----- ENE_SDInit() ---------------------
+/*
+ * ENE_SDInit():
+ */
int ENE_SDInit(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
BYTE buf[0x200];
- printk("transport --- ENE_SDInit\n");
- // SD Init Part-1
+ printk(KERN_INFO "transport --- ENE_SDInit\n");
+ /* SD Init Part-1 */
result = ENE_LoadBinCode(us, SD_INIT1_PATTERN);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Load SD Init Code Part-1 Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Load SD Init Code Part-1 Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF2;
result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Exection SD Init Code Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Exection SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- // SD Init Part-2
+ /* SD Init Part-2 */
result = ENE_LoadBinCode(us, SD_INIT2_PATTERN);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Load SD Init Code Part-2 Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Load SD Init Code Part-2 Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Exection SD Init Code Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Exection SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
us->SD_Status = *(PSD_STATUS)&buf[0];
- if (us->SD_Status.Insert && us->SD_Status.Ready)
- {
+ if (us->SD_Status.Insert && us->SD_Status.Ready) {
ENE_ReadSDReg(us, (PBYTE)&buf);
- printk("Insert = %x\n", us->SD_Status.Insert);
- printk("Ready = %x\n", us->SD_Status.Ready);
- printk("IsMMC = %x\n", us->SD_Status.IsMMC);
- printk("HiCapacity = %x\n", us->SD_Status.HiCapacity);
- printk("HiSpeed = %x\n", us->SD_Status.HiSpeed);
- printk("WtP = %x\n", us->SD_Status.WtP);
- }
- else
- {
- printk("SD Card Not Ready --- %x\n", buf[0]);
+ printk(KERN_INFO "Insert = %x\n", us->SD_Status.Insert);
+ printk(KERN_INFO "Ready = %x\n", us->SD_Status.Ready);
+ printk(KERN_INFO "IsMMC = %x\n", us->SD_Status.IsMMC);
+ printk(KERN_INFO "HiCapacity = %x\n", us->SD_Status.HiCapacity);
+ printk(KERN_INFO "HiSpeed = %x\n", us->SD_Status.HiSpeed);
+ printk(KERN_INFO "WtP = %x\n", us->SD_Status.WtP);
+ } else {
+ printk(KERN_ERR "SD Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_MSInit() ----------------------------------------
+/*
+ * ENE_MSInit():
+ */
int ENE_MSInit(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
BYTE buf[0x200];
WORD MSP_BlockSize, MSP_UserAreaBlocks;
-
- printk("transport --- ENE_MSInit\n");
+ printk(KERN_INFO "transport --- ENE_MSInit\n");
result = ENE_LoadBinCode(us, MS_INIT_PATTERN);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Load MS Init Code Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Load MS Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -169,57 +160,53 @@ int ENE_MSInit(struct us_data *us)
bcb->CDB[1] = 0x01;
result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Exection MS Init Code Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Exection MS Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
us->MS_Status = *(PMS_STATUS)&buf[0];
- if (us->MS_Status.Insert && us->MS_Status.Ready)
- {
- printk("Insert = %x\n", us->MS_Status.Insert);
- printk("Ready = %x\n", us->MS_Status.Ready);
- printk("IsMSPro = %x\n", us->MS_Status.IsMSPro);
- printk("IsMSPHG = %x\n", us->MS_Status.IsMSPHG);
- printk("WtP = %x\n", us->MS_Status.WtP);
- if (us->MS_Status.IsMSPro)
- {
- MSP_BlockSize = (buf[6] <<8) | buf[7];
- MSP_UserAreaBlocks = (buf[10]<<8) | buf[11];
+ if (us->MS_Status.Insert && us->MS_Status.Ready) {
+ printk(KERN_INFO "Insert = %x\n", us->MS_Status.Insert);
+ printk(KERN_INFO "Ready = %x\n", us->MS_Status.Ready);
+ printk(KERN_INFO "IsMSPro = %x\n", us->MS_Status.IsMSPro);
+ printk(KERN_INFO "IsMSPHG = %x\n", us->MS_Status.IsMSPHG);
+ printk(KERN_INFO "WtP = %x\n", us->MS_Status.WtP);
+ if (us->MS_Status.IsMSPro) {
+ MSP_BlockSize = (buf[6] << 8) | buf[7];
+ MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
us->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
- }
- else
+ } else {
MS_CardInit(us);
- printk("MS Init Code OK !!\n");
- }
- else
- {
- printk("MS Card Not Ready --- %x\n", buf[0]);
+ }
+ printk(KERN_INFO "MS Init Code OK !!\n");
+ } else {
+ printk(KERN_INFO "MS Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_SMInit() ----------------------------------------
+/*
+ *ENE_SMInit()
+ */
int ENE_SMInit(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
BYTE buf[0x200];
- printk("transport --- ENE_SMInit\n");
+ printk(KERN_INFO "transport --- ENE_SMInit\n");
result = ENE_LoadBinCode(us, SM_INIT_PATTERN);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Load SM Init Code Fail !!\n");
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_INFO "Load SM Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -227,9 +214,9 @@ int ENE_SMInit(struct us_data *us)
bcb->CDB[1] = 0x01;
result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("Exection SM Init Code Fail !! result = %x\n", result);
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR
+ "Exection SM Init Code Fail !! result = %x\n", result);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -238,32 +225,31 @@ int ENE_SMInit(struct us_data *us)
us->SM_DeviceID = buf[1];
us->SM_CardID = buf[2];
- if (us->SM_Status.Insert && us->SM_Status.Ready)
- {
- printk("Insert = %x\n", us->SM_Status.Insert);
- printk("Ready = %x\n", us->SM_Status.Ready);
- printk("WtP = %x\n", us->SM_Status.WtP);
- printk("DeviceID = %x\n", us->SM_DeviceID);
- printk("CardID = %x\n", us->SM_CardID);
+ if (us->SM_Status.Insert && us->SM_Status.Ready) {
+ printk(KERN_INFO "Insert = %x\n", us->SM_Status.Insert);
+ printk(KERN_INFO "Ready = %x\n", us->SM_Status.Ready);
+ printk(KERN_INFO "WtP = %x\n", us->SM_Status.WtP);
+ printk(KERN_INFO "DeviceID = %x\n", us->SM_DeviceID);
+ printk(KERN_INFO "CardID = %x\n", us->SM_CardID);
MediaChange = 1;
Check_D_MediaFmt(us);
- }
- else
- {
- printk("SM Card Not Ready --- %x\n", buf[0]);
+ } else {
+ printk(KERN_ERR "SM Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_ReadSDReg() ----------------------------------------------
+/*
+ * ENE_ReadSDReg()
+ */
int ENE_ReadSDReg(struct us_data *us, u8 *RdBuf)
{
WORD tmpreg;
DWORD reg4b;
-
- //printk("transport --- ENE_ReadSDReg\n");
+
+ /* printk(KERN_INFO "transport --- ENE_ReadSDReg\n"); */
reg4b = *(PDWORD)&RdBuf[0x18];
us->SD_READ_BL_LEN = (BYTE)((reg4b >> 8) & 0x0f);
@@ -277,74 +263,75 @@ int ENE_ReadSDReg(struct us_data *us, u8 *RdBuf)
if (us->SD_Status.HiCapacity && us->SD_Status.IsMMC)
us->HC_C_SIZE = *(PDWORD)(&RdBuf[0x100]);
- if (us->SD_READ_BL_LEN > SD_BLOCK_LEN)
- {
- us->SD_Block_Mult = 1 << (us->SD_READ_BL_LEN - SD_BLOCK_LEN); us->SD_READ_BL_LEN = SD_BLOCK_LEN;
- }
- else
- { us->SD_Block_Mult = 1;
+ if (us->SD_READ_BL_LEN > SD_BLOCK_LEN) {
+ us->SD_Block_Mult =
+ 1 << (us->SD_READ_BL_LEN - SD_BLOCK_LEN);
+ us->SD_READ_BL_LEN = SD_BLOCK_LEN;
+ } else {
+ us->SD_Block_Mult = 1;
}
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_LoadBinCode() ---------------------
+/*
+ * ENE_LoadBinCode()
+ */
int ENE_LoadBinCode(struct us_data *us, BYTE flag)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- //void *buf;
+ /* void *buf; */
PBYTE buf;
- //printk("transport --- ENE_LoadBinCode\n");
+ /* printk(KERN_INFO "transport --- ENE_LoadBinCode\n"); */
if (us->BIN_FLAG == flag)
return USB_STOR_TRANSPORT_GOOD;
buf = kmalloc(0x800, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
- switch ( flag )
- {
- // For SD
- case SD_INIT1_PATTERN:
- printk("SD_INIT1_PATTERN\n");
- memcpy(buf, SD_Init1, 0x800);
+ switch (flag) {
+ /* For SD */
+ case SD_INIT1_PATTERN:
+ printk(KERN_INFO "SD_INIT1_PATTERN\n");
+ memcpy(buf, SD_Init1, 0x800);
break;
- case SD_INIT2_PATTERN:
- printk("SD_INIT2_PATTERN\n");
- memcpy(buf, SD_Init2, 0x800);
+ case SD_INIT2_PATTERN:
+ printk(KERN_INFO "SD_INIT2_PATTERN\n");
+ memcpy(buf, SD_Init2, 0x800);
break;
- case SD_RW_PATTERN:
- printk("SD_RW_PATTERN\n");
- memcpy(buf, SD_Rdwr, 0x800);
+ case SD_RW_PATTERN:
+ printk(KERN_INFO "SD_RW_PATTERN\n");
+ memcpy(buf, SD_Rdwr, 0x800);
break;
- // For MS
- case MS_INIT_PATTERN:
- printk("MS_INIT_PATTERN\n");
- memcpy(buf, MS_Init, 0x800);
+ /* For MS */
+ case MS_INIT_PATTERN:
+ printk(KERN_INFO "MS_INIT_PATTERN\n");
+ memcpy(buf, MS_Init, 0x800);
break;
- case MSP_RW_PATTERN:
- printk("MSP_RW_PATTERN\n");
- memcpy(buf, MSP_Rdwr, 0x800);
+ case MSP_RW_PATTERN:
+ printk(KERN_INFO "MSP_RW_PATTERN\n");
+ memcpy(buf, MSP_Rdwr, 0x800);
break;
- case MS_RW_PATTERN:
- printk("MS_RW_PATTERN\n");
- memcpy(buf, MS_Rdwr, 0x800);
+ case MS_RW_PATTERN:
+ printk(KERN_INFO "MS_RW_PATTERN\n");
+ memcpy(buf, MS_Rdwr, 0x800);
break;
- // For SS
- case SM_INIT_PATTERN:
- printk("SM_INIT_PATTERN\n");
- memcpy(buf, SM_Init, 0x800);
+ /* For SS */
+ case SM_INIT_PATTERN:
+ printk(KERN_INFO "SM_INIT_PATTERN\n");
+ memcpy(buf, SM_Init, 0x800);
break;
- case SM_RW_PATTERN:
- printk("SM_RW_PATTERN\n");
- memcpy(buf, SM_Rdwr, 0x800);
+ case SM_RW_PATTERN:
+ printk(KERN_INFO "SM_RW_PATTERN\n");
+ memcpy(buf, SM_Rdwr, 0x800);
break;
}
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x800;
- bcb->Flags =0x00;
+ bcb->Flags = 0x00;
bcb->CDB[0] = 0xEF;
result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
@@ -354,54 +341,63 @@ int ENE_LoadBinCode(struct us_data *us, BYTE flag)
return result;
}
-//----- ENE_SendScsiCmd() ---------------------
+/*
+ * ENE_SendScsiCmd():
+ */
int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
- unsigned int transfer_length=bcb->DataTransferLength, cswlen=0, partial=0;
+ unsigned int transfer_length = bcb->DataTransferLength,
+ cswlen = 0, partial = 0;
unsigned int residue;
- //printk("transport --- ENE_SendScsiCmd\n");
- // send cmd to out endpoint
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("send cmd to out endpoint fail ---\n");
+ /* printk(KERN_INFO "transport --- ENE_SendScsiCmd\n"); */
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, US_BULK_CB_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "send cmd to out endpoint fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
- if (buf)
- {
- unsigned int pipe = fDir == FDIR_READ ? us->recv_bulk_pipe : us->send_bulk_pipe;
- // Bulk
+ if (buf) {
+ unsigned int pipe = fDir;
+
+ if (fDir == FDIR_READ)
+ pipe = us->recv_bulk_pipe;
+ else
+ pipe = us->send_bulk_pipe;
+
+ /* Bulk */
if (use_sg)
result = usb_stor_bulk_srb(us, pipe, us->srb);
else
- result = usb_stor_bulk_transfer_sg(us, pipe, buf, transfer_length, 0, &partial);
- if (result != USB_STOR_XFER_GOOD)
- {
- printk("data transfer fail ---\n");
+ result = usb_stor_bulk_transfer_sg(us, pipe, buf,
+ transfer_length, 0, &partial);
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "data transfer fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
}
- // Get CSW for device status
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen);
- if (result == USB_STOR_XFER_SHORT && cswlen == 0)
- {
- printk("Received 0-length CSW; retrying...\n");
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+ printk(KERN_WARNING "Received 0-length CSW; retrying...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
- if (result == USB_STOR_XFER_STALLED)
- {
+ if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
- printk("Attempting to get CSW (2nd try)...\n");
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL);
+ printk(KERN_WARNING "Attempting to get CSW (2nd try)...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, NULL);
}
if (result != USB_STOR_XFER_GOOD)
@@ -410,12 +406,14 @@ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg)
/* check bulk status */
residue = le32_to_cpu(bcs->Residue);
- /* try to compute the actual residue, based on how much data
- * was really transferred and what the device tells us */
- if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE))
- {
+ /*
+ * try to compute the actual residue, based on how much data
+ * was really transferred and what the device tells us
+ */
+ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
residue = min(residue, transfer_length);
- scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), (int) residue));
+ scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
+ (int) residue));
}
if (bcs->Status != US_BULK_STAT_OK)
@@ -424,35 +422,40 @@ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg)
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_Read_Data() ---------------------
+/*
+ * ENE_Read_Data()
+ */
int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
- //printk("transport --- ENE_Read_Data\n");
- // set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ /* printk(KERN_INFO "transport --- ENE_Read_Data\n"); */
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = length;
- bcb->Flags =0x80;
+ bcb->Flags = 0x80;
bcb->CDB[0] = 0xED;
bcb->CDB[2] = 0xFF;
bcb->CDB[3] = 0x81;
- // send cmd to out endpoint
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL);
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+ US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- // R/W data
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, buf, length, NULL);
+ /* R/W data */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ buf, length, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- // Get CSW for device status
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL);
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (bcs->Status != US_BULK_STAT_OK)
@@ -461,35 +464,40 @@ int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length)
return USB_STOR_TRANSPORT_GOOD;
}
-//----- ENE_Write_Data() ---------------------
+/*
+ * ENE_Write_Data():
+ */
int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
- //printk("transport --- ENE_Write_Data\n");
- // set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ /* printk("transport --- ENE_Write_Data\n"); */
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = length;
- bcb->Flags =0x00;
+ bcb->Flags = 0x00;
bcb->CDB[0] = 0xEE;
bcb->CDB[2] = 0xFF;
bcb->CDB[3] = 0x81;
- // send cmd to out endpoint
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL);
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+ US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- // R/W data
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, buf, length, NULL);
+ /* R/W data */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ buf, length, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- // Get CSW for device status
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL);
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (bcs->Status != US_BULK_STAT_OK)
@@ -498,42 +506,52 @@ int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length)
return USB_STOR_TRANSPORT_GOOD;
}
-//----- usb_stor_print_cmd() ---------------------
+/*
+ * usb_stor_print_cmd():
+ */
void usb_stor_print_cmd(struct scsi_cmnd *srb)
{
PBYTE Cdb = srb->cmnd;
DWORD cmd = Cdb[0];
- DWORD bn = ((Cdb[2]<<24) & 0xff000000) | ((Cdb[3]<<16) & 0x00ff0000) |
- ((Cdb[4]<< 8) & 0x0000ff00) | ((Cdb[5]<< 0) & 0x000000ff);
- WORD blen = ((Cdb[7]<< 8) & 0xff00) | ((Cdb[8]<< 0) & 0x00ff);
+ DWORD bn = ((Cdb[2] << 24) & 0xff000000) |
+ ((Cdb[3] << 16) & 0x00ff0000) |
+ ((Cdb[4] << 8) & 0x0000ff00) |
+ ((Cdb[5] << 0) & 0x000000ff);
+ WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
switch (cmd) {
case TEST_UNIT_READY:
- //printk("scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd);
+ /* printk(KERN_INFO
+ "scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd); */
break;
case INQUIRY:
- printk("scsi cmd %X --- SCSIOP_INQUIRY\n", cmd);
+ printk(KERN_INFO "scsi cmd %X --- SCSIOP_INQUIRY\n", cmd);
break;
case MODE_SENSE:
- printk("scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd);
+ printk(KERN_INFO "scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd);
break;
case START_STOP:
- printk("scsi cmd %X --- SCSIOP_START_STOP\n", cmd);
+ printk(KERN_INFO "scsi cmd %X --- SCSIOP_START_STOP\n", cmd);
break;
case READ_CAPACITY:
- printk("scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd);
+ printk(KERN_INFO "scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd);
break;
case READ_10:
- //printk("scsi cmd %X --- SCSIOP_READ, bn = %X, blen = %X\n", cmd, bn, blen);
+ /* printk(KERN_INFO
+ "scsi cmd %X --- SCSIOP_READ,bn = %X, blen = %X\n"
+ ,cmd, bn, blen); */
break;
case WRITE_10:
- //printk("scsi cmd %X --- SCSIOP_WRITE, bn = %X, blen = %X\n", cmd, bn, blen);
+ /* printk(KERN_INFO
+ "scsi cmd %X --- SCSIOP_WRITE,
+ bn = %X, blen = %X\n" , cmd, bn, blen); */
break;
case ALLOW_MEDIUM_REMOVAL:
- printk("scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd);
+ printk(KERN_INFO
+ "scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd);
break;
default:
- printk("scsi cmd %X --- Other cmd\n", cmd);
+ printk(KERN_INFO "scsi cmd %X --- Other cmd\n", cmd);
break;
}
bn = 0;
diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h
index cd199fc1e6d5..5223132a6c24 100644
--- a/drivers/staging/keucr/init.h
+++ b/drivers/staging/keucr/init.h
@@ -1,5 +1,8 @@
#include "common.h"
+extern DWORD MediaChange;
+extern int Check_D_MediaFmt(struct us_data *);
+
BYTE SD_Init1[] = {
0x90, 0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90,
0xFF, 0x23, 0x74, 0x80, 0xF0, 0x90, 0xFF, 0x09,
diff --git a/drivers/staging/keucr/ms.c b/drivers/staging/keucr/ms.c
index d4340a9da87d..452ea8f54f67 100644
--- a/drivers/staging/keucr/ms.c
+++ b/drivers/staging/keucr/ms.c
@@ -15,7 +15,7 @@ int MS_ReaderCopyBlock(struct us_data *us, WORD oldphy, WORD newphy, WORD PhyBlo
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*len;
bcb->Flags = 0x00;
@@ -53,7 +53,7 @@ int MS_ReaderReadPage(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, PDWO
return USB_STOR_TRANSPORT_ERROR;
// Read Page Data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -69,7 +69,7 @@ int MS_ReaderReadPage(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, PDWO
return USB_STOR_TRANSPORT_ERROR;
// Read Extra Data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
bcb->Flags = 0x80;
@@ -108,7 +108,7 @@ int MS_ReaderEraseBlock(struct us_data *us, DWORD PhyBlockAddr)
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -347,7 +347,7 @@ int MS_LibProcessBootBlock(struct us_data *us, WORD PhyBlock, BYTE *PageData)
BYTE *PageBuffer;
MS_LibTypeExtdat ExtraData;
- if ((PageBuffer = (BYTE *)kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL))==NULL)
+ if ((PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL))==NULL)
return (DWORD)-1;
result = (DWORD)-1;
@@ -480,8 +480,8 @@ int MS_LibAllocLogicalMap(struct us_data *us)
DWORD i;
- us->MS_Lib.Phy2LogMap = (WORD *)kmalloc(us->MS_Lib.NumberOfPhyBlock * sizeof(WORD), GFP_KERNEL);
- us->MS_Lib.Log2PhyMap = (WORD *)kmalloc(us->MS_Lib.NumberOfLogBlock * sizeof(WORD), GFP_KERNEL);
+ us->MS_Lib.Phy2LogMap = kmalloc(us->MS_Lib.NumberOfPhyBlock * sizeof(WORD), GFP_KERNEL);
+ us->MS_Lib.Log2PhyMap = kmalloc(us->MS_Lib.NumberOfLogBlock * sizeof(WORD), GFP_KERNEL);
if ((us->MS_Lib.Phy2LogMap == NULL) || (us->MS_Lib.Log2PhyMap == NULL))
{
@@ -610,8 +610,8 @@ int MS_LibAllocWriteBuf(struct us_data *us)
{
us->MS_Lib.wrtblk = (WORD)-1;
- us->MS_Lib.blkpag = (BYTE *)kmalloc(us->MS_Lib.PagesPerBlock * us->MS_Lib.BytesPerSector, GFP_KERNEL);
- us->MS_Lib.blkext = (MS_LibTypeExtdat *)kmalloc(us->MS_Lib.PagesPerBlock * sizeof(MS_LibTypeExtdat), GFP_KERNEL);
+ us->MS_Lib.blkpag = kmalloc(us->MS_Lib.PagesPerBlock * us->MS_Lib.BytesPerSector, GFP_KERNEL);
+ us->MS_Lib.blkext = kmalloc(us->MS_Lib.PagesPerBlock * sizeof(MS_LibTypeExtdat), GFP_KERNEL);
if ((us->MS_Lib.blkpag == NULL) || (us->MS_Lib.blkext == NULL))
{
@@ -673,7 +673,7 @@ int MS_LibReadExtraBlock(struct us_data *us, DWORD PhyBlock, BYTE PageNum, BYTE
//printk("MS_LibReadExtraBlock --- PhyBlock = %x, PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen);
// Read Extra Data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4 * blen;
bcb->Flags = 0x80;
@@ -700,7 +700,7 @@ int MS_LibReadExtra(struct us_data *us, DWORD PhyBlock, BYTE PageNum, MS_LibType
BYTE ExtBuf[4];
//printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum);
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
bcb->Flags = 0x80;
@@ -807,7 +807,7 @@ int MS_LibOverwriteExtra(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, B
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
bcb->Flags = 0x80;
diff --git a/drivers/staging/keucr/msscsi.c b/drivers/staging/keucr/msscsi.c
index ad0c5c629935..cb92d25acee0 100644
--- a/drivers/staging/keucr/msscsi.c
+++ b/drivers/staging/keucr/msscsi.c
@@ -145,7 +145,7 @@ int MS_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
}
// set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
bcb->Flags = 0x80;
@@ -193,7 +193,7 @@ int MS_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
blkno = phyblk * 0x20 + PageNum;
// set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200 * len;
bcb->Flags = 0x80;
@@ -250,7 +250,7 @@ int MS_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
}
// set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
bcb->Flags = 0x00;
diff --git a/drivers/staging/keucr/scsiglue.c b/drivers/staging/keucr/scsiglue.c
index a2671404f7ac..da4f42af3838 100644
--- a/drivers/staging/keucr/scsiglue.c
+++ b/drivers/staging/keucr/scsiglue.c
@@ -87,7 +87,7 @@ static int slave_configure(struct scsi_device *sdev)
/* This is always called with scsi_lock(host) held */
//----- queuecommand() ---------------------
-static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
+static int queuecommand_lck(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
@@ -117,6 +117,8 @@ static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
diff --git a/drivers/staging/keucr/sdscsi.c b/drivers/staging/keucr/sdscsi.c
index 6c332f850ebe..d646507a3611 100644
--- a/drivers/staging/keucr/sdscsi.c
+++ b/drivers/staging/keucr/sdscsi.c
@@ -152,7 +152,7 @@ int SD_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
bnByte = bn;
// set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
bcb->Flags = 0x80;
@@ -192,7 +192,7 @@ int SD_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
bnByte = bn;
// set up the command wrapper
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
bcb->Flags = 0x00;
diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c
index bdfbf76f8df9..2cbe9f897eef 100644
--- a/drivers/staging/keucr/smilmain.c
+++ b/drivers/staging/keucr/smilmain.c
@@ -153,9 +153,9 @@ int Media_D_ReadSector(struct us_data *us, DWORD start,WORD count,BYTE *buf)
WORD len, bn;
//if (Check_D_MediaPower()) ; ¦b 6250 don't care
- // return(ErrCode); ;
+ // return(ErrCode);
//if (Check_D_MediaFmt(fdoExt)) ;
- // return(ErrCode); ;
+ // return(ErrCode);
if (Conv_D_MediaAddr(us, start))
return(ErrCode);
diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c
index 844b65988636..ce10cf215f51 100644
--- a/drivers/staging/keucr/smilsub.c
+++ b/drivers/staging/keucr/smilsub.c
@@ -266,7 +266,7 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf,BYTE *redundant)
addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
// Read sect data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -281,7 +281,7 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf,BYTE *redundant)
return USB_STOR_TRANSPORT_ERROR;
// Read redundant
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
@@ -319,7 +319,7 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
// Read sect data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*count;
bcb->Flags = 0x80;
@@ -334,7 +334,7 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
return USB_STOR_TRANSPORT_ERROR;
// Read redundant
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
@@ -536,7 +536,7 @@ int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
WriteAddr = WriteAddr*(WORD)Ssfdc.MaxSectors;
// Write sect data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*count;
bcb->Flags = 0x00;
@@ -754,7 +754,7 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
// Write sect data
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x00;
@@ -763,8 +763,8 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
bcb->CDB[7] = (BYTE)addr;
bcb->CDB[6] = (BYTE)(addr/0x0100);
bcb->CDB[5] = Media.Zone/2;
- bcb->CDB[8] = *(redundant+REDT_ADDR1H);;
- bcb->CDB[9] = *(redundant+REDT_ADDR1L);;
+ bcb->CDB[8] = *(redundant+REDT_ADDR1H);
+ bcb->CDB[9] = *(redundant+REDT_ADDR1L);
result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
if (result != USB_STOR_XFER_GOOD)
@@ -791,7 +791,7 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
addr=(WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
addr=addr*(WORD)Ssfdc.MaxSectors;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
@@ -827,7 +827,7 @@ int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
addr = (WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
@@ -870,7 +870,7 @@ int Ssfdc_D_WriteRedtData(struct us_data *us, BYTE *redundant)
addr = (WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
- memset(bcb, 0, sizeof(bcb));
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
diff --git a/drivers/staging/keucr/transport.c b/drivers/staging/keucr/transport.c
index fd98df643ab0..111160cce441 100644
--- a/drivers/staging/keucr/transport.c
+++ b/drivers/staging/keucr/transport.c
@@ -40,7 +40,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
us->current_urb->error_count = 0;
us->current_urb->status = 0;
-// us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
+ us->current_urb->transfer_flags = 0;
if (us->current_urb->transfer_buffer == us->iobuf)
us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
us->current_urb->transfer_dma = us->iobuf_dma;
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
index 1e3bb1406331..9647154a4923 100644
--- a/drivers/staging/line6/capture.c
+++ b/drivers/staging/line6/capture.c
@@ -147,7 +147,7 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
int frames = fsize / bytes_per_frame;
- if (runtime == 0)
+ if (runtime == NULL)
return;
if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
diff --git a/drivers/staging/line6/control.c b/drivers/staging/line6/control.c
index 040e25ca6d33..67e23b6e2d35 100644
--- a/drivers/staging/line6/control.c
+++ b/drivers/staging/line6/control.c
@@ -266,210 +266,210 @@ VARIAX_PARAM_R(float, mix2);
VARIAX_PARAM_R(float, mix1);
VARIAX_PARAM_R(int, pickup_wiring);
-static DEVICE_ATTR(tweak, S_IWUGO | S_IRUGO, pod_get_tweak, pod_set_tweak);
-static DEVICE_ATTR(wah_position, S_IWUGO | S_IRUGO, pod_get_wah_position,
+static DEVICE_ATTR(tweak, S_IWUSR | S_IRUGO, pod_get_tweak, pod_set_tweak);
+static DEVICE_ATTR(wah_position, S_IWUSR | S_IRUGO, pod_get_wah_position,
pod_set_wah_position);
-static DEVICE_ATTR(compression_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(compression_gain, S_IWUSR | S_IRUGO,
pod_get_compression_gain, pod_set_compression_gain);
-static DEVICE_ATTR(vol_pedal_position, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(vol_pedal_position, S_IWUSR | S_IRUGO,
pod_get_vol_pedal_position, pod_set_vol_pedal_position);
-static DEVICE_ATTR(compression_threshold, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(compression_threshold, S_IWUSR | S_IRUGO,
pod_get_compression_threshold,
pod_set_compression_threshold);
-static DEVICE_ATTR(pan, S_IWUGO | S_IRUGO, pod_get_pan, pod_set_pan);
-static DEVICE_ATTR(amp_model_setup, S_IWUGO | S_IRUGO, pod_get_amp_model_setup,
+static DEVICE_ATTR(pan, S_IWUSR | S_IRUGO, pod_get_pan, pod_set_pan);
+static DEVICE_ATTR(amp_model_setup, S_IWUSR | S_IRUGO, pod_get_amp_model_setup,
pod_set_amp_model_setup);
-static DEVICE_ATTR(amp_model, S_IWUGO | S_IRUGO, pod_get_amp_model,
+static DEVICE_ATTR(amp_model, S_IWUSR | S_IRUGO, pod_get_amp_model,
pod_set_amp_model);
-static DEVICE_ATTR(drive, S_IWUGO | S_IRUGO, pod_get_drive, pod_set_drive);
-static DEVICE_ATTR(bass, S_IWUGO | S_IRUGO, pod_get_bass, pod_set_bass);
-static DEVICE_ATTR(mid, S_IWUGO | S_IRUGO, pod_get_mid, pod_set_mid);
-static DEVICE_ATTR(lowmid, S_IWUGO | S_IRUGO, pod_get_lowmid, pod_set_lowmid);
-static DEVICE_ATTR(treble, S_IWUGO | S_IRUGO, pod_get_treble, pod_set_treble);
-static DEVICE_ATTR(highmid, S_IWUGO | S_IRUGO, pod_get_highmid,
+static DEVICE_ATTR(drive, S_IWUSR | S_IRUGO, pod_get_drive, pod_set_drive);
+static DEVICE_ATTR(bass, S_IWUSR | S_IRUGO, pod_get_bass, pod_set_bass);
+static DEVICE_ATTR(mid, S_IWUSR | S_IRUGO, pod_get_mid, pod_set_mid);
+static DEVICE_ATTR(lowmid, S_IWUSR | S_IRUGO, pod_get_lowmid, pod_set_lowmid);
+static DEVICE_ATTR(treble, S_IWUSR | S_IRUGO, pod_get_treble, pod_set_treble);
+static DEVICE_ATTR(highmid, S_IWUSR | S_IRUGO, pod_get_highmid,
pod_set_highmid);
-static DEVICE_ATTR(chan_vol, S_IWUGO | S_IRUGO, pod_get_chan_vol,
+static DEVICE_ATTR(chan_vol, S_IWUSR | S_IRUGO, pod_get_chan_vol,
pod_set_chan_vol);
-static DEVICE_ATTR(reverb_mix, S_IWUGO | S_IRUGO, pod_get_reverb_mix,
+static DEVICE_ATTR(reverb_mix, S_IWUSR | S_IRUGO, pod_get_reverb_mix,
pod_set_reverb_mix);
-static DEVICE_ATTR(effect_setup, S_IWUGO | S_IRUGO, pod_get_effect_setup,
+static DEVICE_ATTR(effect_setup, S_IWUSR | S_IRUGO, pod_get_effect_setup,
pod_set_effect_setup);
-static DEVICE_ATTR(band_1_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_1_frequency, S_IWUSR | S_IRUGO,
pod_get_band_1_frequency, pod_set_band_1_frequency);
-static DEVICE_ATTR(presence, S_IWUGO | S_IRUGO, pod_get_presence,
+static DEVICE_ATTR(presence, S_IWUSR | S_IRUGO, pod_get_presence,
pod_set_presence);
-static DEVICE_ATTR2(treble__bass, treble, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(treble__bass, treble, S_IWUSR | S_IRUGO,
pod_get_treble__bass, pod_set_treble__bass);
-static DEVICE_ATTR(noise_gate_enable, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(noise_gate_enable, S_IWUSR | S_IRUGO,
pod_get_noise_gate_enable, pod_set_noise_gate_enable);
-static DEVICE_ATTR(gate_threshold, S_IWUGO | S_IRUGO, pod_get_gate_threshold,
+static DEVICE_ATTR(gate_threshold, S_IWUSR | S_IRUGO, pod_get_gate_threshold,
pod_set_gate_threshold);
-static DEVICE_ATTR(gate_decay_time, S_IWUGO | S_IRUGO, pod_get_gate_decay_time,
+static DEVICE_ATTR(gate_decay_time, S_IWUSR | S_IRUGO, pod_get_gate_decay_time,
pod_set_gate_decay_time);
-static DEVICE_ATTR(stomp_enable, S_IWUGO | S_IRUGO, pod_get_stomp_enable,
+static DEVICE_ATTR(stomp_enable, S_IWUSR | S_IRUGO, pod_get_stomp_enable,
pod_set_stomp_enable);
-static DEVICE_ATTR(comp_enable, S_IWUGO | S_IRUGO, pod_get_comp_enable,
+static DEVICE_ATTR(comp_enable, S_IWUSR | S_IRUGO, pod_get_comp_enable,
pod_set_comp_enable);
-static DEVICE_ATTR(stomp_time, S_IWUGO | S_IRUGO, pod_get_stomp_time,
+static DEVICE_ATTR(stomp_time, S_IWUSR | S_IRUGO, pod_get_stomp_time,
pod_set_stomp_time);
-static DEVICE_ATTR(delay_enable, S_IWUGO | S_IRUGO, pod_get_delay_enable,
+static DEVICE_ATTR(delay_enable, S_IWUSR | S_IRUGO, pod_get_delay_enable,
pod_set_delay_enable);
-static DEVICE_ATTR(mod_param_1, S_IWUGO | S_IRUGO, pod_get_mod_param_1,
+static DEVICE_ATTR(mod_param_1, S_IWUSR | S_IRUGO, pod_get_mod_param_1,
pod_set_mod_param_1);
-static DEVICE_ATTR(delay_param_1, S_IWUGO | S_IRUGO, pod_get_delay_param_1,
+static DEVICE_ATTR(delay_param_1, S_IWUSR | S_IRUGO, pod_get_delay_param_1,
pod_set_delay_param_1);
-static DEVICE_ATTR(delay_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_delay_param_1_note_value,
pod_set_delay_param_1_note_value);
-static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUSR | S_IRUGO,
pod_get_band_2_frequency__bass,
pod_set_band_2_frequency__bass);
-static DEVICE_ATTR(delay_param_2, S_IWUGO | S_IRUGO, pod_get_delay_param_2,
+static DEVICE_ATTR(delay_param_2, S_IWUSR | S_IRUGO, pod_get_delay_param_2,
pod_set_delay_param_2);
-static DEVICE_ATTR(delay_volume_mix, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_volume_mix, S_IWUSR | S_IRUGO,
pod_get_delay_volume_mix, pod_set_delay_volume_mix);
-static DEVICE_ATTR(delay_param_3, S_IWUGO | S_IRUGO, pod_get_delay_param_3,
+static DEVICE_ATTR(delay_param_3, S_IWUSR | S_IRUGO, pod_get_delay_param_3,
pod_set_delay_param_3);
-static DEVICE_ATTR(reverb_enable, S_IWUGO | S_IRUGO, pod_get_reverb_enable,
+static DEVICE_ATTR(reverb_enable, S_IWUSR | S_IRUGO, pod_get_reverb_enable,
pod_set_reverb_enable);
-static DEVICE_ATTR(reverb_type, S_IWUGO | S_IRUGO, pod_get_reverb_type,
+static DEVICE_ATTR(reverb_type, S_IWUSR | S_IRUGO, pod_get_reverb_type,
pod_set_reverb_type);
-static DEVICE_ATTR(reverb_decay, S_IWUGO | S_IRUGO, pod_get_reverb_decay,
+static DEVICE_ATTR(reverb_decay, S_IWUSR | S_IRUGO, pod_get_reverb_decay,
pod_set_reverb_decay);
-static DEVICE_ATTR(reverb_tone, S_IWUGO | S_IRUGO, pod_get_reverb_tone,
+static DEVICE_ATTR(reverb_tone, S_IWUSR | S_IRUGO, pod_get_reverb_tone,
pod_set_reverb_tone);
-static DEVICE_ATTR(reverb_pre_delay, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(reverb_pre_delay, S_IWUSR | S_IRUGO,
pod_get_reverb_pre_delay, pod_set_reverb_pre_delay);
-static DEVICE_ATTR(reverb_pre_post, S_IWUGO | S_IRUGO, pod_get_reverb_pre_post,
+static DEVICE_ATTR(reverb_pre_post, S_IWUSR | S_IRUGO, pod_get_reverb_pre_post,
pod_set_reverb_pre_post);
-static DEVICE_ATTR(band_2_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_2_frequency, S_IWUSR | S_IRUGO,
pod_get_band_2_frequency, pod_set_band_2_frequency);
-static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUSR | S_IRUGO,
pod_get_band_3_frequency__bass,
pod_set_band_3_frequency__bass);
-static DEVICE_ATTR(wah_enable, S_IWUGO | S_IRUGO, pod_get_wah_enable,
+static DEVICE_ATTR(wah_enable, S_IWUSR | S_IRUGO, pod_get_wah_enable,
pod_set_wah_enable);
-static DEVICE_ATTR(modulation_lo_cut, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(modulation_lo_cut, S_IWUSR | S_IRUGO,
pod_get_modulation_lo_cut, pod_set_modulation_lo_cut);
-static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUSR | S_IRUGO,
pod_get_delay_reverb_lo_cut, pod_set_delay_reverb_lo_cut);
-static DEVICE_ATTR(volume_pedal_minimum, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(volume_pedal_minimum, S_IWUSR | S_IRUGO,
pod_get_volume_pedal_minimum, pod_set_volume_pedal_minimum);
-static DEVICE_ATTR(eq_pre_post, S_IWUGO | S_IRUGO, pod_get_eq_pre_post,
+static DEVICE_ATTR(eq_pre_post, S_IWUSR | S_IRUGO, pod_get_eq_pre_post,
pod_set_eq_pre_post);
-static DEVICE_ATTR(volume_pre_post, S_IWUGO | S_IRUGO, pod_get_volume_pre_post,
+static DEVICE_ATTR(volume_pre_post, S_IWUSR | S_IRUGO, pod_get_volume_pre_post,
pod_set_volume_pre_post);
-static DEVICE_ATTR(di_model, S_IWUGO | S_IRUGO, pod_get_di_model,
+static DEVICE_ATTR(di_model, S_IWUSR | S_IRUGO, pod_get_di_model,
pod_set_di_model);
-static DEVICE_ATTR(di_delay, S_IWUGO | S_IRUGO, pod_get_di_delay,
+static DEVICE_ATTR(di_delay, S_IWUSR | S_IRUGO, pod_get_di_delay,
pod_set_di_delay);
-static DEVICE_ATTR(mod_enable, S_IWUGO | S_IRUGO, pod_get_mod_enable,
+static DEVICE_ATTR(mod_enable, S_IWUSR | S_IRUGO, pod_get_mod_enable,
pod_set_mod_enable);
-static DEVICE_ATTR(mod_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(mod_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_mod_param_1_note_value,
pod_set_mod_param_1_note_value);
-static DEVICE_ATTR(mod_param_2, S_IWUGO | S_IRUGO, pod_get_mod_param_2,
+static DEVICE_ATTR(mod_param_2, S_IWUSR | S_IRUGO, pod_get_mod_param_2,
pod_set_mod_param_2);
-static DEVICE_ATTR(mod_param_3, S_IWUGO | S_IRUGO, pod_get_mod_param_3,
+static DEVICE_ATTR(mod_param_3, S_IWUSR | S_IRUGO, pod_get_mod_param_3,
pod_set_mod_param_3);
-static DEVICE_ATTR(mod_param_4, S_IWUGO | S_IRUGO, pod_get_mod_param_4,
+static DEVICE_ATTR(mod_param_4, S_IWUSR | S_IRUGO, pod_get_mod_param_4,
pod_set_mod_param_4);
-static DEVICE_ATTR(mod_param_5, S_IWUGO | S_IRUGO, pod_get_mod_param_5,
+static DEVICE_ATTR(mod_param_5, S_IWUSR | S_IRUGO, pod_get_mod_param_5,
pod_set_mod_param_5);
-static DEVICE_ATTR(mod_volume_mix, S_IWUGO | S_IRUGO, pod_get_mod_volume_mix,
+static DEVICE_ATTR(mod_volume_mix, S_IWUSR | S_IRUGO, pod_get_mod_volume_mix,
pod_set_mod_volume_mix);
-static DEVICE_ATTR(mod_pre_post, S_IWUGO | S_IRUGO, pod_get_mod_pre_post,
+static DEVICE_ATTR(mod_pre_post, S_IWUSR | S_IRUGO, pod_get_mod_pre_post,
pod_set_mod_pre_post);
-static DEVICE_ATTR(modulation_model, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(modulation_model, S_IWUSR | S_IRUGO,
pod_get_modulation_model, pod_set_modulation_model);
-static DEVICE_ATTR(band_3_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_3_frequency, S_IWUSR | S_IRUGO,
pod_get_band_3_frequency, pod_set_band_3_frequency);
-static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUSR | S_IRUGO,
pod_get_band_4_frequency__bass,
pod_set_band_4_frequency__bass);
-static DEVICE_ATTR(mod_param_1_double_precision, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(mod_param_1_double_precision, S_IWUSR | S_IRUGO,
pod_get_mod_param_1_double_precision,
pod_set_mod_param_1_double_precision);
-static DEVICE_ATTR(delay_param_1_double_precision, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_param_1_double_precision, S_IWUSR | S_IRUGO,
pod_get_delay_param_1_double_precision,
pod_set_delay_param_1_double_precision);
-static DEVICE_ATTR(eq_enable, S_IWUGO | S_IRUGO, pod_get_eq_enable,
+static DEVICE_ATTR(eq_enable, S_IWUSR | S_IRUGO, pod_get_eq_enable,
pod_set_eq_enable);
-static DEVICE_ATTR(tap, S_IWUGO | S_IRUGO, pod_get_tap, pod_set_tap);
-static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(tap, S_IWUSR | S_IRUGO, pod_get_tap, pod_set_tap);
+static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUSR | S_IRUGO,
pod_get_volume_tweak_pedal_assign,
pod_set_volume_tweak_pedal_assign);
-static DEVICE_ATTR(band_5_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_5_frequency, S_IWUSR | S_IRUGO,
pod_get_band_5_frequency, pod_set_band_5_frequency);
-static DEVICE_ATTR(tuner, S_IWUGO | S_IRUGO, pod_get_tuner, pod_set_tuner);
-static DEVICE_ATTR(mic_selection, S_IWUGO | S_IRUGO, pod_get_mic_selection,
+static DEVICE_ATTR(tuner, S_IWUSR | S_IRUGO, pod_get_tuner, pod_set_tuner);
+static DEVICE_ATTR(mic_selection, S_IWUSR | S_IRUGO, pod_get_mic_selection,
pod_set_mic_selection);
-static DEVICE_ATTR(cabinet_model, S_IWUGO | S_IRUGO, pod_get_cabinet_model,
+static DEVICE_ATTR(cabinet_model, S_IWUSR | S_IRUGO, pod_get_cabinet_model,
pod_set_cabinet_model);
-static DEVICE_ATTR(stomp_model, S_IWUGO | S_IRUGO, pod_get_stomp_model,
+static DEVICE_ATTR(stomp_model, S_IWUSR | S_IRUGO, pod_get_stomp_model,
pod_set_stomp_model);
-static DEVICE_ATTR(roomlevel, S_IWUGO | S_IRUGO, pod_get_roomlevel,
+static DEVICE_ATTR(roomlevel, S_IWUSR | S_IRUGO, pod_get_roomlevel,
pod_set_roomlevel);
-static DEVICE_ATTR(band_4_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_4_frequency, S_IWUSR | S_IRUGO,
pod_get_band_4_frequency, pod_set_band_4_frequency);
-static DEVICE_ATTR(band_6_frequency, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(band_6_frequency, S_IWUSR | S_IRUGO,
pod_get_band_6_frequency, pod_set_band_6_frequency);
-static DEVICE_ATTR(stomp_param_1_note_value, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(stomp_param_1_note_value, S_IWUSR | S_IRUGO,
pod_get_stomp_param_1_note_value,
pod_set_stomp_param_1_note_value);
-static DEVICE_ATTR(stomp_param_2, S_IWUGO | S_IRUGO, pod_get_stomp_param_2,
+static DEVICE_ATTR(stomp_param_2, S_IWUSR | S_IRUGO, pod_get_stomp_param_2,
pod_set_stomp_param_2);
-static DEVICE_ATTR(stomp_param_3, S_IWUGO | S_IRUGO, pod_get_stomp_param_3,
+static DEVICE_ATTR(stomp_param_3, S_IWUSR | S_IRUGO, pod_get_stomp_param_3,
pod_set_stomp_param_3);
-static DEVICE_ATTR(stomp_param_4, S_IWUGO | S_IRUGO, pod_get_stomp_param_4,
+static DEVICE_ATTR(stomp_param_4, S_IWUSR | S_IRUGO, pod_get_stomp_param_4,
pod_set_stomp_param_4);
-static DEVICE_ATTR(stomp_param_5, S_IWUGO | S_IRUGO, pod_get_stomp_param_5,
+static DEVICE_ATTR(stomp_param_5, S_IWUSR | S_IRUGO, pod_get_stomp_param_5,
pod_set_stomp_param_5);
-static DEVICE_ATTR(stomp_param_6, S_IWUGO | S_IRUGO, pod_get_stomp_param_6,
+static DEVICE_ATTR(stomp_param_6, S_IWUSR | S_IRUGO, pod_get_stomp_param_6,
pod_set_stomp_param_6);
-static DEVICE_ATTR(amp_switch_select, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(amp_switch_select, S_IWUSR | S_IRUGO,
pod_get_amp_switch_select, pod_set_amp_switch_select);
-static DEVICE_ATTR(delay_param_4, S_IWUGO | S_IRUGO, pod_get_delay_param_4,
+static DEVICE_ATTR(delay_param_4, S_IWUSR | S_IRUGO, pod_get_delay_param_4,
pod_set_delay_param_4);
-static DEVICE_ATTR(delay_param_5, S_IWUGO | S_IRUGO, pod_get_delay_param_5,
+static DEVICE_ATTR(delay_param_5, S_IWUSR | S_IRUGO, pod_get_delay_param_5,
pod_set_delay_param_5);
-static DEVICE_ATTR(delay_pre_post, S_IWUGO | S_IRUGO, pod_get_delay_pre_post,
+static DEVICE_ATTR(delay_pre_post, S_IWUSR | S_IRUGO, pod_get_delay_pre_post,
pod_set_delay_pre_post);
-static DEVICE_ATTR(delay_model, S_IWUGO | S_IRUGO, pod_get_delay_model,
+static DEVICE_ATTR(delay_model, S_IWUSR | S_IRUGO, pod_get_delay_model,
pod_set_delay_model);
-static DEVICE_ATTR(delay_verb_model, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(delay_verb_model, S_IWUSR | S_IRUGO,
pod_get_delay_verb_model, pod_set_delay_verb_model);
-static DEVICE_ATTR(tempo_msb, S_IWUGO | S_IRUGO, pod_get_tempo_msb,
+static DEVICE_ATTR(tempo_msb, S_IWUSR | S_IRUGO, pod_get_tempo_msb,
pod_set_tempo_msb);
-static DEVICE_ATTR(tempo_lsb, S_IWUGO | S_IRUGO, pod_get_tempo_lsb,
+static DEVICE_ATTR(tempo_lsb, S_IWUSR | S_IRUGO, pod_get_tempo_lsb,
pod_set_tempo_lsb);
-static DEVICE_ATTR(wah_model, S_IWUGO | S_IRUGO, pod_get_wah_model,
+static DEVICE_ATTR(wah_model, S_IWUSR | S_IRUGO, pod_get_wah_model,
pod_set_wah_model);
-static DEVICE_ATTR(bypass_volume, S_IWUGO | S_IRUGO, pod_get_bypass_volume,
+static DEVICE_ATTR(bypass_volume, S_IWUSR | S_IRUGO, pod_get_bypass_volume,
pod_set_bypass_volume);
-static DEVICE_ATTR(fx_loop_on_off, S_IWUGO | S_IRUGO, pod_get_fx_loop_on_off,
+static DEVICE_ATTR(fx_loop_on_off, S_IWUSR | S_IRUGO, pod_get_fx_loop_on_off,
pod_set_fx_loop_on_off);
-static DEVICE_ATTR(tweak_param_select, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(tweak_param_select, S_IWUSR | S_IRUGO,
pod_get_tweak_param_select, pod_set_tweak_param_select);
-static DEVICE_ATTR(amp1_engage, S_IWUGO | S_IRUGO, pod_get_amp1_engage,
+static DEVICE_ATTR(amp1_engage, S_IWUSR | S_IRUGO, pod_get_amp1_engage,
pod_set_amp1_engage);
-static DEVICE_ATTR(band_1_gain, S_IWUGO | S_IRUGO, pod_get_band_1_gain,
+static DEVICE_ATTR(band_1_gain, S_IWUSR | S_IRUGO, pod_get_band_1_gain,
pod_set_band_1_gain);
-static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUSR | S_IRUGO,
pod_get_band_2_gain__bass, pod_set_band_2_gain__bass);
-static DEVICE_ATTR(band_2_gain, S_IWUGO | S_IRUGO, pod_get_band_2_gain,
+static DEVICE_ATTR(band_2_gain, S_IWUSR | S_IRUGO, pod_get_band_2_gain,
pod_set_band_2_gain);
-static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUSR | S_IRUGO,
pod_get_band_3_gain__bass, pod_set_band_3_gain__bass);
-static DEVICE_ATTR(band_3_gain, S_IWUGO | S_IRUGO, pod_get_band_3_gain,
+static DEVICE_ATTR(band_3_gain, S_IWUSR | S_IRUGO, pod_get_band_3_gain,
pod_set_band_3_gain);
-static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUSR | S_IRUGO,
pod_get_band_4_gain__bass, pod_set_band_4_gain__bass);
-static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUSR | S_IRUGO,
pod_get_band_5_gain__bass, pod_set_band_5_gain__bass);
-static DEVICE_ATTR(band_4_gain, S_IWUGO | S_IRUGO, pod_get_band_4_gain,
+static DEVICE_ATTR(band_4_gain, S_IWUSR | S_IRUGO, pod_get_band_4_gain,
pod_set_band_4_gain);
-static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUSR | S_IRUGO,
pod_get_band_6_gain__bass, pod_set_band_6_gain__bass);
static DEVICE_ATTR(body, S_IRUGO, variax_get_body, line6_nop_write);
static DEVICE_ATTR(pickup1_enable, S_IRUGO, variax_get_pickup1_enable,
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 4304dfe6c166..e554a2da643a 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -127,7 +127,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (urb == 0) {
+ if (urb == NULL) {
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM;
}
@@ -137,7 +137,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
transfer_buffer = kmalloc(length, GFP_ATOMIC);
- if (transfer_buffer == 0) {
+ if (transfer_buffer == NULL) {
usb_free_urb(urb);
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM;
@@ -350,9 +350,9 @@ static ssize_t midi_set_midi_mask_receive(struct device *dev,
return count;
}
-static DEVICE_ATTR(midi_mask_transmit, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO,
midi_get_midi_mask_transmit, midi_set_midi_mask_transmit);
-static DEVICE_ATTR(midi_mask_receive, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO,
midi_get_midi_mask_receive, midi_set_midi_mask_receive);
/* MIDI device destructor */
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index e54770e34d2e..b9c55f9eb501 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -79,9 +79,9 @@ static ssize_t pcm_set_impulse_period(struct device *dev,
return count;
}
-static DEVICE_ATTR(impulse_volume, S_IWUGO | S_IRUGO, pcm_get_impulse_volume,
+static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume,
pcm_set_impulse_volume);
-static DEVICE_ATTR(impulse_period, S_IWUGO | S_IRUGO, pcm_get_impulse_period,
+static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
pcm_set_impulse_period);
#endif
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
index 29940fd1671b..10c543836583 100644
--- a/drivers/staging/line6/playback.c
+++ b/drivers/staging/line6/playback.c
@@ -246,7 +246,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
- if (line6pcm->prev_fbuf != 0) {
+ if (line6pcm->prev_fbuf != NULL) {
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (line6pcm->flags & MASK_PCM_IMPULSE) {
create_impulse_test_signal(line6pcm, urb_out,
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
index 22e2cedcacf7..d9b30212585c 100644
--- a/drivers/staging/line6/pod.c
+++ b/drivers/staging/line6/pod.c
@@ -1051,48 +1051,48 @@ POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
#undef GET_SYSTEM_PARAM
/* POD special files: */
-static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel,
+static DEVICE_ATTR(channel, S_IWUSR | S_IRUGO, pod_get_channel,
pod_set_channel);
static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write);
static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
-static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump);
-static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf,
+static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump);
+static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
pod_set_dump_buf);
-static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish);
+static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
line6_nop_write);
-static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
pod_get_midi_postprocess, pod_set_midi_postprocess);
-static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level,
+static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
pod_set_monitor_level);
static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
-static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
pod_set_retrieve_amp_setup);
-static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
pod_set_retrieve_channel);
-static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
pod_set_retrieve_effects_setup);
-static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing,
+static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
pod_set_routing);
static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
line6_nop_write);
-static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
pod_set_store_amp_setup);
-static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
pod_set_store_channel);
-static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read,
+static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
pod_set_store_effects_setup);
-static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq,
+static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
pod_set_tuner_freq);
-static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute,
+static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
pod_set_tuner_mute);
static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
#ifdef CONFIG_LINE6_USB_RAW
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
+static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
#endif
/* control info callback */
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index 6a10b0f9749a..879e6992bbc6 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -154,9 +154,9 @@ static ssize_t toneport_set_led_green(struct device *dev,
return count;
}
-static DEVICE_ATTR(led_red, S_IWUGO | S_IRUGO, line6_nop_read,
+static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read,
+static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_green);
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
index 894eee7f2317..81241cdf1be9 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -549,21 +549,21 @@ static ssize_t variax_set_raw2(struct device *dev,
#endif
/* Variax workbench special files: */
-static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model,
+static DEVICE_ATTR(model, S_IWUSR | S_IRUGO, variax_get_model,
variax_set_model);
-static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume,
+static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO, variax_get_volume,
variax_set_volume);
-static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone);
+static DEVICE_ATTR(tone, S_IWUSR | S_IRUGO, variax_get_tone, variax_set_tone);
static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
-static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active,
+static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active,
variax_set_active);
static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
#ifdef CONFIG_LINE6_USB_RAW
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
-static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2);
+static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
+static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2);
#endif
/*
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
index fa790db75d7e..cdaff5903a8f 100644
--- a/drivers/staging/lirc/Kconfig
+++ b/drivers/staging/lirc/Kconfig
@@ -14,26 +14,19 @@ if LIRC_STAGING
config LIRC_BT829
tristate "BT829 based hardware"
- depends on LIRC_STAGING && PCI
+ depends on LIRC && PCI
help
Driver for the IR interface on BT829-based hardware
-config LIRC_I2C
- tristate "I2C Based IR Receivers"
- depends on LIRC_STAGING && I2C
- help
- Driver for I2C-based IR receivers, such as those commonly
- found onboard Hauppauge PVR-150/250/350 video capture cards
-
config LIRC_IGORPLUGUSB
tristate "Igor Cesko's USB IR Receiver"
- depends on LIRC_STAGING && USB
+ depends on LIRC && USB
help
Driver for Igor Cesko's USB IR Receiver
config LIRC_IMON
tristate "Legacy SoundGraph iMON Receiver and Display"
- depends on LIRC_STAGING && USB
+ depends on LIRC && USB
help
Driver for the original SoundGraph iMON IR Receiver and Display
@@ -41,31 +34,31 @@ config LIRC_IMON
config LIRC_IT87
tristate "ITE IT87XX CIR Port Receiver"
- depends on LIRC_STAGING && PNP
+ depends on LIRC && PNP
help
Driver for the ITE IT87xx IR Receiver
config LIRC_ITE8709
tristate "ITE8709 CIR Port Receiver"
- depends on LIRC_STAGING && PNP
+ depends on LIRC && PNP
help
Driver for the ITE8709 IR Receiver
config LIRC_PARALLEL
tristate "Homebrew Parallel Port Receiver"
- depends on LIRC_STAGING && PARPORT
+ depends on LIRC && PARPORT
help
Driver for Homebrew Parallel Port Receivers
config LIRC_SASEM
tristate "Sasem USB IR Remote"
- depends on LIRC_STAGING && USB
+ depends on LIRC && USB
help
Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
config LIRC_SERIAL
tristate "Homebrew Serial Port Receiver"
- depends on LIRC_STAGING
+ depends on LIRC
help
Driver for Homebrew Serial Port Receivers
@@ -78,19 +71,19 @@ config LIRC_SERIAL_TRANSMITTER
config LIRC_SIR
tristate "Built-in SIR IrDA port"
- depends on LIRC_STAGING
+ depends on LIRC
help
Driver for the SIR IrDA port
config LIRC_TTUSBIR
tristate "Technotrend USB IR Receiver"
- depends on LIRC_STAGING && USB
+ depends on LIRC && USB
help
Driver for the Technotrend USB IR Receiver
config LIRC_ZILOG
tristate "Zilog/Hauppauge IR Transmitter"
- depends on LIRC_STAGING && I2C
+ depends on LIRC && I2C
help
Driver for the Zilog/Hauppauge IR Transmitter, found on
PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile
index 4da1f3397a16..94af218d8373 100644
--- a/drivers/staging/lirc/Makefile
+++ b/drivers/staging/lirc/Makefile
@@ -4,7 +4,6 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
-obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o
obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
obj-$(CONFIG_LIRC_IT87) += lirc_it87.o
diff --git a/drivers/staging/lirc/TODO.lirc_i2c b/drivers/staging/lirc/TODO.lirc_i2c
deleted file mode 100644
index 1f0a6ff65439..000000000000
--- a/drivers/staging/lirc/TODO.lirc_i2c
+++ /dev/null
@@ -1,3 +0,0 @@
-lirc_i2c provides support for some drivers that have already a RC
-driver under drivers/media/video. It should be integrated into those
-drivers, in special with drivers/media/video/ir-kbd-i2c.c.
diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog
new file mode 100644
index 000000000000..6aa312df4018
--- /dev/null
+++ b/drivers/staging/lirc/TODO.lirc_zilog
@@ -0,0 +1,13 @@
+The binding between hdpvr and lirc_zilog is currently disabled,
+due to an OOPS reported a few years ago when both the hdpvr and cx18
+drivers were loaded in his system. More details can be seen at:
+ http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html
+More tests need to be done, in order to fix the reported issue.
+
+There's a conflict between ir-kbd-i2c: Both provide support for RX events.
+Such conflict needs to be fixed, before moving it out of staging.
+
+The way I2C probe works, it will try to register the driver twice, one
+for RX and another for TX. The logic needs to be fixed to avoid such
+issue.
+
diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c
deleted file mode 100644
index 6df2c0e8d721..000000000000
--- a/drivers/staging/lirc/lirc_i2c.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * lirc_i2c.c
- *
- * i2c IR driver for the onboard IR port on many TV tuner cards, including:
- * -Flavors of the Hauppauge PVR-150/250/350
- * -Hauppauge HVR-1300
- * -PixelView (BT878P+W/FM)
- * -KNC ONE TV Station/Anubis Typhoon TView Tuner
- * -Asus TV-Box and Creative/VisionTek BreakOut-Box
- * -Leadtek Winfast PVR2000
- *
- * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- * modified for PixelView (BT878P+W/FM) by
- * Michal Kochanowicz <mkochano@pld.org.pl>
- * Christoph Bartelmus <lirc@bartelmus.de>
- * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
- * Ulrich Mueller <ulrich.mueller42@web.de>
- * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
- * Stefan Jahn <stefan@lkcc.org>
- * modified for inclusion into kernel sources by
- * Jerome Brock <jbrock@users.sourceforge.net>
- * modified for Leadtek Winfast PVR2000 by
- * Thomas Reitmayr (treitmayr@yahoo.com)
- * modified for Hauppauge HVR-1300 by
- * Jan Frey (jfrey@gmx.de)
- *
- * parts are cut&pasted from the old lirc_haup.c driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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/version.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include <media/lirc_dev.h>
-
-struct IR {
- struct lirc_driver l;
- struct i2c_client c;
- int nextkey;
- unsigned char b[3];
- unsigned char bits;
- unsigned char flag;
-};
-
-#define DEVICE_NAME "lirc_i2c"
-
-/* module parameters */
-static int debug; /* debug output */
-static int minor = -1; /* minor number */
-
-#define dprintk(fmt, args...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG DEVICE_NAME ": " fmt, \
- ## args); \
- } while (0)
-
-static int reverse(int data, int bits)
-{
- int i;
- int c;
-
- for (c = 0, i = 0; i < bits; i++)
- c |= ((data & (1<<i)) ? 1 : 0) << (bits-1-i);
-
- return c;
-}
-
-static int add_to_buf_adap(void *data, struct lirc_buffer *buf)
-{
- struct IR *ir = data;
- unsigned char keybuf[4];
-
- keybuf[0] = 0x00;
- i2c_master_send(&ir->c, keybuf, 1);
- /* poll IR chip */
- if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
- dprintk("read error\n");
- return -EIO;
- }
-
- dprintk("key (0x%02x%02x%02x%02x)\n",
- keybuf[0], keybuf[1], keybuf[2], keybuf[3]);
-
- /* key pressed ? */
- if (keybuf[2] == 0xff)
- return -ENODATA;
-
- /* remove repeat bit */
- keybuf[2] &= 0x7f;
- keybuf[3] |= 0x80;
-
- lirc_buffer_write(buf, keybuf);
- return 0;
-}
-
-static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf)
-{
- struct IR *ir = data;
- int rc;
- unsigned char all, mask;
- unsigned char key;
-
- /* compute all valid bits (key code + pressed/release flag) */
- all = ir->bits | ir->flag;
-
- /* save IR writable mask bits */
- mask = i2c_smbus_read_byte(&ir->c) & ~all;
-
- /* send bit mask */
- rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask);
-
- /* receive scan code */
- rc = i2c_smbus_read_byte(&ir->c);
-
- if (rc == -1) {
- dprintk("%s read error\n", ir->c.name);
- return -EIO;
- }
-
- /* drop duplicate polls */
- if (ir->b[0] == (rc & all))
- return -ENODATA;
-
- ir->b[0] = rc & all;
-
- dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits,
- (rc & ir->flag) ? "released" : "pressed");
-
- /* ignore released buttons */
- if (rc & ir->flag)
- return -ENODATA;
-
- /* set valid key code */
- key = rc & ir->bits;
- lirc_buffer_write(buf, &key);
- return 0;
-}
-
-/* common for Hauppauge IR receivers */
-static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf,
- unsigned char *keybuf, int size, int offset)
-{
- struct IR *ir = data;
- __u16 code;
- unsigned char codes[2];
- int ret;
-
- /* poll IR chip */
- ret = i2c_master_recv(&ir->c, keybuf, size);
- if (ret == size) {
- ir->b[0] = keybuf[offset];
- ir->b[1] = keybuf[offset+1];
- ir->b[2] = keybuf[offset+2];
- if (ir->b[0] != 0x00 && ir->b[1] != 0x00)
- dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
- } else {
- dprintk("read error (ret=%d)\n", ret);
- /* keep last successful read buffer */
- }
-
- /* key pressed ? */
- if ((ir->b[0] & 0x80) == 0)
- return -ENODATA;
-
- /* look what we have */
- code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2);
-
- codes[0] = (code >> 8) & 0xff;
- codes[1] = code & 0xff;
-
- /* return it */
- dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]);
- lirc_buffer_write(buf, codes);
- return 0;
-}
-
-/* specific for the Hauppauge PVR150 IR receiver */
-static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf)
-{
- unsigned char keybuf[6];
- /* fetch 6 bytes, first relevant is at offset 3 */
- return add_to_buf_haup_common(data, buf, keybuf, 6, 3);
-}
-
-/* used for all Hauppauge IR receivers but the PVR150 */
-static int add_to_buf_haup(void *data, struct lirc_buffer *buf)
-{
- unsigned char keybuf[3];
- /* fetch 3 bytes, first relevant is at offset 0 */
- return add_to_buf_haup_common(data, buf, keybuf, 3, 0);
-}
-
-
-static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf)
-{
- struct IR *ir = data;
- unsigned char key;
- s32 flags;
- s32 code;
-
- /* poll IR chip */
- flags = i2c_smbus_read_byte_data(&ir->c, 0x10);
- if (-1 == flags) {
- dprintk("read error\n");
- return -ENODATA;
- }
- /* key pressed ? */
- if (0 == (flags & 0x80))
- return -ENODATA;
-
- /* read actual key code */
- code = i2c_smbus_read_byte_data(&ir->c, 0x00);
- if (-1 == code) {
- dprintk("read error\n");
- return -ENODATA;
- }
-
- key = code & 0xFF;
-
- dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF);
-
- /* return it */
- lirc_buffer_write(buf, &key);
- return 0;
-}
-
-static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf)
-{
- struct IR *ir = data;
- unsigned char key;
-
- /* poll IR chip */
- if (1 != i2c_master_recv(&ir->c, &key, 1)) {
- dprintk("read error\n");
- return -1;
- }
- dprintk("key %02x\n", key);
-
- /* return it */
- lirc_buffer_write(buf, &key);
- return 0;
-}
-
-static int add_to_buf_pv951(void *data, struct lirc_buffer *buf)
-{
- struct IR *ir = data;
- unsigned char key;
- unsigned char codes[4];
-
- /* poll IR chip */
- if (1 != i2c_master_recv(&ir->c, &key, 1)) {
- dprintk("read error\n");
- return -ENODATA;
- }
- /* ignore 0xaa */
- if (key == 0xaa)
- return -ENODATA;
- dprintk("key %02x\n", key);
-
- codes[0] = 0x61;
- codes[1] = 0xD6;
- codes[2] = reverse(key, 8);
- codes[3] = (~codes[2])&0xff;
-
- lirc_buffer_write(buf, codes);
- return 0;
-}
-
-static int add_to_buf_knc1(void *data, struct lirc_buffer *buf)
-{
- static unsigned char last_key = 0xFF;
- struct IR *ir = data;
- unsigned char key;
-
- /* poll IR chip */
- if (1 != i2c_master_recv(&ir->c, &key, 1)) {
- dprintk("read error\n");
- return -ENODATA;
- }
-
- /*
- * it seems that 0xFE indicates that a button is still held
- * down, while 0xFF indicates that no button is held
- * down. 0xFE sequences are sometimes interrupted by 0xFF
- */
-
- dprintk("key %02x\n", key);
-
- if (key == 0xFF)
- return -ENODATA;
-
- if (key == 0xFE)
- key = last_key;
-
- last_key = key;
- lirc_buffer_write(buf, &key);
-
- return 0;
-}
-
-static int set_use_inc(void *data)
-{
- struct IR *ir = data;
-
- dprintk("%s called\n", __func__);
-
- /* lock bttv in memory while /dev/lirc is in use */
- i2c_use_client(&ir->c);
-
- return 0;
-}
-
-static void set_use_dec(void *data)
-{
- struct IR *ir = data;
-
- dprintk("%s called\n", __func__);
-
- i2c_release_client(&ir->c);
-}
-
-static struct lirc_driver lirc_template = {
- .name = "lirc_i2c",
- .set_use_inc = set_use_inc,
- .set_use_dec = set_use_dec,
- .dev = NULL,
- .owner = THIS_MODULE,
-};
-
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
-static int ir_remove(struct i2c_client *client);
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
-
-static const struct i2c_device_id ir_receiver_id[] = {
- /* Generic entry for any IR receiver */
- { "ir_video", 0 },
- /* IR device specific entries could be added here */
- { }
-};
-
-static struct i2c_driver driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "i2c ir driver",
- },
- .probe = ir_probe,
- .remove = ir_remove,
- .id_table = ir_receiver_id,
- .command = ir_command,
-};
-
-static void pcf_probe(struct i2c_client *client, struct IR *ir)
-{
- int ret1, ret2, ret3, ret4;
-
- ret1 = i2c_smbus_write_byte(client, 0xff);
- ret2 = i2c_smbus_read_byte(client);
- ret3 = i2c_smbus_write_byte(client, 0x00);
- ret4 = i2c_smbus_read_byte(client);
-
- /* in the Asus TV-Box: bit 1-0 */
- if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) {
- ir->bits = (unsigned char) ~0x07;
- ir->flag = 0x04;
- /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */
- } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) {
- ir->bits = (unsigned char) ~0xe0;
- ir->flag = 0x20;
- }
-
- return;
-}
-
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
- struct IR *ir;
- struct i2c_adapter *adap = client->adapter;
- unsigned short addr = client->addr;
- int retval;
-
- ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
- if (!ir)
- return -ENOMEM;
- memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
- memcpy(&ir->c, client, sizeof(struct i2c_client));
-
- i2c_set_clientdata(client, ir);
- ir->l.data = ir;
- ir->l.minor = minor;
- ir->l.sample_rate = 10;
- ir->l.dev = &ir->c.dev;
- ir->nextkey = -1;
-
- switch (addr) {
- case 0x64:
- strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE);
- ir->l.code_length = 8;
- ir->l.add_to_buf = add_to_buf_pixelview;
- break;
- case 0x4b:
- strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE);
- ir->l.code_length = 32;
- ir->l.add_to_buf = add_to_buf_pv951;
- break;
- case 0x71:
- if (adap->id == I2C_HW_B_CX2388x)
- strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE);
- else /* bt8xx or cx2341x */
- /*
- * The PVR150 IR receiver uses the same protocol as
- * other Hauppauge cards, but the data flow is
- * different, so we need to deal with it by its own.
- */
- strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE);
- ir->l.code_length = 13;
- ir->l.add_to_buf = add_to_buf_haup_pvr150;
- break;
- case 0x6b:
- strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE);
- ir->l.code_length = 32;
- ir->l.add_to_buf = add_to_buf_adap;
- break;
- case 0x18:
- case 0x1a:
- if (adap->id == I2C_HW_B_CX2388x) {
- strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE);
- ir->l.code_length = 8;
- ir->l.add_to_buf = add_to_buf_pvr2000;
- } else { /* bt8xx or cx2341x */
- strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE);
- ir->l.code_length = 13;
- ir->l.add_to_buf = add_to_buf_haup;
- }
- break;
- case 0x30:
- strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE);
- ir->l.code_length = 8;
- ir->l.add_to_buf = add_to_buf_knc1;
- break;
- case 0x21:
- case 0x23:
- pcf_probe(client, ir);
- strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE);
- ir->l.code_length = 8;
- ir->l.add_to_buf = add_to_buf_pcf8574;
- break;
- default:
- /* shouldn't happen */
- printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr);
- kfree(ir);
- return -EINVAL;
- }
- printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n",
- adap->id, addr, ir->c.name);
-
- retval = lirc_register_driver(&ir->l);
-
- if (retval < 0) {
- printk(KERN_ERR "lirc_i2c: failed to register driver!\n");
- kfree(ir);
- return retval;
- }
-
- ir->l.minor = retval;
-
- return 0;
-}
-
-static int ir_remove(struct i2c_client *client)
-{
- struct IR *ir = i2c_get_clientdata(client);
-
- /* unregister device */
- lirc_unregister_driver(ir->l.minor);
-
- /* free memory */
- kfree(ir);
- return 0;
-}
-
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- /* nothing */
- return 0;
-}
-
-static int __init lirc_i2c_init(void)
-{
- i2c_add_driver(&driver);
- return 0;
-}
-
-static void __exit lirc_i2c_exit(void)
-{
- i2c_del_driver(&driver);
-}
-
-MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and "
- "Pixelview cards (i2c stack)");
-MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
- "Ulrich Mueller, Stefan Jahn, Jerome Brock");
-MODULE_LICENSE("GPL");
-
-module_param(minor, int, S_IRUGO);
-MODULE_PARM_DESC(minor, "Preferred minor device number");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
-
-module_init(lirc_i2c_init);
-module_exit(lirc_i2c_exit);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
index 971844bbee28..9bcf149c4260 100644
--- a/drivers/staging/lirc/lirc_serial.c
+++ b/drivers/staging/lirc/lirc_serial.c
@@ -377,7 +377,7 @@ static int init_timing_params(unsigned int new_duty_cycle,
duty_cycle = new_duty_cycle;
freq = new_freq;
- loops_per_sec = current_cpu_data.loops_per_jiffy;
+ loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy);
loops_per_sec *= HZ;
/* How many clocks in a microsecond?, avoiding long long divide */
@@ -398,7 +398,7 @@ static int init_timing_params(unsigned int new_duty_cycle,
dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
"clk/jiffy=%ld, pulse=%ld, space=%ld, "
"conv_us_to_clocks=%ld\n",
- freq, duty_cycle, current_cpu_data.loops_per_jiffy,
+ freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy),
pulse_width, space_width, conv_us_to_clocks);
return 0;
}
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
index f0076eb025f1..ad29bb1275ab 100644
--- a/drivers/staging/lirc/lirc_zilog.c
+++ b/drivers/staging/lirc/lirc_zilog.c
@@ -66,6 +66,7 @@ struct IR {
/* Device info */
struct mutex ir_lock;
int open;
+ bool is_hdpvr;
/* RX device */
struct i2c_client c_rx;
@@ -206,16 +207,12 @@ static int add_to_buf(struct IR *ir)
}
/* key pressed ? */
-#ifdef I2C_HW_B_HDPVR
- if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) {
+ if (ir->is_hdpvr) {
if (got_data && (keybuf[0] == 0x80))
return 0;
else if (got_data && (keybuf[0] == 0x00))
return -ENODATA;
} else if ((ir->b[0] & 0x80) == 0)
-#else
- if ((ir->b[0] & 0x80) == 0)
-#endif
return got_data ? 0 : -ENODATA;
/* look what we have */
@@ -841,15 +838,15 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
return ret < 0 ? ret : -EFAULT;
}
-#ifdef I2C_HW_B_HDPVR
/*
* The sleep bits aren't necessary on the HD PVR, and in fact, the
* last i2c_master_recv always fails with a -5, so for now, we're
* going to skip this whole mess and say we're done on the HD PVR
*/
- if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR)
- goto done;
-#endif
+ if (ir->is_hdpvr) {
+ dprintk("sent code %u, key %u\n", code, key);
+ return 0;
+ }
/*
* This bit NAKs until the device is ready, so we retry it
@@ -883,7 +880,6 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
return -EFAULT;
}
-done:
/* Oh good, it worked */
dprintk("sent code %u, key %u\n", code, key);
return 0;
@@ -1112,12 +1108,14 @@ static int ir_remove(struct i2c_client *client);
static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+#define ID_FLAG_TX 0x01
+#define ID_FLAG_HDPVR 0x02
+
static const struct i2c_device_id ir_transceiver_id[] = {
- /* Generic entry for any IR transceiver */
- { "ir_video", 0 },
- /* IR device specific entries should be added here */
- { "ir_tx_z8f0811_haup", 0 },
- { "ir_rx_z8f0811_haup", 0 },
+ { "ir_tx_z8f0811_haup", ID_FLAG_TX },
+ { "ir_rx_z8f0811_haup", 0 },
+ { "ir_tx_z8f0811_hdpvr", ID_FLAG_HDPVR | ID_FLAG_TX },
+ { "ir_rx_z8f0811_hdpvr", ID_FLAG_HDPVR },
{ }
};
@@ -1197,10 +1195,25 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
int ret;
int have_rx = 0, have_tx = 0;
- dprintk("%s: adapter id=0x%x, client addr=0x%02x\n",
- __func__, adap->id, client->addr);
+ dprintk("%s: adapter name (%s) nr %d, i2c_device_id name (%s), "
+ "client addr=0x%02x\n",
+ __func__, adap->name, adap->nr, id->name, client->addr);
/*
+ * FIXME - This probe function probes both the Tx and Rx
+ * addresses of the IR microcontroller.
+ *
+ * However, the I2C subsystem is passing along one I2C client at a
+ * time, based on matches to the ir_transceiver_id[] table above.
+ * The expectation is that each i2c_client address will be probed
+ * individually by drivers so the I2C subsystem can mark all client
+ * addresses as claimed or not.
+ *
+ * This probe routine causes only one of the client addresses, TX or RX,
+ * to be claimed. This will cause a problem if the I2C subsystem is
+ * subsequently triggered to probe unclaimed clients again.
+ */
+ /*
* The external IR receiver is at i2c address 0x71.
* The IR transmitter is at 0x70.
*/
@@ -1242,6 +1255,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
mutex_init(&ir->ir_lock);
mutex_init(&ir->buf_lock);
ir->need_boot = 1;
+ ir->is_hdpvr = (id->driver_data & ID_FLAG_HDPVR) ? true : false;
memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
ir->l.minor = -1;
diff --git a/drivers/staging/memrar/memrar.h b/drivers/staging/memrar/memrar.h
index 0b735b827c09..0feb73b94c91 100644
--- a/drivers/staging/memrar/memrar.h
+++ b/drivers/staging/memrar/memrar.h
@@ -95,6 +95,7 @@ struct RAR_buffer {
dma_addr_t bus_address;
};
+#if defined(CONFIG_MRST_RAR_HANDLER)
/**
* rar_reserve() - reserve RAR buffers
* @buffers: array of RAR_buffers where type and size of buffers to
@@ -149,7 +150,25 @@ extern size_t rar_release(struct RAR_buffer *buffers,
extern size_t rar_handle_to_bus(struct RAR_buffer *buffers,
size_t count);
+#else
+extern inline size_t rar_reserve(struct RAR_buffer *buffers, size_t count)
+{
+ return 0;
+}
+
+extern inline size_t rar_release(struct RAR_buffer *buffers, size_t count)
+{
+ return 0;
+}
+
+extern inline size_t rar_handle_to_bus(struct RAR_buffer *buffers,
+ size_t count)
+{
+ return 0;
+}
+
+#endif /* MRST_RAR_HANDLER */
#endif /* __KERNEL__ */
#endif /* _MEMRAR_H */
diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile
index bb3606faf20e..07a89ecfcc2b 100644
--- a/drivers/staging/msm/Makefile
+++ b/drivers/staging/msm/Makefile
@@ -41,11 +41,11 @@ obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
# MDDI
-msm_mddi-objs := mddi.o mddihost.o mddihosti.o
+msm_mddi-y := mddi.o mddihost.o mddihosti.o
obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
# External MDDI
-msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
+msm_mddi_ext-y := mddihost_e.o mddi_ext.o
obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
# TVEnc
diff --git a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c
index 864d7c18913d..edba78a3afcf 100644
--- a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c
+++ b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c
@@ -77,7 +77,7 @@ static void toshiba_spi_write(char cmd, uint32 data, int num)
/* followed by parameter bytes */
if (num) {
- bp = (char *)&data;;
+ bp = (char *)&data;
bp += (num - 1);
while (num) {
toshiba_spi_write_byte(1, *bp);
diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c
index ea268edbf43b..23fa049b51f2 100644
--- a/drivers/staging/msm/msm_fb.c
+++ b/drivers/staging/msm/msm_fb.c
@@ -1158,7 +1158,7 @@ static int msm_fb_release(struct fb_info *info, int user)
return ret;
}
-DECLARE_MUTEX(msm_fb_pan_sem);
+DEFINE_SEMAPHORE(msm_fb_pan_sem);
static int msm_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
@@ -1962,7 +1962,7 @@ static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
#endif
-DECLARE_MUTEX(msm_fb_ioctl_ppp_sem);
+DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c
index 033fc9486e01..2a8077511fc0 100644
--- a/drivers/staging/msm/msm_fb_bl.c
+++ b/drivers/staging/msm/msm_fb_bl.c
@@ -42,7 +42,7 @@ static int msm_fb_bl_update_status(struct backlight_device *pbd)
return 0;
}
-static struct backlight_ops msm_fb_bl_ops = {
+static const struct backlight_ops msm_fb_bl_ops = {
.get_brightness = msm_fb_bl_get_brightness,
.update_status = msm_fb_bl_update_status,
};
diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c
index f41c5ac22f25..4fbb77b253d3 100644
--- a/drivers/staging/msm/tvenc.c
+++ b/drivers/staging/msm/tvenc.c
@@ -279,12 +279,13 @@ static int __init tvenc_driver_init(void)
if (IS_ERR(tvenc_clk)) {
printk(KERN_ERR "error: can't get tvenc_clk!\n");
- return IS_ERR(tvenc_clk);
+ return PTR_ERR(tvenc_clk);
}
if (IS_ERR(tvdac_clk)) {
printk(KERN_ERR "error: can't get tvdac_clk!\n");
- return IS_ERR(tvdac_clk);
+ clk_put(tvenc_clk);
+ return PTR_ERR(tvdac_clk);
}
// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO
index ac2d3d023715..35f9cda7be11 100644
--- a/drivers/staging/olpc_dcon/TODO
+++ b/drivers/staging/olpc_dcon/TODO
@@ -1,6 +1,5 @@
TODO:
- checkpatch.pl cleanups
- - port geode gpio calls to newer cs5535 API
- see if vx855 gpio API can be made similar enough to cs5535 so we can
share more code
- allow simultaneous XO-1 and XO-1.5 support
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 75aa7a36307d..9f26dc9408bb 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -17,7 +17,6 @@
#include <linux/console.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/i2c-id.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/interrupt.h>
@@ -28,7 +27,6 @@
#include <asm/uaccess.h>
#include <linux/ctype.h>
#include <linux/reboot.h>
-#include <linux/gpio.h>
#include <asm/tsc.h>
#include <asm/olpc.h>
@@ -50,7 +48,7 @@ struct dcon_platform_data {
int (*init)(void);
void (*bus_stabilize_wiggle)(void);
void (*set_dconload)(int);
- int (*read_status)(void);
+ u8 (*read_status)(void);
};
static struct dcon_platform_data *pdata;
@@ -616,7 +614,7 @@ static struct device_attribute dcon_device_files[] = {
__ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store),
};
-static struct backlight_ops dcon_bl_ops = {
+static const struct backlight_ops dcon_bl_ops = {
.get_brightness = dconbl_get,
.update_status = dconbl_set
};
@@ -733,7 +731,6 @@ static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id)
edev:
platform_device_unregister(dcon_device);
dcon_device = NULL;
- i2c_set_clientdata(client, NULL);
eirq:
free_irq(DCON_IRQ, &dcon_driver);
einit:
@@ -757,8 +754,6 @@ static int dcon_remove(struct i2c_client *client)
platform_device_unregister(dcon_device);
cancel_work_sync(&dcon_work);
- i2c_set_clientdata(client, NULL);
-
return 0;
}
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h
index 6453ca4ba0ee..e566d213da2a 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.h
+++ b/drivers/staging/olpc_dcon/olpc_dcon.h
@@ -29,26 +29,6 @@
#define DCON_REG_SCAN_INT 9
#define DCON_REG_BRIGHT 10
-/* GPIO registers (CS5536) */
-
-#define MSR_LBAR_GPIO 0x5140000C
-
-#define GPIOx_OUT_VAL 0x00
-#define GPIOx_OUT_EN 0x04
-#define GPIOx_IN_EN 0x20
-#define GPIOx_INV_EN 0x24
-#define GPIOx_IN_FLTR_EN 0x28
-#define GPIOx_EVNTCNT_EN 0x2C
-#define GPIOx_READ_BACK 0x30
-#define GPIOx_EVNT_EN 0x38
-#define GPIOx_NEGEDGE_EN 0x44
-#define GPIOx_NEGEDGE_STS 0x4C
-#define GPIO_FLT7_AMNT 0xD8
-#define GPIO_MAP_X 0xE0
-#define GPIO_MAP_Y 0xE4
-#define GPIO_FE7_SEL 0xF7
-
-
/* Status values */
#define DCONSTAT_SCANINT 0
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index 779fb7d7b30c..043198dc6ff7 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -10,54 +10,70 @@
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*/
-
+#include <linux/cs5535.h>
+#include <linux/gpio.h>
#include <asm/olpc.h>
#include "olpc_dcon.h"
-/* Base address of the GPIO registers */
-static unsigned long gpio_base;
-
-/*
- * List of GPIOs that we care about:
- * (in) GPIO12 -- DCONBLANK
- * (in) GPIO[56] -- DCONSTAT[01]
- * (out) GPIO11 -- DCONLOAD
- */
-
-#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12))
-#define OUT_GPIOS (1<<11)
-
static int dcon_init_xo_1(void)
{
- unsigned long lo, hi;
unsigned char lob;
- rdmsr(MSR_LBAR_GPIO, lo, hi);
-
- /* Check the mask and whether GPIO is enabled (sanity check) */
- if (hi != 0x0000f001) {
- printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n");
- return -ENODEV;
+ if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) {
+ printk(KERN_ERR "olpc-dcon: failed to request STAT0 GPIO\n");
+ return -EIO;
+ }
+ if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) {
+ printk(KERN_ERR "olpc-dcon: failed to request STAT1 GPIO\n");
+ goto err_gp_stat1;
+ }
+ if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) {
+ printk(KERN_ERR "olpc-dcon: failed to request IRQ GPIO\n");
+ goto err_gp_irq;
+ }
+ if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) {
+ printk(KERN_ERR "olpc-dcon: failed to request LOAD GPIO\n");
+ goto err_gp_load;
+ }
+ if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) {
+ printk(KERN_ERR "olpc-dcon: failed to request BLANK GPIO\n");
+ goto err_gp_blank;
}
-
- /* Mask off the IO base address */
- gpio_base = lo & 0x0000ff00;
/* Turn off the event enable for GPIO7 just to be safe */
- outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE);
+
+ /*
+ * Determine the current state by reading the GPIO bit; earlier
+ * stages of the boot process have established the state.
+ *
+ * Note that we read GPIO_OUPUT_VAL rather than GPIO_READ_BACK here;
+ * this is because OFW will disable input for the pin and set a value..
+ * READ_BACK will only contain a valid value if input is enabled and
+ * then a value is set. So, future readings of the pin can use
+ * READ_BACK, but the first one cannot. Awesome, huh?
+ */
+ dcon_source = cs5535_gpio_isset(OLPC_GPIO_DCON_LOAD, GPIO_OUTPUT_VAL)
+ ? DCON_SOURCE_CPU
+ : DCON_SOURCE_DCON;
+ dcon_pending = dcon_source;
/* Set the directions for the GPIO pins */
- outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN);
- outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN);
+ gpio_direction_input(OLPC_GPIO_DCON_STAT0);
+ gpio_direction_input(OLPC_GPIO_DCON_STAT1);
+ gpio_direction_input(OLPC_GPIO_DCON_IRQ);
+ gpio_direction_input(OLPC_GPIO_DCON_BLANK);
+ gpio_direction_output(OLPC_GPIO_DCON_LOAD,
+ dcon_source == DCON_SOURCE_CPU);
/* Set up the interrupt mappings */
/* Set the IRQ to pair 2 */
- geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2);
+ cs5535_gpio_setup_event(OLPC_GPIO_DCON_IRQ, 2, 0);
/* Enable group 2 to trigger the DCON interrupt */
- geode_gpio_set_irq(2, DCON_IRQ);
+ cs5535_gpio_set_irq(2, DCON_IRQ);
/* Select edge level for interrupt (in PIC) */
lob = inb(0x4d0);
@@ -65,52 +81,61 @@ static int dcon_init_xo_1(void)
outb(lob, 0x4d0);
/* Register the interupt handler */
- if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver))
- return -EIO;
+ if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver)) {
+ printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n");
+ goto err_req_irq;
+ }
/* Clear INV_EN for GPIO7 (DCONIRQ) */
- outl((1<<(16+7)), gpio_base + GPIOx_INV_EN);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_INVERT);
/* Enable filter for GPIO12 (DCONBLANK) */
- outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN);
+ cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_FILTER);
/* Disable filter for GPIO7 */
- outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_FILTER);
/* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
-
- outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
- outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_EVENT_COUNT);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_EVENT_COUNT);
/* Add GPIO12 to the Filter Event Pair #7 */
- outb(12, gpio_base + GPIO_FE7_SEL);
+ cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_FE7_SEL);
/* Turn off negative Edge Enable for GPIO12 */
- outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN);
+ cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_EN);
/* Enable negative Edge Enable for GPIO7 */
- outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN);
+ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_EN);
/* Zero the filter amount for Filter Event Pair #7 */
- outw(0, gpio_base + GPIO_FLT7_AMNT);
+ cs5535_gpio_set(0, GPIO_FLTR7_AMOUNT);
/* Clear the negative edge status for GPIO7 and GPIO12 */
- outl((1<<7) | (1<<12), gpio_base+0x4c);
+ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS);
+ cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS);
/* FIXME: Clear the posiitive status as well, just to be sure */
- outl((1<<7) | (1<<12), gpio_base+0x48);
+ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS);
+ cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS);
/* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */
- outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN);
-
- /* Determine the current state by reading the GPIO bit */
- /* Earlier stages of the boot process have established the state */
- dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11)
- ? DCON_SOURCE_CPU
- : DCON_SOURCE_DCON;
- dcon_pending = dcon_source;
+ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE);
+ cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_EVENTS_ENABLE);
return 0;
+
+err_req_irq:
+ gpio_free(OLPC_GPIO_DCON_BLANK);
+err_gp_blank:
+ gpio_free(OLPC_GPIO_DCON_LOAD);
+err_gp_load:
+ gpio_free(OLPC_GPIO_DCON_IRQ);
+err_gp_irq:
+ gpio_free(OLPC_GPIO_DCON_STAT1);
+err_gp_stat1:
+ gpio_free(OLPC_GPIO_DCON_STAT0);
+ return -EIO;
}
static void dcon_wiggle_xo_1(void)
@@ -128,37 +153,44 @@ static void dcon_wiggle_xo_1(void)
* simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and
* GPIO15.
*/
- geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL);
- geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE);
- geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
- geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2);
- geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
+ cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
+ cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL);
+ cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_ENABLE);
+ cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX2);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
for (x = 0; x < 16; x++) {
udelay(5);
- geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
+ cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
udelay(5);
- geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
+ cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL);
}
udelay(5);
- geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
- geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
+ cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1);
+ cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1);
+ cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1);
+ cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1);
}
static void dcon_set_dconload_1(int val)
{
- if (val)
- outl(1<<11, gpio_base + GPIOx_OUT_VAL);
- else
- outl(1<<(11 + 16), gpio_base + GPIOx_OUT_VAL);
+ gpio_set_value(OLPC_GPIO_DCON_LOAD, val);
}
-static int dcon_read_status_xo_1(void)
+static u8 dcon_read_status_xo_1(void)
{
- int status = inl(gpio_base + GPIOx_READ_BACK) >> 5;
-
+ u8 status;
+
+ status = gpio_get_value(OLPC_GPIO_DCON_STAT0);
+ status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1;
+
/* Clear the negative edge status for GPIO7 */
- outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
+ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS);
return status;
}
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
index cca6a235ef96..4f56098bb366 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
@@ -195,9 +195,9 @@ static void dcon_set_dconload_xo_1_5(int val)
}
}
-static int dcon_read_status_xo_1_5(void)
+static u8 dcon_read_status_xo_1_5(void)
{
- int status;
+ u8 status;
if (!dcon_was_irq())
return -1;
diff --git a/drivers/staging/phison/phison.c b/drivers/staging/phison/phison.c
index 677152044f45..683657cb21f5 100644
--- a/drivers/staging/phison/phison.c
+++ b/drivers/staging/phison/phison.c
@@ -69,7 +69,7 @@ static int phison_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
}
-static const struct pci_device_id phison_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(phison_pci_tbl) = {
{ PCI_VENDOR_ID_PHISON, PCI_DEVICE_ID_PS5000, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ 0, },
diff --git a/drivers/staging/pohmelfs/crypto.c b/drivers/staging/pohmelfs/crypto.c
index 2fdb3e01460d..6540864216c8 100644
--- a/drivers/staging/pohmelfs/crypto.c
+++ b/drivers/staging/pohmelfs/crypto.c
@@ -130,10 +130,8 @@ err_out_exit:
void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
{
- if (e->hash)
- crypto_free_hash(e->hash);
- if (e->cipher)
- crypto_free_ablkcipher(e->cipher);
+ crypto_free_hash(e->hash);
+ crypto_free_ablkcipher(e->cipher);
kfree(e->data);
}
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index 61685ccceda8..56d3a4e5622f 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -826,6 +826,13 @@ const struct address_space_operations pohmelfs_aops = {
.set_page_dirty = __set_page_dirty_nobuffers,
};
+static void pohmelfs_i_callback(struct rcu_head *head)
+{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
+ INIT_LIST_HEAD(&inode->i_dentry);
+ kmem_cache_free(pohmelfs_inode_cache, POHMELFS_I(inode));
+}
+
/*
* ->detroy_inode() callback. Deletes inode from the caches
* and frees private data.
@@ -842,8 +849,8 @@ static void pohmelfs_destroy_inode(struct inode *inode)
dprintk("%s: pi: %p, inode: %p, ino: %llu.\n",
__func__, pi, &pi->vfs_inode, pi->ino);
- kmem_cache_free(pohmelfs_inode_cache, pi);
atomic_long_dec(&psb->total_inodes);
+ call_rcu(&inode->i_rcu, pohmelfs_i_callback);
}
/*
@@ -1318,8 +1325,8 @@ static void pohmelfs_put_super(struct super_block *sb)
}
psb->trans_scan_timeout = psb->drop_scan_timeout = 0;
- cancel_rearming_delayed_work(&psb->dwork);
- cancel_rearming_delayed_work(&psb->drop_dwork);
+ cancel_delayed_work_sync(&psb->dwork);
+ cancel_delayed_work_sync(&psb->drop_dwork);
flush_scheduled_work();
dprintk("%s: stopped workqueues.\n", __func__);
diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c
index 9279897ff161..b2e918622088 100644
--- a/drivers/staging/pohmelfs/net.c
+++ b/drivers/staging/pohmelfs/net.c
@@ -413,7 +413,7 @@ static int pohmelfs_readdir_response(struct netfs_state *st)
if (dentry) {
alias = d_materialise_unique(dentry, &npi->vfs_inode);
if (alias)
- dput(dentry);
+ dput(alias);
}
dput(dentry);
diff --git a/drivers/staging/pohmelfs/path_entry.c b/drivers/staging/pohmelfs/path_entry.c
index 8ec83d2dffb7..400a9fc386ad 100644
--- a/drivers/staging/pohmelfs/path_entry.c
+++ b/drivers/staging/pohmelfs/path_entry.c
@@ -83,10 +83,11 @@ out:
int pohmelfs_path_length(struct pohmelfs_inode *pi)
{
struct dentry *d, *root, *first;
- int len = 1; /* Root slash */
+ int len;
+ unsigned seq;
- first = d = d_find_alias(&pi->vfs_inode);
- if (!d) {
+ first = d_find_alias(&pi->vfs_inode);
+ if (!first) {
dprintk("%s: ino: %llu, mode: %o.\n", __func__, pi->ino, pi->vfs_inode.i_mode);
return -ENOENT;
}
@@ -95,7 +96,11 @@ int pohmelfs_path_length(struct pohmelfs_inode *pi)
root = dget(current->fs->root.dentry);
spin_unlock(&current->fs->lock);
- spin_lock(&dcache_lock);
+rename_retry:
+ len = 1; /* Root slash */
+ d = first;
+ seq = read_seqbegin(&rename_lock);
+ rcu_read_lock();
if (!IS_ROOT(d) && d_unhashed(d))
len += UNHASHED_OBSCURE_STRING_SIZE; /* Obscure " (deleted)" string */
@@ -104,7 +109,9 @@ int pohmelfs_path_length(struct pohmelfs_inode *pi)
len += d->d_name.len + 1; /* Plus slash */
d = d->d_parent;
}
- spin_unlock(&dcache_lock);
+ rcu_read_unlock();
+ if (read_seqretry(&rename_lock, seq))
+ goto rename_retry;
dput(root);
dput(first);
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index d746715d3d89..d83bec876d2e 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -355,7 +355,6 @@ static int quickstart_acpi_remove(struct acpi_device *device, int type)
static void quickstart_exit(void)
{
input_unregister_device(quickstart_input);
- input_free_device(quickstart_input);
device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
device_remove_file(&pf_device->dev, &dev_attr_buttons);
@@ -375,6 +374,7 @@ static int __init quickstart_init_input(void)
{
struct quickstart_btn **ptr = &quickstart_data.btn_lst;
int count;
+ int ret;
quickstart_input = input_allocate_device();
@@ -391,7 +391,13 @@ static int __init quickstart_init_input(void)
ptr = &((*ptr)->next);
}
- return input_register_device(quickstart_input);
+ ret = input_register_device(quickstart_input);
+ if (ret) {
+ input_free_device(quickstart_input);
+ return ret;
+ }
+
+ return 0;
}
static int __init quickstart_init(void)
diff --git a/drivers/staging/rt2860/chip/mac_pci.h b/drivers/staging/rt2860/chip/mac_pci.h
index 9f25ef047f59..b8868a5b9e04 100644
--- a/drivers/staging/rt2860/chip/mac_pci.h
+++ b/drivers/staging/rt2860/chip/mac_pci.h
@@ -30,7 +30,8 @@
Abstract:
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix some typos
--------- ---------- ----------------------------------------------
*/
@@ -45,7 +46,7 @@
/* */
/* Device ID & Vendor ID related definitions, */
-/* NOTE: you should not add the new VendorID/DeviceID here unless you not sure it belongs to what chip. */
+/* NOTE: you should not add the new VendorID/DeviceID here unless you know for sure what chip it belongs too. */
/* */
#define NIC_PCI_VENDOR_ID 0x1814
#define PCIBUS_INTEL_VENDOR 0x8086
@@ -83,7 +84,7 @@ struct PACKED rt_txd {
u32 SDPtr1;
/*Word3 */
u32 rsv2:24;
- u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition */
+ u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correct position */
u32 QSEL:2; /* select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA */
u32 rsv:2;
u32 TCO:1; /* */
diff --git a/drivers/staging/rt2860/chip/mac_usb.h b/drivers/staging/rt2860/chip/mac_usb.h
index ed0c0b43b05e..e8158fb58648 100644
--- a/drivers/staging/rt2860/chip/mac_usb.h
+++ b/drivers/staging/rt2860/chip/mac_usb.h
@@ -30,7 +30,8 @@
Abstract:
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix a typo
--------- ---------- ----------------------------------------------
*/
@@ -93,7 +94,7 @@ struct rt_txinfo {
/* Word 0 */
u32 USBDMATxPktLen:16; /*used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. */
u32 rsv:8;
- u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition */
+ u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correct position */
u32 QSEL:2; /* select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA */
u32 SwUseLastRound:1; /* Software use. */
u32 rsv2:2; /* Software use. */
diff --git a/drivers/staging/rt2860/chip/rtmp_mac.h b/drivers/staging/rt2860/chip/rtmp_mac.h
index e8f7172ce42a..3d1e4915b956 100644
--- a/drivers/staging/rt2860/chip/rtmp_mac.h
+++ b/drivers/staging/rt2860/chip/rtmp_mac.h
@@ -32,6 +32,7 @@
Revision History:
Who When What
+ Justin P. Mattock 11/07/2010 Fix a comments, and typos
-------- ---------- ----------------------------------------------
*/
@@ -43,7 +44,7 @@
/* ================================================================================= */
/* the first 24-byte in TXD 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. */
+/* MAC block uses this TXINFO to control the transmission behavior of this frame. */
#define FIFO_MGMT 0
#define FIFO_HCCA 1
#define FIFO_EDCA 2
@@ -458,8 +459,8 @@ typedef union _BBP_CSR_CFG_STRUC {
/* */
typedef union _RF_CSR_CFG0_STRUC {
struct {
- u32 RegIdAndContent:24; /* Register value to program into BBP */
- u32 bitwidth:5; /* Selected BBP register */
+ u32 RegIdAndContent:24; /* Register value to program into BBP */
+ u32 bitwidth:5; /* Selected BBP register */
u32 StandbyMode:1; /* 0: high when stand by 1: low when standby */
u32 Sel:1; /* 0:RF_LE0 activate 1:RF_LE1 activate */
u32 Busy:1; /* 0: idle 1: 8busy */
@@ -469,7 +470,7 @@ typedef union _RF_CSR_CFG0_STRUC {
#define RF_CSR_CFG1 0x1024
typedef union _RF_CSR_CFG1_STRUC {
struct {
- u32 RegIdAndContent:24; /* Register value to program into BBP */
+ u32 RegIdAndContent:24; /* Register value to program into BBP */
u32 RFGap:5; /* Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) */
u32 rsv:7; /* 0: idle 1: 8busy */
} field;
@@ -478,7 +479,7 @@ typedef union _RF_CSR_CFG1_STRUC {
#define RF_CSR_CFG2 0x1028 /* */
typedef union _RF_CSR_CFG2_STRUC {
struct {
- u32 RegIdAndContent:24; /* Register value to program into BBP */
+ u32 RegIdAndContent:24; /* Register value to program into BBP */
u32 rsv:8; /* 0: idle 1: 8busy */
} field;
u32 word;
@@ -490,7 +491,7 @@ typedef union _LED_CFG_STRUC {
u32 OffPeriod:8; /* blinking off period unit 1ms */
u32 SlowBlinkPeriod:6; /* slow blinking period. unit:1ms */
u32 rsv:2;
- u32 RLedMode:2; /* red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on */
+ u32 RLedMode:2; /* red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on */
u32 GLedMode:2; /* green Led Mode */
u32 YLedMode:2; /* yellow Led Mode */
u32 LedPolar:1; /* Led Polarity. 0: active low1: active high */
@@ -621,9 +622,9 @@ typedef union _TX_TIMEOUT_CFG_STRUC {
#define TX_RTY_CFG 0x134c
typedef union PACKED _TX_RTY_CFG_STRUC {
struct {
- u32 ShortRtyLimit:8; /* short retry limit */
- u32 LongRtyLimit:8; /*long retry limit */
- u32 LongRtyThre:12; /* Long retry threshoold */
+ u32 ShortRtyLimit:8; /* short retry limit */
+ u32 LongRtyLimit:8; /* long retry limit */
+ u32 LongRtyThre:12; /* Long retry threshold */
u32 NonAggRtyMode:1; /* Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer */
u32 AggRtyMode:1; /* Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer */
u32 TxautoFBEnable:1; /* Tx retry PHY rate auto fallback enable */
diff --git a/drivers/staging/rt2860/chip/rtmp_phy.h b/drivers/staging/rt2860/chip/rtmp_phy.h
index 9f924ea6ca35..98454df30a22 100644
--- a/drivers/staging/rt2860/chip/rtmp_phy.h
+++ b/drivers/staging/rt2860/chip/rtmp_phy.h
@@ -247,7 +247,7 @@
} \
} \
if (BbpCsr.field.Busy == BUSY) { \
- DBGPRINT_ERR(("BBP(viaMCU=%d) read R%d fail\n", (_bViaMCU), _bbpID)); \
+ DBGPRINT_ERR("BBP(viaMCU=%d) read R%d fail\n", (_bViaMCU), _bbpID); \
*(_pV) = (_pAd)->BbpWriteLatch[_bbpID]; \
if ((_bViaMCU) == TRUE) { \
RTMP_IO_READ32(_pAd, _regID, &BbpCsr.word); \
@@ -336,11 +336,11 @@
} \
} \
} else { \
- DBGPRINT_ERR((" , brt30xxBanMcuCmd = %d, Read BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I))); \
+ DBGPRINT_ERR(" , brt30xxBanMcuCmd = %d, Read BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I)); \
*(_pV) = (_A)->BbpWriteLatch[_I]; \
} \
if ((BbpCsr.field.Busy == BUSY) || ((_A)->bPCIclkOff == TRUE)) { \
- DBGPRINT_ERR(("BBP read R%d=0x%x fail\n", _I, BbpCsr.word)); \
+ DBGPRINT_ERR("BBP read R%d=0x%x fail\n", _I, BbpCsr.word); \
*(_pV) = (_A)->BbpWriteLatch[_I]; \
} \
}
@@ -378,7 +378,7 @@
break; \
} \
if (_busyCnt == MAX_BUSY_COUNT) { \
- DBGPRINT_ERR(("BBP write R%d fail\n", _bbpID)); \
+ DBGPRINT_ERR("BBP write R%d fail\n", _bbpID); \
if ((_bViaMCU) == TRUE) { \
RTMP_IO_READ32(_pAd, H2M_BBP_AGENT, &BbpCsr.word); \
BbpCsr.field.Busy = 0; \
@@ -459,15 +459,15 @@
break; \
} \
} else { \
- DBGPRINT_ERR((" brt30xxBanMcuCmd = %d. Write BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I))); \
+ DBGPRINT_ERR(" brt30xxBanMcuCmd = %d. Write BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I)); \
} \
if ((BusyCnt == MAX_BUSY_COUNT) || ((_A)->bPCIclkOff == TRUE)) { \
if (BusyCnt == MAX_BUSY_COUNT) \
(_A)->AccessBBPFailCount++; \
- DBGPRINT_ERR(("BBP write R%d=0x%x fail. BusyCnt= %d.bPCIclkOff = %d. \n", _I, BbpCsr.word, BusyCnt, (_A)->bPCIclkOff)); \
+ DBGPRINT_ERR("BBP write R%d=0x%x fail. BusyCnt= %d.bPCIclkOff = %d. \n", _I, BbpCsr.word, BusyCnt, (_A)->bPCIclkOff); \
} \
} else { \
- DBGPRINT_ERR(("****** BBP_Write_Latch Buffer exceeds max boundry ****** \n")); \
+ DBGPRINT_ERR("****** BBP_Write_Latch Buffer exceeds max boundry ****** \n"); \
} \
}
#endif /* RTMP_MAC_PCI // */
diff --git a/drivers/staging/rt2860/chips/rt3090.c b/drivers/staging/rt2860/chips/rt3090.c
index c2933c69bc04..334720ee1345 100644
--- a/drivers/staging/rt2860/chips/rt3090.c
+++ b/drivers/staging/rt2860/chips/rt3090.c
@@ -28,10 +28,11 @@
rt3090.c
Abstract:
- Specific funcitons and variables for RT3070
+ Specific functions and variables for RT3070
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix a typo
-------- ---------- ----------------------------------------------
*/
@@ -51,7 +52,8 @@ void NICInitRT3090RFRegisters(struct rt_rtmp_adapter *pAd)
if (IS_RT3090(pAd)) {
/* Init RF calibration */
/* Driver should toggle RF R30 bit7 before init RF registers */
- u32 RfReg = 0, data;
+ u8 RfReg;
+ u32 data;
RT30xxReadRFRegister(pAd, RF_R30, (u8 *)&RfReg);
RfReg |= 0x80;
diff --git a/drivers/staging/rt2860/chips/rt30xx.c b/drivers/staging/rt2860/chips/rt30xx.c
index 4367a196aeff..354debfe1477 100644
--- a/drivers/staging/rt2860/chips/rt30xx.c
+++ b/drivers/staging/rt2860/chips/rt30xx.c
@@ -28,10 +28,11 @@
rt30xx.c
Abstract:
- Specific funcitons and variables for RT30xx.
+ Specific functions and variables for RT30xx.
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix some typos
-------- ---------- ----------------------------------------------
*/
@@ -53,7 +54,7 @@ struct rt_reg_pair RT30xx_RFRegTable[] = {
,
{RF_R06, 0x02}
,
- {RF_R07, 0x70}
+ {RF_R07, 0x60}
,
{RF_R09, 0x0F}
,
@@ -89,7 +90,7 @@ struct rt_reg_pair RT30xx_RFRegTable[] = {
u8 NUM_RF_REG_PARMS = (sizeof(RT30xx_RFRegTable) / sizeof(struct rt_reg_pair));
-/* Antenna divesity use GPIO3 and EESK pin for control */
+/* Antenna diversity use GPIO3 and EESK pin for control */
/* Antenna and EEPROM access are both using EESK pin, */
/* Therefor we should avoid accessing EESK at the same time */
/* Then restore antenna after EEPROM access */
@@ -243,7 +244,7 @@ void RTMPFilterCalibration(struct rt_rtmp_adapter *pAd)
break;
}
- /* prevent infinite loop cause driver hang. */
+ /* prevent infinite loop; causes driver hang. */
if (loopcnt++ > 100) {
DBGPRINT(RT_DEBUG_ERROR,
("RTMPFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating",
@@ -441,7 +442,7 @@ void RT30xxReverseRFSleepModeSetup(struct rt_rtmp_adapter *pAd)
/* VCO_IC, RF R7 register Bit 4 & Bit 5 to 1 */
RT30xxReadRFRegister(pAd, RF_R07, &RFValue);
- RFValue |= 0x30;
+ RFValue |= 0x20;
RT30xxWriteRFRegister(pAd, RF_R07, RFValue);
/* Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1 */
diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c
index 8eef82d92621..b046c2b814c5 100644
--- a/drivers/staging/rt2860/common/ba_action.c
+++ b/drivers/staging/rt2860/common/ba_action.c
@@ -799,8 +799,8 @@ void BAOriSessionTearDown(struct rt_rtmp_adapter *pAd,
/* force send specified TID DelBA */
struct rt_mlme_delba_req DelbaReq;
struct rt_mlme_queue_elem *Elem =
- (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
- MEM_ALLOC_FLAG);
+ kmalloc(sizeof(struct rt_mlme_queue_elem),
+ MEM_ALLOC_FLAG);
if (Elem != NULL) {
NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
@@ -839,8 +839,8 @@ void BAOriSessionTearDown(struct rt_rtmp_adapter *pAd,
&& (pBAEntry->ORI_BA_Status == Originator_Done)) {
struct rt_mlme_delba_req DelbaReq;
struct rt_mlme_queue_elem *Elem =
- (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
- MEM_ALLOC_FLAG);
+ kmalloc(sizeof(struct rt_mlme_queue_elem),
+ MEM_ALLOC_FLAG);
if (Elem != NULL) {
NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
@@ -908,8 +908,8 @@ void BARecSessionTearDown(struct rt_rtmp_adapter *pAd,
/* */
if (bPassive == FALSE) {
struct rt_mlme_queue_elem *Elem =
- (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
- MEM_ALLOC_FLAG);
+ kmalloc(sizeof(struct rt_mlme_queue_elem),
+ MEM_ALLOC_FLAG);
if (Elem != NULL) {
NdisZeroMemory(&DelbaReq, sizeof(DelbaReq));
NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem));
@@ -1270,13 +1270,13 @@ BOOLEAN CntlEnqueueForRecv(struct rt_rtmp_adapter *pAd,
/* First check the size, it MUST not exceed the mlme queue size */
if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
- DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
+ DBGPRINT_ERR("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen);
return FALSE;
} else if (MsgLen != sizeof(struct rt_frame_ba_req)) {
- DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
+ DBGPRINT_ERR("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen);
return FALSE;
} else if (MsgLen != sizeof(struct rt_frame_ba_req)) {
- DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen));
+ DBGPRINT_ERR("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen);
return FALSE;
}
diff --git a/drivers/staging/rt2860/common/cmm_aes.c b/drivers/staging/rt2860/common/cmm_aes.c
index 1d159ff82fd2..a99879bada42 100644
--- a/drivers/staging/rt2860/common/cmm_aes.c
+++ b/drivers/staging/rt2860/common/cmm_aes.c
@@ -330,8 +330,6 @@ void construct_mic_iv(unsigned char *mic_iv,
for (i = 8; i < 14; i++)
mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */
#endif
- i = (payload_length / 256);
- i = (payload_length % 256);
mic_iv[14] = (unsigned char)(payload_length / 256);
mic_iv[15] = (unsigned char)(payload_length % 256);
diff --git a/drivers/staging/rt2860/common/cmm_data.c b/drivers/staging/rt2860/common/cmm_data.c
index 93a53479d766..2204c2bda386 100644
--- a/drivers/staging/rt2860/common/cmm_data.c
+++ b/drivers/staging/rt2860/common/cmm_data.c
@@ -1366,7 +1366,7 @@ void RTMPResumeMsduTransmission(struct rt_rtmp_adapter *pAd)
/* R66 should not be 0 */
if (pAd->BbpTuning.R66CurrentValue == 0) {
pAd->BbpTuning.R66CurrentValue = 0x38;
- DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n"));
+ DBGPRINT_ERR("RTMPResumeMsduTransmission, R66CurrentValue=0...\n");
}
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66,
diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c
index 43d73a05c8eb..7af59ff9e220 100644
--- a/drivers/staging/rt2860/common/cmm_data_pci.c
+++ b/drivers/staging/rt2860/common/cmm_data_pci.c
@@ -137,7 +137,7 @@ u16 RtmpPCI_WriteSingleTxResource(struct rt_rtmp_adapter *pAd,
pTxD->SDPtr0 = BufBasePaLow;
pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */
- pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
+ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
pTxD->SDLen1 = pTxBlk->SrcBufLen;
pTxD->LastSec0 = 0;
pTxD->LastSec1 = (bIsLast) ? 1 : 0;
@@ -215,7 +215,7 @@ u16 RtmpPCI_WriteMultiTxResource(struct rt_rtmp_adapter *pAd,
pTxD->SDPtr0 = BufBasePaLow;
pTxD->SDLen0 = firstDMALen; /* include padding */
- pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
+ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
pTxD->SDLen1 = pTxBlk->SrcBufLen;
pTxD->LastSec0 = 0;
pTxD->LastSec1 = (bIsLast) ? 1 : 0;
diff --git a/drivers/staging/rt2860/common/cmm_mac_pci.c b/drivers/staging/rt2860/common/cmm_mac_pci.c
index e26ba4942877..850f0fbc6d90 100644
--- a/drivers/staging/rt2860/common/cmm_mac_pci.c
+++ b/drivers/staging/rt2860/common/cmm_mac_pci.c
@@ -89,7 +89,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
if (pAd->TxDescRing[num].AllocVa == NULL) {
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
- DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
+ DBGPRINT_ERR("Failed to allocate a big buffer\n");
Status = NDIS_STATUS_RESOURCES;
break;
}
@@ -121,7 +121,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
if (pAd->TxBufSpace[num].AllocVa == NULL) {
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
- DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
+ DBGPRINT_ERR("Failed to allocate a big buffer\n");
Status = NDIS_STATUS_RESOURCES;
break;
}
@@ -197,7 +197,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
if (pAd->MgmtDescRing.AllocVa == NULL) {
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
- DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
+ DBGPRINT_ERR("Failed to allocate a big buffer\n");
Status = NDIS_STATUS_RESOURCES;
break;
}
@@ -251,7 +251,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
if (pAd->RxDescRing.AllocVa == NULL) {
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
- DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
+ DBGPRINT_ERR("Failed to allocate a big buffer\n");
Status = NDIS_STATUS_RESOURCES;
break;
}
@@ -304,7 +304,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
/* Error handling */
if (pDmaBuf->AllocVa == NULL) {
ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
- DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n"));
+ DBGPRINT_ERR("Failed to allocate RxRing's 1st buffer\n");
Status = NDIS_STATUS_RESOURCES;
break;
}
diff --git a/drivers/staging/rt2860/common/cmm_mac_usb.c b/drivers/staging/rt2860/common/cmm_mac_usb.c
index 72731cbb81df..64a65a460c29 100644
--- a/drivers/staging/rt2860/common/cmm_mac_usb.c
+++ b/drivers/staging/rt2860/common/cmm_mac_usb.c
@@ -236,7 +236,7 @@ int NICInitTransmit(struct rt_rtmp_adapter *pAd)
os_alloc_mem(pAd, (u8 **) (&pAd->MgmtDescRing.AllocVa),
pAd->MgmtDescRing.AllocSize);
if (pAd->MgmtDescRing.AllocVa == NULL) {
- DBGPRINT_ERR(("Failed to allocate a big buffer for MgmtDescRing!\n"));
+ DBGPRINT_ERR("Failed to allocate a big buffer for MgmtDescRing!\n");
Status = NDIS_STATUS_RESOURCES;
goto out1;
}
diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c
index e37b64b6a608..0040f45b629b 100644
--- a/drivers/staging/rt2860/common/cmm_wpa.c
+++ b/drivers/staging/rt2860/common/cmm_wpa.c
@@ -2794,7 +2794,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
/* Check length */
if ((len <= 0) || (pEid->Len != len)) {
- DBGPRINT_ERR(("%s : The length is invalid\n", __func__));
+ DBGPRINT_ERR("%s : The length is invalid\n", __func__);
return NULL;
}
/* Check WPA or WPA2 */
@@ -2803,14 +2803,13 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
u16 ucount;
if (len < sizeof(struct rt_rsnie)) {
- DBGPRINT_ERR(("%s : The length is too short for WPA\n",
- __func__));
+ DBGPRINT_ERR("%s : The length is too short for WPA\n", __func__);
return NULL;
}
/* Get the count of pairwise cipher */
ucount = cpu2le16(pRsnie->ucount);
if (ucount > 2) {
- DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
+ DBGPRINT_ERR("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount);
return NULL;
}
/* Get the group cipher */
@@ -2836,14 +2835,13 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
isWPA2 = TRUE;
if (len < sizeof(struct rt_rsnie2)) {
- DBGPRINT_ERR(("%s : The length is too short for WPA2\n",
- __func__));
+ DBGPRINT_ERR("%s : The length is too short for WPA2\n", __func__);
return NULL;
}
/* Get the count of pairwise cipher */
ucount = cpu2le16(pRsnie->ucount);
if (ucount > 2) {
- DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount));
+ DBGPRINT_ERR("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount);
return NULL;
}
/* Get the group cipher */
@@ -2863,7 +2861,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
offset = sizeof(struct rt_rsnie2) + (4 * (ucount - 1));
} else {
- DBGPRINT_ERR(("%s : Unknown IE (%d)\n", __func__, pEid->Eid));
+ DBGPRINT_ERR("%s : Unknown IE (%d)\n", __func__, pEid->Eid);
return NULL;
}
@@ -2872,8 +2870,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
len -= offset;
if (len < sizeof(struct rt_rsnie_auth)) {
- DBGPRINT_ERR(("%s : The length of RSNIE is too short\n",
- __func__));
+ DBGPRINT_ERR("%s : The length of RSNIE is too short\n", __func__);
return NULL;
}
/* pointer to AKM count */
@@ -2882,8 +2879,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
/* Get the count of pairwise cipher */
acount = cpu2le16(pAkm->acount);
if (acount > 2) {
- DBGPRINT_ERR(("%s : The count(%d) of AKM is invlaid\n",
- __func__, acount));
+ DBGPRINT_ERR("%s : The count(%d) of AKM is invlaid\n", __func__, acount);
return NULL;
}
/* Get the AKM suite */
@@ -2910,7 +2906,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie,
return pBuf;
}
} else {
- DBGPRINT_ERR(("%s : it can't get any more information beyond AKM \n", __func__));
+ DBGPRINT_ERR("%s : it can't get any more information beyond AKM \n", __func__);
return NULL;
}
diff --git a/drivers/staging/rt2860/common/ee_efuse.c b/drivers/staging/rt2860/common/ee_efuse.c
index 03412f5bc990..fed0ba452271 100644
--- a/drivers/staging/rt2860/common/ee_efuse.c
+++ b/drivers/staging/rt2860/common/ee_efuse.c
@@ -264,7 +264,7 @@ int set_eFuseGetFreeBlockCount_Proc(struct rt_rtmp_adapter *pAd, char *arg)
if (i == EFUSE_USAGE_MAP_END)
efusefreenum = 0;
}
- printk("efuseFreeNumber is %d\n", efusefreenum);
+ printk(KERN_DEBUG "efuseFreeNumber is %d\n", efusefreenum);
return TRUE;
}
@@ -274,16 +274,23 @@ int set_eFusedump_Proc(struct rt_rtmp_adapter *pAd, char *arg)
int i = 0;
if (!pAd->bUseEfuse)
return FALSE;
+
+ printk(KERN_DEBUG "Block 0: ");
+
for (i = 0; i < EFUSE_USAGE_MAP_END / 2; i++) {
InBuf[0] = 2 * i;
InBuf[1] = 2;
InBuf[2] = 0x0;
eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2);
- if (i % 4 == 0)
- printk("\nBlock %x:", i / 8);
- printk("%04x ", InBuf[2]);
+ if (i && i % 4 == 0) {
+ printk(KERN_CONT "\n");
+ printk(KERN_DEBUG "Block %x:", i / 8);
+ }
+ printk(KERN_CONT "%04x ", InBuf[2]);
}
+ printk(KERN_CONT "\n");
+
return TRUE;
}
diff --git a/drivers/staging/rt2860/common/mlme.c b/drivers/staging/rt2860/common/mlme.c
index 7300c6e9c175..d9c3fd5c2166 100644
--- a/drivers/staging/rt2860/common/mlme.c
+++ b/drivers/staging/rt2860/common/mlme.c
@@ -550,7 +550,7 @@ void MlmeHandler(struct rt_rtmp_adapter *pAd)
Elem->MsgLen = 0;
} else {
- DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
+ DBGPRINT_ERR("MlmeHandler: MlmeQueue empty\n");
}
}
@@ -4698,8 +4698,7 @@ BOOLEAN MlmeEnqueue(struct rt_rtmp_adapter *pAd,
/* First check the size, it MUST not exceed the mlme queue size */
if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
- DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n",
- MsgLen));
+ DBGPRINT_ERR("MlmeEnqueue: msg too large, size = %ld \n", MsgLen);
return FALSE;
}
@@ -4762,12 +4761,12 @@ BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd,
if (RTMP_TEST_FLAG
(pAd,
fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) {
- DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
+ DBGPRINT_ERR("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n");
return FALSE;
}
/* First check the size, it MUST not exceed the mlme queue size */
if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
- DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
+ DBGPRINT_ERR("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen);
return FALSE;
}
@@ -4777,7 +4776,7 @@ BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd,
{
if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) {
- DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType));
+ DBGPRINT_ERR("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType);
return FALSE;
}
}
@@ -4867,7 +4866,7 @@ void MlmeRestartStateMachine(struct rt_rtmp_adapter *pAd)
Elem->MsgLen = 0;
} else {
- DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
+ DBGPRINT_ERR("MlmeRestartStateMachine: MlmeQueue empty\n");
}
}
#endif /* RTMP_MAC_PCI // */
diff --git a/drivers/staging/rt2860/common/rt_rf.c b/drivers/staging/rt2860/common/rt_rf.c
index 519121d81040..2895447ffc48 100644
--- a/drivers/staging/rt2860/common/rt_rf.c
+++ b/drivers/staging/rt2860/common/rt_rf.c
@@ -131,8 +131,7 @@ int RT30xxReadRFRegister(struct rt_rtmp_adapter *pAd,
}
}
if (rfcsr.field.RF_CSR_KICK == BUSY) {
- DBGPRINT_ERR(("RF read R%d=0x%x fail, i[%d], k[%d]\n", regID,
- rfcsr.word, i, k));
+ DBGPRINT_ERR("RF read R%d=0x%x fail, i[%d], k[%d]\n", regID, rfcsr.word, i, k);
return STATUS_UNSUCCESSFUL;
}
diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c
index 3628e85802e3..d359a14f5d4d 100644
--- a/drivers/staging/rt2860/common/rtmp_init.c
+++ b/drivers/staging/rt2860/common/rtmp_init.c
@@ -169,14 +169,14 @@ int RTMPAllocAdapterBlock(void *handle,
pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG);
if (pBeaconBuf == NULL) {
Status = NDIS_STATUS_FAILURE;
- DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n"));
+ DBGPRINT_ERR("Failed to allocate memory - BeaconBuf!\n");
break;
}
NdisZeroMemory(pBeaconBuf, MAX_BEACON_SIZE);
Status = AdapterBlockAllocateMemory(handle, (void **) & pAd);
if (Status != NDIS_STATUS_SUCCESS) {
- DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n"));
+ DBGPRINT_ERR("Failed to allocate memory - ADAPTER\n");
break;
}
pAd->BeaconBuf = pBeaconBuf;
@@ -785,8 +785,7 @@ void NICReadEEPROMParameters(struct rt_rtmp_adapter *pAd, u8 *mac_addr)
Version.field.Version, Version.field.FaeReleaseNumber));
if (Version.field.Version > VALID_EEPROM_VERSION) {
- DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",
- Version.field.Version, VALID_EEPROM_VERSION));
+ DBGPRINT_ERR("E2PROM: WRONG VERSION 0x%x, should be %d\n", Version.field.Version, VALID_EEPROM_VERSION);
/*pAd->SystemErrorBitmap |= 0x00000001;
// hard-code default value when no proper E2PROM installed
@@ -2911,7 +2910,7 @@ void RTMPSetTimer(struct rt_ralink_timer *pTimer, unsigned long Value)
RTMP_OS_Add_Timer(&pTimer->TimerObj, Value);
}
} else {
- DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n"));
+ DBGPRINT_ERR("RTMPSetTimer failed, Timer hasn't been initialize!\n");
}
}
@@ -2947,7 +2946,7 @@ void RTMPModTimer(struct rt_ralink_timer *pTimer, unsigned long Value)
RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value);
}
} else {
- DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n"));
+ DBGPRINT_ERR("RTMPModTimer failed, Timer hasn't been initialize!\n");
}
}
@@ -2989,7 +2988,7 @@ void RTMPCancelTimer(struct rt_ralink_timer *pTimer, OUT BOOLEAN * pCancelled)
RtmpTimerQRemove(pTimer->pAd, pTimer);
#endif /* RTMP_TIMER_TASK_SUPPORT // */
} else {
- DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n"));
+ DBGPRINT_ERR("RTMPCancelTimer failed, Timer hasn't been initialize!\n");
}
}
@@ -3251,8 +3250,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd,
/* Load 8051 firmware */
Status = NICLoadFirmware(pAd);
if (Status != NDIS_STATUS_SUCCESS) {
- DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n",
- Status));
+ DBGPRINT_ERR("NICLoadFirmware failed, Status[=0x%08x]\n", Status);
goto err1;
}
@@ -3268,8 +3266,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd,
Status = RTMPAllocTxRxRingMemory(pAd);
if (Status != NDIS_STATUS_SUCCESS) {
- DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n",
- Status));
+ DBGPRINT_ERR("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status);
goto err1;
}
@@ -3284,7 +3281,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd,
Status = MlmeInit(pAd);
if (Status != NDIS_STATUS_SUCCESS) {
- DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status));
+ DBGPRINT_ERR("MlmeInit failed, Status[=0x%08x]\n", Status);
goto err2;
}
/* Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default */
@@ -3309,8 +3306,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd,
/* */
Status = NICInitializeAdapter(pAd, TRUE);
if (Status != NDIS_STATUS_SUCCESS) {
- DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n",
- Status));
+ DBGPRINT_ERR("NICInitializeAdapter failed, Status[=0x%08x]\n", Status);
if (Status != NDIS_STATUS_SUCCESS)
goto err3;
}
diff --git a/drivers/staging/rt2860/common/rtmp_mcu.c b/drivers/staging/rt2860/common/rtmp_mcu.c
index 844d4b987b78..80fa4160ed62 100644
--- a/drivers/staging/rt2860/common/rtmp_mcu.c
+++ b/drivers/staging/rt2860/common/rtmp_mcu.c
@@ -267,7 +267,7 @@ int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd,
} while (i++ < 100);
if (i > 100) {
- DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
+ DBGPRINT_ERR("H2M_MAILBOX still hold by MCU. command fail\n");
return FALSE;
}
@@ -296,7 +296,7 @@ int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd,
#ifdef RTMP_MAC_PCI
#endif /* RTMP_MAC_PCI // */
{
- DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
+ DBGPRINT_ERR("H2M_MAILBOX still hold by MCU. command fail\n");
}
return FALSE;
}
diff --git a/drivers/staging/rt2860/common/spectrum.c b/drivers/staging/rt2860/common/spectrum.c
index 2d5f847e6cc6..1dfb802aab9a 100644
--- a/drivers/staging/rt2860/common/spectrum.c
+++ b/drivers/staging/rt2860/common/spectrum.c
@@ -1837,7 +1837,7 @@ static void PeerChSwAnnAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_
}
if (index >= pAd->ChannelListNum) {
- DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
+ DBGPRINT_ERR("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum);
}
}
}
diff --git a/drivers/staging/rt2860/mlme.h b/drivers/staging/rt2860/mlme.h
index 01414c3b4889..cd1ee3d7a91d 100644
--- a/drivers/staging/rt2860/mlme.h
+++ b/drivers/staging/rt2860/mlme.h
@@ -32,8 +32,9 @@
Revision History:
Who When What
-------- ---------- ------------------------------
- John Chang 2003-08-28 Created
- John Chang 2004-09-06 modified for RT2600
+ John Chang 2003-08-28 Created
+ John Chang 2004-09-06 modified for RT2600
+ Justin P. Mattock 11/07/2010 Fix typos in comments
*/
#ifndef __MLME_H__
@@ -41,7 +42,7 @@
#include "rtmp_dot11.h"
-/* maximum supported capability information - */
+/* maximum supported capability information */
/* ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot */
#define SUPPORTED_CAPABILITY_INFO 0x0533
@@ -77,7 +78,7 @@
#define CW_MAX_IN_BITS 10 /* actual CwMax = 2^CW_MAX_IN_BITS - 1 */
/* Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). */
-/* SHould not refer to this constant anymore */
+/* Should not refer to this constant anymore */
/*#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm */
#define RSSI_FOR_MID_TX_POWER -55 /* -55 db is considered mid-distance */
#define RSSI_FOR_LOW_TX_POWER -45 /* -45 db is considered very short distance and */
@@ -123,7 +124,7 @@
#define TID_MAC_HASH_INDEX(Addr, TID) (TID_MAC_HASH(Addr, TID) % HASH_TABLE_SIZE)
/* LED Control */
-/* assoiation ON. one LED ON. another blinking when TX, OFF when idle */
+/* association ON. one LED ON. another blinking when TX, OFF when idle */
/* no association, both LED off */
#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46)
#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46)
@@ -284,8 +285,8 @@ struct PACKED rt_ht_capability_ie {
/* 802.11n draft3 related structure definitions. */
/* 7.3.2.60 */
-#define dot11OBSSScanPassiveDwell 20 /* in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. */
-#define dot11OBSSScanActiveDwell 10 /* in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. */
+#define dot11OBSSScanPassiveDwell 20 /* in TU. min amount of time that the STA continuously scans each channel when performing an active OBSS scan. */
+#define dot11OBSSScanActiveDwell 10 /* in TU.min amount of time that the STA continuously scans each channel when performing an passive OBSS scan. */
#define dot11BSSWidthTriggerScanInterval 300 /* in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. */
#define dot11OBSSScanPassiveTotalPerChannel 200 /* in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. */
#define dot11OBSSScanActiveTotalPerChannel 20 /*in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan */
@@ -325,7 +326,7 @@ struct rt_trigger_eventa {
};
/* 20/40 trigger event table */
-/* If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. */
+/* If one Event (A) is deleted or created, or if Event (B) is detected or not detected, STA should send 2040BSSCoexistence to AP. */
#define MAX_TRIGGER_EVENT 64
struct rt_trigger_event_tab {
u8 EventANo;
@@ -357,14 +358,14 @@ struct PACKED rt_bss_2040_intolerant_ch_report {
u8 ChList[0];
};
-/* The structure for channel switch annoucement IE. This is in 802.11n D3.03 */
+/* The structure for channel switch announcement IE. This is in 802.11n D3.03 */
struct PACKED rt_cha_switch_announce_ie {
u8 SwitchMode; /*channel switch mode */
u8 NewChannel; /* */
u8 SwitchCount; /* */
};
-/* The structure for channel switch annoucement IE. This is in 802.11n D3.03 */
+/* The structure for channel switch announcement IE. This is in 802.11n D3.03 */
struct PACKED rt_sec_cha_offset_ie {
u8 SecondaryChannelOffset; /* 1: Secondary above, 3: Secondary below, 0: no Secondary */
};
@@ -377,7 +378,7 @@ struct rt_ht_phy_info {
u8 MCSSet[16];
};
-/*This structure substracts ralink supports from all 802.11n-related features. */
+/*This structure subtracts ralink supports from all 802.11n-related features. */
/*Features not listed here but contained in 802.11n spec are not supported in rt2860. */
struct rt_ht_capability {
u16 ChannelWidth:1;
@@ -387,14 +388,14 @@ struct rt_ht_capability {
u16 ShortGIfor40:1; /*for40MHz */
u16 TxSTBC:1;
u16 RxSTBC:2; /* 2 bits */
- u16 AmsduEnable:1; /* Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n */
+ u16 AmsduEnable:1; /* Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benefit of 802.11n */
u16 AmsduSize:1; /* Max receiving A-MSDU size */
u16 rsv:5;
/*Substract from Addiont HT INFO IE */
u8 MaxRAmpduFactor:2;
u8 MpduDensity:3;
- u8 ExtChanOffset:2; /* Please not the difference with following u8 NewExtChannelOffset; from 802.11n */
+ u8 ExtChanOffset:2; /* Please note the difference with following u8 NewExtChannelOffset; from 802.11n */
u8 RecomWidth:1;
u16 OperaionMode:2;
@@ -481,7 +482,7 @@ struct PACKED rt_ba_parm {
u16 AMSDUSupported:1; /* 0: not permitted 1: permitted */
u16 BAPolicy:1; /* 1: immediately BA 0:delayed BA */
u16 TID:4; /* value of TC os TS */
- u16 BufSize:10; /* number of buffe of size 2304 octetsr */
+ u16 BufSize:10; /* number of buffer of size 2304 octetsr */
};
/* 2-byte BA Starting Seq CONTROL field */
@@ -551,7 +552,7 @@ struct PACKED rt_frame_mtba_req {
BASEQ_CONTROL BAStartingSeq;
};
-/* Compressed format is mandantory in HT STA */
+/* Compressed format is mandatory in HT STA */
struct PACKED rt_frame_mtba {
struct rt_frame_control FC;
u16 Duration;
@@ -647,7 +648,7 @@ struct PACKED rt_frame_ba {
u8 bitmask[8];
};
-/* Radio Measuement Request Frame Format */
+/* Radio Measurement Request Frame Format */
struct PACKED rt_frame_rm_req_action {
struct rt_header_802_11 Hdr;
u8 Category;
@@ -709,7 +710,7 @@ struct rt_edca_parm {
u8 Cwmin[4];
u8 Cwmax[4];
u16 Txop[4]; /* in unit of 32-us */
- BOOLEAN bACM[4]; /* 1: Admission Control of AC_BK is mandattory */
+ BOOLEAN bACM[4]; /* 1: Admission Control of AC_BK is mandatory */
};
/* QBSS LOAD information from QAP's BEACON/ProbeRsp */
@@ -757,7 +758,7 @@ struct rt_wpa_ie {
struct rt_bss_entry {
u8 Bssid[MAC_ADDR_LEN];
u8 Channel;
- u8 CentralChannel; /*Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. */
+ u8 CentralChannel; /*Store the wide-band central channel for 40MHz. used in 40MHz AP. Or this is the same as Channel. */
u8 BssType;
u16 AtimWin;
u16 BeaconPeriod;
@@ -855,7 +856,7 @@ struct rt_state_machine {
STATE_MACHINE_FUNC *TransFunc;
};
-/* MLME AUX data structure that hold temporarliy settings during a connection attempt. */
+/* MLME AUX data structure that holds temporarliy settings during a connection attempt. */
/* Once this attemp succeeds, all settings will be copy to pAd->StaActive. */
/* A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of */
/* several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely */
@@ -996,7 +997,7 @@ struct PACKED rt_rtmp_tx_rate_switch {
#define MAC_TABLE_ASSOC_TIMEOUT 5 /* unit: sec */
#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE)
-/* AP shall drop the sta if contine Tx fail count reach it. */
+/* AP shall drop the sta if continue Tx fail count reach it. */
#define MAC_ENTRY_LIFE_CHECK_CNT 20 /* packet cnt. */
/* Value domain of pMacEntry->Sst */
diff --git a/drivers/staging/rt2860/oid.h b/drivers/staging/rt2860/oid.h
index 1704c27b2736..5a25f0d3cfeb 100644
--- a/drivers/staging/rt2860/oid.h
+++ b/drivers/staging/rt2860/oid.h
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- Name Date Modification logs
+ Name Date Modification logs
+ Justin P. Mattock 11/07/2010 Fix typos in comments
*/
#ifndef _OID_H_
#define _OID_H_
@@ -78,7 +79,7 @@
#define NDIS_802_11_LENGTH_RATES 8
#define NDIS_802_11_LENGTH_RATES_EX 16
#define MAC_ADDR_LENGTH 6
-/*#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc */
+/*#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination */
#define MAX_NUM_OF_CHS 54 /* 14 channels @2.4G + 12@UNII(lower/middle) + 16@HiperLAN2 + 11@UNII(upper) + 0 @Japan + 1 as NULL termination */
#define MAX_NUMBER_OF_EVENT 10 /* entry # in EVENT table */
#define MAX_NUMBER_OF_MAC 32 /* if MAX_MBSSID_NUM is 8, this value can't be larger than 211 */
@@ -87,7 +88,7 @@
#define MAX_NUMBER_OF_DLS_ENTRY 4
#define RT_QUERY_SIGNAL_CONTEXT 0x0402
-#define RT_SET_IAPP_PID 0x0404
+#define RT_SET_IAPP_PID 0x0404
#define RT_SET_APD_PID 0x0405
#define RT_SET_DEL_MAC_ENTRY 0x0406
#define RT_QUERY_EVENT_TABLE 0x0407
@@ -610,7 +611,7 @@ struct rt_802_11_event_log {
struct rt_802_11_event_table {
unsigned long Num;
- unsigned long Rsv; /* to align Log[] at LARGE_INEGER boundary */
+ unsigned long Rsv; /* to align Log[] at LARGE_INTEGER boundary */
struct rt_802_11_event_log Log[MAX_NUMBER_OF_EVENT];
};
@@ -721,9 +722,9 @@ struct rt_802_11_tx_rates {
#define AUTH_FAIL 0x4 /* Open authentication fail */
#define AUTH_FAIL_KEYS 0x5 /* Shared authentication fail */
#define ASSOC_FAIL 0x6 /* Association failed */
-#define EAP_MIC_FAILURE 0x7 /* Deauthencation because MIC failure */
-#define EAP_4WAY_TIMEOUT 0x8 /* Deauthencation on 4-way handshake timeout */
-#define EAP_GROUP_KEY_TIMEOUT 0x9 /* Deauthencation on group key handshake timeout */
+#define EAP_MIC_FAILURE 0x7 /* Deauthentication because MIC failure */
+#define EAP_4WAY_TIMEOUT 0x8 /* Deauthentication on 4-way handshake timeout */
+#define EAP_GROUP_KEY_TIMEOUT 0x9 /* Deauthentication on group key handshake timeout */
#define EAP_SUCCESS 0xa /* EAP succeed */
#define DETECT_RADAR_SIGNAL 0xb /* Radar signal occur in current channel */
#define EXTRA_INFO_MAX 0xb /* Indicate Last OID */
diff --git a/drivers/staging/rt2860/pci_main_dev.c b/drivers/staging/rt2860/pci_main_dev.c
index 321facd6b0ab..25fbb1880ff2 100644
--- a/drivers/staging/rt2860/pci_main_dev.c
+++ b/drivers/staging/rt2860/pci_main_dev.c
@@ -31,7 +31,8 @@
Create and register network interface for PCI based chipsets in Linux platform.
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix typos in some comments
-------- ---------- ----------------------------------------------
*/
@@ -40,8 +41,8 @@
#include <linux/slab.h>
/* Following information will be show when you run 'modinfo' */
-/* *** If you have a solution for the bug in current version of driver, please mail to me. */
-/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** */
+/* If you have a solution for a bug in current version of driver, please e-mail me. */
+/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. */
MODULE_AUTHOR("Jett Chen <jett_chen@ralinktech.com>");
MODULE_DESCRIPTION("RT2860/RT3090 Wireless Lan Linux Driver");
MODULE_LICENSE("GPL");
@@ -50,9 +51,6 @@ MODULE_ALIAS("rt3090sta");
/* */
/* Function declarations */
/* */
-extern int rt28xx_close(IN struct net_device *net_dev);
-extern int rt28xx_open(struct net_device *net_dev);
-
static void __devexit rt2860_remove_one(struct pci_dev *pci_dev);
static int __devinit rt2860_probe(struct pci_dev *pci_dev,
const struct pci_device_id *ent);
@@ -205,7 +203,7 @@ static int rt2860_resume(struct pci_dev *pci_dev)
/* initialize device before it's used by a driver */
if (pci_enable_device(pci_dev)) {
- printk("pci enable fail!\n");
+ printk(KERN_ERR "rt2860: pci enable fail!\n");
return 0;
}
@@ -599,7 +597,7 @@ void RTMPInitPCIeLinkCtrlValue(struct rt_rtmp_adapter *pAd)
DBGPRINT_RAW(RT_DEBUG_ERROR,
(" AUX_CTRL = 0x%32x\n", MacValue));
- /* for RT30xx F and after, PCIe infterface, and for power solution 3 */
+ /* for RT30xx F and after, PCIe interface, and for power solution 3 */
if ((IS_VERSION_AFTER_F(pAd))
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode >= 2)
&& (pAd->StaCfg.PSControl.field.rt30xxPowerMode <= 3)) {
@@ -902,7 +900,7 @@ void RTMPPCIeLinkCtrlValueRestore(struct rt_rtmp_adapter *pAd, u8 Level)
Configuration);
if ((Configuration != 0) && (Configuration != 0xFFFF)) {
Configuration &= 0xfefc;
- /* If call from interface down, restore to orginial setting. */
+ /* If call from interface down, restore to original setting. */
if (Level == RESTORE_CLOSE)
Configuration |= pAd->HostLnkCtrlConfiguration;
else
@@ -924,7 +922,7 @@ void RTMPPCIeLinkCtrlValueRestore(struct rt_rtmp_adapter *pAd, u8 Level)
Configuration);
if ((Configuration != 0) && (Configuration != 0xFFFF)) {
Configuration &= 0xfefc;
- /* If call from interface down, restore to orginial setting. */
+ /* If call from interface down, restore to original setting. */
if (Level == RESTORE_CLOSE)
Configuration |= pAd->RLnkCtrlConfiguration;
else
@@ -1106,12 +1104,12 @@ void RTMPrt3xSetPCIePowerLinkCtrl(struct rt_rtmp_adapter *pAd)
if (pos != 0)
pAd->HostLnkCtrlOffset = pos + PCI_EXP_LNKCTL;
- /* If configurared to turn on L1. */
+ /* If configured to turn on L1. */
HostConfiguration = 0;
if (pAd->StaCfg.PSControl.field.rt30xxForceASPMTest == 1) {
DBGPRINT(RT_DEBUG_TRACE, ("Enter,PSM : Force ASPM\n"));
- /* Skip non-exist deice right away */
+ /* Skip non-exist device right away */
if ((pAd->HostLnkCtrlOffset != 0)) {
PCI_REG_READ_WORD(pObj->parent_pci_dev,
pAd->HostLnkCtrlOffset,
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index abfeea11721d..728864e18a18 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -321,7 +321,7 @@ int RTMPCloneNdisPacket(struct rt_rtmp_adapter *pAd,
RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS);
- printk("###Clone###\n");
+ printk(KERN_DEBUG "###Clone###\n");
return NDIS_STATUS_SUCCESS;
}
@@ -343,9 +343,8 @@ int RTMPAllocateNdisPacket(struct rt_rtmp_adapter *pAd,
RTMP_PKT_TAIL_PADDING);
if (pPacket == NULL) {
*ppPacket = NULL;
-#ifdef DEBUG
- printk("RTMPAllocateNdisPacket Fail\n");
-#endif
+ pr_devel("RTMPAllocateNdisPacket Fail\n");
+
return NDIS_STATUS_FAILURE;
}
/* 2. clone the frame content */
@@ -601,15 +600,15 @@ void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen)
return;
pt = pSrcBufVA;
- printk("%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen);
+ printk(KERN_DEBUG "%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen);
for (x = 0; x < SrcBufLen; x++) {
if (x % 16 == 0)
- printk("0x%04x : ", x);
- printk("%02x ", ((unsigned char)pt[x]));
+ printk(KERN_DEBUG "0x%04x : ", x);
+ printk(KERN_DEBUG "%02x ", ((unsigned char)pt[x]));
if (x % 16 == 15)
- printk("\n");
+ printk(KERN_DEBUG "\n");
}
- printk("\n");
+ printk(KERN_DEBUG "\n");
}
/*
@@ -767,13 +766,13 @@ void send_monitor_packets(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk)
/* QOS */
if (pRxBlk->pHeader->FC.SubType & 0x08) {
header_len += 2;
- /* Data skip QOS contorl field */
+ /* Data skip QOS control field */
pRxBlk->DataSize -= 2;
}
/* Order bit: A-Ralink or HTC+ */
if (pRxBlk->pHeader->FC.Order) {
header_len += 4;
- /* Data skip HTC contorl field */
+ /* Data skip HTC control field */
pRxBlk->DataSize -= 4;
}
/* Copy Header */
@@ -854,7 +853,7 @@ void send_monitor_packets(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk)
RSSI1,
RSSI_1),
ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2,
- RSSI_2));;
+ RSSI_2));
ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
ph->signal.status = 0;
@@ -926,7 +925,7 @@ int RtmpOSIRQRequest(struct net_device *pNetDev)
request_irq(_pObj->pci_dev->irq, rt2860_interrupt, SA_SHIRQ,
(net_dev)->name, (net_dev));
if (retval != 0)
- printk("RT2860: request_irq ERROR(%d)\n", retval);
+ printk(KERN_ERR "rt2860: request_irq ERROR(%d)\n", retval);
}
return retval;
@@ -1022,7 +1021,7 @@ int RtmpOSTaskKill(struct rt_rtmp_os_task *pTask)
}
#else
CHECK_PID_LEGALITY(pTask->taskPID) {
- printk("Terminate the task(%s) with pid(%d)!\n",
+ printk(KERN_INFO "Terminate the task(%s) with pid(%d)!\n",
pTask->taskName, GET_PID_NUMBER(pTask->taskPID));
mb();
pTask->task_killed = 1;
@@ -1175,7 +1174,7 @@ int RtmpOSNetDevAddrSet(struct net_device *pNetDev, u8 *pMacAddr)
net_dev = pNetDev;
GET_PAD_FROM_NET_DEV(pAd, net_dev);
- /* work-around for the SuSE due to it has it's own interface name management system. */
+ /* work-around for SuSE, due to them having their own interface name management system. */
{
NdisZeroMemory(pAd->StaCfg.dev_name, 16);
NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name,
@@ -1300,7 +1299,7 @@ int RtmpOSNetDevAttach(struct net_device *pNetDev,
int ret, rtnl_locked = FALSE;
DBGPRINT(RT_DEBUG_TRACE, ("RtmpOSNetDevAttach()--->\n"));
- /* If we need hook some callback function to the net device structrue, now do it. */
+ /* If we need hook some callback function to the net device structure, now do it. */
if (pDevOpHook) {
struct rt_rtmp_adapter *pAd = NULL;
@@ -1351,10 +1350,10 @@ struct net_device *RtmpOSNetDevCreate(struct rt_rtmp_adapter *pAd,
return NULL;
}
- /* find a available interface name, max 32 interfaces */
+ /* find an available interface name, max 32 interfaces */
status = RtmpOSNetDevRequestName(pAd, pNetDev, pNamePrefix, devNum);
if (status != NDIS_STATUS_SUCCESS) {
- /* error! no any available ra name can be used! */
+ /* error! no available ra name can be used! */
DBGPRINT(RT_DEBUG_ERROR,
("Assign interface name (%s with suffix 0~32) failed...\n",
pNamePrefix));
diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h
index 5acedf18b1ab..92ff5438e777 100644
--- a/drivers/staging/rt2860/rt_linux.h
+++ b/drivers/staging/rt2860/rt_linux.h
@@ -30,7 +30,8 @@
Abstract:
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix typo in a comment
--------- ---------- ----------------------------------------------
*/
@@ -422,11 +423,7 @@ do{ \
#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt)
-#define DBGPRINT_ERR(Fmt) \
-{ \
- printk("ERROR! "); \
- printk Fmt; \
-}
+#define DBGPRINT_ERR(fmt, args...) printk(KERN_ERR fmt, ##args)
#define DBGPRINT_S(Status, Fmt) \
{ \
@@ -726,7 +723,7 @@ void linux_pci_unmap_single(struct rt_rtmp_adapter *pAd, dma_addr_t dma_addr,
#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7])
/* */
-/* Sepcific Pakcet Type definition */
+/* Specific Packet Type definition */
/* */
#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11
diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c
index ad60ceaf4b88..701561d6b6fd 100644
--- a/drivers/staging/rt2860/rt_main_dev.c
+++ b/drivers/staging/rt2860/rt_main_dev.c
@@ -31,7 +31,8 @@
Create and register network interface.
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix typos in comments
-------- ---------- ----------------------------------------------
*/
@@ -101,8 +102,8 @@ int MainVirtualIF_close(IN struct net_device *net_dev)
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) {
struct rt_mlme_disassoc_req DisReq;
struct rt_mlme_queue_elem *MsgElem =
- (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem),
- MEM_ALLOC_FLAG);
+ kmalloc(sizeof(struct rt_mlme_queue_elem),
+ MEM_ALLOC_FLAG);
if (MsgElem) {
COPY_MAC_ADDR(DisReq.Addr,
@@ -234,7 +235,7 @@ int rt28xx_close(struct net_device *dev)
RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_CLOSE);
#endif /* RTMP_MAC_PCI // */
- /* If dirver doesn't wake up firmware here, */
+ /* If driver doesn't wake up firmware here, */
/* NICLoadFirmware will hang forever when interface is up again. */
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) {
AsicForceWakeup(pAd, TRUE);
@@ -310,8 +311,8 @@ int rt28xx_close(struct net_device *dev)
RTMP_ASIC_INTERRUPT_DISABLE(pAd);
}
/* Receive packets to clear DMA index after disable interrupt. */
- /*RTMPHandleRxDoneInterrupt(pAd); */
- /* put to radio off to save power when driver unload. After radiooff, can't write /read register. So need to finish all */
+ /* RTMPHandleRxDoneInterrupt(pAd); */
+ /* put radio off to save power when driver unloads. After radiooff, can't write/read register, so need to finish all. */
/* register access before Radio off. */
brc = RT28xxPciAsicRadioOff(pAd, RTMP_HALT, 0);
@@ -420,7 +421,7 @@ int rt28xx_open(struct net_device *dev)
{
u32 reg = 0;
RTMP_IO_READ32(pAd, 0x1300, &reg); /* clear garbage interrupts */
- printk("0x1300 = %08x\n", reg);
+ printk(KERN_DEBUG "0x1300 = %08x\n", reg);
}
{
@@ -724,7 +725,8 @@ Note:
int AdapterBlockAllocateMemory(void *handle, void ** ppAd)
{
- *ppAd = (void *)vmalloc(sizeof(struct rt_rtmp_adapter)); /*pci_alloc_consistent(pci_dev, sizeof(struct rt_rtmp_adapter), phy_addr); */
+ *ppAd = vmalloc(sizeof(struct rt_rtmp_adapter));
+ /* pci_alloc_consistent(pci_dev, sizeof(struct rt_rtmp_adapter), phy_addr); */
if (*ppAd) {
NdisZeroMemory(*ppAd, sizeof(struct rt_rtmp_adapter));
diff --git a/drivers/staging/rt2860/rt_pci_rbus.c b/drivers/staging/rt2860/rt_pci_rbus.c
index 3004be6da003..e5fb67cd9a68 100644
--- a/drivers/staging/rt2860/rt_pci_rbus.c
+++ b/drivers/staging/rt2860/rt_pci_rbus.c
@@ -31,7 +31,8 @@
Create and register network interface.
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix a typo
-------- ---------- ----------------------------------------------
*/
@@ -356,7 +357,7 @@ static void mgmt_dma_done_tasklet(unsigned long data)
RTMPHandleMgmtRingDmaDoneInterrupt(pAd);
- /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, no any */
+ /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, without any */
/* bug report output */
RTMP_INT_LOCK(&pAd->irq_lock, flags);
/*
@@ -787,7 +788,7 @@ IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance)
}
/*
- * invaild or writeback cache
+ * invalid or writeback cache
* and convert virtual address to physical address
*/
dma_addr_t linux_pci_map_single(struct rt_rtmp_adapter *pAd, void *ptr,
diff --git a/drivers/staging/rt2860/rt_usb.c b/drivers/staging/rt2860/rt_usb.c
index bcfc0f54d2aa..eb037d2e04a2 100644
--- a/drivers/staging/rt2860/rt_usb.c
+++ b/drivers/staging/rt2860/rt_usb.c
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- Name Date Modification logs
+ Name Date Modification logs
+ Justin P. Mattock 11/07/2010 Fix some typos.
*/
@@ -40,25 +41,25 @@
void dump_urb(struct urb *purb)
{
- printk("urb :0x%08lx\n", (unsigned long)purb);
- printk("\tdev :0x%08lx\n", (unsigned long)purb->dev);
- printk("\t\tdev->state :0x%d\n", purb->dev->state);
- printk("\tpipe :0x%08x\n", purb->pipe);
- printk("\tstatus :%d\n", purb->status);
- printk("\ttransfer_flags :0x%08x\n", purb->transfer_flags);
- printk("\ttransfer_buffer :0x%08lx\n",
+ printk(KERN_DEBUG "urb :0x%08lx\n", (unsigned long)purb);
+ printk(KERN_DEBUG "\tdev :0x%08lx\n", (unsigned long)purb->dev);
+ printk(KERN_DEBUG "\t\tdev->state :0x%d\n", purb->dev->state);
+ printk(KERN_DEBUG "\tpipe :0x%08x\n", purb->pipe);
+ printk(KERN_DEBUG "\tstatus :%d\n", purb->status);
+ printk(KERN_DEBUG "\ttransfer_flags :0x%08x\n", purb->transfer_flags);
+ printk(KERN_DEBUG "\ttransfer_buffer :0x%08lx\n",
(unsigned long)purb->transfer_buffer);
- printk("\ttransfer_buffer_length:%d\n", purb->transfer_buffer_length);
- printk("\tactual_length :%d\n", purb->actual_length);
- printk("\tsetup_packet :0x%08lx\n",
+ printk(KERN_DEBUG "\ttransfer_buffer_length:%d\n", purb->transfer_buffer_length);
+ printk(KERN_DEBUG "\tactual_length :%d\n", purb->actual_length);
+ printk(KERN_DEBUG "\tsetup_packet :0x%08lx\n",
(unsigned long)purb->setup_packet);
- printk("\tstart_frame :%d\n", purb->start_frame);
- printk("\tnumber_of_packets :%d\n", purb->number_of_packets);
- printk("\tinterval :%d\n", purb->interval);
- printk("\terror_count :%d\n", purb->error_count);
- printk("\tcontext :0x%08lx\n",
+ printk(KERN_DEBUG "\tstart_frame :%d\n", purb->start_frame);
+ printk(KERN_DEBUG "\tnumber_of_packets :%d\n", purb->number_of_packets);
+ printk(KERN_DEBUG "\tinterval :%d\n", purb->interval);
+ printk(KERN_DEBUG "\terror_count :%d\n", purb->error_count);
+ printk(KERN_DEBUG "\tcontext :0x%08lx\n",
(unsigned long)purb->context);
- printk("\tcomplete :0x%08lx\n\n",
+ printk(KERN_DEBUG "\tcomplete :0x%08lx\n\n",
(unsigned long)purb->complete);
}
@@ -279,7 +280,7 @@ static void rtusb_dataout_complete(unsigned long data)
&& !RTUSB_TEST_BULK_FLAG(pAd,
(fRTUSB_BULK_OUT_DATA_FRAG <<
BulkOutPipeId))) {
- /* Indicate There is data avaliable */
+ /* Indicate There is data available */
RTUSB_SET_BULK_FLAG(pAd,
(fRTUSB_BULK_OUT_DATA_NORMAL <<
BulkOutPipeId));
@@ -335,7 +336,7 @@ static void rtusb_null_frame_done_tasklet(unsigned long data)
}
/* Always call Bulk routine, even reset bulk. */
- /* The protectioon of rest bulk should be in BulkOut routine */
+ /* The protection of rest bulk should be in BulkOut routine */
RTUSBKickBulkOut(pAd);
}
@@ -383,7 +384,7 @@ static void rtusb_rts_frame_done_tasklet(unsigned long data)
RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]);
/* Always call Bulk routine, even reset bulk. */
- /* The protectioon of rest bulk should be in BulkOut routine */
+ /* The protection of rest bulk should be in BulkOut routine */
RTUSBKickBulkOut(pAd);
}
@@ -427,7 +428,7 @@ static void rtusb_pspoll_frame_done_tasklet(unsigned long data)
RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]);
/* Always call Bulk routine, even reset bulk. */
- /* The protectioon of rest bulk should be in BulkOut routine */
+ /* The protection of rest bulk should be in BulkOut routine */
RTUSBKickBulkOut(pAd);
}
@@ -575,7 +576,7 @@ static void rtusb_mgmt_dma_done_tasklet(unsigned long data)
} else {
/* Always call Bulk routine, even reset bulk. */
- /* The protectioon of rest bulk should be in BulkOut routine */
+ /* The protection of rest bulk should be in BulkOut routine */
if (pAd->MgmtRing.TxSwFreeIdx <
MGMT_RING_SIZE
/* pMLMEContext->bWaitingBulkOut == TRUE */) {
diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h
index ca54e53b6603..70daaa4f9ac2 100644
--- a/drivers/staging/rt2860/rtmp.h
+++ b/drivers/staging/rt2860/rtmp.h
@@ -31,11 +31,12 @@
Miniport generic portion header file
Revision History:
- Who When What
+ Who When What
-------- ---------- ----------------------------------------------
- Paul Lin 2002-08-01 created
- James Tan 2002-09-06 modified (Revise NTCRegTable)
- John Chang 2004-09-06 modified for RT2600
+ Paul Lin 2002-08-01 created
+ James Tan 2002-09-06 modified (Revise NTCRegTable)
+ John Chang 2004-09-06 modified for RT2600
+ Justin P. Mattock 11/07/2010 Fix some typos
*/
#ifndef __RTMP_H__
#define __RTMP_H__
@@ -337,7 +338,7 @@ struct rt_rtmp_sg_list {
#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP)
#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE))
-/* if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required */
+/* if original Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required */
#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \
{ \
if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) { \
@@ -466,7 +467,7 @@ struct rt_rtmp_dmabuf {
/* Control block (Descriptor) for all ring descriptor DMA operation, buffer must be */
/* contiguous physical memory. char stored the binding Rx packet descriptor */
/* which won't be released, driver has to wait until upper layer return the packet */
-/* before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair */
+/* before giving up this rx ring descriptor to ASIC. NDIS_BUFFER is associated pair */
/* to describe the packet buffer. For Tx, char stored the tx packet descriptor */
/* which driver should ACK upper layer when the tx is physically done or failed. */
/* */
@@ -602,7 +603,7 @@ struct rt_counter_ralink {
};
struct rt_counter_drs {
- /* to record the each TX rate's quality. 0 is best, the bigger the worse. */
+ /* record each TX rate's quality. 0 is best, the bigger the worse. */
u16 TxQuality[MAX_STEP_OF_TX_RATE_SWITCH];
u8 PER[MAX_STEP_OF_TX_RATE_SWITCH];
u8 TxRateUpPenalty; /* extra # of second penalty due to last unstable condition */
@@ -719,7 +720,7 @@ struct rt_fragment_frame {
/* Packet information for NdisQueryPacket */
/* */
struct rt_packet_info {
- u32 PhysicalBufferCount; /* Physical breaks of buffer descripor chained */
+ u32 PhysicalBufferCount; /* Physical breaks of buffer descriptor chained */
u32 BufferCount; /* Number of Buffer descriptor chained */
u32 TotalPacketLength; /* Self explained */
char *pFirstBuffer; /* Pointer to first buffer descriptor */
@@ -846,8 +847,8 @@ typedef enum _ABGBAND_STATE_ {
/* Power save method control */
typedef union _PS_CONTROL {
struct {
- unsigned long EnablePSinIdle:1; /* Enable radio off when not connect to AP. radio on only when sitesurvey, */
- unsigned long EnableNewPS:1; /* Enable new Chip power save fucntion . New method can only be applied in chip version after 2872. and PCIe. */
+ unsigned long EnablePSinIdle:1; /* Enable radio off when not connected to AP. radio on only when sitesurvey, */
+ unsigned long EnableNewPS:1; /* Enable new Chip power save function . New method can only be applied in chip version after 2872. and PCIe. */
unsigned long rt30xxPowerMode:2; /* Power Level Mode for rt30xx chip */
unsigned long rt30xxFollowHostASPM:1; /* Card Follows Host's setting for rt30xx chip. */
unsigned long rt30xxForceASPMTest:1; /* Force enable L1 for rt30xx chip. This has higher priority than rt30xxFollowHostASPM Mode. */
@@ -1117,8 +1118,8 @@ struct rt_beacon_sync {
unsigned long TimIELocationInBeacon[HW_BEACON_MAX_COUNT];
unsigned long CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT];
BOOLEAN EnableBeacon; /* trigger to enable beacon transmission. */
- u8 BeaconBitMap; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. */
- u8 DtimBitOn; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. */
+ u8 BeaconBitMap; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter needs to change. */
+ u8 DtimBitOn; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter needs to change. */
};
#endif /* RTMP_MAC_USB // */
@@ -1211,7 +1212,7 @@ struct rt_common_config {
/*BOOLEAN bAutoTxRateSwitch; */
u8 MinTxRate; /* RATE_1, RATE_2, RATE_5_5, RATE_11 */
u8 RtsRate; /* RATE_xxx */
- HTTRANSMIT_SETTING MlmeTransmit; /* MGMT frame PHY rate setting when operatin at Ht rate. */
+ HTTRANSMIT_SETTING MlmeTransmit; /* MGMT frame PHY rate setting when operation at Ht rate. */
u8 MlmeRate; /* RATE_xxx, used to send MLME frames */
u8 BasicMlmeRate; /* Default Rate for sending MLME frames */
@@ -1264,7 +1265,7 @@ struct rt_common_config {
struct rt_ht_capability_ie HtCapability;
struct rt_add_ht_info_ie AddHTInfo; /* Useful as AP. */
/*This IE is used with channel switch announcement element when changing to a new 40MHz. */
- /*This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. */
+ /*This IE is included in channel switch announcement frames 7.4.1.5, beacons, probe Rsp. */
struct rt_new_ext_chan_ie NewExtChanOffset; /*7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present */
BOOLEAN bHTProtect;
@@ -1329,7 +1330,7 @@ struct rt_sta_admin_config {
/* GROUP 1 - */
/* User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe */
/* the user intended configuration, but not necessary fully equal to the final */
- /* settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either */
+ /* settings in ACTIVE BSS after negotiation/compromise with the BSS holder (either */
/* AP or IBSS holder). */
/* Once initialized, user configuration can only be changed via OID_xxx */
u8 BssType; /* BSS_INFRA or BSS_ADHOC */
@@ -1386,12 +1387,12 @@ struct rt_sta_admin_config {
/* For WPA countermeasures */
unsigned long LastMicErrorTime; /* record last MIC error time */
- unsigned long MicErrCnt; /* Should be 0, 1, 2, then reset to zero (after disassoiciation). */
+ unsigned long MicErrCnt; /* Should be 0, 1, 2, then reset to zero (after disassociation). */
BOOLEAN bBlockAssoc; /* Block associate attempt for 60 seconds after counter measure occurred. */
/* For WPA-PSK supplicant state */
WPA_STATE WpaState; /* Default is SS_NOTUSE and handled by microsoft 802.1x */
u8 ReplayCounter[8];
- u8 ANonce[32]; /* ANonce for WPA-PSK from aurhenticator */
+ u8 ANonce[32]; /* ANonce for WPA-PSK from auhenticator */
u8 SNonce[32]; /* SNonce for WPA-PSK */
u8 LastSNR0; /* last received BEACON's SNR */
@@ -1423,7 +1424,7 @@ struct rt_sta_admin_config {
u8 RSNIE_Len;
u8 RSN_IE[MAX_LEN_OF_RSNIE]; /* The content saved here should be little-endian format. */
- unsigned long CLBusyBytes; /* Save the total bytes received durning channel load scan time */
+ unsigned long CLBusyBytes; /* Save the total bytes received during channel load scan time */
u16 RPIDensity[8]; /* Array for RPI density collection */
u8 RMReqCnt; /* Number of measurement request saved. */
@@ -1489,9 +1490,9 @@ struct rt_sta_admin_config {
BOOLEAN bForceTxBurst; /* 1: force enble TX PACKET BURST, 0: disable */
};
-/* This data structure keep the current active BSS/IBSS's configuration that this STA */
+/* This data structure keeps the current active BSS/IBSS's configuration that this STA */
/* had agreed upon joining the network. Which means these parameters are usually decided */
-/* by the BSS/IBSS creator instead of user configuration. Data in this data structurre */
+/* by the BSS/IBSS creator instead of user configuration. Data in this data structure */
/* is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. */
/* Normally, after SCAN or failed roaming attempts, we need to recover back to */
/* the current active settings. */
@@ -1519,7 +1520,7 @@ struct rt_mac_table_entry {
/*Choose 1 from ValidAsWDS and ValidAsCLI to validize. */
BOOLEAN ValidAsCLI; /* Sta mode, set this TRUE after Linkup,too. */
BOOLEAN ValidAsWDS; /* This is WDS Entry. only for AP mode. */
- BOOLEAN ValidAsApCli; /*This is a AP-Client entry, only for AP mode which enable AP-Client functions. */
+ BOOLEAN ValidAsApCli; /* This is a AP-Client entry, only for AP mode which enable AP-Client functions. */
BOOLEAN ValidAsMesh;
BOOLEAN ValidAsDls; /* This is DLS Entry. only for STA mode. */
BOOLEAN isCached;
@@ -1527,7 +1528,7 @@ struct rt_mac_table_entry {
u8 EnqueueEapolStartTimerRunning; /* Enqueue EAPoL-Start for triggering EAP SM */
/*jan for wpa */
- /* record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB */
+ /* record which entry revoke MIC Failure, if it leaves the BSS itself, AP won't update aMICFailTime MIB */
u8 CMTimerRunning;
u8 apidx; /* MBSS number */
u8 RSNIE_Len;
@@ -1722,7 +1723,7 @@ struct rt_rtmp_adapter {
unsigned long Rt3xxRalinkLinkCtrl; /* USed for 3090F chip */
u16 DeviceID; /* Read from PCI config */
unsigned long AccessBBPFailCount;
- BOOLEAN bPCIclkOff; /* flag that indicate if the PICE power status in Configuration SPace.. */
+ BOOLEAN bPCIclkOff; /* flag that indicates if the PICE power status in Configuration Space.. */
BOOLEAN bPCIclkOffDisableTx; /* */
BOOLEAN brt30xxBanMcuCmd; /*when = 0xff means all commands are ok to set . */
@@ -1871,9 +1872,9 @@ struct rt_rtmp_adapter {
/* ---------------------------- */
u8 RfIcType; /* RFIC_xxx */
unsigned long RfFreqOffset; /* Frequency offset for channel switching */
- struct rt_rtmp_rf_regs LatchRfRegs; /* latch th latest RF programming value since RF IC doesn't support READ */
+ struct rt_rtmp_rf_regs LatchRfRegs; /* latch the latest RF programming value since RF IC doesn't support READ */
- EEPROM_ANTENNA_STRUC Antenna; /* Since ANtenna definition is different for a & g. We need to save it for future reference. */
+ EEPROM_ANTENNA_STRUC Antenna; /* Since Antenna definition is different for a & g. We need to save it for future reference. */
EEPROM_NIC_CONFIG2_STRUC NicConfig2;
/* This soft Rx Antenna Diversity mechanism is used only when user set */
@@ -1990,7 +1991,7 @@ struct rt_rtmp_adapter {
struct rt_common_config CommonCfg;
struct rt_mlme Mlme;
- /* AP needs those vaiables for site survey feature. */
+ /* AP needs those variables for site survey feature. */
struct rt_mlme_aux MlmeAux; /* temporary settings used during MLME state machine */
struct rt_bss_table ScanTab; /* store the latest SCAN result */
@@ -2012,7 +2013,7 @@ struct rt_rtmp_adapter {
/* various Counters */
struct rt_counter_802_3 Counters8023; /* 802.3 counters */
struct rt_counter_802_11 WlanCounters; /* 802.11 MIB counters */
- struct rt_counter_ralink RalinkCounters; /* Ralink propriety counters */
+ struct rt_counter_ralink RalinkCounters; /* Ralink proprietary counters */
struct rt_counter_drs DrsCounters; /* counters for Dynamic TX Rate Switching */
struct rt_private PrivateInfo; /* Private information & counters */
@@ -2024,7 +2025,7 @@ struct rt_rtmp_adapter {
u16 Sequence;
/* Control disconnect / connect event generation */
- /*+++Didn't used anymore */
+ /*+++Not used anymore */
unsigned long LinkDownTime;
/*--- */
unsigned long LastRxRate;
@@ -2036,7 +2037,7 @@ struct rt_rtmp_adapter {
unsigned long ExtraInfo; /* Extra information for displaying status */
unsigned long SystemErrorBitmap; /* b0: E2PROM version error */
- /*+++Didn't used anymore */
+ /*+++Not used anymore */
unsigned long MacIcVersion; /* MAC/BBP serial interface issue solved after ver.D */
/*--- */
@@ -2089,7 +2090,7 @@ struct rt_rtmp_adapter {
unsigned long BulkOutReq;
unsigned long BulkOutComplete;
unsigned long BulkOutCompleteOther;
- unsigned long BulkOutCompleteCancel; /* seems not use now? */
+ unsigned long BulkOutCompleteCancel; /* seems not used now? */
unsigned long BulkInReq;
unsigned long BulkInComplete;
unsigned long BulkInCompleteFail;
@@ -2196,9 +2197,9 @@ struct rt_rx_blk {
struct rt_tx_blk {
u8 QueIdx;
u8 TxFrameType; /* Indicate the Transmission type of the all frames in one batch */
- u8 TotalFrameNum; /* Total frame number want to send-out in one batch */
+ u8 TotalFrameNum; /* Total frame number that wants to send-out in one batch */
u16 TotalFragNum; /* Total frame fragments required in one batch */
- u16 TotalFrameLen; /* Total length of all frames want to send-out in one batch */
+ u16 TotalFrameLen; /* Total length of all frames that wants to send-out in one batch */
struct rt_queue_header TxPacketList;
struct rt_mac_table_entry *pMacEntry; /* NULL: packet with 802.11 RA field is multicast/broadcast address */
@@ -2207,7 +2208,7 @@ struct rt_tx_blk {
/* Following structure used for the characteristics of a specific packet. */
void *pPacket;
u8 *pSrcBufHeader; /* Reference to the head of sk_buff->data */
- u8 *pSrcBufData; /* Reference to the sk_buff->data, will changed depends on hanlding progresss */
+ u8 *pSrcBufData; /* Reference to the sk_buff->data, will change depending on the handling progresss */
u32 SrcBufLen; /* Length of packet payload which not including Layer 2 header */
u8 *pExtraLlcSnapEncap; /* NULL means no extra LLC/SNAP is required */
u8 HeaderBuf[128]; /* TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP */
@@ -2219,7 +2220,7 @@ struct rt_tx_blk {
u8 apidx; /* The interface associated to this packet */
u8 Wcid; /* The MAC entry associated to this packet */
u8 UserPriority; /* priority class of packet */
- u8 FrameGap; /* what kind of IFS this packet use */
+ u8 FrameGap; /* what kind of IFS does this packet use */
u8 MpduReqNum; /* number of fragments of this frame */
u8 TxRate; /* TODO: Obsoleted? Should change to MCS? */
u8 CipherAlg; /* cipher alogrithm */
@@ -2978,7 +2979,7 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP);
void IterateOnBssTab(struct rt_rtmp_adapter *pAd);
-void IterateOnBssTab2(struct rt_rtmp_adapter *pAd);;
+void IterateOnBssTab2(struct rt_rtmp_adapter *pAd);
void JoinParmFill(struct rt_rtmp_adapter *pAd,
struct rt_mlme_join_req *JoinReq, unsigned long BssIdx);
diff --git a/drivers/staging/rt2860/rtmp_def.h b/drivers/staging/rt2860/rtmp_def.h
index 9c54bacb845b..6ac617e7c9bb 100644
--- a/drivers/staging/rt2860/rtmp_def.h
+++ b/drivers/staging/rt2860/rtmp_def.h
@@ -31,10 +31,11 @@
Miniport related definition header
Revision History:
- Who When What
+ Who When What
-------- ---------- ----------------------------------------------
- Paul Lin 08-01-2002 created
- John Chang 08-05-2003 add definition for 11g & other drafts
+ Paul Lin 08-01-2002 created
+ John Chang 08-05-2003 add definition for 11g & other drafts
+ Justin P. Mattock 11/07/2010 Fix some typos
*/
#ifndef __RTMP_DEF_H__
#define __RTMP_DEF_H__
@@ -111,11 +112,11 @@
WMM Note: If memory of your system is not much, please reduce the definition;
or when you do WMM test, the queue for low priority AC will be full, i.e.
TX_RING_SIZE + MAX_PACKETS_IN_QUEUE packets for the AC will be buffered in
- WLAN, maybe no any packet buffer can be got in Ethernet driver.
+ WLAN, maybe no packet buffers can get into the Ethernet driver.
- Sometimes no packet buffer can be got in Ethernet driver, the system will
+ Sometimes no packet buffer can be get into the Ethernet driver, the system will
send flow control packet to the sender to slow down its sending rate.
- So no WMM can be saw in the air.
+ So no WMM can be seen in the air.
*/
/*
@@ -125,7 +126,7 @@
And in rt_main_end.c, clConfig.clNum = RX_RING_SIZE * 3; is changed to
clConfig.clNum = RX_RING_SIZE * 4;
*/
-/* TODO: For VxWorks the size is 256. Shall we cahnge the value as 256 for all OS????? */
+/* TODO: For VxWorks the size is 256. Shall we change the value as 256 for all OS? */
#define MAX_PACKETS_IN_QUEUE (512) /*(512) // to pass WMM A5-WPAPSK */
#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32
@@ -171,7 +172,7 @@
#define fRTMP_ADAPTER_SCAN_2040 0x04000000
#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000
-#define fRTMP_ADAPTER_START_UP 0x10000000 /*Devive already initialized and enabled Tx/Rx. */
+#define fRTMP_ADAPTER_START_UP 0x10000000 /*Device already initialized and enabled Tx/Rx. */
#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000
#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000
@@ -205,8 +206,8 @@
#define fRTMP_PS_SET_PCI_CLK_OFF_COMMAND 0x00000002
/* Indicate driver should disable kick off hardware to send packets from now. */
#define fRTMP_PS_DISABLE_TX 0x00000004
-/* Indicate driver should IMMEDIATELY fo to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me */
-/*. This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. */
+/* Indicate driver should IMMEDIATELY go to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me */
+/* This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. */
#define fRTMP_PS_GO_TO_SLEEP_NOW 0x00000008
#define fRTMP_PS_TOGGLE_L1 0x00000010 /* Use Toggle L1 mechanism for rt28xx PCIe */
@@ -303,7 +304,7 @@
/* WDS definition */
#define MAX_WDS_ENTRY 4
-#define WDS_PAIRWISE_KEY_OFFSET 60 /* WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table */
+#define WDS_PAIRWISE_KEY_OFFSET 60 /* WDS links use pairwise key#60 ~ 63 in ASIC pairwise key table */
#define WDS_DISABLE_MODE 0
#define WDS_RESTRICT_MODE 1
@@ -559,7 +560,7 @@
#define IE_ADD_HT2 53 /* 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD */
/* For 802.11n D3.03 */
-/*#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet */
+/*#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset element */
#define IE_SECONDARY_CH_OFFSET 62 /* 802.11n D3.03 Secondary Channel Offset element */
#define IE_WAPI 68 /* WAPI information element */
#define IE_2040_BSS_COEXIST 72 /* 802.11n D3.0.3 */
@@ -678,7 +679,7 @@
#define ACT_MACHINE_BASE 0
-/*Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. */
+/*Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please do not modify it by your self. */
/*Category */
#define MT2_PEER_SPECTRUM_CATE 0
#define MT2_PEER_QOS_CATE 1
@@ -748,7 +749,7 @@
#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG)
/* */
-/* STA's AUTHENTICATION state machine: states, evvents, total function # */
+/* STA's AUTHENTICATION state machine: states, events, total function # */
/* */
#define AUTH_REQ_IDLE 0
#define AUTH_WAIT_SEQ2 1
@@ -948,7 +949,7 @@
#define BLOCK_ACK 0x60 /* b6:5 = 11 */
/* */
-/* rtmp_data.c use these definition */
+/* rtmp_data.c uses this definition */
/* */
#define LENGTH_802_11 24
#define LENGTH_802_11_AND_H 30
@@ -1288,7 +1289,7 @@
#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210
#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211
#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212
-/* if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END */
+/* if add new system event flag, please update the IW_SYS_EVENT_FLAG_END */
#define IW_SYS_EVENT_FLAG_END 0x0212
#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1)
/* For system event - end */
@@ -1305,7 +1306,7 @@
#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307
#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308
#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309
-/* if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END */
+/* if add new spoof attack event flag, please update the IW_SPOOF_EVENT_FLAG_END */
#define IW_SPOOF_EVENT_FLAG_END 0x0309
#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1)
/* For spoof attack event - end */
@@ -1319,7 +1320,7 @@
#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404
#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405
#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406
-/* if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END */
+/* if add new flooding attack event flag, please update the IW_FLOOD_EVENT_FLAG_END */
#define IW_FLOOD_EVENT_FLAG_END 0x0406
#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1)
/* For flooding attack - end */
diff --git a/drivers/staging/rt2860/rtmp_timer.h b/drivers/staging/rt2860/rtmp_timer.h
index 28b8ac6e8352..15b628743500 100644
--- a/drivers/staging/rt2860/rtmp_timer.h
+++ b/drivers/staging/rt2860/rtmp_timer.h
@@ -28,13 +28,14 @@
rtmp_timer.h
Abstract:
- Ralink Wireless Driver timer related data structures and delcarations
+ Ralink Wireless Driver timer related data structures and declarations
Revision History:
- Who When What
+ Who When What
-------- ---------- ----------------------------------------------
- Name Date Modification logs
- Shiang Tu Aug-28-2008 init version
+ Name Date Modification logs
+ Shiang Tu Aug-28-2008 init version
+ Justin P. Mattock 11/07/2010 Fix a typo
*/
@@ -51,8 +52,8 @@
/* ----------------- Timer Related MARCO ---------------*/
/* In some os or chipset, we have a lot of timer functions and will read/write register, */
-/* it's not allowed in Linux USB sub-system to do it ( because of sleep issue when */
-/* submit to ctrl pipe). So we need a wrapper function to take care it. */
+/* it's not allowed in Linux USB sub-system to do it ( because of sleep issue when */
+/* submit to ctrl pipe). So we need a wrapper function to take care it. */
#ifdef RTMP_TIMER_TASK_SUPPORT
typedef void(*RTMP_TIMER_TASK_HANDLE) (void *SystemSpecific1,
diff --git a/drivers/staging/rt2860/spectrum.h b/drivers/staging/rt2860/spectrum.h
index 648fd632b606..4c325ba7ba21 100644
--- a/drivers/staging/rt2860/spectrum.h
+++ b/drivers/staging/rt2860/spectrum.h
@@ -37,7 +37,7 @@ char RTMP_GetTxPwr(struct rt_rtmp_adapter *pAd, IN HTTRANSMIT_SETTING HTTxMode);
==========================================================================
Description:
Prepare Measurement request action frame and enqueue it into
- management queue waiting for transmition.
+ management queue waiting for transmission.
Parametrs:
1. the destination mac address of the frame.
@@ -60,7 +60,7 @@ void MakeMeasurementReqFrame(struct rt_rtmp_adapter *pAd,
==========================================================================
Description:
Prepare Measurement report action frame and enqueue it into
- management queue waiting for transmition.
+ management queue waiting for transmission.
Parametrs:
1. the destination mac address of the frame.
@@ -80,7 +80,7 @@ void EnqueueMeasurementRep(struct rt_rtmp_adapter *pAd,
==========================================================================
Description:
Prepare TPC Request action frame and enqueue it into
- management queue waiting for transmition.
+ management queue waiting for transmission.
Parametrs:
1. the destination mac address of the frame.
@@ -94,7 +94,7 @@ void EnqueueTPCReq(struct rt_rtmp_adapter *pAd, u8 *pDA, u8 DialogToken);
==========================================================================
Description:
Prepare TPC Report action frame and enqueue it into
- management queue waiting for transmition.
+ management queue waiting for transmission.
Parametrs:
1. the destination mac address of the frame.
@@ -110,7 +110,7 @@ void EnqueueTPCRep(struct rt_rtmp_adapter *pAd,
==========================================================================
Description:
Prepare Channel Switch Announcement action frame and enqueue it into
- management queue waiting for transmition.
+ management queue waiting for transmission.
Parametrs:
1. the destination mac address of the frame.
@@ -126,7 +126,7 @@ void EnqueueChSwAnn(struct rt_rtmp_adapter *pAd,
/*
==========================================================================
Description:
- Spectrun action frames Handler such as channel switch annoucement,
+ Spectrun action frames Handler such as channel switch announcement,
measurement report, measurement request actions frames.
Parametrs:
diff --git a/drivers/staging/rt2860/sta/assoc.c b/drivers/staging/rt2860/sta/assoc.c
index b7efb0b6b3f0..59e931c3190d 100644
--- a/drivers/staging/rt2860/sta/assoc.c
+++ b/drivers/staging/rt2860/sta/assoc.c
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- John 2004-9-3 porting from RT2500
+ John 2004-9-3 porting from RT2500
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -277,10 +278,10 @@ void MlmeAssocReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *
u16 VarIesOffset;
u16 Status;
- /* Block all authentication request durning WPA block period */
+ /* Block all authentication request during WPA block period */
if (pAd->StaCfg.bBlockAssoc == TRUE) {
DBGPRINT(RT_DEBUG_TRACE,
- ("ASSOC - Block Assoc request durning WPA block period!\n"));
+ ("ASSOC - Block Assoc request during WPA block period!\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2,
@@ -605,10 +606,10 @@ void MlmeReassocReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem
u8 *pOutBuffer = NULL;
u16 Status;
- /* Block all authentication request durning WPA block period */
+ /* Block all authentication request during WPA block period */
if (pAd->StaCfg.bBlockAssoc == TRUE) {
DBGPRINT(RT_DEBUG_TRACE,
- ("ASSOC - Block ReAssoc request durning WPA block period!\n"));
+ ("ASSOC - Block ReAssoc request during WPA block period!\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2,
@@ -1001,7 +1002,7 @@ void AssocPostProc(struct rt_rtmp_adapter *pAd, u8 *pAddr2, u16 CapabilityInfo,
pAd->MlmeAux.CapabilityInfo =
CapabilityInfo & SUPPORTED_CAPABILITY_INFO;
- /* Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. */
+ /* Some HT AP might lost WMM IE. We add WMM ourselves. because HT requires QoS on. */
if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) {
pEdcaParm->bValid = TRUE;
pEdcaParm->Aifsn[0] = 3;
@@ -1054,7 +1055,7 @@ void AssocPostProc(struct rt_rtmp_adapter *pAd, u8 *pAddr2, u16 CapabilityInfo,
/* Set New WPA information */
Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel);
if (Idx == BSS_NOT_FOUND) {
- DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n"));
+ DBGPRINT_ERR("ASSOC - Can't find BSS after receiving Assoc response\n");
} else {
/* Init variable */
pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0;
diff --git a/drivers/staging/rt2860/sta/auth.c b/drivers/staging/rt2860/sta/auth.c
index 404bd220679d..23ea00b896b0 100644
--- a/drivers/staging/rt2860/sta/auth.c
+++ b/drivers/staging/rt2860/sta/auth.c
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- John 2004-9-3 porting from RT2500
+ John 2004-9-3 porting from RT2500
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -455,10 +456,10 @@ BOOLEAN AUTH_ReqSend(struct rt_rtmp_adapter *pAd,
u8 *pOutBuffer = NULL;
unsigned long FrameLen = 0, tmp = 0;
- /* Block all authentication request durning WPA block period */
+ /* Block all authentication request during WPA block period */
if (pAd->StaCfg.bBlockAssoc == TRUE) {
DBGPRINT(RT_DEBUG_TRACE,
- ("%s - Block Auth request durning WPA block period!\n",
+ ("%s - Block Auth request during WPA block period!\n",
pSMName));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
@@ -508,8 +509,7 @@ BOOLEAN AUTH_ReqSend(struct rt_rtmp_adapter *pAd,
RTMPSetTimer(pAuthTimer, Timeout);
return TRUE;
} else {
- DBGPRINT_ERR(("%s - MlmeAuthReqAction() sanity check failed\n",
- pSMName));
+ DBGPRINT_ERR("%s - MlmeAuthReqAction() sanity check failed\n", pSMName);
return FALSE;
}
diff --git a/drivers/staging/rt2860/sta/connect.c b/drivers/staging/rt2860/sta/connect.c
index c380551c0354..4996258f6ecd 100644
--- a/drivers/staging/rt2860/sta/connect.c
+++ b/drivers/staging/rt2860/sta/connect.c
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- John 2004-08-08 Major modification from RT2560
+ John 2004-08-08 Major modification from RT2560
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -64,7 +65,7 @@ u8 CipherSuiteWpaNoneAesLen =
/* The following MACRO is called after 1. starting an new IBSS, 2. successfully JOIN an IBSS, */
/* or 3. successfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS */
-/* All settings successfuly negotiated furing MLME state machines become final settings */
+/* All settings successfuly negotiated firing MLME state machines become final settings */
/* and are copied to pAd->StaActive */
#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \
{ \
@@ -214,8 +215,7 @@ void MlmeCntlMachinePerformAction(struct rt_rtmp_adapter *pAd,
break;
#endif /* RTMP_MAC_USB // */
default:
- DBGPRINT_ERR(("ERROR! CNTL - Illegal message type(=%ld)",
- Elem->MsgType));
+ DBGPRINT_ERR("ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType);
break;
}
}
@@ -553,7 +553,7 @@ void CntlOidRTBssidProc(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *
NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0],
&pAd->ScanTab.BssEntry[BssIdx], sizeof(struct rt_bss_entry));
- /* Add SSID into MlmeAux for site surey joining hidden SSID */
+ /* Add SSID into MlmeAux for site survey joining hidden SSID */
pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen;
NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid,
pAd->MlmeAux.SsidLen);
@@ -666,7 +666,7 @@ void CntlOidRTBssidProc(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *
}
/* Roaming is the only external request triggering CNTL state machine */
-/* despite of other "SET OID" operation. All "SET OID" related oerations */
+/* despite of other "SET OID" operation. All "SET OID" related operations */
/* happen in sequence, because no other SET OID will be sent to this device */
/* until the the previous SET operation is complete (successful o failed). */
/* So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? */
@@ -1224,7 +1224,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
/* Change to AP channel */
if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) {
- /* Must using 40MHz. */
+ /* Must use 40MHz. */
pAd->CommonCfg.BBPCurrentBW = BW_40;
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
@@ -1259,7 +1259,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
} else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel)
&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth ==
BW_40)) {
- /* Must using 40MHz. */
+ /* Must use 40MHz. */
pAd->CommonCfg.BBPCurrentBW = BW_40;
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
@@ -1343,12 +1343,12 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
AsicSetSlotTime(pAd, TRUE);
AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm);
- /* Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit */
+ /* Call this for RTS protection for legacy rate, we will always enable RTS threshold, but normally it will not hit */
AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE,
FALSE);
if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) {
- /* Update HT protectionfor based on AP's operating mode. */
+ /* Update HT protection for based on AP's operating mode. */
if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) {
AsicUpdateProtect(pAd,
pAd->MlmeAux.AddHtInfo.AddHtInfo2.
@@ -1530,7 +1530,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
/* Add BSSID to WCID search table */
AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid);
- /* If WEP is enabled, add paiewise and shared key */
+ /* If WEP is enabled, add pairwise and shared key */
if (((pAd->StaCfg.WpaSupplicantUP) &&
(pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) ||
@@ -1681,9 +1681,9 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
pAd->Mlme.PeriodicRound = 0;
pAd->Mlme.OneSecPeriodicRound = 0;
pAd->bConfigChanged = FALSE; /* Reset config flag */
- pAd->ExtraInfo = GENERAL_LINK_UP; /* Update extra information to link is up */
+ pAd->ExtraInfo = GENERAL_LINK_UP; /* Update extra information after link is up */
- /* Set asic auto fall back */
+ /* Set basic auto fall back */
{
u8 *pTable;
u8 TableSize = 0;
@@ -1854,8 +1854,8 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType)
Note:
We need more information to know it's this requst from AP.
If yes! we need to do extra handling, for example, remove the WPA key.
- Otherwise on 4-way handshaking will faied, since the WPA key didn't be
- remove while auto reconnect.
+ Otherwise on 4-way handshaking will fail, since the WPA key didn't get
+ removed while auto reconnect.
Disconnect request from AP, it means we will start afresh 4-way handshaking
on WPA mode.
@@ -1870,9 +1870,9 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP)
return;
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
- /*Comment the codes, beasue the line 2291 call the same function. */
- /*RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); */
- /* Not allow go to sleep within linkdown function. */
+ /* Comment the codes, because the line 2291 call the same function. */
+ /* RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); */
+ /* Not allowed go to sleep within the linkdown function. */
RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP);
if (pAd->CommonCfg.bWirelessEvent) {
@@ -1970,7 +1970,7 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP)
/* Set LED */
RTMPSetLED(pAd, LED_LINK_DOWN);
pAd->LedIndicatorStrength = 0xF0;
- RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware is not done it. */
+ RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware has not done it. */
AsicDisableSync(pAd);
diff --git a/drivers/staging/rt2860/sta/rtmp_data.c b/drivers/staging/rt2860/sta/rtmp_data.c
index 23879b7cd49a..e82c6b669eb2 100644
--- a/drivers/staging/rt2860/sta/rtmp_data.c
+++ b/drivers/staging/rt2860/sta/rtmp_data.c
@@ -31,7 +31,8 @@
Data path subroutines
Revision History:
- Who When What
+ Who When What
+ Justin P. Mattock 11/07/2010 Fix typos
-------- ---------- ----------------------------------------------
*/
#include "../rt_config.h"
@@ -257,8 +258,8 @@ void STARxDataFrameAnnounce(struct rt_rtmp_adapter *pAd,
&& (pAd->CommonCfg.bDisableReordering == 0)) {
Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID);
} else {
- /* Determin the destination of the EAP frame */
- /* to WPA state machine or upper layer */
+ /* Determine the destination of the EAP frame */
+ /* to WPA state machine or upper layer */
STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk,
FromWhichBSSID);
}
@@ -644,7 +645,7 @@ void STAHandleRxMgmtFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk)
/* First check the size, it MUST not exceed the mlme queue size */
if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) {
- DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount));
+ DBGPRINT_ERR("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount);
break;
}
@@ -853,7 +854,7 @@ Return Value:
NONE
Note:
- This function do early checking and classification for send-out packet.
+ This function does early checking and classification for send-out packet.
You only can put OS-depened & STA related code in here.
========================================================================
*/
@@ -943,7 +944,7 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket)
DBGPRINT(RT_DEBUG_ERROR,
("STASendPacket --> pSrcBufVA == NULL !SrcBufLen=%x\n",
SrcBufLen));
- /* Resourece is low, system did not allocate virtual address */
+ /* Resource is low, system did not allocate virtual address */
/* return NDIS_STATUS_FAILURE directly to upper layer */
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
@@ -979,7 +980,7 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket)
DBGPRINT(RT_DEBUG_ERROR,
("STASendPacket->Cannot find pEntry(%pM) in MacTab!\n",
pSrcBufVA));
- /* Resourece is low, system did not allocate virtual address */
+ /* Resource is low, system did not allocate virtual address */
/* return NDIS_STATUS_FAILURE directly to upper layer */
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
@@ -1057,9 +1058,9 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket)
/* STEP 2. Check the requirement of RTS: */
/* If multiple fragment required, RTS is required only for the first fragment */
- /* if the fragment size large than RTS threshold */
+ /* if the fragment size is larger than RTS threshold */
/* For RT28xx, Let ASIC send RTS/CTS */
-/* RTMP_SET_PACKET_RTS(pPacket, 0); */
+ /* RTMP_SET_PACKET_RTS(pPacket, 0); */
if (NumberOfFrag > 1)
RTSRequired =
(pAd->CommonCfg.FragmentThreshold >
@@ -1171,8 +1172,8 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket)
========================================================================
Routine Description:
- This subroutine will scan through releative ring descriptor to find
- out avaliable free ring descriptor and compare with request size.
+ This subroutine will scan through relative ring descriptor to find
+ out available free ring descriptor and compare with request size.
Arguments:
pAd Pointer to our adapter
@@ -1588,7 +1589,7 @@ static inline u8 *STA_Build_ARalink_Frame_Header(struct rt_rtmp_adapter *pAd,
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += 2;
}
- /* padding at front of LLC header. LLC header should at 4-bytes aligment. */
+ /* padding at front of LLC header. LLC header should at 4-bytes alignment. */
pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr;
pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen);
@@ -2014,7 +2015,7 @@ void STA_Legacy_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk)
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += 2;
}
- /* The remaining content of MPDU header should locate at 4-octets aligment */
+ /* The remaining content of MPDU header should locate at 4-octets alignment */
pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr;
pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen);
@@ -2114,7 +2115,7 @@ void STA_ARalink_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk)
STA_Build_ARalink_Frame_Header(pAd, pTxBlk);
/* It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount */
- /* will be updated after final frame was handled. */
+ /* will be updated after final frame was handled. */
RTMPWriteTxWI_Data(pAd,
(struct rt_txwi *) (&pTxBlk->
HeaderBuf
@@ -2291,8 +2292,8 @@ void STA_Fragment_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk
pTxBlk->pExtraLlcSnapEncap, pTxBlk->pKey,
0);
- /* NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust */
- /* to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. */
+ /* NOTE: DON'T refer the skb->len directly after following copy. Because the length is not adjusted */
+ /* to correct length, refer to pTxBlk->SrcBufLen for the packet length in following progress. */
NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen,
&pAd->PrivateInfo.Tx.MIC[0], 8);
/*skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); */
@@ -2301,7 +2302,7 @@ void STA_Fragment_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk
pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC;
}
/* */
- /* calcuate the overhead bytes that encryption algorithm may add. This */
+ /* calculate the overhead bytes that encryption algorithm may add. This */
/* affects the calculate of "duration" field */
/* */
if ((pTxBlk->CipherAlg == CIPHER_WEP64)
diff --git a/drivers/staging/rt2860/sta/sanity.c b/drivers/staging/rt2860/sta/sanity.c
index 8f9fd19be151..0c32604f2d3f 100644
--- a/drivers/staging/rt2860/sta/sanity.c
+++ b/drivers/staging/rt2860/sta/sanity.c
@@ -32,7 +32,8 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- John Chang 2004-09-01 add WMM support
+ John Chang 2004-09-01 add WMM support
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -118,7 +119,7 @@ BOOLEAN PeerAssocRspSanity(struct rt_rtmp_adapter *pAd, void * pMsg, unsigned lo
NdisMoveMemory(pAid, &pFrame->Octet[4], 2);
Length += 2;
- /* Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform */
+ /* Aid already swapped byte order in RTMPFrameEndianChange() for big endian platform */
*pAid = (*pAid) & 0x3fff; /* AID is low 14-bit */
/* -- get supported rates from payload and advance the pointer */
diff --git a/drivers/staging/rt2860/sta/sync.c b/drivers/staging/rt2860/sta/sync.c
index 747d3c6d1851..7054ba1323d0 100644
--- a/drivers/staging/rt2860/sta/sync.c
+++ b/drivers/staging/rt2860/sta/sync.c
@@ -32,8 +32,9 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- John Chang 2004-09-01 modified for rt2561/2661
- Jan Lee 2006-08-01 modified for rt2860 for 802.11n
+ John Chang 2004-09-01 modified for rt2561/2661
+ Jan Lee 2006-08-01 modified for rt2860 for 802.11n
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -233,9 +234,9 @@ void MlmeScanReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *E
RTMPSuspendMsduTransmission(pAd);
/* */
- /* To prevent data lost. */
- /* Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. */
- /* And should send an NULL data with turned PSM bit off to AP, when scan progress done */
+ /* To prevent data loss. */
+ /* Send a NULL data with turned PSM bit on to current associated AP before SCAN progress. */
+ /* And should send a NULL data with turned PSM bit off to AP, when scan progress done */
/* */
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
&& (INFRA_ON(pAd))) {
@@ -283,7 +284,7 @@ void MlmeScanReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *E
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n"));
ScanNextChannel(pAd);
} else {
- DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n"));
+ DBGPRINT_ERR("SYNC - MlmeScanReqAction() sanity check fail\n");
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2,
@@ -535,7 +536,7 @@ void MlmeStartReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2,
&Status);
} else {
- DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n"));
+ DBGPRINT_ERR("SYNC - MlmeStartReqAction() sanity check fail.\n");
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2,
@@ -750,9 +751,9 @@ void PeerBeaconAtJoinAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_el
/* BEACON from desired BSS/IBSS found. We should be able to decide most */
/* BSS parameters here. */
- /* Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? */
- /* Do we need to receover back all parameters belonging to previous BSS? */
- /* A. Should be not. There's no back-door recover to previous AP. It still need */
+ /* Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATION? */
+ /* Do we need to recover back all parameters belonging to previous BSS? */
+ /* A. Should be not. There's no back-door recover to previous AP. It still needs */
/* a new JOIN-AUTH-ASSOC sequence. */
if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) {
DBGPRINT(RT_DEBUG_TRACE,
@@ -876,7 +877,7 @@ void PeerBeaconAtJoinAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_el
pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration;
pAd->MlmeAux.APRalinkIe = RalinkIe;
- /* Copy AP's supported rate to MlmeAux for creating assoication request */
+ /* Copy AP's supported rate to MlmeAux for creating association request */
/* Also filter out not supported rate */
pAd->MlmeAux.SupRateLen = SupRateLen;
NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate,
@@ -1207,7 +1208,7 @@ void PeerBeacon(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
}
if (index >= pAd->ChannelListNum) {
- DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
+ DBGPRINT_ERR("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum);
}
}
/* if the ssid matched & bssid unmatched, we should select the bssid with large value. */
diff --git a/drivers/staging/rt2860/sta/wpa.c b/drivers/staging/rt2860/sta/wpa.c
index 69b8a24daa21..ff348325028b 100644
--- a/drivers/staging/rt2860/sta/wpa.c
+++ b/drivers/staging/rt2860/sta/wpa.c
@@ -33,7 +33,8 @@
Who When What
-------- ---------- ----------------------------------------------
Jan Lee 03-07-22 Initial
- Paul Lin 03-11-28 Modify for supplicant
+ Paul Lin 03-11-28 Modify for supplicant
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "../rt_config.h"
@@ -86,7 +87,7 @@ void RTMPReportMicError(struct rt_rtmp_adapter *pAd, struct rt_cipher_key *pWpaK
/* Violate MIC error counts, MIC countermeasures kicks in */
pAd->StaCfg.MicErrCnt++;
/* We shall block all reception */
- /* We shall clean all Tx ring and disassoicate from AP after next EAPOL frame */
+ /* We shall clean all Tx ring and disassociate from AP after next EAPOL frame */
/* */
/* No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets */
/* if pAd->StaCfg.MicErrCnt greater than 2. */
diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c
index e095a44cbc0e..5717e12a9544 100644
--- a/drivers/staging/rt2860/sta_ioctl.c
+++ b/drivers/staging/rt2860/sta_ioctl.c
@@ -31,10 +31,11 @@
IOCTL related subroutines
Revision History:
- Who When What
+ Who When What
-------- ---------- ----------------------------------------------
- Rory Chen 01-03-2003 created
- Rory Chen 02-14-2005 modify to support RT61
+ Rory Chen 01-03-2003 created
+ Rory Chen 02-14-2005 modify to support RT61
+ Justin P. Mattock 11/07/2010 Fix typos
*/
#include "rt_config.h"
@@ -851,7 +852,7 @@ int rt_ioctl_giwscan(struct net_device *dev,
/*
Protocol:
- it will show scanned AP's WirelessMode .
+ it will show scanned AP's WirelessMode.
it might be
802.11a
802.11a/n
@@ -875,13 +876,13 @@ int rt_ioctl_giwscan(struct net_device *dev,
strcpy(iwe.u.name, "802.11a");
} else {
/*
- if one of non B mode rate is set supported rate . it mean G only.
+ if one of non B mode rate is set supported rate, it means G only.
*/
for (rateCnt = 0;
rateCnt < pBssEntry->SupRateLen;
rateCnt++) {
/*
- 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only.
+ 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate, it means G only.
*/
if (pBssEntry->SupRate[rateCnt] == 140
|| pBssEntry->SupRate[rateCnt] ==
@@ -1417,7 +1418,7 @@ int rt_ioctl_siwencode(struct net_device *dev,
if ((index >= 0) && (index < 4)) {
pAdapter->StaCfg.DefaultKeyId = index;
} else
- /* Don't complain if only change the mode */
+ /* Don't complain if the mode is only changed */
if (!(erq->flags & IW_ENCODE_MODE))
return -EINVAL;
}
@@ -2732,8 +2733,8 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg)
}
if (INFRA_ON(pAdapter)) {
/*BOOLEAN Cancelled; */
- /* Set the AutoReconnectSsid to prevent it reconnect to old SSID */
- /* Since calling this indicate user don't want to connect to that SSID anymore. */
+ /* Set the AutoReconnectSsid to prevent it from reconnecting to the old SSID */
+ /* Since calling this indicates users don't want to connect to that SSID anymore. */
pAdapter->MlmeAux.AutoReconnectSsidLen = 32;
NdisZeroMemory(pAdapter->MlmeAux.
AutoReconnectSsid,
@@ -2766,8 +2767,8 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg)
LinkDown(pAdapter, FALSE);
}
if (ADHOC_ON(pAdapter)) {
- /* Set the AutoReconnectSsid to prevent it reconnect to old SSID */
- /* Since calling this indicate user don't want to connect to that SSID anymore. */
+ /* Set the AutoReconnectSsid to prevent it from reconnecting to the old SSID */
+ /* Since calling this indicates users don't want to connect to that SSID anymore. */
pAdapter->MlmeAux.AutoReconnectSsidLen = 32;
NdisZeroMemory(pAdapter->MlmeAux.
AutoReconnectSsid,
@@ -2884,7 +2885,7 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg)
}
/* Enable Rx with promiscuous reception */
RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3);
- /* ASIC supporsts sniffer function with replacing RSSI with timestamp. */
+ /* ASIC supports sniffer function with replacing RSSI with timestamp. */
/*RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); */
/*Value |= (0x80); */
/*RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); */
diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c
index ebf9074a9083..ee68d51caa4e 100644
--- a/drivers/staging/rt2860/usb_main_dev.c
+++ b/drivers/staging/rt2860/usb_main_dev.c
@@ -27,8 +27,8 @@
#include "rt_config.h"
/* Following information will be show when you run 'modinfo' */
-/* *** If you have a solution for the bug in current version of driver, please mail to me. */
-/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** */
+/* If you have a solution for the bug in current version of driver, please e-mail me. */
+/* Otherwise post to the forum at ralinktech's web site(www.ralinktech.com) and let all users help you. */
MODULE_AUTHOR("Paul Lin <paul_lin@ralinktech.com>");
MODULE_DESCRIPTION("RT2870/RT3070 Wireless Lan Linux Driver");
MODULE_LICENSE("GPL");
@@ -65,6 +65,7 @@ struct usb_device_id rtusb_usb_id[] = {
{USB_DEVICE(0x14B2, 0x3C07)}, /* AL */
{USB_DEVICE(0x050D, 0x8053)}, /* Belkin */
{USB_DEVICE(0x050D, 0x825B)}, /* Belkin */
+ {USB_DEVICE(0x050D, 0x935A)}, /* Belkin F6D4050 v1 */
{USB_DEVICE(0x050D, 0x935B)}, /* Belkin F6D4050 v2 */
{USB_DEVICE(0x14B2, 0x3C23)}, /* Airlink */
{USB_DEVICE(0x14B2, 0x3C27)}, /* Airlink */
@@ -181,6 +182,7 @@ struct usb_device_id rtusb_usb_id[] = {
{USB_DEVICE(0x2001, 0x3C09)}, /* D-Link */
{USB_DEVICE(0x2001, 0x3C0A)}, /* D-Link 3072 */
{USB_DEVICE(0x2019, 0xED14)}, /* Planex Communications, Inc. */
+ {USB_DEVICE(0x0411, 0x015D)}, /* Buffalo Airstation WLI-UC-GN */
{} /* Terminating entry */
};
@@ -231,7 +233,7 @@ BOOLEAN RT28XXChipsetCheck(IN void *_dev_p)
for (i = 0; i < rtusb_usb_id_len; i++) {
if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor &&
dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) {
- printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
+ printk(KERN_INFO "rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
dev_p->descriptor.idVendor,
dev_p->descriptor.idProduct);
break;
@@ -239,7 +241,7 @@ BOOLEAN RT28XXChipsetCheck(IN void *_dev_p)
}
if (i == rtusb_usb_id_len) {
- printk("rt2870: Error! Device Descriptor not matching!\n");
+ printk(KERN_ERR "rt2870: Error! Device Descriptor not matching!\n");
return FALSE;
}
@@ -321,7 +323,7 @@ static BOOLEAN USBDevConfigInit(IN struct usb_device *dev,
if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) {
printk
- ("%s: Could not find both bulk-in and bulk-out endpoints\n",
+ (KERN_ERR "%s: Could not find both bulk-in and bulk-out endpoints\n",
__FUNCTION__);
return FALSE;
}
@@ -421,7 +423,7 @@ static int rt2870_resume(struct usb_interface *intf)
/* Init driver module */
int __init rtusb_init(void)
{
- printk("rtusb init --->\n");
+ printk(KERN_DEBUG "rtusb init --->\n");
return usb_register(&rtusb_driver);
}
@@ -429,7 +431,7 @@ int __init rtusb_init(void)
void __exit rtusb_exit(void)
{
usb_deregister(&rtusb_driver);
- printk("<--- rtusb exit\n");
+ printk(KERN_DEBUG "<--- rtusb exit\n");
}
module_init(rtusb_init);
@@ -812,7 +814,7 @@ static void rt2870_disconnect(struct usb_device *dev, struct rt_rtmp_adapter *pA
dev->bus->bus_name, dev->devpath));
if (!pAd) {
usb_put_dev(dev);
- printk("rtusb_disconnect: pAd == NULL!\n");
+ printk(KERN_ERR "rtusb_disconnect: pAd == NULL!\n");
return;
}
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST);
@@ -882,8 +884,8 @@ static int __devinit rt2870_probe(IN struct usb_interface *intf,
if (net_dev == NULL)
goto err_out_free_radev;
- /* Here are the net_device structure with usb specific parameters. */
- /* for supporting Network Manager.
+ /* Here are the net_device structure with usb specific parameters.
+ * for supporting Network Manager.
* Set the sysfs physical device reference for the network logical device if set prior to registration will
* cause a symlink during initialization.
*/
diff --git a/drivers/staging/rt2860/wpa.h b/drivers/staging/rt2860/wpa.h
index 6199ae6cdcd0..116fc2caa886 100644
--- a/drivers/staging/rt2860/wpa.h
+++ b/drivers/staging/rt2860/wpa.h
@@ -32,13 +32,14 @@
Revision History:
Who When What
-------- ---------- ----------------------------------------------
- Name Date Modification logs
+ Name Date Modification logs
+ Justin P. Mattock 11/07/2010 Fix a typo
*/
#ifndef __WPA_H__
#define __WPA_H__
-/* EAPOL Key descripter frame format related length */
+/* EAPOL Key descriptor frame format related length */
#define LEN_KEY_DESC_NONCE 32
#define LEN_KEY_DESC_IV 16
#define LEN_KEY_DESC_RSC 8
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 46000d72f4c4..3bdf9b31cc4e 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -264,8 +264,12 @@ HwHSSIThreeWire(
udelay(10);
}
- if (TryCnt == TC_3W_POLL_MAX_TRY_CNT)
- panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp);
+ if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) {
+ printk(KERN_ERR "rtl8187se: HwThreeWire(): CmdReg:"
+ " %#X RE|WE bits are not clear!!\n", u1bTmp);
+ dump_stack();
+ return 0;
+ }
/* RTL8187S HSSI Read/Write Function */
u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
@@ -298,13 +302,23 @@ HwHSSIThreeWire(
int idx;
int ByteCnt = nDataBufBitCnt / 8;
/* printk("%d\n",nDataBufBitCnt); */
- if ((nDataBufBitCnt % 8) != 0)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n",
- nDataBufBitCnt);
+ if ((nDataBufBitCnt % 8) != 0) {
+ printk(KERN_ERR "rtl8187se: "
+ "HwThreeWire(): nDataBufBitCnt(%d)"
+ " should be multiple of 8!!!\n",
+ nDataBufBitCnt);
+ dump_stack();
+ nDataBufBitCnt += 8;
+ nDataBufBitCnt &= ~7;
+ }
- if (nDataBufBitCnt > 64)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n",
- nDataBufBitCnt);
+ if (nDataBufBitCnt > 64) {
+ printk(KERN_ERR "rtl8187se: HwThreeWire():"
+ " nDataBufBitCnt(%d) should <= 64!!!\n",
+ nDataBufBitCnt);
+ dump_stack();
+ nDataBufBitCnt = 64;
+ }
for (idx = 0; idx < ByteCnt; idx++)
write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
index dd8a221e21ae..b26b5a8b5f6b 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
@@ -822,7 +822,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
{
txb->queue_index = UP2AC(skb->priority);
} else {
- txb->queue_index = WME_AC_BK;;
+ txb->queue_index = WME_AC_BK;
}
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index a202194b5cbb..fac4eee28e4e 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -89,7 +89,7 @@ u32 rt_global_debug_component =
// COMP_INTR |
COMP_ERR ; //always open err flags on
-static const struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8192_pci_id_tbl) = {
#ifdef RTL8190P
/* Realtek */
/* Dlink */
@@ -2283,9 +2283,7 @@ static void rtl8192_init_priv_variable(struct net_device* dev)
IMR_TXFOVW | IMR_BcnInt | IMR_TBDOK | IMR_TBDER);
priv->AcmControl = 0;
- priv->pFirmware = (rt_firmware*)vmalloc(sizeof(rt_firmware));
- if (priv->pFirmware)
- memset(priv->pFirmware, 0, sizeof(rt_firmware));
+ priv->pFirmware = vzalloc(sizeof(rt_firmware));
/* rx related queue */
skb_queue_head_init(&priv->rx_queue);
@@ -5829,6 +5827,9 @@ static void rtl8192_rx(struct net_device *dev)
}
}
+ pci_unmap_single(priv->pdev, *((dma_addr_t *) skb->cb),
+ priv->rxbuffersize, PCI_DMA_FROMDEVICE);
+
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
*((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
diff --git a/drivers/staging/rtl8192e/r819xE_phy.c b/drivers/staging/rtl8192e/r819xE_phy.c
index d83bcbcb20bd..50cd0e52b921 100644
--- a/drivers/staging/rtl8192e/r819xE_phy.c
+++ b/drivers/staging/rtl8192e/r819xE_phy.c
@@ -2596,7 +2596,7 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E
break;
}
- return ret;;
+ return ret;
}
/******************************************************************************
diff --git a/drivers/staging/rtl8192u/Makefile b/drivers/staging/rtl8192u/Makefile
index 206d924a707c..eefc657ce99e 100644
--- a/drivers/staging/rtl8192u/Makefile
+++ b/drivers/staging/rtl8192u/Makefile
@@ -9,7 +9,6 @@ ccflags-y += -DTHOMAS_BEACON -DTHOMAS_TASKLET -DTHOMAS_SKB -DTHOMAS_TURBO
#ccflags-y += -DUSB_TX_DRIVER_AGGREGATION_ENABLE
#ccflags-y += -DUSB_RX_AGGREGATION_SUPPORT
ccflags-y += -DUSE_ONE_PIPE
-ccflags-y += -DENABLE_DOT11D
ccflags-y += -Idrivers/staging/rtl8192u/ieee80211
r8192u_usb-y := r8192U_core.o r8180_93cx6.o r8192U_wx.o \
diff --git a/drivers/staging/rtl8192u/dot11d.h b/drivers/staging/rtl8192u/dot11d.h
index d99cc030ec7a..92e7a00f3ee1 100644
--- a/drivers/staging/rtl8192u/dot11d.h
+++ b/drivers/staging/rtl8192u/dot11d.h
@@ -1,7 +1,6 @@
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
-#ifdef ENABLE_DOT11D
#include "ieee80211/ieee80211.h"
@@ -98,5 +97,4 @@ int ToLegalChannel(
struct ieee80211_device *dev,
u8 channel
);
-#endif /* ENABLE_DOT11D */
#endif /* #ifndef __INC_DOT11D_H */
diff --git a/drivers/staging/rtl8192u/ieee80211/Makefile b/drivers/staging/rtl8192u/ieee80211/Makefile
index 45704f85ef0b..0775c5599d69 100644
--- a/drivers/staging/rtl8192u/ieee80211/Makefile
+++ b/drivers/staging/rtl8192u/ieee80211/Makefile
@@ -20,7 +20,6 @@ ifeq ($(NIC_SELECT),RTL8192U)
endif
#ccflags-y := -DJOHN_NOCPY
#flags to enable or disble 80211D feature
-ccflags-y += -DENABLE_DOT11D
ieee80211-rsl-objs := ieee80211_rx.o \
ieee80211_softmac.o \
ieee80211_tx.o \
@@ -75,7 +74,6 @@ CFLAGS += -I$(KSRC)/include -I.
CFLAGS += -DMODVERSIONS -DEXPORT_SYMTAB -include $(KSRC)/include/linux/modversions.h
#Kernel 2.4.20
#CFLAGS += -D__NO_VERSION__ -DEXPORT_SYMTAB
-#CFLAGS += -DENABLE_DOT11D
SMP := $(shell $(CC) $(MODCFLAGS) -E -dM $(CONFIG_FILE) | \
grep CONFIG_SMP | awk '{print $$3}')
ifneq ($(SMP),1)
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.c b/drivers/staging/rtl8192u/ieee80211/dot11d.c
index b91cbfcfa71f..ce63fc341c6e 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.c
@@ -1,4 +1,3 @@
-#ifdef ENABLE_DOT11D
//-----------------------------------------------------------------------------
// File:
// Dot11d.c
@@ -220,4 +219,3 @@ EXPORT_SYMBOL(DOT11D_ScanComplete);
EXPORT_SYMBOL(IsLegalChannel);
EXPORT_SYMBOL(ToLegalChannel);
-#endif
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.h b/drivers/staging/rtl8192u/ieee80211/dot11d.h
index 15b7a4ba37b6..54f2b4c434ff 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.h
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.h
@@ -1,10 +1,8 @@
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
-#ifdef ENABLE_DOT11D
#include "ieee80211.h"
-//#define ENABLE_DOT11D
//#define DOT11D_MAX_CHNL_NUM 83
@@ -98,5 +96,4 @@ int ToLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
-#endif //ENABLE_DOT11D
#endif // #ifndef __INC_DOT11D_H
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index e1216b704959..c0b844d75c0d 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -1572,10 +1572,8 @@ struct ieee80211_network {
#ifdef THOMAS_TURBO
u8 Turbo_Enable;//enable turbo mode, added by thomas
#endif
-#ifdef ENABLE_DOT11D
u16 CountryIeLen;
u8 CountryIeBuf[MAX_IE_LEN];
-#endif
// HT Related, by amy, 2008.04.29
BSS_HT bssht;
// Add to handle broadcom AP management frame CCK rate.
@@ -1769,7 +1767,6 @@ typedef u32 RT_RF_CHANGE_SOURCE;
#define RF_CHANGE_BY_IPS BIT28
#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17.
-#ifdef ENABLE_DOT11D
typedef enum
{
COUNTRY_CODE_FCC = 0,
@@ -1784,7 +1781,6 @@ typedef enum
COUNTRY_CODE_MIC,
COUNTRY_CODE_GLOBAL_DOMAIN
}country_code_type_t;
-#endif
#define RT_MAX_LD_SLOT_NUM 10
typedef struct _RT_LINK_DETECT_T{
@@ -1970,12 +1966,8 @@ struct ieee80211_device {
/* map of allowed channels. 0 is dummy */
// FIXME: remeber to default to a basic channel plan depending of the PHY type
-#ifdef ENABLE_DOT11D
void* pDot11dInfo;
bool bGlobalDomain;
-#else
- int channel_map[MAX_CHANNEL_NUMBER+1];
-#endif
int rate; /* current rate */
int basic_rate;
//FIXME: pleace callback, see if redundant with softmac_features
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index c8ca9d8ed5d2..1ea8da3655ec 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -44,9 +44,7 @@
#include <linux/ctype.h>
#include "ieee80211.h"
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats)
@@ -1599,7 +1597,6 @@ static const char *get_info_element_string(u16 id)
}
#endif
-#ifdef ENABLE_DOT11D
static inline void ieee80211_extract_country_ie(
struct ieee80211_device *ieee,
struct ieee80211_info_element *info_element,
@@ -1632,7 +1629,6 @@ static inline void ieee80211_extract_country_ie(
}
}
-#endif
int ieee80211_parse_info_param(struct ieee80211_device *ieee,
struct ieee80211_info_element *info_element,
@@ -2086,14 +2082,12 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
"QoS Error need to parse QOS_PARAMETER IE\n");
break;
-#ifdef ENABLE_DOT11D
case MFIE_TYPE_COUNTRY:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n",
info_element->len);
//printk("=====>Receive <%s> Country IE\n",network->ssid);
ieee80211_extract_country_ie(ieee, info_element, network, network->bssid);//addr2 is same as addr3 when from an AP
break;
-#endif
/* TODO */
default:
IEEE80211_DEBUG_MGMT
@@ -2229,10 +2223,8 @@ static inline int ieee80211_network_init(
#ifdef THOMAS_TURBO
network->Turbo_Enable = 0;
#endif
-#ifdef ENABLE_DOT11D
network->CountryIeLen = 0;
memset(network->CountryIeBuf, 0, MAX_IE_LEN);
-#endif
//Initialize HT parameters
//ieee80211_ht_initialize(&network->bssht);
HTInitializeBssDesc(&network->bssht);
@@ -2399,10 +2391,8 @@ static inline void update_network(struct ieee80211_network *dst,
dst->Turbo_Enable = src->Turbo_Enable;
#endif
-#ifdef ENABLE_DOT11D
dst->CountryIeLen = src->CountryIeLen;
memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen);
-#endif
//added by amy for LEAP
dst->bWithAironetIE = src->bWithAironetIE;
@@ -2470,7 +2460,6 @@ static inline void ieee80211_process_probe_response(
return;
}
-#ifdef ENABLE_DOT11D
// For Asus EeePc request,
// (1) if wireless adapter receive get any 802.11d country code in AP beacon,
// wireless adapter should follow the country code.
@@ -2527,7 +2516,6 @@ static inline void ieee80211_process_probe_response(
}
}
}
-#endif
/* The network parsed correctly -- so now we scan our known networks
* to see if we can find it in our list.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index bc8c42533693..20f8c347cae4 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -21,9 +21,7 @@
#include <linux/slab.h>
#include <linux/version.h>
#include <asm/uaccess.h>
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
u8 rsn_authen_cipher_suite[16][4] = {
{0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved
@@ -430,10 +428,8 @@ void ieee80211_send_probe_requests(struct ieee80211_device *ieee)
void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
{
short ch = 0;
-#ifdef ENABLE_DOT11D
u8 channel_map[MAX_CHANNEL_NUMBER+1];
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
-#endif
down(&ieee->scan_sem);
while(1)
@@ -443,11 +439,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
ch++;
if (ch > MAX_CHANNEL_NUMBER)
goto out; /* scan completed */
-#ifdef ENABLE_DOT11D
}while(!channel_map[ch]);
-#else
- }while(!ieee->channel_map[ch]);
-#endif
/* this function can be called in two situations
* 1- We have switched to ad-hoc mode and we are
@@ -471,9 +463,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
if (ieee->state == IEEE80211_LINKED)
goto out;
ieee->set_chan(ieee->dev, ch);
-#ifdef ENABLE_DOT11D
if(channel_map[ch] == 1)
-#endif
ieee80211_send_probe_requests(ieee);
/* this prevent excessive time wait when we
@@ -496,10 +486,8 @@ out:
}
else{
ieee->sync_scan_hurryup = 0;
-#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee))
DOT11D_ScanComplete(ieee);
-#endif
up(&ieee->scan_sem);
}
}
@@ -510,10 +498,8 @@ void ieee80211_softmac_scan_wq(struct work_struct *work)
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
static short watchdog = 0;
-#ifdef ENABLE_DOT11D
u8 channel_map[MAX_CHANNEL_NUMBER+1];
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
-#endif
if(!ieee->ieee_up)
return;
down(&ieee->scan_sem);
@@ -523,25 +509,16 @@ void ieee80211_softmac_scan_wq(struct work_struct *work)
if (watchdog++ > MAX_CHANNEL_NUMBER)
{
//if current channel is not in channel map, set to default channel.
- #ifdef ENABLE_DOT11D
- if (!channel_map[ieee->current_network.channel]);
- #else
- if (!ieee->channel_map[ieee->current_network.channel]);
- #endif
+ if (!channel_map[ieee->current_network.channel]) {
ieee->current_network.channel = 6;
goto out; /* no good chans */
+ }
}
-#ifdef ENABLE_DOT11D
}while(!channel_map[ieee->current_network.channel]);
-#else
- }while(!ieee->channel_map[ieee->current_network.channel]);
-#endif
if (ieee->scanning == 0 )
goto out;
ieee->set_chan(ieee->dev, ieee->current_network.channel);
-#ifdef ENABLE_DOT11D
if(channel_map[ieee->current_network.channel] == 1)
-#endif
ieee80211_send_probe_requests(ieee);
@@ -550,10 +527,8 @@ void ieee80211_softmac_scan_wq(struct work_struct *work)
up(&ieee->scan_sem);
return;
out:
-#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee))
DOT11D_ScanComplete(ieee);
-#endif
ieee->actscanning = false;
watchdog = 0;
ieee->scanning = 0;
@@ -635,7 +610,6 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
/* called with ieee->lock held */
void ieee80211_start_scan(struct ieee80211_device *ieee)
{
-#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee) )
{
if(IS_COUNTRY_IE_VALID(ieee))
@@ -643,7 +617,6 @@ void ieee80211_start_scan(struct ieee80211_device *ieee)
RESET_CIE_WATCHDOG(ieee);
}
}
-#endif
if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){
if (ieee->scanning == 0){
ieee->scanning = 1;
@@ -657,7 +630,6 @@ void ieee80211_start_scan(struct ieee80211_device *ieee)
/* called with wx_sem held */
void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
{
-#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee) )
{
if(IS_COUNTRY_IE_VALID(ieee))
@@ -665,7 +637,6 @@ void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
RESET_CIE_WATCHDOG(ieee);
}
}
-#endif
ieee->sync_scan_hurryup = 0;
if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
ieee80211_softmac_scan_syncro(ieee);
@@ -2390,11 +2361,9 @@ void ieee80211_start_ibss_wq(struct work_struct *work)
ieee80211_softmac_check_all_nets(ieee);
-#ifdef ENABLE_DOT11D //if creating an ad-hoc, set its channel to 10 temporarily--this is the requirement for ASUS, not 11D, so disable 11d.
// if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK))
if (ieee->state == IEEE80211_NOLINK)
ieee->current_network.channel = 6;
-#endif
/* if not then the state is not linked. Maybe the user swithced to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
@@ -2483,7 +2452,6 @@ inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
void ieee80211_start_bss(struct ieee80211_device *ieee)
{
unsigned long flags;
-#ifdef ENABLE_DOT11D
//
// Ref: 802.11d 11.1.3.3
// STA shall not start a BSS unless properly formed Beacon frame including a Country IE.
@@ -2495,7 +2463,6 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
return;
}
}
-#endif
/* check if we have already found the net we
* are interested in (if any).
* if not (we are disassociated and we are not
@@ -2530,10 +2497,8 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
-#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee))
Dot11d_Reset(ieee);
-#endif
ieee->state = IEEE80211_NOLINK;
ieee->is_set_key = false;
ieee->link_change(ieee->dev);
@@ -2669,11 +2634,7 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee)
ch++;
if (ch > MAX_CHANNEL_NUMBER)
return; /* no channel found */
-#ifdef ENABLE_DOT11D
}while(!GET_DOT11D_INFO(ieee)->channel_map[ch]);
-#else
- }while(!ieee->channel_map[ch]);
-#endif
ieee->current_network.channel = ch;
}
@@ -2721,11 +2682,9 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
for(i = 0; i < 5; i++) {
ieee->seq_ctrl[i] = 0;
}
-#ifdef ENABLE_DOT11D
ieee->pDot11dInfo = kzalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC);
if (!ieee->pDot11dInfo)
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n");
-#endif
//added for AP roaming
ieee->LinkDetectInfo.SlotNum = 2;
ieee->LinkDetectInfo.NumRecvBcnInPeriod=0;
@@ -2796,13 +2755,11 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
void ieee80211_softmac_free(struct ieee80211_device *ieee)
{
down(&ieee->wx_sem);
-#ifdef ENABLE_DOT11D
if(NULL != ieee->pDot11dInfo)
{
kfree(ieee->pDot11dInfo);
ieee->pDot11dInfo = NULL;
}
-#endif
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index f335c258ba84..cb5a3c32974e 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -15,9 +15,7 @@
#include "ieee80211.h"
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
/* FIXME: add A freqs */
const long ieee80211_wlan_frequencies[] = {
@@ -63,12 +61,10 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info
}else { /* Set the channel */
-#ifdef ENABLE_DOT11D
if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) {
ret = -EINVAL;
goto out;
}
-#endif
ieee->current_network.channel = fwrq->m;
ieee->set_chan(ieee->dev, ieee->current_network.channel);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 81aa2ed226ac..ec7845ecdb7e 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -754,7 +754,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
{
txb->queue_index = UP2AC(skb->priority);
} else {
- txb->queue_index = WME_AC_BK;;
+ txb->queue_index = WME_AC_BK;
}
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 494f180acc26..ae4f2b9d9e8f 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -77,9 +77,7 @@ double __extendsfdf2(float a) {return a;}
#include "r8192_pm.h"
#endif
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
//set here to open your trace code. //WB
u32 rt_global_debug_component = \
// COMP_INIT |
@@ -166,7 +164,6 @@ static struct usb_driver rtl8192_usb_driver = {
#endif
};
-#ifdef ENABLE_DOT11D
typedef struct _CHANNEL_LIST
{
@@ -242,9 +239,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv)
}
return;
}
-#endif
-#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
#define rx_hal_is_cck_rate(_pdrvinfo)\
(_pdrvinfo->RxRate == DESC90_RATE1M ||\
@@ -1507,7 +1502,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
{
//
// Handle HW Beacon:
- // We had transfer our beacon frame to host controler at this moment.
+ // We had transfer our beacon frame to host controller at this moment.
//
//
// Caution:
@@ -2203,6 +2198,8 @@ short rtl8192_usb_initendpoints(struct net_device *dev)
priv->rx_urb = kmalloc(sizeof(struct urb *) * (MAX_RX_URB+1),
GFP_KERNEL);
+ if (priv->rx_urb == NULL)
+ return -ENOMEM;
#ifndef JACKSON_NEW_RX
for(i=0;i<(MAX_RX_URB+1);i++){
@@ -3155,7 +3152,6 @@ static void rtl8192_read_eeprom_info(struct net_device* dev)
short rtl8192_get_channel_map(struct net_device * dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
-#ifdef ENABLE_DOT11D
if(priv->ChannelPlan > COUNTRY_CODE_GLOBAL_DOMAIN){
printk("rtl8180_init:Error channel plan! Set to default.\n");
priv->ChannelPlan= 0;
@@ -3163,21 +3159,6 @@ short rtl8192_get_channel_map(struct net_device * dev)
RT_TRACE(COMP_INIT, "Channel plan is %d\n",priv->ChannelPlan);
rtl819x_set_channel_map(priv->ChannelPlan, priv);
-#else
- int ch,i;
- //Set Default Channel Plan
- if(!channels){
- DMESG("No channels, aborting");
- return -1;
- }
- ch=channels;
- priv->ChannelPlan= 0;//hikaru
- // set channels 1..14 allowed in given locale
- for (i=1; i<=14; i++) {
- (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01);
- ch >>= 1;
- }
-#endif
return 0;
}
@@ -5085,7 +5066,7 @@ static void rtl8192_query_rxphystatus(
//Get Rx snr value in DB
tmp_rxsnr = pofdm_buf->rxsnr_X[i];
rx_snrX = (char)(tmp_rxsnr);
- //rx_snrX >>= 1;;
+ //rx_snrX >>= 1;
rx_snrX /= 2;
priv->stats.rxSNRdB[i] = (long)rx_snrX;
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index 25d5c870b0fb..f6408f98ede6 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -21,9 +21,7 @@
#include "r8192U.h"
#include "r8192U_hw.h"
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
#define RATE_COUNT 12
u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000,
@@ -458,11 +456,7 @@ static int rtl8180_wx_get_range(struct net_device *dev,
for (i = 0, val = 0; i < 14; i++) {
// Include only legal frequencies for some countries
-#ifdef ENABLE_DOT11D
if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) {
-#else
- if ((priv->ieee80211->channel_map)[i+1]) {
-#endif
range->freq[val].i = i + 1;
range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
range->freq[val].e = 1;
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index a3adaedece9a..41684e8fcf4c 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -6,9 +6,7 @@
#include "r8192U_dm.h"
#include "r819xU_firmware_img.h"
-#ifdef ENABLE_DOT11D
#include "dot11d.h"
-#endif
static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
0,
0x085c, //2412 1
@@ -1011,7 +1009,7 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E
break;
}
- return ret;;
+ return ret;
}
/******************************************************************************
@@ -1257,13 +1255,11 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u
RT_TRACE(COMP_CH, "====>%s()====stage:%d, step:%d, channel:%d\n", __FUNCTION__, *stage, *step, channel);
// RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel));
-#ifdef ENABLE_DOT11D
if (!IsLegalChannel(priv->ieee80211, channel))
{
RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel);
return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop.
}
-#endif
//FIXME:need to check whether channel is legal or not here.WB
diff --git a/drivers/staging/rtl8712/TODO b/drivers/staging/rtl8712/TODO
index 5c888214666e..2aa5deb3af7b 100644
--- a/drivers/staging/rtl8712/TODO
+++ b/drivers/staging/rtl8712/TODO
@@ -3,7 +3,6 @@ TODO:
- switch to use LIB80211
- switch to use MAC80211
- checkpatch.pl fixes - only a few remain
-- sparse fixes
- switch from large inline firmware file to use the firmware interface
and add the file to the linux-firmware package.
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 7fca42c7c0d4..36eeb5a1b5a5 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kref.h>
-#include <linux/smp_lock.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
@@ -161,7 +160,7 @@ static inline u32 _down_sema(struct semaphore *sema)
static inline void _rtl_rwlock_init(struct semaphore *prwlock)
{
- init_MUTEX(prwlock);
+ sema_init(prwlock, 1);
}
static inline void _init_listhead(struct list_head *list)
@@ -196,10 +195,7 @@ static inline void sleep_schedulable(int ms)
static inline u8 *_malloc(u32 sz)
{
- u8 *pbuf;
-
- pbuf = kmalloc(sz, GFP_ATOMIC);
- return pbuf;
+ return kmalloc(sz, GFP_ATOMIC);
}
static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer)
@@ -221,34 +217,22 @@ static inline void flush_signals_thread(void)
static inline u32 _RND8(u32 sz)
{
- u32 val;
-
- val = ((sz >> 3) + ((sz & 7) ? 1 : 0)) << 3;
- return val;
+ return ((sz >> 3) + ((sz & 7) ? 1 : 0)) << 3;
}
static inline u32 _RND128(u32 sz)
{
- u32 val;
-
- val = ((sz >> 7) + ((sz & 127) ? 1 : 0)) << 7;
- return val;
+ return ((sz >> 7) + ((sz & 127) ? 1 : 0)) << 7;
}
static inline u32 _RND256(u32 sz)
{
- u32 val;
-
- val = ((sz >> 8) + ((sz & 255) ? 1 : 0)) << 8;
- return val;
+ return ((sz >> 8) + ((sz & 255) ? 1 : 0)) << 8;
}
static inline u32 _RND512(u32 sz)
{
- u32 val;
-
- val = ((sz >> 9) + ((sz & 511) ? 1 : 0)) << 9;
- return val;
+ return ((sz >> 9) + ((sz & 511) ? 1 : 0)) << 9;
}
#define STRUCT_PACKED __attribute__ ((packed))
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index 9730ae1c58d5..1dc12b7a2f52 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -428,7 +428,7 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
u16 cnts, u8 *data)
{
int i;
- u8 res = true;;
+ u8 res = true;
if (start_addr > EFUSE_MAX_SIZE)
return false;
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 8edc518536f9..88a15049bc2a 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -148,7 +148,7 @@ static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe)
case 0x11:
case 0x12:
case 0x13:
- addr = RTL8712_DMA_H2CCMD;;
+ addr = RTL8712_DMA_H2CCMD;
break;
default:
addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index b8195e3a72d4..75f1a6bba2f6 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -372,7 +372,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0};
datalen = pattrib->pktlen - pattrib->hdrlen;
- pframe = pxmitframe->buf_addr + TXDESC_OFFSET;;
+ pframe = pxmitframe->buf_addr + TXDESC_OFFSET;
if (bmcst) {
if (!memcmp(psecuritypriv->XGrptxmickey
[psecuritypriv->XGrpKeyid].skey,
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index f6569dce3012..0e9483bbabe1 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -37,7 +37,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
{
u8 val8 = 0;
u8 ret = _SUCCESS;
- u8 PollingCnt = 20;
+ int PollingCnt = 20;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
if (pregistrypriv->chip_version == RTL8712_FPGA) {
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index f1f0c63e5bbc..a692ee88b9e9 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -527,7 +527,7 @@ error:
static void r871xu_dev_remove(struct usb_interface *pusb_intf)
{
struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
- struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev);
+ struct _adapter *padapter = netdev_priv(pnetdev);
struct usb_device *udev = interface_to_usbdev(pusb_intf);
if (padapter) {
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
index eb44b60e1eb5..701e8d52a9fa 100644
--- a/drivers/staging/samsung-laptop/samsung-laptop.c
+++ b/drivers/staging/samsung-laptop/samsung-laptop.c
@@ -269,7 +269,7 @@ static int update_status(struct backlight_device *bd)
return 0;
}
-static struct backlight_ops backlight_ops = {
+static const struct backlight_ops backlight_ops = {
.get_brightness = get_brightness,
.update_status = update_status,
};
@@ -356,7 +356,7 @@ static ssize_t set_silent_state(struct device *dev,
}
return count;
}
-static DEVICE_ATTR(silent, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(silent, S_IWUSR | S_IRUGO,
get_silent_state, set_silent_state);
diff --git a/drivers/staging/se401/Kconfig b/drivers/staging/se401/Kconfig
new file mode 100644
index 000000000000..b7f8222ad21b
--- /dev/null
+++ b/drivers/staging/se401/Kconfig
@@ -0,0 +1,13 @@
+config USB_SE401
+ tristate "USB SE401 Camera support (DEPRECATED)"
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB
+ ---help---
+ Say Y here if you want to connect this type of camera to your
+ computer's USB port. See <file:Documentation/video4linux/se401.txt>
+ for more information and for a list of supported cameras.
+
+ This driver uses the deprecated V4L1 API and will be removed in
+ 2.6.39, unless someone converts it to the V4L2 API.
+
+ To compile this driver as a module, choose M here: the
+ module will be called se401.
diff --git a/drivers/staging/se401/Makefile b/drivers/staging/se401/Makefile
new file mode 100644
index 000000000000..b465d49783af
--- /dev/null
+++ b/drivers/staging/se401/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_SE401) += se401.o
diff --git a/drivers/staging/se401/TODO b/drivers/staging/se401/TODO
new file mode 100644
index 000000000000..3b2c03836286
--- /dev/null
+++ b/drivers/staging/se401/TODO
@@ -0,0 +1,5 @@
+This is an obsolete driver for some old webcams that still use V4L1 API.
+As V4L1 support is being removed from kernel, if nobody take care on it,
+the driver will be removed for 2.6.39.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/media/video/se401.c b/drivers/staging/se401/se401.c
index 41d0166c0f95..41360d7c3e96 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/staging/se401/se401.c
@@ -31,7 +31,6 @@ static const char version[] = "0.24";
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/usb.h>
#include "se401.h"
@@ -951,9 +950,9 @@ static int se401_open(struct file *file)
struct usb_se401 *se401 = (struct usb_se401 *)dev;
int err = 0;
- lock_kernel();
+ mutex_lock(&se401->lock);
if (se401->user) {
- unlock_kernel();
+ mutex_unlock(&se401->lock);
return -EBUSY;
}
se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
@@ -962,7 +961,7 @@ static int se401_open(struct file *file)
else
err = -ENOMEM;
se401->user = !err;
- unlock_kernel();
+ mutex_unlock(&se401->lock);
return err;
}
diff --git a/drivers/media/video/se401.h b/drivers/staging/se401/se401.h
index bf7d2e9765b0..2758f4716c3d 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/staging/se401/se401.h
@@ -3,7 +3,7 @@
#define __LINUX_se401_H
#include <linux/uaccess.h>
-#include <linux/videodev.h>
+#include "videodev.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <linux/mutex.h>
diff --git a/drivers/staging/se401/videodev.h b/drivers/staging/se401/videodev.h
new file mode 100644
index 000000000000..f11efbef1c05
--- /dev/null
+++ b/drivers/staging/se401/videodev.h
@@ -0,0 +1,318 @@
+/*
+ * Video for Linux version 1 - OBSOLETE
+ *
+ * Header file for v4l1 drivers and applications, for
+ * Linux kernels 2.2.x or 2.4.x.
+ *
+ * Provides header for legacy drivers and applications
+ *
+ * See http://linuxtv.org for more info
+ *
+ */
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/videodev2.h>
+
+#define VID_TYPE_CAPTURE 1 /* Can capture */
+#define VID_TYPE_TUNER 2 /* Can tune */
+#define VID_TYPE_TELETEXT 4 /* Does teletext */
+#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING 32 /* Can clip */
+#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES 128 /* Scalable */
+#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ __u32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ __u16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+ __u16 norm; /* Norm set by channel */
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ unsigned long rangelow, rangehigh; /* Tuner range */
+ __u32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */
+ __u16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ __u16 brightness;
+ __u16 hue;
+ __u16 colour;
+ __u16 contrast;
+ __u16 whiteness; /* Black and white only */
+ __u16 depth; /* Capture depth */
+ __u16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ __u16 volume; /* If settable */
+ __u16 bass, treble;
+ __u32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+#define VIDEO_AUDIO_BALANCE 32
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 4
+#define VIDEO_SOUND_LANG2 8
+ __u16 mode;
+ __u16 balance; /* Stereo balance */
+ __u16 step; /* Step actual volume uses */
+};
+
+struct video_clip
+{
+ __s32 x,y;
+ __s32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ __u32 x,y; /* Position of window */
+ __u32 width,height; /* Its size */
+ __u32 chromakey;
+ __u32 flags;
+ struct video_clip __user *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
+};
+
+struct video_capture
+{
+ __u32 x,y; /* Offsets into image */
+ __u32 width, height; /* Area to capture */
+ __u16 decimation; /* Decimation divider */
+ __u16 flags; /* Flags for capture */
+#define VIDEO_CAPTURE_ODD 0 /* Temporal */
+#define VIDEO_CAPTURE_EVEN 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 - n) for double buffer */
+ int height,width;
+ unsigned int format; /* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+ __u8 key[8];
+ __u32 flags;
+};
+
+struct video_mbuf
+{
+ int size; /* Total memory to map */
+ int frames; /* Frames */
+ int offsets[VIDEO_MAX_FRAME];
+};
+
+#define VIDEO_NO_UNIT (-1)
+
+struct video_unit
+{
+ int video; /* Video minor */
+ int vbi; /* VBI minor */
+ int radio; /* Radio minor */
+ int audio; /* Audio minor */
+ int teletext; /* Teletext minor */
+};
+
+struct vbi_format {
+ __u32 sampling_rate; /* in Hz */
+ __u32 samples_per_line;
+ __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */
+ __s32 start[2]; /* starting line for each frame */
+ __u32 count[2]; /* count of lines for each frame */
+ __u32 flags;
+#define VBI_UNSYNC 1 /* can distingues between top/bottom field */
+#define VBI_INTERLACED 2 /* lines are interlaced */
+};
+
+/* video_info is biased towards hardware mpeg encode/decode */
+/* but it could apply generically to any hardware compressor/decompressor */
+struct video_info
+{
+ __u32 frame_count; /* frames output since decode/encode began */
+ __u32 h_size; /* current unscaled horizontal size */
+ __u32 v_size; /* current unscaled veritcal size */
+ __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */
+ __u32 picture_type; /* current picture type */
+ __u32 temporal_reference; /* current temporal reference */
+ __u8 user_data[256]; /* user data last found in compressed stream */
+ /* user_data[0] contains user data flags, user_data[1] has count */
+};
+
+/* generic structure for setting playback modes */
+struct video_play_mode
+{
+ int mode;
+ int p1;
+ int p2;
+};
+
+/* for loading microcode / fpga programming */
+struct video_code
+{
+ char loadwhat[16]; /* name or tag of file being passed */
+ int datasize;
+ __u8 *data;
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
+#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
+#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
+#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
+#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
+#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
+#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
+
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+/* VIDIOCSWRITEMODE */
+#define VID_WRITE_MPEG_AUD 0
+#define VID_WRITE_MPEG_VID 1
+#define VID_WRITE_OSD 2
+#define VID_WRITE_TTX 3
+#define VID_WRITE_CC 4
+#define VID_WRITE_MJPEG 5
+
+/* VIDIOCSPLAYMODE */
+#define VID_PLAY_VID_OUT_MODE 0
+ /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
+#define VID_PLAY_GENLOCK 1
+ /* p1: 0 = OFF, 1 = ON */
+ /* p2: GENLOCK FINE DELAY value */
+#define VID_PLAY_NORMAL 2
+#define VID_PLAY_PAUSE 3
+#define VID_PLAY_SINGLE_FRAME 4
+#define VID_PLAY_FAST_FORWARD 5
+#define VID_PLAY_SLOW_MOTION 6
+#define VID_PLAY_IMMEDIATE_NORMAL 7
+#define VID_PLAY_SWITCH_CHANNELS 8
+#define VID_PLAY_FREEZE_FRAME 9
+#define VID_PLAY_STILL_MODE 10
+#define VID_PLAY_MASTER_MODE 11
+ /* p1: see below */
+#define VID_PLAY_MASTER_NONE 1
+#define VID_PLAY_MASTER_VIDEO 2
+#define VID_PLAY_MASTER_AUDIO 3
+#define VID_PLAY_ACTIVE_SCANLINES 12
+ /* p1 = first active; p2 = last active */
+#define VID_PLAY_RESET 13
+#define VID_PLAY_END_MARK 14
+
+#endif /* __LINUX_VIDEODEV_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig
new file mode 100644
index 000000000000..92bf16667d04
--- /dev/null
+++ b/drivers/staging/sep/Kconfig
@@ -0,0 +1,10 @@
+config DX_SEP
+ tristate "Discretix SEP driver"
+ depends on PCI
+ help
+ Discretix SEP driver; used for the security processor subsystem
+ on bard the Intel Mobile Internet Device.
+
+ The driver's name is sep_driver.
+
+ If unsure, select N.
diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile
new file mode 100644
index 000000000000..628d5f919414
--- /dev/null
+++ b/drivers/staging/sep/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_DX_SEP) := sep_driver.o
+
diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO
new file mode 100644
index 000000000000..089c2406345e
--- /dev/null
+++ b/drivers/staging/sep/TODO
@@ -0,0 +1,5 @@
+Todo's so far (from Alan Cox)
+- Check whether it can be plugged into any of the kernel crypto API
+ interfaces - Crypto API 'glue' is still not ready to submit
+- Clean up unused ioctls - Needs vendor help
+- Clean up unused fields in ioctl structures - Needs vendor help
diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h
new file mode 100644
index 000000000000..0ffe68cb7140
--- /dev/null
+++ b/drivers/staging/sep/sep_dev.h
@@ -0,0 +1,156 @@
+#ifndef __SEP_DEV_H__
+#define __SEP_DEV_H__
+
+/*
+ *
+ * sep_dev.h - Security Processor Device Structures
+ *
+ * Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
+ * Contributions(c) 2009,2010 Discretix. 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * CONTACTS:
+ *
+ * Mark Allyn mark.a.allyn@intel.com
+ * Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ * CHANGES
+ * 2010.09.14 upgrade to Medfield
+ */
+
+struct sep_device {
+ /* pointer to pci dev */
+ struct pci_dev *pdev;
+
+ /* character device file */
+ struct cdev sep_cdev;
+ struct cdev sep_daemon_cdev;
+ struct cdev sep_singleton_cdev;
+
+ /* devices (using misc dev) */
+ struct miscdevice miscdev_sep;
+ struct miscdevice miscdev_singleton;
+ struct miscdevice miscdev_daemon;
+
+ /* major / minor numbers of device */
+ dev_t sep_devno;
+ dev_t sep_daemon_devno;
+ dev_t sep_singleton_devno;
+
+ struct mutex sep_mutex;
+ struct mutex ioctl_mutex;
+ spinlock_t snd_rply_lck;
+
+ /* flags to indicate use and lock status of sep */
+ u32 pid_doing_transaction;
+ unsigned long in_use_flags;
+
+ /* request daemon alread open */
+ unsigned long request_daemon_open;
+
+ /* 1 = Moorestown; 0 = Medfield */
+ int mrst;
+
+ /* address of the shared memory allocated during init for SEP driver
+ (coherent alloc) */
+ dma_addr_t shared_bus;
+ size_t shared_size;
+ void *shared_addr;
+
+ /* restricted access region (coherent alloc) */
+ dma_addr_t rar_bus;
+ size_t rar_size;
+ void *rar_addr;
+
+ /* Firmware regions; cache is at rar for Moorestown and
+ resident is at rar for Medfield */
+ dma_addr_t cache_bus;
+ size_t cache_size;
+ void *cache_addr;
+
+ dma_addr_t resident_bus;
+ size_t resident_size;
+ void *resident_addr;
+
+ /* sep's scratchpad */
+ dma_addr_t dcache_bus;
+ size_t dcache_size;
+ void *dcache_addr;
+
+ /* Only used on Medfield */
+ dma_addr_t extapp_bus;
+ size_t extapp_size;
+ void *extapp_addr;
+
+ /* start address of the access to the SEP registers from driver */
+ dma_addr_t reg_physical_addr;
+ dma_addr_t reg_physical_end;
+ void __iomem *reg_addr;
+
+ /* wait queue head (event) of the driver */
+ wait_queue_head_t event;
+ wait_queue_head_t event_request_daemon;
+ wait_queue_head_t event_mmap;
+
+ struct sep_caller_id_entry
+ caller_id_table[SEP_CALLER_ID_TABLE_NUM_ENTRIES];
+
+ /* access flag for singleton device */
+ unsigned long singleton_access_flag;
+
+ /* transaction counter that coordinates the
+ transactions between SEP and HOST */
+ unsigned long send_ct;
+ /* counter for the messages from sep */
+ unsigned long reply_ct;
+ /* counter for the number of bytes allocated in the pool for the
+ current transaction */
+ long data_pool_bytes_allocated;
+
+ u32 num_of_data_allocations;
+
+ /* number of the lli tables created in the current transaction */
+ u32 num_lli_tables_created;
+
+ /* number of data control blocks */
+ u32 nr_dcb_creat;
+
+ struct sep_dma_resource dma_res_arr[SEP_MAX_NUM_SYNC_DMA_OPS];
+
+};
+
+static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value)
+{
+ void __iomem *addr = dev->reg_addr + reg;
+ writel(value, addr);
+}
+
+static inline u32 sep_read_reg(struct sep_device *dev, int reg)
+{
+ void __iomem *addr = dev->reg_addr + reg;
+ return readl(addr);
+}
+
+/* wait for SRAM write complete(indirect write */
+static inline void sep_wait_sram_write(struct sep_device *dev)
+{
+ u32 reg_val;
+ do {
+ reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR);
+ } while (!(reg_val & 1));
+}
+
+
+#endif
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
new file mode 100644
index 000000000000..ac5d56943d4b
--- /dev/null
+++ b/drivers/staging/sep/sep_driver.c
@@ -0,0 +1,3577 @@
+/*
+ *
+ * sep_driver.c - Security Processor Driver main group of functions
+ *
+ * Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
+ * Contributions(c) 2009,2010 Discretix. 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * CONTACTS:
+ *
+ * Mark Allyn mark.a.allyn@intel.com
+ * Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ * CHANGES:
+ *
+ * 2009.06.26 Initial publish
+ * 2010.09.14 Upgrade to Medfield
+ *
+ */
+#define DEBUG
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kdev_t.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <asm/current.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <asm/cacheflush.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/rar_register.h>
+
+#include "../memrar/memrar.h"
+
+#include "sep_driver_hw_defs.h"
+#include "sep_driver_config.h"
+#include "sep_driver_api.h"
+#include "sep_dev.h"
+
+/*----------------------------------------
+ DEFINES
+-----------------------------------------*/
+
+#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000
+
+/*--------------------------------------------
+ GLOBAL variables
+--------------------------------------------*/
+
+/* Keep this a single static object for now to keep the conversion easy */
+
+static struct sep_device *sep_dev;
+
+/**
+ * sep_load_firmware - copy firmware cache/resident
+ * @sep: pointer to struct sep_device we are loading
+ *
+ * This functions copies the cache and resident from their source
+ * location into destination shared memory.
+ */
+static int sep_load_firmware(struct sep_device *sep)
+{
+ const struct firmware *fw;
+ char *cache_name = "cache.image.bin";
+ char *res_name = "resident.image.bin";
+ char *extapp_name = "extapp.image.bin";
+ int error ;
+ unsigned long work1, work2, work3;
+
+ /* Set addresses and load resident */
+ sep->resident_bus = sep->rar_bus;
+ sep->resident_addr = sep->rar_addr;
+
+ error = request_firmware(&fw, res_name, &sep->pdev->dev);
+ if (error) {
+ dev_warn(&sep->pdev->dev, "can't request resident fw\n");
+ return error;
+ }
+
+ memcpy(sep->resident_addr, (void *)fw->data, fw->size);
+ sep->resident_size = fw->size;
+ release_firmware(fw);
+
+ dev_dbg(&sep->pdev->dev, "resident virtual is %p\n",
+ sep->resident_addr);
+ dev_dbg(&sep->pdev->dev, "resident bus is %lx\n",
+ (unsigned long)sep->resident_bus);
+ dev_dbg(&sep->pdev->dev, "resident size is %08zx\n",
+ sep->resident_size);
+
+ /* Set addresses for dcache (no loading needed) */
+ work1 = (unsigned long)sep->resident_bus;
+ work2 = (unsigned long)sep->resident_size;
+ work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000;
+ sep->dcache_bus = (dma_addr_t)work3;
+
+ work1 = (unsigned long)sep->resident_addr;
+ work2 = (unsigned long)sep->resident_size;
+ work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000;
+ sep->dcache_addr = (void *)work3;
+
+ sep->dcache_size = 1024 * 128;
+
+ /* Set addresses and load cache */
+ sep->cache_bus = sep->dcache_bus + sep->dcache_size;
+ sep->cache_addr = sep->dcache_addr + sep->dcache_size;
+
+ error = request_firmware(&fw, cache_name, &sep->pdev->dev);
+ if (error) {
+ dev_warn(&sep->pdev->dev, "Unable to request cache firmware\n");
+ return error;
+ }
+
+ memcpy(sep->cache_addr, (void *)fw->data, fw->size);
+ sep->cache_size = fw->size;
+ release_firmware(fw);
+
+ dev_dbg(&sep->pdev->dev, "cache virtual is %p\n",
+ sep->cache_addr);
+ dev_dbg(&sep->pdev->dev, "cache bus is %08lx\n",
+ (unsigned long)sep->cache_bus);
+ dev_dbg(&sep->pdev->dev, "cache size is %08zx\n",
+ sep->cache_size);
+
+ /* Set addresses and load extapp */
+ sep->extapp_bus = sep->cache_bus + (1024 * 370);
+ sep->extapp_addr = sep->cache_addr + (1024 * 370);
+
+ error = request_firmware(&fw, extapp_name, &sep->pdev->dev);
+ if (error) {
+ dev_warn(&sep->pdev->dev, "Unable to request extapp firmware\n");
+ return error;
+ }
+
+ memcpy(sep->extapp_addr, (void *)fw->data, fw->size);
+ sep->extapp_size = fw->size;
+ release_firmware(fw);
+
+ dev_dbg(&sep->pdev->dev, "extapp virtual is %p\n",
+ sep->extapp_addr);
+ dev_dbg(&sep->pdev->dev, "extapp bus is %08llx\n",
+ (unsigned long long)sep->extapp_bus);
+ dev_dbg(&sep->pdev->dev, "extapp size is %08zx\n",
+ sep->extapp_size);
+
+ return error;
+}
+
+MODULE_FIRMWARE("sep/cache.image.bin");
+MODULE_FIRMWARE("sep/resident.image.bin");
+MODULE_FIRMWARE("sep/extapp.image.bin");
+
+/**
+ * sep_dump_message - dump the message that is pending
+ * @sep: SEP device
+ */
+static void sep_dump_message(struct sep_device *sep)
+{
+ int count;
+ u32 *p = sep->shared_addr;
+ for (count = 0; count < 12 * 4; count += 4)
+ dev_dbg(&sep->pdev->dev, "Word %d of the message is %x\n",
+ count, *p++);
+}
+
+/**
+ * sep_map_and_alloc_shared_area - allocate shared block
+ * @sep: security processor
+ * @size: size of shared area
+ */
+static int sep_map_and_alloc_shared_area(struct sep_device *sep)
+{
+ sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev,
+ sep->shared_size,
+ &sep->shared_bus, GFP_KERNEL);
+
+ if (!sep->shared_addr) {
+ dev_warn(&sep->pdev->dev,
+ "shared memory dma_alloc_coherent failed\n");
+ return -ENOMEM;
+ }
+ dev_dbg(&sep->pdev->dev,
+ "shared_addr %zx bytes @%p (bus %llx)\n",
+ sep->shared_size, sep->shared_addr,
+ (unsigned long long)sep->shared_bus);
+ return 0;
+}
+
+/**
+ * sep_unmap_and_free_shared_area - free shared block
+ * @sep: security processor
+ */
+static void sep_unmap_and_free_shared_area(struct sep_device *sep)
+{
+ dev_dbg(&sep->pdev->dev, "shared area unmap and free\n");
+ dma_free_coherent(&sep->pdev->dev, sep->shared_size,
+ sep->shared_addr, sep->shared_bus);
+}
+
+/**
+ * sep_shared_bus_to_virt - convert bus/virt addresses
+ * @sep: pointer to struct sep_device
+ * @bus_address: address to convert
+ *
+ * Returns virtual address inside the shared area according
+ * to the bus address.
+ */
+static void *sep_shared_bus_to_virt(struct sep_device *sep,
+ dma_addr_t bus_address)
+{
+ return sep->shared_addr + (bus_address - sep->shared_bus);
+}
+
+/**
+ * open function for the singleton driver
+ * @inode_ptr struct inode *
+ * @file_ptr struct file *
+ *
+ * Called when the user opens the singleton device interface
+ */
+static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr)
+{
+ int error = 0;
+ struct sep_device *sep;
+
+ /*
+ * Get the SEP device structure and use it for the
+ * private_data field in filp for other methods
+ */
+ sep = sep_dev;
+
+ file_ptr->private_data = sep;
+
+ dev_dbg(&sep->pdev->dev, "Singleton open for pid %d\n", current->pid);
+
+ dev_dbg(&sep->pdev->dev, "calling test and set for singleton 0\n");
+ if (test_and_set_bit(0, &sep->singleton_access_flag)) {
+ error = -EBUSY;
+ goto end_function;
+ }
+
+ dev_dbg(&sep->pdev->dev, "sep_singleton_open end\n");
+end_function:
+ return error;
+}
+
+/**
+ * sep_open - device open method
+ * @inode: inode of SEP device
+ * @filp: file handle to SEP device
+ *
+ * Open method for the SEP device. Called when userspace opens
+ * the SEP device node.
+ *
+ * Returns zero on success otherwise an error code.
+ */
+static int sep_open(struct inode *inode, struct file *filp)
+{
+ struct sep_device *sep;
+
+ /*
+ * Get the SEP device structure and use it for the
+ * private_data field in filp for other methods
+ */
+ sep = sep_dev;
+ filp->private_data = sep;
+
+ dev_dbg(&sep->pdev->dev, "Open for pid %d\n", current->pid);
+
+ /* Anyone can open; locking takes place at transaction level */
+ return 0;
+}
+
+/**
+ * sep_singleton_release - close a SEP singleton device
+ * @inode: inode of SEP device
+ * @filp: file handle being closed
+ *
+ * Called on the final close of a SEP device. As the open protects against
+ * multiple simultaenous opens that means this method is called when the
+ * final reference to the open handle is dropped.
+ */
+static int sep_singleton_release(struct inode *inode, struct file *filp)
+{
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "Singleton release for pid %d\n",
+ current->pid);
+ clear_bit(0, &sep->singleton_access_flag);
+ return 0;
+}
+
+/**
+ * sep_request_daemonopen - request daemon open method
+ * @inode: inode of SEP device
+ * @filp: file handle to SEP device
+ *
+ * Open method for the SEP request daemon. Called when
+ * request daemon in userspace opens the SEP device node.
+ *
+ * Returns zero on success otherwise an error code.
+ */
+static int sep_request_daemon_open(struct inode *inode, struct file *filp)
+{
+ struct sep_device *sep = sep_dev;
+ int error = 0;
+
+ filp->private_data = sep;
+
+ dev_dbg(&sep->pdev->dev, "Request daemon open for pid %d\n",
+ current->pid);
+
+ /* There is supposed to be only one request daemon */
+ dev_dbg(&sep->pdev->dev, "calling test and set for req_dmon open 0\n");
+ if (test_and_set_bit(0, &sep->request_daemon_open))
+ error = -EBUSY;
+ return error;
+}
+
+/**
+ * sep_request_daemon_release - close a SEP daemon
+ * @inode: inode of SEP device
+ * @filp: file handle being closed
+ *
+ * Called on the final close of a SEP daemon.
+ */
+static int sep_request_daemon_release(struct inode *inode, struct file *filp)
+{
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "Reques daemon release for pid %d\n",
+ current->pid);
+
+ /* Clear the request_daemon_open flag */
+ clear_bit(0, &sep->request_daemon_open);
+ return 0;
+}
+
+/**
+ * sep_req_daemon_send_reply_command_handler - poke the SEP
+ * @sep: struct sep_device *
+ *
+ * This function raises interrupt to SEPm that signals that is has a
+ * new command from HOST
+ */
+static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep)
+{
+ unsigned long lck_flags;
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_req_daemon_send_reply_command_handler start\n");
+
+ sep_dump_message(sep);
+
+ /* Counters are lockable region */
+ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
+ sep->send_ct++;
+ sep->reply_ct++;
+
+ /* Send the interrupt to SEP */
+ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct);
+ sep->send_ct++;
+
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_req_daemon_send_reply send_ct %lx reply_ct %lx\n",
+ sep->send_ct, sep->reply_ct);
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_req_daemon_send_reply_command_handler end\n");
+
+ return 0;
+}
+
+
+/**
+ * sep_free_dma_table_data_handler - free DMA table
+ * @sep: pointere to struct sep_device
+ *
+ * Handles the request to free DMA table for synchronic actions
+ */
+static int sep_free_dma_table_data_handler(struct sep_device *sep)
+{
+ int count;
+ int dcb_counter;
+ /* Pointer to the current dma_resource struct */
+ struct sep_dma_resource *dma;
+
+ dev_dbg(&sep->pdev->dev, "sep_free_dma_table_data_handler start\n");
+
+ for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; dcb_counter++) {
+ dma = &sep->dma_res_arr[dcb_counter];
+
+ /* Unmap and free input map array */
+ if (dma->in_map_array) {
+ for (count = 0; count < dma->in_num_pages; count++) {
+ dma_unmap_page(&sep->pdev->dev,
+ dma->in_map_array[count].dma_addr,
+ dma->in_map_array[count].size,
+ DMA_TO_DEVICE);
+ }
+ kfree(dma->in_map_array);
+ }
+
+ /* Unmap output map array, DON'T free it yet */
+ if (dma->out_map_array) {
+ for (count = 0; count < dma->out_num_pages; count++) {
+ dma_unmap_page(&sep->pdev->dev,
+ dma->out_map_array[count].dma_addr,
+ dma->out_map_array[count].size,
+ DMA_FROM_DEVICE);
+ }
+ kfree(dma->out_map_array);
+ }
+
+ /* Free page cache for output */
+ if (dma->in_page_array) {
+ for (count = 0; count < dma->in_num_pages; count++) {
+ flush_dcache_page(dma->in_page_array[count]);
+ page_cache_release(dma->in_page_array[count]);
+ }
+ kfree(dma->in_page_array);
+ }
+
+ if (dma->out_page_array) {
+ for (count = 0; count < dma->out_num_pages; count++) {
+ if (!PageReserved(dma->out_page_array[count]))
+ SetPageDirty(dma->out_page_array[count]);
+ flush_dcache_page(dma->out_page_array[count]);
+ page_cache_release(dma->out_page_array[count]);
+ }
+ kfree(dma->out_page_array);
+ }
+
+ /* Reset all the values */
+ dma->in_page_array = NULL;
+ dma->out_page_array = NULL;
+ dma->in_num_pages = 0;
+ dma->out_num_pages = 0;
+ dma->in_map_array = NULL;
+ dma->out_map_array = NULL;
+ dma->in_map_num_entries = 0;
+ dma->out_map_num_entries = 0;
+ }
+
+ sep->nr_dcb_creat = 0;
+ sep->num_lli_tables_created = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_free_dma_table_data_handler end\n");
+ return 0;
+}
+
+/**
+ * sep_request_daemon_mmap - maps the shared area to user space
+ * @filp: pointer to struct file
+ * @vma: pointer to vm_area_struct
+ *
+ * Called by the kernel when the daemon attempts an mmap() syscall
+ * using our handle.
+ */
+static int sep_request_daemon_mmap(struct file *filp,
+ struct vm_area_struct *vma)
+{
+ struct sep_device *sep = filp->private_data;
+ dma_addr_t bus_address;
+ int error = 0;
+
+ dev_dbg(&sep->pdev->dev, "daemon mmap start\n");
+
+ if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
+ error = -EINVAL;
+ goto end_function;
+ }
+
+ /* Get physical address */
+ bus_address = sep->shared_bus;
+
+ dev_dbg(&sep->pdev->dev, "bus_address is %08lx\n",
+ (unsigned long)bus_address);
+
+ if (remap_pfn_range(vma, vma->vm_start, bus_address >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+
+ dev_warn(&sep->pdev->dev, "remap_page_range failed\n");
+ error = -EAGAIN;
+ goto end_function;
+ }
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "daemon mmap end\n");
+ return error;
+}
+
+/**
+ * sep_request_daemon_poll - poll implementation
+ * @sep: struct sep_device * for current SEP device
+ * @filp: struct file * for open file
+ * @wait: poll_table * for poll
+ *
+ * Called when our device is part of a poll() or select() syscall
+ */
+static unsigned int sep_request_daemon_poll(struct file *filp,
+ poll_table *wait)
+{
+ u32 mask = 0;
+ /* GPR2 register */
+ u32 retval2;
+ unsigned long lck_flags;
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "daemon poll: start\n");
+
+ poll_wait(filp, &sep->event_request_daemon, wait);
+
+ dev_dbg(&sep->pdev->dev, "daemon poll: send_ct is %lx reply ct is %lx\n",
+ sep->send_ct, sep->reply_ct);
+
+ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
+ /* Check if the data is ready */
+ if (sep->send_ct == sep->reply_ct) {
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+
+ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+ dev_dbg(&sep->pdev->dev,
+ "daemon poll: data check (GPR2) is %x\n", retval2);
+
+ /* Check if PRINT request */
+ if ((retval2 >> 30) & 0x1) {
+ dev_dbg(&sep->pdev->dev, "daemon poll: PRINTF request in\n");
+ mask |= POLLIN;
+ goto end_function;
+ }
+ /* Check if NVS request */
+ if (retval2 >> 31) {
+ dev_dbg(&sep->pdev->dev, "daemon poll: NVS request in\n");
+ mask |= POLLPRI | POLLWRNORM;
+ }
+ } else {
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+ dev_dbg(&sep->pdev->dev,
+ "daemon poll: no reply received; returning 0\n");
+ mask = 0;
+ }
+end_function:
+ dev_dbg(&sep->pdev->dev, "daemon poll: exit\n");
+ return mask;
+}
+
+/**
+ * sep_release - close a SEP device
+ * @inode: inode of SEP device
+ * @filp: file handle being closed
+ *
+ * Called on the final close of a SEP device.
+ */
+static int sep_release(struct inode *inode, struct file *filp)
+{
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "Release for pid %d\n", current->pid);
+
+ mutex_lock(&sep->sep_mutex);
+ /* Is this the process that has a transaction open?
+ * If so, lets reset pid_doing_transaction to 0 and
+ * clear the in use flags, and then wake up sep_event
+ * so that other processes can do transactions
+ */
+ dev_dbg(&sep->pdev->dev, "waking up event and mmap_event\n");
+ if (sep->pid_doing_transaction == current->pid) {
+ clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
+ clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags);
+ sep_free_dma_table_data_handler(sep);
+ wake_up(&sep->event);
+ sep->pid_doing_transaction = 0;
+ }
+
+ mutex_unlock(&sep->sep_mutex);
+ return 0;
+}
+
+/**
+ * sep_mmap - maps the shared area to user space
+ * @filp: pointer to struct file
+ * @vma: pointer to vm_area_struct
+ *
+ * Called on an mmap of our space via the normal SEP device
+ */
+static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ dma_addr_t bus_addr;
+ struct sep_device *sep = filp->private_data;
+ unsigned long error = 0;
+
+ dev_dbg(&sep->pdev->dev, "mmap start\n");
+
+ /* Set the transaction busy (own the device) */
+ wait_event_interruptible(sep->event,
+ test_and_set_bit(SEP_MMAP_LOCK_BIT,
+ &sep->in_use_flags) == 0);
+
+ if (signal_pending(current)) {
+ error = -EINTR;
+ goto end_function_with_error;
+ }
+ /*
+ * The pid_doing_transaction indicates that this process
+ * now owns the facilities to performa a transaction with
+ * the SEP. While this process is performing a transaction,
+ * no other process who has the SEP device open can perform
+ * any transactions. This method allows more than one process
+ * to have the device open at any given time, which provides
+ * finer granularity for device utilization by multiple
+ * processes.
+ */
+ mutex_lock(&sep->sep_mutex);
+ sep->pid_doing_transaction = current->pid;
+ mutex_unlock(&sep->sep_mutex);
+
+ /* Zero the pools and the number of data pool alocation pointers */
+ sep->data_pool_bytes_allocated = 0;
+ sep->num_of_data_allocations = 0;
+
+ /*
+ * Check that the size of the mapped range is as the size of the message
+ * shared area
+ */
+ if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
+ error = -EINVAL;
+ goto end_function_with_error;
+ }
+
+ dev_dbg(&sep->pdev->dev, "shared_addr is %p\n", sep->shared_addr);
+
+ /* Get bus address */
+ bus_addr = sep->shared_bus;
+
+ dev_dbg(&sep->pdev->dev,
+ "bus_address is %lx\n", (unsigned long)bus_addr);
+
+ if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_warn(&sep->pdev->dev, "remap_page_range failed\n");
+ error = -EAGAIN;
+ goto end_function_with_error;
+ }
+ dev_dbg(&sep->pdev->dev, "mmap end\n");
+ goto end_function;
+
+end_function_with_error:
+ /* Clear the bit */
+ clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
+ mutex_lock(&sep->sep_mutex);
+ sep->pid_doing_transaction = 0;
+ mutex_unlock(&sep->sep_mutex);
+
+ /* Raise event for stuck contextes */
+
+ dev_warn(&sep->pdev->dev, "mmap error - waking up event\n");
+ wake_up(&sep->event);
+
+end_function:
+ return error;
+}
+
+/**
+ * sep_poll - poll handler
+ * @filp: pointer to struct file
+ * @wait: pointer to poll_table
+ *
+ * Called by the OS when the kernel is asked to do a poll on
+ * a SEP file handle.
+ */
+static unsigned int sep_poll(struct file *filp, poll_table *wait)
+{
+ u32 mask = 0;
+ u32 retval = 0;
+ u32 retval2 = 0;
+ unsigned long lck_flags;
+
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "poll: start\n");
+
+ /* Am I the process that owns the transaction? */
+ mutex_lock(&sep->sep_mutex);
+ if (current->pid != sep->pid_doing_transaction) {
+ dev_warn(&sep->pdev->dev, "poll; wrong pid\n");
+ mask = POLLERR;
+ mutex_unlock(&sep->sep_mutex);
+ goto end_function;
+ }
+ mutex_unlock(&sep->sep_mutex);
+
+ /* Check if send command or send_reply were activated previously */
+ if (!test_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) {
+ dev_warn(&sep->pdev->dev, "poll; lock bit set\n");
+ mask = POLLERR;
+ goto end_function;
+ }
+
+ /* Add the event to the polling wait table */
+ dev_dbg(&sep->pdev->dev, "poll: calling wait sep_event\n");
+
+ poll_wait(filp, &sep->event, wait);
+
+ dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n",
+ sep->send_ct, sep->reply_ct);
+
+ /* Check if error occured during poll */
+ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+ if (retval2 != 0x0) {
+ dev_warn(&sep->pdev->dev, "poll; poll error %x\n", retval2);
+ mask |= POLLERR;
+ goto end_function;
+ }
+
+ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
+
+ if (sep->send_ct == sep->reply_ct) {
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+ retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+ dev_dbg(&sep->pdev->dev, "poll: data ready check (GPR2) %x\n",
+ retval);
+
+ /* Check if printf request */
+ if ((retval >> 30) & 0x1) {
+ dev_dbg(&sep->pdev->dev, "poll: SEP printf request\n");
+ wake_up(&sep->event_request_daemon);
+ goto end_function;
+ }
+
+ /* Check if the this is SEP reply or request */
+ if (retval >> 31) {
+ dev_dbg(&sep->pdev->dev, "poll: SEP request\n");
+ wake_up(&sep->event_request_daemon);
+ } else {
+ dev_dbg(&sep->pdev->dev, "poll: normal return\n");
+ /* In case it is again by send_reply_comand */
+ clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags);
+ sep_dump_message(sep);
+ dev_dbg(&sep->pdev->dev,
+ "poll; SEP reply POLLIN | POLLRDNORM\n");
+ mask |= POLLIN | POLLRDNORM;
+ }
+ } else {
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+ dev_dbg(&sep->pdev->dev,
+ "poll; no reply received; returning mask of 0\n");
+ mask = 0;
+ }
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "poll: end\n");
+ return mask;
+}
+
+/**
+ * sep_time_address - address in SEP memory of time
+ * @sep: SEP device we want the address from
+ *
+ * Return the address of the two dwords in memory used for time
+ * setting.
+ */
+static u32 *sep_time_address(struct sep_device *sep)
+{
+ return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES;
+}
+
+/**
+ * sep_set_time - set the SEP time
+ * @sep: the SEP we are setting the time for
+ *
+ * Calculates time and sets it at the predefined address.
+ * Called with the SEP mutex held.
+ */
+static unsigned long sep_set_time(struct sep_device *sep)
+{
+ struct timeval time;
+ u32 *time_addr; /* Address of time as seen by the kernel */
+
+
+ dev_dbg(&sep->pdev->dev, "sep_set_time start\n");
+
+ do_gettimeofday(&time);
+
+ /* Set value in the SYSTEM MEMORY offset */
+ time_addr = sep_time_address(sep);
+
+ time_addr[0] = SEP_TIME_VAL_TOKEN;
+ time_addr[1] = time.tv_sec;
+
+ dev_dbg(&sep->pdev->dev, "time.tv_sec is %lu\n", time.tv_sec);
+ dev_dbg(&sep->pdev->dev, "time_addr is %p\n", time_addr);
+ dev_dbg(&sep->pdev->dev, "sep->shared_addr is %p\n", sep->shared_addr);
+
+ return time.tv_sec;
+}
+
+/**
+ * sep_set_caller_id_handler - insert caller id entry
+ * @sep: SEP device
+ * @arg: pointer to struct caller_id_struct
+ *
+ * Inserts the data into the caller id table. Note that this function
+ * falls under the ioctl lock
+ */
+static int sep_set_caller_id_handler(struct sep_device *sep, unsigned long arg)
+{
+ void __user *hash;
+ int error = 0;
+ int i;
+ struct caller_id_struct command_args;
+
+ dev_dbg(&sep->pdev->dev, "sep_set_caller_id_handler start\n");
+
+ for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) {
+ if (sep->caller_id_table[i].pid == 0)
+ break;
+ }
+
+ if (i == SEP_CALLER_ID_TABLE_NUM_ENTRIES) {
+ dev_warn(&sep->pdev->dev, "no more caller id entries left\n");
+ dev_warn(&sep->pdev->dev, "maximum number is %d\n",
+ SEP_CALLER_ID_TABLE_NUM_ENTRIES);
+ error = -EUSERS;
+ goto end_function;
+ }
+
+ /* Copy the data */
+ if (copy_from_user(&command_args, (void __user *)arg,
+ sizeof(command_args))) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ hash = (void __user *)(unsigned long)command_args.callerIdAddress;
+
+ if (!command_args.pid || !command_args.callerIdSizeInBytes) {
+ error = -EINVAL;
+ goto end_function;
+ }
+
+ dev_dbg(&sep->pdev->dev, "pid is %x\n", command_args.pid);
+ dev_dbg(&sep->pdev->dev, "callerIdSizeInBytes is %x\n",
+ command_args.callerIdSizeInBytes);
+
+ if (command_args.callerIdSizeInBytes >
+ SEP_CALLER_ID_HASH_SIZE_IN_BYTES) {
+ error = -EMSGSIZE;
+ goto end_function;
+ }
+
+ sep->caller_id_table[i].pid = command_args.pid;
+
+ if (copy_from_user(sep->caller_id_table[i].callerIdHash,
+ hash, command_args.callerIdSizeInBytes))
+ error = -EFAULT;
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_set_caller_id_handler end\n");
+ return error;
+}
+
+/**
+ * sep_set_current_caller_id - set the caller id
+ * @sep: pointer to struct_sep_device
+ *
+ * Set the caller ID (if it exists) to the SEP. Note that this
+ * function falls under the ioctl lock
+ */
+static int sep_set_current_caller_id(struct sep_device *sep)
+{
+ int i;
+ u32 *hash_buf_ptr;
+
+ dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id start\n");
+ dev_dbg(&sep->pdev->dev, "current process is %d\n", current->pid);
+
+ /* Zero the previous value */
+ memset(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES,
+ 0, SEP_CALLER_ID_HASH_SIZE_IN_BYTES);
+
+ for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) {
+ if (sep->caller_id_table[i].pid == current->pid) {
+ dev_dbg(&sep->pdev->dev, "Caller Id found\n");
+
+ memcpy(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES,
+ (void *)(sep->caller_id_table[i].callerIdHash),
+ SEP_CALLER_ID_HASH_SIZE_IN_BYTES);
+ break;
+ }
+ }
+ /* Ensure data is in little endian */
+ hash_buf_ptr = (u32 *)sep->shared_addr +
+ SEP_CALLER_ID_OFFSET_BYTES;
+
+ for (i = 0; i < SEP_CALLER_ID_HASH_SIZE_IN_WORDS; i++)
+ hash_buf_ptr[i] = cpu_to_le32(hash_buf_ptr[i]);
+
+ dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id end\n");
+ return 0;
+}
+
+/**
+ * sep_send_command_handler - kick off a command
+ * @sep: SEP being signalled
+ *
+ * This function raises interrupt to SEP that signals that is has a new
+ * command from the host
+ *
+ * Note that this function does fall under the ioctl lock
+ */
+static int sep_send_command_handler(struct sep_device *sep)
+{
+ unsigned long lck_flags;
+ int error = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_send_command_handler start\n");
+
+ if (test_and_set_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) {
+ error = -EPROTO;
+ goto end_function;
+ }
+ sep_set_time(sep);
+
+ sep_set_current_caller_id(sep);
+
+ sep_dump_message(sep);
+
+ /* Update counter */
+ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
+ sep->send_ct++;
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_send_command_handler send_ct %lx reply_ct %lx\n",
+ sep->send_ct, sep->reply_ct);
+
+ /* Send interrupt to SEP */
+ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_send_command_handler end\n");
+ return error;
+}
+
+/**
+ * sep_allocate_data_pool_memory_handler -allocate pool memory
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to struct alloc_struct
+ *
+ * This function handles the allocate data pool memory request
+ * This function returns calculates the bus address of the
+ * allocated memory, and the offset of this area from the mapped address.
+ * Therefore, the FVOs in user space can calculate the exact virtual
+ * address of this allocated memory
+ */
+static int sep_allocate_data_pool_memory_handler(struct sep_device *sep,
+ unsigned long arg)
+{
+ int error = 0;
+ struct alloc_struct command_args;
+
+ /* Holds the allocated buffer address in the system memory pool */
+ u32 *token_addr;
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_allocate_data_pool_memory_handler start\n");
+
+ if (copy_from_user(&command_args, (void __user *)arg,
+ sizeof(struct alloc_struct))) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ /* Allocate memory */
+ if ((sep->data_pool_bytes_allocated + command_args.num_bytes) >
+ SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
+ error = -ENOMEM;
+ goto end_function;
+ }
+
+ dev_dbg(&sep->pdev->dev,
+ "bytes_allocated: %x\n", (int)sep->data_pool_bytes_allocated);
+ dev_dbg(&sep->pdev->dev,
+ "offset: %x\n", SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES);
+ /* Set the virtual and bus address */
+ command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES +
+ sep->data_pool_bytes_allocated;
+
+ dev_dbg(&sep->pdev->dev,
+ "command_args.offset: %x\n", command_args.offset);
+
+ /* Place in the shared area that is known by the SEP */
+ token_addr = (u32 *)(sep->shared_addr +
+ SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES +
+ (sep->num_of_data_allocations)*2*sizeof(u32));
+
+ dev_dbg(&sep->pdev->dev, "allocation offset: %x\n",
+ SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES);
+ dev_dbg(&sep->pdev->dev, "data pool token addr is %p\n", token_addr);
+
+ token_addr[0] = SEP_DATA_POOL_POINTERS_VAL_TOKEN;
+ token_addr[1] = (u32)sep->shared_bus +
+ SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES +
+ sep->data_pool_bytes_allocated;
+
+ dev_dbg(&sep->pdev->dev, "data pool token [0] %x\n", token_addr[0]);
+ dev_dbg(&sep->pdev->dev, "data pool token [1] %x\n", token_addr[1]);
+
+ /* Write the memory back to the user space */
+ error = copy_to_user((void *)arg, (void *)&command_args,
+ sizeof(struct alloc_struct));
+ if (error) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ /* Update the allocation */
+ sep->data_pool_bytes_allocated += command_args.num_bytes;
+ sep->num_of_data_allocations += 1;
+
+ dev_dbg(&sep->pdev->dev, "data_allocations %d\n",
+ sep->num_of_data_allocations);
+ dev_dbg(&sep->pdev->dev, "bytes allocated %d\n",
+ (int)sep->data_pool_bytes_allocated);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_allocate_data_pool_memory_handler end\n");
+ return error;
+}
+
+/**
+ * sep_lock_kernel_pages - map kernel pages for DMA
+ * @sep: pointer to struct sep_device
+ * @kernel_virt_addr: address of data buffer in kernel
+ * @data_size: size of data
+ * @lli_array_ptr: lli array
+ * @in_out_flag: input into device or output from device
+ *
+ * This function locks all the physical pages of the kernel virtual buffer
+ * and construct a basic lli array, where each entry holds the physical
+ * page address and the size that application data holds in this page
+ * This function is used only during kernel crypto mod calls from within
+ * the kernel (when ioctl is not used)
+ */
+static int sep_lock_kernel_pages(struct sep_device *sep,
+ unsigned long kernel_virt_addr,
+ u32 data_size,
+ struct sep_lli_entry **lli_array_ptr,
+ int in_out_flag)
+
+{
+ int error = 0;
+ /* Array of lli */
+ struct sep_lli_entry *lli_array;
+ /* Map array */
+ struct sep_dma_map *map_array;
+
+ dev_dbg(&sep->pdev->dev, "sep_lock_kernel_pages start\n");
+ dev_dbg(&sep->pdev->dev, "kernel_virt_addr is %08lx\n",
+ (unsigned long)kernel_virt_addr);
+ dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size);
+
+ lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC);
+ if (!lli_array) {
+ error = -ENOMEM;
+ goto end_function;
+ }
+ map_array = kmalloc(sizeof(struct sep_dma_map), GFP_ATOMIC);
+ if (!map_array) {
+ error = -ENOMEM;
+ goto end_function_with_error;
+ }
+
+ map_array[0].dma_addr =
+ dma_map_single(&sep->pdev->dev, (void *)kernel_virt_addr,
+ data_size, DMA_BIDIRECTIONAL);
+ map_array[0].size = data_size;
+
+
+ /*
+ * Set the start address of the first page - app data may start not at
+ * the beginning of the page
+ */
+ lli_array[0].bus_address = (u32)map_array[0].dma_addr;
+ lli_array[0].block_size = map_array[0].size;
+
+ dev_dbg(&sep->pdev->dev,
+ "lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n",
+ (unsigned long)lli_array[0].bus_address,
+ lli_array[0].block_size);
+
+ /* Set the output parameters */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = 1;
+ } else {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = 1;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1;
+ }
+ goto end_function;
+
+end_function_with_error:
+ kfree(lli_array);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_lock_kernel_pages end\n");
+ return error;
+}
+
+/**
+ * sep_lock_user_pages - lock and map user pages for DMA
+ * @sep: pointer to struct sep_device
+ * @app_virt_addr: user memory data buffer
+ * @data_size: size of data buffer
+ * @lli_array_ptr: lli array
+ * @in_out_flag: input or output to device
+ *
+ * This function locks all the physical pages of the application
+ * virtual buffer and construct a basic lli array, where each entry
+ * holds the physical page address and the size that application
+ * data holds in this physical pages
+ */
+static int sep_lock_user_pages(struct sep_device *sep,
+ u32 app_virt_addr,
+ u32 data_size,
+ struct sep_lli_entry **lli_array_ptr,
+ int in_out_flag)
+
+{
+ int error = 0;
+ u32 count;
+ int result;
+ /* The the page of the end address of the user space buffer */
+ u32 end_page;
+ /* The page of the start address of the user space buffer */
+ u32 start_page;
+ /* The range in pages */
+ u32 num_pages;
+ /* Array of pointers to page */
+ struct page **page_array;
+ /* Array of lli */
+ struct sep_lli_entry *lli_array;
+ /* Map array */
+ struct sep_dma_map *map_array;
+ /* Direction of the DMA mapping for locked pages */
+ enum dma_data_direction dir;
+
+ dev_dbg(&sep->pdev->dev, "sep_lock_user_pages start\n");
+
+ /* Set start and end pages and num pages */
+ end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT;
+ start_page = app_virt_addr >> PAGE_SHIFT;
+ num_pages = end_page - start_page + 1;
+
+ dev_dbg(&sep->pdev->dev, "app_virt_addr is %x\n", app_virt_addr);
+ dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size);
+ dev_dbg(&sep->pdev->dev, "start_page is %x\n", start_page);
+ dev_dbg(&sep->pdev->dev, "end_page is %x\n", end_page);
+ dev_dbg(&sep->pdev->dev, "num_pages is %x\n", num_pages);
+
+ dev_dbg(&sep->pdev->dev, "starting page_array malloc\n");
+
+ /* Allocate array of pages structure pointers */
+ page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
+ if (!page_array) {
+ error = -ENOMEM;
+ goto end_function;
+ }
+ map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC);
+ if (!map_array) {
+ dev_warn(&sep->pdev->dev, "kmalloc for map_array failed\n");
+ error = -ENOMEM;
+ goto end_function_with_error1;
+ }
+
+ lli_array = kmalloc(sizeof(struct sep_lli_entry) * num_pages,
+ GFP_ATOMIC);
+
+ if (!lli_array) {
+ dev_warn(&sep->pdev->dev, "kmalloc for lli_array failed\n");
+ error = -ENOMEM;
+ goto end_function_with_error2;
+ }
+
+ dev_dbg(&sep->pdev->dev, "starting get_user_pages\n");
+
+ /* Convert the application virtual address into a set of physical */
+ down_read(&current->mm->mmap_sem);
+ result = get_user_pages(current, current->mm, app_virt_addr,
+ num_pages,
+ ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1),
+ 0, page_array, NULL);
+
+ up_read(&current->mm->mmap_sem);
+
+ /* Check the number of pages locked - if not all then exit with error */
+ if (result != num_pages) {
+ dev_warn(&sep->pdev->dev,
+ "not all pages locked by get_user_pages\n");
+ error = -ENOMEM;
+ goto end_function_with_error3;
+ }
+
+ dev_dbg(&sep->pdev->dev, "get_user_pages succeeded\n");
+
+ /* Set direction */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG)
+ dir = DMA_TO_DEVICE;
+ else
+ dir = DMA_FROM_DEVICE;
+
+ /*
+ * Fill the array using page array data and
+ * map the pages - this action will also flush the cache as needed
+ */
+ for (count = 0; count < num_pages; count++) {
+ /* Fill the map array */
+ map_array[count].dma_addr =
+ dma_map_page(&sep->pdev->dev, page_array[count],
+ 0, PAGE_SIZE, /*dir*/DMA_BIDIRECTIONAL);
+
+ map_array[count].size = PAGE_SIZE;
+
+ /* Fill the lli array entry */
+ lli_array[count].bus_address = (u32)map_array[count].dma_addr;
+ lli_array[count].block_size = PAGE_SIZE;
+
+ dev_warn(&sep->pdev->dev, "lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is %x\n",
+ count, (unsigned long)lli_array[count].bus_address,
+ count, lli_array[count].block_size);
+ }
+
+ /* Check the offset for the first page */
+ lli_array[0].bus_address =
+ lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK));
+
+ /* Check that not all the data is in the first page only */
+ if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size)
+ lli_array[0].block_size = data_size;
+ else
+ lli_array[0].block_size =
+ PAGE_SIZE - (app_virt_addr & (~PAGE_MASK));
+
+ dev_dbg(&sep->pdev->dev,
+ "lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n",
+ (unsigned long)lli_array[count].bus_address,
+ lli_array[count].block_size);
+
+ /* Check the size of the last page */
+ if (num_pages > 1) {
+ lli_array[num_pages - 1].block_size =
+ (app_virt_addr + data_size) & (~PAGE_MASK);
+
+ dev_warn(&sep->pdev->dev,
+ "lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is %x\n",
+ num_pages - 1,
+ (unsigned long)lli_array[count].bus_address,
+ num_pages - 1,
+ lli_array[count].block_size);
+ }
+
+ /* Set output params acording to the in_out flag */
+ if (in_out_flag == SEP_DRIVER_IN_FLAG) {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = num_pages;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = page_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries =
+ num_pages;
+ } else {
+ *lli_array_ptr = lli_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = num_pages;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_page_array =
+ page_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries =
+ num_pages;
+ }
+ goto end_function;
+
+end_function_with_error3:
+ /* Free lli array */
+ kfree(lli_array);
+
+end_function_with_error2:
+ kfree(map_array);
+
+end_function_with_error1:
+ /* Free page array */
+ kfree(page_array);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_lock_user_pages end\n");
+ return error;
+}
+
+/**
+ * u32 sep_calculate_lli_table_max_size - size the LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_in_array_ptr
+ * @num_array_entries
+ * @last_table_flag
+ *
+ * This function calculates the size of data that can be inserted into
+ * the lli table from this array, such that either the table is full
+ * (all entries are entered), or there are no more entries in the
+ * lli array
+ */
+static u32 sep_calculate_lli_table_max_size(struct sep_device *sep,
+ struct sep_lli_entry *lli_in_array_ptr,
+ u32 num_array_entries,
+ u32 *last_table_flag)
+{
+ u32 counter;
+ /* Table data size */
+ u32 table_data_size = 0;
+ /* Data size for the next table */
+ u32 next_table_data_size;
+
+ *last_table_flag = 0;
+
+ /*
+ * Calculate the data in the out lli table till we fill the whole
+ * table or till the data has ended
+ */
+ for (counter = 0;
+ (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) &&
+ (counter < num_array_entries); counter++)
+ table_data_size += lli_in_array_ptr[counter].block_size;
+
+ /*
+ * Check if we reached the last entry,
+ * meaning this ia the last table to build,
+ * and no need to check the block alignment
+ */
+ if (counter == num_array_entries) {
+ /* Set the last table flag */
+ *last_table_flag = 1;
+ goto end_function;
+ }
+
+ /*
+ * Calculate the data size of the next table.
+ * Stop if no entries left or if data size is more the DMA restriction
+ */
+ next_table_data_size = 0;
+ for (; counter < num_array_entries; counter++) {
+ next_table_data_size += lli_in_array_ptr[counter].block_size;
+ if (next_table_data_size >= SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
+ break;
+ }
+
+ /*
+ * Check if the next table data size is less then DMA rstriction.
+ * if it is - recalculate the current table size, so that the next
+ * table data size will be adaquete for DMA
+ */
+ if (next_table_data_size &&
+ next_table_data_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE)
+
+ table_data_size -= (SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE -
+ next_table_data_size);
+
+ dev_dbg(&sep->pdev->dev, "table data size is %x\n",
+ table_data_size);
+end_function:
+ return table_data_size;
+}
+
+/**
+ * sep_build_lli_table - build an lli array for the given table
+ * @sep: pointer to struct sep_device
+ * @lli_array_ptr: pointer to lli array
+ * @lli_table_ptr: pointer to lli table
+ * @num_processed_entries_ptr: pointer to number of entries
+ * @num_table_entries_ptr: pointer to number of tables
+ * @table_data_size: total data size
+ *
+ * Builds ant lli table from the lli_array according to
+ * the given size of data
+ */
+static void sep_build_lli_table(struct sep_device *sep,
+ struct sep_lli_entry *lli_array_ptr,
+ struct sep_lli_entry *lli_table_ptr,
+ u32 *num_processed_entries_ptr,
+ u32 *num_table_entries_ptr,
+ u32 table_data_size)
+{
+ /* Current table data size */
+ u32 curr_table_data_size;
+ /* Counter of lli array entry */
+ u32 array_counter;
+
+ dev_dbg(&sep->pdev->dev, "sep_build_lli_table start\n");
+
+ /* Init currrent table data size and lli array entry counter */
+ curr_table_data_size = 0;
+ array_counter = 0;
+ *num_table_entries_ptr = 1;
+
+ dev_dbg(&sep->pdev->dev, "table_data_size is %x\n", table_data_size);
+
+ /* Fill the table till table size reaches the needed amount */
+ while (curr_table_data_size < table_data_size) {
+ /* Update the number of entries in table */
+ (*num_table_entries_ptr)++;
+
+ lli_table_ptr->bus_address =
+ cpu_to_le32(lli_array_ptr[array_counter].bus_address);
+
+ lli_table_ptr->block_size =
+ cpu_to_le32(lli_array_ptr[array_counter].block_size);
+
+ curr_table_data_size += lli_array_ptr[array_counter].block_size;
+
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr is %p\n",
+ lli_table_ptr);
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n",
+ (unsigned long)lli_table_ptr->bus_address);
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n",
+ lli_table_ptr->block_size);
+
+ /* Check for overflow of the table data */
+ if (curr_table_data_size > table_data_size) {
+ dev_dbg(&sep->pdev->dev,
+ "curr_table_data_size too large\n");
+
+ /* Update the size of block in the table */
+ lli_table_ptr->block_size -=
+ cpu_to_le32((curr_table_data_size - table_data_size));
+
+ /* Update the physical address in the lli array */
+ lli_array_ptr[array_counter].bus_address +=
+ cpu_to_le32(lli_table_ptr->block_size);
+
+ /* Update the block size left in the lli array */
+ lli_array_ptr[array_counter].block_size =
+ (curr_table_data_size - table_data_size);
+ } else
+ /* Advance to the next entry in the lli_array */
+ array_counter++;
+
+ dev_dbg(&sep->pdev->dev,
+ "lli_table_ptr->bus_address is %08lx\n",
+ (unsigned long)lli_table_ptr->bus_address);
+ dev_dbg(&sep->pdev->dev,
+ "lli_table_ptr->block_size is %x\n",
+ lli_table_ptr->block_size);
+
+ /* Move to the next entry in table */
+ lli_table_ptr++;
+ }
+
+ /* Set the info entry to default */
+ lli_table_ptr->bus_address = 0xffffffff;
+ lli_table_ptr->block_size = 0;
+
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr is %p\n", lli_table_ptr);
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n",
+ (unsigned long)lli_table_ptr->bus_address);
+ dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n",
+ lli_table_ptr->block_size);
+
+ /* Set the output parameter */
+ *num_processed_entries_ptr += array_counter;
+
+ dev_dbg(&sep->pdev->dev, "num_processed_entries_ptr is %x\n",
+ *num_processed_entries_ptr);
+
+ dev_dbg(&sep->pdev->dev, "sep_build_lli_table end\n");
+}
+
+/**
+ * sep_shared_area_virt_to_bus - map shared area to bus address
+ * @sep: pointer to struct sep_device
+ * @virt_address: virtual address to convert
+ *
+ * This functions returns the physical address inside shared area according
+ * to the virtual address. It can be either on the externa RAM device
+ * (ioremapped), or on the system RAM
+ * This implementation is for the external RAM
+ */
+static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep,
+ void *virt_address)
+{
+ dev_dbg(&sep->pdev->dev, "sh virt to phys v %p\n", virt_address);
+ dev_dbg(&sep->pdev->dev, "sh virt to phys p %08lx\n",
+ (unsigned long)
+ sep->shared_bus + (virt_address - sep->shared_addr));
+
+ return sep->shared_bus + (size_t)(virt_address - sep->shared_addr);
+}
+
+/**
+ * sep_shared_area_bus_to_virt - map shared area bus address to kernel
+ * @sep: pointer to struct sep_device
+ * @bus_address: bus address to convert
+ *
+ * This functions returns the virtual address inside shared area
+ * according to the physical address. It can be either on the
+ * externa RAM device (ioremapped), or on the system RAM
+ * This implementation is for the external RAM
+ */
+static void *sep_shared_area_bus_to_virt(struct sep_device *sep,
+ dma_addr_t bus_address)
+{
+ dev_dbg(&sep->pdev->dev, "shared bus to virt b=%lx v=%lx\n",
+ (unsigned long)bus_address, (unsigned long)(sep->shared_addr +
+ (size_t)(bus_address - sep->shared_bus)));
+
+ return sep->shared_addr + (size_t)(bus_address - sep->shared_bus);
+}
+
+/**
+ * sep_debug_print_lli_tables - dump LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_table_ptr: pointer to sep_lli_entry
+ * @num_table_entries: number of entries
+ * @table_data_size: total data size
+ *
+ * Walk the the list of the print created tables and print all the data
+ */
+static void sep_debug_print_lli_tables(struct sep_device *sep,
+ struct sep_lli_entry *lli_table_ptr,
+ unsigned long num_table_entries,
+ unsigned long table_data_size)
+{
+ unsigned long table_count = 1;
+ unsigned long entries_count = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables start\n");
+
+ while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) {
+ dev_dbg(&sep->pdev->dev,
+ "lli table %08lx, table_data_size is %lu\n",
+ table_count, table_data_size);
+ dev_dbg(&sep->pdev->dev, "num_table_entries is %lu\n",
+ num_table_entries);
+
+ /* Print entries of the table (without info entry) */
+ for (entries_count = 0; entries_count < num_table_entries;
+ entries_count++, lli_table_ptr++) {
+
+ dev_dbg(&sep->pdev->dev,
+ "lli_table_ptr address is %08lx\n",
+ (unsigned long) lli_table_ptr);
+
+ dev_dbg(&sep->pdev->dev,
+ "phys address is %08lx block size is %x\n",
+ (unsigned long)lli_table_ptr->bus_address,
+ lli_table_ptr->block_size);
+ }
+ /* Point to the info entry */
+ lli_table_ptr--;
+
+ dev_dbg(&sep->pdev->dev,
+ "phys lli_table_ptr->block_size is %x\n",
+ lli_table_ptr->block_size);
+
+ dev_dbg(&sep->pdev->dev,
+ "phys lli_table_ptr->physical_address is %08lu\n",
+ (unsigned long)lli_table_ptr->bus_address);
+
+
+ table_data_size = lli_table_ptr->block_size & 0xffffff;
+ num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
+
+ dev_dbg(&sep->pdev->dev,
+ "phys table_data_size is %lu num_table_entries is"
+ " %lu bus_address is%lu\n", table_data_size,
+ num_table_entries, (unsigned long)lli_table_ptr->bus_address);
+
+ if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff)
+ lli_table_ptr = (struct sep_lli_entry *)
+ sep_shared_bus_to_virt(sep,
+ (unsigned long)lli_table_ptr->bus_address);
+
+ table_count++;
+ }
+ dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables end\n");
+}
+
+
+/**
+ * sep_prepare_empty_lli_table - create a blank LLI table
+ * @sep: pointer to struct sep_device
+ * @lli_table_addr_ptr: pointer to lli table
+ * @num_entries_ptr: pointer to number of entries
+ * @table_data_size_ptr: point to table data size
+ *
+ * This function creates empty lli tables when there is no data
+ */
+static void sep_prepare_empty_lli_table(struct sep_device *sep,
+ dma_addr_t *lli_table_addr_ptr,
+ u32 *num_entries_ptr,
+ u32 *table_data_size_ptr)
+{
+ struct sep_lli_entry *lli_table_ptr;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n");
+
+ /* Find the area for new table */
+ lli_table_ptr =
+ (struct sep_lli_entry *)(sep->shared_addr +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ sep->num_lli_tables_created * sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+ lli_table_ptr->bus_address = 0;
+ lli_table_ptr->block_size = 0;
+
+ lli_table_ptr++;
+ lli_table_ptr->bus_address = 0xFFFFFFFF;
+ lli_table_ptr->block_size = 0;
+
+ /* Set the output parameter value */
+ *lli_table_addr_ptr = sep->shared_bus +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ sep->num_lli_tables_created *
+ sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+ /* Set the num of entries and table data size for empty table */
+ *num_entries_ptr = 2;
+ *table_data_size_ptr = 0;
+
+ /* Update the number of created tables */
+ sep->num_lli_tables_created++;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n");
+
+}
+
+/**
+ * sep_prepare_input_dma_table - prepare input DMA mappings
+ * @sep: pointer to struct sep_device
+ * @data_size:
+ * @block_size:
+ * @lli_table_ptr:
+ * @num_entries_ptr:
+ * @table_data_size_ptr:
+ * @is_kva: set for kernel data (kernel cryptio call)
+ *
+ * This function prepares only input DMA table for synhronic symmetric
+ * operations (HASH)
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_prepare_input_dma_table(struct sep_device *sep,
+ unsigned long app_virt_addr,
+ u32 data_size,
+ u32 block_size,
+ dma_addr_t *lli_table_ptr,
+ u32 *num_entries_ptr,
+ u32 *table_data_size_ptr,
+ bool is_kva)
+{
+ int error = 0;
+ /* Pointer to the info entry of the table - the last entry */
+ struct sep_lli_entry *info_entry_ptr;
+ /* Array of pointers to page */
+ struct sep_lli_entry *lli_array_ptr;
+ /* Points to the first entry to be processed in the lli_in_array */
+ u32 current_entry = 0;
+ /* Num entries in the virtual buffer */
+ u32 sep_lli_entries = 0;
+ /* Lli table pointer */
+ struct sep_lli_entry *in_lli_table_ptr;
+ /* The total data in one table */
+ u32 table_data_size = 0;
+ /* Flag for last table */
+ u32 last_table_flag = 0;
+ /* Number of entries in lli table */
+ u32 num_entries_in_table = 0;
+ /* Next table address */
+ void *lli_table_alloc_addr = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table start\n");
+ dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size);
+ dev_dbg(&sep->pdev->dev, "block_size is %x\n", block_size);
+
+ /* Initialize the pages pointers */
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0;
+
+ /* Set the kernel address for first table to be allocated */
+ lli_table_alloc_addr = (void *)(sep->shared_addr +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ sep->num_lli_tables_created * sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+ if (data_size == 0) {
+ /* Special case - create meptu table - 2 entries, zero data */
+ sep_prepare_empty_lli_table(sep, lli_table_ptr,
+ num_entries_ptr, table_data_size_ptr);
+ goto update_dcb_counter;
+ }
+
+ /* Check if the pages are in Kernel Virtual Address layout */
+ if (is_kva == true)
+ /* Lock the pages in the kernel */
+ error = sep_lock_kernel_pages(sep, app_virt_addr,
+ data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG);
+ else
+ /*
+ * Lock the pages of the user buffer
+ * and translate them to pages
+ */
+ error = sep_lock_user_pages(sep, app_virt_addr,
+ data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG);
+
+ if (error)
+ goto end_function;
+
+ dev_dbg(&sep->pdev->dev, "output sep_in_num_pages is %x\n",
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages);
+
+ current_entry = 0;
+ info_entry_ptr = NULL;
+
+ sep_lli_entries = sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages;
+
+ /* Loop till all the entries in in array are not processed */
+ while (current_entry < sep_lli_entries) {
+
+ /* Set the new input and output tables */
+ in_lli_table_ptr =
+ (struct sep_lli_entry *)lli_table_alloc_addr;
+
+ lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+ if (lli_table_alloc_addr >
+ ((void *)sep->shared_addr +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
+
+ error = -ENOMEM;
+ goto end_function_error;
+
+ }
+
+ /* Update the number of created tables */
+ sep->num_lli_tables_created++;
+
+ /* Calculate the maximum size of data for input table */
+ table_data_size = sep_calculate_lli_table_max_size(sep,
+ &lli_array_ptr[current_entry],
+ (sep_lli_entries - current_entry),
+ &last_table_flag);
+
+ /*
+ * If this is not the last table -
+ * then allign it to the block size
+ */
+ if (!last_table_flag)
+ table_data_size =
+ (table_data_size / block_size) * block_size;
+
+ dev_dbg(&sep->pdev->dev, "output table_data_size is %x\n",
+ table_data_size);
+
+ /* Construct input lli table */
+ sep_build_lli_table(sep, &lli_array_ptr[current_entry],
+ in_lli_table_ptr,
+ &current_entry, &num_entries_in_table, table_data_size);
+
+ if (info_entry_ptr == NULL) {
+
+ /* Set the output parameters to physical addresses */
+ *lli_table_ptr = sep_shared_area_virt_to_bus(sep,
+ in_lli_table_ptr);
+ *num_entries_ptr = num_entries_in_table;
+ *table_data_size_ptr = table_data_size;
+
+ dev_dbg(&sep->pdev->dev,
+ "output lli_table_in_ptr is %08lx\n",
+ (unsigned long)*lli_table_ptr);
+
+ } else {
+ /* Update the info entry of the previous in table */
+ info_entry_ptr->bus_address =
+ sep_shared_area_virt_to_bus(sep,
+ in_lli_table_ptr);
+ info_entry_ptr->block_size =
+ ((num_entries_in_table) << 24) |
+ (table_data_size);
+ }
+ /* Save the pointer to the info entry of the current tables */
+ info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1;
+ }
+ /* Print input tables */
+ sep_debug_print_lli_tables(sep, (struct sep_lli_entry *)
+ sep_shared_area_bus_to_virt(sep, *lli_table_ptr),
+ *num_entries_ptr, *table_data_size_ptr);
+ /* The array of the pages */
+ kfree(lli_array_ptr);
+
+update_dcb_counter:
+ /* Update DCB counter */
+ sep->nr_dcb_creat++;
+ goto end_function;
+
+end_function_error:
+ /* Free all the allocated resources */
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array);
+ kfree(lli_array_ptr);
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table end\n");
+ return error;
+
+}
+/**
+ * sep_construct_dma_tables_from_lli - prepare AES/DES mappings
+ * @sep: pointer to struct sep_device
+ * @lli_in_array:
+ * @sep_in_lli_entries:
+ * @lli_out_array:
+ * @sep_out_lli_entries
+ * @block_size
+ * @lli_table_in_ptr
+ * @lli_table_out_ptr
+ * @in_num_entries_ptr
+ * @out_num_entries_ptr
+ * @table_data_size_ptr
+ *
+ * This function creates the input and output DMA tables for
+ * symmetric operations (AES/DES) according to the block
+ * size from LLI arays
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_construct_dma_tables_from_lli(
+ struct sep_device *sep,
+ struct sep_lli_entry *lli_in_array,
+ u32 sep_in_lli_entries,
+ struct sep_lli_entry *lli_out_array,
+ u32 sep_out_lli_entries,
+ u32 block_size,
+ dma_addr_t *lli_table_in_ptr,
+ dma_addr_t *lli_table_out_ptr,
+ u32 *in_num_entries_ptr,
+ u32 *out_num_entries_ptr,
+ u32 *table_data_size_ptr)
+{
+ /* Points to the area where next lli table can be allocated */
+ void *lli_table_alloc_addr = 0;
+ /* Input lli table */
+ struct sep_lli_entry *in_lli_table_ptr = NULL;
+ /* Output lli table */
+ struct sep_lli_entry *out_lli_table_ptr = NULL;
+ /* Pointer to the info entry of the table - the last entry */
+ struct sep_lli_entry *info_in_entry_ptr = NULL;
+ /* Pointer to the info entry of the table - the last entry */
+ struct sep_lli_entry *info_out_entry_ptr = NULL;
+ /* Points to the first entry to be processed in the lli_in_array */
+ u32 current_in_entry = 0;
+ /* Points to the first entry to be processed in the lli_out_array */
+ u32 current_out_entry = 0;
+ /* Max size of the input table */
+ u32 in_table_data_size = 0;
+ /* Max size of the output table */
+ u32 out_table_data_size = 0;
+ /* Flag te signifies if this is the last tables build */
+ u32 last_table_flag = 0;
+ /* The data size that should be in table */
+ u32 table_data_size = 0;
+ /* Number of etnries in the input table */
+ u32 num_entries_in_table = 0;
+ /* Number of etnries in the output table */
+ u32 num_entries_out_table = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli start\n");
+
+ /* Initiate to point after the message area */
+ lli_table_alloc_addr = (void *)(sep->shared_addr +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ (sep->num_lli_tables_created *
+ (sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP)));
+
+ /* Loop till all the entries in in array are not processed */
+ while (current_in_entry < sep_in_lli_entries) {
+ /* Set the new input and output tables */
+ in_lli_table_ptr =
+ (struct sep_lli_entry *)lli_table_alloc_addr;
+
+ lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+ /* Set the first output tables */
+ out_lli_table_ptr =
+ (struct sep_lli_entry *)lli_table_alloc_addr;
+
+ /* Check if the DMA table area limit was overrun */
+ if ((lli_table_alloc_addr + sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) >
+ ((void *)sep->shared_addr +
+ SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES +
+ SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) {
+
+ dev_warn(&sep->pdev->dev, "dma table limit overrun\n");
+ return -ENOMEM;
+ }
+
+ /* Update the number of the lli tables created */
+ sep->num_lli_tables_created += 2;
+
+ lli_table_alloc_addr += sizeof(struct sep_lli_entry) *
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP;
+
+ /* Calculate the maximum size of data for input table */
+ in_table_data_size =
+ sep_calculate_lli_table_max_size(sep,
+ &lli_in_array[current_in_entry],
+ (sep_in_lli_entries - current_in_entry),
+ &last_table_flag);
+
+ /* Calculate the maximum size of data for output table */
+ out_table_data_size =
+ sep_calculate_lli_table_max_size(sep,
+ &lli_out_array[current_out_entry],
+ (sep_out_lli_entries - current_out_entry),
+ &last_table_flag);
+
+ dev_dbg(&sep->pdev->dev,
+ "in_table_data_size is %x\n",
+ in_table_data_size);
+
+ dev_dbg(&sep->pdev->dev,
+ "out_table_data_size is %x\n",
+ out_table_data_size);
+
+ table_data_size = in_table_data_size;
+
+ if (!last_table_flag) {
+ /*
+ * If this is not the last table,
+ * then must check where the data is smallest
+ * and then align it to the block size
+ */
+ if (table_data_size > out_table_data_size)
+ table_data_size = out_table_data_size;
+
+ /*
+ * Now calculate the table size so that
+ * it will be module block size
+ */
+ table_data_size = (table_data_size / block_size) *
+ block_size;
+ }
+
+ dev_dbg(&sep->pdev->dev, "table_data_size is %x\n",
+ table_data_size);
+
+ /* Construct input lli table */
+ sep_build_lli_table(sep, &lli_in_array[current_in_entry],
+ in_lli_table_ptr,
+ &current_in_entry,
+ &num_entries_in_table,
+ table_data_size);
+
+ /* Construct output lli table */
+ sep_build_lli_table(sep, &lli_out_array[current_out_entry],
+ out_lli_table_ptr,
+ &current_out_entry,
+ &num_entries_out_table,
+ table_data_size);
+
+ /* If info entry is null - this is the first table built */
+ if (info_in_entry_ptr == NULL) {
+ /* Set the output parameters to physical addresses */
+ *lli_table_in_ptr =
+ sep_shared_area_virt_to_bus(sep, in_lli_table_ptr);
+
+ *in_num_entries_ptr = num_entries_in_table;
+
+ *lli_table_out_ptr =
+ sep_shared_area_virt_to_bus(sep,
+ out_lli_table_ptr);
+
+ *out_num_entries_ptr = num_entries_out_table;
+ *table_data_size_ptr = table_data_size;
+
+ dev_dbg(&sep->pdev->dev,
+ "output lli_table_in_ptr is %08lx\n",
+ (unsigned long)*lli_table_in_ptr);
+ dev_dbg(&sep->pdev->dev,
+ "output lli_table_out_ptr is %08lx\n",
+ (unsigned long)*lli_table_out_ptr);
+ } else {
+ /* Update the info entry of the previous in table */
+ info_in_entry_ptr->bus_address =
+ sep_shared_area_virt_to_bus(sep,
+ in_lli_table_ptr);
+
+ info_in_entry_ptr->block_size =
+ ((num_entries_in_table) << 24) |
+ (table_data_size);
+
+ /* Update the info entry of the previous in table */
+ info_out_entry_ptr->bus_address =
+ sep_shared_area_virt_to_bus(sep,
+ out_lli_table_ptr);
+
+ info_out_entry_ptr->block_size =
+ ((num_entries_out_table) << 24) |
+ (table_data_size);
+
+ dev_dbg(&sep->pdev->dev,
+ "output lli_table_in_ptr:%08lx %08x\n",
+ (unsigned long)info_in_entry_ptr->bus_address,
+ info_in_entry_ptr->block_size);
+
+ dev_dbg(&sep->pdev->dev,
+ "output lli_table_out_ptr:%08lx %08x\n",
+ (unsigned long)info_out_entry_ptr->bus_address,
+ info_out_entry_ptr->block_size);
+ }
+
+ /* Save the pointer to the info entry of the current tables */
+ info_in_entry_ptr = in_lli_table_ptr +
+ num_entries_in_table - 1;
+ info_out_entry_ptr = out_lli_table_ptr +
+ num_entries_out_table - 1;
+
+ dev_dbg(&sep->pdev->dev,
+ "output num_entries_out_table is %x\n",
+ (u32)num_entries_out_table);
+ dev_dbg(&sep->pdev->dev,
+ "output info_in_entry_ptr is %lx\n",
+ (unsigned long)info_in_entry_ptr);
+ dev_dbg(&sep->pdev->dev,
+ "output info_out_entry_ptr is %lx\n",
+ (unsigned long)info_out_entry_ptr);
+ }
+
+ /* Print input tables */
+ sep_debug_print_lli_tables(sep,
+ (struct sep_lli_entry *)
+ sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr),
+ *in_num_entries_ptr,
+ *table_data_size_ptr);
+
+ /* Print output tables */
+ sep_debug_print_lli_tables(sep,
+ (struct sep_lli_entry *)
+ sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr),
+ *out_num_entries_ptr,
+ *table_data_size_ptr);
+
+ dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli end\n");
+ return 0;
+}
+
+/**
+ * sep_prepare_input_output_dma_table - prepare DMA I/O table
+ * @app_virt_in_addr:
+ * @app_virt_out_addr:
+ * @data_size:
+ * @block_size:
+ * @lli_table_in_ptr:
+ * @lli_table_out_ptr:
+ * @in_num_entries_ptr:
+ * @out_num_entries_ptr:
+ * @table_data_size_ptr:
+ * @is_kva: set for kernel data; used only for kernel crypto module
+ *
+ * This function builds input and output DMA tables for synhronic
+ * symmetric operations (AES, DES, HASH). It also checks that each table
+ * is of the modular block size
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_prepare_input_output_dma_table(struct sep_device *sep,
+ unsigned long app_virt_in_addr,
+ unsigned long app_virt_out_addr,
+ u32 data_size,
+ u32 block_size,
+ dma_addr_t *lli_table_in_ptr,
+ dma_addr_t *lli_table_out_ptr,
+ u32 *in_num_entries_ptr,
+ u32 *out_num_entries_ptr,
+ u32 *table_data_size_ptr,
+ bool is_kva)
+
+{
+ int error = 0;
+ /* Array of pointers of page */
+ struct sep_lli_entry *lli_in_array;
+ /* Array of pointers of page */
+ struct sep_lli_entry *lli_out_array;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_input_output_dma_table start\n");
+
+ if (data_size == 0) {
+ /* Prepare empty table for input and output */
+ sep_prepare_empty_lli_table(sep, lli_table_in_ptr,
+ in_num_entries_ptr, table_data_size_ptr);
+
+ sep_prepare_empty_lli_table(sep, lli_table_out_ptr,
+ out_num_entries_ptr, table_data_size_ptr);
+
+ goto update_dcb_counter;
+ }
+
+ /* Initialize the pages pointers */
+ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL;
+ sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL;
+
+ /* Lock the pages of the buffer and translate them to pages */
+ if (is_kva == true) {
+ error = sep_lock_kernel_pages(sep, app_virt_in_addr,
+ data_size, &lli_in_array, SEP_DRIVER_IN_FLAG);
+
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "lock kernel for in failed\n");
+ goto end_function;
+ }
+
+ error = sep_lock_kernel_pages(sep, app_virt_out_addr,
+ data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG);
+
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "lock kernel for out failed\n");
+ goto end_function;
+ }
+ }
+
+ else {
+ error = sep_lock_user_pages(sep, app_virt_in_addr,
+ data_size, &lli_in_array, SEP_DRIVER_IN_FLAG);
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "sep_lock_user_pages for input virtual buffer failed\n");
+ goto end_function;
+ }
+
+ error = sep_lock_user_pages(sep, app_virt_out_addr,
+ data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG);
+
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "sep_lock_user_pages for output virtual buffer failed\n");
+ goto end_function_free_lli_in;
+ }
+ }
+
+ dev_dbg(&sep->pdev->dev, "sep_in_num_pages is %x\n",
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages);
+ dev_dbg(&sep->pdev->dev, "sep_out_num_pages is %x\n",
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages);
+ dev_dbg(&sep->pdev->dev, "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n",
+ SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP);
+
+ /* Call the fucntion that creates table from the lli arrays */
+ error = sep_construct_dma_tables_from_lli(sep, lli_in_array,
+ sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages,
+ lli_out_array,
+ sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages,
+ block_size, lli_table_in_ptr, lli_table_out_ptr,
+ in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr);
+
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "sep_construct_dma_tables_from_lli failed\n");
+ goto end_function_with_error;
+ }
+
+ kfree(lli_out_array);
+ kfree(lli_in_array);
+
+update_dcb_counter:
+ /* Update DCB counter */
+ sep->nr_dcb_creat++;
+ /* Fall through - free the lli entry arrays */
+ dev_dbg(&sep->pdev->dev, "in_num_entries_ptr is %08x\n",
+ *in_num_entries_ptr);
+ dev_dbg(&sep->pdev->dev, "out_num_entries_ptr is %08x\n",
+ *out_num_entries_ptr);
+ dev_dbg(&sep->pdev->dev, "table_data_size_ptr is %08x\n",
+ *table_data_size_ptr);
+
+ goto end_function;
+
+end_function_with_error:
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_map_array);
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_page_array);
+ kfree(lli_out_array);
+
+
+end_function_free_lli_in:
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array);
+ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array);
+ kfree(lli_in_array);
+
+end_function:
+ dev_dbg(&sep->pdev->dev,
+ "sep_prepare_input_output_dma_table end result = %d\n", error);
+
+ return error;
+
+}
+
+/**
+ * sep_prepare_input_output_dma_table_in_dcb - prepare control blocks
+ * @app_in_address: unsigned long; for data buffer in (user space)
+ * @app_out_address: unsigned long; for data buffer out (user space)
+ * @data_in_size: u32; for size of data
+ * @block_size: u32; for block size
+ * @tail_block_size: u32; for size of tail block
+ * @isapplet: bool; to indicate external app
+ * @is_kva: bool; kernel buffer; only used for kernel crypto module
+ *
+ * This function prepares the linked DMA tables and puts the
+ * address for the linked list of tables inta a DCB (data control
+ * block) the address of which is known by the SEP hardware
+ * Note that all bus addresses that are passed to the SEP
+ * are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
+ unsigned long app_in_address,
+ unsigned long app_out_address,
+ u32 data_in_size,
+ u32 block_size,
+ u32 tail_block_size,
+ bool isapplet,
+ bool is_kva)
+{
+ int error = 0;
+ /* Size of tail */
+ u32 tail_size = 0;
+ /* Address of the created DCB table */
+ struct sep_dcblock *dcb_table_ptr = NULL;
+ /* The physical address of the first input DMA table */
+ dma_addr_t in_first_mlli_address = 0;
+ /* Number of entries in the first input DMA table */
+ u32 in_first_num_entries = 0;
+ /* The physical address of the first output DMA table */
+ dma_addr_t out_first_mlli_address = 0;
+ /* Number of entries in the first output DMA table */
+ u32 out_first_num_entries = 0;
+ /* Data in the first input/output table */
+ u32 first_data_size = 0;
+
+ dev_dbg(&sep->pdev->dev, "prepare_input_output_dma_table_in_dcb start\n");
+
+ if (sep->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) {
+ /* No more DCBs to allocate */
+ dev_warn(&sep->pdev->dev, "no more DCBs available\n");
+ error = -ENOSPC;
+ goto end_function;
+ }
+
+ /* Allocate new DCB */
+ dcb_table_ptr = (struct sep_dcblock *)(sep->shared_addr +
+ SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES +
+ (sep->nr_dcb_creat * sizeof(struct sep_dcblock)));
+
+ /* Set the default values in the DCB */
+ dcb_table_ptr->input_mlli_address = 0;
+ dcb_table_ptr->input_mlli_num_entries = 0;
+ dcb_table_ptr->input_mlli_data_size = 0;
+ dcb_table_ptr->output_mlli_address = 0;
+ dcb_table_ptr->output_mlli_num_entries = 0;
+ dcb_table_ptr->output_mlli_data_size = 0;
+ dcb_table_ptr->tail_data_size = 0;
+ dcb_table_ptr->out_vr_tail_pt = 0;
+
+ if (isapplet == true) {
+ tail_size = data_in_size % block_size;
+ if (tail_size) {
+ if (data_in_size < tail_block_size) {
+ dev_warn(&sep->pdev->dev, "data in size smaller than tail block size\n");
+ error = -ENOSPC;
+ goto end_function;
+ }
+ if (tail_block_size)
+ /*
+ * Case the tail size should be
+ * bigger than the real block size
+ */
+ tail_size = tail_block_size +
+ ((data_in_size -
+ tail_block_size) % block_size);
+ }
+
+ /* Check if there is enough data for DMA operation */
+ if (data_in_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) {
+ if (is_kva == true) {
+ memcpy(dcb_table_ptr->tail_data,
+ (void *)app_in_address, data_in_size);
+ } else {
+ if (copy_from_user(dcb_table_ptr->tail_data,
+ (void __user *)app_in_address,
+ data_in_size)) {
+ error = -EFAULT;
+ goto end_function;
+ }
+ }
+
+ dcb_table_ptr->tail_data_size = data_in_size;
+
+ /* Set the output user-space address for mem2mem op */
+ if (app_out_address)
+ dcb_table_ptr->out_vr_tail_pt =
+ (u32)app_out_address;
+
+ /*
+ * Update both data length parameters in order to avoid
+ * second data copy and allow building of empty mlli
+ * tables
+ */
+ tail_size = 0x0;
+ data_in_size = 0x0;
+ }
+ if (tail_size) {
+ if (is_kva == true) {
+ memcpy(dcb_table_ptr->tail_data,
+ (void *)(app_in_address + data_in_size -
+ tail_size), tail_size);
+ } else {
+ /* We have tail data - copy it to DCB */
+ if (copy_from_user(dcb_table_ptr->tail_data,
+ (void *)(app_in_address +
+ data_in_size - tail_size), tail_size)) {
+ error = -EFAULT;
+ goto end_function;
+ }
+ }
+ if (app_out_address)
+ /*
+ * Calculate the output address
+ * according to tail data size
+ */
+ dcb_table_ptr->out_vr_tail_pt =
+ (u32)app_out_address + data_in_size
+ - tail_size;
+
+ /* Save the real tail data size */
+ dcb_table_ptr->tail_data_size = tail_size;
+ /*
+ * Update the data size without the tail
+ * data size AKA data for the dma
+ */
+ data_in_size = (data_in_size - tail_size);
+ }
+ }
+ /* Check if we need to build only input table or input/output */
+ if (app_out_address) {
+ /* Prepare input/output tables */
+ error = sep_prepare_input_output_dma_table(sep,
+ app_in_address,
+ app_out_address,
+ data_in_size,
+ block_size,
+ &in_first_mlli_address,
+ &out_first_mlli_address,
+ &in_first_num_entries,
+ &out_first_num_entries,
+ &first_data_size,
+ is_kva);
+ } else {
+ /* Prepare input tables */
+ error = sep_prepare_input_dma_table(sep,
+ app_in_address,
+ data_in_size,
+ block_size,
+ &in_first_mlli_address,
+ &in_first_num_entries,
+ &first_data_size,
+ is_kva);
+ }
+
+ if (error) {
+ dev_warn(&sep->pdev->dev, "prepare DMA table call failed from prepare DCB call\n");
+ goto end_function;
+ }
+
+ /* Set the DCB values */
+ dcb_table_ptr->input_mlli_address = in_first_mlli_address;
+ dcb_table_ptr->input_mlli_num_entries = in_first_num_entries;
+ dcb_table_ptr->input_mlli_data_size = first_data_size;
+ dcb_table_ptr->output_mlli_address = out_first_mlli_address;
+ dcb_table_ptr->output_mlli_num_entries = out_first_num_entries;
+ dcb_table_ptr->output_mlli_data_size = first_data_size;
+
+end_function:
+ dev_dbg(&sep->pdev->dev,
+ "sep_prepare_input_output_dma_table_in_dcb end\n");
+ return error;
+
+}
+
+
+/**
+ * sep_create_sync_dma_tables_handler - create sync DMA tables
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to struct bld_syn_tab_struct
+ *
+ * Handle the request for creation of the DMA tables for the synchronic
+ * symmetric operations (AES,DES). Note that all bus addresses that are
+ * passed to the SEP are in 32 bit format; the SEP is a 32 bit device
+ */
+static int sep_create_sync_dma_tables_handler(struct sep_device *sep,
+ unsigned long arg)
+{
+ int error = 0;
+
+ /* Command arguments */
+ struct bld_syn_tab_struct command_args;
+
+ dev_dbg(&sep->pdev->dev,
+ "sep_create_sync_dma_tables_handler start\n");
+
+ if (copy_from_user(&command_args, (void __user *)arg,
+ sizeof(struct bld_syn_tab_struct))) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ dev_dbg(&sep->pdev->dev, "app_in_address is %08llx\n",
+ command_args.app_in_address);
+ dev_dbg(&sep->pdev->dev, "app_out_address is %08llx\n",
+ command_args.app_out_address);
+ dev_dbg(&sep->pdev->dev, "data_size is %u\n",
+ command_args.data_in_size);
+ dev_dbg(&sep->pdev->dev, "block_size is %u\n",
+ command_args.block_size);
+
+ /* Validate user parameters */
+ if (!command_args.app_in_address) {
+ error = -EINVAL;
+ goto end_function;
+ }
+
+ error = sep_prepare_input_output_dma_table_in_dcb(sep,
+ (unsigned long)command_args.app_in_address,
+ (unsigned long)command_args.app_out_address,
+ command_args.data_in_size,
+ command_args.block_size,
+ 0x0,
+ false,
+ false);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_create_sync_dma_tables_handler end\n");
+ return error;
+}
+
+/**
+ * sep_free_dma_tables_and_dcb - free DMA tables and DCBs
+ * @sep: pointer to struct sep_device
+ * @isapplet: indicates external application (used for kernel access)
+ * @is_kva: indicates kernel addresses (only used for kernel crypto)
+ *
+ * This function frees the DMA tables and DCB
+ */
+static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
+ bool is_kva)
+{
+ int i = 0;
+ int error = 0;
+ int error_temp = 0;
+ struct sep_dcblock *dcb_table_ptr;
+ unsigned long pt_hold;
+ void *tail_pt;
+
+ dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb start\n");
+
+ if (isapplet == true) {
+ /* Set pointer to first DCB table */
+ dcb_table_ptr = (struct sep_dcblock *)
+ (sep->shared_addr +
+ SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES);
+
+ /* Go over each DCB and see if tail pointer must be updated */
+ for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) {
+ if (dcb_table_ptr->out_vr_tail_pt) {
+ pt_hold = (unsigned long)dcb_table_ptr->out_vr_tail_pt;
+ tail_pt = (void *)pt_hold;
+ if (is_kva == true) {
+ memcpy(tail_pt,
+ dcb_table_ptr->tail_data,
+ dcb_table_ptr->tail_data_size);
+ } else {
+ error_temp = copy_to_user(
+ tail_pt,
+ dcb_table_ptr->tail_data,
+ dcb_table_ptr->tail_data_size);
+ }
+ if (error_temp) {
+ /* Release the DMA resource */
+ error = -EFAULT;
+ break;
+ }
+ }
+ }
+ }
+ /* Free the output pages, if any */
+ sep_free_dma_table_data_handler(sep);
+
+ dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb end\n");
+ return error;
+}
+
+/**
+ * sep_get_static_pool_addr_handler - get static pool address
+ * @sep: pointer to struct sep_device
+ *
+ * This function sets the bus and virtual addresses of the static pool
+ */
+static int sep_get_static_pool_addr_handler(struct sep_device *sep)
+{
+ u32 *static_pool_addr = NULL;
+
+ dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler start\n");
+
+ static_pool_addr = (u32 *)(sep->shared_addr +
+ SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES);
+
+ static_pool_addr[0] = SEP_STATIC_POOL_VAL_TOKEN;
+ static_pool_addr[1] = (u32)sep->shared_bus +
+ SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES;
+
+ dev_dbg(&sep->pdev->dev, "static pool: physical %x\n",
+ (u32)static_pool_addr[1]);
+
+ dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler end\n");
+
+ return 0;
+}
+
+/**
+ * sep_start_handler - start device
+ * @sep: pointer to struct sep_device
+ */
+static int sep_start_handler(struct sep_device *sep)
+{
+ unsigned long reg_val;
+ unsigned long error = 0;
+
+ dev_dbg(&sep->pdev->dev, "sep_start_handler start\n");
+
+ /* Wait in polling for message from SEP */
+ do {
+ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+ } while (!reg_val);
+
+ /* Check the value */
+ if (reg_val == 0x1)
+ /* Fatal error - read error status from GPRO */
+ error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
+ dev_dbg(&sep->pdev->dev, "sep_start_handler end\n");
+ return error;
+}
+
+/**
+ * ep_check_sum_calc - checksum messages
+ * @data: buffer to checksum
+ * @length: buffer size
+ *
+ * This function performs a checksum for messages that are sent
+ * to the SEP.
+ */
+static u32 sep_check_sum_calc(u8 *data, u32 length)
+{
+ u32 sum = 0;
+ u16 *Tdata = (u16 *)data;
+
+ while (length > 1) {
+ /* This is the inner loop */
+ sum += *Tdata++;
+ length -= 2;
+ }
+
+ /* Add left-over byte, if any */
+ if (length > 0)
+ sum += *(u8 *)Tdata;
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum>>16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return ~sum & 0xFFFF;
+}
+
+/**
+ * sep_init_handler -
+ * @sep: pointer to struct sep_device
+ * @arg: parameters from user space application
+ *
+ * Handles the request for SEP initialization
+ * Note that this will go away for Medfield once the SCU
+ * SEP initialization is complete
+ * Also note that the message to the SEP has components
+ * from user space as well as components written by the driver
+ * This is becuase the portions of the message that pertain to
+ * physical addresses must be set by the driver after the message
+ * leaves custody of the user space application for security
+ * reasons.
+ */
+static int sep_init_handler(struct sep_device *sep, unsigned long arg)
+{
+ u32 message_buff[14];
+ u32 counter;
+ int error = 0;
+ u32 reg_val;
+ dma_addr_t new_base_addr;
+ unsigned long addr_hold;
+ struct init_struct command_args;
+
+ dev_dbg(&sep->pdev->dev, "sep_init_handler start\n");
+
+ /* Make sure that we have not initialized already */
+ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+
+ if (reg_val != 0x2) {
+ error = SEP_ALREADY_INITIALIZED_ERR;
+ dev_warn(&sep->pdev->dev, "init; device already initialized\n");
+ goto end_function;
+ }
+
+ /* Only root can initialize */
+ if (!capable(CAP_SYS_ADMIN)) {
+ error = -EACCES;
+ goto end_function;
+ }
+
+ /* Copy in the parameters */
+ error = copy_from_user(&command_args, (void __user *)arg,
+ sizeof(struct init_struct));
+
+ if (error) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ /* Validate parameters */
+ if (!command_args.message_addr || !command_args.sep_sram_addr ||
+ command_args.message_size_in_words > 14) {
+ error = -EINVAL;
+ goto end_function;
+ }
+
+ /* Copy in the SEP init message */
+ addr_hold = (unsigned long)command_args.message_addr;
+ error = copy_from_user(message_buff,
+ (void __user *)addr_hold,
+ command_args.message_size_in_words*sizeof(u32));
+
+ if (error) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ /* Load resident, cache, and extapp firmware */
+ error = sep_load_firmware(sep);
+
+ if (error) {
+ dev_warn(&sep->pdev->dev,
+ "init; copy SEP init message failed %x\n", error);
+ goto end_function;
+ }
+
+ /* Compute the base address */
+ new_base_addr = sep->shared_bus;
+
+ if (sep->resident_bus < new_base_addr)
+ new_base_addr = sep->resident_bus;
+
+ if (sep->cache_bus < new_base_addr)
+ new_base_addr = sep->cache_bus;
+
+ if (sep->dcache_bus < new_base_addr)
+ new_base_addr = sep->dcache_bus;
+
+ /* Put physical addresses in SEP message */
+ message_buff[3] = (u32)new_base_addr;
+ message_buff[4] = (u32)sep->shared_bus;
+ message_buff[6] = (u32)sep->resident_bus;
+ message_buff[7] = (u32)sep->cache_bus;
+ message_buff[8] = (u32)sep->dcache_bus;
+
+ message_buff[command_args.message_size_in_words - 1] = 0x0;
+ message_buff[command_args.message_size_in_words - 1] =
+ sep_check_sum_calc((u8 *)message_buff,
+ command_args.message_size_in_words*sizeof(u32));
+
+ /* Debug print of message */
+ for (counter = 0; counter < command_args.message_size_in_words;
+ counter++)
+ dev_dbg(&sep->pdev->dev, "init; SEP message word %d is %x\n",
+ counter, message_buff[counter]);
+
+ /* Tell the SEP the sram address */
+ sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, command_args.sep_sram_addr);
+
+ /* Push the message to the SEP */
+ for (counter = 0; counter < command_args.message_size_in_words;
+ counter++) {
+ sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR,
+ message_buff[counter]);
+ sep_wait_sram_write(sep);
+ }
+
+ /* Signal SEP that message is ready and to init */
+ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1);
+
+ /* Wait for acknowledge */
+ dev_dbg(&sep->pdev->dev, "init; waiting for msg response\n");
+
+ do {
+ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+ } while (!(reg_val & 0xFFFFFFFD));
+
+ if (reg_val == 0x1) {
+ dev_warn(&sep->pdev->dev, "init; device int failed\n");
+ error = sep_read_reg(sep, 0x8060);
+ dev_warn(&sep->pdev->dev, "init; sw monitor is %x\n", error);
+ error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR);
+ dev_warn(&sep->pdev->dev, "init; error is %x\n", error);
+ goto end_function;
+ }
+ dev_dbg(&sep->pdev->dev, "init; end CC INIT, reg_val is %x\n", reg_val);
+
+ /* Signal SEP to zero the GPR3 */
+ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x10);
+
+ /* Wait for response */
+ dev_dbg(&sep->pdev->dev, "init; waiting for zero set response\n");
+
+ do {
+ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
+ } while (reg_val != 0);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "init is done\n");
+ return error;
+}
+
+/**
+ * sep_end_transaction_handler - end transaction
+ * @sep: pointer to struct sep_device
+ *
+ * This API handles the end transaction request
+ */
+static int sep_end_transaction_handler(struct sep_device *sep)
+{
+ dev_dbg(&sep->pdev->dev, "sep_end_transaction_handler start\n");
+
+ /* Clear the data pool pointers Token */
+ memset((void *)(sep->shared_addr +
+ SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES),
+ 0, sep->num_of_data_allocations*2*sizeof(u32));
+
+ /* Check that all the DMA resources were freed */
+ sep_free_dma_table_data_handler(sep);
+
+ clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags);
+
+ /*
+ * We are now through with the transaction. Let's
+ * allow other processes who have the device open
+ * to perform transactions
+ */
+ mutex_lock(&sep->sep_mutex);
+ sep->pid_doing_transaction = 0;
+ mutex_unlock(&sep->sep_mutex);
+ /* Raise event for stuck contextes */
+ wake_up(&sep->event);
+
+ dev_dbg(&sep->pdev->dev, "waking up event\n");
+ dev_dbg(&sep->pdev->dev, "sep_end_transaction_handler end\n");
+
+ return 0;
+}
+
+/**
+ * sep_prepare_dcb_handler - prepare a control block
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to user parameters
+ *
+ * This function will retrieve the RAR buffer physical addresses, type
+ * & size corresponding to the RAR handles provided in the buffers vector.
+ */
+static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg)
+{
+ int error;
+ /* Command arguments */
+ struct build_dcb_struct command_args;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n");
+
+ /* Get the command arguments */
+ if (copy_from_user(&command_args, (void __user *)arg,
+ sizeof(struct build_dcb_struct))) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ dev_dbg(&sep->pdev->dev, "app_in_address is %08llx\n",
+ command_args.app_in_address);
+ dev_dbg(&sep->pdev->dev, "app_out_address is %08llx\n",
+ command_args.app_out_address);
+ dev_dbg(&sep->pdev->dev, "data_size is %x\n",
+ command_args.data_in_size);
+ dev_dbg(&sep->pdev->dev, "block_size is %x\n",
+ command_args.block_size);
+ dev_dbg(&sep->pdev->dev, "tail block_size is %x\n",
+ command_args.tail_block_size);
+
+ error = sep_prepare_input_output_dma_table_in_dcb(sep,
+ (unsigned long)command_args.app_in_address,
+ (unsigned long)command_args.app_out_address,
+ command_args.data_in_size, command_args.block_size,
+ command_args.tail_block_size, true, false);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler end\n");
+ return error;
+
+}
+
+/**
+ * sep_free_dcb_handler - free control block resources
+ * @sep: pointer to struct sep_device
+ *
+ * This function frees the DCB resources and updates the needed
+ * user-space buffers.
+ */
+static int sep_free_dcb_handler(struct sep_device *sep)
+{
+ int error ;
+
+ dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n");
+ dev_dbg(&sep->pdev->dev, "num of DCBs %x\n", sep->nr_dcb_creat);
+
+ error = sep_free_dma_tables_and_dcb(sep, false, false);
+
+ dev_dbg(&sep->pdev->dev, "sep_free_dcb_handler end\n");
+ return error;
+}
+
+/**
+ * sep_rar_prepare_output_msg_handler - prepare an output message
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to user parameters
+ *
+ * This function will retrieve the RAR buffer physical addresses, type
+ * & size corresponding to the RAR handles provided in the buffers vector.
+ */
+static int sep_rar_prepare_output_msg_handler(struct sep_device *sep,
+ unsigned long arg)
+{
+ int error = 0;
+ /* Command args */
+ struct rar_hndl_to_bus_struct command_args;
+ struct RAR_buffer rar_buf;
+ /* Bus address */
+ dma_addr_t rar_bus = 0;
+ /* Holds the RAR address in the system memory offset */
+ u32 *rar_addr;
+
+ dev_dbg(&sep->pdev->dev, "sep_rar_prepare_output_msg_handler start\n");
+
+ /* Copy the data */
+ if (copy_from_user(&command_args, (void __user *)arg,
+ sizeof(command_args))) {
+ error = -EFAULT;
+ goto end_function;
+ }
+
+ /* Call to translation function only if user handle is not NULL */
+ if (command_args.rar_handle) {
+ memset(&rar_buf, 0, sizeof(rar_buf));
+ rar_buf.info.handle = (u32)command_args.rar_handle;
+
+ if (rar_handle_to_bus(&rar_buf, 1) != 1) {
+ dev_dbg(&sep->pdev->dev, "rar_handle_to_bus failure\n");
+ error = -EFAULT;
+ goto end_function;
+ }
+ rar_bus = rar_buf.bus_address;
+ }
+ dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", (u32)rar_bus);
+
+ /* Set value in the SYSTEM MEMORY offset */
+ rar_addr = (u32 *)(sep->shared_addr +
+ SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES);
+
+ /* Copy the physical address to the System Area for the SEP */
+ rar_addr[0] = SEP_RAR_VAL_TOKEN;
+ rar_addr[1] = rar_bus;
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "sep_rar_prepare_output_msg_handler start\n");
+ return error;
+}
+
+/**
+ * sep_realloc_ext_cache_handler - report location of extcache
+ * @sep: pointer to struct sep_device
+ * @arg: pointer to user parameters
+ *
+ * This function tells the SEP where the extapp is located
+ */
+static int sep_realloc_ext_cache_handler(struct sep_device *sep,
+ unsigned long arg)
+{
+ /* Holds the new ext cache address in the system memory offset */
+ u32 *system_addr;
+
+ /* Set value in the SYSTEM MEMORY offset */
+ system_addr = (u32 *)(sep->shared_addr +
+ SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES);
+
+ /* Copy the physical address to the System Area for the SEP */
+ system_addr[0] = SEP_EXT_CACHE_ADDR_VAL_TOKEN;
+ dev_dbg(&sep->pdev->dev, "ext cache init; system addr 0 is %x\n",
+ system_addr[0]);
+ system_addr[1] = sep->extapp_bus;
+ dev_dbg(&sep->pdev->dev, "ext cache init; system addr 1 is %x\n",
+ system_addr[1]);
+
+ return 0;
+}
+
+/**
+ * sep_ioctl - ioctl api
+ * @filp: pointer to struct file
+ * @cmd: command
+ * @arg: pointer to argument structure
+ *
+ * Implement the ioctl methods availble on the SEP device.
+ */
+static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int error = 0;
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "ioctl start\n");
+
+ dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd);
+
+ /* Make sure we own this device */
+ mutex_lock(&sep->sep_mutex);
+ if ((current->pid != sep->pid_doing_transaction) &&
+ (sep->pid_doing_transaction != 0)) {
+ dev_dbg(&sep->pdev->dev, "ioctl pid is not owner\n");
+ mutex_unlock(&sep->sep_mutex);
+ error = -EACCES;
+ goto end_function;
+ }
+
+ mutex_unlock(&sep->sep_mutex);
+
+ /* Check that the command is for SEP device */
+ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) {
+ error = -ENOTTY;
+ goto end_function;
+ }
+
+ /* Lock to prevent the daemon to interfere with operation */
+ mutex_lock(&sep->ioctl_mutex);
+
+ switch (cmd) {
+ case SEP_IOCSENDSEPCOMMAND:
+ /* Send command to SEP */
+ error = sep_send_command_handler(sep);
+ break;
+ case SEP_IOCALLOCDATAPOLL:
+ /* Allocate data pool */
+ error = sep_allocate_data_pool_memory_handler(sep, arg);
+ break;
+ case SEP_IOCCREATESYMDMATABLE:
+ /* Create DMA table for synhronic operation */
+ error = sep_create_sync_dma_tables_handler(sep, arg);
+ break;
+ case SEP_IOCFREEDMATABLEDATA:
+ /* Free the pages */
+ error = sep_free_dma_table_data_handler(sep);
+ break;
+ case SEP_IOCSEPSTART:
+ /* Start command to SEP */
+ if (sep->pdev->revision == 0) /* Only for old chip */
+ error = sep_start_handler(sep);
+ else
+ error = -EPERM; /* Not permitted on new chip */
+ break;
+ case SEP_IOCSEPINIT:
+ /* Init command to SEP */
+ if (sep->pdev->revision == 0) /* Only for old chip */
+ error = sep_init_handler(sep, arg);
+ else
+ error = -EPERM; /* Not permitted on new chip */
+ break;
+ case SEP_IOCGETSTATICPOOLADDR:
+ /* Inform the SEP the bus address of the static pool */
+ error = sep_get_static_pool_addr_handler(sep);
+ break;
+ case SEP_IOCENDTRANSACTION:
+ error = sep_end_transaction_handler(sep);
+ break;
+ case SEP_IOCREALLOCEXTCACHE:
+ if (sep->pdev->revision == 0) /* Only for old chip */
+ error = sep_realloc_ext_cache_handler(sep, arg);
+ else
+ error = -EPERM; /* Not permitted on new chip */
+ break;
+ case SEP_IOCRARPREPAREMESSAGE:
+ error = sep_rar_prepare_output_msg_handler(sep, arg);
+ break;
+ case SEP_IOCPREPAREDCB:
+ error = sep_prepare_dcb_handler(sep, arg);
+ break;
+ case SEP_IOCFREEDCB:
+ error = sep_free_dcb_handler(sep);
+ break;
+ default:
+ dev_dbg(&sep->pdev->dev, "invalid ioctl %x\n", cmd);
+ error = -ENOTTY;
+ break;
+ }
+ mutex_unlock(&sep->ioctl_mutex);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "ioctl end\n");
+ return error;
+}
+
+/**
+ * sep_singleton_ioctl - ioctl api for singleton interface
+ * @filp: pointer to struct file
+ * @cmd: command
+ * @arg: pointer to argument structure
+ *
+ * Implement the additional ioctls for the singleton device
+ */
+static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg)
+{
+ long error = 0;
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "singleton_ioctl start\n");
+ dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd);
+
+ /* Check that the command is for the SEP device */
+ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) {
+ error = -ENOTTY;
+ goto end_function;
+ }
+
+ /* Make sure we own this device */
+ mutex_lock(&sep->sep_mutex);
+ if ((current->pid != sep->pid_doing_transaction) &&
+ (sep->pid_doing_transaction != 0)) {
+ dev_dbg(&sep->pdev->dev, "singleton ioctl pid is not owner\n");
+ mutex_unlock(&sep->sep_mutex);
+ error = -EACCES;
+ goto end_function;
+ }
+
+ mutex_unlock(&sep->sep_mutex);
+
+ switch (cmd) {
+ case SEP_IOCTLSETCALLERID:
+ mutex_lock(&sep->ioctl_mutex);
+ error = sep_set_caller_id_handler(sep, arg);
+ mutex_unlock(&sep->ioctl_mutex);
+ break;
+ default:
+ error = sep_ioctl(filp, cmd, arg);
+ break;
+ }
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "singleton ioctl end\n");
+ return error;
+}
+
+/**
+ * sep_request_daemon_ioctl - ioctl for daemon
+ * @filp: pointer to struct file
+ * @cmd: command
+ * @arg: pointer to argument structure
+ *
+ * Called by the request daemon to perform ioctls on the daemon device
+ */
+static long sep_request_daemon_ioctl(struct file *filp, u32 cmd,
+ unsigned long arg)
+{
+
+ long error;
+ struct sep_device *sep = filp->private_data;
+
+ dev_dbg(&sep->pdev->dev, "daemon ioctl: start\n");
+ dev_dbg(&sep->pdev->dev, "daemon ioctl: cmd is %x\n", cmd);
+
+ /* Check that the command is for SEP device */
+ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) {
+ error = -ENOTTY;
+ goto end_function;
+ }
+
+ /* Only one process can access ioctl at any given time */
+ mutex_lock(&sep->ioctl_mutex);
+
+ switch (cmd) {
+ case SEP_IOCSENDSEPRPLYCOMMAND:
+ /* Send reply command to SEP */
+ error = sep_req_daemon_send_reply_command_handler(sep);
+ break;
+ case SEP_IOCENDTRANSACTION:
+ /*
+ * End req daemon transaction, do nothing
+ * will be removed upon update in middleware
+ * API library
+ */
+ error = 0;
+ break;
+ default:
+ dev_dbg(&sep->pdev->dev, "daemon ioctl: no such IOCTL\n");
+ error = -ENOTTY;
+ }
+ mutex_unlock(&sep->ioctl_mutex);
+
+end_function:
+ dev_dbg(&sep->pdev->dev, "daemon ioctl: end\n");
+ return error;
+
+}
+
+/**
+ * sep_inthandler - interrupt handler
+ * @irq: interrupt
+ * @dev_id: device id
+ */
+static irqreturn_t sep_inthandler(int irq, void *dev_id)
+{
+ irqreturn_t int_error = IRQ_HANDLED;
+ unsigned long lck_flags;
+ u32 reg_val, reg_val2 = 0;
+ struct sep_device *sep = dev_id;
+
+ /* Read the IRR register to check if this is SEP interrupt */
+ reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR);
+ dev_dbg(&sep->pdev->dev, "SEP Interrupt - reg is %08x\n", reg_val);
+
+ if (reg_val & (0x1 << 13)) {
+ /* Lock and update the counter of reply messages */
+ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags);
+ sep->reply_ct++;
+ spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags);
+
+ dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n",
+ sep->send_ct, sep->reply_ct);
+
+ /* Is this printf or daemon request? */
+ reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+ dev_dbg(&sep->pdev->dev,
+ "SEP Interrupt - reg2 is %08x\n", reg_val2);
+
+ if ((reg_val2 >> 30) & 0x1) {
+ dev_dbg(&sep->pdev->dev, "int: printf request\n");
+ wake_up(&sep->event_request_daemon);
+ } else if (reg_val2 >> 31) {
+ dev_dbg(&sep->pdev->dev, "int: daemon request\n");
+ wake_up(&sep->event_request_daemon);
+ } else {
+ dev_dbg(&sep->pdev->dev, "int: SEP reply\n");
+ wake_up(&sep->event);
+ }
+ } else {
+ dev_dbg(&sep->pdev->dev, "int: not SEP interrupt\n");
+ int_error = IRQ_NONE;
+ }
+ if (int_error == IRQ_HANDLED)
+ sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val);
+
+ return int_error;
+}
+
+/**
+ * sep_reconfig_shared_area - reconfigure shared area
+ * @sep: pointer to struct sep_device
+ *
+ * Reconfig the shared area between HOST and SEP - needed in case
+ * the DX_CC_Init function was called before OS loading.
+ */
+static int sep_reconfig_shared_area(struct sep_device *sep)
+{
+ int ret_val;
+
+ /* use to limit waiting for SEP */
+ unsigned long end_time;
+
+ dev_dbg(&sep->pdev->dev, "reconfig shared area start\n");
+
+ /* Send the new SHARED MESSAGE AREA to the SEP */
+ dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n",
+ (unsigned long long)sep->shared_bus);
+
+ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus);
+
+ /* Poll for SEP response */
+ ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
+
+ end_time = jiffies + (WAIT_TIME * HZ);
+
+ while ((time_before(jiffies, end_time)) && (ret_val != 0xffffffff) &&
+ (ret_val != sep->shared_bus))
+ ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR);
+
+ /* Check the return value (register) */
+ if (ret_val != sep->shared_bus) {
+ dev_warn(&sep->pdev->dev, "could not reconfig shared area\n");
+ dev_warn(&sep->pdev->dev, "result was %x\n", ret_val);
+ ret_val = -ENOMEM;
+ } else
+ ret_val = 0;
+
+ dev_dbg(&sep->pdev->dev, "reconfig shared area end\n");
+ return ret_val;
+}
+
+/* File operation for singleton SEP operations */
+static const struct file_operations singleton_file_operations = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = sep_singleton_ioctl,
+ .poll = sep_poll,
+ .open = sep_singleton_open,
+ .release = sep_singleton_release,
+ .mmap = sep_mmap,
+};
+
+/* File operation for daemon operations */
+static const struct file_operations daemon_file_operations = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = sep_request_daemon_ioctl,
+ .poll = sep_request_daemon_poll,
+ .open = sep_request_daemon_open,
+ .release = sep_request_daemon_release,
+ .mmap = sep_request_daemon_mmap,
+};
+
+/* The files operations structure of the driver */
+static const struct file_operations sep_file_operations = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = sep_ioctl,
+ .poll = sep_poll,
+ .open = sep_open,
+ .release = sep_release,
+ .mmap = sep_mmap,
+};
+
+/**
+ * sep_register_driver_with_fs - register misc devices
+ * @sep: pointer to struct sep_device
+ *
+ * This function registers the driver with the file system
+ */
+static int sep_register_driver_with_fs(struct sep_device *sep)
+{
+ int ret_val;
+
+ sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR;
+ sep->miscdev_sep.name = SEP_DEV_NAME;
+ sep->miscdev_sep.fops = &sep_file_operations;
+
+ sep->miscdev_singleton.minor = MISC_DYNAMIC_MINOR;
+ sep->miscdev_singleton.name = SEP_DEV_SINGLETON;
+ sep->miscdev_singleton.fops = &singleton_file_operations;
+
+ sep->miscdev_daemon.minor = MISC_DYNAMIC_MINOR;
+ sep->miscdev_daemon.name = SEP_DEV_DAEMON;
+ sep->miscdev_daemon.fops = &daemon_file_operations;
+
+ ret_val = misc_register(&sep->miscdev_sep);
+ if (ret_val) {
+ dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n",
+ ret_val);
+ return ret_val;
+ }
+
+ ret_val = misc_register(&sep->miscdev_singleton);
+ if (ret_val) {
+ dev_warn(&sep->pdev->dev, "misc reg fails for sing %x\n",
+ ret_val);
+ misc_deregister(&sep->miscdev_sep);
+ return ret_val;
+ }
+
+ ret_val = misc_register(&sep->miscdev_daemon);
+ if (ret_val) {
+ dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n",
+ ret_val);
+ misc_deregister(&sep->miscdev_sep);
+ misc_deregister(&sep->miscdev_singleton);
+
+ return ret_val;
+ }
+ return ret_val;
+}
+
+
+/**
+ * sep_probe - probe a matching PCI device
+ * @pdev: pci_device
+ * @end: pci_device_id
+ *
+ * Attempt to set up and configure a SEP device that has been
+ * discovered by the PCI layer.
+ */
+static int __devinit sep_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int error = 0;
+ struct sep_device *sep;
+
+ pr_debug("SEP pci probe starting\n");
+ if (sep_dev != NULL) {
+ dev_warn(&pdev->dev, "only one SEP supported.\n");
+ return -EBUSY;
+ }
+
+ /* Enable the device */
+ error = pci_enable_device(pdev);
+ if (error) {
+ dev_warn(&pdev->dev, "error enabling pci device\n");
+ goto end_function;
+ }
+
+ /* Allocate the sep_device structure for this device */
+ sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC);
+ if (sep_dev == NULL) {
+ dev_warn(&pdev->dev,
+ "can't kmalloc the sep_device structure\n");
+ error = -ENOMEM;
+ goto end_function_disable_device;
+ }
+
+ /*
+ * We're going to use another variable for actually
+ * working with the device; this way, if we have
+ * multiple devices in the future, it would be easier
+ * to make appropriate changes
+ */
+ sep = sep_dev;
+
+ sep->pdev = pci_dev_get(pdev);
+
+ init_waitqueue_head(&sep->event);
+ init_waitqueue_head(&sep->event_request_daemon);
+ spin_lock_init(&sep->snd_rply_lck);
+ mutex_init(&sep->sep_mutex);
+ mutex_init(&sep->ioctl_mutex);
+
+ dev_dbg(&sep->pdev->dev, "PCI obtained, device being prepared\n");
+ dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision);
+
+ /* Set up our register area */
+ sep->reg_physical_addr = pci_resource_start(sep->pdev, 0);
+ if (!sep->reg_physical_addr) {
+ dev_warn(&sep->pdev->dev, "Error getting register start\n");
+ error = -ENODEV;
+ goto end_function_free_sep_dev;
+ }
+
+ sep->reg_physical_end = pci_resource_end(sep->pdev, 0);
+ if (!sep->reg_physical_end) {
+ dev_warn(&sep->pdev->dev, "Error getting register end\n");
+ error = -ENODEV;
+ goto end_function_free_sep_dev;
+ }
+
+ sep->reg_addr = ioremap_nocache(sep->reg_physical_addr,
+ (size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1));
+ if (!sep->reg_addr) {
+ dev_warn(&sep->pdev->dev, "Error getting register virtual\n");
+ error = -ENODEV;
+ goto end_function_free_sep_dev;
+ }
+
+ dev_dbg(&sep->pdev->dev,
+ "Register area start %llx end %llx virtual %p\n",
+ (unsigned long long)sep->reg_physical_addr,
+ (unsigned long long)sep->reg_physical_end,
+ sep->reg_addr);
+
+ /* Allocate the shared area */
+ sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
+ SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES +
+ SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES +
+ SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES +
+ SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;
+
+ if (sep_map_and_alloc_shared_area(sep)) {
+ error = -ENOMEM;
+ /* Allocation failed */
+ goto end_function_error;
+ }
+
+ sep->rar_size = FAKE_RAR_SIZE;
+ sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev,
+ sep->rar_size, &sep->rar_bus, GFP_KERNEL);
+ if (sep->rar_addr == NULL) {
+ dev_warn(&sep->pdev->dev, "can't allocate mfld rar\n");
+ error = -ENOMEM;
+ goto end_function_deallocate_sep_shared_area;
+ }
+
+ dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx,"
+ " size is %zx\n", sep->rar_addr,
+ (unsigned long long)sep->rar_bus,
+ sep->rar_size);
+
+ dev_dbg(&sep->pdev->dev, "about to write IMR and ICR REG_ADDR\n");
+
+ /* Clear ICR register */
+ sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);
+
+ /* Set the IMR register - open only GPR 2 */
+ sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));
+
+ /* Read send/receive counters from SEP */
+ sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR);
+ sep->reply_ct &= 0x3FFFFFFF;
+ sep->send_ct = sep->reply_ct;
+
+ dev_dbg(&sep->pdev->dev, "about to call request_irq\n");
+ /* Get the interrupt line */
+ error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED,
+ "sep_driver", sep);
+
+ if (error)
+ goto end_function_dealloc_rar;
+
+ /* The new chip requires ashared area reconfigure */
+ if (sep->pdev->revision == 4) { /* Only for new chip */
+ error = sep_reconfig_shared_area(sep);
+ if (error)
+ goto end_function_free_irq;
+ }
+ /* Finally magic up the device nodes */
+ /* Register driver with the fs */
+ error = sep_register_driver_with_fs(sep);
+ if (error == 0)
+ /* Success */
+ return 0;
+
+end_function_free_irq:
+ free_irq(pdev->irq, sep);
+
+end_function_dealloc_rar:
+ if (sep->rar_addr)
+ dma_free_coherent(&sep->pdev->dev, sep->rar_size,
+ sep->rar_addr, sep->rar_bus);
+ goto end_function;
+
+end_function_deallocate_sep_shared_area:
+ /* De-allocate shared area */
+ sep_unmap_and_free_shared_area(sep);
+
+end_function_error:
+ iounmap(sep->reg_addr);
+
+end_function_free_sep_dev:
+ pci_dev_put(sep_dev->pdev);
+ kfree(sep_dev);
+ sep_dev = NULL;
+
+end_function_disable_device:
+ pci_disable_device(pdev);
+
+end_function:
+ return error;
+}
+
+static void sep_remove(struct pci_dev *pdev)
+{
+ struct sep_device *sep = sep_dev;
+
+ /* Unregister from fs */
+ misc_deregister(&sep->miscdev_sep);
+ misc_deregister(&sep->miscdev_singleton);
+ misc_deregister(&sep->miscdev_daemon);
+
+ /* Free the irq */
+ free_irq(sep->pdev->irq, sep);
+
+ /* Free the shared area */
+ sep_unmap_and_free_shared_area(sep_dev);
+ iounmap((void *) sep_dev->reg_addr);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_PCI_DEVICE_ID)},
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl);
+
+/* Field for registering driver to PCI device */
+static struct pci_driver sep_pci_driver = {
+ .name = "sep_sec_driver",
+ .id_table = sep_pci_id_tbl,
+ .probe = sep_probe,
+ .remove = sep_remove
+};
+
+
+/**
+ * sep_init - init function
+ *
+ * Module load time. Register the PCI device driver.
+ */
+static int __init sep_init(void)
+{
+ return pci_register_driver(&sep_pci_driver);
+}
+
+
+/**
+ * sep_exit - called to unload driver
+ *
+ * Drop the misc devices then remove and unmap the various resources
+ * that are not released by the driver remove method.
+ */
+static void __exit sep_exit(void)
+{
+ pci_unregister_driver(&sep_pci_driver);
+}
+
+
+module_init(sep_init);
+module_exit(sep_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h
new file mode 100644
index 000000000000..fbbfa2396555
--- /dev/null
+++ b/drivers/staging/sep/sep_driver_api.h
@@ -0,0 +1,297 @@
+/*
+ *
+ * sep_driver_api.h - Security Processor Driver api definitions
+ *
+ * Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
+ * Contributions(c) 2009,2010 Discretix. 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * CONTACTS:
+ *
+ * Mark Allyn mark.a.allyn@intel.com
+ * Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ * CHANGES:
+ *
+ * 2010.09.14 Upgrade to Medfield
+ *
+ */
+
+#ifndef __SEP_DRIVER_API_H__
+#define __SEP_DRIVER_API_H__
+
+/* Type of request from device */
+#define SEP_DRIVER_SRC_REPLY 1
+#define SEP_DRIVER_SRC_REQ 2
+#define SEP_DRIVER_SRC_PRINTF 3
+
+
+/*-------------------------------------------
+ TYPEDEFS
+----------------------------------------------*/
+
+/*
+ * Note that several members of these structres are only here
+ * for campatability with the middleware; they are not used
+ * by this driver.
+ * All user space buffer addresses are set to aligned u64
+ * in order to ensure compatibility with 64 bit systems
+ */
+
+/*
+ init command struct; this will go away when SCU does init
+*/
+struct init_struct {
+ /* address that SEP can access for message */
+ aligned_u64 message_addr;
+
+ /* message size */
+ u32 message_size_in_words;
+
+ /* offset of the init message in the sep sram */
+ u32 sep_sram_addr;
+
+ /* -not used- resident size in bytes*/
+ u32 unused_resident_size_in_bytes;
+
+ /* -not used- cache size in bytes*/
+ u32 unused_cache_size_in_bytes;
+
+ /* -not used- ext cache current address */
+ aligned_u64 unused_extcache_addr;
+
+ /* -not used- ext cache size in bytes*/
+ u32 unused_extcache_size_in_bytes;
+};
+
+struct realloc_ext_struct {
+ /* -not used- current external cache address */
+ aligned_u64 unused_ext_cache_addr;
+
+ /* -not used- external cache size in bytes*/
+ u32 unused_ext_cache_size_in_bytes;
+};
+
+struct alloc_struct {
+ /* offset from start of shared pool area */
+ u32 offset;
+ /* number of bytes to allocate */
+ u32 num_bytes;
+};
+
+/*
+ Note that all app addresses are cast as u32; the sep
+ middleware sends them as fixed 32 bit words
+*/
+struct bld_syn_tab_struct {
+ /* address value of the data in (user space addr) */
+ aligned_u64 app_in_address;
+
+ /* size of data in */
+ u32 data_in_size;
+
+ /* address of the data out (user space addr) */
+ aligned_u64 app_out_address;
+
+ /* the size of the block of the operation - if needed,
+ every table will be modulo this parameter */
+ u32 block_size;
+
+ /* -not used- distinct user/kernel layout */
+ bool isKernelVirtualAddress;
+
+};
+
+/* command struct for getting caller id value and address */
+struct caller_id_struct {
+ /* pid of the process */
+ u32 pid;
+ /* virtual address of the caller id hash */
+ aligned_u64 callerIdAddress;
+ /* caller id hash size in bytes */
+ u32 callerIdSizeInBytes;
+};
+
+/*
+ structure that represents DCB
+*/
+struct sep_dcblock {
+ /* physical address of the first input mlli */
+ u32 input_mlli_address;
+ /* num of entries in the first input mlli */
+ u32 input_mlli_num_entries;
+ /* size of data in the first input mlli */
+ u32 input_mlli_data_size;
+ /* physical address of the first output mlli */
+ u32 output_mlli_address;
+ /* num of entries in the first output mlli */
+ u32 output_mlli_num_entries;
+ /* size of data in the first output mlli */
+ u32 output_mlli_data_size;
+ /* pointer to the output virtual tail */
+ u32 out_vr_tail_pt;
+ /* size of tail data */
+ u32 tail_data_size;
+ /* input tail data array */
+ u8 tail_data[64];
+};
+
+struct sep_caller_id_entry {
+ int pid;
+ unsigned char callerIdHash[SEP_CALLER_ID_HASH_SIZE_IN_BYTES];
+};
+
+/*
+ command structure for building dcb block (currently for ext app only
+*/
+struct build_dcb_struct {
+ /* address value of the data in */
+ aligned_u64 app_in_address;
+ /* size of data in */
+ u32 data_in_size;
+ /* address of the data out */
+ aligned_u64 app_out_address;
+ /* the size of the block of the operation - if needed,
+ every table will be modulo this parameter */
+ u32 block_size;
+ /* the size of the block of the operation - if needed,
+ every table will be modulo this parameter */
+ u32 tail_block_size;
+};
+
+/**
+ * @struct sep_dma_map
+ *
+ * Structure that contains all information needed for mapping the user pages
+ * or kernel buffers for dma operations
+ *
+ *
+ */
+struct sep_dma_map {
+ /* mapped dma address */
+ dma_addr_t dma_addr;
+ /* size of the mapped data */
+ size_t size;
+};
+
+struct sep_dma_resource {
+ /* array of pointers to the pages that represent
+ input data for the synchronic DMA action */
+ struct page **in_page_array;
+
+ /* array of pointers to the pages that represent out
+ data for the synchronic DMA action */
+ struct page **out_page_array;
+
+ /* number of pages in the sep_in_page_array */
+ u32 in_num_pages;
+
+ /* number of pages in the sep_out_page_array */
+ u32 out_num_pages;
+
+ /* map array of the input data */
+ struct sep_dma_map *in_map_array;
+
+ /* map array of the output data */
+ struct sep_dma_map *out_map_array;
+
+ /* number of entries of the input mapp array */
+ u32 in_map_num_entries;
+
+ /* number of entries of the output mapp array */
+ u32 out_map_num_entries;
+};
+
+
+/* command struct for translating rar handle to bus address
+ and setting it at predefined location */
+struct rar_hndl_to_bus_struct {
+
+ /* rar handle */
+ aligned_u64 rar_handle;
+};
+
+/*
+ structure that represent one entry in the DMA LLI table
+*/
+struct sep_lli_entry {
+ /* physical address */
+ u32 bus_address;
+
+ /* block size */
+ u32 block_size;
+};
+
+/*----------------------------------------------------------------
+ IOCTL command defines
+ -----------------------------------------------------------------*/
+
+/* magic number 1 of the sep IOCTL command */
+#define SEP_IOC_MAGIC_NUMBER 's'
+
+/* sends interrupt to sep that message is ready */
+#define SEP_IOCSENDSEPCOMMAND \
+ _IO(SEP_IOC_MAGIC_NUMBER, 0)
+
+/* sends interrupt to sep that message is ready */
+#define SEP_IOCSENDSEPRPLYCOMMAND \
+ _IO(SEP_IOC_MAGIC_NUMBER, 1)
+
+/* allocate memory in data pool */
+#define SEP_IOCALLOCDATAPOLL \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 2, struct alloc_struct)
+
+/* create sym dma lli tables */
+#define SEP_IOCCREATESYMDMATABLE \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 5, struct bld_syn_tab_struct)
+
+/* free dynamic data aalocated during table creation */
+#define SEP_IOCFREEDMATABLEDATA \
+ _IO(SEP_IOC_MAGIC_NUMBER, 7)
+
+/* get the static pool area addersses (physical and virtual) */
+#define SEP_IOCGETSTATICPOOLADDR \
+ _IO(SEP_IOC_MAGIC_NUMBER, 8)
+
+/* start sep command */
+#define SEP_IOCSEPSTART \
+ _IO(SEP_IOC_MAGIC_NUMBER, 12)
+
+/* init sep command */
+#define SEP_IOCSEPINIT \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 13, struct init_struct)
+
+/* end transaction command */
+#define SEP_IOCENDTRANSACTION \
+ _IO(SEP_IOC_MAGIC_NUMBER, 15)
+
+/* reallocate external app; unused structure still needed for
+ * compatability with middleware */
+#define SEP_IOCREALLOCEXTCACHE \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 18, struct realloc_ext_struct)
+
+#define SEP_IOCRARPREPAREMESSAGE \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 20, struct rar_hndl_to_bus_struct)
+
+#define SEP_IOCTLSETCALLERID \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 34, struct caller_id_struct)
+
+#define SEP_IOCPREPAREDCB \
+ _IOW(SEP_IOC_MAGIC_NUMBER, 35, struct build_dcb_struct)
+
+#define SEP_IOCFREEDCB \
+ _IO(SEP_IOC_MAGIC_NUMBER, 36)
+
+#endif
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
new file mode 100644
index 000000000000..b18625d2f7f4
--- /dev/null
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -0,0 +1,239 @@
+/*
+ *
+ * sep_driver_config.h - Security Processor Driver configuration
+ *
+ * Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
+ * Contributions(c) 2009,2010 Discretix. 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * CONTACTS:
+ *
+ * Mark Allyn mark.a.allyn@intel.com
+ * Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ * CHANGES:
+ *
+ * 2010.06.26 Upgrade to Medfield
+ *
+ */
+
+#ifndef __SEP_DRIVER_CONFIG_H__
+#define __SEP_DRIVER_CONFIG_H__
+
+
+/*--------------------------------------
+ DRIVER CONFIGURATION FLAGS
+ -------------------------------------*/
+
+/* if flag is on , then the driver is running in polling and
+ not interrupt mode */
+#define SEP_DRIVER_POLLING_MODE 0
+
+/* flag which defines if the shared area address should be
+ reconfiged (send to SEP anew) during init of the driver */
+#define SEP_DRIVER_RECONFIG_MESSAGE_AREA 0
+
+/* the mode for running on the ARM1172 Evaluation platform (flag is 1) */
+#define SEP_DRIVER_ARM_DEBUG_MODE 0
+
+/*-------------------------------------------
+ INTERNAL DATA CONFIGURATION
+ -------------------------------------------*/
+
+/* flag for the input array */
+#define SEP_DRIVER_IN_FLAG 0
+
+/* flag for output array */
+#define SEP_DRIVER_OUT_FLAG 1
+
+/* maximum number of entries in one LLI tables */
+#define SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP 31
+
+/* minimum data size of the MLLI table */
+#define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16
+
+/* flag that signifies tah the lock is
+currently held by the proccess (struct file) */
+#define SEP_DRIVER_OWN_LOCK_FLAG 1
+
+/* flag that signifies tah the lock is currently NOT
+held by the proccess (struct file) */
+#define SEP_DRIVER_DISOWN_LOCK_FLAG 0
+
+/* indicates whether driver has mapped/unmapped shared area */
+#define SEP_REQUEST_DAEMON_MAPPED 1
+#define SEP_REQUEST_DAEMON_UNMAPPED 0
+
+/*--------------------------------------------------------
+ SHARED AREA memory total size is 36K
+ it is divided is following:
+
+ SHARED_MESSAGE_AREA 8K }
+ }
+ STATIC_POOL_AREA 4K } MAPPED AREA ( 24 K)
+ }
+ DATA_POOL_AREA 12K }
+
+ SYNCHRONIC_DMA_TABLES_AREA 5K
+
+ placeholder until drver changes
+ FLOW_DMA_TABLES_AREA 4K
+
+ SYSTEM_MEMORY_AREA 3k
+
+ SYSTEM_MEMORY total size is 3k
+ it is divided as following:
+
+ TIME_MEMORY_AREA 8B
+-----------------------------------------------------------*/
+
+#define SEP_DEV_NAME "sep_sec_driver"
+#define SEP_DEV_SINGLETON "sep_sec_singleton_driver"
+#define SEP_DEV_DAEMON "sep_req_daemon_driver"
+
+
+/*
+ the maximum length of the message - the rest of the message shared
+ area will be dedicated to the dma lli tables
+*/
+#define SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES (8 * 1024)
+
+/* the size of the message shared area in pages */
+#define SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES (8 * 1024)
+
+/* the size of the data pool static area in pages */
+#define SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES (4 * 1024)
+
+/* the size of the data pool shared area size in pages */
+#define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES (16 * 1024)
+
+/* the size of the message shared area in pages */
+#define SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES (1024 * 5)
+
+/* Placeholder until driver changes */
+#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 4)
+
+/* system data (time, caller id etc') pool */
+#define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES (1024 * 3)
+
+/* the size in bytes of the time memory */
+#define SEP_DRIVER_TIME_MEMORY_SIZE_IN_BYTES 8
+
+/* the size in bytes of the RAR parameters memory */
+#define SEP_DRIVER_SYSTEM_RAR_MEMORY_SIZE_IN_BYTES 8
+
+/* area size that is mapped - we map the MESSAGE AREA, STATIC POOL and
+ DATA POOL areas. area must be module 4k */
+#define SEP_DRIVER_MMMAP_AREA_SIZE (1024 * 28)
+
+/*-----------------------------------------------
+ offsets of the areas starting from the shared area start address
+*/
+
+/* message area offset */
+#define SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES 0
+
+/* static pool area offset */
+#define SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES \
+ (SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES)
+
+/* data pool area offset */
+#define SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES \
+ (SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \
+ SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES)
+
+/* synhronic dma tables area offset */
+#define SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES \
+ (SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \
+ SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)
+
+/* system memory offset in bytes */
+#define SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES \
+ (SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + \
+ SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)
+
+/* offset of the time area */
+#define SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES \
+ (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES)
+
+/* offset of the RAR area */
+#define SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES \
+ (SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES + \
+ SEP_DRIVER_TIME_MEMORY_SIZE_IN_BYTES)
+
+/* offset of the caller id area */
+#define SEP_CALLER_ID_OFFSET_BYTES \
+ (SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES + \
+ SEP_DRIVER_SYSTEM_RAR_MEMORY_SIZE_IN_BYTES)
+
+/* offset of the DCB area */
+#define SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES \
+ (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES + \
+ 0x400)
+
+/* offset of the ext cache area */
+#define SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES \
+ SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES
+
+/* offset of the allocation data pointer area */
+#define SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES \
+ (SEP_CALLER_ID_OFFSET_BYTES + \
+ SEP_CALLER_ID_HASH_SIZE_IN_BYTES)
+
+/* the token that defines the start of time address */
+#define SEP_TIME_VAL_TOKEN 0x12345678
+
+#define FAKE_RAR_SIZE (1024*1024) /* used only for mfld */
+/* DEBUG LEVEL MASKS */
+
+/* size of the caller id hash (sha2) */
+#define SEP_CALLER_ID_HASH_SIZE_IN_BYTES 32
+
+/* size of the caller id hash (sha2) in 32 bit words */
+#define SEP_CALLER_ID_HASH_SIZE_IN_WORDS 8
+
+/* maximum number of entries in the caller id table */
+#define SEP_CALLER_ID_TABLE_NUM_ENTRIES 20
+
+/* maximum number of symetric operation (that require DMA resource)
+ per one message */
+#define SEP_MAX_NUM_SYNC_DMA_OPS 16
+
+/* the token that defines the start of time address */
+#define SEP_RAR_VAL_TOKEN 0xABABABAB
+
+/* ioctl error that should be returned when trying
+ to realloc the cache/resident second time */
+#define SEP_ALREADY_INITIALIZED_ERR 12
+
+/* bit that locks access to the shared area */
+#define SEP_MMAP_LOCK_BIT 0
+
+/* bit that lock access to the poll - after send_command */
+#define SEP_SEND_MSG_LOCK_BIT 1
+
+/* the token that defines the static pool address address */
+#define SEP_STATIC_POOL_VAL_TOKEN 0xABBAABBA
+
+/* the token that defines the data pool pointers address */
+#define SEP_DATA_POOL_POINTERS_VAL_TOKEN 0xEDDEEDDE
+
+/* the token that defines the data pool pointers address */
+#define SEP_EXT_CACHE_ADDR_VAL_TOKEN 0xBABABABA
+
+/* Time limit for SEP to finish */
+#define WAIT_TIME 10
+
+#endif /* SEP DRIVER CONFIG */
diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h
new file mode 100644
index 000000000000..300f90963de3
--- /dev/null
+++ b/drivers/staging/sep/sep_driver_hw_defs.h
@@ -0,0 +1,233 @@
+/*
+ *
+ * sep_driver_hw_defs.h - Security Processor Driver hardware definitions
+ *
+ * Copyright(c) 2009,2010 Intel Corporation. All rights reserved.
+ * Contributions(c) 2009,2010 Discretix. 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * CONTACTS:
+ *
+ * Mark Allyn mark.a.allyn@intel.com
+ * Jayant Mangalampalli jayant.mangalampalli@intel.com
+ *
+ * CHANGES:
+ *
+ * 2010.09.20 Upgrade to Medfield
+ *
+ */
+
+#ifndef SEP_DRIVER_HW_DEFS__H
+#define SEP_DRIVER_HW_DEFS__H
+
+/* PCI ID's */
+#define MFLD_PCI_DEVICE_ID 0x0826
+
+/*----------------------- */
+/* HW Registers Defines. */
+/* */
+/*---------------------- -*/
+
+
+/* cf registers */
+#define HW_R0B_ADDR_0_REG_ADDR 0x0000UL
+#define HW_R0B_ADDR_1_REG_ADDR 0x0004UL
+#define HW_R0B_ADDR_2_REG_ADDR 0x0008UL
+#define HW_R0B_ADDR_3_REG_ADDR 0x000cUL
+#define HW_R0B_ADDR_4_REG_ADDR 0x0010UL
+#define HW_R0B_ADDR_5_REG_ADDR 0x0014UL
+#define HW_R0B_ADDR_6_REG_ADDR 0x0018UL
+#define HW_R0B_ADDR_7_REG_ADDR 0x001cUL
+#define HW_R0B_ADDR_8_REG_ADDR 0x0020UL
+#define HW_R2B_ADDR_0_REG_ADDR 0x0080UL
+#define HW_R2B_ADDR_1_REG_ADDR 0x0084UL
+#define HW_R2B_ADDR_2_REG_ADDR 0x0088UL
+#define HW_R2B_ADDR_3_REG_ADDR 0x008cUL
+#define HW_R2B_ADDR_4_REG_ADDR 0x0090UL
+#define HW_R2B_ADDR_5_REG_ADDR 0x0094UL
+#define HW_R2B_ADDR_6_REG_ADDR 0x0098UL
+#define HW_R2B_ADDR_7_REG_ADDR 0x009cUL
+#define HW_R2B_ADDR_8_REG_ADDR 0x00a0UL
+#define HW_R3B_REG_ADDR 0x00C0UL
+#define HW_R4B_REG_ADDR 0x0100UL
+#define HW_CSA_ADDR_0_REG_ADDR 0x0140UL
+#define HW_CSA_ADDR_1_REG_ADDR 0x0144UL
+#define HW_CSA_ADDR_2_REG_ADDR 0x0148UL
+#define HW_CSA_ADDR_3_REG_ADDR 0x014cUL
+#define HW_CSA_ADDR_4_REG_ADDR 0x0150UL
+#define HW_CSA_ADDR_5_REG_ADDR 0x0154UL
+#define HW_CSA_ADDR_6_REG_ADDR 0x0158UL
+#define HW_CSA_ADDR_7_REG_ADDR 0x015cUL
+#define HW_CSA_ADDR_8_REG_ADDR 0x0160UL
+#define HW_CSA_REG_ADDR 0x0140UL
+#define HW_SINB_REG_ADDR 0x0180UL
+#define HW_SOUTB_REG_ADDR 0x0184UL
+#define HW_PKI_CONTROL_REG_ADDR 0x01C0UL
+#define HW_PKI_STATUS_REG_ADDR 0x01C4UL
+#define HW_PKI_BUSY_REG_ADDR 0x01C8UL
+#define HW_PKI_A_1025_REG_ADDR 0x01CCUL
+#define HW_PKI_SDMA_CTL_REG_ADDR 0x01D0UL
+#define HW_PKI_SDMA_OFFSET_REG_ADDR 0x01D4UL
+#define HW_PKI_SDMA_POINTERS_REG_ADDR 0x01D8UL
+#define HW_PKI_SDMA_DLENG_REG_ADDR 0x01DCUL
+#define HW_PKI_SDMA_EXP_POINTERS_REG_ADDR 0x01E0UL
+#define HW_PKI_SDMA_RES_POINTERS_REG_ADDR 0x01E4UL
+#define HW_PKI_CLR_REG_ADDR 0x01E8UL
+#define HW_PKI_SDMA_BUSY_REG_ADDR 0x01E8UL
+#define HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR 0x01ECUL
+#define HW_PKI_SDMA_MUL_BY1_REG_ADDR 0x01F0UL
+#define HW_PKI_SDMA_RMUL_SEL_REG_ADDR 0x01F4UL
+#define HW_DES_KEY_0_REG_ADDR 0x0208UL
+#define HW_DES_KEY_1_REG_ADDR 0x020CUL
+#define HW_DES_KEY_2_REG_ADDR 0x0210UL
+#define HW_DES_KEY_3_REG_ADDR 0x0214UL
+#define HW_DES_KEY_4_REG_ADDR 0x0218UL
+#define HW_DES_KEY_5_REG_ADDR 0x021CUL
+#define HW_DES_CONTROL_0_REG_ADDR 0x0220UL
+#define HW_DES_CONTROL_1_REG_ADDR 0x0224UL
+#define HW_DES_IV_0_REG_ADDR 0x0228UL
+#define HW_DES_IV_1_REG_ADDR 0x022CUL
+#define HW_AES_KEY_0_ADDR_0_REG_ADDR 0x0400UL
+#define HW_AES_KEY_0_ADDR_1_REG_ADDR 0x0404UL
+#define HW_AES_KEY_0_ADDR_2_REG_ADDR 0x0408UL
+#define HW_AES_KEY_0_ADDR_3_REG_ADDR 0x040cUL
+#define HW_AES_KEY_0_ADDR_4_REG_ADDR 0x0410UL
+#define HW_AES_KEY_0_ADDR_5_REG_ADDR 0x0414UL
+#define HW_AES_KEY_0_ADDR_6_REG_ADDR 0x0418UL
+#define HW_AES_KEY_0_ADDR_7_REG_ADDR 0x041cUL
+#define HW_AES_KEY_0_REG_ADDR 0x0400UL
+#define HW_AES_IV_0_ADDR_0_REG_ADDR 0x0440UL
+#define HW_AES_IV_0_ADDR_1_REG_ADDR 0x0444UL
+#define HW_AES_IV_0_ADDR_2_REG_ADDR 0x0448UL
+#define HW_AES_IV_0_ADDR_3_REG_ADDR 0x044cUL
+#define HW_AES_IV_0_REG_ADDR 0x0440UL
+#define HW_AES_CTR1_ADDR_0_REG_ADDR 0x0460UL
+#define HW_AES_CTR1_ADDR_1_REG_ADDR 0x0464UL
+#define HW_AES_CTR1_ADDR_2_REG_ADDR 0x0468UL
+#define HW_AES_CTR1_ADDR_3_REG_ADDR 0x046cUL
+#define HW_AES_CTR1_REG_ADDR 0x0460UL
+#define HW_AES_SK_REG_ADDR 0x0478UL
+#define HW_AES_MAC_OK_REG_ADDR 0x0480UL
+#define HW_AES_PREV_IV_0_ADDR_0_REG_ADDR 0x0490UL
+#define HW_AES_PREV_IV_0_ADDR_1_REG_ADDR 0x0494UL
+#define HW_AES_PREV_IV_0_ADDR_2_REG_ADDR 0x0498UL
+#define HW_AES_PREV_IV_0_ADDR_3_REG_ADDR 0x049cUL
+#define HW_AES_PREV_IV_0_REG_ADDR 0x0490UL
+#define HW_AES_CONTROL_REG_ADDR 0x04C0UL
+#define HW_HASH_H0_REG_ADDR 0x0640UL
+#define HW_HASH_H1_REG_ADDR 0x0644UL
+#define HW_HASH_H2_REG_ADDR 0x0648UL
+#define HW_HASH_H3_REG_ADDR 0x064CUL
+#define HW_HASH_H4_REG_ADDR 0x0650UL
+#define HW_HASH_H5_REG_ADDR 0x0654UL
+#define HW_HASH_H6_REG_ADDR 0x0658UL
+#define HW_HASH_H7_REG_ADDR 0x065CUL
+#define HW_HASH_H8_REG_ADDR 0x0660UL
+#define HW_HASH_H9_REG_ADDR 0x0664UL
+#define HW_HASH_H10_REG_ADDR 0x0668UL
+#define HW_HASH_H11_REG_ADDR 0x066CUL
+#define HW_HASH_H12_REG_ADDR 0x0670UL
+#define HW_HASH_H13_REG_ADDR 0x0674UL
+#define HW_HASH_H14_REG_ADDR 0x0678UL
+#define HW_HASH_H15_REG_ADDR 0x067CUL
+#define HW_HASH_CONTROL_REG_ADDR 0x07C0UL
+#define HW_HASH_PAD_EN_REG_ADDR 0x07C4UL
+#define HW_HASH_PAD_CFG_REG_ADDR 0x07C8UL
+#define HW_HASH_CUR_LEN_0_REG_ADDR 0x07CCUL
+#define HW_HASH_CUR_LEN_1_REG_ADDR 0x07D0UL
+#define HW_HASH_CUR_LEN_2_REG_ADDR 0x07D4UL
+#define HW_HASH_CUR_LEN_3_REG_ADDR 0x07D8UL
+#define HW_HASH_PARAM_REG_ADDR 0x07DCUL
+#define HW_HASH_INT_BUSY_REG_ADDR 0x07E0UL
+#define HW_HASH_SW_RESET_REG_ADDR 0x07E4UL
+#define HW_HASH_ENDIANESS_REG_ADDR 0x07E8UL
+#define HW_HASH_DATA_REG_ADDR 0x07ECUL
+#define HW_DRNG_CONTROL_REG_ADDR 0x0800UL
+#define HW_DRNG_VALID_REG_ADDR 0x0804UL
+#define HW_DRNG_DATA_REG_ADDR 0x0808UL
+#define HW_RND_SRC_EN_REG_ADDR 0x080CUL
+#define HW_AES_CLK_ENABLE_REG_ADDR 0x0810UL
+#define HW_DES_CLK_ENABLE_REG_ADDR 0x0814UL
+#define HW_HASH_CLK_ENABLE_REG_ADDR 0x0818UL
+#define HW_PKI_CLK_ENABLE_REG_ADDR 0x081CUL
+#define HW_CLK_STATUS_REG_ADDR 0x0824UL
+#define HW_CLK_ENABLE_REG_ADDR 0x0828UL
+#define HW_DRNG_SAMPLE_REG_ADDR 0x0850UL
+#define HW_RND_SRC_CTL_REG_ADDR 0x0858UL
+#define HW_CRYPTO_CTL_REG_ADDR 0x0900UL
+#define HW_CRYPTO_STATUS_REG_ADDR 0x090CUL
+#define HW_CRYPTO_BUSY_REG_ADDR 0x0910UL
+#define HW_AES_BUSY_REG_ADDR 0x0914UL
+#define HW_DES_BUSY_REG_ADDR 0x0918UL
+#define HW_HASH_BUSY_REG_ADDR 0x091CUL
+#define HW_CONTENT_REG_ADDR 0x0924UL
+#define HW_VERSION_REG_ADDR 0x0928UL
+#define HW_CONTEXT_ID_REG_ADDR 0x0930UL
+#define HW_DIN_BUFFER_REG_ADDR 0x0C00UL
+#define HW_DIN_MEM_DMA_BUSY_REG_ADDR 0x0c20UL
+#define HW_SRC_LLI_MEM_ADDR_REG_ADDR 0x0c24UL
+#define HW_SRC_LLI_WORD0_REG_ADDR 0x0C28UL
+#define HW_SRC_LLI_WORD1_REG_ADDR 0x0C2CUL
+#define HW_SRAM_SRC_ADDR_REG_ADDR 0x0c30UL
+#define HW_DIN_SRAM_BYTES_LEN_REG_ADDR 0x0c34UL
+#define HW_DIN_SRAM_DMA_BUSY_REG_ADDR 0x0C38UL
+#define HW_WRITE_ALIGN_REG_ADDR 0x0C3CUL
+#define HW_OLD_DATA_REG_ADDR 0x0C48UL
+#define HW_WRITE_ALIGN_LAST_REG_ADDR 0x0C4CUL
+#define HW_DOUT_BUFFER_REG_ADDR 0x0C00UL
+#define HW_DST_LLI_WORD0_REG_ADDR 0x0D28UL
+#define HW_DST_LLI_WORD1_REG_ADDR 0x0D2CUL
+#define HW_DST_LLI_MEM_ADDR_REG_ADDR 0x0D24UL
+#define HW_DOUT_MEM_DMA_BUSY_REG_ADDR 0x0D20UL
+#define HW_SRAM_DEST_ADDR_REG_ADDR 0x0D30UL
+#define HW_DOUT_SRAM_BYTES_LEN_REG_ADDR 0x0D34UL
+#define HW_DOUT_SRAM_DMA_BUSY_REG_ADDR 0x0D38UL
+#define HW_READ_ALIGN_REG_ADDR 0x0D3CUL
+#define HW_READ_LAST_DATA_REG_ADDR 0x0D44UL
+#define HW_RC4_THRU_CPU_REG_ADDR 0x0D4CUL
+#define HW_AHB_SINGLE_REG_ADDR 0x0E00UL
+#define HW_SRAM_DATA_REG_ADDR 0x0F00UL
+#define HW_SRAM_ADDR_REG_ADDR 0x0F04UL
+#define HW_SRAM_DATA_READY_REG_ADDR 0x0F08UL
+#define HW_HOST_IRR_REG_ADDR 0x0A00UL
+#define HW_HOST_IMR_REG_ADDR 0x0A04UL
+#define HW_HOST_ICR_REG_ADDR 0x0A08UL
+#define HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR 0x0A10UL
+#define HW_HOST_SEP_BUSY_REG_ADDR 0x0A14UL
+#define HW_HOST_SEP_LCS_REG_ADDR 0x0A18UL
+#define HW_HOST_CC_SW_RST_REG_ADDR 0x0A40UL
+#define HW_HOST_SEP_SW_RST_REG_ADDR 0x0A44UL
+#define HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR 0x0A80UL
+#define HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR 0x0A84UL
+#define HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR 0x0A88UL
+#define HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR 0x0A8cUL
+#define HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR 0x0A90UL
+#define HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR 0x0A94UL
+#define HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR 0x0A98UL
+#define HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR 0x0A9cUL
+#define HW_HOST_SEP_HOST_GPR0_REG_ADDR 0x0B00UL
+#define HW_HOST_SEP_HOST_GPR1_REG_ADDR 0x0B04UL
+#define HW_HOST_SEP_HOST_GPR2_REG_ADDR 0x0B08UL
+#define HW_HOST_SEP_HOST_GPR3_REG_ADDR 0x0B0CUL
+#define HW_HOST_HOST_SEP_GPR0_REG_ADDR 0x0B80UL
+#define HW_HOST_HOST_SEP_GPR1_REG_ADDR 0x0B84UL
+#define HW_HOST_HOST_SEP_GPR2_REG_ADDR 0x0B88UL
+#define HW_HOST_HOST_SEP_GPR3_REG_ADDR 0x0B8CUL
+#define HW_HOST_HOST_ENDIAN_REG_ADDR 0x0B90UL
+#define HW_HOST_HOST_COMM_CLK_EN_REG_ADDR 0x0B94UL
+#define HW_CLR_SRAM_BUSY_REG_REG_ADDR 0x0F0CUL
+#define HW_CC_SRAM_BASE_ADDRESS 0x5800UL
+
+#endif /* ifndef HW_DEFS */
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 24f47d6388f4..0bc113c44d39 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -996,7 +996,7 @@ failed_free:
/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
-static const struct pci_device_id smtcfb_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
{0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -1071,7 +1071,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
/* when resuming, restore pci data and fb cursor */
if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
retv = pci_set_power_state(pdev, PCI_D0);
- retv = pci_restore_state(pdev);
+ pci_restore_state(pdev);
if (pci_enable_device(pdev))
return -1;
pci_set_master(pdev);
diff --git a/drivers/staging/smbfs/cache.c b/drivers/staging/smbfs/cache.c
index dbb98658148b..f2a1323ca827 100644
--- a/drivers/staging/smbfs/cache.c
+++ b/drivers/staging/smbfs/cache.c
@@ -62,7 +62,7 @@ smb_invalidate_dircache_entries(struct dentry *parent)
struct list_head *next;
struct dentry *dentry;
- spin_lock(&dcache_lock);
+ spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
dentry = list_entry(next, struct dentry, d_u.d_child);
@@ -70,7 +70,7 @@ smb_invalidate_dircache_entries(struct dentry *parent)
smb_age_dentry(server, dentry);
next = next->next;
}
- spin_unlock(&dcache_lock);
+ spin_unlock(&parent->d_lock);
}
/*
@@ -96,13 +96,13 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
}
/* If a pointer is invalid, we search the dentry. */
- spin_lock(&dcache_lock);
+ spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
dent = list_entry(next, struct dentry, d_u.d_child);
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
- dget_locked(dent);
+ dget(dent);
else
dent = NULL;
goto out_unlock;
@@ -111,7 +111,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
}
dent = NULL;
out_unlock:
- spin_unlock(&dcache_lock);
+ spin_unlock(&parent->d_lock);
return dent;
}
@@ -134,7 +134,7 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
qname->hash = full_name_hash(qname->name, qname->len);
if (dentry->d_op && dentry->d_op->d_hash)
- if (dentry->d_op->d_hash(dentry, qname) != 0)
+ if (dentry->d_op->d_hash(dentry, inode, qname) != 0)
goto end_advance;
newdent = d_lookup(dentry, qname);
@@ -145,8 +145,8 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
goto end_advance;
} else {
hashed = 1;
- memcpy((char *) newdent->d_name.name, qname->name,
- newdent->d_name.len);
+ /* dir i_mutex is locked because we're in readdir */
+ dentry_update_name_case(newdent, qname);
}
if (!newdent->d_inode) {
diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c
index f088ea2f6ac9..f204d33910ec 100644
--- a/drivers/staging/smbfs/dir.c
+++ b/drivers/staging/smbfs/dir.c
@@ -14,6 +14,7 @@
#include <linux/ctype.h>
#include <linux/net.h>
#include <linux/sched.h>
+#include <linux/namei.h>
#include "smb_fs.h"
#include "smb_mount.h"
@@ -274,11 +275,15 @@ smb_dir_open(struct inode *dir, struct file *file)
* Dentry operations routines
*/
static int smb_lookup_validate(struct dentry *, struct nameidata *);
-static int smb_hash_dentry(struct dentry *, struct qstr *);
-static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static int smb_delete_dentry(struct dentry *);
-
-static const struct dentry_operations smbfs_dentry_operations =
+static int smb_hash_dentry(const struct dentry *, const struct inode *,
+ struct qstr *);
+static int smb_compare_dentry(const struct dentry *,
+ const struct inode *,
+ const struct dentry *, const struct inode *,
+ unsigned int, const char *, const struct qstr *);
+static int smb_delete_dentry(const struct dentry *);
+
+const struct dentry_operations smbfs_dentry_operations =
{
.d_revalidate = smb_lookup_validate,
.d_hash = smb_hash_dentry,
@@ -286,7 +291,7 @@ static const struct dentry_operations smbfs_dentry_operations =
.d_delete = smb_delete_dentry,
};
-static const struct dentry_operations smbfs_dentry_operations_case =
+const struct dentry_operations smbfs_dentry_operations_case =
{
.d_revalidate = smb_lookup_validate,
.d_delete = smb_delete_dentry,
@@ -297,13 +302,20 @@ static const struct dentry_operations smbfs_dentry_operations_case =
* This is the callback when the dcache has a lookup hit.
*/
static int
-smb_lookup_validate(struct dentry * dentry, struct nameidata *nd)
+smb_lookup_validate(struct dentry *dentry, struct nameidata *nd)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
- struct inode * inode = dentry->d_inode;
- unsigned long age = jiffies - dentry->d_time;
+ struct smb_sb_info *server;
+ struct inode *inode;
+ unsigned long age;
int valid;
+ if (nd->flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ server = server_from_dentry(dentry);
+ inode = dentry->d_inode;
+ age = jiffies - dentry->d_time;
+
/*
* The default validation is based on dentry age:
* we believe in dentries for a few seconds. (But each
@@ -333,7 +345,8 @@ smb_lookup_validate(struct dentry * dentry, struct nameidata *nd)
}
static int
-smb_hash_dentry(struct dentry *dir, struct qstr *this)
+smb_hash_dentry(const struct dentry *dir, const struct inode *inode,
+ struct qstr *this)
{
unsigned long hash;
int i;
@@ -347,14 +360,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this)
}
static int
-smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
+smb_compare_dentry(const struct dentry *parent,
+ const struct inode *pinode,
+ const struct dentry *dentry, const struct inode *inode,
+ unsigned int len, const char *str, const struct qstr *name)
{
int i, result = 1;
- if (a->len != b->len)
+ if (len != name->len)
goto out;
- for (i=0; i < a->len; i++) {
- if (tolower(a->name[i]) != tolower(b->name[i]))
+ for (i=0; i < len; i++) {
+ if (tolower(str[i]) != tolower(name->name[i]))
goto out;
}
result = 0;
@@ -367,7 +383,7 @@ out:
* We use this to unhash dentries with bad inodes.
*/
static int
-smb_delete_dentry(struct dentry * dentry)
+smb_delete_dentry(const struct dentry *dentry)
{
if (dentry->d_inode) {
if (is_bad_inode(dentry->d_inode)) {
@@ -387,12 +403,6 @@ smb_delete_dentry(struct dentry * dentry)
void
smb_new_dentry(struct dentry *dentry)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
-
- if (server->mnt->flags & SMB_MOUNT_CASE)
- dentry->d_op = &smbfs_dentry_operations_case;
- else
- dentry->d_op = &smbfs_dentry_operations;
dentry->d_time = jiffies;
}
@@ -424,7 +434,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
struct smb_fattr finfo;
struct inode *inode;
int error;
- struct smb_sb_info *server;
error = -ENAMETOOLONG;
if (dentry->d_name.len > SMB_MAXNAMELEN)
@@ -452,12 +461,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
inode = smb_iget(dir->i_sb, &finfo);
if (inode) {
add_entry:
- server = server_from_dentry(dentry);
- if (server->mnt->flags & SMB_MOUNT_CASE)
- dentry->d_op = &smbfs_dentry_operations_case;
- else
- dentry->d_op = &smbfs_dentry_operations;
-
d_add(dentry, inode);
smb_renew_times(dentry);
error = 0;
diff --git a/drivers/staging/smbfs/file.c b/drivers/staging/smbfs/file.c
index 5dcd19c60eb9..31372e7b12de 100644
--- a/drivers/staging/smbfs/file.c
+++ b/drivers/staging/smbfs/file.c
@@ -407,11 +407,14 @@ smb_file_release(struct inode *inode, struct file * file)
* privileges, so we need our own check for this.
*/
static int
-smb_file_permission(struct inode *inode, int mask)
+smb_file_permission(struct inode *inode, int mask, unsigned int flags)
{
int mode = inode->i_mode;
int error = 0;
+ if (flags & IPERM_FLAG_RCU)
+ return -ECHILD;
+
VERBOSE("mode=%x, mask=%x\n", mode, mask);
/* Look at user permissions */
diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c
index f9c493591ce7..0778589d9e9e 100644
--- a/drivers/staging/smbfs/inode.c
+++ b/drivers/staging/smbfs/inode.c
@@ -62,11 +62,18 @@ static struct inode *smb_alloc_inode(struct super_block *sb)
return &ei->vfs_inode;
}
-static void smb_destroy_inode(struct inode *inode)
+static void smb_i_callback(struct rcu_head *head)
{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
+ INIT_LIST_HEAD(&inode->i_dentry);
kmem_cache_free(smb_inode_cachep, SMB_I(inode));
}
+static void smb_destroy_inode(struct inode *inode)
+{
+ call_rcu(&inode->i_rcu, smb_i_callback);
+}
+
static void init_once(void *foo)
{
struct smb_inode_info *ei = (struct smb_inode_info *) foo;
@@ -537,7 +544,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
server->mnt = NULL;
server->sock_file = NULL;
init_waitqueue_head(&server->conn_wq);
- init_MUTEX(&server->sem);
+ sema_init(&server->sem, 1);
INIT_LIST_HEAD(&server->entry);
INIT_LIST_HEAD(&server->xmitq);
INIT_LIST_HEAD(&server->recvq);
@@ -607,6 +614,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
printk(KERN_ERR "smbfs: failed to start smbiod\n");
goto out_no_smbiod;
}
+ if (server->mnt->flags & SMB_MOUNT_CASE)
+ sb->s_d_op = &smbfs_dentry_operations_case;
+ else
+ sb->s_d_op = &smbfs_dentry_operations;
/*
* Keep the super block locked while we get the root inode.
diff --git a/drivers/staging/smbfs/proto.h b/drivers/staging/smbfs/proto.h
index 05939a6f43e6..3883cb16a3f6 100644
--- a/drivers/staging/smbfs/proto.h
+++ b/drivers/staging/smbfs/proto.h
@@ -38,6 +38,8 @@ extern void smb_install_null_ops(struct smb_ops *ops);
extern const struct file_operations smb_dir_operations;
extern const struct inode_operations smb_dir_inode_operations;
extern const struct inode_operations smb_dir_inode_operations_unix;
+extern const struct dentry_operations smbfs_dentry_operations_case;
+extern const struct dentry_operations smbfs_dentry_operations;
extern void smb_new_dentry(struct dentry *dentry);
extern void smb_renew_times(struct dentry *dentry);
/* cache.c */
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig
index d96398c701f8..2cf77c940860 100644
--- a/drivers/staging/solo6x10/Kconfig
+++ b/drivers/staging/solo6x10/Kconfig
@@ -1,7 +1,7 @@
config SOLO6X10
tristate "Softlogic 6x10 MPEG codec cards"
- depends on PCI && VIDEO_DEV && SND
- select VIDEOBUF_DMA_CONTIG
+ depends on PCI && VIDEO_DEV && SND && I2C
+ select VIDEOBUF_DMA_SG
---help---
This driver supports the Softlogic based MPEG-4 and h.264 codec
codec cards.
diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO
index e6a2ee226743..7e6c4fa130df 100644
--- a/drivers/staging/solo6x10/TODO
+++ b/drivers/staging/solo6x10/TODO
@@ -1,7 +1,5 @@
TODO (staging => main):
- * checkpatch.pl (haven't run it yet)
- * Lindent (should be clean, but check)
* Motion detection flags need to be moved to v4l2
* Some private CIDs need to be moved to v4l2
@@ -21,8 +19,6 @@ TODO (general):
- implement playback via external sound jack
- implement loopback of external sound jack with incoming audio?
- implement pause/resume
- - check into jacking sound from tx28xx chips directly (to avoid
- g.723/8khz limitations)
Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
<bcollins@bluecherry.net>
diff --git a/drivers/staging/solo6x10/solo6010-core.c b/drivers/staging/solo6x10/solo6010-core.c
index 4a051cde55da..c433136f972c 100644
--- a/drivers/staging/solo6x10/solo6010-core.c
+++ b/drivers/staging/solo6x10/solo6010-core.c
@@ -136,6 +136,7 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
int ret;
int sdram;
u8 chip_id;
+
solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
if (solo_dev == NULL)
return -ENOMEM;
@@ -163,21 +164,21 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
SOLO_CHIP_ID_MASK;
switch (chip_id) {
- case 7:
- solo_dev->nr_chans = 16;
- solo_dev->nr_ext = 5;
- break;
- case 6:
- solo_dev->nr_chans = 8;
- solo_dev->nr_ext = 2;
- break;
- default:
- dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
- "defaulting to 4 channels\n",
- chip_id);
- case 5:
- solo_dev->nr_chans = 4;
- solo_dev->nr_ext = 1;
+ case 7:
+ solo_dev->nr_chans = 16;
+ solo_dev->nr_ext = 5;
+ break;
+ case 6:
+ solo_dev->nr_chans = 8;
+ solo_dev->nr_ext = 2;
+ break;
+ default:
+ dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
+ "defaulting to 4 channels\n",
+ chip_id);
+ case 5:
+ solo_dev->nr_chans = 4;
+ solo_dev->nr_ext = 1;
}
/* Disable all interrupts to start */
@@ -261,13 +262,18 @@ static void __devexit solo6010_pci_remove(struct pci_dev *pdev)
}
static struct pci_device_id solo6010_id_table[] = {
+ /* 6010 based cards */
{PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)},
+ /* 6110 based cards */
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)},
{0,}
};
diff --git a/drivers/staging/solo6x10/solo6010-disp.c b/drivers/staging/solo6x10/solo6010-disp.c
index 555f024f72e7..f866f8438175 100644
--- a/drivers/staging/solo6x10/solo6010-disp.c
+++ b/drivers/staging/solo6x10/solo6010-disp.c
@@ -198,12 +198,12 @@ static void solo_motion_config(struct solo6010_dev *solo_dev)
}
/* Default motion settings */
- solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
+ solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
(SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
SOLO_VI_MOTION_FRAME_COUNT(3) |
SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
- | //SOLO_VI_MOTION_INTR_START_STOP |
+ | /* SOLO_VI_MOTION_INTR_START_STOP | */
SOLO_VI_MOTION_SAMPLE_COUNT(10));
solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
@@ -264,7 +264,7 @@ void solo_disp_exit(struct solo6010_dev *solo_dev)
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
-
+
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
diff --git a/drivers/staging/solo6x10/solo6010-enc.c b/drivers/staging/solo6x10/solo6010-enc.c
index a6cf0a8a3f20..481a49277f77 100644
--- a/drivers/staging/solo6x10/solo6010-enc.c
+++ b/drivers/staging/solo6x10/solo6010-enc.c
@@ -22,7 +22,7 @@
#include "solo6010.h"
#include "solo6010-osd-font.h"
-#define CAPTURE_MAX_BANDWIDTH 32 // D1 4channel (D1 == 4)
+#define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */
#define OSG_BUFFER_SIZE 1024
#define VI_PROG_HSIZE (1280 - 16)
@@ -145,8 +145,8 @@ int solo_osd_print(struct solo_enc_dev *solo_enc)
solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) +
(solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
- reg |= (1 << solo_enc->ch);
- solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+ reg |= (1 << solo_enc->ch);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
kfree(buf);
diff --git a/drivers/staging/solo6x10/solo6010-g723.c b/drivers/staging/solo6x10/solo6010-g723.c
index 82fbcb845878..254b46ab20c5 100644
--- a/drivers/staging/solo6x10/solo6010-g723.c
+++ b/drivers/staging/solo6x10/solo6010-g723.c
@@ -47,7 +47,7 @@
* is broken down to 20 * 48 byte regions (one for each channel possible)
* with the rest of the page being dummy data. */
#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
-#define IRQ_PAGES 4 // 0 - 4
+#define IRQ_PAGES 4 /* 0 - 4 */
#define PERIODS_MIN (1 << IRQ_PAGES)
#define PERIODS_MAX G723_FDMA_PAGES
@@ -158,7 +158,7 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
kfree(solo_pcm);
- return 0;
+ return 0;
}
static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
@@ -197,7 +197,7 @@ static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
{
- return 0;
+ return 0;
}
static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
@@ -271,7 +271,7 @@ static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
- return 0;
+ return 0;
}
static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
@@ -279,15 +279,15 @@ static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
{
struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol);
u8 ch = value->id.numid - 1;
- u8 old_val;
+ u8 old_val;
- old_val = tw28_get_audio_gain(solo_dev, ch);
+ old_val = tw28_get_audio_gain(solo_dev, ch);
if (old_val == value->value.integer.value[0])
return 0;
tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
- return 1;
+ return 1;
}
static struct snd_kcontrol_new snd_solo_capture_volume = {
@@ -368,14 +368,16 @@ int solo_g723_init(struct solo6010_dev *solo_dev)
strcpy(card->mixername, "SOLO-6010");
kctl = snd_solo_capture_volume;
kctl.count = solo_dev->nr_chans;
- ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
+ ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
if (ret < 0)
return ret;
- if ((ret = solo_snd_pcm_init(solo_dev)) < 0)
+ ret = solo_snd_pcm_init(solo_dev);
+ if (ret < 0)
goto snd_error;
- if ((ret = snd_card_register(card)) < 0)
+ ret = snd_card_register(card);
+ if (ret < 0)
goto snd_error;
solo_g723_config(solo_dev);
diff --git a/drivers/staging/solo6x10/solo6010-gpio.c b/drivers/staging/solo6x10/solo6010-gpio.c
index 46f7a71edabc..8869b88dc307 100644
--- a/drivers/staging/solo6x10/solo6010-gpio.c
+++ b/drivers/staging/solo6x10/solo6010-gpio.c
@@ -92,8 +92,8 @@ static void solo_gpio_config(struct solo6010_dev *solo_dev)
int solo_gpio_init(struct solo6010_dev *solo_dev)
{
- solo_gpio_config(solo_dev);
- return 0;
+ solo_gpio_config(solo_dev);
+ return 0;
}
void solo_gpio_exit(struct solo6010_dev *solo_dev)
diff --git a/drivers/staging/solo6x10/solo6010-i2c.c b/drivers/staging/solo6x10/solo6010-i2c.c
index cadd5120d575..60b69cd0d09d 100644
--- a/drivers/staging/solo6x10/solo6010-i2c.c
+++ b/drivers/staging/solo6x10/solo6010-i2c.c
@@ -46,7 +46,7 @@ u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off)
i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
- return data;
+ return data;
}
void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr,
@@ -225,9 +225,9 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap,
}
if (i == SOLO_I2C_ADAPTERS)
- return num; // XXX Right return value for failure?
+ return num; /* XXX Right return value for failure? */
- down(&solo_dev->i2c_sem);
+ mutex_lock(&solo_dev->i2c_mutex);
solo_dev->i2c_id = i;
solo_dev->i2c_msg = msgs;
solo_dev->i2c_msg_num = num;
@@ -258,7 +258,7 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap,
solo_dev->i2c_state = IIC_STATE_IDLE;
solo_dev->i2c_id = -1;
- up(&solo_dev->i2c_sem);
+ mutex_unlock(&solo_dev->i2c_mutex);
return ret;
}
@@ -284,7 +284,7 @@ int solo_i2c_init(struct solo6010_dev *solo_dev)
solo_dev->i2c_id = -1;
solo_dev->i2c_state = IIC_STATE_IDLE;
init_waitqueue_head(&solo_dev->i2c_wait);
- sema_init(&solo_dev->i2c_sem, 1);
+ mutex_init(&solo_dev->i2c_mutex);
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
@@ -296,7 +296,8 @@ int solo_i2c_init(struct solo6010_dev *solo_dev)
adap->retries = 1;
adap->dev.parent = &solo_dev->pdev->dev;
- if ((ret = i2c_add_adapter(adap))) {
+ ret = i2c_add_adapter(adap);
+ if (ret) {
adap->algo_data = NULL;
break;
}
diff --git a/drivers/staging/solo6x10/solo6010-osd-font.h b/drivers/staging/solo6x10/solo6010-osd-font.h
index d6f565bd76cc..d72efbb3bb3d 100644
--- a/drivers/staging/solo6x10/solo6010-osd-font.h
+++ b/drivers/staging/solo6x10/solo6010-osd-font.h
@@ -22,7 +22,7 @@
static const unsigned int solo_osd_font[] = {
0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
- 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, // 0
+ 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */
0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
0x00000000, 0x00001038, 0x10000000, 0x00000000,
@@ -54,67 +54,67 @@ static const unsigned int solo_osd_font[] = {
0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, // 32 !
+ 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32 ! */
0x00000066, 0x66240000, 0x00000000, 0x00000000,
- 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, // 34 " #
+ 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */
0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
- 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, // 36 $ %
+ 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */
0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
- 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, // 38 & '
+ 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */
0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
- 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, // 40 ( )
+ 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */
0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
- 0x00000000, 0x00001818, 0x7e181800, 0x00000000, // 42 * +
+ 0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */
0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
- 0x00000000, 0x00000000, 0x7e000000, 0x00000000, // 44 , -
+ 0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */
0x00000000, 0x00000000, 0x00000006, 0x06000000,
- 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, // 46 . /
+ 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */
0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
- 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, // 48 0 1
+ 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */
0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
- 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, // 50 2 3
+ 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */
0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
- 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, // 52 4 5
+ 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */
0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
- 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, // 54 6 7
+ 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */
0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
- 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, // 56 8 9
+ 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */
0x00000000, 0x18180000, 0x00181800, 0x00000000,
- 0x00000000, 0x18180000, 0x0018180c, 0x00000000, // 58 : ;
+ 0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */
0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
- 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, // 64 @ A
+ 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */
0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
- 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, // 66
+ 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */
0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
- 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, // 68
+ 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */
0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
- 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, // 70
+ 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */
0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
- 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, // 72
+ 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */
0x00000060, 0x60606060, 0x6066663c, 0x00000000,
- 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, // 74
+ 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */
0x00000006, 0x06060606, 0x060606fe, 0x00000000,
- 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, // 76
+ 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */
0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
- 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, // 78
+ 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */
0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
- 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, // 80
+ 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */
0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
- 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, // 82
+ 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */
0x0000007e, 0x18181818, 0x18181818, 0x00000000,
- 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, // 84
+ 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */
0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
- 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, // 86
+ 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */
0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
- 0x00000066, 0x66666666, 0x3c181818, 0x00000000, // 88
+ 0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */
0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
- 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, // 90
+ 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */
0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
- 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, // 92
+ 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */
0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
0x00001818, 0x30000000, 0x00000000, 0x00000000,
diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c
index 7ed3ed4b8f7e..956dea09348a 100644
--- a/drivers/staging/solo6x10/solo6010-p2m.c
+++ b/drivers/staging/solo6x10/solo6010-p2m.c
@@ -18,10 +18,11 @@
*/
#include <linux/kernel.h>
+#include <linux/scatterlist.h>
#include "solo6010.h"
-// #define SOLO_TEST_P2M
+/* #define SOLO_TEST_P2M */
int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
void *sys_addr, u32 ext_addr, u32 size)
@@ -30,8 +31,9 @@ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
int ret;
WARN_ON(!size);
- WARN_ON(id >= SOLO_NR_P2M);
- if (!size || id >= SOLO_NR_P2M)
+ BUG_ON(id >= SOLO_NR_P2M);
+
+ if (!size)
return -EINVAL;
dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
@@ -48,41 +50,136 @@ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
dma_addr_t dma_addr, u32 ext_addr, u32 size)
{
+ struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
+ int ret;
+
+ if (desc == NULL)
+ return -ENOMEM;
+
+ solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
+ ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
+ kfree(desc);
+
+ return ret;
+}
+
+void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
+ u32 ext_addr, u32 size, int repeat, u32 ext_size)
+{
+ desc->ta = dma_addr;
+ desc->fa = ext_addr;
+
+ desc->ext = SOLO_P2M_COPY_SIZE(size >> 2);
+ desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
+ (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON;
+
+ /* Ext size only matters when we're repeating */
+ if (repeat) {
+ desc->ext |= SOLO_P2M_EXT_INC(ext_size >> 2);
+ desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) |
+ SOLO_P2M_REPEAT(repeat);
+ }
+}
+
+int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, u8 id,
+ struct p2m_desc *desc, int desc_count)
+{
struct solo_p2m_dev *p2m_dev;
- unsigned int timeout = 0;
+ unsigned int timeout;
+ int ret = 0;
+ u32 config = 0;
+ dma_addr_t desc_dma = 0;
- WARN_ON(!size);
- WARN_ON(id >= SOLO_NR_P2M);
- if (!size || id >= SOLO_NR_P2M)
- return -EINVAL;
+ BUG_ON(id >= SOLO_NR_P2M);
+ BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
p2m_dev = &solo_dev->p2m_dev[id];
- down(&p2m_dev->sem);
+ mutex_lock(&p2m_dev->mutex);
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-start_dma:
INIT_COMPLETION(p2m_dev->completion);
p2m_dev->error = 0;
- solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr);
- solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr);
- solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id),
- SOLO_P2M_COPY_SIZE(size >> 2));
- solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id),
- SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
- (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
+ /* Enable the descriptors */
+ config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
+ desc_dma = pci_map_single(solo_dev->pdev, desc,
+ desc_count * sizeof(*desc),
+ PCI_DMA_TODEVICE);
+ solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
+ solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
+ SOLO_P2M_DESC_MODE);
+
+ /* Should have all descriptors completed from one interrupt */
timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
- /* XXX Really looks to me like we will get stuck here if a
- * real PCI P2M error occurs */
+ /* Reset back to non-descriptor mode */
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
+ solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
+ solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
+ pci_unmap_single(solo_dev->pdev, desc_dma,
+ desc_count * sizeof(*desc),
+ PCI_DMA_TODEVICE);
+
if (p2m_dev->error)
- goto start_dma;
+ ret = -EIO;
+ else if (timeout == 0)
+ ret = -EAGAIN;
+
+ mutex_unlock(&p2m_dev->mutex);
+
+ WARN_ON_ONCE(ret);
- up(&p2m_dev->sem);
+ return ret;
+}
+
+int solo_p2m_dma_sg(struct solo6010_dev *solo_dev, u8 id,
+ struct p2m_desc *pdesc, int wr,
+ struct scatterlist *sg, u32 sg_off,
+ u32 ext_addr, u32 size)
+{
+ int i;
+ int idx;
+
+ BUG_ON(id >= SOLO_NR_P2M);
+
+ if (WARN_ON_ONCE(!size))
+ return -EINVAL;
+
+ memset(pdesc, 0, sizeof(*pdesc));
+
+ /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
+ for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
+ i++, sg = sg_next(sg)) {
+ struct p2m_desc *desc = &pdesc[idx];
+ u32 sg_len = sg_dma_len(sg);
+ u32 len;
- return (timeout == 0) ? -EAGAIN : 0;
+ if (sg_off >= sg_len) {
+ sg_off -= sg_len;
+ continue;
+ }
+
+ sg_len -= sg_off;
+ len = min(sg_len, size);
+
+ solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
+ ext_addr, len, 0, 0);
+
+ size -= len;
+ ext_addr += len;
+ idx++;
+
+ sg_off = 0;
+ }
+
+ WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
+
+ return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
}
#ifdef SOLO_TEST_P2M
@@ -147,13 +244,16 @@ static void run_p2m_test(struct solo6010_dev *solo_dev)
return;
}
#else
-#define run_p2m_test(__solo) do{}while(0)
+#define run_p2m_test(__solo) do {} while (0)
#endif
void solo_p2m_isr(struct solo6010_dev *solo_dev, int id)
{
+ struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
+
solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
- complete(&solo_dev->p2m_dev[id].completion);
+
+ complete(&p2m_dev->completion);
}
void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status)
@@ -188,16 +288,14 @@ int solo_p2m_init(struct solo6010_dev *solo_dev)
for (i = 0; i < SOLO_NR_P2M; i++) {
p2m_dev = &solo_dev->p2m_dev[i];
- sema_init(&p2m_dev->sem, 1);
+ mutex_init(&p2m_dev->mutex);
init_completion(&p2m_dev->completion);
- solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i),
- __pa(p2m_dev->desc));
-
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
SOLO_P2M_CSC_16BIT_565 |
- SOLO_P2M_DMA_INTERVAL(0) |
+ SOLO_P2M_DMA_INTERVAL(3) |
+ SOLO_P2M_DESC_INTR_OPT |
SOLO_P2M_PCI_MASTER_MODE);
solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i));
}
diff --git a/drivers/staging/solo6x10/solo6010-tw28.c b/drivers/staging/solo6x10/solo6010-tw28.c
index 0159c8392436..905a6ad23a37 100644
--- a/drivers/staging/solo6x10/solo6010-tw28.c
+++ b/drivers/staging/solo6x10/solo6010-tw28.c
@@ -35,107 +35,107 @@
#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
static u8 tbl_tw2864_template[] = {
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x00
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x10
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x20
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x30
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
- 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
- 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, // 0x90
+ 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
- 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, // 0xa0
+ 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
- 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, // 0xb0
+ 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
- 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, // 0xd0
+ 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
- 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
- 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
+ 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
};
static u8 tbl_tw2865_ntsc_template[] = {
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x00
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x10
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x20
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, // 0x30
+ 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, // 0x40
+ 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
- 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
- 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
- 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
- 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, // 0xa0
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
- 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
- 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
- 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
- 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
- 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
+ 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
};
static u8 tbl_tw2865_pal_template[] = {
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x00
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x10
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x20
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
- 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x30
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
- 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, // 0x40
+ 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
- 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
- 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
- 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
- 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, // 0xa0
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
- 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
- 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
- 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
- 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
- 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, // 0xf0
+ 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
};
@@ -181,8 +181,8 @@ static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off,
msleep_interruptible(1);
}
-// printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
-// addr, off, val);
+/* printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
+ addr, off, val); */
}
static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
@@ -217,7 +217,7 @@ static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
for (i = 0; i < 0xff; i++) {
/* Skip read only registers */
- if (i >= 0xb8 && i <= 0xc1 )
+ if (i >= 0xb8 && i <= 0xc1)
continue;
if ((i & ~0x30) == 0x00 ||
(i & ~0x30) == 0x0c ||
@@ -302,7 +302,7 @@ static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
for (i = 0; i < 0xff; i++) {
/* Skip read only registers */
- if (i >= 0xb8 && i <= 0xc1 )
+ if (i >= 0xb8 && i <= 0xc1)
continue;
if ((i & ~0x30) == 0x00 ||
(i & ~0x30) == 0x0c ||
@@ -334,13 +334,13 @@ static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
};
u8 tbl_tw2815_sfr[] = {
- 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, // 0x00
+ 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, // 0x10
+ 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
- 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, // 0x20
+ 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
- 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, // 0x30
+ 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */
};
u8 *tbl_tw2815_common;
int i;
@@ -459,7 +459,7 @@ static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
for (i = 0; i < 0x0f; i++) {
if (i == 0x00)
- continue; // read-only
+ continue; /* read-only */
solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
dev_addr, (ch * 0x10) + i,
tbl_tw2815_common[i]);
@@ -597,7 +597,7 @@ int solo_tw28_init(struct solo6010_dev *solo_dev)
return 0;
}
-/*
+/*
* We accessed the video status signal in the Techwell chip through
* iic/i2c because the video status reported by register REG_VI_STATUS1
* (address 0x012C) of the SOLO6010 chip doesn't give the correct video
@@ -751,7 +751,7 @@ int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
rval = tw_readbyte(solo_dev, chip_num,
TW286x_BRIGHTNESS_ADDR(ch),
TW_BRIGHTNESS_ADDR(ch));
- if (is_tw286x(solo_dev, chip_num))
+ if (is_tw286x(solo_dev, chip_num))
*val = (s32)((char)rval) + 128;
else
*val = rval;
diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
index bbf3d9c4abb0..7bbb94097d29 100644
--- a/drivers/staging/solo6x10/solo6010-v4l2-enc.c
+++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
@@ -24,7 +24,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
#include "solo6010.h"
#include "solo6010-tw28.h"
@@ -47,13 +47,14 @@ struct solo_enc_fh {
struct videobuf_queue vidq;
struct list_head vidq_active;
struct task_struct *kthread;
+ struct p2m_desc desc[SOLO_NR_P2M_DESC];
};
static unsigned char vid_vop_header[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
0x02, 0x48, 0x05, 0xc0, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
- 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3e,
+ 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3f,
};
/*
@@ -151,6 +152,11 @@ static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
else
solo_dev->motion_mask &= ~(1 << ch);
+ /* Do this regardless of if we are turning on or off */
+ solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
+ 1 << solo_enc->ch);
+ solo_enc->motion_detected = 0;
+
solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
(SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
@@ -184,7 +190,7 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc)
solo_enc->bw_weight <<= 2;
break;
default:
- WARN(1, "mode is unknown");
+ WARN(1, "mode is unknown\n");
}
}
@@ -211,11 +217,6 @@ static int solo_enc_on(struct solo_enc_fh *fh)
solo_dev->enc_bw_remain -= solo_enc->bw_weight;
}
- fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc");
-
- if (IS_ERR(fh->kthread))
- return PTR_ERR(fh->kthread);
-
fh->enc_on = 1;
fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
@@ -279,6 +280,24 @@ static void solo_enc_off(struct solo_enc_fh *fh)
solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
}
+static int solo_start_fh_thread(struct solo_enc_fh *fh)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+
+ fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc");
+
+ /* Oops, we had a problem */
+ if (IS_ERR(fh->kthread)) {
+ spin_lock(&solo_enc->lock);
+ solo_enc_off(fh);
+ spin_unlock(&solo_enc->lock);
+
+ return PTR_ERR(fh->kthread);
+ }
+
+ return 0;
+}
+
static void enc_reset_gop(struct solo6010_dev *solo_dev, u8 ch)
{
BUG_ON(ch >= solo_dev->nr_chans);
@@ -299,22 +318,68 @@ static int enc_gop_reset(struct solo6010_dev *solo_dev, u8 ch, u8 vop)
return 0;
}
-static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev, dma_addr_t buf,
- unsigned int off, unsigned int size)
+static void enc_write_sg(struct scatterlist *sglist, void *buf, int size)
+{
+ struct scatterlist *sg;
+ u8 *src = buf;
+
+ for (sg = sglist; sg && size > 0; sg = sg_next(sg)) {
+ u8 *p = sg_virt(sg);
+ size_t len = sg_dma_len(sg);
+ int i;
+
+ for (i = 0; i < len && size; i++)
+ p[i] = *(src++);
+ }
+}
+
+static int enc_get_mpeg_dma_sg(struct solo6010_dev *solo_dev,
+ struct p2m_desc *desc,
+ struct scatterlist *sglist, int skip,
+ unsigned int off, unsigned int size)
{
int ret;
if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
return -EINVAL;
- if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev))
+ if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
+ return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E,
+ desc, 0, sglist, skip,
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
+ }
+
+ /* Buffer wrap */
+ ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
+ sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+ SOLO_MP4E_EXT_SIZE(solo_dev) - off);
+
+ ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
+ sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+ SOLO_MP4E_EXT_ADDR(solo_dev),
+ size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
+
+ return ret;
+}
+
+static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev,
+ dma_addr_t buf, unsigned int off,
+ unsigned int size)
+{
+ int ret;
+
+ if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+ return -EINVAL;
+
+ if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
+ }
/* Buffer wrap */
ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
- SOLO_MP4E_EXT_ADDR(solo_dev) + off,
- SOLO_MP4E_EXT_SIZE(solo_dev) - off);
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+ SOLO_MP4E_EXT_SIZE(solo_dev) - off);
ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
@@ -337,70 +402,108 @@ static int enc_get_mpeg_dma(struct solo6010_dev *solo_dev, void *buf,
return ret;
}
-static int enc_get_jpeg_dma(struct solo6010_dev *solo_dev, dma_addr_t buf,
- unsigned int off, unsigned int size)
+static int enc_get_jpeg_dma_sg(struct solo6010_dev *solo_dev,
+ struct p2m_desc *desc,
+ struct scatterlist *sglist, int skip,
+ unsigned int off, unsigned int size)
{
int ret;
if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
return -EINVAL;
- if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev))
- return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
- SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
+ if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) {
+ return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG,
+ desc, 0, sglist, skip,
+ SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
+ }
/* Buffer wrap */
- ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
- SOLO_JPEG_EXT_ADDR(solo_dev) + off,
- SOLO_JPEG_EXT_SIZE(solo_dev) - off);
+ ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
+ sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off,
+ SOLO_JPEG_EXT_SIZE(solo_dev) - off);
- ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0,
- buf + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
- SOLO_JPEG_EXT_ADDR(solo_dev),
- size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
+ ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
+ sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
+ SOLO_JPEG_EXT_ADDR(solo_dev),
+ size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
return ret;
}
+/* Returns true of __chk is within the first __range bytes of __off */
+#define OFF_IN_RANGE(__off, __range, __chk) \
+ ((__off <= __chk) && ((__off + __range) >= __chk))
+
+static void solo_jpeg_header(struct solo_enc_dev *solo_enc,
+ struct videobuf_dmabuf *vbuf)
+{
+ struct scatterlist *sg;
+ void *src = jpeg_header;
+ size_t copied = 0;
+ size_t to_copy = sizeof(jpeg_header);
+
+ for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) {
+ size_t this_copy = min(sg_dma_len(sg),
+ (unsigned int)(to_copy - copied));
+ u8 *p = sg_virt(sg);
+
+ memcpy(p, src + copied, this_copy);
+
+ if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5))
+ p[(SOF0_START + 5) - copied] =
+ 0xff & (solo_enc->height >> 8);
+ if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6))
+ p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height;
+ if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7))
+ p[(SOF0_START + 7) - copied] =
+ 0xff & (solo_enc->width >> 8);
+ if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8))
+ p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width;
+
+ copied += this_copy;
+ }
+}
+
static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
- struct videobuf_buffer *vb, dma_addr_t vbuf)
+ struct videobuf_buffer *vb,
+ struct videobuf_dmabuf *vbuf)
{
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo6010_dev *solo_dev = solo_enc->solo_dev;
- u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+ struct solo6010_dev *solo_dev = fh->enc->solo_dev;
+ int size = enc_buf->jpeg_size;
- memcpy(p, jpeg_header, sizeof(jpeg_header));
- p[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
- p[SOF0_START + 6] = 0xff & solo_enc->height;
- p[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
- p[SOF0_START + 8] = 0xff & solo_enc->width;
+ /* Copy the header first (direct write) */
+ solo_jpeg_header(fh->enc, vbuf);
- vbuf += sizeof(jpeg_header);
- vb->size = enc_buf->jpeg_size + sizeof(jpeg_header);
+ vb->size = size + sizeof(jpeg_header);
- return enc_get_jpeg_dma(solo_dev, vbuf, enc_buf->jpeg_off,
- enc_buf->jpeg_size);
+ /* Grab the jpeg frame */
+ return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
+ sizeof(jpeg_header),
+ enc_buf->jpeg_off, size);
}
static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
- struct videobuf_buffer *vb, dma_addr_t vbuf)
+ struct videobuf_buffer *vb,
+ struct videobuf_dmabuf *vbuf)
{
struct solo_enc_dev *solo_enc = fh->enc;
struct solo6010_dev *solo_dev = solo_enc->solo_dev;
struct vop_header vh;
int ret;
int frame_size, frame_off;
+ int skip = 0;
if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
- return -1;
+ return -EINVAL;
/* First get the hardware vop header (not real mpeg) */
ret = enc_get_mpeg_dma(solo_dev, &vh, enc_buf->off, sizeof(vh));
- if (ret)
- return -1;
+ if (WARN_ON_ONCE(ret))
+ return ret;
if (WARN_ON_ONCE(vh.size > enc_buf->size))
- return -1;
+ return -EINVAL;
vb->width = vh.hsize << 4;
vb->height = vh.vsize << 4;
@@ -410,9 +513,9 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
if (!enc_buf->vop) {
u16 fps = solo_dev->fps * 1000;
u16 interval = solo_enc->interval * 1000;
- u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+ u8 p[sizeof(vid_vop_header)];
- memcpy(p, vid_vop_header, sizeof(vid_vop_header));
+ memcpy(p, vid_vop_header, sizeof(p));
if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
p[10] |= ((XVID_PAR_43_NTSC << 3) & 0x78);
@@ -434,43 +537,49 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
if (vh.interlace)
p[29] |= 0x20;
+ enc_write_sg(vbuf->sglist, p, sizeof(p));
+
/* Adjust the dma buffer past this header */
vb->size += sizeof(vid_vop_header);
- vbuf += sizeof(vid_vop_header);
+ skip = sizeof(vid_vop_header);
}
/* Now get the actual mpeg payload */
frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
frame_size = enc_buf->size - sizeof(vh);
- ret = enc_get_mpeg_dma_t(solo_dev, vbuf, frame_off, frame_size);
- if (WARN_ON_ONCE(ret))
- return -1;
- return 0;
+ ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
+ skip, frame_off, frame_size);
+ WARN_ON_ONCE(ret);
+
+ return ret;
}
-/* On successful return (0), leaves solo_enc->lock unlocked */
-static int solo_enc_fillbuf(struct solo_enc_fh *fh,
+static void solo_enc_fillbuf(struct solo_enc_fh *fh,
struct videobuf_buffer *vb)
{
struct solo_enc_dev *solo_enc = fh->enc;
struct solo6010_dev *solo_dev = solo_enc->solo_dev;
struct solo_enc_buf *enc_buf = NULL;
- dma_addr_t vbuf;
+ struct videobuf_dmabuf *vbuf;
int ret;
+ int error = 1;
u16 idx = fh->rd_idx;
while (idx != solo_dev->enc_wr_idx) {
struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
+
idx = (idx + 1) % SOLO_NR_RING_BUFS;
+
+ if (ebuf->ch != solo_enc->ch)
+ continue;
+
if (fh->fmt == V4L2_PIX_FMT_MPEG) {
- if (fh->type != ebuf->type)
- continue;
- if (ebuf->ch == solo_enc->ch) {
+ if (fh->type == ebuf->type) {
enc_buf = ebuf;
break;
}
- } else if (ebuf->ch == solo_enc->ch) {
+ } else {
/* For mjpeg, keep reading to the newest frame */
enc_buf = ebuf;
}
@@ -478,48 +587,55 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh,
fh->rd_idx = idx;
- if (!enc_buf)
- return -1;
+ if (WARN_ON_ONCE(!enc_buf))
+ goto buf_err;
if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
vb->bsize < enc_buf->size) ||
(fh->fmt == V4L2_PIX_FMT_MJPEG &&
vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
- return -1;
+ WARN_ON_ONCE(1);
+ goto buf_err;
}
- if (!(vbuf = videobuf_to_dma_contig(vb)))
- return -1;
-
- /* Is it ok that we mess with this buffer out of lock? */
- spin_unlock(&solo_enc->lock);
+ vbuf = videobuf_to_dma(vb);
+ if (WARN_ON_ONCE(!vbuf))
+ goto buf_err;
if (fh->fmt == V4L2_PIX_FMT_MPEG)
ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
else
ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
- if (ret) // Ignore failures
- return 0;
+ if (!ret)
+ error = 0;
- list_del(&vb->queue);
- vb->field_count++;
- vb->ts = enc_buf->ts;
- vb->state = VIDEOBUF_DONE;
+buf_err:
+ if (error) {
+ vb->state = VIDEOBUF_ERROR;
+ } else {
+ vb->field_count++;
+ vb->ts = enc_buf->ts;
+ vb->state = VIDEOBUF_DONE;
+ }
wake_up(&vb->done);
- return 0;
+ return;
}
static void solo_enc_thread_try(struct solo_enc_fh *fh)
{
struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
struct videobuf_buffer *vb;
for (;;) {
spin_lock(&solo_enc->lock);
+ if (fh->rd_idx == solo_dev->enc_wr_idx)
+ break;
+
if (list_empty(&fh->vidq_active))
break;
@@ -529,9 +645,11 @@ static void solo_enc_thread_try(struct solo_enc_fh *fh)
if (!waitqueue_active(&vb->done))
break;
- /* On success, returns with solo_enc->lock unlocked */
- if (solo_enc_fillbuf(fh, vb))
- break;
+ list_del(&vb->queue);
+
+ spin_unlock(&solo_enc->lock);
+
+ solo_enc_fillbuf(fh, vb);
}
assert_spin_locked(&solo_enc->lock);
@@ -557,7 +675,7 @@ static int solo_enc_thread(void *data)
remove_wait_queue(&solo_enc->thread_wait, &wait);
- return 0;
+ return 0;
}
void solo_motion_isr(struct solo6010_dev *solo_dev)
@@ -614,7 +732,8 @@ void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev)
jpeg_next = solo_reg_read(solo_dev,
SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
- if ((ch = (mpeg_current >> 24) & 0x1f) >= SOLO_MAX_CHANNELS) {
+ ch = (mpeg_current >> 24) & 0x1f;
+ if (ch >= SOLO_MAX_CHANNELS) {
ch -= SOLO_MAX_CHANNELS;
enc_type = SOLO_ENC_TYPE_EXT;
} else
@@ -669,12 +788,12 @@ void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev)
static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
- *size = FRAME_BUF_SIZE;
+ *size = FRAME_BUF_SIZE;
- if (*count < MIN_VID_BUFFERS)
+ if (*count < MIN_VID_BUFFERS)
*count = MIN_VID_BUFFERS;
- return 0;
+ return 0;
}
static int solo_enc_buf_prepare(struct videobuf_queue *vq,
@@ -696,7 +815,9 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq,
if (vb->state == VIDEOBUF_NEEDS_INIT) {
int rc = videobuf_iolock(vq, vb, NULL);
if (rc < 0) {
- videobuf_dma_contig_free(vq, vb);
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ videobuf_dma_unmap(vq->dev, dma);
+ videobuf_dma_free(dma);
vb->state = VIDEOBUF_NEEDS_INIT;
return rc;
}
@@ -719,7 +840,10 @@ static void solo_enc_buf_queue(struct videobuf_queue *vq,
static void solo_enc_buf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
- videobuf_dma_contig_free(vq, vb);
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ videobuf_dma_unmap(vq->dev, dma);
+ videobuf_dma_free(dma);
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -750,25 +874,22 @@ static int solo_enc_open(struct file *file)
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_enc_fh *fh;
- if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
return -ENOMEM;
- spin_lock(&solo_enc->lock);
-
fh->enc = solo_enc;
file->private_data = fh;
INIT_LIST_HEAD(&fh->vidq_active);
fh->fmt = V4L2_PIX_FMT_MPEG;
fh->type = SOLO_ENC_TYPE_STD;
- videobuf_queue_dma_contig_init(&fh->vidq, &solo_enc_video_qops,
- &solo_enc->solo_dev->pdev->dev,
- &solo_enc->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer), fh);
-
- spin_unlock(&solo_enc->lock);
+ videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
+ &solo_enc->solo_dev->pdev->dev,
+ &solo_enc->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct videobuf_buffer), fh, NULL);
return 0;
}
@@ -785,7 +906,11 @@ static ssize_t solo_enc_read(struct file *file, char __user *data,
spin_lock(&solo_enc->lock);
ret = solo_enc_on(fh);
- spin_unlock(&solo_enc->lock);
+ spin_unlock(&solo_enc->lock);
+ if (ret)
+ return ret;
+
+ ret = solo_start_fh_thread(fh);
if (ret)
return ret;
}
@@ -797,10 +922,15 @@ static ssize_t solo_enc_read(struct file *file, char __user *data,
static int solo_enc_release(struct file *file)
{
struct solo_enc_fh *fh = file->private_data;
+ struct solo_enc_dev *solo_enc = fh->enc;
videobuf_stop(&fh->vidq);
videobuf_mmap_free(&fh->vidq);
+
+ spin_lock(&solo_enc->lock);
solo_enc_off(fh);
+ spin_unlock(&solo_enc->lock);
+
kfree(fh);
return 0;
@@ -842,7 +972,7 @@ static int solo_enc_enum_input(struct file *file, void *priv,
if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
input->std = V4L2_STD_NTSC_M;
else
- input->std = V4L2_STD_PAL_M;
+ input->std = V4L2_STD_PAL_B;
if (!tw28_get_video_status(solo_dev, solo_enc->ch))
input->status = V4L2_IN_ST_NO_SIGNAL;
@@ -915,9 +1045,8 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv,
if (pix->field == V4L2_FIELD_ANY)
pix->field = V4L2_FIELD_INTERLACED;
- else if (pix->field != V4L2_FIELD_INTERLACED) {
+ else if (pix->field != V4L2_FIELD_INTERLACED)
pix->field = V4L2_FIELD_INTERLACED;
- }
/* Just set these */
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
@@ -937,7 +1066,8 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv,
spin_lock(&solo_enc->lock);
- if ((ret = solo_enc_try_fmt_cap(file, priv, f))) {
+ ret = solo_enc_try_fmt_cap(file, priv, f);
+ if (ret) {
spin_unlock(&solo_enc->lock);
return ret;
}
@@ -956,7 +1086,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv,
spin_unlock(&solo_enc->lock);
- return ret;
+ if (ret)
+ return ret;
+
+ return solo_start_fh_thread(fh);
}
static int solo_enc_get_fmt_cap(struct file *file, void *priv,
@@ -977,7 +1110,7 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int solo_enc_reqbufs(struct file *file, void *priv,
+static int solo_enc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *req)
{
struct solo_enc_fh *fh = priv;
@@ -1014,6 +1147,10 @@ static int solo_enc_dqbuf(struct file *file, void *priv,
spin_unlock(&solo_enc->lock);
if (ret)
return ret;
+
+ ret = solo_start_fh_thread(fh);
+ if (ret)
+ return ret;
}
ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
@@ -1033,12 +1170,16 @@ static int solo_enc_dqbuf(struct file *file, void *priv,
/* Check for key frame on mpeg data */
if (fh->fmt == V4L2_PIX_FMT_MPEG) {
- struct videobuf_buffer *vb = fh->vidq.bufs[buf->index];
- u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
- if (p[3] == 0x00)
- buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
- else
- buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ struct videobuf_dmabuf *vbuf =
+ videobuf_to_dma(fh->vidq.bufs[buf->index]);
+
+ if (vbuf) {
+ u8 *p = sg_virt(vbuf->sglist);
+ if (p[3] == 0x00)
+ buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else
+ buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ }
}
return 0;
@@ -1136,7 +1277,7 @@ static int solo_g_parm(struct file *file, void *priv,
/* XXX: Shouldn't we be able to get/set this from videobuf? */
cp->readbuffers = 2;
- return 0;
+ return 0;
}
static int solo_s_parm(struct file *file, void *priv,
@@ -1176,7 +1317,7 @@ static int solo_s_parm(struct file *file, void *priv,
spin_unlock(&solo_enc->lock);
- return 0;
+ return 0;
}
static int solo_queryctrl(struct file *file, void *priv,
@@ -1240,7 +1381,7 @@ static int solo_queryctrl(struct file *file, void *priv,
return 0;
}
- return -EINVAL;
+ return -EINVAL;
}
static int solo_querymenu(struct file *file, void *priv,
@@ -1250,7 +1391,8 @@ static int solo_querymenu(struct file *file, void *priv,
int err;
qctrl.id = qmenu->id;
- if ((err = solo_queryctrl(file, priv, &qctrl)))
+ err = solo_queryctrl(file, priv, &qctrl);
+ if (err)
return err;
return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
@@ -1350,9 +1492,9 @@ static int solo_s_ext_ctrls(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_RDS_TX_RADIO_TEXT:
if (ctrl->size - 1 > OSD_TEXT_MAX)
- err = -ERANGE;
+ err = -ERANGE;
else {
- err = copy_from_user(solo_enc->osd_text,
+ err = copy_from_user(solo_enc->osd_text,
ctrl->string,
OSD_TEXT_MAX);
solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
@@ -1459,7 +1601,7 @@ static struct video_device solo_enc_template = {
.minor = -1,
.release = video_device_release,
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
.current_norm = V4L2_STD_NTSC_M,
};
@@ -1505,7 +1647,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo6010_dev *solo_dev, u8 ch)
atomic_set(&solo_enc->readers, 0);
solo_enc->qp = SOLO_DEFAULT_QP;
- solo_enc->gop = solo_dev->fps;
+ solo_enc->gop = solo_dev->fps;
solo_enc->interval = 1;
solo_enc->mode = SOLO_ENC_MODE_CIF;
solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c
index 9731fa02b5e8..a8491dc0e914 100644
--- a/drivers/staging/solo6x10/solo6010-v4l2.c
+++ b/drivers/staging/solo6x10/solo6010-v4l2.c
@@ -24,14 +24,13 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
#include "solo6010.h"
#include "solo6010-tw28.h"
#define SOLO_HW_BPL 2048
#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
-#define SOLO_DISP_BUF_SIZE (64 * 1024) // 64k
/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
#define solo_vlines(__solo) (__solo->video_vsize * 2)
@@ -49,6 +48,8 @@ struct solo_filehandle {
spinlock_t slock;
int old_write;
struct list_head vidq_active;
+ struct p2m_desc desc[SOLO_NR_P2M_DESC];
+ int desc_idx;
};
unsigned video_nr = -1;
@@ -96,7 +97,7 @@ static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch,
SOLO_VI_WIN_EX(ex) |
SOLO_VI_WIN_SCALE(scale));
- solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
SOLO_VI_WIN_SY(sy) |
SOLO_VI_WIN_EY(ey));
}
@@ -203,50 +204,149 @@ static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch)
return 0;
}
+static void disp_reset_desc(struct solo_filehandle *fh)
+{
+ /* We use desc mode, which ignores desc 0 */
+ memset(fh->desc, 0, sizeof(*fh->desc));
+ fh->desc_idx = 1;
+}
+
+static int disp_flush_descs(struct solo_filehandle *fh)
+{
+ int ret;
+
+ if (!fh->desc_idx)
+ return 0;
+
+ ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
+ fh->desc, fh->desc_idx);
+ disp_reset_desc(fh);
+
+ return ret;
+}
+
+static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
+ u32 ext_addr, int size, int repeat, int ext_size)
+{
+ if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
+ int ret = disp_flush_descs(fh);
+ if (ret)
+ return ret;
+ }
+
+ solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
+ size, repeat, ext_size);
+ fh->desc_idx++;
+
+ return 0;
+}
+
static void solo_fillbuf(struct solo_filehandle *fh,
struct videobuf_buffer *vb)
{
struct solo6010_dev *solo_dev = fh->solo_dev;
- dma_addr_t vbuf;
+ struct videobuf_dmabuf *vbuf;
unsigned int fdma_addr;
- int frame_size;
int error = 1;
int i;
+ struct scatterlist *sg;
+ dma_addr_t sg_dma;
+ int sg_size_left;
- if (!(vbuf = videobuf_to_dma_contig(vb)))
+ vbuf = videobuf_to_dma(vb);
+ if (!vbuf)
goto finish_buf;
if (erase_off(solo_dev)) {
- void *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
- int image_size = solo_image_size(solo_dev);
- for (i = 0; i < image_size; i += 2) {
- ((u8 *)p)[i] = 0x80;
- ((u8 *)p)[i + 1] = 0x00;
+ int i;
+
+ /* Just blit to the entire sg list, ignoring size */
+ for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
+ void *p = sg_virt(sg);
+ size_t len = sg_dma_len(sg);
+
+ for (i = 0; i < len; i += 2) {
+ ((u8 *)p)[i] = 0x80;
+ ((u8 *)p)[i + 1] = 0x00;
+ }
}
+
error = 0;
goto finish_buf;
}
- frame_size = SOLO_HW_BPL * solo_vlines(solo_dev);
- fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size);
+ disp_reset_desc(fh);
+ sg = vbuf->sglist;
+ sg_dma = sg_dma_address(sg);
+ sg_size_left = sg_dma_len(sg);
+
+ fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write *
+ (SOLO_HW_BPL * solo_vlines(solo_dev)));
- for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) {
- int j;
- for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) {
- if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0,
- vbuf, fdma_addr + (j * SOLO_HW_BPL),
- solo_bytesperline(solo_dev)))
+ for (i = 0; i < solo_vlines(solo_dev); i++) {
+ int line_len = solo_bytesperline(solo_dev);
+ int lines;
+
+ if (!sg_size_left) {
+ sg = sg_next(sg);
+ if (sg == NULL)
goto finish_buf;
- vbuf += solo_bytesperline(solo_dev);
+ sg_dma = sg_dma_address(sg);
+ sg_size_left = sg_dma_len(sg);
}
- fdma_addr += SOLO_DISP_BUF_SIZE;
+
+ /* No room for an entire line, so chunk it up */
+ if (sg_size_left < line_len) {
+ int this_addr = fdma_addr;
+
+ while (line_len > 0) {
+ int this_write;
+
+ if (!sg_size_left) {
+ sg = sg_next(sg);
+ if (sg == NULL)
+ goto finish_buf;
+ sg_dma = sg_dma_address(sg);
+ sg_size_left = sg_dma_len(sg);
+ }
+
+ this_write = min(sg_size_left, line_len);
+
+ if (disp_push_desc(fh, sg_dma, this_addr,
+ this_write, 0, 0))
+ goto finish_buf;
+
+ line_len -= this_write;
+ sg_size_left -= this_write;
+ sg_dma += this_write;
+ this_addr += this_write;
+ }
+
+ fdma_addr += SOLO_HW_BPL;
+ continue;
+ }
+
+ /* Shove as many lines into a repeating descriptor as possible */
+ lines = min(sg_size_left / line_len,
+ solo_vlines(solo_dev) - i);
+
+ if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
+ lines - 1, SOLO_HW_BPL))
+ goto finish_buf;
+
+ i += lines - 1;
+ fdma_addr += SOLO_HW_BPL * lines;
+ sg_dma += lines * line_len;
+ sg_size_left -= lines * line_len;
}
- error = 0;
+
+ error = disp_flush_descs(fh);
finish_buf:
if (error) {
vb->state = VIDEOBUF_ERROR;
} else {
+ vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
vb->state = VIDEOBUF_DONE;
vb->field_count++;
do_gettimeofday(&vb->ts);
@@ -275,7 +375,7 @@ static void solo_thread_try(struct solo_filehandle *fh)
break;
cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
- SOLO_VI_STATUS0));
+ SOLO_VI_STATUS0));
if (cur_write == fh->old_write)
break;
@@ -310,7 +410,7 @@ static int solo_thread(void *data)
remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
- return 0;
+ return 0;
}
static int solo_start_thread(struct solo_filehandle *fh)
@@ -337,12 +437,12 @@ static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
struct solo_filehandle *fh = vq->priv_data;
struct solo6010_dev *solo_dev = fh->solo_dev;
- *size = solo_image_size(solo_dev);
+ *size = solo_image_size(solo_dev);
- if (*count < MIN_VID_BUFFERS)
+ if (*count < MIN_VID_BUFFERS)
*count = MIN_VID_BUFFERS;
- return 0;
+ return 0;
}
static int solo_buf_prepare(struct videobuf_queue *vq,
@@ -364,7 +464,9 @@ static int solo_buf_prepare(struct videobuf_queue *vq,
if (vb->state == VIDEOBUF_NEEDS_INIT) {
int rc = videobuf_iolock(vq, vb, NULL);
if (rc < 0) {
- videobuf_dma_contig_free(vq, vb);
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ videobuf_dma_unmap(vq->dev, dma);
+ videobuf_dma_free(dma);
vb->state = VIDEOBUF_NEEDS_INIT;
return rc;
}
@@ -388,7 +490,10 @@ static void solo_buf_queue(struct videobuf_queue *vq,
static void solo_buf_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
- videobuf_dma_contig_free(vq, vb);
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ videobuf_dma_unmap(vq->dev, dma);
+ videobuf_dma_free(dma);
vb->state = VIDEOBUF_NEEDS_INIT;
}
@@ -404,7 +509,7 @@ static unsigned int solo_v4l2_poll(struct file *file,
{
struct solo_filehandle *fh = file->private_data;
- return videobuf_poll_stream(file, &fh->vidq, wait);
+ return videobuf_poll_stream(file, &fh->vidq, wait);
}
static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
@@ -420,7 +525,8 @@ static int solo_v4l2_open(struct file *file)
struct solo_filehandle *fh;
int ret;
- if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
return -ENOMEM;
spin_lock_init(&fh->slock);
@@ -428,16 +534,17 @@ static int solo_v4l2_open(struct file *file)
fh->solo_dev = solo_dev;
file->private_data = fh;
- if ((ret = solo_start_thread(fh))) {
+ ret = solo_start_thread(fh);
+ if (ret) {
kfree(fh);
return ret;
}
- videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops,
- &solo_dev->pdev->dev, &fh->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- SOLO_DISP_PIX_FIELD,
- sizeof(struct videobuf_buffer), fh);
+ videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
+ &solo_dev->pdev->dev, &fh->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ SOLO_DISP_PIX_FIELD,
+ sizeof(struct videobuf_buffer), fh, NULL);
return 0;
}
@@ -530,7 +637,7 @@ static int solo_enum_input(struct file *file, void *priv,
if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
input->std = V4L2_STD_NTSC_M;
else
- input->std = V4L2_STD_PAL_M;
+ input->std = V4L2_STD_PAL_B;
return 0;
}
@@ -622,7 +729,7 @@ static int solo_get_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int solo_reqbufs(struct file *file, void *priv,
+static int solo_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *req)
{
struct solo_filehandle *fh = priv;
@@ -781,11 +888,11 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
.vidioc_qbuf = solo_qbuf,
.vidioc_dqbuf = solo_dqbuf,
.vidioc_streamon = solo_streamon,
- .vidioc_streamoff = solo_streamoff,
+ .vidioc_streamoff = solo_streamoff,
/* Controls */
.vidioc_queryctrl = solo_disp_queryctrl,
- .vidioc_g_ctrl = solo_disp_g_ctrl,
- .vidioc_s_ctrl = solo_disp_s_ctrl,
+ .vidioc_g_ctrl = solo_disp_g_ctrl,
+ .vidioc_s_ctrl = solo_disp_s_ctrl,
};
static struct video_device solo_v4l2_template = {
@@ -795,7 +902,7 @@ static struct video_device solo_v4l2_template = {
.minor = -1,
.release = video_device_release,
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
.current_norm = V4L2_STD_NTSC_M,
};
@@ -836,13 +943,13 @@ int solo_v4l2_init(struct solo6010_dev *solo_dev)
for (i = 0; i < solo_dev->nr_chans; i++) {
solo_v4l2_set_ch(solo_dev, i);
while (erase_off(solo_dev))
- ;// Do nothing
+ ;/* Do nothing */
}
/* Set the default display channel */
solo_v4l2_set_ch(solo_dev, 0);
while (erase_off(solo_dev))
- ;// Do nothing
+ ;/* Do nothing */
solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h
index dca8e3e15450..9c930f3a017b 100644
--- a/drivers/staging/solo6x10/solo6010.h
+++ b/drivers/staging/solo6x10/solo6010.h
@@ -26,8 +26,8 @@
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/list.h>
-#include <linux/delay.h>
#include <linux/wait.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/atomic.h>
@@ -48,10 +48,14 @@
#define PCI_DEVICE_ID_NEUSOLO_4 0x4304
#define PCI_DEVICE_ID_NEUSOLO_9 0x4309
#define PCI_DEVICE_ID_NEUSOLO_16 0x4310
-/* Commell Softlogic 6010 based cards */
-#define PCI_DEVICE_ID_COMMSOLO_4 0x4E04
-#define PCI_DEVICE_ID_COMMSOLO_9 0x4E09
-#define PCI_DEVICE_ID_COMMSOLO_16 0x4E10
+/* Bluecherry Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_BC_SOLO_4 0x4E04
+#define PCI_DEVICE_ID_BC_SOLO_9 0x4E09
+#define PCI_DEVICE_ID_BC_SOLO_16 0x4E10
+/* Bluecherry Softlogic 6110 based cards */
+#define PCI_DEVICE_ID_BC_6110_4 0x5304
+#define PCI_DEVICE_ID_BC_6110_8 0x5308
+#define PCI_DEVICE_ID_BC_6110_16 0x5310
#endif /* Bluecherry */
#define SOLO6010_NAME "solo6010"
@@ -64,7 +68,7 @@
#define SOLO6010_VER_MINOR 0
#define SOLO6010_VER_SUB 0
#define SOLO6010_VER_NUM \
- KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB)
+ KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB)
/*
* The SOLO6010 actually has 8 i2c channels, but we only use 2.
@@ -78,7 +82,6 @@
/* DMA Engine setup */
#define SOLO_NR_P2M 4
#define SOLO_NR_P2M_DESC 256
-#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16)
/* MPEG and JPEG share the same interrupt and locks so they must be together
* in the same dma channel. */
#define SOLO_P2M_DMA_ID_MP4E 0
@@ -123,11 +126,17 @@ enum SOLO_I2C_STATE {
IIC_STATE_STOP
};
+struct p2m_desc {
+ u32 ctrl;
+ u32 ext;
+ u32 ta;
+ u32 fa;
+};
+
struct solo_p2m_dev {
- struct semaphore sem;
+ struct mutex mutex;
struct completion completion;
int error;
- u8 desc[SOLO_P2M_DESC_SIZE];
};
#define OSD_TEXT_MAX 30
@@ -185,7 +194,7 @@ struct solo6010_dev {
/* i2c related items */
struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS];
enum SOLO_I2C_STATE i2c_state;
- struct semaphore i2c_sem;
+ struct mutex i2c_mutex;
int i2c_id;
wait_queue_head_t i2c_wait;
struct i2c_msg *i2c_msg;
@@ -212,7 +221,7 @@ struct solo6010_dev {
struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS];
/* Current video settings */
- u32 video_type;
+ u32 video_type;
u16 video_hsize, video_vsize;
u16 vout_hstart, vout_vstart;
u16 vin_hstart, vin_vstart;
@@ -306,6 +315,14 @@ int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
dma_addr_t dma_addr, u32 ext_addr, u32 size);
int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
void *sys_addr, u32 ext_addr, u32 size);
+int solo_p2m_dma_sg(struct solo6010_dev *solo_dev, u8 id,
+ struct p2m_desc *pdesc, int wr,
+ struct scatterlist *sglist, u32 sg_off,
+ u32 ext_addr, u32 size);
+void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
+ u32 ext_addr, u32 size, int repeat, u32 ext_size);
+int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, u8 id,
+ struct p2m_desc *desc, int desc_count);
/* Set the threshold for motion detection */
void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val);
diff --git a/drivers/staging/speakup/buffers.c b/drivers/staging/speakup/buffers.c
index b7b60d5e8660..a2db956edd54 100644
--- a/drivers/staging/speakup/buffers.c
+++ b/drivers/staging/speakup/buffers.c
@@ -1,5 +1,4 @@
#include <linux/console.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/wait.h>
diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c
index adb93f21c0d6..1b34a8771641 100644
--- a/drivers/staging/speakup/fakekey.c
+++ b/drivers/staging/speakup/fakekey.c
@@ -62,7 +62,6 @@ void speakup_remove_virtual_keyboard(void)
{
if (virt_keyboard != NULL) {
input_unregister_device(virt_keyboard);
- input_free_device(virt_keyboard);
virt_keyboard = NULL;
}
}
@@ -79,10 +78,10 @@ void speakup_fake_down_arrow(void)
/* don't change CPU */
preempt_disable();
- __get_cpu_var(reporting_keystroke) = true;
+ __this_cpu_write(reporting_keystroke, true);
input_report_key(virt_keyboard, KEY_DOWN, PRESSED);
input_report_key(virt_keyboard, KEY_DOWN, RELEASED);
- __get_cpu_var(reporting_keystroke) = false;
+ __this_cpu_write(reporting_keystroke, false);
/* reenable preemption */
preempt_enable();
@@ -96,10 +95,5 @@ void speakup_fake_down_arrow(void)
*/
bool speakup_fake_key_pressed(void)
{
- bool is_pressed;
-
- is_pressed = get_cpu_var(reporting_keystroke);
- put_cpu_var(reporting_keystroke);
-
- return is_pressed;
+ return this_cpu_read(reporting_keystroke);
}
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
index cc79f9edfe9e..408bb9b3303e 100644
--- a/drivers/staging/speakup/kobjects.c
+++ b/drivers/staging/speakup/kobjects.c
@@ -984,8 +984,10 @@ int speakup_kobj_init(void)
* not known ahead of time.
*/
accessibility_kobj = kobject_create_and_add("accessibility", NULL);
- if (!accessibility_kobj)
- return -ENOMEM;
+ if (!accessibility_kobj) {
+ retval = -ENOMEM;
+ goto out;
+ }
speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
if (!speakup_kobj) {
@@ -1002,7 +1004,7 @@ int speakup_kobj_init(void)
if (retval)
goto err_group;
- return 0;
+ goto out;
err_group:
sysfs_remove_group(speakup_kobj, &main_attr_group);
@@ -1010,6 +1012,7 @@ err_speakup:
kobject_put(speakup_kobj);
err_acc:
kobject_put(accessibility_kobj);
+out:
return retval;
}
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
index 4b7a9c2b965f..3cd00396a462 100644
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -2253,17 +2253,17 @@ static int __init speakup_init(void)
err = speakup_add_virtual_keyboard();
if (err)
- return err;
+ goto out;
initialize_msgs(); /* Initialize arrays for i18n. */
first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
- if (!first_console)
- return -ENOMEM;
- err = speakup_kobj_init();
- if (err) {
- kfree(first_console);
- return err;
+ if (!first_console) {
+ err = -ENOMEM;
+ goto err_cons;
}
+ err = speakup_kobj_init();
+ if (err)
+ goto err_kobject;
reset_default_chars();
reset_default_chartab();
@@ -2299,11 +2299,20 @@ static int __init speakup_init(void)
speakup_task = kthread_create(speakup_thread, NULL, "speakup");
set_user_nice(speakup_task, 10);
- if (!IS_ERR(speakup_task))
- wake_up_process(speakup_task);
- else
- return -ENOMEM;
- return 0;
+ if (IS_ERR(speakup_task)) {
+ err = -ENOMEM;
+ goto err_kobject;
+ }
+ wake_up_process(speakup_task);
+ goto out;
+
+err_kobject:
+speakup_kobj_exit();
+ kfree(first_console);
+err_cons:
+ speakup_remove_virtual_keyboard();
+out:
+ return err;
}
module_init(speakup_init);
diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h
index 840bddb64101..d36c90e30d54 100644
--- a/drivers/staging/speakup/spk_types.h
+++ b/drivers/staging/speakup/spk_types.h
@@ -52,7 +52,7 @@ typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch,
#define COLOR_BUFFER_SIZE 160
-struct spk_highlight_color_track{
+struct spk_highlight_color_track {
/* Count of each background color */
unsigned int bgcount[8];
/* Buffer for characters drawn with each background color */
diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c
index c7932da03c56..007b24b54e25 100644
--- a/drivers/staging/spectra/ffsport.c
+++ b/drivers/staging/spectra/ffsport.c
@@ -28,6 +28,7 @@
#include <linux/log2.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/async.h>
/**** Helper functions used for Div, Remainder operation on u64 ****/
@@ -656,7 +657,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which)
/* Here we force report 512 byte hardware sector size to Kernel */
blk_queue_logical_block_size(dev->queue, 512);
- blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH);
+ blk_queue_flush(dev->queue, REQ_FLUSH);
dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd");
if (IS_ERR(dev->thread)) {
@@ -729,34 +730,16 @@ static void create_sysfs_entry(struct device *dev)
}
*/
-static int GLOB_SBD_init(void)
+static void register_spectra_ftl_async(void *unused, async_cookie_t cookie)
{
int i;
- /* Set debug output level (0~3) here. 3 is most verbose */
- printk(KERN_ALERT "Spectra: %s\n", GLOB_version);
-
- mutex_init(&spectra_lock);
-
- GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME);
- if (GLOB_SBD_majornum <= 0) {
- printk(KERN_ERR "Unable to get the major %d for Spectra",
- GLOB_SBD_majornum);
- return -EBUSY;
- }
-
- if (PASS != GLOB_FTL_Flash_Init()) {
- printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. "
- "Aborting\n");
- goto out_flash_register;
- }
-
/* create_sysfs_entry(&dev->dev); */
if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) {
printk(KERN_ERR "Spectra: Unable to Read Flash Device. "
"Aborting\n");
- goto out_flash_register;
+ return;
} else {
nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: "
"Num blocks=%d, pagesperblock=%d, "
@@ -775,24 +758,50 @@ static int GLOB_SBD_init(void)
}
printk(KERN_ALERT "Spectra: block table has been found.\n");
+ GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME);
+ if (GLOB_SBD_majornum <= 0) {
+ printk(KERN_ERR "Unable to get the major %d for Spectra",
+ GLOB_SBD_majornum);
+ goto out_ftl_flash_register;
+ }
+
for (i = 0; i < NUM_DEVICES; i++)
if (SBD_setup_device(&nand_device[i], i) == -ENOMEM)
- goto out_ftl_flash_register;
+ goto out_blk_register;
nand_dbg_print(NAND_DBG_DEBUG,
"Spectra: module loaded with major number %d\n",
GLOB_SBD_majornum);
- return 0;
+ return;
+out_blk_register:
+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);
out_ftl_flash_register:
GLOB_FTL_Cache_Release();
-out_flash_register:
- GLOB_FTL_Flash_Release();
- unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);
printk(KERN_ERR "Spectra: Module load failed.\n");
+}
- return -ENOMEM;
+int register_spectra_ftl()
+{
+ async_schedule(register_spectra_ftl_async, NULL);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_spectra_ftl);
+
+static int GLOB_SBD_init(void)
+{
+ /* Set debug output level (0~3) here. 3 is most verbose */
+ printk(KERN_ALERT "Spectra: %s\n", GLOB_version);
+
+ mutex_init(&spectra_lock);
+
+ if (PASS != GLOB_FTL_Flash_Init()) {
+ printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. "
+ "Aborting\n");
+ return -ENODEV;
+ }
+ return 0;
}
static void __exit GLOB_SBD_exit(void)
diff --git a/drivers/staging/spectra/ffsport.h b/drivers/staging/spectra/ffsport.h
index 6c5d90c53430..85c0750612f6 100644
--- a/drivers/staging/spectra/ffsport.h
+++ b/drivers/staging/spectra/ffsport.h
@@ -80,5 +80,6 @@ extern int nand_debug_level;
extern int GLOB_Calc_Used_Bits(u32 n);
extern u64 GLOB_u64_Div(u64 addr, u32 divisor);
extern u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type);
+extern int register_spectra_ftl(void);
#endif /* _FFSPORT_ */
diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c
index 4e6e451cd5c8..fb39c8ecf596 100644
--- a/drivers/staging/spectra/flash.c
+++ b/drivers/staging/spectra/flash.c
@@ -1258,9 +1258,7 @@ int GLOB_FTL_Flash_Init(void)
g_SBDCmdIndex = 0;
- GLOB_LLD_Flash_Init();
-
- status = GLOB_LLD_Read_Device_ID();
+ status = GLOB_LLD_Flash_Init();
return status;
}
diff --git a/drivers/staging/spectra/lld_emu.c b/drivers/staging/spectra/lld_emu.c
index 6733bbf8016d..095f2f0c2e5b 100644
--- a/drivers/staging/spectra/lld_emu.c
+++ b/drivers/staging/spectra/lld_emu.c
@@ -180,10 +180,8 @@ u16 emu_Flash_Init(void)
nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
- flash_memory[0] = (u8 *)vmalloc(GLOB_LLD_PAGE_SIZE *
- GLOB_LLD_BLOCKS *
- GLOB_LLD_PAGES *
- sizeof(u8));
+ flash_memory[0] = vmalloc(GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS *
+ GLOB_LLD_PAGES * sizeof(u8));
if (!flash_memory[0]) {
printk(KERN_ERR "Fail to allocate memory "
"for nand emulator!\n");
diff --git a/drivers/staging/spectra/lld_nand.c b/drivers/staging/spectra/lld_nand.c
index 0d647a8fd2b6..2263d3ea5456 100644
--- a/drivers/staging/spectra/lld_nand.c
+++ b/drivers/staging/spectra/lld_nand.c
@@ -2395,14 +2395,94 @@ static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
unsigned long csr_base;
unsigned long csr_len;
struct mrst_nand_info *pndev = &info;
+ u32 int_mask;
nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
+ FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE,
+ GLOB_HWCTL_REG_SIZE);
+ if (!FlashReg) {
+ printk(KERN_ERR "Spectra: ioremap_nocache failed!");
+ return -ENOMEM;
+ }
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: Remapped reg base address: "
+ "0x%p, len: %d\n",
+ FlashReg, GLOB_HWCTL_REG_SIZE);
+
+ FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE,
+ GLOB_HWCTL_MEM_SIZE);
+ if (!FlashMem) {
+ printk(KERN_ERR "Spectra: ioremap_nocache failed!");
+ iounmap(FlashReg);
+ return -ENOMEM;
+ }
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: Remapped flash base address: "
+ "0x%p, len: %d\n",
+ (void *)FlashMem, GLOB_HWCTL_MEM_SIZE);
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:"
+ "acc_clks: %d, re_2_we: %d, we_2_re: %d,"
+ "addr_2_data: %d, rdwr_en_lo_cnt: %d, "
+ "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
+ ioread32(FlashReg + ACC_CLKS),
+ ioread32(FlashReg + RE_2_WE),
+ ioread32(FlashReg + WE_2_RE),
+ ioread32(FlashReg + ADDR_2_DATA),
+ ioread32(FlashReg + RDWR_EN_LO_CNT),
+ ioread32(FlashReg + RDWR_EN_HI_CNT),
+ ioread32(FlashReg + CS_SETUP_CNT));
+
+ NAND_Flash_Reset();
+
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+
+#if CMD_DMA
+ info.pcmds_num = 0;
+ info.flash_bank = 0;
+ info.cdma_num = 0;
+ int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 |
+ DMA_INTR__DESC_COMP_CHANNEL1 |
+ DMA_INTR__DESC_COMP_CHANNEL2 |
+ DMA_INTR__DESC_COMP_CHANNEL3 |
+ DMA_INTR__MEMCOPY_DESC_COMP);
+ iowrite32(int_mask, FlashReg + DMA_INTR_EN);
+ iowrite32(0xFFFF, FlashReg + DMA_INTR);
+
+ int_mask = (INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL);
+#else
+ int_mask = INTR_STATUS0__DMA_CMD_COMP |
+ INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL;
+#endif
+ iowrite32(int_mask, FlashReg + INTR_EN0);
+ iowrite32(int_mask, FlashReg + INTR_EN1);
+ iowrite32(int_mask, FlashReg + INTR_EN2);
+ iowrite32(int_mask, FlashReg + INTR_EN3);
+
+ /* Clear all status bits */
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS0);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS1);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS2);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS3);
+
+ iowrite32(0x0F, FlashReg + RB_PIN_ENABLED);
+ iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE);
+
+ /* Should set value for these registers when init */
+ iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES);
+ iowrite32(1, FlashReg + ECC_ENABLE);
+ enable_ecc = 1;
ret = pci_enable_device(dev);
if (ret) {
printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
- return ret;
+ goto failed_req_csr;
}
pci_set_master(dev);
@@ -2461,12 +2541,26 @@ static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, pndev);
+ ret = GLOB_LLD_Read_Device_ID();
+ if (ret) {
+ iounmap(pndev->ioaddr);
+ goto failed_remap_csr;
+ }
+
+ ret = register_spectra_ftl();
+ if (ret) {
+ iounmap(pndev->ioaddr);
+ goto failed_remap_csr;
+ }
+
return 0;
failed_remap_csr:
pci_release_regions(dev);
failed_req_csr:
pci_disable_device(dev);
+ iounmap(FlashMem);
+ iounmap(FlashReg);
return ret;
}
@@ -2498,91 +2592,10 @@ static struct pci_driver nand_pci_driver = {
int NAND_Flash_Init(void)
{
int retval;
- u32 int_mask;
nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__);
- FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE,
- GLOB_HWCTL_REG_SIZE);
- if (!FlashReg) {
- printk(KERN_ERR "Spectra: ioremap_nocache failed!");
- return -ENOMEM;
- }
- nand_dbg_print(NAND_DBG_WARN,
- "Spectra: Remapped reg base address: "
- "0x%p, len: %d\n",
- FlashReg, GLOB_HWCTL_REG_SIZE);
-
- FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE,
- GLOB_HWCTL_MEM_SIZE);
- if (!FlashMem) {
- printk(KERN_ERR "Spectra: ioremap_nocache failed!");
- iounmap(FlashReg);
- return -ENOMEM;
- }
- nand_dbg_print(NAND_DBG_WARN,
- "Spectra: Remapped flash base address: "
- "0x%p, len: %d\n",
- (void *)FlashMem, GLOB_HWCTL_MEM_SIZE);
-
- nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:"
- "acc_clks: %d, re_2_we: %d, we_2_re: %d,"
- "addr_2_data: %d, rdwr_en_lo_cnt: %d, "
- "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
- ioread32(FlashReg + ACC_CLKS),
- ioread32(FlashReg + RE_2_WE),
- ioread32(FlashReg + WE_2_RE),
- ioread32(FlashReg + ADDR_2_DATA),
- ioread32(FlashReg + RDWR_EN_LO_CNT),
- ioread32(FlashReg + RDWR_EN_HI_CNT),
- ioread32(FlashReg + CS_SETUP_CNT));
-
- NAND_Flash_Reset();
-
- iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
-
-#if CMD_DMA
- info.pcmds_num = 0;
- info.flash_bank = 0;
- info.cdma_num = 0;
- int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 |
- DMA_INTR__DESC_COMP_CHANNEL1 |
- DMA_INTR__DESC_COMP_CHANNEL2 |
- DMA_INTR__DESC_COMP_CHANNEL3 |
- DMA_INTR__MEMCOPY_DESC_COMP);
- iowrite32(int_mask, FlashReg + DMA_INTR_EN);
- iowrite32(0xFFFF, FlashReg + DMA_INTR);
-
- int_mask = (INTR_STATUS0__ECC_ERR |
- INTR_STATUS0__PROGRAM_FAIL |
- INTR_STATUS0__ERASE_FAIL);
-#else
- int_mask = INTR_STATUS0__DMA_CMD_COMP |
- INTR_STATUS0__ECC_TRANSACTION_DONE |
- INTR_STATUS0__ECC_ERR |
- INTR_STATUS0__PROGRAM_FAIL |
- INTR_STATUS0__ERASE_FAIL;
-#endif
- iowrite32(int_mask, FlashReg + INTR_EN0);
- iowrite32(int_mask, FlashReg + INTR_EN1);
- iowrite32(int_mask, FlashReg + INTR_EN2);
- iowrite32(int_mask, FlashReg + INTR_EN3);
-
- /* Clear all status bits */
- iowrite32(0xFFFF, FlashReg + INTR_STATUS0);
- iowrite32(0xFFFF, FlashReg + INTR_STATUS1);
- iowrite32(0xFFFF, FlashReg + INTR_STATUS2);
- iowrite32(0xFFFF, FlashReg + INTR_STATUS3);
-
- iowrite32(0x0F, FlashReg + RB_PIN_ENABLED);
- iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE);
-
- /* Should set value for these registers when init */
- iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES);
- iowrite32(1, FlashReg + ECC_ENABLE);
- enable_ecc = 1;
-
retval = pci_register_driver(&nand_pci_driver);
if (retval)
return -ENOMEM;
diff --git a/drivers/staging/ste_rmi4/Kconfig b/drivers/staging/ste_rmi4/Kconfig
new file mode 100644
index 000000000000..e8679509e525
--- /dev/null
+++ b/drivers/staging/ste_rmi4/Kconfig
@@ -0,0 +1,9 @@
+config TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ tristate "Synaptics i2c rmi4 touchscreen"
+ depends on I2C && INPUT
+ help
+ Say Y here if you have a Synaptics RMI4 and
+ want to enable support for the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called synaptics_rmi4_ts.
diff --git a/drivers/staging/ste_rmi4/Makefile b/drivers/staging/ste_rmi4/Makefile
new file mode 100644
index 000000000000..6cce2ed187ef
--- /dev/null
+++ b/drivers/staging/ste_rmi4/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the RMI4 touchscreen driver.
+#
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
diff --git a/drivers/staging/ste_rmi4/TODO b/drivers/staging/ste_rmi4/TODO
new file mode 100644
index 000000000000..9be2437da85f
--- /dev/null
+++ b/drivers/staging/ste_rmi4/TODO
@@ -0,0 +1,7 @@
+TODO
+----
+
+Wait for the official upstream synaptics rmi4 clearpad drivers as promised over the past few months
+Merge any device support needed from this driver into it
+Delete this driver
+
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
new file mode 100644
index 000000000000..e8f047e86a32
--- /dev/null
+++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
@@ -0,0 +1,1179 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include "synaptics_i2c_rmi4.h"
+
+/* TODO: for multiple device support will need a per-device mutex */
+#define DRIVER_NAME "synaptics_rmi4_i2c"
+
+#define MAX_ERROR_REPORT 6
+#define MAX_TOUCH_MAJOR 15
+#define MAX_RETRY_COUNT 5
+#define STD_QUERY_LEN 21
+#define PAGE_LEN 2
+#define DATA_BUF_LEN 32
+#define BUF_LEN 37
+#define QUERY_LEN 9
+#define DATA_LEN 12
+#define HAS_TAP 0x01
+#define HAS_PALMDETECT 0x01
+#define HAS_ROTATE 0x02
+#define HAS_TAPANDHOLD 0x02
+#define HAS_DOUBLETAP 0x04
+#define HAS_EARLYTAP 0x08
+#define HAS_RELEASE 0x08
+#define HAS_FLICK 0x10
+#define HAS_PRESS 0x20
+#define HAS_PINCH 0x40
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+#define TOUCHPAD_CTRL_INTR 0x8
+#define PDT_START_SCAN_LOCATION (0x00E9)
+#define PDT_END_SCAN_LOCATION (0x000A)
+#define PDT_ENTRY_SIZE (0x0006)
+#define RMI4_NUMBER_OF_MAX_FINGERS (8)
+#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM (0x11)
+#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01)
+
+/**
+ * struct synaptics_rmi4_fn_desc - contains the funtion descriptor information
+ * @query_base_addr: base address for query
+ * @cmd_base_addr: base address for command
+ * @ctrl_base_addr: base address for control
+ * @data_base_addr: base address for data
+ * @intr_src_count: count for the interrupt source
+ * @fn_number: function number
+ *
+ * This structure is used to gives the function descriptor information
+ * of the particular functionality.
+ */
+struct synaptics_rmi4_fn_desc {
+ unsigned char query_base_addr;
+ unsigned char cmd_base_addr;
+ unsigned char ctrl_base_addr;
+ unsigned char data_base_addr;
+ unsigned char intr_src_count;
+ unsigned char fn_number;
+};
+
+/**
+ * struct synaptics_rmi4_fn - contains the funtion information
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: number of fingers touched
+ * @size_of_data_register_block: data register block size
+ * @index_to_intr_reg: index for interrupt register
+ * @intr_mask: interrupt mask value
+ * @fn_desc: variable for function descriptor structure
+ * @link: linked list for function descriptors
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_fn {
+ unsigned char fn_number;
+ unsigned char num_of_data_sources;
+ unsigned char num_of_data_points;
+ unsigned char size_of_data_register_block;
+ unsigned char index_to_intr_reg;
+ unsigned char intr_mask;
+ struct synaptics_rmi4_fn_desc fn_desc;
+ struct list_head link;
+};
+
+/**
+ * struct synaptics_rmi4_device_info - contains the rmi4 device information
+ * @version_major: protocol major version number
+ * @version_minor: protocol minor version number
+ * @manufacturer_id: manufacturer identification byte
+ * @product_props: product properties information
+ * @product_info: product info array
+ * @date_code: device manufacture date
+ * @tester_id: tester id array
+ * @serial_number: serial number for that device
+ * @product_id_string: product id for the device
+ * @support_fn_list: linked list for device information
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_device_info {
+ unsigned int version_major;
+ unsigned int version_minor;
+ unsigned char manufacturer_id;
+ unsigned char product_props;
+ unsigned char product_info[2];
+ unsigned char date_code[3];
+ unsigned short tester_id;
+ unsigned short serial_number;
+ unsigned char product_id_string[11];
+ struct list_head support_fn_list;
+};
+
+/**
+ * struct synaptics_rmi4_data - contains the rmi4 device data
+ * @rmi4_mod_info: structure variable for rmi4 device info
+ * @input_dev: pointer for input device
+ * @i2c_client: pointer for i2c client
+ * @board: constant pointer for touch platform data
+ * @fn_list_mutex: mutex for funtion list
+ * @rmi4_page_mutex: mutex for rmi4 page
+ * @current_page: variable for integer
+ * @number_of_interrupt_register: interrupt registers count
+ * @fn01_ctrl_base_addr: control base address for fn01
+ * @fn01_query_base_addr: query base address for fn01
+ * @fn01_data_base_addr: data base address for fn01
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @regulator: pointer to the regulator structure
+ * @wait: wait queue structure variable
+ * @touch_stopped: flag to stop the thread function
+ *
+ * This structure gives the device data information.
+ */
+struct synaptics_rmi4_data {
+ struct synaptics_rmi4_device_info rmi4_mod_info;
+ struct input_dev *input_dev;
+ struct i2c_client *i2c_client;
+ const struct synaptics_rmi4_platform_data *board;
+ struct mutex fn_list_mutex;
+ struct mutex rmi4_page_mutex;
+ int current_page;
+ unsigned int number_of_interrupt_register;
+ unsigned short fn01_ctrl_base_addr;
+ unsigned short fn01_query_base_addr;
+ unsigned short fn01_data_base_addr;
+ int sensor_max_x;
+ int sensor_max_y;
+ struct regulator *regulator;
+ wait_queue_head_t wait;
+ bool touch_stopped;
+};
+
+/**
+ * synaptics_rmi4_set_page() - sets the page
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: set the address of the page
+ *
+ * This function is used to set the page and returns integer.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata,
+ unsigned int address)
+{
+ unsigned char txbuf[PAGE_LEN];
+ int retval;
+ unsigned int page;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ page = ((address >> 8) & MASK_8BIT);
+ if (page != pdata->current_page) {
+ txbuf[0] = MASK_8BIT;
+ txbuf[1] = page;
+ retval = i2c_master_send(i2c, txbuf, PAGE_LEN);
+ if (retval != PAGE_LEN)
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ else
+ pdata->current_page = page;
+ } else
+ retval = PAGE_LEN;
+ return retval;
+}
+/**
+ * synaptics_rmi4_i2c_block_read() - read the block of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: read the block of data from this offset
+ * @valp: pointer to a buffer containing the data to be read
+ * @size: number of bytes to read
+ *
+ * This function is to read the block of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size)
+{
+ int retval = 0;
+ int retry_count = 0;
+ int index;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ mutex_lock(&(pdata->rmi4_page_mutex));
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ index = address & MASK_8BIT;
+retry:
+ retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp);
+ if (retval != size) {
+ if (++retry_count == MAX_RETRY_COUNT)
+ dev_err(&i2c->dev,
+ "%s:address 0x%04x size %d failed:%d\n",
+ __func__, address, size, retval);
+ else {
+ synaptics_rmi4_set_page(pdata, address);
+ goto retry;
+ }
+ }
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_byte_write() - write the single byte data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: write the block of data from this offset
+ * @data: data to be write
+ *
+ * This function is to write the single byte data and returns integer.
+ */
+static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char data)
+{
+ unsigned char txbuf[2];
+ int retval = 0;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&(pdata->rmi4_page_mutex));
+
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ txbuf[0] = address & MASK_8BIT;
+ txbuf[1] = data;
+ retval = i2c_master_send(pdata->i2c_client, txbuf, 2);
+ /* Add in retry on writes only in certian error return values */
+ if (retval != 2) {
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ retval = -EIO;
+ } else
+ retval = 1;
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+
+/**
+ * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to reports for the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /* number of touch points - fingers down in this case */
+ int touch_count = 0;
+ int finger;
+ int fingers_supported;
+ int finger_registers;
+ int reg;
+ int finger_shift;
+ int finger_status;
+ int retval;
+ unsigned short data_base_addr;
+ unsigned short data_offset;
+ unsigned char data_reg_blk_size;
+ unsigned char values[2];
+ unsigned char data[DATA_LEN];
+ int x[RMI4_NUMBER_OF_MAX_FINGERS];
+ int y[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wx[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wy[RMI4_NUMBER_OF_MAX_FINGERS];
+ struct i2c_client *client = pdata->i2c_client;
+
+ /* get 2D sensor finger data */
+ /*
+ * First get the finger status field - the size of the finger status
+ * field is determined by the number of finger supporte - 2 bits per
+ * finger, so the number of registers to read is:
+ * registerCount = ceil(numberOfFingers/4).
+ * Read the required number of registers and check each 2 bit field to
+ * determine if a finger is down:
+ * 00 = finger not present,
+ * 01 = finger present and data accurate,
+ * 10 = finger present but data may not be accurate,
+ * 11 = reserved for product use.
+ */
+ fingers_supported = rfi->num_of_data_points;
+ finger_registers = (fingers_supported + 3)/4;
+ data_base_addr = rfi->fn_desc.data_base_addr;
+ retval = synaptics_rmi4_i2c_block_read(pdata, data_base_addr, values,
+ finger_registers);
+ if (retval != finger_registers) {
+ dev_err(&client->dev, "%s:read status registers failed\n",
+ __func__);
+ return 0;
+ }
+ /*
+ * For each finger present, read the proper number of registers
+ * to get absolute data.
+ */
+ data_reg_blk_size = rfi->size_of_data_register_block;
+ for (finger = 0; finger < fingers_supported; finger++) {
+ /* determine which data byte the finger status is in */
+ reg = finger/4;
+ /* bit shift to get finger's status */
+ finger_shift = (finger % 4) * 2;
+ finger_status = (values[reg] >> finger_shift) & 3;
+ /*
+ * if finger status indicates a finger is present then
+ * read the finger data and report it
+ */
+ if (finger_status == 1 || finger_status == 2) {
+ /* Read the finger data */
+ data_offset = data_base_addr +
+ ((finger * data_reg_blk_size) +
+ finger_registers);
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ data_offset, data,
+ data_reg_blk_size);
+ if (retval != data_reg_blk_size) {
+ printk(KERN_ERR "%s:read data failed\n",
+ __func__);
+ return 0;
+ } else {
+ x[touch_count] =
+ (data[0] << 4) | (data[2] & MASK_4BIT);
+ y[touch_count] =
+ (data[1] << 4) |
+ ((data[2] >> 4) & MASK_4BIT);
+ wy[touch_count] =
+ (data[3] >> 4) & MASK_4BIT;
+ wx[touch_count] =
+ (data[3] & MASK_4BIT);
+
+ if (pdata->board->x_flip)
+ x[touch_count] =
+ pdata->sensor_max_x -
+ x[touch_count];
+ if (pdata->board->y_flip)
+ y[touch_count] =
+ pdata->sensor_max_y -
+ y[touch_count];
+ }
+ /* number of active touch points */
+ touch_count++;
+ }
+ }
+
+ /* report to input subsystem */
+ if (touch_count) {
+ for (finger = 0; finger < touch_count; finger++) {
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR,
+ max(wx[finger] , wy[finger]));
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_X,
+ x[finger]);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y,
+ y[finger]);
+ input_mt_sync(pdata->input_dev);
+ }
+ } else
+ input_mt_sync(pdata->input_dev);
+
+ /* sync after groups of events */
+ input_sync(pdata->input_dev);
+ /* return the number of touch points */
+ return touch_count;
+}
+
+/**
+ * synaptics_rmi4_report_device() - reports the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn
+ *
+ * This function is used to call the report function of the rmi4 device.
+ */
+static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ int touch = 0;
+ struct i2c_client *client = pdata->i2c_client;
+ static int num_error_reports;
+ if (rfi->fn_number != SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+ num_error_reports++;
+ if (num_error_reports < MAX_ERROR_REPORT)
+ dev_err(&client->dev, "%s:report not supported\n",
+ __func__);
+ } else
+ touch = synpatics_rmi4_touchpad_report(pdata, rfi);
+ return touch;
+}
+/**
+ * synaptics_rmi4_sensor_report() - reports to input subsystem
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to reads in all data sources and reports
+ * them to the input subsystem.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata)
+{
+ unsigned char intr_status[4];
+ /* number of touch points - fingers or buttons */
+ int touch = 0;
+ unsigned int retval;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * Get the interrupt status from the function $01
+ * control register+1 to find which source(s) were interrupting
+ * so we can read the data from the source(s) (2D sensor, buttons..)
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ pdata->fn01_data_base_addr + 1,
+ intr_status,
+ pdata->number_of_interrupt_register);
+ if (retval != pdata->number_of_interrupt_register) {
+ dev_err(&client->dev,
+ "could not read interrupt status registers\n");
+ return 0;
+ }
+ /*
+ * check each function that has data sources and if the interrupt for
+ * that triggered then call that RMI4 functions report() function to
+ * gather data and report it to the input subsystem
+ */
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ if (intr_status[rfi->index_to_intr_reg] &
+ rfi->intr_mask)
+ touch = synaptics_rmi4_report_device(pdata,
+ rfi);
+ }
+ }
+ /* return the number of touch points */
+ return touch;
+}
+
+/**
+ * synaptics_rmi4_irq() - thread function for rmi4 attention line
+ * @irq: irq value
+ * @data: void pointer
+ *
+ * This function is interrupt thread function. It just notifies the
+ * application layer that attention is required.
+ */
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
+{
+ struct synaptics_rmi4_data *pdata = data;
+ int touch_count;
+ do {
+ touch_count = synaptics_rmi4_sensor_report(pdata);
+ if (touch_count)
+ wait_event_timeout(pdata->wait, pdata->touch_stopped,
+ msecs_to_jiffies(1));
+ else
+ break;
+ } while (!pdata->touch_stopped);
+ return IRQ_HANDLED;
+}
+
+/**
+ * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ * @fd: pointer to synaptics_rmi4_fn_desc structure
+ * @interruptcount: count the number of interrupts
+ *
+ * This function calls to detects the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int interruptcount)
+{
+ unsigned char queries[QUERY_LEN];
+ unsigned short intr_offset;
+ unsigned char abs_data_size;
+ unsigned char abs_data_blk_size;
+ unsigned char egr_0, egr_1;
+ unsigned int all_data_blk_size;
+ int has_pinch, has_flick, has_tap;
+ int has_tapandhold, has_doubletap;
+ int has_earlytap, has_press;
+ int has_palmdetect, has_rotate;
+ int has_rel;
+ int i;
+ int retval;
+ struct i2c_client *client = pdata->i2c_client;
+
+ rfi->fn_desc.query_base_addr = fd->query_base_addr;
+ rfi->fn_desc.data_base_addr = fd->data_base_addr;
+ rfi->fn_desc.intr_src_count = fd->intr_src_count;
+ rfi->fn_desc.fn_number = fd->fn_number;
+ rfi->fn_number = fd->fn_number;
+ rfi->num_of_data_sources = fd->intr_src_count;
+ rfi->fn_desc.ctrl_base_addr = fd->ctrl_base_addr;
+ rfi->fn_desc.cmd_base_addr = fd->cmd_base_addr;
+
+ /*
+ * need to get number of fingers supported, data size, etc.
+ * to be used when getting data since the number of registers to
+ * read depends on the number of fingers supported and data size.
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata, fd->query_base_addr,
+ queries,
+ sizeof(queries));
+ if (retval != sizeof(queries)) {
+ dev_err(&client->dev, "%s:read function query registers\n",
+ __func__);
+ return retval;
+ }
+ /*
+ * 2D data sources have only 3 bits for the number of fingers
+ * supported - so the encoding is a bit wierd.
+ */
+ if ((queries[1] & MASK_3BIT) <= 4)
+ /* add 1 since zero based */
+ rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1;
+ else {
+ /*
+ * a value of 5 is up to 10 fingers - 6 and 7 are reserved
+ * (shouldn't get these i int retval;n a normal 2D source).
+ */
+ if ((queries[1] & MASK_3BIT) == 5)
+ rfi->num_of_data_points = 10;
+ }
+ /* Need to get interrupt info for handling interrupts */
+ rfi->index_to_intr_reg = (interruptcount + 7)/8;
+ if (rfi->index_to_intr_reg != 0)
+ rfi->index_to_intr_reg -= 1;
+ /*
+ * loop through interrupts for each source in fn $11
+ * and or in a bit to the interrupt mask for each.
+ */
+ intr_offset = interruptcount % 8;
+ rfi->intr_mask = 0;
+ for (i = intr_offset;
+ i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++)
+ rfi->intr_mask |= 1 << i;
+
+ /* Size of just the absolute data for one finger */
+ abs_data_size = queries[5] & MASK_2BIT;
+ /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
+ abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
+ rfi->size_of_data_register_block = abs_data_blk_size;
+
+ /*
+ * need to determine the size of data to read - this depends on
+ * conditions such as whether Relative data is reported and if Gesture
+ * data is reported.
+ */
+ egr_0 = queries[7];
+ egr_1 = queries[8];
+
+ /*
+ * Get info about what EGR data is supported, whether it has
+ * Relative data supported, etc.
+ */
+ has_pinch = egr_0 & HAS_PINCH;
+ has_flick = egr_0 & HAS_FLICK;
+ has_tap = egr_0 & HAS_TAP;
+ has_earlytap = egr_0 & HAS_EARLYTAP;
+ has_press = egr_0 & HAS_PRESS;
+ has_rotate = egr_1 & HAS_ROTATE;
+ has_rel = queries[1] & HAS_RELEASE;
+ has_tapandhold = egr_0 & HAS_TAPANDHOLD;
+ has_doubletap = egr_0 & HAS_DOUBLETAP;
+ has_palmdetect = egr_1 & HAS_PALMDETECT;
+
+ /*
+ * Size of all data including finger status, absolute data for each
+ * finger, relative data and EGR data
+ */
+ all_data_blk_size =
+ /* finger status, four fingers per register */
+ ((rfi->num_of_data_points + 3) / 4) +
+ /* absolute data, per finger times number of fingers */
+ (abs_data_blk_size * rfi->num_of_data_points) +
+ /*
+ * two relative registers (if relative is being reported)
+ */
+ 2 * has_rel +
+ /*
+ * F11_2D_data8 is only present if the egr_0
+ * register is non-zero.
+ */
+ !!(egr_0) +
+ /*
+ * F11_2D_data9 is only present if either egr_0 or
+ * egr_1 registers are non-zero.
+ */
+ (egr_0 || egr_1) +
+ /*
+ * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of
+ * egr_0 reports as 1.
+ */
+ !!(has_pinch | has_flick) +
+ /*
+ * F11_2D_data11 and F11_2D_data12 are only present if
+ * EGR_FLICK of egr_0 reports as 1.
+ */
+ 2 * !!(has_flick);
+ return retval;
+}
+
+/**
+ * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to confiures the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /*
+ * For the data source - print info and do any
+ * source specific configuration.
+ */
+ unsigned char data[BUF_LEN];
+ int retval = 0;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /* Get and print some info about the data source... */
+ /* To Query 2D devices we need to read from the address obtained
+ * from the function descriptor stored in the RMI function info.
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ rfi->fn_desc.query_base_addr,
+ data, QUERY_LEN);
+ if (retval != QUERY_LEN)
+ dev_err(&client->dev, "%s:read query registers failed\n",
+ __func__);
+ else {
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ rfi->fn_desc.ctrl_base_addr,
+ data, DATA_BUF_LEN);
+ if (retval != DATA_BUF_LEN) {
+ dev_err(&client->dev,
+ "%s:read control registers failed\n",
+ __func__);
+ return retval;
+ }
+ /* Store these for use later*/
+ pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) |
+ ((data[7] & MASK_4BIT) << 8);
+ pdata->sensor_max_y = ((data[8] & MASK_5BIT) << 0) |
+ ((data[9] & MASK_4BIT) << 8);
+ }
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_query_device() - query the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to query the rmi4 device.
+ */
+static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata)
+{
+ int i;
+ int retval;
+ unsigned char std_queries[STD_QUERY_LEN];
+ unsigned char intr_count = 0;
+ int data_sources = 0;
+ unsigned int ctrl_offset;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * init the physical drivers RMI module
+ * info list of functions
+ */
+ INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list);
+
+ /*
+ * Read the Page Descriptor Table to determine what functions
+ * are present
+ */
+ for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION;
+ i -= PDT_ENTRY_SIZE) {
+ retval = synaptics_rmi4_i2c_block_read(pdata, i,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval != sizeof(rmi_fd)) {
+ /* failed to read next PDT entry */
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+ rfi = NULL;
+ if (rmi_fd.fn_number) {
+ switch (rmi_fd.fn_number & MASK_8BIT) {
+ case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM:
+ pdata->fn01_query_base_addr =
+ rmi_fd.query_base_addr;
+ pdata->fn01_ctrl_base_addr =
+ rmi_fd.ctrl_base_addr;
+ pdata->fn01_data_base_addr =
+ rmi_fd.data_base_addr;
+ break;
+ case SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM:
+ if (rmi_fd.intr_src_count) {
+ rfi = kmalloc(sizeof(*rfi),
+ GFP_KERNEL);
+ if (!rfi) {
+ dev_err(&client->dev,
+ "%s:kmalloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ retval = synpatics_rmi4_touchpad_detect
+ (pdata, rfi,
+ &rmi_fd,
+ intr_count);
+ if (retval < 0)
+ return retval;
+ }
+ break;
+ }
+ /* interrupt count for next iteration */
+ intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+ /*
+ * We only want to add functions to the list
+ * that have data associated with them.
+ */
+ if (rfi && rmi_fd.intr_src_count) {
+ /* link this function info to the RMI module */
+ mutex_lock(&(pdata->fn_list_mutex));
+ list_add_tail(&rfi->link,
+ &pdata->rmi4_mod_info.support_fn_list);
+ mutex_unlock(&(pdata->fn_list_mutex));
+ }
+ } else {
+ /*
+ * A zero in the function number
+ * signals the end of the PDT
+ */
+ dev_dbg(&client->dev,
+ "%s:end of PDT\n", __func__);
+ break;
+ }
+ }
+ /*
+ * calculate the interrupt register count - used in the
+ * ISR to read the correct number of interrupt registers
+ */
+ pdata->number_of_interrupt_register = (intr_count + 7) / 8;
+ /*
+ * Function $01 will be used to query the product properties,
+ * and product ID so we had to read the PDT above first to get
+ * the Fn $01 query address and prior to filling in the product
+ * info. NOTE: Even an unflashed device will still have FN $01.
+ */
+
+ /* Load up the standard queries and get the RMI4 module info */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ pdata->fn01_query_base_addr,
+ std_queries,
+ sizeof(std_queries));
+ if (retval != sizeof(std_queries)) {
+ dev_err(&client->dev, "%s:Failed reading queries\n",
+ __func__);
+ return -EIO;
+ }
+
+ /* Currently supported RMI version is 4.0 */
+ pdata->rmi4_mod_info.version_major = 4;
+ pdata->rmi4_mod_info.version_minor = 0;
+ /*
+ * get manufacturer id, product_props, product info,
+ * date code, tester id, serial num and product id (name)
+ */
+ pdata->rmi4_mod_info.manufacturer_id = std_queries[0];
+ pdata->rmi4_mod_info.product_props = std_queries[1];
+ pdata->rmi4_mod_info.product_info[0] = std_queries[2];
+ pdata->rmi4_mod_info.product_info[1] = std_queries[3];
+ /* year - 2001-2032 */
+ pdata->rmi4_mod_info.date_code[0] = std_queries[4] & MASK_5BIT;
+ /* month - 1-12 */
+ pdata->rmi4_mod_info.date_code[1] = std_queries[5] & MASK_4BIT;
+ /* day - 1-31 */
+ pdata->rmi4_mod_info.date_code[2] = std_queries[6] & MASK_5BIT;
+ pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) |
+ (std_queries[8] & MASK_7BIT);
+ pdata->rmi4_mod_info.serial_number =
+ ((std_queries[9] & MASK_7BIT) << 8) |
+ (std_queries[10] & MASK_7BIT);
+ memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10);
+
+ /* Check if this is a Synaptics device - report if not. */
+ if (pdata->rmi4_mod_info.manufacturer_id != 1)
+ dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n",
+ __func__, pdata->rmi4_mod_info.manufacturer_id);
+
+ list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link)
+ data_sources += rfi->num_of_data_sources;
+ if (data_sources) {
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ if (rfi->fn_number ==
+ SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+ retval = synpatics_rmi4_touchpad_config
+ (pdata, rfi);
+ if (retval < 0)
+ return retval;
+ } else
+ dev_err(&client->dev,
+ "%s:fn_number not supported\n",
+ __func__);
+ /*
+ * Turn on interrupts for this
+ * function's data sources.
+ */
+ ctrl_offset = pdata->fn01_ctrl_base_addr + 1 +
+ rfi->index_to_intr_reg;
+ retval = synaptics_rmi4_i2c_byte_write(pdata,
+ ctrl_offset,
+ rfi->intr_mask);
+ if (retval < 0)
+ return retval;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
+ *
+ * This function will allocate and initialize the instance
+ * data and request the irq and set the instance data as the clients
+ * platform data then register the physical driver which will do a scan of
+ * the rmi4 Physical Device Table and enumerate any rmi4 functions that
+ * have data sources associated with them.
+ */
+static int __devinit synaptics_rmi4_probe
+ (struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+ int retval;
+ unsigned char intr_status[4];
+ struct synaptics_rmi4_data *rmi4_data;
+ const struct synaptics_rmi4_platform_data *platformdata =
+ client->dev.platform_data;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ return -EIO;
+ }
+
+ if (!platformdata) {
+ dev_err(&client->dev, "%s: no platform data\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Allocate and initialize the instance data for this client */
+ rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2,
+ GFP_KERNEL);
+ if (!rmi4_data) {
+ dev_err(&client->dev, "%s: no memory allocated\n", __func__);
+ return -ENOMEM;
+ }
+
+ rmi4_data->input_dev = input_allocate_device();
+ if (rmi4_data->input_dev == NULL) {
+ dev_err(&client->dev, "%s:input device alloc failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_input;
+ }
+
+ dev_set_name(&client->dev, platformdata->name);
+
+ if (platformdata->regulator_en) {
+ rmi4_data->regulator = regulator_get(&client->dev, "v-touch");
+ if (IS_ERR(rmi4_data->regulator)) {
+ dev_err(&client->dev, "%s:get regulator failed\n",
+ __func__);
+ retval = PTR_ERR(rmi4_data->regulator);
+ goto err_regulator;
+ }
+ regulator_enable(rmi4_data->regulator);
+ }
+
+ init_waitqueue_head(&rmi4_data->wait);
+ /*
+ * Copy i2c_client pointer into RTID's i2c_client pointer for
+ * later use in rmi4_read, rmi4_write, etc.
+ */
+ rmi4_data->i2c_client = client;
+ /* So we set the page correctly the first time */
+ rmi4_data->current_page = MASK_16BIT;
+ rmi4_data->board = platformdata;
+ rmi4_data->touch_stopped = false;
+
+ /* init the mutexes for maintain the lists */
+ mutex_init(&(rmi4_data->fn_list_mutex));
+ mutex_init(&(rmi4_data->rmi4_page_mutex));
+
+ /*
+ * Register physical driver - this will call the detect function that
+ * will then scan the device and determine the supported
+ * rmi4 functions.
+ */
+ retval = synaptics_rmi4_i2c_query_device(rmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s: rmi4 query device failed\n",
+ __func__);
+ goto err_query_dev;
+ }
+
+ /* Store the instance data in the i2c_client */
+ i2c_set_clientdata(client, rmi4_data);
+
+ /*initialize the input device parameters */
+ rmi4_data->input_dev->name = DRIVER_NAME;
+ rmi4_data->input_dev->phys = "Synaptics_Clearpad";
+ rmi4_data->input_dev->id.bustype = BUS_I2C;
+ rmi4_data->input_dev->dev.parent = &client->dev;
+ input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+ /* Initialize the function handlers for rmi4 */
+ set_bit(EV_SYN, rmi4_data->input_dev->evbit);
+ set_bit(EV_KEY, rmi4_data->input_dev->evbit);
+ set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X, 0,
+ rmi4_data->sensor_max_x, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y, 0,
+ rmi4_data->sensor_max_y, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+ MAX_TOUCH_MAJOR, 0, 0);
+
+ retval = input_register_device(rmi4_data->input_dev);
+ if (retval) {
+ dev_err(&client->dev, "%s:input register failed\n", __func__);
+ goto err_input_register;
+ }
+
+ /* Clear interrupts */
+ synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1, intr_status,
+ rmi4_data->number_of_interrupt_register);
+ retval = request_threaded_irq(platformdata->irq_number, NULL,
+ synaptics_rmi4_irq,
+ platformdata->irq_type,
+ platformdata->name, rmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
+ __func__, platformdata->irq_number);
+ goto err_request_irq;
+ }
+
+ return retval;
+
+err_request_irq:
+ free_irq(platformdata->irq_number, rmi4_data);
+ input_unregister_device(rmi4_data->input_dev);
+err_input_register:
+ i2c_set_clientdata(client, NULL);
+err_query_dev:
+ if (platformdata->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+err_regulator:
+ input_free_device(rmi4_data->input_dev);
+ rmi4_data->input_dev = NULL;
+err_input:
+ kfree(rmi4_data);
+
+ return retval;
+}
+/**
+ * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This funtion uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit synaptics_rmi4_remove(struct i2c_client *client)
+{
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+ free_irq(pdata->irq_number, rmi4_data);
+ input_unregister_device(rmi4_data->input_dev);
+ if (pdata->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+ kfree(rmi4_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * synaptics_rmi4_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This funtion is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+ /* Touch sleep mode */
+ int retval;
+ unsigned char intr_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ rmi4_data->touch_stopped = true;
+ disable_irq(pdata->irq_number);
+
+ retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+ rmi4_data->fn01_ctrl_base_addr + 1,
+ (intr_status & ~TOUCHPAD_CTRL_INTR));
+ if (retval < 0)
+ return retval;
+
+ if (pdata->regulator_en)
+ regulator_disable(rmi4_data->regulator);
+
+ return 0;
+}
+/**
+ * synaptics_rmi4_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This funtion is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int synaptics_rmi4_resume(struct device *dev)
+{
+ int retval;
+ unsigned char intr_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ if (pdata->regulator_en)
+ regulator_enable(rmi4_data->regulator);
+
+ enable_irq(pdata->irq_number);
+ rmi4_data->touch_stopped = false;
+
+ retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+ rmi4_data->fn01_ctrl_base_addr + 1,
+ (intr_status | TOUCHPAD_CTRL_INTR));
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+ .suspend = synaptics_rmi4_suspend,
+ .resume = synaptics_rmi4_resume,
+};
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+ { DRIVER_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static struct i2c_driver synaptics_rmi4_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &synaptics_rmi4_dev_pm_ops,
+#endif
+ },
+ .probe = synaptics_rmi4_probe,
+ .remove = __devexit_p(synaptics_rmi4_remove),
+ .id_table = synaptics_rmi4_id_table,
+};
+/**
+ * synaptics_rmi4_init() - Initialize the touchscreen driver
+ *
+ * This funtion uses to initializes the synaptics
+ * touchscreen driver and returns integer.
+ */
+static int __init synaptics_rmi4_init(void)
+{
+ return i2c_add_driver(&synaptics_rmi4_driver);
+}
+/**
+ * synaptics_rmi4_exit() - De-initialize the touchscreen driver
+ *
+ * This funtion uses to de-initialize the synaptics
+ * touchscreen driver and returns none.
+ */
+static void __exit synaptics_rmi4_exit(void)
+{
+ i2c_del_driver(&synaptics_rmi4_driver);
+}
+
+
+module_init(synaptics_rmi4_init);
+module_exit(synaptics_rmi4_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com");
+MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver");
+MODULE_ALIAS("i2c:synaptics_rmi4_ts");
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h
new file mode 100644
index 000000000000..820ae275fa2b
--- /dev/null
+++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h
@@ -0,0 +1,50 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#ifndef _SYNAPTICS_RMI4_H_INCLUDED_
+#define _SYNAPTICS_RMI4_H_INCLUDED_
+
+/**
+ * struct synaptics_rmi4_platform_data - contains the rmi4 platform data
+ * @irq_number: irq number
+ * @irq_type: irq type
+ * @x flip: x flip flag
+ * @y flip: y flip flag
+ * @regulator_en: regulator enable flag
+ *
+ * This structure gives platform data for rmi4.
+ */
+struct synaptics_rmi4_platform_data {
+ const char *name;
+ int irq_number;
+ int irq_type;
+ bool x_flip;
+ bool y_flip;
+ bool regulator_en;
+};
+
+#endif
diff --git a/drivers/staging/stradis/Kconfig b/drivers/staging/stradis/Kconfig
deleted file mode 100644
index 92e891141896..000000000000
--- a/drivers/staging/stradis/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config VIDEO_STRADIS
- tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
- 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
- <http://www.stradis.com/>.
diff --git a/drivers/staging/stradis/Makefile b/drivers/staging/stradis/Makefile
deleted file mode 100644
index 0f1feab59e39..000000000000
--- a/drivers/staging/stradis/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
-
-EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/stradis/TODO b/drivers/staging/stradis/TODO
deleted file mode 100644
index f48150fe2fa9..000000000000
--- a/drivers/staging/stradis/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-This is an obsolete driver for ancient stradis hardware.
-We couldn't find anyone with this hardware in order to port it to use V4L2.
-
-If nobody take care on it, the driver will be removed for 2.6.38.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/stradis/stradis.c b/drivers/staging/stradis/stradis.c
deleted file mode 100644
index a057824e7ebc..000000000000
--- a/drivers/staging/stradis/stradis.c
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * stradis.c - stradis 4:2:2 mpeg decoder driver
- *
- * Stradis 4:2:2 MPEG-2 Decoder Driver
- * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <linux/ioport.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <asm/types.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "saa7146.h"
-#include "saa7146reg.h"
-#include "ibmmpeg2.h"
-#include "saa7121.h"
-#include "cs8420.h"
-
-#define DEBUG(x) /* debug driver */
-#undef IDEBUG /* debug irq handler */
-#undef MDEBUG /* debug memory management */
-
-#define SAA7146_MAX 6
-
-static struct saa7146 saa7146s[SAA7146_MAX];
-
-static int saa_num; /* number of SAA7146s in use */
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-MODULE_LICENSE("GPL");
-
-#define nDebNormal 0x00480000
-#define nDebNoInc 0x00480000
-#define nDebVideo 0xd0480000
-#define nDebAudio 0xd0400000
-#define nDebDMA 0x02c80000
-
-#define oDebNormal 0x13c80000
-#define oDebNoInc 0x13c80000
-#define oDebVideo 0xd1080000
-#define oDebAudio 0xd1080000
-#define oDebDMA 0x03080000
-
-#define NewCard (saa->boardcfg[3])
-#define ChipControl (saa->boardcfg[1])
-#define NTSCFirstActive (saa->boardcfg[4])
-#define PALFirstActive (saa->boardcfg[5])
-#define NTSCLastActive (saa->boardcfg[54])
-#define PALLastActive (saa->boardcfg[55])
-#define Have2MB (saa->boardcfg[18] & 0x40)
-#define HaveCS8420 (saa->boardcfg[18] & 0x04)
-#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20)
-#define HaveCS3310 (saa->boardcfg[18] & 0x01)
-#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31])
-#define HaveCS4341 (saa->boardcfg[40] == 2)
-#define SDIType (saa->boardcfg[27])
-#define CurrentMode (saa->boardcfg[2])
-
-#define debNormal (NewCard ? nDebNormal : oDebNormal)
-#define debNoInc (NewCard ? nDebNoInc : oDebNoInc)
-#define debVideo (NewCard ? nDebVideo : oDebVideo)
-#define debAudio (NewCard ? nDebAudio : oDebAudio)
-#define debDMA (NewCard ? nDebDMA : oDebDMA)
-
-#ifdef USE_RESCUE_EEPROM_SDM275
-static unsigned char rescue_eeprom[64] = {
- 0x00, 0x01, 0x04, 0x13, 0x26, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x43, 0x63,
- 0x22, 0x01, 0x29, 0x15, 0x73, 0x00, 0x1f, 'd', 'e', 'c', 'x', 'l',
- 'd', 'v', 'a', 0x02, 0x00, 0x01, 0x00, 0xcc, 0xa4, 0x63, 0x09, 0xe2,
- 0x10, 0x00, 0x0a, 0x00, 0x02, 0x02, 'd', 'e', 'c', 'x', 'l', 'a',
- 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-};
-#endif
-
-/* ----------------------------------------------------------------------- */
-/* Hardware I2C functions */
-static void I2CWipe(struct saa7146 *saa)
-{
- int i;
- /* set i2c to ~=100kHz, abort transfer, clear busy */
- saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- saawrite(0x600, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- saawrite(0x600, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
-}
-
-/* read I2C */
-static int I2CRead(struct saa7146 *saa, unsigned char addr,
- unsigned char subaddr, int dosub)
-{
- int i;
-
- if (saaread(SAA7146_I2C_STATUS) & 0x3c)
- I2CWipe(saa);
- for (i = 0;
- i < 1000 && (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY);
- i++)
- schedule();
- if (i == 1000)
- I2CWipe(saa);
- if (dosub)
- saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
- ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
- else
- saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
- 0xf1, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- /* wait for valid data */
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
- return -1;
- if (i == 1000)
- printk("i2c setup read timeout\n");
- saawrite(0x41, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- /* wait for valid data */
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
- return -1;
- if (i == 1000)
- printk("i2c read timeout\n");
- return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
-}
-
-/* set both to write both bytes, reset it to write only b1 */
-
-static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
- unsigned char b2, int both)
-{
- int i;
- u32 data;
-
- if (saaread(SAA7146_I2C_STATUS) & 0x3c)
- I2CWipe(saa);
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (i == 1000)
- I2CWipe(saa);
- data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
- if (both)
- data |= ((b2 & 0xff) << 8) | 0xe5;
- else
- data |= 0xd1;
- saawrite(data, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
- SAA7146_MC2);
- return 0;
-}
-
-static void attach_inform(struct saa7146 *saa, int id)
-{
- int i;
-
- DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr,
- id));
- if (id == 0xa0) { /* we have rev2 or later board, fill in info */
- for (i = 0; i < 64; i++)
- saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
-#ifdef USE_RESCUE_EEPROM_SDM275
- if (saa->boardcfg[0] != 0) {
- printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE "
- "BEEN IGNORED\n", saa->nr);
- for (i = 0; i < 64; i++)
- saa->boardcfg[i] = rescue_eeprom[i];
- }
-#endif
- printk("stradis%d: config =", saa->nr);
- for (i = 0; i < 51; i++) {
- printk(" %02x", saa->boardcfg[i]);
- }
- printk("\n");
- }
-}
-
-static void I2CBusScan(struct saa7146 *saa)
-{
- int i;
- for (i = 0; i < 0xff; i += 2)
- if ((I2CRead(saa, i, 0, 0)) >= 0)
- attach_inform(saa, i);
-}
-
-static int debiwait_maxwait;
-
-static int wait_for_debi_done(struct saa7146 *saa)
-{
- int i;
-
- /* wait for registers to be programmed */
- for (i = 0; i < 100000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
- saaread(SAA7146_MC2);
- /* wait for transfer to complete */
- for (i = 0; i < 500000 &&
- (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
- saaread(SAA7146_MC2);
-
- if (i > debiwait_maxwait)
- printk("wait-for-debi-done maxwait: %d\n",
- debiwait_maxwait = i);
-
- if (i == 500000)
- return -1;
-
- return 0;
-}
-
-static int debiwrite(struct saa7146 *saa, u32 config, int addr,
- u32 val, int count)
-{
- u32 cmd;
- if (count <= 0 || count > 32764)
- return -1;
- if (wait_for_debi_done(saa) < 0)
- return -1;
- saawrite(config, SAA7146_DEBI_CONFIG);
- if (count <= 4) /* immediate transfer */
- saawrite(val, SAA7146_DEBI_AD);
- else /* block transfer */
- saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
- saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
- saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
- SAA7146_MC2);
- return 0;
-}
-
-static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
-{
- u32 result = 0;
-
- if (count > 32764 || count <= 0)
- return 0;
- if (wait_for_debi_done(saa) < 0)
- return 0;
- saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
- saawrite((count << 17) | 0x10000 | (addr & 0xffff),
- SAA7146_DEBI_COMMAND);
- saawrite(config, SAA7146_DEBI_CONFIG);
- saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
- SAA7146_MC2);
- if (count > 4) /* not an immediate transfer */
- return count;
- wait_for_debi_done(saa);
- result = saaread(SAA7146_DEBI_AD);
- if (count == 1)
- result &= 0xff;
- if (count == 2)
- result &= 0xffff;
- if (count == 3)
- result &= 0xffffff;
- return result;
-}
-
-static void do_irq_send_data(struct saa7146 *saa)
-{
- int split, audbytes, vidbytes;
-
- saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
- /* if special feature mode in effect, disable audio sending */
- if (saa->playmode != VID_PLAY_NORMAL)
- saa->audtail = saa->audhead = 0;
- if (saa->audhead <= saa->audtail)
- audbytes = saa->audtail - saa->audhead;
- else
- audbytes = 65536 - (saa->audhead - saa->audtail);
- if (saa->vidhead <= saa->vidtail)
- vidbytes = saa->vidtail - saa->vidhead;
- else
- vidbytes = 524288 - (saa->vidhead - saa->vidtail);
- if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
- saawrite(0, SAA7146_IER);
- return;
- }
- /* if at least 1 block audio waiting and audio fifo isn't full */
- if (audbytes >= 2048 && (debiread(saa, debNormal, IBM_MP2_AUD_FIFO, 2)
- & 0xff) < 60) {
- if (saa->audhead > saa->audtail)
- split = 65536 - saa->audhead;
- else
- split = 0;
- audbytes = 2048;
- if (split > 0 && split < 2048) {
- memcpy(saa->dmadebi, saa->audbuf + saa->audhead, split);
- saa->audhead = 0;
- audbytes -= split;
- } else
- split = 0;
- memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
- audbytes);
- saa->audhead += audbytes;
- saa->audhead &= 0xffff;
- debiwrite(saa, debAudio, (NewCard ? IBM_MP2_AUD_FIFO :
- IBM_MP2_AUD_FIFOW), 0, 2048);
- wake_up_interruptible(&saa->audq);
- /* if at least 1 block video waiting and video fifo isn't full */
- } else if (vidbytes >= 30720 && (debiread(saa, debNormal,
- IBM_MP2_FIFO, 2)) < 16384) {
- if (saa->vidhead > saa->vidtail)
- split = 524288 - saa->vidhead;
- else
- split = 0;
- vidbytes = 30720;
- if (split > 0 && split < 30720) {
- memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, split);
- saa->vidhead = 0;
- vidbytes -= split;
- } else
- split = 0;
- memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
- vidbytes);
- saa->vidhead += vidbytes;
- saa->vidhead &= 0x7ffff;
- debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
- IBM_MP2_FIFOW), 0, 30720);
- wake_up_interruptible(&saa->vidq);
- }
- saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
-}
-
-static void send_osd_data(struct saa7146 *saa)
-{
- int size = saa->osdtail - saa->osdhead;
- if (size > 30720)
- size = 30720;
- /* ensure some multiple of 8 bytes is transferred */
- size = 8 * ((size + 8) >> 3);
- if (size) {
- debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
- (saa->osdhead >> 3), 2);
- memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
- saa->osdhead += size;
- /* block transfer of next 8 bytes to ~32k bytes */
- debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
- }
- if (saa->osdhead >= saa->osdtail) {
- saa->osdhead = saa->osdtail = 0;
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- }
-}
-
-static irqreturn_t saa7146_irq(int irq, void *dev_id)
-{
- struct saa7146 *saa = dev_id;
- u32 stat, astat;
- int count;
- int handled = 0;
-
- count = 0;
- while (1) {
- /* get/clear interrupt status bits */
- stat = saaread(SAA7146_ISR);
- astat = stat & saaread(SAA7146_IER);
- if (!astat)
- break;
- handled = 1;
- saawrite(astat, SAA7146_ISR);
- if (astat & SAA7146_PSR_DEBI_S) {
- do_irq_send_data(saa);
- }
- if (astat & SAA7146_PSR_PIN1) {
- int istat;
- /* the following read will trigger DEBI_S */
- istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- if (istat & 1) {
- saawrite(0, SAA7146_IER);
- send_osd_data(saa);
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- }
- if (istat & 0x20) { /* Video Start */
- saa->vidinfo.frame_count++;
- }
- if (istat & 0x400) { /* Picture Start */
- /* update temporal reference */
- }
- if (istat & 0x200) { /* Picture Resolution Change */
- /* read new resolution */
- }
- if (istat & 0x100) { /* New User Data found */
- /* read new user data */
- }
- if (istat & 0x1000) { /* new GOP/SMPTE */
- /* read new SMPTE */
- }
- if (istat & 0x8000) { /* Sequence Start Code */
- /* reset frame counter, load sizes */
- saa->vidinfo.frame_count = 0;
- saa->vidinfo.h_size = 704;
- saa->vidinfo.v_size = 480;
-#if 0
- if (saa->endmarkhead != saa->endmarktail) {
- saa->audhead =
- saa->endmark[saa->endmarkhead];
- saa->endmarkhead++;
- if (saa->endmarkhead >= MAX_MARKS)
- saa->endmarkhead = 0;
- }
-#endif
- }
- if (istat & 0x4000) { /* Sequence Error Code */
- if (saa->endmarkhead != saa->endmarktail) {
- saa->audhead =
- saa->endmark[saa->endmarkhead];
- saa->endmarkhead++;
- if (saa->endmarkhead >= MAX_MARKS)
- saa->endmarkhead = 0;
- }
- }
- }
-#ifdef IDEBUG
- if (astat & SAA7146_PSR_PPEF) {
- IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PABO) {
- IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PPED) {
- IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_I1) {
- IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_I0) {
- IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_LATE1) {
- IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_LATE0) {
- IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_E1) {
- IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_E0) {
- IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_TO1) {
- IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_TO0) {
- IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_UPLD) {
- IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
- }
- if (astat & SAA7146_PSR_DEBI_E) {
- IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
- }
- if (astat & SAA7146_PSR_I2C_S) {
- IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
- }
- if (astat & SAA7146_PSR_I2C_E) {
- IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A2_IN) {
- IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A2_OUT) {
- IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A1_IN) {
- IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A1_OUT) {
- IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
- }
- if (astat & SAA7146_PSR_AFOU) {
- IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
- }
- if (astat & SAA7146_PSR_V_PE) {
- IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
- }
- if (astat & SAA7146_PSR_VFOU) {
- IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
- }
- if (astat & SAA7146_PSR_FIDA) {
- IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
- }
- if (astat & SAA7146_PSR_FIDB) {
- IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN3) {
- IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN2) {
- IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN0) {
- IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_ECS) {
- IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
- }
- if (astat & SAA7146_PSR_EC3S) {
- IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
- }
- if (astat & SAA7146_PSR_EC0S) {
- IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
- }
-#endif
- count++;
- if (count > 15)
- printk(KERN_WARNING "stradis%d: irq loop %d\n",
- saa->nr, count);
- if (count > 20) {
- saawrite(0, SAA7146_IER);
- printk(KERN_ERR
- "stradis%d: IRQ loop cleared\n", saa->nr);
- }
- }
- return IRQ_RETVAL(handled);
-}
-
-static int ibm_send_command(struct saa7146 *saa,
- int command, int data, int chain)
-{
- int i;
-
- if (chain)
- debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1)| 1,2);
- else
- debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
- for (i = 0; i < 100 &&
- (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
- schedule();
- if (i == 100)
- return -1;
- return 0;
-}
-
-static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
-{
- I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
- I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
-}
-
-static void initialize_cs4341(struct saa7146 *saa)
-{
- int i;
- for (i = 0; i < 200; i++) {
- /* auto mute off, power on, no de-emphasis */
- /* I2S data up to 24-bit 64xFs internal SCLK */
- I2CWrite(saa, 0x22, 0x01, 0x11, 2);
- /* ATAPI mixer settings */
- I2CWrite(saa, 0x22, 0x02, 0x49, 2);
- /* attenuation left 3db */
- I2CWrite(saa, 0x22, 0x03, 0x00, 2);
- /* attenuation right 3db */
- I2CWrite(saa, 0x22, 0x04, 0x00, 2);
- I2CWrite(saa, 0x22, 0x01, 0x10, 2);
- if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
- break;
- schedule();
- }
- printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
- return;
-}
-
-static void initialize_cs8420(struct saa7146 *saa, int pro)
-{
- int i;
- u8 *sequence;
- if (pro)
- sequence = mode8420pro;
- else
- sequence = mode8420con;
- for (i = 0; i < INIT8420LEN; i++)
- I2CWrite(saa, 0x20, init8420[i * 2], init8420[i * 2 + 1], 2);
- for (i = 0; i < MODE8420LEN; i++)
- I2CWrite(saa, 0x20, sequence[i * 2], sequence[i * 2 + 1], 2);
- printk("stradis%d: CS8420 initialized\n", saa->nr);
-}
-
-static void initialize_saa7121(struct saa7146 *saa, int dopal)
-{
- int i, mod;
- u8 *sequence;
- if (dopal)
- sequence = init7121pal;
- else
- sequence = init7121ntsc;
- mod = saaread(SAA7146_PSR) & 0x08;
- /* initialize PAL/NTSC video encoder */
- for (i = 0; i < INIT7121LEN; i++) {
- if (NewCard) { /* handle new card encoder differences */
- if (sequence[i * 2] == 0x3a)
- I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
- else if (sequence[i * 2] == 0x6b)
- I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
- else if (sequence[i * 2] == 0x6c)
- I2CWrite(saa, 0x88, 0x6c,
- dopal ? 0x09 : 0xf5, 2);
- else if (sequence[i * 2] == 0x6d)
- I2CWrite(saa, 0x88, 0x6d,
- dopal ? 0x20 : 0x00, 2);
- else if (sequence[i * 2] == 0x7a)
- I2CWrite(saa, 0x88, 0x7a,
- dopal ? (PALFirstActive - 1) :
- (NTSCFirstActive - 4), 2);
- else if (sequence[i * 2] == 0x7b)
- I2CWrite(saa, 0x88, 0x7b,
- dopal ? PALLastActive :
- NTSCLastActive, 2);
- else
- I2CWrite(saa, 0x88, sequence[i * 2],
- sequence[i * 2 + 1], 2);
- } else {
- if (sequence[i * 2] == 0x6b && mod)
- I2CWrite(saa, 0x88, 0x6b,
- (sequence[i * 2 + 1] ^ 0x09), 2);
- else if (sequence[i * 2] == 0x7a)
- I2CWrite(saa, 0x88, 0x7a,
- dopal ? (PALFirstActive - 1) :
- (NTSCFirstActive - 4), 2);
- else if (sequence[i * 2] == 0x7b)
- I2CWrite(saa, 0x88, 0x7b,
- dopal ? PALLastActive :
- NTSCLastActive, 2);
- else
- I2CWrite(saa, 0x88, sequence[i * 2],
- sequence[i * 2 + 1], 2);
- }
- }
-}
-
-static void set_genlock_offset(struct saa7146 *saa, int noffset)
-{
- int nCode;
- int PixelsPerLine = 858;
- if (CurrentMode == VIDEO_MODE_PAL)
- PixelsPerLine = 864;
- if (noffset > 500)
- noffset = 500;
- else if (noffset < -500)
- noffset = -500;
- nCode = noffset + 0x100;
- if (nCode == 1)
- nCode = 0x401;
- else if (nCode < 1)
- nCode = 0x400 + PixelsPerLine + nCode;
- debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
-}
-
-static void set_out_format(struct saa7146 *saa, int mode)
-{
- initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
- saa->boardcfg[2] = mode;
- /* do not adjust analog video parameters here, use saa7121 init */
- /* you will affect the SDI output on the new card */
- if (mode == VIDEO_MODE_PAL) { /* PAL */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
- mdelay(50);
- saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
- if (NewCard) {
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, 0xe100, 2);
- mdelay(50);
- }
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- NewCard ? 0xe500 : 0x6500, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
- (1 << 8) |
- (NewCard ? PALFirstActive : PALFirstActive - 6), 2);
- } else { /* NTSC */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
- mdelay(50);
- saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- NewCard ? 0xe100 : 0x6100, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
- (1 << 8) |
- (NewCard ? NTSCFirstActive : NTSCFirstActive - 6), 2);
- }
-}
-
-/* Intialize bitmangler to map from a byte value to the mangled word that
- * must be output to program the Xilinx part through the DEBI port.
- * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
- * transfer FPGA code, init IBM chip, transfer IBM microcode
- * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
- */
-static u16 bitmangler[256];
-
-static int initialize_fpga(struct video_code *bitdata)
-{
- int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
- u16 *dmabuf;
- u8 *newdma;
- struct saa7146 *saa;
-
- /* verify fpga code */
- for (startindex = 0; startindex < bitdata->datasize; startindex++)
- if (bitdata->data[startindex] == 255)
- break;
- if (startindex == bitdata->datasize) {
- printk(KERN_INFO "stradis: bad fpga code\n");
- return -1;
- }
- /* initialize all detected cards */
- for (num = 0; num < saa_num; num++) {
- saa = &saa7146s[num];
- if (saa->boardcfg[0] > 20)
- continue; /* card was programmed */
- loadtwo = (saa->boardcfg[18] & 0x10);
- if (!NewCard) /* we have an old board */
- for (i = 0; i < 256; i++)
- bitmangler[i] = ((i & 0x01) << 15) |
- ((i & 0x02) << 6) | ((i & 0x04) << 4) |
- ((i & 0x08) << 9) | ((i & 0x10) << 7) |
- ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
- ((i & 0x80) >> 7);
- else /* else we have a new board */
- for (i = 0; i < 256; i++)
- bitmangler[i] = ((i & 0x01) << 7) |
- ((i & 0x02) << 5) | ((i & 0x04) << 3) |
- ((i & 0x08) << 1) | ((i & 0x10) >> 1) |
- ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
- ((i & 0x80) >> 7);
-
- dmabuf = (u16 *) saa->dmadebi;
- newdma = (u8 *) saa->dmadebi;
- if (NewCard) { /* SDM2xxx */
- if (!strncmp(bitdata->loadwhat, "decoder2", 8))
- continue; /* fpga not for this card */
- if (!strncmp(&saa->boardcfg[42], bitdata->loadwhat, 8))
- loadfile = 1;
- else if (loadtwo && !strncmp(&saa->boardcfg[19],
- bitdata->loadwhat, 8))
- loadfile = 2;
- else if (!saa->boardcfg[42] && !strncmp("decxl",
- bitdata->loadwhat, 8))
- loadfile = 1; /* special */
- else
- continue; /* fpga not for this card */
- if (loadfile != 1 && loadfile != 2)
- continue; /* skip to next card */
- if (saa->boardcfg[0] && loadfile == 1)
- continue; /* skip to next card */
- if (saa->boardcfg[0] != 1 && loadfile == 2)
- continue; /* skip to next card */
- saa->boardcfg[0]++; /* mark fpga handled */
- printk("stradis%d: loading %s\n", saa->nr,
- bitdata->loadwhat);
- if (loadtwo && loadfile == 2)
- goto send_fpga_stuff;
- /* turn on the Audio interface to set PROG low */
- saawrite(0x00400040, SAA7146_GPIO_CTRL);
- saaread(SAA7146_PSR); /* ensure posted write */
- /* wait for everyone to reset */
- mdelay(10);
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- } else { /* original card */
- if (strncmp(bitdata->loadwhat, "decoder2", 8))
- continue; /* fpga not for this card */
- /* Pull the Xilinx PROG signal WS3 low */
- saawrite(0x02000200, SAA7146_MC1);
- /* Turn on the Audio interface so can set PROG low */
- saawrite(0x000000c0, SAA7146_ACON1);
- /* Pull the Xilinx INIT signal (GPIO2) low */
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- /* Make sure everybody resets */
- saaread(SAA7146_PSR); /* ensure posted write */
- mdelay(10);
- /* Release the Xilinx PROG signal */
- saawrite(0x00000000, SAA7146_ACON1);
- /* Turn off the Audio interface */
- saawrite(0x02000000, SAA7146_MC1);
- }
- /* Release Xilinx INIT signal (WS2) */
- saawrite(0x00000000, SAA7146_GPIO_CTRL);
- /* Wait for the INIT to go High */
- for (i = 0;
- i < 10000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
- i++)
- schedule();
- if (i == 1000) {
- printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
- return -1;
- }
-send_fpga_stuff:
- if (NewCard) {
- for (i = startindex; i < bitdata->datasize; i++)
- newdma[i - startindex] =
- bitmangler[bitdata->data[i]];
- debiwrite(saa, 0x01420000, 0, 0,
- ((bitdata->datasize - startindex) + 5));
- if (loadtwo && loadfile == 1) {
- printk("stradis%d: awaiting 2nd FPGA bitfile\n",
- saa->nr);
- continue; /* skip to next card */
- }
- } else {
- for (i = startindex; i < bitdata->datasize; i++)
- dmabuf[i - startindex] =
- bitmangler[bitdata->data[i]];
- debiwrite(saa, 0x014a0000, 0, 0,
- ((bitdata->datasize - startindex) + 5) * 2);
- }
- for (i = 0;
- i < 1000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
- i++)
- schedule();
- if (i == 1000) {
- printk(KERN_INFO "stradis%d: FPGA load failed\n",
- saa->nr);
- failure++;
- continue;
- }
- if (!NewCard) {
- /* Pull the Xilinx INIT signal (GPIO2) low */
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- saaread(SAA7146_PSR); /* ensure posted write */
- mdelay(2);
- saawrite(0x00000000, SAA7146_GPIO_CTRL);
- mdelay(2);
- }
- printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
- saa->boardcfg[0] = 26; /* mark fpga programmed */
- /* set VXCO to its lowest frequency */
- debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
- if (NewCard) {
- /* mute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
- 0, 2);
- /* set VXCO to PWM mode, release reset, blank on */
- debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
- mdelay(10);
- /* unmute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CTL0,
- 0x2020, 2);
- }
- /* set source Black */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
- saa->boardcfg[4] = 22; /* set NTSC First Active Line */
- saa->boardcfg[5] = 23; /* set PAL First Active Line */
- saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */
- saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */
- set_out_format(saa, VIDEO_MODE_NTSC);
- mdelay(50);
- /* begin IBM chip init */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
- saaread(SAA7146_PSR); /* wait for reset */
- mdelay(5);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
- debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
- if (NewCard) {
- mdelay(5);
- /* set i2s rate converter to 48KHz */
- debiwrite(saa, debNormal, 0x80c0, 6, 2);
- /* we must init CS8420 first since rev b pulls i2s */
- /* master clock low and CS4341 needs i2s master to */
- /* run the i2c port. */
- if (HaveCS8420)
- /* 0=consumer, 1=pro */
- initialize_cs8420(saa, 0);
-
- mdelay(5);
- if (HaveCS4341)
- initialize_cs4341(saa);
- }
- debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
- debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
- if (NewCard)
- set_genlock_offset(saa, 0);
- debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
-#if 0
- /* enable genlock */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
-#else
- /* disable genlock */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
-#endif
- }
-
- return failure;
-}
-
-static int do_ibm_reset(struct saa7146 *saa)
-{
- /* failure if decoder not previously programmed */
- if (saa->boardcfg[0] < 37)
- return -EIO;
- /* mute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
- /* disable interrupts */
- saawrite(0, SAA7146_IER);
- saa->audhead = saa->audtail = 0;
- saa->vidhead = saa->vidtail = 0;
- /* tristate debi bus, disable debi transfers */
- saawrite(0x00880000, SAA7146_MC1);
- /* ensure posted write */
- saaread(SAA7146_MC1);
- mdelay(50);
- /* re-enable debi transfers */
- saawrite(0x00880088, SAA7146_MC1);
- /* set source Black */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
- /* begin IBM chip init */
- set_out_format(saa, CurrentMode);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
- saaread(SAA7146_PSR); /* wait for reset */
- mdelay(5);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
- debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
- if (NewCard) {
- mdelay(5);
- /* set i2s rate converter to 48KHz */
- debiwrite(saa, debNormal, 0x80c0, 6, 2);
- /* we must init CS8420 first since rev b pulls i2s */
- /* master clock low and CS4341 needs i2s master to */
- /* run the i2c port. */
- if (HaveCS8420)
- /* 0=consumer, 1=pro */
- initialize_cs8420(saa, 1);
-
- mdelay(5);
- if (HaveCS4341)
- initialize_cs4341(saa);
- }
- debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
- debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
- if (NewCard)
- set_genlock_offset(saa, 0);
- debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
- if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
- (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
- printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
- }
- if (HaveCS3310) {
- int i = CS3310MaxLvl;
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i << 8)| i),2);
- }
- /* start video decoder */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- /* 256k vid, 3520 bytes aud */
- debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- /* enable buffer threshold irq */
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- /* clear pending interrupts */
- debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
-
- return 0;
-}
-
-/* load the decoder microcode */
-static int initialize_ibmmpeg2(struct video_code *microcode)
-{
- int i, num;
- struct saa7146 *saa;
-
- for (num = 0; num < saa_num; num++) {
- saa = &saa7146s[num];
- /* check that FPGA is loaded */
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
- i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2);
- if (i != 0xa55a) {
- printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
- saa->nr, i);
-#if 0
- return -1;
-#endif
- }
- if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
- if (saa->boardcfg[0] > 27)
- continue; /* skip to next card */
- /* load video control store */
- saa->boardcfg[1] = 0x13; /* no-sync default */
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
- for (i = 0; i < microcode->datasize / 2; i++)
- debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
- (microcode->data[i * 2] << 8) |
- microcode->data[i * 2 + 1], 2);
- debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- saa->boardcfg[0] = 28;
- }
- if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
- if (saa->boardcfg[0] > 35)
- continue; /* skip to next card */
- /* load audio control store */
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
- for (i = 0; i < microcode->datasize; i++)
- debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
- microcode->data[i], 1);
- debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
- if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
- 0xe000, 1)) {
- printk(KERN_ERR "stradis%d: IBM config "
- "failed\n", saa->nr);
- return -1;
- }
- /* set PWM to center value */
- if (NewCard) {
- debiwrite(saa, debNormal, XILINX_PWM,
- saa->boardcfg[14] +
- (saa->boardcfg[13] << 8), 2);
- } else
- debiwrite(saa, debNormal, XILINX_PWM, 0x46, 2);
-
- if (HaveCS3310) {
- i = CS3310MaxLvl;
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
- (i << 8) | i, 2);
- }
- printk(KERN_INFO "stradis%d: IBM MPEGCD%d Inited\n",
- saa->nr, 18 + (debiread(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, 2) >> 12));
- /* start video decoder */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037,
- 2); /* 256k vid, 3520 bytes aud */
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- /* enable buffer threshold irq */
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- /* enable gpio irq */
- saawrite(0x00002000, SAA7146_GPIO_CTRL);
- /* enable decoder output to HPS */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
- saa->boardcfg[0] = 37;
- }
- }
-
- return 0;
-}
-
-static u32 palette2fmt[] = { /* some of these YUV translations are wrong */
- 0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
- 0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
- 0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
-};
-static int bpp2fmt[4] = {
- VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
- VIDEO_PALETTE_RGB32
-};
-
-/* I wish I could find a formula to calculate these... */
-static u32 h_prescale[64] = {
- 0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
- 0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
- 0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
- 0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
- 0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
- 0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
- 0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
- 0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
- 0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
- 0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
- 0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
-};
-static u32 v_gain[64] = {
- 0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
- 0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
- 0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-};
-
-static void saa7146_set_winsize(struct saa7146 *saa)
-{
- u32 format;
- int offset, yacl, ysci;
- saa->win.color_fmt = format =
- (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
- palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
- offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
- saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
- saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
- saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
- saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
- SAA7146_PROT_ADDR1);
- saawrite(0, SAA7146_PAGE1);
- saawrite(format | 0x60, SAA7146_CLIP_FORMAT_CTRL);
- offset = (704 / (saa->win.width - 1)) & 0x3f;
- saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
- offset = (720896 / saa->win.width) / (offset + 1);
- saawrite((offset << 12) | 0x0c, SAA7146_HPS_H_SCALE);
- if (CurrentMode == VIDEO_MODE_NTSC) {
- yacl = /*(480 / saa->win.height - 1) & 0x3f */ 0;
- ysci = 1024 - (saa->win.height * 1024 / 480);
- } else {
- yacl = /*(576 / saa->win.height - 1) & 0x3f */ 0;
- ysci = 1024 - (saa->win.height * 1024 / 576);
- }
- saawrite((1 << 31) | (ysci << 21) | (yacl << 15), SAA7146_HPS_V_SCALE);
- saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
- saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
- SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
- SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), SAA7146_MC2);
-}
-
-/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
- * bitmap is fixed width, 128 bytes (1024 pixels represented)
- * arranged most-sigificant-bit-left in 32-bit words
- * based on saa7146 clipping hardware, it swaps bytes if LE
- * much of this makes up for egcs brain damage -- so if you
- * are wondering "why did he do this?" it is because the C
- * was adjusted to generate the optimal asm output without
- * writing non-portable __asm__ directives.
- */
-
-static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
-{
- register int startword, endword;
- register u32 bitsleft, bitsright;
- u32 *temp;
- if (x < 0) {
- w += x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- y = 0;
- }
- if (w <= 0 || h <= 0 || x > 1023 || y > 639)
- return; /* throw away bad clips */
- if (x + w > 1024)
- w = 1024 - x;
- if (y + h > 640)
- h = 640 - y;
- startword = (x >> 5);
- endword = ((x + w) >> 5);
- bitsleft = (0xffffffff >> (x & 31));
- bitsright = (0xffffffff << (~((x + w) - (endword << 5))));
- temp = &clipmap[(y << 5) + startword];
- w = endword - startword;
- if (!w) {
- bitsleft |= bitsright;
- for (y = 0; y < h; y++) {
- *temp |= bitsleft;
- temp += 32;
- }
- } else {
- for (y = 0; y < h; y++) {
- *temp++ |= bitsleft;
- for (x = 1; x < w; x++)
- *temp++ = 0xffffffff;
- *temp |= bitsright;
- temp += (32 - w);
- }
- }
-}
-
-static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
-{
- int i, width, height;
- u32 *clipmap;
-
- clipmap = saa->dmavid2;
- if ((width = saa->win.width) > 1023)
- width = 1023; /* sanity check */
- if ((height = saa->win.height) > 640)
- height = 639; /* sanity check */
- if (ncr > 0) { /* rectangles pased */
- /* convert rectangular clips to a bitmap */
- memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
- for (i = 0; i < ncr; i++)
- clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
- cr[i].width, cr[i].height);
- }
- /* clip against viewing window AND screen
- so we do not have to rely on the user program
- */
- clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
- (saa->win.swidth - saa->win.x) : width, 0, 1024, 768);
- clip_draw_rectangle(clipmap, 0,
- (saa->win.y + height > saa->win.sheight) ?
- (saa->win.sheight - saa->win.y) : height, 1024, 768);
- if (saa->win.x < 0)
- clip_draw_rectangle(clipmap, 0, 0, -saa->win.x, 768);
- if (saa->win.y < 0)
- clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
-}
-
-static long saa_ioctl(struct file *file,
- unsigned int cmd, unsigned long argl)
-{
- struct saa7146 *saa = file->private_data;
- void __user *arg = (void __user *)argl;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability b;
- strcpy(b.name, saa->video_dev.name);
- b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
- VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
- VID_TYPE_SCALES;
- b.channels = 1;
- b.audios = 1;
- b.maxwidth = 768;
- b.maxheight = 576;
- b.minwidth = 32;
- b.minheight = 32;
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture p = saa->picture;
- if (saa->win.depth == 8)
- p.palette = VIDEO_PALETTE_HI240;
- if (saa->win.depth == 15)
- p.palette = VIDEO_PALETTE_RGB555;
- if (saa->win.depth == 16)
- p.palette = VIDEO_PALETTE_RGB565;
- if (saa->win.depth == 24)
- p.palette = VIDEO_PALETTE_RGB24;
- if (saa->win.depth == 32)
- p.palette = VIDEO_PALETTE_RGB32;
- if (copy_to_user(arg, &p, sizeof(p)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture p;
- u32 format;
- if (copy_from_user(&p, arg, sizeof(p)))
- return -EFAULT;
- if (p.palette < ARRAY_SIZE(palette2fmt)) {
- format = palette2fmt[p.palette];
- saa->win.color_fmt = format;
- saawrite(format | 0x60,
- SAA7146_CLIP_FORMAT_CTRL);
- }
- saawrite(((p.brightness & 0xff00) << 16) |
- ((p.contrast & 0xfe00) << 7) |
- ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
- saa->picture = p;
- /* upload changed registers */
- saawrite(((SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V) << 16) |
- SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V, SAA7146_MC2);
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window vw;
- struct video_clip *vcp = NULL;
-
- if (copy_from_user(&vw, arg, sizeof(vw)))
- return -EFAULT;
-
- /* stop capture */
- if (vw.flags || vw.width < 16 || vw.height < 16) {
- saawrite((SAA7146_MC1_TR_E_1 << 16),
- SAA7146_MC1);
- return -EINVAL;
- }
- /* 32-bit align start and adjust width */
- if (saa->win.bpp < 4) {
- int i = vw.x;
- vw.x = (vw.x + 3) & ~3;
- i = vw.x - i;
- vw.width -= i;
- }
- saa->win.x = vw.x;
- saa->win.y = vw.y;
- saa->win.width = vw.width;
- if (saa->win.width > 768)
- saa->win.width = 768;
- saa->win.height = vw.height;
- if (CurrentMode == VIDEO_MODE_NTSC) {
- if (saa->win.height > 480)
- saa->win.height = 480;
- } else {
- if (saa->win.height > 576)
- saa->win.height = 576;
- }
-
- /* stop capture */
- saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
- saa7146_set_winsize(saa);
-
- /*
- * Do any clips.
- */
- if (vw.clipcount < 0) {
- if (copy_from_user(saa->dmavid2, vw.clips,
- VIDEO_CLIPMAP_SIZE))
- return -EFAULT;
- } else if (vw.clipcount > 16384) {
- return -EINVAL;
- } else if (vw.clipcount > 0) {
- vcp = vmalloc(sizeof(struct video_clip) *
- vw.clipcount);
- if (vcp == NULL)
- return -ENOMEM;
- if (copy_from_user(vcp, vw.clips,
- sizeof(struct video_clip) *
- vw.clipcount)) {
- vfree(vcp);
- return -EFAULT;
- }
- } else /* nothing clipped */
- memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
-
- make_clip_tab(saa, vcp, vw.clipcount);
- if (vw.clipcount > 0)
- vfree(vcp);
-
- /* start capture & clip dma if we have an address */
- if ((saa->cap & 3) && saa->win.vidadr != 0)
- saawrite(((SAA7146_MC1_TR_E_1 |
- SAA7146_MC1_TR_E_2) << 16) | 0xffff,
- SAA7146_MC1);
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window vw;
- vw.x = saa->win.x;
- vw.y = saa->win.y;
- vw.width = saa->win.width;
- vw.height = saa->win.height;
- vw.chromakey = 0;
- vw.flags = 0;
- if (copy_to_user(arg, &vw, sizeof(vw)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCCAPTURE:
- {
- int v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v == 0) {
- saa->cap &= ~1;
- saawrite((SAA7146_MC1_TR_E_1 << 16),
- SAA7146_MC1);
- } else {
- if (saa->win.vidadr == 0 || saa->win.width == 0
- || saa->win.height == 0)
- return -EINVAL;
- saa->cap |= 1;
- saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
- SAA7146_MC1);
- }
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer v;
- v.base = (void *)saa->win.vidadr;
- v.height = saa->win.sheight;
- v.width = saa->win.swidth;
- v.depth = saa->win.depth;
- v.bytesperline = saa->win.bpl;
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
-
- }
- case VIDIOCSFBUF:
- {
- struct video_buffer v;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
- v.depth != 24 && v.depth != 32 && v.width > 16 &&
- v.height > 16 && v.bytesperline > 16)
- return -EINVAL;
- if (v.base)
- saa->win.vidadr = (unsigned long)v.base;
- saa->win.sheight = v.height;
- saa->win.swidth = v.width;
- saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
- saa->win.depth = v.depth;
- saa->win.bpl = v.bytesperline;
-
- DEBUG(printk("Display at %p is %d by %d, bytedepth %d, "
- "bpl %d\n", v.base, v.width, v.height,
- saa->win.bpp, saa->win.bpl));
- saa7146_set_winsize(saa);
- return 0;
- }
- case VIDIOCKEY:
- {
- /* Will be handled higher up .. */
- return 0;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio v;
- v = saa->audio_dev;
- v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
- v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- strcpy(v.name, "MPEG");
- v.mode = VIDEO_SOUND_STEREO;
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio v;
- int i;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- i = (~(v.volume >> 8)) & 0xff;
- if (!HaveCS4341) {
- if (v.flags & VIDEO_AUDIO_MUTE)
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN, 0xffff, 2);
- if (!(v.flags & VIDEO_AUDIO_MUTE))
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN, 0x0000, 2);
- if (v.flags & VIDEO_AUDIO_VOLUME)
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN,
- (i << 8) | i, 2);
- } else {
- if (v.flags & VIDEO_AUDIO_MUTE)
- cs4341_setlevel(saa, 0xff, 0xff);
- if (!(v.flags & VIDEO_AUDIO_MUTE))
- cs4341_setlevel(saa, 0, 0);
- if (v.flags & VIDEO_AUDIO_VOLUME)
- cs4341_setlevel(saa, i, i);
- }
- saa->audio_dev = v;
- return 0;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit vu;
- vu.video = saa->video_dev.minor;
- vu.vbi = VIDEO_NO_UNIT;
- vu.radio = VIDEO_NO_UNIT;
- vu.audio = VIDEO_NO_UNIT;
- vu.teletext = VIDEO_NO_UNIT;
- if (copy_to_user(arg, &vu, sizeof(vu)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSPLAYMODE:
- {
- struct video_play_mode pmode;
- if (copy_from_user((void *)&pmode, arg,
- sizeof(struct video_play_mode)))
- return -EFAULT;
- switch (pmode.mode) {
- case VID_PLAY_VID_OUT_MODE:
- if (pmode.p1 != VIDEO_MODE_NTSC &&
- pmode.p1 != VIDEO_MODE_PAL)
- return -EINVAL;
- set_out_format(saa, pmode.p1);
- return 0;
- case VID_PLAY_GENLOCK:
- debiwrite(saa, debNormal, XILINX_CTL0,
- pmode.p1 ? 0x8000 : 0x8080, 2);
- if (NewCard)
- set_genlock_offset(saa, pmode.p2);
- return 0;
- case VID_PLAY_NORMAL:
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_PAUSE:
- /* IBM removed the PAUSE command */
- /* they say use SINGLE_FRAME now */
- case VID_PLAY_SINGLE_FRAME:
- ibm_send_command(saa, IBM_MP2_SINGLE_FRAME,0,0);
- if (saa->playmode == pmode.mode) {
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- }
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_FAST_FORWARD:
- ibm_send_command(saa, IBM_MP2_FAST_FORWARD,0,0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_SLOW_MOTION:
- ibm_send_command(saa, IBM_MP2_SLOW_MOTION,
- pmode.p1, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_IMMEDIATE_NORMAL:
- /* ensure transfers resume */
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_IMED_NORM_PLAY,
- 0, 0);
- saa->playmode = VID_PLAY_NORMAL;
- return 0;
- case VID_PLAY_SWITCH_CHANNELS:
- saa->audhead = saa->audtail = 0;
- saa->vidhead = saa->vidtail = 0;
- ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,1);
- ibm_send_command(saa, IBM_MP2_RESET_AUD_RATE,
- 0, 1);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- 0, 2);
- ibm_send_command(saa, IBM_MP2_CHANNEL_SWITCH,
- 0, 1);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- saa->playmode = VID_PLAY_NORMAL;
- return 0;
- case VID_PLAY_FREEZE_FRAME:
- ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_STILL_MODE:
- ibm_send_command(saa, IBM_MP2_SET_STILL_MODE,
- 0, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_MASTER_MODE:
- if (pmode.p1 == VID_PLAY_MASTER_NONE)
- saa->boardcfg[1] = 0x13;
- else if (pmode.p1 == VID_PLAY_MASTER_VIDEO)
- saa->boardcfg[1] = 0x23;
- else if (pmode.p1 == VID_PLAY_MASTER_AUDIO)
- saa->boardcfg[1] = 0x43;
- else
- return -EINVAL;
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- return 0;
- case VID_PLAY_ACTIVE_SCANLINES:
- if (CurrentMode == VIDEO_MODE_PAL) {
- if (pmode.p1 < 1 || pmode.p2 > 625)
- return -EINVAL;
- saa->boardcfg[5] = pmode.p1;
- saa->boardcfg[55] = (pmode.p1 +
- (pmode.p2 / 2) - 1) & 0xff;
- } else {
- if (pmode.p1 < 4 || pmode.p2 > 525)
- return -EINVAL;
- saa->boardcfg[4] = pmode.p1;
- saa->boardcfg[54] = (pmode.p1 +
- (pmode.p2 / 2) - 4) & 0xff;
- }
- set_out_format(saa, CurrentMode);
- case VID_PLAY_RESET:
- return do_ibm_reset(saa);
- case VID_PLAY_END_MARK:
- if (saa->endmarktail < saa->endmarkhead) {
- if (saa->endmarkhead -
- saa->endmarktail < 2)
- return -ENOSPC;
- } else if (saa->endmarkhead <=saa->endmarktail){
- if (saa->endmarktail - saa->endmarkhead
- > (MAX_MARKS - 2))
- return -ENOSPC;
- } else
- return -ENOSPC;
- saa->endmark[saa->endmarktail] = saa->audtail;
- saa->endmarktail++;
- if (saa->endmarktail >= MAX_MARKS)
- saa->endmarktail = 0;
- }
- return -EINVAL;
- }
- case VIDIOCSWRITEMODE:
- {
- int mode;
- if (copy_from_user((void *)&mode, arg, sizeof(int)))
- return -EFAULT;
- if (mode == VID_WRITE_MPEG_AUD ||
- mode == VID_WRITE_MPEG_VID ||
- mode == VID_WRITE_CC ||
- mode == VID_WRITE_TTX ||
- mode == VID_WRITE_OSD) {
- saa->writemode = mode;
- return 0;
- }
- return -EINVAL;
- }
- case VIDIOCSMICROCODE:
- {
- struct video_code ucode;
- __u8 *udata;
- int i;
- if (copy_from_user(&ucode, arg, sizeof(ucode)))
- return -EFAULT;
- if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
- strncmp(ucode.loadwhat, "dec", 3))
- return -EINVAL;
- if ((udata = vmalloc(ucode.datasize)) == NULL)
- return -ENOMEM;
- if (copy_from_user(udata, ucode.data, ucode.datasize)) {
- vfree(udata);
- return -EFAULT;
- }
- ucode.data = udata;
- if (!strncmp(ucode.loadwhat, "decoder.aud", 11) ||
- !strncmp(ucode.loadwhat, "decoder.vid", 11))
- i = initialize_ibmmpeg2(&ucode);
- else
- i = initialize_fpga(&ucode);
- vfree(udata);
- if (i)
- return -EINVAL;
- return 0;
-
- }
- case VIDIOCGCHAN: /* this makes xawtv happy */
- {
- struct video_channel v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- v.flags = VIDEO_VC_AUDIO;
- v.tuners = 0;
- v.type = VID_TYPE_MPEG_DECODER;
- v.norm = CurrentMode;
- strcpy(v.name, "MPEG2");
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSCHAN: /* this makes xawtv happy */
- {
- struct video_channel v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- /* do nothing */
- return 0;
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static int saa_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct saa7146 *saa = file->private_data;
- printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
- return -EINVAL;
-}
-
-static ssize_t saa_read(struct file *file, char __user * buf,
- size_t count, loff_t * ppos)
-{
- return -EINVAL;
-}
-
-static ssize_t saa_write(struct file *file, const char __user * buf,
- size_t count, loff_t * ppos)
-{
- struct saa7146 *saa = file->private_data;
- unsigned long todo = count;
- int blocksize, split;
- unsigned long flags;
-
- while (todo > 0) {
- if (saa->writemode == VID_WRITE_MPEG_AUD) {
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->audhead <= saa->audtail)
- blocksize = 65536 -
- (saa->audtail - saa->audhead);
- else
- blocksize = saa->audhead - saa->audtail;
- spin_unlock_irqrestore(&saa->lock, flags);
- if (blocksize < 16384) {
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- /* wait for buffer space to open */
- interruptible_sleep_on(&saa->audq);
- }
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->audhead <= saa->audtail) {
- blocksize = 65536 -
- (saa->audtail - saa->audhead);
- split = 65536 - saa->audtail;
- } else {
- blocksize = saa->audhead - saa->audtail;
- split = 65536;
- }
- spin_unlock_irqrestore(&saa->lock, flags);
- blocksize--;
- if (blocksize > todo)
- blocksize = todo;
- /* double check that we really have space */
- if (!blocksize)
- return -ENOSPC;
- if (split < blocksize) {
- if (copy_from_user(saa->audbuf +
- saa->audtail, buf, split))
- return -EFAULT;
- buf += split;
- todo -= split;
- blocksize -= split;
- saa->audtail = 0;
- }
- if (copy_from_user(saa->audbuf + saa->audtail, buf,
- blocksize))
- return -EFAULT;
- saa->audtail += blocksize;
- todo -= blocksize;
- buf += blocksize;
- saa->audtail &= 0xffff;
- } else if (saa->writemode == VID_WRITE_MPEG_VID) {
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->vidhead <= saa->vidtail)
- blocksize = 524288 -
- (saa->vidtail - saa->vidhead);
- else
- blocksize = saa->vidhead - saa->vidtail;
- spin_unlock_irqrestore(&saa->lock, flags);
- if (blocksize < 65536) {
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- /* wait for buffer space to open */
- interruptible_sleep_on(&saa->vidq);
- }
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->vidhead <= saa->vidtail) {
- blocksize = 524288 -
- (saa->vidtail - saa->vidhead);
- split = 524288 - saa->vidtail;
- } else {
- blocksize = saa->vidhead - saa->vidtail;
- split = 524288;
- }
- spin_unlock_irqrestore(&saa->lock, flags);
- blocksize--;
- if (blocksize > todo)
- blocksize = todo;
- /* double check that we really have space */
- if (!blocksize)
- return -ENOSPC;
- if (split < blocksize) {
- if (copy_from_user(saa->vidbuf +
- saa->vidtail, buf, split))
- return -EFAULT;
- buf += split;
- todo -= split;
- blocksize -= split;
- saa->vidtail = 0;
- }
- if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
- blocksize))
- return -EFAULT;
- saa->vidtail += blocksize;
- todo -= blocksize;
- buf += blocksize;
- saa->vidtail &= 0x7ffff;
- } else if (saa->writemode == VID_WRITE_OSD) {
- if (count > 131072)
- return -ENOSPC;
- if (copy_from_user(saa->osdbuf, buf, count))
- return -EFAULT;
- buf += count;
- saa->osdhead = 0;
- saa->osdtail = count;
- debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- debiread(saa, debNormal,
- IBM_MP2_DISP_MODE, 2) | 1, 2);
- /* trigger osd data transfer */
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- }
- }
- return count;
-}
-
-static int saa_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
-
- lock_kernel();
- file->private_data = saa;
-
- saa->user++;
- if (saa->user > 1) {
- unlock_kernel();
- return 0; /* device open already, don't reset */
- }
- saa->writemode = VID_WRITE_MPEG_VID; /* default to video */
- unlock_kernel();
- return 0;
-}
-
-static int saa_release(struct file *file)
-{
- struct saa7146 *saa = file->private_data;
- saa->user--;
-
- if (saa->user > 0) /* still someone using device */
- return 0;
- saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */
- return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
- .owner = THIS_MODULE,
- .open = saa_open,
- .release = saa_release,
- .ioctl = saa_ioctl,
- .read = saa_read,
- .write = saa_write,
- .mmap = saa_mmap,
-};
-
-/* template for video_device-structure */
-static struct video_device saa_template = {
- .name = "SAA7146A",
- .fops = &saa_fops,
- .release = video_device_release_empty,
-};
-
-static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
-{
- int retval;
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- saa->endmarkhead = saa->endmarktail = 0;
- saa->win.x = saa->win.y = 0;
- saa->win.width = saa->win.cropwidth = 720;
- saa->win.height = saa->win.cropheight = 480;
- saa->win.cropx = saa->win.cropy = 0;
- saa->win.bpp = 2;
- saa->win.depth = 16;
- saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
- saa->win.bpl = 1024 * saa->win.bpp;
- saa->win.swidth = 1024;
- saa->win.sheight = 768;
- saa->picture.brightness = 32768;
- saa->picture.contrast = 38768;
- saa->picture.colour = 32768;
- saa->cap = 0;
- saa->nr = num;
- saa->playmode = VID_PLAY_NORMAL;
- memset(saa->boardcfg, 0, 64); /* clear board config area */
- saa->saa7146_mem = NULL;
- saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
- saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
- saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
- saa->pagea1out = saa->pagea2in = saa->pagea2out =
- saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
- saa->pageRPS2 = NULL;
- saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
- saa->audhead = saa->vidtail = 0;
-
- init_waitqueue_head(&saa->i2cq);
- init_waitqueue_head(&saa->audq);
- init_waitqueue_head(&saa->debiq);
- init_waitqueue_head(&saa->vidq);
- spin_lock_init(&saa->lock);
-
- retval = pci_enable_device(pdev);
- if (retval) {
- dev_err(&pdev->dev, "%d: pci_enable_device failed!\n", num);
- goto err;
- }
-
- saa->id = pdev->device;
- saa->irq = pdev->irq;
- saa->saa7146_adr = pci_resource_start(pdev, 0);
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision);
-
- saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
- if (saa->saa7146_mem == NULL) {
- dev_err(&pdev->dev, "%d: ioremap failed!\n", num);
- retval = -EIO;
- goto err;
- }
-
- memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
- saawrite(0, SAA7146_IER); /* turn off all interrupts */
-
- retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
- "stradis", saa);
- if (retval == -EINVAL)
- dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
- else if (retval == -EBUSY)
- dev_err(&pdev->dev, "%d: IRQ %ld busy, change your PnP config "
- "in BIOS\n", num, saa->irq);
- if (retval < 0)
- goto errio;
-
- pci_set_master(pdev);
- retval = video_register_device(&saa->video_dev, VFL_TYPE_GRABBER,
- video_nr);
- if (retval < 0) {
- dev_err(&pdev->dev, "%d: error in registering video device!\n",
- num);
- goto errio;
- }
-
- return 0;
-errio:
- iounmap(saa->saa7146_mem);
-err:
- return retval;
-}
-
-static int __devinit init_saa7146(struct pci_dev *pdev)
-{
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- saa->user = 0;
- /* reset the saa7146 */
- saawrite(0xffff0000, SAA7146_MC1);
- mdelay(5);
- /* enable debi and i2c transfers and pins */
- saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
- SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
- /* ensure proper state of chip */
- saawrite(0x00000000, SAA7146_PAGE1);
- saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
- saawrite(0x00000000, SAA7146_PAGE2);
- saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
- saawrite(0x00000000, SAA7146_DD1_INIT);
- saawrite(0x00000000, SAA7146_DD1_STREAM_B);
- saawrite(0x00000000, SAA7146_DD1_STREAM_A);
- saawrite(0x00000000, SAA7146_BRS_CTRL);
- saawrite(0x80400040, SAA7146_BCS_CTRL);
- saawrite(0x0000e000 /*| (1<<29) */ , SAA7146_HPS_CTRL);
- saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
- saawrite(0x00000000, SAA7146_ACON1);
- saawrite(0x00000000, SAA7146_ACON2);
- saawrite(0x00000600, SAA7146_I2C_STATUS);
- saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
- SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
- SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
- SAA7146_MC2);
- /* setup arbitration control registers */
- saawrite(0x1412121a, SAA7146_PCI_BT_V1);
-
- /* allocate 32k dma buffer + 4k for page table */
- if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
- dev_err(&pdev->dev, "%d: debi kmalloc failed\n", saa->nr);
- goto err;
- }
-#if 0
- saa->pagedebi = saa->dmadebi + 32768; /* top 4k is for mmu */
- saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
- for (i = 0; i < 12; i++) /* setup mmu page table */
- saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
-#endif
- saa->audhead = saa->vidhead = saa->osdhead = 0;
- saa->audtail = saa->vidtail = saa->osdtail = 0;
- if (saa->vidbuf == NULL && (saa->vidbuf = vmalloc(524288)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto err;
- }
- if (saa->audbuf == NULL && (saa->audbuf = vmalloc(65536)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto errfree;
- }
- if (saa->osdbuf == NULL && (saa->osdbuf = vmalloc(131072)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto errfree;
- }
- /* allocate 81920 byte buffer for clipping */
- if ((saa->dmavid2 = kzalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
- dev_err(&pdev->dev, "%d: clip kmalloc failed\n", saa->nr);
- goto errfree;
- }
- /* setup clipping registers */
- saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
- saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
- saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
- SAA7146_PROT_ADDR2);
- saawrite(256, SAA7146_PITCH2);
- saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */
- saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
- SAA7146_MC2);
- I2CBusScan(saa);
-
- return 0;
-errfree:
- vfree(saa->osdbuf);
- vfree(saa->audbuf);
- vfree(saa->vidbuf);
- saa->audbuf = saa->osdbuf = saa->vidbuf = NULL;
-err:
- return -ENOMEM;
-}
-
-static void stradis_release_saa(struct pci_dev *pdev)
-{
- u8 command;
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- /* turn off all capturing, DMA and IRQs */
- saawrite(0xffff0000, SAA7146_MC1); /* reset chip */
- saawrite(0, SAA7146_MC2);
- saawrite(0, SAA7146_IER);
- saawrite(0xffffffffUL, SAA7146_ISR);
-
- /* disable PCI bus-mastering */
- pci_read_config_byte(pdev, PCI_COMMAND, &command);
- command &= ~PCI_COMMAND_MASTER;
- pci_write_config_byte(pdev, PCI_COMMAND, command);
-
- /* unmap and free memory */
- saa->audhead = saa->audtail = saa->osdhead = 0;
- saa->vidhead = saa->vidtail = saa->osdtail = 0;
- vfree(saa->vidbuf);
- vfree(saa->audbuf);
- vfree(saa->osdbuf);
- kfree(saa->dmavid2);
- saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
- saa->dmavid2 = NULL;
- kfree(saa->dmadebi);
- kfree(saa->dmavid1);
- kfree(saa->dmavid3);
- kfree(saa->dmaa1in);
- kfree(saa->dmaa1out);
- kfree(saa->dmaa2in);
- kfree(saa->dmaa2out);
- kfree(saa->dmaRPS1);
- kfree(saa->dmaRPS2);
- free_irq(saa->irq, saa);
- if (saa->saa7146_mem)
- iounmap(saa->saa7146_mem);
- if (video_is_registered(&saa->video_dev))
- video_unregister_device(&saa->video_dev);
-}
-
-static int __devinit stradis_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int retval = -EINVAL;
-
- if (saa_num >= SAA7146_MAX)
- goto err;
-
- if (!pdev->subsystem_vendor)
- dev_info(&pdev->dev, "%d: rev1 decoder\n", saa_num);
- else
- dev_info(&pdev->dev, "%d: SDM2xx found\n", saa_num);
-
- pci_set_drvdata(pdev, &saa7146s[saa_num]);
-
- retval = configure_saa7146(pdev, saa_num);
- if (retval) {
- dev_err(&pdev->dev, "%d: error in configuring\n", saa_num);
- goto err;
- }
-
- if (init_saa7146(pdev) < 0) {
- dev_err(&pdev->dev, "%d: error in initialization\n", saa_num);
- retval = -EIO;
- goto errrel;
- }
-
- saa_num++;
-
- return 0;
-errrel:
- stradis_release_saa(pdev);
-err:
- return retval;
-}
-
-static void __devexit stradis_remove(struct pci_dev *pdev)
-{
- stradis_release_saa(pdev);
-}
-
-static struct pci_device_id stradis_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146) },
- { 0 }
-};
-
-
-static struct pci_driver stradis_driver = {
- .name = "stradis",
- .id_table = stradis_pci_tbl,
- .probe = stradis_probe,
- .remove = __devexit_p(stradis_remove)
-};
-
-static int __init stradis_init(void)
-{
- int retval;
-
- saa_num = 0;
-
- retval = pci_register_driver(&stradis_driver);
- if (retval)
- printk(KERN_ERR "stradis: Unable to register pci driver.\n");
-
- return retval;
-}
-
-static void __exit stradis_exit(void)
-{
- pci_unregister_driver(&stradis_driver);
- printk(KERN_INFO "stradis: module cleanup complete\n");
-}
-
-module_init(stradis_init);
-module_exit(stradis_exit);
diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
index ff64d464143c..93de4f2e8bf8 100644
--- a/drivers/staging/tidspbridge/Kconfig
+++ b/drivers/staging/tidspbridge/Kconfig
@@ -6,7 +6,6 @@ menuconfig TIDSPBRIDGE
tristate "DSP Bridge driver"
depends on ARCH_OMAP3
select OMAP_MBOX_FWK
- select OMAP_IOMMU
help
DSP/BIOS Bridge is designed for platforms that contain a GPP and
one or more attached DSPs. The GPP is considered the master or
diff --git a/drivers/staging/tidspbridge/Makefile b/drivers/staging/tidspbridge/Makefile
index 50decc2935c5..41c644c3318f 100644
--- a/drivers/staging/tidspbridge/Makefile
+++ b/drivers/staging/tidspbridge/Makefile
@@ -2,18 +2,19 @@ obj-$(CONFIG_TIDSPBRIDGE) += bridgedriver.o
libgen = gen/gb.o gen/gs.o gen/gh.o gen/uuidutil.o
libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \
- core/tiomap3430_pwr.o core/tiomap_io.o core/dsp-mmu.o \
+ core/tiomap3430_pwr.o core/tiomap_io.o \
core/ue_deh.o core/wdt.o core/dsp-clock.o core/sync.o
libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/dspapi.o \
- pmgr/cmm.o pmgr/dbll.o
+ pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o
librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \
rmgr/proc.o rmgr/pwr.o rmgr/rmm.o rmgr/strm.o rmgr/dspdrv.o \
rmgr/nldr.o rmgr/drv_interface.o
libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o \
dynload/tramp.o
+libhw = hw/hw_mmu.o
bridgedriver-y := $(libgen) $(libservices) $(libcore) $(libpmgr) $(librmgr) \
- $(libdload)
+ $(libdload) $(libhw)
#Machine dependent
ccflags-y += -D_TI_ -D_DB_TIOMAP -DTMS32060 \
diff --git a/drivers/staging/tidspbridge/core/_deh.h b/drivers/staging/tidspbridge/core/_deh.h
index 8ae263387a87..16723cd34831 100644
--- a/drivers/staging/tidspbridge/core/_deh.h
+++ b/drivers/staging/tidspbridge/core/_deh.h
@@ -27,8 +27,9 @@
struct deh_mgr {
struct bridge_dev_context *hbridge_context; /* Bridge context. */
struct ntfy_object *ntfy_obj; /* NTFY object */
-};
-int mmu_fault_isr(struct iommu *mmu);
+ /* MMU Fault DPC */
+ struct tasklet_struct dpc_tasklet;
+};
#endif /* _DEH_ */
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h
index e0a801c1cb98..1159a500f49d 100644
--- a/drivers/staging/tidspbridge/core/_tiomap.h
+++ b/drivers/staging/tidspbridge/core/_tiomap.h
@@ -19,12 +19,23 @@
#ifndef _TIOMAP_
#define _TIOMAP_
-#include <plat/powerdomain.h>
-#include <plat/clockdomain.h>
+/*
+ * XXX These powerdomain.h/clockdomain.h includes are wrong and should
+ * be removed. No driver should call pwrdm_* or clkdm_* functions
+ * directly; they should rely on OMAP core code to do this.
+ */
+#include <mach-omap2/powerdomain.h>
+#include <mach-omap2/clockdomain.h>
+/*
+ * XXX These mach-omap2/ includes are wrong and should be removed. No
+ * driver should read or write to PRM/CM registers directly; they
+ * should rely on OMAP core code to do this.
+ */
+#include <mach-omap2/cm2xxx_3xxx.h>
#include <mach-omap2/prm-regbits-34xx.h>
#include <mach-omap2/cm-regbits-34xx.h>
-#include <dspbridge/dsp-mmu.h>
#include <dspbridge/devdefs.h>
+#include <hw_defs.h>
#include <dspbridge/dspioctl.h> /* for bridge_ioctl_extproc defn */
#include <dspbridge/sync.h>
#include <dspbridge/clk.h>
@@ -306,18 +317,6 @@ static const struct bpwr_clk_t bpwr_clks[] = {
#define CLEAR_BIT_INDEX(reg, index) (reg &= ~(1 << (index)))
-struct shm_segs {
- u32 seg0_da;
- u32 seg0_pa;
- u32 seg0_va;
- u32 seg0_size;
- u32 seg1_da;
- u32 seg1_pa;
- u32 seg1_va;
- u32 seg1_size;
-};
-
-
/* This Bridge driver's device context: */
struct bridge_dev_context {
struct dev_object *hdev_obj; /* Handle to Bridge device object. */
@@ -328,6 +327,7 @@ struct bridge_dev_context {
*/
u32 dw_dsp_ext_base_addr; /* See the comment above */
u32 dw_api_reg_base; /* API mem map'd registers */
+ void __iomem *dw_dsp_mmu_base; /* DSP MMU Mapped registers */
u32 dw_api_clk_base; /* CLK Registers */
u32 dw_dsp_clk_m2_base; /* DSP Clock Module m2 */
u32 dw_public_rhea; /* Pub Rhea */
@@ -339,8 +339,7 @@ struct bridge_dev_context {
u32 dw_internal_size; /* Internal memory size */
struct omap_mbox *mbox; /* Mail box handle */
- struct iommu *dsp_mmu; /* iommu for iva2 handler */
- struct shm_segs sh_s;
+
struct cfg_hostres *resources; /* Host Resources */
/*
@@ -353,6 +352,7 @@ struct bridge_dev_context {
/* TC Settings */
bool tc_word_swap_on; /* Traffic Controller Word Swap */
+ struct pg_table_attrs *pt_attrs;
u32 dsp_per_clks;
};
diff --git a/drivers/staging/tidspbridge/core/dsp-mmu.c b/drivers/staging/tidspbridge/core/dsp-mmu.c
deleted file mode 100644
index 983c95adc8ff..000000000000
--- a/drivers/staging/tidspbridge/core/dsp-mmu.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * dsp-mmu.c
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * DSP iommu.
- *
- * Copyright (C) 2010 Texas Instruments, Inc.
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include <dspbridge/host_os.h>
-#include <plat/dmtimer.h>
-#include <dspbridge/dbdefs.h>
-#include <dspbridge/dev.h>
-#include <dspbridge/io_sm.h>
-#include <dspbridge/dspdeh.h>
-#include "_tiomap.h"
-
-#include <dspbridge/dsp-mmu.h>
-
-#define MMU_CNTL_TWL_EN (1 << 2)
-
-static struct tasklet_struct mmu_tasklet;
-
-#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
-static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
-{
- void *dummy_addr;
- u32 fa, tmp;
- struct iotlb_entry e;
- struct iommu *mmu = dev_context->dsp_mmu;
- dummy_addr = (void *)__get_free_page(GFP_ATOMIC);
-
- /*
- * Before acking the MMU fault, let's make sure MMU can only
- * access entry #0. Then add a new entry so that the DSP OS
- * can continue in order to dump the stack.
- */
- tmp = iommu_read_reg(mmu, MMU_CNTL);
- tmp &= ~MMU_CNTL_TWL_EN;
- iommu_write_reg(mmu, tmp, MMU_CNTL);
- fa = iommu_read_reg(mmu, MMU_FAULT_AD);
- e.da = fa & PAGE_MASK;
- e.pa = virt_to_phys(dummy_addr);
- e.valid = 1;
- e.prsvd = 1;
- e.pgsz = IOVMF_PGSZ_4K & MMU_CAM_PGSZ_MASK;
- e.endian = MMU_RAM_ENDIAN_LITTLE;
- e.elsz = MMU_RAM_ELSZ_32;
- e.mixed = 0;
-
- load_iotlb_entry(mmu, &e);
-
- dsp_clk_enable(DSP_CLK_GPT8);
-
- dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
-
- /* Clear MMU interrupt */
- tmp = iommu_read_reg(mmu, MMU_IRQSTATUS);
- iommu_write_reg(mmu, tmp, MMU_IRQSTATUS);
-
- dump_dsp_stack(dev_context);
- dsp_clk_disable(DSP_CLK_GPT8);
-
- iopgtable_clear_entry(mmu, fa);
- free_page((unsigned long)dummy_addr);
-}
-#endif
-
-
-static void fault_tasklet(unsigned long data)
-{
- struct iommu *mmu = (struct iommu *)data;
- struct bridge_dev_context *dev_ctx;
- struct deh_mgr *dm;
- u32 fa;
- dev_get_deh_mgr(dev_get_first(), &dm);
- dev_get_bridge_context(dev_get_first(), &dev_ctx);
-
- if (!dm || !dev_ctx)
- return;
-
- fa = iommu_read_reg(mmu, MMU_FAULT_AD);
-
-#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
- print_dsp_trace_buffer(dev_ctx);
- dump_dl_modules(dev_ctx);
- mmu_fault_print_stack(dev_ctx);
-#endif
-
- bridge_deh_notify(dm, DSP_MMUFAULT, fa);
-}
-
-/*
- * ======== mmu_fault_isr ========
- * ISR to be triggered by a DSP MMU fault interrupt.
- */
-static int mmu_fault_callback(struct iommu *mmu)
-{
- if (!mmu)
- return -EPERM;
-
- iommu_write_reg(mmu, 0, MMU_IRQENABLE);
- tasklet_schedule(&mmu_tasklet);
- return 0;
-}
-
-/**
- * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
- *
- * This function initialize dsp mmu module and returns a struct iommu
- * handle to use it for dsp maps.
- *
- */
-struct iommu *dsp_mmu_init()
-{
- struct iommu *mmu;
-
- mmu = iommu_get("iva2");
-
- if (!IS_ERR(mmu)) {
- tasklet_init(&mmu_tasklet, fault_tasklet, (unsigned long)mmu);
- mmu->isr = mmu_fault_callback;
- }
-
- return mmu;
-}
-
-/**
- * dsp_mmu_exit() - destroy dsp mmu module
- * @mmu: Pointer to iommu handle.
- *
- * This function destroys dsp mmu module.
- *
- */
-void dsp_mmu_exit(struct iommu *mmu)
-{
- if (mmu)
- iommu_put(mmu);
- tasklet_kill(&mmu_tasklet);
-}
-
-/**
- * user_va2_pa() - get physical address from userspace address.
- * @mm: mm_struct Pointer of the process.
- * @address: Virtual user space address.
- *
- */
-static u32 user_va2_pa(struct mm_struct *mm, u32 address)
-{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- pgd = pgd_offset(mm, address);
- if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
- pmd = pmd_offset(pgd, address);
- if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
- ptep = pte_offset_map(pmd, address);
- if (ptep) {
- pte = *ptep;
- if (pte_present(pte))
- return pte & PAGE_MASK;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * get_io_pages() - pin and get pages of io user's buffer.
- * @mm: mm_struct Pointer of the process.
- * @uva: Virtual user space address.
- * @pages Pages to be pined.
- * @usr_pgs struct page array pointer where the user pages will be stored
- *
- */
-static int get_io_pages(struct mm_struct *mm, u32 uva, unsigned pages,
- struct page **usr_pgs)
-{
- u32 pa;
- int i;
- struct page *pg;
-
- for (i = 0; i < pages; i++) {
- pa = user_va2_pa(mm, uva);
-
- if (!pfn_valid(__phys_to_pfn(pa)))
- break;
-
- pg = phys_to_page(pa);
- usr_pgs[i] = pg;
- get_page(pg);
- }
- return i;
-}
-
-/**
- * user_to_dsp_map() - maps user to dsp virtual address
- * @mmu: Pointer to iommu handle.
- * @uva: Virtual user space address.
- * @da DSP address
- * @size Buffer size to map.
- * @usr_pgs struct page array pointer where the user pages will be stored
- *
- * This function maps a user space buffer into DSP virtual address.
- *
- */
-u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
- struct page **usr_pgs)
-{
- int res, w;
- unsigned pages;
- int i;
- struct vm_area_struct *vma;
- struct mm_struct *mm = current->mm;
- struct sg_table *sgt;
- struct scatterlist *sg;
-
- if (!size || !usr_pgs)
- return -EINVAL;
-
- pages = size / PG_SIZE4K;
-
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, uva);
- while (vma && (uva + size > vma->vm_end))
- vma = find_vma(mm, vma->vm_end + 1);
-
- if (!vma) {
- pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
- __func__, uva, size);
- up_read(&mm->mmap_sem);
- return -EINVAL;
- }
- if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
- w = 1;
-
- if (vma->vm_flags & VM_IO)
- i = get_io_pages(mm, uva, pages, usr_pgs);
- else
- i = get_user_pages(current, mm, uva, pages, w, 1,
- usr_pgs, NULL);
- up_read(&mm->mmap_sem);
-
- if (i < 0)
- return i;
-
- if (i < pages) {
- res = -EFAULT;
- goto err_pages;
- }
-
- sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
- if (!sgt) {
- res = -ENOMEM;
- goto err_pages;
- }
-
- res = sg_alloc_table(sgt, pages, GFP_KERNEL);
-
- if (res < 0)
- goto err_sg;
-
- for_each_sg(sgt->sgl, sg, sgt->nents, i)
- sg_set_page(sg, usr_pgs[i], PAGE_SIZE, 0);
-
- da = iommu_vmap(mmu, da, sgt, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-
- if (!IS_ERR_VALUE(da))
- return da;
- res = (int)da;
-
- sg_free_table(sgt);
-err_sg:
- kfree(sgt);
- i = pages;
-err_pages:
- while (i--)
- put_page(usr_pgs[i]);
- return res;
-}
-
-/**
- * user_to_dsp_unmap() - unmaps DSP virtual buffer.
- * @mmu: Pointer to iommu handle.
- * @da DSP address
- *
- * This function unmaps a user space buffer into DSP virtual address.
- *
- */
-int user_to_dsp_unmap(struct iommu *mmu, u32 da)
-{
- unsigned i;
- struct sg_table *sgt;
- struct scatterlist *sg;
-
- sgt = iommu_vunmap(mmu, da);
- if (!sgt)
- return -EFAULT;
-
- for_each_sg(sgt->sgl, sg, sgt->nents, i)
- put_page(sg_page(sg));
- sg_free_table(sgt);
- kfree(sgt);
-
- return 0;
-}
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 194badaba0ed..571864555ddd 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -39,6 +39,10 @@
#include <dspbridge/ntfy.h>
#include <dspbridge/sync.h>
+/* Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
/* Bridge Driver */
#include <dspbridge/dspdeh.h>
#include <dspbridge/dspio.h>
@@ -287,7 +291,6 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
struct cod_manager *cod_man;
struct chnl_mgr *hchnl_mgr;
struct msg_mgr *hmsg_mgr;
- struct shm_segs *sm_sg;
u32 ul_shm_base;
u32 ul_shm_base_offset;
u32 ul_shm_limit;
@@ -310,9 +313,18 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
struct bridge_ioctl_extproc ae_proc[BRDIOCTL_NUMOFMMUTLB];
struct cfg_hostres *host_res;
struct bridge_dev_context *pbridge_context;
+ u32 map_attrs;
u32 shm0_end;
u32 ul_dyn_ext_base;
u32 ul_seg1_size = 0;
+ u32 pa_curr = 0;
+ u32 va_curr = 0;
+ u32 gpp_va_curr = 0;
+ u32 num_bytes = 0;
+ u32 all_bits = 0;
+ u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+ HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+ };
status = dev_get_bridge_context(hio_mgr->hdev_obj, &pbridge_context);
if (!pbridge_context) {
@@ -325,8 +337,6 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
status = -EFAULT;
goto func_end;
}
- sm_sg = &pbridge_context->sh_s;
-
status = dev_get_cod_mgr(hio_mgr->hdev_obj, &cod_man);
if (!cod_man) {
status = -EFAULT;
@@ -461,14 +471,129 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
if (status)
goto func_end;
- sm_sg->seg1_pa = ul_gpp_pa;
- sm_sg->seg1_da = ul_dyn_ext_base;
- sm_sg->seg1_va = ul_gpp_va;
- sm_sg->seg1_size = ul_seg1_size;
- sm_sg->seg0_pa = ul_gpp_pa + ul_pad_size + ul_seg1_size;
- sm_sg->seg0_da = ul_dsp_va;
- sm_sg->seg0_va = ul_gpp_va + ul_pad_size + ul_seg1_size;
- sm_sg->seg0_size = ul_seg_size;
+ pa_curr = ul_gpp_pa;
+ va_curr = ul_dyn_ext_base * hio_mgr->word_size;
+ gpp_va_curr = ul_gpp_va;
+ num_bytes = ul_seg1_size;
+
+ /*
+ * Try to fit into TLB entries. If not possible, push them to page
+ * tables. It is quite possible that if sections are not on
+ * bigger page boundary, we may end up making several small pages.
+ * So, push them onto page tables, if that is the case.
+ */
+ map_attrs = 0x00000000;
+ map_attrs = DSP_MAPLITTLEENDIAN;
+ map_attrs |= DSP_MAPPHYSICALADDR;
+ map_attrs |= DSP_MAPELEMSIZE32;
+ map_attrs |= DSP_MAPDONOTLOCK;
+
+ while (num_bytes) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned.
+ */
+ all_bits = pa_curr | va_curr;
+ dev_dbg(bridge, "all_bits %x, pa_curr %x, va_curr %x, "
+ "num_bytes %x\n", all_bits, pa_curr, va_curr,
+ num_bytes);
+ for (i = 0; i < 4; i++) {
+ if ((num_bytes >= page_size[i]) && ((all_bits &
+ (page_size[i] -
+ 1)) == 0)) {
+ status =
+ hio_mgr->intf_fxns->
+ pfn_brd_mem_map(hio_mgr->hbridge_context,
+ pa_curr, va_curr,
+ page_size[i], map_attrs,
+ NULL);
+ if (status)
+ goto func_end;
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ gpp_va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /*
+ * Don't try smaller sizes. Hopefully we have
+ * reached an address aligned to a bigger page
+ * size.
+ */
+ break;
+ }
+ }
+ }
+ pa_curr += ul_pad_size;
+ va_curr += ul_pad_size;
+ gpp_va_curr += ul_pad_size;
+
+ /* Configure the TLB entries for the next cacheable segment */
+ num_bytes = ul_seg_size;
+ va_curr = ul_dsp_va * hio_mgr->word_size;
+ while (num_bytes) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned.
+ */
+ all_bits = pa_curr | va_curr;
+ dev_dbg(bridge, "all_bits for Seg1 %x, pa_curr %x, "
+ "va_curr %x, num_bytes %x\n", all_bits, pa_curr,
+ va_curr, num_bytes);
+ for (i = 0; i < 4; i++) {
+ if (!(num_bytes >= page_size[i]) ||
+ !((all_bits & (page_size[i] - 1)) == 0))
+ continue;
+ if (ndx < MAX_LOCK_TLB_ENTRIES) {
+ /*
+ * This is the physical address written to
+ * DSP MMU.
+ */
+ ae_proc[ndx].ul_gpp_pa = pa_curr;
+ /*
+ * This is the virtual uncached ioremapped
+ * address!!!
+ */
+ ae_proc[ndx].ul_gpp_va = gpp_va_curr;
+ ae_proc[ndx].ul_dsp_va =
+ va_curr / hio_mgr->word_size;
+ ae_proc[ndx].ul_size = page_size[i];
+ ae_proc[ndx].endianism = HW_LITTLE_ENDIAN;
+ ae_proc[ndx].elem_size = HW_ELEM_SIZE16BIT;
+ ae_proc[ndx].mixed_mode = HW_MMU_CPUES;
+ dev_dbg(bridge, "shm MMU TLB entry PA %x"
+ " VA %x DSP_VA %x Size %x\n",
+ ae_proc[ndx].ul_gpp_pa,
+ ae_proc[ndx].ul_gpp_va,
+ ae_proc[ndx].ul_dsp_va *
+ hio_mgr->word_size, page_size[i]);
+ ndx++;
+ } else {
+ status =
+ hio_mgr->intf_fxns->
+ pfn_brd_mem_map(hio_mgr->hbridge_context,
+ pa_curr, va_curr,
+ page_size[i], map_attrs,
+ NULL);
+ dev_dbg(bridge,
+ "shm MMU PTE entry PA %x"
+ " VA %x DSP_VA %x Size %x\n",
+ ae_proc[ndx].ul_gpp_pa,
+ ae_proc[ndx].ul_gpp_va,
+ ae_proc[ndx].ul_dsp_va *
+ hio_mgr->word_size, page_size[i]);
+ if (status)
+ goto func_end;
+ }
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ gpp_va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /*
+ * Don't try smaller sizes. Hopefully we have reached
+ * an address aligned to a bigger page size.
+ */
+ break;
+ }
+ }
/*
* Copy remaining entries from CDB. All entries are 1 MB and
@@ -509,12 +634,38 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
"DSP_VA 0x%x\n", ae_proc[ndx].ul_gpp_pa,
ae_proc[ndx].ul_dsp_va);
ndx++;
+ } else {
+ status = hio_mgr->intf_fxns->pfn_brd_mem_map
+ (hio_mgr->hbridge_context,
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_gpp_phys,
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_dsp_virt, 0x100000, map_attrs,
+ NULL);
}
}
if (status)
goto func_end;
}
+ map_attrs = 0x00000000;
+ map_attrs = DSP_MAPLITTLEENDIAN;
+ map_attrs |= DSP_MAPPHYSICALADDR;
+ map_attrs |= DSP_MAPELEMSIZE32;
+ map_attrs |= DSP_MAPDONOTLOCK;
+
+ /* Map the L4 peripherals */
+ i = 0;
+ while (l4_peripheral_table[i].phys_addr) {
+ status = hio_mgr->intf_fxns->pfn_brd_mem_map
+ (hio_mgr->hbridge_context, l4_peripheral_table[i].phys_addr,
+ l4_peripheral_table[i].dsp_virt_addr, HW_PAGE_SIZE4KB,
+ map_attrs, NULL);
+ if (status)
+ goto func_end;
+ i++;
+ }
+
for (i = ndx; i < BRDIOCTL_NUMOFMMUTLB; i++) {
ae_proc[i].ul_dsp_va = 0;
ae_proc[i].ul_gpp_pa = 0;
@@ -537,12 +688,12 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
status = -EFAULT;
goto func_end;
} else {
- if (sm_sg->seg0_da > ul_shm_base) {
+ if (ae_proc[0].ul_dsp_va > ul_shm_base) {
status = -EPERM;
goto func_end;
}
/* ul_shm_base may not be at ul_dsp_va address */
- ul_shm_base_offset = (ul_shm_base - sm_sg->seg0_da) *
+ ul_shm_base_offset = (ul_shm_base - ae_proc[0].ul_dsp_va) *
hio_mgr->word_size;
/*
* bridge_dev_ctrl() will set dev context dsp-mmu info. In
@@ -566,7 +717,8 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
goto func_end;
}
/* Register SM */
- status = register_shm_segs(hio_mgr, cod_man, sm_sg->seg0_pa);
+ status =
+ register_shm_segs(hio_mgr, cod_man, ae_proc[0].ul_gpp_pa);
}
hio_mgr->shared_mem = (struct shm *)ul_shm_base;
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index f22bc12bc0d3..a3b0a183d570 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -23,7 +23,6 @@
#include <dspbridge/host_os.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
-#include <plat/control.h>
/* ----------------------------------- DSP/BIOS Bridge */
#include <dspbridge/dbdefs.h>
@@ -35,6 +34,10 @@
#include <dspbridge/drv.h>
#include <dspbridge/sync.h>
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
/* ----------------------------------- Link Driver */
#include <dspbridge/dspdefs.h>
#include <dspbridge/dspchnl.h>
@@ -47,6 +50,7 @@
/* ----------------------------------- Platform Manager */
#include <dspbridge/dev.h>
#include <dspbridge/dspapi.h>
+#include <dspbridge/dmm.h>
#include <dspbridge/wdt.h>
/* ----------------------------------- Local */
@@ -67,6 +71,20 @@
#define MMU_SMALL_PAGE_MASK 0xFFFFF000
#define OMAP3_IVA2_BOOTADDR_MASK 0xFFFFFC00
#define PAGES_II_LVL_TABLE 512
+#define PHYS_TO_PAGE(phys) pfn_to_page((phys) >> PAGE_SHIFT)
+
+/*
+ * This is a totally ugly layer violation, but needed until
+ * omap_ctrl_set_dsp_boot*() are provided.
+ */
+#define OMAP3_IVA2_BOOTMOD_IDLE 1
+#define OMAP2_CONTROL_GENERAL 0x270
+#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
+#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194)
+
+#define OMAP343X_CTRL_REGADDR(reg) \
+ OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+
/* Forward Declarations: */
static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt);
@@ -91,6 +109,12 @@ static int bridge_brd_mem_copy(struct bridge_dev_context *dev_ctxt,
static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
u8 *host_buff, u32 dsp_addr,
u32 ul_num_bytes, u32 mem_type);
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes, u32 ul_map_attr,
+ struct page **mapped_pages);
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes);
static int bridge_dev_create(struct bridge_dev_context
**dev_cntxt,
struct dev_object *hdev_obj,
@@ -98,8 +122,57 @@ static int bridge_dev_create(struct bridge_dev_context
static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
u32 dw_cmd, void *pargs);
static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt);
+static u32 user_va2_pa(struct mm_struct *mm, u32 address);
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+ u32 va, u32 size,
+ struct hw_mmu_map_attrs_t *map_attrs);
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+ u32 size, struct hw_mmu_map_attrs_t *attrs);
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes,
+ struct hw_mmu_map_attrs_t *hw_attrs);
+
bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr);
+/* ----------------------------------- Globals */
+
+/* Attributes of L2 page tables for DSP MMU */
+struct page_info {
+ u32 num_entries; /* Number of valid PTEs in the L2 PT */
+};
+
+/* Attributes used to manage the DSP MMU page tables */
+struct pg_table_attrs {
+ spinlock_t pg_lock; /* Critical section object handle */
+
+ u32 l1_base_pa; /* Physical address of the L1 PT */
+ u32 l1_base_va; /* Virtual address of the L1 PT */
+ u32 l1_size; /* Size of the L1 PT */
+ u32 l1_tbl_alloc_pa;
+ /* Physical address of Allocated mem for L1 table. May not be aligned */
+ u32 l1_tbl_alloc_va;
+ /* Virtual address of Allocated mem for L1 table. May not be aligned */
+ u32 l1_tbl_alloc_sz;
+ /* Size of consistent memory allocated for L1 table.
+ * May not be aligned */
+
+ u32 l2_base_pa; /* Physical address of the L2 PT */
+ u32 l2_base_va; /* Virtual address of the L2 PT */
+ u32 l2_size; /* Size of the L2 PT */
+ u32 l2_tbl_alloc_pa;
+ /* Physical address of Allocated mem for L2 table. May not be aligned */
+ u32 l2_tbl_alloc_va;
+ /* Virtual address of Allocated mem for L2 table. May not be aligned */
+ u32 l2_tbl_alloc_sz;
+ /* Size of consistent memory allocated for L2 table.
+ * May not be aligned */
+
+ u32 l2_num_pages; /* Number of allocated L2 PT */
+ /* Array [l2_num_pages] of L2 PT info structs */
+ struct page_info *pg_info;
+};
+
/*
* This Bridge driver's function interface table.
*/
@@ -119,6 +192,8 @@ static struct bridge_drv_interface drv_interface_fxns = {
bridge_brd_set_state,
bridge_brd_mem_copy,
bridge_brd_mem_write,
+ bridge_brd_mem_map,
+ bridge_brd_mem_un_map,
/* The following CHNL functions are provided by chnl_io.lib: */
bridge_chnl_create,
bridge_chnl_destroy,
@@ -148,6 +223,27 @@ static struct bridge_drv_interface drv_interface_fxns = {
bridge_msg_set_queue_id,
};
+static inline void flush_all(struct bridge_dev_context *dev_context)
+{
+ if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
+ dev_context->dw_brd_state == BRD_HIBERNATION)
+ wake_dsp(dev_context, NULL);
+
+ hw_mmu_tlb_flush_all(dev_context->dw_dsp_mmu_base);
+}
+
+static void bad_page_dump(u32 pa, struct page *pg)
+{
+ pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa);
+ pr_emerg("Bad page state in process '%s'\n"
+ "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n"
+ "Backtrace:\n",
+ current->comm, pg, (int)(2 * sizeof(unsigned long)),
+ (unsigned long)pg->flags, pg->mapping,
+ page_mapcount(pg), page_count(pg));
+ dump_stack();
+}
+
/*
* ======== bridge_drv_entry ========
* purpose:
@@ -203,7 +299,8 @@ static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt)
(*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_DISABLE_AUTO,
OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
}
-
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
dsp_clk_enable(DSP_CLK_IVA2);
/* set the device state to IDLE */
@@ -274,17 +371,14 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
{
int status = 0;
struct bridge_dev_context *dev_context = dev_ctxt;
- struct iommu *mmu = NULL;
- struct shm_segs *sm_sg;
- int l4_i = 0, tlb_i = 0;
- u32 sg0_da = 0, sg1_da = 0;
- struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry;
u32 dw_sync_addr = 0;
u32 ul_shm_base; /* Gpp Phys SM base addr(byte) */
u32 ul_shm_base_virt; /* Dsp Virt SM base addr */
u32 ul_tlb_base_virt; /* Base of MMU TLB entry */
/* Offset of shm_base_virt from tlb_base_virt */
u32 ul_shm_offset_virt;
+ s32 entry_ndx;
+ s32 itmp_entry_ndx = 0; /* DSP-MMU TLB entry base address */
struct cfg_hostres *resources = NULL;
u32 temp;
u32 ul_dsp_clk_rate;
@@ -305,12 +399,12 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
ul_shm_base_virt *= DSPWORDSIZE;
DBC_ASSERT(ul_shm_base_virt != 0);
/* DSP Virtual address */
- ul_tlb_base_virt = dev_context->sh_s.seg0_da;
+ ul_tlb_base_virt = dev_context->atlb_entry[0].ul_dsp_va;
DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
ul_shm_offset_virt =
ul_shm_base_virt - (ul_tlb_base_virt * DSPWORDSIZE);
/* Kernel logical address */
- ul_shm_base = dev_context->sh_s.seg0_va + ul_shm_offset_virt;
+ ul_shm_base = dev_context->atlb_entry[0].ul_gpp_va + ul_shm_offset_virt;
DBC_ASSERT(ul_shm_base != 0);
/* 2nd wd is used as sync field */
@@ -345,83 +439,78 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
OMAP343X_CONTROL_IVA2_BOOTMOD));
}
}
-
if (!status) {
+ /* Reset and Unreset the RST2, so that BOOTADDR is copied to
+ * IVA2 SYSC register */
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
+ OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ udelay(100);
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
- mmu = dev_context->dsp_mmu;
- if (mmu)
- dsp_mmu_exit(mmu);
- mmu = dsp_mmu_init();
- if (IS_ERR(mmu)) {
- dev_err(bridge, "dsp_mmu_init failed!\n");
- dev_context->dsp_mmu = NULL;
- status = (int)mmu;
- }
- }
- if (!status) {
- dev_context->dsp_mmu = mmu;
- sm_sg = &dev_context->sh_s;
- sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa,
- sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
- if (IS_ERR_VALUE(sg0_da)) {
- status = (int)sg0_da;
- sg0_da = 0;
- }
- }
- if (!status) {
- sg1_da = iommu_kmap(mmu, sm_sg->seg1_da, sm_sg->seg1_pa,
- sm_sg->seg1_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
- if (IS_ERR_VALUE(sg1_da)) {
- status = (int)sg1_da;
- sg1_da = 0;
- }
- }
- if (!status) {
- u32 da;
- for (tlb_i = 0; tlb_i < BRDIOCTL_NUMOFMMUTLB; tlb_i++) {
- if (!tlb[tlb_i].ul_gpp_pa)
+ udelay(100);
+
+ /* Disbale the DSP MMU */
+ hw_mmu_disable(resources->dw_dmmu_base);
+ /* Disable TWL */
+ hw_mmu_twl_disable(resources->dw_dmmu_base);
+
+ /* Only make TLB entry if both addresses are non-zero */
+ for (entry_ndx = 0; entry_ndx < BRDIOCTL_NUMOFMMUTLB;
+ entry_ndx++) {
+ struct bridge_ioctl_extproc *e = &dev_context->atlb_entry[entry_ndx];
+ struct hw_mmu_map_attrs_t map_attrs = {
+ .endianism = e->endianism,
+ .element_size = e->elem_size,
+ .mixed_size = e->mixed_mode,
+ };
+
+ if (!e->ul_gpp_pa || !e->ul_dsp_va)
continue;
- dev_dbg(bridge, "IOMMU %d GppPa: 0x%x DspVa 0x%x Size"
- " 0x%x\n", tlb_i, tlb[tlb_i].ul_gpp_pa,
- tlb[tlb_i].ul_dsp_va, tlb[tlb_i].ul_size);
-
- da = iommu_kmap(mmu, tlb[tlb_i].ul_dsp_va,
- tlb[tlb_i].ul_gpp_pa, PAGE_SIZE,
- IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
- if (IS_ERR_VALUE(da)) {
- status = (int)da;
- break;
- }
- }
- }
- if (!status) {
- u32 da;
- l4_i = 0;
- while (l4_peripheral_table[l4_i].phys_addr) {
- da = iommu_kmap(mmu, l4_peripheral_table[l4_i].
- dsp_virt_addr, l4_peripheral_table[l4_i].
- phys_addr, PAGE_SIZE,
- IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
- if (IS_ERR_VALUE(da)) {
- status = (int)da;
- break;
- }
- l4_i++;
+ dev_dbg(bridge,
+ "MMU %d, pa: 0x%x, va: 0x%x, size: 0x%x",
+ itmp_entry_ndx,
+ e->ul_gpp_pa,
+ e->ul_dsp_va,
+ e->ul_size);
+
+ hw_mmu_tlb_add(dev_context->dw_dsp_mmu_base,
+ e->ul_gpp_pa,
+ e->ul_dsp_va,
+ e->ul_size,
+ itmp_entry_ndx,
+ &map_attrs, 1, 1);
+
+ itmp_entry_ndx++;
}
}
/* Lock the above TLB entries and get the BIOS and load monitor timer
* information */
if (!status) {
+ hw_mmu_num_locked_set(resources->dw_dmmu_base, itmp_entry_ndx);
+ hw_mmu_victim_num_set(resources->dw_dmmu_base, itmp_entry_ndx);
+ hw_mmu_ttb_set(resources->dw_dmmu_base,
+ dev_context->pt_attrs->l1_base_pa);
+ hw_mmu_twl_enable(resources->dw_dmmu_base);
+ /* Enable the SmartIdle and AutoIdle bit for MMU_SYSCONFIG */
+
+ temp = __raw_readl((resources->dw_dmmu_base) + 0x10);
+ temp = (temp & 0xFFFFFFEF) | 0x11;
+ __raw_writel(temp, (resources->dw_dmmu_base) + 0x10);
+
+ /* Let the DSP MMU run */
+ hw_mmu_enable(resources->dw_dmmu_base);
+
/* Enable the BIOS clock */
(void)dev_get_symbol(dev_context->hdev_obj,
BRIDGEINIT_BIOSGPTIMER, &ul_bios_gp_timer);
(void)dev_get_symbol(dev_context->hdev_obj,
BRIDGEINIT_LOADMON_GPTIMER,
&ul_load_monitor_timer);
+ }
+ if (!status) {
if (ul_load_monitor_timer != 0xFFFF) {
clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
ul_load_monitor_timer;
@@ -430,7 +519,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
dev_dbg(bridge, "Not able to get the symbol for Load "
"Monitor Timer\n");
}
+ }
+ if (!status) {
if (ul_bios_gp_timer != 0xFFFF) {
clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
ul_bios_gp_timer;
@@ -439,7 +530,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
dev_dbg(bridge,
"Not able to get the symbol for BIOS Timer\n");
}
+ }
+ if (!status) {
/* Set the DSP clock rate */
(void)dev_get_symbol(dev_context->hdev_obj,
"_BRIDGEINIT_DSP_FREQ", &ul_dsp_clk_addr);
@@ -492,6 +585,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Let DSP go */
dev_dbg(bridge, "%s Unreset\n", __func__);
+ /* Enable DSP MMU Interrupts */
+ hw_mmu_event_enable(resources->dw_dmmu_base,
+ HW_MMU_ALL_INTERRUPTS);
/* release the RST1, DSP starts executing now .. */
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
@@ -500,7 +596,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr);
if (dsp_debug)
while (__raw_readw(dw_sync_addr))
- ;;
+ ;
/* Wait for DSP to clear word in shared memory */
/* Read the Location */
@@ -521,23 +617,11 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* update board state */
dev_context->dw_brd_state = BRD_RUNNING;
- return 0;
+ /* (void)chnlsm_enable_interrupt(dev_context); */
} else {
dev_context->dw_brd_state = BRD_UNKNOWN;
}
}
-
- while (tlb_i--) {
- if (!tlb[tlb_i].ul_gpp_pa)
- continue;
- iommu_kunmap(mmu, tlb[tlb_i].ul_gpp_va);
- }
- while (l4_i--)
- iommu_kunmap(mmu, l4_peripheral_table[l4_i].dsp_virt_addr);
- if (sg0_da)
- iommu_kunmap(mmu, sg0_da);
- if (sg1_da)
- iommu_kunmap(mmu, sg1_da);
return status;
}
@@ -553,9 +637,8 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
{
int status = 0;
struct bridge_dev_context *dev_context = dev_ctxt;
+ struct pg_table_attrs *pt_attrs;
u32 dsp_pwr_state;
- int i;
- struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry;
struct omap_dsp_platform_data *pdata =
omap_dspbridge_dev->dev.platform_data;
@@ -591,37 +674,23 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
dsp_wdt_enable(false);
- /* Reset DSP */
- (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
- OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
+ /* This is a good place to clear the MMU page tables as well */
+ if (dev_context->pt_attrs) {
+ pt_attrs = dev_context->pt_attrs;
+ memset((u8 *) pt_attrs->l1_base_va, 0x00, pt_attrs->l1_size);
+ memset((u8 *) pt_attrs->l2_base_va, 0x00, pt_attrs->l2_size);
+ memset((u8 *) pt_attrs->pg_info, 0x00,
+ (pt_attrs->l2_num_pages * sizeof(struct page_info)));
+ }
/* Disable the mailbox interrupts */
if (dev_context->mbox) {
omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
omap_mbox_put(dev_context->mbox);
dev_context->mbox = NULL;
}
- if (dev_context->dsp_mmu) {
- pr_err("Proc stop mmu if statement\n");
- for (i = 0; i < BRDIOCTL_NUMOFMMUTLB; i++) {
- if (!tlb[i].ul_gpp_pa)
- continue;
- iommu_kunmap(dev_context->dsp_mmu, tlb[i].ul_gpp_va);
- }
- i = 0;
- while (l4_peripheral_table[i].phys_addr) {
- iommu_kunmap(dev_context->dsp_mmu,
- l4_peripheral_table[i].dsp_virt_addr);
- i++;
- }
- iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da);
- iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg1_da);
- dsp_mmu_exit(dev_context->dsp_mmu);
- dev_context->dsp_mmu = NULL;
- }
- /* Reset IVA IOMMU*/
- (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
- OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ /* Reset IVA2 clocks*/
+ (*pdata->dsp_prm_write)(OMAP3430_RST1_IVA2_MASK | OMAP3430_RST2_IVA2_MASK |
+ OMAP3430_RST3_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
dsp_clock_disable_all(dev_context->dsp_per_clks);
dsp_clk_disable(DSP_CLK_IVA2);
@@ -681,6 +750,10 @@ static int bridge_dev_create(struct bridge_dev_context
struct bridge_dev_context *dev_context = NULL;
s32 entry_ndx;
struct cfg_hostres *resources = config_param;
+ struct pg_table_attrs *pt_attrs;
+ u32 pg_tbl_pa;
+ u32 pg_tbl_va;
+ u32 align_size;
struct drv_data *drv_datap = dev_get_drvdata(bridge);
/* Allocate and initialize a data structure to contain the bridge driver
@@ -711,8 +784,97 @@ static int bridge_dev_create(struct bridge_dev_context
if (!dev_context->dw_dsp_base_addr)
status = -EPERM;
+ pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL);
+ if (pt_attrs != NULL) {
+ /* Assuming that we use only DSP's memory map
+ * until 0x4000:0000 , we would need only 1024
+ * L1 enties i.e L1 size = 4K */
+ pt_attrs->l1_size = 0x1000;
+ align_size = pt_attrs->l1_size;
+ /* Align sizes are expected to be power of 2 */
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l1_size,
+ align_size, &pg_tbl_pa);
+
+ /* Check if the PA is aligned for us */
+ if ((pg_tbl_pa) & (align_size - 1)) {
+ /* PA not aligned to page table size ,
+ * try with more allocation and align */
+ mem_free_phys_mem((void *)pg_tbl_va, pg_tbl_pa,
+ pt_attrs->l1_size);
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va =
+ (u32) mem_alloc_phys_mem((pt_attrs->l1_size) * 2,
+ align_size, &pg_tbl_pa);
+ /* We should be able to get aligned table now */
+ pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size * 2;
+ /* Align the PA to the next 'align' boundary */
+ pt_attrs->l1_base_pa =
+ ((pg_tbl_pa) +
+ (align_size - 1)) & (~(align_size - 1));
+ pt_attrs->l1_base_va =
+ pg_tbl_va + (pt_attrs->l1_base_pa - pg_tbl_pa);
+ } else {
+ /* We got aligned PA, cool */
+ pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size;
+ pt_attrs->l1_base_pa = pg_tbl_pa;
+ pt_attrs->l1_base_va = pg_tbl_va;
+ }
+ if (pt_attrs->l1_base_va)
+ memset((u8 *) pt_attrs->l1_base_va, 0x00,
+ pt_attrs->l1_size);
+
+ /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM +
+ * L4 pages */
+ pt_attrs->l2_num_pages = ((DMMPOOLSIZE >> 20) + 6);
+ pt_attrs->l2_size = HW_MMU_COARSE_PAGE_SIZE *
+ pt_attrs->l2_num_pages;
+ align_size = 4; /* Make it u32 aligned */
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l2_size,
+ align_size, &pg_tbl_pa);
+ pt_attrs->l2_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l2_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l2_tbl_alloc_sz = pt_attrs->l2_size;
+ pt_attrs->l2_base_pa = pg_tbl_pa;
+ pt_attrs->l2_base_va = pg_tbl_va;
+
+ if (pt_attrs->l2_base_va)
+ memset((u8 *) pt_attrs->l2_base_va, 0x00,
+ pt_attrs->l2_size);
+
+ pt_attrs->pg_info = kzalloc(pt_attrs->l2_num_pages *
+ sizeof(struct page_info), GFP_KERNEL);
+ dev_dbg(bridge,
+ "L1 pa %x, va %x, size %x\n L2 pa %x, va "
+ "%x, size %x\n", pt_attrs->l1_base_pa,
+ pt_attrs->l1_base_va, pt_attrs->l1_size,
+ pt_attrs->l2_base_pa, pt_attrs->l2_base_va,
+ pt_attrs->l2_size);
+ dev_dbg(bridge, "pt_attrs %p L2 NumPages %x pg_info %p\n",
+ pt_attrs, pt_attrs->l2_num_pages, pt_attrs->pg_info);
+ }
+ if ((pt_attrs != NULL) && (pt_attrs->l1_base_va != 0) &&
+ (pt_attrs->l2_base_va != 0) && (pt_attrs->pg_info != NULL))
+ dev_context->pt_attrs = pt_attrs;
+ else
+ status = -ENOMEM;
+
if (!status) {
+ spin_lock_init(&pt_attrs->pg_lock);
dev_context->tc_word_swap_on = drv_datap->tc_wordswapon;
+
+ /* Set the Clock Divisor for the DSP module */
+ udelay(5);
+ /* MMU address is obtained from the host
+ * resources struct */
+ dev_context->dw_dsp_mmu_base = resources->dw_dmmu_base;
+ }
+ if (!status) {
dev_context->hdev_obj = hdev_obj;
/* Store current board state. */
dev_context->dw_brd_state = BRD_UNKNOWN;
@@ -722,6 +884,23 @@ static int bridge_dev_create(struct bridge_dev_context
/* Return ptr to our device state to the DSP API for storage */
*dev_cntxt = dev_context;
} else {
+ if (pt_attrs != NULL) {
+ kfree(pt_attrs->pg_info);
+
+ if (pt_attrs->l2_tbl_alloc_va) {
+ mem_free_phys_mem((void *)
+ pt_attrs->l2_tbl_alloc_va,
+ pt_attrs->l2_tbl_alloc_pa,
+ pt_attrs->l2_tbl_alloc_sz);
+ }
+ if (pt_attrs->l1_tbl_alloc_va) {
+ mem_free_phys_mem((void *)
+ pt_attrs->l1_tbl_alloc_va,
+ pt_attrs->l1_tbl_alloc_pa,
+ pt_attrs->l1_tbl_alloc_sz);
+ }
+ }
+ kfree(pt_attrs);
kfree(dev_context);
}
func_end:
@@ -789,6 +968,7 @@ static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
*/
static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
{
+ struct pg_table_attrs *pt_attrs;
int status = 0;
struct bridge_dev_context *dev_context = (struct bridge_dev_context *)
dev_ctxt;
@@ -802,6 +982,23 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
/* first put the device to stop state */
bridge_brd_stop(dev_context);
+ if (dev_context->pt_attrs) {
+ pt_attrs = dev_context->pt_attrs;
+ kfree(pt_attrs->pg_info);
+
+ if (pt_attrs->l2_tbl_alloc_va) {
+ mem_free_phys_mem((void *)pt_attrs->l2_tbl_alloc_va,
+ pt_attrs->l2_tbl_alloc_pa,
+ pt_attrs->l2_tbl_alloc_sz);
+ }
+ if (pt_attrs->l1_tbl_alloc_va) {
+ mem_free_phys_mem((void *)pt_attrs->l1_tbl_alloc_va,
+ pt_attrs->l1_tbl_alloc_pa,
+ pt_attrs->l1_tbl_alloc_sz);
+ }
+ kfree(pt_attrs);
+
+ }
if (dev_context->resources) {
host_res = dev_context->resources;
@@ -832,6 +1029,8 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
iounmap((void *)host_res->dw_mem_base[3]);
if (host_res->dw_mem_base[4])
iounmap((void *)host_res->dw_mem_base[4]);
+ if (host_res->dw_dmmu_base)
+ iounmap(host_res->dw_dmmu_base);
if (host_res->dw_per_base)
iounmap(host_res->dw_per_base);
if (host_res->dw_per_pm_base)
@@ -845,6 +1044,7 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
host_res->dw_mem_base[2] = (u32) NULL;
host_res->dw_mem_base[3] = (u32) NULL;
host_res->dw_mem_base[4] = (u32) NULL;
+ host_res->dw_dmmu_base = NULL;
host_res->dw_sys_ctrl_base = NULL;
kfree(host_res);
@@ -928,6 +1128,673 @@ static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
}
/*
+ * ======== bridge_brd_mem_map ========
+ * This function maps MPU buffer to the DSP address space. It performs
+ * linear to physical address translation if required. It translates each
+ * page since linear addresses can be physically non-contiguous
+ * All address & size arguments are assumed to be page aligned (in proc.c)
+ *
+ * TODO: Disable MMU while updating the page tables (but that'll stall DSP)
+ */
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes, u32 ul_map_attr,
+ struct page **mapped_pages)
+{
+ u32 attrs;
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ struct hw_mmu_map_attrs_t hw_attrs;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ u32 write = 0;
+ u32 num_usr_pgs = 0;
+ struct page *mapped_page, *pg;
+ s32 pg_num;
+ u32 va = virt_addr;
+ struct task_struct *curr_task = current;
+ u32 pg_i = 0;
+ u32 mpu_addr, pa;
+
+ dev_dbg(bridge,
+ "%s hDevCtxt %p, pa %x, va %x, size %x, ul_map_attr %x\n",
+ __func__, dev_ctxt, ul_mpu_addr, virt_addr, ul_num_bytes,
+ ul_map_attr);
+ if (ul_num_bytes == 0)
+ return -EINVAL;
+
+ if (ul_map_attr & DSP_MAP_DIR_MASK) {
+ attrs = ul_map_attr;
+ } else {
+ /* Assign default attributes */
+ attrs = ul_map_attr | (DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE16);
+ }
+ /* Take mapping properties */
+ if (attrs & DSP_MAPBIGENDIAN)
+ hw_attrs.endianism = HW_BIG_ENDIAN;
+ else
+ hw_attrs.endianism = HW_LITTLE_ENDIAN;
+
+ hw_attrs.mixed_size = (enum hw_mmu_mixed_size_t)
+ ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2);
+ /* Ignore element_size if mixed_size is enabled */
+ if (hw_attrs.mixed_size == 0) {
+ if (attrs & DSP_MAPELEMSIZE8) {
+ /* Size is 8 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE8BIT;
+ } else if (attrs & DSP_MAPELEMSIZE16) {
+ /* Size is 16 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE16BIT;
+ } else if (attrs & DSP_MAPELEMSIZE32) {
+ /* Size is 32 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE32BIT;
+ } else if (attrs & DSP_MAPELEMSIZE64) {
+ /* Size is 64 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE64BIT;
+ } else {
+ /*
+ * Mixedsize isn't enabled, so size can't be
+ * zero here
+ */
+ return -EINVAL;
+ }
+ }
+ if (attrs & DSP_MAPDONOTLOCK)
+ hw_attrs.donotlockmpupage = 1;
+ else
+ hw_attrs.donotlockmpupage = 0;
+
+ if (attrs & DSP_MAPVMALLOCADDR) {
+ return mem_map_vmalloc(dev_ctxt, ul_mpu_addr, virt_addr,
+ ul_num_bytes, &hw_attrs);
+ }
+ /*
+ * Do OS-specific user-va to pa translation.
+ * Combine physically contiguous regions to reduce TLBs.
+ * Pass the translated pa to pte_update.
+ */
+ if ((attrs & DSP_MAPPHYSICALADDR)) {
+ status = pte_update(dev_context, ul_mpu_addr, virt_addr,
+ ul_num_bytes, &hw_attrs);
+ goto func_cont;
+ }
+
+ /*
+ * Important Note: ul_mpu_addr is mapped from user application process
+ * to current process - it must lie completely within the current
+ * virtual memory address space in order to be of use to us here!
+ */
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, ul_mpu_addr);
+ if (vma)
+ dev_dbg(bridge,
+ "VMAfor UserBuf: ul_mpu_addr=%x, ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+ ul_num_bytes, vma->vm_start, vma->vm_end,
+ vma->vm_flags);
+
+ /*
+ * It is observed that under some circumstances, the user buffer is
+ * spread across several VMAs. So loop through and check if the entire
+ * user buffer is covered
+ */
+ while ((vma) && (ul_mpu_addr + ul_num_bytes > vma->vm_end)) {
+ /* jump to the next VMA region */
+ vma = find_vma(mm, vma->vm_end + 1);
+ dev_dbg(bridge,
+ "VMA for UserBuf ul_mpu_addr=%x ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+ ul_num_bytes, vma->vm_start, vma->vm_end,
+ vma->vm_flags);
+ }
+ if (!vma) {
+ pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
+ __func__, ul_mpu_addr, ul_num_bytes);
+ status = -EINVAL;
+ up_read(&mm->mmap_sem);
+ goto func_cont;
+ }
+
+ if (vma->vm_flags & VM_IO) {
+ num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+ mpu_addr = ul_mpu_addr;
+
+ /* Get the physical addresses for user buffer */
+ for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+ pa = user_va2_pa(mm, mpu_addr);
+ if (!pa) {
+ status = -EPERM;
+ pr_err("DSPBRIDGE: VM_IO mapping physical"
+ "address is invalid\n");
+ break;
+ }
+ if (pfn_valid(__phys_to_pfn(pa))) {
+ pg = PHYS_TO_PAGE(pa);
+ get_page(pg);
+ if (page_count(pg) < 1) {
+ pr_err("Bad page in VM_IO buffer\n");
+ bad_page_dump(pa, pg);
+ }
+ }
+ status = pte_set(dev_context->pt_attrs, pa,
+ va, HW_PAGE_SIZE4KB, &hw_attrs);
+ if (status)
+ break;
+
+ va += HW_PAGE_SIZE4KB;
+ mpu_addr += HW_PAGE_SIZE4KB;
+ pa += HW_PAGE_SIZE4KB;
+ }
+ } else {
+ num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+ if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+ write = 1;
+
+ for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+ pg_num = get_user_pages(curr_task, mm, ul_mpu_addr, 1,
+ write, 1, &mapped_page, NULL);
+ if (pg_num > 0) {
+ if (page_count(mapped_page) < 1) {
+ pr_err("Bad page count after doing"
+ "get_user_pages on"
+ "user buffer\n");
+ bad_page_dump(page_to_phys(mapped_page),
+ mapped_page);
+ }
+ status = pte_set(dev_context->pt_attrs,
+ page_to_phys(mapped_page), va,
+ HW_PAGE_SIZE4KB, &hw_attrs);
+ if (status)
+ break;
+
+ if (mapped_pages)
+ mapped_pages[pg_i] = mapped_page;
+
+ va += HW_PAGE_SIZE4KB;
+ ul_mpu_addr += HW_PAGE_SIZE4KB;
+ } else {
+ pr_err("DSPBRIDGE: get_user_pages FAILED,"
+ "MPU addr = 0x%x,"
+ "vma->vm_flags = 0x%lx,"
+ "get_user_pages Err"
+ "Value = %d, Buffer"
+ "size=0x%x\n", ul_mpu_addr,
+ vma->vm_flags, pg_num, ul_num_bytes);
+ status = -EPERM;
+ break;
+ }
+ }
+ }
+ up_read(&mm->mmap_sem);
+func_cont:
+ if (status) {
+ /*
+ * Roll out the mapped pages incase it failed in middle of
+ * mapping
+ */
+ if (pg_i) {
+ bridge_brd_mem_un_map(dev_context, virt_addr,
+ (pg_i * PG_SIZE4K));
+ }
+ status = -EPERM;
+ }
+ /*
+ * In any case, flush the TLB
+ * This is called from here instead from pte_update to avoid unnecessary
+ * repetition while mapping non-contiguous physical regions of a virtual
+ * region
+ */
+ flush_all(dev_context);
+ dev_dbg(bridge, "%s status %x\n", __func__, status);
+ return status;
+}
+
+/*
+ * ======== bridge_brd_mem_un_map ========
+ * Invalidate the PTEs for the DSP VA block to be unmapped.
+ *
+ * PTEs of a mapped memory block are contiguous in any page table
+ * So, instead of looking up the PTE address for every 4K block,
+ * we clear consecutive PTEs until we unmap all the bytes
+ */
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes)
+{
+ u32 l1_base_va;
+ u32 l2_base_va;
+ u32 l2_base_pa;
+ u32 l2_page_num;
+ u32 pte_val;
+ u32 pte_size;
+ u32 pte_count;
+ u32 pte_addr_l1;
+ u32 pte_addr_l2 = 0;
+ u32 rem_bytes;
+ u32 rem_bytes_l2;
+ u32 va_curr;
+ struct page *pg = NULL;
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ struct pg_table_attrs *pt = dev_context->pt_attrs;
+ u32 temp;
+ u32 paddr;
+ u32 numof4k_pages = 0;
+
+ va_curr = virt_addr;
+ rem_bytes = ul_num_bytes;
+ rem_bytes_l2 = 0;
+ l1_base_va = pt->l1_base_va;
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+ dev_dbg(bridge, "%s dev_ctxt %p, va %x, NumBytes %x l1_base_va %x, "
+ "pte_addr_l1 %x\n", __func__, dev_ctxt, virt_addr,
+ ul_num_bytes, l1_base_va, pte_addr_l1);
+
+ while (rem_bytes && !status) {
+ u32 va_curr_orig = va_curr;
+ /* Find whether the L1 PTE points to a valid L2 PT */
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+ pte_val = *(u32 *) pte_addr_l1;
+ pte_size = hw_mmu_pte_size_l1(pte_val);
+
+ if (pte_size != HW_MMU_COARSE_PAGE_SIZE)
+ goto skip_coarse_page;
+
+ /*
+ * Get the L2 PA from the L1 PTE, and find
+ * corresponding L2 VA
+ */
+ l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+ l2_base_va = l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+ l2_page_num =
+ (l2_base_pa - pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+ /*
+ * Find the L2 PTE address from which we will start
+ * clearing, the number of PTEs to be cleared on this
+ * page, and the size of VA space that needs to be
+ * cleared on this L2 page
+ */
+ pte_addr_l2 = hw_mmu_pte_addr_l2(l2_base_va, va_curr);
+ pte_count = pte_addr_l2 & (HW_MMU_COARSE_PAGE_SIZE - 1);
+ pte_count = (HW_MMU_COARSE_PAGE_SIZE - pte_count) / sizeof(u32);
+ if (rem_bytes < (pte_count * PG_SIZE4K))
+ pte_count = rem_bytes / PG_SIZE4K;
+ rem_bytes_l2 = pte_count * PG_SIZE4K;
+
+ /*
+ * Unmap the VA space on this L2 PT. A quicker way
+ * would be to clear pte_count entries starting from
+ * pte_addr_l2. However, below code checks that we don't
+ * clear invalid entries or less than 64KB for a 64KB
+ * entry. Similar checking is done for L1 PTEs too
+ * below
+ */
+ while (rem_bytes_l2 && !status) {
+ pte_val = *(u32 *) pte_addr_l2;
+ pte_size = hw_mmu_pte_size_l2(pte_val);
+ /* va_curr aligned to pte_size? */
+ if (pte_size == 0 || rem_bytes_l2 < pte_size ||
+ va_curr & (pte_size - 1)) {
+ status = -EPERM;
+ break;
+ }
+
+ /* Collect Physical addresses from VA */
+ paddr = (pte_val & ~(pte_size - 1));
+ if (pte_size == HW_PAGE_SIZE64KB)
+ numof4k_pages = 16;
+ else
+ numof4k_pages = 1;
+ temp = 0;
+ while (temp++ < numof4k_pages) {
+ if (!pfn_valid(__phys_to_pfn(paddr))) {
+ paddr += HW_PAGE_SIZE4KB;
+ continue;
+ }
+ pg = PHYS_TO_PAGE(paddr);
+ if (page_count(pg) < 1) {
+ pr_info("DSPBRIDGE: UNMAP function: "
+ "COUNT 0 FOR PA 0x%x, size = "
+ "0x%x\n", paddr, ul_num_bytes);
+ bad_page_dump(paddr, pg);
+ } else {
+ set_page_dirty(pg);
+ page_cache_release(pg);
+ }
+ paddr += HW_PAGE_SIZE4KB;
+ }
+ if (hw_mmu_pte_clear(pte_addr_l2, va_curr, pte_size)) {
+ status = -EPERM;
+ goto EXIT_LOOP;
+ }
+
+ status = 0;
+ rem_bytes_l2 -= pte_size;
+ va_curr += pte_size;
+ pte_addr_l2 += (pte_size >> 12) * sizeof(u32);
+ }
+ spin_lock(&pt->pg_lock);
+ if (rem_bytes_l2 == 0) {
+ pt->pg_info[l2_page_num].num_entries -= pte_count;
+ if (pt->pg_info[l2_page_num].num_entries == 0) {
+ /*
+ * Clear the L1 PTE pointing to the L2 PT
+ */
+ if (!hw_mmu_pte_clear(l1_base_va, va_curr_orig,
+ HW_MMU_COARSE_PAGE_SIZE))
+ status = 0;
+ else {
+ status = -EPERM;
+ spin_unlock(&pt->pg_lock);
+ goto EXIT_LOOP;
+ }
+ }
+ rem_bytes -= pte_count * PG_SIZE4K;
+ } else
+ status = -EPERM;
+
+ spin_unlock(&pt->pg_lock);
+ continue;
+skip_coarse_page:
+ /* va_curr aligned to pte_size? */
+ /* pte_size = 1 MB or 16 MB */
+ if (pte_size == 0 || rem_bytes < pte_size ||
+ va_curr & (pte_size - 1)) {
+ status = -EPERM;
+ break;
+ }
+
+ if (pte_size == HW_PAGE_SIZE1MB)
+ numof4k_pages = 256;
+ else
+ numof4k_pages = 4096;
+ temp = 0;
+ /* Collect Physical addresses from VA */
+ paddr = (pte_val & ~(pte_size - 1));
+ while (temp++ < numof4k_pages) {
+ if (pfn_valid(__phys_to_pfn(paddr))) {
+ pg = PHYS_TO_PAGE(paddr);
+ if (page_count(pg) < 1) {
+ pr_info("DSPBRIDGE: UNMAP function: "
+ "COUNT 0 FOR PA 0x%x, size = "
+ "0x%x\n", paddr, ul_num_bytes);
+ bad_page_dump(paddr, pg);
+ } else {
+ set_page_dirty(pg);
+ page_cache_release(pg);
+ }
+ }
+ paddr += HW_PAGE_SIZE4KB;
+ }
+ if (!hw_mmu_pte_clear(l1_base_va, va_curr, pte_size)) {
+ status = 0;
+ rem_bytes -= pte_size;
+ va_curr += pte_size;
+ } else {
+ status = -EPERM;
+ goto EXIT_LOOP;
+ }
+ }
+ /*
+ * It is better to flush the TLB here, so that any stale old entries
+ * get flushed
+ */
+EXIT_LOOP:
+ flush_all(dev_context);
+ dev_dbg(bridge,
+ "%s: va_curr %x, pte_addr_l1 %x pte_addr_l2 %x rem_bytes %x,"
+ " rem_bytes_l2 %x status %x\n", __func__, va_curr, pte_addr_l1,
+ pte_addr_l2, rem_bytes, rem_bytes_l2, status);
+ return status;
+}
+
+/*
+ * ======== user_va2_pa ========
+ * Purpose:
+ * This function walks through the page tables to convert a userland
+ * virtual address to physical address
+ */
+static u32 user_va2_pa(struct mm_struct *mm, u32 address)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(mm, address);
+ if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
+ pmd = pmd_offset(pgd, address);
+ if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
+ ptep = pte_offset_map(pmd, address);
+ if (ptep) {
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte & PAGE_MASK;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * ======== pte_update ========
+ * This function calculates the optimum page-aligned addresses and sizes
+ * Caller must pass page-aligned values
+ */
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+ u32 va, u32 size,
+ struct hw_mmu_map_attrs_t *map_attrs)
+{
+ u32 i;
+ u32 all_bits;
+ u32 pa_curr = pa;
+ u32 va_curr = va;
+ u32 num_bytes = size;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ int status = 0;
+ u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+ HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+ };
+
+ while (num_bytes && !status) {
+ /* To find the max. page size with which both PA & VA are
+ * aligned */
+ all_bits = pa_curr | va_curr;
+
+ for (i = 0; i < 4; i++) {
+ if ((num_bytes >= page_size[i]) && ((all_bits &
+ (page_size[i] -
+ 1)) == 0)) {
+ status =
+ pte_set(dev_context->pt_attrs, pa_curr,
+ va_curr, page_size[i], map_attrs);
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /* Don't try smaller sizes. Hopefully we have
+ * reached an address aligned to a bigger page
+ * size */
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== pte_set ========
+ * This function calculates PTE address (MPU virtual) to be updated
+ * It also manages the L2 page tables
+ */
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+ u32 size, struct hw_mmu_map_attrs_t *attrs)
+{
+ u32 i;
+ u32 pte_val;
+ u32 pte_addr_l1;
+ u32 pte_size;
+ /* Base address of the PT that will be updated */
+ u32 pg_tbl_va;
+ u32 l1_base_va;
+ /* Compiler warns that the next three variables might be used
+ * uninitialized in this function. Doesn't seem so. Working around,
+ * anyways. */
+ u32 l2_base_va = 0;
+ u32 l2_base_pa = 0;
+ u32 l2_page_num = 0;
+ int status = 0;
+
+ l1_base_va = pt->l1_base_va;
+ pg_tbl_va = l1_base_va;
+ if ((size == HW_PAGE_SIZE64KB) || (size == HW_PAGE_SIZE4KB)) {
+ /* Find whether the L1 PTE points to a valid L2 PT */
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va);
+ if (pte_addr_l1 <= (pt->l1_base_va + pt->l1_size)) {
+ pte_val = *(u32 *) pte_addr_l1;
+ pte_size = hw_mmu_pte_size_l1(pte_val);
+ } else {
+ return -EPERM;
+ }
+ spin_lock(&pt->pg_lock);
+ if (pte_size == HW_MMU_COARSE_PAGE_SIZE) {
+ /* Get the L2 PA from the L1 PTE, and find
+ * corresponding L2 VA */
+ l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+ l2_base_va =
+ l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+ l2_page_num =
+ (l2_base_pa -
+ pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+ } else if (pte_size == 0) {
+ /* L1 PTE is invalid. Allocate a L2 PT and
+ * point the L1 PTE to it */
+ /* Find a free L2 PT. */
+ for (i = 0; (i < pt->l2_num_pages) &&
+ (pt->pg_info[i].num_entries != 0); i++)
+ ;
+ if (i < pt->l2_num_pages) {
+ l2_page_num = i;
+ l2_base_pa = pt->l2_base_pa + (l2_page_num *
+ HW_MMU_COARSE_PAGE_SIZE);
+ l2_base_va = pt->l2_base_va + (l2_page_num *
+ HW_MMU_COARSE_PAGE_SIZE);
+ /* Endianness attributes are ignored for
+ * HW_MMU_COARSE_PAGE_SIZE */
+ status =
+ hw_mmu_pte_set(l1_base_va, l2_base_pa, va,
+ HW_MMU_COARSE_PAGE_SIZE,
+ attrs);
+ } else {
+ status = -ENOMEM;
+ }
+ } else {
+ /* Found valid L1 PTE of another size.
+ * Should not overwrite it. */
+ status = -EPERM;
+ }
+ if (!status) {
+ pg_tbl_va = l2_base_va;
+ if (size == HW_PAGE_SIZE64KB)
+ pt->pg_info[l2_page_num].num_entries += 16;
+ else
+ pt->pg_info[l2_page_num].num_entries++;
+ dev_dbg(bridge, "PTE: L2 BaseVa %x, BasePa %x, PageNum "
+ "%x, num_entries %x\n", l2_base_va,
+ l2_base_pa, l2_page_num,
+ pt->pg_info[l2_page_num].num_entries);
+ }
+ spin_unlock(&pt->pg_lock);
+ }
+ if (!status) {
+ dev_dbg(bridge, "PTE: pg_tbl_va %x, pa %x, va %x, size %x\n",
+ pg_tbl_va, pa, va, size);
+ dev_dbg(bridge, "PTE: endianism %x, element_size %x, "
+ "mixed_size %x\n", attrs->endianism,
+ attrs->element_size, attrs->mixed_size);
+ status = hw_mmu_pte_set(pg_tbl_va, pa, va, size, attrs);
+ }
+
+ return status;
+}
+
+/* Memory map kernel VA -- memory allocated with vmalloc */
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes,
+ struct hw_mmu_map_attrs_t *hw_attrs)
+{
+ int status = 0;
+ struct page *page[1];
+ u32 i;
+ u32 pa_curr;
+ u32 pa_next;
+ u32 va_curr;
+ u32 size_curr;
+ u32 num_pages;
+ u32 pa;
+ u32 num_of4k_pages;
+ u32 temp = 0;
+
+ /*
+ * Do Kernel va to pa translation.
+ * Combine physically contiguous regions to reduce TLBs.
+ * Pass the translated pa to pte_update.
+ */
+ num_pages = ul_num_bytes / PAGE_SIZE; /* PAGE_SIZE = OS page size */
+ i = 0;
+ va_curr = ul_mpu_addr;
+ page[0] = vmalloc_to_page((void *)va_curr);
+ pa_next = page_to_phys(page[0]);
+ while (!status && (i < num_pages)) {
+ /*
+ * Reuse pa_next from the previous iteraion to avoid
+ * an extra va2pa call
+ */
+ pa_curr = pa_next;
+ size_curr = PAGE_SIZE;
+ /*
+ * If the next page is physically contiguous,
+ * map it with the current one by increasing
+ * the size of the region to be mapped
+ */
+ while (++i < num_pages) {
+ page[0] =
+ vmalloc_to_page((void *)(va_curr + size_curr));
+ pa_next = page_to_phys(page[0]);
+
+ if (pa_next == (pa_curr + size_curr))
+ size_curr += PAGE_SIZE;
+ else
+ break;
+
+ }
+ if (pa_next == 0) {
+ status = -ENOMEM;
+ break;
+ }
+ pa = pa_curr;
+ num_of4k_pages = size_curr / HW_PAGE_SIZE4KB;
+ while (temp++ < num_of4k_pages) {
+ get_page(PHYS_TO_PAGE(pa));
+ pa += HW_PAGE_SIZE4KB;
+ }
+ status = pte_update(dev_context, pa_curr, virt_addr +
+ (va_curr - ul_mpu_addr), size_curr,
+ hw_attrs);
+ va_curr += size_curr;
+ }
+ /*
+ * In any case, flush the TLB
+ * This is called from here instead from pte_update to avoid unnecessary
+ * repetition while mapping non-contiguous physical regions of a virtual
+ * region
+ */
+ flush_all(dev_context);
+ dev_dbg(bridge, "%s status %x\n", __func__, status);
+ return status;
+}
+
+/*
* ======== wait_for_start ========
* Wait for the singal from DSP that it has started, or time out.
*/
diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
index b57a9fd5e757..fb9026e1403c 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
@@ -31,6 +31,10 @@
#include <dspbridge/dev.h>
#include <dspbridge/iodefs.h>
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
#include <dspbridge/pwr_sh.h>
/* ----------------------------------- Bridge Driver */
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.c b/drivers/staging/tidspbridge/core/tiomap_io.c
index 66dbf02549e4..ba2961049dad 100644
--- a/drivers/staging/tidspbridge/core/tiomap_io.c
+++ b/drivers/staging/tidspbridge/core/tiomap_io.c
@@ -134,16 +134,17 @@ int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
if (!status) {
ul_tlb_base_virt =
- dev_context->sh_s.seg0_da * DSPWORDSIZE;
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
- dw_ext_prog_virt_mem = dev_context->sh_s.seg0_va;
+ dw_ext_prog_virt_mem =
+ dev_context->atlb_entry[0].ul_gpp_va;
if (!trace_read) {
ul_shm_offset_virt =
ul_shm_base_virt - ul_tlb_base_virt;
ul_shm_offset_virt +=
PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base +
- 1, PAGE_SIZE * 16);
+ 1, HW_PAGE_SIZE64KB);
dw_ext_prog_virt_mem -= ul_shm_offset_virt;
dw_ext_prog_virt_mem +=
(ul_ext_base - ul_dyn_ext_base);
@@ -317,9 +318,8 @@ int write_ext_dsp_data(struct bridge_dev_context *dev_context,
ret = -EPERM;
if (!ret) {
- ul_tlb_base_virt = dev_context->sh_s.seg0_da *
- DSPWORDSIZE;
-
+ ul_tlb_base_virt =
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
if (symbols_reloaded) {
@@ -337,7 +337,7 @@ int write_ext_dsp_data(struct bridge_dev_context *dev_context,
ul_shm_base_virt - ul_tlb_base_virt;
if (trace_load) {
dw_ext_prog_virt_mem =
- dev_context->sh_s.seg0_va;
+ dev_context->atlb_entry[0].ul_gpp_va;
} else {
dw_ext_prog_virt_mem = host_res->dw_mem_base[1];
dw_ext_prog_virt_mem +=
@@ -393,6 +393,7 @@ int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
omap_dspbridge_dev->dev.platform_data;
struct cfg_hostres *resources = dev_context->resources;
int status = 0;
+ u32 temp;
if (!dev_context->mbox)
return 0;
@@ -436,7 +437,7 @@ int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
omap_mbox_restore_ctx(dev_context->mbox);
/* Access MMU SYS CONFIG register to generate a short wakeup */
- iommu_read_reg(dev_context->dsp_mmu, MMU_SYSCONFIG);
+ temp = readl(resources->dw_dmmu_base + 0x10);
dev_context->dw_brd_state = BRD_RUNNING;
} else if (dev_context->dw_brd_state == BRD_RETENTION) {
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
index e24ea0c73914..3430418190da 100644
--- a/drivers/staging/tidspbridge/core/ue_deh.c
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -31,6 +31,57 @@
#include <dspbridge/drv.h>
#include <dspbridge/wdt.h>
+static u32 fault_addr;
+
+static void mmu_fault_dpc(unsigned long data)
+{
+ struct deh_mgr *deh = (void *)data;
+
+ if (!deh)
+ return;
+
+ bridge_deh_notify(deh, DSP_MMUFAULT, 0);
+}
+
+static irqreturn_t mmu_fault_isr(int irq, void *data)
+{
+ struct deh_mgr *deh = data;
+ struct cfg_hostres *resources;
+ u32 event;
+
+ if (!deh)
+ return IRQ_HANDLED;
+
+ resources = deh->hbridge_context->resources;
+ if (!resources) {
+ dev_dbg(bridge, "%s: Failed to get Host Resources\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ hw_mmu_event_status(resources->dw_dmmu_base, &event);
+ if (event == HW_MMU_TRANSLATION_FAULT) {
+ hw_mmu_fault_addr_read(resources->dw_dmmu_base, &fault_addr);
+ dev_dbg(bridge, "%s: event=0x%x, fault_addr=0x%x\n", __func__,
+ event, fault_addr);
+ /*
+ * Schedule a DPC directly. In the future, it may be
+ * necessary to check if DSP MMU fault is intended for
+ * Bridge.
+ */
+ tasklet_schedule(&deh->dpc_tasklet);
+
+ /* Disable the MMU events, else once we clear it will
+ * start to raise INTs again */
+ hw_mmu_event_disable(resources->dw_dmmu_base,
+ HW_MMU_TRANSLATION_FAULT);
+ } else {
+ hw_mmu_event_disable(resources->dw_dmmu_base,
+ HW_MMU_ALL_INTERRUPTS);
+ }
+ return IRQ_HANDLED;
+}
+
int bridge_deh_create(struct deh_mgr **ret_deh,
struct dev_object *hdev_obj)
{
@@ -58,9 +109,18 @@ int bridge_deh_create(struct deh_mgr **ret_deh,
}
ntfy_init(deh->ntfy_obj);
+ /* Create a MMUfault DPC */
+ tasklet_init(&deh->dpc_tasklet, mmu_fault_dpc, (u32) deh);
+
/* Fill in context structure */
deh->hbridge_context = hbridge_context;
+ /* Install ISR function for DSP MMU fault */
+ status = request_irq(INT_DSP_MMU_IRQ, mmu_fault_isr, 0,
+ "DspBridge\tiommu fault", deh);
+ if (status < 0)
+ goto err;
+
*ret_deh = deh;
return 0;
@@ -80,6 +140,11 @@ int bridge_deh_destroy(struct deh_mgr *deh)
ntfy_delete(deh->ntfy_obj);
kfree(deh->ntfy_obj);
}
+ /* Disable DSP MMU fault */
+ free_irq(INT_DSP_MMU_IRQ, deh);
+
+ /* Free DPC object */
+ tasklet_kill(&deh->dpc_tasklet);
/* Deallocate the DEH manager object */
kfree(deh);
@@ -101,6 +166,48 @@ int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask,
return ntfy_unregister(deh->ntfy_obj, hnotification);
}
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
+{
+ struct cfg_hostres *resources;
+ struct hw_mmu_map_attrs_t map_attrs = {
+ .endianism = HW_LITTLE_ENDIAN,
+ .element_size = HW_ELEM_SIZE16BIT,
+ .mixed_size = HW_MMU_CPUES,
+ };
+ void *dummy_va_addr;
+
+ resources = dev_context->resources;
+ dummy_va_addr = (void*)__get_free_page(GFP_ATOMIC);
+
+ /*
+ * Before acking the MMU fault, let's make sure MMU can only
+ * access entry #0. Then add a new entry so that the DSP OS
+ * can continue in order to dump the stack.
+ */
+ hw_mmu_twl_disable(resources->dw_dmmu_base);
+ hw_mmu_tlb_flush_all(resources->dw_dmmu_base);
+
+ hw_mmu_tlb_add(resources->dw_dmmu_base,
+ virt_to_phys(dummy_va_addr), fault_addr,
+ HW_PAGE_SIZE4KB, 1,
+ &map_attrs, HW_SET, HW_SET);
+
+ dsp_clk_enable(DSP_CLK_GPT8);
+
+ dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
+
+ /* Clear MMU interrupt */
+ hw_mmu_event_ack(resources->dw_dmmu_base,
+ HW_MMU_TRANSLATION_FAULT);
+ dump_dsp_stack(dev_context);
+ dsp_clk_disable(DSP_CLK_GPT8);
+
+ hw_mmu_disable(resources->dw_dmmu_base);
+ free_page((unsigned long)dummy_va_addr);
+}
+#endif
+
static inline const char *event_to_string(int event)
{
switch (event) {
@@ -133,7 +240,13 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
#endif
break;
case DSP_MMUFAULT:
- dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, info);
+ dev_err(bridge, "%s: %s, addr=0x%x", __func__,
+ str, fault_addr);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+ print_dsp_trace_buffer(dev_context);
+ dump_dl_modules(dev_context);
+ mmu_fault_print_stack(dev_context);
+#endif
break;
default:
dev_err(bridge, "%s: %s", __func__, str);
diff --git a/drivers/staging/tidspbridge/hw/EasiGlobal.h b/drivers/staging/tidspbridge/hw/EasiGlobal.h
new file mode 100644
index 000000000000..e48d7f67c60a
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/EasiGlobal.h
@@ -0,0 +1,41 @@
+/*
+ * EasiGlobal.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _EASIGLOBAL_H
+#define _EASIGLOBAL_H
+#include <linux/types.h>
+
+/*
+ * DEFINE: READ_ONLY, WRITE_ONLY & READ_WRITE
+ *
+ * DESCRIPTION: Defines used to describe register types for EASI-checker tests.
+ */
+
+#define READ_ONLY 1
+#define WRITE_ONLY 2
+#define READ_WRITE 3
+
+/*
+ * MACRO: _DEBUG_LEVEL1_EASI
+ *
+ * DESCRIPTION: A MACRO which can be used to indicate that a particular beach
+ * register access function was called.
+ *
+ * NOTE: We currently dont use this functionality.
+ */
+#define _DEBUG_LEVEL1_EASI(easi_num) ((void)0)
+
+#endif /* _EASIGLOBAL_H */
diff --git a/drivers/staging/tidspbridge/hw/MMUAccInt.h b/drivers/staging/tidspbridge/hw/MMUAccInt.h
new file mode 100644
index 000000000000..1cefca321d71
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/MMUAccInt.h
@@ -0,0 +1,76 @@
+/*
+ * MMUAccInt.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_ACC_INT_H
+#define _MMU_ACC_INT_H
+
+/* Mappings of level 1 EASI function numbers to function names */
+
+#define EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32 (MMU_BASE_EASIL1 + 3)
+#define EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32 (MMU_BASE_EASIL1 + 17)
+#define EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32 (MMU_BASE_EASIL1 + 39)
+#define EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 51)
+#define EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32 (MMU_BASE_EASIL1 + 102)
+#define EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 103)
+#define EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32 (MMU_BASE_EASIL1 + 156)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32 (MMU_BASE_EASIL1 + 174)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32 (MMU_BASE_EASIL1 + 180)
+#define EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32 (MMU_BASE_EASIL1 + 190)
+#define EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32 (MMU_BASE_EASIL1 + 194)
+#define EASIL1_MMUMMU_TTB_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 198)
+#define EASIL1_MMUMMU_LOCK_READ_REGISTER32 (MMU_BASE_EASIL1 + 203)
+#define EASIL1_MMUMMU_LOCK_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 204)
+#define EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32 (MMU_BASE_EASIL1 + 205)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32 (MMU_BASE_EASIL1 + 209)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32 (MMU_BASE_EASIL1 + 211)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32 (MMU_BASE_EASIL1 + 212)
+#define EASIL1_MMUMMU_LD_TLB_READ_REGISTER32 (MMU_BASE_EASIL1 + 213)
+#define EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 214)
+#define EASIL1_MMUMMU_CAM_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 226)
+#define EASIL1_MMUMMU_RAM_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 268)
+#define EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 322)
+
+/* Register offset address definitions */
+#define MMU_MMU_SYSCONFIG_OFFSET 0x10
+#define MMU_MMU_IRQSTATUS_OFFSET 0x18
+#define MMU_MMU_IRQENABLE_OFFSET 0x1c
+#define MMU_MMU_WALKING_ST_OFFSET 0x40
+#define MMU_MMU_CNTL_OFFSET 0x44
+#define MMU_MMU_FAULT_AD_OFFSET 0x48
+#define MMU_MMU_TTB_OFFSET 0x4c
+#define MMU_MMU_LOCK_OFFSET 0x50
+#define MMU_MMU_LD_TLB_OFFSET 0x54
+#define MMU_MMU_CAM_OFFSET 0x58
+#define MMU_MMU_RAM_OFFSET 0x5c
+#define MMU_MMU_GFLUSH_OFFSET 0x60
+#define MMU_MMU_FLUSH_ENTRY_OFFSET 0x64
+/* Bitfield mask and offset declarations */
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_MASK 0x18
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET 3
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK 0x1
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET 0
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_MASK 0x1
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET 0
+#define MMU_MMU_CNTL_TWL_ENABLE_MASK 0x4
+#define MMU_MMU_CNTL_TWL_ENABLE_OFFSET 2
+#define MMU_MMU_CNTL_MMU_ENABLE_MASK 0x2
+#define MMU_MMU_CNTL_MMU_ENABLE_OFFSET 1
+#define MMU_MMU_LOCK_BASE_VALUE_MASK 0xfc00
+#define MMU_MMU_LOCK_BASE_VALUE_OFFSET 10
+#define MMU_MMU_LOCK_CURRENT_VICTIM_MASK 0x3f0
+#define MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET 4
+
+#endif /* _MMU_ACC_INT_H */
diff --git a/drivers/staging/tidspbridge/hw/MMURegAcM.h b/drivers/staging/tidspbridge/hw/MMURegAcM.h
new file mode 100644
index 000000000000..ab1a16da731c
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/MMURegAcM.h
@@ -0,0 +1,225 @@
+/*
+ * MMURegAcM.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_REG_ACM_H
+#define _MMU_REG_ACM_H
+
+#include <linux/io.h>
+#include <EasiGlobal.h>
+
+#include "MMUAccInt.h"
+
+#if defined(USE_LEVEL_1_MACROS)
+
+#define MMUMMU_SYSCONFIG_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_SYSCONFIG_OFFSET))
+
+#define MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32);\
+ data &= ~(MMU_MMU_SYSCONFIG_IDLE_MODE_MASK);\
+ new_value <<= MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET;\
+ new_value &= MMU_MMU_SYSCONFIG_IDLE_MODE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32);\
+ data &= ~(MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK);\
+ new_value <<= MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET;\
+ new_value &= MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_IRQSTATUS_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(easil1_mmummu_irqstatus_read_register32),\
+ __raw_readl((base_address)+MMU_MMU_IRQSTATUS_OFFSET))
+
+#define MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_IRQSTATUS_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_IRQENABLE_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_IRQENABLE_OFFSET))
+
+#define MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_IRQENABLE_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_WALKING_STTWL_RUNNING_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_WALKING_ST_OFFSET))))\
+ & MMU_MMU_WALKING_ST_TWL_RUNNING_MASK) >>\
+ MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_CNTL_OFFSET)))) &\
+ MMU_MMU_CNTL_TWL_ENABLE_MASK) >>\
+ MMU_MMU_CNTL_TWL_ENABLE_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CNTL_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32);\
+ data &= ~(MMU_MMU_CNTL_TWL_ENABLE_MASK);\
+ new_value <<= MMU_MMU_CNTL_TWL_ENABLE_OFFSET;\
+ new_value &= MMU_MMU_CNTL_TWL_ENABLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CNTL_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32);\
+ data &= ~(MMU_MMU_CNTL_MMU_ENABLE_MASK);\
+ new_value <<= MMU_MMU_CNTL_MMU_ENABLE_OFFSET;\
+ new_value &= MMU_MMU_CNTL_MMU_ENABLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_FAULT_AD_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_FAULT_AD_OFFSET))
+
+#define MMUMMU_TTB_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_TTB_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_TTB_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_LOCK_OFFSET))
+
+#define MMUMMU_LOCK_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_BASE_VALUE_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+ MMU_MMU_LOCK_BASE_VALUE_MASK) >>\
+ MMU_MMU_LOCK_BASE_VALUE_OFFSET))
+
+#define MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(easil1_mmummu_lock_base_value_write32);\
+ data &= ~(MMU_MMU_LOCK_BASE_VALUE_MASK);\
+ new_value <<= MMU_MMU_LOCK_BASE_VALUE_OFFSET;\
+ new_value &= MMU_MMU_LOCK_BASE_VALUE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+ MMU_MMU_LOCK_CURRENT_VICTIM_MASK) >>\
+ MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET))
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32);\
+ data &= ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK);\
+ new_value <<= MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET;\
+ new_value &= MMU_MMU_LOCK_CURRENT_VICTIM_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_SET32(var, value)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32),\
+ (((var) & ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK)) |\
+ (((value) << MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET) &\
+ MMU_MMU_LOCK_CURRENT_VICTIM_MASK)))
+
+#define MMUMMU_LD_TLB_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_LD_TLB_OFFSET))
+
+#define MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LD_TLB_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_CAM_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CAM_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CAM_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_RAM_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_RAM_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_RAM_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_FLUSH_ENTRY_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#endif /* USE_LEVEL_1_MACROS */
+
+#endif /* _MMU_REG_ACM_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_defs.h b/drivers/staging/tidspbridge/hw/hw_defs.h
new file mode 100644
index 000000000000..d5266d4c163f
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_defs.h
@@ -0,0 +1,58 @@
+/*
+ * hw_defs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global HW definitions
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_DEFS_H
+#define _HW_DEFS_H
+
+/* Page size */
+#define HW_PAGE_SIZE4KB 0x1000
+#define HW_PAGE_SIZE64KB 0x10000
+#define HW_PAGE_SIZE1MB 0x100000
+#define HW_PAGE_SIZE16MB 0x1000000
+
+/* hw_status: return type for HW API */
+typedef long hw_status;
+
+/* Macro used to set and clear any bit */
+#define HW_CLEAR 0
+#define HW_SET 1
+
+/* hw_endianism_t: Enumerated Type used to specify the endianism
+ * Do NOT change these values. They are used as bit fields. */
+enum hw_endianism_t {
+ HW_LITTLE_ENDIAN,
+ HW_BIG_ENDIAN
+};
+
+/* hw_element_size_t: Enumerated Type used to specify the element size
+ * Do NOT change these values. They are used as bit fields. */
+enum hw_element_size_t {
+ HW_ELEM_SIZE8BIT,
+ HW_ELEM_SIZE16BIT,
+ HW_ELEM_SIZE32BIT,
+ HW_ELEM_SIZE64BIT
+};
+
+/* hw_idle_mode_t: Enumerated Type used to specify Idle modes */
+enum hw_idle_mode_t {
+ HW_FORCE_IDLE,
+ HW_NO_IDLE,
+ HW_SMART_IDLE
+};
+
+#endif /* _HW_DEFS_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c
new file mode 100644
index 000000000000..014f5d5293ae
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_mmu.c
@@ -0,0 +1,562 @@
+/*
+ * hw_mmu.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * API definitions to setup MMU TLB and PTE
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/io.h>
+#include "MMURegAcM.h"
+#include <hw_defs.h>
+#include <hw_mmu.h>
+#include <linux/types.h>
+#include <linux/err.h>
+
+#define MMU_BASE_VAL_MASK 0xFC00
+#define MMU_PAGE_MAX 3
+#define MMU_ELEMENTSIZE_MAX 3
+#define MMU_ADDR_MASK 0xFFFFF000
+#define MMU_TTB_MASK 0xFFFFC000
+#define MMU_SECTION_ADDR_MASK 0xFFF00000
+#define MMU_SSECTION_ADDR_MASK 0xFF000000
+#define MMU_PAGE_TABLE_MASK 0xFFFFFC00
+#define MMU_LARGE_PAGE_MASK 0xFFFF0000
+#define MMU_SMALL_PAGE_MASK 0xFFFFF000
+
+#define MMU_LOAD_TLB 0x00000001
+#define MMU_GFLUSH 0x60
+
+/*
+ * hw_mmu_page_size_t: Enumerated Type used to specify the MMU Page Size(SLSS)
+ */
+enum hw_mmu_page_size_t {
+ HW_MMU_SECTION,
+ HW_MMU_LARGE_PAGE,
+ HW_MMU_SMALL_PAGE,
+ HW_MMU_SUPERSECTION
+};
+
+/*
+ * FUNCTION : mmu_flush_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * Type : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer
+ * Paramater was set to NULL
+ *
+ * PURPOSE: : Flush the TLB entry pointed by the
+ * lock counter register
+ * even if this entry is set protected
+ *
+ * METHOD: : Check the Input parameter and Flush a
+ * single entry in the TLB.
+ */
+static hw_status mmu_flush_entry(const void __iomem *base_address);
+
+/*
+ * FUNCTION : mmu_set_cam_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * TypE : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * Identifier : page_sz
+ * TypE : const u32
+ * Description : It indicates the page size
+ *
+ * Identifier : preserved_bit
+ * Type : const u32
+ * Description : It indicates the TLB entry is preserved entry
+ * or not
+ *
+ * Identifier : valid_bit
+ * Type : const u32
+ * Description : It indicates the TLB entry is valid entry or not
+ *
+ *
+ * Identifier : virtual_addr_tag
+ * Type : const u32
+ * Description : virtual Address
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer Paramater
+ * was set to NULL
+ * RET_PARAM_OUT_OF_RANGE -- Input Parameter out
+ * of Range
+ *
+ * PURPOSE: : Set MMU_CAM reg
+ *
+ * METHOD: : Check the Input parameters and set the CAM entry.
+ */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+ const u32 page_sz,
+ const u32 preserved_bit,
+ const u32 valid_bit,
+ const u32 virtual_addr_tag);
+
+/*
+ * FUNCTION : mmu_set_ram_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * Type : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * Identifier : physical_addr
+ * Type : const u32
+ * Description : Physical Address to which the corresponding
+ * virtual Address shouldpoint
+ *
+ * Identifier : endianism
+ * Type : hw_endianism_t
+ * Description : endianism for the given page
+ *
+ * Identifier : element_size
+ * Type : hw_element_size_t
+ * Description : The element size ( 8,16, 32 or 64 bit)
+ *
+ * Identifier : mixed_size
+ * Type : hw_mmu_mixed_size_t
+ * Description : Element Size to follow CPU or TLB
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer Paramater
+ * was set to NULL
+ * RET_PARAM_OUT_OF_RANGE -- Input Parameter
+ * out of Range
+ *
+ * PURPOSE: : Set MMU_CAM reg
+ *
+ * METHOD: : Check the Input parameters and set the RAM entry.
+ */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+ const u32 physical_addr,
+ enum hw_endianism_t endianism,
+ enum hw_element_size_t element_size,
+ enum hw_mmu_mixed_size_t mixed_size);
+
+/* HW FUNCTIONS */
+
+hw_status hw_mmu_enable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_SET);
+
+ return status;
+}
+
+hw_status hw_mmu_disable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+ return status;
+}
+
+hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+ u32 num_locked_entries)
+{
+ hw_status status = 0;
+
+ MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, num_locked_entries);
+
+ return status;
+}
+
+hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+ u32 victim_entry_num)
+{
+ hw_status status = 0;
+
+ MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, victim_entry_num);
+
+ return status;
+}
+
+hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+
+ MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+ u32 irq_reg;
+
+ irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+ MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg & ~irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+ u32 irq_reg;
+
+ irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+ MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg | irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask)
+{
+ hw_status status = 0;
+
+ *irq_mask = MMUMMU_IRQSTATUS_READ_REGISTER32(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr)
+{
+ hw_status status = 0;
+
+ /* read values from register */
+ *addr = MMUMMU_FAULT_AD_READ_REGISTER32(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr)
+{
+ hw_status status = 0;
+ u32 load_ttb;
+
+ load_ttb = ttb_phys_addr & ~0x7FUL;
+ /* write values to register */
+ MMUMMU_TTB_WRITE_REGISTER32(base_address, load_ttb);
+
+ return status;
+}
+
+hw_status hw_mmu_twl_enable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_SET);
+
+ return status;
+}
+
+hw_status hw_mmu_twl_disable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+ return status;
+}
+
+hw_status hw_mmu_tlb_flush(const void __iomem *base_address, u32 virtual_addr,
+ u32 page_sz)
+{
+ hw_status status = 0;
+ u32 virtual_addr_tag;
+ enum hw_mmu_page_size_t pg_size_bits;
+
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ pg_size_bits = HW_MMU_SMALL_PAGE;
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ pg_size_bits = HW_MMU_LARGE_PAGE;
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ pg_size_bits = HW_MMU_SECTION;
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ pg_size_bits = HW_MMU_SUPERSECTION;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Generate the 20-bit tag from virtual address */
+ virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+ mmu_set_cam_entry(base_address, pg_size_bits, 0, 0, virtual_addr_tag);
+
+ mmu_flush_entry(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ u32 entry_num,
+ struct hw_mmu_map_attrs_t *map_attrs,
+ s8 preserved_bit, s8 valid_bit)
+{
+ hw_status status = 0;
+ u32 lock_reg;
+ u32 virtual_addr_tag;
+ enum hw_mmu_page_size_t mmu_pg_size;
+
+ /*Check the input Parameters */
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ mmu_pg_size = HW_MMU_SMALL_PAGE;
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ mmu_pg_size = HW_MMU_LARGE_PAGE;
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ mmu_pg_size = HW_MMU_SECTION;
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ mmu_pg_size = HW_MMU_SUPERSECTION;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ lock_reg = MMUMMU_LOCK_READ_REGISTER32(base_address);
+
+ /* Generate the 20-bit tag from virtual address */
+ virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+ /* Write the fields in the CAM Entry Register */
+ mmu_set_cam_entry(base_address, mmu_pg_size, preserved_bit, valid_bit,
+ virtual_addr_tag);
+
+ /* Write the different fields of the RAM Entry Register */
+ /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit) */
+ mmu_set_ram_entry(base_address, physical_addr, map_attrs->endianism,
+ map_attrs->element_size, map_attrs->mixed_size);
+
+ /* Update the MMU Lock Register */
+ /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1) */
+ MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, entry_num);
+
+ /* Enable loading of an entry in TLB by writing 1
+ into LD_TLB_REG register */
+ MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, MMU_LOAD_TLB);
+
+ MMUMMU_LOCK_WRITE_REGISTER32(base_address, lock_reg);
+
+ return status;
+}
+
+hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz, struct hw_mmu_map_attrs_t *map_attrs)
+{
+ hw_status status = 0;
+ u32 pte_addr, pte_val;
+ s32 num_entries = 1;
+
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_SMALL_PAGE_MASK);
+ pte_val =
+ ((physical_addr & MMU_SMALL_PAGE_MASK) |
+ (map_attrs->endianism << 9) | (map_attrs->
+ element_size << 4) |
+ (map_attrs->mixed_size << 11) | 2);
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_LARGE_PAGE_MASK);
+ pte_val =
+ ((physical_addr & MMU_LARGE_PAGE_MASK) |
+ (map_attrs->endianism << 9) | (map_attrs->
+ element_size << 4) |
+ (map_attrs->mixed_size << 11) | 1);
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ pte_val =
+ ((((physical_addr & MMU_SECTION_ADDR_MASK) |
+ (map_attrs->endianism << 15) | (map_attrs->
+ element_size << 10) |
+ (map_attrs->mixed_size << 17)) & ~0x40000) | 0x2);
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SSECTION_ADDR_MASK);
+ pte_val =
+ (((physical_addr & MMU_SSECTION_ADDR_MASK) |
+ (map_attrs->endianism << 15) | (map_attrs->
+ element_size << 10) |
+ (map_attrs->mixed_size << 17)
+ ) | 0x40000 | 0x2);
+ break;
+
+ case HW_MMU_COARSE_PAGE_SIZE:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ pte_val = (physical_addr & MMU_PAGE_TABLE_MASK) | 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ while (--num_entries >= 0)
+ ((u32 *) pte_addr)[num_entries] = pte_val;
+
+ return status;
+}
+
+hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size)
+{
+ hw_status status = 0;
+ u32 pte_addr;
+ s32 num_entries = 1;
+
+ switch (page_size) {
+ case HW_PAGE_SIZE4KB:
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_SMALL_PAGE_MASK);
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_LARGE_PAGE_MASK);
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ case HW_MMU_COARSE_PAGE_SIZE:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SSECTION_ADDR_MASK);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ while (--num_entries >= 0)
+ ((u32 *) pte_addr)[num_entries] = 0;
+
+ return status;
+}
+
+/* mmu_flush_entry */
+static hw_status mmu_flush_entry(const void __iomem *base_address)
+{
+ hw_status status = 0;
+ u32 flush_entry_data = 0x1;
+
+ /* write values to register */
+ MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, flush_entry_data);
+
+ return status;
+}
+
+/* mmu_set_cam_entry */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+ const u32 page_sz,
+ const u32 preserved_bit,
+ const u32 valid_bit,
+ const u32 virtual_addr_tag)
+{
+ hw_status status = 0;
+ u32 mmu_cam_reg;
+
+ mmu_cam_reg = (virtual_addr_tag << 12);
+ mmu_cam_reg = (mmu_cam_reg) | (page_sz) | (valid_bit << 2) |
+ (preserved_bit << 3);
+
+ /* write values to register */
+ MMUMMU_CAM_WRITE_REGISTER32(base_address, mmu_cam_reg);
+
+ return status;
+}
+
+/* mmu_set_ram_entry */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+ const u32 physical_addr,
+ enum hw_endianism_t endianism,
+ enum hw_element_size_t element_size,
+ enum hw_mmu_mixed_size_t mixed_size)
+{
+ hw_status status = 0;
+ u32 mmu_ram_reg;
+
+ mmu_ram_reg = (physical_addr & MMU_ADDR_MASK);
+ mmu_ram_reg = (mmu_ram_reg) | ((endianism << 9) | (element_size << 7) |
+ (mixed_size << 6));
+
+ /* write values to register */
+ MMUMMU_RAM_WRITE_REGISTER32(base_address, mmu_ram_reg);
+
+ return status;
+
+}
+
+void hw_mmu_tlb_flush_all(const void __iomem *base)
+{
+ __raw_writeb(1, base + MMU_GFLUSH);
+}
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.h b/drivers/staging/tidspbridge/hw/hw_mmu.h
new file mode 100644
index 000000000000..1458a2c6027b
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_mmu.h
@@ -0,0 +1,163 @@
+/*
+ * hw_mmu.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * MMU types and API declarations
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_MMU_H
+#define _HW_MMU_H
+
+#include <linux/types.h>
+
+/* Bitmasks for interrupt sources */
+#define HW_MMU_TRANSLATION_FAULT 0x2
+#define HW_MMU_ALL_INTERRUPTS 0x1F
+
+#define HW_MMU_COARSE_PAGE_SIZE 0x400
+
+/* hw_mmu_mixed_size_t: Enumerated Type used to specify whether to follow
+ CPU/TLB Element size */
+enum hw_mmu_mixed_size_t {
+ HW_MMU_TLBES,
+ HW_MMU_CPUES
+};
+
+/* hw_mmu_map_attrs_t: Struct containing MMU mapping attributes */
+struct hw_mmu_map_attrs_t {
+ enum hw_endianism_t endianism;
+ enum hw_element_size_t element_size;
+ enum hw_mmu_mixed_size_t mixed_size;
+ bool donotlockmpupage;
+};
+
+extern hw_status hw_mmu_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+ u32 num_locked_entries);
+
+extern hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+ u32 victim_entry_num);
+
+/* For MMU faults */
+extern hw_status hw_mmu_event_ack(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_disable(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_enable(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_status(const void __iomem *base_address,
+ u32 *irq_mask);
+
+extern hw_status hw_mmu_fault_addr_read(const void __iomem *base_address,
+ u32 *addr);
+
+/* Set the TT base address */
+extern hw_status hw_mmu_ttb_set(const void __iomem *base_address,
+ u32 ttb_phys_addr);
+
+extern hw_status hw_mmu_twl_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_twl_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_tlb_flush(const void __iomem *base_address,
+ u32 virtual_addr, u32 page_sz);
+
+extern hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ u32 entry_num,
+ struct hw_mmu_map_attrs_t *map_attrs,
+ s8 preserved_bit, s8 valid_bit);
+
+/* For PTEs */
+extern hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ struct hw_mmu_map_attrs_t *map_attrs);
+
+extern hw_status hw_mmu_pte_clear(const u32 pg_tbl_va,
+ u32 virtual_addr, u32 page_size);
+
+void hw_mmu_tlb_flush_all(const void __iomem *base);
+
+static inline u32 hw_mmu_pte_addr_l1(u32 l1_base, u32 va)
+{
+ u32 pte_addr;
+ u32 va31_to20;
+
+ va31_to20 = va >> (20 - 2); /* Left-shift by 2 here itself */
+ va31_to20 &= 0xFFFFFFFCUL;
+ pte_addr = l1_base + va31_to20;
+
+ return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_addr_l2(u32 l2_base, u32 va)
+{
+ u32 pte_addr;
+
+ pte_addr = (l2_base & 0xFFFFFC00) | ((va >> 10) & 0x3FC);
+
+ return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_coarse_l1(u32 pte_val)
+{
+ u32 pte_coarse;
+
+ pte_coarse = pte_val & 0xFFFFFC00;
+
+ return pte_coarse;
+}
+
+static inline u32 hw_mmu_pte_size_l1(u32 pte_val)
+{
+ u32 pte_size = 0;
+
+ if ((pte_val & 0x3) == 0x1) {
+ /* Points to L2 PT */
+ pte_size = HW_MMU_COARSE_PAGE_SIZE;
+ }
+
+ if ((pte_val & 0x3) == 0x2) {
+ if (pte_val & (1 << 18))
+ pte_size = HW_PAGE_SIZE16MB;
+ else
+ pte_size = HW_PAGE_SIZE1MB;
+ }
+
+ return pte_size;
+}
+
+static inline u32 hw_mmu_pte_size_l2(u32 pte_val)
+{
+ u32 pte_size = 0;
+
+ if (pte_val & 0x2)
+ pte_size = HW_PAGE_SIZE4KB;
+ else if (pte_val & 0x1)
+ pte_size = HW_PAGE_SIZE64KB;
+
+ return pte_size;
+}
+
+#endif /* _HW_MMU_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h b/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
index dfb55cca34c7..38122dbf877a 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
@@ -68,6 +68,7 @@ struct cfg_hostres {
void __iomem *dw_per_base;
u32 dw_per_pm_base;
u32 dw_core_pm_base;
+ void __iomem *dw_dmmu_base;
void __iomem *dw_sys_ctrl_base;
};
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dev.h b/drivers/staging/tidspbridge/include/dspbridge/dev.h
index 9bdd48f57429..357458fadd2a 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dev.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dev.h
@@ -27,6 +27,7 @@
#include <dspbridge/nodedefs.h>
#include <dspbridge/dispdefs.h>
#include <dspbridge/dspdefs.h>
+#include <dspbridge/dmm.h>
#include <dspbridge/host_os.h>
/* ----------------------------------- This */
@@ -233,6 +234,29 @@ extern int dev_get_cmm_mgr(struct dev_object *hdev_obj,
struct cmm_object **mgr);
/*
+ * ======== dev_get_dmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the dynamic memory manager created for this
+ * device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *mgr contains a handle to a channel manager object,
+ * or NULL.
+ * else: *mgr is NULL.
+ */
+extern int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+ struct dmm_object **mgr);
+
+/*
* ======== dev_get_cod_mgr ========
* Purpose:
* Retrieve the COD manager create for this device.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dmm.h b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
new file mode 100644
index 000000000000..6c58335c5f60
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
@@ -0,0 +1,75 @@
+/*
+ * dmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Mapping(DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DMM_
+#define DMM_
+
+#include <dspbridge/dbdefs.h>
+
+struct dmm_object;
+
+/* DMM attributes used in dmm_create() */
+struct dmm_mgrattrs {
+ u32 reserved;
+};
+
+#define DMMPOOLSIZE 0x4000000
+
+/*
+ * ======== dmm_get_handle ========
+ * Purpose:
+ * Return the dynamic memory manager object for this device.
+ * This is typically called from the client process.
+ */
+
+extern int dmm_get_handle(void *hprocessor,
+ struct dmm_object **dmm_manager);
+
+extern int dmm_reserve_memory(struct dmm_object *dmm_mgr,
+ u32 size, u32 *prsv_addr);
+
+extern int dmm_un_reserve_memory(struct dmm_object *dmm_mgr,
+ u32 rsv_addr);
+
+extern int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr,
+ u32 size);
+
+extern int dmm_un_map_memory(struct dmm_object *dmm_mgr,
+ u32 addr, u32 *psize);
+
+extern int dmm_destroy(struct dmm_object *dmm_mgr);
+
+extern int dmm_delete_tables(struct dmm_object *dmm_mgr);
+
+extern int dmm_create(struct dmm_object **dmm_manager,
+ struct dev_object *hdev_obj,
+ const struct dmm_mgrattrs *mgr_attrts);
+
+extern bool dmm_init(void);
+
+extern void dmm_exit(void);
+
+extern int dmm_create_tables(struct dmm_object *dmm_mgr,
+ u32 addr, u32 size);
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr);
+#endif
+
+#endif /* DMM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/drv.h b/drivers/staging/tidspbridge/include/dspbridge/drv.h
index 75a2c9b5c6f2..c1f363ec9afa 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/drv.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/drv.h
@@ -108,6 +108,12 @@ struct dmm_map_object {
struct bridge_dma_map_info dma_info;
};
+/* Used for DMM reserved memory accounting */
+struct dmm_rsv_object {
+ struct list_head link;
+ u32 dsp_reserved_addr;
+};
+
/* New structure (member of process context) abstracts DMM resource info */
struct dspheap_res_object {
s32 heap_allocated; /* DMM status */
@@ -159,6 +165,10 @@ struct process_context {
struct list_head dmm_map_list;
spinlock_t dmm_map_lock;
+ /* DMM reserved memory resources */
+ struct list_head dmm_rsv_list;
+ spinlock_t dmm_rsv_lock;
+
/* DSP Heap resources */
struct dspheap_res_object *pdspheap_list;
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h b/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h
deleted file mode 100644
index cb38d4cc0734..000000000000
--- a/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * dsp-mmu.h
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * DSP iommu.
- *
- * Copyright (C) 2005-2010 Texas Instruments, Inc.
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef _DSP_MMU_
-#define _DSP_MMU_
-
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-
-/**
- * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
- *
- * This function initialize dsp mmu module and returns a struct iommu
- * handle to use it for dsp maps.
- *
- */
-struct iommu *dsp_mmu_init(void);
-
-/**
- * dsp_mmu_exit() - destroy dsp mmu module
- * @mmu: Pointer to iommu handle.
- *
- * This function destroys dsp mmu module.
- *
- */
-void dsp_mmu_exit(struct iommu *mmu);
-
-/**
- * user_to_dsp_map() - maps user to dsp virtual address
- * @mmu: Pointer to iommu handle.
- * @uva: Virtual user space address.
- * @da DSP address
- * @size Buffer size to map.
- * @usr_pgs struct page array pointer where the user pages will be stored
- *
- * This function maps a user space buffer into DSP virtual address.
- *
- */
-u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
- struct page **usr_pgs);
-
-/**
- * user_to_dsp_unmap() - unmaps DSP virtual buffer.
- * @mmu: Pointer to iommu handle.
- * @da DSP address
- *
- * This function unmaps a user space buffer into DSP virtual address.
- *
- */
-int user_to_dsp_unmap(struct iommu *mmu, u32 da);
-
-#endif
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
index 615363474810..0ae7d1646a1b 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
@@ -162,6 +162,48 @@ typedef int(*fxn_brd_memwrite) (struct bridge_dev_context
u32 mem_type);
/*
+ * ======== bridge_brd_mem_map ========
+ * Purpose:
+ * Map a MPU memory region to a DSP/IVA memory space
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * ul_mpu_addr: MPU memory region start address.
+ * virt_addr: DSP/IVA memory region u8 address.
+ * ul_num_bytes: Number of bytes to map.
+ * map_attrs: Mapping attributes (e.g. endianness).
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * Ensures:
+ */
+typedef int(*fxn_brd_memmap) (struct bridge_dev_context
+ * dev_ctxt, u32 ul_mpu_addr,
+ u32 virt_addr, u32 ul_num_bytes,
+ u32 map_attr,
+ struct page **mapped_pages);
+
+/*
+ * ======== bridge_brd_mem_un_map ========
+ * Purpose:
+ * UnMap an MPU memory region from DSP/IVA memory space
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * virt_addr: DSP/IVA memory region u8 address.
+ * ul_num_bytes: Number of bytes to unmap.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * Ensures:
+ */
+typedef int(*fxn_brd_memunmap) (struct bridge_dev_context
+ * dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes);
+
+/*
* ======== bridge_brd_stop ========
* Purpose:
* Bring board to the BRD_STOPPED state.
@@ -951,6 +993,8 @@ struct bridge_drv_interface {
fxn_brd_setstate pfn_brd_set_state; /* Sets the Board State */
fxn_brd_memcopy pfn_brd_mem_copy; /* Copies DSP Memory */
fxn_brd_memwrite pfn_brd_mem_write; /* Write DSP Memory w/o halt */
+ fxn_brd_memmap pfn_brd_mem_map; /* Maps MPU mem to DSP mem */
+ fxn_brd_memunmap pfn_brd_mem_un_map; /* Unmaps MPU mem to DSP mem */
fxn_chnl_create pfn_chnl_create; /* Create channel manager. */
fxn_chnl_destroy pfn_chnl_destroy; /* Destroy channel manager. */
fxn_chnl_open pfn_chnl_open; /* Create a new channel. */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
index bad180108ada..41e0594dff34 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
@@ -19,6 +19,10 @@
#ifndef DSPIOCTL_
#define DSPIOCTL_
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
/*
* Any IOCTLS at or above this value are reserved for standard Bridge driver
* interfaces.
@@ -61,6 +65,9 @@ struct bridge_ioctl_extproc {
/* GPP virtual address. __va does not work for ioremapped addresses */
u32 ul_gpp_va;
u32 ul_size; /* Size of the mapped memory in bytes */
+ enum hw_endianism_t endianism;
+ enum hw_mmu_mixed_size_t mixed_mode;
+ enum hw_element_size_t elem_size;
};
#endif /* DSPIOCTL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
index 2d12aab6b5bf..5e09fd165d9d 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/proc.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -551,6 +551,29 @@ extern int proc_map(void *hprocessor,
struct process_context *pr_ctxt);
/*
+ * ======== proc_reserve_memory ========
+ * Purpose:
+ * Reserve a virtually contiguous region of DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * ul_size : Size of the address space to reserve.
+ * pp_rsv_addr : Ptr to DSP side reserved u8 address.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOMEM : Cannot reserve chunk of this size.
+ * Requires:
+ * pp_rsv_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_reserve_memory(void *hprocessor,
+ u32 ul_size, void **pp_rsv_addr,
+ struct process_context *pr_ctxt);
+
+/*
* ======== proc_un_map ========
* Purpose:
* Removes a MPU buffer mapping from the DSP address space.
@@ -572,4 +595,27 @@ extern int proc_map(void *hprocessor,
extern int proc_un_map(void *hprocessor, void *map_addr,
struct process_context *pr_ctxt);
+/*
+ * ======== proc_un_reserve_memory ========
+ * Purpose:
+ * Frees a previously reserved region of DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * prsv_addr : Ptr to DSP side reservedBYTE address.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOENT : Cannot find a reserved region starting with this
+ * : address.
+ * Requires:
+ * prsv_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_un_reserve_memory(void *hprocessor,
+ void *prsv_addr,
+ struct process_context *pr_ctxt);
+
#endif /* PROC_ */
diff --git a/drivers/staging/tidspbridge/pmgr/dev.c b/drivers/staging/tidspbridge/pmgr/dev.c
index 7b30267ef0e2..132e960967b9 100644
--- a/drivers/staging/tidspbridge/pmgr/dev.c
+++ b/drivers/staging/tidspbridge/pmgr/dev.c
@@ -34,6 +34,7 @@
#include <dspbridge/cod.h>
#include <dspbridge/drv.h>
#include <dspbridge/proc.h>
+#include <dspbridge/dmm.h>
/* ----------------------------------- Resource Manager */
#include <dspbridge/mgr.h>
@@ -74,6 +75,7 @@ struct dev_object {
struct msg_mgr *hmsg_mgr; /* Message manager. */
struct io_mgr *hio_mgr; /* IO manager (CHNL, msg_ctrl) */
struct cmm_object *hcmm_mgr; /* SM memory manager. */
+ struct dmm_object *dmm_mgr; /* Dynamic memory manager. */
struct ldr_module *module_obj; /* Bridge Module handle. */
u32 word_size; /* DSP word size: quick access. */
struct drv_object *hdrv_obj; /* Driver Object */
@@ -248,6 +250,9 @@ int dev_create_device(struct dev_object **device_obj,
/* Instantiate the DEH module */
status = bridge_deh_create(&dev_obj->hdeh_mgr, dev_obj);
}
+ /* Create DMM mgr . */
+ status = dmm_create(&dev_obj->dmm_mgr,
+ (struct dev_object *)dev_obj, NULL);
}
/* Add the new DEV_Object to the global list: */
if (!status) {
@@ -273,6 +278,8 @@ leave:
kfree(dev_obj->proc_list);
if (dev_obj->cod_mgr)
cod_delete(dev_obj->cod_mgr);
+ if (dev_obj->dmm_mgr)
+ dmm_destroy(dev_obj->dmm_mgr);
kfree(dev_obj);
}
@@ -382,6 +389,11 @@ int dev_destroy_device(struct dev_object *hdev_obj)
dev_obj->hcmm_mgr = NULL;
}
+ if (dev_obj->dmm_mgr) {
+ dmm_destroy(dev_obj->dmm_mgr);
+ dev_obj->dmm_mgr = NULL;
+ }
+
/* Call the driver's bridge_dev_destroy() function: */
/* Require of DevDestroy */
if (dev_obj->hbridge_context) {
@@ -462,6 +474,32 @@ int dev_get_cmm_mgr(struct dev_object *hdev_obj,
}
/*
+ * ======== dev_get_dmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the dynamic memory manager created for this
+ * device.
+ */
+int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+ struct dmm_object **mgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ if (hdev_obj) {
+ *mgr = dev_obj->dmm_mgr;
+ } else {
+ *mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
+ return status;
+}
+
+/*
* ======== dev_get_cod_mgr ========
* Purpose:
* Retrieve the COD manager create for this device.
@@ -713,8 +751,10 @@ void dev_exit(void)
refs--;
- if (refs == 0)
+ if (refs == 0) {
cmm_exit();
+ dmm_exit();
+ }
DBC_ENSURE(refs >= 0);
}
@@ -726,12 +766,25 @@ void dev_exit(void)
*/
bool dev_init(void)
{
- bool ret = true;
+ bool cmm_ret, dmm_ret, ret = true;
DBC_REQUIRE(refs >= 0);
- if (refs == 0)
- ret = cmm_init();
+ if (refs == 0) {
+ cmm_ret = cmm_init();
+ dmm_ret = dmm_init();
+
+ ret = cmm_ret && dmm_ret;
+
+ if (!ret) {
+ if (cmm_ret)
+ cmm_exit();
+
+ if (dmm_ret)
+ dmm_exit();
+
+ }
+ }
if (ret)
refs++;
@@ -1065,6 +1118,8 @@ static void store_interface_fxns(struct bridge_drv_interface *drv_fxns,
STORE_FXN(fxn_brd_setstate, pfn_brd_set_state);
STORE_FXN(fxn_brd_memcopy, pfn_brd_mem_copy);
STORE_FXN(fxn_brd_memwrite, pfn_brd_mem_write);
+ STORE_FXN(fxn_brd_memmap, pfn_brd_mem_map);
+ STORE_FXN(fxn_brd_memunmap, pfn_brd_mem_un_map);
STORE_FXN(fxn_chnl_create, pfn_chnl_create);
STORE_FXN(fxn_chnl_destroy, pfn_chnl_destroy);
STORE_FXN(fxn_chnl_open, pfn_chnl_open);
diff --git a/drivers/staging/tidspbridge/pmgr/dmm.c b/drivers/staging/tidspbridge/pmgr/dmm.c
new file mode 100644
index 000000000000..8685233d7627
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/dmm.c
@@ -0,0 +1,533 @@
+/*
+ * dmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Manager (DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region
+ *
+ * Notes:
+ * Region: Generic memory entitiy having a start address and a size
+ * Chunk: Reserved region
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/proc.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dmm.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define DMM_ADDR_VIRTUAL(a) \
+ (((struct map_page *)(a) - virtual_mapping_table) * PG_SIZE4K +\
+ dyn_mem_map_beg)
+#define DMM_ADDR_TO_INDEX(a) (((a) - dyn_mem_map_beg) / PG_SIZE4K)
+
+/* DMM Mgr */
+struct dmm_object {
+ /* Dmm Lock is used to serialize access mem manager for
+ * multi-threads. */
+ spinlock_t dmm_lock; /* Lock to access dmm mgr */
+};
+
+/* ----------------------------------- Globals */
+static u32 refs; /* module reference count */
+struct map_page {
+ u32 region_size:15;
+ u32 mapped_size:15;
+ u32 reserved:1;
+ u32 mapped:1;
+};
+
+/* Create the free list */
+static struct map_page *virtual_mapping_table;
+static u32 free_region; /* The index of free region */
+static u32 free_size;
+static u32 dyn_mem_map_beg; /* The Beginning of dynamic memory mapping */
+static u32 table_size; /* The size of virt and phys pages tables */
+
+/* ----------------------------------- Function Prototypes */
+static struct map_page *get_region(u32 addr);
+static struct map_page *get_free_region(u32 len);
+static struct map_page *get_mapped_region(u32 addrs);
+
+/* ======== dmm_create_tables ========
+ * Purpose:
+ * Create table to hold the information of physical address
+ * the buffer pages that is passed by the user, and the table
+ * to hold the information of the virtual memory that is reserved
+ * for DSP.
+ */
+int dmm_create_tables(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ int status = 0;
+
+ status = dmm_delete_tables(dmm_obj);
+ if (!status) {
+ dyn_mem_map_beg = addr;
+ table_size = PG_ALIGN_HIGH(size, PG_SIZE4K) / PG_SIZE4K;
+ /* Create the free list */
+ virtual_mapping_table = __vmalloc(table_size *
+ sizeof(struct map_page), GFP_KERNEL |
+ __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
+ if (virtual_mapping_table == NULL)
+ status = -ENOMEM;
+ else {
+ /* On successful allocation,
+ * all entries are zero ('free') */
+ free_region = 0;
+ free_size = table_size * PG_SIZE4K;
+ virtual_mapping_table[0].region_size = table_size;
+ }
+ }
+
+ if (status)
+ pr_err("%s: failure, status 0x%x\n", __func__, status);
+
+ return status;
+}
+
+/*
+ * ======== dmm_create ========
+ * Purpose:
+ * Create a dynamic memory manager object.
+ */
+int dmm_create(struct dmm_object **dmm_manager,
+ struct dev_object *hdev_obj,
+ const struct dmm_mgrattrs *mgr_attrts)
+{
+ struct dmm_object *dmm_obj = NULL;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dmm_manager != NULL);
+
+ *dmm_manager = NULL;
+ /* create, zero, and tag a cmm mgr object */
+ dmm_obj = kzalloc(sizeof(struct dmm_object), GFP_KERNEL);
+ if (dmm_obj != NULL) {
+ spin_lock_init(&dmm_obj->dmm_lock);
+ *dmm_manager = dmm_obj;
+ } else {
+ status = -ENOMEM;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dmm_destroy ========
+ * Purpose:
+ * Release the communication memory manager resources.
+ */
+int dmm_destroy(struct dmm_object *dmm_mgr)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ if (dmm_mgr) {
+ status = dmm_delete_tables(dmm_obj);
+ if (!status)
+ kfree(dmm_obj);
+ } else
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== dmm_delete_tables ========
+ * Purpose:
+ * Delete DMM Tables.
+ */
+int dmm_delete_tables(struct dmm_object *dmm_mgr)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ /* Delete all DMM tables */
+ if (dmm_mgr)
+ vfree(virtual_mapping_table);
+ else
+ status = -EFAULT;
+ return status;
+}
+
+/*
+ * ======== dmm_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ */
+void dmm_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+}
+
+/*
+ * ======== dmm_get_handle ========
+ * Purpose:
+ * Return the dynamic memory manager object for this device.
+ * This is typically called from the client process.
+ */
+int dmm_get_handle(void *hprocessor, struct dmm_object **dmm_manager)
+{
+ int status = 0;
+ struct dev_object *hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dmm_manager != NULL);
+ if (hprocessor != NULL)
+ status = proc_get_dev_object(hprocessor, &hdev_obj);
+ else
+ hdev_obj = dev_get_first(); /* default */
+
+ if (!status)
+ status = dev_get_dmm_mgr(hdev_obj, dmm_manager);
+
+ return status;
+}
+
+/*
+ * ======== dmm_init ========
+ * Purpose:
+ * Initializes private state of DMM module.
+ */
+bool dmm_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ virtual_mapping_table = NULL;
+ table_size = 0;
+
+ return ret;
+}
+
+/*
+ * ======== dmm_map_memory ========
+ * Purpose:
+ * Add a mapping block to the reserved chunk. DMM assumes that this block
+ * will be mapped in the DSP/IVA's address space. DMM returns an error if a
+ * mapping overlaps another one. This function stores the info that will be
+ * required later while unmapping the block.
+ */
+int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ int status = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+ /* Find the Reserved memory chunk containing the DSP block to
+ * be mapped */
+ chunk = (struct map_page *)get_region(addr);
+ if (chunk != NULL) {
+ /* Mark the region 'mapped', leave the 'reserved' info as-is */
+ chunk->mapped = true;
+ chunk->mapped_size = (size / PG_SIZE4K);
+ } else
+ status = -ENOENT;
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s dmm_mgr %p, addr %x, size %x\n\tstatus %x, "
+ "chunk %p", __func__, dmm_mgr, addr, size, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== dmm_reserve_memory ========
+ * Purpose:
+ * Reserve a chunk of virtually contiguous DSP/IVA address space.
+ */
+int dmm_reserve_memory(struct dmm_object *dmm_mgr, u32 size,
+ u32 *prsv_addr)
+{
+ int status = 0;
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *node;
+ u32 rsv_addr = 0;
+ u32 rsv_size = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+
+ /* Try to get a DSP chunk from the free list */
+ node = get_free_region(size);
+ if (node != NULL) {
+ /* DSP chunk of given size is available. */
+ rsv_addr = DMM_ADDR_VIRTUAL(node);
+ /* Calculate the number entries to use */
+ rsv_size = size / PG_SIZE4K;
+ if (rsv_size < node->region_size) {
+ /* Mark remainder of free region */
+ node[rsv_size].mapped = false;
+ node[rsv_size].reserved = false;
+ node[rsv_size].region_size =
+ node->region_size - rsv_size;
+ node[rsv_size].mapped_size = 0;
+ }
+ /* get_region will return first fit chunk. But we only use what
+ is requested. */
+ node->mapped = false;
+ node->reserved = true;
+ node->region_size = rsv_size;
+ node->mapped_size = 0;
+ /* Return the chunk's starting address */
+ *prsv_addr = rsv_addr;
+ } else
+ /*dSP chunk of given size is not available */
+ status = -ENOMEM;
+
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s dmm_mgr %p, size %x, prsv_addr %p\n\tstatus %x, "
+ "rsv_addr %x, rsv_size %x\n", __func__, dmm_mgr, size,
+ prsv_addr, status, rsv_addr, rsv_size);
+
+ return status;
+}
+
+/*
+ * ======== dmm_un_map_memory ========
+ * Purpose:
+ * Remove the mapped block from the reserved chunk.
+ */
+int dmm_un_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 *psize)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ int status = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+ chunk = get_mapped_region(addr);
+ if (chunk == NULL)
+ status = -ENOENT;
+
+ if (!status) {
+ /* Unmap the region */
+ *psize = chunk->mapped_size * PG_SIZE4K;
+ chunk->mapped = false;
+ chunk->mapped_size = 0;
+ }
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s: dmm_mgr %p, addr %x, psize %p\n\tstatus %x, "
+ "chunk %p\n", __func__, dmm_mgr, addr, psize, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== dmm_un_reserve_memory ========
+ * Purpose:
+ * Free a chunk of reserved DSP/IVA address space.
+ */
+int dmm_un_reserve_memory(struct dmm_object *dmm_mgr, u32 rsv_addr)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ u32 i;
+ int status = 0;
+ u32 chunk_size;
+
+ spin_lock(&dmm_obj->dmm_lock);
+
+ /* Find the chunk containing the reserved address */
+ chunk = get_mapped_region(rsv_addr);
+ if (chunk == NULL)
+ status = -ENOENT;
+
+ if (!status) {
+ /* Free all the mapped pages for this reserved region */
+ i = 0;
+ while (i < chunk->region_size) {
+ if (chunk[i].mapped) {
+ /* Remove mapping from the page tables. */
+ chunk_size = chunk[i].mapped_size;
+ /* Clear the mapping flags */
+ chunk[i].mapped = false;
+ chunk[i].mapped_size = 0;
+ i += chunk_size;
+ } else
+ i++;
+ }
+ /* Clear the flags (mark the region 'free') */
+ chunk->reserved = false;
+ /* NOTE: We do NOT coalesce free regions here.
+ * Free regions are coalesced in get_region(), as it traverses
+ *the whole mapping table
+ */
+ }
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s: dmm_mgr %p, rsv_addr %x\n\tstatus %x chunk %p",
+ __func__, dmm_mgr, rsv_addr, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== get_region ========
+ * Purpose:
+ * Returns a region containing the specified memory region
+ */
+static struct map_page *get_region(u32 addr)
+{
+ struct map_page *curr_region = NULL;
+ u32 i = 0;
+
+ if (virtual_mapping_table != NULL) {
+ /* find page mapped by this address */
+ i = DMM_ADDR_TO_INDEX(addr);
+ if (i < table_size)
+ curr_region = virtual_mapping_table + i;
+ }
+
+ dev_dbg(bridge, "%s: curr_region %p, free_region %d, free_size %d\n",
+ __func__, curr_region, free_region, free_size);
+ return curr_region;
+}
+
+/*
+ * ======== get_free_region ========
+ * Purpose:
+ * Returns the requested free region
+ */
+static struct map_page *get_free_region(u32 len)
+{
+ struct map_page *curr_region = NULL;
+ u32 i = 0;
+ u32 region_size = 0;
+ u32 next_i = 0;
+
+ if (virtual_mapping_table == NULL)
+ return curr_region;
+ if (len > free_size) {
+ /* Find the largest free region
+ * (coalesce during the traversal) */
+ while (i < table_size) {
+ region_size = virtual_mapping_table[i].region_size;
+ next_i = i + region_size;
+ if (virtual_mapping_table[i].reserved == false) {
+ /* Coalesce, if possible */
+ if (next_i < table_size &&
+ virtual_mapping_table[next_i].reserved
+ == false) {
+ virtual_mapping_table[i].region_size +=
+ virtual_mapping_table
+ [next_i].region_size;
+ continue;
+ }
+ region_size *= PG_SIZE4K;
+ if (region_size > free_size) {
+ free_region = i;
+ free_size = region_size;
+ }
+ }
+ i = next_i;
+ }
+ }
+ if (len <= free_size) {
+ curr_region = virtual_mapping_table + free_region;
+ free_region += (len / PG_SIZE4K);
+ free_size -= len;
+ }
+ return curr_region;
+}
+
+/*
+ * ======== get_mapped_region ========
+ * Purpose:
+ * Returns the requestedmapped region
+ */
+static struct map_page *get_mapped_region(u32 addrs)
+{
+ u32 i = 0;
+ struct map_page *curr_region = NULL;
+
+ if (virtual_mapping_table == NULL)
+ return curr_region;
+
+ i = DMM_ADDR_TO_INDEX(addrs);
+ if (i < table_size && (virtual_mapping_table[i].mapped ||
+ virtual_mapping_table[i].reserved))
+ curr_region = virtual_mapping_table + i;
+ return curr_region;
+}
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr)
+{
+ struct map_page *curr_node = NULL;
+ u32 i;
+ u32 freemem = 0;
+ u32 bigsize = 0;
+
+ spin_lock(&dmm_mgr->dmm_lock);
+
+ if (virtual_mapping_table != NULL) {
+ for (i = 0; i < table_size; i +=
+ virtual_mapping_table[i].region_size) {
+ curr_node = virtual_mapping_table + i;
+ if (curr_node->reserved) {
+ /*printk("RESERVED size = 0x%x, "
+ "Map size = 0x%x\n",
+ (curr_node->region_size * PG_SIZE4K),
+ (curr_node->mapped == false) ? 0 :
+ (curr_node->mapped_size * PG_SIZE4K));
+ */
+ } else {
+/* printk("UNRESERVED size = 0x%x\n",
+ (curr_node->region_size * PG_SIZE4K));
+ */
+ freemem += (curr_node->region_size * PG_SIZE4K);
+ if (curr_node->region_size > bigsize)
+ bigsize = curr_node->region_size;
+ }
+ }
+ }
+ spin_unlock(&dmm_mgr->dmm_lock);
+ printk(KERN_INFO "Total DSP VA FREE memory = %d Mbytes\n",
+ freemem / (1024 * 1024));
+ printk(KERN_INFO "Total DSP VA USED memory= %d Mbytes \n",
+ (((table_size * PG_SIZE4K) - freemem)) / (1024 * 1024));
+ printk(KERN_INFO "DSP VA - Biggest FREE block = %d Mbytes \n\n",
+ (bigsize * PG_SIZE4K / (1024 * 1024)));
+
+ return 0;
+}
+#endif
diff --git a/drivers/staging/tidspbridge/pmgr/dspapi.c b/drivers/staging/tidspbridge/pmgr/dspapi.c
index 981551ce4d78..86ca785f1913 100644
--- a/drivers/staging/tidspbridge/pmgr/dspapi.c
+++ b/drivers/staging/tidspbridge/pmgr/dspapi.c
@@ -993,10 +993,27 @@ u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt)
/*
* ======== procwrap_reserve_memory ========
*/
-u32 __deprecated procwrap_reserve_memory(union trapped_args *args,
- void *pr_ctxt)
+u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt)
{
- return 0;
+ int status;
+ void *prsv_addr;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if ((args->args_proc_rsvmem.ul_size <= 0) ||
+ (args->args_proc_rsvmem.ul_size & (PG_SIZE4K - 1)) != 0)
+ return -EINVAL;
+
+ status = proc_reserve_memory(hprocessor,
+ args->args_proc_rsvmem.ul_size, &prsv_addr,
+ pr_ctxt);
+ if (!status) {
+ if (put_user(prsv_addr, args->args_proc_rsvmem.pp_rsv_addr)) {
+ status = -EINVAL;
+ proc_un_reserve_memory(args->args_proc_rsvmem.
+ hprocessor, prsv_addr, pr_ctxt);
+ }
+ }
+ return status;
}
/*
@@ -1025,10 +1042,15 @@ u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt)
/*
* ======== procwrap_un_reserve_memory ========
*/
-u32 __deprecated procwrap_un_reserve_memory(union trapped_args *args,
- void *pr_ctxt)
+u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt)
{
- return 0;
+ int status;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ status = proc_un_reserve_memory(hprocessor,
+ args->args_proc_unrsvmem.prsv_addr,
+ pr_ctxt);
+ return status;
}
/*
diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c
index 91cc168516e5..81b1b9013550 100644
--- a/drivers/staging/tidspbridge/rmgr/drv.c
+++ b/drivers/staging/tidspbridge/rmgr/drv.c
@@ -146,6 +146,7 @@ int drv_remove_all_dmm_res_elements(void *process_ctxt)
struct process_context *ctxt = (struct process_context *)process_ctxt;
int status = 0;
struct dmm_map_object *temp_map, *map_obj;
+ struct dmm_rsv_object *temp_rsv, *rsv_obj;
/* Free DMM mapped memory resources */
list_for_each_entry_safe(map_obj, temp_map, &ctxt->dmm_map_list, link) {
@@ -155,6 +156,16 @@ int drv_remove_all_dmm_res_elements(void *process_ctxt)
pr_err("%s: proc_un_map failed!"
" status = 0x%xn", __func__, status);
}
+
+ /* Free DMM reserved memory resources */
+ list_for_each_entry_safe(rsv_obj, temp_rsv, &ctxt->dmm_rsv_list, link) {
+ status = proc_un_reserve_memory(ctxt->hprocessor, (void *)
+ rsv_obj->dsp_reserved_addr,
+ ctxt);
+ if (status)
+ pr_err("%s: proc_un_reserve_memory failed!"
+ " status = 0x%xn", __func__, status);
+ }
return status;
}
@@ -732,6 +743,7 @@ static int request_bridge_resources(struct cfg_hostres *res)
host_res->dw_sys_ctrl_base = ioremap(OMAP_SYSC_BASE, OMAP_SYSC_SIZE);
dev_dbg(bridge, "dw_mem_base[0] 0x%x\n", host_res->dw_mem_base[0]);
dev_dbg(bridge, "dw_mem_base[3] 0x%x\n", host_res->dw_mem_base[3]);
+ dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
/* for 24xx base port is not mapping the mamory for DSP
* internal memory TODO Do a ioremap here */
@@ -785,6 +797,8 @@ int drv_request_bridge_res_dsp(void **phost_resources)
OMAP_PER_PRM_SIZE);
host_res->dw_core_pm_base = (u32) ioremap(OMAP_CORE_PRM_BASE,
OMAP_CORE_PRM_SIZE);
+ host_res->dw_dmmu_base = ioremap(OMAP_DMMU_BASE,
+ OMAP_DMMU_SIZE);
dev_dbg(bridge, "dw_mem_base[0] 0x%x\n",
host_res->dw_mem_base[0]);
@@ -796,6 +810,7 @@ int drv_request_bridge_res_dsp(void **phost_resources)
host_res->dw_mem_base[3]);
dev_dbg(bridge, "dw_mem_base[4] 0x%x\n",
host_res->dw_mem_base[4]);
+ dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
shm_size = drv_datap->shm_size;
if (shm_size >= 0x10000) {
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c
index 34be43fec044..324fcdffb3b3 100644
--- a/drivers/staging/tidspbridge/rmgr/drv_interface.c
+++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c
@@ -509,6 +509,8 @@ static int bridge_open(struct inode *ip, struct file *filp)
pr_ctxt->res_state = PROC_RES_ALLOCATED;
spin_lock_init(&pr_ctxt->dmm_map_lock);
INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
+ spin_lock_init(&pr_ctxt->dmm_rsv_lock);
+ INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
if (pr_ctxt->node_id) {
diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c
index a6ae007015d0..28354bbf1aeb 100644
--- a/drivers/staging/tidspbridge/rmgr/nldr.c
+++ b/drivers/staging/tidspbridge/rmgr/nldr.c
@@ -943,7 +943,7 @@ static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
/* Determine which phase this section belongs to */
for (pch = sect_name + 1; *pch && *pch != seps; pch++)
- ;;
+ ;
if (*pch) {
pch++; /* Skip over the ':' */
diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c
index a660247f527a..1562f3c1281c 100644
--- a/drivers/staging/tidspbridge/rmgr/node.c
+++ b/drivers/staging/tidspbridge/rmgr/node.c
@@ -56,6 +56,7 @@
/* ----------------------------------- This */
#include <dspbridge/nodepriv.h>
#include <dspbridge/node.h>
+#include <dspbridge/dmm.h>
/* Static/Dynamic Loader includes */
#include <dspbridge/dbll.h>
@@ -316,6 +317,10 @@ int node_allocate(struct proc_object *hprocessor,
u32 mapped_addr = 0;
u32 map_attrs = 0x0;
struct dsp_processorstate proc_state;
+#ifdef DSP_DMM_DEBUG
+ struct dmm_object *dmm_mgr;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+#endif
void *node_res;
@@ -425,12 +430,34 @@ int node_allocate(struct proc_object *hprocessor,
if (status)
goto func_cont;
+ status = proc_reserve_memory(hprocessor,
+ pnode->create_args.asa.task_arg_obj.
+ heap_size + PAGE_SIZE,
+ (void **)&(pnode->create_args.asa.
+ task_arg_obj.udsp_heap_res_addr),
+ pr_ctxt);
+ if (status) {
+ pr_err("%s: Failed to reserve memory for heap: 0x%x\n",
+ __func__, status);
+ goto func_cont;
+ }
+#ifdef DSP_DMM_DEBUG
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = DSP_EHANDLE;
+ goto func_cont;
+ }
+
+ dmm_mem_map_dump(dmm_mgr);
+#endif
+
map_attrs |= DSP_MAPLITTLEENDIAN;
map_attrs |= DSP_MAPELEMSIZE32;
map_attrs |= DSP_MAPVIRTUALADDR;
status = proc_map(hprocessor, (void *)attr_in->pgpp_virt_addr,
pnode->create_args.asa.task_arg_obj.heap_size,
- NULL, (void **)&mapped_addr, map_attrs,
+ (void *)pnode->create_args.asa.task_arg_obj.
+ udsp_heap_res_addr, (void **)&mapped_addr, map_attrs,
pr_ctxt);
if (status)
pr_err("%s: Failed to map memory for Heap: 0x%x\n",
@@ -2484,7 +2511,11 @@ static void delete_node(struct node_object *hnode,
struct stream_chnl stream;
struct node_msgargs node_msg_args;
struct node_taskargs task_arg_obj;
-
+#ifdef DSP_DMM_DEBUG
+ struct dmm_object *dmm_mgr;
+ struct proc_object *p_proc_object =
+ (struct proc_object *)hnode->hprocessor;
+#endif
int status;
if (!hnode)
goto func_end;
@@ -2545,6 +2576,19 @@ static void delete_node(struct node_object *hnode,
status = proc_un_map(hnode->hprocessor, (void *)
task_arg_obj.udsp_heap_addr,
pr_ctxt);
+
+ status = proc_un_reserve_memory(hnode->hprocessor,
+ (void *)
+ task_arg_obj.
+ udsp_heap_res_addr,
+ pr_ctxt);
+#ifdef DSP_DMM_DEBUG
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (dmm_mgr)
+ dmm_mem_map_dump(dmm_mgr);
+ else
+ status = DSP_EHANDLE;
+#endif
}
}
if (node_type != NODE_MESSAGE) {
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
index 7a15a02efedf..b47d7aa747b1 100644
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -39,6 +39,7 @@
#include <dspbridge/cod.h>
#include <dspbridge/dev.h>
#include <dspbridge/procpriv.h>
+#include <dspbridge/dmm.h>
/* ----------------------------------- Resource Manager */
#include <dspbridge/mgr.h>
@@ -51,7 +52,6 @@
#include <dspbridge/msg.h>
#include <dspbridge/dspioctl.h>
#include <dspbridge/drv.h>
-#include <_tiomap.h>
/* ----------------------------------- This */
#include <dspbridge/proc.h>
@@ -151,21 +151,34 @@ static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
return map_obj;
}
+static int match_exact_map_obj(struct dmm_map_object *map_obj,
+ u32 dsp_addr, u32 size)
+{
+ if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
+ pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
+ __func__, dsp_addr, map_obj->size, size);
+
+ return map_obj->dsp_addr == dsp_addr &&
+ map_obj->size == size;
+}
+
static void remove_mapping_information(struct process_context *pr_ctxt,
- u32 dsp_addr)
+ u32 dsp_addr, u32 size)
{
struct dmm_map_object *map_obj;
- pr_debug("%s: looking for virt 0x%x\n", __func__, dsp_addr);
+ pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
+ dsp_addr, size);
spin_lock(&pr_ctxt->dmm_map_lock);
list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
- pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x\n",
+ pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
__func__,
map_obj->mpu_addr,
- map_obj->dsp_addr);
+ map_obj->dsp_addr,
+ map_obj->size);
- if (map_obj->dsp_addr == dsp_addr) {
+ if (match_exact_map_obj(map_obj, dsp_addr, size)) {
pr_debug("%s: match, deleting map info\n", __func__);
list_del(&map_obj->link);
kfree(map_obj->dma_info.sg);
@@ -1077,6 +1090,7 @@ int proc_load(void *hprocessor, const s32 argc_index,
s32 cnew_envp; /* " " in new_envp[] */
s32 nproc_id = 0; /* Anticipate MP version. */
struct dcd_manager *hdcd_handle;
+ struct dmm_object *dmm_mgr;
u32 dw_ext_end;
u32 proc_id;
int brd_state;
@@ -1267,6 +1281,25 @@ int proc_load(void *hprocessor, const s32 argc_index,
if (!status)
status = cod_get_sym_value(cod_mgr, EXTEND,
&dw_ext_end);
+
+ /* Reset DMM structs and add an initial free chunk */
+ if (!status) {
+ status =
+ dev_get_dmm_mgr(p_proc_object->hdev_obj,
+ &dmm_mgr);
+ if (dmm_mgr) {
+ /* Set dw_ext_end to DMM START u8
+ * address */
+ dw_ext_end =
+ (dw_ext_end + 1) * DSPWORDSIZE;
+ /* DMM memory is from EXT_END */
+ status = dmm_create_tables(dmm_mgr,
+ dw_ext_end,
+ DMMPOOLSIZE);
+ } else {
+ status = -EFAULT;
+ }
+ }
}
}
/* Restore the original argv[0] */
@@ -1319,10 +1352,12 @@ int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
{
u32 va_align;
u32 pa_align;
+ struct dmm_object *dmm_mgr;
u32 size_align;
int status = 0;
struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
struct dmm_map_object *map_obj;
+ u32 tmp_addr = 0;
#ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
@@ -1347,30 +1382,33 @@ int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
}
/* Critical section */
mutex_lock(&proc_lock);
+ dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (dmm_mgr)
+ status = dmm_map_memory(dmm_mgr, va_align, size_align);
+ else
+ status = -EFAULT;
/* Add mapping to the page tables. */
if (!status) {
+
+ /* Mapped address = MSB of VA | LSB of PA */
+ tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
/* mapped memory resource tracking */
- map_obj = add_mapping_info(pr_ctxt, pa_align, va_align,
+ map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
size_align);
- if (!map_obj) {
+ if (!map_obj)
status = -ENOMEM;
- } else {
- va_align = user_to_dsp_map(
- p_proc_object->hbridge_context->dsp_mmu,
- pa_align, va_align, size_align,
- map_obj->pages);
- if (IS_ERR_VALUE(va_align))
- status = (int)va_align;
- }
+ else
+ status = (*p_proc_object->intf_fxns->pfn_brd_mem_map)
+ (p_proc_object->hbridge_context, pa_align, va_align,
+ size_align, ul_map_attr, map_obj->pages);
}
if (!status) {
/* Mapped address = MSB of VA | LSB of PA */
- map_obj->dsp_addr = (va_align |
- ((u32)pmpu_addr & (PG_SIZE4K - 1)));
- *pp_map_addr = (void *)map_obj->dsp_addr;
+ *pp_map_addr = (void *) tmp_addr;
} else {
- remove_mapping_information(pr_ctxt, va_align);
+ remove_mapping_information(pr_ctxt, tmp_addr, size_align);
+ dmm_un_map_memory(dmm_mgr, va_align, &size_align);
}
mutex_unlock(&proc_lock);
@@ -1463,6 +1501,55 @@ func_end:
}
/*
+ * ======== proc_reserve_memory ========
+ * Purpose:
+ * Reserve a virtually contiguous region of DSP address space.
+ */
+int proc_reserve_memory(void *hprocessor, u32 ul_size,
+ void **pp_rsv_addr,
+ struct process_context *pr_ctxt)
+{
+ struct dmm_object *dmm_mgr;
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_rsv_object *rsv_obj;
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
+ if (status != 0)
+ goto func_end;
+
+ /*
+ * A successful reserve should be followed by insertion of rsv_obj
+ * into dmm_rsv_list, so that reserved memory resource tracking
+ * remains uptodate
+ */
+ rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
+ if (rsv_obj) {
+ rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
+ spin_lock(&pr_ctxt->dmm_rsv_lock);
+ list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
+ spin_unlock(&pr_ctxt->dmm_rsv_lock);
+ }
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
+ "status 0x%x\n", __func__, hprocessor,
+ ul_size, pp_rsv_addr, status);
+ return status;
+}
+
+/*
* ======== proc_start ========
* Purpose:
* Start a processor running.
@@ -1610,7 +1697,9 @@ int proc_un_map(void *hprocessor, void *map_addr,
{
int status = 0;
struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_object *dmm_mgr;
u32 va_align;
+ u32 size_align;
va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
if (!p_proc_object) {
@@ -1618,11 +1707,24 @@ int proc_un_map(void *hprocessor, void *map_addr,
goto func_end;
}
+ status = dmm_get_handle(hprocessor, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
/* Critical section */
mutex_lock(&proc_lock);
+ /*
+ * Update DMM structures. Get the size to unmap.
+ * This function returns error if the VA is not mapped
+ */
+ status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
/* Remove mapping from the page tables. */
- status = user_to_dsp_unmap(p_proc_object->hbridge_context->dsp_mmu,
- va_align);
+ if (!status) {
+ status = (*p_proc_object->intf_fxns->pfn_brd_mem_un_map)
+ (p_proc_object->hbridge_context, va_align, size_align);
+ }
mutex_unlock(&proc_lock);
if (status)
@@ -1633,7 +1735,7 @@ int proc_un_map(void *hprocessor, void *map_addr,
* from dmm_map_list, so that mapped memory resource tracking
* remains uptodate
*/
- remove_mapping_information(pr_ctxt, (u32) map_addr);
+ remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
func_end:
dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
@@ -1642,6 +1744,55 @@ func_end:
}
/*
+ * ======== proc_un_reserve_memory ========
+ * Purpose:
+ * Frees a previously reserved region of DSP address space.
+ */
+int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
+ struct process_context *pr_ctxt)
+{
+ struct dmm_object *dmm_mgr;
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_rsv_object *rsv_obj;
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
+ if (status != 0)
+ goto func_end;
+
+ /*
+ * A successful unreserve should be followed by removal of rsv_obj
+ * from dmm_rsv_list, so that reserved memory resource tracking
+ * remains uptodate
+ */
+ spin_lock(&pr_ctxt->dmm_rsv_lock);
+ list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
+ if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
+ list_del(&rsv_obj->link);
+ kfree(rsv_obj);
+ break;
+ }
+ }
+ spin_unlock(&pr_ctxt->dmm_rsv_lock);
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
+ __func__, hprocessor, prsv_addr, status);
+ return status;
+}
+
+/*
* ======== = proc_monitor ======== ==
* Purpose:
* Place the Processor in Monitor State. This is an internal
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
index de7ebb99d8f6..114eec8a630a 100644
--- a/drivers/staging/tm6000/Kconfig
+++ b/drivers/staging/tm6000/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_TM6000
tristate "TV Master TM5600/6000/6010 driver"
- depends on VIDEO_DEV && I2C && INPUT && IR_CORE && USB && EXPERIMENTAL
+ depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
select VIDEO_TUNER
select MEDIA_TUNER_XC2028
select MEDIA_TUNER_XC5000
diff --git a/drivers/staging/tm6000/TODO b/drivers/staging/tm6000/TODO
index 34780fc17b16..135d0ea3ad70 100644
--- a/drivers/staging/tm6000/TODO
+++ b/drivers/staging/tm6000/TODO
@@ -1,4 +1,6 @@
There a few things to do before putting this driver in production:
+ - IR NEC with tm5600/6000 TV cards
+ - IR RC5 with tm5600/6000/6010 TV cards
- CodingStyle;
- Fix audio;
- Fix some panic/OOPS conditions.
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 664e6038090d..455038bdfc9f 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -328,6 +328,47 @@ struct usb_device_id tm6000_id_table[] = {
{ },
};
+/* Control power led for show some activity */
+void tm6000_flash_led(struct tm6000_core *dev, u8 state)
+{
+ /* Power LED unconfigured */
+ if (!dev->gpio.power_led)
+ return;
+
+ /* ON Power LED */
+ if (state) {
+ switch (dev->model) {
+ case TM6010_BOARD_HAUPPAUGE_900H:
+ case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+ case TM6010_BOARD_TWINHAN_TU501:
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x00);
+ break;
+ case TM6010_BOARD_BEHOLD_WANDER:
+ case TM6010_BOARD_BEHOLD_VOYAGER:
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x01);
+ break;
+ }
+ }
+ /* OFF Power LED */
+ else {
+ switch (dev->model) {
+ case TM6010_BOARD_HAUPPAUGE_900H:
+ case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+ case TM6010_BOARD_TWINHAN_TU501:
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x01);
+ break;
+ case TM6010_BOARD_BEHOLD_WANDER:
+ case TM6010_BOARD_BEHOLD_VOYAGER:
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x00);
+ break;
+ }
+ }
+}
+
/* Tuner callback to provide the proper gpio changes needed for xc5000 */
int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
{
@@ -521,13 +562,6 @@ int tm6000_cards_setup(struct tm6000_core *dev)
printk(KERN_ERR "Error %i doing tuner reset\n", rc);
return rc;
}
- msleep(10);
-
- if (!i) {
- rc = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
- if (rc >= 0)
- printk(KERN_DEBUG "board=0x%08x\n", rc);
- }
}
} else {
printk(KERN_ERR "Tuner reset is not configured\n");
@@ -545,7 +579,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
/* Load tuner module */
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
memset(&tun_setup, 0, sizeof(tun_setup));
tun_setup.type = dev->tuner_type;
@@ -683,7 +717,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
if (dev->caps.has_tda9874)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- NULL, "tvaudio", I2C_ADDR_TDA9874, NULL);
+ "tvaudio", I2C_ADDR_TDA9874, NULL);
/* register and initialize V4L2 */
rc = tm6000_v4l2_register(dev);
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index 40a0206e2432..96aed4ace467 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -542,6 +542,26 @@ int tm6000_init(struct tm6000_core *dev)
int board, rc = 0, i, size;
struct reg_init *tab;
+ /* Check board revision */
+ board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+ if (board >= 0) {
+ switch (board & 0xff) {
+ case 0xf3:
+ printk(KERN_INFO "Found tm6000\n");
+ if (dev->dev_type != TM6000)
+ dev->dev_type = TM6000;
+ break;
+ case 0xf4:
+ printk(KERN_INFO "Found tm6010\n");
+ if (dev->dev_type != TM6010)
+ dev->dev_type = TM6010;
+ break;
+ default:
+ printk(KERN_INFO "Unknown board version = 0x%08x\n", board);
+ }
+ } else
+ printk(KERN_ERR "Error %i while retrieving board version\n", board);
+
if (dev->dev_type == TM6010) {
tab = tm6010_init_tab;
size = ARRAY_SIZE(tm6010_init_tab);
@@ -563,13 +583,6 @@ int tm6000_init(struct tm6000_core *dev)
msleep(5); /* Just to be conservative */
- /* Check board version - maybe 10Moons specific */
- board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
- if (board >= 0)
- printk(KERN_INFO "Board version = 0x%08x\n", board);
- else
- printk(KERN_ERR "Error %i while retrieving board version\n", board);
-
rc = tm6000_cards_setup(dev);
return rc;
@@ -709,5 +722,5 @@ void tm6000_close_extension(struct tm6000_core *dev)
ops->fini(dev);
}
}
- mutex_lock(&tm6000_devlist_mutex);
+ mutex_unlock(&tm6000_devlist_mutex);
}
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
index 3e46866dd279..18de4748f27e 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -301,34 +301,11 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-#define mass_write(addr, reg, data...) \
- { static const u8 _val[] = data; \
- rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, \
- REQ_16_SET_GET_I2C_WR1_RDN, (reg<<8)+addr, 0x00, (u8 *) _val, \
- ARRAY_SIZE(_val)); \
- if (rc < 0) { \
- printk(KERN_ERR "Error on line %d: %d\n", __LINE__, rc); \
- return rc; \
- } \
- msleep(10); \
- }
-
-static struct i2c_algorithm tm6000_algo = {
+static const struct i2c_algorithm tm6000_algo = {
.master_xfer = tm6000_i2c_xfer,
.functionality = functionality,
};
-static struct i2c_adapter tm6000_adap_template = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
- .name = "tm6000",
- .algo = &tm6000_algo,
-};
-
-static struct i2c_client tm6000_client_template = {
- .name = "tm6000 internal",
-};
-
/* ----------------------------------------------------------- */
/*
@@ -338,17 +315,20 @@ static struct i2c_client tm6000_client_template = {
int tm6000_i2c_register(struct tm6000_core *dev)
{
unsigned char eedata[256];
+ int rc;
- dev->i2c_adap = tm6000_adap_template;
+ dev->i2c_adap.owner = THIS_MODULE;
+ dev->i2c_adap.algo = &tm6000_algo;
dev->i2c_adap.dev.parent = &dev->udev->dev;
- strcpy(dev->i2c_adap.name, dev->name);
+ strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
dev->i2c_adap.algo_data = dev;
- i2c_add_adapter(&dev->i2c_adap);
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ rc = i2c_add_adapter(&dev->i2c_adap);
+ if (rc)
+ return rc;
- dev->i2c_client = tm6000_client_template;
dev->i2c_client.adapter = &dev->i2c_adap;
-
- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
index 6022caaa739b..21e7da40f049 100644
--- a/drivers/staging/tm6000/tm6000-input.c
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -24,8 +24,7 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include <media/ir-core.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include "tm6000.h"
#include "tm6000-regs.h"
@@ -38,6 +37,10 @@ static unsigned int enable_ir = 1;
module_param(enable_ir, int, 0644);
MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
+/* number of 50ms for ON-OFF-ON power led */
+/* show IR activity */
+#define PWLED_OFF 2
+
#undef dprintk
#define dprintk(fmt, arg...) \
@@ -51,8 +54,7 @@ struct tm6000_ir_poll_result {
struct tm6000_IR {
struct tm6000_core *dev;
- struct ir_input_dev *input;
- struct ir_input_state ir;
+ struct rc_dev *rc;
char name[32];
char phys[32];
@@ -61,13 +63,16 @@ struct tm6000_IR {
struct delayed_work work;
u8 wait:1;
u8 key:1;
+ u8 pwled:1;
+ u8 pwledcnt;
+ u16 key_addr;
struct urb *int_urb;
u8 *urb_data;
int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
/* IR device properties */
- struct ir_dev_props props;
+ u64 rc_type;
};
@@ -91,26 +96,49 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
u8 buf[10];
int rc;
- /* hack */
- buf[0] = 0xff;
- buf[1] = 0xff;
- buf[2] = 0xf2;
- buf[3] = 0x2b;
- buf[4] = 0x20;
- buf[5] = 0x35;
- buf[6] = 0x60;
- buf[7] = 0x04;
- buf[8] = 0xc0;
- buf[9] = 0x08;
-
- rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
- msleep(100);
-
- if (rc < 0) {
- printk(KERN_INFO "IR configuration failed");
- return rc;
+ switch (ir->rc_type) {
+ case RC_TYPE_NEC:
+ /* Setup IR decoder for NEC standard 12MHz system clock */
+ /* IR_LEADER_CNT = 0.9ms */
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
+ /* IR_PULSE_CNT = 0.7ms */
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
+ /* Remote WAKEUP = enable */
+ tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+ /* IR_WKUP_SEL = Low byte in decoded IR data */
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
+ /* IR_WKU_ADD code */
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
+ tm6000_flash_led(dev, 0);
+ msleep(100);
+ tm6000_flash_led(dev, 1);
+ break;
+ default:
+ /* hack */
+ buf[0] = 0xff;
+ buf[1] = 0xff;
+ buf[2] = 0xf2;
+ buf[3] = 0x2b;
+ buf[4] = 0x20;
+ buf[5] = 0x35;
+ buf[6] = 0x60;
+ buf[7] = 0x04;
+ buf[8] = 0xc0;
+ buf[9] = 0x08;
+
+ rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+ msleep(100);
+
+ if (rc < 0) {
+ printk(KERN_INFO "IR configuration failed");
+ return rc;
+ }
+ break;
}
+
return 0;
}
@@ -145,17 +173,28 @@ static int default_polling_getkey(struct tm6000_IR *ir,
return 0;
if (&dev->int_in) {
- if (ir->ir.ir_type == IR_TYPE_RC5)
+ switch (ir->rc_type) {
+ case RC_TYPE_RC5:
poll_result->rc_data = ir->urb_data[0];
- else
- poll_result->rc_data = ir->urb_data[0] | ir->urb_data[1] << 8;
+ break;
+ case RC_TYPE_NEC:
+ if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
+ poll_result->rc_data = ir->urb_data[0]
+ | ir->urb_data[1] << 8;
+ }
+ break;
+ default:
+ poll_result->rc_data = ir->urb_data[0]
+ | ir->urb_data[1] << 8;
+ break;
+ }
} else {
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
msleep(10);
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
msleep(10);
- if (ir->ir.ir_type == IR_TYPE_RC5) {
+ if (ir->rc_type == RC_TYPE_RC5) {
rc = tm6000_read_write_usb(dev, USB_DIR_IN |
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
REQ_02_GET_IR_CODE, 0, 0, buf, 1);
@@ -188,6 +227,7 @@ static int default_polling_getkey(struct tm6000_IR *ir,
static void tm6000_ir_handle_key(struct tm6000_IR *ir)
{
+ struct tm6000_core *dev = ir->dev;
int result;
struct tm6000_ir_poll_result poll_result;
@@ -200,12 +240,21 @@ static void tm6000_ir_handle_key(struct tm6000_IR *ir)
dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
- if (ir->key) {
- ir_input_keydown(ir->input->input_dev, &ir->ir,
- (u32)poll_result.rc_data);
+ if (ir->pwled) {
+ if (ir->pwledcnt >= PWLED_OFF) {
+ ir->pwled = 0;
+ ir->pwledcnt = 0;
+ tm6000_flash_led(dev, 1);
+ } else
+ ir->pwledcnt += 1;
+ }
- ir_input_nokey(ir->input->input_dev, &ir->ir);
+ if (ir->key) {
+ rc_keydown(ir->rc, poll_result.rc_data, 0);
ir->key = 0;
+ ir->pwled = 1;
+ ir->pwledcnt = 0;
+ tm6000_flash_led(dev, 0);
}
return;
}
@@ -218,9 +267,9 @@ static void tm6000_ir_work(struct work_struct *work)
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
-static int tm6000_ir_start(void *priv)
+static int tm6000_ir_start(struct rc_dev *rc)
{
- struct tm6000_IR *ir = priv;
+ struct tm6000_IR *ir = rc->priv;
INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
schedule_delayed_work(&ir->work, 0);
@@ -228,30 +277,91 @@ static int tm6000_ir_start(void *priv)
return 0;
}
-static void tm6000_ir_stop(void *priv)
+static void tm6000_ir_stop(struct rc_dev *rc)
{
- struct tm6000_IR *ir = priv;
+ struct tm6000_IR *ir = rc->priv;
cancel_delayed_work_sync(&ir->work);
}
-int tm6000_ir_change_protocol(void *priv, u64 ir_type)
+int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
{
- struct tm6000_IR *ir = priv;
+ struct tm6000_IR *ir = rc->priv;
+
+ if (!ir)
+ return 0;
+
+ if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
+ ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
ir->get_key = default_polling_getkey;
+ ir->rc_type = rc_type;
tm6000_ir_config(ir);
/* TODO */
return 0;
}
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+ int pipe, size;
+ int err = -ENOMEM;
+
+
+ if (!ir)
+ return -ENODEV;
+
+ ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ pipe = usb_rcvintpipe(dev->udev,
+ dev->int_in.endp->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+
+ size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+ dprintk("IR max size: %d\n", size);
+
+ ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+ if (ir->int_urb->transfer_buffer == NULL) {
+ usb_free_urb(ir->int_urb);
+ return err;
+ }
+ dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+ usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+ ir->int_urb->transfer_buffer, size,
+ tm6000_ir_urb_received, dev,
+ dev->int_in.endp->desc.bInterval);
+ err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+ if (err) {
+ kfree(ir->int_urb->transfer_buffer);
+ usb_free_urb(ir->int_urb);
+ return err;
+ }
+ ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+ return 0;
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ if (!ir)
+ return;
+
+ usb_kill_urb(ir->int_urb);
+ kfree(ir->int_urb->transfer_buffer);
+ usb_free_urb(ir->int_urb);
+ ir->int_urb = NULL;
+ kfree(ir->urb_data);
+ ir->urb_data = NULL;
+}
+
int tm6000_ir_init(struct tm6000_core *dev)
{
struct tm6000_IR *ir;
- struct ir_input_dev *ir_input_dev;
+ struct rc_dev *rc;
int err = -ENOMEM;
- int pipe, size, rc;
if (!enable_ir)
return -ENODEV;
@@ -263,26 +373,27 @@ int tm6000_ir_init(struct tm6000_core *dev)
return 0;
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL);
- ir_input_dev->input_dev = input_allocate_device();
- if (!ir || !ir_input_dev || !ir_input_dev->input_dev)
- goto err_out_free;
+ rc = rc_allocate_device();
+ if (!ir | !rc)
+ goto out;
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;
-
- ir->input = ir_input_dev;
+ ir->rc = rc;
/* input einrichten */
- ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
- ir->props.priv = ir;
- ir->props.change_protocol = tm6000_ir_change_protocol;
- ir->props.open = tm6000_ir_start;
- ir->props.close = tm6000_ir_stop;
- ir->props.driver_type = RC_DRIVER_SCANCODE;
+ rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ rc->priv = ir;
+ rc->change_protocol = tm6000_ir_change_protocol;
+ rc->open = tm6000_ir_start;
+ rc->close = tm6000_ir_stop;
+ rc->driver_type = RC_DRIVER_SCANCODE;
ir->polling = 50;
+ ir->pwled = 0;
+ ir->pwledcnt = 0;
+
snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
dev->name);
@@ -290,64 +401,37 @@ int tm6000_ir_init(struct tm6000_core *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
- err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER);
- if (err < 0)
- goto err_out_free;
-
- ir_input_dev->input_dev->name = ir->name;
- ir_input_dev->input_dev->phys = ir->phys;
- ir_input_dev->input_dev->id.bustype = BUS_USB;
- ir_input_dev->input_dev->id.version = 1;
- ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
- ir_input_dev->input_dev->dev.parent = &dev->udev->dev;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_USB;
+ rc->input_id.version = 1;
+ rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ rc->map_name = dev->ir_codes;
+ rc->driver_name = "tm6000";
+ rc->dev.parent = &dev->udev->dev;
if (&dev->int_in) {
dprintk("IR over int\n");
- ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+ err = tm6000_ir_int_start(dev);
- pipe = usb_rcvintpipe(dev->udev,
- dev->int_in.endp->desc.bEndpointAddress
- & USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
- dprintk("IR max size: %d\n", size);
-
- ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
- if (ir->int_urb->transfer_buffer == NULL) {
- usb_free_urb(ir->int_urb);
- goto err_out_stop;
- }
- dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
- usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
- ir->int_urb->transfer_buffer, size,
- tm6000_ir_urb_received, dev,
- dev->int_in.endp->desc.bInterval);
- rc = usb_submit_urb(ir->int_urb, GFP_KERNEL);
- if (rc) {
- kfree(ir->int_urb->transfer_buffer);
- usb_free_urb(ir->int_urb);
- err = rc;
- goto err_out_stop;
- }
- ir->urb_data = kzalloc(size, GFP_KERNEL);
+ if (err)
+ goto out;
}
/* ir register */
- err = ir_input_register(ir->input->input_dev, dev->ir_codes,
- &ir->props, "tm6000");
+ err = rc_register_device(rc);
if (err)
- goto err_out_stop;
+ goto out;
return 0;
-err_out_stop:
+out:
dev->ir = NULL;
-err_out_free:
- kfree(ir_input_dev);
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -361,19 +445,12 @@ int tm6000_ir_fini(struct tm6000_core *dev)
if (!ir)
return 0;
- ir_input_unregister(ir->input->input_dev);
+ rc_unregister_device(ir->rc);
if (ir->int_urb) {
- usb_kill_urb(ir->int_urb);
- kfree(ir->int_urb->transfer_buffer);
- usb_free_urb(ir->int_urb);
- ir->int_urb = NULL;
- kfree(ir->urb_data);
- ir->urb_data = NULL;
+ tm6000_ir_int_stop(dev);
}
- kfree(ir->input);
- ir->input = NULL;
kfree(ir);
dev->ir = NULL;
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index 9ec82796634e..8fe017c3721f 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -545,11 +545,16 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
/* De-allocates all pending stuff */
tm6000_uninit_isoc(dev);
+ /* Stop interrupt USB pipe */
+ tm6000_ir_int_stop(dev);
usb_set_interface(dev->udev,
dev->isoc_in.bInterfaceNumber,
dev->isoc_in.bAlternateSetting);
+ /* Start interrupt USB pipe */
+ tm6000_ir_int_start(dev);
+
pipe = usb_rcvisocpipe(dev->udev,
dev->isoc_in.endp->desc.bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK);
@@ -986,15 +991,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct tm6000_fh *fh = priv;
@@ -1032,6 +1028,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
struct tm6000_fh *fh=priv;
struct tm6000_core *dev = fh->dev;
+ dev->norm = *norm;
rc = tm6000_init_analog_mode(dev);
fh->width = dev->width;
@@ -1437,9 +1434,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device tm6000_template = {
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 46017b603190..bf11eeec92c7 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -266,6 +266,7 @@ struct tm6000_fh {
int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
int tm6000_cards_setup(struct tm6000_core *dev);
+void tm6000_flash_led(struct tm6000_core *dev, u8 state);
/* In tm6000-core.c */
@@ -332,6 +333,8 @@ int tm6000_queue_init(struct tm6000_core *dev);
int tm6000_ir_init(struct tm6000_core *dev);
int tm6000_ir_fini(struct tm6000_core *dev);
void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
+int tm6000_ir_int_start(struct tm6000_core *dev);
+void tm6000_ir_int_stop(struct tm6000_core *dev);
/* Debug stuff */
diff --git a/drivers/staging/udlfb/Kconfig b/drivers/staging/udlfb/Kconfig
deleted file mode 100644
index 65bd5db4ca56..000000000000
--- a/drivers/staging/udlfb/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-config FB_UDL
- tristate "Displaylink USB Framebuffer support"
- depends on FB && USB
- select FB_MODE_HELPERS
- select FB_SYS_FILLRECT
- select FB_SYS_COPYAREA
- select FB_SYS_IMAGEBLIT
- select FB_SYS_FOPS
- select FB_DEFERRED_IO
- ---help---
- This is a kernel framebuffer driver for DisplayLink USB devices.
- Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
- mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
- To compile as a module, choose M here: the module name is udlfb.
diff --git a/drivers/staging/udlfb/Makefile b/drivers/staging/udlfb/Makefile
deleted file mode 100644
index 30d9e675b10f..000000000000
--- a/drivers/staging/udlfb/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_FB_UDL) += udlfb.o
diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
deleted file mode 100644
index 6f9785e9d62e..000000000000
--- a/drivers/staging/udlfb/udlfb.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef UDLFB_H
-#define UDLFB_H
-
-/*
- * TODO: Propose standard fb.h ioctl for reporting damage,
- * using _IOWR() and one of the existing area structs from fb.h
- * Consider these ioctls deprecated, but they're still used by the
- * DisplayLink X server as yet - need both to be modified in tandem
- * when new ioctl(s) are ready.
- */
-#define DLFB_IOCTL_RETURN_EDID 0xAD
-#define DLFB_IOCTL_REPORT_DAMAGE 0xAA
-struct dloarea {
- int x, y;
- int w, h;
- int x2, y2;
-};
-
-struct urb_node {
- struct list_head entry;
- struct dlfb_data *dev;
- struct delayed_work release_urb_work;
- struct urb *urb;
-};
-
-struct urb_list {
- struct list_head list;
- spinlock_t lock;
- struct semaphore limit_sem;
- int available;
- int count;
- size_t size;
-};
-
-struct dlfb_data {
- struct usb_device *udev;
- struct device *gdev; /* &udev->dev */
- struct fb_info *info;
- struct urb_list urbs;
- struct kref kref;
- char *backing_buffer;
- int fb_count;
- bool virtualized; /* true when physical usb device not present */
- struct delayed_work free_framebuffer_work;
- atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
- atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
- char *edid; /* null until we read edid from hw or get from sysfs */
- size_t edid_size;
- int sku_pixel_limit;
- int base16;
- int base8;
- u32 pseudo_palette[256];
- /* blit-only rendering path metrics, exposed through sysfs */
- atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
- atomic_t bytes_identical; /* saved effort with backbuffer comparison */
- atomic_t bytes_sent; /* to usb, after compression including overhead */
- atomic_t cpu_kcycles_used; /* transpired during pixel processing */
-};
-
-#define NR_USB_REQUEST_I2C_SUB_IO 0x02
-#define NR_USB_REQUEST_CHANNEL 0x12
-
-/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
-#define BULK_SIZE 512
-#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
-#define WRITES_IN_FLIGHT (4)
-
-#define MIN_EDID_SIZE 128
-#define MAX_EDID_SIZE 128
-
-#define MAX_VENDOR_DESCRIPTOR_SIZE 256
-
-#define GET_URB_TIMEOUT HZ
-#define FREE_URB_TIMEOUT (HZ*2)
-
-#define BPP 2
-#define MAX_CMD_PIXELS 255
-
-#define RLX_HEADER_BYTES 7
-#define MIN_RLX_PIX_BYTES 4
-#define MIN_RLX_CMD_BYTES (RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
-
-#define RLE_HEADER_BYTES 6
-#define MIN_RLE_PIX_BYTES 3
-#define MIN_RLE_CMD_BYTES (RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
-
-#define RAW_HEADER_BYTES 6
-#define MIN_RAW_PIX_BYTES 2
-#define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
-
-#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */
-#define DL_DEFIO_WRITE_DISABLE (HZ*60) /* "disable" with long delay */
-
-/* remove these once align.h patch is taken into kernel */
-#define DL_ALIGN_UP(x, a) ALIGN(x, a)
-#define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a)
-
-/* remove once this gets added to sysfs.h */
-#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
-
-/*
- * udlfb is both a usb device, and a framebuffer device.
- * They may exist at the same time, but during various stages
- * inactivity, teardown, or "virtual" operation, only one or the
- * other will exist (one will outlive the other). So we can't
- * call the dev_*() macros, because we don't have a stable dev object.
- */
-#define dl_err(format, arg...) \
- pr_err("udlfb: " format, ## arg)
-#define dl_warn(format, arg...) \
- pr_warning("udlfb: " format, ## arg)
-#define dl_notice(format, arg...) \
- pr_notice("udlfb: " format, ## arg)
-#define dl_info(format, arg...) \
- pr_info("udlfb: " format, ## arg)
-
-#endif
diff --git a/drivers/staging/udlfb/udlfb.txt b/drivers/staging/udlfb/udlfb.txt
deleted file mode 100644
index 7fdde2a02a27..000000000000
--- a/drivers/staging/udlfb/udlfb.txt
+++ /dev/null
@@ -1,144 +0,0 @@
-
-What is udlfb?
-===============
-
-This is a driver for DisplayLink USB 2.0 era graphics chips.
-
-DisplayLink chips provide simple hline/blit operations with some compression,
-pairing that with a hardware framebuffer (16MB) on the other end of the
-USB wire. That hardware framebuffer is able to drive the VGA, DVI, or HDMI
-monitor with no CPU involvement until a pixel has to change.
-
-The CPU or other local resource does all the rendering; optinally compares the
-result with a local shadow of the remote hardware framebuffer to identify
-the minimal set of pixels that have changed; and compresses and sends those
-pixels line-by-line via USB bulk transfers.
-
-Because of the efficiency of bulk transfers and a protocol on top that
-does not require any acks - the effect is very low latency that
-can support surprisingly high resolutions with good performance for
-non-gaming and non-video applications.
-
-Mode setting, EDID read, etc are other bulk or control transfers. Mode
-setting is very flexible - able to set nearly arbitrary modes from any timing.
-
-Advantages of USB graphics in general:
-
- * Ability to add a nearly arbitrary number of displays to any USB 2.0
- capable system. On Linux, number of displays is limited by fbdev interface
- (FB_MAX is currently 32). Of course, all USB devices on the same
- host controller share the same 480Mbs USB 2.0 interface.
-
-Advantages of supporting DisplayLink chips with kernel framebuffer interface:
-
- * The actual hardware functionality of DisplayLink chips matches nearly
- one-to-one with the fbdev interface, making the driver quite small and
- tight relative to the functionality it provides.
- * X servers and other applications can use the standard fbdev interface
- from user mode to talk to the device, without needing to know anything
- about USB or DisplayLink's protocol at all. A "displaylink" X driver
- and a slightly modified "fbdev" X driver are among those that already do.
-
-Disadvantages:
-
- * Fbdev's mmap interface assumes a real hardware framebuffer is mapped.
- In the case of USB graphics, it is just an allocated (virtual) buffer.
- Writes need to be detected and encoded into USB bulk transfers by the CPU.
- Accurate damage/changed area notifications work around this problem.
- In the future, hopefully fbdev will be enhanced with an small standard
- interface to allow mmap clients to report damage, for the benefit
- of virtual or remote framebuffers.
- * Fbdev does not arbitrate client ownership of the framebuffer well.
- * Fbcon assumes the first framebuffer it finds should be consumed for console.
- * It's not clear what the future of fbdev is, given the rise of KMS/DRM.
-
-How to use it?
-==============
-
-Udlfb, when loaded as a module, will match against all USB 2.0 generation
-DisplayLink chips (Alex and Ollie family). It will then attempt to read the EDID
-of the monitor, and set the best common mode between the DisplayLink device
-and the monitor's capabilities.
-
-If the DisplayLink device is successful, it will paint a "green screen" which
-means that from a hardware and fbdev software perspective, everything is good.
-
-At that point, a /dev/fb? interface will be present for user-mode applications
-to open and begin writing to the framebuffer of the DisplayLink device using
-standard fbdev calls. Note that if mmap() is used, by default the user mode
-application must send down damage notifcations to trigger repaints of the
-changed regions. Alternatively, udlfb can be recompiled with experimental
-defio support enabled, to support a page-fault based detection mechanism
-that can work without explicit notifcation.
-
-The most common client of udlfb is xf86-video-displaylink or a modified
-xf86-video-fbdev X server. These servers have no real DisplayLink specific
-code. They write to the standard framebuffer interface and rely on udlfb
-to do its thing. The one extra feature they have is the ability to report
-rectangles from the X DAMAGE protocol extension down to udlfb via udlfb's
-damage interface (which will hopefully be standardized for all virtual
-framebuffers that need damage info). These damage notifications allow
-udlfb to efficiently process the changed pixels.
-
-Module Options
-==============
-
-Special configuration for udlfb is usually unnecessary. There are a few
-options, however.
-
-From the command line, pass options to modprobe
-modprobe udlfb defio=1 console=1
-
-Or for permanent option, create file like /etc/modprobe.d/options with text
-options udlfb defio=1 console=1
-
-Accepted options:
-
-fb_defio Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel
- module to track changed areas of the framebuffer by page faults.
- Standard fbdev applications that use mmap but that do not
- report damage, may be able to work with this enabled.
- Disabled by default because of overhead and other issues.
-
-console Allow fbcon to attach to udlfb provided framebuffers. This
- is disabled by default because fbcon will aggressively consume
- the first framebuffer it finds, which isn't usually what the
- user wants in the case of USB displays.
-
-Sysfs Attributes
-================
-
-Udlfb creates several files in /sys/class/graphics/fb?
-Where ? is the sequential framebuffer id of the particular DisplayLink device
-
-edid If a valid EDID blob is written to this file (typically
- by a udev rule), then udlfb will use this EDID as a
- backup in case reading the actual EDID of the monitor
- attached to the DisplayLink device fails. This is
- especially useful for fixed panels, etc. that cannot
- communicate their capabilities via EDID. Reading
- this file returns the current EDID of the attached
- monitor (or last backup value written). This is
- useful to get the EDID of the attached monitor,
- which can be passed to utilities like parse-edid.
-
-metrics_bytes_rendered 32-bit count of pixel bytes rendered
-
-metrics_bytes_identical 32-bit count of how many of those bytes were found to be
- unchanged, based on a shadow framebuffer check
-
-metrics_bytes_sent 32-bit count of how many bytes were transferred over
- USB to communicate the resulting changed pixels to the
- hardware. Includes compression and protocol overhead
-
-metrics_cpu_kcycles_used 32-bit count of CPU cycles used in processing the
- above pixels (in thousands of cycles).
-
-metrics_reset Write-only. Any write to this file resets all metrics
- above to zero. Note that the 32-bit counters above
- roll over very quickly. To get reliable results, design
- performance tests to start and finish in a very short
- period of time (one minute or less is safe).
-
---
-Bernie Thompson <bernie@plugable.com>
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 832608d3e579..08bd26a245d5 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -799,20 +799,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
spin_unlock_irqrestore(&vdev->priv_lock, flags2);
}
-
- if (!vdev->ud.tcp_socket) {
- /* tcp connection is closed */
- usbip_uinfo("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n",
- urb);
-
- usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- spin_unlock_irqrestore(&the_controller->lock, flags);
- usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
- urb->status);
- spin_lock_irqsave(&the_controller->lock, flags);
- }
-
spin_unlock_irqrestore(&the_controller->lock, flags);
usbip_dbg_vhci_hc("leave\n");
diff --git a/drivers/staging/usbvideo/Kconfig b/drivers/staging/usbvideo/Kconfig
new file mode 100644
index 000000000000..566d659e6ff3
--- /dev/null
+++ b/drivers/staging/usbvideo/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_USBVIDEO
+ tristate
+
+config USB_VICAM
+ tristate "USB 3com HomeConnect (aka vicam) support (DEPRECATED)"
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB
+ select VIDEO_USBVIDEO
+ ---help---
+ Say Y here if you have 3com homeconnect camera (vicam).
+
+ This driver uses the deprecated V4L1 API and will be removed in
+ 2.6.39, unless someone converts it to the V4L2 API.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vicam.
diff --git a/drivers/staging/usbvideo/Makefile b/drivers/staging/usbvideo/Makefile
new file mode 100644
index 000000000000..3c99a9a2d8d3
--- /dev/null
+++ b/drivers/staging/usbvideo/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
+obj-$(CONFIG_USB_VICAM) += vicam.o
diff --git a/drivers/staging/usbvideo/TODO b/drivers/staging/usbvideo/TODO
new file mode 100644
index 000000000000..3b2c03836286
--- /dev/null
+++ b/drivers/staging/usbvideo/TODO
@@ -0,0 +1,5 @@
+This is an obsolete driver for some old webcams that still use V4L1 API.
+As V4L1 support is being removed from kernel, if nobody take care on it,
+the driver will be removed for 2.6.39.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/staging/usbvideo/usbvideo.c
index f1fcf9744961..f1fcf9744961 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/staging/usbvideo/usbvideo.c
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/staging/usbvideo/usbvideo.h
index c66985beb8c9..95638a072b19 100644
--- a/drivers/media/video/usbvideo/usbvideo.h
+++ b/drivers/staging/usbvideo/usbvideo.h
@@ -16,7 +16,7 @@
#ifndef usbvideo_h
#define usbvideo_h
-#include <linux/videodev.h>
+#include "videodev.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <linux/usb.h>
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/staging/usbvideo/vicam.c
index 5d6fd01f918a..ecdb121297c9 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/staging/usbvideo/vicam.c
@@ -38,12 +38,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/videodev.h>
+#include "videodev.h"
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
#include <linux/ihex.h>
@@ -483,29 +482,28 @@ vicam_open(struct file *file)
return -EINVAL;
}
- /* the videodev_lock held above us protects us from
- * simultaneous opens...for now. we probably shouldn't
- * rely on this fact forever.
+ /* cam_lock/open_count protects us from simultaneous opens
+ * ... for now. we probably shouldn't rely on this fact forever.
*/
- lock_kernel();
+ mutex_lock(&cam->cam_lock);
if (cam->open_count > 0) {
printk(KERN_INFO
"vicam_open called on already opened camera");
- unlock_kernel();
+ mutex_unlock(&cam->cam_lock);
return -EBUSY;
}
cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
if (!cam->raw_image) {
- unlock_kernel();
+ mutex_unlock(&cam->cam_lock);
return -ENOMEM;
}
cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
if (!cam->framebuf) {
kfree(cam->raw_image);
- unlock_kernel();
+ mutex_unlock(&cam->cam_lock);
return -ENOMEM;
}
@@ -513,10 +511,17 @@ vicam_open(struct file *file)
if (!cam->cntrlbuf) {
kfree(cam->raw_image);
rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
- unlock_kernel();
+ mutex_unlock(&cam->cam_lock);
return -ENOMEM;
}
+ cam->needsDummyRead = 1;
+ cam->open_count++;
+
+ file->private_data = cam;
+ mutex_unlock(&cam->cam_lock);
+
+
// First upload firmware, then turn the camera on
if (!cam->is_initialized) {
@@ -527,12 +532,6 @@ vicam_open(struct file *file)
set_camera_power(cam, 1);
- cam->needsDummyRead = 1;
- cam->open_count++;
-
- file->private_data = cam;
- unlock_kernel();
-
return 0;
}
diff --git a/drivers/staging/usbvideo/videodev.h b/drivers/staging/usbvideo/videodev.h
new file mode 100644
index 000000000000..f11efbef1c05
--- /dev/null
+++ b/drivers/staging/usbvideo/videodev.h
@@ -0,0 +1,318 @@
+/*
+ * Video for Linux version 1 - OBSOLETE
+ *
+ * Header file for v4l1 drivers and applications, for
+ * Linux kernels 2.2.x or 2.4.x.
+ *
+ * Provides header for legacy drivers and applications
+ *
+ * See http://linuxtv.org for more info
+ *
+ */
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/videodev2.h>
+
+#define VID_TYPE_CAPTURE 1 /* Can capture */
+#define VID_TYPE_TUNER 2 /* Can tune */
+#define VID_TYPE_TELETEXT 4 /* Does teletext */
+#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING 32 /* Can clip */
+#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES 128 /* Scalable */
+#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ __u32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ __u16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+ __u16 norm; /* Norm set by channel */
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ unsigned long rangelow, rangehigh; /* Tuner range */
+ __u32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */
+ __u16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ __u16 brightness;
+ __u16 hue;
+ __u16 colour;
+ __u16 contrast;
+ __u16 whiteness; /* Black and white only */
+ __u16 depth; /* Capture depth */
+ __u16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ __u16 volume; /* If settable */
+ __u16 bass, treble;
+ __u32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+#define VIDEO_AUDIO_BALANCE 32
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 4
+#define VIDEO_SOUND_LANG2 8
+ __u16 mode;
+ __u16 balance; /* Stereo balance */
+ __u16 step; /* Step actual volume uses */
+};
+
+struct video_clip
+{
+ __s32 x,y;
+ __s32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ __u32 x,y; /* Position of window */
+ __u32 width,height; /* Its size */
+ __u32 chromakey;
+ __u32 flags;
+ struct video_clip __user *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
+};
+
+struct video_capture
+{
+ __u32 x,y; /* Offsets into image */
+ __u32 width, height; /* Area to capture */
+ __u16 decimation; /* Decimation divider */
+ __u16 flags; /* Flags for capture */
+#define VIDEO_CAPTURE_ODD 0 /* Temporal */
+#define VIDEO_CAPTURE_EVEN 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 - n) for double buffer */
+ int height,width;
+ unsigned int format; /* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+ __u8 key[8];
+ __u32 flags;
+};
+
+struct video_mbuf
+{
+ int size; /* Total memory to map */
+ int frames; /* Frames */
+ int offsets[VIDEO_MAX_FRAME];
+};
+
+#define VIDEO_NO_UNIT (-1)
+
+struct video_unit
+{
+ int video; /* Video minor */
+ int vbi; /* VBI minor */
+ int radio; /* Radio minor */
+ int audio; /* Audio minor */
+ int teletext; /* Teletext minor */
+};
+
+struct vbi_format {
+ __u32 sampling_rate; /* in Hz */
+ __u32 samples_per_line;
+ __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */
+ __s32 start[2]; /* starting line for each frame */
+ __u32 count[2]; /* count of lines for each frame */
+ __u32 flags;
+#define VBI_UNSYNC 1 /* can distingues between top/bottom field */
+#define VBI_INTERLACED 2 /* lines are interlaced */
+};
+
+/* video_info is biased towards hardware mpeg encode/decode */
+/* but it could apply generically to any hardware compressor/decompressor */
+struct video_info
+{
+ __u32 frame_count; /* frames output since decode/encode began */
+ __u32 h_size; /* current unscaled horizontal size */
+ __u32 v_size; /* current unscaled veritcal size */
+ __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */
+ __u32 picture_type; /* current picture type */
+ __u32 temporal_reference; /* current temporal reference */
+ __u8 user_data[256]; /* user data last found in compressed stream */
+ /* user_data[0] contains user data flags, user_data[1] has count */
+};
+
+/* generic structure for setting playback modes */
+struct video_play_mode
+{
+ int mode;
+ int p1;
+ int p2;
+};
+
+/* for loading microcode / fpga programming */
+struct video_code
+{
+ char loadwhat[16]; /* name or tag of file being passed */
+ int datasize;
+ __u8 *data;
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
+#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
+#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
+#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
+#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
+#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
+#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
+
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+/* VIDIOCSWRITEMODE */
+#define VID_WRITE_MPEG_AUD 0
+#define VID_WRITE_MPEG_VID 1
+#define VID_WRITE_OSD 2
+#define VID_WRITE_TTX 3
+#define VID_WRITE_CC 4
+#define VID_WRITE_MJPEG 5
+
+/* VIDIOCSPLAYMODE */
+#define VID_PLAY_VID_OUT_MODE 0
+ /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
+#define VID_PLAY_GENLOCK 1
+ /* p1: 0 = OFF, 1 = ON */
+ /* p2: GENLOCK FINE DELAY value */
+#define VID_PLAY_NORMAL 2
+#define VID_PLAY_PAUSE 3
+#define VID_PLAY_SINGLE_FRAME 4
+#define VID_PLAY_FAST_FORWARD 5
+#define VID_PLAY_SLOW_MOTION 6
+#define VID_PLAY_IMMEDIATE_NORMAL 7
+#define VID_PLAY_SWITCH_CHANNELS 8
+#define VID_PLAY_FREEZE_FRAME 9
+#define VID_PLAY_STILL_MODE 10
+#define VID_PLAY_MASTER_MODE 11
+ /* p1: see below */
+#define VID_PLAY_MASTER_NONE 1
+#define VID_PLAY_MASTER_VIDEO 2
+#define VID_PLAY_MASTER_AUDIO 3
+#define VID_PLAY_ACTIVE_SCANLINES 12
+ /* p1 = first active; p2 = last active */
+#define VID_PLAY_RESET 13
+#define VID_PLAY_END_MARK 14
+
+#endif /* __LINUX_VIDEODEV_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/vme/bridges/Module.symvers
index e69de29bb2d1..e69de29bb2d1 100644
--- a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
+++ b/drivers/staging/vme/bridges/Module.symvers
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index 4d745623211b..42de83e6f1d9 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -44,7 +44,7 @@ static int geoid;
static char driver_name[] = "vme_ca91cx42";
-static const struct pci_device_id ca91cx42_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(ca91cx42_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) },
{ },
};
@@ -58,7 +58,7 @@ static struct pci_driver ca91cx42_driver = {
static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge)
{
- wake_up(&(bridge->dma_queue));
+ wake_up(&bridge->dma_queue);
return CA91CX42_LINT_DMA;
}
@@ -82,14 +82,14 @@ static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat)
/* XXX This needs to be split into 4 queues */
static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask)
{
- wake_up(&(bridge->mbox_queue));
+ wake_up(&bridge->mbox_queue);
return CA91CX42_LINT_MBOX;
}
static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge)
{
- wake_up(&(bridge->iack_queue));
+ wake_up(&bridge->iack_queue);
return CA91CX42_LINT_SW_IACK;
}
@@ -207,9 +207,9 @@ static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
/* Initialise list for VME bus errors */
- INIT_LIST_HEAD(&(ca91cx42_bridge->vme_errors));
+ INIT_LIST_HEAD(&ca91cx42_bridge->vme_errors);
- mutex_init(&(ca91cx42_bridge->irq_mtx));
+ mutex_init(&ca91cx42_bridge->irq_mtx);
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
@@ -259,8 +259,8 @@ static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
/*
* Set up an VME interrupt
*/
-void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, int state,
- int sync)
+static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level,
+ int state, int sync)
{
struct pci_dev *pdev;
@@ -287,7 +287,7 @@ void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, int state,
}
}
-int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
+static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
int statid)
{
u32 tmp;
@@ -299,7 +299,7 @@ int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
if (statid & 1)
return -EINVAL;
- mutex_lock(&(bridge->vme_int));
+ mutex_lock(&bridge->vme_int);
tmp = ioread32(bridge->base + VINT_EN);
@@ -318,12 +318,12 @@ int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
tmp = tmp & ~(1 << (level + 24));
iowrite32(tmp, bridge->base + VINT_EN);
- mutex_unlock(&(bridge->vme_int));
+ mutex_unlock(&bridge->vme_int);
return 0;
}
-int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
+static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
unsigned long long vme_base, unsigned long long size,
dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle)
{
@@ -429,7 +429,7 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
return 0;
}
-int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
+static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle)
{
@@ -518,8 +518,8 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
image->kern_base = NULL;
if (image->bus_resource.name != NULL)
kfree(image->bus_resource.name);
- release_resource(&(image->bus_resource));
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ release_resource(&image->bus_resource);
+ memset(&image->bus_resource, 0, sizeof(struct resource));
}
if (image->bus_resource.name == NULL) {
@@ -540,7 +540,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
image->bus_resource.flags = IORESOURCE_MEM;
retval = pci_bus_alloc_resource(pdev->bus,
- &(image->bus_resource), size, size, PCIBIOS_MIN_MEM,
+ &image->bus_resource, size, size, PCIBIOS_MIN_MEM,
0, NULL, NULL);
if (retval) {
dev_err(ca91cx42_bridge->parent, "Failed to allocate mem "
@@ -563,10 +563,10 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
iounmap(image->kern_base);
image->kern_base = NULL;
err_remap:
- release_resource(&(image->bus_resource));
+ release_resource(&image->bus_resource);
err_resource:
kfree(image->bus_resource.name);
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ memset(&image->bus_resource, 0, sizeof(struct resource));
err_name:
return retval;
}
@@ -578,13 +578,13 @@ static void ca91cx42_free_resource(struct vme_master_resource *image)
{
iounmap(image->kern_base);
image->kern_base = NULL;
- release_resource(&(image->bus_resource));
+ release_resource(&image->bus_resource);
kfree(image->bus_resource.name);
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ memset(&image->bus_resource, 0, sizeof(struct resource));
}
-int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
+static int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
unsigned long long vme_base, unsigned long long size,
vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
{
@@ -620,7 +620,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
goto err_window;
}
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
/*
* Let's allocate the resource here rather than further up the stack as
@@ -628,7 +628,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
*/
retval = ca91cx42_alloc_resource(image, size);
if (retval) {
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(ca91cx42_bridge->parent, "Unable to allocate memory "
"for resource name\n");
retval = -ENOMEM;
@@ -672,7 +672,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
temp_ctl |= CA91CX42_LSI_CTL_VDW_D64;
break;
default:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(ca91cx42_bridge->parent, "Invalid data width\n");
retval = -EINVAL;
goto err_dwidth;
@@ -704,7 +704,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
case VME_USER3:
case VME_USER4:
default:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(ca91cx42_bridge->parent, "Invalid address space\n");
retval = -EINVAL;
goto err_aspace;
@@ -730,7 +730,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return 0;
err_aspace:
@@ -741,8 +741,8 @@ err_window:
return retval;
}
-int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
- unsigned long long *vme_base, unsigned long long *size,
+static int __ca91cx42_master_get(struct vme_master_resource *image,
+ int *enabled, unsigned long long *vme_base, unsigned long long *size,
vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
{
unsigned int i, ctl;
@@ -828,24 +828,24 @@ int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
return 0;
}
-int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
+static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
{
int retval;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace,
cycle, dwidth);
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return retval;
}
-ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf,
- size_t count, loff_t offset)
+static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
+ void *buf, size_t count, loff_t offset)
{
ssize_t retval;
void *addr = image->kern_base + offset;
@@ -855,7 +855,7 @@ ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf,
if (count == 0)
return 0;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
/* The following code handles VME address alignment problem
* in order to assure the maximal data width cycle.
@@ -899,13 +899,13 @@ ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf,
}
out:
retval = count;
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return retval;
}
-ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
- size_t count, loff_t offset)
+static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
+ void *buf, size_t count, loff_t offset)
{
ssize_t retval;
void *addr = image->kern_base + offset;
@@ -915,7 +915,7 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
if (count == 0)
return 0;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
/* Here we apply for the same strategy we do in master_read
* function in order to assure D16 cycle when required.
@@ -954,11 +954,12 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
out:
retval = count;
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
+
return retval;
}
-unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
+static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
unsigned int mask, unsigned int compare, unsigned int swap,
loff_t offset)
{
@@ -974,10 +975,10 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
i = image->number;
/* Locking as we can only do one of these at a time */
- mutex_lock(&(bridge->vme_rmw));
+ mutex_lock(&bridge->vme_rmw);
/* Lock image */
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
pci_addr = (u32)image->kern_base + offset;
@@ -1007,15 +1008,15 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
iowrite32(0, bridge->base + SCYC_CTL);
out:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
- mutex_unlock(&(bridge->vme_rmw));
+ mutex_unlock(&bridge->vme_rmw);
return result;
}
-int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
- struct vme_dma_attr *dest, size_t count)
+static int ca91cx42_dma_list_add(struct vme_dma_list *list,
+ struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
{
struct ca91cx42_dma_entry *entry, *prev;
struct vme_dma_pci *pci_attr;
@@ -1036,14 +1037,14 @@ int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
}
/* Test descriptor alignment */
- if ((unsigned long)&(entry->descriptor) & CA91CX42_DCPP_M) {
+ if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) {
dev_err(dev, "Descriptor not aligned to 16 byte boundary as "
- "required: %p\n", &(entry->descriptor));
+ "required: %p\n", &entry->descriptor);
retval = -EINVAL;
goto err_align;
}
- memset(&(entry->descriptor), 0, sizeof(struct ca91cx42_dma_descriptor));
+ memset(&entry->descriptor, 0, sizeof(struct ca91cx42_dma_descriptor));
if (dest->type == VME_DMA_VME) {
entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
@@ -1138,14 +1139,14 @@ int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.dcpp = CA91CX42_DCPP_NULL;
/* Add to list */
- list_add_tail(&(entry->list), &(list->entries));
+ list_add_tail(&entry->list, &list->entries);
/* Fill out previous descriptors "Next Address" */
- if (entry->list.prev != &(list->entries)) {
+ if (entry->list.prev != &list->entries) {
prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry,
list);
/* We need the bus address for the pointer */
- desc_ptr = virt_to_bus(&(entry->descriptor));
+ desc_ptr = virt_to_bus(&entry->descriptor);
prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M;
}
@@ -1175,7 +1176,7 @@ static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge)
return 1;
}
-int ca91cx42_dma_list_exec(struct vme_dma_list *list)
+static int ca91cx42_dma_list_exec(struct vme_dma_list *list)
{
struct vme_dma_resource *ctrlr;
struct ca91cx42_dma_entry *entry;
@@ -1190,28 +1191,28 @@ int ca91cx42_dma_list_exec(struct vme_dma_list *list)
bridge = ctrlr->parent->driver_priv;
dev = ctrlr->parent->parent;
- mutex_lock(&(ctrlr->mtx));
+ mutex_lock(&ctrlr->mtx);
- if (!(list_empty(&(ctrlr->running)))) {
+ if (!(list_empty(&ctrlr->running))) {
/*
* XXX We have an active DMA transfer and currently haven't
* sorted out the mechanism for "pending" DMA transfers.
* Return busy.
*/
/* Need to add to pending here */
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
return -EBUSY;
} else {
- list_add(&(list->list), &(ctrlr->running));
+ list_add(&list->list, &ctrlr->running);
}
/* Get first bus address and write into registers */
- entry = list_first_entry(&(list->entries), struct ca91cx42_dma_entry,
+ entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry,
list);
- bus_addr = virt_to_bus(&(entry->descriptor));
+ bus_addr = virt_to_bus(&entry->descriptor);
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
iowrite32(0, bridge->base + DTBC);
iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP);
@@ -1249,21 +1250,21 @@ int ca91cx42_dma_list_exec(struct vme_dma_list *list)
}
/* Remove list from running list */
- mutex_lock(&(ctrlr->mtx));
- list_del(&(list->list));
- mutex_unlock(&(ctrlr->mtx));
+ mutex_lock(&ctrlr->mtx);
+ list_del(&list->list);
+ mutex_unlock(&ctrlr->mtx);
return retval;
}
-int ca91cx42_dma_list_empty(struct vme_dma_list *list)
+static int ca91cx42_dma_list_empty(struct vme_dma_list *list)
{
struct list_head *pos, *temp;
struct ca91cx42_dma_entry *entry;
/* detach and free each entry */
- list_for_each_safe(pos, temp, &(list->entries)) {
+ list_for_each_safe(pos, temp, &list->entries) {
list_del(pos);
entry = list_entry(pos, struct ca91cx42_dma_entry, list);
kfree(entry);
@@ -1279,8 +1280,8 @@ int ca91cx42_dma_list_empty(struct vme_dma_list *list)
* This does not enable the LM monitor - that should be done when the first
* callback is attached and disabled when the last callback is removed.
*/
-int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
- vme_address_t aspace, vme_cycle_t cycle)
+static int ca91cx42_lm_set(struct vme_lm_resource *lm,
+ unsigned long long lm_base, vme_address_t aspace, vme_cycle_t cycle)
{
u32 temp_base, lm_ctl = 0;
int i;
@@ -1298,12 +1299,12 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
return -EINVAL;
}
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* If we already have a callback attached, we can't move it! */
for (i = 0; i < lm->monitors; i++) {
if (bridge->lm_callback[i] != NULL) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(dev, "Location monitor callback attached, "
"can't reset\n");
return -EBUSY;
@@ -1321,7 +1322,7 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
lm_ctl |= CA91CX42_LM_CTL_AS_A32;
break;
default:
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(dev, "Invalid address space\n");
return -EINVAL;
break;
@@ -1339,7 +1340,7 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
iowrite32(lm_base, bridge->base + LM_BS);
iowrite32(lm_ctl, bridge->base + LM_CTL);
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
@@ -1347,15 +1348,15 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
/* Get configuration of the callback monitor and return whether it is enabled
* or disabled.
*/
-int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
- vme_address_t *aspace, vme_cycle_t *cycle)
+static int ca91cx42_lm_get(struct vme_lm_resource *lm,
+ unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle)
{
u32 lm_ctl, enabled = 0;
struct ca91cx42_driver *bridge;
bridge = lm->parent->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
*lm_base = (unsigned long long)ioread32(bridge->base + LM_BS);
lm_ctl = ioread32(bridge->base + LM_CTL);
@@ -1380,7 +1381,7 @@ int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
if (lm_ctl & CA91CX42_LM_CTL_DATA)
*cycle |= VME_DATA;
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return enabled;
}
@@ -1390,7 +1391,7 @@ int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
*
* Callback will be passed the monitor triggered.
*/
-int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
+static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
void (*callback)(int))
{
u32 lm_ctl, tmp;
@@ -1400,19 +1401,19 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
bridge = lm->parent->driver_priv;
dev = lm->parent->parent;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* Ensure that the location monitor is configured - need PGM or DATA */
lm_ctl = ioread32(bridge->base + LM_CTL);
if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(dev, "Location monitor not properly configured\n");
return -EINVAL;
}
/* Check that a callback isn't already attached */
if (bridge->lm_callback[monitor] != NULL) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(dev, "Existing callback attached\n");
return -EBUSY;
}
@@ -1431,7 +1432,7 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
iowrite32(lm_ctl, bridge->base + LM_CTL);
}
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
@@ -1439,14 +1440,14 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
/*
* Detach a callback function forn a specific location monitor.
*/
-int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
+static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
{
u32 tmp;
struct ca91cx42_driver *bridge;
bridge = lm->parent->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* Disable Location Monitor and ensure previous interrupts are clear */
tmp = ioread32(bridge->base + LINT_EN);
@@ -1467,12 +1468,12 @@ int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
iowrite32(tmp, bridge->base + LM_CTL);
}
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
-int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
+static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
{
u32 slot = 0;
struct ca91cx42_driver *bridge;
@@ -1526,7 +1527,7 @@ static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge,
/* Allocate mem for CR/CSR image */
bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
- &(bridge->crcsr_bus));
+ &bridge->crcsr_bus);
if (bridge->crcsr_kernel == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
"image\n");
@@ -1632,12 +1633,12 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Initialize wait queues & mutual exclusion flags */
- init_waitqueue_head(&(ca91cx42_device->dma_queue));
- init_waitqueue_head(&(ca91cx42_device->iack_queue));
- mutex_init(&(ca91cx42_device->vme_int));
- mutex_init(&(ca91cx42_device->vme_rmw));
+ init_waitqueue_head(&ca91cx42_device->dma_queue);
+ init_waitqueue_head(&ca91cx42_device->iack_queue);
+ mutex_init(&ca91cx42_device->vme_int);
+ mutex_init(&ca91cx42_device->vme_rmw);
- ca91cx42_bridge->parent = &(pdev->dev);
+ ca91cx42_bridge->parent = &pdev->dev;
strcpy(ca91cx42_bridge->name, driver_name);
/* Setup IRQ */
@@ -1648,7 +1649,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Add master windows to list */
- INIT_LIST_HEAD(&(ca91cx42_bridge->master_resources));
+ INIT_LIST_HEAD(&ca91cx42_bridge->master_resources);
for (i = 0; i < CA91C142_MAX_MASTER; i++) {
master_image = kmalloc(sizeof(struct vme_master_resource),
GFP_KERNEL);
@@ -1659,7 +1660,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_master;
}
master_image->parent = ca91cx42_bridge;
- spin_lock_init(&(master_image->lock));
+ spin_lock_init(&master_image->lock);
master_image->locked = 0;
master_image->number = i;
master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
@@ -1667,15 +1668,15 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
VME_SUPER | VME_USER | VME_PROG | VME_DATA;
master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
- memset(&(master_image->bus_resource), 0,
+ memset(&master_image->bus_resource, 0,
sizeof(struct resource));
master_image->kern_base = NULL;
- list_add_tail(&(master_image->list),
- &(ca91cx42_bridge->master_resources));
+ list_add_tail(&master_image->list,
+ &ca91cx42_bridge->master_resources);
}
/* Add slave windows to list */
- INIT_LIST_HEAD(&(ca91cx42_bridge->slave_resources));
+ INIT_LIST_HEAD(&ca91cx42_bridge->slave_resources);
for (i = 0; i < CA91C142_MAX_SLAVE; i++) {
slave_image = kmalloc(sizeof(struct vme_slave_resource),
GFP_KERNEL);
@@ -1686,7 +1687,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_slave;
}
slave_image->parent = ca91cx42_bridge;
- mutex_init(&(slave_image->mtx));
+ mutex_init(&slave_image->mtx);
slave_image->locked = 0;
slave_image->number = i;
slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 |
@@ -1698,12 +1699,12 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
VME_SUPER | VME_USER | VME_PROG | VME_DATA;
- list_add_tail(&(slave_image->list),
- &(ca91cx42_bridge->slave_resources));
+ list_add_tail(&slave_image->list,
+ &ca91cx42_bridge->slave_resources);
}
/* Add dma engines to list */
- INIT_LIST_HEAD(&(ca91cx42_bridge->dma_resources));
+ INIT_LIST_HEAD(&ca91cx42_bridge->dma_resources);
for (i = 0; i < CA91C142_MAX_DMA; i++) {
dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
GFP_KERNEL);
@@ -1714,19 +1715,19 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_dma;
}
dma_ctrlr->parent = ca91cx42_bridge;
- mutex_init(&(dma_ctrlr->mtx));
+ mutex_init(&dma_ctrlr->mtx);
dma_ctrlr->locked = 0;
dma_ctrlr->number = i;
dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
VME_DMA_MEM_TO_VME;
- INIT_LIST_HEAD(&(dma_ctrlr->pending));
- INIT_LIST_HEAD(&(dma_ctrlr->running));
- list_add_tail(&(dma_ctrlr->list),
- &(ca91cx42_bridge->dma_resources));
+ INIT_LIST_HEAD(&dma_ctrlr->pending);
+ INIT_LIST_HEAD(&dma_ctrlr->running);
+ list_add_tail(&dma_ctrlr->list,
+ &ca91cx42_bridge->dma_resources);
}
/* Add location monitor to list */
- INIT_LIST_HEAD(&(ca91cx42_bridge->lm_resources));
+ INIT_LIST_HEAD(&ca91cx42_bridge->lm_resources);
lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
if (lm == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for "
@@ -1735,11 +1736,11 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_lm;
}
lm->parent = ca91cx42_bridge;
- mutex_init(&(lm->mtx));
+ mutex_init(&lm->mtx);
lm->locked = 0;
lm->number = 1;
lm->monitors = 4;
- list_add_tail(&(lm->list), &(ca91cx42_bridge->lm_resources));
+ list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources);
ca91cx42_bridge->slave_get = ca91cx42_slave_get;
ca91cx42_bridge->slave_set = ca91cx42_slave_set;
@@ -1786,28 +1787,28 @@ err_reg:
ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
err_lm:
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->lm_resources) {
lm = list_entry(pos, struct vme_lm_resource, list);
list_del(pos);
kfree(lm);
}
err_dma:
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->dma_resources) {
dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
list_del(pos);
kfree(dma_ctrlr);
}
err_slave:
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->slave_resources) {
slave_image = list_entry(pos, struct vme_slave_resource, list);
list_del(pos);
kfree(slave_image);
}
err_master:
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->master_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->master_resources) {
master_image = list_entry(pos, struct vme_master_resource,
list);
list_del(pos);
@@ -1831,7 +1832,7 @@ err_struct:
}
-void ca91cx42_remove(struct pci_dev *pdev)
+static void ca91cx42_remove(struct pci_dev *pdev)
{
struct list_head *pos = NULL;
struct vme_master_resource *master_image;
@@ -1870,28 +1871,28 @@ void ca91cx42_remove(struct pci_dev *pdev)
ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->lm_resources) {
lm = list_entry(pos, struct vme_lm_resource, list);
list_del(pos);
kfree(lm);
}
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->dma_resources) {
dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
list_del(pos);
kfree(dma_ctrlr);
}
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->slave_resources) {
slave_image = list_entry(pos, struct vme_slave_resource, list);
list_del(pos);
kfree(slave_image);
}
/* resources are stored in link list */
- list_for_each(pos, &(ca91cx42_bridge->master_resources)) {
+ list_for_each(pos, &ca91cx42_bridge->master_resources) {
master_image = list_entry(pos, struct vme_master_resource,
list);
list_del(pos);
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/staging/vme/bridges/vme_ca91cx42.h
index e72c65b193ec..02a7c794db05 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.h
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.h
@@ -39,7 +39,7 @@
/* Structure used to hold driver specific information */
struct ca91cx42_driver {
- void *base; /* Base Address of device registers */
+ void __iomem *base; /* Base Address of device registers */
wait_queue_head_t dma_queue;
wait_queue_head_t iack_queue;
wait_queue_head_t mbox_queue;
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index 492ddb2d5108..26ea42fa784d 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -46,7 +46,7 @@ static int geoid;
static char driver_name[] = "vme_tsi148";
-static const struct pci_device_id tsi148_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
{ },
};
@@ -81,11 +81,11 @@ static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
u32 serviced = 0;
if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
- wake_up(&(bridge->dma_queue[0]));
+ wake_up(&bridge->dma_queue[0]);
serviced |= TSI148_LCSR_INTC_DMA0C;
}
if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
- wake_up(&(bridge->dma_queue[1]));
+ wake_up(&bridge->dma_queue[1]);
serviced |= TSI148_LCSR_INTC_DMA1C;
}
@@ -191,7 +191,7 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
if (error) {
error->address = error_addr;
error->attributes = error_attrib;
- list_add_tail(&(error->list), &(tsi148_bridge->vme_errors));
+ list_add_tail(&error->list, &tsi148_bridge->vme_errors);
} else {
dev_err(tsi148_bridge->parent, "Unable to alloc memory for "
"VMEbus Error reporting\n");
@@ -210,7 +210,7 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
*/
static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
{
- wake_up(&(bridge->iack_queue));
+ wake_up(&bridge->iack_queue);
return TSI148_LCSR_INTC_IACKC;
}
@@ -320,9 +320,9 @@ static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
bridge = tsi148_bridge->driver_priv;
/* Initialise list for VME bus errors */
- INIT_LIST_HEAD(&(tsi148_bridge->vme_errors));
+ INIT_LIST_HEAD(&tsi148_bridge->vme_errors);
- mutex_init(&(tsi148_bridge->irq_mtx));
+ mutex_init(&tsi148_bridge->irq_mtx);
result = request_irq(pdev->irq,
tsi148_irqhandler,
@@ -374,8 +374,11 @@ static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
return 0;
}
-static void tsi148_irq_exit(struct tsi148_driver *bridge, struct pci_dev *pdev)
+static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge,
+ struct pci_dev *pdev)
{
+ struct tsi148_driver *bridge = tsi148_bridge->driver_priv;
+
/* Turn off interrupts */
iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
@@ -384,13 +387,13 @@ static void tsi148_irq_exit(struct tsi148_driver *bridge, struct pci_dev *pdev)
iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
/* Detach interrupt handler */
- free_irq(pdev->irq, pdev);
+ free_irq(pdev->irq, tsi148_bridge);
}
/*
* Check to see if an IACk has been received, return true (1) or false (0).
*/
-int tsi148_iack_received(struct tsi148_driver *bridge)
+static int tsi148_iack_received(struct tsi148_driver *bridge)
{
u32 tmp;
@@ -405,7 +408,7 @@ int tsi148_iack_received(struct tsi148_driver *bridge)
/*
* Configure VME interrupt
*/
-void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
+static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
int state, int sync)
{
struct pci_dev *pdev;
@@ -445,14 +448,15 @@ void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
* Generate a VME bus interrupt at the requested level & vector. Wait for
* interrupt to be acked.
*/
-int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid)
+static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level,
+ int statid)
{
u32 tmp;
struct tsi148_driver *bridge;
bridge = tsi148_bridge->driver_priv;
- mutex_lock(&(bridge->vme_int));
+ mutex_lock(&bridge->vme_int);
/* Read VICR register */
tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
@@ -470,7 +474,7 @@ int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid)
wait_event_interruptible(bridge->iack_queue,
tsi148_iack_received(bridge));
- mutex_unlock(&(bridge->vme_int));
+ mutex_unlock(&bridge->vme_int);
return 0;
}
@@ -496,7 +500,7 @@ static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
*/
err_pos = NULL;
/* Iterate through errors */
- list_for_each(err_pos, &(tsi148_bridge->vme_errors)) {
+ list_for_each(err_pos, &tsi148_bridge->vme_errors) {
vme_err = list_entry(err_pos, struct vme_bus_error, list);
if ((vme_err->address >= address) &&
(vme_err->address < bound)) {
@@ -530,7 +534,7 @@ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
*/
err_pos = NULL;
/* Iterate through errors */
- list_for_each_safe(err_pos, temp, &(tsi148_bridge->vme_errors)) {
+ list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) {
vme_err = list_entry(err_pos, struct vme_bus_error, list);
if ((vme_err->address >= address) &&
@@ -545,7 +549,7 @@ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
/*
* Initialize a slave window with the requested attributes.
*/
-int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
+static int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
unsigned long long vme_base, unsigned long long size,
dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle)
{
@@ -695,7 +699,7 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
/*
* Get slave window configuration.
*/
-int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
+static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle)
{
@@ -819,8 +823,8 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
image->kern_base = NULL;
if (image->bus_resource.name != NULL)
kfree(image->bus_resource.name);
- release_resource(&(image->bus_resource));
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ release_resource(&image->bus_resource);
+ memset(&image->bus_resource, 0, sizeof(struct resource));
}
/* Exit here if size is zero */
@@ -845,7 +849,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
image->bus_resource.flags = IORESOURCE_MEM;
retval = pci_bus_alloc_resource(pdev->bus,
- &(image->bus_resource), size, size, PCIBIOS_MIN_MEM,
+ &image->bus_resource, size, size, PCIBIOS_MIN_MEM,
0, NULL, NULL);
if (retval) {
dev_err(tsi148_bridge->parent, "Failed to allocate mem "
@@ -868,10 +872,10 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
iounmap(image->kern_base);
image->kern_base = NULL;
err_remap:
- release_resource(&(image->bus_resource));
+ release_resource(&image->bus_resource);
err_resource:
kfree(image->bus_resource.name);
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ memset(&image->bus_resource, 0, sizeof(struct resource));
err_name:
return retval;
}
@@ -883,15 +887,15 @@ static void tsi148_free_resource(struct vme_master_resource *image)
{
iounmap(image->kern_base);
image->kern_base = NULL;
- release_resource(&(image->bus_resource));
+ release_resource(&image->bus_resource);
kfree(image->bus_resource.name);
- memset(&(image->bus_resource), 0, sizeof(struct resource));
+ memset(&image->bus_resource, 0, sizeof(struct resource));
}
/*
* Set the attributes of an outbound window.
*/
-int tsi148_master_set(struct vme_master_resource *image, int enabled,
+static int tsi148_master_set(struct vme_master_resource *image, int enabled,
unsigned long long vme_base, unsigned long long size,
vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
{
@@ -924,7 +928,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
goto err_window;
}
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
/* Let's allocate the resource here rather than further up the stack as
* it avoids pushing loads of bus dependant stuff up the stack. If size
@@ -932,7 +936,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
*/
retval = tsi148_alloc_resource(image, size);
if (retval) {
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Unable to allocate memory for "
"resource\n");
goto err_res;
@@ -959,19 +963,19 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
if (pci_base_low & 0xFFFF) {
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n");
retval = -EINVAL;
goto err_gran;
}
if (pci_bound_low & 0xFFFF) {
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n");
retval = -EINVAL;
goto err_gran;
}
if (vme_offset_low & 0xFFFF) {
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Invalid VME Offset "
"alignment\n");
retval = -EINVAL;
@@ -1035,7 +1039,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
break;
default:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Invalid data width\n");
retval = -EINVAL;
goto err_dwidth;
@@ -1072,7 +1076,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
break;
default:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
dev_err(tsi148_bridge->parent, "Invalid address space\n");
retval = -EINVAL;
goto err_aspace;
@@ -1109,7 +1113,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled,
iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return 0;
err_aspace:
@@ -1127,7 +1131,7 @@ err_window:
*
* XXX Not parsing prefetch information.
*/
-int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
+static int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
{
@@ -1237,23 +1241,23 @@ int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
}
-int tsi148_master_get(struct vme_master_resource *image, int *enabled,
+static int tsi148_master_get(struct vme_master_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
{
int retval;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
cycle, dwidth);
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return retval;
}
-ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
+static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
size_t count, loff_t offset)
{
int retval, enabled;
@@ -1266,7 +1270,7 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
tsi148_bridge = image->parent;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
retval = count;
@@ -1289,13 +1293,13 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
}
skip_chk:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return retval;
}
-ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
+static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
size_t count, loff_t offset)
{
int retval = 0, enabled;
@@ -1312,7 +1316,7 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
bridge = tsi148_bridge->driver_priv;
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
retval = count;
@@ -1352,7 +1356,7 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
}
skip_chk:
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
return retval;
}
@@ -1362,7 +1366,7 @@ skip_chk:
*
* Requires a previously configured master window, returns final value.
*/
-unsigned int tsi148_master_rmw(struct vme_master_resource *image,
+static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
unsigned int mask, unsigned int compare, unsigned int swap,
loff_t offset)
{
@@ -1378,10 +1382,10 @@ unsigned int tsi148_master_rmw(struct vme_master_resource *image,
i = image->number;
/* Locking as we can only do one of these at a time */
- mutex_lock(&(bridge->vme_rmw));
+ mutex_lock(&bridge->vme_rmw);
/* Lock image */
- spin_lock(&(image->lock));
+ spin_lock(&image->lock);
pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAU);
@@ -1411,9 +1415,9 @@ unsigned int tsi148_master_rmw(struct vme_master_resource *image,
tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
- spin_unlock(&(image->lock));
+ spin_unlock(&image->lock);
- mutex_unlock(&(bridge->vme_rmw));
+ mutex_unlock(&bridge->vme_rmw);
return result;
}
@@ -1609,8 +1613,8 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
/*
* Add a link list descriptor to the list
*/
-int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
- struct vme_dma_attr *dest, size_t count)
+static int tsi148_dma_list_add(struct vme_dma_list *list,
+ struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
{
struct tsi148_dma_entry *entry, *prev;
u32 address_high, address_low;
@@ -1633,10 +1637,10 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
}
/* Test descriptor alignment */
- if ((unsigned long)&(entry->descriptor) & 0x7) {
+ if ((unsigned long)&entry->descriptor & 0x7) {
dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 "
"byte boundary as required: %p\n",
- &(entry->descriptor));
+ &entry->descriptor);
retval = -EINVAL;
goto err_align;
}
@@ -1644,7 +1648,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
/* Given we are going to fill out the structure, we probably don't
* need to zero it, but better safe than sorry for now.
*/
- memset(&(entry->descriptor), 0, sizeof(struct tsi148_dma_descriptor));
+ memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor));
/* Fill out source part */
switch (src->type) {
@@ -1681,7 +1685,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
retval = tsi148_dma_set_vme_src_attributes(
- tsi148_bridge->parent, &(entry->descriptor.dsat),
+ tsi148_bridge->parent, &entry->descriptor.dsat,
vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
if (retval < 0)
goto err_source;
@@ -1719,7 +1723,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
retval = tsi148_dma_set_vme_dest_attributes(
- tsi148_bridge->parent, &(entry->descriptor.ddat),
+ tsi148_bridge->parent, &entry->descriptor.ddat,
vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
if (retval < 0)
goto err_dest;
@@ -1735,16 +1739,16 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.dcnt = (u32)count;
/* Add to list */
- list_add_tail(&(entry->list), &(list->entries));
+ list_add_tail(&entry->list, &list->entries);
/* Fill out previous descriptors "Next Address" */
- if (entry->list.prev != &(list->entries)) {
+ if (entry->list.prev != &list->entries) {
prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
list);
/* We need the bus address for the pointer */
- desc_ptr = virt_to_bus(&(entry->descriptor));
- reg_split(desc_ptr, &(prev->descriptor.dnlau),
- &(prev->descriptor.dnlal));
+ desc_ptr = virt_to_bus(&entry->descriptor);
+ reg_split(desc_ptr, &prev->descriptor.dnlau,
+ &prev->descriptor.dnlal);
}
return 0;
@@ -1782,7 +1786,7 @@ static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
*
* XXX Need to provide control register configuration.
*/
-int tsi148_dma_list_exec(struct vme_dma_list *list)
+static int tsi148_dma_list_exec(struct vme_dma_list *list)
{
struct vme_dma_resource *ctrlr;
int channel, retval = 0;
@@ -1799,30 +1803,30 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
bridge = tsi148_bridge->driver_priv;
- mutex_lock(&(ctrlr->mtx));
+ mutex_lock(&ctrlr->mtx);
channel = ctrlr->number;
- if (!list_empty(&(ctrlr->running))) {
+ if (!list_empty(&ctrlr->running)) {
/*
* XXX We have an active DMA transfer and currently haven't
* sorted out the mechanism for "pending" DMA transfers.
* Return busy.
*/
/* Need to add to pending here */
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
return -EBUSY;
} else {
- list_add(&(list->list), &(ctrlr->running));
+ list_add(&list->list, &ctrlr->running);
}
/* Get first bus address and write into registers */
- entry = list_first_entry(&(list->entries), struct tsi148_dma_entry,
+ entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
list);
- bus_addr = virt_to_bus(&(entry->descriptor));
+ bus_addr = virt_to_bus(&entry->descriptor);
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
@@ -1850,9 +1854,9 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
}
/* Remove list from running list */
- mutex_lock(&(ctrlr->mtx));
- list_del(&(list->list));
- mutex_unlock(&(ctrlr->mtx));
+ mutex_lock(&ctrlr->mtx);
+ list_del(&list->list);
+ mutex_unlock(&ctrlr->mtx);
return retval;
}
@@ -1862,13 +1866,13 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
*
* We have a separate function, don't assume that the chain can't be reused.
*/
-int tsi148_dma_list_empty(struct vme_dma_list *list)
+static int tsi148_dma_list_empty(struct vme_dma_list *list)
{
struct list_head *pos, *temp;
struct tsi148_dma_entry *entry;
/* detach and free each entry */
- list_for_each_safe(pos, temp, &(list->entries)) {
+ list_for_each_safe(pos, temp, &list->entries) {
list_del(pos);
entry = list_entry(pos, struct tsi148_dma_entry, list);
kfree(entry);
@@ -1884,7 +1888,7 @@ int tsi148_dma_list_empty(struct vme_dma_list *list)
* This does not enable the LM monitor - that should be done when the first
* callback is attached and disabled when the last callback is removed.
*/
-int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
+static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
vme_address_t aspace, vme_cycle_t cycle)
{
u32 lm_base_high, lm_base_low, lm_ctl = 0;
@@ -1896,12 +1900,12 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
bridge = tsi148_bridge->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* If we already have a callback attached, we can't move it! */
for (i = 0; i < lm->monitors; i++) {
if (bridge->lm_callback[i] != NULL) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(tsi148_bridge->parent, "Location monitor "
"callback attached, can't reset\n");
return -EBUSY;
@@ -1922,7 +1926,7 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
break;
default:
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(tsi148_bridge->parent, "Invalid address space\n");
return -EINVAL;
break;
@@ -1943,7 +1947,7 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
@@ -1951,15 +1955,15 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
/* Get configuration of the callback monitor and return whether it is enabled
* or disabled.
*/
-int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
- vme_address_t *aspace, vme_cycle_t *cycle)
+static int tsi148_lm_get(struct vme_lm_resource *lm,
+ unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle)
{
u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
struct tsi148_driver *bridge;
bridge = lm->parent->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
@@ -1992,7 +1996,7 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
if (lm_ctl & TSI148_LCSR_LMAT_DATA)
*cycle |= VME_DATA;
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return enabled;
}
@@ -2002,7 +2006,7 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
*
* Callback will be passed the monitor triggered.
*/
-int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
+static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
void (*callback)(int))
{
u32 lm_ctl, tmp;
@@ -2013,12 +2017,12 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
bridge = tsi148_bridge->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* Ensure that the location monitor is configured - need PGM or DATA */
lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(tsi148_bridge->parent, "Location monitor not properly "
"configured\n");
return -EINVAL;
@@ -2026,7 +2030,7 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
/* Check that a callback isn't already attached */
if (bridge->lm_callback[monitor] != NULL) {
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
dev_err(tsi148_bridge->parent, "Existing callback attached\n");
return -EBUSY;
}
@@ -2049,7 +2053,7 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
}
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
@@ -2057,14 +2061,14 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
/*
* Detach a callback function forn a specific location monitor.
*/
-int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
+static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
{
u32 lm_en, tmp;
struct tsi148_driver *bridge;
bridge = lm->parent->driver_priv;
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* Disable Location Monitor and ensure previous interrupts are clear */
lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
@@ -2089,7 +2093,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
}
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
return 0;
}
@@ -2097,7 +2101,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
/*
* Determine Geographical Addressing
*/
-int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
+static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
{
u32 slot = 0;
struct tsi148_driver *bridge;
@@ -2142,7 +2146,7 @@ static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
/* Allocate mem for CR/CSR image */
bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
- &(bridge->crcsr_bus));
+ &bridge->crcsr_bus);
if (bridge->crcsr_kernel == NULL) {
dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
"CR/CSR image\n");
@@ -2280,13 +2284,13 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Initialize wait queues & mutual exclusion flags */
- init_waitqueue_head(&(tsi148_device->dma_queue[0]));
- init_waitqueue_head(&(tsi148_device->dma_queue[1]));
- init_waitqueue_head(&(tsi148_device->iack_queue));
- mutex_init(&(tsi148_device->vme_int));
- mutex_init(&(tsi148_device->vme_rmw));
+ init_waitqueue_head(&tsi148_device->dma_queue[0]);
+ init_waitqueue_head(&tsi148_device->dma_queue[1]);
+ init_waitqueue_head(&tsi148_device->iack_queue);
+ mutex_init(&tsi148_device->vme_int);
+ mutex_init(&tsi148_device->vme_rmw);
- tsi148_bridge->parent = &(pdev->dev);
+ tsi148_bridge->parent = &pdev->dev;
strcpy(tsi148_bridge->name, driver_name);
/* Setup IRQ */
@@ -2314,7 +2318,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_master;
}
tsi148_device->flush_image->parent = tsi148_bridge;
- spin_lock_init(&(tsi148_device->flush_image->lock));
+ spin_lock_init(&tsi148_device->flush_image->lock);
tsi148_device->flush_image->locked = 1;
tsi148_device->flush_image->number = master_num;
tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 |
@@ -2324,13 +2328,13 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER |
VME_USER | VME_PROG | VME_DATA;
tsi148_device->flush_image->width_attr = VME_D16 | VME_D32;
- memset(&(tsi148_device->flush_image->bus_resource), 0,
+ memset(&tsi148_device->flush_image->bus_resource, 0,
sizeof(struct resource));
tsi148_device->flush_image->kern_base = NULL;
}
/* Add master windows to list */
- INIT_LIST_HEAD(&(tsi148_bridge->master_resources));
+ INIT_LIST_HEAD(&tsi148_bridge->master_resources);
for (i = 0; i < master_num; i++) {
master_image = kmalloc(sizeof(struct vme_master_resource),
GFP_KERNEL);
@@ -2341,7 +2345,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_master;
}
master_image->parent = tsi148_bridge;
- spin_lock_init(&(master_image->lock));
+ spin_lock_init(&master_image->lock);
master_image->locked = 0;
master_image->number = i;
master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
@@ -2351,15 +2355,15 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
VME_PROG | VME_DATA;
master_image->width_attr = VME_D16 | VME_D32;
- memset(&(master_image->bus_resource), 0,
+ memset(&master_image->bus_resource, 0,
sizeof(struct resource));
master_image->kern_base = NULL;
- list_add_tail(&(master_image->list),
- &(tsi148_bridge->master_resources));
+ list_add_tail(&master_image->list,
+ &tsi148_bridge->master_resources);
}
/* Add slave windows to list */
- INIT_LIST_HEAD(&(tsi148_bridge->slave_resources));
+ INIT_LIST_HEAD(&tsi148_bridge->slave_resources);
for (i = 0; i < TSI148_MAX_SLAVE; i++) {
slave_image = kmalloc(sizeof(struct vme_slave_resource),
GFP_KERNEL);
@@ -2370,7 +2374,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_slave;
}
slave_image->parent = tsi148_bridge;
- mutex_init(&(slave_image->mtx));
+ mutex_init(&slave_image->mtx);
slave_image->locked = 0;
slave_image->number = i;
slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
@@ -2380,12 +2384,12 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
VME_PROG | VME_DATA;
- list_add_tail(&(slave_image->list),
- &(tsi148_bridge->slave_resources));
+ list_add_tail(&slave_image->list,
+ &tsi148_bridge->slave_resources);
}
/* Add dma engines to list */
- INIT_LIST_HEAD(&(tsi148_bridge->dma_resources));
+ INIT_LIST_HEAD(&tsi148_bridge->dma_resources);
for (i = 0; i < TSI148_MAX_DMA; i++) {
dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
GFP_KERNEL);
@@ -2396,21 +2400,21 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_dma;
}
dma_ctrlr->parent = tsi148_bridge;
- mutex_init(&(dma_ctrlr->mtx));
+ mutex_init(&dma_ctrlr->mtx);
dma_ctrlr->locked = 0;
dma_ctrlr->number = i;
dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
VME_DMA_PATTERN_TO_MEM;
- INIT_LIST_HEAD(&(dma_ctrlr->pending));
- INIT_LIST_HEAD(&(dma_ctrlr->running));
- list_add_tail(&(dma_ctrlr->list),
- &(tsi148_bridge->dma_resources));
+ INIT_LIST_HEAD(&dma_ctrlr->pending);
+ INIT_LIST_HEAD(&dma_ctrlr->running);
+ list_add_tail(&dma_ctrlr->list,
+ &tsi148_bridge->dma_resources);
}
/* Add location monitor to list */
- INIT_LIST_HEAD(&(tsi148_bridge->lm_resources));
+ INIT_LIST_HEAD(&tsi148_bridge->lm_resources);
lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
if (lm == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for "
@@ -2419,11 +2423,11 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_lm;
}
lm->parent = tsi148_bridge;
- mutex_init(&(lm->mtx));
+ mutex_init(&lm->mtx);
lm->locked = 0;
lm->number = 1;
lm->monitors = 4;
- list_add_tail(&(lm->list), &(tsi148_bridge->lm_resources));
+ list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
tsi148_bridge->slave_get = tsi148_slave_get;
tsi148_bridge->slave_set = tsi148_slave_set;
@@ -2477,41 +2481,40 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
- vme_unregister_bridge(tsi148_bridge);
err_reg:
tsi148_crcsr_exit(tsi148_bridge, pdev);
err_crcsr:
err_lm:
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->lm_resources)) {
+ list_for_each(pos, &tsi148_bridge->lm_resources) {
lm = list_entry(pos, struct vme_lm_resource, list);
list_del(pos);
kfree(lm);
}
err_dma:
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->dma_resources)) {
+ list_for_each(pos, &tsi148_bridge->dma_resources) {
dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
list_del(pos);
kfree(dma_ctrlr);
}
err_slave:
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->slave_resources)) {
+ list_for_each(pos, &tsi148_bridge->slave_resources) {
slave_image = list_entry(pos, struct vme_slave_resource, list);
list_del(pos);
kfree(slave_image);
}
err_master:
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->master_resources)) {
+ list_for_each(pos, &tsi148_bridge->master_resources) {
master_image = list_entry(pos, struct vme_master_resource,
list);
list_del(pos);
kfree(master_image);
}
- tsi148_irq_exit(tsi148_device, pdev);
+ tsi148_irq_exit(tsi148_bridge, pdev);
err_irq:
err_test:
iounmap(tsi148_device->base);
@@ -2531,6 +2534,7 @@ err_struct:
static void tsi148_remove(struct pci_dev *pdev)
{
struct list_head *pos = NULL;
+ struct list_head *tmplist;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
@@ -2582,36 +2586,34 @@ static void tsi148_remove(struct pci_dev *pdev)
iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
- tsi148_irq_exit(bridge, pdev);
+ tsi148_irq_exit(tsi148_bridge, pdev);
vme_unregister_bridge(tsi148_bridge);
tsi148_crcsr_exit(tsi148_bridge, pdev);
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->dma_resources)) {
+ list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
list_del(pos);
kfree(dma_ctrlr);
}
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->slave_resources)) {
+ list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) {
slave_image = list_entry(pos, struct vme_slave_resource, list);
list_del(pos);
kfree(slave_image);
}
/* resources are stored in link list */
- list_for_each(pos, &(tsi148_bridge->master_resources)) {
+ list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) {
master_image = list_entry(pos, struct vme_master_resource,
list);
list_del(pos);
kfree(master_image);
}
- tsi148_irq_exit(bridge, pdev);
-
iounmap(bridge->base);
pci_release_regions(pdev);
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h
index bda64ef85754..9f97fa8084e8 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.h
+++ b/drivers/staging/vme/bridges/vme_tsi148.h
@@ -35,7 +35,7 @@
/* Structure used to hold driver specific information */
struct tsi148_driver {
- void *base; /* Base Address of device registers */
+ void __iomem *base; /* Base Address of device registers */
wait_queue_head_t dma_queue[2];
wait_queue_head_t iack_queue;
void (*lm_callback[4])(int); /* Called in interrupt handler */
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 71bbc526626c..a571173249cf 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -44,7 +44,7 @@ static DEFINE_MUTEX(vme_user_mutex);
static char driver_name[] = "vme_user";
static int bus[USER_BUS_MAX];
-static int bus_num;
+static unsigned int bus_num;
/* Currently Documentation/devices.txt defines the following for VME:
*
@@ -92,7 +92,7 @@ static int bus_num;
* Structure to handle image related parameters.
*/
typedef struct {
- void __iomem *kern_buf; /* Buffer address in kernel space */
+ void *kern_buf; /* Buffer address in kernel space */
dma_addr_t pci_buf; /* Buffer address in PCI address space */
unsigned long long size_buf; /* Buffer size */
struct semaphore sem; /* Semaphore for locking image */
@@ -114,9 +114,9 @@ typedef struct {
} driver_stats_t;
static driver_stats_t statistics;
-struct cdev *vme_user_cdev; /* Character device */
-struct class *vme_user_sysfs_class; /* Sysfs class */
-struct device *vme_user_bridge; /* Pointer to the bridge device */
+static struct cdev *vme_user_cdev; /* Character device */
+static struct class *vme_user_sysfs_class; /* Sysfs class */
+static struct device *vme_user_bridge; /* Pointer to bridge device */
static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR,
@@ -129,13 +129,14 @@ static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR,
static int vme_user_open(struct inode *, struct file *);
static int vme_user_release(struct inode *, struct file *);
-static ssize_t vme_user_read(struct file *, char *, size_t, loff_t *);
-static ssize_t vme_user_write(struct file *, const char *, size_t, loff_t *);
+static ssize_t vme_user_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t vme_user_write(struct file *, const char __user *, size_t,
+ loff_t *);
static loff_t vme_user_llseek(struct file *, loff_t, int);
static long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-static int __init vme_user_probe(struct device *, int, int);
-static int __exit vme_user_remove(struct device *, int, int);
+static int __devinit vme_user_probe(struct device *, int, int);
+static int __devexit vme_user_remove(struct device *, int, int);
static struct file_operations vme_user_fops = {
.open = vme_user_open,
@@ -246,7 +247,7 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
* page) transfers will lock the user space buffer into memory and then
* transfer the data directly from the user space buffers out to VME.
*/
-static ssize_t resource_from_user(unsigned int minor, const char *buf,
+static ssize_t resource_from_user(unsigned int minor, const char __user *buf,
size_t count, loff_t *ppos)
{
ssize_t retval;
@@ -277,7 +278,7 @@ static ssize_t resource_from_user(unsigned int minor, const char *buf,
static ssize_t buffer_to_user(unsigned int minor, char __user *buf,
size_t count, loff_t *ppos)
{
- void __iomem *image_ptr;
+ void *image_ptr;
ssize_t retval;
image_ptr = image[minor].kern_buf + *ppos;
@@ -293,10 +294,10 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf,
return retval;
}
-static ssize_t buffer_from_user(unsigned int minor, const char *buf,
+static ssize_t buffer_from_user(unsigned int minor, const char __user *buf,
size_t count, loff_t *ppos)
{
- void __iomem *image_ptr;
+ void *image_ptr;
size_t retval;
image_ptr = image[minor].kern_buf + *ppos;
@@ -312,7 +313,7 @@ static ssize_t buffer_from_user(unsigned int minor, const char *buf,
return retval;
}
-static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
+static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
@@ -356,8 +357,8 @@ static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
return retval;
}
-static ssize_t vme_user_write(struct file *file, const char *buf, size_t count,
- loff_t *ppos)
+static ssize_t vme_user_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
ssize_t retval;
@@ -455,6 +456,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
unsigned int minor = MINOR(inode->i_rdev);
int retval;
dma_addr_t pci_addr;
+ void __user *argp = (void __user *)arg;
statistics.ioctls++;
@@ -470,11 +472,11 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
* to userspace as they are
*/
retval = vme_master_get(image[minor].resource,
- &(master.enable), &(master.vme_addr),
- &(master.size), &(master.aspace),
- &(master.cycle), &(master.dwidth));
+ &master.enable, &master.vme_addr,
+ &master.size, &master.aspace,
+ &master.cycle, &master.dwidth);
- copied = copy_to_user((char *)arg, &master,
+ copied = copy_to_user(argp, &master,
sizeof(struct vme_master));
if (copied != 0) {
printk(KERN_WARNING "Partial copy to "
@@ -487,8 +489,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
case VME_SET_MASTER:
- copied = copy_from_user(&master, (char *)arg,
- sizeof(master));
+ copied = copy_from_user(&master, argp, sizeof(master));
if (copied != 0) {
printk(KERN_WARNING "Partial copy from "
"userspace\n");
@@ -514,11 +515,11 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
* to userspace as they are
*/
retval = vme_slave_get(image[minor].resource,
- &(slave.enable), &(slave.vme_addr),
- &(slave.size), &pci_addr, &(slave.aspace),
- &(slave.cycle));
+ &slave.enable, &slave.vme_addr,
+ &slave.size, &pci_addr, &slave.aspace,
+ &slave.cycle);
- copied = copy_to_user((char *)arg, &slave,
+ copied = copy_to_user(argp, &slave,
sizeof(struct vme_slave));
if (copied != 0) {
printk(KERN_WARNING "Partial copy to "
@@ -531,8 +532,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file,
case VME_SET_SLAVE:
- copied = copy_from_user(&slave, (char *)arg,
- sizeof(slave));
+ copied = copy_from_user(&slave, argp, sizeof(slave));
if (copied != 0) {
printk(KERN_WARNING "Partial copy from "
"userspace\n");
@@ -596,7 +596,7 @@ static void buf_unalloc(int num)
static struct vme_driver vme_user_driver = {
.name = driver_name,
.probe = vme_user_probe,
- .remove = vme_user_remove,
+ .remove = __devexit_p(vme_user_remove),
};
@@ -611,6 +611,7 @@ static int __init vme_user_init(void)
if (bus_num == 0) {
printk(KERN_ERR "%s: No cards, skipping registration\n",
driver_name);
+ retval = -ENODEV;
goto err_nocard;
}
@@ -629,6 +630,7 @@ static int __init vme_user_init(void)
if (ids == NULL) {
printk(KERN_ERR "%s: Unable to allocate ID table\n",
driver_name);
+ retval = -ENOMEM;
goto err_id;
}
@@ -652,7 +654,6 @@ static int __init vme_user_init(void)
return retval;
- vme_unregister_driver(&vme_user_driver);
err_reg:
kfree(ids);
err_id:
@@ -665,7 +666,8 @@ err_nocard:
* as practical. We will therefore reserve the buffers and request the images
* here so that we don't have to do it later.
*/
-static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
+static int __devinit vme_user_probe(struct device *dev, int cur_bus,
+ int cur_slot)
{
int i, err;
char name[12];
@@ -683,7 +685,7 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
for (i = 0; i < VME_DEVS; i++) {
image[i].kern_buf = NULL;
image[i].pci_buf = 0;
- sema_init(&(image[i].sem), 1);
+ sema_init(&image[i].sem, 1);
image[i].device = NULL;
image[i].resource = NULL;
image[i].users = 0;
@@ -727,7 +729,7 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
}
image[i].size_buf = PCI_BUF_SIZE;
image[i].kern_buf = vme_alloc_consistent(image[i].resource,
- image[i].size_buf, &(image[i].pci_buf));
+ image[i].size_buf, &image[i].pci_buf);
if (image[i].kern_buf == NULL) {
printk(KERN_WARNING "Unable to allocate memory for "
"buffer\n");
@@ -828,8 +830,8 @@ err_master:
err_slave:
while (i > SLAVE_MINOR) {
i--;
- vme_slave_free(image[i].resource);
buf_unalloc(i);
+ vme_slave_free(image[i].resource);
}
err_class:
cdev_del(vme_user_cdev);
@@ -840,7 +842,8 @@ err_dev:
return err;
}
-static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
+static int __devexit vme_user_remove(struct device *dev, int cur_bus,
+ int cur_slot)
{
int i;
@@ -849,13 +852,15 @@ static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
class_destroy(vme_user_sysfs_class);
- for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++)
+ for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
kfree(image[i].kern_buf);
+ vme_master_free(image[i].resource);
+ }
for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
- vme_slave_free(image[i].resource);
buf_unalloc(i);
+ vme_slave_free(image[i].resource);
}
/* Unregister device driver */
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
index 093fbffbf557..d9fc8644376e 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/staging/vme/vme.c
@@ -245,7 +245,7 @@ struct vme_resource *vme_slave_request(struct device *dev,
}
/* Loop through slave resources */
- list_for_each(slave_pos, &(bridge->slave_resources)) {
+ list_for_each(slave_pos, &bridge->slave_resources) {
slave_image = list_entry(slave_pos,
struct vme_slave_resource, list);
@@ -255,17 +255,17 @@ struct vme_resource *vme_slave_request(struct device *dev,
}
/* Find an unlocked and compatible image */
- mutex_lock(&(slave_image->mtx));
+ mutex_lock(&slave_image->mtx);
if (((slave_image->address_attr & address) == address) &&
((slave_image->cycle_attr & cycle) == cycle) &&
(slave_image->locked == 0)) {
slave_image->locked = 1;
- mutex_unlock(&(slave_image->mtx));
+ mutex_unlock(&slave_image->mtx);
allocated_image = slave_image;
break;
}
- mutex_unlock(&(slave_image->mtx));
+ mutex_unlock(&slave_image->mtx);
}
/* No free image */
@@ -278,15 +278,15 @@ struct vme_resource *vme_slave_request(struct device *dev,
goto err_alloc;
}
resource->type = VME_SLAVE;
- resource->entry = &(allocated_image->list);
+ resource->entry = &allocated_image->list;
return resource;
err_alloc:
/* Unlock image */
- mutex_lock(&(slave_image->mtx));
+ mutex_lock(&slave_image->mtx);
slave_image->locked = 0;
- mutex_unlock(&(slave_image->mtx));
+ mutex_unlock(&slave_image->mtx);
err_image:
err_bus:
return NULL;
@@ -369,12 +369,12 @@ void vme_slave_free(struct vme_resource *resource)
}
/* Unlock image */
- mutex_lock(&(slave_image->mtx));
+ mutex_lock(&slave_image->mtx);
if (slave_image->locked == 0)
printk(KERN_ERR "Image is already free\n");
slave_image->locked = 0;
- mutex_unlock(&(slave_image->mtx));
+ mutex_unlock(&slave_image->mtx);
/* Free up resource memory */
kfree(resource);
@@ -401,7 +401,7 @@ struct vme_resource *vme_master_request(struct device *dev,
}
/* Loop through master resources */
- list_for_each(master_pos, &(bridge->master_resources)) {
+ list_for_each(master_pos, &bridge->master_resources) {
master_image = list_entry(master_pos,
struct vme_master_resource, list);
@@ -411,18 +411,18 @@ struct vme_resource *vme_master_request(struct device *dev,
}
/* Find an unlocked and compatible image */
- spin_lock(&(master_image->lock));
+ spin_lock(&master_image->lock);
if (((master_image->address_attr & address) == address) &&
((master_image->cycle_attr & cycle) == cycle) &&
((master_image->width_attr & dwidth) == dwidth) &&
(master_image->locked == 0)) {
master_image->locked = 1;
- spin_unlock(&(master_image->lock));
+ spin_unlock(&master_image->lock);
allocated_image = master_image;
break;
}
- spin_unlock(&(master_image->lock));
+ spin_unlock(&master_image->lock);
}
/* Check to see if we found a resource */
@@ -437,16 +437,16 @@ struct vme_resource *vme_master_request(struct device *dev,
goto err_alloc;
}
resource->type = VME_MASTER;
- resource->entry = &(allocated_image->list);
+ resource->entry = &allocated_image->list;
return resource;
kfree(resource);
err_alloc:
/* Unlock image */
- spin_lock(&(master_image->lock));
+ spin_lock(&master_image->lock);
master_image->locked = 0;
- spin_unlock(&(master_image->lock));
+ spin_unlock(&master_image->lock);
err_image:
err_bus:
return NULL;
@@ -628,12 +628,12 @@ void vme_master_free(struct vme_resource *resource)
}
/* Unlock image */
- spin_lock(&(master_image->lock));
+ spin_lock(&master_image->lock);
if (master_image->locked == 0)
printk(KERN_ERR "Image is already free\n");
master_image->locked = 0;
- spin_unlock(&(master_image->lock));
+ spin_unlock(&master_image->lock);
/* Free up resource memory */
kfree(resource);
@@ -662,7 +662,7 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route)
}
/* Loop through DMA resources */
- list_for_each(dma_pos, &(bridge->dma_resources)) {
+ list_for_each(dma_pos, &bridge->dma_resources) {
dma_ctrlr = list_entry(dma_pos,
struct vme_dma_resource, list);
@@ -672,16 +672,16 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route)
}
/* Find an unlocked and compatible controller */
- mutex_lock(&(dma_ctrlr->mtx));
+ mutex_lock(&dma_ctrlr->mtx);
if (((dma_ctrlr->route_attr & route) == route) &&
(dma_ctrlr->locked == 0)) {
dma_ctrlr->locked = 1;
- mutex_unlock(&(dma_ctrlr->mtx));
+ mutex_unlock(&dma_ctrlr->mtx);
allocated_ctrlr = dma_ctrlr;
break;
}
- mutex_unlock(&(dma_ctrlr->mtx));
+ mutex_unlock(&dma_ctrlr->mtx);
}
/* Check to see if we found a resource */
@@ -694,15 +694,15 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route)
goto err_alloc;
}
resource->type = VME_DMA;
- resource->entry = &(allocated_ctrlr->list);
+ resource->entry = &allocated_ctrlr->list;
return resource;
err_alloc:
/* Unlock image */
- mutex_lock(&(dma_ctrlr->mtx));
+ mutex_lock(&dma_ctrlr->mtx);
dma_ctrlr->locked = 0;
- mutex_unlock(&(dma_ctrlr->mtx));
+ mutex_unlock(&dma_ctrlr->mtx);
err_ctrlr:
err_bus:
return NULL;
@@ -729,9 +729,9 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
printk(KERN_ERR "Unable to allocate memory for new dma list\n");
return NULL;
}
- INIT_LIST_HEAD(&(dma_list->entries));
+ INIT_LIST_HEAD(&dma_list->entries);
dma_list->parent = ctrlr;
- mutex_init(&(dma_list->mtx));
+ mutex_init(&dma_list->mtx);
return dma_list;
}
@@ -880,14 +880,14 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
return -EINVAL;
}
- if (!mutex_trylock(&(list->mtx))) {
+ if (!mutex_trylock(&list->mtx)) {
printk(KERN_ERR "Link List already submitted\n");
return -EINVAL;
}
retval = bridge->dma_list_add(list, src, dest, count);
- mutex_unlock(&(list->mtx));
+ mutex_unlock(&list->mtx);
return retval;
}
@@ -903,11 +903,11 @@ int vme_dma_list_exec(struct vme_dma_list *list)
return -EINVAL;
}
- mutex_lock(&(list->mtx));
+ mutex_lock(&list->mtx);
retval = bridge->dma_list_exec(list);
- mutex_unlock(&(list->mtx));
+ mutex_unlock(&list->mtx);
return retval;
}
@@ -923,7 +923,7 @@ int vme_dma_list_free(struct vme_dma_list *list)
return -EINVAL;
}
- if (!mutex_trylock(&(list->mtx))) {
+ if (!mutex_trylock(&list->mtx)) {
printk(KERN_ERR "Link List in use\n");
return -EINVAL;
}
@@ -935,10 +935,10 @@ int vme_dma_list_free(struct vme_dma_list *list)
retval = bridge->dma_list_empty(list);
if (retval) {
printk(KERN_ERR "Unable to empty link-list entries\n");
- mutex_unlock(&(list->mtx));
+ mutex_unlock(&list->mtx);
return retval;
}
- mutex_unlock(&(list->mtx));
+ mutex_unlock(&list->mtx);
kfree(list);
return retval;
@@ -956,20 +956,20 @@ int vme_dma_free(struct vme_resource *resource)
ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
- if (!mutex_trylock(&(ctrlr->mtx))) {
+ if (!mutex_trylock(&ctrlr->mtx)) {
printk(KERN_ERR "Resource busy, can't free\n");
return -EBUSY;
}
- if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) {
+ if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
printk(KERN_WARNING "Resource still processing transfers\n");
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
return -EBUSY;
}
ctrlr->locked = 0;
- mutex_unlock(&(ctrlr->mtx));
+ mutex_unlock(&ctrlr->mtx);
return 0;
}
@@ -1013,10 +1013,10 @@ int vme_irq_request(struct device *dev, int level, int statid,
return -EINVAL;
}
- mutex_lock(&(bridge->irq_mtx));
+ mutex_lock(&bridge->irq_mtx);
if (bridge->irq[level - 1].callback[statid].func) {
- mutex_unlock(&(bridge->irq_mtx));
+ mutex_unlock(&bridge->irq_mtx);
printk(KERN_WARNING "VME Interrupt already taken\n");
return -EBUSY;
}
@@ -1028,7 +1028,7 @@ int vme_irq_request(struct device *dev, int level, int statid,
/* Enable IRQ level */
bridge->irq_set(bridge, level, 1, 1);
- mutex_unlock(&(bridge->irq_mtx));
+ mutex_unlock(&bridge->irq_mtx);
return 0;
}
@@ -1054,7 +1054,7 @@ void vme_irq_free(struct device *dev, int level, int statid)
return;
}
- mutex_lock(&(bridge->irq_mtx));
+ mutex_lock(&bridge->irq_mtx);
bridge->irq[level - 1].count--;
@@ -1065,7 +1065,7 @@ void vme_irq_free(struct device *dev, int level, int statid)
bridge->irq[level - 1].callback[statid].func = NULL;
bridge->irq[level - 1].callback[statid].priv_data = NULL;
- mutex_unlock(&(bridge->irq_mtx));
+ mutex_unlock(&bridge->irq_mtx);
}
EXPORT_SYMBOL(vme_irq_free);
@@ -1111,7 +1111,7 @@ struct vme_resource *vme_lm_request(struct device *dev)
}
/* Loop through DMA resources */
- list_for_each(lm_pos, &(bridge->lm_resources)) {
+ list_for_each(lm_pos, &bridge->lm_resources) {
lm = list_entry(lm_pos,
struct vme_lm_resource, list);
@@ -1122,14 +1122,14 @@ struct vme_resource *vme_lm_request(struct device *dev)
}
/* Find an unlocked controller */
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
if (lm->locked == 0) {
lm->locked = 1;
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
allocated_lm = lm;
break;
}
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
}
/* Check to see if we found a resource */
@@ -1142,15 +1142,15 @@ struct vme_resource *vme_lm_request(struct device *dev)
goto err_alloc;
}
resource->type = VME_LM;
- resource->entry = &(allocated_lm->list);
+ resource->entry = &allocated_lm->list;
return resource;
err_alloc:
/* Unlock image */
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
lm->locked = 0;
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
err_lm:
err_bus:
return NULL;
@@ -1270,7 +1270,7 @@ void vme_lm_free(struct vme_resource *resource)
lm = list_entry(resource->entry, struct vme_lm_resource, list);
- mutex_lock(&(lm->mtx));
+ mutex_lock(&lm->mtx);
/* XXX
* Check to see that there aren't any callbacks still attached, if
@@ -1279,7 +1279,7 @@ void vme_lm_free(struct vme_resource *resource)
lm->locked = 0;
- mutex_unlock(&(lm->mtx));
+ mutex_unlock(&lm->mtx);
kfree(resource);
}
@@ -1326,7 +1326,7 @@ static int vme_alloc_bus_num(void)
static void vme_free_bus_num(int bus)
{
mutex_lock(&vme_bus_num_mtx);
- vme_bus_numbers |= ~(0x1 << bus);
+ vme_bus_numbers &= ~(0x1 << bus);
mutex_unlock(&vme_bus_num_mtx);
}
@@ -1343,11 +1343,11 @@ int vme_register_bridge(struct vme_bridge *bridge)
* specification.
*/
for (i = 0; i < VME_SLOTS_MAX; i++) {
- dev = &(bridge->dev[i]);
+ dev = &bridge->dev[i];
memset(dev, 0, sizeof(struct device));
dev->parent = bridge->parent;
- dev->bus = &(vme_bus_type);
+ dev->bus = &vme_bus_type;
/*
* We save a pointer to the bridge in platform_data so that we
* can get to it later. We keep driver_data for use by the
@@ -1366,7 +1366,7 @@ int vme_register_bridge(struct vme_bridge *bridge)
i = VME_SLOTS_MAX;
err_reg:
while (i > -1) {
- dev = &(bridge->dev[i]);
+ dev = &bridge->dev[i];
device_unregister(dev);
}
vme_free_bus_num(bridge->num);
@@ -1381,7 +1381,7 @@ void vme_unregister_bridge(struct vme_bridge *bridge)
for (i = 0; i < VME_SLOTS_MAX; i++) {
- dev = &(bridge->dev[i]);
+ dev = &bridge->dev[i];
device_unregister(dev);
}
vme_free_bus_num(bridge->num);
@@ -1418,7 +1418,7 @@ static int vme_calc_slot(struct device *dev)
/* Determine slot number */
num = 0;
while (num < VME_SLOTS_MAX) {
- if (&(bridge->dev[num]) == dev)
+ if (&bridge->dev[num] == dev)
break;
num++;
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h
index b653ec02e1fc..4c6ec31b01db 100644
--- a/drivers/staging/vme/vme_bridge.h
+++ b/drivers/staging/vme/vme_bridge.h
@@ -20,7 +20,7 @@ struct vme_master_resource {
vme_cycle_t cycle_attr;
vme_width_t width_attr;
struct resource bus_resource;
- void *kern_base;
+ void __iomem *kern_base;
};
struct vme_slave_resource {
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 32d095c4d51c..951a3a8ddcb2 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -2058,7 +2058,7 @@ bool CARDbSoftwareReset (void *pDeviceHandler)
QWORD CARDqGetTSFOffset (unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2)
{
QWORD qwTSFOffset;
- unsigned short wRxBcnTSFOffst= 0;;
+ unsigned short wRxBcnTSFOffst= 0;
HIDWORD(qwTSFOffset) = 0;
LODWORD(qwTSFOffset) = 0;
diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c
index 92e33999054b..5e425d1476b8 100644
--- a/drivers/staging/vt6655/iwctl.c
+++ b/drivers/staging/vt6655/iwctl.c
@@ -2073,7 +2073,7 @@ int iwctl_giwencodeext(struct net_device *dev,
struct iw_point *wrq,
char *extra)
{
- return -EOPNOTSUPP;;
+ return -EOPNOTSUPP;
}
int iwctl_siwmlme(struct net_device *dev,
diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c
index 805164bed7e4..744799cfe832 100644
--- a/drivers/staging/vt6655/wpa2.c
+++ b/drivers/staging/vt6655/wpa2.c
@@ -216,7 +216,7 @@ WPA2vParseRSN (
m = *((unsigned short *) &(pRSN->abyRSN[4]));
if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
- pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));;
+ pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));
j = 0;
pbyOUI = &(pRSN->abyRSN[8+4*m]);
for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
@@ -235,7 +235,7 @@ WPA2vParseRSN (
pBSSNode->wAKMSSAuthCount = (unsigned short)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
- n = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));;
+ n = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));
if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
pBSSNode->sRSNCapObj.bRSNCapExist = true;
pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *) &(pRSN->abyRSN[8+4*m+4*n]));
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index e5add2046375..0d11147f91c1 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -963,7 +963,7 @@ BBvSetAntennaMode (PSDevice pDevice, BYTE byAntennaMode)
break;
case ANT_RXB:
pDevice->byBBRxConf &= 0xFE;
- pDevice->byBBRxConf |= 0x02;;
+ pDevice->byBBRxConf |= 0x02;
break;
}
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 8de21aac1bff..a49053bd7c65 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -1092,7 +1092,7 @@ CARDbChannelSwitch (
pDevice->sMgmtObj.uCurrChannel = byNewChannel;
bResult = CARDbSetMediaChannel(pDevice, byNewChannel);
- return(bResult);
+ return bResult;
}
pDevice->byChannelSwitchCount = byCount;
pDevice->byNewChannel = byNewChannel;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index 1f9d29636803..f4fb0c6e4eac 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -1608,8 +1608,8 @@ void RXvMngWorkItem(void *Context)
}
}
- pDevice->bIsRxMngWorkItemQueued = FALSE;
- spin_unlock_irq(&pDevice->lock);
+ pDevice->bIsRxMngWorkItemQueued = FALSE;
+ spin_unlock_irq(&pDevice->lock);
}
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index 0004be8e3957..2121205a912b 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -1883,7 +1883,7 @@ int iwctl_giwencodeext(struct net_device *dev,
struct iw_point *wrq,
char *extra)
{
- return -EOPNOTSUPP;;
+ return -EOPNOTSUPP;
}
int iwctl_siwmlme(struct net_device *dev,
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index e992d5d9e15b..7cc3d2407d1b 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1675,13 +1675,14 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
{
char essid[IW_ESSID_MAX_SIZE+1];
- if (wrq->u.essid.pointer)
+ if (wrq->u.essid.pointer) {
rc = iwctl_giwessid(dev, NULL,
&(wrq->u.essid), essid);
if (copy_to_user(wrq->u.essid.pointer,
essid,
wrq->u.essid.length) )
rc = -EFAULT;
+ }
}
break;
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index 0c12fd36d0f9..e8c1b35e8128 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -192,7 +192,7 @@ BOOL PSbConsiderPowerDown(void *hDeviceContext,
// check if already in Doze mode
ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PSCTL, &byData);
if ( (byData & PSCTL_PS) != 0 )
- return TRUE;;
+ return TRUE;
if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
// check if in TIM wake period
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index bbdc127a987d..8f18578a5903 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -68,8 +68,7 @@
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c
index a6bd533f9577..0715636cb9cb 100644
--- a/drivers/staging/vt6656/tkip.c
+++ b/drivers/staging/vt6656/tkip.c
@@ -214,13 +214,14 @@ void TKIPvMixKey(
/* Phase 1, step 2 */
for (i=0; i<8; i++) {
j = 2*(i & 1);
- p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536 )) % 65536;
- p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536 )) % 65536;
- p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536 )) % 65536;
- p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536 )) % 65536;
- p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536 )) % 65536;
+ p1k[0] = (p1k[0] + tkip_sbox((p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536)) % 65536;
+ p1k[1] = (p1k[1] + tkip_sbox((p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536)) % 65536;
+ p1k[2] = (p1k[2] + tkip_sbox((p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536)) % 65536;
+ p1k[3] = (p1k[3] + tkip_sbox((p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536)) % 65536;
+ p1k[4] = (p1k[4] + tkip_sbox((p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536)) % 65536;
p1k[4] = (p1k[4] + i) % 65536;
}
+
/* Phase 2, Step 1 */
ppk0 = p1k[0];
ppk1 = p1k[1];
@@ -230,19 +231,19 @@ void TKIPvMixKey(
ppk5 = (p1k[4] + tsc2) % 65536;
/* Phase2, Step 2 */
- ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
- ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
- ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
- ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
- ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
- ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
-
- ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
- ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
- ppk2 = ppk2 + rotr1(ppk1);
- ppk3 = ppk3 + rotr1(ppk2);
- ppk4 = ppk4 + rotr1(ppk3);
- ppk5 = ppk5 + rotr1(ppk4);
+ ppk0 = ppk0 + tkip_sbox((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
+ ppk1 = ppk1 + tkip_sbox((ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
+ ppk2 = ppk2 + tkip_sbox((ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
+ ppk3 = ppk3 + tkip_sbox((ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
+ ppk4 = ppk4 + tkip_sbox((ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
+ ppk5 = ppk5 + tkip_sbox((ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
+
+ ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
+ ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
+ ppk2 = ppk2 + rotr1(ppk1);
+ ppk3 = ppk3 + rotr1(ppk2);
+ ppk4 = ppk4 + rotr1(ppk3);
+ ppk5 = ppk5 + rotr1(ppk4);
/* Phase 2, Step 3 */
pbyRC4Key[0] = (tsc2 >> 8) % 256;
diff --git a/drivers/staging/vt6656/wpa2.c b/drivers/staging/vt6656/wpa2.c
index 6d13190885d1..d4f3f7530ee4 100644
--- a/drivers/staging/vt6656/wpa2.c
+++ b/drivers/staging/vt6656/wpa2.c
@@ -215,7 +215,7 @@ WPA2vParseRSN (
m = *((PWORD) &(pRSN->abyRSN[4]));
if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
- pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));;
+ pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));
j = 0;
pbyOUI = &(pRSN->abyRSN[8+4*m]);
for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) {
@@ -234,7 +234,7 @@ WPA2vParseRSN (
pBSSNode->wAKMSSAuthCount = (WORD)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
- n = *((PWORD) &(pRSN->abyRSN[6+4*m]));;
+ n = *((PWORD) &(pRSN->abyRSN[6+4*m]));
if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
pBSSNode->sRSNCapObj.bRSNCapExist = TRUE;
pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n]));
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasusb.c b/drivers/staging/westbridge/astoria/api/src/cyasusb.c
index 5a2197012065..7777d9a60a52 100644
--- a/drivers/staging/westbridge/astoria/api/src/cyasusb.c
+++ b/drivers/staging/westbridge/astoria/api/src/cyasusb.c
@@ -1417,7 +1417,6 @@ cy_as_usb_set_enum_config(cy_as_device_handle handle,
*/
bus_mask = 0;
media_mask = 0;
- media_mask = 0;
for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
if (config_p->devices_to_enumerate[bus][device] ==
diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c
index a6780296888f..ad0c61db9937 100644
--- a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c
+++ b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c
@@ -2127,10 +2127,7 @@ void cy_as_hal_pll_lock_loss_handler(cy_as_hal_device_tag tag)
*/
void *cy_as_hal_alloc(uint32_t cnt)
{
- void *ret_p;
-
- ret_p = kmalloc(cnt, GFP_ATOMIC);
- return ret_p;
+ return kmalloc(cnt, GFP_ATOMIC);
}
/*
@@ -2150,10 +2147,7 @@ void cy_as_hal_free(void *mem_p)
*/
void *cy_as_hal_c_b_alloc(uint32_t cnt)
{
- void *ret_p;
-
- ret_p = kmalloc(cnt, GFP_ATOMIC);
- return ret_p;
+ return kmalloc(cnt, GFP_ATOMIC);
}
/*
diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
index f428a7af357a..e1851f00be56 100644
--- a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
+++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
@@ -157,7 +157,7 @@ struct cyasblkdev_blk_data {
/* pointer to west bridge block data device superstructure */
static struct cyasblkdev_blk_data *gl_bd;
-static DECLARE_MUTEX(open_lock);
+static DEFINE_SEMAPHORE(open_lock);
/* local forwardd declarationss */
static cy_as_device_handle *cyas_dev_handle;
diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c
index 24e959eca412..0bbb8a3e191d 100644
--- a/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c
+++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c
@@ -334,7 +334,7 @@ int cyasblkdev_init_queue(struct cyasblkdev_queue *bq, spinlock_t *lock)
init_completion(&bq->thread_complete);
init_waitqueue_head(&bq->thread_wq);
- init_MUTEX(&bq->thread_sem);
+ sema_init(&bq->thread_sem, 1);
ret = kernel_thread(cyasblkdev_queue_thread, bq, CLONE_KERNEL);
if (ret >= 0) {
diff --git a/drivers/staging/winbond/Makefile b/drivers/staging/winbond/Makefile
index 79fa2271a0c1..081d48db04cb 100644
--- a/drivers/staging/winbond/Makefile
+++ b/drivers/staging/winbond/Makefile
@@ -1,6 +1,5 @@
w35und-y := \
mds.o \
- mlmetxrx.o \
mto.o \
phy_calibration.o \
reg.o \
diff --git a/drivers/staging/winbond/core.h b/drivers/staging/winbond/core.h
index 2b87a0007319..d7b3aca5ddeb 100644
--- a/drivers/staging/winbond/core.h
+++ b/drivers/staging/winbond/core.h
@@ -4,7 +4,7 @@
#include <linux/wireless.h>
#include <linux/types.h>
-#include "wbhal_s.h"
+#include "wbhal.h"
#include "mto.h"
#include "mac_structures.h"
diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h
index ed3df2964065..76c63c74d50c 100644
--- a/drivers/staging/winbond/mac_structures.h
+++ b/drivers/staging/winbond/mac_structures.h
@@ -21,23 +21,11 @@
#ifndef _MAC_Structures_H_
#define _MAC_Structures_H_
-#include <linux/skbuff.h>
-
-/*=========================================================
-// Some miscellaneous definitions
-//-----*/
-#define MAX_CHANNELS 30
#define MAC_ADDR_LENGTH 6
-#define MAX_WEP_KEY_SIZE 16 /* 128 bits */
-#define MAX_802_11_FRAGMENT_NUMBER 10 /* By spec */
/* ========================================================
// 802.11 Frame define
//----- */
-#define MASK_PROTOCOL_VERSION_TYPE 0x0F
-#define MASK_FRAGMENT_NUMBER 0x000F
-#define SEQUENCE_NUMBER_SHIFT 4
-#define DIFFER_11_TO_3 18
#define DOT_11_MAC_HEADER_SIZE 24
#define DOT_11_SNAP_SIZE 6
#define DOT_11_DURATION_OFFSET 2
@@ -47,15 +35,9 @@
#define DOT_11_TYPE_OFFSET 30
#define DOT_11_DATA_OFFSET 24
#define DOT_11_DA_OFFSET 4
-#define DOT_3_TYPE_ARP 0x80F3
-#define DOT_3_TYPE_IPX 0x8137
-#define DOT_3_TYPE_OFFSET 12
-
-#define ETHERNET_HEADER_SIZE 14
#define MAX_ETHERNET_PACKET_SIZE 1514
-
/* ----- management : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */
#define MAC_SUBTYPE_MNGMNT_ASSOC_REQUEST 0x00
#define MAC_SUBTYPE_MNGMNT_ASSOC_RESPONSE 0x10
@@ -69,129 +51,6 @@
#define MAC_SUBTYPE_MNGMNT_AUTHENTICATION 0xB0
#define MAC_SUBTYPE_MNGMNT_DEAUTHENTICATION 0xC0
-/* ----- control : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */
-#define MAC_SUBTYPE_CONTROL_PSPOLL 0xA4
-#define MAC_SUBTYPE_CONTROL_RTS 0xB4
-#define MAC_SUBTYPE_CONTROL_CTS 0xC4
-#define MAC_SUBTYPE_CONTROL_ACK 0xD4
-#define MAC_SUBTYPE_CONTROL_CFEND 0xE4
-#define MAC_SUBTYPE_CONTROL_CFEND_CFACK 0xF4
-
-/* ----- data : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */
-#define MAC_SUBTYPE_DATA 0x08
-#define MAC_SUBTYPE_DATA_CFACK 0x18
-#define MAC_SUBTYPE_DATA_CFPOLL 0x28
-#define MAC_SUBTYPE_DATA_CFACK_CFPOLL 0x38
-#define MAC_SUBTYPE_DATA_NULL 0x48
-#define MAC_SUBTYPE_DATA_CFACK_NULL 0x58
-#define MAC_SUBTYPE_DATA_CFPOLL_NULL 0x68
-#define MAC_SUBTYPE_DATA_CFACK_CFPOLL_NULL 0x78
-
-/* ----- Frame Type of Bits (2, 3) */
-#define MAC_TYPE_MANAGEMENT 0x00
-#define MAC_TYPE_CONTROL 0x04
-#define MAC_TYPE_DATA 0x08
-
-/* ----- definitions for Management Frame Element ID (1 BYTE) */
-#define ELEMENT_ID_SSID 0
-#define ELEMENT_ID_SUPPORTED_RATES 1
-#define ELEMENT_ID_FH_PARAMETER_SET 2
-#define ELEMENT_ID_DS_PARAMETER_SET 3
-#define ELEMENT_ID_CF_PARAMETER_SET 4
-#define ELEMENT_ID_TIM 5
-#define ELEMENT_ID_IBSS_PARAMETER_SET 6
-/* 7~15 reserverd */
-#define ELEMENT_ID_CHALLENGE_TEXT 16
-/* 17~31 reserved for challenge text extension */
-/* 32~255 reserved */
-/*-- 11G -- */
-#define ELEMENT_ID_ERP_INFORMATION 42
-#define ELEMENT_ID_EXTENDED_SUPPORTED_RATES 50
-
-/* -- WPA -- */
-
-#define ELEMENT_ID_RSN_WPA 221
-#ifdef _WPA2_
-#define ELEMENT_ID_RSN_WPA2 48
-#endif /* endif WPA2 */
-
-#define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6)
-#define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2)
-
-/* ===================================================================
-* Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen
-* length of ReasonCode is 2 Octs.
-* =================================================================== */
-#define REASON_REASERED 0
-#define REASON_UNSPECIDIED 1
-#define REASON_PREAUTH_INVALID 2
-#define DEAUTH_REASON_LEFT_BSS 3
-#define DISASS_REASON_AP_INACTIVE 4
-#define DISASS_REASON_AP_BUSY 5
-#define REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define REASON_CLASS3_FRAME_FROM_NONASSO_STA 7
-#define DISASS_REASON_LEFT_BSS 8
-#define REASON_NOT_AUTH_YET 9
-/* 802.11i define */
-#define REASON_INVALID_IE 13
-#define REASON_MIC_ERROR 14
-#define REASON_4WAY_HANDSHAKE_TIMEOUT 15
-#define REASON_GROUPKEY_UPDATE_TIMEOUT 16
-#define REASON_IE_DIFF_4WAY_ASSOC 17
-#define REASON_INVALID_MULTICAST_CIPHER 18
-#define REASON_INVALID_UNICAST_CIPHER 19
-#define REASON_INVALID_AKMP 20
-#define REASON_UNSUPPORTED_RSNIE_VERSION 21
-#define REASON_INVALID_RSNIE_CAPABILITY 22
-#define REASON_802_1X_AUTH_FAIL 23
-#define REASON_CIPHER_REJECT_PER_SEC_POLICY 14
-
-/*
-//===========================================================
-// enum_MMPDUResultCode --
-// Status code (2 Octs) in the MMPDU's frame body. Table.19
-//
-//===========================================================
-enum enum_MMPDUResultCode
-{
-// SUCCESS = 0, // Redefined
- UNSPECIFIED_FAILURE = 1,
-
- // 2 - 9 Reserved
-
- NOT_SUPPROT_CAPABILITIES = 10,
-
- //REASSOCIATION_DENIED
- //
- REASSOC_DENIED_UNABLE_CFM_ASSOC_EXIST = 11,
-
- //ASSOCIATION_DENIED_NOT_IN_STANDARD
- //
- ASSOC_DENIED_REASON_NOT_IN_STANDARD = 12,
- PEER_NOT_SUPPORT_AUTH_ALGORITHM = 13,
- AUTH_SEQNUM_OUT_OF_EXPECT = 14,
- AUTH_REJECT_REASON_CHALLENGE_FAIL = 15,
- AUTH_REJECT_REASON_WAIT_TIMEOUT = 16,
- ASSOC_DENIED_REASON_AP_BUSY = 17,
- ASSOC_DENIED_REASON_NOT_SUPPORT_BASIC_RATE = 18
-} WB_MMPDURESULTCODE, *PWB_MMPDURESULTCODE;
-*/
-
-#define RATE_BITMAP_1M 1
-#define RATE_BITMAP_2M 2
-#define RATE_BITMAP_5dot5M 5
-#define RATE_BITMAP_6M 6
-#define RATE_BITMAP_9M 9
-#define RATE_BITMAP_11M 11
-#define RATE_BITMAP_12M 12
-#define RATE_BITMAP_18M 18
-#define RATE_BITMAP_22M 22
-#define RATE_BITMAP_24M 24
-#define RATE_BITMAP_33M 17
-#define RATE_BITMAP_36M 19
-#define RATE_BITMAP_48M 25
-#define RATE_BITMAP_54M 28
-
#define RATE_AUTO 0
#define RATE_1M 2
#define RATE_2M 4
@@ -209,408 +68,4 @@ enum enum_MMPDUResultCode
#define RATE_54M 108
#define RATE_MAX 255
-/* CAPABILITY */
-#define CAPABILITY_ESS_BIT 0x0001
-#define CAPABILITY_IBSS_BIT 0x0002
-#define CAPABILITY_CF_POLL_BIT 0x0004
-#define CAPABILITY_CF_POLL_REQ_BIT 0x0008
-#define CAPABILITY_PRIVACY_BIT 0x0010
-#define CAPABILITY_SHORT_PREAMBLE_BIT 0x0020
-#define CAPABILITY_PBCC_BIT 0x0040
-#define CAPABILITY_CHAN_AGILITY_BIT 0x0080
-#define CAPABILITY_SHORT_SLOT_TIME_BIT 0x0400
-#define CAPABILITY_DSSS_OFDM_BIT 0x2000
-
-
-struct Capability_Information_Element {
- union {
- u16 __attribute__ ((packed)) wValue;
- #ifdef _BIG_ENDIAN_ /* 20060926 add by anson's endian */
- struct _Capability {
- /* -- 11G -- */
- u8 Reserved3:2;
- u8 DSSS_OFDM:1;
- u8 Reserved2:2;
- u8 Short_Slot_Time:1;
- u8 Reserved1:2;
- u8 Channel_Agility:1;
- u8 PBCC:1;
- u8 ShortPreamble:1;
- u8 CF_Privacy:1;
- u8 CF_Poll_Request:1;
- u8 CF_Pollable:1;
- u8 IBSS:1;
- u8 ESS:1;
- } __attribute__ ((packed)) Capability;
- #else
- struct _Capability {
- u8 ESS:1;
- u8 IBSS:1;
- u8 CF_Pollable:1;
- u8 CF_Poll_Request:1;
- u8 CF_Privacy:1;
- u8 ShortPreamble:1;
- u8 PBCC:1;
- u8 Channel_Agility:1;
- u8 Reserved1:2;
- /* -- 11G -- */
- u8 Short_Slot_Time:1;
- u8 Reserved2:2;
- u8 DSSS_OFDM:1;
- u8 Reserved3:2;
- } __attribute__ ((packed)) Capability;
- #endif
- } __attribute__ ((packed)) ;
-} __attribute__ ((packed));
-
-struct FH_Parameter_Set_Element {
- u8 Element_ID;
- u8 Length;
- u8 Dwell_Time[2];
- u8 Hop_Set;
- u8 Hop_Pattern;
- u8 Hop_Index;
-};
-
-struct DS_Parameter_Set_Element {
- u8 Element_ID;
- u8 Length;
- u8 Current_Channel;
-};
-
-struct Supported_Rates_Element {
- u8 Element_ID;
- u8 Length;
- u8 SupportedRates[8];
-} __attribute__ ((packed));
-
-struct SSID_Element {
- u8 Element_ID;
- u8 Length;
- u8 SSID[32];
-} __attribute__ ((packed)) ;
-
-struct CF_Parameter_Set_Element {
- u8 Element_ID;
- u8 Length;
- u8 CFP_Count;
- u8 CFP_Period;
- u8 CFP_MaxDuration[2]; /* in Time Units */
- u8 CFP_DurRemaining[2]; /* in time units */
-};
-
-struct TIM_Element {
- u8 Element_ID;
- u8 Length;
- u8 DTIM_Count;
- u8 DTIM_Period;
- u8 Bitmap_Control;
- u8 Partial_Virtual_Bitmap[251];
-};
-
-struct IBSS_Parameter_Set_Element {
- u8 Element_ID;
- u8 Length;
- u8 ATIM_Window[2];
-};
-
-struct Challenge_Text_Element {
- u8 Element_ID;
- u8 Length;
- u8 Challenge_Text[253];
-};
-
-struct PHY_Parameter_Set_Element {
-/* int aSlotTime; */
-/* int aSifsTime; */
- s32 aCCATime;
- s32 aRxTxTurnaroundTime;
- s32 aTxPLCPDelay;
- s32 RxPLCPDelay;
- s32 aRxTxSwitchTime;
- s32 aTxRampOntime;
- s32 aTxRampOffTime;
- s32 aTxRFDelay;
- s32 aRxRFDelay;
- s32 aAirPropagationTime;
- s32 aMACProcessingDelay;
- s32 aPreambleLength;
- s32 aPLCPHeaderLength;
- s32 aMPDUDurationFactor;
- s32 aMPDUMaxLength;
-/* int aCWmin; */
-/* int aCWmax; */
-};
-
-/* -- 11G -- */
-struct ERP_Information_Element {
- u8 Element_ID;
- u8 Length;
- #ifdef _BIG_ENDIAN_ /* 20060926 add by anson's endian */
- u8 Reserved:5; /* 20060926 add by anson */
- u8 Barker_Preamble_Mode:1;
- u8 Use_Protection:1;
- u8 NonERP_Present:1;
- #else
- u8 NonERP_Present:1;
- u8 Use_Protection:1;
- u8 Barker_Preamble_Mode:1;
- u8 Reserved:5;
- #endif
-};
-
-struct Extended_Supported_Rates_Element {
- u8 Element_ID;
- u8 Length;
- u8 ExtendedSupportedRates[255];
-} __attribute__ ((packed));
-
-/* WPA(802.11i draft 3.0) */
-#define VERSION_WPA 1
-#ifdef _WPA2_
-#define VERSION_WPA2 1
-#endif /* end def _WPA2_ */
-/* WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type */
-#define OUI_WPA 0x00F25000
-#ifdef _WPA2_
-/* for wpa2 change to 0x00ACOF04 by Ws 26/04/04 */
-#define OUI_WPA2 0x00AC0F00
-#endif /* end def _WPA2_ */
-
-#define OUI_WPA_ADDITIONAL 0x01
-#define WLAN_MIN_RSN_WPA_LENGTH 6 /* added by ws 09/10/04 */
-#ifdef _WPA2_
-#define WLAN_MIN_RSN_WPA2_LENGTH 2 /* Fix to 2 09/14/05 */
-#endif /* end def _WPA2_ */
-
-#define oui_wpa (u32)(OUI_WPA|OUI_WPA_ADDITIONAL)
-
-#define WPA_OUI_BIG ((u32) 0x01F25000)/* added by ws 09/23/04 */
-#define WPA_OUI_LITTLE ((u32) 0x01F25001)/* added by ws 09/23/04 */
-/* 20061108 For WPS. It's little endian. Big endian is 0x0050F204 */
-#define WPA_WPS_OUI cpu_to_le32(0x04F25000)
-
-/* -----WPA2----- */
-#ifdef _WPA2_
-#define WPA2_OUI_BIG ((u32)0x01AC0F00)
-#define WPA2_OUI_LITTLE ((u32)0x01AC0F01)
-#endif /* end def _WPA2_ */
-
-/* Authentication suite */
-#define OUI_AUTH_WPA_NONE 0x00 /* for WPA_NONE */
-#define OUI_AUTH_8021X 0x01
-#define OUI_AUTH_PSK 0x02
-/* Cipher suite */
-#define OUI_CIPHER_GROUP_KEY 0x00 /* added by ws 05/21/04 */
-#define OUI_CIPHER_WEP_40 0x01
-#define OUI_CIPHER_TKIP 0x02
-#define OUI_CIPHER_CCMP 0x04
-#define OUI_CIPHER_WEP_104 0x05
-
-struct suite_selector{
- union{
- u8 Value[4];
- struct _SUIT_ {
- u8 OUI[3];
- u8 Type;
- } SuitSelector;
- };
-};
-
-/* -- WPA -- */
-struct RSN_Information_Element{
- u8 Element_ID;
- u8 Length;
- /* WPA version 2.0 additional field, and should be 00:50:F2:01 */
- struct suite_selector OuiWPAAdditional;
- u16 Version;
- struct suite_selector GroupKeySuite;
- u16 PairwiseKeySuiteCount;
- struct suite_selector PairwiseKeySuite[1];
-} __attribute__ ((packed));
-struct RSN_Auth_Sub_Information_Element {
- u16 AuthKeyMngtSuiteCount;
- struct suite_selector AuthKeyMngtSuite[1];
-} __attribute__ ((packed));
-
-/* -- WPA2 -- */
-struct RSN_Capability_Element {
- union {
- u16 __attribute__ ((packed)) wValue;
- #ifdef _BIG_ENDIAN_ /* 20060927 add by anson's endian */
- struct _RSN_Capability {
- u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */
- u16 __attribute__ ((packed)) Reserved1:2;
- u16 __attribute__ ((packed)) GTK_Replay_Counter:2;
- u16 __attribute__ ((packed)) PTK_Replay_Counter:2;
- u16 __attribute__ ((packed)) No_Pairwise:1;
- u16 __attribute__ ((packed)) Pre_Auth:1;
- } __attribute__ ((packed)) RSN_Capability;
- #else
- struct _RSN_Capability {
- u16 __attribute__ ((packed)) Pre_Auth:1;
- u16 __attribute__ ((packed)) No_Pairwise:1;
- u16 __attribute__ ((packed)) PTK_Replay_Counter:2;
- u16 __attribute__ ((packed)) GTK_Replay_Counter:2;
- u16 __attribute__ ((packed)) Reserved1:2;
- u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */
- } __attribute__ ((packed)) RSN_Capability;
- #endif
-
- } __attribute__ ((packed)) ;
-} __attribute__ ((packed)) ;
-
-#ifdef _WPA2_
-struct pmkid {
- u8 pValue[16];
-};
-
-struct WPA2_RSN_Information_Element {
- u8 Element_ID;
- u8 Length;
- u16 Version;
- struct suite_selector GroupKeySuite;
- u16 PairwiseKeySuiteCount;
- struct suite_selector PairwiseKeySuite[1];
-
-} __attribute__ ((packed));
-
-struct WPA2_RSN_Auth_Sub_Information_Element {
- u16 AuthKeyMngtSuiteCount;
- struct suite_selector AuthKeyMngtSuite[1];
-} __attribute__ ((packed));
-
-
-struct PMKID_Information_Element {
- u16 PMKID_Count;
- struct pmkid pmkid[16];
-} __attribute__ ((packed));
-
-#endif /* enddef _WPA2_ */
-/*============================================================
-// MAC Frame structure (different type) and subfield structure
-//============================================================*/
-struct MAC_frame_control {
-/* a combination of the [Protocol Version, Control Type, Control Subtype]*/
- u8 mac_frame_info;
-/* 20060927 add by anson's endian */
- #ifdef _BIG_ENDIAN_
- u8 order:1;
- u8 WEP:1;
- u8 more_data:1;
- u8 pwr_mgt:1;
- u8 retry:1;
- u8 more_frag:1;
- u8 from_ds:1;
- u8 to_ds:1;
- #else
- u8 to_ds:1;
- u8 from_ds:1;
- u8 more_frag:1;
- u8 retry:1;
- u8 pwr_mgt:1;
- u8 more_data:1;
- u8 WEP:1;
- u8 order:1;
- #endif
-} __attribute__ ((packed));
-
-struct Management_Frame {
-/* 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0 */
- struct MAC_frame_control frame_control;
- u16 duration;
- u8 DA[MAC_ADDR_LENGTH]; /* Addr1 */
- u8 SA[MAC_ADDR_LENGTH]; /* Addr2 */
- u8 BSSID[MAC_ADDR_LENGTH]; /* Addr3 */
- u16 Sequence_Control;
- /* Management Frame Body <= 325 bytes */
- /* FCS 4 bytes */
-} __attribute__ ((packed));
-
-/* SW-MAC don't Tx/Rx Control-Frame, HW-MAC do it. */
-struct Control_Frame {
-/* ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0 */
- struct MAC_frame_control frame_control;
- u16 duration;
- u8 RA[MAC_ADDR_LENGTH];
- u8 TA[MAC_ADDR_LENGTH];
- u16 FCS;
-} __attribute__ ((packed));
-
-struct Data_Frame {
- struct MAC_frame_control frame_control;
- u16 duration;
- u8 Addr1[MAC_ADDR_LENGTH];
- u8 Addr2[MAC_ADDR_LENGTH];
- u8 Addr3[MAC_ADDR_LENGTH];
- u16 Sequence_Control;
- u8 Addr4[MAC_ADDR_LENGTH]; /* only exist when ToDS=FromDS=1 */
- /* Data Frame Body <= 2312 */
- /* FCS */
-} __attribute__ ((packed));
-
-struct Disassociation_Frame_Body {
- u16 reasonCode;
-} __attribute__ ((packed));
-
-struct Association_Request_Frame_Body {
- u16 capability_information;
- u16 listenInterval;
- u8 Current_AP_Address[MAC_ADDR_LENGTH];/* for reassociation only */
- /* SSID (2+32 bytes) */
- /* Supported_Rates (2+8 bytes) */
-} __attribute__ ((packed));
-
-struct Association_Response_Frame_Body {
- u16 capability_information;
- u16 statusCode;
- u16 Association_ID;
- struct Supported_Rates_Element supportedRates;
-} __attribute__ ((packed));
-
-/*struct Reassociation_Request_Frame_Body
-{
- u16 capability_information;
- u16 listenInterval;
- u8 Current_AP_Address[MAC_ADDR_LENGTH];
- // SSID (2+32 bytes)
- // Supported_Rates (2+8 bytes)
-};*/
-/* eliminated by WS 07/22/04 comboined with associateion request frame. */
-
-struct Reassociation_Response_Frame_Body {
- u16 capability_information;
- u16 statusCode;
- u16 Association_ID;
- struct Supported_Rates_Element supportedRates;
-} __attribute__ ((packed));
-
-struct Deauthentication_Frame_Body {
- u16 reasonCode;
-} __attribute__ ((packed));
-
-
-struct Probe_Response_Frame_Body {
- u16 Timestamp;
- u16 Beacon_Interval;
- u16 Capability_Information;
- /* SSID
- // Supported_Rates
- // PHY parameter Set (DS Parameters)
- // CF parameter Set
- // IBSS parameter Set */
-} __attribute__ ((packed));
-
-struct Authentication_Frame_Body {
- u16 algorithmNumber;
- u16 sequenceNumber;
- u16 statusCode;
- /* NB: don't include ChallengeText in this structure
- // struct Challenge_Text_Element sChallengeTextElement;
- // wkchen added */
-} __attribute__ ((packed));
-
-
#endif /* _MAC_Structure_H_ */
-
-
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
index 9217762b1814..9cfea94bcea5 100644
--- a/drivers/staging/winbond/mds.c
+++ b/drivers/staging/winbond/mds.c
@@ -1,9 +1,7 @@
#include "mds_f.h"
-#include "mlmetxrx_f.h"
#include "mto.h"
-#include "sysdef.h"
-#include "wbhal_f.h"
-#include "wblinux_f.h"
+#include "wbhal.h"
+#include "wb35tx_f.h"
unsigned char
Mds_initial(struct wbsoft_priv *adapter)
@@ -17,11 +15,6 @@ Mds_initial(struct wbsoft_priv *adapter)
return hal_get_tx_buffer(&adapter->sHwData, &pMds->pTxBuffer);
}
-void
-Mds_Destroy(struct wbsoft_priv *adapter)
-{
-}
-
static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *buffer)
{
struct T00_descriptor *pT00;
@@ -350,9 +343,7 @@ static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *
ctmp1 = ctmpf = CURRENT_TX_RATE_FOR_MNG;
pDes->TxRate = ctmp1;
- #ifdef _PE_TX_DUMP_
- printk("Tx rate =%x\n", ctmp1);
- #endif
+ pr_debug("Tx rate =%x\n", ctmp1);
pT01->T01_modulation_type = (ctmp1%3) ? 0 : 1;
@@ -404,6 +395,44 @@ static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *
}
+static void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc)
+{
+ desc->InternalUsed = desc->buffer_start_index + desc->buffer_number;
+ desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX;
+ desc->buffer_address[desc->InternalUsed] = adapter->sMlmeFrame.pMMPDU;
+ desc->buffer_size[desc->InternalUsed] = adapter->sMlmeFrame.len;
+ desc->buffer_total_size += adapter->sMlmeFrame.len;
+ desc->buffer_number++;
+ desc->Type = adapter->sMlmeFrame.DataType;
+}
+
+static void MLMEfreeMMPDUBuffer(struct wbsoft_priv *adapter, s8 *pData)
+{
+ int i;
+
+ /* Reclaim the data buffer */
+ for (i = 0; i < MAX_NUM_TX_MMPDU; i++) {
+ if (pData == (s8 *)&(adapter->sMlmeFrame.TxMMPDU[i]))
+ break;
+ }
+ if (adapter->sMlmeFrame.TxMMPDUInUse[i])
+ adapter->sMlmeFrame.TxMMPDUInUse[i] = false;
+ else {
+ /* Something wrong
+ PD43 Add debug code here??? */
+ }
+}
+
+static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK)
+{
+ /* Reclaim the data buffer */
+ adapter->sMlmeFrame.len = 0;
+ MLMEfreeMMPDUBuffer(adapter, adapter->sMlmeFrame.pMMPDU);
+
+ /* Return resource */
+ adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE;
+}
+
void
Mds_Tx(struct wbsoft_priv *adapter)
{
@@ -430,9 +459,7 @@ Mds_Tx(struct wbsoft_priv *adapter)
do {
FillIndex = pMds->TxFillIndex;
if (pMds->TxOwner[FillIndex]) { /* Is owned by software 0:Yes 1:No */
-#ifdef _PE_TX_DUMP_
- printk("[Mds_Tx] Tx Owner is H/W.\n");
-#endif
+ pr_debug("[Mds_Tx] Tx Owner is H/W.\n");
break;
}
@@ -476,9 +503,7 @@ Mds_Tx(struct wbsoft_priv *adapter)
/* For speed up Key setting */
if (pTxDes->EapFix) {
-#ifdef _PE_TX_DUMP_
- printk("35: EPA 4th frame detected. Size = %d\n", PacketSize);
-#endif
+ pr_debug("35: EPA 4th frame detected. Size = %d\n", PacketSize);
pHwData->IsKeyPreSet = 1;
}
@@ -492,11 +517,6 @@ Mds_Tx(struct wbsoft_priv *adapter)
XmitBufSize += CurrentSize;
XmitBufAddress += CurrentSize;
-#ifdef _IBSS_BEACON_SEQ_STICK_
- if ((XmitBufAddress[DOT_11_DA_OFFSET+8] & 0xfc) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) /* +8 for USB hdr */
-#endif
- pMds->TxToggle = true;
-
/* Get packet to transmit completed, 1:TESTSTA 2:MLME 3: Ndis data */
MLME_SendComplete(adapter, 0, true);
@@ -567,9 +587,7 @@ Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pT02)
pHwData->tx_retry_count[RetryCount] += RetryCount;
else
pHwData->tx_retry_count[7] += RetryCount;
- #ifdef _PE_STATE_DUMP_
- printk("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count);
- #endif
+ pr_debug("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count);
MTO_SetTxCount(adapter, TxRate, RetryCount);
}
pHwData->dto_tx_frag_count += (RetryCount+1);
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
index 7f68deae6d04..ce8be079e957 100644
--- a/drivers/staging/winbond/mds_f.h
+++ b/drivers/staging/winbond/mds_f.h
@@ -1,11 +1,10 @@
#ifndef __WINBOND_MDS_F_H
#define __WINBOND_MDS_F_H
-#include "wbhal_s.h"
+#include "wbhal.h"
#include "core.h"
unsigned char Mds_initial(struct wbsoft_priv *adapter);
-void Mds_Destroy(struct wbsoft_priv *adapter);
void Mds_Tx(struct wbsoft_priv *adapter);
void Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pt02);
void Mds_MpduProcess(struct wbsoft_priv *adapter, struct wb35_descriptor *prxdes);
diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h
index e2de4bd23b4d..eeedf0186365 100644
--- a/drivers/staging/winbond/mds_s.h
+++ b/drivers/staging/winbond/mds_s.h
@@ -107,10 +107,6 @@ struct wb35_mds {
u8 TxRate[((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01)][2]; /* [0] current tx rate, [1] fall back rate */
u8 TxInfo[((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01)]; /*Store information for callback function */
- /* for scanning mechanism */
- u8 TxToggle; /* It is TRUE if there are tx activities in some time interval */
- u8 Reserved_[3];
-
/* ---- for Tx Parameter */
u16 TxFragmentThreshold; /* For frame body only */
u16 TxRTSThreshold;
diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c
deleted file mode 100644
index 7425a23f12e8..000000000000
--- a/drivers/staging/winbond/mlmetxrx.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ============================================================================
- Module Name:
- MLMETxRx.C
-
- Description:
- The interface between MDS (MAC Data Service) and MLME.
-
- Revision History:
- --------------------------------------------------------------------------
- 200209 UN20 Jennifer Xu
- Initial Release
- 20021108 PD43 Austin Liu
- 20030117 PD43 Austin Liu
- Deleted MLMEReturnPacket and MLMEProcThread()
-
- Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved.
-============================================================================ */
-#include "sysdef.h"
-
-#include "mds_f.h"
-
-void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc)
-{
- desc->InternalUsed = desc->buffer_start_index + desc->buffer_number;
- desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX;
- desc->buffer_address[desc->InternalUsed] = adapter->sMlmeFrame.pMMPDU;
- desc->buffer_size[desc->InternalUsed] = adapter->sMlmeFrame.len;
- desc->buffer_total_size += adapter->sMlmeFrame.len;
- desc->buffer_number++;
- desc->Type = adapter->sMlmeFrame.DataType;
-}
-
-static void MLMEfreeMMPDUBuffer(struct wbsoft_priv *adapter, s8 *pData)
-{
- int i;
-
- /* Reclaim the data buffer */
- for (i = 0; i < MAX_NUM_TX_MMPDU; i++) {
- if (pData == (s8 *)&(adapter->sMlmeFrame.TxMMPDU[i]))
- break;
- }
- if (adapter->sMlmeFrame.TxMMPDUInUse[i])
- adapter->sMlmeFrame.TxMMPDUInUse[i] = false;
- else {
- /* Something wrong
- PD43 Add debug code here??? */
- }
-}
-
-void
-MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK)
-{
- /* Reclaim the data buffer */
- adapter->sMlmeFrame.len = 0;
- MLMEfreeMMPDUBuffer(adapter, adapter->sMlmeFrame.pMMPDU);
-
- /* Return resource */
- adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE;
-}
-
-
-
diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h
deleted file mode 100644
index 012507fc49e3..000000000000
--- a/drivers/staging/winbond/mlmetxrx_f.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* ================================================================
-// MLMETxRx.H --
-//
-// Functions defined in MLMETxRx.c.
-//
-// Copyright (c) 2002 Winbond Electrics Corp. All Rights Reserved.
-//================================================================ */
-#ifndef _MLMETXRX_H
-#define _MLMETXRX_H
-
-#include "core.h"
-
-void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes);
-
-void
-MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID,
- unsigned char SendOK);
-
-#ifdef _IBSS_BEACON_SEQ_STICK_
-s8 SendBCNullData(struct wbsoft_priv *adapter, u16 wIdx);
-#endif
-
-#endif
diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c
index 9cd212783d61..c03e5010ca34 100644
--- a/drivers/staging/winbond/mto.c
+++ b/drivers/staging/winbond/mto.c
@@ -17,9 +17,10 @@
* ============================================================================
*/
-#include "sysdef.h"
#include "sme_api.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
/* Declare SQ3 to rate and fragmentation threshold table */
/* Declare fragmentation thresholds table */
diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c
index 2b375ba3812a..09844db64fe9 100644
--- a/drivers/staging/winbond/phy_calibration.c
+++ b/drivers/staging/winbond/phy_calibration.c
@@ -10,9 +10,10 @@
*/
/****************** INCLUDE FILES SECTION ***********************************/
-#include "sysdef.h"
#include "phy_calibration.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
/****************** DEBUG CONSTANT AND MACRO SECTION ************************/
diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h
index 303203148839..84f6e840a47a 100644
--- a/drivers/staging/winbond/phy_calibration.h
+++ b/drivers/staging/winbond/phy_calibration.h
@@ -1,7 +1,7 @@
#ifndef __WINBOND_PHY_CALIBRATION_H
#define __WINBOND_PHY_CALIBRATION_H
-#include "wbhal_f.h"
+#include "wbhal.h"
#define REG_AGC_CTRL1 0x1000
#define REG_AGC_CTRL2 0x1004
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
index 990f9d4bdbbd..1b38d6d225c9 100644
--- a/drivers/staging/winbond/reg.c
+++ b/drivers/staging/winbond/reg.c
@@ -1,5 +1,6 @@
-#include "sysdef.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
/*
* ====================================================
@@ -1010,9 +1011,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
case RF_AIROHA_7230:
/* Start to fill RF parameters, PLL_ON should be pulled low. */
Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000000);
- #ifdef _PE_STATE_DUMP_
- printk("* PLL_ON low\n");
- #endif
+ pr_debug("* PLL_ON low\n");
number = ARRAY_SIZE(al7230_rf_data_24);
Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number);
break;
@@ -1098,9 +1097,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
case RF_AIROHA_7230:
/* RF parameters have filled completely, PLL_ON should be pulled high */
Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000080);
- #ifdef _PE_STATE_DUMP_
- printk("* PLL_ON high\n");
- #endif
+ pr_debug("* PLL_ON high\n");
/* 2.4GHz */
ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F;
@@ -1115,9 +1112,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
/* 5GHz */
Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000000);
- #ifdef _PE_STATE_DUMP_
- printk("* PLL_ON low\n");
- #endif
+ pr_debug("* PLL_ON low\n");
number = ARRAY_SIZE(al7230_rf_data_50);
Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number);
@@ -1127,9 +1122,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
msleep(5);
Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000080);
- #ifdef _PE_STATE_DUMP_
- printk("* PLL_ON high\n");
- #endif
+ pr_debug("* PLL_ON high\n");
ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F;
Wb35Reg_WriteSync(pHwData, 0x0864, ltmp);
@@ -1795,9 +1788,7 @@ void RFSynthesizer_SwitchingChannel(struct hw_data *pHwData, struct chan_info C
/* Write to register. number must less and equal than 16 */
Wb35Reg_BurstWrite(pHwData, 0x0864, pltmp, number, NO_INCREMENT);
- #ifdef _PE_STATE_DUMP_
- printk("Band changed\n");
- #endif
+ pr_debug("Band changed\n");
}
if (Channel.band <= BAND_TYPE_OFDM_24) { /* channel 1 ~ 14 */
@@ -2073,11 +2064,7 @@ void Mxx_initial(struct hw_data *pHwData)
*/
/* M00 bit set */
- #ifdef _IBSS_BEACON_SEQ_STICK_
- reg->M00_MacControl = 0; /* Solve beacon sequence number stop by software */
- #else
reg->M00_MacControl = 0x80000000; /* Solve beacon sequence number stop by hardware */
- #endif
/* M24 disable enter power save, BB RxOn and enable NAV attack */
reg->M24_MacControl = 0x08040042;
@@ -2336,13 +2323,6 @@ void EEPROMTxVgaAdjust(struct hw_data *pHwData)
pHwData->TxVgaFor50[32].TxVgaValue = pTxVga[17] - stmp * 2 / 4;
pHwData->TxVgaFor50[31].TxVgaValue = pTxVga[17] - stmp * 3 / 4;
}
-
- #ifdef _PE_STATE_DUMP_
- printk(" TxVgaFor24 :\n");
- DataDmp((u8 *)pHwData->TxVgaFor24, 14 , 0);
- printk(" TxVgaFor50 :\n");
- DataDmp((u8 *)pHwData->TxVgaFor50, 70 , 0);
- #endif
}
void BBProcessor_RateChanging(struct hw_data *pHwData, u8 rate)
diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h
deleted file mode 100644
index 9195adf98e14..000000000000
--- a/drivers/staging/winbond/sysdef.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Winbond WLAN System Configuration defines */
-
-#ifndef SYS_DEF_H
-#define SYS_DEF_H
-#define WB_LINUX
-#define WB_LINUX_WPA_PSK
-
-#define _USE_FALLBACK_RATE_
-
-#define _WPA2_
-
-#ifndef _WPA_PSK_DEBUG
-#undef _WPA_PSK_DEBUG
-#endif
-
-/* debug print options, mark what debug you don't need */
-
-#ifdef FULL_DEBUG
-#define _PE_STATE_DUMP_
-#define _PE_TX_DUMP_
-#define _PE_RX_DUMP_
-#define _PE_OID_DUMP_
-#define _PE_DTO_DUMP_
-#define _PE_REG_DUMP_
-#define _PE_USB_INI_DUMP_
-#endif
-
-#endif
diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c
index 770722385eeb..42ae61014522 100644
--- a/drivers/staging/winbond/wb35reg.c
+++ b/drivers/staging/winbond/wb35reg.c
@@ -1,4 +1,3 @@
-#include "sysdef.h"
#include "wb35reg_f.h"
#include <linux/usb.h>
@@ -140,8 +139,8 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg
/* Sync IoCallDriver */
reg->EP0vm_state = VM_RUNNING;
- ret = usb_control_msg(pHwData->WbUsb.udev,
- usb_sndctrlpipe(pHwData->WbUsb.udev, 0),
+ ret = usb_control_msg(pHwData->udev,
+ usb_sndctrlpipe(pHwData->udev, 0),
0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
0x0, RegisterNo, &RegisterValue, 4, HZ * 100);
reg->EP0vm_state = VM_STOP;
@@ -150,9 +149,7 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg
Wb35Reg_EP0VM_start(pHwData);
if (ret < 0) {
-#ifdef _PE_REG_DUMP_
- printk("EP0 Write register usb message sending error\n");
-#endif
+ pr_debug("EP0 Write register usb message sending error\n");
pHwData->SurpriseRemove = 1;
return false;
}
@@ -305,8 +302,8 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe
msleep(10);
reg->EP0vm_state = VM_RUNNING;
- ret = usb_control_msg(pHwData->WbUsb.udev,
- usb_rcvctrlpipe(pHwData->WbUsb.udev, 0),
+ ret = usb_control_msg(pHwData->udev,
+ usb_rcvctrlpipe(pHwData->udev, 0),
0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x0, RegisterNo, pltmp, 4, HZ * 100);
@@ -320,9 +317,7 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe
Wb35Reg_EP0VM_start(pHwData);
if (ret < 0) {
-#ifdef _PE_REG_DUMP_
- printk("EP0 Read register usb message sending error\n");
-#endif
+ pr_debug("EP0 Read register usb message sending error\n");
pHwData->SurpriseRemove = 1;
return false;
}
@@ -432,8 +427,8 @@ void Wb35Reg_EP0VM(struct hw_data *pHwData)
if (reg_queue->DIRECT == 1) /* output */
pBuffer = &reg_queue->VALUE;
- usb_fill_control_urb(urb, pHwData->WbUsb.udev,
- REG_DIRECTION(pHwData->WbUsb.udev, reg_queue),
+ usb_fill_control_urb(urb, pHwData->udev,
+ REG_DIRECTION(pHwData->udev, reg_queue),
(u8 *)dr, pBuffer, cpu_to_le16(dr->wLength),
Wb35Reg_EP0VM_complete, (void *)pHwData);
@@ -442,9 +437,7 @@ void Wb35Reg_EP0VM(struct hw_data *pHwData)
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
-#ifdef _PE_REG_DUMP_
- printk("EP0 Irp sending error\n");
-#endif
+ pr_debug("EP0 Irp sending error\n");
goto cleanup;
}
return;
@@ -479,9 +472,7 @@ void Wb35Reg_EP0VM_complete(struct urb *urb)
spin_unlock_irq(&reg->EP0VM_spin_lock);
if (reg->EP0VM_status) {
-#ifdef _PE_REG_DUMP_
- printk("EP0 IoCompleteRoutine return error\n");
-#endif
+ pr_debug("EP0 IoCompleteRoutine return error\n");
reg->EP0vm_state = VM_STOP;
pHwData->SurpriseRemove = 1;
} else {
@@ -526,9 +517,7 @@ void Wb35Reg_destroy(struct hw_data *pHwData)
usb_free_urb(urb);
kfree(reg_queue);
} else {
-#ifdef _PE_REG_DUMP_
- printk("EP0 queue release error\n");
-#endif
+ pr_debug("EP0 queue release error\n");
}
spin_lock_irq(&reg->EP0VM_spin_lock);
diff --git a/drivers/staging/winbond/wb35reg_f.h b/drivers/staging/winbond/wb35reg_f.h
index bf23c1084199..95dc98096845 100644
--- a/drivers/staging/winbond/wb35reg_f.h
+++ b/drivers/staging/winbond/wb35reg_f.h
@@ -1,7 +1,7 @@
#ifndef __WINBOND_WB35REG_F_H
#define __WINBOND_WB35REG_F_H
-#include "wbhal_s.h"
+#include "wbhal.h"
/*
* ====================================
diff --git a/drivers/staging/winbond/wb35reg_s.h b/drivers/staging/winbond/wb35reg_s.h
index 4eff009444b8..eb274ffdd1ba 100644
--- a/drivers/staging/winbond/wb35reg_s.h
+++ b/drivers/staging/winbond/wb35reg_s.h
@@ -5,6 +5,8 @@
#include <linux/types.h>
#include <asm/atomic.h>
+struct hw_data;
+
/* =========================================================================
*
* HAL setting function
@@ -49,11 +51,7 @@
#define DEFAULT_CWMAX 1023 /* (M2C) CWmax. Its value is in the range 0-1023. */
#define DEFAULT_AID 1 /* (M34) AID. Its value is in the range 1-2007. */
-#ifdef _USE_FALLBACK_RATE_
#define DEFAULT_RATE_RETRY_LIMIT 2 /* (M38) as named */
-#else
-#define DEFAULT_RATE_RETRY_LIMIT 7 /* (M38) as named */
-#endif
#define DEFAULT_LONG_RETRY_LIMIT 7 /* (M38) LongRetryLimit. Its value is in the range 0-15. */
#define DEFAULT_SHORT_RETRY_LIMIT 7 /* (M38) ShortRetryLimit. Its value is in the range 0-15. */
@@ -168,4 +166,75 @@ struct wb35_reg {
u32 SQ3_filter[MAX_SQ3_FILTER_SIZE];
u32 SQ3_index;
};
+
+/* =====================================================================
+ * Function declaration
+ * =====================================================================
+ */
+void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr);
+void hal_remove_default_key(struct hw_data *hw_data, u32 index);
+unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr,
+ u8 null_key, u8 wep_on, u8 *tx_tsc,
+ u8 *rx_tsc, u8 key_type, u8 key_len,
+ u8 *key_data);
+unsigned char hal_set_default_key(struct hw_data *adapter, u8 index,
+ u8 null_key, u8 wep_on, u8 *tx_tsc,
+ u8 *rx_tsc, u8 key_type, u8 key_len,
+ u8 *key_data);
+void hal_clear_all_default_key(struct hw_data *hw_data);
+void hal_clear_all_group_key(struct hw_data *hw_data);
+void hal_clear_all_mapping_key(struct hw_data *hw_data);
+void hal_clear_all_key(struct hw_data *hw_data);
+void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save,
+ unsigned char wakeup, unsigned char dtim);
+void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save);
+void hal_set_slot_time(struct hw_data *hw_data, u8 type);
+
+#define hal_set_atim_window(_A, _ATM)
+
+void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode);
+
+/* 0:BSS STA 1:IBSS STA */
+void hal_join_request(struct hw_data *hw_data, u8 bss_type);
+
+void hal_stop_sync_bss(struct hw_data *hw_data);
+void hal_resume_sync_bss(struct hw_data *hw_data);
+void hal_set_aid(struct hw_data *hw_data, u16 aid);
+void hal_set_bssid(struct hw_data *hw_data, u8 *bssid);
+void hal_get_bssid(struct hw_data *hw_data, u8 *bssid);
+void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval);
+void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info);
+void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len);
+void hal_start_tx0(struct hw_data *hw_data);
+
+#define hal_get_cwmin(_A) ((_A)->cwmin)
+
+void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max);
+
+#define hal_get_cwmax(_A) ((_A)->cwmax)
+
+void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap,
+ u32 *rsn_oui_type , unsigned char desired_auth_mode);
+void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect);
+u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count);
+void hal_descriptor_indicate(struct hw_data *hw_data,
+ struct wb35_descriptor *des);
+u8 hal_get_antenna_number(struct hw_data *hw_data);
+u32 hal_get_bss_pk_cnt(struct hw_data *hw_data);
+
+#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion)
+#define hal_get_tx_buffer(_A, _B) Wb35Tx_get_tx_buffer(_A, _B)
+#define hal_software_set(_A) (_A->SoftwareSet)
+#define hal_driver_init_OK(_A) (_A->IsInitOK)
+#define hal_rssi_boundary_high(_A) (_A->RSSI_high)
+#define hal_rssi_boundary_low(_A) (_A->RSSI_low)
+#define hal_scan_interval(_A) (_A->Scan_Interval)
+
+#define PHY_DEBUG(msg, args...)
+
+/* return 100ms count */
+#define hal_get_time_count(_P) (_P->time_count / 10)
+
+#define hal_ibss_disconnect(_A) (hal_stop_sync_bss(_A))
+
#endif
diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c
index 448514aada44..f118eeba396a 100644
--- a/drivers/staging/winbond/wb35rx.c
+++ b/drivers/staging/winbond/wb35rx.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include "core.h"
-#include "sysdef.h"
#include "wb35rx_f.h"
static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize)
@@ -109,10 +108,7 @@ static u16 Wb35Rx_indicate(struct ieee80211_hw *hw)
/* Basic check for Rx length. Is length valid? */
if (PacketSize > MAX_PACKET_SIZE) {
-#ifdef _PE_RX_DUMP_
- printk("Serious ERROR : Rx data size too long, size =%d\n", PacketSize);
-#endif
-
+ pr_debug("Serious ERROR : Rx data size too long, size =%d\n", PacketSize);
pWb35Rx->EP3vm_state = VM_STOP;
pWb35Rx->Ep3ErrorCount2++;
break;
@@ -174,7 +170,7 @@ static void Wb35Rx_Complete(struct urb *urb)
/* The IRP is completed */
pWb35Rx->EP3vm_state = VM_COMPLETED;
- if (pHwData->SurpriseRemove || pHwData->HwStop) /* Must be here, or RxBufferId is invalid */
+ if (pHwData->SurpriseRemove) /* Must be here, or RxBufferId is invalid */
goto error;
if (pWb35Rx->rx_halt)
@@ -186,9 +182,7 @@ static void Wb35Rx_Complete(struct urb *urb)
/* The URB is completed, check the result */
if (pWb35Rx->EP3VM_status != 0) {
-#ifdef _PE_USB_STATE_DUMP_
- printk("EP3 IoCompleteRoutine return error\n");
-#endif
+ pr_debug("EP3 IoCompleteRoutine return error\n");
pWb35Rx->EP3vm_state = VM_STOP;
goto error;
}
@@ -239,7 +233,7 @@ static void Wb35Rx(struct ieee80211_hw *hw)
u32 RxBufferId;
/* Issuing URB */
- if (pHwData->SurpriseRemove || pHwData->HwStop)
+ if (pHwData->SurpriseRemove)
goto error;
if (pWb35Rx->rx_halt)
@@ -249,9 +243,7 @@ static void Wb35Rx(struct ieee80211_hw *hw)
RxBufferId = pWb35Rx->RxBufferId;
if (!pWb35Rx->RxOwner[RxBufferId]) {
/* It's impossible to run here. */
-#ifdef _PE_RX_DUMP_
- printk("Rx driver fifo unavailable\n");
-#endif
+ pr_debug("Rx driver fifo unavailable\n");
goto error;
}
@@ -268,8 +260,8 @@ static void Wb35Rx(struct ieee80211_hw *hw)
}
pRxBufferAddress = pWb35Rx->pDRx;
- usb_fill_bulk_urb(urb, pHwData->WbUsb.udev,
- usb_rcvbulkpipe(pHwData->WbUsb.udev, 3),
+ usb_fill_bulk_urb(urb, pHwData->udev,
+ usb_rcvbulkpipe(pHwData->udev, 3),
pRxBufferAddress, MAX_USB_RX_BUFFER,
Wb35Rx_Complete, hw);
@@ -337,9 +329,7 @@ void Wb35Rx_stop(struct hw_data *pHwData)
/* Canceling the Irp if already sends it out. */
if (pWb35Rx->EP3vm_state == VM_RUNNING) {
usb_unlink_urb(pWb35Rx->RxUrb); /* Only use unlink, let Wb35Rx_destroy to free them */
-#ifdef _PE_RX_DUMP_
- printk("EP3 Rx stop\n");
-#endif
+ pr_debug("EP3 Rx stop\n");
}
}
@@ -355,8 +345,6 @@ void Wb35Rx_destroy(struct hw_data *pHwData)
if (pWb35Rx->RxUrb)
usb_free_urb(pWb35Rx->RxUrb);
-#ifdef _PE_RX_DUMP_
- printk("Wb35Rx_destroy OK\n");
-#endif
+ pr_debug("Wb35Rx_destroy OK\n");
}
diff --git a/drivers/staging/winbond/wb35rx_f.h b/drivers/staging/winbond/wb35rx_f.h
index 98acce517d90..1fdf65ea6041 100644
--- a/drivers/staging/winbond/wb35rx_f.h
+++ b/drivers/staging/winbond/wb35rx_f.h
@@ -2,7 +2,7 @@
#define __WINBOND_WB35RX_F_H
#include <net/mac80211.h>
-#include "wbhal_s.h"
+#include "wbhal.h"
//====================================
// Interface function declare
diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c
index 2a9d05557678..44fc3fe79b79 100644
--- a/drivers/staging/winbond/wb35tx.c
+++ b/drivers/staging/winbond/wb35tx.c
@@ -13,7 +13,6 @@
#include "wb35tx_f.h"
#include "mds_f.h"
-#include "sysdef.h"
unsigned char
Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer)
@@ -41,7 +40,7 @@ static void Wb35Tx_complete(struct urb * pUrb)
pWb35Tx->TxSendIndex++;
pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
- if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
goto error;
if (pWb35Tx->tx_halt)
@@ -74,7 +73,7 @@ static void Wb35Tx(struct wbsoft_priv *adapter)
u32 SendIndex;
- if (pHwData->SurpriseRemove || pHwData->HwStop)
+ if (pHwData->SurpriseRemove)
goto cleanup;
if (pWb35Tx->tx_halt)
@@ -89,8 +88,8 @@ static void Wb35Tx(struct wbsoft_priv *adapter)
//
// Issuing URB
//
- usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
- usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
+ usb_fill_bulk_urb(pUrb, pHwData->udev,
+ usb_sndbulkpipe(pHwData->udev, 4),
pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
Wb35Tx_complete, adapter);
@@ -153,16 +152,12 @@ void Wb35Tx_stop(struct hw_data * pHwData)
// Trying to canceling the Trp of EP2
if (pWb35Tx->EP2vm_state == VM_RUNNING)
usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
- #ifdef _PE_TX_DUMP_
- printk("EP2 Tx stop\n");
- #endif
+ pr_debug("EP2 Tx stop\n");
// Trying to canceling the Irp of EP4
if (pWb35Tx->EP4vm_state == VM_RUNNING)
usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
- #ifdef _PE_TX_DUMP_
- printk("EP4 Tx stop\n");
- #endif
+ pr_debug("EP4 Tx stop\n");
}
//======================================================
@@ -182,9 +177,7 @@ void Wb35Tx_destroy(struct hw_data * pHwData)
if (pWb35Tx->Tx2Urb)
usb_free_urb( pWb35Tx->Tx2Urb );
- #ifdef _PE_TX_DUMP_
- printk("Wb35Tx_destroy OK\n");
- #endif
+ pr_debug("Wb35Tx_destroy OK\n");
}
void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
@@ -222,7 +215,7 @@ static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
pWb35Tx->EP2VM_status = pUrb->status;
// For Linux 2.4. Interrupt will always trigger
- if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
goto error;
if (pWb35Tx->tx_halt)
@@ -263,7 +256,7 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
int retv;
- if (pHwData->SurpriseRemove || pHwData->HwStop)
+ if (pHwData->SurpriseRemove)
goto error;
if (pWb35Tx->tx_halt)
@@ -272,16 +265,14 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
//
// Issuing URB
//
- usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
+ usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2),
pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32);
pWb35Tx->EP2vm_state = VM_RUNNING;
retv = usb_submit_urb(pUrb, GFP_ATOMIC);
if (retv < 0) {
- #ifdef _PE_TX_DUMP_
- printk("EP2 Tx Irp sending error\n");
- #endif
+ pr_debug("EP2 Tx Irp sending error\n");
goto error;
}
diff --git a/drivers/staging/winbond/wb35tx_f.h b/drivers/staging/winbond/wb35tx_f.h
index 1d3b515f83bc..018fd35e815d 100644
--- a/drivers/staging/winbond/wb35tx_f.h
+++ b/drivers/staging/winbond/wb35tx_f.h
@@ -2,7 +2,6 @@
#define __WINBOND_WB35TX_F_H
#include "core.h"
-#include "wbhal_f.h"
/*
* ====================================
diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal.h
index 821a1b3f1301..39e84a0d9729 100644
--- a/drivers/staging/winbond/wbhal_s.h
+++ b/drivers/staging/winbond/wbhal.h
@@ -342,9 +342,6 @@ struct wb35_descriptor { /* Skip length = 8 DWORD */
void *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX];
};
-
-#define DEFAULT_NULL_PACKET_COUNT 180000 /* 180 seconds */
-
#define MAX_TXVGA_EEPROM 9 /* How many word(u16) of EEPROM will be used for TxVGA */
#define MAX_RF_PARAMETER 32
@@ -359,7 +356,6 @@ struct txvga_for_50 {
* ==============================================
*/
-#include "wbusb_s.h"
#include "wb35reg_s.h"
#include "wb35tx_s.h"
#include "wb35rx_s.h"
@@ -440,7 +436,7 @@ struct hw_data {
* Variable for each module
* ==================================================
*/
- struct wb_usb WbUsb; /* Need WbUsb.h */
+ struct usb_device *udev;
struct wb35_reg reg; /* Need Wb35Reg.h */
struct wb35_tx Wb35Tx; /* Need Wb35Tx.h */
struct wb35_rx Wb35Rx; /* Need Wb35Rx.h */
@@ -510,16 +506,8 @@ struct hw_data {
u32 RxByteCountLast;
u32 TxByteCountLast;
- atomic_t SurpriseRemoveCount;
-
/* For global timer */
u32 time_count; /* TICK_TIME_100ms 1 = 100ms */
-
- /* For error recover */
- u32 HwStop;
-
- /* For avoid AP disconnect */
- u32 NullPacketCount;
};
#endif
diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h
deleted file mode 100644
index fc78c14ae583..000000000000
--- a/drivers/staging/winbond/wbhal_f.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * =====================================================================
- * Device related include
- * =====================================================================
-*/
-#include "wb35reg_f.h"
-#include "wb35tx_f.h"
-#include "wb35rx_f.h"
-
-#include "core.h"
-
-/* =====================================================================
- * Function declaration
- * =====================================================================
- */
-void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr);
-void hal_remove_default_key(struct hw_data *hw_data, u32 index);
-unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr,
- u8 null_key, u8 wep_on, u8 *tx_tsc,
- u8 *rx_tsc, u8 key_type, u8 key_len,
- u8 *key_data);
-unsigned char hal_set_default_key(struct hw_data *adapter, u8 index,
- u8 null_key, u8 wep_on, u8 *tx_tsc,
- u8 *rx_tsc, u8 key_type, u8 key_len,
- u8 *key_data);
-void hal_clear_all_default_key(struct hw_data *hw_data);
-void hal_clear_all_group_key(struct hw_data *hw_data);
-void hal_clear_all_mapping_key(struct hw_data *hw_data);
-void hal_clear_all_key(struct hw_data *hw_data);
-void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save,
- unsigned char wakeup, unsigned char dtim);
-void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save);
-void hal_set_slot_time(struct hw_data *hw_data, u8 type);
-
-#define hal_set_atim_window(_A, _ATM)
-
-void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode);
-
-/* 0:BSS STA 1:IBSS STA */
-void hal_join_request(struct hw_data *hw_data, u8 bss_type);
-
-void hal_stop_sync_bss(struct hw_data *hw_data);
-void hal_resume_sync_bss(struct hw_data *hw_data);
-void hal_set_aid(struct hw_data *hw_data, u16 aid);
-void hal_set_bssid(struct hw_data *hw_data, u8 *bssid);
-void hal_get_bssid(struct hw_data *hw_data, u8 *bssid);
-void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval);
-void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info);
-void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len);
-void hal_start_tx0(struct hw_data *hw_data);
-
-#define hal_get_cwmin(_A) ((_A)->cwmin)
-
-void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max);
-
-#define hal_get_cwmax(_A) ((_A)->cwmax)
-
-void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap,
- u32 *rsn_oui_type , unsigned char desired_auth_mode);
-void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect);
-u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count);
-void hal_descriptor_indicate(struct hw_data *hw_data,
- struct wb35_descriptor *des);
-u8 hal_get_antenna_number(struct hw_data *hw_data);
-u32 hal_get_bss_pk_cnt(struct hw_data *hw_data);
-
-#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion)
-#define hal_get_tx_buffer(_A, _B) Wb35Tx_get_tx_buffer(_A, _B)
-#define hal_software_set(_A) (_A->SoftwareSet)
-#define hal_driver_init_OK(_A) (_A->IsInitOK)
-#define hal_rssi_boundary_high(_A) (_A->RSSI_high)
-#define hal_rssi_boundary_low(_A) (_A->RSSI_low)
-#define hal_scan_interval(_A) (_A->Scan_Interval)
-
-#define PHY_DEBUG(msg, args...)
-
-/* return 100ms count */
-#define hal_get_time_count(_P) (_P->time_count / 10)
-#define hal_detect_error(_P) (_P->WbUsb.DetectCount)
-
-#define hal_ibss_disconnect(_A) (hal_stop_sync_bss(_A))
diff --git a/drivers/staging/winbond/wblinux_f.h b/drivers/staging/winbond/wblinux_f.h
deleted file mode 100644
index 0a9d214f7187..000000000000
--- a/drivers/staging/winbond/wblinux_f.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __WBLINUX_F_H
-#define __WBLINUX_F_H
-
-#include "core.h"
-#include "mds_s.h"
-
-/*
- * ====================================================================
- * Copyright (c) 1996-2004 Winbond Electronic Corporation
- *
- * wblinux_f.h
- * ====================================================================
- */
-int wb35_start_xmit(struct sk_buff *skb, struct net_device *netdev);
-void wb35_set_multicast(struct net_device *netdev);
-struct net_device_stats *wb35_netdev_stats(struct net_device *netdev);
-#endif
diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c
index 3f60cf7e6ec1..2163d60c2eaf 100644
--- a/drivers/staging/winbond/wbusb.c
+++ b/drivers/staging/winbond/wbusb.c
@@ -14,10 +14,11 @@
#include "core.h"
#include "mds_f.h"
-#include "mlmetxrx_f.h"
#include "mto.h"
-#include "wbhal_f.h"
-#include "wblinux_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "wb35tx_f.h"
+#include "wb35rx_f.h"
MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
MODULE_LICENSE("GPL");
@@ -181,10 +182,7 @@ static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info
RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */
pHwData->Channel = channel.ChanNo;
pHwData->band = channel.band;
-#ifdef _PE_STATE_DUMP_
- printk("Set channel is %d, band =%d\n", pHwData->Channel,
- pHwData->band);
-#endif
+ pr_debug("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band);
reg->M28_MacControl &= ~0xff; /* Clean channel information field */
reg->M28_MacControl |= channel.ChanNo;
Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
@@ -339,10 +337,8 @@ static void hal_stop(struct hw_data *pHwData)
static unsigned char hal_idle(struct hw_data *pHwData)
{
struct wb35_reg *reg = &pHwData->reg;
- struct wb_usb *pWbUsb = &pHwData->WbUsb;
- if (!pHwData->SurpriseRemove
- && (pWbUsb->DetectCount || reg->EP0vm_state != VM_STOP))
+ if (!pHwData->SurpriseRemove && reg->EP0vm_state != VM_STOP)
return false;
return true;
@@ -608,15 +604,6 @@ static void hal_led_control(unsigned long data)
}
break;
}
-
- /* Active send null packet to avoid AP disconnect */
- if (pHwData->LED_LinkOn) {
- pHwData->NullPacketCount += TimeInterval;
- if (pHwData->NullPacketCount >=
- DEFAULT_NULL_PACKET_COUNT) {
- pHwData->NullPacketCount = 0;
- }
- }
}
pHwData->time_count += TimeInterval;
@@ -651,13 +638,6 @@ static int hal_init_hardware(struct ieee80211_hw *hw)
SoftwareSet = hal_software_set(pHwData);
-#ifdef Vendor2
- /* Try to make sure the EEPROM contain */
- SoftwareSet >>= 8;
- if (SoftwareSet != 0x82)
- return false;
-#endif
-
Wb35Rx_start(hw);
Wb35Tx_EP2VM_start(priv);
@@ -734,9 +714,7 @@ static int wb35_hw_init(struct ieee80211_hw *hw)
}
priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
-#ifdef _PE_STATE_DUMP_
- printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo);
-#endif
+ pr_debug("Driver init, antenna no = %d\n", priv->sLocalPara.bAntennaNo);
hal_get_hw_radio_off(pHwData);
/* Waiting for HAL setting OK */
@@ -769,7 +747,6 @@ static int wb35_probe(struct usb_interface *intf,
struct usb_host_interface *interface;
struct ieee80211_hw *dev;
struct wbsoft_priv *priv;
- struct wb_usb *pWbUsb;
int nr, err;
u32 ltmp;
@@ -800,16 +777,13 @@ static int wb35_probe(struct usb_interface *intf,
priv = dev->priv;
- pWbUsb = &priv->sHwData.WbUsb;
- pWbUsb->udev = udev;
+ priv->sHwData.udev = udev;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
- if (endpoint[2].wMaxPacketSize == 512) {
+ if (endpoint[2].wMaxPacketSize == 512)
printk("[w35und] Working on USB 2.0\n");
- pWbUsb->IsUsb20 = 1;
- }
err = wb35_hw_init(dev);
if (err)
@@ -860,13 +834,9 @@ static void hal_halt(struct hw_data *pHwData)
static void wb35_hw_halt(struct wbsoft_priv *adapter)
{
- Mds_Destroy(adapter);
-
/* Turn off Rx and Tx hardware ability */
hal_stop(&adapter->sHwData);
-#ifdef _PE_USB_INI_DUMP_
- printk("[w35und] Hal_stop O.K.\n");
-#endif
+ pr_debug("[w35und] Hal_stop O.K.\n");
/* Waiting Irp completed */
msleep(100);
diff --git a/drivers/staging/winbond/wbusb_s.h b/drivers/staging/winbond/wbusb_s.h
deleted file mode 100644
index 8961ae594c4e..000000000000
--- a/drivers/staging/winbond/wbusb_s.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* =========================================================
- * Copyright (c) 1996-2004 Winbond Electronic Corporation
- *
- * Module Name:
- * wbusb_s.h
- * =========================================================
- */
-#ifndef __WINBOND_WBUSB_S_H
-#define __WINBOND_WBUSB_S_H
-
-#include <linux/types.h>
-
-struct wb_usb {
- u32 IsUsb20;
- struct usb_device *udev;
- u32 DetectCount;
-};
-#endif
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 020b17adee2d..28ae9dd1b44e 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -458,7 +458,7 @@ void __devexit wl_pci_remove(struct pci_dev *pdev)
return;
}
- dev = (struct net_device *)pci_get_drvdata( pdev );
+ dev = pci_get_drvdata( pdev );
if( dev == NULL ) {
DBG_ERROR( DbgInfo, "Could not retrieve net_device structure\n" );
return;
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index 7a1337db7aa1..a459e48c7bf0 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -248,7 +248,7 @@ void parse_config(struct net_device *dev)
} else {
DBG_TRACE(DbgInfo, "F/W image file found\n");
#define DHF_ALLOC_SIZE 96000 /* just below 96K, let's hope it suffices for now and for the future */
- cp = (char *)vmalloc(DHF_ALLOC_SIZE);
+ cp = vmalloc(DHF_ALLOC_SIZE);
if (cp == NULL) {
DBG_ERROR(DbgInfo, "error in vmalloc\n");
} else {
diff --git a/drivers/staging/wlags49_h2/wl_sysfs.c b/drivers/staging/wlags49_h2/wl_sysfs.c
index e4c8804ac37d..9b833b30ae62 100644
--- a/drivers/staging/wlags49_h2/wl_sysfs.c
+++ b/drivers/staging/wlags49_h2/wl_sysfs.c
@@ -42,7 +42,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
CFG_HERMES_TALLIES_STRCT tallies;
ssize_t ret = -EINVAL;
- read_lock(&dev_base_lock);
+ rcu_read_lock();
if (dev_isalive(dev)) {
wl_lock(lp, &flags);
@@ -102,7 +102,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
}
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
return ret;
}
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 4af83d5318f2..6a71f52c59b1 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -139,7 +139,7 @@ exit:
}
int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_index, const u8 *mac_addr,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
wlandevice_t *wlandev = dev->ml_priv;
@@ -198,7 +198,7 @@ exit:
}
int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_index, const u8 *mac_addr, void *cookie,
+ u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*))
{
wlandevice_t *wlandev = dev->ml_priv;
@@ -227,7 +227,7 @@ int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
}
int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_index, const u8 *mac_addr)
+ u8 key_index, bool pairwise, const u8 *mac_addr)
{
wlandevice_t *wlandev = dev->ml_priv;
u32 did;
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 83879f9a0b7d..146f3651b6f2 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -148,7 +148,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* tack on SNAP */
e_snap =
- (struct wlan_snap *) skb_push(skb, sizeof(struct wlan_snap));
+ (struct wlan_snap *) skb_push(skb,
+ sizeof(struct wlan_snap));
e_snap->type = htons(proto);
if (ethconv == WLAN_ETHCONV_8021h
&& p80211_stt_findproto(proto)) {
@@ -161,7 +162,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* tack on llc */
e_llc =
- (struct wlan_llc *) skb_push(skb, sizeof(struct wlan_llc));
+ (struct wlan_llc *) skb_push(skb,
+ sizeof(struct wlan_llc));
e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
e_llc->ssap = 0xAA;
e_llc->ctl = 0x03;
@@ -297,10 +299,12 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
- } else if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1)) {
+ } else if ((WLAN_GET_FC_TODS(fc) == 0)
+ && (WLAN_GET_FC_FROMDS(fc) == 1)) {
memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
- } else if ((WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
+ } else if ((WLAN_GET_FC_TODS(fc) == 1)
+ && (WLAN_GET_FC_FROMDS(fc) == 0)) {
memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
} else {
@@ -349,7 +353,8 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
e_llc = (struct wlan_llc *) (skb->data + payload_offset);
e_snap =
- (struct wlan_snap *) (skb->data + payload_offset + sizeof(struct wlan_llc));
+ (struct wlan_snap *) (skb->data + payload_offset +
+ sizeof(struct wlan_llc));
/* Test for the various encodings */
if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
@@ -372,9 +377,11 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
/* chop off the 802.11 CRC */
skb_trim(skb, skb->len - WLAN_CRC_LEN);
- } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap))
- && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa)
- && (e_llc->ctl == 0x03)
+ } else if ((payload_length >= sizeof(struct wlan_llc) +
+ sizeof(struct wlan_snap))
+ &&(e_llc->dsap == 0xaa)
+ && (e_llc->ssap == 0xaa)
+ && (e_llc->ctl == 0x03)
&&
(((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0)
&& (ethconv == WLAN_ETHCONV_8021h)
@@ -406,21 +413,25 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
/* chop off the 802.11 CRC */
skb_trim(skb, skb->len - WLAN_CRC_LEN);
- } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap))
- && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa)
- && (e_llc->ctl == 0x03)) {
+ } else if ((payload_length >= sizeof(struct wlan_llc) +
+ sizeof(struct wlan_snap))
+ &&(e_llc->dsap == 0xaa)
+ && (e_llc->ssap == 0xaa)
+ && (e_llc->ctl == 0x03)) {
pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
- /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */
- /* build a DIXII + RFC894 */
+ /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
+ build a DIXII + RFC894 */
/* Test for an overlength frame */
- if ((payload_length - sizeof(struct wlan_llc) - sizeof(struct wlan_snap))
- > netdev->mtu) {
+ if ((payload_length - sizeof(struct wlan_llc) -
+ sizeof(struct wlan_snap))
+ > netdev->mtu) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
printk(KERN_ERR "DIXII frame too large (%ld > %d)\n",
- (long int)(payload_length - sizeof(struct wlan_llc) -
- sizeof(struct wlan_snap)), netdev->mtu);
+ (long int)(payload_length -
+ sizeof(struct wlan_llc) -
+ sizeof(struct wlan_snap)), netdev->mtu);
return 1;
}
diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h
index eca0391c676f..ea493aa74f00 100644
--- a/drivers/staging/wlan-ng/p80211conv.h
+++ b/drivers/staging/wlan-ng/p80211conv.h
@@ -66,12 +66,14 @@
#define P80211_FRMMETA_MAGIC 0x802110
#define P80211SKB_FRMMETA(s) \
- (((((struct p80211_frmmeta *)((s)->cb))->magic) == P80211_FRMMETA_MAGIC) ? \
+ (((((struct p80211_frmmeta *)((s)->cb))->magic) == \
+ P80211_FRMMETA_MAGIC) ? \
((struct p80211_frmmeta *)((s)->cb)) : \
(NULL))
#define P80211SKB_RXMETA(s) \
- (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((struct p80211_rxmeta *)(NULL)))
+ (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : \
+ ((struct p80211_rxmeta *)(NULL)))
struct p80211_rxmeta {
struct wlandevice *wlandev;
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index aa1792c8429e..b0af292bc7e3 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -301,7 +301,8 @@ static void p80211netdev_rx_bh(unsigned long arg)
if (memcmp
(hdr->a1, wlandev->netdev->dev_addr,
ETH_ALEN) != 0) {
- /* but reject anything else that isn't multicast */
+ /* but reject anything else that
+ isn't multicast */
if (!(hdr->a1[0] & 0x01)) {
dev_kfree_skb(skb);
continue;
@@ -522,8 +523,8 @@ static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr)
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
- }
#endif
+ }
return -EOPNOTSUPP;
}
@@ -770,7 +771,8 @@ int wlan_setup(wlandevice_t *wlandev, struct device *physdev)
}
/* Allocate and initialize the struct device */
- netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", ether_setup);
+ netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d",
+ ether_setup);
if (netdev == NULL) {
printk(KERN_ERR "Failed to alloc netdev.\n");
wlan_free_wiphy(wiphy);
diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h
index 1ec33740f10f..85884176b661 100644
--- a/drivers/staging/wlan-ng/p80211netdev.h
+++ b/drivers/staging/wlan-ng/p80211netdev.h
@@ -94,11 +94,11 @@ typedef struct net_device netdevice_t;
#endif
/*--- NSD Capabilities Flags ------------------------------*/
-#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */
-#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */
-#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */
-#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */
-#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */
+#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */
+#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */
+#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */
+#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */
+#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */
/* Received frame statistics */
typedef struct p80211_frmrx_t {
diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h
index 41a99c59c6c5..9dec8596f451 100644
--- a/drivers/staging/wlan-ng/p80211types.h
+++ b/drivers/staging/wlan-ng/p80211types.h
@@ -141,14 +141,14 @@
#define P80211DID_LSB_ITEM (12)
#define P80211DID_LSB_INDEX (18)
#define P80211DID_LSB_ISTABLE (26)
-#define P80211DID_LSB_ACCESS (27)
+#define P80211DID_LSB_ACCESS (27)
#define P80211DID_MASK_SECTION (0x0000003fUL)
#define P80211DID_MASK_GROUP (0x0000003fUL)
#define P80211DID_MASK_ITEM (0x0000003fUL)
#define P80211DID_MASK_INDEX (0x000000ffUL)
#define P80211DID_MASK_ISTABLE (0x00000001UL)
-#define P80211DID_MASK_ACCESS (0x00000003UL)
+#define P80211DID_MASK_ACCESS (0x00000003UL)
#define P80211DID_MK(a, m, l) ((((u32)(a)) & (m)) << (l))
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 04514a85d101..6675c8226cef 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -213,8 +213,8 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp)
u16 wordbuf[17];
result = hfa384x_drvr_setconfig16(hw,
- HFA384x_RID_CNFROAMINGMODE,
- HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
+ HFA384x_RID_CNFROAMINGMODE,
+ HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
if (result) {
printk(KERN_ERR
"setconfig(ROAMINGMODE) failed. result=%d\n",
@@ -258,8 +258,8 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp)
}
/* ibss options */
result = hfa384x_drvr_setconfig16(hw,
- HFA384x_RID_CREATEIBSS,
- HFA384x_CREATEIBSS_JOINCREATEIBSS);
+ HFA384x_RID_CREATEIBSS,
+ HFA384x_CREATEIBSS_JOINCREATEIBSS);
if (result) {
printk(KERN_ERR "Failed to set CREATEIBSS.\n");
msg->resultcode.data =
@@ -416,7 +416,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
#define REQBASICRATE(N) \
if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \
req->basicrate ## N .data = item->supprates[(N)-1]; \
- req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \
+ req->basicrate ## N .status = \
+ P80211ENUM_msgitem_status_data_ok; \
}
REQBASICRATE(1);
@@ -431,7 +432,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
#define REQSUPPRATE(N) \
if (count >= N) { \
req->supprate ## N .data = item->supprates[(N)-1]; \
- req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \
+ req->supprate ## N .status = \
+ P80211ENUM_msgitem_status_data_ok; \
}
REQSUPPRATE(1);
@@ -1102,7 +1104,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
result = hfa384x_drvr_disable(hw, 0);
if (result) {
pr_debug
- ("failed to disable port 0 after sniffing, result=%d\n",
+ ("failed to disable port 0 after sniffing, result=%d\n",
result);
goto failed;
}
@@ -1137,7 +1139,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
result = hfa384x_drvr_enable(hw, 0);
if (result) {
pr_debug
- ("failed to enable port to presniff setting, result=%d\n",
+ ("failed to enable port to presniff setting, result=%d\n",
result);
goto failed;
}
@@ -1161,7 +1163,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
&(hw->presniff_port_type));
if (result) {
pr_debug
- ("failed to read porttype, result=%d\n",
+ ("failed to read porttype, result=%d\n",
result);
goto failed;
}
@@ -1171,7 +1173,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
&(hw->presniff_wepflags));
if (result) {
pr_debug
- ("failed to read wepflags, result=%d\n",
+ ("failed to read wepflags, result=%d\n",
result);
goto failed;
}
@@ -1238,8 +1240,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
if (result) {
pr_debug
- ("failed to set wepflags=0x%04x, result=%d\n",
- word, result);
+ ("failed to set wepflags=0x%04x, result=%d\n",
+ word, result);
goto failed;
}
}
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 4f73d095c3ac..ee008e5a0cbc 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -472,9 +472,11 @@ unsigned char XGIfb_query_north_bridge_space(struct xgi_hw_device_info *pXGIhw_e
break;
}
- pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
- if (pdev)
+ pdev = pci_get_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
+ if (pdev) {
valid_pdev = 1;
+ pci_dev_put(pdev);
+ }
}
if (!valid_pdev) {
@@ -2178,8 +2180,7 @@ static int XGIfb_heap_init(void)
#ifndef AGPOFF
if (XGIfb_queuemode == AGP_CMD_QUEUE) {
- agp_info = vmalloc(sizeof(*agp_info));
- memset((void *)agp_info, 0x00, sizeof(*agp_info));
+ agp_info = vzalloc(sizeof(*agp_info));
agp_copy_info(agp_info);
agp_backend_acquire();
diff --git a/drivers/staging/zram/xvmalloc.c b/drivers/staging/zram/xvmalloc.c
index 3fdbb8ada827..b64406739d05 100644
--- a/drivers/staging/zram/xvmalloc.c
+++ b/drivers/staging/zram/xvmalloc.c
@@ -187,7 +187,7 @@ static void insert_block(struct xv_pool *pool, struct page *page, u32 offset,
slindex = get_index_for_insert(block->size);
flindex = slindex / BITS_PER_LONG;
- block->link.prev_page = 0;
+ block->link.prev_page = NULL;
block->link.prev_offset = 0;
block->link.next_page = pool->freelist[slindex].page;
block->link.next_offset = pool->freelist[slindex].offset;
@@ -217,7 +217,7 @@ static void remove_block_head(struct xv_pool *pool,
pool->freelist[slindex].page = block->link.next_page;
pool->freelist[slindex].offset = block->link.next_offset;
- block->link.prev_page = 0;
+ block->link.prev_page = NULL;
block->link.prev_offset = 0;
if (!pool->freelist[slindex].page) {
@@ -232,7 +232,7 @@ static void remove_block_head(struct xv_pool *pool,
*/
tmpblock = get_ptr_atomic(pool->freelist[slindex].page,
pool->freelist[slindex].offset, KM_USER1);
- tmpblock->link.prev_page = 0;
+ tmpblock->link.prev_page = NULL;
tmpblock->link.prev_offset = 0;
put_ptr_atomic(tmpblock, KM_USER1);
}
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 8c3c057aa847..5415712f01f8 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -435,12 +435,6 @@ static int zram_make_request(struct request_queue *queue, struct bio *bio)
int ret = 0;
struct zram *zram = queue->queuedata;
- if (unlikely(!zram->init_done)) {
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
- }
-
if (!valid_io_request(zram, bio)) {
zram_stat64_inc(zram, &zram->stats.invalid_io);
bio_io_error(bio);
@@ -533,7 +527,7 @@ int zram_init_device(struct zram *zram)
}
num_pages = zram->disksize >> PAGE_SHIFT;
- zram->table = vmalloc(num_pages * sizeof(*zram->table));
+ zram->table = vzalloc(num_pages * sizeof(*zram->table));
if (!zram->table) {
pr_err("Error allocating zram address table\n");
/* To prevent accessing table entries during cleanup */
@@ -541,7 +535,6 @@ int zram_init_device(struct zram *zram)
ret = -ENOMEM;
goto fail;
}
- memset(zram->table, 0, num_pages * sizeof(*zram->table));
set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
index 6c574a994d11..6b3cf00b0ff4 100644
--- a/drivers/staging/zram/zram_sysfs.c
+++ b/drivers/staging/zram/zram_sysfs.c
@@ -189,10 +189,10 @@ static ssize_t mem_used_total_show(struct device *dev,
return sprintf(buf, "%llu\n", val);
}
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
disksize_show, disksize_store);
static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUGO, NULL, reset_store);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
new file mode 100644
index 000000000000..2fac3be209ac
--- /dev/null
+++ b/drivers/target/Kconfig
@@ -0,0 +1,32 @@
+
+menuconfig TARGET_CORE
+ tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure"
+ depends on SCSI && BLOCK
+ select CONFIGFS_FS
+ default n
+ help
+ Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
+ control path for target_core_mod. This includes built-in TCM RAMDISK
+ subsystem logic for virtual LUN 0 access
+
+if TARGET_CORE
+
+config TCM_IBLOCK
+ tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK"
+ help
+ Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered
+ access to Linux/Block devices using BIO
+
+config TCM_FILEIO
+ tristate "TCM/FILEIO Subsystem Plugin for Linux/VFS"
+ help
+ Say Y here to enable the TCM/FILEIO subsystem plugin for buffered
+ access to Linux/VFS struct file or struct block_device
+
+config TCM_PSCSI
+ tristate "TCM/pSCSI Subsystem Plugin for Linux/SCSI"
+ help
+ Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
+ passthrough access to Linux/SCSI device
+
+endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
new file mode 100644
index 000000000000..5cfd70819f08
--- /dev/null
+++ b/drivers/target/Makefile
@@ -0,0 +1,24 @@
+EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/
+
+target_core_mod-y := target_core_configfs.o \
+ target_core_device.o \
+ target_core_fabric_configfs.o \
+ target_core_fabric_lib.o \
+ target_core_hba.o \
+ target_core_pr.o \
+ target_core_alua.o \
+ target_core_scdb.o \
+ target_core_tmr.o \
+ target_core_tpg.o \
+ target_core_transport.o \
+ target_core_cdb.o \
+ target_core_ua.o \
+ target_core_rd.o \
+ target_core_mib.o
+
+obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
+
+# Subsystem modules
+obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
+obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
+obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
new file mode 100644
index 000000000000..2c5fcfed5934
--- /dev/null
+++ b/drivers/target/target_core_alua.c
@@ -0,0 +1,1991 @@
+/*******************************************************************************
+ * Filename: target_core_alua.c
+ *
+ * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)
+ *
+ * Copyright (c) 2009-2010 Rising Tide Systems
+ * Copyright (c) 2009-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/configfs.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_ua.h"
+
+static int core_alua_check_transition(int state, int *primary);
+static int core_alua_set_tg_pt_secondary_state(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port, int explict, int offline);
+
+/*
+ * REPORT_TARGET_PORT_GROUPS
+ *
+ * See spc4r17 section 6.27
+ */
+int core_emulate_report_target_port_groups(struct se_cmd *cmd)
+{
+ struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev;
+ struct se_port *port;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
+ Target port group descriptor */
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ /*
+ * PREF: Preferred target port bit, determine if this
+ * bit should be set for port group.
+ */
+ if (tg_pt_gp->tg_pt_gp_pref)
+ buf[off] = 0x80;
+ /*
+ * Set the ASYMMETRIC ACCESS State
+ */
+ buf[off++] |= (atomic_read(
+ &tg_pt_gp->tg_pt_gp_alua_access_state) & 0xff);
+ /*
+ * Set supported ASYMMETRIC ACCESS State bits
+ */
+ buf[off] = 0x80; /* T_SUP */
+ buf[off] |= 0x40; /* O_SUP */
+ buf[off] |= 0x8; /* U_SUP */
+ buf[off] |= 0x4; /* S_SUP */
+ buf[off] |= 0x2; /* AN_SUP */
+ buf[off++] |= 0x1; /* AO_SUP */
+ /*
+ * TARGET PORT GROUP
+ */
+ buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff);
+ buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff);
+
+ off++; /* Skip over Reserved */
+ /*
+ * STATUS CODE
+ */
+ buf[off++] = (tg_pt_gp->tg_pt_gp_alua_access_status & 0xff);
+ /*
+ * Vendor Specific field
+ */
+ buf[off++] = 0x00;
+ /*
+ * TARGET PORT COUNT
+ */
+ buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff);
+ rd_len += 8;
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = tg_pt_gp_mem->tg_pt;
+ /*
+ * Start Target Port descriptor format
+ *
+ * See spc4r17 section 6.2.7 Table 247
+ */
+ off += 2; /* Skip over Obsolete */
+ /*
+ * Set RELATIVE TARGET PORT IDENTIFIER
+ */
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ rd_len += 4;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
+ */
+ buf[0] = ((rd_len >> 24) & 0xff);
+ buf[1] = ((rd_len >> 16) & 0xff);
+ buf[2] = ((rd_len >> 8) & 0xff);
+ buf[3] = (rd_len & 0xff);
+
+ return 0;
+}
+
+/*
+ * SET_TARGET_PORT_GROUPS for explict ALUA operation.
+ *
+ * See spc4r17 section 6.35
+ */
+int core_emulate_set_target_port_groups(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev;
+ struct se_port *port, *l_port = SE_LUN(cmd)->lun_sep;
+ struct se_node_acl *nacl = SE_SESS(cmd)->se_node_acl;
+ struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *ptr = &buf[4]; /* Skip over RESERVED area in header */
+ u32 len = 4; /* Skip over RESERVED area in header */
+ int alua_access_state, primary = 0, rc;
+ u16 tg_pt_id, rtpi;
+
+ if (!(l_port))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ /*
+ * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed
+ * for the local tg_pt_gp.
+ */
+ l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem;
+ if (!(l_tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to access l_port->sep_alua_tg_pt_gp_mem\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp;
+ if (!(l_tg_pt_gp)) {
+ spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_ERR "Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA);
+ spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ if (!(rc)) {
+ printk(KERN_INFO "Unable to process SET_TARGET_PORT_GROUPS"
+ " while TPGS_EXPLICT_ALUA is disabled\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ while (len < cmd->data_length) {
+ alua_access_state = (ptr[0] & 0x0f);
+ /*
+ * Check the received ALUA access state, and determine if
+ * the state is a primary or secondary target port asymmetric
+ * access state.
+ */
+ rc = core_alua_check_transition(alua_access_state, &primary);
+ if (rc != 0) {
+ /*
+ * If the SET TARGET PORT GROUPS attempts to establish
+ * an invalid combination of target port asymmetric
+ * access states or attempts to establish an
+ * unsupported target port asymmetric access state,
+ * then the command shall be terminated with CHECK
+ * CONDITION status, with the sense key set to ILLEGAL
+ * REQUEST, and the additional sense code set to INVALID
+ * FIELD IN PARAMETER LIST.
+ */
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ rc = -1;
+ /*
+ * If the ASYMMETRIC ACCESS STATE field (see table 267)
+ * specifies a primary target port asymmetric access state,
+ * then the TARGET PORT GROUP OR TARGET PORT field specifies
+ * a primary target port group for which the primary target
+ * port asymmetric access state shall be changed. If the
+ * ASYMMETRIC ACCESS STATE field specifies a secondary target
+ * port asymmetric access state, then the TARGET PORT GROUP OR
+ * TARGET PORT field specifies the relative target port
+ * identifier (see 3.1.120) of the target port for which the
+ * secondary target port asymmetric access state shall be
+ * changed.
+ */
+ if (primary) {
+ tg_pt_id = ((ptr[2] << 8) & 0xff);
+ tg_pt_id |= (ptr[3] & 0xff);
+ /*
+ * Locate the matching target port group ID from
+ * the global tg_pt_gp list
+ */
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp,
+ &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+
+ if (tg_pt_id != tg_pt_gp->tg_pt_gp_id)
+ continue;
+
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ rc = core_alua_do_port_transition(tg_pt_gp,
+ dev, l_port, nacl,
+ alua_access_state, 1);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ break;
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * If not matching target port group ID can be located
+ * throw an exception with ASCQ: INVALID_PARAMETER_LIST
+ */
+ if (rc != 0)
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ } else {
+ /*
+ * Extact the RELATIVE TARGET PORT IDENTIFIER to identify
+ * the Target Port in question for the the incoming
+ * SET_TARGET_PORT_GROUPS op.
+ */
+ rtpi = ((ptr[2] << 8) & 0xff);
+ rtpi |= (ptr[3] & 0xff);
+ /*
+ * Locate the matching relative target port identifer
+ * for the struct se_device storage object.
+ */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(port, &dev->dev_sep_list,
+ sep_list) {
+ if (port->sep_rtpi != rtpi)
+ continue;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ spin_unlock(&dev->se_port_lock);
+
+ rc = core_alua_set_tg_pt_secondary_state(
+ tg_pt_gp_mem, port, 1, 1);
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+ /*
+ * If not matching relative target port identifier can
+ * be located, throw an exception with ASCQ:
+ * INVALID_PARAMETER_LIST
+ */
+ if (rc != 0)
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+
+ ptr += 4;
+ len += 4;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_nonoptimized(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ int nonop_delay_msecs,
+ u8 *alua_ascq)
+{
+ /*
+ * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked
+ * later to determine if processing of this cmd needs to be
+ * temporarily delayed for the Active/NonOptimized primary access state.
+ */
+ cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED;
+ cmd->alua_nonop_delay = nonop_delay_msecs;
+ return 0;
+}
+
+static inline int core_alua_state_standby(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by
+ * spc4r17 section 5.9.2.4.4
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case LOG_SELECT:
+ case LOG_SENSE:
+ case MODE_SELECT:
+ case MODE_SENSE:
+ case REPORT_LUNS:
+ case RECEIVE_DIAGNOSTIC:
+ case SEND_DIAGNOSTIC:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+ case MAINTENANCE_OUT:
+ switch (cdb[1]) {
+ case MO_SET_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_unavailable(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by
+ * spc4r17 section 5.9.2.4.5
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+ case MAINTENANCE_OUT:
+ switch (cdb[1]) {
+ case MO_SET_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_transition(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITIO as defined by
+ * spc4r17 section 5.9.2.5
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Used for alua_type SPC_ALUA_PASSTHROUGH and SPC2_ALUA_DISABLED
+ * in transport_cmd_sequencer(). This function is assigned to
+ * struct t10_alua *->state_check() in core_setup_alua()
+ */
+static int core_alua_state_check_nop(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ return 0;
+}
+
+/*
+ * Used for alua_type SPC3_ALUA_EMULATED in transport_cmd_sequencer().
+ * This function is assigned to struct t10_alua *->state_check() in
+ * core_setup_alua()
+ *
+ * Also, this function can return three different return codes to
+ * signal transport_generic_cmd_sequencer()
+ *
+ * return 1: Is used to signal LUN not accecsable, and check condition/not ready
+ * return 0: Used to signal success
+ * reutrn -1: Used to signal failure, and invalid cdb field
+ */
+static int core_alua_state_check(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_port *port = lun->lun_sep;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ int out_alua_state, nonop_delay_msecs;
+
+ if (!(port))
+ return 0;
+ /*
+ * First, check for a struct se_port specific secondary ALUA target port
+ * access state: OFFLINE
+ */
+ if (atomic_read(&port->sep_tg_pt_secondary_offline)) {
+ *alua_ascq = ASCQ_04H_ALUA_OFFLINE;
+ printk(KERN_INFO "ALUA: Got secondary offline status for local"
+ " target port\n");
+ *alua_ascq = ASCQ_04H_ALUA_OFFLINE;
+ return 1;
+ }
+ /*
+ * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the
+ * ALUA target port group, to obtain current ALUA access state.
+ * Otherwise look for the underlying struct se_device association with
+ * a ALUA logical unit group.
+ */
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
+ nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ /*
+ * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a seperate conditional
+ * statement so the complier knows explictly to check this case first.
+ * For the Optimized ALUA access state case, we want to process the
+ * incoming fabric cmd ASAP..
+ */
+ if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTMIZED)
+ return 0;
+
+ switch (out_alua_state) {
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ return core_alua_state_nonoptimized(cmd, cdb,
+ nonop_delay_msecs, alua_ascq);
+ case ALUA_ACCESS_STATE_STANDBY:
+ return core_alua_state_standby(cmd, cdb, alua_ascq);
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ return core_alua_state_unavailable(cmd, cdb, alua_ascq);
+ case ALUA_ACCESS_STATE_TRANSITION:
+ return core_alua_state_transition(cmd, cdb, alua_ascq);
+ /*
+ * OFFLINE is a secondary ALUA target port group access state, that is
+ * handled above with struct se_port->sep_tg_pt_secondary_offline=1
+ */
+ case ALUA_ACCESS_STATE_OFFLINE:
+ default:
+ printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n",
+ out_alua_state);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check implict and explict ALUA state change request.
+ */
+static int core_alua_check_transition(int state, int *primary)
+{
+ switch (state) {
+ case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED:
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ case ALUA_ACCESS_STATE_STANDBY:
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ /*
+ * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
+ * defined as primary target port asymmetric access states.
+ */
+ *primary = 1;
+ break;
+ case ALUA_ACCESS_STATE_OFFLINE:
+ /*
+ * OFFLINE state is defined as a secondary target port
+ * asymmetric access state.
+ */
+ *primary = 0;
+ break;
+ default:
+ printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n", state);
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *core_alua_dump_state(int state)
+{
+ switch (state) {
+ case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED:
+ return "Active/Optimized";
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ return "Active/NonOptimized";
+ case ALUA_ACCESS_STATE_STANDBY:
+ return "Standby";
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ return "Unavailable";
+ case ALUA_ACCESS_STATE_OFFLINE:
+ return "Offline";
+ default:
+ return "Unknown";
+ }
+
+ return NULL;
+}
+
+char *core_alua_dump_status(int status)
+{
+ switch (status) {
+ case ALUA_STATUS_NONE:
+ return "None";
+ case ALUA_STATUS_ALTERED_BY_EXPLICT_STPG:
+ return "Altered by Explict STPG";
+ case ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA:
+ return "Altered by Implict ALUA";
+ default:
+ return "Unknown";
+ }
+
+ return NULL;
+}
+
+/*
+ * Used by fabric modules to determine when we need to delay processing
+ * for the Active/NonOptimized paths..
+ */
+int core_alua_check_nonop_delay(
+ struct se_cmd *cmd)
+{
+ if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED))
+ return 0;
+ if (in_interrupt())
+ return 0;
+ /*
+ * The ALUA Active/NonOptimized access state delay can be disabled
+ * in via configfs with a value of zero
+ */
+ if (!(cmd->alua_nonop_delay))
+ return 0;
+ /*
+ * struct se_cmd->alua_nonop_delay gets set by a target port group
+ * defined interval in core_alua_state_nonoptimized()
+ */
+ msleep_interruptible(cmd->alua_nonop_delay);
+ return 0;
+}
+EXPORT_SYMBOL(core_alua_check_nonop_delay);
+
+/*
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex
+ *
+ */
+static int core_alua_write_tpg_metadata(
+ const char *path,
+ unsigned char *md_buf,
+ u32 md_buf_len)
+{
+ mm_segment_t old_fs;
+ struct file *file;
+ struct iovec iov[1];
+ int flags = O_RDWR | O_CREAT | O_TRUNC, ret;
+
+ memset(iov, 0, sizeof(struct iovec));
+
+ file = filp_open(path, flags, 0600);
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) for ALUA metadata failed\n",
+ path);
+ return -ENODEV;
+ }
+
+ iov[0].iov_base = &md_buf[0];
+ iov[0].iov_len = md_buf_len;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(file, &iov[0], 1, &file->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error writing ALUA metadata file: %s\n", path);
+ filp_close(file, NULL);
+ return -EIO;
+ }
+ filp_close(file, NULL);
+
+ return 0;
+}
+
+/*
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex held
+ */
+static int core_alua_update_tpg_primary_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ int primary_state,
+ unsigned char *md_buf)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_wwn *wwn = &su_dev->t10_wwn;
+ char path[ALUA_METADATA_PATH_LEN];
+ int len;
+
+ memset(path, 0, ALUA_METADATA_PATH_LEN);
+
+ len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len,
+ "tg_pt_gp_id=%hu\n"
+ "alua_access_state=0x%02x\n"
+ "alua_access_status=0x%02x\n",
+ tg_pt_gp->tg_pt_gp_id, primary_state,
+ tg_pt_gp->tg_pt_gp_alua_access_status);
+
+ snprintf(path, ALUA_METADATA_PATH_LEN,
+ "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0],
+ config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
+static int core_alua_do_transition_tg_pt(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ struct se_port *l_port,
+ struct se_node_acl *nacl,
+ unsigned char *md_buf,
+ int new_state,
+ int explict)
+{
+ struct se_dev_entry *se_deve;
+ struct se_lun_acl *lacl;
+ struct se_port *port;
+ struct t10_alua_tg_pt_gp_member *mem;
+ int old_state = 0;
+ /*
+ * Save the old primary ALUA access state, and set the current state
+ * to ALUA_ACCESS_STATE_TRANSITION.
+ */
+ old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+ ALUA_ACCESS_STATE_TRANSITION);
+ tg_pt_gp->tg_pt_gp_alua_access_status = (explict) ?
+ ALUA_STATUS_ALTERED_BY_EXPLICT_STPG :
+ ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
+ /*
+ * Check for the optional ALUA primary state transition delay
+ */
+ if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0)
+ msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = mem->tg_pt;
+ /*
+ * After an implicit target port asymmetric access state
+ * change, a device server shall establish a unit attention
+ * condition for the initiator port associated with every I_T
+ * nexus with the additional sense code set to ASYMMETRIC
+ * ACCESS STATE CHAGED.
+ *
+ * After an explicit target port asymmetric access state
+ * change, a device server shall establish a unit attention
+ * condition with the additional sense code set to ASYMMETRIC
+ * ACCESS STATE CHANGED for the initiator port associated with
+ * every I_T nexus other than the I_T nexus on which the SET
+ * TARGET PORT GROUPS command
+ */
+ atomic_inc(&mem->tg_pt_gp_mem_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_for_each_entry(se_deve, &port->sep_alua_list,
+ alua_port_list) {
+ lacl = se_deve->se_lun_acl;
+ /*
+ * se_deve->se_lun_acl pointer may be NULL for a
+ * entry created without explict Node+MappedLUN ACLs
+ */
+ if (!(lacl))
+ continue;
+
+ if (explict &&
+ (nacl != NULL) && (nacl == lacl->se_lun_nacl) &&
+ (l_port != NULL) && (l_port == port))
+ continue;
+
+ core_scsi3_ua_allocate(lacl->se_lun_nacl,
+ se_deve->mapped_lun, 0x2A,
+ ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED);
+ }
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ atomic_dec(&mem->tg_pt_gp_mem_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ /*
+ * Update the ALUA metadata buf that has been allocated in
+ * core_alua_do_port_transition(), this metadata will be written
+ * to struct file.
+ *
+ * Note that there is the case where we do not want to update the
+ * metadata when the saved metadata is being parsed in userspace
+ * when setting the existing port access state and access status.
+ *
+ * Also note that the failure to write out the ALUA metadata to
+ * struct file does NOT affect the actual ALUA transition.
+ */
+ if (tg_pt_gp->tg_pt_gp_write_metadata) {
+ mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex);
+ core_alua_update_tpg_primary_metadata(tg_pt_gp,
+ new_state, md_buf);
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex);
+ }
+ /*
+ * Set the current primary ALUA access state to the requested new state
+ */
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, new_state);
+
+ printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu"
+ " from primary access state %s to %s\n", (explict) ? "explict" :
+ "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(old_state),
+ core_alua_dump_state(new_state));
+
+ return 0;
+}
+
+int core_alua_do_port_transition(
+ struct t10_alua_tg_pt_gp *l_tg_pt_gp,
+ struct se_device *l_dev,
+ struct se_port *l_port,
+ struct se_node_acl *l_nacl,
+ int new_state,
+ int explict)
+{
+ struct se_device *dev;
+ struct se_port *port;
+ struct se_subsystem_dev *su_dev;
+ struct se_node_acl *nacl;
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ unsigned char *md_buf;
+ int primary;
+
+ if (core_alua_check_transition(new_state, &primary) != 0)
+ return -EINVAL;
+
+ md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL);
+ if (!(md_buf)) {
+ printk("Unable to allocate buf for ALUA metadata\n");
+ return -ENOMEM;
+ }
+
+ local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem;
+ spin_lock(&local_lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = local_lu_gp_mem->lu_gp;
+ atomic_inc(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock);
+ /*
+ * For storage objects that are members of the 'default_lu_gp',
+ * we only do transition on the passed *l_tp_pt_gp, and not
+ * on all of the matching target port groups IDs in default_lu_gp.
+ */
+ if (!(lu_gp->lu_gp_id)) {
+ /*
+ * core_alua_do_transition_tg_pt() will always return
+ * success.
+ */
+ core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl,
+ md_buf, new_state, explict);
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ kfree(md_buf);
+ return 0;
+ }
+ /*
+ * For all other LU groups aside from 'default_lu_gp', walk all of
+ * the associated storage objects looking for a matching target port
+ * group ID from the local target port group.
+ */
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list,
+ lu_gp_mem_list) {
+
+ dev = lu_gp_mem->lu_gp_mem_dev;
+ su_dev = dev->se_sub_dev;
+ atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp,
+ &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+ /*
+ * If the target behavior port asymmetric access state
+ * is changed for any target port group accessiable via
+ * a logical unit within a LU group, the target port
+ * behavior group asymmetric access states for the same
+ * target port group accessible via other logical units
+ * in that LU group will also change.
+ */
+ if (l_tg_pt_gp->tg_pt_gp_id != tg_pt_gp->tg_pt_gp_id)
+ continue;
+
+ if (l_tg_pt_gp == tg_pt_gp) {
+ port = l_port;
+ nacl = l_nacl;
+ } else {
+ port = NULL;
+ nacl = NULL;
+ }
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * core_alua_do_transition_tg_pt() will always return
+ * success.
+ */
+ core_alua_do_transition_tg_pt(tg_pt_gp, port,
+ nacl, md_buf, new_state, explict);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ printk(KERN_INFO "Successfully processed LU Group: %s all ALUA TG PT"
+ " Group IDs: %hu %s transition to primary state: %s\n",
+ config_item_name(&lu_gp->lu_gp_group.cg_item),
+ l_tg_pt_gp->tg_pt_gp_id, (explict) ? "explict" : "implict",
+ core_alua_dump_state(new_state));
+
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ kfree(md_buf);
+ return 0;
+}
+
+/*
+ * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held
+ */
+static int core_alua_update_tpg_secondary_metadata(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port,
+ unsigned char *md_buf,
+ u32 md_buf_len)
+{
+ struct se_portal_group *se_tpg = port->sep_tpg;
+ char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN];
+ int len;
+
+ memset(path, 0, ALUA_METADATA_PATH_LEN);
+ memset(wwn, 0, ALUA_SECONDARY_METADATA_WWN_LEN);
+
+ len = snprintf(wwn, ALUA_SECONDARY_METADATA_WWN_LEN, "%s",
+ TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg));
+
+ if (TPG_TFO(se_tpg)->tpg_get_tag != NULL)
+ snprintf(wwn+len, ALUA_SECONDARY_METADATA_WWN_LEN-len, "+%hu",
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg));
+
+ len = snprintf(md_buf, md_buf_len, "alua_tg_pt_offline=%d\n"
+ "alua_tg_pt_status=0x%02x\n",
+ atomic_read(&port->sep_tg_pt_secondary_offline),
+ port->sep_tg_pt_secondary_stat);
+
+ snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u",
+ TPG_TFO(se_tpg)->get_fabric_name(), wwn,
+ port->sep_lun->unpacked_lun);
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
+static int core_alua_set_tg_pt_secondary_state(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port,
+ int explict,
+ int offline)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ unsigned char *md_buf;
+ u32 md_buf_len;
+ int trans_delay_msecs;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (!(tg_pt_gp)) {
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_ERR "Unable to complete secondary state"
+ " transition\n");
+ return -1;
+ }
+ trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs;
+ /*
+ * Set the secondary ALUA target port access state to OFFLINE
+ * or release the previously secondary state for struct se_port
+ */
+ if (offline)
+ atomic_set(&port->sep_tg_pt_secondary_offline, 1);
+ else
+ atomic_set(&port->sep_tg_pt_secondary_offline, 0);
+
+ md_buf_len = tg_pt_gp->tg_pt_gp_md_buf_len;
+ port->sep_tg_pt_secondary_stat = (explict) ?
+ ALUA_STATUS_ALTERED_BY_EXPLICT_STPG :
+ ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
+
+ printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu"
+ " to secondary access state: %s\n", (explict) ? "explict" :
+ "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE");
+
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ /*
+ * Do the optional transition delay after we set the secondary
+ * ALUA access state.
+ */
+ if (trans_delay_msecs != 0)
+ msleep_interruptible(trans_delay_msecs);
+ /*
+ * See if we need to update the ALUA fabric port metadata for
+ * secondary state and status
+ */
+ if (port->sep_tg_pt_secondary_write_md) {
+ md_buf = kzalloc(md_buf_len, GFP_KERNEL);
+ if (!(md_buf)) {
+ printk(KERN_ERR "Unable to allocate md_buf for"
+ " secondary ALUA access metadata\n");
+ return -1;
+ }
+ mutex_lock(&port->sep_tg_pt_md_mutex);
+ core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port,
+ md_buf, md_buf_len);
+ mutex_unlock(&port->sep_tg_pt_md_mutex);
+
+ kfree(md_buf);
+ }
+
+ return 0;
+}
+
+struct t10_alua_lu_gp *
+core_alua_allocate_lu_gp(const char *name, int def_group)
+{
+ struct t10_alua_lu_gp *lu_gp;
+
+ lu_gp = kmem_cache_zalloc(t10_alua_lu_gp_cache, GFP_KERNEL);
+ if (!(lu_gp)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp\n");
+ return ERR_PTR(-ENOMEM);;
+ }
+ INIT_LIST_HEAD(&lu_gp->lu_gp_list);
+ INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list);
+ spin_lock_init(&lu_gp->lu_gp_lock);
+ atomic_set(&lu_gp->lu_gp_ref_cnt, 0);
+
+ if (def_group) {
+ lu_gp->lu_gp_id = se_global->alua_lu_gps_counter++;;
+ lu_gp->lu_gp_valid_id = 1;
+ se_global->alua_lu_gps_count++;
+ }
+
+ return lu_gp;
+}
+
+int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *lu_gp, u16 lu_gp_id)
+{
+ struct t10_alua_lu_gp *lu_gp_tmp;
+ u16 lu_gp_id_tmp;
+ /*
+ * The lu_gp->lu_gp_id may only be set once..
+ */
+ if (lu_gp->lu_gp_valid_id) {
+ printk(KERN_WARNING "ALUA LU Group already has a valid ID,"
+ " ignoring request\n");
+ return -1;
+ }
+
+ spin_lock(&se_global->lu_gps_lock);
+ if (se_global->alua_lu_gps_count == 0x0000ffff) {
+ printk(KERN_ERR "Maximum ALUA se_global->alua_lu_gps_count:"
+ " 0x0000ffff reached\n");
+ spin_unlock(&se_global->lu_gps_lock);
+ kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+ return -1;
+ }
+again:
+ lu_gp_id_tmp = (lu_gp_id != 0) ? lu_gp_id :
+ se_global->alua_lu_gps_counter++;
+
+ list_for_each_entry(lu_gp_tmp, &se_global->g_lu_gps_list, lu_gp_list) {
+ if (lu_gp_tmp->lu_gp_id == lu_gp_id_tmp) {
+ if (!(lu_gp_id))
+ goto again;
+
+ printk(KERN_WARNING "ALUA Logical Unit Group ID: %hu"
+ " already exists, ignoring request\n",
+ lu_gp_id);
+ spin_unlock(&se_global->lu_gps_lock);
+ return -1;
+ }
+ }
+
+ lu_gp->lu_gp_id = lu_gp_id_tmp;
+ lu_gp->lu_gp_valid_id = 1;
+ list_add_tail(&lu_gp->lu_gp_list, &se_global->g_lu_gps_list);
+ se_global->alua_lu_gps_count++;
+ spin_unlock(&se_global->lu_gps_lock);
+
+ return 0;
+}
+
+static struct t10_alua_lu_gp_member *
+core_alua_allocate_lu_gp_mem(struct se_device *dev)
+{
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+
+ lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL);
+ if (!(lu_gp_mem)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp_member\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list);
+ spin_lock_init(&lu_gp_mem->lu_gp_mem_lock);
+ atomic_set(&lu_gp_mem->lu_gp_mem_ref_cnt, 0);
+
+ lu_gp_mem->lu_gp_mem_dev = dev;
+ dev->dev_alua_lu_gp_mem = lu_gp_mem;
+
+ return lu_gp_mem;
+}
+
+void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp)
+{
+ struct t10_alua_lu_gp_member *lu_gp_mem, *lu_gp_mem_tmp;
+ /*
+ * Once we have reached this point, config_item_put() has
+ * already been called from target_core_alua_drop_lu_gp().
+ *
+ * Here, we remove the *lu_gp from the global list so that
+ * no associations can be made while we are releasing
+ * struct t10_alua_lu_gp.
+ */
+ spin_lock(&se_global->lu_gps_lock);
+ atomic_set(&lu_gp->lu_gp_shutdown, 1);
+ list_del(&lu_gp->lu_gp_list);
+ se_global->alua_lu_gps_count--;
+ spin_unlock(&se_global->lu_gps_lock);
+ /*
+ * Allow struct t10_alua_lu_gp * referenced by core_alua_get_lu_gp_by_name()
+ * in target_core_configfs.c:target_core_store_alua_lu_gp() to be
+ * released with core_alua_put_lu_gp_from_name()
+ */
+ while (atomic_read(&lu_gp->lu_gp_ref_cnt))
+ cpu_relax();
+ /*
+ * Release reference to struct t10_alua_lu_gp * from all associated
+ * struct se_device.
+ */
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp,
+ &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+ if (lu_gp_mem->lu_gp_assoc) {
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp->lu_gp_members--;
+ lu_gp_mem->lu_gp_assoc = 0;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+ /*
+ *
+ * lu_gp_mem is assoicated with a single
+ * struct se_device->dev_alua_lu_gp_mem, and is released when
+ * struct se_device is released via core_alua_free_lu_gp_mem().
+ *
+ * If the passed lu_gp does NOT match the default_lu_gp, assume
+ * we want to re-assocate a given lu_gp_mem with default_lu_gp.
+ */
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ if (lu_gp != se_global->default_lu_gp)
+ __core_alua_attach_lu_gp_mem(lu_gp_mem,
+ se_global->default_lu_gp);
+ else
+ lu_gp_mem->lu_gp = NULL;
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+}
+
+void core_alua_free_lu_gp_mem(struct se_device *dev)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return;
+
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem))
+ return;
+
+ while (atomic_read(&lu_gp_mem->lu_gp_mem_ref_cnt))
+ cpu_relax();
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ spin_lock(&lu_gp->lu_gp_lock);
+ if (lu_gp_mem->lu_gp_assoc) {
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp->lu_gp_members--;
+ lu_gp_mem->lu_gp_assoc = 0;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+ lu_gp_mem->lu_gp = NULL;
+ }
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem);
+}
+
+struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *name)
+{
+ struct t10_alua_lu_gp *lu_gp;
+ struct config_item *ci;
+
+ spin_lock(&se_global->lu_gps_lock);
+ list_for_each_entry(lu_gp, &se_global->g_lu_gps_list, lu_gp_list) {
+ if (!(lu_gp->lu_gp_valid_id))
+ continue;
+ ci = &lu_gp->lu_gp_group.cg_item;
+ if (!(strcmp(config_item_name(ci), name))) {
+ atomic_inc(&lu_gp->lu_gp_ref_cnt);
+ spin_unlock(&se_global->lu_gps_lock);
+ return lu_gp;
+ }
+ }
+ spin_unlock(&se_global->lu_gps_lock);
+
+ return NULL;
+}
+
+void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&se_global->lu_gps_lock);
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ spin_unlock(&se_global->lu_gps_lock);
+}
+
+/*
+ * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
+ */
+void __core_alua_attach_lu_gp_mem(
+ struct t10_alua_lu_gp_member *lu_gp_mem,
+ struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&lu_gp->lu_gp_lock);
+ lu_gp_mem->lu_gp = lu_gp;
+ lu_gp_mem->lu_gp_assoc = 1;
+ list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list);
+ lu_gp->lu_gp_members++;
+ spin_unlock(&lu_gp->lu_gp_lock);
+}
+
+/*
+ * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
+ */
+void __core_alua_drop_lu_gp_mem(
+ struct t10_alua_lu_gp_member *lu_gp_mem,
+ struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp_mem->lu_gp = NULL;
+ lu_gp_mem->lu_gp_assoc = 0;
+ lu_gp->lu_gp_members--;
+ spin_unlock(&lu_gp->lu_gp_lock);
+}
+
+struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
+ struct se_subsystem_dev *su_dev,
+ const char *name,
+ int def_group)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+
+ tg_pt_gp = kmem_cache_zalloc(t10_alua_tg_pt_gp_cache, GFP_KERNEL);
+ if (!(tg_pt_gp)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
+ INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list);
+ mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);
+ spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
+ atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
+ tg_pt_gp->tg_pt_gp_su_dev = su_dev;
+ tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN;
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+ ALUA_ACCESS_STATE_ACTIVE_OPTMIZED);
+ /*
+ * Enable both explict and implict ALUA support by default
+ */
+ tg_pt_gp->tg_pt_gp_alua_access_type =
+ TPGS_EXPLICT_ALUA | TPGS_IMPLICT_ALUA;
+ /*
+ * Set the default Active/NonOptimized Delay in milliseconds
+ */
+ tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS;
+ tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS;
+
+ if (def_group) {
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ tg_pt_gp->tg_pt_gp_id =
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter++;
+ tg_pt_gp->tg_pt_gp_valid_id = 1;
+ T10_ALUA(su_dev)->alua_tg_pt_gps_count++;
+ list_add_tail(&tg_pt_gp->tg_pt_gp_list,
+ &T10_ALUA(su_dev)->tg_pt_gps_list);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ }
+
+ return tg_pt_gp;
+}
+
+int core_alua_set_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ u16 tg_pt_gp_id)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_alua_tg_pt_gp *tg_pt_gp_tmp;
+ u16 tg_pt_gp_id_tmp;
+ /*
+ * The tg_pt_gp->tg_pt_gp_id may only be set once..
+ */
+ if (tg_pt_gp->tg_pt_gp_valid_id) {
+ printk(KERN_WARNING "ALUA TG PT Group already has a valid ID,"
+ " ignoring request\n");
+ return -1;
+ }
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ if (T10_ALUA(su_dev)->alua_tg_pt_gps_count == 0x0000ffff) {
+ printk(KERN_ERR "Maximum ALUA alua_tg_pt_gps_count:"
+ " 0x0000ffff reached\n");
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
+ return -1;
+ }
+again:
+ tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id :
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter++;
+
+ list_for_each_entry(tg_pt_gp_tmp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) {
+ if (!(tg_pt_gp_id))
+ goto again;
+
+ printk(KERN_ERR "ALUA Target Port Group ID: %hu already"
+ " exists, ignoring request\n", tg_pt_gp_id);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ return -1;
+ }
+ }
+
+ tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp;
+ tg_pt_gp->tg_pt_gp_valid_id = 1;
+ list_add_tail(&tg_pt_gp->tg_pt_gp_list,
+ &T10_ALUA(su_dev)->tg_pt_gps_list);
+ T10_ALUA(su_dev)->alua_tg_pt_gps_count++;
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ return 0;
+}
+
+struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
+ struct se_port *port)
+{
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache,
+ GFP_KERNEL);
+ if (!(tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp_member\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0);
+
+ tg_pt_gp_mem->tg_pt = port;
+ port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem;
+ atomic_set(&port->sep_tg_pt_gp_active, 1);
+
+ return tg_pt_gp_mem;
+}
+
+void core_alua_free_tg_pt_gp(
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp;
+ /*
+ * Once we have reached this point, config_item_put() has already
+ * been called from target_core_alua_drop_tg_pt_gp().
+ *
+ * Here we remove *tg_pt_gp from the global list so that
+ * no assications *OR* explict ALUA via SET_TARGET_PORT_GROUPS
+ * can be made while we are releasing struct t10_alua_tg_pt_gp.
+ */
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_del(&tg_pt_gp->tg_pt_gp_list);
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter--;
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * Allow a struct t10_alua_tg_pt_gp_member * referenced by
+ * core_alua_get_tg_pt_gp_by_name() in
+ * target_core_configfs.c:target_core_store_alua_tg_pt_gp()
+ * to be released with core_alua_put_tg_pt_gp_from_name().
+ */
+ while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt))
+ cpu_relax();
+ /*
+ * Release reference to struct t10_alua_tg_pt_gp from all associated
+ * struct se_port.
+ */
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp,
+ &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) {
+ if (tg_pt_gp_mem->tg_pt_gp_assoc) {
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members--;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ /*
+ * tg_pt_gp_mem is assoicated with a single
+ * se_port->sep_alua_tg_pt_gp_mem, and is released via
+ * core_alua_free_tg_pt_gp_mem().
+ *
+ * If the passed tg_pt_gp does NOT match the default_tg_pt_gp,
+ * assume we want to re-assocate a given tg_pt_gp_mem with
+ * default_tg_pt_gp.
+ */
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ if (tg_pt_gp != T10_ALUA(su_dev)->default_tg_pt_gp) {
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ } else
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
+}
+
+void core_alua_free_tg_pt_gp_mem(struct se_port *port)
+{
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem))
+ return;
+
+ while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt))
+ cpu_relax();
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ if (tg_pt_gp_mem->tg_pt_gp_assoc) {
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members--;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ }
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem);
+}
+
+static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name(
+ struct se_subsystem_dev *su_dev,
+ const char *name)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct config_item *ci;
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+ ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
+ if (!(strcmp(config_item_name(ci), name))) {
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ return tg_pt_gp;
+ }
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ return NULL;
+}
+
+static void core_alua_put_tg_pt_gp_from_name(
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+}
+
+/*
+ * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
+ */
+void __core_alua_attach_tg_pt_gp_mem(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ tg_pt_gp_mem->tg_pt_gp = tg_pt_gp;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 1;
+ list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list,
+ &tg_pt_gp->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members++;
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+}
+
+/*
+ * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
+ */
+static void __core_alua_drop_tg_pt_gp_mem(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ tg_pt_gp->tg_pt_gp_members--;
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+}
+
+ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page)
+{
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct config_item *tg_pt_ci;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ ssize_t len = 0;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return len;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem))
+ return len;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
+ len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:"
+ " %hu\nTG Port Primary Access State: %s\nTG Port "
+ "Primary Access Status: %s\nTG Port Secondary Access"
+ " State: %s\nTG Port Secondary Access Status: %s\n",
+ config_item_name(tg_pt_ci), tg_pt_gp->tg_pt_gp_id,
+ core_alua_dump_state(atomic_read(
+ &tg_pt_gp->tg_pt_gp_alua_access_state)),
+ core_alua_dump_status(
+ tg_pt_gp->tg_pt_gp_alua_access_status),
+ (atomic_read(&port->sep_tg_pt_secondary_offline)) ?
+ "Offline" : "None",
+ core_alua_dump_status(port->sep_tg_pt_secondary_stat));
+ }
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ return len;
+}
+
+ssize_t core_alua_store_tg_pt_gp_info(
+ struct se_port *port,
+ const char *page,
+ size_t count)
+{
+ struct se_portal_group *tpg;
+ struct se_lun *lun;
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char buf[TG_PT_GROUP_NAME_BUF];
+ int move = 0;
+
+ tpg = port->sep_tpg;
+ lun = port->sep_lun;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) {
+ printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for"
+ " %s/tpgt_%hu/%s\n", TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item));
+ return -EINVAL;
+ }
+
+ if (count > TG_PT_GROUP_NAME_BUF) {
+ printk(KERN_ERR "ALUA Target Port Group alias too large!\n");
+ return -EINVAL;
+ }
+ memset(buf, 0, TG_PT_GROUP_NAME_BUF);
+ memcpy(buf, page, count);
+ /*
+ * Any ALUA target port group alias besides "NULL" means we will be
+ * making a new group association.
+ */
+ if (strcmp(strstrip(buf), "NULL")) {
+ /*
+ * core_alua_get_tg_pt_gp_by_name() will increment reference to
+ * struct t10_alua_tg_pt_gp. This reference is released with
+ * core_alua_put_tg_pt_gp_from_name() below.
+ */
+ tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(su_dev,
+ strstrip(buf));
+ if (!(tg_pt_gp_new))
+ return -ENODEV;
+ }
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem)) {
+ if (tg_pt_gp_new)
+ core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
+ printk(KERN_ERR "NULL struct se_port->sep_alua_tg_pt_gp_mem pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ /*
+ * Clearing an existing tg_pt_gp association, and replacing
+ * with the default_tg_pt_gp.
+ */
+ if (!(tg_pt_gp_new)) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Moving"
+ " %s/tpgt_%hu/%s from ALUA Target Port Group:"
+ " alua/%s, ID: %hu back to"
+ " default_tg_pt_gp\n",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item),
+ config_item_name(
+ &tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id);
+
+ __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ return count;
+ }
+ /*
+ * Removing existing association of tg_pt_gp_mem with tg_pt_gp
+ */
+ __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
+ move = 1;
+ }
+ /*
+ * Associate tg_pt_gp_mem with tg_pt_gp_new.
+ */
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_INFO "Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA"
+ " Target Port Group: alua/%s, ID: %hu\n", (move) ?
+ "Moving" : "Adding", TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item),
+ config_item_name(&tg_pt_gp_new->tg_pt_gp_group.cg_item),
+ tg_pt_gp_new->tg_pt_gp_id);
+
+ core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
+ return count;
+}
+
+ssize_t core_alua_show_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ if ((tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA) &&
+ (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA))
+ return sprintf(page, "Implict and Explict\n");
+ else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)
+ return sprintf(page, "Implict\n");
+ else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA)
+ return sprintf(page, "Explict\n");
+ else
+ return sprintf(page, "None\n");
+}
+
+ssize_t core_alua_store_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_access_type\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) {
+ printk(KERN_ERR "Illegal value for alua_access_type:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ if (tmp == 3)
+ tg_pt_gp->tg_pt_gp_alua_access_type =
+ TPGS_IMPLICT_ALUA | TPGS_EXPLICT_ALUA;
+ else if (tmp == 2)
+ tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_EXPLICT_ALUA;
+ else if (tmp == 1)
+ tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_IMPLICT_ALUA;
+ else
+ tg_pt_gp->tg_pt_gp_alua_access_type = 0;
+
+ return count;
+}
+
+ssize_t core_alua_show_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_nonop_delay_msecs);
+}
+
+ssize_t core_alua_store_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract nonop_delay_msecs\n");
+ return -EINVAL;
+ }
+ if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) {
+ printk(KERN_ERR "Passed nonop_delay_msecs: %lu, exceeds"
+ " ALUA_MAX_NONOP_DELAY_MSECS: %d\n", tmp,
+ ALUA_MAX_NONOP_DELAY_MSECS);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_nonop_delay_msecs = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+}
+
+ssize_t core_alua_store_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract trans_delay_msecs\n");
+ return -EINVAL;
+ }
+ if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) {
+ printk(KERN_ERR "Passed trans_delay_msecs: %lu, exceeds"
+ " ALUA_MAX_TRANS_DELAY_MSECS: %d\n", tmp,
+ ALUA_MAX_TRANS_DELAY_MSECS);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_preferred_bit(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_pref);
+}
+
+ssize_t core_alua_store_preferred_bit(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract preferred ALUA value\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for preferred ALUA: %lu\n", tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_pref = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page)
+{
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return sprintf(page, "%d\n",
+ atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline));
+}
+
+ssize_t core_alua_store_offline_bit(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned long tmp;
+ int ret;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_offline value\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_offline: %lu\n",
+ tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to locate *tg_pt_gp_mem\n");
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem,
+ lun->lun_sep, 0, (int)tmp);
+ if (ret < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+ssize_t core_alua_show_secondary_status(
+ struct se_lun *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat);
+}
+
+ssize_t core_alua_store_secondary_status(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_status\n");
+ return -EINVAL;
+ }
+ if ((tmp != ALUA_STATUS_NONE) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_status: %lu\n",
+ tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_secondary_write_metadata(
+ struct se_lun *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ lun->lun_sep->sep_tg_pt_secondary_write_md);
+}
+
+ssize_t core_alua_store_secondary_write_metadata(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_write_md\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_write_md:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp;
+
+ return count;
+}
+
+int core_setup_alua(struct se_device *dev, int force_pt)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic
+ * of the Underlying SCSI hardware. In Linux/SCSI terms, this can
+ * cause a problem because libata and some SATA RAID HBAs appear
+ * under Linux/SCSI, but emulate SCSI logic themselves.
+ */
+ if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ !(DEV_ATTRIB(dev)->emulate_alua)) || force_pt) {
+ alua->alua_type = SPC_ALUA_PASSTHROUGH;
+ alua->alua_state_check = &core_alua_state_check_nop;
+ printk(KERN_INFO "%s: Using SPC_ALUA_PASSTHROUGH, no ALUA"
+ " emulation\n", TRANSPORT(dev)->name);
+ return 0;
+ }
+ /*
+ * If SPC-3 or above is reported by real or emulated struct se_device,
+ * use emulated ALUA.
+ */
+ if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
+ printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3"
+ " device\n", TRANSPORT(dev)->name);
+ /*
+ * Assoicate this struct se_device with the default ALUA
+ * LUN Group.
+ */
+ lu_gp_mem = core_alua_allocate_lu_gp_mem(dev);
+ if (IS_ERR(lu_gp_mem) || !lu_gp_mem)
+ return -1;
+
+ alua->alua_type = SPC3_ALUA_EMULATED;
+ alua->alua_state_check = &core_alua_state_check;
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ __core_alua_attach_lu_gp_mem(lu_gp_mem,
+ se_global->default_lu_gp);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ printk(KERN_INFO "%s: Adding to default ALUA LU Group:"
+ " core/alua/lu_gps/default_lu_gp\n",
+ TRANSPORT(dev)->name);
+ } else {
+ alua->alua_type = SPC2_ALUA_DISABLED;
+ alua->alua_state_check = &core_alua_state_check_nop;
+ printk(KERN_INFO "%s: Disabling ALUA Emulation for SPC-2"
+ " device\n", TRANSPORT(dev)->name);
+ }
+
+ return 0;
+}
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
new file mode 100644
index 000000000000..c86f97a081ed
--- /dev/null
+++ b/drivers/target/target_core_alua.h
@@ -0,0 +1,126 @@
+#ifndef TARGET_CORE_ALUA_H
+#define TARGET_CORE_ALUA_H
+
+/*
+ * INQUIRY response data, TPGS Field
+ *
+ * from spc4r17 section 6.4.2 Table 135
+ */
+#define TPGS_NO_ALUA 0x00
+#define TPGS_IMPLICT_ALUA 0x10
+#define TPGS_EXPLICT_ALUA 0x20
+
+/*
+ * ASYMMETRIC ACCESS STATE field
+ *
+ * from spc4r17 section 6.27 Table 245
+ */
+#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0
+#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
+#define ALUA_ACCESS_STATE_STANDBY 0x2
+#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
+#define ALUA_ACCESS_STATE_OFFLINE 0xe
+#define ALUA_ACCESS_STATE_TRANSITION 0xf
+
+/*
+ * REPORT_TARGET_PORT_GROUP STATUS CODE
+ *
+ * from spc4r17 section 6.27 Table 246
+ */
+#define ALUA_STATUS_NONE 0x00
+#define ALUA_STATUS_ALTERED_BY_EXPLICT_STPG 0x01
+#define ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA 0x02
+
+/*
+ * From spc4r17, Table D.1: ASC and ASCQ Assignement
+ */
+#define ASCQ_04H_ALUA_STATE_TRANSITION 0x0a
+#define ASCQ_04H_ALUA_TG_PT_STANDBY 0x0b
+#define ASCQ_04H_ALUA_TG_PT_UNAVAILABLE 0x0c
+#define ASCQ_04H_ALUA_OFFLINE 0x12
+
+/*
+ * Used as the default for Active/NonOptimized delay (in milliseconds)
+ * This can also be changed via configfs on a per target port group basis..
+ */
+#define ALUA_DEFAULT_NONOP_DELAY_MSECS 100
+#define ALUA_MAX_NONOP_DELAY_MSECS 10000 /* 10 seconds */
+/*
+ * Used for implict and explict ALUA transitional delay, that is disabled
+ * by default, and is intended to be used for debugging client side ALUA code.
+ */
+#define ALUA_DEFAULT_TRANS_DELAY_MSECS 0
+#define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */
+/*
+ * Used by core_alua_update_tpg_primary_metadata() and
+ * core_alua_update_tpg_secondary_metadata()
+ */
+#define ALUA_METADATA_PATH_LEN 512
+/*
+ * Used by core_alua_update_tpg_secondary_metadata()
+ */
+#define ALUA_SECONDARY_METADATA_WWN_LEN 256
+
+extern struct kmem_cache *t10_alua_lu_gp_cache;
+extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+
+extern int core_emulate_report_target_port_groups(struct se_cmd *);
+extern int core_emulate_set_target_port_groups(struct se_cmd *);
+extern int core_alua_check_nonop_delay(struct se_cmd *);
+extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
+ struct se_device *, struct se_port *,
+ struct se_node_acl *, int, int);
+extern char *core_alua_dump_status(int);
+extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int);
+extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16);
+extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *);
+extern void core_alua_free_lu_gp_mem(struct se_device *);
+extern struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *);
+extern void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *);
+extern void __core_alua_attach_lu_gp_mem(struct t10_alua_lu_gp_member *,
+ struct t10_alua_lu_gp *);
+extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *,
+ struct t10_alua_lu_gp *);
+extern void core_alua_drop_lu_gp_dev(struct se_device *);
+extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
+ struct se_subsystem_dev *, const char *, int);
+extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16);
+extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
+ struct se_port *);
+extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *);
+extern void core_alua_free_tg_pt_gp_mem(struct se_port *);
+extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *,
+ struct t10_alua_tg_pt_gp *);
+extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *);
+extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *,
+ size_t);
+extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *);
+extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_offline_bit(struct se_lun *, char *);
+extern ssize_t core_alua_store_offline_bit(struct se_lun *, const char *,
+ size_t);
+extern ssize_t core_alua_show_secondary_status(struct se_lun *, char *);
+extern ssize_t core_alua_store_secondary_status(struct se_lun *,
+ const char *, size_t);
+extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *,
+ char *);
+extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *,
+ const char *, size_t);
+extern int core_setup_alua(struct se_device *, int);
+
+#endif /* TARGET_CORE_ALUA_H */
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
new file mode 100644
index 000000000000..366080baf474
--- /dev/null
+++ b/drivers/target/target_core_cdb.c
@@ -0,0 +1,1131 @@
+/*
+ * CDB emulation for non-READ/WRITE commands.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include "target_core_ua.h"
+
+static void
+target_fill_alua_data(struct se_port *port, unsigned char *buf)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ /*
+ * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS.
+ */
+ buf[5] = 0x80;
+
+ /*
+ * Set TPGS field for explict and/or implict ALUA access type
+ * and opteration.
+ *
+ * See spc4r17 section 6.4.2 Table 135
+ */
+ if (!port)
+ return;
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!tg_pt_gp_mem)
+ return;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (tg_pt_gp)
+ buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+}
+
+static int
+target_emulate_inquiry_std(struct se_cmd *cmd)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+
+ /*
+ * Make sure we at least have 6 bytes of INQUIRY response
+ * payload going back for EVPD=0
+ */
+ if (cmd->data_length < 6) {
+ printk(KERN_ERR "SCSI Inquiry payload length: %u"
+ " too small for EVPD=0\n", cmd->data_length);
+ return -1;
+ }
+
+ buf[0] = dev->transport->get_device_type(dev);
+ if (buf[0] == TYPE_TAPE)
+ buf[1] = 0x80;
+ buf[2] = dev->transport->get_device_rev(dev);
+
+ /*
+ * Enable SCCS and TPGS fields for Emulated ALUA
+ */
+ if (T10_ALUA(dev->se_sub_dev)->alua_type == SPC3_ALUA_EMULATED)
+ target_fill_alua_data(lun->lun_sep, buf);
+
+ if (cmd->data_length < 8) {
+ buf[4] = 1; /* Set additional length to 1 */
+ return 0;
+ }
+
+ buf[7] = 0x32; /* Sync=1 and CmdQue=1 */
+
+ /*
+ * Do not include vendor, product, reversion info in INQUIRY
+ * response payload for cdbs with a small allocation length.
+ */
+ if (cmd->data_length < 36) {
+ buf[4] = 3; /* Set additional length to 3 */
+ return 0;
+ }
+
+ snprintf((unsigned char *)&buf[8], 8, "LIO-ORG");
+ snprintf((unsigned char *)&buf[16], 16, "%s",
+ &DEV_T10_WWN(dev)->model[0]);
+ snprintf((unsigned char *)&buf[32], 4, "%s",
+ &DEV_T10_WWN(dev)->revision[0]);
+ buf[4] = 31; /* Set additional length to 31 */
+ return 0;
+}
+
+/* supported vital product data pages */
+static int
+target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
+{
+ buf[1] = 0x00;
+ if (cmd->data_length < 8)
+ return 0;
+
+ buf[4] = 0x0;
+ /*
+ * Only report the INQUIRY EVPD=1 pages after a valid NAA
+ * Registered Extended LUN WWN has been set via ConfigFS
+ * during device creation/restart.
+ */
+ if (SE_DEV(cmd)->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ buf[3] = 3;
+ buf[5] = 0x80;
+ buf[6] = 0x83;
+ buf[7] = 0x86;
+ }
+
+ return 0;
+}
+
+/* unit serial number */
+static int
+target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ u16 len = 0;
+
+ buf[1] = 0x80;
+ if (dev->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ u32 unit_serial_len;
+
+ unit_serial_len =
+ strlen(&DEV_T10_WWN(dev)->unit_serial[0]);
+ unit_serial_len++; /* For NULL Terminator */
+
+ if (((len + 4) + unit_serial_len) > cmd->data_length) {
+ len += unit_serial_len;
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff);
+ return 0;
+ }
+ len += sprintf((unsigned char *)&buf[4], "%s",
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ len++; /* Extra Byte for NULL Terminator */
+ buf[3] = len;
+ }
+ return 0;
+}
+
+/*
+ * Device identification VPD, for a complete list of
+ * DESIGNATOR TYPEs see spc4r17 Table 459.
+ */
+static int
+target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_port *port = NULL;
+ struct se_portal_group *tpg = NULL;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char binary, binary_new;
+ unsigned char *prod = &DEV_T10_WWN(dev)->model[0];
+ u32 prod_len;
+ u32 unit_serial_len, off = 0;
+ int i;
+ u16 len = 0, id_len;
+
+ buf[1] = 0x83;
+ off = 4;
+
+ /*
+ * NAA IEEE Registered Extended Assigned designator format, see
+ * spc4r17 section 7.7.3.6.5
+ *
+ * We depend upon a target_core_mod/ConfigFS provided
+ * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial
+ * value in order to return the NAA id.
+ */
+ if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL))
+ goto check_t10_vend_desc;
+
+ if (off + 20 > cmd->data_length)
+ goto check_t10_vend_desc;
+
+ /* CODE SET == Binary */
+ buf[off++] = 0x1;
+
+ /* Set ASSOICATION == addressed logical unit: 0)b */
+ buf[off] = 0x00;
+
+ /* Identifier/Designator type == NAA identifier */
+ buf[off++] = 0x3;
+ off++;
+
+ /* Identifier/Designator length */
+ buf[off++] = 0x10;
+
+ /*
+ * Start NAA IEEE Registered Extended Identifier/Designator
+ */
+ buf[off++] = (0x6 << 4);
+
+ /*
+ * Use OpenFabrics IEEE Company ID: 00 14 05
+ */
+ buf[off++] = 0x01;
+ buf[off++] = 0x40;
+ buf[off] = (0x5 << 4);
+
+ /*
+ * Return ConfigFS Unit Serial Number information for
+ * VENDOR_SPECIFIC_IDENTIFIER and
+ * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
+ */
+ binary = transport_asciihex_to_binaryhex(
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ buf[off++] |= (binary & 0xf0) >> 4;
+ for (i = 0; i < 24; i += 2) {
+ binary_new = transport_asciihex_to_binaryhex(
+ &DEV_T10_WWN(dev)->unit_serial[i+2]);
+ buf[off] = (binary & 0x0f) << 4;
+ buf[off++] |= (binary_new & 0xf0) >> 4;
+ binary = binary_new;
+ }
+ len = 20;
+ off = (len + 4);
+
+check_t10_vend_desc:
+ /*
+ * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4
+ */
+ id_len = 8; /* For Vendor field */
+ prod_len = 4; /* For VPD Header */
+ prod_len += 8; /* For Vendor field */
+ prod_len += strlen(prod);
+ prod_len++; /* For : */
+
+ if (dev->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ unit_serial_len =
+ strlen(&DEV_T10_WWN(dev)->unit_serial[0]);
+ unit_serial_len++; /* For NULL Terminator */
+
+ if ((len + (id_len + 4) +
+ (prod_len + unit_serial_len)) >
+ cmd->data_length) {
+ len += (prod_len + unit_serial_len);
+ goto check_port;
+ }
+ id_len += sprintf((unsigned char *)&buf[off+12],
+ "%s:%s", prod,
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ }
+ buf[off] = 0x2; /* ASCII */
+ buf[off+1] = 0x1; /* T10 Vendor ID */
+ buf[off+2] = 0x0;
+ memcpy((unsigned char *)&buf[off+4], "LIO-ORG", 8);
+ /* Extra Byte for NULL Terminator */
+ id_len++;
+ /* Identifier Length */
+ buf[off+3] = id_len;
+ /* Header size for Designation descriptor */
+ len += (id_len + 4);
+ off += (id_len + 4);
+ /*
+ * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD
+ */
+check_port:
+ port = lun->lun_sep;
+ if (port) {
+ struct t10_alua_lu_gp *lu_gp;
+ u32 padding, scsi_name_len;
+ u16 lu_gp_id = 0;
+ u16 tg_pt_gp_id = 0;
+ u16 tpgt;
+
+ tpg = port->sep_tpg;
+ /*
+ * Relative target port identifer, see spc4r17
+ * section 7.7.3.7
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_tpgi;
+ }
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == Relative target port identifer */
+ buf[off++] |= 0x4;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ /* Skip over Obsolete field in RTPI payload
+ * in Table 472 */
+ off += 2;
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * Target port group identifier, see spc4r17
+ * section 7.7.3.8
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+check_tpgi:
+ if (T10_ALUA(dev->se_sub_dev)->alua_type !=
+ SPC3_ALUA_EMULATED)
+ goto check_scsi_name;
+
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_lu_gp;
+ }
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!tg_pt_gp_mem)
+ goto check_lu_gp;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (!(tg_pt_gp)) {
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ goto check_lu_gp;
+ }
+ tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == Target port group identifier */
+ buf[off++] |= 0x5;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ off += 2; /* Skip over Reserved Field */
+ buf[off++] = ((tg_pt_gp_id >> 8) & 0xff);
+ buf[off++] = (tg_pt_gp_id & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * Logical Unit Group identifier, see spc4r17
+ * section 7.7.3.8
+ */
+check_lu_gp:
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_scsi_name;
+ }
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem))
+ goto check_scsi_name;
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if (!(lu_gp)) {
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+ goto check_scsi_name;
+ }
+ lu_gp_id = lu_gp->lu_gp_id;
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ /* DESIGNATOR TYPE == Logical Unit Group identifier */
+ buf[off++] |= 0x6;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ off += 2; /* Skip over Reserved Field */
+ buf[off++] = ((lu_gp_id >> 8) & 0xff);
+ buf[off++] = (lu_gp_id & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * SCSI name string designator, see spc4r17
+ * section 7.7.3.11
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+check_scsi_name:
+ scsi_name_len = strlen(TPG_TFO(tpg)->tpg_get_wwn(tpg));
+ /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
+ scsi_name_len += 10;
+ /* Check for 4-byte padding */
+ padding = ((-scsi_name_len) & 3);
+ if (padding != 0)
+ scsi_name_len += padding;
+ /* Header size + Designation descriptor */
+ scsi_name_len += 4;
+
+ if (((len + 4) + scsi_name_len) > cmd->data_length) {
+ len += scsi_name_len;
+ goto set_len;
+ }
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x3; /* CODE SET == UTF-8 */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == SCSI name string */
+ buf[off++] |= 0x8;
+ off += 2; /* Skip over Reserved and length */
+ /*
+ * SCSI name string identifer containing, $FABRIC_MOD
+ * dependent information. For LIO-Target and iSCSI
+ * Target Port, this means "<iSCSI name>,t,0x<TPGT> in
+ * UTF-8 encoding.
+ */
+ tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg);
+ scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg), tpgt);
+ scsi_name_len += 1 /* Include NULL terminator */;
+ /*
+ * The null-terminated, null-padded (see 4.4.2) SCSI
+ * NAME STRING field contains a UTF-8 format string.
+ * The number of bytes in the SCSI NAME STRING field
+ * (i.e., the value in the DESIGNATOR LENGTH field)
+ * shall be no larger than 256 and shall be a multiple
+ * of four.
+ */
+ if (padding)
+ scsi_name_len += padding;
+
+ buf[off-1] = scsi_name_len;
+ off += scsi_name_len;
+ /* Header size + Designation descriptor */
+ len += (scsi_name_len + 4);
+ }
+set_len:
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
+ return 0;
+}
+
+/* Extended INQUIRY Data VPD Page */
+static int
+target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
+{
+ if (cmd->data_length < 60)
+ return 0;
+
+ buf[1] = 0x86;
+ buf[2] = 0x3c;
+ /* Set HEADSUP, ORDSUP, SIMPSUP */
+ buf[5] = 0x07;
+
+ /* If WriteCache emulation is enabled, set V_SUP */
+ if (DEV_ATTRIB(SE_DEV(cmd))->emulate_write_cache > 0)
+ buf[6] = 0x01;
+ return 0;
+}
+
+/* Block Limits VPD page */
+static int
+target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ int have_tp = 0;
+
+ /*
+ * Following sbc3r22 section 6.5.3 Block Limits VPD page, when
+ * emulate_tpu=1 or emulate_tpws=1 we will be expect a
+ * different page length for Thin Provisioning.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ have_tp = 1;
+
+ if (cmd->data_length < (0x10 + 4)) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for EVPD 0xb0\n",
+ cmd->data_length);
+ return -1;
+ }
+
+ if (have_tp && cmd->data_length < (0x3c + 4)) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for TPE=1 EVPD 0xb0\n",
+ cmd->data_length);
+ have_tp = 0;
+ }
+
+ buf[0] = dev->transport->get_device_type(dev);
+ buf[1] = 0xb0;
+ buf[3] = have_tp ? 0x3c : 0x10;
+
+ /*
+ * Set OPTIMAL TRANSFER LENGTH GRANULARITY
+ */
+ put_unaligned_be16(1, &buf[6]);
+
+ /*
+ * Set MAXIMUM TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_sectors, &buf[8]);
+
+ /*
+ * Set OPTIMAL TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->optimal_sectors, &buf[12]);
+
+ /*
+ * Exit now if we don't support TP or the initiator sent a too
+ * short buffer.
+ */
+ if (!have_tp || cmd->data_length < (0x3c + 4))
+ return 0;
+
+ /*
+ * Set MAXIMUM UNMAP LBA COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_lba_count, &buf[20]);
+
+ /*
+ * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_block_desc_count,
+ &buf[24]);
+
+ /*
+ * Set OPTIMAL UNMAP GRANULARITY
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity, &buf[28]);
+
+ /*
+ * UNMAP GRANULARITY ALIGNMENT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity_alignment,
+ &buf[32]);
+ if (DEV_ATTRIB(dev)->unmap_granularity_alignment != 0)
+ buf[32] |= 0x80; /* Set the UGAVALID bit */
+
+ return 0;
+}
+
+/* Thin Provisioning VPD */
+static int
+target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ /*
+ * From sbc3r22 section 6.5.4 Thin Provisioning VPD page:
+ *
+ * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to
+ * zero, then the page length shall be set to 0004h. If the DP bit
+ * is set to one, then the page length shall be set to the value
+ * defined in table 162.
+ */
+ buf[0] = dev->transport->get_device_type(dev);
+ buf[1] = 0xb2;
+
+ /*
+ * Set Hardcoded length mentioned above for DP=0
+ */
+ put_unaligned_be16(0x0004, &buf[2]);
+
+ /*
+ * The THRESHOLD EXPONENT field indicates the threshold set size in
+ * LBAs as a power of 2 (i.e., the threshold set size is equal to
+ * 2(threshold exponent)).
+ *
+ * Note that this is currently set to 0x00 as mkp says it will be
+ * changing again. We can enable this once it has settled in T10
+ * and is actually used by Linux/SCSI ML code.
+ */
+ buf[4] = 0x00;
+
+ /*
+ * A TPU bit set to one indicates that the device server supports
+ * the UNMAP command (see 5.25). A TPU bit set to zero indicates
+ * that the device server does not support the UNMAP command.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu != 0)
+ buf[5] = 0x80;
+
+ /*
+ * A TPWS bit set to one indicates that the device server supports
+ * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs.
+ * A TPWS bit set to zero indicates that the device server does not
+ * support the use of the WRITE SAME (16) command to unmap LBAs.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpws != 0)
+ buf[5] |= 0x40;
+
+ return 0;
+}
+
+static int
+target_emulate_inquiry(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ unsigned char *cdb = cmd->t_task->t_task_cdb;
+
+ if (!(cdb[1] & 0x1))
+ return target_emulate_inquiry_std(cmd);
+
+ /*
+ * Make sure we at least have 4 bytes of INQUIRY response
+ * payload for 0x00 going back for EVPD=1. Note that 0x80
+ * and 0x83 will check for enough payload data length and
+ * jump to set_len: label when there is not enough inquiry EVPD
+ * payload length left for the next outgoing EVPD metadata
+ */
+ if (cmd->data_length < 4) {
+ printk(KERN_ERR "SCSI Inquiry payload length: %u"
+ " too small for EVPD=1\n", cmd->data_length);
+ return -1;
+ }
+ buf[0] = dev->transport->get_device_type(dev);
+
+ switch (cdb[2]) {
+ case 0x00:
+ return target_emulate_evpd_00(cmd, buf);
+ case 0x80:
+ return target_emulate_evpd_80(cmd, buf);
+ case 0x83:
+ return target_emulate_evpd_83(cmd, buf);
+ case 0x86:
+ return target_emulate_evpd_86(cmd, buf);
+ case 0xb0:
+ return target_emulate_evpd_b0(cmd, buf);
+ case 0xb2:
+ return target_emulate_evpd_b2(cmd, buf);
+ default:
+ printk(KERN_ERR "Unknown VPD Code: 0x%02x\n", cdb[2]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+target_emulate_readcapacity(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ u32 blocks = dev->transport->get_blocks(dev);
+
+ buf[0] = (blocks >> 24) & 0xff;
+ buf[1] = (blocks >> 16) & 0xff;
+ buf[2] = (blocks >> 8) & 0xff;
+ buf[3] = blocks & 0xff;
+ buf[4] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff;
+ buf[5] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
+ buf[6] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
+ buf[7] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set max 32-bit blocks to signal SERVICE ACTION READ_CAPACITY_16
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ put_unaligned_be32(0xFFFFFFFF, &buf[0]);
+
+ return 0;
+}
+
+static int
+target_emulate_readcapacity_16(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ unsigned long long blocks = dev->transport->get_blocks(dev);
+
+ buf[0] = (blocks >> 56) & 0xff;
+ buf[1] = (blocks >> 48) & 0xff;
+ buf[2] = (blocks >> 40) & 0xff;
+ buf[3] = (blocks >> 32) & 0xff;
+ buf[4] = (blocks >> 24) & 0xff;
+ buf[5] = (blocks >> 16) & 0xff;
+ buf[6] = (blocks >> 8) & 0xff;
+ buf[7] = blocks & 0xff;
+ buf[8] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff;
+ buf[9] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
+ buf[10] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
+ buf[11] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set Thin Provisioning Enable bit following sbc3r22 in section
+ * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ buf[14] = 0x80;
+
+ return 0;
+}
+
+static int
+target_modesense_rwrecovery(unsigned char *p)
+{
+ p[0] = 0x01;
+ p[1] = 0x0a;
+
+ return 12;
+}
+
+static int
+target_modesense_control(struct se_device *dev, unsigned char *p)
+{
+ p[0] = 0x0a;
+ p[1] = 0x0a;
+ p[2] = 2;
+ /*
+ * From spc4r17, section 7.4.6 Control mode Page
+ *
+ * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b
+ *
+ * 00b: The logical unit shall clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall not establish a unit attention condition when a com-
+ * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT
+ * status.
+ *
+ * 10b: The logical unit shall not clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall not establish a unit attention condition when
+ * a command is completed with BUSY, TASK SET FULL, or RESERVATION
+ * CONFLICT status.
+ *
+ * 11b a The logical unit shall not clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall establish a unit attention condition for the
+ * initiator port associated with the I_T nexus on which the BUSY,
+ * TASK SET FULL, or RESERVATION CONFLICT status is being returned.
+ * Depending on the status, the additional sense code shall be set to
+ * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS
+ * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE
+ * command, a unit attention condition shall be established only once
+ * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless
+ * to the number of commands completed with one of those status codes.
+ */
+ p[4] = (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 2) ? 0x30 :
+ (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00;
+ /*
+ * From spc4r17, section 7.4.6 Control mode Page
+ *
+ * Task Aborted Status (TAS) bit set to zero.
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ p[5] = (DEV_ATTRIB(dev)->emulate_tas) ? 0x40 : 0x00;
+ p[8] = 0xff;
+ p[9] = 0xff;
+ p[11] = 30;
+
+ return 12;
+}
+
+static int
+target_modesense_caching(struct se_device *dev, unsigned char *p)
+{
+ p[0] = 0x08;
+ p[1] = 0x12;
+ if (DEV_ATTRIB(dev)->emulate_write_cache > 0)
+ p[2] = 0x04; /* Write Cache Enable */
+ p[12] = 0x20; /* Disabled Read Ahead */
+
+ return 20;
+}
+
+static void
+target_modesense_write_protect(unsigned char *buf, int type)
+{
+ /*
+ * I believe that the WP bit (bit 7) in the mode header is the same for
+ * all device types..
+ */
+ switch (type) {
+ case TYPE_DISK:
+ case TYPE_TAPE:
+ default:
+ buf[0] |= 0x80; /* WP bit */
+ break;
+ }
+}
+
+static void
+target_modesense_dpofua(unsigned char *buf, int type)
+{
+ switch (type) {
+ case TYPE_DISK:
+ buf[0] |= 0x10; /* DPOFUA bit */
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+target_emulate_modesense(struct se_cmd *cmd, int ten)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ char *cdb = cmd->t_task->t_task_cdb;
+ unsigned char *rbuf = cmd->t_task->t_task_buf;
+ int type = dev->transport->get_device_type(dev);
+ int offset = (ten) ? 8 : 4;
+ int length = 0;
+ unsigned char buf[SE_MODE_PAGE_BUF];
+
+ memset(buf, 0, SE_MODE_PAGE_BUF);
+
+ switch (cdb[2] & 0x3f) {
+ case 0x01:
+ length = target_modesense_rwrecovery(&buf[offset]);
+ break;
+ case 0x08:
+ length = target_modesense_caching(dev, &buf[offset]);
+ break;
+ case 0x0a:
+ length = target_modesense_control(dev, &buf[offset]);
+ break;
+ case 0x3f:
+ length = target_modesense_rwrecovery(&buf[offset]);
+ length += target_modesense_caching(dev, &buf[offset+length]);
+ length += target_modesense_control(dev, &buf[offset+length]);
+ break;
+ default:
+ printk(KERN_ERR "Got Unknown Mode Page: 0x%02x\n",
+ cdb[2] & 0x3f);
+ return PYX_TRANSPORT_UNKNOWN_MODE_PAGE;
+ }
+ offset += length;
+
+ if (ten) {
+ offset -= 2;
+ buf[0] = (offset >> 8) & 0xff;
+ buf[1] = offset & 0xff;
+
+ if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+ (cmd->se_deve &&
+ (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+ target_modesense_write_protect(&buf[3], type);
+
+ if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) &&
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0))
+ target_modesense_dpofua(&buf[3], type);
+
+ if ((offset + 2) > cmd->data_length)
+ offset = cmd->data_length;
+
+ } else {
+ offset -= 1;
+ buf[0] = offset & 0xff;
+
+ if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+ (cmd->se_deve &&
+ (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+ target_modesense_write_protect(&buf[2], type);
+
+ if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) &&
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0))
+ target_modesense_dpofua(&buf[2], type);
+
+ if ((offset + 1) > cmd->data_length)
+ offset = cmd->data_length;
+ }
+ memcpy(rbuf, buf, offset);
+
+ return 0;
+}
+
+static int
+target_emulate_request_sense(struct se_cmd *cmd)
+{
+ unsigned char *cdb = cmd->t_task->t_task_cdb;
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ u8 ua_asc = 0, ua_ascq = 0;
+
+ if (cdb[1] & 0x01) {
+ printk(KERN_ERR "REQUEST_SENSE description emulation not"
+ " supported\n");
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+ if (!(core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq))) {
+ /*
+ * CURRENT ERROR, UNIT ATTENTION
+ */
+ buf[0] = 0x70;
+ buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+ /*
+ * Make sure request data length is enough for additional
+ * sense data.
+ */
+ if (cmd->data_length <= 18) {
+ buf[7] = 0x00;
+ return 0;
+ }
+ /*
+ * The Additional Sense Code (ASC) from the UNIT ATTENTION
+ */
+ buf[SPC_ASC_KEY_OFFSET] = ua_asc;
+ buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq;
+ buf[7] = 0x0A;
+ } else {
+ /*
+ * CURRENT ERROR, NO SENSE
+ */
+ buf[0] = 0x70;
+ buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
+ /*
+ * Make sure request data length is enough for additional
+ * sense data.
+ */
+ if (cmd->data_length <= 18) {
+ buf[7] = 0x00;
+ return 0;
+ }
+ /*
+ * NO ADDITIONAL SENSE INFORMATION
+ */
+ buf[SPC_ASC_KEY_OFFSET] = 0x00;
+ buf[7] = 0x0A;
+ }
+
+ return 0;
+}
+
+/*
+ * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
+ * Note this is not used for TCM/pSCSI passthrough
+ */
+static int
+target_emulate_unmap(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf, *ptr = NULL;
+ unsigned char *cdb = &cmd->t_task->t_task_cdb[0];
+ sector_t lba;
+ unsigned int size = cmd->data_length, range;
+ int ret, offset;
+ unsigned short dl, bd_dl;
+
+ /* First UNMAP block descriptor starts at 8 byte offset */
+ offset = 8;
+ size -= 8;
+ dl = get_unaligned_be16(&cdb[0]);
+ bd_dl = get_unaligned_be16(&cdb[2]);
+ ptr = &buf[offset];
+ printk(KERN_INFO "UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
+ " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
+
+ while (size) {
+ lba = get_unaligned_be64(&ptr[0]);
+ range = get_unaligned_be32(&ptr[8]);
+ printk(KERN_INFO "UNMAP: Using lba: %llu and range: %u\n",
+ (unsigned long long)lba, range);
+
+ ret = dev->transport->do_discard(dev, lba, range);
+ if (ret < 0) {
+ printk(KERN_ERR "blkdev_issue_discard() failed: %d\n",
+ ret);
+ return -1;
+ }
+
+ ptr += 16;
+ size -= 16;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
+}
+
+/*
+ * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
+ * Note this is not used for TCM/pSCSI passthrough
+ */
+static int
+target_emulate_write_same(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ sector_t lba = cmd->t_task->t_task_lba;
+ unsigned int range;
+ int ret;
+
+ range = (cmd->data_length / DEV_ATTRIB(dev)->block_size);
+
+ printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %u\n",
+ (unsigned long long)lba, range);
+
+ ret = dev->transport->do_discard(dev, lba, range);
+ if (ret < 0) {
+ printk(KERN_INFO "blkdev_issue_discard() failed for WRITE_SAME\n");
+ return -1;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
+}
+
+int
+transport_emulate_control_cdb(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned short service_action;
+ int ret = 0;
+
+ switch (cmd->t_task->t_task_cdb[0]) {
+ case INQUIRY:
+ ret = target_emulate_inquiry(cmd);
+ break;
+ case READ_CAPACITY:
+ ret = target_emulate_readcapacity(cmd);
+ break;
+ case MODE_SENSE:
+ ret = target_emulate_modesense(cmd, 0);
+ break;
+ case MODE_SENSE_10:
+ ret = target_emulate_modesense(cmd, 1);
+ break;
+ case SERVICE_ACTION_IN:
+ switch (cmd->t_task->t_task_cdb[1] & 0x1f) {
+ case SAI_READ_CAPACITY_16:
+ ret = target_emulate_readcapacity_16(cmd);
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ cmd->t_task->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ break;
+ case REQUEST_SENSE:
+ ret = target_emulate_request_sense(cmd);
+ break;
+ case UNMAP:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "UNMAP emulation not supported for: %s\n",
+ dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_unmap(task);
+ break;
+ case WRITE_SAME_16:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "WRITE_SAME_16 emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task);
+ break;
+ case VARIABLE_LENGTH_CMD:
+ service_action =
+ get_unaligned_be16(&cmd->t_task->t_task_cdb[8]);
+ switch (service_action) {
+ case WRITE_SAME_32:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "WRITE_SAME_32 SA emulation not"
+ " supported for: %s\n",
+ dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task);
+ break;
+ default:
+ printk(KERN_ERR "Unsupported VARIABLE_LENGTH_CMD SA:"
+ " 0x%02x\n", service_action);
+ break;
+ }
+ break;
+ case SYNCHRONIZE_CACHE:
+ case 0x91: /* SYNCHRONIZE_CACHE_16: */
+ if (!dev->transport->do_sync_cache) {
+ printk(KERN_ERR
+ "SYNCHRONIZE_CACHE emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ dev->transport->do_sync_cache(task);
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for %s\n",
+ cmd->t_task->t_task_cdb[0], dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ if (ret < 0)
+ return ret;
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
new file mode 100644
index 000000000000..2764510798b0
--- /dev/null
+++ b/drivers/target/target_core_configfs.c
@@ -0,0 +1,3225 @@
+/*******************************************************************************
+ * Filename: target_core_configfs.c
+ *
+ * This file contains ConfigFS logic for the Generic Target Engine project.
+ *
+ * Copyright (c) 2008-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * based on configfs Copyright (C) 2005 Oracle. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/syscalls.h>
+#include <linux/configfs.h>
+#include <linux/proc_fs.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_rd.h"
+
+static struct list_head g_tf_list;
+static struct mutex g_tf_lock;
+
+struct target_core_configfs_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(void *, char *);
+ ssize_t (*store)(void *, const char *, size_t);
+};
+
+static inline struct se_hba *
+item_to_hba(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_hba, hba_group);
+}
+
+/*
+ * Attributes for /sys/kernel/config/target/
+ */
+static ssize_t target_core_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s"
+ " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION,
+ utsname()->sysname, utsname()->machine);
+}
+
+static struct configfs_item_operations target_core_fabric_item_ops = {
+ .show_attribute = target_core_attr_show,
+};
+
+static struct configfs_attribute target_core_item_attr_version = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "version",
+ .ca_mode = S_IRUGO,
+};
+
+static struct target_fabric_configfs *target_core_get_fabric(
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+
+ if (!(name))
+ return NULL;
+
+ mutex_lock(&g_tf_lock);
+ list_for_each_entry(tf, &g_tf_list, tf_list) {
+ if (!(strcmp(tf->tf_name, name))) {
+ atomic_inc(&tf->tf_access_cnt);
+ mutex_unlock(&g_tf_lock);
+ return tf;
+ }
+ }
+ mutex_unlock(&g_tf_lock);
+
+ return NULL;
+}
+
+/*
+ * Called from struct target_core_group_ops->make_group()
+ */
+static struct config_group *target_core_register_fabric(
+ struct config_group *group,
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+ int ret;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> group: %p name:"
+ " %s\n", group, name);
+ /*
+ * Ensure that TCM subsystem plugins are loaded at this point for
+ * using the RAMDISK_DR virtual LUN 0 and all other struct se_port
+ * LUN symlinks.
+ */
+ if (transport_subsystem_check_init() < 0)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Below are some hardcoded request_module() calls to automatically
+ * local fabric modules when the following is called:
+ *
+ * mkdir -p /sys/kernel/config/target/$MODULE_NAME
+ *
+ * Note that this does not limit which TCM fabric module can be
+ * registered, but simply provids auto loading logic for modules with
+ * mkdir(2) system calls with known TCM fabric modules.
+ */
+ if (!(strncmp(name, "iscsi", 5))) {
+ /*
+ * Automatically load the LIO Target fabric module when the
+ * following is called:
+ *
+ * mkdir -p $CONFIGFS/target/iscsi
+ */
+ ret = request_module("iscsi_target_mod");
+ if (ret < 0) {
+ printk(KERN_ERR "request_module() failed for"
+ " iscsi_target_mod.ko: %d\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ } else if (!(strncmp(name, "loopback", 8))) {
+ /*
+ * Automatically load the tcm_loop fabric module when the
+ * following is called:
+ *
+ * mkdir -p $CONFIGFS/target/loopback
+ */
+ ret = request_module("tcm_loop");
+ if (ret < 0) {
+ printk(KERN_ERR "request_module() failed for"
+ " tcm_loop.ko: %d\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ tf = target_core_get_fabric(name);
+ if (!(tf)) {
+ printk(KERN_ERR "target_core_get_fabric() failed for %s\n",
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Located fabric:"
+ " %s\n", tf->tf_name);
+ /*
+ * On a successful target_core_get_fabric() look, the returned
+ * struct target_fabric_configfs *tf will contain a usage reference.
+ */
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n",
+ &TF_CIT_TMPL(tf)->tfc_wwn_cit);
+
+ tf->tf_group.default_groups = tf->tf_default_groups;
+ tf->tf_group.default_groups[0] = &tf->tf_disc_group;
+ tf->tf_group.default_groups[1] = NULL;
+
+ config_group_init_type_name(&tf->tf_group, name,
+ &TF_CIT_TMPL(tf)->tfc_wwn_cit);
+ config_group_init_type_name(&tf->tf_disc_group, "discovery_auth",
+ &TF_CIT_TMPL(tf)->tfc_discovery_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
+ " %s\n", tf->tf_group.cg_item.ci_name);
+ /*
+ * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item()
+ */
+ tf->tf_ops.tf_subsys = tf->tf_subsys;
+ tf->tf_fabric = &tf->tf_group.cg_item;
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric"
+ " for %s\n", name);
+
+ return &tf->tf_group;
+}
+
+/*
+ * Called from struct target_core_group_ops->drop_item()
+ */
+static void target_core_deregister_fabric(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct target_fabric_configfs *tf = container_of(
+ to_config_group(item), struct target_fabric_configfs, tf_group);
+ struct config_group *tf_group;
+ struct config_item *df_item;
+ int i;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Looking up %s in"
+ " tf list\n", config_item_name(item));
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> located fabric:"
+ " %s\n", tf->tf_name);
+ atomic_dec(&tf->tf_access_cnt);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing"
+ " tf->tf_fabric for %s\n", tf->tf_name);
+ tf->tf_fabric = NULL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing ci"
+ " %s\n", config_item_name(item));
+
+ tf_group = &tf->tf_group;
+ for (i = 0; tf_group->default_groups[i]; i++) {
+ df_item = &tf_group->default_groups[i]->cg_item;
+ tf_group->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+ config_item_put(item);
+}
+
+static struct configfs_group_operations target_core_fabric_group_ops = {
+ .make_group = &target_core_register_fabric,
+ .drop_item = &target_core_deregister_fabric,
+};
+
+/*
+ * All item attributes appearing in /sys/kernel/target/ appear here.
+ */
+static struct configfs_attribute *target_core_fabric_item_attrs[] = {
+ &target_core_item_attr_version,
+ NULL,
+};
+
+/*
+ * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/
+ */
+static struct config_item_type target_core_fabrics_item = {
+ .ct_item_ops = &target_core_fabric_item_ops,
+ .ct_group_ops = &target_core_fabric_group_ops,
+ .ct_attrs = target_core_fabric_item_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem target_core_fabrics = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "target",
+ .ci_type = &target_core_fabrics_item,
+ },
+ },
+};
+
+static struct configfs_subsystem *target_core_subsystem[] = {
+ &target_core_fabrics,
+ NULL,
+};
+
+/*##############################################################################
+// Start functions called by external Target Fabrics Modules
+//############################################################################*/
+
+/*
+ * First function called by fabric modules to:
+ *
+ * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer.
+ * 2) Add struct target_fabric_configfs to g_tf_list
+ * 3) Return struct target_fabric_configfs to fabric module to be passed
+ * into target_fabric_configfs_register().
+ */
+struct target_fabric_configfs *target_fabric_configfs_init(
+ struct module *fabric_mod,
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+
+ if (!(fabric_mod)) {
+ printk(KERN_ERR "Missing struct module *fabric_mod pointer\n");
+ return NULL;
+ }
+ if (!(name)) {
+ printk(KERN_ERR "Unable to locate passed fabric name\n");
+ return NULL;
+ }
+ if (strlen(name) > TARGET_FABRIC_NAME_SIZE) {
+ printk(KERN_ERR "Passed name: %s exceeds TARGET_FABRIC"
+ "_NAME_SIZE\n", name);
+ return NULL;
+ }
+
+ tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
+ if (!(tf))
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&tf->tf_list);
+ atomic_set(&tf->tf_access_cnt, 0);
+ /*
+ * Setup the default generic struct config_item_type's (cits) in
+ * struct target_fabric_configfs->tf_cit_tmpl
+ */
+ tf->tf_module = fabric_mod;
+ target_fabric_setup_cits(tf);
+
+ tf->tf_subsys = target_core_subsystem[0];
+ snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name);
+
+ mutex_lock(&g_tf_lock);
+ list_add_tail(&tf->tf_list, &g_tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>"
+ ">>>>>>>>>>>>>>\n");
+ printk(KERN_INFO "Initialized struct target_fabric_configfs: %p for"
+ " %s\n", tf, tf->tf_name);
+ return tf;
+}
+EXPORT_SYMBOL(target_fabric_configfs_init);
+
+/*
+ * Called by fabric plugins after FAILED target_fabric_configfs_register() call.
+ */
+void target_fabric_configfs_free(
+ struct target_fabric_configfs *tf)
+{
+ mutex_lock(&g_tf_lock);
+ list_del(&tf->tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ kfree(tf);
+}
+EXPORT_SYMBOL(target_fabric_configfs_free);
+
+/*
+ * Perform a sanity check of the passed tf->tf_ops before completing
+ * TCM fabric module registration.
+ */
+static int target_fabric_tf_ops_check(
+ struct target_fabric_configfs *tf)
+{
+ struct target_core_fabric_ops *tfo = &tf->tf_ops;
+
+ if (!(tfo->get_fabric_name)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_name()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_fabric_proto_ident)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_proto_ident()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_wwn)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_tag)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_tag()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_default_depth)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_default_depth()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_pr_transport_id)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_pr_transport_id_len)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode_cache)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_cache()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode_write_protect)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_write_protect()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_prod_mode_write_protect)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_prod_mode_write_protect()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_alloc_fabric_acl)) {
+ printk(KERN_ERR "Missing tfo->tpg_alloc_fabric_acl()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_release_fabric_acl)) {
+ printk(KERN_ERR "Missing tfo->tpg_release_fabric_acl()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_inst_index)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_inst_index()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->release_cmd_to_pool)) {
+ printk(KERN_ERR "Missing tfo->release_cmd_to_pool()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->release_cmd_direct)) {
+ printk(KERN_ERR "Missing tfo->release_cmd_direct()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->shutdown_session)) {
+ printk(KERN_ERR "Missing tfo->shutdown_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->close_session)) {
+ printk(KERN_ERR "Missing tfo->close_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->stop_session)) {
+ printk(KERN_ERR "Missing tfo->stop_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fall_back_to_erl0)) {
+ printk(KERN_ERR "Missing tfo->fall_back_to_erl0()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->sess_logged_in)) {
+ printk(KERN_ERR "Missing tfo->sess_logged_in()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->sess_get_index)) {
+ printk(KERN_ERR "Missing tfo->sess_get_index()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->write_pending)) {
+ printk(KERN_ERR "Missing tfo->write_pending()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->write_pending_status)) {
+ printk(KERN_ERR "Missing tfo->write_pending_status()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->set_default_node_attributes)) {
+ printk(KERN_ERR "Missing tfo->set_default_node_attributes()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_task_tag)) {
+ printk(KERN_ERR "Missing tfo->get_task_tag()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_cmd_state)) {
+ printk(KERN_ERR "Missing tfo->get_cmd_state()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->new_cmd_failure)) {
+ printk(KERN_ERR "Missing tfo->new_cmd_failure()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_data_in)) {
+ printk(KERN_ERR "Missing tfo->queue_data_in()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_status)) {
+ printk(KERN_ERR "Missing tfo->queue_status()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_tm_rsp)) {
+ printk(KERN_ERR "Missing tfo->queue_tm_rsp()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->set_fabric_sense_len)) {
+ printk(KERN_ERR "Missing tfo->set_fabric_sense_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_fabric_sense_len)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_sense_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->is_state_remove)) {
+ printk(KERN_ERR "Missing tfo->is_state_remove()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->pack_lun)) {
+ printk(KERN_ERR "Missing tfo->pack_lun()\n");
+ return -EINVAL;
+ }
+ /*
+ * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
+ * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
+ * target_core_fabric_configfs.c WWN+TPG group context code.
+ */
+ if (!(tfo->fabric_make_wwn)) {
+ printk(KERN_ERR "Missing tfo->fabric_make_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_drop_wwn)) {
+ printk(KERN_ERR "Missing tfo->fabric_drop_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_make_tpg)) {
+ printk(KERN_ERR "Missing tfo->fabric_make_tpg()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_drop_tpg)) {
+ printk(KERN_ERR "Missing tfo->fabric_drop_tpg()\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Called 2nd from fabric module with returned parameter of
+ * struct target_fabric_configfs * from target_fabric_configfs_init().
+ *
+ * Upon a successful registration, the new fabric's struct config_item is
+ * return. Also, a pointer to this struct is set in the passed
+ * struct target_fabric_configfs.
+ */
+int target_fabric_configfs_register(
+ struct target_fabric_configfs *tf)
+{
+ struct config_group *su_group;
+ int ret;
+
+ if (!(tf)) {
+ printk(KERN_ERR "Unable to locate target_fabric_configfs"
+ " pointer\n");
+ return -EINVAL;
+ }
+ if (!(tf->tf_subsys)) {
+ printk(KERN_ERR "Unable to target struct config_subsystem"
+ " pointer\n");
+ return -EINVAL;
+ }
+ su_group = &tf->tf_subsys->su_group;
+ if (!(su_group)) {
+ printk(KERN_ERR "Unable to locate target struct config_group"
+ " pointer\n");
+ return -EINVAL;
+ }
+ ret = target_fabric_tf_ops_check(tf);
+ if (ret < 0)
+ return ret;
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
+ ">>>>>>>>>>\n");
+ return 0;
+}
+EXPORT_SYMBOL(target_fabric_configfs_register);
+
+void target_fabric_configfs_deregister(
+ struct target_fabric_configfs *tf)
+{
+ struct config_group *su_group;
+ struct configfs_subsystem *su;
+
+ if (!(tf)) {
+ printk(KERN_ERR "Unable to locate passed target_fabric_"
+ "configfs\n");
+ return;
+ }
+ su = tf->tf_subsys;
+ if (!(su)) {
+ printk(KERN_ERR "Unable to locate passed tf->tf_subsys"
+ " pointer\n");
+ return;
+ }
+ su_group = &tf->tf_subsys->su_group;
+ if (!(su_group)) {
+ printk(KERN_ERR "Unable to locate target struct config_group"
+ " pointer\n");
+ return;
+ }
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
+ ">>>>>>>>>>>>\n");
+ mutex_lock(&g_tf_lock);
+ if (atomic_read(&tf->tf_access_cnt)) {
+ mutex_unlock(&g_tf_lock);
+ printk(KERN_ERR "Non zero tf->tf_access_cnt for fabric %s\n",
+ tf->tf_name);
+ BUG();
+ }
+ list_del(&tf->tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
+ " %s\n", tf->tf_name);
+ tf->tf_module = NULL;
+ tf->tf_subsys = NULL;
+ kfree(tf);
+
+ printk("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
+ ">>>>>\n");
+ return;
+}
+EXPORT_SYMBOL(target_fabric_configfs_deregister);
+
+/*##############################################################################
+// Stop functions called by external Target Fabrics Modules
+//############################################################################*/
+
+/* Start functions for struct config_item_type target_core_dev_attrib_cit */
+
+#define DEF_DEV_ATTRIB_SHOW(_name) \
+static ssize_t target_core_dev_show_attr_##_name( \
+ struct se_dev_attrib *da, \
+ char *page) \
+{ \
+ struct se_device *dev; \
+ struct se_subsystem_dev *se_dev = da->da_sub_dev; \
+ ssize_t rb; \
+ \
+ spin_lock(&se_dev->se_dev_lock); \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ return -ENODEV; \
+ } \
+ rb = snprintf(page, PAGE_SIZE, "%u\n", (u32)DEV_ATTRIB(dev)->_name); \
+ spin_unlock(&se_dev->se_dev_lock); \
+ \
+ return rb; \
+}
+
+#define DEF_DEV_ATTRIB_STORE(_name) \
+static ssize_t target_core_dev_store_attr_##_name( \
+ struct se_dev_attrib *da, \
+ const char *page, \
+ size_t count) \
+{ \
+ struct se_device *dev; \
+ struct se_subsystem_dev *se_dev = da->da_sub_dev; \
+ unsigned long val; \
+ int ret; \
+ \
+ spin_lock(&se_dev->se_dev_lock); \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ return -ENODEV; \
+ } \
+ ret = strict_strtoul(page, 0, &val); \
+ if (ret < 0) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ printk(KERN_ERR "strict_strtoul() failed with" \
+ " ret: %d\n", ret); \
+ return -EINVAL; \
+ } \
+ ret = se_dev_set_##_name(dev, (u32)val); \
+ spin_unlock(&se_dev->se_dev_lock); \
+ \
+ return (!ret) ? count : -EINVAL; \
+}
+
+#define DEF_DEV_ATTRIB(_name) \
+DEF_DEV_ATTRIB_SHOW(_name); \
+DEF_DEV_ATTRIB_STORE(_name);
+
+#define DEF_DEV_ATTRIB_RO(_name) \
+DEF_DEV_ATTRIB_SHOW(_name);
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib);
+#define SE_DEV_ATTR(_name, _mode) \
+static struct target_core_dev_attrib_attribute \
+ target_core_dev_attrib_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_show_attr_##_name, \
+ target_core_dev_store_attr_##_name);
+
+#define SE_DEV_ATTR_RO(_name); \
+static struct target_core_dev_attrib_attribute \
+ target_core_dev_attrib_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_show_attr_##_name);
+
+DEF_DEV_ATTRIB(emulate_dpo);
+SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_fua_write);
+SE_DEV_ATTR(emulate_fua_write, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_fua_read);
+SE_DEV_ATTR(emulate_fua_read, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_write_cache);
+SE_DEV_ATTR(emulate_write_cache, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_ua_intlck_ctrl);
+SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tas);
+SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tpu);
+SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tpws);
+SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(enforce_pr_isids);
+SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_block_size);
+SE_DEV_ATTR_RO(hw_block_size);
+
+DEF_DEV_ATTRIB(block_size);
+SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_max_sectors);
+SE_DEV_ATTR_RO(hw_max_sectors);
+
+DEF_DEV_ATTRIB(max_sectors);
+SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(optimal_sectors);
+SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_queue_depth);
+SE_DEV_ATTR_RO(hw_queue_depth);
+
+DEF_DEV_ATTRIB(queue_depth);
+SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(task_timeout);
+SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(max_unmap_lba_count);
+SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(max_unmap_block_desc_count);
+SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity);
+SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity_alignment);
+SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
+
+static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
+ &target_core_dev_attrib_emulate_dpo.attr,
+ &target_core_dev_attrib_emulate_fua_write.attr,
+ &target_core_dev_attrib_emulate_fua_read.attr,
+ &target_core_dev_attrib_emulate_write_cache.attr,
+ &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr,
+ &target_core_dev_attrib_emulate_tas.attr,
+ &target_core_dev_attrib_emulate_tpu.attr,
+ &target_core_dev_attrib_emulate_tpws.attr,
+ &target_core_dev_attrib_enforce_pr_isids.attr,
+ &target_core_dev_attrib_hw_block_size.attr,
+ &target_core_dev_attrib_block_size.attr,
+ &target_core_dev_attrib_hw_max_sectors.attr,
+ &target_core_dev_attrib_max_sectors.attr,
+ &target_core_dev_attrib_optimal_sectors.attr,
+ &target_core_dev_attrib_hw_queue_depth.attr,
+ &target_core_dev_attrib_queue_depth.attr,
+ &target_core_dev_attrib_task_timeout.attr,
+ &target_core_dev_attrib_max_unmap_lba_count.attr,
+ &target_core_dev_attrib_max_unmap_block_desc_count.attr,
+ &target_core_dev_attrib_unmap_granularity.attr,
+ &target_core_dev_attrib_unmap_granularity_alignment.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_attrib_ops = {
+ .show_attribute = target_core_dev_attrib_attr_show,
+ .store_attribute = target_core_dev_attrib_attr_store,
+};
+
+static struct config_item_type target_core_dev_attrib_cit = {
+ .ct_item_ops = &target_core_dev_attrib_ops,
+ .ct_attrs = target_core_dev_attrib_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_attrib_cit */
+
+/* Start functions for struct config_item_type target_core_dev_wwn_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn);
+#define SE_DEV_WWN_ATTR(_name, _mode) \
+static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_wwn_show_attr_##_name, \
+ target_core_dev_wwn_store_attr_##_name);
+
+#define SE_DEV_WWN_ATTR_RO(_name); \
+do { \
+ static struct target_core_dev_wwn_attribute \
+ target_core_dev_wwn_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_wwn_show_attr_##_name); \
+} while (0);
+
+/*
+ * VPD page 0x80 Unit serial
+ */
+static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial(
+ struct t10_wwn *t10_wwn,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ return sprintf(page, "T10 VPD Unit Serial Number: %s\n",
+ &t10_wwn->unit_serial[0]);
+}
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+ unsigned char buf[INQUIRY_VPD_SERIAL_LEN];
+
+ /*
+ * If Linux/SCSI subsystem_api_t plugin got a VPD Unit Serial
+ * from the struct scsi_device level firmware, do not allow
+ * VPD Unit Serial to be emulated.
+ *
+ * Note this struct scsi_device could also be emulating VPD
+ * information from its drivers/scsi LLD. But for now we assume
+ * it is doing 'the right thing' wrt a world wide unique
+ * VPD Unit Serial Number that OS dependent multipath can depend on.
+ */
+ if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) {
+ printk(KERN_ERR "Underlying SCSI device firmware provided VPD"
+ " Unit Serial, ignoring request\n");
+ return -EOPNOTSUPP;
+ }
+
+ if ((strlen(page) + 1) > INQUIRY_VPD_SERIAL_LEN) {
+ printk(KERN_ERR "Emulated VPD Unit Serial exceeds"
+ " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN);
+ return -EOVERFLOW;
+ }
+ /*
+ * Check to see if any active $FABRIC_MOD exports exist. If they
+ * do exist, fail here as changing this information on the fly
+ * (underneath the initiator side OS dependent multipath code)
+ * could cause negative effects.
+ */
+ dev = su_dev->se_dev_ptr;
+ if ((dev)) {
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "Unable to set VPD Unit Serial while"
+ " active %d $FABRIC_MOD exports exist\n",
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -EINVAL;
+ }
+ }
+ /*
+ * This currently assumes ASCII encoding for emulated VPD Unit Serial.
+ *
+ * Also, strip any newline added from the userspace
+ * echo $UUID > $TARGET/$HBA/$STORAGE_OBJECT/wwn/vpd_unit_serial
+ */
+ memset(buf, 0, INQUIRY_VPD_SERIAL_LEN);
+ snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page);
+ snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN,
+ "%s", strstrip(buf));
+ su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set emulated VPD Unit Serial:"
+ " %s\n", su_dev->t10_wwn.unit_serial);
+
+ return count;
+}
+
+SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Protocol Identifier
+ */
+static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(
+ struct t10_wwn *t10_wwn,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+ struct t10_vpd *vpd;
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ ssize_t len = 0;
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+
+ spin_lock(&t10_wwn->t10_vpd_lock);
+ list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) {
+ if (!(vpd->protocol_identifier_set))
+ continue;
+
+ transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE);
+
+ if ((len + strlen(buf) > PAGE_SIZE))
+ break;
+
+ len += sprintf(page+len, "%s", buf);
+ }
+ spin_unlock(&t10_wwn->t10_vpd_lock);
+
+ return len;
+}
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR);
+
+/*
+ * Generic wrapper for dumping VPD identifiers by association.
+ */
+#define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \
+static ssize_t target_core_dev_wwn_show_attr_##_name( \
+ struct t10_wwn *t10_wwn, \
+ char *page) \
+{ \
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \
+ struct se_device *dev; \
+ struct t10_vpd *vpd; \
+ unsigned char buf[VPD_TMP_BUF_SIZE]; \
+ ssize_t len = 0; \
+ \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) \
+ return -ENODEV; \
+ \
+ spin_lock(&t10_wwn->t10_vpd_lock); \
+ list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \
+ if (vpd->association != _assoc) \
+ continue; \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ } \
+ spin_unlock(&t10_wwn->t10_vpd_lock); \
+ \
+ return len; \
+}
+
+/*
+ * VPD page 0x83 Assoication: Logical Unit
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Association: Target Port
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Association: SCSI Target Device
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group);
+
+static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
+ &target_core_dev_wwn_vpd_unit_serial.attr,
+ &target_core_dev_wwn_vpd_protocol_identifier.attr,
+ &target_core_dev_wwn_vpd_assoc_logical_unit.attr,
+ &target_core_dev_wwn_vpd_assoc_target_port.attr,
+ &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_wwn_ops = {
+ .show_attribute = target_core_dev_wwn_attr_show,
+ .store_attribute = target_core_dev_wwn_attr_store,
+};
+
+static struct config_item_type target_core_dev_wwn_cit = {
+ .ct_item_ops = &target_core_dev_wwn_ops,
+ .ct_attrs = target_core_dev_wwn_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_wwn_cit */
+
+/* Start functions for struct config_item_type target_core_dev_pr_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev);
+#define SE_DEV_PR_ATTR(_name, _mode) \
+static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_pr_show_attr_##_name, \
+ target_core_dev_pr_store_attr_##_name);
+
+#define SE_DEV_PR_ATTR_RO(_name); \
+static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_pr_show_attr_##_name);
+
+/*
+ * res_holder
+ */
+static ssize_t target_core_dev_pr_show_spc3_res(
+ struct se_device *dev,
+ char *page,
+ ssize_t *len)
+{
+ struct se_node_acl *se_nacl;
+ struct t10_pr_registration *pr_reg;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ *len += sprintf(page + *len, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return *len;
+ }
+ se_nacl = pr_reg->pr_reg_nacl;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n",
+ TPG_TFO(se_nacl->se_tpg)->get_fabric_name(),
+ se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return *len;
+}
+
+static ssize_t target_core_dev_pr_show_spc2_res(
+ struct se_device *dev,
+ char *page,
+ ssize_t *len)
+{
+ struct se_node_acl *se_nacl;
+
+ spin_lock(&dev->dev_reservation_lock);
+ se_nacl = dev->dev_reserved_node_acl;
+ if (!(se_nacl)) {
+ *len += sprintf(page + *len, "No SPC-2 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return *len;
+ }
+ *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n",
+ TPG_TFO(se_nacl->se_tpg)->get_fabric_name(),
+ se_nacl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return *len;
+}
+
+static ssize_t target_core_dev_pr_show_attr_res_holder(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ ssize_t len = 0;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ switch (T10_RES(su_dev)->res_type) {
+ case SPC3_PERSISTENT_RESERVATIONS:
+ target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr,
+ page, &len);
+ break;
+ case SPC2_RESERVATIONS:
+ target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr,
+ page, &len);
+ break;
+ case SPC_PASSTHROUGH:
+ len += sprintf(page+len, "Passthrough\n");
+ break;
+ default:
+ len += sprintf(page+len, "Unknown\n");
+ break;
+ }
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_holder);
+
+/*
+ * res_pr_all_tgt_pts
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct t10_pr_registration *pr_reg;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ /*
+ * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3
+ * Basic PERSISTENT RESERVER OUT parameter list, page 290
+ */
+ if (pr_reg->pr_reg_all_tg_pt)
+ len = sprintf(page, "SPC-3 Reservation: All Target"
+ " Ports registration\n");
+ else
+ len = sprintf(page, "SPC-3 Reservation: Single"
+ " Target Port registration\n");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts);
+
+/*
+ * res_pr_generation
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_generation(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "0x%08x\n", T10_RES(su_dev)->pr_generation);
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_generation);
+
+/*
+ * res_pr_holder_tg_port
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct se_node_acl *se_nacl;
+ struct se_lun *lun;
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg;
+ struct target_core_fabric_ops *tfo;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ se_nacl = pr_reg->pr_reg_nacl;
+ se_tpg = se_nacl->se_tpg;
+ lun = pr_reg->pr_reg_tg_pt_lun;
+ tfo = TPG_TFO(se_tpg);
+
+ len += sprintf(page+len, "SPC-3 Reservation: %s"
+ " Target Node Endpoint: %s\n", tfo->get_fabric_name(),
+ tfo->tpg_get_wwn(se_tpg));
+ len += sprintf(page+len, "SPC-3 Reservation: Relative Port"
+ " Identifer Tag: %hu %s Portal Group Tag: %hu"
+ " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi,
+ tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg),
+ tfo->get_fabric_name(), lun->unpacked_lun);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
+
+/*
+ * res_pr_registered_i_pts
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct target_core_fabric_ops *tfo;
+ struct t10_pr_registration *pr_reg;
+ unsigned char buf[384];
+ char i_buf[PR_REG_ISID_ID_LEN];
+ ssize_t len = 0;
+ int reg_count = 0, prf_isid;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ len += sprintf(page+len, "SPC-3 PR Registrations:\n");
+
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+
+ memset(buf, 0, 384);
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n",
+ tfo->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ?
+ &i_buf[0] : "", pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ if ((len + strlen(buf) > PAGE_SIZE))
+ break;
+
+ len += sprintf(page+len, "%s", buf);
+ reg_count++;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ if (!(reg_count))
+ len += sprintf(page+len, "None\n");
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts);
+
+/*
+ * res_pr_type
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_type(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct t10_pr_registration *pr_reg;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ len = sprintf(page, "SPC-3 Reservation Type: %s\n",
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type));
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_type);
+
+/*
+ * res_type
+ */
+static ssize_t target_core_dev_pr_show_attr_res_type(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ ssize_t len = 0;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ switch (T10_RES(su_dev)->res_type) {
+ case SPC3_PERSISTENT_RESERVATIONS:
+ len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");
+ break;
+ case SPC2_RESERVATIONS:
+ len = sprintf(page, "SPC2_RESERVATIONS\n");
+ break;
+ case SPC_PASSTHROUGH:
+ len = sprintf(page, "SPC_PASSTHROUGH\n");
+ break;
+ default:
+ len = sprintf(page, "UNKNOWN\n");
+ break;
+ }
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_type);
+
+/*
+ * res_aptpl_active
+ */
+
+static ssize_t target_core_dev_pr_show_attr_res_aptpl_active(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "APTPL Bit Status: %s\n",
+ (T10_RES(su_dev)->pr_aptpl_active) ? "Activated" : "Disabled");
+}
+
+SE_DEV_PR_ATTR_RO(res_aptpl_active);
+
+/*
+ * res_aptpl_metadata
+ */
+static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "Ready to process PR APTPL metadata..\n");
+}
+
+enum {
+ Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid,
+ Opt_sa_res_key, Opt_res_holder, Opt_res_type, Opt_res_scope,
+ Opt_res_all_tg_pt, Opt_mapped_lun, Opt_target_fabric,
+ Opt_target_node, Opt_tpgt, Opt_port_rtpi, Opt_target_lun, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_initiator_fabric, "initiator_fabric=%s"},
+ {Opt_initiator_node, "initiator_node=%s"},
+ {Opt_initiator_sid, "initiator_sid=%s"},
+ {Opt_sa_res_key, "sa_res_key=%s"},
+ {Opt_res_holder, "res_holder=%d"},
+ {Opt_res_type, "res_type=%d"},
+ {Opt_res_scope, "res_scope=%d"},
+ {Opt_res_all_tg_pt, "res_all_tg_pt=%d"},
+ {Opt_mapped_lun, "mapped_lun=%d"},
+ {Opt_target_fabric, "target_fabric=%s"},
+ {Opt_target_node, "target_node=%s"},
+ {Opt_tpgt, "tpgt=%d"},
+ {Opt_port_rtpi, "port_rtpi=%d"},
+ {Opt_target_lun, "target_lun=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
+ struct se_subsystem_dev *su_dev,
+ const char *page,
+ size_t count)
+{
+ struct se_device *dev;
+ unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL;
+ unsigned char *isid = NULL;
+ char *orig, *ptr, *arg_p, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ unsigned long long tmp_ll;
+ u64 sa_res_key = 0;
+ u32 mapped_lun = 0, target_lun = 0;
+ int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token;
+ u16 port_rpti = 0, tpgt = 0;
+ u8 type = 0, scope;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_INFO "Unable to process APTPL metadata while"
+ " active fabric exports exist\n");
+ return -EINVAL;
+ }
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_initiator_fabric:
+ i_fabric = match_strdup(&args[0]);
+ break;
+ case Opt_initiator_node:
+ i_port = match_strdup(&args[0]);
+ if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) {
+ printk(KERN_ERR "APTPL metadata initiator_node="
+ " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n",
+ PR_APTPL_MAX_IPORT_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_initiator_sid:
+ isid = match_strdup(&args[0]);
+ if (strlen(isid) > PR_REG_ISID_LEN) {
+ printk(KERN_ERR "APTPL metadata initiator_isid"
+ "= exceeds PR_REG_ISID_LEN: %d\n",
+ PR_REG_ISID_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_sa_res_key:
+ arg_p = match_strdup(&args[0]);
+ ret = strict_strtoull(arg_p, 0, &tmp_ll);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " sa_res_key=\n");
+ goto out;
+ }
+ sa_res_key = (u64)tmp_ll;
+ break;
+ /*
+ * PR APTPL Metadata for Reservation
+ */
+ case Opt_res_holder:
+ match_int(args, &arg);
+ res_holder = arg;
+ break;
+ case Opt_res_type:
+ match_int(args, &arg);
+ type = (u8)arg;
+ break;
+ case Opt_res_scope:
+ match_int(args, &arg);
+ scope = (u8)arg;
+ break;
+ case Opt_res_all_tg_pt:
+ match_int(args, &arg);
+ all_tg_pt = (int)arg;
+ break;
+ case Opt_mapped_lun:
+ match_int(args, &arg);
+ mapped_lun = (u32)arg;
+ break;
+ /*
+ * PR APTPL Metadata for Target Port
+ */
+ case Opt_target_fabric:
+ t_fabric = match_strdup(&args[0]);
+ break;
+ case Opt_target_node:
+ t_port = match_strdup(&args[0]);
+ if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) {
+ printk(KERN_ERR "APTPL metadata target_node="
+ " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n",
+ PR_APTPL_MAX_TPORT_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_tpgt:
+ match_int(args, &arg);
+ tpgt = (u16)arg;
+ break;
+ case Opt_port_rtpi:
+ match_int(args, &arg);
+ port_rpti = (u16)arg;
+ break;
+ case Opt_target_lun:
+ match_int(args, &arg);
+ target_lun = (u32)arg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!(i_port) || !(t_port) || !(sa_res_key)) {
+ printk(KERN_ERR "Illegal parameters for APTPL registration\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (res_holder && !(type)) {
+ printk(KERN_ERR "Illegal PR type: 0x%02x for reservation"
+ " holder\n", type);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = core_scsi3_alloc_aptpl_registration(T10_RES(su_dev), sa_res_key,
+ i_port, isid, mapped_lun, t_port, tpgt, target_lun,
+ res_holder, all_tg_pt, type);
+out:
+ kfree(orig);
+ return (ret == 0) ? count : ret;
+}
+
+SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group);
+
+static struct configfs_attribute *target_core_dev_pr_attrs[] = {
+ &target_core_dev_pr_res_holder.attr,
+ &target_core_dev_pr_res_pr_all_tgt_pts.attr,
+ &target_core_dev_pr_res_pr_generation.attr,
+ &target_core_dev_pr_res_pr_holder_tg_port.attr,
+ &target_core_dev_pr_res_pr_registered_i_pts.attr,
+ &target_core_dev_pr_res_pr_type.attr,
+ &target_core_dev_pr_res_type.attr,
+ &target_core_dev_pr_res_aptpl_active.attr,
+ &target_core_dev_pr_res_aptpl_metadata.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_pr_ops = {
+ .show_attribute = target_core_dev_pr_attr_show,
+ .store_attribute = target_core_dev_pr_attr_store,
+};
+
+static struct config_item_type target_core_dev_pr_cit = {
+ .ct_item_ops = &target_core_dev_pr_ops,
+ .ct_attrs = target_core_dev_pr_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_pr_cit */
+
+/* Start functions for struct config_item_type target_core_dev_cit */
+
+static ssize_t target_core_show_dev_info(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+ int bl = 0;
+ ssize_t read_bytes = 0;
+
+ if (!(se_dev->se_dev_ptr))
+ return -ENODEV;
+
+ transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl);
+ read_bytes += bl;
+ read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes);
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_info = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "info",
+ .ca_mode = S_IRUGO },
+ .show = target_core_show_dev_info,
+ .store = NULL,
+};
+
+static ssize_t target_core_store_dev_control(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate struct se_subsystem_dev>se"
+ "_dev_su_ptr\n");
+ return -EINVAL;
+ }
+
+ return t->set_configfs_dev_params(hba, se_dev, page, count);
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_control = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "control",
+ .ca_mode = S_IWUSR },
+ .show = NULL,
+ .store = target_core_store_dev_control,
+};
+
+static ssize_t target_core_show_dev_alias(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+
+ if (!(se_dev->su_dev_flags & SDF_USING_ALIAS))
+ return 0;
+
+ return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias);
+}
+
+static ssize_t target_core_store_dev_alias(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ ssize_t read_bytes;
+
+ if (count > (SE_DEV_ALIAS_LEN-1)) {
+ printk(KERN_ERR "alias count: %d exceeds"
+ " SE_DEV_ALIAS_LEN-1: %u\n", (int)count,
+ SE_DEV_ALIAS_LEN-1);
+ return -EINVAL;
+ }
+
+ se_dev->su_dev_flags |= SDF_USING_ALIAS;
+ read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN,
+ "%s", page);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set alias: %s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&se_dev->se_dev_group.cg_item),
+ se_dev->se_dev_alias);
+
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_alias = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "alias",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_dev_alias,
+ .store = target_core_store_dev_alias,
+};
+
+static ssize_t target_core_show_dev_udev_path(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+
+ if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH))
+ return 0;
+
+ return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path);
+}
+
+static ssize_t target_core_store_dev_udev_path(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ ssize_t read_bytes;
+
+ if (count > (SE_UDEV_PATH_LEN-1)) {
+ printk(KERN_ERR "udev_path count: %d exceeds"
+ " SE_UDEV_PATH_LEN-1: %u\n", (int)count,
+ SE_UDEV_PATH_LEN-1);
+ return -EINVAL;
+ }
+
+ se_dev->su_dev_flags |= SDF_USING_UDEV_PATH;
+ read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN,
+ "%s", page);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set udev_path: %s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&se_dev->se_dev_group.cg_item),
+ se_dev->se_dev_udev_path);
+
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_udev_path = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "udev_path",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_dev_udev_path,
+ .store = target_core_store_dev_udev_path,
+};
+
+static ssize_t target_core_store_dev_enable(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_device *dev;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+ char *ptr;
+
+ ptr = strstr(page, "1");
+ if (!(ptr)) {
+ printk(KERN_ERR "For dev_enable ops, only valid value"
+ " is \"1\"\n");
+ return -EINVAL;
+ }
+ if ((se_dev->se_dev_ptr)) {
+ printk(KERN_ERR "se_dev->se_dev_ptr already set for storage"
+ " object\n");
+ return -EEXIST;
+ }
+
+ if (t->check_configfs_dev_params(hba, se_dev) < 0)
+ return -EINVAL;
+
+ dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr);
+ if (!(dev) || IS_ERR(dev))
+ return -EINVAL;
+
+ se_dev->se_dev_ptr = dev;
+ printk(KERN_INFO "Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:"
+ " %p\n", se_dev->se_dev_ptr);
+
+ return count;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_enable = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "enable",
+ .ca_mode = S_IWUSR },
+ .show = NULL,
+ .store = target_core_store_dev_enable,
+};
+
+static ssize_t target_core_show_alua_lu_gp(void *p, char *page)
+{
+ struct se_device *dev;
+ struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+ struct config_item *lu_ci;
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED)
+ return len;
+
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem)) {
+ printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem"
+ " pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ lu_ci = &lu_gp->lu_gp_group.cg_item;
+ len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n",
+ config_item_name(lu_ci), lu_gp->lu_gp_id);
+ }
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ return len;
+}
+
+static ssize_t target_core_store_alua_lu_gp(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_device *dev;
+ struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = su_dev->se_dev_hba;
+ struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ unsigned char buf[LU_GROUP_NAME_BUF];
+ int move = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) {
+ printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for %s/%s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item));
+ return -EINVAL;
+ }
+ if (count > LU_GROUP_NAME_BUF) {
+ printk(KERN_ERR "ALUA LU Group Alias too large!\n");
+ return -EINVAL;
+ }
+ memset(buf, 0, LU_GROUP_NAME_BUF);
+ memcpy(buf, page, count);
+ /*
+ * Any ALUA logical unit alias besides "NULL" means we will be
+ * making a new group association.
+ */
+ if (strcmp(strstrip(buf), "NULL")) {
+ /*
+ * core_alua_get_lu_gp_by_name() will increment reference to
+ * struct t10_alua_lu_gp. This reference is released with
+ * core_alua_get_lu_gp_by_name below().
+ */
+ lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf));
+ if (!(lu_gp_new))
+ return -ENODEV;
+ }
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem)) {
+ if (lu_gp_new)
+ core_alua_put_lu_gp_from_name(lu_gp_new);
+ printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem"
+ " pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ /*
+ * Clearing an existing lu_gp association, and replacing
+ * with NULL
+ */
+ if (!(lu_gp_new)) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing %s/%s"
+ " from ALUA LU Group: core/alua/lu_gps/%s, ID:"
+ " %hu\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item),
+ config_item_name(&lu_gp->lu_gp_group.cg_item),
+ lu_gp->lu_gp_id);
+
+ __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ return count;
+ }
+ /*
+ * Removing existing association of lu_gp_mem with lu_gp
+ */
+ __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
+ move = 1;
+ }
+ /*
+ * Associate lu_gp_mem with lu_gp_new.
+ */
+ __core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:"
+ " core/alua/lu_gps/%s, ID: %hu\n",
+ (move) ? "Moving" : "Adding",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item),
+ config_item_name(&lu_gp_new->lu_gp_group.cg_item),
+ lu_gp_new->lu_gp_id);
+
+ core_alua_put_lu_gp_from_name(lu_gp_new);
+ return count;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "alua_lu_gp",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_alua_lu_gp,
+ .store = target_core_store_alua_lu_gp,
+};
+
+static struct configfs_attribute *lio_core_dev_attrs[] = {
+ &target_core_attr_dev_info.attr,
+ &target_core_attr_dev_control.attr,
+ &target_core_attr_dev_alias.attr,
+ &target_core_attr_dev_udev_path.attr,
+ &target_core_attr_dev_enable.attr,
+ &target_core_attr_dev_alua_lu_gp.attr,
+ NULL,
+};
+
+static void target_core_dev_release(struct config_item *item)
+{
+ struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
+ struct se_subsystem_dev, se_dev_group);
+ struct config_group *dev_cg;
+
+ if (!(se_dev))
+ return;
+
+ dev_cg = &se_dev->se_dev_group;
+ kfree(dev_cg->default_groups);
+}
+
+static ssize_t target_core_dev_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(item), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_core_configfs_attribute *tc_attr = container_of(
+ attr, struct target_core_configfs_attribute, attr);
+
+ if (!(tc_attr->show))
+ return -EINVAL;
+
+ return tc_attr->show((void *)se_dev, page);
+}
+
+static ssize_t target_core_dev_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(item), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_core_configfs_attribute *tc_attr = container_of(
+ attr, struct target_core_configfs_attribute, attr);
+
+ if (!(tc_attr->store))
+ return -EINVAL;
+
+ return tc_attr->store((void *)se_dev, page, count);
+}
+
+static struct configfs_item_operations target_core_dev_item_ops = {
+ .release = target_core_dev_release,
+ .show_attribute = target_core_dev_show,
+ .store_attribute = target_core_dev_store,
+};
+
+static struct config_item_type target_core_dev_cit = {
+ .ct_item_ops = &target_core_dev_item_ops,
+ .ct_attrs = lio_core_dev_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_cit */
+
+/* Start functions for struct config_item_type target_core_alua_lu_gp_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp);
+#define SE_DEV_ALUA_LU_ATTR(_name, _mode) \
+static struct target_core_alua_lu_gp_attribute \
+ target_core_alua_lu_gp_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_alua_lu_gp_show_attr_##_name, \
+ target_core_alua_lu_gp_store_attr_##_name);
+
+#define SE_DEV_ALUA_LU_ATTR_RO(_name) \
+static struct target_core_alua_lu_gp_attribute \
+ target_core_alua_lu_gp_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_alua_lu_gp_show_attr_##_name);
+
+/*
+ * lu_gp_id
+ */
+static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id(
+ struct t10_alua_lu_gp *lu_gp,
+ char *page)
+{
+ if (!(lu_gp->lu_gp_valid_id))
+ return 0;
+
+ return sprintf(page, "%hu\n", lu_gp->lu_gp_id);
+}
+
+static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id(
+ struct t10_alua_lu_gp *lu_gp,
+ const char *page,
+ size_t count)
+{
+ struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group;
+ unsigned long lu_gp_id;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &lu_gp_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " lu_gp_id\n", ret);
+ return -EINVAL;
+ }
+ if (lu_gp_id > 0x0000ffff) {
+ printk(KERN_ERR "ALUA lu_gp_id: %lu exceeds maximum:"
+ " 0x0000ffff\n", lu_gp_id);
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_lu_gp_id(lu_gp, (u16)lu_gp_id);
+ if (ret < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s to ID: %hu\n",
+ config_item_name(&alua_lu_gp_cg->cg_item),
+ lu_gp->lu_gp_id);
+
+ return count;
+}
+
+SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR);
+
+/*
+ * members
+ */
+static ssize_t target_core_alua_lu_gp_show_attr_members(
+ struct t10_alua_lu_gp *lu_gp,
+ char *page)
+{
+ struct se_device *dev;
+ struct se_hba *hba;
+ struct se_subsystem_dev *su_dev;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ ssize_t len = 0, cur_len;
+ unsigned char buf[LU_GROUP_NAME_BUF];
+
+ memset(buf, 0, LU_GROUP_NAME_BUF);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+ dev = lu_gp_mem->lu_gp_mem_dev;
+ su_dev = dev->se_sub_dev;
+ hba = su_dev->se_dev_hba;
+
+ cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item));
+ cur_len++; /* Extra byte for NULL terminator */
+
+ if ((cur_len + len) > PAGE_SIZE) {
+ printk(KERN_WARNING "Ran out of lu_gp_show_attr"
+ "_members buffer\n");
+ break;
+ }
+ memcpy(page+len, buf, cur_len);
+ len += cur_len;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ return len;
+}
+
+SE_DEV_ALUA_LU_ATTR_RO(members);
+
+CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group);
+
+static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = {
+ &target_core_alua_lu_gp_lu_gp_id.attr,
+ &target_core_alua_lu_gp_members.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_alua_lu_gp_ops = {
+ .show_attribute = target_core_alua_lu_gp_attr_show,
+ .store_attribute = target_core_alua_lu_gp_attr_store,
+};
+
+static struct config_item_type target_core_alua_lu_gp_cit = {
+ .ct_item_ops = &target_core_alua_lu_gp_ops,
+ .ct_attrs = target_core_alua_lu_gp_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_lu_gp_cit */
+
+/* Start functions for struct config_item_type target_core_alua_lu_gps_cit */
+
+static struct config_group *target_core_alua_create_lu_gp(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua_lu_gp *lu_gp;
+ struct config_group *alua_lu_gp_cg = NULL;
+ struct config_item *alua_lu_gp_ci = NULL;
+
+ lu_gp = core_alua_allocate_lu_gp(name, 0);
+ if (IS_ERR(lu_gp))
+ return NULL;
+
+ alua_lu_gp_cg = &lu_gp->lu_gp_group;
+ alua_lu_gp_ci = &alua_lu_gp_cg->cg_item;
+
+ config_group_init_type_name(alua_lu_gp_cg, name,
+ &target_core_alua_lu_gp_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s\n",
+ config_item_name(alua_lu_gp_ci));
+
+ return alua_lu_gp_cg;
+
+}
+
+static void target_core_alua_drop_lu_gp(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item),
+ struct t10_alua_lu_gp, lu_gp_group);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s, ID: %hu\n",
+ config_item_name(item), lu_gp->lu_gp_id);
+
+ config_item_put(item);
+ core_alua_free_lu_gp(lu_gp);
+}
+
+static struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
+ .make_group = &target_core_alua_create_lu_gp,
+ .drop_item = &target_core_alua_drop_lu_gp,
+};
+
+static struct config_item_type target_core_alua_lu_gps_cit = {
+ .ct_item_ops = NULL,
+ .ct_group_ops = &target_core_alua_lu_gps_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_lu_gps_cit */
+
+/* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp);
+#define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \
+static struct target_core_alua_tg_pt_gp_attribute \
+ target_core_alua_tg_pt_gp_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_alua_tg_pt_gp_show_attr_##_name, \
+ target_core_alua_tg_pt_gp_store_attr_##_name);
+
+#define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \
+static struct target_core_alua_tg_pt_gp_attribute \
+ target_core_alua_tg_pt_gp_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_alua_tg_pt_gp_show_attr_##_name);
+
+/*
+ * alua_access_state
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state));
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ unsigned long tmp;
+ int new_state, ret;
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id)) {
+ printk(KERN_ERR "Unable to do implict ALUA on non valid"
+ " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id);
+ return -EINVAL;
+ }
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk("Unable to extract new ALUA access state from"
+ " %s\n", page);
+ return -EINVAL;
+ }
+ new_state = (int)tmp;
+
+ if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Unable to process implict configfs ALUA"
+ " transition while TPGS_IMPLICT_ALUA is diabled\n");
+ return -EINVAL;
+ }
+
+ ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr,
+ NULL, NULL, new_state, 0);
+ return (!ret) ? count : -EINVAL;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_access_status
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%s\n",
+ core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status));
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int new_status, ret;
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id)) {
+ printk(KERN_ERR "Unable to do set ALUA access status on non"
+ " valid tg_pt_gp ID: %hu\n",
+ tg_pt_gp->tg_pt_gp_valid_id);
+ return -EINVAL;
+ }
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract new ALUA access status"
+ " from %s\n", page);
+ return -EINVAL;
+ }
+ new_status = (int)tmp;
+
+ if ((new_status != ALUA_STATUS_NONE) &&
+ (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
+ (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Illegal ALUA access status: 0x%02x\n",
+ new_status);
+ return -EINVAL;
+ }
+
+ tg_pt_gp->tg_pt_gp_alua_access_status = new_status;
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_access_type
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_access_type(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_access_type(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_write_metadata
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_write_metadata\n");
+ return -EINVAL;
+ }
+
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_write_metadata:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_write_metadata = (int)tmp;
+
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR);
+
+
+
+/*
+ * nonop_delay_msecs
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_nonop_delay_msecs(tg_pt_gp, page);
+
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR);
+
+/*
+ * trans_delay_msecs
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_trans_delay_msecs(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);
+
+/*
+ * preferred
+ */
+
+static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_preferred_bit(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_preferred_bit(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR);
+
+/*
+ * tg_pt_gp_id
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ return 0;
+
+ return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group;
+ unsigned long tg_pt_gp_id;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tg_pt_gp_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " tg_pt_gp_id\n", ret);
+ return -EINVAL;
+ }
+ if (tg_pt_gp_id > 0x0000ffff) {
+ printk(KERN_ERR "ALUA tg_pt_gp_id: %lu exceeds maximum:"
+ " 0x0000ffff\n", tg_pt_gp_id);
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_tg_pt_gp_id(tg_pt_gp, (u16)tg_pt_gp_id);
+ if (ret < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Target Port Group: "
+ "core/alua/tg_pt_gps/%s to ID: %hu\n",
+ config_item_name(&alua_tg_pt_gp_cg->cg_item),
+ tg_pt_gp->tg_pt_gp_id);
+
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR);
+
+/*
+ * members
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_members(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ struct se_port *port;
+ struct se_portal_group *tpg;
+ struct se_lun *lun;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ ssize_t len = 0, cur_len;
+ unsigned char buf[TG_PT_GROUP_NAME_BUF];
+
+ memset(buf, 0, TG_PT_GROUP_NAME_BUF);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = tg_pt_gp_mem->tg_pt;
+ tpg = port->sep_tpg;
+ lun = port->sep_lun;
+
+ cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu"
+ "/%s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item));
+ cur_len++; /* Extra byte for NULL terminator */
+
+ if ((cur_len + len) > PAGE_SIZE) {
+ printk(KERN_WARNING "Ran out of lu_gp_show_attr"
+ "_members buffer\n");
+ break;
+ }
+ memcpy(page+len, buf, cur_len);
+ len += cur_len;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ return len;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR_RO(members);
+
+CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp,
+ tg_pt_gp_group);
+
+static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
+ &target_core_alua_tg_pt_gp_alua_access_state.attr,
+ &target_core_alua_tg_pt_gp_alua_access_status.attr,
+ &target_core_alua_tg_pt_gp_alua_access_type.attr,
+ &target_core_alua_tg_pt_gp_alua_write_metadata.attr,
+ &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_trans_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_preferred.attr,
+ &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,
+ &target_core_alua_tg_pt_gp_members.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
+ .show_attribute = target_core_alua_tg_pt_gp_attr_show,
+ .store_attribute = target_core_alua_tg_pt_gp_attr_store,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_cit = {
+ .ct_item_ops = &target_core_alua_tg_pt_gp_ops,
+ .ct_attrs = target_core_alua_tg_pt_gp_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
+
+/* Start functions for struct config_item_type target_core_alua_tg_pt_gps_cit */
+
+static struct config_group *target_core_alua_create_tg_pt_gp(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua *alua = container_of(group, struct t10_alua,
+ alua_tg_pt_gps_group);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct se_subsystem_dev *su_dev = alua->t10_sub_dev;
+ struct config_group *alua_tg_pt_gp_cg = NULL;
+ struct config_item *alua_tg_pt_gp_ci = NULL;
+
+ tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0);
+ if (!(tg_pt_gp))
+ return NULL;
+
+ alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group;
+ alua_tg_pt_gp_ci = &alua_tg_pt_gp_cg->cg_item;
+
+ config_group_init_type_name(alua_tg_pt_gp_cg, name,
+ &target_core_alua_tg_pt_gp_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Target Port"
+ " Group: alua/tg_pt_gps/%s\n",
+ config_item_name(alua_tg_pt_gp_ci));
+
+ return alua_tg_pt_gp_cg;
+}
+
+static void target_core_alua_drop_tg_pt_gp(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item),
+ struct t10_alua_tg_pt_gp, tg_pt_gp_group);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port"
+ " Group: alua/tg_pt_gps/%s, ID: %hu\n",
+ config_item_name(item), tg_pt_gp->tg_pt_gp_id);
+
+ config_item_put(item);
+ core_alua_free_tg_pt_gp(tg_pt_gp);
+}
+
+static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
+ .make_group = &target_core_alua_create_tg_pt_gp,
+ .drop_item = &target_core_alua_drop_tg_pt_gp,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gps_cit = {
+ .ct_group_ops = &target_core_alua_tg_pt_gps_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_tg_pt_gps_cit */
+
+/* Start functions for struct config_item_type target_core_alua_cit */
+
+/*
+ * target_core_alua_cit is a ConfigFS group that lives under
+ * /sys/kernel/config/target/core/alua. There are default groups
+ * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to
+ * target_core_alua_cit in target_core_init_configfs() below.
+ */
+static struct config_item_type target_core_alua_cit = {
+ .ct_item_ops = NULL,
+ .ct_attrs = NULL,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_cit */
+
+/* Start functions for struct config_item_type target_core_hba_cit */
+
+static struct config_group *target_core_make_subdev(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct se_subsystem_dev *se_dev;
+ struct se_subsystem_api *t;
+ struct config_item *hba_ci = &group->cg_item;
+ struct se_hba *hba = item_to_hba(hba_ci);
+ struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;
+
+ if (mutex_lock_interruptible(&hba->hba_access_mutex))
+ return NULL;
+
+ /*
+ * Locate the struct se_subsystem_api from parent's struct se_hba.
+ */
+ t = hba->transport;
+
+ se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL);
+ if (!se_dev) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_subsystem_dev\n");
+ goto unlock;
+ }
+ INIT_LIST_HEAD(&se_dev->g_se_dev_list);
+ INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list);
+ spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list);
+ spin_lock_init(&se_dev->t10_reservation.registration_lock);
+ spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock);
+ INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list);
+ spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock);
+ spin_lock_init(&se_dev->se_dev_lock);
+ se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
+ se_dev->t10_wwn.t10_sub_dev = se_dev;
+ se_dev->t10_alua.t10_sub_dev = se_dev;
+ se_dev->se_dev_attrib.da_sub_dev = se_dev;
+
+ se_dev->se_dev_hba = hba;
+ dev_cg = &se_dev->se_dev_group;
+
+ dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6,
+ GFP_KERNEL);
+ if (!(dev_cg->default_groups))
+ goto out;
+ /*
+ * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr
+ * for ->allocate_virtdevice()
+ *
+ * se_dev->se_dev_ptr will be set after ->create_virtdev()
+ * has been called successfully in the next level up in the
+ * configfs tree for device object's struct config_group.
+ */
+ se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name);
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate subsystem dependent pointer"
+ " from allocate_virtdevice()\n");
+ goto out;
+ }
+ spin_lock(&se_global->g_device_lock);
+ list_add_tail(&se_dev->g_se_dev_list, &se_global->g_se_dev_list);
+ spin_unlock(&se_global->g_device_lock);
+
+ config_group_init_type_name(&se_dev->se_dev_group, name,
+ &target_core_dev_cit);
+ config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib",
+ &target_core_dev_attrib_cit);
+ config_group_init_type_name(&se_dev->se_dev_pr_group, "pr",
+ &target_core_dev_pr_cit);
+ config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn",
+ &target_core_dev_wwn_cit);
+ config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group,
+ "alua", &target_core_alua_tg_pt_gps_cit);
+ dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group;
+ dev_cg->default_groups[1] = &se_dev->se_dev_pr_group;
+ dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group;
+ dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group;
+ dev_cg->default_groups[4] = NULL;
+ /*
+ * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp
+ */
+ tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1);
+ if (!(tg_pt_gp))
+ goto out;
+
+ tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group;
+ tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(tg_pt_gp_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate tg_pt_gp_cg->"
+ "default_groups\n");
+ goto out;
+ }
+
+ config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,
+ "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);
+ tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;
+ tg_pt_gp_cg->default_groups[1] = NULL;
+ T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:"
+ " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr);
+
+ mutex_unlock(&hba->hba_access_mutex);
+ return &se_dev->se_dev_group;
+out:
+ if (T10_ALUA(se_dev)->default_tg_pt_gp) {
+ core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+ T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
+ }
+ if (tg_pt_gp_cg)
+ kfree(tg_pt_gp_cg->default_groups);
+ if (dev_cg)
+ kfree(dev_cg->default_groups);
+ if (se_dev->se_dev_su_ptr)
+ t->free_device(se_dev->se_dev_su_ptr);
+ kfree(se_dev);
+unlock:
+ mutex_unlock(&hba->hba_access_mutex);
+ return NULL;
+}
+
+static void target_core_drop_subdev(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
+ struct se_subsystem_dev, se_dev_group);
+ struct se_hba *hba;
+ struct se_subsystem_api *t;
+ struct config_item *df_item;
+ struct config_group *dev_cg, *tg_pt_gp_cg;
+ int i, ret;
+
+ hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
+
+ if (mutex_lock_interruptible(&hba->hba_access_mutex))
+ goto out;
+
+ t = hba->transport;
+
+ spin_lock(&se_global->g_device_lock);
+ list_del(&se_dev->g_se_dev_list);
+ spin_unlock(&se_global->g_device_lock);
+
+ tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group;
+ for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {
+ df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;
+ tg_pt_gp_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+ kfree(tg_pt_gp_cg->default_groups);
+ core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+ T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
+
+ dev_cg = &se_dev->se_dev_group;
+ for (i = 0; dev_cg->default_groups[i]; i++) {
+ df_item = &dev_cg->default_groups[i]->cg_item;
+ dev_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ /*
+ * This pointer will set when the storage is enabled with:
+ * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+ */
+ if (se_dev->se_dev_ptr) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
+ "virtual_device() for se_dev_ptr: %p\n",
+ se_dev->se_dev_ptr);
+
+ ret = se_free_virtual_device(se_dev->se_dev_ptr, hba);
+ if (ret < 0)
+ goto hba_out;
+ } else {
+ /*
+ * Release struct se_subsystem_dev->se_dev_su_ptr..
+ */
+ printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
+ "device() for se_dev_su_ptr: %p\n",
+ se_dev->se_dev_su_ptr);
+
+ t->free_device(se_dev->se_dev_su_ptr);
+ }
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
+ "_dev_t: %p\n", se_dev);
+
+hba_out:
+ mutex_unlock(&hba->hba_access_mutex);
+out:
+ kfree(se_dev);
+}
+
+static struct configfs_group_operations target_core_hba_group_ops = {
+ .make_group = target_core_make_subdev,
+ .drop_item = target_core_drop_subdev,
+};
+
+CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba);
+#define SE_HBA_ATTR(_name, _mode) \
+static struct target_core_hba_attribute \
+ target_core_hba_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_hba_show_attr_##_name, \
+ target_core_hba_store_attr_##_name);
+
+#define SE_HBA_ATTR_RO(_name) \
+static struct target_core_hba_attribute \
+ target_core_hba_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_hba_show_attr_##_name);
+
+static ssize_t target_core_hba_show_attr_hba_info(
+ struct se_hba *hba,
+ char *page)
+{
+ return sprintf(page, "HBA Index: %d plugin: %s version: %s\n",
+ hba->hba_id, hba->transport->name,
+ TARGET_CORE_CONFIGFS_VERSION);
+}
+
+SE_HBA_ATTR_RO(hba_info);
+
+static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba,
+ char *page)
+{
+ int hba_mode = 0;
+
+ if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE)
+ hba_mode = 1;
+
+ return sprintf(page, "%d\n", hba_mode);
+}
+
+static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,
+ const char *page, size_t count)
+{
+ struct se_subsystem_api *transport = hba->transport;
+ unsigned long mode_flag;
+ int ret;
+
+ if (transport->pmode_enable_hba == NULL)
+ return -EINVAL;
+
+ ret = strict_strtoul(page, 0, &mode_flag);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract hba mode flag: %d\n", ret);
+ return -EINVAL;
+ }
+
+ spin_lock(&hba->device_lock);
+ if (!(list_empty(&hba->hba_dev_list))) {
+ printk(KERN_ERR "Unable to set hba_mode with active devices\n");
+ spin_unlock(&hba->device_lock);
+ return -EINVAL;
+ }
+ spin_unlock(&hba->device_lock);
+
+ ret = transport->pmode_enable_hba(hba, mode_flag);
+ if (ret < 0)
+ return -EINVAL;
+ if (ret > 0)
+ hba->hba_flags |= HBA_FLAGS_PSCSI_MODE;
+ else if (ret == 0)
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+
+ return count;
+}
+
+SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group);
+
+static struct configfs_attribute *target_core_hba_attrs[] = {
+ &target_core_hba_hba_info.attr,
+ &target_core_hba_hba_mode.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_hba_item_ops = {
+ .show_attribute = target_core_hba_attr_show,
+ .store_attribute = target_core_hba_attr_store,
+};
+
+static struct config_item_type target_core_hba_cit = {
+ .ct_item_ops = &target_core_hba_item_ops,
+ .ct_group_ops = &target_core_hba_group_ops,
+ .ct_attrs = target_core_hba_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *target_core_call_addhbatotarget(
+ struct config_group *group,
+ const char *name)
+{
+ char *se_plugin_str, *str, *str2;
+ struct se_hba *hba;
+ char buf[TARGET_CORE_NAME_MAX_LEN];
+ unsigned long plugin_dep_id = 0;
+ int ret;
+
+ memset(buf, 0, TARGET_CORE_NAME_MAX_LEN);
+ if (strlen(name) > TARGET_CORE_NAME_MAX_LEN) {
+ printk(KERN_ERR "Passed *name strlen(): %d exceeds"
+ " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name),
+ TARGET_CORE_NAME_MAX_LEN);
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+ snprintf(buf, TARGET_CORE_NAME_MAX_LEN, "%s", name);
+
+ str = strstr(buf, "_");
+ if (!(str)) {
+ printk(KERN_ERR "Unable to locate \"_\" for $SUBSYSTEM_PLUGIN_$HOST_ID\n");
+ return ERR_PTR(-EINVAL);
+ }
+ se_plugin_str = buf;
+ /*
+ * Special case for subsystem plugins that have "_" in their names.
+ * Namely rd_direct and rd_mcp..
+ */
+ str2 = strstr(str+1, "_");
+ if ((str2)) {
+ *str2 = '\0'; /* Terminate for *se_plugin_str */
+ str2++; /* Skip to start of plugin dependent ID */
+ str = str2;
+ } else {
+ *str = '\0'; /* Terminate for *se_plugin_str */
+ str++; /* Skip to start of plugin dependent ID */
+ }
+
+ ret = strict_strtoul(str, 0, &plugin_dep_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " plugin_dep_id\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ /*
+ * Load up TCM subsystem plugins if they have not already been loaded.
+ */
+ if (transport_subsystem_check_init() < 0)
+ return ERR_PTR(-EINVAL);
+
+ hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
+ if (IS_ERR(hba))
+ return ERR_CAST(hba);
+
+ config_group_init_type_name(&hba->hba_group, name,
+ &target_core_hba_cit);
+
+ return &hba->hba_group;
+}
+
+static void target_core_call_delhbafromtarget(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_hba *hba = item_to_hba(item);
+
+ config_item_put(item);
+ core_delete_hba(hba);
+}
+
+static struct configfs_group_operations target_core_group_ops = {
+ .make_group = target_core_call_addhbatotarget,
+ .drop_item = target_core_call_delhbafromtarget,
+};
+
+static struct config_item_type target_core_cit = {
+ .ct_item_ops = NULL,
+ .ct_group_ops = &target_core_group_ops,
+ .ct_attrs = NULL,
+ .ct_owner = THIS_MODULE,
+};
+
+/* Stop functions for struct config_item_type target_core_hba_cit */
+
+static int target_core_init_configfs(void)
+{
+ struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
+ struct config_group *lu_gp_cg = NULL;
+ struct configfs_subsystem *subsys;
+ struct proc_dir_entry *scsi_target_proc = NULL;
+ struct t10_alua_lu_gp *lu_gp;
+ int ret;
+
+ printk(KERN_INFO "TARGET_CORE[0]: Loading Generic Kernel Storage"
+ " Engine: %s on %s/%s on "UTS_RELEASE"\n",
+ TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine);
+
+ subsys = target_core_subsystem[0];
+ config_group_init(&subsys->su_group);
+ mutex_init(&subsys->su_mutex);
+
+ INIT_LIST_HEAD(&g_tf_list);
+ mutex_init(&g_tf_lock);
+ init_scsi_index_table();
+ ret = init_se_global();
+ if (ret < 0)
+ return -1;
+ /*
+ * Create $CONFIGFS/target/core default group for HBA <-> Storage Object
+ * and ALUA Logical Unit Group and Target Port Group infrastructure.
+ */
+ target_cg = &subsys->su_group;
+ target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(target_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate target_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&se_global->target_core_hbagroup,
+ "core", &target_core_cit);
+ target_cg->default_groups[0] = &se_global->target_core_hbagroup;
+ target_cg->default_groups[1] = NULL;
+ /*
+ * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/
+ */
+ hba_cg = &se_global->target_core_hbagroup;
+ hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(hba_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate hba_cg->default_groups\n");
+ goto out_global;
+ }
+ config_group_init_type_name(&se_global->alua_group,
+ "alua", &target_core_alua_cit);
+ hba_cg->default_groups[0] = &se_global->alua_group;
+ hba_cg->default_groups[1] = NULL;
+ /*
+ * Add ALUA Logical Unit Group and Target Port Group ConfigFS
+ * groups under /sys/kernel/config/target/core/alua/
+ */
+ alua_cg = &se_global->alua_group;
+ alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(alua_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate alua_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&se_global->alua_lu_gps_group,
+ "lu_gps", &target_core_alua_lu_gps_cit);
+ alua_cg->default_groups[0] = &se_global->alua_lu_gps_group;
+ alua_cg->default_groups[1] = NULL;
+ /*
+ * Add core/alua/lu_gps/default_lu_gp
+ */
+ lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1);
+ if (IS_ERR(lu_gp))
+ goto out_global;
+
+ lu_gp_cg = &se_global->alua_lu_gps_group;
+ lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(lu_gp_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate lu_gp_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp",
+ &target_core_alua_lu_gp_cit);
+ lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group;
+ lu_gp_cg->default_groups[1] = NULL;
+ se_global->default_lu_gp = lu_gp;
+ /*
+ * Register the target_core_mod subsystem with configfs.
+ */
+ ret = configfs_register_subsystem(subsys);
+ if (ret < 0) {
+ printk(KERN_ERR "Error %d while registering subsystem %s\n",
+ ret, subsys->su_group.cg_item.ci_namebuf);
+ goto out_global;
+ }
+ printk(KERN_INFO "TARGET_CORE[0]: Initialized ConfigFS Fabric"
+ " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s"
+ " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine);
+ /*
+ * Register built-in RAMDISK subsystem logic for virtual LUN 0
+ */
+ ret = rd_module_init();
+ if (ret < 0)
+ goto out;
+
+ if (core_dev_setup_virtual_lun0() < 0)
+ goto out;
+
+ scsi_target_proc = proc_mkdir("scsi_target", 0);
+ if (!(scsi_target_proc)) {
+ printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n");
+ goto out;
+ }
+ ret = init_scsi_target_mib();
+ if (ret < 0)
+ goto out;
+
+ return 0;
+
+out:
+ configfs_unregister_subsystem(subsys);
+ if (scsi_target_proc)
+ remove_proc_entry("scsi_target", 0);
+ core_dev_release_virtual_lun0();
+ rd_module_exit();
+out_global:
+ if (se_global->default_lu_gp) {
+ core_alua_free_lu_gp(se_global->default_lu_gp);
+ se_global->default_lu_gp = NULL;
+ }
+ if (lu_gp_cg)
+ kfree(lu_gp_cg->default_groups);
+ if (alua_cg)
+ kfree(alua_cg->default_groups);
+ if (hba_cg)
+ kfree(hba_cg->default_groups);
+ kfree(target_cg->default_groups);
+ release_se_global();
+ return -1;
+}
+
+static void target_core_exit_configfs(void)
+{
+ struct configfs_subsystem *subsys;
+ struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
+ struct config_item *item;
+ int i;
+
+ se_global->in_shutdown = 1;
+ subsys = target_core_subsystem[0];
+
+ lu_gp_cg = &se_global->alua_lu_gps_group;
+ for (i = 0; lu_gp_cg->default_groups[i]; i++) {
+ item = &lu_gp_cg->default_groups[i]->cg_item;
+ lu_gp_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(lu_gp_cg->default_groups);
+ core_alua_free_lu_gp(se_global->default_lu_gp);
+ se_global->default_lu_gp = NULL;
+
+ alua_cg = &se_global->alua_group;
+ for (i = 0; alua_cg->default_groups[i]; i++) {
+ item = &alua_cg->default_groups[i]->cg_item;
+ alua_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(alua_cg->default_groups);
+
+ hba_cg = &se_global->target_core_hbagroup;
+ for (i = 0; hba_cg->default_groups[i]; i++) {
+ item = &hba_cg->default_groups[i]->cg_item;
+ hba_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(hba_cg->default_groups);
+
+ for (i = 0; subsys->su_group.default_groups[i]; i++) {
+ item = &subsys->su_group.default_groups[i]->cg_item;
+ subsys->su_group.default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(subsys->su_group.default_groups);
+
+ configfs_unregister_subsystem(subsys);
+ printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric"
+ " Infrastructure\n");
+
+ remove_scsi_target_mib();
+ remove_proc_entry("scsi_target", 0);
+ core_dev_release_virtual_lun0();
+ rd_module_exit();
+ release_se_global();
+
+ return;
+}
+
+MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(target_core_init_configfs);
+module_exit(target_core_exit_configfs);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
new file mode 100644
index 000000000000..317ce58d426d
--- /dev/null
+++ b/drivers/target/target_core_device.c
@@ -0,0 +1,1694 @@
+/*******************************************************************************
+ * Filename: target_core_device.c (based on iscsi_target_device.c)
+ *
+ * This file contains the iSCSI Virtual Device and Disk Transport
+ * agnostic related functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kthread.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+static void se_dev_start(struct se_device *dev);
+static void se_dev_stop(struct se_device *dev);
+
+int transport_get_lun_for_cmd(
+ struct se_cmd *se_cmd,
+ unsigned char *cdb,
+ u32 unpacked_lun)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun = NULL;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ unsigned long flags;
+ int read_only = 0;
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ deve = se_cmd->se_deve =
+ &SE_NODE_ACL(se_sess)->device_list[unpacked_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ if (se_cmd) {
+ deve->total_cmds++;
+ deve->total_bytes += se_cmd->data_length;
+
+ if (se_cmd->data_direction == DMA_TO_DEVICE) {
+ if (deve->lun_flags &
+ TRANSPORT_LUNFLAGS_READ_ONLY) {
+ read_only = 1;
+ goto out;
+ }
+ deve->write_bytes += se_cmd->data_length;
+ } else if (se_cmd->data_direction ==
+ DMA_FROM_DEVICE) {
+ deve->read_bytes += se_cmd->data_length;
+ }
+ }
+ deve->deve_cmds++;
+
+ se_lun = se_cmd->se_lun = deve->se_lun;
+ se_cmd->pr_res_key = deve->pr_res_key;
+ se_cmd->orig_fe_lun = unpacked_lun;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+ se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+ }
+out:
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ if (!se_lun) {
+ if (read_only) {
+ se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ printk("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ return -1;
+ } else {
+ /*
+ * Use the se_portal_group->tpg_virt_lun0 to allow for
+ * REPORT_LUNS, et al to be returned when no active
+ * MappedLUN=0 exists for this Initiator Port.
+ */
+ if (unpacked_lun != 0) {
+ se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ printk("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ return -1;
+ }
+ /*
+ * Force WRITE PROTECT for virtual LUN 0
+ */
+ if ((se_cmd->data_direction != DMA_FROM_DEVICE) &&
+ (se_cmd->data_direction != DMA_NONE)) {
+ se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+#if 0
+ printk("TARGET_CORE[%s]: Using virtual LUN0! :-)\n",
+ CMD_TFO(se_cmd)->get_fabric_name());
+#endif
+ se_lun = se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0;
+ se_cmd->orig_fe_lun = 0;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+ se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+ }
+ }
+ /*
+ * Determine if the struct se_lun is online.
+ */
+/* #warning FIXME: Check for LUN_RESET + UNIT Attention */
+ if (se_dev_check_online(se_lun->lun_se_dev) != 0) {
+ se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+
+ {
+ struct se_device *dev = se_lun->lun_se_dev;
+ spin_lock(&dev->stats_lock);
+ dev->num_cmds++;
+ if (se_cmd->data_direction == DMA_TO_DEVICE)
+ dev->write_bytes += se_cmd->data_length;
+ else if (se_cmd->data_direction == DMA_FROM_DEVICE)
+ dev->read_bytes += se_cmd->data_length;
+ spin_unlock(&dev->stats_lock);
+ }
+
+ /*
+ * Add the iscsi_cmd_t to the struct se_lun's cmd list. This list is used
+ * for tracking state of struct se_cmds during LUN shutdown events.
+ */
+ spin_lock_irqsave(&se_lun->lun_cmd_lock, flags);
+ list_add_tail(&se_cmd->se_lun_list, &se_lun->lun_cmd_list);
+ atomic_set(&T_TASK(se_cmd)->transport_lun_active, 1);
+#if 0
+ printk(KERN_INFO "Adding ITT: 0x%08x to LUN LIST[%d]\n",
+ CMD_TFO(se_cmd)->get_task_tag(se_cmd), se_lun->unpacked_lun);
+#endif
+ spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_get_lun_for_cmd);
+
+int transport_get_lun_for_tmr(
+ struct se_cmd *se_cmd,
+ u32 unpacked_lun)
+{
+ struct se_device *dev = NULL;
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun = NULL;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ deve = se_cmd->se_deve =
+ &SE_NODE_ACL(se_sess)->device_list[unpacked_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ se_lun = se_cmd->se_lun = se_tmr->tmr_lun = deve->se_lun;
+ dev = se_tmr->tmr_dev = se_lun->lun_se_dev;
+ se_cmd->pr_res_key = deve->pr_res_key;
+ se_cmd->orig_fe_lun = unpacked_lun;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+/* se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; */
+ }
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ if (!se_lun) {
+ printk(KERN_INFO "TARGET_CORE[%s]: Detected NON_EXISTENT_LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+ /*
+ * Determine if the struct se_lun is online.
+ */
+/* #warning FIXME: Check for LUN_RESET + UNIT Attention */
+ if (se_dev_check_online(se_lun->lun_se_dev) != 0) {
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+
+ spin_lock(&dev->se_tmr_lock);
+ list_add_tail(&se_tmr->tmr_list, &dev->dev_tmr_list);
+ spin_unlock(&dev->se_tmr_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_get_lun_for_tmr);
+
+/*
+ * This function is called from core_scsi3_emulate_pro_register_and_move()
+ * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_ref_count
+ * when a matching rtpi is found.
+ */
+struct se_dev_entry *core_get_se_deve_from_rtpi(
+ struct se_node_acl *nacl,
+ u16 rtpi)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_port *port;
+ struct se_portal_group *tpg = nacl->se_tpg;
+ u32 i;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ lun = deve->se_lun;
+ if (!(lun)) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ port = lun->lun_sep;
+ if (!(port)) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ if (port->sep_rtpi != rtpi)
+ continue;
+
+ atomic_inc(&deve->pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return deve;
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return NULL;
+}
+
+int core_free_device_list_for_node(
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ u32 i;
+
+ if (!nacl->device_list)
+ return 0;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ if (!deve->se_lun) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ lun = deve->se_lun;
+
+ spin_unlock_irq(&nacl->device_list_lock);
+ core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+ spin_lock_irq(&nacl->device_list_lock);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ kfree(nacl->device_list);
+ nacl->device_list = NULL;
+
+ return 0;
+}
+
+void core_dec_lacl_count(struct se_node_acl *se_nacl, struct se_cmd *se_cmd)
+{
+ struct se_dev_entry *deve;
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ deve = &se_nacl->device_list[se_cmd->orig_fe_lun];
+ deve->deve_cmds--;
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ return;
+}
+
+void core_update_device_list_access(
+ u32 mapped_lun,
+ u32 lun_access,
+ struct se_node_acl *nacl)
+{
+ struct se_dev_entry *deve;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[mapped_lun];
+ if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return;
+}
+
+/* core_update_device_list_for_node():
+ *
+ *
+ */
+int core_update_device_list_for_node(
+ struct se_lun *lun,
+ struct se_lun_acl *lun_acl,
+ u32 mapped_lun,
+ u32 lun_access,
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg,
+ int enable)
+{
+ struct se_port *port = lun->lun_sep;
+ struct se_dev_entry *deve = &nacl->device_list[mapped_lun];
+ int trans = 0;
+ /*
+ * If the MappedLUN entry is being disabled, the entry in
+ * port->sep_alua_list must be removed now before clearing the
+ * struct se_dev_entry pointers below as logic in
+ * core_alua_do_transition_tg_pt() depends on these being present.
+ */
+ if (!(enable)) {
+ /*
+ * deve->se_lun_acl will be NULL for demo-mode created LUNs
+ * that have not been explictly concerted to MappedLUNs ->
+ * struct se_lun_acl.
+ */
+ if (!(deve->se_lun_acl))
+ return 0;
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_del(&deve->alua_port_list);
+ spin_unlock_bh(&port->sep_alua_lock);
+ }
+
+ spin_lock_irq(&nacl->device_list_lock);
+ if (enable) {
+ /*
+ * Check if the call is handling demo mode -> explict LUN ACL
+ * transition. This transition must be for the same struct se_lun
+ * + mapped_lun that was setup in demo mode..
+ */
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ if (deve->se_lun_acl != NULL) {
+ printk(KERN_ERR "struct se_dev_entry->se_lun_acl"
+ " already set for demo mode -> explict"
+ " LUN ACL transition\n");
+ return -1;
+ }
+ if (deve->se_lun != lun) {
+ printk(KERN_ERR "struct se_dev_entry->se_lun does"
+ " match passed struct se_lun for demo mode"
+ " -> explict LUN ACL transition\n");
+ return -1;
+ }
+ deve->se_lun_acl = lun_acl;
+ trans = 1;
+ } else {
+ deve->se_lun = lun;
+ deve->se_lun_acl = lun_acl;
+ deve->mapped_lun = mapped_lun;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS;
+ }
+
+ if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
+ }
+
+ if (trans) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return 0;
+ }
+ deve->creation_time = get_jiffies_64();
+ deve->attach_count++;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_add_tail(&deve->alua_port_list, &port->sep_alua_list);
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ return 0;
+ }
+ /*
+ * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE
+ * PR operation to complete.
+ */
+ spin_unlock_irq(&nacl->device_list_lock);
+ while (atomic_read(&deve->pr_ref_count) != 0)
+ cpu_relax();
+ spin_lock_irq(&nacl->device_list_lock);
+ /*
+ * Disable struct se_dev_entry LUN ACL mapping
+ */
+ core_scsi3_ua_release_all(deve);
+ deve->se_lun = NULL;
+ deve->se_lun_acl = NULL;
+ deve->lun_flags = 0;
+ deve->creation_time = 0;
+ deve->attach_count--;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl);
+ return 0;
+}
+
+/* core_clear_lun_from_tpg():
+ *
+ *
+ */
+void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
+{
+ struct se_node_acl *nacl;
+ struct se_dev_entry *deve;
+ u32 i;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+ if (lun != deve->se_lun)
+ continue;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ core_update_device_list_for_node(lun, NULL,
+ deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS,
+ nacl, tpg, 0);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return;
+}
+
+static struct se_port *core_alloc_port(struct se_device *dev)
+{
+ struct se_port *port, *port_tmp;
+
+ port = kzalloc(sizeof(struct se_port), GFP_KERNEL);
+ if (!(port)) {
+ printk(KERN_ERR "Unable to allocate struct se_port\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(&port->sep_alua_list);
+ INIT_LIST_HEAD(&port->sep_list);
+ atomic_set(&port->sep_tg_pt_secondary_offline, 0);
+ spin_lock_init(&port->sep_alua_lock);
+ mutex_init(&port->sep_tg_pt_md_mutex);
+
+ spin_lock(&dev->se_port_lock);
+ if (dev->dev_port_count == 0x0000ffff) {
+ printk(KERN_WARNING "Reached dev->dev_port_count =="
+ " 0x0000ffff\n");
+ spin_unlock(&dev->se_port_lock);
+ return NULL;
+ }
+again:
+ /*
+ * Allocate the next RELATIVE TARGET PORT IDENTIFER for this struct se_device
+ * Here is the table from spc4r17 section 7.7.3.8.
+ *
+ * Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
+ *
+ * Code Description
+ * 0h Reserved
+ * 1h Relative port 1, historically known as port A
+ * 2h Relative port 2, historically known as port B
+ * 3h to FFFFh Relative port 3 through 65 535
+ */
+ port->sep_rtpi = dev->dev_rpti_counter++;
+ if (!(port->sep_rtpi))
+ goto again;
+
+ list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) {
+ /*
+ * Make sure RELATIVE TARGET PORT IDENTIFER is unique
+ * for 16-bit wrap..
+ */
+ if (port->sep_rtpi == port_tmp->sep_rtpi)
+ goto again;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return port;
+}
+
+static void core_export_port(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_port *port,
+ struct se_lun *lun)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL;
+
+ spin_lock(&dev->se_port_lock);
+ spin_lock(&lun->lun_sep_lock);
+ port->sep_tpg = tpg;
+ port->sep_lun = lun;
+ lun->lun_sep = port;
+ spin_unlock(&lun->lun_sep_lock);
+
+ list_add_tail(&port->sep_list, &dev->dev_sep_list);
+ spin_unlock(&dev->se_port_lock);
+
+ if (T10_ALUA(su_dev)->alua_type == SPC3_ALUA_EMULATED) {
+ tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port);
+ if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) {
+ printk(KERN_ERR "Unable to allocate t10_alua_tg_pt"
+ "_gp_member_t\n");
+ return;
+ }
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_INFO "%s/%s: Adding to default ALUA Target Port"
+ " Group: alua/default_tg_pt_gp\n",
+ TRANSPORT(dev)->name, TPG_TFO(tpg)->get_fabric_name());
+ }
+
+ dev->dev_port_count++;
+ port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFER */
+}
+
+/*
+ * Called with struct se_device->se_port_lock spinlock held.
+ */
+static void core_release_port(struct se_device *dev, struct se_port *port)
+{
+ /*
+ * Wait for any port reference for PR ALL_TG_PT=1 operation
+ * to complete in __core_scsi3_alloc_registration()
+ */
+ spin_unlock(&dev->se_port_lock);
+ if (atomic_read(&port->sep_tg_pt_ref_cnt))
+ cpu_relax();
+ spin_lock(&dev->se_port_lock);
+
+ core_alua_free_tg_pt_gp_mem(port);
+
+ list_del(&port->sep_list);
+ dev->dev_port_count--;
+ kfree(port);
+
+ return;
+}
+
+int core_dev_export(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ struct se_port *port;
+
+ port = core_alloc_port(dev);
+ if (!(port))
+ return -1;
+
+ lun->lun_se_dev = dev;
+ se_dev_start(dev);
+
+ atomic_inc(&dev->dev_export_obj.obj_access_count);
+ core_export_port(dev, tpg, port, lun);
+ return 0;
+}
+
+void core_dev_unexport(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ struct se_port *port = lun->lun_sep;
+
+ spin_lock(&lun->lun_sep_lock);
+ if (lun->lun_se_dev == NULL) {
+ spin_unlock(&lun->lun_sep_lock);
+ return;
+ }
+ spin_unlock(&lun->lun_sep_lock);
+
+ spin_lock(&dev->se_port_lock);
+ atomic_dec(&dev->dev_export_obj.obj_access_count);
+ core_release_port(dev, port);
+ spin_unlock(&dev->se_port_lock);
+
+ se_dev_stop(dev);
+ lun->lun_se_dev = NULL;
+}
+
+int transport_core_report_lun_response(struct se_cmd *se_cmd)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ struct se_task *se_task;
+ unsigned char *buf = (unsigned char *)T_TASK(se_cmd)->t_task_buf;
+ u32 cdb_offset = 0, lun_count = 0, offset = 8;
+ u64 i, lun;
+
+ list_for_each_entry(se_task, &T_TASK(se_cmd)->t_task_list, t_list)
+ break;
+
+ if (!(se_task)) {
+ printk(KERN_ERR "Unable to locate struct se_task for struct se_cmd\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ /*
+ * If no struct se_session pointer is present, this struct se_cmd is
+ * coming via a target_core_mod PASSTHROUGH op, and not through
+ * a $FABRIC_MOD. In that case, report LUN=0 only.
+ */
+ if (!(se_sess)) {
+ lun = 0;
+ buf[offset++] = ((lun >> 56) & 0xff);
+ buf[offset++] = ((lun >> 48) & 0xff);
+ buf[offset++] = ((lun >> 40) & 0xff);
+ buf[offset++] = ((lun >> 32) & 0xff);
+ buf[offset++] = ((lun >> 24) & 0xff);
+ buf[offset++] = ((lun >> 16) & 0xff);
+ buf[offset++] = ((lun >> 8) & 0xff);
+ buf[offset++] = (lun & 0xff);
+ lun_count = 1;
+ goto done;
+ }
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &SE_NODE_ACL(se_sess)->device_list[i];
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+ se_lun = deve->se_lun;
+ /*
+ * We determine the correct LUN LIST LENGTH even once we
+ * have reached the initial allocation length.
+ * See SPC2-R20 7.19.
+ */
+ lun_count++;
+ if ((cdb_offset + 8) >= se_cmd->data_length)
+ continue;
+
+ lun = cpu_to_be64(CMD_TFO(se_cmd)->pack_lun(deve->mapped_lun));
+ buf[offset++] = ((lun >> 56) & 0xff);
+ buf[offset++] = ((lun >> 48) & 0xff);
+ buf[offset++] = ((lun >> 40) & 0xff);
+ buf[offset++] = ((lun >> 32) & 0xff);
+ buf[offset++] = ((lun >> 24) & 0xff);
+ buf[offset++] = ((lun >> 16) & 0xff);
+ buf[offset++] = ((lun >> 8) & 0xff);
+ buf[offset++] = (lun & 0xff);
+ cdb_offset += 8;
+ }
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ /*
+ * See SPC3 r07, page 159.
+ */
+done:
+ lun_count *= 8;
+ buf[0] = ((lun_count >> 24) & 0xff);
+ buf[1] = ((lun_count >> 16) & 0xff);
+ buf[2] = ((lun_count >> 8) & 0xff);
+ buf[3] = (lun_count & 0xff);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* se_release_device_for_hba():
+ *
+ *
+ */
+void se_release_device_for_hba(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ if ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) ||
+ (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_DEACTIVATED))
+ se_dev_stop(dev);
+
+ if (dev->dev_ptr) {
+ kthread_stop(dev->process_thread);
+ if (dev->transport->free_device)
+ dev->transport->free_device(dev->dev_ptr);
+ }
+
+ spin_lock(&hba->device_lock);
+ list_del(&dev->dev_list);
+ hba->dev_count--;
+ spin_unlock(&hba->device_lock);
+
+ core_scsi3_free_all_registrations(dev);
+ se_release_vpd_for_dev(dev);
+
+ kfree(dev->dev_status_queue_obj);
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+
+ return;
+}
+
+void se_release_vpd_for_dev(struct se_device *dev)
+{
+ struct t10_vpd *vpd, *vpd_tmp;
+
+ spin_lock(&DEV_T10_WWN(dev)->t10_vpd_lock);
+ list_for_each_entry_safe(vpd, vpd_tmp,
+ &DEV_T10_WWN(dev)->t10_vpd_list, vpd_list) {
+ list_del(&vpd->vpd_list);
+ kfree(vpd);
+ }
+ spin_unlock(&DEV_T10_WWN(dev)->t10_vpd_lock);
+
+ return;
+}
+
+/*
+ * Called with struct se_hba->device_lock held.
+ */
+void se_clear_dev_ports(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+ struct se_lun *lun;
+ struct se_portal_group *tpg;
+ struct se_port *sep, *sep_tmp;
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ spin_unlock(&dev->se_port_lock);
+ spin_unlock(&hba->device_lock);
+
+ lun = sep->sep_lun;
+ tpg = sep->sep_tpg;
+ spin_lock(&lun->lun_sep_lock);
+ if (lun->lun_se_dev == NULL) {
+ spin_unlock(&lun->lun_sep_lock);
+ continue;
+ }
+ spin_unlock(&lun->lun_sep_lock);
+
+ core_dev_del_lun(tpg, lun->unpacked_lun);
+
+ spin_lock(&hba->device_lock);
+ spin_lock(&dev->se_port_lock);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return;
+}
+
+/* se_free_virtual_device():
+ *
+ * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers.
+ */
+int se_free_virtual_device(struct se_device *dev, struct se_hba *hba)
+{
+ spin_lock(&hba->device_lock);
+ se_clear_dev_ports(dev);
+ spin_unlock(&hba->device_lock);
+
+ core_alua_free_lu_gp_mem(dev);
+ se_release_device_for_hba(dev);
+
+ return 0;
+}
+
+static void se_dev_start(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ spin_lock(&hba->device_lock);
+ atomic_inc(&dev->dev_obj.obj_access_count);
+ if (atomic_read(&dev->dev_obj.obj_access_count) == 1) {
+ if (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_DEACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_ACTIVATED;
+ } else if (dev->dev_status &
+ TRANSPORT_DEVICE_OFFLINE_DEACTIVATED) {
+ dev->dev_status &=
+ ~TRANSPORT_DEVICE_OFFLINE_DEACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_ACTIVATED;
+ }
+ }
+ spin_unlock(&hba->device_lock);
+}
+
+static void se_dev_stop(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ spin_lock(&hba->device_lock);
+ atomic_dec(&dev->dev_obj.obj_access_count);
+ if (atomic_read(&dev->dev_obj.obj_access_count) == 0) {
+ if (dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_ACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED;
+ } else if (dev->dev_status &
+ TRANSPORT_DEVICE_OFFLINE_ACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_OFFLINE_ACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_DEACTIVATED;
+ }
+ }
+ spin_unlock(&hba->device_lock);
+
+ while (atomic_read(&hba->dev_mib_access_count))
+ cpu_relax();
+}
+
+int se_dev_check_online(struct se_device *dev)
+{
+ int ret;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ ret = ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED)) ? 0 : 1;
+ spin_unlock_irq(&dev->dev_status_lock);
+
+ return ret;
+}
+
+int se_dev_check_shutdown(struct se_device *dev)
+{
+ int ret;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ ret = (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN);
+ spin_unlock_irq(&dev->dev_status_lock);
+
+ return ret;
+}
+
+void se_dev_set_default_attribs(
+ struct se_device *dev,
+ struct se_dev_limits *dev_limits)
+{
+ struct queue_limits *limits = &dev_limits->limits;
+
+ DEV_ATTRIB(dev)->emulate_dpo = DA_EMULATE_DPO;
+ DEV_ATTRIB(dev)->emulate_fua_write = DA_EMULATE_FUA_WRITE;
+ DEV_ATTRIB(dev)->emulate_fua_read = DA_EMULATE_FUA_READ;
+ DEV_ATTRIB(dev)->emulate_write_cache = DA_EMULATE_WRITE_CACHE;
+ DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL;
+ DEV_ATTRIB(dev)->emulate_tas = DA_EMULATE_TAS;
+ DEV_ATTRIB(dev)->emulate_tpu = DA_EMULATE_TPU;
+ DEV_ATTRIB(dev)->emulate_tpws = DA_EMULATE_TPWS;
+ DEV_ATTRIB(dev)->emulate_reservations = DA_EMULATE_RESERVATIONS;
+ DEV_ATTRIB(dev)->emulate_alua = DA_EMULATE_ALUA;
+ DEV_ATTRIB(dev)->enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
+ /*
+ * The TPU=1 and TPWS=1 settings will be set in TCM/IBLOCK
+ * iblock_create_virtdevice() from struct queue_limits values
+ * if blk_queue_discard()==1
+ */
+ DEV_ATTRIB(dev)->max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT;
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count =
+ DA_MAX_UNMAP_BLOCK_DESC_COUNT;
+ DEV_ATTRIB(dev)->unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
+ DEV_ATTRIB(dev)->unmap_granularity_alignment =
+ DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
+ /*
+ * block_size is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_block_size = limits->logical_block_size;
+ DEV_ATTRIB(dev)->block_size = limits->logical_block_size;
+ /*
+ * max_sectors is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_max_sectors = limits->max_hw_sectors;
+ DEV_ATTRIB(dev)->max_sectors = limits->max_sectors;
+ /*
+ * Set optimal_sectors from max_sectors, which can be lowered via
+ * configfs.
+ */
+ DEV_ATTRIB(dev)->optimal_sectors = limits->max_sectors;
+ /*
+ * queue_depth is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_queue_depth = dev_limits->hw_queue_depth;
+ DEV_ATTRIB(dev)->queue_depth = dev_limits->queue_depth;
+}
+
+int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
+{
+ if (task_timeout > DA_TASK_TIMEOUT_MAX) {
+ printk(KERN_ERR "dev[%p]: Passed task_timeout: %u larger then"
+ " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout);
+ return -1;
+ } else {
+ DEV_ATTRIB(dev)->task_timeout = task_timeout;
+ printk(KERN_INFO "dev[%p]: Set SE Device task_timeout: %u\n",
+ dev, task_timeout);
+ }
+
+ return 0;
+}
+
+int se_dev_set_max_unmap_lba_count(
+ struct se_device *dev,
+ u32 max_unmap_lba_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_lba_count = max_unmap_lba_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_lba_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_lba_count);
+ return 0;
+}
+
+int se_dev_set_max_unmap_block_desc_count(
+ struct se_device *dev,
+ u32 max_unmap_block_desc_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count = max_unmap_block_desc_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_block_desc_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_block_desc_count);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity(
+ struct se_device *dev,
+ u32 unmap_granularity)
+{
+ DEV_ATTRIB(dev)->unmap_granularity = unmap_granularity;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity_alignment(
+ struct se_device *dev,
+ u32 unmap_granularity_alignment)
+{
+ DEV_ATTRIB(dev)->unmap_granularity_alignment = unmap_granularity_alignment;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity_alignment: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity_alignment);
+ return 0;
+}
+
+int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->dpo_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->dpo_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_dpo = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Page Out (DPO) Emulation"
+ " bit: %d\n", dev, DEV_ATTRIB(dev)->emulate_dpo);
+ return 0;
+}
+
+int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_write_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_write_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_fua_write = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_fua_write);
+ return 0;
+}
+
+int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_read_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_read_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_fua_read = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access READs: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_fua_read);
+ return 0;
+}
+
+int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->write_cache_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->write_cache_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_write_cache = flag;
+ printk(KERN_INFO "dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_write_cache);
+ return 0;
+}
+
+int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1) && (flag != 2)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " UA_INTRLCK_CTRL while dev_export_obj: %d count"
+ " exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = flag;
+ printk(KERN_INFO "dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl);
+
+ return 0;
+}
+
+int se_dev_set_emulate_tas(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device TAS while"
+ " dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_tas = flag;
+ printk(KERN_INFO "dev[%p]: SE Device TASK_ABORTED status bit: %s\n",
+ dev, (DEV_ATTRIB(dev)->emulate_tas) ? "Enabled" : "Disabled");
+
+ return 0;
+}
+
+int se_dev_set_emulate_tpu(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ /*
+ * We expect this value to be non-zero when generic Block Layer
+ * Discard supported is detected iblock_create_virtdevice().
+ */
+ if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) {
+ printk(KERN_ERR "Generic Block Discard not supported\n");
+ return -ENOSYS;
+ }
+
+ DEV_ATTRIB(dev)->emulate_tpu = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n",
+ dev, flag);
+ return 0;
+}
+
+int se_dev_set_emulate_tpws(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ /*
+ * We expect this value to be non-zero when generic Block Layer
+ * Discard supported is detected iblock_create_virtdevice().
+ */
+ if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) {
+ printk(KERN_ERR "Generic Block Discard not supported\n");
+ return -ENOSYS;
+ }
+
+ DEV_ATTRIB(dev)->emulate_tpws = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n",
+ dev, flag);
+ return 0;
+}
+
+int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ DEV_ATTRIB(dev)->enforce_pr_isids = flag;
+ printk(KERN_INFO "dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev,
+ (DEV_ATTRIB(dev)->enforce_pr_isids) ? "Enabled" : "Disabled");
+ return 0;
+}
+
+/*
+ * Note, this can only be called on unexported SE Device Object.
+ */
+int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
+{
+ u32 orig_queue_depth = dev->queue_depth;
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device TCQ while"
+ " dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ if (!(queue_depth)) {
+ printk(KERN_ERR "dev[%p]: Illegal ZERO value for queue"
+ "_depth\n", dev);
+ return -1;
+ }
+
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) {
+ printk(KERN_ERR "dev[%p]: Passed queue_depth: %u"
+ " exceeds TCM/SE_Device TCQ: %u\n",
+ dev, queue_depth,
+ DEV_ATTRIB(dev)->hw_queue_depth);
+ return -1;
+ }
+ } else {
+ if (queue_depth > DEV_ATTRIB(dev)->queue_depth) {
+ if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) {
+ printk(KERN_ERR "dev[%p]: Passed queue_depth:"
+ " %u exceeds TCM/SE_Device MAX"
+ " TCQ: %u\n", dev, queue_depth,
+ DEV_ATTRIB(dev)->hw_queue_depth);
+ return -1;
+ }
+ }
+ }
+
+ DEV_ATTRIB(dev)->queue_depth = dev->queue_depth = queue_depth;
+ if (queue_depth > orig_queue_depth)
+ atomic_add(queue_depth - orig_queue_depth, &dev->depth_left);
+ else if (queue_depth < orig_queue_depth)
+ atomic_sub(orig_queue_depth - queue_depth, &dev->depth_left);
+
+ printk(KERN_INFO "dev[%p]: SE Device TCQ Depth changed to: %u\n",
+ dev, queue_depth);
+ return 0;
+}
+
+int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
+{
+ int force = 0; /* Force setting for VDEVS */
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " max_sectors while dev_export_obj: %d count exists\n",
+ dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ if (!(max_sectors)) {
+ printk(KERN_ERR "dev[%p]: Illegal ZERO value for"
+ " max_sectors\n", dev);
+ return -1;
+ }
+ if (max_sectors < DA_STATUS_MAX_SECTORS_MIN) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u less than"
+ " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, max_sectors,
+ DA_STATUS_MAX_SECTORS_MIN);
+ return -1;
+ }
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (max_sectors > DEV_ATTRIB(dev)->hw_max_sectors) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than TCM/SE_Device max_sectors:"
+ " %u\n", dev, max_sectors,
+ DEV_ATTRIB(dev)->hw_max_sectors);
+ return -1;
+ }
+ } else {
+ if (!(force) && (max_sectors >
+ DEV_ATTRIB(dev)->hw_max_sectors)) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than TCM/SE_Device max_sectors"
+ ": %u, use force=1 to override.\n", dev,
+ max_sectors, DEV_ATTRIB(dev)->hw_max_sectors);
+ return -1;
+ }
+ if (max_sectors > DA_STATUS_MAX_SECTORS_MAX) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than DA_STATUS_MAX_SECTORS_MAX:"
+ " %u\n", dev, max_sectors,
+ DA_STATUS_MAX_SECTORS_MAX);
+ return -1;
+ }
+ }
+
+ DEV_ATTRIB(dev)->max_sectors = max_sectors;
+ printk("dev[%p]: SE Device max_sectors changed to %u\n",
+ dev, max_sectors);
+ return 0;
+}
+
+int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
+{
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " optimal_sectors while dev_export_obj: %d count exists\n",
+ dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -EINVAL;
+ }
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors cannot be"
+ " changed for TCM/pSCSI\n", dev);
+ return -EINVAL;
+ }
+ if (optimal_sectors > DEV_ATTRIB(dev)->max_sectors) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors %u cannot be"
+ " greater than max_sectors: %u\n", dev,
+ optimal_sectors, DEV_ATTRIB(dev)->max_sectors);
+ return -EINVAL;
+ }
+
+ DEV_ATTRIB(dev)->optimal_sectors = optimal_sectors;
+ printk(KERN_INFO "dev[%p]: SE Device optimal_sectors changed to %u\n",
+ dev, optimal_sectors);
+ return 0;
+}
+
+int se_dev_set_block_size(struct se_device *dev, u32 block_size)
+{
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device block_size"
+ " while dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+
+ if ((block_size != 512) &&
+ (block_size != 1024) &&
+ (block_size != 2048) &&
+ (block_size != 4096)) {
+ printk(KERN_ERR "dev[%p]: Illegal value for block_device: %u"
+ " for SE device, must be 512, 1024, 2048 or 4096\n",
+ dev, block_size);
+ return -1;
+ }
+
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ printk(KERN_ERR "dev[%p]: Not allowed to change block_size for"
+ " Physical Device, use for Linux/SCSI to change"
+ " block_size for underlying hardware\n", dev);
+ return -1;
+ }
+
+ DEV_ATTRIB(dev)->block_size = block_size;
+ printk(KERN_INFO "dev[%p]: SE Device block_size changed to %u\n",
+ dev, block_size);
+ return 0;
+}
+
+struct se_lun *core_dev_add_lun(
+ struct se_portal_group *tpg,
+ struct se_hba *hba,
+ struct se_device *dev,
+ u32 lun)
+{
+ struct se_lun *lun_p;
+ u32 lun_access = 0;
+
+ if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) {
+ printk(KERN_ERR "Unable to export struct se_device while dev_access_obj: %d\n",
+ atomic_read(&dev->dev_access_obj.obj_access_count));
+ return NULL;
+ }
+
+ lun_p = core_tpg_pre_addlun(tpg, lun);
+ if ((IS_ERR(lun_p)) || !(lun_p))
+ return NULL;
+
+ if (dev->dev_flags & DF_READ_ONLY)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+
+ if (core_tpg_post_addlun(tpg, lun_p, lun_access, dev) < 0)
+ return NULL;
+
+ printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"
+ " CORE HBA: %u\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun_p->unpacked_lun,
+ TPG_TFO(tpg)->get_fabric_name(), hba->hba_id);
+ /*
+ * Update LUN maps for dynamically added initiators when
+ * generate_node_acl is enabled.
+ */
+ if (TPG_TFO(tpg)->tpg_check_demo_mode(tpg)) {
+ struct se_node_acl *acl;
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (acl->dynamic_node_acl) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+ core_tpg_add_node_to_devs(acl, tpg);
+ spin_lock_bh(&tpg->acl_node_lock);
+ }
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+ }
+
+ return lun_p;
+}
+
+/* core_dev_del_lun():
+ *
+ *
+ */
+int core_dev_del_lun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun)
+{
+ struct se_lun *lun;
+ int ret = 0;
+
+ lun = core_tpg_pre_dellun(tpg, unpacked_lun, &ret);
+ if (!(lun))
+ return ret;
+
+ core_tpg_post_dellun(tpg, lun);
+
+ printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Deactivated %s Logical Unit from"
+ " device object\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun,
+ TPG_TFO(tpg)->get_fabric_name());
+
+ return 0;
+}
+
+struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS"
+ "_PER_TPG-1: %u for Target Portal Group: %hu\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not free on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+/* core_dev_get_lun():
+ *
+ *
+ */
+static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER"
+ "_TPG-1: %u for Target Portal Group: %hu\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ u32 mapped_lun,
+ char *initiatorname,
+ int *ret)
+{
+ struct se_lun_acl *lacl;
+ struct se_node_acl *nacl;
+
+ if (strlen(initiatorname) > TRANSPORT_IQN_LEN) {
+ printk(KERN_ERR "%s InitiatorName exceeds maximum size.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ *ret = -EOVERFLOW;
+ return NULL;
+ }
+ nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (!(nacl)) {
+ *ret = -EINVAL;
+ return NULL;
+ }
+ lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL);
+ if (!(lacl)) {
+ printk(KERN_ERR "Unable to allocate memory for struct se_lun_acl.\n");
+ *ret = -ENOMEM;
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&lacl->lacl_list);
+ lacl->mapped_lun = mapped_lun;
+ lacl->se_lun_nacl = nacl;
+ snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+
+ return lacl;
+}
+
+int core_dev_add_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun_acl *lacl,
+ u32 unpacked_lun,
+ u32 lun_access)
+{
+ struct se_lun *lun;
+ struct se_node_acl *nacl;
+
+ lun = core_dev_get_lun(tpg, unpacked_lun);
+ if (!(lun)) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return -EINVAL;
+ }
+
+ nacl = lacl->se_lun_nacl;
+ if (!(nacl))
+ return -EINVAL;
+
+ if ((lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) &&
+ (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE))
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+
+ lacl->se_lun = lun;
+
+ if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun,
+ lun_access, nacl, tpg, 1) < 0)
+ return -EINVAL;
+
+ spin_lock(&lun->lun_acl_lock);
+ list_add_tail(&lacl->lacl_list, &lun->lun_acl_list);
+ atomic_inc(&lun->lun_acl_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&lun->lun_acl_lock);
+
+ printk(KERN_INFO "%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for "
+ " InitiatorNode: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun, lacl->mapped_lun,
+ (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO",
+ lacl->initiatorname);
+ /*
+ * Check to see if there are any existing persistent reservation APTPL
+ * pre-registrations that need to be enabled for this LUN ACL..
+ */
+ core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, lacl);
+ return 0;
+}
+
+/* core_dev_del_initiator_node_lun_acl():
+ *
+ *
+ */
+int core_dev_del_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ struct se_lun_acl *lacl)
+{
+ struct se_node_acl *nacl;
+
+ nacl = lacl->se_lun_nacl;
+ if (!(nacl))
+ return -EINVAL;
+
+ spin_lock(&lun->lun_acl_lock);
+ list_del(&lacl->lacl_list);
+ atomic_dec(&lun->lun_acl_count);
+ smp_mb__after_atomic_dec();
+ spin_unlock(&lun->lun_acl_lock);
+
+ core_update_device_list_for_node(lun, NULL, lacl->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+
+ lacl->se_lun = NULL;
+
+ printk(KERN_INFO "%s_TPG[%hu]_LUN[%u] - Removed ACL for"
+ " InitiatorNode: %s Mapped LUN: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun,
+ lacl->initiatorname, lacl->mapped_lun);
+
+ return 0;
+}
+
+void core_dev_free_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun_acl *lacl)
+{
+ printk("%s_TPG[%hu] - Freeing ACL for %s InitiatorNode: %s"
+ " Mapped LUN: %u\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ TPG_TFO(tpg)->get_fabric_name(),
+ lacl->initiatorname, lacl->mapped_lun);
+
+ kfree(lacl);
+}
+
+int core_dev_setup_virtual_lun0(void)
+{
+ struct se_hba *hba;
+ struct se_device *dev;
+ struct se_subsystem_dev *se_dev = NULL;
+ struct se_subsystem_api *t;
+ char buf[16];
+ int ret;
+
+ hba = core_alloc_hba("rd_dr", 0, HBA_FLAGS_INTERNAL_USE);
+ if (IS_ERR(hba))
+ return PTR_ERR(hba);
+
+ se_global->g_lun0_hba = hba;
+ t = hba->transport;
+
+ se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL);
+ if (!(se_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_subsystem_dev\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(&se_dev->g_se_dev_list);
+ INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list);
+ spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list);
+ spin_lock_init(&se_dev->t10_reservation.registration_lock);
+ spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock);
+ INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list);
+ spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock);
+ spin_lock_init(&se_dev->se_dev_lock);
+ se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
+ se_dev->t10_wwn.t10_sub_dev = se_dev;
+ se_dev->t10_alua.t10_sub_dev = se_dev;
+ se_dev->se_dev_attrib.da_sub_dev = se_dev;
+ se_dev->se_dev_hba = hba;
+
+ se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, "virt_lun0");
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate subsystem dependent pointer"
+ " from allocate_virtdevice()\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ se_global->g_lun0_su_dev = se_dev;
+
+ memset(buf, 0, 16);
+ sprintf(buf, "rd_pages=8");
+ t->set_configfs_dev_params(hba, se_dev, buf, sizeof(buf));
+
+ dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr);
+ if (!(dev) || IS_ERR(dev)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ se_dev->se_dev_ptr = dev;
+ se_global->g_lun0_dev = dev;
+
+ return 0;
+out:
+ se_global->g_lun0_su_dev = NULL;
+ kfree(se_dev);
+ if (se_global->g_lun0_hba) {
+ core_delete_hba(se_global->g_lun0_hba);
+ se_global->g_lun0_hba = NULL;
+ }
+ return ret;
+}
+
+
+void core_dev_release_virtual_lun0(void)
+{
+ struct se_hba *hba = se_global->g_lun0_hba;
+ struct se_subsystem_dev *su_dev = se_global->g_lun0_su_dev;
+
+ if (!(hba))
+ return;
+
+ if (se_global->g_lun0_dev)
+ se_free_virtual_device(se_global->g_lun0_dev, hba);
+
+ kfree(su_dev);
+ core_delete_hba(hba);
+}
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
new file mode 100644
index 000000000000..32b148d7e261
--- /dev/null
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -0,0 +1,996 @@
+/*******************************************************************************
+* Filename: target_core_fabric_configfs.c
+ *
+ * This file contains generic fabric module configfs infrastructure for
+ * TCM v4.x code
+ *
+ * Copyright (c) 2010 Rising Tide Systems
+ * Copyright (c) 2010 Linux-iSCSI.org
+ *
+ * Copyright (c) 2010 Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/string.h>
+#include <linux/syscalls.h>
+#include <linux/configfs.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+
+#define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \
+static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
+{ \
+ struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \
+ struct config_item_type *cit = &tfc->tfc_##_name##_cit; \
+ \
+ cit->ct_item_ops = _item_ops; \
+ cit->ct_group_ops = _group_ops; \
+ cit->ct_attrs = _attrs; \
+ cit->ct_owner = tf->tf_module; \
+ printk("Setup generic %s\n", __stringify(_name)); \
+}
+
+/* Start of tfc_tpg_mappedlun_cit */
+
+static int target_fabric_mappedlun_link(
+ struct config_item *lun_acl_ci,
+ struct config_item *lun_ci)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
+ struct se_lun_acl, se_lun_group);
+ struct se_portal_group *se_tpg;
+ struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s;
+ int ret = 0, lun_access;
+ /*
+ * Ensure that the source port exists
+ */
+ if (!(lun->lun_sep) || !(lun->lun_sep->sep_tpg)) {
+ printk(KERN_ERR "Source se_lun->lun_sep or lun->lun_sep->sep"
+ "_tpg does not exist\n");
+ return -EINVAL;
+ }
+ se_tpg = lun->lun_sep->sep_tpg;
+
+ nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item;
+ tpg_ci = &nacl_ci->ci_group->cg_item;
+ wwn_ci = &tpg_ci->ci_group->cg_item;
+ tpg_ci_s = &lun_ci->ci_parent->ci_group->cg_item;
+ wwn_ci_s = &tpg_ci_s->ci_group->cg_item;
+ /*
+ * Make sure the SymLink is going to the same $FABRIC/$WWN/tpgt_$TPGT
+ */
+ if (strcmp(config_item_name(wwn_ci), config_item_name(wwn_ci_s))) {
+ printk(KERN_ERR "Illegal Initiator ACL SymLink outside of %s\n",
+ config_item_name(wwn_ci));
+ return -EINVAL;
+ }
+ if (strcmp(config_item_name(tpg_ci), config_item_name(tpg_ci_s))) {
+ printk(KERN_ERR "Illegal Initiator ACL Symlink outside of %s"
+ " TPGT: %s\n", config_item_name(wwn_ci),
+ config_item_name(tpg_ci));
+ return -EINVAL;
+ }
+ /*
+ * If this struct se_node_acl was dynamically generated with
+ * tpg_1/attrib/generate_node_acls=1, use the existing deve->lun_flags,
+ * which be will write protected (READ-ONLY) when
+ * tpg_1/attrib/demo_mode_write_protect=1
+ */
+ spin_lock_irq(&lacl->se_lun_nacl->device_list_lock);
+ deve = &lacl->se_lun_nacl->device_list[lacl->mapped_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)
+ lun_access = deve->lun_flags;
+ else
+ lun_access =
+ (TPG_TFO(se_tpg)->tpg_check_prod_mode_write_protect(
+ se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY :
+ TRANSPORT_LUNFLAGS_READ_WRITE;
+ spin_unlock_irq(&lacl->se_lun_nacl->device_list_lock);
+ /*
+ * Determine the actual mapped LUN value user wants..
+ *
+ * This value is what the SCSI Initiator actually sees the
+ * iscsi/$IQN/$TPGT/lun/lun_* as on their SCSI Initiator Ports.
+ */
+ ret = core_dev_add_initiator_node_lun_acl(se_tpg, lacl,
+ lun->unpacked_lun, lun_access);
+
+ return (ret < 0) ? -EINVAL : 0;
+}
+
+static int target_fabric_mappedlun_unlink(
+ struct config_item *lun_acl_ci,
+ struct config_item *lun_ci)
+{
+ struct se_lun *lun;
+ struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
+ struct se_lun_acl, se_lun_group);
+ struct se_node_acl *nacl = lacl->se_lun_nacl;
+ struct se_dev_entry *deve = &nacl->device_list[lacl->mapped_lun];
+ struct se_portal_group *se_tpg;
+ /*
+ * Determine if the underlying MappedLUN has already been released..
+ */
+ if (!(deve->se_lun))
+ return 0;
+
+ lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group);
+ se_tpg = lun->lun_sep->sep_tpg;
+
+ core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl);
+ return 0;
+}
+
+CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl);
+#define TCM_MAPPEDLUN_ATTR(_name, _mode) \
+static struct target_fabric_mappedlun_attribute target_fabric_mappedlun_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_fabric_mappedlun_show_##_name, \
+ target_fabric_mappedlun_store_##_name);
+
+static ssize_t target_fabric_mappedlun_show_write_protect(
+ struct se_lun_acl *lacl,
+ char *page)
+{
+ struct se_node_acl *se_nacl = lacl->se_lun_nacl;
+ struct se_dev_entry *deve;
+ ssize_t len;
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ deve = &se_nacl->device_list[lacl->mapped_lun];
+ len = sprintf(page, "%d\n",
+ (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ?
+ 1 : 0);
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ return len;
+}
+
+static ssize_t target_fabric_mappedlun_store_write_protect(
+ struct se_lun_acl *lacl,
+ const char *page,
+ size_t count)
+{
+ struct se_node_acl *se_nacl = lacl->se_lun_nacl;
+ struct se_portal_group *se_tpg = se_nacl->se_tpg;
+ unsigned long op;
+
+ if (strict_strtoul(page, 0, &op))
+ return -EINVAL;
+
+ if ((op != 1) && (op != 0))
+ return -EINVAL;
+
+ core_update_device_list_access(lacl->mapped_lun, (op) ?
+ TRANSPORT_LUNFLAGS_READ_ONLY :
+ TRANSPORT_LUNFLAGS_READ_WRITE,
+ lacl->se_lun_nacl);
+
+ printk(KERN_INFO "%s_ConfigFS: Changed Initiator ACL: %s"
+ " Mapped LUN: %u Write Protect bit to %s\n",
+ TPG_TFO(se_tpg)->get_fabric_name(),
+ lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF");
+
+ return count;
+
+}
+
+TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group);
+
+static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
+ &target_fabric_mappedlun_write_protect.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
+ .show_attribute = target_fabric_mappedlun_attr_show,
+ .store_attribute = target_fabric_mappedlun_attr_store,
+ .allow_link = target_fabric_mappedlun_link,
+ .drop_link = target_fabric_mappedlun_unlink,
+};
+
+TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL,
+ target_fabric_mappedlun_attrs);
+
+/* End of tfc_tpg_mappedlun_cit */
+
+/* Start of tfc_tpg_nacl_attrib_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group);
+
+static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = {
+ .show_attribute = target_fabric_nacl_attrib_attr_show,
+ .store_attribute = target_fabric_nacl_attrib_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_attrib_cit */
+
+/* Start of tfc_tpg_nacl_auth_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_auth, se_node_acl, acl_auth_group);
+
+static struct configfs_item_operations target_fabric_nacl_auth_item_ops = {
+ .show_attribute = target_fabric_nacl_auth_attr_show,
+ .store_attribute = target_fabric_nacl_auth_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_auth_cit */
+
+/* Start of tfc_tpg_nacl_param_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_param, se_node_acl, acl_param_group);
+
+static struct configfs_item_operations target_fabric_nacl_param_item_ops = {
+ .show_attribute = target_fabric_nacl_param_attr_show,
+ .store_attribute = target_fabric_nacl_param_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_param_cit */
+
+/* Start of tfc_tpg_nacl_base_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_base, se_node_acl, acl_group);
+
+static struct config_group *target_fabric_make_mappedlun(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl = container_of(group,
+ struct se_node_acl, acl_group);
+ struct se_portal_group *se_tpg = se_nacl->se_tpg;
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_lun_acl *lacl;
+ struct config_item *acl_ci;
+ char *buf;
+ unsigned long mapped_lun;
+ int ret = 0;
+
+ acl_ci = &group->cg_item;
+ if (!(acl_ci)) {
+ printk(KERN_ERR "Unable to locatel acl_ci\n");
+ return NULL;
+ }
+
+ buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for name buf\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ snprintf(buf, strlen(name) + 1, "%s", name);
+ /*
+ * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID.
+ */
+ if (strstr(buf, "lun_") != buf) {
+ printk(KERN_ERR "Unable to locate \"lun_\" from buf: %s"
+ " name: %s\n", buf, name);
+ ret = -EINVAL;
+ goto out;
+ }
+ /*
+ * Determine the Mapped LUN value. This is what the SCSI Initiator
+ * Port will actually see.
+ */
+ if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun,
+ config_item_name(acl_ci), &ret);
+ if (!(lacl))
+ goto out;
+
+ config_group_init_type_name(&lacl->se_lun_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit);
+
+ kfree(buf);
+ return &lacl->se_lun_group;
+out:
+ kfree(buf);
+ return ERR_PTR(ret);
+}
+
+static void target_fabric_drop_mappedlun(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_lun_acl *lacl = container_of(to_config_group(item),
+ struct se_lun_acl, se_lun_group);
+ struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
+
+ config_item_put(item);
+ core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
+static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
+ .show_attribute = target_fabric_nacl_base_attr_show,
+ .store_attribute = target_fabric_nacl_base_attr_store,
+};
+
+static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
+ .make_group = target_fabric_make_mappedlun,
+ .drop_item = target_fabric_drop_mappedlun,
+};
+
+TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
+ &target_fabric_nacl_base_group_ops, NULL);
+
+/* End of tfc_tpg_nacl_base_cit */
+
+/* Start of tfc_tpg_nacl_cit */
+
+static struct config_group *target_fabric_make_nodeacl(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_acl_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_node_acl *se_nacl;
+ struct config_group *nacl_cg;
+
+ if (!(tf->tf_ops.fabric_make_nodeacl)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_nodeacl is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name);
+ if (IS_ERR(se_nacl))
+ return ERR_PTR(PTR_ERR(se_nacl));
+
+ nacl_cg = &se_nacl->acl_group;
+ nacl_cg->default_groups = se_nacl->acl_default_groups;
+ nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
+ nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
+ nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
+ nacl_cg->default_groups[3] = NULL;
+
+ config_group_init_type_name(&se_nacl->acl_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit);
+ config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_attrib_cit);
+ config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit);
+ config_group_init_type_name(&se_nacl->acl_param_group, "param",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit);
+
+ return &se_nacl->acl_group;
+}
+
+static void target_fabric_drop_nodeacl(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_acl_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_node_acl *se_nacl = container_of(to_config_group(item),
+ struct se_node_acl, acl_group);
+ struct config_item *df_item;
+ struct config_group *nacl_cg;
+ int i;
+
+ nacl_cg = &se_nacl->acl_group;
+ for (i = 0; nacl_cg->default_groups[i]; i++) {
+ df_item = &nacl_cg->default_groups[i]->cg_item;
+ nacl_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_nodeacl(se_nacl);
+}
+
+static struct configfs_group_operations target_fabric_nacl_group_ops = {
+ .make_group = target_fabric_make_nodeacl,
+ .drop_item = target_fabric_drop_nodeacl,
+};
+
+TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL);
+
+/* End of tfc_tpg_nacl_cit */
+
+/* Start of tfc_tpg_np_base_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group);
+
+static struct configfs_item_operations target_fabric_np_base_item_ops = {
+ .show_attribute = target_fabric_np_base_attr_show,
+ .store_attribute = target_fabric_np_base_attr_store,
+};
+
+TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_np_base_cit */
+
+/* Start of tfc_tpg_np_cit */
+
+static struct config_group *target_fabric_make_np(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_np_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_tpg_np *se_tpg_np;
+
+ if (!(tf->tf_ops.fabric_make_np)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_np is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name);
+ if (!(se_tpg_np) || IS_ERR(se_tpg_np))
+ return ERR_PTR(-EINVAL);
+
+ config_group_init_type_name(&se_tpg_np->tpg_np_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit);
+
+ return &se_tpg_np->tpg_np_group;
+}
+
+static void target_fabric_drop_np(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_np_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
+ struct se_tpg_np, tpg_np_group);
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_np(se_tpg_np);
+}
+
+static struct configfs_group_operations target_fabric_np_group_ops = {
+ .make_group = &target_fabric_make_np,
+ .drop_item = &target_fabric_drop_np,
+};
+
+TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL);
+
+/* End of tfc_tpg_np_cit */
+
+/* Start of tfc_tpg_port_cit */
+
+CONFIGFS_EATTR_STRUCT(target_fabric_port, se_lun);
+#define TCM_PORT_ATTR(_name, _mode) \
+static struct target_fabric_port_attribute target_fabric_port_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_fabric_port_show_attr_##_name, \
+ target_fabric_port_store_attr_##_name);
+
+#define TCM_PORT_ATTOR_RO(_name) \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_fabric_port_show_attr_##_name);
+
+/*
+ * alua_tg_pt_gp
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_tg_pt_gp_info(lun->lun_sep, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_tg_pt_gp_info(lun->lun_sep, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_offline
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_offline_bit(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_offline_bit(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_offline, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_status
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_status(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_secondary_status(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_status(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_secondary_status(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_status, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_write_md
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_secondary_write_metadata(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_secondary_write_metadata(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_write_md, S_IRUGO | S_IWUSR);
+
+
+static struct configfs_attribute *target_fabric_port_attrs[] = {
+ &target_fabric_port_alua_tg_pt_gp.attr,
+ &target_fabric_port_alua_tg_pt_offline.attr,
+ &target_fabric_port_alua_tg_pt_status.attr,
+ &target_fabric_port_alua_tg_pt_write_md.attr,
+ NULL,
+};
+
+CONFIGFS_EATTR_OPS(target_fabric_port, se_lun, lun_group);
+
+static int target_fabric_port_link(
+ struct config_item *lun_ci,
+ struct config_item *se_dev_ci)
+{
+ struct config_item *tpg_ci;
+ struct se_device *dev;
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_lun *lun_p;
+ struct se_portal_group *se_tpg;
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(se_dev_ci), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_fabric_configfs *tf;
+ int ret;
+
+ tpg_ci = &lun_ci->ci_parent->ci_group->cg_item;
+ se_tpg = container_of(to_config_group(tpg_ci),
+ struct se_portal_group, tpg_group);
+ tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+ if (lun->lun_se_dev != NULL) {
+ printk(KERN_ERR "Port Symlink already exists\n");
+ return -EEXIST;
+ }
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev)) {
+ printk(KERN_ERR "Unable to locate struct se_device pointer from"
+ " %s\n", config_item_name(se_dev_ci));
+ ret = -ENODEV;
+ goto out;
+ }
+
+ lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev,
+ lun->unpacked_lun);
+ if ((IS_ERR(lun_p)) || !(lun_p)) {
+ printk(KERN_ERR "core_dev_add_lun() failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (tf->tf_ops.fabric_post_link) {
+ /*
+ * Call the optional fabric_post_link() to allow a
+ * fabric module to setup any additional state once
+ * core_dev_add_lun() has been called..
+ */
+ tf->tf_ops.fabric_post_link(se_tpg, lun);
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static int target_fabric_port_unlink(
+ struct config_item *lun_ci,
+ struct config_item *se_dev_ci)
+{
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg;
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+ if (tf->tf_ops.fabric_pre_unlink) {
+ /*
+ * Call the optional fabric_pre_unlink() to allow a
+ * fabric module to release any additional stat before
+ * core_dev_del_lun() is called.
+ */
+ tf->tf_ops.fabric_pre_unlink(se_tpg, lun);
+ }
+
+ core_dev_del_lun(se_tpg, lun->unpacked_lun);
+ return 0;
+}
+
+static struct configfs_item_operations target_fabric_port_item_ops = {
+ .show_attribute = target_fabric_port_attr_show,
+ .store_attribute = target_fabric_port_attr_store,
+ .allow_link = target_fabric_port_link,
+ .drop_link = target_fabric_port_unlink,
+};
+
+TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_attrs);
+
+/* End of tfc_tpg_port_cit */
+
+/* Start of tfc_tpg_lun_cit */
+
+static struct config_group *target_fabric_make_lun(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_lun *lun;
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_lun_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ unsigned long unpacked_lun;
+
+ if (strstr(name, "lun_") != name) {
+ printk(KERN_ERR "Unable to locate \'_\" in"
+ " \"lun_$LUN_NUMBER\"\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ lun = core_get_lun_from_tpg(se_tpg, unpacked_lun);
+ if (!(lun))
+ return ERR_PTR(-EINVAL);
+
+ config_group_init_type_name(&lun->lun_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_port_cit);
+
+ return &lun->lun_group;
+}
+
+static void target_fabric_drop_lun(
+ struct config_group *group,
+ struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations target_fabric_lun_group_ops = {
+ .make_group = &target_fabric_make_lun,
+ .drop_item = &target_fabric_drop_lun,
+};
+
+TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL);
+
+/* End of tfc_tpg_lun_cit */
+
+/* Start of tfc_tpg_attrib_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_attrib, se_portal_group, tpg_attrib_group);
+
+static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = {
+ .show_attribute = target_fabric_tpg_attrib_attr_show,
+ .store_attribute = target_fabric_tpg_attrib_attr_store,
+};
+
+TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_attrib_cit */
+
+/* Start of tfc_tpg_param_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group);
+
+static struct configfs_item_operations target_fabric_tpg_param_item_ops = {
+ .show_attribute = target_fabric_tpg_param_attr_show,
+ .store_attribute = target_fabric_tpg_param_attr_store,
+};
+
+TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_param_cit */
+
+/* Start of tfc_tpg_base_cit */
+/*
+ * For use with TF_TPG_ATTR() and TF_TPG_ATTR_RO()
+ */
+CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group);
+
+static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
+ .show_attribute = target_fabric_tpg_attr_show,
+ .store_attribute = target_fabric_tpg_attr_store,
+};
+
+TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_base_cit */
+
+/* Start of tfc_tpg_cit */
+
+static struct config_group *target_fabric_make_tpg(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
+ struct target_fabric_configfs *tf = wwn->wwn_tf;
+ struct se_portal_group *se_tpg;
+
+ if (!(tf->tf_ops.fabric_make_tpg)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_tpg is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name);
+ if (!(se_tpg) || IS_ERR(se_tpg))
+ return ERR_PTR(-EINVAL);
+ /*
+ * Setup default groups from pre-allocated se_tpg->tpg_default_groups
+ */
+ se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
+ se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
+ se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
+ se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
+ se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
+ se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_param_group;
+ se_tpg->tpg_group.default_groups[5] = NULL;
+
+ config_group_init_type_name(&se_tpg->tpg_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_base_cit);
+ config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
+ &TF_CIT_TMPL(tf)->tfc_tpg_lun_cit);
+ config_group_init_type_name(&se_tpg->tpg_np_group, "np",
+ &TF_CIT_TMPL(tf)->tfc_tpg_np_cit);
+ config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit);
+ config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
+ &TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit);
+ config_group_init_type_name(&se_tpg->tpg_param_group, "param",
+ &TF_CIT_TMPL(tf)->tfc_tpg_param_cit);
+
+ return &se_tpg->tpg_group;
+}
+
+static void target_fabric_drop_tpg(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
+ struct target_fabric_configfs *tf = wwn->wwn_tf;
+ struct se_portal_group *se_tpg = container_of(to_config_group(item),
+ struct se_portal_group, tpg_group);
+ struct config_group *tpg_cg = &se_tpg->tpg_group;
+ struct config_item *df_item;
+ int i;
+ /*
+ * Release default groups, but do not release tpg_cg->default_groups
+ * memory as it is statically allocated at se_tpg->tpg_default_groups.
+ */
+ for (i = 0; tpg_cg->default_groups[i]; i++) {
+ df_item = &tpg_cg->default_groups[i]->cg_item;
+ tpg_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_tpg(se_tpg);
+}
+
+static struct configfs_group_operations target_fabric_tpg_group_ops = {
+ .make_group = target_fabric_make_tpg,
+ .drop_item = target_fabric_drop_tpg,
+};
+
+TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL);
+
+/* End of tfc_tpg_cit */
+
+/* Start of tfc_wwn_cit */
+
+static struct config_group *target_fabric_make_wwn(
+ struct config_group *group,
+ const char *name)
+{
+ struct target_fabric_configfs *tf = container_of(group,
+ struct target_fabric_configfs, tf_group);
+ struct se_wwn *wwn;
+
+ if (!(tf->tf_ops.fabric_make_wwn)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_wwn is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ wwn = tf->tf_ops.fabric_make_wwn(tf, group, name);
+ if (!(wwn) || IS_ERR(wwn))
+ return ERR_PTR(-EINVAL);
+
+ wwn->wwn_tf = tf;
+ config_group_init_type_name(&wwn->wwn_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_cit);
+
+ return &wwn->wwn_group;
+}
+
+static void target_fabric_drop_wwn(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct target_fabric_configfs *tf = container_of(group,
+ struct target_fabric_configfs, tf_group);
+ struct se_wwn *wwn = container_of(to_config_group(item),
+ struct se_wwn, wwn_group);
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_wwn(wwn);
+}
+
+static struct configfs_group_operations target_fabric_wwn_group_ops = {
+ .make_group = target_fabric_make_wwn,
+ .drop_item = target_fabric_drop_wwn,
+};
+/*
+ * For use with TF_WWN_ATTR() and TF_WWN_ATTR_RO()
+ */
+CONFIGFS_EATTR_OPS(target_fabric_wwn, target_fabric_configfs, tf_group);
+
+static struct configfs_item_operations target_fabric_wwn_item_ops = {
+ .show_attribute = target_fabric_wwn_attr_show,
+ .store_attribute = target_fabric_wwn_attr_store,
+};
+
+TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL);
+
+/* End of tfc_wwn_cit */
+
+/* Start of tfc_discovery_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_discovery, target_fabric_configfs,
+ tf_disc_group);
+
+static struct configfs_item_operations target_fabric_discovery_item_ops = {
+ .show_attribute = target_fabric_discovery_attr_show,
+ .store_attribute = target_fabric_discovery_attr_store,
+};
+
+TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL);
+
+/* End of tfc_discovery_cit */
+
+int target_fabric_setup_cits(struct target_fabric_configfs *tf)
+{
+ target_fabric_setup_discovery_cit(tf);
+ target_fabric_setup_wwn_cit(tf);
+ target_fabric_setup_tpg_cit(tf);
+ target_fabric_setup_tpg_base_cit(tf);
+ target_fabric_setup_tpg_port_cit(tf);
+ target_fabric_setup_tpg_lun_cit(tf);
+ target_fabric_setup_tpg_np_cit(tf);
+ target_fabric_setup_tpg_np_base_cit(tf);
+ target_fabric_setup_tpg_attrib_cit(tf);
+ target_fabric_setup_tpg_param_cit(tf);
+ target_fabric_setup_tpg_nacl_cit(tf);
+ target_fabric_setup_tpg_nacl_base_cit(tf);
+ target_fabric_setup_tpg_nacl_attrib_cit(tf);
+ target_fabric_setup_tpg_nacl_auth_cit(tf);
+ target_fabric_setup_tpg_nacl_param_cit(tf);
+ target_fabric_setup_tpg_mappedlun_cit(tf);
+
+ return 0;
+}
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
new file mode 100644
index 000000000000..26285644e4de
--- /dev/null
+++ b/drivers/target/target_core_fabric_lib.c
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Filename: target_core_fabric_lib.c
+ *
+ * This file contains generic high level protocol identifier and PR
+ * handlers for TCM fabric modules
+ *
+ * Copyright (c) 2010 Rising Tide Systems, Inc.
+ * Copyright (c) 2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+
+/*
+ * Handlers for Serial Attached SCSI (SAS)
+ */
+u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * Return a SAS Serial SCSI Protocol identifier for loopback operations
+ * This is defined in section 7.5.1 Table 362 in spc4r17
+ */
+ return 0x6;
+}
+EXPORT_SYMBOL(sas_get_fabric_proto_ident);
+
+u32 sas_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ unsigned char binary, *ptr;
+ int i;
+ u32 off = 4;
+ /*
+ * Set PROTOCOL IDENTIFIER to 6h for SAS
+ */
+ buf[0] = 0x06;
+ /*
+ * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
+ * over SAS Serial SCSI Protocol
+ */
+ ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */
+
+ for (i = 0; i < 16; i += 2) {
+ binary = transport_asciihex_to_binaryhex(&ptr[i]);
+ buf[off++] = binary;
+ }
+ /*
+ * The SAS Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(sas_get_pr_transport_id);
+
+u32 sas_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
+ * over SAS Serial SCSI Protocol
+ *
+ * The SAS Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(sas_get_pr_transport_id_len);
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+char *sas_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID
+ * for initiator ports using SCSI over SAS Serial SCSI Protocol
+ *
+ * The TransportID for a SAS Initiator Port is of fixed size of
+ * 24 bytes, and SAS does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[4];
+}
+EXPORT_SYMBOL(sas_parse_pr_out_transport_id);
+
+/*
+ * Handlers for Fibre Channel Protocol (FCP)
+ */
+u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */
+}
+EXPORT_SYMBOL(fc_get_fabric_proto_ident);
+
+u32 fc_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * The FC Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(fc_get_pr_transport_id_len);
+
+u32 fc_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ unsigned char binary, *ptr;
+ int i;
+ u32 off = 8;
+ /*
+ * PROTOCOL IDENTIFIER is 0h for FCP-2
+ *
+ * From spc4r17, 7.5.4.2 TransportID for initiator ports using
+ * SCSI over Fibre Channel
+ *
+ * We convert the ASCII formatted N Port name into a binary
+ * encoded TransportID.
+ */
+ ptr = &se_nacl->initiatorname[0];
+
+ for (i = 0; i < 24; ) {
+ if (!(strncmp(&ptr[i], ":", 1))) {
+ i++;
+ continue;
+ }
+ binary = transport_asciihex_to_binaryhex(&ptr[i]);
+ buf[off++] = binary;
+ i += 2;
+ }
+ /*
+ * The FC Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(fc_get_pr_transport_id);
+
+char *fc_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * The TransportID for a FC N Port is of fixed size of
+ * 24 bytes, and FC does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[8];
+}
+EXPORT_SYMBOL(fc_parse_pr_out_transport_id);
+
+/*
+ * Handlers for Internet Small Computer Systems Interface (iSCSI)
+ */
+
+u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * This value is defined for "Internet SCSI (iSCSI)"
+ * in spc4r17 section 7.5.1 Table 362
+ */
+ return 0x5;
+}
+EXPORT_SYMBOL(iscsi_get_fabric_proto_ident);
+
+u32 iscsi_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ u32 off = 4, padding = 0;
+ u16 len = 0;
+
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * Set PROTOCOL IDENTIFIER to 5h for iSCSI
+ */
+ buf[0] = 0x05;
+ /*
+ * From spc4r17 Section 7.5.4.6: TransportID for initiator
+ * ports using SCSI over iSCSI.
+ *
+ * The null-terminated, null-padded (see 4.4.2) ISCSI NAME field
+ * shall contain the iSCSI name of an iSCSI initiator node (see
+ * RFC 3720). The first ISCSI NAME field byte containing an ASCII
+ * null character terminates the ISCSI NAME field without regard for
+ * the specified length of the iSCSI TransportID or the contents of
+ * the ADDITIONAL LENGTH field.
+ */
+ len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
+ /*
+ * Add Extra byte for NULL terminator
+ */
+ len++;
+ /*
+ * If there is ISID present with the registration and *format code == 1
+ * 1, use iSCSI Initiator port TransportID format.
+ *
+ * Otherwise use iSCSI Initiator device TransportID format that
+ * does not contain the ASCII encoded iSCSI Initiator iSID value
+ * provied by the iSCSi Initiator during the iSCSI login process.
+ */
+ if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
+ /*
+ * Set FORMAT CODE 01b for iSCSI Initiator port TransportID
+ * format.
+ */
+ buf[0] |= 0x40;
+ /*
+ * From spc4r17 Section 7.5.4.6: TransportID for initiator
+ * ports using SCSI over iSCSI. Table 390
+ *
+ * The SEPARATOR field shall contain the five ASCII
+ * characters ",i,0x".
+ *
+ * The null-terminated, null-padded ISCSI INITIATOR SESSION ID
+ * field shall contain the iSCSI initiator session identifier
+ * (see RFC 3720) in the form of ASCII characters that are the
+ * hexadecimal digits converted from the binary iSCSI initiator
+ * session identifier value. The first ISCSI INITIATOR SESSION
+ * ID field byte containing an ASCII null character
+ */
+ buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
+ buf[off+len] = 0x69; off++; /* ASCII Character: "i" */
+ buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
+ buf[off+len] = 0x30; off++; /* ASCII Character: "0" */
+ buf[off+len] = 0x78; off++; /* ASCII Character: "x" */
+ len += 5;
+ buf[off+len] = pr_reg->pr_reg_isid[0]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[1]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[2]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[3]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[4]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[5]; off++;
+ buf[off+len] = '\0'; off++;
+ len += 7;
+ }
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The ADDITIONAL LENGTH field specifies the number of bytes that follow
+ * in the TransportID. The additional length shall be at least 20 and
+ * shall be a multiple of four.
+ */
+ padding = ((-len) & 3);
+ if (padding != 0)
+ len += padding;
+
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff);
+ /*
+ * Increment value for total payload + header length for
+ * full status descriptor
+ */
+ len += 4;
+
+ return len;
+}
+EXPORT_SYMBOL(iscsi_get_pr_transport_id);
+
+u32 iscsi_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ u32 len = 0, padding = 0;
+
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ len = strlen(se_nacl->initiatorname);
+ /*
+ * Add extra byte for NULL terminator
+ */
+ len++;
+ /*
+ * If there is ISID present with the registration, use format code:
+ * 01b: iSCSI Initiator port TransportID format
+ *
+ * If there is not an active iSCSI session, use format code:
+ * 00b: iSCSI Initiator device TransportID format
+ */
+ if (pr_reg->isid_present_at_reg) {
+ len += 5; /* For ",i,0x" ASCII seperator */
+ len += 7; /* For iSCSI Initiator Session ID + Null terminator */
+ *format_code = 1;
+ } else
+ *format_code = 0;
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The ADDITIONAL LENGTH field specifies the number of bytes that follow
+ * in the TransportID. The additional length shall be at least 20 and
+ * shall be a multiple of four.
+ */
+ padding = ((-len) & 3);
+ if (padding != 0)
+ len += padding;
+ /*
+ * Increment value for total payload + header length for
+ * full status descriptor
+ */
+ len += 4;
+
+ return len;
+}
+EXPORT_SYMBOL(iscsi_get_pr_transport_id_len);
+
+char *iscsi_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ char *p;
+ u32 tid_len, padding;
+ int i;
+ u16 add_len;
+ u8 format_code = (buf[0] & 0xc0);
+ /*
+ * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6:
+ *
+ * TransportID for initiator ports using SCSI over iSCSI,
+ * from Table 388 -- iSCSI TransportID formats.
+ *
+ * 00b Initiator port is identified using the world wide unique
+ * SCSI device name of the iSCSI initiator
+ * device containing the initiator port (see table 389).
+ * 01b Initiator port is identified using the world wide unique
+ * initiator port identifier (see table 390).10b to 11b
+ * Reserved
+ */
+ if ((format_code != 0x00) && (format_code != 0x40)) {
+ printk(KERN_ERR "Illegal format code: 0x%02x for iSCSI"
+ " Initiator Transport ID\n", format_code);
+ return NULL;
+ }
+ /*
+ * If the caller wants the TransportID Length, we set that value for the
+ * entire iSCSI Tarnsport ID now.
+ */
+ if (out_tid_len != NULL) {
+ add_len = ((buf[2] >> 8) & 0xff);
+ add_len |= (buf[3] & 0xff);
+
+ tid_len = strlen((char *)&buf[4]);
+ tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
+ tid_len += 1; /* Add one byte for NULL terminator */
+ padding = ((-tid_len) & 3);
+ if (padding != 0)
+ tid_len += padding;
+
+ if ((add_len + 4) != tid_len) {
+ printk(KERN_INFO "LIO-Target Extracted add_len: %hu "
+ "does not match calculated tid_len: %u,"
+ " using tid_len instead\n", add_len+4, tid_len);
+ *out_tid_len = tid_len;
+ } else
+ *out_tid_len = (add_len + 4);
+ }
+ /*
+ * Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator
+ * Session ID as defined in Table 390 - iSCSI initiator port TransportID
+ * format.
+ */
+ if (format_code == 0x40) {
+ p = strstr((char *)&buf[4], ",i,0x");
+ if (!(p)) {
+ printk(KERN_ERR "Unable to locate \",i,0x\" seperator"
+ " for Initiator port identifier: %s\n",
+ (char *)&buf[4]);
+ return NULL;
+ }
+ *p = '\0'; /* Terminate iSCSI Name */
+ p += 5; /* Skip over ",i,0x" seperator */
+
+ *port_nexus_ptr = p;
+ /*
+ * Go ahead and do the lower case conversion of the received
+ * 12 ASCII characters representing the ISID in the TransportID
+ * for comparision against the running iSCSI session's ISID from
+ * iscsi_target.c:lio_sess_get_initiator_sid()
+ */
+ for (i = 0; i < 12; i++) {
+ if (isdigit(*p)) {
+ p++;
+ continue;
+ }
+ *p = tolower(*p);
+ p++;
+ }
+ }
+
+ return (char *)&buf[4];
+}
+EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
new file mode 100644
index 000000000000..0aaca885668f
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,688 @@
+/*******************************************************************************
+ * Filename: target_core_file.c
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific functions
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_file.h"
+
+#if 1
+#define DEBUG_FD_CACHE(x...) printk(x)
+#else
+#define DEBUG_FD_CACHE(x...)
+#endif
+
+#if 1
+#define DEBUG_FD_FUA(x...) printk(x)
+#else
+#define DEBUG_FD_FUA(x...)
+#endif
+
+static struct se_subsystem_api fileio_template;
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int fd_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct fd_host *fd_host;
+
+ fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for struct fd_host\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"
+ " Target Core Stack %s\n", hba->hba_id, FD_VERSION,
+ TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+static void fd_detach_hba(struct se_hba *hba)
+{
+ struct fd_host *fd_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+}
+
+static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct fd_dev *fd_dev;
+ struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for struct fd_dev\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static struct se_device *fd_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct queue_limits *limits;
+ struct fd_dev *fd_dev = (struct fd_dev *) p;
+ struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct file *file;
+ struct inode *inode = NULL;
+ int dev_flags = 0, flags;
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ dev_p = getname(fd_dev->fd_dev_name);
+ set_fs(old_fs);
+
+ if (IS_ERR(dev_p)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ goto fail;
+ }
+#if 0
+ if (di->no_create_file)
+ flags = O_RDWR | O_LARGEFILE;
+ else
+ flags = O_RDWR | O_CREAT | O_LARGEFILE;
+#else
+ flags = O_RDWR | O_CREAT | O_LARGEFILE;
+#endif
+/* flags |= O_DIRECT; */
+ /*
+ * If fd_buffered_io=1 has not been set explictly (the default),
+ * use O_SYNC to force FILEIO writes to disk.
+ */
+ if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO))
+ flags |= O_SYNC;
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If using a block backend with this struct file, we extract
+ * fd_dev->fd_[block,dev]_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = file->f_mapping->host;
+ if (S_ISBLK(inode->i_mode)) {
+ struct request_queue *q;
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = bdev_get_queue(inode->i_bdev);
+ limits = &dev_limits.limits;
+ limits->logical_block_size = bdev_logical_block_size(inode->i_bdev);
+ limits->max_hw_sectors = queue_max_hw_sectors(q);
+ limits->max_sectors = queue_max_sectors(q);
+ /*
+ * Determine the number of bytes from i_size_read() minus
+ * one (1) logical sector from underlying struct block_device
+ */
+ fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
+ fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) -
+ fd_dev->fd_block_size);
+
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct"
+ " block_device blocks: %llu logical_block_size: %d\n",
+ fd_dev->fd_dev_size,
+ div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size),
+ fd_dev->fd_block_size);
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+
+ limits = &dev_limits.limits;
+ limits->logical_block_size = FD_BLOCKSIZE;
+ limits->max_hw_sectors = FD_MAX_SECTORS;
+ limits->max_sectors = FD_MAX_SECTORS;
+ fd_dev->fd_block_size = FD_BLOCKSIZE;
+ }
+
+ dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH;
+
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev,
+ &dev_limits, "FILEIO", FD_VERSION);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ putname(dev_p);
+ return NULL;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void fd_free_device(void *p)
+{
+ struct fd_dev *fd_dev = (struct fd_dev *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+static inline struct fd_request *FILE_REQ(struct se_task *task)
+{
+ return container_of(task, struct fd_request, fd_task);
+}
+
+
+static struct se_task *
+fd_alloc_task(struct se_cmd *cmd)
+{
+ struct fd_request *fd_req;
+
+ fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate struct fd_request\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = SE_DEV(cmd)->dev_ptr;
+
+ return &fd_req->fd_task;
+}
+
+static int fd_do_readv(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ mm_segment_t old_fs;
+ loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size);
+ int ret = 0, i;
+
+ iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL);
+ if (!(iov)) {
+ printk(KERN_ERR "Unable to allocate fd_do_readv iov[]\n");
+ return -1;
+ }
+
+ for (i = 0; i < task->task_sg_num; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], task->task_sg_num, &pos);
+ set_fs(old_fs);
+
+ kfree(iov);
+ /*
+ * Return zeros and GOOD status even if the READ did not return
+ * the expected virt_size for struct file w/o a backing struct
+ * block_device.
+ */
+ if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) {
+ if (ret < 0 || ret != task->task_size) {
+ printk(KERN_ERR "vfs_readv() returned %d,"
+ " expecting %d for S_ISBLK\n", ret,
+ (int)task->task_size);
+ return -1;
+ }
+ } else {
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d for non"
+ " S_ISBLK\n", ret);
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+static int fd_do_writev(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ mm_segment_t old_fs;
+ loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size);
+ int ret, i = 0;
+
+ iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL);
+ if (!(iov)) {
+ printk(KERN_ERR "Unable to allocate fd_do_writev iov[]\n");
+ return -1;
+ }
+
+ for (i = 0; i < task->task_sg_num; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], task->task_sg_num, &pos);
+ set_fs(old_fs);
+
+ kfree(iov);
+
+ if (ret < 0 || ret != task->task_size) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+static void fd_emulate_sync_cache(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = cmd->se_dev;
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ int immed = (cmd->t_task->t_task_cdb[1] & 0x2);
+ loff_t start, end;
+ int ret;
+
+ /*
+ * If the Immediate bit is set, queue up the GOOD response
+ * for this SYNCHRONIZE_CACHE op
+ */
+ if (immed)
+ transport_complete_sync_cache(cmd, 1);
+
+ /*
+ * Determine if we will be flushing the entire device.
+ */
+ if (cmd->t_task->t_task_lba == 0 && cmd->data_length == 0) {
+ start = 0;
+ end = LLONG_MAX;
+ } else {
+ start = cmd->t_task->t_task_lba * DEV_ATTRIB(dev)->block_size;
+ if (cmd->data_length)
+ end = start + cmd->data_length;
+ else
+ end = LLONG_MAX;
+ }
+
+ ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
+ if (ret != 0)
+ printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret);
+
+ if (!immed)
+ transport_complete_sync_cache(cmd, ret == 0);
+}
+
+/*
+ * Tell TCM Core that we are capable of WriteCache emulation for
+ * an underlying struct se_device.
+ */
+static int fd_emulated_write_cache(struct se_device *dev)
+{
+ return 1;
+}
+
+static int fd_emulated_dpo(struct se_device *dev)
+{
+ return 0;
+}
+/*
+ * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
+ * for TYPE_DISK.
+ */
+static int fd_emulated_fua_write(struct se_device *dev)
+{
+ return 1;
+}
+
+static int fd_emulated_fua_read(struct se_device *dev)
+{
+ return 0;
+}
+
+/*
+ * WRITE Force Unit Access (FUA) emulation on a per struct se_task
+ * LBA range basis..
+ */
+static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ loff_t start = task->task_lba * DEV_ATTRIB(dev)->block_size;
+ loff_t end = start + task->task_size;
+ int ret;
+
+ DEBUG_FD_CACHE("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
+ task->task_lba, task->task_size);
+
+ ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
+ if (ret != 0)
+ printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret);
+}
+
+static int fd_do_task(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = cmd->se_dev;
+ int ret = 0;
+
+ /*
+ * Call vectorized fileio functions to map struct scatterlist
+ * physical memory addresses to struct iovec virtual memory.
+ */
+ if (task->task_data_direction == DMA_FROM_DEVICE) {
+ ret = fd_do_readv(task);
+ } else {
+ ret = fd_do_writev(task);
+
+ if (ret > 0 &&
+ DEV_ATTRIB(dev)->emulate_write_cache > 0 &&
+ DEV_ATTRIB(dev)->emulate_fua_write > 0 &&
+ T_TASK(cmd)->t_tasks_fua) {
+ /*
+ * We might need to be a bit smarter here
+ * and return some sense data to let the initiator
+ * know the FUA WRITE cache sync failed..?
+ */
+ fd_emulate_write_fua(cmd, task);
+ }
+
+ }
+
+ if (ret < 0)
+ return ret;
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void fd_free_task(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+
+ kfree(req);
+}
+
+enum {
+ Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_fd_dev_name, "fd_dev_name=%s"},
+ {Opt_fd_dev_size, "fd_dev_size=%s"},
+ {Opt_fd_buffered_io, "fd_buffered_id=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t fd_set_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page, ssize_t count)
+{
+ struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *arg_p, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_fd_dev_name:
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", match_strdup(&args[0]));
+ printk(KERN_INFO "FILEIO: Referencing Path: %s\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ break;
+ case Opt_fd_dev_size:
+ arg_p = match_strdup(&args[0]);
+ ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " fd_dev_size=\n");
+ goto out;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %llu"
+ " bytes\n", fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ break;
+ case Opt_fd_buffered_io:
+ match_int(args, &arg);
+ if (arg != 1) {
+ printk(KERN_ERR "bogus fd_buffered_io=%d value\n", arg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ printk(KERN_INFO "FILEIO: Using buffered I/O"
+ " operations for struct fd_dev\n");
+
+ fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
+{
+ struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t fd_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
+ ssize_t bl = 0;
+
+ bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
+ bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size,
+ (fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
+ "Buffered" : "Synchronous");
+ return bl;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static unsigned char *fd_get_cdb(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static u32 fd_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static u32 fd_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t fd_get_blocks(struct se_device *dev)
+{
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
+ DEV_ATTRIB(dev)->block_size);
+
+ return blocks_long;
+}
+
+static struct se_subsystem_api fileio_template = {
+ .name = "fileio",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .free_device = fd_free_device,
+ .dpo_emulated = fd_emulated_dpo,
+ .fua_write_emulated = fd_emulated_fua_write,
+ .fua_read_emulated = fd_emulated_fua_read,
+ .write_cache_emulated = fd_emulated_write_cache,
+ .alloc_task = fd_alloc_task,
+ .do_task = fd_do_task,
+ .do_sync_cache = fd_emulate_sync_cache,
+ .free_task = fd_free_task,
+ .check_configfs_dev_params = fd_check_configfs_dev_params,
+ .set_configfs_dev_params = fd_set_configfs_dev_params,
+ .show_configfs_dev_params = fd_show_configfs_dev_params,
+ .get_cdb = fd_get_cdb,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_blocks = fd_get_blocks,
+};
+
+static int __init fileio_module_init(void)
+{
+ return transport_subsystem_register(&fileio_template);
+}
+
+static void fileio_module_exit(void)
+{
+ transport_subsystem_release(&fileio_template);
+}
+
+MODULE_DESCRIPTION("TCM FILEIO subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(fileio_module_init);
+module_exit(fileio_module_exit);
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
new file mode 100644
index 000000000000..ef4de2b4bd46
--- /dev/null
+++ b/drivers/target/target_core_file.h
@@ -0,0 +1,50 @@
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "4.0"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+struct fd_request {
+ struct se_task fd_task;
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ /* FILEIO device */
+ struct fd_dev *fd_dev;
+} ____cacheline_aligned;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+#define FDBD_USE_BUFFERED_IO 0x04
+
+struct fd_dev {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ u32 fd_block_size;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ /* FILEIO HBA device is connected to */
+ struct fd_host *fd_host;
+} ____cacheline_aligned;
+
+struct fd_host {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_FILE_H */
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
new file mode 100644
index 000000000000..4bbe8208b241
--- /dev/null
+++ b/drivers/target/target_core_hba.c
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Filename: target_core_hba.c
+ *
+ * This file copntains the iSCSI HBA Transport related functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_hba.h"
+
+static LIST_HEAD(subsystem_list);
+static DEFINE_MUTEX(subsystem_mutex);
+
+int transport_subsystem_register(struct se_subsystem_api *sub_api)
+{
+ struct se_subsystem_api *s;
+
+ INIT_LIST_HEAD(&sub_api->sub_api_list);
+
+ mutex_lock(&subsystem_mutex);
+ list_for_each_entry(s, &subsystem_list, sub_api_list) {
+ if (!(strcmp(s->name, sub_api->name))) {
+ printk(KERN_ERR "%p is already registered with"
+ " duplicate name %s, unable to process"
+ " request\n", s, s->name);
+ mutex_unlock(&subsystem_mutex);
+ return -EEXIST;
+ }
+ }
+ list_add_tail(&sub_api->sub_api_list, &subsystem_list);
+ mutex_unlock(&subsystem_mutex);
+
+ printk(KERN_INFO "TCM: Registered subsystem plugin: %s struct module:"
+ " %p\n", sub_api->name, sub_api->owner);
+ return 0;
+}
+EXPORT_SYMBOL(transport_subsystem_register);
+
+void transport_subsystem_release(struct se_subsystem_api *sub_api)
+{
+ mutex_lock(&subsystem_mutex);
+ list_del(&sub_api->sub_api_list);
+ mutex_unlock(&subsystem_mutex);
+}
+EXPORT_SYMBOL(transport_subsystem_release);
+
+static struct se_subsystem_api *core_get_backend(const char *sub_name)
+{
+ struct se_subsystem_api *s;
+
+ mutex_lock(&subsystem_mutex);
+ list_for_each_entry(s, &subsystem_list, sub_api_list) {
+ if (!strcmp(s->name, sub_name))
+ goto found;
+ }
+ mutex_unlock(&subsystem_mutex);
+ return NULL;
+found:
+ if (s->owner && !try_module_get(s->owner))
+ s = NULL;
+ mutex_unlock(&subsystem_mutex);
+ return s;
+}
+
+struct se_hba *
+core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags)
+{
+ struct se_hba *hba;
+ int ret = 0;
+
+ hba = kzalloc(sizeof(*hba), GFP_KERNEL);
+ if (!hba) {
+ printk(KERN_ERR "Unable to allocate struct se_hba\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ INIT_LIST_HEAD(&hba->hba_dev_list);
+ spin_lock_init(&hba->device_lock);
+ spin_lock_init(&hba->hba_queue_lock);
+ mutex_init(&hba->hba_access_mutex);
+
+ hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX);
+ hba->hba_flags |= hba_flags;
+
+ atomic_set(&hba->max_queue_depth, 0);
+ atomic_set(&hba->left_queue_depth, 0);
+
+ hba->transport = core_get_backend(plugin_name);
+ if (!hba->transport) {
+ ret = -EINVAL;
+ goto out_free_hba;
+ }
+
+ ret = hba->transport->attach_hba(hba, plugin_dep_id);
+ if (ret < 0)
+ goto out_module_put;
+
+ spin_lock(&se_global->hba_lock);
+ hba->hba_id = se_global->g_hba_id_counter++;
+ list_add_tail(&hba->hba_list, &se_global->g_hba_list);
+ spin_unlock(&se_global->hba_lock);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Attached HBA to Generic Target"
+ " Core\n", hba->hba_id);
+
+ return hba;
+
+out_module_put:
+ if (hba->transport->owner)
+ module_put(hba->transport->owner);
+ hba->transport = NULL;
+out_free_hba:
+ kfree(hba);
+ return ERR_PTR(ret);
+}
+
+int
+core_delete_hba(struct se_hba *hba)
+{
+ struct se_device *dev, *dev_tmp;
+
+ spin_lock(&hba->device_lock);
+ list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) {
+
+ se_clear_dev_ports(dev);
+ spin_unlock(&hba->device_lock);
+
+ se_release_device_for_hba(dev);
+
+ spin_lock(&hba->device_lock);
+ }
+ spin_unlock(&hba->device_lock);
+
+ hba->transport->detach_hba(hba);
+
+ spin_lock(&se_global->hba_lock);
+ list_del(&hba->hba_list);
+ spin_unlock(&se_global->hba_lock);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached HBA from Generic Target"
+ " Core\n", hba->hba_id);
+
+ if (hba->transport->owner)
+ module_put(hba->transport->owner);
+
+ hba->transport = NULL;
+ kfree(hba);
+ return 0;
+}
diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h
new file mode 100644
index 000000000000..bb0fea5f730c
--- /dev/null
+++ b/drivers/target/target_core_hba.h
@@ -0,0 +1,7 @@
+#ifndef TARGET_CORE_HBA_H
+#define TARGET_CORE_HBA_H
+
+extern struct se_hba *core_alloc_hba(const char *, u32, u32);
+extern int core_delete_hba(struct se_hba *);
+
+#endif /* TARGET_CORE_HBA_H */
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
new file mode 100644
index 000000000000..c6e0d757e76e
--- /dev/null
+++ b/drivers/target/target_core_iblock.c
@@ -0,0 +1,808 @@
+/*******************************************************************************
+ * Filename: target_core_iblock.c
+ *
+ * This file contains the Storage Engine <-> Linux BlockIO transport
+ * specific functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/bio.h>
+#include <linux/genhd.h>
+#include <linux/file.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_iblock.h"
+
+#if 0
+#define DEBUG_IBLOCK(x...) printk(x)
+#else
+#define DEBUG_IBLOCK(x...)
+#endif
+
+static struct se_subsystem_api iblock_template;
+
+static void iblock_bio_done(struct bio *, int);
+
+/* iblock_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int iblock_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct iblock_hba *ib_host;
+
+ ib_host = kzalloc(sizeof(struct iblock_hba), GFP_KERNEL);
+ if (!(ib_host)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct iblock_hba\n");
+ return -ENOMEM;
+ }
+
+ ib_host->iblock_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, IBLOCK_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, IBLOCK_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) ib_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM iBlock HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ IBLOCK_VERSION, TARGET_CORE_MOD_VERSION);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Attached iBlock HBA: %u to Generic"
+ " Target Core TCQ Depth: %d\n", hba->hba_id,
+ ib_host->iblock_host_id, atomic_read(&hba->max_queue_depth));
+
+ return 0;
+}
+
+static void iblock_detach_hba(struct se_hba *hba)
+{
+ struct iblock_hba *ib_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached iBlock HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, ib_host->iblock_host_id);
+
+ kfree(ib_host);
+ hba->hba_ptr = NULL;
+}
+
+static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct iblock_dev *ib_dev = NULL;
+ struct iblock_hba *ib_host = hba->hba_ptr;
+
+ ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL);
+ if (!(ib_dev)) {
+ printk(KERN_ERR "Unable to allocate struct iblock_dev\n");
+ return NULL;
+ }
+ ib_dev->ibd_host = ib_host;
+
+ printk(KERN_INFO "IBLOCK: Allocated ib_dev for %s\n", name);
+
+ return ib_dev;
+}
+
+static struct se_device *iblock_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ struct iblock_dev *ib_dev = p;
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct block_device *bd = NULL;
+ struct request_queue *q;
+ struct queue_limits *limits;
+ u32 dev_flags = 0;
+
+ if (!(ib_dev)) {
+ printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n");
+ return 0;
+ }
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+ /*
+ * These settings need to be made tunable..
+ */
+ ib_dev->ibd_bio_set = bioset_create(32, 64);
+ if (!(ib_dev->ibd_bio_set)) {
+ printk(KERN_ERR "IBLOCK: Unable to create bioset()\n");
+ return 0;
+ }
+ printk(KERN_INFO "IBLOCK: Created bio_set()\n");
+ /*
+ * iblock_check_configfs_dev_params() ensures that ib_dev->ibd_udev_path
+ * must already have been set in order for echo 1 > $HBA/$DEV/enable to run.
+ */
+ printk(KERN_INFO "IBLOCK: Claiming struct block_device: %s\n",
+ ib_dev->ibd_udev_path);
+
+ bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
+ if (!(bd))
+ goto failed;
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = bdev_get_queue(bd);
+ limits = &dev_limits.limits;
+ limits->logical_block_size = bdev_logical_block_size(bd);
+ limits->max_hw_sectors = queue_max_hw_sectors(q);
+ limits->max_sectors = queue_max_sectors(q);
+ dev_limits.hw_queue_depth = IBLOCK_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = IBLOCK_DEVICE_QUEUE_DEPTH;
+
+ ib_dev->ibd_major = MAJOR(bd->bd_dev);
+ ib_dev->ibd_minor = MINOR(bd->bd_dev);
+ ib_dev->ibd_bd = bd;
+
+ dev = transport_add_device_to_core_hba(hba,
+ &iblock_template, se_dev, dev_flags, (void *)ib_dev,
+ &dev_limits, "IBLOCK", IBLOCK_VERSION);
+ if (!(dev))
+ goto failed;
+
+ ib_dev->ibd_depth = dev->queue_depth;
+
+ /*
+ * Check if the underlying struct block_device request_queue supports
+ * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
+ * in ATA and we need to set TPE=1
+ */
+ if (blk_queue_discard(bdev_get_queue(bd))) {
+ struct request_queue *q = bdev_get_queue(bd);
+
+ DEV_ATTRIB(dev)->max_unmap_lba_count =
+ q->limits.max_discard_sectors;
+ /*
+ * Currently hardcoded to 1 in Linux/SCSI code..
+ */
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count = 1;
+ DEV_ATTRIB(dev)->unmap_granularity =
+ q->limits.discard_granularity;
+ DEV_ATTRIB(dev)->unmap_granularity_alignment =
+ q->limits.discard_alignment;
+
+ printk(KERN_INFO "IBLOCK: BLOCK Discard support available,"
+ " disabled by default\n");
+ }
+
+ return dev;
+
+failed:
+ if (ib_dev->ibd_bio_set) {
+ bioset_free(ib_dev->ibd_bio_set);
+ ib_dev->ibd_bio_set = NULL;
+ }
+ ib_dev->ibd_bd = NULL;
+ ib_dev->ibd_major = 0;
+ ib_dev->ibd_minor = 0;
+ return NULL;
+}
+
+static void iblock_free_device(void *p)
+{
+ struct iblock_dev *ib_dev = p;
+
+ blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ bioset_free(ib_dev->ibd_bio_set);
+ kfree(ib_dev);
+}
+
+static inline struct iblock_req *IBLOCK_REQ(struct se_task *task)
+{
+ return container_of(task, struct iblock_req, ib_task);
+}
+
+static struct se_task *
+iblock_alloc_task(struct se_cmd *cmd)
+{
+ struct iblock_req *ib_req;
+
+ ib_req = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+ if (!(ib_req)) {
+ printk(KERN_ERR "Unable to allocate memory for struct iblock_req\n");
+ return NULL;
+ }
+
+ ib_req->ib_dev = SE_DEV(cmd)->dev_ptr;
+ atomic_set(&ib_req->ib_bio_cnt, 0);
+ return &ib_req->ib_task;
+}
+
+static unsigned long long iblock_emulate_read_cap_with_block_size(
+ struct se_device *dev,
+ struct block_device *bd,
+ struct request_queue *q)
+{
+ unsigned long long blocks_long = (div_u64(i_size_read(bd->bd_inode),
+ bdev_logical_block_size(bd)) - 1);
+ u32 block_size = bdev_logical_block_size(bd);
+
+ if (block_size == DEV_ATTRIB(dev)->block_size)
+ return blocks_long;
+
+ switch (block_size) {
+ case 4096:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 2048:
+ blocks_long <<= 1;
+ break;
+ case 1024:
+ blocks_long <<= 2;
+ break;
+ case 512:
+ blocks_long <<= 3;
+ default:
+ break;
+ }
+ break;
+ case 2048:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 1;
+ break;
+ case 1024:
+ blocks_long <<= 1;
+ break;
+ case 512:
+ blocks_long <<= 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1024:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 2;
+ break;
+ case 2048:
+ blocks_long >>= 1;
+ break;
+ case 512:
+ blocks_long <<= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 512:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 3;
+ break;
+ case 2048:
+ blocks_long >>= 2;
+ break;
+ case 1024:
+ blocks_long >>= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return blocks_long;
+}
+
+/*
+ * Emulate SYCHRONIZE_CACHE_*
+ */
+static void iblock_emulate_sync_cache(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
+ int immed = (T_TASK(cmd)->t_task_cdb[1] & 0x2);
+ sector_t error_sector;
+ int ret;
+
+ /*
+ * If the Immediate bit is set, queue up the GOOD response
+ * for this SYNCHRONIZE_CACHE op
+ */
+ if (immed)
+ transport_complete_sync_cache(cmd, 1);
+
+ /*
+ * blkdev_issue_flush() does not support a specifying a range, so
+ * we have to flush the entire cache.
+ */
+ ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector);
+ if (ret != 0) {
+ printk(KERN_ERR "IBLOCK: block_issue_flush() failed: %d "
+ " error_sector: %llu\n", ret,
+ (unsigned long long)error_sector);
+ }
+
+ if (!immed)
+ transport_complete_sync_cache(cmd, ret == 0);
+}
+
+/*
+ * Tell TCM Core that we are capable of WriteCache emulation for
+ * an underlying struct se_device.
+ */
+static int iblock_emulated_write_cache(struct se_device *dev)
+{
+ return 1;
+}
+
+static int iblock_emulated_dpo(struct se_device *dev)
+{
+ return 0;
+}
+
+/*
+ * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
+ * for TYPE_DISK.
+ */
+static int iblock_emulated_fua_write(struct se_device *dev)
+{
+ return 1;
+}
+
+static int iblock_emulated_fua_read(struct se_device *dev)
+{
+ return 0;
+}
+
+static int iblock_do_task(struct se_task *task)
+{
+ struct se_device *dev = task->task_se_cmd->se_dev;
+ struct iblock_req *req = IBLOCK_REQ(task);
+ struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev;
+ struct request_queue *q = bdev_get_queue(ibd->ibd_bd);
+ struct bio *bio = req->ib_bio, *nbio = NULL;
+ int rw;
+
+ if (task->task_data_direction == DMA_TO_DEVICE) {
+ /*
+ * Force data to disk if we pretend to not have a volatile
+ * write cache, or the initiator set the Force Unit Access bit.
+ */
+ if (DEV_ATTRIB(dev)->emulate_write_cache == 0 ||
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0 &&
+ T_TASK(task->task_se_cmd)->t_tasks_fua))
+ rw = WRITE_FUA;
+ else
+ rw = WRITE;
+ } else {
+ rw = READ;
+ }
+
+ while (bio) {
+ nbio = bio->bi_next;
+ bio->bi_next = NULL;
+ DEBUG_IBLOCK("Calling submit_bio() task: %p bio: %p"
+ " bio->bi_sector: %llu\n", task, bio, bio->bi_sector);
+
+ submit_bio(rw, bio);
+ bio = nbio;
+ }
+
+ if (q->unplug_fn)
+ q->unplug_fn(q);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
+{
+ struct iblock_dev *ibd = dev->dev_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ int barrier = 0;
+
+ return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier);
+}
+
+static void iblock_free_task(struct se_task *task)
+{
+ struct iblock_req *req = IBLOCK_REQ(task);
+ struct bio *bio, *hbio = req->ib_bio;
+ /*
+ * We only release the bio(s) here if iblock_bio_done() has not called
+ * bio_put() -> iblock_bio_destructor().
+ */
+ while (hbio != NULL) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_put(bio);
+ }
+
+ kfree(req);
+}
+
+enum {
+ Opt_udev_path, Opt_force, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_udev_path, "udev_path=%s"},
+ {Opt_force, "force=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page, ssize_t count)
+{
+ struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_udev_path:
+ if (ib_dev->ibd_bd) {
+ printk(KERN_ERR "Unable to set udev_path= while"
+ " ib_dev->ibd_bd exists\n");
+ ret = -EEXIST;
+ goto out;
+ }
+
+ ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN,
+ "%s", match_strdup(&args[0]));
+ printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n",
+ ib_dev->ibd_udev_path);
+ ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
+ break;
+ case Opt_force:
+ match_int(args, &arg);
+ ib_dev->ibd_force = arg;
+ printk(KERN_INFO "IBLOCK: Set force=%d\n",
+ ib_dev->ibd_force);
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t iblock_check_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev)
+{
+ struct iblock_dev *ibd = se_dev->se_dev_su_ptr;
+
+ if (!(ibd->ibd_flags & IBDF_HAS_UDEV_PATH)) {
+ printk(KERN_ERR "Missing udev_path= parameters for IBLOCK\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t iblock_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct iblock_dev *ibd = se_dev->se_dev_su_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ char buf[BDEVNAME_SIZE];
+ ssize_t bl = 0;
+
+ if (bd)
+ bl += sprintf(b + bl, "iBlock device: %s",
+ bdevname(bd, buf));
+ if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) {
+ bl += sprintf(b + bl, " UDEV PATH: %s\n",
+ ibd->ibd_udev_path);
+ } else
+ bl += sprintf(b + bl, "\n");
+
+ bl += sprintf(b + bl, " ");
+ if (bd) {
+ bl += sprintf(b + bl, "Major: %d Minor: %d %s\n",
+ ibd->ibd_major, ibd->ibd_minor, (!bd->bd_contains) ?
+ "" : (bd->bd_holder == (struct iblock_dev *)ibd) ?
+ "CLAIMED: IBLOCK" : "CLAIMED: OS");
+ } else {
+ bl += sprintf(b + bl, "Major: %d Minor: %d\n",
+ ibd->ibd_major, ibd->ibd_minor);
+ }
+
+ return bl;
+}
+
+static void iblock_bio_destructor(struct bio *bio)
+{
+ struct se_task *task = bio->bi_private;
+ struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+
+ bio_free(bio, ib_dev->ibd_bio_set);
+}
+
+static struct bio *iblock_get_bio(
+ struct se_task *task,
+ struct iblock_req *ib_req,
+ struct iblock_dev *ib_dev,
+ int *ret,
+ sector_t lba,
+ u32 sg_num)
+{
+ struct bio *bio;
+
+ bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
+ if (!(bio)) {
+ printk(KERN_ERR "Unable to allocate memory for bio\n");
+ *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ return NULL;
+ }
+
+ DEBUG_IBLOCK("Allocated bio: %p task_sg_num: %u using ibd_bio_set:"
+ " %p\n", bio, task->task_sg_num, ib_dev->ibd_bio_set);
+ DEBUG_IBLOCK("Allocated bio: %p task_size: %u\n", bio, task->task_size);
+
+ bio->bi_bdev = ib_dev->ibd_bd;
+ bio->bi_private = (void *) task;
+ bio->bi_destructor = iblock_bio_destructor;
+ bio->bi_end_io = &iblock_bio_done;
+ bio->bi_sector = lba;
+ atomic_inc(&ib_req->ib_bio_cnt);
+
+ DEBUG_IBLOCK("Set bio->bi_sector: %llu\n", bio->bi_sector);
+ DEBUG_IBLOCK("Set ib_req->ib_bio_cnt: %d\n",
+ atomic_read(&ib_req->ib_bio_cnt));
+ return bio;
+}
+
+static int iblock_map_task_SG(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = SE_DEV(cmd);
+ struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+ struct iblock_req *ib_req = IBLOCK_REQ(task);
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct scatterlist *sg;
+ int ret = 0;
+ u32 i, sg_num = task->task_sg_num;
+ sector_t block_lba;
+ /*
+ * Do starting conversion up from non 512-byte blocksize with
+ * struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
+ */
+ if (DEV_ATTRIB(dev)->block_size == 4096)
+ block_lba = (task->task_lba << 3);
+ else if (DEV_ATTRIB(dev)->block_size == 2048)
+ block_lba = (task->task_lba << 2);
+ else if (DEV_ATTRIB(dev)->block_size == 1024)
+ block_lba = (task->task_lba << 1);
+ else if (DEV_ATTRIB(dev)->block_size == 512)
+ block_lba = task->task_lba;
+ else {
+ printk(KERN_ERR "Unsupported SCSI -> BLOCK LBA conversion:"
+ " %u\n", DEV_ATTRIB(dev)->block_size);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num);
+ if (!(bio))
+ return ret;
+
+ ib_req->ib_bio = bio;
+ hbio = tbio = bio;
+ /*
+ * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
+ * from TCM struct se_mem -> task->task_sg -> struct scatterlist memory.
+ */
+ for_each_sg(task->task_sg, sg, task->task_sg_num, i) {
+ DEBUG_IBLOCK("task: %p bio: %p Calling bio_add_page(): page:"
+ " %p len: %u offset: %u\n", task, bio, sg_page(sg),
+ sg->length, sg->offset);
+again:
+ ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset);
+ if (ret != sg->length) {
+
+ DEBUG_IBLOCK("*** Set bio->bi_sector: %llu\n",
+ bio->bi_sector);
+ DEBUG_IBLOCK("** task->task_size: %u\n",
+ task->task_size);
+ DEBUG_IBLOCK("*** bio->bi_max_vecs: %u\n",
+ bio->bi_max_vecs);
+ DEBUG_IBLOCK("*** bio->bi_vcnt: %u\n",
+ bio->bi_vcnt);
+
+ bio = iblock_get_bio(task, ib_req, ib_dev, &ret,
+ block_lba, sg_num);
+ if (!(bio))
+ goto fail;
+
+ tbio = tbio->bi_next = bio;
+ DEBUG_IBLOCK("-----------------> Added +1 bio: %p to"
+ " list, Going to again\n", bio);
+ goto again;
+ }
+ /* Always in 512 byte units for Linux/Block */
+ block_lba += sg->length >> IBLOCK_LBA_SHIFT;
+ sg_num--;
+ DEBUG_IBLOCK("task: %p bio-add_page() passed!, decremented"
+ " sg_num to %u\n", task, sg_num);
+ DEBUG_IBLOCK("task: %p bio_add_page() passed!, increased lba"
+ " to %llu\n", task, block_lba);
+ DEBUG_IBLOCK("task: %p bio_add_page() passed!, bio->bi_vcnt:"
+ " %u\n", task, bio->bi_vcnt);
+ }
+
+ return 0;
+fail:
+ while (hbio) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_put(bio);
+ }
+ return ret;
+}
+
+static unsigned char *iblock_get_cdb(struct se_task *task)
+{
+ return IBLOCK_REQ(task)->ib_scsi_cdb;
+}
+
+static u32 iblock_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+static u32 iblock_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t iblock_get_blocks(struct se_device *dev)
+{
+ struct iblock_dev *ibd = dev->dev_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ struct request_queue *q = bdev_get_queue(bd);
+
+ return iblock_emulate_read_cap_with_block_size(dev, bd, q);
+}
+
+static void iblock_bio_done(struct bio *bio, int err)
+{
+ struct se_task *task = bio->bi_private;
+ struct iblock_req *ibr = IBLOCK_REQ(task);
+ /*
+ * Set -EIO if !BIO_UPTODATE and the passed is still err=0
+ */
+ if (!(test_bit(BIO_UPTODATE, &bio->bi_flags)) && !(err))
+ err = -EIO;
+
+ if (err != 0) {
+ printk(KERN_ERR "test_bit(BIO_UPTODATE) failed for bio: %p,"
+ " err: %d\n", bio, err);
+ /*
+ * Bump the ib_bio_err_cnt and release bio.
+ */
+ atomic_inc(&ibr->ib_bio_err_cnt);
+ smp_mb__after_atomic_inc();
+ bio_put(bio);
+ /*
+ * Wait to complete the task until the last bio as completed.
+ */
+ if (!(atomic_dec_and_test(&ibr->ib_bio_cnt)))
+ return;
+
+ ibr->ib_bio = NULL;
+ transport_complete_task(task, 0);
+ return;
+ }
+ DEBUG_IBLOCK("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
+ task, bio, task->task_lba, bio->bi_sector, err);
+ /*
+ * bio_put() will call iblock_bio_destructor() to release the bio back
+ * to ibr->ib_bio_set.
+ */
+ bio_put(bio);
+ /*
+ * Wait to complete the task until the last bio as completed.
+ */
+ if (!(atomic_dec_and_test(&ibr->ib_bio_cnt)))
+ return;
+ /*
+ * Return GOOD status for task if zero ib_bio_err_cnt exists.
+ */
+ ibr->ib_bio = NULL;
+ transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt)));
+}
+
+static struct se_subsystem_api iblock_template = {
+ .name = "iblock",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .map_task_SG = iblock_map_task_SG,
+ .attach_hba = iblock_attach_hba,
+ .detach_hba = iblock_detach_hba,
+ .allocate_virtdevice = iblock_allocate_virtdevice,
+ .create_virtdevice = iblock_create_virtdevice,
+ .free_device = iblock_free_device,
+ .dpo_emulated = iblock_emulated_dpo,
+ .fua_write_emulated = iblock_emulated_fua_write,
+ .fua_read_emulated = iblock_emulated_fua_read,
+ .write_cache_emulated = iblock_emulated_write_cache,
+ .alloc_task = iblock_alloc_task,
+ .do_task = iblock_do_task,
+ .do_discard = iblock_do_discard,
+ .do_sync_cache = iblock_emulate_sync_cache,
+ .free_task = iblock_free_task,
+ .check_configfs_dev_params = iblock_check_configfs_dev_params,
+ .set_configfs_dev_params = iblock_set_configfs_dev_params,
+ .show_configfs_dev_params = iblock_show_configfs_dev_params,
+ .get_cdb = iblock_get_cdb,
+ .get_device_rev = iblock_get_device_rev,
+ .get_device_type = iblock_get_device_type,
+ .get_blocks = iblock_get_blocks,
+};
+
+static int __init iblock_module_init(void)
+{
+ return transport_subsystem_register(&iblock_template);
+}
+
+static void iblock_module_exit(void)
+{
+ transport_subsystem_release(&iblock_template);
+}
+
+MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(iblock_module_init);
+module_exit(iblock_module_exit);
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
new file mode 100644
index 000000000000..64c1f4d69f76
--- /dev/null
+++ b/drivers/target/target_core_iblock.h
@@ -0,0 +1,40 @@
+#ifndef TARGET_CORE_IBLOCK_H
+#define TARGET_CORE_IBLOCK_H
+
+#define IBLOCK_VERSION "4.0"
+
+#define IBLOCK_HBA_QUEUE_DEPTH 512
+#define IBLOCK_DEVICE_QUEUE_DEPTH 32
+#define IBLOCK_MAX_DEVICE_QUEUE_DEPTH 128
+#define IBLOCK_MAX_CDBS 16
+#define IBLOCK_LBA_SHIFT 9
+
+struct iblock_req {
+ struct se_task ib_task;
+ unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ atomic_t ib_bio_cnt;
+ atomic_t ib_bio_err_cnt;
+ struct bio *ib_bio;
+ struct iblock_dev *ib_dev;
+} ____cacheline_aligned;
+
+#define IBDF_HAS_UDEV_PATH 0x01
+#define IBDF_HAS_FORCE 0x02
+
+struct iblock_dev {
+ unsigned char ibd_udev_path[SE_UDEV_PATH_LEN];
+ int ibd_force;
+ int ibd_major;
+ int ibd_minor;
+ u32 ibd_depth;
+ u32 ibd_flags;
+ struct bio_set *ibd_bio_set;
+ struct block_device *ibd_bd;
+ struct iblock_hba *ibd_host;
+} ____cacheline_aligned;
+
+struct iblock_hba {
+ int iblock_host_id;
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_IBLOCK_H */
diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c
new file mode 100644
index 000000000000..d5a48aa0d2d1
--- /dev/null
+++ b/drivers/target/target_core_mib.c
@@ -0,0 +1,1078 @@
+/*******************************************************************************
+ * Filename: target_core_mib.c
+ *
+ * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_mib.h"
+
+/* SCSI mib table index */
+static struct scsi_index_table scsi_index_table;
+
+#ifndef INITIAL_JIFFIES
+#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+#endif
+
+/* SCSI Instance Table */
+#define SCSI_INST_SW_INDEX 1
+#define SCSI_TRANSPORT_INDEX 1
+
+#define NONE "None"
+#define ISPRINT(a) ((a >= ' ') && (a <= '~'))
+
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
+static void *locate_hba_start(
+ struct seq_file *seq,
+ loff_t *pos)
+{
+ spin_lock(&se_global->g_device_lock);
+ return seq_list_start(&se_global->g_se_dev_list, *pos);
+}
+
+static void *locate_hba_next(
+ struct seq_file *seq,
+ void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_dev_list, pos);
+}
+
+static void locate_hba_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock(&se_global->g_device_lock);
+}
+
+/****************************************************************************
+ * SCSI MIB Tables
+ ****************************************************************************/
+
+/*
+ * SCSI Instance Table
+ */
+static void *scsi_inst_seq_start(
+ struct seq_file *seq,
+ loff_t *pos)
+{
+ spin_lock(&se_global->hba_lock);
+ return seq_list_start(&se_global->g_hba_list, *pos);
+}
+
+static void *scsi_inst_seq_next(
+ struct seq_file *seq,
+ void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_hba_list, pos);
+}
+
+static void scsi_inst_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock(&se_global->hba_lock);
+}
+
+static int scsi_inst_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba = list_entry(v, struct se_hba, hba_list);
+
+ if (list_is_first(&hba->hba_list, &se_global->g_hba_list))
+ seq_puts(seq, "inst sw_indx\n");
+
+ seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX);
+ seq_printf(seq, "plugin: %s version: %s\n",
+ hba->transport->name, TARGET_CORE_VERSION);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_inst_seq_ops = {
+ .start = scsi_inst_seq_start,
+ .next = scsi_inst_seq_next,
+ .stop = scsi_inst_seq_stop,
+ .show = scsi_inst_seq_show
+};
+
+static int scsi_inst_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_inst_seq_ops);
+}
+
+static const struct file_operations scsi_inst_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_inst_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Device Table
+ */
+static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_dev_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ char str[28];
+ int k;
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst indx role ports\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ seq_printf(seq, "%u %u %s %u\n", hba->hba_index,
+ dev->dev_index, "Target", dev->dev_port_count);
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+
+ /* vendor */
+ for (k = 0; k < 8; k++)
+ str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ?
+ DEV_T10_WWN(dev)->vendor[k] : 0x20;
+ str[k] = 0x20;
+
+ /* model */
+ for (k = 0; k < 16; k++)
+ str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ?
+ DEV_T10_WWN(dev)->model[k] : 0x20;
+ str[k + 9] = 0;
+
+ seq_printf(seq, "dev_alias: %s\n", str);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_dev_seq_ops = {
+ .start = scsi_dev_seq_start,
+ .next = scsi_dev_seq_next,
+ .stop = scsi_dev_seq_stop,
+ .show = scsi_dev_seq_show
+};
+
+static int scsi_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_dev_seq_ops);
+}
+
+static const struct file_operations scsi_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Port Table
+ */
+static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *sep, *sep_tmp;
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx role busy_count\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ /* FIXME: scsiPortBusyStatuses count */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index,
+ dev->dev_index, sep->sep_index, "Device",
+ dev->dev_index, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_port_seq_ops = {
+ .start = scsi_port_seq_start,
+ .next = scsi_port_seq_next,
+ .stop = scsi_port_seq_stop,
+ .show = scsi_port_seq_show
+};
+
+static int scsi_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_port_seq_ops);
+}
+
+static const struct file_operations scsi_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Transport Table
+ */
+static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_transport_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_transport_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *se, *se_tmp;
+ struct se_portal_group *tpg;
+ struct t10_wwn *wwn;
+ char buf[64];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx dev_name\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ wwn = DEV_T10_WWN(dev);
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) {
+ tpg = se->sep_tpg;
+ sprintf(buf, "scsiTransport%s",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %s %u %s+%s\n",
+ hba->hba_index, /* scsiTransportIndex */
+ buf, /* scsiTransportType */
+ (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(tpg)->tpg_get_inst_index(tpg) :
+ 0,
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ (strlen(wwn->unit_serial)) ?
+ /* scsiTransportDevName */
+ wwn->unit_serial : wwn->vendor);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_transport_seq_ops = {
+ .start = scsi_transport_seq_start,
+ .next = scsi_transport_seq_next,
+ .stop = scsi_transport_seq_stop,
+ .show = scsi_transport_seq_show
+};
+
+static int scsi_transport_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_transport_seq_ops);
+}
+
+static const struct file_operations scsi_transport_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_transport_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Device Table
+ */
+static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+
+#define LU_COUNT 1 /* for now */
+static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ int non_accessible_lus = 0;
+ char status[16];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst indx num_LUs status non_access_LUs"
+ " resets\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ switch (dev->dev_status) {
+ case TRANSPORT_DEVICE_ACTIVATED:
+ strcpy(status, "activated");
+ break;
+ case TRANSPORT_DEVICE_DEACTIVATED:
+ strcpy(status, "deactivated");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_SHUTDOWN:
+ strcpy(status, "shutdown");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
+ case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
+ strcpy(status, "offline");
+ non_accessible_lus = 1;
+ break;
+ default:
+ sprintf(status, "unknown(%d)", dev->dev_status);
+ non_accessible_lus = 1;
+ }
+
+ seq_printf(seq, "%u %u %u %s %u %u\n",
+ hba->hba_index, dev->dev_index, LU_COUNT,
+ status, non_accessible_lus, dev->num_resets);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_dev_seq_ops = {
+ .start = scsi_tgt_dev_seq_start,
+ .next = scsi_tgt_dev_seq_next,
+ .stop = scsi_tgt_dev_seq_stop,
+ .show = scsi_tgt_dev_seq_show
+};
+
+static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_dev_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Port Table
+ */
+static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *sep, *sep_tmp;
+ struct se_portal_group *tpg;
+ u32 rx_mbytes, tx_mbytes;
+ unsigned long long num_cmds;
+ char buf[64];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx name port_index in_cmds"
+ " write_mbytes read_mbytes hs_in_cmds\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ tpg = sep->sep_tpg;
+ sprintf(buf, "%sPort#",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %u %u %s%d %s%s%d ",
+ hba->hba_index,
+ dev->dev_index,
+ sep->sep_index,
+ buf, sep->sep_index,
+ TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+",
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+
+ spin_lock(&sep->sep_lun->lun_sep_lock);
+ num_cmds = sep->sep_stats.cmd_pdus;
+ rx_mbytes = (sep->sep_stats.rx_data_octets >> 20);
+ tx_mbytes = (sep->sep_stats.tx_data_octets >> 20);
+ spin_unlock(&sep->sep_lun->lun_sep_lock);
+
+ seq_printf(seq, "%llu %u %u %u\n", num_cmds,
+ rx_mbytes, tx_mbytes, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_port_seq_ops = {
+ .start = scsi_tgt_port_seq_start,
+ .next = scsi_tgt_port_seq_next,
+ .stop = scsi_tgt_port_seq_stop,
+ .show = scsi_tgt_port_seq_show
+};
+
+static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_port_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Authorized Initiator Table:
+ * It contains the SCSI Initiators authorized to be attached to one of the
+ * local Target ports.
+ * Iterates through all active TPGs and extracts the info from the ACLs
+ */
+static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
+ se_tpg_list);
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_node_acl *se_nacl;
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx dev_or_port intr_name "
+ "map_indx att_count num_cmds read_mbytes "
+ "write_mbytes hs_num_cmds creation_time row_status\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->acl_node_lock);
+ list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) {
+
+ atomic_inc(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&se_tpg->acl_node_lock);
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+ lun = deve->se_lun;
+ if (!lun->lun_se_dev)
+ continue;
+
+ seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u"
+ " %u %s\n",
+ /* scsiInstIndex */
+ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
+ 0,
+ /* scsiDeviceIndex */
+ lun->lun_se_dev->dev_index,
+ /* scsiAuthIntrTgtPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAuthIntrIndex */
+ se_nacl->acl_index,
+ /* scsiAuthIntrDevOrPort */
+ 1,
+ /* scsiAuthIntrName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* FIXME: scsiAuthIntrLunMapIndex */
+ 0,
+ /* scsiAuthIntrAttachedTimes */
+ deve->attach_count,
+ /* scsiAuthIntrOutCommands */
+ deve->total_cmds,
+ /* scsiAuthIntrReadMegaBytes */
+ (u32)(deve->read_bytes >> 20),
+ /* scsiAuthIntrWrittenMegaBytes */
+ (u32)(deve->write_bytes >> 20),
+ /* FIXME: scsiAuthIntrHSOutCommands */
+ 0,
+ /* scsiAuthIntrLastCreation */
+ (u32)(((u32)deve->creation_time -
+ INITIAL_JIFFIES) * 100 / HZ),
+ /* FIXME: scsiAuthIntrRowStatus */
+ "Ready");
+ }
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ spin_lock(&se_tpg->acl_node_lock);
+ atomic_dec(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&se_tpg->acl_node_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_auth_intr_seq_ops = {
+ .start = scsi_auth_intr_seq_start,
+ .next = scsi_auth_intr_seq_next,
+ .stop = scsi_auth_intr_seq_stop,
+ .show = scsi_auth_intr_seq_show
+};
+
+static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_auth_intr_seq_ops);
+}
+
+static const struct file_operations scsi_auth_intr_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_auth_intr_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Attached Initiator Port Table:
+ * It lists the SCSI Initiators attached to one of the local Target ports.
+ * Iterates through all active TPGs and use active sessions from each TPG
+ * to list the info fo this table.
+ */
+static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
+ se_tpg_list);
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_node_acl *se_nacl;
+ struct se_session *se_sess;
+ unsigned char buf[64];
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx port_auth_indx port_name"
+ " port_ident\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->session_lock);
+ list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
+ if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) ||
+ (!se_sess->se_node_acl) ||
+ (!se_sess->se_node_acl->device_list))
+ continue;
+
+ atomic_inc(&se_sess->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ se_nacl = se_sess->se_node_acl;
+ atomic_inc(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&se_tpg->session_lock);
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+
+ lun = deve->se_lun;
+ if (!lun->lun_se_dev)
+ continue;
+
+ memset(buf, 0, 64);
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL)
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(
+ se_sess, (unsigned char *)&buf[0], 64);
+
+ seq_printf(seq, "%u %u %u %u %u %s+i+%s\n",
+ /* scsiInstIndex */
+ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
+ 0,
+ /* scsiDeviceIndex */
+ lun->lun_se_dev->dev_index,
+ /* scsiPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAttIntrPortIndex */
+ (TPG_TFO(se_tpg)->sess_get_index != NULL) ?
+ TPG_TFO(se_tpg)->sess_get_index(se_sess) :
+ 0,
+ /* scsiAttIntrPortAuthIntrIdx */
+ se_nacl->acl_index,
+ /* scsiAttIntrPortName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* scsiAttIntrPortIdentifier */
+ buf);
+ }
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ spin_lock(&se_tpg->session_lock);
+ atomic_dec(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&se_sess->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&se_tpg->session_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_att_intr_port_seq_ops = {
+ .start = scsi_att_intr_port_seq_start,
+ .next = scsi_att_intr_port_seq_next,
+ .stop = scsi_att_intr_port_seq_stop,
+ .show = scsi_att_intr_port_seq_show
+};
+
+static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_att_intr_port_seq_ops);
+}
+
+static const struct file_operations scsi_att_intr_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_att_intr_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Logical Unit Table
+ */
+static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_lu_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+#define SCSI_LU_INDEX 1
+static int scsi_lu_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ int j;
+ char str[28];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst dev indx LUN lu_name vend prod rev"
+ " dev_type status state-bit num_cmds read_mbytes"
+ " write_mbytes resets full_stat hs_num_cmds creation_time\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ /* Fix LU state, if we can read it from the device */
+ seq_printf(seq, "%u %u %u %llu %s", hba->hba_index,
+ dev->dev_index, SCSI_LU_INDEX,
+ (unsigned long long)0, /* FIXME: scsiLuDefaultLun */
+ (strlen(DEV_T10_WWN(dev)->unit_serial)) ?
+ /* scsiLuWwnName */
+ (char *)&DEV_T10_WWN(dev)->unit_serial[0] :
+ "None");
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+ /* scsiLuVendorId */
+ for (j = 0; j < 8; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ?
+ DEV_T10_WWN(dev)->vendor[j] : 0x20;
+ str[8] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuProductId */
+ for (j = 0; j < 16; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ?
+ DEV_T10_WWN(dev)->model[j] : 0x20;
+ str[16] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuRevisionId */
+ for (j = 0; j < 4; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ?
+ DEV_T10_WWN(dev)->revision[j] : 0x20;
+ str[4] = 0;
+ seq_printf(seq, " %s", str);
+
+ seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n",
+ /* scsiLuPeripheralType */
+ TRANSPORT(dev)->get_device_type(dev),
+ (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ?
+ "available" : "notavailable", /* scsiLuStatus */
+ "exposed", /* scsiLuState */
+ (unsigned long long)dev->num_cmds,
+ /* scsiLuReadMegaBytes */
+ (u32)(dev->read_bytes >> 20),
+ /* scsiLuWrittenMegaBytes */
+ (u32)(dev->write_bytes >> 20),
+ dev->num_resets, /* scsiLuInResets */
+ 0, /* scsiLuOutTaskSetFullStatus */
+ 0, /* scsiLuHSInCommands */
+ (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) *
+ 100 / HZ));
+
+ return 0;
+}
+
+static const struct seq_operations scsi_lu_seq_ops = {
+ .start = scsi_lu_seq_start,
+ .next = scsi_lu_seq_next,
+ .stop = scsi_lu_seq_stop,
+ .show = scsi_lu_seq_show
+};
+
+static int scsi_lu_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_lu_seq_ops);
+}
+
+static const struct file_operations scsi_lu_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_lu_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/****************************************************************************/
+
+/*
+ * Remove proc fs entries
+ */
+void remove_scsi_target_mib(void)
+{
+ remove_proc_entry("scsi_target/mib/scsi_inst", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_transport", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_lu", NULL);
+ remove_proc_entry("scsi_target/mib", NULL);
+}
+
+/*
+ * Create proc fs entries for the mib tables
+ */
+int init_scsi_target_mib(void)
+{
+ struct proc_dir_entry *dir_entry;
+ struct proc_dir_entry *scsi_inst_entry;
+ struct proc_dir_entry *scsi_dev_entry;
+ struct proc_dir_entry *scsi_port_entry;
+ struct proc_dir_entry *scsi_transport_entry;
+ struct proc_dir_entry *scsi_tgt_dev_entry;
+ struct proc_dir_entry *scsi_tgt_port_entry;
+ struct proc_dir_entry *scsi_auth_intr_entry;
+ struct proc_dir_entry *scsi_att_intr_port_entry;
+ struct proc_dir_entry *scsi_lu_entry;
+
+ dir_entry = proc_mkdir("scsi_target/mib", NULL);
+ if (!(dir_entry)) {
+ printk(KERN_ERR "proc_mkdir() failed.\n");
+ return -1;
+ }
+
+ scsi_inst_entry =
+ create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL);
+ if (scsi_inst_entry)
+ scsi_inst_entry->proc_fops = &scsi_inst_seq_fops;
+ else
+ goto error;
+
+ scsi_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL);
+ if (scsi_dev_entry)
+ scsi_dev_entry->proc_fops = &scsi_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_port", 0, NULL);
+ if (scsi_port_entry)
+ scsi_port_entry->proc_fops = &scsi_port_seq_fops;
+ else
+ goto error;
+
+ scsi_transport_entry =
+ create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL);
+ if (scsi_transport_entry)
+ scsi_transport_entry->proc_fops = &scsi_transport_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL);
+ if (scsi_tgt_dev_entry)
+ scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL);
+ if (scsi_tgt_port_entry)
+ scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops;
+ else
+ goto error;
+
+ scsi_auth_intr_entry =
+ create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL);
+ if (scsi_auth_intr_entry)
+ scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops;
+ else
+ goto error;
+
+ scsi_att_intr_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL);
+ if (scsi_att_intr_port_entry)
+ scsi_att_intr_port_entry->proc_fops =
+ &scsi_att_intr_port_seq_fops;
+ else
+ goto error;
+
+ scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL);
+ if (scsi_lu_entry)
+ scsi_lu_entry->proc_fops = &scsi_lu_seq_fops;
+ else
+ goto error;
+
+ return 0;
+
+error:
+ printk(KERN_ERR "create_proc_entry() failed.\n");
+ remove_scsi_target_mib();
+ return -1;
+}
+
+/*
+ * Initialize the index table for allocating unique row indexes to various mib
+ * tables
+ */
+void init_scsi_index_table(void)
+{
+ memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
+ spin_lock_init(&scsi_index_table.lock);
+}
+
+/*
+ * Allocate a new row index for the entry type specified
+ */
+u32 scsi_get_new_index(scsi_index_t type)
+{
+ u32 new_index;
+
+ if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
+ printk(KERN_ERR "Invalid index type %d\n", type);
+ return -1;
+ }
+
+ spin_lock(&scsi_index_table.lock);
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ if (new_index == 0)
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ spin_unlock(&scsi_index_table.lock);
+
+ return new_index;
+}
+EXPORT_SYMBOL(scsi_get_new_index);
diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h
new file mode 100644
index 000000000000..277204633850
--- /dev/null
+++ b/drivers/target/target_core_mib.h
@@ -0,0 +1,28 @@
+#ifndef TARGET_CORE_MIB_H
+#define TARGET_CORE_MIB_H
+
+typedef enum {
+ SCSI_INST_INDEX,
+ SCSI_DEVICE_INDEX,
+ SCSI_AUTH_INTR_INDEX,
+ SCSI_INDEX_TYPE_MAX
+} scsi_index_t;
+
+struct scsi_index_table {
+ spinlock_t lock;
+ u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX];
+} ____cacheline_aligned;
+
+/* SCSI Port stats */
+struct scsi_port_stats {
+ u64 cmd_pdus;
+ u64 tx_data_octets;
+ u64 rx_data_octets;
+} ____cacheline_aligned;
+
+extern int init_scsi_target_mib(void);
+extern void remove_scsi_target_mib(void);
+extern void init_scsi_index_table(void);
+extern u32 scsi_get_new_index(scsi_index_t);
+
+#endif /*** TARGET_CORE_MIB_H ***/
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
new file mode 100644
index 000000000000..2521f75362c3
--- /dev/null
+++ b/drivers/target/target_core_pr.c
@@ -0,0 +1,4252 @@
+/*******************************************************************************
+ * Filename: target_core_pr.c
+ *
+ * This file contains SPC-3 compliant persistent reservations and
+ * legacy SPC-2 reservations with compatible reservation handling (CRH=1)
+ *
+ * Copyright (c) 2009, 2010 Rising Tide Systems
+ * Copyright (c) 2009, 2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+/*
+ * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT)
+ */
+struct pr_transport_id_holder {
+ int dest_local_nexus;
+ struct t10_pr_registration *dest_pr_reg;
+ struct se_portal_group *dest_tpg;
+ struct se_node_acl *dest_node_acl;
+ struct se_dev_entry *dest_se_deve;
+ struct list_head dest_list;
+};
+
+int core_pr_dump_initiator_port(
+ struct t10_pr_registration *pr_reg,
+ char *buf,
+ u32 size)
+{
+ if (!(pr_reg->isid_present_at_reg))
+ return 0;
+
+ snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]);
+ return 1;
+}
+
+static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
+ struct t10_pr_registration *, int);
+
+static int core_scsi2_reservation_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ switch (cdb[0]) {
+ case INQUIRY:
+ case RELEASE:
+ case RELEASE_10:
+ return 0;
+ default:
+ return 1;
+ }
+
+ return 1;
+}
+
+static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ int ret;
+
+ if (!(sess))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!dev->dev_reserved_node_acl || !sess) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ if (dev->dev_reserved_node_acl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return -1;
+ }
+ if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -1;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+static int core_scsi2_reservation_release(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+
+ if (!(sess) || !(tpg))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!dev->dev_reserved_node_acl || !sess) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+
+ if (dev->dev_reserved_node_acl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ dev->dev_reserved_node_acl = NULL;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) {
+ dev->dev_res_bin_isid = 0;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ printk(KERN_INFO "SCSI-2 Released reservation for %s LUN: %u ->"
+ " MAPPED LUN: %u for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return 0;
+}
+
+static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x01) &&
+ (T_TASK(cmd)->t_task_cdb[1] & 0x02)) {
+ printk(KERN_ERR "LongIO and Obselete Bits set, returning"
+ " ILLEGAL_REQUEST\n");
+ return PYX_TRANSPORT_ILLEGAL_REQUEST;
+ }
+ /*
+ * This is currently the case for target_core_mod passthrough struct se_cmd
+ * ops
+ */
+ if (!(sess) || !(tpg))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (dev->dev_reserved_node_acl &&
+ (dev->dev_reserved_node_acl != sess->se_node_acl)) {
+ printk(KERN_ERR "SCSI-2 RESERVATION CONFLIFT for %s fabric\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ printk(KERN_ERR "Original reserver LUN: %u %s\n",
+ SE_LUN(cmd)->unpacked_lun,
+ dev->dev_reserved_node_acl->initiatorname);
+ printk(KERN_ERR "Current attempt - LUN: %u -> MAPPED LUN: %u"
+ " from %s \n", SE_LUN(cmd)->unpacked_lun,
+ cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ dev->dev_reserved_node_acl = sess->se_node_acl;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS;
+ if (sess->sess_bin_isid != 0) {
+ dev->dev_res_bin_isid = sess->sess_bin_isid;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ printk(KERN_INFO "SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u"
+ " for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return 0;
+}
+
+static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *,
+ struct se_node_acl *, struct se_session *);
+static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
+
+/*
+ * Setup in target_core_transport.c:transport_generic_cmd_sequencer()
+ * and called via struct se_cmd->transport_emulate_cdb() in TCM processing
+ * thread context.
+ */
+int core_scsi2_emulate_crh(struct se_cmd *cmd)
+{
+ struct se_session *se_sess = cmd->se_sess;
+ struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+ struct t10_pr_registration *pr_reg;
+ struct t10_reservation_template *pr_tmpl = &su_dev->t10_reservation;
+ unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+ int crh = (T10_RES(su_dev)->res_type == SPC3_PERSISTENT_RESERVATIONS);
+ int conflict = 0;
+
+ if (!(se_sess))
+ return 0;
+
+ if (!(crh))
+ goto after_crh;
+
+ pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
+ se_sess);
+ if (pr_reg) {
+ /*
+ * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE
+ * behavior
+ *
+ * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
+ * status, but no reservation shall be established and the
+ * persistent reservation shall not be changed, if the command
+ * is received from a) and b) below.
+ *
+ * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
+ * status, but the persistent reservation shall not be released,
+ * if the command is received from a) and b)
+ *
+ * a) An I_T nexus that is a persistent reservation holder; or
+ * b) An I_T nexus that is registered if a registrants only or
+ * all registrants type persistent reservation is present.
+ *
+ * In all other cases, a RESERVE(6) command, RESERVE(10) command,
+ * RELEASE(6) command, or RELEASE(10) command shall be processed
+ * as defined in SPC-2.
+ */
+ if (pr_reg->pr_res_holder) {
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+ }
+ if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+ (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
+ (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+ }
+ core_scsi3_put_pr_reg(pr_reg);
+ conflict = 1;
+ } else {
+ /*
+ * Following spc2r20 5.5.1 Reservations overview:
+ *
+ * If a logical unit has executed a PERSISTENT RESERVE OUT
+ * command with the REGISTER or the REGISTER AND IGNORE
+ * EXISTING KEY service action and is still registered by any
+ * initiator, all RESERVE commands and all RELEASE commands
+ * regardless of initiator shall conflict and shall terminate
+ * with a RESERVATION CONFLICT status.
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1;
+ spin_unlock(&pr_tmpl->registration_lock);
+ }
+
+ if (conflict) {
+ printk(KERN_ERR "Received legacy SPC-2 RESERVE/RELEASE"
+ " while active SPC-3 registrations exist,"
+ " returning RESERVATION_CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+after_crh:
+ if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10))
+ return core_scsi2_reservation_reserve(cmd);
+ else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10))
+ return core_scsi2_reservation_release(cmd);
+ else
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+}
+
+/*
+ * Begin SPC-3/SPC-4 Persistent Reservations emulation support
+ *
+ * This function is called by those initiator ports who are *NOT*
+ * the active PR reservation holder when a reservation is present.
+ */
+static int core_scsi3_pr_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ struct se_dev_entry *se_deve;
+ struct se_session *se_sess = SE_SESS(cmd);
+ int other_cdb = 0, ignore_reg;
+ int registered_nexus = 0, ret = 1; /* Conflict by default */
+ int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */
+ int we = 0; /* Write Exclusive */
+ int legacy = 0; /* Act like a legacy device and return
+ * RESERVATION CONFLICT on some CDBs */
+ /*
+ * A legacy SPC-2 reservation is being held.
+ */
+ if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS)
+ return core_scsi2_reservation_seq_non_holder(cmd,
+ cdb, pr_reg_type);
+
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Determine if the registration should be ignored due to
+ * non-matching ISIDs in core_scsi3_pr_reservation_check().
+ */
+ ignore_reg = (pr_reg_type & 0x80000000);
+ if (ignore_reg)
+ pr_reg_type &= ~0x80000000;
+
+ switch (pr_reg_type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ /*
+ * Some commands are only allowed for the persistent reservation
+ * holder.
+ */
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ /*
+ * Some commands are only allowed for registered I_T Nexuses.
+ */
+ reg_only = 1;
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ /*
+ * Each registered I_T Nexus is a reservation holder.
+ */
+ all_reg = 1;
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ default:
+ return -1;
+ }
+ /*
+ * Referenced from spc4r17 table 45 for *NON* PR holder access
+ */
+ switch (cdb[0]) {
+ case SECURITY_PROTOCOL_IN:
+ if (registered_nexus)
+ return 0;
+ ret = (we) ? 0 : 1;
+ break;
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case READ_ATTRIBUTE:
+ case READ_BUFFER:
+ case RECEIVE_DIAGNOSTIC:
+ if (legacy) {
+ ret = 1;
+ break;
+ }
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case PERSISTENT_RESERVE_OUT:
+ /*
+ * This follows PERSISTENT_RESERVE_OUT service actions that
+ * are allowed in the presence of various reservations.
+ * See spc4r17, table 46
+ */
+ switch (cdb[1] & 0x1f) {
+ case PRO_CLEAR:
+ case PRO_PREEMPT:
+ case PRO_PREEMPT_AND_ABORT:
+ ret = (registered_nexus) ? 0 : 1;
+ break;
+ case PRO_REGISTER:
+ case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
+ ret = 0;
+ break;
+ case PRO_REGISTER_AND_MOVE:
+ case PRO_RESERVE:
+ ret = 1;
+ break;
+ case PRO_RELEASE:
+ ret = (registered_nexus) ? 0 : 1;
+ break;
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return -1;
+ }
+ break;
+ case RELEASE:
+ case RELEASE_10:
+ /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ ret = 0;
+ break;
+ case RESERVE:
+ case RESERVE_10:
+ /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ ret = 0;
+ break;
+ case TEST_UNIT_READY:
+ ret = (legacy) ? 1 : 0; /* Conflict for legacy */
+ break;
+ case MAINTENANCE_IN:
+ switch (cdb[1] & 0x1f) {
+ case MI_MANAGEMENT_PROTOCOL_IN:
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case MI_REPORT_SUPPORTED_OPERATION_CODES:
+ case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
+ if (legacy) {
+ ret = 1;
+ break;
+ }
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case MI_REPORT_ALIASES:
+ case MI_REPORT_IDENTIFYING_INFORMATION:
+ case MI_REPORT_PRIORITY:
+ case MI_REPORT_TARGET_PGS:
+ case MI_REPORT_TIMESTAMP:
+ ret = 0; /* Allowed */
+ break;
+ default:
+ printk(KERN_ERR "Unknown MI Service Action: 0x%02x\n",
+ (cdb[1] & 0x1f));
+ return -1;
+ }
+ break;
+ case ACCESS_CONTROL_IN:
+ case ACCESS_CONTROL_OUT:
+ case INQUIRY:
+ case LOG_SENSE:
+ case READ_MEDIA_SERIAL_NUMBER:
+ case REPORT_LUNS:
+ case REQUEST_SENSE:
+ ret = 0; /*/ Allowed CDBs */
+ break;
+ default:
+ other_cdb = 1;
+ break;
+ }
+ /*
+ * Case where the CDB is explictly allowed in the above switch
+ * statement.
+ */
+ if (!(ret) && !(other_cdb)) {
+#if 0
+ printk(KERN_INFO "Allowing explict CDB: 0x%02x for %s"
+ " reservation holder\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+#endif
+ return ret;
+ }
+ /*
+ * Check if write exclusive initiator ports *NOT* holding the
+ * WRITE_EXCLUSIVE_* reservation.
+ */
+ if ((we) && !(registered_nexus)) {
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ /*
+ * Conflict for write exclusive
+ */
+ printk(KERN_INFO "%s Conflict for unregistered nexus"
+ " %s CDB: 0x%02x to %s reservation\n",
+ transport_dump_cmd_direction(cmd),
+ se_sess->se_node_acl->initiatorname, cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+ return 1;
+ } else {
+ /*
+ * Allow non WRITE CDBs for all Write Exclusive
+ * PR TYPEs to pass for registered and
+ * non-registered_nexuxes NOT holding the reservation.
+ *
+ * We only make noise for the unregisterd nexuses,
+ * as we expect registered non-reservation holding
+ * nexuses to issue CDBs.
+ */
+#if 0
+ if (!(registered_nexus)) {
+ printk(KERN_INFO "Allowing implict CDB: 0x%02x"
+ " for %s reservation on unregistered"
+ " nexus\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+ }
+#endif
+ return 0;
+ }
+ } else if ((reg_only) || (all_reg)) {
+ if (registered_nexus) {
+ /*
+ * For PR_*_REG_ONLY and PR_*_ALL_REG reservations,
+ * allow commands from registered nexuses.
+ */
+#if 0
+ printk(KERN_INFO "Allowing implict CDB: 0x%02x for %s"
+ " reservation\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+#endif
+ return 0;
+ }
+ }
+ printk(KERN_INFO "%s Conflict for %sregistered nexus %s CDB: 0x%2x"
+ " for %s reservation\n", transport_dump_cmd_direction(cmd),
+ (registered_nexus) ? "" : "un",
+ se_sess->se_node_acl->initiatorname, cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+
+ return 1; /* Conflict by default */
+}
+
+static u32 core_scsi3_pr_generation(struct se_device *dev)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ u32 prg;
+ /*
+ * PRGeneration field shall contain the value of a 32-bit wrapping
+ * counter mainted by the device server.
+ *
+ * Note that this is done regardless of Active Persist across
+ * Target PowerLoss (APTPL)
+ *
+ * See spc4r17 section 6.3.12 READ_KEYS service action
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ prg = T10_RES(su_dev)->pr_generation++;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return prg;
+}
+
+static int core_scsi3_pr_reservation_check(
+ struct se_cmd *cmd,
+ u32 *pr_reg_type)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ int ret;
+
+ if (!(sess))
+ return 0;
+ /*
+ * A legacy SPC-2 reservation is being held.
+ */
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS)
+ return core_scsi2_reservation_check(cmd, pr_reg_type);
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!(dev->dev_pr_res_holder)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ *pr_reg_type = dev->dev_pr_res_holder->pr_res_type;
+ cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key;
+ if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return -1;
+ }
+ if (!(dev->dev_pr_res_holder->isid_present_at_reg)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ ret = (dev->dev_pr_res_holder->pr_reg_bin_isid ==
+ sess->sess_bin_isid) ? 0 : -1;
+ /*
+ * Use bit in *pr_reg_type to notify ISID mismatch in
+ * core_scsi3_pr_seq_non_holder().
+ */
+ if (ret != 0)
+ *pr_reg_type |= 0x80000000;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_pr_registration *pr_reg;
+
+ pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n");
+ return NULL;
+ }
+
+ pr_reg->pr_aptpl_buf = kzalloc(T10_RES(su_dev)->pr_aptpl_buf_len,
+ GFP_ATOMIC);
+ if (!(pr_reg->pr_aptpl_buf)) {
+ printk(KERN_ERR "Unable to allocate pr_reg->pr_aptpl_buf\n");
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&pr_reg->pr_reg_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list);
+ atomic_set(&pr_reg->pr_res_holders, 0);
+ pr_reg->pr_reg_nacl = nacl;
+ pr_reg->pr_reg_deve = deve;
+ pr_reg->pr_res_mapped_lun = deve->mapped_lun;
+ pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun;
+ pr_reg->pr_res_key = sa_res_key;
+ pr_reg->pr_reg_all_tg_pt = all_tg_pt;
+ pr_reg->pr_reg_aptpl = aptpl;
+ pr_reg->pr_reg_tg_pt_lun = deve->se_lun;
+ /*
+ * If an ISID value for this SCSI Initiator Port exists,
+ * save it to the registration now.
+ */
+ if (isid != NULL) {
+ pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid);
+ snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid);
+ pr_reg->isid_present_at_reg = 1;
+ }
+
+ return pr_reg;
+}
+
+static int core_scsi3_lunacl_depend_item(struct se_dev_entry *);
+static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *);
+
+/*
+ * Function used for handling PR registrations for ALL_TG_PT=1 and ALL_TG_PT=0
+ * modes.
+ */
+static struct t10_pr_registration *__core_scsi3_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_dev_entry *deve_tmp;
+ struct se_node_acl *nacl_tmp;
+ struct se_port *port, *port_tmp;
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
+ int ret;
+ /*
+ * Create a registration for the I_T Nexus upon which the
+ * PROUT REGISTER was received.
+ */
+ pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg))
+ return NULL;
+ /*
+ * Return pointer to pr_reg for ALL_TG_PT=0
+ */
+ if (!(all_tg_pt))
+ return pr_reg;
+ /*
+ * Create list of matching SCSI Initiator Port registrations
+ * for ALL_TG_PT=1
+ */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) {
+ atomic_inc(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_for_each_entry(deve_tmp, &port->sep_alua_list,
+ alua_port_list) {
+ /*
+ * This pointer will be NULL for demo mode MappedLUNs
+ * that have not been make explict via a ConfigFS
+ * MappedLUN group for the SCSI Initiator Node ACL.
+ */
+ if (!(deve_tmp->se_lun_acl))
+ continue;
+
+ nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl;
+ /*
+ * Skip the matching struct se_node_acl that is allocated
+ * above..
+ */
+ if (nacl == nacl_tmp)
+ continue;
+ /*
+ * Only perform PR registrations for target ports on
+ * the same fabric module as the REGISTER w/ ALL_TG_PT=1
+ * arrived.
+ */
+ if (tfo != nacl_tmp->se_tpg->se_tpg_tfo)
+ continue;
+ /*
+ * Look for a matching Initiator Node ACL in ASCII format
+ */
+ if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname))
+ continue;
+
+ atomic_inc(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock_bh(&port->sep_alua_lock);
+ /*
+ * Grab a configfs group dependency that is released
+ * for the exception path at label out: below, or upon
+ * completion of adding ALL_TG_PT=1 registrations in
+ * __core_scsi3_add_registration()
+ */
+ ret = core_scsi3_lunacl_depend_item(deve_tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend"
+ "_item() failed\n");
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ goto out;
+ }
+ /*
+ * Located a matching SCSI Initiator Port on a different
+ * port, allocate the pr_reg_atp and attach it to the
+ * pr_reg->pr_reg_atp_list that will be processed once
+ * the original *pr_reg is processed in
+ * __core_scsi3_add_registration()
+ */
+ pr_reg_atp = __core_scsi3_do_alloc_registration(dev,
+ nacl_tmp, deve_tmp, NULL,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg_atp)) {
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_lunacl_undepend_item(deve_tmp);
+ goto out;
+ }
+
+ list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list,
+ &pr_reg->pr_reg_atp_list);
+ spin_lock_bh(&port->sep_alua_lock);
+ }
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ spin_lock(&dev->se_port_lock);
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return pr_reg;
+out:
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);
+ }
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return NULL;
+}
+
+int core_scsi3_alloc_aptpl_registration(
+ struct t10_reservation_template *pr_tmpl,
+ u64 sa_res_key,
+ unsigned char *i_port,
+ unsigned char *isid,
+ u32 mapped_lun,
+ unsigned char *t_port,
+ u16 tpgt,
+ u32 target_lun,
+ int res_holder,
+ int all_tg_pt,
+ u8 type)
+{
+ struct t10_pr_registration *pr_reg;
+
+ if (!(i_port) || !(t_port) || !(sa_res_key)) {
+ printk(KERN_ERR "Illegal parameters for APTPL registration\n");
+ return -1;
+ }
+
+ pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n");
+ return -1;
+ }
+ pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL);
+
+ INIT_LIST_HEAD(&pr_reg->pr_reg_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list);
+ atomic_set(&pr_reg->pr_res_holders, 0);
+ pr_reg->pr_reg_nacl = NULL;
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_res_mapped_lun = mapped_lun;
+ pr_reg->pr_aptpl_target_lun = target_lun;
+ pr_reg->pr_res_key = sa_res_key;
+ pr_reg->pr_reg_all_tg_pt = all_tg_pt;
+ pr_reg->pr_reg_aptpl = 1;
+ pr_reg->pr_reg_tg_pt_lun = NULL;
+ pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */
+ pr_reg->pr_res_type = type;
+ /*
+ * If an ISID value had been saved in APTPL metadata for this
+ * SCSI Initiator Port, restore it now.
+ */
+ if (isid != NULL) {
+ pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid);
+ snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid);
+ pr_reg->isid_present_at_reg = 1;
+ }
+ /*
+ * Copy the i_port and t_port information from caller.
+ */
+ snprintf(pr_reg->pr_iport, PR_APTPL_MAX_IPORT_LEN, "%s", i_port);
+ snprintf(pr_reg->pr_tport, PR_APTPL_MAX_TPORT_LEN, "%s", t_port);
+ pr_reg->pr_reg_tpgt = tpgt;
+ /*
+ * Set pr_res_holder from caller, the pr_reg who is the reservation
+ * holder will get it's pointer set in core_scsi3_aptpl_reserve() once
+ * the Initiator Node LUN ACL from the fabric module is created for
+ * this registration.
+ */
+ pr_reg->pr_res_holder = res_holder;
+
+ list_add_tail(&pr_reg->pr_reg_aptpl_list, &pr_tmpl->aptpl_reg_list);
+ printk(KERN_INFO "SPC-3 PR APTPL Successfully added registration%s from"
+ " metadata\n", (res_holder) ? "+reservation" : "");
+ return 0;
+}
+
+static void core_scsi3_aptpl_reserve(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_node_acl *node_acl,
+ struct t10_pr_registration *pr_reg)
+{
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ spin_lock(&dev->dev_reservation_lock);
+ dev->dev_pr_res_holder = pr_reg;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: APTPL RESERVE created"
+ " new reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n",
+ TPG_TFO(tpg)->get_fabric_name(), node_acl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+}
+
+static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *,
+ struct t10_pr_registration *, int, int);
+
+static int __core_scsi3_check_aptpl_registration(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ u32 target_lun,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char i_port[PR_APTPL_MAX_IPORT_LEN];
+ unsigned char t_port[PR_APTPL_MAX_TPORT_LEN];
+ u16 tpgt;
+
+ memset(i_port, 0, PR_APTPL_MAX_IPORT_LEN);
+ memset(t_port, 0, PR_APTPL_MAX_TPORT_LEN);
+ /*
+ * Copy Initiator Port information from struct se_node_acl
+ */
+ snprintf(i_port, PR_APTPL_MAX_IPORT_LEN, "%s", nacl->initiatorname);
+ snprintf(t_port, PR_APTPL_MAX_TPORT_LEN, "%s",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg));
+ tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg);
+ /*
+ * Look for the matching registrations+reservation from those
+ * created from APTPL metadata. Note that multiple registrations
+ * may exist for fabrics that use ISIDs in their SCSI Initiator Port
+ * TransportIDs.
+ */
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
+ pr_reg_aptpl_list) {
+ if (!(strcmp(pr_reg->pr_iport, i_port)) &&
+ (pr_reg->pr_res_mapped_lun == deve->mapped_lun) &&
+ !(strcmp(pr_reg->pr_tport, t_port)) &&
+ (pr_reg->pr_reg_tpgt == tpgt) &&
+ (pr_reg->pr_aptpl_target_lun == target_lun)) {
+
+ pr_reg->pr_reg_nacl = nacl;
+ pr_reg->pr_reg_deve = deve;
+ pr_reg->pr_reg_tg_pt_lun = lun;
+
+ list_del(&pr_reg->pr_reg_aptpl_list);
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+ /*
+ * At this point all of the pointers in *pr_reg will
+ * be setup, so go ahead and add the registration.
+ */
+
+ __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0);
+ /*
+ * If this registration is the reservation holder,
+ * make that happen now..
+ */
+ if (pr_reg->pr_res_holder)
+ core_scsi3_aptpl_reserve(dev, tpg,
+ nacl, pr_reg);
+ /*
+ * Reenable pr_aptpl_active to accept new metadata
+ * updates once the SCSI device is active again..
+ */
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ pr_tmpl->pr_aptpl_active = 1;
+ }
+ }
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+
+ return 0;
+}
+
+int core_scsi3_check_aptpl_registration(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ struct se_lun_acl *lun_acl)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct se_node_acl *nacl = lun_acl->se_lun_nacl;
+ struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun];
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return __core_scsi3_check_aptpl_registration(dev, tpg, lun,
+ lun->unpacked_lun, nacl, deve);
+}
+
+static void __core_scsi3_dump_registration(
+ struct target_core_fabric_ops *tfo,
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct t10_pr_registration *pr_reg,
+ int register_type)
+{
+ struct se_portal_group *se_tpg = nacl->se_tpg;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER%s Initiator"
+ " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ?
+ "_AND_MOVE" : (register_type == 1) ?
+ "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname,
+ (prf_isid) ? i_buf : "");
+ printk(KERN_INFO "SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n",
+ tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg),
+ tfo->tpg_get_tag(se_tpg));
+ printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"
+ " Port(s)\n", tfo->get_fabric_name(),
+ (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE",
+ TRANSPORT(dev)->name);
+ printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:"
+ " 0x%08x APTPL: %d\n", tfo->get_fabric_name(),
+ pr_reg->pr_res_key, pr_reg->pr_res_generation,
+ pr_reg->pr_reg_aptpl);
+}
+
+/*
+ * this function can be called with struct se_device->dev_reservation_lock
+ * when register_move = 1
+ */
+static void __core_scsi3_add_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct t10_pr_registration *pr_reg,
+ int register_type,
+ int register_move)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+
+ /*
+ * Increment PRgeneration counter for struct se_device upon a successful
+ * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action
+ *
+ * Also, when register_move = 1 for PROUT REGISTER_AND_MOVE service
+ * action, the struct se_device->dev_reservation_lock will already be held,
+ * so we do not call core_scsi3_pr_generation() which grabs the lock
+ * for the REGISTER.
+ */
+ pr_reg->pr_res_generation = (register_move) ?
+ T10_RES(su_dev)->pr_generation++ :
+ core_scsi3_pr_generation(dev);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list);
+ pr_reg->pr_reg_deve->def_pr_registered = 1;
+
+ __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type);
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE.
+ */
+ if (!(pr_reg->pr_reg_all_tg_pt) || (register_move))
+ return;
+ /*
+ * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1
+ * allocated in __core_scsi3_alloc_registration()
+ */
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+
+ pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_add_tail(&pr_reg_tmp->pr_reg_list,
+ &pr_tmpl->registration_list);
+ pr_reg_tmp->pr_reg_deve->def_pr_registered = 1;
+
+ __core_scsi3_dump_registration(tfo, dev,
+ pr_reg_tmp->pr_reg_nacl, pr_reg_tmp,
+ register_type);
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Drop configfs group dependency reference from
+ * __core_scsi3_alloc_registration()
+ */
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ }
+}
+
+static int core_scsi3_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl,
+ int register_type,
+ int register_move)
+{
+ struct t10_pr_registration *pr_reg;
+
+ pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg))
+ return -1;
+
+ __core_scsi3_add_registration(dev, nacl, pr_reg,
+ register_type, register_move);
+ return 0;
+}
+
+static struct t10_pr_registration *__core_scsi3_locate_pr_reg(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ unsigned char *isid)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct se_portal_group *tpg;
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ /*
+ * First look for a matching struct se_node_acl
+ */
+ if (pr_reg->pr_reg_nacl != nacl)
+ continue;
+
+ tpg = pr_reg->pr_reg_nacl->se_tpg;
+ /*
+ * If this registration does NOT contain a fabric provided
+ * ISID, then we have found a match.
+ */
+ if (!(pr_reg->isid_present_at_reg)) {
+ /*
+ * Determine if this SCSI device server requires that
+ * SCSI Intiatior TransportID w/ ISIDs is enforced
+ * for fabric modules (iSCSI) requiring them.
+ */
+ if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) {
+ if (DEV_ATTRIB(dev)->enforce_pr_isids)
+ continue;
+ }
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ return pr_reg;
+ }
+ /*
+ * If the *pr_reg contains a fabric defined ISID for multi-value
+ * SCSI Initiator Port TransportIDs, then we expect a valid
+ * matching ISID to be provided by the local SCSI Initiator Port.
+ */
+ if (!(isid))
+ continue;
+ if (strcmp(isid, pr_reg->pr_reg_isid))
+ continue;
+
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ return pr_reg;
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ return NULL;
+}
+
+static struct t10_pr_registration *core_scsi3_locate_pr_reg(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_session *sess)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+ unsigned char buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
+
+ if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) {
+ memset(&buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(tpg)->sess_get_initiator_sid(sess, &buf[0],
+ PR_REG_ISID_LEN);
+ isid_ptr = &buf[0];
+ }
+
+ return __core_scsi3_locate_pr_reg(dev, nacl, isid_ptr);
+}
+
+static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg)
+{
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_check_implict_release(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg)
+{
+ struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
+ struct t10_pr_registration *pr_res_holder;
+ int ret = 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return ret;
+ }
+ if (pr_res_holder == pr_reg) {
+ /*
+ * Perform an implict RELEASE if the registration that
+ * is being released is holding the reservation.
+ *
+ * From spc4r17, section 5.7.11.1:
+ *
+ * e) If the I_T nexus is the persistent reservation holder
+ * and the persistent reservation is not an all registrants
+ * type, then a PERSISTENT RESERVE OUT command with REGISTER
+ * service action or REGISTER AND IGNORE EXISTING KEY
+ * service action with the SERVICE ACTION RESERVATION KEY
+ * field set to zero (see 5.7.11.3).
+ */
+ __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0);
+ ret = 1;
+ /*
+ * For 'All Registrants' reservation types, all existing
+ * registrations are still processed as reservation holders
+ * in core_scsi3_pr_seq_non_holder() after the initial
+ * reservation holder is implictly released here.
+ */
+ } else if (pr_reg->pr_reg_all_tg_pt &&
+ (!strcmp(pr_res_holder->pr_reg_nacl->initiatorname,
+ pr_reg->pr_reg_nacl->initiatorname)) &&
+ (pr_res_holder->pr_res_key == pr_reg->pr_res_key)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to perform ALL_TG_PT=1"
+ " UNREGISTER while existing reservation with matching"
+ " key 0x%016Lx is present from another SCSI Initiator"
+ " Port\n", pr_reg->pr_res_key);
+ ret = -1;
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+/*
+ * Called with struct t10_reservation_template->registration_lock held.
+ */
+static void __core_scsi3_free_registration(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg,
+ struct list_head *preempt_and_abort_list,
+ int dec_holders)
+{
+ struct target_core_fabric_ops *tfo =
+ pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ pr_reg->pr_reg_deve->def_pr_registered = 0;
+ pr_reg->pr_reg_deve->pr_res_key = 0;
+ list_del(&pr_reg->pr_reg_list);
+ /*
+ * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(),
+ * so call core_scsi3_put_pr_reg() to decrement our reference.
+ */
+ if (dec_holders)
+ core_scsi3_put_pr_reg(pr_reg);
+ /*
+ * Wait until all reference from any other I_T nexuses for this
+ * *pr_reg have been released. Because list_del() is called above,
+ * the last core_scsi3_put_pr_reg(pr_reg) will release this reference
+ * count back to zero, and we release *pr_reg.
+ */
+ while (atomic_read(&pr_reg->pr_res_holders) != 0) {
+ spin_unlock(&pr_tmpl->registration_lock);
+ printk("SPC-3 PR [%s] waiting for pr_res_holders\n",
+ tfo->get_fabric_name());
+ cpu_relax();
+ spin_lock(&pr_tmpl->registration_lock);
+ }
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: UNREGISTER Initiator"
+ " Node: %s%s\n", tfo->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"
+ " Port(s)\n", tfo->get_fabric_name(),
+ (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE",
+ TRANSPORT(dev)->name);
+ printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:"
+ " 0x%08x\n", tfo->get_fabric_name(), pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ if (!(preempt_and_abort_list)) {
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return;
+ }
+ /*
+ * For PREEMPT_AND_ABORT, the list of *pr_reg in preempt_and_abort_list
+ * are released once the ABORT_TASK_SET has completed..
+ */
+ list_add_tail(&pr_reg->pr_reg_abort_list, preempt_and_abort_list);
+}
+
+void core_scsi3_free_pr_reg_from_nacl(
+ struct se_device *dev,
+ struct se_node_acl *nacl)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
+ /*
+ * If the passed se_node_acl matches the reservation holder,
+ * release the reservation.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if ((pr_res_holder != NULL) &&
+ (pr_res_holder->pr_reg_nacl == nacl))
+ __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0);
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * Release any registration associated with the struct se_node_acl.
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ if (pr_reg->pr_reg_nacl != nacl)
+ continue;
+
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 0);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+}
+
+void core_scsi3_free_all_registrations(
+ struct se_device *dev)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder != NULL) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ pr_res_holder, 0);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 0);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
+ pr_reg_aptpl_list) {
+ list_del(&pr_reg->pr_reg_aptpl_list);
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ }
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+}
+
+static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg)
+{
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &tpg->tpg_group.cg_item);
+}
+
+static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg)
+{
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &tpg->tpg_group.cg_item);
+
+ atomic_dec(&tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+
+ if (nacl->dynamic_node_acl)
+ return 0;
+
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &nacl->acl_group.cg_item);
+}
+
+static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+
+ if (nacl->dynamic_node_acl) {
+ atomic_dec(&nacl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ return;
+ }
+
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &nacl->acl_group.cg_item);
+
+ atomic_dec(&nacl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
+{
+ struct se_lun_acl *lun_acl = se_deve->se_lun_acl;
+ struct se_node_acl *nacl;
+ struct se_portal_group *tpg;
+ /*
+ * For nacl->dynamic_node_acl=1
+ */
+ if (!(lun_acl))
+ return 0;
+
+ nacl = lun_acl->se_lun_nacl;
+ tpg = nacl->se_tpg;
+
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &lun_acl->se_lun_group.cg_item);
+}
+
+static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
+{
+ struct se_lun_acl *lun_acl = se_deve->se_lun_acl;
+ struct se_node_acl *nacl;
+ struct se_portal_group *tpg;
+ /*
+ * For nacl->dynamic_node_acl=1
+ */
+ if (!(lun_acl)) {
+ atomic_dec(&se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ return;
+ }
+ nacl = lun_acl->se_lun_nacl;
+ tpg = nacl->se_tpg;
+
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &lun_acl->se_lun_group.cg_item);
+
+ atomic_dec(&se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_decode_spec_i_port(
+ struct se_cmd *cmd,
+ struct se_portal_group *tpg,
+ unsigned char *l_isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_port *tmp_port;
+ struct se_portal_group *dest_tpg = NULL, *tmp_tpg;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_node_acl *dest_node_acl = NULL;
+ struct se_dev_entry *dest_se_deve = NULL, *local_se_deve;
+ struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e;
+ struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
+ struct list_head tid_dest_list;
+ struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
+ struct target_core_fabric_ops *tmp_tf_ops;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
+ char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
+ u32 tpdl, tid_len = 0;
+ int ret, dest_local_nexus, prf_isid;
+ u32 dest_rtpi = 0;
+
+ memset(dest_iport, 0, 64);
+ INIT_LIST_HEAD(&tid_dest_list);
+
+ local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Allocate a struct pr_transport_id_holder and setup the
+ * local_node_acl and local_se_deve pointers and add to
+ * struct list_head tid_dest_list for add registration
+ * processing in the loop of tid_dest_list below.
+ */
+ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL);
+ if (!(tidh_new)) {
+ printk(KERN_ERR "Unable to allocate tidh_new\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ INIT_LIST_HEAD(&tidh_new->dest_list);
+ tidh_new->dest_tpg = tpg;
+ tidh_new->dest_node_acl = se_sess->se_node_acl;
+ tidh_new->dest_se_deve = local_se_deve;
+
+ local_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd),
+ se_sess->se_node_acl, local_se_deve, l_isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(local_pr_reg)) {
+ kfree(tidh_new);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ tidh_new->dest_pr_reg = local_pr_reg;
+ /*
+ * The local I_T nexus does not hold any configfs dependances,
+ * so we set tid_h->dest_local_nexus=1 to prevent the
+ * configfs_undepend_item() calls in the tid_dest_list loops below.
+ */
+ tidh_new->dest_local_nexus = 1;
+ list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+ /*
+ * For a PERSISTENT RESERVE OUT specify initiator ports payload,
+ * first extract TransportID Parameter Data Length, and make sure
+ * the value matches up to the SCSI expected data transfer length.
+ */
+ tpdl = (buf[24] & 0xff) << 24;
+ tpdl |= (buf[25] & 0xff) << 16;
+ tpdl |= (buf[26] & 0xff) << 8;
+ tpdl |= buf[27] & 0xff;
+
+ if ((tpdl + 28) != cmd->data_length) {
+ printk(KERN_ERR "SPC-3 PR: Illegal tpdl: %u + 28 byte header"
+ " does not equal CDB data_length: %u\n", tpdl,
+ cmd->data_length);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ /*
+ * Start processing the received transport IDs using the
+ * receiving I_T Nexus portal's fabric dependent methods to
+ * obtain the SCSI Initiator Port/Device Identifiers.
+ */
+ ptr = &buf[28];
+
+ while (tpdl > 0) {
+ proto_ident = (ptr[0] & 0x0f);
+ dest_tpg = NULL;
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) {
+ tmp_tpg = tmp_port->sep_tpg;
+ if (!(tmp_tpg))
+ continue;
+ tmp_tf_ops = TPG_TFO(tmp_tpg);
+ if (!(tmp_tf_ops))
+ continue;
+ if (!(tmp_tf_ops->get_fabric_proto_ident) ||
+ !(tmp_tf_ops->tpg_parse_pr_out_transport_id))
+ continue;
+ /*
+ * Look for the matching proto_ident provided by
+ * the received TransportID
+ */
+ tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg);
+ if (tmp_proto_ident != proto_ident)
+ continue;
+ dest_rtpi = tmp_port->sep_rtpi;
+
+ i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id(
+ tmp_tpg, (const char *)ptr, &tid_len,
+ &iport_ptr);
+ if (!(i_str))
+ continue;
+
+ atomic_inc(&tmp_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ ret = core_scsi3_tpg_depend_item(tmp_tpg);
+ if (ret != 0) {
+ printk(KERN_ERR " core_scsi3_tpg_depend_item()"
+ " for tmp_tpg\n");
+ atomic_dec(&tmp_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ /*
+ * Locate the desination initiator ACL to be registered
+ * from the decoded fabric module specific TransportID
+ * at *i_str.
+ */
+ spin_lock_bh(&tmp_tpg->acl_node_lock);
+ dest_node_acl = __core_tpg_get_initiator_node_acl(
+ tmp_tpg, i_str);
+ if (dest_node_acl) {
+ atomic_inc(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ }
+ spin_unlock_bh(&tmp_tpg->acl_node_lock);
+
+ if (!(dest_node_acl)) {
+ core_scsi3_tpg_undepend_item(tmp_tpg);
+ spin_lock(&dev->se_port_lock);
+ continue;
+ }
+
+ ret = core_scsi3_nodeacl_depend_item(dest_node_acl);
+ if (ret != 0) {
+ printk(KERN_ERR "configfs_depend_item() failed"
+ " for dest_node_acl->acl_group\n");
+ atomic_dec(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_tpg_undepend_item(tmp_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+
+ dest_tpg = tmp_tpg;
+ printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node:"
+ " %s Port RTPI: %hu\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, dest_rtpi);
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ if (!(dest_tpg)) {
+ printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Unable to locate"
+ " dest_tpg\n");
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+#if 0
+ printk("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u"
+ " tid_len: %d for %s + %s\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(), cmd->data_length,
+ tpdl, tid_len, i_str, iport_ptr);
+#endif
+ if (tid_len > tpdl) {
+ printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Illegal tid_len:"
+ " %u for Transport ID: %s\n", tid_len, ptr);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ /*
+ * Locate the desintation struct se_dev_entry pointer for matching
+ * RELATIVE TARGET PORT IDENTIFIER on the receiving I_T Nexus
+ * Target Port.
+ */
+ dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl,
+ dest_rtpi);
+ if (!(dest_se_deve)) {
+ printk(KERN_ERR "Unable to locate %s dest_se_deve"
+ " from destination RTPI: %hu\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_rtpi);
+
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ ret = core_scsi3_lunacl_depend_item(dest_se_deve);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend_item()"
+ " failed\n");
+ atomic_dec(&dest_se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node: %s"
+ " dest_se_deve mapped_lun: %u\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, dest_se_deve->mapped_lun);
+#endif
+ /*
+ * Skip any TransportIDs that already have a registration for
+ * this target port.
+ */
+ pr_reg_e = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ if (pr_reg_e) {
+ core_scsi3_put_pr_reg(pr_reg_e);
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ptr += tid_len;
+ tpdl -= tid_len;
+ tid_len = 0;
+ continue;
+ }
+ /*
+ * Allocate a struct pr_transport_id_holder and setup
+ * the dest_node_acl and dest_se_deve pointers for the
+ * loop below.
+ */
+ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder),
+ GFP_KERNEL);
+ if (!(tidh_new)) {
+ printk(KERN_ERR "Unable to allocate tidh_new\n");
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ INIT_LIST_HEAD(&tidh_new->dest_list);
+ tidh_new->dest_tpg = dest_tpg;
+ tidh_new->dest_node_acl = dest_node_acl;
+ tidh_new->dest_se_deve = dest_se_deve;
+
+ /*
+ * Allocate, but do NOT add the registration for the
+ * TransportID referenced SCSI Initiator port. This
+ * done because of the following from spc4r17 in section
+ * 6.14.3 wrt SPEC_I_PT:
+ *
+ * "If a registration fails for any initiator port (e.g., if th
+ * logical unit does not have enough resources available to
+ * hold the registration information), no registrations shall be
+ * made, and the command shall be terminated with
+ * CHECK CONDITION status."
+ *
+ * That means we call __core_scsi3_alloc_registration() here,
+ * and then call __core_scsi3_add_registration() in the
+ * 2nd loop which will never fail.
+ */
+ dest_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd),
+ dest_node_acl, dest_se_deve, iport_ptr,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(dest_pr_reg)) {
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ kfree(tidh_new);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ tidh_new->dest_pr_reg = dest_pr_reg;
+ list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+
+ ptr += tid_len;
+ tpdl -= tid_len;
+ tid_len = 0;
+
+ }
+ /*
+ * Go ahead and create a registrations from tid_dest_list for the
+ * SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl
+ * and dest_se_deve.
+ *
+ * The SA Reservation Key from the PROUT is set for the
+ * registration, and ALL_TG_PT is also passed. ALL_TG_PT=1
+ * means that the TransportID Initiator port will be
+ * registered on all of the target ports in the SCSI target device
+ * ALL_TG_PT=0 means the registration will only be for the
+ * SCSI target port the PROUT REGISTER with SPEC_I_PT=1
+ * was received.
+ */
+ list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) {
+ dest_tpg = tidh->dest_tpg;
+ dest_node_acl = tidh->dest_node_acl;
+ dest_se_deve = tidh->dest_se_deve;
+ dest_pr_reg = tidh->dest_pr_reg;
+ dest_local_nexus = tidh->dest_local_nexus;
+
+ list_del(&tidh->dest_list);
+ kfree(tidh);
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ __core_scsi3_add_registration(SE_DEV(cmd), dest_node_acl,
+ dest_pr_reg, 0, 0);
+
+ printk(KERN_INFO "SPC-3 PR [%s] SPEC_I_PT: Successfully"
+ " registered Transport ID for Node: %s%s Mapped LUN:"
+ " %u\n", TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, (prf_isid) ?
+ &i_buf[0] : "", dest_se_deve->mapped_lun);
+
+ if (dest_local_nexus)
+ continue;
+
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ }
+
+ return 0;
+out:
+ /*
+ * For the failure case, release everything from tid_dest_list
+ * including *dest_pr_reg and the configfs dependances..
+ */
+ list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) {
+ dest_tpg = tidh->dest_tpg;
+ dest_node_acl = tidh->dest_node_acl;
+ dest_se_deve = tidh->dest_se_deve;
+ dest_pr_reg = tidh->dest_pr_reg;
+ dest_local_nexus = tidh->dest_local_nexus;
+
+ list_del(&tidh->dest_list);
+ kfree(tidh);
+ /*
+ * Release any extra ALL_TG_PT=1 registrations for
+ * the SPEC_I_PT=1 case.
+ */
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &dest_pr_reg->pr_reg_atp_list,
+ pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);
+ }
+
+ kfree(dest_pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, dest_pr_reg);
+
+ if (dest_local_nexus)
+ continue;
+
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ }
+ return ret;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held
+ */
+static int __core_scsi3_update_aptpl_buf(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len,
+ int clear_aptpl_metadata)
+{
+ struct se_lun *lun;
+ struct se_portal_group *tpg;
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char tmp[512], isid_buf[32];
+ ssize_t len = 0;
+ int reg_count = 0;
+
+ memset(buf, 0, pr_aptpl_buf_len);
+ /*
+ * Called to clear metadata once APTPL has been deactivated.
+ */
+ if (clear_aptpl_metadata) {
+ snprintf(buf, pr_aptpl_buf_len,
+ "No Registrations or Reservations\n");
+ return 0;
+ }
+ /*
+ * Walk the registration list..
+ */
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+
+ tmp[0] = '\0';
+ isid_buf[0] = '\0';
+ tpg = pr_reg->pr_reg_nacl->se_tpg;
+ lun = pr_reg->pr_reg_tg_pt_lun;
+ /*
+ * Write out any ISID value to APTPL metadata that was included
+ * in the original registration.
+ */
+ if (pr_reg->isid_present_at_reg)
+ snprintf(isid_buf, 32, "initiator_sid=%s\n",
+ pr_reg->pr_reg_isid);
+ /*
+ * Include special metadata if the pr_reg matches the
+ * reservation holder.
+ */
+ if (dev->dev_pr_res_holder == pr_reg) {
+ snprintf(tmp, 512, "PR_REG_START: %d"
+ "\ninitiator_fabric=%s\n"
+ "initiator_node=%s\n%s"
+ "sa_res_key=%llu\n"
+ "res_holder=1\nres_type=%02x\n"
+ "res_scope=%02x\nres_all_tg_pt=%d\n"
+ "mapped_lun=%u\n", reg_count,
+ TPG_TFO(tpg)->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, isid_buf,
+ pr_reg->pr_res_key, pr_reg->pr_res_type,
+ pr_reg->pr_res_scope, pr_reg->pr_reg_all_tg_pt,
+ pr_reg->pr_res_mapped_lun);
+ } else {
+ snprintf(tmp, 512, "PR_REG_START: %d\n"
+ "initiator_fabric=%s\ninitiator_node=%s\n%s"
+ "sa_res_key=%llu\nres_holder=0\n"
+ "res_all_tg_pt=%d\nmapped_lun=%u\n",
+ reg_count, TPG_TFO(tpg)->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, isid_buf,
+ pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt,
+ pr_reg->pr_res_mapped_lun);
+ }
+
+ if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+ printk(KERN_ERR "Unable to update renaming"
+ " APTPL metadata\n");
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+ return -1;
+ }
+ len += sprintf(buf+len, "%s", tmp);
+
+ /*
+ * Include information about the associated SCSI target port.
+ */
+ snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n"
+ "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:"
+ " %d\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count);
+
+ if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+ printk(KERN_ERR "Unable to update renaming"
+ " APTPL metadata\n");
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+ return -1;
+ }
+ len += sprintf(buf+len, "%s", tmp);
+ reg_count++;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ if (!(reg_count))
+ len += sprintf(buf+len, "No Registrations or Reservations");
+
+ return 0;
+}
+
+static int core_scsi3_update_aptpl_buf(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len,
+ int clear_aptpl_metadata)
+{
+ int ret;
+
+ spin_lock(&dev->dev_reservation_lock);
+ ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
+ clear_aptpl_metadata);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+/*
+ * Called with struct se_device->aptpl_file_mutex held
+ */
+static int __core_scsi3_write_aptpl_to_file(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len)
+{
+ struct t10_wwn *wwn = &SU_DEV(dev)->t10_wwn;
+ struct file *file;
+ struct iovec iov[1];
+ mm_segment_t old_fs;
+ int flags = O_RDWR | O_CREAT | O_TRUNC;
+ char path[512];
+ int ret;
+
+ memset(iov, 0, sizeof(struct iovec));
+ memset(path, 0, 512);
+
+ if (strlen(&wwn->unit_serial[0]) > 512) {
+ printk(KERN_ERR "WWN value for struct se_device does not fit"
+ " into path buffer\n");
+ return -1;
+ }
+
+ snprintf(path, 512, "/var/target/pr/aptpl_%s", &wwn->unit_serial[0]);
+ file = filp_open(path, flags, 0600);
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) for APTPL metadata"
+ " failed\n", path);
+ return -1;
+ }
+
+ iov[0].iov_base = &buf[0];
+ if (!(pr_aptpl_buf_len))
+ iov[0].iov_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */
+ else
+ iov[0].iov_len = pr_aptpl_buf_len;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(file, &iov[0], 1, &file->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk("Error writing APTPL metadata file: %s\n", path);
+ filp_close(file, NULL);
+ return -1;
+ }
+ filp_close(file, NULL);
+
+ return 0;
+}
+
+static int core_scsi3_update_and_write_aptpl(
+ struct se_device *dev,
+ unsigned char *in_buf,
+ u32 in_pr_aptpl_buf_len)
+{
+ unsigned char null_buf[64], *buf;
+ u32 pr_aptpl_buf_len;
+ int ret, clear_aptpl_metadata = 0;
+ /*
+ * Can be called with a NULL pointer from PROUT service action CLEAR
+ */
+ if (!(in_buf)) {
+ memset(null_buf, 0, 64);
+ buf = &null_buf[0];
+ /*
+ * This will clear the APTPL metadata to:
+ * "No Registrations or Reservations" status
+ */
+ pr_aptpl_buf_len = 64;
+ clear_aptpl_metadata = 1;
+ } else {
+ buf = in_buf;
+ pr_aptpl_buf_len = in_pr_aptpl_buf_len;
+ }
+
+ ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
+ clear_aptpl_metadata);
+ if (ret != 0)
+ return -1;
+ /*
+ * __core_scsi3_write_aptpl_to_file() will call strlen()
+ * on the passed buf to determine pr_aptpl_buf_len.
+ */
+ ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0);
+ if (ret != 0)
+ return -1;
+
+ return ret;
+}
+
+static int core_scsi3_emulate_pro_register(
+ struct se_cmd *cmd,
+ u64 res_key,
+ u64 sa_res_key,
+ int aptpl,
+ int all_tg_pt,
+ int spec_i_pt,
+ int ignore_key)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ /* Used for APTPL metadata w/ UNREGISTER */
+ unsigned char *pr_aptpl_buf = NULL;
+ unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
+ int pr_holder = 0, ret = 0, type;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ se_tpg = se_sess->se_tpg;
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) {
+ memset(&isid_buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess, &isid_buf[0],
+ PR_REG_ISID_LEN);
+ isid_ptr = &isid_buf[0];
+ }
+ /*
+ * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47
+ */
+ pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+ if (!(pr_reg_e)) {
+ if (res_key) {
+ printk(KERN_WARNING "SPC-3 PR: Reservation Key non-zero"
+ " for SA REGISTER, returning CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * Do nothing but return GOOD status.
+ */
+ if (!(sa_res_key))
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+
+ if (!(spec_i_pt)) {
+ /*
+ * Perform the Service Action REGISTER on the Initiator
+ * Port Endpoint that the PRO was received from on the
+ * Logical Unit of the SCSI device server.
+ */
+ ret = core_scsi3_alloc_registration(SE_DEV(cmd),
+ se_sess->se_node_acl, se_deve, isid_ptr,
+ sa_res_key, all_tg_pt, aptpl,
+ ignore_key, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "Unable to allocate"
+ " struct t10_pr_registration\n");
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ } else {
+ /*
+ * Register both the Initiator port that received
+ * PROUT SA REGISTER + SPEC_I_PT=1 and extract SCSI
+ * TransportID from Parameter list and loop through
+ * fabric dependent parameter list while calling
+ * logic from of core_scsi3_alloc_registration() for
+ * each TransportID provided SCSI Initiator Port/Device
+ */
+ ret = core_scsi3_decode_spec_i_port(cmd, se_tpg,
+ isid_ptr, sa_res_key, all_tg_pt, aptpl);
+ if (ret != 0)
+ return ret;
+ }
+ /*
+ * Nothing left to do for the APTPL=0 case.
+ */
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated for"
+ " REGISTER\n");
+ return 0;
+ }
+ /*
+ * Locate the newly allocated local I_T Nexus *pr_reg, and
+ * update the APTPL metadata information using its
+ * preallocated *pr_reg->pr_aptpl_buf.
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd),
+ se_sess->se_node_acl, se_sess);
+
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return ret;
+ } else {
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = pr_reg_e;
+ type = pr_reg->pr_res_type;
+
+ if (!(ignore_key)) {
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR REGISTER: Received"
+ " res_key: 0x%016Lx does not match"
+ " existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key,
+ pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ }
+ if (spec_i_pt) {
+ printk(KERN_ERR "SPC-3 PR UNREGISTER: SPEC_I_PT"
+ " set while sa_res_key=0\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * An existing ALL_TG_PT=1 registration being released
+ * must also set ALL_TG_PT=1 in the incoming PROUT.
+ */
+ if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) {
+ printk(KERN_ERR "SPC-3 PR UNREGISTER: ALL_TG_PT=1"
+ " registration exists, but ALL_TG_PT=1 bit not"
+ " present in received PROUT\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+ /*
+ * Allocate APTPL metadata buffer used for UNREGISTER ops
+ */
+ if (aptpl) {
+ pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len,
+ GFP_KERNEL);
+ if (!(pr_aptpl_buf)) {
+ printk(KERN_ERR "Unable to allocate"
+ " pr_aptpl_buf\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ }
+ /*
+ * sa_res_key=0 Unregister Reservation Key for registered I_T
+ * Nexus sa_res_key=1 Change Reservation Key for registered I_T
+ * Nexus.
+ */
+ if (!(sa_res_key)) {
+ pr_holder = core_scsi3_check_implict_release(
+ SE_DEV(cmd), pr_reg);
+ if (pr_holder < 0) {
+ kfree(pr_aptpl_buf);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ spin_lock(&pr_tmpl->registration_lock);
+ /*
+ * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port
+ * and matching pr_res_key.
+ */
+ if (pr_reg->pr_reg_all_tg_pt) {
+ list_for_each_entry_safe(pr_reg_p, pr_reg_tmp,
+ &pr_tmpl->registration_list,
+ pr_reg_list) {
+
+ if (!(pr_reg_p->pr_reg_all_tg_pt))
+ continue;
+
+ if (pr_reg_p->pr_res_key != res_key)
+ continue;
+
+ if (pr_reg == pr_reg_p)
+ continue;
+
+ if (strcmp(pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg_p->pr_reg_nacl->initiatorname))
+ continue;
+
+ __core_scsi3_free_registration(dev,
+ pr_reg_p, NULL, 0);
+ }
+ }
+ /*
+ * Release the calling I_T Nexus registration now..
+ */
+ __core_scsi3_free_registration(SE_DEV(cmd), pr_reg,
+ NULL, 1);
+ /*
+ * From spc4r17, section 5.7.11.3 Unregistering
+ *
+ * If the persistent reservation is a registrants only
+ * type, the device server shall establish a unit
+ * attention condition for the initiator port associated
+ * with every registered I_T nexus except for the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command was
+ * received, with the additional sense code set to
+ * RESERVATIONS RELEASED.
+ */
+ if (pr_holder &&
+ ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+ (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) {
+ list_for_each_entry(pr_reg_p,
+ &pr_tmpl->registration_list,
+ pr_reg_list) {
+
+ core_scsi3_ua_allocate(
+ pr_reg_p->pr_reg_nacl,
+ pr_reg_p->pr_res_mapped_lun,
+ 0x2A,
+ ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(dev, NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated"
+ " for UNREGISTER\n");
+ return 0;
+ }
+
+ ret = core_scsi3_update_and_write_aptpl(dev,
+ &pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated"
+ " for UNREGISTER\n");
+ }
+
+ kfree(pr_aptpl_buf);
+ return ret;
+ } else {
+ /*
+ * Increment PRgeneration counter for struct se_device"
+ * upon a successful REGISTER, see spc4r17 section 6.3.2
+ * READ_KEYS service action.
+ */
+ pr_reg->pr_res_generation = core_scsi3_pr_generation(
+ SE_DEV(cmd));
+ pr_reg->pr_res_key = sa_res_key;
+ printk("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
+ " Key for %s to: 0x%016Lx PRgeneration:"
+ " 0x%08x\n", CMD_TFO(cmd)->get_fabric_name(),
+ (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "",
+ pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg->pr_res_key, pr_reg->pr_res_generation);
+
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(dev, NULL, 0);
+ core_scsi3_put_pr_reg(pr_reg);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated"
+ " for REGISTER\n");
+ return 0;
+ }
+
+ ret = core_scsi3_update_and_write_aptpl(dev,
+ &pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated"
+ " for REGISTER\n");
+ }
+
+ kfree(pr_aptpl_buf);
+ core_scsi3_put_pr_reg(pr_reg);
+ }
+ }
+ return 0;
+}
+
+unsigned char *core_scsi3_pr_dump_type(int type)
+{
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ return "Write Exclusive Access";
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ return "Exclusive Access";
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ return "Write Exclusive Access, Registrants Only";
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ return "Exclusive Access, Registrants Only";
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ return "Write Exclusive Access, All Registrants";
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ return "Exclusive Access, All Registrants";
+ default:
+ break;
+ }
+
+ return "Unknown SPC-3 PR Type";
+}
+
+static int core_scsi3_pro_reserve(
+ struct se_cmd *cmd,
+ struct se_device *dev,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int ret, prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ se_tpg = se_sess->se_tpg;
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for RESERVE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * An application client creates a persistent reservation by issuing
+ * a PERSISTENT RESERVE OUT command with RESERVE service action through
+ * a registered I_T nexus with the following parameters:
+ * a) RESERVATION KEY set to the value of the reservation key that is
+ * registered with the logical unit for the I_T nexus; and
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR RESERVE: Received res_key: 0x%016Lx"
+ " does not match existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * From above:
+ * b) TYPE field and SCOPE field set to the persistent reservation
+ * being created.
+ *
+ * Only one persistent reservation is allowed at a time per logical unit
+ * and that persistent reservation has a scope of LU_SCOPE.
+ */
+ if (scope != PR_SCOPE_LU_SCOPE) {
+ printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * See if we have an existing PR reservation holder pointer at
+ * struct se_device->dev_pr_res_holder in the form struct t10_pr_registration
+ * *pr_res_holder.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if ((pr_res_holder)) {
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If the device server receives a PERSISTENT RESERVE OUT
+ * command from an I_T nexus other than a persistent reservation
+ * holder (see 5.7.10) that attempts to create a persistent
+ * reservation when a persistent reservation already exists for
+ * the logical unit, then the command shall be completed with
+ * RESERVATION CONFLICT status.
+ */
+ if (pr_res_holder != pr_reg) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from"
+ " [%s]: %s while reservation already held by"
+ " [%s]: %s, returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If a persistent reservation holder attempts to modify the
+ * type or scope of an existing persistent reservation, the
+ * command shall be completed with RESERVATION CONFLICT status.
+ */
+ if ((pr_res_holder->pr_res_type != type) ||
+ (pr_res_holder->pr_res_scope != scope)) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from"
+ " [%s]: %s trying to change TYPE and/or SCOPE,"
+ " while reservation already held by [%s]: %s,"
+ " returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If the device server receives a PERSISTENT RESERVE OUT
+ * command with RESERVE service action where the TYPE field and
+ * the SCOPE field contain the same values as the existing type
+ * and scope from a persistent reservation holder, it shall not
+ * make any change to the existing persistent reservation and
+ * shall completethe command with GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ /*
+ * Otherwise, our *pr_reg becomes the PR reservation holder for said
+ * TYPE/SCOPE. Also set the received scope and type in *pr_reg.
+ */
+ pr_reg->pr_res_scope = scope;
+ pr_reg->pr_res_type = type;
+ pr_reg->pr_res_holder = 1;
+ dev->dev_pr_res_holder = pr_reg;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: RESERVE created new"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ CMD_TFO(cmd)->get_fabric_name(), core_scsi3_pr_dump_type(type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata"
+ " for RESERVE\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_reserve(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ int ret = 0;
+
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key);
+ break;
+ default:
+ printk(KERN_ERR "SPC-3 PR: Unknown Service Action RESERVE Type:"
+ " 0x%02x\n", type);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return ret;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held.
+ */
+static void __core_scsi3_complete_pro_release(
+ struct se_device *dev,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int explict)
+{
+ struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Go ahead and release the current PR reservation holder.
+ */
+ dev->dev_pr_res_holder = NULL;
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: %s RELEASE cleared"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ tfo->get_fabric_name(), (explict) ? "explict" : "implict",
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RELEASE Node: %s%s\n",
+ tfo->get_fabric_name(), se_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ /*
+ * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE
+ */
+ pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0;
+}
+
+static int core_scsi3_emulate_pro_release(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ int ret, all_reg = 0;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for RELEASE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing:
+ *
+ * If there is no persistent reservation or in response to a persistent
+ * reservation release request from a registered I_T nexus that is not a
+ * persistent reservation holder (see 5.7.10), the device server shall
+ * do the following:
+ *
+ * a) Not release the persistent reservation, if any;
+ * b) Not remove any registrations; and
+ * c) Complete the command with GOOD status.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ /*
+ * No persistent reservation, return GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
+ all_reg = 1;
+
+ if ((all_reg == 0) && (pr_res_holder != pr_reg)) {
+ /*
+ * Non 'All Registrants' PR Type cases..
+ * Release request from a registered I_T nexus that is not a
+ * persistent reservation holder. return GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing:
+ *
+ * Only the persistent reservation holder (see 5.7.10) is allowed to
+ * release a persistent reservation.
+ *
+ * An application client releases the persistent reservation by issuing
+ * a PERSISTENT RESERVE OUT command with RELEASE service action through
+ * an I_T nexus that is a persistent reservation holder with the
+ * following parameters:
+ *
+ * a) RESERVATION KEY field set to the value of the reservation key
+ * that is registered with the logical unit for the I_T nexus;
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR RELEASE: Received res_key: 0x%016Lx"
+ " does not match existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing and above:
+ *
+ * b) TYPE field and SCOPE field set to match the persistent
+ * reservation being released.
+ */
+ if ((pr_res_holder->pr_res_type != type) ||
+ (pr_res_holder->pr_res_scope != scope)) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR RELEASE: Attempted to release"
+ " reservation from [%s]: %s with different TYPE "
+ "and/or SCOPE while reservation already held by"
+ " [%s]: %s, returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * In response to a persistent reservation release request from the
+ * persistent reservation holder the device server shall perform a
+ * release by doing the following as an uninterrupted series of actions:
+ * a) Release the persistent reservation;
+ * b) Not remove any registration(s);
+ * c) If the released persistent reservation is a registrants only type
+ * or all registrants type persistent reservation,
+ * the device server shall establish a unit attention condition for
+ * the initiator port associated with every regis-
+ * tered I_T nexus other than I_T nexus on which the PERSISTENT
+ * RESERVE OUT command with RELEASE service action was received,
+ * with the additional sense code set to RESERVATIONS RELEASED; and
+ * d) If the persistent reservation is of any other type, the device
+ * server shall not establish a unit attention condition.
+ */
+ __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl,
+ pr_reg, 1);
+
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) &&
+ (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ /*
+ * If no UNIT ATTENTION conditions will be established for
+ * PR_TYPE_WRITE_EXCLUSIVE or PR_TYPE_EXCLUSIVE_ACCESS
+ * go ahead and check for APTPL=1 update+write below
+ */
+ goto write_aptpl;
+ }
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list,
+ pr_reg_list) {
+ /*
+ * Do not establish a UNIT ATTENTION condition
+ * for the calling I_T Nexus
+ */
+ if (pr_reg_p == pr_reg)
+ continue;
+
+ core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl,
+ pr_reg_p->pr_res_mapped_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+write_aptpl:
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Updated APTPL metadata for RELEASE\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_clear(
+ struct se_cmd *cmd,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_node_acl *pr_reg_nacl;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
+ u32 pr_res_mapped_lun = 0;
+ int calling_it_nexus = 0;
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd),
+ se_sess->se_node_acl, se_sess);
+ if (!(pr_reg_n)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for CLEAR\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 section 5.7.11.6, Clearing:
+ *
+ * Any application client may release the persistent reservation and
+ * remove all registrations from a device server by issuing a
+ * PERSISTENT RESERVE OUT command with CLEAR service action through a
+ * registered I_T nexus with the following parameter:
+ *
+ * a) RESERVATION KEY field set to the value of the reservation key
+ * that is registered with the logical unit for the I_T nexus.
+ */
+ if (res_key != pr_reg_n->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR REGISTER: Received"
+ " res_key: 0x%016Lx does not match"
+ " existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * a) Release the persistent reservation, if any;
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ pr_res_holder, 0);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * b) Remove all registration(s) (see spc4r17 5.7.7);
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg, NULL,
+ calling_it_nexus);
+ /*
+ * e) Establish a unit attention condition for the initiator
+ * port associated with every registered I_T nexus other
+ * than the I_T nexus on which the PERSISTENT RESERVE OUT
+ * command with CLEAR service action was received, with the
+ * additional sense code set to RESERVATIONS PREEMPTED.
+ */
+ if (!(calling_it_nexus))
+ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: CLEAR complete\n",
+ CMD_TFO(cmd)->get_fabric_name());
+
+ if (pr_tmpl->pr_aptpl_active) {
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata"
+ " for CLEAR\n");
+ }
+
+ core_scsi3_pr_generation(dev);
+ return 0;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held.
+ */
+static void __core_scsi3_complete_pro_preempt(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg,
+ struct list_head *preempt_and_abort_list,
+ int type,
+ int scope,
+ int abort)
+{
+ struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Do an implict RELEASE of the existing reservation.
+ */
+ if (dev->dev_pr_res_holder)
+ __core_scsi3_complete_pro_release(dev, nacl,
+ dev->dev_pr_res_holder, 0);
+
+ dev->dev_pr_res_holder = pr_reg;
+ pr_reg->pr_res_holder = 1;
+ pr_reg->pr_res_type = type;
+ pr_reg->pr_res_scope = scope;
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: PREEMPT%s created new"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
+ core_scsi3_pr_dump_type(type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n",
+ tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
+ nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+ /*
+ * For PREEMPT_AND_ABORT, add the preempting reservation's
+ * struct t10_pr_registration to the list that will be compared
+ * against received CDBs..
+ */
+ if (preempt_and_abort_list)
+ list_add_tail(&pr_reg->pr_reg_abort_list,
+ preempt_and_abort_list);
+}
+
+static void core_scsi3_release_preempt_and_abort(
+ struct list_head *preempt_and_abort_list,
+ struct t10_pr_registration *pr_reg_holder)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list,
+ pr_reg_abort_list) {
+
+ list_del(&pr_reg->pr_reg_abort_list);
+ if (pr_reg_holder == pr_reg)
+ continue;
+ if (pr_reg->pr_res_holder) {
+ printk(KERN_WARNING "pr_reg->pr_res_holder still set\n");
+ continue;
+ }
+
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ }
+}
+
+int core_scsi3_check_cdb_abort_and_preempt(
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *cmd)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list,
+ pr_reg_abort_list) {
+ if (pr_reg->pr_res_key == cmd->pr_res_key)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int core_scsi3_pro_preempt(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key,
+ int abort)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_node_acl *pr_reg_nacl;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct list_head preempt_and_abort_list;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ u32 pr_res_mapped_lun = 0;
+ int all_reg = 0, calling_it_nexus = 0, released_regs = 0;
+ int prh_type = 0, prh_scope = 0, ret;
+
+ if (!(se_sess))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg_n)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for PREEMPT%s\n",
+ (abort) ? "_AND_ABORT" : "");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ if (pr_reg_n->pr_res_key != res_key) {
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ if (scope != PR_SCOPE_LU_SCOPE) {
+ printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ INIT_LIST_HEAD(&preempt_and_abort_list);
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder &&
+ ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)))
+ all_reg = 1;
+
+ if (!(all_reg) && !(sa_res_key)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * From spc4r17, section 5.7.11.4.4 Removing Registrations:
+ *
+ * If the SERVICE ACTION RESERVATION KEY field does not identify a
+ * persistent reservation holder or there is no persistent reservation
+ * holder (i.e., there is no persistent reservation), then the device
+ * server shall perform a preempt by doing the following in an
+ * uninterrupted series of actions. (See below..)
+ */
+ if (!(pr_res_holder) || (pr_res_holder->pr_res_key != sa_res_key)) {
+ /*
+ * No existing or SA Reservation Key matching reservations..
+ *
+ * PROUT SA PREEMPT with All Registrant type reservations are
+ * allowed to be processed without a matching SA Reservation Key
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ /*
+ * Removing of registrations in non all registrants
+ * type reservations without a matching SA reservation
+ * key.
+ *
+ * a) Remove the registrations for all I_T nexuses
+ * specified by the SERVICE ACTION RESERVATION KEY
+ * field;
+ * b) Ignore the contents of the SCOPE and TYPE fields;
+ * c) Process tasks as defined in 5.7.1; and
+ * d) Establish a unit attention condition for the
+ * initiator port associated with every I_T nexus
+ * that lost its registration other than the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command
+ * was received, with the additional sense code set
+ * to REGISTRATIONS PREEMPTED.
+ */
+ if (!(all_reg)) {
+ if (pr_reg->pr_res_key != sa_res_key)
+ continue;
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list :
+ NULL, calling_it_nexus);
+ released_regs++;
+ } else {
+ /*
+ * Case for any existing all registrants type
+ * reservation, follow logic in spc4r17 section
+ * 5.7.11.4 Preempting, Table 52 and Figure 7.
+ *
+ * For a ZERO SA Reservation key, release
+ * all other registrations and do an implict
+ * release of active persistent reservation.
+ *
+ * For a non-ZERO SA Reservation key, only
+ * release the matching reservation key from
+ * registrations.
+ */
+ if ((sa_res_key) &&
+ (pr_reg->pr_res_key != sa_res_key))
+ continue;
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list :
+ NULL, 0);
+ released_regs++;
+ }
+ if (!(calling_it_nexus))
+ core_scsi3_ua_allocate(pr_reg_nacl,
+ pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * If a PERSISTENT RESERVE OUT with a PREEMPT service action or
+ * a PREEMPT AND ABORT service action sets the SERVICE ACTION
+ * RESERVATION KEY field to a value that does not match any
+ * registered reservation key, then the device server shall
+ * complete the command with RESERVATION CONFLICT status.
+ */
+ if (!(released_regs)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * For an existing all registrants type reservation
+ * with a zero SA rservation key, preempt the existing
+ * reservation with the new PR type and scope.
+ */
+ if (pr_res_holder && all_reg && !(sa_res_key)) {
+ __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
+ (abort) ? &preempt_and_abort_list : NULL,
+ type, scope, abort);
+
+ if (abort)
+ core_scsi3_release_preempt_and_abort(
+ &preempt_and_abort_list, pr_reg_n);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg_n->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL"
+ " metadata for PREEMPT%s\n", (abort) ?
+ "_AND_ABORT" : "");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg_n);
+ core_scsi3_pr_generation(SE_DEV(cmd));
+ return 0;
+ }
+ /*
+ * The PREEMPTing SA reservation key matches that of the
+ * existing persistent reservation, first, we check if
+ * we are preempting our own reservation.
+ * From spc4r17, section 5.7.11.4.3 Preempting
+ * persistent reservations and registration handling
+ *
+ * If an all registrants persistent reservation is not
+ * present, it is not an error for the persistent
+ * reservation holder to preempt itself (i.e., a
+ * PERSISTENT RESERVE OUT with a PREEMPT service action
+ * or a PREEMPT AND ABORT service action with the
+ * SERVICE ACTION RESERVATION KEY value equal to the
+ * persistent reservation holder's reservation key that
+ * is received from the persistent reservation holder).
+ * In that case, the device server shall establish the
+ * new persistent reservation and maintain the
+ * registration.
+ */
+ prh_type = pr_res_holder->pr_res_type;
+ prh_scope = pr_res_holder->pr_res_scope;
+ /*
+ * If the SERVICE ACTION RESERVATION KEY field identifies a
+ * persistent reservation holder (see 5.7.10), the device
+ * server shall perform a preempt by doing the following as
+ * an uninterrupted series of actions:
+ *
+ * a) Release the persistent reservation for the holder
+ * identified by the SERVICE ACTION RESERVATION KEY field;
+ */
+ if (pr_reg_n != pr_res_holder)
+ __core_scsi3_complete_pro_release(dev,
+ pr_res_holder->pr_reg_nacl,
+ dev->dev_pr_res_holder, 0);
+ /*
+ * b) Remove the registrations for all I_T nexuses identified
+ * by the SERVICE ACTION RESERVATION KEY field, except the
+ * I_T nexus that is being used for the PERSISTENT RESERVE
+ * OUT command. If an all registrants persistent reservation
+ * is present and the SERVICE ACTION RESERVATION KEY field
+ * is set to zero, then all registrations shall be removed
+ * except for that of the I_T nexus that is being used for
+ * the PERSISTENT RESERVE OUT command;
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ if (pr_reg->pr_res_key != sa_res_key)
+ continue;
+
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list : NULL,
+ calling_it_nexus);
+ /*
+ * e) Establish a unit attention condition for the initiator
+ * port associated with every I_T nexus that lost its
+ * persistent reservation and/or registration, with the
+ * additional sense code set to REGISTRATIONS PREEMPTED;
+ */
+ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * c) Establish a persistent reservation for the preempting
+ * I_T nexus using the contents of the SCOPE and TYPE fields;
+ */
+ __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
+ (abort) ? &preempt_and_abort_list : NULL,
+ type, scope, abort);
+ /*
+ * d) Process tasks as defined in 5.7.1;
+ * e) See above..
+ * f) If the type or scope has changed, then for every I_T nexus
+ * whose reservation key was not removed, except for the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command was
+ * received, the device server shall establish a unit
+ * attention condition for the initiator port associated with
+ * that I_T nexus, with the additional sense code set to
+ * RESERVATIONS RELEASED. If the type or scope have not
+ * changed, then no unit attention condition(s) shall be
+ * established for this reason.
+ */
+ if ((prh_type != type) || (prh_scope != scope)) {
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ core_scsi3_ua_allocate(pr_reg->pr_reg_nacl,
+ pr_reg->pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * Call LUN_RESET logic upon list of struct t10_pr_registration,
+ * All received CDBs for the matching existing reservation and
+ * registrations undergo ABORT_TASK logic.
+ *
+ * From there, core_scsi3_release_preempt_and_abort() will
+ * release every registration in the list (which have already
+ * been removed from the primary pr_reg list), except the
+ * new persistent reservation holder, the calling Initiator Port.
+ */
+ if (abort) {
+ core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd);
+ core_scsi3_release_preempt_and_abort(&preempt_and_abort_list,
+ pr_reg_n);
+ }
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg_n->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Updated APTPL metadata for PREEMPT"
+ "%s\n", (abort) ? "_AND_ABORT" : "");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg_n);
+ core_scsi3_pr_generation(SE_DEV(cmd));
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_preempt(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key,
+ int abort)
+{
+ int ret = 0;
+
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ ret = core_scsi3_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, abort);
+ break;
+ default:
+ printk(KERN_ERR "SPC-3 PR: Unknown Service Action PREEMPT%s"
+ " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return ret;
+}
+
+
+static int core_scsi3_emulate_pro_register_and_move(
+ struct se_cmd *cmd,
+ u64 res_key,
+ u64 sa_res_key,
+ int aptpl,
+ int unreg)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve, *dest_se_deve = NULL;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
+ struct se_port *se_port;
+ struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
+ struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
+ struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *initiator_str;
+ char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
+ u32 tid_len, tmp_tid_len;
+ int new_reg = 0, type, scope, ret, matching_iname, prf_isid;
+ unsigned short rtpi;
+ unsigned char proto_ident;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ memset(dest_iport, 0, 64);
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ se_tpg = se_sess->se_tpg;
+ tf_ops = TPG_TFO(se_tpg);
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Follow logic from spc4r17 Section 5.7.8, Table 50 --
+ * Register behaviors for a REGISTER AND MOVE service action
+ *
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate PR_REGISTERED"
+ " *pr_reg for REGISTER_AND_MOVE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * The provided reservation key much match the existing reservation key
+ * provided during this initiator's I_T nexus registration.
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received"
+ " res_key: 0x%016Lx does not match existing SA REGISTER"
+ " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * The service active reservation key needs to be non zero
+ */
+ if (!(sa_res_key)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received zero"
+ " sa_res_key\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * Determine the Relative Target Port Identifier where the reservation
+ * will be moved to for the TransportID containing SCSI initiator WWN
+ * information.
+ */
+ rtpi = (buf[18] & 0xff) << 8;
+ rtpi |= buf[19] & 0xff;
+ tid_len = (buf[20] & 0xff) << 24;
+ tid_len |= (buf[21] & 0xff) << 16;
+ tid_len |= (buf[22] & 0xff) << 8;
+ tid_len |= buf[23] & 0xff;
+
+ if ((tid_len + 24) != cmd->data_length) {
+ printk(KERN_ERR "SPC-3 PR: Illegal tid_len: %u + 24 byte header"
+ " does not equal CDB data_length: %u\n", tid_len,
+ cmd->data_length);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) {
+ if (se_port->sep_rtpi != rtpi)
+ continue;
+ dest_se_tpg = se_port->sep_tpg;
+ if (!(dest_se_tpg))
+ continue;
+ dest_tf_ops = TPG_TFO(dest_se_tpg);
+ if (!(dest_tf_ops))
+ continue;
+
+ atomic_inc(&dest_se_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ ret = core_scsi3_tpg_depend_item(dest_se_tpg);
+ if (ret != 0) {
+ printk(KERN_ERR "core_scsi3_tpg_depend_item() failed"
+ " for dest_se_tpg\n");
+ atomic_dec(&dest_se_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ if (!(dest_se_tpg) || (!dest_tf_ops)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate"
+ " fabric ops from Relative Target Port Identifier:"
+ " %hu\n", rtpi);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ proto_ident = (buf[24] & 0x0f);
+#if 0
+ printk("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:"
+ " 0x%02x\n", proto_ident);
+#endif
+ if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Received"
+ " proto_ident: 0x%02x does not match ident: 0x%02x"
+ " from fabric: %s\n", proto_ident,
+ dest_tf_ops->get_fabric_proto_ident(dest_se_tpg),
+ dest_tf_ops->get_fabric_name());
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Fabric does not"
+ " containg a valid tpg_parse_pr_out_transport_id"
+ " function pointer\n");
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg,
+ (const char *)&buf[24], &tmp_tid_len, &iport_ptr);
+ if (!(initiator_str)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate"
+ " initiator_str from Transport ID\n");
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ printk(KERN_INFO "SPC-3 PR [%s] Extracted initiator %s identifier: %s"
+ " %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ?
+ "port" : "device", initiator_str, (iport_ptr != NULL) ?
+ iport_ptr : "");
+ /*
+ * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service
+ * action specifies a TransportID that is the same as the initiator port
+ * of the I_T nexus for the command received, then the command shall
+ * be terminated with CHECK CONDITION status, with the sense key set to
+ * ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD
+ * IN PARAMETER LIST.
+ */
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ matching_iname = (!strcmp(initiator_str,
+ pr_reg_nacl->initiatorname)) ? 1 : 0;
+ if (!(matching_iname))
+ goto after_iport_check;
+
+ if (!(iport_ptr) || !(pr_reg->isid_present_at_reg)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s"
+ " matches: %s on received I_T Nexus\n", initiator_str,
+ pr_reg_nacl->initiatorname);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ if (!(strcmp(iport_ptr, pr_reg->pr_reg_isid))) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s %s"
+ " matches: %s %s on received I_T Nexus\n",
+ initiator_str, iport_ptr, pr_reg_nacl->initiatorname,
+ pr_reg->pr_reg_isid);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+after_iport_check:
+ /*
+ * Locate the destination struct se_node_acl from the received Transport ID
+ */
+ spin_lock_bh(&dest_se_tpg->acl_node_lock);
+ dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg,
+ initiator_str);
+ if (dest_node_acl) {
+ atomic_inc(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ }
+ spin_unlock_bh(&dest_se_tpg->acl_node_lock);
+
+ if (!(dest_node_acl)) {
+ printk(KERN_ERR "Unable to locate %s dest_node_acl for"
+ " TransportID%s\n", dest_tf_ops->get_fabric_name(),
+ initiator_str);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ ret = core_scsi3_nodeacl_depend_item(dest_node_acl);
+ if (ret != 0) {
+ printk(KERN_ERR "core_scsi3_nodeacl_depend_item() for"
+ " dest_node_acl\n");
+ atomic_dec(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ dest_node_acl = NULL;
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:"
+ " %s from TransportID\n", dest_tf_ops->get_fabric_name(),
+ dest_node_acl->initiatorname);
+#endif
+ /*
+ * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET
+ * PORT IDENTIFIER.
+ */
+ dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, rtpi);
+ if (!(dest_se_deve)) {
+ printk(KERN_ERR "Unable to locate %s dest_se_deve from RTPI:"
+ " %hu\n", dest_tf_ops->get_fabric_name(), rtpi);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ ret = core_scsi3_lunacl_depend_item(dest_se_deve);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend_item() failed\n");
+ atomic_dec(&dest_se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ dest_se_deve = NULL;
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN"
+ " ACL for dest_se_deve->mapped_lun: %u\n",
+ dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname,
+ dest_se_deve->mapped_lun);
+#endif
+ /*
+ * A persistent reservation needs to already existing in order to
+ * successfully complete the REGISTER_AND_MOVE service action..
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: No reservation"
+ " currently held\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_INVALID_CDB_FIELD;
+ goto out;
+ }
+ /*
+ * The received on I_T Nexus must be the reservation holder.
+ *
+ * From spc4r17 section 5.7.8 Table 50 --
+ * Register behaviors for a REGISTER AND MOVE service action
+ */
+ if (pr_res_holder != pr_reg) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
+ " Nexus is not reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out;
+ }
+ /*
+ * From spc4r17 section 5.7.8: registering and moving reservation
+ *
+ * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service
+ * action is received and the established persistent reservation is a
+ * Write Exclusive - All Registrants type or Exclusive Access -
+ * All Registrants type reservation, then the command shall be completed
+ * with RESERVATION CONFLICT status.
+ */
+ if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Unable to move"
+ " reservation for type: %s\n",
+ core_scsi3_pr_dump_type(pr_res_holder->pr_res_type));
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out;
+ }
+ pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ /*
+ * b) Ignore the contents of the (received) SCOPE and TYPE fields;
+ */
+ type = pr_res_holder->pr_res_type;
+ scope = pr_res_holder->pr_res_type;
+ /*
+ * c) Associate the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field with the I_T nexus specified as the
+ * destination of the register and move, where:
+ * A) The I_T nexus is specified by the TransportID and the
+ * RELATIVE TARGET PORT IDENTIFIER field (see 6.14.4); and
+ * B) Regardless of the TransportID format used, the association for
+ * the initiator port is based on either the initiator port name
+ * (see 3.1.71) on SCSI transport protocols where port names are
+ * required or the initiator port identifier (see 3.1.70) on SCSI
+ * transport protocols where port names are not required;
+ * d) Register the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field;
+ * e) Retain the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field and associated information;
+ *
+ * Also, It is not an error for a REGISTER AND MOVE service action to
+ * register an I_T nexus that is already registered with the same
+ * reservation key or a different reservation key.
+ */
+ dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ if (!(dest_pr_reg)) {
+ ret = core_scsi3_alloc_registration(SE_DEV(cmd),
+ dest_node_acl, dest_se_deve, iport_ptr,
+ sa_res_key, 0, aptpl, 2, 1);
+ if (ret != 0) {
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ new_reg = 1;
+ }
+ /*
+ * f) Release the persistent reservation for the persistent reservation
+ * holder (i.e., the I_T nexus on which the
+ */
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ dev->dev_pr_res_holder, 0);
+ /*
+ * g) Move the persistent reservation to the specified I_T nexus using
+ * the same scope and type as the persistent reservation released in
+ * item f); and
+ */
+ dev->dev_pr_res_holder = dest_pr_reg;
+ dest_pr_reg->pr_res_holder = 1;
+ dest_pr_reg->pr_res_type = type;
+ pr_reg->pr_res_scope = scope;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Increment PRGeneration for existing registrations..
+ */
+ if (!(new_reg))
+ dest_pr_reg->pr_res_generation = pr_tmpl->pr_generation++;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER_AND_MOVE"
+ " created new reservation holder TYPE: %s on object RTPI:"
+ " %hu PRGeneration: 0x%08x\n", dest_tf_ops->get_fabric_name(),
+ core_scsi3_pr_dump_type(type), rtpi,
+ dest_pr_reg->pr_res_generation);
+ printk(KERN_INFO "SPC-3 PR Successfully moved reservation from"
+ " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n",
+ tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(),
+ dest_node_acl->initiatorname, (iport_ptr != NULL) ?
+ iport_ptr : "");
+ /*
+ * It is now safe to release configfs group dependencies for destination
+ * of Transport ID Initiator Device/Port Identifier
+ */
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_se_tpg);
+ /*
+ * h) If the UNREG bit is set to one, unregister (see 5.7.11.3) the I_T
+ * nexus on which PERSISTENT RESERVE OUT command was received.
+ */
+ if (unreg) {
+ spin_lock(&pr_tmpl->registration_lock);
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 1);
+ spin_unlock(&pr_tmpl->registration_lock);
+ } else
+ core_scsi3_put_pr_reg(pr_reg);
+
+ /*
+ * Clear the APTPL metadata if APTPL has been disabled, otherwise
+ * write out the updated metadata to struct file for this SCSI device.
+ */
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated for"
+ " REGISTER_AND_MOVE\n");
+ } else {
+ pr_tmpl->pr_aptpl_active = 1;
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &dest_pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Set APTPL Bit Activated for"
+ " REGISTER_AND_MOVE\n");
+ }
+
+ core_scsi3_put_pr_reg(dest_pr_reg);
+ return 0;
+out:
+ if (dest_se_deve)
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ if (dest_node_acl)
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_se_tpg);
+ core_scsi3_put_pr_reg(pr_reg);
+ return ret;
+}
+
+static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3];
+ __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * See spc4r17 section 6.14 Table 170
+ */
+static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
+{
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u64 res_key, sa_res_key;
+ int sa, scope, type, aptpl;
+ int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
+ /*
+ * FIXME: A NULL struct se_session pointer means an this is not coming from
+ * a $FABRIC_MOD's nexus, but from internal passthrough ops.
+ */
+ if (!(SE_SESS(cmd)))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (cmd->data_length < 24) {
+ printk(KERN_WARNING "SPC-PR: Recieved PR OUT parameter list"
+ " length too small: %u\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB)
+ */
+ sa = (cdb[1] & 0x1f);
+ scope = (cdb[2] & 0xf0);
+ type = (cdb[2] & 0x0f);
+ /*
+ * From PERSISTENT_RESERVE_OUT parameter list (payload)
+ */
+ res_key = core_scsi3_extract_reservation_key(&buf[0]);
+ sa_res_key = core_scsi3_extract_reservation_key(&buf[8]);
+ /*
+ * REGISTER_AND_MOVE uses a different SA parameter list containing
+ * SCSI TransportIDs.
+ */
+ if (sa != PRO_REGISTER_AND_MOVE) {
+ spec_i_pt = (buf[20] & 0x08);
+ all_tg_pt = (buf[20] & 0x04);
+ aptpl = (buf[20] & 0x01);
+ } else {
+ aptpl = (buf[17] & 0x01);
+ unreg = (buf[17] & 0x02);
+ }
+ /*
+ * SPEC_I_PT=1 is only valid for Service action: REGISTER
+ */
+ if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER))
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ /*
+ * From spc4r17 section 6.14:
+ *
+ * If the SPEC_I_PT bit is set to zero, the service action is not
+ * REGISTER AND MOVE, and the parameter list length is not 24, then
+ * the command shall be terminated with CHECK CONDITION status, with
+ * the sense key set to ILLEGAL REQUEST, and the additional sense
+ * code set to PARAMETER LIST LENGTH ERROR.
+ */
+ if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) &&
+ (cmd->data_length != 24)) {
+ printk(KERN_WARNING "SPC-PR: Recieved PR OUT illegal parameter"
+ " list length: %u\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * (core_scsi3_emulate_pro_* function parameters
+ * are defined by spc4r17 Table 174:
+ * PERSISTENT_RESERVE_OUT service actions and valid parameters.
+ */
+ switch (sa) {
+ case PRO_REGISTER:
+ return core_scsi3_emulate_pro_register(cmd,
+ res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0);
+ case PRO_RESERVE:
+ return core_scsi3_emulate_pro_reserve(cmd,
+ type, scope, res_key);
+ case PRO_RELEASE:
+ return core_scsi3_emulate_pro_release(cmd,
+ type, scope, res_key);
+ case PRO_CLEAR:
+ return core_scsi3_emulate_pro_clear(cmd, res_key);
+ case PRO_PREEMPT:
+ return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, 0);
+ case PRO_PREEMPT_AND_ABORT:
+ return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, 1);
+ case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
+ return core_scsi3_emulate_pro_register(cmd,
+ 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1);
+ case PRO_REGISTER_AND_MOVE:
+ return core_scsi3_emulate_pro_register_and_move(cmd, res_key,
+ sa_res_key, aptpl, unreg);
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_KEYS
+ *
+ * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160
+ */
+static int core_scsi3_pri_read_keys(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_len = 0, off = 8;
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_KEYS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+ /*
+ * Check for overflow of 8byte PRI READ_KEYS payload and
+ * next reservation key list descriptor.
+ */
+ if ((add_len + 8) > (cmd->data_length - 8))
+ break;
+
+ buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
+ buf[off++] = (pr_reg->pr_res_key & 0xff);
+
+ add_len += 8;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION
+ *
+ * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162
+ */
+static int core_scsi3_pri_read_reservation(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u64 pr_res_key;
+ u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_RESERVATIONS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&se_dev->dev_reservation_lock);
+ pr_reg = se_dev->dev_pr_res_holder;
+ if ((pr_reg)) {
+ /*
+ * Set the hardcoded Additional Length
+ */
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ if (cmd->data_length < 22) {
+ spin_unlock(&se_dev->dev_reservation_lock);
+ return 0;
+ }
+ /*
+ * Set the Reservation key.
+ *
+ * From spc4r17, section 5.7.10:
+ * A persistent reservation holder has its reservation key
+ * returned in the parameter data from a PERSISTENT
+ * RESERVE IN command with READ RESERVATION service action as
+ * follows:
+ * a) For a persistent reservation of the type Write Exclusive
+ * - All Registrants or Exclusive Access ­ All Regitrants,
+ * the reservation key shall be set to zero; or
+ * b) For all other persistent reservation types, the
+ * reservation key shall be set to the registered
+ * reservation key for the I_T nexus that holds the
+ * persistent reservation.
+ */
+ if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
+ pr_res_key = 0;
+ else
+ pr_res_key = pr_reg->pr_res_key;
+
+ buf[8] = ((pr_res_key >> 56) & 0xff);
+ buf[9] = ((pr_res_key >> 48) & 0xff);
+ buf[10] = ((pr_res_key >> 40) & 0xff);
+ buf[11] = ((pr_res_key >> 32) & 0xff);
+ buf[12] = ((pr_res_key >> 24) & 0xff);
+ buf[13] = ((pr_res_key >> 16) & 0xff);
+ buf[14] = ((pr_res_key >> 8) & 0xff);
+ buf[15] = (pr_res_key & 0xff);
+ /*
+ * Set the SCOPE and TYPE
+ */
+ buf[21] = (pr_reg->pr_res_scope & 0xf0) |
+ (pr_reg->pr_res_type & 0x0f);
+ }
+ spin_unlock(&se_dev->dev_reservation_lock);
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action REPORT_CAPABILITIES
+ *
+ * See spc4r17 section 6.13.4 Table 165
+ */
+static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u16 add_len = 8; /* Hardcoded to 8. */
+
+ if (cmd->data_length < 6) {
+ printk(KERN_ERR "PRIN SA REPORT_CAPABILITIES SCSI Data Length:"
+ " %u too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((add_len << 8) & 0xff);
+ buf[1] = (add_len & 0xff);
+ buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
+ buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */
+ buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */
+ buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */
+ /*
+ * We are filling in the PERSISTENT RESERVATION TYPE MASK below, so
+ * set the TMV: Task Mask Valid bit.
+ */
+ buf[3] |= 0x80;
+ /*
+ * Change ALLOW COMMANDs to 0x20 or 0x40 later from Table 166
+ */
+ buf[3] |= 0x10; /* ALLOW COMMANDs field 001b */
+ /*
+ * PTPL_A: Persistence across Target Power Loss Active bit
+ */
+ if (pr_tmpl->pr_aptpl_active)
+ buf[3] |= 0x01;
+ /*
+ * Setup the PERSISTENT RESERVATION TYPE MASK from Table 167
+ */
+ buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
+ buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */
+ buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */
+ buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */
+ buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */
+ buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS
+ *
+ * See spc4r17 section 6.13.5 Table 168 and 169
+ */
+static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_node_acl *se_nacl;
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(se_dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
+ u32 off = 8; /* off into first Full Status descriptor */
+ int format_code = 0;
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_FULL_STATUS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ se_nacl = pr_reg->pr_reg_nacl;
+ se_tpg = pr_reg->pr_reg_nacl->se_tpg;
+ add_desc_len = 0;
+
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Determine expected length of $FABRIC_MOD specific
+ * TransportID full status descriptor..
+ */
+ exp_desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id_len(
+ se_tpg, se_nacl, pr_reg, &format_code);
+
+ if ((exp_desc_len + add_len) > cmd->data_length) {
+ printk(KERN_WARNING "SPC-3 PRIN READ_FULL_STATUS ran"
+ " out of buffer: %d\n", cmd->data_length);
+ spin_lock(&pr_tmpl->registration_lock);
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+ break;
+ }
+ /*
+ * Set RESERVATION KEY
+ */
+ buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
+ buf[off++] = (pr_reg->pr_res_key & 0xff);
+ off += 4; /* Skip Over Reserved area */
+
+ /*
+ * Set ALL_TG_PT bit if PROUT SA REGISTER had this set.
+ */
+ if (pr_reg->pr_reg_all_tg_pt)
+ buf[off] = 0x02;
+ /*
+ * The struct se_lun pointer will be present for the
+ * reservation holder for PR_HOLDER bit.
+ *
+ * Also, if this registration is the reservation
+ * holder, fill in SCOPE and TYPE in the next byte.
+ */
+ if (pr_reg->pr_res_holder) {
+ buf[off++] |= 0x01;
+ buf[off++] = (pr_reg->pr_res_scope & 0xf0) |
+ (pr_reg->pr_res_type & 0x0f);
+ } else
+ off += 2;
+
+ off += 4; /* Skip over reserved area */
+ /*
+ * From spc4r17 6.3.15:
+ *
+ * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT
+ * IDENTIFIER field contains the relative port identifier (see
+ * 3.1.120) of the target port that is part of the I_T nexus
+ * described by this full status descriptor. If the ALL_TG_PT
+ * bit is set to one, the contents of the RELATIVE TARGET PORT
+ * IDENTIFIER field are not defined by this standard.
+ */
+ if (!(pr_reg->pr_reg_all_tg_pt)) {
+ struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep;
+
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ } else
+ off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */
+
+ /*
+ * Now, have the $FABRIC_MOD fill in the protocol identifier
+ */
+ desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id(se_tpg,
+ se_nacl, pr_reg, &format_code, &buf[off+4]);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+ /*
+ * Set the ADDITIONAL DESCRIPTOR LENGTH
+ */
+ buf[off++] = ((desc_len >> 24) & 0xff);
+ buf[off++] = ((desc_len >> 16) & 0xff);
+ buf[off++] = ((desc_len >> 8) & 0xff);
+ buf[off++] = (desc_len & 0xff);
+ /*
+ * Size of full desctipor header minus TransportID
+ * containing $FABRIC_MOD specific) initiator device/port
+ * WWN information.
+ *
+ * See spc4r17 Section 6.13.5 Table 169
+ */
+ add_desc_len = (24 + desc_len);
+
+ off += desc_len;
+ add_len += add_desc_len;
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Set ADDITIONAL_LENGTH
+ */
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ return 0;
+}
+
+static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb)
+{
+ switch (cdb[1] & 0x1f) {
+ case PRI_READ_KEYS:
+ return core_scsi3_pri_read_keys(cmd);
+ case PRI_READ_RESERVATION:
+ return core_scsi3_pri_read_reservation(cmd);
+ case PRI_REPORT_CAPABILITIES:
+ return core_scsi3_pri_report_capabilities(cmd);
+ case PRI_READ_FULL_STATUS:
+ return core_scsi3_pri_read_full_status(cmd);
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_IN service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+}
+
+int core_scsi3_emulate_pr(struct se_cmd *cmd)
+{
+ unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+ struct se_device *dev = cmd->se_dev;
+ /*
+ * Following spc2r20 5.5.1 Reservations overview:
+ *
+ * If a logical unit has been reserved by any RESERVE command and is
+ * still reserved by any initiator, all PERSISTENT RESERVE IN and all
+ * PERSISTENT RESERVE OUT commands shall conflict regardless of
+ * initiator or service action and shall terminate with a RESERVATION
+ * CONFLICT status.
+ */
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS) {
+ printk(KERN_ERR "Received PERSISTENT_RESERVE CDB while legacy"
+ " SPC-2 reservation is held, returning"
+ " RESERVATION_CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ return (cdb[0] == PERSISTENT_RESERVE_OUT) ?
+ core_scsi3_emulate_pr_out(cmd, cdb) :
+ core_scsi3_emulate_pr_in(cmd, cdb);
+}
+
+static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type)
+{
+ return 0;
+}
+
+static int core_pt_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ return 0;
+}
+
+int core_setup_reservations(struct se_device *dev, int force_pt)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_reservation_template *rest = &su_dev->t10_reservation;
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, use the reservations
+ * of the Underlying SCSI hardware. In Linux/SCSI terms, this can
+ * cause a problem because libata and some SATA RAID HBAs appear
+ * under Linux/SCSI, but to emulate reservations themselves.
+ */
+ if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ !(DEV_ATTRIB(dev)->emulate_reservations)) || force_pt) {
+ rest->res_type = SPC_PASSTHROUGH;
+ rest->pr_ops.t10_reservation_check = &core_pt_reservation_check;
+ rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC_PASSTHROUGH, no reservation"
+ " emulation\n", TRANSPORT(dev)->name);
+ return 0;
+ }
+ /*
+ * If SPC-3 or above is reported by real or emulated struct se_device,
+ * use emulated Persistent Reservations.
+ */
+ if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
+ rest->res_type = SPC3_PERSISTENT_RESERVATIONS;
+ rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check;
+ rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC3_PERSISTENT_RESERVATIONS"
+ " emulation\n", TRANSPORT(dev)->name);
+ } else {
+ rest->res_type = SPC2_RESERVATIONS;
+ rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check;
+ rest->pr_ops.t10_seq_non_holder =
+ &core_scsi2_reservation_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC2_RESERVATIONS emulation\n",
+ TRANSPORT(dev)->name);
+ }
+
+ return 0;
+}
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
new file mode 100644
index 000000000000..5603bcfd86d3
--- /dev/null
+++ b/drivers/target/target_core_pr.h
@@ -0,0 +1,67 @@
+#ifndef TARGET_CORE_PR_H
+#define TARGET_CORE_PR_H
+/*
+ * PERSISTENT_RESERVE_OUT service action codes
+ *
+ * spc4r17 section 6.14.2 Table 171
+ */
+#define PRO_REGISTER 0x00
+#define PRO_RESERVE 0x01
+#define PRO_RELEASE 0x02
+#define PRO_CLEAR 0x03
+#define PRO_PREEMPT 0x04
+#define PRO_PREEMPT_AND_ABORT 0x05
+#define PRO_REGISTER_AND_IGNORE_EXISTING_KEY 0x06
+#define PRO_REGISTER_AND_MOVE 0x07
+/*
+ * PERSISTENT_RESERVE_IN service action codes
+ *
+ * spc4r17 section 6.13.1 Table 159
+ */
+#define PRI_READ_KEYS 0x00
+#define PRI_READ_RESERVATION 0x01
+#define PRI_REPORT_CAPABILITIES 0x02
+#define PRI_READ_FULL_STATUS 0x03
+/*
+ * PERSISTENT_RESERVE_ SCOPE field
+ *
+ * spc4r17 section 6.13.3.3 Table 163
+ */
+#define PR_SCOPE_LU_SCOPE 0x00
+/*
+ * PERSISTENT_RESERVE_* TYPE field
+ *
+ * spc4r17 section 6.13.3.4 Table 164
+ */
+#define PR_TYPE_WRITE_EXCLUSIVE 0x01
+#define PR_TYPE_EXCLUSIVE_ACCESS 0x03
+#define PR_TYPE_WRITE_EXCLUSIVE_REGONLY 0x05
+#define PR_TYPE_EXCLUSIVE_ACCESS_REGONLY 0x06
+#define PR_TYPE_WRITE_EXCLUSIVE_ALLREG 0x07
+#define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG 0x08
+
+#define PR_APTPL_MAX_IPORT_LEN 256
+#define PR_APTPL_MAX_TPORT_LEN 256
+
+extern struct kmem_cache *t10_pr_reg_cache;
+
+extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
+ char *, u32);
+extern int core_scsi2_emulate_crh(struct se_cmd *);
+extern int core_scsi3_alloc_aptpl_registration(
+ struct t10_reservation_template *, u64,
+ unsigned char *, unsigned char *, u32,
+ unsigned char *, u16, u32, int, int, u8);
+extern int core_scsi3_check_aptpl_registration(struct se_device *,
+ struct se_portal_group *, struct se_lun *,
+ struct se_lun_acl *);
+extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,
+ struct se_node_acl *);
+extern void core_scsi3_free_all_registrations(struct se_device *);
+extern unsigned char *core_scsi3_pr_dump_type(int);
+extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *,
+ struct se_cmd *);
+extern int core_scsi3_emulate_pr(struct se_cmd *);
+extern int core_setup_reservations(struct se_device *, int);
+
+#endif /* TARGET_CORE_PR_H */
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
new file mode 100644
index 000000000000..742d24609a9b
--- /dev/null
+++ b/drivers/target/target_core_pscsi.c
@@ -0,0 +1,1470 @@
+/*******************************************************************************
+ * Filename: target_core_pscsi.c
+ *
+ * This file contains the generic target mode <-> Linux SCSI subsystem plugin.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/blk_types.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/genhd.h>
+#include <linux/cdrom.h>
+#include <linux/file.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/libsas.h> /* For TASK_ATTR_* */
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_pscsi.h"
+
+#define ISPRINT(a) ((a >= ' ') && (a <= '~'))
+
+static struct se_subsystem_api pscsi_template;
+
+static void pscsi_req_done(struct request *, int);
+
+/* pscsi_get_sh():
+ *
+ *
+ */
+static struct Scsi_Host *pscsi_get_sh(u32 host_no)
+{
+ struct Scsi_Host *sh = NULL;
+
+ sh = scsi_host_lookup(host_no);
+ if (IS_ERR(sh)) {
+ printk(KERN_ERR "Unable to locate SCSI HBA with Host ID:"
+ " %u\n", host_no);
+ return NULL;
+ }
+
+ return sh;
+}
+
+/* pscsi_attach_hba():
+ *
+ * pscsi_get_sh() used scsi_host_lookup() to locate struct Scsi_Host.
+ * from the passed SCSI Host ID.
+ */
+static int pscsi_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ int hba_depth;
+ struct pscsi_hba_virt *phv;
+
+ phv = kzalloc(sizeof(struct pscsi_hba_virt), GFP_KERNEL);
+ if (!(phv)) {
+ printk(KERN_ERR "Unable to allocate struct pscsi_hba_virt\n");
+ return -1;
+ }
+ phv->phv_host_id = host_id;
+ phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+ hba_depth = PSCSI_VIRTUAL_HBA_DEPTH;
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ hba->hba_ptr = (void *)phv;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM SCSI HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ PSCSI_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached SCSI HBA to Generic"
+ " Target Core with TCQ Depth: %d\n", hba->hba_id,
+ atomic_read(&hba->max_queue_depth));
+
+ return 0;
+}
+
+static void pscsi_detach_hba(struct se_hba *hba)
+{
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ struct Scsi_Host *scsi_host = phv->phv_lld_host;
+
+ if (scsi_host) {
+ scsi_host_put(scsi_host);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached SCSI HBA: %s from"
+ " Generic Target Core\n", hba->hba_id,
+ (scsi_host->hostt->name) ? (scsi_host->hostt->name) :
+ "Unknown");
+ } else
+ printk(KERN_INFO "CORE_HBA[%d] - Detached Virtual SCSI HBA"
+ " from Generic Target Core\n", hba->hba_id);
+
+ kfree(phv);
+ hba->hba_ptr = NULL;
+}
+
+static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag)
+{
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+ struct Scsi_Host *sh = phv->phv_lld_host;
+ int hba_depth = PSCSI_VIRTUAL_HBA_DEPTH;
+ /*
+ * Release the struct Scsi_Host
+ */
+ if (!(mode_flag)) {
+ if (!(sh))
+ return 0;
+
+ phv->phv_lld_host = NULL;
+ phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Disabled pSCSI HBA Passthrough"
+ " %s\n", hba->hba_id, (sh->hostt->name) ?
+ (sh->hostt->name) : "Unknown");
+
+ scsi_host_put(sh);
+ return 0;
+ }
+ /*
+ * Otherwise, locate struct Scsi_Host from the original passed
+ * pSCSI Host ID and enable for phba mode
+ */
+ sh = pscsi_get_sh(phv->phv_host_id);
+ if (!(sh)) {
+ printk(KERN_ERR "pSCSI: Unable to locate SCSI Host for"
+ " phv_host_id: %d\n", phv->phv_host_id);
+ return -1;
+ }
+ /*
+ * Usually the SCSI LLD will use the hostt->can_queue value to define
+ * its HBA TCQ depth. Some other drivers (like 2.6 megaraid) don't set
+ * this at all and set sh->can_queue at runtime.
+ */
+ hba_depth = (sh->hostt->can_queue > sh->can_queue) ?
+ sh->hostt->can_queue : sh->can_queue;
+
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ phv->phv_lld_host = sh;
+ phv->phv_mode = PHV_LLD_SCSI_HOST_NO;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Enabled pSCSI HBA Passthrough %s\n",
+ hba->hba_id, (sh->hostt->name) ? (sh->hostt->name) : "Unknown");
+
+ return 1;
+}
+
+static void pscsi_tape_read_blocksize(struct se_device *dev,
+ struct scsi_device *sdev)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf;
+ int ret;
+
+ buf = kzalloc(12, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = MODE_SENSE;
+ cdb[4] = 0x0c; /* 12 bytes */
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, 12, NULL,
+ HZ, 1, NULL);
+ if (ret)
+ goto out_free;
+
+ /*
+ * If MODE_SENSE still returns zero, set the default value to 1024.
+ */
+ sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]);
+ if (!sdev->sector_size)
+ sdev->sector_size = 1024;
+out_free:
+ kfree(buf);
+}
+
+static void
+pscsi_set_inquiry_info(struct scsi_device *sdev, struct t10_wwn *wwn)
+{
+ unsigned char *buf;
+
+ if (sdev->inquiry_len < INQUIRY_LEN)
+ return;
+
+ buf = sdev->inquiry;
+ if (!buf)
+ return;
+ /*
+ * Use sdev->inquiry from drivers/scsi/scsi_scan.c:scsi_alloc_sdev()
+ */
+ memcpy(&wwn->vendor[0], &buf[8], sizeof(wwn->vendor));
+ memcpy(&wwn->model[0], &buf[16], sizeof(wwn->model));
+ memcpy(&wwn->revision[0], &buf[32], sizeof(wwn->revision));
+}
+
+static int
+pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf;
+ int ret;
+
+ buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL);
+ if (!buf)
+ return -1;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = INQUIRY;
+ cdb[1] = 0x01; /* Query VPD */
+ cdb[2] = 0x80; /* Unit Serial Number */
+ cdb[3] = (INQUIRY_VPD_SERIAL_LEN >> 8) & 0xff;
+ cdb[4] = (INQUIRY_VPD_SERIAL_LEN & 0xff);
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
+ INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL);
+ if (ret)
+ goto out_free;
+
+ snprintf(&wwn->unit_serial[0], INQUIRY_VPD_SERIAL_LEN, "%s", &buf[4]);
+
+ wwn->t10_sub_dev->su_dev_flags |= SDF_FIRMWARE_VPD_UNIT_SERIAL;
+
+ kfree(buf);
+ return 0;
+
+out_free:
+ kfree(buf);
+ return -1;
+}
+
+static void
+pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
+ struct t10_wwn *wwn)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf, *page_83;
+ int ident_len, page_len, off = 4, ret;
+ struct t10_vpd *vpd;
+
+ buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = INQUIRY;
+ cdb[1] = 0x01; /* Query VPD */
+ cdb[2] = 0x83; /* Device Identifier */
+ cdb[3] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN >> 8) & 0xff;
+ cdb[4] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN & 0xff);
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
+ INQUIRY_VPD_DEVICE_IDENTIFIER_LEN,
+ NULL, HZ, 1, NULL);
+ if (ret)
+ goto out;
+
+ page_len = (buf[2] << 8) | buf[3];
+ while (page_len > 0) {
+ /* Grab a pointer to the Identification descriptor */
+ page_83 = &buf[off];
+ ident_len = page_83[3];
+ if (!ident_len) {
+ printk(KERN_ERR "page_83[3]: identifier"
+ " length zero!\n");
+ break;
+ }
+ printk(KERN_INFO "T10 VPD Identifer Length: %d\n", ident_len);
+
+ vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL);
+ if (!vpd) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct t10_vpd\n");
+ goto out;
+ }
+ INIT_LIST_HEAD(&vpd->vpd_list);
+
+ transport_set_vpd_proto_id(vpd, page_83);
+ transport_set_vpd_assoc(vpd, page_83);
+
+ if (transport_set_vpd_ident_type(vpd, page_83) < 0) {
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ kfree(vpd);
+ continue;
+ }
+ if (transport_set_vpd_ident(vpd, page_83) < 0) {
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ kfree(vpd);
+ continue;
+ }
+
+ list_add_tail(&vpd->vpd_list, &wwn->t10_vpd_list);
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ }
+
+out:
+ kfree(buf);
+}
+
+/* pscsi_add_device_to_list():
+ *
+ *
+ */
+static struct se_device *pscsi_add_device_to_list(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ struct pscsi_dev_virt *pdv,
+ struct scsi_device *sd,
+ int dev_flags)
+{
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct request_queue *q;
+ struct queue_limits *limits;
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ if (!sd->queue_depth) {
+ sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH;
+
+ printk(KERN_ERR "Set broken SCSI Device %d:%d:%d"
+ " queue_depth to %d\n", sd->channel, sd->id,
+ sd->lun, sd->queue_depth);
+ }
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = sd->request_queue;
+ limits = &dev_limits.limits;
+ limits->logical_block_size = sd->sector_size;
+ limits->max_hw_sectors = (sd->host->max_sectors > queue_max_hw_sectors(q)) ?
+ queue_max_hw_sectors(q) : sd->host->max_sectors;
+ limits->max_sectors = (sd->host->max_sectors > queue_max_sectors(q)) ?
+ queue_max_sectors(q) : sd->host->max_sectors;
+ dev_limits.hw_queue_depth = sd->queue_depth;
+ dev_limits.queue_depth = sd->queue_depth;
+ /*
+ * Setup our standard INQUIRY info into se_dev->t10_wwn
+ */
+ pscsi_set_inquiry_info(sd, &se_dev->t10_wwn);
+
+ /*
+ * Set the pointer pdv->pdv_sd to from passed struct scsi_device,
+ * which has already been referenced with Linux SCSI code with
+ * scsi_device_get() in this file's pscsi_create_virtdevice().
+ *
+ * The passthrough operations called by the transport_add_device_*
+ * function below will require this pointer to be set for passthroug
+ * ops.
+ *
+ * For the shutdown case in pscsi_free_device(), this struct
+ * scsi_device reference is released with Linux SCSI code
+ * scsi_device_put() and the pdv->pdv_sd cleared.
+ */
+ pdv->pdv_sd = sd;
+
+ dev = transport_add_device_to_core_hba(hba, &pscsi_template,
+ se_dev, dev_flags, (void *)pdv,
+ &dev_limits, NULL, NULL);
+ if (!(dev)) {
+ pdv->pdv_sd = NULL;
+ return NULL;
+ }
+
+ /*
+ * Locate VPD WWN Information used for various purposes within
+ * the Storage Engine.
+ */
+ if (!pscsi_get_inquiry_vpd_serial(sd, &se_dev->t10_wwn)) {
+ /*
+ * If VPD Unit Serial returned GOOD status, try
+ * VPD Device Identification page (0x83).
+ */
+ pscsi_get_inquiry_vpd_device_ident(sd, &se_dev->t10_wwn);
+ }
+
+ /*
+ * For TYPE_TAPE, attempt to determine blocksize with MODE_SENSE.
+ */
+ if (sd->type == TYPE_TAPE)
+ pscsi_tape_read_blocksize(dev, sd);
+ return dev;
+}
+
+static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct pscsi_dev_virt *pdv;
+
+ pdv = kzalloc(sizeof(struct pscsi_dev_virt), GFP_KERNEL);
+ if (!(pdv)) {
+ printk(KERN_ERR "Unable to allocate memory for struct pscsi_dev_virt\n");
+ return NULL;
+ }
+ pdv->pdv_se_hba = hba;
+
+ printk(KERN_INFO "PSCSI: Allocated pdv: %p for %s\n", pdv, name);
+ return (void *)pdv;
+}
+
+/*
+ * Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_disk(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ struct block_device *bd;
+ u32 dev_flags = 0;
+
+ if (scsi_device_get(sd)) {
+ printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n",
+ sh->host_no, sd->channel, sd->id, sd->lun);
+ spin_unlock_irq(sh->host_lock);
+ return NULL;
+ }
+ spin_unlock_irq(sh->host_lock);
+ /*
+ * Claim exclusive struct block_device access to struct scsi_device
+ * for TYPE_DISK using supplied udev_path
+ */
+ bd = blkdev_get_by_path(se_dev->se_dev_udev_path,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);
+ if (!(bd)) {
+ printk("pSCSI: blkdev_get_by_path() failed\n");
+ scsi_device_put(sd);
+ return NULL;
+ }
+ pdv->pdv_bd = bd;
+
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev)) {
+ blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ scsi_device_put(sd);
+ return NULL;
+ }
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%d\n",
+ phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+/*
+ * Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_rom(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ u32 dev_flags = 0;
+
+ if (scsi_device_get(sd)) {
+ printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n",
+ sh->host_no, sd->channel, sd->id, sd->lun);
+ spin_unlock_irq(sh->host_lock);
+ return NULL;
+ }
+ spin_unlock_irq(sh->host_lock);
+
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev)) {
+ scsi_device_put(sd);
+ return NULL;
+ }
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",
+ phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,
+ sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+/*
+ *Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_other(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ u32 dev_flags = 0;
+
+ spin_unlock_irq(sh->host_lock);
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev))
+ return NULL;
+
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",
+ phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,
+ sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+static struct se_device *pscsi_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ struct pscsi_dev_virt *pdv = (struct pscsi_dev_virt *)p;
+ struct se_device *dev;
+ struct scsi_device *sd;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+ struct Scsi_Host *sh = phv->phv_lld_host;
+ int legacy_mode_enable = 0;
+
+ if (!(pdv)) {
+ printk(KERN_ERR "Unable to locate struct pscsi_dev_virt"
+ " parameter\n");
+ return NULL;
+ }
+ /*
+ * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the
+ * struct Scsi_Host we will need to bring the TCM/pSCSI object online
+ */
+ if (!(sh)) {
+ if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) {
+ printk(KERN_ERR "pSCSI: Unable to locate struct"
+ " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n");
+ return NULL;
+ }
+ /*
+ * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device
+ * reference, we enforce that udev_path has been set
+ */
+ if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) {
+ printk(KERN_ERR "pSCSI: udev_path attribute has not"
+ " been set before ENABLE=1\n");
+ return NULL;
+ }
+ /*
+ * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID,
+ * use the original TCM hba ID to reference Linux/SCSI Host No
+ * and enable for PHV_LLD_SCSI_HOST_NO mode.
+ */
+ if (!(pdv->pdv_flags & PDF_HAS_VIRT_HOST_ID)) {
+ spin_lock(&hba->device_lock);
+ if (!(list_empty(&hba->hba_dev_list))) {
+ printk(KERN_ERR "pSCSI: Unable to set hba_mode"
+ " with active devices\n");
+ spin_unlock(&hba->device_lock);
+ return NULL;
+ }
+ spin_unlock(&hba->device_lock);
+
+ if (pscsi_pmode_enable_hba(hba, 1) != 1)
+ return NULL;
+
+ legacy_mode_enable = 1;
+ hba->hba_flags |= HBA_FLAGS_PSCSI_MODE;
+ sh = phv->phv_lld_host;
+ } else {
+ sh = pscsi_get_sh(pdv->pdv_host_id);
+ if (!(sh)) {
+ printk(KERN_ERR "pSCSI: Unable to locate"
+ " pdv_host_id: %d\n", pdv->pdv_host_id);
+ return NULL;
+ }
+ }
+ } else {
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) {
+ printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while"
+ " struct Scsi_Host exists\n");
+ return NULL;
+ }
+ }
+
+ spin_lock_irq(sh->host_lock);
+ list_for_each_entry(sd, &sh->__devices, siblings) {
+ if ((pdv->pdv_channel_id != sd->channel) ||
+ (pdv->pdv_target_id != sd->id) ||
+ (pdv->pdv_lun_id != sd->lun))
+ continue;
+ /*
+ * Functions will release the held struct scsi_host->host_lock
+ * before calling calling pscsi_add_device_to_list() to register
+ * struct scsi_device with target_core_mod.
+ */
+ switch (sd->type) {
+ case TYPE_DISK:
+ dev = pscsi_create_type_disk(sd, pdv, se_dev, hba);
+ break;
+ case TYPE_ROM:
+ dev = pscsi_create_type_rom(sd, pdv, se_dev, hba);
+ break;
+ default:
+ dev = pscsi_create_type_other(sd, pdv, se_dev, hba);
+ break;
+ }
+
+ if (!(dev)) {
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ scsi_host_put(sh);
+ else if (legacy_mode_enable) {
+ pscsi_pmode_enable_hba(hba, 0);
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+ }
+ pdv->pdv_sd = NULL;
+ return NULL;
+ }
+ return dev;
+ }
+ spin_unlock_irq(sh->host_lock);
+
+ printk(KERN_ERR "pSCSI: Unable to locate %d:%d:%d:%d\n", sh->host_no,
+ pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id);
+
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ scsi_host_put(sh);
+ else if (legacy_mode_enable) {
+ pscsi_pmode_enable_hba(hba, 0);
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+ }
+
+ return NULL;
+}
+
+/* pscsi_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void pscsi_free_device(void *p)
+{
+ struct pscsi_dev_virt *pdv = p;
+ struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ if (sd) {
+ /*
+ * Release exclusive pSCSI internal struct block_device claim for
+ * struct scsi_device with TYPE_DISK from pscsi_create_type_disk()
+ */
+ if ((sd->type == TYPE_DISK) && pdv->pdv_bd) {
+ blkdev_put(pdv->pdv_bd,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ pdv->pdv_bd = NULL;
+ }
+ /*
+ * For HBA mode PHV_LLD_SCSI_HOST_NO, release the reference
+ * to struct Scsi_Host now.
+ */
+ if ((phv->phv_mode == PHV_LLD_SCSI_HOST_NO) &&
+ (phv->phv_lld_host != NULL))
+ scsi_host_put(phv->phv_lld_host);
+
+ if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM))
+ scsi_device_put(sd);
+
+ pdv->pdv_sd = NULL;
+ }
+
+ kfree(pdv);
+}
+
+static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
+{
+ return container_of(task, struct pscsi_plugin_task, pscsi_task);
+}
+
+
+/* pscsi_transport_complete():
+ *
+ *
+ */
+static int pscsi_transport_complete(struct se_task *task)
+{
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+ int result;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ unsigned char *cdb = &pt->pscsi_cdb[0];
+
+ result = pt->pscsi_result;
+ /*
+ * Hack to make sure that Write-Protect modepage is set if R/O mode is
+ * forced.
+ */
+ if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
+ (status_byte(result) << 1) == SAM_STAT_GOOD) {
+ if (!TASK_CMD(task)->se_deve)
+ goto after_mode_sense;
+
+ if (TASK_CMD(task)->se_deve->lun_flags &
+ TRANSPORT_LUNFLAGS_READ_ONLY) {
+ unsigned char *buf = (unsigned char *)
+ T_TASK(task->task_se_cmd)->t_task_buf;
+
+ if (cdb[0] == MODE_SENSE_10) {
+ if (!(buf[3] & 0x80))
+ buf[3] |= 0x80;
+ } else {
+ if (!(buf[2] & 0x80))
+ buf[2] |= 0x80;
+ }
+ }
+ }
+after_mode_sense:
+
+ if (sd->type != TYPE_TAPE)
+ goto after_mode_select;
+
+ /*
+ * Hack to correctly obtain the initiator requested blocksize for
+ * TYPE_TAPE. Since this value is dependent upon each tape media,
+ * struct scsi_device->sector_size will not contain the correct value
+ * by default, so we go ahead and set it so
+ * TRANSPORT(dev)->get_blockdev() returns the correct value to the
+ * storage engine.
+ */
+ if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) &&
+ (status_byte(result) << 1) == SAM_STAT_GOOD) {
+ unsigned char *buf;
+ struct scatterlist *sg = task->task_sg;
+ u16 bdl;
+ u32 blocksize;
+
+ buf = sg_virt(&sg[0]);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to get buf for scatterlist\n");
+ goto after_mode_select;
+ }
+
+ if (cdb[0] == MODE_SELECT)
+ bdl = (buf[3]);
+ else
+ bdl = (buf[6] << 8) | (buf[7]);
+
+ if (!bdl)
+ goto after_mode_select;
+
+ if (cdb[0] == MODE_SELECT)
+ blocksize = (buf[9] << 16) | (buf[10] << 8) |
+ (buf[11]);
+ else
+ blocksize = (buf[13] << 16) | (buf[14] << 8) |
+ (buf[15]);
+
+ sd->sector_size = blocksize;
+ }
+after_mode_select:
+
+ if (status_byte(result) & CHECK_CONDITION)
+ return 1;
+
+ return 0;
+}
+
+static struct se_task *
+pscsi_alloc_task(struct se_cmd *cmd)
+{
+ struct pscsi_plugin_task *pt;
+ unsigned char *cdb = T_TASK(cmd)->t_task_cdb;
+
+ pt = kzalloc(sizeof(struct pscsi_plugin_task), GFP_KERNEL);
+ if (!pt) {
+ printk(KERN_ERR "Unable to allocate struct pscsi_plugin_task\n");
+ return NULL;
+ }
+
+ /*
+ * If TCM Core is signaling a > TCM_MAX_COMMAND_SIZE allocation,
+ * allocate the extended CDB buffer for per struct se_task context
+ * pt->pscsi_cdb now.
+ */
+ if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb) {
+
+ pt->pscsi_cdb = kzalloc(scsi_command_size(cdb), GFP_KERNEL);
+ if (!(pt->pscsi_cdb)) {
+ printk(KERN_ERR "pSCSI: Unable to allocate extended"
+ " pt->pscsi_cdb\n");
+ return NULL;
+ }
+ } else
+ pt->pscsi_cdb = &pt->__pscsi_cdb[0];
+
+ return &pt->pscsi_task;
+}
+
+static inline void pscsi_blk_init_request(
+ struct se_task *task,
+ struct pscsi_plugin_task *pt,
+ struct request *req,
+ int bidi_read)
+{
+ /*
+ * Defined as "scsi command" in include/linux/blkdev.h.
+ */
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ /*
+ * For the extra BIDI-COMMAND READ struct request we do not
+ * need to setup the remaining structure members
+ */
+ if (bidi_read)
+ return;
+ /*
+ * Setup the done function pointer for struct request,
+ * also set the end_io_data pointer.to struct se_task.
+ */
+ req->end_io = pscsi_req_done;
+ req->end_io_data = (void *)task;
+ /*
+ * Load the referenced struct se_task's SCSI CDB into
+ * include/linux/blkdev.h:struct request->cmd
+ */
+ req->cmd_len = scsi_command_size(pt->pscsi_cdb);
+ req->cmd = &pt->pscsi_cdb[0];
+ /*
+ * Setup pointer for outgoing sense data.
+ */
+ req->sense = (void *)&pt->pscsi_sense[0];
+ req->sense_len = 0;
+}
+
+/*
+ * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB
+*/
+static int pscsi_blk_get_request(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+
+ pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue,
+ (task->task_data_direction == DMA_TO_DEVICE),
+ GFP_KERNEL);
+ if (!(pt->pscsi_req) || IS_ERR(pt->pscsi_req)) {
+ printk(KERN_ERR "PSCSI: blk_get_request() failed: %ld\n",
+ IS_ERR(pt->pscsi_req));
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
+ * and setup rq callback, CDB and sense.
+ */
+ pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
+ return 0;
+}
+
+/* pscsi_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int pscsi_do_task(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ /*
+ * Set the struct request->timeout value based on peripheral
+ * device type from SCSI.
+ */
+ if (pdv->pdv_sd->type == TYPE_DISK)
+ pt->pscsi_req->timeout = PS_TIMEOUT_DISK;
+ else
+ pt->pscsi_req->timeout = PS_TIMEOUT_OTHER;
+
+ pt->pscsi_req->retries = PS_RETRY;
+ /*
+ * Queue the struct request into the struct scsi_device->request_queue.
+ * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd
+ * descriptor
+ */
+ blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
+ (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ),
+ pscsi_req_done);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static void pscsi_free_task(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct se_cmd *cmd = task->task_se_cmd;
+
+ /*
+ * Release the extended CDB allocation from pscsi_alloc_task()
+ * if one exists.
+ */
+ if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb)
+ kfree(pt->pscsi_cdb);
+ /*
+ * We do not release the bio(s) here associated with this task, as
+ * this is handled by bio_put() and pscsi_bi_endio().
+ */
+ kfree(pt);
+}
+
+enum {
+ Opt_scsi_host_id, Opt_scsi_channel_id, Opt_scsi_target_id,
+ Opt_scsi_lun_id, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_scsi_host_id, "scsi_host_id=%d"},
+ {Opt_scsi_channel_id, "scsi_channel_id=%d"},
+ {Opt_scsi_target_id, "scsi_target_id=%d"},
+ {Opt_scsi_lun_id, "scsi_lun_id=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page,
+ ssize_t count)
+{
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_scsi_host_id:
+ if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) {
+ printk(KERN_ERR "PSCSI[%d]: Unable to accept"
+ " scsi_host_id while phv_mode =="
+ " PHV_LLD_SCSI_HOST_NO\n",
+ phv->phv_host_id);
+ ret = -EINVAL;
+ goto out;
+ }
+ match_int(args, &arg);
+ pdv->pdv_host_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Host ID:"
+ " %d\n", phv->phv_host_id, pdv->pdv_host_id);
+ pdv->pdv_flags |= PDF_HAS_VIRT_HOST_ID;
+ break;
+ case Opt_scsi_channel_id:
+ match_int(args, &arg);
+ pdv->pdv_channel_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Channel"
+ " ID: %d\n", phv->phv_host_id,
+ pdv->pdv_channel_id);
+ pdv->pdv_flags |= PDF_HAS_CHANNEL_ID;
+ break;
+ case Opt_scsi_target_id:
+ match_int(args, &arg);
+ pdv->pdv_target_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Target"
+ " ID: %d\n", phv->phv_host_id,
+ pdv->pdv_target_id);
+ pdv->pdv_flags |= PDF_HAS_TARGET_ID;
+ break;
+ case Opt_scsi_lun_id:
+ match_int(args, &arg);
+ pdv->pdv_lun_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI LUN ID:"
+ " %d\n", phv->phv_host_id, pdv->pdv_lun_id);
+ pdv->pdv_flags |= PDF_HAS_LUN_ID;
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t pscsi_check_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev)
+{
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+
+ if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) ||
+ !(pdv->pdv_flags & PDF_HAS_TARGET_ID) ||
+ !(pdv->pdv_flags & PDF_HAS_LUN_ID)) {
+ printk(KERN_ERR "Missing scsi_channel_id=, scsi_target_id= and"
+ " scsi_lun_id= parameters\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t pscsi_show_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+ unsigned char host_id[16];
+ ssize_t bl;
+ int i;
+
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ snprintf(host_id, 16, "%d", pdv->pdv_host_id);
+ else
+ snprintf(host_id, 16, "PHBA Mode");
+
+ bl = sprintf(b, "SCSI Device Bus Location:"
+ " Channel ID: %d Target ID: %d LUN: %d Host ID: %s\n",
+ pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id,
+ host_id);
+
+ if (sd) {
+ bl += sprintf(b + bl, " ");
+ bl += sprintf(b + bl, "Vendor: ");
+ for (i = 0; i < 8; i++) {
+ if (ISPRINT(sd->vendor[i])) /* printable character? */
+ bl += sprintf(b + bl, "%c", sd->vendor[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, " Model: ");
+ for (i = 0; i < 16; i++) {
+ if (ISPRINT(sd->model[i])) /* printable character ? */
+ bl += sprintf(b + bl, "%c", sd->model[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, " Rev: ");
+ for (i = 0; i < 4; i++) {
+ if (ISPRINT(sd->rev[i])) /* printable character ? */
+ bl += sprintf(b + bl, "%c", sd->rev[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, "\n");
+ }
+ return bl;
+}
+
+static void pscsi_bi_endio(struct bio *bio, int error)
+{
+ bio_put(bio);
+}
+
+static inline struct bio *pscsi_get_bio(struct pscsi_dev_virt *pdv, int sg_num)
+{
+ struct bio *bio;
+ /*
+ * Use bio_malloc() following the comment in for bio -> struct request
+ * in block/blk-core.c:blk_make_request()
+ */
+ bio = bio_kmalloc(GFP_KERNEL, sg_num);
+ if (!(bio)) {
+ printk(KERN_ERR "PSCSI: bio_kmalloc() failed\n");
+ return NULL;
+ }
+ bio->bi_end_io = pscsi_bi_endio;
+
+ return bio;
+}
+
+#if 0
+#define DEBUG_PSCSI(x...) printk(x)
+#else
+#define DEBUG_PSCSI(x...)
+#endif
+
+static int __pscsi_map_task_SG(
+ struct se_task *task,
+ struct scatterlist *task_sg,
+ u32 task_sg_num,
+ int bidi_read)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct page *page;
+ struct scatterlist *sg;
+ u32 data_len = task->task_size, i, len, bytes, off;
+ int nr_pages = (task->task_size + task_sg[0].offset +
+ PAGE_SIZE - 1) >> PAGE_SHIFT;
+ int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ int rw = (task->task_data_direction == DMA_TO_DEVICE);
+
+ if (!task->task_size)
+ return 0;
+ /*
+ * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
+ * the bio_vec maplist from TC< struct se_mem -> task->task_sg ->
+ * struct scatterlist memory. The struct se_task->task_sg[] currently needs
+ * to be attached to struct bios for submission to Linux/SCSI using
+ * struct request to struct scsi_device->request_queue.
+ *
+ * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI
+ * is ported to upstream SCSI passthrough functionality that accepts
+ * struct scatterlist->page_link or struct page as a paraemeter.
+ */
+ DEBUG_PSCSI("PSCSI: nr_pages: %d\n", nr_pages);
+
+ for_each_sg(task_sg, sg, task_sg_num, i) {
+ page = sg_page(sg);
+ off = sg->offset;
+ len = sg->length;
+
+ DEBUG_PSCSI("PSCSI: i: %d page: %p len: %d off: %d\n", i,
+ page, len, off);
+
+ while (len > 0 && data_len > 0) {
+ bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+ bytes = min(bytes, data_len);
+
+ if (!(bio)) {
+ nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
+ nr_pages -= nr_vecs;
+ /*
+ * Calls bio_kmalloc() and sets bio->bi_end_io()
+ */
+ bio = pscsi_get_bio(pdv, nr_vecs);
+ if (!(bio))
+ goto fail;
+
+ if (rw)
+ bio->bi_rw |= REQ_WRITE;
+
+ DEBUG_PSCSI("PSCSI: Allocated bio: %p,"
+ " dir: %s nr_vecs: %d\n", bio,
+ (rw) ? "rw" : "r", nr_vecs);
+ /*
+ * Set *hbio pointer to handle the case:
+ * nr_pages > BIO_MAX_PAGES, where additional
+ * bios need to be added to complete a given
+ * struct se_task
+ */
+ if (!hbio)
+ hbio = tbio = bio;
+ else
+ tbio = tbio->bi_next = bio;
+ }
+
+ DEBUG_PSCSI("PSCSI: Calling bio_add_pc_page() i: %d"
+ " bio: %p page: %p len: %d off: %d\n", i, bio,
+ page, len, off);
+
+ rc = bio_add_pc_page(pdv->pdv_sd->request_queue,
+ bio, page, bytes, off);
+ if (rc != bytes)
+ goto fail;
+
+ DEBUG_PSCSI("PSCSI: bio->bi_vcnt: %d nr_vecs: %d\n",
+ bio->bi_vcnt, nr_vecs);
+
+ if (bio->bi_vcnt > nr_vecs) {
+ DEBUG_PSCSI("PSCSI: Reached bio->bi_vcnt max:"
+ " %d i: %d bio: %p, allocating another"
+ " bio\n", bio->bi_vcnt, i, bio);
+ /*
+ * Clear the pointer so that another bio will
+ * be allocated with pscsi_get_bio() above, the
+ * current bio has already been set *tbio and
+ * bio->bi_next.
+ */
+ bio = NULL;
+ }
+
+ page++;
+ len -= bytes;
+ data_len -= bytes;
+ off = 0;
+ }
+ }
+ /*
+ * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND
+ * primary SCSI WRITE poayload mapped for struct se_task->task_sg[]
+ */
+ if (!(bidi_read)) {
+ /*
+ * Starting with v2.6.31, call blk_make_request() passing in *hbio to
+ * allocate the pSCSI task a struct request.
+ */
+ pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue,
+ hbio, GFP_KERNEL);
+ if (!(pt->pscsi_req)) {
+ printk(KERN_ERR "pSCSI: blk_make_request() failed\n");
+ goto fail;
+ }
+ /*
+ * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
+ * and setup rq callback, CDB and sense.
+ */
+ pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
+
+ return task->task_sg_num;
+ }
+ /*
+ * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND
+ * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[]
+ */
+ pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue,
+ hbio, GFP_KERNEL);
+ if (!(pt->pscsi_req->next_rq)) {
+ printk(KERN_ERR "pSCSI: blk_make_request() failed for BIDI\n");
+ goto fail;
+ }
+ pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1);
+
+ return task->task_sg_num;
+fail:
+ while (hbio) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_endio(bio, 0);
+ }
+ return ret;
+}
+
+static int pscsi_map_task_SG(struct se_task *task)
+{
+ int ret;
+
+ /*
+ * Setup the main struct request for the task->task_sg[] payload
+ */
+
+ ret = __pscsi_map_task_SG(task, task->task_sg, task->task_sg_num, 0);
+ if (ret >= 0 && task->task_sg_bidi) {
+ /*
+ * If present, set up the extra BIDI-COMMAND SCSI READ
+ * struct request and payload.
+ */
+ ret = __pscsi_map_task_SG(task, task->task_sg_bidi,
+ task->task_sg_num, 1);
+ }
+
+ if (ret < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ return 0;
+}
+
+/* pscsi_map_task_non_SG():
+ *
+ *
+ */
+static int pscsi_map_task_non_SG(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ int ret = 0;
+
+ if (pscsi_blk_get_request(task) < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (!task->task_size)
+ return 0;
+
+ ret = blk_rq_map_kern(pdv->pdv_sd->request_queue,
+ pt->pscsi_req, T_TASK(cmd)->t_task_buf,
+ task->task_size, GFP_KERNEL);
+ if (ret < 0) {
+ printk(KERN_ERR "PSCSI: blk_rq_map_kern() failed: %d\n", ret);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ return 0;
+}
+
+static int pscsi_CDB_none(struct se_task *task)
+{
+ return pscsi_blk_get_request(task);
+}
+
+/* pscsi_get_cdb():
+ *
+ *
+ */
+static unsigned char *pscsi_get_cdb(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ return pt->pscsi_cdb;
+}
+
+/* pscsi_get_sense_buffer():
+ *
+ *
+ */
+static unsigned char *pscsi_get_sense_buffer(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ return (unsigned char *)&pt->pscsi_sense[0];
+}
+
+/* pscsi_get_device_rev():
+ *
+ *
+ */
+static u32 pscsi_get_device_rev(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1;
+}
+
+/* pscsi_get_device_type():
+ *
+ *
+ */
+static u32 pscsi_get_device_type(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ return sd->type;
+}
+
+static sector_t pscsi_get_blocks(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+
+ if (pdv->pdv_bd && pdv->pdv_bd->bd_part)
+ return pdv->pdv_bd->bd_part->nr_sects;
+
+ dump_stack();
+ return 0;
+}
+
+/* pscsi_handle_SAM_STATUS_failures():
+ *
+ *
+ */
+static inline void pscsi_process_SAM_status(
+ struct se_task *task,
+ struct pscsi_plugin_task *pt)
+{
+ task->task_scsi_status = status_byte(pt->pscsi_result);
+ if ((task->task_scsi_status)) {
+ task->task_scsi_status <<= 1;
+ printk(KERN_INFO "PSCSI Status Byte exception at task: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ pt->pscsi_result);
+ }
+
+ switch (host_byte(pt->pscsi_result)) {
+ case DID_OK:
+ transport_complete_task(task, (!task->task_scsi_status));
+ break;
+ default:
+ printk(KERN_INFO "PSCSI Host Byte exception at task: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ pt->pscsi_result);
+ task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
+ task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ TASK_CMD(task)->transport_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ transport_complete_task(task, 0);
+ break;
+ }
+
+ return;
+}
+
+static void pscsi_req_done(struct request *req, int uptodate)
+{
+ struct se_task *task = req->end_io_data;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ pt->pscsi_result = req->errors;
+ pt->pscsi_resid = req->resid_len;
+
+ pscsi_process_SAM_status(task, pt);
+ /*
+ * Release BIDI-READ if present
+ */
+ if (req->next_rq != NULL)
+ __blk_put_request(req->q, req->next_rq);
+
+ __blk_put_request(req->q, req);
+ pt->pscsi_req = NULL;
+}
+
+static struct se_subsystem_api pscsi_template = {
+ .name = "pscsi",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
+ .cdb_none = pscsi_CDB_none,
+ .map_task_non_SG = pscsi_map_task_non_SG,
+ .map_task_SG = pscsi_map_task_SG,
+ .attach_hba = pscsi_attach_hba,
+ .detach_hba = pscsi_detach_hba,
+ .pmode_enable_hba = pscsi_pmode_enable_hba,
+ .allocate_virtdevice = pscsi_allocate_virtdevice,
+ .create_virtdevice = pscsi_create_virtdevice,
+ .free_device = pscsi_free_device,
+ .transport_complete = pscsi_transport_complete,
+ .alloc_task = pscsi_alloc_task,
+ .do_task = pscsi_do_task,
+ .free_task = pscsi_free_task,
+ .check_configfs_dev_params = pscsi_check_configfs_dev_params,
+ .set_configfs_dev_params = pscsi_set_configfs_dev_params,
+ .show_configfs_dev_params = pscsi_show_configfs_dev_params,
+ .get_cdb = pscsi_get_cdb,
+ .get_sense_buffer = pscsi_get_sense_buffer,
+ .get_device_rev = pscsi_get_device_rev,
+ .get_device_type = pscsi_get_device_type,
+ .get_blocks = pscsi_get_blocks,
+};
+
+static int __init pscsi_module_init(void)
+{
+ return transport_subsystem_register(&pscsi_template);
+}
+
+static void pscsi_module_exit(void)
+{
+ transport_subsystem_release(&pscsi_template);
+}
+
+MODULE_DESCRIPTION("TCM PSCSI subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(pscsi_module_init);
+module_exit(pscsi_module_exit);
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
new file mode 100644
index 000000000000..a4cd5d352c3a
--- /dev/null
+++ b/drivers/target/target_core_pscsi.h
@@ -0,0 +1,65 @@
+#ifndef TARGET_CORE_PSCSI_H
+#define TARGET_CORE_PSCSI_H
+
+#define PSCSI_VERSION "v4.0"
+#define PSCSI_VIRTUAL_HBA_DEPTH 2048
+
+/* used in pscsi_find_alloc_len() */
+#ifndef INQUIRY_DATA_SIZE
+#define INQUIRY_DATA_SIZE 0x24
+#endif
+
+/* used in pscsi_add_device_to_list() */
+#define PSCSI_DEFAULT_QUEUEDEPTH 1
+
+#define PS_RETRY 5
+#define PS_TIMEOUT_DISK (15*HZ)
+#define PS_TIMEOUT_OTHER (500*HZ)
+
+#include <linux/device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_device.h>
+#include <linux/kref.h>
+#include <linux/kobject.h>
+
+struct pscsi_plugin_task {
+ struct se_task pscsi_task;
+ unsigned char *pscsi_cdb;
+ unsigned char __pscsi_cdb[TCM_MAX_COMMAND_SIZE];
+ unsigned char pscsi_sense[SCSI_SENSE_BUFFERSIZE];
+ int pscsi_direction;
+ int pscsi_result;
+ u32 pscsi_resid;
+ struct request *pscsi_req;
+} ____cacheline_aligned;
+
+#define PDF_HAS_CHANNEL_ID 0x01
+#define PDF_HAS_TARGET_ID 0x02
+#define PDF_HAS_LUN_ID 0x04
+#define PDF_HAS_VPD_UNIT_SERIAL 0x08
+#define PDF_HAS_VPD_DEV_IDENT 0x10
+#define PDF_HAS_VIRT_HOST_ID 0x20
+
+struct pscsi_dev_virt {
+ int pdv_flags;
+ int pdv_host_id;
+ int pdv_channel_id;
+ int pdv_target_id;
+ int pdv_lun_id;
+ struct block_device *pdv_bd;
+ struct scsi_device *pdv_sd;
+ struct se_hba *pdv_se_hba;
+} ____cacheline_aligned;
+
+typedef enum phv_modes {
+ PHV_VIRUTAL_HOST_ID,
+ PHV_LLD_SCSI_HOST_NO
+} phv_modes_t;
+
+struct pscsi_hba_virt {
+ int phv_host_id;
+ phv_modes_t phv_mode;
+ struct Scsi_Host *phv_lld_host;
+} ____cacheline_aligned;
+
+#endif /*** TARGET_CORE_PSCSI_H ***/
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
new file mode 100644
index 000000000000..979aebf20019
--- /dev/null
+++ b/drivers/target/target_core_rd.c
@@ -0,0 +1,1091 @@
+/*******************************************************************************
+ * Filename: target_core_rd.c
+ *
+ * This file contains the Storage Engine <-> Ramdisk transport
+ * specific functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_rd.h"
+
+static struct se_subsystem_api rd_dr_template;
+static struct se_subsystem_api rd_mcp_template;
+
+/* #define DEBUG_RAMDISK_MCP */
+/* #define DEBUG_RAMDISK_DR */
+
+/* rd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct rd_host *rd_host;
+
+ rd_host = kzalloc(sizeof(struct rd_host), GFP_KERNEL);
+ if (!(rd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for struct rd_host\n");
+ return -ENOMEM;
+ }
+
+ rd_host->rd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, RD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, RD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) rd_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ RD_HBA_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached Ramdisk HBA: %u to Generic"
+ " Target Core TCQ Depth: %d MaxSectors: %u\n", hba->hba_id,
+ rd_host->rd_host_id, atomic_read(&hba->max_queue_depth),
+ RD_MAX_SECTORS);
+
+ return 0;
+}
+
+static void rd_detach_hba(struct se_hba *hba)
+{
+ struct rd_host *rd_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached Ramdisk HBA: %u from"
+ " Generic Target Core\n", hba->hba_id, rd_host->rd_host_id);
+
+ kfree(rd_host);
+ hba->hba_ptr = NULL;
+}
+
+/* rd_release_device_space():
+ *
+ *
+ */
+static void rd_release_device_space(struct rd_dev *rd_dev)
+{
+ u32 i, j, page_count = 0, sg_per_table;
+ struct rd_dev_sg_table *sg_table;
+ struct page *pg;
+ struct scatterlist *sg;
+
+ if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
+ return;
+
+ sg_table = rd_dev->sg_table_array;
+
+ for (i = 0; i < rd_dev->sg_table_count; i++) {
+ sg = sg_table[i].sg_table;
+ sg_per_table = sg_table[i].rd_sg_count;
+
+ for (j = 0; j < sg_per_table; j++) {
+ pg = sg_page(&sg[j]);
+ if ((pg)) {
+ __free_page(pg);
+ page_count++;
+ }
+ }
+
+ kfree(sg);
+ }
+
+ printk(KERN_INFO "CORE_RD[%u] - Released device space for Ramdisk"
+ " Device ID: %u, pages %u in %u tables total bytes %lu\n",
+ rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
+ rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
+
+ kfree(sg_table);
+ rd_dev->sg_table_array = NULL;
+ rd_dev->sg_table_count = 0;
+}
+
+
+/* rd_build_device_space():
+ *
+ *
+ */
+static int rd_build_device_space(struct rd_dev *rd_dev)
+{
+ u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed;
+ u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
+ sizeof(struct scatterlist));
+ struct rd_dev_sg_table *sg_table;
+ struct page *pg;
+ struct scatterlist *sg;
+
+ if (rd_dev->rd_page_count <= 0) {
+ printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n",
+ rd_dev->rd_page_count);
+ return -1;
+ }
+ total_sg_needed = rd_dev->rd_page_count;
+
+ sg_tables = (total_sg_needed / max_sg_per_table) + 1;
+
+ sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
+ if (!(sg_table)) {
+ printk(KERN_ERR "Unable to allocate memory for Ramdisk"
+ " scatterlist tables\n");
+ return -1;
+ }
+
+ rd_dev->sg_table_array = sg_table;
+ rd_dev->sg_table_count = sg_tables;
+
+ while (total_sg_needed) {
+ sg_per_table = (total_sg_needed > max_sg_per_table) ?
+ max_sg_per_table : total_sg_needed;
+
+ sg = kzalloc(sg_per_table * sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (!(sg)) {
+ printk(KERN_ERR "Unable to allocate scatterlist array"
+ " for struct rd_dev\n");
+ return -1;
+ }
+
+ sg_init_table((struct scatterlist *)&sg[0], sg_per_table);
+
+ sg_table[i].sg_table = sg;
+ sg_table[i].rd_sg_count = sg_per_table;
+ sg_table[i].page_start_offset = page_offset;
+ sg_table[i++].page_end_offset = (page_offset + sg_per_table)
+ - 1;
+
+ for (j = 0; j < sg_per_table; j++) {
+ pg = alloc_pages(GFP_KERNEL, 0);
+ if (!(pg)) {
+ printk(KERN_ERR "Unable to allocate scatterlist"
+ " pages for struct rd_dev_sg_table\n");
+ return -1;
+ }
+ sg_assign_page(&sg[j], pg);
+ sg[j].length = PAGE_SIZE;
+ }
+
+ page_offset += sg_per_table;
+ total_sg_needed -= sg_per_table;
+ }
+
+ printk(KERN_INFO "CORE_RD[%u] - Built Ramdisk Device ID: %u space of"
+ " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
+ rd_dev->rd_dev_id, rd_dev->rd_page_count,
+ rd_dev->sg_table_count);
+
+ return 0;
+}
+
+static void *rd_allocate_virtdevice(
+ struct se_hba *hba,
+ const char *name,
+ int rd_direct)
+{
+ struct rd_dev *rd_dev;
+ struct rd_host *rd_host = hba->hba_ptr;
+
+ rd_dev = kzalloc(sizeof(struct rd_dev), GFP_KERNEL);
+ if (!(rd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for struct rd_dev\n");
+ return NULL;
+ }
+
+ rd_dev->rd_host = rd_host;
+ rd_dev->rd_direct = rd_direct;
+
+ return rd_dev;
+}
+
+static void *rd_DIRECT_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ return rd_allocate_virtdevice(hba, name, 1);
+}
+
+static void *rd_MEMCPY_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ return rd_allocate_virtdevice(hba, name, 0);
+}
+
+/* rd_create_virtdevice():
+ *
+ *
+ */
+static struct se_device *rd_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p,
+ int rd_direct)
+{
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct rd_dev *rd_dev = p;
+ struct rd_host *rd_host = hba->hba_ptr;
+ int dev_flags = 0;
+ char prod[16], rev[4];
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ if (rd_build_device_space(rd_dev) < 0)
+ goto fail;
+
+ snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP");
+ snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION :
+ RD_MCP_VERSION);
+
+ dev_limits.limits.logical_block_size = RD_BLOCKSIZE;
+ dev_limits.limits.max_hw_sectors = RD_MAX_SECTORS;
+ dev_limits.limits.max_sectors = RD_MAX_SECTORS;
+ dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH;
+
+ dev = transport_add_device_to_core_hba(hba,
+ (rd_dev->rd_direct) ? &rd_dr_template :
+ &rd_mcp_template, se_dev, dev_flags, (void *)rd_dev,
+ &dev_limits, prod, rev);
+ if (!(dev))
+ goto fail;
+
+ rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++;
+ rd_dev->rd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_RD[%u] - Added TCM %s Ramdisk Device ID: %u of"
+ " %u pages in %u tables, %lu total bytes\n",
+ rd_host->rd_host_id, (!rd_dev->rd_direct) ? "MEMCPY" :
+ "DIRECT", rd_dev->rd_dev_id, rd_dev->rd_page_count,
+ rd_dev->sg_table_count,
+ (unsigned long)(rd_dev->rd_page_count * PAGE_SIZE));
+
+ return dev;
+
+fail:
+ rd_release_device_space(rd_dev);
+ return NULL;
+}
+
+static struct se_device *rd_DIRECT_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ return rd_create_virtdevice(hba, se_dev, p, 1);
+}
+
+static struct se_device *rd_MEMCPY_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ return rd_create_virtdevice(hba, se_dev, p, 0);
+}
+
+/* rd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void rd_free_device(void *p)
+{
+ struct rd_dev *rd_dev = p;
+
+ rd_release_device_space(rd_dev);
+ kfree(rd_dev);
+}
+
+static inline struct rd_request *RD_REQ(struct se_task *task)
+{
+ return container_of(task, struct rd_request, rd_task);
+}
+
+static struct se_task *
+rd_alloc_task(struct se_cmd *cmd)
+{
+ struct rd_request *rd_req;
+
+ rd_req = kzalloc(sizeof(struct rd_request), GFP_KERNEL);
+ if (!rd_req) {
+ printk(KERN_ERR "Unable to allocate struct rd_request\n");
+ return NULL;
+ }
+ rd_req->rd_dev = SE_DEV(cmd)->dev_ptr;
+
+ return &rd_req->rd_task;
+}
+
+/* rd_get_sg_table():
+ *
+ *
+ */
+static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
+{
+ u32 i;
+ struct rd_dev_sg_table *sg_table;
+
+ for (i = 0; i < rd_dev->sg_table_count; i++) {
+ sg_table = &rd_dev->sg_table_array[i];
+ if ((sg_table->page_start_offset <= page) &&
+ (sg_table->page_end_offset >= page))
+ return sg_table;
+ }
+
+ printk(KERN_ERR "Unable to locate struct rd_dev_sg_table for page: %u\n",
+ page);
+
+ return NULL;
+}
+
+/* rd_MEMCPY_read():
+ *
+ *
+ */
+static int rd_MEMCPY_read(struct rd_request *req)
+{
+ struct se_task *task = &req->rd_task;
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct scatterlist *sg_d, *sg_s;
+ void *dst, *src;
+ u32 i = 0, j = 0, dst_offset = 0, src_offset = 0;
+ u32 length, page_end = 0, table_sg_end;
+ u32 rd_offset = req->rd_offset;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_d = task->task_sg;
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "RD[%u]: Read LBA: %llu, Size: %u Page: %u, Offset:"
+ " %u\n", dev->rd_dev_id, task->task_lba, req->rd_size,
+ req->rd_page, req->rd_offset);
+#endif
+ src_offset = rd_offset;
+
+ while (req->rd_size) {
+ if ((sg_d[i].length - dst_offset) <
+ (sg_s[j].length - src_offset)) {
+ length = (sg_d[i].length - dst_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 1 - sg_d[%d]: %p length: %d"
+ " offset: %u sg_s[%d].length: %u\n", i,
+ &sg_d[i], sg_d[i].length, sg_d[i].offset, j,
+ sg_s[j].length);
+ printk(KERN_INFO "Step 1 - length: %u dst_offset: %u"
+ " src_offset: %u\n", length, dst_offset,
+ src_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ dst = sg_virt(&sg_d[i++]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ src = sg_virt(&sg_s[j]) + src_offset;
+ if (!src)
+ BUG();
+
+ dst_offset = 0;
+ src_offset = length;
+ page_end = 0;
+ } else {
+ length = (sg_s[j].length - src_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 2 - sg_d[%d]: %p length: %d"
+ " offset: %u sg_s[%d].length: %u\n", i,
+ &sg_d[i], sg_d[i].length, sg_d[i].offset,
+ j, sg_s[j].length);
+ printk(KERN_INFO "Step 2 - length: %u dst_offset: %u"
+ " src_offset: %u\n", length, dst_offset,
+ src_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ dst = sg_virt(&sg_d[i]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ if (sg_d[i].length == length) {
+ i++;
+ dst_offset = 0;
+ } else
+ dst_offset = length;
+
+ src = sg_virt(&sg_s[j++]) + src_offset;
+ if (!src)
+ BUG();
+
+ src_offset = 0;
+ page_end = 1;
+ }
+
+ memcpy(dst, src, length);
+
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u, remaining size: %u, length: %u,"
+ " i: %u, j: %u\n", req->rd_page,
+ (req->rd_size - length), length, i, j);
+#endif
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ return 0;
+
+ if (!page_end)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+ return 0;
+}
+
+/* rd_MEMCPY_write():
+ *
+ *
+ */
+static int rd_MEMCPY_write(struct rd_request *req)
+{
+ struct se_task *task = &req->rd_task;
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct scatterlist *sg_d, *sg_s;
+ void *dst, *src;
+ u32 i = 0, j = 0, dst_offset = 0, src_offset = 0;
+ u32 length, page_end = 0, table_sg_end;
+ u32 rd_offset = req->rd_offset;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_d = &table->sg_table[req->rd_page - table->page_start_offset];
+ sg_s = task->task_sg;
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "RD[%d] Write LBA: %llu, Size: %u, Page: %u,"
+ " Offset: %u\n", dev->rd_dev_id, task->task_lba, req->rd_size,
+ req->rd_page, req->rd_offset);
+#endif
+ dst_offset = rd_offset;
+
+ while (req->rd_size) {
+ if ((sg_s[i].length - src_offset) <
+ (sg_d[j].length - dst_offset)) {
+ length = (sg_s[i].length - src_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 1 - sg_s[%d]: %p length: %d"
+ " offset: %d sg_d[%d].length: %u\n", i,
+ &sg_s[i], sg_s[i].length, sg_s[i].offset,
+ j, sg_d[j].length);
+ printk(KERN_INFO "Step 1 - length: %u src_offset: %u"
+ " dst_offset: %u\n", length, src_offset,
+ dst_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ src = sg_virt(&sg_s[i++]) + src_offset;
+ if (!src)
+ BUG();
+
+ dst = sg_virt(&sg_d[j]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ src_offset = 0;
+ dst_offset = length;
+ page_end = 0;
+ } else {
+ length = (sg_d[j].length - dst_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 2 - sg_s[%d]: %p length: %d"
+ " offset: %d sg_d[%d].length: %u\n", i,
+ &sg_s[i], sg_s[i].length, sg_s[i].offset,
+ j, sg_d[j].length);
+ printk(KERN_INFO "Step 2 - length: %u src_offset: %u"
+ " dst_offset: %u\n", length, src_offset,
+ dst_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ src = sg_virt(&sg_s[i]) + src_offset;
+ if (!src)
+ BUG();
+
+ if (sg_s[i].length == length) {
+ i++;
+ src_offset = 0;
+ } else
+ src_offset = length;
+
+ dst = sg_virt(&sg_d[j++]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ dst_offset = 0;
+ page_end = 1;
+ }
+
+ memcpy(dst, src, length);
+
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u, remaining size: %u, length: %u,"
+ " i: %u, j: %u\n", req->rd_page,
+ (req->rd_size - length), length, i, j);
+#endif
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ return 0;
+
+ if (!page_end)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_d = &table->sg_table[j = 0];
+ }
+
+ return 0;
+}
+
+/* rd_MEMCPY_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_MEMCPY_do_task(struct se_task *task)
+{
+ struct se_device *dev = task->se_dev;
+ struct rd_request *req = RD_REQ(task);
+ unsigned long long lba;
+ int ret;
+
+ req->rd_page = (task->task_lba * DEV_ATTRIB(dev)->block_size) / PAGE_SIZE;
+ lba = task->task_lba;
+ req->rd_offset = (do_div(lba,
+ (PAGE_SIZE / DEV_ATTRIB(dev)->block_size))) *
+ DEV_ATTRIB(dev)->block_size;
+ req->rd_size = task->task_size;
+
+ if (task->task_data_direction == DMA_FROM_DEVICE)
+ ret = rd_MEMCPY_read(req);
+ else
+ ret = rd_MEMCPY_write(req);
+
+ if (ret != 0)
+ return ret;
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* rd_DIRECT_with_offset():
+ *
+ *
+ */
+static int rd_DIRECT_with_offset(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct rd_request *req = RD_REQ(task);
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct se_mem *se_mem;
+ struct scatterlist *sg_s;
+ u32 j = 0, set_offset = 1;
+ u32 get_next_table = 0, offset_length, table_sg_end;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u Page: %u, Offset: %u\n",
+ (task->task_data_direction == DMA_TO_DEVICE) ?
+ "Write" : "Read",
+ task->task_lba, req->rd_size, req->rd_page, req->rd_offset);
+#endif
+ while (req->rd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+
+ if (set_offset) {
+ offset_length = sg_s[j].length - req->rd_offset;
+ if (offset_length > req->rd_size)
+ offset_length = req->rd_size;
+
+ se_mem->se_page = sg_page(&sg_s[j++]);
+ se_mem->se_off = req->rd_offset;
+ se_mem->se_len = offset_length;
+
+ set_offset = 0;
+ get_next_table = (j > table_sg_end);
+ goto check_eot;
+ }
+
+ offset_length = (req->rd_size < req->rd_offset) ?
+ req->rd_size : req->rd_offset;
+
+ se_mem->se_page = sg_page(&sg_s[j]);
+ se_mem->se_len = offset_length;
+
+ set_offset = 1;
+
+check_eot:
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u, size: %u, offset_length: %u, j: %u"
+ " se_mem: %p, se_page: %p se_off: %u se_len: %u\n",
+ req->rd_page, req->rd_size, offset_length, j, se_mem,
+ se_mem->se_page, se_mem->se_off, se_mem->se_len);
+#endif
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+
+ req->rd_size -= offset_length;
+ if (!(req->rd_size))
+ goto out;
+
+ if (!set_offset && !get_next_table)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+out:
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n",
+ *se_mem_cnt);
+#endif
+ return 0;
+}
+
+/* rd_DIRECT_without_offset():
+ *
+ *
+ */
+static int rd_DIRECT_without_offset(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct rd_request *req = RD_REQ(task);
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct se_mem *se_mem;
+ struct scatterlist *sg_s;
+ u32 length, j = 0;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u, Page: %u\n",
+ (task->task_data_direction == DMA_TO_DEVICE) ?
+ "Write" : "Read",
+ task->task_lba, req->rd_size, req->rd_page);
+#endif
+ while (req->rd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+
+ length = (req->rd_size < sg_s[j].length) ?
+ req->rd_size : sg_s[j].length;
+
+ se_mem->se_page = sg_page(&sg_s[j++]);
+ se_mem->se_len = length;
+
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u, size: %u, j: %u se_mem: %p,"
+ " se_page: %p se_off: %u se_len: %u\n", req->rd_page,
+ req->rd_size, j, se_mem, se_mem->se_page,
+ se_mem->se_off, se_mem->se_len);
+#endif
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ goto out;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_DR
+ printk("page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+out:
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n",
+ *se_mem_cnt);
+#endif
+ return 0;
+}
+
+/* rd_DIRECT_do_se_mem_map():
+ *
+ *
+ */
+static int rd_DIRECT_do_se_mem_map(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset_in)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct rd_request *req = RD_REQ(task);
+ u32 task_offset = *task_offset_in;
+ unsigned long long lba;
+ int ret;
+
+ req->rd_page = ((task->task_lba * DEV_ATTRIB(task->se_dev)->block_size) /
+ PAGE_SIZE);
+ lba = task->task_lba;
+ req->rd_offset = (do_div(lba,
+ (PAGE_SIZE / DEV_ATTRIB(task->se_dev)->block_size))) *
+ DEV_ATTRIB(task->se_dev)->block_size;
+ req->rd_size = task->task_size;
+
+ if (req->rd_offset)
+ ret = rd_DIRECT_with_offset(task, se_mem_list, se_mem_cnt,
+ task_offset_in);
+ else
+ ret = rd_DIRECT_without_offset(task, se_mem_list, se_mem_cnt,
+ task_offset_in);
+
+ if (ret < 0)
+ return ret;
+
+ if (CMD_TFO(cmd)->task_sg_chaining == 0)
+ return 0;
+ /*
+ * Currently prevent writers from multiple HW fabrics doing
+ * pci_map_sg() to RD_DR's internal scatterlist memory.
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ printk(KERN_ERR "DMA_TO_DEVICE not supported for"
+ " RAMDISK_DR with task_sg_chaining=1\n");
+ return -1;
+ }
+ /*
+ * Special case for if task_sg_chaining is enabled, then
+ * we setup struct se_task->task_sg[], as it will be used by
+ * transport_do_task_sg_chain() for creating chainged SGLs
+ * across multiple struct se_task->task_sg[].
+ */
+ if (!(transport_calc_sg_num(task,
+ list_entry(T_TASK(cmd)->t_mem_list->next,
+ struct se_mem, se_list),
+ task_offset)))
+ return -1;
+
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg,
+ list_entry(T_TASK(cmd)->t_mem_list->next,
+ struct se_mem, se_list),
+ out_se_mem, se_mem_cnt, task_offset_in);
+}
+
+/* rd_DIRECT_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_DIRECT_do_task(struct se_task *task)
+{
+ /*
+ * At this point the locally allocated RD tables have been mapped
+ * to struct se_mem elements in rd_DIRECT_do_se_mem_map().
+ */
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* rd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void rd_free_task(struct se_task *task)
+{
+ kfree(RD_REQ(task));
+}
+
+enum {
+ Opt_rd_pages, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_rd_pages, "rd_pages=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t rd_set_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page,
+ ssize_t count)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_rd_pages:
+ match_int(args, &arg);
+ rd_dev->rd_page_count = arg;
+ printk(KERN_INFO "RAMDISK: Referencing Page"
+ " Count: %u\n", rd_dev->rd_page_count);
+ rd_dev->rd_flags |= RDF_HAS_PAGE_COUNT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t rd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+
+ if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) {
+ printk(KERN_INFO "Missing rd_pages= parameter\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t rd_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+ ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: %s\n",
+ rd_dev->rd_dev_id, (rd_dev->rd_direct) ?
+ "rd_direct" : "rd_mcp");
+ bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu"
+ " SG_table_count: %u\n", rd_dev->rd_page_count,
+ PAGE_SIZE, rd_dev->sg_table_count);
+ return bl;
+}
+
+/* rd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static unsigned char *rd_get_cdb(struct se_task *task)
+{
+ struct rd_request *req = RD_REQ(task);
+
+ return req->rd_scsi_cdb;
+}
+
+static u32 rd_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+static u32 rd_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t rd_get_blocks(struct se_device *dev)
+{
+ struct rd_dev *rd_dev = dev->dev_ptr;
+ unsigned long long blocks_long = ((rd_dev->rd_page_count * PAGE_SIZE) /
+ DEV_ATTRIB(dev)->block_size) - 1;
+
+ return blocks_long;
+}
+
+static struct se_subsystem_api rd_dr_template = {
+ .name = "rd_dr",
+ .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV,
+ .attach_hba = rd_attach_hba,
+ .detach_hba = rd_detach_hba,
+ .allocate_virtdevice = rd_DIRECT_allocate_virtdevice,
+ .create_virtdevice = rd_DIRECT_create_virtdevice,
+ .free_device = rd_free_device,
+ .alloc_task = rd_alloc_task,
+ .do_task = rd_DIRECT_do_task,
+ .free_task = rd_free_task,
+ .check_configfs_dev_params = rd_check_configfs_dev_params,
+ .set_configfs_dev_params = rd_set_configfs_dev_params,
+ .show_configfs_dev_params = rd_show_configfs_dev_params,
+ .get_cdb = rd_get_cdb,
+ .get_device_rev = rd_get_device_rev,
+ .get_device_type = rd_get_device_type,
+ .get_blocks = rd_get_blocks,
+ .do_se_mem_map = rd_DIRECT_do_se_mem_map,
+};
+
+static struct se_subsystem_api rd_mcp_template = {
+ .name = "rd_mcp",
+ .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV,
+ .attach_hba = rd_attach_hba,
+ .detach_hba = rd_detach_hba,
+ .allocate_virtdevice = rd_MEMCPY_allocate_virtdevice,
+ .create_virtdevice = rd_MEMCPY_create_virtdevice,
+ .free_device = rd_free_device,
+ .alloc_task = rd_alloc_task,
+ .do_task = rd_MEMCPY_do_task,
+ .free_task = rd_free_task,
+ .check_configfs_dev_params = rd_check_configfs_dev_params,
+ .set_configfs_dev_params = rd_set_configfs_dev_params,
+ .show_configfs_dev_params = rd_show_configfs_dev_params,
+ .get_cdb = rd_get_cdb,
+ .get_device_rev = rd_get_device_rev,
+ .get_device_type = rd_get_device_type,
+ .get_blocks = rd_get_blocks,
+};
+
+int __init rd_module_init(void)
+{
+ int ret;
+
+ ret = transport_subsystem_register(&rd_dr_template);
+ if (ret < 0)
+ return ret;
+
+ ret = transport_subsystem_register(&rd_mcp_template);
+ if (ret < 0) {
+ transport_subsystem_release(&rd_dr_template);
+ return ret;
+ }
+
+ return 0;
+}
+
+void rd_module_exit(void)
+{
+ transport_subsystem_release(&rd_dr_template);
+ transport_subsystem_release(&rd_mcp_template);
+}
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
new file mode 100644
index 000000000000..13badfbaf9c0
--- /dev/null
+++ b/drivers/target/target_core_rd.h
@@ -0,0 +1,73 @@
+#ifndef TARGET_CORE_RD_H
+#define TARGET_CORE_RD_H
+
+#define RD_HBA_VERSION "v4.0"
+#define RD_DR_VERSION "4.0"
+#define RD_MCP_VERSION "4.0"
+
+/* Largest piece of memory kmalloc can allocate */
+#define RD_MAX_ALLOCATION_SIZE 65536
+/* Maximum queuedepth for the Ramdisk HBA */
+#define RD_HBA_QUEUE_DEPTH 256
+#define RD_DEVICE_QUEUE_DEPTH 32
+#define RD_MAX_DEVICE_QUEUE_DEPTH 128
+#define RD_BLOCKSIZE 512
+#define RD_MAX_SECTORS 1024
+
+extern struct kmem_cache *se_mem_cache;
+
+/* Used in target_core_init_configfs() for virtual LUN 0 access */
+int __init rd_module_init(void);
+void rd_module_exit(void);
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+struct rd_request {
+ struct se_task rd_task;
+
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ /* Offset from start of page */
+ u32 rd_offset;
+ /* Starting page in Ramdisk for request */
+ u32 rd_page;
+ /* Total number of pages needed for request */
+ u32 rd_page_count;
+ /* Scatterlist count */
+ u32 rd_size;
+ /* Ramdisk device */
+ struct rd_dev *rd_dev;
+} ____cacheline_aligned;
+
+struct rd_dev_sg_table {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 rd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned;
+
+#define RDF_HAS_PAGE_COUNT 0x01
+
+struct rd_dev {
+ int rd_direct;
+ u32 rd_flags;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 rd_dev_id;
+ /* Total page count for ramdisk device */
+ u32 rd_page_count;
+ /* Number of SG tables in sg_table_array */
+ u32 sg_table_count;
+ u32 rd_queue_depth;
+ /* Array of rd_dev_sg_table_t containing scatterlists */
+ struct rd_dev_sg_table *sg_table_array;
+ /* Ramdisk HBA device is connected to */
+ struct rd_host *rd_host;
+} ____cacheline_aligned;
+
+struct rd_host {
+ u32 rd_host_dev_id_count;
+ u32 rd_host_id; /* Unique Ramdisk Host ID */
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_RD_H */
diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c
new file mode 100644
index 000000000000..dc6fed037ab3
--- /dev/null
+++ b/drivers/target/target_core_scdb.c
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Filename: target_core_scdb.c
+ *
+ * This file contains the generic target engine Split CDB related functions.
+ *
+ * Copyright (c) 2004-2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <scsi/scsi.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_scdb.h"
+
+/* split_cdb_XX_6():
+ *
+ * 21-bit LBA w/ 8-bit SECTORS
+ */
+void split_cdb_XX_6(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ cdb[1] = (lba >> 16) & 0x1f;
+ cdb[2] = (lba >> 8) & 0xff;
+ cdb[3] = lba & 0xff;
+ cdb[4] = *sectors & 0xff;
+}
+
+/* split_cdb_XX_10():
+ *
+ * 32-bit LBA w/ 16-bit SECTORS
+ */
+void split_cdb_XX_10(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be16(*sectors, &cdb[7]);
+}
+
+/* split_cdb_XX_12():
+ *
+ * 32-bit LBA w/ 32-bit SECTORS
+ */
+void split_cdb_XX_12(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be32(*sectors, &cdb[6]);
+}
+
+/* split_cdb_XX_16():
+ *
+ * 64-bit LBA w/ 32-bit SECTORS
+ */
+void split_cdb_XX_16(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be64(lba, &cdb[2]);
+ put_unaligned_be32(*sectors, &cdb[10]);
+}
+
+/*
+ * split_cdb_XX_32():
+ *
+ * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32
+ */
+void split_cdb_XX_32(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be64(lba, &cdb[12]);
+ put_unaligned_be32(*sectors, &cdb[28]);
+}
diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h
new file mode 100644
index 000000000000..98cd1c01ed83
--- /dev/null
+++ b/drivers/target/target_core_scdb.h
@@ -0,0 +1,10 @@
+#ifndef TARGET_CORE_SCDB_H
+#define TARGET_CORE_SCDB_H
+
+extern void split_cdb_XX_6(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_10(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_12(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_16(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_32(unsigned long long, u32 *, unsigned char *);
+
+#endif /* TARGET_CORE_SCDB_H */
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
new file mode 100644
index 000000000000..158cecbec718
--- /dev/null
+++ b/drivers/target/target_core_tmr.c
@@ -0,0 +1,404 @@
+/*******************************************************************************
+ * Filename: target_core_tmr.c
+ *
+ * This file contains SPC-3 task management infrastructure
+ *
+ * Copyright (c) 2009,2010 Rising Tide Systems
+ * Copyright (c) 2009,2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_pr.h"
+
+#define DEBUG_LUN_RESET
+#ifdef DEBUG_LUN_RESET
+#define DEBUG_LR(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_LR(x...)
+#endif
+
+struct se_tmr_req *core_tmr_alloc_req(
+ struct se_cmd *se_cmd,
+ void *fabric_tmr_ptr,
+ u8 function)
+{
+ struct se_tmr_req *tmr;
+
+ tmr = kmem_cache_zalloc(se_tmr_req_cache, GFP_KERNEL);
+ if (!(tmr)) {
+ printk(KERN_ERR "Unable to allocate struct se_tmr_req\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ tmr->task_cmd = se_cmd;
+ tmr->fabric_tmr_ptr = fabric_tmr_ptr;
+ tmr->function = function;
+ INIT_LIST_HEAD(&tmr->tmr_list);
+
+ return tmr;
+}
+EXPORT_SYMBOL(core_tmr_alloc_req);
+
+void core_tmr_release_req(
+ struct se_tmr_req *tmr)
+{
+ struct se_device *dev = tmr->tmr_dev;
+
+ spin_lock(&dev->se_tmr_lock);
+ list_del(&tmr->tmr_list);
+ kmem_cache_free(se_tmr_req_cache, tmr);
+ spin_unlock(&dev->se_tmr_lock);
+}
+
+static void core_tmr_handle_tas_abort(
+ struct se_node_acl *tmr_nacl,
+ struct se_cmd *cmd,
+ int tas,
+ int fe_count)
+{
+ if (!(fe_count)) {
+ transport_cmd_finish_abort(cmd, 1);
+ return;
+ }
+ /*
+ * TASK ABORTED status (TAS) bit support
+ */
+ if (((tmr_nacl != NULL) &&
+ (tmr_nacl == cmd->se_sess->se_node_acl)) || tas)
+ transport_send_task_abort(cmd);
+
+ transport_cmd_finish_abort(cmd, 0);
+}
+
+int core_tmr_lun_reset(
+ struct se_device *dev,
+ struct se_tmr_req *tmr,
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *prout_cmd)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr, *qr_tmp;
+ struct se_node_acl *tmr_nacl = NULL;
+ struct se_portal_group *tmr_tpg = NULL;
+ struct se_queue_obj *qobj = dev->dev_queue_obj;
+ struct se_tmr_req *tmr_p, *tmr_pp;
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int fe_count, state, tas;
+ /*
+ * TASK_ABORTED status bit, this is configurable via ConfigFS
+ * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ tas = DEV_ATTRIB(dev)->emulate_tas;
+ /*
+ * Determine if this se_tmr is coming from a $FABRIC_MOD
+ * or struct se_device passthrough..
+ */
+ if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
+ tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
+ tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+ if (tmr_nacl && tmr_tpg) {
+ DEBUG_LR("LUN_RESET: TMR caller fabric: %s"
+ " initiator port %s\n",
+ TPG_TFO(tmr_tpg)->get_fabric_name(),
+ tmr_nacl->initiatorname);
+ }
+ }
+ DEBUG_LR("LUN_RESET: %s starting for [%s], tas: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ TRANSPORT(dev)->name, tas);
+ /*
+ * Release all pending and outgoing TMRs aside from the received
+ * LUN_RESET tmr..
+ */
+ spin_lock(&dev->se_tmr_lock);
+ list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
+ /*
+ * Allow the received TMR to return with FUNCTION_COMPLETE.
+ */
+ if (tmr && (tmr_p == tmr))
+ continue;
+
+ cmd = tmr_p->task_cmd;
+ if (!(cmd)) {
+ printk(KERN_ERR "Unable to locate struct se_cmd for TMR\n");
+ continue;
+ }
+ /*
+ * If this function was called with a valid pr_res_key
+ * parameter (eg: for PROUT PREEMPT_AND_ABORT service action
+ * skip non regisration key matching TMRs.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ spin_unlock(&dev->se_tmr_lock);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ spin_lock(&dev->se_tmr_lock);
+ continue;
+ }
+ if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ spin_lock(&dev->se_tmr_lock);
+ continue;
+ }
+ DEBUG_LR("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
+ " Response: 0x%02x, t_state: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "", tmr_p,
+ tmr_p->function, tmr_p->response, cmd->t_state);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_cmd_finish_abort_tmr(cmd);
+ spin_lock(&dev->se_tmr_lock);
+ }
+ spin_unlock(&dev->se_tmr_lock);
+ /*
+ * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
+ * This is following sam4r17, section 5.6 Aborting commands, Table 38
+ * for TMR LUN_RESET:
+ *
+ * a) "Yes" indicates that each command that is aborted on an I_T nexus
+ * other than the one that caused the SCSI device condition is
+ * completed with TASK ABORTED status, if the TAS bit is set to one in
+ * the Control mode page (see SPC-4). "No" indicates that no status is
+ * returned for aborted commands.
+ *
+ * d) If the logical unit reset is caused by a particular I_T nexus
+ * (e.g., by a LOGICAL UNIT RESET task management function), then "yes"
+ * (TASK_ABORTED status) applies.
+ *
+ * Otherwise (e.g., if triggered by a hard reset), "no"
+ * (no TASK_ABORTED SAM status) applies.
+ *
+ * Note that this seems to be independent of TAS (Task Aborted Status)
+ * in the Control Mode Page.
+ */
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_for_each_entry_safe(task, task_tmp, &dev->state_task_list,
+ t_state_list) {
+ if (!(TASK_CMD(task))) {
+ printk(KERN_ERR "TASK_CMD(task) is NULL!\n");
+ continue;
+ }
+ cmd = TASK_CMD(task);
+
+ if (!T_TASK(cmd)) {
+ printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:"
+ " %p ITT: 0x%08x\n", task, cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ continue;
+ }
+ /*
+ * For PREEMPT_AND_ABORT usage, only process commands
+ * with a matching reservation key.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ /*
+ * Not aborting PROUT PREEMPT_AND_ABORT CDB..
+ */
+ if (prout_cmd == cmd)
+ continue;
+
+ list_del(&task->t_state_list);
+ atomic_set(&task->task_state_active, 0);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ DEBUG_LR("LUN_RESET: %s cmd: %p task: %p"
+ " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/"
+ "def_t_state: %d/%d cdb: 0x%02x\n",
+ (preempt_and_abort_list) ? "Preempt" : "", cmd, task,
+ CMD_TFO(cmd)->get_task_tag(cmd), 0,
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state,
+ cmd->deferred_t_state, T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_LR("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
+ " t_task_cdbs: %d t_task_cdbs_left: %d"
+ " t_task_cdbs_sent: %d -- t_transport_active: %d"
+ " t_transport_stop: %d t_transport_sent: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), cmd->pr_res_key,
+ T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_LR("LUN_RESET: Waiting for task: %p to shutdown"
+ " for dev: %p\n", task, dev);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_LR("LUN_RESET Completed task: %p shutdown for"
+ " dev: %p\n", task, dev);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ }
+ __transport_stop_task_timer(task, &flags);
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ DEBUG_LR("LUN_RESET: Skipping task: %p, dev: %p for"
+ " t_task_cdbs_ex_left: %d\n", task, dev,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left));
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ fe_count = atomic_read(&T_TASK(cmd)->t_fe_count);
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_active)) {
+ DEBUG_LR("LUN_RESET: got t_transport_active = 1 for"
+ " task: %p, t_fe_count: %d dev: %p\n", task,
+ fe_count, dev);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p,"
+ " t_fe_count: %d dev: %p\n", task, fe_count, dev);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Release all commands remaining in the struct se_device cmd queue.
+ *
+ * This follows the same logic as above for the struct se_device
+ * struct se_task state list, where commands are returned with
+ * TASK_ABORTED status, if there is an outstanding $FABRIC_MOD
+ * reference, otherwise the struct se_cmd is released.
+ */
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ list_for_each_entry_safe(qr, qr_tmp, &qobj->qobj_list, qr_list) {
+ cmd = (struct se_cmd *)qr->cmd;
+ if (!(cmd)) {
+ /*
+ * Skip these for non PREEMPT_AND_ABORT usage..
+ */
+ if (preempt_and_abort_list != NULL)
+ continue;
+
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ kfree(qr);
+ continue;
+ }
+ /*
+ * For PREEMPT_AND_ABORT usage, only process commands
+ * with a matching reservation key.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ /*
+ * Not aborting PROUT PREEMPT_AND_ABORT CDB..
+ */
+ if (prout_cmd == cmd)
+ continue;
+
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ state = qr->state;
+ kfree(qr);
+
+ DEBUG_LR("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
+ " %d t_fe_count: %d\n", (preempt_and_abort_list) ?
+ "Preempt" : "", cmd, state,
+ atomic_read(&T_TASK(cmd)->t_fe_count));
+ /*
+ * Signal that the command has failed via cmd->se_cmd_flags,
+ * and call TFO->new_cmd_failure() to wakeup any fabric
+ * dependent code used to wait for unsolicited data out
+ * allocation to complete. The fabric module is expected
+ * to dump any remaining unsolicited data out for the aborted
+ * command at this point.
+ */
+ transport_new_cmd_failure(cmd);
+
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
+ atomic_read(&T_TASK(cmd)->t_fe_count));
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ /*
+ * Clear any legacy SPC-2 reservation when called during
+ * LOGICAL UNIT RESET
+ */
+ if (!(preempt_and_abort_list) &&
+ (dev->dev_flags & DF_SPC2_RESERVATIONS)) {
+ spin_lock(&dev->dev_reservation_lock);
+ dev->dev_reserved_node_acl = NULL;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
+ spin_unlock(&dev->dev_reservation_lock);
+ printk(KERN_INFO "LUN_RESET: SCSI-2 Released reservation\n");
+ }
+
+ spin_lock(&dev->stats_lock);
+ dev->num_resets++;
+ spin_unlock(&dev->stats_lock);
+
+ DEBUG_LR("LUN_RESET: %s for [%s] Complete\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ TRANSPORT(dev)->name);
+ return 0;
+}
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
new file mode 100644
index 000000000000..abfa81a57115
--- /dev/null
+++ b/drivers/target/target_core_tpg.c
@@ -0,0 +1,826 @@
+/*******************************************************************************
+ * Filename: target_core_tpg.c
+ *
+ * This file contains generic Target Portal Group related functions.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_hba.h"
+
+/* core_clear_initiator_node_from_tpg():
+ *
+ *
+ */
+static void core_clear_initiator_node_from_tpg(
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg)
+{
+ int i;
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_lun_acl *acl, *acl_tmp;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ if (!deve->se_lun) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+
+ lun = deve->se_lun;
+ spin_unlock_irq(&nacl->device_list_lock);
+ core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+
+ spin_lock(&lun->lun_acl_lock);
+ list_for_each_entry_safe(acl, acl_tmp,
+ &lun->lun_acl_list, lacl_list) {
+ if (!(strcmp(acl->initiatorname,
+ nacl->initiatorname)) &&
+ (acl->mapped_lun == deve->mapped_lun))
+ break;
+ }
+
+ if (!acl) {
+ printk(KERN_ERR "Unable to locate struct se_lun_acl for %s,"
+ " mapped_lun: %u\n", nacl->initiatorname,
+ deve->mapped_lun);
+ spin_unlock(&lun->lun_acl_lock);
+ spin_lock_irq(&nacl->device_list_lock);
+ continue;
+ }
+
+ list_del(&acl->lacl_list);
+ spin_unlock(&lun->lun_acl_lock);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ kfree(acl);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+}
+
+/* __core_tpg_get_initiator_node_acl():
+ *
+ * spin_lock_bh(&tpg->acl_node_lock); must be held when calling
+ */
+struct se_node_acl *__core_tpg_get_initiator_node_acl(
+ struct se_portal_group *tpg,
+ const char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!(strcmp(acl->initiatorname, initiatorname)))
+ return acl;
+ }
+
+ return NULL;
+}
+
+/* core_tpg_get_initiator_node_acl():
+ *
+ *
+ */
+struct se_node_acl *core_tpg_get_initiator_node_acl(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!(strcmp(acl->initiatorname, initiatorname)) &&
+ (!(acl->dynamic_node_acl))) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return acl;
+ }
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return NULL;
+}
+
+/* core_tpg_add_node_to_devs():
+ *
+ *
+ */
+void core_tpg_add_node_to_devs(
+ struct se_node_acl *acl,
+ struct se_portal_group *tpg)
+{
+ int i = 0;
+ u32 lun_access = 0;
+ struct se_lun *lun;
+ struct se_device *dev;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &tpg->tpg_lun_list[i];
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+ continue;
+
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ dev = lun->lun_se_dev;
+ /*
+ * By default in LIO-Target $FABRIC_MOD,
+ * demo_mode_write_protect is ON, or READ_ONLY;
+ */
+ if (!(TPG_TFO(tpg)->tpg_check_demo_mode_write_protect(tpg))) {
+ if (dev->dev_flags & DF_READ_ONLY)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ /*
+ * Allow only optical drives to issue R/W in default RO
+ * demo mode.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+ }
+
+ printk(KERN_INFO "TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s"
+ " access for LUN in Demo Mode\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun,
+ (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ?
+ "READ-WRITE" : "READ-ONLY");
+
+ core_update_device_list_for_node(lun, NULL, lun->unpacked_lun,
+ lun_access, acl, tpg, 1);
+ spin_lock(&tpg->tpg_lun_lock);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+}
+
+/* core_set_queue_depth_for_node():
+ *
+ *
+ */
+static int core_set_queue_depth_for_node(
+ struct se_portal_group *tpg,
+ struct se_node_acl *acl)
+{
+ if (!acl->queue_depth) {
+ printk(KERN_ERR "Queue depth for %s Initiator Node: %s is 0,"
+ "defaulting to 1.\n", TPG_TFO(tpg)->get_fabric_name(),
+ acl->initiatorname);
+ acl->queue_depth = 1;
+ }
+
+ return 0;
+}
+
+/* core_create_device_list_for_node():
+ *
+ *
+ */
+static int core_create_device_list_for_node(struct se_node_acl *nacl)
+{
+ struct se_dev_entry *deve;
+ int i;
+
+ nacl->device_list = kzalloc(sizeof(struct se_dev_entry) *
+ TRANSPORT_MAX_LUNS_PER_TPG, GFP_KERNEL);
+ if (!(nacl->device_list)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_node_acl->device_list\n");
+ return -1;
+ }
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ atomic_set(&deve->ua_count, 0);
+ atomic_set(&deve->pr_ref_count, 0);
+ spin_lock_init(&deve->ua_lock);
+ INIT_LIST_HEAD(&deve->alua_port_list);
+ INIT_LIST_HEAD(&deve->ua_list);
+ }
+
+ return 0;
+}
+
+/* core_tpg_check_initiator_node_acl()
+ *
+ *
+ */
+struct se_node_acl *core_tpg_check_initiator_node_acl(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ acl = core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if ((acl))
+ return acl;
+
+ if (!(TPG_TFO(tpg)->tpg_check_demo_mode(tpg)))
+ return NULL;
+
+ acl = TPG_TFO(tpg)->tpg_alloc_fabric_acl(tpg);
+ if (!(acl))
+ return NULL;
+
+ INIT_LIST_HEAD(&acl->acl_list);
+ INIT_LIST_HEAD(&acl->acl_sess_list);
+ spin_lock_init(&acl->device_list_lock);
+ spin_lock_init(&acl->nacl_sess_lock);
+ atomic_set(&acl->acl_pr_ref_count, 0);
+ atomic_set(&acl->mib_ref_count, 0);
+ acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg);
+ snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+ acl->se_tpg = tpg;
+ acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
+ spin_lock_init(&acl->stats_lock);
+ acl->dynamic_node_acl = 1;
+
+ TPG_TFO(tpg)->set_default_node_attributes(acl);
+
+ if (core_create_device_list_for_node(acl) < 0) {
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return NULL;
+ }
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ core_free_device_list_for_node(acl, tpg);
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return NULL;
+ }
+
+ core_tpg_add_node_to_devs(acl, tpg);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_add_tail(&acl->acl_list, &tpg->acl_node_list);
+ tpg->num_node_acls++;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ printk("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+
+ return acl;
+}
+EXPORT_SYMBOL(core_tpg_check_initiator_node_acl);
+
+void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl)
+{
+ while (atomic_read(&nacl->acl_pr_ref_count) != 0)
+ cpu_relax();
+}
+
+void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl)
+{
+ while (atomic_read(&nacl->mib_ref_count) != 0)
+ cpu_relax();
+}
+
+void core_tpg_clear_object_luns(struct se_portal_group *tpg)
+{
+ int i, ret;
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &tpg->tpg_lun_list[i];
+
+ if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) ||
+ (lun->lun_se_dev == NULL))
+ continue;
+
+ spin_unlock(&tpg->tpg_lun_lock);
+ ret = core_dev_del_lun(tpg, lun->unpacked_lun);
+ spin_lock(&tpg->tpg_lun_lock);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+}
+EXPORT_SYMBOL(core_tpg_clear_object_luns);
+
+/* core_tpg_add_initiator_node_acl():
+ *
+ *
+ */
+struct se_node_acl *core_tpg_add_initiator_node_acl(
+ struct se_portal_group *tpg,
+ struct se_node_acl *se_nacl,
+ const char *initiatorname,
+ u32 queue_depth)
+{
+ struct se_node_acl *acl = NULL;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if ((acl)) {
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ printk(KERN_INFO "%s_TPG[%u] - Replacing dynamic ACL"
+ " for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), initiatorname);
+ spin_unlock_bh(&tpg->acl_node_lock);
+ /*
+ * Release the locally allocated struct se_node_acl
+ * because * core_tpg_add_initiator_node_acl() returned
+ * a pointer to an existing demo mode node ACL.
+ */
+ if (se_nacl)
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg,
+ se_nacl);
+ goto done;
+ }
+
+ printk(KERN_ERR "ACL entry for %s Initiator"
+ " Node %s already exists for TPG %u, ignoring"
+ " request.\n", TPG_TFO(tpg)->get_fabric_name(),
+ initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return ERR_PTR(-EEXIST);
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ if (!(se_nacl)) {
+ printk("struct se_node_acl pointer is NULL\n");
+ return ERR_PTR(-EINVAL);
+ }
+ /*
+ * For v4.x logic the se_node_acl_s is hanging off a fabric
+ * dependent structure allocated via
+ * struct target_core_fabric_ops->fabric_make_nodeacl()
+ */
+ acl = se_nacl;
+
+ INIT_LIST_HEAD(&acl->acl_list);
+ INIT_LIST_HEAD(&acl->acl_sess_list);
+ spin_lock_init(&acl->device_list_lock);
+ spin_lock_init(&acl->nacl_sess_lock);
+ atomic_set(&acl->acl_pr_ref_count, 0);
+ acl->queue_depth = queue_depth;
+ snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+ acl->se_tpg = tpg;
+ acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
+ spin_lock_init(&acl->stats_lock);
+
+ TPG_TFO(tpg)->set_default_node_attributes(acl);
+
+ if (core_create_device_list_for_node(acl) < 0) {
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ core_free_device_list_for_node(acl, tpg);
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_add_tail(&acl->acl_list, &tpg->acl_node_list);
+ tpg->num_node_acls++;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+done:
+ printk(KERN_INFO "%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+
+ return acl;
+}
+EXPORT_SYMBOL(core_tpg_add_initiator_node_acl);
+
+/* core_tpg_del_initiator_node_acl():
+ *
+ *
+ */
+int core_tpg_del_initiator_node_acl(
+ struct se_portal_group *tpg,
+ struct se_node_acl *acl,
+ int force)
+{
+ struct se_session *sess, *sess_tmp;
+ int dynamic_acl = 0;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ dynamic_acl = 1;
+ }
+ list_del(&acl->acl_list);
+ tpg->num_node_acls--;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_bh(&tpg->session_lock);
+ list_for_each_entry_safe(sess, sess_tmp,
+ &tpg->tpg_sess_list, sess_list) {
+ if (sess->se_node_acl != acl)
+ continue;
+ /*
+ * Determine if the session needs to be closed by our context.
+ */
+ if (!(TPG_TFO(tpg)->shutdown_session(sess)))
+ continue;
+
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * If the $FABRIC_MOD session for the Initiator Node ACL exists,
+ * forcefully shutdown the $FABRIC_MOD session/nexus.
+ */
+ TPG_TFO(tpg)->close_session(sess);
+
+ spin_lock_bh(&tpg->session_lock);
+ }
+ spin_unlock_bh(&tpg->session_lock);
+
+ core_tpg_wait_for_nacl_pr_ref(acl);
+ core_tpg_wait_for_mib_ref(acl);
+ core_clear_initiator_node_from_tpg(acl, tpg);
+ core_free_device_list_for_node(acl, tpg);
+
+ printk(KERN_INFO "%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), acl->initiatorname);
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_del_initiator_node_acl);
+
+/* core_tpg_set_initiator_node_queue_depth():
+ *
+ *
+ */
+int core_tpg_set_initiator_node_queue_depth(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname,
+ u32 queue_depth,
+ int force)
+{
+ struct se_session *sess, *init_sess = NULL;
+ struct se_node_acl *acl;
+ int dynamic_acl = 0;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (!(acl)) {
+ printk(KERN_ERR "Access Control List entry for %s Initiator"
+ " Node %s does not exists for TPG %hu, ignoring"
+ " request.\n", TPG_TFO(tpg)->get_fabric_name(),
+ initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -ENODEV;
+ }
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ dynamic_acl = 1;
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_bh(&tpg->session_lock);
+ list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
+ if (sess->se_node_acl != acl)
+ continue;
+
+ if (!force) {
+ printk(KERN_ERR "Unable to change queue depth for %s"
+ " Initiator Node: %s while session is"
+ " operational. To forcefully change the queue"
+ " depth and force session reinstatement"
+ " use the \"force=1\" parameter.\n",
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+ spin_unlock_bh(&tpg->session_lock);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -EEXIST;
+ }
+ /*
+ * Determine if the session needs to be closed by our context.
+ */
+ if (!(TPG_TFO(tpg)->shutdown_session(sess)))
+ continue;
+
+ init_sess = sess;
+ break;
+ }
+
+ /*
+ * User has requested to change the queue depth for a Initiator Node.
+ * Change the value in the Node's struct se_node_acl, and call
+ * core_set_queue_depth_for_node() to add the requested queue depth.
+ *
+ * Finally call TPG_TFO(tpg)->close_session() to force session
+ * reinstatement to occur if there is an active session for the
+ * $FABRIC_MOD Initiator Node in question.
+ */
+ acl->queue_depth = queue_depth;
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * Force session reinstatement if
+ * core_set_queue_depth_for_node() failed, because we assume
+ * the $FABRIC_MOD has already the set session reinstatement
+ * bit from TPG_TFO(tpg)->shutdown_session() called above.
+ */
+ if (init_sess)
+ TPG_TFO(tpg)->close_session(init_sess);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -EINVAL;
+ }
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * If the $FABRIC_MOD session for the Initiator Node ACL exists,
+ * forcefully shutdown the $FABRIC_MOD session/nexus.
+ */
+ if (init_sess)
+ TPG_TFO(tpg)->close_session(init_sess);
+
+ printk(KERN_INFO "Successfuly changed queue depth to: %d for Initiator"
+ " Node: %s on %s Target Portal Group: %u\n", queue_depth,
+ initiatorname, TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);
+
+static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
+{
+ /* Set in core_dev_setup_virtual_lun0() */
+ struct se_device *dev = se_global->g_lun0_dev;
+ struct se_lun *lun = &se_tpg->tpg_virt_lun0;
+ u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ int ret;
+
+ lun->unpacked_lun = 0;
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ atomic_set(&lun->lun_acl_count, 0);
+ init_completion(&lun->lun_shutdown_comp);
+ INIT_LIST_HEAD(&lun->lun_acl_list);
+ INIT_LIST_HEAD(&lun->lun_cmd_list);
+ spin_lock_init(&lun->lun_acl_lock);
+ spin_lock_init(&lun->lun_cmd_lock);
+ spin_lock_init(&lun->lun_sep_lock);
+
+ ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static void core_tpg_release_virtual_lun0(struct se_portal_group *se_tpg)
+{
+ struct se_lun *lun = &se_tpg->tpg_virt_lun0;
+
+ core_tpg_post_dellun(se_tpg, lun);
+}
+
+int core_tpg_register(
+ struct target_core_fabric_ops *tfo,
+ struct se_wwn *se_wwn,
+ struct se_portal_group *se_tpg,
+ void *tpg_fabric_ptr,
+ int se_tpg_type)
+{
+ struct se_lun *lun;
+ u32 i;
+
+ se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) *
+ TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL);
+ if (!(se_tpg->tpg_lun_list)) {
+ printk(KERN_ERR "Unable to allocate struct se_portal_group->"
+ "tpg_lun_list\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &se_tpg->tpg_lun_list[i];
+ lun->unpacked_lun = i;
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ atomic_set(&lun->lun_acl_count, 0);
+ init_completion(&lun->lun_shutdown_comp);
+ INIT_LIST_HEAD(&lun->lun_acl_list);
+ INIT_LIST_HEAD(&lun->lun_cmd_list);
+ spin_lock_init(&lun->lun_acl_lock);
+ spin_lock_init(&lun->lun_cmd_lock);
+ spin_lock_init(&lun->lun_sep_lock);
+ }
+
+ se_tpg->se_tpg_type = se_tpg_type;
+ se_tpg->se_tpg_fabric_ptr = tpg_fabric_ptr;
+ se_tpg->se_tpg_tfo = tfo;
+ se_tpg->se_tpg_wwn = se_wwn;
+ atomic_set(&se_tpg->tpg_pr_ref_count, 0);
+ INIT_LIST_HEAD(&se_tpg->acl_node_list);
+ INIT_LIST_HEAD(&se_tpg->se_tpg_list);
+ INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
+ spin_lock_init(&se_tpg->acl_node_lock);
+ spin_lock_init(&se_tpg->session_lock);
+ spin_lock_init(&se_tpg->tpg_lun_lock);
+
+ if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) {
+ if (core_tpg_setup_virtual_lun0(se_tpg) < 0) {
+ kfree(se_tpg);
+ return -ENOMEM;
+ }
+ }
+
+ spin_lock_bh(&se_global->se_tpg_lock);
+ list_add_tail(&se_tpg->se_tpg_list, &se_global->g_se_tpg_list);
+ spin_unlock_bh(&se_global->se_tpg_lock);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Allocated %s struct se_portal_group for"
+ " endpoint: %s, Portal Tag: %u\n", tfo->get_fabric_name(),
+ (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
+ "Normal" : "Discovery", (tfo->tpg_get_wwn(se_tpg) == NULL) ?
+ "None" : tfo->tpg_get_wwn(se_tpg), tfo->tpg_get_tag(se_tpg));
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_register);
+
+int core_tpg_deregister(struct se_portal_group *se_tpg)
+{
+ printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group"
+ " for endpoint: %s Portal Tag %u\n",
+ (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
+ "Normal" : "Discovery", TPG_TFO(se_tpg)->get_fabric_name(),
+ TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg),
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg));
+
+ spin_lock_bh(&se_global->se_tpg_lock);
+ list_del(&se_tpg->se_tpg_list);
+ spin_unlock_bh(&se_global->se_tpg_lock);
+
+ while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)
+ cpu_relax();
+
+ if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
+ core_tpg_release_virtual_lun0(se_tpg);
+
+ se_tpg->se_tpg_fabric_ptr = NULL;
+ kfree(se_tpg->tpg_lun_list);
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_deregister);
+
+struct se_lun *core_tpg_pre_addlun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG"
+ "-1: %u for Target Portal Group: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+ if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "TPG Logical Unit Number: %u is already active"
+ " on %s Target Portal Group: %u, ignoring request.\n",
+ unpacked_lun, TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return ERR_PTR(-EINVAL);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+int core_tpg_post_addlun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ u32 lun_access,
+ void *lun_ptr)
+{
+ if (core_dev_export(lun_ptr, tpg, lun) < 0)
+ return -1;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun->lun_access = lun_access;
+ lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE;
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return 0;
+}
+
+static void core_tpg_shutdown_lun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ core_clear_lun_from_tpg(lun, tpg);
+ transport_clear_lun_from_sessions(lun);
+}
+
+struct se_lun *core_tpg_pre_dellun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun,
+ int *ret)
+{
+ struct se_lun *lun;
+
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG"
+ "-1: %u for Target Portal Group: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %u, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return ERR_PTR(-ENODEV);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+int core_tpg_post_dellun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ core_tpg_shutdown_lun(tpg, lun);
+
+ core_dev_unexport(lun->lun_se_dev, tpg, lun);
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return 0;
+}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
new file mode 100644
index 000000000000..28b6292ff298
--- /dev/null
+++ b/drivers/target/target_core_transport.c
@@ -0,0 +1,6134 @@
+/*******************************************************************************
+ * Filename: target_core_transport.c
+ *
+ * This file contains the Generic Target Engine Core.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/net.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kthread.h>
+#include <linux/in.h>
+#include <linux/cdrom.h>
+#include <asm/unaligned.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libsas.h> /* For TASK_ATTR_* */
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_scdb.h"
+#include "target_core_ua.h"
+
+/* #define DEBUG_CDB_HANDLER */
+#ifdef DEBUG_CDB_HANDLER
+#define DEBUG_CDB_H(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CDB_H(x...)
+#endif
+
+/* #define DEBUG_CMD_MAP */
+#ifdef DEBUG_CMD_MAP
+#define DEBUG_CMD_M(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CMD_M(x...)
+#endif
+
+/* #define DEBUG_MEM_ALLOC */
+#ifdef DEBUG_MEM_ALLOC
+#define DEBUG_MEM(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_MEM(x...)
+#endif
+
+/* #define DEBUG_MEM2_ALLOC */
+#ifdef DEBUG_MEM2_ALLOC
+#define DEBUG_MEM2(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_MEM2(x...)
+#endif
+
+/* #define DEBUG_SG_CALC */
+#ifdef DEBUG_SG_CALC
+#define DEBUG_SC(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_SC(x...)
+#endif
+
+/* #define DEBUG_SE_OBJ */
+#ifdef DEBUG_SE_OBJ
+#define DEBUG_SO(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_SO(x...)
+#endif
+
+/* #define DEBUG_CMD_VOL */
+#ifdef DEBUG_CMD_VOL
+#define DEBUG_VOL(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_VOL(x...)
+#endif
+
+/* #define DEBUG_CMD_STOP */
+#ifdef DEBUG_CMD_STOP
+#define DEBUG_CS(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CS(x...)
+#endif
+
+/* #define DEBUG_PASSTHROUGH */
+#ifdef DEBUG_PASSTHROUGH
+#define DEBUG_PT(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_PT(x...)
+#endif
+
+/* #define DEBUG_TASK_STOP */
+#ifdef DEBUG_TASK_STOP
+#define DEBUG_TS(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TS(x...)
+#endif
+
+/* #define DEBUG_TRANSPORT_STOP */
+#ifdef DEBUG_TRANSPORT_STOP
+#define DEBUG_TRANSPORT_S(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TRANSPORT_S(x...)
+#endif
+
+/* #define DEBUG_TASK_FAILURE */
+#ifdef DEBUG_TASK_FAILURE
+#define DEBUG_TF(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TF(x...)
+#endif
+
+/* #define DEBUG_DEV_OFFLINE */
+#ifdef DEBUG_DEV_OFFLINE
+#define DEBUG_DO(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_DO(x...)
+#endif
+
+/* #define DEBUG_TASK_STATE */
+#ifdef DEBUG_TASK_STATE
+#define DEBUG_TSTATE(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TSTATE(x...)
+#endif
+
+/* #define DEBUG_STATUS_THR */
+#ifdef DEBUG_STATUS_THR
+#define DEBUG_ST(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_ST(x...)
+#endif
+
+/* #define DEBUG_TASK_TIMEOUT */
+#ifdef DEBUG_TASK_TIMEOUT
+#define DEBUG_TT(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TT(x...)
+#endif
+
+/* #define DEBUG_GENERIC_REQUEST_FAILURE */
+#ifdef DEBUG_GENERIC_REQUEST_FAILURE
+#define DEBUG_GRF(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_GRF(x...)
+#endif
+
+/* #define DEBUG_SAM_TASK_ATTRS */
+#ifdef DEBUG_SAM_TASK_ATTRS
+#define DEBUG_STA(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_STA(x...)
+#endif
+
+struct se_global *se_global;
+
+static struct kmem_cache *se_cmd_cache;
+static struct kmem_cache *se_sess_cache;
+struct kmem_cache *se_tmr_req_cache;
+struct kmem_cache *se_ua_cache;
+struct kmem_cache *se_mem_cache;
+struct kmem_cache *t10_pr_reg_cache;
+struct kmem_cache *t10_alua_lu_gp_cache;
+struct kmem_cache *t10_alua_lu_gp_mem_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+
+/* Used for transport_dev_get_map_*() */
+typedef int (*map_func_t)(struct se_task *, u32);
+
+static int transport_generic_write_pending(struct se_cmd *);
+static int transport_processing_thread(void *);
+static int __transport_execute_tasks(struct se_device *dev);
+static void transport_complete_task_attr(struct se_cmd *cmd);
+static void transport_direct_request_timeout(struct se_cmd *cmd);
+static void transport_free_dev_tasks(struct se_cmd *cmd);
+static u32 transport_generic_get_cdb_count(struct se_cmd *cmd,
+ unsigned long long starting_lba, u32 sectors,
+ enum dma_data_direction data_direction,
+ struct list_head *mem_list, int set_counts);
+static int transport_generic_get_mem(struct se_cmd *cmd, u32 length,
+ u32 dma_size);
+static int transport_generic_remove(struct se_cmd *cmd,
+ int release_to_pool, int session_reinstatement);
+static int transport_get_sectors(struct se_cmd *cmd);
+static struct list_head *transport_init_se_mem_list(void);
+static int transport_map_sg_to_mem(struct se_cmd *cmd,
+ struct list_head *se_mem_list, void *in_mem,
+ u32 *se_mem_cnt);
+static void transport_memcpy_se_mem_read_contig(struct se_cmd *cmd,
+ unsigned char *dst, struct list_head *se_mem_list);
+static void transport_release_fe_cmd(struct se_cmd *cmd);
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
+ struct se_queue_obj *qobj);
+static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
+static void transport_stop_all_task_timers(struct se_cmd *cmd);
+
+int transport_emulate_control_cdb(struct se_task *task);
+
+int init_se_global(void)
+{
+ struct se_global *global;
+
+ global = kzalloc(sizeof(struct se_global), GFP_KERNEL);
+ if (!(global)) {
+ printk(KERN_ERR "Unable to allocate memory for struct se_global\n");
+ return -1;
+ }
+
+ INIT_LIST_HEAD(&global->g_lu_gps_list);
+ INIT_LIST_HEAD(&global->g_se_tpg_list);
+ INIT_LIST_HEAD(&global->g_hba_list);
+ INIT_LIST_HEAD(&global->g_se_dev_list);
+ spin_lock_init(&global->g_device_lock);
+ spin_lock_init(&global->hba_lock);
+ spin_lock_init(&global->se_tpg_lock);
+ spin_lock_init(&global->lu_gps_lock);
+ spin_lock_init(&global->plugin_class_lock);
+
+ se_cmd_cache = kmem_cache_create("se_cmd_cache",
+ sizeof(struct se_cmd), __alignof__(struct se_cmd), 0, NULL);
+ if (!(se_cmd_cache)) {
+ printk(KERN_ERR "kmem_cache_create for struct se_cmd failed\n");
+ goto out;
+ }
+ se_tmr_req_cache = kmem_cache_create("se_tmr_cache",
+ sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req),
+ 0, NULL);
+ if (!(se_tmr_req_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_tmr_req"
+ " failed\n");
+ goto out;
+ }
+ se_sess_cache = kmem_cache_create("se_sess_cache",
+ sizeof(struct se_session), __alignof__(struct se_session),
+ 0, NULL);
+ if (!(se_sess_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_session"
+ " failed\n");
+ goto out;
+ }
+ se_ua_cache = kmem_cache_create("se_ua_cache",
+ sizeof(struct se_ua), __alignof__(struct se_ua),
+ 0, NULL);
+ if (!(se_ua_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_ua failed\n");
+ goto out;
+ }
+ se_mem_cache = kmem_cache_create("se_mem_cache",
+ sizeof(struct se_mem), __alignof__(struct se_mem), 0, NULL);
+ if (!(se_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_mem failed\n");
+ goto out;
+ }
+ t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache",
+ sizeof(struct t10_pr_registration),
+ __alignof__(struct t10_pr_registration), 0, NULL);
+ if (!(t10_pr_reg_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct t10_pr_registration"
+ " failed\n");
+ goto out;
+ }
+ t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache",
+ sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp),
+ 0, NULL);
+ if (!(t10_alua_lu_gp_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_cache"
+ " failed\n");
+ goto out;
+ }
+ t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache",
+ sizeof(struct t10_alua_lu_gp_member),
+ __alignof__(struct t10_alua_lu_gp_member), 0, NULL);
+ if (!(t10_alua_lu_gp_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_mem_"
+ "cache failed\n");
+ goto out;
+ }
+ t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache",
+ sizeof(struct t10_alua_tg_pt_gp),
+ __alignof__(struct t10_alua_tg_pt_gp), 0, NULL);
+ if (!(t10_alua_tg_pt_gp_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_"
+ "cache failed\n");
+ goto out;
+ }
+ t10_alua_tg_pt_gp_mem_cache = kmem_cache_create(
+ "t10_alua_tg_pt_gp_mem_cache",
+ sizeof(struct t10_alua_tg_pt_gp_member),
+ __alignof__(struct t10_alua_tg_pt_gp_member),
+ 0, NULL);
+ if (!(t10_alua_tg_pt_gp_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_"
+ "mem_t failed\n");
+ goto out;
+ }
+
+ se_global = global;
+
+ return 0;
+out:
+ if (se_cmd_cache)
+ kmem_cache_destroy(se_cmd_cache);
+ if (se_tmr_req_cache)
+ kmem_cache_destroy(se_tmr_req_cache);
+ if (se_sess_cache)
+ kmem_cache_destroy(se_sess_cache);
+ if (se_ua_cache)
+ kmem_cache_destroy(se_ua_cache);
+ if (se_mem_cache)
+ kmem_cache_destroy(se_mem_cache);
+ if (t10_pr_reg_cache)
+ kmem_cache_destroy(t10_pr_reg_cache);
+ if (t10_alua_lu_gp_cache)
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+ if (t10_alua_lu_gp_mem_cache)
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+ if (t10_alua_tg_pt_gp_cache)
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+ if (t10_alua_tg_pt_gp_mem_cache)
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+ kfree(global);
+ return -1;
+}
+
+void release_se_global(void)
+{
+ struct se_global *global;
+
+ global = se_global;
+ if (!(global))
+ return;
+
+ kmem_cache_destroy(se_cmd_cache);
+ kmem_cache_destroy(se_tmr_req_cache);
+ kmem_cache_destroy(se_sess_cache);
+ kmem_cache_destroy(se_ua_cache);
+ kmem_cache_destroy(se_mem_cache);
+ kmem_cache_destroy(t10_pr_reg_cache);
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+ kfree(global);
+
+ se_global = NULL;
+}
+
+void transport_init_queue_obj(struct se_queue_obj *qobj)
+{
+ atomic_set(&qobj->queue_cnt, 0);
+ INIT_LIST_HEAD(&qobj->qobj_list);
+ init_waitqueue_head(&qobj->thread_wq);
+ spin_lock_init(&qobj->cmd_queue_lock);
+}
+EXPORT_SYMBOL(transport_init_queue_obj);
+
+static int transport_subsystem_reqmods(void)
+{
+ int ret;
+
+ ret = request_module("target_core_iblock");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_iblock\n");
+
+ ret = request_module("target_core_file");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_file\n");
+
+ ret = request_module("target_core_pscsi");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_pscsi\n");
+
+ ret = request_module("target_core_stgt");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_stgt\n");
+
+ return 0;
+}
+
+int transport_subsystem_check_init(void)
+{
+ if (se_global->g_sub_api_initialized)
+ return 0;
+ /*
+ * Request the loading of known TCM subsystem plugins..
+ */
+ if (transport_subsystem_reqmods() < 0)
+ return -1;
+
+ se_global->g_sub_api_initialized = 1;
+ return 0;
+}
+
+struct se_session *transport_init_session(void)
+{
+ struct se_session *se_sess;
+
+ se_sess = kmem_cache_zalloc(se_sess_cache, GFP_KERNEL);
+ if (!(se_sess)) {
+ printk(KERN_ERR "Unable to allocate struct se_session from"
+ " se_sess_cache\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&se_sess->sess_list);
+ INIT_LIST_HEAD(&se_sess->sess_acl_list);
+ atomic_set(&se_sess->mib_ref_count, 0);
+
+ return se_sess;
+}
+EXPORT_SYMBOL(transport_init_session);
+
+/*
+ * Called with spin_lock_bh(&struct se_portal_group->session_lock called.
+ */
+void __transport_register_session(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct se_session *se_sess,
+ void *fabric_sess_ptr)
+{
+ unsigned char buf[PR_REG_ISID_LEN];
+
+ se_sess->se_tpg = se_tpg;
+ se_sess->fabric_sess_ptr = fabric_sess_ptr;
+ /*
+ * Used by struct se_node_acl's under ConfigFS to locate active se_session-t
+ *
+ * Only set for struct se_session's that will actually be moving I/O.
+ * eg: *NOT* discovery sessions.
+ */
+ if (se_nacl) {
+ /*
+ * If the fabric module supports an ISID based TransportID,
+ * save this value in binary from the fabric I_T Nexus now.
+ */
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) {
+ memset(&buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess,
+ &buf[0], PR_REG_ISID_LEN);
+ se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
+ }
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The se_nacl->nacl_sess pointer will be set to the
+ * last active I_T Nexus for each struct se_node_acl.
+ */
+ se_nacl->nacl_sess = se_sess;
+
+ list_add_tail(&se_sess->sess_acl_list,
+ &se_nacl->acl_sess_list);
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ }
+ list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Registered fabric_sess_ptr: %p\n",
+ TPG_TFO(se_tpg)->get_fabric_name(), se_sess->fabric_sess_ptr);
+}
+EXPORT_SYMBOL(__transport_register_session);
+
+void transport_register_session(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct se_session *se_sess,
+ void *fabric_sess_ptr)
+{
+ spin_lock_bh(&se_tpg->session_lock);
+ __transport_register_session(se_tpg, se_nacl, se_sess, fabric_sess_ptr);
+ spin_unlock_bh(&se_tpg->session_lock);
+}
+EXPORT_SYMBOL(transport_register_session);
+
+void transport_deregister_session_configfs(struct se_session *se_sess)
+{
+ struct se_node_acl *se_nacl;
+
+ /*
+ * Used by struct se_node_acl's under ConfigFS to locate active struct se_session
+ */
+ se_nacl = se_sess->se_node_acl;
+ if ((se_nacl)) {
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ list_del(&se_sess->sess_acl_list);
+ /*
+ * If the session list is empty, then clear the pointer.
+ * Otherwise, set the struct se_session pointer from the tail
+ * element of the per struct se_node_acl active session list.
+ */
+ if (list_empty(&se_nacl->acl_sess_list))
+ se_nacl->nacl_sess = NULL;
+ else {
+ se_nacl->nacl_sess = container_of(
+ se_nacl->acl_sess_list.prev,
+ struct se_session, sess_acl_list);
+ }
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ }
+}
+EXPORT_SYMBOL(transport_deregister_session_configfs);
+
+void transport_free_session(struct se_session *se_sess)
+{
+ kmem_cache_free(se_sess_cache, se_sess);
+}
+EXPORT_SYMBOL(transport_free_session);
+
+void transport_deregister_session(struct se_session *se_sess)
+{
+ struct se_portal_group *se_tpg = se_sess->se_tpg;
+ struct se_node_acl *se_nacl;
+
+ if (!(se_tpg)) {
+ transport_free_session(se_sess);
+ return;
+ }
+ /*
+ * Wait for possible reference in drivers/target/target_core_mib.c:
+ * scsi_att_intr_port_seq_show()
+ */
+ while (atomic_read(&se_sess->mib_ref_count) != 0)
+ cpu_relax();
+
+ spin_lock_bh(&se_tpg->session_lock);
+ list_del(&se_sess->sess_list);
+ se_sess->se_tpg = NULL;
+ se_sess->fabric_sess_ptr = NULL;
+ spin_unlock_bh(&se_tpg->session_lock);
+
+ /*
+ * Determine if we need to do extra work for this initiator node's
+ * struct se_node_acl if it had been previously dynamically generated.
+ */
+ se_nacl = se_sess->se_node_acl;
+ if ((se_nacl)) {
+ spin_lock_bh(&se_tpg->acl_node_lock);
+ if (se_nacl->dynamic_node_acl) {
+ if (!(TPG_TFO(se_tpg)->tpg_check_demo_mode_cache(
+ se_tpg))) {
+ list_del(&se_nacl->acl_list);
+ se_tpg->num_node_acls--;
+ spin_unlock_bh(&se_tpg->acl_node_lock);
+
+ core_tpg_wait_for_nacl_pr_ref(se_nacl);
+ core_tpg_wait_for_mib_ref(se_nacl);
+ core_free_device_list_for_node(se_nacl, se_tpg);
+ TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg,
+ se_nacl);
+ spin_lock_bh(&se_tpg->acl_node_lock);
+ }
+ }
+ spin_unlock_bh(&se_tpg->acl_node_lock);
+ }
+
+ transport_free_session(se_sess);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Deregistered fabric_sess\n",
+ TPG_TFO(se_tpg)->get_fabric_name());
+}
+EXPORT_SYMBOL(transport_deregister_session);
+
+/*
+ * Called with T_TASK(cmd)->t_state_lock held.
+ */
+static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
+{
+ struct se_device *dev;
+ struct se_task *task;
+ unsigned long flags;
+
+ if (!T_TASK(cmd))
+ return;
+
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ dev = task->se_dev;
+ if (!(dev))
+ continue;
+
+ if (atomic_read(&task->task_active))
+ continue;
+
+ if (!(atomic_read(&task->task_state_active)))
+ continue;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_del(&task->t_state_list);
+ DEBUG_TSTATE("Removed ITT: 0x%08x dev: %p task[%p]\n",
+ CMD_TFO(cmd)->tfo_get_task_tag(cmd), dev, task);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ atomic_set(&task->task_state_active, 0);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_ex_left);
+ }
+}
+
+/* transport_cmd_check_stop():
+ *
+ * 'transport_off = 1' determines if t_transport_active should be cleared.
+ * 'transport_off = 2' determines if task_dev_state should be removed.
+ *
+ * A non-zero u8 t_state sets cmd->t_state.
+ * Returns 1 when command is stopped, else 0.
+ */
+static int transport_cmd_check_stop(
+ struct se_cmd *cmd,
+ int transport_off,
+ u8 t_state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * Determine if IOCTL context caller in requesting the stopping of this
+ * command for LUN shutdown purposes.
+ */
+ if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) {
+ DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->transport_lun_stop)"
+ " == TRUE for ITT: 0x%08x\n", __func__, __LINE__,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ cmd->deferred_t_state = cmd->t_state;
+ cmd->t_state = TRANSPORT_DEFERRED_CMD;
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ if (transport_off == 2)
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&T_TASK(cmd)->transport_lun_stop_comp);
+ return 1;
+ }
+ /*
+ * Determine if frontend context caller is requesting the stopping of
+ * this command for frontend excpections.
+ */
+ if (atomic_read(&T_TASK(cmd)->t_transport_stop)) {
+ DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->t_transport_stop) =="
+ " TRUE for ITT: 0x%08x\n", __func__, __LINE__,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ cmd->deferred_t_state = cmd->t_state;
+ cmd->t_state = TRANSPORT_DEFERRED_CMD;
+ if (transport_off == 2)
+ transport_all_task_dev_remove_state(cmd);
+
+ /*
+ * Clear struct se_cmd->se_lun before the transport_off == 2 handoff
+ * to FE.
+ */
+ if (transport_off == 2)
+ cmd->se_lun = NULL;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&T_TASK(cmd)->t_transport_stop_comp);
+ return 1;
+ }
+ if (transport_off) {
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ if (transport_off == 2) {
+ transport_all_task_dev_remove_state(cmd);
+ /*
+ * Clear struct se_cmd->se_lun before the transport_off == 2
+ * handoff to fabric module.
+ */
+ cmd->se_lun = NULL;
+ /*
+ * Some fabric modules like tcm_loop can release
+ * their internally allocated I/O refrence now and
+ * struct se_cmd now.
+ */
+ if (CMD_TFO(cmd)->check_stop_free != NULL) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ CMD_TFO(cmd)->check_stop_free(cmd);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+ } else if (t_state)
+ cmd->t_state = t_state;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+}
+
+static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
+{
+ return transport_cmd_check_stop(cmd, 2, 0);
+}
+
+static void transport_lun_remove_cmd(struct se_cmd *cmd)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ unsigned long flags;
+
+ if (!lun)
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto check_lun;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_free_dev_tasks(cmd);
+
+check_lun:
+ spin_lock_irqsave(&lun->lun_cmd_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->transport_lun_active)) {
+ list_del(&cmd->se_lun_list);
+ atomic_set(&T_TASK(cmd)->transport_lun_active, 0);
+#if 0
+ printk(KERN_INFO "Removed ITT: 0x%08x from LUN LIST[%d]\n"
+ CMD_TFO(cmd)->get_task_tag(cmd), lun->unpacked_lun);
+#endif
+ }
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, flags);
+}
+
+void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
+{
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop_to_fabric(cmd))
+ return;
+ if (remove)
+ transport_generic_remove(cmd, 0, 0);
+}
+
+void transport_cmd_finish_abort_tmr(struct se_cmd *cmd)
+{
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+
+ if (transport_cmd_check_stop_to_fabric(cmd))
+ return;
+
+ transport_generic_remove(cmd, 0, 0);
+}
+
+static int transport_add_cmd_to_queue(
+ struct se_cmd *cmd,
+ int t_state)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_queue_obj *qobj = dev->dev_queue_obj;
+ struct se_queue_req *qr;
+ unsigned long flags;
+
+ qr = kzalloc(sizeof(struct se_queue_req), GFP_ATOMIC);
+ if (!(qr)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_queue_req\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&qr->qr_list);
+
+ qr->cmd = (void *)cmd;
+ qr->state = t_state;
+
+ if (t_state) {
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ cmd->t_state = t_state;
+ atomic_set(&T_TASK(cmd)->t_transport_active, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ }
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ list_add_tail(&qr->qr_list, &qobj->qobj_list);
+ atomic_inc(&T_TASK(cmd)->t_transport_queue_active);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ atomic_inc(&qobj->queue_cnt);
+ wake_up_interruptible(&qobj->thread_wq);
+ return 0;
+}
+
+/*
+ * Called with struct se_queue_obj->cmd_queue_lock held.
+ */
+static struct se_queue_req *
+__transport_get_qr_from_queue(struct se_queue_obj *qobj)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr = NULL;
+
+ if (list_empty(&qobj->qobj_list))
+ return NULL;
+
+ list_for_each_entry(qr, &qobj->qobj_list, qr_list)
+ break;
+
+ if (qr->cmd) {
+ cmd = (struct se_cmd *)qr->cmd;
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ }
+ list_del(&qr->qr_list);
+ atomic_dec(&qobj->queue_cnt);
+
+ return qr;
+}
+
+static struct se_queue_req *
+transport_get_qr_from_queue(struct se_queue_obj *qobj)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ if (list_empty(&qobj->qobj_list)) {
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ return NULL;
+ }
+
+ list_for_each_entry(qr, &qobj->qobj_list, qr_list)
+ break;
+
+ if (qr->cmd) {
+ cmd = (struct se_cmd *)qr->cmd;
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ }
+ list_del(&qr->qr_list);
+ atomic_dec(&qobj->queue_cnt);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ return qr;
+}
+
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
+ struct se_queue_obj *qobj)
+{
+ struct se_cmd *q_cmd;
+ struct se_queue_req *qr = NULL, *qr_p = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_queue_active))) {
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ return;
+ }
+
+ list_for_each_entry_safe(qr, qr_p, &qobj->qobj_list, qr_list) {
+ q_cmd = (struct se_cmd *)qr->cmd;
+ if (q_cmd != cmd)
+ continue;
+
+ atomic_dec(&T_TASK(q_cmd)->t_transport_queue_active);
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ kfree(qr);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_queue_active)) {
+ printk(KERN_ERR "ITT: 0x%08x t_transport_queue_active: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ atomic_read(&T_TASK(cmd)->t_transport_queue_active));
+ }
+}
+
+/*
+ * Completion function used by TCM subsystem plugins (such as FILEIO)
+ * for queueing up response from struct se_subsystem_api->do_task()
+ */
+void transport_complete_sync_cache(struct se_cmd *cmd, int good)
+{
+ struct se_task *task = list_entry(T_TASK(cmd)->t_task_list.next,
+ struct se_task, t_list);
+
+ if (good) {
+ cmd->scsi_status = SAM_STAT_GOOD;
+ task->task_scsi_status = GOOD;
+ } else {
+ task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
+ task->task_error_status = PYX_TRANSPORT_ILLEGAL_REQUEST;
+ TASK_CMD(task)->transport_error_status =
+ PYX_TRANSPORT_ILLEGAL_REQUEST;
+ }
+
+ transport_complete_task(task, good);
+}
+EXPORT_SYMBOL(transport_complete_sync_cache);
+
+/* transport_complete_task():
+ *
+ * Called from interrupt and non interrupt context depending
+ * on the transport plugin.
+ */
+void transport_complete_task(struct se_task *task, int success)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = task->se_dev;
+ int t_state;
+ unsigned long flags;
+#if 0
+ printk(KERN_INFO "task: %p CDB: 0x%02x obj_ptr: %p\n", task,
+ T_TASK(cmd)->t_task_cdb[0], dev);
+#endif
+ if (dev) {
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);
+ atomic_inc(&dev->depth_left);
+ atomic_inc(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ }
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&task->task_active, 0);
+
+ /*
+ * See if any sense data exists, if so set the TASK_SENSE flag.
+ * Also check for any other post completion work that needs to be
+ * done by the plugins.
+ */
+ if (dev && dev->transport->transport_complete) {
+ if (dev->transport->transport_complete(task) != 0) {
+ cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
+ task->task_sense = 1;
+ success = 1;
+ }
+ }
+
+ /*
+ * See if we are waiting for outstanding struct se_task
+ * to complete for an exception condition
+ */
+ if (atomic_read(&task->task_stop)) {
+ /*
+ * Decrement T_TASK(cmd)->t_se_count if this task had
+ * previously thrown its timeout exception handler.
+ */
+ if (atomic_read(&task->task_timeout)) {
+ atomic_dec(&T_TASK(cmd)->t_se_count);
+ atomic_set(&task->task_timeout, 0);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&task->task_stop_comp);
+ return;
+ }
+ /*
+ * If the task's timeout handler has fired, use the t_task_cdbs_timeout
+ * left counter to determine when the struct se_cmd is ready to be queued to
+ * the processing thread.
+ */
+ if (atomic_read(&task->task_timeout)) {
+ if (!(atomic_dec_and_test(
+ &T_TASK(cmd)->t_task_cdbs_timeout_left))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return;
+ }
+ t_state = TRANSPORT_COMPLETE_TIMEOUT;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, t_state);
+ return;
+ }
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_timeout_left);
+
+ /*
+ * Decrement the outstanding t_task_cdbs_left count. The last
+ * struct se_task from struct se_cmd will complete itself into the
+ * device queue depending upon int success.
+ */
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) {
+ if (!success)
+ T_TASK(cmd)->t_tasks_failed = 1;
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ if (!success || T_TASK(cmd)->t_tasks_failed) {
+ t_state = TRANSPORT_COMPLETE_FAILURE;
+ if (!task->task_error_status) {
+ task->task_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ cmd->transport_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ } else {
+ atomic_set(&T_TASK(cmd)->t_transport_complete, 1);
+ t_state = TRANSPORT_COMPLETE_OK;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, t_state);
+}
+EXPORT_SYMBOL(transport_complete_task);
+
+/*
+ * Called by transport_add_tasks_from_cmd() once a struct se_cmd's
+ * struct se_task list are ready to be added to the active execution list
+ * struct se_device
+
+ * Called with se_dev_t->execute_task_lock called.
+ */
+static inline int transport_add_task_check_sam_attr(
+ struct se_task *task,
+ struct se_task *task_prev,
+ struct se_device *dev)
+{
+ /*
+ * No SAM Task attribute emulation enabled, add to tail of
+ * execution queue
+ */
+ if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) {
+ list_add_tail(&task->t_execute_list, &dev->execute_task_list);
+ return 0;
+ }
+ /*
+ * HEAD_OF_QUEUE attribute for received CDB, which means
+ * the first task that is associated with a struct se_cmd goes to
+ * head of the struct se_device->execute_task_list, and task_prev
+ * after that for each subsequent task
+ */
+ if (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ list_add(&task->t_execute_list,
+ (task_prev != NULL) ?
+ &task_prev->t_execute_list :
+ &dev->execute_task_list);
+
+ DEBUG_STA("Set HEAD_OF_QUEUE for task CDB: 0x%02x"
+ " in execution queue\n",
+ T_TASK(task->task_se_cmd)->t_task_cdb[0]);
+ return 1;
+ }
+ /*
+ * For ORDERED, SIMPLE or UNTAGGED attribute tasks once they have been
+ * transitioned from Dermant -> Active state, and are added to the end
+ * of the struct se_device->execute_task_list
+ */
+ list_add_tail(&task->t_execute_list, &dev->execute_task_list);
+ return 0;
+}
+
+/* __transport_add_task_to_execute_queue():
+ *
+ * Called with se_dev_t->execute_task_lock called.
+ */
+static void __transport_add_task_to_execute_queue(
+ struct se_task *task,
+ struct se_task *task_prev,
+ struct se_device *dev)
+{
+ int head_of_queue;
+
+ head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev);
+ atomic_inc(&dev->execute_tasks);
+
+ if (atomic_read(&task->task_state_active))
+ return;
+ /*
+ * Determine if this task needs to go to HEAD_OF_QUEUE for the
+ * state list as well. Running with SAM Task Attribute emulation
+ * will always return head_of_queue == 0 here
+ */
+ if (head_of_queue)
+ list_add(&task->t_state_list, (task_prev) ?
+ &task_prev->t_state_list :
+ &dev->state_task_list);
+ else
+ list_add_tail(&task->t_state_list, &dev->state_task_list);
+
+ atomic_set(&task->task_state_active, 1);
+
+ DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n",
+ CMD_TFO(task->task_se_cmd)->get_task_tag(task->task_se_cmd),
+ task, dev);
+}
+
+static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
+{
+ struct se_device *dev;
+ struct se_task *task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ dev = task->se_dev;
+
+ if (atomic_read(&task->task_state_active))
+ continue;
+
+ spin_lock(&dev->execute_task_lock);
+ list_add_tail(&task->t_state_list, &dev->state_task_list);
+ atomic_set(&task->task_state_active, 1);
+
+ DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n",
+ CMD_TFO(task->task_se_cmd)->get_task_tag(
+ task->task_se_cmd), task, dev);
+
+ spin_unlock(&dev->execute_task_lock);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_task *task, *task_prev = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_execute_queue))
+ continue;
+ /*
+ * __transport_add_task_to_execute_queue() handles the
+ * SAM Task Attribute emulation if enabled
+ */
+ __transport_add_task_to_execute_queue(task, task_prev, dev);
+ atomic_set(&task->task_execute_queue, 1);
+ task_prev = task;
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ return;
+}
+
+/* transport_get_task_from_execute_queue():
+ *
+ * Called with dev->execute_task_lock held.
+ */
+static struct se_task *
+transport_get_task_from_execute_queue(struct se_device *dev)
+{
+ struct se_task *task;
+
+ if (list_empty(&dev->execute_task_list))
+ return NULL;
+
+ list_for_each_entry(task, &dev->execute_task_list, t_execute_list)
+ break;
+
+ list_del(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+
+ return task;
+}
+
+/* transport_remove_task_from_execute_queue():
+ *
+ *
+ */
+static void transport_remove_task_from_execute_queue(
+ struct se_task *task,
+ struct se_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_del(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+}
+
+unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd)
+{
+ switch (cmd->data_direction) {
+ case DMA_NONE:
+ return "NONE";
+ case DMA_FROM_DEVICE:
+ return "READ";
+ case DMA_TO_DEVICE:
+ return "WRITE";
+ case DMA_BIDIRECTIONAL:
+ return "BIDI";
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+}
+
+void transport_dump_dev_state(
+ struct se_device *dev,
+ char *b,
+ int *bl)
+{
+ *bl += sprintf(b + *bl, "Status: ");
+ switch (dev->dev_status) {
+ case TRANSPORT_DEVICE_ACTIVATED:
+ *bl += sprintf(b + *bl, "ACTIVATED");
+ break;
+ case TRANSPORT_DEVICE_DEACTIVATED:
+ *bl += sprintf(b + *bl, "DEACTIVATED");
+ break;
+ case TRANSPORT_DEVICE_SHUTDOWN:
+ *bl += sprintf(b + *bl, "SHUTDOWN");
+ break;
+ case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
+ case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
+ *bl += sprintf(b + *bl, "OFFLINE");
+ break;
+ default:
+ *bl += sprintf(b + *bl, "UNKNOWN=%d", dev->dev_status);
+ break;
+ }
+
+ *bl += sprintf(b + *bl, " Execute/Left/Max Queue Depth: %d/%d/%d",
+ atomic_read(&dev->execute_tasks), atomic_read(&dev->depth_left),
+ dev->queue_depth);
+ *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n",
+ DEV_ATTRIB(dev)->block_size, DEV_ATTRIB(dev)->max_sectors);
+ *bl += sprintf(b + *bl, " ");
+}
+
+/* transport_release_all_cmds():
+ *
+ *
+ */
+static void transport_release_all_cmds(struct se_device *dev)
+{
+ struct se_cmd *cmd = NULL;
+ struct se_queue_req *qr = NULL, *qr_p = NULL;
+ int bug_out = 0, t_state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ list_for_each_entry_safe(qr, qr_p, &dev->dev_queue_obj->qobj_list,
+ qr_list) {
+
+ cmd = (struct se_cmd *)qr->cmd;
+ t_state = qr->state;
+ list_del(&qr->qr_list);
+ kfree(qr);
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock,
+ flags);
+
+ printk(KERN_ERR "Releasing ITT: 0x%08x, i_state: %u,"
+ " t_state: %u directly\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), t_state);
+
+ transport_release_fe_cmd(cmd);
+ bug_out = 1;
+
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags);
+#if 0
+ if (bug_out)
+ BUG();
+#endif
+}
+
+void transport_dump_vpd_proto_id(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Protocol Identifier: ");
+
+ switch (vpd->protocol_identifier) {
+ case 0x00:
+ sprintf(buf+len, "Fibre Channel\n");
+ break;
+ case 0x10:
+ sprintf(buf+len, "Parallel SCSI\n");
+ break;
+ case 0x20:
+ sprintf(buf+len, "SSA\n");
+ break;
+ case 0x30:
+ sprintf(buf+len, "IEEE 1394\n");
+ break;
+ case 0x40:
+ sprintf(buf+len, "SCSI Remote Direct Memory Access"
+ " Protocol\n");
+ break;
+ case 0x50:
+ sprintf(buf+len, "Internet SCSI (iSCSI)\n");
+ break;
+ case 0x60:
+ sprintf(buf+len, "SAS Serial SCSI Protocol\n");
+ break;
+ case 0x70:
+ sprintf(buf+len, "Automation/Drive Interface Transport"
+ " Protocol\n");
+ break;
+ case 0x80:
+ sprintf(buf+len, "AT Attachment Interface ATA/ATAPI\n");
+ break;
+ default:
+ sprintf(buf+len, "Unknown 0x%02x\n",
+ vpd->protocol_identifier);
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk(KERN_INFO "%s", buf);
+}
+
+void
+transport_set_vpd_proto_id(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * Check if the Protocol Identifier Valid (PIV) bit is set..
+ *
+ * from spc3r23.pdf section 7.5.1
+ */
+ if (page_83[1] & 0x80) {
+ vpd->protocol_identifier = (page_83[0] & 0xf0);
+ vpd->protocol_identifier_set = 1;
+ transport_dump_vpd_proto_id(vpd, NULL, 0);
+ }
+}
+EXPORT_SYMBOL(transport_set_vpd_proto_id);
+
+int transport_dump_vpd_assoc(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0, len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Identifier Association: ");
+
+ switch (vpd->association) {
+ case 0x00:
+ sprintf(buf+len, "addressed logical unit\n");
+ break;
+ case 0x10:
+ sprintf(buf+len, "target port\n");
+ break;
+ case 0x20:
+ sprintf(buf+len, "SCSI target device\n");
+ break;
+ default:
+ sprintf(buf+len, "Unknown 0x%02x\n", vpd->association);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int transport_set_vpd_assoc(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * The VPD identification association..
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 297
+ */
+ vpd->association = (page_83[1] & 0x30);
+ return transport_dump_vpd_assoc(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_assoc);
+
+int transport_dump_vpd_ident_type(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0, len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Identifier Type: ");
+
+ switch (vpd->device_identifier_type) {
+ case 0x00:
+ sprintf(buf+len, "Vendor specific\n");
+ break;
+ case 0x01:
+ sprintf(buf+len, "T10 Vendor ID based\n");
+ break;
+ case 0x02:
+ sprintf(buf+len, "EUI-64 based\n");
+ break;
+ case 0x03:
+ sprintf(buf+len, "NAA\n");
+ break;
+ case 0x04:
+ sprintf(buf+len, "Relative target port identifier\n");
+ break;
+ case 0x08:
+ sprintf(buf+len, "SCSI name string\n");
+ break;
+ default:
+ sprintf(buf+len, "Unsupported: 0x%02x\n",
+ vpd->device_identifier_type);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int transport_set_vpd_ident_type(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * The VPD identifier type..
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 298
+ */
+ vpd->device_identifier_type = (page_83[1] & 0x0f);
+ return transport_dump_vpd_ident_type(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_ident_type);
+
+int transport_dump_vpd_ident(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+
+ switch (vpd->device_identifier_code_set) {
+ case 0x01: /* Binary */
+ sprintf(buf, "T10 VPD Binary Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ case 0x02: /* ASCII */
+ sprintf(buf, "T10 VPD ASCII Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ case 0x03: /* UTF-8 */
+ sprintf(buf, "T10 VPD UTF-8 Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ default:
+ sprintf(buf, "T10 VPD Device Identifier encoding unsupported:"
+ " 0x%02x", vpd->device_identifier_code_set);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int
+transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ static const char hex_str[] = "0123456789abcdef";
+ int j = 0, i = 4; /* offset to start of the identifer */
+
+ /*
+ * The VPD Code Set (encoding)
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 296
+ */
+ vpd->device_identifier_code_set = (page_83[0] & 0x0f);
+ switch (vpd->device_identifier_code_set) {
+ case 0x01: /* Binary */
+ vpd->device_identifier[j++] =
+ hex_str[vpd->device_identifier_type];
+ while (i < (4 + page_83[3])) {
+ vpd->device_identifier[j++] =
+ hex_str[(page_83[i] & 0xf0) >> 4];
+ vpd->device_identifier[j++] =
+ hex_str[page_83[i] & 0x0f];
+ i++;
+ }
+ break;
+ case 0x02: /* ASCII */
+ case 0x03: /* UTF-8 */
+ while (i < (4 + page_83[3]))
+ vpd->device_identifier[j++] = page_83[i++];
+ break;
+ default:
+ break;
+ }
+
+ return transport_dump_vpd_ident(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_ident);
+
+static void core_setup_task_attr_emulation(struct se_device *dev)
+{
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, disable the
+ * SAM Task Attribute emulation.
+ *
+ * This is currently not available in upsream Linux/SCSI Target
+ * mode code, and is assumed to be disabled while using TCM/pSCSI.
+ */
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ dev->dev_task_attr_type = SAM_TASK_ATTR_PASSTHROUGH;
+ return;
+ }
+
+ dev->dev_task_attr_type = SAM_TASK_ATTR_EMULATED;
+ DEBUG_STA("%s: Using SAM_TASK_ATTR_EMULATED for SPC: 0x%02x"
+ " device\n", TRANSPORT(dev)->name,
+ TRANSPORT(dev)->get_device_rev(dev));
+}
+
+static void scsi_dump_inquiry(struct se_device *dev)
+{
+ struct t10_wwn *wwn = DEV_T10_WWN(dev);
+ int i, device_type;
+ /*
+ * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer
+ */
+ printk(" Vendor: ");
+ for (i = 0; i < 8; i++)
+ if (wwn->vendor[i] >= 0x20)
+ printk("%c", wwn->vendor[i]);
+ else
+ printk(" ");
+
+ printk(" Model: ");
+ for (i = 0; i < 16; i++)
+ if (wwn->model[i] >= 0x20)
+ printk("%c", wwn->model[i]);
+ else
+ printk(" ");
+
+ printk(" Revision: ");
+ for (i = 0; i < 4; i++)
+ if (wwn->revision[i] >= 0x20)
+ printk("%c", wwn->revision[i]);
+ else
+ printk(" ");
+
+ printk("\n");
+
+ device_type = TRANSPORT(dev)->get_device_type(dev);
+ printk(" Type: %s ", scsi_device_type(device_type));
+ printk(" ANSI SCSI revision: %02x\n",
+ TRANSPORT(dev)->get_device_rev(dev));
+}
+
+struct se_device *transport_add_device_to_core_hba(
+ struct se_hba *hba,
+ struct se_subsystem_api *transport,
+ struct se_subsystem_dev *se_dev,
+ u32 device_flags,
+ void *transport_dev,
+ struct se_dev_limits *dev_limits,
+ const char *inquiry_prod,
+ const char *inquiry_rev)
+{
+ int ret = 0, force_pt;
+ struct se_device *dev;
+
+ dev = kzalloc(sizeof(struct se_device), GFP_KERNEL);
+ if (!(dev)) {
+ printk(KERN_ERR "Unable to allocate memory for se_dev_t\n");
+ return NULL;
+ }
+ dev->dev_queue_obj = kzalloc(sizeof(struct se_queue_obj), GFP_KERNEL);
+ if (!(dev->dev_queue_obj)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " dev->dev_queue_obj\n");
+ kfree(dev);
+ return NULL;
+ }
+ transport_init_queue_obj(dev->dev_queue_obj);
+
+ dev->dev_status_queue_obj = kzalloc(sizeof(struct se_queue_obj),
+ GFP_KERNEL);
+ if (!(dev->dev_status_queue_obj)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " dev->dev_status_queue_obj\n");
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+ return NULL;
+ }
+ transport_init_queue_obj(dev->dev_status_queue_obj);
+
+ dev->dev_flags = device_flags;
+ dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED;
+ dev->dev_ptr = (void *) transport_dev;
+ dev->se_hba = hba;
+ dev->se_sub_dev = se_dev;
+ dev->transport = transport;
+ atomic_set(&dev->active_cmds, 0);
+ INIT_LIST_HEAD(&dev->dev_list);
+ INIT_LIST_HEAD(&dev->dev_sep_list);
+ INIT_LIST_HEAD(&dev->dev_tmr_list);
+ INIT_LIST_HEAD(&dev->execute_task_list);
+ INIT_LIST_HEAD(&dev->delayed_cmd_list);
+ INIT_LIST_HEAD(&dev->ordered_cmd_list);
+ INIT_LIST_HEAD(&dev->state_task_list);
+ spin_lock_init(&dev->execute_task_lock);
+ spin_lock_init(&dev->delayed_cmd_lock);
+ spin_lock_init(&dev->ordered_cmd_lock);
+ spin_lock_init(&dev->state_task_lock);
+ spin_lock_init(&dev->dev_alua_lock);
+ spin_lock_init(&dev->dev_reservation_lock);
+ spin_lock_init(&dev->dev_status_lock);
+ spin_lock_init(&dev->dev_status_thr_lock);
+ spin_lock_init(&dev->se_port_lock);
+ spin_lock_init(&dev->se_tmr_lock);
+
+ dev->queue_depth = dev_limits->queue_depth;
+ atomic_set(&dev->depth_left, dev->queue_depth);
+ atomic_set(&dev->dev_ordered_id, 0);
+
+ se_dev_set_default_attribs(dev, dev_limits);
+
+ dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX);
+ dev->creation_time = get_jiffies_64();
+ spin_lock_init(&dev->stats_lock);
+
+ spin_lock(&hba->device_lock);
+ list_add_tail(&dev->dev_list, &hba->hba_dev_list);
+ hba->dev_count++;
+ spin_unlock(&hba->device_lock);
+ /*
+ * Setup the SAM Task Attribute emulation for struct se_device
+ */
+ core_setup_task_attr_emulation(dev);
+ /*
+ * Force PR and ALUA passthrough emulation with internal object use.
+ */
+ force_pt = (hba->hba_flags & HBA_FLAGS_INTERNAL_USE);
+ /*
+ * Setup the Reservations infrastructure for struct se_device
+ */
+ core_setup_reservations(dev, force_pt);
+ /*
+ * Setup the Asymmetric Logical Unit Assignment for struct se_device
+ */
+ if (core_setup_alua(dev, force_pt) < 0)
+ goto out;
+
+ /*
+ * Startup the struct se_device processing thread
+ */
+ dev->process_thread = kthread_run(transport_processing_thread, dev,
+ "LIO_%s", TRANSPORT(dev)->name);
+ if (IS_ERR(dev->process_thread)) {
+ printk(KERN_ERR "Unable to create kthread: LIO_%s\n",
+ TRANSPORT(dev)->name);
+ goto out;
+ }
+
+ /*
+ * Preload the initial INQUIRY const values if we are doing
+ * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI
+ * passthrough because this is being provided by the backend LLD.
+ * This is required so that transport_get_inquiry() copies these
+ * originals once back into DEV_T10_WWN(dev) for the virtual device
+ * setup.
+ */
+ if (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (!(inquiry_prod) || !(inquiry_prod)) {
+ printk(KERN_ERR "All non TCM/pSCSI plugins require"
+ " INQUIRY consts\n");
+ goto out;
+ }
+
+ strncpy(&DEV_T10_WWN(dev)->vendor[0], "LIO-ORG", 8);
+ strncpy(&DEV_T10_WWN(dev)->model[0], inquiry_prod, 16);
+ strncpy(&DEV_T10_WWN(dev)->revision[0], inquiry_rev, 4);
+ }
+ scsi_dump_inquiry(dev);
+
+out:
+ if (!ret)
+ return dev;
+ kthread_stop(dev->process_thread);
+
+ spin_lock(&hba->device_lock);
+ list_del(&dev->dev_list);
+ hba->dev_count--;
+ spin_unlock(&hba->device_lock);
+
+ se_release_vpd_for_dev(dev);
+
+ kfree(dev->dev_status_queue_obj);
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(transport_add_device_to_core_hba);
+
+/* transport_generic_prepare_cdb():
+ *
+ * Since the Initiator sees iSCSI devices as LUNs, the SCSI CDB will
+ * contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2.
+ * The point of this is since we are mapping iSCSI LUNs to
+ * SCSI Target IDs having a non-zero LUN in the CDB will throw the
+ * devices and HBAs for a loop.
+ */
+static inline void transport_generic_prepare_cdb(
+ unsigned char *cdb)
+{
+ switch (cdb[0]) {
+ case READ_10: /* SBC - RDProtect */
+ case READ_12: /* SBC - RDProtect */
+ case READ_16: /* SBC - RDProtect */
+ case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
+ case VERIFY: /* SBC - VRProtect */
+ case VERIFY_16: /* SBC - VRProtect */
+ case WRITE_VERIFY: /* SBC - VRProtect */
+ case WRITE_VERIFY_12: /* SBC - VRProtect */
+ break;
+ default:
+ cdb[1] &= 0x1f; /* clear logical unit number */
+ break;
+ }
+}
+
+static struct se_task *
+transport_generic_get_task(struct se_cmd *cmd,
+ enum dma_data_direction data_direction)
+{
+ struct se_task *task;
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned long flags;
+
+ task = dev->transport->alloc_task(cmd);
+ if (!task) {
+ printk(KERN_ERR "Unable to allocate struct se_task\n");
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&task->t_list);
+ INIT_LIST_HEAD(&task->t_execute_list);
+ INIT_LIST_HEAD(&task->t_state_list);
+ init_completion(&task->task_stop_comp);
+ task->task_no = T_TASK(cmd)->t_tasks_no++;
+ task->task_se_cmd = cmd;
+ task->se_dev = dev;
+ task->task_data_direction = data_direction;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_add_tail(&task->t_list, &T_TASK(cmd)->t_task_list);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return task;
+}
+
+static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
+
+void transport_device_setup_cmd(struct se_cmd *cmd)
+{
+ cmd->se_dev = SE_LUN(cmd)->lun_se_dev;
+}
+EXPORT_SYMBOL(transport_device_setup_cmd);
+
+/*
+ * Used by fabric modules containing a local struct se_cmd within their
+ * fabric dependent per I/O descriptor.
+ */
+void transport_init_se_cmd(
+ struct se_cmd *cmd,
+ struct target_core_fabric_ops *tfo,
+ struct se_session *se_sess,
+ u32 data_length,
+ int data_direction,
+ int task_attr,
+ unsigned char *sense_buffer)
+{
+ INIT_LIST_HEAD(&cmd->se_lun_list);
+ INIT_LIST_HEAD(&cmd->se_delayed_list);
+ INIT_LIST_HEAD(&cmd->se_ordered_list);
+ /*
+ * Setup t_task pointer to t_task_backstore
+ */
+ cmd->t_task = &cmd->t_task_backstore;
+
+ INIT_LIST_HEAD(&T_TASK(cmd)->t_task_list);
+ init_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ init_completion(&T_TASK(cmd)->transport_lun_stop_comp);
+ init_completion(&T_TASK(cmd)->t_transport_stop_comp);
+ spin_lock_init(&T_TASK(cmd)->t_state_lock);
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 1);
+
+ cmd->se_tfo = tfo;
+ cmd->se_sess = se_sess;
+ cmd->data_length = data_length;
+ cmd->data_direction = data_direction;
+ cmd->sam_task_attr = task_attr;
+ cmd->sense_buffer = sense_buffer;
+}
+EXPORT_SYMBOL(transport_init_se_cmd);
+
+static int transport_check_alloc_task_attr(struct se_cmd *cmd)
+{
+ /*
+ * Check if SAM Task Attribute emulation is enabled for this
+ * struct se_device storage object
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+ return 0;
+
+ if (cmd->sam_task_attr == TASK_ATTR_ACA) {
+ DEBUG_STA("SAM Task Attribute ACA"
+ " emulation is not supported\n");
+ return -1;
+ }
+ /*
+ * Used to determine when ORDERED commands should go from
+ * Dormant to Active status.
+ */
+ cmd->se_ordered_id = atomic_inc_return(&SE_DEV(cmd)->dev_ordered_id);
+ smp_mb__after_atomic_inc();
+ DEBUG_STA("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n",
+ cmd->se_ordered_id, cmd->sam_task_attr,
+ TRANSPORT(cmd->se_dev)->name);
+ return 0;
+}
+
+void transport_free_se_cmd(
+ struct se_cmd *se_cmd)
+{
+ if (se_cmd->se_tmr_req)
+ core_tmr_release_req(se_cmd->se_tmr_req);
+ /*
+ * Check and free any extended CDB buffer that was allocated
+ */
+ if (T_TASK(se_cmd)->t_task_cdb != T_TASK(se_cmd)->__t_task_cdb)
+ kfree(T_TASK(se_cmd)->t_task_cdb);
+}
+EXPORT_SYMBOL(transport_free_se_cmd);
+
+static void transport_generic_wait_for_tasks(struct se_cmd *, int, int);
+
+/* transport_generic_allocate_tasks():
+ *
+ * Called from fabric RX Thread.
+ */
+int transport_generic_allocate_tasks(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ int ret;
+
+ transport_generic_prepare_cdb(cdb);
+
+ /*
+ * This is needed for early exceptions.
+ */
+ cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
+
+ transport_device_setup_cmd(cmd);
+ /*
+ * Ensure that the received CDB is less than the max (252 + 8) bytes
+ * for VARIABLE_LENGTH_CMD
+ */
+ if (scsi_command_size(cdb) > SCSI_MAX_VARLEN_CDB_SIZE) {
+ printk(KERN_ERR "Received SCSI CDB with command_size: %d that"
+ " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
+ scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE);
+ return -1;
+ }
+ /*
+ * If the received CDB is larger than TCM_MAX_COMMAND_SIZE,
+ * allocate the additional extended CDB buffer now.. Otherwise
+ * setup the pointer from __t_task_cdb to t_task_cdb.
+ */
+ if (scsi_command_size(cdb) > sizeof(T_TASK(cmd)->__t_task_cdb)) {
+ T_TASK(cmd)->t_task_cdb = kzalloc(scsi_command_size(cdb),
+ GFP_KERNEL);
+ if (!(T_TASK(cmd)->t_task_cdb)) {
+ printk(KERN_ERR "Unable to allocate T_TASK(cmd)->t_task_cdb"
+ " %u > sizeof(T_TASK(cmd)->__t_task_cdb): %lu ops\n",
+ scsi_command_size(cdb),
+ (unsigned long)sizeof(T_TASK(cmd)->__t_task_cdb));
+ return -1;
+ }
+ } else
+ T_TASK(cmd)->t_task_cdb = &T_TASK(cmd)->__t_task_cdb[0];
+ /*
+ * Copy the original CDB into T_TASK(cmd).
+ */
+ memcpy(T_TASK(cmd)->t_task_cdb, cdb, scsi_command_size(cdb));
+ /*
+ * Setup the received CDB based on SCSI defined opcodes and
+ * perform unit attention, persistent reservations and ALUA
+ * checks for virtual device backends. The T_TASK(cmd)->t_task_cdb
+ * pointer is expected to be setup before we reach this point.
+ */
+ ret = transport_generic_cmd_sequencer(cmd, cdb);
+ if (ret < 0)
+ return ret;
+ /*
+ * Check for SAM Task Attribute Emulation
+ */
+ if (transport_check_alloc_task_attr(cmd) < 0) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -2;
+ }
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (cmd->se_lun->lun_sep)
+ cmd->se_lun->lun_sep->sep_stats.cmd_pdus++;
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_allocate_tasks);
+
+/*
+ * Used by fabric module frontends not defining a TFO->new_cmd_map()
+ * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis
+ */
+int transport_generic_handle_cdb(
+ struct se_cmd *cmd)
+{
+ if (!SE_LUN(cmd)) {
+ dump_stack();
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_cdb);
+
+/*
+ * Used by fabric module frontends defining a TFO->new_cmd_map() caller
+ * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to
+ * complete setup in TCM process context w/ TFO->new_cmd_map().
+ */
+int transport_generic_handle_cdb_map(
+ struct se_cmd *cmd)
+{
+ if (!SE_LUN(cmd)) {
+ dump_stack();
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_cdb_map);
+
+/* transport_generic_handle_data():
+ *
+ *
+ */
+int transport_generic_handle_data(
+ struct se_cmd *cmd)
+{
+ /*
+ * For the software fabric case, then we assume the nexus is being
+ * failed/shutdown when signals are pending from the kthread context
+ * caller, so we return a failure. For the HW target mode case running
+ * in interrupt code, the signal_pending() check is skipped.
+ */
+ if (!in_interrupt() && signal_pending(current))
+ return -1;
+ /*
+ * If the received CDB has aleady been ABORTED by the generic
+ * target engine, we now call transport_check_aborted_status()
+ * to queue any delated TASK_ABORTED status for the received CDB to the
+ * fabric module as we are expecting no futher incoming DATA OUT
+ * sequences at this point.
+ */
+ if (transport_check_aborted_status(cmd, 1) != 0)
+ return 0;
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_data);
+
+/* transport_generic_handle_tmr():
+ *
+ *
+ */
+int transport_generic_handle_tmr(
+ struct se_cmd *cmd)
+{
+ /*
+ * This is needed for early exceptions.
+ */
+ cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
+ transport_device_setup_cmd(cmd);
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_tmr);
+
+static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
+{
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int ret = 0;
+
+ DEBUG_TS("ITT[0x%08x] - Stopping tasks\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ /*
+ * No tasks remain in the execution queue
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+ DEBUG_TS("task_no[%d] - Processing task %p\n",
+ task->task_no, task);
+ /*
+ * If the struct se_task has not been sent and is not active,
+ * remove the struct se_task from the execution queue.
+ */
+ if (!atomic_read(&task->task_sent) &&
+ !atomic_read(&task->task_active)) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ transport_remove_task_from_execute_queue(task,
+ task->se_dev);
+
+ DEBUG_TS("task_no[%d] - Removed from execute queue\n",
+ task->task_no);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ continue;
+ }
+
+ /*
+ * If the struct se_task is active, sleep until it is returned
+ * from the plugin.
+ */
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+
+ DEBUG_TS("task_no[%d] - Waiting to complete\n",
+ task->task_no);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_TS("task_no[%d] - Stopped successfully\n",
+ task->task_no);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ } else {
+ DEBUG_TS("task_no[%d] - Did nothing\n", task->task_no);
+ ret++;
+ }
+
+ __transport_stop_task_timer(task, &flags);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return ret;
+}
+
+static void transport_failure_reset_queue_depth(struct se_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);;
+ atomic_inc(&dev->depth_left);
+ atomic_inc(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+}
+
+/*
+ * Handle SAM-esque emulation for generic transport request failures.
+ */
+static void transport_generic_request_failure(
+ struct se_cmd *cmd,
+ struct se_device *dev,
+ int complete,
+ int sc)
+{
+ DEBUG_GRF("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x"
+ " CDB: 0x%02x\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd),
+ T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_GRF("-----[ i_state: %d t_state/def_t_state:"
+ " %d/%d transport_error_status: %d\n",
+ CMD_TFO(cmd)->get_cmd_state(cmd),
+ cmd->t_state, cmd->deferred_t_state,
+ cmd->transport_error_status);
+ DEBUG_GRF("-----[ t_task_cdbs: %d t_task_cdbs_left: %d"
+ " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
+ " t_transport_active: %d t_transport_stop: %d"
+ " t_transport_sent: %d\n", T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ transport_stop_all_task_timers(cmd);
+
+ if (dev)
+ transport_failure_reset_queue_depth(dev);
+ /*
+ * For SAM Task Attribute emulation for failed struct se_cmd
+ */
+ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+
+ if (complete) {
+ transport_direct_request_timeout(cmd);
+ cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ switch (cmd->transport_error_status) {
+ case PYX_TRANSPORT_UNKNOWN_SAM_OPCODE:
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ break;
+ case PYX_TRANSPORT_REQ_TOO_MANY_SECTORS:
+ cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY;
+ break;
+ case PYX_TRANSPORT_INVALID_CDB_FIELD:
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ break;
+ case PYX_TRANSPORT_INVALID_PARAMETER_LIST:
+ cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+ break;
+ case PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES:
+ if (!sc)
+ transport_new_cmd_failure(cmd);
+ /*
+ * Currently for PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES,
+ * we force this session to fall back to session
+ * recovery.
+ */
+ CMD_TFO(cmd)->fall_back_to_erl0(cmd->se_sess);
+ CMD_TFO(cmd)->stop_session(cmd->se_sess, 0, 0);
+
+ goto check_stop;
+ case PYX_TRANSPORT_LU_COMM_FAILURE:
+ case PYX_TRANSPORT_ILLEGAL_REQUEST:
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ break;
+ case PYX_TRANSPORT_UNKNOWN_MODE_PAGE:
+ cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
+ break;
+ case PYX_TRANSPORT_WRITE_PROTECTED:
+ cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ break;
+ case PYX_TRANSPORT_RESERVATION_CONFLICT:
+ /*
+ * No SENSE Data payload for this case, set SCSI Status
+ * and queue the response to $FABRIC_MOD.
+ *
+ * Uses linux/include/scsi/scsi.h SAM status codes defs
+ */
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+ /*
+ * For UA Interlock Code 11b, a RESERVATION CONFLICT will
+ * establish a UNIT ATTENTION with PREVIOUS RESERVATION
+ * CONFLICT STATUS.
+ *
+ * See spc4r17, section 7.4.6 Control Mode Page, Table 349
+ */
+ if (SE_SESS(cmd) &&
+ DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2)
+ core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl,
+ cmd->orig_fe_lun, 0x2C,
+ ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
+
+ CMD_TFO(cmd)->queue_status(cmd);
+ goto check_stop;
+ case PYX_TRANSPORT_USE_SENSE_REASON:
+ /*
+ * struct se_cmd->scsi_sense_reason already set
+ */
+ break;
+ default:
+ printk(KERN_ERR "Unknown transport error for CDB 0x%02x: %d\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->transport_error_status);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ break;
+ }
+
+ if (!sc)
+ transport_new_cmd_failure(cmd);
+ else
+ transport_send_check_condition_and_sense(cmd,
+ cmd->scsi_sense_reason, 0);
+check_stop:
+ transport_lun_remove_cmd(cmd);
+ if (!(transport_cmd_check_stop_to_fabric(cmd)))
+ ;
+}
+
+static void transport_direct_request_timeout(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_timeout))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ if (atomic_read(&T_TASK(cmd)->t_task_cdbs_timeout_left)) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ atomic_sub(atomic_read(&T_TASK(cmd)->t_transport_timeout),
+ &T_TASK(cmd)->t_se_count);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static void transport_generic_request_timeout(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ /*
+ * Reset T_TASK(cmd)->t_se_count to allow transport_generic_remove()
+ * to allow last call to free memory resources.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_transport_timeout) > 1) {
+ int tmp = (atomic_read(&T_TASK(cmd)->t_transport_timeout) - 1);
+
+ atomic_sub(tmp, &T_TASK(cmd)->t_se_count);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_generic_remove(cmd, 0, 0);
+}
+
+static int
+transport_generic_allocate_buf(struct se_cmd *cmd, u32 data_length)
+{
+ unsigned char *buf;
+
+ buf = kzalloc(data_length, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for buffer\n");
+ return -1;
+ }
+
+ T_TASK(cmd)->t_tasks_se_num = 0;
+ T_TASK(cmd)->t_task_buf = buf;
+
+ return 0;
+}
+
+static inline u32 transport_lba_21(unsigned char *cdb)
+{
+ return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
+}
+
+static inline u32 transport_lba_32(unsigned char *cdb)
+{
+ return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+}
+
+static inline unsigned long long transport_lba_64(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+ __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
+ */
+static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
+ __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags);
+ se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
+ spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags);
+}
+
+/*
+ * Called from interrupt context.
+ */
+static void transport_task_timeout_handler(unsigned long data)
+{
+ struct se_task *task = (struct se_task *)data;
+ struct se_cmd *cmd = TASK_CMD(task);
+ unsigned long flags;
+
+ DEBUG_TT("transport task timeout fired! task: %p cmd: %p\n", task, cmd);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (task->task_flags & TF_STOP) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ task->task_flags &= ~TF_RUNNING;
+
+ /*
+ * Determine if transport_complete_task() has already been called.
+ */
+ if (!(atomic_read(&task->task_active))) {
+ DEBUG_TT("transport task: %p cmd: %p timeout task_active"
+ " == 0\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ atomic_inc(&T_TASK(cmd)->t_se_count);
+ atomic_inc(&T_TASK(cmd)->t_transport_timeout);
+ T_TASK(cmd)->t_tasks_failed = 1;
+
+ atomic_set(&task->task_timeout, 1);
+ task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT;
+ task->task_scsi_status = 1;
+
+ if (atomic_read(&task->task_stop)) {
+ DEBUG_TT("transport task: %p cmd: %p timeout task_stop"
+ " == 1\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ complete(&task->task_stop_comp);
+ return;
+ }
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) {
+ DEBUG_TT("transport task: %p cmd: %p timeout non zero"
+ " t_task_cdbs_left\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ DEBUG_TT("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n",
+ task, cmd);
+
+ cmd->t_state = TRANSPORT_COMPLETE_FAILURE;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE);
+}
+
+/*
+ * Called with T_TASK(cmd)->t_state_lock held.
+ */
+static void transport_start_task_timer(struct se_task *task)
+{
+ struct se_device *dev = task->se_dev;
+ int timeout;
+
+ if (task->task_flags & TF_RUNNING)
+ return;
+ /*
+ * If the task_timeout is disabled, exit now.
+ */
+ timeout = DEV_ATTRIB(dev)->task_timeout;
+ if (!(timeout))
+ return;
+
+ init_timer(&task->task_timer);
+ task->task_timer.expires = (get_jiffies_64() + timeout * HZ);
+ task->task_timer.data = (unsigned long) task;
+ task->task_timer.function = transport_task_timeout_handler;
+
+ task->task_flags |= TF_RUNNING;
+ add_timer(&task->task_timer);
+#if 0
+ printk(KERN_INFO "Starting task timer for cmd: %p task: %p seconds:"
+ " %d\n", task->task_se_cmd, task, timeout);
+#endif
+}
+
+/*
+ * Called with spin_lock_irq(&T_TASK(cmd)->t_state_lock) held.
+ */
+void __transport_stop_task_timer(struct se_task *task, unsigned long *flags)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+
+ if (!(task->task_flags & TF_RUNNING))
+ return;
+
+ task->task_flags |= TF_STOP;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, *flags);
+
+ del_timer_sync(&task->task_timer);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, *flags);
+ task->task_flags &= ~TF_RUNNING;
+ task->task_flags &= ~TF_STOP;
+}
+
+static void transport_stop_all_task_timers(struct se_cmd *cmd)
+{
+ struct se_task *task = NULL, *task_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list)
+ __transport_stop_task_timer(task, &flags);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static inline int transport_tcq_window_closed(struct se_device *dev)
+{
+ if (dev->dev_tcq_window_closed++ <
+ PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) {
+ msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT);
+ } else
+ msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG);
+
+ wake_up_interruptible(&dev->dev_queue_obj->thread_wq);
+ return 0;
+}
+
+/*
+ * Called from Fabric Module context from transport_execute_tasks()
+ *
+ * The return of this function determins if the tasks from struct se_cmd
+ * get added to the execution queue in transport_execute_tasks(),
+ * or are added to the delayed or ordered lists here.
+ */
+static inline int transport_execute_task_attr(struct se_cmd *cmd)
+{
+ if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+ return 1;
+ /*
+ * Check for the existance of HEAD_OF_QUEUE, and if true return 1
+ * to allow the passed struct se_cmd list of tasks to the front of the list.
+ */
+ if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ atomic_inc(&SE_DEV(cmd)->dev_hoq_count);
+ smp_mb__after_atomic_inc();
+ DEBUG_STA("Added HEAD_OF_QUEUE for CDB:"
+ " 0x%02x, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->se_ordered_id);
+ return 1;
+ } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+ spin_lock(&SE_DEV(cmd)->ordered_cmd_lock);
+ list_add_tail(&cmd->se_ordered_list,
+ &SE_DEV(cmd)->ordered_cmd_list);
+ spin_unlock(&SE_DEV(cmd)->ordered_cmd_lock);
+
+ atomic_inc(&SE_DEV(cmd)->dev_ordered_sync);
+ smp_mb__after_atomic_inc();
+
+ DEBUG_STA("Added ORDERED for CDB: 0x%02x to ordered"
+ " list, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->se_ordered_id);
+ /*
+ * Add ORDERED command to tail of execution queue if
+ * no other older commands exist that need to be
+ * completed first.
+ */
+ if (!(atomic_read(&SE_DEV(cmd)->simple_cmds)))
+ return 1;
+ } else {
+ /*
+ * For SIMPLE and UNTAGGED Task Attribute commands
+ */
+ atomic_inc(&SE_DEV(cmd)->simple_cmds);
+ smp_mb__after_atomic_inc();
+ }
+ /*
+ * Otherwise if one or more outstanding ORDERED task attribute exist,
+ * add the dormant task(s) built for the passed struct se_cmd to the
+ * execution queue and become in Active state for this struct se_device.
+ */
+ if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) {
+ /*
+ * Otherwise, add cmd w/ tasks to delayed cmd queue that
+ * will be drained upon competion of HEAD_OF_QUEUE task.
+ */
+ spin_lock(&SE_DEV(cmd)->delayed_cmd_lock);
+ cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR;
+ list_add_tail(&cmd->se_delayed_list,
+ &SE_DEV(cmd)->delayed_cmd_list);
+ spin_unlock(&SE_DEV(cmd)->delayed_cmd_lock);
+
+ DEBUG_STA("Added CDB: 0x%02x Task Attr: 0x%02x to"
+ " delayed CMD list, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0], cmd->sam_task_attr,
+ cmd->se_ordered_id);
+ /*
+ * Return zero to let transport_execute_tasks() know
+ * not to add the delayed tasks to the execution list.
+ */
+ return 0;
+ }
+ /*
+ * Otherwise, no ORDERED task attributes exist..
+ */
+ return 1;
+}
+
+/*
+ * Called from fabric module context in transport_generic_new_cmd() and
+ * transport_generic_process_write()
+ */
+static int transport_execute_tasks(struct se_cmd *cmd)
+{
+ int add_tasks;
+
+ if (!(cmd->se_cmd_flags & SCF_SE_DISABLE_ONLINE_CHECK)) {
+ if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) {
+ cmd->transport_error_status =
+ PYX_TRANSPORT_LU_COMM_FAILURE;
+ transport_generic_request_failure(cmd, NULL, 0, 1);
+ return 0;
+ }
+ }
+ /*
+ * Call transport_cmd_check_stop() to see if a fabric exception
+ * has occured that prevents execution.
+ */
+ if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) {
+ /*
+ * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE
+ * attribute for the tasks of the received struct se_cmd CDB
+ */
+ add_tasks = transport_execute_task_attr(cmd);
+ if (add_tasks == 0)
+ goto execute_tasks;
+ /*
+ * This calls transport_add_tasks_from_cmd() to handle
+ * HEAD_OF_QUEUE ordering for SAM Task Attribute emulation
+ * (if enabled) in __transport_add_task_to_execute_queue() and
+ * transport_add_task_check_sam_attr().
+ */
+ transport_add_tasks_from_cmd(cmd);
+ }
+ /*
+ * Kick the execution queue for the cmd associated struct se_device
+ * storage object.
+ */
+execute_tasks:
+ __transport_execute_tasks(SE_DEV(cmd));
+ return 0;
+}
+
+/*
+ * Called to check struct se_device tcq depth window, and once open pull struct se_task
+ * from struct se_device->execute_task_list and
+ *
+ * Called from transport_processing_thread()
+ */
+static int __transport_execute_tasks(struct se_device *dev)
+{
+ int error;
+ struct se_cmd *cmd = NULL;
+ struct se_task *task;
+ unsigned long flags;
+
+ /*
+ * Check if there is enough room in the device and HBA queue to send
+ * struct se_transport_task's to the selected transport.
+ */
+check_depth:
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);
+ if (!(atomic_read(&dev->depth_left)) ||
+ !(atomic_read(&SE_HBA(dev)->left_queue_depth))) {
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ return transport_tcq_window_closed(dev);
+ }
+ dev->dev_tcq_window_closed = 0;
+
+ spin_lock(&dev->execute_task_lock);
+ task = transport_get_task_from_execute_queue(dev);
+ spin_unlock(&dev->execute_task_lock);
+
+ if (!task) {
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ return 0;
+ }
+
+ atomic_dec(&dev->depth_left);
+ atomic_dec(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+
+ cmd = TASK_CMD(task);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&task->task_active, 1);
+ atomic_set(&task->task_sent, 1);
+ atomic_inc(&T_TASK(cmd)->t_task_cdbs_sent);
+
+ if (atomic_read(&T_TASK(cmd)->t_task_cdbs_sent) ==
+ T_TASK(cmd)->t_task_cdbs)
+ atomic_set(&cmd->transport_sent, 1);
+
+ transport_start_task_timer(task);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * The struct se_cmd->transport_emulate_cdb() function pointer is used
+ * to grab REPORT_LUNS CDBs before they hit the
+ * struct se_subsystem_api->do_task() caller below.
+ */
+ if (cmd->transport_emulate_cdb) {
+ error = cmd->transport_emulate_cdb(cmd);
+ if (error != 0) {
+ cmd->transport_error_status = error;
+ atomic_set(&task->task_active, 0);
+ atomic_set(&cmd->transport_sent, 0);
+ transport_stop_tasks_for_cmd(cmd);
+ transport_generic_request_failure(cmd, dev, 0, 1);
+ goto check_depth;
+ }
+ /*
+ * Handle the successful completion for transport_emulate_cdb()
+ * for synchronous operation, following SCF_EMULATE_CDB_ASYNC
+ * Otherwise the caller is expected to complete the task with
+ * proper status.
+ */
+ if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
+ cmd->scsi_status = SAM_STAT_GOOD;
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ } else {
+ /*
+ * Currently for all virtual TCM plugins including IBLOCK, FILEIO and
+ * RAMDISK we use the internal transport_emulate_control_cdb() logic
+ * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK
+ * LUN emulation code.
+ *
+ * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we
+ * call ->do_task() directly and let the underlying TCM subsystem plugin
+ * code handle the CDB emulation.
+ */
+ if ((TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
+ error = transport_emulate_control_cdb(task);
+ else
+ error = TRANSPORT(dev)->do_task(task);
+
+ if (error != 0) {
+ cmd->transport_error_status = error;
+ atomic_set(&task->task_active, 0);
+ atomic_set(&cmd->transport_sent, 0);
+ transport_stop_tasks_for_cmd(cmd);
+ transport_generic_request_failure(cmd, dev, 0, 1);
+ }
+ }
+
+ goto check_depth;
+
+ return 0;
+}
+
+void transport_new_cmd_failure(struct se_cmd *se_cmd)
+{
+ unsigned long flags;
+ /*
+ * Any unsolicited data will get dumped for failed command inside of
+ * the fabric plugin
+ */
+ spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags);
+ se_cmd->se_cmd_flags |= SCF_SE_CMD_FAILED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags);
+
+ CMD_TFO(se_cmd)->new_cmd_failure(se_cmd);
+}
+
+static void transport_nop_wait_for_tasks(struct se_cmd *, int, int);
+
+static inline u32 transport_get_sectors_6(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 8-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * Use 24-bit allocation length for TYPE_TAPE.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE)
+ return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4];
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 8-bit sector value.
+ */
+type_disk:
+ return (u32)cdb[4];
+}
+
+static inline u32 transport_get_sectors_10(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 16-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * XXX_10 is not defined in SSC, throw an exception
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ *ret = -1;
+ return 0;
+ }
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 16-bit sector value.
+ */
+type_disk:
+ return (u32)(cdb[7] << 8) + cdb[8];
+}
+
+static inline u32 transport_get_sectors_12(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * XXX_12 is not defined in SSC, throw an exception
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ *ret = -1;
+ return 0;
+ }
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 32-bit sector value.
+ */
+type_disk:
+ return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
+}
+
+static inline u32 transport_get_sectors_16(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * Use 24-bit allocation length for TYPE_TAPE.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE)
+ return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14];
+
+type_disk:
+ return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
+ (cdb[12] << 8) + cdb[13];
+}
+
+/*
+ * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
+ */
+static inline u32 transport_get_sectors_32(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
+ (cdb[30] << 8) + cdb[31];
+
+}
+
+static inline u32 transport_get_size(
+ u32 sectors,
+ unsigned char *cdb,
+ struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ if (cdb[1] & 1) { /* sectors */
+ return DEV_ATTRIB(dev)->block_size * sectors;
+ } else /* bytes */
+ return sectors;
+ }
+#if 0
+ printk(KERN_INFO "Returning block_size: %u, sectors: %u == %u for"
+ " %s object\n", DEV_ATTRIB(dev)->block_size, sectors,
+ DEV_ATTRIB(dev)->block_size * sectors,
+ TRANSPORT(dev)->name);
+#endif
+ return DEV_ATTRIB(dev)->block_size * sectors;
+}
+
+unsigned char transport_asciihex_to_binaryhex(unsigned char val[2])
+{
+ unsigned char result = 0;
+ /*
+ * MSB
+ */
+ if ((val[0] >= 'a') && (val[0] <= 'f'))
+ result = ((val[0] - 'a' + 10) & 0xf) << 4;
+ else
+ if ((val[0] >= 'A') && (val[0] <= 'F'))
+ result = ((val[0] - 'A' + 10) & 0xf) << 4;
+ else /* digit */
+ result = ((val[0] - '0') & 0xf) << 4;
+ /*
+ * LSB
+ */
+ if ((val[1] >= 'a') && (val[1] <= 'f'))
+ result |= ((val[1] - 'a' + 10) & 0xf);
+ else
+ if ((val[1] >= 'A') && (val[1] <= 'F'))
+ result |= ((val[1] - 'A' + 10) & 0xf);
+ else /* digit */
+ result |= ((val[1] - '0') & 0xf);
+
+ return result;
+}
+EXPORT_SYMBOL(transport_asciihex_to_binaryhex);
+
+static void transport_xor_callback(struct se_cmd *cmd)
+{
+ unsigned char *buf, *addr;
+ struct se_mem *se_mem;
+ unsigned int offset;
+ int i;
+ /*
+ * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
+ *
+ * 1) read the specified logical block(s);
+ * 2) transfer logical blocks from the data-out buffer;
+ * 3) XOR the logical blocks transferred from the data-out buffer with
+ * the logical blocks read, storing the resulting XOR data in a buffer;
+ * 4) if the DISABLE WRITE bit is set to zero, then write the logical
+ * blocks transferred from the data-out buffer; and
+ * 5) transfer the resulting XOR data to the data-in buffer.
+ */
+ buf = kmalloc(cmd->data_length, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate xor_callback buf\n");
+ return;
+ }
+ /*
+ * Copy the scatterlist WRITE buffer located at T_TASK(cmd)->t_mem_list
+ * into the locally allocated *buf
+ */
+ transport_memcpy_se_mem_read_contig(cmd, buf, T_TASK(cmd)->t_mem_list);
+ /*
+ * Now perform the XOR against the BIDI read memory located at
+ * T_TASK(cmd)->t_mem_bidi_list
+ */
+
+ offset = 0;
+ list_for_each_entry(se_mem, T_TASK(cmd)->t_mem_bidi_list, se_list) {
+ addr = (unsigned char *)kmap_atomic(se_mem->se_page, KM_USER0);
+ if (!(addr))
+ goto out;
+
+ for (i = 0; i < se_mem->se_len; i++)
+ *(addr + se_mem->se_off + i) ^= *(buf + offset + i);
+
+ offset += se_mem->se_len;
+ kunmap_atomic(addr, KM_USER0);
+ }
+out:
+ kfree(buf);
+}
+
+/*
+ * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
+ */
+static int transport_get_sense_data(struct se_cmd *cmd)
+{
+ unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
+ struct se_device *dev;
+ struct se_task *task = NULL, *task_tmp;
+ unsigned long flags;
+ u32 offset = 0;
+
+ if (!SE_LUN(cmd)) {
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return 0;
+ }
+
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+
+ if (!task->task_sense)
+ continue;
+
+ dev = task->se_dev;
+ if (!(dev))
+ continue;
+
+ if (!TRANSPORT(dev)->get_sense_buffer) {
+ printk(KERN_ERR "TRANSPORT(dev)->get_sense_buffer"
+ " is NULL\n");
+ continue;
+ }
+
+ sense_buffer = TRANSPORT(dev)->get_sense_buffer(task);
+ if (!(sense_buffer)) {
+ printk(KERN_ERR "ITT[0x%08x]_TASK[%d]: Unable to locate"
+ " sense buffer for task with sense\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), task->task_no);
+ continue;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd,
+ TRANSPORT_SENSE_BUFFER);
+
+ memcpy((void *)&buffer[offset], (void *)sense_buffer,
+ TRANSPORT_SENSE_BUFFER);
+ cmd->scsi_status = task->task_scsi_status;
+ /* Automatically padded */
+ cmd->scsi_sense_length =
+ (TRANSPORT_SENSE_BUFFER + offset);
+
+ printk(KERN_INFO "HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x"
+ " and sense\n",
+ dev->se_hba->hba_id, TRANSPORT(dev)->name,
+ cmd->scsi_status);
+ return 0;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return -1;
+}
+
+static int transport_allocate_resources(struct se_cmd *cmd)
+{
+ u32 length = cmd->data_length;
+
+ if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB))
+ return transport_generic_get_mem(cmd, length, PAGE_SIZE);
+ else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB)
+ return transport_generic_allocate_buf(cmd, length);
+ else
+ return 0;
+}
+
+static int
+transport_handle_reservation_conflict(struct se_cmd *cmd)
+{
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+ /*
+ * For UA Interlock Code 11b, a RESERVATION CONFLICT will
+ * establish a UNIT ATTENTION with PREVIOUS RESERVATION
+ * CONFLICT STATUS.
+ *
+ * See spc4r17, section 7.4.6 Control Mode Page, Table 349
+ */
+ if (SE_SESS(cmd) &&
+ DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2)
+ core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl,
+ cmd->orig_fe_lun, 0x2C,
+ ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
+ return -2;
+}
+
+/* transport_generic_cmd_sequencer():
+ *
+ * Generic Command Sequencer that should work for most DAS transport
+ * drivers.
+ *
+ * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD
+ * RX Thread.
+ *
+ * FIXME: Need to support other SCSI OPCODES where as well.
+ */
+static int transport_generic_cmd_sequencer(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ int ret = 0, sector_ret = 0, passthrough;
+ u32 sectors = 0, size = 0, pr_reg_type = 0;
+ u16 service_action;
+ u8 alua_ascq = 0;
+ /*
+ * Check for an existing UNIT ATTENTION condition
+ */
+ if (core_scsi3_ua_check(cmd, cdb) < 0) {
+ cmd->transport_wait_for_tasks =
+ &transport_nop_wait_for_tasks;
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
+ return -2;
+ }
+ /*
+ * Check status of Asymmetric Logical Unit Assignment port
+ */
+ ret = T10_ALUA(su_dev)->alua_state_check(cmd, cdb, &alua_ascq);
+ if (ret != 0) {
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ /*
+ * Set SCSI additional sense code (ASC) to 'LUN Not Accessable';
+ * The ALUA additional sense code qualifier (ASCQ) is determined
+ * by the ALUA primary or secondary access state..
+ */
+ if (ret > 0) {
+#if 0
+ printk(KERN_INFO "[%s]: ALUA TG Port not available,"
+ " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n",
+ CMD_TFO(cmd)->get_fabric_name(), alua_ascq);
+#endif
+ transport_set_sense_codes(cmd, 0x04, alua_ascq);
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
+ return -2;
+ }
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Check status for SPC-3 Persistent Reservations
+ */
+ if (T10_PR_OPS(su_dev)->t10_reservation_check(cmd, &pr_reg_type) != 0) {
+ if (T10_PR_OPS(su_dev)->t10_seq_non_holder(
+ cmd, cdb, pr_reg_type) != 0)
+ return transport_handle_reservation_conflict(cmd);
+ /*
+ * This means the CDB is allowed for the SCSI Initiator port
+ * when said port is *NOT* holding the legacy SPC-2 or
+ * SPC-3 Persistent Reservation.
+ */
+ }
+
+ switch (cdb[0]) {
+ case READ_6:
+ sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_6;
+ T_TASK(cmd)->t_task_lba = transport_lba_21(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_10:
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_12:
+ sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_12;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_16;
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_6:
+ sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_6;
+ T_TASK(cmd)->t_task_lba = transport_lba_21(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_10:
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_12:
+ sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_12;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_16;
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case XDWRITEREAD_10:
+ if ((cmd->data_direction != DMA_TO_DEVICE) ||
+ !(T_TASK(cmd)->t_tasks_bidi))
+ goto out_invalid_cdb_field;
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+ /*
+ * Setup BIDI XOR callback to be run during transport_generic_complete_ok()
+ */
+ cmd->transport_complete_callback = &transport_xor_callback;
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ break;
+ case VARIABLE_LENGTH_CMD:
+ service_action = get_unaligned_be16(&cdb[8]);
+ /*
+ * Determine if this is TCM/PSCSI device and we should disable
+ * internal emulation for this CDB.
+ */
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+
+ switch (service_action) {
+ case XDWRITEREAD_32:
+ sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ /*
+ * Use WRITE_32 and READ_32 opcodes for the emulated
+ * XDWRITE_READ_32 logic.
+ */
+ cmd->transport_split_cdb = &split_cdb_XX_32;
+ T_TASK(cmd)->t_task_lba = transport_lba_64_ext(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+
+ /*
+ * Setup BIDI XOR callback to be run during
+ * transport_generic_complete_ok()
+ */
+ cmd->transport_complete_callback = &transport_xor_callback;
+ T_TASK(cmd)->t_tasks_fua = (cdb[10] & 0x8);
+ break;
+ case WRITE_SAME_32:
+ sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ T_TASK(cmd)->t_task_lba = get_unaligned_be64(&cdb[12]);
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+
+ if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) {
+ printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(cdb[10] & 0x08)) {
+ printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not"
+ " supported for Block Discard Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ break;
+ default:
+ printk(KERN_ERR "VARIABLE_LENGTH_CMD service action"
+ " 0x%04x not supported\n", service_action);
+ goto out_unsupported_cdb;
+ }
+ break;
+ case 0xa3:
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
+ /* MAINTENANCE_IN from SCC-2 */
+ /*
+ * Check for emulated MI_REPORT_TARGET_PGS.
+ */
+ if (cdb[1] == MI_REPORT_TARGET_PGS) {
+ cmd->transport_emulate_cdb =
+ (T10_ALUA(su_dev)->alua_type ==
+ SPC3_ALUA_EMULATED) ?
+ &core_emulate_report_target_port_groups :
+ NULL;
+ }
+ size = (cdb[6] << 24) | (cdb[7] << 16) |
+ (cdb[8] << 8) | cdb[9];
+ } else {
+ /* GPCMD_SEND_KEY from multi media commands */
+ size = (cdb[8] << 8) + cdb[9];
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case MODE_SELECT:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case MODE_SELECT_10:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case MODE_SENSE:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case MODE_SENSE_10:
+ case GPCMD_READ_BUFFER_CAPACITY:
+ case GPCMD_SEND_OPC:
+ case LOG_SELECT:
+ case LOG_SENSE:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_BLOCK_LIMITS:
+ size = READ_BLOCK_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case GPCMD_GET_CONFIGURATION:
+ case GPCMD_READ_FORMAT_CAPACITIES:
+ case GPCMD_READ_DISC_INFO:
+ case GPCMD_READ_TRACK_RZONE_INFO:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type ==
+ SPC3_PERSISTENT_RESERVATIONS) ?
+ &core_scsi3_emulate_pr : NULL;
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case GPCMD_MECHANISM_STATUS:
+ case GPCMD_READ_DVD_STRUCTURE:
+ size = (cdb[8] << 8) + cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case READ_POSITION:
+ size = READ_POSITION_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case 0xa4:
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
+ /* MAINTENANCE_OUT from SCC-2
+ *
+ * Check for emulated MO_SET_TARGET_PGS.
+ */
+ if (cdb[1] == MO_SET_TARGET_PGS) {
+ cmd->transport_emulate_cdb =
+ (T10_ALUA(su_dev)->alua_type ==
+ SPC3_ALUA_EMULATED) ?
+ &core_emulate_set_target_port_groups :
+ NULL;
+ }
+
+ size = (cdb[6] << 24) | (cdb[7] << 16) |
+ (cdb[8] << 8) | cdb[9];
+ } else {
+ /* GPCMD_REPORT_KEY from multi media commands */
+ size = (cdb[8] << 8) + cdb[9];
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case INQUIRY:
+ size = (cdb[3] << 8) + cdb[4];
+ /*
+ * Do implict HEAD_OF_QUEUE processing for INQUIRY.
+ * See spc4r17 section 5.3
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ cmd->sam_task_attr = TASK_ATTR_HOQ;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_BUFFER:
+ size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_CAPACITY:
+ size = READ_CAP_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_MEDIA_SERIAL_NUMBER:
+ case SECURITY_PROTOCOL_IN:
+ case SECURITY_PROTOCOL_OUT:
+ size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case SERVICE_ACTION_IN:
+ case ACCESS_CONTROL_IN:
+ case ACCESS_CONTROL_OUT:
+ case EXTENDED_COPY:
+ case READ_ATTRIBUTE:
+ case RECEIVE_COPY_RESULTS:
+ case WRITE_ATTRIBUTE:
+ size = (cdb[10] << 24) | (cdb[11] << 16) |
+ (cdb[12] << 8) | cdb[13];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case RECEIVE_DIAGNOSTIC:
+ case SEND_DIAGNOSTIC:
+ size = (cdb[3] << 8) | cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */
+#if 0
+ case GPCMD_READ_CD:
+ sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ size = (2336 * sectors);
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+#endif
+ case READ_TOC:
+ size = cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case REQUEST_SENSE:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_ELEMENT_STATUS:
+ size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case WRITE_BUFFER:
+ size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case RESERVE:
+ case RESERVE_10:
+ /*
+ * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
+ * Assume the passthrough or $FABRIC_MOD will tell us about it.
+ */
+ if (cdb[0] == RESERVE_10)
+ size = (cdb[7] << 8) | cdb[8];
+ else
+ size = cmd->data_length;
+
+ /*
+ * Setup the legacy emulated handler for SPC-2 and
+ * >= SPC-3 compatible reservation handling (CRH=1)
+ * Otherwise, we assume the underlying SCSI logic is
+ * is running in SPC_PASSTHROUGH, and wants reservations
+ * emulation disabled.
+ */
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type !=
+ SPC_PASSTHROUGH) ?
+ &core_scsi2_emulate_crh : NULL;
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case RELEASE:
+ case RELEASE_10:
+ /*
+ * The SPC-2 RELEASE does not contain a size in the SCSI CDB.
+ * Assume the passthrough or $FABRIC_MOD will tell us about it.
+ */
+ if (cdb[0] == RELEASE_10)
+ size = (cdb[7] << 8) | cdb[8];
+ else
+ size = cmd->data_length;
+
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type !=
+ SPC_PASSTHROUGH) ?
+ &core_scsi2_emulate_crh : NULL;
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case SYNCHRONIZE_CACHE:
+ case 0x91: /* SYNCHRONIZE_CACHE_16: */
+ /*
+ * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
+ */
+ if (cdb[0] == SYNCHRONIZE_CACHE) {
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ } else {
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ }
+ if (sector_ret)
+ goto out_unsupported_cdb;
+
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+
+ /*
+ * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb()
+ */
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+ break;
+ /*
+ * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation
+ * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks()
+ */
+ cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
+ /*
+ * Check to ensure that LBA + Range does not exceed past end of
+ * device.
+ */
+ if (transport_get_sectors(cmd) < 0)
+ goto out_invalid_cdb_field;
+ break;
+ case UNMAP:
+ size = get_unaligned_be16(&cdb[7]);
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Determine if the received UNMAP used to for direct passthrough
+ * into Linux/SCSI with struct request via TCM/pSCSI or we are
+ * signaling the use of internal transport_generic_unmap() emulation
+ * for UNMAP -> Linux/BLOCK disbard with TCM/IBLOCK and TCM/FILEIO
+ * subsystem plugin backstores.
+ */
+ if (!(passthrough))
+ cmd->se_cmd_flags |= SCF_EMULATE_SYNC_UNMAP;
+
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case WRITE_SAME_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ T_TASK(cmd)->t_task_lba = get_unaligned_be16(&cdb[2]);
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Determine if the received WRITE_SAME_16 is used to for direct
+ * passthrough into Linux/SCSI with struct request via TCM/pSCSI
+ * or we are signaling the use of internal WRITE_SAME + UNMAP=1
+ * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and
+ * TCM/FILEIO subsystem plugin backstores.
+ */
+ if (!(passthrough)) {
+ if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) {
+ printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(cdb[1] & 0x08)) {
+ printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not "
+ " supported for Block Discard Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case GPCMD_CLOSE_TRACK:
+ case ERASE:
+ case INITIALIZE_ELEMENT_STATUS:
+ case GPCMD_LOAD_UNLOAD:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case GPCMD_SET_SPEED:
+ case SPACE:
+ case START_STOP:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case MOVE_MEDIUM:
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case REPORT_LUNS:
+ cmd->transport_emulate_cdb =
+ &transport_core_report_lun_response;
+ size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+ /*
+ * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
+ * See spc4r17 section 5.3
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ cmd->sam_task_attr = TASK_ATTR_HOQ;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ default:
+ printk(KERN_WARNING "TARGET_CORE[%s]: Unsupported SCSI Opcode"
+ " 0x%02x, sending CHECK_CONDITION.\n",
+ CMD_TFO(cmd)->get_fabric_name(), cdb[0]);
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ goto out_unsupported_cdb;
+ }
+
+ if (size != cmd->data_length) {
+ printk(KERN_WARNING "TARGET_CORE[%s]: Expected Transfer Length:"
+ " %u does not match SCSI CDB Length: %u for SAM Opcode:"
+ " 0x%02x\n", CMD_TFO(cmd)->get_fabric_name(),
+ cmd->data_length, size, cdb[0]);
+
+ cmd->cmd_spdtl = size;
+
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ printk(KERN_ERR "Rejecting underflow/overflow"
+ " WRITE data\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Reject READ_* or WRITE_* with overflow/underflow for
+ * type SCF_SCSI_DATA_SG_IO_CDB.
+ */
+ if (!(ret) && (DEV_ATTRIB(dev)->block_size != 512)) {
+ printk(KERN_ERR "Failing OVERFLOW/UNDERFLOW for LBA op"
+ " CDB on non 512-byte sector setup subsystem"
+ " plugin: %s\n", TRANSPORT(dev)->name);
+ /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
+ goto out_invalid_cdb_field;
+ }
+
+ if (size > cmd->data_length) {
+ cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
+ cmd->residual_count = (size - cmd->data_length);
+ } else {
+ cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+ cmd->residual_count = (cmd->data_length - size);
+ }
+ cmd->data_length = size;
+ }
+
+ transport_set_supported_SAM_opcode(cmd);
+ return ret;
+
+out_unsupported_cdb:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ return -2;
+out_invalid_cdb_field:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -2;
+}
+
+static inline void transport_release_tasks(struct se_cmd *);
+
+/*
+ * This function will copy a contiguous *src buffer into a destination
+ * struct scatterlist array.
+ */
+static void transport_memcpy_write_contig(
+ struct se_cmd *cmd,
+ struct scatterlist *sg_d,
+ unsigned char *src)
+{
+ u32 i = 0, length = 0, total_length = cmd->data_length;
+ void *dst;
+
+ while (total_length) {
+ length = sg_d[i].length;
+
+ if (length > total_length)
+ length = total_length;
+
+ dst = sg_virt(&sg_d[i]);
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ src += length;
+ i++;
+ }
+}
+
+/*
+ * This function will copy a struct scatterlist array *sg_s into a destination
+ * contiguous *dst buffer.
+ */
+static void transport_memcpy_read_contig(
+ struct se_cmd *cmd,
+ unsigned char *dst,
+ struct scatterlist *sg_s)
+{
+ u32 i = 0, length = 0, total_length = cmd->data_length;
+ void *src;
+
+ while (total_length) {
+ length = sg_s[i].length;
+
+ if (length > total_length)
+ length = total_length;
+
+ src = sg_virt(&sg_s[i]);
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ dst += length;
+ i++;
+ }
+}
+
+static void transport_memcpy_se_mem_read_contig(
+ struct se_cmd *cmd,
+ unsigned char *dst,
+ struct list_head *se_mem_list)
+{
+ struct se_mem *se_mem;
+ void *src;
+ u32 length = 0, total_length = cmd->data_length;
+
+ list_for_each_entry(se_mem, se_mem_list, se_list) {
+ length = se_mem->se_len;
+
+ if (length > total_length)
+ length = total_length;
+
+ src = page_address(se_mem->se_page) + se_mem->se_off;
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ dst += length;
+ }
+}
+
+/*
+ * Called from transport_generic_complete_ok() and
+ * transport_generic_request_failure() to determine which dormant/delayed
+ * and ordered cmds need to have their tasks added to the execution queue.
+ */
+static void transport_complete_task_attr(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_cmd *cmd_p, *cmd_tmp;
+ int new_active_tasks = 0;
+
+ if (cmd->sam_task_attr == TASK_ATTR_SIMPLE) {
+ atomic_dec(&dev->simple_cmds);
+ smp_mb__after_atomic_dec();
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev->dev_cur_ordered_id: %u for"
+ " SIMPLE: %u\n", dev->dev_cur_ordered_id,
+ cmd->se_ordered_id);
+ } else if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ atomic_dec(&dev->dev_hoq_count);
+ smp_mb__after_atomic_dec();
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev_cur_ordered_id: %u for"
+ " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id,
+ cmd->se_ordered_id);
+ } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+ spin_lock(&dev->ordered_cmd_lock);
+ list_del(&cmd->se_ordered_list);
+ atomic_dec(&dev->dev_ordered_sync);
+ smp_mb__after_atomic_dec();
+ spin_unlock(&dev->ordered_cmd_lock);
+
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev_cur_ordered_id: %u for ORDERED:"
+ " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id);
+ }
+ /*
+ * Process all commands up to the last received
+ * ORDERED task attribute which requires another blocking
+ * boundary
+ */
+ spin_lock(&dev->delayed_cmd_lock);
+ list_for_each_entry_safe(cmd_p, cmd_tmp,
+ &dev->delayed_cmd_list, se_delayed_list) {
+
+ list_del(&cmd_p->se_delayed_list);
+ spin_unlock(&dev->delayed_cmd_lock);
+
+ DEBUG_STA("Calling add_tasks() for"
+ " cmd_p: 0x%02x Task Attr: 0x%02x"
+ " Dormant -> Active, se_ordered_id: %u\n",
+ T_TASK(cmd_p)->t_task_cdb[0],
+ cmd_p->sam_task_attr, cmd_p->se_ordered_id);
+
+ transport_add_tasks_from_cmd(cmd_p);
+ new_active_tasks++;
+
+ spin_lock(&dev->delayed_cmd_lock);
+ if (cmd_p->sam_task_attr == TASK_ATTR_ORDERED)
+ break;
+ }
+ spin_unlock(&dev->delayed_cmd_lock);
+ /*
+ * If new tasks have become active, wake up the transport thread
+ * to do the processing of the Active tasks.
+ */
+ if (new_active_tasks != 0)
+ wake_up_interruptible(&dev->dev_queue_obj->thread_wq);
+}
+
+static void transport_generic_complete_ok(struct se_cmd *cmd)
+{
+ int reason = 0;
+ /*
+ * Check if we need to move delayed/dormant tasks from cmds on the
+ * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task
+ * Attribute.
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+ /*
+ * Check if we need to retrieve a sense buffer from
+ * the struct se_cmd in question.
+ */
+ if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+ if (transport_get_sense_data(cmd) < 0)
+ reason = TCM_NON_EXISTENT_LUN;
+
+ /*
+ * Only set when an struct se_task->task_scsi_status returned
+ * a non GOOD status.
+ */
+ if (cmd->scsi_status) {
+ transport_send_check_condition_and_sense(
+ cmd, reason, 1);
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
+ return;
+ }
+ }
+ /*
+ * Check for a callback, used by amoungst other things
+ * XDWRITE_READ_10 emulation.
+ */
+ if (cmd->transport_complete_callback)
+ cmd->transport_complete_callback(cmd);
+
+ switch (cmd->data_direction) {
+ case DMA_FROM_DEVICE:
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ /*
+ * If enabled by TCM fabirc module pre-registered SGL
+ * memory, perform the memcpy() from the TCM internal
+ * contigious buffer back to the original SGL.
+ */
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
+ transport_memcpy_write_contig(cmd,
+ T_TASK(cmd)->t_task_pt_sgl,
+ T_TASK(cmd)->t_task_buf);
+
+ CMD_TFO(cmd)->queue_data_in(cmd);
+ break;
+ case DMA_TO_DEVICE:
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.rx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ /*
+ * Check if we need to send READ payload for BIDI-COMMAND
+ */
+ if (T_TASK(cmd)->t_mem_bidi_list != NULL) {
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ CMD_TFO(cmd)->queue_data_in(cmd);
+ break;
+ }
+ /* Fall through for DMA_TO_DEVICE */
+ case DMA_NONE:
+ CMD_TFO(cmd)->queue_status(cmd);
+ break;
+ default:
+ break;
+ }
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
+}
+
+static void transport_free_dev_tasks(struct se_cmd *cmd)
+{
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_active))
+ continue;
+
+ kfree(task->task_sg_bidi);
+ kfree(task->task_sg);
+
+ list_del(&task->t_list);
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ if (task->se_dev)
+ TRANSPORT(task->se_dev)->free_task(task);
+ else
+ printk(KERN_ERR "task[%u] - task->se_dev is NULL\n",
+ task->task_no);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static inline void transport_free_pages(struct se_cmd *cmd)
+{
+ struct se_mem *se_mem, *se_mem_tmp;
+ int free_page = 1;
+
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)
+ free_page = 0;
+ if (cmd->se_dev->transport->do_se_mem_map)
+ free_page = 0;
+
+ if (T_TASK(cmd)->t_task_buf) {
+ kfree(T_TASK(cmd)->t_task_buf);
+ T_TASK(cmd)->t_task_buf = NULL;
+ return;
+ }
+
+ /*
+ * Caller will handle releasing of struct se_mem.
+ */
+ if (cmd->se_cmd_flags & SCF_CMD_PASSTHROUGH_NOALLOC)
+ return;
+
+ if (!(T_TASK(cmd)->t_tasks_se_num))
+ return;
+
+ list_for_each_entry_safe(se_mem, se_mem_tmp,
+ T_TASK(cmd)->t_mem_list, se_list) {
+ /*
+ * We only release call __free_page(struct se_mem->se_page) when
+ * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use,
+ */
+ if (free_page)
+ __free_page(se_mem->se_page);
+
+ list_del(&se_mem->se_list);
+ kmem_cache_free(se_mem_cache, se_mem);
+ }
+
+ if (T_TASK(cmd)->t_mem_bidi_list && T_TASK(cmd)->t_tasks_se_bidi_num) {
+ list_for_each_entry_safe(se_mem, se_mem_tmp,
+ T_TASK(cmd)->t_mem_bidi_list, se_list) {
+ /*
+ * We only release call __free_page(struct se_mem->se_page) when
+ * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use,
+ */
+ if (free_page)
+ __free_page(se_mem->se_page);
+
+ list_del(&se_mem->se_list);
+ kmem_cache_free(se_mem_cache, se_mem);
+ }
+ }
+
+ kfree(T_TASK(cmd)->t_mem_bidi_list);
+ T_TASK(cmd)->t_mem_bidi_list = NULL;
+ kfree(T_TASK(cmd)->t_mem_list);
+ T_TASK(cmd)->t_mem_list = NULL;
+ T_TASK(cmd)->t_tasks_se_num = 0;
+}
+
+static inline void transport_release_tasks(struct se_cmd *cmd)
+{
+ transport_free_dev_tasks(cmd);
+}
+
+static inline int transport_dec_and_check(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_fe_count))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return 1;
+ }
+ }
+
+ if (atomic_read(&T_TASK(cmd)->t_se_count)) {
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_se_count))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+}
+
+static void transport_release_fe_cmd(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ if (transport_dec_and_check(cmd))
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto free_pages;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_release_tasks(cmd);
+free_pages:
+ transport_free_pages(cmd);
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_direct(cmd);
+}
+
+static int transport_generic_remove(
+ struct se_cmd *cmd,
+ int release_to_pool,
+ int session_reinstatement)
+{
+ unsigned long flags;
+
+ if (!(T_TASK(cmd)))
+ goto release_cmd;
+
+ if (transport_dec_and_check(cmd)) {
+ if (session_reinstatement) {
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ }
+ return 1;
+ }
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto free_pages;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_release_tasks(cmd);
+free_pages:
+ transport_free_pages(cmd);
+
+release_cmd:
+ if (release_to_pool) {
+ transport_release_cmd_to_pool(cmd);
+ } else {
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_direct(cmd);
+ }
+
+ return 0;
+}
+
+/*
+ * transport_generic_map_mem_to_cmd - Perform SGL -> struct se_mem map
+ * @cmd: Associated se_cmd descriptor
+ * @mem: SGL style memory for TCM WRITE / READ
+ * @sg_mem_num: Number of SGL elements
+ * @mem_bidi_in: SGL style memory for TCM BIDI READ
+ * @sg_mem_bidi_num: Number of BIDI READ SGL elements
+ *
+ * Return: nonzero return cmd was rejected for -ENOMEM or inproper usage
+ * of parameters.
+ */
+int transport_generic_map_mem_to_cmd(
+ struct se_cmd *cmd,
+ struct scatterlist *mem,
+ u32 sg_mem_num,
+ struct scatterlist *mem_bidi_in,
+ u32 sg_mem_bidi_num)
+{
+ u32 se_mem_cnt_out = 0;
+ int ret;
+
+ if (!(mem) || !(sg_mem_num))
+ return 0;
+ /*
+ * Passed *mem will contain a list_head containing preformatted
+ * struct se_mem elements...
+ */
+ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM)) {
+ if ((mem_bidi_in) || (sg_mem_bidi_num)) {
+ printk(KERN_ERR "SCF_CMD_PASSTHROUGH_NOALLOC not supported"
+ " with BIDI-COMMAND\n");
+ return -ENOSYS;
+ }
+
+ T_TASK(cmd)->t_mem_list = (struct list_head *)mem;
+ T_TASK(cmd)->t_tasks_se_num = sg_mem_num;
+ cmd->se_cmd_flags |= SCF_CMD_PASSTHROUGH_NOALLOC;
+ return 0;
+ }
+ /*
+ * Otherwise, assume the caller is passing a struct scatterlist
+ * array from include/linux/scatterlist.h
+ */
+ if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ /*
+ * For CDB using TCM struct se_mem linked list scatterlist memory
+ * processed into a TCM struct se_subsystem_dev, we do the mapping
+ * from the passed physical memory to struct se_mem->se_page here.
+ */
+ T_TASK(cmd)->t_mem_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_list))
+ return -ENOMEM;
+
+ ret = transport_map_sg_to_mem(cmd,
+ T_TASK(cmd)->t_mem_list, mem, &se_mem_cnt_out);
+ if (ret < 0)
+ return -ENOMEM;
+
+ T_TASK(cmd)->t_tasks_se_num = se_mem_cnt_out;
+ /*
+ * Setup BIDI READ list of struct se_mem elements
+ */
+ if ((mem_bidi_in) && (sg_mem_bidi_num)) {
+ T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_bidi_list)) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+ se_mem_cnt_out = 0;
+
+ ret = transport_map_sg_to_mem(cmd,
+ T_TASK(cmd)->t_mem_bidi_list, mem_bidi_in,
+ &se_mem_cnt_out);
+ if (ret < 0) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+
+ T_TASK(cmd)->t_tasks_se_bidi_num = se_mem_cnt_out;
+ }
+ cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+
+ } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ if (mem_bidi_in || sg_mem_bidi_num) {
+ printk(KERN_ERR "BIDI-Commands not supported using "
+ "SCF_SCSI_CONTROL_NONSG_IO_CDB\n");
+ return -ENOSYS;
+ }
+ /*
+ * For incoming CDBs using a contiguous buffer internall with TCM,
+ * save the passed struct scatterlist memory. After TCM storage object
+ * processing has completed for this struct se_cmd, TCM core will call
+ * transport_memcpy_[write,read]_contig() as necessary from
+ * transport_generic_complete_ok() and transport_write_pending() in order
+ * to copy the TCM buffer to/from the original passed *mem in SGL ->
+ * struct scatterlist format.
+ */
+ cmd->se_cmd_flags |= SCF_PASSTHROUGH_CONTIG_TO_SG;
+ T_TASK(cmd)->t_task_pt_sgl = mem;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
+
+
+static inline long long transport_dev_end_lba(struct se_device *dev)
+{
+ return dev->transport->get_blocks(dev) + 1;
+}
+
+static int transport_get_sectors(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ T_TASK(cmd)->t_tasks_sectors =
+ (cmd->data_length / DEV_ATTRIB(dev)->block_size);
+ if (!(T_TASK(cmd)->t_tasks_sectors))
+ T_TASK(cmd)->t_tasks_sectors = 1;
+
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_DISK)
+ return 0;
+
+ if ((T_TASK(cmd)->t_task_lba + T_TASK(cmd)->t_tasks_sectors) >
+ transport_dev_end_lba(dev)) {
+ printk(KERN_ERR "LBA: %llu Sectors: %u exceeds"
+ " transport_dev_end_lba(): %llu\n",
+ T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors,
+ transport_dev_end_lba(dev));
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY;
+ return PYX_TRANSPORT_REQ_TOO_MANY_SECTORS;
+ }
+
+ return 0;
+}
+
+static int transport_new_cmd_obj(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ u32 task_cdbs = 0, rc;
+
+ if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) {
+ task_cdbs++;
+ T_TASK(cmd)->t_task_cdbs++;
+ } else {
+ int set_counts = 1;
+
+ /*
+ * Setup any BIDI READ tasks and memory from
+ * T_TASK(cmd)->t_mem_bidi_list so the READ struct se_tasks
+ * are queued first for the non pSCSI passthrough case.
+ */
+ if ((T_TASK(cmd)->t_mem_bidi_list != NULL) &&
+ (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) {
+ rc = transport_generic_get_cdb_count(cmd,
+ T_TASK(cmd)->t_task_lba,
+ T_TASK(cmd)->t_tasks_sectors,
+ DMA_FROM_DEVICE, T_TASK(cmd)->t_mem_bidi_list,
+ set_counts);
+ if (!(rc)) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason =
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ set_counts = 0;
+ }
+ /*
+ * Setup the tasks and memory from T_TASK(cmd)->t_mem_list
+ * Note for BIDI transfers this will contain the WRITE payload
+ */
+ task_cdbs = transport_generic_get_cdb_count(cmd,
+ T_TASK(cmd)->t_task_lba,
+ T_TASK(cmd)->t_tasks_sectors,
+ cmd->data_direction, T_TASK(cmd)->t_mem_list,
+ set_counts);
+ if (!(task_cdbs)) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason =
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ T_TASK(cmd)->t_task_cdbs += task_cdbs;
+
+#if 0
+ printk(KERN_INFO "data_length: %u, LBA: %llu t_tasks_sectors:"
+ " %u, t_task_cdbs: %u\n", obj_ptr, cmd->data_length,
+ T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors,
+ T_TASK(cmd)->t_task_cdbs);
+#endif
+ }
+
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_left, task_cdbs);
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_ex_left, task_cdbs);
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_timeout_left, task_cdbs);
+ return 0;
+}
+
+static struct list_head *transport_init_se_mem_list(void)
+{
+ struct list_head *se_mem_list;
+
+ se_mem_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!(se_mem_list)) {
+ printk(KERN_ERR "Unable to allocate memory for se_mem_list\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(se_mem_list);
+
+ return se_mem_list;
+}
+
+static int
+transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size)
+{
+ unsigned char *buf;
+ struct se_mem *se_mem;
+
+ T_TASK(cmd)->t_mem_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_list))
+ return -ENOMEM;
+
+ /*
+ * If the device uses memory mapping this is enough.
+ */
+ if (cmd->se_dev->transport->do_se_mem_map)
+ return 0;
+
+ /*
+ * Setup BIDI-COMMAND READ list of struct se_mem elements
+ */
+ if (T_TASK(cmd)->t_tasks_bidi) {
+ T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_bidi_list)) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+ }
+
+ while (length) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ goto out;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+ se_mem->se_len = (length > dma_size) ? dma_size : length;
+
+/* #warning FIXME Allocate contigous pages for struct se_mem elements */
+ se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0);
+ if (!(se_mem->se_page)) {
+ printk(KERN_ERR "alloc_pages() failed\n");
+ goto out;
+ }
+
+ buf = kmap_atomic(se_mem->se_page, KM_IRQ0);
+ if (!(buf)) {
+ printk(KERN_ERR "kmap_atomic() failed\n");
+ goto out;
+ }
+ memset(buf, 0, se_mem->se_len);
+ kunmap_atomic(buf, KM_IRQ0);
+
+ list_add_tail(&se_mem->se_list, T_TASK(cmd)->t_mem_list);
+ T_TASK(cmd)->t_tasks_se_num++;
+
+ DEBUG_MEM("Allocated struct se_mem page(%p) Length(%u)"
+ " Offset(%u)\n", se_mem->se_page, se_mem->se_len,
+ se_mem->se_off);
+
+ length -= se_mem->se_len;
+ }
+
+ DEBUG_MEM("Allocated total struct se_mem elements(%u)\n",
+ T_TASK(cmd)->t_tasks_se_num);
+
+ return 0;
+out:
+ return -1;
+}
+
+extern u32 transport_calc_sg_num(
+ struct se_task *task,
+ struct se_mem *in_se_mem,
+ u32 task_offset)
+{
+ struct se_cmd *se_cmd = task->task_se_cmd;
+ struct se_device *se_dev = SE_DEV(se_cmd);
+ struct se_mem *se_mem = in_se_mem;
+ struct target_core_fabric_ops *tfo = CMD_TFO(se_cmd);
+ u32 sg_length, task_size = task->task_size, task_sg_num_padded;
+
+ while (task_size != 0) {
+ DEBUG_SC("se_mem->se_page(%p) se_mem->se_len(%u)"
+ " se_mem->se_off(%u) task_offset(%u)\n",
+ se_mem->se_page, se_mem->se_len,
+ se_mem->se_off, task_offset);
+
+ if (task_offset == 0) {
+ if (task_size >= se_mem->se_len) {
+ sg_length = se_mem->se_len;
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list)))
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ } else {
+ sg_length = task_size;
+ task_size -= sg_length;
+ goto next;
+ }
+
+ DEBUG_SC("sg_length(%u) task_size(%u)\n",
+ sg_length, task_size);
+ } else {
+ if ((se_mem->se_len - task_offset) > task_size) {
+ sg_length = task_size;
+ task_size -= sg_length;
+ goto next;
+ } else {
+ sg_length = (se_mem->se_len - task_offset);
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list)))
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ }
+
+ DEBUG_SC("sg_length(%u) task_size(%u)\n",
+ sg_length, task_size);
+
+ task_offset = 0;
+ }
+ task_size -= sg_length;
+next:
+ DEBUG_SC("task[%u] - Reducing task_size to(%u)\n",
+ task->task_no, task_size);
+
+ task->task_sg_num++;
+ }
+ /*
+ * Check if the fabric module driver is requesting that all
+ * struct se_task->task_sg[] be chained together.. If so,
+ * then allocate an extra padding SG entry for linking and
+ * marking the end of the chained SGL.
+ */
+ if (tfo->task_sg_chaining) {
+ task_sg_num_padded = (task->task_sg_num + 1);
+ task->task_padded_sg = 1;
+ } else
+ task_sg_num_padded = task->task_sg_num;
+
+ task->task_sg = kzalloc(task_sg_num_padded *
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (!(task->task_sg)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " task->task_sg\n");
+ return 0;
+ }
+ sg_init_table(&task->task_sg[0], task_sg_num_padded);
+ /*
+ * Setup task->task_sg_bidi for SCSI READ payload for
+ * TCM/pSCSI passthrough if present for BIDI-COMMAND
+ */
+ if ((T_TASK(se_cmd)->t_mem_bidi_list != NULL) &&
+ (TRANSPORT(se_dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)) {
+ task->task_sg_bidi = kzalloc(task_sg_num_padded *
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (!(task->task_sg_bidi)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " task->task_sg_bidi\n");
+ return 0;
+ }
+ sg_init_table(&task->task_sg_bidi[0], task_sg_num_padded);
+ }
+ /*
+ * For the chaining case, setup the proper end of SGL for the
+ * initial submission struct task into struct se_subsystem_api.
+ * This will be cleared later by transport_do_task_sg_chain()
+ */
+ if (task->task_padded_sg) {
+ sg_mark_end(&task->task_sg[task->task_sg_num - 1]);
+ /*
+ * Added the 'if' check before marking end of bi-directional
+ * scatterlist (which gets created only in case of request
+ * (RD + WR).
+ */
+ if (task->task_sg_bidi)
+ sg_mark_end(&task->task_sg_bidi[task->task_sg_num - 1]);
+ }
+
+ DEBUG_SC("Successfully allocated task->task_sg_num(%u),"
+ " task_sg_num_padded(%u)\n", task->task_sg_num,
+ task_sg_num_padded);
+
+ return task->task_sg_num;
+}
+
+static inline int transport_set_tasks_sectors_disk(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ if ((lba + sectors) > transport_dev_end_lba(dev)) {
+ task->task_sectors = ((transport_dev_end_lba(dev) - lba) + 1);
+
+ if (task->task_sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ }
+ } else {
+ if (sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ } else
+ task->task_sectors = sectors;
+ }
+
+ return 0;
+}
+
+static inline int transport_set_tasks_sectors_non_disk(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ if (sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ } else
+ task->task_sectors = sectors;
+
+ return 0;
+}
+
+static inline int transport_set_tasks_sectors(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ return (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK) ?
+ transport_set_tasks_sectors_disk(task, dev, lba, sectors,
+ max_sectors_set) :
+ transport_set_tasks_sectors_non_disk(task, dev, lba, sectors,
+ max_sectors_set);
+}
+
+static int transport_map_sg_to_mem(
+ struct se_cmd *cmd,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ u32 *se_mem_cnt)
+{
+ struct se_mem *se_mem;
+ struct scatterlist *sg;
+ u32 sg_count = 1, cmd_size = cmd->data_length;
+
+ if (!in_mem) {
+ printk(KERN_ERR "No source scatterlist\n");
+ return -1;
+ }
+ sg = (struct scatterlist *)in_mem;
+
+ while (cmd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+ DEBUG_MEM("sg_to_mem: Starting loop with cmd_size: %u"
+ " sg_page: %p offset: %d length: %d\n", cmd_size,
+ sg_page(sg), sg->offset, sg->length);
+
+ se_mem->se_page = sg_page(sg);
+ se_mem->se_off = sg->offset;
+
+ if (cmd_size > sg->length) {
+ se_mem->se_len = sg->length;
+ sg = sg_next(sg);
+ sg_count++;
+ } else
+ se_mem->se_len = cmd_size;
+
+ cmd_size -= se_mem->se_len;
+
+ DEBUG_MEM("sg_to_mem: *se_mem_cnt: %u cmd_size: %u\n",
+ *se_mem_cnt, cmd_size);
+ DEBUG_MEM("sg_to_mem: Final se_page: %p se_off: %d se_len: %d\n",
+ se_mem->se_page, se_mem->se_off, se_mem->se_len);
+
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+ }
+
+ DEBUG_MEM("task[0] - Mapped(%u) struct scatterlist segments to(%u)"
+ " struct se_mem\n", sg_count, *se_mem_cnt);
+
+ if (sg_count != *se_mem_cnt)
+ BUG();
+
+ return 0;
+}
+
+/* transport_map_mem_to_sg():
+ *
+ *
+ */
+int transport_map_mem_to_sg(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct se_cmd *se_cmd = task->task_se_cmd;
+ struct se_mem *se_mem = in_se_mem;
+ struct scatterlist *sg = (struct scatterlist *)in_mem;
+ u32 task_size = task->task_size, sg_no = 0;
+
+ if (!sg) {
+ printk(KERN_ERR "Unable to locate valid struct"
+ " scatterlist pointer\n");
+ return -1;
+ }
+
+ while (task_size != 0) {
+ /*
+ * Setup the contigious array of scatterlists for
+ * this struct se_task.
+ */
+ sg_assign_page(sg, se_mem->se_page);
+
+ if (*task_offset == 0) {
+ sg->offset = se_mem->se_off;
+
+ if (task_size >= se_mem->se_len) {
+ sg->length = se_mem->se_len;
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list))) {
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ (*se_mem_cnt)++;
+ }
+ } else {
+ sg->length = task_size;
+ /*
+ * Determine if we need to calculate an offset
+ * into the struct se_mem on the next go around..
+ */
+ task_size -= sg->length;
+ if (!(task_size))
+ *task_offset = sg->length;
+
+ goto next;
+ }
+
+ } else {
+ sg->offset = (*task_offset + se_mem->se_off);
+
+ if ((se_mem->se_len - *task_offset) > task_size) {
+ sg->length = task_size;
+ /*
+ * Determine if we need to calculate an offset
+ * into the struct se_mem on the next go around..
+ */
+ task_size -= sg->length;
+ if (!(task_size))
+ *task_offset += sg->length;
+
+ goto next;
+ } else {
+ sg->length = (se_mem->se_len - *task_offset);
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list))) {
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ (*se_mem_cnt)++;
+ }
+ }
+
+ *task_offset = 0;
+ }
+ task_size -= sg->length;
+next:
+ DEBUG_MEM("task[%u] mem_to_sg - sg[%u](%p)(%u)(%u) - Reducing"
+ " task_size to(%u), task_offset: %u\n", task->task_no, sg_no,
+ sg_page(sg), sg->length, sg->offset, task_size, *task_offset);
+
+ sg_no++;
+ if (!(task_size))
+ break;
+
+ sg = sg_next(sg);
+
+ if (task_size > se_cmd->data_length)
+ BUG();
+ }
+ *out_se_mem = se_mem;
+
+ DEBUG_MEM("task[%u] - Mapped(%u) struct se_mem segments to total(%u)"
+ " SGs\n", task->task_no, *se_mem_cnt, sg_no);
+
+ return 0;
+}
+
+/*
+ * This function can be used by HW target mode drivers to create a linked
+ * scatterlist from all contiguously allocated struct se_task->task_sg[].
+ * This is intended to be called during the completion path by TCM Core
+ * when struct target_core_fabric_ops->check_task_sg_chaining is enabled.
+ */
+void transport_do_task_sg_chain(struct se_cmd *cmd)
+{
+ struct scatterlist *sg_head = NULL, *sg_link = NULL, *sg_first = NULL;
+ struct scatterlist *sg_head_cur = NULL, *sg_link_cur = NULL;
+ struct scatterlist *sg, *sg_end = NULL, *sg_end_cur = NULL;
+ struct se_task *task;
+ struct target_core_fabric_ops *tfo = CMD_TFO(cmd);
+ u32 task_sg_num = 0, sg_count = 0;
+ int i;
+
+ if (tfo->task_sg_chaining == 0) {
+ printk(KERN_ERR "task_sg_chaining is diabled for fabric module:"
+ " %s\n", tfo->get_fabric_name());
+ dump_stack();
+ return;
+ }
+ /*
+ * Walk the struct se_task list and setup scatterlist chains
+ * for each contiguosly allocated struct se_task->task_sg[].
+ */
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (!(task->task_sg) || !(task->task_padded_sg))
+ continue;
+
+ if (sg_head && sg_link) {
+ sg_head_cur = &task->task_sg[0];
+ sg_link_cur = &task->task_sg[task->task_sg_num];
+ /*
+ * Either add chain or mark end of scatterlist
+ */
+ if (!(list_is_last(&task->t_list,
+ &T_TASK(cmd)->t_task_list))) {
+ /*
+ * Clear existing SGL termination bit set in
+ * transport_calc_sg_num(), see sg_mark_end()
+ */
+ sg_end_cur = &task->task_sg[task->task_sg_num - 1];
+ sg_end_cur->page_link &= ~0x02;
+
+ sg_chain(sg_head, task_sg_num, sg_head_cur);
+ sg_count += (task->task_sg_num + 1);
+ } else
+ sg_count += task->task_sg_num;
+
+ sg_head = sg_head_cur;
+ sg_link = sg_link_cur;
+ task_sg_num = task->task_sg_num;
+ continue;
+ }
+ sg_head = sg_first = &task->task_sg[0];
+ sg_link = &task->task_sg[task->task_sg_num];
+ task_sg_num = task->task_sg_num;
+ /*
+ * Check for single task..
+ */
+ if (!(list_is_last(&task->t_list, &T_TASK(cmd)->t_task_list))) {
+ /*
+ * Clear existing SGL termination bit set in
+ * transport_calc_sg_num(), see sg_mark_end()
+ */
+ sg_end = &task->task_sg[task->task_sg_num - 1];
+ sg_end->page_link &= ~0x02;
+ sg_count += (task->task_sg_num + 1);
+ } else
+ sg_count += task->task_sg_num;
+ }
+ /*
+ * Setup the starting pointer and total t_tasks_sg_linked_no including
+ * padding SGs for linking and to mark the end.
+ */
+ T_TASK(cmd)->t_tasks_sg_chained = sg_first;
+ T_TASK(cmd)->t_tasks_sg_chained_no = sg_count;
+
+ DEBUG_CMD_M("Setup T_TASK(cmd)->t_tasks_sg_chained: %p and"
+ " t_tasks_sg_chained_no: %u\n", T_TASK(cmd)->t_tasks_sg_chained,
+ T_TASK(cmd)->t_tasks_sg_chained_no);
+
+ for_each_sg(T_TASK(cmd)->t_tasks_sg_chained, sg,
+ T_TASK(cmd)->t_tasks_sg_chained_no, i) {
+
+ DEBUG_CMD_M("SG: %p page: %p length: %d offset: %d\n",
+ sg, sg_page(sg), sg->length, sg->offset);
+ if (sg_is_chain(sg))
+ DEBUG_CMD_M("SG: %p sg_is_chain=1\n", sg);
+ if (sg_is_last(sg))
+ DEBUG_CMD_M("SG: %p sg_is_last=1\n", sg);
+ }
+
+}
+EXPORT_SYMBOL(transport_do_task_sg_chain);
+
+static int transport_do_se_mem_map(
+ struct se_device *dev,
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset_in)
+{
+ u32 task_offset = *task_offset_in;
+ int ret = 0;
+ /*
+ * se_subsystem_api_t->do_se_mem_map is used when internal allocation
+ * has been done by the transport plugin.
+ */
+ if (TRANSPORT(dev)->do_se_mem_map) {
+ ret = TRANSPORT(dev)->do_se_mem_map(task, se_mem_list,
+ in_mem, in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+ if (ret == 0)
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+
+ return ret;
+ }
+ /*
+ * This is the normal path for all normal non BIDI and BIDI-COMMAND
+ * WRITE payloads.. If we need to do BIDI READ passthrough for
+ * TCM/pSCSI the first call to transport_do_se_mem_map ->
+ * transport_calc_sg_num() -> transport_map_mem_to_sg() will do the
+ * allocation for task->task_sg_bidi, and the subsequent call to
+ * transport_do_se_mem_map() from transport_generic_get_cdb_count()
+ */
+ if (!(task->task_sg_bidi)) {
+ /*
+ * Assume default that transport plugin speaks preallocated
+ * scatterlists.
+ */
+ if (!(transport_calc_sg_num(task, in_se_mem, task_offset)))
+ return -1;
+ /*
+ * struct se_task->task_sg now contains the struct scatterlist array.
+ */
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg,
+ in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+ }
+ /*
+ * Handle the se_mem_list -> struct task->task_sg_bidi
+ * memory map for the extra BIDI READ payload
+ */
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg_bidi,
+ in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+}
+
+static u32 transport_generic_get_cdb_count(
+ struct se_cmd *cmd,
+ unsigned long long lba,
+ u32 sectors,
+ enum dma_data_direction data_direction,
+ struct list_head *mem_list,
+ int set_counts)
+{
+ unsigned char *cdb = NULL;
+ struct se_task *task;
+ struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
+ struct se_mem *se_mem_bidi = NULL, *se_mem_bidi_lout = NULL;
+ struct se_device *dev = SE_DEV(cmd);
+ int max_sectors_set = 0, ret;
+ u32 task_offset_in = 0, se_mem_cnt = 0, se_mem_bidi_cnt = 0, task_cdbs = 0;
+
+ if (!mem_list) {
+ printk(KERN_ERR "mem_list is NULL in transport_generic_get"
+ "_cdb_count()\n");
+ return 0;
+ }
+ /*
+ * While using RAMDISK_DR backstores is the only case where
+ * mem_list will ever be empty at this point.
+ */
+ if (!(list_empty(mem_list)))
+ se_mem = list_entry(mem_list->next, struct se_mem, se_list);
+ /*
+ * Check for extra se_mem_bidi mapping for BIDI-COMMANDs to
+ * struct se_task->task_sg_bidi for TCM/pSCSI passthrough operation
+ */
+ if ((T_TASK(cmd)->t_mem_bidi_list != NULL) &&
+ !(list_empty(T_TASK(cmd)->t_mem_bidi_list)) &&
+ (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV))
+ se_mem_bidi = list_entry(T_TASK(cmd)->t_mem_bidi_list->next,
+ struct se_mem, se_list);
+
+ while (sectors) {
+ DEBUG_VOL("ITT[0x%08x] LBA(%llu) SectorsLeft(%u) EOBJ(%llu)\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), lba, sectors,
+ transport_dev_end_lba(dev));
+
+ task = transport_generic_get_task(cmd, data_direction);
+ if (!(task))
+ goto out;
+
+ transport_set_tasks_sectors(task, dev, lba, sectors,
+ &max_sectors_set);
+
+ task->task_lba = lba;
+ lba += task->task_sectors;
+ sectors -= task->task_sectors;
+ task->task_size = (task->task_sectors *
+ DEV_ATTRIB(dev)->block_size);
+
+ cdb = TRANSPORT(dev)->get_cdb(task);
+ if ((cdb)) {
+ memcpy(cdb, T_TASK(cmd)->t_task_cdb,
+ scsi_command_size(T_TASK(cmd)->t_task_cdb));
+ cmd->transport_split_cdb(task->task_lba,
+ &task->task_sectors, cdb);
+ }
+
+ /*
+ * Perform the SE OBJ plugin and/or Transport plugin specific
+ * mapping for T_TASK(cmd)->t_mem_list. And setup the
+ * task->task_sg and if necessary task->task_sg_bidi
+ */
+ ret = transport_do_se_mem_map(dev, task, mem_list,
+ NULL, se_mem, &se_mem_lout, &se_mem_cnt,
+ &task_offset_in);
+ if (ret < 0)
+ goto out;
+
+ se_mem = se_mem_lout;
+ /*
+ * Setup the T_TASK(cmd)->t_mem_bidi_list -> task->task_sg_bidi
+ * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI
+ *
+ * Note that the first call to transport_do_se_mem_map() above will
+ * allocate struct se_task->task_sg_bidi in transport_do_se_mem_map()
+ * -> transport_calc_sg_num(), and the second here will do the
+ * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI.
+ */
+ if (task->task_sg_bidi != NULL) {
+ ret = transport_do_se_mem_map(dev, task,
+ T_TASK(cmd)->t_mem_bidi_list, NULL,
+ se_mem_bidi, &se_mem_bidi_lout, &se_mem_bidi_cnt,
+ &task_offset_in);
+ if (ret < 0)
+ goto out;
+
+ se_mem_bidi = se_mem_bidi_lout;
+ }
+ task_cdbs++;
+
+ DEBUG_VOL("Incremented task_cdbs(%u) task->task_sg_num(%u)\n",
+ task_cdbs, task->task_sg_num);
+
+ if (max_sectors_set) {
+ max_sectors_set = 0;
+ continue;
+ }
+
+ if (!sectors)
+ break;
+ }
+
+ if (set_counts) {
+ atomic_inc(&T_TASK(cmd)->t_fe_count);
+ atomic_inc(&T_TASK(cmd)->t_se_count);
+ }
+
+ DEBUG_VOL("ITT[0x%08x] total %s cdbs(%u)\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), (data_direction == DMA_TO_DEVICE)
+ ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE", task_cdbs);
+
+ return task_cdbs;
+out:
+ return 0;
+}
+
+static int
+transport_map_control_cmd_to_task(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *cdb;
+ struct se_task *task;
+ int ret;
+
+ task = transport_generic_get_task(cmd, cmd->data_direction);
+ if (!task)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ cdb = TRANSPORT(dev)->get_cdb(task);
+ if (cdb)
+ memcpy(cdb, cmd->t_task->t_task_cdb,
+ scsi_command_size(cmd->t_task->t_task_cdb));
+
+ task->task_size = cmd->data_length;
+ task->task_sg_num =
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) ? 1 : 0;
+
+ atomic_inc(&cmd->t_task->t_fe_count);
+ atomic_inc(&cmd->t_task->t_se_count);
+
+ if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) {
+ struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
+ u32 se_mem_cnt = 0, task_offset = 0;
+
+ BUG_ON(list_empty(cmd->t_task->t_mem_list));
+
+ ret = transport_do_se_mem_map(dev, task,
+ cmd->t_task->t_mem_list, NULL, se_mem,
+ &se_mem_lout, &se_mem_cnt, &task_offset);
+ if (ret < 0)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ if (dev->transport->map_task_SG)
+ return dev->transport->map_task_SG(task);
+ return 0;
+ } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ if (dev->transport->map_task_non_SG)
+ return dev->transport->map_task_non_SG(task);
+ return 0;
+ } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+ if (dev->transport->cdb_none)
+ return dev->transport->cdb_none(task);
+ return 0;
+ } else {
+ BUG();
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ }
+}
+
+/* transport_generic_new_cmd(): Called from transport_processing_thread()
+ *
+ * Allocate storage transport resources from a set of values predefined
+ * by transport_generic_cmd_sequencer() from the iSCSI Target RX process.
+ * Any non zero return here is treated as an "out of resource' op here.
+ */
+ /*
+ * Generate struct se_task(s) and/or their payloads for this CDB.
+ */
+static int transport_generic_new_cmd(struct se_cmd *cmd)
+{
+ struct se_portal_group *se_tpg;
+ struct se_task *task;
+ struct se_device *dev = SE_DEV(cmd);
+ int ret = 0;
+
+ /*
+ * Determine is the TCM fabric module has already allocated physical
+ * memory, and is directly calling transport_generic_map_mem_to_cmd()
+ * to setup beforehand the linked list of physical memory at
+ * T_TASK(cmd)->t_mem_list of struct se_mem->se_page
+ */
+ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
+ ret = transport_allocate_resources(cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = transport_get_sectors(cmd);
+ if (ret < 0)
+ return ret;
+
+ ret = transport_new_cmd_obj(cmd);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Determine if the calling TCM fabric module is talking to
+ * Linux/NET via kernel sockets and needs to allocate a
+ * struct iovec array to complete the struct se_cmd
+ */
+ se_tpg = SE_LUN(cmd)->lun_sep->sep_tpg;
+ if (TPG_TFO(se_tpg)->alloc_cmd_iovecs != NULL) {
+ ret = TPG_TFO(se_tpg)->alloc_cmd_iovecs(cmd);
+ if (ret < 0)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ }
+
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_sent))
+ continue;
+ if (!dev->transport->map_task_SG)
+ continue;
+
+ ret = dev->transport->map_task_SG(task);
+ if (ret < 0)
+ return ret;
+ }
+ } else {
+ ret = transport_map_control_cmd_to_task(cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * For WRITEs, let the iSCSI Target RX Thread know its buffer is ready..
+ * This WRITE struct se_cmd (and all of its associated struct se_task's)
+ * will be added to the struct se_device execution queue after its WRITE
+ * data has arrived. (ie: It gets handled by the transport processing
+ * thread a second time)
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ transport_add_tasks_to_state_queue(cmd);
+ return transport_generic_write_pending(cmd);
+ }
+ /*
+ * Everything else but a WRITE, add the struct se_cmd's struct se_task's
+ * to the execution queue.
+ */
+ transport_execute_tasks(cmd);
+ return 0;
+}
+
+/* transport_generic_process_write():
+ *
+ *
+ */
+void transport_generic_process_write(struct se_cmd *cmd)
+{
+#if 0
+ /*
+ * Copy SCSI Presented DTL sector(s) from received buffers allocated to
+ * original EDTL
+ */
+ if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+ if (!T_TASK(cmd)->t_tasks_se_num) {
+ unsigned char *dst, *buf =
+ (unsigned char *)T_TASK(cmd)->t_task_buf;
+
+ dst = kzalloc(cmd->cmd_spdtl), GFP_KERNEL);
+ if (!(dst)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " WRITE underflow\n");
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ return;
+ }
+ memcpy(dst, buf, cmd->cmd_spdtl);
+
+ kfree(T_TASK(cmd)->t_task_buf);
+ T_TASK(cmd)->t_task_buf = dst;
+ } else {
+ struct scatterlist *sg =
+ (struct scatterlist *sg)T_TASK(cmd)->t_task_buf;
+ struct scatterlist *orig_sg;
+
+ orig_sg = kzalloc(sizeof(struct scatterlist) *
+ T_TASK(cmd)->t_tasks_se_num,
+ GFP_KERNEL))) {
+ if (!(orig_sg)) {
+ printk(KERN_ERR "Unable to allocate memory"
+ " for WRITE underflow\n");
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ return;
+ }
+
+ memcpy(orig_sg, T_TASK(cmd)->t_task_buf,
+ sizeof(struct scatterlist) *
+ T_TASK(cmd)->t_tasks_se_num);
+
+ cmd->data_length = cmd->cmd_spdtl;
+ /*
+ * FIXME, clear out original struct se_task and state
+ * information.
+ */
+ if (transport_generic_new_cmd(cmd) < 0) {
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ kfree(orig_sg);
+ return;
+ }
+
+ transport_memcpy_write_sg(cmd, orig_sg);
+ }
+ }
+#endif
+ transport_execute_tasks(cmd);
+}
+EXPORT_SYMBOL(transport_generic_process_write);
+
+/* transport_generic_write_pending():
+ *
+ *
+ */
+static int transport_generic_write_pending(struct se_cmd *cmd)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ cmd->t_state = TRANSPORT_WRITE_PENDING;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * For the TCM control CDBs using a contiguous buffer, do the memcpy
+ * from the passed Linux/SCSI struct scatterlist located at
+ * T_TASK(se_cmd)->t_task_pt_buf to the contiguous buffer at
+ * T_TASK(se_cmd)->t_task_buf.
+ */
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
+ transport_memcpy_read_contig(cmd,
+ T_TASK(cmd)->t_task_buf,
+ T_TASK(cmd)->t_task_pt_sgl);
+ /*
+ * Clear the se_cmd for WRITE_PENDING status in order to set
+ * T_TASK(cmd)->t_transport_active=0 so that transport_generic_handle_data
+ * can be called from HW target mode interrupt code. This is safe
+ * to be called with transport_off=1 before the CMD_TFO(cmd)->write_pending
+ * because the se_cmd->se_lun pointer is not being cleared.
+ */
+ transport_cmd_check_stop(cmd, 1, 0);
+
+ /*
+ * Call the fabric write_pending function here to let the
+ * frontend know that WRITE buffers are ready.
+ */
+ ret = CMD_TFO(cmd)->write_pending(cmd);
+ if (ret < 0)
+ return ret;
+
+ return PYX_TRANSPORT_WRITE_PENDING;
+}
+
+/* transport_release_cmd_to_pool():
+ *
+ *
+ */
+void transport_release_cmd_to_pool(struct se_cmd *cmd)
+{
+ BUG_ON(!T_TASK(cmd));
+ BUG_ON(!CMD_TFO(cmd));
+
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_to_pool(cmd);
+}
+EXPORT_SYMBOL(transport_release_cmd_to_pool);
+
+/* transport_generic_free_cmd():
+ *
+ * Called from processing frontend to release storage engine resources
+ */
+void transport_generic_free_cmd(
+ struct se_cmd *cmd,
+ int wait_for_tasks,
+ int release_to_pool,
+ int session_reinstatement)
+{
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) || !T_TASK(cmd))
+ transport_release_cmd_to_pool(cmd);
+ else {
+ core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd);
+
+ if (SE_LUN(cmd)) {
+#if 0
+ printk(KERN_INFO "cmd: %p ITT: 0x%08x contains"
+ " SE_LUN(cmd)\n", cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ transport_lun_remove_cmd(cmd);
+ }
+
+ if (wait_for_tasks && cmd->transport_wait_for_tasks)
+ cmd->transport_wait_for_tasks(cmd, 0, 0);
+
+ transport_generic_remove(cmd, release_to_pool,
+ session_reinstatement);
+ }
+}
+EXPORT_SYMBOL(transport_generic_free_cmd);
+
+static void transport_nop_wait_for_tasks(
+ struct se_cmd *cmd,
+ int remove_cmd,
+ int session_reinstatement)
+{
+ return;
+}
+
+/* transport_lun_wait_for_tasks():
+ *
+ * Called from ConfigFS context to stop the passed struct se_cmd to allow
+ * an struct se_lun to be successfully shutdown.
+ */
+static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
+{
+ unsigned long flags;
+ int ret;
+ /*
+ * If the frontend has already requested this struct se_cmd to
+ * be stopped, we can safely ignore this struct se_cmd.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_transport_stop)) {
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 0);
+ DEBUG_TRANSPORT_S("ConfigFS ITT[0x%08x] - t_transport_stop =="
+ " TRUE, skipping\n", CMD_TFO(cmd)->get_task_tag(cmd));
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ transport_cmd_check_stop(cmd, 1, 0);
+ return -1;
+ }
+ atomic_set(&T_TASK(cmd)->transport_lun_fe_stop, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq);
+
+ ret = transport_stop_tasks_for_cmd(cmd);
+
+ DEBUG_TRANSPORT_S("ConfigFS: cmd: %p t_task_cdbs: %d stop tasks ret:"
+ " %d\n", cmd, T_TASK(cmd)->t_task_cdbs, ret);
+ if (!ret) {
+ DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopping cmd....\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ wait_for_completion(&T_TASK(cmd)->transport_lun_stop_comp);
+ DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopped cmd....\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ }
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+
+ return 0;
+}
+
+/* #define DEBUG_CLEAR_LUN */
+#ifdef DEBUG_CLEAR_LUN
+#define DEBUG_CLEAR_L(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CLEAR_L(x...)
+#endif
+
+static void __transport_clear_lun_from_sessions(struct se_lun *lun)
+{
+ struct se_cmd *cmd = NULL;
+ unsigned long lun_flags, cmd_flags;
+ /*
+ * Do exception processing and return CHECK_CONDITION status to the
+ * Initiator Port.
+ */
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ while (!list_empty_careful(&lun->lun_cmd_list)) {
+ cmd = list_entry(lun->lun_cmd_list.next,
+ struct se_cmd, se_lun_list);
+ list_del(&cmd->se_lun_list);
+
+ if (!(T_TASK(cmd))) {
+ printk(KERN_ERR "ITT: 0x%08x, T_TASK(cmd) = NULL"
+ "[i,t]_state: %u/%u\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state);
+ BUG();
+ }
+ atomic_set(&T_TASK(cmd)->transport_lun_active, 0);
+ /*
+ * This will notify iscsi_target_transport.c:
+ * transport_cmd_check_stop() that a LUN shutdown is in
+ * progress for the iscsi_cmd_t.
+ */
+ spin_lock(&T_TASK(cmd)->t_state_lock);
+ DEBUG_CLEAR_L("SE_LUN[%d] - Setting T_TASK(cmd)->transport"
+ "_lun_stop for ITT: 0x%08x\n",
+ SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 1);
+ spin_unlock(&T_TASK(cmd)->t_state_lock);
+
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
+
+ if (!(SE_LUN(cmd))) {
+ printk(KERN_ERR "ITT: 0x%08x, [i,t]_state: %u/%u\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state);
+ BUG();
+ }
+ /*
+ * If the Storage engine still owns the iscsi_cmd_t, determine
+ * and/or stop its context.
+ */
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x before transport"
+ "_lun_wait_for_tasks()\n", SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ if (transport_lun_wait_for_tasks(cmd, SE_LUN(cmd)) < 0) {
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ continue;
+ }
+
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x after transport_lun"
+ "_wait_for_tasks(): SUCCESS\n",
+ SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ goto check_cond;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+
+ transport_free_dev_tasks(cmd);
+ /*
+ * The Storage engine stopped this struct se_cmd before it was
+ * send to the fabric frontend for delivery back to the
+ * Initiator Node. Return this SCSI CDB back with an
+ * CHECK_CONDITION status.
+ */
+check_cond:
+ transport_send_check_condition_and_sense(cmd,
+ TCM_NON_EXISTENT_LUN, 0);
+ /*
+ * If the fabric frontend is waiting for this iscsi_cmd_t to
+ * be released, notify the waiting thread now that LU has
+ * finished accessing it.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ if (atomic_read(&T_TASK(cmd)->transport_lun_fe_stop)) {
+ DEBUG_CLEAR_L("SE_LUN[%d] - Detected FE stop for"
+ " struct se_cmd: %p ITT: 0x%08x\n",
+ lun->unpacked_lun,
+ cmd, CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ cmd_flags);
+ transport_cmd_check_stop(cmd, 1, 0);
+ complete(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ continue;
+ }
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x finished processing\n",
+ lun->unpacked_lun, CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ }
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
+}
+
+static int transport_clear_lun_thread(void *p)
+{
+ struct se_lun *lun = (struct se_lun *)p;
+
+ __transport_clear_lun_from_sessions(lun);
+ complete(&lun->lun_shutdown_comp);
+
+ return 0;
+}
+
+int transport_clear_lun_from_sessions(struct se_lun *lun)
+{
+ struct task_struct *kt;
+
+ kt = kthread_run(transport_clear_lun_thread, (void *)lun,
+ "tcm_cl_%u", lun->unpacked_lun);
+ if (IS_ERR(kt)) {
+ printk(KERN_ERR "Unable to start clear_lun thread\n");
+ return -1;
+ }
+ wait_for_completion(&lun->lun_shutdown_comp);
+
+ return 0;
+}
+
+/* transport_generic_wait_for_tasks():
+ *
+ * Called from frontend or passthrough context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
+ */
+static void transport_generic_wait_for_tasks(
+ struct se_cmd *cmd,
+ int remove_cmd,
+ int session_reinstatement)
+{
+ unsigned long flags;
+
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req))
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * If we are already stopped due to an external event (ie: LUN shutdown)
+ * sleep until the connection can have the passed struct se_cmd back.
+ * The T_TASK(cmd)->transport_lun_stopped_sem will be upped by
+ * transport_clear_lun_from_sessions() once the ConfigFS context caller
+ * has completed its operation on the struct se_cmd.
+ */
+ if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) {
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopping"
+ " wait_for_completion(&T_TASK(cmd)transport_lun_fe"
+ "_stop_comp); for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ /*
+ * There is a special case for WRITES where a FE exception +
+ * LUN shutdown means ConfigFS context is still sleeping on
+ * transport_lun_stop_comp in transport_lun_wait_for_tasks().
+ * We go ahead and up transport_lun_stop_comp just to be sure
+ * here.
+ */
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ complete(&T_TASK(cmd)->transport_lun_stop_comp);
+ wait_for_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_all_task_dev_remove_state(cmd);
+ /*
+ * At this point, the frontend who was the originator of this
+ * struct se_cmd, now owns the structure and can be released through
+ * normal means below.
+ */
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopped"
+ " wait_for_completion(&T_TASK(cmd)transport_lun_fe_"
+ "stop_comp); for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 0);
+ }
+ if (!atomic_read(&T_TASK(cmd)->t_transport_active))
+ goto remove;
+
+ atomic_set(&T_TASK(cmd)->t_transport_stop, 1);
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopping %p ITT: 0x%08x"
+ " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop"
+ " = TRUE\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state,
+ cmd->deferred_t_state);
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq);
+
+ wait_for_completion(&T_TASK(cmd)->t_transport_stop_comp);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ atomic_set(&T_TASK(cmd)->t_transport_stop, 0);
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopped wait_for_compltion("
+ "&T_TASK(cmd)->t_transport_stop_comp) for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+remove:
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ if (!remove_cmd)
+ return;
+
+ transport_generic_free_cmd(cmd, 0, 0, session_reinstatement);
+}
+
+static int transport_get_sense_codes(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ *asc = cmd->scsi_asc;
+ *ascq = cmd->scsi_ascq;
+
+ return 0;
+}
+
+static int transport_set_sense_codes(
+ struct se_cmd *cmd,
+ u8 asc,
+ u8 ascq)
+{
+ cmd->scsi_asc = asc;
+ cmd->scsi_ascq = ascq;
+
+ return 0;
+}
+
+int transport_send_check_condition_and_sense(
+ struct se_cmd *cmd,
+ u8 reason,
+ int from_transport)
+{
+ unsigned char *buffer = cmd->sense_buffer;
+ unsigned long flags;
+ int offset;
+ u8 asc = 0, ascq = 0;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return 0;
+ }
+ cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ if (!reason && from_transport)
+ goto after_reason;
+
+ if (!from_transport)
+ cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
+ /*
+ * Data Segment and SenseLength of the fabric response PDU.
+ *
+ * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE
+ * from include/scsi/scsi_cmnd.h
+ */
+ offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd,
+ TRANSPORT_SENSE_BUFFER);
+ /*
+ * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses
+ * SENSE KEY values from include/scsi/scsi.h
+ */
+ switch (reason) {
+ case TCM_NON_EXISTENT_LUN:
+ case TCM_UNSUPPORTED_SCSI_OPCODE:
+ case TCM_SECTOR_COUNT_TOO_MANY:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* INVALID COMMAND OPERATION CODE */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20;
+ break;
+ case TCM_UNKNOWN_MODE_PAGE:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* INVALID FIELD IN CDB */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ break;
+ case TCM_CHECK_CONDITION_ABORT_CMD:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* BUS DEVICE RESET FUNCTION OCCURRED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03;
+ break;
+ case TCM_INCORRECT_AMOUNT_OF_DATA:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* WRITE ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ /* NOT ENOUGH UNSOLICITED DATA */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d;
+ break;
+ case TCM_INVALID_CDB_FIELD:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* INVALID FIELD IN CDB */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ break;
+ case TCM_INVALID_PARAMETER_LIST:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* INVALID FIELD IN PARAMETER LIST */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
+ break;
+ case TCM_UNEXPECTED_UNSOLICITED_DATA:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* WRITE ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ /* UNEXPECTED_UNSOLICITED_DATA */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c;
+ break;
+ case TCM_SERVICE_CRC_ERROR:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* PROTOCOL SERVICE CRC ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47;
+ /* N/A */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05;
+ break;
+ case TCM_SNACK_REJECTED:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* READ ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11;
+ /* FAILED RETRANSMISSION REQUEST */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13;
+ break;
+ case TCM_WRITE_PROTECTED:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* DATA PROTECT */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
+ /* WRITE PROTECTED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
+ break;
+ case TCM_CHECK_CONDITION_UNIT_ATTENTION:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* UNIT ATTENTION */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+ core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
+ buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ break;
+ case TCM_CHECK_CONDITION_NOT_READY:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* Not Ready */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
+ transport_get_sense_codes(cmd, &asc, &ascq);
+ buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ break;
+ case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
+ default:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* LOGICAL UNIT COMMUNICATION FAILURE */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
+ break;
+ }
+ /*
+ * This code uses linux/include/scsi/scsi.h SAM status codes!
+ */
+ cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+ /*
+ * Automatically padded, this value is encoded in the fabric's
+ * data_length response PDU containing the SCSI defined sense data.
+ */
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+
+after_reason:
+ CMD_TFO(cmd)->queue_status(cmd);
+ return 0;
+}
+EXPORT_SYMBOL(transport_send_check_condition_and_sense);
+
+int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+{
+ int ret = 0;
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_aborted) != 0) {
+ if (!(send_status) ||
+ (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
+ return 1;
+#if 0
+ printk(KERN_INFO "Sending delayed SAM_STAT_TASK_ABORTED"
+ " status for CDB: 0x%02x ITT: 0x%08x\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
+ CMD_TFO(cmd)->queue_status(cmd);
+ ret = 1;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(transport_check_aborted_status);
+
+void transport_send_task_abort(struct se_cmd *cmd)
+{
+ /*
+ * If there are still expected incoming fabric WRITEs, we wait
+ * until until they have completed before sending a TASK_ABORTED
+ * response. This response with TASK_ABORTED status will be
+ * queued back to fabric module by transport_check_aborted_status().
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ if (CMD_TFO(cmd)->write_pending_status(cmd) != 0) {
+ atomic_inc(&T_TASK(cmd)->t_transport_aborted);
+ smp_mb__after_atomic_inc();
+ cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+ transport_new_cmd_failure(cmd);
+ return;
+ }
+ }
+ cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+#if 0
+ printk(KERN_INFO "Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x,"
+ " ITT: 0x%08x\n", T_TASK(cmd)->t_task_cdb[0],
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ CMD_TFO(cmd)->queue_status(cmd);
+}
+
+/* transport_generic_do_tmr():
+ *
+ *
+ */
+int transport_generic_do_tmr(struct se_cmd *cmd)
+{
+ struct se_cmd *ref_cmd;
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_tmr_req *tmr = cmd->se_tmr_req;
+ int ret;
+
+ switch (tmr->function) {
+ case ABORT_TASK:
+ ref_cmd = tmr->ref_cmd;
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ case ABORT_TASK_SET:
+ case CLEAR_ACA:
+ case CLEAR_TASK_SET:
+ tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+ break;
+ case LUN_RESET:
+ ret = core_tmr_lun_reset(dev, tmr, NULL, NULL);
+ tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE :
+ TMR_FUNCTION_REJECTED;
+ break;
+#if 0
+ case TARGET_WARM_RESET:
+ transport_generic_host_reset(dev->se_hba);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ case TARGET_COLD_RESET:
+ transport_generic_host_reset(dev->se_hba);
+ transport_generic_cold_reset(dev->se_hba);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+#endif
+ default:
+ printk(KERN_ERR "Uknown TMR function: 0x%02x.\n",
+ tmr->function);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ }
+
+ cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+ CMD_TFO(cmd)->queue_tm_rsp(cmd);
+
+ transport_cmd_check_stop(cmd, 2, 0);
+ return 0;
+}
+
+/*
+ * Called with spin_lock_irq(&dev->execute_task_lock); held
+ *
+ */
+static struct se_task *
+transport_get_task_from_state_list(struct se_device *dev)
+{
+ struct se_task *task;
+
+ if (list_empty(&dev->state_task_list))
+ return NULL;
+
+ list_for_each_entry(task, &dev->state_task_list, t_state_list)
+ break;
+
+ list_del(&task->t_state_list);
+ atomic_set(&task->task_state_active, 0);
+
+ return task;
+}
+
+static void transport_processing_shutdown(struct se_device *dev)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr;
+ struct se_task *task;
+ u8 state;
+ unsigned long flags;
+ /*
+ * Empty the struct se_device's struct se_task state list.
+ */
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ while ((task = transport_get_task_from_state_list(dev))) {
+ if (!(TASK_CMD(task))) {
+ printk(KERN_ERR "TASK_CMD(task) is NULL!\n");
+ continue;
+ }
+ cmd = TASK_CMD(task);
+
+ if (!T_TASK(cmd)) {
+ printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:"
+ " %p ITT: 0x%08x\n", task, cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ continue;
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("PT: cmd: %p task: %p ITT/CmdSN: 0x%08x/0x%08x,"
+ " i_state/def_i_state: %d/%d, t_state/def_t_state:"
+ " %d/%d cdb: 0x%02x\n", cmd, task,
+ CMD_TFO(cmd)->get_task_tag(cmd), cmd->cmd_sn,
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->deferred_i_state,
+ cmd->t_state, cmd->deferred_t_state,
+ T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_DO("PT: ITT[0x%08x] - t_task_cdbs: %d t_task_cdbs_left:"
+ " %d t_task_cdbs_sent: %d -- t_transport_active: %d"
+ " t_transport_stop: %d t_transport_sent: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("Waiting for task: %p to shutdown for dev:"
+ " %p\n", task, dev);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_DO("Completed task: %p shutdown for dev: %p\n",
+ task, dev);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ }
+ __transport_stop_task_timer(task, &flags);
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("Skipping task: %p, dev: %p for"
+ " t_task_cdbs_ex_left: %d\n", task, dev,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left));
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_active)) {
+ DEBUG_DO("got t_transport_active = 1 for task: %p, dev:"
+ " %p\n", task, dev);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ transport_send_check_condition_and_sense(
+ cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE,
+ 0);
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ DEBUG_DO("Got t_transport_active = 0 for task: %p, dev: %p\n",
+ task, dev);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ transport_send_check_condition_and_sense(cmd,
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Empty the struct se_device's struct se_cmd list.
+ */
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ while ((qr = __transport_get_qr_from_queue(dev->dev_queue_obj))) {
+ spin_unlock_irqrestore(
+ &dev->dev_queue_obj->cmd_queue_lock, flags);
+ cmd = (struct se_cmd *)qr->cmd;
+ state = qr->state;
+ kfree(qr);
+
+ DEBUG_DO("From Device Queue: cmd: %p t_state: %d\n",
+ cmd, state);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ transport_send_check_condition_and_sense(cmd,
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ transport_lun_remove_cmd(cmd);
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags);
+}
+
+/* transport_processing_thread():
+ *
+ *
+ */
+static int transport_processing_thread(void *param)
+{
+ int ret, t_state;
+ struct se_cmd *cmd;
+ struct se_device *dev = (struct se_device *) param;
+ struct se_queue_req *qr;
+
+ set_user_nice(current, -20);
+
+ while (!kthread_should_stop()) {
+ ret = wait_event_interruptible(dev->dev_queue_obj->thread_wq,
+ atomic_read(&dev->dev_queue_obj->queue_cnt) ||
+ kthread_should_stop());
+ if (ret < 0)
+ goto out;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) {
+ spin_unlock_irq(&dev->dev_status_lock);
+ transport_processing_shutdown(dev);
+ continue;
+ }
+ spin_unlock_irq(&dev->dev_status_lock);
+
+get_cmd:
+ __transport_execute_tasks(dev);
+
+ qr = transport_get_qr_from_queue(dev->dev_queue_obj);
+ if (!(qr))
+ continue;
+
+ cmd = (struct se_cmd *)qr->cmd;
+ t_state = qr->state;
+ kfree(qr);
+
+ switch (t_state) {
+ case TRANSPORT_NEW_CMD_MAP:
+ if (!(CMD_TFO(cmd)->new_cmd_map)) {
+ printk(KERN_ERR "CMD_TFO(cmd)->new_cmd_map is"
+ " NULL for TRANSPORT_NEW_CMD_MAP\n");
+ BUG();
+ }
+ ret = CMD_TFO(cmd)->new_cmd_map(cmd);
+ if (ret < 0) {
+ cmd->transport_error_status = ret;
+ transport_generic_request_failure(cmd, NULL,
+ 0, (cmd->data_direction !=
+ DMA_TO_DEVICE));
+ break;
+ }
+ /* Fall through */
+ case TRANSPORT_NEW_CMD:
+ ret = transport_generic_new_cmd(cmd);
+ if (ret < 0) {
+ cmd->transport_error_status = ret;
+ transport_generic_request_failure(cmd, NULL,
+ 0, (cmd->data_direction !=
+ DMA_TO_DEVICE));
+ }
+ break;
+ case TRANSPORT_PROCESS_WRITE:
+ transport_generic_process_write(cmd);
+ break;
+ case TRANSPORT_COMPLETE_OK:
+ transport_stop_all_task_timers(cmd);
+ transport_generic_complete_ok(cmd);
+ break;
+ case TRANSPORT_REMOVE:
+ transport_generic_remove(cmd, 1, 0);
+ break;
+ case TRANSPORT_PROCESS_TMR:
+ transport_generic_do_tmr(cmd);
+ break;
+ case TRANSPORT_COMPLETE_FAILURE:
+ transport_generic_request_failure(cmd, NULL, 1, 1);
+ break;
+ case TRANSPORT_COMPLETE_TIMEOUT:
+ transport_stop_all_task_timers(cmd);
+ transport_generic_request_timeout(cmd);
+ break;
+ default:
+ printk(KERN_ERR "Unknown t_state: %d deferred_t_state:"
+ " %d for ITT: 0x%08x i_state: %d on SE LUN:"
+ " %u\n", t_state, cmd->deferred_t_state,
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd),
+ SE_LUN(cmd)->unpacked_lun);
+ BUG();
+ }
+
+ goto get_cmd;
+ }
+
+out:
+ transport_release_all_cmds(dev);
+ dev->process_thread = NULL;
+ return 0;
+}
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c
new file mode 100644
index 000000000000..a2ef346087e8
--- /dev/null
+++ b/drivers/target/target_core_ua.c
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Filename: target_core_ua.c
+ *
+ * This file contains logic for SPC-3 Unit Attention emulation
+ *
+ * Copyright (c) 2009,2010 Rising Tide Systems
+ * Copyright (c) 2009,2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+int core_scsi3_ua_check(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+
+ if (!(sess))
+ return 0;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return 0;
+
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count)))
+ return 0;
+ /*
+ * From sam4r14, section 5.14 Unit attention condition:
+ *
+ * a) if an INQUIRY command enters the enabled command state, the
+ * device server shall process the INQUIRY command and shall neither
+ * report nor clear any unit attention condition;
+ * b) if a REPORT LUNS command enters the enabled command state, the
+ * device server shall process the REPORT LUNS command and shall not
+ * report any unit attention condition;
+ * e) if a REQUEST SENSE command enters the enabled command state while
+ * a unit attention condition exists for the SCSI initiator port
+ * associated with the I_T nexus on which the REQUEST SENSE command
+ * was received, then the device server shall process the command
+ * and either:
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case REQUEST_SENSE:
+ return 0;
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+int core_scsi3_ua_allocate(
+ struct se_node_acl *nacl,
+ u32 unpacked_lun,
+ u8 asc,
+ u8 ascq)
+{
+ struct se_dev_entry *deve;
+ struct se_ua *ua, *ua_p, *ua_tmp;
+ /*
+ * PASSTHROUGH OPS
+ */
+ if (!(nacl))
+ return -1;
+
+ ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC);
+ if (!(ua)) {
+ printk(KERN_ERR "Unable to allocate struct se_ua\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&ua->ua_dev_list);
+ INIT_LIST_HEAD(&ua->ua_nacl_list);
+
+ ua->ua_nacl = nacl;
+ ua->ua_asc = asc;
+ ua->ua_ascq = ascq;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[unpacked_lun];
+
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) {
+ /*
+ * Do not report the same UNIT ATTENTION twice..
+ */
+ if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) {
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+ kmem_cache_free(se_ua_cache, ua);
+ return 0;
+ }
+ /*
+ * Attach the highest priority Unit Attention to
+ * the head of the list following sam4r14,
+ * Section 5.14 Unit Attention Condition:
+ *
+ * POWER ON, RESET, OR BUS DEVICE RESET OCCURRED highest
+ * POWER ON OCCURRED or
+ * DEVICE INTERNAL RESET
+ * SCSI BUS RESET OCCURRED or
+ * MICROCODE HAS BEEN CHANGED or
+ * protocol specific
+ * BUS DEVICE RESET FUNCTION OCCURRED
+ * I_T NEXUS LOSS OCCURRED
+ * COMMANDS CLEARED BY POWER LOSS NOTIFICATION
+ * all others Lowest
+ *
+ * Each of the ASCQ codes listed above are defined in
+ * the 29h ASC family, see spc4r17 Table D.1
+ */
+ if (ua_p->ua_asc == 0x29) {
+ if ((asc == 0x29) && (ascq > ua_p->ua_ascq))
+ list_add(&ua->ua_nacl_list,
+ &deve->ua_list);
+ else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ } else if (ua_p->ua_asc == 0x2a) {
+ /*
+ * Incoming Family 29h ASCQ codes will override
+ * Family 2AHh ASCQ codes for Unit Attention condition.
+ */
+ if ((asc == 0x29) || (ascq > ua_p->ua_asc))
+ list_add(&ua->ua_nacl_list,
+ &deve->ua_list);
+ else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ } else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ atomic_inc(&deve->ua_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+ }
+ list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:"
+ " 0x%02x, ASCQ: 0x%02x\n",
+ TPG_TFO(nacl->se_tpg)->get_fabric_name(), unpacked_lun,
+ asc, ascq);
+
+ atomic_inc(&deve->ua_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+}
+
+void core_scsi3_ua_release_all(
+ struct se_dev_entry *deve)
+{
+ struct se_ua *ua, *ua_p;
+
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+}
+
+void core_scsi3_ua_for_check_condition(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+ struct se_ua *ua = NULL, *ua_p;
+ int head = 1;
+
+ if (!(sess))
+ return;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count))) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return;
+ }
+ /*
+ * The highest priority Unit Attentions are placed at the head of the
+ * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION +
+ * sense data for the received CDB.
+ */
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ /*
+ * For ua_intlck_ctrl code not equal to 00b, only report the
+ * highest priority UNIT_ATTENTION and ASC/ASCQ without
+ * clearing it.
+ */
+ if (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ break;
+ }
+ /*
+ * Otherwise for the default 00b, release the UNIT ATTENTION
+ * condition. Return the ASC/ASCQ of the higest priority UA
+ * (head of the list) in the outgoing CHECK_CONDITION + sense.
+ */
+ if (head) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ head = 0;
+ }
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: %s UNIT ATTENTION condition with"
+ " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x"
+ " reported ASC: 0x%02x, ASCQ: 0x%02x\n",
+ TPG_TFO(nacl->se_tpg)->get_fabric_name(),
+ (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) ? "Reporting" :
+ "Releasing", DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl,
+ cmd->orig_fe_lun, T_TASK(cmd)->t_task_cdb[0], *asc, *ascq);
+}
+
+int core_scsi3_ua_clear_for_request_sense(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+ struct se_ua *ua = NULL, *ua_p;
+ int head = 1;
+
+ if (!(sess))
+ return -1;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return -1;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count))) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return -1;
+ }
+ /*
+ * The highest priority Unit Attentions are placed at the head of the
+ * struct se_dev_entry->ua_list. The First (and hence highest priority)
+ * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the
+ * matching struct se_lun.
+ *
+ * Once the returning ASC/ASCQ values are set, we go ahead and
+ * release all of the Unit Attention conditions for the assoicated
+ * struct se_lun.
+ */
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ if (head) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ head = 0;
+ }
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: Released UNIT ATTENTION condition, mapped"
+ " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x,"
+ " ASCQ: 0x%02x\n", TPG_TFO(nacl->se_tpg)->get_fabric_name(),
+ cmd->orig_fe_lun, *asc, *ascq);
+
+ return (head) ? -1 : 0;
+}
diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h
new file mode 100644
index 000000000000..6e6b03460a1a
--- /dev/null
+++ b/drivers/target/target_core_ua.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_CORE_UA_H
+
+/*
+ * From spc4r17, Table D.1: ASC and ASCQ Assignement
+ */
+#define ASCQ_29H_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURED 0x00
+#define ASCQ_29H_POWER_ON_OCCURRED 0x01
+#define ASCQ_29H_SCSI_BUS_RESET_OCCURED 0x02
+#define ASCQ_29H_BUS_DEVICE_RESET_FUNCTION_OCCURRED 0x03
+#define ASCQ_29H_DEVICE_INTERNAL_RESET 0x04
+#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_SINGLE_ENDED 0x05
+#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_LVD 0x06
+#define ASCQ_29H_NEXUS_LOSS_OCCURRED 0x07
+
+#define ASCQ_2AH_PARAMETERS_CHANGED 0x00
+#define ASCQ_2AH_MODE_PARAMETERS_CHANGED 0x01
+#define ASCQ_2AH_LOG_PARAMETERS_CHANGED 0x02
+#define ASCQ_2AH_RESERVATIONS_PREEMPTED 0x03
+#define ASCQ_2AH_RESERVATIONS_RELEASED 0x04
+#define ASCQ_2AH_REGISTRATIONS_PREEMPTED 0x05
+#define ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06
+#define ASCQ_2AH_IMPLICT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED 0x07
+#define ASCQ_2AH_PRIORITY_CHANGED 0x08
+
+#define ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS 0x09
+
+extern struct kmem_cache *se_ua_cache;
+
+extern int core_scsi3_ua_check(struct se_cmd *, unsigned char *);
+extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8);
+extern void core_scsi3_ua_release_all(struct se_dev_entry *);
+extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *);
+extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *,
+ u8 *, u8 *);
+
+#endif /* TARGET_CORE_UA_H */
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 0d236f4bb8c2..b00101972f20 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -284,12 +284,11 @@ static int samplerate = 100;
module_param(ixjdebug, int, 0);
-static struct pci_device_id ixj_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ixj_pci_tbl) = {
{ PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
-
MODULE_DEVICE_TABLE(pci, ixj_pci_tbl);
/************************************************************************
@@ -6581,7 +6580,8 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
case IXJCTL_SET_FILTER:
if (copy_from_user(&jf, argp, sizeof(jf)))
retval = -EFAULT;
- retval = ixj_init_filter(j, &jf);
+ else
+ retval = ixj_init_filter(j, &jf);
break;
case IXJCTL_SET_FILTER_RAW:
if (copy_from_user(&jfr, argp, sizeof(jfr)))
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index bf7c687519ef..f7a5dba3ca23 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -4,6 +4,7 @@
menuconfig THERMAL
tristate "Generic Thermal sysfs driver"
+ depends on NET
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 13c72c629329..7d0e63c79280 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -32,6 +32,8 @@
#include <linux/thermal.h>
#include <linux/spinlock.h>
#include <linux/reboot.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
+static unsigned int thermal_event_seqnum;
+
+static struct genl_family thermal_event_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = THERMAL_GENL_FAMILY_NAME,
+ .version = THERMAL_GENL_VERSION,
+ .maxattr = THERMAL_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group thermal_event_mcgrp = {
+ .name = THERMAL_GENL_MCAST_GROUP_NAME,
+};
+
+static int genetlink_init(void);
+static void genetlink_exit(void);
+
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
@@ -823,11 +841,8 @@ static struct class thermal_class = {
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
*/
-struct thermal_cooling_device *thermal_cooling_device_register(char *type,
- void *devdata,
- struct
- thermal_cooling_device_ops
- *ops)
+struct thermal_cooling_device *thermal_cooling_device_register(
+ char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos;
@@ -1048,13 +1063,9 @@ EXPORT_SYMBOL(thermal_zone_device_update);
* section 11.1.5.1 of the ACPI specification 3.0.
*/
struct thermal_zone_device *thermal_zone_device_register(char *type,
- int trips,
- void *devdata, struct
- thermal_zone_device_ops
- *ops, int tc1, int
- tc2,
- int passive_delay,
- int polling_delay)
+ int trips, void *devdata,
+ const struct thermal_zone_device_ops *ops,
+ int tc1, int tc2, int passive_delay, int polling_delay)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
@@ -1214,6 +1225,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
EXPORT_SYMBOL(thermal_zone_device_unregister);
+int generate_netlink_event(u32 orig, enum events event)
+{
+ struct sk_buff *skb;
+ struct nlattr *attr;
+ struct thermal_genl_event *thermal_event;
+ void *msg_header;
+ int size;
+ int result;
+
+ /* allocate memory */
+ size = nla_total_size(sizeof(struct thermal_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, thermal_event_seqnum++,
+ &thermal_event_genl_family, 0,
+ THERMAL_GENL_CMD_EVENT);
+ if (!msg_header) {
+ nlmsg_free(skb);
+ return -ENOMEM;
+ }
+
+ /* fill the data */
+ attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \
+ sizeof(struct thermal_genl_event));
+
+ if (!attr) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ thermal_event = nla_data(attr);
+ if (!thermal_event) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ memset(thermal_event, 0, sizeof(struct thermal_genl_event));
+
+ thermal_event->orig = orig;
+ thermal_event->event = event;
+
+ /* send multicast genetlink message */
+ result = genlmsg_end(skb, msg_header);
+ if (result < 0) {
+ nlmsg_free(skb);
+ return result;
+ }
+
+ result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
+ if (result)
+ printk(KERN_INFO "failed to send netlink event:%d", result);
+
+ return result;
+}
+EXPORT_SYMBOL(generate_netlink_event);
+
+static int genetlink_init(void)
+{
+ int result;
+
+ result = genl_register_family(&thermal_event_genl_family);
+ if (result)
+ return result;
+
+ result = genl_register_mc_group(&thermal_event_genl_family,
+ &thermal_event_mcgrp);
+ if (result)
+ genl_unregister_family(&thermal_event_genl_family);
+ return result;
+}
+
static int __init thermal_init(void)
{
int result = 0;
@@ -1225,9 +1312,15 @@ static int __init thermal_init(void)
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
}
+ result = genetlink_init();
return result;
}
+static void genetlink_exit(void)
+{
+ genl_unregister_family(&thermal_event_genl_family);
+}
+
static void __exit thermal_exit(void)
{
class_unregister(&thermal_class);
@@ -1235,7 +1328,8 @@ static void __exit thermal_exit(void)
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
+ genetlink_exit();
}
-subsys_initcall(thermal_init);
+fs_initcall(thermal_init);
module_exit(thermal_exit);
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
new file mode 100644
index 000000000000..c43ef48b1a0f
--- /dev/null
+++ b/drivers/tty/Makefile
@@ -0,0 +1,11 @@
+obj-y += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+ tty_buffer.o tty_port.o tty_mutex.o
+obj-$(CONFIG_LEGACY_PTYS) += pty.o
+obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-$(CONFIG_AUDIT) += tty_audit.o
+obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
+obj-$(CONFIG_N_HDLC) += n_hdlc.o
+obj-$(CONFIG_N_GSM) += n_gsm.o
+obj-$(CONFIG_R3964) += n_r3964.o
+
+obj-y += vt/
diff --git a/drivers/char/n_gsm.c b/drivers/tty/n_gsm.c
index 04ef3ef0a422..44b8412a04e8 100644
--- a/drivers/char/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -19,7 +19,7 @@
*
* TO DO:
* Mostly done: ioctls for setting modes/timing
- * Partly done: hooks so you can pull off frames to non tty devs
+ * Partly done: hooks so you can pull off frames to non tty devs
* Restart DLCI 0 when it closes ?
* Test basic encoding
* Improve the tx engine
@@ -73,8 +73,10 @@ module_param(debug, int, 0600);
#define T2 (2 * HZ)
#endif
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
- limits so this is plenty */
+/*
+ * Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+ * limits so this is plenty
+ */
#define MAX_MRU 512
#define MAX_MTU 512
@@ -184,6 +186,9 @@ struct gsm_mux {
#define GSM_DATA 5
#define GSM_FCS 6
#define GSM_OVERRUN 7
+#define GSM_LEN0 8
+#define GSM_LEN1 9
+#define GSM_SSOF 10
unsigned int len;
unsigned int address;
unsigned int count;
@@ -191,6 +196,7 @@ struct gsm_mux {
int encoding;
u8 control;
u8 fcs;
+ u8 received_fcs;
u8 *txframe; /* TX framing buffer */
/* Methods for the receiver side */
@@ -286,7 +292,7 @@ static spinlock_t gsm_mux_lock;
#define MDM_DV 0x40
#define GSM0_SOF 0xF9
-#define GSM1_SOF 0x7E
+#define GSM1_SOF 0x7E
#define GSM1_ESCAPE 0x7D
#define GSM1_ESCAPE_BITS 0x20
#define XON 0x11
@@ -429,61 +435,63 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
if (!(debug & 1))
return;
- printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+ pr_info("%s %d) %c: ", hdr, addr, "RC"[cr]);
switch (control & ~PF) {
case SABM:
- printk(KERN_CONT "SABM");
+ pr_cont("SABM");
break;
case UA:
- printk(KERN_CONT "UA");
+ pr_cont("UA");
break;
case DISC:
- printk(KERN_CONT "DISC");
+ pr_cont("DISC");
break;
case DM:
- printk(KERN_CONT "DM");
+ pr_cont("DM");
break;
case UI:
- printk(KERN_CONT "UI");
+ pr_cont("UI");
break;
case UIH:
- printk(KERN_CONT "UIH");
+ pr_cont("UIH");
break;
default:
if (!(control & 0x01)) {
- printk(KERN_CONT "I N(S)%d N(R)%d",
- (control & 0x0E) >> 1, (control & 0xE)>> 5);
+ pr_cont("I N(S)%d N(R)%d",
+ (control & 0x0E) >> 1, (control & 0xE) >> 5);
} else switch (control & 0x0F) {
- case RR:
- printk("RR(%d)", (control & 0xE0) >> 5);
- break;
- case RNR:
- printk("RNR(%d)", (control & 0xE0) >> 5);
- break;
- case REJ:
- printk("REJ(%d)", (control & 0xE0) >> 5);
- break;
- default:
- printk(KERN_CONT "[%02X]", control);
+ case RR:
+ pr_cont("RR(%d)", (control & 0xE0) >> 5);
+ break;
+ case RNR:
+ pr_cont("RNR(%d)", (control & 0xE0) >> 5);
+ break;
+ case REJ:
+ pr_cont("REJ(%d)", (control & 0xE0) >> 5);
+ break;
+ default:
+ pr_cont("[%02X]", control);
}
}
if (control & PF)
- printk(KERN_CONT "(P)");
+ pr_cont("(P)");
else
- printk(KERN_CONT "(F)");
+ pr_cont("(F)");
if (dlen) {
int ct = 0;
while (dlen--) {
- if (ct % 8 == 0)
- printk(KERN_CONT "\n ");
- printk(KERN_CONT "%02X ", *data++);
+ if (ct % 8 == 0) {
+ pr_cont("\n");
+ pr_debug(" ");
+ }
+ pr_cont("%02X ", *data++);
ct++;
}
}
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
@@ -522,11 +530,13 @@ static void hex_packet(const unsigned char *p, int len)
{
int i;
for (i = 0; i < len; i++) {
- if (i && (i % 16) == 0)
- printk("\n");
- printk("%02X ", *p++);
+ if (i && (i % 16) == 0) {
+ pr_cont("\n");
+ pr_debug("");
+ }
+ pr_cont("%02X ", *p++);
}
- printk("\n");
+ pr_cont("\n");
}
/**
@@ -676,7 +686,7 @@ static void gsm_data_kick(struct gsm_mux *gsm)
}
if (debug & 4) {
- printk("gsm_data_kick: \n");
+ pr_debug("gsm_data_kick:\n");
hex_packet(gsm->txframe, len);
}
@@ -716,8 +726,8 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
if (msg->len < 128)
*--dp = (msg->len << 1) | EA;
else {
- *--dp = (msg->len >> 6) | EA;
- *--dp = (msg->len & 127) << 1;
+ *--dp = (msg->len >> 7); /* bits 7 - 15 */
+ *--dp = (msg->len & 127) << 1; /* bits 0 - 6 */
}
}
@@ -968,6 +978,8 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
{
struct gsm_msg *msg;
msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
+ if (msg == NULL)
+ return;
msg->data[0] = (cmd & 0xFE) << 1 | EA; /* Clear C/R */
msg->data[1] = (dlen << 1) | EA;
memcpy(msg->data + 2, data, dlen);
@@ -1229,7 +1241,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
}
/**
- * gsm_control_transmit - send control packet
+ * gsm_control_transmit - send control packet
* @gsm: gsm mux
* @ctrl: frame to send
*
@@ -1359,7 +1371,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
{
del_timer(&dlci->t1);
if (debug & 8)
- printk("DLCI %d goes closed.\n", dlci->addr);
+ pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) {
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
@@ -1390,7 +1402,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
/* This will let a tty open continue */
dlci->state = DLCI_OPEN;
if (debug & 8)
- printk("DLCI %d goes open.\n", dlci->addr);
+ pr_debug("DLCI %d goes open.\n", dlci->addr);
wake_up(&dlci->gsm->event);
}
@@ -1492,29 +1504,29 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
unsigned int modem = 0;
if (debug & 16)
- printk("%d bytes for tty %p\n", len, tty);
+ pr_debug("%d bytes for tty %p\n", len, tty);
if (tty) {
switch (dlci->adaption) {
- /* Unsupported types */
- /* Packetised interruptible data */
- case 4:
- break;
- /* Packetised uininterruptible voice/data */
- case 3:
- break;
- /* Asynchronous serial with line state in each frame */
- case 2:
- while (gsm_read_ea(&modem, *data++) == 0) {
- len--;
- if (len == 0)
- return;
- }
- gsm_process_modem(tty, dlci, modem);
- /* Line state will go via DLCI 0 controls only */
- case 1:
- default:
- tty_insert_flip_string(tty, data, len);
- tty_flip_buffer_push(tty);
+ /* Unsupported types */
+ /* Packetised interruptible data */
+ case 4:
+ break;
+ /* Packetised uininterruptible voice/data */
+ case 3:
+ break;
+ /* Asynchronous serial with line state in each frame */
+ case 2:
+ while (gsm_read_ea(&modem, *data++) == 0) {
+ len--;
+ if (len == 0)
+ return;
+ }
+ gsm_process_modem(tty, dlci, modem);
+ /* Line state will go via DLCI 0 controls only */
+ case 1:
+ default:
+ tty_insert_flip_string(tty, data, len);
+ tty_flip_buffer_push(tty);
}
tty_kref_put(tty);
}
@@ -1623,7 +1635,6 @@ static void gsm_dlci_free(struct gsm_dlci *dlci)
kfree(dlci);
}
-
/*
* LAPBish link layer logic
*/
@@ -1648,10 +1659,12 @@ static void gsm_queue(struct gsm_mux *gsm)
if ((gsm->control & ~PF) == UI)
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+ /* generate final CRC with received FCS */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
if (gsm->fcs != GOOD_FCS) {
gsm->bad_fcs++;
if (debug & 4)
- printk("BAD FCS %02x\n", gsm->fcs);
+ pr_debug("BAD FCS %02x\n", gsm->fcs);
return;
}
address = gsm->address >> 1;
@@ -1746,6 +1759,8 @@ invalid:
static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
{
+ unsigned int len;
+
switch (gsm->state) {
case GSM_SEARCH: /* SOF marker */
if (c == GSM0_SOF) {
@@ -1754,8 +1769,8 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
gsm->len = 0;
gsm->fcs = INIT_FCS;
}
- break; /* Address EA */
- case GSM_ADDRESS:
+ break;
+ case GSM_ADDRESS: /* Address EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->address, c))
gsm->state = GSM_CONTROL;
@@ -1763,9 +1778,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
case GSM_CONTROL: /* Control Byte */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
gsm->control = c;
- gsm->state = GSM_LEN;
+ gsm->state = GSM_LEN0;
break;
- case GSM_LEN: /* Length EA */
+ case GSM_LEN0: /* Length EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->len, c)) {
if (gsm->len > gsm->mru) {
@@ -1774,8 +1789,28 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
}
gsm->count = 0;
- gsm->state = GSM_DATA;
+ if (!gsm->len)
+ gsm->state = GSM_FCS;
+ else
+ gsm->state = GSM_DATA;
+ break;
+ }
+ gsm->state = GSM_LEN1;
+ break;
+ case GSM_LEN1:
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ len = c;
+ gsm->len |= len << 7;
+ if (gsm->len > gsm->mru) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ break;
}
+ gsm->count = 0;
+ if (!gsm->len)
+ gsm->state = GSM_FCS;
+ else
+ gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
@@ -1783,16 +1818,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_FCS;
break;
case GSM_FCS: /* FCS follows the packet */
- gsm->fcs = c;
+ gsm->received_fcs = c;
+ if (c == GSM0_SOF) {
+ gsm->state = GSM_SEARCH;
+ break;
+ }
gsm_queue(gsm);
- /* And then back for the next frame */
- gsm->state = GSM_SEARCH;
+ gsm->state = GSM_SSOF;
+ break;
+ case GSM_SSOF:
+ if (c == GSM0_SOF) {
+ gsm->state = GSM_SEARCH;
+ break;
+ }
break;
}
}
/**
- * gsm0_receive - perform processing for non-transparency
+ * gsm1_receive - perform processing for non-transparency
* @gsm: gsm data for this ldisc instance
* @c: character
*
@@ -1854,7 +1898,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru ) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
@@ -2032,9 +2076,6 @@ struct gsm_mux *gsm_alloc_mux(void)
}
EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
/**
* gsmld_output - write to link
* @gsm: our mux
@@ -2052,7 +2093,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
return -ENOSPC;
}
if (debug & 4) {
- printk("-->%d bytes out\n", len);
+ pr_debug("-->%d bytes out\n", len);
hex_packet(data, len);
}
gsm->tty->ops->write(gsm->tty, data, len);
@@ -2109,7 +2150,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char flags;
if (debug & 4) {
- printk("Inbytes %dd\n", count);
+ pr_debug("Inbytes %dd\n", count);
hex_packet(cp, count);
}
@@ -2126,7 +2167,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
gsm->error(gsm, *dp, flags);
break;
default:
- printk(KERN_ERR "%s: unknown flag %d\n",
+ WARN_ONCE("%s: unknown flag %d\n",
tty_name(tty, buf), flags);
break;
}
@@ -2321,7 +2362,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
int need_restart = 0;
/* Stuff we don't support yet - UI or I frame transport, windowing */
- if ((c->adaption !=1 && c->adaption != 2) || c->k)
+ if ((c->adaption != 1 && c->adaption != 2) || c->k)
return -EOPNOTSUPP;
/* Check the MRU/MTU range looks sane */
if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
@@ -2375,6 +2416,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
gsm->mru = c->mru;
gsm->encoding = c->encapsulation;
gsm->adaption = c->adaption;
+ gsm->n2 = c->n2;
if (c->i == 1)
gsm->ftype = UIH;
@@ -2415,7 +2457,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
c.i = 1;
else
c.i = 2;
- printk("Ftype %d i %d\n", gsm->ftype, c.i);
+ pr_debug("Ftype %d i %d\n", gsm->ftype, c.i);
c.mru = gsm->mru;
c.mtu = gsm->mtu;
c.k = 0;
@@ -2709,14 +2751,15 @@ static int __init gsm_init(void)
/* Fill in our line protocol discipline, and register it */
int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
if (status != 0) {
- printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+ pr_err("n_gsm: can't register line discipline (err = %d)\n",
+ status);
return status;
}
gsm_tty_driver = alloc_tty_driver(256);
if (!gsm_tty_driver) {
tty_unregister_ldisc(N_GSM0710);
- printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+ pr_err("gsm_init: tty allocation failed.\n");
return -EINVAL;
}
gsm_tty_driver->owner = THIS_MODULE;
@@ -2727,7 +2770,7 @@ static int __init gsm_init(void)
gsm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
gsm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_HARDWARE_BREAK;
+ | TTY_DRIVER_HARDWARE_BREAK;
gsm_tty_driver->init_termios = tty_std_termios;
/* Fixme */
gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
@@ -2738,10 +2781,11 @@ static int __init gsm_init(void)
if (tty_register_driver(gsm_tty_driver)) {
put_tty_driver(gsm_tty_driver);
tty_unregister_ldisc(N_GSM0710);
- printk(KERN_ERR "gsm_init: tty registration failed.\n");
+ pr_err("gsm_init: tty registration failed.\n");
return -EBUSY;
}
- printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+ pr_debug("gsm_init: loaded as %d,%d.\n",
+ gsm_tty_driver->major, gsm_tty_driver->minor_start);
return 0;
}
@@ -2749,10 +2793,10 @@ static void __exit gsm_exit(void)
{
int status = tty_unregister_ldisc(N_GSM0710);
if (status != 0)
- printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+ pr_err("n_gsm: can't unregister line discipline (err = %d)\n",
+ status);
tty_unregister_driver(gsm_tty_driver);
put_tty_driver(gsm_tty_driver);
- printk(KERN_INFO "gsm_init: unloaded.\n");
}
module_init(gsm_init);
diff --git a/drivers/char/n_hdlc.c b/drivers/tty/n_hdlc.c
index 47d32281032c..47d32281032c 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
diff --git a/drivers/char/n_r3964.c b/drivers/tty/n_r3964.c
index 88dda0c45ee0..88dda0c45ee0 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/tty/n_r3964.c
diff --git a/drivers/char/n_tty.c b/drivers/tty/n_tty.c
index 428f4fe0b5f7..428f4fe0b5f7 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/tty/n_tty.c
diff --git a/drivers/char/pty.c b/drivers/tty/pty.c
index 923a48585501..923a48585501 100644
--- a/drivers/char/pty.c
+++ b/drivers/tty/pty.c
diff --git a/drivers/char/sysrq.c b/drivers/tty/sysrq.c
index eaa5d3efa79d..c556ed9db13d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -554,7 +554,7 @@ EXPORT_SYMBOL(handle_sysrq);
#ifdef CONFIG_INPUT
/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
+static const unsigned char sysrq_xlate[KEY_CNT] =
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
@@ -563,53 +563,129 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] =
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
"\r\000/"; /* 0x60 - 0x6f */
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-static DEFINE_SPINLOCK(sysrq_event_lock);
+struct sysrq_state {
+ struct input_handle handle;
+ struct work_struct reinject_work;
+ unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+ unsigned int alt;
+ unsigned int alt_use;
+ bool active;
+ bool need_reinject;
+};
+
+static void sysrq_reinject_alt_sysrq(struct work_struct *work)
+{
+ struct sysrq_state *sysrq =
+ container_of(work, struct sysrq_state, reinject_work);
+ struct input_handle *handle = &sysrq->handle;
+ unsigned int alt_code = sysrq->alt_use;
+
+ if (sysrq->need_reinject) {
+ /* Simulate press and release of Alt + SysRq */
+ input_inject_event(handle, EV_KEY, alt_code, 1);
+ input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+
+ input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
+ input_inject_event(handle, EV_KEY, alt_code, 0);
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+ }
+}
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
- unsigned int code, int value)
+static bool sysrq_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
+ struct sysrq_state *sysrq = handle->private;
+ bool was_active = sysrq->active;
bool suppress;
- /* We are called with interrupts disabled, just take the lock */
- spin_lock(&sysrq_event_lock);
+ switch (type) {
- if (type != EV_KEY)
- goto out;
+ case EV_SYN:
+ suppress = false;
+ break;
- switch (code) {
+ case EV_KEY:
+ switch (code) {
- case KEY_LEFTALT:
- case KEY_RIGHTALT:
- if (value)
- sysrq_alt = code;
- else {
- if (sysrq_down && code == sysrq_alt_use)
- sysrq_down = false;
+ case KEY_LEFTALT:
+ case KEY_RIGHTALT:
+ if (!value) {
+ /* One of ALTs is being released */
+ if (sysrq->active && code == sysrq->alt_use)
+ sysrq->active = false;
- sysrq_alt = 0;
+ sysrq->alt = KEY_RESERVED;
+
+ } else if (value != 2) {
+ sysrq->alt = code;
+ sysrq->need_reinject = false;
+ }
+ break;
+
+ case KEY_SYSRQ:
+ if (value == 1 && sysrq->alt != KEY_RESERVED) {
+ sysrq->active = true;
+ sysrq->alt_use = sysrq->alt;
+ /*
+ * If nothing else will be pressed we'll need
+ * to * re-inject Alt-SysRq keysroke.
+ */
+ sysrq->need_reinject = true;
+ }
+
+ /*
+ * Pretend that sysrq was never pressed at all. This
+ * is needed to properly handle KGDB which will try
+ * to release all keys after exiting debugger. If we
+ * do not clear key bit it KGDB will end up sending
+ * release events for Alt and SysRq, potentially
+ * triggering print screen function.
+ */
+ if (sysrq->active)
+ clear_bit(KEY_SYSRQ, handle->dev->key);
+
+ break;
+
+ default:
+ if (sysrq->active && value && value != 2) {
+ sysrq->need_reinject = false;
+ __handle_sysrq(sysrq_xlate[code], true);
+ }
+ break;
}
- break;
- case KEY_SYSRQ:
- if (value == 1 && sysrq_alt) {
- sysrq_down = true;
- sysrq_alt_use = sysrq_alt;
+ suppress = sysrq->active;
+
+ if (!sysrq->active) {
+ /*
+ * If we are not suppressing key presses keep track of
+ * keyboard state so we can release keys that have been
+ * pressed before entering SysRq mode.
+ */
+ if (value)
+ set_bit(code, sysrq->key_down);
+ else
+ clear_bit(code, sysrq->key_down);
+
+ if (was_active)
+ schedule_work(&sysrq->reinject_work);
+
+ } else if (value == 0 &&
+ test_and_clear_bit(code, sysrq->key_down)) {
+ /*
+ * Pass on release events for keys that was pressed before
+ * entering SysRq mode.
+ */
+ suppress = false;
}
break;
default:
- if (sysrq_down && value && value != 2)
- __handle_sysrq(sysrq_xlate[code], true);
+ suppress = sysrq->active;
break;
}
-out:
- suppress = sysrq_down;
- spin_unlock(&sysrq_event_lock);
-
return suppress;
}
@@ -617,28 +693,28 @@ static int sysrq_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
- struct input_handle *handle;
+ struct sysrq_state *sysrq;
int error;
- sysrq_down = false;
- sysrq_alt = 0;
-
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
+ sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
+ if (!sysrq)
return -ENOMEM;
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "sysrq";
+ INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
+
+ sysrq->handle.dev = dev;
+ sysrq->handle.handler = handler;
+ sysrq->handle.name = "sysrq";
+ sysrq->handle.private = sysrq;
- error = input_register_handle(handle);
+ error = input_register_handle(&sysrq->handle);
if (error) {
pr_err("Failed to register input sysrq handler, error %d\n",
error);
goto err_free;
}
- error = input_open_device(handle);
+ error = input_open_device(&sysrq->handle);
if (error) {
pr_err("Failed to open input device, error %d\n", error);
goto err_unregister;
@@ -647,17 +723,20 @@ static int sysrq_connect(struct input_handler *handler,
return 0;
err_unregister:
- input_unregister_handle(handle);
+ input_unregister_handle(&sysrq->handle);
err_free:
- kfree(handle);
+ kfree(sysrq);
return error;
}
static void sysrq_disconnect(struct input_handle *handle)
{
+ struct sysrq_state *sysrq = handle->private;
+
input_close_device(handle);
+ cancel_work_sync(&sysrq->reinject_work);
input_unregister_handle(handle);
- kfree(handle);
+ kfree(sysrq);
}
/*
diff --git a/drivers/char/tty_audit.c b/drivers/tty/tty_audit.c
index 1b8ee590b4ca..f64582b0f623 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -188,25 +188,43 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
}
/**
- * tty_audit_push_task - Flush task's pending audit data
+ * tty_audit_push_task - Flush task's pending audit data
+ * @tsk: task pointer
+ * @loginuid: sender login uid
+ * @sessionid: sender session id
+ *
+ * Called with a ref on @tsk held. Try to lock sighand and get a
+ * reference to the tty audit buffer if available.
+ * Flush the buffer or return an appropriate error code.
*/
-void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
{
- struct tty_audit_buf *buf;
+ struct tty_audit_buf *buf = ERR_PTR(-EPERM);
+ unsigned long flags;
- spin_lock_irq(&tsk->sighand->siglock);
- buf = tsk->signal->tty_audit_buf;
- if (buf)
- atomic_inc(&buf->count);
- spin_unlock_irq(&tsk->sighand->siglock);
- if (!buf)
- return;
+ if (!lock_task_sighand(tsk, &flags))
+ return -ESRCH;
+
+ if (tsk->signal->audit_tty) {
+ buf = tsk->signal->tty_audit_buf;
+ if (buf)
+ atomic_inc(&buf->count);
+ }
+ unlock_task_sighand(tsk, &flags);
+
+ /*
+ * Return 0 when signal->audit_tty set
+ * but tsk->signal->tty_audit_buf == NULL.
+ */
+ if (!buf || IS_ERR(buf))
+ return PTR_ERR(buf);
mutex_lock(&buf->mutex);
tty_audit_buf_push(tsk, loginuid, sessionid, buf);
mutex_unlock(&buf->mutex);
tty_audit_buf_put(buf);
+ return 0;
}
/**
diff --git a/drivers/char/tty_buffer.c b/drivers/tty/tty_buffer.c
index cc1e9850d655..d8210ca00720 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -413,7 +413,8 @@ static void flush_to_ldisc(struct work_struct *work)
spin_lock_irqsave(&tty->buf.lock, flags);
if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
- struct tty_buffer *head;
+ struct tty_buffer *head, *tail = tty->buf.tail;
+ int seen_tail = 0;
while ((head = tty->buf.head) != NULL) {
int count;
char *char_buf;
@@ -423,6 +424,15 @@ static void flush_to_ldisc(struct work_struct *work)
if (!count) {
if (head->next == NULL)
break;
+ /*
+ There's a possibility tty might get new buffer
+ added during the unlock window below. We could
+ end up spinning in here forever hogging the CPU
+ completely. To avoid this let's have a rest each
+ time we processed the tail buffer.
+ */
+ if (tail == head)
+ seen_tail = 1;
tty->buf.head = head->next;
tty_buffer_free(tty, head);
continue;
@@ -432,7 +442,7 @@ static void flush_to_ldisc(struct work_struct *work)
line discipline as we want to empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
break;
- if (!tty->receive_room) {
+ if (!tty->receive_room || seen_tail) {
schedule_delayed_work(&tty->buf.work, 1);
break;
}
diff --git a/drivers/char/tty_io.c b/drivers/tty/tty_io.c
index c05c5af5aa04..464d09d97873 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -559,6 +559,9 @@ void __tty_hangup(struct tty_struct *tty)
tty_lock();
+ /* some functions below drop BTM, so we need this bit */
+ set_bit(TTY_HUPPING, &tty->flags);
+
/* inuse_filps is protected by the single tty lock,
this really needs to change if we want to flush the
workqueue with the lock held */
@@ -578,6 +581,10 @@ void __tty_hangup(struct tty_struct *tty)
}
spin_unlock(&tty_files_lock);
+ /*
+ * it drops BTM and thus races with reopen
+ * we protect the race by TTY_HUPPING
+ */
tty_ldisc_hangup(tty);
read_lock(&tasklist_lock);
@@ -615,7 +622,6 @@ void __tty_hangup(struct tty_struct *tty)
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
- set_bit(TTY_HUPPED, &tty->flags);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
/* Account for the p->signal references we killed */
@@ -641,6 +647,7 @@ void __tty_hangup(struct tty_struct *tty)
* can't yet guarantee all that.
*/
set_bit(TTY_HUPPED, &tty->flags);
+ clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
tty_unlock();
@@ -1310,7 +1317,9 @@ static int tty_reopen(struct tty_struct *tty)
{
struct tty_driver *driver = tty->driver;
- if (test_bit(TTY_CLOSING, &tty->flags))
+ if (test_bit(TTY_CLOSING, &tty->flags) ||
+ test_bit(TTY_HUPPING, &tty->flags) ||
+ test_bit(TTY_LDISC_CHANGING, &tty->flags))
return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2618,6 +2627,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(tty->ldisc->ops->num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
+ case TIOCGDEV:
+ {
+ unsigned int ret = new_encode_dev(tty_devnum(real_tty));
+ return put_user(ret, (unsigned int __user *)p);
+ }
/*
* Break handling
*/
@@ -3232,9 +3246,45 @@ static int __init tty_class_init(void)
postcore_initcall(tty_class_init);
/* 3/2004 jmc: why do these devices exist? */
-
static struct cdev tty_cdev, console_cdev;
+static ssize_t show_cons_active(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct console *cs[16];
+ int i = 0;
+ struct console *c;
+ ssize_t count = 0;
+
+ acquire_console_sem();
+ for (c = console_drivers; c; c = c->next) {
+ if (!c->device)
+ continue;
+ if (!c->write)
+ continue;
+ if ((c->flags & CON_ENABLED) == 0)
+ continue;
+ cs[i++] = c;
+ if (i >= ARRAY_SIZE(cs))
+ break;
+ }
+ while (i--)
+ count += sprintf(buf + count, "%s%d%c",
+ cs[i]->name, cs[i]->index, i ? ' ':'\n');
+ release_console_sem();
+
+ return count;
+}
+static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
+
+static struct device *consdev;
+
+void console_sysfs_notify(void)
+{
+ if (consdev)
+ sysfs_notify(&consdev->kobj, NULL, "active");
+}
+
/*
* Ok, now we can initialize the rest of the tty devices and can count
* on memory allocations, interrupts etc..
@@ -3245,15 +3295,18 @@ int __init tty_init(void)
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
panic("Couldn't register /dev/tty driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
- "tty");
+ device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+ consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
"console");
+ if (IS_ERR(consdev))
+ consdev = NULL;
+ else
+ device_create_file(consdev, &dev_attr_active);
#ifdef CONFIG_VT
vty_init(&console_fops);
diff --git a/drivers/char/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 0c1889971459..0c1889971459 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
diff --git a/drivers/char/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 412f9775d19c..4214d58276f7 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -47,6 +47,7 @@
static DEFINE_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
@@ -83,6 +84,7 @@ static void put_ldisc(struct tty_ldisc *ld)
return;
}
local_irq_restore(flags);
+ wake_up(&tty_ldisc_idle);
}
/**
@@ -452,6 +454,8 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
/* BTM here locks versus a hangup event */
WARN_ON(!tty_locked());
ret = ld->ops->open(tty);
+ if (ret)
+ clear_bit(TTY_LDISC_OPEN, &tty->flags);
return ret;
}
return 0;
@@ -531,6 +535,23 @@ static int tty_ldisc_halt(struct tty_struct *tty)
}
/**
+ * tty_ldisc_wait_idle - wait for the ldisc to become idle
+ * @tty: tty to wait for
+ *
+ * Wait for the line discipline to become idle. The discipline must
+ * have been halted for this to guarantee it remains idle.
+ */
+static int tty_ldisc_wait_idle(struct tty_struct *tty)
+{
+ int ret;
+ ret = wait_event_interruptible_timeout(tty_ldisc_idle,
+ atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+ if (ret < 0)
+ return ret;
+ return ret > 0 ? 0 : -EBUSY;
+}
+
+/**
* tty_set_ldisc - set line discipline
* @tty: the terminal to set
* @ldisc: the line discipline
@@ -634,8 +655,17 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
flush_scheduled_work();
+ retval = tty_ldisc_wait_idle(tty);
+
tty_lock();
mutex_lock(&tty->ldisc_mutex);
+
+ /* handle wait idle failure locked */
+ if (retval) {
+ tty_ldisc_put(new_ldisc);
+ goto enable;
+ }
+
if (test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
the ldisc data and closed the ldisc down */
@@ -669,6 +699,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_ldisc_put(o_ldisc);
+enable:
/*
* Allow ldisc referencing to occur again
*/
@@ -714,9 +745,12 @@ static void tty_reset_termios(struct tty_struct *tty)
* state closed
*/
-static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
{
- struct tty_ldisc *ld;
+ struct tty_ldisc *ld = tty_ldisc_get(ldisc);
+
+ if (IS_ERR(ld))
+ return -1;
tty_ldisc_close(tty, tty->ldisc);
tty_ldisc_put(tty->ldisc);
@@ -724,10 +758,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
/*
* Switch the line discipline back
*/
- ld = tty_ldisc_get(ldisc);
- BUG_ON(IS_ERR(ld));
tty_ldisc_assign(tty, ld);
tty_set_termios_ldisc(tty, ldisc);
+
+ return 0;
}
/**
@@ -802,13 +836,16 @@ void tty_ldisc_hangup(struct tty_struct *tty)
a FIXME */
if (tty->ldisc) { /* Not yet closed */
if (reset == 0) {
- tty_ldisc_reinit(tty, tty->termios->c_line);
- err = tty_ldisc_open(tty, tty->ldisc);
+
+ if (!tty_ldisc_reinit(tty, tty->termios->c_line))
+ err = tty_ldisc_open(tty, tty->ldisc);
+ else
+ err = 1;
}
/* If the re-open fails or we reset then go to N_TTY. The
N_TTY open cannot fail */
if (reset || err) {
- tty_ldisc_reinit(tty, N_TTY);
+ BUG_ON(tty_ldisc_reinit(tty, N_TTY));
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
}
tty_ldisc_enable(tty);
diff --git a/drivers/char/tty_mutex.c b/drivers/tty/tty_mutex.c
index 133697540c73..133697540c73 100644
--- a/drivers/char/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
diff --git a/drivers/char/tty_port.c b/drivers/tty/tty_port.c
index 33d37d230f8f..33d37d230f8f 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/tty/tty_port.c
diff --git a/drivers/char/.gitignore b/drivers/tty/vt/.gitignore
index 83683a2d8e6a..83683a2d8e6a 100644
--- a/drivers/char/.gitignore
+++ b/drivers/tty/vt/.gitignore
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
new file mode 100644
index 000000000000..14a51c9960df
--- /dev/null
+++ b/drivers/tty/vt/Makefile
@@ -0,0 +1,34 @@
+#
+# This file contains the font map for the default (hardware) font
+#
+FONTMAPFILE = cp437.uni
+
+obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \
+ selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
+
+# Files generated that shall be removed upon make clean
+clean-files := consolemap_deftbl.c defkeymap.c
+
+quiet_cmd_conmk = CONMK $@
+ cmd_conmk = scripts/conmakehash $< > $@
+
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+ $(call cmd,conmk)
+
+$(obj)/defkeymap.o: $(obj)/defkeymap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
+ loadkeys --mktable $< > $@.tmp
+ sed -e 's/^static *//' $@.tmp > $@
+ rm $@.tmp
+
+endif
diff --git a/drivers/char/consolemap.c b/drivers/tty/vt/consolemap.c
index 45d3e80156d4..45d3e80156d4 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
diff --git a/drivers/char/cp437.uni b/drivers/tty/vt/cp437.uni
index bc6163484f62..bc6163484f62 100644
--- a/drivers/char/cp437.uni
+++ b/drivers/tty/vt/cp437.uni
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped
index d2208dfe3f67..d2208dfe3f67 100644
--- a/drivers/char/defkeymap.c_shipped
+++ b/drivers/tty/vt/defkeymap.c_shipped
diff --git a/drivers/char/defkeymap.map b/drivers/tty/vt/defkeymap.map
index 50b30cace261..50b30cace261 100644
--- a/drivers/char/defkeymap.map
+++ b/drivers/tty/vt/defkeymap.map
diff --git a/drivers/char/keyboard.c b/drivers/tty/vt/keyboard.c
index e95d7876ca6b..e95d7876ca6b 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
diff --git a/drivers/char/selection.c b/drivers/tty/vt/selection.c
index ebae344ce910..ebae344ce910 100644
--- a/drivers/char/selection.c
+++ b/drivers/tty/vt/selection.c
diff --git a/drivers/char/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 273ab44cc91d..eab3a1ff99e4 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -553,12 +553,12 @@ static unsigned int
vcs_poll(struct file *file, poll_table *wait)
{
struct vcs_poll_data *poll = vcs_poll_data_get(file);
- int ret = 0;
+ int ret = DEFAULT_POLLMASK|POLLERR|POLLPRI;
if (poll) {
poll_wait(file, &poll->waitq, wait);
- if (!poll->seen_last_update)
- ret = POLLIN | POLLRDNORM;
+ if (poll->seen_last_update)
+ ret = DEFAULT_POLLMASK;
}
return ret;
}
diff --git a/drivers/char/vt.c b/drivers/tty/vt/vt.c
index a8ec48ed14d9..76407eca9ab0 100644
--- a/drivers/char/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -236,6 +236,14 @@ enum {
};
/*
+ * /sys/class/tty/tty0/
+ *
+ * the attribute 'active' contains the name of the current vc
+ * console and it supports poll() to detect vc switches
+ */
+static struct device *tty0dev;
+
+/*
* Notifier list for console events.
*/
static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
@@ -688,6 +696,8 @@ void redraw_screen(struct vc_data *vc, int is_switch)
save_screen(old_vc);
set_origin(old_vc);
}
+ if (tty0dev)
+ sysfs_notify(&tty0dev->kobj, NULL, "active");
} else {
hide_cursor(vc);
redraw = 1;
@@ -2967,13 +2977,24 @@ static const struct tty_operations con_ops = {
static struct cdev vc0_cdev;
+static ssize_t show_tty_active(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "tty%d\n", fg_console + 1);
+}
+static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
+
int __init vty_init(const struct file_operations *console_fops)
{
cdev_init(&vc0_cdev, console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
- device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+ tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+ if (IS_ERR(tty0dev))
+ tty0dev = NULL;
+ else
+ device_create_file(tty0dev, &dev_attr_active);
vcs_init();
diff --git a/drivers/char/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 6b68a0fb4611..6b68a0fb4611 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index a858d2b87b94..51fe1795d5a8 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -3,7 +3,7 @@
*
* 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, Hans J. Koch <hjk@hansjkoch.de>
* Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
*
* Userspace IO
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
index a8ea2f19a0cc..a84a451159ed 100644
--- a/drivers/uio/uio_cif.c
+++ b/drivers/uio/uio_cif.c
@@ -1,7 +1,7 @@
/*
* UIO Hilscher CIF card driver
*
- * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
* Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
*
* Licensed under GPL version 2 only.
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c
index 5a18e9f7b836..5ffdb483b015 100644
--- a/drivers/uio/uio_netx.c
+++ b/drivers/uio/uio_netx.c
@@ -2,7 +2,7 @@
* UIO driver for Hilscher NetX based fieldbus cards (cifX, comX).
* See http://www.hilscher.com for details.
*
- * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
* (C) 2008 Manuel Traut <manut@linutronix.de>
*
* Licensed under GPL version 2 only.
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 67eb3770868f..fceea5e4e02f 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -41,17 +41,14 @@ config USB_ARCH_HAS_OHCI
default y if MFD_TC6393XB
default y if ARCH_W90X900
default y if ARCH_DAVINCI_DA8XX
+ default y if ARCH_CNS3XXX
+ default y if PLAT_SPEAR
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
# MIPS:
default y if MIPS_ALCHEMY
default y if MACH_JZ4740
- # SH:
- default y if CPU_SUBTYPE_SH7720
- default y if CPU_SUBTYPE_SH7721
- default y if CPU_SUBTYPE_SH7763
- default y if CPU_SUBTYPE_SH7786
# more:
default PCI
@@ -66,6 +63,10 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_AT91SAM9G45
default y if ARCH_MXC
default y if ARCH_OMAP3
+ default y if ARCH_CNS3XXX
+ default y if ARCH_VT8500
+ default y if PLAT_SPEAR
+ default y if ARCH_MSM
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index f383cb42b1d7..a845f8b8382f 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -1247,7 +1247,7 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
mutex_unlock(&instance->poll_state_serialize);
if (is_polling)
- cancel_rearming_delayed_work(&instance->poll_work);
+ cancel_delayed_work_sync(&instance->poll_work);
usb_kill_urb(instance->snd_urb);
usb_kill_urb(instance->rcv_urb);
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 4716e707de59..0842cfbf60cf 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -139,7 +139,8 @@ struct speedtch_instance_data {
struct speedtch_params params; /* set in probe, constant afterwards */
- struct delayed_work status_checker;
+ struct timer_list status_check_timer;
+ struct work_struct status_check_work;
unsigned char last_status;
@@ -498,7 +499,7 @@ static void speedtch_check_status(struct work_struct *work)
{
struct speedtch_instance_data *instance =
container_of(work, struct speedtch_instance_data,
- status_checker.work);
+ status_check_work);
struct usbatm_data *usbatm = instance->usbatm;
struct atm_dev *atm_dev = usbatm->atm_dev;
unsigned char *buf = instance->scratch_buffer;
@@ -575,11 +576,11 @@ static void speedtch_status_poll(unsigned long data)
{
struct speedtch_instance_data *instance = (void *)data;
- schedule_delayed_work(&instance->status_checker, 0);
+ schedule_work(&instance->status_check_work);
/* The following check is racy, but the race is harmless */
if (instance->poll_delay < MAX_POLL_DELAY)
- mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
+ mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(instance->poll_delay));
else
atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
}
@@ -595,7 +596,7 @@ static void speedtch_resubmit_int(unsigned long data)
if (int_urb) {
ret = usb_submit_urb(int_urb, GFP_ATOMIC);
if (!ret)
- schedule_delayed_work(&instance->status_checker, 0);
+ schedule_work(&instance->status_check_work);
else {
atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
@@ -624,7 +625,7 @@ static void speedtch_handle_int(struct urb *int_urb)
}
if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
- del_timer(&instance->status_checker.timer);
+ del_timer(&instance->status_check_timer);
atm_info(usbatm, "DSL line goes up\n");
} else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
atm_info(usbatm, "DSL line goes down\n");
@@ -640,7 +641,7 @@ static void speedtch_handle_int(struct urb *int_urb)
if ((int_urb = instance->int_urb)) {
ret = usb_submit_urb(int_urb, GFP_ATOMIC);
- schedule_delayed_work(&instance->status_checker, 0);
+ schedule_work(&instance->status_check_work);
if (ret < 0) {
atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
goto fail;
@@ -686,7 +687,7 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de
}
/* Start status polling */
- mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
+ mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(1000));
return 0;
}
@@ -698,7 +699,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de
atm_dbg(usbatm, "%s entered\n", __func__);
- del_timer_sync(&instance->status_checker.timer);
+ del_timer_sync(&instance->status_check_timer);
/*
* Since resubmit_timer and int_urb can schedule themselves and
@@ -717,7 +718,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de
del_timer_sync(&instance->resubmit_timer);
usb_free_urb(int_urb);
- flush_scheduled_work();
+ flush_work_sync(&instance->status_check_work);
}
static int speedtch_pre_reset(struct usb_interface *intf)
@@ -869,10 +870,11 @@ static int speedtch_bind(struct usbatm_data *usbatm,
usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
- INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status);
+ INIT_WORK(&instance->status_check_work, speedtch_check_status);
+ init_timer(&instance->status_check_timer);
- instance->status_checker.timer.function = speedtch_status_poll;
- instance->status_checker.timer.data = (unsigned long)instance;
+ instance->status_check_timer.function = speedtch_status_poll;
+ instance->status_check_timer.data = (unsigned long)instance;
instance->last_status = 0xff;
instance->poll_delay = MIN_POLL_DELAY;
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index ea071a5b6eee..99ac70e32556 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2206,8 +2206,11 @@ static int uea_boot(struct uea_softc *sc)
goto err1;
}
- sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
- if (sc->kthread == ERR_PTR(-ENOMEM)) {
+ /* Create worker thread, but don't start it here. Start it after
+ * all usbatm generic initialization is done.
+ */
+ sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm");
+ if (IS_ERR(sc->kthread)) {
uea_err(INS_TO_USBDEV(sc), "failed to create thread\n");
goto err2;
}
@@ -2301,7 +2304,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
+static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot);
static ssize_t read_human_status(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -2364,8 +2367,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
- read_human_status, NULL);
+static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL);
static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2397,7 +2399,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
+static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL);
#define UEA_ATTR(name, reset) \
\
@@ -2625,6 +2627,7 @@ static struct usbatm_driver uea_usbatm_driver = {
static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usb = interface_to_usbdev(intf);
+ int ret;
uea_enters(usb);
uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
@@ -2638,7 +2641,19 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (UEA_IS_PREFIRM(id))
return uea_load_firmware(usb, UEA_CHIP_VERSION(id));
- return usbatm_usb_probe(intf, id, &uea_usbatm_driver);
+ ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver);
+ if (ret == 0) {
+ struct usbatm_data *usbatm = usb_get_intfdata(intf);
+ struct uea_softc *sc = usbatm->driver_data;
+
+ /* Ensure carrier is initialized to off as early as possible */
+ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST);
+
+ /* Only start the worker thread when all init is done */
+ wake_up_process(sc->kthread);
+ }
+
+ return ret;
}
static void uea_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 05bf5a27b5b0..989e16e4ab5c 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -951,7 +951,9 @@ static int usbatm_atm_init(struct usbatm_data *instance)
* condition: callbacks we register can be executed at once, before we have
* initialized the struct atm_dev. To protect against this, all callbacks
* abort if atm_dev->dev_data is NULL. */
- atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+ atm_dev = atm_dev_register(instance->driver_name,
+ &instance->usb_intf->dev, &usbatm_atm_devops,
+ -1, NULL);
if (!atm_dev) {
usb_err(instance, "%s: failed to register ATM device!\n", __func__);
return -1;
@@ -966,14 +968,6 @@ static int usbatm_atm_init(struct usbatm_data *instance)
/* temp init ATM device, set to 128kbit */
atm_dev->link_rate = 128 * 1000 / 424;
- ret = sysfs_create_link(&atm_dev->class_dev.kobj,
- &instance->usb_intf->dev.kobj, "device");
- if (ret) {
- atm_err(instance, "%s: sysfs_create_link failed: %d\n",
- __func__, ret);
- goto fail_sysfs;
- }
-
if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
goto fail;
@@ -992,8 +986,6 @@ static int usbatm_atm_init(struct usbatm_data *instance)
return 0;
fail:
- sysfs_remove_link(&atm_dev->class_dev.kobj, "device");
- fail_sysfs:
instance->atm_dev = NULL;
atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
return ret;
@@ -1329,7 +1321,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
/* ATM finalize */
if (instance->atm_dev) {
- sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
instance->atm_dev = NULL;
}
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 9eed5b52d9de..bcc24779ba0e 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -107,11 +107,19 @@ config USB_SUSPEND
If you are unsure about this, say N here.
config USB_OTG
- bool
+ bool "OTG support"
depends on USB && EXPERIMENTAL
depends on USB_SUSPEND
default n
-
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role is decided by the type of
+ plug inserted and can be changed later when two dual
+ role devices talk to each other.
+
+ Select this only if your board has Mini-AB/Micro-AB
+ connector.
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ddb4dc980923..a3d2e2399655 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -54,7 +54,6 @@
#include <linux/gfp.h>
#include <linux/poll.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/mutex.h>
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index f1aaff6202a5..a7131ad630f9 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -37,7 +37,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/module.h>
@@ -965,10 +964,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
static int proc_connectinfo(struct dev_state *ps, void __user *arg)
{
- struct usbdevfs_connectinfo ci;
+ struct usbdevfs_connectinfo ci = {
+ .devnum = ps->dev->devnum,
+ .slow = ps->dev->speed == USB_SPEED_LOW
+ };
- ci.devnum = ps->dev->devnum;
- ci.slow = ps->dev->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci)))
return -EFAULT;
return 0;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index c0e60fbcb048..fca61720b873 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -27,7 +27,6 @@
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h>
-#include <linux/pm_runtime.h>
#include "usb.h"
@@ -376,7 +375,7 @@ static int usb_unbind_interface(struct device *dev)
* Just re-enable it without affecting the endpoint toggles.
*/
usb_enable_interface(udev, intf, false);
- } else if (!error && intf->dev.power.status == DPM_ON) {
+ } else if (!error && !intf->dev.power.in_suspend) {
r = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
if (r < 0)
@@ -961,7 +960,7 @@ void usb_rebind_intf(struct usb_interface *intf)
}
/* Try to rebind the interface */
- if (intf->dev.power.status == DPM_ON) {
+ if (!intf->dev.power.in_suspend) {
intf->needs_binding = 0;
rc = device_attach(&intf->dev);
if (rc < 0)
@@ -1108,8 +1107,7 @@ static int usb_resume_interface(struct usb_device *udev,
if (intf->condition == USB_INTERFACE_UNBOUND) {
/* Carry out a deferred switch to altsetting 0 */
- if (intf->needs_altsetting0 &&
- intf->dev.power.status == DPM_ON) {
+ if (intf->needs_altsetting0 && !intf->dev.power.in_suspend) {
usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
intf->needs_altsetting0 = 0;
@@ -1262,6 +1260,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
udev->reset_resume);
}
}
+ usb_mark_last_busy(udev);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@@ -1329,7 +1328,6 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- udev->last_busy = jiffies;
do_unbind_rebind(udev, DO_REBIND);
}
}
@@ -1397,33 +1395,8 @@ void usb_autosuspend_device(struct usb_device *udev)
{
int status;
- udev->last_busy = jiffies;
- status = pm_runtime_put_sync(&udev->dev);
- dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
- __func__, atomic_read(&udev->dev.power.usage_count),
- status);
-}
-
-/**
- * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
- * @udev: the usb_device to autosuspend
- *
- * This routine should be called when a core subsystem thinks @udev may
- * be ready to autosuspend.
- *
- * @udev's usage counter left unchanged. If it is 0 and all the interfaces
- * are inactive then an autosuspend will be attempted. The attempt may
- * fail or be delayed.
- *
- * The caller must hold @udev's device lock.
- *
- * This routine can run only in process context.
- */
-void usb_try_autosuspend_device(struct usb_device *udev)
-{
- int status;
-
- status = pm_runtime_idle(&udev->dev);
+ usb_mark_last_busy(udev);
+ status = pm_runtime_put_sync_autosuspend(&udev->dev);
dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&udev->dev.power.usage_count),
status);
@@ -1482,7 +1455,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
struct usb_device *udev = interface_to_usbdev(intf);
int status;
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
status = pm_runtime_put_sync(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
@@ -1509,32 +1482,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
void usb_autopm_put_interface_async(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- unsigned long last_busy;
- int status = 0;
+ int status;
- last_busy = udev->last_busy;
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
- pm_runtime_put_noidle(&intf->dev);
-
- if (udev->dev.power.runtime_auto) {
- /* Optimization: Don't schedule a delayed autosuspend if
- * the timer is already running and the expiration time
- * wouldn't change.
- *
- * We have to use the interface's timer. Attempts to
- * schedule a suspend for the device would fail because
- * the interface is still active.
- */
- if (intf->dev.power.timer_expires == 0 ||
- round_jiffies_up(last_busy) !=
- round_jiffies_up(jiffies)) {
- status = pm_schedule_suspend(&intf->dev,
- jiffies_to_msecs(
- round_jiffies_up_relative(
- udev->autosuspend_delay)));
- }
- }
+ status = pm_runtime_put(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count),
status);
@@ -1554,7 +1506,7 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
pm_runtime_put_noidle(&intf->dev);
}
@@ -1612,18 +1564,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
*/
int usb_autopm_get_interface_async(struct usb_interface *intf)
{
- int status = 0;
- enum rpm_status s;
-
- /* Don't request a resume unless the interface is already suspending
- * or suspended. Doing so would force a running suspend timer to be
- * cancelled.
- */
- pm_runtime_get_noresume(&intf->dev);
- s = ACCESS_ONCE(intf->dev.power.runtime_status);
- if (s == RPM_SUSPENDING || s == RPM_SUSPENDED)
- status = pm_request_resume(&intf->dev);
+ int status;
+ status = pm_runtime_get(&intf->dev);
if (status < 0 && status != -EINPROGRESS)
pm_runtime_put_noidle(&intf->dev);
else
@@ -1650,7 +1593,7 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_inc(&intf->pm_usage_cnt);
pm_runtime_get_noresume(&intf->dev);
}
@@ -1661,7 +1604,6 @@ static int autosuspend_check(struct usb_device *udev)
{
int w, i;
struct usb_interface *intf;
- unsigned long suspend_time, j;
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
@@ -1701,87 +1643,46 @@ static int autosuspend_check(struct usb_device *udev)
return -EOPNOTSUPP;
}
udev->do_remote_wakeup = w;
-
- /* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request.
- */
- j = ACCESS_ONCE(jiffies);
- suspend_time = udev->last_busy + udev->autosuspend_delay;
- if (time_before(j, suspend_time)) {
- pm_schedule_suspend(&udev->dev, jiffies_to_msecs(
- round_jiffies_up_relative(suspend_time - j)));
- return -EAGAIN;
- }
return 0;
}
static int usb_runtime_suspend(struct device *dev)
{
- int status = 0;
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
/* A USB device can be suspended if it passes the various autosuspend
* checks. Runtime suspend for a USB device means suspending all the
* interfaces and then the device itself.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
-
- if (autosuspend_check(udev) != 0)
- return -EAGAIN;
-
- status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
-
- /* If an interface fails the suspend, adjust the last_busy
- * time so that we don't get another suspend attempt right
- * away.
- */
- if (status) {
- udev->last_busy = jiffies +
- (udev->autosuspend_delay == 0 ?
- HZ/2 : 0);
- }
-
- /* Prevent the parent from suspending immediately after */
- else if (udev->parent)
- udev->parent->last_busy = jiffies;
- }
+ if (autosuspend_check(udev) != 0)
+ return -EAGAIN;
- /* Runtime suspend for a USB interface doesn't mean anything. */
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
return status;
}
static int usb_runtime_resume(struct device *dev)
{
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
+
/* Runtime resume for a USB device means resuming both the device
* and all its interfaces.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
- int status;
-
- status = usb_resume_both(udev, PMSG_AUTO_RESUME);
- udev->last_busy = jiffies;
- return status;
- }
-
- /* Runtime resume for a USB interface doesn't mean anything. */
- return 0;
+ status = usb_resume_both(udev, PMSG_AUTO_RESUME);
+ return status;
}
static int usb_runtime_idle(struct device *dev)
{
+ struct usb_device *udev = to_usb_device(dev);
+
/* An idle USB device can be suspended if it passes the various
- * autosuspend checks. An idle interface can be suspended at
- * any time.
+ * autosuspend checks.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
-
- if (autosuspend_check(udev) != 0)
- return 0;
- }
-
- pm_runtime_suspend(dev);
+ if (autosuspend_check(udev) == 0)
+ pm_runtime_autosuspend(dev);
return 0;
}
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 9fe34fb78ef1..cf6a5423de09 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include "usb.h"
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 3799573bd385..b55d46070a25 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 61800f77dac8..6a95017fa62b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -38,7 +38,6 @@
#include <asm/unaligned.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
-#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -1330,6 +1329,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
*/
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ if (hcd->self.uses_pio_for_control)
+ return ret;
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 27115b45edc5..b98efae6a1cf 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -24,7 +24,6 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
-#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -1804,8 +1803,15 @@ int usb_new_device(struct usb_device *udev)
/* Tell the runtime-PM framework the device is active */
pm_runtime_set_active(&udev->dev);
+ pm_runtime_get_noresume(&udev->dev);
+ pm_runtime_use_autosuspend(&udev->dev);
pm_runtime_enable(&udev->dev);
+ /* By default, forbid autosuspend for all devices. It will be
+ * allowed for hubs during binding.
+ */
+ usb_disable_autosuspend(udev);
+
err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
goto fail;
@@ -1831,6 +1837,8 @@ int usb_new_device(struct usb_device *udev)
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
+ usb_mark_last_busy(udev);
+ pm_runtime_put_sync_autosuspend(&udev->dev);
return err;
fail:
@@ -2221,6 +2229,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
+ usb_mark_last_busy(hub->hdev);
return status;
}
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 9819a4cc3b26..1b125c224dcf 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -39,7 +39,6 @@
#include <linux/parser.h>
#include <linux/notifier.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/usb/hcd.h>
#include <asm/byteorder.h>
#include "usb.h"
@@ -344,17 +343,19 @@ static int usbfs_empty (struct dentry *dentry)
{
struct list_head *list;
- spin_lock(&dcache_lock);
-
+ spin_lock(&dentry->d_lock);
list_for_each(list, &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
+
+ spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
if (usbfs_positive(de)) {
- spin_unlock(&dcache_lock);
+ spin_unlock(&de->d_lock);
+ spin_unlock(&dentry->d_lock);
return 0;
}
+ spin_unlock(&de->d_lock);
}
-
- spin_unlock(&dcache_lock);
+ spin_unlock(&dentry->d_lock);
return 1;
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index d6e3e410477e..832487423826 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1804,6 +1804,7 @@ free_interfaces:
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
intf->minor = -1;
device_initialize(&intf->dev);
+ pm_runtime_no_callbacks(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 25719da45e33..44c595432d6f 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -117,21 +117,6 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
-#ifdef CONFIG_USB_SUSPEND
-
- /* By default, disable autosuspend for all devices. The hub driver
- * will enable it for hubs.
- */
- usb_disable_autosuspend(udev);
-
- /* Autosuspend can also be disabled if the initial autosuspend_delay
- * is negative.
- */
- if (udev->autosuspend_delay < 0)
- usb_autoresume_device(udev);
-
-#endif
-
/* For the present, all devices default to USB-PERSIST enabled */
#if 0 /* was: #ifdef CONFIG_PM */
/* Hubs are automatically enabled for USB-PERSIST */
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 448f5b47fc48..6781c369ce2d 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -233,8 +233,6 @@ static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
#ifdef CONFIG_PM
-static const char power_group[] = "power";
-
static ssize_t
show_persist(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -278,7 +276,7 @@ static int add_persist_attributes(struct device *dev)
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_persist.attr,
- power_group);
+ power_group_name);
}
return rc;
}
@@ -287,7 +285,7 @@ static void remove_persist_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_persist.attr,
- power_group);
+ power_group_name);
}
#else
@@ -336,44 +334,20 @@ static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
static ssize_t
show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct usb_device *udev = to_usb_device(dev);
-
- return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ);
+ return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
}
static ssize_t
set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device(dev);
- int value, old_delay;
- int rc;
+ int value;
- if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
- value <= - INT_MAX/HZ)
+ if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 ||
+ value <= -INT_MAX/1000)
return -EINVAL;
- value *= HZ;
-
- usb_lock_device(udev);
- old_delay = udev->autosuspend_delay;
- udev->autosuspend_delay = value;
-
- if (old_delay < 0) { /* Autosuspend wasn't allowed */
- if (value >= 0)
- usb_autosuspend_device(udev);
- } else { /* Autosuspend was allowed */
- if (value < 0) {
- rc = usb_autoresume_device(udev);
- if (rc < 0) {
- count = rc;
- udev->autosuspend_delay = old_delay;
- }
- } else {
- usb_try_autosuspend_device(udev);
- }
- }
- usb_unlock_device(udev);
+ pm_runtime_set_autosuspend_delay(dev, value * 1000);
return count;
}
@@ -438,44 +412,30 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
+static struct attribute *power_attrs[] = {
+ &dev_attr_autosuspend.attr,
+ &dev_attr_level.attr,
+ &dev_attr_connected_duration.attr,
+ &dev_attr_active_duration.attr,
+ NULL,
+};
+static struct attribute_group power_attr_group = {
+ .name = power_group_name,
+ .attrs = power_attrs,
+};
+
static int add_power_attributes(struct device *dev)
{
int rc = 0;
- if (is_usb_device(dev)) {
- rc = sysfs_add_file_to_group(&dev->kobj,
- &dev_attr_autosuspend.attr,
- power_group);
- if (rc == 0)
- rc = sysfs_add_file_to_group(&dev->kobj,
- &dev_attr_level.attr,
- power_group);
- if (rc == 0)
- rc = sysfs_add_file_to_group(&dev->kobj,
- &dev_attr_connected_duration.attr,
- power_group);
- if (rc == 0)
- rc = sysfs_add_file_to_group(&dev->kobj,
- &dev_attr_active_duration.attr,
- power_group);
- }
+ if (is_usb_device(dev))
+ rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
return rc;
}
static void remove_power_attributes(struct device *dev)
{
- sysfs_remove_file_from_group(&dev->kobj,
- &dev_attr_active_duration.attr,
- power_group);
- sysfs_remove_file_from_group(&dev->kobj,
- &dev_attr_connected_duration.attr,
- power_group);
- sysfs_remove_file_from_group(&dev->kobj,
- &dev_attr_level.attr,
- power_group);
- sysfs_remove_file_from_group(&dev->kobj,
- &dev_attr_autosuspend.attr,
- power_group);
+ sysfs_unmerge_group(&dev->kobj, &power_attr_group);
}
#else
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index fdd4130fbb7d..079cb57bab4f 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -445,7 +445,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
- dev->autosuspend_delay = usb_autosuspend_delay * HZ;
+ pm_runtime_set_autosuspend_delay(&dev->dev,
+ usb_autosuspend_delay * 1000);
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
#endif
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index cd882203ad34..b975450f403e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -75,14 +75,12 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
#ifdef CONFIG_USB_SUSPEND
extern void usb_autosuspend_device(struct usb_device *udev);
-extern void usb_try_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
extern int usb_remote_wakeup(struct usb_device *dev);
#else
#define usb_autosuspend_device(udev) do {} while (0)
-#define usb_try_autosuspend_device(udev) do {} while (0)
static inline int usb_autoresume_device(struct usb_device *udev)
{
return 0;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b739ca814651..1dc9739277b4 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -158,7 +158,7 @@ config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC
select USB_GADGET_DUALSPEED
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
help
Some of Freescale PowerPC processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
@@ -338,6 +338,19 @@ config USB_S3C2410_DEBUG
boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410
+config USB_GADGET_PXA_U2O
+ boolean "PXA9xx Processor USB2.0 controller"
+ select USB_GADGET_DUALSPEED
+ help
+ PXA9xx Processor series include a high speed USB2.0 device
+ controller, which support high speed and full speed USB peripheral.
+
+config USB_PXA_U2O
+ tristate
+ depends on USB_GADGET_PXA_U2O
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
#
# Controllers available in both integrated and discrete versions
#
@@ -414,8 +427,8 @@ config USB_FSL_QE
default USB_GADGET
select USB_GADGET_SELECTED
-config USB_GADGET_CI13XXX
- boolean "MIPS USB CI13xxx"
+config USB_GADGET_CI13XXX_PCI
+ boolean "MIPS USB CI13xxx PCI UDC"
depends on PCI
select USB_GADGET_DUALSPEED
help
@@ -426,9 +439,9 @@ config USB_GADGET_CI13XXX
dynamically linked module called "ci13xxx_udc" and force all
gadget drivers to also be dynamically linked.
-config USB_CI13XXX
+config USB_CI13XXX_PCI
tristate
- depends on USB_GADGET_CI13XXX
+ depends on USB_GADGET_CI13XXX_PCI
default USB_GADGET
select USB_GADGET_SELECTED
@@ -495,6 +508,49 @@ config USB_LANGWELL
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_EG20T
+ boolean "Intel EG20T(Topcliff) USB Device controller"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ This is a USB device driver for EG20T PCH.
+ EG20T PCH is the platform controller hub that is used in Intel's
+ general embedded platform. EG20T PCH has USB device interface.
+ Using this interface, it is able to access system devices connected
+ to USB device.
+ This driver enables USB device function.
+ USB device is a USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+ This driver supports both control transfer and bulk transfer modes.
+ This driver dose not support interrupt transfer or isochronous
+ transfer modes.
+
+config USB_EG20T
+ tristate
+ depends on USB_GADGET_EG20T
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_CI13XXX_MSM
+ boolean "MIPS USB CI13xxx for MSM"
+ depends on ARCH_MSM
+ select USB_GADGET_DUALSPEED
+ select USB_MSM_OTG_72K
+ help
+ MSM SoC has chipidea USB controller. This driver uses
+ ci13xxx_udc core.
+ This driver depends on OTG driver for PHY initialization,
+ clock management, powering up VBUS, and power management.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "ci13xxx_msm" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_CI13XXX_MSM
+ tristate
+ depends on USB_GADGET_CI13XXX_MSM
+ default USB_GADGET
+ select USB_GADGET_SELECTED
#
# LAST -- dummy/emulated controller
@@ -685,6 +741,19 @@ config USB_ETH_EEM
If you say "y" here, the Ethernet gadget driver will use the EEM
protocol rather than ECM. If unsure, say "n".
+config USB_G_NCM
+ tristate "Network Control Model (NCM) support"
+ depends on NET
+ select CRC32
+ help
+ This driver implements USB CDC NCM subclass standard. NCM is
+ an advanced protocol for Ethernet encapsulation, allows grouping
+ of several ethernet frames into one USB transfer and diffferent
+ alignment possibilities.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_ncm".
+
config USB_GADGETFS
tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5780db42417b..55f5e8ae5924 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -21,9 +21,13 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
-obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
+obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
+obj-$(CONFIG_USB_EG20T) += pch_udc.o
+obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
+mv_udc-y := mv_udc_core.o mv_udc_phy.o
+obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
#
# USB gadget drivers
@@ -43,6 +47,7 @@ g_hid-y := hid.o
g_dbgp-y := dbgp.o
g_nokia-y := nokia.o
g_webcam-y := webcam.o
+g_ncm-y := ncm.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -60,3 +65,4 @@ obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
+obj-$(CONFIG_USB_G_NCM) += g_ncm.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 9034e0344723..f8dd7269d79c 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -3359,7 +3359,6 @@ static int udc_probe(struct udc *dev)
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
- dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
/* init registers, interrupts, ... */
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index b5e20e873cba..e7c65a4408fb 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -2017,7 +2017,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
- ubc->vbus_pin = -EINVAL;
+ udc->vbus_pin = -EINVAL;
}
}
@@ -2057,8 +2057,10 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
usba_ep_cleanup_debugfs(&usba_ep[i]);
usba_cleanup_debugfs(udc);
- if (gpio_is_valid(udc->vbus_pin))
+ if (gpio_is_valid(udc->vbus_pin)) {
+ free_irq(gpio_to_irq(udc->vbus_pin), udc);
gpio_free(udc->vbus_pin);
+ }
free_irq(udc->irq, udc);
kfree(usba_ep);
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
new file mode 100644
index 000000000000..139ac9419597
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/ulpi.h>
+
+#include "ci13xxx_udc.c"
+
+#define MSM_USB_BASE (udc->regs)
+
+static irqreturn_t msm_udc_irq(int irq, void *data)
+{
+ return udc_irq();
+}
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
+{
+ struct device *dev = udc->gadget.dev.parent;
+ int val;
+
+ switch (event) {
+ case CI13XXX_CONTROLLER_RESET_EVENT:
+ dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+ writel(0, USB_AHBBURST);
+ writel(0, USB_AHBMODE);
+ break;
+ case CI13XXX_CONTROLLER_STOPPED_EVENT:
+ dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
+ /*
+ * Put the transceiver in non-driving mode. Otherwise host
+ * may not detect soft-disconnection.
+ */
+ val = otg_io_read(udc->transceiver, ULPI_FUNC_CTRL);
+ val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+ val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+ otg_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
+ break;
+ default:
+ dev_dbg(dev, "unknown ci13xxx_udc event\n");
+ break;
+ }
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
+ .name = "ci13xxx_msm",
+ .flags = CI13XXX_REGS_SHARED |
+ CI13XXX_REQUIRE_TRANSCEIVER |
+ CI13XXX_PULLUP_ON_VBUS |
+ CI13XXX_DISABLE_STREAMING,
+
+ .notify_event = ci13xxx_msm_notify_event,
+};
+
+static int ci13xxx_msm_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *regs;
+ int irq;
+ int ret;
+
+ dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get platform resource mem\n");
+ return -ENXIO;
+ }
+
+ regs = ioremap(res->start, resource_size(res));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+
+ ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "udc_probe failed\n");
+ goto iounmap;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "IRQ not found\n");
+ ret = -ENXIO;
+ goto udc_remove;
+ }
+
+ ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto udc_remove;
+ }
+
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+udc_remove:
+ udc_remove();
+iounmap:
+ iounmap(regs);
+
+ return ret;
+}
+
+static struct platform_driver ci13xxx_msm_driver = {
+ .probe = ci13xxx_msm_probe,
+ .driver = { .name = "msm_hsusb", },
+};
+
+static int __init ci13xxx_msm_init(void)
+{
+ return platform_driver_register(&ci13xxx_msm_driver);
+}
+module_init(ci13xxx_msm_init);
diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/gadget/ci13xxx_pci.c
new file mode 100644
index 000000000000..883ab5e832d1
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_pci.c
@@ -0,0 +1,176 @@
+/*
+ * ci13xxx_pci.c - MIPS USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "ci13xxx_udc.c"
+
+/* driver name */
+#define UDC_DRIVER_NAME "ci13xxx_pci"
+
+/******************************************************************************
+ * PCI block
+ *****************************************************************************/
+/**
+ * ci13xxx_pci_irq: interrut handler
+ * @irq: irq number
+ * @pdev: USB Device Controller interrupt source
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * This is an ISR don't trace, use attribute interface instead
+ */
+static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
+{
+ if (irq == 0) {
+ dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
+ return IRQ_HANDLED;
+ }
+ return udc_irq();
+}
+
+static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
+ .name = UDC_DRIVER_NAME,
+};
+
+/**
+ * ci13xxx_pci_probe: PCI probe
+ * @pdev: USB device controller being probed
+ * @id: PCI hotplug ID connecting controller to UDC framework
+ *
+ * This function returns an error code
+ * Allocates basic PCI resources for this USB device controller, and then
+ * invokes the udc_probe() method to start the UDC associated with it
+ */
+static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *regs = NULL;
+ int retval = 0;
+
+ if (id == NULL)
+ return -EINVAL;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto done;
+
+ if (!pdev->irq) {
+ dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
+ retval = -ENODEV;
+ goto disable_device;
+ }
+
+ retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
+ if (retval)
+ goto disable_device;
+
+ /* BAR 0 holds all the registers */
+ regs = pci_iomap(pdev, 0, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "Error mapping memory!");
+ retval = -EFAULT;
+ goto release_regions;
+ }
+ pci_set_drvdata(pdev, (__force void *)regs);
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
+ if (retval)
+ goto iounmap;
+
+ /* our device does not have MSI capability */
+
+ retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
+ UDC_DRIVER_NAME, pdev);
+ if (retval)
+ goto gadget_remove;
+
+ return 0;
+
+ gadget_remove:
+ udc_remove();
+ iounmap:
+ pci_iounmap(pdev, regs);
+ release_regions:
+ pci_release_regions(pdev);
+ disable_device:
+ pci_disable_device(pdev);
+ done:
+ return retval;
+}
+
+/**
+ * ci13xxx_pci_remove: PCI remove
+ * @pdev: USB Device Controller being removed
+ *
+ * Reverses the effect of ci13xxx_pci_probe(),
+ * first invoking the udc_remove() and then releases
+ * all PCI resources allocated for this USB device controller
+ */
+static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
+{
+ free_irq(pdev->irq, pdev);
+ udc_remove();
+ pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+/**
+ * PCI device table
+ * PCI device structure
+ *
+ * Check "pci.h" for details
+ */
+static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
+ { PCI_DEVICE(0x153F, 0x1004) },
+ { PCI_DEVICE(0x153F, 0x1006) },
+ { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
+
+static struct pci_driver ci13xxx_pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .id_table = ci13xxx_pci_id_table,
+ .probe = ci13xxx_pci_probe,
+ .remove = __devexit_p(ci13xxx_pci_remove),
+};
+
+/**
+ * ci13xxx_pci_init: module init
+ *
+ * Driver load
+ */
+static int __init ci13xxx_pci_init(void)
+{
+ return pci_register_driver(&ci13xxx_pci_driver);
+}
+module_init(ci13xxx_pci_init);
+
+/**
+ * ci13xxx_pci_exit: module exit
+ *
+ * Driver unload
+ */
+static void __exit ci13xxx_pci_exit(void)
+{
+ pci_unregister_driver(&ci13xxx_pci_driver);
+}
+module_exit(ci13xxx_pci_exit);
+
+MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("June 2008");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 98b36fc88c77..31656a2b4ab4 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -22,7 +22,6 @@
* - ENDPT: endpoint operations (Gadget API)
* - GADGET: gadget operations (Gadget API)
* - BUS: bus glue code, bus abstraction layer
- * - PCI: PCI core interface and PCI resources (interrupts, memory...)
*
* Compile Options
* - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
@@ -60,11 +59,11 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
#include "ci13xxx_udc.h"
@@ -75,9 +74,6 @@
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
-/* driver name */
-#define UDC_DRIVER_NAME "ci13xxx_udc"
-
/* control endpoint description */
static const struct usb_endpoint_descriptor
ctrl_endpt_desc = {
@@ -132,6 +128,9 @@ static struct {
size_t size; /* bank size */
} hw_bank;
+/* MSM specific */
+#define ABS_AHBBURST (0x0090UL)
+#define ABS_AHBMODE (0x0098UL)
/* UDC register map */
#define ABS_CAPLENGTH (0x100UL)
#define ABS_HCCPARAMS (0x108UL)
@@ -248,13 +247,7 @@ static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
return (reg & mask) >> ffs_nr(mask);
}
-/**
- * hw_device_reset: resets chip (execute without interruption)
- * @base: register base address
- *
- * This function returns an error code
- */
-static int hw_device_reset(void __iomem *base)
+static int hw_device_init(void __iomem *base)
{
u32 reg;
@@ -271,6 +264,28 @@ static int hw_device_reset(void __iomem *base)
hw_bank.size += CAP_LAST;
hw_bank.size /= sizeof(u32);
+ reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
+ if (reg == 0 || reg > ENDPT_MAX)
+ return -ENODEV;
+
+ hw_ep_max = reg; /* cache hw ENDPT_MAX */
+
+ /* setup lock mode ? */
+
+ /* ENDPTSETUPSTAT is '0' by default */
+
+ /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+ return 0;
+}
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @base: register base address
+ *
+ * This function returns an error code
+ */
+static int hw_device_reset(struct ci13xxx *udc)
+{
/* should flush & stop before reset */
hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
@@ -279,6 +294,14 @@ static int hw_device_reset(void __iomem *base)
while (hw_cread(CAP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
+
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_RESET_EVENT);
+
+ if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING)
+ hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+
/* USBMODE should be configured step by step */
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
@@ -290,18 +313,6 @@ static int hw_device_reset(void __iomem *base)
return -ENODEV;
}
- reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
- if (reg == 0 || reg > ENDPT_MAX)
- return -ENODEV;
-
- hw_ep_max = reg; /* cache hw ENDPT_MAX */
-
- /* setup lock mode ? */
-
- /* ENDPTSETUPSTAT is '0' by default */
-
- /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
-
return 0;
}
@@ -1449,7 +1460,7 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
mReq->ptr->page[0] = mReq->req.dma;
for (i = 1; i < 5; i++)
mReq->ptr->page[i] =
- (mReq->req.dma + i * PAGE_SIZE) & ~TD_RESERVED_MASK;
+ (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
/*
* QH configuration
@@ -1540,7 +1551,7 @@ __acquires(mEp->lock)
list_del_init(&mReq->queue);
mReq->req.status = -ESHUTDOWN;
- if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
@@ -1557,8 +1568,6 @@ __acquires(mEp->lock)
* Caller must hold lock
*/
static int _gadget_stop_activity(struct usb_gadget *gadget)
-__releases(udc->lock)
-__acquires(udc->lock)
{
struct usb_ep *ep;
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
@@ -1570,8 +1579,6 @@ __acquires(udc->lock)
if (gadget == NULL)
return -EINVAL;
- spin_unlock(udc->lock);
-
/* flush all endpoints */
gadget_for_each_ep(ep, gadget) {
usb_ep_fifo_flush(ep);
@@ -1591,8 +1598,6 @@ __acquires(udc->lock)
mEp->status = NULL;
}
- spin_lock(udc->lock);
-
return 0;
}
@@ -1621,6 +1626,7 @@ __acquires(udc->lock)
dbg_event(0xFF, "BUS RST", 0);
+ spin_unlock(udc->lock);
retval = _gadget_stop_activity(&udc->gadget);
if (retval)
goto done;
@@ -1629,10 +1635,9 @@ __acquires(udc->lock)
if (retval)
goto done;
- spin_unlock(udc->lock);
retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc);
if (!retval) {
- mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_KERNEL);
+ mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_ATOMIC);
if (mEp->status == NULL) {
usb_ep_disable(&mEp->ep);
retval = -ENOMEM;
@@ -1789,18 +1794,20 @@ __acquires(mEp->lock)
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
- if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ if (!list_empty(&mEp->qh[mEp->dir].queue)) {
+ struct ci13xxx_req* mReqEnq;
+
+ mReqEnq = list_entry(mEp->qh[mEp->dir].queue.next,
+ struct ci13xxx_req, queue);
+ _hardware_enqueue(mEp, mReqEnq);
+ }
+
+ if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
}
- if (!list_empty(&mEp->qh[mEp->dir].queue)) {
- mReq = list_entry(mEp->qh[mEp->dir].queue.next,
- struct ci13xxx_req, queue);
- _hardware_enqueue(mEp, mReq);
- }
-
done:
return retval;
}
@@ -2061,7 +2068,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_req *mReq = NULL;
- unsigned long flags;
trace("%p, %i", ep, gfp_flags);
@@ -2070,8 +2076,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
return NULL;
}
- spin_lock_irqsave(mEp->lock, flags);
-
mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
if (mReq != NULL) {
INIT_LIST_HEAD(&mReq->queue);
@@ -2086,8 +2090,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
- spin_unlock_irqrestore(mEp->lock, flags);
-
return (mReq == NULL) ? NULL : &mReq->req;
}
@@ -2157,8 +2159,8 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
goto done;
}
- if (req->length > (4 * PAGE_SIZE)) {
- req->length = (4 * PAGE_SIZE);
+ if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
+ req->length = (4 * CI13XXX_PAGE_SIZE);
retval = -EMSGSIZE;
warn("request length truncated");
}
@@ -2170,8 +2172,10 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
mReq->req.actual = 0;
list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
- retval = _hardware_enqueue(mEp, mReq);
- if (retval == -EALREADY || retval == -EBUSY) {
+ if (list_is_singular(&mEp->qh[mEp->dir].queue))
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY) {
dbg_event(_usb_addr(mEp), "QUEUE", retval);
retval = 0;
}
@@ -2209,7 +2213,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
list_del_init(&mReq->queue);
req->status = -ECONNRESET;
- if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
mReq->req.complete(&mEp->ep, &mReq->req);
spin_lock(mEp->lock);
@@ -2332,12 +2336,47 @@ static const struct usb_ep_ops usb_ep_ops = {
/******************************************************************************
* GADGET block
*****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int gadget_ready = 0;
+
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(udc->lock, flags);
+ udc->vbus_active = is_active;
+ if (udc->driver)
+ gadget_ready = 1;
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ if (gadget_ready) {
+ if (is_active) {
+ pm_runtime_get_sync(&_gadget->dev);
+ hw_device_reset(udc);
+ hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+ } else {
+ hw_device_state(0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
+ _gadget_stop_activity(&udc->gadget);
+ pm_runtime_put_sync(&_gadget->dev);
+ }
+ }
+
+ return 0;
+}
+
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
* Check "usb_gadget.h" for details
*/
-static const struct usb_gadget_ops usb_gadget_ops;
+static const struct usb_gadget_ops usb_gadget_ops = {
+ .vbus_session = ci13xxx_vbus_session,
+};
/**
* usb_gadget_probe_driver: register a gadget driver
@@ -2358,7 +2397,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
if (driver == NULL ||
bind == NULL ||
- driver->unbind == NULL ||
driver->setup == NULL ||
driver->disconnect == NULL ||
driver->suspend == NULL ||
@@ -2372,13 +2410,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* alloc resources */
udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
sizeof(struct ci13xxx_qh),
- 64, PAGE_SIZE);
+ 64, CI13XXX_PAGE_SIZE);
if (udc->qh_pool == NULL)
return -ENOMEM;
udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
sizeof(struct ci13xxx_td),
- 64, PAGE_SIZE);
+ 64, CI13XXX_PAGE_SIZE);
if (udc->td_pool == NULL) {
dma_pool_destroy(udc->qh_pool);
udc->qh_pool = NULL;
@@ -2390,7 +2428,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
info("hw_ep_max = %d", hw_ep_max);
udc->driver = driver;
- udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
retval = 0;
@@ -2410,9 +2447,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* this allocation cannot be random */
for (k = RX; k <= TX; k++) {
INIT_LIST_HEAD(&mEp->qh[k].queue);
+ spin_unlock_irqrestore(udc->lock, flags);
mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool,
GFP_KERNEL,
&mEp->qh[k].dma);
+ spin_lock_irqsave(udc->lock, flags);
if (mEp->qh[k].ptr == NULL)
retval = -ENOMEM;
else
@@ -2429,7 +2468,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
/* bind gadget */
driver->driver.bus = NULL;
- udc->gadget.ops = &usb_gadget_ops;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(udc->lock, flags);
@@ -2437,12 +2475,24 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
spin_lock_irqsave(udc->lock, flags);
if (retval) {
- udc->gadget.ops = NULL;
udc->gadget.dev.driver = NULL;
goto done;
}
+ pm_runtime_get_sync(&udc->gadget.dev);
+ if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+ if (udc->vbus_active) {
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+ hw_device_reset(udc);
+ } else {
+ pm_runtime_put_sync(&udc->gadget.dev);
+ goto done;
+ }
+ }
+
retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+ if (retval)
+ pm_runtime_put_sync(&udc->gadget.dev);
done:
spin_unlock_irqrestore(udc->lock, flags);
@@ -2475,19 +2525,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(udc->lock, flags);
- hw_device_state(0);
-
- /* unbind gadget */
- if (udc->gadget.ops != NULL) {
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+ udc->vbus_active) {
+ hw_device_state(0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&udc->gadget);
+ pm_runtime_put(&udc->gadget.dev);
+ }
- spin_unlock_irqrestore(udc->lock, flags);
- driver->unbind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
+ /* unbind gadget */
+ spin_unlock_irqrestore(udc->lock, flags);
+ driver->unbind(&udc->gadget); /* MAY SLEEP */
+ spin_lock_irqsave(udc->lock, flags);
- udc->gadget.ops = NULL;
- udc->gadget.dev.driver = NULL;
- }
+ udc->gadget.dev.driver = NULL;
/* free resources */
for (i = 0; i < hw_ep_max; i++) {
@@ -2544,6 +2597,14 @@ static irqreturn_t udc_irq(void)
}
spin_lock(udc->lock);
+
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+ if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
+ USBMODE_CM_DEVICE) {
+ spin_unlock(udc->lock);
+ return IRQ_NONE;
+ }
+ }
intr = hw_test_and_clear_intr_active();
if (intr) {
isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
@@ -2602,14 +2663,16 @@ static void udc_release(struct device *dev)
* No interrupts active, the IRQ has not been requested yet
* Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
*/
-static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
+static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
+ void __iomem *regs)
{
struct ci13xxx *udc;
int retval = 0;
trace("%p, %p, %p", dev, regs, name);
- if (dev == NULL || regs == NULL || name == NULL)
+ if (dev == NULL || regs == NULL || driver == NULL ||
+ driver->name == NULL)
return -EINVAL;
udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
@@ -2617,42 +2680,77 @@ static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
return -ENOMEM;
udc->lock = &udc_lock;
+ udc->regs = regs;
+ udc->udc_driver = driver;
- retval = hw_device_reset(regs);
- if (retval)
- goto done;
-
- udc->gadget.ops = NULL;
+ udc->gadget.ops = &usb_gadget_ops;
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.is_dualspeed = 1;
udc->gadget.is_otg = 0;
- udc->gadget.name = name;
+ udc->gadget.name = driver->name;
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.ep0 = NULL;
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.dev.dma_mask = dev->dma_mask;
+ udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
udc->gadget.dev.parent = dev;
udc->gadget.dev.release = udc_release;
+ retval = hw_device_init(regs);
+ if (retval < 0)
+ goto free_udc;
+
+ udc->transceiver = otg_get_transceiver();
+
+ if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+ if (udc->transceiver == NULL) {
+ retval = -ENODEV;
+ goto free_udc;
+ }
+ }
+
+ if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+ retval = hw_device_reset(udc);
+ if (retval)
+ goto put_transceiver;
+ }
+
retval = device_register(&udc->gadget.dev);
- if (retval)
- goto done;
+ if (retval) {
+ put_device(&udc->gadget.dev);
+ goto put_transceiver;
+ }
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
retval = dbg_create_files(&udc->gadget.dev);
#endif
- if (retval) {
- device_unregister(&udc->gadget.dev);
- goto done;
+ if (retval)
+ goto unreg_device;
+
+ if (udc->transceiver) {
+ retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+ if (retval)
+ goto remove_dbg;
}
+ pm_runtime_no_callbacks(&udc->gadget.dev);
+ pm_runtime_enable(&udc->gadget.dev);
_udc = udc;
return retval;
- done:
err("error = %i", retval);
+remove_dbg:
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ dbg_remove_files(&udc->gadget.dev);
+#endif
+unreg_device:
+ device_unregister(&udc->gadget.dev);
+put_transceiver:
+ if (udc->transceiver)
+ otg_put_transceiver(udc->transceiver);
+free_udc:
kfree(udc);
_udc = NULL;
return retval;
@@ -2672,6 +2770,10 @@ static void udc_remove(void)
return;
}
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver, &udc->gadget);
+ otg_put_transceiver(udc->transceiver);
+ }
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);
#endif
@@ -2680,156 +2782,3 @@ static void udc_remove(void)
kfree(udc);
_udc = NULL;
}
-
-/******************************************************************************
- * PCI block
- *****************************************************************************/
-/**
- * ci13xxx_pci_irq: interrut handler
- * @irq: irq number
- * @pdev: USB Device Controller interrupt source
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * This is an ISR don't trace, use attribute interface instead
- */
-static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
-{
- if (irq == 0) {
- dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
- return IRQ_HANDLED;
- }
- return udc_irq();
-}
-
-/**
- * ci13xxx_pci_probe: PCI probe
- * @pdev: USB device controller being probed
- * @id: PCI hotplug ID connecting controller to UDC framework
- *
- * This function returns an error code
- * Allocates basic PCI resources for this USB device controller, and then
- * invokes the udc_probe() method to start the UDC associated with it
- */
-static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- void __iomem *regs = NULL;
- int retval = 0;
-
- if (id == NULL)
- return -EINVAL;
-
- retval = pci_enable_device(pdev);
- if (retval)
- goto done;
-
- if (!pdev->irq) {
- dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
- retval = -ENODEV;
- goto disable_device;
- }
-
- retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
- if (retval)
- goto disable_device;
-
- /* BAR 0 holds all the registers */
- regs = pci_iomap(pdev, 0, 0);
- if (!regs) {
- dev_err(&pdev->dev, "Error mapping memory!");
- retval = -EFAULT;
- goto release_regions;
- }
- pci_set_drvdata(pdev, (__force void *)regs);
-
- pci_set_master(pdev);
- pci_try_set_mwi(pdev);
-
- retval = udc_probe(&pdev->dev, regs, UDC_DRIVER_NAME);
- if (retval)
- goto iounmap;
-
- /* our device does not have MSI capability */
-
- retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
- UDC_DRIVER_NAME, pdev);
- if (retval)
- goto gadget_remove;
-
- return 0;
-
- gadget_remove:
- udc_remove();
- iounmap:
- pci_iounmap(pdev, regs);
- release_regions:
- pci_release_regions(pdev);
- disable_device:
- pci_disable_device(pdev);
- done:
- return retval;
-}
-
-/**
- * ci13xxx_pci_remove: PCI remove
- * @pdev: USB Device Controller being removed
- *
- * Reverses the effect of ci13xxx_pci_probe(),
- * first invoking the udc_remove() and then releases
- * all PCI resources allocated for this USB device controller
- */
-static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
-{
- free_irq(pdev->irq, pdev);
- udc_remove();
- pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-/**
- * PCI device table
- * PCI device structure
- *
- * Check "pci.h" for details
- */
-static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
- { PCI_DEVICE(0x153F, 0x1004) },
- { PCI_DEVICE(0x153F, 0x1006) },
- { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
-
-static struct pci_driver ci13xxx_pci_driver = {
- .name = UDC_DRIVER_NAME,
- .id_table = ci13xxx_pci_id_table,
- .probe = ci13xxx_pci_probe,
- .remove = __devexit_p(ci13xxx_pci_remove),
-};
-
-/**
- * ci13xxx_pci_init: module init
- *
- * Driver load
- */
-static int __init ci13xxx_pci_init(void)
-{
- return pci_register_driver(&ci13xxx_pci_driver);
-}
-module_init(ci13xxx_pci_init);
-
-/**
- * ci13xxx_pci_exit: module exit
- *
- * Driver unload
- */
-static void __exit ci13xxx_pci_exit(void)
-{
- pci_unregister_driver(&ci13xxx_pci_driver);
-}
-module_exit(ci13xxx_pci_exit);
-
-MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
-MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("June 2008");
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 4026e9cede34..f61fed07f76b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -19,6 +19,7 @@
/******************************************************************************
* DEFINE
*****************************************************************************/
+#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX (16)
#define CTRL_PAYLOAD_MAX (64)
#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
@@ -97,9 +98,24 @@ struct ci13xxx_ep {
struct dma_pool *td_pool;
};
+struct ci13xxx;
+struct ci13xxx_udc_driver {
+ const char *name;
+ unsigned long flags;
+#define CI13XXX_REGS_SHARED BIT(0)
+#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
+#define CI13XXX_PULLUP_ON_VBUS BIT(2)
+#define CI13XXX_DISABLE_STREAMING BIT(3)
+
+#define CI13XXX_CONTROLLER_RESET_EVENT 0
+#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
+ void (*notify_event) (struct ci13xxx *udc, unsigned event);
+};
+
/* CI13XXX UDC descriptor & global resources */
struct ci13xxx {
spinlock_t *lock; /* ctrl register bank access */
+ void __iomem *regs; /* registers address space */
struct dma_pool *qh_pool; /* DMA pool for queue heads */
struct dma_pool *td_pool; /* DMA pool for transfer descs */
@@ -108,6 +124,9 @@ struct ci13xxx {
struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
+ struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
+ int vbus_active; /* is VBUS active */
+ struct otg_transceiver *transceiver; /* Transceiver struct */
};
/******************************************************************************
@@ -157,6 +176,7 @@ struct ci13xxx {
#define USBMODE_CM_DEVICE (0x02UL << 0)
#define USBMODE_CM_HOST (0x03UL << 0)
#define USBMODE_SLOM BIT(3)
+#define USBMODE_SDIS BIT(4)
/* ENDPTCTRL */
#define ENDPTCTRL_RXS BIT(0)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7b5cc16e4a0b..f6ff8456d52d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1047,9 +1047,9 @@ composite_unbind(struct usb_gadget *gadget)
kfree(cdev->req->buf);
usb_ep_free_request(gadget->ep0, cdev->req);
}
+ device_remove_file(&gadget->dev, &dev_attr_suspended);
kfree(cdev);
set_gadget_data(gadget, NULL);
- device_remove_file(&gadget->dev, &dev_attr_suspended);
composite = NULL;
}
@@ -1107,14 +1107,6 @@ static int composite_bind(struct usb_gadget *gadget)
*/
usb_ep_autoconfig_reset(cdev->gadget);
- /* standardized runtime overrides for device ID data */
- if (idVendor)
- cdev->desc.idVendor = cpu_to_le16(idVendor);
- if (idProduct)
- cdev->desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-
/* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
* power state and consumption, etc
@@ -1126,7 +1118,15 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
- /* stirng overrides */
+ /* standardized runtime overrides for device ID data */
+ if (idVendor)
+ cdev->desc.idVendor = cpu_to_le16(idVendor);
+ if (idProduct)
+ cdev->desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice)
+ cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+
+ /* string overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
if (!iManufacturer && !composite->iManufacturer &&
!*composite_manufacturer)
@@ -1188,6 +1188,8 @@ composite_suspend(struct usb_gadget *gadget)
composite->suspend(cdev);
cdev->suspended = 1;
+
+ usb_gadget_vbus_draw(gadget, 2);
}
static void
@@ -1195,6 +1197,7 @@ composite_resume(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f;
+ u8 maxpower;
/* REVISIT: should we have config level
* suspend/resume callbacks?
@@ -1207,6 +1210,11 @@ composite_resume(struct usb_gadget *gadget)
if (f->resume)
f->resume(f);
}
+
+ maxpower = cdev->config->bMaxPower;
+
+ usb_gadget_vbus_draw(gadget, maxpower ?
+ (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
}
cdev->suspended = 0;
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 1d2a2abbfa80..13b9f47feecd 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1197,6 +1197,139 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
#define Ep_InRequest (Ep_Request | USB_DIR_IN)
+
+/**
+ * handle_control_request() - handles all control transfers
+ * @dum: pointer to dummy (the_controller)
+ * @urb: the urb request to handle
+ * @setup: pointer to the setup data for a USB device control
+ * request
+ * @status: pointer to request handling status
+ *
+ * Return 0 - if the request was handled
+ * 1 - if the request wasn't handles
+ * error code on error
+ */
+static int handle_control_request(struct dummy *dum, struct urb *urb,
+ struct usb_ctrlrequest *setup,
+ int *status)
+{
+ struct dummy_ep *ep2;
+ int ret_val = 1;
+ unsigned w_index;
+ unsigned w_value;
+
+ w_index = le16_to_cpu(setup->wIndex);
+ w_value = le16_to_cpu(setup->wValue);
+ switch (setup->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if (setup->bRequestType != Dev_Request)
+ break;
+ dum->address = w_value;
+ *status = 0;
+ dev_dbg(udc_dev(dum), "set_address = %d\n",
+ w_value);
+ ret_val = 0;
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (setup->bRequestType == Dev_Request) {
+ ret_val = 0;
+ switch (w_value) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
+ case USB_DEVICE_B_HNP_ENABLE:
+ dum->gadget.b_hnp_enable = 1;
+ break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ dum->gadget.a_hnp_support = 1;
+ break;
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ dum->gadget.a_alt_hnp_support = 1;
+ break;
+ default:
+ ret_val = -EOPNOTSUPP;
+ }
+ if (ret_val == 0) {
+ dum->devstatus |= (1 << w_value);
+ *status = 0;
+ }
+ } else if (setup->bRequestType == Ep_Request) {
+ /* endpoint halt */
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2 || ep2->ep.name == ep0name) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ ep2->halted = 1;
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ if (setup->bRequestType == Dev_Request) {
+ ret_val = 0;
+ switch (w_value) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ w_value = USB_DEVICE_REMOTE_WAKEUP;
+ break;
+ default:
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ if (ret_val == 0) {
+ dum->devstatus &= ~(1 << w_value);
+ *status = 0;
+ }
+ } else if (setup->bRequestType == Ep_Request) {
+ /* endpoint halt */
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ if (!ep2->wedged)
+ ep2->halted = 0;
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (setup->bRequestType == Dev_InRequest
+ || setup->bRequestType == Intf_InRequest
+ || setup->bRequestType == Ep_InRequest) {
+ char *buf;
+ /*
+ * device: remote wakeup, selfpowered
+ * interface: nothing
+ * endpoint: halt
+ */
+ buf = (char *)urb->transfer_buffer;
+ if (urb->transfer_buffer_length > 0) {
+ if (setup->bRequestType == Ep_InRequest) {
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ buf[0] = ep2->halted;
+ } else if (setup->bRequestType ==
+ Dev_InRequest) {
+ buf[0] = (u8)dum->devstatus;
+ } else
+ buf[0] = 0;
+ }
+ if (urb->transfer_buffer_length > 1)
+ buf[1] = 0;
+ urb->actual_length = min_t(u32, 2,
+ urb->transfer_buffer_length);
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ }
+ return ret_val;
+}
+
/* drive both sides of the transfers; looks like irq handlers to
* both drivers except the callbacks aren't in_irq().
*/
@@ -1299,14 +1432,8 @@ restart:
if (ep == &dum->ep [0] && ep->setup_stage) {
struct usb_ctrlrequest setup;
int value = 1;
- struct dummy_ep *ep2;
- unsigned w_index;
- unsigned w_value;
setup = *(struct usb_ctrlrequest*) urb->setup_packet;
- w_index = le16_to_cpu(setup.wIndex);
- w_value = le16_to_cpu(setup.wValue);
-
/* paranoia, in case of stale queued data */
list_for_each_entry (req, &ep->queue, queue) {
list_del_init (&req->queue);
@@ -1328,117 +1455,9 @@ restart:
ep->last_io = jiffies;
ep->setup_stage = 0;
ep->halted = 0;
- switch (setup.bRequest) {
- case USB_REQ_SET_ADDRESS:
- if (setup.bRequestType != Dev_Request)
- break;
- dum->address = w_value;
- status = 0;
- dev_dbg (udc_dev(dum), "set_address = %d\n",
- w_value);
- value = 0;
- break;
- case USB_REQ_SET_FEATURE:
- if (setup.bRequestType == Dev_Request) {
- value = 0;
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- break;
- case USB_DEVICE_B_HNP_ENABLE:
- dum->gadget.b_hnp_enable = 1;
- break;
- case USB_DEVICE_A_HNP_SUPPORT:
- dum->gadget.a_hnp_support = 1;
- break;
- case USB_DEVICE_A_ALT_HNP_SUPPORT:
- dum->gadget.a_alt_hnp_support
- = 1;
- break;
- default:
- value = -EOPNOTSUPP;
- }
- if (value == 0) {
- dum->devstatus |=
- (1 << w_value);
- status = 0;
- }
- } else if (setup.bRequestType == Ep_Request) {
- // endpoint halt
- ep2 = find_endpoint (dum, w_index);
- if (!ep2 || ep2->ep.name == ep0name) {
- value = -EOPNOTSUPP;
- break;
- }
- ep2->halted = 1;
- value = 0;
- status = 0;
- }
- break;
- case USB_REQ_CLEAR_FEATURE:
- if (setup.bRequestType == Dev_Request) {
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- dum->devstatus &= ~(1 <<
- USB_DEVICE_REMOTE_WAKEUP);
- value = 0;
- status = 0;
- break;
- default:
- value = -EOPNOTSUPP;
- break;
- }
- } else if (setup.bRequestType == Ep_Request) {
- // endpoint halt
- ep2 = find_endpoint (dum, w_index);
- if (!ep2) {
- value = -EOPNOTSUPP;
- break;
- }
- if (!ep2->wedged)
- ep2->halted = 0;
- value = 0;
- status = 0;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (setup.bRequestType == Dev_InRequest
- || setup.bRequestType
- == Intf_InRequest
- || setup.bRequestType
- == Ep_InRequest
- ) {
- char *buf;
-
- // device: remote wakeup, selfpowered
- // interface: nothing
- // endpoint: halt
- buf = (char *)urb->transfer_buffer;
- if (urb->transfer_buffer_length > 0) {
- if (setup.bRequestType ==
- Ep_InRequest) {
- ep2 = find_endpoint (dum, w_index);
- if (!ep2) {
- value = -EOPNOTSUPP;
- break;
- }
- buf [0] = ep2->halted;
- } else if (setup.bRequestType ==
- Dev_InRequest) {
- buf [0] = (u8)
- dum->devstatus;
- } else
- buf [0] = 0;
- }
- if (urb->transfer_buffer_length > 1)
- buf [1] = 0;
- urb->actual_length = min_t(u32, 2,
- urb->transfer_buffer_length);
- value = 0;
- status = 0;
- }
- break;
- }
+ value = handle_control_request(dum, urb, &setup,
+ &status);
/* gadget driver handles all other requests. block
* until setup() returns; no reentrancy issues etc.
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 4a830df4fc31..1499f9e4afa8 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1,10 +1,10 @@
/*
- * f_fs.c -- user mode filesystem api for usb composite funtcion controllers
+ * f_fs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
*
- * Based on inode.c (GadgetFS):
+ * Based on inode.c (GadgetFS) which was:
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies
*
@@ -30,7 +30,6 @@
#include <linux/blkdev.h>
#include <linux/pagemap.h>
#include <asm/unaligned.h>
-#include <linux/smp_lock.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
@@ -39,62 +38,56 @@
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
-/* Debuging *****************************************************************/
-
-#define ffs_printk(level, fmt, args...) printk(level "f_fs: " fmt "\n", ## args)
-
-#define FERR(...) ffs_printk(KERN_ERR, __VA_ARGS__)
-#define FINFO(...) ffs_printk(KERN_INFO, __VA_ARGS__)
-
-#ifdef DEBUG
-# define FDBG(...) ffs_printk(KERN_DEBUG, __VA_ARGS__)
-#else
-# define FDBG(...) do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE_DEBUG
-# define FVDBG FDBG
-#else
-# define FVDBG(...) do { } while (0)
-#endif /* VERBOSE_DEBUG */
-
-#define ENTER() FVDBG("%s()", __func__)
+/* Debugging ****************************************************************/
#ifdef VERBOSE_DEBUG
+# define pr_vdebug pr_debug
# define ffs_dump_mem(prefix, ptr, len) \
- print_hex_dump_bytes("f_fs" prefix ": ", DUMP_PREFIX_NONE, ptr, len)
+ print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
#else
+# define pr_vdebug(...) do { } while (0)
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
-#endif
+#endif /* VERBOSE_DEBUG */
+
+#define ENTER() pr_vdebug("%s()\n", __func__)
/* The data structure and setup file ****************************************/
enum ffs_state {
- /* Waiting for descriptors and strings. */
- /* In this state no open(2), read(2) or write(2) on epfiles
+ /*
+ * Waiting for descriptors and strings.
+ *
+ * In this state no open(2), read(2) or write(2) on epfiles
* may succeed (which should not be the problem as there
- * should be no such files opened in the firts place). */
+ * should be no such files opened in the first place).
+ */
FFS_READ_DESCRIPTORS,
FFS_READ_STRINGS,
- /* We've got descriptors and strings. We are or have called
+ /*
+ * We've got descriptors and strings. We are or have called
* functionfs_ready_callback(). functionfs_bind() may have
- * been called but we don't know. */
- /* This is the only state in which operations on epfiles may
- * succeed. */
+ * been called but we don't know.
+ *
+ * This is the only state in which operations on epfiles may
+ * succeed.
+ */
FFS_ACTIVE,
- /* All endpoints have been closed. This state is also set if
+ /*
+ * All endpoints have been closed. This state is also set if
* we encounter an unrecoverable error. The only
* unrecoverable error is situation when after reading strings
- * from user space we fail to initialise EP files or
- * functionfs_ready_callback() returns with error (<0). */
- /* In this state no open(2), read(2) or write(2) (both on ep0
+ * from user space we fail to initialise epfiles or
+ * functionfs_ready_callback() returns with error (<0).
+ *
+ * In this state no open(2), read(2) or write(2) (both on ep0
* as well as epfile) may succeed (at this point epfiles are
* unlinked and all closed so this is not a problem; ep0 is
* also closed but ep0 file exists and so open(2) on ep0 must
- * fail). */
+ * fail).
+ */
FFS_CLOSING
};
@@ -102,14 +95,18 @@ enum ffs_state {
enum ffs_setup_state {
/* There is no setup request pending. */
FFS_NO_SETUP,
- /* User has read events and there was a setup request event
+ /*
+ * User has read events and there was a setup request event
* there. The next read/write on ep0 will handle the
- * request. */
+ * request.
+ */
FFS_SETUP_PENDING,
- /* There was event pending but before user space handled it
+ /*
+ * There was event pending but before user space handled it
* some other event was introduced which canceled existing
* setup. If this state is set read/write on ep0 return
- * -EIDRM. This state is only set when adding event. */
+ * -EIDRM. This state is only set when adding event.
+ */
FFS_SETUP_CANCELED
};
@@ -121,23 +118,29 @@ struct ffs_function;
struct ffs_data {
struct usb_gadget *gadget;
- /* Protect access read/write operations, only one read/write
+ /*
+ * Protect access read/write operations, only one read/write
* at a time. As a consequence protects ep0req and company.
* While setup request is being processed (queued) this is
- * held. */
+ * held.
+ */
struct mutex mutex;
- /* Protect access to enpoint related structures (basically
+ /*
+ * Protect access to endpoint related structures (basically
* usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
- * endpint zero. */
+ * endpoint zero.
+ */
spinlock_t eps_lock;
- /* XXX REVISIT do we need our own request? Since we are not
- * handling setup requests immidiatelly user space may be so
+ /*
+ * XXX REVISIT do we need our own request? Since we are not
+ * handling setup requests immediately user space may be so
* slow that another setup will be sent to the gadget but this
* time not to us but another function and then there could be
* a race. Is that the case? Or maybe we can use cdev->req
- * after all, maybe we just need some spinlock for that? */
+ * after all, maybe we just need some spinlock for that?
+ */
struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
int ep0req_status; /* P: mutex */
@@ -151,7 +154,7 @@ struct ffs_data {
enum ffs_state state;
/*
- * Possible transations:
+ * Possible transitions:
* + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
* happens only in ep0 read which is P: mutex
* + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
@@ -184,18 +187,21 @@ struct ffs_data {
/* Active function */
struct ffs_function *func;
- /* Device name, write once when file system is mounted.
- * Intendet for user to read if she wants. */
+ /*
+ * Device name, write once when file system is mounted.
+ * Intended for user to read if she wants.
+ */
const char *dev_name;
- /* Private data for our user (ie. gadget). Managed by
- * user. */
+ /* Private data for our user (ie. gadget). Managed by user. */
void *private_data;
/* filled by __ffs_data_got_descs() */
- /* real descriptors are 16 bytes after raw_descs (so you need
+ /*
+ * Real descriptors are 16 bytes after raw_descs (so you need
* to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
* first full speed descriptor). raw_descs_length and
- * raw_fs_descs_length do not have those 16 bytes added. */
+ * raw_fs_descs_length do not have those 16 bytes added.
+ */
const void *raw_descs;
unsigned raw_descs_length;
unsigned raw_fs_descs_length;
@@ -212,18 +218,23 @@ struct ffs_data {
const void *raw_strings;
struct usb_gadget_strings **stringtabs;
- /* File system's super block, write once when file system is mounted. */
+ /*
+ * File system's super block, write once when file system is
+ * mounted.
+ */
struct super_block *sb;
- /* File permissions, written once when fs is mounted*/
+ /* File permissions, written once when fs is mounted */
struct ffs_file_perms {
umode_t mode;
uid_t uid;
gid_t gid;
} file_perms;
- /* The endpoint files, filled by ffs_epfiles_create(),
- * destroyed by ffs_epfiles_destroy(). */
+ /*
+ * The endpoint files, filled by ffs_epfiles_create(),
+ * destroyed by ffs_epfiles_destroy().
+ */
struct ffs_epfile *epfiles;
};
@@ -237,7 +248,7 @@ static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);
-/* Called with ffs->mutex held; take over ownerrship of data. */
+/* Called with ffs->mutex held; take over ownership of data. */
static int __must_check
__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
static int __must_check
@@ -268,11 +279,9 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
static void ffs_func_free(struct ffs_function *func);
-
static void ffs_func_eps_disable(struct ffs_function *func);
static int __must_check ffs_func_eps_enable(struct ffs_function *func);
-
static int ffs_func_bind(struct usb_configuration *,
struct usb_function *);
static void ffs_func_unbind(struct usb_configuration *,
@@ -289,7 +298,6 @@ static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
-
/* The endpoints structures *************************************************/
struct ffs_ep {
@@ -322,7 +330,6 @@ struct ffs_epfile {
unsigned char _pad;
};
-
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
@@ -349,7 +356,6 @@ static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
complete_all(&ffs->ep0req_completion);
}
-
static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
{
struct usb_request *req = ffs->ep0req;
@@ -381,17 +387,16 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
static int __ffs_ep0_stall(struct ffs_data *ffs)
{
if (ffs->ev.can_stall) {
- FVDBG("ep0 stall\n");
+ pr_vdebug("ep0 stall\n");
usb_ep_set_halt(ffs->gadget->ep0);
ffs->setup_state = FFS_NO_SETUP;
return -EL2HLT;
} else {
- FDBG("bogus ep0 stall!\n");
+ pr_debug("bogus ep0 stall!\n");
return -ESRCH;
}
}
-
static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
size_t len, loff_t *ptr)
{
@@ -410,7 +415,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
if (unlikely(ret < 0))
return ret;
-
/* Check state */
switch (ffs->state) {
case FFS_READ_DESCRIPTORS:
@@ -422,14 +426,14 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
}
data = ffs_prepare_buffer(buf, len);
- if (unlikely(IS_ERR(data))) {
+ if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
/* Handle data */
if (ffs->state == FFS_READ_DESCRIPTORS) {
- FINFO("read descriptors");
+ pr_info("read descriptors\n");
ret = __ffs_data_got_descs(ffs, data, len);
if (unlikely(ret < 0))
break;
@@ -437,7 +441,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
ffs->state = FFS_READ_STRINGS;
ret = len;
} else {
- FINFO("read strings");
+ pr_info("read strings\n");
ret = __ffs_data_got_strings(ffs, data, len);
if (unlikely(ret < 0))
break;
@@ -462,11 +466,12 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
}
break;
-
case FFS_ACTIVE:
data = NULL;
- /* We're called from user space, we can use _irq
- * rather then _irqsave */
+ /*
+ * We're called from user space, we can use _irq
+ * rather then _irqsave
+ */
spin_lock_irq(&ffs->ev.waitq.lock);
switch (FFS_SETUP_STATE(ffs)) {
case FFS_SETUP_CANCELED:
@@ -494,23 +499,25 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
spin_unlock_irq(&ffs->ev.waitq.lock);
data = ffs_prepare_buffer(buf, len);
- if (unlikely(IS_ERR(data))) {
+ if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
spin_lock_irq(&ffs->ev.waitq.lock);
- /* We are guaranteed to be still in FFS_ACTIVE state
+ /*
+ * We are guaranteed to be still in FFS_ACTIVE state
* but the state of setup could have changed from
* FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
* to check for that. If that happened we copied data
- * from user space in vain but it's unlikely. */
- /* For sure we are not in FFS_NO_SETUP since this is
+ * from user space in vain but it's unlikely.
+ *
+ * For sure we are not in FFS_NO_SETUP since this is
* the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
* transition can be performed and it's protected by
- * mutex. */
-
+ * mutex.
+ */
if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
ret = -EIDRM;
done_spin:
@@ -522,25 +529,22 @@ done_spin:
kfree(data);
break;
-
default:
ret = -EBADFD;
break;
}
-
mutex_unlock(&ffs->mutex);
return ret;
}
-
-
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
{
- /* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
- * to release them. */
-
+ /*
+ * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
+ * to release them.
+ */
struct usb_functionfs_event events[n];
unsigned i = 0;
@@ -569,7 +573,6 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
? -EFAULT : sizeof events;
}
-
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t len, loff_t *ptr)
{
@@ -589,16 +592,16 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
if (unlikely(ret < 0))
return ret;
-
/* Check state */
if (ffs->state != FFS_ACTIVE) {
ret = -EBADFD;
goto done_mutex;
}
-
- /* We're called from user space, we can use _irq rather then
- * _irqsave */
+ /*
+ * We're called from user space, we can use _irq rather then
+ * _irqsave
+ */
spin_lock_irq(&ffs->ev.waitq.lock);
switch (FFS_SETUP_STATE(ffs)) {
@@ -618,7 +621,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
break;
}
- if (unlikely(wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, ffs->ev.count))) {
+ if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
+ ffs->ev.count)) {
ret = -EINTR;
break;
}
@@ -626,7 +630,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
return __ffs_ep0_read_events(ffs, buf,
min(n, (size_t)ffs->ev.count));
-
case FFS_SETUP_PENDING:
if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -672,8 +675,6 @@ done_mutex:
return ret;
}
-
-
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = inode->i_private;
@@ -689,7 +690,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
return 0;
}
-
static int ffs_ep0_release(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = file->private_data;
@@ -701,7 +701,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file)
return 0;
}
-
static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
{
struct ffs_data *ffs = file->private_data;
@@ -722,7 +721,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
return ret;
}
-
static const struct file_operations ffs_ep0_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -737,7 +735,6 @@ static const struct file_operations ffs_ep0_operations = {
/* "Normal" endpoints operations ********************************************/
-
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
ENTER();
@@ -748,7 +745,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
}
}
-
static ssize_t ffs_epfile_io(struct file *file,
char __user *buf, size_t len, int read)
{
@@ -778,8 +774,8 @@ first_try:
goto error;
}
- if (unlikely(wait_event_interruptible
- (epfile->wait, (ep = epfile->ep)))) {
+ if (wait_event_interruptible(epfile->wait,
+ (ep = epfile->ep))) {
ret = -EINTR;
goto error;
}
@@ -811,12 +807,16 @@ first_try:
if (unlikely(ret))
goto error;
- /* We're called from user space, we can use _irq rather then
- * _irqsave */
+ /*
+ * We're called from user space, we can use _irq rather then
+ * _irqsave
+ */
spin_lock_irq(&epfile->ffs->eps_lock);
- /* While we were acquiring mutex endpoint got disabled
- * or changed? */
+ /*
+ * While we were acquiring mutex endpoint got disabled
+ * or changed?
+ */
} while (unlikely(epfile->ep != ep));
/* Halt */
@@ -858,7 +858,6 @@ error:
return ret;
}
-
static ssize_t
ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
loff_t *ptr)
@@ -904,7 +903,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
return 0;
}
-
static long ffs_epfile_ioctl(struct file *file, unsigned code,
unsigned long value)
{
@@ -943,7 +941,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
return ret;
}
-
static const struct file_operations ffs_epfile_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -956,15 +953,13 @@ static const struct file_operations ffs_epfile_operations = {
};
-
/* File system and super block operations ***********************************/
/*
- * Mounting the filesystem creates a controller file, used first for
+ * Mounting the file system creates a controller file, used first for
* function configuration then later for event monitoring.
*/
-
static struct inode *__must_check
ffs_sb_make_inode(struct super_block *sb, void *data,
const struct file_operations *fops,
@@ -997,9 +992,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
return inode;
}
-
/* Create "regular" file */
-
static struct inode *ffs_sb_create_file(struct super_block *sb,
const char *name, void *data,
const struct file_operations *fops,
@@ -1028,9 +1021,7 @@ static struct inode *ffs_sb_create_file(struct super_block *sb,
return inode;
}
-
/* Super block */
-
static const struct super_operations ffs_sb_operations = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
@@ -1051,7 +1042,7 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
ENTER();
- /* Initialize data */
+ /* Initialise data */
ffs = ffs_data_new();
if (unlikely(!ffs))
goto enomem0;
@@ -1097,7 +1088,6 @@ enomem0:
return -ENOMEM;
}
-
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
{
ENTER();
@@ -1117,7 +1107,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
/* Value limit */
eq = strchr(opts, '=');
if (unlikely(!eq)) {
- FERR("'=' missing in %s", opts);
+ pr_err("'=' missing in %s\n", opts);
return -EINVAL;
}
*eq = 0;
@@ -1125,7 +1115,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
/* Parse value */
value = simple_strtoul(eq + 1, &end, 0);
if (unlikely(*end != ',' && *end != 0)) {
- FERR("%s: invalid value: %s", opts, eq + 1);
+ pr_err("%s: invalid value: %s\n", opts, eq + 1);
return -EINVAL;
}
@@ -1160,7 +1150,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
default:
invalid:
- FERR("%s: invalid option", opts);
+ pr_err("%s: invalid option\n", opts);
return -EINVAL;
}
@@ -1173,7 +1163,6 @@ invalid:
return 0;
}
-
/* "mount -t functionfs dev_name /dev/function" ends up here */
static struct dentry *
@@ -1225,10 +1214,8 @@ static struct file_system_type ffs_fs_type = {
};
-
/* Driver's main init/cleanup functions *************************************/
-
static int functionfs_init(void)
{
int ret;
@@ -1237,9 +1224,9 @@ static int functionfs_init(void)
ret = register_filesystem(&ffs_fs_type);
if (likely(!ret))
- FINFO("file system registered");
+ pr_info("file system registered\n");
else
- FERR("failed registering file system (%d)", ret);
+ pr_err("failed registering file system (%d)\n", ret);
return ret;
}
@@ -1248,18 +1235,16 @@ static void functionfs_cleanup(void)
{
ENTER();
- FINFO("unloading");
+ pr_info("unloading\n");
unregister_filesystem(&ffs_fs_type);
}
-
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
static void ffs_data_reset(struct ffs_data *ffs);
-
static void ffs_data_get(struct ffs_data *ffs)
{
ENTER();
@@ -1280,7 +1265,7 @@ static void ffs_data_put(struct ffs_data *ffs)
ENTER();
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
- FINFO("%s(): freeing", __func__);
+ pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
BUG_ON(mutex_is_locked(&ffs->mutex) ||
spin_is_locked(&ffs->ev.waitq.lock) ||
@@ -1290,8 +1275,6 @@ static void ffs_data_put(struct ffs_data *ffs)
}
}
-
-
static void ffs_data_closed(struct ffs_data *ffs)
{
ENTER();
@@ -1304,7 +1287,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
ffs_data_put(ffs);
}
-
static struct ffs_data *ffs_data_new(void)
{
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
@@ -1327,7 +1309,6 @@ static struct ffs_data *ffs_data_new(void)
return ffs;
}
-
static void ffs_data_clear(struct ffs_data *ffs)
{
ENTER();
@@ -1345,7 +1326,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
kfree(ffs->stringtabs);
}
-
static void ffs_data_reset(struct ffs_data *ffs)
{
ENTER();
@@ -1408,7 +1388,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
return 0;
}
-
static void functionfs_unbind(struct ffs_data *ffs)
{
ENTER();
@@ -1421,7 +1400,6 @@ static void functionfs_unbind(struct ffs_data *ffs)
}
}
-
static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
@@ -1452,7 +1430,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
return 0;
}
-
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
@@ -1472,7 +1449,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
kfree(epfiles);
}
-
static int functionfs_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct ffs_data *ffs)
@@ -1492,7 +1468,6 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev,
func->function.bind = ffs_func_bind;
func->function.unbind = ffs_func_unbind;
func->function.set_alt = ffs_func_set_alt;
- /*func->function.get_alt = ffs_func_get_alt;*/
func->function.disable = ffs_func_disable;
func->function.setup = ffs_func_setup;
func->function.suspend = ffs_func_suspend;
@@ -1517,14 +1492,15 @@ static void ffs_func_free(struct ffs_function *func)
ffs_data_put(func->ffs);
kfree(func->eps);
- /* eps and interfaces_nums are allocated in the same chunk so
+ /*
+ * eps and interfaces_nums are allocated in the same chunk so
* only one free is required. Descriptors are also allocated
- * in the same chunk. */
+ * in the same chunk.
+ */
kfree(func);
}
-
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
@@ -1582,11 +1558,12 @@ static int ffs_func_eps_enable(struct ffs_function *func)
/* Parsing and building descriptors and strings *****************************/
-
-/* This validates if data pointed by data is a valid USB descriptor as
+/*
+ * This validates if data pointed by data is a valid USB descriptor as
* well as record how many interfaces, endpoints and strings are
- * required by given configuration. Returns address afther the
- * descriptor or NULL if data is invalid. */
+ * required by given configuration. Returns address after the
+ * descriptor or NULL if data is invalid.
+ */
enum ffs_entity_type {
FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
@@ -1608,14 +1585,14 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
/* At least two bytes are required: length and type */
if (len < 2) {
- FVDBG("descriptor too short");
+ pr_vdebug("descriptor too short\n");
return -EINVAL;
}
/* If we have at least as many bytes as the descriptor takes? */
length = _ds->bLength;
if (len < length) {
- FVDBG("descriptor longer then available data");
+ pr_vdebug("descriptor longer then available data\n");
return -EINVAL;
}
@@ -1623,15 +1600,15 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
#define __entity_check_STRING(val) (val)
#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
#define __entity(type, val) do { \
- FVDBG("entity " #type "(%02x)", (val)); \
+ pr_vdebug("entity " #type "(%02x)\n", (val)); \
if (unlikely(!__entity_check_ ##type(val))) { \
- FVDBG("invalid entity's value"); \
+ pr_vdebug("invalid entity's value\n"); \
return -EINVAL; \
} \
ret = entity(FFS_ ##type, &val, _ds, priv); \
if (unlikely(ret < 0)) { \
- FDBG("entity " #type "(%02x); ret = %d", \
- (val), ret); \
+ pr_debug("entity " #type "(%02x); ret = %d\n", \
+ (val), ret); \
return ret; \
} \
} while (0)
@@ -1643,12 +1620,13 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
case USB_DT_STRING:
case USB_DT_DEVICE_QUALIFIER:
/* function can't have any of those */
- FVDBG("descriptor reserved for gadget: %d", _ds->bDescriptorType);
+ pr_vdebug("descriptor reserved for gadget: %d\n",
+ _ds->bDescriptorType);
return -EINVAL;
case USB_DT_INTERFACE: {
struct usb_interface_descriptor *ds = (void *)_ds;
- FVDBG("interface descriptor");
+ pr_vdebug("interface descriptor\n");
if (length != sizeof *ds)
goto inv_length;
@@ -1660,7 +1638,7 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
case USB_DT_ENDPOINT: {
struct usb_endpoint_descriptor *ds = (void *)_ds;
- FVDBG("endpoint descriptor");
+ pr_vdebug("endpoint descriptor\n");
if (length != USB_DT_ENDPOINT_SIZE &&
length != USB_DT_ENDPOINT_AUDIO_SIZE)
goto inv_length;
@@ -1675,7 +1653,7 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
case USB_DT_INTERFACE_ASSOCIATION: {
struct usb_interface_assoc_descriptor *ds = (void *)_ds;
- FVDBG("interface association descriptor");
+ pr_vdebug("interface association descriptor\n");
if (length != sizeof *ds)
goto inv_length;
if (ds->iFunction)
@@ -1689,17 +1667,17 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
case USB_DT_SECURITY:
case USB_DT_CS_RADIO_CONTROL:
/* TODO */
- FVDBG("unimplemented descriptor: %d", _ds->bDescriptorType);
+ pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
return -EINVAL;
default:
/* We should never be here */
- FVDBG("unknown descriptor: %d", _ds->bDescriptorType);
+ pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
return -EINVAL;
- inv_length:
- FVDBG("invalid length: %d (descriptor %d)",
- _ds->bLength, _ds->bDescriptorType);
+inv_length:
+ pr_vdebug("invalid length: %d (descriptor %d)\n",
+ _ds->bLength, _ds->bDescriptorType);
return -EINVAL;
}
@@ -1712,7 +1690,6 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
return length;
}
-
static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ffs_entity_callback entity, void *priv)
{
@@ -1727,10 +1704,11 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
if (num == count)
data = NULL;
- /* Record "descriptor" entitny */
+ /* Record "descriptor" entity */
ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
if (unlikely(ret < 0)) {
- FDBG("entity DESCRIPTOR(%02lx); ret = %d", num, ret);
+ pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
+ num, ret);
return ret;
}
@@ -1739,7 +1717,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ret = ffs_do_desc(data, len, entity, priv);
if (unlikely(ret < 0)) {
- FDBG("%s returns %d", __func__, ret);
+ pr_debug("%s returns %d\n", __func__, ret);
return ret;
}
@@ -1749,7 +1727,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
}
}
-
static int __ffs_data_do_entity(enum ffs_entity_type type,
u8 *valuep, struct usb_descriptor_header *desc,
void *priv)
@@ -1763,16 +1740,20 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
break;
case FFS_INTERFACE:
- /* Interfaces are indexed from zero so if we
+ /*
+ * Interfaces are indexed from zero so if we
* encountered interface "n" then there are at least
- * "n+1" interfaces. */
+ * "n+1" interfaces.
+ */
if (*valuep >= ffs->interfaces_count)
ffs->interfaces_count = *valuep + 1;
break;
case FFS_STRING:
- /* Strings are indexed from 1 (0 is magic ;) reserved
- * for languages list or some such) */
+ /*
+ * Strings are indexed from 1 (0 is magic ;) reserved
+ * for languages list or some such)
+ */
if (*valuep > ffs->strings_count)
ffs->strings_count = *valuep;
break;
@@ -1787,7 +1768,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
return 0;
}
-
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{
@@ -1850,8 +1830,6 @@ error:
return ret;
}
-
-
static int __ffs_data_got_strings(struct ffs_data *ffs,
char *const _data, size_t len)
{
@@ -1877,17 +1855,17 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
if (unlikely(str_count < needed_count))
goto error;
- /* If we don't need any strings just return and free all
- * memory */
+ /*
+ * If we don't need any strings just return and free all
+ * memory.
+ */
if (!needed_count) {
kfree(_data);
return 0;
}
- /* Allocate */
+ /* Allocate everything in one chunk so there's less maintenance. */
{
- /* Allocate everything in one chunk so there's less
- * maintanance. */
struct {
struct usb_gadget_strings *stringtabs[lang_count + 1];
struct usb_gadget_strings stringtab[lang_count];
@@ -1938,13 +1916,17 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
if (unlikely(length == len))
goto error_free;
- /* user may provide more strings then we need,
- * if that's the case we simply ingore the
- * rest */
+ /*
+ * User may provide more strings then we need,
+ * if that's the case we simply ignore the
+ * rest
+ */
if (likely(needed)) {
- /* s->id will be set while adding
+ /*
+ * s->id will be set while adding
* function to configuration so for
- * now just leave garbage here. */
+ * now just leave garbage here.
+ */
s->s = data;
--needed;
++s;
@@ -1978,8 +1960,6 @@ error:
}
-
-
/* Events handling and management *******************************************/
static void __ffs_event_add(struct ffs_data *ffs,
@@ -1988,29 +1968,32 @@ static void __ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type rem_type1, rem_type2 = type;
int neg = 0;
- /* Abort any unhandled setup */
- /* We do not need to worry about some cmpxchg() changing value
+ /*
+ * Abort any unhandled setup
+ *
+ * We do not need to worry about some cmpxchg() changing value
* of ffs->setup_state without holding the lock because when
* state is FFS_SETUP_PENDING cmpxchg() in several places in
- * the source does nothing. */
+ * the source does nothing.
+ */
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELED;
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
- /* FALL THGOUTH */
+ /* FALL THROUGH */
case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_SETUP:
rem_type1 = type;
- /* discard all similar events */
+ /* Discard all similar events */
break;
case FUNCTIONFS_BIND:
case FUNCTIONFS_UNBIND:
case FUNCTIONFS_DISABLE:
case FUNCTIONFS_ENABLE:
- /* discard everything other then power management. */
+ /* Discard everything other then power management. */
rem_type1 = FUNCTIONFS_SUSPEND;
rem_type2 = FUNCTIONFS_RESUME;
neg = 1;
@@ -2027,11 +2010,11 @@ static void __ffs_event_add(struct ffs_data *ffs,
if ((*ev == rem_type1 || *ev == rem_type2) == neg)
*out++ = *ev;
else
- FVDBG("purging event %d", *ev);
+ pr_vdebug("purging event %d\n", *ev);
ffs->ev.count = out - ffs->ev.types;
}
- FVDBG("adding event %d", type);
+ pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
}
@@ -2056,8 +2039,10 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct ffs_function *func = priv;
struct ffs_ep *ffs_ep;
- /* If hs_descriptors is not NULL then we are reading hs
- * descriptors now */
+ /*
+ * If hs_descriptors is not NULL then we are reading hs
+ * descriptors now
+ */
const int isHS = func->function.hs_descriptors != NULL;
unsigned idx;
@@ -2076,9 +2061,9 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
ffs_ep = func->eps + idx;
if (unlikely(ffs_ep->descs[isHS])) {
- FVDBG("two %sspeed descriptors for EP %d",
- isHS ? "high" : "full",
- ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ pr_vdebug("two %sspeed descriptors for EP %d\n",
+ isHS ? "high" : "full",
+ ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
return -EINVAL;
}
ffs_ep->descs[isHS] = ds;
@@ -2092,11 +2077,11 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_request *req;
struct usb_ep *ep;
- FVDBG("autoconfig");
+ pr_vdebug("autoconfig\n");
ep = usb_ep_autoconfig(func->gadget, ds);
if (unlikely(!ep))
return -ENOTSUPP;
- ep->driver_data = func->eps + idx;;
+ ep->driver_data = func->eps + idx;
req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (unlikely(!req))
@@ -2112,7 +2097,6 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
return 0;
}
-
static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
@@ -2144,8 +2128,10 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
break;
case FFS_ENDPOINT:
- /* USB_DT_ENDPOINT are handled in
- * __ffs_func_bind_do_descs(). */
+ /*
+ * USB_DT_ENDPOINT are handled in
+ * __ffs_func_bind_do_descs().
+ */
if (desc->bDescriptorType == USB_DT_ENDPOINT)
return 0;
@@ -2161,7 +2147,7 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
break;
}
- FVDBG("%02x -> %02x", *valuep, newValue);
+ pr_vdebug("%02x -> %02x\n", *valuep, newValue);
*valuep = newValue;
return 0;
}
@@ -2212,9 +2198,11 @@ static int ffs_func_bind(struct usb_configuration *c,
func->eps = data->eps;
func->interfaces_nums = data->inums;
- /* Go throught all the endpoint descriptors and allocate
+ /*
+ * Go through all the endpoint descriptors and allocate
* endpoints first, so that later we can rewrite the endpoint
- * numbers without worying that it may be described later on. */
+ * numbers without worrying that it may be described later on.
+ */
if (likely(full)) {
func->function.descriptors = data->fs_descs;
ret = ffs_do_descs(ffs->fs_descs_count,
@@ -2235,9 +2223,11 @@ static int ffs_func_bind(struct usb_configuration *c,
__ffs_func_bind_do_descs, func);
}
- /* Now handle interface numbers allocation and interface and
- * enpoint numbers rewritting. We can do that in one go
- * now. */
+ /*
+ * Now handle interface numbers allocation and interface and
+ * endpoint numbers rewriting. We can do that in one go
+ * now.
+ */
ret = ffs_do_descs(ffs->fs_descs_count +
(high ? ffs->hs_descs_count : 0),
data->raw_descs, sizeof data->raw_descs,
@@ -2275,7 +2265,6 @@ static void ffs_func_unbind(struct usb_configuration *c,
ffs_func_free(func);
}
-
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
@@ -2323,20 +2312,21 @@ static int ffs_func_setup(struct usb_function *f,
ENTER();
- FVDBG("creq->bRequestType = %02x", creq->bRequestType);
- FVDBG("creq->bRequest = %02x", creq->bRequest);
- FVDBG("creq->wValue = %04x", le16_to_cpu(creq->wValue));
- FVDBG("creq->wIndex = %04x", le16_to_cpu(creq->wIndex));
- FVDBG("creq->wLength = %04x", le16_to_cpu(creq->wLength));
+ pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
+ pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
+ pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
+ pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex));
+ pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength));
- /* Most requests directed to interface go throught here
+ /*
+ * Most requests directed to interface go through here
* (notable exceptions are set/get interface) so we need to
* handle them. All other either handled by composite or
* passed to usb_configuration->setup() (if one is set). No
* matter, we will handle requests directed to endpoint here
* as well (as it's straightforward) but what to do with any
- * other request? */
-
+ * other request?
+ */
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
@@ -2379,8 +2369,7 @@ static void ffs_func_resume(struct usb_function *f)
}
-
-/* Enpoint and interface numbers reverse mapping ****************************/
+/* Endpoint and interface numbers reverse mapping ***************************/
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
{
@@ -2411,7 +2400,6 @@ static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
: mutex_lock_interruptible(mutex);
}
-
static char *ffs_prepare_buffer(const char * __user buf, size_t len)
{
char *data;
@@ -2428,7 +2416,7 @@ static char *ffs_prepare_buffer(const char * __user buf, size_t len)
return ERR_PTR(-EFAULT);
}
- FVDBG("Buffer from user space:");
+ pr_vdebug("Buffer from user space:\n");
ffs_dump_mem("", data, len);
return data;
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 4f891eddd060..598e7e2ab80c 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -25,7 +25,6 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/usb/g_hid.h>
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 838286b1cd14..b5dbb2308f56 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -37,7 +37,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
/*
* The Mass Storage Function acts as a USB Mass Storage device,
* appearing to the host as a disk drive or as a CD-ROM drive. In
@@ -185,7 +184,6 @@
* <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
*/
-
/*
* Driver Design
*
@@ -275,7 +273,6 @@
/* #define VERBOSE_DEBUG */
/* #define DUMP_MSGS */
-
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/dcache.h>
@@ -300,7 +297,6 @@
#include "gadget_chips.h"
-
/*------------------------------------------------------------------------*/
#define FSG_DRIVER_DESC "Mass Storage Function"
@@ -308,7 +304,6 @@
static const char fsg_string_interface[] = "Mass Storage";
-
#define FSG_NO_INTR_EP 1
#define FSG_NO_DEVICE_STRINGS 1
#define FSG_NO_OTG 1
@@ -324,25 +319,30 @@ struct fsg_common;
/* FSF callback functions */
struct fsg_operations {
- /* Callback function to call when thread exits. If no
+ /*
+ * Callback function to call when thread exits. If no
* callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on (including those
* marked as non-removable or with prevent_medium_removal flag
- * set). */
+ * set).
+ */
int (*thread_exits)(struct fsg_common *common);
- /* Called prior to ejection. Negative return means error,
+ /*
+ * Called prior to ejection. Negative return means error,
* zero means to continue with ejection, positive means not to
- * eject. */
+ * eject.
+ */
int (*pre_eject)(struct fsg_common *common,
struct fsg_lun *lun, int num);
- /* Called after ejection. Negative return means error, zero
- * or positive is just a success. */
+ /*
+ * Called after ejection. Negative return means error, zero
+ * or positive is just a success.
+ */
int (*post_eject)(struct fsg_common *common,
struct fsg_lun *lun, int num);
};
-
/* Data shared by all the FSG instances. */
struct fsg_common {
struct usb_gadget *gadget;
@@ -398,14 +398,15 @@ struct fsg_common {
/* Gadget's private data. */
void *private_data;
- /* Vendor (8 chars), product (16 chars), release (4
- * hexadecimal digits) and NUL byte */
+ /*
+ * Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte
+ */
char inquiry_string[8 + 16 + 4 + 1];
struct kref ref;
};
-
struct fsg_config {
unsigned nluns;
struct fsg_lun_config {
@@ -431,7 +432,6 @@ struct fsg_config {
char can_stall;
};
-
struct fsg_dev {
struct usb_function function;
struct usb_gadget *gadget; /* Copy of cdev->gadget */
@@ -449,7 +449,6 @@ struct fsg_dev {
struct usb_ep *bulk_out;
};
-
static inline int __fsg_is_set(struct fsg_common *common,
const char *func, unsigned line)
{
@@ -462,13 +461,11 @@ static inline int __fsg_is_set(struct fsg_common *common,
#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
-
static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
{
return container_of(f, struct fsg_dev, function);
}
-
typedef void (*fsg_routine_t)(struct fsg_dev *);
static int exception_in_progress(struct fsg_common *common)
@@ -478,7 +475,7 @@ static int exception_in_progress(struct fsg_common *common)
/* Make bulk-out requests be divisible by the maxpacket size */
static void set_bulk_out_req_length(struct fsg_common *common,
- struct fsg_buffhd *bh, unsigned int length)
+ struct fsg_buffhd *bh, unsigned int length)
{
unsigned int rem;
@@ -489,6 +486,7 @@ static void set_bulk_out_req_length(struct fsg_common *common,
bh->outreq->length = length;
}
+
/*-------------------------------------------------------------------------*/
static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
@@ -519,14 +517,15 @@ static void wakeup_thread(struct fsg_common *common)
wake_up_process(common->thread_task);
}
-
static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
{
unsigned long flags;
- /* Do nothing if a higher-priority exception is already in progress.
+ /*
+ * Do nothing if a higher-priority exception is already in progress.
* If a lower-or-equal priority exception is in progress, preempt it
- * and notify the main thread by sending it a signal. */
+ * and notify the main thread by sending it a signal.
+ */
spin_lock_irqsave(&common->lock, flags);
if (common->state <= new_state) {
common->exception_req_tag = common->ep0_req_tag;
@@ -555,10 +554,10 @@ static int ep0_queue(struct fsg_common *common)
return rc;
}
+
/*-------------------------------------------------------------------------*/
-/* Bulk and interrupt endpoint completion handlers.
- * These always run in_irq. */
+/* Completion handlers. These always run in_irq. */
static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
{
@@ -567,7 +566,7 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
if (req->status || req->actual != req->length)
DBG(common, "%s --> %d, %u/%u\n", __func__,
- req->status, req->actual, req->length);
+ req->status, req->actual, req->length);
if (req->status == -ECONNRESET) /* Request was cancelled */
usb_ep_fifo_flush(ep);
@@ -588,8 +587,7 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
dump_msg(common, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
DBG(common, "%s --> %d, %u/%u\n", __func__,
- req->status, req->actual,
- bh->bulk_out_intended_length);
+ req->status, req->actual, bh->bulk_out_intended_length);
if (req->status == -ECONNRESET) /* Request was cancelled */
usb_ep_fifo_flush(ep);
@@ -602,13 +600,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
spin_unlock(&common->lock);
}
-
-/*-------------------------------------------------------------------------*/
-
-/* Ep0 class-specific handlers. These always run in_irq. */
-
static int fsg_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
+ const struct usb_ctrlrequest *ctrl)
{
struct fsg_dev *fsg = fsg_from_func(f);
struct usb_request *req = fsg->common->ep0req;
@@ -628,8 +621,10 @@ static int fsg_setup(struct usb_function *f,
if (w_index != fsg->interface_number || w_value != 0)
return -EDOM;
- /* Raise an exception to stop the current operation
- * and reinitialize our state. */
+ /*
+ * Raise an exception to stop the current operation
+ * and reinitialize our state.
+ */
DBG(fsg, "bulk reset request\n");
raise_exception(fsg->common, FSG_STATE_RESET);
return DELAYED_STATUS;
@@ -641,7 +636,7 @@ static int fsg_setup(struct usb_function *f,
if (w_index != fsg->interface_number || w_value != 0)
return -EDOM;
VDBG(fsg, "get max LUN\n");
- *(u8 *) req->buf = fsg->common->nluns - 1;
+ *(u8 *)req->buf = fsg->common->nluns - 1;
/* Respond with data/status */
req->length = min((u16)1, w_length);
@@ -649,8 +644,7 @@ static int fsg_setup(struct usb_function *f,
}
VDBG(fsg,
- "unknown class-specific control req "
- "%02x.%02x v%04x i%04x l%u\n",
+ "unknown class-specific control req %02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
le16_to_cpu(ctrl->wValue), w_index, w_length);
return -EOPNOTSUPP;
@@ -661,11 +655,10 @@ static int fsg_setup(struct usb_function *f,
/* All the following routines run in process context */
-
/* Use this for bulk or interrupt transfers, not ep0 */
static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
- struct usb_request *req, int *pbusy,
- enum fsg_buffer_state *state)
+ struct usb_request *req, int *pbusy,
+ enum fsg_buffer_state *state)
{
int rc;
@@ -683,25 +676,34 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
/* We can't do much more than wait for a reset */
- /* Note: currently the net2280 driver fails zero-length
- * submissions if DMA is enabled. */
- if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
- req->length == 0))
+ /*
+ * Note: currently the net2280 driver fails zero-length
+ * submissions if DMA is enabled.
+ */
+ if (rc != -ESHUTDOWN &&
+ !(rc == -EOPNOTSUPP && req->length == 0))
WARNING(fsg, "error in submission: %s --> %d\n",
- ep->name, rc);
+ ep->name, rc);
}
}
-#define START_TRANSFER_OR(common, ep_name, req, pbusy, state) \
- if (fsg_is_set(common)) \
- start_transfer((common)->fsg, (common)->fsg->ep_name, \
- req, pbusy, state); \
- else
-
-#define START_TRANSFER(common, ep_name, req, pbusy, state) \
- START_TRANSFER_OR(common, ep_name, req, pbusy, state) (void)0
-
+static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+ if (!fsg_is_set(common))
+ return false;
+ start_transfer(common->fsg, common->fsg->bulk_in,
+ bh->inreq, &bh->inreq_busy, &bh->state);
+ return true;
+}
+static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+ if (!fsg_is_set(common))
+ return false;
+ start_transfer(common->fsg, common->fsg->bulk_out,
+ bh->outreq, &bh->outreq_busy, &bh->state);
+ return true;
+}
static int sleep_thread(struct fsg_common *common)
{
@@ -739,16 +741,20 @@ static int do_read(struct fsg_common *common)
unsigned int partial_page;
ssize_t nread;
- /* Get the starting Logical Block Address and check that it's
- * not too big */
+ /*
+ * Get the starting Logical Block Address and check that it's
+ * not too big.
+ */
if (common->cmnd[0] == READ_6)
lba = get_unaligned_be24(&common->cmnd[1]);
else {
lba = get_unaligned_be32(&common->cmnd[2]);
- /* We allow DPO (Disable Page Out = don't save data in the
+ /*
+ * We allow DPO (Disable Page Out = don't save data in the
* cache) and FUA (Force Unit Access = don't read from the
- * cache), but we don't implement them. */
+ * cache), but we don't implement them.
+ */
if ((common->cmnd[1] & ~0x18) != 0) {
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
@@ -766,22 +772,23 @@ static int do_read(struct fsg_common *common)
return -EIO; /* No default reply */
for (;;) {
-
- /* Figure out how much we need to read:
+ /*
+ * Figure out how much we need to read:
* Try to read the remaining amount.
* But don't read more than the buffer size.
* And don't try to read past the end of the file.
* Finally, if we're not at a page boundary, don't read past
* the next page.
* If this means reading 0 then we were asked to read past
- * the end of file. */
+ * the end of file.
+ */
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t) amount,
- curlun->file_length - file_offset);
+ amount = min((loff_t)amount,
+ curlun->file_length - file_offset);
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
- partial_page);
+ amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
+ partial_page);
/* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill;
@@ -791,8 +798,10 @@ static int do_read(struct fsg_common *common)
return rc;
}
- /* If we were asked to read past the end of file,
- * end with an empty buffer. */
+ /*
+ * If we were asked to read past the end of file,
+ * end with an empty buffer.
+ */
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
@@ -806,21 +815,19 @@ static int do_read(struct fsg_common *common)
/* Perform the read */
file_offset_tmp = file_offset;
nread = vfs_read(curlun->filp,
- (char __user *) bh->buf,
- amount, &file_offset_tmp);
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
- (unsigned long long) file_offset,
- (int) nread);
+ (unsigned long long)file_offset, (int)nread);
if (signal_pending(current))
return -EINTR;
if (nread < 0) {
- LDBG(curlun, "error in file read: %d\n",
- (int) nread);
+ LDBG(curlun, "error in file read: %d\n", (int)nread);
nread = 0;
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
- (int) nread, amount);
+ (int)nread, amount);
nread -= (nread & 511); /* Round down to a block */
}
file_offset += nread;
@@ -842,10 +849,8 @@ static int do_read(struct fsg_common *common)
/* Send this buffer and go read some more */
bh->inreq->zero = 0;
- START_TRANSFER_OR(common, bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state)
- /* Don't know what to do if
- * common->fsg is NULL */
+ if (!start_in_transfer(common, bh))
+ /* Don't know what to do if common->fsg is NULL */
return -EIO;
common->next_buffhd_to_fill = bh->next;
}
@@ -877,17 +882,21 @@ static int do_write(struct fsg_common *common)
curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */
spin_unlock(&curlun->filp->f_lock);
- /* Get the starting Logical Block Address and check that it's
- * not too big */
+ /*
+ * Get the starting Logical Block Address and check that it's
+ * not too big
+ */
if (common->cmnd[0] == WRITE_6)
lba = get_unaligned_be24(&common->cmnd[1]);
else {
lba = get_unaligned_be32(&common->cmnd[2]);
- /* We allow DPO (Disable Page Out = don't save data in the
+ /*
+ * We allow DPO (Disable Page Out = don't save data in the
* cache) and FUA (Force Unit Access = write directly to the
* medium). We don't implement DPO; we implement FUA by
- * performing synchronous output. */
+ * performing synchronous output.
+ */
if (common->cmnd[1] & ~0x18) {
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
@@ -915,7 +924,8 @@ static int do_write(struct fsg_common *common)
bh = common->next_buffhd_to_fill;
if (bh->state == BUF_STATE_EMPTY && get_some_more) {
- /* Figure out how much we want to get:
+ /*
+ * Figure out how much we want to get:
* Try to get the remaining amount.
* But don't get more than the buffer size.
* And don't try to go past the end of the file.
@@ -923,14 +933,15 @@ static int do_write(struct fsg_common *common)
* don't go past the next page.
* If this means getting 0, then we were asked
* to write past the end of file.
- * Finally, round down to a block boundary. */
+ * Finally, round down to a block boundary.
+ */
amount = min(amount_left_to_req, FSG_BUFLEN);
- amount = min((loff_t) amount, curlun->file_length -
- usb_offset);
+ amount = min((loff_t)amount,
+ curlun->file_length - usb_offset);
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
amount = min(amount,
- (unsigned int) PAGE_CACHE_SIZE - partial_page);
+ (unsigned int)PAGE_CACHE_SIZE - partial_page);
if (amount == 0) {
get_some_more = 0;
@@ -940,11 +951,13 @@ static int do_write(struct fsg_common *common)
curlun->info_valid = 1;
continue;
}
- amount -= (amount & 511);
+ amount -= amount & 511;
if (amount == 0) {
- /* Why were we were asked to transfer a
- * partial block? */
+ /*
+ * Why were we were asked to transfer a
+ * partial block?
+ */
get_some_more = 0;
continue;
}
@@ -956,15 +969,15 @@ static int do_write(struct fsg_common *common)
if (amount_left_to_req == 0)
get_some_more = 0;
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
+ /*
+ * amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size
+ */
bh->outreq->length = amount;
bh->bulk_out_intended_length = amount;
bh->outreq->short_not_ok = 1;
- START_TRANSFER_OR(common, bulk_out, bh->outreq,
- &bh->outreq_busy, &bh->state)
- /* Don't know what to do if
- * common->fsg is NULL */
+ if (!start_out_transfer(common, bh))
+ /* Dunno what to do if common->fsg is NULL */
return -EIO;
common->next_buffhd_to_fill = bh->next;
continue;
@@ -990,30 +1003,29 @@ static int do_write(struct fsg_common *common)
amount = bh->outreq->actual;
if (curlun->file_length - file_offset < amount) {
LERROR(curlun,
- "write %u @ %llu beyond end %llu\n",
- amount, (unsigned long long) file_offset,
- (unsigned long long) curlun->file_length);
+ "write %u @ %llu beyond end %llu\n",
+ amount, (unsigned long long)file_offset,
+ (unsigned long long)curlun->file_length);
amount = curlun->file_length - file_offset;
}
/* Perform the write */
file_offset_tmp = file_offset;
nwritten = vfs_write(curlun->filp,
- (char __user *) bh->buf,
- amount, &file_offset_tmp);
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
- (unsigned long long) file_offset,
- (int) nwritten);
+ (unsigned long long)file_offset, (int)nwritten);
if (signal_pending(current))
return -EINTR; /* Interrupted! */
if (nwritten < 0) {
LDBG(curlun, "error in file write: %d\n",
- (int) nwritten);
+ (int)nwritten);
nwritten = 0;
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
- (int) nwritten, amount);
+ (int)nwritten, amount);
nwritten -= (nwritten & 511);
/* Round down to a block */
}
@@ -1086,16 +1098,20 @@ static int do_verify(struct fsg_common *common)
unsigned int amount;
ssize_t nread;
- /* Get the starting Logical Block Address and check that it's
- * not too big */
+ /*
+ * Get the starting Logical Block Address and check that it's
+ * not too big.
+ */
lba = get_unaligned_be32(&common->cmnd[2]);
if (lba >= curlun->num_sectors) {
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- /* We allow DPO (Disable Page Out = don't save data in the
- * cache) but we don't implement it. */
+ /*
+ * We allow DPO (Disable Page Out = don't save data in the
+ * cache) but we don't implement it.
+ */
if (common->cmnd[1] & ~0x10) {
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
@@ -1120,16 +1136,17 @@ static int do_verify(struct fsg_common *common)
/* Just try to read the requested blocks */
while (amount_left > 0) {
-
- /* Figure out how much we need to read:
+ /*
+ * Figure out how much we need to read:
* Try to read the remaining amount, but not more than
* the buffer size.
* And don't try to read past the end of the file.
* If this means reading 0 then we were asked to read
- * past the end of file. */
+ * past the end of file.
+ */
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t) amount,
- curlun->file_length - file_offset);
+ amount = min((loff_t)amount,
+ curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
@@ -1150,13 +1167,12 @@ static int do_verify(struct fsg_common *common)
return -EINTR;
if (nread < 0) {
- LDBG(curlun, "error in file verify: %d\n",
- (int) nread);
+ LDBG(curlun, "error in file verify: %d\n", (int)nread);
nread = 0;
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
- (int) nread, amount);
- nread -= (nread & 511); /* Round down to a sector */
+ (int)nread, amount);
+ nread -= nread & 511; /* Round down to a sector */
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
@@ -1198,7 +1214,6 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
return 36;
}
-
static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
@@ -1252,13 +1267,12 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
return 18;
}
-
static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
u32 lba = get_unaligned_be32(&common->cmnd[2]);
int pmi = common->cmnd[8];
- u8 *buf = (u8 *) bh->buf;
+ u8 *buf = (u8 *)bh->buf;
/* Check the PMI and LBA fields */
if (pmi > 1 || (pmi == 0 && lba != 0)) {
@@ -1272,13 +1286,12 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
return 8;
}
-
static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
int msf = common->cmnd[1] & 0x02;
u32 lba = get_unaligned_be32(&common->cmnd[2]);
- u8 *buf = (u8 *) bh->buf;
+ u8 *buf = (u8 *)bh->buf;
if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
@@ -1295,13 +1308,12 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
return 8;
}
-
static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
int msf = common->cmnd[1] & 0x02;
int start_track = common->cmnd[6];
- u8 *buf = (u8 *) bh->buf;
+ u8 *buf = (u8 *)bh->buf;
if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
start_track > 1) {
@@ -1323,7 +1335,6 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
return 20;
}
-
static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
@@ -1348,10 +1359,12 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
changeable_values = (pc == 1);
all_pages = (page_code == 0x3f);
- /* Write the mode parameter header. Fixed values are: default
+ /*
+ * Write the mode parameter header. Fixed values are: default
* medium type, no cache control (DPOFUA), and no block descriptors.
* The only variable value is the WriteProtect bit. We will fill in
- * the mode data length later. */
+ * the mode data length later.
+ */
memset(buf, 0, 8);
if (mscmnd == MODE_SENSE) {
buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
@@ -1365,8 +1378,10 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
/* No block descriptors */
- /* The mode pages, in numerical order. The only page we support
- * is the Caching page. */
+ /*
+ * The mode pages, in numerical order. The only page we support
+ * is the Caching page.
+ */
if (page_code == 0x08 || all_pages) {
valid_page = 1;
buf[0] = 0x08; /* Page code */
@@ -1388,8 +1403,10 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
buf += 12;
}
- /* Check that a valid page was requested and the mode data length
- * isn't too long. */
+ /*
+ * Check that a valid page was requested and the mode data length
+ * isn't too long.
+ */
len = buf - buf0;
if (!valid_page || len > limit) {
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
@@ -1404,7 +1421,6 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
return len;
}
-
static int do_start_stop(struct fsg_common *common)
{
struct fsg_lun *curlun = common->curlun;
@@ -1424,8 +1440,10 @@ static int do_start_stop(struct fsg_common *common)
loej = common->cmnd[4] & 0x02;
start = common->cmnd[4] & 0x01;
- /* Our emulation doesn't support mounting; the medium is
- * available for use as soon as it is loaded. */
+ /*
+ * Our emulation doesn't support mounting; the medium is
+ * available for use as soon as it is loaded.
+ */
if (start) {
if (!fsg_lun_is_open(curlun)) {
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
@@ -1466,7 +1484,6 @@ static int do_start_stop(struct fsg_common *common)
: 0;
}
-
static int do_prevent_allow(struct fsg_common *common)
{
struct fsg_lun *curlun = common->curlun;
@@ -1491,7 +1508,6 @@ static int do_prevent_allow(struct fsg_common *common)
return 0;
}
-
static int do_read_format_capacities(struct fsg_common *common,
struct fsg_buffhd *bh)
{
@@ -1509,7 +1525,6 @@ static int do_read_format_capacities(struct fsg_common *common,
return 12;
}
-
static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
@@ -1591,7 +1606,7 @@ static int pad_with_zeros(struct fsg_dev *fsg)
bh->inreq->length = nsend;
bh->inreq->zero = 0;
start_transfer(fsg, fsg->bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state);
+ &bh->inreq_busy, &bh->state);
bh = fsg->common->next_buffhd_to_fill = bh->next;
fsg->common->usb_amount_left -= nsend;
nkeep = 0;
@@ -1617,7 +1632,7 @@ static int throw_away_data(struct fsg_common *common)
/* A short packet or an error ends everything */
if (bh->outreq->actual != bh->outreq->length ||
- bh->outreq->status != 0) {
+ bh->outreq->status != 0) {
raise_exception(common,
FSG_STATE_ABORT_BULK_OUT);
return -EINTR;
@@ -1631,15 +1646,15 @@ static int throw_away_data(struct fsg_common *common)
&& common->usb_amount_left > 0) {
amount = min(common->usb_amount_left, FSG_BUFLEN);
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
+ /*
+ * amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size.
+ */
bh->outreq->length = amount;
bh->bulk_out_intended_length = amount;
bh->outreq->short_not_ok = 1;
- START_TRANSFER_OR(common, bulk_out, bh->outreq,
- &bh->outreq_busy, &bh->state)
- /* Don't know what to do if
- * common->fsg is NULL */
+ if (!start_out_transfer(common, bh))
+ /* Dunno what to do if common->fsg is NULL */
return -EIO;
common->next_buffhd_to_fill = bh->next;
common->usb_amount_left -= amount;
@@ -1654,7 +1669,6 @@ static int throw_away_data(struct fsg_common *common)
return 0;
}
-
static int finish_reply(struct fsg_common *common)
{
struct fsg_buffhd *bh = common->next_buffhd_to_fill;
@@ -1664,10 +1678,12 @@ static int finish_reply(struct fsg_common *common)
case DATA_DIR_NONE:
break; /* Nothing to send */
- /* If we don't know whether the host wants to read or write,
+ /*
+ * If we don't know whether the host wants to read or write,
* this must be CB or CBI with an unknown command. We mustn't
* try to send or receive any data. So stall both bulk pipes
- * if we can and wait for a reset. */
+ * if we can and wait for a reset.
+ */
case DATA_DIR_UNKNOWN:
if (!common->can_stall) {
/* Nothing */
@@ -1688,18 +1704,18 @@ static int finish_reply(struct fsg_common *common)
/* If there's no residue, simply send the last buffer */
} else if (common->residue == 0) {
bh->inreq->zero = 0;
- START_TRANSFER_OR(common, bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state)
+ if (!start_in_transfer(common, bh))
return -EIO;
common->next_buffhd_to_fill = bh->next;
- /* For Bulk-only, if we're allowed to stall then send the
+ /*
+ * For Bulk-only, if we're allowed to stall then send the
* short packet and halt the bulk-in endpoint. If we can't
- * stall, pad out the remaining data with 0's. */
+ * stall, pad out the remaining data with 0's.
+ */
} else if (common->can_stall) {
bh->inreq->zero = 1;
- START_TRANSFER_OR(common, bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state)
+ if (!start_in_transfer(common, bh))
/* Don't know what to do if
* common->fsg is NULL */
rc = -EIO;
@@ -1714,8 +1730,10 @@ static int finish_reply(struct fsg_common *common)
}
break;
- /* We have processed all we want from the data the host has sent.
- * There may still be outstanding bulk-out requests. */
+ /*
+ * We have processed all we want from the data the host has sent.
+ * There may still be outstanding bulk-out requests.
+ */
case DATA_DIR_FROM_HOST:
if (common->residue == 0) {
/* Nothing to receive */
@@ -1725,12 +1743,14 @@ static int finish_reply(struct fsg_common *common)
raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
rc = -EINTR;
- /* We haven't processed all the incoming data. Even though
+ /*
+ * We haven't processed all the incoming data. Even though
* we may be allowed to stall, doing so would cause a race.
* The controller may already have ACK'ed all the remaining
* bulk-out packets, in which case the host wouldn't see a
* STALL. Not realizing the endpoint was halted, it wouldn't
- * clear the halt -- leading to problems later on. */
+ * clear the halt -- leading to problems later on.
+ */
#if 0
} else if (common->can_stall) {
if (fsg_is_set(common))
@@ -1740,8 +1760,10 @@ static int finish_reply(struct fsg_common *common)
rc = -EINTR;
#endif
- /* We can't stall. Read in the excess data and throw it
- * all away. */
+ /*
+ * We can't stall. Read in the excess data and throw it
+ * all away.
+ */
} else {
rc = throw_away_data(common);
}
@@ -1750,7 +1772,6 @@ static int finish_reply(struct fsg_common *common)
return rc;
}
-
static int send_status(struct fsg_common *common)
{
struct fsg_lun *curlun = common->curlun;
@@ -1798,8 +1819,7 @@ static int send_status(struct fsg_common *common)
bh->inreq->length = USB_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
- START_TRANSFER_OR(common, bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state)
+ if (!start_in_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
@@ -1810,11 +1830,13 @@ static int send_status(struct fsg_common *common)
/*-------------------------------------------------------------------------*/
-/* Check whether the command is properly formed and whether its data size
- * and direction agree with the values we already have. */
+/*
+ * Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have.
+ */
static int check_command(struct fsg_common *common, int cmnd_size,
- enum data_direction data_dir, unsigned int mask,
- int needs_medium, const char *name)
+ enum data_direction data_dir, unsigned int mask,
+ int needs_medium, const char *name)
{
int i;
int lun = common->cmnd[1] >> 5;
@@ -1825,19 +1847,23 @@ static int check_command(struct fsg_common *common, int cmnd_size,
hdlen[0] = 0;
if (common->data_dir != DATA_DIR_UNKNOWN)
sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
- common->data_size);
+ common->data_size);
VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
name, cmnd_size, dirletter[(int) data_dir],
common->data_size_from_cmnd, common->cmnd_size, hdlen);
- /* We can't reply at all until we know the correct data direction
- * and size. */
+ /*
+ * We can't reply at all until we know the correct data direction
+ * and size.
+ */
if (common->data_size_from_cmnd == 0)
data_dir = DATA_DIR_NONE;
if (common->data_size < common->data_size_from_cmnd) {
- /* Host data size < Device data size is a phase error.
+ /*
+ * Host data size < Device data size is a phase error.
* Carry out the command, but only transfer as much as
- * we are allowed. */
+ * we are allowed.
+ */
common->data_size_from_cmnd = common->data_size;
common->phase_error = 1;
}
@@ -1845,8 +1871,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
common->usb_amount_left = common->data_size;
/* Conflicting data directions is a phase error */
- if (common->data_dir != data_dir
- && common->data_size_from_cmnd > 0) {
+ if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) {
common->phase_error = 1;
return -EINVAL;
}
@@ -1854,7 +1879,8 @@ static int check_command(struct fsg_common *common, int cmnd_size,
/* Verify the length of the command itself */
if (cmnd_size != common->cmnd_size) {
- /* Special case workaround: There are plenty of buggy SCSI
+ /*
+ * Special case workaround: There are plenty of buggy SCSI
* implementations. Many have issues with cbw->Length
* field passing a wrong command size. For those cases we
* always try to work around the problem by using the length
@@ -1896,8 +1922,10 @@ static int check_command(struct fsg_common *common, int cmnd_size,
curlun = NULL;
common->bad_lun_okay = 0;
- /* INQUIRY and REQUEST SENSE commands are explicitly allowed
- * to use unsupported LUNs; all others may not. */
+ /*
+ * INQUIRY and REQUEST SENSE commands are explicitly allowed
+ * to use unsupported LUNs; all others may not.
+ */
if (common->cmnd[0] != INQUIRY &&
common->cmnd[0] != REQUEST_SENSE) {
DBG(common, "unsupported LUN %d\n", common->lun);
@@ -1905,11 +1933,13 @@ static int check_command(struct fsg_common *common, int cmnd_size,
}
}
- /* If a unit attention condition exists, only INQUIRY and
- * REQUEST SENSE commands are allowed; anything else must fail. */
+ /*
+ * If a unit attention condition exists, only INQUIRY and
+ * REQUEST SENSE commands are allowed; anything else must fail.
+ */
if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
- common->cmnd[0] != INQUIRY &&
- common->cmnd[0] != REQUEST_SENSE) {
+ common->cmnd[0] != INQUIRY &&
+ common->cmnd[0] != REQUEST_SENSE) {
curlun->sense_data = curlun->unit_attention_data;
curlun->unit_attention_data = SS_NO_SENSE;
return -EINVAL;
@@ -1935,7 +1965,6 @@ static int check_command(struct fsg_common *common, int cmnd_size,
return 0;
}
-
static int do_scsi_command(struct fsg_common *common)
{
struct fsg_buffhd *bh;
@@ -2123,8 +2152,10 @@ static int do_scsi_command(struct fsg_common *common)
"TEST UNIT READY");
break;
- /* Although optional, this command is used by MS-Windows. We
- * support a minimal version: BytChk must be 0. */
+ /*
+ * Although optional, this command is used by MS-Windows. We
+ * support a minimal version: BytChk must be 0.
+ */
case VERIFY:
common->data_size_from_cmnd = 0;
reply = check_command(common, 10, DATA_DIR_NONE,
@@ -2164,10 +2195,12 @@ static int do_scsi_command(struct fsg_common *common)
reply = do_write(common);
break;
- /* Some mandatory commands that we recognize but don't implement.
+ /*
+ * Some mandatory commands that we recognize but don't implement.
* They don't mean much in this setting. It's left as an exercise
* for anyone interested to implement RESERVE and RELEASE in terms
- * of Posix locks. */
+ * of Posix locks.
+ */
case FORMAT_UNIT:
case RELEASE:
case RESERVE:
@@ -2195,7 +2228,7 @@ unknown_cmnd:
if (reply == -EINVAL)
reply = 0; /* Error reply length */
if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
- reply = min((u32) reply, common->data_size_from_cmnd);
+ reply = min((u32)reply, common->data_size_from_cmnd);
bh->inreq->length = reply;
bh->state = BUF_STATE_FULL;
common->residue -= reply;
@@ -2225,7 +2258,8 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
req->actual,
le32_to_cpu(cbw->Signature));
- /* The Bulk-only spec says we MUST stall the IN endpoint
+ /*
+ * The Bulk-only spec says we MUST stall the IN endpoint
* (6.6.1), so it's unavoidable. It also says we must
* retain this state until the next reset, but there's
* no way to tell the controller driver it should ignore
@@ -2233,7 +2267,8 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
*
* We aren't required to halt the OUT endpoint; instead
* we can simply accept and discard any data received
- * until the next reset. */
+ * until the next reset.
+ */
wedge_bulk_in_endpoint(fsg);
set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
@@ -2246,8 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
- /* We can do anything we want here, so let's stall the
- * bulk pipes if we are allowed to. */
+ /*
+ * We can do anything we want here, so let's stall the
+ * bulk pipes if we are allowed to.
+ */
if (common->can_stall) {
fsg_set_halt(fsg, fsg->bulk_out);
halt_bulk_in_endpoint(fsg);
@@ -2270,7 +2307,6 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
return 0;
}
-
static int get_next_command(struct fsg_common *common)
{
struct fsg_buffhd *bh;
@@ -2287,14 +2323,15 @@ static int get_next_command(struct fsg_common *common)
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
bh->outreq->short_not_ok = 1;
- START_TRANSFER_OR(common, bulk_out, bh->outreq,
- &bh->outreq_busy, &bh->state)
+ if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
- /* We will drain the buffer in software, which means we
+ /*
+ * We will drain the buffer in software, which means we
* can reuse it for the next filling. No need to advance
- * next_buffhd_to_fill. */
+ * next_buffhd_to_fill.
+ */
/* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) {
@@ -2425,7 +2462,6 @@ reset:
/****************************** ALT CONFIGS ******************************/
-
static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct fsg_dev *fsg = fsg_from_func(f);
@@ -2453,8 +2489,10 @@ static void handle_exception(struct fsg_common *common)
struct fsg_lun *curlun;
unsigned int exception_req_tag;
- /* Clear the existing signals. Anything but SIGUSR1 is converted
- * into a high-priority EXIT exception. */
+ /*
+ * Clear the existing signals. Anything but SIGUSR1 is converted
+ * into a high-priority EXIT exception.
+ */
for (;;) {
int sig =
dequeue_signal_lock(current, &current->blocked, &info);
@@ -2498,8 +2536,10 @@ static void handle_exception(struct fsg_common *common)
usb_ep_fifo_flush(common->fsg->bulk_out);
}
- /* Reset the I/O buffer states and pointers, the SCSI
- * state, and the exception. Then invoke the handler. */
+ /*
+ * Reset the I/O buffer states and pointers, the SCSI
+ * state, and the exception. Then invoke the handler.
+ */
spin_lock_irq(&common->lock);
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
@@ -2537,9 +2577,11 @@ static void handle_exception(struct fsg_common *common)
break;
case FSG_STATE_RESET:
- /* In case we were forced against our will to halt a
+ /*
+ * In case we were forced against our will to halt a
* bulk endpoint, clear the halt now. (The SuperH UDC
- * requires this.) */
+ * requires this.)
+ */
if (!fsg_is_set(common))
break;
if (test_and_clear_bit(IGNORE_BULK_OUT,
@@ -2549,9 +2591,11 @@ static void handle_exception(struct fsg_common *common)
if (common->ep0_req_tag == exception_req_tag)
ep0_queue(common); /* Complete the status stage */
- /* Technically this should go here, but it would only be
+ /*
+ * Technically this should go here, but it would only be
* a waste of time. Ditto for the INTERFACE_CHANGE and
- * CONFIG_CHANGE cases. */
+ * CONFIG_CHANGE cases.
+ */
/* for (i = 0; i < common->nluns; ++i) */
/* common->luns[i].unit_attention_data = */
/* SS_RESET_OCCURRED; */
@@ -2586,8 +2630,10 @@ static int fsg_main_thread(void *common_)
{
struct fsg_common *common = common_;
- /* Allow the thread to be killed by a signal, but set the signal mask
- * to block everything but INT, TERM, KILL, and USR1. */
+ /*
+ * Allow the thread to be killed by a signal, but set the signal mask
+ * to block everything but INT, TERM, KILL, and USR1.
+ */
allow_signal(SIGINT);
allow_signal(SIGTERM);
allow_signal(SIGKILL);
@@ -2596,9 +2642,11 @@ static int fsg_main_thread(void *common_)
/* Allow the thread to be frozen */
set_freezable();
- /* Arrange for userspace references to be interpreted as kernel
+ /*
+ * Arrange for userspace references to be interpreted as kernel
* pointers. That way we can pass a kernel pointer to a routine
- * that expects a __user pointer and it will work okay. */
+ * that expects a __user pointer and it will work okay.
+ */
set_fs(get_ds());
/* The main loop */
@@ -2658,7 +2706,7 @@ static int fsg_main_thread(void *common_)
up_write(&common->filesem);
}
- /* Let the unbind and cleanup routines know the thread has exited */
+ /* Let fsg_unbind() know the thread has exited */
complete_and_exit(&common->thread_notifier, 0);
}
@@ -2690,7 +2738,6 @@ static inline void fsg_common_put(struct fsg_common *common)
kref_put(&common->ref, fsg_common_release);
}
-
static struct fsg_common *fsg_common_init(struct fsg_common *common,
struct usb_composite_dev *cdev,
struct fsg_config *cfg)
@@ -2736,8 +2783,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
fsg_intf_desc.iInterface = rc;
}
- /* Create the LUNs, open their backing files, and register the
- * LUN devices in sysfs. */
+ /*
+ * Create the LUNs, open their backing files, and register the
+ * LUN devices in sysfs.
+ */
curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
if (unlikely(!curlun)) {
rc = -ENOMEM;
@@ -2765,6 +2814,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
if (rc) {
INFO(common, "failed to register LUN%d: %d\n", i, rc);
common->nluns = i;
+ put_device(&curlun->dev);
goto error_release;
}
@@ -2790,7 +2840,6 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
}
common->nluns = nluns;
-
/* Data buffers cyclic list */
bh = common->buffhds;
i = FSG_NUM_BUFFERS;
@@ -2807,7 +2856,6 @@ buffhds_first_it:
} while (--i);
bh->next = common->buffhds;
-
/* Prepare inquiryString */
if (cfg->release != 0xffff) {
i = cfg->release;
@@ -2821,41 +2869,35 @@ buffhds_first_it:
i = 0x0399;
}
}
-#define OR(x, y) ((x) ? (x) : (y))
snprintf(common->inquiry_string, sizeof common->inquiry_string,
- "%-8s%-16s%04x",
- OR(cfg->vendor_name, "Linux "),
+ "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
/* Assume product name dependent on the first LUN */
- OR(cfg->product_name, common->luns->cdrom
+ cfg->product_name ?: (common->luns->cdrom
? "File-Stor Gadget"
- : "File-CD Gadget "),
+ : "File-CD Gadget"),
i);
-
- /* Some peripheral controllers are known not to be able to
+ /*
+ * Some peripheral controllers are known not to be able to
* halt bulk endpoints correctly. If one of them is present,
* disable stalls.
*/
common->can_stall = cfg->can_stall &&
!(gadget_is_at91(common->gadget));
-
spin_lock_init(&common->lock);
kref_init(&common->ref);
-
/* Tell the thread to start working */
common->thread_task =
kthread_create(fsg_main_thread, common,
- OR(cfg->thread_name, "file-storage"));
+ cfg->thread_name ?: "file-storage");
if (IS_ERR(common->thread_task)) {
rc = PTR_ERR(common->thread_task);
goto error_release;
}
init_completion(&common->thread_notifier);
init_waitqueue_head(&common->fsg_wait);
-#undef OR
-
/* Information */
INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
@@ -2889,18 +2931,15 @@ buffhds_first_it:
return common;
-
error_luns:
common->nluns = i + 1;
error_release:
common->state = FSG_STATE_TERMINATED; /* The thread is dead */
- /* Call fsg_common_release() directly, ref might be not
- * initialised */
+ /* Call fsg_common_release() directly, ref might be not initialised. */
fsg_common_release(&common->ref);
return ERR_PTR(rc);
}
-
static void fsg_common_release(struct kref *ref)
{
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
@@ -2909,9 +2948,6 @@ static void fsg_common_release(struct kref *ref)
if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT);
wait_for_completion(&common->thread_notifier);
-
- /* The cleanup routine waits for this completion also */
- complete(&common->thread_notifier);
}
if (likely(common->luns)) {
@@ -2945,7 +2981,6 @@ static void fsg_common_release(struct kref *ref)
/*-------------------------------------------------------------------------*/
-
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
@@ -2965,7 +3000,6 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(fsg);
}
-
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
@@ -3048,11 +3082,13 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
fsg->function.disable = fsg_disable;
fsg->common = common;
- /* Our caller holds a reference to common structure so we
+ /*
+ * Our caller holds a reference to common structure so we
* don't have to be worry about it being freed until we return
* from this function. So instead of incrementing counter now
* and decrement in error recovery we increment it only when
- * call to usb_add_function() was successful. */
+ * call to usb_add_function() was successful.
+ */
rc = usb_add_function(c, &fsg->function);
if (unlikely(rc))
@@ -3063,8 +3099,7 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
}
static inline int __deprecated __maybe_unused
-fsg_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
+fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c,
struct fsg_common *common)
{
return fsg_bind_config(cdev, c, common);
@@ -3073,7 +3108,6 @@ fsg_add(struct usb_composite_dev *cdev,
/************************* Module parameters *************************/
-
struct fsg_module_parameters {
char *file[FSG_MAX_LUNS];
int ro[FSG_MAX_LUNS];
@@ -3087,7 +3121,6 @@ struct fsg_module_parameters {
int stall; /* can_stall */
};
-
#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
module_param_array_named(prefix ## name, params.name, type, \
&prefix ## params.name ## _count, \
@@ -3115,7 +3148,6 @@ struct fsg_module_parameters {
_FSG_MODULE_PARAM(prefix, params, stall, bool, \
"false to prevent bulk stalls")
-
static void
fsg_config_from_params(struct fsg_config *cfg,
const struct fsg_module_parameters *params)
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
new file mode 100644
index 000000000000..130eee678c8b
--- /dev/null
+++ b/drivers/usb/gadget/f_ncm.c
@@ -0,0 +1,1407 @@
+/*
+ * f_ncm.c -- USB CDC Network (NCM) link function driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
+ *
+ * The driver borrows from f_ecm.c which is:
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2008 Nokia 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/kernel.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+
+#include <linux/usb/cdc.h>
+
+#include "u_ether.h"
+
+/*
+ * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
+ * NCM is intended to be used with high-speed network attachments.
+ *
+ * Note that NCM requires the use of "alternate settings" for its data
+ * interface. This means that the set_alt() method has real work to do,
+ * and also means that a get_alt() method is required.
+ */
+
+/* to trigger crc/non-crc ndp signature */
+
+#define NCM_NDP_HDR_CRC_MASK 0x01000000
+#define NCM_NDP_HDR_CRC 0x01000000
+#define NCM_NDP_HDR_NOCRC 0x00000000
+
+struct ncm_ep_descs {
+ struct usb_endpoint_descriptor *in;
+ struct usb_endpoint_descriptor *out;
+ struct usb_endpoint_descriptor *notify;
+};
+
+enum ncm_notify_state {
+ NCM_NOTIFY_NONE, /* don't notify */
+ NCM_NOTIFY_CONNECT, /* issue CONNECT next */
+ NCM_NOTIFY_SPEED, /* issue SPEED_CHANGE next */
+};
+
+struct f_ncm {
+ struct gether port;
+ u8 ctrl_id, data_id;
+
+ char ethaddr[14];
+
+ struct ncm_ep_descs fs;
+ struct ncm_ep_descs hs;
+
+ struct usb_ep *notify;
+ struct usb_endpoint_descriptor *notify_desc;
+ struct usb_request *notify_req;
+ u8 notify_state;
+ bool is_open;
+
+ struct ndp_parser_opts *parser_opts;
+ bool is_crc;
+
+ /*
+ * for notification, it is accessed from both
+ * callback and ethernet open/close
+ */
+ spinlock_t lock;
+};
+
+static inline struct f_ncm *func_to_ncm(struct usb_function *f)
+{
+ return container_of(f, struct f_ncm, port.func);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static inline unsigned ncm_bitrate(struct usb_gadget *g)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return 13 * 512 * 8 * 1000 * 8;
+ else
+ return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * We cannot group frames so use just the minimal size which ok to put
+ * one max-size ethernet frame.
+ * If the host can group frames, allow it to do that, 16K is selected,
+ * because it's used by default by the current linux host driver
+ */
+#define NTB_DEFAULT_IN_SIZE USB_CDC_NCM_NTB_MIN_IN_SIZE
+#define NTB_OUT_SIZE 16384
+
+/*
+ * skbs of size less than that will not be alligned
+ * to NCM's dwNtbInMaxSize to save bus bandwidth
+ */
+
+#define MAX_TX_NONFIXED (512 * 3)
+
+#define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \
+ USB_CDC_NCM_NTB32_SUPPORTED)
+
+static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
+ .wLength = sizeof ntb_parameters,
+ .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
+ .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
+ .wNdpInDivisor = cpu_to_le16(4),
+ .wNdpInPayloadRemainder = cpu_to_le16(0),
+ .wNdpInAlignment = cpu_to_le16(4),
+
+ .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+ .wNdpOutDivisor = cpu_to_le16(4),
+ .wNdpOutPayloadRemainder = cpu_to_le16(0),
+ .wNdpOutAlignment = cpu_to_le16(4),
+};
+
+/*
+ * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
+ * waste less bandwidth.
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
+#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
+
+static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
+ .bLength = sizeof ncm_iad_desc,
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+
+ /* .bFirstInterface = DYNAMIC, */
+ .bInterfaceCount = 2, /* control + data */
+ .bFunctionClass = USB_CLASS_COMM,
+ .bFunctionSubClass = USB_CDC_SUBCLASS_NCM,
+ .bFunctionProtocol = USB_CDC_PROTO_NONE,
+ /* .iFunction = DYNAMIC */
+};
+
+/* interface descriptor: */
+
+static struct usb_interface_descriptor ncm_control_intf __initdata = {
+ .bLength = sizeof ncm_control_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc ncm_header_desc __initdata = {
+ .bLength = sizeof ncm_header_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+
+ .bcdCDC = cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_union_desc ncm_union_desc __initdata = {
+ .bLength = sizeof(ncm_union_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
+ /* .bMasterInterface0 = DYNAMIC */
+ /* .bSlaveInterface0 = DYNAMIC */
+};
+
+static struct usb_cdc_ether_desc ecm_desc __initdata = {
+ .bLength = sizeof ecm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
+
+ /* this descriptor actually adds value, surprise! */
+ /* .iMACAddress = DYNAMIC */
+ .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */
+ .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN),
+ .wNumberMCFilters = cpu_to_le16(0),
+ .bNumberPowerFilters = 0,
+};
+
+#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
+
+static struct usb_cdc_ncm_desc ncm_desc __initdata = {
+ .bLength = sizeof ncm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_NCM_TYPE,
+
+ .bcdNcmVersion = cpu_to_le16(0x0100),
+ /* can process SetEthernetPacketFilter */
+ .bmNetworkCapabilities = NCAPS,
+};
+
+/* the default data interface has no endpoints ... */
+
+static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
+ .bLength = sizeof ncm_data_nop_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = USB_CDC_NCM_PROTO_NTB,
+ /* .iInterface = DYNAMIC */
+};
+
+/* ... but the "real" data interface has two bulk endpoints */
+
+static struct usb_interface_descriptor ncm_data_intf __initdata = {
+ .bLength = sizeof ncm_data_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = USB_CDC_NCM_PROTO_NTB,
+ /* .iInterface = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
+ (struct usb_descriptor_header *) &ncm_iad_desc,
+ /* CDC NCM control descriptors */
+ (struct usb_descriptor_header *) &ncm_control_intf,
+ (struct usb_descriptor_header *) &ncm_header_desc,
+ (struct usb_descriptor_header *) &ncm_union_desc,
+ (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &ncm_desc,
+ (struct usb_descriptor_header *) &fs_ncm_notify_desc,
+ /* data interface, altsettings 0 and 1 */
+ (struct usb_descriptor_header *) &ncm_data_nop_intf,
+ (struct usb_descriptor_header *) &ncm_data_intf,
+ (struct usb_descriptor_header *) &fs_ncm_in_desc,
+ (struct usb_descriptor_header *) &fs_ncm_out_desc,
+ NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
+ .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
+ (struct usb_descriptor_header *) &ncm_iad_desc,
+ /* CDC NCM control descriptors */
+ (struct usb_descriptor_header *) &ncm_control_intf,
+ (struct usb_descriptor_header *) &ncm_header_desc,
+ (struct usb_descriptor_header *) &ncm_union_desc,
+ (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &ncm_desc,
+ (struct usb_descriptor_header *) &hs_ncm_notify_desc,
+ /* data interface, altsettings 0 and 1 */
+ (struct usb_descriptor_header *) &ncm_data_nop_intf,
+ (struct usb_descriptor_header *) &ncm_data_intf,
+ (struct usb_descriptor_header *) &hs_ncm_in_desc,
+ (struct usb_descriptor_header *) &hs_ncm_out_desc,
+ NULL,
+};
+
+/* string descriptors: */
+
+#define STRING_CTRL_IDX 0
+#define STRING_MAC_IDX 1
+#define STRING_DATA_IDX 2
+#define STRING_IAD_IDX 3
+
+static struct usb_string ncm_string_defs[] = {
+ [STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
+ [STRING_MAC_IDX].s = NULL /* DYNAMIC */,
+ [STRING_DATA_IDX].s = "CDC Network Data",
+ [STRING_IAD_IDX].s = "CDC NCM",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings ncm_string_table = {
+ .language = 0x0409, /* en-us */
+ .strings = ncm_string_defs,
+};
+
+static struct usb_gadget_strings *ncm_strings[] = {
+ &ncm_string_table,
+ NULL,
+};
+
+/*
+ * Here are options for NCM Datagram Pointer table (NDP) parser.
+ * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
+ * in NDP16 offsets and sizes fields are 1 16bit word wide,
+ * in NDP32 -- 2 16bit words wide. Also signatures are different.
+ * To make the parser code the same, put the differences in the structure,
+ * and switch pointers to the structures when the format is changed.
+ */
+
+struct ndp_parser_opts {
+ u32 nth_sign;
+ u32 ndp_sign;
+ unsigned nth_size;
+ unsigned ndp_size;
+ unsigned ndplen_align;
+ /* sizes in u16 units */
+ unsigned dgram_item_len; /* index or length */
+ unsigned block_length;
+ unsigned fp_index;
+ unsigned reserved1;
+ unsigned reserved2;
+ unsigned next_fp_index;
+};
+
+#define INIT_NDP16_OPTS { \
+ .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
+ .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
+ .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
+ .ndplen_align = 4, \
+ .dgram_item_len = 1, \
+ .block_length = 1, \
+ .fp_index = 1, \
+ .reserved1 = 0, \
+ .reserved2 = 0, \
+ .next_fp_index = 1, \
+ }
+
+
+#define INIT_NDP32_OPTS { \
+ .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
+ .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
+ .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
+ .ndplen_align = 8, \
+ .dgram_item_len = 2, \
+ .block_length = 2, \
+ .fp_index = 2, \
+ .reserved1 = 1, \
+ .reserved2 = 2, \
+ .next_fp_index = 2, \
+ }
+
+static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
+static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+
+static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
+{
+ switch (size) {
+ case 1:
+ put_unaligned_le16((u16)val, *p);
+ break;
+ case 2:
+ put_unaligned_le32((u32)val, *p);
+
+ break;
+ default:
+ BUG();
+ }
+
+ *p += size;
+}
+
+static inline unsigned get_ncm(__le16 **p, unsigned size)
+{
+ unsigned tmp;
+
+ switch (size) {
+ case 1:
+ tmp = get_unaligned_le16(*p);
+ break;
+ case 2:
+ tmp = get_unaligned_le32(*p);
+ break;
+ default:
+ BUG();
+ }
+
+ *p += size;
+ return tmp;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void ncm_reset_values(struct f_ncm *ncm)
+{
+ ncm->parser_opts = &ndp16_opts;
+ ncm->is_crc = false;
+ ncm->port.cdc_filter = DEFAULT_FILTER;
+
+ /* doesn't make sense for ncm, fixed size used */
+ ncm->port.header_len = 0;
+
+ ncm->port.fixed_out_len = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+ ncm->port.fixed_in_len = NTB_DEFAULT_IN_SIZE;
+}
+
+/*
+ * Context: ncm->lock held
+ */
+static void ncm_do_notify(struct f_ncm *ncm)
+{
+ struct usb_request *req = ncm->notify_req;
+ struct usb_cdc_notification *event;
+ struct usb_composite_dev *cdev = ncm->port.func.config->cdev;
+ __le32 *data;
+ int status;
+
+ /* notification already in flight? */
+ if (!req)
+ return;
+
+ event = req->buf;
+ switch (ncm->notify_state) {
+ case NCM_NOTIFY_NONE:
+ return;
+
+ case NCM_NOTIFY_CONNECT:
+ event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+ if (ncm->is_open)
+ event->wValue = cpu_to_le16(1);
+ else
+ event->wValue = cpu_to_le16(0);
+ event->wLength = 0;
+ req->length = sizeof *event;
+
+ DBG(cdev, "notify connect %s\n",
+ ncm->is_open ? "true" : "false");
+ ncm->notify_state = NCM_NOTIFY_NONE;
+ break;
+
+ case NCM_NOTIFY_SPEED:
+ event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+ event->wValue = cpu_to_le16(0);
+ event->wLength = cpu_to_le16(8);
+ req->length = NCM_STATUS_BYTECOUNT;
+
+ /* SPEED_CHANGE data is up/down speeds in bits/sec */
+ data = req->buf + sizeof *event;
+ data[0] = cpu_to_le32(ncm_bitrate(cdev->gadget));
+ data[1] = data[0];
+
+ DBG(cdev, "notify speed %d\n", ncm_bitrate(cdev->gadget));
+ ncm->notify_state = NCM_NOTIFY_CONNECT;
+ break;
+ }
+ event->bmRequestType = 0xA1;
+ event->wIndex = cpu_to_le16(ncm->ctrl_id);
+
+ ncm->notify_req = NULL;
+ /*
+ * In double buffering if there is a space in FIFO,
+ * completion callback can be called right after the call,
+ * so unlocking
+ */
+ spin_unlock(&ncm->lock);
+ status = usb_ep_queue(ncm->notify, req, GFP_ATOMIC);
+ spin_lock(&ncm->lock);
+ if (status < 0) {
+ ncm->notify_req = req;
+ DBG(cdev, "notify --> %d\n", status);
+ }
+}
+
+/*
+ * Context: ncm->lock held
+ */
+static void ncm_notify(struct f_ncm *ncm)
+{
+ /*
+ * NOTE on most versions of Linux, host side cdc-ethernet
+ * won't listen for notifications until its netdevice opens.
+ * The first notification then sits in the FIFO for a long
+ * time, and the second one is queued.
+ *
+ * If ncm_notify() is called before the second (CONNECT)
+ * notification is sent, then it will reset to send the SPEED
+ * notificaion again (and again, and again), but it's not a problem
+ */
+ ncm->notify_state = NCM_NOTIFY_SPEED;
+ ncm_do_notify(ncm);
+}
+
+static void ncm_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_ncm *ncm = req->context;
+ struct usb_composite_dev *cdev = ncm->port.func.config->cdev;
+ struct usb_cdc_notification *event = req->buf;
+
+ spin_lock(&ncm->lock);
+ switch (req->status) {
+ case 0:
+ VDBG(cdev, "Notification %02x sent\n",
+ event->bNotificationType);
+ break;
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ ncm->notify_state = NCM_NOTIFY_NONE;
+ break;
+ default:
+ DBG(cdev, "event %02x --> %d\n",
+ event->bNotificationType, req->status);
+ break;
+ }
+ ncm->notify_req = req;
+ ncm_do_notify(ncm);
+ spin_unlock(&ncm->lock);
+}
+
+static void ncm_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ /* now for SET_NTB_INPUT_SIZE only */
+ unsigned in_size;
+ struct usb_function *f = req->context;
+ struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = ep->driver_data;
+
+ req->context = NULL;
+ if (req->status || req->actual != req->length) {
+ DBG(cdev, "Bad control-OUT transfer\n");
+ goto invalid;
+ }
+
+ in_size = get_unaligned_le32(req->buf);
+ if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
+ in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ DBG(cdev, "Got wrong INPUT SIZE (%d) from host\n", in_size);
+ goto invalid;
+ }
+
+ ncm->port.fixed_in_len = in_size;
+ VDBG(cdev, "Set NTB INPUT SIZE %d\n", in_size);
+ return;
+
+invalid:
+ usb_ep_set_halt(ep);
+ return;
+}
+
+static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ 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);
+
+ /*
+ * composite driver infrastructure handles everything except
+ * CDC class messages; interface activation uses set_alt().
+ */
+ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_ETHERNET_PACKET_FILTER:
+ /*
+ * see 6.2.30: no data, wIndex = interface,
+ * wValue = packet filter bitmap
+ */
+ if (w_length != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ DBG(cdev, "packet filter %02x\n", w_value);
+ /*
+ * REVISIT locking of cdc_filter. This assumes the UDC
+ * driver won't have a concurrent packet TX irq running on
+ * another CPU; or that if it does, this write is atomic...
+ */
+ ncm->port.cdc_filter = w_value;
+ value = 0;
+ break;
+ /*
+ * and optionally:
+ * case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+ * case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+ * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+ * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+ * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+ * case USB_CDC_GET_ETHERNET_STATISTIC:
+ */
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_PARAMETERS:
+
+ if (w_length == 0 || w_value != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ value = w_length > sizeof ntb_parameters ?
+ sizeof ntb_parameters : w_length;
+ memcpy(req->buf, &ntb_parameters, value);
+ VDBG(cdev, "Host asked NTB parameters\n");
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_INPUT_SIZE:
+
+ if (w_length < 4 || w_value != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ put_unaligned_le32(ncm->port.fixed_in_len, req->buf);
+ value = 4;
+ VDBG(cdev, "Host asked INPUT SIZE, sending %d\n",
+ ncm->port.fixed_in_len);
+ break;
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_NTB_INPUT_SIZE:
+ {
+ if (w_length != 4 || w_value != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ req->complete = ncm_ep0out_complete;
+ req->length = w_length;
+ req->context = f;
+
+ value = req->length;
+ break;
+ }
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_FORMAT:
+ {
+ uint16_t format;
+
+ if (w_length < 2 || w_value != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ format = (ncm->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+ put_unaligned_le16(format, req->buf);
+ value = 2;
+ VDBG(cdev, "Host asked NTB FORMAT, sending %d\n", format);
+ break;
+ }
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_NTB_FORMAT:
+ {
+ if (w_length != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ switch (w_value) {
+ case 0x0000:
+ ncm->parser_opts = &ndp16_opts;
+ DBG(cdev, "NCM16 selected\n");
+ break;
+ case 0x0001:
+ ncm->parser_opts = &ndp32_opts;
+ DBG(cdev, "NCM32 selected\n");
+ break;
+ default:
+ goto invalid;
+ }
+ value = 0;
+ break;
+ }
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_CRC_MODE:
+ {
+ uint16_t is_crc;
+
+ if (w_length < 2 || w_value != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ is_crc = ncm->is_crc ? 0x0001 : 0x0000;
+ put_unaligned_le16(is_crc, req->buf);
+ value = 2;
+ VDBG(cdev, "Host asked CRC MODE, sending %d\n", is_crc);
+ break;
+ }
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_CRC_MODE:
+ {
+ int ndp_hdr_crc = 0;
+
+ if (w_length != 0 || w_index != ncm->ctrl_id)
+ goto invalid;
+ switch (w_value) {
+ case 0x0000:
+ ncm->is_crc = false;
+ ndp_hdr_crc = NCM_NDP_HDR_NOCRC;
+ DBG(cdev, "non-CRC mode selected\n");
+ break;
+ case 0x0001:
+ ncm->is_crc = true;
+ ndp_hdr_crc = NCM_NDP_HDR_CRC;
+ DBG(cdev, "CRC mode selected\n");
+ break;
+ default:
+ goto invalid;
+ }
+ ncm->parser_opts->ndp_sign &= ~NCM_NDP_HDR_CRC_MASK;
+ ncm->parser_opts->ndp_sign |= ndp_hdr_crc;
+ value = 0;
+ break;
+ }
+
+ /* and disabled in ncm descriptor: */
+ /* case USB_CDC_GET_NET_ADDRESS: */
+ /* case USB_CDC_SET_NET_ADDRESS: */
+ /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
+ /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
+
+ default:
+invalid:
+ DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ DBG(cdev, "ncm req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = value;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0)
+ ERROR(cdev, "ncm req %02x.%02x response err %d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ value);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+
+static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ /* Control interface has only altsetting 0 */
+ if (intf == ncm->ctrl_id) {
+ if (alt != 0)
+ goto fail;
+
+ if (ncm->notify->driver_data) {
+ DBG(cdev, "reset ncm control %d\n", intf);
+ usb_ep_disable(ncm->notify);
+ } else {
+ DBG(cdev, "init ncm ctrl %d\n", intf);
+ ncm->notify_desc = ep_choose(cdev->gadget,
+ ncm->hs.notify,
+ ncm->fs.notify);
+ }
+ usb_ep_enable(ncm->notify, ncm->notify_desc);
+ ncm->notify->driver_data = ncm;
+
+ /* Data interface has two altsettings, 0 and 1 */
+ } else if (intf == ncm->data_id) {
+ if (alt > 1)
+ goto fail;
+
+ if (ncm->port.in_ep->driver_data) {
+ DBG(cdev, "reset ncm\n");
+ gether_disconnect(&ncm->port);
+ ncm_reset_values(ncm);
+ }
+
+ /*
+ * CDC Network only sends data in non-default altsettings.
+ * Changing altsettings resets filters, statistics, etc.
+ */
+ if (alt == 1) {
+ struct net_device *net;
+
+ if (!ncm->port.in) {
+ DBG(cdev, "init ncm\n");
+ ncm->port.in = ep_choose(cdev->gadget,
+ ncm->hs.in,
+ ncm->fs.in);
+ ncm->port.out = ep_choose(cdev->gadget,
+ ncm->hs.out,
+ ncm->fs.out);
+ }
+
+ /* TODO */
+ /* Enable zlps by default for NCM conformance;
+ * override for musb_hdrc (avoids txdma ovhead)
+ */
+ ncm->port.is_zlp_ok = !(
+ gadget_is_musbhdrc(cdev->gadget)
+ );
+ ncm->port.cdc_filter = DEFAULT_FILTER;
+ DBG(cdev, "activate ncm\n");
+ net = gether_connect(&ncm->port);
+ if (IS_ERR(net))
+ return PTR_ERR(net);
+ }
+
+ spin_lock(&ncm->lock);
+ ncm_notify(ncm);
+ spin_unlock(&ncm->lock);
+ } else
+ goto fail;
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+/*
+ * Because the data interface supports multiple altsettings,
+ * this NCM function *MUST* implement a get_alt() method.
+ */
+static int ncm_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_ncm *ncm = func_to_ncm(f);
+
+ if (intf == ncm->ctrl_id)
+ return 0;
+ return ncm->port.in_ep->driver_data ? 1 : 0;
+}
+
+static struct sk_buff *ncm_wrap_ntb(struct gether *port,
+ struct sk_buff *skb)
+{
+ struct f_ncm *ncm = func_to_ncm(&port->func);
+ struct sk_buff *skb2;
+ int ncb_len = 0;
+ __le16 *tmp;
+ int div = ntb_parameters.wNdpInDivisor;
+ int rem = ntb_parameters.wNdpInPayloadRemainder;
+ int pad;
+ int ndp_align = ntb_parameters.wNdpInAlignment;
+ int ndp_pad;
+ unsigned max_size = ncm->port.fixed_in_len;
+ struct ndp_parser_opts *opts = ncm->parser_opts;
+ unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
+
+ ncb_len += opts->nth_size;
+ ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len;
+ ncb_len += ndp_pad;
+ ncb_len += opts->ndp_size;
+ ncb_len += 2 * 2 * opts->dgram_item_len; /* Datagram entry */
+ ncb_len += 2 * 2 * opts->dgram_item_len; /* Zero datagram entry */
+ pad = ALIGN(ncb_len, div) + rem - ncb_len;
+ ncb_len += pad;
+
+ if (ncb_len + skb->len + crc_len > max_size) {
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
+
+ skb2 = skb_copy_expand(skb, ncb_len,
+ max_size - skb->len - ncb_len - crc_len,
+ GFP_ATOMIC);
+ dev_kfree_skb_any(skb);
+ if (!skb2)
+ return NULL;
+
+ skb = skb2;
+
+ tmp = (void *) skb_push(skb, ncb_len);
+ memset(tmp, 0, ncb_len);
+
+ put_unaligned_le32(opts->nth_sign, tmp); /* dwSignature */
+ tmp += 2;
+ /* wHeaderLength */
+ put_unaligned_le16(opts->nth_size, tmp++);
+ tmp++; /* skip wSequence */
+ put_ncm(&tmp, opts->block_length, skb->len); /* (d)wBlockLength */
+ /* (d)wFpIndex */
+ /* the first pointer is right after the NTH + align */
+ put_ncm(&tmp, opts->fp_index, opts->nth_size + ndp_pad);
+
+ tmp = (void *)tmp + ndp_pad;
+
+ /* NDP */
+ put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */
+ tmp += 2;
+ /* wLength */
+ put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++);
+
+ tmp += opts->reserved1;
+ tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */
+ tmp += opts->reserved2;
+
+ if (ncm->is_crc) {
+ uint32_t crc;
+
+ crc = ~crc32_le(~0,
+ skb->data + ncb_len,
+ skb->len - ncb_len);
+ put_unaligned_le32(crc, skb->data + skb->len);
+ skb_put(skb, crc_len);
+ }
+
+ /* (d)wDatagramIndex[0] */
+ put_ncm(&tmp, opts->dgram_item_len, ncb_len);
+ /* (d)wDatagramLength[0] */
+ put_ncm(&tmp, opts->dgram_item_len, skb->len - ncb_len);
+ /* (d)wDatagramIndex[1] and (d)wDatagramLength[1] already zeroed */
+
+ if (skb->len > MAX_TX_NONFIXED)
+ memset(skb_put(skb, max_size - skb->len),
+ 0, max_size - skb->len);
+
+ return skb;
+}
+
+static int ncm_unwrap_ntb(struct gether *port,
+ struct sk_buff *skb,
+ struct sk_buff_head *list)
+{
+ struct f_ncm *ncm = func_to_ncm(&port->func);
+ __le16 *tmp = (void *) skb->data;
+ unsigned index, index2;
+ unsigned dg_len, dg_len2;
+ unsigned ndp_len;
+ struct sk_buff *skb2;
+ int ret = -EINVAL;
+ unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+ struct ndp_parser_opts *opts = ncm->parser_opts;
+ unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
+ int dgram_counter;
+
+ /* dwSignature */
+ if (get_unaligned_le32(tmp) != opts->nth_sign) {
+ INFO(port->func.config->cdev, "Wrong NTH SIGN, skblen %d\n",
+ skb->len);
+ print_hex_dump(KERN_INFO, "HEAD:", DUMP_PREFIX_ADDRESS, 32, 1,
+ skb->data, 32, false);
+
+ goto err;
+ }
+ tmp += 2;
+ /* wHeaderLength */
+ if (get_unaligned_le16(tmp++) != opts->nth_size) {
+ INFO(port->func.config->cdev, "Wrong NTB headersize\n");
+ goto err;
+ }
+ tmp++; /* skip wSequence */
+
+ /* (d)wBlockLength */
+ if (get_ncm(&tmp, opts->block_length) > max_size) {
+ INFO(port->func.config->cdev, "OUT size exceeded\n");
+ goto err;
+ }
+
+ index = get_ncm(&tmp, opts->fp_index);
+ /* NCM 3.2 */
+ if (((index % 4) != 0) && (index < opts->nth_size)) {
+ INFO(port->func.config->cdev, "Bad index: %x\n",
+ index);
+ goto err;
+ }
+
+ /* walk through NDP */
+ tmp = ((void *)skb->data) + index;
+ if (get_unaligned_le32(tmp) != opts->ndp_sign) {
+ INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
+ goto err;
+ }
+ tmp += 2;
+
+ ndp_len = get_unaligned_le16(tmp++);
+ /*
+ * NCM 3.3.1
+ * entry is 2 items
+ * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
+ * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
+ */
+ if ((ndp_len < opts->ndp_size + 2 * 2 * (opts->dgram_item_len * 2))
+ || (ndp_len % opts->ndplen_align != 0)) {
+ INFO(port->func.config->cdev, "Bad NDP length: %x\n", ndp_len);
+ goto err;
+ }
+ tmp += opts->reserved1;
+ tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */
+ tmp += opts->reserved2;
+
+ ndp_len -= opts->ndp_size;
+ index2 = get_ncm(&tmp, opts->dgram_item_len);
+ dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
+ dgram_counter = 0;
+
+ do {
+ index = index2;
+ dg_len = dg_len2;
+ if (dg_len < 14 + crc_len) { /* ethernet header + crc */
+ INFO(port->func.config->cdev, "Bad dgram length: %x\n",
+ dg_len);
+ goto err;
+ }
+ if (ncm->is_crc) {
+ uint32_t crc, crc2;
+
+ crc = get_unaligned_le32(skb->data +
+ index + dg_len - crc_len);
+ crc2 = ~crc32_le(~0,
+ skb->data + index,
+ dg_len - crc_len);
+ if (crc != crc2) {
+ INFO(port->func.config->cdev, "Bad CRC\n");
+ goto err;
+ }
+ }
+
+ index2 = get_ncm(&tmp, opts->dgram_item_len);
+ dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
+
+ if (index2 == 0 || dg_len2 == 0) {
+ skb2 = skb;
+ } else {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ goto err;
+ }
+
+ if (!skb_pull(skb2, index)) {
+ ret = -EOVERFLOW;
+ goto err;
+ }
+
+ skb_trim(skb2, dg_len - crc_len);
+ skb_queue_tail(list, skb2);
+
+ ndp_len -= 2 * (opts->dgram_item_len * 2);
+
+ dgram_counter++;
+
+ if (index2 == 0 || dg_len2 == 0)
+ break;
+ } while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */
+
+ VDBG(port->func.config->cdev,
+ "Parsed NTB with %d frames\n", dgram_counter);
+ return 0;
+err:
+ skb_queue_purge(list);
+ dev_kfree_skb_any(skb);
+ return ret;
+}
+
+static void ncm_disable(struct usb_function *f)
+{
+ struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ DBG(cdev, "ncm deactivated\n");
+
+ if (ncm->port.in_ep->driver_data)
+ gether_disconnect(&ncm->port);
+
+ if (ncm->notify->driver_data) {
+ usb_ep_disable(ncm->notify);
+ ncm->notify->driver_data = NULL;
+ ncm->notify_desc = NULL;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Callbacks let us notify the host about connect/disconnect when the
+ * net device is opened or closed.
+ *
+ * For testing, note that link states on this side include both opened
+ * and closed variants of:
+ *
+ * - disconnected/unconfigured
+ * - configured but inactive (data alt 0)
+ * - configured and active (data alt 1)
+ *
+ * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and
+ * SET_INTERFACE (altsetting). Remember also that "configured" doesn't
+ * imply the host is actually polling the notification endpoint, and
+ * likewise that "active" doesn't imply it's actually using the data
+ * endpoints for traffic.
+ */
+
+static void ncm_open(struct gether *geth)
+{
+ struct f_ncm *ncm = func_to_ncm(&geth->func);
+
+ DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+
+ spin_lock(&ncm->lock);
+ ncm->is_open = true;
+ ncm_notify(ncm);
+ spin_unlock(&ncm->lock);
+}
+
+static void ncm_close(struct gether *geth)
+{
+ struct f_ncm *ncm = func_to_ncm(&geth->func);
+
+ DBG(ncm->port.func.config->cdev, "%s\n", __func__);
+
+ spin_lock(&ncm->lock);
+ ncm->is_open = false;
+ ncm_notify(ncm);
+ spin_unlock(&ncm->lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethernet function driver setup/binding */
+
+static int __init
+ncm_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_ncm *ncm = func_to_ncm(f);
+ int status;
+ struct usb_ep *ep;
+
+ /* allocate instance-specific interface IDs */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ ncm->ctrl_id = status;
+ ncm_iad_desc.bFirstInterface = status;
+
+ ncm_control_intf.bInterfaceNumber = status;
+ ncm_union_desc.bMasterInterface0 = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ ncm->data_id = status;
+
+ ncm_data_nop_intf.bInterfaceNumber = status;
+ ncm_data_intf.bInterfaceNumber = status;
+ ncm_union_desc.bSlaveInterface0 = status;
+
+ status = -ENODEV;
+
+ /* allocate instance-specific endpoints */
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc);
+ if (!ep)
+ goto fail;
+ ncm->port.in_ep = ep;
+ ep->driver_data = cdev; /* claim */
+
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc);
+ if (!ep)
+ goto fail;
+ ncm->port.out_ep = ep;
+ ep->driver_data = cdev; /* claim */
+
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc);
+ if (!ep)
+ goto fail;
+ ncm->notify = ep;
+ ep->driver_data = cdev; /* claim */
+
+ status = -ENOMEM;
+
+ /* allocate notification request and buffer */
+ ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!ncm->notify_req)
+ goto fail;
+ ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
+ if (!ncm->notify_req->buf)
+ goto fail;
+ ncm->notify_req->context = ncm;
+ ncm->notify_req->complete = ncm_notify_complete;
+
+ /* copy descriptors, and track endpoint copies */
+ f->descriptors = usb_copy_descriptors(ncm_fs_function);
+ if (!f->descriptors)
+ goto fail;
+
+ ncm->fs.in = usb_find_endpoint(ncm_fs_function,
+ f->descriptors, &fs_ncm_in_desc);
+ ncm->fs.out = usb_find_endpoint(ncm_fs_function,
+ f->descriptors, &fs_ncm_out_desc);
+ ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
+ f->descriptors, &fs_ncm_notify_desc);
+
+ /*
+ * support all relevant hardware speeds... we expect that when
+ * hardware is dual speed, all bulk-capable endpoints work at
+ * both speeds
+ */
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ hs_ncm_in_desc.bEndpointAddress =
+ fs_ncm_in_desc.bEndpointAddress;
+ hs_ncm_out_desc.bEndpointAddress =
+ fs_ncm_out_desc.bEndpointAddress;
+ hs_ncm_notify_desc.bEndpointAddress =
+ fs_ncm_notify_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
+ if (!f->hs_descriptors)
+ goto fail;
+
+ ncm->hs.in = usb_find_endpoint(ncm_hs_function,
+ f->hs_descriptors, &hs_ncm_in_desc);
+ ncm->hs.out = usb_find_endpoint(ncm_hs_function,
+ f->hs_descriptors, &hs_ncm_out_desc);
+ ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
+ f->hs_descriptors, &hs_ncm_notify_desc);
+ }
+
+ /*
+ * NOTE: all that is done without knowing or caring about
+ * the network link ... which is unavailable to this code
+ * until we're activated via set_alt().
+ */
+
+ ncm->port.open = ncm_open;
+ ncm->port.close = ncm_close;
+
+ DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+ ncm->port.in_ep->name, ncm->port.out_ep->name,
+ ncm->notify->name);
+ return 0;
+
+fail:
+ if (f->descriptors)
+ usb_free_descriptors(f->descriptors);
+
+ if (ncm->notify_req) {
+ kfree(ncm->notify_req->buf);
+ usb_ep_free_request(ncm->notify, ncm->notify_req);
+ }
+
+ /* we might as well release our claims on endpoints */
+ if (ncm->notify)
+ ncm->notify->driver_data = NULL;
+ if (ncm->port.out)
+ ncm->port.out_ep->driver_data = NULL;
+ if (ncm->port.in)
+ ncm->port.in_ep->driver_data = NULL;
+
+ ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+
+ return status;
+}
+
+static void
+ncm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_ncm *ncm = func_to_ncm(f);
+
+ DBG(c->cdev, "ncm unbind\n");
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+
+ kfree(ncm->notify_req->buf);
+ usb_ep_free_request(ncm->notify, ncm->notify_req);
+
+ ncm_string_defs[1].s = NULL;
+ kfree(ncm);
+}
+
+/**
+ * ncm_bind_config - add CDC Network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ * side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup(). Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+{
+ struct f_ncm *ncm;
+ int status;
+
+ if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
+ return -EINVAL;
+
+ /* maybe allocate device-global string IDs */
+ if (ncm_string_defs[0].id == 0) {
+
+ /* control interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ncm_string_defs[STRING_CTRL_IDX].id = status;
+ ncm_control_intf.iInterface = status;
+
+ /* data interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ncm_string_defs[STRING_DATA_IDX].id = status;
+ ncm_data_nop_intf.iInterface = status;
+ ncm_data_intf.iInterface = status;
+
+ /* MAC address */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ncm_string_defs[STRING_MAC_IDX].id = status;
+ ecm_desc.iMACAddress = status;
+
+ /* IAD */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ncm_string_defs[STRING_IAD_IDX].id = status;
+ ncm_iad_desc.iFunction = status;
+ }
+
+ /* allocate and initialize one new instance */
+ ncm = kzalloc(sizeof *ncm, GFP_KERNEL);
+ if (!ncm)
+ return -ENOMEM;
+
+ /* export host's Ethernet address in CDC format */
+ snprintf(ncm->ethaddr, sizeof ncm->ethaddr,
+ "%02X%02X%02X%02X%02X%02X",
+ ethaddr[0], ethaddr[1], ethaddr[2],
+ ethaddr[3], ethaddr[4], ethaddr[5]);
+ ncm_string_defs[1].s = ncm->ethaddr;
+
+ spin_lock_init(&ncm->lock);
+ ncm_reset_values(ncm);
+ ncm->port.is_fixed = true;
+
+ ncm->port.func.name = "cdc_network";
+ ncm->port.func.strings = ncm_strings;
+ /* descriptors are per-instance copies */
+ ncm->port.func.bind = ncm_bind;
+ ncm->port.func.unbind = ncm_unbind;
+ ncm->port.func.set_alt = ncm_set_alt;
+ ncm->port.func.get_alt = ncm_get_alt;
+ ncm->port.func.setup = ncm_setup;
+ ncm->port.func.disable = ncm_disable;
+
+ ncm->port.wrap = ncm_wrap_ntb;
+ ncm->port.unwrap = ncm_unwrap_ntb;
+
+ status = usb_add_function(c, &ncm->port.func);
+ if (status) {
+ ncm_string_defs[1].s = NULL;
+ kfree(ncm);
+ }
+ return status;
+}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index d4fdf65fb925..a6eacb59571b 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -3392,25 +3392,28 @@ static int __init fsg_bind(struct usb_gadget *gadget)
dev_set_name(&curlun->dev,"%s-lun%d",
dev_name(&gadget->dev), i);
- if ((rc = device_register(&curlun->dev)) != 0) {
+ kref_get(&fsg->ref);
+ rc = device_register(&curlun->dev);
+ if (rc) {
INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
- goto out;
- }
- if ((rc = device_create_file(&curlun->dev,
- &dev_attr_ro)) != 0 ||
- (rc = device_create_file(&curlun->dev,
- &dev_attr_nofua)) != 0 ||
- (rc = device_create_file(&curlun->dev,
- &dev_attr_file)) != 0) {
- device_unregister(&curlun->dev);
+ put_device(&curlun->dev);
goto out;
}
curlun->registered = 1;
- kref_get(&fsg->ref);
+
+ rc = device_create_file(&curlun->dev, &dev_attr_ro);
+ if (rc)
+ goto out;
+ rc = device_create_file(&curlun->dev, &dev_attr_nofua);
+ if (rc)
+ goto out;
+ rc = device_create_file(&curlun->dev, &dev_attr_file);
+ if (rc)
+ goto out;
if (mod_data.file[i] && *mod_data.file[i]) {
- if ((rc = fsg_lun_open(curlun,
- mod_data.file[i])) != 0)
+ rc = fsg_lun_open(curlun, mod_data.file[i]);
+ if (rc)
goto out;
} else if (!mod_data.removable) {
ERROR(fsg, "no file given for LUN%d\n", i);
diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c
index 5bdbfe619853..77b1eb577029 100644
--- a/drivers/usb/gadget/fsl_mxc_udc.c
+++ b/drivers/usb/gadget/fsl_mxc_udc.c
@@ -93,9 +93,9 @@ void fsl_udc_clk_finalize(struct platform_device *pdev)
/* workaround ENGcm09152 for i.MX35 */
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
- v = readl(MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR +
+ v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
- writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR +
+ writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET));
}
#endif
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index af75e3620849..ebf6970a10bf 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -1,7 +1,29 @@
+/*
+ * g_ffs.c -- user mode file system API for USB composite function controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) "g_ffs: " fmt
+
#include <linux/module.h>
#include <linux/utsname.h>
-
/*
* kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
@@ -43,7 +65,6 @@ static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
#include "f_fs.c"
-
#define DRIVER_NAME "g_ffs"
#define DRIVER_DESC "USB Function Filesystem"
#define DRIVER_VERSION "24 Aug 2004"
@@ -73,8 +94,6 @@ MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
-
-
static const struct usb_descriptor_header *gfs_otg_desc[] = {
(const struct usb_descriptor_header *)
&(const struct usb_otg_descriptor) {
@@ -91,8 +110,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
NULL
};
-/* string IDs are assigned dynamically */
-
+/* String IDs are assigned dynamically */
static struct usb_string gfs_strings[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{ .s = "FunctionFS + RNDIS" },
@@ -114,8 +132,6 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
NULL,
};
-
-
struct gfs_configuration {
struct usb_configuration c;
int (*eth)(struct usb_configuration *c, u8 *ethaddr);
@@ -138,7 +154,6 @@ struct gfs_configuration {
#endif
};
-
static int gfs_bind(struct usb_composite_dev *cdev);
static int gfs_unbind(struct usb_composite_dev *cdev);
static int gfs_do_config(struct usb_configuration *c);
@@ -151,11 +166,9 @@ static struct usb_composite_driver gfs_driver = {
.iProduct = DRIVER_DESC,
};
-
static struct ffs_data *gfs_ffs_data;
static unsigned long gfs_registered;
-
static int gfs_init(void)
{
ENTER();
@@ -175,7 +188,6 @@ static void gfs_exit(void)
}
module_exit(gfs_exit);
-
static int functionfs_ready_callback(struct ffs_data *ffs)
{
int ret;
@@ -200,14 +212,11 @@ static void functionfs_closed_callback(struct ffs_data *ffs)
usb_composite_unregister(&gfs_driver);
}
-
static int functionfs_check_dev_callback(const char *dev_name)
{
return 0;
}
-
-
static int gfs_bind(struct usb_composite_dev *cdev)
{
int ret, i;
@@ -274,7 +283,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
return 0;
}
-
static int gfs_do_config(struct usb_configuration *c)
{
struct gfs_configuration *gc =
@@ -315,7 +323,6 @@ static int gfs_do_config(struct usb_configuration *c)
return 0;
}
-
#ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e511fec9f26d..5c2720d64ffa 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -96,7 +96,7 @@
/* Mentor high speed "dual role" controller, in peripheral role */
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
+#define gadget_is_musbhdrc(g) !strcmp("musb-hdrc", (g)->name)
#else
#define gadget_is_musbhdrc(g) 0
#endif
@@ -120,10 +120,10 @@
#define gadget_is_fsl_qe(g) 0
#endif
-#ifdef CONFIG_USB_GADGET_CI13XXX
-#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
+#ifdef CONFIG_USB_GADGET_CI13XXX_PCI
+#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
#else
-#define gadget_is_ci13xxx(g) 0
+#define gadget_is_ci13xxx_pci(g) 0
#endif
// CONFIG_USB_GADGET_SX2
@@ -142,6 +142,17 @@
#define gadget_is_s3c_hsotg(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_EG20T
+#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
+#else
+#define gadget_is_pch(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_CI13XXX_MSM
+#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
+#else
+#define gadget_is_ci13xxx_msm(g) 0
+#endif
/**
* usb_gadget_controller_number - support bcdDevice id convention
@@ -192,7 +203,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x21;
else if (gadget_is_fsl_qe(gadget))
return 0x22;
- else if (gadget_is_ci13xxx(gadget))
+ else if (gadget_is_ci13xxx_pci(gadget))
return 0x23;
else if (gadget_is_langwell(gadget))
return 0x24;
@@ -200,6 +211,10 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x25;
else if (gadget_is_s3c_hsotg(gadget))
return 0x26;
+ else if (gadget_is_pch(gadget))
+ return 0x27;
+ else if (gadget_is_ci13xxx_msm(gadget))
+ return 0x28;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index 566cb2319056..e7e0c69d3b1f 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -251,7 +251,8 @@ struct goku_udc {
got_region:1,
req_config:1,
configured:1,
- enabled:1;
+ enabled:1,
+ registered:1;
/* pci state used to access those endpoints */
struct pci_dev *pdev;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index ed0266462c57..5408186afc35 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1191,13 +1191,17 @@ static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
return IRQ_HANDLED;
}
+#ifndef MX1_INT_USBD0
+#define MX1_INT_USBD0 MX1_USBD_INT0
+#endif
+
static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
{
struct imx_udc_struct *imx_usb = dev;
- struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - USBD_INT0];
+ struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0];
int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
- dump_ep_intr(__func__, irq - USBD_INT0, intr, imx_usb->dev);
+ dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev);
if (!imx_usb->driver) {
__raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
@@ -1316,7 +1320,7 @@ static struct imx_udc_struct controller = {
};
/*******************************************************************************
- * USB gadged driver functions
+ * USB gadget driver functions
*******************************************************************************
*/
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
index b48ad59603d1..7136c242b4ec 100644
--- a/drivers/usb/gadget/imx_udc.h
+++ b/drivers/usb/gadget/imx_udc.h
@@ -23,9 +23,6 @@
/* Helper macros */
#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
-#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) \
- ? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/
-#define ep_to_irq(ep) (EP_NO((ep)) + USBD_INT0)
#define IMX_USB_NB_EP 6
/* Driver structures */
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index b8ec954c0692..1eca8b47ce3c 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -2225,6 +2225,7 @@ static void handle_setup_packet(struct langwell_udc *dev,
u16 wValue = le16_to_cpu(setup->wValue);
u16 wIndex = le16_to_cpu(setup->wIndex);
u16 wLength = le16_to_cpu(setup->wLength);
+ u32 portsc1;
dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -2313,6 +2314,28 @@ static void handle_setup_packet(struct langwell_udc *dev,
dev->dev_status &= ~(1 << wValue);
}
break;
+ case USB_DEVICE_TEST_MODE:
+ dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n");
+ if ((wIndex & 0xff) ||
+ (dev->gadget.speed != USB_SPEED_HIGH))
+ ep0_stall(dev);
+
+ switch (wIndex >> 8) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ if (prime_status_phase(dev, EP_DIR_IN))
+ ep0_stall(dev);
+ portsc1 = readl(&dev->op_regs->portsc1);
+ portsc1 |= (wIndex & 0xf00) << 8;
+ writel(portsc1, &dev->op_regs->portsc1);
+ goto end;
+ default:
+ rc = -EOPNOTSUPP;
+ }
+ break;
default:
rc = -EOPNOTSUPP;
break;
@@ -3063,7 +3086,7 @@ static void langwell_udc_remove(struct pci_dev *pdev)
kfree(dev->ep);
- /* diable IRQ handler */
+ /* disable IRQ handler */
if (dev->got_irq)
free_irq(pdev->irq, dev);
@@ -3383,7 +3406,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
/* disable interrupt and set controller to stop state */
langwell_udc_stop(dev);
- /* diable IRQ handler */
+ /* disable IRQ handler */
if (dev->got_irq)
free_irq(pdev->irq, dev);
dev->got_irq = 0;
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 0769179dbdb0..01822422c3e8 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -102,7 +102,7 @@ static struct fsg_module_parameters mod_data = {
};
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
-static unsigned long msg_registered = 0;
+static unsigned long msg_registered;
static void msg_cleanup(void);
static int msg_thread_exits(struct fsg_common *common)
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
new file mode 100644
index 000000000000..65f1f7c3bd4e
--- /dev/null
+++ b/drivers/usb/gadget/mv_udc.h
@@ -0,0 +1,294 @@
+
+#ifndef __MV_UDC_H
+#define __MV_UDC_H
+
+#define VUSBHS_MAX_PORTS 8
+
+#define DQH_ALIGNMENT 2048
+#define DTD_ALIGNMENT 64
+#define DMA_BOUNDARY 4096
+
+#define EP_DIR_IN 1
+#define EP_DIR_OUT 0
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define EP0_MAX_PKT_SIZE 64
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+#define CAPLENGTH_MASK (0xff)
+#define DCCPARAMS_DEN_MASK (0x1f)
+
+#define HCSPARAMS_PPC (0x10)
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_MASKS 0x3fff
+
+/* Command Register Bit Masks */
+#define USBCMD_RUN_STOP (0x00000001)
+#define USBCMD_CTRL_RESET (0x00000002)
+#define USBCMD_SETUP_TRIPWIRE_SET (0x00002000)
+#define USBCMD_SETUP_TRIPWIRE_CLEAR (~USBCMD_SETUP_TRIPWIRE_SET)
+
+#define USBCMD_ATDTW_TRIPWIRE_SET (0x00004000)
+#define USBCMD_ATDTW_TRIPWIRE_CLEAR (~USBCMD_ATDTW_TRIPWIRE_SET)
+
+/* bit 15,3,2 are for frame list size */
+#define USBCMD_FRAME_SIZE_1024 (0x00000000) /* 000 */
+#define USBCMD_FRAME_SIZE_512 (0x00000004) /* 001 */
+#define USBCMD_FRAME_SIZE_256 (0x00000008) /* 010 */
+#define USBCMD_FRAME_SIZE_128 (0x0000000C) /* 011 */
+#define USBCMD_FRAME_SIZE_64 (0x00008000) /* 100 */
+#define USBCMD_FRAME_SIZE_32 (0x00008004) /* 101 */
+#define USBCMD_FRAME_SIZE_16 (0x00008008) /* 110 */
+#define USBCMD_FRAME_SIZE_8 (0x0000800C) /* 111 */
+
+#define EPCTRL_TX_ALL_MASK (0xFFFF0000)
+#define EPCTRL_RX_ALL_MASK (0x0000FFFF)
+
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000)
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_EP_STALL (0x00000001)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_CONTROL (0x00000000)
+#define EPCTRL_ISOCHRONOUS (0x00040000)
+#define EPCTRL_BULK (0x00080000)
+#define EPCTRL_INT (0x000C0000)
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_DATA_TOGGLE_INHIBIT (0x00000020)
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+#define EPCOMPLETE_MAX_ENDPOINTS (16)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
+
+#define PORTSCX_W1C_BITS 0x2a
+#define PORTSCX_PORT_RESET 0x00000100
+#define PORTSCX_PORT_POWER 0x00001000
+#define PORTSCX_FORCE_FULL_SPEED_CONNECT 0x01000000
+#define PORTSCX_PAR_XCVR_SELECT 0xC0000000
+#define PORTSCX_PORT_FORCE_RESUME 0x00000040
+#define PORTSCX_PORT_SUSPEND 0x00000080
+#define PORTSCX_PORT_SPEED_FULL 0x00000000
+#define PORTSCX_PORT_SPEED_LOW 0x04000000
+#define PORTSCX_PORT_SPEED_HIGH 0x08000000
+#define PORTSCX_PORT_SPEED_MASK 0x0C000000
+
+/* USB MODE Register Bit Masks */
+#define USBMODE_CTRL_MODE_IDLE 0x00000000
+#define USBMODE_CTRL_MODE_DEVICE 0x00000002
+#define USBMODE_CTRL_MODE_HOST 0x00000003
+#define USBMODE_CTRL_MODE_RSV 0x00000001
+#define USBMODE_SETUP_LOCK_OFF 0x00000008
+#define USBMODE_STREAM_DISABLE 0x00000010
+
+/* USB STS Register Bit Masks */
+#define USBSTS_INT 0x00000001
+#define USBSTS_ERR 0x00000002
+#define USBSTS_PORT_CHANGE 0x00000004
+#define USBSTS_FRM_LST_ROLL 0x00000008
+#define USBSTS_SYS_ERR 0x00000010
+#define USBSTS_IAA 0x00000020
+#define USBSTS_RESET 0x00000040
+#define USBSTS_SOF 0x00000080
+#define USBSTS_SUSPEND 0x00000100
+#define USBSTS_HC_HALTED 0x00001000
+#define USBSTS_RCL 0x00002000
+#define USBSTS_PERIODIC_SCHEDULE 0x00004000
+#define USBSTS_ASYNC_SCHEDULE 0x00008000
+
+
+/* Interrupt Enable Register Bit Masks */
+#define USBINTR_INT_EN (0x00000001)
+#define USBINTR_ERR_INT_EN (0x00000002)
+#define USBINTR_PORT_CHANGE_DETECT_EN (0x00000004)
+
+#define USBINTR_ASYNC_ADV_AAE (0x00000020)
+#define USBINTR_ASYNC_ADV_AAE_ENABLE (0x00000020)
+#define USBINTR_ASYNC_ADV_AAE_DISABLE (0xFFFFFFDF)
+
+#define USBINTR_RESET_EN (0x00000040)
+#define USBINTR_SOF_UFRAME_EN (0x00000080)
+#define USBINTR_DEVICE_SUSPEND (0x00000100)
+
+#define USB_DEVICE_ADDRESS_MASK (0xfe000000)
+#define USB_DEVICE_ADDRESS_BIT_SHIFT (25)
+
+struct mv_cap_regs {
+ u32 caplength_hciversion;
+ u32 hcsparams; /* HC structural parameters */
+ u32 hccparams; /* HC Capability Parameters*/
+ u32 reserved[5];
+ u32 dciversion; /* DC version number and reserved 16 bits */
+ u32 dccparams; /* DC Capability Parameters */
+};
+
+struct mv_op_regs {
+ u32 usbcmd; /* Command register */
+ u32 usbsts; /* Status register */
+ u32 usbintr; /* Interrupt enable */
+ u32 frindex; /* Frame index */
+ u32 reserved1[1];
+ u32 deviceaddr; /* Device Address */
+ u32 eplistaddr; /* Endpoint List Address */
+ u32 ttctrl; /* HOST TT status and control */
+ u32 burstsize; /* Programmable Burst Size */
+ u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */
+ u32 reserved[4];
+ u32 epnak; /* Endpoint NAK */
+ u32 epnaken; /* Endpoint NAK Enable */
+ u32 configflag; /* Configured Flag register */
+ u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */
+ u32 otgsc;
+ u32 usbmode; /* USB Host/Device mode */
+ u32 epsetupstat; /* Endpoint Setup Status */
+ u32 epprime; /* Endpoint Initialize */
+ u32 epflush; /* Endpoint De-initialize */
+ u32 epstatus; /* Endpoint Status */
+ u32 epcomplete; /* Endpoint Interrupt On Complete */
+ u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */
+ u32 mcr; /* Mux Control */
+ u32 isr; /* Interrupt Status */
+ u32 ier; /* Interrupt Enable */
+};
+
+struct mv_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ spinlock_t lock;
+ struct completion *done;
+ struct platform_device *dev;
+ int irq;
+
+ struct mv_cap_regs __iomem *cap_regs;
+ struct mv_op_regs __iomem *op_regs;
+ unsigned int phy_regs;
+ unsigned int max_eps;
+ struct mv_dqh *ep_dqh;
+ size_t ep_dqh_size;
+ dma_addr_t ep_dqh_dma;
+
+ struct dma_pool *dtd_pool;
+ struct mv_ep *eps;
+
+ struct mv_dtd *dtd_head;
+ struct mv_dtd *dtd_tail;
+ unsigned int dtd_entries;
+
+ struct mv_req *status_req;
+ struct usb_ctrlrequest local_setup_buff;
+
+ unsigned int resume_state; /* USB state to resume */
+ unsigned int usb_state; /* USB current state */
+ unsigned int ep0_state; /* Endpoint zero state */
+ unsigned int ep0_dir;
+
+ unsigned int dev_addr;
+
+ int errors;
+ unsigned softconnect:1,
+ vbus_active:1,
+ remote_wakeup:1,
+ softconnected:1,
+ force_fs:1;
+ struct clk *clk;
+};
+
+/* endpoint data structure */
+struct mv_ep {
+ struct usb_ep ep;
+ struct mv_udc *udc;
+ struct list_head queue;
+ struct mv_dqh *dqh;
+ const struct usb_endpoint_descriptor *desc;
+ u32 direction;
+ char name[14];
+ unsigned stopped:1,
+ wedge:1,
+ ep_type:2,
+ ep_num:8;
+};
+
+/* request data structure */
+struct mv_req {
+ struct usb_request req;
+ struct mv_dtd *dtd, *head, *tail;
+ struct mv_ep *ep;
+ struct list_head queue;
+ unsigned dtd_count;
+ unsigned mapped:1;
+};
+
+#define EP_QUEUE_HEAD_MULT_POS 30
+#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
+#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
+#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
+#define EP_QUEUE_HEAD_IOS 0x00008000
+#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
+#define EP_QUEUE_HEAD_IOC 0x00008000
+#define EP_QUEUE_HEAD_MULTO 0x00000C00
+#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
+#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
+#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
+#define EP_QUEUE_FRINDEX_MASK 0x000007FF
+#define EP_MAX_LENGTH_TRANSFER 0x4000
+
+struct mv_dqh {
+ /* Bits 16..26 Bit 15 is Interrupt On Setup */
+ u32 max_packet_length;
+ u32 curr_dtd_ptr; /* Current dTD Pointer */
+ u32 next_dtd_ptr; /* Next dTD Pointer */
+ /* Total bytes (16..30), IOC (15), INT (8), STS (0-7) */
+ u32 size_ioc_int_sts;
+ u32 buff_ptr0; /* Buffer pointer Page 0 (12-31) */
+ u32 buff_ptr1; /* Buffer pointer Page 1 (12-31) */
+ u32 buff_ptr2; /* Buffer pointer Page 2 (12-31) */
+ u32 buff_ptr3; /* Buffer pointer Page 3 (12-31) */
+ u32 buff_ptr4; /* Buffer pointer Page 4 (12-31) */
+ u32 reserved1;
+ /* 8 bytes of setup data that follows the Setup PID */
+ u8 setup_buffer[8];
+ u32 reserved2[4];
+};
+
+
+#define DTD_NEXT_TERMINATE (0x00000001)
+#define DTD_IOC (0x00008000)
+#define DTD_STATUS_ACTIVE (0x00000080)
+#define DTD_STATUS_HALTED (0x00000040)
+#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
+#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
+#define DTD_RESERVED_FIELDS (0x00007F00)
+#define DTD_ERROR_MASK (0x68)
+#define DTD_ADDR_MASK (0xFFFFFFE0)
+#define DTD_PACKET_SIZE 0x7FFF0000
+#define DTD_LENGTH_BIT_POS (16)
+
+struct mv_dtd {
+ u32 dtd_next;
+ u32 size_ioc_sts;
+ u32 buff_ptr0; /* Buffer pointer Page 0 */
+ u32 buff_ptr1; /* Buffer pointer Page 1 */
+ u32 buff_ptr2; /* Buffer pointer Page 2 */
+ u32 buff_ptr3; /* Buffer pointer Page 3 */
+ u32 buff_ptr4; /* Buffer pointer Page 4 */
+ u32 scratch_ptr;
+ /* 32 bytes */
+ dma_addr_t td_dma; /* dma address for this td */
+ struct mv_dtd *next_dtd_virt;
+};
+
+extern int mv_udc_phy_init(unsigned int base);
+
+#endif
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
new file mode 100644
index 000000000000..d5468a7f38e0
--- /dev/null
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -0,0 +1,2149 @@
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include "mv_udc.h"
+
+#define DRIVER_DESC "Marvell PXA USB Device Controller driver"
+#define DRIVER_VERSION "8 Nov 2010"
+
+#define ep_dir(ep) (((ep)->ep_num == 0) ? \
+ ((ep)->udc->ep0_dir) : ((ep)->direction))
+
+/* timeout value -- usec */
+#define RESET_TIMEOUT 10000
+#define FLUSH_TIMEOUT 10000
+#define EPSTATUS_TIMEOUT 10000
+#define PRIME_TIMEOUT 10000
+#define READSAFE_TIMEOUT 1000
+#define DTD_TIMEOUT 1000
+
+#define LOOPS_USEC_SHIFT 4
+#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
+#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
+
+static const char driver_name[] = "mv_udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+/* controller device global variable */
+static struct mv_udc *the_controller;
+int mv_usb_otgsc;
+
+static void nuke(struct mv_ep *ep, int status);
+
+/* for endpoint 0 operations */
+static const struct usb_endpoint_descriptor mv_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = EP0_MAX_PKT_SIZE,
+};
+
+static void ep0_reset(struct mv_udc *udc)
+{
+ struct mv_ep *ep;
+ u32 epctrlx;
+ int i = 0;
+
+ /* ep0 in and out */
+ for (i = 0; i < 2; i++) {
+ ep = &udc->eps[i];
+ ep->udc = udc;
+
+ /* ep0 dQH */
+ ep->dqh = &udc->ep_dqh[i];
+
+ /* configure ep0 endpoint capabilities in dQH */
+ ep->dqh->max_packet_length =
+ (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | EP_QUEUE_HEAD_IOS;
+
+ epctrlx = readl(&udc->op_regs->epctrlx[0]);
+ if (i) { /* TX */
+ epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST
+ | (USB_ENDPOINT_XFER_CONTROL
+ << EPCTRL_TX_EP_TYPE_SHIFT);
+
+ } else { /* RX */
+ epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST
+ | (USB_ENDPOINT_XFER_CONTROL
+ << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+
+ writel(epctrlx, &udc->op_regs->epctrlx[0]);
+ }
+}
+
+/* protocol ep0 stall, will automatically be cleared on new transaction */
+static void ep0_stall(struct mv_udc *udc)
+{
+ u32 epctrlx;
+
+ /* set TX and RX to stall */
+ epctrlx = readl(&udc->op_regs->epctrlx[0]);
+ epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL;
+ writel(epctrlx, &udc->op_regs->epctrlx[0]);
+
+ /* update ep0 state */
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = EP_DIR_OUT;
+}
+
+static int process_ep_req(struct mv_udc *udc, int index,
+ struct mv_req *curr_req)
+{
+ struct mv_dtd *curr_dtd;
+ struct mv_dqh *curr_dqh;
+ int td_complete, actual, remaining_length;
+ int i, direction;
+ int retval = 0;
+ u32 errors;
+
+ curr_dqh = &udc->ep_dqh[index];
+ direction = index % 2;
+
+ curr_dtd = curr_req->head;
+ td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (i = 0; i < curr_req->dtd_count; i++) {
+ if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) {
+ dev_dbg(&udc->dev->dev, "%s, dTD not completed\n",
+ udc->eps[index].name);
+ return 1;
+ }
+
+ errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK;
+ if (!errors) {
+ remaining_length +=
+ (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+ actual -= remaining_length;
+ } else {
+ dev_info(&udc->dev->dev,
+ "complete_tr error: ep=%d %s: error = 0x%x\n",
+ index >> 1, direction ? "SEND" : "RECV",
+ errors);
+ if (errors & DTD_STATUS_HALTED) {
+ /* Clear the errors and Halt condition */
+ curr_dqh->size_ioc_int_sts &= ~errors;
+ retval = -EPIPE;
+ } else if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+ retval = -EPROTO;
+ } else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+ retval = -EILSEQ;
+ }
+ }
+ if (i != curr_req->dtd_count - 1)
+ curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt;
+ }
+ if (retval)
+ return retval;
+
+ curr_req->req.actual = actual;
+
+ return 0;
+}
+
+/*
+ * done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ * request is still in progress.
+ */
+static void done(struct mv_ep *ep, struct mv_req *req, int status)
+{
+ struct mv_udc *udc = NULL;
+ unsigned char stopped = ep->stopped;
+ struct mv_dtd *curr_td, *next_td;
+ int j;
+
+ udc = (struct mv_udc *)ep->udc;
+ /* Removed the req from fsl_ep->queue */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ /* Free dtd for the request */
+ next_td = req->head;
+ for (j = 0; j < req->dtd_count; j++) {
+ curr_td = next_td;
+ if (j != req->dtd_count - 1)
+ next_td = curr_td->next_dtd_virt;
+ dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
+ }
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ((ep_dir(ep) == EP_DIR_IN) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ((ep_dir(ep) == EP_DIR_IN) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+ if (status && (status != -ESHUTDOWN))
+ dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ ep->stopped = 1;
+
+ spin_unlock(&ep->udc->lock);
+ /*
+ * complete() is from gadget layer,
+ * eg fsg->bulk_in_complete()
+ */
+ if (req->req.complete)
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock(&ep->udc->lock);
+ ep->stopped = stopped;
+}
+
+static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
+{
+ u32 tmp, epstatus, bit_pos, direction;
+ struct mv_udc *udc;
+ struct mv_dqh *dqh;
+ unsigned int loops;
+ int readsafe, retval = 0;
+
+ udc = ep->udc;
+ direction = ep_dir(ep);
+ dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]);
+ bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
+
+ /* check if the pipe is empty */
+ if (!(list_empty(&ep->queue))) {
+ struct mv_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
+ lastreq->tail->dtd_next =
+ req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ if (readl(&udc->op_regs->epprime) & bit_pos) {
+ loops = LOOPS(PRIME_TIMEOUT);
+ while (readl(&udc->op_regs->epprime) & bit_pos) {
+ if (loops == 0) {
+ retval = -ETIME;
+ goto done;
+ }
+ udelay(LOOPS_USEC);
+ loops--;
+ }
+ if (readl(&udc->op_regs->epstatus) & bit_pos)
+ goto done;
+ }
+ readsafe = 0;
+ loops = LOOPS(READSAFE_TIMEOUT);
+ while (readsafe == 0) {
+ if (loops == 0) {
+ retval = -ETIME;
+ goto done;
+ }
+ /* start with setting the semaphores */
+ tmp = readl(&udc->op_regs->usbcmd);
+ tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
+ writel(tmp, &udc->op_regs->usbcmd);
+
+ /* read the endpoint status */
+ epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
+
+ /*
+ * Reread the ATDTW semaphore bit to check if it is
+ * cleared. When hardware see a hazard, it will clear
+ * the bit or else we remain set to 1 and we can
+ * proceed with priming of endpoint if not already
+ * primed.
+ */
+ if (readl(&udc->op_regs->usbcmd)
+ & USBCMD_ATDTW_TRIPWIRE_SET) {
+ readsafe = 1;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+ }
+
+ /* Clear the semaphore */
+ tmp = readl(&udc->op_regs->usbcmd);
+ tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
+ writel(tmp, &udc->op_regs->usbcmd);
+
+ /* If endpoint is not active, we activate it now. */
+ if (!epstatus) {
+ if (direction == EP_DIR_IN) {
+ struct mv_dtd *curr_dtd = dma_to_virt(
+ &udc->dev->dev, dqh->curr_dtd_ptr);
+
+ loops = LOOPS(DTD_TIMEOUT);
+ while (curr_dtd->size_ioc_sts
+ & DTD_STATUS_ACTIVE) {
+ if (loops == 0) {
+ retval = -ETIME;
+ goto done;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+ }
+ }
+ /* No other transfers on the queue */
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ dqh->next_dtd_ptr = req->head->td_dma
+ & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ dqh->size_ioc_int_sts = 0;
+
+ /*
+ * Ensure that updates to the QH will
+ * occure before priming.
+ */
+ wmb();
+
+ /* Prime the Endpoint */
+ writel(bit_pos, &udc->op_regs->epprime);
+ }
+ } else {
+ /* Write dQH next pointer and terminate bit to 0 */
+ dqh->next_dtd_ptr = req->head->td_dma
+ & EP_QUEUE_HEAD_NEXT_POINTER_MASK;;
+ dqh->size_ioc_int_sts = 0;
+
+ /* Ensure that updates to the QH will occure before priming. */
+ wmb();
+
+ /* Prime the Endpoint */
+ writel(bit_pos, &udc->op_regs->epprime);
+
+ if (direction == EP_DIR_IN) {
+ /* FIXME add status check after prime the IN ep */
+ int prime_again;
+ u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
+
+ loops = LOOPS(DTD_TIMEOUT);
+ prime_again = 0;
+ while ((curr_dtd_ptr != req->head->td_dma)) {
+ curr_dtd_ptr = dqh->curr_dtd_ptr;
+ if (loops == 0) {
+ dev_err(&udc->dev->dev,
+ "failed to prime %s\n",
+ ep->name);
+ retval = -ETIME;
+ goto done;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+
+ if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
+ if (prime_again)
+ goto done;
+ dev_info(&udc->dev->dev,
+ "prime again\n");
+ writel(bit_pos,
+ &udc->op_regs->epprime);
+ prime_again = 1;
+ }
+ }
+ }
+ }
+done:
+ return retval;;
+}
+
+static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
+ dma_addr_t *dma, int *is_last)
+{
+ u32 temp;
+ struct mv_dtd *dtd;
+ struct mv_udc *udc;
+
+ /* how big will this transfer be? */
+ *length = min(req->req.length - req->req.actual,
+ (unsigned)EP_MAX_LENGTH_TRANSFER);
+
+ udc = req->ep->udc;
+
+ /*
+ * Be careful that no _GFP_HIGHMEM is set,
+ * or we can not use dma_to_virt
+ */
+ dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma);
+ if (dtd == NULL)
+ return dtd;
+
+ dtd->td_dma = *dma;
+ /* initialize buffer page pointers */
+ temp = (u32)(req->req.dma + req->req.actual);
+ dtd->buff_ptr0 = cpu_to_le32(temp);
+ temp &= ~0xFFF;
+ dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000);
+
+ req->req.actual += *length;
+
+ /* zlp is needed if req->req.zero is set */
+ if (req->req.zero) {
+ if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+ *is_last = 1;
+ else
+ *is_last = 0;
+ } else if (req->req.length == req->req.actual)
+ *is_last = 1;
+ else
+ *is_last = 0;
+
+ /* Fill in the transfer size; set active bit */
+ temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+ /* Enable interrupt for the last dtd of a request */
+ if (*is_last && !req->req.no_interrupt)
+ temp |= DTD_IOC;
+
+ dtd->size_ioc_sts = temp;
+
+ mb();
+
+ return dtd;
+}
+
+/* generate dTD linked list for a request */
+static int req_to_dtd(struct mv_req *req)
+{
+ unsigned count;
+ int is_last, is_first = 1;
+ struct mv_dtd *dtd, *last_dtd = NULL;
+ struct mv_udc *udc;
+ dma_addr_t dma;
+
+ udc = req->ep->udc;
+
+ do {
+ dtd = build_dtd(req, &count, &dma, &is_last);
+ if (dtd == NULL)
+ return -ENOMEM;
+
+ if (is_first) {
+ is_first = 0;
+ req->head = dtd;
+ } else {
+ last_dtd->dtd_next = dma;
+ last_dtd->next_dtd_virt = dtd;
+ }
+ last_dtd = dtd;
+ req->dtd_count++;
+ } while (!is_last);
+
+ /* set terminate bit to 1 for the last dTD */
+ dtd->dtd_next = DTD_NEXT_TERMINATE;
+
+ req->tail = dtd;
+
+ return 0;
+}
+
+static int mv_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct mv_udc *udc;
+ struct mv_ep *ep;
+ struct mv_dqh *dqh;
+ u16 max = 0;
+ u32 bit_pos, epctrlx, direction;
+ unsigned char zlt = 0, ios = 0, mult = 0;
+
+ ep = container_of(_ep, struct mv_ep, ep);
+ udc = ep->udc;
+
+ if (!_ep || !desc || ep->desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ direction = ep_dir(ep);
+ max = le16_to_cpu(desc->wMaxPacketSize);
+
+ /*
+ * disable HW zero length termination select
+ * driver handles zero length packet through req->req.zero
+ */
+ zlt = 1;
+
+ /* Get the endpoint queue head address */
+ dqh = (struct mv_dqh *)ep->dqh;
+
+ bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
+
+ /* Check if the Endpoint is Primed */
+ if ((readl(&udc->op_regs->epprime) & bit_pos)
+ || (readl(&udc->op_regs->epstatus) & bit_pos)) {
+ dev_info(&udc->dev->dev,
+ "ep=%d %s: Init ERROR: ENDPTPRIME=0x%x,"
+ " ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
+ (unsigned)ep->ep_num, direction ? "SEND" : "RECV",
+ (unsigned)readl(&udc->op_regs->epprime),
+ (unsigned)readl(&udc->op_regs->epstatus),
+ (unsigned)bit_pos);
+ goto en_done;
+ }
+ /* Set the max packet length, interrupt on Setup and Mult fields */
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ zlt = 1;
+ mult = 0;
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ ios = 1;
+ case USB_ENDPOINT_XFER_INT:
+ mult = 0;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* Calculate transactions needed for high bandwidth iso */
+ mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+ max = max & 0x8ff; /* bit 0~10 */
+ /* 3 transactions at most */
+ if (mult > 3)
+ goto en_done;
+ break;
+ default:
+ goto en_done;
+ }
+ dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+ | (mult << EP_QUEUE_HEAD_MULT_POS)
+ | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
+ | (ios ? EP_QUEUE_HEAD_IOS : 0);
+ dqh->next_dtd_ptr = 1;
+ dqh->size_ioc_int_sts = 0;
+
+ ep->ep.maxpacket = max;
+ ep->desc = desc;
+ ep->stopped = 0;
+
+ /* Enable the endpoint for Rx or Tx and set the endpoint type */
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ if (direction == EP_DIR_IN) {
+ epctrlx &= ~EPCTRL_TX_ALL_MASK;
+ epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST
+ | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ epctrlx &= ~EPCTRL_RX_ALL_MASK;
+ epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST
+ | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+
+ /*
+ * Implement Guideline (GL# USB-7) The unused endpoint type must
+ * be programmed to bulk.
+ */
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ if ((epctrlx & EPCTRL_RX_ENABLE) == 0) {
+ epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ << EPCTRL_RX_EP_TYPE_SHIFT);
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+ }
+
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ if ((epctrlx & EPCTRL_TX_ENABLE) == 0) {
+ epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ << EPCTRL_TX_EP_TYPE_SHIFT);
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+ }
+
+ return 0;
+en_done:
+ return -EINVAL;
+}
+
+static int mv_ep_disable(struct usb_ep *_ep)
+{
+ struct mv_udc *udc;
+ struct mv_ep *ep;
+ struct mv_dqh *dqh;
+ u32 bit_pos, epctrlx, direction;
+
+ ep = container_of(_ep, struct mv_ep, ep);
+ if ((_ep == NULL) || !ep->desc)
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ /* Get the endpoint queue head address */
+ dqh = ep->dqh;
+
+ direction = ep_dir(ep);
+ bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
+
+ /* Reset the max packet length and the interrupt on Setup */
+ dqh->max_packet_length = 0;
+
+ /* Disable the endpoint for Rx or Tx and reset the endpoint type */
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ epctrlx &= ~((direction == EP_DIR_IN)
+ ? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE)
+ : (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE));
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+
+ /* nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = NULL;
+ ep->stopped = 1;
+ return 0;
+}
+
+static struct usb_request *
+mv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct mv_req *req = NULL;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void mv_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mv_req *req = NULL;
+
+ req = container_of(_req, struct mv_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+static void mv_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct mv_udc *udc;
+ u32 bit_pos, direction;
+ struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
+ unsigned int loops;
+
+ udc = ep->udc;
+ direction = ep_dir(ep);
+ bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
+ /*
+ * Flushing will halt the pipe
+ * Write 1 to the Flush register
+ */
+ writel(bit_pos, &udc->op_regs->epflush);
+
+ /* Wait until flushing completed */
+ loops = LOOPS(FLUSH_TIMEOUT);
+ while (readl(&udc->op_regs->epflush) & bit_pos) {
+ /*
+ * ENDPTFLUSH bit should be cleared to indicate this
+ * operation is complete
+ */
+ if (loops == 0) {
+ dev_err(&udc->dev->dev,
+ "TIMEOUT for ENDPTFLUSH=0x%x, bit_pos=0x%x\n",
+ (unsigned)readl(&udc->op_regs->epflush),
+ (unsigned)bit_pos);
+ return;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+ }
+ loops = LOOPS(EPSTATUS_TIMEOUT);
+ while (readl(&udc->op_regs->epstatus) & bit_pos) {
+ unsigned int inter_loops;
+
+ if (loops == 0) {
+ dev_err(&udc->dev->dev,
+ "TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
+ (unsigned)readl(&udc->op_regs->epstatus),
+ (unsigned)bit_pos);
+ return;
+ }
+ /* Write 1 to the Flush register */
+ writel(bit_pos, &udc->op_regs->epflush);
+
+ /* Wait until flushing completed */
+ inter_loops = LOOPS(FLUSH_TIMEOUT);
+ while (readl(&udc->op_regs->epflush) & bit_pos) {
+ /*
+ * ENDPTFLUSH bit should be cleared to indicate this
+ * operation is complete
+ */
+ if (inter_loops == 0) {
+ dev_err(&udc->dev->dev,
+ "TIMEOUT for ENDPTFLUSH=0x%x,"
+ "bit_pos=0x%x\n",
+ (unsigned)readl(&udc->op_regs->epflush),
+ (unsigned)bit_pos);
+ return;
+ }
+ inter_loops--;
+ udelay(LOOPS_USEC);
+ }
+ loops--;
+ }
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
+ struct mv_req *req = container_of(_req, struct mv_req, req);
+ struct mv_udc *udc = ep->udc;
+ unsigned long flags;
+
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+ dev_err(&udc->dev->dev, "%s, bad params", __func__);
+ return -EINVAL;
+ }
+ if (unlikely(!_ep || !ep->desc)) {
+ dev_err(&udc->dev->dev, "%s, bad ep", __func__);
+ return -EINVAL;
+ }
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (req->req.length > ep->ep.maxpacket)
+ return -EMSGSIZE;
+ }
+
+ udc = ep->udc;
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length, ep_dir(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_dir(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->dtd_count = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* build dtds and push them to device queue */
+ if (!req_to_dtd(req)) {
+ int retval;
+ retval = queue_dtd(ep, req);
+ if (retval) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return retval;
+ }
+ } else {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -ENOMEM;
+ }
+
+ /* Update ep0 state */
+ if (ep->ep_num == 0)
+ udc->ep0_state = DATA_STATE_XMIT;
+
+ /* irq handler advances the queue */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
+ struct mv_req *req;
+ struct mv_udc *udc = ep->udc;
+ unsigned long flags;
+ int stopped, ret = 0;
+ u32 epctrlx;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ stopped = ep->stopped;
+
+ /* Stop the ep before we deal with the queue */
+ ep->stopped = 1;
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ if (ep_dir(ep) == EP_DIR_IN)
+ epctrlx &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrlx &= ~EPCTRL_RX_ENABLE;
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The request is in progress, or completed but not dequeued */
+ if (ep->queue.next == &req->queue) {
+ _req->status = -ECONNRESET;
+ mv_ep_fifo_flush(_ep); /* flush current transfer */
+
+ /* The request isn't the last request in this ep queue */
+ if (req->queue.next != &ep->queue) {
+ struct mv_dqh *qh;
+ struct mv_req *next_req;
+
+ qh = ep->dqh;
+ next_req = list_entry(req->queue.next, struct mv_req,
+ queue);
+
+ /* Point the QH to the first TD of next request */
+ writel((u32) next_req->head, &qh->curr_dtd_ptr);
+ } else {
+ struct mv_dqh *qh;
+
+ qh = ep->dqh;
+ qh->next_dtd_ptr = 1;
+ qh->size_ioc_int_sts = 0;
+ }
+
+ /* The request hasn't been processed, patch up the TD chain */
+ } else {
+ struct mv_req *prev_req;
+
+ prev_req = list_entry(req->queue.prev, struct mv_req, queue);
+ writel(readl(&req->tail->dtd_next),
+ &prev_req->tail->dtd_next);
+
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ /* Enable EP */
+out:
+ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
+ if (ep_dir(ep) == EP_DIR_IN)
+ epctrlx |= EPCTRL_TX_ENABLE;
+ else
+ epctrlx |= EPCTRL_RX_ENABLE;
+ writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
+ ep->stopped = stopped;
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+static void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall)
+{
+ u32 epctrlx;
+
+ epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
+
+ if (stall) {
+ if (direction == EP_DIR_IN)
+ epctrlx |= EPCTRL_TX_EP_STALL;
+ else
+ epctrlx |= EPCTRL_RX_EP_STALL;
+ } else {
+ if (direction == EP_DIR_IN) {
+ epctrlx &= ~EPCTRL_TX_EP_STALL;
+ epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST;
+ } else {
+ epctrlx &= ~EPCTRL_RX_EP_STALL;
+ epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST;
+ }
+ }
+ writel(epctrlx, &udc->op_regs->epctrlx[ep_num]);
+}
+
+static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
+{
+ u32 epctrlx;
+
+ epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
+
+ if (direction == EP_DIR_OUT)
+ return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0;
+ else
+ return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0;
+}
+
+static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
+{
+ struct mv_ep *ep;
+ unsigned long flags = 0;
+ int status = 0;
+ struct mv_udc *udc;
+
+ ep = container_of(_ep, struct mv_ep, ep);
+ udc = ep->udc;
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ status = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /*
+ * Attempt to halt IN ep will fail if any transfer requests
+ * are still queue
+ */
+ if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) {
+ status = -EAGAIN;
+ goto out;
+ }
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt);
+ if (halt && wedge)
+ ep->wedge = 1;
+ else if (!halt)
+ ep->wedge = 0;
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if (ep->ep_num == 0) {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = EP_DIR_OUT;
+ }
+out:
+ return status;
+}
+
+static int mv_ep_set_halt(struct usb_ep *_ep, int halt)
+{
+ return mv_ep_set_halt_wedge(_ep, halt, 0);
+}
+
+static int mv_ep_set_wedge(struct usb_ep *_ep)
+{
+ return mv_ep_set_halt_wedge(_ep, 1, 1);
+}
+
+static struct usb_ep_ops mv_ep_ops = {
+ .enable = mv_ep_enable,
+ .disable = mv_ep_disable,
+
+ .alloc_request = mv_alloc_request,
+ .free_request = mv_free_request,
+
+ .queue = mv_ep_queue,
+ .dequeue = mv_ep_dequeue,
+
+ .set_wedge = mv_ep_set_wedge,
+ .set_halt = mv_ep_set_halt,
+ .fifo_flush = mv_ep_fifo_flush, /* flush fifo */
+};
+
+static void udc_stop(struct mv_udc *udc)
+{
+ u32 tmp;
+
+ /* Disable interrupts */
+ tmp = readl(&udc->op_regs->usbintr);
+ tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN |
+ USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
+ writel(tmp, &udc->op_regs->usbintr);
+
+ /* Reset the Run the bit in the command register to stop VUSB */
+ tmp = readl(&udc->op_regs->usbcmd);
+ tmp &= ~USBCMD_RUN_STOP;
+ writel(tmp, &udc->op_regs->usbcmd);
+}
+
+static void udc_start(struct mv_udc *udc)
+{
+ u32 usbintr;
+
+ usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN
+ | USBINTR_PORT_CHANGE_DETECT_EN
+ | USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND;
+ /* Enable interrupts */
+ writel(usbintr, &udc->op_regs->usbintr);
+
+ /* Set the Run bit in the command register */
+ writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
+}
+
+static int udc_reset(struct mv_udc *udc)
+{
+ unsigned int loops;
+ u32 tmp, portsc;
+
+ /* Stop the controller */
+ tmp = readl(&udc->op_regs->usbcmd);
+ tmp &= ~USBCMD_RUN_STOP;
+ writel(tmp, &udc->op_regs->usbcmd);
+
+ /* Reset the controller to get default values */
+ writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd);
+
+ /* wait for reset to complete */
+ loops = LOOPS(RESET_TIMEOUT);
+ while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
+ if (loops == 0) {
+ dev_err(&udc->dev->dev,
+ "Wait for RESET completed TIMEOUT\n");
+ return -ETIMEDOUT;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+ }
+
+ /* set controller to device mode */
+ tmp = readl(&udc->op_regs->usbmode);
+ tmp |= USBMODE_CTRL_MODE_DEVICE;
+
+ /* turn setup lockout off, require setup tripwire in usbcmd */
+ tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE;
+
+ writel(tmp, &udc->op_regs->usbmode);
+
+ writel(0x0, &udc->op_regs->epsetupstat);
+
+ /* Configure the Endpoint List Address */
+ writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK,
+ &udc->op_regs->eplistaddr);
+
+ portsc = readl(&udc->op_regs->portsc[0]);
+ if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC)
+ portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER);
+
+ if (udc->force_fs)
+ portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT;
+ else
+ portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT);
+
+ writel(portsc, &udc->op_regs->portsc[0]);
+
+ tmp = readl(&udc->op_regs->epctrlx[0]);
+ tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL);
+ writel(tmp, &udc->op_regs->epctrlx[0]);
+
+ return 0;
+}
+
+static int mv_udc_get_frame(struct usb_gadget *gadget)
+{
+ struct mv_udc *udc;
+ u16 retval;
+
+ if (!gadget)
+ return -ENODEV;
+
+ udc = container_of(gadget, struct mv_udc, gadget);
+
+ retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS;
+
+ return retval;
+}
+
+/* Tries to wake up the host connected to this gadget */
+static int mv_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget);
+ u32 portsc;
+
+ /* Remote wakeup feature not enabled by host */
+ if (!udc->remote_wakeup)
+ return -ENOTSUPP;
+
+ portsc = readl(&udc->op_regs->portsc);
+ /* not suspended? */
+ if (!(portsc & PORTSCX_PORT_SUSPEND))
+ return 0;
+ /* trigger force resume */
+ portsc |= PORTSCX_PORT_FORCE_RESUME;
+ writel(portsc, &udc->op_regs->portsc[0]);
+ return 0;
+}
+
+static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct mv_udc *udc;
+ unsigned long flags;
+
+ udc = container_of(gadget, struct mv_udc, gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+
+ udc->softconnect = (is_on != 0);
+ if (udc->driver && udc->softconnect)
+ udc_start(udc);
+ else
+ udc_stop(udc);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return 0;
+}
+
+/* device controller usb_gadget_ops structure */
+static const struct usb_gadget_ops mv_ops = {
+
+ /* returns the current frame number */
+ .get_frame = mv_udc_get_frame,
+
+ /* tries to wake up the host connected to this gadget */
+ .wakeup = mv_udc_wakeup,
+
+ /* D+ pullup, software-controlled connect/disconnect to USB host */
+ .pullup = mv_udc_pullup,
+};
+
+static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
+{
+ dev_info(&udc->dev->dev, "Test Mode is not support yet\n");
+}
+
+static int eps_init(struct mv_udc *udc)
+{
+ struct mv_ep *ep;
+ char name[14];
+ int i;
+
+ /* initialize ep0 */
+ ep = &udc->eps[0];
+ ep->udc = udc;
+ strncpy(ep->name, "ep0", sizeof(ep->name));
+ ep->ep.name = ep->name;
+ ep->ep.ops = &mv_ep_ops;
+ ep->wedge = 0;
+ ep->stopped = 0;
+ ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
+ ep->ep_num = 0;
+ ep->desc = &mv_ep0_desc;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+ /* initialize other endpoints */
+ for (i = 2; i < udc->max_eps * 2; i++) {
+ ep = &udc->eps[i];
+ if (i % 2) {
+ snprintf(name, sizeof(name), "ep%din", i / 2);
+ ep->direction = EP_DIR_IN;
+ } else {
+ snprintf(name, sizeof(name), "ep%dout", i / 2);
+ ep->direction = EP_DIR_OUT;
+ }
+ ep->udc = udc;
+ strncpy(ep->name, name, sizeof(ep->name));
+ ep->ep.name = ep->name;
+
+ ep->ep.ops = &mv_ep_ops;
+ ep->stopped = 0;
+ ep->ep.maxpacket = (unsigned short) ~0;
+ ep->ep_num = i / 2;
+
+ INIT_LIST_HEAD(&ep->queue);
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+
+ ep->dqh = &udc->ep_dqh[i];
+ }
+
+ return 0;
+}
+
+/* delete all endpoint requests, called with spinlock held */
+static void nuke(struct mv_ep *ep, int status)
+{
+ /* called with spinlock held */
+ ep->stopped = 1;
+
+ /* endpoint fifo flush */
+ mv_ep_fifo_flush(&ep->ep);
+
+ while (!list_empty(&ep->queue)) {
+ struct mv_req *req = NULL;
+ req = list_entry(ep->queue.next, struct mv_req, queue);
+ done(ep, req, status);
+ }
+}
+
+/* stop all USB activities */
+static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
+{
+ struct mv_ep *ep;
+
+ nuke(&udc->eps[0], -ESHUTDOWN);
+
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ nuke(ep, -ESHUTDOWN);
+ }
+
+ /* report disconnect; the driver is already quiesced */
+ if (driver) {
+ spin_unlock(&udc->lock);
+ driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+}
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct mv_udc *udc = the_controller;
+ int retval = 0;
+ unsigned long flags;
+
+ if (!udc)
+ return -ENODEV;
+
+ if (udc->driver)
+ return -EBUSY;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* hook up the driver ... */
+ driver->driver.bus = NULL;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = USB_DIR_OUT;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ retval = bind(&udc->gadget);
+ if (retval) {
+ dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
+ driver->driver.name, retval);
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+ }
+ udc_reset(udc);
+ ep0_reset(udc);
+ udc_start(udc);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct mv_udc *udc = the_controller;
+ unsigned long flags;
+
+ if (!udc)
+ return -ENODEV;
+
+ udc_stop(udc);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* stop all usb activities */
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ stop_activity(udc, driver);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* unbind gadget driver */
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int
+udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
+{
+ int retval = 0;
+ struct mv_req *req;
+ struct mv_ep *ep;
+
+ ep = &udc->eps[0];
+ udc->ep0_dir = direction;
+
+ req = udc->status_req;
+
+ /* fill in the reqest structure */
+ if (empty == false) {
+ *((u16 *) req->req.buf) = cpu_to_le16(status);
+ req->req.length = 2;
+ } else
+ req->req.length = 0;
+
+ req->ep = ep;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ /* prime the data phase */
+ if (!req_to_dtd(req))
+ retval = queue_dtd(ep, req);
+ else{ /* no mem */
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (retval) {
+ dev_err(&udc->dev->dev, "response error on GET_STATUS request\n");
+ goto out;
+ }
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ return 0;
+out:
+ return retval;
+}
+
+static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup)
+{
+ udc->dev_addr = (u8)setup->wValue;
+
+ /* update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+
+ if (udc_prime_status(udc, EP_DIR_IN, 0, true))
+ ep0_stall(udc);
+}
+
+static void ch9getstatus(struct mv_udc *udc, u8 ep_num,
+ struct usb_ctrlrequest *setup)
+{
+ u16 status;
+ int retval;
+
+ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ return;
+
+ if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ status = 1 << USB_DEVICE_SELF_POWERED;
+ status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+ } else if ((setup->bRequestType & USB_RECIP_MASK)
+ == USB_RECIP_INTERFACE) {
+ /* get interface status */
+ status = 0;
+ } else if ((setup->bRequestType & USB_RECIP_MASK)
+ == USB_RECIP_ENDPOINT) {
+ u8 ep_num, direction;
+
+ ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
+ direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
+ ? EP_DIR_IN : EP_DIR_OUT;
+ status = ep_is_stall(udc, ep_num, direction)
+ << USB_ENDPOINT_HALT;
+ }
+
+ retval = udc_prime_status(udc, EP_DIR_IN, status, false);
+ if (retval)
+ ep0_stall(udc);
+}
+
+static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
+{
+ u8 ep_num;
+ u8 direction;
+ struct mv_ep *ep;
+
+ if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
+ == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
+ switch (setup->wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ udc->remote_wakeup = 0;
+ break;
+ case USB_DEVICE_TEST_MODE:
+ mv_udc_testmode(udc, 0, false);
+ break;
+ default:
+ goto out;
+ }
+ } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
+ == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
+ switch (setup->wValue) {
+ case USB_ENDPOINT_HALT:
+ ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
+ direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
+ ? EP_DIR_IN : EP_DIR_OUT;
+ if (setup->wValue != 0 || setup->wLength != 0
+ || ep_num > udc->max_eps)
+ goto out;
+ ep = &udc->eps[ep_num * 2 + direction];
+ if (ep->wedge == 1)
+ break;
+ spin_unlock(&udc->lock);
+ ep_set_stall(udc, ep_num, direction, 0);
+ spin_lock(&udc->lock);
+ break;
+ default:
+ goto out;
+ }
+ } else
+ goto out;
+
+ if (udc_prime_status(udc, EP_DIR_IN, 0, true))
+ ep0_stall(udc);
+ else
+ udc->ep0_state = DATA_STATE_XMIT;
+out:
+ return;
+}
+
+static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
+{
+ u8 ep_num;
+ u8 direction;
+
+ if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
+ == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
+ switch (setup->wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ udc->remote_wakeup = 1;
+ break;
+ case USB_DEVICE_TEST_MODE:
+ if (setup->wIndex & 0xFF
+ && udc->gadget.speed != USB_SPEED_HIGH)
+ goto out;
+ if (udc->usb_state == USB_STATE_CONFIGURED
+ || udc->usb_state == USB_STATE_ADDRESS
+ || udc->usb_state == USB_STATE_DEFAULT)
+ mv_udc_testmode(udc,
+ setup->wIndex & 0xFF00, true);
+ else
+ goto out;
+ break;
+ default:
+ goto out;
+ }
+ } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
+ == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
+ switch (setup->wValue) {
+ case USB_ENDPOINT_HALT:
+ ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
+ direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
+ ? EP_DIR_IN : EP_DIR_OUT;
+ if (setup->wValue != 0 || setup->wLength != 0
+ || ep_num > udc->max_eps)
+ goto out;
+ spin_unlock(&udc->lock);
+ ep_set_stall(udc, ep_num, direction, 1);
+ spin_lock(&udc->lock);
+ break;
+ default:
+ goto out;
+ }
+ } else
+ goto out;
+
+ if (udc_prime_status(udc, EP_DIR_IN, 0, true))
+ ep0_stall(udc);
+out:
+ return;
+}
+
+static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
+ struct usb_ctrlrequest *setup)
+{
+ bool delegate = false;
+
+ nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN);
+
+ dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+ setup->bRequestType, setup->bRequest,
+ setup->wValue, setup->wIndex, setup->wLength);
+ /* We process some stardard setup requests here */
+ if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (setup->bRequest) {
+ case USB_REQ_GET_STATUS:
+ ch9getstatus(udc, ep_num, setup);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ ch9setaddress(udc, setup);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ ch9clearfeature(udc, setup);
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ ch9setfeature(udc, setup);
+ break;
+
+ default:
+ delegate = true;
+ }
+ } else
+ delegate = true;
+
+ /* delegate USB standard requests to the gadget driver */
+ if (delegate == true) {
+ /* USB requests handled by gadget */
+ if (setup->wLength) {
+ /* DATA phase from gadget, STATUS phase from udc */
+ udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+ ? EP_DIR_IN : EP_DIR_OUT;
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0_stall(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 phase from gadget */
+ udc->ep0_dir = EP_DIR_IN;
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0_stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+ }
+}
+
+/* complete DATA or STATUS phase of ep0 prime status phase if needed */
+static void ep0_req_complete(struct mv_udc *udc,
+ struct mv_ep *ep0, struct mv_req *req)
+{
+ u32 new_addr;
+
+ if (udc->usb_state == USB_STATE_ADDRESS) {
+ /* set the new address */
+ new_addr = (u32)udc->dev_addr;
+ writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT,
+ &udc->op_regs->deviceaddr);
+ }
+
+ done(ep0, req, 0);
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+ /* receive status phase */
+ if (udc_prime_status(udc, EP_DIR_OUT, 0, true))
+ ep0_stall(udc);
+ break;
+ case DATA_STATE_RECV:
+ /* send status phase */
+ if (udc_prime_status(udc, EP_DIR_IN, 0 , true))
+ ep0_stall(udc);
+ break;
+ case WAIT_FOR_OUT_STATUS:
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+ case WAIT_FOR_SETUP:
+ dev_err(&udc->dev->dev, "unexpect ep0 packets\n");
+ break;
+ default:
+ ep0_stall(udc);
+ break;
+ }
+}
+
+static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr)
+{
+ u32 temp;
+ struct mv_dqh *dqh;
+
+ dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT];
+
+ /* Clear bit in ENDPTSETUPSTAT */
+ temp = readl(&udc->op_regs->epsetupstat);
+ writel(temp | (1 << ep_num), &udc->op_regs->epsetupstat);
+
+ /* while a hazard exists when setup package arrives */
+ do {
+ /* Set Setup Tripwire */
+ temp = readl(&udc->op_regs->usbcmd);
+ writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
+
+ /* Copy the setup packet to local buffer */
+ memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8);
+ } while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET));
+
+ /* Clear Setup Tripwire */
+ temp = readl(&udc->op_regs->usbcmd);
+ writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
+}
+
+static void irq_process_tr_complete(struct mv_udc *udc)
+{
+ u32 tmp, bit_pos;
+ int i, ep_num = 0, direction = 0;
+ struct mv_ep *curr_ep;
+ struct mv_req *curr_req, *temp_req;
+ int status;
+
+ /*
+ * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE
+ * because the setup packets are to be read ASAP
+ */
+
+ /* Process all Setup packet received interrupts */
+ tmp = readl(&udc->op_regs->epsetupstat);
+
+ if (tmp) {
+ for (i = 0; i < udc->max_eps; i++) {
+ if (tmp & (1 << i)) {
+ get_setup_data(udc, i,
+ (u8 *)(&udc->local_setup_buff));
+ handle_setup_packet(udc, i,
+ &udc->local_setup_buff);
+ }
+ }
+ }
+
+ /* Don't clear the endpoint setup status register here.
+ * It is cleared as a setup packet is read out of the buffer
+ */
+
+ /* Process non-setup transaction complete interrupts */
+ tmp = readl(&udc->op_regs->epcomplete);
+
+ if (!tmp)
+ return;
+
+ writel(tmp, &udc->op_regs->epcomplete);
+
+ for (i = 0; i < udc->max_eps * 2; i++) {
+ ep_num = i >> 1;
+ direction = i % 2;
+
+ bit_pos = 1 << (ep_num + 16 * direction);
+
+ if (!(bit_pos & tmp))
+ continue;
+
+ if (i == 1)
+ curr_ep = &udc->eps[0];
+ else
+ curr_ep = &udc->eps[i];
+ /* process the req queue until an uncomplete request */
+ list_for_each_entry_safe(curr_req, temp_req,
+ &curr_ep->queue, queue) {
+ status = process_ep_req(udc, i, curr_req);
+ if (status)
+ break;
+
+ /* write back status to req */
+ curr_req->req.status = status;
+
+ /* ep0 request completion */
+ if (ep_num == 0) {
+ ep0_req_complete(udc, curr_ep, curr_req);
+ break;
+ } else {
+ done(curr_ep, curr_req, status);
+ }
+ }
+ }
+}
+
+void irq_process_reset(struct mv_udc *udc)
+{
+ u32 tmp;
+ unsigned int loops;
+
+ udc->ep0_dir = EP_DIR_OUT;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
+
+ /* The address bits are past bit 25-31. Set the address */
+ tmp = readl(&udc->op_regs->deviceaddr);
+ tmp &= ~(USB_DEVICE_ADDRESS_MASK);
+ writel(tmp, &udc->op_regs->deviceaddr);
+
+ /* Clear all the setup token semaphores */
+ tmp = readl(&udc->op_regs->epsetupstat);
+ writel(tmp, &udc->op_regs->epsetupstat);
+
+ /* Clear all the endpoint complete status bits */
+ tmp = readl(&udc->op_regs->epcomplete);
+ writel(tmp, &udc->op_regs->epcomplete);
+
+ /* wait until all endptprime bits cleared */
+ loops = LOOPS(PRIME_TIMEOUT);
+ while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) {
+ if (loops == 0) {
+ dev_err(&udc->dev->dev,
+ "Timeout for ENDPTPRIME = 0x%x\n",
+ readl(&udc->op_regs->epprime));
+ break;
+ }
+ loops--;
+ udelay(LOOPS_USEC);
+ }
+
+ /* Write 1s to the Flush register */
+ writel((u32)~0, &udc->op_regs->epflush);
+
+ if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) {
+ dev_info(&udc->dev->dev, "usb bus reset\n");
+ udc->usb_state = USB_STATE_DEFAULT;
+ /* reset all the queues, stop all USB activities */
+ stop_activity(udc, udc->driver);
+ } else {
+ dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n",
+ readl(&udc->op_regs->portsc));
+
+ /*
+ * re-initialize
+ * controller reset
+ */
+ udc_reset(udc);
+
+ /* reset all the queues, stop all USB activities */
+ stop_activity(udc, udc->driver);
+
+ /* reset ep0 dQH and endptctrl */
+ ep0_reset(udc);
+
+ /* enable interrupt and set controller to run state */
+ udc_start(udc);
+
+ udc->usb_state = USB_STATE_ATTACHED;
+ }
+}
+
+static void handle_bus_resume(struct mv_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver */
+ if (udc->driver) {
+ if (udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+static void irq_process_suspend(struct mv_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ if (udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+}
+
+static void irq_process_port_change(struct mv_udc *udc)
+{
+ u32 portsc;
+
+ portsc = readl(&udc->op_regs->portsc[0]);
+ if (!(portsc & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ u32 speed = portsc & PORTSCX_PORT_SPEED_MASK;
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ udc->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ udc->gadget.speed = USB_SPEED_FULL;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ udc->gadget.speed = USB_SPEED_LOW;
+ break;
+ default:
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ if (portsc & PORTSCX_PORT_SUSPEND) {
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+ if (udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ if (!(portsc & PORTSCX_PORT_SUSPEND)
+ && udc->usb_state == USB_STATE_SUSPENDED) {
+ handle_bus_resume(udc);
+ }
+
+ if (!udc->resume_state)
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+static void irq_process_error(struct mv_udc *udc)
+{
+ /* Increment the error count */
+ udc->errors++;
+}
+
+static irqreturn_t mv_udc_irq(int irq, void *dev)
+{
+ struct mv_udc *udc = (struct mv_udc *)dev;
+ u32 status, intr;
+
+ spin_lock(&udc->lock);
+
+ status = readl(&udc->op_regs->usbsts);
+ intr = readl(&udc->op_regs->usbintr);
+ status &= intr;
+
+ if (status == 0) {
+ spin_unlock(&udc->lock);
+ return IRQ_NONE;
+ }
+
+ /* Clear all the interrupts occured */
+ writel(status, &udc->op_regs->usbsts);
+
+ if (status & USBSTS_ERR)
+ irq_process_error(udc);
+
+ if (status & USBSTS_RESET)
+ irq_process_reset(udc);
+
+ if (status & USBSTS_PORT_CHANGE)
+ irq_process_port_change(udc);
+
+ if (status & USBSTS_INT)
+ irq_process_tr_complete(udc);
+
+ if (status & USBSTS_SUSPEND)
+ irq_process_suspend(udc);
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* release device structure */
+static void gadget_release(struct device *_dev)
+{
+ struct mv_udc *udc = the_controller;
+
+ complete(udc->done);
+ kfree(udc);
+}
+
+static int mv_udc_remove(struct platform_device *dev)
+{
+ struct mv_udc *udc = the_controller;
+
+ DECLARE_COMPLETION(done);
+
+ udc->done = &done;
+
+ /* free memory allocated in probe */
+ if (udc->dtd_pool)
+ dma_pool_destroy(udc->dtd_pool);
+
+ if (udc->ep_dqh)
+ dma_free_coherent(&dev->dev, udc->ep_dqh_size,
+ udc->ep_dqh, udc->ep_dqh_dma);
+
+ kfree(udc->eps);
+
+ if (udc->irq)
+ free_irq(udc->irq, &dev->dev);
+
+ if (udc->cap_regs)
+ iounmap(udc->cap_regs);
+ udc->cap_regs = NULL;
+
+ if (udc->phy_regs)
+ iounmap((void *)udc->phy_regs);
+ udc->phy_regs = 0;
+
+ if (udc->status_req) {
+ kfree(udc->status_req->req.buf);
+ kfree(udc->status_req);
+ }
+
+ device_unregister(&udc->gadget.dev);
+
+ /* free dev, wait for the release() finished */
+ wait_for_completion(&done);
+
+ the_controller = NULL;
+
+ return 0;
+}
+
+int mv_udc_probe(struct platform_device *dev)
+{
+ struct mv_udc *udc;
+ int retval = 0;
+ struct resource *r;
+ size_t size;
+
+ udc = kzalloc(sizeof *udc, GFP_KERNEL);
+ if (udc == NULL) {
+ dev_err(&dev->dev, "failed to allocate memory for udc\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ spin_lock_init(&udc->lock);
+
+ udc->dev = dev;
+
+ udc->clk = clk_get(&dev->dev, "U2OCLK");
+ if (IS_ERR(udc->clk)) {
+ retval = PTR_ERR(udc->clk);
+ goto error;
+ }
+
+ r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2o");
+ if (r == NULL) {
+ dev_err(&dev->dev, "no I/O memory resource defined\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ udc->cap_regs = (struct mv_cap_regs __iomem *)
+ ioremap(r->start, resource_size(r));
+ if (udc->cap_regs == NULL) {
+ dev_err(&dev->dev, "failed to map I/O memory\n");
+ retval = -EBUSY;
+ goto error;
+ }
+
+ r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2ophy");
+ if (r == NULL) {
+ dev_err(&dev->dev, "no phy I/O memory resource defined\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
+ if (udc->phy_regs == 0) {
+ dev_err(&dev->dev, "failed to map phy I/O memory\n");
+ retval = -EBUSY;
+ goto error;
+ }
+
+ /* we will acces controller register, so enable the clk */
+ clk_enable(udc->clk);
+ retval = mv_udc_phy_init(udc->phy_regs);
+ if (retval) {
+ dev_err(&dev->dev, "phy initialization error %d\n", retval);
+ goto error;
+ }
+
+ udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
+ + (readl(&udc->cap_regs->caplength_hciversion)
+ & CAPLENGTH_MASK));
+ udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
+
+ size = udc->max_eps * sizeof(struct mv_dqh) *2;
+ size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
+ udc->ep_dqh = dma_alloc_coherent(&dev->dev, size,
+ &udc->ep_dqh_dma, GFP_KERNEL);
+
+ if (udc->ep_dqh == NULL) {
+ dev_err(&dev->dev, "allocate dQH memory failed\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+ udc->ep_dqh_size = size;
+
+ /* create dTD dma_pool resource */
+ udc->dtd_pool = dma_pool_create("mv_dtd",
+ &dev->dev,
+ sizeof(struct mv_dtd),
+ DTD_ALIGNMENT,
+ DMA_BOUNDARY);
+
+ if (!udc->dtd_pool) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ size = udc->max_eps * sizeof(struct mv_ep) *2;
+ udc->eps = kzalloc(size, GFP_KERNEL);
+ if (udc->eps == NULL) {
+ dev_err(&dev->dev, "allocate ep memory failed\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ /* initialize ep0 status request structure */
+ udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL);
+ if (!udc->status_req) {
+ dev_err(&dev->dev, "allocate status_req memory failed\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+ INIT_LIST_HEAD(&udc->status_req->queue);
+
+ /* allocate a small amount of memory to get valid address */
+ udc->status_req->req.buf = kzalloc(8, GFP_KERNEL);
+ udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = EP_DIR_OUT;
+ udc->remote_wakeup = 0;
+
+ r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
+ if (r == NULL) {
+ dev_err(&dev->dev, "no IRQ resource defined\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ udc->irq = r->start;
+ if (request_irq(udc->irq, mv_udc_irq,
+ IRQF_DISABLED | IRQF_SHARED, driver_name, udc)) {
+ dev_err(&dev->dev, "Request irq %d for UDC failed\n",
+ udc->irq);
+ retval = -ENODEV;
+ goto error;
+ }
+
+ /* initialize gadget structure */
+ udc->gadget.ops = &mv_ops; /* usb_gadget_ops */
+ udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */
+ INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */
+ udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
+ udc->gadget.is_dualspeed = 1; /* support dual speed */
+
+ /* the "gadget" abstracts/virtualizes the controller */
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.parent = &dev->dev;
+ udc->gadget.dev.dma_mask = dev->dev.dma_mask;
+ udc->gadget.dev.release = gadget_release;
+ udc->gadget.name = driver_name; /* gadget name */
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval)
+ goto error;
+
+ eps_init(udc);
+
+ the_controller = udc;
+
+ goto out;
+error:
+ if (udc)
+ mv_udc_remove(udc->dev);
+out:
+ return retval;
+}
+
+#ifdef CONFIG_PM
+static int mv_udc_suspend(struct platform_device *_dev, pm_message_t state)
+{
+ struct mv_udc *udc = the_controller;
+
+ udc_stop(udc);
+
+ return 0;
+}
+
+static int mv_udc_resume(struct platform_device *_dev)
+{
+ struct mv_udc *udc = the_controller;
+ int retval;
+
+ retval = mv_udc_phy_init(udc->phy_regs);
+ if (retval) {
+ dev_err(_dev, "phy initialization error %d\n", retval);
+ goto error;
+ }
+ udc_reset(udc);
+ ep0_reset(udc);
+ udc_start(udc);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mv_udc_pm_ops = {
+ .suspend = mv_udc_suspend,
+ .resume = mv_udc_resume,
+};
+#endif
+
+static struct platform_driver udc_driver = {
+ .probe = mv_udc_probe,
+ .remove = __exit_p(mv_udc_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pxa-u2o",
+#ifdef CONFIG_PM
+ .pm = mv_udc_pm_ops,
+#endif
+ },
+};
+
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+
+static int __init init(void)
+{
+ return platform_driver_register(&udc_driver);
+}
+module_init(init);
+
+
+static void __exit cleanup(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(cleanup);
+
diff --git a/drivers/usb/gadget/mv_udc_phy.c b/drivers/usb/gadget/mv_udc_phy.c
new file mode 100644
index 000000000000..d4dea97e38a5
--- /dev/null
+++ b/drivers/usb/gadget/mv_udc_phy.c
@@ -0,0 +1,214 @@
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#include <mach/cputype.h>
+
+#ifdef CONFIG_ARCH_MMP
+
+#define UTMI_REVISION 0x0
+#define UTMI_CTRL 0x4
+#define UTMI_PLL 0x8
+#define UTMI_TX 0xc
+#define UTMI_RX 0x10
+#define UTMI_IVREF 0x14
+#define UTMI_T0 0x18
+#define UTMI_T1 0x1c
+#define UTMI_T2 0x20
+#define UTMI_T3 0x24
+#define UTMI_T4 0x28
+#define UTMI_T5 0x2c
+#define UTMI_RESERVE 0x30
+#define UTMI_USB_INT 0x34
+#define UTMI_DBG_CTL 0x38
+#define UTMI_OTG_ADDON 0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN (1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
+#define UTMI_CTRL_PU_REF_SHIFT 20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
+#define UTMI_CTRL_PWR_UP_SHIFT 0
+/* For UTMI_PLL Register */
+#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
+#define UTMI_PLL_FBDIV_SHIFT 4
+#define UTMI_PLL_REFDIV_SHIFT 0
+#define UTMI_PLL_FBDIV_MASK 0x00000FF0
+#define UTMI_PLL_REFDIV_MASK 0x0000000F
+#define UTMI_PLL_ICP_MASK 0x00007000
+#define UTMI_PLL_KVCO_MASK 0x00031000
+#define UTMI_PLL_PLLCALI12_SHIFT 29
+#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
+#define UTMI_PLL_PLLVDD18_SHIFT 27
+#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
+#define UTMI_PLL_PLLVDD12_SHIFT 25
+#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
+#define UTMI_PLL_KVCO_SHIFT 15
+#define UTMI_PLL_ICP_SHIFT 12
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK 26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN (0x1 << 26)
+#define UTMI_TX_LOW_VDD_EN_SHIFT 11
+#define UTMI_TX_IMPCAL_VTH_SHIFT 14
+#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
+#define UTMI_TX_CK60_PHSEL_SHIFT 17
+#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
+#define UTMI_TX_TXVDD12_SHIFT 22
+#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
+#define UTMI_TX_AMP_SHIFT 0
+#define UTMI_TX_AMP_MASK (0x7 << 0)
+/* For UTMI_RX Register */
+#define UTMI_RX_SQ_THRESH_SHIFT 4
+#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
+#define UTMI_REG_SQ_LENGTH_SHIFT 15
+#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
+
+#define REG_RCAL_START 0x00001000
+#define VCOCAL_START 0x00200000
+#define KVCO_EXT 0x00400000
+#define PLL_READY 0x00800000
+#define CLK_BLK_EN 0x01000000
+#endif
+
+static unsigned int u2o_read(unsigned int base, unsigned int offset)
+{
+ return readl(base + offset);
+}
+
+static void u2o_set(unsigned int base, unsigned int offset, unsigned int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + offset);
+ reg |= value;
+ writel(reg, base + offset);
+ readl(base + offset);
+}
+
+static void u2o_clear(unsigned int base, unsigned int offset,
+ unsigned int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + offset);
+ reg &= ~value;
+ writel(reg, base + offset);
+ readl(base + offset);
+}
+
+static void u2o_write(unsigned int base, unsigned int offset,
+ unsigned int value)
+{
+ writel(value, base + offset);
+ readl(base + offset);
+}
+
+#ifdef CONFIG_ARCH_MMP
+int mv_udc_phy_init(unsigned int base)
+{
+ unsigned long timeout;
+
+ /* Initialize the USB PHY power */
+ if (cpu_is_pxa910()) {
+ u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+ | (1 << UTMI_CTRL_PU_REF_SHIFT));
+ }
+
+ u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT);
+ u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT);
+
+ /* UTMI_PLL settings */
+ u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+ | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+ | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+ | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+ u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT)
+ | (0xb << UTMI_PLL_REFDIV_SHIFT)
+ | (3 << UTMI_PLL_PLLVDD18_SHIFT)
+ | (3 << UTMI_PLL_PLLVDD12_SHIFT)
+ | (3 << UTMI_PLL_PLLCALI12_SHIFT)
+ | (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT));
+
+ /* UTMI_TX */
+ u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+ | UTMI_TX_TXVDD12_MASK
+ | UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK
+ | UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK);
+ u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT)
+ | (4 << UTMI_TX_CK60_PHSEL_SHIFT)
+ | (4 << UTMI_TX_IMPCAL_VTH_SHIFT)
+ | (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT)
+ | (3 << UTMI_TX_AMP_SHIFT));
+
+ /* UTMI_RX */
+ u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+ | UTMI_REG_SQ_LENGTH_MASK);
+ if (cpu_is_pxa168())
+ u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT)
+ | (2 << UTMI_REG_SQ_LENGTH_SHIFT));
+ else
+ u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT)
+ | (2 << UTMI_REG_SQ_LENGTH_SHIFT));
+
+ /* UTMI_IVREF */
+ if (cpu_is_pxa168())
+ /*
+ * fixing Microsoft Altair board interface with NEC hub issue -
+ * Set UTMI_IVREF from 0x4a3 to 0x4bf
+ */
+ u2o_write(base, UTMI_IVREF, 0x4bf);
+
+ /* calibrate */
+ timeout = jiffies + 100;
+ while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
+ if (time_after(jiffies, timeout))
+ return -ETIME;
+ cpu_relax();
+ }
+
+ /* toggle VCOCAL_START bit of UTMI_PLL */
+ udelay(200);
+ u2o_set(base, UTMI_PLL, VCOCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+ /* toggle REG_RCAL_START bit of UTMI_TX */
+ udelay(200);
+ u2o_set(base, UTMI_TX, REG_RCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_TX, REG_RCAL_START);
+ udelay(200);
+
+ /* make sure phy is ready */
+ timeout = jiffies + 100;
+ while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
+ if (time_after(jiffies, timeout))
+ return -ETIME;
+ cpu_relax();
+ }
+
+ if (cpu_is_pxa168()) {
+ u2o_set(base, UTMI_RESERVE, 1 << 5);
+ /* Turn on UTMI PHY OTG extension */
+ u2o_write(base, UTMI_OTG_ADDON, 1);
+ }
+ return 0;
+}
+#else
+int mv_udc_phy_init(unsigned int base)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
new file mode 100644
index 000000000000..99c179ad729d
--- /dev/null
+++ b/drivers/usb/gadget/ncm.c
@@ -0,0 +1,248 @@
+/*
+ * ncm.c -- NCM gadget driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
+ *
+ * The driver borrows from ether.c which is:
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia 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 */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+
+
+#include "u_ether.h"
+
+#define DRIVER_DESC "NCM Gadget"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "f_ncm.c"
+#include "u_ether.c"
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM 0x0525 /* NetChip */
+#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16 (0x0200),
+
+ .bDeviceClass = USB_CLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ /* .bMaxPacketSize0 = f(hardware) */
+
+ /* Vendor and product id defaults change according to what configs
+ * we support. (As does bNumConfigurations.) These values can
+ * also be overridden by module parameters.
+ */
+ .idVendor = cpu_to_le16 (CDC_VENDOR_NUM),
+ .idProduct = cpu_to_le16 (CDC_PRODUCT_NUM),
+ /* .bcdDevice = f(hardware) */
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ /* NO SERIAL NUMBER */
+ .bNumConfigurations = 1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+ /* REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ...
+ */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer,
+ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+static u8 hostaddr[ETH_ALEN];
+
+/*-------------------------------------------------------------------------*/
+
+static int __init ncm_do_config(struct usb_configuration *c)
+{
+ /* FIXME alloc iConfiguration string, set it in c->strings */
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ return ncm_bind_config(c, hostaddr);
+}
+
+static struct usb_configuration ncm_config_driver = {
+ /* .label = f(hardware) */
+ .label = "CDC Ethernet (NCM)",
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init gncm_bind(struct usb_composite_dev *cdev)
+{
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+
+ /* set up network link layer */
+ status = gether_setup(cdev->gadget, hostaddr);
+ if (status < 0)
+ return status;
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+ else {
+ /* We assume that can_support_ecm() tells the truth;
+ * but if the controller isn't recognized at all then
+ * that assumption is a bit more likely to be wrong.
+ */
+ dev_warn(&gadget->dev,
+ "controller '%s' not recognized; trying %s\n",
+ gadget->name,
+ ncm_config_driver.label);
+ device_desc.bcdDevice =
+ cpu_to_le16(0x0300 | 0x0099);
+ }
+
+
+ /* Allocate string descriptor numbers ... note that string
+ * contents can be overridden by the composite_dev glue.
+ */
+
+ /* device descriptor strings: manufacturer, product */
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+ device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+ device_desc.iProduct = status;
+
+ status = usb_add_config(cdev, &ncm_config_driver,
+ ncm_do_config);
+ if (status < 0)
+ goto fail;
+
+ dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
+
+ return 0;
+
+fail:
+ gether_cleanup();
+ return status;
+}
+
+static int __exit gncm_unbind(struct usb_composite_dev *cdev)
+{
+ gether_cleanup();
+ return 0;
+}
+
+static struct usb_composite_driver ncm_driver = {
+ .name = "g_ncm",
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .unbind = __exit_p(gncm_unbind),
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Yauheni Kaliuta");
+MODULE_LICENSE("GPL");
+
+static int __init init(void)
+{
+ return usb_composite_probe(&ncm_driver, gncm_bind);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+ usb_composite_unregister(&ncm_driver);
+}
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
new file mode 100644
index 000000000000..0c8dd81dddca
--- /dev/null
+++ b/drivers/usb/gadget/pch_udc.c
@@ -0,0 +1,2947 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Address offset of Registers */
+#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
+
+#define UDC_EPCTL_ADDR 0x00 /* Endpoint control */
+#define UDC_EPSTS_ADDR 0x04 /* Endpoint status */
+#define UDC_BUFIN_FRAMENUM_ADDR 0x08 /* buffer size in / frame number out */
+#define UDC_BUFOUT_MAXPKT_ADDR 0x0C /* buffer size out / maxpkt in */
+#define UDC_SUBPTR_ADDR 0x10 /* setup buffer pointer */
+#define UDC_DESPTR_ADDR 0x14 /* Data descriptor pointer */
+#define UDC_CONFIRM_ADDR 0x18 /* Write/Read confirmation */
+
+#define UDC_DEVCFG_ADDR 0x400 /* Device configuration */
+#define UDC_DEVCTL_ADDR 0x404 /* Device control */
+#define UDC_DEVSTS_ADDR 0x408 /* Device status */
+#define UDC_DEVIRQSTS_ADDR 0x40C /* Device irq status */
+#define UDC_DEVIRQMSK_ADDR 0x410 /* Device irq mask */
+#define UDC_EPIRQSTS_ADDR 0x414 /* Endpoint irq status */
+#define UDC_EPIRQMSK_ADDR 0x418 /* Endpoint irq mask */
+#define UDC_DEVLPM_ADDR 0x41C /* LPM control / status */
+#define UDC_CSR_BUSY_ADDR 0x4f0 /* UDC_CSR_BUSY Status register */
+#define UDC_SRST_ADDR 0x4fc /* SOFT RESET register */
+#define UDC_CSR_ADDR 0x500 /* USB_DEVICE endpoint register */
+
+/* Endpoint control register */
+/* Bit position */
+#define UDC_EPCTL_MRXFLUSH (1 << 12)
+#define UDC_EPCTL_RRDY (1 << 9)
+#define UDC_EPCTL_CNAK (1 << 8)
+#define UDC_EPCTL_SNAK (1 << 7)
+#define UDC_EPCTL_NAK (1 << 6)
+#define UDC_EPCTL_P (1 << 3)
+#define UDC_EPCTL_F (1 << 1)
+#define UDC_EPCTL_S (1 << 0)
+#define UDC_EPCTL_ET_SHIFT 4
+/* Mask patern */
+#define UDC_EPCTL_ET_MASK 0x00000030
+/* Value for ET field */
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+/* Endpoint status register */
+/* Bit position */
+#define UDC_EPSTS_XFERDONE (1 << 27)
+#define UDC_EPSTS_RSS (1 << 26)
+#define UDC_EPSTS_RCS (1 << 25)
+#define UDC_EPSTS_TXEMPTY (1 << 24)
+#define UDC_EPSTS_TDC (1 << 10)
+#define UDC_EPSTS_HE (1 << 9)
+#define UDC_EPSTS_MRXFIFO_EMP (1 << 8)
+#define UDC_EPSTS_BNA (1 << 7)
+#define UDC_EPSTS_IN (1 << 6)
+#define UDC_EPSTS_OUT_SHIFT 4
+/* Mask patern */
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_ALL_CLR_MASK 0x1F0006F0
+/* Value for OUT field */
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_DATA 1
+
+/* Device configuration register */
+/* Bit position */
+#define UDC_DEVCFG_CSR_PRG (1 << 17)
+#define UDC_DEVCFG_SP (1 << 3)
+/* SPD Valee */
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+
+/* Device control register */
+/* Bit position */
+#define UDC_DEVCTL_THLEN_SHIFT 24
+#define UDC_DEVCTL_BRLEN_SHIFT 16
+#define UDC_DEVCTL_CSR_DONE (1 << 13)
+#define UDC_DEVCTL_SD (1 << 10)
+#define UDC_DEVCTL_MODE (1 << 9)
+#define UDC_DEVCTL_BREN (1 << 8)
+#define UDC_DEVCTL_THE (1 << 7)
+#define UDC_DEVCTL_DU (1 << 4)
+#define UDC_DEVCTL_TDE (1 << 3)
+#define UDC_DEVCTL_RDE (1 << 2)
+#define UDC_DEVCTL_RES (1 << 0)
+
+/* Device status register */
+/* Bit position */
+#define UDC_DEVSTS_TS_SHIFT 18
+#define UDC_DEVSTS_ENUM_SPEED_SHIFT 13
+#define UDC_DEVSTS_ALT_SHIFT 8
+#define UDC_DEVSTS_INTF_SHIFT 4
+#define UDC_DEVSTS_CFG_SHIFT 0
+/* Mask patern */
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+/* value for maximum speed for SPEED field */
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+#define UDC_DEVSTS_ENUM_SPEED_LOW 2
+#define UDC_DEVSTS_ENUM_SPEED_FULLX 3
+
+/* Device irq register */
+/* Bit position */
+#define UDC_DEVINT_RWKP (1 << 7)
+#define UDC_DEVINT_ENUM (1 << 6)
+#define UDC_DEVINT_SOF (1 << 5)
+#define UDC_DEVINT_US (1 << 4)
+#define UDC_DEVINT_UR (1 << 3)
+#define UDC_DEVINT_ES (1 << 2)
+#define UDC_DEVINT_SI (1 << 1)
+#define UDC_DEVINT_SC (1 << 0)
+/* Mask patern */
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint irq register */
+/* Bit position */
+#define UDC_EPINT_IN_SHIFT 0
+#define UDC_EPINT_OUT_SHIFT 16
+#define UDC_EPINT_IN_EP0 (1 << 0)
+#define UDC_EPINT_OUT_EP0 (1 << 16)
+/* Mask patern */
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+
+/* UDC_CSR_BUSY Status register */
+/* Bit position */
+#define UDC_CSR_BUSY (1 << 0)
+
+/* SOFT RESET register */
+/* Bit position */
+#define UDC_PSRST (1 << 1)
+#define UDC_SRST (1 << 0)
+
+/* USB_DEVICE endpoint register */
+/* Bit position */
+#define UDC_CSR_NE_NUM_SHIFT 0
+#define UDC_CSR_NE_DIR_SHIFT 4
+#define UDC_CSR_NE_TYPE_SHIFT 5
+#define UDC_CSR_NE_CFG_SHIFT 7
+#define UDC_CSR_NE_INTF_SHIFT 11
+#define UDC_CSR_NE_ALT_SHIFT 15
+#define UDC_CSR_NE_MAX_PKT_SHIFT 19
+/* Mask patern */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+
+#define PCH_UDC_CSR(ep) (UDC_CSR_ADDR + ep*4)
+#define PCH_UDC_EPINT(in, num)\
+ (1 << (num + (in ? UDC_EPINT_IN_SHIFT : UDC_EPINT_OUT_SHIFT)))
+
+/* Index of endpoint */
+#define UDC_EP0IN_IDX 0
+#define UDC_EP0OUT_IDX 1
+#define UDC_EPIN_IDX(ep) (ep * 2)
+#define UDC_EPOUT_IDX(ep) (ep * 2 + 1)
+#define PCH_UDC_EP0 0
+#define PCH_UDC_EP1 1
+#define PCH_UDC_EP2 2
+#define PCH_UDC_EP3 3
+
+/* Number of endpoint */
+#define PCH_UDC_EP_NUM 32 /* Total number of EPs (16 IN,16 OUT) */
+#define PCH_UDC_USED_EP_NUM 4 /* EP number of EP's really used */
+/* Length Value */
+#define PCH_UDC_BRLEN 0x0F /* Burst length */
+#define PCH_UDC_THLEN 0x1F /* Threshold length */
+/* Value of EP Buffer Size */
+#define UDC_EP0IN_BUFF_SIZE 64
+#define UDC_EPIN_BUFF_SIZE 512
+#define UDC_EP0OUT_BUFF_SIZE 64
+#define UDC_EPOUT_BUFF_SIZE 512
+/* Value of EP maximum packet size */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+#define UDC_BULK_MAX_PKT_SIZE 512
+
+/* DMA */
+#define DMA_DIR_RX 1 /* DMA for data receive */
+#define DMA_DIR_TX 2 /* DMA for data transmit */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define UDC_DMA_MAXPACKET 65536 /* maximum packet size for DMA */
+
+/**
+ * struct pch_udc_data_dma_desc - Structure to hold DMA descriptor information
+ * for data
+ * @status: Status quadlet
+ * @reserved: Reserved
+ * @dataptr: Buffer descriptor
+ * @next: Next descriptor
+ */
+struct pch_udc_data_dma_desc {
+ u32 status;
+ u32 reserved;
+ u32 dataptr;
+ u32 next;
+};
+
+/**
+ * struct pch_udc_stp_dma_desc - Structure to hold DMA descriptor information
+ * for control data
+ * @status: Status
+ * @reserved: Reserved
+ * @data12: First setup word
+ * @data34: Second setup word
+ */
+struct pch_udc_stp_dma_desc {
+ u32 status;
+ u32 reserved;
+ struct usb_ctrlrequest request;
+} __attribute((packed));
+
+/* DMA status definitions */
+/* Buffer status */
+#define PCH_UDC_BUFF_STS 0xC0000000
+#define PCH_UDC_BS_HST_RDY 0x00000000
+#define PCH_UDC_BS_DMA_BSY 0x40000000
+#define PCH_UDC_BS_DMA_DONE 0x80000000
+#define PCH_UDC_BS_HST_BSY 0xC0000000
+/* Rx/Tx Status */
+#define PCH_UDC_RXTX_STS 0x30000000
+#define PCH_UDC_RTS_SUCC 0x00000000
+#define PCH_UDC_RTS_DESERR 0x10000000
+#define PCH_UDC_RTS_BUFERR 0x30000000
+/* Last Descriptor Indication */
+#define PCH_UDC_DMA_LAST 0x08000000
+/* Number of Rx/Tx Bytes Mask */
+#define PCH_UDC_RXTX_BYTES 0x0000ffff
+
+/**
+ * struct pch_udc_cfg_data - Structure to hold current configuration
+ * and interface information
+ * @cur_cfg: current configuration in use
+ * @cur_intf: current interface in use
+ * @cur_alt: current alt interface in use
+ */
+struct pch_udc_cfg_data {
+ u16 cur_cfg;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/**
+ * struct pch_udc_ep - Structure holding a PCH USB device Endpoint information
+ * @ep: embedded ep request
+ * @td_stp_phys: for setup request
+ * @td_data_phys: for data request
+ * @td_stp: for setup request
+ * @td_data: for data request
+ * @dev: reference to device struct
+ * @offset_addr: offset address of ep register
+ * @desc: for this ep
+ * @queue: queue for requests
+ * @num: endpoint number
+ * @in: endpoint is IN
+ * @halted: endpoint halted?
+ * @epsts: Endpoint status
+ */
+struct pch_udc_ep {
+ struct usb_ep ep;
+ dma_addr_t td_stp_phys;
+ dma_addr_t td_data_phys;
+ struct pch_udc_stp_dma_desc *td_stp;
+ struct pch_udc_data_dma_desc *td_data;
+ struct pch_udc_dev *dev;
+ unsigned long offset_addr;
+ const struct usb_endpoint_descriptor *desc;
+ struct list_head queue;
+ unsigned num:5,
+ in:1,
+ halted:1;
+ unsigned long epsts;
+};
+
+/**
+ * struct pch_udc_dev - Structure holding complete information
+ * of the PCH USB device
+ * @gadget: gadget driver data
+ * @driver: reference to gadget driver bound
+ * @pdev: reference to the PCI device
+ * @ep: array of endpoints
+ * @lock: protects all state
+ * @active: enabled the PCI device
+ * @stall: stall requested
+ * @prot_stall: protcol stall requested
+ * @irq_registered: irq registered with system
+ * @mem_region: device memory mapped
+ * @registered: driver regsitered with system
+ * @suspended: driver in suspended state
+ * @connected: gadget driver associated
+ * @set_cfg_not_acked: pending acknowledgement 4 setup
+ * @waiting_zlp_ack: pending acknowledgement 4 ZLP
+ * @data_requests: DMA pool for data requests
+ * @stp_requests: DMA pool for setup requests
+ * @dma_addr: DMA pool for received
+ * @ep0out_buf: Buffer for DMA
+ * @setup_data: Received setup data
+ * @phys_addr: of device memory
+ * @base_addr: for mapped device memory
+ * @irq: IRQ line for the device
+ * @cfg_data: current cfg, intf, and alt in use
+ */
+struct pch_udc_dev {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct pci_dev *pdev;
+ struct pch_udc_ep ep[PCH_UDC_EP_NUM];
+ spinlock_t lock; /* protects all state */
+ unsigned active:1,
+ stall:1,
+ prot_stall:1,
+ irq_registered:1,
+ mem_region:1,
+ registered:1,
+ suspended:1,
+ connected:1,
+ set_cfg_not_acked:1,
+ waiting_zlp_ack:1;
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+ dma_addr_t dma_addr;
+ unsigned long ep0out_buf[64];
+ struct usb_ctrlrequest setup_data;
+ unsigned long phys_addr;
+ void __iomem *base_addr;
+ unsigned irq;
+ struct pch_udc_cfg_data cfg_data;
+};
+
+#define PCH_UDC_PCI_BAR 1
+#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
+
+static const char ep0_string[] = "ep0in";
+static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
+struct pch_udc_dev *pch_udc; /* pointer to device object */
+
+static int speed_fs;
+module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
+MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
+
+/**
+ * struct pch_udc_request - Structure holding a PCH USB device request packet
+ * @req: embedded ep request
+ * @td_data_phys: phys. address
+ * @td_data: first dma desc. of chain
+ * @td_data_last: last dma desc. of chain
+ * @queue: associated queue
+ * @dma_going: DMA in progress for request
+ * @dma_mapped: DMA memory mapped for request
+ * @dma_done: DMA completed for request
+ * @chain_len: chain length
+ */
+struct pch_udc_request {
+ struct usb_request req;
+ dma_addr_t td_data_phys;
+ struct pch_udc_data_dma_desc *td_data;
+ struct pch_udc_data_dma_desc *td_data_last;
+ struct list_head queue;
+ unsigned dma_going:1,
+ dma_mapped:1,
+ dma_done:1;
+ unsigned chain_len;
+};
+
+static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg)
+{
+ return ioread32(dev->base_addr + reg);
+}
+
+static inline void pch_udc_writel(struct pch_udc_dev *dev,
+ unsigned long val, unsigned long reg)
+{
+ iowrite32(val, dev->base_addr + reg);
+}
+
+static inline void pch_udc_bit_set(struct pch_udc_dev *dev,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_writel(dev, pch_udc_readl(dev, reg) | bitmask, reg);
+}
+
+static inline void pch_udc_bit_clr(struct pch_udc_dev *dev,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_writel(dev, pch_udc_readl(dev, reg) & ~(bitmask), reg);
+}
+
+static inline u32 pch_udc_ep_readl(struct pch_udc_ep *ep, unsigned long reg)
+{
+ return ioread32(ep->dev->base_addr + ep->offset_addr + reg);
+}
+
+static inline void pch_udc_ep_writel(struct pch_udc_ep *ep,
+ unsigned long val, unsigned long reg)
+{
+ iowrite32(val, ep->dev->base_addr + ep->offset_addr + reg);
+}
+
+static inline void pch_udc_ep_bit_set(struct pch_udc_ep *ep,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) | bitmask, reg);
+}
+
+static inline void pch_udc_ep_bit_clr(struct pch_udc_ep *ep,
+ unsigned long reg,
+ unsigned long bitmask)
+{
+ pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) & ~(bitmask), reg);
+}
+
+/**
+ * pch_udc_csr_busy() - Wait till idle.
+ * @dev: Reference to pch_udc_dev structure
+ */
+static void pch_udc_csr_busy(struct pch_udc_dev *dev)
+{
+ unsigned int count = 200;
+
+ /* Wait till idle */
+ while ((pch_udc_readl(dev, UDC_CSR_BUSY_ADDR) & UDC_CSR_BUSY)
+ && --count)
+ cpu_relax();
+ if (!count)
+ dev_err(&dev->pdev->dev, "%s: wait error\n", __func__);
+}
+
+/**
+ * pch_udc_write_csr() - Write the command and status registers.
+ * @dev: Reference to pch_udc_dev structure
+ * @val: value to be written to CSR register
+ * @addr: address of CSR register
+ */
+static void pch_udc_write_csr(struct pch_udc_dev *dev, unsigned long val,
+ unsigned int ep)
+{
+ unsigned long reg = PCH_UDC_CSR(ep);
+
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ pch_udc_writel(dev, val, reg);
+ pch_udc_csr_busy(dev); /* Wait till idle */
+}
+
+/**
+ * pch_udc_read_csr() - Read the command and status registers.
+ * @dev: Reference to pch_udc_dev structure
+ * @addr: address of CSR register
+ *
+ * Return codes: content of CSR register
+ */
+static u32 pch_udc_read_csr(struct pch_udc_dev *dev, unsigned int ep)
+{
+ unsigned long reg = PCH_UDC_CSR(ep);
+
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ pch_udc_readl(dev, reg); /* Dummy read */
+ pch_udc_csr_busy(dev); /* Wait till idle */
+ return pch_udc_readl(dev, reg);
+}
+
+/**
+ * pch_udc_rmt_wakeup() - Initiate for remote wakeup
+ * @dev: Reference to pch_udc_dev structure
+ */
+static inline void pch_udc_rmt_wakeup(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+ mdelay(1);
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_get_frame() - Get the current frame from device status register
+ * @dev: Reference to pch_udc_dev structure
+ * Retern current frame
+ */
+static inline int pch_udc_get_frame(struct pch_udc_dev *dev)
+{
+ u32 frame = pch_udc_readl(dev, UDC_DEVSTS_ADDR);
+ return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_SHIFT;
+}
+
+/**
+ * pch_udc_clear_selfpowered() - Clear the self power control
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_clear_selfpowered(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_clr(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_selfpowered() - Set the self power control
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_set_selfpowered(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_disconnect() - Set the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ */
+static inline void pch_udc_set_disconnect(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+}
+
+/**
+ * pch_udc_clear_disconnect() - Clear the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ */
+static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
+{
+ /* Clear the disconnect */
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+ mdelay(1);
+ /* Resume USB signalling */
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_vbus_session() - set or clearr the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ * @is_active: Parameter specifying the action
+ * 0: indicating VBUS power is ending
+ * !0: indicating VBUS power is starting
+ */
+static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
+ int is_active)
+{
+ if (is_active)
+ pch_udc_clear_disconnect(dev);
+ else
+ pch_udc_set_disconnect(dev);
+}
+
+/**
+ * pch_udc_ep_set_stall() - Set the stall of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static void pch_udc_ep_set_stall(struct pch_udc_ep *ep)
+{
+ if (ep->in) {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ } else {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ }
+}
+
+/**
+ * pch_udc_ep_clear_stall() - Clear the stall of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_clear_stall(struct pch_udc_ep *ep)
+{
+ /* Clear the stall */
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S);
+ /* Clear NAK by writing CNAK */
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK);
+}
+
+/**
+ * pch_udc_ep_set_trfr_type() - Set the transfer type of endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @type: Type of endpoint
+ */
+static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep,
+ u8 type)
+{
+ pch_udc_ep_writel(ep, ((type << UDC_EPCTL_ET_SHIFT) &
+ UDC_EPCTL_ET_MASK), UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @buf_size: The buffer size
+ */
+static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
+ u32 buf_size, u32 ep_in)
+{
+ u32 data;
+ if (ep_in) {
+ data = pch_udc_ep_readl(ep, UDC_BUFIN_FRAMENUM_ADDR);
+ data = (data & 0xffff0000) | (buf_size & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFIN_FRAMENUM_ADDR);
+ } else {
+ data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR);
+ data = (buf_size << 16) | (data & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR);
+ }
+}
+
+/**
+ * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @pkt_size: The packet size
+ */
+static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size)
+{
+ u32 data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR);
+ data = (data & 0xffff0000) | (pkt_size & 0xffff);
+ pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_subptr() - Set the Setup buffer pointer for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @addr: Address of the register
+ */
+static inline void pch_udc_ep_set_subptr(struct pch_udc_ep *ep, u32 addr)
+{
+ pch_udc_ep_writel(ep, addr, UDC_SUBPTR_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_ddptr() - Set the Data descriptor pointer for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @addr: Address of the register
+ */
+static inline void pch_udc_ep_set_ddptr(struct pch_udc_ep *ep, u32 addr)
+{
+ pch_udc_ep_writel(ep, addr, UDC_DESPTR_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_pd() - Set the poll demand bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_pd(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_P);
+}
+
+/**
+ * pch_udc_ep_set_rrdy() - Set the receive ready bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_rrdy(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_ep_clear_rrdy() - Clear the receive ready bit for the endpoint
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_clear_rrdy(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_set_dma() - Set the 'TDE' or RDE bit of device control
+ * register depending on the direction specified
+ * @dev: Reference to structure of type pch_udc_regs
+ * @dir: whether Tx or Rx
+ * DMA_DIR_RX: Receive
+ * DMA_DIR_TX: Transmit
+ */
+static inline void pch_udc_set_dma(struct pch_udc_dev *dev, int dir)
+{
+ if (dir == DMA_DIR_RX)
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE);
+ else if (dir == DMA_DIR_TX)
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE);
+}
+
+/**
+ * pch_udc_clear_dma() - Clear the 'TDE' or RDE bit of device control
+ * register depending on the direction specified
+ * @dev: Reference to structure of type pch_udc_regs
+ * @dir: Whether Tx or Rx
+ * DMA_DIR_RX: Receive
+ * DMA_DIR_TX: Transmit
+ */
+static inline void pch_udc_clear_dma(struct pch_udc_dev *dev, int dir)
+{
+ if (dir == DMA_DIR_RX)
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE);
+ else if (dir == DMA_DIR_TX)
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE);
+}
+
+/**
+ * pch_udc_set_csr_done() - Set the device control register
+ * CSR done field (bit 13)
+ * @dev: reference to structure of type pch_udc_regs
+ */
+static inline void pch_udc_set_csr_done(struct pch_udc_dev *dev)
+{
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_CSR_DONE);
+}
+
+/**
+ * pch_udc_disable_interrupts() - Disables the specified interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to disable interrupts
+ */
+static inline void pch_udc_disable_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_enable_interrupts() - Enable the specified interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to enable interrupts
+ */
+static inline void pch_udc_enable_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_disable_ep_interrupts() - Disable endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to disable interrupts
+ */
+static inline void pch_udc_disable_ep_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_enable_ep_interrupts() - Enable endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @mask: Mask to enable interrupts
+ */
+static inline void pch_udc_enable_ep_interrupts(struct pch_udc_dev *dev,
+ u32 mask)
+{
+ pch_udc_bit_clr(dev, UDC_EPIRQMSK_ADDR, mask);
+}
+
+/**
+ * pch_udc_read_device_interrupts() - Read the device interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The device interrupts
+ */
+static inline u32 pch_udc_read_device_interrupts(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_DEVIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_write_device_interrupts() - Write device interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @val: The value to be written to interrupt register
+ */
+static inline void pch_udc_write_device_interrupts(struct pch_udc_dev *dev,
+ u32 val)
+{
+ pch_udc_writel(dev, val, UDC_DEVIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_interrupts() - Read the endpoint interrupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The endpoint interrupt
+ */
+static inline u32 pch_udc_read_ep_interrupts(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_EPIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_write_ep_interrupts() - Clear endpoint interupts
+ * @dev: Reference to structure of type pch_udc_regs
+ * @val: The value to be written to interrupt register
+ */
+static inline void pch_udc_write_ep_interrupts(struct pch_udc_dev *dev,
+ u32 val)
+{
+ pch_udc_writel(dev, val, UDC_EPIRQSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_device_status() - Read the device status
+ * @dev: Reference to structure of type pch_udc_regs
+ * Retern The device status
+ */
+static inline u32 pch_udc_read_device_status(struct pch_udc_dev *dev)
+{
+ return pch_udc_readl(dev, UDC_DEVSTS_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_control() - Read the endpoint control
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint control register value
+ */
+static inline u32 pch_udc_read_ep_control(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_readl(ep, UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_clear_ep_control() - Clear the endpoint control register
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint control register value
+ */
+static inline void pch_udc_clear_ep_control(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_writel(ep, 0, UDC_EPCTL_ADDR);
+}
+
+/**
+ * pch_udc_read_ep_status() - Read the endpoint status
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * Retern The endpoint status
+ */
+static inline u32 pch_udc_read_ep_status(struct pch_udc_ep *ep)
+{
+ return pch_udc_ep_readl(ep, UDC_EPSTS_ADDR);
+}
+
+/**
+ * pch_udc_clear_ep_status() - Clear the endpoint status
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ * @stat: Endpoint status
+ */
+static inline void pch_udc_clear_ep_status(struct pch_udc_ep *ep,
+ u32 stat)
+{
+ return pch_udc_ep_writel(ep, stat, UDC_EPSTS_ADDR);
+}
+
+/**
+ * pch_udc_ep_set_nak() - Set the bit 7 (SNAK field)
+ * of the endpoint control register
+ * @ep: Reference to structure of type pch_udc_ep_regs
+ */
+static inline void pch_udc_ep_set_nak(struct pch_udc_ep *ep)
+{
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_SNAK);
+}
+
+/**
+ * pch_udc_ep_clear_nak() - Set the bit 8 (CNAK field)
+ * of the endpoint control register
+ * @ep: reference to structure of type pch_udc_ep_regs
+ */
+static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep)
+{
+ unsigned int loopcnt = 0;
+ struct pch_udc_dev *dev = ep->dev;
+
+ if (!(pch_udc_ep_readl(ep, UDC_EPCTL_ADDR) & UDC_EPCTL_NAK))
+ return;
+ if (!ep->in) {
+ loopcnt = 10000;
+ while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
+ --loopcnt)
+ udelay(5);
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "%s: RxFIFO not Empty\n",
+ __func__);
+ }
+ loopcnt = 10000;
+ while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_NAK) && --loopcnt) {
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK);
+ udelay(5);
+ }
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "%s: Clear NAK not set for ep%d%s\n",
+ __func__, ep->num, (ep->in ? "in" : "out"));
+}
+
+/**
+ * pch_udc_ep_fifo_flush() - Flush the endpoint fifo
+ * @ep: reference to structure of type pch_udc_ep_regs
+ * @dir: direction of endpoint
+ * 0: endpoint is OUT
+ * !0: endpoint is IN
+ */
+static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir)
+{
+ unsigned int loopcnt = 0;
+ struct pch_udc_dev *dev = ep->dev;
+
+ if (dir) { /* IN ep */
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
+ return;
+ }
+
+ if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP)
+ return;
+ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
+ /* Wait for RxFIFO Empty */
+ loopcnt = 10000;
+ while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
+ --loopcnt)
+ udelay(5);
+ if (!loopcnt)
+ dev_err(&dev->pdev->dev, "RxFIFO not Empty\n");
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
+}
+
+/**
+ * pch_udc_ep_enable() - This api enables endpoint
+ * @regs: Reference to structure pch_udc_ep_regs
+ * @desc: endpoint descriptor
+ */
+static void pch_udc_ep_enable(struct pch_udc_ep *ep,
+ struct pch_udc_cfg_data *cfg,
+ const struct usb_endpoint_descriptor *desc)
+{
+ u32 val = 0;
+ u32 buff_size = 0;
+
+ pch_udc_ep_set_trfr_type(ep, desc->bmAttributes);
+ if (ep->in)
+ buff_size = UDC_EPIN_BUFF_SIZE;
+ else
+ buff_size = UDC_EPOUT_BUFF_SIZE;
+ pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
+ pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
+ pch_udc_ep_set_nak(ep);
+ pch_udc_ep_fifo_flush(ep, ep->in);
+ /* Configure the endpoint */
+ val = ep->num << UDC_CSR_NE_NUM_SHIFT | ep->in << UDC_CSR_NE_DIR_SHIFT |
+ ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) <<
+ UDC_CSR_NE_TYPE_SHIFT) |
+ (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
+ (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
+ (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
+ le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
+
+ if (ep->in)
+ pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
+ else
+ pch_udc_write_csr(ep->dev, val, UDC_EPOUT_IDX(ep->num));
+}
+
+/**
+ * pch_udc_ep_disable() - This api disables endpoint
+ * @regs: Reference to structure pch_udc_ep_regs
+ */
+static void pch_udc_ep_disable(struct pch_udc_ep *ep)
+{
+ if (ep->in) {
+ /* flush the fifo */
+ pch_udc_ep_writel(ep, UDC_EPCTL_F, UDC_EPCTL_ADDR);
+ /* set NAK */
+ pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR);
+ pch_udc_ep_bit_set(ep, UDC_EPSTS_ADDR, UDC_EPSTS_IN);
+ } else {
+ /* set NAK */
+ pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR);
+ }
+ /* reset desc pointer */
+ pch_udc_ep_writel(ep, 0, UDC_DESPTR_ADDR);
+}
+
+/**
+ * pch_udc_wait_ep_stall() - Wait EP stall.
+ * @dev: Reference to pch_udc_dev structure
+ */
+static void pch_udc_wait_ep_stall(struct pch_udc_ep *ep)
+{
+ unsigned int count = 10000;
+
+ /* Wait till idle */
+ while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_S) && --count)
+ udelay(5);
+ if (!count)
+ dev_err(&ep->dev->pdev->dev, "%s: wait error\n", __func__);
+}
+
+/**
+ * pch_udc_init() - This API initializes usb device controller
+ * @dev: Rreference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev)
+{
+ if (NULL == dev) {
+ pr_err("%s: Invalid address\n", __func__);
+ return;
+ }
+ /* Soft Reset and Reset PHY */
+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+ pch_udc_writel(dev, UDC_SRST | UDC_PSRST, UDC_SRST_ADDR);
+ mdelay(1);
+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+ pch_udc_writel(dev, 0x00, UDC_SRST_ADDR);
+ mdelay(1);
+ /* mask and clear all device interrupts */
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK);
+ pch_udc_bit_set(dev, UDC_DEVIRQSTS_ADDR, UDC_DEVINT_MSK);
+
+ /* mask and clear all ep interrupts */
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+ pch_udc_bit_set(dev, UDC_EPIRQSTS_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+
+ /* enable dynamic CSR programmingi, self powered and device speed */
+ if (speed_fs)
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG |
+ UDC_DEVCFG_SP | UDC_DEVCFG_SPD_FS);
+ else /* defaul high speed */
+ pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG |
+ UDC_DEVCFG_SP | UDC_DEVCFG_SPD_HS);
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR,
+ (PCH_UDC_THLEN << UDC_DEVCTL_THLEN_SHIFT) |
+ (PCH_UDC_BRLEN << UDC_DEVCTL_BRLEN_SHIFT) |
+ UDC_DEVCTL_MODE | UDC_DEVCTL_BREN |
+ UDC_DEVCTL_THE);
+}
+
+/**
+ * pch_udc_exit() - This API exit usb device controller
+ * @dev: Reference to pch_udc_regs structure
+ */
+static void pch_udc_exit(struct pch_udc_dev *dev)
+{
+ /* mask all device interrupts */
+ pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK);
+ /* mask all ep interrupts */
+ pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL);
+ /* put device in disconnected state */
+ pch_udc_set_disconnect(dev);
+}
+
+/**
+ * pch_udc_pcd_get_frame() - This API is invoked to get the current frame number
+ * @gadget: Reference to the gadget driver
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_get_frame(struct usb_gadget *gadget)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ return pch_udc_get_frame(dev);
+}
+
+/**
+ * pch_udc_pcd_wakeup() - This API is invoked to initiate a remote wakeup
+ * @gadget: Reference to the gadget driver
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_wakeup(struct usb_gadget *gadget)
+{
+ struct pch_udc_dev *dev;
+ unsigned long flags;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ spin_lock_irqsave(&dev->lock, flags);
+ pch_udc_rmt_wakeup(dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_selfpowered() - This API is invoked to specify whether the device
+ * is self powered or not
+ * @gadget: Reference to the gadget driver
+ * @value: Specifies self powered or not
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ if (value)
+ pch_udc_set_selfpowered(dev);
+ else
+ pch_udc_clear_selfpowered(dev);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_pullup() - This API is invoked to make the device
+ * visible/invisible to the host
+ * @gadget: Reference to the gadget driver
+ * @is_on: Specifies whether the pull up is made active or inactive
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ pch_udc_vbus_session(dev, is_on);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_vbus_session() - This API is used by a driver for an external
+ * transceiver (or GPIO) that
+ * detects a VBUS power session starting/ending
+ * @gadget: Reference to the gadget driver
+ * @is_active: specifies whether the session is starting or ending
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: If the gadget passed is NULL
+ */
+static int pch_udc_pcd_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct pch_udc_dev *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct pch_udc_dev, gadget);
+ pch_udc_vbus_session(dev, is_active);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_vbus_draw() - This API is used by gadget drivers during
+ * SET_CONFIGURATION calls to
+ * specify how much power the device can consume
+ * @gadget: Reference to the gadget driver
+ * @mA: specifies the current limit in 2mA unit
+ *
+ * Return codes:
+ * -EINVAL: If the gadget passed is NULL
+ * -EOPNOTSUPP:
+ */
+static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
+{
+ return -EOPNOTSUPP;
+}
+
+static const struct usb_gadget_ops pch_udc_ops = {
+ .get_frame = pch_udc_pcd_get_frame,
+ .wakeup = pch_udc_pcd_wakeup,
+ .set_selfpowered = pch_udc_pcd_selfpowered,
+ .pullup = pch_udc_pcd_pullup,
+ .vbus_session = pch_udc_pcd_vbus_session,
+ .vbus_draw = pch_udc_pcd_vbus_draw,
+};
+
+/**
+ * complete_req() - This API is invoked from the driver when processing
+ * of a request is complete
+ * @ep: Reference to the endpoint structure
+ * @req: Reference to the request structure
+ * @status: Indicates the success/failure of completion
+ */
+static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
+ int status)
+{
+ struct pch_udc_dev *dev;
+ unsigned halted = ep->halted;
+
+ list_del_init(&req->queue);
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ dev = ep->dev;
+ if (req->dma_mapped) {
+ 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_mapped = 0;
+ req->req.dma = DMA_ADDR_INVALID;
+ }
+ ep->halted = 1;
+ spin_unlock(&dev->lock);
+ if (!ep->in)
+ pch_udc_ep_clear_rrdy(ep);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->halted = halted;
+}
+
+/**
+ * empty_req_queue() - This API empties the request queue of an endpoint
+ * @ep: Reference to the endpoint structure
+ */
+static void empty_req_queue(struct pch_udc_ep *ep)
+{
+ struct pch_udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ complete_req(ep, req, -ESHUTDOWN); /* Remove from list */
+ }
+}
+
+/**
+ * pch_udc_free_dma_chain() - This function frees the DMA chain created
+ * for the request
+ * @dev Reference to the driver structure
+ * @req Reference to the request to be freed
+ *
+ * Return codes:
+ * 0: Success
+ */
+static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
+ struct pch_udc_request *req)
+{
+ struct pch_udc_data_dma_desc *td = req->td_data;
+ unsigned i = req->chain_len;
+
+ for (; i > 1; --i) {
+ dma_addr_t addr = (dma_addr_t)td->next;
+ /* do not free first desc., will be done by free for request */
+ td = phys_to_virt(addr);
+ pci_pool_free(dev->data_requests, td, addr);
+ }
+}
+
+/**
+ * pch_udc_create_dma_chain() - This function creates or reinitializes
+ * a DMA chain
+ * @ep: Reference to the endpoint structure
+ * @req: Reference to the request
+ * @buf_len: The buffer length
+ * @gfp_flags: Flags to be used while mapping the data buffer
+ *
+ * Return codes:
+ * 0: success,
+ * -ENOMEM: pci_pool_alloc invocation fails
+ */
+static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
+ struct pch_udc_request *req,
+ unsigned long buf_len,
+ gfp_t gfp_flags)
+{
+ struct pch_udc_data_dma_desc *td = req->td_data, *last;
+ unsigned long bytes = req->req.length, i = 0;
+ dma_addr_t dma_addr;
+ unsigned len = 1;
+
+ if (req->chain_len > 1)
+ pch_udc_free_dma_chain(ep->dev, req);
+
+ for (; ; bytes -= buf_len, ++len) {
+ if (ep->in)
+ td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes);
+ else
+ td->status = PCH_UDC_BS_HST_BSY;
+
+ if (bytes <= buf_len)
+ break;
+
+ last = td;
+ td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
+ &dma_addr);
+ if (!td)
+ goto nomem;
+
+ i += buf_len;
+ td->dataptr = req->req.dma + i;
+ last->next = dma_addr;
+ }
+
+ req->td_data_last = td;
+ td->status |= PCH_UDC_DMA_LAST;
+ td->next = req->td_data_phys;
+ req->chain_len = len;
+ return 0;
+
+nomem:
+ if (len > 1) {
+ req->chain_len = len;
+ pch_udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = 1;
+ return -ENOMEM;
+}
+
+/**
+ * prepare_dma() - This function creates and initializes the DMA chain
+ * for the request
+ * @ep: Reference to the endpoint structure
+ * @req: Reference to the request
+ * @gfp: Flag to be used while mapping the data buffer
+ *
+ * Return codes:
+ * 0: Success
+ * Other 0: linux error number on failure
+ */
+static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req,
+ gfp_t gfp)
+{
+ int retval;
+
+ req->td_data->dataptr = req->req.dma;
+ req->td_data->status |= PCH_UDC_DMA_LAST;
+ /* Allocate and create a DMA chain */
+ retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+ if (retval) {
+ pr_err("%s: could not create DMA chain: %d\n",
+ __func__, retval);
+ return retval;
+ }
+ if (!ep->in)
+ return 0;
+ if (req->req.length <= ep->ep.maxpacket)
+ req->td_data->status = PCH_UDC_DMA_LAST | PCH_UDC_BS_HST_BSY |
+ req->req.length;
+ /* if bytes < max packet then tx bytes must
+ * be written in packet per buffer mode
+ */
+ if ((req->req.length < ep->ep.maxpacket) || !ep->num)
+ req->td_data->status = (req->td_data->status &
+ ~PCH_UDC_RXTX_BYTES) | req->req.length;
+ req->td_data->status = (req->td_data->status &
+ ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_BSY;
+ return 0;
+}
+
+/**
+ * process_zlp() - This function process zero length packets
+ * from the gadget driver
+ * @ep: Reference to the endpoint structure
+ * @req: Reference to the request
+ */
+static void process_zlp(struct pch_udc_ep *ep, struct pch_udc_request *req)
+{
+ struct pch_udc_dev *dev = ep->dev;
+
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+
+ /* if set_config or set_intf is waiting for ack by zlp
+ * then set CSR_DONE
+ */
+ if (dev->set_cfg_not_acked) {
+ pch_udc_set_csr_done(dev);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (!dev->stall && dev->waiting_zlp_ack) {
+ pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX]));
+ dev->waiting_zlp_ack = 0;
+ }
+}
+
+/**
+ * pch_udc_start_rxrequest() - This function starts the receive requirement.
+ * @ep: Reference to the endpoint structure
+ * @req: Reference to the request structure
+ */
+static void pch_udc_start_rxrequest(struct pch_udc_ep *ep,
+ struct pch_udc_request *req)
+{
+ struct pch_udc_data_dma_desc *td_data;
+
+ pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
+ td_data = req->td_data;
+ ep->td_data = req->td_data;
+ /* Set the status bits for all descriptors */
+ while (1) {
+ td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
+ PCH_UDC_BS_HST_RDY;
+ if ((td_data->status & PCH_UDC_DMA_LAST) == PCH_UDC_DMA_LAST)
+ break;
+ td_data = phys_to_virt(td_data->next);
+ }
+ /* Write the descriptor pointer */
+ pch_udc_ep_set_ddptr(ep, req->td_data_phys);
+ req->dma_going = 1;
+ pch_udc_enable_ep_interrupts(ep->dev, UDC_EPINT_OUT_EP0 << ep->num);
+ pch_udc_set_dma(ep->dev, DMA_DIR_RX);
+ pch_udc_ep_clear_nak(ep);
+ pch_udc_ep_set_rrdy(ep);
+}
+
+/**
+ * pch_udc_pcd_ep_enable() - This API enables the endpoint. It is called
+ * from gadget driver
+ * @usbep: Reference to the USB endpoint structure
+ * @desc: Reference to the USB endpoint descriptor structure
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL:
+ * -ESHUTDOWN:
+ */
+static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_dev *dev;
+ unsigned long iflags;
+
+ if (!usbep || (usbep->name == ep0_string) || !desc ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT) || !desc->wMaxPacketSize)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+ spin_lock_irqsave(&dev->lock, iflags);
+ ep->desc = desc;
+ ep->halted = 0;
+ pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return 0;
+}
+
+/**
+ * pch_udc_pcd_ep_disable() - This API disables endpoint and is called
+ * from gadget driver
+ * @usbep Reference to the USB endpoint structure
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL:
+ */
+static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_dev *dev;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if ((usbep->name == ep0_string) || !ep->desc)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ empty_req_queue(ep);
+ ep->halted = 1;
+ pch_udc_ep_disable(ep);
+ pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
+ ep->desc = NULL;
+ INIT_LIST_HEAD(&ep->queue);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+ return 0;
+}
+
+/**
+ * pch_udc_alloc_request() - This function allocates request structure.
+ * It is called by gadget driver
+ * @usbep: Reference to the USB endpoint structure
+ * @gfp: Flag to be used while allocating memory
+ *
+ * Return codes:
+ * NULL: Failure
+ * Allocated address: Success
+ */
+static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
+ gfp_t gfp)
+{
+ struct pch_udc_request *req;
+ struct pch_udc_ep *ep;
+ struct pch_udc_data_dma_desc *dma_desc;
+ struct pch_udc_dev *dev;
+
+ if (!usbep)
+ return NULL;
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ req = kzalloc(sizeof *req, gfp);
+ if (!req)
+ return NULL;
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+ if (!ep->dev->dma_addr)
+ return &req->req;
+ /* ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+ &req->td_data_phys);
+ if (NULL == dma_desc) {
+ kfree(req);
+ return NULL;
+ }
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status |= PCH_UDC_BS_HST_BSY;
+ dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
+ req->td_data = dma_desc;
+ req->td_data_last = dma_desc;
+ req->chain_len = 1;
+ return &req->req;
+}
+
+/**
+ * pch_udc_free_request() - This function frees request structure.
+ * It is called by gadget driver
+ * @usbep: Reference to the USB endpoint structure
+ * @usbreq: Reference to the USB request
+ */
+static void pch_udc_free_request(struct usb_ep *usbep,
+ struct usb_request *usbreq)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_request *req;
+ struct pch_udc_dev *dev;
+
+ if (!usbep || !usbreq)
+ return;
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ req = container_of(usbreq, struct pch_udc_request, req);
+ dev = ep->dev;
+ if (!list_empty(&req->queue))
+ dev_err(&dev->pdev->dev, "%s: %s req=0x%p queue not empty\n",
+ __func__, usbep->name, req);
+ if (req->td_data != NULL) {
+ if (req->chain_len > 1)
+ pch_udc_free_dma_chain(ep->dev, req);
+ pci_pool_free(ep->dev->data_requests, req->td_data,
+ req->td_data_phys);
+ }
+ kfree(req);
+}
+
+/**
+ * pch_udc_pcd_queue() - This function queues a request packet. It is called
+ * by gadget driver
+ * @usbep: Reference to the USB endpoint structure
+ * @usbreq: Reference to the USB request
+ * @gfp: Flag to be used while mapping the data buffer
+ *
+ * Return codes:
+ * 0: Success
+ * linux error number: Failure
+ */
+static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
+ gfp_t gfp)
+{
+ int retval = 0;
+ struct pch_udc_ep *ep;
+ struct pch_udc_dev *dev;
+ struct pch_udc_request *req;
+ unsigned long iflags;
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf)
+ return -EINVAL;
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if (!ep->desc && ep->num)
+ return -EINVAL;
+ req = container_of(usbreq, struct pch_udc_request, req);
+ if (!list_empty(&req->queue))
+ return -EINVAL;
+ if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ /* map the buffer for dma */
+ if (usbreq->length &&
+ ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
+ 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_mapped = 1;
+ }
+ if (usbreq->length > 0) {
+ retval = prepare_dma(ep, req, gfp);
+ if (retval)
+ goto probe_end;
+ }
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+ if (list_empty(&ep->queue) && !ep->halted) {
+ /* no pending transfer, so start this req */
+ if (!usbreq->length) {
+ process_zlp(ep, req);
+ retval = 0;
+ goto probe_end;
+ }
+ if (!ep->in) {
+ pch_udc_start_rxrequest(ep, req);
+ } else {
+ /*
+ * For IN trfr the descriptors will be programmed and
+ * P bit will be set when
+ * we get an IN token
+ */
+ pch_udc_wait_ep_stall(ep);
+ pch_udc_ep_clear_nak(ep);
+ pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num));
+ pch_udc_set_dma(dev, DMA_DIR_TX);
+ }
+ }
+ /* Now add this request to the ep's pending requests */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+
+probe_end:
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return retval;
+}
+
+/**
+ * pch_udc_pcd_dequeue() - This function de-queues a request packet.
+ * It is called by gadget driver
+ * @usbep: Reference to the USB endpoint structure
+ * @usbreq: Reference to the USB request
+ *
+ * Return codes:
+ * 0: Success
+ * linux error number: Failure
+ */
+static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
+ struct usb_request *usbreq)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_request *req;
+ struct pch_udc_dev *dev;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if (!usbep || !usbreq || (!ep->desc && ep->num))
+ return ret;
+ req = container_of(usbreq, struct pch_udc_request, req);
+ spin_lock_irqsave(&ep->dev->lock, flags);
+ /* make sure it's still queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == usbreq) {
+ pch_udc_ep_set_nak(ep);
+ if (!list_empty(&req->queue))
+ complete_req(ep, req, -ECONNRESET);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return ret;
+}
+
+/**
+ * pch_udc_pcd_set_halt() - This function Sets or clear the endpoint halt
+ * feature
+ * @usbep: Reference to the USB endpoint structure
+ * @halt: Specifies whether to set or clear the feature
+ *
+ * Return codes:
+ * 0: Success
+ * linux error number: Failure
+ */
+static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_dev *dev;
+ unsigned long iflags;
+ int ret;
+
+ if (!usbep)
+ return -EINVAL;
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if (!ep->desc && !ep->num)
+ return -EINVAL;
+ if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ if (list_empty(&ep->queue)) {
+ if (halt) {
+ if (ep->num == PCH_UDC_EP0)
+ ep->dev->stall = 1;
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in,
+ ep->num));
+ } else {
+ pch_udc_ep_clear_stall(ep);
+ }
+ ret = 0;
+ } else {
+ ret = -EAGAIN;
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return ret;
+}
+
+/**
+ * pch_udc_pcd_set_wedge() - This function Sets or clear the endpoint
+ * halt feature
+ * @usbep: Reference to the USB endpoint structure
+ * @halt: Specifies whether to set or clear the feature
+ *
+ * Return codes:
+ * 0: Success
+ * linux error number: Failure
+ */
+static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_dev *dev;
+ unsigned long iflags;
+ int ret;
+
+ if (!usbep)
+ return -EINVAL;
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ dev = ep->dev;
+ if (!ep->desc && !ep->num)
+ return -EINVAL;
+ if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ } else {
+ if (ep->num == PCH_UDC_EP0)
+ ep->dev->stall = 1;
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ ep->dev->prot_stall = 1;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return ret;
+}
+
+/**
+ * pch_udc_pcd_fifo_flush() - This function Flush the FIFO of specified endpoint
+ * @usbep: Reference to the USB endpoint structure
+ */
+static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep)
+{
+ struct pch_udc_ep *ep;
+
+ if (!usbep)
+ return;
+
+ ep = container_of(usbep, struct pch_udc_ep, ep);
+ if (ep->desc || !ep->num)
+ pch_udc_ep_fifo_flush(ep, ep->in);
+}
+
+static const struct usb_ep_ops pch_udc_ep_ops = {
+ .enable = pch_udc_pcd_ep_enable,
+ .disable = pch_udc_pcd_ep_disable,
+ .alloc_request = pch_udc_alloc_request,
+ .free_request = pch_udc_free_request,
+ .queue = pch_udc_pcd_queue,
+ .dequeue = pch_udc_pcd_dequeue,
+ .set_halt = pch_udc_pcd_set_halt,
+ .set_wedge = pch_udc_pcd_set_wedge,
+ .fifo_status = NULL,
+ .fifo_flush = pch_udc_pcd_fifo_flush,
+};
+
+/**
+ * pch_udc_init_setup_buff() - This function initializes the SETUP buffer
+ * @td_stp: Reference to the SETP buffer structure
+ */
+static void pch_udc_init_setup_buff(struct pch_udc_stp_dma_desc *td_stp)
+{
+ static u32 pky_marker;
+
+ if (!td_stp)
+ return;
+ td_stp->reserved = ++pky_marker;
+ memset(&td_stp->request, 0xFF, sizeof td_stp->request);
+ td_stp->status = PCH_UDC_BS_HST_RDY;
+}
+
+/**
+ * pch_udc_start_next_txrequest() - This function starts
+ * the next transmission requirement
+ * @ep: Reference to the endpoint structure
+ */
+static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
+{
+ struct pch_udc_request *req;
+ struct pch_udc_data_dma_desc *td_data;
+
+ if (pch_udc_read_ep_control(ep) & UDC_EPCTL_P)
+ return;
+
+ if (list_empty(&ep->queue))
+ return;
+
+ /* next request */
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ if (req->dma_going)
+ return;
+ if (!req->td_data)
+ return;
+ pch_udc_wait_ep_stall(ep);
+ req->dma_going = 1;
+ pch_udc_ep_set_ddptr(ep, 0);
+ td_data = req->td_data;
+ while (1) {
+ td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
+ PCH_UDC_BS_HST_RDY;
+ if ((td_data->status & PCH_UDC_DMA_LAST) == PCH_UDC_DMA_LAST)
+ break;
+ td_data = phys_to_virt(td_data->next);
+ }
+ pch_udc_ep_set_ddptr(ep, req->td_data_phys);
+ pch_udc_set_dma(ep->dev, DMA_DIR_TX);
+ pch_udc_ep_set_pd(ep);
+ pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
+ pch_udc_ep_clear_nak(ep);
+}
+
+/**
+ * pch_udc_complete_transfer() - This function completes a transfer
+ * @ep: Reference to the endpoint structure
+ */
+static void pch_udc_complete_transfer(struct pch_udc_ep *ep)
+{
+ struct pch_udc_request *req;
+ struct pch_udc_dev *dev = ep->dev;
+
+ if (list_empty(&ep->queue))
+ return;
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
+ PCH_UDC_BS_DMA_DONE)
+ return;
+ if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
+ PCH_UDC_RTS_SUCC) {
+ dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
+ "epstatus=0x%08x\n",
+ (req->td_data_last->status & PCH_UDC_RXTX_STS),
+ (int)(ep->epsts));
+ return;
+ }
+
+ req->req.actual = req->req.length;
+ req->td_data_last->status = PCH_UDC_BS_HST_BSY | PCH_UDC_DMA_LAST;
+ req->td_data->status = PCH_UDC_BS_HST_BSY | PCH_UDC_DMA_LAST;
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+ if (!list_empty(&ep->queue)) {
+ pch_udc_wait_ep_stall(ep);
+ pch_udc_ep_clear_nak(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ } else {
+ pch_udc_disable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ }
+}
+
+/**
+ * pch_udc_complete_receiver() - This function completes a receiver
+ * @ep: Reference to the endpoint structure
+ */
+static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
+{
+ struct pch_udc_request *req;
+ struct pch_udc_dev *dev = ep->dev;
+ unsigned int count;
+
+ if (list_empty(&ep->queue))
+ return;
+
+ /* next request */
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
+ PCH_UDC_BS_DMA_DONE)
+ return;
+ pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
+ if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
+ PCH_UDC_RTS_SUCC) {
+ dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
+ "epstatus=0x%08x\n",
+ (req->td_data_last->status & PCH_UDC_RXTX_STS),
+ (int)(ep->epsts));
+ return;
+ }
+ count = req->td_data_last->status & PCH_UDC_RXTX_BYTES;
+
+ /* on 64k packets the RXBYTES field is zero */
+ if (!count && (req->req.length == UDC_DMA_MAXPACKET))
+ count = UDC_DMA_MAXPACKET;
+ req->td_data->status |= PCH_UDC_DMA_LAST;
+ req->td_data_last->status |= PCH_UDC_BS_HST_BSY;
+
+ req->dma_going = 0;
+ req->req.actual = count;
+ complete_req(ep, req, 0);
+ /* If there is a new/failed requests try that now */
+ if (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ pch_udc_start_rxrequest(ep, req);
+ }
+}
+
+/**
+ * pch_udc_svc_data_in() - This function process endpoint interrupts
+ * for IN endpoints
+ * @dev: Reference to the device structure
+ * @ep_num: Endpoint that generated the interrupt
+ */
+static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
+{
+ u32 epsts;
+ struct pch_udc_ep *ep;
+
+ ep = &dev->ep[2*ep_num];
+ epsts = ep->epsts;
+ ep->epsts = 0;
+
+ if (!(epsts & (UDC_EPSTS_IN | UDC_EPSTS_BNA | UDC_EPSTS_HE |
+ UDC_EPSTS_TDC | UDC_EPSTS_RCS | UDC_EPSTS_TXEMPTY |
+ UDC_EPSTS_RSS | UDC_EPSTS_XFERDONE)))
+ return;
+ if ((epsts & UDC_EPSTS_BNA))
+ return;
+ if (epsts & UDC_EPSTS_HE)
+ return;
+ if (epsts & UDC_EPSTS_RSS) {
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ }
+ if (epsts & UDC_EPSTS_RCS) {
+ if (!dev->prot_stall) {
+ pch_udc_ep_clear_stall(ep);
+ } else {
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ }
+ }
+ if (epsts & UDC_EPSTS_TDC)
+ pch_udc_complete_transfer(ep);
+ /* On IN interrupt, provide data if we have any */
+ if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_RSS) &&
+ !(epsts & UDC_EPSTS_TDC) && !(epsts & UDC_EPSTS_TXEMPTY))
+ pch_udc_start_next_txrequest(ep);
+}
+
+/**
+ * pch_udc_svc_data_out() - Handles interrupts from OUT endpoint
+ * @dev: Reference to the device structure
+ * @ep_num: Endpoint that generated the interrupt
+ */
+static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
+{
+ u32 epsts;
+ struct pch_udc_ep *ep;
+ struct pch_udc_request *req = NULL;
+
+ ep = &dev->ep[2*ep_num + 1];
+ epsts = ep->epsts;
+ ep->epsts = 0;
+
+ if ((epsts & UDC_EPSTS_BNA) && (!list_empty(&ep->queue))) {
+ /* next request */
+ req = list_entry(ep->queue.next, struct pch_udc_request,
+ queue);
+ if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
+ PCH_UDC_BS_DMA_DONE) {
+ if (!req->dma_going)
+ pch_udc_start_rxrequest(ep, req);
+ return;
+ }
+ }
+ if (epsts & UDC_EPSTS_HE)
+ return;
+ if (epsts & UDC_EPSTS_RSS)
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ if (epsts & UDC_EPSTS_RCS) {
+ if (!dev->prot_stall) {
+ pch_udc_ep_clear_stall(ep);
+ } else {
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ }
+ }
+ if (((epsts & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
+ UDC_EPSTS_OUT_DATA) {
+ if (ep->dev->prot_stall == 1) {
+ pch_udc_ep_set_stall(ep);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ } else {
+ pch_udc_complete_receiver(ep);
+ }
+ }
+ if (list_empty(&ep->queue))
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+}
+
+/**
+ * pch_udc_svc_control_in() - Handle Control IN endpoint interrupts
+ * @dev: Reference to the device structure
+ */
+static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
+{
+ u32 epsts;
+ struct pch_udc_ep *ep;
+
+ ep = &dev->ep[UDC_EP0IN_IDX];
+ epsts = ep->epsts;
+ ep->epsts = 0;
+
+ if (!(epsts & (UDC_EPSTS_IN | UDC_EPSTS_BNA | UDC_EPSTS_HE |
+ UDC_EPSTS_TDC | UDC_EPSTS_RCS | UDC_EPSTS_TXEMPTY |
+ UDC_EPSTS_XFERDONE)))
+ return;
+ if ((epsts & UDC_EPSTS_BNA))
+ return;
+ if (epsts & UDC_EPSTS_HE)
+ return;
+ if ((epsts & UDC_EPSTS_TDC) && (!dev->stall))
+ pch_udc_complete_transfer(ep);
+ /* On IN interrupt, provide data if we have any */
+ if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) &&
+ !(epsts & UDC_EPSTS_TXEMPTY))
+ pch_udc_start_next_txrequest(ep);
+}
+
+/**
+ * pch_udc_svc_control_out() - Routine that handle Control
+ * OUT endpoint interrupts
+ * @dev: Reference to the device structure
+ */
+static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
+{
+ u32 stat;
+ int setup_supported;
+ struct pch_udc_ep *ep;
+
+ ep = &dev->ep[UDC_EP0OUT_IDX];
+ stat = ep->epsts;
+ ep->epsts = 0;
+
+ /* If setup data */
+ if (((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
+ UDC_EPSTS_OUT_SETUP) {
+ dev->stall = 0;
+ dev->ep[UDC_EP0IN_IDX].halted = 0;
+ dev->ep[UDC_EP0OUT_IDX].halted = 0;
+ /* In data not ready */
+ pch_udc_ep_set_nak(&(dev->ep[UDC_EP0IN_IDX]));
+ dev->setup_data = ep->td_stp->request;
+ pch_udc_init_setup_buff(ep->td_stp);
+ pch_udc_clear_dma(dev, DMA_DIR_TX);
+ pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]),
+ dev->ep[UDC_EP0IN_IDX].in);
+ if ((dev->setup_data.bRequestType & USB_DIR_IN))
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep;
+ else /* OUT */
+ dev->gadget.ep0 = &ep->ep;
+ spin_unlock(&dev->lock);
+ /* If Mass storage Reset */
+ if ((dev->setup_data.bRequestType == 0x21) &&
+ (dev->setup_data.bRequest == 0xFF))
+ dev->prot_stall = 0;
+ /* call gadget with setup data received */
+ setup_supported = dev->driver->setup(&dev->gadget,
+ &dev->setup_data);
+ spin_lock(&dev->lock);
+ /* ep0 in returns data on IN phase */
+ if (setup_supported >= 0 && setup_supported <
+ UDC_EP0IN_MAX_PKT_SIZE) {
+ pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX]));
+ /* Gadget would have queued a request when
+ * we called the setup */
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+ pch_udc_ep_clear_nak(ep);
+ } else if (setup_supported < 0) {
+ /* if unsupported request, then stall */
+ pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX]));
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ dev->stall = 0;
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+ } else {
+ dev->waiting_zlp_ack = 1;
+ }
+ } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
+ UDC_EPSTS_OUT_DATA) && !dev->stall) {
+ if (list_empty(&ep->queue)) {
+ dev_err(&dev->pdev->dev, "%s: No request\n", __func__);
+ ep->td_data->status = (ep->td_data->status &
+ ~PCH_UDC_BUFF_STS) |
+ PCH_UDC_BS_HST_RDY;
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+ } else {
+ /* control write */
+ /* next function will pickuo an clear the status */
+ ep->epsts = stat;
+
+ pch_udc_svc_data_out(dev, 0);
+ /* re-program desc. pointer for possible ZLPs */
+ pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+ }
+ }
+ pch_udc_ep_set_rrdy(ep);
+}
+
+
+/**
+ * pch_udc_postsvc_epinters() - This function enables end point interrupts
+ * and clears NAK status
+ * @dev: Reference to the device structure
+ * @ep_num: End point number
+ */
+static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
+{
+ struct pch_udc_ep *ep;
+ struct pch_udc_request *req;
+
+ ep = &dev->ep[2*ep_num];
+ if (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+ pch_udc_enable_ep_interrupts(ep->dev,
+ PCH_UDC_EPINT(ep->in, ep->num));
+ pch_udc_ep_clear_nak(ep);
+ }
+}
+
+/**
+ * pch_udc_read_all_epstatus() - This function read all endpoint status
+ * @dev: Reference to the device structure
+ * @ep_intr: Status of endpoint interrupt
+ */
+static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
+{
+ int i;
+ struct pch_udc_ep *ep;
+
+ for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
+ /* IN */
+ if (ep_intr & (0x1 << i)) {
+ ep = &dev->ep[2*i];
+ ep->epsts = pch_udc_read_ep_status(ep);
+ pch_udc_clear_ep_status(ep, ep->epsts);
+ }
+ /* OUT */
+ if (ep_intr & (0x10000 << i)) {
+ ep = &dev->ep[2*i+1];
+ ep->epsts = pch_udc_read_ep_status(ep);
+ pch_udc_clear_ep_status(ep, ep->epsts);
+ }
+ }
+}
+
+/**
+ * pch_udc_activate_control_ep() - This function enables the control endpoints
+ * for traffic after a reset
+ * @dev: Reference to the device structure
+ */
+static void pch_udc_activate_control_ep(struct pch_udc_dev *dev)
+{
+ struct pch_udc_ep *ep;
+ u32 val;
+
+ /* Setup the IN endpoint */
+ ep = &dev->ep[UDC_EP0IN_IDX];
+ pch_udc_clear_ep_control(ep);
+ pch_udc_ep_fifo_flush(ep, ep->in);
+ pch_udc_ep_set_bufsz(ep, UDC_EP0IN_BUFF_SIZE, ep->in);
+ pch_udc_ep_set_maxpkt(ep, UDC_EP0IN_MAX_PKT_SIZE);
+ /* Initialize the IN EP Descriptor */
+ ep->td_data = NULL;
+ ep->td_stp = NULL;
+ ep->td_data_phys = 0;
+ ep->td_stp_phys = 0;
+
+ /* Setup the OUT endpoint */
+ ep = &dev->ep[UDC_EP0OUT_IDX];
+ pch_udc_clear_ep_control(ep);
+ pch_udc_ep_fifo_flush(ep, ep->in);
+ pch_udc_ep_set_bufsz(ep, UDC_EP0OUT_BUFF_SIZE, ep->in);
+ pch_udc_ep_set_maxpkt(ep, UDC_EP0OUT_MAX_PKT_SIZE);
+ val = UDC_EP0OUT_MAX_PKT_SIZE << UDC_CSR_NE_MAX_PKT_SHIFT;
+ pch_udc_write_csr(ep->dev, val, UDC_EP0OUT_IDX);
+
+ /* Initialize the SETUP buffer */
+ pch_udc_init_setup_buff(ep->td_stp);
+ /* Write the pointer address of dma descriptor */
+ pch_udc_ep_set_subptr(ep, ep->td_stp_phys);
+ /* Write the pointer address of Setup descriptor */
+ pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
+
+ /* Initialize the dma descriptor */
+ ep->td_data->status = PCH_UDC_DMA_LAST;
+ ep->td_data->dataptr = dev->dma_addr;
+ ep->td_data->next = ep->td_data_phys;
+
+ pch_udc_ep_clear_nak(ep);
+}
+
+
+/**
+ * pch_udc_svc_ur_interrupt() - This function handles a USB reset interrupt
+ * @dev: Reference to driver structure
+ */
+static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
+{
+ struct pch_udc_ep *ep;
+ int i;
+
+ pch_udc_clear_dma(dev, DMA_DIR_TX);
+ pch_udc_clear_dma(dev, DMA_DIR_RX);
+ /* Mask all endpoint interrupts */
+ pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
+ /* clear all endpoint interrupts */
+ pch_udc_write_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
+
+ for (i = 0; i < PCH_UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ pch_udc_clear_ep_status(ep, UDC_EPSTS_ALL_CLR_MASK);
+ pch_udc_clear_ep_control(ep);
+ pch_udc_ep_set_ddptr(ep, 0);
+ pch_udc_write_csr(ep->dev, 0x00, i);
+ }
+ dev->stall = 0;
+ dev->prot_stall = 0;
+ dev->waiting_zlp_ack = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* disable ep to empty req queue. Skip the control EP's */
+ for (i = 0; i < (PCH_UDC_USED_EP_NUM*2); i++) {
+ ep = &dev->ep[i];
+ pch_udc_ep_set_nak(ep);
+ pch_udc_ep_fifo_flush(ep, ep->in);
+ /* Complete request queue */
+ empty_req_queue(ep);
+ }
+ if (dev->driver && dev->driver->disconnect)
+ dev->driver->disconnect(&dev->gadget);
+}
+
+/**
+ * pch_udc_svc_enum_interrupt() - This function handles a USB speed enumeration
+ * done interrupt
+ * @dev: Reference to driver structure
+ */
+static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
+{
+ u32 dev_stat, dev_speed;
+ u32 speed = USB_SPEED_FULL;
+
+ dev_stat = pch_udc_read_device_status(dev);
+ dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >>
+ UDC_DEVSTS_ENUM_SPEED_SHIFT;
+ switch (dev_speed) {
+ case UDC_DEVSTS_ENUM_SPEED_HIGH:
+ speed = USB_SPEED_HIGH;
+ break;
+ case UDC_DEVSTS_ENUM_SPEED_FULL:
+ speed = USB_SPEED_FULL;
+ break;
+ case UDC_DEVSTS_ENUM_SPEED_LOW:
+ speed = USB_SPEED_LOW;
+ break;
+ default:
+ BUG();
+ }
+ dev->gadget.speed = speed;
+ pch_udc_activate_control_ep(dev);
+ pch_udc_enable_ep_interrupts(dev, UDC_EPINT_IN_EP0 | UDC_EPINT_OUT_EP0);
+ pch_udc_set_dma(dev, DMA_DIR_TX);
+ pch_udc_set_dma(dev, DMA_DIR_RX);
+ pch_udc_ep_set_rrdy(&(dev->ep[UDC_EP0OUT_IDX]));
+}
+
+/**
+ * pch_udc_svc_intf_interrupt() - This function handles a set interface
+ * interrupt
+ * @dev: Reference to driver structure
+ */
+static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
+{
+ u32 reg, dev_stat = 0;
+ int i, ret;
+
+ dev_stat = pch_udc_read_device_status(dev);
+ dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
+ UDC_DEVSTS_INTF_SHIFT;
+ dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >>
+ UDC_DEVSTS_ALT_SHIFT;
+ dev->set_cfg_not_acked = 1;
+ /* Construct the usb request for gadget driver and inform it */
+ memset(&dev->setup_data, 0 , sizeof dev->setup_data);
+ dev->setup_data.bRequest = USB_REQ_SET_INTERFACE;
+ dev->setup_data.bRequestType = USB_RECIP_INTERFACE;
+ dev->setup_data.wValue = cpu_to_le16(dev->cfg_data.cur_alt);
+ dev->setup_data.wIndex = cpu_to_le16(dev->cfg_data.cur_intf);
+ /* programm the Endpoint Cfg registers */
+ /* Only one end point cfg register */
+ reg = pch_udc_read_csr(dev, UDC_EP0OUT_IDX);
+ reg = (reg & ~UDC_CSR_NE_INTF_MASK) |
+ (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_SHIFT);
+ reg = (reg & ~UDC_CSR_NE_ALT_MASK) |
+ (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_SHIFT);
+ pch_udc_write_csr(dev, reg, UDC_EP0OUT_IDX);
+ for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
+ /* clear stall bits */
+ pch_udc_ep_clear_stall(&(dev->ep[i]));
+ dev->ep[i].halted = 0;
+ }
+ dev->stall = 0;
+ spin_unlock(&dev->lock);
+ ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
+ spin_lock(&dev->lock);
+}
+
+/**
+ * pch_udc_svc_cfg_interrupt() - This function handles a set configuration
+ * interrupt
+ * @dev: Reference to driver structure
+ */
+static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
+{
+ int i, ret;
+ u32 reg, dev_stat = 0;
+
+ dev_stat = pch_udc_read_device_status(dev);
+ dev->set_cfg_not_acked = 1;
+ dev->cfg_data.cur_cfg = (dev_stat & UDC_DEVSTS_CFG_MASK) >>
+ UDC_DEVSTS_CFG_SHIFT;
+ /* make usb request for gadget driver */
+ memset(&dev->setup_data, 0 , sizeof dev->setup_data);
+ dev->setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
+ dev->setup_data.wValue = cpu_to_le16(dev->cfg_data.cur_cfg);
+ /* program the NE registers */
+ /* Only one end point cfg register */
+ reg = pch_udc_read_csr(dev, UDC_EP0OUT_IDX);
+ reg = (reg & ~UDC_CSR_NE_CFG_MASK) |
+ (dev->cfg_data.cur_cfg << UDC_CSR_NE_CFG_SHIFT);
+ pch_udc_write_csr(dev, reg, UDC_EP0OUT_IDX);
+ for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
+ /* clear stall bits */
+ pch_udc_ep_clear_stall(&(dev->ep[i]));
+ dev->ep[i].halted = 0;
+ }
+ dev->stall = 0;
+
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
+ spin_lock(&dev->lock);
+}
+
+/**
+ * pch_udc_dev_isr() - This function services device interrupts
+ * by invoking appropriate routines.
+ * @dev: Reference to the device structure
+ * @dev_intr: The Device interrupt status.
+ */
+static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
+{
+ /* USB Reset Interrupt */
+ if (dev_intr & UDC_DEVINT_UR)
+ pch_udc_svc_ur_interrupt(dev);
+ /* Enumeration Done Interrupt */
+ if (dev_intr & UDC_DEVINT_ENUM)
+ pch_udc_svc_enum_interrupt(dev);
+ /* Set Interface Interrupt */
+ if (dev_intr & UDC_DEVINT_SI)
+ pch_udc_svc_intf_interrupt(dev);
+ /* Set Config Interrupt */
+ if (dev_intr & UDC_DEVINT_SC)
+ pch_udc_svc_cfg_interrupt(dev);
+ /* USB Suspend interrupt */
+ if (dev_intr & UDC_DEVINT_US)
+ dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
+ /* Clear the SOF interrupt, if enabled */
+ if (dev_intr & UDC_DEVINT_SOF)
+ dev_dbg(&dev->pdev->dev, "SOF\n");
+ /* ES interrupt, IDLE > 3ms on the USB */
+ if (dev_intr & UDC_DEVINT_ES)
+ dev_dbg(&dev->pdev->dev, "ES\n");
+ /* RWKP interrupt */
+ if (dev_intr & UDC_DEVINT_RWKP)
+ dev_dbg(&dev->pdev->dev, "RWKP\n");
+}
+
+/**
+ * pch_udc_isr() - This function handles interrupts from the PCH USB Device
+ * @irq: Interrupt request number
+ * @dev: Reference to the device structure
+ */
+static irqreturn_t pch_udc_isr(int irq, void *pdev)
+{
+ struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev;
+ u32 dev_intr, ep_intr;
+ int i;
+
+ dev_intr = pch_udc_read_device_interrupts(dev);
+ ep_intr = pch_udc_read_ep_interrupts(dev);
+
+ if (dev_intr)
+ /* Clear device interrupts */
+ pch_udc_write_device_interrupts(dev, dev_intr);
+ if (ep_intr)
+ /* Clear ep interrupts */
+ pch_udc_write_ep_interrupts(dev, ep_intr);
+ if (!dev_intr && !ep_intr)
+ return IRQ_NONE;
+ spin_lock(&dev->lock);
+ if (dev_intr)
+ pch_udc_dev_isr(dev, dev_intr);
+ if (ep_intr) {
+ pch_udc_read_all_epstatus(dev, ep_intr);
+ /* Process Control In interrupts, if present */
+ if (ep_intr & UDC_EPINT_IN_EP0) {
+ pch_udc_svc_control_in(dev);
+ pch_udc_postsvc_epinters(dev, 0);
+ }
+ /* Process Control Out interrupts, if present */
+ if (ep_intr & UDC_EPINT_OUT_EP0)
+ pch_udc_svc_control_out(dev);
+ /* Process data in end point interrupts */
+ for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
+ if (ep_intr & (1 << i)) {
+ pch_udc_svc_data_in(dev, i);
+ pch_udc_postsvc_epinters(dev, i);
+ }
+ }
+ /* Process data out end point interrupts */
+ for (i = UDC_EPINT_OUT_SHIFT + 1; i < (UDC_EPINT_OUT_SHIFT +
+ PCH_UDC_USED_EP_NUM); i++)
+ if (ep_intr & (1 << i))
+ pch_udc_svc_data_out(dev, i -
+ UDC_EPINT_OUT_SHIFT);
+ }
+ spin_unlock(&dev->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * pch_udc_setup_ep0() - This function enables control endpoint for traffic
+ * @dev: Reference to the device structure
+ */
+static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
+{
+ /* enable ep0 interrupts */
+ pch_udc_enable_ep_interrupts(dev, UDC_EPINT_IN_EP0 |
+ UDC_EPINT_OUT_EP0);
+ /* enable device interrupts */
+ pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US |
+ UDC_DEVINT_ES | UDC_DEVINT_ENUM |
+ UDC_DEVINT_SI | UDC_DEVINT_SC);
+}
+
+/**
+ * gadget_release() - Free the gadget driver private data
+ * @pdev reference to struct pci_dev
+ */
+static void gadget_release(struct device *pdev)
+{
+ struct pch_udc_dev *dev = dev_get_drvdata(pdev);
+
+ kfree(dev);
+}
+
+/**
+ * pch_udc_pcd_reinit() - This API initializes the endpoint structures
+ * @dev: Reference to the driver structure
+ */
+static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
+{
+ const char *const ep_string[] = {
+ ep0_string, "ep0out", "ep1in", "ep1out", "ep2in", "ep2out",
+ "ep3in", "ep3out", "ep4in", "ep4out", "ep5in", "ep5out",
+ "ep6in", "ep6out", "ep7in", "ep7out", "ep8in", "ep8out",
+ "ep9in", "ep9out", "ep10in", "ep10out", "ep11in", "ep11out",
+ "ep12in", "ep12out", "ep13in", "ep13out", "ep14in", "ep14out",
+ "ep15in", "ep15out",
+ };
+ int i;
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+
+ /* Initialize the endpoints structures */
+ memset(dev->ep, 0, sizeof dev->ep);
+ for (i = 0; i < PCH_UDC_EP_NUM; i++) {
+ struct pch_udc_ep *ep = &dev->ep[i];
+ ep->dev = dev;
+ ep->halted = 1;
+ ep->num = i / 2;
+ ep->in = ~i & 1;
+ ep->ep.name = ep_string[i];
+ ep->ep.ops = &pch_udc_ep_ops;
+ if (ep->in)
+ ep->offset_addr = ep->num * UDC_EP_REG_SHIFT;
+ else
+ ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) *
+ UDC_EP_REG_SHIFT;
+ /* need to set ep->ep.maxpacket and set Default Configuration?*/
+ ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE;
+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+ INIT_LIST_HEAD(&ep->queue);
+ }
+ dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+
+ dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256,
+ PCI_DMA_FROMDEVICE);
+
+ /* remove ep0 in and out from the list. They have own pointer */
+ list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
+ list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list);
+
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep;
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+}
+
+/**
+ * pch_udc_pcd_init() - This API initializes the driver structure
+ * @dev: Reference to the driver structure
+ *
+ * Return codes:
+ * 0: Success
+ */
+static int pch_udc_pcd_init(struct pch_udc_dev *dev)
+{
+ pch_udc_init(dev);
+ pch_udc_pcd_reinit(dev);
+ return 0;
+}
+
+/**
+ * init_dma_pools() - create dma pools during initialization
+ * @pdev: reference to struct pci_dev
+ */
+static int init_dma_pools(struct pch_udc_dev *dev)
+{
+ struct pch_udc_stp_dma_desc *td_stp;
+ struct pch_udc_data_dma_desc *td_data;
+
+ /* DMA setup */
+ dev->data_requests = pci_pool_create("data_requests", dev->pdev,
+ sizeof(struct pch_udc_data_dma_desc), 0, 0);
+ if (!dev->data_requests) {
+ dev_err(&dev->pdev->dev, "%s: can't get request data pool\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* dma desc for setup data */
+ dev->stp_requests = pci_pool_create("setup requests", dev->pdev,
+ sizeof(struct pch_udc_stp_dma_desc), 0, 0);
+ if (!dev->stp_requests) {
+ dev_err(&dev->pdev->dev, "%s: can't get setup request pool\n",
+ __func__);
+ return -ENOMEM;
+ }
+ /* setup */
+ td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
+ if (!td_stp) {
+ dev_err(&dev->pdev->dev,
+ "%s: can't allocate setup dma descriptor\n", __func__);
+ return -ENOMEM;
+ }
+ dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp;
+
+ /* data: 0 packets !? */
+ td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IDX].td_data_phys);
+ if (!td_data) {
+ dev_err(&dev->pdev->dev,
+ "%s: can't allocate data dma descriptor\n", __func__);
+ return -ENOMEM;
+ }
+ dev->ep[UDC_EP0OUT_IDX].td_data = td_data;
+ dev->ep[UDC_EP0IN_IDX].td_stp = NULL;
+ dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0;
+ dev->ep[UDC_EP0IN_IDX].td_data = NULL;
+ dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
+ return 0;
+}
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct pch_udc_dev *dev = pch_udc;
+ int retval;
+
+ if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind ||
+ !driver->setup || !driver->unbind || !driver->disconnect) {
+ dev_err(&dev->pdev->dev,
+ "%s: invalid driver parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!dev)
+ return -ENODEV;
+
+ if (dev->driver) {
+ dev_err(&dev->pdev->dev, "%s: already bound\n", __func__);
+ return -EBUSY;
+ }
+ driver->driver.bus = NULL;
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ /* Invoke the bind routine of the gadget driver */
+ retval = bind(&dev->gadget);
+
+ if (retval) {
+ dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n",
+ __func__, driver->driver.name, retval);
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
+ /* get ready for ep0 traffic */
+ pch_udc_setup_ep0(dev);
+
+ /* clear SD */
+ pch_udc_clear_disconnect(dev);
+
+ dev->connected = 1;
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct pch_udc_dev *dev = pch_udc;
+
+ if (!dev)
+ return -ENODEV;
+
+ if (!driver || (driver != dev->driver)) {
+ dev_err(&dev->pdev->dev,
+ "%s: invalid driver parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
+
+ /* Assues that there are no pending requets with this driver */
+ driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
+ dev->driver = NULL;
+ dev->connected = 0;
+
+ /* set SD */
+ pch_udc_set_disconnect(dev);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static void pch_udc_shutdown(struct pci_dev *pdev)
+{
+ struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+
+ pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
+ pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
+
+ /* disable the pullup so the host will think we're gone */
+ pch_udc_set_disconnect(dev);
+}
+
+static void pch_udc_remove(struct pci_dev *pdev)
+{
+ struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+
+ /* gadget driver must not be registered */
+ if (dev->driver)
+ dev_err(&pdev->dev,
+ "%s: gadget driver still bound!!!\n", __func__);
+ /* dma pool cleanup */
+ if (dev->data_requests)
+ pci_pool_destroy(dev->data_requests);
+
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ if (dev->ep[UDC_EP0OUT_IDX].td_stp) {
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IDX].td_stp,
+ dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
+ }
+ if (dev->ep[UDC_EP0OUT_IDX].td_data) {
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IDX].td_data,
+ dev->ep[UDC_EP0OUT_IDX].td_data_phys);
+ }
+ pci_pool_destroy(dev->stp_requests);
+ }
+
+ pch_udc_exit(dev);
+
+ if (dev->irq_registered)
+ free_irq(pdev->irq, dev);
+ if (dev->base_addr)
+ iounmap(dev->base_addr);
+ if (dev->mem_region)
+ release_mem_region(dev->phys_addr,
+ pci_resource_len(pdev, PCH_UDC_PCI_BAR));
+ if (dev->active)
+ pci_disable_device(pdev);
+ if (dev->registered)
+ device_unregister(&dev->gadget.dev);
+ kfree(dev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+
+ pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
+ pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
+
+ pci_disable_device(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ if (pci_save_state(pdev)) {
+ dev_err(&pdev->dev,
+ "%s: could not save PCI config state\n", __func__);
+ return -ENOMEM;
+ }
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int pch_udc_resume(struct pci_dev *pdev)
+{
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_restore_state(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__);
+ return ret;
+ }
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
+ return ret;
+ }
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ return 0;
+}
+#else
+#define pch_udc_suspend NULL
+#define pch_udc_resume NULL
+#endif /* CONFIG_PM */
+
+static int pch_udc_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned long resource;
+ unsigned long len;
+ int retval;
+ struct pch_udc_dev *dev;
+
+ /* one udc only */
+ if (pch_udc) {
+ pr_err("%s: already probed\n", __func__);
+ return -EBUSY;
+ }
+ /* init */
+ dev = kzalloc(sizeof *dev, GFP_KERNEL);
+ if (!dev) {
+ pr_err("%s: no memory for device structure\n", __func__);
+ return -ENOMEM;
+ }
+ /* pci setup */
+ if (pci_enable_device(pdev) < 0) {
+ kfree(dev);
+ pr_err("%s: pci_enable_device failed\n", __func__);
+ return -ENODEV;
+ }
+ dev->active = 1;
+ pci_set_drvdata(pdev, dev);
+
+ /* PCI resource allocation */
+ resource = pci_resource_start(pdev, 1);
+ len = pci_resource_len(pdev, 1);
+
+ if (!request_mem_region(resource, len, KBUILD_MODNAME)) {
+ dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->phys_addr = resource;
+ dev->mem_region = 1;
+
+ dev->base_addr = ioremap_nocache(resource, len);
+ if (!dev->base_addr) {
+ pr_err("%s: device memory cannot be mapped\n", __func__);
+ retval = -ENOMEM;
+ goto finished;
+ }
+ if (!pdev->irq) {
+ dev_err(&pdev->dev, "%s: irq not set\n", __func__);
+ retval = -ENODEV;
+ goto finished;
+ }
+ pch_udc = dev;
+ /* initialize the hardware */
+ if (pch_udc_pcd_init(dev))
+ goto finished;
+ if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
+ dev)) {
+ dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
+ pdev->irq);
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev->irq = pdev->irq;
+ dev->irq_registered = 1;
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ /* device struct setup */
+ spin_lock_init(&dev->lock);
+ dev->pdev = pdev;
+ dev->gadget.ops = &pch_udc_ops;
+
+ retval = init_dma_pools(dev);
+ if (retval)
+ goto finished;
+
+ dev_set_name(&dev->gadget.dev, "gadget");
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = KBUILD_MODNAME;
+ dev->gadget.is_dualspeed = 1;
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval)
+ goto finished;
+ dev->registered = 1;
+
+ /* Put the device in disconnected state till a driver is bound */
+ pch_udc_set_disconnect(dev);
+ return 0;
+
+finished:
+ pch_udc_remove(pdev);
+ return retval;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+ },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
+
+
+static struct pci_driver pch_udc_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = pch_udc_pcidev_id,
+ .probe = pch_udc_probe,
+ .remove = pch_udc_remove,
+ .suspend = pch_udc_suspend,
+ .resume = pch_udc_resume,
+ .shutdown = pch_udc_shutdown,
+};
+
+static int __init pch_udc_pci_init(void)
+{
+ return pci_register_driver(&pch_udc_driver);
+}
+module_init(pch_udc_pci_init);
+
+static void __exit pch_udc_pci_exit(void)
+{
+ pci_unregister_driver(&pch_udc_driver);
+}
+module_exit(pch_udc_pci_exit);
+
+MODULE_DESCRIPTION("Intel EG20T USB Device Controller");
+MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 3b513bafaf2a..b015561fd602 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -543,7 +543,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
ro = curlun->initially_ro;
if (!ro) {
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
- if (-EROFS == PTR_ERR(filp))
+ if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
ro = 1;
}
if (ro)
@@ -558,10 +558,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
if (filp->f_path.dentry)
inode = filp->f_path.dentry->d_inode;
- if (inode && S_ISBLK(inode->i_mode)) {
- if (bdev_read_only(inode->i_bdev))
- ro = 1;
- } else if (!inode || !S_ISREG(inode->i_mode)) {
+ if (!inode || (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
LINFO(curlun, "invalid file type: %s\n", filename);
goto out;
}
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c
index 7a86d2c9109c..59ffe1ecf1c9 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_audio.c
@@ -255,6 +255,7 @@ static int gaudio_open_snd_dev(struct gaudio *card)
ERROR(card, "No such PCM capture device: %s\n", fn_cap);
snd->substream = NULL;
snd->card = NULL;
+ snd->filp = NULL;
} else {
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
@@ -273,17 +274,17 @@ static int gaudio_close_snd_dev(struct gaudio *gau)
/* Close control device */
snd = &gau->control;
- if (!IS_ERR(snd->filp))
+ if (snd->filp)
filp_close(snd->filp, current->files);
/* Close PCM playback device and setup substream */
snd = &gau->playback;
- if (!IS_ERR(snd->filp))
+ if (snd->filp)
filp_close(snd->filp, current->files);
/* Close PCM capture device and setup substream */
snd = &gau->capture;
- if (!IS_ERR(snd->filp))
+ if (snd->filp)
filp_close(snd->filp, current->files);
return 0;
@@ -304,8 +305,7 @@ int __init gaudio_setup(struct gaudio *card)
ret = gaudio_open_snd_dev(card);
if (ret)
ERROR(card, "we need at least one control device\n");
-
- if (!the_card)
+ else if (!the_card)
the_card = card;
return ret;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index cb23355f52d3..1eda968b5644 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -240,6 +240,9 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
size += out->maxpacket - 1;
size -= size % out->maxpacket;
+ if (dev->port_usb->is_fixed)
+ size = max(size, dev->port_usb->fixed_out_len);
+
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
DBG(dev, "no rx skb\n");
@@ -578,12 +581,19 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
req->context = skb;
req->complete = tx_complete;
+ /* NCM requires no zlp if transfer is dwNtbInMaxSize */
+ if (dev->port_usb->is_fixed &&
+ length == dev->port_usb->fixed_in_len &&
+ (length % in->maxpacket) == 0)
+ req->zero = 0;
+ else
+ req->zero = 1;
+
/* use zlp framing on tx for strict CDC-Ether conformance,
* though any robust network rx path ignores extra padding.
* and some hardware doesn't like to write zlps.
*/
- req->zero = 1;
- if (!dev->zlp && (length % in->maxpacket) == 0)
+ if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
length++;
req->length = length;
@@ -811,7 +821,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- netif_stop_queue(net);
the_dev = dev;
}
@@ -830,11 +839,9 @@ void gether_cleanup(void)
return;
unregister_netdev(the_dev->net);
+ flush_work_sync(&the_dev->work);
free_netdev(the_dev->net);
- /* assuming we used keventd, it must quiesce too */
- flush_scheduled_work();
-
the_dev = NULL;
}
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 3c8c0c9f9d72..b56e1e7d423c 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -62,6 +62,10 @@ struct gether {
/* hooks for added framing, as needed for RNDIS and EEM. */
u32 header_len;
+ /* NCM requires fixed size bundles */
+ bool is_fixed;
+ u32 fixed_out_len;
+ u32 fixed_in_len;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
int (*unwrap)(struct gether *port,
@@ -103,6 +107,7 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
/* each configuration may bind one instance of an ethernet link */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int eem_bind_config(struct usb_configuration *c);
#ifdef USB_ETH_RNDIS
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 01e5354a4c20..40f7716b31fc 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -105,11 +105,15 @@ struct gs_port {
wait_queue_head_t close_wait; /* wait for last close */
struct list_head read_pool;
+ int read_started;
+ int read_allocated;
struct list_head read_queue;
unsigned n_read;
struct tasklet_struct push;
struct list_head write_pool;
+ int write_started;
+ int write_allocated;
struct gs_buf port_write_buf;
wait_queue_head_t drain_wait; /* wait while writes drain */
@@ -363,6 +367,9 @@ __acquires(&port->port_lock)
struct usb_request *req;
int len;
+ if (port->write_started >= QUEUE_SIZE)
+ break;
+
req = list_entry(pool->next, struct usb_request, list);
len = gs_send_packet(port, req->buf, in->maxpacket);
if (len == 0) {
@@ -397,6 +404,8 @@ __acquires(&port->port_lock)
break;
}
+ port->write_started++;
+
/* abort immediately after disconnect */
if (!port->port_usb)
break;
@@ -418,7 +427,6 @@ __acquires(&port->port_lock)
{
struct list_head *pool = &port->read_pool;
struct usb_ep *out = port->port_usb->out;
- unsigned started = 0;
while (!list_empty(pool)) {
struct usb_request *req;
@@ -430,6 +438,9 @@ __acquires(&port->port_lock)
if (!tty)
break;
+ if (port->read_started >= QUEUE_SIZE)
+ break;
+
req = list_entry(pool->next, struct usb_request, list);
list_del(&req->list);
req->length = out->maxpacket;
@@ -447,13 +458,13 @@ __acquires(&port->port_lock)
list_add(&req->list, pool);
break;
}
- started++;
+ port->read_started++;
/* abort immediately after disconnect */
if (!port->port_usb)
break;
}
- return started;
+ return port->read_started;
}
/*
@@ -535,6 +546,7 @@ static void gs_rx_push(unsigned long _port)
}
recycle:
list_move(&req->list, &port->read_pool);
+ port->read_started--;
}
/* Push from tty to ldisc; without low_latency set this is handled by
@@ -587,6 +599,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&port->port_lock);
list_add(&req->list, &port->write_pool);
+ port->write_started--;
switch (req->status) {
default:
@@ -608,7 +621,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
spin_unlock(&port->port_lock);
}
-static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
+static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
+ int *allocated)
{
struct usb_request *req;
@@ -616,25 +630,31 @@ static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
req = list_entry(head->next, struct usb_request, list);
list_del(&req->list);
gs_free_req(ep, req);
+ if (allocated)
+ (*allocated)--;
}
}
static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
- void (*fn)(struct usb_ep *, struct usb_request *))
+ void (*fn)(struct usb_ep *, struct usb_request *),
+ int *allocated)
{
int i;
struct usb_request *req;
+ int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE;
/* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
* do quite that many this time, don't fail ... we just won't
* be as speedy as we might otherwise be.
*/
- for (i = 0; i < QUEUE_SIZE; i++) {
+ for (i = 0; i < n; i++) {
req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
if (!req)
return list_empty(head) ? -ENOMEM : 0;
req->complete = fn;
list_add_tail(&req->list, head);
+ if (allocated)
+ (*allocated)++;
}
return 0;
}
@@ -661,14 +681,15 @@ static int gs_start_io(struct gs_port *port)
* configurations may use different endpoints with a given port;
* and high speed vs full speed changes packet sizes too.
*/
- status = gs_alloc_requests(ep, head, gs_read_complete);
+ status = gs_alloc_requests(ep, head, gs_read_complete,
+ &port->read_allocated);
if (status)
return status;
status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
- gs_write_complete);
+ gs_write_complete, &port->write_allocated);
if (status) {
- gs_free_requests(ep, head);
+ gs_free_requests(ep, head, &port->read_allocated);
return status;
}
@@ -680,8 +701,9 @@ static int gs_start_io(struct gs_port *port)
if (started) {
tty_wakeup(port->port_tty);
} else {
- gs_free_requests(ep, head);
- gs_free_requests(port->port_usb->in, &port->write_pool);
+ gs_free_requests(ep, head, &port->read_allocated);
+ gs_free_requests(port->port_usb->in, &port->write_pool,
+ &port->write_allocated);
status = -EIO;
}
@@ -1315,8 +1337,12 @@ void gserial_disconnect(struct gserial *gser)
spin_lock_irqsave(&port->port_lock, flags);
if (port->open_count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf);
- gs_free_requests(gser->out, &port->read_pool);
- gs_free_requests(gser->out, &port->read_queue);
- gs_free_requests(gser->in, &port->write_pool);
+ gs_free_requests(gser->out, &port->read_pool, NULL);
+ gs_free_requests(gser->out, &port->read_queue, NULL);
+ gs_free_requests(gser->in, &port->write_pool, NULL);
+
+ port->read_allocated = port->read_started =
+ port->write_allocated = port->write_started = 0;
+
spin_unlock_irqrestore(&port->port_lock, flags);
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2391c396ca32..24046c0f5878 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -122,7 +122,7 @@ config USB_EHCI_FSL
bool "Support for Freescale on-chip EHCI USB controller"
depends on USB_EHCI_HCD && FSL_SOC
select USB_EHCI_ROOT_HUB_TT
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
---help---
Variation of ARC USB block used in some Freescale chips.
@@ -133,6 +133,25 @@ config USB_EHCI_MXC
---help---
Variation of ARC USB block used in some Freescale chips.
+config USB_EHCI_HCD_OMAP
+ bool "EHCI support for OMAP3 and later chips"
+ depends on USB_EHCI_HCD && ARCH_OMAP
+ default y
+ --- help ---
+ Enables support for the on-chip EHCI controller on
+ OMAP3 and later chips.
+
+config USB_EHCI_MSM
+ bool "Support for MSM on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && ARCH_MSM
+ select USB_EHCI_ROOT_HUB_TT
+ select USB_MSM_OTG_72K
+ ---help---
+ Enables support for the USB Host controller present on the
+ Qualcomm chipsets. Root Hub has inbuilt TT.
+ This driver depends on OTG driver for PHY initialization,
+ clock management, powering up VBUS, and power management.
+
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
depends on USB_EHCI_HCD && PPC_OF
@@ -147,6 +166,14 @@ config USB_W90X900_EHCI
---help---
Enables support for the W90X900 USB controller
+config USB_CNS3XXX_EHCI
+ bool "Cavium CNS3XXX EHCI Module"
+ depends on USB_EHCI_HCD && ARCH_CNS3XXX
+ ---help---
+ Enable support for the CNS3XXX SOC's on-chip EHCI controller.
+ It is needed for high-speed (480Mbit/sec) USB 2.0 device
+ support.
+
config USB_OXU210HP_HCD
tristate "OXU210HP HCD support"
depends on USB
@@ -286,6 +313,13 @@ config USB_OHCI_HCD_SSB
If unsure, say N.
+config USB_CNS3XXX_OHCI
+ bool "Cavium CNS3XXX OHCI Module"
+ depends on USB_OHCI_HCD && ARCH_CNS3XXX
+ ---help---
+ Enable support for the CNS3XXX SOC's on-chip OHCI controller.
+ It is needed for low-speed USB 1.0 device support.
+
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 51bd0edf544f..d6a69d514a84 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -99,6 +99,7 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/* scheduling support */
.get_frame_number = ehci_get_frame,
@@ -110,6 +111,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c
new file mode 100644
index 000000000000..708a05b5d258
--- /dev/null
+++ b/drivers/usb/host/ehci-cns3xxx.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/atomic.h>
+#include <mach/cns3xxx.h>
+#include <mach/pm.h>
+
+static int cns3xxx_ehci_init(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ /*
+ * EHCI and OHCI share the same clock and power,
+ * resetting twice would cause the 1st controller been reset.
+ * Therefore only do power up at the first up device, and
+ * power down at the last down device.
+ *
+ * Set USB AHB INCR length to 16
+ */
+ if (atomic_inc_return(&usb_pwr_ref) == 1) {
+ cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
+ cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
+ cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST);
+ __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)),
+ MISC_CHIP_CONFIG_REG);
+ }
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs
+ + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ hcd->has_tt = 0;
+ ehci_reset(ehci);
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_port_power(ehci, 0);
+
+ return retval;
+}
+
+static const struct hc_driver cns3xxx_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "CNS3XXX EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = cns3xxx_ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int cns3xxx_ehci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd;
+ const struct hc_driver *driver = &cns3xxx_ehci_hc_driver;
+ struct resource *res;
+ int irq;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "Found HC with no IRQ.\n");
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "Found HC with no register addr.\n");
+ retval = -ENODEV;
+ goto err1;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err2;
+ }
+
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (retval == 0)
+ return retval;
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+
+ return retval;
+}
+
+static int cns3xxx_ehci_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ /*
+ * EHCI and OHCI share the same clock and power,
+ * resetting twice would cause the 1st controller been reset.
+ * Therefore only do power up at the first up device, and
+ * power down at the last down device.
+ */
+ if (atomic_dec_return(&usb_pwr_ref) == 0)
+ cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
+
+ usb_put_hcd(hcd);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:cns3xxx-ehci");
+
+static struct platform_driver cns3xxx_ehci_driver = {
+ .probe = cns3xxx_ehci_probe,
+ .remove = cns3xxx_ehci_remove,
+ .driver = {
+ .name = "cns3xxx-ehci",
+ },
+};
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 86afdc73322f..3be238a24cc5 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -879,7 +879,7 @@ static int fill_buffer(struct debug_buffer *buf)
int ret = 0;
if (!buf->output_buf)
- buf->output_buf = (char *)vmalloc(buf->alloc_size);
+ buf->output_buf = vmalloc(buf->alloc_size);
if (!buf->output_buf) {
ret = -ENOMEM;
@@ -1067,7 +1067,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
&debug_registers_fops))
goto file_error;
- if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
+ if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
&debug_lpm_fops))
goto file_error;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 502a7e6fef42..6fee3cd58efe 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -114,6 +114,9 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+/* for ASPM quirk of ISOC on AMD SB800 */
+static struct pci_dev *amd_nb_dev;
+
/*-------------------------------------------------------------------------*/
#include "ehci.h"
@@ -529,6 +532,11 @@ static void ehci_stop (struct usb_hcd *hcd)
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
+ if (amd_nb_dev) {
+ pci_dev_put(amd_nb_dev);
+ amd_nb_dev = NULL;
+ }
+
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
@@ -1063,10 +1071,11 @@ rescan:
tmp && tmp != qh;
tmp = tmp->qh_next.qh)
continue;
- /* periodic qh self-unlinks on empty */
- if (!tmp)
- goto nogood;
- unlink_async (ehci, qh);
+ /* periodic qh self-unlinks on empty, and a COMPLETING qh
+ * may already be unlinked.
+ */
+ if (tmp)
+ unlink_async(ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
@@ -1083,7 +1092,6 @@ idle_timeout:
}
/* else FALL THROUGH */
default:
-nogood:
/* caller was supposed to have unlinked any requests;
* that's not our job. just leak this memory.
*/
@@ -1166,12 +1174,17 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mxc_driver
#endif
+#ifdef CONFIG_CPU_SUBTYPE_SH7786
+#include "ehci-sh.c"
+#define PLATFORM_DRIVER ehci_hcd_sh_driver
+#endif
+
#ifdef CONFIG_SOC_AU1200
#include "ehci-au1xxx.c"
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
-#ifdef CONFIG_ARCH_OMAP3
+#ifdef CONFIG_USB_EHCI_HCD_OMAP
#include "ehci-omap.c"
#define PLATFORM_DRIVER ehci_hcd_omap_driver
#endif
@@ -1216,6 +1229,26 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
+#ifdef CONFIG_USB_CNS3XXX_EHCI
+#include "ehci-cns3xxx.c"
+#define PLATFORM_DRIVER cns3xxx_ehci_driver
+#endif
+
+#ifdef CONFIG_ARCH_VT8500
+#include "ehci-vt8500.c"
+#define PLATFORM_DRIVER vt8500_ehci_driver
+#endif
+
+#ifdef CONFIG_PLAT_SPEAR
+#include "ehci-spear.c"
+#define PLATFORM_DRIVER spear_ehci_hcd_driver
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM
+#include "ehci-msm.c"
+#define PLATFORM_DRIVER ehci_msm_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index d36e4e75e08d..12f70c302b0b 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
qh_put (ehci->async);
ehci->async = NULL;
+ if (ehci->dummy)
+ qh_put(ehci->dummy);
+ ehci->dummy = NULL;
+
/* DMA consistent memory and pools */
if (ehci->qtd_pool)
dma_pool_destroy (ehci->qtd_pool);
@@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
if (ehci->periodic == NULL) {
goto fail;
}
- for (i = 0; i < ehci->periodic_size; i++)
- ehci->periodic [i] = EHCI_LIST_END(ehci);
+
+ if (ehci->use_dummy_qh) {
+ struct ehci_qh_hw *hw;
+ ehci->dummy = ehci_qh_alloc(ehci, flags);
+ if (!ehci->dummy)
+ goto fail;
+
+ hw = ehci->dummy->hw;
+ hw->hw_next = EHCI_LIST_END(ehci);
+ hw->hw_qtd_next = EHCI_LIST_END(ehci);
+ hw->hw_alt_next = EHCI_LIST_END(ehci);
+ hw->hw_token &= ~QTD_STS_ACTIVE;
+ ehci->dummy->hw = hw;
+
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = ehci->dummy->qh_dma;
+ } else {
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = EHCI_LIST_END(ehci);
+ }
/* software shadow of hardware table */
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
new file mode 100644
index 000000000000..413f4deca532
--- /dev/null
+++ b/drivers/usb/host/ehci-msm.c
@@ -0,0 +1,345 @@
+/* ehci-msm.c - HSUSB Host Controller Driver Implementation
+ *
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Partly derived from ehci-fsl.c and ehci-hcd.c
+ * Copyright (c) 2000-2004 by David Brownell
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * 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, you can find it at http://www.fsf.org
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb_hw.h>
+
+#define MSM_USB_BASE (hcd->regs)
+
+static struct otg_transceiver *otg;
+
+/*
+ * ehci_run defined in drivers/usb/host/ehci-hcd.c reset the controller and
+ * the configuration settings in ehci_msm_reset vanish after controller is
+ * reset. Resetting the controler in ehci_run seems to be un-necessary
+ * provided HCD reset the controller before calling ehci_run. Most of the HCD
+ * do but some are not. So this function is same as ehci_run but we don't
+ * reset the controller here.
+ */
+static int ehci_msm_run(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 temp;
+ u32 hcc_params;
+
+ hcd->uses_new_polling = 1;
+
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
+
+ /*
+ * hcc_params controls whether ehci->regs->segment must (!!!)
+ * be used; it constrains QH/ITD/SITD and QTD locations.
+ * pci_pool consistent memory always uses segment zero.
+ * streaming mappings for I/O buffers, like pci_map_single(),
+ * can return segments above 4GB, if the device allows.
+ *
+ * NOTE: the dma mask is visible through dma_supported(), so
+ * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+ * Scsi_Host.highmem_io, and so forth. It's readonly to all
+ * host side drivers though.
+ */
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
+ if (HCC_64BIT_ADDR(hcc_params))
+ ehci_writel(ehci, 0, &ehci->regs->segment);
+
+ /*
+ * Philips, Intel, and maybe others need CMD_RUN before the
+ * root hub will detect new devices (why?); NEC doesn't
+ */
+ ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+ ehci->command |= CMD_RUN;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ dbg_cmd(ehci, "init", ehci->command);
+
+ /*
+ * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+ * 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. After we set CF,
+ * a short delay lets the hardware catch up; new resets shouldn't
+ * be started before the port switching actions could complete.
+ */
+ 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 */
+ usleep_range(5000, 5500);
+ up_write(&ehci_cf_port_reset_rwsem);
+ ehci->last_periodic_enable = ktime_get_real();
+
+ temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci_info(ehci,
+ "USB %x.%x started, EHCI %x.%02x%s\n",
+ ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
+ temp >> 8, temp & 0xff,
+ ignore_oc ? ", overcurrent ignored" : "");
+
+ ehci_writel(ehci, INTR_MASK,
+ &ehci->regs->intr_enable); /* Turn On Interrupts */
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ create_debug_files(ehci);
+ create_companion_file(ehci);
+
+ return 0;
+}
+
+static int ehci_msm_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ ehci->caps = USB_CAPLENGTH;
+ ehci->regs = USB_CAPLENGTH +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* cache the data to minimize the chip reads*/
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ hcd->has_tt = 1;
+ ehci->sbrn = HCD_USB2;
+
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ retval = ehci_reset(ehci);
+ if (retval)
+ return retval;
+
+ /* bursts of unspecified length. */
+ writel(0, USB_AHBBURST);
+ /* Use the AHB transactor */
+ writel(0, USB_AHBMODE);
+ /* Disable streaming mode and select host mode */
+ writel(0x13, USB_USBMODE);
+
+ ehci_port_power(ehci, 1);
+ return 0;
+}
+
+static struct hc_driver msm_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Qualcomm On-Chip EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ .reset = ehci_msm_reset,
+ .start = ehci_msm_run,
+
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /*
+ * PM support
+ */
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+};
+
+static int ehci_msm_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int ret;
+
+ dev_dbg(&pdev->dev, "ehci_msm proble\n");
+
+ hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "Unable to create HCD\n");
+ return -ENOMEM;
+ }
+
+ hcd->irq = platform_get_irq(pdev, 0);
+ if (hcd->irq < 0) {
+ dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+ ret = hcd->irq;
+ goto put_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get memory resource\n");
+ ret = -ENODEV;
+ goto put_hcd;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto put_hcd;
+ }
+
+ /*
+ * OTG driver takes care of PHY initialization, clock management,
+ * powering up VBUS, mapping of registers address space and power
+ * management.
+ */
+ otg = otg_get_transceiver();
+ if (!otg) {
+ dev_err(&pdev->dev, "unable to find transceiver\n");
+ ret = -ENODEV;
+ goto unmap;
+ }
+
+ ret = otg_set_host(otg, &hcd->self);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register with transceiver\n");
+ goto put_transceiver;
+ }
+
+ device_init_wakeup(&pdev->dev, 1);
+ /*
+ * OTG device parent of HCD takes care of putting
+ * hardware into low power mode.
+ */
+ pm_runtime_no_callbacks(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+put_transceiver:
+ otg_put_transceiver(otg);
+unmap:
+ iounmap(hcd->regs);
+put_hcd:
+ usb_put_hcd(hcd);
+
+ return ret;
+}
+
+static int __devexit ehci_msm_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ otg_set_host(otg, NULL);
+ otg_put_transceiver(otg);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ehci_msm_pm_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ bool wakeup = device_may_wakeup(dev);
+
+ dev_dbg(dev, "ehci-msm PM suspend\n");
+
+ /*
+ * EHCI helper function has also the same check before manipulating
+ * port wakeup flags. We do check here the same condition before
+ * calling the same helper function to avoid bringing hardware
+ * from Low power mode when there is no need for adjusting port
+ * wakeup flags.
+ */
+ if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
+ pm_runtime_resume(dev);
+ ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
+ wakeup);
+ }
+
+ return 0;
+}
+
+static int ehci_msm_pm_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "ehci-msm PM resume\n");
+ ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+
+ return 0;
+}
+#else
+#define ehci_msm_pm_suspend NULL
+#define ehci_msm_pm_resume NULL
+#endif
+
+static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
+ .suspend = ehci_msm_pm_suspend,
+ .resume = ehci_msm_pm_resume,
+};
+
+static struct platform_driver ehci_msm_driver = {
+ .probe = ehci_msm_probe,
+ .remove = __devexit_p(ehci_msm_remove),
+ .driver = {
+ .name = "msm_hsusb_host",
+ .pm = &ehci_msm_dev_pm_ops,
+ },
+};
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index ac9c4d7c44af..fa59b26fc5bc 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -28,7 +28,7 @@
#define ULPI_VIEWPORT_OFFSET 0x170
struct ehci_mxc_priv {
- struct clk *usbclk, *ahbclk;
+ struct clk *usbclk, *ahbclk, *phy1clk;
struct usb_hcd *hcd;
};
@@ -38,10 +38,6 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
- /* EHCI registers start at offset 0x100 */
- ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -92,6 +88,7 @@ static const struct hc_driver ehci_mxc_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@@ -107,6 +104,8 @@ static const struct hc_driver ehci_mxc_hc_driver = {
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_mxc_drv_probe(struct platform_device *pdev)
@@ -114,9 +113,10 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd;
struct resource *res;
- int irq, ret, temp;
+ int irq, ret;
struct ehci_mxc_priv *priv;
struct device *dev = &pdev->dev;
+ struct ehci_hcd *ehci;
dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
@@ -160,17 +160,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
goto err_ioremap;
}
- /* call platform specific init function */
- if (pdata->init) {
- ret = pdata->init(pdev);
- if (ret) {
- dev_err(dev, "platform init failed\n");
- goto err_init;
- }
- /* platforms need some time to settle changed IO settings */
- mdelay(10);
- }
-
/* enable clocks */
priv->usbclk = clk_get(dev, "usb");
if (IS_ERR(priv->usbclk)) {
@@ -188,15 +177,46 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
clk_enable(priv->ahbclk);
}
- /* set up the PORTSCx register */
- ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
- mdelay(10);
+ /* "dr" device has its own clock */
+ if (pdev->id == 0) {
+ priv->phy1clk = clk_get(dev, "usb_phy1");
+ if (IS_ERR(priv->phy1clk)) {
+ ret = PTR_ERR(priv->phy1clk);
+ goto err_clk_phy;
+ }
+ clk_enable(priv->phy1clk);
+ }
+
+
+ /* call platform specific init function */
+ if (pdata->init) {
+ ret = pdata->init(pdev);
+ if (ret) {
+ dev_err(dev, "platform init failed\n");
+ goto err_init;
+ }
+ /* platforms need some time to settle changed IO settings */
+ mdelay(10);
+ }
/* setup specific usb hw */
ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
if (ret < 0)
goto err_init;
+ ehci = hcd_to_ehci(hcd);
+
+ /* EHCI registers start at offset 0x100 */
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100 +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* set up the PORTSCx register */
+ ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
+
+ /* is this really needed? */
+ msleep(10);
+
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
@@ -226,6 +246,11 @@ err_add:
if (pdata && pdata->exit)
pdata->exit(pdev);
err_init:
+ if (priv->phy1clk) {
+ clk_disable(priv->phy1clk);
+ clk_put(priv->phy1clk);
+ }
+err_clk_phy:
if (priv->ahbclk) {
clk_disable(priv->ahbclk);
clk_put(priv->ahbclk);
@@ -269,6 +294,10 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
clk_disable(priv->ahbclk);
clk_put(priv->ahbclk);
}
+ if (priv->phy1clk) {
+ clk_disable(priv->phy1clk);
+ clk_put(priv->phy1clk);
+ }
kfree(priv);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 116ae280053a..680f2ef4e59f 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -1,11 +1,12 @@
/*
- * ehci-omap.c - driver for USBHOST on OMAP 34xx processor
+ * ehci-omap.c - driver for USBHOST on OMAP3/4 processors
*
- * Bus Glue for OMAP34xx USBHOST 3 port EHCI controller
- * Tested on OMAP3430 ES2.0 SDP
+ * Bus Glue for the EHCI controllers in OMAP3/4
+ * Tested on several OMAP3 boards, and OMAP4 Pandaboard
*
- * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
* Author: Vikram Pandita <vikram.pandita@ti.com>
+ * Author: Anand Gadiyar <gadiyar@ti.com>
*
* Copyright (C) 2009 Nokia Corporation
* Contact: Felipe Balbi <felipe.balbi@nokia.com>
@@ -26,11 +27,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * TODO (last updated Feb 12, 2010):
+ * TODO (last updated Nov 21, 2010):
* - add kernel-doc
* - enable AUTOIDLE
* - add suspend/resume
* - move workarounds to board-files
+ * - factor out code common to OHCI
+ * - add HSIC and TLL support
+ * - convert to use hwmod and runtime PM
*/
#include <linux/platform_device.h>
@@ -86,9 +90,9 @@
#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
#define OMAP_TLL_CHANNEL_COUNT 3
-#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 1)
-#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 2)
-#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 4)
+#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
+#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
+#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
/* UHH Register Set */
#define OMAP_UHH_REVISION (0x00)
@@ -114,6 +118,23 @@
#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9)
#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10)
+/* OMAP4-specific defines */
+#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2)
+#define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2)
+
+#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4)
+#define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4)
+#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0)
+
+#define OMAP4_P1_MODE_CLEAR (3 << 16)
+#define OMAP4_P1_MODE_TLL (1 << 16)
+#define OMAP4_P1_MODE_HSIC (3 << 16)
+#define OMAP4_P2_MODE_CLEAR (3 << 18)
+#define OMAP4_P2_MODE_TLL (1 << 18)
+#define OMAP4_P2_MODE_HSIC (3 << 18)
+
+#define OMAP_REV2_TLL_CHANNEL_COUNT 2
+
#define OMAP_UHH_DEBUG_CSR (0x44)
/* EHCI Register Set */
@@ -127,6 +148,17 @@
#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
+/* Values of UHH_REVISION - Note: these are not given in the TRM */
+#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */
+#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */
+
+#define is_omap_ehci_rev1(x) (x->omap_ehci_rev == OMAP_EHCI_REV1)
+#define is_omap_ehci_rev2(x) (x->omap_ehci_rev == OMAP_EHCI_REV2)
+
+#define is_ehci_phy_mode(x) (x == EHCI_HCD_OMAP_MODE_PHY)
+#define is_ehci_tll_mode(x) (x == EHCI_HCD_OMAP_MODE_TLL)
+#define is_ehci_hsic_mode(x) (x == EHCI_HCD_OMAP_MODE_HSIC)
+
/*-------------------------------------------------------------------------*/
static inline void ehci_omap_writel(void __iomem *base, u32 reg, u32 val)
@@ -156,10 +188,14 @@ struct ehci_hcd_omap {
struct device *dev;
struct clk *usbhost_ick;
- struct clk *usbhost2_120m_fck;
- struct clk *usbhost1_48m_fck;
+ struct clk *usbhost_hs_fck;
+ struct clk *usbhost_fs_fck;
struct clk *usbtll_fck;
struct clk *usbtll_ick;
+ struct clk *xclk60mhsp1_ck;
+ struct clk *xclk60mhsp2_ck;
+ struct clk *utmi_p1_fck;
+ struct clk *utmi_p2_fck;
/* FIXME the following two workarounds are
* board specific not silicon-specific so these
@@ -176,6 +212,9 @@ struct ehci_hcd_omap {
/* phy reset workaround */
int phy_reset;
+ /* IP revision */
+ u32 omap_ehci_rev;
+
/* desired phy_mode: TLL, PHY */
enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS];
@@ -191,13 +230,14 @@ struct ehci_hcd_omap {
/*-------------------------------------------------------------------------*/
-static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask)
+static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask,
+ u8 tll_channel_count)
{
unsigned reg;
int i;
/* Program the 3 TLL channels upfront */
- for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+ for (i = 0; i < tll_channel_count; i++) {
reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
/* Disable AutoIdle, BitStuffing and use SDR Mode */
@@ -217,7 +257,7 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask)
ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);
/* Enable channels now */
- for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+ for (i = 0; i < tll_channel_count; i++) {
reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
/* Enable only the reg that is needed */
@@ -286,19 +326,19 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
}
clk_enable(omap->usbhost_ick);
- omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
- if (IS_ERR(omap->usbhost2_120m_fck)) {
- ret = PTR_ERR(omap->usbhost2_120m_fck);
+ omap->usbhost_hs_fck = clk_get(omap->dev, "hs_fck");
+ if (IS_ERR(omap->usbhost_hs_fck)) {
+ ret = PTR_ERR(omap->usbhost_hs_fck);
goto err_host_120m_fck;
}
- clk_enable(omap->usbhost2_120m_fck);
+ clk_enable(omap->usbhost_hs_fck);
- omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
- if (IS_ERR(omap->usbhost1_48m_fck)) {
- ret = PTR_ERR(omap->usbhost1_48m_fck);
+ omap->usbhost_fs_fck = clk_get(omap->dev, "fs_fck");
+ if (IS_ERR(omap->usbhost_fs_fck)) {
+ ret = PTR_ERR(omap->usbhost_fs_fck);
goto err_host_48m_fck;
}
- clk_enable(omap->usbhost1_48m_fck);
+ clk_enable(omap->usbhost_fs_fck);
if (omap->phy_reset) {
/* Refer: ISSUE1 */
@@ -333,6 +373,80 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
}
clk_enable(omap->usbtll_ick);
+ omap->omap_ehci_rev = ehci_omap_readl(omap->uhh_base,
+ OMAP_UHH_REVISION);
+ dev_dbg(omap->dev, "OMAP UHH_REVISION 0x%x\n",
+ omap->omap_ehci_rev);
+
+ /*
+ * Enable per-port clocks as needed (newer controllers only).
+ * - External ULPI clock for PHY mode
+ * - Internal clocks for TLL and HSIC modes (TODO)
+ */
+ if (is_omap_ehci_rev2(omap)) {
+ switch (omap->port_mode[0]) {
+ case EHCI_HCD_OMAP_MODE_PHY:
+ omap->xclk60mhsp1_ck = clk_get(omap->dev,
+ "xclk60mhsp1_ck");
+ if (IS_ERR(omap->xclk60mhsp1_ck)) {
+ ret = PTR_ERR(omap->xclk60mhsp1_ck);
+ dev_err(omap->dev,
+ "Unable to get Port1 ULPI clock\n");
+ }
+
+ omap->utmi_p1_fck = clk_get(omap->dev,
+ "utmi_p1_gfclk");
+ if (IS_ERR(omap->utmi_p1_fck)) {
+ ret = PTR_ERR(omap->utmi_p1_fck);
+ dev_err(omap->dev,
+ "Unable to get utmi_p1_fck\n");
+ }
+
+ ret = clk_set_parent(omap->utmi_p1_fck,
+ omap->xclk60mhsp1_ck);
+ if (ret != 0) {
+ dev_err(omap->dev,
+ "Unable to set P1 f-clock\n");
+ }
+ break;
+ case EHCI_HCD_OMAP_MODE_TLL:
+ /* TODO */
+ default:
+ break;
+ }
+ switch (omap->port_mode[1]) {
+ case EHCI_HCD_OMAP_MODE_PHY:
+ omap->xclk60mhsp2_ck = clk_get(omap->dev,
+ "xclk60mhsp2_ck");
+ if (IS_ERR(omap->xclk60mhsp2_ck)) {
+ ret = PTR_ERR(omap->xclk60mhsp2_ck);
+ dev_err(omap->dev,
+ "Unable to get Port2 ULPI clock\n");
+ }
+
+ omap->utmi_p2_fck = clk_get(omap->dev,
+ "utmi_p2_gfclk");
+ if (IS_ERR(omap->utmi_p2_fck)) {
+ ret = PTR_ERR(omap->utmi_p2_fck);
+ dev_err(omap->dev,
+ "Unable to get utmi_p2_fck\n");
+ }
+
+ ret = clk_set_parent(omap->utmi_p2_fck,
+ omap->xclk60mhsp2_ck);
+ if (ret != 0) {
+ dev_err(omap->dev,
+ "Unable to set P2 f-clock\n");
+ }
+ break;
+ case EHCI_HCD_OMAP_MODE_TLL:
+ /* TODO */
+ default:
+ break;
+ }
+ }
+
+
/* perform TLL soft reset, and wait until reset is complete */
ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
OMAP_USBTLL_SYSCONFIG_SOFTRESET);
@@ -360,12 +474,20 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
/* Put UHH in NoIdle/NoStandby mode */
reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
- reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
- | OMAP_UHH_SYSCONFIG_SIDLEMODE
- | OMAP_UHH_SYSCONFIG_CACTIVITY
- | OMAP_UHH_SYSCONFIG_MIDLEMODE);
- reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
+ if (is_omap_ehci_rev1(omap)) {
+ reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
+ | OMAP_UHH_SYSCONFIG_SIDLEMODE
+ | OMAP_UHH_SYSCONFIG_CACTIVITY
+ | OMAP_UHH_SYSCONFIG_MIDLEMODE);
+ reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
+
+ } else if (is_omap_ehci_rev2(omap)) {
+ reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
+ reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
+ reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
+ reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
+ }
ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
@@ -376,40 +498,56 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
- if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
- reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
- if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
- reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
- if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
- reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
-
- /* Bypass the TLL module for PHY mode operation */
- if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
- dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
- if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
- (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
- (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
- else
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
- } else {
- dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
- if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
- else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
-
- if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
- else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
-
- if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
- else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
+ if (is_omap_ehci_rev1(omap)) {
+ if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+ if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+ if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+
+ /* Bypass the TLL module for PHY mode operation */
+ if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
+ dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
+ if (is_ehci_phy_mode(omap->port_mode[0]) ||
+ is_ehci_phy_mode(omap->port_mode[1]) ||
+ is_ehci_phy_mode(omap->port_mode[2]))
+ reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+ else
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+ } else {
+ dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
+ if (is_ehci_phy_mode(omap->port_mode[0]))
+ reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+ else if (is_ehci_tll_mode(omap->port_mode[0]))
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+
+ if (is_ehci_phy_mode(omap->port_mode[1]))
+ reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
+ else if (is_ehci_tll_mode(omap->port_mode[1]))
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
+
+ if (is_ehci_phy_mode(omap->port_mode[2]))
+ reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
+ else if (is_ehci_tll_mode(omap->port_mode[2]))
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
+ }
+ } else if (is_omap_ehci_rev2(omap)) {
+ /* Clear port mode fields for PHY mode*/
+ reg &= ~OMAP4_P1_MODE_CLEAR;
+ reg &= ~OMAP4_P2_MODE_CLEAR;
+
+ if (is_ehci_tll_mode(omap->port_mode[0]))
+ reg |= OMAP4_P1_MODE_TLL;
+ else if (is_ehci_hsic_mode(omap->port_mode[0]))
+ reg |= OMAP4_P1_MODE_HSIC;
+ if (is_ehci_tll_mode(omap->port_mode[1]))
+ reg |= OMAP4_P2_MODE_TLL;
+ else if (is_ehci_hsic_mode(omap->port_mode[1]))
+ reg |= OMAP4_P2_MODE_HSIC;
}
+
ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
@@ -438,7 +576,7 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;
/* Enable UTMI mode for required TLL channels */
- omap_usb_utmi_init(omap, tll_ch_mask);
+ omap_usb_utmi_init(omap, tll_ch_mask, OMAP_TLL_CHANNEL_COUNT);
}
if (omap->phy_reset) {
@@ -464,6 +602,14 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
return 0;
err_sys_status:
+ clk_disable(omap->utmi_p2_fck);
+ clk_put(omap->utmi_p2_fck);
+ clk_disable(omap->xclk60mhsp2_ck);
+ clk_put(omap->xclk60mhsp2_ck);
+ clk_disable(omap->utmi_p1_fck);
+ clk_put(omap->utmi_p1_fck);
+ clk_disable(omap->xclk60mhsp1_ck);
+ clk_put(omap->xclk60mhsp1_ck);
clk_disable(omap->usbtll_ick);
clk_put(omap->usbtll_ick);
@@ -472,8 +618,8 @@ err_tll_ick:
clk_put(omap->usbtll_fck);
err_tll_fck:
- clk_disable(omap->usbhost1_48m_fck);
- clk_put(omap->usbhost1_48m_fck);
+ clk_disable(omap->usbhost_fs_fck);
+ clk_put(omap->usbhost_fs_fck);
if (omap->phy_reset) {
if (gpio_is_valid(omap->reset_gpio_port[0]))
@@ -484,8 +630,8 @@ err_tll_fck:
}
err_host_48m_fck:
- clk_disable(omap->usbhost2_120m_fck);
- clk_put(omap->usbhost2_120m_fck);
+ clk_disable(omap->usbhost_hs_fck);
+ clk_put(omap->usbhost_hs_fck);
err_host_120m_fck:
clk_disable(omap->usbhost_ick);
@@ -503,6 +649,8 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
/* Reset OMAP modules for insmod/rmmod to work */
ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
+ is_omap_ehci_rev2(omap) ?
+ OMAP4_UHH_SYSCONFIG_SOFTRESET :
OMAP_UHH_SYSCONFIG_SOFTRESET);
while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
& (1 << 0))) {
@@ -550,16 +698,16 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
omap->usbhost_ick = NULL;
}
- if (omap->usbhost1_48m_fck != NULL) {
- clk_disable(omap->usbhost1_48m_fck);
- clk_put(omap->usbhost1_48m_fck);
- omap->usbhost1_48m_fck = NULL;
+ if (omap->usbhost_fs_fck != NULL) {
+ clk_disable(omap->usbhost_fs_fck);
+ clk_put(omap->usbhost_fs_fck);
+ omap->usbhost_fs_fck = NULL;
}
- if (omap->usbhost2_120m_fck != NULL) {
- clk_disable(omap->usbhost2_120m_fck);
- clk_put(omap->usbhost2_120m_fck);
- omap->usbhost2_120m_fck = NULL;
+ if (omap->usbhost_hs_fck != NULL) {
+ clk_disable(omap->usbhost_hs_fck);
+ clk_put(omap->usbhost_hs_fck);
+ omap->usbhost_hs_fck = NULL;
}
if (omap->usbtll_ick != NULL) {
@@ -568,6 +716,32 @@ static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
omap->usbtll_ick = NULL;
}
+ if (is_omap_ehci_rev2(omap)) {
+ if (omap->xclk60mhsp1_ck != NULL) {
+ clk_disable(omap->xclk60mhsp1_ck);
+ clk_put(omap->xclk60mhsp1_ck);
+ omap->xclk60mhsp1_ck = NULL;
+ }
+
+ if (omap->utmi_p1_fck != NULL) {
+ clk_disable(omap->utmi_p1_fck);
+ clk_put(omap->utmi_p1_fck);
+ omap->utmi_p1_fck = NULL;
+ }
+
+ if (omap->xclk60mhsp2_ck != NULL) {
+ clk_disable(omap->xclk60mhsp2_ck);
+ clk_put(omap->xclk60mhsp2_ck);
+ omap->xclk60mhsp2_ck = NULL;
+ }
+
+ if (omap->utmi_p2_fck != NULL) {
+ clk_disable(omap->utmi_p2_fck);
+ clk_put(omap->utmi_p2_fck);
+ omap->utmi_p2_fck = NULL;
+ }
+ }
+
if (omap->phy_reset) {
if (gpio_is_valid(omap->reset_gpio_port[0]))
gpio_free(omap->reset_gpio_port[0]);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a1e8d273103f..76179c39c0e3 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -22,6 +22,9 @@
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
+/* defined here to avoid adding to pci_ids.h for single instance use */
+#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
+
/*-------------------------------------------------------------------------*/
/* called after powerup, by probe or system-pm "wakeup" */
@@ -41,6 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
return 0;
}
+static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci)
+{
+ struct pci_dev *amd_smbus_dev;
+ u8 rev = 0;
+
+ amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
+ if (!amd_smbus_dev)
+ return 0;
+
+ pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+ if (rev < 0x40) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+ return 0;
+ }
+
+ if (!amd_nb_dev)
+ amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
+ if (!amd_nb_dev)
+ ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
+
+ ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n");
+
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+
+ return 1;
+}
+
/* called during probe() after chip reset completes */
static int ehci_pci_setup(struct usb_hcd *hcd)
{
@@ -99,10 +131,26 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ if (ehci_quirk_amd_SB800(ehci))
+ ehci->amd_l1_fix = 1;
+
retval = ehci_halt(ehci);
if (retval)
return retval;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+ (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+ /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
+ */
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+ "dummy qh workaround\n");
+ }
+
/* data structure init */
retval = ehci_init(hcd);
if (retval)
@@ -124,6 +172,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci_info(ehci, "disable lpm for langwell/penwell\n");
ehci->has_lpm = 0;
}
+ if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
+ hcd->has_tt = 1;
+ tdi_reset(ehci);
+ }
break;
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
@@ -148,6 +200,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;
+
+ /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+ * fetching device descriptors unless LPM is disabled.
+ * There are also intermittent problems enumerating
+ * devices with PPCD enabled.
+ */
+ case 0x0d9d:
+ ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+ ehci->has_lpm = 0;
+ ehci->has_ppcd = 0;
+ ehci->command &= ~CMD_PPCEE;
+ break;
}
break;
case PCI_VENDOR_ID_VIA:
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a92526d6e5ae..aa46f57f9ec8 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
*/
*prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
- *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+
+ if (!ehci->use_dummy_qh ||
+ *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
+ != EHCI_LIST_END(ehci))
+ *hw_p = *shadow_next_periodic(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+ else
+ *hw_p = ehci->dummy->qh_dma;
}
/* how many of the uframe's 125 usecs are allocated? */
@@ -1583,6 +1590,63 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
+#define AB_REG_BAR_LOW 0xe0
+#define AB_REG_BAR_HIGH 0xe1
+#define AB_INDX(addr) ((addr) + 0x00)
+#define AB_DATA(addr) ((addr) + 0x04)
+#define NB_PCIE_INDX_ADDR 0xe0
+#define NB_PCIE_INDX_DATA 0xe4
+#define NB_PIF0_PWRDOWN_0 0x01100012
+#define NB_PIF0_PWRDOWN_1 0x01100013
+
+static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable)
+{
+ u32 addr, addr_low, addr_high, val;
+
+ outb_p(AB_REG_BAR_LOW, 0xcd6);
+ addr_low = inb_p(0xcd7);
+ outb_p(AB_REG_BAR_HIGH, 0xcd6);
+ addr_high = inb_p(0xcd7);
+ addr = addr_high << 8 | addr_low;
+ outl_p(0x30, AB_INDX(addr));
+ outl_p(0x40, AB_DATA(addr));
+ outl_p(0x34, AB_INDX(addr));
+ val = inl_p(AB_DATA(addr));
+
+ if (disable) {
+ val &= ~0x8;
+ val |= (1 << 4) | (1 << 9);
+ } else {
+ val |= 0x8;
+ val &= ~((1 << 4) | (1 << 9));
+ }
+ outl_p(val, AB_DATA(addr));
+
+ if (amd_nb_dev) {
+ addr = NB_PIF0_PWRDOWN_0;
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
+ pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
+ if (disable)
+ val &= ~(0x3f << 7);
+ else
+ val |= 0x3f << 7;
+
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
+
+ addr = NB_PIF0_PWRDOWN_1;
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
+ pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
+ if (disable)
+ val &= ~(0x3f << 7);
+ else
+ val |= 0x3f << 7;
+
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
+ }
+
+ return;
+}
+
/* fit urb's itds into the selected schedule slot; activate as needed */
static int
itd_link_urb (
@@ -1609,6 +1673,12 @@ itd_link_urb (
urb->interval,
next_uframe >> 3, next_uframe & 0x7);
}
+
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 1);
+ }
+
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill iTDs uframe by uframe */
@@ -1733,6 +1803,11 @@ itd_complete (
(void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 0);
+ }
+
if (unlikely(list_is_singular(&stream->td_list))) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
@@ -2018,6 +2093,12 @@ sitd_link_urb (
(next_uframe >> 3) & (ehci->periodic_size - 1),
stream->interval, hc32_to_cpu(ehci, stream->splits));
}
+
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 1);
+ }
+
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill sITDs frame by frame */
@@ -2118,6 +2199,11 @@ sitd_complete (
(void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 0);
+ }
+
if (list_is_singular(&stream->td_list)) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
@@ -2335,7 +2421,11 @@ restart:
* pointer for much longer, if at all.
*/
*q_p = q.itd->itd_next;
- *hw_p = q.itd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.itd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.itd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
@@ -2368,7 +2458,11 @@ restart:
* URB completion.
*/
*q_p = q.sitd->sitd_next;
- *hw_p = q.sitd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.sitd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.sitd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
new file mode 100644
index 000000000000..595f70f42b52
--- /dev/null
+++ b/drivers/usb/host/ehci-sh.c
@@ -0,0 +1,243 @@
+/*
+ * SuperH EHCI host controller driver
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * Based on ohci-sh.c and ehci-atmel.c.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+struct ehci_sh_priv {
+ struct clk *iclk, *fclk;
+ struct usb_hcd *hcd;
+};
+
+static int ehci_sh_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ &ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ ret = ehci_halt(ehci);
+ if (unlikely(ret))
+ return ret;
+
+ ret = ehci_init(hcd);
+ if (unlikely(ret))
+ return ret;
+
+ ehci->sbrn = 0x20;
+
+ ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+
+ return ret;
+}
+
+static const struct hc_driver ehci_sh_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SuperH EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_sh_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+
+#ifdef CONFIG_PM
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_sh_probe(struct platform_device *pdev)
+{
+ const struct hc_driver *driver = &ehci_sh_hc_driver;
+ struct resource *res;
+ struct ehci_sh_priv *priv;
+ struct usb_hcd *hcd;
+ int irq, ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto fail_create_hcd;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto fail_create_hcd;
+ }
+
+ /* initialize hcd */
+ hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto fail_request_resource;
+ }
+
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -ENXIO;
+ goto fail_ioremap;
+ }
+
+ priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_dbg(&pdev->dev, "error allocating priv data\n");
+ ret = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ /* These are optional, we don't care if they fail */
+ priv->fclk = clk_get(&pdev->dev, "usb_fck");
+ if (IS_ERR(priv->fclk))
+ priv->fclk = NULL;
+
+ priv->iclk = clk_get(&pdev->dev, "usb_ick");
+ if (IS_ERR(priv->iclk))
+ priv->iclk = NULL;
+
+ clk_enable(priv->fclk);
+ clk_enable(priv->iclk);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to add hcd");
+ goto fail_add_hcd;
+ }
+
+ priv->hcd = hcd;
+ platform_set_drvdata(pdev, priv);
+
+ return ret;
+
+fail_add_hcd:
+ clk_disable(priv->iclk);
+ clk_disable(priv->fclk);
+
+ clk_put(priv->iclk);
+ clk_put(priv->fclk);
+
+ kfree(priv);
+fail_alloc:
+ iounmap(hcd->regs);
+fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
+
+ return ret;
+}
+
+static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
+{
+ struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = priv->hcd;
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ clk_disable(priv->fclk);
+ clk_disable(priv->iclk);
+
+ clk_put(priv->fclk);
+ clk_put(priv->iclk);
+
+ kfree(priv);
+
+ return 0;
+}
+
+static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
+{
+ struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = priv->hcd;
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver ehci_hcd_sh_driver = {
+ .probe = ehci_hcd_sh_probe,
+ .remove = __exit_p(ehci_hcd_sh_remove),
+ .shutdown = ehci_hcd_sh_shutdown,
+ .driver = {
+ .name = "sh_ehci",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS("platform:sh_ehci");
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
new file mode 100644
index 000000000000..75c00873443d
--- /dev/null
+++ b/drivers/usb/host/ehci-spear.c
@@ -0,0 +1,212 @@
+/*
+* Driver for EHCI HCD on SPEAR SOC
+*
+* Copyright (C) 2010 ST Micro Electronics,
+* Deepak Sikri <deepak.sikri@st.com>
+*
+* Based on various ehci-*.c drivers
+*
+* This file is subject to the terms and conditions of the GNU General Public
+* License. See the file COPYING in the main directory of this archive for
+* more details.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+struct spear_ehci {
+ struct ehci_hcd ehci;
+ struct clk *clk;
+};
+
+#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd)
+
+static void spear_start_ehci(struct spear_ehci *ehci)
+{
+ clk_enable(ehci->clk);
+}
+
+static void spear_stop_ehci(struct spear_ehci *ehci)
+{
+ clk_disable(ehci->clk);
+}
+
+static int ehci_spear_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval = 0;
+
+ /* registers start at offset 0x0 */
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ &ehci->caps->hc_capbase));
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+
+ return retval;
+}
+
+static const struct hc_driver ehci_spear_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SPEAr EHCI",
+ .hcd_priv_size = sizeof(struct spear_ehci),
+
+ /* generic hardware linkage */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /* basic lifecycle operations */
+ .reset = ehci_spear_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /* managing i/o requests and associated device resources */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /* scheduling support */
+ .get_frame_number = ehci_get_frame,
+
+ /* root hub support */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd ;
+ struct spear_ehci *ehci;
+ struct resource *res;
+ struct clk *usbh_clk;
+ const struct hc_driver *driver = &ehci_spear_hc_driver;
+ int *pdata = pdev->dev.platform_data;
+ int irq, retval;
+ char clk_name[20] = "usbh_clk";
+
+ if (pdata == NULL)
+ return -EFAULT;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ retval = irq;
+ goto fail_irq_get;
+ }
+
+ if (*pdata >= 0)
+ sprintf(clk_name, "usbh.%01d_clk", *pdata);
+
+ usbh_clk = clk_get(NULL, clk_name);
+ if (IS_ERR(usbh_clk)) {
+ dev_err(&pdev->dev, "Error getting interface clock\n");
+ retval = PTR_ERR(usbh_clk);
+ goto fail_get_usbh_clk;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ retval = -ENODEV;
+ goto fail_request_resource;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ retval = -EBUSY;
+ goto fail_request_resource;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ retval = -ENOMEM;
+ goto fail_ioremap;
+ }
+
+ ehci = (struct spear_ehci *)hcd_to_ehci(hcd);
+ ehci->clk = usbh_clk;
+
+ spear_start_ehci(ehci);
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ if (retval)
+ goto fail_add_hcd;
+
+ return retval;
+
+fail_add_hcd:
+ spear_stop_ehci(ehci);
+ iounmap(hcd->regs);
+fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ clk_put(usbh_clk);
+fail_get_usbh_clk:
+fail_irq_get:
+ dev_err(&pdev->dev, "init fail, %d\n", retval);
+
+ return retval ;
+}
+
+static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct spear_ehci *ehci_p = to_spear_ehci(hcd);
+
+ if (!hcd)
+ return 0;
+ if (in_interrupt())
+ BUG();
+ usb_remove_hcd(hcd);
+
+ if (ehci_p->clk)
+ spear_stop_ehci(ehci_p);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ if (ehci_p->clk)
+ clk_put(ehci_p->clk);
+
+ return 0;
+}
+
+static struct platform_driver spear_ehci_hcd_driver = {
+ .probe = spear_ehci_hcd_drv_probe,
+ .remove = spear_ehci_hcd_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "spear-ehci",
+ .bus = &platform_bus_type
+ }
+};
+
+MODULE_ALIAS("platform:spear-ehci");
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
new file mode 100644
index 000000000000..20168062035a
--- /dev/null
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -0,0 +1,172 @@
+/*
+ * drivers/usb/host/ehci-vt8500.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on ehci-au1xxx.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int rc = 0;
+
+ if (!udev->parent) /* udev is root hub itself, impossible */
+ rc = -1;
+ /* we only support lpm device connected to root hub yet */
+ if (ehci->has_lpm && !udev->parent->parent) {
+ rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum);
+ if (!rc)
+ rc = ehci_lpm_check(ehci, udev->portnum);
+ }
+ return rc;
+}
+
+static const struct hc_driver vt8500_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "VT8500 EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /*
+ * call back when device connected and addressed
+ */
+ .update_device = ehci_update_device,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int vt8500_ehci_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource *res;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+ hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500");
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ ret = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+ ehci_port_power(ehci, 1);
+
+ ret = usb_add_hcd(hcd, pdev->resource[1].start,
+ IRQF_DISABLED | IRQF_SHARED);
+ if (ret == 0) {
+ platform_set_drvdata(pdev, hcd);
+ return ret;
+ }
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int vt8500_ehci_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_ehci_driver = {
+ .probe = vt8500_ehci_drv_probe,
+ .remove = vt8500_ehci_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "vt8500-ehci",
+ .owner = THIS_MODULE,
+ }
+};
+
+MODULE_ALIAS("platform:vt8500-ehci");
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index cfa21ea20f82..6bc35809a5c6 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -130,6 +130,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@@ -147,6 +148,8 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
#endif
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int __devinit ehci_w90x900_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 6c8076ad821d..e8f4f36fdf0b 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -117,6 +117,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bde823f704e9..799ac16a54b4 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -73,6 +73,7 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
+ struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
unsigned scanning : 1;
@@ -130,7 +131,9 @@ struct ehci_hcd { /* one per controller */
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
+ unsigned amd_l1_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
+ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 20092a27a1e8..12fd184226f2 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -98,13 +98,13 @@ void fhci_usb_enable_interrupt(struct fhci_usb *usb)
usb->intr_nesting_cnt--;
}
-/* diable the usb interrupt */
+/* disable the usb interrupt */
void fhci_usb_disable_interrupt(struct fhci_usb *usb)
{
struct fhci_hcd *fhci = usb->fhci;
if (usb->intr_nesting_cnt == 0) {
- /* diable the timer interrupt */
+ /* disable the timer interrupt */
disable_irq_nosync(fhci->timer->irq);
/* disable the usb interrupt */
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 7be548ca2183..38fe058fbe61 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -271,8 +271,8 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep,
/*
* Collect the submitted frames and inform the application about them
- * It is also prepearing the TDs for new frames. If the Tx interrupts
- * are diabled, the application should call that routine to get
+ * It is also preparing the TDs for new frames. If the Tx interrupts
+ * are disabled, the application should call that routine to get
* confirmation about the submitted frames. Otherwise, the routine is
* called frome the interrupt service routine during the Tx interrupt.
* In that case the application is informed by calling the application
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index e49b75a78000..f90d003f2302 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1658,7 +1658,7 @@ static int imx21_hc_reset(struct usb_hcd *hcd)
spin_lock_irqsave(&imx21->lock, flags);
- /* Reset the Host controler modules */
+ /* Reset the Host controller modules */
writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH |
USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC,
imx21->regs + USBOTG_RST_CTRL);
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 8196fa11fec4..43a39eb56cc6 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -70,7 +70,6 @@
#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/list.h>
@@ -2684,7 +2683,7 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
return 0;
}
-static int __init isp1362_probe(struct platform_device *pdev)
+static int __devinit isp1362_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp1362_hcd *isp1362_hcd;
diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c
new file mode 100644
index 000000000000..f05ef87e934c
--- /dev/null
+++ b/drivers/usb/host/ohci-cns3xxx.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/atomic.h>
+#include <mach/cns3xxx.h>
+#include <mach/pm.h>
+
+static int __devinit
+cns3xxx_ohci_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ /*
+ * EHCI and OHCI share the same clock and power,
+ * resetting twice would cause the 1st controller been reset.
+ * Therefore only do power up at the first up device, and
+ * power down at the last down device.
+ *
+ * Set USB AHB INCR length to 16
+ */
+ if (atomic_inc_return(&usb_pwr_ref) == 1) {
+ cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
+ cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
+ cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST);
+ __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)),
+ MISC_CHIP_CONFIG_REG);
+ }
+
+ ret = ohci_init(ohci);
+ if (ret < 0)
+ return ret;
+
+ ohci->num_ports = 1;
+
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct hc_driver cns3xxx_ohci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "CNS3XXX OHCI Host controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .start = cns3xxx_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int cns3xxx_ohci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd;
+ const struct hc_driver *driver = &cns3xxx_ohci_hc_driver;
+ struct resource *res;
+ int irq;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "Found HC with no IRQ.\n");
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(driver, dev, dev_name(dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "Found HC with no register addr.\n");
+ retval = -ENODEV;
+ goto err1;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err2;
+ }
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (retval == 0)
+ return retval;
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+static int cns3xxx_ohci_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ /*
+ * EHCI and OHCI share the same clock and power,
+ * resetting twice would cause the 1st controller been reset.
+ * Therefore only do power up at the first up device, and
+ * power down at the last down device.
+ */
+ if (atomic_dec_return(&usb_pwr_ref) == 0)
+ cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
+
+ usb_put_hcd(hcd);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:cns3xxx-ohci");
+
+static struct platform_driver ohci_hcd_cns3xxx_driver = {
+ .probe = cns3xxx_ohci_probe,
+ .remove = cns3xxx_ohci_remove,
+ .driver = {
+ .name = "cns3xxx-ohci",
+ },
+};
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 5179acb7aa2f..759a12ff8048 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -901,7 +901,8 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_dump (ohci, 1);
- flush_scheduled_work();
+ if (quirk_nec(ohci))
+ flush_work_sync(&ohci->nec_work);
ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
@@ -1081,6 +1082,11 @@ MODULE_LICENSE ("GPL");
#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
#endif
+#ifdef CONFIG_PLAT_SPEAR
+#include "ohci-spear.c"
+#define PLATFORM_DRIVER spear_ohci_hcd_driver
+#endif
+
#ifdef CONFIG_PPC_PS3
#include "ohci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
@@ -1111,6 +1117,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_octeon_driver
#endif
+#ifdef CONFIG_USB_CNS3XXX_OHCI
+#include "ohci-cns3xxx.c"
+#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
index 10e1872f3ab9..931d588c3fb5 100644
--- a/drivers/usb/host/ohci-jz4740.c
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -273,4 +273,4 @@ static struct platform_driver ohci_hcd_jz4740_driver = {
},
};
-MODULE_ALIAS("platfrom:jz4740-ohci");
+MODULE_ALIAS("platform:jz4740-ohci");
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index 2cc8a504b18c..a37d5993e4e3 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -648,7 +648,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
ret = omap3_start_ohci(omap, hcd);
if (ret) {
- dev_dbg(&pdev->dev, "failed to start ehci\n");
+ dev_dbg(&pdev->dev, "failed to start ohci\n");
goto err_start;
}
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 0b35d22cc70e..f47867ff78c7 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -109,7 +109,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
hcd->regs = (void __iomem *)res->start;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret != 0) {
err("Failed to add hcd");
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
new file mode 100644
index 000000000000..4fd4bea9ac7a
--- /dev/null
+++ b/drivers/usb/host/ohci-spear.c
@@ -0,0 +1,240 @@
+/*
+* OHCI HCD (Host Controller Driver) for USB.
+*
+* Copyright (C) 2010 ST Microelectronics.
+* Deepak Sikri<deepak.sikri@st.com>
+*
+* Based on various ohci-*.c drivers
+*
+* This file is licensed under the terms of the GNU General Public
+* License version 2. This program is licensed "as is" without any
+* warranty of any kind, whether express or implied.
+*/
+
+#include <linux/signal.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+struct spear_ohci {
+ struct ohci_hcd ohci;
+ struct clk *clk;
+};
+
+#define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd)
+
+static void spear_start_ohci(struct spear_ohci *ohci)
+{
+ clk_enable(ohci->clk);
+}
+
+static void spear_stop_ohci(struct spear_ohci *ohci)
+{
+ clk_disable(ohci->clk);
+}
+
+static int __devinit ohci_spear_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ret = ohci_init(ohci);
+ if (ret < 0)
+ return ret;
+ ohci->regs = hcd->regs;
+
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ dev_err(hcd->self.controller, "can't start\n");
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ create_debug_files(ohci);
+
+#ifdef DEBUG
+ ohci_dump(ohci, 1);
+#endif
+ return 0;
+}
+
+static const struct hc_driver ohci_spear_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SPEAr OHCI",
+ .hcd_priv_size = sizeof(struct spear_ohci),
+
+ /* generic hardware linkage */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /* basic lifecycle operations */
+ .start = ohci_spear_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+
+ /* managing i/o requests and associated device resources */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /* scheduling support */
+ .get_frame_number = ohci_get_frame,
+
+ /* root hub support */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
+{
+ const struct hc_driver *driver = &ohci_spear_hc_driver;
+ struct usb_hcd *hcd = NULL;
+ struct clk *usbh_clk;
+ struct spear_ohci *ohci_p;
+ struct resource *res;
+ int retval, irq;
+ int *pdata = pdev->dev.platform_data;
+ char clk_name[20] = "usbh_clk";
+
+ if (pdata == NULL)
+ return -EFAULT;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ retval = irq;
+ goto fail_irq_get;
+ }
+
+ if (*pdata >= 0)
+ sprintf(clk_name, "usbh.%01d_clk", *pdata);
+
+ usbh_clk = clk_get(NULL, clk_name);
+ if (IS_ERR(usbh_clk)) {
+ dev_err(&pdev->dev, "Error getting interface clock\n");
+ retval = PTR_ERR(usbh_clk);
+ goto fail_get_usbh_clk;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ retval = -ENODEV;
+ goto fail_request_resource;
+ }
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = resource_size(res);
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ retval = -EBUSY;
+ goto fail_request_resource;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "ioremap failed\n");
+ retval = -ENOMEM;
+ goto fail_ioremap;
+ }
+
+ ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd);
+ ohci_p->clk = usbh_clk;
+ spear_start_ohci(ohci_p);
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), IRQF_DISABLED);
+ if (retval == 0)
+ return retval;
+
+ spear_stop_ohci(ohci_p);
+ iounmap(hcd->regs);
+fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ clk_put(usbh_clk);
+fail_get_usbh_clk:
+fail_irq_get:
+ dev_err(&pdev->dev, "init fail, %d\n", retval);
+
+ return retval;
+}
+
+static int spear_ohci_hcd_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct spear_ohci *ohci_p = to_spear_ohci(hcd);
+
+ usb_remove_hcd(hcd);
+ if (ohci_p->clk)
+ spear_stop_ohci(ohci_p);
+
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ if (ohci_p->clk)
+ clk_put(ohci_p->clk);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+static int spear_ohci_hcd_drv_suspend(struct platform_device *dev,
+ pm_message_t message)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct spear_ohci *ohci_p = to_spear_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ spear_stop_ohci(ohci_p);
+ ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+ return 0;
+}
+
+static int spear_ohci_hcd_drv_resume(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct spear_ohci *ohci_p = to_spear_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ spear_start_ohci(ohci_p);
+ ohci_finish_controller_resume(hcd);
+ return 0;
+}
+#endif
+
+/* Driver definition to register with the platform bus */
+static struct platform_driver spear_ohci_hcd_driver = {
+ .probe = spear_ohci_hcd_drv_probe,
+ .remove = spear_ohci_hcd_drv_remove,
+#ifdef CONFIG_PM
+ .suspend = spear_ohci_hcd_drv_suspend,
+ .resume = spear_ohci_hcd_drv_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "spear-ohci",
+ },
+};
+
+MODULE_ALIAS("platform:spear-ohci");
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 32149be4ad8e..e0cb12b573f9 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -3094,7 +3094,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf)
/* Some boards (mostly VIA?) report bogus overcurrent indications,
* causing massive log spam unless we completely ignore them. It
- * may be relevant that VIA VT8235 controlers, where PORT_POWER is
+ * may be relevant that VIA VT8235 controllers, where PORT_POWER is
* always set, seem to clear PORT_OCC and PORT_CSC when writing to
* PORT_POWER; that's surprising, but maybe within-spec.
*/
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 6e7fb5f38db6..ee60cd3ea642 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include "uhci-hcd.h"
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index f52d04db28f4..cee867829ec9 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -569,7 +569,7 @@ static int uhci_init(struct usb_hcd *hcd)
*/
static void uhci_shutdown(struct pci_dev *pdev)
{
- struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
+ struct usb_hcd *hcd = pci_get_drvdata(pdev);
uhci_hc_died(hcd_to_uhci(hcd));
}
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 2090b45eb606..af77abb5c68b 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -29,7 +29,7 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
- uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
+ uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
@@ -195,7 +195,9 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
} else {
struct uhci_td *ntd;
- ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+ ntd = list_entry(td->fl_list.next,
+ struct uhci_td,
+ fl_list);
uhci->frame[td->frame] = LINK_TO_TD(ntd);
uhci->frame_cpu[td->frame] = ntd;
}
@@ -728,7 +730,7 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
urbp->urb = urb;
urb->hcpriv = urbp;
-
+
INIT_LIST_HEAD(&urbp->node);
INIT_LIST_HEAD(&urbp->td_list);
@@ -846,7 +848,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
-
+
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(pktsze),
data);
@@ -857,7 +859,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
}
/*
- * Build the final TD for control status
+ * Build the final TD for control status
*/
td = uhci_alloc_td(uhci);
if (!td)
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
index 72b6892fda67..9546f6cd01f0 100644
--- a/drivers/usb/host/whci/hcd.c
+++ b/drivers/usb/host/whci/hcd.c
@@ -356,7 +356,7 @@ static void __exit whci_hc_driver_exit(void)
module_exit(whci_hc_driver_exit);
/* PCI device ID's that we handle (so it gets loaded) */
-static struct pci_device_id whci_hcd_id_table[] = {
+static struct pci_device_id __used whci_hcd_id_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
{ /* empty last entry */ }
};
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index fef5a1f9d483..5d963e350494 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
+ /* Don't allow the USB core to disable SuperSpeed ports. */
+ if (xhci->port_array[wIndex] == 0x03) {
+ xhci_dbg(xhci, "Ignoring request to disable "
+ "SuperSpeed port.\n");
+ return;
+ }
+
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
port_status = xhci_readl(xhci, addr);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 202770676da3..1d0f45f0e7a6 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1045,7 +1045,7 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
if (udev->speed == USB_SPEED_SUPER)
return ep->ss_ep_comp.wBytesPerInterval;
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
@@ -1135,7 +1135,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
break;
default:
@@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->dcbaa = NULL;
scratchpad_free(xhci);
+
+ xhci->num_usb2_ports = 0;
+ xhci->num_usb3_ports = 0;
+ kfree(xhci->usb2_ports);
+ kfree(xhci->usb3_ports);
+ kfree(xhci->port_array);
+
xhci->page_size = 0;
xhci->page_shift = 0;
xhci->bus_suspended = 0;
@@ -1627,6 +1634,166 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
&xhci->ir_set->erst_dequeue);
}
+static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+ u32 __iomem *addr, u8 major_revision)
+{
+ u32 temp, port_offset, port_count;
+ int i;
+
+ if (major_revision > 0x03) {
+ xhci_warn(xhci, "Ignoring unknown port speed, "
+ "Ext Cap %p, revision = 0x%x\n",
+ addr, major_revision);
+ /* Ignoring port protocol we can't understand. FIXME */
+ return;
+ }
+
+ /* Port offset and count in the third dword, see section 7.2 */
+ temp = xhci_readl(xhci, addr + 2);
+ port_offset = XHCI_EXT_PORT_OFF(temp);
+ port_count = XHCI_EXT_PORT_COUNT(temp);
+ xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
+ "count = %u, revision = 0x%x\n",
+ addr, port_offset, port_count, major_revision);
+ /* Port count includes the current port offset */
+ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
+ /* WTF? "Valid values are ‘1’ to MaxPorts" */
+ return;
+ port_offset--;
+ for (i = port_offset; i < (port_offset + port_count); i++) {
+ /* Duplicate entry. Ignore the port if the revisions differ. */
+ if (xhci->port_array[i] != 0) {
+ xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
+ " port %u\n", addr, i);
+ xhci_warn(xhci, "Port was marked as USB %u, "
+ "duplicated as USB %u\n",
+ xhci->port_array[i], major_revision);
+ /* Only adjust the roothub port counts if we haven't
+ * found a similar duplicate.
+ */
+ if (xhci->port_array[i] != major_revision &&
+ xhci->port_array[i] != (u8) -1) {
+ if (xhci->port_array[i] == 0x03)
+ xhci->num_usb3_ports--;
+ else
+ xhci->num_usb2_ports--;
+ xhci->port_array[i] = (u8) -1;
+ }
+ /* FIXME: Should we disable the port? */
+ continue;
+ }
+ xhci->port_array[i] = major_revision;
+ if (major_revision == 0x03)
+ xhci->num_usb3_ports++;
+ else
+ xhci->num_usb2_ports++;
+ }
+ /* FIXME: Should we disable ports not in the Extended Capabilities? */
+}
+
+/*
+ * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
+ * specify what speeds each port is supposed to be. We can't count on the port
+ * speed bits in the PORTSC register being correct until a device is connected,
+ * but we need to set up the two fake roothubs with the correct number of USB
+ * 3.0 and USB 2.0 ports at host controller initialization time.
+ */
+static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+{
+ u32 __iomem *addr;
+ u32 offset;
+ unsigned int num_ports;
+ int i, port_index;
+
+ addr = &xhci->cap_regs->hcc_params;
+ offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
+ if (offset == 0) {
+ xhci_err(xhci, "No Extended Capability registers, "
+ "unable to set up roothub.\n");
+ return -ENODEV;
+ }
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+ xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
+ if (!xhci->port_array)
+ return -ENOMEM;
+
+ /*
+ * For whatever reason, the first capability offset is from the
+ * capability register base, not from the HCCPARAMS register.
+ * See section 5.3.6 for offset calculation.
+ */
+ addr = &xhci->cap_regs->hc_capbase + offset;
+ while (1) {
+ u32 cap_id;
+
+ cap_id = xhci_readl(xhci, addr);
+ if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
+ xhci_add_in_port(xhci, num_ports, addr,
+ (u8) XHCI_EXT_PORT_MAJOR(cap_id));
+ offset = XHCI_EXT_CAPS_NEXT(cap_id);
+ if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
+ == num_ports)
+ break;
+ /*
+ * Once you're into the Extended Capabilities, the offset is
+ * always relative to the register holding the offset.
+ */
+ addr += offset;
+ }
+
+ if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
+ xhci_warn(xhci, "No ports on the roothubs?\n");
+ return -ENODEV;
+ }
+ xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+ xhci->num_usb2_ports, xhci->num_usb3_ports);
+ /*
+ * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
+ * Not sure how the USB core will handle a hub with no ports...
+ */
+ if (xhci->num_usb2_ports) {
+ xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
+ xhci->num_usb2_ports, flags);
+ if (!xhci->usb2_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++) {
+ if (xhci->port_array[i] == 0x03 ||
+ xhci->port_array[i] == 0 ||
+ xhci->port_array[i] == -1)
+ continue;
+
+ xhci->usb2_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 2.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb2_ports[port_index]);
+ port_index++;
+ }
+ }
+ if (xhci->num_usb3_ports) {
+ xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
+ xhci->num_usb3_ports, flags);
+ if (!xhci->usb3_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++)
+ if (xhci->port_array[i] == 0x03) {
+ xhci->usb3_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 3.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb3_ports[port_index]);
+ port_index++;
+ }
+ }
+ return 0;
+}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
@@ -1809,6 +1976,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
if (scratchpad_alloc(xhci, flags))
goto fail;
+ if (xhci_setup_port_arrays(xhci, flags))
+ goto fail;
return 0;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9f3115e729b1..df558f6f84e3 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2104,7 +2104,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (!(status & STS_EINT)) {
spin_unlock(&xhci->lock);
- xhci_warn(xhci, "Spurious interrupt.\n");
return IRQ_NONE;
}
xhci_dbg(xhci, "op reg status = %08x\n", status);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5d7d4e951ea4..45e4a3108cc3 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -577,6 +577,65 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
}
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+ u64 val_64;
+
+ /* step 2: initialize command ring buffer */
+ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+ (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+ xhci->cmd_ring->dequeue) &
+ (u64) ~CMD_RING_RSVD_BITS) |
+ xhci->cmd_ring->cycle_state;
+ xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+ (long unsigned long) val_64);
+ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+}
+
+/*
+ * The whole command ring must be cleared to zero when we suspend the host.
+ *
+ * The host doesn't save the command ring pointer in the suspend well, so we
+ * need to re-program it on resume. Unfortunately, the pointer must be 64-byte
+ * aligned, because of the reserved bits in the command ring dequeue pointer
+ * register. Therefore, we can't just set the dequeue pointer back in the
+ * middle of the ring (TRBs are 16-byte aligned).
+ */
+static void xhci_clear_command_ring(struct xhci_hcd *xhci)
+{
+ struct xhci_ring *ring;
+ struct xhci_segment *seg;
+
+ ring = xhci->cmd_ring;
+ seg = ring->deq_seg;
+ do {
+ memset(seg->trbs, 0, SEGMENT_SIZE);
+ seg = seg->next;
+ } while (seg != ring->deq_seg);
+
+ /* Reset the software enqueue and dequeue pointers */
+ ring->deq_seg = ring->first_seg;
+ ring->dequeue = ring->first_seg->trbs;
+ ring->enq_seg = ring->deq_seg;
+ ring->enqueue = ring->dequeue;
+
+ /*
+ * Ring is now zeroed, so the HW should look for change of ownership
+ * when the cycle bit is set to 1.
+ */
+ ring->cycle_state = 1;
+
+ /*
+ * Reset the hardware dequeue pointer.
+ * Yes, this will need to be re-written after resume, but we're paranoid
+ * and want to make sure the hardware doesn't access bogus memory
+ * because, say, the BIOS or an SMI started the host without changing
+ * the command ring pointers.
+ */
+ xhci_set_cmd_ring_deq(xhci);
+}
+
/*
* Stop HC (not bus-specific)
*
@@ -604,6 +663,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
}
+ xhci_clear_command_ring(xhci);
/* step 3: save registers */
xhci_save_registers(xhci);
@@ -635,7 +695,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
u32 command, temp = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- u64 val_64;
int old_state, retval;
old_state = hcd->state;
@@ -648,15 +707,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* step 1: restore register */
xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */
- val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
- val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
- (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
- xhci->cmd_ring->dequeue) &
- (u64) ~CMD_RING_RSVD_BITS) |
- xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
- (long unsigned long) val_64);
- xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+ xhci_set_cmd_ring_deq(xhci);
/* step 3: restore state and start state*/
/* step 3: set CRS flag */
command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -714,6 +765,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
return retval;
}
+ spin_unlock_irq(&xhci->lock);
/* Re-setup MSI-X */
if (hcd->irq)
free_irq(hcd->irq, hcd);
@@ -736,6 +788,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
hcd->irq = pdev->irq;
}
+ spin_lock_irq(&xhci->lock);
/* step 4: set Run/Stop bit */
command = xhci_readl(xhci, &xhci->op_regs->command);
command |= CMD_RUN;
@@ -1496,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ command->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
@@ -2219,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ reset_device_cmd->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 93d3bf4d213c..170c367112d2 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -454,6 +454,24 @@ struct xhci_doorbell_array {
/**
+ * struct xhci_protocol_caps
+ * @revision: major revision, minor revision, capability ID,
+ * and next capability pointer.
+ * @name_string: Four ASCII characters to say which spec this xHC
+ * follows, typically "USB ".
+ * @port_info: Port offset, count, and protocol-defined information.
+ */
+struct xhci_protocol_caps {
+ u32 revision;
+ u32 name_string;
+ u32 port_info;
+};
+
+#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
+#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
+#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)
+
+/**
* struct xhci_container_ctx
* @type: Type of context. Used to calculated offsets to contained contexts.
* @size: Size of the context data
@@ -621,6 +639,11 @@ struct xhci_ep_ctx {
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
+/* Get max packet size from ep desc. Bit 10..0 specify the max packet size.
+ * USB2.0 spec 9.6.6.
+ */
+#define GET_MAX_PACKET(p) ((p) & 0x7ff)
+
/* tx_info bitmasks */
#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
@@ -1235,6 +1258,14 @@ struct xhci_hcd {
u32 suspended_ports[8]; /* which ports are
suspended */
unsigned long resume_done[MAX_HC_PORTS];
+ /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
+ u8 *port_array;
+ /* Array of pointers to USB 3.0 PORTSC registers */
+ u32 __iomem **usb3_ports;
+ unsigned int num_usb3_ports;
+ /* Array of pointers to USB 2.0 PORTSC registers */
+ u32 __iomem **usb2_ports;
+ unsigned int num_usb2_ports;
};
/* For testing purposes */
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 5a47805d9580..c90c89dc0003 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -364,7 +364,7 @@ static int mts_scsi_host_reset(struct scsi_cmnd *srb)
}
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
+mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb);
static void mts_transfer_cleanup( struct urb *transfer );
static void mts_do_sg(struct urb * transfer);
@@ -573,7 +573,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
+mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int err = 0;
@@ -626,6 +626,8 @@ out:
return err;
}
+static DEF_SCSI_QCMD(mts_scsi_queuecommand)
+
static struct scsi_host_template mts_scsi_host_template = {
.module = THIS_MODULE,
.name = "microtekX6",
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 44f8b9225054..a6afd15f6a46 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -717,7 +717,7 @@ static int adu_probe(struct usb_interface *interface,
goto exit;
}
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index 2f43c57743c9..9251773ecef4 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -196,11 +196,9 @@ static ssize_t get_port1_handler(struct device *dev,
return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
}
-static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
- get_port0_handler, set_port0_handler);
+static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler);
-static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
- get_port1_handler, set_port1_handler);
+static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler);
static int cypress_probe(struct usb_interface *interface,
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 375664198776..e573e4704015 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -553,6 +553,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
/* needed for power consumption */
struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
+ memset(&info, 0, sizeof(info));
/* directly from the descriptor */
info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
info.product = dev->product_id;
@@ -768,7 +769,7 @@ static int iowarrior_probe(struct usb_interface *interface,
int i;
int retval = -ENOMEM;
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index edffef642337..eefb8275bb7e 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -642,7 +642,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
int i;
int retval = -ENOMEM;
- /* allocate memory for our device state and intialize it */
+ /* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 70d00e99a4b4..dd573abd2d1e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3008,6 +3008,7 @@ sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#else
x.sisusb_conactive = 0;
#endif
+ memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
if (copy_to_user((void __user *)arg, &x, sizeof(x)))
retval = -EFAULT;
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index d77aba46ae85..f63776a48e2a 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -86,7 +86,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed);
static int tv_probe(struct usb_interface *interface,
const struct usb_device_id *id)
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 63da2c3c838f..1732d9bc097e 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -1,5 +1,5 @@
/*
- * USB LED driver - 1.1
+ * USB LED driver
*
* Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
*
@@ -20,12 +20,17 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
#define DRIVER_DESC "USB LED Driver"
-#define VENDOR_ID 0x0fc5
-#define PRODUCT_ID 0x1223
+enum led_type {
+ DELCOM_VISUAL_SIGNAL_INDICATOR,
+ DREAM_CHEEKY_WEBMAIL_NOTIFIER,
+};
/* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {
- { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
+ { USB_DEVICE(0x0fc5, 0x1223),
+ .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
+ { USB_DEVICE(0x1d34, 0x0004),
+ .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ },
};
MODULE_DEVICE_TABLE (usb, id_table);
@@ -35,15 +40,12 @@ struct usb_led {
unsigned char blue;
unsigned char red;
unsigned char green;
+ enum led_type type;
};
-#define BLUE 0x04
-#define RED 0x02
-#define GREEN 0x01
static void change_color(struct usb_led *led)
{
int retval;
- unsigned char color = 0x07;
unsigned char *buffer;
buffer = kmalloc(8, GFP_KERNEL);
@@ -52,25 +54,59 @@ static void change_color(struct usb_led *led)
return;
}
- if (led->blue)
- color &= ~(BLUE);
- if (led->red)
- color &= ~(RED);
- if (led->green)
- color &= ~(GREEN);
- dev_dbg(&led->udev->dev,
- "blue = %d, red = %d, green = %d, color = %.2x\n",
- led->blue, led->red, led->green, color);
-
- retval = usb_control_msg(led->udev,
- usb_sndctrlpipe(led->udev, 0),
- 0x12,
- 0xc8,
- (0x02 * 0x100) + 0x0a,
- (0x00 * 0x100) + color,
- buffer,
- 8,
- 2000);
+ switch (led->type) {
+ case DELCOM_VISUAL_SIGNAL_INDICATOR: {
+ unsigned char color = 0x07;
+
+ if (led->blue)
+ color &= ~0x04;
+ if (led->red)
+ color &= ~0x02;
+ if (led->green)
+ color &= ~0x01;
+ dev_dbg(&led->udev->dev,
+ "blue = %d, red = %d, green = %d, color = %.2x\n",
+ led->blue, led->red, led->green, color);
+
+ retval = usb_control_msg(led->udev,
+ usb_sndctrlpipe(led->udev, 0),
+ 0x12,
+ 0xc8,
+ (0x02 * 0x100) + 0x0a,
+ (0x00 * 0x100) + color,
+ buffer,
+ 8,
+ 2000);
+ break;
+ }
+
+ case DREAM_CHEEKY_WEBMAIL_NOTIFIER:
+ dev_dbg(&led->udev->dev,
+ "red = %d, green = %d, blue = %d\n",
+ led->red, led->green, led->blue);
+
+ buffer[0] = led->red;
+ buffer[1] = led->green;
+ buffer[2] = led->blue;
+ buffer[3] = buffer[4] = buffer[5] = 0;
+ buffer[6] = 0x1a;
+ buffer[7] = 0x05;
+
+ retval = usb_control_msg(led->udev,
+ usb_sndctrlpipe(led->udev, 0),
+ 0x09,
+ 0x21,
+ 0x200,
+ 0,
+ buffer,
+ 8,
+ 2000);
+ break;
+
+ default:
+ dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
+ }
+
if (retval)
dev_dbg(&led->udev->dev, "retval = %d\n", retval);
kfree(buffer);
@@ -94,7 +130,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
change_color(led); \
return count; \
} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
show_set(blue);
show_set(red);
show_set(green);
@@ -107,11 +143,12 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
if (dev == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
+ dev_err(&interface->dev, "out of memory\n");
goto error_mem;
}
dev->udev = usb_get_dev(udev);
+ dev->type = id->driver_info;
usb_set_intfdata (interface, dev);
@@ -125,6 +162,31 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
if (retval)
goto error;
+ if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) {
+ unsigned char *enable;
+
+ enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL);
+ if (!enable) {
+ dev_err(&interface->dev, "out of memory\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ retval = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ 0x09,
+ 0x21,
+ 0x200,
+ 0,
+ enable,
+ 8,
+ 2000);
+
+ kfree(enable);
+ if (retval != 8)
+ goto error;
+ }
+
dev_info(&interface->dev, "USB LED device now attached\n");
return 0;
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index de8ef945b536..417b8f207e8b 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -192,7 +192,7 @@ static ssize_t set_attr_##name(struct device *dev, \
\
return count; \
} \
-static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name);
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name);
static ssize_t show_attr_text(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -223,7 +223,7 @@ static ssize_t set_attr_text(struct device *dev,
return count;
}
-static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text);
+static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text);
static ssize_t show_attr_decimals(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -272,8 +272,7 @@ static ssize_t set_attr_decimals(struct device *dev,
return count;
}
-static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO,
- show_attr_decimals, set_attr_decimals);
+static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals);
static ssize_t show_attr_textmode(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -319,8 +318,7 @@ static ssize_t set_attr_textmode(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO,
- show_attr_textmode, set_attr_textmode);
+static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 796e2f68f749..4ff21587ab03 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -3,7 +3,7 @@
/*
* uss720.c -- USS720 USB Parport Cable.
*
- * Copyright (C) 1999, 2005
+ * Copyright (C) 1999, 2005, 2010
* Thomas Sailer (t.sailer@alumni.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
@@ -776,6 +776,8 @@ static const struct usb_device_id uss720_table[] = {
{ USB_DEVICE(0x0557, 0x2001) },
{ USB_DEVICE(0x0729, 0x1284) },
{ USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x050d, 0x0002) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 719c6180b31f..ac5bfd619e62 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -536,6 +536,7 @@ static const struct file_operations yurex_fops = {
.open = yurex_open,
.release = yurex_release,
.fasync = yurex_fasync,
+ .llseek = default_llseek,
};
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 44cb37b5a4dc..a09dbd243eb3 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -15,7 +15,6 @@
#include <linux/poll.h>
#include <linux/compat.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
@@ -437,6 +436,28 @@ static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp,
return length;
}
+/*
+ * This is the look-ahead pass in case of 'C Zi', when actual_length cannot
+ * be used to determine the length of the whole contiguous buffer.
+ */
+static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp,
+ struct urb *urb, unsigned int ndesc)
+{
+ struct usb_iso_packet_descriptor *fp;
+ unsigned int length;
+
+ length = 0;
+ fp = urb->iso_frame_desc;
+ while (ndesc-- != 0) {
+ if (fp->actual_length != 0) {
+ if (fp->offset + fp->actual_length > length)
+ length = fp->offset + fp->actual_length;
+ }
+ fp++;
+ }
+ return length;
+}
+
static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
{
@@ -479,6 +500,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
/*
* Find the maximum allowable length, then allocate space.
*/
+ urb_length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ length = urb_length;
+
if (usb_endpoint_xfer_isoc(epd)) {
if (urb->number_of_packets < 0) {
ndesc = 0;
@@ -487,14 +512,16 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
} else {
ndesc = urb->number_of_packets;
}
+ if (ev_type == 'C' && usb_urb_dir_in(urb))
+ length = mon_bin_collate_isodesc(rp, urb, ndesc);
} else {
ndesc = 0;
}
lendesc = ndesc*sizeof(struct mon_bin_isodesc);
- urb_length = (ev_type == 'S') ?
- urb->transfer_buffer_length : urb->actual_length;
- length = urb_length;
+ /* not an issue unless there's a subtle bug in a HCD somewhere */
+ if (length >= urb->transfer_buffer_length)
+ length = urb->transfer_buffer_length;
if (length >= rp->b_size/5)
length = rp->b_size/5;
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index 8ec94f15a738..e5ce42bd316e 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -11,7 +11,6 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 341a37a469bd..4cbb7e4b368d 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -12,6 +12,7 @@ config USB_MUSB_HDRC
depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
select TWL4030_USB if MACH_OMAP_3430SDP
+ select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
@@ -30,57 +31,41 @@ config USB_MUSB_HDRC
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
- module will be called "musb_hdrc".
+ module will be called "musb-hdrc".
-config USB_MUSB_SOC
- boolean
+choice
+ prompt "Platform Glue Layer"
depends on USB_MUSB_HDRC
- default y if ARCH_DAVINCI
- default y if ARCH_OMAP2430
- default y if ARCH_OMAP3
- default y if ARCH_OMAP4
- default y if (BF54x && !BF544)
- default y if (BF52x && !BF522 && !BF523)
-comment "DaVinci 35x and 644x USB support"
- depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx
+config USB_MUSB_DAVINCI
+ bool "DaVinci"
+ depends on ARCH_DAVINCI_DMx
-comment "DA8xx/OMAP-L1x USB support"
- depends on USB_MUSB_HDRC && ARCH_DAVINCI_DA8XX
+config USB_MUSB_DA8XX
+ bool "DA8xx/OMAP-L1x"
+ depends on ARCH_DAVINCI_DA8XX
-comment "OMAP 243x high speed USB support"
- depends on USB_MUSB_HDRC && ARCH_OMAP2430
+config USB_MUSB_TUSB6010
+ bool "TUSB6010"
+ depends on ARCH_OMAP
-comment "OMAP 343x high speed USB support"
- depends on USB_MUSB_HDRC && ARCH_OMAP3
+config USB_MUSB_OMAP2PLUS
+ bool "OMAP2430 and onwards"
+ depends on ARCH_OMAP2PLUS
-comment "OMAP 44xx high speed USB support"
- depends on USB_MUSB_HDRC && ARCH_OMAP4
+config USB_MUSB_AM35X
+ bool "AM35x"
+ depends on ARCH_OMAP
-comment "Blackfin high speed USB Support"
- depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
+config USB_MUSB_BLACKFIN
+ bool "Blackfin"
+ depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
-config USB_MUSB_AM35X
- bool
- depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4
- select NOP_USB_XCEIV
- default MACH_OMAP3517EVM
- help
- Select this option if your platform is based on AM35x. As
- AM35x has an updated MUSB with CPPI4.1 DMA so this config
- is introduced to differentiate musb ip between OMAP3x and
- AM35x platforms.
-
-config USB_TUSB6010
- boolean "TUSB 6010 support"
- depends on USB_MUSB_HDRC && !USB_MUSB_SOC
- select NOP_USB_XCEIV
- default y
- help
- The TUSB 6010 chip, from Texas Instruments, connects a discrete
- HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
- (a high speed serial link). It can use system-specific external
- DMA controllers.
+config USB_MUSB_UX500
+ bool "U8500 and U5500"
+ depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500)
+
+endchoice
choice
prompt "Driver Mode"
@@ -158,7 +143,7 @@ config USB_MUSB_HDRC_HCD
config MUSB_PIO_ONLY
bool 'Disable DMA (always use PIO)'
depends on USB_MUSB_HDRC
- default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X
+ default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
help
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.
@@ -171,21 +156,21 @@ config MUSB_PIO_ONLY
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
- default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4
+ default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
help
Enable DMA transfers using Mentor's engine.
config USB_TI_CPPI_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
- default ARCH_DAVINCI
+ default USB_MUSB_DAVINCI
help
Enable DMA transfers when TI CPPI DMA is available.
config USB_TUSB_OMAP_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
- depends on USB_TUSB6010
+ depends on USB_MUSB_TUSB6010
depends on ARCH_OMAP
default y
help
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index ce164e8998d8..74df5284894f 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -8,22 +8,19 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
musb_hdrc-y := musb_core.o
-musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx) += davinci.o
-musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o
-musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o
-musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o
-ifeq ($(CONFIG_USB_MUSB_AM35X),y)
- musb_hdrc-$(CONFIG_ARCH_OMAP3430) += am35x.o
-else
- musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o
-endif
-musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o
-musb_hdrc-$(CONFIG_BF54x) += blackfin.o
-musb_hdrc-$(CONFIG_BF52x) += blackfin.o
musb_hdrc-$(CONFIG_USB_GADGET_MUSB_HDRC) += musb_gadget_ep0.o musb_gadget.o
musb_hdrc-$(CONFIG_USB_MUSB_HDRC_HCD) += musb_virthub.o musb_host.o
musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
+# Hardware Glue Layer
+obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
+obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
+obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
+obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
+obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
+obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
+obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
+
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
# PIO only, or DMA (several potential schemes).
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index b0aabf3a606f..d5a3da37c90c 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -29,8 +29,9 @@
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
-#include <plat/control.h>
#include <plat/usb.h>
#include "musb_core.h"
@@ -80,51 +81,18 @@
#define USB_MENTOR_CORE_OFFSET 0x400
-static inline void phy_on(void)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(100);
- u32 devconf2;
-
- /*
- * Start the on-chip PHY and its PLL.
- */
- devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
- devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
- devconf2 |= CONF2_PHY_PLLON;
-
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
-
- DBG(1, "Waiting for PHY clock good...\n");
- while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
- & CONF2_PHYCLKGD)) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- DBG(1, "musb PHY clock good timed out\n");
- break;
- }
- }
-}
-
-static inline void phy_off(void)
-{
- u32 devconf2;
-
- /*
- * Power down the on-chip PHY.
- */
- devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
- devconf2 &= ~CONF2_PHY_PLLON;
- devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
-}
+struct am35x_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *phy_clk;
+ struct clk *clk;
+};
+#define glue_to_musb(g) platform_get_drvdata(g->musb)
/*
- * musb_platform_enable - enable interrupts
+ * am35x_musb_enable - enable interrupts
*/
-void musb_platform_enable(struct musb *musb)
+static void am35x_musb_enable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 epmask;
@@ -143,9 +111,9 @@ void musb_platform_enable(struct musb *musb)
}
/*
- * musb_platform_disable - disable HDRC and flush interrupts
+ * am35x_musb_disable - disable HDRC and flush interrupts
*/
-void musb_platform_disable(struct musb *musb)
+static void am35x_musb_disable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
@@ -162,7 +130,7 @@ void musb_platform_disable(struct musb *musb)
#define portstate(stmt)
#endif
-static void am35x_set_vbus(struct musb *musb, int is_on)
+static void am35x_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
}
@@ -221,7 +189,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
-void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
@@ -251,13 +219,16 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&otg_workaround, timeout);
}
-static irqreturn_t am35x_interrupt(int irq, void *hci)
+static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
- u32 epintr, usbintr, lvl_intr;
+ u32 epintr, usbintr;
spin_lock_irqsave(&musb->lock, flags);
@@ -346,9 +317,8 @@ eoi:
/* EOI needs to be written for the IRQ to be re-asserted. */
if (ret == IRQ_HANDLED || epintr || usbintr) {
/* clear level interrupt */
- lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
- lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
- omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+ if (data->clear_irq)
+ data->clear_irq();
/* write EOI */
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
}
@@ -362,137 +332,85 @@ eoi:
return ret;
}
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
{
- u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+ int retval = 0;
- devconf2 &= ~CONF2_OTGMODE;
- switch (musb_mode) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- case MUSB_HOST: /* Force VBUS valid, ID = 0 */
- devconf2 |= CONF2_FORCE_HOST;
- break;
-#endif
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
- devconf2 |= CONF2_FORCE_DEVICE;
- break;
-#endif
-#ifdef CONFIG_USB_MUSB_OTG
- case MUSB_OTG: /* Don't override the VBUS/ID comparators */
- devconf2 |= CONF2_NO_OVERRIDE;
- break;
-#endif
- default:
- DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
- }
+ if (data->set_mode)
+ data->set_mode(musb_mode);
+ else
+ retval = -EIO;
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
- return 0;
+ return retval;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static int am35x_musb_init(struct musb *musb)
{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
void __iomem *reg_base = musb->ctrl_base;
- u32 rev, lvl_intr, sw_reset;
- int status;
+ u32 rev;
musb->mregs += USB_MENTOR_CORE_OFFSET;
- clk_enable(musb->clock);
- DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock));
-
- musb->phy_clock = clk_get(musb->controller, "fck");
- if (IS_ERR(musb->phy_clock)) {
- status = PTR_ERR(musb->phy_clock);
- goto exit0;
- }
- clk_enable(musb->phy_clock);
- DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock));
-
/* Returns zero if e.g. not clocked */
rev = musb_readl(reg_base, USB_REVISION_REG);
- if (!rev) {
- status = -ENODEV;
- goto exit1;
- }
+ if (!rev)
+ return -ENODEV;
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
- status = -ENODEV;
- goto exit1;
- }
+ if (!musb->xceiv)
+ return -ENODEV;
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
- musb->board_set_vbus = am35x_set_vbus;
-
- /* Global reset */
- sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-
- sw_reset |= AM35XX_USBOTGSS_SW_RST;
- omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
-
- sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
- omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
+ /* Reset the musb */
+ if (data->reset)
+ data->reset();
/* Reset the controller */
musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
/* Start the on-chip PHY and its PLL. */
- phy_on();
+ if (data->set_phy_power)
+ data->set_phy_power(1);
msleep(5);
- musb->isr = am35x_interrupt;
+ musb->isr = am35x_musb_interrupt;
/* clear level interrupt */
- lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
- lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
- omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+ if (data->clear_irq)
+ data->clear_irq();
+
return 0;
-exit1:
- clk_disable(musb->phy_clock);
- clk_put(musb->phy_clock);
-exit0:
- clk_disable(musb->clock);
- return status;
}
-int musb_platform_exit(struct musb *musb)
+static int am35x_musb_exit(struct musb *musb)
{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
- phy_off();
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
- clk_disable(musb->clock);
-
- clk_disable(musb->phy_clock);
- clk_put(musb->phy_clock);
-
return 0;
}
-#ifdef CONFIG_PM
-void musb_platform_save_context(struct musb *musb,
- struct musb_context_registers *musb_context)
-{
- phy_off();
-}
-
-void musb_platform_restore_context(struct musb *musb,
- struct musb_context_registers *musb_context)
-{
- phy_on();
-}
-#endif
-
/* AM35x supports only 32bit read operation */
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
@@ -522,3 +440,215 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
memcpy(dst, &val, len);
}
}
+
+static const struct musb_platform_ops am35x_ops = {
+ .init = am35x_musb_init,
+ .exit = am35x_musb_exit,
+
+ .enable = am35x_musb_enable,
+ .disable = am35x_musb_disable,
+
+ .set_mode = am35x_musb_set_mode,
+ .try_idle = am35x_musb_try_idle,
+
+ .set_vbus = am35x_musb_set_vbus,
+};
+
+static u64 am35x_dmamask = DMA_BIT_MASK(32);
+
+static int __init am35x_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct am35x_glue *glue;
+
+ struct clk *phy_clk;
+ struct clk *clk;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ phy_clk = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(phy_clk)) {
+ dev_err(&pdev->dev, "failed to get PHY clock\n");
+ ret = PTR_ERR(phy_clk);
+ goto err2;
+ }
+
+ clk = clk_get(&pdev->dev, "ick");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(clk);
+ goto err3;
+ }
+
+ ret = clk_enable(phy_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable PHY clock\n");
+ goto err4;
+ }
+
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ goto err5;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &am35x_dmamask;
+ musb->dev.coherent_dma_mask = am35x_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+ glue->phy_clk = phy_clk;
+ glue->clk = clk;
+
+ pdata->platform_ops = &am35x_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err6;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err6;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err6;
+ }
+
+ return 0;
+
+err6:
+ clk_disable(clk);
+
+err5:
+ clk_disable(phy_clk);
+
+err4:
+ clk_put(clk);
+
+err3:
+ clk_put(phy_clk);
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit am35x_remove(struct platform_device *pdev)
+{
+ struct am35x_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ clk_disable(glue->clk);
+ clk_disable(glue->phy_clk);
+ clk_put(glue->clk);
+ clk_put(glue->phy_clk);
+ kfree(glue);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int am35x_suspend(struct device *dev)
+{
+ struct am35x_glue *glue = dev_get_drvdata(dev);
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
+
+ clk_disable(glue->phy_clk);
+ clk_disable(glue->clk);
+
+ return 0;
+}
+
+static int am35x_resume(struct device *dev)
+{
+ struct am35x_glue *glue = dev_get_drvdata(dev);
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+ int ret;
+
+ /* Start the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(1);
+
+ ret = clk_enable(glue->phy_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable PHY clock\n");
+ return ret;
+ }
+
+ ret = clk_enable(glue->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct dev_pm_ops am35x_pm_ops = {
+ .suspend = am35x_suspend,
+ .resume = am35x_resume,
+};
+
+#define DEV_PM_OPS &am35x_pm_ops
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver am35x_driver = {
+ .remove = __exit_p(am35x_remove),
+ .driver = {
+ .name = "musb-am35x",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init am35x_init(void)
+{
+ return platform_driver_probe(&am35x_driver, am35x_probe);
+}
+subsys_initcall(am35x_init);
+
+static void __exit am35x_exit(void)
+{
+ platform_driver_unregister(&am35x_driver);
+}
+module_exit(am35x_exit);
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 611a9d274363..eeba228eb2af 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -15,12 +15,20 @@
#include <linux/list.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "musb_core.h"
#include "blackfin.h"
+struct bfin_glue {
+ struct device *dev;
+ struct platform_device *musb;
+};
+#define glue_to_musb(g) platform_get_drvdata(g->musb)
+
/*
* Load an endpoint's FIFO
*/
@@ -171,8 +179,9 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
}
/* Start sampling ID pin, when plug is removed from MUSB */
- if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
- || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
+ || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+ (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
}
@@ -277,7 +286,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
DBG(4, "state is %s\n", otg_state_string(musb));
}
-void musb_platform_enable(struct musb *musb)
+static void bfin_musb_enable(struct musb *musb)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
@@ -285,11 +294,11 @@ void musb_platform_enable(struct musb *musb)
}
}
-void musb_platform_disable(struct musb *musb)
+static void bfin_musb_disable(struct musb *musb)
{
}
-static void bfin_set_vbus(struct musb *musb, int is_on)
+static void bfin_musb_set_vbus(struct musb *musb, int is_on)
{
int value = musb->config->gpio_vrsel_active;
if (!is_on)
@@ -302,51 +311,29 @@ static void bfin_set_vbus(struct musb *musb, int is_on)
musb_readb(musb->mregs, MUSB_DEVCTL));
}
-static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
+static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
-void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb))
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
-int musb_platform_get_vbus_status(struct musb *musb)
+static int bfin_musb_get_vbus_status(struct musb *musb)
{
return 0;
}
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
{
return -EIO;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static void bfin_musb_reg_init(struct musb *musb)
{
-
- /*
- * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
- * and OTG HOST modes, while rev 1.1 and greater require PE7 to
- * be low for DEVICE mode and high for HOST mode. We set it high
- * here because we are in host mode
- */
-
- if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
- printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
- musb->config->gpio_vrsel);
- return -ENODEV;
- }
- gpio_direction_output(musb->config->gpio_vrsel, 0);
-
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
- gpio_free(musb->config->gpio_vrsel);
- return -ENODEV;
- }
-
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
@@ -358,7 +345,8 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
}
/* Configure PLL oscillator register */
- bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ bfin_write_USB_PLLOSC_CTRL(0x3080 |
+ ((480/musb->config->clkin) << 1));
SSYNC();
bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
@@ -380,21 +368,47 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
SSYNC();
+}
+
+static int bfin_musb_init(struct musb *musb)
+{
+
+ /*
+ * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
+ * and OTG HOST modes, while rev 1.1 and greater require PE7 to
+ * be low for DEVICE mode and high for HOST mode. We set it high
+ * here because we are in host mode
+ */
+
+ if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
+ printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
+ musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+ gpio_direction_output(musb->config->gpio_vrsel, 0);
+
+ usb_nop_xceiv_register();
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv) {
+ gpio_free(musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+
+ bfin_musb_reg_init(musb);
if (is_host_enabled(musb)) {
- musb->board_set_vbus = bfin_set_vbus;
setup_timer(&musb_conn_timer,
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
- musb->xceiv->set_power = bfin_set_power;
+ musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt;
return 0;
}
-int musb_platform_exit(struct musb *musb)
+static int bfin_musb_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
@@ -402,3 +416,154 @@ int musb_platform_exit(struct musb *musb)
usb_nop_xceiv_unregister();
return 0;
}
+
+static const struct musb_platform_ops bfin_ops = {
+ .init = bfin_musb_init,
+ .exit = bfin_musb_exit,
+
+ .enable = bfin_musb_enable,
+ .disable = bfin_musb_disable,
+
+ .set_mode = bfin_musb_set_mode,
+ .try_idle = bfin_musb_try_idle,
+
+ .vbus_status = bfin_musb_vbus_status,
+ .set_vbus = bfin_musb_set_vbus,
+};
+
+static u64 bfin_dmamask = DMA_BIT_MASK(32);
+
+static int __init bfin_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct bfin_glue *glue;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &bfin_dmamask;
+ musb->dev.coherent_dma_mask = bfin_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+
+ pdata->platform_ops = &bfin_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err2;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err2;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err2;
+ }
+
+ return 0;
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit bfin_remove(struct platform_device *pdev)
+{
+ struct bfin_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ kfree(glue);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_suspend(struct device *dev)
+{
+ struct bfin_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ if (is_host_active(musb))
+ /*
+ * During hibernate gpio_vrsel will change from high to low
+ * low which will generate wakeup event resume the system
+ * immediately. Set it to 0 before hibernate to avoid this
+ * wakeup event.
+ */
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+
+ return 0;
+}
+
+static int bfin_resume(struct device *dev)
+{
+ struct bfin_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ bfin_musb_reg_init(musb);
+
+ return 0;
+}
+
+static struct dev_pm_ops bfin_pm_ops = {
+ .suspend = bfin_suspend,
+ .resume = bfin_resume,
+};
+
+#define DEV_PM_OPS &bfin_pm_op,
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver bfin_driver = {
+ .remove = __exit_p(bfin_remove),
+ .driver = {
+ .name = "musb-bfin",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
+MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
+MODULE_LICENSE("GPL v2");
+
+static int __init bfin_init(void)
+{
+ return platform_driver_probe(&bfin_driver, bfin_probe);
+}
+subsys_initcall(bfin_init);
+
+static void __exit bfin_exit(void)
+{
+ platform_driver_unregister(&bfin_driver);
+}
+module_exit(bfin_exit);
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index f5a65ff0ac2b..de55a3c3259a 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1308,7 +1308,7 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
struct cppi *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
- int irq = platform_get_irq(pdev, 1);
+ int irq = platform_get_irq_byname(pdev, "dma");
controller = kzalloc(sizeof *controller, GFP_KERNEL);
if (!controller)
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 84427bebbf62..69a0da3c8f09 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -29,6 +29,8 @@
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <mach/da8xx.h>
#include <mach/usb.h>
@@ -78,6 +80,12 @@
#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG)
+struct da8xx_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *clk;
+};
+
/*
* REVISIT (PM): we should be able to keep the PHY in low power mode most
* of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0
@@ -131,9 +139,9 @@ static inline void phy_off(void)
*/
/**
- * musb_platform_enable - enable interrupts
+ * da8xx_musb_enable - enable interrupts
*/
-void musb_platform_enable(struct musb *musb)
+static void da8xx_musb_enable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 mask;
@@ -151,9 +159,9 @@ void musb_platform_enable(struct musb *musb)
}
/**
- * musb_platform_disable - disable HDRC and flush interrupts
+ * da8xx_musb_disable - disable HDRC and flush interrupts
*/
-void musb_platform_disable(struct musb *musb)
+static void da8xx_musb_disable(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
@@ -170,7 +178,7 @@ void musb_platform_disable(struct musb *musb)
#define portstate(stmt)
#endif
-static void da8xx_set_vbus(struct musb *musb, int is_on)
+static void da8xx_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
}
@@ -252,7 +260,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
-void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
@@ -282,7 +290,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&otg_workaround, timeout);
}
-static irqreturn_t da8xx_interrupt(int irq, void *hci)
+static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
@@ -380,7 +388,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)
return ret;
}
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
{
u32 cfgchip2 = __raw_readl(CFGCHIP2);
@@ -409,15 +417,13 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
return 0;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static int da8xx_musb_init(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 rev;
musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
- clk_enable(musb->clock);
-
/* Returns zero if e.g. not clocked */
rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
if (!rev)
@@ -431,8 +437,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
- musb->board_set_vbus = da8xx_set_vbus;
-
/* Reset the controller */
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
@@ -446,14 +450,13 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
rev, __raw_readl(CFGCHIP2),
musb_readb(reg_base, DA8XX_USB_CTRL_REG));
- musb->isr = da8xx_interrupt;
+ musb->isr = da8xx_musb_interrupt;
return 0;
fail:
- clk_disable(musb->clock);
return -ENODEV;
}
-int musb_platform_exit(struct musb *musb)
+static int da8xx_musb_exit(struct musb *musb)
{
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
@@ -463,7 +466,140 @@ int musb_platform_exit(struct musb *musb)
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
- clk_disable(musb->clock);
+ return 0;
+}
+
+static const struct musb_platform_ops da8xx_ops = {
+ .init = da8xx_musb_init,
+ .exit = da8xx_musb_exit,
+
+ .enable = da8xx_musb_enable,
+ .disable = da8xx_musb_disable,
+
+ .set_mode = da8xx_musb_set_mode,
+ .try_idle = da8xx_musb_try_idle,
+
+ .set_vbus = da8xx_musb_set_vbus,
+};
+
+static u64 da8xx_dmamask = DMA_BIT_MASK(32);
+
+static int __init da8xx_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct da8xx_glue *glue;
+
+ struct clk *clk;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ clk = clk_get(&pdev->dev, "usb20");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(clk);
+ goto err2;
+ }
+
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ goto err3;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &da8xx_dmamask;
+ musb->dev.coherent_dma_mask = da8xx_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+ glue->clk = clk;
+
+ pdata->platform_ops = &da8xx_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err4;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err4;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ clk_disable(clk);
+
+err3:
+ clk_put(clk);
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit da8xx_remove(struct platform_device *pdev)
+{
+ struct da8xx_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ clk_disable(glue->clk);
+ clk_put(glue->clk);
+ kfree(glue);
return 0;
}
+
+static struct platform_driver da8xx_driver = {
+ .remove = __exit_p(da8xx_remove),
+ .driver = {
+ .name = "musb-da8xx",
+ },
+};
+
+MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer");
+MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init da8xx_init(void)
+{
+ return platform_driver_probe(&da8xx_driver, da8xx_probe);
+}
+subsys_initcall(da8xx_init);
+
+static void __exit da8xx_exit(void)
+{
+ platform_driver_unregister(&da8xx_driver);
+}
+module_exit(da8xx_exit);
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 6e67629f50cc..e6de097fb7e8 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -30,6 +30,8 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <mach/hardware.h>
#include <mach/memory.h>
@@ -51,6 +53,12 @@
#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR)
#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR)
+struct davinci_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *clk;
+};
+
/* REVISIT (PM) we should be able to keep the PHY in low power mode most
* of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
* and, when in host mode, autosuspending idle root ports... PHYPLLON
@@ -83,7 +91,7 @@ static inline void phy_off(void)
static int dma_off = 1;
-void musb_platform_enable(struct musb *musb)
+static void davinci_musb_enable(struct musb *musb)
{
u32 tmp, old, val;
@@ -116,7 +124,7 @@ void musb_platform_enable(struct musb *musb)
/*
* Disable the HDRC and flush interrupts
*/
-void musb_platform_disable(struct musb *musb)
+static void davinci_musb_disable(struct musb *musb)
{
/* because we don't set CTRLR.UINT, "important" to:
* - not read/write INTRUSB/INTRUSBE
@@ -167,7 +175,7 @@ static void evm_deferred_drvvbus(struct work_struct *ignored)
#endif /* EVM */
-static void davinci_source_power(struct musb *musb, int is_on, int immediate)
+static void davinci_musb_source_power(struct musb *musb, int is_on, int immediate)
{
#ifdef CONFIG_MACH_DAVINCI_EVM
if (is_on)
@@ -190,10 +198,10 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)
#endif
}
-static void davinci_set_vbus(struct musb *musb, int is_on)
+static void davinci_musb_set_vbus(struct musb *musb, int is_on)
{
WARN_ON(is_on && is_peripheral_active(musb));
- davinci_source_power(musb, is_on, 0);
+ davinci_musb_source_power(musb, is_on, 0);
}
@@ -259,7 +267,7 @@ static void otg_timer(unsigned long _musb)
spin_unlock_irqrestore(&musb->lock, flags);
}
-static irqreturn_t davinci_interrupt(int irq, void *__hci)
+static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
@@ -345,7 +353,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* NOTE: this must complete poweron within 100 msec
* (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
*/
- davinci_source_power(musb, drvvbus, 0);
+ davinci_musb_source_power(musb, drvvbus, 0);
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
otg_state_string(musb),
@@ -370,13 +378,13 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
return retval;
}
-int musb_platform_set_mode(struct musb *musb, u8 mode)
+static int davinci_musb_set_mode(struct musb *musb, u8 mode)
{
/* EVM can't do this (right?) */
return -EIO;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static int davinci_musb_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
u32 revision;
@@ -388,8 +396,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
musb->mregs += DAVINCI_BASE_OFFSET;
- clk_enable(musb->clock);
-
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
if (revision == 0)
@@ -398,8 +404,7 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
- musb->board_set_vbus = davinci_set_vbus;
- davinci_source_power(musb, 0, 1);
+ davinci_musb_source_power(musb, 0, 1);
/* dm355 EVM swaps D+/D- for signal integrity, and
* is clocked from the main 24 MHz crystal.
@@ -440,18 +445,16 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
revision, __raw_readl(USB_PHY_CTRL),
musb_readb(tibase, DAVINCI_USB_CTRL_REG));
- musb->isr = davinci_interrupt;
+ musb->isr = davinci_musb_interrupt;
return 0;
fail:
- clk_disable(musb->clock);
-
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return -ENODEV;
}
-int musb_platform_exit(struct musb *musb)
+static int davinci_musb_exit(struct musb *musb)
{
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
@@ -465,7 +468,7 @@ int musb_platform_exit(struct musb *musb)
__raw_writel(deepsleep, DM355_DEEPSLEEP);
}
- davinci_source_power(musb, 0 /*off*/, 1);
+ davinci_musb_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
if (is_host_enabled(musb) && musb->xceiv->default_a) {
@@ -495,10 +498,141 @@ int musb_platform_exit(struct musb *musb)
phy_off();
- clk_disable(musb->clock);
-
otg_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
}
+
+static const struct musb_platform_ops davinci_ops = {
+ .init = davinci_musb_init,
+ .exit = davinci_musb_exit,
+
+ .enable = davinci_musb_enable,
+ .disable = davinci_musb_disable,
+
+ .set_mode = davinci_musb_set_mode,
+
+ .set_vbus = davinci_musb_set_vbus,
+};
+
+static u64 davinci_dmamask = DMA_BIT_MASK(32);
+
+static int __init davinci_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct davinci_glue *glue;
+ struct clk *clk;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ clk = clk_get(&pdev->dev, "usb");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(clk);
+ goto err2;
+ }
+
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ goto err3;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &davinci_dmamask;
+ musb->dev.coherent_dma_mask = davinci_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+ glue->clk = clk;
+
+ pdata->platform_ops = &davinci_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err4;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err4;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ clk_disable(clk);
+
+err3:
+ clk_put(clk);
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit davinci_remove(struct platform_device *pdev)
+{
+ struct davinci_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ clk_disable(glue->clk);
+ clk_put(glue->clk);
+ kfree(glue);
+
+ return 0;
+}
+
+static struct platform_driver davinci_driver = {
+ .remove = __exit_p(davinci_remove),
+ .driver = {
+ .name = "musb-davinci",
+ },
+};
+
+MODULE_DESCRIPTION("DaVinci MUSB Glue Layer");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init davinci_init(void)
+{
+ return platform_driver_probe(&davinci_driver, davinci_probe);
+}
+subsys_initcall(davinci_init);
+
+static void __exit davinci_exit(void)
+{
+ platform_driver_unregister(&davinci_driver);
+}
+module_exit(davinci_exit);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c9f9024c5515..07cf394e491b 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -99,19 +99,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#ifdef CONFIG_ARM
-#include <mach/hardware.h>
-#include <mach/memory.h>
-#include <asm/mach-types.h>
-#endif
-
#include "musb_core.h"
-
-#ifdef CONFIG_ARCH_DAVINCI
-#include "davinci.h"
-#endif
-
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
@@ -126,7 +115,7 @@ MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
-#define MUSB_DRIVER_NAME "musb_hdrc"
+#define MUSB_DRIVER_NAME "musb-hdrc"
const char musb_driver_name[] = MUSB_DRIVER_NAME;
MODULE_DESCRIPTION(DRIVER_INFO);
@@ -230,7 +219,7 @@ static struct otg_io_access_ops musb_ulpi_access = {
/*-------------------------------------------------------------------------*/
-#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
+#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
/*
* Load an endpoint's FIFO
@@ -390,7 +379,7 @@ void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
- musb_set_vbus(musb, 0);
+ musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
@@ -552,7 +541,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (int_usb & MUSB_INTR_SESSREQ) {
void __iomem *mbase = musb->mregs;
- if (devctl & MUSB_DEVCTL_BDEVICE) {
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+ && (devctl & MUSB_DEVCTL_BDEVICE)) {
DBG(3, "SessReq while on B state\n");
return IRQ_HANDLED;
}
@@ -570,7 +560,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->ep0_stage = MUSB_EP0_START;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
- musb_set_vbus(musb, 1);
+ musb_platform_set_vbus(musb, 1);
handled = IRQ_HANDLED;
}
@@ -641,7 +631,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
/* go through A_WAIT_VFALL then start a new session */
if (!ignore)
- musb_set_vbus(musb, 0);
+ musb_platform_set_vbus(musb, 0);
handled = IRQ_HANDLED;
}
@@ -1048,10 +1038,13 @@ static void musb_shutdown(struct platform_device *pdev)
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
musb_generic_disable(musb);
- if (musb->clock)
- clk_put(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
+ if (!is_otg_enabled(musb) && is_host_enabled(musb))
+ usb_remove_hcd(musb_to_hcd(musb));
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ musb_platform_exit(musb);
+
/* FIXME power down */
}
@@ -1068,10 +1061,11 @@ static void musb_shutdown(struct platform_device *pdev)
* We don't currently use dynamic fifo setup capability to do anything
* more than selecting one of a bunch of predefined configurations.
*/
-#if defined(CONFIG_USB_TUSB6010) || \
- defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
- || defined(CONFIG_ARCH_OMAP4)
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \
+ || defined(CONFIG_USB_MUSB_AM35X)
static ushort __initdata fifo_mode = 4;
+#elif defined(CONFIG_USB_MUSB_UX500)
+static ushort __initdata fifo_mode = 5;
#else
static ushort __initdata fifo_mode = 2;
#endif
@@ -1495,7 +1489,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
struct musb_hw_ep *hw_ep = musb->endpoints + i;
hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync_va =
@@ -1542,7 +1536,8 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
+ defined(CONFIG_ARCH_U5500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
@@ -1898,6 +1893,7 @@ allocate_instance(struct device *dev,
}
musb->controller = dev;
+
return musb;
}
@@ -1994,30 +1990,14 @@ bad_config:
spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
- musb->set_clock = plat->set_clock;
musb->min_power = plat->min_power;
-
- /* Clock usage is chip-specific ... functional clock (DaVinci,
- * OMAP2430), or PHY ref (some TUSB6010 boards). All this core
- * code does is make sure a clock handle is available; platform
- * code manages it during start/stop and suspend/resume.
- */
- if (plat->clock) {
- musb->clock = clk_get(dev, plat->clock);
- if (IS_ERR(musb->clock)) {
- status = PTR_ERR(musb->clock);
- musb->clock = NULL;
- goto fail1;
- }
- }
+ musb->ops = plat->platform_ops;
/* The musb_platform_init() call:
* - adjusts musb->mregs and musb->isr if needed,
* - may initialize an integrated tranceiver
* - initializes musb->xceiv, usually by otg_get_transceiver()
- * - activates clocks.
* - stops powering VBUS
- * - assigns musb->board_set_vbus if host mode is enabled
*
* There are various transciever configurations. Blackfin,
* DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
@@ -2025,9 +2005,9 @@ bad_config:
* isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
musb->isr = generic_interrupt;
- status = musb_platform_init(musb, plat->board_data);
+ status = musb_platform_init(musb);
if (status < 0)
- goto fail2;
+ goto fail1;
if (!musb->isr) {
status = -ENODEV;
@@ -2110,12 +2090,15 @@ bad_config:
* Otherwise, wait till the gadget driver hooks up.
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
MUSB_HST_MODE(musb);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ hcd->self.uses_pio_for_control = 1;
DBG(1, "%s mode, status %d, devctl %02x %c\n",
"HOST", status,
musb_readb(musb->mregs, MUSB_DEVCTL),
@@ -2177,10 +2160,6 @@ fail3:
device_init_wakeup(dev, 0);
musb_platform_exit(musb);
-fail2:
- if (musb->clock)
- clk_put(musb->clock);
-
fail1:
dev_err(musb->controller,
"musb_init_controller failed with status %d\n", status);
@@ -2206,7 +2185,7 @@ static u64 *orig_dma_mask;
static int __init musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- int irq = platform_get_irq(pdev, 0);
+ int irq = platform_get_irq_byname(pdev, "mc");
int status;
struct resource *iomem;
void __iomem *base;
@@ -2244,13 +2223,6 @@ static int __exit musb_remove(struct platform_device *pdev)
*/
musb_exit_debugfs(musb);
musb_shutdown(pdev);
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- if (musb->board_mode == MUSB_HOST)
- usb_remove_hcd(musb_to_hcd(musb));
-#endif
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
- musb_platform_exit(musb);
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_free(musb);
iounmap(ctrl_base);
@@ -2263,144 +2235,138 @@ static int __exit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
-static struct musb_context_registers musb_context;
-
-void musb_save_context(struct musb *musb)
+static void musb_save_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *epio;
if (is_host_enabled(musb)) {
- musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
- musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
- musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
+ musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
+ musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+ musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
}
- musb_context.power = musb_readb(musb_base, MUSB_POWER);
- musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
- musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
- musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
- musb_context.index = musb_readb(musb_base, MUSB_INDEX);
- musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+ musb->context.power = musb_readb(musb_base, MUSB_POWER);
+ musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+ musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+ musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+ musb->context.index = musb_readb(musb_base, MUSB_INDEX);
+ musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
- musb_context.index_regs[i].txmaxp =
+ musb->context.index_regs[i].txmaxp =
musb_readw(epio, MUSB_TXMAXP);
- musb_context.index_regs[i].txcsr =
+ musb->context.index_regs[i].txcsr =
musb_readw(epio, MUSB_TXCSR);
- musb_context.index_regs[i].rxmaxp =
+ musb->context.index_regs[i].rxmaxp =
musb_readw(epio, MUSB_RXMAXP);
- musb_context.index_regs[i].rxcsr =
+ musb->context.index_regs[i].rxcsr =
musb_readw(epio, MUSB_RXCSR);
if (musb->dyn_fifo) {
- musb_context.index_regs[i].txfifoadd =
+ musb->context.index_regs[i].txfifoadd =
musb_read_txfifoadd(musb_base);
- musb_context.index_regs[i].rxfifoadd =
+ musb->context.index_regs[i].rxfifoadd =
musb_read_rxfifoadd(musb_base);
- musb_context.index_regs[i].txfifosz =
+ musb->context.index_regs[i].txfifosz =
musb_read_txfifosz(musb_base);
- musb_context.index_regs[i].rxfifosz =
+ musb->context.index_regs[i].rxfifosz =
musb_read_rxfifosz(musb_base);
}
if (is_host_enabled(musb)) {
- musb_context.index_regs[i].txtype =
+ musb->context.index_regs[i].txtype =
musb_readb(epio, MUSB_TXTYPE);
- musb_context.index_regs[i].txinterval =
+ musb->context.index_regs[i].txinterval =
musb_readb(epio, MUSB_TXINTERVAL);
- musb_context.index_regs[i].rxtype =
+ musb->context.index_regs[i].rxtype =
musb_readb(epio, MUSB_RXTYPE);
- musb_context.index_regs[i].rxinterval =
+ musb->context.index_regs[i].rxinterval =
musb_readb(epio, MUSB_RXINTERVAL);
- musb_context.index_regs[i].txfunaddr =
+ musb->context.index_regs[i].txfunaddr =
musb_read_txfunaddr(musb_base, i);
- musb_context.index_regs[i].txhubaddr =
+ musb->context.index_regs[i].txhubaddr =
musb_read_txhubaddr(musb_base, i);
- musb_context.index_regs[i].txhubport =
+ musb->context.index_regs[i].txhubport =
musb_read_txhubport(musb_base, i);
- musb_context.index_regs[i].rxfunaddr =
+ musb->context.index_regs[i].rxfunaddr =
musb_read_rxfunaddr(musb_base, i);
- musb_context.index_regs[i].rxhubaddr =
+ musb->context.index_regs[i].rxhubaddr =
musb_read_rxhubaddr(musb_base, i);
- musb_context.index_regs[i].rxhubport =
+ musb->context.index_regs[i].rxhubport =
musb_read_rxhubport(musb_base, i);
}
}
-
- musb_platform_save_context(musb, &musb_context);
}
-void musb_restore_context(struct musb *musb)
+static void musb_restore_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
- musb_platform_restore_context(musb, &musb_context);
-
if (is_host_enabled(musb)) {
- musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
- musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
- musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl);
+ musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
+ musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
+ musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
}
- musb_writeb(musb_base, MUSB_POWER, musb_context.power);
- musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
- musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
- musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
- musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
+ musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+ musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
+ musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
+ musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
+ musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
musb_writew(epio, MUSB_TXMAXP,
- musb_context.index_regs[i].txmaxp);
+ musb->context.index_regs[i].txmaxp);
musb_writew(epio, MUSB_TXCSR,
- musb_context.index_regs[i].txcsr);
+ musb->context.index_regs[i].txcsr);
musb_writew(epio, MUSB_RXMAXP,
- musb_context.index_regs[i].rxmaxp);
+ musb->context.index_regs[i].rxmaxp);
musb_writew(epio, MUSB_RXCSR,
- musb_context.index_regs[i].rxcsr);
+ musb->context.index_regs[i].rxcsr);
if (musb->dyn_fifo) {
musb_write_txfifosz(musb_base,
- musb_context.index_regs[i].txfifosz);
+ musb->context.index_regs[i].txfifosz);
musb_write_rxfifosz(musb_base,
- musb_context.index_regs[i].rxfifosz);
+ musb->context.index_regs[i].rxfifosz);
musb_write_txfifoadd(musb_base,
- musb_context.index_regs[i].txfifoadd);
+ musb->context.index_regs[i].txfifoadd);
musb_write_rxfifoadd(musb_base,
- musb_context.index_regs[i].rxfifoadd);
+ musb->context.index_regs[i].rxfifoadd);
}
if (is_host_enabled(musb)) {
musb_writeb(epio, MUSB_TXTYPE,
- musb_context.index_regs[i].txtype);
+ musb->context.index_regs[i].txtype);
musb_writeb(epio, MUSB_TXINTERVAL,
- musb_context.index_regs[i].txinterval);
+ musb->context.index_regs[i].txinterval);
musb_writeb(epio, MUSB_RXTYPE,
- musb_context.index_regs[i].rxtype);
+ musb->context.index_regs[i].rxtype);
musb_writeb(epio, MUSB_RXINTERVAL,
- musb_context.index_regs[i].rxinterval);
+ musb->context.index_regs[i].rxinterval);
musb_write_txfunaddr(musb_base, i,
- musb_context.index_regs[i].txfunaddr);
+ musb->context.index_regs[i].txfunaddr);
musb_write_txhubaddr(musb_base, i,
- musb_context.index_regs[i].txhubaddr);
+ musb->context.index_regs[i].txhubaddr);
musb_write_txhubport(musb_base, i,
- musb_context.index_regs[i].txhubport);
+ musb->context.index_regs[i].txhubport);
ep_target_regs =
musb_read_target_reg_base(i, musb_base);
musb_write_rxfunaddr(ep_target_regs,
- musb_context.index_regs[i].rxfunaddr);
+ musb->context.index_regs[i].rxfunaddr);
musb_write_rxhubaddr(ep_target_regs,
- musb_context.index_regs[i].rxhubaddr);
+ musb->context.index_regs[i].rxhubaddr);
musb_write_rxhubport(ep_target_regs,
- musb_context.index_regs[i].rxhubport);
+ musb->context.index_regs[i].rxhubport);
}
}
}
@@ -2411,9 +2377,6 @@ static int musb_suspend(struct device *dev)
unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) {
@@ -2428,10 +2391,6 @@ static int musb_suspend(struct device *dev)
musb_save_context(musb);
- if (musb->set_clock)
- musb->set_clock(musb->clock, 0);
- else
- clk_disable(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
@@ -2441,14 +2400,6 @@ static int musb_resume_noirq(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
- if (musb->set_clock)
- musb->set_clock(musb->clock, 1);
- else
- clk_enable(musb->clock);
-
musb_restore_context(musb);
/* for static cmos like DaVinci, register values were preserved
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 69797e5b46a7..d0c236f8e191 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -222,7 +222,7 @@ enum musb_g_ep0_state {
#endif
/* TUSB mapping: "flat" plus ep0 special cases */
-#if defined(CONFIG_USB_TUSB6010)
+#if defined(CONFIG_USB_MUSB_TUSB6010)
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
@@ -253,6 +253,29 @@ enum musb_g_ep0_state {
/******************************** TYPES *************************************/
+/**
+ * struct musb_platform_ops - Operations passed to musb_core by HW glue layer
+ * @init: turns on clocks, sets up platform-specific registers, etc
+ * @exit: undoes @init
+ * @set_mode: forcefully changes operating mode
+ * @try_ilde: tries to idle the IP
+ * @vbus_status: returns vbus status if possible
+ * @set_vbus: forces vbus status
+ */
+struct musb_platform_ops {
+ int (*init)(struct musb *musb);
+ int (*exit)(struct musb *musb);
+
+ void (*enable)(struct musb *musb);
+ void (*disable)(struct musb *musb);
+
+ int (*set_mode)(struct musb *musb, u8 mode);
+ void (*try_idle)(struct musb *musb, unsigned long timeout);
+
+ int (*vbus_status)(struct musb *musb);
+ void (*set_vbus)(struct musb *musb, int on);
+};
+
/*
* struct musb_hw_ep - endpoint hardware (bidirectional)
*
@@ -263,7 +286,7 @@ struct musb_hw_ep {
void __iomem *fifo;
void __iomem *regs;
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
void __iomem *conf;
#endif
@@ -280,7 +303,7 @@ struct musb_hw_ep {
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
@@ -323,14 +346,43 @@ static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
#endif
}
+struct musb_csr_regs {
+ /* FIFO registers */
+ u16 txmaxp, txcsr, rxmaxp, rxcsr;
+ u16 rxfifoadd, txfifoadd;
+ u8 txtype, txinterval, rxtype, rxinterval;
+ u8 rxfifosz, txfifosz;
+ u8 txfunaddr, txhubaddr, txhubport;
+ u8 rxfunaddr, rxhubaddr, rxhubport;
+};
+
+struct musb_context_registers {
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
+ defined(CONFIG_ARCH_OMAP4)
+ u32 otg_sysconfig, otg_forcestandby;
+#endif
+ u8 power;
+ u16 intrtxe, intrrxe;
+ u8 intrusbe;
+ u16 frame;
+ u8 index, testmode;
+
+ u8 devctl, busctl, misc;
+
+ struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
+};
+
/*
* struct musb - Driver instance data.
*/
struct musb {
/* device lock */
spinlock_t lock;
- struct clk *clock;
- struct clk *phy_clock;
+
+ const struct musb_platform_ops *ops;
+ struct musb_context_registers context;
+
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
u16 hwvers;
@@ -359,11 +411,7 @@ struct musb {
struct timer_list otg_timer;
#endif
-
- /* called with IRQs blocked; ON/nonzero implies starting a session,
- * and waiting at least a_wait_vrise_tmout.
- */
- void (*board_set_vbus)(struct musb *, int is_on);
+ struct notifier_block nb;
struct dma_controller *dma_controller;
@@ -371,7 +419,7 @@ struct musb {
void __iomem *ctrl_base;
void __iomem *mregs;
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
@@ -398,8 +446,6 @@ struct musb {
u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state);
- int (*set_clock)(struct clk *clk, int is_active);
-
u8 min_power; /* vbus for periph, in mA/2 */
bool is_host;
@@ -458,52 +504,6 @@ struct musb {
#endif
};
-#ifdef CONFIG_PM
-struct musb_csr_regs {
- /* FIFO registers */
- u16 txmaxp, txcsr, rxmaxp, rxcsr;
- u16 rxfifoadd, txfifoadd;
- u8 txtype, txinterval, rxtype, rxinterval;
- u8 rxfifosz, txfifosz;
- u8 txfunaddr, txhubaddr, txhubport;
- u8 rxfunaddr, rxhubaddr, rxhubport;
-};
-
-struct musb_context_registers {
-
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
- u32 otg_sysconfig, otg_forcestandby;
-#endif
- u8 power;
- u16 intrtxe, intrrxe;
- u8 intrusbe;
- u16 frame;
- u8 index, testmode;
-
- u8 devctl, busctl, misc;
-
- struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
-};
-
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
-extern void musb_platform_save_context(struct musb *musb,
- struct musb_context_registers *musb_context);
-extern void musb_platform_restore_context(struct musb *musb,
- struct musb_context_registers *musb_context);
-#else
-#define musb_platform_save_context(m, x) do {} while (0)
-#define musb_platform_restore_context(m, x) do {} while (0)
-#endif
-
-#endif
-
-static inline void musb_set_vbus(struct musb *musb, int is_on)
-{
- musb->board_set_vbus(musb, is_on);
-}
-
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
static inline struct musb *gadget_to_musb(struct usb_gadget *g)
{
@@ -592,29 +592,63 @@ extern void musb_load_testpacket(struct musb *);
extern irqreturn_t musb_interrupt(struct musb *);
-extern void musb_platform_enable(struct musb *musb);
-extern void musb_platform_disable(struct musb *musb);
-
extern void musb_hnp_stop(struct musb *musb);
-extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
+static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
+{
+ if (musb->ops->set_vbus)
+ musb->ops->set_vbus(musb, is_on);
+}
-#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
- defined(CONFIG_ARCH_DAVINCI_DA8XX) || \
- defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
-extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
-#else
-#define musb_platform_try_idle(x, y) do {} while (0)
-#endif
+static inline void musb_platform_enable(struct musb *musb)
+{
+ if (musb->ops->enable)
+ musb->ops->enable(musb);
+}
-#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN)
-extern int musb_platform_get_vbus_status(struct musb *musb);
-#else
-#define musb_platform_get_vbus_status(x) 0
-#endif
+static inline void musb_platform_disable(struct musb *musb)
+{
+ if (musb->ops->disable)
+ musb->ops->disable(musb);
+}
+
+static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
+{
+ if (!musb->ops->set_mode)
+ return 0;
+
+ return musb->ops->set_mode(musb, mode);
+}
+
+static inline void musb_platform_try_idle(struct musb *musb,
+ unsigned long timeout)
+{
+ if (musb->ops->try_idle)
+ musb->ops->try_idle(musb, timeout);
+}
+
+static inline int musb_platform_get_vbus_status(struct musb *musb)
+{
+ if (!musb->ops->vbus_status)
+ return 0;
-extern int __init musb_platform_init(struct musb *musb, void *board_data);
-extern int musb_platform_exit(struct musb *musb);
+ return musb->ops->vbus_status(musb);
+}
+
+static inline int musb_platform_init(struct musb *musb)
+{
+ if (!musb->ops->init)
+ return -EINVAL;
+
+ return musb->ops->init(musb);
+}
+
+static inline int musb_platform_exit(struct musb *musb)
+{
+ if (!musb->ops->exit)
+ return -EINVAL;
+
+ return musb->ops->exit(musb);
+}
#endif /* __MUSB_CORE_H__ */
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 9e8639d4e862..b0176e4569e0 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -36,7 +36,6 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/debugfs.h>
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 5d815049cbaa..ed58c6c8f15c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -92,6 +92,59 @@
/* ----------------------------------------------------------------------- */
+/* Maps the buffer to dma */
+
+static inline void map_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ request->request.dma = dma_map_single(
+ musb->controller,
+ request->request.buf,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 1;
+ } else {
+ dma_sync_single_for_device(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 0;
+ }
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ DBG(20, "not unmapping a never mapped buffer\n");
+ return;
+ }
+ if (request->mapped) {
+ dma_unmap_single(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->mapped = 0;
+ } else {
+ dma_sync_single_for_cpu(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ }
+}
+
/*
* Immediately complete a request.
*
@@ -119,24 +172,8 @@ __acquires(ep->musb->lock)
ep->busy = 1;
spin_unlock(&musb->lock);
- if (is_dma_capable()) {
- if (req->mapped) {
- dma_unmap_single(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->request.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else if (req->request.dma != DMA_ADDR_INVALID)
- dma_sync_single_for_cpu(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
+ if (is_dma_capable() && ep->dma)
+ unmap_dma_buffer(req, musb);
if (request->status == 0)
DBG(5, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
@@ -395,6 +432,13 @@ static void txstate(struct musb *musb, struct musb_request *req)
#endif
if (!use_dma) {
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails
+ */
+ if (is_dma_capable() && musb_ep->dma)
+ unmap_dma_buffer(req, musb);
+
musb_write_fifo(musb_ep->hw_ep, fifo_count,
(u8 *) (request->buf + request->actual));
request->actual += fifo_count;
@@ -644,10 +688,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
csr |= MUSB_RXCSR_DMAENAB;
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
- csr |= MUSB_RXCSR_AUTOCLEAR;
#ifdef USE_MODE1
+ csr |= MUSB_RXCSR_AUTOCLEAR;
/* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then
@@ -656,6 +698,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
musb_writew(epio, MUSB_RXCSR,
csr | MUSB_RXCSR_DMAMODE);
+#else
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
#endif
musb_writew(epio, MUSB_RXCSR, csr);
@@ -711,6 +757,21 @@ static void rxstate(struct musb *musb, struct musb_request *req)
return;
}
#endif
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails. This buffer is mapped if the
+ * channel allocation is successful
+ */
+ if (is_dma_capable() && musb_ep->dma) {
+ unmap_dma_buffer(req, musb);
+
+ /*
+ * Clear DMAENAB and AUTOCLEAR for the
+ * PIO mode transfer
+ */
+ csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
(request->buf + request->actual));
@@ -807,7 +868,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
- if ((dma->desired_mode == 0)
+ if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) {
/* ack the read! */
@@ -818,8 +879,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)
/* incomplete, and not short? wait for next IN packet */
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
- == musb_ep->packet_sz))
+ == musb_ep->packet_sz)) {
+ /* In double buffer case, continue to unload fifo if
+ * there is Rx packet in FIFO.
+ **/
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+ hw_ep->rx_double_buffered)
+ goto exit;
return;
+ }
#endif
musb_g_giveback(musb_ep, request, 0);
@@ -827,7 +896,9 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if (!request)
return;
}
-
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+exit:
+#endif
/* Analyze request */
rxstate(musb, to_musb_request(request));
}
@@ -916,13 +987,9 @@ static int musb_gadget_enable(struct usb_ep *ep,
* likewise high bandwidth periodic tx
*/
/* Set TXMAXP with the FIFO size of the endpoint
- * to disable double buffering mode. Currently, It seems that double
- * buffering has problem if musb RTL revision number < 2.0.
+ * to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
- else
- musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -958,10 +1025,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* Set RXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
- else
- musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
@@ -1072,13 +1136,16 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
struct musb_request *request = NULL;
request = kzalloc(sizeof *request, gfp_flags);
- if (request) {
- INIT_LIST_HEAD(&request->request.list);
- request->request.dma = DMA_ADDR_INVALID;
- request->epnum = musb_ep->current_epnum;
- request->ep = musb_ep;
+ if (!request) {
+ DBG(4, "not enough memory\n");
+ return NULL;
}
+ INIT_LIST_HEAD(&request->request.list);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->epnum = musb_ep->current_epnum;
+ request->ep = musb_ep;
+
return &request->request;
}
@@ -1147,28 +1214,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
request->epnum = musb_ep->current_epnum;
request->tx = musb_ep->is_in;
- if (is_dma_capable() && musb_ep->dma) {
- if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
- musb->controller,
- request->request.buf,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 1;
- } else {
- dma_sync_single_for_device(musb->controller,
- request->request.dma,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 0;
- }
- } else if (!req->buf) {
- return -ENODATA;
- } else
+ if (is_dma_capable() && musb_ep->dma)
+ map_dma_buffer(request, musb);
+ else
request->mapped = 0;
spin_lock_irqsave(&musb->lock, lockflags);
@@ -1636,7 +1684,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb)
struct musb_hw_ep *hw_ep;
unsigned count = 0;
- /* intialize endpoint list just once */
+ /* initialize endpoint list just once */
INIT_LIST_HEAD(&(musb->g.ep_list));
for (epnum = 0, hw_ep = musb->endpoints;
@@ -1695,8 +1743,10 @@ int __init musb_gadget_setup(struct musb *musb)
musb_platform_try_idle(musb, 0);
status = device_register(&musb->g.dev);
- if (status != 0)
+ if (status != 0) {
+ put_device(&musb->g.dev);
the_gadget = NULL;
+ }
return status;
}
@@ -1715,7 +1765,7 @@ void musb_gadget_cleanup(struct musb *musb)
*
* -EINVAL something went wrong (not driver)
* -EBUSY another gadget is already using the controller
- * -ENOMEM no memeory to perform the operation
+ * -ENOMEM no memory to perform the operation
*
* @param driver the gadget driver
* @param bind the driver's bind function
@@ -1786,6 +1836,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
DBG(3, "OTG startup...\n");
/* REVISIT: funcall to other code, which also
@@ -1800,6 +1852,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
musb->gadget_driver = NULL;
musb->g.dev.driver = NULL;
spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ hcd->self.uses_pio_for_control = 1;
}
}
}
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index b06e9ef00cfc..03c6ccdbb3be 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -74,7 +74,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
{ __raw_writel(data, addr + offset); }
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
/*
* TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
@@ -114,7 +114,7 @@ static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
{ __raw_writeb(data, addr + offset); }
-#endif /* CONFIG_USB_TUSB6010 */
+#endif /* CONFIG_USB_MUSB_TUSB6010 */
#else
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 244267527a60..82410703dcd3 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -234,7 +234,7 @@
#define MUSB_TESTMODE 0x0F /* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
#else
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
@@ -295,7 +295,7 @@
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(0x100 + (0x10*(_epnum)) + (_offset))
-#ifdef CONFIG_USB_TUSB6010
+#ifdef CONFIG_USB_MUSB_TUSB6010
/* TUSB6010 EP0 configuration register is special */
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
(0x10 + _offset)
@@ -633,8 +633,9 @@ static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
return 0;
}
-static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
{
+ return 0;
}
#endif /* CONFIG_BLACKFIN */
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index 43233c397b6e..b46d1877e28e 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -276,7 +276,7 @@ int musb_hub_control(
break;
case USB_PORT_FEAT_POWER:
if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
- musb_set_vbus(musb, 0);
+ musb_platform_set_vbus(musb, 0);
break;
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_ENABLE:
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 6f771af5cbdb..0144a2d481fd 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -158,6 +158,8 @@ static int dma_channel_program(struct dma_channel *channel,
dma_addr_t dma_addr, u32 len)
{
struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ struct musb *musb = controller->private_data;
DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
musb_channel->epnum,
@@ -167,6 +169,18 @@ static int dma_channel_program(struct dma_channel *channel,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * It ends up masking the last two bits of the address
+ * programmed in DMA_ADDR.
+ *
+ * Fail such DMA transfers, so that the backup PIO mode
+ * can carry out the transfer
+ */
+ if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4))
+ return false;
+
channel->actual_len = 0;
musb_channel->start_addr = dma_addr;
musb_channel->len = len;
@@ -363,7 +377,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)
struct musb_dma_controller *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
- int irq = platform_get_irq(pdev, 1);
+ int irq = platform_get_irq_byname(pdev, "dma");
if (irq == 0) {
dev_err(dev, "No DMA interrupt line!\n");
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index ed618bde1eec..a3f12333fc41 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -31,10 +31,18 @@
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include "musb_core.h"
#include "omap2430.h"
+struct omap2430_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *clk;
+};
+#define glue_to_musb(g) platform_get_drvdata(g->musb)
static struct timer_list musb_idle_timer;
@@ -49,12 +57,8 @@ static void musb_do_idle(unsigned long _musb)
spin_lock_irqsave(&musb->lock, flags);
- devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_BCON:
- devctl &= ~MUSB_DEVCTL_SESSION;
- musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) {
@@ -98,7 +102,7 @@ static void musb_do_idle(unsigned long _musb)
}
-void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
{
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
static unsigned long last_timer;
@@ -131,15 +135,11 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
mod_timer(&musb_idle_timer, timeout);
}
-void musb_platform_enable(struct musb *musb)
-{
-}
-void musb_platform_disable(struct musb *musb)
-{
-}
-static void omap_set_vbus(struct musb *musb, int is_on)
+static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
{
u8 devctl;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ int ret = 1;
/* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions
* that must be ignored.
@@ -148,12 +148,35 @@ static void omap_set_vbus(struct musb *musb, int is_on)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (is_on) {
- musb->is_active = 1;
- musb->xceiv->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
- devctl |= MUSB_DEVCTL_SESSION;
-
- MUSB_HST_MODE(musb);
+ if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ /* start the session */
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ /*
+ * Wait for the musb to set as A device to enable the
+ * VBUS
+ */
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(musb->controller,
+ "configured as A device timeout");
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (ret && musb->xceiv->set_vbus)
+ otg_set_vbus(musb->xceiv, 1);
+ } else {
+ musb->is_active = 1;
+ musb->xceiv->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+ MUSB_HST_MODE(musb);
+ }
} else {
musb->is_active = 0;
@@ -175,9 +198,7 @@ static void omap_set_vbus(struct musb *musb, int is_on)
musb_readb(musb->mregs, MUSB_DEVCTL));
}
-static int musb_platform_resume(struct musb *musb);
-
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
{
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -187,10 +208,94 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
return 0;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static inline void omap2430_low_level_exit(struct musb *musb)
{
u32 l;
- struct omap_musb_board_data *data = board_data;
+
+ /* in any role */
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+ l |= ENABLEFORCE; /* enable MSTANDBY */
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+ l |= ENABLEWAKEUP; /* enable wakeup */
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+}
+
+static inline void omap2430_low_level_init(struct musb *musb)
+{
+ u32 l;
+
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+ l &= ~ENABLEWAKEUP; /* disable wakeup */
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+ l &= ~ENABLEFORCE; /* disable MSTANDBY */
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+}
+
+/* blocking notifier support */
+static int musb_otg_notifications(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ struct musb *musb = container_of(nb, struct musb, nb);
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct omap_musb_board_data *data = pdata->board_data;
+
+ switch (event) {
+ case USB_EVENT_ID:
+ DBG(4, "ID GND\n");
+
+ if (is_otg_enabled(musb)) {
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (musb->gadget_driver) {
+ otg_init(musb->xceiv);
+
+ if (data->interface_type ==
+ MUSB_INTERFACE_UTMI)
+ omap2430_musb_set_vbus(musb, 1);
+
+ }
+#endif
+ } else {
+ otg_init(musb->xceiv);
+ if (data->interface_type ==
+ MUSB_INTERFACE_UTMI)
+ omap2430_musb_set_vbus(musb, 1);
+ }
+ break;
+
+ case USB_EVENT_VBUS:
+ DBG(4, "VBUS Connect\n");
+
+ otg_init(musb->xceiv);
+ break;
+
+ case USB_EVENT_NONE:
+ DBG(4, "VBUS Disconnect\n");
+
+ if (data->interface_type == MUSB_INTERFACE_UTMI) {
+ if (musb->xceiv->set_vbus)
+ otg_set_vbus(musb->xceiv, 0);
+ }
+ otg_shutdown(musb->xceiv);
+ break;
+ default:
+ DBG(4, "ID float\n");
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int omap2430_musb_init(struct musb *musb)
+{
+ u32 l, status = 0;
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
/* We require some kind of external transceiver, hooked
* up through ULPI. TWL4030-family PMICs include one,
@@ -202,7 +307,7 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
return -ENODEV;
}
- musb_platform_resume(musb);
+ omap2430_low_level_init(musb);
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l &= ~ENABLEWAKEUP; /* disable wakeup */
@@ -239,87 +344,214 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
musb_readl(musb->mregs, OTG_INTERFSEL),
musb_readl(musb->mregs, OTG_SIMENABLE));
- if (is_host_enabled(musb))
- musb->board_set_vbus = omap_set_vbus;
+ musb->nb.notifier_call = musb_otg_notifications;
+ status = otg_register_notifier(musb->xceiv, &musb->nb);
+
+ if (status)
+ DBG(1, "notification register failed\n");
+
+ /* check whether cable is already connected */
+ if (musb->xceiv->state ==OTG_STATE_B_IDLE)
+ musb_otg_notifications(&musb->nb, 1,
+ musb->xceiv->gadget);
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
return 0;
}
-#ifdef CONFIG_PM
-void musb_platform_save_context(struct musb *musb,
- struct musb_context_registers *musb_context)
+static int omap2430_musb_exit(struct musb *musb)
{
- musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
- musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
-}
-void musb_platform_restore_context(struct musb *musb,
- struct musb_context_registers *musb_context)
-{
- musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
- musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
+ omap2430_low_level_exit(musb);
+ otg_put_transceiver(musb->xceiv);
+
+ return 0;
}
-#endif
-static int musb_platform_suspend(struct musb *musb)
+static const struct musb_platform_ops omap2430_ops = {
+ .init = omap2430_musb_init,
+ .exit = omap2430_musb_exit,
+
+ .set_mode = omap2430_musb_set_mode,
+ .try_idle = omap2430_musb_try_idle,
+
+ .set_vbus = omap2430_musb_set_vbus,
+};
+
+static u64 omap2430_dmamask = DMA_BIT_MASK(32);
+
+static int __init omap2430_probe(struct platform_device *pdev)
{
- u32 l;
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct omap2430_glue *glue;
+ struct clk *clk;
- if (!musb->clock)
- return 0;
+ int ret = -ENOMEM;
- /* in any role */
- l = musb_readl(musb->mregs, OTG_FORCESTDBY);
- l |= ENABLEFORCE; /* enable MSTANDBY */
- musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
- l = musb_readl(musb->mregs, OTG_SYSCONFIG);
- l |= ENABLEWAKEUP; /* enable wakeup */
- musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
- otg_set_suspend(musb->xceiv, 1);
+ clk = clk_get(&pdev->dev, "ick");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(clk);
+ goto err2;
+ }
- if (musb->set_clock)
- musb->set_clock(musb->clock, 0);
- else
- clk_disable(musb->clock);
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ goto err3;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &omap2430_dmamask;
+ musb->dev.coherent_dma_mask = omap2430_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+ glue->clk = clk;
+
+ pdata->platform_ops = &omap2430_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err4;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err4;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err4;
+ }
return 0;
+
+err4:
+ clk_disable(clk);
+
+err3:
+ clk_put(clk);
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
}
-static int musb_platform_resume(struct musb *musb)
+static int __exit omap2430_remove(struct platform_device *pdev)
{
- u32 l;
+ struct omap2430_glue *glue = platform_get_drvdata(pdev);
- if (!musb->clock)
- return 0;
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ clk_disable(glue->clk);
+ clk_put(glue->clk);
+ kfree(glue);
- otg_set_suspend(musb->xceiv, 0);
+ return 0;
+}
- if (musb->set_clock)
- musb->set_clock(musb->clock, 1);
- else
- clk_enable(musb->clock);
+#ifdef CONFIG_PM
+static void omap2430_save_context(struct musb *musb)
+{
+ musb->context.otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
+ musb->context.otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
+}
- l = musb_readl(musb->mregs, OTG_SYSCONFIG);
- l &= ~ENABLEWAKEUP; /* disable wakeup */
- musb_writel(musb->mregs, OTG_SYSCONFIG, l);
+static void omap2430_restore_context(struct musb *musb)
+{
+ musb_writel(musb->mregs, OTG_SYSCONFIG, musb->context.otg_sysconfig);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, musb->context.otg_forcestandby);
+}
- l = musb_readl(musb->mregs, OTG_FORCESTDBY);
- l &= ~ENABLEFORCE; /* disable MSTANDBY */
- musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+static int omap2430_suspend(struct device *dev)
+{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ omap2430_low_level_exit(musb);
+ otg_set_suspend(musb->xceiv, 1);
+ omap2430_save_context(musb);
+ clk_disable(glue->clk);
return 0;
}
-
-int musb_platform_exit(struct musb *musb)
+static int omap2430_resume(struct device *dev)
{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+ int ret;
+
+ ret = clk_enable(glue->clk);
+ if (ret) {
+ dev_err(dev, "faled to enable clock\n");
+ return ret;
+ }
- musb_platform_suspend(musb);
+ omap2430_low_level_init(musb);
+ omap2430_restore_context(musb);
+ otg_set_suspend(musb->xceiv, 0);
- otg_put_transceiver(musb->xceiv);
return 0;
}
+
+static struct dev_pm_ops omap2430_pm_ops = {
+ .suspend = omap2430_suspend,
+ .resume = omap2430_resume,
+};
+
+#define DEV_PM_OPS (&omap2430_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver omap2430_driver = {
+ .remove = __exit_p(omap2430_remove),
+ .driver = {
+ .name = "musb-omap2430",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init omap2430_init(void)
+{
+ return platform_driver_probe(&omap2430_driver, omap2430_probe);
+}
+subsys_initcall(omap2430_init);
+
+static void __exit omap2430_exit(void)
+{
+ platform_driver_unregister(&omap2430_driver);
+}
+module_exit(omap2430_exit);
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index bde40efc7046..2ba3b070ed0b 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -21,10 +21,16 @@
#include <linux/usb.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include "musb_core.h"
-static void tusb_source_power(struct musb *musb, int is_on);
+struct tusb6010_glue {
+ struct device *dev;
+ struct platform_device *musb;
+};
+
+static void tusb_musb_set_vbus(struct musb *musb, int is_on);
#define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf)
#define TUSB_REV_MINOR(reg_val) (reg_val & 0xf)
@@ -50,7 +56,7 @@ u8 tusb_get_revision(struct musb *musb)
return rev;
}
-static int __init tusb_print_revision(struct musb *musb)
+static int tusb_print_revision(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
u8 rev;
@@ -275,17 +281,6 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
void __iomem *tbase = musb->ctrl_base;
u32 reg;
- /*
- * Keep clock active when enabled. Note that this is not tied to
- * drawing VBUS, as with OTG mA can be less than musb->min_power.
- */
- if (musb->set_clock) {
- if (mA)
- musb->set_clock(musb->clock, 1);
- else
- musb->set_clock(musb->clock, 0);
- }
-
/* tps65030 seems to consume max 100mA, with maybe 60mA available
* (measured on one board) for things other than tps and tusb.
*
@@ -348,7 +343,7 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode)
* USB link is not suspended ... and tells us the relevant wakeup
* events. SW_EN for voltage is handled separately.
*/
-void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
+static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
{
void __iomem *tbase = musb->ctrl_base;
u32 reg;
@@ -385,7 +380,7 @@ void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
/*
* Updates cable VBUS status. Caller must take care of locking.
*/
-int musb_platform_get_vbus_status(struct musb *musb)
+static int tusb_musb_vbus_status(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, prcm_mngmt;
@@ -431,7 +426,7 @@ static void musb_do_idle(unsigned long _musb)
}
/* FALLTHROUGH */
case OTG_STATE_A_IDLE:
- tusb_source_power(musb, 0);
+ tusb_musb_set_vbus(musb, 0);
default:
break;
}
@@ -475,7 +470,7 @@ done:
* we don't want to treat that full speed J as a wakeup event.
* ... peripherals must draw only suspend current after 10 msec.
*/
-void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
{
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
static unsigned long last_timer;
@@ -515,7 +510,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
| TUSB_DEV_OTG_TIMER_ENABLE) \
: 0)
-static void tusb_source_power(struct musb *musb, int is_on)
+static void tusb_musb_set_vbus(struct musb *musb, int is_on)
{
void __iomem *tbase = musb->ctrl_base;
u32 conf, prcm, timer;
@@ -531,8 +526,6 @@ static void tusb_source_power(struct musb *musb, int is_on)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (is_on) {
- if (musb->set_clock)
- musb->set_clock(musb->clock, 1);
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@@ -571,8 +564,6 @@ static void tusb_source_power(struct musb *musb, int is_on)
devctl &= ~MUSB_DEVCTL_SESSION;
conf &= ~TUSB_DEV_CONF_USB_HOST_MODE;
- if (musb->set_clock)
- musb->set_clock(musb->clock, 0);
}
prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
@@ -599,7 +590,7 @@ static void tusb_source_power(struct musb *musb, int is_on)
* and peripheral modes in non-OTG configurations by reconfiguring hardware
* and then setting musb->board_mode. For now, only support OTG mode.
*/
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)
{
void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
@@ -677,7 +668,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
default_a = is_host_enabled(musb);
DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
musb->xceiv->default_a = default_a;
- tusb_source_power(musb, default_a);
+ tusb_musb_set_vbus(musb, default_a);
/* Don't allow idling immediately */
if (default_a)
@@ -722,7 +713,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
DBG(2, "Got SRP, turning on VBUS\n");
- musb_set_vbus(musb, 1);
+ musb_platform_set_vbus(musb, 1);
/* CONNECT can wake if a_wait_bcon is set */
if (musb->a_wait_bcon != 0)
@@ -748,11 +739,11 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
*/
if (musb->vbuserr_retry) {
musb->vbuserr_retry--;
- tusb_source_power(musb, 1);
+ tusb_musb_set_vbus(musb, 1);
} else {
musb->vbuserr_retry
= VBUSERR_RETRY_COUNT;
- tusb_source_power(musb, 0);
+ tusb_musb_set_vbus(musb, 0);
}
break;
default:
@@ -786,7 +777,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
} else {
/* REVISIT report overcurrent to hub? */
ERR("vbus too slow, devctl %02x\n", devctl);
- tusb_source_power(musb, 0);
+ tusb_musb_set_vbus(musb, 0);
}
break;
case OTG_STATE_A_WAIT_BCON:
@@ -807,7 +798,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
return idle_timeout;
}
-static irqreturn_t tusb_interrupt(int irq, void *__hci)
+static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
{
struct musb *musb = __hci;
void __iomem *tbase = musb->ctrl_base;
@@ -911,7 +902,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)
musb_writel(tbase, TUSB_INT_SRC_CLEAR,
int_src & ~TUSB_INT_MASK_RESERVED_BITS);
- musb_platform_try_idle(musb, idle_timeout);
+ tusb_musb_try_idle(musb, idle_timeout);
musb_writel(tbase, TUSB_INT_MASK, int_mask);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -926,7 +917,7 @@ static int dma_off;
* REVISIT:
* - Check what is unnecessary in MGC_HdrcStart()
*/
-void musb_platform_enable(struct musb *musb)
+static void tusb_musb_enable(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
@@ -970,7 +961,7 @@ void musb_platform_enable(struct musb *musb)
/*
* Disables TUSB6010. Caller must take care of locking.
*/
-void musb_platform_disable(struct musb *musb)
+static void tusb_musb_disable(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
@@ -995,7 +986,7 @@ void musb_platform_disable(struct musb *musb)
* Sets up TUSB6010 CPU interface specific signals and registers
* Note: Settings optimized for OMAP24xx
*/
-static void __init tusb_setup_cpu_interface(struct musb *musb)
+static void tusb_setup_cpu_interface(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
@@ -1022,7 +1013,7 @@ static void __init tusb_setup_cpu_interface(struct musb *musb)
musb_writel(tbase, TUSB_WAIT_COUNT, 1);
}
-static int __init tusb_start(struct musb *musb)
+static int tusb_musb_start(struct musb *musb)
{
void __iomem *tbase = musb->ctrl_base;
int ret = 0;
@@ -1091,7 +1082,7 @@ err:
return -ENODEV;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static int tusb_musb_init(struct musb *musb)
{
struct platform_device *pdev;
struct resource *mem;
@@ -1131,16 +1122,14 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
*/
musb->mregs += TUSB_BASE_OFFSET;
- ret = tusb_start(musb);
+ ret = tusb_musb_start(musb);
if (ret) {
printk(KERN_ERR "Could not start tusb6010 (%d)\n",
ret);
goto done;
}
- musb->isr = tusb_interrupt;
+ musb->isr = tusb_musb_interrupt;
- if (is_host_enabled(musb))
- musb->board_set_vbus = tusb_source_power;
if (is_peripheral_enabled(musb)) {
musb->xceiv->set_power = tusb_draw_power;
the_musb = musb;
@@ -1159,7 +1148,7 @@ done:
return ret;
}
-int musb_platform_exit(struct musb *musb)
+static int tusb_musb_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
the_musb = NULL;
@@ -1173,3 +1162,115 @@ int musb_platform_exit(struct musb *musb)
usb_nop_xceiv_unregister();
return 0;
}
+
+static const struct musb_platform_ops tusb_ops = {
+ .init = tusb_musb_init,
+ .exit = tusb_musb_exit,
+
+ .enable = tusb_musb_enable,
+ .disable = tusb_musb_disable,
+
+ .set_mode = tusb_musb_set_mode,
+ .try_idle = tusb_musb_try_idle,
+
+ .vbus_status = tusb_musb_vbus_status,
+ .set_vbus = tusb_musb_set_vbus,
+};
+
+static u64 tusb_dmamask = DMA_BIT_MASK(32);
+
+static int __init tusb_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct tusb6010_glue *glue;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &tusb_dmamask;
+ musb->dev.coherent_dma_mask = tusb_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+
+ pdata->platform_ops = &tusb_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err2;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err2;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err1;
+ }
+
+ return 0;
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit tusb_remove(struct platform_device *pdev)
+{
+ struct tusb6010_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ kfree(glue);
+
+ return 0;
+}
+
+static struct platform_driver tusb_driver = {
+ .remove = __exit_p(tusb_remove),
+ .driver = {
+ .name = "musb-tusb",
+ },
+};
+
+MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init tusb_init(void)
+{
+ return platform_driver_probe(&tusb_driver, tusb_probe);
+}
+subsys_initcall(tusb_init);
+
+static void __exit tusb_exit(void)
+{
+ platform_driver_unregister(&tusb_driver);
+}
+module_exit(tusb_exit);
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
new file mode 100644
index 000000000000..d6384e4aeef9
--- /dev/null
+++ b/drivers/usb/musb/ux500.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ *
+ * Based on omap2430.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "musb_core.h"
+
+struct ux500_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *clk;
+};
+#define glue_to_musb(g) platform_get_drvdata(g->musb)
+
+static int ux500_musb_init(struct musb *musb)
+{
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv) {
+ pr_err("HS USB OTG: no transceiver configured\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ux500_musb_exit(struct musb *musb)
+{
+ otg_put_transceiver(musb->xceiv);
+
+ return 0;
+}
+
+static const struct musb_platform_ops ux500_ops = {
+ .init = ux500_musb_init,
+ .exit = ux500_musb_exit,
+};
+
+static int __init ux500_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct ux500_glue *glue;
+ struct clk *clk;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ clk = clk_get(&pdev->dev, "usb");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(clk);
+ goto err2;
+ }
+
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ goto err3;
+ }
+
+ musb->dev.parent = &pdev->dev;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+ glue->clk = clk;
+
+ pdata->platform_ops = &ux500_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err4;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err4;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ clk_disable(clk);
+
+err3:
+ clk_put(clk);
+
+err2:
+ platform_device_put(musb);
+
+err1:
+ kfree(glue);
+
+err0:
+ return ret;
+}
+
+static int __exit ux500_remove(struct platform_device *pdev)
+{
+ struct ux500_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ clk_disable(glue->clk);
+ clk_put(glue->clk);
+ kfree(glue);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ux500_suspend(struct device *dev)
+{
+ struct ux500_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ otg_set_suspend(musb->xceiv, 1);
+ clk_disable(glue->clk);
+
+ return 0;
+}
+
+static int ux500_resume(struct device *dev)
+{
+ struct ux500_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+ int ret;
+
+ ret = clk_enable(glue->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ otg_set_suspend(musb->xceiv, 0);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ux500_pm_ops = {
+ .suspend = ux500_suspend,
+ .resume = ux500_resume,
+};
+
+#define DEV_PM_OPS (&ux500_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver ux500_driver = {
+ .remove = __exit_p(ux500_remove),
+ .driver = {
+ .name = "musb-ux500",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
+MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init ux500_init(void)
+{
+ return platform_driver_probe(&ux500_driver, ux500_probe);
+}
+subsys_initcall(ux500_init);
+
+static void __exit ux500_exit(void)
+{
+ platform_driver_unregister(&ux500_driver);
+}
+module_exit(ux500_exit);
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 5ce07528cd0c..9fb875d5f09c 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -59,6 +59,18 @@ config TWL4030_USB
This transceiver supports high and full speed devices plus,
in host mode, low speed.
+config TWL6030_USB
+ tristate "TWL6030 USB Transceiver Driver"
+ depends on TWL4030_CORE
+ select USB_OTG_UTILS
+ help
+ Enable this to support the USB OTG transceiver on TWL6030
+ family chips. This TWL6030 transceiver has the VBUS and ID GND
+ and OTG SRP events capabilities. For all other transceiver functionality
+ UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
+ are hooked to this driver through platform_data structure.
+ The definition of internal PHY APIs are in the mach-omap2 layer.
+
config NOP_USB_XCEIV
tristate "NOP USB Transceiver Driver"
select USB_OTG_UTILS
@@ -81,4 +93,24 @@ config USB_LANGWELL_OTG
To compile this driver as a module, choose M here: the
module will be called langwell_otg.
+config USB_MSM_OTG_72K
+ tristate "OTG support for Qualcomm on-chip USB controller"
+ depends on (USB || USB_GADGET) && ARCH_MSM
+ select USB_OTG_UTILS
+ help
+ Enable this to support the USB OTG transceiver on MSM chips. It
+ handles PHY initialization, clock management, and workarounds
+ required after resetting the hardware and power management.
+ This driver is required even for peripheral only or host only
+ mode configurations.
+
+config AB8500_USB
+ tristate "AB8500 USB Transceiver Driver"
+ depends on AB8500_CORE
+ select USB_OTG_UTILS
+ help
+ Enable this to support the USB OTG transceiver in AB8500 chip.
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index 66f1b83e4fa7..a520e715cfd6 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -12,6 +12,9 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
+obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
obj-$(CONFIG_USB_ULPI) += ulpi.o
+obj-$(CONFIG_USB_MSM_OTG_72K) += msm72k_otg.o
+obj-$(CONFIG_AB8500_USB) += ab8500-usb.o
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
new file mode 100644
index 000000000000..d14736b3107b
--- /dev/null
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -0,0 +1,585 @@
+/*
+ * drivers/usb/otg/ab8500_usb.c
+ *
+ * USB transceiver driver for AB8500 chip
+ *
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.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/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+
+#define AB8500_MAIN_WD_CTRL_REG 0x01
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8500_USB_PHY_CTRL_REG 0x8A
+
+#define AB8500_BIT_OTG_STAT_ID (1 << 0)
+#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
+#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
+#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
+
+#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
+#define AB8500_WD_KICK_DELAY_US 100 /* usec */
+#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
+#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
+
+/* Usb line status register */
+enum ab8500_usb_link_status {
+ USB_LINK_NOT_CONFIGURED = 0,
+ USB_LINK_STD_HOST_NC,
+ USB_LINK_STD_HOST_C_NS,
+ USB_LINK_STD_HOST_C_S,
+ USB_LINK_HOST_CHG_NM,
+ USB_LINK_HOST_CHG_HS,
+ USB_LINK_HOST_CHG_HS_CHIRP,
+ USB_LINK_DEDICATED_CHG,
+ USB_LINK_ACA_RID_A,
+ USB_LINK_ACA_RID_B,
+ USB_LINK_ACA_RID_C_NM,
+ USB_LINK_ACA_RID_C_HS,
+ USB_LINK_ACA_RID_C_HS_CHIRP,
+ USB_LINK_HM_IDGND,
+ USB_LINK_RESERVED,
+ USB_LINK_NOT_VALID_LINK
+};
+
+struct ab8500_usb {
+ struct otg_transceiver otg;
+ struct device *dev;
+ int irq_num_id_rise;
+ int irq_num_id_fall;
+ int irq_num_vbus_rise;
+ int irq_num_vbus_fall;
+ int irq_num_link_status;
+ unsigned vbus_draw;
+ struct delayed_work dwork;
+ struct work_struct phy_dis_work;
+ unsigned long link_status_wait;
+ int rev;
+};
+
+static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x)
+{
+ return container_of(x, struct ab8500_usb, otg);
+}
+
+static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
+{
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ AB8500_BIT_WD_CTRL_ENABLE);
+
+ udelay(AB8500_WD_KICK_DELAY_US);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ (AB8500_BIT_WD_CTRL_ENABLE
+ | AB8500_BIT_WD_CTRL_KICK));
+
+ if (ab->rev > 0x10) /* v1.1 v2.0 */
+ udelay(AB8500_WD_V11_DISABLE_DELAY_US);
+ else /* v1.0 */
+ msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ 0);
+}
+
+static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
+ bool enable)
+{
+ u8 ctrl_reg;
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ &ctrl_reg);
+ if (sel_host) {
+ if (enable)
+ ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
+ else
+ ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
+ } else {
+ if (enable)
+ ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
+ else
+ ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
+ }
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ ctrl_reg);
+
+ /* Needed to enable the phy.*/
+ if (enable)
+ ab8500_usb_wd_workaround(ab);
+}
+
+#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true)
+#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false)
+#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true)
+#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false)
+
+static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
+{
+ u8 reg;
+ enum ab8500_usb_link_status lsts;
+ void *v = NULL;
+ enum usb_xceiv_events event;
+
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB,
+ AB8500_USB_LINE_STAT_REG,
+ &reg);
+
+ lsts = (reg >> 3) & 0x0F;
+
+ switch (lsts) {
+ case USB_LINK_NOT_CONFIGURED:
+ case USB_LINK_RESERVED:
+ case USB_LINK_NOT_VALID_LINK:
+ /* TODO: Disable regulators. */
+ ab8500_usb_host_phy_dis(ab);
+ ab8500_usb_peri_phy_dis(ab);
+ ab->otg.state = OTG_STATE_B_IDLE;
+ ab->otg.default_a = false;
+ ab->vbus_draw = 0;
+ event = USB_EVENT_NONE;
+ break;
+
+ case USB_LINK_STD_HOST_NC:
+ case USB_LINK_STD_HOST_C_NS:
+ case USB_LINK_STD_HOST_C_S:
+ case USB_LINK_HOST_CHG_NM:
+ case USB_LINK_HOST_CHG_HS:
+ case USB_LINK_HOST_CHG_HS_CHIRP:
+ if (ab->otg.gadget) {
+ /* TODO: Enable regulators. */
+ ab8500_usb_peri_phy_en(ab);
+ v = ab->otg.gadget;
+ }
+ event = USB_EVENT_VBUS;
+ break;
+
+ case USB_LINK_HM_IDGND:
+ if (ab->otg.host) {
+ /* TODO: Enable regulators. */
+ ab8500_usb_host_phy_en(ab);
+ v = ab->otg.host;
+ }
+ ab->otg.state = OTG_STATE_A_IDLE;
+ ab->otg.default_a = true;
+ event = USB_EVENT_ID;
+ break;
+
+ case USB_LINK_ACA_RID_A:
+ case USB_LINK_ACA_RID_B:
+ /* TODO */
+ case USB_LINK_ACA_RID_C_NM:
+ case USB_LINK_ACA_RID_C_HS:
+ case USB_LINK_ACA_RID_C_HS_CHIRP:
+ case USB_LINK_DEDICATED_CHG:
+ /* TODO: vbus_draw */
+ event = USB_EVENT_CHARGER;
+ break;
+ }
+
+ blocking_notifier_call_chain(&ab->otg.notifier, event, v);
+
+ return 0;
+}
+
+static void ab8500_usb_delayed_work(struct work_struct *work)
+{
+ struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+ dwork.work);
+
+ ab8500_usb_link_status_update(ab);
+}
+
+static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+ /* Wait for link status to become stable. */
+ schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+ /* Link status will not be updated till phy is disabled. */
+ ab8500_usb_peri_phy_dis(ab);
+
+ /* Wait for link status to become stable. */
+ schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+ ab8500_usb_link_status_update(ab);
+
+ return IRQ_HANDLED;
+}
+
+static void ab8500_usb_phy_disable_work(struct work_struct *work)
+{
+ struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+ phy_dis_work);
+
+ if (!ab->otg.host)
+ ab8500_usb_host_phy_dis(ab);
+
+ if (!ab->otg.gadget)
+ ab8500_usb_peri_phy_dis(ab);
+}
+
+static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = xceiv_to_ab(otg);
+
+ ab->vbus_draw = mA;
+
+ if (mA)
+ blocking_notifier_call_chain(&ab->otg.notifier,
+ USB_EVENT_ENUMERATED, ab->otg.gadget);
+ return 0;
+}
+
+/* TODO: Implement some way for charging or other drivers to read
+ * ab->vbus_draw.
+ */
+
+static int ab8500_usb_set_suspend(struct otg_transceiver *x, int suspend)
+{
+ /* TODO */
+ return 0;
+}
+
+static int ab8500_usb_set_peripheral(struct otg_transceiver *otg,
+ struct usb_gadget *gadget)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = xceiv_to_ab(otg);
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if (!gadget) {
+ /* TODO: Disable regulators. */
+ ab->otg.gadget = NULL;
+ schedule_work(&ab->phy_dis_work);
+ } else {
+ ab->otg.gadget = gadget;
+ ab->otg.state = OTG_STATE_B_IDLE;
+
+ /* Phy will not be enabled if cable is already
+ * plugged-in. Schedule to enable phy.
+ * Use same delay to avoid any race condition.
+ */
+ schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_set_host(struct otg_transceiver *otg,
+ struct usb_bus *host)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = xceiv_to_ab(otg);
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if (!host) {
+ /* TODO: Disable regulators. */
+ ab->otg.host = NULL;
+ schedule_work(&ab->phy_dis_work);
+ } else {
+ ab->otg.host = host;
+ /* Phy will not be enabled if cable is already
+ * plugged-in. Schedule to enable phy.
+ * Use same delay to avoid any race condition.
+ */
+ schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+ }
+
+ return 0;
+}
+
+static void ab8500_usb_irq_free(struct ab8500_usb *ab)
+{
+ if (ab->rev < 0x20) {
+ free_irq(ab->irq_num_id_rise, ab);
+ free_irq(ab->irq_num_id_fall, ab);
+ free_irq(ab->irq_num_vbus_rise, ab);
+ free_irq(ab->irq_num_vbus_fall, ab);
+ } else {
+ free_irq(ab->irq_num_link_status, ab);
+ }
+}
+
+static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
+ struct ab8500_usb *ab)
+{
+ int err;
+
+ ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
+ if (ab->irq_num_id_rise < 0) {
+ dev_err(&pdev->dev, "ID rise irq not found\n");
+ return ab->irq_num_id_rise;
+ }
+ err = request_threaded_irq(ab->irq_num_id_rise, NULL,
+ ab8500_usb_v1x_common_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED,
+ "usb-id-rise", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for ID rise irq\n");
+ goto fail0;
+ }
+
+ ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+ if (ab->irq_num_id_fall < 0) {
+ dev_err(&pdev->dev, "ID fall irq not found\n");
+ return ab->irq_num_id_fall;
+ }
+ err = request_threaded_irq(ab->irq_num_id_fall, NULL,
+ ab8500_usb_v1x_common_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED,
+ "usb-id-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for ID fall irq\n");
+ goto fail1;
+ }
+
+ ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
+ if (ab->irq_num_vbus_rise < 0) {
+ dev_err(&pdev->dev, "VBUS rise irq not found\n");
+ return ab->irq_num_vbus_rise;
+ }
+ err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
+ ab8500_usb_v1x_common_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED,
+ "usb-vbus-rise", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
+ goto fail2;
+ }
+
+ ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
+ if (ab->irq_num_vbus_fall < 0) {
+ dev_err(&pdev->dev, "VBUS fall irq not found\n");
+ return ab->irq_num_vbus_fall;
+ }
+ err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
+ ab8500_usb_v1x_vbus_fall_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED,
+ "usb-vbus-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
+ goto fail3;
+ }
+
+ return 0;
+fail3:
+ free_irq(ab->irq_num_vbus_rise, ab);
+fail2:
+ free_irq(ab->irq_num_id_fall, ab);
+fail1:
+ free_irq(ab->irq_num_id_rise, ab);
+fail0:
+ return err;
+}
+
+static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
+ struct ab8500_usb *ab)
+{
+ int err;
+
+ ab->irq_num_link_status = platform_get_irq_byname(pdev,
+ "USB_LINK_STATUS");
+ if (ab->irq_num_link_status < 0) {
+ dev_err(&pdev->dev, "Link status irq not found\n");
+ return ab->irq_num_link_status;
+ }
+
+ err = request_threaded_irq(ab->irq_num_link_status, NULL,
+ ab8500_usb_v20_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED,
+ "usb-link-status", ab);
+ if (err < 0) {
+ dev_err(ab->dev,
+ "request_irq failed for link status irq\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int __devinit ab8500_usb_probe(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab;
+ int err;
+ int rev;
+
+ rev = abx500_get_chip_id(&pdev->dev);
+ if (rev < 0) {
+ dev_err(&pdev->dev, "Chip id read failed\n");
+ return rev;
+ } else if (rev < 0x10) {
+ dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
+ return -ENODEV;
+ }
+
+ ab = kzalloc(sizeof *ab, GFP_KERNEL);
+ if (!ab)
+ return -ENOMEM;
+
+ ab->dev = &pdev->dev;
+ ab->rev = rev;
+ ab->otg.dev = ab->dev;
+ ab->otg.label = "ab8500";
+ ab->otg.state = OTG_STATE_UNDEFINED;
+ ab->otg.set_host = ab8500_usb_set_host;
+ ab->otg.set_peripheral = ab8500_usb_set_peripheral;
+ ab->otg.set_suspend = ab8500_usb_set_suspend;
+ ab->otg.set_power = ab8500_usb_set_power;
+
+ platform_set_drvdata(pdev, ab);
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&ab->otg.notifier);
+
+ /* v1: Wait for link status to become stable.
+ * all: Updates form set_host and set_peripheral as they are atomic.
+ */
+ INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
+
+ /* all: Disable phy when called from set_host and set_peripheral */
+ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
+
+ if (ab->rev < 0x20) {
+ err = ab8500_usb_v1x_res_setup(pdev, ab);
+ ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
+ } else {
+ err = ab8500_usb_v2_res_setup(pdev, ab);
+ }
+
+ if (err < 0)
+ goto fail0;
+
+ err = otg_set_transceiver(&ab->otg);
+ if (err) {
+ dev_err(&pdev->dev, "Can't register transceiver\n");
+ goto fail1;
+ }
+
+ dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
+
+ return 0;
+fail1:
+ ab8500_usb_irq_free(ab);
+fail0:
+ kfree(ab);
+ return err;
+}
+
+static int __devexit ab8500_usb_remove(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab = platform_get_drvdata(pdev);
+
+ ab8500_usb_irq_free(ab);
+
+ cancel_delayed_work_sync(&ab->dwork);
+
+ cancel_work_sync(&ab->phy_dis_work);
+
+ otg_set_transceiver(NULL);
+
+ ab8500_usb_host_phy_dis(ab);
+ ab8500_usb_peri_phy_dis(ab);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(ab);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_usb_driver = {
+ .probe = ab8500_usb_probe,
+ .remove = __devexit_p(ab8500_usb_remove),
+ .driver = {
+ .name = "ab8500-usb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_usb_init(void)
+{
+ return platform_driver_register(&ab8500_usb_driver);
+}
+subsys_initcall(ab8500_usb_init);
+
+static void __exit ab8500_usb_exit(void)
+{
+ platform_driver_unregister(&ab8500_usb_driver);
+}
+module_exit(ab8500_usb_exit);
+
+MODULE_ALIAS("platform:ab8500_usb");
+MODULE_AUTHOR("ST-Ericsson AB");
+MODULE_DESCRIPTION("AB8500 usb transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 456969492410..e00fa1b22ecd 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -1247,7 +1247,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c)
isp->timer.data = 0;
set_bit(WORK_STOP, &isp->todo);
del_timer_sync(&isp->timer);
- flush_scheduled_work();
+ flush_work_sync(&isp->work);
put_device(&i2c->dev);
the_transceiver = NULL;
diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c
index bdc3ea66be69..9fea48264fa2 100644
--- a/drivers/usb/otg/langwell_otg.c
+++ b/drivers/usb/otg/langwell_otg.c
@@ -1896,7 +1896,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1942,8 +1942,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
- get_a_bus_drop, set_a_bus_drop);
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop);
static ssize_t
get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1988,7 +1987,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
+static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
@@ -2012,7 +2011,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
new file mode 100644
index 000000000000..1cd52edcd0c2
--- /dev/null
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -0,0 +1,1125 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_hsusb_hw.h>
+
+#include <mach/clk.h>
+
+#define MSM_USB_BASE (motg->regs)
+#define DRIVER_NAME "msm_otg"
+
+#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
+static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ int cnt = 0;
+
+ /* initiate read operation */
+ writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ while (cnt < ULPI_IO_TIMEOUT_USEC) {
+ if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+ break;
+ udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+ dev_err(otg->dev, "ulpi_read: timeout %08x\n",
+ readl(USB_ULPI_VIEWPORT));
+ return -ETIMEDOUT;
+ }
+ return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ int cnt = 0;
+
+ /* initiate write operation */
+ writel(ULPI_RUN | ULPI_WRITE |
+ ULPI_ADDR(reg) | ULPI_DATA(val),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ while (cnt < ULPI_IO_TIMEOUT_USEC) {
+ if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+ break;
+ udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+ dev_err(otg->dev, "ulpi_write: timeout\n");
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static struct otg_io_access_ops msm_otg_io_ops = {
+ .read = ulpi_read,
+ .write = ulpi_write,
+};
+
+static void ulpi_init(struct msm_otg *motg)
+{
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ int *seq = pdata->phy_init_seq;
+
+ if (!seq)
+ return;
+
+ while (seq[0] >= 0) {
+ dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
+ seq[0], seq[1]);
+ ulpi_write(&motg->otg, seq[0], seq[1]);
+ seq += 2;
+ }
+}
+
+static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
+{
+ int ret;
+
+ if (assert) {
+ ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
+ if (ret)
+ dev_err(motg->otg.dev, "usb hs_clk assert failed\n");
+ } else {
+ ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
+ if (ret)
+ dev_err(motg->otg.dev, "usb hs_clk deassert failed\n");
+ }
+ return ret;
+}
+
+static int msm_otg_phy_clk_reset(struct msm_otg *motg)
+{
+ int ret;
+
+ ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
+ if (ret) {
+ dev_err(motg->otg.dev, "usb phy clk assert failed\n");
+ return ret;
+ }
+ usleep_range(10000, 12000);
+ ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
+ if (ret)
+ dev_err(motg->otg.dev, "usb phy clk deassert failed\n");
+ return ret;
+}
+
+static int msm_otg_phy_reset(struct msm_otg *motg)
+{
+ u32 val;
+ int ret;
+ int retries;
+
+ ret = msm_otg_link_clk_reset(motg, 1);
+ if (ret)
+ return ret;
+ ret = msm_otg_phy_clk_reset(motg);
+ if (ret)
+ return ret;
+ ret = msm_otg_link_clk_reset(motg, 0);
+ if (ret)
+ return ret;
+
+ val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
+ writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+ for (retries = 3; retries > 0; retries--) {
+ ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM,
+ ULPI_CLR(ULPI_FUNC_CTRL));
+ if (!ret)
+ break;
+ ret = msm_otg_phy_clk_reset(motg);
+ if (ret)
+ return ret;
+ }
+ if (!retries)
+ return -ETIMEDOUT;
+
+ /* This reset calibrates the phy, if the above write succeeded */
+ ret = msm_otg_phy_clk_reset(motg);
+ if (ret)
+ return ret;
+
+ for (retries = 3; retries > 0; retries--) {
+ ret = ulpi_read(&motg->otg, ULPI_DEBUG);
+ if (ret != -ETIMEDOUT)
+ break;
+ ret = msm_otg_phy_clk_reset(motg);
+ if (ret)
+ return ret;
+ }
+ if (!retries)
+ return -ETIMEDOUT;
+
+ dev_info(motg->otg.dev, "phy_reset: success\n");
+ return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
+static int msm_otg_reset(struct otg_transceiver *otg)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ int cnt = 0;
+ int ret;
+ u32 val = 0;
+ u32 ulpi_val = 0;
+
+ ret = msm_otg_phy_reset(motg);
+ if (ret) {
+ dev_err(otg->dev, "phy_reset failed\n");
+ return ret;
+ }
+
+ ulpi_init(motg);
+
+ writel(USBCMD_RESET, USB_USBCMD);
+ while (cnt < LINK_RESET_TIMEOUT_USEC) {
+ if (!(readl(USB_USBCMD) & USBCMD_RESET))
+ break;
+ udelay(1);
+ cnt++;
+ }
+ if (cnt >= LINK_RESET_TIMEOUT_USEC)
+ return -ETIMEDOUT;
+
+ /* select ULPI phy */
+ writel(0x80000000, USB_PORTSC);
+
+ msleep(100);
+
+ writel(0x0, USB_AHBBURST);
+ writel(0x00, USB_AHBMODE);
+
+ if (pdata->otg_control == OTG_PHY_CONTROL) {
+ val = readl(USB_OTGSC);
+ if (pdata->mode == USB_OTG) {
+ ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+ val |= OTGSC_IDIE | OTGSC_BSVIE;
+ } else if (pdata->mode == USB_PERIPHERAL) {
+ ulpi_val = ULPI_INT_SESS_VALID;
+ val |= OTGSC_BSVIE;
+ }
+ writel(val, USB_OTGSC);
+ ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
+ ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
+ }
+
+ return 0;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
+static int msm_otg_suspend(struct msm_otg *motg)
+{
+ struct otg_transceiver *otg = &motg->otg;
+ struct usb_bus *bus = otg->host;
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ int cnt = 0;
+
+ if (atomic_read(&motg->in_lpm))
+ return 0;
+
+ disable_irq(motg->irq);
+ /*
+ * Interrupt Latch Register auto-clear feature is not present
+ * in all PHY versions. Latch register is clear on read type.
+ * Clear latch register to avoid spurious wakeup from
+ * low power mode (LPM).
+ */
+ ulpi_read(otg, 0x14);
+
+ /*
+ * PHY comparators are disabled when PHY enters into low power
+ * mode (LPM). Keep PHY comparators ON in LPM only when we expect
+ * VBUS/Id notifications from USB PHY. Otherwise turn off USB
+ * PHY comparators. This save significant amount of power.
+ */
+ if (pdata->otg_control == OTG_PHY_CONTROL)
+ ulpi_write(otg, 0x01, 0x30);
+
+ /*
+ * PLL is not turned off when PHY enters into low power mode (LPM).
+ * Disable PLL for maximum power savings.
+ */
+ ulpi_write(otg, 0x08, 0x09);
+
+ /*
+ * PHY may take some time or even fail to enter into low power
+ * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+ * in failure case.
+ */
+ writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+ while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+ if (readl(USB_PORTSC) & PORTSC_PHCD)
+ break;
+ udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
+ dev_err(otg->dev, "Unable to suspend PHY\n");
+ msm_otg_reset(otg);
+ enable_irq(motg->irq);
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * PHY has capability to generate interrupt asynchronously in low
+ * power mode (LPM). This interrupt is level triggered. So USB IRQ
+ * line must be disabled till async interrupt enable bit is cleared
+ * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+ * block data communication from PHY.
+ */
+ writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
+
+ clk_disable(motg->pclk);
+ clk_disable(motg->clk);
+ if (motg->core_clk)
+ clk_disable(motg->core_clk);
+
+ if (device_may_wakeup(otg->dev))
+ enable_irq_wake(motg->irq);
+ if (bus)
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+ atomic_set(&motg->in_lpm, 1);
+ enable_irq(motg->irq);
+
+ dev_info(otg->dev, "USB in low power mode\n");
+
+ return 0;
+}
+
+#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
+static int msm_otg_resume(struct msm_otg *motg)
+{
+ struct otg_transceiver *otg = &motg->otg;
+ struct usb_bus *bus = otg->host;
+ int cnt = 0;
+ unsigned temp;
+
+ if (!atomic_read(&motg->in_lpm))
+ return 0;
+
+ clk_enable(motg->pclk);
+ clk_enable(motg->clk);
+ if (motg->core_clk)
+ clk_enable(motg->core_clk);
+
+ temp = readl(USB_USBCMD);
+ temp &= ~ASYNC_INTR_CTRL;
+ temp &= ~ULPI_STP_CTRL;
+ writel(temp, USB_USBCMD);
+
+ /*
+ * PHY comes out of low power mode (LPM) in case of wakeup
+ * from asynchronous interrupt.
+ */
+ if (!(readl(USB_PORTSC) & PORTSC_PHCD))
+ goto skip_phy_resume;
+
+ writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
+ while (cnt < PHY_RESUME_TIMEOUT_USEC) {
+ if (!(readl(USB_PORTSC) & PORTSC_PHCD))
+ break;
+ udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
+ /*
+ * This is a fatal error. Reset the link and
+ * PHY. USB state can not be restored. Re-insertion
+ * of USB cable is the only way to get USB working.
+ */
+ dev_err(otg->dev, "Unable to resume USB."
+ "Re-plugin the cable\n");
+ msm_otg_reset(otg);
+ }
+
+skip_phy_resume:
+ if (device_may_wakeup(otg->dev))
+ disable_irq_wake(motg->irq);
+ if (bus)
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+ if (motg->async_int) {
+ motg->async_int = 0;
+ pm_runtime_put(otg->dev);
+ enable_irq(motg->irq);
+ }
+
+ atomic_set(&motg->in_lpm, 0);
+
+ dev_info(otg->dev, "USB exited from low power mode\n");
+
+ return 0;
+}
+
+static void msm_otg_start_host(struct otg_transceiver *otg, int on)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ struct usb_hcd *hcd;
+
+ if (!otg->host)
+ return;
+
+ hcd = bus_to_hcd(otg->host);
+
+ if (on) {
+ dev_dbg(otg->dev, "host on\n");
+
+ if (pdata->vbus_power)
+ pdata->vbus_power(1);
+ /*
+ * Some boards have a switch cotrolled by gpio
+ * to enable/disable internal HUB. Enable internal
+ * HUB before kicking the host.
+ */
+ if (pdata->setup_gpio)
+ pdata->setup_gpio(OTG_STATE_A_HOST);
+#ifdef CONFIG_USB
+ usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+#endif
+ } else {
+ dev_dbg(otg->dev, "host off\n");
+
+#ifdef CONFIG_USB
+ usb_remove_hcd(hcd);
+#endif
+ if (pdata->setup_gpio)
+ pdata->setup_gpio(OTG_STATE_UNDEFINED);
+ if (pdata->vbus_power)
+ pdata->vbus_power(0);
+ }
+}
+
+static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct usb_hcd *hcd;
+
+ /*
+ * Fail host registration if this board can support
+ * only peripheral configuration.
+ */
+ if (motg->pdata->mode == USB_PERIPHERAL) {
+ dev_info(otg->dev, "Host mode is not supported\n");
+ return -ENODEV;
+ }
+
+ if (!host) {
+ if (otg->state == OTG_STATE_A_HOST) {
+ pm_runtime_get_sync(otg->dev);
+ msm_otg_start_host(otg, 0);
+ otg->host = NULL;
+ otg->state = OTG_STATE_UNDEFINED;
+ schedule_work(&motg->sm_work);
+ } else {
+ otg->host = NULL;
+ }
+
+ return 0;
+ }
+
+ hcd = bus_to_hcd(host);
+ hcd->power_budget = motg->pdata->power_budget;
+
+ otg->host = host;
+ dev_dbg(otg->dev, "host driver registered w/ tranceiver\n");
+
+ /*
+ * Kick the state machine work, if peripheral is not supported
+ * or peripheral is already registered with us.
+ */
+ if (motg->pdata->mode == USB_HOST || otg->gadget) {
+ pm_runtime_get_sync(otg->dev);
+ schedule_work(&motg->sm_work);
+ }
+
+ return 0;
+}
+
+static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg_platform_data *pdata = motg->pdata;
+
+ if (!otg->gadget)
+ return;
+
+ if (on) {
+ dev_dbg(otg->dev, "gadget on\n");
+ /*
+ * Some boards have a switch cotrolled by gpio
+ * to enable/disable internal HUB. Disable internal
+ * HUB before kicking the gadget.
+ */
+ if (pdata->setup_gpio)
+ pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
+ usb_gadget_vbus_connect(otg->gadget);
+ } else {
+ dev_dbg(otg->dev, "gadget off\n");
+ usb_gadget_vbus_disconnect(otg->gadget);
+ if (pdata->setup_gpio)
+ pdata->setup_gpio(OTG_STATE_UNDEFINED);
+ }
+
+}
+
+static int msm_otg_set_peripheral(struct otg_transceiver *otg,
+ struct usb_gadget *gadget)
+{
+ struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+
+ /*
+ * Fail peripheral registration if this board can support
+ * only host configuration.
+ */
+ if (motg->pdata->mode == USB_HOST) {
+ dev_info(otg->dev, "Peripheral mode is not supported\n");
+ return -ENODEV;
+ }
+
+ if (!gadget) {
+ if (otg->state == OTG_STATE_B_PERIPHERAL) {
+ pm_runtime_get_sync(otg->dev);
+ msm_otg_start_peripheral(otg, 0);
+ otg->gadget = NULL;
+ otg->state = OTG_STATE_UNDEFINED;
+ schedule_work(&motg->sm_work);
+ } else {
+ otg->gadget = NULL;
+ }
+
+ return 0;
+ }
+ otg->gadget = gadget;
+ dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n");
+
+ /*
+ * Kick the state machine work, if host is not supported
+ * or host is already registered with us.
+ */
+ if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
+ pm_runtime_get_sync(otg->dev);
+ schedule_work(&motg->sm_work);
+ }
+
+ return 0;
+}
+
+/*
+ * We support OTG, Peripheral only and Host only configurations. In case
+ * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
+ * via Id pin status or user request (debugfs). Id/BSV interrupts are not
+ * enabled when switch is controlled by user and default mode is supplied
+ * by board file, which can be changed by userspace later.
+ */
+static void msm_otg_init_sm(struct msm_otg *motg)
+{
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ u32 otgsc = readl(USB_OTGSC);
+
+ switch (pdata->mode) {
+ case USB_OTG:
+ if (pdata->otg_control == OTG_PHY_CONTROL) {
+ if (otgsc & OTGSC_ID)
+ set_bit(ID, &motg->inputs);
+ else
+ clear_bit(ID, &motg->inputs);
+
+ if (otgsc & OTGSC_BSV)
+ set_bit(B_SESS_VLD, &motg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ } else if (pdata->otg_control == OTG_USER_CONTROL) {
+ if (pdata->default_mode == USB_HOST) {
+ clear_bit(ID, &motg->inputs);
+ } else if (pdata->default_mode == USB_PERIPHERAL) {
+ set_bit(ID, &motg->inputs);
+ set_bit(B_SESS_VLD, &motg->inputs);
+ } else {
+ set_bit(ID, &motg->inputs);
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ }
+ }
+ break;
+ case USB_HOST:
+ clear_bit(ID, &motg->inputs);
+ break;
+ case USB_PERIPHERAL:
+ set_bit(ID, &motg->inputs);
+ if (otgsc & OTGSC_BSV)
+ set_bit(B_SESS_VLD, &motg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ break;
+ default:
+ break;
+ }
+}
+
+static void msm_otg_sm_work(struct work_struct *w)
+{
+ struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
+ struct otg_transceiver *otg = &motg->otg;
+
+ switch (otg->state) {
+ case OTG_STATE_UNDEFINED:
+ dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
+ msm_otg_reset(otg);
+ msm_otg_init_sm(motg);
+ otg->state = OTG_STATE_B_IDLE;
+ /* FALL THROUGH */
+ case OTG_STATE_B_IDLE:
+ dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
+ if (!test_bit(ID, &motg->inputs) && otg->host) {
+ /* disable BSV bit */
+ writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
+ msm_otg_start_host(otg, 1);
+ otg->state = OTG_STATE_A_HOST;
+ } else if (test_bit(B_SESS_VLD, &motg->inputs) && otg->gadget) {
+ msm_otg_start_peripheral(otg, 1);
+ otg->state = OTG_STATE_B_PERIPHERAL;
+ }
+ pm_runtime_put_sync(otg->dev);
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
+ if (!test_bit(B_SESS_VLD, &motg->inputs) ||
+ !test_bit(ID, &motg->inputs)) {
+ msm_otg_start_peripheral(otg, 0);
+ otg->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg);
+ schedule_work(w);
+ }
+ break;
+ case OTG_STATE_A_HOST:
+ dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
+ if (test_bit(ID, &motg->inputs)) {
+ msm_otg_start_host(otg, 0);
+ otg->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg);
+ schedule_work(w);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static irqreturn_t msm_otg_irq(int irq, void *data)
+{
+ struct msm_otg *motg = data;
+ struct otg_transceiver *otg = &motg->otg;
+ u32 otgsc = 0;
+
+ if (atomic_read(&motg->in_lpm)) {
+ disable_irq_nosync(irq);
+ motg->async_int = 1;
+ pm_runtime_get(otg->dev);
+ return IRQ_HANDLED;
+ }
+
+ otgsc = readl(USB_OTGSC);
+ if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+ return IRQ_NONE;
+
+ if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
+ if (otgsc & OTGSC_ID)
+ set_bit(ID, &motg->inputs);
+ else
+ clear_bit(ID, &motg->inputs);
+ dev_dbg(otg->dev, "ID set/clear\n");
+ pm_runtime_get_noresume(otg->dev);
+ } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
+ if (otgsc & OTGSC_BSV)
+ set_bit(B_SESS_VLD, &motg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ dev_dbg(otg->dev, "BSV set/clear\n");
+ pm_runtime_get_noresume(otg->dev);
+ }
+
+ writel(otgsc, USB_OTGSC);
+ schedule_work(&motg->sm_work);
+ return IRQ_HANDLED;
+}
+
+static int msm_otg_mode_show(struct seq_file *s, void *unused)
+{
+ struct msm_otg *motg = s->private;
+ struct otg_transceiver *otg = &motg->otg;
+
+ switch (otg->state) {
+ case OTG_STATE_A_HOST:
+ seq_printf(s, "host\n");
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ seq_printf(s, "peripheral\n");
+ break;
+ default:
+ seq_printf(s, "none\n");
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_otg_mode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_otg_mode_show, inode->i_private);
+}
+
+static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_otg *motg = file->private_data;
+ char buf[16];
+ struct otg_transceiver *otg = &motg->otg;
+ int status = count;
+ enum usb_mode_type req_mode;
+
+ memset(buf, 0x00, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+ status = -EFAULT;
+ goto out;
+ }
+
+ if (!strncmp(buf, "host", 4)) {
+ req_mode = USB_HOST;
+ } else if (!strncmp(buf, "peripheral", 10)) {
+ req_mode = USB_PERIPHERAL;
+ } else if (!strncmp(buf, "none", 4)) {
+ req_mode = USB_NONE;
+ } else {
+ status = -EINVAL;
+ goto out;
+ }
+
+ switch (req_mode) {
+ case USB_NONE:
+ switch (otg->state) {
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_B_PERIPHERAL:
+ set_bit(ID, &motg->inputs);
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ break;
+ default:
+ goto out;
+ }
+ break;
+ case USB_PERIPHERAL:
+ switch (otg->state) {
+ case OTG_STATE_B_IDLE:
+ case OTG_STATE_A_HOST:
+ set_bit(ID, &motg->inputs);
+ set_bit(B_SESS_VLD, &motg->inputs);
+ break;
+ default:
+ goto out;
+ }
+ break;
+ case USB_HOST:
+ switch (otg->state) {
+ case OTG_STATE_B_IDLE:
+ case OTG_STATE_B_PERIPHERAL:
+ clear_bit(ID, &motg->inputs);
+ break;
+ default:
+ goto out;
+ }
+ break;
+ default:
+ goto out;
+ }
+
+ pm_runtime_get_sync(otg->dev);
+ schedule_work(&motg->sm_work);
+out:
+ return status;
+}
+
+const struct file_operations msm_otg_mode_fops = {
+ .open = msm_otg_mode_open,
+ .read = seq_read,
+ .write = msm_otg_mode_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *msm_otg_dbg_root;
+static struct dentry *msm_otg_dbg_mode;
+
+static int msm_otg_debugfs_init(struct msm_otg *motg)
+{
+ msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
+
+ if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
+ return -ENODEV;
+
+ msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
+ msm_otg_dbg_root, motg, &msm_otg_mode_fops);
+ if (!msm_otg_dbg_mode) {
+ debugfs_remove(msm_otg_dbg_root);
+ msm_otg_dbg_root = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void msm_otg_debugfs_cleanup(void)
+{
+ debugfs_remove(msm_otg_dbg_mode);
+ debugfs_remove(msm_otg_dbg_root);
+}
+
+static int __init msm_otg_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+ struct msm_otg *motg;
+ struct otg_transceiver *otg;
+
+ dev_info(&pdev->dev, "msm_otg probe\n");
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "No platform data given. Bailing out\n");
+ return -ENODEV;
+ }
+
+ motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+ if (!motg) {
+ dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+ return -ENOMEM;
+ }
+
+ motg->pdata = pdev->dev.platform_data;
+ otg = &motg->otg;
+ otg->dev = &pdev->dev;
+
+ motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
+ if (IS_ERR(motg->phy_reset_clk)) {
+ dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
+ ret = PTR_ERR(motg->phy_reset_clk);
+ goto free_motg;
+ }
+
+ motg->clk = clk_get(&pdev->dev, "usb_hs_clk");
+ if (IS_ERR(motg->clk)) {
+ dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
+ ret = PTR_ERR(motg->clk);
+ goto put_phy_reset_clk;
+ }
+
+ motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+ if (IS_ERR(motg->pclk)) {
+ dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
+ ret = PTR_ERR(motg->pclk);
+ goto put_clk;
+ }
+
+ /*
+ * USB core clock is not present on all MSM chips. This
+ * clock is introduced to remove the dependency on AXI
+ * bus frequency.
+ */
+ motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk");
+ if (IS_ERR(motg->core_clk))
+ motg->core_clk = NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get platform resource mem\n");
+ ret = -ENODEV;
+ goto put_core_clk;
+ }
+
+ motg->regs = ioremap(res->start, resource_size(res));
+ if (!motg->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto put_core_clk;
+ }
+ dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
+
+ motg->irq = platform_get_irq(pdev, 0);
+ if (!motg->irq) {
+ dev_err(&pdev->dev, "platform_get_irq failed\n");
+ ret = -ENODEV;
+ goto free_regs;
+ }
+
+ clk_enable(motg->clk);
+ clk_enable(motg->pclk);
+ if (motg->core_clk)
+ clk_enable(motg->core_clk);
+
+ writel(0, USB_USBINTR);
+ writel(0, USB_OTGSC);
+
+ INIT_WORK(&motg->sm_work, msm_otg_sm_work);
+ ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
+ "msm_otg", motg);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq failed\n");
+ goto disable_clks;
+ }
+
+ otg->init = msm_otg_reset;
+ otg->set_host = msm_otg_set_host;
+ otg->set_peripheral = msm_otg_set_peripheral;
+
+ otg->io_ops = &msm_otg_io_ops;
+
+ ret = otg_set_transceiver(&motg->otg);
+ if (ret) {
+ dev_err(&pdev->dev, "otg_set_transceiver failed\n");
+ goto free_irq;
+ }
+
+ platform_set_drvdata(pdev, motg);
+ device_init_wakeup(&pdev->dev, 1);
+
+ if (motg->pdata->mode == USB_OTG &&
+ motg->pdata->otg_control == OTG_USER_CONTROL) {
+ ret = msm_otg_debugfs_init(motg);
+ if (ret)
+ dev_dbg(&pdev->dev, "mode debugfs file is"
+ "not available\n");
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+free_irq:
+ free_irq(motg->irq, motg);
+disable_clks:
+ clk_disable(motg->pclk);
+ clk_disable(motg->clk);
+free_regs:
+ iounmap(motg->regs);
+put_core_clk:
+ if (motg->core_clk)
+ clk_put(motg->core_clk);
+ clk_put(motg->pclk);
+put_clk:
+ clk_put(motg->clk);
+put_phy_reset_clk:
+ clk_put(motg->phy_reset_clk);
+free_motg:
+ kfree(motg);
+ return ret;
+}
+
+static int __devexit msm_otg_remove(struct platform_device *pdev)
+{
+ struct msm_otg *motg = platform_get_drvdata(pdev);
+ struct otg_transceiver *otg = &motg->otg;
+ int cnt = 0;
+
+ if (otg->host || otg->gadget)
+ return -EBUSY;
+
+ msm_otg_debugfs_cleanup();
+ cancel_work_sync(&motg->sm_work);
+
+ msm_otg_resume(motg);
+
+ device_init_wakeup(&pdev->dev, 0);
+ pm_runtime_disable(&pdev->dev);
+
+ otg_set_transceiver(NULL);
+ free_irq(motg->irq, motg);
+
+ /*
+ * Put PHY in low power mode.
+ */
+ ulpi_read(otg, 0x14);
+ ulpi_write(otg, 0x08, 0x09);
+
+ writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+ while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+ if (readl(USB_PORTSC) & PORTSC_PHCD)
+ break;
+ udelay(1);
+ cnt++;
+ }
+ if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
+ dev_err(otg->dev, "Unable to suspend PHY\n");
+
+ clk_disable(motg->pclk);
+ clk_disable(motg->clk);
+ if (motg->core_clk)
+ clk_disable(motg->core_clk);
+
+ iounmap(motg->regs);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ clk_put(motg->phy_reset_clk);
+ clk_put(motg->pclk);
+ clk_put(motg->clk);
+ if (motg->core_clk)
+ clk_put(motg->core_clk);
+
+ kfree(motg);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int msm_otg_runtime_idle(struct device *dev)
+{
+ struct msm_otg *motg = dev_get_drvdata(dev);
+ struct otg_transceiver *otg = &motg->otg;
+
+ dev_dbg(dev, "OTG runtime idle\n");
+
+ /*
+ * It is observed some times that a spurious interrupt
+ * comes when PHY is put into LPM immediately after PHY reset.
+ * This 1 sec delay also prevents entering into LPM immediately
+ * after asynchronous interrupt.
+ */
+ if (otg->state != OTG_STATE_UNDEFINED)
+ pm_schedule_suspend(dev, 1000);
+
+ return -EAGAIN;
+}
+
+static int msm_otg_runtime_suspend(struct device *dev)
+{
+ struct msm_otg *motg = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "OTG runtime suspend\n");
+ return msm_otg_suspend(motg);
+}
+
+static int msm_otg_runtime_resume(struct device *dev)
+{
+ struct msm_otg *motg = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "OTG runtime resume\n");
+ return msm_otg_resume(motg);
+}
+#else
+#define msm_otg_runtime_idle NULL
+#define msm_otg_runtime_suspend NULL
+#define msm_otg_runtime_resume NULL
+#endif
+
+#ifdef CONFIG_PM
+static int msm_otg_pm_suspend(struct device *dev)
+{
+ struct msm_otg *motg = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "OTG PM suspend\n");
+ return msm_otg_suspend(motg);
+}
+
+static int msm_otg_pm_resume(struct device *dev)
+{
+ struct msm_otg *motg = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(dev, "OTG PM resume\n");
+
+ ret = msm_otg_resume(motg);
+ if (ret)
+ return ret;
+
+ /*
+ * Runtime PM Documentation recommends bringing the
+ * device to full powered state upon resume.
+ */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+#else
+#define msm_otg_pm_suspend NULL
+#define msm_otg_pm_resume NULL
+#endif
+
+static const struct dev_pm_ops msm_otg_dev_pm_ops = {
+ .runtime_suspend = msm_otg_runtime_suspend,
+ .runtime_resume = msm_otg_runtime_resume,
+ .runtime_idle = msm_otg_runtime_idle,
+ .suspend = msm_otg_pm_suspend,
+ .resume = msm_otg_pm_resume,
+};
+
+static struct platform_driver msm_otg_driver = {
+ .remove = __devexit_p(msm_otg_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &msm_otg_dev_pm_ops,
+ },
+};
+
+static int __init msm_otg_init(void)
+{
+ return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
+}
+
+static void __exit msm_otg_exit(void)
+{
+ platform_driver_unregister(&msm_otg_driver);
+}
+
+module_init(msm_otg_init);
+module_exit(msm_otg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM USB transceiver driver");
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index d335f484fcd8..6ca505f333e4 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -678,7 +678,8 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
/* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
- twl4030_phy_power(twl, 0);
+ if (!twl->asleep)
+ twl4030_phy_power(twl, 0);
regulator_put(twl->usb1v5);
regulator_put(twl->usb1v8);
regulator_put(twl->usb3v1);
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
new file mode 100644
index 000000000000..28f770103640
--- /dev/null
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -0,0 +1,493 @@
+/*
+ * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ * Author: Hema HK <hemahk@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c/twl.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+
+/* usb register definitions */
+#define USB_VENDOR_ID_LSB 0x00
+#define USB_VENDOR_ID_MSB 0x01
+#define USB_PRODUCT_ID_LSB 0x02
+#define USB_PRODUCT_ID_MSB 0x03
+#define USB_VBUS_CTRL_SET 0x04
+#define USB_VBUS_CTRL_CLR 0x05
+#define USB_ID_CTRL_SET 0x06
+#define USB_ID_CTRL_CLR 0x07
+#define USB_VBUS_INT_SRC 0x08
+#define USB_VBUS_INT_LATCH_SET 0x09
+#define USB_VBUS_INT_LATCH_CLR 0x0A
+#define USB_VBUS_INT_EN_LO_SET 0x0B
+#define USB_VBUS_INT_EN_LO_CLR 0x0C
+#define USB_VBUS_INT_EN_HI_SET 0x0D
+#define USB_VBUS_INT_EN_HI_CLR 0x0E
+#define USB_ID_INT_SRC 0x0F
+#define USB_ID_INT_LATCH_SET 0x10
+#define USB_ID_INT_LATCH_CLR 0x11
+
+#define USB_ID_INT_EN_LO_SET 0x12
+#define USB_ID_INT_EN_LO_CLR 0x13
+#define USB_ID_INT_EN_HI_SET 0x14
+#define USB_ID_INT_EN_HI_CLR 0x15
+#define USB_OTG_ADP_CTRL 0x16
+#define USB_OTG_ADP_HIGH 0x17
+#define USB_OTG_ADP_LOW 0x18
+#define USB_OTG_ADP_RISE 0x19
+#define USB_OTG_REVISION 0x1A
+
+/* to be moved to LDO */
+#define TWL6030_MISC2 0xE5
+#define TWL6030_CFG_LDO_PD2 0xF5
+#define TWL6030_BACKUP_REG 0xFA
+
+#define STS_HW_CONDITIONS 0x21
+
+/* In module TWL6030_MODULE_PM_MASTER */
+#define STS_HW_CONDITIONS 0x21
+#define STS_USB_ID BIT(2)
+
+/* In module TWL6030_MODULE_PM_RECEIVER */
+#define VUSB_CFG_TRANS 0x71
+#define VUSB_CFG_STATE 0x72
+#define VUSB_CFG_VOLTAGE 0x73
+
+/* in module TWL6030_MODULE_MAIN_CHARGE */
+
+#define CHARGERUSB_CTRL1 0x8
+
+#define CONTROLLER_STAT1 0x03
+#define VBUS_DET BIT(2)
+
+struct twl6030_usb {
+ struct otg_transceiver otg;
+ struct device *dev;
+
+ /* for vbus reporting with irqs disabled */
+ spinlock_t lock;
+
+ struct regulator *usb3v3;
+
+ int irq1;
+ int irq2;
+ u8 linkstat;
+ u8 asleep;
+ bool irq_enabled;
+};
+
+#define xceiv_to_twl(x) container_of((x), struct twl6030_usb, otg);
+
+/*-------------------------------------------------------------------------*/
+
+static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
+ u8 data, u8 address)
+{
+ int ret = 0;
+
+ ret = twl_i2c_write_u8(module, data, address);
+ if (ret < 0)
+ dev_err(twl->dev,
+ "Write[0x%x] Error %d\n", address, ret);
+ return ret;
+}
+
+static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
+{
+ u8 data, ret = 0;
+
+ ret = twl_i2c_read_u8(module, &data, address);
+ if (ret >= 0)
+ ret = data;
+ else
+ dev_err(twl->dev,
+ "readb[0x%x,0x%x] Error %d\n",
+ module, address, ret);
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+static int twl6030_set_phy_clk(struct otg_transceiver *x, int on)
+{
+ struct twl6030_usb *twl;
+ struct device *dev;
+ struct twl4030_usb_data *pdata;
+
+ twl = xceiv_to_twl(x);
+ dev = twl->dev;
+ pdata = dev->platform_data;
+
+ pdata->phy_set_clock(twl->dev, on);
+
+ return 0;
+}
+
+static int twl6030_phy_init(struct otg_transceiver *x)
+{
+ u8 hw_state;
+ struct twl6030_usb *twl;
+ struct device *dev;
+ struct twl4030_usb_data *pdata;
+
+ twl = xceiv_to_twl(x);
+ dev = twl->dev;
+ pdata = dev->platform_data;
+
+ regulator_enable(twl->usb3v3);
+
+ hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
+
+ if (hw_state & STS_USB_ID)
+ pdata->phy_power(twl->dev, 1, 1);
+ else
+ pdata->phy_power(twl->dev, 0, 1);
+
+ return 0;
+}
+
+static void twl6030_phy_shutdown(struct otg_transceiver *x)
+{
+ struct twl6030_usb *twl;
+ struct device *dev;
+ struct twl4030_usb_data *pdata;
+
+ twl = xceiv_to_twl(x);
+ dev = twl->dev;
+ pdata = dev->platform_data;
+ pdata->phy_power(twl->dev, 0, 0);
+ regulator_disable(twl->usb3v3);
+}
+
+static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
+{
+
+ /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
+ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
+
+ /* Program CFG_LDO_PD2 register and set VUSB bit */
+ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
+
+ /* Program MISC2 register and set bit VUSB_IN_VBAT */
+ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
+
+ twl->usb3v3 = regulator_get(twl->dev, "vusb");
+ if (IS_ERR(twl->usb3v3))
+ return -ENODEV;
+
+ regulator_enable(twl->usb3v3);
+
+ /* Program the VUSB_CFG_TRANS for ACTIVE state. */
+ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x3F,
+ VUSB_CFG_TRANS);
+
+ /* Program the VUSB_CFG_STATE register to ON on all groups. */
+ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0xE1,
+ VUSB_CFG_STATE);
+
+ /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
+ twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
+
+ /*
+ * Program the USB_ID_CTRL_SET register to enable GND drive
+ * and the ID comparators
+ */
+ twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
+
+ return 0;
+}
+
+static ssize_t twl6030_usb_vbus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct twl6030_usb *twl = dev_get_drvdata(dev);
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&twl->lock, flags);
+
+ switch (twl->linkstat) {
+ case USB_EVENT_VBUS:
+ ret = snprintf(buf, PAGE_SIZE, "vbus\n");
+ break;
+ case USB_EVENT_ID:
+ ret = snprintf(buf, PAGE_SIZE, "id\n");
+ break;
+ case USB_EVENT_NONE:
+ ret = snprintf(buf, PAGE_SIZE, "none\n");
+ break;
+ default:
+ ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+ }
+ spin_unlock_irqrestore(&twl->lock, flags);
+
+ return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
+
+static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
+{
+ struct twl6030_usb *twl = _twl;
+ int status;
+ u8 vbus_state, hw_state;
+
+ hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
+
+ vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
+ CONTROLLER_STAT1);
+ if (!(hw_state & STS_USB_ID)) {
+ if (vbus_state & VBUS_DET) {
+ status = USB_EVENT_VBUS;
+ twl->otg.default_a = false;
+ twl->otg.state = OTG_STATE_B_IDLE;
+ } else {
+ status = USB_EVENT_NONE;
+ }
+ if (status >= 0) {
+ twl->linkstat = status;
+ blocking_notifier_call_chain(&twl->otg.notifier,
+ status, twl->otg.gadget);
+ }
+ }
+ sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
+{
+ struct twl6030_usb *twl = _twl;
+ int status = USB_EVENT_NONE;
+ u8 hw_state;
+
+ hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
+
+ if (hw_state & STS_USB_ID) {
+
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
+ 0x10);
+ status = USB_EVENT_ID;
+ twl->otg.default_a = true;
+ twl->otg.state = OTG_STATE_A_IDLE;
+ blocking_notifier_call_chain(&twl->otg.notifier, status,
+ twl->otg.gadget);
+ } else {
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
+ 0x10);
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
+ 0x1);
+ }
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status);
+ twl->linkstat = status;
+
+ return IRQ_HANDLED;
+}
+
+static int twl6030_set_peripheral(struct otg_transceiver *x,
+ struct usb_gadget *gadget)
+{
+ struct twl6030_usb *twl;
+
+ if (!x)
+ return -ENODEV;
+
+ twl = xceiv_to_twl(x);
+ twl->otg.gadget = gadget;
+ if (!gadget)
+ twl->otg.state = OTG_STATE_UNDEFINED;
+
+ return 0;
+}
+
+static int twl6030_enable_irq(struct otg_transceiver *x)
+{
+ struct twl6030_usb *twl = xceiv_to_twl(x);
+
+ twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1);
+ twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
+ twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
+
+ twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
+ REG_INT_MSK_LINE_C);
+ twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
+ REG_INT_MSK_STS_C);
+ twl6030_usb_irq(twl->irq2, twl);
+ twl6030_usbotg_irq(twl->irq1, twl);
+
+ return 0;
+}
+
+static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
+{
+ struct twl6030_usb *twl = xceiv_to_twl(x);
+
+ /*
+ * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
+ * register. This enables boost mode.
+ */
+ if (enabled)
+ twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
+ CHARGERUSB_CTRL1);
+ else
+ twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
+ CHARGERUSB_CTRL1);
+ return 0;
+}
+
+static int twl6030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+{
+ struct twl6030_usb *twl;
+
+ if (!x)
+ return -ENODEV;
+
+ twl = xceiv_to_twl(x);
+ twl->otg.host = host;
+ if (!host)
+ twl->otg.state = OTG_STATE_UNDEFINED;
+ return 0;
+}
+
+static int __devinit twl6030_usb_probe(struct platform_device *pdev)
+{
+ struct twl6030_usb *twl;
+ int status, err;
+ struct twl4030_usb_data *pdata;
+ struct device *dev = &pdev->dev;
+ pdata = dev->platform_data;
+
+ twl = kzalloc(sizeof *twl, GFP_KERNEL);
+ if (!twl)
+ return -ENOMEM;
+
+ twl->dev = &pdev->dev;
+ twl->irq1 = platform_get_irq(pdev, 0);
+ twl->irq2 = platform_get_irq(pdev, 1);
+ twl->otg.dev = twl->dev;
+ twl->otg.label = "twl6030";
+ twl->otg.set_host = twl6030_set_host;
+ twl->otg.set_peripheral = twl6030_set_peripheral;
+ twl->otg.set_vbus = twl6030_set_vbus;
+ twl->otg.init = twl6030_phy_init;
+ twl->otg.shutdown = twl6030_phy_shutdown;
+
+ /* init spinlock for workqueue */
+ spin_lock_init(&twl->lock);
+
+ err = twl6030_usb_ldo_init(twl);
+ if (err) {
+ dev_err(&pdev->dev, "ldo init failed\n");
+ kfree(twl);
+ return err;
+ }
+ otg_set_transceiver(&twl->otg);
+
+ platform_set_drvdata(pdev, twl);
+ if (device_create_file(&pdev->dev, &dev_attr_vbus))
+ dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+
+ twl->irq_enabled = true;
+ status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "twl6030_usb", twl);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ twl->irq1, status);
+ device_remove_file(twl->dev, &dev_attr_vbus);
+ kfree(twl);
+ return status;
+ }
+
+ status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "twl6030_usb", twl);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ twl->irq2, status);
+ free_irq(twl->irq1, twl);
+ device_remove_file(twl->dev, &dev_attr_vbus);
+ kfree(twl);
+ return status;
+ }
+
+ pdata->phy_init(dev);
+ twl6030_enable_irq(&twl->otg);
+ dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
+
+ return 0;
+}
+
+static int __exit twl6030_usb_remove(struct platform_device *pdev)
+{
+ struct twl6030_usb *twl = platform_get_drvdata(pdev);
+
+ struct twl4030_usb_data *pdata;
+ struct device *dev = &pdev->dev;
+ pdata = dev->platform_data;
+
+ twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
+ REG_INT_MSK_LINE_C);
+ twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
+ REG_INT_MSK_STS_C);
+ free_irq(twl->irq1, twl);
+ free_irq(twl->irq2, twl);
+ regulator_put(twl->usb3v3);
+ pdata->phy_exit(twl->dev);
+ device_remove_file(twl->dev, &dev_attr_vbus);
+ kfree(twl);
+
+ return 0;
+}
+
+static struct platform_driver twl6030_usb_driver = {
+ .probe = twl6030_usb_probe,
+ .remove = __exit_p(twl6030_usb_remove),
+ .driver = {
+ .name = "twl6030_usb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init twl6030_usb_init(void)
+{
+ return platform_driver_register(&twl6030_usb_driver);
+}
+subsys_initcall(twl6030_usb_init);
+
+static void __exit twl6030_usb_exit(void)
+{
+ platform_driver_unregister(&twl6030_usb_driver);
+}
+module_exit(twl6030_usb_exit);
+
+MODULE_ALIAS("platform:twl6030_usb");
+MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
+MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 89a9a5847803..a2668d089260 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -75,6 +75,7 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ char transmit_empty; /* If transmitter is empty or not */
struct usb_serial_port *port;
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
@@ -201,6 +202,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
+ { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
@@ -696,6 +698,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
@@ -794,6 +797,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
+ { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -1318,6 +1324,23 @@ check_and_exit:
return 0;
}
+static int get_lsr_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ unsigned int result = 0;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (priv->transmit_empty)
+ result = TIOCSER_TEMT;
+
+ if (copy_to_user(retinfo, &result, sizeof(unsigned int)))
+ return -EFAULT;
+ return 0;
+}
+
/* Determine type of FTDI chip based on USB config and descriptor. */
static void ftdi_determine_type(struct usb_serial_port *port)
@@ -1867,6 +1890,12 @@ static int ftdi_process_packet(struct tty_struct *tty,
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
+ /* save if the transmitter is empty or not */
+ if (packet[1] & FTDI_RS_TEMT)
+ priv->transmit_empty = 1;
+ else
+ priv->transmit_empty = 0;
+
len -= 2;
if (!len)
return 0; /* status only */
@@ -2230,6 +2259,9 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
}
}
return 0;
+ case TIOCSERGETLSR:
+ return get_lsr_info(port, (struct serial_struct __user *)arg);
+ break;
default:
break;
}
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 7dfe02f1fb6a..bf0867285481 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -114,6 +114,9 @@
/* Lenz LI-USB Computer Interface. */
#define FTDI_LENZ_LIUSB_PID 0xD780
+/* Vardaan Enterprises Serial Interface VEUSB422R3 */
+#define FTDI_VARDAAN_PID 0xF070
+
/*
* Xsens Technologies BV products (http://www.xsens.com).
*/
@@ -721,6 +724,7 @@
*/
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
+#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
@@ -1077,6 +1081,11 @@
#define MJSG_HD_RADIO_PID 0x937C
/*
+ * D.O.Tec products (http://www.directout.eu)
+ */
+#define FTDI_DOTEC_PID 0x9868
+
+/*
* Xverve Signalyzer tools (http://www.signalyzer.com/)
*/
#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
@@ -1100,3 +1109,10 @@
#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18
#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C
#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
+
+/*
+ * Milkymist One JTAG/Serial
+ */
+#define QIHARDWARE_VID 0x20B7
+#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
+
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2297fb1bcf65..748778288d94 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -518,7 +518,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
@@ -615,7 +615,6 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) },
@@ -989,6 +988,7 @@ static struct usb_serial_driver option_1port_device = {
.set_termios = usb_wwan_set_termios,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
+ .ioctl = usb_wwan_ioctl,
.attach = usb_wwan_startup,
.disconnect = usb_wwan_disconnect,
.release = usb_wwan_release,
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index e199b0f4f99c..5be866bb7a41 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -613,9 +613,8 @@ static void oti6858_close(struct usb_serial_port *port)
dbg("%s(): after buf_clear()", __func__);
/* cancel scheduled setup */
- cancel_delayed_work(&priv->delayed_setup_work);
- cancel_delayed_work(&priv->delayed_write_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&priv->delayed_setup_work);
+ cancel_delayed_work_sync(&priv->delayed_write_work);
/* shutdown our urbs */
dbg("%s(): shutting down urbs", __func__);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index f5312dd3331b..8359ec798959 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -79,7 +79,6 @@ struct ssu100_port_private {
u8 shadowLSR;
u8 shadowMSR;
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- unsigned short max_packet_size;
struct async_icount icount;
};
@@ -464,36 +463,6 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
-static void ssu100_set_max_packet_size(struct usb_serial_port *port)
-{
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct usb_serial *serial = port->serial;
- struct usb_device *udev = serial->dev;
-
- struct usb_interface *interface = serial->interface;
- struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
-
- unsigned num_endpoints;
- int i;
- unsigned long flags;
-
- num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
- dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
-
- for (i = 0; i < num_endpoints; i++) {
- dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
- interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
- ep_desc = &interface->cur_altsetting->endpoint[i].desc;
- }
-
- /* set max packet size based on descriptor */
- spin_lock_irqsave(&priv->status_lock, flags);
- priv->max_packet_size = ep_desc->wMaxPacketSize;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
-}
-
static int ssu100_attach(struct usb_serial *serial)
{
struct ssu100_port_private *priv;
@@ -511,7 +480,6 @@ static int ssu100_attach(struct usb_serial *serial)
spin_lock_init(&priv->status_lock);
init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
- ssu100_set_max_packet_size(port);
return ssu100_initdevice(serial->dev);
}
@@ -641,13 +609,14 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
}
-static int ssu100_process_packet(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ssu100_port_private *priv,
- char *packet, int len)
+static int ssu100_process_packet(struct urb *urb,
+ struct tty_struct *tty)
{
- int i;
+ struct usb_serial_port *port = urb->context;
+ char *packet = (char *)urb->transfer_buffer;
char flag = TTY_NORMAL;
+ u32 len = urb->actual_length;
+ int i;
char *ch;
dbg("%s - port %d", __func__, port->number);
@@ -685,12 +654,8 @@ static int ssu100_process_packet(struct tty_struct *tty,
static void ssu100_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- char *data = (char *)urb->transfer_buffer;
struct tty_struct *tty;
- int count = 0;
- int i;
- int len;
+ int count;
dbg("%s", __func__);
@@ -698,10 +663,7 @@ static void ssu100_process_read_urb(struct urb *urb)
if (!tty)
return;
- for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
- len = min_t(int, urb->actual_length - i, priv->max_packet_size);
- count += ssu100_process_packet(tty, port, priv, &data[i], len);
- }
+ count = ssu100_process_packet(urb, tty);
if (count)
tty_flip_buffer_push(tty);
@@ -717,8 +679,6 @@ static struct usb_serial_driver ssu100_device = {
.id_table = id_table,
.usb_driver = &ssu100_driver,
.num_ports = 1,
- .bulk_in_size = 256,
- .bulk_out_size = 256,
.open = ssu100_open,
.close = ssu100_close,
.attach = ssu100_attach,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index e64da74bdcc5..6954de50c0ff 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
@@ -52,6 +51,7 @@ static struct usb_driver usb_serial_driver = {
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.no_dynamic_id = 1,
+ .supports_autosuspend = 1,
};
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
@@ -1344,6 +1344,8 @@ int usb_serial_register(struct usb_serial_driver *driver)
return -ENODEV;
fixup_generic(driver);
+ if (driver->usb_driver)
+ driver->usb_driver->supports_autosuspend = 1;
if (!driver->description)
driver->description = driver->driver.name;
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index 2be298a1305b..3ab77c5d9819 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -18,6 +18,8 @@ extern void usb_wwan_set_termios(struct tty_struct *tty,
extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file);
extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
+extern int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg);
extern int usb_wwan_send_setup(struct usb_serial_port *port);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index fbc946797801..b004b2a485c3 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -31,8 +31,10 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/serial.h>
#include "usb-wwan.h"
static int debug;
@@ -123,6 +125,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
}
EXPORT_SYMBOL(usb_wwan_tiocmset);
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = port->number;
+ tmp.baud_base = tty_get_baud_rate(port->port.tty);
+ tmp.close_delay = port->port.close_delay / 10;
+ tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE :
+ port->port.closing_wait / 10;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *newinfo)
+{
+ struct serial_struct new_serial;
+ unsigned int closing_wait, close_delay;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ close_delay = new_serial.close_delay * 10;
+ closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+ mutex_lock(&port->port.mutex);
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((close_delay != port->port.close_delay) ||
+ (closing_wait != port->port.closing_wait))
+ retval = -EPERM;
+ else
+ retval = -EOPNOTSUPP;
+ } else {
+ port->port.close_delay = close_delay;
+ port->port.closing_wait = closing_wait;
+ }
+
+ mutex_unlock(&port->port.mutex);
+ return retval;
+}
+
+int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ dbg("%s cmd 0x%04x", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(port,
+ (struct serial_struct __user *) arg);
+ default:
+ break;
+ }
+
+ dbg("%s arg not supported", __func__);
+
+ return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(usb_wwan_ioctl);
+
/* Write */
int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a688b1e686ea..689ee1fb702a 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,7 +285,7 @@ static int slave_configure(struct scsi_device *sdev)
/* queue a command */
/* This is always called with scsi_lock(host) held */
-static int queuecommand(struct scsi_cmnd *srb,
+static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
@@ -315,6 +315,8 @@ static int queuecommand(struct scsi_cmnd *srb,
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
index 57fc2f532cab..ceba512f84d0 100644
--- a/drivers/usb/storage/sierra_ms.c
+++ b/drivers/usb/storage/sierra_ms.c
@@ -121,7 +121,7 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
}
return result;
}
-static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
+static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL);
int sierra_ms_init(struct us_data *us)
{
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 2054b1e25a65..23f0dd9c36d4 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -49,14 +49,17 @@ struct command_iu {
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
};
+/*
+ * Also used for the Read Ready and Write Ready IUs since they have the
+ * same first four bytes
+ */
struct sense_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__be16 status_qual;
__u8 status;
- __u8 service_response;
- __u8 rsvd8[6];
+ __u8 rsvd7[7];
__be16 len;
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
@@ -97,8 +100,8 @@ struct uas_dev_info {
};
enum {
- ALLOC_SENSE_URB = (1 << 0),
- SUBMIT_SENSE_URB = (1 << 1),
+ ALLOC_STATUS_URB = (1 << 0),
+ SUBMIT_STATUS_URB = (1 << 1),
ALLOC_DATA_IN_URB = (1 << 2),
SUBMIT_DATA_IN_URB = (1 << 3),
ALLOC_DATA_OUT_URB = (1 << 4),
@@ -112,7 +115,7 @@ struct uas_cmd_info {
unsigned int state;
unsigned int stream;
struct urb *cmd_urb;
- struct urb *sense_urb;
+ struct urb *status_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
struct list_head list;
@@ -138,7 +141,7 @@ static void uas_do_work(struct work_struct *work)
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
- uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_KERNEL);
+ uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
}
}
@@ -204,7 +207,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err;
- cmdinfo->state = direction | SUBMIT_SENSE_URB;
+ cmdinfo->state = direction | SUBMIT_STATUS_URB;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
spin_lock(&uas_work_lock);
@@ -294,7 +297,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
if (!urb)
goto out;
- iu = kmalloc(sizeof(*iu), gfp);
+ iu = kzalloc(sizeof(*iu), gfp);
if (!iu)
goto free;
@@ -325,16 +328,13 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
if (len < 0)
len = 0;
len = ALIGN(len, 4);
- iu = kmalloc(sizeof(*iu) + len, gfp);
+ iu = kzalloc(sizeof(*iu) + len, gfp);
if (!iu)
goto free;
iu->iu_id = IU_ID_COMMAND;
iu->tag = cpu_to_be16(stream_id);
- if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER))
- iu->prio_attr = UAS_ORDERED_TAG;
- else
- iu->prio_attr = UAS_SIMPLE_TAG;
+ iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
@@ -360,21 +360,21 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
{
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
- if (cmdinfo->state & ALLOC_SENSE_URB) {
- cmdinfo->sense_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
- cmdinfo->stream);
- if (!cmdinfo->sense_urb)
+ if (cmdinfo->state & ALLOC_STATUS_URB) {
+ cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
+ cmdinfo->stream);
+ if (!cmdinfo->status_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
- cmdinfo->state &= ~ALLOC_SENSE_URB;
+ cmdinfo->state &= ~ALLOC_STATUS_URB;
}
- if (cmdinfo->state & SUBMIT_SENSE_URB) {
- if (usb_submit_urb(cmdinfo->sense_urb, gfp)) {
+ if (cmdinfo->state & SUBMIT_STATUS_URB) {
+ if (usb_submit_urb(cmdinfo->status_urb, gfp)) {
scmd_printk(KERN_INFO, cmnd,
"sense urb submission failure\n");
return SCSI_MLQUEUE_DEVICE_BUSY;
}
- cmdinfo->state &= ~SUBMIT_SENSE_URB;
+ cmdinfo->state &= ~SUBMIT_STATUS_URB;
}
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
@@ -433,7 +433,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
return 0;
}
-static int uas_queuecommand(struct scsi_cmnd *cmnd,
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmnd->device;
@@ -443,7 +443,7 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
- if (!cmdinfo->sense_urb && sdev->current_cmnd)
+ if (!cmdinfo->status_urb && sdev->current_cmnd)
return SCSI_MLQUEUE_DEVICE_BUSY;
if (blk_rq_tagged(cmnd->request)) {
@@ -455,7 +455,7 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
cmnd->scsi_done = done;
- cmdinfo->state = ALLOC_SENSE_URB | SUBMIT_SENSE_URB |
+ cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB |
ALLOC_CMD_URB | SUBMIT_CMD_URB;
switch (cmnd->sc_data_direction) {
@@ -478,8 +478,8 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
if (err) {
/* If we did nothing, give up now */
- if (cmdinfo->state & SUBMIT_SENSE_URB) {
- usb_free_urb(cmdinfo->sense_urb);
+ if (cmdinfo->state & SUBMIT_STATUS_URB) {
+ usb_free_urb(cmdinfo->status_urb);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
spin_lock(&uas_work_lock);
@@ -491,6 +491,8 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
return 0;
}
+static DEF_SCSI_QCMD(uas_queuecommand)
+
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
{
struct scsi_device *sdev = cmnd->device;
@@ -579,6 +581,34 @@ static struct usb_device_id uas_usb_ids[] = {
};
MODULE_DEVICE_TABLE(usb, uas_usb_ids);
+static int uas_is_interface(struct usb_host_interface *intf)
+{
+ return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
+ intf->desc.bInterfaceProtocol == USB_PR_UAS);
+}
+
+static int uas_switch_interface(struct usb_device *udev,
+ struct usb_interface *intf)
+{
+ int i;
+
+ if (uas_is_interface(intf->cur_altsetting))
+ return 0;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ struct usb_host_interface *alt = &intf->altsetting[i];
+ if (alt == intf->cur_altsetting)
+ continue;
+ if (uas_is_interface(alt))
+ return usb_set_interface(udev,
+ alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return -ENODEV;
+}
+
static void uas_configure_endpoints(struct uas_dev_info *devinfo)
{
struct usb_host_endpoint *eps[4] = { };
@@ -652,13 +682,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct uas_dev_info *devinfo;
struct usb_device *udev = interface_to_usbdev(intf);
- if (id->bInterfaceProtocol == 0x50) {
- int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-/* XXX: Shouldn't assume that 1 is the alternative we want */
- int ret = usb_set_interface(udev, ifnum, 1);
- if (ret)
- return -ENODEV;
- }
+ if (uas_switch_interface(udev, intf))
+ return -ENODEV;
devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
if (!devinfo)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 6ccdd3dd5259..fcc1e32ce256 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -481,6 +481,13 @@ UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64),
+/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */
+UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999,
+ "Samsung",
+ "YP-CP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Device uses standards-violating 32-byte Bulk Command Block Wrappers and
* reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index c7b1d8108de9..8cb9d80207fa 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -49,7 +49,7 @@
*
* USB Stack port number 4 (1 based)
* WUSB code port index 3 (0 based)
- * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub)
+ * USB Address 5 (2 based -- 0 is for default, 1 for root hub)
*
* Now, because we don't use the concept as default address exactly
* like the (wired) USB code does, we need to kind of skip it. So we
diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c
index 436e4f7110cb..e45e673b8770 100644
--- a/drivers/uwb/allocator.c
+++ b/drivers/uwb/allocator.c
@@ -326,7 +326,8 @@ int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *availab
int bit_index;
ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
-
+ if (!ai)
+ return UWB_RSV_ALLOC_NOT_FOUND;
ai->min_mas = rsv->min_mas;
ai->max_mas = rsv->max_mas;
ai->max_interval = rsv->max_interval;
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c
index f2eb4d8b76c9..d5de5e131d47 100644
--- a/drivers/uwb/i1480/i1480-est.c
+++ b/drivers/uwb/i1480/i1480-est.c
@@ -91,7 +91,7 @@ MODULE_LICENSE("GPL");
*
* [so we are loaded when this kind device is connected]
*/
-static struct usb_device_id i1480_est_id_table[] = {
+static struct usb_device_id __used i1480_est_id_table[] = {
{ USB_DEVICE(0x8086, 0xdf3b), },
{ USB_DEVICE(0x8086, 0x0c3b), },
{ },
diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c
index 43ea9982e687..ccd2184e05d2 100644
--- a/drivers/uwb/umc-dev.c
+++ b/drivers/uwb/umc-dev.c
@@ -54,11 +54,8 @@ int umc_device_register(struct umc_dev *umc)
err = request_resource(umc->resource.parent, &umc->resource);
if (err < 0) {
- dev_err(&umc->dev, "can't allocate resource range "
- "%016Lx to %016Lx: %d\n",
- (unsigned long long)umc->resource.start,
- (unsigned long long)umc->resource.end,
- err);
+ dev_err(&umc->dev, "can't allocate resource range %pR: %d\n",
+ &umc->resource, err);
goto error_request_resource;
}
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c
index 73495583c444..70a004aa19db 100644
--- a/drivers/uwb/whc-rc.c
+++ b/drivers/uwb/whc-rc.c
@@ -449,7 +449,7 @@ static int whcrc_post_reset(struct umc_dev *umc)
}
/* PCI device ID's that we handle [so it gets loaded] */
-static struct pci_device_id whcrc_id_table[] = {
+static struct pci_device_id __used whcrc_id_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
{ /* empty last entry */ }
};
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 4b4da5b86ff9..9b3ca103135f 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -10,7 +10,6 @@
#include <linux/eventfd.h>
#include <linux/vhost.h>
#include <linux/virtio_net.h>
-#include <linux/mmu_context.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -129,8 +128,9 @@ static void handle_tx(struct vhost_net *net)
size_t hdr_size;
struct socket *sock;
- sock = rcu_dereference_check(vq->private_data,
- lockdep_is_held(&vq->mutex));
+ /* TODO: check that we are running from vhost_worker?
+ * Not sure it's worth it, it's straight-forward enough. */
+ sock = rcu_dereference_check(vq->private_data, 1);
if (!sock)
return;
@@ -142,7 +142,6 @@ static void handle_tx(struct vhost_net *net)
return;
}
- use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
@@ -207,7 +206,6 @@ static void handle_tx(struct vhost_net *net)
}
mutex_unlock(&vq->mutex);
- unuse_mm(net->dev.mm);
}
static int peek_head_len(struct sock *sk)
@@ -312,7 +310,6 @@ static void handle_rx_big(struct vhost_net *net)
if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
return;
- use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
hdr_size = vq->vhost_hlen;
@@ -391,7 +388,6 @@ static void handle_rx_big(struct vhost_net *net)
}
mutex_unlock(&vq->mutex);
- unuse_mm(net->dev.mm);
}
/* Expects to be always run from workqueue - which acts as
@@ -423,7 +419,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
return;
- use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
vhost_hlen = vq->vhost_hlen;
@@ -458,7 +453,7 @@ static void handle_rx_mergeable(struct vhost_net *net)
move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
else
/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
- * needed because sendmsg can modify msg_iov. */
+ * needed because recvmsg can modify msg_iov. */
copy_iovec_hdr(vq->iov, vq->hdr, sock_hlen, in);
msg.msg_iovlen = in;
err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -500,7 +495,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
}
mutex_unlock(&vq->mutex);
- unuse_mm(net->dev.mm);
}
static void handle_rx(struct vhost_net *net)
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
new file mode 100644
index 000000000000..099f30230d06
--- /dev/null
+++ b/drivers/vhost/test.c
@@ -0,0 +1,320 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * test virtio server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+
+#include "test.h"
+#include "vhost.c"
+
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_TEST_WEIGHT 0x80000
+
+enum {
+ VHOST_TEST_VQ = 0,
+ VHOST_TEST_VQ_MAX = 1,
+};
+
+struct vhost_test {
+ struct vhost_dev dev;
+ struct vhost_virtqueue vqs[VHOST_TEST_VQ_MAX];
+};
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_vq(struct vhost_test *n)
+{
+ struct vhost_virtqueue *vq = &n->dev.vqs[VHOST_TEST_VQ];
+ unsigned out, in;
+ int head;
+ size_t len, total_len = 0;
+ void *private;
+
+ private = rcu_dereference_check(vq->private_data, 1);
+ if (!private)
+ return;
+
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+
+ for (;;) {
+ head = vhost_get_vq_desc(&n->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ NULL, NULL);
+ /* On error, stop handling until the next kick. */
+ if (unlikely(head < 0))
+ break;
+ /* Nothing new? Wait for eventfd to tell us they refilled. */
+ if (head == vq->num) {
+ if (unlikely(vhost_enable_notify(vq))) {
+ vhost_disable_notify(vq);
+ continue;
+ }
+ break;
+ }
+ if (in) {
+ vq_err(vq, "Unexpected descriptor format for TX: "
+ "out %d, int %d\n", out, in);
+ break;
+ }
+ len = iov_length(vq->iov, out);
+ /* Sanity check */
+ if (!len) {
+ vq_err(vq, "Unexpected 0 len for TX\n");
+ break;
+ }
+ vhost_add_used_and_signal(&n->dev, vq, head, 0);
+ total_len += len;
+ if (unlikely(total_len >= VHOST_TEST_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+}
+
+static void handle_vq_kick(struct vhost_work *work)
+{
+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+ poll.work);
+ struct vhost_test *n = container_of(vq->dev, struct vhost_test, dev);
+
+ handle_vq(n);
+}
+
+static int vhost_test_open(struct inode *inode, struct file *f)
+{
+ struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL);
+ struct vhost_dev *dev;
+ int r;
+
+ if (!n)
+ return -ENOMEM;
+
+ dev = &n->dev;
+ n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
+ r = vhost_dev_init(dev, n->vqs, VHOST_TEST_VQ_MAX);
+ if (r < 0) {
+ kfree(n);
+ return r;
+ }
+
+ f->private_data = n;
+
+ return 0;
+}
+
+static void *vhost_test_stop_vq(struct vhost_test *n,
+ struct vhost_virtqueue *vq)
+{
+ void *private;
+
+ mutex_lock(&vq->mutex);
+ private = rcu_dereference_protected(vq->private_data,
+ lockdep_is_held(&vq->mutex));
+ rcu_assign_pointer(vq->private_data, NULL);
+ mutex_unlock(&vq->mutex);
+ return private;
+}
+
+static void vhost_test_stop(struct vhost_test *n, void **privatep)
+{
+ *privatep = vhost_test_stop_vq(n, n->vqs + VHOST_TEST_VQ);
+}
+
+static void vhost_test_flush_vq(struct vhost_test *n, int index)
+{
+ vhost_poll_flush(&n->dev.vqs[index].poll);
+}
+
+static void vhost_test_flush(struct vhost_test *n)
+{
+ vhost_test_flush_vq(n, VHOST_TEST_VQ);
+}
+
+static int vhost_test_release(struct inode *inode, struct file *f)
+{
+ struct vhost_test *n = f->private_data;
+ void *private;
+
+ vhost_test_stop(n, &private);
+ vhost_test_flush(n);
+ vhost_dev_cleanup(&n->dev);
+ /* We do an extra flush before freeing memory,
+ * since jobs can re-queue themselves. */
+ vhost_test_flush(n);
+ kfree(n);
+ return 0;
+}
+
+static long vhost_test_run(struct vhost_test *n, int test)
+{
+ void *priv, *oldpriv;
+ struct vhost_virtqueue *vq;
+ int r, index;
+
+ if (test < 0 || test > 1)
+ return -EINVAL;
+
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_check_owner(&n->dev);
+ if (r)
+ goto err;
+
+ for (index = 0; index < n->dev.nvqs; ++index) {
+ /* Verify that ring has been setup correctly. */
+ if (!vhost_vq_access_ok(&n->vqs[index])) {
+ r = -EFAULT;
+ goto err;
+ }
+ }
+
+ for (index = 0; index < n->dev.nvqs; ++index) {
+ vq = n->vqs + index;
+ mutex_lock(&vq->mutex);
+ priv = test ? n : NULL;
+
+ /* start polling new socket */
+ oldpriv = rcu_dereference_protected(vq->private_data,
+ lockdep_is_held(&vq->mutex));
+ rcu_assign_pointer(vq->private_data, priv);
+
+ mutex_unlock(&vq->mutex);
+
+ if (oldpriv) {
+ vhost_test_flush_vq(n, index);
+ }
+ }
+
+ mutex_unlock(&n->dev.mutex);
+ return 0;
+
+err:
+ mutex_unlock(&n->dev.mutex);
+ return r;
+}
+
+static long vhost_test_reset_owner(struct vhost_test *n)
+{
+ void *priv = NULL;
+ long err;
+ mutex_lock(&n->dev.mutex);
+ err = vhost_dev_check_owner(&n->dev);
+ if (err)
+ goto done;
+ vhost_test_stop(n, &priv);
+ vhost_test_flush(n);
+ err = vhost_dev_reset_owner(&n->dev);
+done:
+ mutex_unlock(&n->dev.mutex);
+ return err;
+}
+
+static int vhost_test_set_features(struct vhost_test *n, u64 features)
+{
+ mutex_lock(&n->dev.mutex);
+ if ((features & (1 << VHOST_F_LOG_ALL)) &&
+ !vhost_log_access_ok(&n->dev)) {
+ mutex_unlock(&n->dev.mutex);
+ return -EFAULT;
+ }
+ n->dev.acked_features = features;
+ smp_wmb();
+ vhost_test_flush(n);
+ mutex_unlock(&n->dev.mutex);
+ return 0;
+}
+
+static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct vhost_test *n = f->private_data;
+ void __user *argp = (void __user *)arg;
+ u64 __user *featurep = argp;
+ int test;
+ u64 features;
+ int r;
+ switch (ioctl) {
+ case VHOST_TEST_RUN:
+ if (copy_from_user(&test, argp, sizeof test))
+ return -EFAULT;
+ return vhost_test_run(n, test);
+ case VHOST_GET_FEATURES:
+ features = VHOST_FEATURES;
+ if (copy_to_user(featurep, &features, sizeof features))
+ return -EFAULT;
+ return 0;
+ case VHOST_SET_FEATURES:
+ if (copy_from_user(&features, featurep, sizeof features))
+ return -EFAULT;
+ if (features & ~VHOST_FEATURES)
+ return -EOPNOTSUPP;
+ return vhost_test_set_features(n, features);
+ case VHOST_RESET_OWNER:
+ return vhost_test_reset_owner(n);
+ default:
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_ioctl(&n->dev, ioctl, arg);
+ vhost_test_flush(n);
+ mutex_unlock(&n->dev.mutex);
+ return r;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_test_compat_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ return vhost_test_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations vhost_test_fops = {
+ .owner = THIS_MODULE,
+ .release = vhost_test_release,
+ .unlocked_ioctl = vhost_test_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vhost_test_compat_ioctl,
+#endif
+ .open = vhost_test_open,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice vhost_test_misc = {
+ MISC_DYNAMIC_MINOR,
+ "vhost-test",
+ &vhost_test_fops,
+};
+
+static int vhost_test_init(void)
+{
+ return misc_register(&vhost_test_misc);
+}
+module_init(vhost_test_init);
+
+static void vhost_test_exit(void)
+{
+ misc_deregister(&vhost_test_misc);
+}
+module_exit(vhost_test_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel side for virtio simulator");
diff --git a/drivers/vhost/test.h b/drivers/vhost/test.h
new file mode 100644
index 000000000000..1fef5df82153
--- /dev/null
+++ b/drivers/vhost/test.h
@@ -0,0 +1,7 @@
+#ifndef LINUX_VHOST_TEST_H
+#define LINUX_VHOST_TEST_H
+
+/* Start a given test on the virtio null device. 0 stops all tests. */
+#define VHOST_TEST_RUN _IOW(VHOST_VIRTIO, 0x31, int)
+
+#endif
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 94701ff3a23a..ade0568c07a4 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -15,6 +15,7 @@
#include <linux/vhost.h>
#include <linux/virtio_net.h>
#include <linux/mm.h>
+#include <linux/mmu_context.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/rcupdate.h>
@@ -29,8 +30,6 @@
#include <linux/if_packet.h>
#include <linux/if_arp.h>
-#include <net/sock.h>
-
#include "vhost.h"
enum {
@@ -98,22 +97,26 @@ void vhost_poll_stop(struct vhost_poll *poll)
remove_wait_queue(poll->wqh, &poll->wait);
}
+static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
+ unsigned seq)
+{
+ int left;
+ spin_lock_irq(&dev->work_lock);
+ left = seq - work->done_seq;
+ spin_unlock_irq(&dev->work_lock);
+ return left <= 0;
+}
+
static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
{
unsigned seq;
- int left;
int flushing;
spin_lock_irq(&dev->work_lock);
seq = work->queue_seq;
work->flushing++;
spin_unlock_irq(&dev->work_lock);
- wait_event(work->done, ({
- spin_lock_irq(&dev->work_lock);
- left = seq - work->done_seq <= 0;
- spin_unlock_irq(&dev->work_lock);
- left;
- }));
+ wait_event(work->done, vhost_work_seq_done(dev, work, seq));
spin_lock_irq(&dev->work_lock);
flushing = --work->flushing;
spin_unlock_irq(&dev->work_lock);
@@ -157,7 +160,6 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->avail_idx = 0;
vq->last_used_idx = 0;
vq->used_flags = 0;
- vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
vq->vhost_hlen = 0;
@@ -178,6 +180,8 @@ static int vhost_worker(void *data)
struct vhost_work *work = NULL;
unsigned uninitialized_var(seq);
+ use_mm(dev->mm);
+
for (;;) {
/* mb paired w/ kthread_stop */
set_current_state(TASK_INTERRUPTIBLE);
@@ -192,7 +196,7 @@ static int vhost_worker(void *data)
if (kthread_should_stop()) {
spin_unlock_irq(&dev->work_lock);
__set_current_state(TASK_RUNNING);
- return 0;
+ break;
}
if (!list_empty(&dev->work_list)) {
work = list_first_entry(&dev->work_list,
@@ -210,6 +214,8 @@ static int vhost_worker(void *data)
schedule();
}
+ unuse_mm(dev->mm);
+ return 0;
}
/* Helper to allocate iovec buffers for all vqs. */
@@ -402,15 +408,14 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
kfree(rcu_dereference_protected(dev->memory,
lockdep_is_held(&dev->mutex)));
RCU_INIT_POINTER(dev->memory, NULL);
- if (dev->mm)
- mmput(dev->mm);
- dev->mm = NULL;
-
WARN_ON(!list_empty(&dev->work_list));
if (dev->worker) {
kthread_stop(dev->worker);
dev->worker = NULL;
}
+ if (dev->mm)
+ mmput(dev->mm);
+ dev->mm = NULL;
}
static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
@@ -881,14 +886,15 @@ static int set_bit_to_user(int nr, void __user *addr)
static int log_write(void __user *log_base,
u64 write_address, u64 write_length)
{
+ u64 write_page = write_address / VHOST_PAGE_SIZE;
int r;
if (!write_length)
return 0;
- write_address /= VHOST_PAGE_SIZE;
+ write_length += write_address % VHOST_PAGE_SIZE;
for (;;) {
u64 base = (u64)(unsigned long)log_base;
- u64 log = base + write_address / 8;
- int bit = write_address % 8;
+ u64 log = base + write_page / 8;
+ int bit = write_page % 8;
if ((u64)(unsigned long)log != log)
return -EFAULT;
r = set_bit_to_user(bit, (void __user *)(unsigned long)log);
@@ -897,7 +903,7 @@ static int log_write(void __user *log_base,
if (write_length <= VHOST_PAGE_SIZE)
break;
write_length -= VHOST_PAGE_SIZE;
- write_address += VHOST_PAGE_SIZE;
+ write_page += 1;
}
return r;
}
@@ -1092,7 +1098,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
/* Check it isn't doing very strange things with descriptor numbers. */
last_avail_idx = vq->last_avail_idx;
- if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) {
+ if (unlikely(__get_user(vq->avail_idx, &vq->avail->idx))) {
vq_err(vq, "Failed to access avail idx at %p\n",
&vq->avail->idx);
return -EFAULT;
@@ -1113,8 +1119,8 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
/* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */
- if (unlikely(get_user(head,
- &vq->avail->ring[last_avail_idx % vq->num]))) {
+ if (unlikely(__get_user(head,
+ &vq->avail->ring[last_avail_idx % vq->num]))) {
vq_err(vq, "Failed to read head: idx %d address %p\n",
last_avail_idx,
&vq->avail->ring[last_avail_idx % vq->num]);
@@ -1213,17 +1219,17 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
/* The virtqueue contains a ring of used buffers. Get a pointer to the
* next entry in that used ring. */
used = &vq->used->ring[vq->last_used_idx % vq->num];
- if (put_user(head, &used->id)) {
+ if (__put_user(head, &used->id)) {
vq_err(vq, "Failed to write used id");
return -EFAULT;
}
- if (put_user(len, &used->len)) {
+ if (__put_user(len, &used->len)) {
vq_err(vq, "Failed to write used len");
return -EFAULT;
}
/* Make sure buffer is written before we update index. */
smp_wmb();
- if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ if (__put_user(vq->last_used_idx + 1, &vq->used->idx)) {
vq_err(vq, "Failed to increment used idx");
return -EFAULT;
}
@@ -1255,7 +1261,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
start = vq->last_used_idx % vq->num;
used = vq->used->ring + start;
- if (copy_to_user(used, heads, count * sizeof *used)) {
+ if (__copy_to_user(used, heads, count * sizeof *used)) {
vq_err(vq, "Failed to write used");
return -EFAULT;
}
@@ -1316,7 +1322,7 @@ void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
* interrupts. */
smp_mb();
- if (get_user(flags, &vq->avail->flags)) {
+ if (__get_user(flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return;
}
@@ -1367,7 +1373,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
/* They could have slipped one in as we were doing that: make
* sure it's written, then check again. */
smp_mb();
- r = get_user(avail_idx, &vq->avail->idx);
+ r = __get_user(avail_idx, &vq->avail->idx);
if (r) {
vq_err(vq, "Failed to check avail idx at %p: %d\n",
&vq->avail->idx, r);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 073d06ae091f..2af44b7b1f3f 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -102,7 +102,7 @@ struct vhost_virtqueue {
* flush the vhost_work instead of synchronize_rcu. Therefore readers do
* not need to call rcu_read_lock/rcu_read_unlock: the beginning of
* vhost_work execution acts instead of rcu_read_lock() and the end of
- * vhost_work execution acts instead of rcu_read_lock().
+ * vhost_work execution acts instead of rcu_read_unlock().
* Writers use virtqueue mutex. */
void __rcu *private_data;
/* Log write descriptors */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4b1e0d..d916ac04abab 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -11,6 +11,13 @@ config HAVE_FB_ATMEL
config HAVE_FB_IMX
bool
+config SH_MIPI_DSI
+ tristate
+ depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+
+config SH_LCD_MIPI_DSI
+ bool
+
source "drivers/char/agp/Kconfig"
source "drivers/gpu/vga/Kconfig"
@@ -186,6 +193,14 @@ config FB_SYS_FOPS
depends on FB
default n
+config FB_WMT_GE_ROPS
+ tristate
+ depends on FB
+ default n
+ ---help---
+ Include functions for accelerated rectangle filling and area
+ copying using WonderMedia Graphics Engine operations.
+
config FB_DEFERRED_IO
bool
depends on FB
@@ -406,7 +421,7 @@ config FB_SA1100
Y here.
config FB_IMX
- tristate "Motorola i.MX LCD support"
+ tristate "Freescale i.MX LCD support"
depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -635,6 +650,72 @@ config FB_BFIN_LQ035Q1
To compile this driver as a module, choose M here: the
module will be called bfin-lq035q1-fb.
+config FB_BF537_LQ035
+ tristate "SHARP LQ035 TFT LCD (BF537 STAMP)"
+ depends on FB && (BF534 || BF536 || BF537) && I2C_BLACKFIN_TWI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select BFIN_GPTIMERS
+ help
+ This is the framebuffer device for a SHARP LQ035Q7DB03 TFT LCD
+ attached to a BF537.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bf537-lq035.
+
+config FB_BFIN_7393
+ tristate "Blackfin ADV7393 Video encoder"
+ depends on FB && BLACKFIN
+ select I2C
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer device for a ADV7393 video encoder
+ attached to a Blackfin on the PPI port.
+ If your Blackfin board has a ADV7393 select Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_adv7393fb.
+
+choice
+ prompt "Video mode support"
+ depends on FB_BFIN_7393
+ default NTSC
+
+config NTSC
+ bool 'NTSC 720x480'
+
+config PAL
+ bool 'PAL 720x576'
+
+config NTSC_640x480
+ bool 'NTSC 640x480 (Experimental)'
+
+config PAL_640x480
+ bool 'PAL 640x480 (Experimental)'
+
+config NTSC_YCBCR
+ bool 'NTSC 720x480 YCbCR input'
+
+config PAL_YCBCR
+ bool 'PAL 720x576 YCbCR input'
+
+endchoice
+
+choice
+ prompt "Size of ADV7393 frame buffer memory Single/Double Size"
+ depends on (FB_BFIN_7393)
+ default ADV7393_1XMEM
+
+config ADV7393_1XMEM
+ bool 'Single'
+
+config ADV7393_2XMEM
+ bool 'Double'
+endchoice
+
config FB_STI
tristate "HP STI frame buffer device support"
depends on FB && PARISC
@@ -750,24 +831,14 @@ config FB_N411
config FB_HGA
tristate "Hercules mono graphics support"
depends on FB && X86
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
help
Say Y here if you have a Hercules mono graphics card.
To compile this driver as a module, choose M here: the
module will be called hgafb.
- As this card technology is 15 years old, most people will answer N
- here.
-
-config FB_HGA_ACCEL
- bool "Hercules mono Acceleration functions (EXPERIMENTAL)"
- depends on FB_HGA && EXPERIMENTAL
- ---help---
- This will compile the Hercules mono graphics with
- acceleration functions.
+ As this card technology is at least 25 years old,
+ most people will answer N here.
config FB_SGIVW
tristate "SGI Visual Workstation framebuffer support"
@@ -1209,7 +1280,7 @@ config FB_MATROX
module will be called matroxfb.
You can pass several parameters to the driver at boot time or at
- module load time. The parameters look like "video=matrox:XXX", and
+ module load time. The parameters look like "video=matroxfb:XXX", and
are described in <file:Documentation/fb/matroxfb.txt>.
config FB_MATROX_MILLENIUM
@@ -1722,6 +1793,24 @@ config FB_AU1200
various panels and CRTs by passing in kernel cmd line option
au1200fb:panel=<name>.
+config FB_VT8500
+ bool "VT8500 LCD Driver"
+ depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_VT8500
+ select FB_WMT_GE_ROPS
+ select FB_SYS_IMAGEBLIT
+ help
+ This is the framebuffer driver for VIA VT8500 integrated LCD
+ controller.
+
+config FB_WM8505
+ bool "WM8505 frame buffer support"
+ depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_WM8505
+ select FB_WMT_GE_ROPS
+ select FB_SYS_IMAGEBLIT
+ help
+ This is the framebuffer driver for WonderMedia WM8505
+ integrated LCD controller.
+
source "drivers/video/geode/Kconfig"
config FB_HIT
@@ -1850,6 +1939,16 @@ config FB_PXA_PARAMETERS
<file:Documentation/fb/pxafb.txt> describes the available parameters.
+config PXA3XX_GCU
+ tristate "PXA3xx 2D graphics accelerator driver"
+ depends on FB_PXA
+ help
+ Kernelspace driver for the 2D graphics controller unit (GCU)
+ found on PXA3xx processors. There is a counterpart driver in the
+ DirectFB suite, see http://www.directfb.org/
+
+ If you compile this as a module, it will be called pxa3xx_gcu.
+
config FB_MBX
tristate "2700G LCD framebuffer support"
depends on FB && ARCH_PXA
@@ -1898,13 +1997,6 @@ config FB_W100
If unsure, say N.
-config SH_MIPI_DSI
- tristate
- depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
-
-config SH_LCD_MIPI_DSI
- bool
-
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
@@ -2034,6 +2126,20 @@ config FB_SM501
If unsure, say N.
+config FB_UDL
+ tristate "Displaylink USB Framebuffer support"
+ depends on FB && USB
+ select FB_MODE_HELPERS
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ ---help---
+ This is a kernel framebuffer driver for DisplayLink USB devices.
+ Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
+ mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
+ To compile as a module, choose M here: the module name is udlfb.
config FB_PNX4008_DUM
tristate "Display Update Module support on Philips PNX4008 board"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed1318c..8c8fabdff9d0 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
+obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
@@ -100,10 +101,13 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
obj-$(CONFIG_FB_PXA) += pxafb.o
obj-$(CONFIG_FB_PXA168) += pxa168fb.o
+obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o
obj-$(CONFIG_FB_W100) += w100fb.o
obj-$(CONFIG_FB_TMIO) += tmiofb.o
obj-$(CONFIG_FB_AU1100) += au1100fb.o
obj-$(CONFIG_FB_AU1200) += au1200fb.o
+obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o
+obj-$(CONFIG_FB_WM8505) += wm8505fb.o
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
@@ -122,6 +126,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
+obj-$(CONFIG_FB_UDL) += udlfb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
@@ -141,9 +146,11 @@ obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
+obj-$(CONFIG_FB_BF537_LQ035) += bf537-lq035.o
obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o
obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
+obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8dce25126330..bac163450216 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -111,7 +111,7 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
}
-static struct backlight_ops atmel_lcdc_bl_ops = {
+static const struct backlight_ops atmel_lcdc_bl_ops = {
.update_status = atmel_bl_update_status,
.get_brightness = atmel_bl_get_brightness,
};
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 34a0851bcbfa..dd9de2e80580 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1786,7 +1786,7 @@ static int aty128_bl_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops aty128_bl_data = {
+static const struct backlight_ops aty128_bl_data = {
.get_brightness = aty128_bl_get_brightness,
.update_status = aty128_bl_update_status,
};
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 5bf91236c701..767ab4fb1a05 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2221,7 +2221,7 @@ static int aty_bl_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops aty_bl_data = {
+static const struct backlight_ops aty_bl_data = {
.get_brightness = aty_bl_get_brightness,
.update_status = aty_bl_update_status,
};
@@ -2969,10 +2969,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
{
struct atyfb_par *par = info->par;
struct device_node *dp;
- char prop[128];
- phandle node;
- int len, i, j, ret;
u32 mem, chip_id;
+ int i, j, ret;
/*
* Map memory-mapped registers.
@@ -3088,23 +3086,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
aty_st_le32(MEM_CNTL, mem, par);
}
- /*
- * If this is the console device, we will set default video
- * settings to what the PROM left us with.
- */
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "aliases");
- if (node) {
- len = prom_getproperty(node, "screen", prop, sizeof(prop));
- if (len > 0) {
- prop[len] = '\0';
- node = prom_finddevice(prop);
- } else
- node = 0;
- }
-
dp = pci_device_to_OF_node(pdev);
- if (node == dp->phandle) {
+ if (dp == of_console_device) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
@@ -3112,9 +3095,9 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
u8 pll_regs[16];
u8 clock_cntl;
- crtc.vxres = prom_getintdefault(node, "width", 1024);
- crtc.vyres = prom_getintdefault(node, "height", 768);
- var->bits_per_pixel = prom_getintdefault(node, "depth", 8);
+ crtc.vxres = of_getintprop_default(dp, "width", 1024);
+ crtc.vyres = of_getintprop_default(dp, "height", 768);
+ var->bits_per_pixel = of_getintprop_default(dp, "depth", 8);
var->xoffset = var->yoffset = 0;
crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 256966e9667d..9b811ddbce83 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -128,7 +128,7 @@ static int radeon_bl_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops radeon_bl_data = {
+static const struct backlight_ops radeon_bl_data = {
.get_brightness = radeon_bl_get_brightness,
.update_status = radeon_bl_update_status,
};
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 38ffc3fbcbe4..c789c46e38af 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -155,7 +155,7 @@ out:
return -EINVAL;
}
-static struct backlight_ops pm860x_backlight_ops = {
+static const struct backlight_ops pm860x_backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.update_status = pm860x_backlight_update_status,
.get_brightness = pm860x_backlight_get_brightness,
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 3ec24609151e..734c650a47c4 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -502,8 +502,10 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
+ int ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+ if (ret)
+ return ret;
- strict_strtoul(buf, 10, &data->cached_daylight_max);
return adp8860_store(dev, buf, count, ADP8860_BLMX1);
}
static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
@@ -614,7 +616,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
if (val == 0) {
/* Enable automatic ambient light sensing */
adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
- } else if ((val > 0) && (val < 6)) {
+ } else if ((val > 0) && (val <= 3)) {
/* Disable automatic ambient light sensing */
adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
@@ -622,7 +624,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
mutex_lock(&data->lock);
adp8860_read(data->client, ADP8860_CFGR, &reg_val);
reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
- reg_val |= val << CFGR_BLV_SHIFT;
+ reg_val |= (val - 1) << CFGR_BLV_SHIFT;
adp8860_write(data->client, ADP8860_CFGR, reg_val);
mutex_unlock(&data->lock);
}
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index e207810bba3c..08703299ef61 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -197,12 +197,12 @@ static int backlight_suspend(struct device *dev, pm_message_t state)
{
struct backlight_device *bd = to_backlight_device(dev);
- if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
- mutex_lock(&bd->ops_lock);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state |= BL_CORE_SUSPENDED;
backlight_update_status(bd);
- mutex_unlock(&bd->ops_lock);
}
+ mutex_unlock(&bd->ops_lock);
return 0;
}
@@ -211,12 +211,12 @@ static int backlight_resume(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
- if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
- mutex_lock(&bd->ops_lock);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state &= ~BL_CORE_SUSPENDED;
backlight_update_status(bd);
- mutex_unlock(&bd->ops_lock);
}
+ mutex_unlock(&bd->ops_lock);
return 0;
}
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index a4f4546f0be0..397d15eb1ea8 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -242,6 +242,7 @@ static int cr_backlight_remove(struct platform_device *pdev)
backlight_device_unregister(crp->cr_backlight_device);
lcd_device_unregister(crp->cr_lcd_device);
pci_dev_put(lpc_dev);
+ kfree(crp);
return 0;
}
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index 9093ef0fa869..98ad3e5f7c85 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -25,7 +25,7 @@
struct l4f00242t03_priv {
struct spi_device *spi;
struct lcd_device *ld;
- int lcd_on:1;
+ int lcd_state;
struct regulator *io_reg;
struct regulator *core_reg;
};
@@ -62,11 +62,36 @@ static void l4f00242t03_lcd_init(struct spi_device *spi)
regulator_enable(priv->core_reg);
}
+ l4f00242t03_reset(pdata->reset_gpio);
+
gpio_set_value(pdata->data_enable_gpio, 1);
msleep(60);
spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16));
}
+static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
+{
+ struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
+ struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "Powering down LCD\n");
+
+ gpio_set_value(pdata->data_enable_gpio, 0);
+
+ if (priv->io_reg)
+ regulator_disable(priv->io_reg);
+
+ if (priv->core_reg)
+ regulator_disable(priv->core_reg);
+}
+
+static int l4f00242t03_lcd_power_get(struct lcd_device *ld)
+{
+ struct l4f00242t03_priv *priv = lcd_get_data(ld);
+
+ return priv->lcd_state;
+}
+
static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
{
struct l4f00242t03_priv *priv = lcd_get_data(ld);
@@ -78,36 +103,55 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
const u16 slpin = 0x10;
const u16 disoff = 0x28;
- if (power) {
- if (priv->lcd_on)
- return 0;
-
- dev_dbg(&spi->dev, "turning on LCD\n");
-
- spi_write(spi, (const u8 *)&slpout, sizeof(u16));
- msleep(60);
- spi_write(spi, (const u8 *)&dison, sizeof(u16));
-
- priv->lcd_on = 1;
+ if (power <= FB_BLANK_NORMAL) {
+ if (priv->lcd_state <= FB_BLANK_NORMAL) {
+ /* Do nothing, the LCD is running */
+ } else if (priv->lcd_state < FB_BLANK_POWERDOWN) {
+ dev_dbg(&spi->dev, "Resuming LCD\n");
+
+ spi_write(spi, (const u8 *)&slpout, sizeof(u16));
+ msleep(60);
+ spi_write(spi, (const u8 *)&dison, sizeof(u16));
+ } else {
+ /* priv->lcd_state == FB_BLANK_POWERDOWN */
+ l4f00242t03_lcd_init(spi);
+ priv->lcd_state = FB_BLANK_VSYNC_SUSPEND;
+ l4f00242t03_lcd_power_set(priv->ld, power);
+ }
+ } else if (power < FB_BLANK_POWERDOWN) {
+ if (priv->lcd_state <= FB_BLANK_NORMAL) {
+ /* Send the display in standby */
+ dev_dbg(&spi->dev, "Standby the LCD\n");
+
+ spi_write(spi, (const u8 *)&disoff, sizeof(u16));
+ msleep(60);
+ spi_write(spi, (const u8 *)&slpin, sizeof(u16));
+ } else if (priv->lcd_state < FB_BLANK_POWERDOWN) {
+ /* Do nothing, the LCD is already in standby */
+ } else {
+ /* priv->lcd_state == FB_BLANK_POWERDOWN */
+ l4f00242t03_lcd_init(spi);
+ priv->lcd_state = FB_BLANK_UNBLANK;
+ l4f00242t03_lcd_power_set(ld, power);
+ }
} else {
- if (!priv->lcd_on)
- return 0;
-
- dev_dbg(&spi->dev, "turning off LCD\n");
-
- spi_write(spi, (const u8 *)&disoff, sizeof(u16));
- msleep(60);
- spi_write(spi, (const u8 *)&slpin, sizeof(u16));
-
- priv->lcd_on = 0;
+ /* power == FB_BLANK_POWERDOWN */
+ if (priv->lcd_state != FB_BLANK_POWERDOWN) {
+ /* Clear the screen before shutting down */
+ spi_write(spi, (const u8 *)&disoff, sizeof(u16));
+ msleep(60);
+ l4f00242t03_lcd_powerdown(spi);
+ }
}
+ priv->lcd_state = power;
+
return 0;
}
static struct lcd_ops l4f_ops = {
.set_power = l4f00242t03_lcd_power_set,
- .get_power = NULL,
+ .get_power = l4f00242t03_lcd_power_get,
};
static int __devinit l4f00242t03_probe(struct spi_device *spi)
@@ -185,9 +229,9 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
}
/* Init the LCD */
- l4f00242t03_reset(pdata->reset_gpio);
l4f00242t03_lcd_init(spi);
- l4f00242t03_lcd_power_set(priv->ld, 1);
+ priv->lcd_state = FB_BLANK_VSYNC_SUSPEND;
+ l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK);
dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
@@ -214,9 +258,11 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data;
- l4f00242t03_lcd_power_set(priv->ld, 0);
+ l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
lcd_device_unregister(priv->ld);
+ dev_set_drvdata(&spi->dev, NULL);
+
gpio_free(pdata->data_enable_gpio);
gpio_free(pdata->reset_gpio);
@@ -230,6 +276,15 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
return 0;
}
+static void l4f00242t03_shutdown(struct spi_device *spi)
+{
+ struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+
+ if (priv)
+ l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
+
+}
+
static struct spi_driver l4f00242t03_driver = {
.driver = {
.name = "l4f00242t03",
@@ -237,6 +292,7 @@ static struct spi_driver l4f00242t03_driver = {
},
.probe = l4f00242t03_probe,
.remove = __devexit_p(l4f00242t03_remove),
+ .shutdown = l4f00242t03_shutdown,
};
static __init int l4f00242t03_init(void)
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c
index abc43a0eb97d..5d3cf33953ac 100644
--- a/drivers/video/backlight/lms283gf05.c
+++ b/drivers/video/backlight/lms283gf05.c
@@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power)
struct spi_device *spi = st->spi;
struct lms283gf05_pdata *pdata = spi->dev.platform_data;
- if (power) {
+ if (power <= FB_BLANK_NORMAL) {
if (pdata)
lms283gf05_reset(pdata->reset_gpio,
pdata->reset_inverted);
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index b2b2c7ba1f63..209acc105cbc 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -92,7 +92,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl)
return ret;
}
-static struct backlight_ops max8925_backlight_ops = {
+static const struct backlight_ops max8925_backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.update_status = max8925_backlight_update_status,
.get_brightness = max8925_backlight_get_brightness,
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 9fb533f6373e..1485f7345f49 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -335,6 +335,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
},
.driver_data = (void *)&nvidia_chipset_data,
},
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookAir 3,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
+ },
+ .driver_data = (void *)&nvidia_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookAir 3,2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
+ },
+ .driver_data = (void *)&nvidia_chipset_data,
+ },
{ }
};
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 550443518891..21866ec69656 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -25,6 +25,7 @@ struct pwm_bl_data {
struct pwm_device *pwm;
struct device *dev;
unsigned int period;
+ unsigned int lth_brightness;
int (*notify)(struct device *,
int brightness);
};
@@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
} else {
- pwm_config(pb->pwm, brightness * pb->period / max, pb->period);
+ brightness = pb->lth_brightness +
+ (brightness * (pb->period - pb->lth_brightness) / max);
+ pwm_config(pb->pwm, brightness, pb->period);
pwm_enable(pb->pwm);
}
return 0;
@@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
+ pb->lth_brightness = data->lth_brightness *
+ (data->pwm_period_ns / data->max_brightness);
pb->dev = &pdev->dev;
pb->pwm = pwm_request(data->pwm_id, "backlight");
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
index a3128c9cb7ad..5927db0da999 100644
--- a/drivers/video/backlight/s6e63m0.c
+++ b/drivers/video/backlight/s6e63m0.c
@@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
return strlen(buf);
}
-static DEVICE_ATTR(gamma_table, 0644,
+static DEVICE_ATTR(gamma_table, 0444,
s6e63m0_sysfs_show_gamma_table, NULL);
-static int __init s6e63m0_probe(struct spi_device *spi)
+static int __devinit s6e63m0_probe(struct spi_device *spi)
{
int ret = 0;
struct s6e63m0 *lcd = NULL;
@@ -829,6 +829,9 @@ static int __devexit s6e63m0_remove(struct spi_device *spi)
struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+ device_remove_file(&spi->dev, &dev_attr_gamma_table);
+ device_remove_file(&spi->dev, &dev_attr_gamma_mode);
+ backlight_device_unregister(lcd->bd);
lcd_device_unregister(lcd->ld);
kfree(lcd);
diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c
new file mode 100644
index 000000000000..18c507874ff1
--- /dev/null
+++ b/drivers/video/bf537-lq035.c
@@ -0,0 +1,914 @@
+/*
+ * Analog Devices Blackfin(BF537 STAMP) + SHARP TFT LCD.
+ * http://docs.blackfin.uclinux.org/doku.php?id=hw:cards:tft-lcd
+ *
+ * Copyright 2006-2010 Analog Devices Inc.
+ * Licensed under the GPL-2.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/dpmc.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define NO_BL 1
+
+#define MAX_BRIGHENESS 95
+#define MIN_BRIGHENESS 5
+#define NBR_PALETTE 256
+
+static const unsigned short ppi_pins[] = {
+ P_PPI0_CLK, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+ P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+ P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+ P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, 0
+};
+
+static unsigned char *fb_buffer; /* RGB Buffer */
+static unsigned long *dma_desc_table;
+static int t_conf_done, lq035_open_cnt;
+static DEFINE_SPINLOCK(bfin_lq035_lock);
+
+static int landscape;
+module_param(landscape, int, 0);
+MODULE_PARM_DESC(landscape,
+ "LANDSCAPE use 320x240 instead of Native 240x320 Resolution");
+
+static int bgr;
+module_param(bgr, int, 0);
+MODULE_PARM_DESC(bgr,
+ "BGR use 16-bit BGR-565 instead of RGB-565");
+
+static int nocursor = 1;
+module_param(nocursor, int, 0644);
+MODULE_PARM_DESC(nocursor, "cursor enable/disable");
+
+static unsigned long current_brightness; /* backlight */
+
+/* AD5280 vcomm */
+static unsigned char vcomm_value = 150;
+static struct i2c_client *ad5280_client;
+
+static void set_vcomm(void)
+{
+ int nr;
+
+ if (!ad5280_client)
+ return;
+
+ nr = i2c_smbus_write_byte_data(ad5280_client, 0x00, vcomm_value);
+ if (nr)
+ pr_err("i2c_smbus_write_byte_data fail: %d\n", nr);
+}
+
+static int __devinit ad5280_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+ return -EIO;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, 0x00, vcomm_value);
+ if (ret) {
+ dev_err(&client->dev, "write fail: %d\n", ret);
+ return ret;
+ }
+
+ ad5280_client = client;
+
+ return 0;
+}
+
+static int __devexit ad5280_remove(struct i2c_client *client)
+{
+ ad5280_client = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id ad5280_id[] = {
+ {"bf537-lq035-ad5280", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad5280_id);
+
+static struct i2c_driver ad5280_driver = {
+ .driver = {
+ .name = "bf537-lq035-ad5280",
+ },
+ .probe = ad5280_probe,
+ .remove = __devexit_p(ad5280_remove),
+ .id_table = ad5280_id,
+};
+
+#ifdef CONFIG_PNAV10
+#define MOD GPIO_PH13
+
+#define bfin_write_TIMER_LP_CONFIG bfin_write_TIMER0_CONFIG
+#define bfin_write_TIMER_LP_WIDTH bfin_write_TIMER0_WIDTH
+#define bfin_write_TIMER_LP_PERIOD bfin_write_TIMER0_PERIOD
+#define bfin_read_TIMER_LP_COUNTER bfin_read_TIMER0_COUNTER
+#define TIMDIS_LP TIMDIS0
+#define TIMEN_LP TIMEN0
+
+#define bfin_write_TIMER_SPS_CONFIG bfin_write_TIMER1_CONFIG
+#define bfin_write_TIMER_SPS_WIDTH bfin_write_TIMER1_WIDTH
+#define bfin_write_TIMER_SPS_PERIOD bfin_write_TIMER1_PERIOD
+#define TIMDIS_SPS TIMDIS1
+#define TIMEN_SPS TIMEN1
+
+#define bfin_write_TIMER_SP_CONFIG bfin_write_TIMER5_CONFIG
+#define bfin_write_TIMER_SP_WIDTH bfin_write_TIMER5_WIDTH
+#define bfin_write_TIMER_SP_PERIOD bfin_write_TIMER5_PERIOD
+#define TIMDIS_SP TIMDIS5
+#define TIMEN_SP TIMEN5
+
+#define bfin_write_TIMER_PS_CLS_CONFIG bfin_write_TIMER2_CONFIG
+#define bfin_write_TIMER_PS_CLS_WIDTH bfin_write_TIMER2_WIDTH
+#define bfin_write_TIMER_PS_CLS_PERIOD bfin_write_TIMER2_PERIOD
+#define TIMDIS_PS_CLS TIMDIS2
+#define TIMEN_PS_CLS TIMEN2
+
+#define bfin_write_TIMER_REV_CONFIG bfin_write_TIMER3_CONFIG
+#define bfin_write_TIMER_REV_WIDTH bfin_write_TIMER3_WIDTH
+#define bfin_write_TIMER_REV_PERIOD bfin_write_TIMER3_PERIOD
+#define TIMDIS_REV TIMDIS3
+#define TIMEN_REV TIMEN3
+#define bfin_read_TIMER_REV_COUNTER bfin_read_TIMER3_COUNTER
+
+#define FREQ_PPI_CLK (5*1024*1024) /* PPI_CLK 5MHz */
+
+#define TIMERS {P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR5, 0}
+
+#else
+
+#define UD GPIO_PF13 /* Up / Down */
+#define MOD GPIO_PF10
+#define LBR GPIO_PF14 /* Left Right */
+
+#define bfin_write_TIMER_LP_CONFIG bfin_write_TIMER6_CONFIG
+#define bfin_write_TIMER_LP_WIDTH bfin_write_TIMER6_WIDTH
+#define bfin_write_TIMER_LP_PERIOD bfin_write_TIMER6_PERIOD
+#define bfin_read_TIMER_LP_COUNTER bfin_read_TIMER6_COUNTER
+#define TIMDIS_LP TIMDIS6
+#define TIMEN_LP TIMEN6
+
+#define bfin_write_TIMER_SPS_CONFIG bfin_write_TIMER1_CONFIG
+#define bfin_write_TIMER_SPS_WIDTH bfin_write_TIMER1_WIDTH
+#define bfin_write_TIMER_SPS_PERIOD bfin_write_TIMER1_PERIOD
+#define TIMDIS_SPS TIMDIS1
+#define TIMEN_SPS TIMEN1
+
+#define bfin_write_TIMER_SP_CONFIG bfin_write_TIMER0_CONFIG
+#define bfin_write_TIMER_SP_WIDTH bfin_write_TIMER0_WIDTH
+#define bfin_write_TIMER_SP_PERIOD bfin_write_TIMER0_PERIOD
+#define TIMDIS_SP TIMDIS0
+#define TIMEN_SP TIMEN0
+
+#define bfin_write_TIMER_PS_CLS_CONFIG bfin_write_TIMER7_CONFIG
+#define bfin_write_TIMER_PS_CLS_WIDTH bfin_write_TIMER7_WIDTH
+#define bfin_write_TIMER_PS_CLS_PERIOD bfin_write_TIMER7_PERIOD
+#define TIMDIS_PS_CLS TIMDIS7
+#define TIMEN_PS_CLS TIMEN7
+
+#define bfin_write_TIMER_REV_CONFIG bfin_write_TIMER5_CONFIG
+#define bfin_write_TIMER_REV_WIDTH bfin_write_TIMER5_WIDTH
+#define bfin_write_TIMER_REV_PERIOD bfin_write_TIMER5_PERIOD
+#define TIMDIS_REV TIMDIS5
+#define TIMEN_REV TIMEN5
+#define bfin_read_TIMER_REV_COUNTER bfin_read_TIMER5_COUNTER
+
+#define FREQ_PPI_CLK (6*1000*1000) /* PPI_CLK 6MHz */
+#define TIMERS {P_TMR0, P_TMR1, P_TMR5, P_TMR6, P_TMR7, 0}
+
+#endif
+
+#define LCD_X_RES 240 /* Horizontal Resolution */
+#define LCD_Y_RES 320 /* Vertical Resolution */
+
+#define LCD_BBP 16 /* Bit Per Pixel */
+
+/* the LCD and the DMA start counting differently;
+ * since one starts at 0 and the other starts at 1,
+ * we have a difference of 1 between START_LINES
+ * and U_LINES.
+ */
+#define START_LINES 8 /* lines for field flyback or field blanking signal */
+#define U_LINES 9 /* number of undisplayed blanking lines */
+
+#define FRAMES_PER_SEC (60)
+
+#define DCLKS_PER_FRAME (FREQ_PPI_CLK/FRAMES_PER_SEC)
+#define DCLKS_PER_LINE (DCLKS_PER_FRAME/(LCD_Y_RES+U_LINES))
+
+#define PPI_CONFIG_VALUE (PORT_DIR|XFR_TYPE|DLEN_16|POLS)
+#define PPI_DELAY_VALUE (0)
+#define TIMER_CONFIG (PWM_OUT|PERIOD_CNT|TIN_SEL|CLK_SEL)
+
+#define ACTIVE_VIDEO_MEM_OFFSET (LCD_X_RES*START_LINES*(LCD_BBP/8))
+#define ACTIVE_VIDEO_MEM_SIZE (LCD_Y_RES*LCD_X_RES*(LCD_BBP/8))
+#define TOTAL_VIDEO_MEM_SIZE ((LCD_Y_RES+U_LINES)*LCD_X_RES*(LCD_BBP/8))
+#define TOTAL_DMA_DESC_SIZE (2 * sizeof(u32) * (LCD_Y_RES + U_LINES))
+
+static void start_timers(void) /* CHECK with HW */
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ bfin_write_TIMER_ENABLE(TIMEN_REV);
+ SSYNC();
+
+ while (bfin_read_TIMER_REV_COUNTER() <= 11)
+ continue;
+ bfin_write_TIMER_ENABLE(TIMEN_LP);
+ SSYNC();
+
+ while (bfin_read_TIMER_LP_COUNTER() < 3)
+ continue;
+ bfin_write_TIMER_ENABLE(TIMEN_SP|TIMEN_SPS|TIMEN_PS_CLS);
+ SSYNC();
+ t_conf_done = 1;
+ local_irq_restore(flags);
+}
+
+static void config_timers(void)
+{
+ /* Stop timers */
+ bfin_write_TIMER_DISABLE(TIMDIS_SP|TIMDIS_SPS|TIMDIS_REV|
+ TIMDIS_LP|TIMDIS_PS_CLS);
+ SSYNC();
+
+ /* LP, timer 6 */
+ bfin_write_TIMER_LP_CONFIG(TIMER_CONFIG|PULSE_HI);
+ bfin_write_TIMER_LP_WIDTH(1);
+
+ bfin_write_TIMER_LP_PERIOD(DCLKS_PER_LINE);
+ SSYNC();
+
+ /* SPS, timer 1 */
+ bfin_write_TIMER_SPS_CONFIG(TIMER_CONFIG|PULSE_HI);
+ bfin_write_TIMER_SPS_WIDTH(DCLKS_PER_LINE*2);
+ bfin_write_TIMER_SPS_PERIOD((DCLKS_PER_LINE * (LCD_Y_RES+U_LINES)));
+ SSYNC();
+
+ /* SP, timer 0 */
+ bfin_write_TIMER_SP_CONFIG(TIMER_CONFIG|PULSE_HI);
+ bfin_write_TIMER_SP_WIDTH(1);
+ bfin_write_TIMER_SP_PERIOD(DCLKS_PER_LINE);
+ SSYNC();
+
+ /* PS & CLS, timer 7 */
+ bfin_write_TIMER_PS_CLS_CONFIG(TIMER_CONFIG);
+ bfin_write_TIMER_PS_CLS_WIDTH(LCD_X_RES + START_LINES);
+ bfin_write_TIMER_PS_CLS_PERIOD(DCLKS_PER_LINE);
+
+ SSYNC();
+
+#ifdef NO_BL
+ /* REV, timer 5 */
+ bfin_write_TIMER_REV_CONFIG(TIMER_CONFIG|PULSE_HI);
+
+ bfin_write_TIMER_REV_WIDTH(DCLKS_PER_LINE);
+ bfin_write_TIMER_REV_PERIOD(DCLKS_PER_LINE*2);
+
+ SSYNC();
+#endif
+}
+
+static void config_ppi(void)
+{
+ bfin_write_PPI_DELAY(PPI_DELAY_VALUE);
+ bfin_write_PPI_COUNT(LCD_X_RES-1);
+ /* 0x10 -> PORT_CFG -> 2 or 3 frame syncs */
+ bfin_write_PPI_CONTROL((PPI_CONFIG_VALUE|0x10) & (~POLS));
+}
+
+static int config_dma(void)
+{
+ u32 i;
+
+ if (landscape) {
+
+ for (i = 0; i < U_LINES; ++i) {
+ /* blanking lines point to first line of fb_buffer */
+ dma_desc_table[2*i] = (unsigned long)&dma_desc_table[2*i+2];
+ dma_desc_table[2*i+1] = (unsigned long)fb_buffer;
+ }
+
+ for (i = U_LINES; i < U_LINES + LCD_Y_RES; ++i) {
+ /* visible lines */
+ dma_desc_table[2*i] = (unsigned long)&dma_desc_table[2*i+2];
+ dma_desc_table[2*i+1] = (unsigned long)fb_buffer +
+ (LCD_Y_RES+U_LINES-1-i)*2;
+ }
+
+ /* last descriptor points to first */
+ dma_desc_table[2*(LCD_Y_RES+U_LINES-1)] = (unsigned long)&dma_desc_table[0];
+
+ set_dma_x_count(CH_PPI, LCD_X_RES);
+ set_dma_x_modify(CH_PPI, LCD_Y_RES * (LCD_BBP / 8));
+ set_dma_y_count(CH_PPI, 0);
+ set_dma_y_modify(CH_PPI, 0);
+ set_dma_next_desc_addr(CH_PPI, (void *)dma_desc_table[0]);
+ set_dma_config(CH_PPI, DMAFLOW_LARGE | NDSIZE_4 | WDSIZE_16);
+
+ } else {
+
+ set_dma_config(CH_PPI, set_bfin_dma_config(DIR_READ,
+ DMA_FLOW_AUTO,
+ INTR_DISABLE,
+ DIMENSION_2D,
+ DATA_SIZE_16,
+ DMA_NOSYNC_KEEP_DMA_BUF));
+ set_dma_x_count(CH_PPI, LCD_X_RES);
+ set_dma_x_modify(CH_PPI, LCD_BBP / 8);
+ set_dma_y_count(CH_PPI, LCD_Y_RES+U_LINES);
+ set_dma_y_modify(CH_PPI, LCD_BBP / 8);
+ set_dma_start_addr(CH_PPI, (unsigned long) fb_buffer);
+ }
+
+ return 0;
+}
+
+static int __devinit request_ports(void)
+{
+ u16 tmr_req[] = TIMERS;
+
+ /*
+ UD: PF13
+ MOD: PF10
+ LBR: PF14
+ PPI_CLK: PF15
+ */
+
+ if (peripheral_request_list(ppi_pins, KBUILD_MODNAME)) {
+ pr_err("requesting PPI peripheral failed\n");
+ return -EBUSY;
+ }
+
+ if (peripheral_request_list(tmr_req, KBUILD_MODNAME)) {
+ peripheral_free_list(ppi_pins);
+ pr_err("requesting timer peripheral failed\n");
+ return -EBUSY;
+ }
+
+#if (defined(UD) && defined(LBR))
+ if (gpio_request(UD, KBUILD_MODNAME)) {
+ pr_err("requesting GPIO %d failed\n", UD);
+ return -EBUSY;
+ }
+
+ if (gpio_request(LBR, KBUILD_MODNAME)) {
+ pr_err("requesting GPIO %d failed\n", LBR);
+ gpio_free(UD);
+ return -EBUSY;
+ }
+
+ gpio_direction_output(UD, 0);
+ gpio_direction_output(LBR, 1);
+
+#endif
+
+ if (gpio_request(MOD, KBUILD_MODNAME)) {
+ pr_err("requesting GPIO %d failed\n", MOD);
+#if (defined(UD) && defined(LBR))
+ gpio_free(LBR);
+ gpio_free(UD);
+#endif
+ return -EBUSY;
+ }
+
+ gpio_direction_output(MOD, 1);
+
+ SSYNC();
+ return 0;
+}
+
+static void free_ports(void)
+{
+ u16 tmr_req[] = TIMERS;
+
+ peripheral_free_list(ppi_pins);
+ peripheral_free_list(tmr_req);
+
+#if defined(UD) && defined(LBR)
+ gpio_free(LBR);
+ gpio_free(UD);
+#endif
+ gpio_free(MOD);
+}
+
+static struct fb_info bfin_lq035_fb;
+
+static struct fb_var_screeninfo bfin_lq035_fb_defined = {
+ .bits_per_pixel = LCD_BBP,
+ .activate = FB_ACTIVATE_TEST,
+ .xres = LCD_X_RES, /*default portrait mode RGB*/
+ .yres = LCD_Y_RES,
+ .xres_virtual = LCD_X_RES,
+ .yres_virtual = LCD_Y_RES,
+ .height = -1,
+ .width = -1,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .transp = {0, 0, 0},
+};
+
+static struct fb_fix_screeninfo bfin_lq035_fb_fix __devinitdata = {
+ .id = KBUILD_MODNAME,
+ .smem_len = ACTIVE_VIDEO_MEM_SIZE,
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .line_length = LCD_X_RES*(LCD_BBP/8),
+ .accel = FB_ACCEL_NONE,
+};
+
+
+static int bfin_lq035_fb_open(struct fb_info *info, int user)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfin_lq035_lock, flags);
+ lq035_open_cnt++;
+ spin_unlock_irqrestore(&bfin_lq035_lock, flags);
+
+ if (lq035_open_cnt <= 1) {
+ bfin_write_PPI_CONTROL(0);
+ SSYNC();
+
+ set_vcomm();
+ config_dma();
+ config_ppi();
+
+ /* start dma */
+ enable_dma(CH_PPI);
+ SSYNC();
+ bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
+ SSYNC();
+
+ if (!t_conf_done) {
+ config_timers();
+ start_timers();
+ }
+ /* gpio_set_value(MOD,1); */
+ }
+
+ return 0;
+}
+
+static int bfin_lq035_fb_release(struct fb_info *info, int user)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfin_lq035_lock, flags);
+ lq035_open_cnt--;
+ spin_unlock_irqrestore(&bfin_lq035_lock, flags);
+
+
+ if (lq035_open_cnt <= 0) {
+
+ bfin_write_PPI_CONTROL(0);
+ SSYNC();
+
+ disable_dma(CH_PPI);
+ }
+
+ return 0;
+}
+
+
+static int bfin_lq035_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ switch (var->bits_per_pixel) {
+ case 16:/* DIRECTCOLOUR, 64k */
+ var->red.offset = info->var.red.offset;
+ var->green.offset = info->var.green.offset;
+ var->blue.offset = info->var.blue.offset;
+ var->red.length = info->var.red.length;
+ var->green.length = info->var.green.length;
+ var->blue.length = info->var.blue.length;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ break;
+ default:
+ pr_debug("%s: depth not supported: %u BPP\n", __func__,
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if (info->var.xres != var->xres ||
+ info->var.yres != var->yres ||
+ info->var.xres_virtual != var->xres_virtual ||
+ info->var.yres_virtual != var->yres_virtual) {
+ pr_debug("%s: Resolution not supported: X%u x Y%u\n",
+ __func__, var->xres, var->yres);
+ return -EINVAL;
+ }
+
+ /*
+ * Memory limit
+ */
+
+ if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
+ pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
+ __func__, var->yres_virtual);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* fb_rotate
+ * Rotate the display of this angle. This doesn't seems to be used by the core,
+ * but as our hardware supports it, so why not implementing it...
+ */
+static void bfin_lq035_fb_rotate(struct fb_info *fbi, int angle)
+{
+ pr_debug("%s: %p %d", __func__, fbi, angle);
+#if (defined(UD) && defined(LBR))
+ switch (angle) {
+
+ case 180:
+ gpio_set_value(LBR, 0);
+ gpio_set_value(UD, 1);
+ break;
+ default:
+ gpio_set_value(LBR, 1);
+ gpio_set_value(UD, 0);
+ break;
+ }
+#endif
+}
+
+static int bfin_lq035_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ if (nocursor)
+ return 0;
+ else
+ return -EINVAL; /* just to force soft_cursor() call */
+}
+
+static int bfin_lq035_fb_setcolreg(u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp,
+ struct fb_info *info)
+{
+ if (regno >= NBR_PALETTE)
+ return -EINVAL;
+
+ if (info->var.grayscale)
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+
+ u32 value;
+ /* Place color in the pseudopalette */
+ if (regno > 16)
+ return -EINVAL;
+
+ red >>= (16 - info->var.red.length);
+ green >>= (16 - info->var.green.length);
+ blue >>= (16 - info->var.blue.length);
+
+ value = (red << info->var.red.offset) |
+ (green << info->var.green.offset)|
+ (blue << info->var.blue.offset);
+ value &= 0xFFFF;
+
+ ((u32 *) (info->pseudo_palette))[regno] = value;
+
+ }
+
+ return 0;
+}
+
+static struct fb_ops bfin_lq035_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = bfin_lq035_fb_open,
+ .fb_release = bfin_lq035_fb_release,
+ .fb_check_var = bfin_lq035_fb_check_var,
+ .fb_rotate = bfin_lq035_fb_rotate,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = bfin_lq035_fb_cursor,
+ .fb_setcolreg = bfin_lq035_fb_setcolreg,
+};
+
+static int bl_get_brightness(struct backlight_device *bd)
+{
+ return current_brightness;
+}
+
+static const struct backlight_ops bfin_lq035fb_bl_ops = {
+ .get_brightness = bl_get_brightness,
+};
+
+static struct backlight_device *bl_dev;
+
+static int bfin_lcd_get_power(struct lcd_device *dev)
+{
+ return 0;
+}
+
+static int bfin_lcd_set_power(struct lcd_device *dev, int power)
+{
+ return 0;
+}
+
+static int bfin_lcd_get_contrast(struct lcd_device *dev)
+{
+ return (int)vcomm_value;
+}
+
+static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast)
+{
+ if (contrast > 255)
+ contrast = 255;
+ if (contrast < 0)
+ contrast = 0;
+
+ vcomm_value = (unsigned char)contrast;
+ set_vcomm();
+ return 0;
+}
+
+static int bfin_lcd_check_fb(struct lcd_device *lcd, struct fb_info *fi)
+{
+ if (!fi || (fi == &bfin_lq035_fb))
+ return 1;
+ return 0;
+}
+
+static struct lcd_ops bfin_lcd_ops = {
+ .get_power = bfin_lcd_get_power,
+ .set_power = bfin_lcd_set_power,
+ .get_contrast = bfin_lcd_get_contrast,
+ .set_contrast = bfin_lcd_set_contrast,
+ .check_fb = bfin_lcd_check_fb,
+};
+
+static struct lcd_device *lcd_dev;
+
+static int __devinit bfin_lq035_probe(struct platform_device *pdev)
+{
+ struct backlight_properties props;
+ dma_addr_t dma_handle;
+
+ if (request_dma(CH_PPI, KBUILD_MODNAME)) {
+ pr_err("couldn't request PPI DMA\n");
+ return -EFAULT;
+ }
+
+ if (request_ports()) {
+ pr_err("couldn't request gpio port\n");
+ free_dma(CH_PPI);
+ return -EFAULT;
+ }
+
+ fb_buffer = dma_alloc_coherent(NULL, TOTAL_VIDEO_MEM_SIZE,
+ &dma_handle, GFP_KERNEL);
+ if (fb_buffer == NULL) {
+ pr_err("couldn't allocate dma buffer\n");
+ free_dma(CH_PPI);
+ free_ports();
+ return -ENOMEM;
+ }
+
+ if (L1_DATA_A_LENGTH)
+ dma_desc_table = l1_data_sram_zalloc(TOTAL_DMA_DESC_SIZE);
+ else
+ dma_desc_table = dma_alloc_coherent(NULL, TOTAL_DMA_DESC_SIZE,
+ &dma_handle, 0);
+
+ if (dma_desc_table == NULL) {
+ pr_err("couldn't allocate dma descriptor\n");
+ free_dma(CH_PPI);
+ free_ports();
+ dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+ return -ENOMEM;
+ }
+
+ bfin_lq035_fb.screen_base = (void *)fb_buffer;
+ bfin_lq035_fb_fix.smem_start = (int)fb_buffer;
+ if (landscape) {
+ bfin_lq035_fb_defined.xres = LCD_Y_RES;
+ bfin_lq035_fb_defined.yres = LCD_X_RES;
+ bfin_lq035_fb_defined.xres_virtual = LCD_Y_RES;
+ bfin_lq035_fb_defined.yres_virtual = LCD_X_RES;
+
+ bfin_lq035_fb_fix.line_length = LCD_Y_RES*(LCD_BBP/8);
+ } else {
+ bfin_lq035_fb.screen_base += ACTIVE_VIDEO_MEM_OFFSET;
+ bfin_lq035_fb_fix.smem_start += ACTIVE_VIDEO_MEM_OFFSET;
+ }
+
+ bfin_lq035_fb_defined.green.msb_right = 0;
+ bfin_lq035_fb_defined.red.msb_right = 0;
+ bfin_lq035_fb_defined.blue.msb_right = 0;
+ bfin_lq035_fb_defined.green.offset = 5;
+ bfin_lq035_fb_defined.green.length = 6;
+ bfin_lq035_fb_defined.red.length = 5;
+ bfin_lq035_fb_defined.blue.length = 5;
+
+ if (bgr) {
+ bfin_lq035_fb_defined.red.offset = 0;
+ bfin_lq035_fb_defined.blue.offset = 11;
+ } else {
+ bfin_lq035_fb_defined.red.offset = 11;
+ bfin_lq035_fb_defined.blue.offset = 0;
+ }
+
+ bfin_lq035_fb.fbops = &bfin_lq035_fb_ops;
+ bfin_lq035_fb.var = bfin_lq035_fb_defined;
+
+ bfin_lq035_fb.fix = bfin_lq035_fb_fix;
+ bfin_lq035_fb.flags = FBINFO_DEFAULT;
+
+
+ bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (bfin_lq035_fb.pseudo_palette == NULL) {
+ pr_err("failed to allocate pseudo_palette\n");
+ free_dma(CH_PPI);
+ free_ports();
+ dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+ return -ENOMEM;
+ }
+
+ if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) {
+ pr_err("failed to allocate colormap (%d entries)\n",
+ NBR_PALETTE);
+ free_dma(CH_PPI);
+ free_ports();
+ dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+ kfree(bfin_lq035_fb.pseudo_palette);
+ return -EFAULT;
+ }
+
+ if (register_framebuffer(&bfin_lq035_fb) < 0) {
+ pr_err("unable to register framebuffer\n");
+ free_dma(CH_PPI);
+ free_ports();
+ dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+ fb_buffer = NULL;
+ kfree(bfin_lq035_fb.pseudo_palette);
+ fb_dealloc_cmap(&bfin_lq035_fb.cmap);
+ return -EINVAL;
+ }
+
+ i2c_add_driver(&ad5280_driver);
+
+ memset(&props, 0, sizeof(props));
+ props.max_brightness = MAX_BRIGHENESS;
+ bl_dev = backlight_device_register("bf537-bl", NULL, NULL,
+ &bfin_lq035fb_bl_ops, &props);
+
+ lcd_dev = lcd_device_register(KBUILD_MODNAME, &pdev->dev, NULL,
+ &bfin_lcd_ops);
+ lcd_dev->props.max_contrast = 255,
+
+ pr_info("initialized");
+
+ return 0;
+}
+
+static int __devexit bfin_lq035_remove(struct platform_device *pdev)
+{
+ if (fb_buffer != NULL)
+ dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+
+ if (L1_DATA_A_LENGTH)
+ l1_data_sram_free(dma_desc_table);
+ else
+ dma_free_coherent(NULL, TOTAL_DMA_DESC_SIZE, NULL, 0);
+
+ bfin_write_TIMER_DISABLE(TIMEN_SP|TIMEN_SPS|TIMEN_PS_CLS|
+ TIMEN_LP|TIMEN_REV);
+ t_conf_done = 0;
+
+ free_dma(CH_PPI);
+
+
+ kfree(bfin_lq035_fb.pseudo_palette);
+ fb_dealloc_cmap(&bfin_lq035_fb.cmap);
+
+
+ lcd_device_unregister(lcd_dev);
+ backlight_device_unregister(bl_dev);
+
+ unregister_framebuffer(&bfin_lq035_fb);
+ i2c_del_driver(&ad5280_driver);
+
+ free_ports();
+
+ pr_info("unregistered LCD driver\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_lq035_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (lq035_open_cnt > 0) {
+ bfin_write_PPI_CONTROL(0);
+ SSYNC();
+ disable_dma(CH_PPI);
+ }
+
+ return 0;
+}
+
+static int bfin_lq035_resume(struct platform_device *pdev)
+{
+ if (lq035_open_cnt > 0) {
+ bfin_write_PPI_CONTROL(0);
+ SSYNC();
+
+ config_dma();
+ config_ppi();
+
+ enable_dma(CH_PPI);
+ bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
+ SSYNC();
+
+ config_timers();
+ start_timers();
+ } else {
+ t_conf_done = 0;
+ }
+
+ return 0;
+}
+#else
+# define bfin_lq035_suspend NULL
+# define bfin_lq035_resume NULL
+#endif
+
+static struct platform_driver bfin_lq035_driver = {
+ .probe = bfin_lq035_probe,
+ .remove = __devexit_p(bfin_lq035_remove),
+ .suspend = bfin_lq035_suspend,
+ .resume = bfin_lq035_resume,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bfin_lq035_driver_init(void)
+{
+ request_module("i2c-bfin-twi");
+ return platform_driver_register(&bfin_lq035_driver);
+}
+module_init(bfin_lq035_driver_init);
+
+static void __exit bfin_lq035_driver_cleanup(void)
+{
+ platform_driver_unregister(&bfin_lq035_driver);
+}
+module_exit(bfin_lq035_driver_cleanup);
+
+MODULE_DESCRIPTION("SHARP LQ035Q7DB03 TFT LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c
new file mode 100644
index 000000000000..8486f541156b
--- /dev/null
+++ b/drivers/video/bfin_adv7393fb.c
@@ -0,0 +1,832 @@
+/*
+ * Frame buffer driver for ADV7393/2 video encoder
+ *
+ * Copyright 2006-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or late.
+ */
+
+/*
+ * TODO: Remove Globals
+ * TODO: Code Cleanup
+ */
+
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <asm/portmux.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/proc_fs.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "bfin_adv7393fb.h"
+
+static int mode = VMODE;
+static int mem = VMEM;
+static int nocursor = 1;
+
+static const unsigned short ppi_pins[] = {
+ P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+ P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+ P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+ P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+ P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
+ 0
+};
+
+/*
+ * card parameters
+ */
+
+static struct bfin_adv7393_fb_par {
+ /* structure holding blackfin / adv7393 paramters when
+ screen is blanked */
+ struct {
+ u8 Mode; /* ntsc/pal/? */
+ } vga_state;
+ atomic_t ref_count;
+} bfin_par;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo bfin_adv7393_fb_defined = {
+ .xres = 720,
+ .yres = 480,
+ .xres_virtual = 720,
+ .yres_virtual = 480,
+ .bits_per_pixel = 16,
+ .activate = FB_ACTIVATE_TEST,
+ .height = -1,
+ .width = -1,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .vmode = FB_VMODE_INTERLACED,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .transp = {0, 0, 0},
+};
+
+static struct fb_fix_screeninfo bfin_adv7393_fb_fix __devinitdata = {
+ .id = "BFIN ADV7393",
+ .smem_len = 720 * 480 * 2,
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .line_length = 720 * 2,
+ .accel = FB_ACCEL_NONE
+};
+
+static struct fb_ops bfin_adv7393_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = bfin_adv7393_fb_open,
+ .fb_release = bfin_adv7393_fb_release,
+ .fb_check_var = bfin_adv7393_fb_check_var,
+ .fb_pan_display = bfin_adv7393_fb_pan_display,
+ .fb_blank = bfin_adv7393_fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = bfin_adv7393_fb_cursor,
+ .fb_setcolreg = bfin_adv7393_fb_setcolreg,
+};
+
+static int dma_desc_list(struct adv7393fb_device *fbdev, u16 arg)
+{
+ if (arg == BUILD) { /* Build */
+ fbdev->vb1 = l1_data_sram_zalloc(sizeof(struct dmasg));
+ if (fbdev->vb1 == NULL)
+ goto error;
+
+ fbdev->av1 = l1_data_sram_zalloc(sizeof(struct dmasg));
+ if (fbdev->av1 == NULL)
+ goto error;
+
+ fbdev->vb2 = l1_data_sram_zalloc(sizeof(struct dmasg));
+ if (fbdev->vb2 == NULL)
+ goto error;
+
+ fbdev->av2 = l1_data_sram_zalloc(sizeof(struct dmasg));
+ if (fbdev->av2 == NULL)
+ goto error;
+
+ /* Build linked DMA descriptor list */
+ fbdev->vb1->next_desc_addr = fbdev->av1;
+ fbdev->av1->next_desc_addr = fbdev->vb2;
+ fbdev->vb2->next_desc_addr = fbdev->av2;
+ fbdev->av2->next_desc_addr = fbdev->vb1;
+
+ /* Save list head */
+ fbdev->descriptor_list_head = fbdev->av2;
+
+ /* Vertical Blanking Field 1 */
+ fbdev->vb1->start_addr = VB_DUMMY_MEMORY_SOURCE;
+ fbdev->vb1->cfg = DMA_CFG_VAL;
+
+ fbdev->vb1->x_count =
+ fbdev->modes[mode].xres + fbdev->modes[mode].boeft_blank;
+
+ fbdev->vb1->x_modify = 0;
+ fbdev->vb1->y_count = fbdev->modes[mode].vb1_lines;
+ fbdev->vb1->y_modify = 0;
+
+ /* Active Video Field 1 */
+
+ fbdev->av1->start_addr = (unsigned long)fbdev->fb_mem;
+ fbdev->av1->cfg = DMA_CFG_VAL;
+ fbdev->av1->x_count =
+ fbdev->modes[mode].xres + fbdev->modes[mode].boeft_blank;
+ fbdev->av1->x_modify = fbdev->modes[mode].bpp / 8;
+ fbdev->av1->y_count = fbdev->modes[mode].a_lines;
+ fbdev->av1->y_modify =
+ (fbdev->modes[mode].xres - fbdev->modes[mode].boeft_blank +
+ 1) * (fbdev->modes[mode].bpp / 8);
+
+ /* Vertical Blanking Field 2 */
+
+ fbdev->vb2->start_addr = VB_DUMMY_MEMORY_SOURCE;
+ fbdev->vb2->cfg = DMA_CFG_VAL;
+ fbdev->vb2->x_count =
+ fbdev->modes[mode].xres + fbdev->modes[mode].boeft_blank;
+
+ fbdev->vb2->x_modify = 0;
+ fbdev->vb2->y_count = fbdev->modes[mode].vb2_lines;
+ fbdev->vb2->y_modify = 0;
+
+ /* Active Video Field 2 */
+
+ fbdev->av2->start_addr =
+ (unsigned long)fbdev->fb_mem + fbdev->line_len;
+
+ fbdev->av2->cfg = DMA_CFG_VAL;
+
+ fbdev->av2->x_count =
+ fbdev->modes[mode].xres + fbdev->modes[mode].boeft_blank;
+
+ fbdev->av2->x_modify = (fbdev->modes[mode].bpp / 8);
+ fbdev->av2->y_count = fbdev->modes[mode].a_lines;
+
+ fbdev->av2->y_modify =
+ (fbdev->modes[mode].xres - fbdev->modes[mode].boeft_blank +
+ 1) * (fbdev->modes[mode].bpp / 8);
+
+ return 1;
+ }
+
+error:
+ l1_data_sram_free(fbdev->vb1);
+ l1_data_sram_free(fbdev->av1);
+ l1_data_sram_free(fbdev->vb2);
+ l1_data_sram_free(fbdev->av2);
+
+ return 0;
+}
+
+static int bfin_config_dma(struct adv7393fb_device *fbdev)
+{
+ BUG_ON(!(fbdev->fb_mem));
+
+ set_dma_x_count(CH_PPI, fbdev->descriptor_list_head->x_count);
+ set_dma_x_modify(CH_PPI, fbdev->descriptor_list_head->x_modify);
+ set_dma_y_count(CH_PPI, fbdev->descriptor_list_head->y_count);
+ set_dma_y_modify(CH_PPI, fbdev->descriptor_list_head->y_modify);
+ set_dma_start_addr(CH_PPI, fbdev->descriptor_list_head->start_addr);
+ set_dma_next_desc_addr(CH_PPI,
+ fbdev->descriptor_list_head->next_desc_addr);
+ set_dma_config(CH_PPI, fbdev->descriptor_list_head->cfg);
+
+ return 1;
+}
+
+static void bfin_disable_dma(void)
+{
+ bfin_write_DMA0_CONFIG(bfin_read_DMA0_CONFIG() & ~DMAEN);
+}
+
+static void bfin_config_ppi(struct adv7393fb_device *fbdev)
+{
+ if (ANOMALY_05000183) {
+ bfin_write_TIMER2_CONFIG(WDTH_CAP);
+ bfin_write_TIMER_ENABLE(TIMEN2);
+ }
+
+ bfin_write_PPI_CONTROL(0x381E);
+ bfin_write_PPI_FRAME(fbdev->modes[mode].tot_lines);
+ bfin_write_PPI_COUNT(fbdev->modes[mode].xres +
+ fbdev->modes[mode].boeft_blank - 1);
+ bfin_write_PPI_DELAY(fbdev->modes[mode].aoeft_blank - 1);
+}
+
+static void bfin_enable_ppi(void)
+{
+ bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
+}
+
+static void bfin_disable_ppi(void)
+{
+ bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);
+}
+
+static inline int adv7393_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int adv7393_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+adv7393_write_block(struct i2c_client *client,
+ const u8 *data, unsigned int len)
+{
+ int ret = -1;
+ u8 reg;
+
+ while (len >= 2) {
+ reg = *data++;
+ ret = adv7393_write(client, reg, *data++);
+ if (ret < 0)
+ break;
+ len -= 2;
+ }
+
+ return ret;
+}
+
+static int adv7393_mode(struct i2c_client *client, u16 mode)
+{
+ switch (mode) {
+ case POWER_ON: /* ADV7393 Sleep mode OFF */
+ adv7393_write(client, 0x00, 0x1E);
+ break;
+ case POWER_DOWN: /* ADV7393 Sleep mode ON */
+ adv7393_write(client, 0x00, 0x1F);
+ break;
+ case BLANK_OFF: /* Pixel Data Valid */
+ adv7393_write(client, 0x82, 0xCB);
+ break;
+ case BLANK_ON: /* Pixel Data Invalid */
+ adv7393_write(client, 0x82, 0x8B);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static irqreturn_t ppi_irq_error(int irq, void *dev_id)
+{
+
+ struct adv7393fb_device *fbdev = (struct adv7393fb_device *)dev_id;
+
+ u16 status = bfin_read_PPI_STATUS();
+
+ pr_debug("%s: PPI Status = 0x%X\n", __func__, status);
+
+ if (status) {
+ bfin_disable_dma(); /* TODO: Check Sequence */
+ bfin_disable_ppi();
+ bfin_clear_PPI_STATUS();
+ bfin_config_dma(fbdev);
+ bfin_enable_ppi();
+ }
+
+ return IRQ_HANDLED;
+
+}
+
+static int proc_output(char *buf)
+{
+ char *p = buf;
+
+ p += sprintf(p,
+ "Usage:\n"
+ "echo 0x[REG][Value] > adv7393\n"
+ "example: echo 0x1234 >adv7393\n"
+ "writes 0x34 into Register 0x12\n");
+
+ return p - buf;
+}
+
+static int
+adv7393_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = proc_output(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 int
+adv7393_write_proc(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+{
+ struct adv7393fb_device *fbdev = data;
+ char line[8];
+ unsigned int val;
+ int ret;
+
+ ret = copy_from_user(line, buffer, count);
+ if (ret)
+ return -EFAULT;
+
+ val = simple_strtoul(line, NULL, 0);
+ adv7393_write(fbdev->client, val >> 8, val & 0xff);
+
+ return count;
+}
+
+static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct proc_dir_entry *entry;
+ int num_modes = ARRAY_SIZE(known_modes);
+
+ struct adv7393fb_device *fbdev = NULL;
+
+ if (mem > 2) {
+ dev_err(&client->dev, "mem out of allowed range [1;2]\n");
+ return -EINVAL;
+ }
+
+ if (mode > num_modes) {
+ dev_err(&client->dev, "mode %d: not supported", mode);
+ return -EFAULT;
+ }
+
+ fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+ if (!fbdev) {
+ dev_err(&client->dev, "failed to allocate device private record");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, fbdev);
+
+ fbdev->modes = known_modes;
+ fbdev->client = client;
+
+ fbdev->fb_len =
+ mem * fbdev->modes[mode].xres * fbdev->modes[mode].xres *
+ (fbdev->modes[mode].bpp / 8);
+
+ fbdev->line_len =
+ fbdev->modes[mode].xres * (fbdev->modes[mode].bpp / 8);
+
+ /* Workaround "PPI Does Not Start Properly In Specific Mode" */
+ if (ANOMALY_05000400) {
+ if (gpio_request(P_IDENT(P_PPI0_FS3), "PPI0_FS3")) {
+ dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n");
+ ret = -EBUSY;
+ goto out_8;
+ }
+ gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
+ }
+
+ if (peripheral_request_list(ppi_pins, DRIVER_NAME)) {
+ dev_err(&client->dev, "requesting PPI peripheral failed\n");
+ ret = -EFAULT;
+ goto out_8;
+ }
+
+ fbdev->fb_mem =
+ dma_alloc_coherent(NULL, fbdev->fb_len, &fbdev->dma_handle,
+ GFP_KERNEL);
+
+ if (NULL == fbdev->fb_mem) {
+ dev_err(&client->dev, "couldn't allocate dma buffer (%d bytes)\n",
+ (u32) fbdev->fb_len);
+ ret = -ENOMEM;
+ goto out_7;
+ }
+
+ fbdev->info.screen_base = (void *)fbdev->fb_mem;
+ bfin_adv7393_fb_fix.smem_start = (int)fbdev->fb_mem;
+
+ bfin_adv7393_fb_fix.smem_len = fbdev->fb_len;
+ bfin_adv7393_fb_fix.line_length = fbdev->line_len;
+
+ if (mem > 1)
+ bfin_adv7393_fb_fix.ypanstep = 1;
+
+ bfin_adv7393_fb_defined.red.length = 5;
+ bfin_adv7393_fb_defined.green.length = 6;
+ bfin_adv7393_fb_defined.blue.length = 5;
+
+ bfin_adv7393_fb_defined.xres = fbdev->modes[mode].xres;
+ bfin_adv7393_fb_defined.yres = fbdev->modes[mode].yres;
+ bfin_adv7393_fb_defined.xres_virtual = fbdev->modes[mode].xres;
+ bfin_adv7393_fb_defined.yres_virtual = mem * fbdev->modes[mode].yres;
+ bfin_adv7393_fb_defined.bits_per_pixel = fbdev->modes[mode].bpp;
+
+ fbdev->info.fbops = &bfin_adv7393_fb_ops;
+ fbdev->info.var = bfin_adv7393_fb_defined;
+ fbdev->info.fix = bfin_adv7393_fb_fix;
+ fbdev->info.par = &bfin_par;
+ fbdev->info.flags = FBINFO_DEFAULT;
+
+ fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (!fbdev->info.pseudo_palette) {
+ dev_err(&client->dev, "failed to allocate pseudo_palette\n");
+ ret = -ENOMEM;
+ goto out_6;
+ }
+
+ if (fb_alloc_cmap(&fbdev->info.cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+ dev_err(&client->dev, "failed to allocate colormap (%d entries)\n",
+ BFIN_LCD_NBR_PALETTE_ENTRIES);
+ ret = -EFAULT;
+ goto out_5;
+ }
+
+ if (request_dma(CH_PPI, "BF5xx_PPI_DMA") < 0) {
+ dev_err(&client->dev, "unable to request PPI DMA\n");
+ ret = -EFAULT;
+ goto out_4;
+ }
+
+ if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, IRQF_DISABLED,
+ "PPI ERROR", fbdev) < 0) {
+ dev_err(&client->dev, "unable to request PPI ERROR IRQ\n");
+ ret = -EFAULT;
+ goto out_3;
+ }
+
+ fbdev->open = 0;
+
+ ret = adv7393_write_block(client, fbdev->modes[mode].adv7393_i2c_initd,
+ fbdev->modes[mode].adv7393_i2c_initd_len);
+
+ if (ret) {
+ dev_err(&client->dev, "i2c attach: init error\n");
+ goto out_1;
+ }
+
+
+ if (register_framebuffer(&fbdev->info) < 0) {
+ dev_err(&client->dev, "unable to register framebuffer\n");
+ ret = -EFAULT;
+ goto out_1;
+ }
+
+ dev_info(&client->dev, "fb%d: %s frame buffer device\n",
+ fbdev->info.node, fbdev->info.fix.id);
+ dev_info(&client->dev, "fb memory address : 0x%p\n", fbdev->fb_mem);
+
+ entry = create_proc_entry("driver/adv7393", 0, NULL);
+ if (!entry) {
+ dev_err(&client->dev, "unable to create /proc entry\n");
+ ret = -EFAULT;
+ goto out_0;
+ }
+
+ entry->read_proc = adv7393_read_proc;
+ entry->write_proc = adv7393_write_proc;
+ entry->data = fbdev;
+
+ return 0;
+
+ out_0:
+ unregister_framebuffer(&fbdev->info);
+ out_1:
+ free_irq(IRQ_PPI_ERROR, fbdev);
+ out_3:
+ free_dma(CH_PPI);
+ out_4:
+ dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem,
+ fbdev->dma_handle);
+ out_5:
+ fb_dealloc_cmap(&fbdev->info.cmap);
+ out_6:
+ kfree(fbdev->info.pseudo_palette);
+ out_7:
+ peripheral_free_list(ppi_pins);
+ out_8:
+ kfree(fbdev);
+
+ return ret;
+}
+
+static int bfin_adv7393_fb_open(struct fb_info *info, int user)
+{
+ struct adv7393fb_device *fbdev = to_adv7393fb_device(info);
+
+ fbdev->info.screen_base = (void *)fbdev->fb_mem;
+ if (!fbdev->info.screen_base) {
+ dev_err(&fbdev->client->dev, "unable to map device\n");
+ return -ENOMEM;
+ }
+
+ fbdev->open = 1;
+ dma_desc_list(fbdev, BUILD);
+ adv7393_mode(fbdev->client, BLANK_OFF);
+ bfin_config_ppi(fbdev);
+ bfin_config_dma(fbdev);
+ bfin_enable_ppi();
+
+ return 0;
+}
+
+static int bfin_adv7393_fb_release(struct fb_info *info, int user)
+{
+ struct adv7393fb_device *fbdev = to_adv7393fb_device(info);
+
+ adv7393_mode(fbdev->client, BLANK_ON);
+ bfin_disable_dma();
+ bfin_disable_ppi();
+ dma_desc_list(fbdev, DESTRUCT);
+ fbdev->open = 0;
+ return 0;
+}
+
+static int
+bfin_adv7393_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+
+ switch (var->bits_per_pixel) {
+ case 16:/* DIRECTCOLOUR, 64k */
+ var->red.offset = info->var.red.offset;
+ var->green.offset = info->var.green.offset;
+ var->blue.offset = info->var.blue.offset;
+ var->red.length = info->var.red.length;
+ var->green.length = info->var.green.length;
+ var->blue.length = info->var.blue.length;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ break;
+ default:
+ pr_debug("%s: depth not supported: %u BPP\n", __func__,
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if (info->var.xres != var->xres ||
+ info->var.yres != var->yres ||
+ info->var.xres_virtual != var->xres_virtual ||
+ info->var.yres_virtual != var->yres_virtual) {
+ pr_debug("%s: Resolution not supported: X%u x Y%u\n",
+ __func__, var->xres, var->yres);
+ return -EINVAL;
+ }
+
+ /*
+ * Memory limit
+ */
+
+ if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
+ pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
+ __func__, var->yres_virtual);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int
+bfin_adv7393_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int dy;
+ u32 dmaaddr;
+ struct adv7393fb_device *fbdev = to_adv7393fb_device(info);
+
+ if (!var || !info)
+ return -EINVAL;
+
+ if (var->xoffset - info->var.xoffset) {
+ /* No support for X panning for now! */
+ return -EINVAL;
+ }
+ dy = var->yoffset - info->var.yoffset;
+
+ if (dy) {
+ pr_debug("%s: Panning screen of %d lines\n", __func__, dy);
+
+ dmaaddr = fbdev->av1->start_addr;
+ dmaaddr += (info->fix.line_length * dy);
+ /* TODO: Wait for current frame to finished */
+
+ fbdev->av1->start_addr = (unsigned long)dmaaddr;
+ fbdev->av2->start_addr = (unsigned long)dmaaddr + fbdev->line_len;
+ }
+
+ return 0;
+
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static int bfin_adv7393_fb_blank(int blank, struct fb_info *info)
+{
+ struct adv7393fb_device *fbdev = to_adv7393fb_device(info);
+
+ switch (blank) {
+
+ case VESA_NO_BLANKING:
+ /* Turn on panel */
+ adv7393_mode(fbdev->client, BLANK_OFF);
+ break;
+
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ case VESA_POWERDOWN:
+ /* Turn off panel */
+ adv7393_mode(fbdev->client, BLANK_ON);
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+int bfin_adv7393_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ if (nocursor)
+ return 0;
+ else
+ return -EINVAL; /* just to force soft_cursor() call */
+}
+
+static int bfin_adv7393_fb_setcolreg(u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp,
+ struct fb_info *info)
+{
+ if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
+ return -EINVAL;
+
+ if (info->var.grayscale)
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 value;
+ /* Place color in the pseudopalette */
+ if (regno > 16)
+ return -EINVAL;
+
+ red >>= (16 - info->var.red.length);
+ green >>= (16 - info->var.green.length);
+ blue >>= (16 - info->var.blue.length);
+
+ value = (red << info->var.red.offset) |
+ (green << info->var.green.offset)|
+ (blue << info->var.blue.offset);
+ value &= 0xFFFF;
+
+ ((u32 *) (info->pseudo_palette))[regno] = value;
+ }
+
+ return 0;
+}
+
+static int __devexit bfin_adv7393_fb_remove(struct i2c_client *client)
+{
+ struct adv7393fb_device *fbdev = i2c_get_clientdata(client);
+
+ adv7393_mode(client, POWER_DOWN);
+
+ if (fbdev->fb_mem)
+ dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem, fbdev->dma_handle);
+ free_dma(CH_PPI);
+ free_irq(IRQ_PPI_ERROR, fbdev);
+ unregister_framebuffer(&fbdev->info);
+ remove_proc_entry("driver/adv7393", NULL);
+ fb_dealloc_cmap(&fbdev->info.cmap);
+ kfree(fbdev->info.pseudo_palette);
+
+ if (ANOMALY_05000400)
+ gpio_free(P_IDENT(P_PPI0_FS3)); /* FS3 */
+ peripheral_free_list(ppi_pins);
+ kfree(fbdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_adv7393_fb_suspend(struct device *dev)
+{
+ struct adv7393fb_device *fbdev = dev_get_drvdata(dev);
+
+ if (fbdev->open) {
+ bfin_disable_dma();
+ bfin_disable_ppi();
+ dma_desc_list(fbdev, DESTRUCT);
+ }
+ adv7393_mode(fbdev->client, POWER_DOWN);
+
+ return 0;
+}
+
+static int bfin_adv7393_fb_resume(struct device *dev)
+{
+ struct adv7393fb_device *fbdev = dev_get_drvdata(dev);
+
+ adv7393_mode(fbdev->client, POWER_ON);
+
+ if (fbdev->open) {
+ dma_desc_list(fbdev, BUILD);
+ bfin_config_ppi(fbdev);
+ bfin_config_dma(fbdev);
+ bfin_enable_ppi();
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops bfin_adv7393_dev_pm_ops = {
+ .suspend = bfin_adv7393_fb_suspend,
+ .resume = bfin_adv7393_fb_resume,
+};
+#endif
+
+static const struct i2c_device_id bfin_adv7393_id[] = {
+ {DRIVER_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bfin_adv7393_id);
+
+static struct i2c_driver bfin_adv7393_fb_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &bfin_adv7393_dev_pm_ops,
+#endif
+ },
+ .probe = bfin_adv7393_fb_probe,
+ .remove = __devexit_p(bfin_adv7393_fb_remove),
+ .id_table = bfin_adv7393_id,
+};
+
+static int __init bfin_adv7393_fb_driver_init(void)
+{
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+ request_module("i2c-bfin-twi");
+#else
+ request_module("i2c-gpio");
+#endif
+
+ return i2c_add_driver(&bfin_adv7393_fb_driver);
+}
+module_init(bfin_adv7393_fb_driver_init);
+
+static void __exit bfin_adv7393_fb_driver_cleanup(void)
+{
+ i2c_del_driver(&bfin_adv7393_fb_driver);
+}
+module_exit(bfin_adv7393_fb_driver_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Frame buffer driver for ADV7393/2 Video Encoder");
+
+module_param(mode, int, 0);
+MODULE_PARM_DESC(mode,
+ "Video Mode (0=NTSC,1=PAL,2=NTSC 640x480,3=PAL 640x480,4=NTSC YCbCr input,5=PAL YCbCr input)");
+
+module_param(mem, int, 0);
+MODULE_PARM_DESC(mem,
+ "Size of frame buffer memory 1=Single 2=Double Size (allows y-panning / frame stacking)");
+
+module_param(nocursor, int, 0644);
+MODULE_PARM_DESC(nocursor, "cursor enable/disable");
diff --git a/drivers/video/bfin_adv7393fb.h b/drivers/video/bfin_adv7393fb.h
new file mode 100644
index 000000000000..8c7f9e4fc6eb
--- /dev/null
+++ b/drivers/video/bfin_adv7393fb.h
@@ -0,0 +1,321 @@
+/*
+ * Frame buffer driver for ADV7393/2 video encoder
+ *
+ * Copyright 2006-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or late.
+ */
+
+#ifndef __BFIN_ADV7393FB_H__
+#define __BFIN_ADV7393FB_H__
+
+#define BFIN_LCD_NBR_PALETTE_ENTRIES 256
+
+#ifdef CONFIG_NTSC
+# define VMODE 0
+#endif
+#ifdef CONFIG_PAL
+# define VMODE 1
+#endif
+#ifdef CONFIG_NTSC_640x480
+# define VMODE 2
+#endif
+#ifdef CONFIG_PAL_640x480
+# define VMODE 3
+#endif
+#ifdef CONFIG_NTSC_YCBCR
+# define VMODE 4
+#endif
+#ifdef CONFIG_PAL_YCBCR
+# define VMODE 5
+#endif
+
+#ifndef VMODE
+# define VMODE 1
+#endif
+
+#ifdef CONFIG_ADV7393_2XMEM
+# define VMEM 2
+#else
+# define VMEM 1
+#endif
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536) || defined(CONFIG_BF534)
+# define DMA_CFG_VAL 0x7935 /* Set Sync Bit */
+# define VB_DUMMY_MEMORY_SOURCE L1_DATA_B_START
+#else
+# define DMA_CFG_VAL 0x7915
+# define VB_DUMMY_MEMORY_SOURCE BOOT_ROM_START
+#endif
+
+enum {
+ DESTRUCT,
+ BUILD,
+};
+
+enum {
+ POWER_ON,
+ POWER_DOWN,
+ BLANK_ON,
+ BLANK_OFF,
+};
+
+#define DRIVER_NAME "bfin-adv7393"
+
+struct adv7393fb_modes {
+ const s8 name[25]; /* Full name */
+ u16 xres; /* Active Horizonzal Pixels */
+ u16 yres; /* Active Vertical Pixels */
+ u16 bpp;
+ u16 vmode;
+ u16 a_lines; /* Active Lines per Field */
+ u16 vb1_lines; /* Vertical Blanking Field 1 Lines */
+ u16 vb2_lines; /* Vertical Blanking Field 2 Lines */
+ u16 tot_lines; /* Total Lines per Frame */
+ u16 boeft_blank; /* Before Odd/Even Field Transition No. of Blank Pixels */
+ u16 aoeft_blank; /* After Odd/Even Field Transition No. of Blank Pixels */
+ const s8 *adv7393_i2c_initd;
+ u16 adv7393_i2c_initd_len;
+};
+
+static const u8 init_NTSC_TESTPATTERN[] = {
+ 0x00, 0x1E, /* Power up all DACs and PLL */
+ 0x01, 0x00, /* SD-Only Mode */
+ 0x80, 0x10, /* SSAF Luma Filter Enabled, NTSC Mode */
+ 0x82, 0xCB, /* Step control on, pixel data valid, pedestal on, PrPb SSAF on, CVBS/YC output */
+ 0x84, 0x40, /* SD Color Bar Test Pattern Enabled, DAC 2 = Luma, DAC 3 = Chroma */
+};
+
+static const u8 init_NTSC[] = {
+ 0x00, 0x1E, /* Power up all DACs and PLL */
+ 0xC3, 0x26, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC5, 0x12, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC2, 0x4A, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC6, 0x5E, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xBD, 0x19, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xBF, 0x42, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0x8C, 0x1F, /* NTSC Subcarrier Frequency */
+ 0x8D, 0x7C, /* NTSC Subcarrier Frequency */
+ 0x8E, 0xF0, /* NTSC Subcarrier Frequency */
+ 0x8F, 0x21, /* NTSC Subcarrier Frequency */
+ 0x01, 0x00, /* SD-Only Mode */
+ 0x80, 0x30, /* SSAF Luma Filter Enabled, NTSC Mode */
+ 0x82, 0x8B, /* Step control on, pixel data invalid, pedestal on, PrPb SSAF on, CVBS/YC output */
+ 0x87, 0x80, /* SD Color Bar Test Pattern Enabled, DAC 2 = Luma, DAC 3 = Chroma */
+ 0x86, 0x82,
+ 0x8B, 0x11,
+ 0x88, 0x20,
+ 0x8A, 0x0d,
+};
+
+static const u8 init_PAL[] = {
+ 0x00, 0x1E, /* Power up all DACs and PLL */
+ 0xC3, 0x26, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC5, 0x12, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC2, 0x4A, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xC6, 0x5E, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xBD, 0x19, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0xBF, 0x42, /* Program RGB->YCrCb Color Space convertion matrix */
+ 0x8C, 0xCB, /* PAL Subcarrier Frequency */
+ 0x8D, 0x8A, /* PAL Subcarrier Frequency */
+ 0x8E, 0x09, /* PAL Subcarrier Frequency */
+ 0x8F, 0x2A, /* PAL Subcarrier Frequency */
+ 0x01, 0x00, /* SD-Only Mode */
+ 0x80, 0x11, /* SSAF Luma Filter Enabled, PAL Mode */
+ 0x82, 0x8B, /* Step control on, pixel data invalid, pedestal on, PrPb SSAF on, CVBS/YC output */
+ 0x87, 0x80, /* SD Color Bar Test Pattern Enabled, DAC 2 = Luma, DAC 3 = Chroma */
+ 0x86, 0x82,
+ 0x8B, 0x11,
+ 0x88, 0x20,
+ 0x8A, 0x0d,
+};
+
+static const u8 init_NTSC_YCbCr[] = {
+ 0x00, 0x1E, /* Power up all DACs and PLL */
+ 0x8C, 0x1F, /* NTSC Subcarrier Frequency */
+ 0x8D, 0x7C, /* NTSC Subcarrier Frequency */
+ 0x8E, 0xF0, /* NTSC Subcarrier Frequency */
+ 0x8F, 0x21, /* NTSC Subcarrier Frequency */
+ 0x01, 0x00, /* SD-Only Mode */
+ 0x80, 0x30, /* SSAF Luma Filter Enabled, NTSC Mode */
+ 0x82, 0x8B, /* Step control on, pixel data invalid, pedestal on, PrPb SSAF on, CVBS/YC output */
+ 0x87, 0x00, /* DAC 2 = Luma, DAC 3 = Chroma */
+ 0x86, 0x82,
+ 0x8B, 0x11,
+ 0x88, 0x08,
+ 0x8A, 0x0d,
+};
+
+static const u8 init_PAL_YCbCr[] = {
+ 0x00, 0x1E, /* Power up all DACs and PLL */
+ 0x8C, 0xCB, /* PAL Subcarrier Frequency */
+ 0x8D, 0x8A, /* PAL Subcarrier Frequency */
+ 0x8E, 0x09, /* PAL Subcarrier Frequency */
+ 0x8F, 0x2A, /* PAL Subcarrier Frequency */
+ 0x01, 0x00, /* SD-Only Mode */
+ 0x80, 0x11, /* SSAF Luma Filter Enabled, PAL Mode */
+ 0x82, 0x8B, /* Step control on, pixel data invalid, pedestal on, PrPb SSAF on, CVBS/YC output */
+ 0x87, 0x00, /* DAC 2 = Luma, DAC 3 = Chroma */
+ 0x86, 0x82,
+ 0x8B, 0x11,
+ 0x88, 0x08,
+ 0x8A, 0x0d,
+};
+
+static struct adv7393fb_modes known_modes[] = {
+ /* NTSC 720x480 CRT */
+ {
+ .name = "NTSC 720x480",
+ .xres = 720,
+ .yres = 480,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 240,
+ .vb1_lines = 22,
+ .vb2_lines = 23,
+ .tot_lines = 525,
+ .boeft_blank = 16,
+ .aoeft_blank = 122,
+ .adv7393_i2c_initd = init_NTSC,
+ .adv7393_i2c_initd_len = sizeof(init_NTSC)
+ },
+ /* PAL 720x480 CRT */
+ {
+ .name = "PAL 720x576",
+ .xres = 720,
+ .yres = 576,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 288,
+ .vb1_lines = 24,
+ .vb2_lines = 25,
+ .tot_lines = 625,
+ .boeft_blank = 12,
+ .aoeft_blank = 132,
+ .adv7393_i2c_initd = init_PAL,
+ .adv7393_i2c_initd_len = sizeof(init_PAL)
+ },
+ /* NTSC 640x480 CRT Experimental */
+ {
+ .name = "NTSC 640x480",
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 240,
+ .vb1_lines = 22,
+ .vb2_lines = 23,
+ .tot_lines = 525,
+ .boeft_blank = 16 + 40,
+ .aoeft_blank = 122 + 40,
+ .adv7393_i2c_initd = init_NTSC,
+ .adv7393_i2c_initd_len = sizeof(init_NTSC)
+ },
+ /* PAL 640x480 CRT Experimental */
+ {
+ .name = "PAL 640x480",
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 288 - 20,
+ .vb1_lines = 24 + 20,
+ .vb2_lines = 25 + 20,
+ .tot_lines = 625,
+ .boeft_blank = 12 + 40,
+ .aoeft_blank = 132 + 40,
+ .adv7393_i2c_initd = init_PAL,
+ .adv7393_i2c_initd_len = sizeof(init_PAL)
+ },
+ /* NTSC 720x480 YCbCR */
+ {
+ .name = "NTSC 720x480 YCbCR",
+ .xres = 720,
+ .yres = 480,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 240,
+ .vb1_lines = 22,
+ .vb2_lines = 23,
+ .tot_lines = 525,
+ .boeft_blank = 16,
+ .aoeft_blank = 122,
+ .adv7393_i2c_initd = init_NTSC_YCbCr,
+ .adv7393_i2c_initd_len = sizeof(init_NTSC_YCbCr)
+ },
+ /* PAL 720x480 CRT */
+ {
+ .name = "PAL 720x576 YCbCR",
+ .xres = 720,
+ .yres = 576,
+ .bpp = 16,
+ .vmode = FB_VMODE_INTERLACED,
+ .a_lines = 288,
+ .vb1_lines = 24,
+ .vb2_lines = 25,
+ .tot_lines = 625,
+ .boeft_blank = 12,
+ .aoeft_blank = 132,
+ .adv7393_i2c_initd = init_PAL_YCbCr,
+ .adv7393_i2c_initd_len = sizeof(init_PAL_YCbCr)
+ }
+};
+
+struct adv7393fb_regs {
+
+};
+
+struct adv7393fb_device {
+ struct fb_info info; /* FB driver info record */
+
+ struct i2c_client *client;
+
+ struct dmasg *descriptor_list_head;
+ struct dmasg *vb1;
+ struct dmasg *av1;
+ struct dmasg *vb2;
+ struct dmasg *av2;
+
+ dma_addr_t dma_handle;
+
+ struct fb_info bfin_adv7393_fb;
+
+ struct adv7393fb_modes *modes;
+
+ struct adv7393fb_regs *regs; /* Registers memory map */
+ size_t regs_len;
+ size_t fb_len;
+ size_t line_len;
+ u16 open;
+ u16 *fb_mem; /* RGB Buffer */
+
+};
+
+#define to_adv7393fb_device(_info) \
+ (_info ? container_of(_info, struct adv7393fb_device, info) : NULL);
+
+static int bfin_adv7393_fb_open(struct fb_info *info, int user);
+static int bfin_adv7393_fb_release(struct fb_info *info, int user);
+static int bfin_adv7393_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+
+static int bfin_adv7393_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+
+static int bfin_adv7393_fb_blank(int blank, struct fb_info *info);
+
+static void bfin_config_ppi(struct adv7393fb_device *fbdev);
+static int bfin_config_dma(struct adv7393fb_device *fbdev);
+static void bfin_disable_dma(void);
+static void bfin_enable_ppi(void);
+static void bfin_disable_ppi(void);
+
+static inline int adv7393_write(struct i2c_client *client, u8 reg, u8 value);
+static inline int adv7393_read(struct i2c_client *client, u8 reg);
+static int adv7393_write_block(struct i2c_client *client, const u8 *data,
+ unsigned int len);
+
+int bfin_adv7393_fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
+static int bfin_adv7393_fb_setcolreg(u_int, u_int, u_int, u_int,
+ u_int, struct fb_info *info);
+
+#endif
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index 6b19136aa181..caaa27d4a46a 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -654,7 +654,7 @@ static int __devinit carminefb_probe(struct pci_dev *dev,
printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
"are required.", carminefb_fix.smem_len,
CARMINE_TOTAL_DIPLAY_MEM);
- goto err_free_reg_mmio;
+ goto err_unmap_vregs;
}
if (!request_mem_region(carminefb_fix.smem_start,
@@ -667,8 +667,6 @@ static int __devinit carminefb_probe(struct pci_dev *dev,
carminefb_fix.smem_len);
if (!hw->screen_mem) {
printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
- release_mem_region(carminefb_fix.smem_start,
- carminefb_fix.smem_len);
goto err_reg_smem;
}
@@ -710,7 +708,7 @@ err_deinit_hw:
err_unmap_screen:
iounmap(hw->screen_mem);
err_reg_smem:
- release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
+ release_mem_region(carminefb_fix.smem_start, carminefb_fix.smem_len);
err_unmap_vregs:
iounmap(hw->v_regs);
err_free_reg_mmio:
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 54e32c513610..c97491b8b39b 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -47,7 +47,6 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/screen_info.h>
-#include <linux/smp_lock.h>
#include <video/vga.h>
#include <asm/io.h>
@@ -376,7 +375,8 @@ static const char *vgacon_startup(void)
u16 saved1, saved2;
volatile u16 *p;
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) {
+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
+ screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
no_vga:
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index cad7d45c8bac..c265aed09e04 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -1029,10 +1029,6 @@ static int __init fb_probe(struct platform_device *device)
goto err_release_pl_mem;
}
- ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
- if (ret)
- goto err_release_pl_mem;
-
/* Initialize par */
da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
@@ -1060,7 +1056,7 @@ static int __init fb_probe(struct platform_device *device)
ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
if (ret)
- goto err_free_irq;
+ goto err_release_pl_mem;
da8xx_fb_info->cmap.len = par->palette_sz;
/* initialize var_screeninfo */
@@ -1088,8 +1084,13 @@ static int __init fb_probe(struct platform_device *device)
goto err_cpu_freq;
}
#endif
+
+ ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
+ if (ret)
+ goto irq_freq;
return 0;
+irq_freq:
#ifdef CONFIG_CPU_FREQ
err_cpu_freq:
unregister_framebuffer(da8xx_fb_info);
@@ -1098,9 +1099,6 @@ err_cpu_freq:
err_dealloc_cmap:
fb_dealloc_cmap(&da8xx_fb_info->cmap);
-err_free_irq:
- free_irq(par->irq, par);
-
err_release_pl_mem:
dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
par->p_palette_base);
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index 0c99de0562ca..b358d045f130 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -483,7 +483,7 @@ static void ep93xxfb_dealloc_videomem(struct fb_info *info)
info->screen_base, info->fix.smem_start);
}
-static int __init ep93xxfb_probe(struct platform_device *pdev)
+static int __devinit ep93xxfb_probe(struct platform_device *pdev)
{
struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
struct fb_info *info;
@@ -598,7 +598,7 @@ failed:
return err;
}
-static int ep93xxfb_remove(struct platform_device *pdev)
+static int __devexit ep93xxfb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
struct ep93xx_fbi *fbi = info->par;
@@ -622,7 +622,7 @@ static int ep93xxfb_remove(struct platform_device *pdev)
static struct platform_driver ep93xxfb_driver = {
.probe = ep93xxfb_probe,
- .remove = ep93xxfb_remove,
+ .remove = __devexit_p(ep93xxfb_remove),
.driver = {
.name = "ep93xx-fb",
.owner = THIS_MODULE,
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 6b93ef93cb12..804000183c5e 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -75,7 +75,7 @@ int fb_deferred_io_fsync(struct file *file, int datasync)
return 0;
/* Kill off the delayed work */
- cancel_rearming_delayed_work(&info->deferred_work);
+ cancel_delayed_work_sync(&info->deferred_work);
/* Run it immediately */
return schedule_delayed_work(&info->deferred_work, 0);
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index f53b9f1d6aba..5c3960da755a 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -80,6 +80,7 @@ static const struct fb_cmap default_16_colors = {
* @cmap: frame buffer colormap structure
* @len: length of @cmap
* @transp: boolean, 1 if there is transparency, 0 otherwise
+ * @flags: flags for kmalloc memory allocation
*
* Allocates memory for a colormap @cmap. @len is the
* number of entries in the palette.
@@ -88,34 +89,48 @@ static const struct fb_cmap default_16_colors = {
*
*/
-int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
{
- int size = len*sizeof(u16);
-
- if (cmap->len != len) {
- fb_dealloc_cmap(cmap);
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- goto fail;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
+ int size = len * sizeof(u16);
+ int ret = -ENOMEM;
+
+ if (cmap->len != len) {
+ fb_dealloc_cmap(cmap);
+ if (!len)
+ return 0;
+
+ cmap->red = kmalloc(size, flags);
+ if (!cmap->red)
+ goto fail;
+ cmap->green = kmalloc(size, flags);
+ if (!cmap->green)
+ goto fail;
+ cmap->blue = kmalloc(size, flags);
+ if (!cmap->blue)
+ goto fail;
+ if (transp) {
+ cmap->transp = kmalloc(size, flags);
+ if (!cmap->transp)
+ goto fail;
+ } else {
+ cmap->transp = NULL;
+ }
+ }
+ cmap->start = 0;
+ cmap->len = len;
+ ret = fb_copy_cmap(fb_default_cmap(len), cmap);
+ if (ret)
goto fail;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- fb_copy_cmap(fb_default_cmap(len), cmap);
- return 0;
+ return 0;
fail:
- fb_dealloc_cmap(cmap);
- return -ENOMEM;
+ fb_dealloc_cmap(cmap);
+ return ret;
+}
+
+int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+ return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
}
/**
@@ -250,8 +265,12 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
int rc, size = cmap->len * sizeof(u16);
struct fb_cmap umap;
+ if (size < 0 || size < cmap->len)
+ return -E2BIG;
+
memset(&umap, 0, sizeof(struct fb_cmap));
- rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL);
+ rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
+ GFP_KERNEL);
if (rc)
return rc;
if (copy_from_user(umap.red, cmap->red, size) ||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 0e6aa3d96a42..4ac1201ad6c2 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1458,7 +1458,7 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
if (gen->base == hw->base)
return true;
/* is the generic aperture base inside the hw base->hw base+size */
- if (gen->base > hw->base && gen->base <= hw->base + hw->size)
+ if (gen->base > hw->base && gen->base < hw->base + hw->size)
return true;
return false;
}
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 563a98b88e9b..4f57485f8c54 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -973,6 +973,90 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK("========================================\n");
}
+/**
+ * fb_edid_add_monspecs() - add monitor video modes from E-EDID data
+ * @edid: 128 byte array with an E-EDID block
+ * @spacs: monitor specs to be extended
+ */
+void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+ unsigned char *block;
+ struct fb_videomode *m;
+ int num = 0, i;
+ u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE];
+ u8 pos = 4, svd_n = 0;
+
+ if (!edid)
+ return;
+
+ if (!edid_checksum(edid))
+ return;
+
+ if (edid[0] != 0x2 ||
+ edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
+ return;
+
+ DPRINTK(" Short Video Descriptors\n");
+
+ while (pos < edid[2]) {
+ u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
+ pr_debug("Data block %u of %u bytes\n", type, len);
+ if (type == 2)
+ for (i = pos; i < pos + len; i++) {
+ u8 idx = edid[pos + i] & 0x7f;
+ svd[svd_n++] = idx;
+ pr_debug("N%sative mode #%d\n",
+ edid[pos + i] & 0x80 ? "" : "on-n", idx);
+ }
+ pos += len + 1;
+ }
+
+ block = edid + edid[2];
+
+ DPRINTK(" Extended Detailed Timings\n");
+
+ for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE;
+ i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
+ if (PIXEL_CLOCK)
+ edt[num++] = block - edid;
+
+ /* Yikes, EDID data is totally useless */
+ if (!(num + svd_n))
+ return;
+
+ m = kzalloc((specs->modedb_len + num + svd_n) *
+ sizeof(struct fb_videomode), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode));
+
+ for (i = specs->modedb_len; i < specs->modedb_len + num; i++) {
+ get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]);
+ if (i == specs->modedb_len)
+ m[i].flag |= FB_MODE_IS_FIRST;
+ pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh);
+ }
+
+ for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) {
+ int idx = svd[i - specs->modedb_len - num];
+ if (!idx || idx > 63) {
+ pr_warning("Reserved SVD code %d\n", idx);
+ } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) {
+ pr_warning("Unimplemented SVD code %d\n", idx);
+ } else {
+ memcpy(&m[i], cea_modes + idx, sizeof(m[i]));
+ pr_debug("Adding SVD #%d: %ux%u@%u\n", idx,
+ m[i].xres, m[i].yres, m[i].refresh);
+ }
+ }
+
+ kfree(specs->modedb);
+ specs->modedb = m;
+ specs->modedb_len = specs->modedb_len + num + svd_n;
+}
+
/*
* VESA Generalized Timing Formula (GTF)
*/
@@ -1289,6 +1373,9 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
{
specs = NULL;
}
+void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+}
void fb_destroy_modedb(struct fb_videomode *modedb)
{
}
@@ -1396,6 +1483,7 @@ EXPORT_SYMBOL(fb_firmware_edid);
EXPORT_SYMBOL(fb_parse_edid);
EXPORT_SYMBOL(fb_edid_to_monspecs);
+EXPORT_SYMBOL(fb_edid_add_monspecs);
EXPORT_SYMBOL(fb_get_mode);
EXPORT_SYMBOL(fb_validate_mode);
EXPORT_SYMBOL(fb_destroy_modedb);
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index e4c4d89b7860..be8ccb47ebe0 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -22,6 +22,7 @@
#define DC_HFILT_COUNT 0x100
#define DC_VFILT_COUNT 0x100
#define VP_COEFF_SIZE 0x1000
+#define VP_PAL_COUNT 0x100
#define OUTPUT_CRT 0x01
#define OUTPUT_PANEL 0x02
@@ -48,7 +49,8 @@ struct lxfb_par {
uint64_t vp[VP_REG_COUNT];
uint64_t fp[FP_REG_COUNT];
- uint32_t pal[DC_PAL_COUNT];
+ uint32_t dc_pal[DC_PAL_COUNT];
+ uint32_t vp_pal[VP_PAL_COUNT];
uint32_t hcoeff[DC_HFILT_COUNT * 2];
uint32_t vcoeff[DC_VFILT_COUNT];
uint32_t vp_coeff[VP_COEFF_SIZE / 4];
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index bc35a95e59d4..79e9abc72b83 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -276,10 +276,10 @@ static void lx_graphics_enable(struct fb_info *info)
write_fp(par, FP_PT1, 0);
temp = FP_PT2_SCRC;
- if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
temp |= FP_PT2_HSP;
- if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
temp |= FP_PT2_VSP;
write_fp(par, FP_PT2, temp);
@@ -610,10 +610,15 @@ static void lx_save_regs(struct lxfb_par *par)
memcpy(par->vp, par->vp_regs, sizeof(par->vp));
memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp));
- /* save the palette */
+ /* save the display controller palette */
write_dc(par, DC_PAL_ADDRESS, 0);
- for (i = 0; i < ARRAY_SIZE(par->pal); i++)
- par->pal[i] = read_dc(par, DC_PAL_DATA);
+ for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
+ par->dc_pal[i] = read_dc(par, DC_PAL_DATA);
+
+ /* save the video processor palette */
+ write_vp(par, VP_PAR, 0);
+ for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
+ par->vp_pal[i] = read_vp(par, VP_PDR);
/* save the horizontal filter coefficients */
filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
@@ -706,8 +711,8 @@ static void lx_restore_display_ctlr(struct lxfb_par *par)
/* restore the palette */
write_dc(par, DC_PAL_ADDRESS, 0);
- for (i = 0; i < ARRAY_SIZE(par->pal); i++)
- write_dc(par, DC_PAL_DATA, par->pal[i]);
+ for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++)
+ write_dc(par, DC_PAL_DATA, par->dc_pal[i]);
/* restore the horizontal filter coefficients */
filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
@@ -751,6 +756,11 @@ static void lx_restore_video_proc(struct lxfb_par *par)
}
}
+ /* restore video processor palette */
+ write_vp(par, VP_PAR, 0);
+ for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++)
+ write_vp(par, VP_PDR, par->vp_pal[i]);
+
/* restore video coeff ram */
memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff));
}
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index af8f0f2cc782..4052718eefaa 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -454,7 +454,6 @@ static int hgafb_blank(int blank_mode, struct fb_info *info)
/*
* Accel functions
*/
-#ifdef CONFIG_FB_HGA_ACCEL
static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
u_int rows, y;
@@ -466,7 +465,7 @@ static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
dest = rowaddr(info, y) + (rect->dx >> 3);
switch (rect->rop) {
case ROP_COPY:
- //fb_memset(dest, rect->color, (rect->width >> 3));
+ memset_io(dest, rect->color, (rect->width >> 3));
break;
case ROP_XOR:
fb_writeb(~(fb_readb(dest)), dest);
@@ -488,7 +487,7 @@ static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
for (rows = area->height; rows--; ) {
src = rowaddr(info, y1) + (area->sx >> 3);
dest = rowaddr(info, y2) + (area->dx >> 3);
- //fb_memmove(dest, src, (area->width >> 3));
+ memmove(dest, src, (area->width >> 3));
y1++;
y2++;
}
@@ -499,7 +498,7 @@ static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
for (rows = area->height; rows--;) {
src = rowaddr(info, y1) + (area->sx >> 3);
dest = rowaddr(info, y2) + (area->dx >> 3);
- //fb_memmove(dest, src, (area->width >> 3));
+ memmove(dest, src, (area->width >> 3));
y1--;
y2--;
}
@@ -511,20 +510,17 @@ static void hgafb_imageblit(struct fb_info *info, const struct fb_image *image)
u8 __iomem *dest;
u8 *cdat = (u8 *) image->data;
u_int rows, y = image->dy;
+ u_int x;
u8 d;
for (rows = image->height; rows--; y++) {
- d = *cdat++;
- dest = rowaddr(info, y) + (image->dx >> 3);
- fb_writeb(d, dest);
+ for (x = 0; x < image->width; x+= 8) {
+ d = *cdat++;
+ dest = rowaddr(info, y) + ((image->dx + x)>> 3);
+ fb_writeb(d, dest);
+ }
}
}
-#else /* !CONFIG_FB_HGA_ACCEL */
-#define hgafb_fillrect cfb_fillrect
-#define hgafb_copyarea cfb_copyarea
-#define hgafb_imageblit cfb_imageblit
-#endif /* CONFIG_FB_HGA_ACCEL */
-
static struct fb_ops hgafb_ops = {
.owner = THIS_MODULE,
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index cd2c728a809b..7db17d0d8a8c 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -45,8 +45,10 @@ static void i810i2c_setscl(void *data, int state)
struct i810fb_par *par = chan->par;
u8 __iomem *mmio = par->mmio_start_virtual;
- i810_writel(mmio, chan->ddc_base, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
- SCL_DIR_MASK | SCL_VAL_MASK);
+ if (state)
+ i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK | SCL_VAL_MASK);
+ else
+ i810_writel(mmio, chan->ddc_base, SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
i810_readl(mmio, chan->ddc_base); /* flush posted write */
}
@@ -56,8 +58,10 @@ static void i810i2c_setsda(void *data, int state)
struct i810fb_par *par = chan->par;
u8 __iomem *mmio = par->mmio_start_virtual;
- i810_writel(mmio, chan->ddc_base, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
- SDA_DIR_MASK | SDA_VAL_MASK);
+ if (state)
+ i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK | SDA_VAL_MASK);
+ else
+ i810_writel(mmio, chan->ddc_base, SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
i810_readl(mmio, chan->ddc_base); /* flush posted write */
}
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 5c363d026f64..69bd4a581d4a 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -53,11 +53,8 @@
#define LCDC_SIZE 0x04
#define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
-#ifdef CONFIG_ARCH_MX1
-#define SIZE_YMAX(y) ((y) & 0x1ff)
-#else
-#define SIZE_YMAX(y) ((y) & 0x3ff)
-#endif
+#define YMAX_MASK (cpu_is_mx1() ? 0x1ff : 0x3ff)
+#define SIZE_YMAX(y) ((y) & YMAX_MASK)
#define LCDC_VPW 0x08
#define VPW_VPW(x) ((x) & 0x3ff)
@@ -623,7 +620,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
if (var->right_margin > 255)
printk(KERN_ERR "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 511)
+ if (var->yres < 1 || var->yres > YMAX_MASK)
printk(KERN_ERR "%s: invalid yres %d\n",
info->fix.id, var->yres);
if (var->vsync_len > 100)
@@ -977,6 +974,6 @@ static void __exit imxfb_cleanup(void)
module_init(imxfb_init);
module_exit(imxfb_cleanup);
-MODULE_DESCRIPTION("Motorola i.MX framebuffer driver");
+MODULE_DESCRIPTION("Freescale i.MX framebuffer driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 052dd9f0b760..a082debe824b 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -1247,46 +1247,46 @@ static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel;
};
/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
-static unsigned int mem; /* "matrox:mem:xxxxxM" */
+static unsigned int mem; /* "matroxfb:mem:xxxxxM" */
static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
-static int inv24; /* "matrox:inv24" */
-static int cross4MB = -1; /* "matrox:cross4MB" */
-static int disabled; /* "matrox:disabled" */
-static int noaccel; /* "matrox:noaccel" */
-static int nopan; /* "matrox:nopan" */
-static int no_pci_retry; /* "matrox:nopciretry" */
-static int novga; /* "matrox:novga" */
-static int nobios; /* "matrox:nobios" */
-static int noinit = 1; /* "matrox:init" */
-static int inverse; /* "matrox:inverse" */
-static int sgram; /* "matrox:sgram" */
+static int inv24; /* "matroxfb:inv24" */
+static int cross4MB = -1; /* "matroxfb:cross4MB" */
+static int disabled; /* "matroxfb:disabled" */
+static int noaccel; /* "matroxfb:noaccel" */
+static int nopan; /* "matroxfb:nopan" */
+static int no_pci_retry; /* "matroxfb:nopciretry" */
+static int novga; /* "matroxfb:novga" */
+static int nobios; /* "matroxfb:nobios" */
+static int noinit = 1; /* "matroxfb:init" */
+static int inverse; /* "matroxfb:inverse" */
+static int sgram; /* "matroxfb:sgram" */
#ifdef CONFIG_MTRR
-static int mtrr = 1; /* "matrox:nomtrr" */
+static int mtrr = 1; /* "matroxfb:nomtrr" */
#endif
-static int grayscale; /* "matrox:grayscale" */
-static int dev = -1; /* "matrox:dev:xxxxx" */
-static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
-static int depth = -1; /* "matrox:depth:xxxxx" */
-static unsigned int xres; /* "matrox:xres:xxxxx" */
-static unsigned int yres; /* "matrox:yres:xxxxx" */
-static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
-static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
-static unsigned int vslen; /* "matrox:vslen:xxxxx" */
-static unsigned int left = ~0; /* "matrox:left:xxxxx" */
-static unsigned int right = ~0; /* "matrox:right:xxxxx" */
-static unsigned int hslen; /* "matrox:hslen:xxxxx" */
-static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */
-static int sync = -1; /* "matrox:sync:xxxxx" */
-static unsigned int fv; /* "matrox:fv:xxxxx" */
-static unsigned int fh; /* "matrox:fh:xxxxxk" */
-static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */
-static int dfp; /* "matrox:dfp */
-static int dfp_type = -1; /* "matrox:dfp:xxx */
-static int memtype = -1; /* "matrox:memtype:xxx" */
-static char outputs[8]; /* "matrox:outputs:xxx" */
+static int grayscale; /* "matroxfb:grayscale" */
+static int dev = -1; /* "matroxfb:dev:xxxxx" */
+static unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */
+static int depth = -1; /* "matroxfb:depth:xxxxx" */
+static unsigned int xres; /* "matroxfb:xres:xxxxx" */
+static unsigned int yres; /* "matroxfb:yres:xxxxx" */
+static unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */
+static unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */
+static unsigned int vslen; /* "matroxfb:vslen:xxxxx" */
+static unsigned int left = ~0; /* "matroxfb:left:xxxxx" */
+static unsigned int right = ~0; /* "matroxfb:right:xxxxx" */
+static unsigned int hslen; /* "matroxfb:hslen:xxxxx" */
+static unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */
+static int sync = -1; /* "matroxfb:sync:xxxxx" */
+static unsigned int fv; /* "matroxfb:fv:xxxxx" */
+static unsigned int fh; /* "matroxfb:fh:xxxxxk" */
+static unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */
+static int dfp; /* "matroxfb:dfp */
+static int dfp_type = -1; /* "matroxfb:dfp:xxx */
+static int memtype = -1; /* "matroxfb:memtype:xxx" */
+static char outputs[8]; /* "matroxfb:outputs:xxx" */
#ifndef MODULE
-static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */
+static char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */
#endif
static int matroxfb_getmemory(struct matrox_fb_info *minfo,
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 0a4dbdc1693a..48c3ea8652b6 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -32,252 +32,323 @@
const char *fb_mode_option;
EXPORT_SYMBOL_GPL(fb_mode_option);
- /*
- * Standard video mode definitions (taken from XFree86)
- */
+/*
+ * Standard video mode definitions (taken from XFree86)
+ */
static const struct fb_videomode modedb[] = {
- {
+
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
- NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 640x480 @ 60 Hz, 31.5 kHz hsync */
- NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 800x600 @ 56 Hz, 35.15 kHz hsync */
- NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
- NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8,
- 0, FB_VMODE_INTERLACED
- }, {
+ { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0,
+ FB_VMODE_INTERLACED },
+
/* 640x400 @ 85 Hz, 37.86 kHz hsync */
- NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
- FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+
/* 640x480 @ 72 Hz, 36.5 kHz hsync */
- NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 640x480 @ 75 Hz, 37.50 kHz hsync */
- NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 800x600 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 640x480 @ 85 Hz, 43.27 kHz hsync */
- NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
- NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
- 0, FB_VMODE_INTERLACED
- }, {
+ { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0,
+ FB_VMODE_INTERLACED },
/* 800x600 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
- NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 640x480 @ 100 Hz, 53.01 kHz hsync */
- NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 60 Hz, 53.5 kHz hsync */
- NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 800x600 @ 85 Hz, 55.84 kHz hsync */
- NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
- NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
- NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12,
- 0, FB_VMODE_INTERLACED
- }, {
+ { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
+ FB_VMODE_INTERLACED },
+
/* 800x600 @ 100 Hz, 64.02 kHz hsync */
- NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 76 Hz, 62.5 kHz hsync */
- NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 70 Hz, 62.4 kHz hsync */
- NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
- NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
- NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
- NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
- NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
- NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 78 Hz, 70.8 kHz hsync */
- NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
- NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1600x1200 @ 60Hz, 75.00 kHz hsync */
- NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 84 Hz, 76.0 kHz hsync */
- NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
- NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1024x768 @ 100Hz, 80.21 kHz hsync */
- NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
- NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
- NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x864 @ 100 Hz, 89.62 kHz hsync */
- NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
- NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
- NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
- NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
- NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
- NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1800x1440 @ 64Hz, 96.15 kHz hsync */
- NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1800x1440 @ 70Hz, 104.52 kHz hsync */
- NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 512x384 @ 78 Hz, 31.50 kHz hsync */
- NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 512x384 @ 85 Hz, 34.38 kHz hsync */
- NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
- NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0,
+ FB_VMODE_DOUBLE },
+
/* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
- NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0,
+ FB_VMODE_DOUBLE },
+
/* 320x240 @ 72 Hz, 36.5 kHz hsync */
- NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0,
+ FB_VMODE_DOUBLE },
+
/* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
- NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0,
+ FB_VMODE_DOUBLE },
+
/* 400x300 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0,
+ FB_VMODE_DOUBLE },
+
/* 400x300 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, 0,
+ FB_VMODE_DOUBLE },
+
/* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
- NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0,
+ FB_VMODE_DOUBLE },
+
/* 480x300 @ 60 Hz, 37.8 kHz hsync */
- NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0,
+ FB_VMODE_DOUBLE },
+
/* 480x300 @ 63 Hz, 39.6 kHz hsync */
- NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0,
+ FB_VMODE_DOUBLE },
+
/* 480x300 @ 72 Hz, 48.0 kHz hsync */
- NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3,
- 0, FB_VMODE_DOUBLE
- }, {
+ { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0,
+ FB_VMODE_DOUBLE },
+
/* 1920x1200 @ 60 Hz, 74.5 Khz hsync */
- NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
- NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED },
+
/* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
- NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5,
- 0, FB_VMODE_NONINTERLACED
- }, {
+ { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
- NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
- 0, FB_VMODE_NONINTERLACED
- }, {
- /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
- NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5,
- 0, FB_VMODE_INTERLACED
- }, {
- /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
- NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5,
- 0, FB_VMODE_INTERLACED
- },
+ { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0,
+ FB_VMODE_NONINTERLACED },
+
+ /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+ { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0,
+ FB_VMODE_INTERLACED },
+
+ /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+ { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0,
+ FB_VMODE_INTERLACED },
+
+ /* 864x480 @ 60 Hz, 35.15 kHz hsync */
+ { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0,
+ 0, FB_VMODE_NONINTERLACED },
};
#ifdef CONFIG_FB_MODE_HELPERS
+const struct fb_videomode cea_modes[64] = {
+ /* #1: 640x480p@59.94/60Hz */
+ [1] = {
+ NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #3: 720x480p@59.94/60Hz */
+ [3] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #5: 1920x1080i@59.94/60Hz */
+ [5] = {
+ NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED, 0,
+ },
+ /* #7: 720(1440)x480iH@59.94/60Hz */
+ [7] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED, 0,
+ },
+ /* #9: 720(1440)x240pH@59.94/60Hz */
+ [9] = {
+ NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #18: 720x576pH@50Hz */
+ [18] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #19: 1280x720p@50Hz */
+ [19] = {
+ NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #20: 1920x1080i@50Hz */
+ [20] = {
+ NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED, 0,
+ },
+ /* #32: 1920x1080p@23.98/24Hz */
+ [32] = {
+ NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+ /* #35: (2880)x480p4x@59.94/60Hz */
+ [35] = {
+ NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
+ FB_VMODE_NONINTERLACED, 0,
+ },
+};
+
const struct fb_videomode vesa_modes[] = {
/* 0 640x350-85 VESA */
{ NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3,
@@ -289,10 +360,10 @@ const struct fb_videomode vesa_modes[] = {
{ NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 3 640x480-60 VESA */
- { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
+ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 4 640x480-72 VESA */
- { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
+ { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 5 640x480-75 VESA */
{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
@@ -375,7 +446,7 @@ const struct fb_videomode vesa_modes[] = {
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 26 1600x1200-75 VESA */
- { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 27 1600x1200-85 VESA */
@@ -855,6 +926,7 @@ const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode,
abs(cmode->yres - mode->yres);
if (diff > d) {
diff = d;
+ diff_refresh = abs(cmode->refresh - mode->refresh);
best = cmode;
} else if (diff == d) {
d = abs(cmode->refresh - mode->refresh);
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 7cfc170bce19..cb013919e9ce 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <mach/dma.h>
#include <mach/hardware.h>
#include <mach/ipu.h>
#include <mach/mx3fb.h>
@@ -1420,6 +1421,9 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
struct device *dev;
struct mx3fb_platform_data *mx3fb_pdata;
+ if (!imx_dma_is_ipu(chan))
+ return false;
+
if (!rq)
return false;
@@ -1470,8 +1474,7 @@ static int mx3fb_probe(struct platform_device *pdev)
goto eremap;
}
- pr_debug("Remapped %x to %x at %p\n", sdc_reg->start, sdc_reg->end,
- mx3fb->reg_base);
+ pr_debug("Remapped %pR at %p\n", sdc_reg, mx3fb->reg_base);
/* IDMAC interface */
dmaengine_get();
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 81687ed26ba9..62498bd662fc 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -15,6 +15,7 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -597,9 +598,9 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev)
}
fbi->clk = clk_get(&pdev->dev, NULL);
- if (!fbi->clk || IS_ERR(fbi->clk)) {
+ if (IS_ERR(fbi->clk)) {
printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n");
- ret = -ENOENT;
+ ret = PTR_ERR(fbi->clk);
goto release_irq;
}
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 2fb552a6f32c..6aac6d1b937b 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -87,7 +87,7 @@ static int nvidia_bl_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops nvidia_bl_ops = {
+static const struct backlight_ops nvidia_bl_ops = {
.get_brightness = nvidia_bl_get_brightness,
.update_status = nvidia_bl_update_status,
};
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 455c6055325d..083c8fe53e24 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,7 +1,7 @@
config FB_OMAP
tristate "OMAP frame buffer support (EXPERIMENTAL)"
- depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
-
+ depends on FB && (OMAP2_DSS = "n")
+ depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 64dcc7439c99..90e3bdd1b7ab 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -396,7 +396,7 @@ static void mipid_esd_start_check(struct mipid_device *md)
static void mipid_esd_stop_check(struct mipid_device *md)
{
if (md->esd_check != NULL)
- cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work);
+ cancel_delayed_work_sync(&md->esd_work);
}
static void mipid_esd_work(struct work_struct *work)
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 12327bbfdbbb..940cab394c2e 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -1,11 +1,13 @@
menu "OMAP2/3 Display Device Drivers"
depends on OMAP2_DSS
-config PANEL_GENERIC
- tristate "Generic Panel"
+config PANEL_GENERIC_DPI
+ tristate "Generic DPI Panel"
help
- Generic panel driver.
- Used for DVI output for Beagle and OMAP3 SDP.
+ Generic DPI panel driver.
+ Supports DVI output for Beagle and OMAP3 SDP.
+ Supports LCD Panel used in TI SDP3430 and EVM boards,
+ OMAP3517 EVM boards and CM-T35.
config PANEL_SHARP_LS037V7DW01
tristate "Sharp LS037V7DW01 LCD Panel"
@@ -14,11 +16,12 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
-config PANEL_SHARP_LQ043T1DG01
- tristate "Sharp LQ043T1DG01 LCD Panel"
- depends on OMAP2_DSS
- help
- LCD Panel used in TI's OMAP3517 EVM boards
+config PANEL_NEC_NL8048HL11_01B
+ tristate "NEC NL8048HL11-01B Panel"
+ depends on OMAP2_DSS
+ help
+ This NEC NL8048HL11-01B panel is TFT LCD
+ used in the Zoom2/3/3630 sdp boards.
config PANEL_TAAL
tristate "Taal DSI Panel"
@@ -26,12 +29,6 @@ config PANEL_TAAL
help
Taal DSI command mode panel from TPO.
-config PANEL_TOPPOLY_TDO35S
- tristate "Toppoly TDO35S LCD Panel support"
- depends on OMAP2_DSS
- help
- LCD Panel used in CM-T35
-
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
depends on OMAP2_DSS && SPI
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index aa386095d7c4..861f0255ec6b 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,8 +1,7 @@
-obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
+obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
-obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
+obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
-obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
new file mode 100644
index 000000000000..07eb30ee59c8
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -0,0 +1,365 @@
+/*
+ * Generic DPI Panels support
+ *
+ * Copyright (C) 2010 Canonical Ltd.
+ * Author: Bryan Wu <bryan.wu@canonical.com>
+ *
+ * LCD panel driver for Sharp LQ043T1DG01
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * LCD panel driver for Toppoly TDO35S
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <plat/panel-generic-dpi.h>
+
+struct panel_config {
+ struct omap_video_timings timings;
+
+ int acbi; /* ac-bias pin transitions per interrupt */
+ /* Unit: line clocks */
+ int acb; /* ac-bias pin frequency */
+
+ enum omap_panel_config config;
+
+ int power_on_delay;
+ int power_off_delay;
+
+ /*
+ * Used to match device to panel configuration
+ * when use generic panel driver
+ */
+ const char *name;
+};
+
+/* Panel configurations */
+static struct panel_config generic_dpi_panels[] = {
+ /* Generic Panel */
+ {
+ {
+ .x_res = 640,
+ .y_res = 480,
+
+ .pixel_clock = 23500,
+
+ .hfp = 48,
+ .hsw = 32,
+ .hbp = 80,
+
+ .vfp = 3,
+ .vsw = 4,
+ .vbp = 7,
+ },
+ .acbi = 0x0,
+ .acb = 0x0,
+ .config = OMAP_DSS_LCD_TFT,
+ .power_on_delay = 0,
+ .power_off_delay = 0,
+ .name = "generic",
+ },
+
+ /* Sharp LQ043T1DG01 */
+ {
+ {
+ .x_res = 480,
+ .y_res = 272,
+
+ .pixel_clock = 9000,
+
+ .hsw = 42,
+ .hfp = 3,
+ .hbp = 2,
+
+ .vsw = 11,
+ .vfp = 3,
+ .vbp = 2,
+ },
+ .acbi = 0x0,
+ .acb = 0x0,
+ .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
+ .power_on_delay = 50,
+ .power_off_delay = 100,
+ .name = "sharp_lq",
+ },
+
+ /* Sharp LS037V7DW01 */
+ {
+ {
+ .x_res = 480,
+ .y_res = 640,
+
+ .pixel_clock = 19200,
+
+ .hsw = 2,
+ .hfp = 1,
+ .hbp = 28,
+
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 1,
+ },
+ .acbi = 0x0,
+ .acb = 0x28,
+ .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS,
+ .power_on_delay = 50,
+ .power_off_delay = 100,
+ .name = "sharp_ls",
+ },
+
+ /* Toppoly TDO35S */
+ {
+ {
+ .x_res = 480,
+ .y_res = 640,
+
+ .pixel_clock = 26000,
+
+ .hfp = 104,
+ .hsw = 8,
+ .hbp = 8,
+
+ .vfp = 4,
+ .vsw = 2,
+ .vbp = 2,
+ },
+ .acbi = 0x0,
+ .acb = 0x0,
+ .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
+ OMAP_DSS_LCD_ONOFF,
+ .power_on_delay = 0,
+ .power_off_delay = 0,
+ .name = "toppoly_tdo35s",
+ },
+};
+
+struct panel_drv_data {
+
+ struct omap_dss_device *dssdev;
+
+ struct panel_config *panel_config;
+};
+
+static inline struct panel_generic_dpi_data
+*get_panel_data(const struct omap_dss_device *dssdev)
+{
+ return (struct panel_generic_dpi_data *) dssdev->data;
+}
+
+static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+ struct panel_config *panel_config = drv_data->panel_config;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ /* wait couple of vsyncs until enabling the LCD */
+ if (panel_config->power_on_delay)
+ msleep(panel_config->power_on_delay);
+
+ if (panel_data->platform_enable) {
+ r = panel_data->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
+{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+ struct panel_config *panel_config = drv_data->panel_config;
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
+ if (panel_data->platform_disable)
+ panel_data->platform_disable(dssdev);
+
+ /* wait couple of vsyncs after disabling the LCD */
+ if (panel_config->power_off_delay)
+ msleep(panel_config->power_off_delay);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
+{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ struct panel_config *panel_config = NULL;
+ struct panel_drv_data *drv_data = NULL;
+ int i;
+
+ dev_dbg(&dssdev->dev, "probe\n");
+
+ if (!panel_data || !panel_data->name)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
+ if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
+ panel_config = &generic_dpi_panels[i];
+ break;
+ }
+ }
+
+ if (!panel_config)
+ return -EINVAL;
+
+ dssdev->panel.config = panel_config->config;
+ dssdev->panel.timings = panel_config->timings;
+ dssdev->panel.acb = panel_config->acb;
+ dssdev->panel.acbi = panel_config->acbi;
+
+ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ drv_data->dssdev = dssdev;
+ drv_data->panel_config = panel_config;
+
+ dev_set_drvdata(&dssdev->dev, drv_data);
+
+ return 0;
+}
+
+static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+ dev_dbg(&dssdev->dev, "remove\n");
+
+ kfree(drv_data);
+
+ dev_set_drvdata(&dssdev->dev, NULL);
+}
+
+static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = generic_dpi_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
+{
+ generic_dpi_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
+{
+ generic_dpi_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+ return 0;
+}
+
+static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = generic_dpi_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ dpi_set_timings(dssdev, timings);
+}
+
+static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+
+static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ return dpi_check_timings(dssdev, timings);
+}
+
+static struct omap_dss_driver dpi_driver = {
+ .probe = generic_dpi_panel_probe,
+ .remove = generic_dpi_panel_remove,
+
+ .enable = generic_dpi_panel_enable,
+ .disable = generic_dpi_panel_disable,
+ .suspend = generic_dpi_panel_suspend,
+ .resume = generic_dpi_panel_resume,
+
+ .set_timings = generic_dpi_panel_set_timings,
+ .get_timings = generic_dpi_panel_get_timings,
+ .check_timings = generic_dpi_panel_check_timings,
+
+ .driver = {
+ .name = "generic_dpi_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init generic_dpi_panel_drv_init(void)
+{
+ return omap_dss_register_driver(&dpi_driver);
+}
+
+static void __exit generic_dpi_panel_drv_exit(void)
+{
+ omap_dss_unregister_driver(&dpi_driver);
+}
+
+module_init(generic_dpi_panel_drv_init);
+module_exit(generic_dpi_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
deleted file mode 100644
index 395a68de3990..000000000000
--- a/drivers/video/omap2/displays/panel-generic.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Generic panel support
- *
- * Copyright (C) 2008 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings generic_panel_timings = {
- /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
- .x_res = 640,
- .y_res = 480,
- .pixel_clock = 23500,
- .hfp = 48,
- .hsw = 32,
- .hbp = 80,
- .vfp = 3,
- .vsw = 4,
- .vbp = 7,
-};
-
-static int generic_panel_power_on(struct omap_dss_device *dssdev)
-{
- int r;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- return 0;
-
- r = omapdss_dpi_display_enable(dssdev);
- if (r)
- goto err0;
-
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
-
- return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
-err0:
- return r;
-}
-
-static void generic_panel_power_off(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return;
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- omapdss_dpi_display_disable(dssdev);
-}
-
-static int generic_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.config = OMAP_DSS_LCD_TFT;
- dssdev->panel.timings = generic_panel_timings;
-
- return 0;
-}
-
-static void generic_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int generic_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = generic_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void generic_panel_disable(struct omap_dss_device *dssdev)
-{
- generic_panel_power_off(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int generic_panel_suspend(struct omap_dss_device *dssdev)
-{
- generic_panel_power_off(dssdev);
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
- return 0;
-}
-
-static int generic_panel_resume(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = generic_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void generic_panel_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- dpi_set_timings(dssdev, timings);
-}
-
-static void generic_panel_get_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- *timings = dssdev->panel.timings;
-}
-
-static int generic_panel_check_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- return dpi_check_timings(dssdev, timings);
-}
-
-static struct omap_dss_driver generic_driver = {
- .probe = generic_panel_probe,
- .remove = generic_panel_remove,
-
- .enable = generic_panel_enable,
- .disable = generic_panel_disable,
- .suspend = generic_panel_suspend,
- .resume = generic_panel_resume,
-
- .set_timings = generic_panel_set_timings,
- .get_timings = generic_panel_get_timings,
- .check_timings = generic_panel_check_timings,
-
- .driver = {
- .name = "generic_panel",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init generic_panel_drv_init(void)
-{
- return omap_dss_register_driver(&generic_driver);
-}
-
-static void __exit generic_panel_drv_exit(void)
-{
- omap_dss_unregister_driver(&generic_driver);
-}
-
-module_init(generic_panel_drv_init);
-module_exit(generic_panel_drv_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
new file mode 100644
index 000000000000..925e0fadff54
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -0,0 +1,325 @@
+/*
+ * Support for NEC-nl8048hl11-01b panel driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <plat/display.h>
+
+#define LCD_XRES 800
+#define LCD_YRES 480
+/*
+ * NEC PIX Clock Ratings
+ * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
+ */
+#define LCD_PIXEL_CLOCK 23800
+
+struct nec_8048_data {
+ struct backlight_device *bl;
+};
+
+static const struct {
+ unsigned char addr;
+ unsigned char dat;
+} nec_8048_init_seq[] = {
+ { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
+ { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
+ { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
+ { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
+ { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
+ { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
+ { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
+ { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
+ { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
+ { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
+ { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
+ { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
+ { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
+ { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
+ { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
+ { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
+ { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
+ { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
+};
+
+/*
+ * NEC NL8048HL11-01B Manual
+ * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below
+ */
+
+static struct omap_video_timings nec_8048_panel_timings = {
+ /* 800 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
+ .x_res = LCD_XRES,
+ .y_res = LCD_YRES,
+ .pixel_clock = LCD_PIXEL_CLOCK,
+ .hfp = 6,
+ .hsw = 1,
+ .hbp = 4,
+ .vfp = 3,
+ .vsw = 1,
+ .vbp = 4,
+};
+
+static int nec_8048_bl_update_status(struct backlight_device *bl)
+{
+ struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
+ int level;
+
+ if (!dssdev->set_backlight)
+ return -EINVAL;
+
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ level = bl->props.brightness;
+ else
+ level = 0;
+
+ return dssdev->set_backlight(dssdev, level);
+}
+
+static int nec_8048_bl_get_brightness(struct backlight_device *bl)
+{
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ return bl->props.brightness;
+
+ return 0;
+}
+
+static const struct backlight_ops nec_8048_bl_ops = {
+ .get_brightness = nec_8048_bl_get_brightness,
+ .update_status = nec_8048_bl_update_status,
+};
+
+static int nec_8048_panel_probe(struct omap_dss_device *dssdev)
+{
+ struct backlight_device *bl;
+ struct nec_8048_data *necd;
+ struct backlight_properties props;
+ int r;
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF |
+ OMAP_DSS_LCD_ONOFF;
+ dssdev->panel.timings = nec_8048_panel_timings;
+
+ necd = kzalloc(sizeof(*necd), GFP_KERNEL);
+ if (!necd)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dssdev->dev, necd);
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 255;
+
+ bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev,
+ &nec_8048_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ r = PTR_ERR(bl);
+ kfree(necd);
+ return r;
+ }
+ necd->bl = bl;
+
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.max_brightness = dssdev->max_backlight_level;
+ bl->props.brightness = dssdev->max_backlight_level;
+
+ r = nec_8048_bl_update_status(bl);
+ if (r < 0)
+ dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
+ return 0;
+}
+
+static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
+{
+ struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+ struct backlight_device *bl = necd->bl;
+
+ bl->props.power = FB_BLANK_POWERDOWN;
+ nec_8048_bl_update_status(bl);
+ backlight_device_unregister(bl);
+
+ kfree(necd);
+}
+
+static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+ struct backlight_device *bl = necd->bl;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ r = nec_8048_bl_update_status(bl);
+ if (r < 0)
+ dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
+ r = omapdss_dpi_display_enable(dssdev);
+
+ return r;
+}
+
+static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
+{
+ struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
+ struct backlight_device *bl = necd->bl;
+
+ omapdss_dpi_display_disable(dssdev);
+
+ bl->props.brightness = 0;
+ nec_8048_bl_update_status(bl);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+}
+
+static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
+{
+ nec_8048_panel_disable(dssdev);
+ return 0;
+}
+
+static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
+{
+ return nec_8048_panel_enable(dssdev);
+}
+
+static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
+{
+ return 16;
+}
+
+static struct omap_dss_driver nec_8048_driver = {
+ .probe = nec_8048_panel_probe,
+ .remove = nec_8048_panel_remove,
+ .enable = nec_8048_panel_enable,
+ .disable = nec_8048_panel_disable,
+ .suspend = nec_8048_panel_suspend,
+ .resume = nec_8048_panel_resume,
+ .get_recommended_bpp = nec_8048_recommended_bpp,
+
+ .driver = {
+ .name = "NEC_8048_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
+ unsigned char reg_data)
+{
+ int ret = 0;
+ unsigned int cmd = 0, data = 0;
+
+ cmd = 0x0000 | reg_addr; /* register address write */
+ data = 0x0100 | reg_data ; /* register data write */
+ data = (cmd << 16) | data;
+
+ ret = spi_write(spi, (unsigned char *)&data, 4);
+ if (ret)
+ pr_err("error in spi_write %x\n", data);
+
+ return ret;
+}
+
+static int init_nec_8048_wvga_lcd(struct spi_device *spi)
+{
+ unsigned int i;
+ /* Initialization Sequence */
+ /* nec_8048_spi_send(spi, REG, VAL) */
+ for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
+ nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+ nec_8048_init_seq[i].dat);
+ udelay(20);
+ nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
+ nec_8048_init_seq[i].dat);
+ return 0;
+}
+
+static int nec_8048_spi_probe(struct spi_device *spi)
+{
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 32;
+ spi_setup(spi);
+
+ init_nec_8048_wvga_lcd(spi);
+
+ return omap_dss_register_driver(&nec_8048_driver);
+}
+
+static int nec_8048_spi_remove(struct spi_device *spi)
+{
+ omap_dss_unregister_driver(&nec_8048_driver);
+
+ return 0;
+}
+
+static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ nec_8048_spi_send(spi, 2, 0x01);
+ mdelay(40);
+
+ return 0;
+}
+
+static int nec_8048_spi_resume(struct spi_device *spi)
+{
+ /* reinitialize the panel */
+ spi_setup(spi);
+ nec_8048_spi_send(spi, 2, 0x00);
+ init_nec_8048_wvga_lcd(spi);
+
+ return 0;
+}
+
+static struct spi_driver nec_8048_spi_driver = {
+ .probe = nec_8048_spi_probe,
+ .remove = __devexit_p(nec_8048_spi_remove),
+ .suspend = nec_8048_spi_suspend,
+ .resume = nec_8048_spi_resume,
+ .driver = {
+ .name = "nec_8048_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init nec_8048_lcd_init(void)
+{
+ return spi_register_driver(&nec_8048_spi_driver);
+}
+
+static void __exit nec_8048_lcd_exit(void)
+{
+ return spi_unregister_driver(&nec_8048_spi_driver);
+}
+
+module_init(nec_8048_lcd_init);
+module_exit(nec_8048_lcd_exit);
+MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
+MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
deleted file mode 100644
index 0c6896cea2d0..000000000000
--- a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * LCD panel driver for Sharp LQ043T1DG01
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings sharp_lq_timings = {
- .x_res = 480,
- .y_res = 272,
-
- .pixel_clock = 9000,
-
- .hsw = 42,
- .hfp = 3,
- .hbp = 2,
-
- .vsw = 11,
- .vfp = 3,
- .vbp = 2,
-};
-
-static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
-{
- int r;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- return 0;
-
- r = omapdss_dpi_display_enable(dssdev);
- if (r)
- goto err0;
-
- /* wait couple of vsyncs until enabling the LCD */
- msleep(50);
-
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
-
- return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
-err0:
- return r;
-}
-
-static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return;
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- /* wait at least 5 vsyncs after disabling the LCD */
- msleep(100);
-
- omapdss_dpi_display_disable(dssdev);
-}
-
-static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
-{
-
- dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
- OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
- dssdev->panel.acb = 0x0;
- dssdev->panel.timings = sharp_lq_timings;
-
- return 0;
-}
-
-static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = sharp_lq_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
-{
- sharp_lq_panel_power_off(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
-{
- sharp_lq_panel_power_off(dssdev);
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
- return 0;
-}
-
-static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = sharp_lq_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static struct omap_dss_driver sharp_lq_driver = {
- .probe = sharp_lq_panel_probe,
- .remove = sharp_lq_panel_remove,
-
- .enable = sharp_lq_panel_enable,
- .disable = sharp_lq_panel_disable,
- .suspend = sharp_lq_panel_suspend,
- .resume = sharp_lq_panel_resume,
-
- .driver = {
- .name = "sharp_lq_panel",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sharp_lq_panel_drv_init(void)
-{
- return omap_dss_register_driver(&sharp_lq_driver);
-}
-
-static void __exit sharp_lq_panel_drv_exit(void)
-{
- omap_dss_unregister_driver(&sharp_lq_driver);
-}
-
-module_init(sharp_lq_panel_drv_init);
-module_exit(sharp_lq_panel_drv_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index e1c765d11419..61026f96ad20 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -465,7 +465,7 @@ static int taal_bl_get_intensity(struct backlight_device *dev)
return 0;
}
-static struct backlight_ops taal_bl_ops = {
+static const struct backlight_ops taal_bl_ops = {
.get_brightness = taal_bl_get_intensity,
.update_status = taal_bl_update_status,
};
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
deleted file mode 100644
index 526e906c8a6c..000000000000
--- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * LCD panel driver for Toppoly TDO35S
- *
- * Copyright (C) 2009 CompuLab, Ltd.
- * Author: Mike Rapoport <mike@compulab.co.il>
- *
- * Based on generic panel support
- * Copyright (C) 2008 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-
-#include <plat/display.h>
-
-static struct omap_video_timings toppoly_tdo_panel_timings = {
- /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
- .x_res = 480,
- .y_res = 640,
-
- .pixel_clock = 26000,
-
- .hfp = 104,
- .hsw = 8,
- .hbp = 8,
-
- .vfp = 4,
- .vsw = 2,
- .vbp = 2,
-};
-
-static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
-{
- int r;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- return 0;
-
- r = omapdss_dpi_display_enable(dssdev);
- if (r)
- goto err0;
-
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
-
- return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
-err0:
- return r;
-}
-
-static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return;
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- omapdss_dpi_display_disable(dssdev);
-}
-
-static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.config = OMAP_DSS_LCD_TFT |
- OMAP_DSS_LCD_IVS |
- OMAP_DSS_LCD_IHS |
- OMAP_DSS_LCD_IPC |
- OMAP_DSS_LCD_ONOFF;
-
- dssdev->panel.timings = toppoly_tdo_panel_timings;
-
- return 0;
-}
-
-static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = toppoly_tdo_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
-{
- toppoly_tdo_panel_power_off(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-
-static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
-{
- toppoly_tdo_panel_power_off(dssdev);
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
- return 0;
-}
-
-static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- r = toppoly_tdo_panel_power_on(dssdev);
- if (r)
- return r;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static struct omap_dss_driver generic_driver = {
- .probe = toppoly_tdo_panel_probe,
- .remove = toppoly_tdo_panel_remove,
-
- .enable = toppoly_tdo_panel_enable,
- .disable = toppoly_tdo_panel_disable,
- .suspend = toppoly_tdo_panel_suspend,
- .resume = toppoly_tdo_panel_resume,
-
- .driver = {
- .name = "toppoly_tdo35s_panel",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init toppoly_tdo_panel_drv_init(void)
-{
- return omap_dss_register_driver(&generic_driver);
-}
-
-static void __exit toppoly_tdo_panel_drv_exit(void)
-{
- omap_dss_unregister_driver(&generic_driver);
-}
-
-module_init(toppoly_tdo_panel_drv_init);
-module_exit(toppoly_tdo_panel_drv_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index fa40fa59a9ac..9f8c69f16e61 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -44,34 +44,40 @@
/* DISPC */
#define DISPC_BASE 0x48050400
-#define DISPC_SZ_REGS SZ_1K
+#define DISPC_SZ_REGS SZ_4K
struct dispc_reg { u16 idx; };
#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
-/* DISPC common */
+/*
+ * DISPC common registers and
+ * DISPC channel registers , ch = 0 for LCD, ch = 1 for
+ * DIGIT, and ch = 2 for LCD2
+ */
#define DISPC_REVISION DISPC_REG(0x0000)
#define DISPC_SYSCONFIG DISPC_REG(0x0010)
#define DISPC_SYSSTATUS DISPC_REG(0x0014)
#define DISPC_IRQSTATUS DISPC_REG(0x0018)
#define DISPC_IRQENABLE DISPC_REG(0x001C)
#define DISPC_CONTROL DISPC_REG(0x0040)
+#define DISPC_CONTROL2 DISPC_REG(0x0238)
#define DISPC_CONFIG DISPC_REG(0x0044)
+#define DISPC_CONFIG2 DISPC_REG(0x0620)
#define DISPC_CAPABLE DISPC_REG(0x0048)
-#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
-#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
-#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
-#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
+#define DISPC_DEFAULT_COLOR(ch) DISPC_REG(ch == 0 ? 0x004C : \
+ (ch == 1 ? 0x0050 : 0x03AC))
+#define DISPC_TRANS_COLOR(ch) DISPC_REG(ch == 0 ? 0x0054 : \
+ (ch == 1 ? 0x0058 : 0x03B0))
#define DISPC_LINE_STATUS DISPC_REG(0x005C)
#define DISPC_LINE_NUMBER DISPC_REG(0x0060)
-#define DISPC_TIMING_H DISPC_REG(0x0064)
-#define DISPC_TIMING_V DISPC_REG(0x0068)
-#define DISPC_POL_FREQ DISPC_REG(0x006C)
-#define DISPC_DIVISOR DISPC_REG(0x0070)
+#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
+#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
+#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408)
+#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
#define DISPC_SIZE_DIG DISPC_REG(0x0078)
-#define DISPC_SIZE_LCD DISPC_REG(0x007C)
+#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
/* DISPC GFX plane */
#define DISPC_GFX_BA0 DISPC_REG(0x0080)
@@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; };
#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
-#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
-#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
-#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
-
-#define DISPC_CPR_COEF_R DISPC_REG(0x0220)
-#define DISPC_CPR_COEF_G DISPC_REG(0x0224)
-#define DISPC_CPR_COEF_B DISPC_REG(0x0228)
+#define DISPC_DATA_CYCLE1(ch) DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0)
+#define DISPC_DATA_CYCLE2(ch) DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4)
+#define DISPC_DATA_CYCLE3(ch) DISPC_REG(ch != 2 ? 0x01DC : 0x03C8)
+#define DISPC_CPR_COEF_R(ch) DISPC_REG(ch != 2 ? 0x0220 : 0x03BC)
+#define DISPC_CPR_COEF_G(ch) DISPC_REG(ch != 2 ? 0x0224 : 0x03B8)
+#define DISPC_CPR_COEF_B(ch) DISPC_REG(ch != 2 ? 0x0228 : 0x03B4)
#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
@@ -217,18 +222,29 @@ void dispc_save_context(void)
SR(IRQENABLE);
SR(CONTROL);
SR(CONFIG);
- SR(DEFAULT_COLOR0);
- SR(DEFAULT_COLOR1);
- SR(TRANS_COLOR0);
- SR(TRANS_COLOR1);
+ SR(DEFAULT_COLOR(0));
+ SR(DEFAULT_COLOR(1));
+ SR(TRANS_COLOR(0));
+ SR(TRANS_COLOR(1));
SR(LINE_NUMBER);
- SR(TIMING_H);
- SR(TIMING_V);
- SR(POL_FREQ);
- SR(DIVISOR);
+ SR(TIMING_H(0));
+ SR(TIMING_V(0));
+ SR(POL_FREQ(0));
+ SR(DIVISOR(0));
SR(GLOBAL_ALPHA);
SR(SIZE_DIG);
- SR(SIZE_LCD);
+ SR(SIZE_LCD(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ SR(CONTROL2);
+ SR(DEFAULT_COLOR(2));
+ SR(TRANS_COLOR(2));
+ SR(SIZE_LCD(2));
+ SR(TIMING_H(2));
+ SR(TIMING_V(2));
+ SR(POL_FREQ(2));
+ SR(DIVISOR(2));
+ SR(CONFIG2);
+ }
SR(GFX_BA0);
SR(GFX_BA1);
@@ -241,13 +257,22 @@ void dispc_save_context(void)
SR(GFX_WINDOW_SKIP);
SR(GFX_TABLE_BA);
- SR(DATA_CYCLE1);
- SR(DATA_CYCLE2);
- SR(DATA_CYCLE3);
-
- SR(CPR_COEF_R);
- SR(CPR_COEF_G);
- SR(CPR_COEF_B);
+ SR(DATA_CYCLE1(0));
+ SR(DATA_CYCLE2(0));
+ SR(DATA_CYCLE3(0));
+
+ SR(CPR_COEF_R(0));
+ SR(CPR_COEF_G(0));
+ SR(CPR_COEF_B(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ SR(CPR_COEF_B(2));
+ SR(CPR_COEF_G(2));
+ SR(CPR_COEF_R(2));
+
+ SR(DATA_CYCLE1(2));
+ SR(DATA_CYCLE2(2));
+ SR(DATA_CYCLE3(2));
+ }
SR(GFX_PRELOAD);
@@ -356,18 +381,28 @@ void dispc_restore_context(void)
/*RR(IRQENABLE);*/
/*RR(CONTROL);*/
RR(CONFIG);
- RR(DEFAULT_COLOR0);
- RR(DEFAULT_COLOR1);
- RR(TRANS_COLOR0);
- RR(TRANS_COLOR1);
+ RR(DEFAULT_COLOR(0));
+ RR(DEFAULT_COLOR(1));
+ RR(TRANS_COLOR(0));
+ RR(TRANS_COLOR(1));
RR(LINE_NUMBER);
- RR(TIMING_H);
- RR(TIMING_V);
- RR(POL_FREQ);
- RR(DIVISOR);
+ RR(TIMING_H(0));
+ RR(TIMING_V(0));
+ RR(POL_FREQ(0));
+ RR(DIVISOR(0));
RR(GLOBAL_ALPHA);
RR(SIZE_DIG);
- RR(SIZE_LCD);
+ RR(SIZE_LCD(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ RR(DEFAULT_COLOR(2));
+ RR(TRANS_COLOR(2));
+ RR(SIZE_LCD(2));
+ RR(TIMING_H(2));
+ RR(TIMING_V(2));
+ RR(POL_FREQ(2));
+ RR(DIVISOR(2));
+ RR(CONFIG2);
+ }
RR(GFX_BA0);
RR(GFX_BA1);
@@ -380,13 +415,22 @@ void dispc_restore_context(void)
RR(GFX_WINDOW_SKIP);
RR(GFX_TABLE_BA);
- RR(DATA_CYCLE1);
- RR(DATA_CYCLE2);
- RR(DATA_CYCLE3);
-
- RR(CPR_COEF_R);
- RR(CPR_COEF_G);
- RR(CPR_COEF_B);
+ RR(DATA_CYCLE1(0));
+ RR(DATA_CYCLE2(0));
+ RR(DATA_CYCLE3(0));
+
+ RR(CPR_COEF_R(0));
+ RR(CPR_COEF_G(0));
+ RR(CPR_COEF_B(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ RR(DATA_CYCLE1(2));
+ RR(DATA_CYCLE2(2));
+ RR(DATA_CYCLE3(2));
+
+ RR(CPR_COEF_B(2));
+ RR(CPR_COEF_G(2));
+ RR(CPR_COEF_R(2));
+ }
RR(GFX_PRELOAD);
@@ -490,7 +534,8 @@ void dispc_restore_context(void)
/* enable last, because LCD & DIGIT enable are here */
RR(CONTROL);
-
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ RR(CONTROL2);
/* clear spurious SYNC_LOST_DIGIT interrupts */
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
@@ -516,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel)
{
int bit;
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if (channel == OMAP_DSS_CHANNEL_LCD ||
+ channel == OMAP_DSS_CHANNEL_LCD2)
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
- return REG_GET(DISPC_CONTROL, bit, bit) == 1;
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ return REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+ else
+ return REG_GET(DISPC_CONTROL, bit, bit) == 1;
}
void dispc_go(enum omap_channel channel)
{
int bit;
+ bool enable_bit, go_bit;
enable_clocks(1);
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if (channel == OMAP_DSS_CHANNEL_LCD ||
+ channel == OMAP_DSS_CHANNEL_LCD2)
bit = 0; /* LCDENABLE */
else
bit = 1; /* DIGITALENABLE */
/* if the channel is not enabled, we don't need GO */
- if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+ else
+ enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
+
+ if (!enable_bit)
goto end;
- if (channel == OMAP_DSS_CHANNEL_LCD)
+ if (channel == OMAP_DSS_CHANNEL_LCD ||
+ channel == OMAP_DSS_CHANNEL_LCD2)
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
- if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
+ else
+ go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
+
+ if (go_bit) {
DSSERR("GO bit not down for channel %d\n", channel);
goto end;
}
- DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
+ DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
+ (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT"));
- REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
end:
enable_clocks(0);
}
@@ -773,13 +839,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
dispc_write_reg(vsi_reg[plane-1], val);
}
+static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
+{
+ if (!dss_has_feature(FEAT_PRE_MULT_ALPHA))
+ return;
+
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ plane == OMAP_DSS_VIDEO1)
+ return;
+
+ REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28);
+}
+
static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
{
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return;
- BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
- plane == OMAP_DSS_VIDEO1);
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ plane == OMAP_DSS_VIDEO1)
+ return;
if (plane == OMAP_DSS_GFX)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
@@ -851,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
{
int shift;
u32 val;
+ int chan = 0, chan2 = 0;
switch (plane) {
case OMAP_DSS_GFX:
@@ -866,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane,
}
val = dispc_read_reg(dispc_reg_att[plane]);
- val = FLD_MOD(val, channel, shift, shift);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ chan = 0;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ chan = 1;
+ chan2 = 0;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ chan = 0;
+ chan2 = 1;
+ break;
+ default:
+ BUG();
+ }
+
+ val = FLD_MOD(val, chan, shift, shift);
+ val = FLD_MOD(val, chan2, 31, 30);
+ } else {
+ val = FLD_MOD(val, channel, shift, shift);
+ }
dispc_write_reg(dispc_reg_att[plane], val);
}
@@ -923,13 +1025,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
enable_clocks(0);
}
-void dispc_set_lcd_size(u16 width, u16 height)
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
{
u32 val;
BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
enable_clocks(1);
- dispc_write_reg(DISPC_SIZE_LCD, val);
+ dispc_write_reg(DISPC_SIZE_LCD(channel), val);
enable_clocks(0);
}
@@ -1426,12 +1528,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
}
}
-static unsigned long calc_fclk_five_taps(u16 width, u16 height,
- u16 out_width, u16 out_height, enum omap_color_mode color_mode)
+static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode)
{
u32 fclk = 0;
/* FIXME venc pclk? */
- u64 tmp, pclk = dispc_pclk_rate();
+ u64 tmp, pclk = dispc_pclk_rate(channel);
if (height > out_height) {
/* FIXME get real display PPL */
@@ -1463,8 +1566,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height,
return fclk;
}
-static unsigned long calc_fclk(u16 width, u16 height,
- u16 out_width, u16 out_height)
+static unsigned long calc_fclk(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
{
unsigned int hf, vf;
@@ -1488,7 +1591,7 @@ static unsigned long calc_fclk(u16 width, u16 height,
vf = 1;
/* FIXME venc pclk? */
- return dispc_pclk_rate() * vf * hf;
+ return dispc_pclk_rate(channel) * vf * hf;
}
void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
@@ -1507,7 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, int mirror,
- u8 global_alpha)
+ u8 global_alpha, u8 pre_mult_alpha,
+ enum omap_channel channel)
{
const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
bool five_taps = 0;
@@ -1536,29 +1640,12 @@ static int _dispc_setup_plane(enum omap_plane plane,
height, pos_y, out_height);
}
+ if (!dss_feat_color_mode_supported(plane, color_mode))
+ return -EINVAL;
+
if (plane == OMAP_DSS_GFX) {
if (width != out_width || height != out_height)
return -EINVAL;
-
- switch (color_mode) {
- case OMAP_DSS_COLOR_ARGB16:
- case OMAP_DSS_COLOR_ARGB32:
- case OMAP_DSS_COLOR_RGBA32:
- if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
- return -EINVAL;
- case OMAP_DSS_COLOR_RGBX32:
- if (cpu_is_omap24xx())
- return -EINVAL;
- /* fall through */
- case OMAP_DSS_COLOR_RGB12U:
- case OMAP_DSS_COLOR_RGB16:
- case OMAP_DSS_COLOR_RGB24P:
- case OMAP_DSS_COLOR_RGB24U:
- break;
-
- default:
- return -EINVAL;
- }
} else {
/* video plane */
@@ -1572,42 +1659,16 @@ static int _dispc_setup_plane(enum omap_plane plane,
out_height > height * 8)
return -EINVAL;
- switch (color_mode) {
- case OMAP_DSS_COLOR_RGBX32:
- case OMAP_DSS_COLOR_RGB12U:
- if (cpu_is_omap24xx())
- return -EINVAL;
- /* fall through */
- case OMAP_DSS_COLOR_RGB16:
- case OMAP_DSS_COLOR_RGB24P:
- case OMAP_DSS_COLOR_RGB24U:
- break;
-
- case OMAP_DSS_COLOR_ARGB16:
- case OMAP_DSS_COLOR_ARGB32:
- case OMAP_DSS_COLOR_RGBA32:
- if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
- return -EINVAL;
- if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
- plane == OMAP_DSS_VIDEO1)
- return -EINVAL;
- break;
-
- case OMAP_DSS_COLOR_YUV2:
- case OMAP_DSS_COLOR_UYVY:
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
cconv = 1;
- break;
-
- default:
- return -EINVAL;
- }
/* Must use 5-tap filter? */
five_taps = height > out_height * 2;
if (!five_taps) {
- fclk = calc_fclk(width, height,
- out_width, out_height);
+ fclk = calc_fclk(channel, width, height, out_width,
+ out_height);
/* Try 5-tap filter if 3-tap fclk is too high */
if (cpu_is_omap34xx() && height > out_height &&
@@ -1621,7 +1682,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
}
if (five_taps)
- fclk = calc_fclk_five_taps(width, height,
+ fclk = calc_fclk_five_taps(channel, width, height,
out_width, out_height, color_mode);
DSSDBG("required fclk rate = %lu Hz\n", fclk);
@@ -1693,8 +1754,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
_dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
- if (plane != OMAP_DSS_VIDEO1)
- _dispc_setup_global_alpha(plane, global_alpha);
+ _dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
+ _dispc_setup_global_alpha(plane, global_alpha);
return 0;
}
@@ -1710,36 +1771,44 @@ static void dispc_disable_isr(void *data, u32 mask)
complete(compl);
}
-static void _enable_lcd_out(bool enable)
+static void _enable_lcd_out(enum omap_channel channel, bool enable)
{
- REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
}
-static void dispc_enable_lcd_out(bool enable)
+static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
{
struct completion frame_done_completion;
bool is_on;
int r;
+ u32 irq;
enable_clocks(1);
/* When we disable LCD output, we need to wait until frame is done.
* Otherwise the DSS is still working, and turning off the clocks
* prevents DSS from going to OFF mode */
- is_on = REG_GET(DISPC_CONTROL, 0, 0);
+ is_on = channel == OMAP_DSS_CHANNEL_LCD2 ?
+ REG_GET(DISPC_CONTROL2, 0, 0) :
+ REG_GET(DISPC_CONTROL, 0, 0);
+
+ irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 :
+ DISPC_IRQ_FRAMEDONE;
if (!enable && is_on) {
init_completion(&frame_done_completion);
r = omap_dispc_register_isr(dispc_disable_isr,
- &frame_done_completion,
- DISPC_IRQ_FRAMEDONE);
+ &frame_done_completion, irq);
if (r)
DSSERR("failed to register FRAMEDONE isr\n");
}
- _enable_lcd_out(enable);
+ _enable_lcd_out(channel, enable);
if (!enable && is_on) {
if (!wait_for_completion_timeout(&frame_done_completion,
@@ -1747,8 +1816,7 @@ static void dispc_enable_lcd_out(bool enable)
DSSERR("timeout waiting for FRAME DONE\n");
r = omap_dispc_unregister_isr(dispc_disable_isr,
- &frame_done_completion,
- DISPC_IRQ_FRAMEDONE);
+ &frame_done_completion, irq);
if (r)
DSSERR("failed to unregister FRAMEDONE isr\n");
@@ -1818,6 +1886,8 @@ static void dispc_enable_digit_out(bool enable)
unsigned long flags;
spin_lock_irqsave(&dispc.irq_lock, flags);
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -1832,14 +1902,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel)
return !!REG_GET(DISPC_CONTROL, 0, 0);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
return !!REG_GET(DISPC_CONTROL, 1, 1);
+ else if (channel == OMAP_DSS_CHANNEL_LCD2)
+ return !!REG_GET(DISPC_CONTROL2, 0, 0);
else
BUG();
}
void dispc_enable_channel(enum omap_channel channel, bool enable)
{
- if (channel == OMAP_DSS_CHANNEL_LCD)
- dispc_enable_lcd_out(enable);
+ if (channel == OMAP_DSS_CHANNEL_LCD ||
+ channel == OMAP_DSS_CHANNEL_LCD2)
+ dispc_enable_lcd_out(channel, enable);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
dispc_enable_digit_out(enable);
else
@@ -1848,6 +1921,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable)
void dispc_lcd_enable_signal_polarity(bool act_high)
{
+ if (!dss_has_feature(FEAT_LCDENABLEPOL))
+ return;
+
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
enable_clocks(0);
@@ -1855,6 +1931,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
void dispc_lcd_enable_signal(bool enable)
{
+ if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
+ return;
+
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
enable_clocks(0);
@@ -1862,20 +1941,27 @@ void dispc_lcd_enable_signal(bool enable)
void dispc_pck_free_enable(bool enable)
{
+ if (!dss_has_feature(FEAT_PCKFREEENABLE))
+ return;
+
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
enable_clocks(0);
}
-void dispc_enable_fifohandcheck(bool enable)
+void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
{
enable_clocks(1);
- REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
+ else
+ REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
enable_clocks(0);
}
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
+void dispc_set_lcd_display_type(enum omap_channel channel,
+ enum omap_lcd_display_type type)
{
int mode;
@@ -1894,7 +1980,10 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
}
enable_clocks(1);
- REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
enable_clocks(0);
}
@@ -1908,25 +1997,21 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
void dispc_set_default_color(enum omap_channel channel, u32 color)
{
- const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
- DISPC_DEFAULT_COLOR1 };
-
enable_clocks(1);
- dispc_write_reg(def_reg[channel], color);
+ dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
enable_clocks(0);
}
u32 dispc_get_default_color(enum omap_channel channel)
{
- const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
- DISPC_DEFAULT_COLOR1 };
u32 l;
BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
- channel != OMAP_DSS_CHANNEL_LCD);
+ channel != OMAP_DSS_CHANNEL_LCD &&
+ channel != OMAP_DSS_CHANNEL_LCD2);
enable_clocks(1);
- l = dispc_read_reg(def_reg[channel]);
+ l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
enable_clocks(0);
return l;
@@ -1936,16 +2021,15 @@ void dispc_set_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type type,
u32 trans_key)
{
- const struct dispc_reg tr_reg[] = {
- DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
-
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
- else /* OMAP_DSS_CHANNEL_DIGIT */
+ else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
+ else /* OMAP_DSS_CHANNEL_LCD2 */
+ REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
- dispc_write_reg(tr_reg[ch], trans_key);
+ dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
enable_clocks(0);
}
@@ -1953,21 +2037,20 @@ void dispc_get_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type *type,
u32 *trans_key)
{
- const struct dispc_reg tr_reg[] = {
- DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
-
enable_clocks(1);
if (type) {
if (ch == OMAP_DSS_CHANNEL_LCD)
*type = REG_GET(DISPC_CONFIG, 11, 11);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
*type = REG_GET(DISPC_CONFIG, 13, 13);
+ else if (ch == OMAP_DSS_CHANNEL_LCD2)
+ *type = REG_GET(DISPC_CONFIG2, 11, 11);
else
BUG();
}
if (trans_key)
- *trans_key = dispc_read_reg(tr_reg[ch]);
+ *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
enable_clocks(0);
}
@@ -1976,8 +2059,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
- else /* OMAP_DSS_CHANNEL_DIGIT */
+ else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
+ else /* OMAP_DSS_CHANNEL_LCD2 */
+ REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
enable_clocks(0);
}
void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
@@ -1988,8 +2073,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
- else /* OMAP_DSS_CHANNEL_DIGIT */
+ else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
+ else /* OMAP_DSS_CHANNEL_LCD2 */
+ REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
enable_clocks(0);
}
bool dispc_alpha_blending_enabled(enum omap_channel ch)
@@ -2003,13 +2090,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
if (ch == OMAP_DSS_CHANNEL_LCD)
enabled = REG_GET(DISPC_CONFIG, 18, 18);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
- enabled = REG_GET(DISPC_CONFIG, 18, 18);
+ enabled = REG_GET(DISPC_CONFIG, 19, 19);
+ else if (ch == OMAP_DSS_CHANNEL_LCD2)
+ enabled = REG_GET(DISPC_CONFIG2, 18, 18);
else
BUG();
enable_clocks(0);
return enabled;
-
}
@@ -2022,6 +2110,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
enabled = REG_GET(DISPC_CONFIG, 10, 10);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
enabled = REG_GET(DISPC_CONFIG, 12, 12);
+ else if (ch == OMAP_DSS_CHANNEL_LCD2)
+ enabled = REG_GET(DISPC_CONFIG2, 10, 10);
else
BUG();
enable_clocks(0);
@@ -2030,7 +2120,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
}
-void dispc_set_tft_data_lines(u8 data_lines)
+void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
{
int code;
@@ -2053,11 +2143,15 @@ void dispc_set_tft_data_lines(u8 data_lines)
}
enable_clocks(1);
- REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
+ if (channel == OMAP_DSS_CHANNEL_LCD2)
+ REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
+ else
+ REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
enable_clocks(0);
}
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+ enum omap_parallel_interface_mode mode)
{
u32 l;
int stallmode;
@@ -2087,13 +2181,17 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
enable_clocks(1);
- l = dispc_read_reg(DISPC_CONTROL);
-
- l = FLD_MOD(l, stallmode, 11, 11);
- l = FLD_MOD(l, gpout0, 15, 15);
- l = FLD_MOD(l, gpout1, 16, 16);
-
- dispc_write_reg(DISPC_CONTROL, l);
+ if (channel == OMAP_DSS_CHANNEL_LCD2) {
+ l = dispc_read_reg(DISPC_CONTROL2);
+ l = FLD_MOD(l, stallmode, 11, 11);
+ dispc_write_reg(DISPC_CONTROL2, l);
+ } else {
+ l = dispc_read_reg(DISPC_CONTROL);
+ l = FLD_MOD(l, stallmode, 11, 11);
+ l = FLD_MOD(l, gpout0, 15, 15);
+ l = FLD_MOD(l, gpout1, 16, 16);
+ dispc_write_reg(DISPC_CONTROL, l);
+ }
enable_clocks(0);
}
@@ -2129,8 +2227,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
timings->vfp, timings->vbp);
}
-static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
- int vsw, int vfp, int vbp)
+static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
+ int hfp, int hbp, int vsw, int vfp, int vbp)
{
u32 timing_h, timing_v;
@@ -2149,13 +2247,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
}
enable_clocks(1);
- dispc_write_reg(DISPC_TIMING_H, timing_h);
- dispc_write_reg(DISPC_TIMING_V, timing_v);
+ dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
+ dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
enable_clocks(0);
}
/* change name to mode? */
-void dispc_set_lcd_timings(struct omap_video_timings *timings)
+void dispc_set_lcd_timings(enum omap_channel channel,
+ struct omap_video_timings *timings)
{
unsigned xtot, ytot;
unsigned long ht, vt;
@@ -2165,10 +2264,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
timings->vfp, timings->vbp))
BUG();
- _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
- timings->vsw, timings->vfp, timings->vbp);
+ _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
+ timings->hbp, timings->vsw, timings->vfp,
+ timings->vbp);
- dispc_set_lcd_size(timings->x_res, timings->y_res);
+ dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
@@ -2176,7 +2276,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
ht = (timings->pixel_clock * 1000) / xtot;
vt = (timings->pixel_clock * 1000) / xtot / ytot;
- DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
+ DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res,
+ timings->y_res);
DSSDBG("pck %u\n", timings->pixel_clock);
DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
timings->hsw, timings->hfp, timings->hbp,
@@ -2185,21 +2286,23 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
}
-static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
+static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
+ u16 pck_div)
{
BUG_ON(lck_div < 1);
BUG_ON(pck_div < 2);
enable_clocks(1);
- dispc_write_reg(DISPC_DIVISOR,
+ dispc_write_reg(DISPC_DIVISOR(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
enable_clocks(0);
}
-static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
+static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
+ int *pck_div)
{
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR);
+ l = dispc_read_reg(DISPC_DIVISOR(channel));
*lck_div = FLD_GET(l, 23, 16);
*pck_div = FLD_GET(l, 7, 0);
}
@@ -2219,13 +2322,13 @@ unsigned long dispc_fclk_rate(void)
return r;
}
-unsigned long dispc_lclk_rate(void)
+unsigned long dispc_lclk_rate(enum omap_channel channel)
{
int lcd;
unsigned long r;
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR);
+ l = dispc_read_reg(DISPC_DIVISOR(channel));
lcd = FLD_GET(l, 23, 16);
@@ -2234,13 +2337,13 @@ unsigned long dispc_lclk_rate(void)
return r / lcd;
}
-unsigned long dispc_pclk_rate(void)
+unsigned long dispc_pclk_rate(enum omap_channel channel)
{
int lcd, pcd;
unsigned long r;
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR);
+ l = dispc_read_reg(DISPC_DIVISOR(channel));
lcd = FLD_GET(l, 23, 16);
pcd = FLD_GET(l, 7, 0);
@@ -2256,8 +2359,6 @@ void dispc_dump_clocks(struct seq_file *s)
enable_clocks(1);
- dispc_get_lcd_divisor(&lcd, &pcd);
-
seq_printf(s, "- DISPC -\n");
seq_printf(s, "dispc fclk source = %s\n",
@@ -2265,9 +2366,25 @@ void dispc_dump_clocks(struct seq_file *s)
"dss1_alwon_fclk" : "dsi1_pll_fclk");
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
- seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
- seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
+ seq_printf(s, "- LCD1 -\n");
+
+ dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
+
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
+ seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ seq_printf(s, "- LCD2 -\n");
+
+ dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
+
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
+ seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
+ }
enable_clocks(0);
}
@@ -2309,6 +2426,12 @@ void dispc_dump_irqs(struct seq_file *s)
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
PIS(WAKEUP);
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ PIS(FRAMEDONE2);
+ PIS(VSYNC2);
+ PIS(ACBIAS_COUNT_STAT2);
+ PIS(SYNC_LOST2);
+ }
#undef PIS
}
#endif
@@ -2327,19 +2450,30 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_CONTROL);
DUMPREG(DISPC_CONFIG);
DUMPREG(DISPC_CAPABLE);
- DUMPREG(DISPC_DEFAULT_COLOR0);
- DUMPREG(DISPC_DEFAULT_COLOR1);
- DUMPREG(DISPC_TRANS_COLOR0);
- DUMPREG(DISPC_TRANS_COLOR1);
+ DUMPREG(DISPC_DEFAULT_COLOR(0));
+ DUMPREG(DISPC_DEFAULT_COLOR(1));
+ DUMPREG(DISPC_TRANS_COLOR(0));
+ DUMPREG(DISPC_TRANS_COLOR(1));
DUMPREG(DISPC_LINE_STATUS);
DUMPREG(DISPC_LINE_NUMBER);
- DUMPREG(DISPC_TIMING_H);
- DUMPREG(DISPC_TIMING_V);
- DUMPREG(DISPC_POL_FREQ);
- DUMPREG(DISPC_DIVISOR);
+ DUMPREG(DISPC_TIMING_H(0));
+ DUMPREG(DISPC_TIMING_V(0));
+ DUMPREG(DISPC_POL_FREQ(0));
+ DUMPREG(DISPC_DIVISOR(0));
DUMPREG(DISPC_GLOBAL_ALPHA);
DUMPREG(DISPC_SIZE_DIG);
- DUMPREG(DISPC_SIZE_LCD);
+ DUMPREG(DISPC_SIZE_LCD(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ DUMPREG(DISPC_CONTROL2);
+ DUMPREG(DISPC_CONFIG2);
+ DUMPREG(DISPC_DEFAULT_COLOR(2));
+ DUMPREG(DISPC_TRANS_COLOR(2));
+ DUMPREG(DISPC_TIMING_H(2));
+ DUMPREG(DISPC_TIMING_V(2));
+ DUMPREG(DISPC_POL_FREQ(2));
+ DUMPREG(DISPC_DIVISOR(2));
+ DUMPREG(DISPC_SIZE_LCD(2));
+ }
DUMPREG(DISPC_GFX_BA0);
DUMPREG(DISPC_GFX_BA1);
@@ -2353,13 +2487,22 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_GFX_WINDOW_SKIP);
DUMPREG(DISPC_GFX_TABLE_BA);
- DUMPREG(DISPC_DATA_CYCLE1);
- DUMPREG(DISPC_DATA_CYCLE2);
- DUMPREG(DISPC_DATA_CYCLE3);
-
- DUMPREG(DISPC_CPR_COEF_R);
- DUMPREG(DISPC_CPR_COEF_G);
- DUMPREG(DISPC_CPR_COEF_B);
+ DUMPREG(DISPC_DATA_CYCLE1(0));
+ DUMPREG(DISPC_DATA_CYCLE2(0));
+ DUMPREG(DISPC_DATA_CYCLE3(0));
+
+ DUMPREG(DISPC_CPR_COEF_R(0));
+ DUMPREG(DISPC_CPR_COEF_G(0));
+ DUMPREG(DISPC_CPR_COEF_B(0));
+ if (dss_has_feature(FEAT_MGR_LCD2)) {
+ DUMPREG(DISPC_DATA_CYCLE1(2));
+ DUMPREG(DISPC_DATA_CYCLE2(2));
+ DUMPREG(DISPC_DATA_CYCLE3(2));
+
+ DUMPREG(DISPC_CPR_COEF_R(2));
+ DUMPREG(DISPC_CPR_COEF_G(2));
+ DUMPREG(DISPC_CPR_COEF_B(2));
+ }
DUMPREG(DISPC_GFX_PRELOAD);
@@ -2458,8 +2601,8 @@ void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
- bool ihs, bool ivs, u8 acbi, u8 acb)
+static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
+ bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb)
{
u32 l = 0;
@@ -2476,13 +2619,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
l |= FLD_VAL(acb, 7, 0);
enable_clocks(1);
- dispc_write_reg(DISPC_POL_FREQ, l);
+ dispc_write_reg(DISPC_POL_FREQ(channel), l);
enable_clocks(0);
}
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
+void dispc_set_pol_freq(enum omap_channel channel,
+ enum omap_panel_config config, u8 acbi, u8 acb)
{
- _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
+ _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
(config & OMAP_DSS_LCD_RF) != 0,
(config & OMAP_DSS_LCD_IEO) != 0,
(config & OMAP_DSS_LCD_IPC) != 0,
@@ -2551,24 +2695,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
return 0;
}
-int dispc_set_clock_div(struct dispc_clock_info *cinfo)
+int dispc_set_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo)
{
DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
- dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
+ dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
return 0;
}
-int dispc_get_clock_div(struct dispc_clock_info *cinfo)
+int dispc_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo)
{
unsigned long fck;
fck = dispc_fclk_rate();
- cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
- cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
+ cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
+ cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
cinfo->lck = fck / cinfo->lck_div;
cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2708,6 +2854,8 @@ static void print_irq_status(u32 status)
PIS(VID2_FIFO_UNDERFLOW);
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ PIS(SYNC_LOST2);
#undef PIS
printk("\n");
@@ -2926,6 +3074,45 @@ static void dispc_error_worker(struct work_struct *work)
}
}
+ if (errors & DISPC_IRQ_SYNC_LOST2) {
+ struct omap_overlay_manager *manager = NULL;
+ bool enable = false;
+
+ DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
+
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ struct omap_overlay_manager *mgr;
+ mgr = omap_dss_get_overlay_manager(i);
+
+ if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
+ manager = mgr;
+ enable = mgr->device->state ==
+ OMAP_DSS_DISPLAY_ACTIVE;
+ mgr->device->driver->disable(mgr->device);
+ break;
+ }
+ }
+
+ if (manager) {
+ struct omap_dss_device *dssdev = manager->device;
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(i);
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ if (ovl->id != 0 && ovl->manager == manager)
+ dispc_enable_plane(ovl->id, 0);
+ }
+
+ dispc_go(manager->id);
+ mdelay(50);
+ if (enable)
+ dssdev->driver->enable(dssdev);
+ }
+ }
+
if (errors & DISPC_IRQ_OCP_ERR) {
DSSERR("OCP_ERR\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
@@ -3033,6 +3220,8 @@ static void _omap_dispc_initialize_irq(void)
memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
/* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
* so clear it */
@@ -3065,7 +3254,8 @@ static void _omap_dispc_initial_config(void)
dispc_write_reg(DISPC_SYSCONFIG, l);
/* FUNCGATED */
- REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
+ if (dss_has_feature(FEAT_FUNCGATED))
+ REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
/* L3 firewall setting: enable access to OCM RAM */
/* XXX this should be somewhere in plat-omap */
@@ -3139,17 +3329,18 @@ int dispc_setup_plane(enum omap_plane plane,
enum omap_color_mode color_mode,
bool ilace,
enum omap_dss_rotation_type rotation_type,
- u8 rotation, bool mirror, u8 global_alpha)
+ u8 rotation, bool mirror, u8 global_alpha,
+ u8 pre_mult_alpha, enum omap_channel channel)
{
int r = 0;
DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
- "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
+ "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
plane, paddr, screen_width, pos_x, pos_y,
width, height,
out_width, out_height,
ilace, color_mode,
- rotation, mirror);
+ rotation, mirror, channel);
enable_clocks(1);
@@ -3161,7 +3352,8 @@ int dispc_setup_plane(enum omap_plane plane,
color_mode, ilace,
rotation_type,
rotation, mirror,
- global_alpha);
+ global_alpha,
+ pre_mult_alpha, channel);
enable_clocks(0);
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 960e977a8bf0..75fb0a515430 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -40,8 +40,9 @@ static struct {
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
- unsigned long *fck, int *lck_div, int *pck_div)
+static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
+ unsigned long pck_req, unsigned long *fck, int *lck_div,
+ int *pck_div)
{
struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
@@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
return r;
@@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
return 0;
}
#else
-static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
- unsigned long *fck, int *lck_div, int *pck_div)
+static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
+ unsigned long pck_req, unsigned long *fck, int *lck_div,
+ int *pck_div)
{
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
@@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
if (r)
return r;
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
return r;
@@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
- dssdev->panel.acb);
+ dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
- &fck, &lck_div, &pck_div);
+ r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
+ &lck_div, &pck_div);
#else
- r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
- &fck, &lck_div, &pck_div);
+ r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
+ &lck_div, &pck_div);
#endif
if (r)
goto err0;
@@ -132,7 +134,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
- dispc_set_lcd_timings(t);
+ dispc_set_lcd_timings(dssdev->manager->id, t);
err0:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -145,10 +147,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
- dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
- OMAP_DSS_LCD_DISPLAY_STN);
- dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
+ dispc_set_parallel_interface_mode(dssdev->manager->id,
+ OMAP_DSS_PARALLELMODE_BYPASS);
+ dispc_set_lcd_display_type(dssdev->manager->id, is_tft ?
+ OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
+ dispc_set_tft_data_lines(dssdev->manager->id,
+ dssdev->phy.dpi.data_lines);
return 0;
}
@@ -234,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
dpi_set_mode(dssdev);
- dispc_go(OMAP_DSS_CHANNEL_LCD);
+ dispc_go(dssdev->manager->id);
}
}
EXPORT_SYMBOL(dpi_set_timings);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index aa4f7a5fae29..ddf3a0560822 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
}
/* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
+static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
+ struct dsi_clock_info *cinfo)
{
if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
return -EINVAL;
@@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
* with DSS2_FCK source also */
cinfo->highfreq = 0;
} else {
- cinfo->clkin = dispc_pclk_rate();
+ cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
if (cinfo->clkin < 32000000)
cinfo->highfreq = 0;
@@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s)
seq_printf(s, "VP_CLK\t\t%lu\n"
"VP_PCLK\t\t%lu\n",
- dispc_lclk_rate(),
- dispc_pclk_rate());
+ dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
+ dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
enable_clocks(0);
}
@@ -2888,7 +2889,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h,
enlarge_update_area);
- dispc_set_lcd_size(*w, *h);
+ dispc_set_lcd_size(dssdev->manager->id, *w, *h);
}
return 0;
@@ -2947,12 +2948,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
return r;
}
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+ dispc_set_lcd_display_type(dssdev->manager->id,
+ OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
- dispc_enable_fifohandcheck(1);
+ dispc_set_parallel_interface_mode(dssdev->manager->id,
+ OMAP_DSS_PARALLELMODE_DSI);
+ dispc_enable_fifohandcheck(dssdev->manager->id, 1);
- dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+ dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
{
struct omap_video_timings timings = {
@@ -2964,7 +2967,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
.vbp = 0,
};
- dispc_set_lcd_timings(&timings);
+ dispc_set_lcd_timings(dssdev->manager->id, &timings);
}
return 0;
@@ -2987,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
cinfo.regm = dssdev->phy.dsi.div.regm;
cinfo.regm3 = dssdev->phy.dsi.div.regm3;
cinfo.regm4 = dssdev->phy.dsi.div.regm4;
- r = dsi_calc_clock_rates(&cinfo);
+ r = dsi_calc_clock_rates(dssdev, &cinfo);
if (r) {
DSSERR("Failed to calc dsi clocks\n");
return r;
@@ -3019,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
return r;
}
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r) {
DSSERR("Failed to set dispc clocks\n");
return r;
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 5c7940d5f282..b394951120ac 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -333,9 +333,9 @@ void dispc_disable_sidle(void);
void dispc_lcd_enable_signal_polarity(bool act_high);
void dispc_lcd_enable_signal(bool enable);
void dispc_pck_free_enable(bool enable);
-void dispc_enable_fifohandcheck(bool enable);
+void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
-void dispc_set_lcd_size(u16 width, u16 height);
+void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
void dispc_set_digit_size(u16 width, u16 height);
u32 dispc_get_plane_fifo_size(enum omap_plane plane);
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
@@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror,
- u8 global_alpha);
+ u8 global_alpha, u8 pre_mult_alpha,
+ enum omap_channel channel);
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
@@ -368,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel);
int dispc_enable_plane(enum omap_plane plane, bool enable);
void dispc_enable_replication(enum omap_plane plane, bool enable);
-void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
-void dispc_set_tft_data_lines(u8 data_lines);
-void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
+void dispc_set_parallel_interface_mode(enum omap_channel channel,
+ enum omap_parallel_interface_mode mode);
+void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
+void dispc_set_lcd_display_type(enum omap_channel channel,
+ enum omap_lcd_display_type type);
void dispc_set_loadmode(enum omap_dss_load_mode mode);
void dispc_set_default_color(enum omap_channel channel, u32 color);
@@ -387,17 +390,21 @@ bool dispc_trans_key_enabled(enum omap_channel ch);
bool dispc_alpha_blending_enabled(enum omap_channel ch);
bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
-void dispc_set_lcd_timings(struct omap_video_timings *timings);
+void dispc_set_lcd_timings(enum omap_channel channel,
+ struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void);
-unsigned long dispc_lclk_rate(void);
-unsigned long dispc_pclk_rate(void);
-void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
+unsigned long dispc_lclk_rate(enum omap_channel channel);
+unsigned long dispc_pclk_rate(enum omap_channel channel);
+void dispc_set_pol_freq(enum omap_channel channel,
+ enum omap_panel_config config, u8 acbi, u8 acb);
void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
struct dispc_clock_info *cinfo);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
-int dispc_set_clock_div(struct dispc_clock_info *cinfo);
-int dispc_get_clock_div(struct dispc_clock_info *cinfo);
+int dispc_set_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo);
+int dispc_get_clock_div(enum omap_channel channel,
+ struct dispc_clock_info *cinfo);
/* VENC */
@@ -424,8 +431,8 @@ void rfbi_dump_regs(struct seq_file *s);
int rfbi_configure(int rfbi_module, int bpp, int lines);
void rfbi_enable_rfbi(bool enable);
-void rfbi_transfer_area(u16 width, u16 height,
- void (callback)(void *data), void *data);
+void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+ u16 height, void (callback)(void *data), void *data);
void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
unsigned long rfbi_get_max_tx_rate(void);
int rfbi_init_display(struct omap_dss_device *display);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 867f68de125f..cf3ef696e141 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_VENC,
};
+static const enum omap_display_type omap4_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
+ .has_feature =
+ FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
+ FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
+
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
@@ -134,11 +150,29 @@ static struct omap_dss_features omap2_dss_features = {
};
/* OMAP3 DSS Features */
-static struct omap_dss_features omap3_dss_features = {
+static struct omap_dss_features omap3430_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .has_feature =
+ FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+ FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
+ FEAT_FUNCGATED,
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3_dss_supported_displays,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
+static struct omap_dss_features omap3630_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
- .has_feature = FEAT_GLOBAL_ALPHA,
+ .has_feature =
+ FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
+ FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
+ FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
.num_mgrs = 2,
.num_ovls = 3,
@@ -146,6 +180,21 @@ static struct omap_dss_features omap3_dss_features = {
.supported_color_modes = omap3_dss_supported_color_modes,
};
+/* OMAP4 DSS Features */
+static struct omap_dss_features omap4_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .has_feature =
+ FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
+ FEAT_MGR_LCD2,
+
+ .num_mgrs = 3,
+ .num_ovls = 3,
+ .supported_displays = omap4_dss_supported_displays,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
/* Functions returning values related to a DSS feature */
int dss_feat_get_num_mgrs(void)
{
@@ -167,6 +216,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
return omap_current_dss_features->supported_color_modes[plane];
}
+bool dss_feat_color_mode_supported(enum omap_plane plane,
+ enum omap_color_mode color_mode)
+{
+ return omap_current_dss_features->supported_color_modes[plane] &
+ color_mode;
+}
+
/* DSS has_feature check */
bool dss_has_feature(enum dss_feat_id id)
{
@@ -186,6 +242,10 @@ void dss_features_init(void)
{
if (cpu_is_omap24xx())
omap_current_dss_features = &omap2_dss_features;
+ else if (cpu_is_omap3630())
+ omap_current_dss_features = &omap3630_dss_features;
+ else if (cpu_is_omap34xx())
+ omap_current_dss_features = &omap3430_dss_features;
else
- omap_current_dss_features = &omap3_dss_features;
+ omap_current_dss_features = &omap4_dss_features;
}
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index cb231eaa9b31..b9c70be92588 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -20,13 +20,19 @@
#ifndef __OMAP2_DSS_FEATURES_H
#define __OMAP2_DSS_FEATURES_H
-#define MAX_DSS_MANAGERS 2
+#define MAX_DSS_MANAGERS 3
#define MAX_DSS_OVERLAYS 3
/* DSS has feature id */
enum dss_feat_id {
FEAT_GLOBAL_ALPHA = 1 << 0,
FEAT_GLOBAL_ALPHA_VID1 = 1 << 1,
+ FEAT_PRE_MULT_ALPHA = 1 << 2,
+ FEAT_LCDENABLEPOL = 1 << 3,
+ FEAT_LCDENABLESIGNAL = 1 << 4,
+ FEAT_PCKFREEENABLE = 1 << 5,
+ FEAT_FUNCGATED = 1 << 6,
+ FEAT_MGR_LCD2 = 1 << 7,
};
/* DSS register field id */
@@ -43,6 +49,8 @@ int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
+bool dss_feat_color_mode_supported(enum omap_plane plane,
+ enum omap_color_mode color_mode);
bool dss_has_feature(enum dss_feat_id id);
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 545e9b9a4d92..172d4e697309 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -406,6 +406,7 @@ struct overlay_cache_data {
u16 out_width; /* if 0, out_width == width */
u16 out_height; /* if 0, out_height == height */
u8 global_alpha;
+ u8 pre_mult_alpha;
enum omap_channel channel;
bool replication;
@@ -512,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
unsigned long timeout = msecs_to_jiffies(500);
u32 irq;
- if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+ if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD;
- else
- irq = DISPC_IRQ_VSYNC;
-
+ } else {
+ if (mgr->id == OMAP_DSS_CHANNEL_LCD)
+ irq = DISPC_IRQ_VSYNC;
+ else
+ irq = DISPC_IRQ_VSYNC2;
+ }
return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
}
@@ -524,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct manager_cache_data *mc;
- enum omap_channel channel;
u32 irq;
int r;
int i;
@@ -535,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
- channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
@@ -543,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
- irq = DISPC_IRQ_FRAMEDONE;
+ irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE
+ : DISPC_IRQ_FRAMEDONE2;
} else {
- irq = DISPC_IRQ_VSYNC;
+ irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_VSYNC
+ : DISPC_IRQ_VSYNC2;
}
- channel = OMAP_DSS_CHANNEL_LCD;
}
mc = &dss_cache.manager_cache[mgr->id];
@@ -594,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
- enum omap_channel channel;
struct overlay_cache_data *oc;
struct omap_dss_device *dssdev;
u32 irq;
@@ -611,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
- channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
@@ -619,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
- irq = DISPC_IRQ_FRAMEDONE;
+ irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_FRAMEDONE
+ : DISPC_IRQ_FRAMEDONE2;
} else {
- irq = DISPC_IRQ_VSYNC;
+ irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+ DISPC_IRQ_VSYNC
+ : DISPC_IRQ_VSYNC2;
}
- channel = OMAP_DSS_CHANNEL_LCD;
}
oc = &dss_cache.overlay_cache[ovl->id];
@@ -842,7 +848,9 @@ static int configure_overlay(enum omap_plane plane)
c->rotation_type,
c->rotation,
c->mirror,
- c->global_alpha);
+ c->global_alpha,
+ c->pre_mult_alpha,
+ c->channel);
if (r) {
/* this shouldn't happen */
@@ -894,10 +902,10 @@ static int configure_dispc(void)
r = 0;
busy = false;
- mgr_busy[0] = dispc_go_busy(0);
- mgr_busy[1] = dispc_go_busy(1);
- mgr_go[0] = false;
- mgr_go[1] = false;
+ for (i = 0; i < num_mgrs; i++) {
+ mgr_busy[i] = dispc_go_busy(i);
+ mgr_go[i] = false;
+ }
/* Commit overlay settings */
for (i = 0; i < num_ovls; ++i) {
@@ -1156,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
const int num_mgrs = dss_feat_get_num_mgrs();
int i, r;
bool mgr_busy[MAX_DSS_MANAGERS];
+ u32 irq_mask;
- mgr_busy[0] = dispc_go_busy(0);
- mgr_busy[1] = dispc_go_busy(1);
+ for (i = 0; i < num_mgrs; i++)
+ mgr_busy[i] = dispc_go_busy(i);
spin_lock(&dss_cache.lock);
@@ -1179,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask)
goto end;
/* re-read busy flags */
- mgr_busy[0] = dispc_go_busy(0);
- mgr_busy[1] = dispc_go_busy(1);
+ for (i = 0; i < num_mgrs; i++)
+ mgr_busy[i] = dispc_go_busy(i);
/* keep running as long as there are busy managers, so that
* we can collect overlay-applied information */
@@ -1189,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask)
goto end;
}
- omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
- DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
- DISPC_IRQ_EVSYNC_EVEN);
+ irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
+ DISPC_IRQ_EVSYNC_EVEN;
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ irq_mask |= DISPC_IRQ_VSYNC2;
+
+ omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
dss_cache.irq_enabled = false;
end:
@@ -1265,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->out_width = ovl->info.out_width;
oc->out_height = ovl->info.out_height;
oc->global_alpha = ovl->info.global_alpha;
+ oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
oc->replication =
dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1383,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
if (!dss_cache.irq_enabled) {
- r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
- DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
- DISPC_IRQ_EVSYNC_EVEN);
+ u32 mask;
+
+ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
+ DISPC_IRQ_EVSYNC_EVEN;
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ mask |= DISPC_IRQ_VSYNC2;
+
+ r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
dss_cache.irq_enabled = true;
}
configure_dispc();
@@ -1477,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
mgr->name = "tv";
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
break;
+ case 2:
+ mgr->name = "lcd2";
+ mgr->id = OMAP_DSS_CHANNEL_LCD2;
+ break;
}
mgr->set_device = &omap_dss_set_device;
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 75642c22cac7..456efef03c20 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
return size;
}
+static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ovl->info.pre_mult_alpha);
+}
+
+static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ /* only GFX and Video2 plane support pre alpha multiplied
+ * set zero for Video1 plane
+ */
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ ovl->id == OMAP_DSS_VIDEO1)
+ info.pre_mult_alpha = 0;
+ else
+ info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
@@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
overlay_enabled_show, overlay_enabled_store);
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
+ overlay_pre_mult_alpha_show,
+ overlay_pre_mult_alpha_store);
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
@@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_output_size.attr,
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
+ &overlay_attr_pre_mult_alpha.attr,
NULL
};
@@ -623,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
int i;
struct omap_overlay_manager *lcd_mgr;
struct omap_overlay_manager *tv_mgr;
+ struct omap_overlay_manager *lcd2_mgr = NULL;
struct omap_overlay_manager *mgr = NULL;
lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
-
- if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
+ if (dss_has_feature(FEAT_MGR_LCD2))
+ lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2);
+
+ if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
+ if (!lcd2_mgr->device || force) {
+ if (lcd2_mgr->device)
+ lcd2_mgr->unset_device(lcd2_mgr);
+ lcd2_mgr->set_device(lcd2_mgr, dssdev);
+ mgr = lcd2_mgr;
+ }
+ } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
if (!lcd_mgr->device || force) {
if (lcd_mgr->device)
lcd_mgr->unset_device(lcd_mgr);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index bbe62464e92d..10a2ffe02882 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
-void rfbi_transfer_area(u16 width, u16 height,
- void (callback)(void *data), void *data)
+void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+ u16 height, void (*callback)(void *data), void *data)
{
u32 l;
@@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height,
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
- dispc_set_lcd_size(width, height);
+ dispc_set_lcd_size(dssdev->manager->id, width, height);
- dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
+ dispc_enable_channel(dssdev->manager->id, true);
rfbi.framedone_callback = callback;
rfbi.framedone_callback_data = data;
@@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h, true);
- dispc_set_lcd_size(*w, *h);
+ dispc_set_lcd_size(dssdev->manager->id, *w, *h);
}
return 0;
@@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,
void (*callback)(void *), void *data)
{
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- rfbi_transfer_area(w, h, callback, data);
+ rfbi_transfer_area(dssdev, w, h, callback, data);
} else {
struct omap_overlay *ovl;
void __iomem *addr;
@@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
goto err1;
}
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
+ dispc_set_lcd_display_type(dssdev->manager->id,
+ OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
+ dispc_set_parallel_interface_mode(dssdev->manager->id,
+ OMAP_DSS_PARALLELMODE_RFBI);
- dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
+ dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
rfbi_configure(dssdev->phy.rfbi.channel,
dssdev->ctrl.pixel_size,
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index ee07a3cc22ef..b64adf7dfc88 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -35,12 +35,16 @@ static struct {
struct regulator *vdds_sdi_reg;
} sdi;
-static void sdi_basic_init(void)
+static void sdi_basic_init(struct omap_dss_device *dssdev)
+
{
- dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
+ dispc_set_parallel_interface_mode(dssdev->manager->id,
+ OMAP_DSS_PARALLELMODE_BYPASS);
+
+ dispc_set_lcd_display_type(dssdev->manager->id,
+ OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
- dispc_set_tft_data_lines(24);
+ dispc_set_tft_data_lines(dssdev->manager->id, 24);
dispc_lcd_enable_signal_polarity(1);
}
@@ -68,20 +72,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
- sdi_basic_init();
+ sdi_basic_init(dssdev);
/* 15.5.9.1.2 */
dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
- dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
- dssdev->panel.acb);
+ dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
+ dssdev->panel.acbi, dssdev->panel.acb);
if (!sdi.skip_init) {
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
&dss_cinfo, &dispc_cinfo);
} else {
r = dss_get_clock_div(&dss_cinfo);
- r = dispc_get_clock_div(&dispc_cinfo);
+ r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
}
if (r)
@@ -102,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
- dispc_set_lcd_timings(t);
+ dispc_set_lcd_timings(dssdev->manager->id, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
goto err2;
- r = dispc_set_clock_div(&dispc_cinfo);
+ r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
goto err2;
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 6a704f176c22..4fdab8e9c496 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -2132,8 +2132,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
char *str, *options, *this_opt;
int r = 0;
- str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
- strcpy(str, def_mode);
+ str = kstrdup(def_mode, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
options = str;
while (!r && (this_opt = strsep(&options, ",")) != NULL) {
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
index fed2a72bc6b6..9441e2eb3dee 100644
--- a/drivers/video/omap2/vram.c
+++ b/drivers/video/omap2/vram.c
@@ -551,12 +551,18 @@ void __init omap_vram_reserve_sdram_memblock(void)
if (!size)
return;
- size = PAGE_ALIGN(size);
+ size = ALIGN(size, SZ_2M);
if (paddr) {
- if ((paddr & ~PAGE_MASK) ||
- !memblock_is_region_memory(paddr, size)) {
- pr_err("Illegal SDRAM region for VRAM\n");
+ if (paddr & ~PAGE_MASK) {
+ pr_err("VRAM start address 0x%08x not page aligned\n",
+ paddr);
+ return;
+ }
+
+ if (!memblock_is_region_memory(paddr, size)) {
+ pr_err("Illegal SDRAM region 0x%08x..0x%08x for VRAM\n",
+ paddr, paddr + size - 1);
return;
}
@@ -570,9 +576,12 @@ void __init omap_vram_reserve_sdram_memblock(void)
return;
}
} else {
- paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT);
+ paddr = memblock_alloc(size, SZ_2M);
}
+ memblock_free(paddr, size);
+ memblock_remove(paddr, size);
+
omap_vram_add_region(paddr, size);
pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c
new file mode 100644
index 000000000000..b81168df253d
--- /dev/null
+++ b/drivers/video/pxa3xx-gcu.c
@@ -0,0 +1,772 @@
+/*
+ * pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers
+ *
+ * This driver needs a DirectFB counterpart in user space, communication
+ * is handled via mmap()ed memory areas and an ioctl.
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (c) 2009 Janine Kropp <nin@directfb.org>
+ * Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.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.
+ */
+
+/*
+ * WARNING: This controller is attached to System Bus 2 of the PXA which
+ * needs its arbiter to be enabled explictly (CKENB & 1<<9).
+ * There is currently no way to do this from Linux, so you need to teach
+ * your bootloader for now.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+
+#include "pxa3xx-gcu.h"
+
+#define DRV_NAME "pxa3xx-gcu"
+#define MISCDEV_MINOR 197
+
+#define REG_GCCR 0x00
+#define GCCR_SYNC_CLR (1 << 9)
+#define GCCR_BP_RST (1 << 8)
+#define GCCR_ABORT (1 << 6)
+#define GCCR_STOP (1 << 4)
+
+#define REG_GCISCR 0x04
+#define REG_GCIECR 0x08
+#define REG_GCRBBR 0x20
+#define REG_GCRBLR 0x24
+#define REG_GCRBHR 0x28
+#define REG_GCRBTR 0x2C
+#define REG_GCRBEXHR 0x30
+
+#define IE_EOB (1 << 0)
+#define IE_EEOB (1 << 5)
+#define IE_ALL 0xff
+
+#define SHARED_SIZE PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared))
+
+/* #define PXA3XX_GCU_DEBUG */
+/* #define PXA3XX_GCU_DEBUG_TIMER */
+
+#ifdef PXA3XX_GCU_DEBUG
+#define QDUMP(msg) \
+ do { \
+ QPRINT(priv, KERN_DEBUG, msg); \
+ } while (0)
+#else
+#define QDUMP(msg) do {} while (0)
+#endif
+
+#define QERROR(msg) \
+ do { \
+ QPRINT(priv, KERN_ERR, msg); \
+ } while (0)
+
+struct pxa3xx_gcu_batch {
+ struct pxa3xx_gcu_batch *next;
+ u32 *ptr;
+ dma_addr_t phys;
+ unsigned long length;
+};
+
+struct pxa3xx_gcu_priv {
+ void __iomem *mmio_base;
+ struct clk *clk;
+ struct pxa3xx_gcu_shared *shared;
+ dma_addr_t shared_phys;
+ struct resource *resource_mem;
+ struct miscdevice misc_dev;
+ struct file_operations misc_fops;
+ wait_queue_head_t wait_idle;
+ wait_queue_head_t wait_free;
+ spinlock_t spinlock;
+ struct timeval base_time;
+
+ struct pxa3xx_gcu_batch *free;
+
+ struct pxa3xx_gcu_batch *ready;
+ struct pxa3xx_gcu_batch *ready_last;
+ struct pxa3xx_gcu_batch *running;
+};
+
+static inline unsigned long
+gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off)
+{
+ return __raw_readl(priv->mmio_base + off);
+}
+
+static inline void
+gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val)
+{
+ __raw_writel(val, priv->mmio_base + off);
+}
+
+#define QPRINT(priv, level, msg) \
+ do { \
+ struct timeval tv; \
+ struct pxa3xx_gcu_shared *shared = priv->shared; \
+ u32 base = gc_readl(priv, REG_GCRBBR); \
+ \
+ do_gettimeofday(&tv); \
+ \
+ printk(level "%ld.%03ld.%03ld - %-17s: %-21s (%s, " \
+ "STATUS " \
+ "0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, " \
+ "T %5ld)\n", \
+ tv.tv_sec - priv->base_time.tv_sec, \
+ tv.tv_usec / 1000, tv.tv_usec % 1000, \
+ __func__, msg, \
+ shared->hw_running ? "running" : " idle", \
+ gc_readl(priv, REG_GCISCR), \
+ gc_readl(priv, REG_GCRBBR), \
+ gc_readl(priv, REG_GCRBLR), \
+ (gc_readl(priv, REG_GCRBEXHR) - base) / 4, \
+ (gc_readl(priv, REG_GCRBHR) - base) / 4, \
+ (gc_readl(priv, REG_GCRBTR) - base) / 4); \
+ } while (0)
+
+static void
+pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv)
+{
+ QDUMP("RESET");
+
+ /* disable interrupts */
+ gc_writel(priv, REG_GCIECR, 0);
+
+ /* reset hardware */
+ gc_writel(priv, REG_GCCR, GCCR_ABORT);
+ gc_writel(priv, REG_GCCR, 0);
+
+ memset(priv->shared, 0, SHARED_SIZE);
+ priv->shared->buffer_phys = priv->shared_phys;
+ priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC;
+
+ do_gettimeofday(&priv->base_time);
+
+ /* set up the ring buffer pointers */
+ gc_writel(priv, REG_GCRBLR, 0);
+ gc_writel(priv, REG_GCRBBR, priv->shared_phys);
+ gc_writel(priv, REG_GCRBTR, priv->shared_phys);
+
+ /* enable all IRQs except EOB */
+ gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB);
+}
+
+static void
+dump_whole_state(struct pxa3xx_gcu_priv *priv)
+{
+ struct pxa3xx_gcu_shared *sh = priv->shared;
+ u32 base = gc_readl(priv, REG_GCRBBR);
+
+ QDUMP("DUMP");
+
+ printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n"
+ "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n",
+ sh->hw_running ? "running" : "idle ",
+ gc_readl(priv, REG_GCISCR),
+ gc_readl(priv, REG_GCRBBR),
+ gc_readl(priv, REG_GCRBLR),
+ (gc_readl(priv, REG_GCRBEXHR) - base) / 4,
+ (gc_readl(priv, REG_GCRBHR) - base) / 4,
+ (gc_readl(priv, REG_GCRBTR) - base) / 4);
+}
+
+static void
+flush_running(struct pxa3xx_gcu_priv *priv)
+{
+ struct pxa3xx_gcu_batch *running = priv->running;
+ struct pxa3xx_gcu_batch *next;
+
+ while (running) {
+ next = running->next;
+ running->next = priv->free;
+ priv->free = running;
+ running = next;
+ }
+
+ priv->running = NULL;
+}
+
+static void
+run_ready(struct pxa3xx_gcu_priv *priv)
+{
+ unsigned int num = 0;
+ struct pxa3xx_gcu_shared *shared = priv->shared;
+ struct pxa3xx_gcu_batch *ready = priv->ready;
+
+ QDUMP("Start");
+
+ BUG_ON(!ready);
+
+ shared->buffer[num++] = 0x05000000;
+
+ while (ready) {
+ shared->buffer[num++] = 0x00000001;
+ shared->buffer[num++] = ready->phys;
+ ready = ready->next;
+ }
+
+ shared->buffer[num++] = 0x05000000;
+ priv->running = priv->ready;
+ priv->ready = priv->ready_last = NULL;
+ gc_writel(priv, REG_GCRBLR, 0);
+ shared->hw_running = 1;
+
+ /* ring base address */
+ gc_writel(priv, REG_GCRBBR, shared->buffer_phys);
+
+ /* ring tail address */
+ gc_writel(priv, REG_GCRBTR, shared->buffer_phys + num * 4);
+
+ /* ring length */
+ gc_writel(priv, REG_GCRBLR, ((num + 63) & ~63) * 4);
+}
+
+static irqreturn_t
+pxa3xx_gcu_handle_irq(int irq, void *ctx)
+{
+ struct pxa3xx_gcu_priv *priv = ctx;
+ struct pxa3xx_gcu_shared *shared = priv->shared;
+ u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL;
+
+ QDUMP("-Interrupt");
+
+ if (!status)
+ return IRQ_NONE;
+
+ spin_lock(&priv->spinlock);
+ shared->num_interrupts++;
+
+ if (status & IE_EEOB) {
+ QDUMP(" [EEOB]");
+
+ flush_running(priv);
+ wake_up_all(&priv->wait_free);
+
+ if (priv->ready) {
+ run_ready(priv);
+ } else {
+ /* There is no more data prepared by the userspace.
+ * Set hw_running = 0 and wait for the next userspace
+ * kick-off */
+ shared->num_idle++;
+ shared->hw_running = 0;
+
+ QDUMP(" '-> Idle.");
+
+ /* set ring buffer length to zero */
+ gc_writel(priv, REG_GCRBLR, 0);
+
+ wake_up_all(&priv->wait_idle);
+ }
+
+ shared->num_done++;
+ } else {
+ QERROR(" [???]");
+ dump_whole_state(priv);
+ }
+
+ /* Clear the interrupt */
+ gc_writel(priv, REG_GCISCR, status);
+ spin_unlock(&priv->spinlock);
+
+ return IRQ_HANDLED;
+}
+
+static int
+pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
+{
+ int ret = 0;
+
+ QDUMP("Waiting for idle...");
+
+ /* Does not need to be atomic. There's a lock in user space,
+ * but anyhow, this is just for statistics. */
+ priv->shared->num_wait_idle++;
+
+ while (priv->shared->hw_running) {
+ int num = priv->shared->num_interrupts;
+ u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
+
+ ret = wait_event_interruptible_timeout(priv->wait_idle,
+ !priv->shared->hw_running, HZ*4);
+
+ if (ret < 0)
+ break;
+
+ if (ret > 0)
+ continue;
+
+ if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
+ priv->shared->num_interrupts == num) {
+ QERROR("TIMEOUT");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ QDUMP("done");
+
+ return ret;
+}
+
+static int
+pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv)
+{
+ int ret = 0;
+
+ QDUMP("Waiting for free...");
+
+ /* Does not need to be atomic. There's a lock in user space,
+ * but anyhow, this is just for statistics. */
+ priv->shared->num_wait_free++;
+
+ while (!priv->free) {
+ u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
+
+ ret = wait_event_interruptible_timeout(priv->wait_free,
+ priv->free, HZ*4);
+
+ if (ret < 0)
+ break;
+
+ if (ret > 0)
+ continue;
+
+ if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) {
+ QERROR("TIMEOUT");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ QDUMP("done");
+
+ return ret;
+}
+
+/* Misc device layer */
+
+static ssize_t
+pxa3xx_gcu_misc_write(struct file *filp, const char *buff,
+ size_t count, loff_t *offp)
+{
+ int ret;
+ unsigned long flags;
+ struct pxa3xx_gcu_batch *buffer;
+ struct pxa3xx_gcu_priv *priv =
+ container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
+
+ int words = count / 4;
+
+ /* Does not need to be atomic. There's a lock in user space,
+ * but anyhow, this is just for statistics. */
+ priv->shared->num_writes++;
+
+ priv->shared->num_words += words;
+
+ /* Last word reserved for batch buffer end command */
+ if (words >= PXA3XX_GCU_BATCH_WORDS)
+ return -E2BIG;
+
+ /* Wait for a free buffer */
+ if (!priv->free) {
+ ret = pxa3xx_gcu_wait_free(priv);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * Get buffer from free list
+ */
+ spin_lock_irqsave(&priv->spinlock, flags);
+
+ buffer = priv->free;
+ priv->free = buffer->next;
+
+ spin_unlock_irqrestore(&priv->spinlock, flags);
+
+
+ /* Copy data from user into buffer */
+ ret = copy_from_user(buffer->ptr, buff, words * 4);
+ if (ret) {
+ spin_lock_irqsave(&priv->spinlock, flags);
+ buffer->next = priv->free;
+ priv->free = buffer;
+ spin_unlock_irqrestore(&priv->spinlock, flags);
+ return ret;
+ }
+
+ buffer->length = words;
+
+ /* Append batch buffer end command */
+ buffer->ptr[words] = 0x01000000;
+
+ /*
+ * Add buffer to ready list
+ */
+ spin_lock_irqsave(&priv->spinlock, flags);
+
+ buffer->next = NULL;
+
+ if (priv->ready) {
+ BUG_ON(priv->ready_last == NULL);
+
+ priv->ready_last->next = buffer;
+ } else
+ priv->ready = buffer;
+
+ priv->ready_last = buffer;
+
+ if (!priv->shared->hw_running)
+ run_ready(priv);
+
+ spin_unlock_irqrestore(&priv->spinlock, flags);
+
+ return words * 4;
+}
+
+
+static long
+pxa3xx_gcu_misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ unsigned long flags;
+ struct pxa3xx_gcu_priv *priv =
+ container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
+
+ switch (cmd) {
+ case PXA3XX_GCU_IOCTL_RESET:
+ spin_lock_irqsave(&priv->spinlock, flags);
+ pxa3xx_gcu_reset(priv);
+ spin_unlock_irqrestore(&priv->spinlock, flags);
+ return 0;
+
+ case PXA3XX_GCU_IOCTL_WAIT_IDLE:
+ return pxa3xx_gcu_wait_idle(priv);
+ }
+
+ return -ENOSYS;
+}
+
+static int
+pxa3xx_gcu_misc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned int size = vma->vm_end - vma->vm_start;
+ struct pxa3xx_gcu_priv *priv =
+ container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
+
+ switch (vma->vm_pgoff) {
+ case 0:
+ /* hand out the shared data area */
+ if (size != SHARED_SIZE)
+ return -EINVAL;
+
+ return dma_mmap_coherent(NULL, vma,
+ priv->shared, priv->shared_phys, size);
+
+ case SHARED_SIZE >> PAGE_SHIFT:
+ /* hand out the MMIO base for direct register access
+ * from userspace */
+ if (size != resource_size(priv->resource_mem))
+ return -EINVAL;
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ return io_remap_pfn_range(vma, vma->vm_start,
+ priv->resource_mem->start >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+ }
+
+ return -EINVAL;
+}
+
+
+#ifdef PXA3XX_GCU_DEBUG_TIMER
+static struct timer_list pxa3xx_gcu_debug_timer;
+
+static void pxa3xx_gcu_debug_timedout(unsigned long ptr)
+{
+ struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr;
+
+ QERROR("Timer DUMP");
+
+ /* init the timer structure */
+ init_timer(&pxa3xx_gcu_debug_timer);
+ pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout;
+ pxa3xx_gcu_debug_timer.data = ptr;
+ pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */
+
+ add_timer(&pxa3xx_gcu_debug_timer);
+}
+
+static void pxa3xx_gcu_init_debug_timer(void)
+{
+ pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer);
+}
+#else
+static inline void pxa3xx_gcu_init_debug_timer(void) {}
+#endif
+
+static int
+add_buffer(struct platform_device *dev,
+ struct pxa3xx_gcu_priv *priv)
+{
+ struct pxa3xx_gcu_batch *buffer;
+
+ buffer = kzalloc(sizeof(struct pxa3xx_gcu_batch), GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
+ &buffer->phys, GFP_KERNEL);
+ if (!buffer->ptr) {
+ kfree(buffer);
+ return -ENOMEM;
+ }
+
+ buffer->next = priv->free;
+
+ priv->free = buffer;
+
+ return 0;
+}
+
+static void
+free_buffers(struct platform_device *dev,
+ struct pxa3xx_gcu_priv *priv)
+{
+ struct pxa3xx_gcu_batch *next, *buffer = priv->free;
+
+ while (buffer) {
+ next = buffer->next;
+
+ dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
+ buffer->ptr, buffer->phys);
+
+ kfree(buffer);
+
+ buffer = next;
+ }
+
+ priv->free = NULL;
+}
+
+static int __devinit
+pxa3xx_gcu_probe(struct platform_device *dev)
+{
+ int i, ret, irq;
+ struct resource *r;
+ struct pxa3xx_gcu_priv *priv;
+
+ priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ for (i = 0; i < 8; i++) {
+ ret = add_buffer(dev, priv);
+ if (ret) {
+ dev_err(&dev->dev, "failed to allocate DMA memory\n");
+ goto err_free_priv;
+ }
+ }
+
+ init_waitqueue_head(&priv->wait_idle);
+ init_waitqueue_head(&priv->wait_free);
+ spin_lock_init(&priv->spinlock);
+
+ /* we allocate the misc device structure as part of our own allocation,
+ * so we can get a pointer to our priv structure later on with
+ * container_of(). This isn't really necessary as we have a fixed minor
+ * number anyway, but this is to avoid statics. */
+
+ priv->misc_fops.owner = THIS_MODULE;
+ priv->misc_fops.write = pxa3xx_gcu_misc_write;
+ priv->misc_fops.unlocked_ioctl = pxa3xx_gcu_misc_ioctl;
+ priv->misc_fops.mmap = pxa3xx_gcu_misc_mmap;
+
+ priv->misc_dev.minor = MISCDEV_MINOR,
+ priv->misc_dev.name = DRV_NAME,
+ priv->misc_dev.fops = &priv->misc_fops,
+
+ /* register misc device */
+ ret = misc_register(&priv->misc_dev);
+ if (ret < 0) {
+ dev_err(&dev->dev, "misc_register() for minor %d failed\n",
+ MISCDEV_MINOR);
+ goto err_free_priv;
+ }
+
+ /* handle IO resources */
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&dev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto err_misc_deregister;
+ }
+
+ if (!request_mem_region(r->start, resource_size(r), dev->name)) {
+ dev_err(&dev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto err_misc_deregister;
+ }
+
+ priv->mmio_base = ioremap_nocache(r->start, resource_size(r));
+ if (!priv->mmio_base) {
+ dev_err(&dev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto err_free_mem_region;
+ }
+
+ /* allocate dma memory */
+ priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE,
+ &priv->shared_phys, GFP_KERNEL);
+
+ if (!priv->shared) {
+ dev_err(&dev->dev, "failed to allocate DMA memory\n");
+ ret = -ENOMEM;
+ goto err_free_io;
+ }
+
+ /* enable the clock */
+ priv->clk = clk_get(&dev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&dev->dev, "failed to get clock\n");
+ ret = -ENODEV;
+ goto err_free_dma;
+ }
+
+ ret = clk_enable(priv->clk);
+ if (ret < 0) {
+ dev_err(&dev->dev, "failed to enable clock\n");
+ goto err_put_clk;
+ }
+
+ /* request the IRQ */
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no IRQ defined\n");
+ ret = -ENODEV;
+ goto err_put_clk;
+ }
+
+ ret = request_irq(irq, pxa3xx_gcu_handle_irq,
+ IRQF_DISABLED, DRV_NAME, priv);
+ if (ret) {
+ dev_err(&dev->dev, "request_irq failed\n");
+ ret = -EBUSY;
+ goto err_put_clk;
+ }
+
+ platform_set_drvdata(dev, priv);
+ priv->resource_mem = r;
+ pxa3xx_gcu_reset(priv);
+ pxa3xx_gcu_init_debug_timer();
+
+ dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
+ (void *) r->start, (void *) priv->shared_phys,
+ SHARED_SIZE, irq);
+ return 0;
+
+err_put_clk:
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+
+err_free_dma:
+ dma_free_coherent(&dev->dev, SHARED_SIZE,
+ priv->shared, priv->shared_phys);
+
+err_free_io:
+ iounmap(priv->mmio_base);
+
+err_free_mem_region:
+ release_mem_region(r->start, resource_size(r));
+
+err_misc_deregister:
+ misc_deregister(&priv->misc_dev);
+
+err_free_priv:
+ platform_set_drvdata(dev, NULL);
+ free_buffers(dev, priv);
+ kfree(priv);
+ return ret;
+}
+
+static int __devexit
+pxa3xx_gcu_remove(struct platform_device *dev)
+{
+ struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev);
+ struct resource *r = priv->resource_mem;
+
+ pxa3xx_gcu_wait_idle(priv);
+
+ misc_deregister(&priv->misc_dev);
+ dma_free_coherent(&dev->dev, SHARED_SIZE,
+ priv->shared, priv->shared_phys);
+ iounmap(priv->mmio_base);
+ release_mem_region(r->start, resource_size(r));
+ platform_set_drvdata(dev, NULL);
+ clk_disable(priv->clk);
+ free_buffers(dev, priv);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver pxa3xx_gcu_driver = {
+ .probe = pxa3xx_gcu_probe,
+ .remove = __devexit_p(pxa3xx_gcu_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init
+pxa3xx_gcu_init(void)
+{
+ return platform_driver_register(&pxa3xx_gcu_driver);
+}
+
+static void __exit
+pxa3xx_gcu_exit(void)
+{
+ platform_driver_unregister(&pxa3xx_gcu_driver);
+}
+
+module_init(pxa3xx_gcu_init);
+module_exit(pxa3xx_gcu_exit);
+
+MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(MISCDEV_MINOR);
+MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, "
+ "Denis Oliver Kropp <dok@directfb.org>, "
+ "Daniel Mack <daniel@caiaq.de>");
diff --git a/drivers/video/pxa3xx-gcu.h b/drivers/video/pxa3xx-gcu.h
new file mode 100644
index 000000000000..0428ed03dc49
--- /dev/null
+++ b/drivers/video/pxa3xx-gcu.h
@@ -0,0 +1,38 @@
+#ifndef __PXA3XX_GCU_H__
+#define __PXA3XX_GCU_H__
+
+#include <linux/types.h>
+
+/* Number of 32bit words in display list (ring buffer). */
+#define PXA3XX_GCU_BUFFER_WORDS ((256 * 1024 - 256) / 4)
+
+/* To be increased when breaking the ABI */
+#define PXA3XX_GCU_SHARED_MAGIC 0x30000001
+
+#define PXA3XX_GCU_BATCH_WORDS 8192
+
+struct pxa3xx_gcu_shared {
+ u32 buffer[PXA3XX_GCU_BUFFER_WORDS];
+
+ bool hw_running;
+
+ unsigned long buffer_phys;
+
+ unsigned int num_words;
+ unsigned int num_writes;
+ unsigned int num_done;
+ unsigned int num_interrupts;
+ unsigned int num_wait_idle;
+ unsigned int num_wait_free;
+ unsigned int num_idle;
+
+ u32 magic;
+};
+
+/* Initialization and synchronization.
+ * Hardware is started upon write(). */
+#define PXA3XX_GCU_IOCTL_RESET _IO('G', 0)
+#define PXA3XX_GCU_IOCTL_WAIT_IDLE _IO('G', 2)
+
+#endif /* __PXA3XX_GCU_H__ */
+
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 618f36bec10d..da388186d617 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -331,7 +331,7 @@ static int riva_bl_get_brightness(struct backlight_device *bd)
return bd->props.brightness;
}
-static struct backlight_ops riva_bl_ops = {
+static const struct backlight_ops riva_bl_ops = {
.get_brightness = riva_bl_get_brightness,
.update_status = riva_bl_update_status,
};
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index a0e22ac483a3..167400e2a182 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -94,7 +94,6 @@ static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_HW_B_RIVA;
chan->adapter.class = i2c_class;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pdev->dev;
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index a6247fc081ab..28b1c6c3d8ac 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -410,28 +410,6 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
************************************************************/
/**
- * bltbit_wait_bitset - waits for change in register value
- * @info : framebuffer structure
- * @bit : value expected in register
- * @timeout : ...
- *
- * waits until value changes INTO bit
- */
-static u8
-bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout)
-{
- while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) {
- udelay(10);
- if (!--timeout) {
- dbg_blit("wait_bitset timeout\n");
- break;
- }
- }
-
- return timeout;
-}
-
-/**
* bltbit_wait_bitclear - waits for change in register value
* @info : frambuffer structure
* @bit : value currently in register
@@ -454,34 +432,6 @@ bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
return timeout;
}
-/**
- * bltbit_fifo_status - checks the current status of the fifo
- * @info : framebuffer structure
- *
- * returns number of free words in buffer
- */
-static u8
-bltbit_fifo_status(struct fb_info *info)
-{
- u8 status;
-
- status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0);
-
- /* its empty so room for 16 words */
- if (status & BBLT_FIFO_EMPTY)
- return 16;
-
- /* its full so we dont want to add */
- if (status & BBLT_FIFO_FULL)
- return 0;
-
- /* its atleast half full but we can add one atleast */
- if (status & BBLT_FIFO_NOT_FULL)
- return 1;
-
- return 0;
-}
-
/*
* s1d13xxxfb_bitblt_copyarea - accelerated copyarea function
* @info : framebuffer structure
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index f9aca9d13d1b..83ce9a04d872 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <mach/map.h>
#include <plat/regs-fb-v4.h>
@@ -1013,8 +1014,30 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
return ret;
}
+static int s3c_fb_open(struct fb_info *info, int user)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+
+ pm_runtime_get_sync(sfb->dev);
+
+ return 0;
+}
+
+static int s3c_fb_release(struct fb_info *info, int user)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+
+ pm_runtime_put_sync(sfb->dev);
+
+ return 0;
+}
+
static struct fb_ops s3c_fb_ops = {
.owner = THIS_MODULE,
+ .fb_open = s3c_fb_open,
+ .fb_release = s3c_fb_release,
.fb_check_var = s3c_fb_check_var,
.fb_set_par = s3c_fb_set_par,
.fb_blank = s3c_fb_blank,
@@ -1322,6 +1345,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
clk_enable(sfb->bus_clk);
+ pm_runtime_enable(sfb->dev);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to find registers\n");
@@ -1360,6 +1385,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
+ platform_set_drvdata(pdev, sfb);
+ pm_runtime_get_sync(sfb->dev);
+
/* setup gpio and output polarity controls */
pd->setup_gpio();
@@ -1400,6 +1428,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, sfb);
+ pm_runtime_put_sync(sfb->dev);
return 0;
@@ -1434,6 +1463,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
int win;
+ pm_runtime_get_sync(sfb->dev);
+
for (win = 0; win < S3C_FB_MAX_WIN; win++)
if (sfb->windows[win])
s3c_fb_release_win(sfb, sfb->windows[win]);
@@ -1450,12 +1481,74 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
kfree(sfb);
+ pm_runtime_put_sync(sfb->dev);
+ pm_runtime_disable(sfb->dev);
+
return 0;
}
#ifdef CONFIG_PM
-static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
+static int s3c_fb_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c_fb *sfb = platform_get_drvdata(pdev);
+ struct s3c_fb_win *win;
+ int win_no;
+
+ for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
+ win = sfb->windows[win_no];
+ if (!win)
+ continue;
+
+ /* use the blank function to push into power-down */
+ s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
+ }
+
+ clk_disable(sfb->bus_clk);
+ return 0;
+}
+
+static int s3c_fb_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c_fb *sfb = platform_get_drvdata(pdev);
+ struct s3c_fb_platdata *pd = sfb->pdata;
+ struct s3c_fb_win *win;
+ int win_no;
+
+ clk_enable(sfb->bus_clk);
+
+ /* setup registers */
+ writel(pd->vidcon1, sfb->regs + VIDCON1);
+
+ /* zero all windows before we do anything */
+ for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
+ s3c_fb_clear_win(sfb, win_no);
+
+ for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
+ void __iomem *regs = sfb->regs + sfb->variant.keycon;
+
+ regs += (win_no * 8);
+ writel(0xffffff, regs + WKEYCON0);
+ writel(0xffffff, regs + WKEYCON1);
+ }
+
+ /* restore framebuffers */
+ for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
+ win = sfb->windows[win_no];
+ if (!win)
+ continue;
+
+ dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
+ s3c_fb_set_par(win->fbinfo);
+ }
+
+ return 0;
+}
+
+int s3c_fb_runtime_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_win *win;
int win_no;
@@ -1473,8 +1566,9 @@ static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int s3c_fb_resume(struct platform_device *pdev)
+int s3c_fb_runtime_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_platdata *pd = sfb->pdata;
struct s3c_fb_win *win;
@@ -1509,9 +1603,12 @@ static int s3c_fb_resume(struct platform_device *pdev)
return 0;
}
+
#else
#define s3c_fb_suspend NULL
#define s3c_fb_resume NULL
+#define s3c_fb_runtime_suspend NULL
+#define s3c_fb_runtime_resume NULL
#endif
@@ -1710,15 +1807,21 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
+static const struct dev_pm_ops s3cfb_pm_ops = {
+ .suspend = s3c_fb_suspend,
+ .resume = s3c_fb_resume,
+ .runtime_suspend = s3c_fb_runtime_suspend,
+ .runtime_resume = s3c_fb_runtime_resume,
+};
+
static struct platform_driver s3c_fb_driver = {
.probe = s3c_fb_probe,
.remove = __devexit_p(s3c_fb_remove),
- .suspend = s3c_fb_suspend,
- .resume = s3c_fb_resume,
.id_table = s3c_fb_driver_ids,
.driver = {
.name = "s3c-fb",
.owner = THIS_MODULE,
+ .pm = &s3cfb_pm_ops,
},
};
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 46b430978bcc..61c819e35f7f 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -918,9 +919,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
}
info->clk = clk_get(NULL, "lcd");
- if (!info->clk || IS_ERR(info->clk)) {
+ if (IS_ERR(info->clk)) {
printk(KERN_ERR "failed to get lcd clock source\n");
- ret = -ENOENT;
+ ret = PTR_ERR(info->clk);
goto release_irq;
}
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 3f3d431033ca..24640c8458ab 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -21,18 +22,40 @@
#include <video/sh_mipi_dsi.h>
#include <video/sh_mobile_lcdc.h>
-#define CMTSRTCTR 0x80d0
-#define CMTSRTREQ 0x8070
-
+#define SYSCTRL 0x0000
+#define SYSCONF 0x0004
+#define TIMSET 0x0008
+#define RESREQSET0 0x0018
+#define RESREQSET1 0x001c
+#define HSTTOVSET 0x0020
+#define LPRTOVSET 0x0024
+#define TATOVSET 0x0028
+#define PRTOVSET 0x002c
+#define DSICTRL 0x0030
#define DSIINTE 0x0060
+#define PHYCTRL 0x0070
+
+/* relative to linkbase */
+#define DTCTR 0x0000
+#define VMCTR1 0x0020
+#define VMCTR2 0x0024
+#define VMLEN1 0x0028
+#define CMTSRTREQ 0x0070
+#define CMTSRTCTR 0x00d0
/* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
#define MAX_SH_MIPI_DSI 2
struct sh_mipi {
void __iomem *base;
+ void __iomem *linkbase;
struct clk *dsit_clk;
struct clk *dsip_clk;
+ struct device *dev;
+
+ void *next_board_data;
+ void (*next_display_on)(void *board_data, struct fb_info *info);
+ void (*next_display_off)(void *board_data);
};
static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
@@ -55,10 +78,10 @@ static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
int cnt = 100;
/* transmit a short packet to LCD panel */
- iowrite32(1 | data, mipi->base + 0x80d0); /* CMTSRTCTR */
- iowrite32(1, mipi->base + 0x8070); /* CMTSRTREQ */
+ iowrite32(1 | data, mipi->linkbase + CMTSRTCTR);
+ iowrite32(1, mipi->linkbase + CMTSRTREQ);
- while ((ioread32(mipi->base + 0x8070) & 1) && --cnt)
+ while ((ioread32(mipi->linkbase + CMTSRTREQ) & 1) && --cnt)
udelay(1);
return cnt ? 0 : -ETIMEDOUT;
@@ -90,7 +113,7 @@ static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
* enable LCDC data tx, transition to LPS after completion of each HS
* packet
*/
- iowrite32(0x00000002 | enable, mipi->base + 0x8000); /* DTCTR */
+ iowrite32(0x00000002 | enable, mipi->linkbase + DTCTR);
}
static void sh_mipi_shutdown(struct platform_device *pdev)
@@ -104,14 +127,22 @@ static void mipi_display_on(void *arg, struct fb_info *info)
{
struct sh_mipi *mipi = arg;
+ pm_runtime_get_sync(mipi->dev);
sh_mipi_dsi_enable(mipi, true);
+
+ if (mipi->next_display_on)
+ mipi->next_display_on(mipi->next_board_data, info);
}
static void mipi_display_off(void *arg)
{
struct sh_mipi *mipi = arg;
+ if (mipi->next_display_off)
+ mipi->next_display_off(mipi->next_board_data);
+
sh_mipi_dsi_enable(mipi, false);
+ pm_runtime_put(mipi->dev);
}
static int __init sh_mipi_setup(struct sh_mipi *mipi,
@@ -119,8 +150,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
{
void __iomem *base = mipi->base;
struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
- u32 pctype, datatype, pixfmt;
- u32 linelength;
+ u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000;
bool yuv;
/*
@@ -223,10 +253,10 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
return -EINVAL;
/* reset DSI link */
- iowrite32(0x00000001, base); /* SYSCTRL */
+ iowrite32(0x00000001, base + SYSCTRL);
/* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
udelay(50);
- iowrite32(0x00000000, base); /* SYSCTRL */
+ iowrite32(0x00000000, base + SYSCTRL);
/* setup DSI link */
@@ -238,7 +268,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
* ECC check enable
* additionally enable first two lanes
*/
- iowrite32(0x00003703, base + 0x04); /* SYSCONF */
+ iowrite32(0x00003703, base + SYSCONF);
/*
* T_wakeup = 0x7000
* T_hs-trail = 3
@@ -246,28 +276,28 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
* T_clk-trail = 3
* T_clk-prepare = 2
*/
- iowrite32(0x70003332, base + 0x08); /* TIMSET */
+ iowrite32(0x70003332, base + TIMSET);
/* no responses requested */
- iowrite32(0x00000000, base + 0x18); /* RESREQSET0 */
+ iowrite32(0x00000000, base + RESREQSET0);
/* request response to packets of type 0x28 */
- iowrite32(0x00000100, base + 0x1c); /* RESREQSET1 */
+ iowrite32(0x00000100, base + RESREQSET1);
/* High-speed transmission timeout, default 0xffffffff */
- iowrite32(0x0fffffff, base + 0x20); /* HSTTOVSET */
+ iowrite32(0x0fffffff, base + HSTTOVSET);
/* LP reception timeout, default 0xffffffff */
- iowrite32(0x0fffffff, base + 0x24); /* LPRTOVSET */
+ iowrite32(0x0fffffff, base + LPRTOVSET);
/* Turn-around timeout, default 0xffffffff */
- iowrite32(0x0fffffff, base + 0x28); /* TATOVSET */
+ iowrite32(0x0fffffff, base + TATOVSET);
/* Peripheral reset timeout, default 0xffffffff */
- iowrite32(0x0fffffff, base + 0x2c); /* PRTOVSET */
+ iowrite32(0x0fffffff, base + PRTOVSET);
/* Enable timeout counters */
- iowrite32(0x00000f00, base + 0x30); /* DSICTRL */
+ iowrite32(0x00000f00, base + DSICTRL);
/* Interrupts not used, disable all */
iowrite32(0, base + DSIINTE);
/* DSI-Tx bias on */
- iowrite32(0x00000001, base + 0x70); /* PHYCTRL */
+ iowrite32(0x00000001, base + PHYCTRL);
udelay(200);
/* Deassert resets, power on, set multiplier */
- iowrite32(0x03070b01, base + 0x70); /* PHYCTRL */
+ iowrite32(0x03070b01, base + PHYCTRL);
/* setup l-bridge */
@@ -275,20 +305,28 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
* Enable transmission of all packets,
* transmit LPS after each HS packet completion
*/
- iowrite32(0x00000006, base + 0x8000); /* DTCTR */
+ iowrite32(0x00000006, mipi->linkbase + DTCTR);
/* VSYNC width = 2 (<< 17) */
- iowrite32(0x00040000 | (pctype << 12) | datatype, base + 0x8020); /* VMCTR1 */
+ iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) |
+ (pdata->clksrc << 16) | (pctype << 12) | datatype,
+ mipi->linkbase + VMCTR1);
+
/*
* Non-burst mode with sync pulses: VSE and HSE are output,
* HSA period allowed, no commands in LP
*/
- iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */
+ if (pdata->flags & SH_MIPI_DSI_HSABM)
+ vmctr2 |= 0x20;
+ if (pdata->flags & SH_MIPI_DSI_HSPBM)
+ vmctr2 |= 0x10;
+ iowrite32(vmctr2, mipi->linkbase + VMCTR2);
+
/*
* 0x660 = 1632 bytes per line (RGB24, 544 pixels: see
* sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default
- * (unused, since VMCTR2[HSABM] = 0)
+ * (unused if VMCTR2[HSABM] = 0)
*/
- iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */
+ iowrite32(1 | (linelength << 16), mipi->linkbase + VMLEN1);
msleep(5);
@@ -321,11 +359,12 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
struct sh_mipi *mipi;
struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
unsigned long rate, f_current;
int idx = pdev->id, ret;
char dsip_clk[] = "dsi.p_clk";
- if (!res || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
+ if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
return -ENODEV;
mutex_lock(&array_lock);
@@ -356,6 +395,20 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
goto emap;
}
+ if (!request_mem_region(res2->start, resource_size(res2), pdev->name)) {
+ dev_err(&pdev->dev, "MIPI register region 2 already claimed\n");
+ ret = -EBUSY;
+ goto ereqreg2;
+ }
+
+ mipi->linkbase = ioremap(res2->start, resource_size(res2));
+ if (!mipi->linkbase) {
+ ret = -ENOMEM;
+ goto emap2;
+ }
+
+ mipi->dev = &pdev->dev;
+
mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
if (IS_ERR(mipi->dsit_clk)) {
ret = PTR_ERR(mipi->dsit_clk);
@@ -405,6 +458,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
mipi_dsi[idx] = mipi;
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_resume(&pdev->dev);
+
ret = sh_mipi_setup(mipi, pdata);
if (ret < 0)
goto emipisetup;
@@ -412,15 +468,22 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
mutex_unlock(&array_lock);
platform_set_drvdata(pdev, mipi);
+ /* Save original LCDC callbacks */
+ mipi->next_board_data = pdata->lcd_chan->board_cfg.board_data;
+ mipi->next_display_on = pdata->lcd_chan->board_cfg.display_on;
+ mipi->next_display_off = pdata->lcd_chan->board_cfg.display_off;
+
/* Set up LCDC callbacks */
pdata->lcd_chan->board_cfg.board_data = mipi;
pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
+ pdata->lcd_chan->board_cfg.owner = THIS_MODULE;
return 0;
emipisetup:
mipi_dsi[idx] = NULL;
+ pm_runtime_disable(&pdev->dev);
clk_disable(mipi->dsip_clk);
eclkpon:
clk_disable(mipi->dsit_clk);
@@ -431,6 +494,10 @@ eclkpget:
esettrate:
clk_put(mipi->dsit_clk);
eclktget:
+ iounmap(mipi->linkbase);
+emap2:
+ release_mem_region(res2->start, resource_size(res2));
+ereqreg2:
iounmap(mipi->base);
emap:
release_mem_region(res->start, resource_size(res));
@@ -447,6 +514,7 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
{
struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
struct sh_mipi *mipi = platform_get_drvdata(pdev);
int i, ret;
@@ -467,14 +535,19 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
if (ret < 0)
return ret;
+ pdata->lcd_chan->board_cfg.owner = NULL;
pdata->lcd_chan->board_cfg.display_on = NULL;
pdata->lcd_chan->board_cfg.display_off = NULL;
pdata->lcd_chan->board_cfg.board_data = NULL;
+ pm_runtime_disable(&pdev->dev);
clk_disable(mipi->dsip_clk);
clk_disable(mipi->dsit_clk);
clk_put(mipi->dsit_clk);
clk_put(mipi->dsip_clk);
+ iounmap(mipi->linkbase);
+ if (res2)
+ release_mem_region(res2->start, resource_size(res2));
iounmap(mipi->base);
if (res)
release_mem_region(res->start, resource_size(res));
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 55b3077ff6ff..74d9f546a2e8 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
+#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
@@ -209,7 +210,11 @@ enum hotplug_state {
struct sh_hdmi {
void __iomem *base;
enum hotplug_state hp_state; /* hot-plug status */
- bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */
+ u8 preprogrammed_vic; /* use a pre-programmed VIC or
+ the external mode */
+ u8 edid_block_addr;
+ u8 edid_segment_nr;
+ u8 edid_blocks;
struct clk *hdmi_clk;
struct device *dev;
struct fb_info *info;
@@ -217,6 +222,7 @@ struct sh_hdmi {
struct delayed_work edid_work;
struct fb_var_screeninfo var;
struct fb_monspecs monspec;
+ struct notifier_block notifier;
};
static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
@@ -342,7 +348,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION);
/* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
- if (!hdmi->preprogrammed_mode)
+ if (!hdmi->preprogrammed_vic)
hdmi_write(hdmi, sync | 1 | (voffset << 4),
HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
}
@@ -466,7 +472,18 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
*/
static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
{
- if (hdmi->var.yres > 480) {
+ if (hdmi->var.pixclock < 10000) {
+ /* for 1080p8bit 148MHz */
+ hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
+ hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
+ hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3);
+ hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5);
+ hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6);
+ hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7);
+ hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
+ hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
+ hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
+ } else if (hdmi->var.pixclock < 30000) {
/* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
/*
* [1:0] Speed_A
@@ -565,13 +582,11 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi)
hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3);
/*
- * VIC = 1280 x 720p: ignored if external config is used
- * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode
+ * VIC should be ignored if external config is used, so, we could just use 0,
+ * but play safe and use a valid value in any case just in case
*/
- if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920)
- vic = 16;
- else if (hdmi->var.yres == 480 && hdmi->var.xres == 720)
- vic = 2;
+ if (hdmi->preprogrammed_vic)
+ vic = hdmi->preprogrammed_vic;
else
vic = 4;
hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4);
@@ -685,11 +700,21 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi)
}
static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
- const struct fb_videomode *mode)
+ const struct fb_videomode *mode,
+ unsigned long *hdmi_rate, unsigned long *parent_rate)
{
- long target = PICOS2KHZ(mode->pixclock) * 1000,
- rate = clk_round_rate(hdmi->hdmi_clk, target);
- unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX;
+ unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error;
+ struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
+ *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target);
+ if ((long)*hdmi_rate < 0)
+ *hdmi_rate = clk_get_rate(hdmi->hdmi_clk);
+
+ rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX;
+ if (rate_error && pdata->clk_optimize_parent)
+ rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate);
+ else if (clk_get_parent(hdmi->hdmi_clk))
+ *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n",
mode->left_margin, mode->xres,
@@ -697,14 +722,15 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
mode->upper_margin, mode->yres,
mode->lower_margin, mode->vsync_len);
- dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target,
- rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0,
- mode->refresh);
+ dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target,
+ rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0,
+ mode->refresh, *parent_rate);
return rate_error;
}
-static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
+static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
+ unsigned long *parent_rate)
{
struct fb_var_screeninfo tmpvar;
struct fb_var_screeninfo *var = &tmpvar;
@@ -713,7 +739,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
struct fb_modelist *modelist = NULL;
unsigned int f_width = 0, f_height = 0, f_refresh = 0;
unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
- bool exact_match = false;
+ bool scanning = false, preferred_bad = false;
u8 edid[128];
char *forced;
int i;
@@ -735,7 +761,38 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
printk(KERN_CONT "\n");
#endif
- fb_edid_to_monspecs(edid, &hdmi->monspec);
+ if (!hdmi->edid_blocks) {
+ fb_edid_to_monspecs(edid, &hdmi->monspec);
+ hdmi->edid_blocks = edid[126] + 1;
+
+ dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n",
+ hdmi->monspec.modedb_len, hdmi->edid_blocks - 1);
+ } else {
+ dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n",
+ edid[0], edid[2]);
+ fb_edid_add_monspecs(edid, &hdmi->monspec);
+ }
+
+ if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 +
+ (hdmi->edid_block_addr >> 7) + 1) {
+ /* More blocks to read */
+ if (hdmi->edid_block_addr) {
+ hdmi->edid_block_addr = 0;
+ hdmi->edid_segment_nr++;
+ } else {
+ hdmi->edid_block_addr = 0x80;
+ }
+ /* Set EDID word address */
+ hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
+ /* Enable EDID interrupt */
+ hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
+ /* Set EDID segment pointer - starts reading EDID */
+ hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
+ return -EAGAIN;
+ }
+
+ /* All E-EDID blocks ready */
+ dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len);
fb_get_options("sh_mobile_lcdc", &forced);
if (forced && *forced) {
@@ -745,6 +802,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
if (i < 2) {
f_width = 0;
f_height = 0;
+ } else {
+ /* The user wants us to use the EDID data */
+ scanning = true;
}
dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n",
f_width, f_height, f_refresh);
@@ -752,34 +812,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
/* Walk monitor modes to find the best or the exact match */
for (i = 0, mode = hdmi->monspec.modedb;
- f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match;
+ i < hdmi->monspec.modedb_len && scanning;
i++, mode++) {
- unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode);
+ unsigned long rate_error;
- /* No interest in unmatching modes */
- if (f_width != mode->xres || f_height != mode->yres)
- continue;
- if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
+ if (!f_width && !f_height) {
/*
- * Exact match if either the refresh rate matches or it
- * hasn't been specified and we've found a mode, for
- * which we can configure the clock precisely
- */
- exact_match = true;
- else if (found && found_rate_error <= rate_error)
- /*
- * We otherwise search for the closest matching clock
- * rate - either if no refresh rate has been specified
- * or we cannot find an exactly matching one
+ * A parameter string "video=sh_mobile_lcdc:0x0" means
+ * use the preferred EDID mode. If it is rejected by
+ * .fb_check_var(), keep looking, until an acceptable
+ * one is found.
*/
+ if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad)
+ scanning = false;
+ else
+ continue;
+ } else if (f_width != mode->xres || f_height != mode->yres) {
+ /* No interest in unmatching modes */
continue;
+ }
+
+ rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate);
+
+ if (scanning) {
+ if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
+ /*
+ * Exact match if either the refresh rate
+ * matches or it hasn't been specified and we've
+ * found a mode, for which we can configure the
+ * clock precisely
+ */
+ scanning = false;
+ else if (found && found_rate_error <= rate_error)
+ /*
+ * We otherwise search for the closest matching
+ * clock rate - either if no refresh rate has
+ * been specified or we cannot find an exactly
+ * matching one
+ */
+ continue;
+ }
/* Check if supported: sufficient fb memory, supported clock-rate */
fb_videomode_to_var(var, mode);
+ var->bits_per_pixel = info->var.bits_per_pixel;
+
if (info && info->fbops->fb_check_var &&
info->fbops->fb_check_var(var, info)) {
- exact_match = false;
+ scanning = true;
+ preferred_bad = true;
continue;
}
@@ -787,6 +869,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
found_rate_error = rate_error;
}
+ hdmi->var.width = hdmi->monspec.max_x * 10;
+ hdmi->var.height = hdmi->monspec.max_y * 10;
+
/*
* TODO 1: if no ->info is present, postpone running the config until
* after ->info first gets registered.
@@ -794,15 +879,15 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
* driver, and passing ->info with HDMI platform data.
*/
if (info && !found) {
- modelist = hdmi->info->modelist.next &&
- !list_empty(&hdmi->info->modelist) ?
- list_entry(hdmi->info->modelist.next,
+ modelist = info->modelist.next &&
+ !list_empty(&info->modelist) ?
+ list_entry(info->modelist.next,
struct fb_modelist, list) :
NULL;
if (modelist) {
found = &modelist->mode;
- found_rate_error = sh_hdmi_rate_error(hdmi, found);
+ found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate);
}
}
@@ -810,16 +895,27 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
if (!found)
return -ENXIO;
- dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
- modelist ? "default" : "EDID", found->xres, found->yres,
- found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
-
- if ((found->xres == 720 && found->yres == 480) ||
- (found->xres == 1280 && found->yres == 720) ||
- (found->xres == 1920 && found->yres == 1080))
- hdmi->preprogrammed_mode = true;
+ if (found->xres == 640 && found->yres == 480 && found->refresh == 60)
+ hdmi->preprogrammed_vic = 1;
+ else if (found->xres == 720 && found->yres == 480 && found->refresh == 60)
+ hdmi->preprogrammed_vic = 2;
+ else if (found->xres == 720 && found->yres == 576 && found->refresh == 50)
+ hdmi->preprogrammed_vic = 17;
+ else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60)
+ hdmi->preprogrammed_vic = 4;
+ else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24)
+ hdmi->preprogrammed_vic = 32;
+ else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50)
+ hdmi->preprogrammed_vic = 31;
+ else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60)
+ hdmi->preprogrammed_vic = 16;
else
- hdmi->preprogrammed_mode = false;
+ hdmi->preprogrammed_vic = 0;
+
+ dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
+ modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external",
+ found->xres, found->yres, found->refresh,
+ PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
fb_videomode_to_var(&hdmi->var, found);
sh_hdmi_external_video_param(hdmi);
@@ -868,32 +964,34 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
/* Check, if hot plug & MSENS pin status are both high */
if ((msens & 0xC0) == 0xC0) {
/* Display plug in */
+ hdmi->edid_segment_nr = 0;
+ hdmi->edid_block_addr = 0;
+ hdmi->edid_blocks = 0;
hdmi->hp_state = HDMI_HOTPLUG_CONNECTED;
/* Set EDID word address */
hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
- /* Set EDID segment pointer */
- hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
/* Enable EDID interrupt */
hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
+ /* Set EDID segment pointer - starts reading EDID */
+ hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
} else if (!(status1 & 0x80)) {
/* Display unplug, beware multiple interrupts */
- if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED)
+ if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) {
+ hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
schedule_delayed_work(&hdmi->edid_work, 0);
-
- hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
+ }
/* display_off will switch back to mode_a */
}
} else if (status1 & 2) {
/* EDID error interrupt: retry */
/* Set EDID word address */
- hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
+ hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
/* Set EDID segment pointer */
- hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
+ hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
} else if (status1 & 4) {
/* Disable EDID interrupt */
hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1);
- hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10));
}
@@ -960,8 +1058,12 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
mode1.xres, mode1.yres, mode2.xres, mode2.yres);
- if (fb_mode_is_equal(&mode1, &mode2))
+ if (fb_mode_is_equal(&mode1, &mode2)) {
+ /* It can be a different monitor with an equal video-mode */
+ old_var->width = new_var->width;
+ old_var->height = new_var->height;
return false;
+ }
dev_dbg(info->dev, "Switching %u -> %u lines\n",
mode1.yres, mode2.yres);
@@ -972,39 +1074,37 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
/**
* sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
- * @hdmi: driver context
- * @pixclock: pixel clock period in picoseconds
- * return: configured positive rate if successful
- * 0 if couldn't set the rate, but managed to enable the clock
- * negative error, if couldn't enable the clock
+ * @hdmi: driver context
+ * @hdmi_rate: HDMI clock frequency in Hz
+ * @parent_rate: if != 0 - set parent clock rate for optimal precision
+ * return: configured positive rate if successful
+ * 0 if couldn't set the rate, but managed to enable the
+ * clock, negative error, if couldn't enable the clock
*/
-static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock)
+static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
+ unsigned long parent_rate)
{
- long rate;
int ret;
- rate = PICOS2KHZ(pixclock) * 1000;
- rate = clk_round_rate(hdmi->hdmi_clk, rate);
- if (rate > 0) {
- ret = clk_set_rate(hdmi->hdmi_clk, rate);
+ if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
+ ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
if (ret < 0) {
- dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret);
- rate = 0;
+ dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret);
+ hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate);
} else {
- dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate);
+ dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate);
}
- } else {
- rate = 0;
- dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate);
}
- ret = clk_enable(hdmi->hdmi_clk);
+ ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate);
if (ret < 0) {
- dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret);
- return ret;
+ dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret);
+ hdmi_rate = 0;
+ } else {
+ dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate);
}
- return rate;
+ return hdmi_rate;
}
/* Hotplug interrupt occurred, read EDID */
@@ -1023,17 +1123,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
mutex_lock(&hdmi->mutex);
- if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
+ if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
+ struct fb_info *info = hdmi->info;
+ unsigned long parent_rate = 0, hdmi_rate;
+
/* A device has been plugged in */
pm_runtime_get_sync(hdmi->dev);
- ret = sh_hdmi_read_edid(hdmi);
+ ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
if (ret < 0)
goto out;
+ hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
+
/* Reconfigure the clock */
- clk_disable(hdmi->hdmi_clk);
- ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock);
+ ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
if (ret < 0)
goto out;
@@ -1042,27 +1146,29 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
/* Switched to another (d) power-save mode */
msleep(10);
- if (!hdmi->info)
+ if (!info)
goto out;
- ch = hdmi->info->par;
+ ch = info->par;
acquire_console_sem();
/* HDMI plug in */
if (!sh_hdmi_must_reconfigure(hdmi) &&
- hdmi->info->state == FBINFO_STATE_RUNNING) {
+ info->state == FBINFO_STATE_RUNNING) {
/*
* First activation with the default monitor - just turn
* on, if we run a resume here, the logo disappears
*/
- if (lock_fb_info(hdmi->info)) {
- sh_hdmi_display_on(hdmi, hdmi->info);
- unlock_fb_info(hdmi->info);
+ if (lock_fb_info(info)) {
+ info->var.width = hdmi->var.width;
+ info->var.height = hdmi->var.height;
+ sh_hdmi_display_on(hdmi, info);
+ unlock_fb_info(info);
}
} else {
/* New monitor or have to wake up */
- fb_set_suspend(hdmi->info, 0);
+ fb_set_suspend(info, 0);
}
release_console_sem();
@@ -1071,6 +1177,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
if (!hdmi->info)
goto out;
+ hdmi->monspec.modedb_len = 0;
+ fb_destroy_modedb(hdmi->monspec.modedb);
+ hdmi->monspec.modedb = NULL;
+
acquire_console_sem();
/* HDMI disconnect */
@@ -1078,11 +1188,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
release_console_sem();
pm_runtime_put(hdmi->dev);
- fb_destroy_modedb(hdmi->monspec.modedb);
}
out:
- if (ret < 0)
+ if (ret < 0 && ret != -EAGAIN)
hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
mutex_unlock(&hdmi->mutex);
@@ -1090,13 +1199,6 @@ out:
}
static int sh_hdmi_notify(struct notifier_block *nb,
- unsigned long action, void *data);
-
-static struct notifier_block sh_hdmi_notifier = {
- .notifier_call = sh_hdmi_notify,
-};
-
-static int sh_hdmi_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct fb_event *event = data;
@@ -1105,7 +1207,7 @@ static int sh_hdmi_notify(struct notifier_block *nb,
struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
struct sh_hdmi *hdmi = board_cfg->board_data;
- if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info)
+ if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
return NOTIFY_DONE;
switch(action) {
@@ -1124,11 +1226,11 @@ static int sh_hdmi_notify(struct notifier_block *nb,
* temporarily, synchronise with the work queue and re-acquire
* the info->lock.
*/
- unlock_fb_info(hdmi->info);
+ unlock_fb_info(info);
mutex_lock(&hdmi->mutex);
hdmi->info = NULL;
mutex_unlock(&hdmi->mutex);
- lock_fb_info(hdmi->info);
+ lock_fb_info(info);
return NOTIFY_OK;
}
return NOTIFY_DONE;
@@ -1163,13 +1265,22 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
goto egetclk;
}
- /* Some arbitrary relaxed pixclock just to get things started */
- rate = sh_hdmi_clk_configure(hdmi, 37037);
+ /* An arbitrary relaxed pixclock just to get things started: from standard 480p */
+ rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037));
+ if (rate > 0)
+ rate = sh_hdmi_clk_configure(hdmi, rate, 0);
+
if (rate < 0) {
ret = rate;
goto erate;
}
+ ret = clk_enable(hdmi->hdmi_clk);
+ if (ret < 0) {
+ dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret);
+ goto erate;
+ }
+
dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate);
if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) {
@@ -1187,10 +1298,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdmi);
- /* Product and revision IDs are 0 in sh-mobile version */
- dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
- hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
-
/* Set up LCDC callbacks */
board_cfg = &pdata->lcd_chan->board_cfg;
board_cfg->owner = THIS_MODULE;
@@ -1203,6 +1310,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
+ /* Product and revision IDs are 0 in sh-mobile version */
+ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
+ hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
+
ret = request_irq(irq, sh_hdmi_hotplug, 0,
dev_name(&pdev->dev), hdmi);
if (ret < 0) {
@@ -1217,6 +1328,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
goto ecodec;
}
+ hdmi->notifier.notifier_call = sh_hdmi_notify;
+ fb_register_client(&hdmi->notifier);
+
return 0;
ecodec:
@@ -1247,6 +1361,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
snd_soc_unregister_codec(&pdev->dev);
+ fb_unregister_client(&hdmi->notifier);
+
board_cfg->display_on = NULL;
board_cfg->display_off = NULL;
board_cfg->board_data = NULL;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 50963739a409..bd4840a8a6b7 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = {
};
#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
-#define DEFAULT_XRES 1280
-#define DEFAULT_YRES 1024
+#define MAX_XRES 1920
+#define MAX_YRES 1080
static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
[LDDCKPAT1R] = 0x400,
@@ -115,15 +115,16 @@ static const struct fb_videomode default_720p = {
.xres = 1280,
.yres = 720,
- .left_margin = 200,
- .right_margin = 88,
- .hsync_len = 48,
+ .left_margin = 220,
+ .right_margin = 110,
+ .hsync_len = 40,
.upper_margin = 20,
.lower_margin = 5,
.vsync_len = 5,
.pixclock = 13468,
+ .refresh = 60,
.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
};
@@ -138,6 +139,7 @@ struct sh_mobile_lcdc_priv {
struct notifier_block notifier;
unsigned long saved_shared_regs[NR_SHARED_REGS];
int started;
+ int forced_bpp; /* 2 channel LCDC must share bpp setting */
};
static bool banked(int reg_nr)
@@ -460,13 +462,18 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
struct sh_mobile_lcdc_chan *ch;
struct sh_mobile_lcdc_board_cfg *board_cfg;
unsigned long tmp;
+ int bpp = 0;
int k, m;
int ret = 0;
/* enable clocks before accessing the hardware */
- for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
- if (priv->ch[k].enabled)
+ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+ if (priv->ch[k].enabled) {
sh_mobile_lcdc_clk_on(priv);
+ if (!bpp)
+ bpp = priv->ch[k].info->var.bits_per_pixel;
+ }
+ }
/* reset */
lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
@@ -534,7 +541,17 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* word and long word swap */
- lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+ switch (bpp) {
+ case 16:
+ lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+ break;
+ case 24:
+ lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7);
+ break;
+ case 32:
+ lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4);
+ break;
+ }
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
ch = &priv->ch[k];
@@ -545,7 +562,16 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* set bpp format in PKF[4:0] */
tmp = lcdc_read_chan(ch, LDDFR);
tmp &= ~0x0001001f;
- tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0;
+ switch (ch->info->var.bits_per_pixel) {
+ case 16:
+ tmp |= 0x03;
+ break;
+ case 24:
+ tmp |= 0x0b;
+ break;
+ case 32:
+ break;
+ }
lcdc_write_chan(ch, LDDFR, tmp);
/* point out our frame buffer */
@@ -859,7 +885,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* Couldn't reconfigure, hopefully, can continue as before */
return;
- info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8);
+ info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8);
/*
* fb_set_var() calls the notifier change internally, only if
@@ -867,7 +893,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
* user event, we have to call the chain ourselves.
*/
event.info = info;
- event.data = &mode2;
+ event.data = &mode1;
fb_notifier_call_chain(evnt, &event);
}
@@ -912,25 +938,30 @@ static int sh_mobile_open(struct fb_info *info, int user)
static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ struct sh_mobile_lcdc_priv *p = ch->lcdc;
- if (var->xres < 160 || var->xres > 1920 ||
- var->yres < 120 || var->yres > 1080 ||
- var->left_margin < 32 || var->left_margin > 320 ||
- var->right_margin < 12 || var->right_margin > 240 ||
- var->upper_margin < 12 || var->upper_margin > 120 ||
- var->lower_margin < 1 || var->lower_margin > 64 ||
- var->hsync_len < 32 || var->hsync_len > 240 ||
- var->vsync_len < 2 || var->vsync_len > 64 ||
- var->pixclock < 6000 || var->pixclock > 40000 ||
+ if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
- dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n",
- var->xres, var->yres,
- var->left_margin, var->right_margin,
- var->upper_margin, var->lower_margin,
- var->hsync_len, var->vsync_len,
- var->pixclock);
+ dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
+ var->left_margin, var->xres, var->right_margin, var->hsync_len,
+ var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
+ PICOS2KHZ(var->pixclock));
+ return -EINVAL;
+ }
+
+ /* only accept the forced_bpp for dual channel configurations */
+ if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
+ return -EINVAL;
+
+ switch (var->bits_per_pixel) {
+ case 16: /* PKF[4:0] = 00011 - RGB 565 */
+ case 24: /* PKF[4:0] = 01011 - RGB 888 */
+ case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+ break;
+ default:
return -EINVAL;
}
+
return 0;
}
@@ -963,19 +994,27 @@ static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
var->transp.length = 0;
break;
- case 32: /* PKF[4:0] = 00000 - RGB 888
- * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
- * this may be because LDDDSR has word swap enabled..
- */
- var->red.offset = 0;
+ case 24: /* PKF[4:0] = 01011 - RGB 888 */
+ var->red.offset = 16;
var->red.length = 8;
- var->green.offset = 24;
+ var->green.offset = 8;
var->green.length = 8;
- var->blue.offset = 16;
+ var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
+
+ case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
default:
return -EINVAL;
}
@@ -1179,6 +1218,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
+ /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
+ if (j == 2)
+ priv->forced_bpp = pdata->ch[0].bpp;
+
priv->base = ioremap_nocache(res->start, resource_size(res));
if (!priv->base)
goto err1;
@@ -1197,6 +1240,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
const struct fb_videomode *mode = cfg->lcd_cfg;
unsigned long max_size = 0;
int k;
+ int num_cfg;
ch->info = framebuffer_alloc(0, &pdev->dev);
if (!ch->info) {
@@ -1224,7 +1268,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
}
if (!mode)
- max_size = DEFAULT_XRES * DEFAULT_YRES;
+ max_size = MAX_XRES * MAX_YRES;
else if (max_cfg)
dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
max_cfg->xres, max_cfg->yres);
@@ -1232,10 +1276,18 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
info->fix = sh_mobile_lcdc_fix;
info->fix.smem_len = max_size * (cfg->bpp / 8) * 2;
- if (!mode)
+ if (!mode) {
mode = &default_720p;
+ num_cfg = 1;
+ } else {
+ num_cfg = cfg->num_cfg;
+ }
+
+ fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
fb_videomode_to_var(var, mode);
+ var->width = cfg->lcd_size_cfg.width;
+ var->height = cfg->lcd_size_cfg.height;
/* Default Y virtual resolution is 2x panel size */
var->yres_virtual = var->yres * 2;
var->activate = FB_ACTIVATE_NOW;
@@ -1281,10 +1333,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
for (i = 0; i < j; i++) {
struct sh_mobile_lcdc_chan *ch = priv->ch + i;
- const struct fb_videomode *mode = ch->cfg.lcd_cfg;
-
- if (!mode)
- mode = &default_720p;
info = ch->info;
@@ -1297,7 +1345,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
}
}
- fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist);
error = register_framebuffer(info);
if (error < 0)
goto err1;
diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c
index c311ad3c3687..66de832361cc 100644
--- a/drivers/video/sis/init.c
+++ b/drivers/video/sis/init.c
@@ -56,17 +56,13 @@
* Used by permission.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include "init.h"
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
#include "300vtbl.h"
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#include "310vtbl.h"
#endif
@@ -78,7 +74,7 @@
/* POINTER INITIALIZATION */
/*********************************************/
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
InitCommonPointer(struct SiS_Private *SiS_Pr)
{
@@ -160,7 +156,7 @@ InitCommonPointer(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
InitTo300Pointer(struct SiS_Private *SiS_Pr)
{
@@ -237,7 +233,7 @@ InitTo300Pointer(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
InitTo310Pointer(struct SiS_Private *SiS_Pr)
{
@@ -321,13 +317,13 @@ bool
SiSInitPtr(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
InitTo300Pointer(SiS_Pr);
#else
return false;
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
InitTo310Pointer(SiS_Pr);
#else
return false;
@@ -340,9 +336,7 @@ SiSInitPtr(struct SiS_Private *SiS_Pr)
/* HELPER: Get ModeID */
/*********************************************/
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
int Depth, bool FSTN, int LCDwidth, int LCDheight)
@@ -882,59 +876,59 @@ SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDispl
/*********************************************/
void
-SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data)
+SiS_SetReg(SISIOADDRESS port, u8 index, u8 data)
{
- OutPortByte(port, index);
- OutPortByte(port + 1, data);
+ outb(index, port);
+ outb(data, port + 1);
}
void
-SiS_SetRegByte(SISIOADDRESS port, unsigned short data)
+SiS_SetRegByte(SISIOADDRESS port, u8 data)
{
- OutPortByte(port, data);
+ outb(data, port);
}
void
-SiS_SetRegShort(SISIOADDRESS port, unsigned short data)
+SiS_SetRegShort(SISIOADDRESS port, u16 data)
{
- OutPortWord(port, data);
+ outw(data, port);
}
void
-SiS_SetRegLong(SISIOADDRESS port, unsigned int data)
+SiS_SetRegLong(SISIOADDRESS port, u32 data)
{
- OutPortLong(port, data);
+ outl(data, port);
}
-unsigned char
-SiS_GetReg(SISIOADDRESS port, unsigned short index)
+u8
+SiS_GetReg(SISIOADDRESS port, u8 index)
{
- OutPortByte(port, index);
- return(InPortByte(port + 1));
+ outb(index, port);
+ return inb(port + 1);
}
-unsigned char
+u8
SiS_GetRegByte(SISIOADDRESS port)
{
- return(InPortByte(port));
+ return inb(port);
}
-unsigned short
+u16
SiS_GetRegShort(SISIOADDRESS port)
{
- return(InPortWord(port));
+ return inw(port);
}
-unsigned int
+u32
SiS_GetRegLong(SISIOADDRESS port)
{
- return(InPortLong(port));
+ return inl(port);
}
void
-SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND, unsigned short DataOR)
+SiS_SetRegANDOR(SISIOADDRESS Port, u8 Index, u8 DataAND, u8 DataOR)
{
- unsigned short temp;
+ u8 temp;
temp = SiS_GetReg(Port, Index);
temp = (temp & (DataAND)) | DataOR;
@@ -942,9 +936,9 @@ SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND,
}
void
-SiS_SetRegAND(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND)
+SiS_SetRegAND(SISIOADDRESS Port, u8 Index, u8 DataAND)
{
- unsigned short temp;
+ u8 temp;
temp = SiS_GetReg(Port, Index);
temp &= DataAND;
@@ -952,9 +946,9 @@ SiS_SetRegAND(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND)
}
void
-SiS_SetRegOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataOR)
+SiS_SetRegOR(SISIOADDRESS Port, u8 Index, u8 DataOR)
{
- unsigned short temp;
+ u8 temp;
temp = SiS_GetReg(Port, Index);
temp |= DataOR;
@@ -1089,7 +1083,7 @@ static void
SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_300:
case SIS_540:
case SIS_630:
@@ -1108,7 +1102,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A);
break;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case SIS_315H:
case SIS_315:
case SIS_315PRO:
@@ -1152,9 +1146,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
/* HELPER: SetLVDSetc */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiSSetLVDSetc(struct SiS_Private *SiS_Pr)
{
@@ -1174,7 +1166,7 @@ SiSSetLVDSetc(struct SiS_Private *SiS_Pr)
if((temp == 1) || (temp == 2)) return;
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_540:
case SIS_630:
case SIS_730:
@@ -1188,7 +1180,7 @@ SiSSetLVDSetc(struct SiS_Private *SiS_Pr)
}
break;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case SIS_550:
case SIS_650:
case SIS_740:
@@ -1420,9 +1412,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
/* HELPER: GetVBType */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_GetVBType(struct SiS_Private *SiS_Pr)
{
@@ -1487,7 +1477,6 @@ SiS_GetVBType(struct SiS_Private *SiS_Pr)
/* HELPER: Check RAM size */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static bool
SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
@@ -1501,13 +1490,12 @@ SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if(AdapterMemSize < memorysize) return false;
return true;
}
-#endif
/*********************************************/
/* HELPER: Get DRAM type */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char
SiS_Get310DRAMType(struct SiS_Private *SiS_Pr)
{
@@ -1574,7 +1562,6 @@ SiS_GetMCLK(struct SiS_Private *SiS_Pr)
/* HELPER: ClearBuffer */
/*********************************************/
-#ifdef SIS_LINUX_KERNEL
static void
SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
@@ -1587,7 +1574,7 @@ SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_ModeType >= ModeEGA) {
if(ModeNo > 0x13) {
- SiS_SetMemory(memaddr, memsize, 0);
+ memset_io(memaddr, 0, memsize);
} else {
pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]);
@@ -1596,10 +1583,9 @@ SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
pBuffer = (unsigned short SISIOMEMTYPE *)memaddr;
for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]);
} else {
- SiS_SetMemory(memaddr, 0x8000, 0);
+ memset_io(memaddr, 0, 0x8000);
}
}
-#endif
/*********************************************/
/* HELPER: SearchModeID */
@@ -2132,7 +2118,7 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_20) {
SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1);
if(!(temp = crt1data[5] & 0x1f)) {
@@ -2215,7 +2201,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb);
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01);
if(SiS_Pr->ChipType == XGI_20) {
unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
@@ -2236,7 +2222,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* FIFO */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void
SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1,
unsigned short *idx2)
@@ -2506,11 +2492,7 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
/* Write foreground and background queue */
-#ifdef SIS_LINUX_KERNEL
templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50);
-#else
- templ = pciReadLong(0x00000000, 0x50);
-#endif
if(SiS_Pr->ChipType == SIS_730) {
@@ -2530,13 +2512,8 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ);
templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0);
-#else
- pciWriteLong(0x00000000, 0x50, templ);
- templ = pciReadLong(0x00000000, 0xA0);
-#endif
/* GUI grant timer (PCI config 0xA3) */
if(SiS_Pr->ChipType == SIS_730) {
@@ -2552,15 +2529,11 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ);
-#else
- pciWriteLong(0x00000000, 0xA0, templ);
-#endif
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
{
@@ -2612,7 +2585,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(VCLK > 150) data |= 0x80;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data);
@@ -2621,7 +2594,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data);
#endif
} else if(SiS_Pr->ChipType < XGI_20) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(VCLK >= 166) data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
@@ -2630,7 +2603,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(VCLK >= 200) data |= 0x0c;
if(SiS_Pr->ChipType == XGI_20) data &= ~0x04;
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
@@ -2675,7 +2648,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short RRTI)
{
unsigned short data, infoflag = 0, modeflag, resindex;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short data2, data3;
#endif
@@ -2736,7 +2709,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data);
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb);
}
@@ -2826,7 +2799,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) ||
(SiS_Pr->ChipType == XGI_40)) {
if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
@@ -2845,7 +2818,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
#endif
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetupDualChip(struct SiS_Private *SiS_Pr)
{
@@ -2999,11 +2972,6 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho
SiS_Pr->SiS_SelectCRT2Rate = 0;
SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
-#ifdef SIS_XORG_XF86
- xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
- SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
-#endif
-
if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
@@ -3028,7 +2996,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho
}
switch(SiS_Pr->ChipType) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case SIS_300:
SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex);
break;
@@ -3039,7 +3007,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho
break;
#endif
default:
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_20) {
unsigned char sr2b = 0, sr2c = 0;
switch(ModeNo) {
@@ -3062,7 +3030,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho
SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == XGI_40) {
SiS_SetupDualChip(SiS_Pr);
}
@@ -3070,11 +3038,9 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho
SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
-#ifdef SIS_LINUX_KERNEL
if(SiS_Pr->SiS_flag_clearbuffer) {
SiS_ClearBuffer(SiS_Pr, ModeNo);
}
-#endif
if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) {
SiS_WaitRetrace1(SiS_Pr);
@@ -3104,7 +3070,7 @@ SiS_InitVB(struct SiS_Private *SiS_Pr)
static void
SiS_ResetVB(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short temp;
@@ -3139,7 +3105,7 @@ SiS_StrangeStuff(struct SiS_Private *SiS_Pr)
* which locks CRT2 in some way to CRT1 timing. Disable
* this here.
*/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((IS_SIS651) || (IS_SISM650) ||
SiS_Pr->ChipType == SIS_340 ||
SiS_Pr->ChipType == XGI_40) {
@@ -3160,7 +3126,7 @@ SiS_StrangeStuff(struct SiS_Private *SiS_Pr)
static void
SiS_Handle760(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned int somebase;
unsigned char temp1, temp2, temp3;
@@ -3170,11 +3136,7 @@ SiS_Handle760(struct SiS_Private *SiS_Pr)
(!(SiS_Pr->SiS_SysFlags & SF_760UMA)) )
return;
-#ifdef SIS_LINUX_KERNEL
somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74);
-#else
- somebase = pciReadWord(0x00001000, 0x74);
-#endif
somebase &= 0xffff;
if(somebase == 0) return;
@@ -3190,105 +3152,34 @@ SiS_Handle760(struct SiS_Private *SiS_Pr)
temp2 = 0x0b;
}
-#ifdef SIS_LINUX_KERNEL
sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1);
sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2);
-#else
- pciWriteByte(0x00000000, 0x7e, temp1);
- pciWriteByte(0x00000000, 0x8d, temp2);
-#endif
SiS_SetRegByte((somebase + 0x85), temp3);
#endif
}
/*********************************************/
-/* X.org/XFree86: SET SCREEN PITCH */
-/*********************************************/
-
-#ifdef SIS_XORG_XF86
-static void
-SiS_SetPitchCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short HDisplay = pSiS->scrnPitch >> 3;
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF));
- SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay >> 8));
-}
-
-static void
-SiS_SetPitchCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short HDisplay = pSiS->scrnPitch2 >> 3;
-
- /* Unlock CRT2 */
- if(pSiS->VGAEngine == SIS_315_VGA)
- SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
- else
- SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
-
- SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF));
- SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8));
-}
-
-static void
-SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
-{
- SISPtr pSiS = SISPTR(pScrn);
- bool isslavemode = false;
-
- if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
- ( ((pSiS->VGAEngine == SIS_300_VGA) &&
- (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
- ((pSiS->VGAEngine == SIS_315_VGA) &&
- (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
- isslavemode = true;
- }
-
- /* We need to set pitch for CRT1 if bridge is in slave mode, too */
- if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) {
- SiS_SetPitchCRT1(SiS_Pr, pScrn);
- }
- /* We must not set the pitch for CRT2 if bridge is in slave mode */
- if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) {
- SiS_SetPitchCRT2(SiS_Pr, pScrn);
- }
-}
-#endif
-
-/*********************************************/
/* SiSSetMode() */
/*********************************************/
-#ifdef SIS_XORG_XF86
-/* We need pScrn for setting the pitch correctly */
-bool
-SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, bool dosetpitch)
-#else
bool
SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
-#endif
{
SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
unsigned short RealModeNo, ModeIdIndex;
unsigned char backupreg = 0;
-#ifdef SIS_LINUX_KERNEL
unsigned short KeepLockReg;
SiS_Pr->UseCustomMode = false;
SiS_Pr->CRT1UsesCustomMode = false;
-#endif
SiS_Pr->SiS_flag_clearbuffer = 0;
if(SiS_Pr->UseCustomMode) {
ModeNo = 0xfe;
} else {
-#ifdef SIS_LINUX_KERNEL
if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1;
-#endif
ModeNo &= 0x7f;
}
@@ -3301,13 +3192,8 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_GetSysFlags(SiS_Pr);
SiS_Pr->SiS_VGAINFO = 0x11;
-#if defined(SIS_XORG_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__))
- if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#endif
-#ifdef SIS_LINUX_KERNEL
KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
-#endif
SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
SiSInitPCIetc(SiS_Pr);
@@ -3344,12 +3230,10 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
SiS_SetLowModeTest(SiS_Pr, ModeNo);
-#ifdef SIS_LINUX_KERNEL
/* Check memory size (kernel framebuffer driver only) */
if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) {
return false;
}
-#endif
SiS_OpenCRTC(SiS_Pr);
@@ -3384,7 +3268,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_DisplayOn(SiS_Pr);
SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(!(SiS_IsDualEdge(SiS_Pr))) {
@@ -3396,7 +3280,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(!SiS_Pr->SiS_ROMNew) {
if(SiS_IsVAMode(SiS_Pr)) {
SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
@@ -3424,424 +3308,16 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
}
}
-#ifdef SIS_XORG_XF86
- if(pScrn) {
- /* SetPitch: Adapt to virtual size & position */
- if((ModeNo > 0x13) && (dosetpitch)) {
- SiS_SetPitch(SiS_Pr, pScrn);
- }
-
- /* Backup/Set ModeNo in BIOS scratch area */
- SiS_GetSetModeID(pScrn, ModeNo);
- }
-#endif
-
SiS_CloseCRTC(SiS_Pr);
SiS_Handle760(SiS_Pr);
-#ifdef SIS_LINUX_KERNEL
/* We never lock registers in XF86 */
if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
-#endif
return true;
}
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetMode() */
-/* for non-Dual-Head mode */
-/*********************************************/
-
-#ifdef SIS_XORG_XF86
-bool
-SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short ModeNo = 0;
-
- SiS_Pr->UseCustomMode = false;
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
- SiS_Pr->CHDisplay,
- (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
- (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
- SiS_Pr->CVDisplay)));
-
- } else {
-
- /* Don't need vbflags here; checks done earlier */
- ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return false;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
-
- }
-
- return(SiSSetMode(SiS_Pr, pScrn, ModeNo, true));
-}
-
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetModeCRT2() */
-/* for Dual-Head modes */
-/*********************************************/
-
-bool
-SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
- SISPtr pSiS = SISPTR(pScrn);
-#ifdef SISDUALHEAD
- SISEntPtr pSiSEnt = pSiS->entityPrivate;
-#endif
- unsigned short ModeIdIndex;
- unsigned short ModeNo = 0;
- unsigned char backupreg = 0;
-
- SiS_Pr->UseCustomMode = false;
-
- /* Remember: Custom modes for CRT2 are ONLY supported
- * -) on the 30x/B/C, and
- * -) if CRT2 is LCD or VGA, or CRT1 is LCDA
- */
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- ModeNo = 0xfe;
-
- } else {
-
- ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return false;
-
- }
-
- SiSRegInit(SiS_Pr, BaseAddr);
- SiSInitPtr(SiS_Pr);
- SiS_GetSysFlags(SiS_Pr);
-#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
- SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#else
- SiS_Pr->SiS_VGAINFO = 0x11;
-#endif
-
- SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
-
- SiSInitPCIetc(SiS_Pr);
- SiSSetLVDSetc(SiS_Pr);
- SiSDetermineROMUsage(SiS_Pr);
-
- /* Save mode info so we can set it from within SetMode for CRT1 */
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- pSiSEnt->CRT2ModeNo = ModeNo;
- pSiSEnt->CRT2DMode = mode;
- pSiSEnt->CRT2IsCustom = IsCustom;
- pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
- pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
-#if 0
- /* We can't set CRT2 mode before CRT1 mode is set - says who...? */
- if(pSiSEnt->CRT1ModeNo == -1) {
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting CRT2 mode delayed until after setting CRT1 mode\n");
- return true;
- }
-#endif
- pSiSEnt->CRT2ModeSet = true;
- }
-#endif
-
- if(SiS_Pr->UseCustomMode) {
-
- unsigned short temptemp = SiS_Pr->CVDisplay;
-
- if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1;
- else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting custom mode %dx%d on CRT2\n",
- SiS_Pr->CHDisplay, temptemp);
-
- } else {
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting standard mode 0x%x on CRT2\n", ModeNo);
-
- }
-
- SiS_UnLockCRT2(SiS_Pr);
-
- if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
- } else {
- ModeIdIndex = 0;
- }
-
- SiS_GetVBType(SiS_Pr);
-
- SiS_InitVB(SiS_Pr);
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- SiS_ResetVB(SiS_Pr);
- SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
- SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- } else {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- }
- }
-
- /* Get VB information (connectors, connected devices) */
- if(!SiS_Pr->UseCustomMode) {
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 1);
- } else {
- /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
- }
- SiS_SetYPbPr(SiS_Pr);
- SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_SetLowModeTest(SiS_Pr, ModeNo);
-
- SiS_ResetSegmentRegisters(SiS_Pr);
-
- /* Set mode on CRT2 */
- if( (SiS_Pr->SiS_VBType & VB_SISVB) ||
- (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
- (SiS_Pr->SiS_IF_DEF_CH70xx != 0) ||
- (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
- SiS_SetCRT2Group(SiS_Pr, ModeNo);
- }
-
- SiS_StrangeStuff(SiS_Pr);
-
- SiS_DisplayOn(SiS_Pr);
- SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-
- if(SiS_Pr->ChipType >= SIS_315H) {
- if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
- if(!(SiS_IsDualEdge(SiS_Pr))) {
- SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
- }
- }
- }
-
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- if(!SiS_Pr->SiS_ROMNew) {
- if(SiS_IsVAMode(SiS_Pr)) {
- SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
- } else {
- SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
- }
- }
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
-
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
- SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
- }
- } else if((SiS_Pr->ChipType == SIS_630) ||
- (SiS_Pr->ChipType == SIS_730)) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
- }
- }
-
- /* SetPitch: Adapt to virtual size & position */
- SiS_SetPitchCRT2(SiS_Pr, pScrn);
-
- SiS_Handle760(SiS_Pr);
-
- return true;
-}
-
-/*********************************************/
-/* X.org/XFree86: SiSBIOSSetModeCRT1() */
-/* for Dual-Head modes */
-/*********************************************/
-
-bool
-SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom)
-{
- SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
- SISPtr pSiS = SISPTR(pScrn);
- unsigned short ModeIdIndex, ModeNo = 0;
- unsigned char backupreg = 0;
-#ifdef SISDUALHEAD
- SISEntPtr pSiSEnt = pSiS->entityPrivate;
- unsigned char backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
- bool backupcustom;
-#endif
-
- SiS_Pr->UseCustomMode = false;
-
- if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
-
- unsigned short temptemp = SiS_Pr->CVDisplay;
-
- if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1;
- else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting custom mode %dx%d on CRT1\n",
- SiS_Pr->CHDisplay, temptemp);
- ModeNo = 0xfe;
-
- } else {
-
- ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */
- if(!ModeNo) return false;
-
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "Setting standard mode 0x%x on CRT1\n", ModeNo);
- }
-
- SiSInitPtr(SiS_Pr);
- SiSRegInit(SiS_Pr, BaseAddr);
- SiS_GetSysFlags(SiS_Pr);
-#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)
- SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
-#else
- SiS_Pr->SiS_VGAINFO = 0x11;
-#endif
-
- SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
-
- SiSInitPCIetc(SiS_Pr);
- SiSSetLVDSetc(SiS_Pr);
- SiSDetermineROMUsage(SiS_Pr);
-
- SiS_UnLockCRT2(SiS_Pr);
-
- if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
- } else {
- ModeIdIndex = 0;
- }
-
- /* Determine VBType */
- SiS_GetVBType(SiS_Pr);
-
- SiS_InitVB(SiS_Pr);
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- } else {
- backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- }
- }
-
- /* Get VB information (connectors, connected devices) */
- /* (We don't care if the current mode is a CRT2 mode) */
- SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0);
- SiS_SetYPbPr(SiS_Pr);
- SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex);
- SiS_SetLowModeTest(SiS_Pr, ModeNo);
-
- SiS_OpenCRTC(SiS_Pr);
-
- /* Set mode on CRT1 */
- SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
- if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
- SiS_SetCRT2Group(SiS_Pr, ModeNo);
- }
-
- /* SetPitch: Adapt to virtual size & position */
- SiS_SetPitchCRT1(SiS_Pr, pScrn);
-
- SiS_HandleCRT1(SiS_Pr);
-
- SiS_StrangeStuff(SiS_Pr);
-
- SiS_CloseCRTC(SiS_Pr);
-
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- pSiSEnt->CRT1ModeNo = ModeNo;
- pSiSEnt->CRT1DMode = mode;
- }
-#endif
-
- if(SiS_Pr->UseCustomMode) {
- SiS_Pr->CRT1UsesCustomMode = true;
- SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
- SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
- } else {
- SiS_Pr->CRT1UsesCustomMode = false;
- }
-
- /* Reset CRT2 if changing mode on CRT1 */
-#ifdef SISDUALHEAD
- if(pSiS->DualHeadMode) {
- if(pSiSEnt->CRT2ModeNo != -1) {
- xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
- "(Re-)Setting mode for CRT2\n");
- backupcustom = SiS_Pr->UseCustomMode;
- backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
- backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
- backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- if(SiS_Pr->SiS_VBType & VB_SISVB) {
- /* Backup LUT-enable */
- if(pSiSEnt->CRT2ModeSet) {
- backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08;
- }
- }
- if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38);
- }
-
- SiSBIOSSetModeCRT2(SiS_Pr, pSiSEnt->pScrn_1,
- pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
-
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35);
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38);
- if(SiS_Pr->SiS_VBType & VB_SISVB) {
- SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d);
- }
- SiS_Pr->UseCustomMode = backupcustom;
- }
- }
-#endif
-
- /* Warning: From here, the custom mode entries in SiS_Pr are
- * possibly overwritten
- */
-
- SiS_DisplayOn(SiS_Pr);
- SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
-
- if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
- if(SiS_Pr->ChipType >= SIS_315H) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
- } else if((SiS_Pr->ChipType == SIS_630) ||
- (SiS_Pr->ChipType == SIS_730)) {
- SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
- }
- }
-
- SiS_Handle760(SiS_Pr);
-
- /* Backup/Set ModeNo in BIOS scratch area */
- SiS_GetSetModeID(pScrn,ModeNo);
-
- return true;
-}
-#endif /* Linux_XF86 */
-
#ifndef GETBITSTR
#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l))
#define GENMASK(mask) BITMASK(1?mask,0?mask)
@@ -3927,7 +3403,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE;
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
tempbx = SiS_Pr->SiS_VGAHT;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempbx = SiS_Pr->PanelHT;
@@ -3936,7 +3412,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
remaining = tempbx % 8;
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* OK for LCDA, LVDS */
tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes;
tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */
@@ -3950,7 +3426,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx;
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) {
SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1);
SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE;
@@ -3982,7 +3458,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
tempax = VGAHDE;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempbx = SiS_Pr->PanelXRes;
@@ -4001,7 +3477,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
tempax = SiS_Pr->PanelYRes;
} else if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Stupid hack for 640x400/320x200 */
if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
if((tempax + tempbx) == 438) tempbx += 16;
@@ -4054,36 +3530,12 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if(modeflag & DoubleScanMode) tempax |= 0x80;
SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n",
- SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
- SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
- SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
- xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
- SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
- SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
- SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
- xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
- SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
- SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
- SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
- xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
-#endif
-#endif
}
void
SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
int xres, int yres,
-#ifdef SIS_XORG_XF86
- DisplayModePtr current
-#endif
-#ifdef SIS_LINUX_KERNEL
struct fb_var_screeninfo *var, bool writeres
-#endif
)
{
unsigned short HRE, HBE, HRS, HBS, HDE, HT;
@@ -4127,25 +3579,10 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
D = B - F - C;
-#ifdef SIS_XORG_XF86
- current->HDisplay = (E * 8);
- current->HSyncStart = (E * 8) + (F * 8);
- current->HSyncEnd = (E * 8) + (F * 8) + (C * 8);
- current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8);
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO,
- "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n",
- A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE);
-#else
- (void)VBS; (void)HBS; (void)A;
-#endif
-#endif
-#ifdef SIS_LINUX_KERNEL
if(writeres) var->xres = xres = E * 8;
var->left_margin = D * 8;
var->right_margin = F * 8;
var->hsync_len = C * 8;
-#endif
/* Vertical */
sr_data = crdata[13];
@@ -4192,30 +3629,10 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
D = B - F - C;
-#ifdef SIS_XORG_XF86
- current->VDisplay = VDE + 1;
- current->VSyncStart = VRS + 1;
- current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1;
- if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32;
- current->VTotal = E + D + C + F;
-#if 0
- current->VDisplay = E;
- current->VSyncStart = E + D;
- current->VSyncEnd = E + D + C;
- current->VTotal = E + D + C + F;
-#endif
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO,
- "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n",
- A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE);
-#endif
-#endif
-#ifdef SIS_LINUX_KERNEL
if(writeres) var->yres = yres = E;
var->upper_margin = D;
var->lower_margin = F;
var->vsync_len = C;
-#endif
if((xres == 320) && ((yres == 200) || (yres == 240))) {
/* Terrible hack, but correct CRTC data for
@@ -4224,17 +3641,9 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
* a negative D. The CRT controller does not
* seem to like correcting HRE to 50)
*/
-#ifdef SIS_XORG_XF86
- current->HDisplay = 320;
- current->HSyncStart = 328;
- current->HSyncEnd = 376;
- current->HTotal = 400;
-#endif
-#ifdef SIS_LINUX_KERNEL
var->left_margin = (400 - 376);
var->right_margin = (328 - 320);
var->hsync_len = (376 - 328);
-#endif
}
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
index b96005c39c67..aff73842d877 100644
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -53,21 +53,8 @@
#ifndef _INIT_H_
#define _INIT_H_
-#include "osdef.h"
#include "initdef.h"
-#ifdef SIS_XORG_XF86
-#include "sis.h"
-#define SIS_NEED_inSISREG
-#define SIS_NEED_inSISREGW
-#define SIS_NEED_inSISREGL
-#define SIS_NEED_outSISREG
-#define SIS_NEED_outSISREGW
-#define SIS_NEED_outSISREGL
-#include "sis_regs.h"
-#endif
-
-#ifdef SIS_LINUX_KERNEL
#include "vgatypes.h"
#include "vstruct.h"
#ifdef SIS_CP
@@ -78,7 +65,6 @@
#include <linux/fb.h>
#include "sis.h"
#include <video/sisfb.h>
-#endif
/* Mode numbers */
static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
@@ -286,7 +272,7 @@ static const struct SiS_ModeResInfo_S SiS_ModeResInfo[] =
{ 1280, 854, 8,16} /* 0x22 */
};
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static const struct SiS_StandTable_S SiS_StandTable[]=
{
/* 0x00: MD_0_200 */
@@ -1521,10 +1507,6 @@ static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1_H[] =
};
bool SiSInitPtr(struct SiS_Private *SiS_Pr);
-#ifdef SIS_XORG_XF86
-unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
- int Depth, bool FSTN, int LCDwith, int LCDheight);
-#endif
unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay,
int VDisplay, int Depth, bool FSTN,
unsigned short CustomT, int LCDwith, int LCDheight,
@@ -1534,33 +1516,14 @@ unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDispla
unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay,
int VDisplay, int Depth, unsigned int VBFlags2);
-void SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data);
-void SiS_SetRegByte(SISIOADDRESS port, unsigned short data);
-void SiS_SetRegShort(SISIOADDRESS port, unsigned short data);
-void SiS_SetRegLong(SISIOADDRESS port, unsigned int data);
-unsigned char SiS_GetReg(SISIOADDRESS port, unsigned short index);
-unsigned char SiS_GetRegByte(SISIOADDRESS port);
-unsigned short SiS_GetRegShort(SISIOADDRESS port);
-unsigned int SiS_GetRegLong(SISIOADDRESS port);
-void SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND,
- unsigned short DataOR);
-void SiS_SetRegAND(SISIOADDRESS Port,unsigned short Index, unsigned short DataAND);
-void SiS_SetRegOR(SISIOADDRESS Port,unsigned short Index, unsigned short DataOR);
-
void SiS_DisplayOn(struct SiS_Private *SiS_Pr);
void SiS_DisplayOff(struct SiS_Private *SiS_Pr);
void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
-#ifndef SIS_LINUX_KERNEL
-void SiSSetLVDSetc(struct SiS_Private *SiS_Pr);
-#endif
void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable);
void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable);
unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_GetVBType(struct SiS_Private *SiS_Pr);
-#endif
bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex);
@@ -1572,37 +1535,19 @@ unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short Mode
unsigned short ModeIdIndex);
unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr,unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short RRTI);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1,
unsigned short *idx2);
unsigned short SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2);
unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index);
#endif
void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
-#ifdef SIS_XORG_XF86
-bool SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo,
- bool dosetpitch);
-bool SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-bool SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-bool SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, bool IsCustom);
-#endif
-#ifdef SIS_LINUX_KERNEL
bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-#endif
void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth);
void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
-#ifdef SIS_XORG_XF86
-void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
- int yres, DisplayModePtr current);
-#endif
-#ifdef SIS_LINUX_KERNEL
void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
int yres, struct fb_var_screeninfo *var, bool writeres);
-#endif
/* From init301.c: */
extern void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
@@ -1626,29 +1571,16 @@ extern unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short
extern bool SiS_IsVAMode(struct SiS_Private *);
extern bool SiS_IsDualEdge(struct SiS_Private *);
-#ifdef SIS_XORG_XF86
-/* From other modules: */
-extern unsigned short SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
- unsigned int VBFlags);
-extern unsigned char SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, unsigned short offset,
- unsigned char value);
-extern unsigned char SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id);
-extern unsigned short SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode,
- unsigned int VBFlags);
-#endif
-
-#ifdef SIS_LINUX_KERNEL
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg);
extern void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg,
unsigned int val);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
extern void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg,
unsigned char val);
extern unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg);
#endif
-#endif
#endif
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
index da33d801c22e..a89e3cafd5ad 100644
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -57,10 +57,6 @@
*
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#if 1
#define SET_EMI /* 302LV/ELV: Set EMI values */
#endif
@@ -75,11 +71,11 @@
#include "init301.h"
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
#include "oem300.h"
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#include "oem310.h"
#endif
@@ -87,9 +83,7 @@
#define SiS_I2CDELAYSHORT 150
static unsigned short SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr);
-#ifdef SIS_LINUX_KERNEL
static void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
-#endif
/*********************************************/
/* HELPER: Lock/Unlock CRT2 */
@@ -106,9 +100,7 @@ SiS_UnLockCRT2(struct SiS_Private *SiS_Pr)
SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
}
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_LockCRT2(struct SiS_Private *SiS_Pr)
{
@@ -138,7 +130,7 @@ SiS_SetRegSR11ANDOR(struct SiS_Private *SiS_Pr, unsigned short DataAND, unsigned
/* HELPER: Get Pointer to LCD structure */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char *
GetLCDStructPtr661(struct SiS_Private *SiS_Pr)
{
@@ -404,7 +396,7 @@ SiS_SaveCRT2Info(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
/* HELPER: GET SOME DATA FROM BIOS ROM */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool
SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr)
{
@@ -449,7 +441,7 @@ SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime)
SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05);
}
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
@@ -457,7 +449,7 @@ SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
@@ -467,7 +459,7 @@ SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
}
#endif
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
@@ -480,14 +472,14 @@ SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
static void
SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
{
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short PanelID, DelayIndex, Delay=0;
#endif
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
if(SiS_Pr->SiS_VBType & VB_SISVB) {
@@ -513,11 +505,11 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
}
SiS_ShortDelay(SiS_Pr, Delay);
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((SiS_Pr->ChipType >= SIS_661) ||
(SiS_Pr->ChipType <= SIS_315PRO) ||
@@ -579,12 +571,12 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_PanelDelayLoop(struct SiS_Private *SiS_Pr, unsigned short DelayTime, unsigned short DelayLoop)
{
@@ -613,7 +605,7 @@ SiS_WaitRetrace1(struct SiS_Private *SiS_Pr)
while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
}
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg)
{
@@ -630,7 +622,7 @@ static void
SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return;
}
@@ -641,7 +633,7 @@ SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr)
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) {
SiS_WaitRetrace1(SiS_Pr);
} else {
@@ -686,7 +678,7 @@ SiS_VBLongWait(struct SiS_Private *SiS_Pr)
/* HELPER: MISC */
/*********************************************/
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool
SiS_Is301B(struct SiS_Private *SiS_Pr)
{
@@ -708,7 +700,7 @@ SiS_CRT2IsLCD(struct SiS_Private *SiS_Pr)
bool
SiS_IsDualEdge(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) {
if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return true;
@@ -721,7 +713,7 @@ SiS_IsDualEdge(struct SiS_Private *SiS_Pr)
bool
SiS_IsVAMode(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short flag;
if(SiS_Pr->ChipType >= SIS_315H) {
@@ -732,7 +724,7 @@ SiS_IsVAMode(struct SiS_Private *SiS_Pr)
return false;
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsVAorLCD(struct SiS_Private *SiS_Pr)
{
@@ -745,7 +737,7 @@ SiS_IsVAorLCD(struct SiS_Private *SiS_Pr)
static bool
SiS_IsDualLink(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_CRT2IsLCD(SiS_Pr)) ||
(SiS_IsVAMode(SiS_Pr))) {
@@ -756,7 +748,7 @@ SiS_IsDualLink(struct SiS_Private *SiS_Pr)
return false;
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_TVEnabled(struct SiS_Private *SiS_Pr)
{
@@ -768,7 +760,7 @@ SiS_TVEnabled(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_LCDAEnabled(struct SiS_Private *SiS_Pr)
{
@@ -777,7 +769,7 @@ SiS_LCDAEnabled(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr)
{
@@ -788,7 +780,7 @@ SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr)
{
@@ -804,7 +796,7 @@ SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsYPbPr(struct SiS_Private *SiS_Pr)
{
@@ -816,7 +808,7 @@ SiS_IsYPbPr(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsChScart(struct SiS_Private *SiS_Pr)
{
@@ -828,7 +820,7 @@ SiS_IsChScart(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr)
{
@@ -848,7 +840,7 @@ SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static bool
SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr)
{
@@ -914,7 +906,7 @@ SiS_BridgeInSlavemode(struct SiS_Private *SiS_Pr)
/*********************************************/
/* Setup general purpose IO for Chrontel communication */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
void
SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo)
{
@@ -923,11 +915,7 @@ SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo)
if(!(SiS_Pr->SiS_ChSW)) return;
-#ifdef SIS_LINUX_KERNEL
acpibase = sisfb_read_lpc_pci_dword(SiS_Pr, 0x74);
-#else
- acpibase = pciReadLong(0x00000800, 0x74);
-#endif
acpibase &= 0xFFFF;
if(!acpibase) return;
temp = SiS_GetRegShort((acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */
@@ -969,7 +957,7 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV);
tempbx |= tempax;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_VBType & VB_SISLCDA) {
if(ModeNo == 0x03) {
@@ -1019,7 +1007,7 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
if(!(SiS_Pr->SiS_VBType & VB_SISVGA2)) {
tempbx &= ~(SetCRT2ToRAMDAC);
@@ -1154,24 +1142,16 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_Pr->SiS_VBInfo = tempbx;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType == SIS_630) {
SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo);
}
#endif
-#ifdef SIS_LINUX_KERNEL
#if 0
printk(KERN_DEBUG "sisfb: (init301: VBInfo= 0x%04x, SetFlag=0x%04x)\n",
SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
#endif
-#endif
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n",
- SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
-#endif
-#endif
}
/*********************************************/
@@ -1415,12 +1395,6 @@ SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
}
SiS_Pr->SiS_VBInfo &= ~SetPALTV;
-
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo);
-#endif
-#endif
}
/*********************************************/
@@ -1443,22 +1417,10 @@ SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr)
static void
SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr;
unsigned short temp;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
- SiS_Pr->PanelHT, SiS_Pr->PanelVT,
- SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
- SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
-#endif
-#endif
-
if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) {
if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) {
SiS_Pr->SiS_NeedRomModeData = true;
@@ -1480,18 +1442,6 @@ SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr)
SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C =
SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20];
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Paneldata BIOS: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
- SiS_Pr->PanelHT, SiS_Pr->PanelVT,
- SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
- SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
- SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
-#endif
-#endif
-
}
#endif
}
@@ -1517,13 +1467,13 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
{
unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0;
bool panelcanscale = false;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
static const unsigned char SiS300SeriesLCDRes[] =
{ 0, 1, 2, 3, 7, 4, 5, 8,
0, 0, 10, 0, 0, 0, 0, 15 };
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *myptr = NULL;
#endif
@@ -1562,7 +1512,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1;
}
temp &= 0x0f;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType < SIS_315H) {
/* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */
if(SiS_Pr->SiS_VBType & VB_SIS301) {
@@ -1574,7 +1524,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
#endif
/* Translate to our internal types */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType == SIS_550) {
if (temp == Panel310_1152x768) temp = Panel_320x240_2; /* Verified working */
else if(temp == Panel310_320x240_2) temp = Panel_320x240_2;
@@ -1597,7 +1547,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->SiS_LCDResInfo = temp;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
@@ -1639,7 +1589,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
/* Dual link, Pass 1:1 BIOS default, etc. */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_661) {
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11;
@@ -2076,7 +2026,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
}
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) {
SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */
@@ -2186,17 +2136,10 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->SiS_SetFlag |= LCDVESATiming;
}
-#ifdef SIS_LINUX_KERNEL
#if 0
printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
#endif
-#endif
-#ifdef SIS_XORG_XF86
- xf86DrvMsgVerb(0, X_PROBED, 4,
- "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n",
- SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag);
-#endif
}
/*********************************************/
@@ -2359,7 +2302,7 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
VCLKIndex = SiS_Pr->PanelVCLKIdx315;
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Special Timing: Barco iQ Pro R series */
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44;
@@ -2410,12 +2353,6 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex);
-#endif
-#endif
-
return VCLKIndex;
}
@@ -2428,10 +2365,10 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
{
unsigned short i, j, modeflag, tempah=0;
short tempcl;
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned short tempbl;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short tempah2, tempbl2;
#endif
@@ -2454,7 +2391,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---- 300 series ---- */
+#ifdef CONFIG_FB_SIS_300 /* ---- 300 series ---- */
/* For 301BDH: (with LCD via LVDS) */
if(SiS_Pr->SiS_VBType & VB_NoLCD) {
@@ -2477,11 +2414,11 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------- 315/330 series ------ */
+#ifdef CONFIG_FB_SIS_315 /* ------- 315/330 series ------ */
if(ModeNo > 0x13) {
tempcl -= ModeVGA;
@@ -2494,7 +2431,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50;
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
@@ -2503,7 +2440,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->ChipType < SIS_315H) {
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah);
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);
} else if(SiS_Pr->SiS_VBType & VB_SISVB) {
@@ -2584,7 +2521,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* LVDS can only be slave in 8bpp modes */
tempah = 0x80;
if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) {
@@ -2604,7 +2541,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
} else {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
tempah = 0;
if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
tempah |= 0x02;
@@ -2626,7 +2563,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if(SiS_Pr->ChipType >= SIS_315H) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); */
/* The following is nearly unpreditable and varies from machine
@@ -2718,11 +2655,11 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) ||
@@ -2745,7 +2682,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
} else { /* LVDS */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
@@ -2931,7 +2868,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
@@ -3036,7 +2973,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
case Panel_1280x1024: tempbx = 24; break;
case Panel_1400x1050: tempbx = 26; break;
case Panel_1600x1200: tempbx = 28; break;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case Panel_Barco1366: tempbx = 80; break;
#endif
}
@@ -3053,7 +2990,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 30;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
tempbx = 82;
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
@@ -3189,7 +3126,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex);
#endif
@@ -3214,7 +3151,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
case 16: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break;
case 18: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break;
case 20: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break;
case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break;
case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break;
@@ -3248,7 +3185,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
(SiS_Pr->SiS_SetFlag & SetDOSMode) ) {
SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
if(ResIndex < 0x08) {
SiS_Pr->SiS_HDE = 1280;
@@ -3270,7 +3207,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
unsigned short resinfo, CRT2Index, ResIndex;
const struct SiS_LCDData *LCDPtr = NULL;
const struct SiS_TVData *TVPtr = NULL;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
short resinfo661;
#endif
@@ -3283,7 +3220,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
} else {
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661;
if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
(SiS_Pr->SiS_SetFlag & LCDVESATiming) &&
@@ -3460,7 +3397,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
} else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr];
SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1];
SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8);
@@ -3520,19 +3457,13 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
case Panel_1680x1050 :
case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break;
case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break;
case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break;
#endif
default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
-#endif
-#endif
-
SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX;
SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT;
@@ -3624,7 +3555,7 @@ SiS_GetLVDSDesPtr(struct SiS_Private *SiS_Pr)
{
const struct SiS_LVDSDes *PanelDesPtr = NULL;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
if(SiS_Pr->ChipType < SIS_315H) {
@@ -3696,7 +3627,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
/* non-pass 1:1 only, see above */
if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) {
@@ -3771,7 +3702,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
} else {
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
switch(SiS_Pr->SiS_LCDResInfo) {
case Panel_800x600:
if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) {
@@ -3816,7 +3747,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
}
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(SiS_Pr->SiS_LCDResInfo) {
case Panel_1024x768:
case Panel_1280x1024:
@@ -3844,7 +3775,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
if(SiS_Pr->ChipType < SIS_315H) {
if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320;
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480;
if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804;
if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704;
@@ -3866,7 +3797,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
/* DISABLE VIDEO BRIDGE */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static int
SiS_HandlePWD(struct SiS_Private *SiS_Pr)
{
@@ -3891,11 +3822,6 @@ SiS_HandlePWD(struct SiS_Private *SiS_Pr)
ret = 1;
}
SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x27,0x7f,temp);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, 0, "Setting PWD %x\n", temp);
-#endif
-#endif
}
#endif
return ret;
@@ -3909,7 +3835,7 @@ SiS_HandlePWD(struct SiS_Private *SiS_Pr)
void
SiS_DisableBridge(struct SiS_Private *SiS_Pr)
{
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short tempah, pushax=0, modenum;
#endif
unsigned short temp=0;
@@ -3920,7 +3846,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(!(SiS_CR36BIOSWord23b(SiS_Pr))) {
if(SiS_Pr->SiS_VBType & VB_SISLVDS) {
@@ -3953,11 +3879,11 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
}
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
int didpwd = 0;
bool custom1 = (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
@@ -4081,14 +4007,14 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
} else { /* ============ For 301 ================ */
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(!(SiS_CR36BIOSWord23b(SiS_Pr))) {
SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08);
SiS_PanelDelay(SiS_Pr, 3);
@@ -4111,7 +4037,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
} else {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */
if( (!(SiS_CRT2IsLCD(SiS_Pr))) ||
(!(SiS_CR36BIOSWord23d(SiS_Pr))) ) {
@@ -4127,7 +4053,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
SiS_SetCH700x(SiS_Pr,0x0E,0x09);
@@ -4171,11 +4097,11 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04);
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
if(!(SiS_IsNotM650orLater(SiS_Pr))) {
/*if(SiS_Pr->ChipType < SIS_340) { */ /* XGI needs this */
@@ -4288,7 +4214,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 315 series */
@@ -4304,14 +4230,12 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
* from outside the context of a mode switch!
* MUST call getVBType before calling this
*/
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_EnableBridge(struct SiS_Private *SiS_Pr)
{
unsigned short temp=0, tempah;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short temp1, pushax=0;
bool delaylong = false;
#endif
@@ -4322,7 +4246,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_CRT2IsLCD(SiS_Pr)) {
if(SiS_Pr->SiS_VBType & VB_SISLVDS) {
@@ -4385,11 +4309,11 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
#ifdef SET_EMI
unsigned char r30=0, r31=0, r32=0, r33=0, cr36=0;
@@ -4688,7 +4612,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
@@ -4739,7 +4663,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
if(SiS_CRT2IsLCD(SiS_Pr)) {
if(SiS_Pr->ChipType == SIS_730) {
@@ -4783,11 +4707,11 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
}
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
if(!(SiS_IsNotM650orLater(SiS_Pr))) {
/*if(SiS_Pr->ChipType < SIS_340) {*/ /* XGI needs this */
@@ -4881,7 +4805,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 310 series */
@@ -4971,7 +4895,7 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---- 300 series --- */
+#ifdef CONFIG_FB_SIS_300 /* ---- 300 series --- */
if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* 630 - 301B(-DH) */
@@ -5000,11 +4924,11 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
}
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------- 315 series ------ */
+#ifdef CONFIG_FB_SIS_315 /* ------- 315 series ------ */
if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* 315 - LVDS */
@@ -5076,13 +5000,13 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
}
}
/* Set CRT2 FIFO on 300/540/630/730 */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo)
{
@@ -5154,13 +5078,8 @@ SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo)
} else {
-#ifdef SIS_LINUX_KERNEL
pci50 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50);
pciA0 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xa0);
-#else
- pci50 = pciReadLong(0x00000000, 0x50);
- pciA0 = pciReadLong(0x00000000, 0xA0);
-#endif
if(SiS_Pr->ChipType == SIS_730) {
@@ -5262,7 +5181,7 @@ SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo)
#endif
/* Set CRT2 FIFO on 315/330 series */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void
SiS_SetCRT2FIFO_310(struct SiS_Private *SiS_Pr)
{
@@ -5420,27 +5339,6 @@ SiS_SetGroup1_301(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned sho
temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); /* ? */
-
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n",
- SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
- SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
- SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
-
- xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
- SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
- SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
- SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
- xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
- SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
- SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
- SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
- SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
- xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
-#endif
-#endif
}
/* Setup panel link
@@ -5455,17 +5353,17 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
unsigned short push2, tempax, tempbx, tempcx, temp;
unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0;
bool islvds = false, issis = false, chkdclkfirst = false;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned short crt2crtc = 0;
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short pushcx;
#endif
if(ModeNo <= 0x13) {
modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
#endif
} else if(SiS_Pr->UseCustomMode) {
@@ -5473,7 +5371,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
} else {
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
#endif
}
@@ -5494,7 +5392,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
}
}
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
if(IS_SIS330) {
SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
@@ -5744,7 +5642,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* 300 series */
+#ifdef CONFIG_FB_SIS_300 /* 300 series */
tempeax = SiS_Pr->SiS_VGAVDE << 6;
temp = (tempeax % (unsigned int)SiS_Pr->SiS_VDE);
tempeax = tempeax / (unsigned int)SiS_Pr->SiS_VDE;
@@ -5755,11 +5653,11 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
temp = (unsigned short)(tempeax & 0x00FF);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */
tempvcfact = temp;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* 315 series */
+#ifdef CONFIG_FB_SIS_315 /* 315 series */
tempeax = SiS_Pr->SiS_VGAVDE << 18;
tempebx = SiS_Pr->SiS_VDE;
temp = (tempeax % tempebx);
@@ -5845,7 +5743,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
temp = (unsigned short)(tempecx & 0x00FF);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SISLVDS)) {
@@ -5863,7 +5761,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned char *trumpdata;
@@ -5899,7 +5797,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00);
@@ -5954,7 +5852,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
temp = tempax & 0x00FF;
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,temp);
temp = ((tempax & 0xFF00) >> 8) << 3;
- SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp);
+ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, 0x44, 0x07, temp);
tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */
if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 ||
@@ -5968,7 +5866,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
temp = ((tempeax & 0xFF0000) >> 16) | 0x10;
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,temp);
temp = ((tempeax & 0x01000000) >> 24) << 7;
- SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
+ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port, 0x3C, 0x7F, temp);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x03);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0x50);
@@ -5999,7 +5897,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a);
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
/* Set Part 1 */
@@ -6007,12 +5905,12 @@ static void
SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex)
{
-#if defined(SIS300) || defined(SIS315H)
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
#endif
unsigned short temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0;
unsigned short pushbx=0, CRT1Index=0, modeflag, resinfo=0;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short tempbl=0;
#endif
@@ -6038,11 +5936,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
if(SiS_Pr->ChipType < SIS_315H ) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo);
#endif
} else {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetCRT2FIFO_310(SiS_Pr);
#endif
}
@@ -6051,7 +5949,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
if(SiS_Pr->ChipType < SIS_315H ) {
-#ifdef SIS300 /* ------------- 300 series --------------*/
+#ifdef CONFIG_FB_SIS_300 /* ------------- 300 series --------------*/
temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */
@@ -6070,11 +5968,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
bridgeadd = 12;
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* ------------------- 315/330 series --------------- */
+#ifdef CONFIG_FB_SIS_315 /* ------------------- 315/330 series --------------- */
tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */
if(modeflag & HalfDCLK) {
@@ -6125,7 +6023,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
}
}
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
} /* 315/330 series */
@@ -6256,7 +6154,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
if(SiS_Pr->ChipType < SIS_315H) {
-#ifdef SIS300 /* ---------- 300 series -------------- */
+#ifdef CONFIG_FB_SIS_300 /* ---------- 300 series -------------- */
if(SiS_Pr->SiS_VBType & VB_SISVB) {
temp = 0x20;
@@ -6310,11 +6208,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
-#endif /* SIS300 */
+#endif /* CONFIG_FB_SIS_300 */
} else {
-#ifdef SIS315H /* --------------- 315/330 series ---------------*/
+#ifdef CONFIG_FB_SIS_315 /* --------------- 315/330 series ---------------*/
if(SiS_Pr->ChipType < SIS_661) {
@@ -6349,7 +6247,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
if(modeflag & HalfDCLK) tempax |= 0x40;
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
-#endif /* SIS315H */
+#endif /* CONFIG_FB_SIS_315 */
}
@@ -6381,7 +6279,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
/* SET PART 2 REGISTER GROUP */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned char *
SiS_GetGroup2CLVXPtr(struct SiS_Private *SiS_Pr, int tabletype)
{
@@ -6478,7 +6376,7 @@ SiS_GetCRT2Part2Ptr(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned sh
}
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SiS_Group2LCDSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short crt2crtc)
{
@@ -6690,7 +6588,7 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
unsigned int longtemp, PhaseIndex;
bool newtvphase;
const unsigned char *TimingPoint;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short resindex, CRT2Index;
const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL;
@@ -7069,7 +6967,7 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
&CRT2Index, &resindex)) {
switch(CRT2Index) {
@@ -7130,12 +7028,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
/* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */
@@ -7184,12 +7076,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
tempbx = SiS_Pr->CVSyncStart;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */
temp = (tempbx >> 4) & 0xF0;
@@ -7201,15 +7087,9 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
temp |= (SiS_Pr->CVSyncEnd & 0x0f);
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f));
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_Group2LCDSpecial(SiS_Pr, ModeNo, crt2crtc);
#endif
@@ -7245,12 +7125,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
tempax >>= 1;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx);
-#endif
-#endif
-
tempbx += bridgeoffset;
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */
@@ -7276,12 +7150,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
tempbx += bridgeoffset;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */
SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0));
@@ -7300,20 +7168,14 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
tempbx += bridgeoffset;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx);
-#endif
-#endif
-
SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */
SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
SiS_Set300Part2Regs(SiS_Pr, ModeIdIndex, RefreshRateTableIndex, ModeNo);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
} /* CRT2-LCD from table */
#endif
}
@@ -7382,7 +7244,7 @@ SiS_SetGroup3(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
/* SET PART 4 REGISTER GROUP */
/*********************************************/
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
#if 0
static void
SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift)
@@ -8011,7 +7873,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
/* Chrontel 7005 - I assume that it does not come with a 315 series chip */
@@ -8124,7 +7986,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
/* Chrontel 7019 - assumed that it does not come with a 300 series chip */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
unsigned short temp;
@@ -8175,7 +8037,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
}
-#ifdef SIS315H /* ----------- 315 series only ---------- */
+#ifdef CONFIG_FB_SIS_315 /* ----------- 315 series only ---------- */
void
SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr)
@@ -8657,7 +8519,7 @@ SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr)
bool
SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
#endif
unsigned short ModeIdIndex, RefreshRateTableIndex;
@@ -8703,16 +8565,6 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES);
- xf86DrvMsg(0, X_INFO, "(init301: HDE 0x%03x VDE 0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE);
- xf86DrvMsg(0, X_INFO, "(init301: VGAHDE 0x%03x VGAVDE 0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE);
- xf86DrvMsg(0, X_INFO, "(init301: HT 0x%03x VT 0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT);
- xf86DrvMsg(0, X_INFO, "(init301: VGAHT 0x%03x VGAVT 0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT);
-#endif
-#endif
-
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
}
@@ -8722,12 +8574,12 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
#endif
SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex);
SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetGroup4_C_ELV(SiS_Pr, ModeNo, ModeIdIndex);
#endif
SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex);
@@ -8758,7 +8610,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
SiS_SetCH701xForLCD(SiS_Pr);
#endif
}
@@ -8771,7 +8623,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
if(SiS_Pr->ChipType < SIS_315H) {
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
if(SiS_Pr->SiS_UseOEM) {
@@ -8794,7 +8646,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
}
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
if(SiS_Pr->ChipType >= SIS_315H) {
if(SiS_Pr->SiS_SetFlag & LowModeTests) {
if(SiS_Pr->ChipType < SIS_661) {
@@ -8873,7 +8725,7 @@ SiS_SetupDDCN(struct SiS_Private *SiS_Pr)
}
}
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static unsigned char *
SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
{
@@ -8923,11 +8775,6 @@ SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr);
if(!dataptr) return false;
}
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Trumpion block success\n");
-#endif
-#endif
return true;
}
#endif
@@ -9002,9 +8849,7 @@ SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val)
SiS_SetChReg(SiS_Pr, reg, val, 0);
}
-#ifdef SIS_LINUX_KERNEL
static
-#endif
void
SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val)
{
@@ -9091,9 +8936,7 @@ SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempbx)
/* Read from Chrontel 70xx */
/* Parameter is [Register no (S7-S0)] */
-#ifdef SIS_LINUX_KERNEL
static
-#endif
unsigned short
SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempbx)
{
@@ -9114,9 +8957,7 @@ SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg,
}
/* Our own DDC functions */
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine,
unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32,
@@ -9224,12 +9065,6 @@ SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine,
SiS_SetupDDCN(SiS_Pr);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n",
- SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp);
-#endif
-#endif
return 0;
}
@@ -9292,11 +9127,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
SiS_SetSwitchDDC2(SiS_Pr);
if(SiS_PrepareDDC(SiS_Pr)) {
SiS_SetStop(SiS_Pr);
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n");
-#endif
-#endif
return 0xFFFF;
}
mask = 0xf0;
@@ -9310,11 +9140,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
} else {
failed = true;
ret = 0xFFFF;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n");
-#endif
-#endif
}
}
if(!failed) {
@@ -9324,11 +9149,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
if(temp == value) ret = 0;
else {
ret = 0xFFFF;
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n");
-#endif
-#endif
if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
if(temp == 0x30) ret = 0;
}
@@ -9338,9 +9158,7 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
return ret;
}
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_ProbeDDC(struct SiS_Private *SiS_Pr)
{
@@ -9357,9 +9175,7 @@ SiS_ProbeDDC(struct SiS_Private *SiS_Pr)
return flag;
}
-#ifndef SIS_XORG_XF86
static
-#endif
unsigned short
SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer)
{
@@ -9606,11 +9422,6 @@ SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr)
temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
} while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog);
if (!watchdog) {
-#ifdef SIS_XORG_XF86
-#ifdef TWDEBUG
- xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n");
-#endif
-#endif
return 0xFFFF;
}
SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
@@ -9641,7 +9452,7 @@ SiS_CheckACK(struct SiS_Private *SiS_Pr)
/* =============== SiS 315/330 O.E.M. ================= */
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static unsigned short
GetRAMDACromptr(struct SiS_Private *SiS_Pr)
@@ -10829,7 +10640,7 @@ SiS_FinalizeLCD(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
/* ================= SiS 300 O.E.M. ================== */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void
SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex,
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
index 51d99222375d..2112d6d7feda 100644
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -53,15 +53,8 @@
#ifndef _INIT301_H_
#define _INIT301_H_
-#include "osdef.h"
#include "initdef.h"
-#ifdef SIS_XORG_XF86
-#include "sis.h"
-#include "sis_regs.h"
-#endif
-
-#ifdef SIS_LINUX_KERNEL
#include "vgatypes.h"
#include "vstruct.h"
#ifdef SIS_CP
@@ -72,7 +65,6 @@
#include <linux/fb.h>
#include "sis.h"
#include <video/sisfb.h>
-#endif
static const unsigned char SiS_YPbPrTable[3][64] = {
{
@@ -237,7 +229,7 @@ static const unsigned char SiS_Part2CLVX_6[] = { /* 1080i */
0xFF,0xFF,
};
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
/* 661 et al LCD data structure (2.03.00) */
static const unsigned char SiS_LCDStruct661[] = {
/* 1024x768 */
@@ -279,7 +271,7 @@ static const unsigned char SiS_LCDStruct661[] = {
};
#endif
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static unsigned char SiS300_TrumpionData[14][80] = {
{ 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23,
@@ -356,9 +348,6 @@ static unsigned char SiS300_TrumpionData[14][80] = {
#endif
void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_LockCRT2(struct SiS_Private *SiS_Pr);
-#endif
void SiS_EnableCRT2(struct SiS_Private *SiS_Pr);
unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr);
@@ -375,9 +364,6 @@ unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo
unsigned short RefreshRateTableIndex);
unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex);
void SiS_DisableBridge(struct SiS_Private *SiS_Pr);
-#ifndef SIS_LINUX_KERNEL
-void SiS_EnableBridge(struct SiS_Private *SiS_Pr);
-#endif
bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr);
void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr);
@@ -386,13 +372,9 @@ void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned cha
unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax);
void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempax);
-#ifndef SIS_LINUX_KERNEL
-void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val);
-unsigned short SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempax);
-#endif
void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg,
unsigned char orval,unsigned short andval);
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr);
static void SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr);
static void SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr);
@@ -401,7 +383,7 @@ void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr);
void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr);
#endif /* 315 */
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static bool SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr);
void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo);
#endif
@@ -412,21 +394,12 @@ unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, i
unsigned short adaptnum, unsigned short DDCdatatype,
unsigned char *buffer, unsigned int VBFlags2);
-#ifdef SIS_XORG_XF86
-unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
- int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
- bool checkcr32, unsigned int VBFlags2);
-unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
-unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
- unsigned char *buffer);
-#else
static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
bool checkcr32, unsigned int VBFlags2);
static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
unsigned char *buffer);
-#endif
static void SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr);
static unsigned short SiS_SetStart(struct SiS_Private *SiS_Pr);
static unsigned short SiS_SetStop(struct SiS_Private *SiS_Pr);
@@ -441,13 +414,13 @@ static unsigned short SiS_PrepareDDC(struct SiS_Private *SiS_Pr);
static void SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno);
static unsigned short SiS_DoProbeDDC(struct SiS_Private *SiS_Pr);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
static void SiS_OEM300Setting(struct SiS_Private *SiS_Pr,
unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefTabindex);
static void SetOEMLCDData2(struct SiS_Private *SiS_Pr,
unsigned short ModeNo, unsigned short ModeIdIndex,unsigned short RefTableIndex);
#endif
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
static void SiS_OEM310Setting(struct SiS_Private *SiS_Pr,
unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI);
static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr,
@@ -455,17 +428,6 @@ static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr,
static void SiS_FinalizeLCD(struct SiS_Private *, unsigned short, unsigned short);
#endif
-extern void SiS_SetReg(SISIOADDRESS, unsigned short, unsigned short);
-extern void SiS_SetRegByte(SISIOADDRESS, unsigned short);
-extern void SiS_SetRegShort(SISIOADDRESS, unsigned short);
-extern void SiS_SetRegLong(SISIOADDRESS, unsigned int);
-extern unsigned char SiS_GetReg(SISIOADDRESS, unsigned short);
-extern unsigned char SiS_GetRegByte(SISIOADDRESS);
-extern unsigned short SiS_GetRegShort(SISIOADDRESS);
-extern unsigned int SiS_GetRegLong(SISIOADDRESS);
-extern void SiS_SetRegANDOR(SISIOADDRESS, unsigned short, unsigned short, unsigned short);
-extern void SiS_SetRegOR(SISIOADDRESS, unsigned short, unsigned short);
-extern void SiS_SetRegAND(SISIOADDRESS, unsigned short, unsigned short);
extern void SiS_DisplayOff(struct SiS_Private *SiS_Pr);
extern void SiS_DisplayOn(struct SiS_Private *SiS_Pr);
extern bool SiS_SearchModeID(struct SiS_Private *, unsigned short *, unsigned short *);
@@ -482,15 +444,13 @@ extern void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short M
extern void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth);
extern unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide);
extern unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide);
-#ifdef SIS300
+#ifdef CONFIG_FB_SIS_300
extern void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *tempbx,
unsigned short *tempcl);
extern unsigned short SiS_GetFIFOThresholdB300(unsigned short tempbx, unsigned short tempcl);
extern unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index);
-#ifdef SIS_LINUX_KERNEL
extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg);
extern unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg);
#endif
-#endif
#endif
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index 99c04a4855d1..9dec64da4015 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -25,7 +25,6 @@
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*/
-#include "osdef.h"
#include "initdef.h"
#include "vgatypes.h"
#include "vstruct.h"
@@ -59,7 +58,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
@@ -103,7 +102,7 @@ sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
@@ -187,7 +186,7 @@ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *ht
if(rateindex > 0) rateindex--;
-#ifdef SIS315H
+#ifdef CONFIG_FB_SIS_315
switch(ModeNo) {
case 0x5a: ModeNo = 0x50; break;
case 0x5b: ModeNo = 0x56;
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
deleted file mode 100644
index 6ff8f988a1a7..000000000000
--- a/drivers/video/sis/osdef.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* $XFree86$ */
-/* $XdotOrg$ */
-/*
- * OS depending defines
- *
- * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
- *
- * If distributed as part of the Linux kernel, the following license terms
- * apply:
- *
- * * This program is free software; you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation; either version 2 of the named License,
- * * or any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program; if not, write to the Free Software
- * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
- *
- * 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 EXPRESS OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
- * Silicon Integrated Systems, Inc. (used by permission)
- *
- */
-
-#ifndef _SIS_OSDEF_H_
-#define _SIS_OSDEF_H_
-
-/* The choices are: */
-#define SIS_LINUX_KERNEL /* Linux kernel framebuffer */
-#undef SIS_XORG_XF86 /* XFree86/X.org */
-
-#ifdef OutPortByte
-#undef OutPortByte
-#endif
-
-#ifdef OutPortWord
-#undef OutPortWord
-#endif
-
-#ifdef OutPortLong
-#undef OutPortLong
-#endif
-
-#ifdef InPortByte
-#undef InPortByte
-#endif
-
-#ifdef InPortWord
-#undef InPortWord
-#endif
-
-#ifdef InPortLong
-#undef InPortLong
-#endif
-
-/**********************************************************************/
-/* LINUX KERNEL */
-/**********************************************************************/
-
-#ifdef SIS_LINUX_KERNEL
-
-#ifdef CONFIG_FB_SIS_300
-#define SIS300
-#endif
-
-#ifdef CONFIG_FB_SIS_315
-#define SIS315H
-#endif
-
-#if !defined(SIS300) && !defined(SIS315H)
-#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
-#warning sisfb will not work!
-#endif
-
-#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p))
-#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p))
-#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p))
-#define InPortByte(p) inb((SISIOADDRESS)(p))
-#define InPortWord(p) inw((SISIOADDRESS)(p))
-#define InPortLong(p) inl((SISIOADDRESS)(p))
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize)
-
-#endif /* LINUX_KERNEL */
-
-/**********************************************************************/
-/* XFree86/X.org */
-/**********************************************************************/
-
-#ifdef SIS_XORG_XF86
-
-#define SIS300
-#define SIS315H
-
-#define OutPortByte(p,v) outSISREG((IOADDRESS)(p),(CARD8)(v))
-#define OutPortWord(p,v) outSISREGW((IOADDRESS)(p),(CARD16)(v))
-#define OutPortLong(p,v) outSISREGL((IOADDRESS)(p),(CARD32)(v))
-#define InPortByte(p) inSISREG((IOADDRESS)(p))
-#define InPortWord(p) inSISREGW((IOADDRESS)(p))
-#define InPortLong(p) inSISREGL((IOADDRESS)(p))
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-
-#endif /* XF86 */
-
-#endif /* _OSDEF_H_ */
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index 7c5710e3fb56..eac7a01925f3 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -24,7 +24,6 @@
#ifndef _SIS_H_
#define _SIS_H_
-#include "osdef.h"
#include <video/sisfb.h>
#include "vgatypes.h"
@@ -308,58 +307,19 @@
#define VB2_LCDOVER1600BRIDGE (VB2_307T | VB2_307LV)
#define VB2_RAMDAC202MHZBRIDGE (VB2_301C | VB2_307T)
-/* I/O port access macros */
-#define inSISREG(base) inb(base)
-
-#define outSISREG(base,val) outb(val,base)
-
-#define orSISREG(base,val) \
- do { \
- u8 __Temp = inSISREG(base); \
- outSISREG(base, __Temp | (val));\
- } while (0)
-
-#define andSISREG(base,val) \
- do { \
- u8 __Temp = inSISREG(base); \
- outSISREG(base, __Temp & (val));\
- } while (0)
-
-#define inSISIDXREG(base,idx,var) \
- do { \
- outSISREG(base, idx); \
- var = inSISREG((base)+1); \
- } while (0)
-
-#define outSISIDXREG(base,idx,val) \
- do { \
- outSISREG(base, idx); \
- outSISREG((base)+1, val); \
- } while (0)
-
-#define orSISIDXREG(base,idx,val) \
- do { \
- u8 __Temp; \
- outSISREG(base, idx); \
- __Temp = inSISREG((base)+1) | (val); \
- outSISREG((base)+1, __Temp); \
- } while (0)
-
-#define andSISIDXREG(base,idx,and) \
- do { \
- u8 __Temp; \
- outSISREG(base, idx); \
- __Temp = inSISREG((base)+1) & (and); \
- outSISREG((base)+1, __Temp); \
- } while (0)
-
-#define setSISIDXREG(base,idx,and,or) \
- do { \
- u8 __Temp; \
- outSISREG(base, idx); \
- __Temp = (inSISREG((base)+1) & (and)) | (or); \
- outSISREG((base)+1, __Temp); \
- } while (0)
+/* I/O port access functions */
+
+void SiS_SetReg(SISIOADDRESS, u8, u8);
+void SiS_SetRegByte(SISIOADDRESS, u8);
+void SiS_SetRegShort(SISIOADDRESS, u16);
+void SiS_SetRegLong(SISIOADDRESS, u32);
+void SiS_SetRegANDOR(SISIOADDRESS, u8, u8, u8);
+void SiS_SetRegAND(SISIOADDRESS, u8, u8);
+void SiS_SetRegOR(SISIOADDRESS, u8, u8);
+u8 SiS_GetReg(SISIOADDRESS, u8);
+u8 SiS_GetRegByte(SISIOADDRESS);
+u16 SiS_GetRegShort(SISIOADDRESS);
+u32 SiS_GetRegLong(SISIOADDRESS);
/* MMIO access macros */
#define MMIO_IN8(base, offset) readb((base+offset))
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index b52f8e4ef1fd..2fb8c5a660fb 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -60,6 +60,11 @@
#include "sis.h"
#include "sis_main.h"
+#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
+#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
+#warning sisfb will not work!
+#endif
+
static void sisfb_handle_command(struct sis_video_info *ivideo,
struct sisfb_cmd *sisfb_command);
@@ -732,7 +737,7 @@ sisfb_bridgeisslave(struct sis_video_info *ivideo)
if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
return false;
- inSISIDXREG(SISPART1,0x00,P1_00);
+ P1_00 = SiS_GetReg(SISPART1, 0x00);
if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
return true;
@@ -746,11 +751,11 @@ sisfballowretracecrt1(struct sis_video_info *ivideo)
{
u8 temp;
- inSISIDXREG(SISCR,0x17,temp);
+ temp = SiS_GetReg(SISCR, 0x17);
if(!(temp & 0x80))
return false;
- inSISIDXREG(SISSR,0x1f,temp);
+ temp = SiS_GetReg(SISSR, 0x1f);
if(temp & 0xc0)
return false;
@@ -763,7 +768,7 @@ sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
if(!sisfballowretracecrt1(ivideo))
return false;
- if(inSISREG(SISINPSTAT) & 0x08)
+ if (SiS_GetRegByte(SISINPSTAT) & 0x08)
return true;
else
return false;
@@ -778,9 +783,9 @@ sisfbwaitretracecrt1(struct sis_video_info *ivideo)
return;
watchdog = 65536;
- while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
+ while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
watchdog = 65536;
- while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
+ while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
}
static bool
@@ -794,7 +799,7 @@ sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
default: return false;
}
- inSISIDXREG(SISPART1, reg, temp);
+ temp = SiS_GetReg(SISPART1, reg);
if(temp & 0x02)
return true;
else
@@ -832,10 +837,10 @@ sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
default:
case SIS_315_VGA: idx = 0x30; break;
}
- inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
- inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
- inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
- inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
+ reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
+ reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
+ reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
+ reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
@@ -848,13 +853,13 @@ sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
FB_VBLANK_HAVE_VBLANK |
FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_HCOUNT);
- reg1 = inSISREG(SISINPSTAT);
+ reg1 = SiS_GetRegByte(SISINPSTAT);
if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
- inSISIDXREG(SISCR,0x20,reg1);
- inSISIDXREG(SISCR,0x1b,reg1);
- inSISIDXREG(SISCR,0x1c,reg2);
- inSISIDXREG(SISCR,0x1d,reg3);
+ reg1 = SiS_GetReg(SISCR, 0x20);
+ reg1 = SiS_GetReg(SISCR, 0x1b);
+ reg2 = SiS_GetReg(SISCR, 0x1c);
+ reg3 = SiS_GetReg(SISCR, 0x1d);
(*vcount) = reg2 | ((reg3 & 0x07) << 8);
(*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
}
@@ -925,12 +930,12 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
(ivideo->sisfb_thismonitor.feature & 0xe0))) {
if(ivideo->sisvga_engine == SIS_315_VGA) {
- setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
+ SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
}
if(!(sisfb_bridgeisslave(ivideo))) {
- setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
- setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
+ SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
+ SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
}
}
@@ -960,25 +965,25 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
(ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
((ivideo->sisvga_engine == SIS_315_VGA) &&
((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
- setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
+ SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
}
if(ivideo->sisvga_engine == SIS_300_VGA) {
if((ivideo->vbflags2 & VB2_30xB) &&
(!(ivideo->vbflags2 & VB2_30xBDH))) {
- setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
+ SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
}
} else if(ivideo->sisvga_engine == SIS_315_VGA) {
if((ivideo->vbflags2 & VB2_30xB) &&
(!(ivideo->vbflags2 & VB2_30xBDH))) {
- setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+ SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
}
}
} else if(ivideo->currentvbflags & CRT2_VGA) {
if(ivideo->vbflags2 & VB2_30xB) {
- setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+ SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
}
}
@@ -1109,15 +1114,15 @@ sisfb_set_pitch(struct sis_video_info *ivideo)
/* We need to set pitch for CRT1 if bridge is in slave mode, too */
if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
- outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
- setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
+ SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
+ SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
}
/* We must not set the pitch for CRT2 if bridge is in slave mode */
if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
- orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
- outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
- setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
+ SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
+ SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
+ SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
}
}
@@ -1162,7 +1167,7 @@ sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
/* >=2.6.12's fbcon clears the screen anyway */
modeno |= 0x80;
- outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+ SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sisfb_pre_setmode(ivideo);
@@ -1171,7 +1176,7 @@ sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
return -EINVAL;
}
- outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+ SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sisfb_post_setmode(ivideo);
@@ -1303,13 +1308,13 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
static void
sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
{
- outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+ SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
- outSISIDXREG(SISCR, 0x0D, base & 0xFF);
- outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
- outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
+ SiS_SetReg(SISCR, 0x0D, base & 0xFF);
+ SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
+ SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
if(ivideo->sisvga_engine == SIS_315_VGA) {
- setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+ SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
}
}
@@ -1317,12 +1322,12 @@ static void
sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
{
if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
- orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
- outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
- outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
- outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+ SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
+ SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
+ SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
+ SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
if(ivideo->sisvga_engine == SIS_315_VGA) {
- setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+ SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
}
}
}
@@ -1383,15 +1388,15 @@ sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
switch(info->var.bits_per_pixel) {
case 8:
- outSISREG(SISDACA, regno);
- outSISREG(SISDACD, (red >> 10));
- outSISREG(SISDACD, (green >> 10));
- outSISREG(SISDACD, (blue >> 10));
+ SiS_SetRegByte(SISDACA, regno);
+ SiS_SetRegByte(SISDACD, (red >> 10));
+ SiS_SetRegByte(SISDACD, (green >> 10));
+ SiS_SetRegByte(SISDACD, (blue >> 10));
if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
- outSISREG(SISDAC2A, regno);
- outSISREG(SISDAC2D, (red >> 8));
- outSISREG(SISDAC2D, (green >> 8));
- outSISREG(SISDAC2D, (blue >> 8));
+ SiS_SetRegByte(SISDAC2A, regno);
+ SiS_SetRegByte(SISDAC2D, (red >> 8));
+ SiS_SetRegByte(SISDAC2D, (green >> 8));
+ SiS_SetRegByte(SISDAC2D, (blue >> 8));
}
break;
case 16:
@@ -1956,7 +1961,7 @@ sisfb_get_dram_size(struct sis_video_info *ivideo)
switch(ivideo->chip) {
#ifdef CONFIG_FB_SIS_300
case SIS_300:
- inSISIDXREG(SISSR, 0x14, reg);
+ reg = SiS_GetReg(SISSR, 0x14);
ivideo->video_size = ((reg & 0x3F) + 1) << 20;
break;
case SIS_540:
@@ -1972,7 +1977,7 @@ sisfb_get_dram_size(struct sis_video_info *ivideo)
case SIS_315H:
case SIS_315PRO:
case SIS_315:
- inSISIDXREG(SISSR, 0x14, reg);
+ reg = SiS_GetReg(SISSR, 0x14);
ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
switch((reg >> 2) & 0x03) {
case 0x01:
@@ -1984,31 +1989,31 @@ sisfb_get_dram_size(struct sis_video_info *ivideo)
}
break;
case SIS_330:
- inSISIDXREG(SISSR, 0x14, reg);
+ reg = SiS_GetReg(SISSR, 0x14);
ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
if(reg & 0x0c) ivideo->video_size <<= 1;
break;
case SIS_550:
case SIS_650:
case SIS_740:
- inSISIDXREG(SISSR, 0x14, reg);
+ reg = SiS_GetReg(SISSR, 0x14);
ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
break;
case SIS_661:
case SIS_741:
- inSISIDXREG(SISCR, 0x79, reg);
+ reg = SiS_GetReg(SISCR, 0x79);
ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
break;
case SIS_660:
case SIS_760:
case SIS_761:
- inSISIDXREG(SISCR, 0x79, reg);
+ reg = SiS_GetReg(SISCR, 0x79);
reg = (reg & 0xf0) >> 4;
if(reg) {
ivideo->video_size = (1 << reg) << 20;
ivideo->UMAsize = ivideo->video_size;
}
- inSISIDXREG(SISCR, 0x78, reg);
+ reg = SiS_GetReg(SISCR, 0x78);
reg &= 0x30;
if(reg) {
if(reg == 0x10) {
@@ -2022,7 +2027,7 @@ sisfb_get_dram_size(struct sis_video_info *ivideo)
case SIS_340:
case XGI_20:
case XGI_40:
- inSISIDXREG(SISSR, 0x14, reg);
+ reg = SiS_GetReg(SISSR, 0x14);
ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
if(ivideo->chip != XGI_20) {
reg = (reg & 0x0c) >> 2;
@@ -2056,11 +2061,11 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
#ifdef CONFIG_FB_SIS_300
if(ivideo->sisvga_engine == SIS_300_VGA) {
- inSISIDXREG(SISSR, 0x17, temp);
+ temp = SiS_GetReg(SISSR, 0x17);
if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
/* PAL/NTSC is stored on SR16 on such machines */
if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
- inSISIDXREG(SISSR, 0x16, temp);
+ temp = SiS_GetReg(SISSR, 0x16);
if(temp & 0x20)
ivideo->vbflags |= TV_PAL;
else
@@ -2070,7 +2075,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
}
#endif
- inSISIDXREG(SISCR, 0x32, cr32);
+ cr32 = SiS_GetReg(SISCR, 0x32);
if(cr32 & SIS_CRT1) {
ivideo->sisfb_crt1off = 0;
@@ -2146,15 +2151,15 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
}
if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
if(ivideo->sisvga_engine == SIS_300_VGA) {
- inSISIDXREG(SISSR, 0x38, temp);
+ temp = SiS_GetReg(SISSR, 0x38);
if(temp & 0x01) ivideo->vbflags |= TV_PAL;
else ivideo->vbflags |= TV_NTSC;
} else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
- inSISIDXREG(SISSR, 0x38, temp);
+ temp = SiS_GetReg(SISSR, 0x38);
if(temp & 0x01) ivideo->vbflags |= TV_PAL;
else ivideo->vbflags |= TV_NTSC;
} else {
- inSISIDXREG(SISCR, 0x79, temp);
+ temp = SiS_GetReg(SISCR, 0x79);
if(temp & 0x20) ivideo->vbflags |= TV_PAL;
else ivideo->vbflags |= TV_NTSC;
}
@@ -2193,26 +2198,26 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
u16 temp = 0xffff;
int i;
- inSISIDXREG(SISSR,0x1F,sr1F);
- orSISIDXREG(SISSR,0x1F,0x04);
- andSISIDXREG(SISSR,0x1F,0x3F);
+ sr1F = SiS_GetReg(SISSR, 0x1F);
+ SiS_SetRegOR(SISSR, 0x1F, 0x04);
+ SiS_SetRegAND(SISSR, 0x1F, 0x3F);
if(sr1F & 0xc0) mustwait = true;
#ifdef CONFIG_FB_SIS_315
if(ivideo->sisvga_engine == SIS_315_VGA) {
- inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
+ cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
cr63 &= 0x40;
- andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
+ SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
}
#endif
- inSISIDXREG(SISCR,0x17,cr17);
+ cr17 = SiS_GetReg(SISCR, 0x17);
cr17 &= 0x80;
if(!cr17) {
- orSISIDXREG(SISCR,0x17,0x80);
+ SiS_SetRegOR(SISCR, 0x17, 0x80);
mustwait = true;
- outSISIDXREG(SISSR, 0x00, 0x01);
- outSISIDXREG(SISSR, 0x00, 0x03);
+ SiS_SetReg(SISSR, 0x00, 0x01);
+ SiS_SetReg(SISSR, 0x00, 0x03);
}
if(mustwait) {
@@ -2221,18 +2226,18 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
#ifdef CONFIG_FB_SIS_315
if(ivideo->chip >= SIS_330) {
- andSISIDXREG(SISCR,0x32,~0x20);
+ SiS_SetRegAND(SISCR, 0x32, ~0x20);
if(ivideo->chip >= SIS_340) {
- outSISIDXREG(SISCR, 0x57, 0x4a);
+ SiS_SetReg(SISCR, 0x57, 0x4a);
} else {
- outSISIDXREG(SISCR, 0x57, 0x5f);
+ SiS_SetReg(SISCR, 0x57, 0x5f);
}
- orSISIDXREG(SISCR, 0x53, 0x02);
- while((inSISREG(SISINPSTAT)) & 0x01) break;
- while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
- if((inSISREG(SISMISCW)) & 0x10) temp = 1;
- andSISIDXREG(SISCR, 0x53, 0xfd);
- andSISIDXREG(SISCR, 0x57, 0x00);
+ SiS_SetRegOR(SISCR, 0x53, 0x02);
+ while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
+ while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
+ if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
+ SiS_SetRegAND(SISCR, 0x53, 0xfd);
+ SiS_SetRegAND(SISCR, 0x57, 0x00);
}
#endif
@@ -2249,18 +2254,18 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
}
if((temp) && (temp != 0xffff)) {
- orSISIDXREG(SISCR,0x32,0x20);
+ SiS_SetRegOR(SISCR, 0x32, 0x20);
}
#ifdef CONFIG_FB_SIS_315
if(ivideo->sisvga_engine == SIS_315_VGA) {
- setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
+ SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
}
#endif
- setSISIDXREG(SISCR,0x17,0x7F,cr17);
+ SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
- outSISIDXREG(SISSR,0x1F,sr1F);
+ SiS_SetReg(SISSR, 0x1F, sr1F);
}
/* Determine and detect attached devices on SiS30x */
@@ -2281,7 +2286,7 @@ SiS_SenseLCD(struct sis_video_info *ivideo)
return;
/* If LCD already set up by BIOS, skip it */
- inSISIDXREG(SISCR, 0x32, reg);
+ reg = SiS_GetReg(SISCR, 0x32);
if(reg & 0x08)
return;
@@ -2344,10 +2349,10 @@ SiS_SenseLCD(struct sis_video_info *ivideo)
else
cr37 |= 0xc0;
- outSISIDXREG(SISCR, 0x36, paneltype);
+ SiS_SetReg(SISCR, 0x36, paneltype);
cr37 &= 0xf1;
- setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
- orSISIDXREG(SISCR, 0x32, 0x08);
+ SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
+ SiS_SetRegOR(SISCR, 0x32, 0x08);
ivideo->SiS_Pr.PanelSelfDetected = true;
}
@@ -2361,19 +2366,19 @@ SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
result = 0;
for(i = 0; i < 3; i++) {
mytest = test;
- outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
+ SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
temp = (type >> 8) | (mytest & 0x00ff);
- setSISIDXREG(SISPART4,0x10,0xe0,temp);
+ SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
mytest >>= 8;
mytest &= 0x7f;
- inSISIDXREG(SISPART4,0x03,temp);
+ temp = SiS_GetReg(SISPART4, 0x03);
temp ^= 0x0e;
temp &= mytest;
if(temp == mytest) result++;
#if 1
- outSISIDXREG(SISPART4,0x11,0x00);
- andSISIDXREG(SISPART4,0x10,0xe0);
+ SiS_SetReg(SISPART4, 0x11, 0x00);
+ SiS_SetRegAND(SISPART4, 0x10, 0xe0);
SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
#endif
}
@@ -2395,7 +2400,7 @@ SiS_Sense30x(struct sis_video_info *ivideo)
if(ivideo->vbflags2 & VB2_301) {
svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
- inSISIDXREG(SISPART4,0x01,myflag);
+ myflag = SiS_GetReg(SISPART4, 0x01);
if(myflag & 0x04) {
svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
}
@@ -2425,7 +2430,7 @@ SiS_Sense30x(struct sis_video_info *ivideo)
}
if(ivideo->chip == SIS_300) {
- inSISIDXREG(SISSR,0x3b,myflag);
+ myflag = SiS_GetReg(SISSR, 0x3b);
if(!(myflag & 0x01)) vga2 = vga2_c = 0;
}
@@ -2433,93 +2438,93 @@ SiS_Sense30x(struct sis_video_info *ivideo)
vga2 = vga2_c = 0;
}
- inSISIDXREG(SISSR,0x1e,backupSR_1e);
- orSISIDXREG(SISSR,0x1e,0x20);
+ backupSR_1e = SiS_GetReg(SISSR, 0x1e);
+ SiS_SetRegOR(SISSR, 0x1e, 0x20);
- inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+ backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
if(ivideo->vbflags2 & VB2_30xC) {
- setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
+ SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
} else {
- orSISIDXREG(SISPART4,0x0d,0x04);
+ SiS_SetRegOR(SISPART4, 0x0d, 0x04);
}
SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
- inSISIDXREG(SISPART2,0x00,backupP2_00);
- outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
+ backupP2_00 = SiS_GetReg(SISPART2, 0x00);
+ SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
- inSISIDXREG(SISPART2,0x4d,backupP2_4d);
+ backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
- outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
+ SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
}
if(!(ivideo->vbflags2 & VB2_30xCLV)) {
SISDoSense(ivideo, 0, 0);
}
- andSISIDXREG(SISCR, 0x32, ~0x14);
+ SiS_SetRegAND(SISCR, 0x32, ~0x14);
if(vga2_c || vga2) {
if(SISDoSense(ivideo, vga2, vga2_c)) {
if(biosflag & 0x01) {
printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
- orSISIDXREG(SISCR, 0x32, 0x04);
+ SiS_SetRegOR(SISCR, 0x32, 0x04);
} else {
printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
- orSISIDXREG(SISCR, 0x32, 0x10);
+ SiS_SetRegOR(SISCR, 0x32, 0x10);
}
}
}
- andSISIDXREG(SISCR, 0x32, 0x3f);
+ SiS_SetRegAND(SISCR, 0x32, 0x3f);
if(ivideo->vbflags2 & VB2_30xCLV) {
- orSISIDXREG(SISPART4,0x0d,0x04);
+ SiS_SetRegOR(SISPART4, 0x0d, 0x04);
}
if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
- outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
+ SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
if((result = SISDoSense(ivideo, svhs, 0x0604))) {
if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
- orSISIDXREG(SISCR,0x32,0x80);
+ SiS_SetRegOR(SISCR, 0x32, 0x80);
}
}
- outSISIDXREG(SISPART2,0x4d,backupP2_4d);
+ SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
}
- andSISIDXREG(SISCR, 0x32, ~0x03);
+ SiS_SetRegAND(SISCR, 0x32, ~0x03);
if(!(ivideo->vbflags & TV_YPBPR)) {
if((result = SISDoSense(ivideo, svhs, svhs_c))) {
printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
- orSISIDXREG(SISCR, 0x32, 0x02);
+ SiS_SetRegOR(SISCR, 0x32, 0x02);
}
if((biosflag & 0x02) || (!result)) {
if(SISDoSense(ivideo, cvbs, cvbs_c)) {
printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
- orSISIDXREG(SISCR, 0x32, 0x01);
+ SiS_SetRegOR(SISCR, 0x32, 0x01);
}
}
}
SISDoSense(ivideo, 0, 0);
- outSISIDXREG(SISPART2,0x00,backupP2_00);
- outSISIDXREG(SISPART4,0x0d,backupP4_0d);
- outSISIDXREG(SISSR,0x1e,backupSR_1e);
+ SiS_SetReg(SISPART2, 0x00, backupP2_00);
+ SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
+ SiS_SetReg(SISSR, 0x1e, backupSR_1e);
if(ivideo->vbflags2 & VB2_30xCLV) {
- inSISIDXREG(SISPART2,0x00,biosflag);
+ biosflag = SiS_GetReg(SISPART2, 0x00);
if(biosflag & 0x20) {
for(myflag = 2; myflag > 0; myflag--) {
biosflag ^= 0x20;
- outSISIDXREG(SISPART2,0x00,biosflag);
+ SiS_SetReg(SISPART2, 0x00, biosflag);
}
}
}
- outSISIDXREG(SISPART2,0x00,backupP2_00);
+ SiS_SetReg(SISPART2, 0x00, backupP2_00);
}
/* Determine and detect attached TV's on Chrontel */
@@ -2583,20 +2588,20 @@ SiS_SenseCh(struct sis_video_info *ivideo)
if(temp1 == 0x02) {
printk(KERN_INFO "%s SVIDEO output\n", stdstr);
ivideo->vbflags |= TV_SVIDEO;
- orSISIDXREG(SISCR, 0x32, 0x02);
- andSISIDXREG(SISCR, 0x32, ~0x05);
+ SiS_SetRegOR(SISCR, 0x32, 0x02);
+ SiS_SetRegAND(SISCR, 0x32, ~0x05);
} else if (temp1 == 0x01) {
printk(KERN_INFO "%s CVBS output\n", stdstr);
ivideo->vbflags |= TV_AVIDEO;
- orSISIDXREG(SISCR, 0x32, 0x01);
- andSISIDXREG(SISCR, 0x32, ~0x06);
+ SiS_SetRegOR(SISCR, 0x32, 0x01);
+ SiS_SetRegAND(SISCR, 0x32, ~0x06);
} else {
SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
- andSISIDXREG(SISCR, 0x32, ~0x07);
+ SiS_SetRegAND(SISCR, 0x32, ~0x07);
}
} else if(temp1 == 0) {
SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
- andSISIDXREG(SISCR, 0x32, ~0x07);
+ SiS_SetRegAND(SISCR, 0x32, ~0x07);
}
/* Set general purpose IO for Chrontel communication */
SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
@@ -2627,22 +2632,22 @@ SiS_SenseCh(struct sis_video_info *ivideo)
case 0x01:
printk(KERN_INFO "%s CVBS output\n", stdstr);
ivideo->vbflags |= TV_AVIDEO;
- orSISIDXREG(SISCR, 0x32, 0x01);
- andSISIDXREG(SISCR, 0x32, ~0x06);
+ SiS_SetRegOR(SISCR, 0x32, 0x01);
+ SiS_SetRegAND(SISCR, 0x32, ~0x06);
break;
case 0x02:
printk(KERN_INFO "%s SVIDEO output\n", stdstr);
ivideo->vbflags |= TV_SVIDEO;
- orSISIDXREG(SISCR, 0x32, 0x02);
- andSISIDXREG(SISCR, 0x32, ~0x05);
+ SiS_SetRegOR(SISCR, 0x32, 0x02);
+ SiS_SetRegAND(SISCR, 0x32, ~0x05);
break;
case 0x04:
printk(KERN_INFO "%s SCART output\n", stdstr);
- orSISIDXREG(SISCR, 0x32, 0x04);
- andSISIDXREG(SISCR, 0x32, ~0x03);
+ SiS_SetRegOR(SISCR, 0x32, 0x04);
+ SiS_SetRegAND(SISCR, 0x32, ~0x03);
break;
default:
- andSISIDXREG(SISCR, 0x32, ~0x07);
+ SiS_SetRegAND(SISCR, 0x32, ~0x07);
}
#endif
}
@@ -2660,10 +2665,10 @@ sisfb_get_VB_type(struct sis_video_info *ivideo)
if(ivideo->chip == XGI_20)
return;
- inSISIDXREG(SISPART4, 0x00, vb_chipid);
+ vb_chipid = SiS_GetReg(SISPART4, 0x00);
switch(vb_chipid) {
case 0x01:
- inSISIDXREG(SISPART4, 0x01, reg);
+ reg = SiS_GetReg(SISPART4, 0x01);
if(reg < 0xb0) {
ivideo->vbflags |= VB_301; /* Deprecated */
ivideo->vbflags2 |= VB2_301;
@@ -2671,7 +2676,7 @@ sisfb_get_VB_type(struct sis_video_info *ivideo)
} else if(reg < 0xc0) {
ivideo->vbflags |= VB_301B; /* Deprecated */
ivideo->vbflags2 |= VB2_301B;
- inSISIDXREG(SISPART4,0x23,reg);
+ reg = SiS_GetReg(SISPART4, 0x23);
if(!(reg & 0x02)) {
ivideo->vbflags |= VB_30xBDH; /* Deprecated */
ivideo->vbflags2 |= VB2_30xBDH;
@@ -2688,7 +2693,7 @@ sisfb_get_VB_type(struct sis_video_info *ivideo)
ivideo->vbflags2 |= VB2_301LV;
printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
} else if(reg <= 0xe1) {
- inSISIDXREG(SISPART4,0x39,reg);
+ reg = SiS_GetReg(SISPART4, 0x39);
if(reg == 0xff) {
ivideo->vbflags |= VB_302LV; /* Deprecated */
ivideo->vbflags2 |= VB2_302LV;
@@ -2713,7 +2718,7 @@ sisfb_get_VB_type(struct sis_video_info *ivideo)
}
if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
- inSISIDXREG(SISCR, 0x37, reg);
+ reg = SiS_GetReg(SISCR, 0x37);
reg &= SIS_EXTERNAL_CHIP_MASK;
reg >>= 1;
if(ivideo->sisvga_engine == SIS_300_VGA) {
@@ -2754,7 +2759,7 @@ sisfb_get_VB_type(struct sis_video_info *ivideo)
#endif
} else if(ivideo->chip >= SIS_661) {
#ifdef CONFIG_FB_SIS_315
- inSISIDXREG(SISCR, 0x38, reg);
+ reg = SiS_GetReg(SISCR, 0x38);
reg >>= 5;
switch(reg) {
case 0x02:
@@ -2817,13 +2822,13 @@ sisfb_engine_init(struct sis_video_info *ivideo)
tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
- inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+ tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
tq_state |= 0xf0;
tq_state &= 0xfc;
tq_state |= (u8)(tqueue_pos >> 8);
- outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+ SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
- outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
+ SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
ivideo->caps |= TURBO_QUEUE_CAP;
}
@@ -2860,8 +2865,8 @@ sisfb_engine_init(struct sis_video_info *ivideo)
}
}
- outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
- outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+ SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+ SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
/* Must disable dual pipe on XGI_40. Can't do
@@ -2873,7 +2878,7 @@ sisfb_engine_init(struct sis_video_info *ivideo)
MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
- outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
+ SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
@@ -2890,7 +2895,7 @@ sisfb_engine_init(struct sis_video_info *ivideo)
sisfb_syncaccel(ivideo);
- outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+ SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
}
}
@@ -2899,7 +2904,7 @@ sisfb_engine_init(struct sis_video_info *ivideo)
MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
- outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+ SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
@@ -2917,7 +2922,7 @@ sisfb_detect_lcd_type(struct sis_video_info *ivideo)
u8 reg;
int i;
- inSISIDXREG(SISCR, 0x36, reg);
+ reg = SiS_GetReg(SISCR, 0x36);
reg &= 0x0f;
if(ivideo->sisvga_engine == SIS_300_VGA) {
ivideo->CRT2LCDType = sis300paneltype[reg];
@@ -2936,8 +2941,8 @@ sisfb_detect_lcd_type(struct sis_video_info *ivideo)
if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
/* For broken BIOSes: Assume 1024x768, RGB18 */
ivideo->CRT2LCDType = LCD_1024x768;
- setSISIDXREG(SISCR,0x36,0xf0,0x02);
- setSISIDXREG(SISCR,0x37,0xee,0x01);
+ SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
+ SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
}
@@ -2975,10 +2980,10 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
if(ivideo->sisvga_engine == SIS_300_VGA) {
if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
int tmp;
- inSISIDXREG(SISCR,0x30,tmp);
+ tmp = SiS_GetReg(SISCR, 0x30);
if(tmp & 0x20) {
/* Currently on LCD? If yes, read current pdc */
- inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
+ ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
ivideo->detectedpdc &= 0x3c;
if(ivideo->SiS_Pr.PDC == -1) {
/* Let option override detection */
@@ -3002,7 +3007,7 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
/* Try to find about LCDA */
if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
int tmp;
- inSISIDXREG(SISPART1,0x13,tmp);
+ tmp = SiS_GetReg(SISPART1, 0x13);
if(tmp & 0x04) {
ivideo->SiS_Pr.SiS_UseLCDA = true;
ivideo->detectedlcda = 0x03;
@@ -3012,16 +3017,16 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
/* Save PDC */
if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
int tmp;
- inSISIDXREG(SISCR,0x30,tmp);
+ tmp = SiS_GetReg(SISCR, 0x30);
if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
/* Currently on LCD? If yes, read current pdc */
u8 pdc;
- inSISIDXREG(SISPART1,0x2D,pdc);
+ pdc = SiS_GetReg(SISPART1, 0x2D);
ivideo->detectedpdc = (pdc & 0x0f) << 1;
ivideo->detectedpdca = (pdc & 0xf0) >> 3;
- inSISIDXREG(SISPART1,0x35,pdc);
+ pdc = SiS_GetReg(SISPART1, 0x35);
ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
- inSISIDXREG(SISPART1,0x20,pdc);
+ pdc = SiS_GetReg(SISPART1, 0x20);
ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
if(ivideo->newrom) {
/* New ROM invalidates other PDC resp. */
@@ -3055,10 +3060,10 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
/* Save EMI */
if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
- inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
- inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
- inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
- inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
+ ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
+ ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
+ ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
+ ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
ivideo->SiS_Pr.HaveEMI = true;
if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
ivideo->SiS_Pr.HaveEMILCD = true;
@@ -3483,8 +3488,8 @@ sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
* ivideo->accel here, as this might have
* been changed before this is called.
*/
- inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
- inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
+ cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
+ cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
/* MMIO and 2D/3D engine enabled? */
if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
#ifdef CONFIG_FB_SIS_300
@@ -3502,7 +3507,7 @@ sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
* enabled, and that the queue
* is not in the state of "reset"
*/
- inSISIDXREG(SISSR, 0x26, cr30);
+ cr30 = SiS_GetReg(SISSR, 0x26);
if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
sisfb_syncaccel(ivideo);
}
@@ -3519,9 +3524,9 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
- inSISIDXREG(SISCR, 0x31, cr31);
+ cr31 = SiS_GetReg(SISCR, 0x31);
cr31 &= ~0x60;
cr31 |= 0x04;
@@ -3530,11 +3535,11 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
#ifdef CONFIG_FB_SIS_315
if(ivideo->sisvga_engine == SIS_315_VGA) {
if(ivideo->chip >= SIS_661) {
- inSISIDXREG(SISCR, 0x38, cr38);
+ cr38 = SiS_GetReg(SISCR, 0x38);
cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
} else {
tvregnum = 0x38;
- inSISIDXREG(SISCR, tvregnum, cr38);
+ cr38 = SiS_GetReg(SISCR, tvregnum);
cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
}
}
@@ -3542,7 +3547,7 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
#ifdef CONFIG_FB_SIS_300
if(ivideo->sisvga_engine == SIS_300_VGA) {
tvregnum = 0x35;
- inSISIDXREG(SISCR, tvregnum, cr38);
+ cr38 = SiS_GetReg(SISCR, tvregnum);
}
#endif
@@ -3649,20 +3654,20 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
}
- outSISIDXREG(SISCR, 0x30, cr30);
- outSISIDXREG(SISCR, 0x33, cr33);
+ SiS_SetReg(SISCR, 0x30, cr30);
+ SiS_SetReg(SISCR, 0x33, cr33);
if(ivideo->chip >= SIS_661) {
#ifdef CONFIG_FB_SIS_315
cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
- setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
+ SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
- setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
+ SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
#endif
} else if(ivideo->chip != SIS_300) {
- outSISIDXREG(SISCR, tvregnum, cr38);
+ SiS_SetReg(SISCR, tvregnum, cr38);
}
- outSISIDXREG(SISCR, 0x31, cr31);
+ SiS_SetReg(SISCR, 0x31, cr31);
ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
@@ -3677,15 +3682,15 @@ sisfb_fixup_SR11(struct sis_video_info *ivideo)
u8 tmpreg;
if(ivideo->chip >= SIS_661) {
- inSISIDXREG(SISSR,0x11,tmpreg);
+ tmpreg = SiS_GetReg(SISSR, 0x11);
if(tmpreg & 0x20) {
- inSISIDXREG(SISSR,0x3e,tmpreg);
+ tmpreg = SiS_GetReg(SISSR, 0x3e);
tmpreg = (tmpreg + 1) & 0xff;
- outSISIDXREG(SISSR,0x3e,tmpreg);
- inSISIDXREG(SISSR,0x11,tmpreg);
+ SiS_SetReg(SISSR, 0x3e, tmpreg);
+ tmpreg = SiS_GetReg(SISSR, 0x11);
}
if(tmpreg & 0xf0) {
- andSISIDXREG(SISSR,0x11,0x0f);
+ SiS_SetRegAND(SISSR, 0x11, 0x0f);
}
}
}
@@ -3711,7 +3716,7 @@ sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
case 1:
x += val;
if(x < 0) x = 0;
- outSISIDXREG(SISSR,0x05,0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
break;
@@ -3740,11 +3745,11 @@ sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
temp += (val * 2);
p2_43 = temp & 0xff;
p2_42 = (temp & 0xf00) >> 4;
- outSISIDXREG(SISPART2,0x1f,p2_1f);
- setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
- setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
- setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
- outSISIDXREG(SISPART2,0x43,p2_43);
+ SiS_SetReg(SISPART2, 0x1f, p2_1f);
+ SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
+ SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
+ SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
+ SiS_SetReg(SISPART2, 0x43, p2_43);
}
}
}
@@ -3769,7 +3774,7 @@ sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
case 1:
y -= val;
if(y < 0) y = 0;
- outSISIDXREG(SISSR,0x05,0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
break;
@@ -3793,8 +3798,8 @@ sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
p2_02 += 2;
}
}
- outSISIDXREG(SISPART2,0x01,p2_01);
- outSISIDXREG(SISPART2,0x02,p2_02);
+ SiS_SetReg(SISPART2, 0x01, p2_01);
+ SiS_SetReg(SISPART2, 0x02, p2_02);
}
}
}
@@ -3811,7 +3816,7 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
u8 reg1;
#endif
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
#ifdef CONFIG_FB_SIS_315
sisfb_fixup_SR11(ivideo);
@@ -3835,7 +3840,7 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
crt1isoff = false;
reg = 0x80;
}
- setSISIDXREG(SISCR, 0x17, 0x7f, reg);
+ SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
}
#endif
#ifdef CONFIG_FB_SIS_315
@@ -3849,8 +3854,8 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
reg = 0x00;
reg1 = 0x00;
}
- setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
- setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
+ SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
+ SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
}
#endif
@@ -3866,17 +3871,17 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
}
}
- andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
+ SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
if(ivideo->currentvbflags & CRT2_TV) {
if(ivideo->vbflags2 & VB2_SISBRIDGE) {
- inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
- inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
- inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
- inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
- inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
- inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
- inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
+ ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
+ ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
+ ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
+ ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
+ ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
+ ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
+ ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
} else if(ivideo->vbflags2 & VB2_CHRONTEL) {
if(ivideo->chronteltype == 1) {
ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
@@ -4100,7 +4105,6 @@ sisfb_find_rom(struct pci_dev *pdev)
struct sis_video_info *ivideo = pci_get_drvdata(pdev);
void __iomem *rom_base;
unsigned char *myrombase = NULL;
- u32 temp;
size_t romsize;
/* First, try the official pci ROM functions (except
@@ -4114,14 +4118,6 @@ sisfb_find_rom(struct pci_dev *pdev)
if(sisfb_check_rom(rom_base, ivideo)) {
if((myrombase = vmalloc(65536))) {
-
- /* Work around bug in pci/rom.c: Folks forgot to check
- * whether the size retrieved from the BIOS image eventually
- * is larger than the mapped size
- */
- if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
- romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
-
memcpy_fromio(myrombase, rom_base,
(romsize > 65536) ? 65536 : romsize);
}
@@ -4135,43 +4131,29 @@ sisfb_find_rom(struct pci_dev *pdev)
/* Otherwise do it the conventional way. */
#if defined(__i386__) || defined(__x86_64__)
+ {
+ u32 temp;
- for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
-
- rom_base = ioremap(temp, 65536);
- if(!rom_base)
- continue;
-
- if(!sisfb_check_rom(rom_base, ivideo)) {
- iounmap(rom_base);
- continue;
- }
-
- if((myrombase = vmalloc(65536)))
- memcpy_fromio(myrombase, rom_base, 65536);
+ for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
- iounmap(rom_base);
- break;
+ rom_base = ioremap(temp, 65536);
+ if (!rom_base)
+ continue;
- }
+ if (!sisfb_check_rom(rom_base, ivideo)) {
+ iounmap(rom_base);
+ continue;
+ }
-#else
+ if ((myrombase = vmalloc(65536)))
+ memcpy_fromio(myrombase, rom_base, 65536);
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
- (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+ iounmap(rom_base);
+ break;
- rom_base = ioremap(ivideo->video_base, 65536);
- if(rom_base) {
- if(sisfb_check_rom(rom_base, ivideo)) {
- if((myrombase = vmalloc(65536)))
- memcpy_fromio(myrombase, rom_base, 65536);
}
- iounmap(rom_base);
- }
-
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
+ }
#endif
return myrombase;
@@ -4181,6 +4163,9 @@ static void __devinit
sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
unsigned int min)
{
+ if (*mapsize < (min << 20))
+ return;
+
ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
if(!ivideo->video_vbase) {
@@ -4209,10 +4194,10 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo)
unsigned char reg;
int i, j;
- andSISIDXREG(SISSR, 0x15, 0xFB);
- orSISIDXREG(SISSR, 0x15, 0x04);
- outSISIDXREG(SISSR, 0x13, 0x00);
- outSISIDXREG(SISSR, 0x14, 0xBF);
+ SiS_SetRegAND(SISSR, 0x15, 0xFB);
+ SiS_SetRegOR(SISSR, 0x15, 0x04);
+ SiS_SetReg(SISSR, 0x13, 0x00);
+ SiS_SetReg(SISSR, 0x14, 0xBF);
for(i = 0; i < 2; i++) {
temp = 0x1234;
@@ -4220,12 +4205,12 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo)
writew(temp, FBAddress);
if(readw(FBAddress) == temp)
break;
- orSISIDXREG(SISSR, 0x3c, 0x01);
- inSISIDXREG(SISSR, 0x05, reg);
- inSISIDXREG(SISSR, 0x05, reg);
- andSISIDXREG(SISSR, 0x3c, 0xfe);
- inSISIDXREG(SISSR, 0x05, reg);
- inSISIDXREG(SISSR, 0x05, reg);
+ SiS_SetRegOR(SISSR, 0x3c, 0x01);
+ reg = SiS_GetReg(SISSR, 0x05);
+ reg = SiS_GetReg(SISSR, 0x05);
+ SiS_SetRegAND(SISSR, 0x3c, 0xfe);
+ reg = SiS_GetReg(SISSR, 0x05);
+ reg = SiS_GetReg(SISSR, 0x05);
temp++;
}
}
@@ -4235,7 +4220,7 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo)
writel(0x89ABCDEFL, (FBAddress + 8));
writel(0xCDEF0123L, (FBAddress + 12));
- inSISIDXREG(SISSR, 0x3b, reg);
+ reg = SiS_GetReg(SISSR, 0x3b);
if(reg & 0x01) {
if(readl((FBAddress + 12)) == 0xCDEF0123L)
return 4; /* Channel A 128bit */
@@ -4298,13 +4283,13 @@ sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth
PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
- andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
- orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
+ SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
+ SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
if(buswidth == 4) sr14 |= 0x80;
else if(buswidth == 2) sr14 |= 0x40;
- outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
- outSISIDXREG(SISSR, 0x14, sr14);
+ SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
+ SiS_SetReg(SISSR, 0x14, sr14);
BankNumHigh <<= 16;
BankNumMid <<= 16;
@@ -4371,13 +4356,13 @@ sisfb_post_sis300(struct pci_dev *pdev)
if(!ivideo->SiS_Pr.UseROM)
bios = NULL;
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
if(bios) {
if(bios[0x52] & 0x80) {
memtype = bios[0x52];
} else {
- inSISIDXREG(SISSR, 0x3a, memtype);
+ memtype = SiS_GetReg(SISSR, 0x3a);
}
memtype &= 0x07;
}
@@ -4401,19 +4386,19 @@ sisfb_post_sis300(struct pci_dev *pdev)
v6 = bios[rindex++];
}
}
- outSISIDXREG(SISSR, 0x28, v1);
- outSISIDXREG(SISSR, 0x29, v2);
- outSISIDXREG(SISSR, 0x2a, v3);
- outSISIDXREG(SISSR, 0x2e, v4);
- outSISIDXREG(SISSR, 0x2f, v5);
- outSISIDXREG(SISSR, 0x30, v6);
+ SiS_SetReg(SISSR, 0x28, v1);
+ SiS_SetReg(SISSR, 0x29, v2);
+ SiS_SetReg(SISSR, 0x2a, v3);
+ SiS_SetReg(SISSR, 0x2e, v4);
+ SiS_SetReg(SISSR, 0x2f, v5);
+ SiS_SetReg(SISSR, 0x30, v6);
v1 = 0x10;
if(bios)
v1 = bios[0xa4];
- outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
+ SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
- outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
+ SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
@@ -4430,91 +4415,91 @@ sisfb_post_sis300(struct pci_dev *pdev)
}
if(ivideo->revision_id >= 0x80)
v3 &= 0xfd;
- outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
- outSISIDXREG(SISSR, 0x16, v2);
- outSISIDXREG(SISSR, 0x17, v3);
- outSISIDXREG(SISSR, 0x18, v4);
- outSISIDXREG(SISSR, 0x19, v5);
- outSISIDXREG(SISSR, 0x1a, v6);
- outSISIDXREG(SISSR, 0x1b, v7);
- outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
- andSISIDXREG(SISSR, 0x15 ,0xfb);
- orSISIDXREG(SISSR, 0x15, 0x04);
+ SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
+ SiS_SetReg(SISSR, 0x16, v2);
+ SiS_SetReg(SISSR, 0x17, v3);
+ SiS_SetReg(SISSR, 0x18, v4);
+ SiS_SetReg(SISSR, 0x19, v5);
+ SiS_SetReg(SISSR, 0x1a, v6);
+ SiS_SetReg(SISSR, 0x1b, v7);
+ SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
+ SiS_SetRegAND(SISSR, 0x15, 0xfb);
+ SiS_SetRegOR(SISSR, 0x15, 0x04);
if(bios) {
if(bios[0x53] & 0x02) {
- orSISIDXREG(SISSR, 0x19, 0x20);
+ SiS_SetRegOR(SISSR, 0x19, 0x20);
}
}
v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
if(ivideo->revision_id >= 0x80)
v1 |= 0x01;
- outSISIDXREG(SISSR, 0x1f, v1);
- outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
+ SiS_SetReg(SISSR, 0x1f, v1);
+ SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
if(bios) {
v1 = bios[0xe8];
v2 = bios[0xe9];
v3 = bios[0xea];
}
- outSISIDXREG(SISSR, 0x23, v1);
- outSISIDXREG(SISSR, 0x24, v2);
- outSISIDXREG(SISSR, 0x25, v3);
- outSISIDXREG(SISSR, 0x21, 0x84);
- outSISIDXREG(SISSR, 0x22, 0x00);
- outSISIDXREG(SISCR, 0x37, 0x00);
- orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
- outSISIDXREG(SISPART1, 0x00, 0x00);
+ SiS_SetReg(SISSR, 0x23, v1);
+ SiS_SetReg(SISSR, 0x24, v2);
+ SiS_SetReg(SISSR, 0x25, v3);
+ SiS_SetReg(SISSR, 0x21, 0x84);
+ SiS_SetReg(SISSR, 0x22, 0x00);
+ SiS_SetReg(SISCR, 0x37, 0x00);
+ SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
+ SiS_SetReg(SISPART1, 0x00, 0x00);
v1 = 0x40; v2 = 0x11;
if(bios) {
v1 = bios[0xec];
v2 = bios[0xeb];
}
- outSISIDXREG(SISPART1, 0x02, v1);
+ SiS_SetReg(SISPART1, 0x02, v1);
if(ivideo->revision_id >= 0x80)
v2 &= ~0x01;
- inSISIDXREG(SISPART4, 0x00, reg);
+ reg = SiS_GetReg(SISPART4, 0x00);
if((reg == 1) || (reg == 2)) {
- outSISIDXREG(SISCR, 0x37, 0x02);
- outSISIDXREG(SISPART2, 0x00, 0x1c);
+ SiS_SetReg(SISCR, 0x37, 0x02);
+ SiS_SetReg(SISPART2, 0x00, 0x1c);
v4 = 0x00; v5 = 0x00; v6 = 0x10;
if(ivideo->SiS_Pr.UseROM) {
v4 = bios[0xf5];
v5 = bios[0xf6];
v6 = bios[0xf7];
}
- outSISIDXREG(SISPART4, 0x0d, v4);
- outSISIDXREG(SISPART4, 0x0e, v5);
- outSISIDXREG(SISPART4, 0x10, v6);
- outSISIDXREG(SISPART4, 0x0f, 0x3f);
- inSISIDXREG(SISPART4, 0x01, reg);
+ SiS_SetReg(SISPART4, 0x0d, v4);
+ SiS_SetReg(SISPART4, 0x0e, v5);
+ SiS_SetReg(SISPART4, 0x10, v6);
+ SiS_SetReg(SISPART4, 0x0f, 0x3f);
+ reg = SiS_GetReg(SISPART4, 0x01);
if(reg >= 0xb0) {
- inSISIDXREG(SISPART4, 0x23, reg);
+ reg = SiS_GetReg(SISPART4, 0x23);
reg &= 0x20;
reg <<= 1;
- outSISIDXREG(SISPART4, 0x23, reg);
+ SiS_SetReg(SISPART4, 0x23, reg);
}
} else {
v2 &= ~0x10;
}
- outSISIDXREG(SISSR, 0x32, v2);
+ SiS_SetReg(SISSR, 0x32, v2);
- andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
+ SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
- inSISIDXREG(SISSR, 0x16, reg);
+ reg = SiS_GetReg(SISSR, 0x16);
reg &= 0xc3;
- outSISIDXREG(SISCR, 0x35, reg);
- outSISIDXREG(SISCR, 0x83, 0x00);
+ SiS_SetReg(SISCR, 0x35, reg);
+ SiS_SetReg(SISCR, 0x83, 0x00);
#if !defined(__i386__) && !defined(__x86_64__)
if(sisfb_videoram) {
- outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
+ SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
reg = ((sisfb_videoram >> 10) - 1) | 0x40;
- outSISIDXREG(SISSR, 0x14, reg);
+ SiS_SetReg(SISSR, 0x14, reg);
} else {
#endif
/* Need to map max FB size for finding out about RAM size */
- mapsize = 64 << 20;
+ mapsize = ivideo->video_size;
sisfb_post_map_vram(ivideo, &mapsize, 4);
if(ivideo->video_vbase) {
@@ -4523,8 +4508,8 @@ sisfb_post_sis300(struct pci_dev *pdev)
} else {
printk(KERN_DEBUG
"sisfb: Failed to map memory for size detection, assuming 8MB\n");
- outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
- outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
+ SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
+ SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
}
#if !defined(__i386__) && !defined(__x86_64__)
}
@@ -4533,7 +4518,7 @@ sisfb_post_sis300(struct pci_dev *pdev)
v1 = bios[0xe6];
v2 = bios[0xe7];
} else {
- inSISIDXREG(SISSR, 0x3a, reg);
+ reg = SiS_GetReg(SISSR, 0x3a);
if((reg & 0x30) == 0x30) {
v1 = 0x04; /* PCI */
v2 = 0x92;
@@ -4542,8 +4527,8 @@ sisfb_post_sis300(struct pci_dev *pdev)
v2 = 0xb2;
}
}
- outSISIDXREG(SISSR, 0x21, v1);
- outSISIDXREG(SISSR, 0x22, v2);
+ SiS_SetReg(SISSR, 0x21, v1);
+ SiS_SetReg(SISSR, 0x22, v2);
/* Sense CRT1 */
sisfb_sense_crt1(ivideo);
@@ -4556,13 +4541,13 @@ sisfb_post_sis300(struct pci_dev *pdev)
ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
/* Display off */
- orSISIDXREG(SISSR, 0x01, 0x20);
+ SiS_SetRegOR(SISSR, 0x01, 0x20);
/* Save mode number in CR34 */
- outSISIDXREG(SISCR, 0x34, 0x2e);
+ SiS_SetReg(SISCR, 0x34, 0x2e);
/* Let everyone know what the current mode is */
ivideo->modeprechange = 0x2e;
@@ -4585,7 +4570,7 @@ sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
u8 reg;
for(i = 0; i <= (delay * 10 * 36); i++) {
- inSISIDXREG(SISSR, 0x05, reg);
+ reg = SiS_GetReg(SISSR, 0x05);
reg++;
}
}
@@ -4677,84 +4662,84 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
* - if running on non-x86, there usually is no VGA window
* at a0000.
*/
- orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
+ SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
/* Need to map max FB size for finding out about RAM size */
- mapsize = 256 << 20;
+ mapsize = ivideo->video_size;
sisfb_post_map_vram(ivideo, &mapsize, 32);
if(!ivideo->video_vbase) {
printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
- outSISIDXREG(SISSR, 0x13, 0x35);
- outSISIDXREG(SISSR, 0x14, 0x41);
+ SiS_SetReg(SISSR, 0x13, 0x35);
+ SiS_SetReg(SISSR, 0x14, 0x41);
/* TODO */
return;
}
/* Non-interleaving */
- outSISIDXREG(SISSR, 0x15, 0x00);
+ SiS_SetReg(SISSR, 0x15, 0x00);
/* No tiling */
- outSISIDXREG(SISSR, 0x1c, 0x00);
+ SiS_SetReg(SISSR, 0x1c, 0x00);
if(ivideo->chip == XGI_20) {
channelab = 1;
- inSISIDXREG(SISCR, 0x97, reg);
+ reg = SiS_GetReg(SISCR, 0x97);
if(!(reg & 0x01)) { /* Single 32/16 */
buswidth = 32;
- outSISIDXREG(SISSR, 0x13, 0xb1);
- outSISIDXREG(SISSR, 0x14, 0x52);
+ SiS_SetReg(SISSR, 0x13, 0xb1);
+ SiS_SetReg(SISSR, 0x14, 0x52);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x02;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x31);
- outSISIDXREG(SISSR, 0x14, 0x42);
+ SiS_SetReg(SISSR, 0x13, 0x31);
+ SiS_SetReg(SISSR, 0x14, 0x42);
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
goto bail_out;
buswidth = 16;
- outSISIDXREG(SISSR, 0x13, 0xb1);
- outSISIDXREG(SISSR, 0x14, 0x41);
+ SiS_SetReg(SISSR, 0x13, 0xb1);
+ SiS_SetReg(SISSR, 0x14, 0x41);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x01;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
else
- outSISIDXREG(SISSR, 0x13, 0x31);
+ SiS_SetReg(SISSR, 0x13, 0x31);
} else { /* Dual 16/8 */
buswidth = 16;
- outSISIDXREG(SISSR, 0x13, 0xb1);
- outSISIDXREG(SISSR, 0x14, 0x41);
+ SiS_SetReg(SISSR, 0x13, 0xb1);
+ SiS_SetReg(SISSR, 0x14, 0x41);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x01;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x31);
- outSISIDXREG(SISSR, 0x14, 0x31);
+ SiS_SetReg(SISSR, 0x13, 0x31);
+ SiS_SetReg(SISSR, 0x14, 0x31);
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
goto bail_out;
buswidth = 8;
- outSISIDXREG(SISSR, 0x13, 0xb1);
- outSISIDXREG(SISSR, 0x14, 0x30);
+ SiS_SetReg(SISSR, 0x13, 0xb1);
+ SiS_SetReg(SISSR, 0x14, 0x30);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x00;
if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
goto bail_out;
else
- outSISIDXREG(SISSR, 0x13, 0x31);
+ SiS_SetReg(SISSR, 0x13, 0x31);
}
} else { /* XGI_40 */
- inSISIDXREG(SISCR, 0x97, reg);
+ reg = SiS_GetReg(SISCR, 0x97);
if(!(reg & 0x10)) {
- inSISIDXREG(SISSR, 0x39, reg);
+ reg = SiS_GetReg(SISSR, 0x39);
reg >>= 1;
}
@@ -4762,52 +4747,52 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
buswidth = 32;
if(ivideo->revision_id == 2) {
channelab = 2;
- outSISIDXREG(SISSR, 0x13, 0xa1);
- outSISIDXREG(SISSR, 0x14, 0x44);
+ SiS_SetReg(SISSR, 0x13, 0xa1);
+ SiS_SetReg(SISSR, 0x14, 0x44);
sr14 = 0x04;
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x21);
- outSISIDXREG(SISSR, 0x14, 0x34);
+ SiS_SetReg(SISSR, 0x13, 0x21);
+ SiS_SetReg(SISSR, 0x14, 0x34);
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
channelab = 1;
- outSISIDXREG(SISSR, 0x13, 0xa1);
- outSISIDXREG(SISSR, 0x14, 0x40);
+ SiS_SetReg(SISSR, 0x13, 0xa1);
+ SiS_SetReg(SISSR, 0x14, 0x40);
sr14 = 0x00;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x21);
- outSISIDXREG(SISSR, 0x14, 0x30);
+ SiS_SetReg(SISSR, 0x13, 0x21);
+ SiS_SetReg(SISSR, 0x14, 0x30);
} else {
channelab = 3;
- outSISIDXREG(SISSR, 0x13, 0xa1);
- outSISIDXREG(SISSR, 0x14, 0x4c);
+ SiS_SetReg(SISSR, 0x13, 0xa1);
+ SiS_SetReg(SISSR, 0x14, 0x4c);
sr14 = 0x0c;
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
goto bail_out;
channelab = 2;
- outSISIDXREG(SISSR, 0x14, 0x48);
+ SiS_SetReg(SISSR, 0x14, 0x48);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x08;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x21);
- outSISIDXREG(SISSR, 0x14, 0x3c);
+ SiS_SetReg(SISSR, 0x13, 0x21);
+ SiS_SetReg(SISSR, 0x14, 0x3c);
sr14 = 0x0c;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
channelab = 3;
} else {
channelab = 2;
- outSISIDXREG(SISSR, 0x14, 0x38);
+ SiS_SetReg(SISSR, 0x14, 0x38);
sr14 = 0x08;
}
}
@@ -4818,26 +4803,26 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
buswidth = 64;
if(ivideo->revision_id == 2) {
channelab = 1;
- outSISIDXREG(SISSR, 0x13, 0xa1);
- outSISIDXREG(SISSR, 0x14, 0x52);
+ SiS_SetReg(SISSR, 0x13, 0xa1);
+ SiS_SetReg(SISSR, 0x14, 0x52);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x02;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x21);
- outSISIDXREG(SISSR, 0x14, 0x42);
+ SiS_SetReg(SISSR, 0x13, 0x21);
+ SiS_SetReg(SISSR, 0x14, 0x42);
} else {
channelab = 2;
- outSISIDXREG(SISSR, 0x13, 0xa1);
- outSISIDXREG(SISSR, 0x14, 0x5a);
+ SiS_SetReg(SISSR, 0x13, 0xa1);
+ SiS_SetReg(SISSR, 0x14, 0x5a);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x0a;
if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
goto bail_out;
- outSISIDXREG(SISSR, 0x13, 0x21);
- outSISIDXREG(SISSR, 0x14, 0x4a);
+ SiS_SetReg(SISSR, 0x13, 0x21);
+ SiS_SetReg(SISSR, 0x14, 0x4a);
}
sisfb_post_xgi_delay(ivideo, 1);
@@ -4845,7 +4830,7 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
}
bail_out:
- setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
+ SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
sisfb_post_xgi_delay(ivideo, 1);
j = (ivideo->chip == XGI_20) ? 5 : 9;
@@ -4855,13 +4840,13 @@ bail_out:
reg = (ivideo->chip == XGI_20) ?
dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
- setSISIDXREG(SISSR, 0x13, 0x80, reg);
+ SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
sisfb_post_xgi_delay(ivideo, 50);
ranksize = (ivideo->chip == XGI_20) ?
dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
- inSISIDXREG(SISSR, 0x13, reg);
+ reg = SiS_GetReg(SISSR, 0x13);
if(reg & 0x80) ranksize <<= 1;
if(ivideo->chip == XGI_20) {
@@ -4880,7 +4865,7 @@ bail_out:
if(!reg) continue;
- setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
+ SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
@@ -4925,9 +4910,9 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
v2 = ivideo->bios_abase[0x90 + index + 1];
v3 = ivideo->bios_abase[0x90 + index + 2];
}
- outSISIDXREG(SISSR, 0x28, v1);
- outSISIDXREG(SISSR, 0x29, v2);
- outSISIDXREG(SISSR, 0x2a, v3);
+ SiS_SetReg(SISSR, 0x28, v1);
+ SiS_SetReg(SISSR, 0x29, v2);
+ SiS_SetReg(SISSR, 0x2a, v3);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
@@ -4938,9 +4923,9 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
v2 = ivideo->bios_abase[0xb8 + index + 1];
v3 = ivideo->bios_abase[0xb8 + index + 2];
}
- outSISIDXREG(SISSR, 0x2e, v1);
- outSISIDXREG(SISSR, 0x2f, v2);
- outSISIDXREG(SISSR, 0x30, v3);
+ SiS_SetReg(SISSR, 0x2e, v1);
+ SiS_SetReg(SISSR, 0x2f, v2);
+ SiS_SetReg(SISSR, 0x30, v3);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
@@ -5013,29 +4998,29 @@ sisfb_post_xgi(struct pci_dev *pdev)
};
/* VGA enable */
- reg = inSISREG(SISVGAENABLE) | 0x01;
- outSISREG(SISVGAENABLE, reg);
+ reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
+ SiS_SetRegByte(SISVGAENABLE, reg);
/* Misc */
- reg = inSISREG(SISMISCR) | 0x01;
- outSISREG(SISMISCW, reg);
+ reg = SiS_GetRegByte(SISMISCR) | 0x01;
+ SiS_SetRegByte(SISMISCW, reg);
/* Unlock SR */
- outSISIDXREG(SISSR, 0x05, 0x86);
- inSISIDXREG(SISSR, 0x05, reg);
+ SiS_SetReg(SISSR, 0x05, 0x86);
+ reg = SiS_GetReg(SISSR, 0x05);
if(reg != 0xa1)
return 0;
/* Clear some regs */
for(i = 0; i < 0x22; i++) {
if(0x06 + i == 0x20) continue;
- outSISIDXREG(SISSR, 0x06 + i, 0x00);
+ SiS_SetReg(SISSR, 0x06 + i, 0x00);
}
for(i = 0; i < 0x0b; i++) {
- outSISIDXREG(SISSR, 0x31 + i, 0x00);
+ SiS_SetReg(SISSR, 0x31 + i, 0x00);
}
for(i = 0; i < 0x10; i++) {
- outSISIDXREG(SISCR, 0x30 + i, 0x00);
+ SiS_SetReg(SISCR, 0x30 + i, 0x00);
}
ptr = cs78;
@@ -5043,7 +5028,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
ptr = (const u8 *)&bios[0x78];
}
for(i = 0; i < 3; i++) {
- outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
+ SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
}
ptr = cs76;
@@ -5051,7 +5036,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
ptr = (const u8 *)&bios[0x76];
}
for(i = 0; i < 2; i++) {
- outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
+ SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
}
v1 = 0x18; v2 = 0x00;
@@ -5059,83 +5044,83 @@ sisfb_post_xgi(struct pci_dev *pdev)
v1 = bios[0x74];
v2 = bios[0x75];
}
- outSISIDXREG(SISSR, 0x07, v1);
- outSISIDXREG(SISSR, 0x11, 0x0f);
- outSISIDXREG(SISSR, 0x1f, v2);
+ SiS_SetReg(SISSR, 0x07, v1);
+ SiS_SetReg(SISSR, 0x11, 0x0f);
+ SiS_SetReg(SISSR, 0x1f, v2);
/* PCI linear mode, RelIO enabled, A0000 decoding disabled */
- outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
- outSISIDXREG(SISSR, 0x27, 0x74);
+ SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
+ SiS_SetReg(SISSR, 0x27, 0x74);
ptr = cs7b;
if(ivideo->haveXGIROM) {
ptr = (const u8 *)&bios[0x7b];
}
for(i = 0; i < 3; i++) {
- outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
+ SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
}
if(ivideo->chip == XGI_40) {
if(ivideo->revision_id == 2) {
- setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
+ SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
}
- outSISIDXREG(SISCR, 0x7d, 0xfe);
- outSISIDXREG(SISCR, 0x7e, 0x0f);
+ SiS_SetReg(SISCR, 0x7d, 0xfe);
+ SiS_SetReg(SISCR, 0x7e, 0x0f);
}
if(ivideo->revision_id == 0) { /* 40 *and* 20? */
- andSISIDXREG(SISCR, 0x58, 0xd7);
- inSISIDXREG(SISCR, 0xcb, reg);
+ SiS_SetRegAND(SISCR, 0x58, 0xd7);
+ reg = SiS_GetReg(SISCR, 0xcb);
if(reg & 0x20) {
- setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
+ SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
}
}
reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
- setSISIDXREG(SISCR, 0x38, 0x1f, reg);
+ SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
if(ivideo->chip == XGI_20) {
- outSISIDXREG(SISSR, 0x36, 0x70);
+ SiS_SetReg(SISSR, 0x36, 0x70);
} else {
- outSISIDXREG(SISVID, 0x00, 0x86);
- outSISIDXREG(SISVID, 0x32, 0x00);
- outSISIDXREG(SISVID, 0x30, 0x00);
- outSISIDXREG(SISVID, 0x32, 0x01);
- outSISIDXREG(SISVID, 0x30, 0x00);
- andSISIDXREG(SISVID, 0x2f, 0xdf);
- andSISIDXREG(SISCAP, 0x00, 0x3f);
-
- outSISIDXREG(SISPART1, 0x2f, 0x01);
- outSISIDXREG(SISPART1, 0x00, 0x00);
- outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
- outSISIDXREG(SISPART1, 0x2e, 0x08);
- andSISIDXREG(SISPART1, 0x35, 0x7f);
- andSISIDXREG(SISPART1, 0x50, 0xfe);
-
- inSISIDXREG(SISPART4, 0x00, reg);
+ SiS_SetReg(SISVID, 0x00, 0x86);
+ SiS_SetReg(SISVID, 0x32, 0x00);
+ SiS_SetReg(SISVID, 0x30, 0x00);
+ SiS_SetReg(SISVID, 0x32, 0x01);
+ SiS_SetReg(SISVID, 0x30, 0x00);
+ SiS_SetRegAND(SISVID, 0x2f, 0xdf);
+ SiS_SetRegAND(SISCAP, 0x00, 0x3f);
+
+ SiS_SetReg(SISPART1, 0x2f, 0x01);
+ SiS_SetReg(SISPART1, 0x00, 0x00);
+ SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
+ SiS_SetReg(SISPART1, 0x2e, 0x08);
+ SiS_SetRegAND(SISPART1, 0x35, 0x7f);
+ SiS_SetRegAND(SISPART1, 0x50, 0xfe);
+
+ reg = SiS_GetReg(SISPART4, 0x00);
if(reg == 1 || reg == 2) {
- outSISIDXREG(SISPART2, 0x00, 0x1c);
- outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
- outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
- outSISIDXREG(SISPART4, 0x10, bios[0x81]);
- andSISIDXREG(SISPART4, 0x0f, 0x3f);
+ SiS_SetReg(SISPART2, 0x00, 0x1c);
+ SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
+ SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
+ SiS_SetReg(SISPART4, 0x10, bios[0x81]);
+ SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
- inSISIDXREG(SISPART4, 0x01, reg);
+ reg = SiS_GetReg(SISPART4, 0x01);
if((reg & 0xf0) >= 0xb0) {
- inSISIDXREG(SISPART4, 0x23, reg);
+ reg = SiS_GetReg(SISPART4, 0x23);
if(reg & 0x20) reg |= 0x40;
- outSISIDXREG(SISPART4, 0x23, reg);
+ SiS_SetReg(SISPART4, 0x23, reg);
reg = (reg & 0x20) ? 0x02 : 0x00;
- setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
+ SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
}
}
v1 = bios[0x77];
- inSISIDXREG(SISSR, 0x3b, reg);
+ reg = SiS_GetReg(SISSR, 0x3b);
if(reg & 0x02) {
- inSISIDXREG(SISSR, 0x3a, reg);
+ reg = SiS_GetReg(SISSR, 0x3a);
v2 = (reg & 0x30) >> 3;
if(!(v2 & 0x04)) v2 ^= 0x02;
- inSISIDXREG(SISSR, 0x39, reg);
+ reg = SiS_GetReg(SISSR, 0x39);
if(reg & 0x80) v2 |= 0x80;
v2 |= 0x01;
@@ -5168,36 +5153,36 @@ sisfb_post_xgi(struct pci_dev *pdev)
v2 |= 0x08;
}
}
- setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
+ SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
}
- outSISIDXREG(SISSR, 0x22, v1);
+ SiS_SetReg(SISSR, 0x22, v1);
if(ivideo->revision_id == 2) {
- inSISIDXREG(SISSR, 0x3b, v1);
- inSISIDXREG(SISSR, 0x3a, v2);
+ v1 = SiS_GetReg(SISSR, 0x3b);
+ v2 = SiS_GetReg(SISSR, 0x3a);
regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
- setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
+ SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
/* TODO: set CR5f &0xf1 | 0x01 for version 6570
* of nforce 2 ROM
*/
if(0)
- setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
+ SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
pci_dev_put(mypdev);
}
}
v1 = 0x30;
- inSISIDXREG(SISSR, 0x3b, reg);
- inSISIDXREG(SISCR, 0x5f, v2);
+ reg = SiS_GetReg(SISSR, 0x3b);
+ v2 = SiS_GetReg(SISCR, 0x5f);
if((!(reg & 0x02)) && (v2 & 0x0e))
v1 |= 0x08;
- outSISIDXREG(SISSR, 0x27, v1);
+ SiS_SetReg(SISSR, 0x27, v1);
if(bios[0x64] & 0x01) {
- setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
+ SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
}
v1 = bios[0x4f7];
@@ -5205,27 +5190,27 @@ sisfb_post_xgi(struct pci_dev *pdev)
regd = (regd >> 20) & 0x0f;
if(regd == 1) {
v1 &= 0xfc;
- orSISIDXREG(SISCR, 0x5f, 0x08);
- }
- outSISIDXREG(SISCR, 0x48, v1);
-
- setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
- setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
- setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
- setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
- setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
- outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
- setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
- outSISIDXREG(SISCR, 0x74, 0xd0);
- setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
- setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
- setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
+ SiS_SetRegOR(SISCR, 0x5f, 0x08);
+ }
+ SiS_SetReg(SISCR, 0x48, v1);
+
+ SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
+ SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
+ SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
+ SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
+ SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
+ SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
+ SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
+ SiS_SetReg(SISCR, 0x74, 0xd0);
+ SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
+ SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
+ SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
v1 = bios[0x501];
if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
v1 = 0xf0;
pci_dev_put(mypdev);
}
- outSISIDXREG(SISCR, 0x77, v1);
+ SiS_SetReg(SISCR, 0x77, v1);
}
/* RAM type */
@@ -5236,14 +5221,14 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(ivideo->haveXGIROM) {
v1 = bios[0x140 + regb];
}
- outSISIDXREG(SISCR, 0x6d, v1);
+ SiS_SetReg(SISCR, 0x6d, v1);
ptr = cs128;
if(ivideo->haveXGIROM) {
ptr = (const u8 *)&bios[0x128];
}
for(i = 0, j = 0; i < 3; i++, j += 8) {
- outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
+ SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
}
ptr = cs31a;
@@ -5267,14 +5252,14 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(regd & 0x01) reg |= 0x04;
if(regd & 0x02) reg |= 0x08;
regd >>= 2;
- outSISIDXREG(SISCR, rega, reg);
- inSISIDXREG(SISCR, rega, reg);
- inSISIDXREG(SISCR, rega, reg);
+ SiS_SetReg(SISCR, rega, reg);
+ reg = SiS_GetReg(SISCR, rega);
+ reg = SiS_GetReg(SISCR, rega);
reg += 0x10;
}
}
- andSISIDXREG(SISCR, 0x6e, 0xfc);
+ SiS_SetRegAND(SISCR, 0x6e, 0xfc);
ptr = NULL;
if(ivideo->haveXGIROM) {
@@ -5282,7 +5267,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
ptr = (const u8 *)&bios[index];
}
for(i = 0; i < 4; i++) {
- setSISIDXREG(SISCR, 0x6e, 0xfc, i);
+ SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
reg = 0x00;
for(j = 0; j < 2; j++) {
regd = 0;
@@ -5296,9 +5281,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(regd & 0x01) reg |= 0x01;
if(regd & 0x02) reg |= 0x02;
regd >>= 2;
- outSISIDXREG(SISCR, 0x6f, reg);
- inSISIDXREG(SISCR, 0x6f, reg);
- inSISIDXREG(SISCR, 0x6f, reg);
+ SiS_SetReg(SISCR, 0x6f, reg);
+ reg = SiS_GetReg(SISCR, 0x6f);
+ reg = SiS_GetReg(SISCR, 0x6f);
reg += 0x08;
}
}
@@ -5309,10 +5294,10 @@ sisfb_post_xgi(struct pci_dev *pdev)
ptr = (const u8 *)&bios[0x148];
}
for(i = 0, j = 0; i < 2; i++, j += 8) {
- outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
+ SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
}
- andSISIDXREG(SISCR, 0x89, 0x8f);
+ SiS_SetRegAND(SISCR, 0x89, 0x8f);
ptr = cs45a;
if(ivideo->haveXGIROM) {
@@ -5326,9 +5311,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(regd & 0x01) reg |= 0x01;
if(regd & 0x02) reg |= 0x02;
regd >>= 2;
- outSISIDXREG(SISCR, 0x89, reg);
- inSISIDXREG(SISCR, 0x89, reg);
- inSISIDXREG(SISCR, 0x89, reg);
+ SiS_SetReg(SISCR, 0x89, reg);
+ reg = SiS_GetReg(SISCR, 0x89);
+ reg = SiS_GetReg(SISCR, 0x89);
reg += 0x10;
}
@@ -5339,27 +5324,27 @@ sisfb_post_xgi(struct pci_dev *pdev)
v3 = bios[0x120 + regb];
v4 = bios[0x1ca];
}
- outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
- outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
- orSISIDXREG(SISCR, 0x40, v1 & 0x80);
- outSISIDXREG(SISCR, 0x41, v2);
+ SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
+ SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
+ SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
+ SiS_SetReg(SISCR, 0x41, v2);
ptr = cs170;
if(ivideo->haveXGIROM) {
ptr = (const u8 *)&bios[0x170];
}
for(i = 0, j = 0; i < 7; i++, j += 8) {
- outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
+ SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
}
- outSISIDXREG(SISCR, 0x59, v3);
+ SiS_SetReg(SISCR, 0x59, v3);
ptr = cs1a8;
if(ivideo->haveXGIROM) {
ptr = (const u8 *)&bios[0x1a8];
}
for(i = 0, j = 0; i < 3; i++, j += 8) {
- outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
+ SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
}
ptr = cs100;
@@ -5367,27 +5352,27 @@ sisfb_post_xgi(struct pci_dev *pdev)
ptr = (const u8 *)&bios[0x100];
}
for(i = 0, j = 0; i < 2; i++, j += 8) {
- outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
+ SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
}
- outSISIDXREG(SISCR, 0xcf, v4);
+ SiS_SetReg(SISCR, 0xcf, v4);
- outSISIDXREG(SISCR, 0x83, 0x09);
- outSISIDXREG(SISCR, 0x87, 0x00);
+ SiS_SetReg(SISCR, 0x83, 0x09);
+ SiS_SetReg(SISCR, 0x87, 0x00);
if(ivideo->chip == XGI_40) {
if( (ivideo->revision_id == 1) ||
(ivideo->revision_id == 2) ) {
- outSISIDXREG(SISCR, 0x8c, 0x87);
+ SiS_SetReg(SISCR, 0x8c, 0x87);
}
}
- outSISIDXREG(SISSR, 0x17, 0x00);
- outSISIDXREG(SISSR, 0x1a, 0x87);
+ SiS_SetReg(SISSR, 0x17, 0x00);
+ SiS_SetReg(SISSR, 0x1a, 0x87);
if(ivideo->chip == XGI_20) {
- outSISIDXREG(SISSR, 0x15, 0x00);
- outSISIDXREG(SISSR, 0x1c, 0x00);
+ SiS_SetReg(SISSR, 0x15, 0x00);
+ SiS_SetReg(SISSR, 0x1c, 0x00);
}
ramtype = 0x00; v1 = 0x10;
@@ -5397,16 +5382,16 @@ sisfb_post_xgi(struct pci_dev *pdev)
}
if(!(ramtype & 0x80)) {
if(ivideo->chip == XGI_20) {
- outSISIDXREG(SISCR, 0x97, v1);
- inSISIDXREG(SISCR, 0x97, reg);
+ SiS_SetReg(SISCR, 0x97, v1);
+ reg = SiS_GetReg(SISCR, 0x97);
if(reg & 0x10) {
ramtype = (reg & 0x01) << 1;
}
} else {
- inSISIDXREG(SISSR, 0x39, reg);
+ reg = SiS_GetReg(SISSR, 0x39);
ramtype = reg & 0x02;
if(!(ramtype)) {
- inSISIDXREG(SISSR, 0x3a, reg);
+ reg = SiS_GetReg(SISSR, 0x3a);
ramtype = (reg >> 1) & 0x01;
}
}
@@ -5427,55 +5412,55 @@ sisfb_post_xgi(struct pci_dev *pdev)
v2 = bios[regb + 0x160];
v3 = bios[regb + 0x168];
}
- outSISIDXREG(SISCR, 0x82, v1);
- outSISIDXREG(SISCR, 0x85, v2);
- outSISIDXREG(SISCR, 0x86, v3);
+ SiS_SetReg(SISCR, 0x82, v1);
+ SiS_SetReg(SISCR, 0x85, v2);
+ SiS_SetReg(SISCR, 0x86, v3);
} else {
- outSISIDXREG(SISCR, 0x82, 0x88);
- outSISIDXREG(SISCR, 0x86, 0x00);
- inSISIDXREG(SISCR, 0x86, reg);
- outSISIDXREG(SISCR, 0x86, 0x88);
- inSISIDXREG(SISCR, 0x86, reg);
- outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
- outSISIDXREG(SISCR, 0x82, 0x77);
- outSISIDXREG(SISCR, 0x85, 0x00);
- inSISIDXREG(SISCR, 0x85, reg);
- outSISIDXREG(SISCR, 0x85, 0x88);
- inSISIDXREG(SISCR, 0x85, reg);
- outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
- outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
+ SiS_SetReg(SISCR, 0x82, 0x88);
+ SiS_SetReg(SISCR, 0x86, 0x00);
+ reg = SiS_GetReg(SISCR, 0x86);
+ SiS_SetReg(SISCR, 0x86, 0x88);
+ reg = SiS_GetReg(SISCR, 0x86);
+ SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
+ SiS_SetReg(SISCR, 0x82, 0x77);
+ SiS_SetReg(SISCR, 0x85, 0x00);
+ reg = SiS_GetReg(SISCR, 0x85);
+ SiS_SetReg(SISCR, 0x85, 0x88);
+ reg = SiS_GetReg(SISCR, 0x85);
+ SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
+ SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
}
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISCR, 0x97, 0x00);
+ SiS_SetReg(SISCR, 0x97, 0x00);
}
- outSISIDXREG(SISCR, 0x98, 0x01);
- outSISIDXREG(SISCR, 0x9a, 0x02);
+ SiS_SetReg(SISCR, 0x98, 0x01);
+ SiS_SetReg(SISCR, 0x9a, 0x02);
- outSISIDXREG(SISSR, 0x18, 0x01);
+ SiS_SetReg(SISSR, 0x18, 0x01);
if((ivideo->chip == XGI_20) ||
(ivideo->revision_id == 2)) {
- outSISIDXREG(SISSR, 0x19, 0x40);
+ SiS_SetReg(SISSR, 0x19, 0x40);
} else {
- outSISIDXREG(SISSR, 0x19, 0x20);
+ SiS_SetReg(SISSR, 0x19, 0x20);
}
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
- outSISIDXREG(SISSR, 0x18, 0x00);
+ SiS_SetReg(SISSR, 0x18, 0x00);
if((ivideo->chip == XGI_20) ||
(ivideo->revision_id == 2)) {
- outSISIDXREG(SISSR, 0x19, 0x40);
+ SiS_SetReg(SISSR, 0x19, 0x40);
} else {
- outSISIDXREG(SISSR, 0x19, 0x20);
+ SiS_SetReg(SISSR, 0x19, 0x20);
}
} else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
- /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
+ /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
}
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
sisfb_post_xgi_delay(ivideo, 4);
v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
if(ivideo->haveXGIROM) {
@@ -5486,74 +5471,74 @@ sisfb_post_xgi(struct pci_dev *pdev)
v4 = bios[index + 2];
v5 = bios[index + 3];
}
- outSISIDXREG(SISSR, 0x18, v1);
- outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
- outSISIDXREG(SISSR, 0x16, v2);
- outSISIDXREG(SISSR, 0x16, v3);
+ SiS_SetReg(SISSR, 0x18, v1);
+ SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
+ SiS_SetReg(SISSR, 0x16, v2);
+ SiS_SetReg(SISSR, 0x16, v3);
sisfb_post_xgi_delay(ivideo, 0x43);
- outSISIDXREG(SISSR, 0x1b, 0x03);
+ SiS_SetReg(SISSR, 0x1b, 0x03);
sisfb_post_xgi_delay(ivideo, 0x22);
- outSISIDXREG(SISSR, 0x18, v1);
- outSISIDXREG(SISSR, 0x19, 0x00);
- outSISIDXREG(SISSR, 0x16, v4);
- outSISIDXREG(SISSR, 0x16, v5);
- outSISIDXREG(SISSR, 0x1b, 0x00);
+ SiS_SetReg(SISSR, 0x18, v1);
+ SiS_SetReg(SISSR, 0x19, 0x00);
+ SiS_SetReg(SISSR, 0x16, v4);
+ SiS_SetReg(SISSR, 0x16, v5);
+ SiS_SetReg(SISSR, 0x1b, 0x00);
break;
case 1:
- outSISIDXREG(SISCR, 0x82, 0x77);
- outSISIDXREG(SISCR, 0x86, 0x00);
- inSISIDXREG(SISCR, 0x86, reg);
- outSISIDXREG(SISCR, 0x86, 0x88);
- inSISIDXREG(SISCR, 0x86, reg);
+ SiS_SetReg(SISCR, 0x82, 0x77);
+ SiS_SetReg(SISCR, 0x86, 0x00);
+ reg = SiS_GetReg(SISCR, 0x86);
+ SiS_SetReg(SISCR, 0x86, 0x88);
+ reg = SiS_GetReg(SISCR, 0x86);
v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
if(ivideo->haveXGIROM) {
v1 = bios[regb + 0x168];
v2 = bios[regb + 0x160];
v3 = bios[regb + 0x158];
}
- outSISIDXREG(SISCR, 0x86, v1);
- outSISIDXREG(SISCR, 0x82, 0x77);
- outSISIDXREG(SISCR, 0x85, 0x00);
- inSISIDXREG(SISCR, 0x85, reg);
- outSISIDXREG(SISCR, 0x85, 0x88);
- inSISIDXREG(SISCR, 0x85, reg);
- outSISIDXREG(SISCR, 0x85, v2);
- outSISIDXREG(SISCR, 0x82, v3);
- outSISIDXREG(SISCR, 0x98, 0x01);
- outSISIDXREG(SISCR, 0x9a, 0x02);
-
- outSISIDXREG(SISSR, 0x28, 0x64);
- outSISIDXREG(SISSR, 0x29, 0x63);
+ SiS_SetReg(SISCR, 0x86, v1);
+ SiS_SetReg(SISCR, 0x82, 0x77);
+ SiS_SetReg(SISCR, 0x85, 0x00);
+ reg = SiS_GetReg(SISCR, 0x85);
+ SiS_SetReg(SISCR, 0x85, 0x88);
+ reg = SiS_GetReg(SISCR, 0x85);
+ SiS_SetReg(SISCR, 0x85, v2);
+ SiS_SetReg(SISCR, 0x82, v3);
+ SiS_SetReg(SISCR, 0x98, 0x01);
+ SiS_SetReg(SISCR, 0x9a, 0x02);
+
+ SiS_SetReg(SISSR, 0x28, 0x64);
+ SiS_SetReg(SISSR, 0x29, 0x63);
sisfb_post_xgi_delay(ivideo, 15);
- outSISIDXREG(SISSR, 0x18, 0x00);
- outSISIDXREG(SISSR, 0x19, 0x20);
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
- outSISIDXREG(SISSR, 0x18, 0xc5);
- outSISIDXREG(SISSR, 0x19, 0x23);
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x18, 0x00);
+ SiS_SetReg(SISSR, 0x19, 0x20);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x18, 0xc5);
+ SiS_SetReg(SISSR, 0x19, 0x23);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
sisfb_post_xgi_delay(ivideo, 1);
- outSISIDXREG(SISCR, 0x97,0x11);
+ SiS_SetReg(SISCR, 0x97, 0x11);
sisfb_post_xgi_setclocks(ivideo, regb);
sisfb_post_xgi_delay(ivideo, 0x46);
- outSISIDXREG(SISSR, 0x18, 0xc5);
- outSISIDXREG(SISSR, 0x19, 0x23);
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x18, 0xc5);
+ SiS_SetReg(SISSR, 0x19, 0x23);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
sisfb_post_xgi_delay(ivideo, 1);
- outSISIDXREG(SISSR, 0x1b, 0x04);
+ SiS_SetReg(SISSR, 0x1b, 0x04);
sisfb_post_xgi_delay(ivideo, 1);
- outSISIDXREG(SISSR, 0x1b, 0x00);
+ SiS_SetReg(SISSR, 0x1b, 0x00);
sisfb_post_xgi_delay(ivideo, 1);
v1 = 0x31;
if(ivideo->haveXGIROM) {
v1 = bios[0xf0];
}
- outSISIDXREG(SISSR, 0x18, v1);
- outSISIDXREG(SISSR, 0x19, 0x06);
- outSISIDXREG(SISSR, 0x16, 0x04);
- outSISIDXREG(SISSR, 0x16, 0x84);
+ SiS_SetReg(SISSR, 0x18, v1);
+ SiS_SetReg(SISSR, 0x19, 0x06);
+ SiS_SetReg(SISSR, 0x16, 0x04);
+ SiS_SetReg(SISSR, 0x16, 0x84);
sisfb_post_xgi_delay(ivideo, 1);
break;
default:
@@ -5561,85 +5546,85 @@ sisfb_post_xgi(struct pci_dev *pdev)
if((ivideo->chip == XGI_40) &&
((ivideo->revision_id == 1) ||
(ivideo->revision_id == 2))) {
- outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
- outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
- outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
+ SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
+ SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
+ SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
} else {
- outSISIDXREG(SISCR, 0x82, 0x88);
- outSISIDXREG(SISCR, 0x86, 0x00);
- inSISIDXREG(SISCR, 0x86, reg);
- outSISIDXREG(SISCR, 0x86, 0x88);
- outSISIDXREG(SISCR, 0x82, 0x77);
- outSISIDXREG(SISCR, 0x85, 0x00);
- inSISIDXREG(SISCR, 0x85, reg);
- outSISIDXREG(SISCR, 0x85, 0x88);
- inSISIDXREG(SISCR, 0x85, reg);
+ SiS_SetReg(SISCR, 0x82, 0x88);
+ SiS_SetReg(SISCR, 0x86, 0x00);
+ reg = SiS_GetReg(SISCR, 0x86);
+ SiS_SetReg(SISCR, 0x86, 0x88);
+ SiS_SetReg(SISCR, 0x82, 0x77);
+ SiS_SetReg(SISCR, 0x85, 0x00);
+ reg = SiS_GetReg(SISCR, 0x85);
+ SiS_SetReg(SISCR, 0x85, 0x88);
+ reg = SiS_GetReg(SISCR, 0x85);
v1 = cs160[regb]; v2 = cs158[regb];
if(ivideo->haveXGIROM) {
v1 = bios[regb + 0x160];
v2 = bios[regb + 0x158];
}
- outSISIDXREG(SISCR, 0x85, v1);
- outSISIDXREG(SISCR, 0x82, v2);
+ SiS_SetReg(SISCR, 0x85, v1);
+ SiS_SetReg(SISCR, 0x82, v2);
}
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISCR, 0x97, 0x11);
+ SiS_SetReg(SISCR, 0x97, 0x11);
}
if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
- outSISIDXREG(SISCR, 0x98, 0x01);
+ SiS_SetReg(SISCR, 0x98, 0x01);
} else {
- outSISIDXREG(SISCR, 0x98, 0x03);
+ SiS_SetReg(SISCR, 0x98, 0x03);
}
- outSISIDXREG(SISCR, 0x9a, 0x02);
+ SiS_SetReg(SISCR, 0x9a, 0x02);
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISSR, 0x18, 0x01);
+ SiS_SetReg(SISSR, 0x18, 0x01);
} else {
- outSISIDXREG(SISSR, 0x18, 0x00);
+ SiS_SetReg(SISSR, 0x18, 0x00);
}
- outSISIDXREG(SISSR, 0x19, 0x40);
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x19, 0x40);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
sisfb_post_xgi_delay(ivideo, 0x43);
- outSISIDXREG(SISSR, 0x18, 0x00);
- outSISIDXREG(SISSR, 0x19, 0x40);
- outSISIDXREG(SISSR, 0x16, 0x00);
- outSISIDXREG(SISSR, 0x16, 0x80);
+ SiS_SetReg(SISSR, 0x18, 0x00);
+ SiS_SetReg(SISSR, 0x19, 0x40);
+ SiS_SetReg(SISSR, 0x16, 0x00);
+ SiS_SetReg(SISSR, 0x16, 0x80);
}
sisfb_post_xgi_delay(ivideo, 4);
v1 = 0x31;
if(ivideo->haveXGIROM) {
v1 = bios[0xf0];
}
- outSISIDXREG(SISSR, 0x18, v1);
- outSISIDXREG(SISSR, 0x19, 0x01);
+ SiS_SetReg(SISSR, 0x18, v1);
+ SiS_SetReg(SISSR, 0x19, 0x01);
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISSR, 0x16, bios[0x53e]);
- outSISIDXREG(SISSR, 0x16, bios[0x53f]);
+ SiS_SetReg(SISSR, 0x16, bios[0x53e]);
+ SiS_SetReg(SISSR, 0x16, bios[0x53f]);
} else {
- outSISIDXREG(SISSR, 0x16, 0x05);
- outSISIDXREG(SISSR, 0x16, 0x85);
+ SiS_SetReg(SISSR, 0x16, 0x05);
+ SiS_SetReg(SISSR, 0x16, 0x85);
}
sisfb_post_xgi_delay(ivideo, 0x43);
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISSR, 0x1b, 0x01);
+ SiS_SetReg(SISSR, 0x1b, 0x01);
} else {
- outSISIDXREG(SISSR, 0x1b, 0x03);
+ SiS_SetReg(SISSR, 0x1b, 0x03);
}
sisfb_post_xgi_delay(ivideo, 0x22);
- outSISIDXREG(SISSR, 0x18, v1);
- outSISIDXREG(SISSR, 0x19, 0x00);
+ SiS_SetReg(SISSR, 0x18, v1);
+ SiS_SetReg(SISSR, 0x19, 0x00);
if(ivideo->chip == XGI_40) {
- outSISIDXREG(SISSR, 0x16, bios[0x540]);
- outSISIDXREG(SISSR, 0x16, bios[0x541]);
+ SiS_SetReg(SISSR, 0x16, bios[0x540]);
+ SiS_SetReg(SISSR, 0x16, bios[0x541]);
} else {
- outSISIDXREG(SISSR, 0x16, 0x05);
- outSISIDXREG(SISSR, 0x16, 0x85);
+ SiS_SetReg(SISSR, 0x16, 0x05);
+ SiS_SetReg(SISSR, 0x16, 0x85);
}
- outSISIDXREG(SISSR, 0x1b, 0x00);
+ SiS_SetReg(SISSR, 0x1b, 0x00);
}
regb = 0; /* ! */
@@ -5647,7 +5632,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(ivideo->haveXGIROM) {
v1 = bios[0x110 + regb];
}
- outSISIDXREG(SISSR, 0x1b, v1);
+ SiS_SetReg(SISSR, 0x1b, v1);
/* RAM size */
v1 = 0x00; v2 = 0x00;
@@ -5659,8 +5644,8 @@ sisfb_post_xgi(struct pci_dev *pdev)
regd = 1 << regb;
if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
- outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
- outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
+ SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
+ SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
} else {
@@ -5672,24 +5657,24 @@ sisfb_post_xgi(struct pci_dev *pdev)
ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
/* Disable read-cache */
- andSISIDXREG(SISSR, 0x21, 0xdf);
+ SiS_SetRegAND(SISSR, 0x21, 0xdf);
sisfb_post_xgi_ramsize(ivideo);
/* Enable read-cache */
- orSISIDXREG(SISSR, 0x21, 0x20);
+ SiS_SetRegOR(SISSR, 0x21, 0x20);
}
#if 0
printk(KERN_DEBUG "-----------------\n");
for(i = 0; i < 0xff; i++) {
- inSISIDXREG(SISCR, i, reg);
+ reg = SiS_GetReg(SISCR, i);
printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
}
for(i = 0; i < 0x40; i++) {
- inSISIDXREG(SISSR, i, reg);
+ reg = SiS_GetReg(SISSR, i);
printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
}
printk(KERN_DEBUG "-----------------\n");
@@ -5697,13 +5682,13 @@ sisfb_post_xgi(struct pci_dev *pdev)
/* Sense CRT1 */
if(ivideo->chip == XGI_20) {
- orSISIDXREG(SISCR, 0x32, 0x20);
+ SiS_SetRegOR(SISCR, 0x32, 0x20);
} else {
- inSISIDXREG(SISPART4, 0x00, reg);
+ reg = SiS_GetReg(SISPART4, 0x00);
if((reg == 1) || (reg == 2)) {
sisfb_sense_crt1(ivideo);
} else {
- orSISIDXREG(SISCR, 0x32, 0x20);
+ SiS_SetRegOR(SISCR, 0x32, 0x20);
}
}
@@ -5714,20 +5699,20 @@ sisfb_post_xgi(struct pci_dev *pdev)
ivideo->curFSTN = ivideo->curDSTN = 0;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
/* Display off */
- orSISIDXREG(SISSR, 0x01, 0x20);
+ SiS_SetRegOR(SISSR, 0x01, 0x20);
/* Save mode number in CR34 */
- outSISIDXREG(SISCR, 0x34, 0x2e);
+ SiS_SetReg(SISCR, 0x34, 0x2e);
/* Let everyone know what the current mode is */
ivideo->modeprechange = 0x2e;
if(ivideo->chip == XGI_40) {
- inSISIDXREG(SISCR, 0xca, reg);
- inSISIDXREG(SISCR, 0xcc, v1);
+ reg = SiS_GetReg(SISCR, 0xca);
+ v1 = SiS_GetReg(SISCR, 0xcc);
if((reg & 0x10) && (!(v1 & 0x04))) {
printk(KERN_ERR
"sisfb: Please connect power to the card.\n");
@@ -5936,6 +5921,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
ivideo->video_base = pci_resource_start(pdev, 0);
+ ivideo->video_size = pci_resource_len(pdev, 0);
ivideo->mmio_base = pci_resource_start(pdev, 1);
ivideo->mmio_size = pci_resource_len(pdev, 1);
ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
@@ -5969,7 +5955,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
#endif
- outSISIDXREG(SISSR, 0x05, 0x86);
+ SiS_SetReg(SISSR, 0x05, 0x86);
if( (!ivideo->sisvga_enabled)
#if !defined(__i386__) && !defined(__x86_64__)
@@ -5977,13 +5963,13 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
) {
for(i = 0x30; i <= 0x3f; i++) {
- outSISIDXREG(SISCR, i, 0x00);
+ SiS_SetReg(SISCR, i, 0x00);
}
}
/* Find out about current video mode */
ivideo->modeprechange = 0x03;
- inSISIDXREG(SISCR, 0x34, reg);
+ reg = SiS_GetReg(SISCR, 0x34);
if(reg & 0x7f) {
ivideo->modeprechange = reg & 0x7f;
} else if(ivideo->sisvga_enabled) {
@@ -6080,9 +6066,9 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if((ivideo->sisfb_mode_idx < 0) ||
((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
- orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+ SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
/* Enable 2D accelerator engine */
- orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+ SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
}
if(sisfb_pdc != 0xff) {
diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
index 81a22eaabfde..12c0dfaf2518 100644
--- a/drivers/video/sis/vgatypes.h
+++ b/drivers/video/sis/vgatypes.h
@@ -55,21 +55,10 @@
#define SISIOMEMTYPE
-#ifdef SIS_LINUX_KERNEL
typedef unsigned long SISIOADDRESS;
#include <linux/types.h> /* Need __iomem */
#undef SISIOMEMTYPE
#define SISIOMEMTYPE __iomem
-#endif
-
-#ifdef SIS_XORG_XF86
-#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
-typedef unsigned long IOADDRESS;
-typedef unsigned long SISIOADDRESS;
-#else
-typedef IOADDRESS SISIOADDRESS;
-#endif
-#endif
typedef enum _SIS_CHIP_TYPE {
SIS_VGALegacy = 0,
diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h
index bef4aae388d0..ea94d214dcff 100644
--- a/drivers/video/sis/vstruct.h
+++ b/drivers/video/sis/vstruct.h
@@ -233,24 +233,15 @@ struct SiS_Private
{
unsigned char ChipType;
unsigned char ChipRevision;
-#ifdef SIS_XORG_XF86
- PCITAG PciTag;
-#endif
-#ifdef SIS_LINUX_KERNEL
void *ivideo;
-#endif
unsigned char *VirtualRomBase;
bool UseROM;
-#ifdef SIS_LINUX_KERNEL
unsigned char SISIOMEMTYPE *VideoMemoryAddress;
unsigned int VideoMemorySize;
-#endif
SISIOADDRESS IOAddress;
SISIOADDRESS IOAddress2; /* For dual chip XGI volari */
-#ifdef SIS_LINUX_KERNEL
SISIOADDRESS RelIO;
-#endif
SISIOADDRESS SiS_P3c4;
SISIOADDRESS SiS_P3d4;
SISIOADDRESS SiS_P3c0;
@@ -280,9 +271,6 @@ struct SiS_Private
unsigned short SiS_IF_DEF_FSTN;
unsigned short SiS_SysFlags;
unsigned char SiS_VGAINFO;
-#ifdef SIS_XORG_XF86
- unsigned short SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
-#endif
bool SiS_UseROM;
bool SiS_ROMNew;
bool SiS_XGIROM;
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index dee64c3b1e67..2ab704118c44 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -536,7 +536,7 @@ static int sstfb_set_par(struct fb_info *info)
fbiinit2 = sst_read(FBIINIT2);
fbiinit3 = sst_read(FBIINIT3);
- /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */
+ /* everything is reset. we enable fbiinit2/3 remap : dac access ok */
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
PCI_EN_INIT_WR | PCI_REMAP_DAC );
diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/video/udlfb.c
index 5969e848d297..2c8364e9b632 100644
--- a/drivers/staging/udlfb/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -16,6 +16,8 @@
* from Florian Echtler, Henrik Bjerregaard Pedersen, and others.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -26,8 +28,8 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/delay.h>
-
-#include "udlfb.h"
+#include <video/udlfb.h>
+#include "edid.h"
static struct fb_fix_screeninfo dlfb_fix = {
.id = "udlfb",
@@ -40,9 +42,7 @@ static struct fb_fix_screeninfo dlfb_fix = {
};
static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
-#ifdef FBINFO_VIRTFB
FBINFO_VIRTFB |
-#endif
FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
@@ -293,7 +293,7 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
pos = (unsigned long)info->fix.smem_start + offset;
- dl_notice("mmap() framebuffer addr:%lu size:%lu\n",
+ pr_notice("mmap() framebuffer addr:%lu size:%lu\n",
pos, size);
while (size > 0) {
@@ -595,18 +595,6 @@ error:
return 0;
}
-static ssize_t dlfb_ops_read(struct fb_info *info, char __user *buf,
- size_t count, loff_t *ppos)
-{
- ssize_t result = -ENOSYS;
-
-#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE
- result = fb_sys_read(info, buf, count, ppos);
-#endif
-
- return result;
-}
-
/*
* Path triggered by usermode clients who write to filesystem
* e.g. cat filename > /dev/fb1
@@ -616,12 +604,10 @@ static ssize_t dlfb_ops_read(struct fb_info *info, char __user *buf,
static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
- ssize_t result = -ENOSYS;
+ ssize_t result;
struct dlfb_data *dev = info->par;
u32 offset = (u32) *ppos;
-#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE
-
result = fb_sys_write(info, buf, count, ppos);
if (result > 0) {
@@ -632,7 +618,6 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
dlfb_handle_damage(dev, 0, start, info->var.xres,
lines, info->screen_base);
}
-#endif
return result;
}
@@ -644,14 +629,10 @@ static void dlfb_ops_copyarea(struct fb_info *info,
struct dlfb_data *dev = info->par;
-#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
-
sys_copyarea(info, area);
dlfb_handle_damage(dev, area->dx, area->dy,
area->width, area->height, info->screen_base);
-#endif
-
}
static void dlfb_ops_imageblit(struct fb_info *info,
@@ -659,15 +640,10 @@ static void dlfb_ops_imageblit(struct fb_info *info,
{
struct dlfb_data *dev = info->par;
-#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
-
sys_imageblit(info, image);
dlfb_handle_damage(dev, image->dx, image->dy,
image->width, image->height, info->screen_base);
-
-#endif
-
}
static void dlfb_ops_fillrect(struct fb_info *info,
@@ -675,17 +651,12 @@ static void dlfb_ops_fillrect(struct fb_info *info,
{
struct dlfb_data *dev = info->par;
-#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
-
sys_fillrect(info, rect);
dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
rect->height, info->screen_base);
-#endif
-
}
-#ifdef CONFIG_FB_DEFERRED_IO
/*
* NOTE: fb_defio.c is holding info->fbdefio.mutex
* Touching ANY framebuffer memory that triggers a page fault
@@ -747,8 +718,6 @@ error:
&dev->cpu_kcycles_used);
}
-#endif
-
static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
{
int i;
@@ -765,7 +734,7 @@ static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
(0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
HZ);
if (ret < 1) {
- dl_err("Read EDID byte %d failed err %x\n", i, ret);
+ pr_err("Read EDID byte %d failed err %x\n", i, ret);
i--;
break;
}
@@ -881,13 +850,12 @@ static int dlfb_ops_open(struct fb_info *info, int user)
kref_get(&dev->kref);
-#ifdef CONFIG_FB_DEFERRED_IO
if (fb_defio && (info->fbdefio == NULL)) {
/* enable defio at last moment if not disabled by client */
struct fb_deferred_io *fbdefio;
- fbdefio = kmalloc(GFP_KERNEL, sizeof(struct fb_deferred_io));
+ fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
if (fbdefio) {
fbdefio->delay = DL_DEFIO_WRITE_DELAY;
@@ -897,9 +865,8 @@ static int dlfb_ops_open(struct fb_info *info, int user)
info->fbdefio = fbdefio;
fb_deferred_io_init(info);
}
-#endif
- dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+ pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
info->node, user, info, dev->fb_count);
return 0;
@@ -923,7 +890,7 @@ static void dlfb_free(struct kref *kref)
kfree(dev->edid);
- dl_warn("freeing dlfb_data %p\n", dev);
+ pr_warn("freeing dlfb_data %p\n", dev);
kfree(dev);
}
@@ -959,7 +926,7 @@ static void dlfb_free_framebuffer_work(struct work_struct *work)
/* Assume info structure is freed after this point */
framebuffer_release(info);
- dl_warn("fb_info for /dev/fb%d has been freed\n", node);
+ pr_warn("fb_info for /dev/fb%d has been freed\n", node);
/* ref taken in probe() as part of registering framebfufer */
kref_put(&dev->kref, dlfb_free);
@@ -978,16 +945,14 @@ static int dlfb_ops_release(struct fb_info *info, int user)
if (dev->virtualized && (dev->fb_count == 0))
schedule_delayed_work(&dev->free_framebuffer_work, HZ);
-#ifdef CONFIG_FB_DEFERRED_IO
if ((dev->fb_count == 0) && (info->fbdefio)) {
fb_deferred_io_cleanup(info);
kfree(info->fbdefio);
info->fbdefio = NULL;
info->fbops->fb_mmap = dlfb_ops_mmap;
}
-#endif
- dl_warn("released /dev/fb%d user=%d count=%d\n",
+ pr_warn("released /dev/fb%d user=%d count=%d\n",
info->node, user, dev->fb_count);
kref_put(&dev->kref, dlfb_free);
@@ -1005,12 +970,12 @@ static int dlfb_is_valid_mode(struct fb_videomode *mode,
struct dlfb_data *dev = info->par;
if (mode->xres * mode->yres > dev->sku_pixel_limit) {
- dl_warn("%dx%d beyond chip capabilities\n",
+ pr_warn("%dx%d beyond chip capabilities\n",
mode->xres, mode->yres);
return 0;
}
- dl_info("%dx%d valid mode\n", mode->xres, mode->yres);
+ pr_info("%dx%d valid mode\n", mode->xres, mode->yres);
return 1;
}
@@ -1054,7 +1019,7 @@ static int dlfb_ops_set_par(struct fb_info *info)
u16 *pix_framebuffer;
int i;
- dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
+ pr_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
result = dlfb_set_video_mode(dev, &info->var);
@@ -1104,7 +1069,7 @@ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
static struct fb_ops dlfb_ops = {
.owner = THIS_MODULE,
- .fb_read = dlfb_ops_read,
+ .fb_read = fb_sys_read,
.fb_write = dlfb_ops_write,
.fb_setcolreg = dlfb_ops_setcolreg,
.fb_fillrect = dlfb_ops_fillrect,
@@ -1133,7 +1098,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
unsigned char *new_fb;
unsigned char *new_back;
- dl_warn("Reallocating framebuffer. Addresses will change!\n");
+ pr_warn("Reallocating framebuffer. Addresses will change!\n");
new_len = info->fix.line_length * info->var.yres;
@@ -1143,7 +1108,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
*/
new_fb = vmalloc(new_len);
if (!new_fb) {
- dl_err("Virtual framebuffer alloc failed\n");
+ pr_err("Virtual framebuffer alloc failed\n");
goto error;
}
@@ -1163,14 +1128,13 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
* But with imperfect damage info we may send pixels over USB
* that were, in fact, unchanged - wasting limited USB bandwidth
*/
- new_back = vmalloc(new_len);
+ new_back = vzalloc(new_len);
if (!new_back)
- dl_info("No shadow/backing buffer allcoated\n");
+ pr_info("No shadow/backing buffer allocated\n");
else {
if (dev->backing_buffer)
vfree(dev->backing_buffer);
dev->backing_buffer = new_back;
- memset(dev->backing_buffer, 0, new_len);
}
}
@@ -1207,7 +1171,7 @@ static int dlfb_setup_modes(struct dlfb_data *dev,
if (info->dev) /* only use mutex if info has been registered */
mutex_lock(&info->lock);
- edid = kmalloc(MAX_EDID_SIZE, GFP_KERNEL);
+ edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (!edid) {
result = -ENOMEM;
goto error;
@@ -1223,9 +1187,9 @@ static int dlfb_setup_modes(struct dlfb_data *dev,
*/
while (tries--) {
- i = dlfb_get_edid(dev, edid, MAX_EDID_SIZE);
+ i = dlfb_get_edid(dev, edid, EDID_LENGTH);
- if (i >= MIN_EDID_SIZE)
+ if (i >= EDID_LENGTH)
fb_edid_to_monspecs(edid, &info->monspecs);
if (info->monspecs.modedb_len > 0) {
@@ -1238,24 +1202,24 @@ static int dlfb_setup_modes(struct dlfb_data *dev,
/* If that fails, use a previously returned EDID if available */
if (info->monspecs.modedb_len == 0) {
- dl_err("Unable to get valid EDID from device/display\n");
+ pr_err("Unable to get valid EDID from device/display\n");
if (dev->edid) {
fb_edid_to_monspecs(dev->edid, &info->monspecs);
if (info->monspecs.modedb_len > 0)
- dl_err("Using previously queried EDID\n");
+ pr_err("Using previously queried EDID\n");
}
}
/* If that fails, use the default EDID we were handed */
if (info->monspecs.modedb_len == 0) {
- if (default_edid_size >= MIN_EDID_SIZE) {
+ if (default_edid_size >= EDID_LENGTH) {
fb_edid_to_monspecs(default_edid, &info->monspecs);
if (info->monspecs.modedb_len > 0) {
memcpy(edid, default_edid, default_edid_size);
dev->edid = edid;
dev->edid_size = default_edid_size;
- dl_err("Using default/backup EDID\n");
+ pr_err("Using default/backup EDID\n");
}
}
}
@@ -1381,7 +1345,7 @@ static ssize_t edid_show(
if (off + count > dev->edid_size)
count = dev->edid_size - off;
- dl_info("sysfs edid copy %p to %p, %d bytes\n",
+ pr_info("sysfs edid copy %p to %p, %d bytes\n",
dev->edid, buf, (int) count);
memcpy(buf, dev->edid, count);
@@ -1398,15 +1362,13 @@ static ssize_t edid_store(
struct dlfb_data *dev = fb_info->par;
/* We only support write of entire EDID at once, no offset*/
- if ((src_size < MIN_EDID_SIZE) ||
- (src_size > MAX_EDID_SIZE) ||
- (src_off != 0))
+ if ((src_size != EDID_LENGTH) || (src_off != 0))
return 0;
dlfb_setup_modes(dev, fb_info, src, src_size);
if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) {
- dl_info("sysfs written EDID is new default\n");
+ pr_info("sysfs written EDID is new default\n");
dlfb_ops_set_par(fb_info);
return src_size;
} else
@@ -1431,7 +1393,7 @@ static ssize_t metrics_reset_store(struct device *fbdev,
static struct bin_attribute edid_attr = {
.attr.name = "edid",
.attr.mode = 0666,
- .size = MAX_EDID_SIZE,
+ .size = EDID_LENGTH,
.read = edid_show,
.write = edid_store
};
@@ -1441,7 +1403,7 @@ static struct device_attribute fb_device_attrs[] = {
__ATTR_RO(metrics_bytes_identical),
__ATTR_RO(metrics_bytes_sent),
__ATTR_RO(metrics_cpu_kcycles_used),
- __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+ __ATTR(metrics_reset, S_IWUSR, NULL, metrics_reset_store),
};
/*
@@ -1479,7 +1441,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
if (total_len > 5) {
- dl_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \
+ pr_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \
"%02x %02x %02x %02x %02x %02x %02x\n",
total_len, desc[0],
desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
@@ -1508,7 +1470,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
case 0x0200: { /* max_area */
u32 max_area;
max_area = le32_to_cpu(*((u32 *)desc));
- dl_warn("DL chip limited to %d pixel modes\n",
+ pr_warn("DL chip limited to %d pixel modes\n",
max_area);
dev->sku_pixel_limit = max_area;
break;
@@ -1524,7 +1486,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
unrecognized:
/* allow udlfb to load for now even if firmware unrecognized */
- dl_err("Unrecognized vendor firmware descriptor\n");
+ pr_err("Unrecognized vendor firmware descriptor\n");
success:
kfree(buf);
@@ -1557,24 +1519,24 @@ static int dlfb_usb_probe(struct usb_interface *interface,
dev->gdev = &usbdev->dev; /* our generic struct device * */
usb_set_intfdata(interface, dev);
- dl_info("%s %s - serial #%s\n",
+ pr_info("%s %s - serial #%s\n",
usbdev->manufacturer, usbdev->product, usbdev->serial);
- dl_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n",
+ pr_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n",
usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
usbdev->descriptor.bcdDevice, dev);
- dl_info("console enable=%d\n", console);
- dl_info("fb_defio enable=%d\n", fb_defio);
+ pr_info("console enable=%d\n", console);
+ pr_info("fb_defio enable=%d\n", fb_defio);
dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
if (!dlfb_parse_vendor_descriptor(dev, usbdev)) {
- dl_err("firmware not recognized. Assume incompatible device\n");
+ pr_err("firmware not recognized. Assume incompatible device\n");
goto error;
}
if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
retval = -ENOMEM;
- dl_err("dlfb_alloc_urb_list failed\n");
+ pr_err("dlfb_alloc_urb_list failed\n");
goto error;
}
@@ -1584,7 +1546,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
info = framebuffer_alloc(0, &usbdev->dev);
if (!info) {
retval = -ENOMEM;
- dl_err("framebuffer_alloc failed\n");
+ pr_err("framebuffer_alloc failed\n");
goto error;
}
@@ -1595,7 +1557,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0) {
- dl_err("fb_alloc_cmap failed %x\n", retval);
+ pr_err("fb_alloc_cmap failed %x\n", retval);
goto error;
}
@@ -1606,7 +1568,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
retval = dlfb_setup_modes(dev, info, NULL, 0);
if (retval != 0) {
- dl_err("unable to find common mode for display and adapter\n");
+ pr_err("unable to find common mode for display and adapter\n");
goto error;
}
@@ -1620,7 +1582,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
retval = register_framebuffer(info);
if (retval < 0) {
- dl_err("register_framebuffer failed %d\n", retval);
+ pr_err("register_framebuffer failed %d\n", retval);
goto error;
}
@@ -1629,7 +1591,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
device_create_bin_file(info->dev, &edid_attr);
- dl_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
+ pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
" Using %dK framebuffer memory\n", info->node,
info->var.xres, info->var.yres,
((dev->backing_buffer) ?
@@ -1673,7 +1635,7 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
dev = usb_get_intfdata(interface);
info = dev->info;
- dl_info("USB disconnect starting\n");
+ pr_info("USB disconnect starting\n");
/* we virtualize until all fb clients release. Then we free */
dev->virtualized = true;
@@ -1737,7 +1699,7 @@ static void dlfb_urb_completion(struct urb *urb)
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
- dl_err("%s - nonzero write bulk status received: %d\n",
+ pr_err("%s - nonzero write bulk status received: %d\n",
__func__, urb->status);
atomic_set(&dev->lost_pixels, 1);
}
@@ -1769,7 +1731,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
int ret;
unsigned long flags;
- dl_notice("Waiting for completes and freeing all render urbs\n");
+ pr_notice("Waiting for completes and freeing all render urbs\n");
/* keep waiting and freeing, until we've got 'em all */
while (count--) {
@@ -1848,7 +1810,7 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
dev->urbs.count = i;
dev->urbs.available = i;
- dl_notice("allocated %d %d byte urbs\n", i, (int) size);
+ pr_notice("allocated %d %d byte urbs\n", i, (int) size);
return i;
}
@@ -1865,7 +1827,7 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dev)
ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
if (ret) {
atomic_set(&dev->lost_pixels, 1);
- dl_warn("wait for urb interrupted: %x available: %d\n",
+ pr_warn("wait for urb interrupted: %x available: %d\n",
ret, dev->urbs.available);
goto error;
}
@@ -1897,7 +1859,7 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
if (ret) {
dlfb_urb_completion(urb); /* because no one else will */
atomic_set(&dev->lost_pixels, 1);
- dl_err("usb_submit_urb error %x\n", ret);
+ pr_err("usb_submit_urb error %x\n", ret);
}
return ret;
}
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index a3aa91709503..6723d6910cde 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -15,6 +15,9 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/pm.h>
+#include <asm/olpc.h>
/*
* The default port config.
@@ -29,6 +32,19 @@ static struct via_port_cfg adap_configs[] = {
};
/*
+ * The OLPC XO-1.5 puts the camera power and reset lines onto
+ * GPIO 2C.
+ */
+static const struct via_port_cfg olpc_adap_configs[] = {
+ [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 },
+ [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
+ [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
+ [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x2c },
+ [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
+ { 0, 0, 0, 0 }
+};
+
+/*
* We currently only support one viafb device (will there ever be
* more than one?), so just declare it globally here.
*/
@@ -575,6 +591,78 @@ static void via_teardown_subdevs(void)
}
}
+/*
+ * Power management functions
+ */
+#ifdef CONFIG_PM
+static LIST_HEAD(viafb_pm_hooks);
+static DEFINE_MUTEX(viafb_pm_hooks_lock);
+
+void viafb_pm_register(struct viafb_pm_hooks *hooks)
+{
+ INIT_LIST_HEAD(&hooks->list);
+
+ mutex_lock(&viafb_pm_hooks_lock);
+ list_add_tail(&hooks->list, &viafb_pm_hooks);
+ mutex_unlock(&viafb_pm_hooks_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_pm_register);
+
+void viafb_pm_unregister(struct viafb_pm_hooks *hooks)
+{
+ mutex_lock(&viafb_pm_hooks_lock);
+ list_del(&hooks->list);
+ mutex_unlock(&viafb_pm_hooks_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_pm_unregister);
+
+static int via_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct viafb_pm_hooks *hooks;
+
+ if (state.event != PM_EVENT_SUSPEND)
+ return 0;
+ /*
+ * "I've occasionally hit a few drivers that caused suspend
+ * failures, and each and every time it was a driver bug, and
+ * the right thing to do was to just ignore the error and suspend
+ * anyway - returning an error code and trying to undo the suspend
+ * is not what anybody ever really wants, even if our model
+ *_allows_ for it."
+ * -- Linus Torvalds, Dec. 7, 2009
+ */
+ mutex_lock(&viafb_pm_hooks_lock);
+ list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list)
+ hooks->suspend(hooks->private);
+ mutex_unlock(&viafb_pm_hooks_lock);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int via_resume(struct pci_dev *pdev)
+{
+ struct viafb_pm_hooks *hooks;
+
+ /* Get the bus side powered up */
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev))
+ return 0;
+
+ pci_set_master(pdev);
+
+ /* Now bring back any subdevs */
+ mutex_lock(&viafb_pm_hooks_lock);
+ list_for_each_entry(hooks, &viafb_pm_hooks, list)
+ hooks->resume(hooks->private);
+ mutex_unlock(&viafb_pm_hooks_lock);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -584,6 +672,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
ret = pci_enable_device(pdev);
if (ret)
return ret;
+
/*
* Global device initialization.
*/
@@ -591,6 +680,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
global_dev.pdev = pdev;
global_dev.chip_type = ent->driver_data;
global_dev.port_cfg = adap_configs;
+ if (machine_is_olpc())
+ global_dev.port_cfg = olpc_adap_configs;
+
spin_lock_init(&global_dev.reg_lock);
ret = via_pci_setup_mmio(&global_dev);
if (ret)
@@ -663,8 +755,8 @@ static struct pci_driver via_driver = {
.probe = via_pci_probe,
.remove = __devexit_p(via_pci_remove),
#ifdef CONFIG_PM
- .suspend = viafb_suspend,
- .resume = viafb_resume,
+ .suspend = via_suspend,
+ .resume = via_resume,
#endif
};
diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c
index 39acb37e7a1d..c2a0a1cfd3b3 100644
--- a/drivers/video/via/via-gpio.c
+++ b/drivers/video/via/via-gpio.c
@@ -172,6 +172,28 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio)
via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
}
+#ifdef CONFIG_PM
+
+static int viafb_gpio_suspend(void *private)
+{
+ return 0;
+}
+
+static int viafb_gpio_resume(void *private)
+{
+ int i;
+
+ for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
+ viafb_gpio_enable(gpio_config.active_gpios[i]);
+ return 0;
+}
+
+static struct viafb_pm_hooks viafb_gpio_pm_hooks = {
+ .suspend = viafb_gpio_suspend,
+ .resume = viafb_gpio_resume
+};
+#endif /* CONFIG_PM */
+
/*
* Look up a specific gpio and return the number it was assigned.
*/
@@ -236,6 +258,9 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
gpio_config.gpio_chip.ngpio = 0;
}
+#ifdef CONFIG_PM
+ viafb_pm_register(&viafb_gpio_pm_hooks);
+#endif
return ret;
}
@@ -245,6 +270,10 @@ static int viafb_gpio_remove(struct platform_device *platdev)
unsigned long flags;
int ret = 0, i;
+#ifdef CONFIG_PM
+ viafb_pm_unregister(&viafb_gpio_pm_hooks);
+#endif
+
/*
* Get unregistered.
*/
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index d298cfccd6fc..289edd519527 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1672,31 +1672,19 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
#ifdef CONFIG_PM
-int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
+static int viafb_suspend(void *unused)
{
- if (state.event == PM_EVENT_SUSPEND) {
- acquire_console_sem();
- fb_set_suspend(viafbinfo, 1);
-
- viafb_sync(viafbinfo);
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- release_console_sem();
- }
+ acquire_console_sem();
+ fb_set_suspend(viafbinfo, 1);
+ viafb_sync(viafbinfo);
+ release_console_sem();
return 0;
}
-int viafb_resume(struct pci_dev *pdev)
+static int viafb_resume(void *unused)
{
acquire_console_sem();
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- if (pci_enable_device(pdev))
- goto fail;
- pci_set_master(pdev);
if (viaparinfo->shared->vdev->engine_mmio)
viafb_reset_engine(viaparinfo);
viafb_set_par(viafbinfo);
@@ -1704,11 +1692,15 @@ int viafb_resume(struct pci_dev *pdev)
viafb_set_par(viafbinfo1);
fb_set_suspend(viafbinfo, 0);
-fail:
release_console_sem();
return 0;
}
+static struct viafb_pm_hooks viafb_fb_pm_hooks = {
+ .suspend = viafb_suspend,
+ .resume = viafb_resume
+};
+
#endif
@@ -1899,6 +1891,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
viafb_init_proc(viaparinfo->shared);
viafb_init_dac(IGA2);
+
+#ifdef CONFIG_PM
+ viafb_pm_register(&viafb_fb_pm_hooks);
+#endif
return 0;
out_fb_unreg:
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index 4960e3da6645..d66f963e930e 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -108,6 +108,4 @@ void via_fb_pci_remove(struct pci_dev *pdev);
/* Temporary */
int viafb_init(void);
void viafb_exit(void);
-int viafb_suspend(struct pci_dev *pdev, pm_message_t state);
-int viafb_resume(struct pci_dev *pdev);
#endif /* __VIAFBDEV_H__ */
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
new file mode 100644
index 000000000000..0e120d67eb65
--- /dev/null
+++ b/drivers/video/vt8500lcdfb.c
@@ -0,0 +1,475 @@
+/*
+ * linux/drivers/video/vt8500lcdfb.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on skeletonfb.c and pxafb.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+
+#include <mach/vt8500fb.h>
+
+#include "vt8500lcdfb.h"
+#include "wmt_ge_rops.h"
+
+#define to_vt8500lcd_info(__info) container_of(__info, \
+ struct vt8500lcd_info, fb)
+
+static int vt8500lcd_set_par(struct fb_info *info)
+{
+ struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
+ int reg_bpp = 5; /* 16bpp */
+ int i;
+ unsigned long control0;
+
+ if (!fbi)
+ return -EINVAL;
+
+ if (info->var.bits_per_pixel <= 8) {
+ /* palettized */
+ info->var.red.offset = 0;
+ info->var.red.length = info->var.bits_per_pixel;
+ info->var.red.msb_right = 0;
+
+ info->var.green.offset = 0;
+ info->var.green.length = info->var.bits_per_pixel;
+ info->var.green.msb_right = 0;
+
+ info->var.blue.offset = 0;
+ info->var.blue.length = info->var.bits_per_pixel;
+ info->var.blue.msb_right = 0;
+
+ info->var.transp.offset = 0;
+ info->var.transp.length = 0;
+ info->var.transp.msb_right = 0;
+
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.line_length = info->var.xres_virtual /
+ (8/info->var.bits_per_pixel);
+ } else {
+ /* non-palettized */
+ info->var.transp.offset = 0;
+ info->var.transp.length = 0;
+ info->var.transp.msb_right = 0;
+
+ if (info->var.bits_per_pixel == 16) {
+ /* RGB565 */
+ info->var.red.offset = 11;
+ info->var.red.length = 5;
+ info->var.red.msb_right = 0;
+ info->var.green.offset = 5;
+ info->var.green.length = 6;
+ info->var.green.msb_right = 0;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 5;
+ info->var.blue.msb_right = 0;
+ } else {
+ /* Equal depths per channel */
+ info->var.red.offset = info->var.bits_per_pixel
+ * 2 / 3;
+ info->var.red.length = info->var.bits_per_pixel / 3;
+ info->var.red.msb_right = 0;
+ info->var.green.offset = info->var.bits_per_pixel / 3;
+ info->var.green.length = info->var.bits_per_pixel / 3;
+ info->var.green.msb_right = 0;
+ info->var.blue.offset = 0;
+ info->var.blue.length = info->var.bits_per_pixel / 3;
+ info->var.blue.msb_right = 0;
+ }
+
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = info->var.bits_per_pixel > 16 ?
+ info->var.xres_virtual << 2 :
+ info->var.xres_virtual << 1;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (bpp_values[i] == info->var.bits_per_pixel) {
+ reg_bpp = i;
+ continue;
+ }
+ }
+
+ control0 = readl(fbi->regbase) & ~0xf;
+ writel(0, fbi->regbase);
+ while (readl(fbi->regbase + 0x38) & 0x10)
+ /* wait */;
+ writel((((info->var.hsync_len - 1) & 0x3f) << 26)
+ | ((info->var.left_margin & 0xff) << 18)
+ | (((info->var.xres - 1) & 0x3ff) << 8)
+ | (info->var.right_margin & 0xff), fbi->regbase + 0x4);
+ writel((((info->var.vsync_len - 1) & 0x3f) << 26)
+ | ((info->var.upper_margin & 0xff) << 18)
+ | (((info->var.yres - 1) & 0x3ff) << 8)
+ | (info->var.lower_margin & 0xff), fbi->regbase + 0x8);
+ writel((((info->var.yres - 1) & 0x400) << 2)
+ | ((info->var.xres - 1) & 0x400), fbi->regbase + 0x10);
+ writel(0x80000000, fbi->regbase + 0x20);
+ writel(control0 | (reg_bpp << 1) | 0x100, fbi->regbase);
+
+ 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 vt8500lcd_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info) {
+ struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
+ int ret = 1;
+ unsigned int val;
+ if (regno >= 256)
+ return -EINVAL;
+
+ if (info->var.grayscale)
+ red = green = blue =
+ (19595 * red + 38470 * green + 7471 * blue) >> 16;
+
+ switch (fbi->fb.fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ u32 *pal = fbi->fb.pseudo_palette;
+
+ val = chan_to_field(red, &fbi->fb.var.red);
+ val |= chan_to_field(green, &fbi->fb.var.green);
+ val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ writew((red & 0xf800)
+ | ((green >> 5) & 0x7e0)
+ | ((blue >> 11) & 0x1f),
+ fbi->palette_cpu + sizeof(u16) * regno);
+ break;
+ }
+
+ return ret;
+}
+
+static int vt8500lcd_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
+
+ if (cmd == FBIO_WAITFORVSYNC) {
+ /* Unmask End of Frame interrupt */
+ writel(0xffffffff ^ (1 << 3), fbi->regbase + 0x3c);
+ ret = wait_event_interruptible_timeout(fbi->wait,
+ readl(fbi->regbase + 0x38) & (1 << 3), HZ / 10);
+ /* Mask back to reduce unwanted interrupt traffic */
+ writel(0xffffffff, fbi->regbase + 0x3c);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int vt8500lcd_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned pixlen = info->fix.line_length / info->var.xres_virtual;
+ unsigned off = pixlen * var->xoffset
+ + info->fix.line_length * var->yoffset;
+ struct vt8500lcd_info *fbi = to_vt8500lcd_info(info);
+
+ writel((1 << 31)
+ | (((var->xres_virtual - var->xres) * pixlen / 4) << 20)
+ | (off >> 2), fbi->regbase + 0x20);
+ return 0;
+}
+
+/*
+ * vt8500lcd_blank():
+ * Blank the display by setting all palette values to zero. Note,
+ * True Color modes do not really use the palette, so this will not
+ * blank the display in all modes.
+ */
+static int vt8500lcd_blank(int blank, struct fb_info *info)
+{
+ int i;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+ info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+ for (i = 0; i < 256; i++)
+ vt8500lcd_setcolreg(i, 0, 0, 0, 0, info);
+ case FB_BLANK_UNBLANK:
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+ info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+ fb_set_cmap(&info->cmap, info);
+ }
+ return 0;
+}
+
+static struct fb_ops vt8500lcd_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = vt8500lcd_set_par,
+ .fb_setcolreg = vt8500lcd_setcolreg,
+ .fb_fillrect = wmt_ge_fillrect,
+ .fb_copyarea = wmt_ge_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_sync = wmt_ge_sync,
+ .fb_ioctl = vt8500lcd_ioctl,
+ .fb_pan_display = vt8500lcd_pan_display,
+ .fb_blank = vt8500lcd_blank,
+};
+
+static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id)
+{
+ struct vt8500lcd_info *fbi = dev_id;
+
+ if (readl(fbi->regbase + 0x38) & (1 << 3))
+ wake_up_interruptible(&fbi->wait);
+
+ writel(0xffffffff, fbi->regbase + 0x38);
+ return IRQ_HANDLED;
+}
+
+static int __devinit vt8500lcd_probe(struct platform_device *pdev)
+{
+ struct vt8500lcd_info *fbi;
+ struct resource *res;
+ struct vt8500fb_platform_data *pdata = pdev->dev.platform_data;
+ void *addr;
+ int irq, ret;
+
+ ret = -ENOMEM;
+ fbi = NULL;
+
+ fbi = kzalloc(sizeof(struct vt8500lcd_info) + sizeof(u32) * 16,
+ GFP_KERNEL);
+ if (!fbi) {
+ dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ strcpy(fbi->fb.fix.id, "VT8500 LCD");
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.xpanstep = 0;
+ fbi->fb.fix.ypanstep = 1;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+ fbi->fb.fbops = &vt8500lcd_ops;
+ fbi->fb.flags = FBINFO_DEFAULT
+ | FBINFO_HWACCEL_COPYAREA
+ | FBINFO_HWACCEL_FILLRECT
+ | FBINFO_HWACCEL_YPAN
+ | FBINFO_VIRTFB
+ | FBINFO_PARTIAL_PAN_OK;
+ fbi->fb.node = -1;
+
+ addr = fbi;
+ addr = addr + sizeof(struct vt8500lcd_info);
+ fbi->fb.pseudo_palette = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto failed_fbi;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), "vt8500lcd");
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto failed_fbi;
+ }
+
+ fbi->regbase = ioremap(res->start, resource_size(res));
+ if (fbi->regbase == NULL) {
+ dev_err(&pdev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto failed_free_res;
+ }
+
+ fbi->fb.fix.smem_start = pdata->video_mem_phys;
+ fbi->fb.fix.smem_len = pdata->video_mem_len;
+ fbi->fb.screen_base = pdata->video_mem_virt;
+
+ fbi->palette_size = PAGE_ALIGN(512);
+ fbi->palette_cpu = dma_alloc_coherent(&pdev->dev,
+ fbi->palette_size,
+ &fbi->palette_phys,
+ GFP_KERNEL);
+ if (fbi->palette_cpu == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate palette buffer\n");
+ ret = -ENOMEM;
+ goto failed_free_io;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no IRQ defined\n");
+ ret = -ENODEV;
+ goto failed_free_palette;
+ }
+
+ ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
+ ret = -EBUSY;
+ goto failed_free_palette;
+ }
+
+ init_waitqueue_head(&fbi->wait);
+
+ if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
+ dev_err(&pdev->dev, "Failed to allocate color map\n");
+ ret = -ENOMEM;
+ goto failed_free_irq;
+ }
+
+ fb_videomode_to_var(&fbi->fb.var, &pdata->mode);
+ fbi->fb.var.bits_per_pixel = pdata->bpp;
+ fbi->fb.var.xres_virtual = pdata->xres_virtual;
+ fbi->fb.var.yres_virtual = pdata->yres_virtual;
+
+ ret = vt8500lcd_set_par(&fbi->fb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set parameters\n");
+ goto failed_free_cmap;
+ }
+
+ writel(fbi->fb.fix.smem_start >> 22, fbi->regbase + 0x1c);
+ writel((fbi->palette_phys & 0xfffffe00) | 1, fbi->regbase + 0x18);
+
+ platform_set_drvdata(pdev, fbi);
+
+ ret = register_framebuffer(&fbi->fb);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Failed to register framebuffer device: %d\n", ret);
+ goto failed_free_cmap;
+ }
+
+ /*
+ * Ok, now enable the LCD controller
+ */
+ writel(readl(fbi->regbase) | 1, fbi->regbase);
+
+ return 0;
+
+failed_free_cmap:
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
+failed_free_irq:
+ free_irq(irq, fbi);
+failed_free_palette:
+ dma_free_coherent(&pdev->dev, fbi->palette_size,
+ fbi->palette_cpu, fbi->palette_phys);
+failed_free_io:
+ iounmap(fbi->regbase);
+failed_free_res:
+ release_mem_region(res->start, resource_size(res));
+failed_fbi:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fbi);
+failed:
+ return ret;
+}
+
+static int __devexit vt8500lcd_remove(struct platform_device *pdev)
+{
+ struct vt8500lcd_info *fbi = platform_get_drvdata(pdev);
+ struct resource *res;
+ int irq;
+
+ unregister_framebuffer(&fbi->fb);
+
+ writel(0, fbi->regbase);
+
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
+
+ irq = platform_get_irq(pdev, 0);
+ free_irq(irq, fbi);
+
+ dma_free_coherent(&pdev->dev, fbi->palette_size,
+ fbi->palette_cpu, fbi->palette_phys);
+
+ iounmap(fbi->regbase);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(fbi);
+
+ return 0;
+}
+
+static struct platform_driver vt8500lcd_driver = {
+ .probe = vt8500lcd_probe,
+ .remove = __devexit_p(vt8500lcd_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "vt8500-lcd",
+ },
+};
+
+static int __init vt8500lcd_init(void)
+{
+ return platform_driver_register(&vt8500lcd_driver);
+}
+
+static void __exit vt8500lcd_exit(void)
+{
+ platform_driver_unregister(&vt8500lcd_driver);
+}
+
+module_init(vt8500lcd_init);
+module_exit(vt8500lcd_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("LCD controller driver for VIA VT8500");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vt8500lcdfb.h b/drivers/video/vt8500lcdfb.h
new file mode 100644
index 000000000000..36ca3ca09d83
--- /dev/null
+++ b/drivers/video/vt8500lcdfb.h
@@ -0,0 +1,34 @@
+/*
+ * linux/drivers/video/vt8500lcdfb.h
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+struct vt8500lcd_info {
+ struct fb_info fb;
+ void __iomem *regbase;
+ void __iomem *palette_cpu;
+ dma_addr_t palette_phys;
+ size_t palette_size;
+ wait_queue_head_t wait;
+};
+
+static int bpp_values[] = {
+ 1,
+ 2,
+ 4,
+ 8,
+ 12,
+ 16,
+ 18,
+ 24,
+};
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c
new file mode 100644
index 000000000000..96e34a569169
--- /dev/null
+++ b/drivers/video/wm8505fb.c
@@ -0,0 +1,422 @@
+/*
+ * WonderMedia WM8505 Frame Buffer device driver
+ *
+ * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
+ * Based on vt8500lcdfb.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+
+#include <mach/vt8500fb.h>
+
+#include "wm8505fb_regs.h"
+#include "wmt_ge_rops.h"
+
+#define DRIVER_NAME "wm8505-fb"
+
+#define to_wm8505fb_info(__info) container_of(__info, \
+ struct wm8505fb_info, fb)
+struct wm8505fb_info {
+ struct fb_info fb;
+ void __iomem *regbase;
+ unsigned int contrast;
+};
+
+
+static int wm8505fb_init_hw(struct fb_info *info)
+{
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ int i;
+
+ /* I know the purpose only of few registers, so clear unknown */
+ for (i = 0; i < 0x200; i += 4)
+ writel(0, fbi->regbase + i);
+
+ /* Set frame buffer address */
+ writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR);
+ writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1);
+
+ /* Set in-memory picture format to RGB 32bpp */
+ writel(0x1c, fbi->regbase + WMT_GOVR_COLORSPACE);
+ writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1);
+
+ /* Virtual buffer size */
+ writel(info->var.xres, fbi->regbase + WMT_GOVR_XRES);
+ writel(info->var.xres_virtual, fbi->regbase + WMT_GOVR_XRES_VIRTUAL);
+
+ /* black magic ;) */
+ writel(0xf, fbi->regbase + WMT_GOVR_FHI);
+ writel(4, fbi->regbase + WMT_GOVR_DVO_SET);
+ writel(1, fbi->regbase + WMT_GOVR_MIF_ENABLE);
+ writel(1, fbi->regbase + WMT_GOVR_REG_UPDATE);
+
+ return 0;
+}
+
+static int wm8505fb_set_timing(struct fb_info *info)
+{
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ int h_start = info->var.left_margin;
+ int h_end = h_start + info->var.xres;
+ int h_all = h_end + info->var.right_margin;
+ int h_sync = info->var.hsync_len;
+
+ int v_start = info->var.upper_margin;
+ int v_end = v_start + info->var.yres;
+ int v_all = v_end + info->var.lower_margin;
+ int v_sync = info->var.vsync_len;
+
+ writel(0, fbi->regbase + WMT_GOVR_TG);
+
+ writel(h_start, fbi->regbase + WMT_GOVR_TIMING_H_START);
+ writel(h_end, fbi->regbase + WMT_GOVR_TIMING_H_END);
+ writel(h_all, fbi->regbase + WMT_GOVR_TIMING_H_ALL);
+ writel(h_sync, fbi->regbase + WMT_GOVR_TIMING_H_SYNC);
+
+ writel(v_start, fbi->regbase + WMT_GOVR_TIMING_V_START);
+ writel(v_end, fbi->regbase + WMT_GOVR_TIMING_V_END);
+ writel(v_all, fbi->regbase + WMT_GOVR_TIMING_V_ALL);
+ writel(v_sync, fbi->regbase + WMT_GOVR_TIMING_V_SYNC);
+
+ writel(1, fbi->regbase + WMT_GOVR_TG);
+
+ return 0;
+}
+
+
+static int wm8505fb_set_par(struct fb_info *info)
+{
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ if (!fbi)
+ return -EINVAL;
+
+ if (info->var.bits_per_pixel == 32) {
+ info->var.red.offset = 16;
+ info->var.red.length = 8;
+ info->var.red.msb_right = 0;
+ info->var.green.offset = 8;
+ info->var.green.length = 8;
+ info->var.green.msb_right = 0;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 8;
+ info->var.blue.msb_right = 0;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = info->var.xres_virtual << 2;
+ }
+
+ wm8505fb_set_timing(info);
+
+ writel(fbi->contrast<<16 | fbi->contrast<<8 | fbi->contrast,
+ fbi->regbase + WMT_GOVR_CONTRAST);
+
+ return 0;
+}
+
+static ssize_t contrast_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ return sprintf(buf, "%d\n", fbi->contrast);
+}
+
+static ssize_t contrast_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+ unsigned long tmp;
+
+ if (strict_strtoul(buf, 10, &tmp) || (tmp > 0xff))
+ return -EINVAL;
+ fbi->contrast = tmp;
+
+ wm8505fb_set_par(info);
+
+ return count;
+}
+
+static DEVICE_ATTR(contrast, 0644, contrast_show, contrast_store);
+
+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 wm8505fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info) {
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+ int ret = 1;
+ unsigned int val;
+ if (regno >= 256)
+ return -EINVAL;
+
+ if (info->var.grayscale)
+ red = green = blue =
+ (19595 * red + 38470 * green + 7471 * blue) >> 16;
+
+ switch (fbi->fb.fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &fbi->fb.var.red);
+ val |= chan_to_field(green, &fbi->fb.var.green);
+ val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int wm8505fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ writel(var->xoffset, fbi->regbase + WMT_GOVR_XPAN);
+ writel(var->yoffset, fbi->regbase + WMT_GOVR_YPAN);
+ return 0;
+}
+
+static int wm8505fb_blank(int blank, struct fb_info *info)
+{
+ struct wm8505fb_info *fbi = to_wm8505fb_info(info);
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ wm8505fb_set_timing(info);
+ break;
+ default:
+ writel(0, fbi->regbase + WMT_GOVR_TIMING_V_SYNC);
+ break;
+ }
+
+ return 0;
+}
+
+static struct fb_ops wm8505fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = wm8505fb_set_par,
+ .fb_setcolreg = wm8505fb_setcolreg,
+ .fb_fillrect = wmt_ge_fillrect,
+ .fb_copyarea = wmt_ge_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_sync = wmt_ge_sync,
+ .fb_pan_display = wm8505fb_pan_display,
+ .fb_blank = wm8505fb_blank,
+};
+
+static int __devinit wm8505fb_probe(struct platform_device *pdev)
+{
+ struct wm8505fb_info *fbi;
+ struct resource *res;
+ void *addr;
+ struct vt8500fb_platform_data *pdata;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+
+ ret = -ENOMEM;
+ fbi = NULL;
+
+ fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16,
+ GFP_KERNEL);
+ if (!fbi) {
+ dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ strcpy(fbi->fb.fix.id, DRIVER_NAME);
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.xpanstep = 1;
+ fbi->fb.fix.ypanstep = 1;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.fbops = &wm8505fb_ops;
+ fbi->fb.flags = FBINFO_DEFAULT
+ | FBINFO_HWACCEL_COPYAREA
+ | FBINFO_HWACCEL_FILLRECT
+ | FBINFO_HWACCEL_XPAN
+ | FBINFO_HWACCEL_YPAN
+ | FBINFO_VIRTFB
+ | FBINFO_PARTIAL_PAN_OK;
+ fbi->fb.node = -1;
+
+ addr = fbi;
+ addr = addr + sizeof(struct wm8505fb_info);
+ fbi->fb.pseudo_palette = addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto failed_fbi;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), DRIVER_NAME);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto failed_fbi;
+ }
+
+ fbi->regbase = ioremap(res->start, resource_size(res));
+ if (fbi->regbase == NULL) {
+ dev_err(&pdev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto failed_free_res;
+ }
+
+ fb_videomode_to_var(&fbi->fb.var, &pdata->mode);
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.xres_virtual = pdata->xres_virtual;
+ fbi->fb.var.yres_virtual = pdata->yres_virtual;
+ fbi->fb.var.bits_per_pixel = pdata->bpp;
+
+ fbi->fb.fix.smem_start = pdata->video_mem_phys;
+ fbi->fb.fix.smem_len = pdata->video_mem_len;
+ fbi->fb.screen_base = pdata->video_mem_virt;
+ fbi->fb.screen_size = pdata->video_mem_len;
+
+ if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
+ dev_err(&pdev->dev, "Failed to allocate color map\n");
+ ret = -ENOMEM;
+ goto failed_free_io;
+ }
+
+ wm8505fb_init_hw(&fbi->fb);
+
+ fbi->contrast = 0x80;
+ ret = wm8505fb_set_par(&fbi->fb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set parameters\n");
+ goto failed_free_cmap;
+ }
+
+ platform_set_drvdata(pdev, fbi);
+
+ ret = register_framebuffer(&fbi->fb);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Failed to register framebuffer device: %d\n", ret);
+ goto failed_free_cmap;
+ }
+
+ ret = device_create_file(&pdev->dev, &dev_attr_contrast);
+ if (ret < 0) {
+ printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n",
+ fbi->fb.node, ret);
+ }
+
+ printk(KERN_INFO "fb%d: %s frame buffer at 0x%lx-0x%lx\n",
+ fbi->fb.node, fbi->fb.fix.id, fbi->fb.fix.smem_start,
+ fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);
+
+ return 0;
+
+failed_free_cmap:
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
+failed_free_io:
+ iounmap(fbi->regbase);
+failed_free_res:
+ release_mem_region(res->start, resource_size(res));
+failed_fbi:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fbi);
+failed:
+ return ret;
+}
+
+static int __devexit wm8505fb_remove(struct platform_device *pdev)
+{
+ struct wm8505fb_info *fbi = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ device_remove_file(&pdev->dev, &dev_attr_contrast);
+
+ unregister_framebuffer(&fbi->fb);
+
+ writel(0, fbi->regbase);
+
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
+
+ iounmap(fbi->regbase);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(fbi);
+
+ return 0;
+}
+
+static struct platform_driver wm8505fb_driver = {
+ .probe = wm8505fb_probe,
+ .remove = __devexit_p(wm8505fb_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init wm8505fb_init(void)
+{
+ return platform_driver_register(&wm8505fb_driver);
+}
+
+static void __exit wm8505fb_exit(void)
+{
+ platform_driver_unregister(&wm8505fb_driver);
+}
+
+module_init(wm8505fb_init);
+module_exit(wm8505fb_exit);
+
+MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>");
+MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/wm8505fb_regs.h b/drivers/video/wm8505fb_regs.h
new file mode 100644
index 000000000000..4dd41668c6d1
--- /dev/null
+++ b/drivers/video/wm8505fb_regs.h
@@ -0,0 +1,76 @@
+/*
+ * GOVR registers list for WM8505 chips
+ *
+ * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
+ * Based on VIA/WonderMedia wm8510-govrh-reg.h
+ * http://github.com/projectgus/kernel_wm8505/blob/wm8505_2.6.29/
+ * drivers/video/wmt/register/wm8510/wm8510-govrh-reg.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WM8505FB_REGS_H
+#define _WM8505FB_REGS_H
+
+/*
+ * Color space select register, default value 0x1c
+ * BIT0 GOVRH_DVO_YUV2RGB_ENABLE
+ * BIT1 GOVRH_VGA_YUV2RGB_ENABLE
+ * BIT2 GOVRH_RGB_MODE
+ * BIT3 GOVRH_DAC_CLKINV
+ * BIT4 GOVRH_BLANK_ZERO
+ */
+#define WMT_GOVR_COLORSPACE 0x1e4
+/*
+ * Another colorspace select register, default value 1
+ * BIT0 GOVRH_DVO_RGB
+ * BIT1 GOVRH_DVO_YUV422
+ */
+#define WMT_GOVR_COLORSPACE1 0x30
+
+#define WMT_GOVR_CONTRAST 0x1b8
+#define WMT_GOVR_BRGHTNESS 0x1bc /* incompatible with RGB? */
+
+/* Framubeffer address */
+#define WMT_GOVR_FBADDR 0x90
+#define WMT_GOVR_FBADDR1 0x94 /* UV offset in YUV mode */
+
+/* Offset of visible window */
+#define WMT_GOVR_XPAN 0xa4
+#define WMT_GOVR_YPAN 0xa0
+
+#define WMT_GOVR_XRES 0x98
+#define WMT_GOVR_XRES_VIRTUAL 0x9c
+
+#define WMT_GOVR_MIF_ENABLE 0x80
+#define WMT_GOVR_FHI 0xa8
+#define WMT_GOVR_REG_UPDATE 0xe4
+
+/*
+ * BIT0 GOVRH_DVO_OUTWIDTH
+ * BIT1 GOVRH_DVO_SYNC_POLAR
+ * BIT2 GOVRH_DVO_ENABLE
+ */
+#define WMT_GOVR_DVO_SET 0x148
+
+/* Timing generator? */
+#define WMT_GOVR_TG 0x100
+
+/* Timings */
+#define WMT_GOVR_TIMING_H_ALL 0x108
+#define WMT_GOVR_TIMING_V_ALL 0x10c
+#define WMT_GOVR_TIMING_V_START 0x110
+#define WMT_GOVR_TIMING_V_END 0x114
+#define WMT_GOVR_TIMING_H_START 0x118
+#define WMT_GOVR_TIMING_H_END 0x11c
+#define WMT_GOVR_TIMING_V_SYNC 0x128
+#define WMT_GOVR_TIMING_H_SYNC 0x12c
+
+#endif /* _WM8505FB_REGS_H */
diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c
new file mode 100644
index 000000000000..45832b7ef7d2
--- /dev/null
+++ b/drivers/video/wmt_ge_rops.c
@@ -0,0 +1,186 @@
+/*
+ * linux/drivers/video/wmt_ge_rops.c
+ *
+ * Accelerators for raster operations using WonderMedia Graphics Engine
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include "fb_draw.h"
+
+#define GE_COMMAND_OFF 0x00
+#define GE_DEPTH_OFF 0x04
+#define GE_HIGHCOLOR_OFF 0x08
+#define GE_ROPCODE_OFF 0x14
+#define GE_FIRE_OFF 0x18
+#define GE_SRCBASE_OFF 0x20
+#define GE_SRCDISPW_OFF 0x24
+#define GE_SRCDISPH_OFF 0x28
+#define GE_SRCAREAX_OFF 0x2c
+#define GE_SRCAREAY_OFF 0x30
+#define GE_SRCAREAW_OFF 0x34
+#define GE_SRCAREAH_OFF 0x38
+#define GE_DESTBASE_OFF 0x3c
+#define GE_DESTDISPW_OFF 0x40
+#define GE_DESTDISPH_OFF 0x44
+#define GE_DESTAREAX_OFF 0x48
+#define GE_DESTAREAY_OFF 0x4c
+#define GE_DESTAREAW_OFF 0x50
+#define GE_DESTAREAH_OFF 0x54
+#define GE_PAT0C_OFF 0x88 /* Pattern 0 color */
+#define GE_ENABLE_OFF 0xec
+#define GE_INTEN_OFF 0xf0
+#define GE_STATUS_OFF 0xf8
+
+static void __iomem *regbase;
+
+void wmt_ge_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+ unsigned long fg, pat;
+
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR)
+ fg = ((u32 *) (p->pseudo_palette))[rect->color];
+ else
+ fg = rect->color;
+
+ pat = pixel_to_pat(p->var.bits_per_pixel, fg);
+
+ if (p->fbops->fb_sync)
+ p->fbops->fb_sync(p);
+
+ writel(p->var.bits_per_pixel == 32 ? 3 :
+ (p->var.bits_per_pixel == 8 ? 0 : 1), regbase + GE_DEPTH_OFF);
+ writel(p->var.bits_per_pixel == 15 ? 1 : 0, regbase + GE_HIGHCOLOR_OFF);
+ writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF);
+ writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF);
+ writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF);
+ writel(rect->dx, regbase + GE_DESTAREAX_OFF);
+ writel(rect->dy, regbase + GE_DESTAREAY_OFF);
+ writel(rect->width - 1, regbase + GE_DESTAREAW_OFF);
+ writel(rect->height - 1, regbase + GE_DESTAREAH_OFF);
+
+ writel(pat, regbase + GE_PAT0C_OFF);
+ writel(1, regbase + GE_COMMAND_OFF);
+ writel(rect->rop == ROP_XOR ? 0x5a : 0xf0, regbase + GE_ROPCODE_OFF);
+ writel(1, regbase + GE_FIRE_OFF);
+}
+EXPORT_SYMBOL_GPL(wmt_ge_fillrect);
+
+void wmt_ge_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
+ if (p->fbops->fb_sync)
+ p->fbops->fb_sync(p);
+
+ writel(p->var.bits_per_pixel > 16 ? 3 :
+ (p->var.bits_per_pixel > 8 ? 1 : 0), regbase + GE_DEPTH_OFF);
+
+ writel(p->fix.smem_start, regbase + GE_SRCBASE_OFF);
+ writel(p->var.xres_virtual - 1, regbase + GE_SRCDISPW_OFF);
+ writel(p->var.yres_virtual - 1, regbase + GE_SRCDISPH_OFF);
+ writel(area->sx, regbase + GE_SRCAREAX_OFF);
+ writel(area->sy, regbase + GE_SRCAREAY_OFF);
+ writel(area->width - 1, regbase + GE_SRCAREAW_OFF);
+ writel(area->height - 1, regbase + GE_SRCAREAH_OFF);
+
+ writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF);
+ writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF);
+ writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF);
+ writel(area->dx, regbase + GE_DESTAREAX_OFF);
+ writel(area->dy, regbase + GE_DESTAREAY_OFF);
+ writel(area->width - 1, regbase + GE_DESTAREAW_OFF);
+ writel(area->height - 1, regbase + GE_DESTAREAH_OFF);
+
+ writel(0xcc, regbase + GE_ROPCODE_OFF);
+ writel(1, regbase + GE_COMMAND_OFF);
+ writel(1, regbase + GE_FIRE_OFF);
+}
+EXPORT_SYMBOL_GPL(wmt_ge_copyarea);
+
+int wmt_ge_sync(struct fb_info *p)
+{
+ int loops = 5000000;
+ while ((readl(regbase + GE_STATUS_OFF) & 4) && --loops)
+ cpu_relax();
+ return loops > 0 ? 0 : -EBUSY;
+}
+EXPORT_SYMBOL_GPL(wmt_ge_sync);
+
+static int __devinit wmt_ge_rops_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no I/O memory resource defined\n");
+ return -ENODEV;
+ }
+
+ /* Only one ROP engine is presently supported. */
+ if (unlikely(regbase)) {
+ WARN_ON(1);
+ return -EBUSY;
+ }
+
+ regbase = ioremap(res->start, resource_size(res));
+ if (regbase == NULL) {
+ dev_err(&pdev->dev, "failed to map I/O memory\n");
+ return -EBUSY;
+ }
+
+ writel(1, regbase + GE_ENABLE_OFF);
+ printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n");
+
+ return 0;
+}
+
+static int __devexit wmt_ge_rops_remove(struct platform_device *pdev)
+{
+ iounmap(regbase);
+ return 0;
+}
+
+static struct platform_driver wmt_ge_rops_driver = {
+ .probe = wmt_ge_rops_probe,
+ .remove = __devexit_p(wmt_ge_rops_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wmt_ge_rops",
+ },
+};
+
+static int __init wmt_ge_rops_init(void)
+{
+ return platform_driver_register(&wmt_ge_rops_driver);
+}
+
+static void __exit wmt_ge_rops_exit(void)
+{
+ platform_driver_unregister(&wmt_ge_rops_driver);
+}
+
+module_init(wmt_ge_rops_init);
+module_exit(wmt_ge_rops_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com");
+MODULE_DESCRIPTION("Accelerators for raster operations using "
+ "WonderMedia Graphics Engine");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/wmt_ge_rops.h b/drivers/video/wmt_ge_rops.h
new file mode 100644
index 000000000000..87380751a443
--- /dev/null
+++ b/drivers/video/wmt_ge_rops.h
@@ -0,0 +1,5 @@
+extern void wmt_ge_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect);
+extern void wmt_ge_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area);
+extern int wmt_ge_sync(struct fb_info *info);
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 428d273be727..3e6934d4bea8 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -492,7 +492,7 @@ xenfb_make_preferred_console(void)
return;
acquire_console_sem();
- for (c = console_drivers; c; c = c->next) {
+ for_each_console(c) {
if (!strcmp(c->name, "tty") && c->index == 0)
break;
}
@@ -562,26 +562,24 @@ static void xenfb_init_shared_page(struct xenfb_info *info,
static int xenfb_connect_backend(struct xenbus_device *dev,
struct xenfb_info *info)
{
- int ret, evtchn;
+ int ret, evtchn, irq;
struct xenbus_transaction xbt;
ret = xenbus_alloc_evtchn(dev, &evtchn);
if (ret)
return ret;
- ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
+ irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
0, dev->devicetype, info);
- if (ret < 0) {
+ if (irq < 0) {
xenbus_free_evtchn(dev, evtchn);
xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
- return ret;
+ return irq;
}
- info->irq = ret;
-
again:
ret = xenbus_transaction_start(&xbt);
if (ret) {
xenbus_dev_fatal(dev, ret, "starting transaction");
- return ret;
+ goto unbind_irq;
}
ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
virt_to_mfn(info->page));
@@ -603,20 +601,25 @@ static int xenfb_connect_backend(struct xenbus_device *dev,
if (ret == -EAGAIN)
goto again;
xenbus_dev_fatal(dev, ret, "completing transaction");
- return ret;
+ goto unbind_irq;
}
xenbus_switch_state(dev, XenbusStateInitialised);
+ info->irq = irq;
return 0;
error_xenbus:
xenbus_transaction_end(xbt, 1);
xenbus_dev_fatal(dev, ret, "writing xenstore");
+ unbind_irq:
+ unbind_from_irqhandler(irq, info);
return ret;
}
static void xenfb_disconnect_backend(struct xenfb_info *info)
{
+ /* Prevent xenfb refresh */
+ info->update_wanted = 0;
if (info->irq >= 0)
unbind_from_irqhandler(info->irq, info);
info->irq = -1;
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 3a43ebf83a49..efb35aa8309a 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -9,19 +9,19 @@ static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "%hu", dev->id.device);
+ return sprintf(buf, "0x%04x\n", dev->id.device);
}
static ssize_t vendor_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "%hu", dev->id.vendor);
+ return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static ssize_t status_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
- return sprintf(buf, "0x%08x", dev->config->get_status(dev));
+ return sprintf(buf, "0x%08x\n", dev->config->get_status(dev));
}
static ssize_t modalias_show(struct device *_d,
struct device_attribute *attr, char *buf)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 1475ed6b575f..cc2f73e03475 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -230,9 +230,6 @@ add_head:
pr_debug("Added buffer head %i to %p\n", head, vq);
END_USE(vq);
- /* If we're indirect, we can fit many (assuming not OOM). */
- if (vq->indirect)
- return vq->num_free ? vq->vring.num : 0;
return vq->num_free;
}
EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 1f51366417b9..f0c909625bd1 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -16,6 +16,17 @@ config W1_SLAVE_SMEM
Say Y here if you want to connect 1-wire
simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
+config W1_SLAVE_DS2423
+ tristate "Counter 1-wire device (DS2423)"
+ select CRC16
+ help
+ If you enable this you can read the counter values available
+ in the DS2423 chipset from the w1_slave file under the
+ sys file system.
+
+ Say Y here if you want to use a 1-wire
+ counter family device (DS2423).
+
config W1_SLAVE_DS2431
tristate "1kb EEPROM family support (DS2431)"
help
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index f1f51f19b129..3c76350a24f7 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o
obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o
+obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o
obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o
obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c
new file mode 100644
index 000000000000..7a7dbe5026f1
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2423.c
@@ -0,0 +1,166 @@
+/*
+ * w1_ds2423.c
+ *
+ * Copyright (c) 2010 Mika Laitio <lamikr@pilppa.org>
+ *
+ * This driver will read and write the value of 4 counters to w1_slave file in
+ * sys filesystem.
+ * Inspired by the w1_therm and w1_ds2431 drivers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/crc16.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define CRC16_VALID 0xb001
+#define CRC16_INIT 0
+
+#define COUNTER_COUNT 4
+#define READ_BYTE_COUNT 42
+
+static ssize_t w1_counter_read(struct device *device,
+ struct device_attribute *attr, char *buf);
+
+static struct device_attribute w1_counter_attr =
+ __ATTR(w1_slave, S_IRUGO, w1_counter_read, NULL);
+
+static ssize_t w1_counter_read(struct device *device,
+ struct device_attribute *attr, char *out_buf)
+{
+ struct w1_slave *sl = dev_to_w1_slave(device);
+ struct w1_master *dev = sl->master;
+ u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT];
+ u8 wrbuf[3];
+ int rom_addr;
+ int read_byte_count;
+ int result;
+ ssize_t c;
+ int ii;
+ int p;
+ int crc;
+
+ c = PAGE_SIZE;
+ rom_addr = (12 << 5) + 31;
+ wrbuf[0] = 0xA5;
+ wrbuf[1] = rom_addr & 0xFF;
+ wrbuf[2] = rom_addr >> 8;
+ mutex_lock(&dev->mutex);
+ if (!w1_reset_select_slave(sl)) {
+ w1_write_block(dev, wrbuf, 3);
+ read_byte_count = 0;
+ for (p = 0; p < 4; p++) {
+ /*
+ * 1 byte for first bytes in ram page read
+ * 4 bytes for counter
+ * 4 bytes for zero bits
+ * 2 bytes for crc
+ * 31 remaining bytes from the ram page
+ */
+ read_byte_count += w1_read_block(dev,
+ rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT);
+ for (ii = 0; ii < READ_BYTE_COUNT; ++ii)
+ c -= snprintf(out_buf + PAGE_SIZE - c,
+ c, "%02x ",
+ rbuf[(p * READ_BYTE_COUNT) + ii]);
+ if (read_byte_count != (p + 1) * READ_BYTE_COUNT) {
+ dev_warn(device,
+ "w1_counter_read() returned %u bytes "
+ "instead of %d bytes wanted.\n",
+ read_byte_count,
+ READ_BYTE_COUNT);
+ c -= snprintf(out_buf + PAGE_SIZE - c,
+ c, "crc=NO\n");
+ } else {
+ if (p == 0) {
+ crc = crc16(CRC16_INIT, wrbuf, 3);
+ crc = crc16(crc, rbuf, 11);
+ } else {
+ /*
+ * DS2423 calculates crc from all bytes
+ * read after the previous crc bytes.
+ */
+ crc = crc16(CRC16_INIT,
+ (rbuf + 11) +
+ ((p - 1) * READ_BYTE_COUNT),
+ READ_BYTE_COUNT);
+ }
+ if (crc == CRC16_VALID) {
+ result = 0;
+ for (ii = 4; ii > 0; ii--) {
+ result <<= 8;
+ result |= rbuf[(p *
+ READ_BYTE_COUNT) + ii];
+ }
+ c -= snprintf(out_buf + PAGE_SIZE - c,
+ c, "crc=YES c=%d\n", result);
+ } else {
+ c -= snprintf(out_buf + PAGE_SIZE - c,
+ c, "crc=NO\n");
+ }
+ }
+ }
+ } else {
+ c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");
+ }
+ mutex_unlock(&dev->mutex);
+ return PAGE_SIZE - c;
+}
+
+static int w1_f1d_add_slave(struct w1_slave *sl)
+{
+ return device_create_file(&sl->dev, &w1_counter_attr);
+}
+
+static void w1_f1d_remove_slave(struct w1_slave *sl)
+{
+ device_remove_file(&sl->dev, &w1_counter_attr);
+}
+
+static struct w1_family_ops w1_f1d_fops = {
+ .add_slave = w1_f1d_add_slave,
+ .remove_slave = w1_f1d_remove_slave,
+};
+
+static struct w1_family w1_family_1d = {
+ .fid = W1_COUNTER_DS2423,
+ .fops = &w1_f1d_fops,
+};
+
+static int __init w1_f1d_init(void)
+{
+ return w1_register_family(&w1_family_1d);
+}
+
+static void __exit w1_f1d_exit(void)
+{
+ w1_unregister_family(&w1_family_1d);
+}
+
+module_init(w1_f1d_init);
+module_exit(w1_f1d_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>");
+MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram");
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 3ca1b9298f21..f3b636d7cafe 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -30,6 +30,7 @@
#define W1_FAMILY_SMEM_01 0x01
#define W1_FAMILY_SMEM_81 0x81
#define W1_THERM_DS18S20 0x10
+#define W1_COUNTER_DS2423 0x1D
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
#define W1_THERM_DS18B20 0x28
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4a291045ebac..2e2400e7322e 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -409,15 +409,26 @@ config ALIM7101_WDT
Most people will say N.
config F71808E_WDT
- tristate "Fintek F71808E, F71882FG and F71889FG Watchdog"
+ tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
depends on X86 && EXPERIMENTAL
help
This is the driver for the hardware watchdog on the Fintek
- F71808E, F71882FG and F71889FG Super I/O controllers.
+ F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
You can compile this driver directly into the kernel, or use
it as a module. The module will be called f71808e_wdt.
+config SP5100_TCO
+ tristate "AMD/ATI SP5100 TCO Timer/Watchdog"
+ depends on X86 && PCI
+ ---help---
+ Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO
+ (Total Cost of Ownership) timer is a watchdog timer that will reboot
+ the machine after its expiration. The expiration time can be
+ configured with the "heartbeat" parameter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sp5100_tco.
config GEODE_WDT
tristate "AMD Geode CS5535/CS5536 Watchdog"
@@ -558,6 +569,9 @@ config IT8712F_WDT
This is the driver for the built-in watchdog timer on the IT8712F
Super I/0 chipset used on many motherboards.
+ If the driver does not work, then make sure that the game port in
+ the BIOS is enabled.
+
To compile this driver as a module, choose M here: the
module will be called it8712f_wdt.
@@ -628,6 +642,24 @@ config PC87413_WDT
Most people will say N.
+config NV_TCO
+ tristate "nVidia TCO Timer/Watchdog"
+ depends on X86 && PCI
+ ---help---
+ Hardware driver for the TCO timer built into the nVidia Hub family
+ (such as the MCP51). The TCO (Total Cost of Ownership) timer is a
+ watchdog timer that will reboot the machine after its second
+ expiration. The expiration time can be configured with the
+ "heartbeat" parameter.
+
+ On some motherboards the driver may fail to reset the chipset's
+ NO_REBOOT flag which prevents the watchdog from rebooting the
+ machine. If this is the case you will get a kernel message like
+ "failed to reset NO_REBOOT flag, reboot disabled by hardware".
+
+ To compile this driver as a module, choose M here: the
+ module will be called nv_tco.
+
config RDC321X_WDT
tristate "RDC R-321x SoC watchdog"
depends on X86_RDC321X
@@ -719,14 +751,15 @@ config SMSC37B787_WDT
Most people will say N.
config W83627HF_WDT
- tristate "W83627HF Watchdog Timer"
+ tristate "W83627HF/W83627DHG Watchdog Timer"
depends on X86
---help---
This is the driver for the hardware watchdog on the W83627HF chipset
as used in Advantech PC-9578 and Tyan S2721-533 motherboards
- (and likely others). This watchdog simply watches your kernel to
- make sure it doesn't freeze, and if it does, it reboots your computer
- after a certain amount of time.
+ (and likely others). The driver also supports the W83627DHG chip.
+ This watchdog simply watches your kernel to make sure it doesn't
+ freeze, and if it does, it reboots your computer after a certain
+ amount of time.
To compile this driver as a module, choose M here: the
module will be called w83627hf_wdt.
@@ -829,10 +862,22 @@ config SBC_EPX_C3_WATCHDOG
# M68K Architecture
-# M68KNOMMU Architecture
+config M548x_WATCHDOG
+ tristate "MCF548x watchdog support"
+ depends on M548x
+ help
+ To compile this driver as a module, choose M here: the
+ module will be called m548x_wdt.
# MIPS Architecture
+config ATH79_WDT
+ tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog"
+ depends on ATH79
+ help
+ Hardware driver for the built-in watchdog timer on the Atheros
+ AR71XX/AR724X/AR913X SoCs.
+
config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
depends on BCM47XX
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 4b0ef386229d..dd776651917c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
+obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o
obj-$(CONFIG_GEODE_WDT) += geodewdt.o
obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o
@@ -86,6 +87,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
+obj-$(CONFIG_NV_TCO) += nv_tco.o
obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
@@ -104,10 +106,10 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
# M32R Architecture
# M68K Architecture
-
-# M68KNOMMU Architecture
+obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o
# MIPS Architecture
+obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index 1e9caea8ff8a..fa4d36033552 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
* want to register another driver on the same PCI id.
*/
-static struct pci_device_id ali_pci_tbl[] = {
+static struct pci_device_id ali_pci_tbl[] __used = {
{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index d8d4da9a483d..4b7a2b4138ed 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -430,7 +430,7 @@ err_out:
module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
-static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
+static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
new file mode 100644
index 000000000000..725c84bfdd76
--- /dev/null
+++ b/drivers/watchdog/ath79_wdt.c
@@ -0,0 +1,305 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer.
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This driver was based on: drivers/watchdog/ixp4xx_wdt.c
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * which again was based on sa1100 driver,
+ * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * 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/bitops.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#define DRIVER_NAME "ath79-wdt"
+
+#define WDT_TIMEOUT 15 /* seconds */
+
+#define WDOG_CTRL_LAST_RESET BIT(31)
+#define WDOG_CTRL_ACTION_MASK 3
+#define WDOG_CTRL_ACTION_NONE 0 /* no action */
+#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */
+#define WDOG_CTRL_ACTION_NMI 2 /* NMI */
+#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */
+
+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 int timeout = WDT_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
+ "(default=" __MODULE_STRING(WDT_TIMEOUT) "s)");
+
+static unsigned long wdt_flags;
+
+#define WDT_FLAGS_BUSY 0
+#define WDT_FLAGS_EXPECT_CLOSE 1
+
+static struct clk *wdt_clk;
+static unsigned long wdt_freq;
+static int boot_status;
+static int max_timeout;
+
+static inline void ath79_wdt_keepalive(void)
+{
+ ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout);
+}
+
+static inline void ath79_wdt_enable(void)
+{
+ ath79_wdt_keepalive();
+ ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
+}
+
+static inline void ath79_wdt_disable(void)
+{
+ ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE);
+}
+
+static int ath79_wdt_set_timeout(int val)
+{
+ if (val < 1 || val > max_timeout)
+ return -EINVAL;
+
+ timeout = val;
+ ath79_wdt_keepalive();
+
+ return 0;
+}
+
+static int ath79_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
+ return -EBUSY;
+
+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
+ ath79_wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static int ath79_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
+ ath79_wdt_disable();
+ else {
+ pr_crit(DRIVER_NAME ": device closed unexpectedly, "
+ "watchdog timer will not stop!\n");
+ ath79_wdt_keepalive();
+ }
+
+ clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
+
+ return 0;
+}
+
+static ssize_t ath79_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+
+ if (c == 'V')
+ set_bit(WDT_FLAGS_EXPECT_CLOSE,
+ &wdt_flags);
+ }
+ }
+
+ ath79_wdt_keepalive();
+ }
+
+ return len;
+}
+
+static const struct watchdog_info ath79_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
+ .firmware_version = 0,
+ .identity = "ATH79 watchdog",
+};
+
+static long ath79_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int err;
+ int t;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ err = copy_to_user(argp, &ath79_wdt_info,
+ sizeof(ath79_wdt_info)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ err = put_user(0, p);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ err = put_user(boot_status, p);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ ath79_wdt_keepalive();
+ err = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ err = get_user(t, p);
+ if (err)
+ break;
+
+ err = ath79_wdt_set_timeout(t);
+ if (err)
+ break;
+
+ /* fallthrough */
+ case WDIOC_GETTIMEOUT:
+ err = put_user(timeout, p);
+ break;
+
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ return err;
+}
+
+static const struct file_operations ath79_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = ath79_wdt_write,
+ .unlocked_ioctl = ath79_wdt_ioctl,
+ .open = ath79_wdt_open,
+ .release = ath79_wdt_release,
+};
+
+static struct miscdevice ath79_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ath79_wdt_fops,
+};
+
+static int __devinit ath79_wdt_probe(struct platform_device *pdev)
+{
+ u32 ctrl;
+ int err;
+
+ wdt_clk = clk_get(&pdev->dev, "wdt");
+ if (IS_ERR(wdt_clk))
+ return PTR_ERR(wdt_clk);
+
+ err = clk_enable(wdt_clk);
+ if (err)
+ goto err_clk_put;
+
+ wdt_freq = clk_get_rate(wdt_clk);
+ if (!wdt_freq) {
+ err = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ max_timeout = (0xfffffffful / wdt_freq);
+ if (timeout < 1 || timeout > max_timeout) {
+ timeout = max_timeout;
+ dev_info(&pdev->dev,
+ "timeout value must be 0 < timeout < %d, using %d\n",
+ max_timeout, timeout);
+ }
+
+ ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL);
+ boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;
+
+ err = misc_register(&ath79_wdt_miscdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "unable to register misc device, err=%d\n", err);
+ goto err_clk_disable;
+ }
+
+ return 0;
+
+err_clk_disable:
+ clk_disable(wdt_clk);
+err_clk_put:
+ clk_put(wdt_clk);
+ return err;
+}
+
+static int __devexit ath79_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&ath79_wdt_miscdev);
+ clk_disable(wdt_clk);
+ clk_put(wdt_clk);
+ return 0;
+}
+
+static void ath97_wdt_shutdown(struct platform_device *pdev)
+{
+ ath79_wdt_disable();
+}
+
+static struct platform_driver ath79_wdt_driver = {
+ .remove = __devexit_p(ath79_wdt_remove),
+ .shutdown = ath97_wdt_shutdown,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ath79_wdt_init(void)
+{
+ return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
+}
+module_init(ath79_wdt_init);
+
+static void __exit ath79_wdt_exit(void)
+{
+ platform_driver_unregister(&ath79_wdt_driver);
+}
+module_exit(ath79_wdt_exit);
+
+MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
+MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
index a1debc89356b..3c5045a206dd 100644
--- a/drivers/watchdog/bcm63xx_wdt.c
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -18,7 +18,6 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
@@ -220,14 +219,6 @@ static long bcm63xx_wdt_ioctl(struct file *file, unsigned int cmd,
}
}
-static int bcm63xx_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- bcm63xx_wdt_pause();
- return NOTIFY_DONE;
-}
-
static const struct file_operations bcm63xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -243,12 +234,8 @@ static struct miscdevice bcm63xx_wdt_miscdev = {
.fops = &bcm63xx_wdt_fops,
};
-static struct notifier_block bcm63xx_wdt_notifier = {
- .notifier_call = bcm63xx_wdt_notify_sys,
-};
-
-static int bcm63xx_wdt_probe(struct platform_device *pdev)
+static int __devinit bcm63xx_wdt_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
@@ -280,16 +267,10 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
wdt_time);
}
- ret = register_reboot_notifier(&bcm63xx_wdt_notifier);
- if (ret) {
- dev_err(&pdev->dev, "failed to register reboot_notifier\n");
- goto unregister_timer;
- }
-
ret = misc_register(&bcm63xx_wdt_miscdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register watchdog device\n");
- goto unregister_reboot_notifier;
+ goto unregister_timer;
}
dev_info(&pdev->dev, " started, timer margin: %d sec\n",
@@ -297,8 +278,6 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
return 0;
-unregister_reboot_notifier:
- unregister_reboot_notifier(&bcm63xx_wdt_notifier);
unregister_timer:
bcm63xx_timer_unregister(TIMER_WDT_ID);
unmap:
@@ -306,25 +285,28 @@ unmap:
return ret;
}
-static int bcm63xx_wdt_remove(struct platform_device *pdev)
+static int __devexit bcm63xx_wdt_remove(struct platform_device *pdev)
{
if (!nowayout)
bcm63xx_wdt_pause();
misc_deregister(&bcm63xx_wdt_miscdev);
-
- iounmap(bcm63xx_wdt_device.regs);
-
- unregister_reboot_notifier(&bcm63xx_wdt_notifier);
bcm63xx_timer_unregister(TIMER_WDT_ID);
-
+ iounmap(bcm63xx_wdt_device.regs);
return 0;
}
+static void bcm63xx_wdt_shutdown(struct platform_device *pdev)
+{
+ bcm63xx_wdt_pause();
+}
+
static struct platform_driver bcm63xx_wdt = {
.probe = bcm63xx_wdt_probe,
- .remove = bcm63xx_wdt_remove,
+ .remove = __devexit_p(bcm63xx_wdt_remove),
+ .shutdown = bcm63xx_wdt_shutdown,
.driver = {
+ .owner = THIS_MODULE,
.name = "bcm63xx-wdt",
}
};
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index d11ffb091b0d..7e7ec9c35b6a 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -85,6 +85,22 @@ static unsigned int sec_to_period(unsigned int secs)
return 0;
}
+static void __booke_wdt_set(void *data)
+{
+ u32 val;
+
+ val = mfspr(SPRN_TCR);
+ val &= ~WDTP_MASK;
+ val |= WDTP(booke_wdt_period);
+
+ mtspr(SPRN_TCR, val);
+}
+
+static void booke_wdt_set(void)
+{
+ on_each_cpu(__booke_wdt_set, NULL, 0);
+}
+
static void __booke_wdt_ping(void *data)
{
mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
@@ -181,8 +197,7 @@ static long booke_wdt_ioctl(struct file *file,
#else
booke_wdt_period = tmp;
#endif
- mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) |
- WDTP(booke_wdt_period));
+ booke_wdt_set();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
@@ -193,8 +208,15 @@ static long booke_wdt_ioctl(struct file *file,
return 0;
}
+/* wdt_is_active stores wether or not the /dev/watchdog device is opened */
+static unsigned long wdt_is_active;
+
static int booke_wdt_open(struct inode *inode, struct file *file)
{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &wdt_is_active))
+ return -EBUSY;
+
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
@@ -210,8 +232,17 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
static int booke_wdt_release(struct inode *inode, struct file *file)
{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ /* Normally, the watchdog is disabled when /dev/watchdog is closed, but
+ * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the
+ * watchdog should remain enabled. So we disable it only if
+ * CONFIG_WATCHDOG_NOWAYOUT is not defined.
+ */
on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0;
+#endif
+
+ clear_bit(0, &wdt_is_active);
return 0;
}
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 65e579635dba..d4d8d1fdccc4 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -42,18 +42,21 @@
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
#define SIO_REG_DEVREV 0x22 /* Device revision */
#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
+#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */
+#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */
+#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */
+#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
-#define SIO_F71808_ID 0x0901 /* Chipset ID */
-#define SIO_F71858_ID 0x0507 /* Chipset ID */
+#define SIO_F71808_ID 0x0901 /* Chipset ID */
+#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
+#define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
-#define F71882FG_REG_START 0x01
-
#define F71808FG_REG_WDO_CONF 0xf0
#define F71808FG_REG_WDT_CONF 0xf5
#define F71808FG_REG_WD_TIME 0xf6
@@ -70,13 +73,15 @@
#define WATCHDOG_MAX_TIMEOUT (60 * 255)
#define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for
watchdog signal */
+#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output
+ pin number 63 */
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
static const int max_timeout = WATCHDOG_MAX_TIMEOUT;
-static int timeout = 60; /* default timeout in seconds */
+static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <="
@@ -89,6 +94,12 @@ MODULE_PARM_DESC(pulse_width,
"Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
+static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
+module_param(f71862fg_pin, uint, 0);
+MODULE_PARM_DESC(f71862fg_pin,
+ "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
+ " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
+
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0444);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
@@ -98,12 +109,13 @@ module_param(start_withtimeout, uint, 0);
MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
" given initial timeout. Zero (default) disables this feature.");
-enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg };
+enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg };
static const char *f71808e_names[] = {
"f71808fg",
"f71858fg",
"f71862fg",
+ "f71869",
"f71882fg",
"f71889fg",
};
@@ -282,6 +294,28 @@ exit_unlock:
return err;
}
+static int f71862fg_pin_configure(unsigned short ioaddr)
+{
+ /* When ioaddr is non-zero the calling function has to take care of
+ mutex handling and superio preparation! */
+
+ if (f71862fg_pin == 63) {
+ if (ioaddr) {
+ /* SPI must be disabled first to use this pin! */
+ superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6);
+ superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4);
+ }
+ } else if (f71862fg_pin == 56) {
+ if (ioaddr)
+ superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
+ } else {
+ printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
+ f71862fg_pin);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int watchdog_start(void)
{
/* Make sure we don't die as soon as the watchdog is enabled below */
@@ -299,19 +333,30 @@ static int watchdog_start(void)
switch (watchdog.type) {
case f71808fg:
/* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
- superio_clear_bit(watchdog.sioaddr, 0x2a, 3);
- superio_clear_bit(watchdog.sioaddr, 0x2b, 3);
+ superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3);
+ superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3);
+ break;
+
+ case f71862fg:
+ err = f71862fg_pin_configure(watchdog.sioaddr);
+ if (err)
+ goto exit_superio;
+ break;
+
+ case f71869:
+ /* GPIO14 --> WDTRST# */
+ superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
break;
case f71882fg:
/* Set pin 56 to WDTRST# */
- superio_set_bit(watchdog.sioaddr, 0x29, 1);
+ superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1);
break;
case f71889fg:
/* set pin 40 to WDTRST# */
- superio_outb(watchdog.sioaddr, 0x2b,
- superio_inb(watchdog.sioaddr, 0x2b) & 0xcf);
+ superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3,
+ superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf);
break;
default:
@@ -711,16 +756,19 @@ static int __init f71808e_find(int sioaddr)
case SIO_F71808_ID:
watchdog.type = f71808fg;
break;
+ case SIO_F71862_ID:
+ watchdog.type = f71862fg;
+ err = f71862fg_pin_configure(0); /* validate module parameter */
+ break;
+ case SIO_F71869_ID:
+ watchdog.type = f71869;
+ break;
case SIO_F71882_ID:
watchdog.type = f71882fg;
break;
case SIO_F71889_ID:
watchdog.type = f71889fg;
break;
- case SIO_F71862_ID:
- /* These have a watchdog, though it isn't implemented (yet). */
- err = -ENOSYS;
- goto exit;
case SIO_F71858_ID:
/* Confirmed (by datasheet) not to have a watchdog. */
err = -ENODEV;
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index 9c21d19043a6..f6bd6f10fcec 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
+#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/io.h>
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 3d77116e4634..24b966d5061a 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -469,7 +469,7 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
unsigned long rom_pl;
static int die_nmi_called;
- if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI)
+ if (ulReason != DIE_NMIUNKNOWN)
goto out;
if (!hpwdt_nmi_decoding)
@@ -642,19 +642,14 @@ static struct notifier_block die_notifier = {
*/
#ifdef CONFIG_HPWDT_NMI_DECODING
-#ifdef ARCH_HAS_NMI_WATCHDOG
+#ifdef CONFIG_X86_LOCAL_APIC
static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
{
/*
* If nmi_watchdog is turned off then we can turn on
* our nmi decoding capability.
*/
- if (!nmi_watchdog_active())
- hpwdt_nmi_decoding = 1;
- else
- dev_warn(&dev->dev, "NMI decoding is disabled. To enable this "
- "functionality you must reboot with nmi_watchdog=0 "
- "and load the hpwdt driver with priority=1.\n");
+ hpwdt_nmi_decoding = 1;
}
#else
static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
@@ -662,7 +657,7 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
dev_warn(&dev->dev, "NMI decoding is disabled. "
"Your kernel does not support a NMI Watchdog.\n");
}
-#endif /* ARCH_HAS_NMI_WATCHDOG */
+#endif /* CONFIG_X86_LOCAL_APIC */
static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
{
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index f7e90fe47b71..2c6c2b4ad8bf 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -1,7 +1,7 @@
/*
* intel TCO Watchdog Driver
*
- * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
+ * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,12 +26,15 @@
* document number 301473-002, 301474-026: 82801F (ICH6)
* document number 313082-001, 313075-006: 631xESB, 632xESB
* document number 307013-003, 307014-024: 82801G (ICH7)
+ * document number 322896-001, 322897-001: NM10
* document number 313056-003, 313057-017: 82801H (ICH8)
* document number 316972-004, 316973-012: 82801I (ICH9)
* document number 319973-002, 319974-002: 82801J (ICH10)
* document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
* document number 320066-003, 320257-008: EP80597 (IICH)
- * document number TBD : Cougar Point (CPT)
+ * document number 324645-001, 324646-001: Cougar Point (CPT)
+ * document number TBD : Patsburg (PBG)
+ * document number TBD : DH89xxCC
*/
/*
@@ -84,6 +87,7 @@ enum iTCO_chipsets {
TCO_ICH7DH, /* ICH7DH */
TCO_ICH7M, /* ICH7-M & ICH7-U */
TCO_ICH7MDH, /* ICH7-M DH */
+ TCO_NM10, /* NM10 */
TCO_ICH8, /* ICH8 & ICH8R */
TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */
@@ -146,7 +150,9 @@ enum iTCO_chipsets {
TCO_CPT29, /* Cougar Point */
TCO_CPT30, /* Cougar Point */
TCO_CPT31, /* Cougar Point */
- TCO_PBG, /* Patsburg */
+ TCO_PBG1, /* Patsburg */
+ TCO_PBG2, /* Patsburg */
+ TCO_DH89XXCC, /* DH89xxCC */
};
static struct {
@@ -172,6 +178,7 @@ static struct {
{"ICH7DH", 2},
{"ICH7-M or ICH7-U", 2},
{"ICH7-M DH", 2},
+ {"NM10", 2},
{"ICH8 or ICH8R", 2},
{"ICH8DH", 2},
{"ICH8DO", 2},
@@ -235,6 +242,8 @@ static struct {
{"Cougar Point", 2},
{"Cougar Point", 2},
{"Patsburg", 2},
+ {"Patsburg", 2},
+ {"DH89xxCC", 2},
{NULL, 0}
};
@@ -288,6 +297,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)},
+ { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)},
@@ -350,7 +360,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)},
{ ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)},
{ ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)},
- { ITCO_PCI_DEVICE(0x1d40, TCO_PBG)},
+ { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)},
+ { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)},
+ { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 2ee7dac55a3c..86f7cac1026c 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -270,7 +270,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
return -ENOMEM;
}
- imx2_wdt.clk = clk_get_sys("imx-wdt.0", NULL);
+ imx2_wdt.clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(imx2_wdt.clk)) {
dev_err(&pdev->dev, "can't get Watchdog clock\n");
return PTR_ERR(imx2_wdt.clk);
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 2852bb2e3fd9..811471903e8a 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -21,7 +21,7 @@
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <mach/timex.h>
+#include <mach/hardware.h>
#include <mach/regs-timer.h>
#define WDT_DEFAULT_TIME 5 /* seconds */
diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c
new file mode 100644
index 000000000000..cabbcfe1c847
--- /dev/null
+++ b/drivers/watchdog/m548x_wdt.c
@@ -0,0 +1,227 @@
+/*
+ * drivers/watchdog/m548x_wdt.c
+ *
+ * Watchdog driver for ColdFire MCF548x processors
+ * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
+ *
+ * Adapted from the IXP4xx watchdog driver, which carries these notices:
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * 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/ioport.h>
+#include <linux/uaccess.h>
+
+#include <asm/coldfire.h>
+#include <asm/m548xsim.h>
+#include <asm/m548xgpt.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */
+static unsigned long wdt_status;
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+
+static void wdt_enable(void)
+{
+ unsigned int gms0;
+
+ /* preserve GPIO usage, if any */
+ gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+ if (gms0 & MCF_GPT_GMS_TMS_GPIO)
+ gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
+ | MCF_GPT_GMS_OD);
+ else
+ gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
+ __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+ __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
+ MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
+ gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
+ __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_disable(void)
+{
+ unsigned int gms0;
+
+ /* disable watchdog */
+ gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+ gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
+ __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_keepalive(void)
+{
+ unsigned int gms0;
+
+ gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+ gms0 |= MCF_GPT_GMS_OCPW(0xA5);
+ __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static int m548x_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();
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t m548x_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_keepalive();
+ }
+ return len;
+}
+
+static const struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING,
+ .identity = "Coldfire M548x Watchdog",
+};
+
+static long m548x_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ ret = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ if (time <= 0 || time > 30) {
+ ret = -EINVAL;
+ break;
+ }
+
+ heartbeat = time;
+ wdt_enable();
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+ }
+ return ret;
+}
+
+static int m548x_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ wdt_disable();
+ else {
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "timer will not stop\n");
+ wdt_keepalive();
+ }
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+
+static const struct file_operations m548x_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = m548x_wdt_write,
+ .unlocked_ioctl = m548x_wdt_ioctl,
+ .open = m548x_wdt_open,
+ .release = m548x_wdt_release,
+};
+
+static struct miscdevice m548x_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &m548x_wdt_fops,
+};
+
+static int __init m548x_wdt_init(void)
+{
+ if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
+ "Coldfire M548x Watchdog")) {
+ printk(KERN_WARNING
+ "Coldfire M548x Watchdog : I/O region busy\n");
+ return -EBUSY;
+ }
+ printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+
+ return misc_register(&m548x_wdt_miscdev);
+}
+
+static void __exit m548x_wdt_exit(void)
+{
+ misc_deregister(&m548x_wdt_miscdev);
+ release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
+}
+
+module_init(m548x_wdt_init);
+module_exit(m548x_wdt_exit);
+
+MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
+MODULE_DESCRIPTION("Coldfire M548x Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
new file mode 100644
index 000000000000..1a50aa7079bf
--- /dev/null
+++ b/drivers/watchdog/nv_tco.c
@@ -0,0 +1,512 @@
+/*
+ * nv_tco 0.01: TCO timer driver for NV chipsets
+ *
+ * (c) Copyright 2005 Google Inc., All Rights Reserved.
+ *
+ * Based off i8xx_tco.c:
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
+ * Reserved.
+ * http://www.kernelconcepts.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.
+ *
+ * TCO timer driver for NV chipsets
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "nv_tco.h"
+
+/* Module and version information */
+#define TCO_VERSION "0.01"
+#define TCO_MODULE_NAME "NV_TCO"
+#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
+#define PFX TCO_MODULE_NAME ": "
+
+/* internal variables */
+static unsigned int tcobase;
+static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
+static unsigned long timer_alive;
+static char tco_expect_close;
+static struct pci_dev *tco_pci;
+
+/* the watchdog platform device */
+static struct platform_device *nv_tco_platform_device;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, "
+ "default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
+ " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Some TCO specific functions
+ */
+static inline unsigned char seconds_to_ticks(int seconds)
+{
+ /* the internal timer is stored as ticks which decrement
+ * every 0.6 seconds */
+ return (seconds * 10) / 6;
+}
+
+static void tco_timer_start(void)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ val = inl(TCO_CNT(tcobase));
+ val &= ~TCO_CNT_TCOHALT;
+ outl(val, TCO_CNT(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static void tco_timer_stop(void)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ val = inl(TCO_CNT(tcobase));
+ val |= TCO_CNT_TCOHALT;
+ outl(val, TCO_CNT(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static void tco_timer_keepalive(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ outb(0x01, TCO_RLD(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static int tco_timer_set_heartbeat(int t)
+{
+ int ret = 0;
+ unsigned char tmrval;
+ unsigned long flags;
+ u8 val;
+
+ /*
+ * note seconds_to_ticks(t) > t, so if t > 0x3f, so is
+ * tmrval=seconds_to_ticks(t). Check that the count in seconds isn't
+ * out of range on it's own (to avoid overflow in tmrval).
+ */
+ if (t < 0 || t > 0x3f)
+ return -EINVAL;
+ tmrval = seconds_to_ticks(t);
+
+ /* "Values of 0h-3h are ignored and should not be attempted" */
+ if (tmrval > 0x3f || tmrval < 0x04)
+ return -EINVAL;
+
+ /* Write new heartbeat to watchdog */
+ spin_lock_irqsave(&tco_lock, flags);
+ val = inb(TCO_TMR(tcobase));
+ val &= 0xc0;
+ val |= tmrval;
+ outb(val, TCO_TMR(tcobase));
+ val = inb(TCO_TMR(tcobase));
+
+ if ((val & 0x3f) != tmrval)
+ ret = -EINVAL;
+ spin_unlock_irqrestore(&tco_lock, flags);
+
+ if (ret)
+ return ret;
+
+ heartbeat = t;
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int nv_tco_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &timer_alive))
+ return -EBUSY;
+
+ /* Reload and activate timer */
+ tco_timer_keepalive();
+ tco_timer_start();
+ return nonseekable_open(inode, file);
+}
+
+static int nv_tco_release(struct inode *inode, struct file *file)
+{
+ /* Shut off the timer */
+ if (tco_expect_close == 42) {
+ tco_timer_stop();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping "
+ "watchdog!\n");
+ tco_timer_keepalive();
+ }
+ clear_bit(0, &timer_alive);
+ tco_expect_close = 0;
+ return 0;
+}
+
+static ssize_t nv_tco_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /*
+ * note: just in case someone wrote the magic character
+ * five months ago...
+ */
+ tco_expect_close = 0;
+
+ /*
+ * scan to see whether or not we got the magic
+ * character
+ */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ tco_expect_close = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ tco_timer_keepalive();
+ }
+ return len;
+}
+
+static long nv_tco_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_heartbeat;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = TCO_MODULE_NAME,
+ };
+
+ 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_SETOPTIONS:
+ if (get_user(new_options, p))
+ return -EFAULT;
+ if (new_options & WDIOS_DISABLECARD) {
+ tco_timer_stop();
+ retval = 0;
+ }
+ if (new_options & WDIOS_ENABLECARD) {
+ tco_timer_keepalive();
+ tco_timer_start();
+ retval = 0;
+ }
+ return retval;
+ case WDIOC_KEEPALIVE:
+ tco_timer_keepalive();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+ if (tco_timer_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+ tco_timer_keepalive();
+ /* Fall through */
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static const struct file_operations nv_tco_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = nv_tco_write,
+ .unlocked_ioctl = nv_tco_ioctl,
+ .open = nv_tco_open,
+ .release = nv_tco_release,
+};
+
+static struct miscdevice nv_tco_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &nv_tco_fops,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id tco_pci_tbl[] = {
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE(pci, tco_pci_tbl);
+
+/*
+ * Init & exit routines
+ */
+
+static unsigned char __init nv_tco_getdevice(void)
+{
+ struct pci_dev *dev = NULL;
+ u32 val;
+
+ /* Find the PCI device */
+ for_each_pci_dev(dev) {
+ if (pci_match_id(tco_pci_tbl, dev) != NULL) {
+ tco_pci = dev;
+ break;
+ }
+ }
+
+ if (!tco_pci)
+ return 0;
+
+ /* Find the base io port */
+ pci_read_config_dword(tco_pci, 0x64, &val);
+ val &= 0xffff;
+ if (val == 0x0001 || val == 0x0000) {
+ /* Something is wrong here, bar isn't setup */
+ printk(KERN_ERR PFX "failed to get tcobase address\n");
+ return 0;
+ }
+ val &= 0xff00;
+ tcobase = val + 0x40;
+
+ if (!request_region(tcobase, 0x10, "NV TCO")) {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ tcobase);
+ return 0;
+ }
+
+ /* Set a reasonable heartbeat before we stop the timer */
+ tco_timer_set_heartbeat(30);
+
+ /*
+ * Stop the TCO before we change anything so we don't race with
+ * a zeroed timer.
+ */
+ tco_timer_keepalive();
+ tco_timer_stop();
+
+ /* Disable SMI caused by TCO */
+ if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ MCP51_SMI_EN(tcobase));
+ goto out;
+ }
+ val = inl(MCP51_SMI_EN(tcobase));
+ val &= ~MCP51_SMI_EN_TCO;
+ outl(val, MCP51_SMI_EN(tcobase));
+ val = inl(MCP51_SMI_EN(tcobase));
+ release_region(MCP51_SMI_EN(tcobase), 4);
+ if (val & MCP51_SMI_EN_TCO) {
+ printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n");
+ goto out;
+ }
+
+ /* Check chipset's NO_REBOOT bit */
+ pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
+ val |= MCP51_SMBUS_SETUP_B_TCO_REBOOT;
+ pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
+ pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
+ if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) {
+ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot "
+ "disabled by hardware\n");
+ goto out;
+ }
+
+ return 1;
+out:
+ release_region(tcobase, 0x10);
+ return 0;
+}
+
+static int __devinit nv_tco_init(struct platform_device *dev)
+{
+ int ret;
+
+ /* Check whether or not the hardware watchdog is there */
+ if (!nv_tco_getdevice())
+ return -ENODEV;
+
+ /* Check to see if last reboot was due to watchdog timeout */
+ printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
+ inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
+
+ /* Clear out the old status */
+ outl(TCO_STS_RESET, TCO_STS(tcobase));
+
+ /*
+ * Check that the heartbeat value is within it's range.
+ * If not, reset to the default.
+ */
+ if (tco_timer_set_heartbeat(heartbeat)) {
+ heartbeat = WATCHDOG_HEARTBEAT;
+ tco_timer_set_heartbeat(heartbeat);
+ printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, "
+ "using %d\n", heartbeat);
+ }
+
+ ret = misc_register(&nv_tco_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
+ "(err=%d)\n", WATCHDOG_MINOR, ret);
+ goto unreg_region;
+ }
+
+ clear_bit(0, &timer_alive);
+
+ tco_timer_stop();
+
+ printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec "
+ "(nowayout=%d)\n", tcobase, heartbeat, nowayout);
+
+ return 0;
+
+unreg_region:
+ release_region(tcobase, 0x10);
+ return ret;
+}
+
+static void __devexit nv_tco_cleanup(void)
+{
+ u32 val;
+
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ tco_timer_stop();
+
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
+ val &= ~MCP51_SMBUS_SETUP_B_TCO_REBOOT;
+ pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
+ pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
+ if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) {
+ printk(KERN_CRIT PFX "Couldn't unset REBOOT bit. Machine may "
+ "soon reset\n");
+ }
+
+ /* Deregister */
+ misc_deregister(&nv_tco_miscdev);
+ release_region(tcobase, 0x10);
+}
+
+static int __devexit nv_tco_remove(struct platform_device *dev)
+{
+ if (tcobase)
+ nv_tco_cleanup();
+
+ return 0;
+}
+
+static void nv_tco_shutdown(struct platform_device *dev)
+{
+ tco_timer_stop();
+}
+
+static struct platform_driver nv_tco_driver = {
+ .probe = nv_tco_init,
+ .remove = __devexit_p(nv_tco_remove),
+ .shutdown = nv_tco_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TCO_MODULE_NAME,
+ },
+};
+
+static int __init nv_tco_init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n",
+ TCO_VERSION);
+
+ err = platform_driver_register(&nv_tco_driver);
+ if (err)
+ return err;
+
+ nv_tco_platform_device = platform_device_register_simple(
+ TCO_MODULE_NAME, -1, NULL, 0);
+ if (IS_ERR(nv_tco_platform_device)) {
+ err = PTR_ERR(nv_tco_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&nv_tco_driver);
+ return err;
+}
+
+static void __exit nv_tco_cleanup_module(void)
+{
+ platform_device_unregister(nv_tco_platform_device);
+ platform_driver_unregister(&nv_tco_driver);
+ printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n");
+}
+
+module_init(nv_tco_init_module);
+module_exit(nv_tco_cleanup_module);
+
+MODULE_AUTHOR("Mike Waychison");
+MODULE_DESCRIPTION("TCO timer driver for NV chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/nv_tco.h b/drivers/watchdog/nv_tco.h
new file mode 100644
index 000000000000..c2d1d04e055b
--- /dev/null
+++ b/drivers/watchdog/nv_tco.h
@@ -0,0 +1,64 @@
+/*
+ * nv_tco: TCO timer driver for nVidia chipsets.
+ *
+ * (c) Copyright 2005 Google Inc., All Rights Reserved.
+ *
+ * Supported Chipsets:
+ * - MCP51/MCP55
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
+ * Reserved.
+ * http://www.kernelconcepts.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.
+ *
+ * Neither kernel concepts nor Nils Faerber admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
+ * developed for
+ * Jentro AG, Haar/Munich (Germany)
+ *
+ * TCO timer driver for NV chipsets
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+/*
+ * Some address definitions for the TCO
+ */
+
+#define TCO_RLD(base) ((base) + 0x00) /* TCO Timer Reload and Current Value */
+#define TCO_TMR(base) ((base) + 0x01) /* TCO Timer Initial Value */
+
+#define TCO_STS(base) ((base) + 0x04) /* TCO Status Register */
+/*
+ * TCO Boot Status bit: set on TCO reset, reset by software or standby
+ * power-good (survives reboots), unfortunately this bit is never
+ * set.
+ */
+# define TCO_STS_BOOT_STS (1 << 9)
+/*
+ * first and 2nd timeout status bits, these also survive a warm boot,
+ * and they work, so we use them.
+ */
+# define TCO_STS_TCO_INT_STS (1 << 1)
+# define TCO_STS_TCO2TO_STS (1 << 10)
+# define TCO_STS_RESET (TCO_STS_BOOT_STS | TCO_STS_TCO2TO_STS | \
+ TCO_STS_TCO_INT_STS)
+
+#define TCO_CNT(base) ((base) + 0x08) /* TCO Control Register */
+# define TCO_CNT_TCOHALT (1 << 12)
+
+#define MCP51_SMBUS_SETUP_B 0xe8
+# define MCP51_SMBUS_SETUP_B_TCO_REBOOT (1 << 25)
+
+/*
+ * The SMI_EN register is at the base io address + 0x04,
+ * while TCOBASE is + 0x40.
+ */
+#define MCP51_SMI_EN(base) ((base) - 0x40 + 0x04)
+# define MCP51_SMI_EN_TCO ((1 << 4) | (1 << 5))
diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c
index 428f8a1583e8..3939e53f5f98 100644
--- a/drivers/watchdog/rdc321x_wdt.c
+++ b/drivers/watchdog/rdc321x_wdt.c
@@ -231,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
struct resource *r;
struct rdc321x_wdt_pdata *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = platform_get_drvdata(pdev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
new file mode 100644
index 000000000000..808372883e88
--- /dev/null
+++ b/drivers/watchdog/sp5100_tco.c
@@ -0,0 +1,480 @@
+/*
+ * sp5100_tco : TCO timer driver for sp5100 chipsets
+ *
+ * (c) Copyright 2009 Google Inc., All Rights Reserved.
+ *
+ * Based on i8xx_tco.c:
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
+ * Reserved.
+ * http://www.kernelconcepts.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.
+ *
+ * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide"
+ */
+
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "sp5100_tco.h"
+
+/* Module and version information */
+#define TCO_VERSION "0.01"
+#define TCO_MODULE_NAME "SP5100 TCO timer"
+#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
+#define PFX TCO_MODULE_NAME ": "
+
+/* internal variables */
+static void __iomem *tcobase;
+static unsigned int pm_iobase;
+static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
+static unsigned long timer_alive;
+static char tco_expect_close;
+static struct pci_dev *sp5100_tco_pci;
+
+/* the watchdog platform device */
+static struct platform_device *sp5100_tco_platform_device;
+
+/* module parameters */
+
+#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat. */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
+ __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
+ " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Some TCO specific functions
+ */
+static void tco_timer_start(void)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ val = readl(SP5100_WDT_CONTROL(tcobase));
+ val |= SP5100_WDT_START_STOP_BIT;
+ writel(val, SP5100_WDT_CONTROL(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static void tco_timer_stop(void)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ val = readl(SP5100_WDT_CONTROL(tcobase));
+ val &= ~SP5100_WDT_START_STOP_BIT;
+ writel(val, SP5100_WDT_CONTROL(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static void tco_timer_keepalive(void)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tco_lock, flags);
+ val = readl(SP5100_WDT_CONTROL(tcobase));
+ val |= SP5100_WDT_TRIGGER_BIT;
+ writel(val, SP5100_WDT_CONTROL(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+}
+
+static int tco_timer_set_heartbeat(int t)
+{
+ unsigned long flags;
+
+ if (t < 0 || t > 0xffff)
+ return -EINVAL;
+
+ /* Write new heartbeat to watchdog */
+ spin_lock_irqsave(&tco_lock, flags);
+ writel(t, SP5100_WDT_COUNT(tcobase));
+ spin_unlock_irqrestore(&tco_lock, flags);
+
+ heartbeat = t;
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int sp5100_tco_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &timer_alive))
+ return -EBUSY;
+
+ /* Reload and activate timer */
+ tco_timer_start();
+ tco_timer_keepalive();
+ return nonseekable_open(inode, file);
+}
+
+static int sp5100_tco_release(struct inode *inode, struct file *file)
+{
+ /* Shut off the timer. */
+ if (tco_expect_close == 42) {
+ tco_timer_stop();
+ } else {
+ printk(KERN_CRIT PFX
+ "Unexpected close, not stopping watchdog!\n");
+ tco_timer_keepalive();
+ }
+ clear_bit(0, &timer_alive);
+ tco_expect_close = 0;
+ return 0;
+}
+
+static ssize_t sp5100_tco_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ tco_expect_close = 0;
+
+ /* scan to see whether or not we got the magic character
+ */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ tco_expect_close = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ tco_timer_keepalive();
+ }
+ return len;
+}
+
+static long sp5100_tco_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_heartbeat;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = TCO_MODULE_NAME,
+ };
+
+ 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_SETOPTIONS:
+ if (get_user(new_options, p))
+ return -EFAULT;
+ if (new_options & WDIOS_DISABLECARD) {
+ tco_timer_stop();
+ retval = 0;
+ }
+ if (new_options & WDIOS_ENABLECARD) {
+ tco_timer_start();
+ tco_timer_keepalive();
+ retval = 0;
+ }
+ return retval;
+ case WDIOC_KEEPALIVE:
+ tco_timer_keepalive();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+ if (tco_timer_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+ tco_timer_keepalive();
+ /* Fall through */
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static const struct file_operations sp5100_tco_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = sp5100_tco_write,
+ .unlocked_ioctl = sp5100_tco_ioctl,
+ .open = sp5100_tco_open,
+ .release = sp5100_tco_release,
+};
+
+static struct miscdevice sp5100_tco_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &sp5100_tco_fops,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id sp5100_tco_pci_tbl[] = {
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
+ PCI_ANY_ID, },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
+
+/*
+ * Init & exit routines
+ */
+
+static unsigned char __devinit sp5100_tco_setupdevice(void)
+{
+ struct pci_dev *dev = NULL;
+ u32 val;
+
+ /* Match the PCI device */
+ for_each_pci_dev(dev) {
+ if (pci_match_id(sp5100_tco_pci_tbl, dev) != NULL) {
+ sp5100_tco_pci = dev;
+ break;
+ }
+ }
+
+ if (!sp5100_tco_pci)
+ return 0;
+
+ /* Request the IO ports used by this driver */
+ pm_iobase = SP5100_IO_PM_INDEX_REG;
+ if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ pm_iobase);
+ goto exit;
+ }
+
+ /* Find the watchdog base address. */
+ outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG);
+ val = inb(SP5100_IO_PM_DATA_REG);
+ outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG);
+ val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
+ outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG);
+ val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
+ outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG);
+ /* Low three bits of BASE0 are reserved. */
+ val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8);
+
+ tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
+ if (tcobase == 0) {
+ printk(KERN_ERR PFX "failed to get tcobase address\n");
+ goto unreg_region;
+ }
+
+ /* Enable watchdog decode bit */
+ pci_read_config_dword(sp5100_tco_pci,
+ SP5100_PCI_WATCHDOG_MISC_REG,
+ &val);
+
+ val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+
+ pci_write_config_dword(sp5100_tco_pci,
+ SP5100_PCI_WATCHDOG_MISC_REG,
+ val);
+
+ /* Enable Watchdog timer and set the resolution to 1 sec. */
+ outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
+ val = inb(SP5100_IO_PM_DATA_REG);
+ val |= SP5100_PM_WATCHDOG_SECOND_RES;
+ val &= ~SP5100_PM_WATCHDOG_DISABLE;
+ outb(val, SP5100_IO_PM_DATA_REG);
+
+ /* Check that the watchdog action is set to reset the system. */
+ val = readl(SP5100_WDT_CONTROL(tcobase));
+ val &= ~SP5100_PM_WATCHDOG_ACTION_RESET;
+ writel(val, SP5100_WDT_CONTROL(tcobase));
+
+ /* Set a reasonable heartbeat before we stop the timer */
+ tco_timer_set_heartbeat(heartbeat);
+
+ /*
+ * Stop the TCO before we change anything so we don't race with
+ * a zeroed timer.
+ */
+ tco_timer_stop();
+
+ /* Done */
+ return 1;
+
+ iounmap(tcobase);
+unreg_region:
+ release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
+exit:
+ return 0;
+}
+
+static int __devinit sp5100_tco_init(struct platform_device *dev)
+{
+ int ret;
+ u32 val;
+
+ /* Check whether or not the hardware watchdog is there. If found, then
+ * set it up.
+ */
+ if (!sp5100_tco_setupdevice())
+ return -ENODEV;
+
+ /* Check to see if last reboot was due to watchdog timeout */
+ printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
+ readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
+ "" : "not ");
+
+ /* Clear out the old status */
+ val = readl(SP5100_WDT_CONTROL(tcobase));
+ val &= ~SP5100_PM_WATCHDOG_FIRED;
+ writel(val, SP5100_WDT_CONTROL(tcobase));
+
+ /*
+ * Check that the heartbeat value is within it's range.
+ * If not, reset to the default.
+ */
+ if (tco_timer_set_heartbeat(heartbeat)) {
+ heartbeat = WATCHDOG_HEARTBEAT;
+ tco_timer_set_heartbeat(heartbeat);
+ }
+
+ ret = misc_register(&sp5100_tco_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor="
+ "%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto exit;
+ }
+
+ clear_bit(0, &timer_alive);
+
+ printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec"
+ " (nowayout=%d)\n",
+ tcobase, heartbeat, nowayout);
+
+ return 0;
+
+exit:
+ iounmap(tcobase);
+ release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
+ return ret;
+}
+
+static void __devexit sp5100_tco_cleanup(void)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ tco_timer_stop();
+
+ /* Deregister */
+ misc_deregister(&sp5100_tco_miscdev);
+ iounmap(tcobase);
+ release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
+}
+
+static int __devexit sp5100_tco_remove(struct platform_device *dev)
+{
+ if (tcobase)
+ sp5100_tco_cleanup();
+ return 0;
+}
+
+static void sp5100_tco_shutdown(struct platform_device *dev)
+{
+ tco_timer_stop();
+}
+
+static struct platform_driver sp5100_tco_driver = {
+ .probe = sp5100_tco_init,
+ .remove = __devexit_p(sp5100_tco_remove),
+ .shutdown = sp5100_tco_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TCO_MODULE_NAME,
+ },
+};
+
+static int __init sp5100_tco_init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n",
+ TCO_VERSION);
+
+ err = platform_driver_register(&sp5100_tco_driver);
+ if (err)
+ return err;
+
+ sp5100_tco_platform_device = platform_device_register_simple(
+ TCO_MODULE_NAME, -1, NULL, 0);
+ if (IS_ERR(sp5100_tco_platform_device)) {
+ err = PTR_ERR(sp5100_tco_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&sp5100_tco_driver);
+ return err;
+}
+
+static void __exit sp5100_tco_cleanup_module(void)
+{
+ platform_device_unregister(sp5100_tco_platform_device);
+ platform_driver_unregister(&sp5100_tco_driver);
+ printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n");
+}
+
+module_init(sp5100_tco_init_module);
+module_exit(sp5100_tco_cleanup_module);
+
+MODULE_AUTHOR("Priyanka Gupta");
+MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h
new file mode 100644
index 000000000000..a5a16cc90a34
--- /dev/null
+++ b/drivers/watchdog/sp5100_tco.h
@@ -0,0 +1,41 @@
+/*
+ * sp5100_tco: TCO timer driver for sp5100 chipsets.
+ *
+ * (c) Copyright 2009 Google Inc., All Rights Reserved.
+ *
+ * TCO timer driver for sp5100 chipsets
+ */
+
+/*
+ * Some address definitions for the Watchdog
+ */
+
+#define SP5100_WDT_MEM_MAP_SIZE 0x08
+#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
+#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
+
+#define SP5100_WDT_START_STOP_BIT 1
+#define SP5100_WDT_TRIGGER_BIT (1 << 7)
+
+#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
+#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
+
+#define SP5100_PM_IOPORTS_SIZE 0x02
+
+/* These two IO registers are hardcoded and there doesn't seem to be a way to
+ * read them from a register.
+ */
+#define SP5100_IO_PM_INDEX_REG 0xCD6
+#define SP5100_IO_PM_DATA_REG 0xCD7
+
+#define SP5100_PM_WATCHDOG_CONTROL 0x69
+#define SP5100_PM_WATCHDOG_BASE0 0x6C
+#define SP5100_PM_WATCHDOG_BASE1 0x6D
+#define SP5100_PM_WATCHDOG_BASE2 0x6E
+#define SP5100_PM_WATCHDOG_BASE3 0x6F
+
+#define SP5100_PM_WATCHDOG_FIRED (1 << 1)
+#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
+
+#define SP5100_PM_WATCHDOG_DISABLE 1
+#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 0f5288df0091..e5c91d4404ed 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -42,7 +42,7 @@
#include <asm/system.h>
-#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
+#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
@@ -89,7 +89,7 @@ static void w83627hf_select_wd_register(void)
c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
outb_p(0x2b, WDT_EFER);
outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */
- } else if (c == 0x88) { /* W83627EHF */
+ } else if (c == 0x88 || c == 0xa0) { /* W83627EHF / W83627DHG */
outb_p(0x2d, WDT_EFER); /* select GPIO5 */
c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */
outb_p(0x2d, WDT_EFER);
@@ -129,6 +129,8 @@ static void w83627hf_init(void)
t = inb_p(WDT_EFDR); /* read CRF5 */
t &= ~0x0C; /* set second mode & disable keyboard
turning off watchdog */
+ t |= 0x02; /* enable the WDTO# output low pulse
+ to the KBRST# pin (PIN60) */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */
outb_p(0xF7, WDT_EFER); /* Select CRF7 */
@@ -321,7 +323,7 @@ static int __init wdt_init(void)
{
int ret;
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 6e6180ccd726..07bec09d1dad 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -29,6 +29,14 @@ config XEN_DEV_EVTCHN
firing.
If in doubt, say yes.
+config XEN_BACKEND
+ bool "Backend driver support"
+ depends on XEN_DOM0
+ default y
+ help
+ Support for backend device drivers that provide I/O services
+ to other virtual machines.
+
config XENFS
tristate "Xen filesystem"
default y
@@ -62,9 +70,19 @@ config XEN_SYS_HYPERVISOR
virtual environment, /sys/hypervisor will still be present,
but will have no xen contents.
+config XEN_XENBUS_FRONTEND
+ tristate
+
+config XEN_GNTDEV
+ tristate "userspace grant access device driver"
+ depends on XEN
+ select MMU_NOTIFIER
+ help
+ Allows userspace processes to use grants.
+
config XEN_PLATFORM_PCI
tristate "xen platform pci device driver"
- depends on XEN_PVHVM
+ depends on XEN_PVHVM && PCI
default m
help
Driver for the Xen PCI Platform device: it is responsible for
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index eb8a78d77d9d..5088cc2e6fe2 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -8,9 +8,15 @@ obj-$(CONFIG_BLOCK) += biomerge.o
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
-obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
+obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
+obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
-obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
+obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
obj-$(CONFIG_XEN_DOM0) += pci.o
+
+xen-evtchn-y := evtchn.o
+xen-gntdev-y := gntdev.o
+
+xen-platform-pci-y := platform-pci.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 500290b150bb..43f9f02c7db0 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -50,6 +50,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/tlb.h>
+#include <asm/e820.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -119,7 +120,7 @@ static void scrub_page(struct page *page)
}
/* balloon_append: add the given page to the balloon. */
-static void balloon_append(struct page *page)
+static void __balloon_append(struct page *page)
{
/* Lowmem is re-populated first, so highmem pages go at list tail. */
if (PageHighMem(page)) {
@@ -130,7 +131,11 @@ static void balloon_append(struct page *page)
list_add(&page->lru, &ballooned_pages);
balloon_stats.balloon_low++;
}
+}
+static void balloon_append(struct page *page)
+{
+ __balloon_append(page);
totalram_pages--;
}
@@ -191,7 +196,7 @@ static unsigned long current_target(void)
static int increase_reservation(unsigned long nr_pages)
{
- unsigned long pfn, i, flags;
+ unsigned long pfn, i;
struct page *page;
long rc;
struct xen_memory_reservation reservation = {
@@ -203,8 +208,6 @@ static int increase_reservation(unsigned long nr_pages)
if (nr_pages > ARRAY_SIZE(frame_list))
nr_pages = ARRAY_SIZE(frame_list);
- spin_lock_irqsave(&xen_reservation_lock, flags);
-
page = balloon_first_page();
for (i = 0; i < nr_pages; i++) {
BUG_ON(page == NULL);
@@ -247,14 +250,12 @@ static int increase_reservation(unsigned long nr_pages)
balloon_stats.current_pages += rc;
out:
- spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
return rc < 0 ? rc : rc != nr_pages;
}
static int decrease_reservation(unsigned long nr_pages)
{
- unsigned long pfn, i, flags;
+ unsigned long pfn, i;
struct page *page;
int need_sleep = 0;
int ret;
@@ -292,8 +293,6 @@ static int decrease_reservation(unsigned long nr_pages)
kmap_flush_unused();
flush_tlb_all();
- spin_lock_irqsave(&xen_reservation_lock, flags);
-
/* No more mappings: invalidate P2M and add to balloon. */
for (i = 0; i < nr_pages; i++) {
pfn = mfn_to_pfn(frame_list[i]);
@@ -308,8 +307,6 @@ static int decrease_reservation(unsigned long nr_pages)
balloon_stats.current_pages -= nr_pages;
- spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
return need_sleep;
}
@@ -395,7 +392,7 @@ static struct notifier_block xenstore_notifier;
static int __init balloon_init(void)
{
- unsigned long pfn;
+ unsigned long pfn, extra_pfn_end;
struct page *page;
if (!xen_pv_domain())
@@ -415,11 +412,24 @@ static int __init balloon_init(void)
register_balloon(&balloon_sysdev);
- /* Initialise the balloon with excess memory space. */
- for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
+ /*
+ * Initialise the balloon with excess memory space. We need
+ * to make sure we don't add memory which doesn't exist or
+ * logically exist. The E820 map can be trimmed to be smaller
+ * than the amount of physical memory due to the mem= command
+ * line parameter. And if this is a 32-bit non-HIGHMEM kernel
+ * on a system with memory which requires highmem to access,
+ * don't try to use it.
+ */
+ extra_pfn_end = min(min(max_pfn, e820_end_of_ram_pfn()),
+ (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size));
+ for (pfn = PFN_UP(xen_extra_mem_start);
+ pfn < extra_pfn_end;
+ pfn++) {
page = pfn_to_page(pfn);
- if (!PageReserved(page))
- balloon_append(page);
+ /* totalram_pages doesn't include the boot-time
+ balloon extension, so don't subtract from it. */
+ __balloon_append(page);
}
target_watch.callback = watch_target;
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 97612f548a8e..74681478100a 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -105,7 +105,6 @@ struct irq_info
static struct irq_info *irq_info;
static int *pirq_to_irq;
-static int nr_pirqs;
static int *evtchn_to_irq;
struct cpu_evtchn_s {
@@ -171,6 +170,9 @@ static struct irq_info *info_for_irq(unsigned irq)
static unsigned int evtchn_from_irq(unsigned irq)
{
+ if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)))
+ return 0;
+
return info_for_irq(irq)->evtchn;
}
@@ -278,17 +280,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
#endif
- __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
- __set_bit(chn, cpu_evtchn_mask(cpu));
+ clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
+ set_bit(chn, cpu_evtchn_mask(cpu));
irq_info[irq].cpu = cpu;
}
static void init_evtchn_cpu_bindings(void)
{
+ int i;
#ifdef CONFIG_SMP
struct irq_desc *desc;
- int i;
/* By default all event channels notify CPU#0. */
for_each_irq_desc(i, desc) {
@@ -296,7 +298,10 @@ static void init_evtchn_cpu_bindings(void)
}
#endif
- memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
+ for_each_possible_cpu(i)
+ memset(cpu_evtchn_mask(i),
+ (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s));
+
}
static inline void clear_evtchn(int port)
@@ -353,7 +358,7 @@ static void unmask_evtchn(int port)
struct evtchn_unmask unmask = { .port = port };
(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
} else {
- struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+ struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
sync_clear_bit(port, &s->evtchn_mask[0]);
@@ -382,12 +387,17 @@ static int get_nr_hw_irqs(void)
return ret;
}
-/* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs
- * succeeded otherwise nr_pirqs won't hold the right value */
-static int find_unbound_pirq(void)
+static int find_unbound_pirq(int type)
{
- int i;
- for (i = nr_pirqs-1; i >= 0; i--) {
+ int rc, i;
+ struct physdev_get_free_pirq op_get_free_pirq;
+ op_get_free_pirq.type = type;
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
+ if (!rc)
+ return op_get_free_pirq.pirq;
+
+ for (i = 0; i < nr_irqs; i++) {
if (pirq_to_irq[i] < 0)
return i;
}
@@ -398,15 +408,21 @@ static int find_unbound_irq(void)
{
struct irq_data *data;
int irq, res;
- int start = get_nr_hw_irqs();
+ int bottom = get_nr_hw_irqs();
+ int top = nr_irqs-1;
- if (start == nr_irqs)
+ if (bottom == nr_irqs)
goto no_irqs;
- /* nr_irqs is a magic value. Must not use it.*/
- for (irq = nr_irqs-1; irq > start; irq--) {
+ /* This loop starts from the top of IRQ space and goes down.
+ * We need this b/c if we have a PCI device in a Xen PV guest
+ * we do not have an IO-APIC (though the backend might have them)
+ * mapped in. To not have a collision of physical IRQs with the Xen
+ * event channels start at the top of the IRQ space for virtual IRQs.
+ */
+ for (irq = top; irq > bottom; irq--) {
data = irq_get_irq_data(irq);
- /* only 0->15 have init'd desc; handle irq > 16 */
+ /* only 15->0 have init'd desc; handle irq > 16 */
if (!data)
break;
if (data->chip == &no_irq_chip)
@@ -417,10 +433,10 @@ static int find_unbound_irq(void)
return irq;
}
- if (irq == start)
+ if (irq == bottom)
goto no_irqs;
- res = irq_alloc_desc_at(irq, 0);
+ res = irq_alloc_desc_at(irq, -1);
if (WARN_ON(res != irq))
return -1;
@@ -608,10 +624,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
spin_lock(&irq_mapping_update_lock);
- if ((pirq > nr_pirqs) || (gsi > nr_irqs)) {
+ if ((pirq > nr_irqs) || (gsi > nr_irqs)) {
printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n",
- pirq > nr_pirqs ? "nr_pirqs" :"",
- gsi > nr_irqs ? "nr_irqs" : "");
+ pirq > nr_irqs ? "pirq" :"",
+ gsi > nr_irqs ? "gsi" : "");
goto out;
}
@@ -627,7 +643,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
if (identity_mapped_irq(gsi) || (!xen_initial_domain() &&
xen_pv_domain())) {
irq = gsi;
- irq_alloc_desc_at(irq, 0);
+ irq_alloc_desc_at(irq, -1);
} else
irq = find_unbound_irq();
@@ -661,17 +677,21 @@ out:
#include <linux/msi.h>
#include "../pci/msi.h"
-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq)
+void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
{
spin_lock(&irq_mapping_update_lock);
- *irq = find_unbound_irq();
- if (*irq == -1)
- goto out;
+ if (alloc & XEN_ALLOC_IRQ) {
+ *irq = find_unbound_irq();
+ if (*irq == -1)
+ goto out;
+ }
- *pirq = find_unbound_pirq();
- if (*pirq == -1)
- goto out;
+ if (alloc & XEN_ALLOC_PIRQ) {
+ *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+ if (*pirq == -1)
+ goto out;
+ }
set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
handle_level_irq, name);
@@ -752,13 +772,14 @@ int xen_destroy_irq(int irq)
goto out;
if (xen_initial_domain()) {
- unmap_irq.pirq = info->u.pirq.gsi;
+ unmap_irq.pirq = info->u.pirq.pirq;
unmap_irq.domid = DOMID_SELF;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
if (rc) {
printk(KERN_WARNING "unmap irq failed %d\n", rc);
goto out;
}
+ pirq_to_irq[info->u.pirq.pirq] = -1;
}
irq_info[irq] = mk_unbound_info();
@@ -779,6 +800,11 @@ int xen_gsi_from_irq(unsigned irq)
return gsi_from_irq(irq);
}
+int xen_irq_from_pirq(unsigned pirq)
+{
+ return pirq_to_irq[pirq];
+}
+
int bind_evtchn_to_irq(unsigned int evtchn)
{
int irq;
@@ -1084,7 +1110,7 @@ static void __xen_evtchn_do_upcall(void)
{
int cpu = get_cpu();
struct shared_info *s = HYPERVISOR_shared_info;
- struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+ struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
unsigned count;
do {
@@ -1092,7 +1118,7 @@ static void __xen_evtchn_do_upcall(void)
vcpu_info->evtchn_upcall_pending = 0;
- if (__get_cpu_var(xed_nesting_count)++)
+ if (__this_cpu_inc_return(xed_nesting_count) - 1)
goto out;
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
@@ -1124,8 +1150,8 @@ static void __xen_evtchn_do_upcall(void)
BUG_ON(!irqs_disabled());
- count = __get_cpu_var(xed_nesting_count);
- __get_cpu_var(xed_nesting_count) = 0;
+ count = __this_cpu_read(xed_nesting_count);
+ __this_cpu_write(xed_nesting_count, 0);
} while (count != 1 || vcpu_info->evtchn_upcall_pending);
out:
@@ -1276,6 +1302,42 @@ static int retrigger_dynirq(unsigned int irq)
return ret;
}
+static void restore_cpu_pirqs(void)
+{
+ int pirq, rc, irq, gsi;
+ struct physdev_map_pirq map_irq;
+
+ for (pirq = 0; pirq < nr_irqs; pirq++) {
+ irq = pirq_to_irq[pirq];
+ if (irq == -1)
+ continue;
+
+ /* save/restore of PT devices doesn't work, so at this point the
+ * only devices present are GSI based emulated devices */
+ gsi = gsi_from_irq(irq);
+ if (!gsi)
+ continue;
+
+ map_irq.domid = DOMID_SELF;
+ map_irq.type = MAP_PIRQ_TYPE_GSI;
+ map_irq.index = gsi;
+ map_irq.pirq = pirq;
+
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ if (rc) {
+ printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n",
+ gsi, irq, pirq, rc);
+ irq_info[irq] = mk_unbound_info();
+ pirq_to_irq[pirq] = -1;
+ continue;
+ }
+
+ printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
+
+ startup_pirq(irq);
+ }
+}
+
static void restore_cpu_virqs(unsigned int cpu)
{
struct evtchn_bind_virq bind_virq;
@@ -1299,9 +1361,6 @@ static void restore_cpu_virqs(unsigned int cpu)
evtchn_to_irq[evtchn] = irq;
irq_info[irq] = mk_virq_info(evtchn, virq);
bind_evtchn_to_cpu(evtchn, cpu);
-
- /* Ready for use. */
- unmask_evtchn(evtchn);
}
}
@@ -1327,10 +1386,6 @@ static void restore_cpu_ipis(unsigned int cpu)
evtchn_to_irq[evtchn] = irq;
irq_info[irq] = mk_ipi_info(evtchn, ipi);
bind_evtchn_to_cpu(evtchn, cpu);
-
- /* Ready for use. */
- unmask_evtchn(evtchn);
-
}
}
@@ -1390,6 +1445,7 @@ void xen_poll_irq(int irq)
void xen_irq_resume(void)
{
unsigned int cpu, irq, evtchn;
+ struct irq_desc *desc;
init_evtchn_cpu_bindings();
@@ -1408,6 +1464,25 @@ void xen_irq_resume(void)
restore_cpu_virqs(cpu);
restore_cpu_ipis(cpu);
}
+
+ /*
+ * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These
+ * are not handled by the IRQ core.
+ */
+ for_each_irq_desc(irq, desc) {
+ if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND))
+ continue;
+ if (desc->status & IRQ_DISABLED)
+ continue;
+
+ evtchn = evtchn_from_irq(irq);
+ if (evtchn == -1)
+ continue;
+
+ unmask_evtchn(evtchn);
+ }
+
+ restore_cpu_pirqs();
}
static struct irq_chip xen_dynamic_chip __read_mostly = {
@@ -1492,26 +1567,17 @@ void xen_callback_vector(void) {}
void __init xen_init_IRQ(void)
{
- int i, rc;
- struct physdev_nr_pirqs op_nr_pirqs;
+ int i;
cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s),
GFP_KERNEL);
irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL);
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs);
- if (rc < 0) {
- nr_pirqs = nr_irqs;
- if (rc != -ENOSYS)
- printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc);
- } else {
- if (xen_pv_domain() && !xen_initial_domain())
- nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs);
- else
- nr_pirqs = op_nr_pirqs.nr_pirqs;
- }
- pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL);
- for (i = 0; i < nr_pirqs; i++)
+ /* We are using nr_irqs as the maximum number of pirq available but
+ * that number is actually chosen by Xen and we don't know exactly
+ * what it is. Be careful choosing high pirq numbers. */
+ pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL);
+ for (i = 0; i < nr_irqs; i++)
pirq_to_irq[i] = -1;
evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index fec6ba3c08a8..ef11daf0cafe 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -69,20 +69,51 @@ struct per_user_data {
const char *name;
};
-/* Who's bound to each port? */
-static struct per_user_data *port_user[NR_EVENT_CHANNELS];
+/*
+ * Who's bound to each port? This is logically an array of struct
+ * per_user_data *, but we encode the current enabled-state in bit 0.
+ */
+static unsigned long *port_user;
static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
-irqreturn_t evtchn_interrupt(int irq, void *data)
+static inline struct per_user_data *get_port_user(unsigned port)
+{
+ return (struct per_user_data *)(port_user[port] & ~1);
+}
+
+static inline void set_port_user(unsigned port, struct per_user_data *u)
+{
+ port_user[port] = (unsigned long)u;
+}
+
+static inline bool get_port_enabled(unsigned port)
+{
+ return port_user[port] & 1;
+}
+
+static inline void set_port_enabled(unsigned port, bool enabled)
+{
+ if (enabled)
+ port_user[port] |= 1;
+ else
+ port_user[port] &= ~1;
+}
+
+static irqreturn_t evtchn_interrupt(int irq, void *data)
{
unsigned int port = (unsigned long)data;
struct per_user_data *u;
spin_lock(&port_user_lock);
- u = port_user[port];
+ u = get_port_user(port);
+
+ WARN(!get_port_enabled(port),
+ "Interrupt for port %d, but apparently not enabled; per-user %p\n",
+ port, u);
disable_irq_nosync(irq);
+ set_port_enabled(port, false);
if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
@@ -92,9 +123,8 @@ irqreturn_t evtchn_interrupt(int irq, void *data)
kill_fasync(&u->evtchn_async_queue,
SIGIO, POLL_IN);
}
- } else {
+ } else
u->ring_overflow = 1;
- }
spin_unlock(&port_user_lock);
@@ -198,9 +228,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
goto out;
spin_lock_irq(&port_user_lock);
- for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
- if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
- enable_irq(irq_from_evtchn(kbuf[i]));
+
+ for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
+ unsigned port = kbuf[i];
+
+ if (port < NR_EVENT_CHANNELS &&
+ get_port_user(port) == u &&
+ !get_port_enabled(port)) {
+ set_port_enabled(port, true);
+ enable_irq(irq_from_evtchn(port));
+ }
+ }
+
spin_unlock_irq(&port_user_lock);
rc = count;
@@ -222,8 +261,9 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
* interrupt handler yet, and our caller has already
* serialized bind operations.)
*/
- BUG_ON(port_user[port] != NULL);
- port_user[port] = u;
+ BUG_ON(get_port_user(port) != NULL);
+ set_port_user(port, u);
+ set_port_enabled(port, true); /* start enabled */
rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
u->name, (void *)(unsigned long)port);
@@ -239,10 +279,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port)
unbind_from_irqhandler(irq, (void *)(unsigned long)port);
- /* make sure we unbind the irq handler before clearing the port */
- barrier();
-
- port_user[port] = NULL;
+ set_port_user(port, NULL);
}
static long evtchn_ioctl(struct file *file,
@@ -333,15 +370,17 @@ static long evtchn_ioctl(struct file *file,
spin_lock_irq(&port_user_lock);
rc = -ENOTCONN;
- if (port_user[unbind.port] != u) {
+ if (get_port_user(unbind.port) != u) {
spin_unlock_irq(&port_user_lock);
break;
}
- evtchn_unbind_from_user(u, unbind.port);
+ disable_irq(irq_from_evtchn(unbind.port));
spin_unlock_irq(&port_user_lock);
+ evtchn_unbind_from_user(u, unbind.port);
+
rc = 0;
break;
}
@@ -355,7 +394,7 @@ static long evtchn_ioctl(struct file *file,
if (notify.port >= NR_EVENT_CHANNELS) {
rc = -EINVAL;
- } else if (port_user[notify.port] != u) {
+ } else if (get_port_user(notify.port) != u) {
rc = -ENOTCONN;
} else {
notify_remote_via_evtchn(notify.port);
@@ -431,7 +470,7 @@ static int evtchn_open(struct inode *inode, struct file *filp)
filp->private_data = u;
- return 0;
+ return nonseekable_open(inode, filp);;
}
static int evtchn_release(struct inode *inode, struct file *filp)
@@ -444,14 +483,21 @@ static int evtchn_release(struct inode *inode, struct file *filp)
free_page((unsigned long)u->ring);
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
- if (port_user[i] != u)
+ if (get_port_user(i) != u)
continue;
- evtchn_unbind_from_user(port_user[i], i);
+ disable_irq(irq_from_evtchn(i));
}
spin_unlock_irq(&port_user_lock);
+ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+ if (get_port_user(i) != u)
+ continue;
+
+ evtchn_unbind_from_user(get_port_user(i), i);
+ }
+
kfree(u->name);
kfree(u);
@@ -467,12 +513,12 @@ static const struct file_operations evtchn_fops = {
.fasync = evtchn_fasync,
.open = evtchn_open,
.release = evtchn_release,
- .llseek = noop_llseek,
+ .llseek = no_llseek,
};
static struct miscdevice evtchn_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
- .name = "evtchn",
+ .name = "xen/evtchn",
.fops = &evtchn_fops,
};
static int __init evtchn_init(void)
@@ -482,8 +528,11 @@ static int __init evtchn_init(void)
if (!xen_domain())
return -ENODEV;
+ port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL);
+ if (port_user == NULL)
+ return -ENOMEM;
+
spin_lock_init(&port_user_lock);
- memset(port_user, 0, sizeof(port_user));
/* Create '/dev/misc/evtchn'. */
err = misc_register(&evtchn_miscdev);
@@ -499,6 +548,9 @@ static int __init evtchn_init(void)
static void __exit evtchn_cleanup(void)
{
+ kfree(port_user);
+ port_user = NULL;
+
misc_deregister(&evtchn_miscdev);
}
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
new file mode 100644
index 000000000000..1e31cdcdae1e
--- /dev/null
+++ b/drivers/xen/gntdev.c
@@ -0,0 +1,665 @@
+/******************************************************************************
+ * gntdev.c
+ *
+ * Device for accessing (in user-space) pages that have been granted by other
+ * domains.
+ *
+ * Copyright (c) 2006-2007, D G Murray.
+ * (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ */
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mmu_notifier.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <xen/xen.h>
+#include <xen/grant_table.h>
+#include <xen/gntdev.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/page.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Derek G. Murray <Derek.Murray@cl.cam.ac.uk>, "
+ "Gerd Hoffmann <kraxel@redhat.com>");
+MODULE_DESCRIPTION("User-space granted page access driver");
+
+static int limit = 1024;
+module_param(limit, int, 0644);
+MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped at "
+ "once by a gntdev instance");
+
+struct gntdev_priv {
+ struct list_head maps;
+ uint32_t used;
+ uint32_t limit;
+ /* lock protects maps from concurrent changes */
+ spinlock_t lock;
+ struct mm_struct *mm;
+ struct mmu_notifier mn;
+};
+
+struct grant_map {
+ struct list_head next;
+ struct gntdev_priv *priv;
+ struct vm_area_struct *vma;
+ int index;
+ int count;
+ int flags;
+ int is_mapped;
+ struct ioctl_gntdev_grant_ref *grants;
+ struct gnttab_map_grant_ref *map_ops;
+ struct gnttab_unmap_grant_ref *unmap_ops;
+ struct page **pages;
+};
+
+/* ------------------------------------------------------------------ */
+
+static void gntdev_print_maps(struct gntdev_priv *priv,
+ char *text, int text_index)
+{
+#ifdef DEBUG
+ struct grant_map *map;
+
+ pr_debug("maps list (priv %p, usage %d/%d)\n",
+ priv, priv->used, priv->limit);
+
+ list_for_each_entry(map, &priv->maps, next)
+ pr_debug(" index %2d, count %2d %s\n",
+ map->index, map->count,
+ map->index == text_index && text ? text : "");
+#endif
+}
+
+static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
+{
+ struct grant_map *add;
+ int i;
+
+ add = kzalloc(sizeof(struct grant_map), GFP_KERNEL);
+ if (NULL == add)
+ return NULL;
+
+ add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL);
+ add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL);
+ add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL);
+ add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL);
+ if (NULL == add->grants ||
+ NULL == add->map_ops ||
+ NULL == add->unmap_ops ||
+ NULL == add->pages)
+ goto err;
+
+ for (i = 0; i < count; i++) {
+ add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (add->pages[i] == NULL)
+ goto err;
+ }
+
+ add->index = 0;
+ add->count = count;
+ add->priv = priv;
+
+ if (add->count + priv->used > priv->limit)
+ goto err;
+
+ return add;
+
+err:
+ if (add->pages)
+ for (i = 0; i < count; i++) {
+ if (add->pages[i])
+ __free_page(add->pages[i]);
+ }
+ kfree(add->pages);
+ kfree(add->grants);
+ kfree(add->map_ops);
+ kfree(add->unmap_ops);
+ kfree(add);
+ return NULL;
+}
+
+static void gntdev_add_map(struct gntdev_priv *priv, struct grant_map *add)
+{
+ struct grant_map *map;
+
+ list_for_each_entry(map, &priv->maps, next) {
+ if (add->index + add->count < map->index) {
+ list_add_tail(&add->next, &map->next);
+ goto done;
+ }
+ add->index = map->index + map->count;
+ }
+ list_add_tail(&add->next, &priv->maps);
+
+done:
+ priv->used += add->count;
+ gntdev_print_maps(priv, "[new]", add->index);
+}
+
+static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
+ int index, int count)
+{
+ struct grant_map *map;
+
+ list_for_each_entry(map, &priv->maps, next) {
+ if (map->index != index)
+ continue;
+ if (map->count != count)
+ continue;
+ return map;
+ }
+ return NULL;
+}
+
+static struct grant_map *gntdev_find_map_vaddr(struct gntdev_priv *priv,
+ unsigned long vaddr)
+{
+ struct grant_map *map;
+
+ list_for_each_entry(map, &priv->maps, next) {
+ if (!map->vma)
+ continue;
+ if (vaddr < map->vma->vm_start)
+ continue;
+ if (vaddr >= map->vma->vm_end)
+ continue;
+ return map;
+ }
+ return NULL;
+}
+
+static int gntdev_del_map(struct grant_map *map)
+{
+ int i;
+
+ if (map->vma)
+ return -EBUSY;
+ for (i = 0; i < map->count; i++)
+ if (map->unmap_ops[i].handle)
+ return -EBUSY;
+
+ map->priv->used -= map->count;
+ list_del(&map->next);
+ return 0;
+}
+
+static void gntdev_free_map(struct grant_map *map)
+{
+ int i;
+
+ if (!map)
+ return;
+
+ if (map->pages)
+ for (i = 0; i < map->count; i++) {
+ if (map->pages[i])
+ __free_page(map->pages[i]);
+ }
+ kfree(map->pages);
+ kfree(map->grants);
+ kfree(map->map_ops);
+ kfree(map->unmap_ops);
+ kfree(map);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int find_grant_ptes(pte_t *pte, pgtable_t token,
+ unsigned long addr, void *data)
+{
+ struct grant_map *map = data;
+ unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
+ u64 pte_maddr;
+
+ BUG_ON(pgnr >= map->count);
+ pte_maddr = arbitrary_virt_to_machine(pte).maddr;
+
+ gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr,
+ GNTMAP_contains_pte | map->flags,
+ map->grants[pgnr].ref,
+ map->grants[pgnr].domid);
+ gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr,
+ GNTMAP_contains_pte | map->flags,
+ 0 /* handle */);
+ return 0;
+}
+
+static int map_grant_pages(struct grant_map *map)
+{
+ int i, err = 0;
+
+ pr_debug("map %d+%d\n", map->index, map->count);
+ err = gnttab_map_refs(map->map_ops, map->pages, map->count);
+ if (err)
+ return err;
+
+ for (i = 0; i < map->count; i++) {
+ if (map->map_ops[i].status)
+ err = -EINVAL;
+ map->unmap_ops[i].handle = map->map_ops[i].handle;
+ }
+ return err;
+}
+
+static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
+{
+ int i, err = 0;
+
+ pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages);
+ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
+ if (err)
+ return err;
+
+ for (i = 0; i < pages; i++) {
+ if (map->unmap_ops[offset+i].status)
+ err = -EINVAL;
+ map->unmap_ops[offset+i].handle = 0;
+ }
+ return err;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void gntdev_vma_close(struct vm_area_struct *vma)
+{
+ struct grant_map *map = vma->vm_private_data;
+
+ pr_debug("close %p\n", vma);
+ map->is_mapped = 0;
+ map->vma = NULL;
+ vma->vm_private_data = NULL;
+}
+
+static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ pr_debug("vaddr %p, pgoff %ld (shouldn't happen)\n",
+ vmf->virtual_address, vmf->pgoff);
+ vmf->flags = VM_FAULT_ERROR;
+ return 0;
+}
+
+static struct vm_operations_struct gntdev_vmops = {
+ .close = gntdev_vma_close,
+ .fault = gntdev_vma_fault,
+};
+
+/* ------------------------------------------------------------------ */
+
+static void mn_invl_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
+ struct grant_map *map;
+ unsigned long mstart, mend;
+ int err;
+
+ spin_lock(&priv->lock);
+ list_for_each_entry(map, &priv->maps, next) {
+ if (!map->vma)
+ continue;
+ if (!map->is_mapped)
+ continue;
+ if (map->vma->vm_start >= end)
+ continue;
+ if (map->vma->vm_end <= start)
+ continue;
+ mstart = max(start, map->vma->vm_start);
+ mend = min(end, map->vma->vm_end);
+ pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
+ map->index, map->count,
+ map->vma->vm_start, map->vma->vm_end,
+ start, end, mstart, mend);
+ err = unmap_grant_pages(map,
+ (mstart - map->vma->vm_start) >> PAGE_SHIFT,
+ (mend - mstart) >> PAGE_SHIFT);
+ WARN_ON(err);
+ }
+ spin_unlock(&priv->lock);
+}
+
+static void mn_invl_page(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long address)
+{
+ mn_invl_range_start(mn, mm, address, address + PAGE_SIZE);
+}
+
+static void mn_release(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+{
+ struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
+ struct grant_map *map;
+ int err;
+
+ spin_lock(&priv->lock);
+ list_for_each_entry(map, &priv->maps, next) {
+ if (!map->vma)
+ continue;
+ pr_debug("map %d+%d (%lx %lx)\n",
+ map->index, map->count,
+ map->vma->vm_start, map->vma->vm_end);
+ err = unmap_grant_pages(map, /* offset */ 0, map->count);
+ WARN_ON(err);
+ }
+ spin_unlock(&priv->lock);
+}
+
+struct mmu_notifier_ops gntdev_mmu_ops = {
+ .release = mn_release,
+ .invalidate_page = mn_invl_page,
+ .invalidate_range_start = mn_invl_range_start,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int gntdev_open(struct inode *inode, struct file *flip)
+{
+ struct gntdev_priv *priv;
+ int ret = 0;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&priv->maps);
+ spin_lock_init(&priv->lock);
+ priv->limit = limit;
+
+ priv->mm = get_task_mm(current);
+ if (!priv->mm) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+ priv->mn.ops = &gntdev_mmu_ops;
+ ret = mmu_notifier_register(&priv->mn, priv->mm);
+ mmput(priv->mm);
+
+ if (ret) {
+ kfree(priv);
+ return ret;
+ }
+
+ flip->private_data = priv;
+ pr_debug("priv %p\n", priv);
+
+ return 0;
+}
+
+static int gntdev_release(struct inode *inode, struct file *flip)
+{
+ struct gntdev_priv *priv = flip->private_data;
+ struct grant_map *map;
+ int err;
+
+ pr_debug("priv %p\n", priv);
+
+ spin_lock(&priv->lock);
+ while (!list_empty(&priv->maps)) {
+ map = list_entry(priv->maps.next, struct grant_map, next);
+ err = gntdev_del_map(map);
+ if (WARN_ON(err))
+ gntdev_free_map(map);
+
+ }
+ spin_unlock(&priv->lock);
+
+ mmu_notifier_unregister(&priv->mn, priv->mm);
+ kfree(priv);
+ return 0;
+}
+
+static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
+ struct ioctl_gntdev_map_grant_ref __user *u)
+{
+ struct ioctl_gntdev_map_grant_ref op;
+ struct grant_map *map;
+ int err;
+
+ if (copy_from_user(&op, u, sizeof(op)) != 0)
+ return -EFAULT;
+ pr_debug("priv %p, add %d\n", priv, op.count);
+ if (unlikely(op.count <= 0))
+ return -EINVAL;
+ if (unlikely(op.count > priv->limit))
+ return -EINVAL;
+
+ err = -ENOMEM;
+ map = gntdev_alloc_map(priv, op.count);
+ if (!map)
+ return err;
+ if (copy_from_user(map->grants, &u->refs,
+ sizeof(map->grants[0]) * op.count) != 0) {
+ gntdev_free_map(map);
+ return err;
+ }
+
+ spin_lock(&priv->lock);
+ gntdev_add_map(priv, map);
+ op.index = map->index << PAGE_SHIFT;
+ spin_unlock(&priv->lock);
+
+ if (copy_to_user(u, &op, sizeof(op)) != 0) {
+ spin_lock(&priv->lock);
+ gntdev_del_map(map);
+ spin_unlock(&priv->lock);
+ gntdev_free_map(map);
+ return err;
+ }
+ return 0;
+}
+
+static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
+ struct ioctl_gntdev_unmap_grant_ref __user *u)
+{
+ struct ioctl_gntdev_unmap_grant_ref op;
+ struct grant_map *map;
+ int err = -ENOENT;
+
+ if (copy_from_user(&op, u, sizeof(op)) != 0)
+ return -EFAULT;
+ pr_debug("priv %p, del %d+%d\n", priv, (int)op.index, (int)op.count);
+
+ spin_lock(&priv->lock);
+ map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
+ if (map)
+ err = gntdev_del_map(map);
+ spin_unlock(&priv->lock);
+ if (!err)
+ gntdev_free_map(map);
+ return err;
+}
+
+static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv,
+ struct ioctl_gntdev_get_offset_for_vaddr __user *u)
+{
+ struct ioctl_gntdev_get_offset_for_vaddr op;
+ struct grant_map *map;
+
+ if (copy_from_user(&op, u, sizeof(op)) != 0)
+ return -EFAULT;
+ pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
+
+ spin_lock(&priv->lock);
+ map = gntdev_find_map_vaddr(priv, op.vaddr);
+ if (map == NULL ||
+ map->vma->vm_start != op.vaddr) {
+ spin_unlock(&priv->lock);
+ return -EINVAL;
+ }
+ op.offset = map->index << PAGE_SHIFT;
+ op.count = map->count;
+ spin_unlock(&priv->lock);
+
+ if (copy_to_user(u, &op, sizeof(op)) != 0)
+ return -EFAULT;
+ return 0;
+}
+
+static long gntdev_ioctl_set_max_grants(struct gntdev_priv *priv,
+ struct ioctl_gntdev_set_max_grants __user *u)
+{
+ struct ioctl_gntdev_set_max_grants op;
+
+ if (copy_from_user(&op, u, sizeof(op)) != 0)
+ return -EFAULT;
+ pr_debug("priv %p, limit %d\n", priv, op.count);
+ if (op.count > limit)
+ return -E2BIG;
+
+ spin_lock(&priv->lock);
+ priv->limit = op.count;
+ spin_unlock(&priv->lock);
+ return 0;
+}
+
+static long gntdev_ioctl(struct file *flip,
+ unsigned int cmd, unsigned long arg)
+{
+ struct gntdev_priv *priv = flip->private_data;
+ void __user *ptr = (void __user *)arg;
+
+ switch (cmd) {
+ case IOCTL_GNTDEV_MAP_GRANT_REF:
+ return gntdev_ioctl_map_grant_ref(priv, ptr);
+
+ case IOCTL_GNTDEV_UNMAP_GRANT_REF:
+ return gntdev_ioctl_unmap_grant_ref(priv, ptr);
+
+ case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
+ return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
+
+ case IOCTL_GNTDEV_SET_MAX_GRANTS:
+ return gntdev_ioctl_set_max_grants(priv, ptr);
+
+ default:
+ pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
+{
+ struct gntdev_priv *priv = flip->private_data;
+ int index = vma->vm_pgoff;
+ int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ struct grant_map *map;
+ int err = -EINVAL;
+
+ if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ pr_debug("map %d+%d at %lx (pgoff %lx)\n",
+ index, count, vma->vm_start, vma->vm_pgoff);
+
+ spin_lock(&priv->lock);
+ map = gntdev_find_map_index(priv, index, count);
+ if (!map)
+ goto unlock_out;
+ if (map->vma)
+ goto unlock_out;
+ if (priv->mm != vma->vm_mm) {
+ printk(KERN_WARNING "Huh? Other mm?\n");
+ goto unlock_out;
+ }
+
+ vma->vm_ops = &gntdev_vmops;
+
+ vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
+
+ vma->vm_private_data = map;
+ map->vma = vma;
+
+ map->flags = GNTMAP_host_map | GNTMAP_application_map;
+ if (!(vma->vm_flags & VM_WRITE))
+ map->flags |= GNTMAP_readonly;
+
+ spin_unlock(&priv->lock);
+
+ err = apply_to_page_range(vma->vm_mm, vma->vm_start,
+ vma->vm_end - vma->vm_start,
+ find_grant_ptes, map);
+ if (err) {
+ printk(KERN_WARNING "find_grant_ptes() failure.\n");
+ return err;
+ }
+
+ err = map_grant_pages(map);
+ if (err) {
+ printk(KERN_WARNING "map_grant_pages() failure.\n");
+ return err;
+ }
+
+ map->is_mapped = 1;
+
+ return 0;
+
+unlock_out:
+ spin_unlock(&priv->lock);
+ return err;
+}
+
+static const struct file_operations gntdev_fops = {
+ .owner = THIS_MODULE,
+ .open = gntdev_open,
+ .release = gntdev_release,
+ .mmap = gntdev_mmap,
+ .unlocked_ioctl = gntdev_ioctl
+};
+
+static struct miscdevice gntdev_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "xen/gntdev",
+ .fops = &gntdev_fops,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int __init gntdev_init(void)
+{
+ int err;
+
+ if (!xen_domain())
+ return -ENODEV;
+
+ err = misc_register(&gntdev_miscdev);
+ if (err != 0) {
+ printk(KERN_ERR "Could not register gntdev device\n");
+ return err;
+ }
+ return 0;
+}
+
+static void __exit gntdev_exit(void)
+{
+ misc_deregister(&gntdev_miscdev);
+}
+
+module_init(gntdev_init);
+module_exit(gntdev_exit);
+
+/* ------------------------------------------------------------------ */
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 6c4531816496..9ef54ebc1194 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -447,6 +447,52 @@ unsigned int gnttab_max_grant_frames(void)
}
EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
+int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
+ struct page **pages, unsigned int count)
+{
+ int i, ret;
+ pte_t *pte;
+ unsigned long mfn;
+
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ /* m2p override only supported for GNTMAP_contains_pte mappings */
+ if (!(map_ops[i].flags & GNTMAP_contains_pte))
+ continue;
+ pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
+ (map_ops[i].host_addr & ~PAGE_MASK));
+ mfn = pte_mfn(*pte);
+ ret = m2p_add_override(mfn, pages[i]);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gnttab_map_refs);
+
+int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
+ struct page **pages, unsigned int count)
+{
+ int i, ret;
+
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ ret = m2p_remove_override(pages[i]);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
+
static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
struct gnttab_setup_table setup;
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index ef9c7db52077..db8c4c4ac880 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -49,6 +49,7 @@ static int xen_hvm_suspend(void *data)
if (!*cancelled) {
xen_irq_resume();
+ xen_console_resume();
xen_timer_resume();
}
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index c01b5ddce529..afbe041f42c5 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -105,7 +105,7 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int i, ret;
- long ioaddr, iolen;
+ long ioaddr;
long mmio_addr, mmio_len;
unsigned int max_nr_gframes;
@@ -114,7 +114,6 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
return i;
ioaddr = pci_resource_start(pdev, 0);
- iolen = pci_resource_len(pdev, 0);
mmio_addr = pci_resource_start(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);
@@ -125,19 +124,13 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
goto pci_out;
}
- if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
- dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n",
- mmio_addr, mmio_len);
- ret = -EBUSY;
+ ret = pci_request_region(pdev, 1, DRV_NAME);
+ if (ret < 0)
goto pci_out;
- }
- if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
- dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n",
- iolen, ioaddr);
- ret = -EBUSY;
+ ret = pci_request_region(pdev, 0, DRV_NAME);
+ if (ret < 0)
goto mem_out;
- }
platform_mmio = mmio_addr;
platform_mmiolen = mmio_len;
@@ -169,9 +162,9 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
return 0;
out:
- release_region(ioaddr, iolen);
+ pci_release_region(pdev, 0);
mem_out:
- release_mem_region(mmio_addr, mmio_len);
+ pci_release_region(pdev, 1);
pci_out:
pci_disable_device(pdev);
return ret;
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
index 5571f5b84223..8dca685358b4 100644
--- a/drivers/xen/xenbus/Makefile
+++ b/drivers/xen/xenbus/Makefile
@@ -5,3 +5,8 @@ xenbus-objs += xenbus_client.o
xenbus-objs += xenbus_comms.o
xenbus-objs += xenbus_xs.o
xenbus-objs += xenbus_probe.o
+
+xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
+xenbus-objs += $(xenbus-be-objs-y)
+
+obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index deb9c4ba3a93..baa65e7fbbc7 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -56,7 +56,6 @@
#include <xen/events.h>
#include <xen/page.h>
-#include <xen/platform_pci.h>
#include <xen/hvm.h>
#include "xenbus_comms.h"
@@ -73,15 +72,6 @@ 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);
-
-static int xenbus_dev_suspend(struct device *dev, pm_message_t state);
-static int xenbus_dev_resume(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)
@@ -102,34 +92,7 @@ int xenbus_match(struct device *_dev, struct device_driver *_drv)
return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
}
-
-static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env)
-{
- struct xenbus_device *dev = to_xenbus_device(_dev);
-
- if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype))
- return -ENOMEM;
-
- return 0;
-}
-
-/* device/<type>/<id> => <type>-<id> */
-static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
-{
- nodename = strchr(nodename, '/');
- if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) {
- printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
- return -EINVAL;
- }
-
- strlcpy(bus_id, nodename + 1, XEN_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;
-}
+EXPORT_SYMBOL_GPL(xenbus_match);
static void free_otherend_details(struct xenbus_device *dev)
@@ -149,7 +112,30 @@ static void free_otherend_watch(struct xenbus_device *dev)
}
-int read_otherend_details(struct xenbus_device *xendev,
+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)
+{
+ struct xen_bus_type *bus =
+ container_of(dev->dev.bus, struct xen_bus_type, bus);
+
+ return xenbus_watch_pathfmt(dev, &dev->otherend_watch,
+ bus->otherend_changed,
+ "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_read_otherend_details(struct xenbus_device *xendev,
char *id_node, char *path_node)
{
int err = xenbus_gather(XBT_NIL, xendev->nodename,
@@ -174,39 +160,11 @@ int read_otherend_details(struct xenbus_device *xendev,
return 0;
}
+EXPORT_SYMBOL_GPL(xenbus_read_otherend_details);
-
-static int read_backend_details(struct xenbus_device *xendev)
-{
- return read_otherend_details(xendev, "backend-id", "backend");
-}
-
-static struct device_attribute xenbus_dev_attrs[] = {
- __ATTR_NULL
-};
-
-/* 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,
- .uevent = xenbus_uevent,
- .probe = xenbus_dev_probe,
- .remove = xenbus_dev_remove,
- .shutdown = xenbus_dev_shutdown,
- .dev_attrs = xenbus_dev_attrs,
-
- .suspend = xenbus_dev_suspend,
- .resume = xenbus_dev_resume,
- },
-};
-
-static void otherend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+void xenbus_otherend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len,
+ int ignore_on_shutdown)
{
struct xenbus_device *dev =
container_of(watch, struct xenbus_device, otherend_watch);
@@ -234,11 +192,7 @@ static void otherend_changed(struct xenbus_watch *watch,
* 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))
+ if (ignore_on_shutdown && (state == XenbusStateClosing))
xenbus_frontend_closed(dev);
return;
}
@@ -246,25 +200,7 @@ static void otherend_changed(struct xenbus_watch *watch,
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");
-}
-
+EXPORT_SYMBOL_GPL(xenbus_otherend_changed);
int xenbus_dev_probe(struct device *_dev)
{
@@ -308,8 +244,9 @@ int xenbus_dev_probe(struct device *_dev)
fail:
xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
xenbus_switch_state(dev, XenbusStateClosed);
- return -ENODEV;
+ return err;
}
+EXPORT_SYMBOL_GPL(xenbus_dev_probe);
int xenbus_dev_remove(struct device *_dev)
{
@@ -327,8 +264,9 @@ int xenbus_dev_remove(struct device *_dev)
xenbus_switch_state(dev, XenbusStateClosed);
return 0;
}
+EXPORT_SYMBOL_GPL(xenbus_dev_remove);
-static void xenbus_dev_shutdown(struct device *_dev)
+void xenbus_dev_shutdown(struct device *_dev)
{
struct xenbus_device *dev = to_xenbus_device(_dev);
unsigned long timeout = 5*HZ;
@@ -349,6 +287,7 @@ static void xenbus_dev_shutdown(struct device *_dev)
out:
put_device(&dev->dev);
}
+EXPORT_SYMBOL_GPL(xenbus_dev_shutdown);
int xenbus_register_driver_common(struct xenbus_driver *drv,
struct xen_bus_type *bus,
@@ -362,25 +301,7 @@ int xenbus_register_driver_common(struct xenbus_driver *drv,
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);
+EXPORT_SYMBOL_GPL(xenbus_register_driver_common);
void xenbus_unregister_driver(struct xenbus_driver *drv)
{
@@ -551,24 +472,7 @@ 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;
-}
+EXPORT_SYMBOL_GPL(xenbus_probe_node);
static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
{
@@ -582,10 +486,11 @@ static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
return PTR_ERR(dir);
for (i = 0; i < dir_n; i++) {
- err = bus->probe(type, dir[i]);
+ err = bus->probe(bus, type, dir[i]);
if (err)
break;
}
+
kfree(dir);
return err;
}
@@ -605,9 +510,11 @@ int xenbus_probe_devices(struct xen_bus_type *bus)
if (err)
break;
}
+
kfree(dir);
return err;
}
+EXPORT_SYMBOL_GPL(xenbus_probe_devices);
static unsigned int char_count(const char *str, char c)
{
@@ -670,32 +577,18 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
}
EXPORT_SYMBOL_GPL(xenbus_dev_changed);
-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 xenbus_dev_suspend(struct device *dev, pm_message_t state)
+int xenbus_dev_suspend(struct device *dev, pm_message_t state)
{
int err = 0;
struct xenbus_driver *drv;
- struct xenbus_device *xdev;
+ struct xenbus_device *xdev
+ = container_of(dev, struct xenbus_device, dev);
- DPRINTK("");
+ DPRINTK("%s", xdev->nodename);
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, state);
if (err)
@@ -703,21 +596,20 @@ static int xenbus_dev_suspend(struct device *dev, pm_message_t state)
"xenbus: suspend %s failed: %i\n", dev_name(dev), err);
return 0;
}
+EXPORT_SYMBOL_GPL(xenbus_dev_suspend);
-static int xenbus_dev_resume(struct device *dev)
+int xenbus_dev_resume(struct device *dev)
{
int err;
struct xenbus_driver *drv;
- struct xenbus_device *xdev;
+ struct xenbus_device *xdev
+ = container_of(dev, struct xenbus_device, dev);
- DPRINTK("");
+ DPRINTK("%s", xdev->nodename);
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
@@ -748,6 +640,7 @@ static int xenbus_dev_resume(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(xenbus_dev_resume);
/* A flag to determine if xenstored is 'ready' (i.e. has started) */
int xenstored_ready = 0;
@@ -776,11 +669,6 @@ void xenbus_probe(struct work_struct *unused)
{
xenstored_ready = 1;
- /* 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);
}
@@ -809,16 +697,7 @@ static int __init xenbus_init(void)
err = -ENODEV;
if (!xen_domain())
- 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;
+ return err;
/*
* Domain0 doesn't have a store_evtchn or store_mfn yet.
@@ -874,7 +753,7 @@ static int __init xenbus_init(void)
if (err) {
printk(KERN_WARNING
"XENBUS: Error initializing xenstore comms: %i\n", err);
- goto out_unreg_back;
+ goto out_error;
}
#ifdef CONFIG_XEN_COMPAT_XENFS
@@ -887,133 +766,13 @@ static int __init xenbus_init(void)
return 0;
- out_unreg_back:
- xenbus_backend_bus_unregister();
-
- out_unreg_front:
- bus_unregister(&xenbus_frontend.bus);
-
out_error:
if (page != 0)
free_page(page);
+
return err;
}
postcore_initcall(xenbus_init);
MODULE_LICENSE("GPL");
-
-static int is_device_connecting(struct device *dev, void *data)
-{
- struct xenbus_device *xendev = to_xenbus_device(dev);
- struct device_driver *drv = data;
- struct xenbus_driver *xendrv;
-
- /*
- * 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;
-
- xendrv = to_xenbus_driver(dev->driver);
- return (xendev->state < XenbusStateConnected ||
- (xendev->state == XenbusStateConnected &&
- xendrv->is_ready && !xendrv->is_ready(xendev)));
-}
-
-static int exists_connecting_device(struct device_driver *drv)
-{
- return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
- is_device_connecting);
-}
-
-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) {
- enum xenbus_state rstate = XenbusStateUnknown;
- if (xendev->otherend)
- rstate = xenbus_read_driver_state(xendev->otherend);
- printk(KERN_WARNING "XENBUS: Timeout connecting "
- "to device: %s (local state %d, remote state %d)\n",
- xendev->nodename, xendev->state, rstate);
- }
-
- return 0;
-}
-
-/* We only wait for device setup after most initcalls have run. */
-static int ready_to_wait_for_devices;
-
-/*
- * On a 5-minute 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 start = jiffies;
- struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
- unsigned int seconds_waited = 0;
-
- if (!ready_to_wait_for_devices || !xen_domain())
- return;
-
- while (exists_connecting_device(drv)) {
- if (time_after(jiffies, start + (seconds_waited+5)*HZ)) {
- if (!seconds_waited)
- printk(KERN_WARNING "XENBUS: Waiting for "
- "devices to initialise: ");
- seconds_waited += 5;
- printk("%us...", 300 - seconds_waited);
- if (seconds_waited == 300)
- break;
- }
-
- schedule_timeout_interruptible(HZ/10);
- }
-
- if (seconds_waited)
- printk("\n");
-
- bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
- print_device_status);
-}
-
-#ifndef MODULE
-static int __init boot_wait_for_devices(void)
-{
- if (xen_hvm_domain() && !xen_platform_pci_unplug)
- return -ENODEV;
-
- 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
index 6c5e3185a6a2..24665812316a 100644
--- a/drivers/xen/xenbus/xenbus_probe.h
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -36,26 +36,15 @@
#define XEN_BUS_ID_SIZE 20
-#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[XEN_BUS_ID_SIZE], const char *nodename);
- int (*probe)(const char *type, const char *dir);
+ int (*probe)(struct xen_bus_type *bus, const char *type,
+ const char *dir);
+ void (*otherend_changed)(struct xenbus_watch *watch, const char **vec,
+ unsigned int len);
struct bus_type bus;
};
@@ -73,4 +62,16 @@ extern int xenbus_probe_devices(struct xen_bus_type *bus);
extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+extern void xenbus_dev_shutdown(struct device *_dev);
+
+extern int xenbus_dev_suspend(struct device *dev, pm_message_t state);
+extern int xenbus_dev_resume(struct device *dev);
+
+extern void xenbus_otherend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len,
+ int ignore_on_shutdown);
+
+extern int xenbus_read_otherend_details(struct xenbus_device *xendev,
+ char *id_node, char *path_node);
+
#endif
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c
new file mode 100644
index 000000000000..6cf467bf63ec
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -0,0 +1,276 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have (backend half).
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ * Copyright (C) 2007 Solarflare Communications, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; 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 <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/features.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
+static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
+{
+ int domid, err;
+ const char *devid, *type, *frontend;
+ unsigned int typelen;
+
+ type = strchr(nodename, '/');
+ if (!type)
+ return -EINVAL;
+ type++;
+ typelen = strcspn(type, "/");
+ if (!typelen || type[typelen] != '/')
+ return -EINVAL;
+
+ devid = strrchr(nodename, '/') + 1;
+
+ err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
+ "frontend", NULL, &frontend,
+ NULL);
+ if (err)
+ return err;
+ if (strlen(frontend) == 0)
+ err = -ERANGE;
+ if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
+ err = -ENOENT;
+ kfree(frontend);
+
+ if (err)
+ return err;
+
+ if (snprintf(bus_id, XEN_BUS_ID_SIZE, "%.*s-%i-%s",
+ typelen, type, domid, devid) >= XEN_BUS_ID_SIZE)
+ return -ENOSPC;
+ return 0;
+}
+
+static int xenbus_uevent_backend(struct device *dev,
+ struct kobj_uevent_env *env)
+{
+ struct xenbus_device *xdev;
+ struct xenbus_driver *drv;
+ struct xen_bus_type *bus;
+
+ DPRINTK("");
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ xdev = to_xenbus_device(dev);
+ bus = container_of(xdev->dev.bus, struct xen_bus_type, bus);
+ if (xdev == NULL)
+ return -ENODEV;
+
+ /* stuff we want to pass to /sbin/hotplug */
+ if (add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "XENBUS_BASE_PATH=%s", bus->root))
+ return -ENOMEM;
+
+ if (dev->driver) {
+ drv = to_xenbus_driver(dev->driver);
+ if (drv && drv->uevent)
+ return drv->uevent(xdev, env);
+ }
+
+ return 0;
+}
+
+/* backend/<typename>/<frontend-uuid>/<name> */
+static int xenbus_probe_backend_unit(struct xen_bus_type *bus,
+ const char *dir,
+ const char *type,
+ const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s\n", nodename);
+
+ err = xenbus_probe_node(bus, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+/* backend/<typename>/<frontend-domid> */
+static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type,
+ const char *domid)
+{
+ char *nodename;
+ int err = 0;
+ char **dir;
+ unsigned int i, dir_n = 0;
+
+ DPRINTK("");
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, domid);
+ if (!nodename)
+ return -ENOMEM;
+
+ dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
+ if (IS_ERR(dir)) {
+ kfree(nodename);
+ return PTR_ERR(dir);
+ }
+
+ for (i = 0; i < dir_n; i++) {
+ err = xenbus_probe_backend_unit(bus, nodename, type, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ kfree(nodename);
+ return err;
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ xenbus_otherend_changed(watch, vec, len, 0);
+}
+
+static struct device_attribute xenbus_backend_dev_attrs[] = {
+ __ATTR_NULL
+};
+
+static struct xen_bus_type xenbus_backend = {
+ .root = "backend",
+ .levels = 3, /* backend/type/<frontend>/<id> */
+ .get_bus_id = backend_bus_id,
+ .probe = xenbus_probe_backend,
+ .otherend_changed = frontend_changed,
+ .bus = {
+ .name = "xen-backend",
+ .match = xenbus_match,
+ .uevent = xenbus_uevent_backend,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ .dev_attrs = xenbus_backend_dev_attrs,
+ },
+};
+
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ DPRINTK("");
+
+ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
+}
+
+static struct xenbus_watch be_watch = {
+ .node = "backend",
+ .callback = backend_changed,
+};
+
+static int read_frontend_details(struct xenbus_device *xendev)
+{
+ return xenbus_read_otherend_details(xendev, "frontend-id", "frontend");
+}
+
+int xenbus_dev_is_online(struct xenbus_device *dev)
+{
+ int rc, val;
+
+ rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val);
+ if (rc != 1)
+ val = 0; /* no online node present */
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
+
+int __xenbus_register_backend(struct xenbus_driver *drv,
+ struct module *owner, const char *mod_name)
+{
+ drv->read_otherend_details = read_frontend_details;
+
+ return xenbus_register_driver_common(drv, &xenbus_backend,
+ owner, mod_name);
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_backend);
+
+static int backend_probe_and_watch(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ /* Enumerate devices in xenstore and watch for changes. */
+ xenbus_probe_devices(&xenbus_backend);
+ register_xenbus_watch(&be_watch);
+
+ return NOTIFY_DONE;
+}
+
+static int __init xenbus_probe_backend_init(void)
+{
+ static struct notifier_block xenstore_notifier = {
+ .notifier_call = backend_probe_and_watch
+ };
+ int err;
+
+ DPRINTK("");
+
+ /* Register ourselves with the kernel bus subsystem */
+ err = bus_register(&xenbus_backend.bus);
+ if (err)
+ return err;
+
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+subsys_initcall(xenbus_probe_backend_init);
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
new file mode 100644
index 000000000000..5bcc2d6cf129
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -0,0 +1,294 @@
+#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/proc_fs.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 <xen/platform_pci.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
+{
+ nodename = strchr(nodename, '/');
+ if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) {
+ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+ return -EINVAL;
+ }
+
+ strlcpy(bus_id, nodename + 1, XEN_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;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type,
+ const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s", nodename);
+
+ err = xenbus_probe_node(bus, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+static int xenbus_uevent_frontend(struct device *_dev,
+ struct kobj_uevent_env *env)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+
+ if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype))
+ return -ENOMEM;
+
+ return 0;
+}
+
+
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ xenbus_otherend_changed(watch, vec, len, 1);
+}
+
+static struct device_attribute xenbus_frontend_dev_attrs[] = {
+ __ATTR_NULL
+};
+
+static struct xen_bus_type xenbus_frontend = {
+ .root = "device",
+ .levels = 2, /* device/type/<id> */
+ .get_bus_id = frontend_bus_id,
+ .probe = xenbus_probe_frontend,
+ .otherend_changed = backend_changed,
+ .bus = {
+ .name = "xen",
+ .match = xenbus_match,
+ .uevent = xenbus_uevent_frontend,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ .dev_attrs = xenbus_frontend_dev_attrs,
+
+ .suspend = xenbus_dev_suspend,
+ .resume = xenbus_dev_resume,
+ },
+};
+
+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 read_backend_details(struct xenbus_device *xendev)
+{
+ return xenbus_read_otherend_details(xendev, "backend-id", "backend");
+}
+
+static int is_device_connecting(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+ struct xenbus_driver *xendrv;
+
+ /*
+ * 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;
+
+ xendrv = to_xenbus_driver(dev->driver);
+ return (xendev->state < XenbusStateConnected ||
+ (xendev->state == XenbusStateConnected &&
+ xendrv->is_ready && !xendrv->is_ready(xendev)));
+}
+
+static int exists_connecting_device(struct device_driver *drv)
+{
+ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ is_device_connecting);
+}
+
+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) {
+ enum xenbus_state rstate = XenbusStateUnknown;
+ if (xendev->otherend)
+ rstate = xenbus_read_driver_state(xendev->otherend);
+ printk(KERN_WARNING "XENBUS: Timeout connecting "
+ "to device: %s (local state %d, remote state %d)\n",
+ xendev->nodename, xendev->state, rstate);
+ }
+
+ return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 5-minute 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 start = jiffies;
+ struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+ unsigned int seconds_waited = 0;
+
+ if (!ready_to_wait_for_devices || !xen_domain())
+ return;
+
+ while (exists_connecting_device(drv)) {
+ if (time_after(jiffies, start + (seconds_waited+5)*HZ)) {
+ if (!seconds_waited)
+ printk(KERN_WARNING "XENBUS: Waiting for "
+ "devices to initialise: ");
+ seconds_waited += 5;
+ printk("%us...", 300 - seconds_waited);
+ if (seconds_waited == 300)
+ break;
+ }
+
+ schedule_timeout_interruptible(HZ/10);
+ }
+
+ if (seconds_waited)
+ printk("\n");
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ print_device_status);
+}
+
+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);
+
+static int frontend_probe_and_watch(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ /* Enumerate devices in xenstore and watch for changes. */
+ xenbus_probe_devices(&xenbus_frontend);
+ register_xenbus_watch(&fe_watch);
+
+ return NOTIFY_DONE;
+}
+
+
+static int __init xenbus_probe_frontend_init(void)
+{
+ static struct notifier_block xenstore_notifier = {
+ .notifier_call = frontend_probe_and_watch
+ };
+ int err;
+
+ DPRINTK("");
+
+ /* Register ourselves with the kernel bus subsystem */
+ err = bus_register(&xenbus_frontend.bus);
+ if (err)
+ return err;
+
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+subsys_initcall(xenbus_probe_frontend_init);
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+ if (xen_hvm_domain() && !xen_platform_pci_unplug)
+ return -ENODEV;
+
+ ready_to_wait_for_devices = 1;
+ wait_for_devices(NULL);
+ return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c
index f80be7f6eb95..dbd3b16fd131 100644
--- a/drivers/xen/xenfs/privcmd.c
+++ b/drivers/xen/xenfs/privcmd.c
@@ -15,7 +15,6 @@
#include <linux/mman.h>
#include <linux/uaccess.h>
#include <linux/swap.h>
-#include <linux/smp_lock.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
@@ -266,9 +265,7 @@ static int mmap_return_errors(void *data, void *state)
xen_pfn_t *mfnp = data;
struct mmap_batch_state *st = state;
- put_user(*mfnp, st->user++);
-
- return 0;
+ return put_user(*mfnp, st->user++);
}
static struct vm_operations_struct privcmd_vm_ops;
@@ -323,10 +320,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata)
up_write(&mm->mmap_sem);
if (state.err > 0) {
- ret = 0;
-
state.user = m.arr;
- traverse_pages(m.num, sizeof(xen_pfn_t),
+ ret = traverse_pages(m.num, sizeof(xen_pfn_t),
&pagelist,
mmap_return_errors, &state);
}
@@ -384,8 +379,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
if (xen_feature(XENFEAT_auto_translated_physmap))
return -ENOSYS;
- /* DONTCOPY is essential for Xen as copy_page_range is broken. */
- vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+ /* DONTCOPY is essential for Xen because copy_page_range doesn't know
+ * how to recreate these mappings */
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
vma->vm_ops = &privcmd_vm_ops;
vma->vm_private_data = NULL;
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index f6339d11d59c..1aa389719846 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -12,8 +12,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/magic.h>
-#include <linux/mm.h>
-#include <linux/backing-dev.h>
#include <xen/xen.h>
@@ -24,28 +22,12 @@
MODULE_DESCRIPTION("Xen filesystem");
MODULE_LICENSE("GPL");
-static int xenfs_set_page_dirty(struct page *page)
-{
- return !TestSetPageDirty(page);
-}
-
-static const struct address_space_operations xenfs_aops = {
- .set_page_dirty = xenfs_set_page_dirty,
-};
-
-static struct backing_dev_info xenfs_backing_dev_info = {
- .ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
-};
-
static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
{
struct inode *ret = new_inode(sb);
if (ret) {
ret->i_mode = mode;
- ret->i_mapping->a_ops = &xenfs_aops;
- ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
ret->i_uid = ret->i_gid = 0;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
@@ -121,9 +103,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
return rc;
}
-static int xenfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static struct dentry *xenfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
{
return mount_single(fs_type, flags, data, xenfs_fill_super);
}
@@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = {
static int __init xenfs_init(void)
{
- int err;
- if (!xen_domain()) {
- printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
- return 0;
- }
-
- err = register_filesystem(&xenfs_type);
- if (err) {
- printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
- goto out;
- }
-
- err = bdi_init(&xenfs_backing_dev_info);
- if (err)
- unregister_filesystem(&xenfs_type);
-
- out:
+ if (xen_domain())
+ return register_filesystem(&xenfs_type);
- return err;
+ printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
+ return 0;
}
static void __exit xenfs_exit(void)
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index cafc50454292..e0c84725d3e9 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/amigahw.h>
#include <asm/setup.h>